From 7090c5fd8d2bc46a463549bf26505e67a32d1d0e Mon Sep 17 00:00:00 2001 From: Prakash Dhavali Date: Mon, 2 Nov 2015 17:55:19 -0800 Subject: [PATCH] qcacld-3.0: Initial snapshot of ihelium wlan driver qcacld-3.0: Initial snapshot of ihelium wlan driver to match code-scanned SU Release 5.0.0.139. This is open-source version of wlan for next Android release. Change-Id: Icf598ca97da74f84bea607e4e902d1889806f507 --- Android.mk | 114 + Kbuild | 1331 + Kconfig | 110 + Makefile | 20 + config/WCNSS_qcom_cfg.ini | 591 + core/bmi/inc/bmi.h | 60 + core/bmi/inc/ol_fw.h | 64 + core/bmi/inc/ol_if_athvar.h | 87 + core/bmi/src/bmi.c | 470 + core/bmi/src/bmi_1.c | 321 + core/bmi/src/bmi_2.c | 452 + core/bmi/src/i_ar6320v2_regtable.h | 607 + core/bmi/src/i_bmi.h | 149 + core/bmi/src/ol_fw.c | 1637 ++ core/cdf/inc/cdf_atomic.h | 140 + core/cdf/inc/cdf_defer.h | 138 + core/cdf/inc/cdf_event.h | 154 + core/cdf/inc/cdf_list.h | 110 + core/cdf/inc/cdf_lock.h | 296 + core/cdf/inc/cdf_mc_timer.h | 253 + core/cdf/inc/cdf_memory.h | 225 + core/cdf/inc/cdf_nbuf.h | 1053 + core/cdf/inc/cdf_net_types.h | 117 + core/cdf/inc/cdf_softirq_timer.h | 118 + core/cdf/inc/cdf_status.h | 111 + core/cdf/inc/cdf_threads.h | 83 + core/cdf/inc/cdf_time.h | 184 + core/cdf/inc/cdf_trace.h | 283 + core/cdf/inc/cdf_types.h | 492 + core/cdf/inc/cdf_util.h | 325 + core/cdf/inc/osdep.h | 300 + core/cdf/src/cdf_defer.c | 50 + core/cdf/src/cdf_event.c | 270 + core/cdf/src/cdf_list.c | 225 + core/cdf/src/cdf_lock.c | 491 + core/cdf/src/cdf_mc_timer.c | 800 + core/cdf/src/cdf_memory.c | 631 + core/cdf/src/cdf_nbuf.c | 1017 + core/cdf/src/cdf_threads.c | 107 + core/cdf/src/cdf_trace.c | 1018 + core/cdf/src/i_cdf_atomic.h | 78 + core/cdf/src/i_cdf_defer.h | 106 + core/cdf/src/i_cdf_event.h | 62 + core/cdf/src/i_cdf_lock.h | 255 + core/cdf/src/i_cdf_mc_timer.h | 61 + core/cdf/src/i_cdf_nbuf.h | 1092 + core/cdf/src/i_cdf_softirq_timer.h | 152 + core/cdf/src/i_cdf_time.h | 217 + core/cdf/src/i_cdf_trace.h | 145 + core/cdf/src/i_cdf_types.h | 234 + core/cdf/src/i_cdf_util.h | 107 + core/cds/inc/cds_api.h | 124 + core/cds/inc/cds_concurrency.h | 732 + core/cds/inc/cds_crypto.h | 183 + core/cds/inc/cds_get_bin.h | 75 + core/cds/inc/cds_ieee80211_common.h | 2105 ++ core/cds/inc/cds_ieee80211_defines.h | 1374 + core/cds/inc/cds_if_upperproto.h | 238 + core/cds/inc/cds_mq.h | 165 + core/cds/inc/cds_pack_align.h | 111 + core/cds/inc/cds_packet.h | 185 + core/cds/inc/cds_queue.h | 33 + core/cds/inc/cds_reg_service.h | 310 + core/cds/inc/cds_regdomain.h | 1098 + core/cds/inc/cds_regdomain_common.h | 2218 ++ core/cds/inc/cds_sched.h | 451 + core/cds/inc/cds_utils.h | 189 + core/cds/src/cds_api.c | 2085 ++ core/cds/src/cds_concurrency.c | 6823 +++++ core/cds/src/cds_get_bin.c | 166 + core/cds/src/cds_ieee80211_common_i.h | 545 + core/cds/src/cds_mq.c | 215 + core/cds/src/cds_packet.c | 348 + core/cds/src/cds_reg_service.c | 1439 + core/cds/src/cds_regdomain.c | 699 + core/cds/src/cds_sched.c | 1270 + core/cds/src/cds_utils.c | 1135 + core/cds/src/i_cds_packet.h | 76 + core/cds/src/queue.h | 571 + core/dp/htt/htt.c | 562 + core/dp/htt/htt_fw_stats.c | 1155 + core/dp/htt/htt_h2t.c | 904 + core/dp/htt/htt_internal.h | 500 + core/dp/htt/htt_rx.c | 2444 ++ core/dp/htt/htt_t2h.c | 935 + core/dp/htt/htt_tx.c | 864 + core/dp/htt/htt_types.h | 373 + core/dp/htt/rx_desc.h | 533 + core/dp/ol/inc/ol_cfg.h | 543 + core/dp/ol/inc/ol_ctrl_addba_api.h | 43 + core/dp/ol/inc/ol_ctrl_api.h | 44 + core/dp/ol/inc/ol_defines.h | 47 + core/dp/ol/inc/ol_htt_api.h | 353 + core/dp/ol/inc/ol_htt_rx_api.h | 863 + core/dp/ol/inc/ol_htt_tx_api.h | 969 + core/dp/ol/inc/ol_osif_api.h | 42 + core/dp/ol/inc/ol_params.h | 103 + core/dp/ol/inc/ol_txrx_api.h | 113 + core/dp/ol/inc/ol_txrx_ctrl_api.h | 1312 + core/dp/ol/inc/ol_txrx_dbg.h | 203 + core/dp/ol/inc/ol_txrx_htt_api.h | 579 + core/dp/ol/inc/ol_txrx_osif_api.h | 283 + core/dp/ol/inc/ol_txrx_stats.h | 133 + core/dp/ol/inc/ol_vowext_dbg_defs.h | 66 + core/dp/txrx/ipv6_defs.h | 107 + core/dp/txrx/ol_cfg.c | 323 + core/dp/txrx/ol_ctrl_txrx_api.h | 190 + core/dp/txrx/ol_osif_txrx_api.h | 51 + core/dp/txrx/ol_rx.c | 1493 ++ core/dp/txrx/ol_rx.h | 67 + core/dp/txrx/ol_rx_defrag.c | 1059 + core/dp/txrx/ol_rx_defrag.h | 197 + core/dp/txrx/ol_rx_fwd.c | 232 + core/dp/txrx/ol_rx_fwd.h | 75 + core/dp/txrx/ol_rx_pn.c | 348 + core/dp/txrx/ol_rx_pn.h | 105 + core/dp/txrx/ol_rx_reorder.c | 827 + core/dp/txrx/ol_rx_reorder.h | 93 + core/dp/txrx/ol_rx_reorder_timeout.c | 219 + core/dp/txrx/ol_rx_reorder_timeout.h | 66 + core/dp/txrx/ol_tx.c | 1364 + core/dp/txrx/ol_tx.h | 82 + core/dp/txrx/ol_tx_desc.c | 621 + core/dp/txrx/ol_tx_desc.h | 171 + core/dp/txrx/ol_tx_queue.c | 428 + core/dp/txrx/ol_tx_queue.h | 92 + core/dp/txrx/ol_tx_send.c | 969 + core/dp/txrx/ol_tx_send.h | 86 + core/dp/txrx/ol_txrx.c | 3173 +++ core/dp/txrx/ol_txrx.h | 70 + core/dp/txrx/ol_txrx_encap.c | 593 + core/dp/txrx/ol_txrx_encap.h | 120 + core/dp/txrx/ol_txrx_event.c | 228 + core/dp/txrx/ol_txrx_flow_control.c | 707 + core/dp/txrx/ol_txrx_internal.h | 737 + core/dp/txrx/ol_txrx_peer_find.c | 494 + core/dp/txrx/ol_txrx_peer_find.h | 116 + core/dp/txrx/ol_txrx_types.h | 1018 + core/dp/txrx/txrx.h | 235 + core/dp/txrx/wdi_event.h | 92 + core/dp/txrx/wdi_event_api.h | 95 + core/hdd/inc/qc_sap_ioctl.h | 248 + core/hdd/inc/wlan_hdd_assoc.h | 251 + core/hdd/inc/wlan_hdd_cfg.h | 3351 +++ core/hdd/inc/wlan_hdd_conc_ut.h | 79 + core/hdd/inc/wlan_hdd_debugfs.h | 44 + core/hdd/inc/wlan_hdd_driver_ops.h | 39 + core/hdd/inc/wlan_hdd_ether.h | 89 + core/hdd/inc/wlan_hdd_ftm.h | 68 + core/hdd/inc/wlan_hdd_host_offload.h | 60 + core/hdd/inc/wlan_hdd_includes.h | 69 + core/hdd/inc/wlan_hdd_ipa.h | 151 + core/hdd/inc/wlan_hdd_lro.h | 145 + core/hdd/inc/wlan_hdd_main.h | 1529 ++ core/hdd/inc/wlan_hdd_memdump.h | 92 + core/hdd/inc/wlan_hdd_mib.h | 190 + core/hdd/inc/wlan_hdd_misc.h | 39 + core/hdd/inc/wlan_hdd_nan.h | 59 + core/hdd/inc/wlan_hdd_napi.h | 82 + core/hdd/inc/wlan_hdd_oemdata.h | 172 + core/hdd/inc/wlan_hdd_p2p.h | 202 + core/hdd/inc/wlan_hdd_power.h | 190 + core/hdd/inc/wlan_hdd_softap_tx_rx.h | 94 + core/hdd/inc/wlan_hdd_tdls.h | 633 + core/hdd/inc/wlan_hdd_trace.h | 138 + core/hdd/inc/wlan_hdd_tx_rx.h | 154 + core/hdd/inc/wlan_hdd_wext.h | 385 + core/hdd/inc/wlan_hdd_wmm.h | 404 + core/hdd/inc/wlan_hdd_wowl.h | 183 + core/hdd/src/wlan_hdd_assoc.c | 5426 ++++ core/hdd/src/wlan_hdd_cfg.c | 6612 +++++ core/hdd/src/wlan_hdd_cfg80211.c | 10706 ++++++++ core/hdd/src/wlan_hdd_cfg80211.h | 2279 ++ core/hdd/src/wlan_hdd_conc_ut.c | 865 + core/hdd/src/wlan_hdd_debugfs.c | 648 + core/hdd/src/wlan_hdd_driver_ops.c | 642 + core/hdd/src/wlan_hdd_ext_scan.c | 4605 ++++ core/hdd/src/wlan_hdd_ext_scan.h | 127 + core/hdd/src/wlan_hdd_ftm.c | 1061 + core/hdd/src/wlan_hdd_green_ap.c | 449 + core/hdd/src/wlan_hdd_green_ap.h | 54 + core/hdd/src/wlan_hdd_hostapd.c | 8421 ++++++ core/hdd/src/wlan_hdd_hostapd.h | 128 + core/hdd/src/wlan_hdd_ioctl.c | 6314 +++++ core/hdd/src/wlan_hdd_ioctl.h | 39 + core/hdd/src/wlan_hdd_ipa.c | 3935 +++ core/hdd/src/wlan_hdd_lro.c | 663 + core/hdd/src/wlan_hdd_main.c | 6731 +++++ core/hdd/src/wlan_hdd_memdump.c | 647 + core/hdd/src/wlan_hdd_nan.c | 194 + core/hdd/src/wlan_hdd_napi.c | 262 + core/hdd/src/wlan_hdd_ocb.c | 2112 ++ core/hdd/src/wlan_hdd_ocb.h | 292 + core/hdd/src/wlan_hdd_oemdata.c | 847 + core/hdd/src/wlan_hdd_p2p.c | 2626 ++ core/hdd/src/wlan_hdd_power.c | 2346 ++ core/hdd/src/wlan_hdd_scan.c | 2429 ++ core/hdd/src/wlan_hdd_scan.h | 75 + core/hdd/src/wlan_hdd_softap_tx_rx.c | 943 + core/hdd/src/wlan_hdd_stats.c | 2511 ++ core/hdd/src/wlan_hdd_stats.h | 186 + core/hdd/src/wlan_hdd_tdls.c | 4705 ++++ core/hdd/src/wlan_hdd_trace.c | 71 + core/hdd/src/wlan_hdd_tx_rx.c | 1065 + core/hdd/src/wlan_hdd_wext.c | 10708 ++++++++ core/hdd/src/wlan_hdd_wmm.c | 2590 ++ core/hdd/src/wlan_hdd_wowl.c | 600 + core/hif/inc/hif.h | 650 + core/hif/inc/hif_napi.h | 153 + core/hif/inc/regtable.h | 33 + core/hif/inc/regtable_ce.h | 259 + core/hif/inc/regtable_pcie.h | 1030 + core/hif/src/adrastea_reg_def.h | 2352 ++ core/hif/src/ar6320def.h | 796 + core/hif/src/ar6320v2def.h | 815 + core/hif/src/ar9888def.h | 590 + core/hif/src/ath_procfs.c | 201 + core/hif/src/ce/ce_api.h | 471 + core/hif/src/ce/ce_assignment.h | 291 + core/hif/src/ce/ce_bmi.c | 293 + core/hif/src/ce/ce_bmi.h | 45 + core/hif/src/ce/ce_diag.c | 456 + core/hif/src/ce/ce_internal.h | 314 + core/hif/src/ce/ce_main.c | 2593 ++ core/hif/src/ce/ce_main.h | 168 + core/hif/src/ce/ce_reg.h | 478 + core/hif/src/ce/ce_service.c | 1678 ++ core/hif/src/ce/ce_tasklet.c | 404 + core/hif/src/ce/ce_tasklet.h | 35 + core/hif/src/hif_debug.h | 42 + core/hif/src/hif_hw_version.h | 93 + core/hif/src/hif_io32.h | 39 + core/hif/src/hif_main.c | 894 + core/hif/src/hif_main.h | 142 + core/hif/src/hif_napi.c | 444 + core/hif/src/icnss_stub/icnss_stub.c | 342 + core/hif/src/icnss_stub/icnss_stub.h | 134 + core/hif/src/mp_dev.c | 310 + core/hif/src/mp_dev.h | 36 + core/hif/src/pcie/cnss_stub.h | 40 + core/hif/src/pcie/hif_io32_pci.h | 306 + core/hif/src/pcie/if_pci.c | 2239 ++ core/hif/src/pcie/if_pci.h | 115 + core/hif/src/pcie/if_pci_internal.h | 110 + core/hif/src/qca6180def.h | 1008 + core/hif/src/regtable.c | 91 + core/hif/src/snoc/hif_io32_snoc.h | 236 + core/hif/src/snoc/if_snoc.c | 294 + core/htc/dl_list.h | 208 + core/htc/htc.c | 816 + core/htc/htc_api.h | 712 + core/htc/htc_debug.h | 50 + core/htc/htc_internal.h | 310 + core/htc/htc_packet.h | 266 + core/htc/htc_recv.c | 743 + core/htc/htc_send.c | 1850 ++ core/htc/htc_services.c | 368 + core/mac/inc/ani_global.h | 1064 + core/mac/inc/ani_system_defs.h | 216 + core/mac/inc/mac_init_api.h | 50 + core/mac/inc/mac_trace.h | 72 + core/mac/inc/qwlan_version.h | 49 + core/mac/inc/sir_api.h | 5350 ++++ core/mac/inc/sir_mac_prop_exts.h | 119 + core/mac/inc/sir_mac_prot_def.h | 2192 ++ core/mac/inc/sir_types.h | 236 + core/mac/inc/wni_api.h | 539 + core/mac/inc/wni_cfg.h | 1572 ++ core/mac/src/cfg/cfgUtil/cfg.txt | 4474 ++++ core/mac/src/cfg/cfgUtil/dot11f.frms | 3611 +++ core/mac/src/cfg/cfg_api.c | 948 + core/mac/src/cfg/cfg_debug.c | 57 + core/mac/src/cfg/cfg_debug.h | 51 + core/mac/src/cfg/cfg_def.h | 72 + core/mac/src/cfg/cfg_param_name.c | 326 + core/mac/src/cfg/cfg_priv.h | 90 + core/mac/src/cfg/cfg_proc_msg.c | 2607 ++ core/mac/src/cfg/cfg_send_msg.c | 140 + core/mac/src/dph/dph_hash_table.c | 459 + core/mac/src/dph/dph_hash_table.h | 102 + core/mac/src/include/cfg_api.h | 131 + core/mac/src/include/cfg_global.h | 95 + core/mac/src/include/dot11f.h | 8920 +++++++ core/mac/src/include/dph_global.h | 258 + core/mac/src/include/parser_api.h | 965 + core/mac/src/include/sir_common.h | 55 + core/mac/src/include/sir_debug.h | 109 + core/mac/src/include/sir_params.h | 758 + core/mac/src/include/sys_global.h | 52 + core/mac/src/include/utils_api.h | 669 + core/mac/src/include/utils_global.h | 56 + core/mac/src/pe/include/lim_admit_control.h | 106 + core/mac/src/pe/include/lim_api.h | 251 + core/mac/src/pe/include/lim_ft.h | 80 + core/mac/src/pe/include/lim_ft_defs.h | 131 + core/mac/src/pe/include/lim_global.h | 670 + core/mac/src/pe/include/lim_session.h | 612 + core/mac/src/pe/include/lim_trace.h | 99 + core/mac/src/pe/include/rrm_api.h | 104 + core/mac/src/pe/include/rrm_global.h | 228 + core/mac/src/pe/include/sch_api.h | 112 + core/mac/src/pe/include/sch_global.h | 176 + core/mac/src/pe/include/wmm_apsd.h | 50 + core/mac/src/pe/lim/lim_admit_control.c | 1140 + core/mac/src/pe/lim/lim_aid_mgmt.c | 194 + core/mac/src/pe/lim/lim_api.c | 2202 ++ core/mac/src/pe/lim/lim_assoc_utils.c | 5132 ++++ core/mac/src/pe/lim/lim_assoc_utils.h | 212 + core/mac/src/pe/lim/lim_debug.c | 57 + core/mac/src/pe/lim/lim_debug.h | 61 + core/mac/src/pe/lim/lim_ft.c | 2027 ++ core/mac/src/pe/lim/lim_ibss_peer_mgmt.c | 1833 ++ core/mac/src/pe/lim/lim_ibss_peer_mgmt.h | 60 + .../mac/src/pe/lim/lim_link_monitoring_algo.c | 561 + core/mac/src/pe/lim/lim_p2p.c | 794 + .../mac/src/pe/lim/lim_process_action_frame.c | 2093 ++ .../src/pe/lim/lim_process_assoc_req_frame.c | 1921 ++ .../src/pe/lim/lim_process_assoc_rsp_frame.c | 1109 + core/mac/src/pe/lim/lim_process_auth_frame.c | 1929 ++ .../mac/src/pe/lim/lim_process_beacon_frame.c | 250 + core/mac/src/pe/lim/lim_process_cfg_updates.c | 648 + .../mac/src/pe/lim/lim_process_deauth_frame.c | 596 + .../src/pe/lim/lim_process_disassoc_frame.c | 390 + .../src/pe/lim/lim_process_message_queue.c | 2098 ++ .../src/pe/lim/lim_process_mlm_req_messages.c | 2868 ++ .../src/pe/lim/lim_process_mlm_rsp_messages.c | 4200 +++ .../src/pe/lim/lim_process_probe_req_frame.c | 693 + .../src/pe/lim/lim_process_probe_rsp_frame.c | 362 + .../src/pe/lim/lim_process_sme_req_messages.c | 5690 ++++ core/mac/src/pe/lim/lim_process_tdls.c | 3267 +++ core/mac/src/pe/lim/lim_prop_exts_utils.c | 296 + core/mac/src/pe/lim/lim_prop_exts_utils.h | 64 + core/mac/src/pe/lim/lim_scan_result_utils.c | 421 + core/mac/src/pe/lim/lim_scan_result_utils.h | 59 + core/mac/src/pe/lim/lim_security_utils.c | 1075 + core/mac/src/pe/lim/lim_security_utils.h | 95 + .../src/pe/lim/lim_send_management_frames.c | 5130 ++++ core/mac/src/pe/lim/lim_send_messages.c | 854 + core/mac/src/pe/lim/lim_send_messages.h | 126 + .../src/pe/lim/lim_send_sme_rsp_messages.c | 2370 ++ .../src/pe/lim/lim_send_sme_rsp_messages.h | 134 + core/mac/src/pe/lim/lim_ser_des_utils.c | 78 + core/mac/src/pe/lim/lim_ser_des_utils.h | 98 + core/mac/src/pe/lim/lim_session.c | 767 + core/mac/src/pe/lim/lim_session_utils.c | 145 + core/mac/src/pe/lim/lim_session_utils.h | 36 + core/mac/src/pe/lim/lim_sme_req_utils.c | 925 + core/mac/src/pe/lim/lim_sme_req_utils.h | 59 + core/mac/src/pe/lim/lim_sta_hash_api.c | 76 + core/mac/src/pe/lim/lim_sta_hash_api.h | 50 + core/mac/src/pe/lim/lim_timer_utils.c | 1357 + core/mac/src/pe/lim/lim_timer_utils.h | 102 + core/mac/src/pe/lim/lim_trace.c | 483 + core/mac/src/pe/lim/lim_types.h | 867 + core/mac/src/pe/lim/lim_utils.c | 7145 +++++ core/mac/src/pe/lim/lim_utils.h | 591 + core/mac/src/pe/rrm/rrm_api.c | 1495 ++ core/mac/src/pe/sch/sch_api.c | 625 + core/mac/src/pe/sch/sch_beacon_gen.c | 930 + core/mac/src/pe/sch/sch_beacon_process.c | 1011 + core/mac/src/pe/sch/sch_debug.c | 61 + core/mac/src/pe/sch/sch_debug.h | 53 + core/mac/src/pe/sch/sch_message.c | 574 + core/mac/src/pe/sch/sch_sys_params.h | 107 + core/mac/src/sys/common/inc/wlan_qct_sys.h | 194 + core/mac/src/sys/common/src/wlan_qct_sys.c | 371 + .../sys/legacy/src/platform/inc/sys_wrapper.h | 149 + .../sys/legacy/src/platform/src/sys_wrapper.c | 502 + .../src/sys/legacy/src/system/inc/sys_debug.h | 47 + .../src/sys/legacy/src/system/inc/sys_def.h | 168 + .../legacy/src/system/inc/sys_entry_func.h | 53 + .../sys/legacy/src/system/inc/sys_startup.h | 53 + .../sys/legacy/src/system/src/mac_init_api.c | 194 + .../legacy/src/system/src/sys_entry_func.c | 247 + .../src/sys/legacy/src/utils/inc/dot11fdefs.h | 99 + .../sys/legacy/src/utils/inc/utils_parser.h | 98 + .../mac/src/sys/legacy/src/utils/src/dot11f.c | 21682 ++++++++++++++++ .../src/sys/legacy/src/utils/src/log_api.c | 200 + .../src/sys/legacy/src/utils/src/mac_trace.c | 759 + .../src/sys/legacy/src/utils/src/parser_api.c | 5654 ++++ .../src/sys/legacy/src/utils/src/utils_api.c | 91 + .../sys/legacy/src/utils/src/utils_parser.c | 827 + core/sap/dfs/inc/ath_dfs_structs.h | 257 + core/sap/dfs/inc/dfs.h | 824 + core/sap/dfs/inc/dfs_interface.h | 171 + core/sap/dfs/inc/radar_filters.h | 142 + core/sap/dfs/sources | 62 + core/sap/dfs/src/dfs.c | 993 + core/sap/dfs/src/dfs_bindetects.c | 485 + core/sap/dfs/src/dfs_debug.c | 160 + core/sap/dfs/src/dfs_fcc_bin5.c | 874 + core/sap/dfs/src/dfs_init.c | 403 + core/sap/dfs/src/dfs_ioctl.h | 117 + core/sap/dfs/src/dfs_ioctl_private.h | 100 + core/sap/dfs/src/dfs_misc.c | 276 + core/sap/dfs/src/dfs_nol.c | 405 + core/sap/dfs/src/dfs_phyerr.h | 50 + core/sap/dfs/src/dfs_phyerr_tlv.c | 726 + core/sap/dfs/src/dfs_phyerr_tlv.h | 206 + core/sap/dfs/src/dfs_process_phyerr.c | 855 + core/sap/dfs/src/dfs_process_radarevent.c | 799 + core/sap/dfs/src/dfs_staggered.c | 308 + core/sap/inc/sap_api.h | 920 + core/sap/src/sap_api_link_cntl.c | 1209 + core/sap/src/sap_ch_select.c | 2030 ++ core/sap/src/sap_ch_select.h | 187 + core/sap/src/sap_fsm.c | 4754 ++++ core/sap/src/sap_fsm_ext.h | 61 + core/sap/src/sap_internal.h | 430 + core/sap/src/sap_module.c | 3272 +++ core/sme/inc/csr_api.h | 1644 ++ core/sme/inc/csr_internal.h | 1403 + core/sme/inc/csr_link_list.h | 110 + core/sme/inc/csr_neighbor_roam.h | 311 + core/sme/inc/csr_support.h | 378 + core/sme/inc/nan_api.h | 51 + core/sme/inc/oem_data_api.h | 87 + core/sme/inc/oem_data_internal.h | 68 + core/sme/inc/p2p_api.h | 113 + core/sme/inc/sme_api.h | 1027 + core/sme/inc/sme_ft_api.h | 107 + core/sme/inc/sme_inside.h | 287 + core/sme/inc/sme_internal.h | 223 + core/sme/inc/sme_power_save.h | 152 + core/sme/inc/sme_power_save_api.h | 97 + core/sme/inc/sme_qos_api.h | 257 + core/sme/inc/sme_qos_internal.h | 138 + core/sme/inc/sme_rrm_api.h | 67 + core/sme/inc/sme_rrm_internal.h | 108 + core/sme/inc/sme_trace.h | 137 + core/sme/inc/sms_debug.h | 48 + core/sme/inc/wlan_ps_wow_diag.h | 136 + core/sme/src/common/sme_api.c | 14610 +++++++++++ core/sme/src/common/sme_ft_api.c | 634 + core/sme/src/common/sme_power_save.c | 1214 + core/sme/src/common/sme_trace.c | 209 + core/sme/src/csr/csr_api_roam.c | 18860 ++++++++++++++ core/sme/src/csr/csr_api_scan.c | 6941 +++++ core/sme/src/csr/csr_cmd_process.c | 189 + core/sme/src/csr/csr_inside_api.h | 1070 + core/sme/src/csr/csr_link_list.c | 571 + core/sme/src/csr/csr_neighbor_roam.c | 3541 +++ core/sme/src/csr/csr_tdls_process.c | 820 + core/sme/src/csr/csr_util.c | 5626 ++++ core/sme/src/nan/nan_api.c | 145 + core/sme/src/oem_data/oem_data_api.c | 391 + core/sme/src/p2p/p2p_api.c | 419 + core/sme/src/qos/sme_qos.c | 7834 ++++++ core/sme/src/rrm/sme_rrm.c | 1566 ++ core/utils/epping/inc/epping_internal.h | 197 + core/utils/epping/inc/epping_main.h | 55 + core/utils/epping/src/epping_helper.c | 213 + core/utils/epping/src/epping_main.c | 303 + core/utils/epping/src/epping_rx.c | 161 + core/utils/epping/src/epping_tx.c | 385 + core/utils/epping/src/epping_txrx.c | 457 + core/utils/fwlog/dbglog_host.c | 4464 ++++ core/utils/fwlog/dbglog_host.h | 127 + .../host_diag_log/inc/host_diag_core_event.h | 362 + .../host_diag_log/inc/host_diag_core_log.h | 380 + .../host_diag_log/inc/host_diag_event_defs.h | 61 + core/utils/host_diag_log/inc/log_codes.h | 2078 ++ core/utils/host_diag_log/src/host_diag_log.c | 264 + .../src/i_host_diag_core_event.h | 102 + .../host_diag_log/src/i_host_diag_core_log.h | 132 + .../utils/logging/inc/wlan_logging_sock_svc.h | 61 + .../utils/logging/src/wlan_logging_sock_svc.c | 817 + core/utils/nlink/inc/wlan_nlink_common.h | 139 + core/utils/nlink/inc/wlan_nlink_srv.h | 60 + core/utils/nlink/src/wlan_nlink_srv.c | 309 + core/utils/pktlog/include/pktlog.h | 39 + core/utils/pktlog/include/pktlog_ac.h | 163 + core/utils/pktlog/include/pktlog_ac_api.h | 115 + core/utils/pktlog/include/pktlog_ac_i.h | 67 + core/utils/pktlog/linux_ac.c | 1183 + core/utils/pktlog/pktlog_ac.c | 449 + core/utils/pktlog/pktlog_internal.c | 680 + core/utils/ptt/inc/wlan_ptt_sock_svc.h | 118 + core/utils/ptt/src/wlan_ptt_sock_svc.c | 229 + core/wma/inc/wma.h | 1981 ++ core/wma/inc/wma_api.h | 220 + core/wma/inc/wma_dfs_interface.h | 252 + core/wma/inc/wma_if.h | 1429 + core/wma/inc/wma_internal.h | 1097 + core/wma/inc/wma_tgt_cfg.h | 167 + core/wma/inc/wma_types.h | 679 + core/wma/src/wlan_qct_wma_legacy.c | 157 + core/wma/src/wma_data.c | 3084 +++ core/wma/src/wma_dev_if.c | 4470 ++++ core/wma/src/wma_dfs_interface.c | 245 + core/wma/src/wma_features.c | 7171 +++++ core/wma/src/wma_main.c | 5382 ++++ core/wma/src/wma_mgmt.c | 3208 +++ core/wma/src/wma_ocb.c | 1119 + core/wma/src/wma_ocb.h | 68 + core/wma/src/wma_power.c | 2250 ++ core/wma/src/wma_scan_roam.c | 6886 +++++ core/wma/src/wma_utils.c | 3526 +++ core/wma/src/wma_utils_ut.c | 82 + core/wmi/wmi_tlv_helper.c | 1190 + core/wmi/wmi_tlv_platform.c | 58 + core/wmi/wmi_unified.c | 1222 + core/wmi/wmi_unified_api.h | 160 + core/wmi/wmi_unified_priv.h | 95 + core/wmi/wmi_version_whitelist.c | 38 + target/inc/a_osapi.h | 71 + target/inc/a_usb_defs.h | 97 + target/inc/apb_athr_wlan_map.h | 59 + target/inc/athdefs.h | 83 + target/inc/athendpack.h | 35 + target/inc/bin_sig.h | 45 + target/inc/bmi_msg.h | 364 + target/inc/cepci.h | 125 + target/inc/dbglog.h | 168 + target/inc/dbglog_id.h | 1586 ++ target/inc/efuse_reg.h | 154 + target/inc/enet.h | 148 + target/inc/epping_test.h | 124 + target/inc/htc.h | 405 + target/inc/htc_services.h | 95 + target/inc/htt.h | 7034 +++++ target/inc/htt_common.h | 120 + target/inc/htt_isoc.h | 1058 + target/inc/ip_prot.h | 58 + target/inc/ipv4.h | 55 + target/inc/ol_fw_tx_dbg.h | 184 + target/inc/rtc_soc_reg.h | 1966 ++ target/inc/targaddrs.h | 673 + target/inc/targcfg.h | 53 + target/inc/wal_rx_desc.h | 127 + target/inc/wlan_defs.h | 800 + target/inc/wlan_module_ids.h | 103 + target/inc/wlan_tgt_def_config.h | 259 + target/inc/wmi.h | 188 + target/inc/wmi_services.h | 162 + target/inc/wmi_tlv_defs.h | 2996 +++ target/inc/wmi_tlv_helper.h | 160 + target/inc/wmi_unified.h | 12299 +++++++++ target/inc/wmi_version.h | 80 + target/inc/wmix.h | 182 + uapi/linux/a_debug.h | 202 + uapi/linux/a_types.h | 52 + uapi/linux/athstartpack.h | 48 + uapi/linux/dbglog_common.h | 142 + uapi/linux/debug_linux.h | 50 + uapi/linux/osapi_linux.h | 293 + uapi/linux/pktlog_ac_fmt.h | 267 + 547 files changed, 531140 insertions(+) create mode 100644 Android.mk create mode 100644 Kbuild create mode 100644 Kconfig create mode 100644 Makefile create mode 100644 config/WCNSS_qcom_cfg.ini create mode 100644 core/bmi/inc/bmi.h create mode 100644 core/bmi/inc/ol_fw.h create mode 100644 core/bmi/inc/ol_if_athvar.h create mode 100644 core/bmi/src/bmi.c create mode 100644 core/bmi/src/bmi_1.c create mode 100644 core/bmi/src/bmi_2.c create mode 100644 core/bmi/src/i_ar6320v2_regtable.h create mode 100644 core/bmi/src/i_bmi.h create mode 100644 core/bmi/src/ol_fw.c create mode 100644 core/cdf/inc/cdf_atomic.h create mode 100644 core/cdf/inc/cdf_defer.h create mode 100644 core/cdf/inc/cdf_event.h create mode 100644 core/cdf/inc/cdf_list.h create mode 100644 core/cdf/inc/cdf_lock.h create mode 100644 core/cdf/inc/cdf_mc_timer.h create mode 100644 core/cdf/inc/cdf_memory.h create mode 100644 core/cdf/inc/cdf_nbuf.h create mode 100644 core/cdf/inc/cdf_net_types.h create mode 100644 core/cdf/inc/cdf_softirq_timer.h create mode 100644 core/cdf/inc/cdf_status.h create mode 100644 core/cdf/inc/cdf_threads.h create mode 100644 core/cdf/inc/cdf_time.h create mode 100644 core/cdf/inc/cdf_trace.h create mode 100644 core/cdf/inc/cdf_types.h create mode 100644 core/cdf/inc/cdf_util.h create mode 100644 core/cdf/inc/osdep.h create mode 100644 core/cdf/src/cdf_defer.c create mode 100644 core/cdf/src/cdf_event.c create mode 100644 core/cdf/src/cdf_list.c create mode 100644 core/cdf/src/cdf_lock.c create mode 100644 core/cdf/src/cdf_mc_timer.c create mode 100644 core/cdf/src/cdf_memory.c create mode 100644 core/cdf/src/cdf_nbuf.c create mode 100644 core/cdf/src/cdf_threads.c create mode 100644 core/cdf/src/cdf_trace.c create mode 100644 core/cdf/src/i_cdf_atomic.h create mode 100644 core/cdf/src/i_cdf_defer.h create mode 100644 core/cdf/src/i_cdf_event.h create mode 100644 core/cdf/src/i_cdf_lock.h create mode 100644 core/cdf/src/i_cdf_mc_timer.h create mode 100644 core/cdf/src/i_cdf_nbuf.h create mode 100644 core/cdf/src/i_cdf_softirq_timer.h create mode 100644 core/cdf/src/i_cdf_time.h create mode 100644 core/cdf/src/i_cdf_trace.h create mode 100644 core/cdf/src/i_cdf_types.h create mode 100644 core/cdf/src/i_cdf_util.h create mode 100644 core/cds/inc/cds_api.h create mode 100644 core/cds/inc/cds_concurrency.h create mode 100644 core/cds/inc/cds_crypto.h create mode 100644 core/cds/inc/cds_get_bin.h create mode 100644 core/cds/inc/cds_ieee80211_common.h create mode 100644 core/cds/inc/cds_ieee80211_defines.h create mode 100644 core/cds/inc/cds_if_upperproto.h create mode 100644 core/cds/inc/cds_mq.h create mode 100644 core/cds/inc/cds_pack_align.h create mode 100644 core/cds/inc/cds_packet.h create mode 100644 core/cds/inc/cds_queue.h create mode 100644 core/cds/inc/cds_reg_service.h create mode 100644 core/cds/inc/cds_regdomain.h create mode 100644 core/cds/inc/cds_regdomain_common.h create mode 100644 core/cds/inc/cds_sched.h create mode 100644 core/cds/inc/cds_utils.h create mode 100644 core/cds/src/cds_api.c create mode 100644 core/cds/src/cds_concurrency.c create mode 100644 core/cds/src/cds_get_bin.c create mode 100644 core/cds/src/cds_ieee80211_common_i.h create mode 100644 core/cds/src/cds_mq.c create mode 100644 core/cds/src/cds_packet.c create mode 100644 core/cds/src/cds_reg_service.c create mode 100644 core/cds/src/cds_regdomain.c create mode 100644 core/cds/src/cds_sched.c create mode 100644 core/cds/src/cds_utils.c create mode 100644 core/cds/src/i_cds_packet.h create mode 100644 core/cds/src/queue.h create mode 100644 core/dp/htt/htt.c create mode 100644 core/dp/htt/htt_fw_stats.c create mode 100644 core/dp/htt/htt_h2t.c create mode 100644 core/dp/htt/htt_internal.h create mode 100644 core/dp/htt/htt_rx.c create mode 100644 core/dp/htt/htt_t2h.c create mode 100644 core/dp/htt/htt_tx.c create mode 100644 core/dp/htt/htt_types.h create mode 100644 core/dp/htt/rx_desc.h create mode 100644 core/dp/ol/inc/ol_cfg.h create mode 100644 core/dp/ol/inc/ol_ctrl_addba_api.h create mode 100644 core/dp/ol/inc/ol_ctrl_api.h create mode 100644 core/dp/ol/inc/ol_defines.h create mode 100644 core/dp/ol/inc/ol_htt_api.h create mode 100644 core/dp/ol/inc/ol_htt_rx_api.h create mode 100644 core/dp/ol/inc/ol_htt_tx_api.h create mode 100644 core/dp/ol/inc/ol_osif_api.h create mode 100644 core/dp/ol/inc/ol_params.h create mode 100644 core/dp/ol/inc/ol_txrx_api.h create mode 100644 core/dp/ol/inc/ol_txrx_ctrl_api.h create mode 100644 core/dp/ol/inc/ol_txrx_dbg.h create mode 100644 core/dp/ol/inc/ol_txrx_htt_api.h create mode 100644 core/dp/ol/inc/ol_txrx_osif_api.h create mode 100644 core/dp/ol/inc/ol_txrx_stats.h create mode 100644 core/dp/ol/inc/ol_vowext_dbg_defs.h create mode 100644 core/dp/txrx/ipv6_defs.h create mode 100644 core/dp/txrx/ol_cfg.c create mode 100644 core/dp/txrx/ol_ctrl_txrx_api.h create mode 100644 core/dp/txrx/ol_osif_txrx_api.h create mode 100644 core/dp/txrx/ol_rx.c create mode 100644 core/dp/txrx/ol_rx.h create mode 100644 core/dp/txrx/ol_rx_defrag.c create mode 100644 core/dp/txrx/ol_rx_defrag.h create mode 100644 core/dp/txrx/ol_rx_fwd.c create mode 100644 core/dp/txrx/ol_rx_fwd.h create mode 100644 core/dp/txrx/ol_rx_pn.c create mode 100644 core/dp/txrx/ol_rx_pn.h create mode 100644 core/dp/txrx/ol_rx_reorder.c create mode 100644 core/dp/txrx/ol_rx_reorder.h create mode 100644 core/dp/txrx/ol_rx_reorder_timeout.c create mode 100644 core/dp/txrx/ol_rx_reorder_timeout.h create mode 100644 core/dp/txrx/ol_tx.c create mode 100644 core/dp/txrx/ol_tx.h create mode 100644 core/dp/txrx/ol_tx_desc.c create mode 100644 core/dp/txrx/ol_tx_desc.h create mode 100644 core/dp/txrx/ol_tx_queue.c create mode 100644 core/dp/txrx/ol_tx_queue.h create mode 100644 core/dp/txrx/ol_tx_send.c create mode 100644 core/dp/txrx/ol_tx_send.h create mode 100644 core/dp/txrx/ol_txrx.c create mode 100644 core/dp/txrx/ol_txrx.h create mode 100644 core/dp/txrx/ol_txrx_encap.c create mode 100644 core/dp/txrx/ol_txrx_encap.h create mode 100644 core/dp/txrx/ol_txrx_event.c create mode 100644 core/dp/txrx/ol_txrx_flow_control.c create mode 100644 core/dp/txrx/ol_txrx_internal.h create mode 100644 core/dp/txrx/ol_txrx_peer_find.c create mode 100644 core/dp/txrx/ol_txrx_peer_find.h create mode 100644 core/dp/txrx/ol_txrx_types.h create mode 100644 core/dp/txrx/txrx.h create mode 100644 core/dp/txrx/wdi_event.h create mode 100644 core/dp/txrx/wdi_event_api.h create mode 100644 core/hdd/inc/qc_sap_ioctl.h create mode 100644 core/hdd/inc/wlan_hdd_assoc.h create mode 100644 core/hdd/inc/wlan_hdd_cfg.h create mode 100644 core/hdd/inc/wlan_hdd_conc_ut.h create mode 100644 core/hdd/inc/wlan_hdd_debugfs.h create mode 100644 core/hdd/inc/wlan_hdd_driver_ops.h create mode 100644 core/hdd/inc/wlan_hdd_ether.h create mode 100644 core/hdd/inc/wlan_hdd_ftm.h create mode 100644 core/hdd/inc/wlan_hdd_host_offload.h create mode 100644 core/hdd/inc/wlan_hdd_includes.h create mode 100644 core/hdd/inc/wlan_hdd_ipa.h create mode 100644 core/hdd/inc/wlan_hdd_lro.h create mode 100644 core/hdd/inc/wlan_hdd_main.h create mode 100644 core/hdd/inc/wlan_hdd_memdump.h create mode 100644 core/hdd/inc/wlan_hdd_mib.h create mode 100644 core/hdd/inc/wlan_hdd_misc.h create mode 100644 core/hdd/inc/wlan_hdd_nan.h create mode 100644 core/hdd/inc/wlan_hdd_napi.h create mode 100644 core/hdd/inc/wlan_hdd_oemdata.h create mode 100644 core/hdd/inc/wlan_hdd_p2p.h create mode 100644 core/hdd/inc/wlan_hdd_power.h create mode 100644 core/hdd/inc/wlan_hdd_softap_tx_rx.h create mode 100644 core/hdd/inc/wlan_hdd_tdls.h create mode 100644 core/hdd/inc/wlan_hdd_trace.h create mode 100644 core/hdd/inc/wlan_hdd_tx_rx.h create mode 100644 core/hdd/inc/wlan_hdd_wext.h create mode 100644 core/hdd/inc/wlan_hdd_wmm.h create mode 100644 core/hdd/inc/wlan_hdd_wowl.h create mode 100644 core/hdd/src/wlan_hdd_assoc.c create mode 100644 core/hdd/src/wlan_hdd_cfg.c create mode 100644 core/hdd/src/wlan_hdd_cfg80211.c create mode 100644 core/hdd/src/wlan_hdd_cfg80211.h create mode 100644 core/hdd/src/wlan_hdd_conc_ut.c create mode 100644 core/hdd/src/wlan_hdd_debugfs.c create mode 100644 core/hdd/src/wlan_hdd_driver_ops.c create mode 100644 core/hdd/src/wlan_hdd_ext_scan.c create mode 100644 core/hdd/src/wlan_hdd_ext_scan.h create mode 100644 core/hdd/src/wlan_hdd_ftm.c create mode 100644 core/hdd/src/wlan_hdd_green_ap.c create mode 100644 core/hdd/src/wlan_hdd_green_ap.h create mode 100644 core/hdd/src/wlan_hdd_hostapd.c create mode 100644 core/hdd/src/wlan_hdd_hostapd.h create mode 100644 core/hdd/src/wlan_hdd_ioctl.c create mode 100644 core/hdd/src/wlan_hdd_ioctl.h create mode 100644 core/hdd/src/wlan_hdd_ipa.c create mode 100644 core/hdd/src/wlan_hdd_lro.c create mode 100644 core/hdd/src/wlan_hdd_main.c create mode 100644 core/hdd/src/wlan_hdd_memdump.c create mode 100644 core/hdd/src/wlan_hdd_nan.c create mode 100644 core/hdd/src/wlan_hdd_napi.c create mode 100644 core/hdd/src/wlan_hdd_ocb.c create mode 100644 core/hdd/src/wlan_hdd_ocb.h create mode 100644 core/hdd/src/wlan_hdd_oemdata.c create mode 100644 core/hdd/src/wlan_hdd_p2p.c create mode 100644 core/hdd/src/wlan_hdd_power.c create mode 100644 core/hdd/src/wlan_hdd_scan.c create mode 100644 core/hdd/src/wlan_hdd_scan.h create mode 100644 core/hdd/src/wlan_hdd_softap_tx_rx.c create mode 100644 core/hdd/src/wlan_hdd_stats.c create mode 100644 core/hdd/src/wlan_hdd_stats.h create mode 100644 core/hdd/src/wlan_hdd_tdls.c create mode 100644 core/hdd/src/wlan_hdd_trace.c create mode 100644 core/hdd/src/wlan_hdd_tx_rx.c create mode 100644 core/hdd/src/wlan_hdd_wext.c create mode 100644 core/hdd/src/wlan_hdd_wmm.c create mode 100644 core/hdd/src/wlan_hdd_wowl.c create mode 100644 core/hif/inc/hif.h create mode 100644 core/hif/inc/hif_napi.h create mode 100644 core/hif/inc/regtable.h create mode 100644 core/hif/inc/regtable_ce.h create mode 100644 core/hif/inc/regtable_pcie.h create mode 100644 core/hif/src/adrastea_reg_def.h create mode 100644 core/hif/src/ar6320def.h create mode 100644 core/hif/src/ar6320v2def.h create mode 100644 core/hif/src/ar9888def.h create mode 100644 core/hif/src/ath_procfs.c create mode 100644 core/hif/src/ce/ce_api.h create mode 100644 core/hif/src/ce/ce_assignment.h create mode 100644 core/hif/src/ce/ce_bmi.c create mode 100644 core/hif/src/ce/ce_bmi.h create mode 100644 core/hif/src/ce/ce_diag.c create mode 100644 core/hif/src/ce/ce_internal.h create mode 100644 core/hif/src/ce/ce_main.c create mode 100644 core/hif/src/ce/ce_main.h create mode 100644 core/hif/src/ce/ce_reg.h create mode 100644 core/hif/src/ce/ce_service.c create mode 100644 core/hif/src/ce/ce_tasklet.c create mode 100644 core/hif/src/ce/ce_tasklet.h create mode 100644 core/hif/src/hif_debug.h create mode 100644 core/hif/src/hif_hw_version.h create mode 100644 core/hif/src/hif_io32.h create mode 100644 core/hif/src/hif_main.c create mode 100644 core/hif/src/hif_main.h create mode 100644 core/hif/src/hif_napi.c create mode 100644 core/hif/src/icnss_stub/icnss_stub.c create mode 100644 core/hif/src/icnss_stub/icnss_stub.h create mode 100644 core/hif/src/mp_dev.c create mode 100644 core/hif/src/mp_dev.h create mode 100644 core/hif/src/pcie/cnss_stub.h create mode 100644 core/hif/src/pcie/hif_io32_pci.h create mode 100644 core/hif/src/pcie/if_pci.c create mode 100644 core/hif/src/pcie/if_pci.h create mode 100644 core/hif/src/pcie/if_pci_internal.h create mode 100644 core/hif/src/qca6180def.h create mode 100644 core/hif/src/regtable.c create mode 100644 core/hif/src/snoc/hif_io32_snoc.h create mode 100644 core/hif/src/snoc/if_snoc.c create mode 100644 core/htc/dl_list.h create mode 100644 core/htc/htc.c create mode 100644 core/htc/htc_api.h create mode 100644 core/htc/htc_debug.h create mode 100644 core/htc/htc_internal.h create mode 100644 core/htc/htc_packet.h create mode 100644 core/htc/htc_recv.c create mode 100644 core/htc/htc_send.c create mode 100644 core/htc/htc_services.c create mode 100644 core/mac/inc/ani_global.h create mode 100644 core/mac/inc/ani_system_defs.h create mode 100644 core/mac/inc/mac_init_api.h create mode 100644 core/mac/inc/mac_trace.h create mode 100644 core/mac/inc/qwlan_version.h create mode 100644 core/mac/inc/sir_api.h create mode 100644 core/mac/inc/sir_mac_prop_exts.h create mode 100644 core/mac/inc/sir_mac_prot_def.h create mode 100644 core/mac/inc/sir_types.h create mode 100644 core/mac/inc/wni_api.h create mode 100644 core/mac/inc/wni_cfg.h create mode 100644 core/mac/src/cfg/cfgUtil/cfg.txt create mode 100644 core/mac/src/cfg/cfgUtil/dot11f.frms create mode 100644 core/mac/src/cfg/cfg_api.c create mode 100644 core/mac/src/cfg/cfg_debug.c create mode 100644 core/mac/src/cfg/cfg_debug.h create mode 100644 core/mac/src/cfg/cfg_def.h create mode 100644 core/mac/src/cfg/cfg_param_name.c create mode 100644 core/mac/src/cfg/cfg_priv.h create mode 100644 core/mac/src/cfg/cfg_proc_msg.c create mode 100644 core/mac/src/cfg/cfg_send_msg.c create mode 100644 core/mac/src/dph/dph_hash_table.c create mode 100644 core/mac/src/dph/dph_hash_table.h create mode 100644 core/mac/src/include/cfg_api.h create mode 100644 core/mac/src/include/cfg_global.h create mode 100644 core/mac/src/include/dot11f.h create mode 100644 core/mac/src/include/dph_global.h create mode 100644 core/mac/src/include/parser_api.h create mode 100644 core/mac/src/include/sir_common.h create mode 100644 core/mac/src/include/sir_debug.h create mode 100644 core/mac/src/include/sir_params.h create mode 100644 core/mac/src/include/sys_global.h create mode 100644 core/mac/src/include/utils_api.h create mode 100644 core/mac/src/include/utils_global.h create mode 100644 core/mac/src/pe/include/lim_admit_control.h create mode 100644 core/mac/src/pe/include/lim_api.h create mode 100644 core/mac/src/pe/include/lim_ft.h create mode 100644 core/mac/src/pe/include/lim_ft_defs.h create mode 100644 core/mac/src/pe/include/lim_global.h create mode 100644 core/mac/src/pe/include/lim_session.h create mode 100644 core/mac/src/pe/include/lim_trace.h create mode 100644 core/mac/src/pe/include/rrm_api.h create mode 100644 core/mac/src/pe/include/rrm_global.h create mode 100644 core/mac/src/pe/include/sch_api.h create mode 100644 core/mac/src/pe/include/sch_global.h create mode 100644 core/mac/src/pe/include/wmm_apsd.h create mode 100644 core/mac/src/pe/lim/lim_admit_control.c create mode 100644 core/mac/src/pe/lim/lim_aid_mgmt.c create mode 100644 core/mac/src/pe/lim/lim_api.c create mode 100644 core/mac/src/pe/lim/lim_assoc_utils.c create mode 100644 core/mac/src/pe/lim/lim_assoc_utils.h create mode 100644 core/mac/src/pe/lim/lim_debug.c create mode 100644 core/mac/src/pe/lim/lim_debug.h create mode 100644 core/mac/src/pe/lim/lim_ft.c create mode 100644 core/mac/src/pe/lim/lim_ibss_peer_mgmt.c create mode 100644 core/mac/src/pe/lim/lim_ibss_peer_mgmt.h create mode 100644 core/mac/src/pe/lim/lim_link_monitoring_algo.c create mode 100644 core/mac/src/pe/lim/lim_p2p.c create mode 100644 core/mac/src/pe/lim/lim_process_action_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_assoc_req_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_auth_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_beacon_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_cfg_updates.c create mode 100644 core/mac/src/pe/lim/lim_process_deauth_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_disassoc_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_message_queue.c create mode 100644 core/mac/src/pe/lim/lim_process_mlm_req_messages.c create mode 100644 core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c create mode 100644 core/mac/src/pe/lim/lim_process_probe_req_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_probe_rsp_frame.c create mode 100644 core/mac/src/pe/lim/lim_process_sme_req_messages.c create mode 100644 core/mac/src/pe/lim/lim_process_tdls.c create mode 100644 core/mac/src/pe/lim/lim_prop_exts_utils.c create mode 100644 core/mac/src/pe/lim/lim_prop_exts_utils.h create mode 100644 core/mac/src/pe/lim/lim_scan_result_utils.c create mode 100644 core/mac/src/pe/lim/lim_scan_result_utils.h create mode 100644 core/mac/src/pe/lim/lim_security_utils.c create mode 100644 core/mac/src/pe/lim/lim_security_utils.h create mode 100644 core/mac/src/pe/lim/lim_send_management_frames.c create mode 100644 core/mac/src/pe/lim/lim_send_messages.c create mode 100644 core/mac/src/pe/lim/lim_send_messages.h create mode 100644 core/mac/src/pe/lim/lim_send_sme_rsp_messages.c create mode 100644 core/mac/src/pe/lim/lim_send_sme_rsp_messages.h create mode 100644 core/mac/src/pe/lim/lim_ser_des_utils.c create mode 100644 core/mac/src/pe/lim/lim_ser_des_utils.h create mode 100644 core/mac/src/pe/lim/lim_session.c create mode 100644 core/mac/src/pe/lim/lim_session_utils.c create mode 100644 core/mac/src/pe/lim/lim_session_utils.h create mode 100644 core/mac/src/pe/lim/lim_sme_req_utils.c create mode 100644 core/mac/src/pe/lim/lim_sme_req_utils.h create mode 100644 core/mac/src/pe/lim/lim_sta_hash_api.c create mode 100644 core/mac/src/pe/lim/lim_sta_hash_api.h create mode 100644 core/mac/src/pe/lim/lim_timer_utils.c create mode 100644 core/mac/src/pe/lim/lim_timer_utils.h create mode 100644 core/mac/src/pe/lim/lim_trace.c create mode 100644 core/mac/src/pe/lim/lim_types.h create mode 100644 core/mac/src/pe/lim/lim_utils.c create mode 100644 core/mac/src/pe/lim/lim_utils.h create mode 100644 core/mac/src/pe/rrm/rrm_api.c create mode 100644 core/mac/src/pe/sch/sch_api.c create mode 100644 core/mac/src/pe/sch/sch_beacon_gen.c create mode 100644 core/mac/src/pe/sch/sch_beacon_process.c create mode 100644 core/mac/src/pe/sch/sch_debug.c create mode 100644 core/mac/src/pe/sch/sch_debug.h create mode 100644 core/mac/src/pe/sch/sch_message.c create mode 100644 core/mac/src/pe/sch/sch_sys_params.h create mode 100644 core/mac/src/sys/common/inc/wlan_qct_sys.h create mode 100644 core/mac/src/sys/common/src/wlan_qct_sys.c create mode 100644 core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h create mode 100644 core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c create mode 100644 core/mac/src/sys/legacy/src/system/inc/sys_debug.h create mode 100644 core/mac/src/sys/legacy/src/system/inc/sys_def.h create mode 100644 core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h create mode 100644 core/mac/src/sys/legacy/src/system/inc/sys_startup.h create mode 100644 core/mac/src/sys/legacy/src/system/src/mac_init_api.c create mode 100644 core/mac/src/sys/legacy/src/system/src/sys_entry_func.c create mode 100644 core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h create mode 100644 core/mac/src/sys/legacy/src/utils/inc/utils_parser.h create mode 100644 core/mac/src/sys/legacy/src/utils/src/dot11f.c create mode 100644 core/mac/src/sys/legacy/src/utils/src/log_api.c create mode 100644 core/mac/src/sys/legacy/src/utils/src/mac_trace.c create mode 100644 core/mac/src/sys/legacy/src/utils/src/parser_api.c create mode 100644 core/mac/src/sys/legacy/src/utils/src/utils_api.c create mode 100644 core/mac/src/sys/legacy/src/utils/src/utils_parser.c create mode 100644 core/sap/dfs/inc/ath_dfs_structs.h create mode 100644 core/sap/dfs/inc/dfs.h create mode 100644 core/sap/dfs/inc/dfs_interface.h create mode 100644 core/sap/dfs/inc/radar_filters.h create mode 100644 core/sap/dfs/sources create mode 100644 core/sap/dfs/src/dfs.c create mode 100644 core/sap/dfs/src/dfs_bindetects.c create mode 100644 core/sap/dfs/src/dfs_debug.c create mode 100644 core/sap/dfs/src/dfs_fcc_bin5.c create mode 100644 core/sap/dfs/src/dfs_init.c create mode 100644 core/sap/dfs/src/dfs_ioctl.h create mode 100644 core/sap/dfs/src/dfs_ioctl_private.h create mode 100644 core/sap/dfs/src/dfs_misc.c create mode 100644 core/sap/dfs/src/dfs_nol.c create mode 100644 core/sap/dfs/src/dfs_phyerr.h create mode 100644 core/sap/dfs/src/dfs_phyerr_tlv.c create mode 100644 core/sap/dfs/src/dfs_phyerr_tlv.h create mode 100644 core/sap/dfs/src/dfs_process_phyerr.c create mode 100644 core/sap/dfs/src/dfs_process_radarevent.c create mode 100644 core/sap/dfs/src/dfs_staggered.c create mode 100644 core/sap/inc/sap_api.h create mode 100644 core/sap/src/sap_api_link_cntl.c create mode 100644 core/sap/src/sap_ch_select.c create mode 100644 core/sap/src/sap_ch_select.h create mode 100644 core/sap/src/sap_fsm.c create mode 100644 core/sap/src/sap_fsm_ext.h create mode 100644 core/sap/src/sap_internal.h create mode 100644 core/sap/src/sap_module.c create mode 100644 core/sme/inc/csr_api.h create mode 100644 core/sme/inc/csr_internal.h create mode 100644 core/sme/inc/csr_link_list.h create mode 100644 core/sme/inc/csr_neighbor_roam.h create mode 100644 core/sme/inc/csr_support.h create mode 100644 core/sme/inc/nan_api.h create mode 100644 core/sme/inc/oem_data_api.h create mode 100644 core/sme/inc/oem_data_internal.h create mode 100644 core/sme/inc/p2p_api.h create mode 100644 core/sme/inc/sme_api.h create mode 100644 core/sme/inc/sme_ft_api.h create mode 100644 core/sme/inc/sme_inside.h create mode 100644 core/sme/inc/sme_internal.h create mode 100644 core/sme/inc/sme_power_save.h create mode 100644 core/sme/inc/sme_power_save_api.h create mode 100644 core/sme/inc/sme_qos_api.h create mode 100644 core/sme/inc/sme_qos_internal.h create mode 100644 core/sme/inc/sme_rrm_api.h create mode 100644 core/sme/inc/sme_rrm_internal.h create mode 100644 core/sme/inc/sme_trace.h create mode 100644 core/sme/inc/sms_debug.h create mode 100644 core/sme/inc/wlan_ps_wow_diag.h create mode 100644 core/sme/src/common/sme_api.c create mode 100644 core/sme/src/common/sme_ft_api.c create mode 100644 core/sme/src/common/sme_power_save.c create mode 100644 core/sme/src/common/sme_trace.c create mode 100644 core/sme/src/csr/csr_api_roam.c create mode 100644 core/sme/src/csr/csr_api_scan.c create mode 100644 core/sme/src/csr/csr_cmd_process.c create mode 100644 core/sme/src/csr/csr_inside_api.h create mode 100644 core/sme/src/csr/csr_link_list.c create mode 100644 core/sme/src/csr/csr_neighbor_roam.c create mode 100644 core/sme/src/csr/csr_tdls_process.c create mode 100644 core/sme/src/csr/csr_util.c create mode 100644 core/sme/src/nan/nan_api.c create mode 100644 core/sme/src/oem_data/oem_data_api.c create mode 100644 core/sme/src/p2p/p2p_api.c create mode 100644 core/sme/src/qos/sme_qos.c create mode 100644 core/sme/src/rrm/sme_rrm.c create mode 100644 core/utils/epping/inc/epping_internal.h create mode 100644 core/utils/epping/inc/epping_main.h create mode 100644 core/utils/epping/src/epping_helper.c create mode 100644 core/utils/epping/src/epping_main.c create mode 100644 core/utils/epping/src/epping_rx.c create mode 100644 core/utils/epping/src/epping_tx.c create mode 100644 core/utils/epping/src/epping_txrx.c create mode 100644 core/utils/fwlog/dbglog_host.c create mode 100644 core/utils/fwlog/dbglog_host.h create mode 100644 core/utils/host_diag_log/inc/host_diag_core_event.h create mode 100644 core/utils/host_diag_log/inc/host_diag_core_log.h create mode 100644 core/utils/host_diag_log/inc/host_diag_event_defs.h create mode 100644 core/utils/host_diag_log/inc/log_codes.h create mode 100644 core/utils/host_diag_log/src/host_diag_log.c create mode 100644 core/utils/host_diag_log/src/i_host_diag_core_event.h create mode 100644 core/utils/host_diag_log/src/i_host_diag_core_log.h create mode 100644 core/utils/logging/inc/wlan_logging_sock_svc.h create mode 100644 core/utils/logging/src/wlan_logging_sock_svc.c create mode 100644 core/utils/nlink/inc/wlan_nlink_common.h create mode 100644 core/utils/nlink/inc/wlan_nlink_srv.h create mode 100644 core/utils/nlink/src/wlan_nlink_srv.c create mode 100644 core/utils/pktlog/include/pktlog.h create mode 100644 core/utils/pktlog/include/pktlog_ac.h create mode 100644 core/utils/pktlog/include/pktlog_ac_api.h create mode 100644 core/utils/pktlog/include/pktlog_ac_i.h create mode 100644 core/utils/pktlog/linux_ac.c create mode 100644 core/utils/pktlog/pktlog_ac.c create mode 100644 core/utils/pktlog/pktlog_internal.c create mode 100644 core/utils/ptt/inc/wlan_ptt_sock_svc.h create mode 100644 core/utils/ptt/src/wlan_ptt_sock_svc.c create mode 100644 core/wma/inc/wma.h create mode 100644 core/wma/inc/wma_api.h create mode 100644 core/wma/inc/wma_dfs_interface.h create mode 100644 core/wma/inc/wma_if.h create mode 100644 core/wma/inc/wma_internal.h create mode 100644 core/wma/inc/wma_tgt_cfg.h create mode 100644 core/wma/inc/wma_types.h create mode 100644 core/wma/src/wlan_qct_wma_legacy.c create mode 100644 core/wma/src/wma_data.c create mode 100644 core/wma/src/wma_dev_if.c create mode 100644 core/wma/src/wma_dfs_interface.c create mode 100644 core/wma/src/wma_features.c create mode 100644 core/wma/src/wma_main.c create mode 100644 core/wma/src/wma_mgmt.c create mode 100644 core/wma/src/wma_ocb.c create mode 100644 core/wma/src/wma_ocb.h create mode 100644 core/wma/src/wma_power.c create mode 100644 core/wma/src/wma_scan_roam.c create mode 100644 core/wma/src/wma_utils.c create mode 100644 core/wma/src/wma_utils_ut.c create mode 100644 core/wmi/wmi_tlv_helper.c create mode 100644 core/wmi/wmi_tlv_platform.c create mode 100644 core/wmi/wmi_unified.c create mode 100644 core/wmi/wmi_unified_api.h create mode 100644 core/wmi/wmi_unified_priv.h create mode 100644 core/wmi/wmi_version_whitelist.c create mode 100644 target/inc/a_osapi.h create mode 100644 target/inc/a_usb_defs.h create mode 100644 target/inc/apb_athr_wlan_map.h create mode 100644 target/inc/athdefs.h create mode 100644 target/inc/athendpack.h create mode 100644 target/inc/bin_sig.h create mode 100644 target/inc/bmi_msg.h create mode 100644 target/inc/cepci.h create mode 100644 target/inc/dbglog.h create mode 100644 target/inc/dbglog_id.h create mode 100644 target/inc/efuse_reg.h create mode 100644 target/inc/enet.h create mode 100644 target/inc/epping_test.h create mode 100644 target/inc/htc.h create mode 100644 target/inc/htc_services.h create mode 100644 target/inc/htt.h create mode 100644 target/inc/htt_common.h create mode 100644 target/inc/htt_isoc.h create mode 100644 target/inc/ip_prot.h create mode 100644 target/inc/ipv4.h create mode 100644 target/inc/ol_fw_tx_dbg.h create mode 100644 target/inc/rtc_soc_reg.h create mode 100644 target/inc/targaddrs.h create mode 100644 target/inc/targcfg.h create mode 100644 target/inc/wal_rx_desc.h create mode 100644 target/inc/wlan_defs.h create mode 100644 target/inc/wlan_module_ids.h create mode 100644 target/inc/wlan_tgt_def_config.h create mode 100644 target/inc/wmi.h create mode 100644 target/inc/wmi_services.h create mode 100644 target/inc/wmi_tlv_defs.h create mode 100644 target/inc/wmi_tlv_helper.h create mode 100644 target/inc/wmi_unified.h create mode 100644 target/inc/wmi_version.h create mode 100644 target/inc/wmix.h create mode 100644 uapi/linux/a_debug.h create mode 100644 uapi/linux/a_types.h create mode 100644 uapi/linux/athstartpack.h create mode 100644 uapi/linux/dbglog_common.h create mode 100644 uapi/linux/debug_linux.h create mode 100644 uapi/linux/osapi_linux.h create mode 100644 uapi/linux/pktlog_ac_fmt.h diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000000..0f020f36a5 --- /dev/null +++ b/Android.mk @@ -0,0 +1,114 @@ +# Android makefile for the WLAN Module + +# Assume no targets will be supported +WLAN_CHIPSET := + +ifeq ($(BOARD_HAS_QCOM_WLAN), true) + +# Build/Package options for 8084/8092/8960/8992/8994 target +ifeq ($(call is-board-platform-in-list, apq8084 mpq8092 msm8960 msm8992 msm8994 msm8996 msm8998),true) + WLAN_CHIPSET := qca_cld + WLAN_SELECT := CONFIG_QCA_CLD_WLAN=m +endif # platform + +# Build/Package only in case of supported target +ifneq ($(WLAN_CHIPSET),) + +LOCAL_PATH := $(call my-dir) + +# This makefile is only for DLKM +ifneq ($(findstring vendor,$(LOCAL_PATH)),) + +ifneq ($(findstring opensource,$(LOCAL_PATH)),) + WLAN_PROPRIETARY := 0 + WLAN_BLD_DIR := vendor/qcom/opensource/wlan +else + WLAN_PROPRIETARY := 1 + WLAN_BLD_DIR := vendor/qcom/proprietary/wlan-noship +endif # opensource + +# DLKM_DIR was moved for JELLY_BEAN (PLATFORM_SDK 16) +ifeq ($(call is-platform-sdk-version-at-least,16),true) + DLKM_DIR := $(TOP)/device/qcom/common/dlkm +else + DLKM_DIR := build/dlkm +endif # platform-sdk-version + +# Copy WCNSS_cfg.dat and WCNSS_qcom_cfg.ini file from firmware_bin/ folder to target out directory. +ifeq ($(call is-board-platform-in-list, msm8960),true) +$(shell rm -f $(TARGET_OUT_ETC)/firmware/wlan/qca_cld/WCNSS_cfg.dat) +$(shell rm -f $(TARGET_OUT_ETC)/firmware/wlan/qca_cld/WCNSS_qcom_cfg.ini) +$(shell cp $(LOCAL_PATH)/firmware_bin/WCNSS_cfg.dat $(TARGET_OUT_ETC)/firmware/wlan/qca_cld) +$(shell cp $(LOCAL_PATH)/firmware_bin/WCNSS_qcom_cfg.ini $(TARGET_OUT_ETC)/firmware/wlan/qca_cld) +endif + +# Build wlan.ko as $(WLAN_CHIPSET)_wlan.ko +########################################################### +# This is set once per LOCAL_PATH, not per (kernel) module +ifeq ($(WLAN_PROPRIETARY),1) + KBUILD_OPTIONS := WLAN_ROOT=../$(WLAN_BLD_DIR)/qcacld-new +else + KBUILD_OPTIONS := WLAN_ROOT=../$(WLAN_BLD_DIR)/qcacld-3.0 +endif # WLAN_PROPRIETARY +# We are actually building wlan.ko here, as per the +# requirement we are specifying _wlan.ko as LOCAL_MODULE. +# This means we need to rename the module to _wlan.ko +# after wlan.ko is built. +KBUILD_OPTIONS += MODNAME=wlan +KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) +KBUILD_OPTIONS += $(WLAN_SELECT) + +include $(CLEAR_VARS) +ifeq ($(WLAN_PROPRIETARY),1) + LOCAL_MODULE := proprietary_$(WLAN_CHIPSET)_wlan.ko +else + LOCAL_MODULE := $(WLAN_CHIPSET)_wlan.ko +endif # WLAN_PROPRIETARY +LOCAL_MODULE_KBUILD_NAME := wlan.ko +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/modules/$(WLAN_CHIPSET) +include $(DLKM_DIR)/AndroidKernelModule.mk +########################################################### + +# Create Symbolic link +ifeq ($(WLAN_PROPRIETARY),1) +$(shell mkdir -p $(TARGET_OUT)/lib/modules; \ + ln -sf /system/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE) \ + $(TARGET_OUT)/lib/modules/wlan.ko) +endif +$(shell ln -sf /persist/wlan_mac.bin $(TARGET_OUT_ETC)/firmware/wlan/qca_cld/wlan_mac.bin) + +ifeq ($(call is-board-platform-in-list, msm8960),true) +$(shell ln -sf /firmware/image/bdwlan20.bin $(TARGET_OUT_ETC)/firmware/fakeboar.bin) +$(shell ln -sf /firmware/image/otp20.bin $(TARGET_OUT_ETC)/firmware/otp.bin) +$(shell ln -sf /firmware/image/utf20.bin $(TARGET_OUT_ETC)/firmware/utf.bin) +$(shell ln -sf /firmware/image/qwlan20.bin $(TARGET_OUT_ETC)/firmware/athwlan.bin) + +$(shell ln -sf /firmware/image/bdwlan20.bin $(TARGET_OUT_ETC)/firmware/bdwlan20.bin) +$(shell ln -sf /firmware/image/otp20.bin $(TARGET_OUT_ETC)/firmware/otp20.bin) +$(shell ln -sf /firmware/image/utf20.bin $(TARGET_OUT_ETC)/firmware/utf20.bin) +$(shell ln -sf /firmware/image/qwlan20.bin $(TARGET_OUT_ETC)/firmware/qwlan20.bin) + +$(shell ln -sf /firmware/image/bdwlan30.bin $(TARGET_OUT_ETC)/firmware/bdwlan30.bin) +$(shell ln -sf /firmware/image/otp30.bin $(TARGET_OUT_ETC)/firmware/otp30.bin) +$(shell ln -sf /firmware/image/utf30.bin $(TARGET_OUT_ETC)/firmware/utf30.bin) +$(shell ln -sf /firmware/image/qwlan30.bin $(TARGET_OUT_ETC)/firmware/qwlan30.bin) +endif + +# Copy config ini files to target +#ifeq ($(call is-board-platform-in-list, msm8992 msm8994),false) +ifeq ($(WLAN_PROPRIETARY),1) +$(shell mkdir -p $(TARGET_OUT)/etc/firmware/wlan/$(WLAN_CHIPSET)) +$(shell mkdir -p $(TARGET_OUT)/etc/wifi) +$(shell rm -f $(TARGET_OUT)/etc/wifi/WCNSS_qcom_cfg.ini) +$(shell rm -f $(TARGET_OUT)/etc/firmware/wlan/$(WLAN_SHIPSET)/WCNSS_cfg.dat) +$(shell cp $(LOCAL_PATH)/config/WCNSS_qcom_cfg.ini $(TARGET_OUT)/etc/wifi) +$(shell cp $(LOCAL_PATH)/firmware_bin/WCNSS_cfg.dat $(TARGET_OUT)/etc/firmware/wlan/$(WLAN_CHIPSET)) +endif +#endif + +endif # DLKM check + +endif # supported target check +endif # WLAN enabled check diff --git a/Kbuild b/Kbuild new file mode 100644 index 0000000000..0ad05d87fa --- /dev/null +++ b/Kbuild @@ -0,0 +1,1331 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + +ifeq ($(CONFIG_CNSS), y) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +ifeq ($(KERNEL_BUILD),1) + # These are provided in external module based builds + # Need to explicitly define for Kernel-based builds + MODNAME := wlan + WLAN_ROOT := drivers/staging/qcacld-3.0 +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := 1 + +ifeq ($(KERNEL_BUILD), 0) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + + ifeq ($(CONFIG_ARCH_MDM9630), y) + CONFIG_MOBILE_ROUTER := y + endif + + ifeq ($(CONFIG_ARCH_MDM9640), y) + CONFIG_MOBILE_ROUTER := y + endif + + #Flag to enable Legacy Fast Roaming3(LFR3) + CONFIG_QCACLD_WLAN_LFR3 := y + + #JB kernel has PMKSA patches, hence enabling this flag + CONFIG_PRIMA_WLAN_OKC := y + + # JB kernel has CPU enablement patches, so enable + ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := y + endif + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := n + endif + ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := n + endif + + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable TDLS feature + CONFIG_QCOM_TDLS := y + endif + + ifeq ($(CONFIG_MOBILE_ROUTER), y) + CONFIG_QCACLD_FEATURE_GREEN_AP := y + endif + + #Flag to enable Fast Transition (11r) feature + CONFIG_QCOM_VOWIFI_11R := y + + ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq ($(CONFIG_CNSS),y) + #Flag to enable Protected Managment Frames (11w) feature + CONFIG_WLAN_FEATURE_11W := y + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + endif + + + #Flag to enable Protected Managment Frames (11w) feature + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_WLAN_FEATURE_11W := y + endif + ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_WLAN_FEATURE_11W := y + endif + + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN + CONFIG_QCACLD_FEATURE_NAN := y + endif + + #Flag to enable Linux QCMBR feature as default feature + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y + endif + + ifeq ($(CONFIG_CNSS_EOS),y) + CONFIG_FEATURE_BMI_2 :=y + endif + + CONFIG_MPC_UT_FRAMEWORK := y + + #Flag to enable offload packets feature + CONFIG_WLAN_OFFLOAD_PACKETS := y + + #Flag to enable memdump feature + CONFIG_WLAN_FEATURE_MEMDUMP := y + + #Flag to enable Fast Path feature + CONFIG_WLAN_FASTPATH := y + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + + # Flag to enable LRO (Large Receive Offload) + ifeq ($(CONFIG_CNSS_EOS), y) + ifeq ($(CONFIG_INET_LRO), y) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif + endif +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +# To enable ESE upload, dependent config +# CONFIG_QCOM_ESE must be enabled. +CONFIG_QCOM_ESE := y +CONFIG_QCOM_ESE_UPLOAD := y +endif + +# Feature flags which are not (currently) configurable via Kconfig + +#Whether to build debug version +BUILD_DEBUG_VERSION := 1 + +#Enable this flag to build driver in diag version +BUILD_DIAG_VERSION := 1 + +#Do we panic on bug? default is to warn +PANIC_ON_BUG := 1 + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := 1 + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := 0 + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := 1 +endif +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := 0 +endif + +#Enable per vdev Tx desc pool +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_PER_VDEV_TX_DESC_POOL := 0 +endif +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_PER_VDEV_TX_DESC_POOL := 1 +endif + + +#Enable OS specific IRQ abstraction +CONFIG_ATH_SUPPORT_SHARED_IRQ := 1 + +#Enable message based HIF instead of RAW access in BMI +ifeq ($(CONFIG_QCA_WIFI_SDIO), 1) +CONFIG_HIF_MESSAGE_BASED := 0 +else +CONFIG_HIF_MESSAGE_BASED := 1 +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := 1 +endif + +#Enable pci read/write config functions +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_PCI := 1 +endif +ifeq ($(CONFIG_ROME_IF),usb) +#CONFIG_ATH_PCI := 1 +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Enable IBSS support on CLD +CONFIG_QCA_IBSS_SUPPORT := 1 +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := 1 + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := 0 + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := 0 + +#Enable HOST statistics support +CONFIG_SUPPORT_HOST_STATISTICS := 0 + +#Enable WDI Event support +CONFIG_WDI_EVENT_ENABLE := 1 + +#Endianess selection +CONFIG_LITTLE_ENDIAN := 1 + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := 0 + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := 1 + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := 1 + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := 1 + +#Enable EXT WOW +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_EXT_WOW := 1 +endif + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := 0 + +#Enable IPA offload +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := 1 +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := 0 + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := 0 + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := 1 + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := 0 + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := 1 + +#Flag to force the inclusion of the 802.11p channels because support +#for these channels has not yet been added to the kernel. +CONFIG_STATICALLY_ADD_11P_CHANNELS := n + +ifeq ($(CONFIG_CFG80211),y) +HAVE_CFG80211 := 1 +else +ifeq ($(CONFIG_CFG80211),m) +HAVE_CFG80211 := 1 +else +HAVE_CFG80211 := 0 +endif +endif + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(WLAN_ROOT)/$(UAPI_DIR)/linux + +############ COMMON ############ +COMMON_DIR := core/common +COMMON_INC := -I$(WLAN_ROOT)/$(COMMON_DIR) + +############ HDD ############ +HDD_DIR := core/hdd +HDD_INC_DIR := $(HDD_DIR)/inc +HDD_SRC_DIR := $(HDD_DIR)/src + +HDD_INC := -I$(WLAN_ROOT)/$(HDD_INC_DIR) \ + -I$(WLAN_ROOT)/$(HDD_SRC_DIR) + +HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \ + $(HDD_SRC_DIR)/wlan_hdd_cfg.o \ + $(HDD_SRC_DIR)/wlan_hdd_debugfs.o \ + $(HDD_SRC_DIR)/wlan_hdd_driver_ops.o \ + $(HDD_SRC_DIR)/wlan_hdd_ftm.o \ + $(HDD_SRC_DIR)/wlan_hdd_hostapd.o \ + $(HDD_SRC_DIR)/wlan_hdd_ioctl.o \ + $(HDD_SRC_DIR)/wlan_hdd_main.o \ + $(HDD_SRC_DIR)/wlan_hdd_ocb.o \ + $(HDD_SRC_DIR)/wlan_hdd_oemdata.o \ + $(HDD_SRC_DIR)/wlan_hdd_power.o \ + $(HDD_SRC_DIR)/wlan_hdd_scan.o \ + $(HDD_SRC_DIR)/wlan_hdd_softap_tx_rx.o \ + $(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \ + $(HDD_SRC_DIR)/wlan_hdd_trace.o \ + $(HDD_SRC_DIR)/wlan_hdd_wext.o \ + $(HDD_SRC_DIR)/wlan_hdd_wmm.o \ + $(HDD_SRC_DIR)/wlan_hdd_wowl.o + +ifeq ($(CONFIG_WLAN_LRO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lro.o +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_napi.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ipa.o +endif + +ifeq ($(HAVE_CFG80211),1) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_cfg80211.o \ + $(HDD_SRC_DIR)/wlan_hdd_ext_scan.o \ + $(HDD_SRC_DIR)/wlan_hdd_stats.o \ + $(HDD_SRC_DIR)/wlan_hdd_p2p.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_green_ap.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan.o +endif + +ifeq ($(CONFIG_QCOM_TDLS),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tdls.o +endif + +ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_conc_ut.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_memdump.o +endif + +########### HOST DIAG LOG ########### +HOST_DIAG_LOG_DIR := core/utils/host_diag_log + +HOST_DIAG_LOG_INC_DIR := $(HOST_DIAG_LOG_DIR)/inc +HOST_DIAG_LOG_SRC_DIR := $(HOST_DIAG_LOG_DIR)/src + +HOST_DIAG_LOG_INC := -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_INC_DIR) \ + -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_SRC_DIR) + +HOST_DIAG_LOG_OBJS += $(HOST_DIAG_LOG_SRC_DIR)/host_diag_log.o + +############ EPPING ############ +EPPING_DIR := core/utils/epping +EPPING_INC_DIR := $(EPPING_DIR)/inc +EPPING_SRC_DIR := $(EPPING_DIR)/src + +EPPING_INC := -I$(WLAN_ROOT)/$(EPPING_INC_DIR) + +EPPING_OBJS := $(EPPING_SRC_DIR)/epping_main.o \ + $(EPPING_SRC_DIR)/epping_txrx.o \ + $(EPPING_SRC_DIR)/epping_tx.o \ + $(EPPING_SRC_DIR)/epping_rx.o \ + $(EPPING_SRC_DIR)/epping_helper.o \ + + +############ MAC ############ +MAC_DIR := core/mac +MAC_INC_DIR := $(MAC_DIR)/inc +MAC_SRC_DIR := $(MAC_DIR)/src + +MAC_INC := -I$(WLAN_ROOT)/$(MAC_INC_DIR) \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/dph \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/lim + +MAC_CFG_OBJS := $(MAC_SRC_DIR)/cfg/cfg_api.o \ + $(MAC_SRC_DIR)/cfg/cfg_debug.o \ + $(MAC_SRC_DIR)/cfg/cfg_param_name.o \ + $(MAC_SRC_DIR)/cfg/cfg_proc_msg.o \ + $(MAC_SRC_DIR)/cfg/cfg_send_msg.o + +MAC_DPH_OBJS := $(MAC_SRC_DIR)/dph/dph_hash_table.o + +MAC_LIM_OBJS := $(MAC_SRC_DIR)/pe/lim/lim_aid_mgmt.o \ + $(MAC_SRC_DIR)/pe/lim/lim_admit_control.o \ + $(MAC_SRC_DIR)/pe/lim/lim_api.o \ + $(MAC_SRC_DIR)/pe/lim/lim_assoc_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_debug.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ft.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ibss_peer_mgmt.o \ + $(MAC_SRC_DIR)/pe/lim/lim_link_monitoring_algo.o \ + $(MAC_SRC_DIR)/pe/lim/lim_p2p.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_action_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_auth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_beacon_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_cfg_updates.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_deauth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_disassoc_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_message_queue.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_sme_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_prop_exts_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_scan_result_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_security_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_management_frames.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_sme_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ser_des_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_sme_req_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_sta_hash_api.o \ + $(MAC_SRC_DIR)/pe/lim/lim_timer_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_trace.o \ + $(MAC_SRC_DIR)/pe/lim/lim_utils.o + +ifeq ($(CONFIG_QCOM_ESE),y) +ifneq ($(CONFIG_QCOM_ESE_UPLOAD),y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/limProcessEseFrame.o +endif +endif + +ifeq ($(CONFIG_QCOM_TDLS),y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_tdls.o +endif + +MAC_SCH_OBJS := $(MAC_SRC_DIR)/pe/sch/sch_api.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_gen.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_process.o \ + $(MAC_SRC_DIR)/pe/sch/sch_debug.o \ + $(MAC_SRC_DIR)/pe/sch/sch_message.o + +MAC_RRM_OBJS := $(MAC_SRC_DIR)/pe/rrm/rrm_api.o + +MAC_OBJS := $(MAC_CFG_OBJS) \ + $(MAC_DPH_OBJS) \ + $(MAC_LIM_OBJS) \ + $(MAC_SCH_OBJS) \ + $(MAC_RRM_OBJS) + +############ SAP ############ +SAP_DIR := core/sap +SAP_INC_DIR := $(SAP_DIR)/inc +SAP_SRC_DIR := $(SAP_DIR)/src + +SAP_INC := -I$(WLAN_ROOT)/$(SAP_INC_DIR) \ + -I$(WLAN_ROOT)/$(SAP_SRC_DIR) + +SAP_OBJS := $(SAP_SRC_DIR)/sap_api_link_cntl.o \ + $(SAP_SRC_DIR)/sap_ch_select.o \ + $(SAP_SRC_DIR)/sap_fsm.o \ + $(SAP_SRC_DIR)/sap_module.o + +############ DFS ############ 350 +DFS_DIR := $(SAP_DIR)/dfs +DFS_INC_DIR := $(DFS_DIR)/inc +DFS_SRC_DIR := $(DFS_DIR)/src + +DFS_INC := -I$(WLAN_ROOT)/$(DFS_INC_DIR) \ + -I$(WLAN_ROOT)/$(DFS_SRC_DIR) + +DFS_OBJS := $(DFS_SRC_DIR)/dfs_bindetects.o \ + $(DFS_SRC_DIR)/dfs.o \ + $(DFS_SRC_DIR)/dfs_debug.o\ + $(DFS_SRC_DIR)/dfs_fcc_bin5.o\ + $(DFS_SRC_DIR)/dfs_init.o\ + $(DFS_SRC_DIR)/dfs_misc.o\ + $(DFS_SRC_DIR)/dfs_nol.o\ + $(DFS_SRC_DIR)/dfs_phyerr_tlv.o\ + $(DFS_SRC_DIR)/dfs_process_phyerr.o\ + $(DFS_SRC_DIR)/dfs_process_radarevent.o\ + $(DFS_SRC_DIR)/dfs_staggered.o + +############ SME ############ +SME_DIR := core/sme +SME_INC_DIR := $(SME_DIR)/inc +SME_SRC_DIR := $(SME_DIR)/src + +SME_INC := -I$(WLAN_ROOT)/$(SME_INC_DIR) \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/csr + +SME_CSR_OBJS := $(SME_SRC_DIR)/csr/csr_api_roam.o \ + $(SME_SRC_DIR)/csr/csr_api_scan.o \ + $(SME_SRC_DIR)/csr/csr_cmd_process.o \ + $(SME_SRC_DIR)/csr/csr_link_list.o \ + $(SME_SRC_DIR)/csr/csr_neighbor_roam.o \ + $(SME_SRC_DIR)/csr/csr_util.o + +ifeq ($(CONFIG_QCOM_ESE),y) +ifneq ($(CONFIG_QCOM_ESE_UPLOAD),y) +SME_CSR_OBJS += $(SME_SRC_DIR)/csr/csrEse.o +endif +endif + +ifeq ($(CONFIG_QCOM_TDLS),y) +SME_CSR_OBJS += $(SME_SRC_DIR)/csr/csr_tdls_process.o +endif + +SME_QOS_OBJS := $(SME_SRC_DIR)/qos/sme_qos.o + +SME_CMN_OBJS := $(SME_SRC_DIR)/common/sme_api.o \ + $(SME_SRC_DIR)/common/sme_ft_api.o \ + $(SME_SRC_DIR)/common/sme_power_save.o \ + $(SME_SRC_DIR)/common/sme_trace.o + +SME_OEM_DATA_OBJS := $(SME_SRC_DIR)/oem_data/oem_data_api.o + +SME_P2P_OBJS = $(SME_SRC_DIR)/p2p/p2p_api.o + +SME_RRM_OBJS := $(SME_SRC_DIR)/rrm/sme_rrm.o + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +SME_NAN_OBJS = $(SME_SRC_DIR)/nan/nan_api.o +endif + +SME_OBJS := $(SME_CMN_OBJS) \ + $(SME_CSR_OBJS) \ + $(SME_OEM_DATA_OBJS) \ + $(SME_P2P_OBJS) \ + $(SME_QOS_OBJS) \ + $(SME_RRM_OBJS) \ + $(SME_NAN_OBJS) + +############ NLINK ############ +NLINK_DIR := core/utils/nlink +NLINK_INC_DIR := $(NLINK_DIR)/inc +NLINK_SRC_DIR := $(NLINK_DIR)/src + +NLINK_INC := -I$(WLAN_ROOT)/$(NLINK_INC_DIR) +NLINK_OBJS := $(NLINK_SRC_DIR)/wlan_nlink_srv.o + +############ PTT ############ +PTT_DIR := core/utils/ptt +PTT_INC_DIR := $(PTT_DIR)/inc +PTT_SRC_DIR := $(PTT_DIR)/src + +PTT_INC := -I$(WLAN_ROOT)/$(PTT_INC_DIR) +PTT_OBJS := $(PTT_SRC_DIR)/wlan_ptt_sock_svc.o + +############ WLAN_LOGGING ############ +WLAN_LOGGING_DIR := core/utils/logging +WLAN_LOGGING_INC_DIR := $(WLAN_LOGGING_DIR)/inc +WLAN_LOGGING_SRC_DIR := $(WLAN_LOGGING_DIR)/src + +WLAN_LOGGING_INC := -I$(WLAN_ROOT)/$(WLAN_LOGGING_INC_DIR) +WLAN_LOGGING_OBJS := $(WLAN_LOGGING_SRC_DIR)/wlan_logging_sock_svc.o + +############ SYS ############ +SYS_DIR := core/mac/src/sys + +SYS_INC := -I$(WLAN_ROOT)/$(SYS_DIR)/common/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/platform/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/system/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/utils/inc + +SYS_COMMON_SRC_DIR := $(SYS_DIR)/common/src +SYS_LEGACY_SRC_DIR := $(SYS_DIR)/legacy/src +SYS_OBJS := $(SYS_COMMON_SRC_DIR)/wlan_qct_sys.o \ + $(SYS_LEGACY_SRC_DIR)/platform/src/sys_wrapper.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/mac_init_api.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/sys_entry_func.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/dot11f.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/log_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/mac_trace.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/parser_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/utils_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/utils_parser.o + +############ CDF (Connectivity driver framework) ############ +CDF_DIR := core/cdf +CDF_INC_DIR := $(CDF_DIR)/inc +CDF_SRC_DIR := $(CDF_DIR)/src + +CDF_INC := -I$(WLAN_ROOT)/$(CDF_INC_DIR) \ + -I$(WLAN_ROOT)/$(CDF_SRC_DIR) + +CDF_OBJS := $(CDF_SRC_DIR)/cdf_event.o \ + $(CDF_SRC_DIR)/cdf_list.o \ + $(CDF_SRC_DIR)/cdf_lock.o \ + $(CDF_SRC_DIR)/cdf_memory.o \ + $(CDF_SRC_DIR)/cdf_threads.o \ + $(CDF_SRC_DIR)/cdf_mc_timer.o \ + $(CDF_SRC_DIR)/cdf_trace.o \ + $(CDF_SRC_DIR)/cdf_nbuf.o \ + $(CDF_SRC_DIR)/cdf_defer.o + +############ CDS (Connectivity driver services) ############ +CDS_DIR := core/cds +CDS_INC_DIR := $(CDS_DIR)/inc +CDS_SRC_DIR := $(CDS_DIR)/src + +CDS_INC := -I$(WLAN_ROOT)/$(CDS_INC_DIR) \ + -I$(WLAN_ROOT)/$(CDS_SRC_DIR) + +CDS_OBJS := $(CDS_SRC_DIR)/cds_api.o \ + $(CDS_SRC_DIR)/cds_get_bin.o \ + $(CDS_SRC_DIR)/cds_reg_service.o \ + $(CDS_SRC_DIR)/cds_mq.o \ + $(CDS_SRC_DIR)/cds_packet.o \ + $(CDS_SRC_DIR)/cds_regdomain.o \ + $(CDS_SRC_DIR)/cds_sched.o \ + $(CDS_SRC_DIR)/cds_concurrency.o \ + $(CDS_SRC_DIR)/cds_utils.o + + +########### BMI ########### +BMI_DIR := core/bmi + +BMI_INC := -I$(WLAN_ROOT)/$(BMI_DIR)/inc + +ifneq ($(CONFIG_ICNSS), y) +BMI_OBJS := $(BMI_DIR)/src/bmi.o \ + $(BMI_DIR)/src/ol_fw.o +ifeq ($(CONFIG_FEATURE_BMI_2), y) +BMI_OBJS += $(BMI_DIR)/src/bmi_2.o +else +BMI_OBJS += $(BMI_DIR)/src/bmi_1.o +endif +endif +########### WMI ########### +WMI_DIR := core/wmi + +WMI_INC := -I$(WLAN_ROOT)/$(WMI_DIR) + +WMI_OBJS := $(WMI_DIR)/wmi_unified.o \ + $(WMI_DIR)/wmi_tlv_helper.o + +########### FWLOG ########### +FWLOG_DIR := core/utils/fwlog + +FWLOG_INC := -I$(WLAN_ROOT)/$(FWLOG_DIR) + +FWLOG_OBJS := $(FWLOG_DIR)/dbglog_host.o + +############ TXRX ############ +TXRX_DIR := core/dp/txrx +TXRX_INC := -I$(WLAN_ROOT)/$(TXRX_DIR) + +TXRX_OBJS := $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_cfg.o \ + $(TXRX_DIR)/ol_rx.o \ + $(TXRX_DIR)/ol_rx_fwd.o \ + $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_rx_defrag.o \ + $(TXRX_DIR)/ol_tx_desc.o \ + $(TXRX_DIR)/ol_tx.o \ + $(TXRX_DIR)/ol_rx_reorder_timeout.o \ + $(TXRX_DIR)/ol_rx_reorder.o \ + $(TXRX_DIR)/ol_rx_pn.o \ + $(TXRX_DIR)/ol_tx_queue.o \ + $(TXRX_DIR)/ol_txrx_peer_find.o \ + $(TXRX_DIR)/ol_txrx_event.o \ + $(TXRX_DIR)/ol_txrx_encap.o \ + $(TXRX_DIR)/ol_tx_send.o + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_flow_control.o +endif + +############ OL ############ +OL_DIR := core/dp/ol +OL_INC := -I$(WLAN_ROOT)/$(OL_DIR)/inc + +############ PKTLOG ############ +PKTLOG_DIR := core/utils/pktlog +PKTLOG_INC := -I$(WLAN_ROOT)/$(PKTLOG_DIR)/include + +PKTLOG_OBJS := $(PKTLOG_DIR)/pktlog_ac.o \ + $(PKTLOG_DIR)/pktlog_internal.o \ + $(PKTLOG_DIR)/linux_ac.o + +############ HTT ############ +HTT_DIR := core/dp/htt +HTT_INC := -I$(WLAN_ROOT)/$(HTT_DIR) + +HTT_OBJS := $(HTT_DIR)/htt_tx.o \ + $(HTT_DIR)/htt.o \ + $(HTT_DIR)/htt_t2h.o \ + $(HTT_DIR)/htt_h2t.o \ + $(HTT_DIR)/htt_fw_stats.o \ + $(HTT_DIR)/htt_rx.o + +############## HTC ########## +HTC_DIR := core/htc +HTC_INC := -I$(WLAN_ROOT)/$(HTC_DIR) + +HTC_OBJS := $(HTC_DIR)/htc.o \ + $(HTC_DIR)/htc_send.o \ + $(HTC_DIR)/htc_recv.o \ + $(HTC_DIR)/htc_services.o + +########### HIF ########### +HIF_DIR := core/hif +HIF_CE_DIR := $(HIF_DIR)/src/ce +HIF_CNSS_STUB_DIR := $(HIF_DIR)/src/icnss_stub + +ifeq ($(CONFIG_HIF_PCI), 1) +HIF_PCIE_DIR := $(HIF_DIR)/src/pcie +else +HIF_SNOC_DIR := $(HIF_DIR)/src/snoc +endif + +HIF_INC := -I$(WLAN_ROOT)/$(HIF_DIR)/inc \ + -I$(WLAN_ROOT)/$(HIF_DIR)/src \ + -I$(WLAN_ROOT)/$(HIF_CE_DIR) \ + -I$(WLAN_ROOT)/$(HIF_CNSS_STUB_DIR) + +ifeq ($(CONFIG_HIF_PCI), 1) +HIF_INC += -I$(WLAN_ROOT)/$(HIF_PCIE_DIR) +else +HIF_INC += -I$(WLAN_ROOT)/$(HIF_SNOC_DIR) +endif + +HIF_OBJS := $(HIF_DIR)/src/ath_procfs.o \ + $(HIF_CE_DIR)/ce_diag.o \ + $(HIF_CE_DIR)/ce_main.o \ + $(HIF_CE_DIR)/ce_service.o \ + $(HIF_CE_DIR)/ce_tasklet.o \ + $(HIF_DIR)/src/hif_main.o \ + $(HIF_DIR)/src/mp_dev.o \ + $(HIF_DIR)/src/regtable.o + +ifeq ($(CONFIG_CNSS), y) +HIF_OBJS += $(HIF_CNSS_STUB_DIR)/icnss_stub.o \ + $(HIF_CE_DIR)/ce_bmi.o +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +HIF_OBJS += $(HIF_DIR)/src/hif_napi.o +endif + +ifeq ($(CONFIG_HIF_PCI), 1) +HIF_PCIE_OBJS := $(HIF_PCIE_DIR)/if_pci.o + +HIF_OBJS += $(HIF_PCIE_OBJS) +else +HIF_SNOC_OBJS := $(HIF_SNOC_DIR)/if_snoc.o + +HIF_OBJS += $(HIF_SNOC_OBJS) +endif + +############ WMA ############ +WMA_DIR := core/wma + +WMA_INC_DIR := $(WMA_DIR)/inc +WMA_SRC_DIR := $(WMA_DIR)/src + +WMA_INC := -I$(WLAN_ROOT)/$(WMA_INC_DIR) \ + -I$(WLAN_ROOT)/$(WMA_SRC_DIR) + +WMA_OBJS := $(WMA_SRC_DIR)/wma_main.o \ + $(WMA_SRC_DIR)/wma_scan_roam.o \ + $(WMA_SRC_DIR)/wma_dev_if.o \ + $(WMA_SRC_DIR)/wma_mgmt.o \ + $(WMA_SRC_DIR)/wma_power.o \ + $(WMA_SRC_DIR)/wma_data.o \ + $(WMA_SRC_DIR)/wma_utils.o \ + $(WMA_SRC_DIR)/wma_features.o \ + $(WMA_SRC_DIR)/wma_dfs_interface.o \ + $(WMA_SRC_DIR)/wma_ocb.o \ + $(WMA_SRC_DIR)/wlan_qct_wma_legacy.o + +ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_utils_ut.o +endif + +TARGET_INC := -I$(WLAN_ROOT)/target/inc + +LINUX_INC := -Iinclude/linux + +INCS := $(HDD_INC) \ + $(EPPING_INC) \ + $(LINUX_INC) \ + $(MAC_INC) \ + $(SAP_INC) \ + $(SME_INC) \ + $(SYS_INC) \ + $(CDF_INC) \ + $(CDS_INC) \ + $(DFS_INC) + +INCS += $(WMA_INC) \ + $(UAPI_INC) \ + $(COMMON_INC) \ + $(WMI_INC) \ + $(FWLOG_INC) \ + $(TXRX_INC) \ + $(OL_INC) \ + $(PKTLOG_INC) \ + $(HTT_INC) \ + $(HTC_INC) \ + $(DFS_INC) + +INCS += $(HIF_INC) \ + $(BMI_INC) + +INCS += $(TARGET_INC) + +INCS += $(NLINK_INC) \ + $(PTT_INC) \ + $(WLAN_LOGGING_INC) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), 0) +INCS += $(PKTLOG_INC) +endif + +ifeq ($(BUILD_DIAG_VERSION), 1) +INCS += $(HOST_DIAG_LOG_INC) +endif + +OBJS := $(HDD_OBJS) \ + $(EPPING_OBJS) \ + $(MAC_OBJS) \ + $(SAP_OBJS) \ + $(SME_OBJS) \ + $(SYS_OBJS) \ + $(CDF_OBJS) \ + $(CDS_OBJS) \ + $(DFS_OBJS) + +OBJS += $(WMA_OBJS) \ + $(TXRX_OBJS) \ + $(WMI_OBJS) \ + $(FWLOG_OBJS) \ + $(HTC_OBJS) \ + $(DFS_OBJS) + +OBJS += $(HIF_OBJS) \ + $(BMI_OBJS) \ + $(HTT_OBJS) + +OBJS += $(WLAN_LOGGING_OBJS) +OBJS += $(NLINK_OBJS) +OBJS += $(PTT_OBJS) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), 0) +OBJS += $(PKTLOG_OBJS) +endif + +ifeq ($(BUILD_DIAG_VERSION), 1) +OBJS += $(HOST_DIAG_LOG_OBJS) +endif + + +EXTRA_CFLAGS += $(INCS) + +CDEFINES := -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DQC_WLAN_CHIPSET_QCA_CLD \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DWLAN_PERF \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ \ + -DHAL_SELF_STA_PER_BSS=1 \ + -DWLAN_FEATURE_VOWIFI_11R \ + -DWLAN_FEATURE_NEIGHBOR_ROAMING \ + -DWLAN_FEATURE_NEIGHBOR_ROAMING_DEBUG \ + -DWLAN_FEATURE_VOWIFI_11R_DEBUG \ + -DFEATURE_WLAN_WAPI \ + -DFEATURE_OEM_DATA_SUPPORT\ + -DSOFTAP_CHANNEL_RANGE \ + -DWLAN_AP_STA_CONCURRENCY \ + -DFEATURE_WLAN_SCAN_PNO \ + -DWLAN_FEATURE_PACKET_FILTERING \ + -DWLAN_FEATURE_VOWIFI \ + -DWLAN_FEATURE_11AC \ + -DWLAN_FEATURE_P2P_DEBUG \ + -DWLAN_ENABLE_AGEIE_ON_SCAN_RESULTS \ + -DWLANTL_DEBUG\ + -DWLAN_NS_OFFLOAD \ + -DWLAN_SOFTAP_VSTA_FEATURE \ + -DWLAN_FEATURE_GTK_OFFLOAD \ + -DWLAN_WAKEUP_EVENTS \ + -DFEATURE_WLAN_RA_FILTERING\ + -DWLAN_KD_READY_NOTIFIER \ + -DWLAN_NL80211_TESTMODE \ + -DFEATURE_WLAN_LPHB \ + -DFEATURE_WLAN_PAL_TIMER_DISABLE \ + -DFEATURE_WLAN_PAL_MEM_DISABLE \ + -DQCA_SUPPORT_TX_THROTTLE \ + -DWMI_INTERFACE_EVENT_LOGGING \ + -DATH_SUPPORT_WAPI \ + -DWLAN_FEATURE_LINK_LAYER_STATS \ + -DWLAN_LOGGING_SOCK_SVC_ENABLE \ + -DFEATURE_WLAN_EXTSCAN \ + -DFEATURE_WLAN_LFR \ + -DWLAN_FEATURE_MBSSID \ + -DCONFIG_160MHZ_SUPPORT + +ifeq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS))) +CDEFINES += -DQCA_WIFI_3_0 +CDEFINES += -DQCA_WIFI_3_0_EMU +endif + +ifeq (y,$(filter y,$(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) +CDEFINES += -DQCA_WIFI_3_0_ADRASTEA +CDEFINES += -DADRASTEA_SHADOW_REGISTERS +endif + +ifeq ($(CONFIG_WLAN_FASTPATH), y) +CDEFINES += -DWLAN_FEATURE_FASTPATH +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +CDEFINES += -DFEATURE_NAPI +ifeq ($(CONFIG_WLAN_NAPI_DEBUG), y) +CDEFINES += -DFEATURE_NAPI_DEBUG +endif +endif + +ifeq ($(CONFIG_FEATURE_BMI_2), y) +CDEFINES += -DFEATURE_BMI_2 +endif + +ifeq ($(CONFIG_ARCH_MSM), y) +CDEFINES += -DMSM_PLATFORM +endif + +CDEFINES += -DQCA_SUPPORT_TXRX_LOCAL_PEER_ID + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +CDEFINES += -DQCA_LL_TX_FLOW_CONTROL_V2 +CDEFINES += -DQCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +else +ifeq ($(CONFIG_ROME_IF),pci) +CDEFINES += -DQCA_LL_LEGACY_TX_FLOW_CONTROL +endif +endif + +ifeq ($(CONFIG_DEBUG_LL),y) +CDEFINES += -DQCA_PKT_PROTO_TRACE +endif + +ifneq ($(CONFIG_QCA_CLD_WLAN),) +CDEFINES += -DWCN_PRONTO +CDEFINES += -DWCN_PRONTO_V1 +endif + +ifeq ($(BUILD_DEBUG_VERSION),1) +CDEFINES += -DWLAN_DEBUG \ + -DTRACE_RECORD \ + -DLIM_TRACE_RECORD \ + -DSME_TRACE_RECORD \ + -DHDD_TRACE_RECORD \ + -DPE_DEBUG_LOGW \ + -DPE_DEBUG_LOGE \ + -DDEBUG +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON),y) +CDEFINES += -DTIMER_MANAGER +CDEFINES += -DMEMORY_DEBUG +endif + +ifeq ($(HAVE_CFG80211),1) +CDEFINES += -DWLAN_FEATURE_P2P +CDEFINES += -DWLAN_FEATURE_WFD +ifeq ($(CONFIG_QCOM_VOWIFI_11R),y) +CDEFINES += -DKERNEL_SUPPORT_11R_CFG80211 +CDEFINES += -DUSE_80211_WMMTSPEC_FOR_RIC +endif +endif + +ifeq ($(CONFIG_QCOM_ESE),y) +CDEFINES += -DFEATURE_WLAN_ESE +CDEFINES += -DQCA_COMPUTE_TX_DELAY +CDEFINES += -DQCA_COMPUTE_TX_DELAY_PER_TID +ifeq ($(CONFIG_QCOM_ESE_UPLOAD),y) +CDEFINES += -DFEATURE_WLAN_ESE_UPLOAD +endif +endif + +#normally, TDLS negative behavior is not needed +ifeq ($(CONFIG_QCOM_TDLS),y) +CDEFINES += -DFEATURE_WLAN_TDLS +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR3),y) +CDEFINES += -DWLAN_FEATURE_ROAM_OFFLOAD +endif + +ifeq ($(CONFIG_PRIMA_WLAN_OKC),y) +CDEFINES += -DFEATURE_WLAN_OKC +endif + +ifeq ($(CONFIG_PRIMA_WLAN_11AC_HIGH_TP),y) +CDEFINES += -DWLAN_FEATURE_11AC_HIGH_TP +endif + +ifeq ($(BUILD_DIAG_VERSION),1) +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_LIM +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif +endif + +ifeq ($(CONFIG_HIF_USB), 1) +CDEFINES += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +CDEFINES += -DQCA_SUPPORT_OL_RX_REORDER_TIMEOUT +CDEFINES += -DCONFIG_ATH_PCIE_MAX_PERF=0 -DCONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD=0 -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 +CDEFINES += -DQCA_TX_HTT2_SUPPORT +endif + +# enable the MAC Address auto-generation feature +CDEFINES += -DWLAN_AUTOGEN_MACADDR_FEATURE + +ifeq ($(CONFIG_WLAN_FEATURE_11W),y) +CDEFINES += -DWLAN_FEATURE_11W +endif + +ifeq ($(CONFIG_QCOM_LTE_COEX),y) +CDEFINES += -DFEATURE_WLAN_CH_AVOID +endif + +ifeq ($(CONFIG_WLAN_FEATURE_LPSS),y) +CDEFINES += -DWLAN_FEATURE_LPSS +endif + +ifeq ($(PANIC_ON_BUG),1) +CDEFINES += -DPANIC_ON_BUG +endif + +ifeq ($(WLAN_OPEN_SOURCE), 1) +CDEFINES += -DWLAN_OPEN_SOURCE +endif + +ifeq ($(CONFIG_FEATURE_STATS_EXT), 1) +CDEFINES += -DWLAN_FEATURE_STATS_EXT +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +CDEFINES += -DWLAN_FEATURE_NAN +endif + +ifeq ($(CONFIG_QCA_IBSS_SUPPORT), 1) +CDEFINES += -DQCA_IBSS_SUPPORT +endif + +#Enable OL debug and wmi unified functions +ifeq ($(CONFIG_ATH_PERF_PWR_OFFLOAD), 1) +CDEFINES += -DATH_PERF_PWR_OFFLOAD +endif + +#Disable packet log +ifeq ($(CONFIG_REMOVE_PKT_LOG), 1) +CDEFINES += -DREMOVE_PKT_LOG +endif + +#Enable 11AC TX +ifeq ($(CONFIG_ATH_11AC_TXCOMPACT), 1) +CDEFINES += -DATH_11AC_TXCOMPACT +endif + +#Enable per vdev Tx desc pool +ifeq ($(CONFIG_PER_VDEV_TX_DESC_POOL), 1) +CDEFINES += -DCONFIG_PER_VDEV_TX_DESC_POOL +endif + +#Enable OS specific IRQ abstraction +ifeq ($(CONFIG_ATH_SUPPORT_SHARED_IRQ), 1) +CDEFINES += -DATH_SUPPORT_SHARED_IRQ +endif + +#Enable message based HIF instead of RAW access in BMI +ifeq ($(CONFIG_HIF_MESSAGE_BASED), 1) +CDEFINES += -DHIF_MESSAGE_BASED +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DHIF_PCI +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_HIF_USB), 1) +CDEFINES += -DHIF_USB +CDEFINES += -DCONFIG_HL_SUPPORT +endif + +#Enable FW logs through ini +CDEFINES += -DCONFIG_FW_LOGS_BASED_ON_INI + +#Enable pci read/write config functions +ifeq ($(CONFIG_ATH_PCI), 1) +CDEFINES += -DATH_PCI +endif + +#Enable power management suspend/resume functionality +ifeq ($(CONFIG_ATH_BUS_PM), 1) +CDEFINES += -DATH_BUS_PM +endif + +#Enable FLOWMAC module support +ifeq ($(CONFIG_ATH_SUPPORT_FLOWMAC_MODULE), 1) +CDEFINES += -DATH_SUPPORT_FLOWMAC_MODULE +endif + +#Enable spectral support +ifeq ($(CONFIG_ATH_SUPPORT_SPECTRAL), 1) +CDEFINES += -DATH_SUPPORT_SPECTRAL +endif + +#Enable WDI Event support +ifeq ($(CONFIG_WDI_EVENT_ENABLE), 1) +CDEFINES += -DWDI_EVENT_ENABLE +endif + +#Endianess selection +ifeq ($(CONFIG_LITTLE_ENDIAN), 1) +AH_LITTLE_ENDIAN=1234 +CDEFINES += -DAH_BYTE_ORDER=$(AH_LITTLE_ENDIAN) +else +AH_BIG_ENDIAN=4321 +CDEFINES += -DAH_BYTE_ORDER=$(AH_BIG_ENDIAN) +CDEFINES += -DBIG_ENDIAN_HOST +endif + +#Enable TX reclaim support +ifeq ($(CONFIG_TX_CREDIT_RECLAIM_SUPPORT), 1) +CDEFINES += -DTX_CREDIT_RECLAIM_SUPPORT +endif + +#Enable FTM support +ifeq ($(CONFIG_QCA_WIFI_FTM), 1) +CDEFINES += -DQCA_WIFI_FTM +endif + +#Enable Checksum Offload support +ifeq ($(CONFIG_CHECKSUM_OFFLOAD), 1) +CDEFINES += -DCHECKSUM_OFFLOAD +endif + +#Enable Checksum Offload support +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +CDEFINES += -DIPA_OFFLOAD +endif + +ifneq ($(CONFIG_ARCH_MDM9630), y) +ifeq ($(CONFIG_ARCH_MDM9640), y) +CDEFINES += -DQCA_CONFIG_SMP +endif +endif + +#Enable GTK Offload +ifeq ($(CONFIG_GTK_OFFLOAD), 1) +CDEFINES += -DWLAN_FEATURE_GTK_OFFLOAD +CDEFINES += -DIGTK_OFFLOAD +endif + +#Enable GTK Offload +ifeq ($(CONFIG_EXT_WOW), 1) +CDEFINES += -DWLAN_FEATURE_EXTWOW_SUPPORT +endif + +#Mark it as SMP Kernel +ifeq ($(CONFIG_SMP),y) +CDEFINES += -DQCA_CONFIG_SMP +endif + +ifeq ($(CONFIG_WLAN_FEATURE_RX_WAKELOCK), y) +CDEFINES += -DWLAN_FEATURE_HOLD_RX_WAKELOCK +endif + +#Enable Channel Matrix restriction for all targets +CDEFINES += -DWLAN_ENABLE_CHNL_MATRIX_RESTRICTION + +#features specific to mobile router use case +ifeq ($(CONFIG_MOBILE_ROUTER), y) + +#enable MCC TO SCC switch +CDEFINES += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +#enable wlan auto shutdown feature +CDEFINES += -DFEATURE_WLAN_AUTO_SHUTDOWN + +#enable for MBSSID +CDEFINES += -DWLAN_FEATURE_MBSSID + +#enable AP-AP ACS Optimization +CDEFINES += -DFEATURE_WLAN_AP_AP_ACS_OPTIMIZE + +#Enable 4address scheme +CDEFINES += -DFEATURE_WLAN_STA_4ADDR_SCHEME + +#Disable STA-AP Mode DFS support +CDEFINES += -DFEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + +#Enable OBSS feature +CDEFINES += -DQCA_HT_2040_COEX + +#Disable HT40 in 2.4GHZ STA mode +CDEFINES += -DQCA_HT_20_24G_STA_ONLY + +else #CONFIG_MOBILE_ROUTER + +#Open P2P device interface only for non-Mobile router use cases +CDEFINES += -DWLAN_OPEN_P2P_INTERFACE + +#Enable 2.4 GHz social channels in 5 GHz only mode for p2p usage +CDEFINES += -DWLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + +endif #CONFIG_MOBILE_ROUTER + +#Green AP feature +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP),y) +CDEFINES += -DFEATURE_GREEN_AP +endif + +#Enable RX Full re-order OL feature only "LL and NON-MDM9630 platform" +ifneq ($(CONFIG_ARCH_MDM9630), y) +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DWLAN_FEATURE_RX_FULL_REORDER_OL +endif +endif + +#Enable Signed firmware support for split binary format +ifeq ($(CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT), 1) +CDEFINES += -DQCA_SIGNED_SPLIT_BINARY_SUPPORT +endif + +#Enable single firmware binary format +ifeq ($(CONFIG_QCA_SINGLE_BINARY_SUPPORT), 1) +CDEFINES += -DQCA_SINGLE_BINARY_SUPPORT +endif + +#Enable collecting target RAM dump after kernel panic +ifeq ($(CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC), 1) +CDEFINES += -DTARGET_RAMDUMP_AFTER_KERNEL_PANIC +endif + +#Enable/disable secure firmware feature +ifeq ($(CONFIG_FEATURE_SECURE_FIRMWARE), 1) +CDEFINES += -DFEATURE_SECURE_FIRMWARE +endif + +ifeq ($(CONFIG_ATH_PCIE_ACCESS_DEBUG), 1) +CDEFINES += -DCONFIG_ATH_PCIE_ACCESS_DEBUG +endif + +# Some kernel include files are being moved. Check to see if +# the old version of the files are present + +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/mach-msm/include/mach/msm_smd.h),) +CDEFINES += -DEXISTS_MSM_SMD +endif + +ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/mach-msm/include/mach/msm_smsm.h),) +CDEFINES += -DEXISTS_MSM_SMSM +endif + +# Enable feature support fo Linux version QCMBR +ifeq ($(CONFIG_LINUX_QCMBR),y) +CDEFINES += -DLINUX_QCMBR +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS))) +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_TSO_DEBUG := y +ifeq ($(CONFIG_HELIUMPLUS),y) +CDEFINES += -DHELIUMPLUS_PADDR64 +CDEFINES += -DHELIUMPLUS +ifeq ($(CONFIG_64BIT_PADDR),y) +CDEFINES += -DHTT_PADDR64 +endif +endif +endif + +ifeq ($(CONFIG_FEATURE_TSO),y) +CDEFINES += -DFEATURE_TSO +endif +ifeq ($(CONFIG_FEATURE_TSO_DEBUG),y) +CDEFINES += -DFEATURE_TSO_DEBUG +endif + +ifeq ($(CONFIG_WLAN_LRO), y) +CDEFINES += -DFEATURE_LRO +endif + +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CDEFINES += -DFEATURE_AP_MCC_CH_AVOIDANCE +endif + +ifeq ($(CONFIG_MPC_UT_FRAMEWORK), y) +CDEFINES += -DMPC_UT_FRAMEWORK +endif + +ifeq ($(CONFIG_WLAN_OFFLOAD_PACKETS),y) +CDEFINES += -DWLAN_FEATURE_OFFLOAD_PACKETS +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) +CDEFINES += -DWLAN_FEATURE_MEMDUMP +endif + +ifeq ($(CONFIG_STATICALLY_ADD_11P_CHANNELS),y) +CDEFINES += -DFEATURE_STATICALLY_ADD_11P_CHANNELS +endif + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# WLAN driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif + +# Module information used by KBuild framework +obj-$(CONFIG_QCA_CLD_WLAN) += $(MODNAME).o +$(MODNAME)-y := $(OBJS) diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000000..9cf8e1d9d0 --- /dev/null +++ b/Kconfig @@ -0,0 +1,110 @@ +comment "Qualcomm Atheros CLD WLAN module" + +config QCA_CLD_WLAN + + tristate "Qualcomm Atheros CLD WLAN module" + default n + help + Add support for the Qualcomm Atheros CLD WLAN module + +if QCA_CLD_WLAN != n + +config QCACLD_WLAN_LFR3 + bool "Enable the WLAN Legacy Fast Roaming feature Version 3" + default n + +config PRIMA_WLAN_OKC + bool "Enable the Prima WLAN Opportunistic Key Caching feature" + default n + +config PRIMA_WLAN_11AC_HIGH_TP + bool "Enable the Prima WLAN 802.11ac High Throughput option (depends upon kernel support)" + default n + +config WLAN_FEATURE_11W + bool "Enable the WLAN 802.11w Protected Management Frames feature" + default n + +config WLAN_FEATURE_LPSS + bool "Enable the WLAN LPSS feature" + default n + +config QCOM_VOWIFI_11R + bool "Enable Fast Transition (11r) feature" + default n + +config QCACLD_FEATURE_NAN + bool "Enable NAN feature" + default n + +config QCACLD_FEATURE_GREEN_AP + bool "Enable Green AP feature" + default n + +config HELIUMPLUS + bool "Enable Beeliner based descriptor structures for Helium" + default n + +config 64BIT_PADDR + bool "Enable 37-bit physical/bus addresses" + depends on HELIUMPLUS + default n + +config QCOM_TDLS + bool "Enable TDLS feature" + default n + +config QCOM_LTE_COEX + bool "Enable QCOM LTE Coex feature" + default n + +config MPC_UT_FRAMEWORK + bool "Enable Unit test framework for multiport concurrency" + default n + +config WLAN_OFFLOAD_PACKETS + bool "Enable offload packets feature" + default n + +config WLAN_FEATURE_MEMDUMP + bool "Enable MEMDUMP feature" + default n + +config FEATURE_TSO + bool "Enable TCP Segmentation Offload" + depends on HELIUMPLUS + default n + +config FEATURE_TSO_DEBUG + bool "Enable TCP Segmentation Offload with debug" + depends on FEATURE_TSO + default n + +config WLAN_FASTPATH + bool "Enable fastpath for datapackets" + default n + +config WLAN_NAPI + bool "Enable NAPI - datapath rx" + default n + +config WLAN_NAPI_DEBUG + bool "Enable debug logging on NAPI" + depends on WLAN_NAPI + default n + +config WLAN_TX_FLOW_CONTROL_V2 + bool "Enable tx flow control version:2" + default n + +config WLAN_LRO + bool "Enable Large Receive Offload" + depends on HELIUMPLUS + depends on CONFIG_INET_LRO + default n + +config WLAN_FEATURE_RX_WAKELOCK + bool "Enable RX wake lock feature" + default n + +endif # QCA_CLD_WLAN diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..914198392f --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +KBUILD_OPTIONS := WLAN_ROOT=$(PWD) +KBUILD_OPTIONS += MODNAME=wlan + +#By default build for CLD +WLAN_SELECT := CONFIG_QCA_CLD_WLAN=m +KBUILD_OPTIONS += CONFIG_QCA_WIFI_ISOC=0 +KBUILD_OPTIONS += CONFIG_QCA_WIFI_2_0=1 +KBUILD_OPTIONS += $(WLAN_SELECT) +KBUILD_OPTIONS += $(KBUILD_EXTRA) # Extra config if any + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/config/WCNSS_qcom_cfg.ini b/config/WCNSS_qcom_cfg.ini new file mode 100644 index 0000000000..3deddd75a7 --- /dev/null +++ b/config/WCNSS_qcom_cfg.ini @@ -0,0 +1,591 @@ +# This file allows user to override the factory + +# defaults for the WLAN Driver + + +# Enable IMPS or not +gEnableImps=1 + +# Enable/Disable Idle Scan + +gEnableIdleScan=0 + + +# Increase sleep duration (seconds) during IMPS +# 0 implies no periodic wake up from IMPS. Periodic wakeup is +# unnecessary if Idle Scan is disabled. +gImpsModSleepTime=0 + + +# Enable BMPS or not +gEnableBmps=1 + +# Enable suspend or not + +# 1: Enable standby, 2: Enable Deep sleep, 3: Enable Mcast/Bcast Filter + +gEnableSuspend=3 + + +# Phy Mode (auto, b, g, n, etc) +# Valid values are 0-9, with 0 = Auto, 4 = 11n, 9 = 11ac +# 1 = 11abg, 2 = 11b, 3 = 11g, 5 = 11g only, 6 = 11n only +# 7 = 11b only 8 = 11ac only. +gDot11Mode=0 + + +# CSR Roaming Enable(1) Disable(0) + +gRoamingTime=0 + + +# Assigned MAC Addresses - This will be used until NV items are in place + +# Each byte of MAC address is represented in Hex format as XX + +Intf0MacAddress=000AF58989FF +Intf1MacAddress=000AF58989FE +Intf2MacAddress=000AF58989FD + +Intf3MacAddress=000AF58989FC + + +# UAPSD service interval for VO,VI, BE, BK traffic + +InfraUapsdVoSrvIntv=0 + +InfraUapsdViSrvIntv=0 + +InfraUapsdBeSrvIntv=0 + +InfraUapsdBkSrvIntv=0 + +# Flag to allow STA send AddTspec even when ACM is Off +gAddTSWhenACMIsOff=1 + +# Make 1x1 the default antenna configuration + +gNumRxAnt=1 + + +# Beacon filtering frequency (unit in beacon intervals) + +gNthBeaconFilter=50 + + +# Enable WAPI or not + +# WAPIIsEnabled=0 + + +# Flags to filter Mcast abd Bcast RX packets. + +# Value 0: No filtering, 1: Filter all Multicast. + +# 2: Filter all Broadcast. 3: Filter all Mcast abd Bcast + +McastBcastFilter=3 + + +#Flag to enable HostARPOffload feature or not + +hostArpOffload=1 + +#Flag to enable HostNSOffload feature or not + +hostNSOffload=1 + +# This flag enables IP, TCP and UDP checksum offload +gEnableIpTcpUdpChecksumOffload=1 + +#SoftAP Related Parameters + +# AP MAc addr + +gAPMacAddr=000AF589dcab + + +# 802.11n Protection flag + +gEnableApProt=1 + + +#Enable OBSS protection + +gEnableApOBSSProt=1 + + +#Enable/Disable UAPSD for SoftAP + +gEnableApUapsd=1 + + +# Fixed Rate + +gFixedRate=0 + + +# Maximum Tx power + +# gTxPowerCap=30 + + +# Fragmentation Threshold + +# gFragmentationThreshold=2346 + + +# RTS threshold + +RTSThreshold=1048576 + + +# Intra-BSS forward + +gDisableIntraBssFwd=0 + + +# WMM Enable/Disable + +WmmIsEnabled=0 + + +# 802.11d support + +g11dSupportEnabled=1 + +# 802.11h support + +g11hSupportEnabled=1 + +# DFS Master Capability +gEnableDFSMasterCap=1 + +# ESE Support and fast transition +EseEnabled=1 +ImplicitQosIsEnabled=0 +gNeighborScanTimerPeriod=200 + +gNeighborLookupThreshold=76 +gNeighborReassocThreshold=81 + +gNeighborScanChannelMinTime=20 +gNeighborScanChannelMaxTime=30 +gMaxNeighborReqTries=3 + +# Legacy (non-ESE, non-802.11r) Fast Roaming Support +# To enable, set FastRoamEnabled=1 +# To disable, set FastRoamEnabled=0 +FastRoamEnabled=1 + +#Check if the AP to which we are roaming is better than current AP in terms of RSSI. +#Checking is disabled if set to Zero.Otherwise it will use this value as to how better +#the RSSI of the new/roamable AP should be for roaming +RoamRssiDiff=3 + +# If the RSSI of any available candidate is better than currently associated +# AP by at least gImmediateRoamRssiDiff, then being to roam immediately (without +# registering for reassoc threshold). +# NOTE: Value of 0 means that we would register for reassoc threshold. +gImmediateRoamRssiDiff=10 + +# To enable, set gRoamIntraBand=1 (Roaming within band) +# To disable, set gRoamIntraBand=0 (Roaming across band) +gRoamIntraBand=0 + +#Short Guard Interval Enable/disable + +gShortGI20Mhz=1 + +gShortGI40Mhz=1 + + +#Auto Shutdown Value in seconds. A value of 0 means Auto shutoff is disabled + +gAPAutoShutOff=0 + +#Auto Shutdown wlan : Value in Seconds. 0 means disabled. Max 1 day = 86400 sec +gWlanAutoShutdown = 0 + +# Not used. +gApAutoChannelSelection=0 + + +# Listen Energy Detect Mode Configuration + +# Valid values 0-128 + +# 128 means disable Energy Detect feature + +# 0-9 are threshold code and 7 is recommended value from system if feature is to be enabled. + +# 10-128 are reserved. + +# The EDET threshold mapping is as follows in 3dB step: + +# 0 = -60 dBm + +# 1 = -63 dBm + +# 2 = -66 dBm + +# ... + +# 7 = -81 dBm + +# 8 = -84 dBm + +# 9 = -87 dBm + +# Note: Any of these settings are valid. Setting 0 would yield the highest power saving (in a noisy environment) at the cost of more range. The range impact is approximately #calculated as: + +# + +# Range Loss (dB) = EDET threshold level (dBm) + 97 dBm. + +# + +gEnablePhyAgcListenMode=128 + + +#Preferred band (both or 2.4 only or 5 only) + +BandCapability=0 + + +#Beacon Early Termination (1 = enable the BET feature, 0 = disable) + +enableBeaconEarlyTermination=0 + +beaconEarlyTerminationWakeInterval=3 + + +#Channel Bonding +gChannelBondingMode5GHz=1 + + +#Enable Keep alive with non-zero period value + +gStaKeepAlivePeriod = 30 + +#Say gGoKeepAlivePeriod(5 seconds) and gGoLinkMonitorPeriod(10 seconds). +#For every 10 seconds DUT send Qos Null frame(i.e., Keep Alive frame if link is idle for last 10 seconds.) +#For both active and power save clients. + +#Power save clients: DUT set TIM bit from 10th second onwards and till client honors TIM bit. +#If doesn't honor for 5 seconds then DUT remove client. + +#Active clients: DUT send Qos Null frame for 10th seconds onwards if it is not success still we try on +#11th second if not tries on 12th and so on till 15th second. Hence before disconnection DUT will send 5 NULL frames. +#Hence in any case DUT will detect client got removed in (10+5) seconds. i.e., (gGoKeepAlivePeriod + gGoLinkMonitorPeriod).. + +#gGoLinkMonitorPeriod/ gApLinkMonitorPeriod is period where link is idle and it is period +#where we send NULL frame. + +#gApLinkMonitorPeriod = 10 + +#gGoLinkMonitorPeriod = 10 + +#gGoKeepAlivePeriod/gApKeepAlivePeriod is time to spend to check whether frame are succeed to send or not. +#Hence total effective detection time is gGoLinkMonitorPeriod+ gGoKeepAlivePeriod/gApLinkMonitorPeriod+ gApKeepAlivePeriod. + + +gGoKeepAlivePeriod = 20 + +gApKeepAlivePeriod = 20 + + +#If set will start with active scan after driver load, otherwise will start with + +#passive scan to find out the domain + +gEnableBypass11d=1 + + +#If set to 0, will not scan DFS channels + +gEnableDFSChnlScan=1 + +# Enable DFS channel roam +# 0: DISABLE, 1: ENABLED_NORMAL, 2: ENABLED_ACTIVE +gAllowDFSChannelRoam=1 + +gVhtChannelWidth=2 +gEnableLogp=1 + + +# Enable Automatic Tx Power control + +gEnableAutomaticTxPowerControl=1 + +# 0 for OLPC 1 for CLPC and SCPC +gEnableCloseLoop=1 + +#Data Inactivity Timeout when in powersave (in ms) +gDataInactivityTimeout=200 + +# VHT Tx/Rx MCS values +# Valid values are 0,1,2. If commented out, the default value is 0. +# 0=MCS0-7, 1=MCS0-8, 2=MCS0-9 +gVhtRxMCS=2 +gVhtTxMCS=2 + +# VHT Tx/Rx MCS values for 2x2 +# Valid values are 0,1,2. If commented out, the default value is 0. +# 0=MCS0-7, 1=MCS0-8, 2=MCS0-9 +gEnable2x2=1 +gVhtRxMCS2x2=2 +gVhtTxMCS2x2=2 + +# Set txchainmask and rxchainmask +# These parameters are used only if gEnable2x2 is 0 +# Valid values are 1,2 +# Set gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0. +# Set gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1. +gSetTxChainmask1x1=1 +gSetRxChainmask1x1=1 + +# Scan Timing Parameters +# gPassiveMaxChannelTime=110 +# gPassiveMinChannelTime=60 +gActiveMaxChannelTime=40 +gActiveMinChannelTime=20 + +#If set to 0, MCC is not allowed. +gEnableMCCMode=1 + +# MCC to SCC Switch mode: 0-Disable 1-Enable 2-Force SCC if same band +gWlanMccToSccSwitchMode = 0 + +# 1=enable STBC; 0=disable STBC +gEnableRXSTBC=1 + +# 1=enable tx STBC; 0=disable +gEnableTXSTBC=1 + +# 1=enable rx LDPC; 0=disable +gEnableRXLDPC=1 + +#Enable/Disable Tx beamforming +gTxBFEnable=1 + +# Enable Tx beamforming in VHT20MHz +# Valid values are 0,1. If commented out, the default value is 0. +# 0=disable, 1=enable +gEnableTxBFin20MHz=1 + +#Enable/Disable SU Tx beamformer support. +gEnableTxSUBeamformer=1 + +#Enable Scan Results Aging based on timer +#Timer value is in seconds +#If Set to 0 it will not enable the feature +gScanAgingTime=30 + +#Enable Scan Results Aging based on number of scans +gScanResultAgeCount=1 + +#Enable Power saving mechanism Based on Android Framework +#If set to 0 Driver internally control the Power saving mechanism +#If set to 1 Android Framwrok control the Power saving mechanism +isAndroidPsEn=0 + +#Enable thermal mitigation +gThermalMitigationEnable=0 + +gEnableFastRoamInConcurrency=1 + +#Maxium Channel time in msec +gMaxMediumTime = 6000 + +# 802.11K support +gRrmEnable=1 +gRrmOperChanMax=8 +gRrmNonOperChanMax=8 +gRrmRandIntvl=100 + +#Scan offload +gEnableDirectedScanOffload=1 + +#FlexConnect Power Factor +#Default is set to 0 (disable) +gFlexConnectPowerFactor=0 + +#Disable split scan, the FW will take care of it +gNumChanCombinedConc=60 + +#Enable Power Save offload +gEnablePowerSaveOffload=2 + +#Enable firmware uart print +gEnablefwprint=0 + +#Enable firmware log +gEnablefwlog=1 + +#IPA config +gIPAConfig=0 +gIPADescSize=800 +gIPAPreFilterEnable=1 +gIPARMEnable=1 +gIPAIPv6Enable=1 + +IpaUcOffloadEnabled=0 +gIpaUcStaOffload=0 + +#P2P Listen offload +gEnableP2pListenOffload=1 + +# Maximum Receive AMPDU size (VHT only. Valid values: 0->8k 1->16k 2->32k 3->64k 4->128k) +gVhtAmpduLenExponent=7 + +# Maximum MPDU length (VHT only. Valid values: 0->3895 octets, 1->7991 octets, 2->11454 octets) +gVhtMpduLen=2 + +# Maximum number of wow filters required +#gMaxWoWFilters=22 + +# WOW Enable/Disable. +# 0 - Disable both magic pattern match and pattern byte match. +# 1 - Enable magic pattern match on all interfaces. +# 2 - Enable pattern byte match on all interfaces. +# 3 - Enable both magic patter and pattern byte match on all interfaces. +# Default value of gEnableWoW is 3. +# gEnableWoW=0 + +# Enable or Disable MCC Adaptive Scheduler at the FW +# 1=Enable (default), 0=Disable +gEnableMCCAdaptiveScheduler=1 + +#Enable or Disable p2p device address administered +isP2pDeviceAddrAdministrated=0 + +#Enable Rx thread +gEnableRxThread=1 + +#Enable NAPI +gEnableNAPI=0 + +# Set Thermal Power limit +TxPower2g=10 +TxPower5g=10 + +# Remove Overlap channel restriction +gEnableOverLapCh=0 + +#Enable VHT on 2.4Ghz +gEnableVhtFor24GHzBand=1 + +#Enable or Disable 5G early beacon termination +gEnable5gEBT=1 + +#Maximum number of offload peers supported +# gMaxOffloadPeers=2 + +# controlling the following offload patterns +# through ini parameter. Default value is 1 +# to disable set it to zero. ssdp = 0 +# Setup multicast pattern for mDNS 224.0.0.251, +# SSDP 239.255.255.250 and LLMNR 224.0.0.252 +ssdp = 0 + +#Enable Memory Deep Sleep +gEnableMemDeepSleep=1 + +# Bus bandwidth threshold values in terms of number of packets +gBusBandwidthHighThreshold=2000 +gBusBandwidthMediumThreshold=500 +gBusBandwidthLowThreshold=150 + +# Bus bandwidth compute timeout value in ms +gBusBandwidthComputeInterval=100 + +# Regulatory Setting; 0=STRICT; 1=CUSTOM +gRegulatoryChangeCountry=1 +# RA filtering rate limit param, the current value would not +# help if the lifetime in RA is less than 3*60=3min. Then +# we need to change it, though it is uncommon. +# gRAFilterEnable=0 +gRArateLimitInterval=600 + +# Maximum number of concurrent connections +gMaxConcurrentActiveSessions=2 + +# Disable/Enable GreenAP +# 0 to disable, 1 to enable, default: 1 +gEnableGreenAp=1 + +# Radar PRI multiplier +gDFSradarMappingPriMultiplier=4 + +gPNOScanSupport=1 + +# Enable/Disable RX full reorder offload +gReorderOffloadSupported=1 + +#Enable/Disable LPASS support +# 0 to disable, 1 to enable +gEnableLpassSupport=0 + +# Whether userspace country code setting shld have priority +gCountryCodePriority=1 + +# Enable(1)/Disable(0) SIFS burst +gEnableSifsBurst=1 + +# Enable or Disable Multi-user MIMO +# 1=Enable (default), 0=Disable +gEnableMuBformee=1 + +# Enable/Disable channel avoidance for SAP in SCC scenario +# 0 - disable +# 1 - enable +gSapSccChanAvoidance=0 + +# Inactivity time (in ms) to end TX Service Period while in IBSS power save mode +gIbssTxSpEndInactivityTime=10 + +# Enable/Disable Roaming Offload Support (a.k.a Key Management Offload) +# 0 to disable, 1 to enable +gRoamOffloadEnabled=0 + +# Enable support for TDLS +# 0 - disable +# 1 - enable +gEnableTDLSSupport=1 + +# Enable support for Implicit Trigger of TDLS. That is, wlan driver shall +# initiate TDLS Discovery towards a peer whenever setup criteria (throughput +# and RSSI) is met and then will initiate teardown when teardown criteria +# (idle packet count and RSSI) is met. +# 0 - disable +# 1 - enable +gEnableTDLSImplicitTrigger=1 + +# Enable TDLS External Control. That is, user space application has to +# first configure a peer MAC in wlan driver towards which TDLS is desired. +# Device will establish TDLS only towards those configured peers whenever +# TDLS criteria (throughput and RSSI threshold) is met and teardown TDLS +# when teardown criteria (idle packet count and RSSI) is met. However, +# device will accept TDLS connection if it is initiated from any other peer, +# even if that peer is not configured. +# 0 - disable +# 1 - enable +# For TDLS External Control, Implicit Trigger must also be enabled. +gTDLSExternalControl=1 + +# Enable support for TDLS off-channel operation +# 0 - disable +# 1 - enable +# TDLS off-channel operation will be invoked when there is only one +# TDLS connection. +gEnableTDLSOffChannel=1 + +# Enable or Disable Random MAC (Spoofing) +# 1=Enable, 0=Disable (default) +gEnableMacAddrSpoof=0 + +END + +# Note: Configuration parser would not read anything past the END marker + diff --git a/core/bmi/inc/bmi.h b/core/bmi/inc/bmi.h new file mode 100644 index 0000000000..4548fd7111 --- /dev/null +++ b/core/bmi/inc/bmi.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ================================================================ */ +/* BMI declarations and prototypes */ +/* */ +/* ================================================================= */ + +#ifndef _BMI_H_ +#define _BMI_H_ +#include "bmi_msg.h" +#include "cdf_trace.h" +#include "ol_if_athvar.h" +#include "hif.h" + +#ifdef HIF_PCI +void bmi_cleanup(struct ol_softc *scn); +CDF_STATUS bmi_done(struct ol_softc *scn); +CDF_STATUS bmi_download_firmware(struct ol_softc *scn); +#else +static inline void bmi_cleanup(struct ol_softc *scn) +{ + return; +} + +static inline CDF_STATUS bmi_done(struct ol_softc *scn) +{ + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS bmi_download_firmware(struct ol_softc *scn) +{ + return CDF_STATUS_SUCCESS; +} +#endif +#endif /* _BMI_H_ */ diff --git a/core/bmi/inc/ol_fw.h b/core/bmi/inc/ol_fw.h new file mode 100644 index 0000000000..a9918d7cd8 --- /dev/null +++ b/core/bmi/inc/ol_fw.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_FW_H_ +#define _OL_FW_H_ + +#ifdef QCA_WIFI_FTM +#include "cdf_types.h" +#endif +#include "hif.h" + +#define AR6004_VERSION_REV1_3 0x31c8088a + +#define AR9888_REV2_VERSION 0x4100016c +#define AR6320_REV1_VERSION 0x5000000 +#define AR6320_REV1_1_VERSION 0x5000001 +#define AR6320_REV1_VERSION_1 AR6320_REV1_1_VERSION +#define AR6320_REV1_3_VERSION 0x5000003 +#define AR6320_REV2_VERSION AR6320_REV1_1_VERSION +#define AR6320_REV2_1_VERSION 0x5010000 +#define AR6320_REV3_VERSION 0x5020000 +#define AR6320_REV3_2_VERSION 0x5030000 +#define AR6320_REV4_VERSION AR6320_REV2_1_VERSION +#define AR6320_DEV_VERSION 0x1000000 + +#ifdef HIF_PCI +void ol_target_failure(void *instance, CDF_STATUS status); +uint8_t ol_get_number_of_peers_supported(struct ol_softc *scn); +#else +static inline void ol_target_failure(void *instance, CDF_STATUS status) +{ + return; +} + +static inline uint8_t ol_get_number_of_peers_supported(struct ol_softc *scn) +{ + return 1; +} +#endif +#endif /* _OL_FW_H_ */ diff --git a/core/bmi/inc/ol_if_athvar.h b/core/bmi/inc/ol_if_athvar.h new file mode 100644 index 0000000000..c820cbe2f0 --- /dev/null +++ b/core/bmi/inc/ol_if_athvar.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_ATH_ATHVAR_H +#define _DEV_OL_ATH_ATHVAR_H + +#include +#include "cdf_types.h" +#include "cdf_lock.h" +#include "wmi_unified_api.h" +#include "htc_api.h" +#include "bmi_msg.h" +#include "ol_txrx_api.h" +#include "ol_txrx_ctrl_api.h" +#include "ol_txrx_osif_api.h" +#include "ol_params.h" +#include + +#ifdef CONFIG_CNSS +#include +#endif + +#include "ol_ctrl_addba_api.h" +typedef void *hif_handle_t; + +struct ol_version { + uint32_t host_ver; + uint32_t target_ver; + uint32_t wlan_ver; + uint32_t wlan_ver_1; + uint32_t abi_ver; +}; + +typedef enum _ol_target_status { + OL_TRGET_STATUS_CONNECTED = 0, /* target connected */ + OL_TRGET_STATUS_RESET, /* target got reset */ + OL_TRGET_STATUS_EJECT, /* target got ejected */ + OL_TRGET_STATUS_SUSPEND /*target got suspend */ +} ol_target_status; + +enum ol_ath_tx_ecodes { + TX_IN_PKT_INCR = 0, + TX_OUT_HDR_COMPL, + TX_OUT_PKT_COMPL, + PKT_ENCAP_FAIL, + TX_PKT_BAD, + RX_RCV_MSG_RX_IND, + RX_RCV_MSG_PEER_MAP, + RX_RCV_MSG_TYPE_TEST +}; + +/* + * structure to hold the packet error count for CE and hif layer + */ +struct ol_ath_stats { + int hif_pipe_no_resrc_count; + int ce_ring_delta_fail_count; +}; + +#endif /* _DEV_OL_ATH_ATHVAR_H */ diff --git a/core/bmi/src/bmi.c b/core/bmi/src/bmi.c new file mode 100644 index 0000000000..7104619faf --- /dev/null +++ b/core/bmi/src/bmi.c @@ -0,0 +1,470 @@ +/* + * copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "i_bmi.h" + +/* APIs visible to the driver */ + +/* BMI_1 refers QCA6174 target; the ADDR is AXI addr */ +#define BMI_1_TEST_ADDR (0xa0000) +/* BMI_2 ; */ +#define BMI_2_TEST_ADDR (0x6E0000) +/* Enable BMI_TEST COMMANDs; The Value 0x09 is randomly choosen */ +#define BMI_TEST_ENABLE (0x09) + +static CDF_STATUS +bmi_command_test(uint32_t command, uint32_t address, uint8_t *data, + uint32_t length, struct ol_softc *scn) +{ + switch (command) { + case BMI_NO_COMMAND: + return bmi_no_command(scn); + case BMI_WRITE_MEMORY: + return bmi_write_memory(address, data, length, scn); + case BMI_READ_MEMORY: + return bmi_read_memory(address, data, length, scn); + case BMI_EXECUTE: + return bmi_execute(address, (uint32_t *)data, scn); + default: + break; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS bmi_init(struct ol_softc *scn) +{ + if (!scn) { + BMI_ERR("Invalid scn Context"); + bmi_assert(0); + return CDF_STATUS_NOT_INITIALIZED; + } + scn->bmi_done = false; + + if (!scn->bmi_cmd_buff) { + scn->bmi_cmd_buff = cdf_os_mem_alloc_consistent(scn->cdf_dev, + MAX_BMI_CMDBUF_SZ, &scn->bmi_cmd_da, 0); + if (!scn->bmi_cmd_buff) { + BMI_ERR("No Memory for BMI Command"); + return CDF_STATUS_E_NOMEM; + } + } + + if (!scn->bmi_rsp_buff) { + scn->bmi_rsp_buff = cdf_os_mem_alloc_consistent(scn->cdf_dev, + MAX_BMI_CMDBUF_SZ, &scn->bmi_rsp_da, 0); + if (!scn->bmi_rsp_buff) { + BMI_ERR("No Memory for BMI Response"); + goto end; + } + } + return CDF_STATUS_SUCCESS; +end: + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_cmd_buff, scn->bmi_cmd_da, 0); + scn->bmi_cmd_buff = NULL; + return CDF_STATUS_E_NOMEM; +} + +void bmi_cleanup(struct ol_softc *scn) +{ + if (scn->bmi_cmd_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_cmd_buff, scn->bmi_cmd_da, 0); + scn->bmi_cmd_buff = NULL; + scn->bmi_cmd_da = 0; + } + + if (scn->bmi_rsp_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_rsp_buff, scn->bmi_rsp_da, 0); + scn->bmi_rsp_buff = NULL; + scn->bmi_rsp_da = 0; + } +} + + +CDF_STATUS bmi_done(struct ol_softc *scn) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + hif_claim_device(scn, scn); + + if (IHELIUM_NO_BMI) + return status; + + status = bmi_done_local(scn); + + if (status != CDF_STATUS_SUCCESS) + BMI_ERR("BMI_DONE Failed status:%d", status); + return status; +} + +CDF_STATUS +bmi_get_target_info(struct bmi_target_info *targ_info, + struct ol_softc *scn) +{ + int status = 0; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + uint32_t cid, length; + + if (scn->bmi_done) { + BMI_ERR("BMI Phase is Already Done"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return CDF_STATUS_NOT_INITIALIZED; + } + cid = BMI_GET_TARGET_INFO; + + cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(struct bmi_target_info); + + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid), + (uint8_t *)bmi_rsp_buff, &length, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Failed to target info: status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(targ_info, bmi_rsp_buff, length); + return CDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_BMI_2 +static inline uint32_t bmi_get_test_addr(void) +{ + return BMI_2_TEST_ADDR; +} +#else +static inline uint32_t bmi_get_test_addr(void) +{ + return BMI_1_TEST_ADDR; +} +#endif + +CDF_STATUS bmi_download_firmware(struct ol_softc *scn) +{ + uint8_t data[10], out[10]; + uint32_t address; + int32_t ret; + + if (IHELIUM_NO_BMI) + return CDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */ + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return CDF_STATUS_NOT_INITIALIZED; + } +#ifdef CONFIG_CNSS + if (BMI_TEST_ENABLE == cnss_get_bmi_setup()) { + ret = snprintf(data, 10, "ABCDEFGHI"); + BMI_DBG("ret:%d writing data:%s\n", ret, data); + address = bmi_get_test_addr(); + + if (bmi_init(scn) != CDF_STATUS_SUCCESS) { + BMI_WARN("BMI_INIT Failed; No Memory!"); + goto end; + } + bmi_command_test(BMI_NO_COMMAND, address, data, 9, scn); + bmi_command_test(BMI_WRITE_MEMORY, address, data, 9, scn); + bmi_command_test(BMI_READ_MEMORY, address, out, 9, scn); + BMI_DBG("Output:%s", out); + } +#endif +end: + return bmi_firmware_download(scn); +} + +CDF_STATUS +bmi_read_soc_register(uint32_t address, uint32_t *param, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset, param_len; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + cdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address)); + cdf_mem_set(bmi_rsp_buff, 0, sizeof(cid) + sizeof(address)); + + if (scn->bmi_done) { + BMI_DBG("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Read SOC Register:device: 0x%p, address: 0x%x", + scn, address); + + cid = BMI_READ_SOC_REGISTER; + + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_DBG("Unable to read from the device; status:%d", status); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Read SOC Register: Exit value: %d", *param); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_write_soc_register(uint32_t address, uint32_t param, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + bmi_assert(BMI_COMMAND_FITS(size)); + cdf_mem_set(bmi_cmd_buff, 0, size); + + if (scn->bmi_done) { + BMI_DBG("Command disallowed"); + return CDF_STATUS_E_FAILURE; + } + + BMI_DBG("SOC Register Write:device:0x%p, addr:0x%x, param:%d", + scn, address, param); + + cid = BMI_WRITE_SOC_REGISTER; + + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), ¶m, sizeof(param)); + offset += sizeof(param); + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + BMI_DBG("BMI Read SOC Register: Exit"); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmilz_data(uint8_t *buffer, uint32_t length, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(length); + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Send LZ Data: device: 0x%p, length: %d", + scn, length); + + cid = BMI_LZ_DATA; + + remaining = length; + while (remaining) { + txlen = (remaining < (BMI_DATASZ_MAX - header)) ? + remaining : (BMI_DATASZ_MAX - header); + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + cdf_mem_copy(&(bmi_cmd_buff[offset]), + &buffer[length - remaining], txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device: status:%d", + status); + return CDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + + BMI_DBG("BMI LZ Data: Exit"); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_sign_stream_start(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buf[BMI_DATASZ_MAX + 4]; + uint8_t *src; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint32_t remaining, txlen; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + BMI_ERR("Sign Stream start:device:0x%p, addr:0x%x, length:%d", + scn, address, length); + + cid = BMI_SIGN_STREAM_START; + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 0x3) { + remaining = remaining + (4 - (remaining & 0x3)); + memcpy(aligned_buf, src, remaining); + src = aligned_buf; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(offset); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + cdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, + bmi_cmd_buff, offset, + NULL, NULL, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", + status); + return CDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + BMI_DBG("BMI SIGN Stream Start: Exit"); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmilz_stream_start(uint32_t address, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + cdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address)); + + if (scn->bmi_done) { + BMI_DBG("Command disallowed"); + return CDF_STATUS_E_PERM; + } + BMI_DBG("BMI LZ Stream Start: (device: 0x%p, address: 0x%x)", + scn, address); + + cid = BMI_LZ_STREAM_START; + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to Start LZ Stream to the device status:%d", + status); + return CDF_STATUS_E_FAILURE; + } + BMI_DBG("BMI LZ Stream: Exit"); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_fast_download(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_softc *scn) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t last_word = 0; + uint32_t last_word_offset = length & ~0x3; + uint32_t unaligned_bytes = length & 0x3; + + status = bmilz_stream_start(address, scn); + if (status != CDF_STATUS_SUCCESS) + goto end; + + /* copy the last word into a zero padded buffer */ + if (unaligned_bytes) + cdf_mem_copy(&last_word, &buffer[last_word_offset], + unaligned_bytes); + + status = bmilz_data(buffer, last_word_offset, scn); + + if (status != CDF_STATUS_SUCCESS) + goto end; + + if (unaligned_bytes) + status = bmilz_data((uint8_t *) &last_word, 4, scn); + + if (status != CDF_STATUS_SUCCESS) + /* + * Close compressed stream and open a new (fake) one. + * This serves mainly to flush Target caches. + */ + status = bmilz_stream_start(0x00, scn); +end: + return status; +} + diff --git a/core/bmi/src/bmi_1.c b/core/bmi/src/bmi_1.c new file mode 100644 index 0000000000..2d0783a5a4 --- /dev/null +++ b/core/bmi/src/bmi_1.c @@ -0,0 +1,321 @@ +/* + * copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "i_bmi.h" + +/* APIs visible to the driver */ + +CDF_STATUS +bmi_read_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, rxlen; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + uint32_t align; + + if (scn->bmi_done) { + BMI_DBG("command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!scn->bmi_cmd_buff || !scn->bmi_rsp_buff) { + BMI_ERR("BMI Initialization hasn't done"); + return CDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length))); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + cdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + + BMI_DBG("BMI Read: device: 0x%p, address: 0x%x, length: %d", + scn, address, length); + + cid = BMI_READ_MEMORY; + align = 0; + remaining = length; + + while (remaining) { + rxlen = (remaining < BMI_DATASZ_MAX) ? + remaining : BMI_DATASZ_MAX; + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen)); + offset += sizeof(length); + + /* note we reuse the same buffer to receive on */ + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + bmi_rsp_buff, &rxlen, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to read from the device"); + return CDF_STATUS_E_FAILURE; + } + if (remaining == rxlen) { + cdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen - align); + /* last align bytes are invalid */ + } else { + cdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen); + } + remaining -= rxlen; + address += rxlen; + } + + BMI_DBG("BMI Read Memory: Exit"); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_write_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buffer[BMI_DATASZ_MAX]; + uint8_t *src; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff) { + BMI_ERR("BMI initialization hasn't done"); + return CDF_STATUS_E_PERM; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + BMI_DBG("BMI Write Memory:device: 0x%p, address: 0x%x, length: %d", + scn, address, length); + + cid = BMI_WRITE_MEMORY; + + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 3) { + /* align it with 4 bytes */ + remaining = remaining + (4 - (remaining & 3)); + memcpy(aligned_buffer, src, remaining); + src = aligned_buffer; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + cdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + NULL, NULL, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device; status:%d", + status); + return CDF_STATUS_E_FAILURE; + } + remaining -= txlen; + address += txlen; + } + + BMI_DBG("BMI Write Memory: Exit"); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_execute(uint32_t address, A_UINT32 *param, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t param_len; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return CDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(size)); + cdf_mem_set(bmi_cmd_buff, 0, size); + cdf_mem_set(bmi_rsp_buff, 0, size); + + + BMI_DBG("BMI Execute: device: 0x%p, address: 0x%x, param: %d", + scn, address, *param); + + cid = BMI_EXECUTE; + + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), param, sizeof(*param)); + offset += sizeof(*param); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, 0); + if (status) { + BMI_ERR("Unable to read from the device status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Execute: Exit (param: %d)", *param); + return CDF_STATUS_SUCCESS; +} + +inline CDF_STATUS +bmi_no_command(struct ol_softc *scn) +{ + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_firmware_download(struct ol_softc *scn) +{ + CDF_STATUS status; + struct bmi_target_info targ_info; + cdf_mem_zero(&targ_info, sizeof(targ_info)); + + /* Initialize BMI */ + status = bmi_init(scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI Initialization Failed err:%d", status); + return status; + } + + /* Get target information */ + status = bmi_get_target_info(&targ_info, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI Target Info get failed: status:%d", status); + return status; + } + + scn->target_type = targ_info.target_type; + scn->target_version = targ_info.target_ver; + + /* Configure target */ + status = ol_configure_target(scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI Configure Target Failed status:%d", status); + return status; + } + + status = ol_download_firmware(scn); + if (status != CDF_STATUS_SUCCESS) + BMI_ERR("BMI Download Firmware Failed Status:%d", status); + + return status; +} + +CDF_STATUS bmi_done_local(struct ol_softc *scn) +{ + int status; + uint32_t cid; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return CDF_STATUS_NOT_INITIALIZED; + } + + if (scn->bmi_done) { + BMI_DBG("bmi_done_local skipped"); + return CDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Done: Enter (device: 0x%p)", scn); + + scn->bmi_done = true; + cid = BMI_DONE; + + if (!scn->bmi_cmd_buff) { + BMI_ERR("Invalid scn BMICmdBuff"); + bmi_assert(0); + return CDF_STATUS_NOT_INITIALIZED; + } + + cdf_mem_copy(scn->bmi_cmd_buff, &cid, sizeof(cid)); + + status = hif_exchange_bmi_msg(scn, scn->bmi_cmd_buff, + sizeof(cid), NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device; status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + if (scn->bmi_cmd_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_cmd_buff, scn->bmi_cmd_da, 0); + scn->bmi_cmd_buff = NULL; + scn->bmi_cmd_da = 0; + } + + if (scn->bmi_rsp_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_rsp_buff, scn->bmi_rsp_da, 0); + scn->bmi_rsp_buff = NULL; + scn->bmi_rsp_da = 0; + } + + return CDF_STATUS_SUCCESS; +} diff --git a/core/bmi/src/bmi_2.c b/core/bmi/src/bmi_2.c new file mode 100644 index 0000000000..cd8ce45bcf --- /dev/null +++ b/core/bmi/src/bmi_2.c @@ -0,0 +1,452 @@ +/* + * copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#include "i_bmi.h" +/* This need to defined in firmware interface files. + * Defining here to address compilation issues. + * Will be deleted once firmware interface files for + * target are merged + */ +#define BMI_LOAD_IMAGE 18 + +CDF_STATUS +bmi_no_command(struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t length; + uint8_t ret = 0; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed: BMI DONE ALREADY"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer"); + return CDF_STATUS_NOT_INITIALIZED; + } + cid = BMI_NO_COMMAND; + + cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(ret); + + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid), + bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS); + + if (status) { + BMI_ERR("Failed to write bmi no command status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&ret, bmi_rsp_buff, length); + if (ret != 0) { + BMI_ERR("bmi no command response error ret 0x%x", ret); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_done_local(struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t length; + uint8_t ret = 0; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer"); + return CDF_STATUS_NOT_INITIALIZED; + } + cid = BMI_DONE; + + cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(ret); + + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid), + bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS); + + if (status) { + BMI_ERR("Failed to close BMI on target status:%d", status); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(&ret, bmi_rsp_buff, length); + + if (ret != 0) { + BMI_ERR("BMI DONE response failed:%d", ret); + return CDF_STATUS_E_FAILURE; + } + + if (scn->bmi_cmd_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_cmd_buff, scn->bmi_cmd_da, 0); + scn->bmi_cmd_buff = NULL; + scn->bmi_cmd_da = 0; + } + + if (scn->bmi_rsp_buff) { + cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ, + scn->bmi_rsp_buff, scn->bmi_rsp_da, 0); + scn->bmi_rsp_buff = NULL; + scn->bmi_rsp_da = 0; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_write_memory(uint32_t address, + uint8_t *buffer, + uint32_t length, + struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t rsp_len; + uint8_t ret = 0; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buffer[BMI_DATASZ_MAX]; + uint8_t *src; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("BMI Initialization is not happened"); + return CDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + cid = BMI_WRITE_MEMORY; + rsp_len = sizeof(ret); + + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 3) { + /* align it with 4 bytes */ + remaining = remaining + (4 - (remaining & 3)); + memcpy(aligned_buffer, src, remaining); + src = aligned_buffer; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + cdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + bmi_rsp_buff, &rsp_len, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("BMI Write Memory Failed status:%d", status); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(&ret, bmi_rsp_buff, rsp_len); + if (ret != 0) { + BMI_ERR("BMI Write memory response fail: %x", ret); + return CDF_STATUS_E_FAILURE; + } + remaining -= txlen; address += txlen; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_read_memory(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint8_t ret = 0; + uint32_t offset; + uint32_t remaining, rxlen, rsp_len, total_len; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + /* note we reuse the same buffer to receive on */ + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(length); + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("BMI Initialization is not done"); + return CDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + size)); + cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + size); + cdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + size); + + cid = BMI_READ_MEMORY; + rsp_len = sizeof(ret); + remaining = length; + + while (remaining) { + rxlen = (remaining < BMI_DATASZ_MAX - rsp_len) ? remaining : + (BMI_DATASZ_MAX - rsp_len); + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen)); + offset += sizeof(length); + + total_len = rxlen + rsp_len; + + status = hif_exchange_bmi_msg(scn, + bmi_cmd_buff, + offset, + bmi_rsp_buff, + &total_len, + BMI_EXCHANGE_TIMEOUT_MS); + + if (status) { + BMI_ERR("BMI Read memory failed status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&ret, bmi_rsp_buff, rsp_len); + + if (ret != 0) { + BMI_ERR("bmi read memory response fail %x", ret); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&buffer[length - remaining], + (uint8_t *)bmi_rsp_buff + rsp_len, rxlen); + remaining -= rxlen; address += rxlen; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +bmi_execute(uint32_t address, uint32_t *param, + struct ol_softc *scn) +{ + uint32_t cid; + int status; + uint32_t length; + uint8_t ret = 0; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("No Memory Allocated for bmi buffers"); + return CDF_STATUS_NOT_INITIALIZED; + } + + cid = BMI_EXECUTE; + + cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(ret); + + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid), + bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS); + + if (status) { + BMI_ERR("Failed to do BMI_EXECUTE status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&ret, bmi_rsp_buff, length); + + if (ret != 0) { + BMI_ERR("%s: ret 0x%x", __func__, ret); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS +bmi_load_image(dma_addr_t address, + uint32_t size, struct ol_softc *scn) +{ + uint32_t cid; + CDF_STATUS status; + uint32_t offset; + uint32_t length; + uint8_t ret = 0; + uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff; + uint32_t addr_h, addr_l; + + if (scn->bmi_done) { + BMI_ERR("Command disallowed"); + return CDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer"); + return CDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + cdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address)); + + + BMI_DBG("%s: Enter device: 0x%p, size %d", __func__, scn, size); + + cid = BMI_LOAD_IMAGE; + + offset = 0; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + addr_l = address & 0xffffffff; + addr_h = 0x00; + cdf_mem_copy(&(bmi_cmd_buff[offset]), &addr_l, sizeof(addr_l)); + offset += sizeof(addr_l); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &addr_h, sizeof(addr_h)); + offset += sizeof(addr_h); + cdf_mem_copy(&(bmi_cmd_buff[offset]), &size, sizeof(size)); + offset += sizeof(size); + length = sizeof(ret); + + status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset, + bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS); + + if (status) { + BMI_ERR("BMI Load Image Failed; status:%d", status); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&ret, bmi_rsp_buff, length); + if (ret != 0) { + BMI_ERR("%s: ret 0x%x", __func__, ret); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS bmi_enable(struct ol_softc *scn) +{ + struct bmi_target_info targ_info; + struct image_desc_info image_desc_info; + CDF_STATUS status; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return CDF_STATUS_NOT_INITIALIZED; + } + + if (scn->bmi_cmd_buff == NULL || scn->bmi_rsp_buff == NULL) { + BMI_ERR("bmi_open failed!"); + return CDF_STATUS_NOT_INITIALIZED; + } + + status = bmi_get_target_info(&targ_info, scn); + if (status != CDF_STATUS_SUCCESS) + return status; + + BMI_DBG("%s: target type 0x%x, target ver 0x%x", __func__, + targ_info.target_type, targ_info.target_ver); + scn->target_type = targ_info.target_type; + scn->target_version = targ_info.target_ver; + + if (cnss_get_fw_image(&image_desc_info) != 0) { + BMI_ERR("Failed to get fw image"); + return CDF_STATUS_E_FAILURE; + } + + status = bmi_load_image(image_desc_info.bdata_addr, + image_desc_info.bdata_size, + scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Load board data failed! status:%d", status); + return status; + } + + status = bmi_load_image(image_desc_info.fw_addr, + image_desc_info.fw_size, + scn); + if (status != CDF_STATUS_SUCCESS) + BMI_ERR("Load fw image failed! status:%d", status); + + return status; +} + +CDF_STATUS bmi_firmware_download(struct ol_softc *scn) +{ + CDF_STATUS status; + + if (IHELIUM_NO_BMI) + return CDF_STATUS_SUCCESS; + + status = bmi_init(scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI_INIT Failed status:%d", status); + goto end; + } + + status = bmi_enable(scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI_ENABLE failed status:%d\n", status); + goto err_bmi_enable; + } + + return status; +err_bmi_enable: + bmi_cleanup(scn); +end: + return status; +} diff --git a/core/bmi/src/i_ar6320v2_regtable.h b/core/bmi/src/i_ar6320v2_regtable.h new file mode 100644 index 0000000000..9022e1291d --- /dev/null +++ b/core/bmi/src/i_ar6320v2_regtable.h @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320V2_DBG_REGTABLE_H_ +#define _AR6320V2_DBG_REGTABLE_H_ + +#include "regtable.h" + +#define AR6320_REV2_1_REG_SIZE 0x0007F820 +#define AR6320_REV3_REG_SIZE 0x0007F820 + +#ifdef HIF_PCI +/* + * Redefine the register list. To minimize the size of the array, the list must + * obey the below format. {start0, end0}, {start1, end1}, {start2, end2}....... + * The value below must obey to "start0 < end0 < start1 < end1 < start2 < ...", + * otherwise we may encouter error in the dump processing. + */ + +static const tgt_reg_section ar6320v2_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A064}, + + /* DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + +static const tgt_reg_section ar6320v3_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + + /* + * DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; +#endif +#endif /* #ifndef _AR6320V2_DBG_REGTABLE_H_ */ diff --git a/core/bmi/src/i_bmi.h b/core/bmi/src/i_bmi.h new file mode 100644 index 0000000000..9df099d026 --- /dev/null +++ b/core/bmi/src/i_bmi.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +/* =================================================================== + * Internal BMI Header File + */ + +#ifndef _I_BMI_H_ +#define _I_BMI_H_ + +#ifdef CONFIG_CNSS +#include +#endif + +#include "hif.h" +#include "bmi_msg.h" +#include "bmi.h" +#include "ol_fw.h" + +#define QCA_FIRMWARE_FILE "athwlan.bin" +#define QCA_UTF_FIRMWARE_FILE "utf.bin" +#define QCA_BOARD_DATA_FILE "fakeboar.bin" +#define QCA_OTP_FILE "otp.bin" +#define QCA_SETUP_FILE "athsetup.bin" +#define QCA_FIRMWARE_EPPING_FILE "epping.bin" +/* + * Note that not all the register locations are accessible. + * A list of accessible target registers are specified with + * their start and end addresses in a table for given target + * version. We should NOT access other locations as either + * they are invalid locations or host does not have read + * access to it or the value of the particular register + * read might change + */ +#define REGISTER_LOCATION 0x00000800 + +#define DRAM_LOCATION 0x00400000 +#define DRAM_SIZE 0x000a8000 +/* The local base addr is used to read the target dump using pcie I/O reads */ +#define DRAM_LOCAL_BASE_ADDR (0x100000) + +#define IRAM_LOCATION 0x00980000 +#define IRAM_SIZE 0x00038000 + +#define AXI_LOCATION 0x000a0000 +#define AXI_SIZE 0x00018000 + +#define CE_OFFSET 0x00000400 +#define CE_USEFUL_SIZE 0x00000058 + +#define TOTAL_DUMP_SIZE 0x00200000 +#define PCIE_READ_LIMIT 0x00005000 + +#define SHA256_DIGEST_SIZE 32 + +/* BMI LOGGING WRAPPERS */ + +#define BMI_LOG(level, args...) CDF_TRACE(CDF_MODULE_ID_BMI, \ + level, ##args) +#define BMI_ERR(args ...) BMI_LOG(CDF_TRACE_LEVEL_ERROR, args) +#define BMI_DBG(args ...) BMI_LOG(CDF_TRACE_LEVEL_DEBUG, args) +#define BMI_WARN(args ...) BMI_LOG(CDF_TRACE_LEVEL_WARN, args) +#define BMI_INFO(args ...) BMI_LOG(CDF_TRACE_LEVEL_INFO, args) +/* End of BMI Logging Wrappers */ + +/* BMI Assert Wrappers */ +#define bmi_assert CDF_BUG +/* + * Although we had envisioned BMI to run on top of HTC, this is not how the + * final implementation ended up. On the Target side, BMI is a part of the BSP + * and does not use the HTC protocol nor even DMA -- it is intentionally kept + * very simple. + */ + +#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ + sizeof(uint32_t) /* cmd */ + \ + sizeof(uint32_t) /* addr */ + \ + sizeof(uint32_t)) /* length */ +#define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ) +#define BMI_EXCHANGE_TIMEOUT_MS 1000 + +struct hash_fw { + u8 qwlan[SHA256_DIGEST_SIZE]; + u8 otp[SHA256_DIGEST_SIZE]; + u8 bdwlan[SHA256_DIGEST_SIZE]; + u8 utf[SHA256_DIGEST_SIZE]; +}; + +typedef enum _ATH_BIN_FILE { + ATH_OTP_FILE, + ATH_FIRMWARE_FILE, + ATH_PATCH_FILE, + ATH_BOARD_DATA_FILE, + ATH_FLASH_FILE, + ATH_SETUP_FILE, +} ATH_BIN_FILE; + +#if defined(QCA_WIFI_3_0_IHELIUM) || defined(QCA_WIFI_3_0_ADRASTEA) +#define IHELIUM_NO_BMI 1 +#else +#define IHELIUM_NO_BMI 0 +#endif + +CDF_STATUS bmi_execute(uint32_t address, uint32_t *param, + struct ol_softc *scn); +CDF_STATUS bmi_init(struct ol_softc *scn); +CDF_STATUS bmi_no_command(struct ol_softc *scn); +CDF_STATUS bmi_read_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn); +CDF_STATUS bmi_write_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn); +CDF_STATUS bmi_fast_download(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_softc *scn); +CDF_STATUS bmi_read_soc_register(uint32_t address, + uint32_t *param, struct ol_softc *scn); +CDF_STATUS bmi_write_soc_register(uint32_t address, + uint32_t param, struct ol_softc *scn); +CDF_STATUS bmi_get_target_info( + struct bmi_target_info *targ_info, struct ol_softc *scn); + +CDF_STATUS bmi_firmware_download(struct ol_softc *scn); +CDF_STATUS bmi_done_local(struct ol_softc *scn); + +CDF_STATUS ol_download_firmware(struct ol_softc *scn); +CDF_STATUS ol_configure_target(struct ol_softc *scn); +#endif diff --git a/core/bmi/src/ol_fw.c b/core/bmi/src/ol_fw.c new file mode 100644 index 0000000000..94488b9229 --- /dev/null +++ b/core/bmi/src/ol_fw.c @@ -0,0 +1,1637 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "ol_if_athvar.h" +#include "targaddrs.h" +#include "ol_cfg.h" +#include "cds_api.h" +#include "wma_api.h" +#include "wma.h" +#include "bin_sig.h" +#include "i_ar6320v2_regtable.h" +#include "epping_main.h" +#include "ce_reg.h" +#if defined(CONFIG_CNSS) +#include +#endif + +#include "i_bmi.h" +#include "qwlan_version.h" + +#ifdef FEATURE_SECURE_FIRMWARE +static struct hash_fw fw_hash; +#endif + +static uint32_t refclk_speed_to_hz[] = { + 48000000, /* SOC_REFCLK_48_MHZ */ + 19200000, /* SOC_REFCLK_19_2_MHZ */ + 24000000, /* SOC_REFCLK_24_MHZ */ + 26000000, /* SOC_REFCLK_26_MHZ */ + 37400000, /* SOC_REFCLK_37_4_MHZ */ + 38400000, /* SOC_REFCLK_38_4_MHZ */ + 40000000, /* SOC_REFCLK_40_MHZ */ + 52000000, /* SOC_REFCLK_52_MHZ */ +}; + +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len); +#ifdef FEATURE_SECURE_FIRMWARE +static int ol_check_fw_hash(const u8 *data, u32 fw_size, ATH_BIN_FILE file) +{ + u8 *hash = NULL; +#ifdef CONFIG_CNSS + u8 *fw_mem = NULL; + u8 digest[SHA256_DIGEST_SIZE]; +#endif + u8 temp[SHA256_DIGEST_SIZE] = { }; + int ret = 0; + + switch (file) { + case ATH_BOARD_DATA_FILE: + hash = fw_hash.bdwlan; + break; + case ATH_OTP_FILE: + hash = fw_hash.otp; + break; + case ATH_FIRMWARE_FILE: +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == CDF_FTM_MODE) { + hash = fw_hash.utf; + break; + } +#endif + hash = fw_hash.qwlan; + default: + break; + } + + if (!hash) { + BMI_INFO("No entry for file:%d Download FW in non-secure mode", + file); + goto end; + } + + if (!cdf_mem_compare(hash, temp, SHA256_DIGEST_SIZE)) { + BMI_INFO("Download FW in non-secure mode:%d", file); + goto end; + } + +#ifdef CONFIG_CNSS + fw_mem = (u8 *)cnss_get_fw_ptr(); + if (!fw_mem || (fw_size > MAX_FIRMWARE_SIZE)) { + BMI_ERR("No Memory to copy FW data"); + ret = -1; + goto end; + } + cdf_mem_copy(fw_mem, data, fw_size); + + ret = cnss_get_sha_hash(fw_mem, fw_size, "sha256", digest); + + if (ret) { + BMI_ERR("Sha256 Hash computation failed err:%d", ret); + goto end; + } + + if (cdf_mem_compare(hash, digest, SHA256_DIGEST_SIZE) != 0) { + BMI_ERR("Hash Mismatch"); + cdf_trace_hex_dump(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + digest, SHA256_DIGEST_SIZE); + cdf_trace_hex_dump(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + hash, SHA256_DIGEST_SIZE); + ret = CDF_STATUS_E_FAILURE; + } +#endif +end: + return ret; +} +#endif + +static int __ol_transfer_bin_file(struct ol_softc *scn, ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ + int status = EOK; + const char *filename = NULL; + const struct firmware *fw_entry; + uint32_t fw_entry_size; + uint8_t *temp_eeprom; + uint32_t board_data_size; +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bool bin_sign = false; + int bin_off, bin_len; + SIGN_HEADER_T *sign_header; +#endif + + switch (file) { + default: + BMI_ERR("%s: Unknown file type", __func__); + return -1; + case ATH_OTP_FILE: +#if defined(CONFIG_CNSS) + filename = scn->fw_files.otp_data; +#else + filename = QCA_OTP_FILE; +#endif +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = true; +#endif + break; + case ATH_FIRMWARE_FILE: + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { +#if defined(CONFIG_CNSS) + filename = scn->fw_files.epping_file; +#else + filename = QCA_FIRMWARE_EPPING_FILE; +#endif + BMI_INFO("%s: Loading epping firmware file %s", + __func__, filename); + break; + } +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == CDF_FTM_MODE) { +#if defined(CONFIG_CNSS) + filename = scn->fw_files.utf_file; +#else + filename = QCA_UTF_FIRMWARE_FILE; +#endif +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = true; +#endif + BMI_INFO("%s: Loading firmware file %s", + __func__, filename); + break; + } +#endif +#if defined(CONFIG_CNSS) + filename = scn->fw_files.image_file; +#else + filename = QCA_FIRMWARE_FILE; +#endif +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = true; +#endif + break; + case ATH_PATCH_FILE: + BMI_INFO("%s: no Patch file defined", __func__); + return 0; + case ATH_BOARD_DATA_FILE: +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == CDF_FTM_MODE) { +#if defined(CONFIG_CNSS) + filename = scn->fw_files.utf_board_data; +#else + filename = QCA_BOARD_DATA_FILE; +#endif +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = true; +#endif + BMI_INFO("%s: Loading board data file %s", + __func__, filename); + break; + } +#endif /* QCA_WIFI_FTM */ +#if defined(CONFIG_CNSS) + filename = scn->fw_files.board_data; +#else + filename = QCA_BOARD_DATA_FILE; +#endif +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = false; +#endif + break; + case ATH_SETUP_FILE: + if (cds_get_conparam() != CDF_FTM_MODE && + !WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { +#ifdef CONFIG_CNSS + BMI_INFO("%s: no Setup file defined", __func__); + return -1; +#else + filename = QCA_SETUP_FILE; +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + bin_sign = true; +#endif + BMI_INFO("%s: Loading setup file %s", + __func__, filename); +#endif /* CONFIG_CNSS */ + } else { + BMI_INFO("%s: no Setup file needed", __func__); + return -1; + } + break; + } + + if (request_firmware(&fw_entry, filename, scn->aps_osdev.device) != 0) { + BMI_ERR("%s: Failed to get %s", __func__, filename); + + if (file == ATH_OTP_FILE) + return -ENOENT; + +#if defined(QCA_WIFI_FTM) && defined(CONFIG_CNSS) + /* Try default board data file if FTM specific + * board data file is not present. */ + if (filename == scn->fw_files.utf_board_data) { + filename = scn->fw_files.board_data; + BMI_INFO("%s: Trying to load default %s", + __func__, filename); + if (request_firmware(&fw_entry, filename, + scn->aps_osdev.device) != 0) { + BMI_ERR("%s: Failed to get %s", + __func__, filename); + return -1; + } + } else { + return -1; + } +#else + return -1; +#endif + } + + if (!fw_entry || !fw_entry->data) { + BMI_ERR("Invalid fw_entries"); + return CDF_STATUS_E_FAILURE; + } + + fw_entry_size = fw_entry->size; + temp_eeprom = NULL; + +#ifdef FEATURE_SECURE_FIRMWARE + + if (ol_check_fw_hash(fw_entry->data, fw_entry_size, file)) { + BMI_ERR("Hash Check failed for file:%s", filename); + status = CDF_STATUS_E_FAILURE; + goto end; + } +#endif + + if (file == ATH_BOARD_DATA_FILE) { + uint32_t board_ext_address; + int32_t board_ext_data_size; + + temp_eeprom = cdf_mem_malloc(fw_entry_size); + if (!temp_eeprom) { + BMI_ERR("%s: Memory allocation failed", __func__); + release_firmware(fw_entry); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(temp_eeprom, (uint8_t *) fw_entry->data, + fw_entry_size); + + switch (scn->target_type) { + default: + board_data_size = 0; + board_ext_data_size = 0; + break; + case TARGET_TYPE_AR6004: + board_data_size = AR6004_BOARD_DATA_SZ; + board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; + case TARGET_TYPE_AR9888: + board_data_size = AR9888_BOARD_DATA_SZ; + board_ext_data_size = AR9888_BOARD_EXT_DATA_SZ; + break; + } + + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(HOST_INTEREST_ITEM_ADDRESS(scn->target_type, + hi_board_ext_data), + (uint8_t *) &board_ext_address, 4, scn); + BMI_INFO("Board extended Data download address: 0x%x", + board_ext_address); + + /* Check whether the target has allocated memory for extended + * board data and file contains extended board data + */ + + if ((board_ext_address) + && (fw_entry_size == + (board_data_size + board_ext_data_size))) { + uint32_t param; + + status = bmi_write_memory(board_ext_address, + (uint8_t *)(temp_eeprom + + board_data_size), + board_ext_data_size, scn); + + if (status != EOK) + goto end; + + /* Record extended board Data initialized */ + param = (board_ext_data_size << 16) | 1; + bmi_write_memory( + HOST_INTEREST_ITEM_ADDRESS(scn->target_type, + hi_board_ext_data_config), + (uint8_t *)¶m, 4, scn); + + fw_entry_size = board_data_size; + } + } +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT + if (bin_sign) { + uint32_t chip_id; + + if (fw_entry_size < sizeof(SIGN_HEADER_T)) { + BMI_ERR("Invalid binary size %d", fw_entry_size); + status = CDF_STATUS_E_FAILURE; + goto end; + } + + sign_header = (SIGN_HEADER_T *) fw_entry->data; + chip_id = cpu_to_le32(sign_header->product_id); + if (sign_header->magic_num == SIGN_HEADER_MAGIC + && (chip_id == AR6320_REV1_1_VERSION + || chip_id == AR6320_REV1_3_VERSION + || chip_id == AR6320_REV2_1_VERSION)) { + + status = bmi_sign_stream_start(address, + (uint8_t *)fw_entry->data, + sizeof(SIGN_HEADER_T), scn); + if (status != EOK) { + BMI_ERR("unable to start sign stream"); + status = CDF_STATUS_E_FAILURE; + goto end; + } + + bin_off = sizeof(SIGN_HEADER_T); + bin_len = sign_header->rampatch_len + - sizeof(SIGN_HEADER_T); + } else { + bin_sign = false; + bin_off = 0; + bin_len = fw_entry_size; + } + } else { + bin_len = fw_entry_size; + bin_off = 0; + } + + if (compressed) { + status = bmi_fast_download(address, + (uint8_t *) fw_entry->data + bin_off, + bin_len, scn); + } else { + if (file == ATH_BOARD_DATA_FILE && fw_entry->data) { + status = bmi_write_memory(address, + (uint8_t *) temp_eeprom, + fw_entry_size, scn); + } else { + status = bmi_write_memory(address, + (uint8_t *) fw_entry->data + + bin_off, bin_len, scn); + } + } + + if (bin_sign) { + bin_off += bin_len; + bin_len = sign_header->total_len - sign_header->rampatch_len; + + if (bin_len > 0) { + status = bmi_sign_stream_start(0, + (uint8_t *)fw_entry->data + + bin_off, bin_len, scn); + if (status != EOK) + BMI_ERR("sign stream error"); + } + } +#else + if (compressed) { + status = bmi_fast_download(address, + (uint8_t *) fw_entry->data, + fw_entry_size, scn); + } else { + if (file == ATH_BOARD_DATA_FILE && fw_entry->data) { + status = bmi_write_memory(address, + (uint8_t *) temp_eeprom, + fw_entry_size, scn); + } else { + status = bmi_write_memory(address, + (uint8_t *) fw_entry->data, + fw_entry_size, scn); + } + } +#endif /* QCA_SIGNED_SPLIT_BINARY_SUPPORT */ + +end: + if (temp_eeprom) + cdf_mem_free(temp_eeprom); + + if (status != EOK) { + BMI_ERR("%s, BMI operation failed: %d", __func__, __LINE__); + release_firmware(fw_entry); + return CDF_STATUS_E_FAILURE; + } + + release_firmware(fw_entry); + + BMI_INFO("transferring file: %s size %d bytes done!", + (filename != NULL) ? filename : " ", fw_entry_size); + + return status; +} + +static int ol_transfer_bin_file(struct ol_softc *scn, ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ + int ret; + +#ifdef CONFIG_CNSS + /* Wait until suspend and resume are completed before loading FW */ + cnss_lock_pm_sem(); +#endif + + ret = __ol_transfer_bin_file(scn, file, address, compressed); + +#ifdef CONFIG_CNSS + cnss_release_pm_sem(); +#endif + + return ret; +} + +int dump_ce_register(struct ol_softc *scn) +{ + uint32_t ce_reg_address = CE0_BASE_ADDRESS; + uint32_t ce_reg_values[8][CE_USEFUL_SIZE >> 2]; + uint32_t ce_reg_word_size = CE_USEFUL_SIZE >> 2; + uint16_t i, j; + + for (i = 0; i < 8; i++, ce_reg_address += CE_OFFSET) { + if (hif_diag_read_mem(scn, ce_reg_address, + (uint8_t *) &ce_reg_values[i][0], ce_reg_word_size * + sizeof(uint32_t)) != CDF_STATUS_SUCCESS) { + BMI_ERR("Dumping CE register failed!"); + return -EACCES; + } + } + + for (i = 0; i < 8; i++) { + BMI_ERR("CE%d Registers:", i); + for (j = 0; j < ce_reg_word_size; j++) { + BMI_ERR("0x%08x ", ce_reg_values[i][j]); + if (!((j + 1) % 5) || (ce_reg_word_size - 1) == j) + BMI_ERR(" "); + } + } + + return 0; +} + +#if defined(CONFIG_CNSS) + +static struct ol_softc *ramdump_scn; + +int ol_copy_ramdump(struct ol_softc *scn) +{ + int ret; + + if (!scn->ramdump_base || !scn->ramdump_size) { + BMI_ERR("%s:ramdump collection fail", __func__); + ret = -EACCES; + goto out; + } + + ret = ol_target_coredump(scn, scn->ramdump_base, scn->ramdump_size); + +out: + return ret; +} + +static void ramdump_work_handler(struct work_struct *ramdump) +{ + int ret; + uint32_t host_interest_address; + uint32_t dram_dump_values[4]; + + if (!ramdump_scn) { + BMI_ERR("%s:Ramdump_scn is null:", __func__); + goto out_fail; + } +#ifdef DEBUG + ret = hif_check_soc_status(ramdump_scn); + if (ret) + goto out_fail; + + ret = dump_ce_register(ramdump_scn); + if (ret) + goto out_fail; + + dump_ce_debug_register(ramdump_scn); +#endif + + if (hif_diag_read_mem(ramdump_scn, + hif_hia_item_address(ramdump_scn->target_type, + offsetof(struct host_interest_s, hi_failure_state)), + (uint8_t *)&host_interest_address, + sizeof(uint32_t)) != CDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area Pointer failed!"); + ol_copy_ramdump(ramdump_scn); + cnss_device_crashed(); + return; + } + + BMI_ERR("Host interest item address: 0x%08x", host_interest_address); + + if (hif_diag_read_mem(ramdump_scn, host_interest_address, + (uint8_t *) &dram_dump_values[0], + 4 * sizeof(uint32_t)) != CDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area failed!"); + goto out_fail; + } + BMI_ERR("FW Assertion at PC: 0x%08x BadVA: 0x%08x TargetID: 0x%08x", + dram_dump_values[2], dram_dump_values[3], dram_dump_values[0]); + + if (ol_copy_ramdump(ramdump_scn)) + goto out_fail; + + BMI_ERR("%s: RAM dump collecting completed!", __func__); + /* notify SSR framework the target has crashed. */ + cnss_device_crashed(); + return; + +out_fail: + /* Silent SSR on dump failure */ +#ifdef CNSS_SELF_RECOVERY + cnss_device_self_recovery(); +#else + cnss_device_crashed(); +#endif + return; +} + +static DECLARE_WORK(ramdump_work, ramdump_work_handler); + +void ol_schedule_ramdump_work(struct ol_softc *scn) +{ + ramdump_scn = scn; + schedule_work(&ramdump_work); +} + +static void fw_indication_work_handler(struct work_struct *fw_indication) +{ + cnss_device_self_recovery(); +} + +static DECLARE_WORK(fw_indication_work, fw_indication_work_handler); + +void ol_schedule_fw_indication_work(struct ol_softc *scn) +{ + schedule_work(&fw_indication_work); +} +#endif + +void ol_target_failure(void *instance, CDF_STATUS status) +{ + struct ol_softc *scn = (struct ol_softc *)instance; + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + int ret; + + cdf_event_set(&wma->recovery_event); + + if (OL_TRGET_STATUS_RESET == scn->target_status) { + BMI_ERR("Target is already asserted, ignore!"); + return; + } + scn->target_status = OL_TRGET_STATUS_RESET; + + if (cds_is_logp_in_progress()) { + BMI_ERR("%s: LOGP is in progress, ignore!\n", __func__); + return; + } + + if (cds_is_load_unload_in_progress()) { + BMI_ERR("%s: Loading/Unloading is in progress, ignore!", + __func__); + return; + } + cds_set_logp_in_progress(true); + +#ifdef CONFIG_CNSS + ret = hif_check_fw_reg(scn); + if (0 == ret) { + if (scn->enable_self_recovery) { + ol_schedule_fw_indication_work(scn); + return; + } + } else if (-1 == ret) { + return; + } +#endif + + BMI_ERR("XXX TARGET ASSERTED XXX"); + +#if defined(CONFIG_CNSS) + /* Collect the RAM dump through a workqueue */ + if (scn->enable_ramdump_collection) + ol_schedule_ramdump_work(scn); + else + pr_debug("%s: athdiag read for target reg\n", __func__); +#endif + + return; +} + +CDF_STATUS ol_configure_target(struct ol_softc *scn) +{ + uint32_t param; +#ifdef CONFIG_CNSS + struct cnss_platform_cap cap; + int ret; +#endif + + /* Tell target which HTC version it is used */ + param = HTC_PROTOCOL_VERSION; + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_app_host_interest)), + (uint8_t *) ¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("bmi_write_memory for htc version failed"); + return CDF_STATUS_E_FAILURE; + } + + /* set the firmware mode to STA/IBSS/AP */ + { + if (bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("bmi_read_memory for setting fwmode failed"); + return CDF_STATUS_E_FAILURE; + } + + /* TODO following parameters need to be re-visited. */ + param |= (1 << HI_OPTION_NUM_DEV_SHIFT); /* num_device */ + /* Firmware mode ?? */ + param |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT); + /* mac_addr_method */ + param |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); + /* firmware_bridge */ + param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); + /* fwsubmode */ + param |= (0 << HI_OPTION_FW_SUBMODE_SHIFT); + + BMI_INFO("NUM_DEV=%d FWMODE=0x%x FWSUBMODE=0x%x FWBR_BUF %d", + 1, HI_OPTION_FW_MODE_AP, 0, 0); + + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE for setting fwmode failed"); + return CDF_STATUS_E_FAILURE; + } + } + +#if (CONFIG_DISABLE_CDC_MAX_PERF_WAR) + { + /* set the firmware to disable CDC max perf WAR */ + if (bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ for setting cdc max perf failed"); + return CDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DISABLE_CDC_MAX_PERF_WAR; + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("setting cdc max perf failed"); + return CDF_STATUS_E_FAILURE; + } + } +#endif /* CONFIG_CDC_MAX_PERF_WAR */ + +#ifdef CONFIG_CNSS + + ret = cnss_get_platform_cap(&cap); + if (ret) + BMI_ERR("platform capability info from CNSS not available"); + + if (!ret && cap.cap_flag & CNSS_HAS_EXTERNAL_SWREG) { + if (bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("bmi_read_memory for setting" + "external SWREG failed"); + return CDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_USE_EXT_LDO; + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE for setting external SWREG fail"); + return CDF_STATUS_E_FAILURE; + } + } +#endif + +#ifdef WLAN_FEATURE_LPSS + if (scn->enablelpasssupport) { + if (bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ:Setting LPASS Support failed"); + return CDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DBUART_SUPPORT; + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI_READ for setting LPASS Support fail"); + return CDF_STATUS_E_FAILURE; + } + } +#endif + + /* If host is running on a BE CPU, set the host interest area */ + { +#ifdef BIG_ENDIAN_HOST + param = 1; +#else + param = 0; +#endif + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_be)), + (uint8_t *) ¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("setting host CPU BE mode failed"); + return CDF_STATUS_E_FAILURE; + } + } + + /* FW descriptor/Data swap flags */ + param = 0; + if (bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_fw_swap)), + (uint8_t *) ¶m, 4, scn) != CDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE failed setting FW data/desc swap flags"); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +static int ol_check_dataset_patch(struct ol_softc *scn, uint32_t *address) +{ + /* Check if patch file needed for this target type/version. */ + return 0; +} + + +CDF_STATUS ol_fw_populate_clk_settings(A_refclk_speed_t refclk, + struct cmnos_clock_s *clock_s) +{ + if (!clock_s) + return CDF_STATUS_E_FAILURE; + + switch (refclk) { + case SOC_REFCLK_48_MHZ: + clock_s->wlan_pll.div = 0xE; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 2400; + break; + case SOC_REFCLK_19_2_MHZ: + clock_s->wlan_pll.div = 0x24; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 960; + break; + case SOC_REFCLK_24_MHZ: + clock_s->wlan_pll.div = 0x1D; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1200; + break; + case SOC_REFCLK_26_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 1300; + break; + case SOC_REFCLK_37_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x34B49; + clock_s->pll_settling_time = 1870; + break; + case SOC_REFCLK_38_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1920; + break; + case SOC_REFCLK_40_MHZ: + clock_s->wlan_pll.div = 0x11; + clock_s->wlan_pll.rnfrac = 0x26665; + clock_s->pll_settling_time = 2000; + break; + case SOC_REFCLK_52_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 2600; + break; + case SOC_REFCLK_UNKNOWN: + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.div = 0; + clock_s->wlan_pll.rnfrac = 0; + clock_s->wlan_pll.outdiv = 0; + clock_s->pll_settling_time = 1024; + clock_s->refclk_hz = 0; + default: + return CDF_STATUS_E_FAILURE; + } + + clock_s->refclk_hz = refclk_speed_to_hz[refclk]; + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.outdiv = 1; + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS ol_patch_pll_switch(struct ol_softc *scn) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t addr = 0; + uint32_t reg_val = 0; + uint32_t mem_val = 0; + struct cmnos_clock_s clock_s; + uint32_t cmnos_core_clk_div_addr = 0; + uint32_t cmnos_cpu_pll_init_done_addr = 0; + uint32_t cmnos_cpu_speed_addr = 0; + + switch (scn->target_version) { + case AR6320_REV1_1_VERSION: + cmnos_core_clk_div_addr = AR6320_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320_CPU_SPEED_ADDR; + break; + case AR6320_REV1_3_VERSION: + case AR6320_REV2_1_VERSION: + cmnos_core_clk_div_addr = AR6320V2_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V2_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V2_CPU_SPEED_ADDR; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + cmnos_core_clk_div_addr = AR6320V3_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V3_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V3_CPU_SPEED_ADDR; + break; + default: + BMI_ERR("%s: Unsupported target version %x", __func__, + scn->target_version); + goto end; + } + + addr = (RTC_SOC_BASE_ADDRESS | EFUSE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read EFUSE Addr"); + goto end; + } + + status = ol_fw_populate_clk_settings(EFUSE_XTAL_SEL_GET(reg_val), + &clock_s); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to set clock settings"); + goto end; + } + BMI_DBG("crystal_freq: %dHz", clock_s.refclk_hz); + + /* ------Step 1---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | BB_PLL_CONFIG_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1a: %8X", reg_val); + + reg_val &= ~(BB_PLL_CONFIG_FRAC_MASK | BB_PLL_CONFIG_OUTDIV_MASK); + reg_val |= (BB_PLL_CONFIG_FRAC_SET(clock_s.wlan_pll.rnfrac) | + BB_PLL_CONFIG_OUTDIV_SET(clock_s.wlan_pll.outdiv)); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CONFIG Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1b: %8X", reg_val); + + /* ------Step 2---- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_SETTLE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_SETTLE_TIME_MASK; + reg_val |= WLAN_PLL_SETTLE_TIME_SET(clock_s.pll_settling_time); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_SETTLE Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2b: %8X", reg_val); + + /* ------Step 3---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CORE_CLK_CTRL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3a: %8X", reg_val); + + reg_val &= ~SOC_CORE_CLK_CTRL_DIV_MASK; + reg_val |= SOC_CORE_CLK_CTRL_DIV_SET(1); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3b: %8X", reg_val); + + /* ------Step 4----- */ + mem_val = 1; + status = bmi_write_memory(cmnos_core_clk_div_addr, + (uint8_t *) &mem_val, 4, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_DIV Addr"); + goto end; + } + + /* ------Step 5----- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr"); + goto end; + } + BMI_DBG("Step 5a: %8X", reg_val); + + reg_val &= ~(WLAN_PLL_CONTROL_REFDIV_MASK | WLAN_PLL_CONTROL_DIV_MASK | + WLAN_PLL_CONTROL_NOPWD_MASK); + reg_val |= (WLAN_PLL_CONTROL_REFDIV_SET(clock_s.wlan_pll.refdiv) | + WLAN_PLL_CONTROL_DIV_SET(clock_s.wlan_pll.div) | + WLAN_PLL_CONTROL_NOPWD_SET(1)); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr"); + goto end; + } + OS_DELAY(100); + BMI_DBG("Step 5b: %8X", reg_val); + + /* ------Step 6------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read RTC_SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 7------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_BYPASS_MASK; + reg_val |= WLAN_PLL_CONTROL_BYPASS_SET(0); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7b: %8X", reg_val); + + /* ------Step 8-------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 9-------- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CPU_CLOCK_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9a: %8X", reg_val); + + reg_val &= ~SOC_CPU_CLOCK_STANDARD_MASK; + reg_val |= SOC_CPU_CLOCK_STANDARD_SET(1); + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_CLK Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9b: %8X", reg_val); + + /* ------Step 10------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_NOPWD_MASK; + status = bmi_write_soc_register(addr, reg_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for NOPWD"); + goto end; + } + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10b: %8X", reg_val); + + /* ------Step 11------- */ + mem_val = 1; + status = bmi_write_memory(cmnos_cpu_pll_init_done_addr, + (uint8_t *) &mem_val, 4, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_INIT Addr"); + goto end; + } + + mem_val = TARGET_CPU_FREQ; + status = bmi_write_memory(cmnos_cpu_speed_addr, + (uint8_t *) &mem_val, 4, scn); + if (status != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_SPEED Addr"); + goto end; + } + +end: + return status; +} + +#ifdef CONFIG_CNSS +/* AXI Start Address */ +#define TARGET_ADDR (0xa0000) + +void ol_transfer_codeswap_struct(struct ol_softc *scn) +{ + struct codeswap_codeseg_info wlan_codeswap; + CDF_STATUS rv; + + if (!scn) { + BMI_ERR("%s: ol_softc is null", __func__); + return; + } + if (cnss_get_codeswap_struct(&wlan_codeswap)) { + BMI_ERR("%s: failed to get codeswap structure", __func__); + return; + } + + rv = bmi_write_memory(TARGET_ADDR, + (uint8_t *) &wlan_codeswap, sizeof(wlan_codeswap), + scn); + + if (rv != CDF_STATUS_SUCCESS) { + BMI_ERR("Failed to Write 0xa0000 to Target"); + return; + } + BMI_INFO("codeswap structure is successfully downloaded"); +} +#endif + +CDF_STATUS ol_download_firmware(struct ol_softc *scn) +{ + uint32_t param, address = 0; + int status = !EOK; + CDF_STATUS ret; + +#ifdef CONFIG_CNSS + if (0 != cnss_get_fw_files_for_target(&scn->fw_files, + scn->target_type, + scn->target_version)) { + BMI_ERR("%s: No FW files from CNSS driver", __func__); + return CDF_STATUS_E_FAILURE; + } +#endif + /* Transfer Board Data from Target EEPROM to Target RAM */ + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_board_data)), + (uint8_t *)&address, 4, scn); + + if (!address) { + address = AR6004_REV5_BOARD_DATA_ADDRESS; + BMI_DBG("%s: Target address not known! Using 0x%x", + __func__, address); + } + ret = ol_patch_pll_switch(scn); + if (ret != CDF_STATUS_SUCCESS) { + BMI_ERR("pll switch failed. status %d", ret); + return ret; + } + if (scn->cal_in_flash) { + /* Write EEPROM or Flash data to Target RAM */ + status = ol_transfer_bin_file(scn, ATH_FLASH_FILE, + address, false); + } + + if (status == EOK) { + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, scn); + } else { + /* Flash is either not available or invalid */ + if (ol_transfer_bin_file + (scn, ATH_BOARD_DATA_FILE, address, false) != EOK) { + return -1; + } + + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory( + hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, scn); + + /* Transfer One Time Programmable data */ + address = BMI_SEGMENTED_WRITE_ADDR; + BMI_INFO("%s: Using 0x%x for the remainder of init", + __func__, address); + +#ifdef CONFIG_CNSS + ol_transfer_codeswap_struct(scn); +#endif + status = ol_transfer_bin_file(scn, ATH_OTP_FILE, + address, true); + /* Execute the OTP code only if entry found and downloaded */ + if (status == EOK) { + param = 0; +#ifndef FEATURE_BMI_2 + bmi_execute(address, ¶m, scn); +#endif + } else if (status < 0) { + return status; + } + } + + if (ol_transfer_bin_file(scn, ATH_SETUP_FILE, + BMI_SEGMENTED_WRITE_ADDR, true) == EOK) { + param = 0; +#ifndef FEATURE_BMI_2 + bmi_execute(address, ¶m, scn); +#endif + } + + /* Download Target firmware + * TODO point to target specific files in runtime + */ + address = BMI_SEGMENTED_WRITE_ADDR; + if (ol_transfer_bin_file(scn, ATH_FIRMWARE_FILE, + address, true) != EOK) { + return -1; + } + + /* Apply the patches */ + if (ol_check_dataset_patch(scn, &address)) { + if ((ol_transfer_bin_file(scn, ATH_PATCH_FILE, address, false)) + != EOK) { + return -1; + } + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_dset_list_head)), + (uint8_t *) &address, 4, scn); + } + + if (scn->enableuartprint || + (WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && + WLAN_IS_EPPING_FW_UART(cds_get_conparam()))) { + switch (scn->target_version) { + case AR6004_VERSION_REV1_3: + param = 11; + break; + case AR6320_REV1_VERSION: + case AR6320_REV2_VERSION: + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case AR6320_REV4_VERSION: + case AR6320_DEV_VERSION: + param = 6; + break; + default: + /* Configure GPIO AR9888 UART */ + param = 7; + } + + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_dbg_uart_txpin)), + (uint8_t *)¶m, 4, scn); + param = 1; + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, scn); + } else { + /* + * Explicitly setting UART prints to zero as target turns it on + * based on scratch registers. + */ + param = 0; + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, scn); + } + + if (scn->enablefwlog) { + bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, scn); + + param &= ~(HI_OPTION_DISABLE_DBGLOG); + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, scn); + } else { + /* + * Explicitly setting fwlog prints to zero as target turns it on + * based on scratch registers. + */ + bmi_read_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, scn); + + param |= HI_OPTION_DISABLE_DBGLOG; + bmi_write_memory(hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *) ¶m, 4, scn); + } + + return status; +} + +int ol_diag_read(struct ol_softc *scn, uint8_t *buffer, + uint32_t pos, size_t count) +{ + int result = 0; + + if ((4 == count) && ((pos & 3) == 0)) { + result = hif_diag_read_access(scn, pos, + (uint32_t *) buffer); + } else { + size_t amount_read = 0; + size_t readSize = PCIE_READ_LIMIT; + size_t remainder = 0; + if (count > PCIE_READ_LIMIT) { + while ((amount_read < count) && (0 == result)) { + result = hif_diag_read_mem(scn, pos, + buffer, readSize); + if (0 == result) { + buffer += readSize; + pos += readSize; + amount_read += readSize; + remainder = count - amount_read; + if (remainder < PCIE_READ_LIMIT) + readSize = remainder; + } + } + } else { + result = hif_diag_read_mem(scn, pos, + buffer, count); + } + } + + if (!result) + return count; + else + return -EIO; +} + +static int ol_ath_get_reg_table(uint32_t target_version, + tgt_reg_table *reg_table) +{ + int section_len = 0; + + if (!reg_table) { + cdf_assert(0); + return section_len; + } + + switch (target_version) { + case AR6320_REV2_1_VERSION: + reg_table->section = + (tgt_reg_section *) &ar6320v2_reg_table[0]; + reg_table->section_size = sizeof(ar6320v2_reg_table) + / sizeof(ar6320v2_reg_table[0]); + section_len = AR6320_REV2_1_REG_SIZE; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + reg_table->section = + (tgt_reg_section *) &ar6320v3_reg_table[0]; + reg_table->section_size = sizeof(ar6320v3_reg_table) + / sizeof(ar6320v3_reg_table[0]); + section_len = AR6320_REV3_REG_SIZE; + break; + default: + reg_table->section = (void *)NULL; + reg_table->section_size = 0; + section_len = 0; + } + + return section_len; +} + +static int ol_diag_read_reg_loc(struct ol_softc *scn, uint8_t *buffer, + uint32_t buffer_len) +{ + int i, len, section_len, fill_len; + int dump_len, result = 0; + tgt_reg_table reg_table; + tgt_reg_section *curr_sec, *next_sec; + + section_len = ol_ath_get_reg_table(scn->target_version, ®_table); + + if (!reg_table.section || !reg_table.section_size || !section_len) { + BMI_ERR("%s: failed to get reg table", __func__); + result = -EIO; + goto out; + } + + curr_sec = reg_table.section; + for (i = 0; i < reg_table.section_size; i++) { + + dump_len = curr_sec->end_addr - curr_sec->start_addr; + + if ((buffer_len - result) < dump_len) { + BMI_ERR("Not enough memory to dump the registers:" + " %d: 0x%08x-0x%08x", i, + curr_sec->start_addr, curr_sec->end_addr); + goto out; + } + + len = ol_diag_read(scn, buffer, curr_sec->start_addr, dump_len); + + if (len != -EIO) { + buffer += len; + result += len; + } else { + BMI_ERR("%s: can't read reg 0x%08x len = %d", + __func__, curr_sec->start_addr, dump_len); + result = -EIO; + goto out; + } + + if (result < section_len) { + next_sec = (tgt_reg_section *) ((uint8_t *) curr_sec + + sizeof(*curr_sec)); + fill_len = next_sec->start_addr - curr_sec->end_addr; + if ((buffer_len - result) < fill_len) { + BMI_ERR("Not enough memory to fill registers:" + " %d: 0x%08x-0x%08x", i, + curr_sec->end_addr, + next_sec->start_addr); + goto out; + } + + if (fill_len) { + buffer += fill_len; + result += fill_len; + } + } + curr_sec++; + } + +out: + return result; +} + +void ol_dump_target_memory(struct ol_softc *scn, void *memory_block) +{ + char *buffer_loc = memory_block; + u_int32_t section_count = 0; + u_int32_t address = 0; + u_int32_t size = 0; + + for (; section_count < 2; section_count++) { + switch (section_count) { + case 0: + address = DRAM_LOCAL_BASE_ADDR; + size = DRAM_SIZE; + break; + case 1: + address = AXI_LOCATION; + size = AXI_SIZE; + default: + break; + } + hif_dump_target_memory(scn, buffer_loc, address, size); + buffer_loc += size; + } +} + +/**--------------------------------------------------------------------------- +* \brief ol_target_coredump +* +* Function to perform core dump for the target +* +* \param: scn - ol_softc handler +* memory_block - non-NULL reserved memory location +* block_len - size of the dump to collect +* +* \return: None +* --------------------------------------------------------------------------*/ +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len) +{ + struct ol_softc *scn = (struct ol_softc *)inst; + int8_t *buffer_loc = memory_block; + int result = 0; + int ret = 0; + uint32_t amount_read = 0; + uint32_t section_count = 0; + uint32_t pos = 0; + uint32_t read_len = 0; + + /* + * SECTION = DRAM + * START = 0x00400000 + * LENGTH = 0x000a8000 + * + * SECTION = AXI + * START = 0x000a0000 + * LENGTH = 0x00018000 + * + * SECTION = REG + * START = 0x00000800 + * LENGTH = 0x0007F820 + */ + + while ((section_count < 3) && (amount_read < block_len)) { + switch (section_count) { + case 0: + /* DRAM SECTION */ + pos = DRAM_LOCATION; + read_len = DRAM_SIZE; + BMI_ERR("%s: Dumping DRAM section...", __func__); + break; + case 1: + /* AXI SECTION */ + pos = AXI_LOCATION; + read_len = AXI_SIZE; + BMI_ERR("%s: Dumping AXI section...", __func__); + break; + case 2: + /* REG SECTION */ + pos = REGISTER_LOCATION; + /* ol_diag_read_reg_loc checks for buffer overrun */ + read_len = 0; + BMI_ERR("%s: Dumping Register section...", __func__); + break; + } + + if ((block_len - amount_read) >= read_len) { + if (pos == REGISTER_LOCATION) + result = ol_diag_read_reg_loc(scn, buffer_loc, + block_len - + amount_read); + else + result = ol_diag_read(scn, buffer_loc, + pos, read_len); + if (result != -EIO) { + amount_read += result; + buffer_loc += result; + section_count++; + } else { + BMI_ERR("Could not read dump section!"); + dump_ce_register(scn); + dump_ce_debug_register(scn); + ol_dump_target_memory(scn, memory_block); + ret = -EACCES; + break; /* Could not read the section */ + } + } else { + BMI_ERR("Insufficient room in dump buffer!"); + break; /* Insufficient room in buffer */ + } + } + return ret; +} + +#define MAX_SUPPORTED_PEERS_REV1_1 14 +#define MAX_SUPPORTED_PEERS_REV1_3 32 + +uint8_t ol_get_number_of_peers_supported(struct ol_softc *scn) +{ + uint8_t max_no_of_peers = 0; + + switch (scn->target_version) { + case AR6320_REV1_1_VERSION: + if (scn->max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_1) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_1; + else + max_no_of_peers = scn->max_no_of_peers; + break; + + default: + if (scn->max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_3) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_3; + else + max_no_of_peers = scn->max_no_of_peers; + break; + + } + return max_no_of_peers; +} diff --git a/core/cdf/inc/cdf_atomic.h b/core/cdf/inc/cdf_atomic.h new file mode 100644 index 0000000000..230d4eda30 --- /dev/null +++ b/core/cdf/inc/cdf_atomic.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_atomic.h + * This file abstracts an atomic counter. + */ + +#ifndef _CDF_ATOMIC_H +#define _CDF_ATOMIC_H + +#include + +/** + * cdf_atomic_t - atomic type of variable + * + * Use this when you want a simple resource counter etc. which is atomic + * across multiple CPU's. These maybe slower than usual counters on some + * platforms/OS'es, so use them with caution. + */ + +typedef __cdf_atomic_t cdf_atomic_t; + +/** + * cdf_atomic_init() - initialize an atomic type variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void cdf_atomic_init(cdf_atomic_t *v) +{ + __cdf_atomic_init(v); +} + +/** + * cdf_atomic_read() - read the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline uint32_t cdf_atomic_read(cdf_atomic_t *v) +{ + return __cdf_atomic_read(v); +} + +/** + * cdf_atomic_inc() - increment the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void cdf_atomic_inc(cdf_atomic_t *v) +{ + __cdf_atomic_inc(v); +} + +/** + * cdf_atomic_dec() - decrement the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void cdf_atomic_dec(cdf_atomic_t *v) +{ + __cdf_atomic_dec(v); +} + +/** + * cdf_atomic_add() - add a value to the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * @i: The amount by which to increase the atomic counter + * + * Return: None + */ +static inline void cdf_atomic_add(int i, cdf_atomic_t *v) +{ + __cdf_atomic_add(i, v); +} + +/** + * cdf_atomic_dec_and_test() - decrement an atomic variable and check if the + * new value is zero + * @v: A pointer to an opaque atomic variable + * + * Return: + * true (non-zero) if the new value is zero, + * or false (0) if the new value is non-zero + */ +static inline uint32_t cdf_atomic_dec_and_test(cdf_atomic_t *v) +{ + return __cdf_atomic_dec_and_test(v); +} + +/** + * cdf_atomic_set() - set a value to the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void cdf_atomic_set(cdf_atomic_t *v, int i) +{ + __cdf_atomic_set(v, i); +} + +/** + * cdf_atomic_inc_return() - return the incremented value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline uint32_t cdf_atomic_inc_return(cdf_atomic_t *v) +{ + return __cdf_atomic_inc_return(v); +} + +#endif diff --git a/core/cdf/inc/cdf_defer.h b/core/cdf/inc/cdf_defer.h new file mode 100644 index 0000000000..fa527f3b3d --- /dev/null +++ b/core/cdf/inc/cdf_defer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_defer.h + * This file abstracts deferred execution contexts. + */ + +#ifndef __CDF_DEFER_H +#define __CDF_DEFER_H + +#include +#include + +/** + * This implements work queues (worker threads, kernel threads etc.). + * Note that there is no cancel on a scheduled work. You cannot free a work + * item if its queued. You cannot know if a work item is queued or not unless + * its running, whence you know its not queued. + * + * so if, say, a module is asked to unload itself, how exactly will it make + * sure that the work's not queued, for OS'es that dont provide such a + * mechanism?? + */ + +/* cdf_work_t - representation of a work queue */ +typedef __cdf_work_t cdf_work_t; + +/* cdf_work_t - representation of a bottom half */ +typedef __cdf_bh_t cdf_bh_t; + +/** + * cdf_create_bh() - this creates the Bottom half deferred handler + * @hdl: OS handle + * @bh: Bottom instance + * @func: Func deferred function to run at bottom half interrupt + * context + * Return: None + */ +static inline void +cdf_create_bh(cdf_handle_t hdl, cdf_bh_t *bh, cdf_defer_fn_t func, void *arg) +{ + __cdf_init_bh(hdl, bh, func, arg); +} + +/** + * cdf_sched_bh() - schedule a bottom half (DPC) + * @hdl: OS handle + * @bh: Bottom instance + * + * Return: None + */ +static inline void cdf_sched_bh(cdf_handle_t hdl, cdf_bh_t *bh) +{ + __cdf_sched_bh(hdl, bh); +} + +/** + * cdf_destroy_bh() - destroy a bottom half (DPC) + * @hdl: OS handle + * @bh: Bottom instance + * + * Return: None + */ +static inline void cdf_destroy_bh(cdf_handle_t hdl, cdf_bh_t *bh) +{ + __cdf_disable_bh(hdl, bh); +} + +/*********************Non-Interrupt Context deferred Execution***************/ + +/** + * cdf_create_work() - create a work/task queue, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @hdl: OS handle + * @work: Work instance + * @func: Deferred function to run at bottom half non-interrupt + * context + * @arg: Argument for the deferred function + * + * Return: None + */ +static inline void +cdf_create_work(cdf_handle_t hdl, cdf_work_t *work, + cdf_defer_fn_t func, void *arg) +{ + __cdf_init_work(hdl, work, func, arg); +} + +/** + * cdf_sched_work() - schedule a deferred task on non-interrupt context + * @hdl: OS handle + * @work: Work instance + * + * Return: None + */ +static inline void cdf_sched_work(cdf_handle_t hdl, cdf_work_t *work) +{ + __cdf_sched_work(hdl, work); +} + +/** + * cdf_destroy_work() - destroy the deferred task (synchronous) + * @hdl: OS handle + * @work: Work instance + * + * Return: None + */ +static inline void cdf_destroy_work(cdf_handle_t hdl, cdf_work_t *work) +{ + __cdf_disable_work(hdl, work); +} + +#endif /*__CDF_DEFER_H*/ diff --git a/core/cdf/inc/cdf_event.h b/core/cdf/inc/cdf_event.h new file mode 100644 index 0000000000..e185880636 --- /dev/null +++ b/core/cdf/inc/cdf_event.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_EVENT_H) +#define __CDF_EVENT_H + +/** + * DOC: cdf_event.h + * + * Connectivity driver framework (CDF) events API + * + **/ + +/* Include Files */ +#include "cdf_status.h" +#include "cdf_types.h" +#include "i_cdf_event.h" + +/* Preprocessor definitions and constants */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +/** + * cdf_event_init() - initializes the specified event + * + * @event: Pointer to CDF event object to initialize + * + * Initializes the specified event. Upon successful initialization the state + * of the event becomes initialized and not signaled. + * + * Return: + * CDF_STATUS_SUCCESS - Event was successfully initialized and is ready to + * be used + * Otherwise failure CDF reason code + */ + +CDF_STATUS cdf_event_init(cdf_event_t *event); + +/** + * cdf_event_set() - set a CDF event + * + * @event: Pointer of CDF event to set to the signalled state + * + * The state of the specified event is set to 'signalled by calling + * cdf_event_set(). The state of the event remains signalled until an + * explicit call to cdf_event_reset(). + * + * Any threads waiting on the event as a result of a cdf_event_wait() will + * be unblocked and available to be scheduled for execution when the event + * is signaled by a call to cdf_event_set(). + * + * Return: + * CDF_STATUS_SUCCESS - Event was successfully set + * Otherwise failure CDF reason code + */ +CDF_STATUS cdf_event_set(cdf_event_t *event); + +/** + * cdf_event_reset() - reset a CDF event + * + * @event: Pointer of CDF event to reset + * + * The state of the specified event is set to 'NOT signalled' by calling + * cdf_event_reset(). The state of the event remains NOT signalled until an + * explicit call to cdf_event_set(). + * + * This function sets the event to a NOT signalled state even if the event was + * signalled multiple times before being signaled. + * + * Return: + * CDF_STATUS_SUCCESS - Event was successfully reset + * Otherwise failure CDF reason code + */ +CDF_STATUS cdf_event_reset(cdf_event_t *event); + +/** + * cdf_event_destroy() - destroy a CDF event + * + * @event: Pointer of CDF event to destroy + * + * The function destroys the event object referenced by event. + * After a successful return from cdf_event_destroy() the event object becomes, + * in effect, uninitialized. + * + * A destroyed event object can be reinitialized using cdf_event_init(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to CDF event functions to manipulate the lock such + * as cdf_event_set() will fail if the event is destroyed. Therefore, + * don't use the event after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS - Event was successfully destroyed + * Otherwise failure CDF reason code + */ +CDF_STATUS cdf_event_destroy(cdf_event_t *event); + +/** + * cdf_wait_single_event() - wait for a single input CDF event to be set + * + * @event: Pointer of CDF event to wait on + * @timeout: Timeout value in milli seconds + * + * This API waits for the event to be set. This function returns + * if this interval elapses, regardless if any of the events have + * been set. An input value of 0 for this timeout parameter means + * to wait infinitely, meaning a timeout will never occur. + * + * + * Return: + * CDF_STATUS_SUCCESS - the wait was satisifed by the event being + * set. + * + * CDF_STATUS_E_TIMEOUT - the timeout interval elapsed before the + * event was set. + * + * CDF_STATUS_E_INVAL - The value specified by event is invalid. + */ +CDF_STATUS cdf_wait_single_event(cdf_event_t *pEvent, + uint32_t timeout); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __CDF_EVENT_H */ diff --git a/core/cdf/inc/cdf_list.h b/core/cdf/inc/cdf_list.h new file mode 100644 index 0000000000..d4b793e39c --- /dev/null +++ b/core/cdf/inc/cdf_list.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_LIST_H) +#define __CDF_LIST_H + +/** + * DOC: cdf_list.h + * + * Connectivity driver framework (CDF) list APIs + * + * Definitions for CDF Linked Lists API + * + * Lists are implemented as a doubly linked list. An item in a list can + * be of any type as long as the datatype contains a field of type + * cdf_link_t. + * + * In general, a list is a doubly linked list of items with a pointer + * to the front of the list and a pointer to the end of the list. The + * list items contain a forward and back link. + * + * CDF linked list APIs are NOT thread safe so make sure to use appropriate + * locking mechanisms to assure operations on the list are thread safe. + */ + +/* Include Files */ +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +typedef struct list_head cdf_list_node_t; + +typedef struct cdf_list_s { + cdf_list_node_t anchor; + uint32_t count; + uint32_t max_size; +} cdf_list_t; + +/* Function declarations */ + +CDF_INLINE_FN void cdf_list_init(cdf_list_t *p_list, uint32_t max_size) +{ + INIT_LIST_HEAD(&p_list->anchor); + p_list->count = 0; + p_list->max_size = max_size; +} + +CDF_INLINE_FN void cdf_list_destroy(cdf_list_t *p_list) +{ + if (p_list->count != 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: list length not equal to zero", __func__); + CDF_ASSERT(0); + } +} + +CDF_INLINE_FN void cdf_list_size(cdf_list_t *p_list, uint32_t *p_size) +{ + *p_size = p_list->count; +} + +CDF_STATUS cdf_list_insert_front(cdf_list_t *p_list, cdf_list_node_t *p_node); + +CDF_STATUS cdf_list_insert_back(cdf_list_t *p_list, cdf_list_node_t *p_node); + +CDF_STATUS cdf_list_insert_back_size(cdf_list_t *p_list, + cdf_list_node_t *p_node, uint32_t *p_size); + +CDF_STATUS cdf_list_remove_front(cdf_list_t *p_list, cdf_list_node_t **pp_node); + +CDF_STATUS cdf_list_remove_back(cdf_list_t *p_list, cdf_list_node_t **pp_node); + +CDF_STATUS cdf_list_peek_front(cdf_list_t *p_list, cdf_list_node_t **pp_node); + +CDF_STATUS cdf_list_peek_next(cdf_list_t *p_list, cdf_list_node_t *p_node, + cdf_list_node_t **pp_node); + +CDF_STATUS cdf_list_remove_node(cdf_list_t *p_list, + cdf_list_node_t *p_node_to_remove); + +#endif /* __CDF_LIST_H */ diff --git a/core/cdf/inc/cdf_lock.h b/core/cdf/inc/cdf_lock.h new file mode 100644 index 0000000000..82fd160959 --- /dev/null +++ b/core/cdf/inc/cdf_lock.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_LOCK_H) +#define __CDF_LOCK_H + +/** + * + * @file cdf_lock.h + * + * @brief Connectivity driver framework (CDF) lock APIs + * + * Definitions for CDF locks + * + */ + +/* Include Files */ +#include "cdf_status.h" +#include "i_cdf_lock.h" + +/* Preprocessor definitions and constants */ + +/* Type declarations */ +/** + * @brief Platform spinlock object + */ +typedef __cdf_spinlock_t cdf_spinlock_t; +/** + * @brief Platform mutex object + */ +typedef __cdf_semaphore_t cdf_semaphore_t; + +/* Function declarations and documenation */ + +/** + * cdf_semaphore_init() - initialize a semaphore + * @m: Semaphore to initialize + * + * Return: None + */ + +static inline void cdf_semaphore_init(cdf_semaphore_t *m) +{ + __cdf_semaphore_init(m); +} + +/** + * cdf_semaphore_acquire() - take the semaphore + * @m: Semaphore to take + * + * Return: None + */ +static inline int cdf_semaphore_acquire(cdf_device_t osdev, cdf_semaphore_t *m) +{ + return __cdf_semaphore_acquire(osdev, m); +} + +/** + * cdf_semaphore_release () - give the semaphore + * @m: Semaphore to give + * + * Return: None + */ +static inline void +cdf_semaphore_release(cdf_device_t osdev, cdf_semaphore_t *m) +{ + __cdf_semaphore_release(osdev, m); +} + +/** + * cdf_mutex_init() - initialize a CDF lock + * @lock: Pointer to the opaque lock object to initialize + * + * cdf_mutex_init() function initializes the specified lock. Upon + * successful initialization, the state of the lock becomes initialized + * and unlocked. + * + * A lock must be initialized by calling cdf_mutex_init() before it + * may be used in any other lock functions. + * + * Attempting to initialize an already initialized lock results in + * a failure. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_init(cdf_mutex_t *lock); + +/** + * cdf_mutex_acquire () - acquire a CDF lock + * @lock: Pointer to the opaque lock object to acquire + * + * A lock object is acquired by calling cdf_mutex_acquire(). If the lock + * is already locked, the calling thread shall block until the lock becomes + * available. This operation shall return with the lock object referenced by + * lock in the locked state with the calling thread as its owner. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_acquire(cdf_mutex_t *lock); + +/** + * cdf_mutex_release() - release a CDF lock + * @lock: Pointer to the opaque lock object to be released + * + * cdf_mutex_release() function shall release the lock object + * referenced by 'lock'. + * + * If a thread attempts to release a lock that it unlocked or is not + * initialized, an error is returned. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_release(cdf_mutex_t *lock); + +/** + * cdf_mutex_destroy() - destroy a CDF lock + * @lock: Pointer to the opaque lock object to be destroyed + * + * cdf_mutex_destroy() function shall destroy the lock object + * referenced by lock. After a successful return from \a cdf_mutex_destroy() + * the lock object becomes, in effect, uninitialized. + * + * A destroyed lock object can be reinitialized using cdf_mutex_init(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to CDF lock functions to manipulate the lock such + * as cdf_mutex_acquire() will fail if the lock is destroyed. Therefore, + * don't use the lock after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_destroy(cdf_mutex_t *lock); + +/** + * cdf_spinlock_init() - initialize a spinlock + * @lock: Spinlock object pointer + * + * Return: None + */ +static inline void cdf_spinlock_init(cdf_spinlock_t *lock) +{ + __cdf_spinlock_init(lock); +} + +/** + * cdf_spinlock_destroy() - delete a spinlock + * @lock: Spinlock object pointer + * + * Return: None + */ +static inline void cdf_spinlock_destroy(cdf_spinlock_t *lock) +{ + __cdf_spinlock_destroy(lock); +} + +/** + * cdf_spin_lock_bh() - locks the spinlock semaphore in soft irq context + * @lock: Spinlock object pointer + * + * Return: None + */ +static inline void cdf_spin_lock_bh(cdf_spinlock_t *lock) +{ + __cdf_spin_lock_bh(lock); +} + +/** + * cdf_spin_lock_bh() - unlocks the spinlock semaphore in soft irq context + * @lock: Spinlock object pointer + * + * Return: None + */ +static inline void cdf_spin_unlock_bh(cdf_spinlock_t *lock) +{ + __cdf_spin_unlock_bh(lock); +} + +/** + * cdf_wake_lock_init() - initializes a CDF wake lock + * @lock: The wake lock to initialize + * @name: Name of wake lock + * + * Return: + * CDF status success : if wake lock is initialized + * CDF status fialure : if wake lock was not initialized + */ +CDF_STATUS cdf_wake_lock_init(cdf_wake_lock_t *lock, const char *name); + +/** + * cdf_wake_lock_acquire() - acquires a wake lock + * @lock: The wake lock to acquire + * @reason: Reason for taking wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_acquire(cdf_wake_lock_t *pLock, uint32_t reason); + +/** + * cdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout + * @lock: The wake lock to acquire + * @reason: Reason for taking wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_timeout_acquire(cdf_wake_lock_t *pLock, + uint32_t msec, uint32_t reason); + +/** + * cdf_wake_lock_release() - releases a wake lock + * @lock: the wake lock to release + * @@reason: Reason for taking wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_release(cdf_wake_lock_t *pLock, uint32_t reason); + +/** + * cdf_wake_lock_destroy() - destroys a wake lock + * @lock: The wake lock to destroy + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_destroy(cdf_wake_lock_t *pLock); + +/** + * cdf_spinlock_acquire() - acquires a spin lock + * @lock: Spin lock to acquire + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_spinlock_acquire(cdf_spinlock_t *pLock); + +/** + * cdf_spinlock_release() - release a spin lock + * @lock: Spin lock to release + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status fialure : if wake lock was not acquired + */ +CDF_STATUS cdf_spinlock_release(cdf_spinlock_t *pLock); + +#define cdf_spin_lock(_lock) __cdf_spin_lock(_lock) +#define cdf_spin_unlock(_lock) __cdf_spin_unlock(_lock) +#define cdf_spin_lock_irqsave(_lock) __cdf_spin_lock_irqsave(_lock) +#define cdf_spin_unlock_irqrestore(_lock) \ + __cdf_spin_unlock_irqrestore(_lock) +#define cdf_spin_lock_irq(_pLock, _flags) __cdf_spin_lock_irq(_pLock, _flags) +#define cdf_spin_unlock_irq(_pLock, _flags) \ + __cdf_spin_unlock_irq(_pLock, _flags) + +#define cdf_in_softirq() __cdf_in_softirq() + +#endif /* __CDF_LOCK_H */ diff --git a/core/cdf/inc/cdf_mc_timer.h b/core/cdf/inc/cdf_mc_timer.h new file mode 100644 index 0000000000..b8740d7831 --- /dev/null +++ b/core/cdf/inc/cdf_mc_timer.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_MC_TIMER_H) +#define __CDF_MC_TIMER_H + +/** + * DOC: cdf_mc_timer + * + * Connectivity driver framework timer APIs serialized to MC thread + */ + +/* Include Files */ +#include +#include +#include +#include + +#ifdef TIMER_MANAGER +#include +#endif + +/* Preprocessor definitions and constants */ +#define CDF_TIMER_STATE_COOKIE (0x12) +#define CDF_MC_TIMER_TO_MS_UNIT (1000) +#define CDF_MC_TIMER_TO_SEC_UNIT (1000000) + +/* Type declarations */ +/* cdf Timer callback function prototype (well, actually a prototype for + a pointer to this callback function) */ +typedef void (*cdf_mc_timer_callback_t)(void *userData); + +typedef enum { + CDF_TIMER_STATE_UNUSED = CDF_TIMER_STATE_COOKIE, + CDF_TIMER_STATE_STOPPED, + CDF_TIMER_STATE_STARTING, + CDF_TIMER_STATE_RUNNING, +} CDF_TIMER_STATE; + +#ifdef TIMER_MANAGER +struct cdf_mc_timer_s; +typedef struct cdf_mc_timer_node_s { + cdf_list_node_t pNode; + char *fileName; + unsigned int lineNum; + struct cdf_mc_timer_s *cdf_timer; +} cdf_mc_timer_node_t; +#endif + +typedef struct cdf_mc_timer_s { +#ifdef TIMER_MANAGER + cdf_mc_timer_node_t *ptimerNode; +#endif + + cdf_mc_timer_platform_t platformInfo; + cdf_mc_timer_callback_t callback; + void *userData; + cdf_mutex_t lock; + CDF_TIMER_TYPE type; + CDF_TIMER_STATE state; +} cdf_mc_timer_t; + +/* Function declarations and documenation */ +#ifdef TIMER_MANAGER +void cdf_mc_timer_manager_init(void); +void cdf_mc_timer_exit(void); +#else +/** + * cdf_mc_timer_manager_init() - initialize CDF debug timer manager + * + * This API initializes CDF timer debug functionality. + * + * Return: none + */ +static inline void cdf_mc_timer_manager_init(void) +{ +} + +/** + * cdf_mc_timer_exit() - exit CDF timer debug functionality + * + * This API exists CDF timer debug functionality + * + * Return: none + */ +static inline void cdf_mc_timer_exit(void) +{ +} +#endif +/** + * cdf_mc_timer_get_current_state() - get the current state of the timer + * @pTimer: Pointer to timer object + * + * Return: + * CDF_TIMER_STATE - cdf timer state + */ + +CDF_TIMER_STATE cdf_mc_timer_get_current_state(cdf_mc_timer_t *pTimer); + +/** + * cdf_mc_timer_init() - initialize a CDF timer + * @pTimer: Pointer to timer object + * @timerType: Type of timer + * @callback: Callback to be called after timer expiry + * @serData: User data which will be passed to callback function + * + * This API initializes a CDF Timer object. + * + * cdf_mc_timer_init() initializes a CDF Timer object. A timer must be + * initialized by calling cdf_mc_timer_initialize() before it may be used in + * any other timer functions. + * + * Attempting to initialize timer that is already initialized results in + * a failure. A destroyed timer object can be re-initialized with a call to + * cdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to CDF timer functions to manipulate the timer such + * as cdf_mc_timer_set() will fail if the timer is not initialized or has + * been destroyed. Therefore, don't use the timer after it has been + * destroyed until it has been re-initialized. + * + * All callback will be executed within the CDS main thread unless it is + * initialized from the Tx thread flow, in which case it will be executed + * within the tx thread flow. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +#ifdef TIMER_MANAGER +#define cdf_mc_timer_init(timer, timerType, callback, userdata) \ + cdf_mc_timer_init_debug(timer, timerType, callback, userdata, \ + __FILE__, __LINE__) + +CDF_STATUS cdf_mc_timer_init_debug(cdf_mc_timer_t *timer, + CDF_TIMER_TYPE timerType, + cdf_mc_timer_callback_t callback, + void *userData, char *fileName, + uint32_t lineNum); +#else +CDF_STATUS cdf_mc_timer_init(cdf_mc_timer_t *timer, CDF_TIMER_TYPE timerType, + cdf_mc_timer_callback_t callback, + void *userData); +#endif + +/** + * cdf_mc_timer_destroy() - destroy CDF timer + * @timer: Pointer to timer object + * + * cdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a cdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * cdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to CDF timer functions to manipulate the timer, such + * as cdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_destroy(cdf_mc_timer_t *timer); + +/** + * cdf_mc_timer_start() - start a CDF Timer object + * @timer: Pointer to timer object + * @expirationTime: Time to expire + * + * cdf_mc_timer_start() function starts a timer to expire after the + * specified interval, thus running the timer callback function when + * the interval expires. + * + * A timer only runs once (a one-shot timer). To re-start the + * timer, cdf_mc_timer_start() has to be called after the timer runs + * or has been cancelled. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_start(cdf_mc_timer_t *timer, uint32_t expirationTime); + +/** + * cdf_mc_timer_stop() - stop a CDF Timer + * @timer: Pointer to timer object + * cdf_mc_timer_stop() function stops a timer that has been started but + * has not expired, essentially cancelling the 'start' request. + * + * After a timer is stopped, it goes back to the state it was in after it + * was created and can be started again via a call to cdf_mc_timer_start(). + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_stop(cdf_mc_timer_t *timer); + +/** + * cdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks + + * cdf_mc_timer_get_system_ticks() function returns the current number + * of timer ticks in 10msec intervals. This function is suitable timestamping + * and calculating time intervals by calculating the difference between two + * timestamps. + * + * Return: + * The current system tick count (in 10msec intervals). This + * function cannot fail. + */ +v_TIME_t cdf_mc_timer_get_system_ticks(void); + +/** + * cdf_mc_timer_get_system_time() - Get the system time in milliseconds + * + * cdf_mc_timer_get_system_time() function returns the number of milliseconds + * that have elapsed since the system was started + * + * Return: + * The current system time in milliseconds + */ +v_TIME_t cdf_mc_timer_get_system_time(void); + +#endif /* #if !defined __CDF_MC_TIMER_H */ diff --git a/core/cdf/inc/cdf_memory.h b/core/cdf/inc/cdf_memory.h new file mode 100644 index 0000000000..7380089214 --- /dev/null +++ b/core/cdf/inc/cdf_memory.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_MEMORY_H) +#define __CDF_MEMORY_H + +/** + * DOC: cdf_memory + * + * Connectivity driver framework (CDF) memory management APIs + */ + +/* Include Files */ +#include + +/* Preprocessor definitions and constants */ + +#ifdef MEMORY_DEBUG +void cdf_mem_clean(void); +void cdf_mem_init(void); +void cdf_mem_exit(void); +#else +/** + * cdf_mem_init() - initialize cdf memory debug functionality + * + * Return: none + */ +static inline void cdf_mem_init(void) +{ +} + +/** + * cdf_mem_exit() - exit cdf memory debug functionality + * + * Return: none + */ +static inline void cdf_mem_exit(void) +{ +} +#endif +/* Type declarations */ + +/* Function declarations and documenation */ + +/** + * cdf_mem_malloc() - allocation CDF memory + * @size: Number of bytes of memory to allocate. + * + * This function will dynamicallly allocate the specified number of bytes of + * memory. + * + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns %NULL. + * + */ +#ifdef MEMORY_DEBUG +#define cdf_mem_malloc(size) cdf_mem_malloc_debug(size, __FILE__, __LINE__) +void *cdf_mem_malloc_debug(size_t size, char *fileName, uint32_t lineNum); +#else +void *cdf_mem_malloc(size_t size); +#endif + +/** + * cdf_mem_free() - free CDF memory + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. + * + * Return: + * Nothing + * + */ +void cdf_mem_free(void *ptr); + +/** + * cdf_mem_set() - set (fill) memory with a specified byte value. + * @pMemory: Pointer to memory that will be set + * @numBytes: Number of bytes to be set + * @value: Byte set in memory + * + * Return: + * Nothing + * + */ +void cdf_mem_set(void *ptr, uint32_t numBytes, uint32_t value); + +/** + * cdf_mem_zero() - zero out memory + * @pMemory: pointer to memory that will be set to zero + * @numBytes: number of bytes zero + * @value: byte set in memory + * + * This function sets the memory location to all zeros, essentially clearing + * the memory. + * + * Return: + * Nothing + * + */ +void cdf_mem_zero(void *ptr, uint32_t numBytes); + +/** + * cdf_mem_copy() - copy memory + * @pDst: Pointer to destination memory location (to copy to) + * @pSrc: Pointer to source memory location (to copy from) + * @numBytes: Number of bytes to copy. + * + * Copy host memory from one location to another, similar to memcpy in + * standard C. Note this function does not specifically handle overlapping + * source and destination memory locations. Calling this function with + * overlapping source and destination memory locations will result in + * unpredictable results. Use cdf_mem_move() if the memory locations + * for the source and destination are overlapping (or could be overlapping!) + * + * Return: + * Nothing + * + */ +void cdf_mem_copy(void *pDst, const void *pSrc, uint32_t numBytes); + +/** + * cdf_mem_move() - move memory + * @pDst: pointer to destination memory location (to move to) + * @pSrc: pointer to source memory location (to move from) + * @numBytes: number of bytes to move. + * + * Move host memory from one location to another, similar to memmove in + * standard C. Note this function *does* handle overlapping + * source and destination memory locations. + + * Return: + * Nothing + */ +void cdf_mem_move(void *pDst, const void *pSrc, uint32_t numBytes); + +/** + * cdf_mem_compare() - memory compare + * @pMemory1: pointer to one location in memory to compare. + * @pMemory2: pointer to second location in memory to compare. + * @numBytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * + * Return: + * bool - returns a bool value that tells if the memory locations + * are equal or not equal. + * + */ +bool cdf_mem_compare(const void *pMemory1, const void *pMemory2, + uint32_t numBytes); + +/** + * cdf_mem_compare2() - memory compare + * @pMemory1: pointer to one location in memory to compare. + * @pMemory2: pointer to second location in memory to compare. + * @numBytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * Return: + * int32_t - returns a bool value that tells if the memory + * locations are equal or not equal. + * 0 -- equal + * < 0 -- *pMemory1 is less than *pMemory2 + * > 0 -- *pMemory1 is bigger than *pMemory2 + */ +int32_t cdf_mem_compare2(const void *pMemory1, const void *pMemory2, + uint32_t numBytes); + +void *cdf_os_mem_alloc_consistent(cdf_device_t osdev, cdf_size_t size, + cdf_dma_addr_t *paddr, + cdf_dma_context_t mctx); +void +cdf_os_mem_free_consistent(cdf_device_t osdev, + cdf_size_t size, + void *vaddr, + cdf_dma_addr_t paddr, cdf_dma_context_t memctx); + +void +cdf_os_mem_dma_sync_single_for_device(cdf_device_t osdev, + cdf_dma_addr_t bus_addr, + cdf_size_t size, + enum dma_data_direction direction); + +/** + * cdf_str_len() - returns the length of a string + * @str: input string + * + * Return: + * length of string + */ +static inline int32_t cdf_str_len(const char *str) +{ + return strlen(str); +} + +#endif /* __CDF_MEMORY_H */ diff --git a/core/cdf/inc/cdf_nbuf.h b/core/cdf/inc/cdf_nbuf.h new file mode 100644 index 0000000000..95981820d5 --- /dev/null +++ b/core/cdf/inc/cdf_nbuf.h @@ -0,0 +1,1053 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_nbuf_public network buffer API + * This file defines the network buffer abstraction. + */ + +#ifndef _CDF_NBUF_H +#define _CDF_NBUF_H +#include +#include +#include +#include +#include +#include + +#define IPA_NBUF_OWNER_ID 0xaa55aa55 +#define NBUF_PKT_TRAC_TYPE_EAPOL 0x02 +#define NBUF_PKT_TRAC_TYPE_DHCP 0x04 +#define NBUF_PKT_TRAC_TYPE_MGMT_ACTION 0x08 +#define NBUF_PKT_TRAC_MAX_STRING 12 +#define NBUF_PKT_TRAC_PROTO_STRING 4 +#define NBUF_PKT_ERROR 1 + +/* Tracked Packet types */ +#define NBUF_TX_PKT_INVALID 0 +#define NBUF_TX_PKT_DATA_TRACK 1 +#define NBUF_TX_PKT_MGMT_TRACK 2 + +/* Different Packet states */ +#define NBUF_TX_PKT_HDD 1 +#define NBUF_TX_PKT_TXRX_ENQUEUE 2 +#define NBUF_TX_PKT_TXRX_DEQUEUE 3 +#define NBUF_TX_PKT_TXRX 4 +#define NBUF_TX_PKT_HTT 5 +#define NBUF_TX_PKT_HTC 6 +#define NBUF_TX_PKT_HIF 7 +#define NBUF_TX_PKT_CE 8 +#define NBUF_TX_PKT_FREE 9 +#define NBUF_TX_PKT_STATE_MAX 10 + + +/** + * @cdf_nbuf_t - Platform indepedent packet abstraction + */ +typedef __cdf_nbuf_t cdf_nbuf_t; + +/** + * @cdf_dma_map_cb_t - Dma map callback prototype + */ +typedef void (*cdf_dma_map_cb_t)(void *arg, cdf_nbuf_t buf, + cdf_dma_map_t dmap); + +/** + * @__CDF_NBUF_NULL - invalid handle + */ +#define CDF_NBUF_NULL __CDF_NBUF_NULL +/** + * @cdf_nbuf_queue_t - Platform independent packet queue abstraction + */ +typedef __cdf_nbuf_queue_t cdf_nbuf_queue_t; + +/* BUS/DMA mapping routines */ + +/** + * cdf_nbuf_map() - map a buffer to local bus address space + * @osdev: OS device + * @buf: Buf to be mapped (mapping info is stored in the buf's meta-data area) + * @dir: DMA direction + * + * Return: Status of the operation + */ +static inline CDF_STATUS +cdf_nbuf_map(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ + return __cdf_nbuf_map(osdev, buf, dir); +} + +/** + * cdf_nbuf_unmap() - unmap a previously mapped buf + * @osdev: OS device + * @buf: Buf to be unmapped (mapping info is stored in the buf's meta-data area) + * @dir: DMA direction + * + * Return: none + */ +static inline void +cdf_nbuf_unmap(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ + __cdf_nbuf_unmap(osdev, buf, dir); +} + +/** + * cdf_nbuf_map_single() - map a single buffer to local bus address space + * @osdev: OS device + * @buf: Buf to be mapped (mapping info is stored in the buf's meta-data area) + * @dir: DMA direction + * + * Return: Status of the operation + */ +static inline CDF_STATUS +cdf_nbuf_map_single(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ + return __cdf_nbuf_map_single(osdev, buf, dir); +} + +/** + * cdf_nbuf_unmap_single() - unmap a previously mapped buf + * @osdev: OS device + * @buf: Buf to be unmapped (mapping info is stored in the buf's meta-data area) + * @dir: DMA direction + * + * Return: none + */ +static inline void +cdf_nbuf_unmap_single(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ + __cdf_nbuf_unmap_single(osdev, buf, dir); +} + +/** + * cdf_nbuf_get_num_frags() - get number of fragments + * @buf: Network buffer + * + * Return: Number of fragments + */ +static inline int cdf_nbuf_get_num_frags(cdf_nbuf_t buf) +{ + return __cdf_nbuf_get_num_frags(buf); +} + +/** + * cdf_nbuf_get_frag_len() - get fragment length + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment length + */ +static inline int cdf_nbuf_get_frag_len(cdf_nbuf_t buf, int frag_num) +{ + return __cdf_nbuf_get_frag_len(buf, frag_num); +} + +/** + * cdf_nbuf_get_frag_vaddr() - get fragment virtual address + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment virtual address + */ +static inline unsigned char *cdf_nbuf_get_frag_vaddr(cdf_nbuf_t buf, + int frag_num) +{ + return __cdf_nbuf_get_frag_vaddr(buf, frag_num); +} + +/** + * cdf_nbuf_get_frag_paddr_lo() - get fragment physical address low order bytes + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment physical address lo + */ +static inline uint32_t cdf_nbuf_get_frag_paddr_lo(cdf_nbuf_t buf, int frag_num) +{ + return __cdf_nbuf_get_frag_paddr_lo(buf, frag_num); +} + +/** + * cdf_nbuf_get_frag_is_wordstream() - is fragment wordstream + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment wordstream or not + */ +static inline int cdf_nbuf_get_frag_is_wordstream(cdf_nbuf_t buf, int frag_num) +{ + return __cdf_nbuf_get_frag_is_wordstream(buf, frag_num); +} + +/** + * cdf_nbuf_set_frag_is_wordstream() - set fragment wordstream + * @buf: Network buffer + * @frag_num: Fragment number + * @is_wordstream: Wordstream + * + * Return: none + */ +static inline void +cdf_nbuf_set_frag_is_wordstream(cdf_nbuf_t buf, int frag_num, int is_wordstream) +{ + __cdf_nbuf_set_frag_is_wordstream(buf, frag_num, is_wordstream); +} + +/** + * cdf_nbuf_frag_push_head() - push fragment head + * @buf: Network buffer + * @frag_len: Fragment length + * @frag_vaddr: Fragment virtual address + * @frag_paddr_lo: Fragment physical address lo + * @frag_paddr_hi: Fragment physical address hi + * + * Return: none + */ +static inline void +cdf_nbuf_frag_push_head(cdf_nbuf_t buf, + int frag_len, + char *frag_vaddr, + uint32_t frag_paddr_lo, uint32_t frag_paddr_hi) +{ + __cdf_nbuf_frag_push_head(buf, frag_len, frag_vaddr, frag_paddr_lo, + frag_paddr_hi); +} + +#ifdef MEMORY_DEBUG +void cdf_net_buf_debug_init(void); +void cdf_net_buf_debug_exit(void); +void cdf_net_buf_debug_clean(void); +void cdf_net_buf_debug_add_node(cdf_nbuf_t net_buf, size_t size, + uint8_t *file_name, uint32_t line_num); +void cdf_net_buf_debug_delete_node(cdf_nbuf_t net_buf); +void cdf_net_buf_debug_release_skb(cdf_nbuf_t net_buf); + +/* nbuf allocation rouines */ + +/** + * cdf_nbuf_alloc() - Allocate cdf_nbuf + * @hdl: Platform device object + * @size: Data buffer size for this cdf_nbuf including max header + * size + * @reserve: Headroom to start with. + * @align: Alignment for the start buffer. + * @prio: Indicate if the nbuf is high priority (some OSes e.g darwin + * polls few times if allocation fails and priority is true) + * + * The nbuf created is guarenteed to have only 1 physical segment + * + * Return: The new cdf_nbuf instance or NULL if there's not enough memory. + */ + +#define cdf_nbuf_alloc(d, s, r, a, p) \ + cdf_nbuf_alloc_debug(d, s, r, a, p, __FILE__, __LINE__) +static inline cdf_nbuf_t +cdf_nbuf_alloc_debug(cdf_device_t osdev, cdf_size_t size, int reserve, + int align, int prio, uint8_t *file_name, + uint32_t line_num) +{ + cdf_nbuf_t net_buf; + net_buf = __cdf_nbuf_alloc(osdev, size, reserve, align, prio); + + /* Store SKB in internal CDF tracking table */ + if (cdf_likely(net_buf)) + cdf_net_buf_debug_add_node(net_buf, size, file_name, line_num); + + return net_buf; +} + +/** + * cdf_nbuf_free() - free cdf_nbuf + * @net_buf: Network buffer to free + * + * Return: none + */ +static inline void cdf_nbuf_free(cdf_nbuf_t net_buf) +{ + /* Remove SKB from internal CDF tracking table */ + if (cdf_likely(net_buf)) + cdf_net_buf_debug_delete_node(net_buf); + + __cdf_nbuf_free(net_buf); +} + +#else + +static inline void cdf_net_buf_debug_release_skb(cdf_nbuf_t net_buf) +{ + return; +} + +/* Nbuf allocation rouines */ + +/** + * cdf_nbuf_alloc() - allocate cdf_nbuf + * @hdl: Platform device object + * @size: Data buffer size for this cdf_nbuf including max header + * size + * @reserve: Headroom to start with. + * @align: Alignment for the start buffer. + * @prio: Indicate if the nbuf is high priority (some OSes e.g darwin + * polls few times if allocation fails and priority is true) + * + * The nbuf created is guarenteed to have only 1 physical segment + * + * Return: new cdf_nbuf instance or NULL if there's not enough memory. + */ +static inline cdf_nbuf_t +cdf_nbuf_alloc(cdf_device_t osdev, + cdf_size_t size, int reserve, int align, int prio) +{ + return __cdf_nbuf_alloc(osdev, size, reserve, align, prio); +} + +/** + * cdf_nbuf_free() - free cdf_nbuf + * @buf: Network buffer to free + * + * Return: none + */ +static inline void cdf_nbuf_free(cdf_nbuf_t buf) +{ + __cdf_nbuf_free(buf); +} + +#endif + +/** + * cdf_nbuf_tx_free() - free a list of cdf_nbufs and tell the OS their tx + * status (if req'd) + * @bufs: List of netbufs to free + * @tx_err: Whether the tx frames were transmitted successfully + * + * Return: none + */ +static inline void cdf_nbuf_tx_free(cdf_nbuf_t buf_list, int tx_err) +{ + __cdf_nbuf_tx_free(buf_list, tx_err); +} + +/** + * cdf_nbuf_copy() - copy src buffer into dst. + * @buf: source nbuf to copy from + * + * This API is useful, for example, because most native buffer provide a way to + * copy a chain into a single buffer. Therefore as a side effect, it also + * "linearizes" a buffer (which is perhaps why you'll use it mostly). It + * creates a writeable copy. + * + * + * Return: new nbuf + */ +static inline cdf_nbuf_t cdf_nbuf_copy(cdf_nbuf_t buf) +{ + return __cdf_nbuf_copy(buf); +} + +/** + * cdf_nbuf_cat() - link two nbufs, the new buf is piggybacked into older one + * @dst: Buffer to piggyback into + * @src: Buffer to put + * + * Return: Status of the call - 0 successful + */ +static inline CDF_STATUS cdf_nbuf_cat(cdf_nbuf_t dst, cdf_nbuf_t src) +{ + return __cdf_nbuf_cat(dst, src); +} + +/** + * @cdf_nbuf_copy_bits() - return the length of the copy bits for skb + * @skb: SKB pointer + * @offset: offset + * @len: Length + * @to: To + * + * Return: int32_t + */ +static inline int32_t +cdf_nbuf_copy_bits(cdf_nbuf_t nbuf, uint32_t offset, uint32_t len, void *to) +{ + return __cdf_nbuf_copy_bits(nbuf, offset, len, to); +} + +/** + * cdf_nbuf_clone() - clone the nbuf (copy is readonly) + * @buf: nbuf to clone from + * + * Return: cloned buffer + */ +static inline cdf_nbuf_t cdf_nbuf_clone(cdf_nbuf_t buf) +{ + return __cdf_nbuf_clone(buf); +} + +/* nbuf manipulation routines */ + +/** + * @cdf_nbuf_head() - return the address of an nbuf's buffer + * @buf: netbuf + * + * Return: head address + */ +static inline uint8_t *cdf_nbuf_head(cdf_nbuf_t buf) +{ + return __cdf_nbuf_head(buf); +} + +/** + * cdf_nbuf_data() - Return the address of the start of data within an nbuf + * @buf: Network buffer + * + * Return: Data address + */ +static inline uint8_t *cdf_nbuf_data(cdf_nbuf_t buf) +{ + return __cdf_nbuf_data(buf); +} + +/** + * cdf_nbuf_headroom() - amount of headroom int the current nbuf + * @buf: Network buffer + * + * Return: Amount of head room + */ +static inline uint32_t cdf_nbuf_headroom(cdf_nbuf_t buf) +{ + return __cdf_nbuf_headroom(buf); +} + +/** + * cdf_nbuf_tailroom() - amount of tail space available + * @buf: Network buffer + * + * Return: amount of tail room + */ +static inline uint32_t cdf_nbuf_tailroom(cdf_nbuf_t buf) +{ + return __cdf_nbuf_tailroom(buf); +} + +/** + * cdf_nbuf_push_head() - push data in the front + * @buf: Network buf instance + * @size: Size to be pushed + * + * Return: New data pointer of this buf after data has been pushed, + * or NULL if there is not enough room in this buf. + */ +static inline uint8_t *cdf_nbuf_push_head(cdf_nbuf_t buf, cdf_size_t size) +{ + return __cdf_nbuf_push_head(buf, size); +} + +/** + * cdf_nbuf_put_tail() - puts data in the end + * @buf: Network buf instance + * @size: Size to be pushed + * + * Return: Data pointer of this buf where new data has to be + * put, or NULL if there is not enough room in this buf. + */ +static inline uint8_t *cdf_nbuf_put_tail(cdf_nbuf_t buf, cdf_size_t size) +{ + return __cdf_nbuf_put_tail(buf, size); +} + +/** + * cdf_nbuf_pull_head() - pull data out from the front + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: New data pointer of this buf after data has been popped, + * or NULL if there is not sufficient data to pull. + */ +static inline uint8_t *cdf_nbuf_pull_head(cdf_nbuf_t buf, cdf_size_t size) +{ + return __cdf_nbuf_pull_head(buf, size); +} + +/** + * cdf_nbuf_trim_tail() - trim data out from the end + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: none + */ +static inline void cdf_nbuf_trim_tail(cdf_nbuf_t buf, cdf_size_t size) +{ + __cdf_nbuf_trim_tail(buf, size); +} + +/** + * cdf_nbuf_len() - get the length of the buf + * @buf: Network buf instance + * + * Return: total length of this buf. + */ +static inline cdf_size_t cdf_nbuf_len(cdf_nbuf_t buf) +{ + return __cdf_nbuf_len(buf); +} + +/** + * cdf_nbuf_set_pktlen() - set the length of the buf + * @buf: Network buf instance + * @size: Size to be set + * + * Return: none + */ +static inline void cdf_nbuf_set_pktlen(cdf_nbuf_t buf, uint32_t len) +{ + __cdf_nbuf_set_pktlen(buf, len); +} + +/** + * cdf_nbuf_reserve() - trim data out from the end + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: none + */ +static inline void cdf_nbuf_reserve(cdf_nbuf_t buf, cdf_size_t size) +{ + __cdf_nbuf_reserve(buf, size); +} + +/** + * cdf_nbuf_peek_header() - return the data pointer & length of the header + * @buf: Network nbuf + * @addr: Data pointer + * @len: Length of the data + * + * Return: none + */ +static inline void +cdf_nbuf_peek_header(cdf_nbuf_t buf, uint8_t **addr, uint32_t *len) +{ + __cdf_nbuf_peek_header(buf, addr, len); +} + +/* nbuf private context routines */ + +/* nbuf queue routines */ + +/** + * cdf_nbuf_queue_init() - initialize buf queue + * @head: Network buf queue head + * + * Return: none + */ +static inline void cdf_nbuf_queue_init(cdf_nbuf_queue_t *head) +{ + __cdf_nbuf_queue_init(head); +} + +/** + * cdf_nbuf_queue_add() - append a nbuf to the tail of the buf queue + * @head: Network buf queue head + * @buf: Network buf + * + * Return: none + */ +static inline void cdf_nbuf_queue_add(cdf_nbuf_queue_t *head, cdf_nbuf_t buf) +{ + __cdf_nbuf_queue_add(head, buf); +} + +/** + * cdf_nbuf_queue_insert_head() - insert nbuf at the head of queue + * @head: Network buf queue head + * @buf: Network buf + * + * Return: none + */ +static inline void +cdf_nbuf_queue_insert_head(cdf_nbuf_queue_t *head, cdf_nbuf_t buf) +{ + __cdf_nbuf_queue_insert_head(head, buf); +} + +/** + * cdf_nbuf_queue_remove() - retrieve a buf from the head of the buf queue + * @head: Network buf queue head + * + * Return: The head buf in the buf queue. + */ +static inline cdf_nbuf_t cdf_nbuf_queue_remove(cdf_nbuf_queue_t *head) +{ + return __cdf_nbuf_queue_remove(head); +} + +/** + * cdf_nbuf_queue_len() - get the length of the queue + * @head: Network buf queue head + * + * Return: length of the queue + */ +static inline uint32_t cdf_nbuf_queue_len(cdf_nbuf_queue_t *head) +{ + return __cdf_nbuf_queue_len(head); +} + +/** + * cdf_nbuf_queue_next() - get the next guy/packet of the given buffer + * @buf: Network buffer + * + * Return: next buffer/packet + */ +static inline cdf_nbuf_t cdf_nbuf_queue_next(cdf_nbuf_t buf) +{ + return __cdf_nbuf_queue_next(buf); +} + +/** + * @cdf_nbuf_is_queue_empty() - check if the buf queue is empty + * @nbq: Network buf queue handle + * + * Return: true if queue is empty + * false if queue is not emty + */ +static inline bool cdf_nbuf_is_queue_empty(cdf_nbuf_queue_t *nbq) +{ + return __cdf_nbuf_is_queue_empty(nbq); +} + +/** + * cdf_nbuf_next() - get the next packet in the linked list + * @buf: Network buffer + * + * This function can be used when nbufs are directly linked into a list, + * rather than using a separate network buffer queue object. + * + * Return: next network buffer in the linked list + */ +static inline cdf_nbuf_t cdf_nbuf_next(cdf_nbuf_t buf) +{ + return __cdf_nbuf_next(buf); +} + +/** + * cdf_nbuf_get_protocol() - return the protocol value of the skb + * @skb: Pointer to network buffer + * + * Return: skb protocol + */ +static inline uint16_t cdf_nbuf_get_protocol(struct sk_buff *skb) +{ + return __cdf_nbuf_get_protocol(skb); +} + +/** + * cdf_nbuf_get_ip_summed() - return the ip checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: skb ip_summed + */ +static inline uint8_t cdf_nbuf_get_ip_summed(struct sk_buff *skb) +{ + return __cdf_nbuf_get_ip_summed(skb); +} + +/** + * cdf_nbuf_set_ip_summed() - sets the ip_summed value of the skb + * @skb: Pointer to network buffer + * @ip_summed: ip checksum + * + * Return: none + */ +static inline void cdf_nbuf_set_ip_summed(struct sk_buff *skb, uint8_t ip_summed) +{ + __cdf_nbuf_set_ip_summed(skb, ip_summed); +} + +/** + * cdf_nbuf_set_next() - add a packet to a linked list + * @this_buf: Predecessor buffer + * @next_buf: Successor buffer + * + * This function can be used to directly link nbufs, rather than using + * a separate network buffer queue object. + * + * Return: none + */ +static inline void cdf_nbuf_set_next(cdf_nbuf_t this_buf, cdf_nbuf_t next_buf) +{ + __cdf_nbuf_set_next(this_buf, next_buf); +} + +/* nbuf extension routines */ + +/** + * cdf_nbuf_set_next_ext() - link extension of this packet contained in a new + * nbuf + * @this_buf: predecessor buffer + * @next_buf: successor buffer + * + * This function is used to link up many nbufs containing a single logical + * packet - not a collection of packets. Do not use for linking the first + * extension to the head + * + * Return: none + */ +static inline void +cdf_nbuf_set_next_ext(cdf_nbuf_t this_buf, cdf_nbuf_t next_buf) +{ + __cdf_nbuf_set_next_ext(this_buf, next_buf); +} + +/** + * cdf_nbuf_next_ext() - get the next packet extension in the linked list + * @buf: Network buffer + * + * Return: Next network buffer in the linked list + */ +static inline cdf_nbuf_t cdf_nbuf_next_ext(cdf_nbuf_t buf) +{ + return __cdf_nbuf_next_ext(buf); +} + +/** + * cdf_nbuf_append_ext_list() - link list of packet extensions to the head + * segment + * @head_buf: Network buf holding head segment (single) + * @ext_list: Network buf list holding linked extensions to the head + * @ext_len: Total length of all buffers in the extension list + * + * This function is used to link up a list of packet extensions (seg1, 2, + * ...) to the nbuf holding the head segment (seg0) + * + * Return: none + */ +static inline void +cdf_nbuf_append_ext_list(cdf_nbuf_t head_buf, cdf_nbuf_t ext_list, + cdf_size_t ext_len) +{ + __cdf_nbuf_append_ext_list(head_buf, ext_list, ext_len); +} + +/** + * cdf_nbuf_get_tx_cksum() - gets the tx checksum offload demand + * @buf: Network buffer + * + * Return: cdf_nbuf_tx_cksum_t checksum offload demand for the frame + */ +static inline cdf_nbuf_tx_cksum_t cdf_nbuf_get_tx_cksum(cdf_nbuf_t buf) +{ + return __cdf_nbuf_get_tx_cksum(buf); +} + +/** + * cdf_nbuf_set_rx_cksum() - drivers that support hw checksumming use this to + * indicate checksum info to the stack. + * @buf: Network buffer + * @cksum: Checksum + * + * Return: none + */ +static inline void +cdf_nbuf_set_rx_cksum(cdf_nbuf_t buf, cdf_nbuf_rx_cksum_t *cksum) +{ + __cdf_nbuf_set_rx_cksum(buf, cksum); +} + +/** + * cdf_nbuf_get_tid() - this function extracts the TID value from nbuf + * @buf: Network buffer + * + * Return: TID value + */ +static inline uint8_t cdf_nbuf_get_tid(cdf_nbuf_t buf) +{ + return __cdf_nbuf_get_tid(buf); +} + +/** + * cdf_nbuf_set_tid() - this function sets the TID value in nbuf + * @buf: Network buffer + * @tid: TID value + * + * Return: none + */ +static inline void cdf_nbuf_set_tid(cdf_nbuf_t buf, uint8_t tid) +{ + __cdf_nbuf_set_tid(buf, tid); +} + +/** + * cdf_nbuf_get_exemption_type() - this function extracts the exemption type + * from nbuf + * @buf: Network buffer + * + * Return: Exemption type + */ +static inline uint8_t cdf_nbuf_get_exemption_type(cdf_nbuf_t buf) +{ + return __cdf_nbuf_get_exemption_type(buf); +} + +/** + * cdf_nbuf_set_protocol() - this function peeks data into the buffer at given + * offset + * @buf: Network buffer + * @proto: Protocol + * + * Return: none + */ +static inline void cdf_nbuf_set_protocol(cdf_nbuf_t buf, uint16_t proto) +{ + __cdf_nbuf_set_protocol(buf, proto); +} + +/** + * cdf_nbuf_trace_get_proto_type() - this function return packet proto type + * @buf: Network buffer + * + * Return: Packet protocol type + */ +static inline uint8_t cdf_nbuf_trace_get_proto_type(cdf_nbuf_t buf) +{ + return __cdf_nbuf_trace_get_proto_type(buf); +} + +#ifdef QCA_PKT_PROTO_TRACE +/** + * cdf_nbuf_trace_set_proto_type() - this function updates packet proto type + * @buf: Network buffer + * @proto_type: Protocol type + * + * Return: none + */ +static inline void +cdf_nbuf_trace_set_proto_type(cdf_nbuf_t buf, uint8_t proto_type) +{ + __cdf_nbuf_trace_set_proto_type(buf, proto_type); +} +#else +#define cdf_nbuf_trace_set_proto_type(buf, proto_type) /*NO OP*/ +#endif + +/** + * cdf_nbuf_reg_trace_cb() - this function registers protocol trace callback + * @cb_func_ptr: Callback pointer + * + * Return: none + */ +static inline void cdf_nbuf_reg_trace_cb(cdf_nbuf_trace_update_t cb_func_ptr) +{ + __cdf_nbuf_reg_trace_cb(cb_func_ptr); +} + +/** + * cdf_nbuf_trace_update() - this function updates protocol event + * @buf: Network buffer + * @event_string: Event string pointer + * + * Return: none + */ +static inline void cdf_nbuf_trace_update(cdf_nbuf_t buf, char *event_string) +{ + __cdf_nbuf_trace_update(buf, event_string); +} + +/** + * cdf_nbuf_set_tx_parallel_dnload_frm() - set tx parallel download + * @buf: Network buffer + * @candi: Candidate of parallel download frame + * + * This function stores a flag specifying this TX frame is suitable for + * downloading though a 2nd TX data pipe that is used for short frames for + * protocols that can accept out-of-order delivery. + * + * Return: none + */ +static inline void +cdf_nbuf_set_tx_parallel_dnload_frm(cdf_nbuf_t buf, uint8_t candi) +{ + __cdf_nbuf_set_tx_htt2_frm(buf, candi); +} + +/** + * cdf_nbuf_get_tx_parallel_dnload_frm() - get tx parallel download + * @buf: Network buffer + * + * This function return whether this TX frame is allow to download though a 2nd + * TX data pipe or not. + * + * Return: none + */ +static inline uint8_t cdf_nbuf_get_tx_parallel_dnload_frm(cdf_nbuf_t buf) +{ + return __cdf_nbuf_get_tx_htt2_frm(buf); +} + +/** + * cdf_invalidate_range() - invalidate the virtual address range specified by + * start and end addresses. + * Note: This does not write back the cache entries. + * + * Return: none + */ +static inline void cdf_invalidate_range(void *start, void *end) +{ +#ifdef MSM_PLATFORM + dmac_inv_range(start, end); +#else + /* TODO figure out how to invalidate cache on x86 and other + non-MSM platform */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Cache invalidate not yet implemneted for non-MSM platform"); + return; +#endif +} + +#if defined(FEATURE_TSO) +/** + * cdf_nbuf_dec_num_frags() - decrement the number of fragments + * @buf: Network buffer + * + * Return: Number of fragments + */ +static inline int cdf_nbuf_dec_num_frags(cdf_nbuf_t buf) +{ + return __cdf_nbuf_dec_num_frags(buf); +} + +/** + * cdf_nbuf_is_tso() - is the network buffer a jumbo packet? + * @buf: Network buffer + * + * Return: 1 - this is a jumbo packet 0 - not a jumbo packet + */ +static inline uint8_t cdf_nbuf_is_tso(cdf_nbuf_t nbuf) +{ + return __cdf_nbuf_is_tso(nbuf); +} + +/** + * cdf_nbuf_get_tso_info() - function to divide a jumbo TSO + * network buffer into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: number of TSO segments + */ +static inline uint32_t cdf_nbuf_get_tso_info(cdf_device_t osdev, + cdf_nbuf_t nbuf, struct cdf_tso_info_t *tso_info) +{ + return __cdf_nbuf_get_tso_info(osdev, nbuf, tso_info); +} + +/** + * cdf_nbuf_get_tso_num_seg() - function to calculate the number + * of TCP segments within the TSO jumbo packet + * @nbuf: TSO jumbo network buffer to be segmented + * + * This function calculates the number of TCP segments that the + network buffer can be divided into. + * + * Return: number of TCP segments + */ +static inline uint32_t cdf_nbuf_get_tso_num_seg(cdf_nbuf_t nbuf) +{ + return __cdf_nbuf_get_tso_num_seg(nbuf); +} + +/** + * cdf_nbuf_inc_users() - function to increment the number of + * users referencing this network buffer + * + * @nbuf: network buffer + * + * This function increments the number of users referencing this + * network buffer + * + * Return: the network buffer + */ +static inline cdf_nbuf_t cdf_nbuf_inc_users(cdf_nbuf_t nbuf) +{ + return __cdf_nbuf_inc_users(nbuf); +} +#endif /*TSO*/ + +/** + * cdf_nbuf_data_attr_get() - Get data_attr field from cvg_nbuf_cb + * + * @nbuf: Network buffer (skb on linux) + * + * This function returns the values of data_attr field + * in struct cvg_nbuf_cb{}, to which skb->cb is typecast. + * This value is actually the value programmed in CE descriptor. + * + * Return: Value of data_attr + */ +static inline +uint32_t cdf_nbuf_data_attr_get(cdf_nbuf_t buf) +{ + return __cdf_nbuf_data_attr_get(buf); +} + +/** + * cdf_nbuf_data_attr_set() - Sets data_attr field in cvg_nbuf_cb + * + * @nbuf: Network buffer (skb on linux) + * @data_attr: Value to be stored cvg_nbuf_cb->data_attr + * + * This function stores the value to be programmed in CE + * descriptor as part skb->cb which is typecast to struct cvg_nbuf_cb{} + * + * Return: void + */ +static inline +void cdf_nbuf_data_attr_set(cdf_nbuf_t buf, uint32_t data_attr) +{ + __cdf_nbuf_data_attr_set(buf, data_attr); +} + +/** + * cdf_nbuf_tx_info_get() - Parse skb and get Tx metadata + * + * @nbuf: Network buffer (skb on linux) + * + * This function parses the payload to figure out relevant + * Tx meta-data e.g. whether to enable tx_classify bit + * in CE. + * + * Return: void + */ +#define cdf_nbuf_tx_info_get __cdf_nbuf_tx_info_get + +void cdf_nbuf_set_state(cdf_nbuf_t nbuf, uint8_t current_state); +void cdf_nbuf_tx_desc_count_display(void); +void cdf_nbuf_tx_desc_count_clear(void); + +#endif diff --git a/core/cdf/inc/cdf_net_types.h b/core/cdf/inc/cdf_net_types.h new file mode 100644 index 0000000000..fc70c110e3 --- /dev/null +++ b/core/cdf/inc/cdf_net_types.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_net_types + * This file defines types used in the networking stack abstraction. + */ + +#ifndef _CDF_NET_TYPES_H +#define _CDF_NET_TYPES_H + +#include /* uint8_t, etc. */ + +#define ADF_NET_MAC_ADDR_MAX_LEN 6 +#define ADF_NET_IF_NAME_SIZE 64 +#define ADF_NET_ETH_LEN ADF_NET_MAC_ADDR_MAX_LEN +#define ADF_NET_MAX_MCAST_ADDR 64 + +/* Extended Traffic ID passed to target if the TID is unknown */ +#define ADF_NBUF_TX_EXT_TID_INVALID 0x1f + +/** + * cdf_nbuf_exemption_type - CDF net buf exemption types for encryption + * @CDF_NBUF_EXEMPT_NO_EXEMPTION: No exemption + * @CDF_NBUF_EXEMPT_ALWAYS: Exempt always + * @CDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: Exempt on key mapping + */ +enum cdf_nbuf_exemption_type { + CDF_NBUF_EXEMPT_NO_EXEMPTION = 0, + CDF_NBUF_EXEMPT_ALWAYS, + CDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE +}; + +/** + * typedef cdf_nbuf_tx_cksum_t - transmit checksum offload types + * @CDF_NBUF_TX_CKSUM_NONE: No checksum offload + * @CDF_NBUF_TX_CKSUM_IP: IP header checksum offload + * @CDF_NBUF_TX_CKSUM_TCP_UDP: TCP/UDP checksum offload + * @CDF_NBUF_TX_CKSUM_TCP_UDP_IP: TCP/UDP and IP header checksum offload + */ + +typedef enum { + CDF_NBUF_TX_CKSUM_NONE, + CDF_NBUF_TX_CKSUM_IP, + CDF_NBUF_TX_CKSUM_TCP_UDP, + CDF_NBUF_TX_CKSUM_TCP_UDP_IP, + +} cdf_nbuf_tx_cksum_t; + +/** + * typedef cdf_nbuf_l4_rx_cksum_type_t - receive checksum API types + * @CDF_NBUF_RX_CKSUM_TCP: Rx checksum TCP + * @CDF_NBUF_RX_CKSUM_UDP: Rx checksum UDP + * @CDF_NBUF_RX_CKSUM_TCPIPV6: Rx checksum TCP IPV6 + * @CDF_NBUF_RX_CKSUM_UDPIPV6: Rx checksum UDP IPV6 + * @CDF_NBUF_RX_CKSUM_TCP_NOPSEUDOHEADER: Rx checksum TCP no pseudo header + * @CDF_NBUF_RX_CKSUM_UDP_NOPSEUDOHEADER: Rx checksum UDP no pseudo header + * @CDF_NBUF_RX_CKSUM_TCPSUM16: Rx checksum TCP SUM16 + */ +typedef enum { + CDF_NBUF_RX_CKSUM_TCP = 0x0001, + CDF_NBUF_RX_CKSUM_UDP = 0x0002, + CDF_NBUF_RX_CKSUM_TCPIPV6 = 0x0010, + CDF_NBUF_RX_CKSUM_UDPIPV6 = 0x0020, + CDF_NBUF_RX_CKSUM_TCP_NOPSEUDOHEADER = 0x0100, + CDF_NBUF_RX_CKSUM_UDP_NOPSEUDOHEADER = 0x0200, + CDF_NBUF_RX_CKSUM_TCPSUM16 = 0x1000, +} cdf_nbuf_l4_rx_cksum_type_t; + +/** + * typedef cdf_nbuf_l4_rx_cksum_result_t - receive checksum status types + * @CDF_NBUF_RX_CKSUM_NONE: Device failed to checksum + * @CDF_NBUF_RX_CKSUM_TCP_UDP_HW: TCP/UDP cksum successful and value returned + * @CDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY: TCP/UDP cksum successful, no value + */ +typedef enum { + CDF_NBUF_RX_CKSUM_NONE = 0x0000, + CDF_NBUF_RX_CKSUM_TCP_UDP_HW = 0x0010, + CDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY = 0x0020, +} cdf_nbuf_l4_rx_cksum_result_t; + +/** + * typedef cdf_nbuf_rx_cksum_t - receive checksum type + * @l4_type: L4 type + * @l4_result: L4 result + */ +typedef struct { + cdf_nbuf_l4_rx_cksum_type_t l4_type; + cdf_nbuf_l4_rx_cksum_result_t l4_result; + uint32_t val; +} cdf_nbuf_rx_cksum_t; + +#endif /*_CDF_NET_TYPES_H*/ diff --git a/core/cdf/inc/cdf_softirq_timer.h b/core/cdf/inc/cdf_softirq_timer.h new file mode 100644 index 0000000000..d05a9509f5 --- /dev/null +++ b/core/cdf/inc/cdf_softirq_timer.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_softirq_timer + * This file abstracts OS timers running in soft IRQ context. + */ + +#ifndef _CDF_SOFTIRQ_TIMER_H +#define _CDF_SOFTIRQ_TIMER_H + +#include +#include + +/* Platform timer object */ +typedef __cdf_softirq_timer_t cdf_softirq_timer_t; + +/** + * cdf_softirq_timer_init() - initialize a softirq timer + * @hdl: OS handle + * @timer: Timer object pointer + * @func: Timer function + * @arg: Arguement of timer function + * @type: deferrable or non deferrable timer type + * + * Timer type CDF_TIMER_TYPE_SW means its a deferrable sw timer which will + * not cause CPU wake upon expiry + * Timer type CDF_TIMER_TYPE_WAKE_APPS means its a non-deferrable timer which + * will cause CPU wake up on expiry + * + * Return: none + */ +static inline void +cdf_softirq_timer_init(cdf_handle_t hdl, + cdf_softirq_timer_t *timer, + cdf_softirq_timer_func_t func, void *arg, + CDF_TIMER_TYPE type) +{ + __cdf_softirq_timer_init(hdl, timer, func, arg, type); +} + +/** + * cdf_softirq_timer_start() - start a one-shot softirq timer + * @timer: Timer object pointer + * @msec: Expiration period in milliseconds + * + * Return: none + */ +static inline void +cdf_softirq_timer_start(cdf_softirq_timer_t *timer, int msec) +{ + __cdf_softirq_timer_start(timer, msec); +} + +/** + * cdf_softirq_timer_mod() - modify existing timer to new timeout value + * @timer: Timer object pointer + * @msec: Expiration period in milliseconds + * + * Return: none + */ +static inline void cdf_softirq_timer_mod(cdf_softirq_timer_t *timer, int msec) +{ + __cdf_softirq_timer_mod(timer, msec); +} + +/** + * cdf_softirq_timer_cancel() - cancel cdf softirq timer + * @timer: Timer object pointer + * @retval: Timer was cancelled and deactived + * @retval: Timer was cancelled but already got fired. + * + * The function will return after any running timer completes. + * + * Return: none + */ +static inline bool cdf_softirq_timer_cancel(cdf_softirq_timer_t *timer) +{ + return __cdf_softirq_timer_cancel(timer); +} + +/** + * cdf_softirq_timer_free() - free cdf softirq timer + * @timer: Timer object pointer + * + * The function will return after any running timer completes. + * Return: none + */ +static inline void cdf_softirq_timer_free(cdf_softirq_timer_t *timer) +{ + __cdf_softirq_timer_free(timer); +} + +#endif diff --git a/core/cdf/inc/cdf_status.h b/core/cdf/inc/cdf_status.h new file mode 100644 index 0000000000..635b4ad33b --- /dev/null +++ b/core/cdf/inc/cdf_status.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_STATUS_H) +#define __CDF_STATUS_H + +/** + * DOC: cdf_status + * + * Connectivity driver framework (CDF) status codes + * + * Basic status codes/definitions used by CDF + */ + +/** + * typedef CDF_STATUS - CDF error codes + * @CDF_STATUS_SUCCESS: success + * @CDF_STATUS_E_RESOURCES: system resource(other than memory) not available + * @CDF_STATUS_E_NOMEM: not enough memory + * @CDF_STATUS_E_AGAIN: try again + * @CDF_STATUS_E_INVAL: invalid request + * @CDF_STATUS_E_FAULT: system fault + * @CDF_STATUS_E_ALREADY: another request already in progress + * @CDF_STATUS_E_BADMSG: bad message + * @CDF_STATUS_E_BUSY: device or resource busy + * @CDF_STATUS_E_CANCELED: request cancelled + * @CDF_STATUS_E_ABORTED: request aborted + * @CDF_STATUS_E_NOSUPPORT: request not supported + * @CDF_STATUS_E_PERM: operation not permitted + * @CDF_STATUS_E_EMPTY: empty condition + * @CDF_STATUS_E_EXISTS: existence failure + * @CDF_STATUS_E_TIMEOUT: operation timeout + * @CDF_STATUS_E_FAILURE: unknown reason do not use unless nothign else applies + * @CDF_STATUS_NOT_INITIALIZED: resource not initialized + * @CDF_STATUS_E_NULL_VALUE: request is null + * @CDF_STATUS_PMC_PENDING: request pendign in pmc + * @CDF_STATUS_PMC_DISABLED: pmc is disabled + * @CDF_STATUS_PMC_NOT_NOW: pmc not ready now + * @CDF_STATUS_PMC_AC_POWER: pmc ac power + * @CDF_STATUS_PMC_SYS_ERROR: pmc system error + * @CDF_STATUS_HEARTBEAT_TMOUT: hearbeat timeout error + * @CDF_STATUS_NTH_BEACON_DELIVERY: Nth beacon delivery + * @CDF_STATUS_CSR_WRONG_STATE: csr in wrong state + * @CDF_STATUS_FT_PREAUTH_KEY_SUCCESS: ft preauth key success + * @CDF_STATUS_FT_PREAUTH_KEY_FAILED: ft preauth key failed + * @CDF_STATUS_CMD_NOT_QUEUED: command not queued + * @CDF_STATUS_FW_MSG_TIMEDOUT: target message timeout + * @CDF_STATUS_MAX: not a realy value just a place holder for max + */ +typedef enum { + CDF_STATUS_SUCCESS, + CDF_STATUS_E_RESOURCES, + CDF_STATUS_E_NOMEM, + CDF_STATUS_E_AGAIN, + CDF_STATUS_E_INVAL, + CDF_STATUS_E_FAULT, + CDF_STATUS_E_ALREADY, + CDF_STATUS_E_BADMSG, + CDF_STATUS_E_BUSY, + CDF_STATUS_E_CANCELED, + CDF_STATUS_E_ABORTED, + CDF_STATUS_E_NOSUPPORT, + CDF_STATUS_E_PERM, + CDF_STATUS_E_EMPTY, + CDF_STATUS_E_EXISTS, + CDF_STATUS_E_TIMEOUT, + CDF_STATUS_E_FAILURE, + CDF_STATUS_NOT_INITIALIZED, + CDF_STATUS_E_NULL_VALUE, + CDF_STATUS_PMC_PENDING, + CDF_STATUS_PMC_DISABLED, + CDF_STATUS_PMC_NOT_NOW, + CDF_STATUS_PMC_AC_POWER, + CDF_STATUS_PMC_SYS_ERROR, + CDF_STATUS_HEARTBEAT_TMOUT, + CDF_STATUS_NTH_BEACON_DELIVERY, + CDF_STATUS_CSR_WRONG_STATE, + CDF_STATUS_FT_PREAUTH_KEY_SUCCESS, + CDF_STATUS_FT_PREAUTH_KEY_FAILED, + CDF_STATUS_CMD_NOT_QUEUED, + CDF_STATUS_FW_MSG_TIMEDOUT, + CDF_STATUS_MAX +} CDF_STATUS; + +#define CDF_IS_STATUS_SUCCESS(status) (CDF_STATUS_SUCCESS == (status)) + +#endif /* if !defined __CDF_STATUS_H */ diff --git a/core/cdf/inc/cdf_threads.h b/core/cdf/inc/cdf_threads.h new file mode 100644 index 0000000000..8aa320c50d --- /dev/null +++ b/core/cdf/inc/cdf_threads.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_THREADS_H) +#define __CDF_THREADS_H + +/** + * DOC: cdf_threads + * + * Connectivity driver framework (CDF) thread related APIs + * + */ + +/* Include Files */ +#include + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +/** + * cdf_sleep() - sleep + * @msInterval : Number of milliseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return: nothing + */ +void cdf_sleep(uint32_t msInterval); + +/** + * cdf_sleep_us() - sleep + * @usInterval : Number of microseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return : nothing + */ +void cdf_sleep_us(uint32_t usInterval); + +/** + * cdf_busy_wait() - busy wait + * @usInterval : Number of microseconds to busy wait. + * + * This function places the current thread in busy wait until the specified + * time out interval elapses. If the interval is greater than 50us on WM, the + * behaviour is undefined. + * + * Return : nothing + */ +void cdf_busy_wait(uint32_t usInterval); + +#endif /* __CDF_THREADS_H */ diff --git a/core/cdf/inc/cdf_time.h b/core/cdf/inc/cdf_time.h new file mode 100644 index 0000000000..6f5d1f5214 --- /dev/null +++ b/core/cdf/inc/cdf_time.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_time + * This file abstracts time related functionality. + */ + +#ifndef _CDF_OS_TIME_H +#define _CDF_OS_TIME_H + +#include +#ifdef CONFIG_CNSS +#include +#endif + +typedef __cdf_time_t cdf_time_t; + +/** + * cdf_system_ticks() - Count the number of ticks elapsed from the time when + * the system booted + * + * Return: ticks + */ +static inline unsigned long cdf_system_ticks(void) +{ + return __cdf_system_ticks(); +} + +/** + * cdf_system_ticks_to_msecs() - convert ticks to milliseconds + * @clock_ticks: Number of ticks + * + * Return: Time in milliseconds + */ +static inline uint32_t cdf_system_ticks_to_msecs(unsigned long clock_ticks) +{ + return __cdf_system_ticks_to_msecs(clock_ticks); +} + +/** + * cdf_system_msecs_to_ticks() - convert milliseconds to ticks + * @msec: Time in milliseconds + * + * Return: number of ticks + */ +static inline unsigned long cdf_system_msecs_to_ticks(uint32_t msecs) +{ + return __cdf_system_msecs_to_ticks(msecs); +} + +/** + * cdf_get_system_uptime() - Return a monotonically increasing time. + * This increments once per HZ ticks + * + * Return: system up time + */ +static inline unsigned long cdf_get_system_uptime(void) +{ + return __cdf_get_system_uptime(); +} + +/** + * cdf_get_system_timestamp() - brief Return current timestamp + * + * Return: none + */ +static inline unsigned long cdf_get_system_timestamp(void) +{ + return __cdf_get_system_timestamp(); +} + +/** + * cdf_udelay() - delay in microseconds + * @usecs: Number of microseconds to delay + * + * Return: none + */ +static inline void cdf_udelay(int usecs) +{ + __cdf_udelay(usecs); +} + +/** + * cdf_mdelay() - Delay in milliseconds. + * @msec: Number of milliseconds to delay + * + * Return: none + */ +static inline void cdf_mdelay(int msecs) +{ + __cdf_mdelay(msecs); +} + +/* Check if _a is later than _b */ +#define cdf_system_time_after(_a, _b) __cdf_system_time_after(_a, _b) + +/* Check if _a is prior to _b */ +#define cdf_system_time_before(_a, _b) __cdf_system_time_before(_a, _b) + +/* Check if _a atleast as recent as _b, if not later */ +#define cdf_system_time_after_eq(_a, _b) __cdf_system_time_after_eq(_a, _b) + +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * cdf_get_log_timestamp() - get time stamp for logging + * + * For adrastea this API returns QTIMER tick which is needed to synchronize + * host and fw log timestamps + * + * For ROME and other discrete solution this API returns system boot time stamp + * + * Return: + * QTIMER ticks(19.2MHz) for adrastea + * System tick for rome and other future discrete solutions + */ +static inline uint64_t cdf_get_log_timestamp(void) +{ + return __cdf_get_qtimer_ticks(); +} +#else +/** + * cdf_get_log_timestamp() - get time stamp for logging + * + * For adrastea this API returns QTIMER tick which is needed to synchronize + * host and fw log timestamps + * + * For ROME and other discrete solution this API returns system boot time stamp + * + * Return: + * QTIMER ticks(19.2MHz) for adrastea + * System tick for rome and other future discrete solutions + */ +static inline uint64_t cdf_get_log_timestamp(void) +{ +#ifdef CONFIG_CNSS + struct timespec ts; + + cnss_get_boottime(&ts); + + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +#else + return cdf_system_ticks_to_msecs(cdf_system_ticks()) * 1000; +#endif /* CONFIG_CNSS */ +} +#endif /* QCA_WIFI_3_0_ADRASTEA */ + +/** + * cdf_get_monotonic_boottime() - get monotonic kernel boot time + * This API is similar to cdf_get_system_boottime but it includes + * time spent in suspend. + * + * Return: Time in microseconds + */ +static inline uint64_t cdf_get_monotonic_boottime(void) +{ + return __cdf_get_monotonic_boottime(); +} + +#endif diff --git a/core/cdf/inc/cdf_trace.h b/core/cdf/inc/cdf_trace.h new file mode 100644 index 0000000000..bbf78b9cf6 --- /dev/null +++ b/core/cdf/inc/cdf_trace.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_TRACE_H) +#define __CDF_TRACE_H + +/** + * DOC: cdf_trace + * + * Connectivity driver framework trace APIs + * + * Trace, logging, and debugging definitions and APIs + * + */ + +/* Include Files */ +#include /* For CDF_MODULE_ID... */ +#include /* For va_list... */ +#include +#include +#include +#include + +/* Type declarations */ + +typedef enum { + /* NONE means NO traces will be logged. This value is in place + * for the cdf_trace_setlevel() to allow the user to turn off + * all traces + */ + CDF_TRACE_LEVEL_NONE = 0, + + /* Following trace levels are the ones that 'callers' of CDF_TRACE() + * can specify in for the CDF_TRACE_LEVEL parameter. Traces are + * classified by severity. FATAL being more serious than INFO for + * example + */ + CDF_TRACE_LEVEL_FATAL, + CDF_TRACE_LEVEL_ERROR, + CDF_TRACE_LEVEL_WARN, + CDF_TRACE_LEVEL_INFO, + CDF_TRACE_LEVEL_INFO_HIGH, + CDF_TRACE_LEVEL_INFO_MED, + CDF_TRACE_LEVEL_INFO_LOW, + CDF_TRACE_LEVEL_DEBUG, + + /* All means all trace levels will be active. This value is in place + * for the cdf_trace_setlevel() to allow the user to turn ON all traces + */ + CDF_TRACE_LEVEL_ALL, + + /* Not a real level. Used to identify the maximum number of + * CDF_TRACE_LEVELs defined + */ + CDF_TRACE_LEVEL_MAX +} CDF_TRACE_LEVEL; + +/* By default Data Path module will have all log levels enabled, except debug + * log level. Debug level will be left up to the framework or user space modules + * to be enabled when issue is detected + */ +#define CDF_DATA_PATH_TRACE_LEVEL \ + ((1 << CDF_TRACE_LEVEL_FATAL) | (1 << CDF_TRACE_LEVEL_ERROR) | \ + (1 << CDF_TRACE_LEVEL_WARN) | (1 << CDF_TRACE_LEVEL_INFO) | \ + (1 << CDF_TRACE_LEVEL_INFO_HIGH) | (1 << CDF_TRACE_LEVEL_INFO_MED) | \ + (1 << CDF_TRACE_LEVEL_INFO_LOW)) + +/* Preprocessor definitions and constants */ +#define ASSERT_BUFFER_SIZE (512) + +#define CDF_ENABLE_TRACING +#define MAX_CDF_TRACE_RECORDS 4000 +#define INVALID_CDF_TRACE_ADDR 0xffffffff +#define DEFAULT_CDF_TRACE_DUMP_COUNT 0 + +#include + +#ifdef TRACE_RECORD + +#define MTRACE(p) p +#define NO_SESSION 0xFF + +#else +#define MTRACE(p) { } + +#endif + +/* Structure definition */ +typedef struct cdf_trace_record_s { + uint64_t time; + uint8_t module; + uint8_t code; + uint16_t session; + uint32_t data; + uint32_t pid; +} cdf_trace_record_t, *tp_cdf_trace_record; + +typedef struct s_cdf_trace_data { + /* MTRACE logs are stored in ring buffer where head represents the + * position of first record, tail represents the position of last record + * added till now and num is the count of total record added + */ + uint32_t head; + uint32_t tail; + uint32_t num; + uint16_t numSinceLastDump; + + /* config for controlling the trace */ + uint8_t enable; + /* Dump after number of records reach this number */ + uint16_t dumpCount; +} t_cdf_trace_data; + +#define CASE_RETURN_STRING(str) case ((str)): return (uint8_t *)(# str); + +/* DP Trace Implementation */ +#define DPTRACE(p) p + +#define MAX_CDF_DP_TRACE_RECORDS 4000 +#define CDF_DP_TRACE_RECORD_SIZE 16 +#define INVALID_CDF_DP_TRACE_ADDR 0xffffffff +#define CDF_DP_TRACE_VERBOSITY_HIGH 3 +#define CDF_DP_TRACE_VERBOSITY_MEDIUM 2 +#define CDF_DP_TRACE_VERBOSITY_LOW 1 +#define CDF_DP_TRACE_VERBOSITY_DEFAULT 0 + +/** + * enum CDF_DP_TRACE_ID - Generic ID to identify various events in data path + * @CDF_DP_TRACE_INVALID: Invalid ID + * @CDF_DP_TRACE_DROP_PACKET_RECORD: Dropped packet stored with this id + * @CDF_DP_TRACE_HDD_PACKET_PTR_RECORD: nbuf->data ptr of HDD + * @CDF_DP_TRACE_HDD_PACKET_RECORD: nbuf->data stored with this id + * @CDF_DP_TRACE_CE_PACKET_PTR_RECORD: nbuf->data ptr of CE + * @CDF_DP_TRACE_CE_PACKET_RECORD: nbuf->data stored with this id + * @CDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD: nbuf->data ptr of txrx queue + * @CDF_DP_TRACE_TXRX_PACKET_PTR_RECORD: nbuf->data ptr of txrx + * @CDF_DP_TRACE_HTT_PACKET_PTR_RECORD: nbuf->data ptr of htt + * @CDF_DP_TRACE_HTC_PACKET_PTR_RECORD: nbuf->data ptr of htc + * @CDF_DP_TRACE_HIF_PACKET_PTR_RECORD: nbuf->data ptr of hif + * @CDF_DP_TRACE_HDD_TX_TIMEOUT: hdd tx timeout event + * @CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: hdd tx softap timeout event + * @CDF_DP_TRACE_VDEV_PAUSE: vdev pause event + * @CDF_DP_TRACE_VDEV_UNPAUSE: vdev unpause event + * + */ +enum CDF_DP_TRACE_ID { + CDF_DP_TRACE_INVALID = 0, + CDF_DP_TRACE_DROP_PACKET_RECORD = 1, + CDF_DP_TRACE_HDD_PACKET_PTR_RECORD = 2, + CDF_DP_TRACE_HDD_PACKET_RECORD = 3, + CDF_DP_TRACE_CE_PACKET_PTR_RECORD = 4, + CDF_DP_TRACE_CE_PACKET_RECORD = 5, + CDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD = 6, + CDF_DP_TRACE_TXRX_PACKET_PTR_RECORD = 7, + CDF_DP_TRACE_HTT_PACKET_PTR_RECORD = 8, + CDF_DP_TRACE_HTC_PACKET_PTR_RECORD = 9, + CDF_DP_TRACE_HIF_PACKET_PTR_RECORD = 10, + CDF_DP_TRACE_HDD_TX_TIMEOUT = 11, + CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT = 12, + CDF_DP_TRACE_VDEV_PAUSE = 13, + CDF_DP_TRACE_VDEV_UNPAUSE = 14, + CDF_DP_TRACE_MAX + +}; + +/** + * struct cdf_dp_trace_record_s - Describes a record in DP trace + * @time: time when it got stored + * @code: Describes the particular event + * @data: buffer to store data + * @size: Length of the valid data stored in this record + * @pid : process id which stored the data in this record + */ +struct cdf_dp_trace_record_s { + uint64_t time; + uint8_t code; + uint8_t data[CDF_DP_TRACE_RECORD_SIZE]; + uint8_t size; + uint32_t pid; +}; + +/** + * struct cdf_dp_trace_data - Parameters to configure/control DP trace + * @head: Position of first record + * @tail: Position of last record + * @num: Current index + * @proto_bitmap: defines which protocol to be traced + * @no_of_record: defines every nth packet to be traced + * @verbosity : defines verbosity level + * @enable: enable/disable DP trace + * @count: current packet number + */ +struct s_cdf_dp_trace_data { + uint32_t head; + uint32_t tail; + uint32_t num; + + /* config for controlling the trace */ + uint8_t proto_bitmap; + uint8_t no_of_record; + uint8_t verbosity; + bool enable; + uint32_t count; +}; +/* Function declarations and documenation */ + +/** + * cdf_trace_set_level() - Set the trace level for a particular module + * @level : trace level + * + * Trace level is a member of the CDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * + * This is an external API that allows trace levels to be set for each module. + * + * Return: nothing + */ +void cdf_trace_set_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level); + +/** + * cdf_trace_get_level() - get the trace level + * @level : trace level + * + * This is an external API that returns a bool value to signify if a + * particular trace level is set for the specified module. + * A member of the CDF_TRACE_LEVEL enumeration indicating the severity + * of the condition causing the trace message to be issued. + * + * Note that individual trace levels are the only valid values + * for this API. CDF_TRACE_LEVEL_NONE and CDF_TRACE_LEVEL_ALL + * are not valid input and will return false + * + * Return: + * false - the specified trace level for the specified module is OFF + * true - the specified trace level for the specified module is ON + */ +bool cdf_trace_get_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level); + +typedef void (*tp_cdf_trace_cb)(void *pMac, tp_cdf_trace_record, uint16_t); +void cdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data); +void cdf_trace_register(CDF_MODULE_ID, tp_cdf_trace_cb); +CDF_STATUS cdf_trace_spin_lock_init(void); +void cdf_trace_init(void); +void cdf_trace_enable(uint32_t, uint8_t enable); +void cdf_trace_dump_all(void *, uint8_t, uint8_t, uint32_t, uint32_t); + +void cdf_dp_trace_spin_lock_init(void); +void cdf_dp_trace_init(void); +void cdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_records, + uint8_t verbosity); +void cdf_dp_trace_set_track(cdf_nbuf_t nbuf); +void cdf_dp_trace(cdf_nbuf_t nbuf, enum CDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size); +void cdf_dp_trace_dump_all(uint32_t count); +typedef void (*tp_cdf_dp_trace_cb)(struct cdf_dp_trace_record_s* , uint16_t); +void cdf_dp_display_record(struct cdf_dp_trace_record_s *record, + uint16_t index); +#endif diff --git a/core/cdf/inc/cdf_types.h b/core/cdf/inc/cdf_types.h new file mode 100644 index 0000000000..49099450ce --- /dev/null +++ b/core/cdf/inc/cdf_types.h @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDF_TYPES_H) +#define __CDF_TYPES_H +/** + * DOC: cdf_types.h + * + * Connectivity driver framework (CDF) basic type definitions + */ + +/* Include Files */ +#include "i_cdf_types.h" +#include + +/* Preprocessor definitions and constants */ + +/** + * CDF_MAX - get maximum of two values + * @_x: 1st arguement + * @_y: 2nd arguement + */ +#define CDF_MAX(_x, _y) (((_x) > (_y)) ? (_x) : (_y)) + +/** + * CDF_MIN - get minimum of two values + * @_x: 1st arguement + * @_y: 2nd arguement + */ +#define CDF_MIN(_x, _y) (((_x) < (_y)) ? (_x) : (_y)) + +/** + * CDF_SWAP_U16 - swap input u16 value + * @_x: variable to swap + */ +#define CDF_SWAP_U16(_x) \ + ((((_x) << 8) & 0xFF00) | (((_x) >> 8) & 0x00FF)) + +/** + * CDF_SWAP_U32 - swap input u32 value + * @_x: variable to swap + */ +#define CDF_SWAP_U32(_x) \ + (((((_x) << 24) & 0xFF000000) | (((_x) >> 24) & 0x000000FF)) | \ + ((((_x) << 8) & 0x00FF0000) | (((_x) >> 8) & 0x0000FF00))) + +#define CDF_TICKS_PER_SECOND (1000) + +/** + * CDF_ARRAY_SIZE - get array size + * @_arr: array variable name + */ +#define CDF_ARRAY_SIZE(_arr) (sizeof(_arr) / sizeof((_arr)[0])) + +/* endian operations for Big Endian and Small Endian modes */ +#ifdef ANI_LITTLE_BYTE_ENDIAN + +#define cdf_be16_to_cpu(_x) CDF_SWAP_U16(_x) + +#endif + +#ifdef ANI_BIG_BYTE_ENDIAN + +#define cdf_be16_to_cpu(_x) (_x) + +#endif + +#ifndef __ahdecl +#ifdef __i386__ +#define __ahdecl __attribute__((regparm(0))) +#else +#define __ahdecl +#endif +#endif + +#define CDF_OS_MAX_SCATTER __CDF_OS_MAX_SCATTER + +/** + * @brief denotes structure is packed. + */ +#define cdf_packed __cdf_packed + +/** + * typedef cdf_handle_t - handles opaque to each other + */ +typedef void *cdf_handle_t; + +/** + * typedef cdf_device_t - Platform/bus generic handle. + * Used for bus specific functions. + */ +typedef __cdf_device_t cdf_device_t; + +/** + * typedef cdf_size_t - size of an object + */ +typedef __cdf_size_t cdf_size_t; + +/** + * typedef cdf_dma_map_t - DMA mapping object. + */ +typedef __cdf_dma_map_t cdf_dma_map_t; + +/** + * tyepdef cdf_dma_addr_t - DMA address. + */ +typedef __cdf_dma_addr_t cdf_dma_addr_t; + +/** + * tyepdef cdf_dma_context_t - DMA context. + */ +typedef __cdf_dma_context_t cdf_dma_context_t; + + +#define cdf_iomem_t __cdf_iomem_t; +/** + * typedef enum CDF_TIMER_TYPE - CDF timer type + * @CDF_TIMER_TYPE_SW: Deferrable SW timer it will not cause CPU to wake up + * on expiry + * @CDF_TIMER_TYPE_WAKE_APPS: Non deferrable timer which will cause CPU to + * wake up on expiry + */ +typedef enum { + CDF_TIMER_TYPE_SW, + CDF_TIMER_TYPE_WAKE_APPS +} CDF_TIMER_TYPE; + +/** + * tyepdef cdf_resource_type_t - hw resources + * + * @CDF_RESOURCE_TYPE_MEM: memory resource + * @CDF_RESOURCE_TYPE_IO: io resource + * + * Define the hw resources the OS has allocated for the device + * Note that start defines a mapped area. + */ +typedef enum { + CDF_RESOURCE_TYPE_MEM, + CDF_RESOURCE_TYPE_IO, +} cdf_resource_type_t; + +/** + * tyepdef cdf_resource_t - representation of a h/w resource. + * + * @start: start + * @end: end + * @type: resource type + */ +typedef struct { + uint64_t start; + uint64_t end; + cdf_resource_type_t type; +} cdf_resource_t; + +/** + * typedef cdf_dma_dir_t - DMA directions + * + * @CDF_DMA_BIDIRECTIONAL: bidirectional data + * @CDF_DMA_TO_DEVICE: data going from device to memory + * @CDF_DMA_FROM_DEVICE: data going from memory to device + */ +typedef enum { + CDF_DMA_BIDIRECTIONAL = __CDF_DMA_BIDIRECTIONAL, + CDF_DMA_TO_DEVICE = __CDF_DMA_TO_DEVICE, + CDF_DMA_FROM_DEVICE = __CDF_DMA_FROM_DEVICE, +} cdf_dma_dir_t; + +/* work queue(kernel thread)/DPC function callback */ +typedef void (*cdf_defer_fn_t)(void *); + +/* Prototype of the critical region function that is to be + * executed with spinlock held and interrupt disalbed + */ +typedef bool (*cdf_irqlocked_func_t)(void *); + +/* Prototype of timer function */ +typedef void (*cdf_softirq_timer_func_t)(void *); + +#define cdf_print __cdf_print +#define cdf_vprint __cdf_vprint +#define cdf_snprint __cdf_snprint + +#define cdf_offsetof(type, field) offsetof(type, field) + +/** + * typedef CDF_MODULE_ID - CDF Module IDs + * + * @CDF_MODULE_ID_TLSHIM: TLSHIM module ID + * @CDF_MODULE_ID_WMI: WMI module ID + * @CDF_MODULE_ID_HTT: HTT module ID + * @CDF_MODULE_ID_RSV4: Reserved + * @CDF_MODULE_ID_HDD: HDD module ID + * @CDF_MODULE_ID_SME: SME module ID + * @CDF_MODULE_ID_PE: PE module ID + * @CDF_MODULE_ID_WMA: WMA module ID + * @CDF_MODULE_ID_SYS: SYS module ID + * @CDF_MODULE_ID_CDF: CDF module ID + * @CDF_MODULE_ID_SAP: SAP module ID + * @CDF_MODULE_ID_HDD_SOFTAP: HDD SAP module ID + * @CDF_MODULE_ID_HDD_DATA: HDD DATA module ID + * @CDF_MODULE_ID_HDD_SAP_DATA: HDD SAP DATA module ID + * @CDF_MODULE_ID_HIF: HIF module ID + * @CDF_MODULE_ID_HTC: HTC module ID + * @CDF_MODULE_ID_TXRX: TXRX module ID + * @CDF_MODULE_ID_CDF_DEVICE: CDF DEVICE module ID + * @CDF_MODULE_ID_CFG: CFG module ID + * @CDF_MODULE_ID_BMI: BMI module ID + * @CDF_MODULE_ID_EPPING: EPPING module ID + * @CDF_MODULE_ID_MAX: Max place holder module ID + * + * These are generic IDs that identify the various modules in the software + * system + * 0 is unused for historical purposes + * 3 & 4 are unused for historical purposes + */ +typedef enum { + CDF_MODULE_ID_TLSHIM = 1, + CDF_MODULE_ID_WMI = 2, + CDF_MODULE_ID_HTT = 3, + CDF_MODULE_ID_RSV4 = 4, + CDF_MODULE_ID_HDD = 5, + CDF_MODULE_ID_SME = 6, + CDF_MODULE_ID_PE = 7, + CDF_MODULE_ID_WMA = 8, + CDF_MODULE_ID_SYS = 9, + CDF_MODULE_ID_CDF = 10, + CDF_MODULE_ID_SAP = 11, + CDF_MODULE_ID_HDD_SOFTAP = 12, + CDF_MODULE_ID_HDD_DATA = 14, + CDF_MODULE_ID_HDD_SAP_DATA = 15, + + CDF_MODULE_ID_HIF = 16, + CDF_MODULE_ID_HTC = 17, + CDF_MODULE_ID_TXRX = 18, + CDF_MODULE_ID_CDF_DEVICE = 19, + CDF_MODULE_ID_CFG = 20, + CDF_MODULE_ID_BMI = 21, + CDF_MODULE_ID_EPPING = 22, + + CDF_MODULE_ID_MAX +} CDF_MODULE_ID; + +/** + * typedef enum tCDF_CON_MODE - Concurrency role. + * + * @CDF_STA_MODE: STA mode + * @CDF_SAP_MODE: SAP mode + * @CDF_P2P_CLIENT_MODE: P2P client mode + * @CDF_P2P_GO_MODE: P2P GO mode + * @CDF_FTM_MODE: FTM mode + * @CDF_IBSS_MODE: IBSS mode + * @CDF_P2P_DEVICE_MODE: P2P device mode + * @CDF_EPPING_MODE: EPPING device mode + * @CDF_OCB_MODE: OCB device mode + * @CDF_MAX_NO_OF_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +typedef enum { + CDF_STA_MODE = 0, + CDF_SAP_MODE = 1, + CDF_P2P_CLIENT_MODE, + CDF_P2P_GO_MODE, + CDF_FTM_MODE = 5, + CDF_IBSS_MODE, + CDF_P2P_DEVICE_MODE, + CDF_EPPING_MODE, + CDF_OCB_MODE, + CDF_MAX_NO_OF_MODE +} tCDF_CON_MODE; + +#ifdef WLAN_OPEN_P2P_INTERFACE +/* This should match with WLAN_MAX_INTERFACES */ +#define CDF_MAX_CONCURRENCY_PERSONA (4) +#else +#define CDF_MAX_CONCURRENCY_PERSONA (3) +#endif + +#define CDF_STA_MASK (1 << CDF_STA_MODE) +#define CDF_SAP_MASK (1 << CDF_SAP_MODE) +#define CDF_P2P_CLIENT_MASK (1 << CDF_P2P_CLIENT_MODE) +#define CDF_P2P_GO_MASK (1 << CDF_P2P_GO_MODE) + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef enum { + CDF_MCC_TO_SCC_SWITCH_DISABLE = 0, + CDF_MCC_TO_SCC_SWITCH_ENABLE, + CDF_MCC_TO_SCC_SWITCH_FORCE, + CDF_MCC_TO_SCC_SWITCH_MAX +} tCDF_MCC_TO_SCC_SWITCH_MODE; +#endif + +#if !defined(NULL) +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/* 'Time' type */ +typedef unsigned long v_TIME_t; + +/* typedef for CDF Context... */ +typedef void *v_CONTEXT_t; + +#define CDF_MAC_ADDR_SIZE (6) + +/** + * struct cdf_mac_addr - mac address array + * @bytes: MAC address bytes + */ +struct cdf_mac_addr { + uint8_t bytes[CDF_MAC_ADDR_SIZE]; +}; + +/* This macro is used to initialize a CDF MacAddress to the broadcast + * MacAddress. It is used like this... + * struct cdf_mac_addr macAddress = CDF_MAC_ADDR_BROADCAST_INITIALIZER + */ +#define CDF_MAC_ADDR_BROADCAST_INITIALIZER { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } + +/* This macro is used to initialize a CDF MacAddress to zero + * It is used like this... + * struct cdf_mac_addr macAddress = CDF_MAC_ADDR_ZERO_INITIALIZER + */ +#define CDF_MAC_ADDR_ZERO_INITIALIZER { { 0, 0, 0, 0, 0, 0 } } + +#define CDF_IPV4_ADDR_SIZE (4) + +/** + * struct cdf_tso_frag_t - fragments of a single TCP segment + * @paddr_low_32: Lower 32 bits of the buffer pointer + * @paddr_upper_16: upper 16 bits of the buffer pointer + * @length: length of the buffer + * @vaddr: virtual address + * + * This structure holds the fragments of a single TCP segment of a + * given jumbo TSO network buffer + */ +struct cdf_tso_frag_t { + uint32_t paddr_low_32; + uint32_t paddr_upper_16:16, + length:16; + unsigned char *vaddr; +}; + +#define FRAG_NUM_MAX 6 + +/** + * struct cdf_tso_flags_t - TSO specific flags + * @tso_enable: Enable transmit segmentation offload + * @tcp_flags_mask: Tcp_flag is inserted into the header based + * on the mask + * @l2_len: L2 length for the msdu + * @ip_len: IP length for the msdu + * @tcp_seq_num: TCP sequence number + * @ip_id: IP identification number + * + * This structure holds the TSO specific flags extracted from the TSO network + * buffer for a given TCP segment + */ +struct cdf_tso_flags_t { + u_int32_t tso_enable:1, + reserved_0a:6, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1, + ns:1, + tcp_flags_mask:9, + reserved_0b:7; +/* ------------------------------------------------------------------- */ + + u_int32_t l2_len:16, + ip_len:16; +/* ------------------------------------------------------------------- */ + + u_int32_t tcp_seq_num; +/* ------------------------------------------------------------------- */ + + u_int32_t ip_id:16, + ipv4_checksum_en:1, + udp_ipv4_checksum_en:1, + udp_ipv6_checksum_en:1, + tcp_ipv4_checksum_en:1, + tcp_ipv6_checksum_en:1, + partial_checksum_en:1, + reserved_3a:10; +/* ------------------------------------------------------------------- */ + + u_int32_t checksum_offset:14, + reserved_4a:2, + payload_start_offset:14, + reserved_4b:2; +/* ------------------------------------------------------------------- */ + + u_int32_t payload_end_offset:14, + reserved_5:18; +}; + +/** + * struct cdf_tso_seg_t - single TSO segment + * @tso_flags: TSO flags + * @num_frags: number of fragments + * @tso_frags: array holding the fragments + * + * This structure holds the information of a single TSO segment of a jumbo + * TSO network buffer + */ +struct cdf_tso_seg_t { + struct cdf_tso_flags_t tso_flags; +/* ------------------------------------------------------------------- */ + uint32_t num_frags; + struct cdf_tso_frag_t tso_frags[FRAG_NUM_MAX]; +}; + +struct cdf_tso_seg_elem_t { + struct cdf_tso_seg_t seg; + struct cdf_tso_seg_elem_t *next; +}; + +/** + * struct cdf_tso_info_t - TSO information extracted + * @is_tso: is this is a TSO frame + * @num_segs: number of segments + * @total_len: total length of the packet + * @tso_seg_list: list of TSO segments for this jumbo packet + * @curr_seg: segment that is currently being processed + * + * This structure holds the TSO information extracted after parsing the TSO + * jumbo network buffer. It contains a chain of the TSO segments belonging to + * the jumbo packet + */ +struct cdf_tso_info_t { + uint8_t is_tso; + uint32_t num_segs; + uint32_t total_len; + struct cdf_tso_seg_elem_t *tso_seg_list; + struct cdf_tso_seg_elem_t *curr_seg; +}; + +/** + * Used to set classify bit in CE desc. + */ +#define CDF_CE_TX_CLASSIFY_BIT_S 5 + +/** + * 2 bits starting at bit 6 in CE desc. + */ +#define CDF_CE_TX_PKT_TYPE_BIT_S 6 + +/** + * 12 bits --> 16-27, in the CE desciptor, the length of HTT/HTC descriptor + */ +#define CDF_CE_TX_PKT_OFFSET_BIT_S 16 + +/** + * Mask for packet offset in the CE descriptor. + */ +#define CDF_CE_TX_PKT_OFFSET_BIT_M 0x0fff0000 + +#endif /* if !defined __CDF_TYPES_H */ diff --git a/core/cdf/inc/cdf_util.h b/core/cdf/inc/cdf_util.h new file mode 100644 index 0000000000..c00ac56483 --- /dev/null +++ b/core/cdf/inc/cdf_util.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_util.h + * + * This file defines utility functions. + */ + +#ifndef _CDF_UTIL_H +#define _CDF_UTIL_H + +#include + +/** + * cdf_unlikely - Compiler-dependent macro denoting code likely to execute + * @_expr: expression to be checked + */ +#define cdf_unlikely(_expr) __cdf_unlikely(_expr) + +/** + * cdf_likely - Compiler-dependent macro denoting code unlikely to execute + * @_expr: expression to be checked + */ +#define cdf_likely(_expr) __cdf_likely(_expr) + +CDF_INLINE_FN int cdf_status_to_os_return(CDF_STATUS status) +{ + return __cdf_status_to_os_return(status); +} + +/** + * cdf_assert - assert "expr" evaluates to false + * @expr: assert expression + */ +#ifdef CDF_OS_DEBUG +#define cdf_assert(expr) __cdf_assert(expr) +#else +#define cdf_assert(expr) +#endif /* CDF_OS_DEBUG */ + +/** + * @cdf_assert_always- alway assert "expr" evaluates to false + * @expr: assert expression + */ +#define cdf_assert_always(expr) __cdf_assert(expr) + +/** + * cdf_os_cpu_to_le64 - Convert a 64-bit value from CPU byte order to + * little-endian byte order + * @x: value to be converted + */ +#define cdf_os_cpu_to_le64(x) __cdf_os_cpu_to_le64(x) + +/** + * cdf_le16_to_cpu - Convert a 16-bit value from little-endian byte order + * to CPU byte order + * @x: value to be converted + */ +#define cdf_le16_to_cpu(x) __cdf_le16_to_cpu(x) + +/** + * cdf_le32_to_cpu - Convert a 32-bit value from little-endian byte order to + * CPU byte order + * @x: value to be converted + */ +#define cdf_le32_to_cpu(x) __cdf_le32_to_cpu(x) + +/** + * cdf_in_interrupt - returns true if in interrupt context + */ +#define cdf_in_interrupt in_interrupt + +/** + * cdf_container_of - cast a member of a structure out to the containing + * structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define cdf_container_of(ptr, type, member) \ + __cdf_container_of(ptr, type, member) + +/** + * cdf_is_macaddr_equal() - compare two CDF MacAddress + * @pMacAddr1: Pointer to one cdf MacAddress to compare + * @pMacAddr2: Pointer to the other cdf MacAddress to compare + * + * This function returns a bool that tells if a two CDF MacAddress' + * are equivalent. + * + * Return: true if the MacAddress's are equal + * not true if the MacAddress's are not equal + */ +CDF_INLINE_FN bool cdf_is_macaddr_equal(struct cdf_mac_addr *pMacAddr1, + struct cdf_mac_addr *pMacAddr2) +{ + return 0 == memcmp(pMacAddr1, pMacAddr2, CDF_MAC_ADDR_SIZE); +} + +/** + * cdf_is_macaddr_zero() - check for a MacAddress of all zeros. + * @pMacAddr - pointer to the struct cdf_mac_addr to check. + * + * This function returns a bool that tells if a MacAddress is made up of + * all zeros. + * + * + * Return: true if the MacAddress is all Zeros + * flase if the MacAddress is not all Zeros. + * + */ +CDF_INLINE_FN bool cdf_is_macaddr_zero(struct cdf_mac_addr *pMacAddr) +{ + struct cdf_mac_addr zeroMacAddr = CDF_MAC_ADDR_ZERO_INITIALIZER; + + return cdf_is_macaddr_equal(pMacAddr, &zeroMacAddr); +} + +/** + * cdf_zero_macaddr() - zero out a MacAddress + * @pMacAddr: pointer to the struct cdf_mac_addr to zero. + * + * This function zeros out a CDF MacAddress type. + * + * Return: nothing + */ +CDF_INLINE_FN void cdf_zero_macaddr(struct cdf_mac_addr *pMacAddr) +{ + memset(pMacAddr, 0, CDF_MAC_ADDR_SIZE); +} + +/** + * cdf_is_macaddr_group() - check for a MacAddress is a 'group' address + * @pMacAddr1: pointer to the cdf MacAddress to check + * + * This function returns a bool that tells if a the input CDF MacAddress + * is a "group" address. Group addresses have the 'group address bit' turned + * on in the MacAddress. Group addresses are made up of Broadcast and + * Multicast addresses. + * + * Return: true if the input MacAddress is a Group address + * false if the input MacAddress is not a Group address + */ +CDF_INLINE_FN bool cdf_is_macaddr_group(struct cdf_mac_addr *pMacAddr) +{ + return pMacAddr->bytes[0] & 0x01; +} + +/** + * cdf_is_macaddr_broadcast() - check for a MacAddress is a broadcast address + * + * This function returns a bool that tells if a the input CDF MacAddress + * is a "broadcast" address. + * + * @pMacAddr: Pointer to the cdf MacAddress to check + * + * Return: true if the input MacAddress is a broadcast address + * flase if the input MacAddress is not a broadcast address + */ +CDF_INLINE_FN bool cdf_is_macaddr_broadcast(struct cdf_mac_addr *pMacAddr) +{ + struct cdf_mac_addr broadcastMacAddr = + CDF_MAC_ADDR_BROADCAST_INITIALIZER; + + return cdf_is_macaddr_equal(pMacAddr, &broadcastMacAddr); +} + +/** + * cdf_copy_macaddr() - copy a CDF MacAddress + * @pDst - pointer to the cdf MacAddress to copy TO (the destination) + * @pSrc - pointer to the cdf MacAddress to copy FROM (the source) + * + * This function copies a CDF MacAddress into another CDF MacAddress. + * + * + * Return: nothing + */ +CDF_INLINE_FN void cdf_copy_macaddr(struct cdf_mac_addr *pDst, + struct cdf_mac_addr *pSrc) +{ + *pDst = *pSrc; +} + +/** + * cdf_set_macaddr_broadcast() - set a CDF MacAddress to the 'broadcast' + * @pMacAddr: pointer to the cdf MacAddress to set to broadcast + * + * This function sets a CDF MacAddress to the 'broadcast' MacAddress. Broadcast + * MacAddress contains all 0xFF bytes. + * + * Return: nothing + */ +CDF_INLINE_FN void cdf_set_macaddr_broadcast(struct cdf_mac_addr *pMacAddr) +{ + memset(pMacAddr, 0xff, CDF_MAC_ADDR_SIZE); +} + +#if defined(ANI_LITTLE_BYTE_ENDIAN) + +/** + * i_cdf_htonl() - convert from host byte order to network byte order + * @ul: input to be converted + * + * Return: converted network byte order + */ +CDF_INLINE_FN unsigned long i_cdf_htonl(unsigned long ul) +{ + return ((ul & 0x000000ff) << 24) | + ((ul & 0x0000ff00) << 8) | + ((ul & 0x00ff0000) >> 8) | ((ul & 0xff000000) >> 24); +} + +/** + * i_cdf_ntohl() - convert network byte order to host byte order + * @ul: input to be converted + * + * Return: converted host byte order + */ +CDF_INLINE_FN unsigned long i_cdf_ntohl(unsigned long ul) +{ + return i_cdf_htonl(ul); +} + +#endif + +/** + * cdf_set_u16() - Assign 16-bit unsigned value to a byte array base on CPU's + * endianness. + * @ptr: Starting address of a byte array + * @value: The value to assign to the byte array + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +CDF_INLINE_FN uint8_t *cdf_set_u16(uint8_t *ptr, uint16_t value) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *(ptr) = (uint8_t) (value >> 8); + *(ptr + 1) = (uint8_t) (value); +#else + *(ptr + 1) = (uint8_t) (value >> 8); + *(ptr) = (uint8_t) (value); +#endif + + return ptr + 2; +} + +/** + * cdf_get_u16() - Retrieve a 16-bit unsigned value from a byte array base on + * CPU's endianness. + * @ptr: Starting address of a byte array + * @pValue: Pointer to a caller allocated buffer for 16 bit value. Value is to + * assign to this location. + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +CDF_INLINE_FN uint8_t *cdf_get_u16(uint8_t *ptr, uint16_t *pValue) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *pValue = (((uint16_t) (*ptr << 8)) | ((uint16_t) (*(ptr + 1)))); +#else + *pValue = (((uint16_t) (*(ptr + 1) << 8)) | ((uint16_t) (*ptr))); +#endif + + return ptr + 2; +} + +/** + * cdf_get_u32() - retrieve a 32-bit unsigned value from a byte array base on + * CPU's endianness. + * @ptr: Starting address of a byte array + * @pValue: Pointer to a caller allocated buffer for 32 bit value. Value is to + * assign to this location. + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +CDF_INLINE_FN uint8_t *cdf_get_u32(uint8_t *ptr, uint32_t *pValue) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *pValue = ((uint32_t) (*(ptr) << 24) | + (uint32_t) (*(ptr + 1) << 16) | + (uint32_t) (*(ptr + 2) << 8) | (uint32_t) (*(ptr + 3))); +#else + *pValue = ((uint32_t) (*(ptr + 3) << 24) | + (uint32_t) (*(ptr + 2) << 16) | + (uint32_t) (*(ptr + 1) << 8) | (uint32_t) (*(ptr))); +#endif + return ptr + 4; +} + +#endif /*_CDF_UTIL_H*/ diff --git a/core/cdf/inc/osdep.h b/core/cdf/inc/osdep.h new file mode 100644 index 0000000000..a14a653905 --- /dev/null +++ b/core/cdf/inc/osdep.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OSDEP_H +#define _OSDEP_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + * enum ath_hal_bus_type - Supported Bus types + * @HAL_BUS_TYPE_PCI: PCI Bus + * @HAL_BUS_TYPE_AHB: AHB Bus + * @HAL_BUS_TYPE_SNOC: SNOC Bus + * @HAL_BUS_TYPE_SIM: Simulator + */ +enum ath_hal_bus_type { + HAL_BUS_TYPE_PCI, + HAL_BUS_TYPE_AHB, + HAL_BUS_TYPE_SNOC, + HAL_BUS_TYPE_SIM +}; + +/** + * sturct hal_bus_context - Bus to hal context handoff + * @bc_tag: bus context tag + * @bc_handle: bus context handle + * @bc_bustype: bus type + */ +typedef struct hal_bus_context { + int bc_tag; + char *bc_handle; + enum ath_hal_bus_type bc_bustype; +} HAL_BUS_CONTEXT; + +#define INLINE inline + +/* ATH_DEBUG - + * Control whether debug features (printouts, assertions) are compiled + * into the driver. + */ +#ifndef ATH_DEBUG +#define ATH_DEBUG 1 /* default: include debug code */ +#endif + +#if ATH_DEBUG +#ifndef ASSERT +#define ASSERT(expr) cdf_assert(expr) +#endif +#else +#define ASSERT(expr) +#endif /* ATH_DEBUG */ + +/* + * Need to define byte order based on the CPU configuration. + */ +#ifndef _LITTLE_ENDIAN +#define _LITTLE_ENDIAN 1234 +#endif +#ifndef _BIG_ENDIAN +#define _BIG_ENDIAN 4321 +#endif +#ifdef __BIG_ENDIAN +#define _BYTE_ORDER _BIG_ENDIAN +#else +#define _BYTE_ORDER _LITTLE_ENDIAN +#endif + +/* + * Deduce if tasklets are available. If not then + * fall back to using the immediate work queue. + */ +#define ath_sysctl_decl(f, ctl, write, filp, buffer, lenp, ppos) \ + f(struct ctl_table *ctl, int write, void *buffer, \ + size_t *lenp, loff_t *ppos) +#define ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \ + proc_dointvec(ctl, write, buffer, lenp, ppos) +#define ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \ + proc_dostring(ctl, write, filp, buffer, lenp, ppos) + +/* + * Byte Order stuff + */ +#define le16toh(_x) le16_to_cpu(_x) +#define htole16(_x) cpu_to_le16(_x) +#define htobe16(_x) cpu_to_be16(_x) +#define le32toh(_x) le32_to_cpu(_x) +#define htole32(_x) cpu_to_le32(_x) +#define be16toh(_x) be16_to_cpu(_x) +#define be32toh(_x) be32_to_cpu(_x) +#define htobe32(_x) cpu_to_be32(_x) + +#define EOK (0) + +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 /* IEEE 802.11. */ +#endif + +/* + * Normal Delay functions. Time specified in microseconds. + */ +#define OS_DELAY(_us) cdf_udelay(_us) + +/* + * memory data manipulation functions. + */ +#define OS_MEMCPY(_dst, _src, _len) cdf_mem_copy(_dst, _src, _len) +#define OS_MEMMOVE(_dst, _src, _len) cdf_mem_move(_dst, _src, _len) +#define OS_MEMZERO(_buf, _len) cdf_mem_zero(_buf, _len) +#define OS_MEMSET(_buf, _ch, _len) cdf_mem_set(_buf, _len, _ch) +#define OS_MEMCMP(_mem1, _mem2, _len) cdf_mem_compare(_mem1, _mem2, _len) + +#ifdef CONFIG_SMP +/* Undo the one provided by the kernel to debug spin locks */ +#undef spin_lock +#undef spin_unlock +#undef spin_trylock + +#define spin_lock(x) \ + do { \ + spin_lock_bh(x); \ + } while (0) + +#define spin_unlock(x) \ + do { \ + if (!spin_is_locked(x)) { \ + WARN_ON(1); \ + printk(KERN_EMERG " %s:%d unlock addr=%p, %s \n", __func__, __LINE__, x, \ + !spin_is_locked(x) ? "Not locked" : ""); \ + } \ + spin_unlock_bh(x); \ + } while (0) + +#define spin_trylock(x) spin_trylock_bh(x) + +#define OS_SUPPORT_ASYNC_Q 1 /* support for handling asyn function calls */ + +#else +#define OS_SUPPORT_ASYNC_Q 0 +#endif /* ifdef CONFIG_SMP */ + + +/* + * System time interface + */ +typedef cdf_time_t systime_t; +typedef cdf_time_t systick_t; + +static INLINE cdf_time_t os_get_timestamp(void) +{ + return cdf_system_ticks(); /* Fix double conversion from jiffies to ms */ +} + +struct _NIC_DEV; + +typedef struct _NIC_DEV *osdev_t; + +typedef struct timer_list os_timer_t; + +typedef struct _os_mesg_t { + STAILQ_ENTRY(_os_mesg_t) mesg_next; + uint16_t mesg_type; + uint16_t mesg_len; + /* followed by mesg_len bytes */ +} os_mesg_t; + +typedef void (*os_mesg_handler_t)(void *ctx, + uint16_t mesg_type, + uint16_t mesg_len, void *mesg); + +typedef struct { + osdev_t dev_handle; + int32_t num_queued; + int32_t mesg_len; + uint8_t *mesg_queue_buf; + STAILQ_HEAD(, _os_mesg_t) mesg_head; /* queued mesg buffers */ + STAILQ_HEAD(, _os_mesg_t) mesg_free_head; /* free mesg buffers */ + spinlock_t lock; + spinlock_t ev_handler_lock; +#ifdef USE_SOFTINTR + void *_task; +#else + os_timer_t _timer; +#endif + os_mesg_handler_t handler; + void *ctx; + uint8_t is_synchronous : 1; +} os_mesg_queue_t; + +/* + * Definition of OS-dependent device structure. + * It'll be opaque to the actual ATH layer. + */ +struct _NIC_DEV { + void *bdev; /* bus device handle */ + struct net_device *netdev; /* net device handle (wifi%d) */ + cdf_bh_t intr_tq; /* tasklet */ + struct net_device_stats devstats; /* net device statisitics */ + HAL_BUS_CONTEXT bc; +#ifdef ATH_PERF_PWR_OFFLOAD + struct device *device; /* generic device */ + wait_queue_head_t event_queue; +#endif /* PERF_PWR_OFFLOAD */ +#if OS_SUPPORT_ASYNC_Q + os_mesg_queue_t async_q; /* mesgq to handle async calls */ +#endif +#ifdef ATH_BUS_PM + uint8_t isDeviceAsleep; +#endif /* ATH_BUS_PM */ +}; + +static INLINE unsigned char *os_malloc(osdev_t pNicDev, + unsigned long ulSizeInBytes, int gfp) +{ + return cdf_mem_malloc(ulSizeInBytes); +} + +#define OS_FREE(_p) cdf_mem_free(_p) + +#define OS_DMA_MEM_CONTEXT(context) \ + dma_addr_t context; + +#define OS_GET_DMA_MEM_CONTEXT(var, field) \ + &(var->field) + +#define OS_COPY_DMA_MEM_CONTEXT(dst, src) \ + *dst = *src + +#define OS_ZERO_DMA_MEM_CONTEXT(context) \ + *context = 0 + +/* + * Timer Interfaces. Use these macros to declare timer + * and retrieve timer argument. This is mainly for resolving + * different argument types for timer function in different OS. + */ +#define OS_DECLARE_TIMER(_fn) void _fn(void *) + +#define os_timer_func(_fn) \ + void _fn(void *timer_arg) + +#define OS_GET_TIMER_ARG(_arg, _type) \ + (_arg) = (_type)(timer_arg) + +#define OS_INIT_TIMER(_osdev, _timer, _fn, _ctx, type) \ + cdf_softirq_timer_init(_osdev, _timer, _fn, _ctx, type) + +#define OS_SET_TIMER(_timer, _ms) cdf_softirq_timer_mod(_timer, _ms) + +#define OS_CANCEL_TIMER(_timer) cdf_softirq_timer_cancel(_timer) + +#define OS_FREE_TIMER(_timer) cdf_softirq_timer_cancel(_timer) + +/* + * These are required for network manager support + */ +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(ndev, pdev) +#endif + +#endif /* end of _OSDEP_H */ diff --git a/core/cdf/src/cdf_defer.c b/core/cdf/src/cdf_defer.c new file mode 100644 index 0000000000..061f3c5b99 --- /dev/null +++ b/core/cdf/src/cdf_defer.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include + +#include "i_cdf_defer.h" + +/** + * __cdf_defer_func() - defer work handler + * @work: Pointer to defer work + * + * Return: none + */ +void __cdf_defer_func(struct work_struct *work) +{ + __cdf_work_t *ctx = container_of(work, __cdf_work_t, work); + if (ctx->fn == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "No callback registered !!"); + return; + } + ctx->fn(ctx->arg); +} diff --git a/core/cdf/src/cdf_event.c b/core/cdf/src/cdf_event.c new file mode 100644 index 0000000000..ce39b48546 --- /dev/null +++ b/core/cdf/src/cdf_event.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_event.c + * + * This source file contains linux specific definitions for CDF event APIs + * The APIs mentioned in this file are used for initializing, setting, + * resetting, destroying an event and waiting on an occurance of an event + * among multiple events. + */ + +/* Include Files */ +#include "cdf_event.h" +#include "cdf_trace.h" + +/* Preprocessor Definitions and Constants */ + +/* Type Declarations */ + +/* Global Data Definitions */ + +/* Static Variable Definitions */ + +/* Function Definitions and Documentation */ + +/** + * cdf_event_init() - initializes a CDF event + * @event: Pointer to the opaque event object to initialize + * + * The cdf_event_init() function initializes the specified event. Upon + * successful initialization, the state of the event becomes initialized + * and not signaled. + * + * An event must be initialized before it may be used in any other event + * functions. + * + * Attempting to initialize an already initialized event results in + * a failure. + * + * Return: CDF status + */ +CDF_STATUS cdf_event_init(cdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "NULL event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check for 'already initialized' event */ + if (LINUX_EVENT_COOKIE == event->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Initialized event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_BUSY; + } + + /* initialize new event */ + init_completion(&event->complete); + event->cookie = LINUX_EVENT_COOKIE; + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_event_set() - sets a CDF event + * @event: The event to set to the signalled state + * + * The state of the specified event is set to signalled by calling + * cdf_event_set(). + * + * Any threads waiting on the event as a result of a cdf_event_wait() will + * be unblocked and available to be scheduled for execution when the event + * is signaled by a call to cdf_event_set(). + * + * + * Return: CDF status + */ + +CDF_STATUS cdf_event_set(cdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "NULL event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check if event refers to an initialized object */ + if (LINUX_EVENT_COOKIE != event->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Uninitialized event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + complete(&event->complete); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_event_reset() - resets a CDF event + * @event: The event to set to the NOT signalled state + * + * This function isn't required for Linux. Therefore, it doesn't do much. + * + * The state of the specified event is set to 'NOT signalled' by calling + * cdf_event_reset(). The state of the event remains NOT signalled until an + * explicit call to cdf_event_set(). + * + * This function sets the event to a NOT signalled state even if the event was + * signalled multiple times before being signaled. + * + * + * Return: CDF status + */ +CDF_STATUS cdf_event_reset(cdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "NULL event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check to make sure it is an 'already initialized' event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Uninitialized event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + /* (re)initialize event */ + INIT_COMPLETION(event->complete); + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_event_destroy() - Destroys a CDF event + * @event: The event object to be destroyed. + * + * This function doesn't do much in Linux. There is no need for the caller + * to explicitly destroy an event after use. + * + * The os_event_destroy() function shall destroy the event object + * referenced by event. After a successful return from cdf_event_destroy() + * the event object becomes, in effect, uninitialized. + * + * A destroyed event object can be reinitialized using cdf_event_init(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to CDF event functions to manipulate the lock such + * as cdf_event_set() will fail if the event is destroyed. Therefore, + * don't use the event after it has been destroyed until it has + * been re-initialized. + * + * Return: CDF status + */ + +CDF_STATUS cdf_event_destroy(cdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "NULL event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check to make sure it is an 'already initialized' event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Uninitialized event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + /* make sure nobody is waiting on the event */ + complete_all(&event->complete); + + /* destroy the event */ + memset(event, 0, sizeof(cdf_event_t)); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wait_single_event() - Waits for a single event to be set. + * + * This API waits for the event to be set. + * + * @pEvent: Pointer to an event to wait on. + * @timeout: Timeout value (in milliseconds). This function returns + * if this interval elapses, regardless if any of the events have + * been set. An input value of 0 for this timeout parameter means + * to wait infinitely, meaning a timeout will never occur. + * + * Return: CDF status + */ +CDF_STATUS cdf_wait_single_event(cdf_event_t *event, uint32_t timeout) +{ + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s cannot be called from interrupt context!!!", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check for null pointer */ + if (NULL == event) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "NULL event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check if cookie is same as that of initialized event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Uninitialized event passed into %s", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + if (timeout) { + long ret; + ret = wait_for_completion_timeout(&event->complete, + msecs_to_jiffies(timeout)); + if (0 >= ret) + return CDF_STATUS_E_TIMEOUT; + } else { + CDF_ASSERT(0); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Zero timeout value passed into %s", __func__); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} diff --git a/core/cdf/src/cdf_list.c b/core/cdf/src/cdf_list.c new file mode 100644 index 0000000000..1d60f9e210 --- /dev/null +++ b/core/cdf/src/cdf_list.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_list.c + * + * Connectivity driver framework list manipulation APIs. CDF linked list + * APIs are NOT thread safe so make sure to use appropriate locking mechanisms + * to assure operations on the list are thread safe. + */ + +/* Include files */ +#include +#include + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +/** + * cdf_list_insert_front() - insert input node at front of the list + * @pList: Pointer to list + * @pNode: Pointer to input node + * + * Return: CDF status + */ +CDF_STATUS cdf_list_insert_front(cdf_list_t *pList, cdf_list_node_t *pNode) +{ + list_add(pNode, &pList->anchor); + pList->count++; + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_insert_back() - insert input node at back of the list + * @pList: Pointer to list + * @pNode: Pointer to input node + * + * Return: CDF status + */ +CDF_STATUS cdf_list_insert_back(cdf_list_t *pList, cdf_list_node_t *pNode) +{ + list_add_tail(pNode, &pList->anchor); + pList->count++; + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_insert_back_size() - insert input node at back of list and save + * list size + * @pList: Pointer to list + * @pNode: Pointer to input node + * @pSize: Pointer to store list size + * + * Return: CDF status + */ +CDF_STATUS cdf_list_insert_back_size(cdf_list_t *pList, + cdf_list_node_t *pNode, uint32_t *pSize) +{ + list_add_tail(pNode, &pList->anchor); + pList->count++; + *pSize = pList->count; + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_remove_front() - remove node from front of the list + * @pList: Pointer to list + * @ppNode: Double pointer to store the node which is removed from list + * + * Return: CDF status + */ +CDF_STATUS cdf_list_remove_front(cdf_list_t *pList, cdf_list_node_t **ppNode) +{ + struct list_head *listptr; + + if (list_empty(&pList->anchor)) + return CDF_STATUS_E_EMPTY; + + listptr = pList->anchor.next; + *ppNode = listptr; + list_del(pList->anchor.next); + pList->count--; + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_remove_back() - remove node from end of the list + * @pList: Pointer to list + * @ppNode: Double pointer to store node which is removed from list + * + * Return: CDF status + */ +CDF_STATUS cdf_list_remove_back(cdf_list_t *pList, cdf_list_node_t **ppNode) +{ + struct list_head *listptr; + + if (list_empty(&pList->anchor)) + return CDF_STATUS_E_EMPTY; + + listptr = pList->anchor.prev; + *ppNode = listptr; + list_del(pList->anchor.prev); + pList->count--; + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_remove_node() - remove input node from list + * @pList: Pointer to list + * @pNodeToRemove: Pointer to node which needs to be removed + * + * Return: CDF status + */ +CDF_STATUS cdf_list_remove_node(cdf_list_t *pList, + cdf_list_node_t *pNodeToRemove) +{ + cdf_list_node_t *tmp; + int found = 0; + + if (list_empty(&pList->anchor)) + return CDF_STATUS_E_EMPTY; + + /* verify that pNodeToRemove is indeed part of list pList */ + list_for_each(tmp, &pList->anchor) { + if (tmp == pNodeToRemove) { + found = 1; + break; + } + } + if (found == 0) + return CDF_STATUS_E_INVAL; + + list_del(pNodeToRemove); + pList->count--; + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_peek_front() - peek front node from list + * @pList: Pointer to list + * @ppNode: Double pointer to store peeked node pointer + * + * Return: CDF status + */ +CDF_STATUS cdf_list_peek_front(cdf_list_t *pList, cdf_list_node_t **ppNode) +{ + struct list_head *listptr; + if (list_empty(&pList->anchor)) + return CDF_STATUS_E_EMPTY; + + listptr = pList->anchor.next; + *ppNode = listptr; + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_list_peek_next() - peek next node of input node in the list + * @pList: Pointer to list + * @pNode: Pointer to input node + * @ppNode: Double pointer to store peeked node pointer + * + * Return: CDF status + */ +CDF_STATUS cdf_list_peek_next(cdf_list_t *pList, cdf_list_node_t *pNode, + cdf_list_node_t **ppNode) +{ + struct list_head *listptr; + int found = 0; + cdf_list_node_t *tmp; + + if ((pList == NULL) || (pNode == NULL) || (ppNode == NULL)) + return CDF_STATUS_E_FAULT; + + if (list_empty(&pList->anchor)) + return CDF_STATUS_E_EMPTY; + + /* verify that pNode is indeed part of list pList */ + list_for_each(tmp, &pList->anchor) { + if (tmp == pNode) { + found = 1; + break; + } + } + + if (found == 0) + return CDF_STATUS_E_INVAL; + + listptr = pNode->next; + if (listptr == &pList->anchor) + return CDF_STATUS_E_EMPTY; + + *ppNode = listptr; + + return CDF_STATUS_SUCCESS; +} diff --git a/core/cdf/src/cdf_lock.c b/core/cdf/src/cdf_lock.c new file mode 100644 index 0000000000..283cd510cd --- /dev/null +++ b/core/cdf/src/cdf_lock.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_lock.c + * + * OVERVIEW: This source file contains definitions for CDF lock APIs + * The four APIs mentioned in this file are used for + * initializing, acquiring, releasing and destroying a lock. + * the lock are implemented using critical sections + */ + +/* Include Files */ + +#include "cdf_lock.h" +#include "cdf_memory.h" +#include "cdf_trace.h" +#include +#ifdef CONFIG_CNSS +#include +#endif +#include "i_host_diag_core_event.h" +#include "cds_api.h" +#include "ani_global.h" + +/* Preprocessor Definitions and Constants */ +#define LINUX_LOCK_COOKIE 0x12345678 + +#define WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT 0 +#define WIFI_POWER_EVENT_WAKELOCK_TAKEN 0 +#define WIFI_POWER_EVENT_WAKELOCK_RELEASED 1 + +/* Type Declarations */ + +enum { + LOCK_RELEASED = 0x11223344, + LOCK_ACQUIRED, + LOCK_DESTROYED +}; + +/* Global Data Definitions */ + +/* Function Definitions and Documentation */ + +/** + * cdf_mutex_init() - initialize a CDF lock + * @lock: Pointer to the opaque lock object to initialize + * + * cdf_mutex_init() function initializes the specified lock. Upon + * successful initialization, the state of the lock becomes initialized + * and unlocked. + * + * A lock must be initialized by calling cdf_mutex_init() before it + * may be used in any other lock functions. + * + * Attempting to initialize an already initialized lock results in + * a failure. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_init(cdf_mutex_t *lock) +{ + /* check for invalid pointer */ + if (lock == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + return CDF_STATUS_E_FAULT; + } + /* check for 'already initialized' lock */ + if (LINUX_LOCK_COOKIE == lock->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: already initialized lock", __func__); + return CDF_STATUS_E_BUSY; + } + + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return CDF_STATUS_E_FAULT; + } + + /* initialize new lock */ + mutex_init(&lock->m_lock); + lock->cookie = LINUX_LOCK_COOKIE; + lock->state = LOCK_RELEASED; + lock->processID = 0; + lock->refcount = 0; + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_mutex_acquire() - acquire a CDF lock + * @lock: Pointer to the opaque lock object to acquire + * + * A lock object is acquired by calling cdf_mutex_acquire(). If the lock + * is already locked, the calling thread shall block until the lock becomes + * available. This operation shall return with the lock object referenced by + * lock in the locked state with the calling thread as its owner. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_acquire(cdf_mutex_t *lock) +{ + int rc; + /* check for invalid pointer */ + if (lock == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + /* check if lock refers to an initialized object */ + if (LINUX_LOCK_COOKIE != lock->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + if ((lock->processID == current->pid) && + (lock->state == LOCK_ACQUIRED)) { + lock->refcount++; +#ifdef CDF_NESTED_LOCK_DEBUG + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: %x %d %d", __func__, lock, current->pid, + lock->refcount); +#endif + return CDF_STATUS_SUCCESS; + } + /* acquire a Lock */ + mutex_lock(&lock->m_lock); + rc = mutex_is_locked(&lock->m_lock); + if (rc == 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: unable to lock mutex (rc = %d)", __func__, rc); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } +#ifdef CDF_NESTED_LOCK_DEBUG + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: %x %d", __func__, lock, current->pid); +#endif + if (LOCK_DESTROYED != lock->state) { + lock->processID = current->pid; + lock->refcount++; + lock->state = LOCK_ACQUIRED; + return CDF_STATUS_SUCCESS; + } else { + /* lock is already destroyed */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Lock is already destroyed", __func__); + mutex_unlock(&lock->m_lock); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } +} + +/** + * cdf_mutex_release() - release a CDF lock + * @lock: Pointer to the opaque lock object to be released + * + * cdf_mutex_release() function shall release the lock object + * referenced by 'lock'. + * + * If a thread attempts to release a lock that it unlocked or is not + * initialized, an error is returned. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_release(cdf_mutex_t *lock) +{ + /* check for invalid pointer */ + if (lock == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check if lock refers to an uninitialized object */ + if (LINUX_LOCK_COOKIE != lock->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* CurrentThread = GetCurrentThreadId(); + * Check thread ID of caller against thread ID + * of the thread which acquire the lock + */ + if (lock->processID != current->pid) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: current task pid does not match original task pid!!", + __func__); +#ifdef CDF_NESTED_LOCK_DEBUG + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Lock held by=%d being released by=%d", + __func__, lock->processID, current->pid); +#endif + CDF_ASSERT(0); + return CDF_STATUS_E_PERM; + } + if ((lock->processID == current->pid) && + (lock->state == LOCK_ACQUIRED)) { + if (lock->refcount > 0) + lock->refcount--; + } +#ifdef CDF_NESTED_LOCK_DEBUG + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: %x %d %d", __func__, lock, lock->processID, + lock->refcount); +#endif + if (lock->refcount) + return CDF_STATUS_SUCCESS; + + lock->processID = 0; + lock->refcount = 0; + lock->state = LOCK_RELEASED; + /* release a Lock */ + mutex_unlock(&lock->m_lock); +#ifdef CDF_NESTED_LOCK_DEBUG + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Freeing lock %x %d %d", lock, lock->processID, + lock->refcount); +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_mutex_destroy() - destroy a CDF lock + * @lock: Pointer to the opaque lock object to be destroyed + * + * cdf_mutex_destroy() function shall destroy the lock object + * referenced by lock. After a successful return from cdf_mutex_destroy() + * the lock object becomes, in effect, uninitialized. + * + * A destroyed lock object can be reinitialized using cdf_mutex_init(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to CDF lock functions to manipulate the lock such + * as cdf_mutex_acquire() will fail if the lock is destroyed. Therefore, + * don't use the lock after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS: lock was successfully initialized + * CDF failure reason codes: lock is not initialized and can't be used + */ +CDF_STATUS cdf_mutex_destroy(cdf_mutex_t *lock) +{ + /* check for invalid pointer */ + if (NULL == lock) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + return CDF_STATUS_E_FAULT; + } + + if (LINUX_LOCK_COOKIE != lock->cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + return CDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return CDF_STATUS_E_FAULT; + } + + /* check if lock is released */ + if (!mutex_trylock(&lock->m_lock)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: lock is not released", __func__); + return CDF_STATUS_E_BUSY; + } + lock->cookie = 0; + lock->state = LOCK_DESTROYED; + lock->processID = 0; + lock->refcount = 0; + + mutex_unlock(&lock->m_lock); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_spinlock_acquire() - acquires a spin lock + * @pLock: Spin lock to acquire + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_spinlock_acquire(cdf_spinlock_t *pLock) +{ + spin_lock(&pLock->spinlock); + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_spinlock_release() - release a spin lock + * @pLock: Spin lock to release + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_spinlock_release(cdf_spinlock_t *pLock) +{ + spin_unlock(&pLock->spinlock); + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wake_lock_name() - This function returns the name of the wakelock + * @pLock: Pointer to the wakelock + * + * This function returns the name of the wakelock + * + * Return: Pointer to the name if it is valid or a default string + * + */ +static const char *cdf_wake_lock_name(cdf_wake_lock_t *pLock) +{ +#if defined CONFIG_CNSS + if (pLock->name) + return pLock->name; +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + if (pLock->ws.name) + return pLock->ws.name; +#endif + return "UNNAMED_WAKELOCK"; +} + +/** + * cdf_wake_lock_init() - initializes a CDF wake lock + * @pLock: The wake lock to initialize + * @name: Name of wake lock + * + * Return: + * CDF status success : if wake lock is initialized + * CDF status failure : if wake lock was not initialized + */ +CDF_STATUS cdf_wake_lock_init(cdf_wake_lock_t *pLock, const char *name) +{ +#if defined CONFIG_CNSS + cnss_pm_wake_lock_init(pLock, name); +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_init(pLock, WAKE_LOCK_SUSPEND, name); +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wake_lock_acquire() - acquires a wake lock + * @pLock: The wake lock to acquire + * @reason: Reason for wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_acquire(cdf_wake_lock_t *pLock, uint32_t reason) +{ + host_diag_log_wlock(reason, cdf_wake_lock_name(pLock), + WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_TAKEN); +#if defined CONFIG_CNSS + cnss_pm_wake_lock(pLock); +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + wake_lock(pLock); +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout + * @pLock: The wake lock to acquire + * @reason: Reason for wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_timeout_acquire(cdf_wake_lock_t *pLock, uint32_t msec, + uint32_t reason) +{ + /* Wakelock for Rx is frequent. + * It is reported only during active debug + */ + if (((cds_get_ring_log_level(RING_ID_WAKELOCK) >= WLAN_LOG_LEVEL_ACTIVE) + && (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX == reason)) || + (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX != reason)) { + host_diag_log_wlock(reason, cdf_wake_lock_name(pLock), msec, + WIFI_POWER_EVENT_WAKELOCK_TAKEN); + } +#if defined CONFIG_CNSS + cnss_pm_wake_lock_timeout(pLock, msec); +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_timeout(pLock, msecs_to_jiffies(msec)); +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wake_lock_release() - releases a wake lock + * @pLock: the wake lock to release + * @reason: Reason for wakelock + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_release(cdf_wake_lock_t *pLock, uint32_t reason) +{ + host_diag_log_wlock(reason, cdf_wake_lock_name(pLock), + WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_RELEASED); +#if defined CONFIG_CNSS + cnss_pm_wake_lock_release(pLock); +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + wake_unlock(pLock); +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_wake_lock_destroy() - destroys a wake lock + * @pLock: The wake lock to destroy + * + * Return: + * CDF status success : if wake lock is acquired + * CDF status failure : if wake lock was not acquired + */ +CDF_STATUS cdf_wake_lock_destroy(cdf_wake_lock_t *pLock) +{ +#if defined CONFIG_CNSS + cnss_pm_wake_lock_destroy(pLock); +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_destroy(pLock); +#endif + return CDF_STATUS_SUCCESS; +} diff --git a/core/cdf/src/cdf_mc_timer.c b/core/cdf/src/cdf_mc_timer.c new file mode 100644 index 0000000000..cefdfccd7f --- /dev/null +++ b/core/cdf/src/cdf_mc_timer.c @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_mc_timer + * + * Connectivity driver framework timer APIs serialized to MC thread + */ + +/* Include Files */ +#include +#include +#include +#include "wlan_qct_sys.h" +#include "cds_sched.h" + +/* Preprocessor definitions and constants */ + +#define LINUX_TIMER_COOKIE 0x12341234 +#define LINUX_INVALID_TIMER_COOKIE 0xfeedface +#define TMR_INVALID_ID (0) + +/* Type declarations */ + +/* Static Variable Definitions */ +static unsigned int persistent_timer_count; +static cdf_mutex_t persistent_timer_count_lock; + +/* Function declarations and documenation */ + +/** + * try_allowing_sleep() - clean up timer states after it has been deactivated + * @type: Timer type + * + * Clean up timer states after it has been deactivated check and try to allow + * sleep after a timer has been stopped or expired. + * + * Return: none + */ +static void try_allowing_sleep(CDF_TIMER_TYPE type) +{ + if (CDF_TIMER_TYPE_WAKE_APPS == type) { + /* cdf_mutex_acquire(&persistent_timer_count_lock); */ + persistent_timer_count--; + if (0 == persistent_timer_count) { + /* since the number of persistent timers has + decreased from 1 to 0, the timer should allow + sleep sleep_assert_okts( sleepClientHandle ); */ + } + /* cdf_mutex_release(&persistent_timer_count_lock); */ + } +} + +/** + * cdf_linux_timer_callback() - internal cdf entry point which is + * called when the timer interval expires + * @data: pointer to the timer control block which describes the + * timer that expired + * + * This function in turn calls the CDF client callback and changes the + * state of the timer from running (ACTIVE) to expired (INIT). + * + * Note: function signature is defined by the Linux kernel. The fact + * that the argument is "unsigned long" instead of "void *" is + * unfortunately imposed upon us. But we can safely pass a pointer via + * this parameter for LP32 and LP64 architectures. + * + * Return: nothing + */ + +static void cdf_linux_timer_callback(unsigned long data) +{ + cdf_mc_timer_t *timer = (cdf_mc_timer_t *) data; + cds_msg_t msg; + CDF_STATUS vStatus; + unsigned long flags; + + cdf_mc_timer_callback_t callback = NULL; + void *userData = NULL; + int threadId; + CDF_TIMER_TYPE type = CDF_TIMER_TYPE_SW; + + CDF_ASSERT(timer); + + if (timer == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s Null pointer passed in!", __func__); + return; + } + + threadId = timer->platformInfo.threadID; + spin_lock_irqsave(&timer->platformInfo.spinlock, flags); + + switch (timer->state) { + case CDF_TIMER_STATE_STARTING: + /* we are in this state because someone just started the timer, + * MC timer got started and expired, but the time content have + * not been updated this is a rare race condition! + */ + timer->state = CDF_TIMER_STATE_STOPPED; + vStatus = CDF_STATUS_E_ALREADY; + break; + + case CDF_TIMER_STATE_STOPPED: + vStatus = CDF_STATUS_E_ALREADY; + break; + + case CDF_TIMER_STATE_UNUSED: + vStatus = CDF_STATUS_E_EXISTS; + break; + + case CDF_TIMER_STATE_RUNNING: + /* need to go to stop state here because the call-back function + * may restart timer (to emulate periodic timer) + */ + timer->state = CDF_TIMER_STATE_STOPPED; + /* copy the relevant timer information to local variables; + * once we exist from this critical section, the timer content + * may be modified by other tasks + */ + callback = timer->callback; + userData = timer->userData; + threadId = timer->platformInfo.threadID; + type = timer->type; + vStatus = CDF_STATUS_SUCCESS; + break; + + default: + CDF_ASSERT(0); + vStatus = CDF_STATUS_E_FAULT; + break; + } + + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + + if (CDF_STATUS_SUCCESS != vStatus) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "TIMER callback called in a wrong state=%d", + timer->state); + return; + } + + try_allowing_sleep(type); + + if (callback == NULL) { + CDF_ASSERT(0); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: No TIMER callback, Could not enqueue timer to any queue", + __func__); + return; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "TIMER callback: running on MC thread"); + + /* serialize to the MC thread */ + sys_build_message_header(SYS_MSG_ID_MC_TIMER, &msg); + msg.callback = callback; + msg.bodyptr = userData; + msg.bodyval = 0; + + if (cds_mq_post_message(CDS_MQ_ID_SYS, &msg) == CDF_STATUS_SUCCESS) + return; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Could not enqueue timer to any queue", __func__); + CDF_ASSERT(0); +} + +/** + * cdf_mc_timer_get_current_state() - get the current state of the timer + * @pTimer: Pointer to timer object + * + * Return: + * CDF_TIMER_STATE - cdf timer state + */ +CDF_TIMER_STATE cdf_mc_timer_get_current_state(cdf_mc_timer_t *pTimer) +{ + if (NULL == pTimer) { + CDF_ASSERT(0); + return CDF_TIMER_STATE_UNUSED; + } + + switch (pTimer->state) { + case CDF_TIMER_STATE_STOPPED: + case CDF_TIMER_STATE_STARTING: + case CDF_TIMER_STATE_RUNNING: + case CDF_TIMER_STATE_UNUSED: + return pTimer->state; + default: + CDF_ASSERT(0); + return CDF_TIMER_STATE_UNUSED; + } +} + +/** + * cdf_timer_module_init() - initializes a CDF timer module. + * + * This API initializes the CDF timer module. This needs to be called + * exactly once prior to using any CDF timers. + * + * Return: none + */ +void cdf_timer_module_init(void) +{ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "Initializing the CDF timer module"); + cdf_mutex_init(&persistent_timer_count_lock); +} + +#ifdef TIMER_MANAGER + +cdf_list_t cdf_timer_list; +cdf_spinlock_t cdf_timer_list_lock; + +static void cdf_timer_clean(void); + +/** + * cdf_mc_timer_manager_init() - initialize CDF debug timer manager + * + * This API initializes CDF timer debug functionality. + * + * Return: none + */ +void cdf_mc_timer_manager_init(void) +{ + /* Initalizing the list with maximum size of 60000 */ + cdf_list_init(&cdf_timer_list, 1000); + cdf_spinlock_init(&cdf_timer_list_lock); + return; +} + +/** + * cdf_timer_clean() - clean up CDF timer debug functionality + * + * This API cleans up CDF timer debug functionality and prints which CDF timers + * are leaked. This is called during driver unload. + * + * Return: none + */ +static void cdf_timer_clean(void) +{ + uint32_t listSize; + + cdf_list_size(&cdf_timer_list, &listSize); + + if (listSize) { + cdf_list_node_t *pNode; + CDF_STATUS cdf_status; + + cdf_mc_timer_node_t *ptimerNode; + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: List is not Empty. listSize %d ", + __func__, (int)listSize); + + do { + cdf_spin_lock_irqsave(&cdf_timer_list_lock); + cdf_status = + cdf_list_remove_front(&cdf_timer_list, &pNode); + cdf_spin_unlock_irqrestore(&cdf_timer_list_lock); + if (CDF_STATUS_SUCCESS == cdf_status) { + ptimerNode = (cdf_mc_timer_node_t *) pNode; + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "Timer Leak@ File %s, @Line %d", + ptimerNode->fileName, + (int)ptimerNode->lineNum); + cdf_mem_free(ptimerNode); + } + } while (cdf_status == CDF_STATUS_SUCCESS); + } +} + +/** + * cdf_mc_timer_exit() - exit CDF timer debug functionality + * + * This API exists CDF timer debug functionality + * + * Return: none + */ +void cdf_mc_timer_exit(void) +{ + cdf_timer_clean(); + cdf_list_destroy(&cdf_timer_list); +} +#endif + +/** + * cdf_mc_timer_init() - initialize a CDF timer + * @pTimer: Pointer to timer object + * @timerType: Type of timer + * @callback: Callback to be called after timer expiry + * @serData: User data which will be passed to callback function + * + * This API initializes a CDF Timer object. + * + * cdf_mc_timer_init() initializes a CDF Timer object. A timer must be + * initialized by calling cdf_mc_timer_initialize() before it may be used in + * any other timer functions. + * + * Attempting to initialize timer that is already initialized results in + * a failure. A destroyed timer object can be re-initialized with a call to + * cdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to CDF timer functions to manipulate the timer such + * as cdf_mc_timer_set() will fail if the timer is not initialized or has + * been destroyed. Therefore, don't use the timer after it has been + * destroyed until it has been re-initialized. + * + * All callback will be executed within the CDS main thread unless it is + * initialized from the Tx thread flow, in which case it will be executed + * within the tx thread flow. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +#ifdef TIMER_MANAGER +CDF_STATUS cdf_mc_timer_init_debug(cdf_mc_timer_t *timer, + CDF_TIMER_TYPE timerType, + cdf_mc_timer_callback_t callback, + void *userData, char *fileName, + uint32_t lineNum) +{ + CDF_STATUS cdf_status; + + /* check for invalid pointer */ + if ((timer == NULL) || (callback == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + timer->ptimerNode = cdf_mem_malloc(sizeof(cdf_mc_timer_node_t)); + + if (timer->ptimerNode == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for timeNode", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set(timer->ptimerNode, sizeof(cdf_mc_timer_node_t), 0); + + timer->ptimerNode->fileName = fileName; + timer->ptimerNode->lineNum = lineNum; + timer->ptimerNode->cdf_timer = timer; + + cdf_spin_lock_irqsave(&cdf_timer_list_lock); + cdf_status = cdf_list_insert_front(&cdf_timer_list, + &timer->ptimerNode->pNode); + cdf_spin_unlock_irqrestore(&cdf_timer_list_lock); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Unable to insert node into List cdf_status %d", + __func__, cdf_status); + } + + /* set the various members of the timer structure + * with arguments passed or with default values + */ + spin_lock_init(&timer->platformInfo.spinlock); + if (CDF_TIMER_TYPE_SW == timerType) + init_timer_deferrable(&(timer->platformInfo.Timer)); + else + init_timer(&(timer->platformInfo.Timer)); + timer->platformInfo.Timer.function = cdf_linux_timer_callback; + timer->platformInfo.Timer.data = (unsigned long)timer; + timer->callback = callback; + timer->userData = userData; + timer->type = timerType; + timer->platformInfo.cookie = LINUX_TIMER_COOKIE; + timer->platformInfo.threadID = 0; + timer->state = CDF_TIMER_STATE_STOPPED; + + return CDF_STATUS_SUCCESS; +} +#else +CDF_STATUS cdf_mc_timer_init(cdf_mc_timer_t *timer, CDF_TIMER_TYPE timerType, + cdf_mc_timer_callback_t callback, + void *userData) +{ + /* check for invalid pointer */ + if ((timer == NULL) || (callback == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* set the various members of the timer structure + * with arguments passed or with default values + */ + spin_lock_init(&timer->platformInfo.spinlock); + if (CDF_TIMER_TYPE_SW == timerType) + init_timer_deferrable(&(timer->platformInfo.Timer)); + else + init_timer(&(timer->platformInfo.Timer)); + timer->platformInfo.Timer.function = cdf_linux_timer_callback; + timer->platformInfo.Timer.data = (unsigned long)timer; + timer->callback = callback; + timer->userData = userData; + timer->type = timerType; + timer->platformInfo.cookie = LINUX_TIMER_COOKIE; + timer->platformInfo.threadID = 0; + timer->state = CDF_TIMER_STATE_STOPPED; + + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * cdf_mc_timer_destroy() - destroy CDF timer + * @timer: Pointer to timer object + * + * cdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a cdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * cdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to CDF timer functions to manipulate the timer, such + * as cdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +#ifdef TIMER_MANAGER +CDF_STATUS cdf_mc_timer_destroy(cdf_mc_timer_t *timer) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + unsigned long flags; + + /* check for invalid pointer */ + if (NULL == timer) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null timer pointer being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* Check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platformInfo.cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy uninitialized timer", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + cdf_spin_lock_irqsave(&cdf_timer_list_lock); + vStatus = cdf_list_remove_node(&cdf_timer_list, + &timer->ptimerNode->pNode); + cdf_spin_unlock_irqrestore(&cdf_timer_list_lock); + if (vStatus != CDF_STATUS_SUCCESS) { + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + cdf_mem_free(timer->ptimerNode); + + spin_lock_irqsave(&timer->platformInfo.spinlock, flags); + + switch (timer->state) { + + case CDF_TIMER_STATE_STARTING: + vStatus = CDF_STATUS_E_BUSY; + break; + + case CDF_TIMER_STATE_RUNNING: + /* Stop the timer first */ + del_timer(&(timer->platformInfo.Timer)); + vStatus = CDF_STATUS_SUCCESS; + break; + case CDF_TIMER_STATE_STOPPED: + vStatus = CDF_STATUS_SUCCESS; + break; + + case CDF_TIMER_STATE_UNUSED: + vStatus = CDF_STATUS_E_ALREADY; + break; + + default: + vStatus = CDF_STATUS_E_FAULT; + break; + } + + if (CDF_STATUS_SUCCESS == vStatus) { + timer->platformInfo.cookie = LINUX_INVALID_TIMER_COOKIE; + timer->state = CDF_TIMER_STATE_UNUSED; + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + return vStatus; + } + + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy timer in state = %d", __func__, + timer->state); + CDF_ASSERT(0); + + return vStatus; +} + +#else + +/** + * cdf_mc_timer_destroy() - destroy CDF timer + * @timer: Pointer to timer object + * + * cdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a cdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * cdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to CDF timer functions to manipulate the timer, such + * as cdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_destroy(cdf_mc_timer_t *timer) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + unsigned long flags; + + /* check for invalid pointer */ + if (NULL == timer) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null timer pointer being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platformInfo.cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy uninitialized timer", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + spin_lock_irqsave(&timer->platformInfo.spinlock, flags); + + switch (timer->state) { + + case CDF_TIMER_STATE_STARTING: + vStatus = CDF_STATUS_E_BUSY; + break; + + case CDF_TIMER_STATE_RUNNING: + /* Stop the timer first */ + del_timer(&(timer->platformInfo.Timer)); + vStatus = CDF_STATUS_SUCCESS; + break; + + case CDF_TIMER_STATE_STOPPED: + vStatus = CDF_STATUS_SUCCESS; + break; + + case CDF_TIMER_STATE_UNUSED: + vStatus = CDF_STATUS_E_ALREADY; + break; + + default: + vStatus = CDF_STATUS_E_FAULT; + break; + } + + if (CDF_STATUS_SUCCESS == vStatus) { + timer->platformInfo.cookie = LINUX_INVALID_TIMER_COOKIE; + timer->state = CDF_TIMER_STATE_UNUSED; + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + return vStatus; + } + + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy timer in state = %d", __func__, + timer->state); + CDF_ASSERT(0); + + return vStatus; +} +#endif + +/** + * cdf_mc_timer_start() - start a CDF Timer object + * @timer: Pointer to timer object + * @expirationTime: Time to expire + * + * cdf_mc_timer_start() function starts a timer to expire after the + * specified interval, thus running the timer callback function when + * the interval expires. + * + * A timer only runs once (a one-shot timer). To re-start the + * timer, cdf_mc_timer_start() has to be called after the timer runs + * or has been cancelled. + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_start(cdf_mc_timer_t *timer, uint32_t expirationTime) +{ + unsigned long flags; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "Timer Addr inside cds_enable : 0x%p ", timer); + + /* check for invalid pointer */ + if (NULL == timer) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s Null timer pointer being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platformInfo.cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot start uninitialized timer", __func__); + if (LINUX_INVALID_TIMER_COOKIE != timer->platformInfo.cookie) + CDF_ASSERT(0); + + return CDF_STATUS_E_INVAL; + } + + /* check if timer has expiration time less than 10 ms */ + if (expirationTime < 10) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot start a timer with expiration less than 10 ms", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + /* make sure the remainer of the logic isn't interrupted */ + spin_lock_irqsave(&timer->platformInfo.spinlock, flags); + + /* ensure if the timer can be started */ + if (CDF_TIMER_STATE_STOPPED != timer->state) { + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Cannot start timer in state = %d ", __func__, + timer->state); + return CDF_STATUS_E_ALREADY; + } + + /* start the timer */ + mod_timer(&(timer->platformInfo.Timer), + jiffies + msecs_to_jiffies(expirationTime)); + + timer->state = CDF_TIMER_STATE_RUNNING; + + /* get the thread ID on which the timer is being started */ + timer->platformInfo.threadID = current->pid; + + if (CDF_TIMER_TYPE_WAKE_APPS == timer->type) { + persistent_timer_count++; + if (1 == persistent_timer_count) { + /* since we now have one persistent timer, + * we need to disallow sleep + * sleep_negate_okts(sleepClientHandle); + */ + } + } + + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_mc_timer_stop() - stop a CDF Timer + * @timer: Pointer to timer object + * cdf_mc_timer_stop() function stops a timer that has been started but + * has not expired, essentially cancelling the 'start' request. + * + * After a timer is stopped, it goes back to the state it was in after it + * was created and can be started again via a call to cdf_mc_timer_start(). + * + * Return: + * CDF_STATUS_SUCCESS - Timer is initialized successfully + * CDF failure status - Timer initialization failed + */ +CDF_STATUS cdf_mc_timer_stop(cdf_mc_timer_t *timer) +{ + unsigned long flags; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Timer Addr inside cds_disable : 0x%p", __func__, timer); + + /* check for invalid pointer */ + if (NULL == timer) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s Null timer pointer being passed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platformInfo.cookie) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot stop uninitialized timer", __func__); + if (LINUX_INVALID_TIMER_COOKIE != timer->platformInfo.cookie) + CDF_ASSERT(0); + + return CDF_STATUS_E_INVAL; + } + + /* ensure the timer state is correct */ + spin_lock_irqsave(&timer->platformInfo.spinlock, flags); + + if (CDF_TIMER_STATE_RUNNING != timer->state) { + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Cannot stop timer in state = %d", + __func__, timer->state); + return CDF_STATUS_SUCCESS; + } + + timer->state = CDF_TIMER_STATE_STOPPED; + + del_timer(&(timer->platformInfo.Timer)); + + spin_unlock_irqrestore(&timer->platformInfo.spinlock, flags); + + try_allowing_sleep(timer->type); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks + + * cdf_mc_timer_get_system_ticks() function returns the current number + * of timer ticks in 10msec intervals. This function is suitable timestamping + * and calculating time intervals by calculating the difference between two + * timestamps. + * + * Return: + * The current system tick count (in 10msec intervals). This + * function cannot fail. + */ +v_TIME_t cdf_mc_timer_get_system_ticks(void) +{ + return jiffies_to_msecs(jiffies) / 10; +} + +/** + * cdf_mc_timer_get_system_time() - Get the system time in milliseconds + * + * cdf_mc_timer_get_system_time() function returns the number of milliseconds + * that have elapsed since the system was started + * + * Return: + * The current system time in milliseconds + */ +v_TIME_t cdf_mc_timer_get_system_time(void) +{ + struct timeval tv; + do_gettimeofday(&tv); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} diff --git a/core/cdf/src/cdf_memory.c b/core/cdf/src/cdf_memory.c new file mode 100644 index 0000000000..732d1e59c9 --- /dev/null +++ b/core/cdf/src/cdf_memory.c @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_memory + * + * Connectivity driver framework (CDF) memory management APIs + */ + +/* Include Files */ +#include "cdf_memory.h" +#include "cdf_nbuf.h" +#include "cdf_trace.h" +#include "cdf_lock.h" + +#if defined(CONFIG_CNSS) +#include +#endif + +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +#include +#endif + +#ifdef MEMORY_DEBUG +#include + +cdf_list_t cdf_mem_list; +cdf_spinlock_t cdf_mem_list_lock; + +static uint8_t WLAN_MEM_HEADER[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68 }; +static uint8_t WLAN_MEM_TAIL[] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87 }; + +struct s_cdf_mem_struct { + cdf_list_node_t pNode; + char *fileName; + unsigned int lineNum; + unsigned int size; + uint8_t header[8]; +}; +#endif + +/* Preprocessor Definitions and Constants */ + +/* Type Declarations */ + +/* Data definitions */ + +/* External Function implementation */ +#ifdef MEMORY_DEBUG + +/** + * cdf_mem_init() - initialize cdf memory debug functionality + * + * Return: none + */ +void cdf_mem_init(void) +{ + /* Initalizing the list with maximum size of 60000 */ + cdf_list_init(&cdf_mem_list, 60000); + cdf_spinlock_init(&cdf_mem_list_lock); + cdf_net_buf_debug_init(); + return; +} + +/** + * cdf_mem_clean() - display memory leak debug info and free leaked pointers + * + * Return: none + */ +void cdf_mem_clean(void) +{ + uint32_t listSize; + cdf_list_size(&cdf_mem_list, &listSize); + + cdf_net_buf_debug_clean(); + + if (listSize) { + cdf_list_node_t *pNode; + CDF_STATUS cdf_status; + + struct s_cdf_mem_struct *memStruct; + char *prev_mleak_file = ""; + unsigned int prev_mleak_lineNum = 0; + unsigned int prev_mleak_sz = 0; + unsigned int mleak_cnt = 0; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: List is not Empty. listSize %d ", + __func__, (int)listSize); + + do { + cdf_spin_lock(&cdf_mem_list_lock); + cdf_status = + cdf_list_remove_front(&cdf_mem_list, &pNode); + cdf_spin_unlock(&cdf_mem_list_lock); + if (CDF_STATUS_SUCCESS == cdf_status) { + memStruct = (struct s_cdf_mem_struct *)pNode; + /* Take care to log only once multiple memory + leaks from the same place */ + if (strcmp(prev_mleak_file, memStruct->fileName) + || (prev_mleak_lineNum != + memStruct->lineNum) + || (prev_mleak_sz != memStruct->size)) { + if (mleak_cnt != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "%d Time Memory Leak@ File %s, @Line %d, size %d", + mleak_cnt, + prev_mleak_file, + prev_mleak_lineNum, + prev_mleak_sz); + } + prev_mleak_file = memStruct->fileName; + prev_mleak_lineNum = memStruct->lineNum; + prev_mleak_sz = memStruct->size; + mleak_cnt = 0; + } + mleak_cnt++; + kfree((void *)memStruct); + } + } while (cdf_status == CDF_STATUS_SUCCESS); + + /* Print last memory leak from the module */ + if (mleak_cnt) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%d Time memory Leak@ File %s, @Line %d, size %d", + mleak_cnt, prev_mleak_file, + prev_mleak_lineNum, prev_mleak_sz); + } +#ifdef CONFIG_HALT_KMEMLEAK + BUG_ON(0); +#endif + } +} + +/** + * cdf_mem_exit() - exit cdf memory debug functionality + * + * Return: none + */ +void cdf_mem_exit(void) +{ + cdf_net_buf_debug_exit(); + cdf_mem_clean(); + cdf_list_destroy(&cdf_mem_list); +} + +/** + * cdf_mem_malloc_debug() - debug version of CDF memory allocation API + * @size: Number of bytes of memory to allocate. + * @fileName: File name from which memory allocation is called + * @lineNum: Line number from which memory allocation is called + * + * This function will dynamicallly allocate the specified number of bytes of + * memory and ad it in cdf tracking list to check against memory leaks and + * corruptions + * + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns %NULL. + * + */ +void *cdf_mem_malloc_debug(size_t size, char *fileName, uint32_t lineNum) +{ + struct s_cdf_mem_struct *memStruct; + void *memPtr = NULL; + uint32_t new_size; + int flags = GFP_KERNEL; + + if (size > (1024 * 1024)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: called with arg > 1024K; passed in %zu !!!", + __func__, size); + return NULL; + } + +#if defined(CONFIG_CNSS) && defined(CONFIG_WCNSS_MEM_PRE_ALLOC) + if (size > WCNSS_PRE_ALLOC_GET_THRESHOLD) { + void *pmem; + pmem = wcnss_prealloc_get(size); + if (NULL != pmem) { + memset(pmem, 0, size); + return pmem; + } + } +#endif + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + new_size = size + sizeof(struct s_cdf_mem_struct) + 8; + + memStruct = (struct s_cdf_mem_struct *)kzalloc(new_size, flags); + + if (memStruct != NULL) { + CDF_STATUS cdf_status; + + memStruct->fileName = fileName; + memStruct->lineNum = lineNum; + memStruct->size = size; + + cdf_mem_copy(&memStruct->header[0], + &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER)); + + cdf_mem_copy((uint8_t *) (memStruct + 1) + size, + &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL)); + + cdf_spin_lock_irqsave(&cdf_mem_list_lock); + cdf_status = cdf_list_insert_front(&cdf_mem_list, + &memStruct->pNode); + cdf_spin_unlock_irqrestore(&cdf_mem_list_lock); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Unable to insert node into List cdf_status %d", + __func__, cdf_status); + } + + memPtr = (void *)(memStruct + 1); + } + return memPtr; +} + +/** + * cdf_mem_free() - debug version of CDF memory free API + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. It also checks + * is memory is corrupted or getting double freed and panic. + * + * Return: + * Nothing + */ +void cdf_mem_free(void *ptr) +{ + if (ptr != NULL) { + CDF_STATUS cdf_status; + struct s_cdf_mem_struct *memStruct = + ((struct s_cdf_mem_struct *)ptr) - 1; + +#if defined(CONFIG_CNSS) && defined(CONFIG_WCNSS_MEM_PRE_ALLOC) + if (wcnss_prealloc_put(ptr)) + return; +#endif + + cdf_spin_lock_irqsave(&cdf_mem_list_lock); + cdf_status = + cdf_list_remove_node(&cdf_mem_list, &memStruct->pNode); + cdf_spin_unlock_irqrestore(&cdf_mem_list_lock); + + if (CDF_STATUS_SUCCESS == cdf_status) { + if (0 == cdf_mem_compare(memStruct->header, + &WLAN_MEM_HEADER[0], + sizeof(WLAN_MEM_HEADER))) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "Memory Header is corrupted. MemInfo: Filename %s, LineNum %d", + memStruct->fileName, + (int)memStruct->lineNum); + CDF_BUG(0); + } + if (0 == + cdf_mem_compare((uint8_t *) ptr + memStruct->size, + &WLAN_MEM_TAIL[0], + sizeof(WLAN_MEM_TAIL))) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "Memory Trailer is corrupted. MemInfo: Filename %s, LineNum %d", + memStruct->fileName, + (int)memStruct->lineNum); + CDF_BUG(0); + } + kfree((void *)memStruct); + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Unallocated memory (double free?)", + __func__); + CDF_BUG(0); + } + } +} +#else +/** + * cdf_mem_malloc() - allocation CDF memory + * @size: Number of bytes of memory to allocate. + * + * This function will dynamicallly allocate the specified number of bytes of + * memory. + * + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns %NULL. + * + */ +void *cdf_mem_malloc(size_t size) +{ + int flags = GFP_KERNEL; +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC + void *pmem; +#endif + if (size > (1024 * 1024)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: called with arg > 1024K; passed in %zu !!", + __func__, size); + return NULL; + } + +#if defined(CONFIG_CNSS) && defined(CONFIG_WCNSS_MEM_PRE_ALLOC) + if (size > WCNSS_PRE_ALLOC_GET_THRESHOLD) { + pmem = wcnss_prealloc_get(size); + if (NULL != pmem) { + memset(pmem, 0, size); + return pmem; + } + } +#endif + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + return kzalloc(size, flags); +} + +/** + * cdf_mem_free() - free CDF memory + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. + * + * Return: + * Nothing + * + */ +void cdf_mem_free(void *ptr) +{ + if (ptr == NULL) + return; + +#if defined(CONFIG_CNSS) && defined(CONFIG_WCNSS_MEM_PRE_ALLOC) + if (wcnss_prealloc_put(ptr)) + return; +#endif + + kfree(ptr); +} +#endif + +/** + * cdf_mem_set() - set (fill) memory with a specified byte value. + * @pMemory: Pointer to memory that will be set + * @numBytes: Number of bytes to be set + * @value: Byte set in memory + * + * Return: + * Nothing + * + */ +void cdf_mem_set(void *ptr, uint32_t numBytes, uint32_t value) +{ + if (ptr == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter ptr", __func__); + return; + } + memset(ptr, value, numBytes); +} + +/** + * cdf_mem_zero() - zero out memory + * @pMemory: pointer to memory that will be set to zero + * @numBytes: number of bytes zero + * @value: byte set in memory + * + * This function sets the memory location to all zeros, essentially clearing + * the memory. + * + * Return: + * Nothing + * + */ +void cdf_mem_zero(void *ptr, uint32_t numBytes) +{ + if (0 == numBytes) { + /* special case where ptr can be NULL */ + return; + } + + if (ptr == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter ptr", __func__); + return; + } + memset(ptr, 0, numBytes); +} + +/** + * cdf_mem_copy() - copy memory + * @pDst: Pointer to destination memory location (to copy to) + * @pSrc: Pointer to source memory location (to copy from) + * @numBytes: Number of bytes to copy. + * + * Copy host memory from one location to another, similar to memcpy in + * standard C. Note this function does not specifically handle overlapping + * source and destination memory locations. Calling this function with + * overlapping source and destination memory locations will result in + * unpredictable results. Use cdf_mem_move() if the memory locations + * for the source and destination are overlapping (or could be overlapping!) + * + * Return: + * Nothing + * + */ +void cdf_mem_copy(void *pDst, const void *pSrc, uint32_t numBytes) +{ + if (0 == numBytes) { + /* special case where pDst or pSrc can be NULL */ + return; + } + + if ((pDst == NULL) || (pSrc == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter, source:%p destination:%p", + __func__, pSrc, pDst); + CDF_ASSERT(0); + return; + } + memcpy(pDst, pSrc, numBytes); +} + +/** + * cdf_mem_move() - move memory + * @pDst: pointer to destination memory location (to move to) + * @pSrc: pointer to source memory location (to move from) + * @numBytes: number of bytes to move. + * + * Move host memory from one location to another, similar to memmove in + * standard C. Note this function *does* handle overlapping + * source and destination memory locations. + + * Return: + * Nothing + */ +void cdf_mem_move(void *pDst, const void *pSrc, uint32_t numBytes) +{ + if (0 == numBytes) { + /* special case where pDst or pSrc can be NULL */ + return; + } + + if ((pDst == NULL) || (pSrc == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter, source:%p destination:%p", + __func__, pSrc, pDst); + CDF_ASSERT(0); + return; + } + memmove(pDst, pSrc, numBytes); +} + +/** + * cdf_mem_compare() - memory compare + * @pMemory1: pointer to one location in memory to compare. + * @pMemory2: pointer to second location in memory to compare. + * @numBytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * + * Return: + * bool - returns a bool value that tells if the memory locations + * are equal or not equal. + * + */ +bool cdf_mem_compare(const void *pMemory1, const void *pMemory2, + uint32_t numBytes) +{ + if (0 == numBytes) { + /* special case where pMemory1 or pMemory2 can be NULL */ + return true; + } + + if ((pMemory1 == NULL) || (pMemory2 == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter, p1:%p p2:%p", + __func__, pMemory1, pMemory2); + CDF_ASSERT(0); + return false; + } + return memcmp(pMemory1, pMemory2, numBytes) ? false : true; +} + +/** + * cdf_mem_compare2() - memory compare + * @pMemory1: pointer to one location in memory to compare. + * @pMemory2: pointer to second location in memory to compare. + * @numBytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * Return: + * int32_t - returns a bool value that tells if the memory + * locations are equal or not equal. + * 0 -- equal + * < 0 -- *pMemory1 is less than *pMemory2 + * > 0 -- *pMemory1 is bigger than *pMemory2 + */ +int32_t cdf_mem_compare2(const void *pMemory1, const void *pMemory2, + uint32_t numBytes) +{ + return (int32_t) memcmp(pMemory1, pMemory2, numBytes); +} + +/** + * cdf_os_mem_alloc_consistent() - allocates consistent cdf memory + * @osdev: OS device handle + * @size: Size to be allocated + * @paddr: Physical address + * @mctx: Pointer to DMA context + * + * Return: pointer of allocated memory or null if memory alloc fails + */ +inline void *cdf_os_mem_alloc_consistent(cdf_device_t osdev, cdf_size_t size, + cdf_dma_addr_t *paddr, + cdf_dma_context_t memctx) +{ +#if defined(A_SIMOS_DEVHOST) + static int first = 1; + void *vaddr; + + if (first) { + first = 0; + pr_err("Warning: bypassing %s\n", __func__); + } + vaddr = cdf_mem_malloc(size); + *paddr = ((cdf_dma_addr_t) vaddr); + return vaddr; +#else + int flags = GFP_KERNEL; + void *alloc_mem = NULL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + alloc_mem = dma_alloc_coherent(osdev->dev, size, paddr, flags); + if (alloc_mem == NULL) + pr_err("%s Warning: unable to alloc consistent memory of size %zu!\n", + __func__, size); + return alloc_mem; +#endif +} + +/** + * cdf_os_mem_free_consistent() - free consistent cdf memory + * @osdev: OS device handle + * @size: Size to be allocated + * @paddr: Physical address + * @mctx: Pointer to DMA context + * + * Return: none + */ +inline void +cdf_os_mem_free_consistent(cdf_device_t osdev, + cdf_size_t size, + void *vaddr, + cdf_dma_addr_t paddr, cdf_dma_context_t memctx) +{ +#if defined(A_SIMOS_DEVHOST) + static int first = 1; + + if (first) { + first = 0; + pr_err("Warning: bypassing %s\n", __func__); + } + cdf_mem_free(vaddr); + return; +#else + dma_free_coherent(osdev->dev, size, vaddr, paddr); +#endif +} + + +/** + * cdf_os_mem_dma_sync_single_for_device() - assign memory to device + * @osdev: OS device handle + * @bus_addr: dma address to give to the device + * @size: Size of the memory block + * @direction: direction data will be dma'ed + * + * Assgin memory to the remote device. + * The cache lines are flushed to ram or invalidated as needed. + * + * Return: none + */ + +inline void +cdf_os_mem_dma_sync_single_for_device(cdf_device_t osdev, + cdf_dma_addr_t bus_addr, + cdf_size_t size, + enum dma_data_direction direction) +{ + dma_sync_single_for_device(osdev->dev, bus_addr, size, direction); +} diff --git a/core/cdf/src/cdf_nbuf.c b/core/cdf/src/cdf_nbuf.c new file mode 100644 index 0000000000..382ff2b1ef --- /dev/null +++ b/core/cdf/src/cdf_nbuf.c @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_nbuf.c + * + * Connectivity driver framework(CDF) network buffer management APIs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(FEATURE_TSO) +#include +#include +#include +#include +#include +#endif /* FEATURE_TSO */ + +/* Packet Counter */ +static uint32_t nbuf_tx_mgmt[NBUF_TX_PKT_STATE_MAX]; +static uint32_t nbuf_tx_data[NBUF_TX_PKT_STATE_MAX]; + +/** + * cdf_nbuf_tx_desc_count_display() - Displays the packet counter + * + * Return: none + */ +void cdf_nbuf_tx_desc_count_display(void) +{ + cdf_print("Current Snapshot of the Driver:\n"); + cdf_print("Data Packets:\n"); + cdf_print("HDD %d TXRX_Q %d TXRX %d HTT %d", + nbuf_tx_data[NBUF_TX_PKT_HDD] - + (nbuf_tx_data[NBUF_TX_PKT_TXRX] + + nbuf_tx_data[NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_data[NBUF_TX_PKT_TXRX_DEQUEUE]), + nbuf_tx_data[NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_data[NBUF_TX_PKT_TXRX_DEQUEUE], + nbuf_tx_data[NBUF_TX_PKT_TXRX] - nbuf_tx_data[NBUF_TX_PKT_HTT], + nbuf_tx_data[NBUF_TX_PKT_HTT] - nbuf_tx_data[NBUF_TX_PKT_HTC]); + cdf_print(" HTC %d HIF %d CE %d TX_COMP %d\n", + nbuf_tx_data[NBUF_TX_PKT_HTC] - nbuf_tx_data[NBUF_TX_PKT_HIF], + nbuf_tx_data[NBUF_TX_PKT_HIF] - nbuf_tx_data[NBUF_TX_PKT_CE], + nbuf_tx_data[NBUF_TX_PKT_CE] - nbuf_tx_data[NBUF_TX_PKT_FREE], + nbuf_tx_data[NBUF_TX_PKT_FREE]); + cdf_print("Mgmt Packets:\n"); + cdf_print("TXRX_Q %d TXRX %d HTT %d HTC %d HIF %d CE %d TX_COMP %d\n", + nbuf_tx_mgmt[NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_mgmt[NBUF_TX_PKT_TXRX_DEQUEUE], + nbuf_tx_mgmt[NBUF_TX_PKT_TXRX] - nbuf_tx_mgmt[NBUF_TX_PKT_HTT], + nbuf_tx_mgmt[NBUF_TX_PKT_HTT] - nbuf_tx_mgmt[NBUF_TX_PKT_HTC], + nbuf_tx_mgmt[NBUF_TX_PKT_HTC] - nbuf_tx_mgmt[NBUF_TX_PKT_HIF], + nbuf_tx_mgmt[NBUF_TX_PKT_HIF] - nbuf_tx_mgmt[NBUF_TX_PKT_CE], + nbuf_tx_mgmt[NBUF_TX_PKT_CE] - nbuf_tx_mgmt[NBUF_TX_PKT_FREE], + nbuf_tx_mgmt[NBUF_TX_PKT_FREE]); +} + +/** + * cdf_nbuf_tx_desc_count_update() - Updates the layer packet counter + * @packet_type : packet type either mgmt/data + * @current_state : layer at which the packet currently present + * + * Return: none + */ +static inline void cdf_nbuf_tx_desc_count_update(uint8_t packet_type, + uint8_t current_state) +{ + switch (packet_type) { + case NBUF_TX_PKT_MGMT_TRACK: + nbuf_tx_mgmt[current_state]++; + break; + case NBUF_TX_PKT_DATA_TRACK: + nbuf_tx_data[current_state]++; + break; + default: + break; + } +} + +/** + * cdf_nbuf_tx_desc_count_clear() - Clears packet counter for both data, mgmt + * + * Return: none + */ +void cdf_nbuf_tx_desc_count_clear(void) +{ + memset(nbuf_tx_mgmt, 0, sizeof(nbuf_tx_mgmt)); + memset(nbuf_tx_data, 0, sizeof(nbuf_tx_data)); +} + +/** + * cdf_nbuf_set_state() - Updates the packet state + * @nbuf: network buffer + * @current_state : layer at which the packet currently is + * + * This function updates the packet state to the layer at which the packet + * currently is + * + * Return: none + */ +void cdf_nbuf_set_state(cdf_nbuf_t nbuf, uint8_t current_state) +{ + /* + * Only Mgmt, Data Packets are tracked. WMI messages + * such as scan commands are not tracked + */ + uint8_t packet_type; + packet_type = NBUF_GET_PACKET_TRACK(nbuf); + + if ((packet_type != NBUF_TX_PKT_DATA_TRACK) && + (packet_type != NBUF_TX_PKT_MGMT_TRACK)) { + return; + } + NBUF_SET_PACKET_STATE(nbuf, current_state); + cdf_nbuf_tx_desc_count_update(packet_type, + current_state); +} + +cdf_nbuf_trace_update_t trace_update_cb = NULL; + +/** + * __cdf_nbuf_alloc() - Allocate nbuf + * @hdl: Device handle + * @size: Netbuf requested size + * @reserve: Reserve + * @align: Align + * @prio: Priority + * + * This allocates an nbuf aligns if needed and reserves some space in the front, + * since the reserve is done after alignment the reserve value if being + * unaligned will result in an unaligned address. + * + * Return: nbuf or %NULL if no memory + */ +struct sk_buff *__cdf_nbuf_alloc(cdf_device_t osdev, size_t size, int reserve, + int align, int prio) +{ + struct sk_buff *skb; + unsigned long offset; + + if (align) + size += (align - 1); + + skb = dev_alloc_skb(size); + + if (!skb) { + pr_err("ERROR:NBUF alloc failed\n"); + return NULL; + } + memset(skb->cb, 0x0, sizeof(skb->cb)); + + /* + * The default is for netbuf fragments to be interpreted + * as wordstreams rather than bytestreams. + * Set the CVG_NBUF_MAX_EXTRA_FRAGS+1 wordstream_flags bits, + * to provide this default. + */ + NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) = + (1 << (CVG_NBUF_MAX_EXTRA_FRAGS + 1)) - 1; + + /* + * XXX:how about we reserve first then align + * Align & make sure that the tail & data are adjusted properly + */ + + if (align) { + offset = ((unsigned long)skb->data) % align; + if (offset) + skb_reserve(skb, align - offset); + } + + /* + * NOTE:alloc doesn't take responsibility if reserve unaligns the data + * pointer + */ + skb_reserve(skb, reserve); + + return skb; +} + +/** + * __cdf_nbuf_free() - free the nbuf its interrupt safe + * @skb: Pointer to network buffer + * + * Return: none + */ +void __cdf_nbuf_free(struct sk_buff *skb) +{ + if ((NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID) && NBUF_CALLBACK_FN(skb)) + NBUF_CALLBACK_FN_EXEC(skb); + else + dev_kfree_skb_any(skb); +} + +/** + * __cdf_nbuf_map() - get the dma map of the nbuf + * @osdev: OS device + * @bmap: Bitmap + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: CDF_STATUS + */ +CDF_STATUS +__cdf_nbuf_map(cdf_device_t osdev, struct sk_buff *skb, cdf_dma_dir_t dir) +{ +#ifdef CDF_OS_DEBUG + struct skb_shared_info *sh = skb_shinfo(skb); +#endif + cdf_assert((dir == CDF_DMA_TO_DEVICE) + || (dir == CDF_DMA_FROM_DEVICE)); + + /* + * Assume there's only a single fragment. + * To support multiple fragments, it would be necessary to change + * cdf_nbuf_t to be a separate object that stores meta-info + * (including the bus address for each fragment) and a pointer + * to the underlying sk_buff. + */ + cdf_assert(sh->nr_frags == 0); + + return __cdf_nbuf_map_single(osdev, skb, dir); + + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_nbuf_unmap() - to unmap a previously mapped buf + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: none + */ +void +__cdf_nbuf_unmap(cdf_device_t osdev, struct sk_buff *skb, cdf_dma_dir_t dir) +{ + cdf_assert((dir == CDF_DMA_TO_DEVICE) + || (dir == CDF_DMA_FROM_DEVICE)); + + cdf_assert(((dir == CDF_DMA_TO_DEVICE) + || (dir == CDF_DMA_FROM_DEVICE))); + /* + * Assume there's a single fragment. + * If this is not true, the assertion in __cdf_nbuf_map will catch it. + */ + __cdf_nbuf_unmap_single(osdev, skb, dir); +} + +/** + * __cdf_nbuf_map_single() - dma map of the nbuf + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: CDF_STATUS + */ +CDF_STATUS +__cdf_nbuf_map_single(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ + uint32_t paddr_lo; + +/* tempory hack for simulation */ +#ifdef A_SIMOS_DEVHOST + NBUF_MAPPED_PADDR_LO(buf) = paddr_lo = (uint32_t) buf->data; + return CDF_STATUS_SUCCESS; +#else + /* assume that the OS only provides a single fragment */ + NBUF_MAPPED_PADDR_LO(buf) = paddr_lo = + dma_map_single(osdev->dev, buf->data, + skb_end_pointer(buf) - buf->data, dir); + return dma_mapping_error(osdev->dev, paddr_lo) ? + CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS; +#endif /* #ifdef A_SIMOS_DEVHOST */ +} + +/** + * __cdf_nbuf_unmap_single() - dma unmap nbuf + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: none + */ +void +__cdf_nbuf_unmap_single(cdf_device_t osdev, cdf_nbuf_t buf, cdf_dma_dir_t dir) +{ +#if !defined(A_SIMOS_DEVHOST) + dma_unmap_single(osdev->dev, NBUF_MAPPED_PADDR_LO(buf), + skb_end_pointer(buf) - buf->data, dir); +#endif /* #if !defined(A_SIMOS_DEVHOST) */ +} + +/** + * __cdf_nbuf_set_rx_cksum() - set rx checksum + * @skb: Pointer to network buffer + * @cksum: Pointer to checksum value + * + * Return: CDF_STATUS + */ +CDF_STATUS +__cdf_nbuf_set_rx_cksum(struct sk_buff *skb, cdf_nbuf_rx_cksum_t *cksum) +{ + switch (cksum->l4_result) { + case CDF_NBUF_RX_CKSUM_NONE: + skb->ip_summed = CHECKSUM_NONE; + break; + case CDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + case CDF_NBUF_RX_CKSUM_TCP_UDP_HW: + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = cksum->val; + break; + default: + pr_err("ADF_NET:Unknown checksum type\n"); + cdf_assert(0); + return CDF_STATUS_E_NOSUPPORT; + } + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_nbuf_get_tx_cksum() - get tx checksum + * @skb: Pointer to network buffer + * + * Return: TX checksum value + */ +cdf_nbuf_tx_cksum_t __cdf_nbuf_get_tx_cksum(struct sk_buff *skb) +{ + switch (skb->ip_summed) { + case CHECKSUM_NONE: + return CDF_NBUF_TX_CKSUM_NONE; + case CHECKSUM_PARTIAL: + /* XXX ADF and Linux checksum don't map with 1-to-1. This is + * not 100% correct */ + return CDF_NBUF_TX_CKSUM_TCP_UDP; + case CHECKSUM_COMPLETE: + return CDF_NBUF_TX_CKSUM_TCP_UDP_IP; + default: + return CDF_NBUF_TX_CKSUM_NONE; + } +} + +/** + * __cdf_nbuf_get_tid() - get tid + * @skb: Pointer to network buffer + * + * Return: tid + */ +uint8_t __cdf_nbuf_get_tid(struct sk_buff *skb) +{ + return skb->priority; +} + +/** + * __cdf_nbuf_set_tid() - set tid + * @skb: Pointer to network buffer + * + * Return: none + */ +void __cdf_nbuf_set_tid(struct sk_buff *skb, uint8_t tid) +{ + skb->priority = tid; +} + +/** + * __cdf_nbuf_set_tid() - set tid + * @skb: Pointer to network buffer + * + * Return: none + */ +uint8_t __cdf_nbuf_get_exemption_type(struct sk_buff *skb) +{ + return CDF_NBUF_EXEMPT_NO_EXEMPTION; +} + +/** + * __cdf_nbuf_reg_trace_cb() - register trace callback + * @cb_func_ptr: Pointer to trace callback function + * + * Return: none + */ +void __cdf_nbuf_reg_trace_cb(cdf_nbuf_trace_update_t cb_func_ptr) +{ + trace_update_cb = cb_func_ptr; + return; +} + +#ifdef QCA_PKT_PROTO_TRACE +/** + * __cdf_nbuf_trace_update() - update trace event + * @skb: Pointer to network buffer + * @event_string: Pointer to trace callback function + * + * Return: none + */ +void __cdf_nbuf_trace_update(struct sk_buff *buf, char *event_string) +{ + char string_buf[NBUF_PKT_TRAC_MAX_STRING]; + + if ((!trace_update_cb) || (!event_string)) + return; + + if (!cdf_nbuf_trace_get_proto_type(buf)) + return; + + /* Buffer over flow */ + if (NBUF_PKT_TRAC_MAX_STRING <= + (cdf_str_len(event_string) + NBUF_PKT_TRAC_PROTO_STRING)) { + return; + } + + cdf_mem_zero(string_buf, NBUF_PKT_TRAC_MAX_STRING); + cdf_mem_copy(string_buf, event_string, cdf_str_len(event_string)); + if (NBUF_PKT_TRAC_TYPE_EAPOL & cdf_nbuf_trace_get_proto_type(buf)) { + cdf_mem_copy(string_buf + cdf_str_len(event_string), + "EPL", NBUF_PKT_TRAC_PROTO_STRING); + } else if (NBUF_PKT_TRAC_TYPE_DHCP & cdf_nbuf_trace_get_proto_type(buf)) { + cdf_mem_copy(string_buf + cdf_str_len(event_string), + "DHC", NBUF_PKT_TRAC_PROTO_STRING); + } else if (NBUF_PKT_TRAC_TYPE_MGMT_ACTION & + cdf_nbuf_trace_get_proto_type(buf)) { + cdf_mem_copy(string_buf + cdf_str_len(event_string), + "MACT", NBUF_PKT_TRAC_PROTO_STRING); + } + + trace_update_cb(string_buf); + return; +} +#endif /* QCA_PKT_PROTO_TRACE */ + +#ifdef MEMORY_DEBUG +#define CDF_NET_BUF_TRACK_MAX_SIZE (1024) + +/** + * struct cdf_nbuf_track_t - Network buffer track structure + * + * @p_next: Pointer to next + * @net_buf: Pointer to network buffer + * @file_name: File name + * @line_num: Line number + * @size: Size + */ +struct cdf_nbuf_track_t { + struct cdf_nbuf_track_t *p_next; + cdf_nbuf_t net_buf; + uint8_t *file_name; + uint32_t line_num; + size_t size; +}; + +spinlock_t g_cdf_net_buf_track_lock; +typedef struct cdf_nbuf_track_t CDF_NBUF_TRACK; + +CDF_NBUF_TRACK *gp_cdf_net_buf_track_tbl[CDF_NET_BUF_TRACK_MAX_SIZE]; + +/** + * cdf_net_buf_debug_init() - initialize network buffer debug functionality + * + * CDF network buffer debug feature tracks all SKBs allocated by WLAN driver + * in a hash table and when driver is unloaded it reports about leaked SKBs. + * WLAN driver module whose allocated SKB is freed by network stack are + * suppose to call cdf_net_buf_debug_release_skb() such that the SKB is not + * reported as memory leak. + * + * Return: none + */ +void cdf_net_buf_debug_init(void) +{ + uint32_t i; + unsigned long irq_flag; + + spin_lock_init(&g_cdf_net_buf_track_lock); + + spin_lock_irqsave(&g_cdf_net_buf_track_lock, irq_flag); + + for (i = 0; i < CDF_NET_BUF_TRACK_MAX_SIZE; i++) + gp_cdf_net_buf_track_tbl[i] = NULL; + + spin_unlock_irqrestore(&g_cdf_net_buf_track_lock, irq_flag); + + return; +} + +/** + * cdf_net_buf_debug_init() - exit network buffer debug functionality + * + * Exit network buffer tracking debug functionality and log SKB memory leaks + * + * Return: none + */ +void cdf_net_buf_debug_exit(void) +{ + uint32_t i; + unsigned long irq_flag; + CDF_NBUF_TRACK *p_node; + CDF_NBUF_TRACK *p_prev; + + spin_lock_irqsave(&g_cdf_net_buf_track_lock, irq_flag); + + for (i = 0; i < CDF_NET_BUF_TRACK_MAX_SIZE; i++) { + p_node = gp_cdf_net_buf_track_tbl[i]; + while (p_node) { + p_prev = p_node; + p_node = p_node->p_next; + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "SKB buf memory Leak@ File %s, @Line %d, size %zu\n", + p_prev->file_name, p_prev->line_num, + p_prev->size); + } + } + + spin_unlock_irqrestore(&g_cdf_net_buf_track_lock, irq_flag); + + return; +} + +/** + * cdf_net_buf_debug_clean() - clean up network buffer debug functionality + * + * Return: none + */ +void cdf_net_buf_debug_clean(void) +{ + uint32_t i; + unsigned long irq_flag; + CDF_NBUF_TRACK *p_node; + CDF_NBUF_TRACK *p_prev; + + spin_lock_irqsave(&g_cdf_net_buf_track_lock, irq_flag); + + for (i = 0; i < CDF_NET_BUF_TRACK_MAX_SIZE; i++) { + p_node = gp_cdf_net_buf_track_tbl[i]; + while (p_node) { + p_prev = p_node; + p_node = p_node->p_next; + cdf_mem_free(p_prev); + } + } + + spin_unlock_irqrestore(&g_cdf_net_buf_track_lock, irq_flag); + + return; +} + +/** + * cdf_net_buf_debug_hash() - hash network buffer pointer + * + * Return: hash value + */ +uint32_t cdf_net_buf_debug_hash(cdf_nbuf_t net_buf) +{ + uint32_t i; + + i = (uint32_t) ((uintptr_t) net_buf & (CDF_NET_BUF_TRACK_MAX_SIZE - 1)); + + return i; +} + +/** + * cdf_net_buf_debug_look_up() - look up network buffer in debug hash table + * + * Return: If skb is found in hash table then return pointer to network buffer + * else return %NULL + */ +CDF_NBUF_TRACK *cdf_net_buf_debug_look_up(cdf_nbuf_t net_buf) +{ + uint32_t i; + CDF_NBUF_TRACK *p_node; + + i = cdf_net_buf_debug_hash(net_buf); + p_node = gp_cdf_net_buf_track_tbl[i]; + + while (p_node) { + if (p_node->net_buf == net_buf) + return p_node; + p_node = p_node->p_next; + } + + return NULL; + +} + +/** + * cdf_net_buf_debug_add_node() - store skb in debug hash table + * + * Return: none + */ +void cdf_net_buf_debug_add_node(cdf_nbuf_t net_buf, size_t size, + uint8_t *file_name, uint32_t line_num) +{ + uint32_t i; + unsigned long irq_flag; + CDF_NBUF_TRACK *p_node; + + spin_lock_irqsave(&g_cdf_net_buf_track_lock, irq_flag); + + i = cdf_net_buf_debug_hash(net_buf); + p_node = cdf_net_buf_debug_look_up(net_buf); + + if (p_node) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Double allocation of skb ! Already allocated from %s %d", + p_node->file_name, p_node->line_num); + CDF_ASSERT(0); + goto done; + } else { + p_node = (CDF_NBUF_TRACK *) cdf_mem_malloc(sizeof(*p_node)); + if (p_node) { + p_node->net_buf = net_buf; + p_node->file_name = file_name; + p_node->line_num = line_num; + p_node->size = size; + p_node->p_next = gp_cdf_net_buf_track_tbl[i]; + gp_cdf_net_buf_track_tbl[i] = p_node; + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Mem alloc failed ! Could not track skb from %s %d of size %zu", + file_name, line_num, size); + CDF_ASSERT(0); + } + } + +done: + spin_unlock_irqrestore(&g_cdf_net_buf_track_lock, irq_flag); + + return; +} + +/** + * cdf_net_buf_debug_delete_node() - remove skb from debug hash table + * + * Return: none + */ +void cdf_net_buf_debug_delete_node(cdf_nbuf_t net_buf) +{ + uint32_t i; + bool found = false; + CDF_NBUF_TRACK *p_head; + CDF_NBUF_TRACK *p_node; + unsigned long irq_flag; + CDF_NBUF_TRACK *p_prev; + + spin_lock_irqsave(&g_cdf_net_buf_track_lock, irq_flag); + + i = cdf_net_buf_debug_hash(net_buf); + p_head = gp_cdf_net_buf_track_tbl[i]; + + /* Unallocated SKB */ + if (!p_head) + goto done; + + p_node = p_head; + /* Found at head of the table */ + if (p_head->net_buf == net_buf) { + gp_cdf_net_buf_track_tbl[i] = p_node->p_next; + cdf_mem_free((void *)p_node); + found = true; + goto done; + } + + /* Search in collision list */ + while (p_node) { + p_prev = p_node; + p_node = p_node->p_next; + if ((NULL != p_node) && (p_node->net_buf == net_buf)) { + p_prev->p_next = p_node->p_next; + cdf_mem_free((void *)p_node); + found = true; + break; + } + } + +done: + if (!found) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Unallocated buffer ! Double free of net_buf %p ?", + net_buf); + CDF_ASSERT(0); + } + + spin_unlock_irqrestore(&g_cdf_net_buf_track_lock, irq_flag); + + return; +} + +/** + * cdf_net_buf_debug_release_skb() - release skb to avoid memory leak + * + * WLAN driver module whose allocated SKB is freed by network stack are + * suppose to call this API before returning SKB to network stack such + * that the SKB is not reported as memory leak. + * + * Return: none + */ +void cdf_net_buf_debug_release_skb(cdf_nbuf_t net_buf) +{ + cdf_net_buf_debug_delete_node(net_buf); +} + +#endif /*MEMORY_DEBUG */ +#if defined(FEATURE_TSO) + +struct cdf_tso_cmn_seg_info_t { + uint16_t ethproto; + uint16_t ip_tcp_hdr_len; + uint16_t l2_len; + unsigned char *eit_hdr; + unsigned int eit_hdr_len; + struct tcphdr *tcphdr; + uint16_t ipv4_csum_en; + uint16_t tcp_ipv4_csum_en; + uint16_t tcp_ipv6_csum_en; + uint16_t ip_id; + uint32_t tcp_seq_num; +}; + +/** + * __cdf_nbuf_get_tso_cmn_seg_info() - get TSO common + * information + * + * Get the TSO information that is common across all the TCP + * segments of the jumbo packet + * + * Return: 0 - success 1 - failure + */ +uint8_t __cdf_nbuf_get_tso_cmn_seg_info(struct sk_buff *skb, + struct cdf_tso_cmn_seg_info_t *tso_info) +{ + /* Get ethernet type and ethernet header length */ + tso_info->ethproto = vlan_get_protocol(skb); + + /* Determine whether this is an IPv4 or IPv6 packet */ + if (tso_info->ethproto == htons(ETH_P_IP)) { /* IPv4 */ + /* for IPv4, get the IP ID and enable TCP and IP csum */ + struct iphdr *ipv4_hdr = ip_hdr(skb); + tso_info->ip_id = ntohs(ipv4_hdr->id); + tso_info->ipv4_csum_en = 1; + tso_info->tcp_ipv4_csum_en = 1; + if (cdf_unlikely(ipv4_hdr->protocol != IPPROTO_TCP)) { + cdf_print("TSO IPV4 proto 0x%x not TCP\n", + ipv4_hdr->protocol); + return 1; + } + } else if (tso_info->ethproto == htons(ETH_P_IPV6)) { /* IPv6 */ + /* for IPv6, enable TCP csum. No IP ID or IP csum */ + tso_info->tcp_ipv6_csum_en = 1; + } else { + cdf_print("TSO: ethertype 0x%x is not supported!\n", + tso_info->ethproto); + return 1; + } + + tso_info->l2_len = (skb_network_header(skb) - skb_mac_header(skb)); + tso_info->tcphdr = tcp_hdr(skb); + tso_info->tcp_seq_num = ntohl(tcp_hdr(skb)->seq); + /* get pointer to the ethernet + IP + TCP header and their length */ + tso_info->eit_hdr = skb->data; + tso_info->eit_hdr_len = (skb_transport_header(skb) + - skb_mac_header(skb)) + tcp_hdrlen(skb); + tso_info->ip_tcp_hdr_len = tso_info->eit_hdr_len - tso_info->l2_len; + return 0; +} + +/** + * __cdf_nbuf_get_tso_info() - function to divide a TSO nbuf + * into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: number of TSO segments + */ +uint32_t __cdf_nbuf_get_tso_info(cdf_device_t osdev, struct sk_buff *skb, + struct cdf_tso_info_t *tso_info) +{ + /* common accross all segments */ + struct cdf_tso_cmn_seg_info_t tso_cmn_info; + + /* segment specific */ + char *tso_frag_vaddr; + uint32_t tso_frag_paddr_32 = 0; + uint32_t num_seg = 0; + struct cdf_tso_seg_elem_t *curr_seg; + const struct skb_frag_struct *frag = NULL; + uint32_t tso_frag_len = 0; /* tso segment's fragment length*/ + uint32_t skb_frag_len = 0; /* skb's fragment length (continous memory)*/ + uint32_t foffset = 0; /* offset into the skb's fragment */ + uint32_t skb_proc = 0; /* bytes of the skb that have been processed*/ + uint32_t tso_seg_size = skb_shinfo(skb)->gso_size; + + memset(&tso_cmn_info, 0x0, sizeof(tso_cmn_info)); + + if (cdf_unlikely(__cdf_nbuf_get_tso_cmn_seg_info(skb, &tso_cmn_info))) { + cdf_print("TSO: error getting common segment info\n"); + return 0; + } + curr_seg = tso_info->tso_seg_list; + + /* length of the first chunk of data in the skb */ + skb_proc = skb_frag_len = skb->len - skb->data_len; + + /* the 0th tso segment's 0th fragment always contains the EIT header */ + /* update the remaining skb fragment length and TSO segment length */ + skb_frag_len -= tso_cmn_info.eit_hdr_len; + skb_proc -= tso_cmn_info.eit_hdr_len; + + /* get the address to the next tso fragment */ + tso_frag_vaddr = skb->data + tso_cmn_info.eit_hdr_len; + /* get the length of the next tso fragment */ + tso_frag_len = min(skb_frag_len, tso_seg_size); + tso_frag_paddr_32 = dma_map_single(osdev->dev, + tso_frag_vaddr, tso_frag_len, DMA_TO_DEVICE); + + num_seg = tso_info->num_segs; + tso_info->num_segs = 0; + tso_info->is_tso = 1; + + while (num_seg && curr_seg) { + int i = 1; /* tso fragment index */ + int j = 0; /* skb fragment index */ + uint8_t more_tso_frags = 1; + uint8_t from_frag_table = 0; + + /* Initialize the flags to 0 */ + memset(&curr_seg->seg, 0x0, sizeof(curr_seg->seg)); + tso_info->num_segs++; + + /* The following fields remain the same across all segments of + a jumbo packet */ + curr_seg->seg.tso_flags.tso_enable = 1; + curr_seg->seg.tso_flags.partial_checksum_en = 0; + curr_seg->seg.tso_flags.ipv4_checksum_en = + tso_cmn_info.ipv4_csum_en; + curr_seg->seg.tso_flags.tcp_ipv6_checksum_en = + tso_cmn_info.tcp_ipv6_csum_en; + curr_seg->seg.tso_flags.tcp_ipv4_checksum_en = + tso_cmn_info.tcp_ipv4_csum_en; + curr_seg->seg.tso_flags.l2_len = 0; + curr_seg->seg.tso_flags.tcp_flags_mask = 0x1FF; + curr_seg->seg.num_frags = 0; + + /* The following fields change for the segments */ + curr_seg->seg.tso_flags.ip_id = tso_cmn_info.ip_id; + tso_cmn_info.ip_id++; + + curr_seg->seg.tso_flags.syn = tso_cmn_info.tcphdr->syn; + curr_seg->seg.tso_flags.rst = tso_cmn_info.tcphdr->rst; + curr_seg->seg.tso_flags.psh = tso_cmn_info.tcphdr->psh; + curr_seg->seg.tso_flags.ack = tso_cmn_info.tcphdr->ack; + curr_seg->seg.tso_flags.urg = tso_cmn_info.tcphdr->urg; + curr_seg->seg.tso_flags.ece = tso_cmn_info.tcphdr->ece; + curr_seg->seg.tso_flags.cwr = tso_cmn_info.tcphdr->cwr; + + curr_seg->seg.tso_flags.tcp_seq_num = tso_cmn_info.tcp_seq_num; + + /* First fragment for each segment always contains the ethernet, + IP and TCP header */ + curr_seg->seg.tso_frags[0].vaddr = tso_cmn_info.eit_hdr; + curr_seg->seg.tso_frags[0].length = tso_cmn_info.eit_hdr_len; + tso_info->total_len = curr_seg->seg.tso_frags[0].length; + curr_seg->seg.tso_frags[0].paddr_low_32 = + dma_map_single(osdev->dev, tso_cmn_info.eit_hdr, + tso_cmn_info.eit_hdr_len, DMA_TO_DEVICE); + curr_seg->seg.tso_flags.ip_len = tso_cmn_info.ip_tcp_hdr_len; + curr_seg->seg.num_frags++; + + while (more_tso_frags) { + curr_seg->seg.tso_frags[i].vaddr = tso_frag_vaddr; + curr_seg->seg.tso_frags[i].length = tso_frag_len; + tso_info->total_len += + curr_seg->seg.tso_frags[i].length; + curr_seg->seg.tso_flags.ip_len += + curr_seg->seg.tso_frags[i].length; + curr_seg->seg.num_frags++; + skb_proc = skb_proc - curr_seg->seg.tso_frags[i].length; + + /* increment the TCP sequence number */ + tso_cmn_info.tcp_seq_num += tso_frag_len; + curr_seg->seg.tso_frags[i].paddr_upper_16 = 0; + curr_seg->seg.tso_frags[i].paddr_low_32 = + tso_frag_paddr_32; + + /* if there is no more data left in the skb */ + if (!skb_proc) + return tso_info->num_segs; + + /* get the next payload fragment information */ + /* check if there are more fragments in this segment */ + if ((tso_seg_size - tso_frag_len)) { + more_tso_frags = 1; + i++; + } else { + more_tso_frags = 0; + /* reset i and the tso payload size */ + i = 1; + tso_seg_size = skb_shinfo(skb)->gso_size; + } + + /* if the next fragment is contiguous */ + if (tso_frag_len < skb_frag_len) { + skb_frag_len = skb_frag_len - tso_frag_len; + tso_frag_len = min(skb_frag_len, tso_seg_size); + tso_frag_vaddr = tso_frag_vaddr + tso_frag_len; + if (from_frag_table) { + tso_frag_paddr_32 = + skb_frag_dma_map(osdev->dev, + frag, foffset, + tso_frag_len, + DMA_TO_DEVICE); + } else { + tso_frag_paddr_32 = + dma_map_single(osdev->dev, + tso_frag_vaddr, + tso_frag_len, + DMA_TO_DEVICE); + } + } else { /* the next fragment is not contiguous */ + tso_frag_len = min(skb_frag_len, tso_seg_size); + frag = &skb_shinfo(skb)->frags[j]; + skb_frag_len = skb_frag_size(frag); + + tso_frag_vaddr = skb_frag_address(frag); + tso_frag_paddr_32 = skb_frag_dma_map(osdev->dev, + frag, 0, tso_frag_len, + DMA_TO_DEVICE); + foffset += tso_frag_len; + from_frag_table = 1; + j++; + } + } + num_seg--; + /* if TCP FIN flag was set, set it in the last segment */ + if (!num_seg) + curr_seg->seg.tso_flags.fin = tso_cmn_info.tcphdr->fin; + + curr_seg = curr_seg->next; + } + return tso_info->num_segs; +} + +/** + * __cdf_nbuf_get_tso_num_seg() - function to divide a TSO nbuf + * into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: 0 - success, 1 - failure + */ +uint32_t __cdf_nbuf_get_tso_num_seg(struct sk_buff *skb) +{ + uint32_t gso_size, tmp_len, num_segs = 0; + + gso_size = skb_shinfo(skb)->gso_size; + tmp_len = skb->len - ((skb_transport_header(skb) - skb_mac_header(skb)) + + tcp_hdrlen(skb)); + while (tmp_len) { + num_segs++; + if (tmp_len > gso_size) + tmp_len -= gso_size; + else + break; + } + return num_segs; +} + +struct sk_buff *__cdf_nbuf_inc_users(struct sk_buff *skb) +{ + atomic_inc(&skb->users); + return skb; +} + +#endif /* FEATURE_TSO */ diff --git a/core/cdf/src/cdf_threads.c b/core/cdf/src/cdf_threads.c new file mode 100644 index 0000000000..6b408d5678 --- /dev/null +++ b/core/cdf/src/cdf_threads.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_threads + * + * Connectivity driver framework (CDF) thread APIs + * + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +/** + * cdf_sleep() - sleep + * @msInterval : Number of milliseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return: nothing + */ +void cdf_sleep(uint32_t msInterval) +{ + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return; + } + msleep_interruptible(msInterval); +} + +/** + * cdf_sleep_us() - sleep + * @usInterval : Number of microseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return : nothing + */ +void cdf_sleep_us(uint32_t usInterval) +{ + unsigned long timeout = usecs_to_jiffies(usInterval) + 1; + if (in_interrupt()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return; + } + + while (timeout && !signal_pending(current)) + timeout = schedule_timeout_interruptible(timeout); +} + +/** + * cdf_busy_wait() - busy wait + * @usInterval : Number of microseconds to busy wait. + * + * This function places the current thread in busy wait until the specified + * time out interval elapses. If the interval is greater than 50us on WM, the + * behaviour is undefined. + * + * Return : nothing + */ +void cdf_busy_wait(uint32_t usInterval) +{ + udelay(usInterval); +} diff --git a/core/cdf/src/cdf_trace.c b/core/cdf/src/cdf_trace.c new file mode 100644 index 0000000000..3d59c53d27 --- /dev/null +++ b/core/cdf/src/cdf_trace.c @@ -0,0 +1,1018 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cdf_trace + * + * Connectivity driver framework (CDF) trace APIs + * + * Trace, logging, and debugging definitions and APIs + * + */ + +/* Include Files */ +#include +#include +#include +#include "cdf_time.h" +/* Preprocessor definitions and constants */ + +#define CDF_TRACE_BUFFER_SIZE (512) + +/* macro to map cdf trace levels into the bitmask */ +#define CDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level))) + +typedef struct { + /* Trace level for a module, as a bitmask. The bits in this mask + * are ordered by CDF_TRACE_LEVEL. For example, each bit represents + * one of the bits in CDF_TRACE_LEVEL that may be turned on to have + * traces at that level logged, i.e. if CDF_TRACE_LEVEL_ERROR is + * == 2, then if bit 2 (low order) is turned ON, then ERROR traces + * will be printed to the trace log. + * Note that all bits turned OFF means no traces + */ + uint16_t moduleTraceLevel; + + /* 3 character string name for the module */ + unsigned char moduleNameStr[4]; /* 3 chars plus the NULL */ +} moduleTraceInfo; + +#define CDF_DEFAULT_TRACE_LEVEL \ + ((1 << CDF_TRACE_LEVEL_FATAL) | (1 << CDF_TRACE_LEVEL_ERROR)) + +/* Array of static data that contains all of the per module trace + * information. This includes the trace level for the module and + * the 3 character 'name' of the module for marking the trace logs + */ +moduleTraceInfo g_cdf_trace_info[CDF_MODULE_ID_MAX] = { + [CDF_MODULE_ID_TLSHIM] = {CDF_DEFAULT_TRACE_LEVEL, "DP"}, + [CDF_MODULE_ID_WMI] = {CDF_DEFAULT_TRACE_LEVEL, "WMI"}, + [CDF_MODULE_ID_HDD] = {CDF_DEFAULT_TRACE_LEVEL, "HDD"}, + [CDF_MODULE_ID_SME] = {CDF_DEFAULT_TRACE_LEVEL, "SME"}, + [CDF_MODULE_ID_PE] = {CDF_DEFAULT_TRACE_LEVEL, "PE "}, + [CDF_MODULE_ID_WMA] = {CDF_DEFAULT_TRACE_LEVEL, "WMA"}, + [CDF_MODULE_ID_SYS] = {CDF_DEFAULT_TRACE_LEVEL, "SYS"}, + [CDF_MODULE_ID_CDF] = {CDF_DEFAULT_TRACE_LEVEL, "CDF"}, + [CDF_MODULE_ID_SAP] = {CDF_DEFAULT_TRACE_LEVEL, "SAP"}, + [CDF_MODULE_ID_HDD_SOFTAP] = {CDF_DEFAULT_TRACE_LEVEL, "HSP"}, + [CDF_MODULE_ID_HDD_DATA] = {CDF_DEFAULT_TRACE_LEVEL, "HDP"}, + [CDF_MODULE_ID_HDD_SAP_DATA] = {CDF_DEFAULT_TRACE_LEVEL, "SDP"}, + [CDF_MODULE_ID_BMI] = {CDF_DEFAULT_TRACE_LEVEL, "BMI"}, + [CDF_MODULE_ID_HIF] = {CDF_DEFAULT_TRACE_LEVEL, "HIF"}, + [CDF_MODULE_ID_TXRX] = {CDF_DEFAULT_TRACE_LEVEL, "TRX"}, + [CDF_MODULE_ID_HTT] = {CDF_DEFAULT_TRACE_LEVEL, "HTT"}, +}; + +/* Static and Global variables */ +static spinlock_t ltrace_lock; + +static cdf_trace_record_t g_cdf_trace_tbl[MAX_CDF_TRACE_RECORDS]; +/* global cdf trace data */ +static t_cdf_trace_data g_cdf_trace_data; +/* + * all the call back functions for dumping MTRACE messages from ring buffer + * are stored in cdf_trace_cb_table,these callbacks are initialized during init + * only so, we will make a copy of these call back functions and maintain in to + * cdf_trace_restore_cb_table. Incase if we make modifications to + * cdf_trace_cb_table, we can certainly retrieve all the call back functions + * back from Restore Table + */ +static tp_cdf_trace_cb cdf_trace_cb_table[CDF_MODULE_ID_MAX]; +static tp_cdf_trace_cb cdf_trace_restore_cb_table[CDF_MODULE_ID_MAX]; + +/* Static and Global variables */ +static spinlock_t l_dp_trace_lock; + +static struct cdf_dp_trace_record_s + g_cdf_dp_trace_tbl[MAX_CDF_DP_TRACE_RECORDS]; + +/* + * all the options to configure/control DP trace are + * defined in this structure + */ +static struct s_cdf_dp_trace_data g_cdf_dp_trace_data; +/* + * all the call back functions for dumping DPTRACE messages from ring buffer + * are stored in cdf_dp_trace_cb_table, callbacks are initialized during init + */ +static tp_cdf_dp_trace_cb cdf_dp_trace_cb_table[CDF_DP_TRACE_MAX]; + +/** + * cdf_trace_set_level() - Set the trace level for a particular module + * @level : trace level + * + * Trace level is a member of the CDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * + * This is an external API that allows trace levels to be set for each module. + * + * Return: nothing + */ +void cdf_trace_set_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level) +{ + /* make sure the caller is passing in a valid LEVEL */ + if (level >= CDF_TRACE_LEVEL_MAX) { + pr_err("%s: Invalid trace level %d passed in!\n", __func__, + level); + return; + } + + /* Treat 'none' differently. NONE means we have to run off all + * the bits in the bit mask so none of the traces appear. Anything + * other than 'none' means we need to turn ON a bit in the bitmask + */ + if (CDF_TRACE_LEVEL_NONE == level) + g_cdf_trace_info[module].moduleTraceLevel = + CDF_TRACE_LEVEL_NONE; + else + /* set the desired bit in the bit mask for the module trace + * level */ + g_cdf_trace_info[module].moduleTraceLevel |= + CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level); +} + +/** + * cdf_trace_set_module_trace_level() - Set module trace level + * @module: Module id + * @level: Trace level for a module, as a bitmask as per 'moduleTraceInfo' + * + * Sets the module trace level where the trace level is given as a bit mask + * + * Return: None + */ +void cdf_trace_set_module_trace_level(CDF_MODULE_ID module, uint32_t level) +{ + if (module < 0 || module >= CDF_MODULE_ID_MAX) { + pr_err("%s: Invalid module id %d passed\n", __func__, module); + return; + } + g_cdf_trace_info[module].moduleTraceLevel = level; +} + +void cdf_trace_set_value(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + uint8_t on) +{ + /* make sure the caller is passing in a valid LEVEL */ + if (level < 0 || level >= CDF_TRACE_LEVEL_MAX) { + pr_err("%s: Invalid trace level %d passed in!\n", __func__, + level); + return; + } + + /* make sure the caller is passing in a valid module */ + if (module < 0 || module >= CDF_MODULE_ID_MAX) { + pr_err("%s: Invalid module id %d passed in!\n", __func__, + module); + return; + } + + /* Treat 'none' differently. NONE means we have to turn off all + the bits in the bit mask so none of the traces appear */ + if (CDF_TRACE_LEVEL_NONE == level) { + g_cdf_trace_info[module].moduleTraceLevel = + CDF_TRACE_LEVEL_NONE; + } + /* Treat 'All' differently. All means we have to turn on all + the bits in the bit mask so all of the traces appear */ + else if (CDF_TRACE_LEVEL_ALL == level) { + g_cdf_trace_info[module].moduleTraceLevel = 0xFFFF; + } else { + if (on) + /* set the desired bit in the bit mask for the module + trace level */ + g_cdf_trace_info[module].moduleTraceLevel |= + CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level); + else + /* clear the desired bit in the bit mask for the module + trace level */ + g_cdf_trace_info[module].moduleTraceLevel &= + ~(CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)); + } +} + +/** + * cdf_trace_get_level() - get the trace level + * @level : trace level + * + * This is an external API that returns a bool value to signify if a + * particular trace level is set for the specified module. + * A member of the CDF_TRACE_LEVEL enumeration indicating the severity + * of the condition causing the trace message to be issued. + * + * Note that individual trace levels are the only valid values + * for this API. CDF_TRACE_LEVEL_NONE and CDF_TRACE_LEVEL_ALL + * are not valid input and will return false + * + * Return: + * false - the specified trace level for the specified module is OFF + * true - the specified trace level for the specified module is ON + */ +bool cdf_trace_get_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level) +{ + bool traceOn = false; + + if ((CDF_TRACE_LEVEL_NONE == level) || + (CDF_TRACE_LEVEL_ALL == level) || (level >= CDF_TRACE_LEVEL_MAX)) { + traceOn = false; + } else { + traceOn = (level & g_cdf_trace_info[module].moduleTraceLevel) + ? true : false; + } + + return traceOn; +} + +void cdf_snprintf(char *strBuffer, unsigned int size, char *strFormat, ...) +{ + va_list val; + + va_start(val, strFormat); + snprintf(strBuffer, size, strFormat, val); + va_end(val); +} + +#ifdef CDF_ENABLE_TRACING + +/** + * cdf_trace_msg() - externally called trace function + * @module : Module identifier a member of the CDF_MODULE_ID + * enumeration that identifies the module issuing the trace message. + * @level : Trace level a member of the CDF_TRACE_LEVEL enumeration + * indicating the severity of the condition causing the trace message + * to be issued. More severe conditions are more likely to be logged. + * @strFormat : Format string in which the message to be logged. This format + * string contains printf-like replacement parameters, which follow + * this parameter in the variable argument list. + * + * Checks the level of severity and accordingly prints the trace messages + * + * Return: nothing + * + */ +void cdf_trace_msg(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + char *strFormat, ...) +{ + char strBuffer[CDF_TRACE_BUFFER_SIZE]; + int n; + + /* Print the trace message when the desired level bit is set in + the module tracel level mask */ + if (g_cdf_trace_info[module].moduleTraceLevel & + CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)) { + /* the trace level strings in an array. these are ordered in + * the same order as the trace levels are defined in the enum + * (see CDF_TRACE_LEVEL) so we can index into this array with + * the level and get the right string. The cdf trace levels + * are... none, Fatal, Error, Warning, Info, InfoHigh, InfoMed, + * InfoLow, Debug + */ + static const char *TRACE_LEVEL_STR[] = { " ", "F ", "E ", "W ", + "I ", "IH", "IM", "IL", "D" }; + va_list val; + va_start(val, strFormat); + + /* print the prefix string into the string buffer... */ + n = snprintf(strBuffer, CDF_TRACE_BUFFER_SIZE, + "wlan: [%d:%2s:%3s] ", + in_interrupt() ? 0 : current->pid, + (char *)TRACE_LEVEL_STR[level], + (char *)g_cdf_trace_info[module].moduleNameStr); + + /* print the formatted log message after the prefix string */ + if ((n >= 0) && (n < CDF_TRACE_BUFFER_SIZE)) { + vsnprintf(strBuffer + n, CDF_TRACE_BUFFER_SIZE - n, + strFormat, val); +#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) + wlan_log_to_user(level, (char *)strBuffer, + strlen(strBuffer)); +#else + pr_err("%s\n", strBuffer); +#endif + } + va_end(val); + } +} + +void cdf_trace_display(void) +{ + CDF_MODULE_ID moduleId; + + pr_err + (" 1)FATAL 2)ERROR 3)WARN 4)INFO 5)INFO_H 6)INFO_M 7)INFO_L 8)DEBUG\n"); + for (moduleId = 0; moduleId < CDF_MODULE_ID_MAX; ++moduleId) { + pr_err + ("%2d)%s %s %s %s %s %s %s %s %s\n", + (int)moduleId, g_cdf_trace_info[moduleId].moduleNameStr, + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_FATAL)) ? "X" : + " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_ERROR)) ? "X" : + " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_WARN)) ? "X" : + " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO)) ? "X" : + " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_HIGH)) ? "X" + : " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_MED)) ? "X" + : " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_LOW)) ? "X" + : " ", + (g_cdf_trace_info[moduleId]. + moduleTraceLevel & (1 << CDF_TRACE_LEVEL_DEBUG)) ? "X" : + " "); + } +} + +/** + * cdf_trace_hex_dump() - externally called hex dump function + * @module : Module identifier a member of the CDF_MODULE_ID enumeration that + * identifies the module issuing the trace message. + * @level : Trace level a member of the CDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be + * issued. More severe conditions are more likely to be logged. + * @data : The base address of the buffer to be logged. + * @buf_len : The size of the buffer to be logged. + * + * Checks the level of severity and accordingly prints the trace messages + * + * Return : nothing + */ +void cdf_trace_hex_dump(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + void *data, int buf_len) +{ + char *buf = (char *)data; + int i; + + if (!(g_cdf_trace_info[module].moduleTraceLevel & + CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level))) + return; + + for (i = 0; (i + 15) < buf_len; i += 16) { + cdf_trace_msg(module, level, + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + buf[i], + buf[i + 1], + buf[i + 2], + buf[i + 3], + buf[i + 4], + buf[i + 5], + buf[i + 6], + buf[i + 7], + buf[i + 8], + buf[i + 9], + buf[i + 10], + buf[i + 11], + buf[i + 12], + buf[i + 13], buf[i + 14], buf[i + 15]); + } + + /* Dump the bytes in the last line */ + for (; i < buf_len; i++) + cdf_trace_msg(module, level, "%02x ", buf[i]); +} + +#endif + +/** + * cdf_trace_enable() - Enable MTRACE for specific modules + * @bitmask_of_moduleId : Bitmask according to enum of the modules. + * 32 [dec] = 0010 0000 [bin] + * 64 [dec] = 0100 0000 [bin] + * 128 [dec] = 1000 0000 [bin] + * @enable : can be true or false true implies enabling MTRACE false implies + * disabling MTRACE. + * + * Enable MTRACE for specific modules whose bits are set in bitmask and enable + * is true. if enable is false it disables MTRACE for that module. set the + * bitmask according to enum value of the modules. + * This functions will be called when you issue ioctl as mentioned following + * [iwpriv wlan0 setdumplog ]. + * - Decimal number, i.e. 64 decimal value shows only SME module, + * 128 decimal value shows only PE module, 192 decimal value shows PE and SME. + * + * + * Return : nothing + */ +void cdf_trace_enable(uint32_t bitmask_of_moduleId, uint8_t enable) +{ + int i; + if (bitmask_of_moduleId) { + for (i = 0; i < CDF_MODULE_ID_MAX; i++) { + if (((bitmask_of_moduleId >> i) & 1)) { + if (enable) { + if (NULL != + cdf_trace_restore_cb_table[i]) { + cdf_trace_cb_table[i] = + cdf_trace_restore_cb_table[i]; + } + } else { + cdf_trace_restore_cb_table[i] = + cdf_trace_cb_table[i]; + cdf_trace_cb_table[i] = NULL; + } + } + } + } else { + if (enable) { + for (i = 0; i < CDF_MODULE_ID_MAX; i++) { + if (NULL != cdf_trace_restore_cb_table[i]) { + cdf_trace_cb_table[i] = + cdf_trace_restore_cb_table[i]; + } + } + } else { + for (i = 0; i < CDF_MODULE_ID_MAX; i++) { + cdf_trace_restore_cb_table[i] = + cdf_trace_cb_table[i]; + cdf_trace_cb_table[i] = NULL; + } + } + } +} + +/** + * cdf_trace_init() - initializes cdf trace structures and variables + * + * Called immediately after cds_preopen, so that we can start recording HDD + * events ASAP. + * + * Return : nothing + */ +void cdf_trace_init(void) +{ + uint8_t i; + g_cdf_trace_data.head = INVALID_CDF_TRACE_ADDR; + g_cdf_trace_data.tail = INVALID_CDF_TRACE_ADDR; + g_cdf_trace_data.num = 0; + g_cdf_trace_data.enable = true; + g_cdf_trace_data.dumpCount = DEFAULT_CDF_TRACE_DUMP_COUNT; + g_cdf_trace_data.numSinceLastDump = 0; + + for (i = 0; i < CDF_MODULE_ID_MAX; i++) { + cdf_trace_cb_table[i] = NULL; + cdf_trace_restore_cb_table[i] = NULL; + } +} + +/** + * cdf_trace() - puts the messages in to ring-buffer + * @module : Enum of module, basically module id. + * @param : Code to be recorded + * @session : Session ID of the log + * @data : Actual message contents + * + * This function will be called from each module who wants record the messages + * in circular queue. Before calling this functions make sure you have + * registered your module with cdf through cdf_trace_register function. + * + * + * Return : nothing + */ +void cdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data) +{ + tp_cdf_trace_record rec = NULL; + unsigned long flags; + + if (!g_cdf_trace_data.enable) + return; + + /* if module is not registered, don't record for that module */ + if (NULL == cdf_trace_cb_table[module]) + return; + + /* Aquire the lock so that only one thread at a time can fill the ring + * buffer + */ + spin_lock_irqsave(<race_lock, flags); + + g_cdf_trace_data.num++; + + if (g_cdf_trace_data.num > MAX_CDF_TRACE_RECORDS) + g_cdf_trace_data.num = MAX_CDF_TRACE_RECORDS; + + if (INVALID_CDF_TRACE_ADDR == g_cdf_trace_data.head) { + /* first record */ + g_cdf_trace_data.head = 0; + g_cdf_trace_data.tail = 0; + } else { + /* queue is not empty */ + uint32_t tail = g_cdf_trace_data.tail + 1; + + if (MAX_CDF_TRACE_RECORDS == tail) + tail = 0; + + if (g_cdf_trace_data.head == tail) { + /* full */ + if (MAX_CDF_TRACE_RECORDS == ++g_cdf_trace_data.head) + g_cdf_trace_data.head = 0; + } + g_cdf_trace_data.tail = tail; + } + + rec = &g_cdf_trace_tbl[g_cdf_trace_data.tail]; + rec->code = code; + rec->session = session; + rec->data = data; + rec->time = cdf_get_log_timestamp(); + rec->module = module; + rec->pid = (in_interrupt() ? 0 : current->pid); + g_cdf_trace_data.numSinceLastDump++; + spin_unlock_irqrestore(<race_lock, flags); +} + +/** + * cdf_trace_spin_lock_init() - initializes the lock variable before use + * + * This function will be called from cds_alloc_global_context, we will have lock + * available to use ASAP + * + * Return : nothing + */ +CDF_STATUS cdf_trace_spin_lock_init(void) +{ + spin_lock_init(<race_lock); + + return CDF_STATUS_SUCCESS; +} + +/** + * cdf_trace_register() - registers the call back functions + * @moduleID - enum value of module + * @cdf_trace_callback - call back functions to display the messages in + * particular format. + * + * Registers the call back functions to display the messages in particular + * format mentioned in these call back functions. This functions should be + * called by interested module in their init part as we will be ready to + * register as soon as modules are up. + * + * Return : nothing + */ +void cdf_trace_register(CDF_MODULE_ID moduleID, + tp_cdf_trace_cb cdf_trace_callback) +{ + cdf_trace_cb_table[moduleID] = cdf_trace_callback; +} + +/** + * cdf_trace_dump_all() - Dump data from ring buffer via call back functions + * registered with CDF + * @pMac : Context of particular module + * @code : Reason code + * @session : Session id of log + * @count : Number of lines to dump starting from tail to head + * + * This function will be called up on issueing ioctl call as mentioned following + * [iwpriv wlan0 dumplog 0 0 ] + * + * - number lines to dump starting from tail to head. + * + * - if anybody wants to know how many messages were + * recorded for particular module/s mentioned by setbit in bitmask from last + * messages. It is optional, if you don't provide then it will dump + * everything from buffer. + * + * Return : nothing + */ +void cdf_trace_dump_all(void *pMac, uint8_t code, uint8_t session, + uint32_t count, uint32_t bitmask_of_module) +{ + cdf_trace_record_t pRecord; + int32_t i, tail; + + if (!g_cdf_trace_data.enable) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, "Tracing Disabled"); + return; + } + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Total Records: %d, Head: %d, Tail: %d", + g_cdf_trace_data.num, g_cdf_trace_data.head, + g_cdf_trace_data.tail); + + /* aquire the lock so that only one thread at a time can read + * the ring buffer + */ + spin_lock(<race_lock); + + if (g_cdf_trace_data.head != INVALID_CDF_TRACE_ADDR) { + i = g_cdf_trace_data.head; + tail = g_cdf_trace_data.tail; + + if (count) { + if (count > g_cdf_trace_data.num) + count = g_cdf_trace_data.num; + if (tail >= (count - 1)) + i = tail - count + 1; + else if (count != MAX_CDF_TRACE_RECORDS) + i = MAX_CDF_TRACE_RECORDS - ((count - 1) - + tail); + } + + pRecord = g_cdf_trace_tbl[i]; + /* right now we are not using numSinceLastDump member but + * in future we might re-visit and use this member to track + * how many latest messages got added while we were dumping + * from ring buffer + */ + g_cdf_trace_data.numSinceLastDump = 0; + spin_unlock(<race_lock); + for (;; ) { + if ((code == 0 || (code == pRecord.code)) && + (cdf_trace_cb_table[pRecord.module] != NULL)) { + if (0 == bitmask_of_module) { + cdf_trace_cb_table[pRecord. + module] (pMac, + &pRecord, + (uint16_t) + i); + } else { + if (bitmask_of_module & + (1 << pRecord.module)) { + cdf_trace_cb_table[pRecord. + module] + (pMac, &pRecord, + (uint16_t) i); + } + } + } + + if (i == tail) + break; + i += 1; + + spin_lock(<race_lock); + if (MAX_CDF_TRACE_RECORDS == i) { + i = 0; + pRecord = g_cdf_trace_tbl[0]; + } else { + pRecord = g_cdf_trace_tbl[i]; + } + spin_unlock(<race_lock); + } + } else { + spin_unlock(<race_lock); + } +} + +/** + * cdf_dp_trace_init() - enables the DP trace + * Called during driver load and it enables DP trace + * + * Return: None + */ +void cdf_dp_trace_init(void) +{ + uint8_t i; + + cdf_dp_trace_spin_lock_init(); + g_cdf_dp_trace_data.head = INVALID_CDF_DP_TRACE_ADDR; + g_cdf_dp_trace_data.tail = INVALID_CDF_DP_TRACE_ADDR; + g_cdf_dp_trace_data.num = 0; + g_cdf_dp_trace_data.proto_bitmap = 0; + g_cdf_dp_trace_data.no_of_record = 0; + g_cdf_dp_trace_data.verbosity = CDF_DP_TRACE_VERBOSITY_DEFAULT; + g_cdf_dp_trace_data.enable = true; + + for (i = 0; i < CDF_DP_TRACE_MAX; i++) + cdf_dp_trace_cb_table[i] = cdf_dp_display_record; +} + +/** + * cdf_dp_trace_set_value() - Configure the value to control DP trace + * @proto_bitmap : defines the protocol to be tracked + * @no_of_records : defines the nth packet which is traced + * @verbosity : defines the verbosity level + * + * Return: None + */ +void cdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_record, + uint8_t verbosity) +{ + g_cdf_dp_trace_data.proto_bitmap = proto_bitmap; + g_cdf_dp_trace_data.no_of_record = no_of_record; + g_cdf_dp_trace_data.verbosity = verbosity; + return; +} + +/** + * cdf_dp_trace_enable_track() - enable the tracing for netbuf + * @code : defines the event + * + * Return: true or false depends on whether tracing enabled + */ +static bool cdf_dp_trace_enable_track(enum CDF_DP_TRACE_ID code) +{ + if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_HIGH) + return true; + if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_MEDIUM + && (code <= CDF_DP_TRACE_HIF_PACKET_PTR_RECORD)) + return true; + if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_LOW + && (code <= CDF_DP_TRACE_CE_PACKET_RECORD)) + return true; + if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_DEFAULT + && (code == CDF_DP_TRACE_DROP_PACKET_RECORD)) + return true; + return false; +} + +/** + * cdf_dp_trace_set_track() - Marks whether the packet needs to be traced + * @nbuf : defines the netbuf + * + * Return: None + */ +void cdf_dp_trace_set_track(cdf_nbuf_t nbuf) +{ + spin_lock_bh(&l_dp_trace_lock); + g_cdf_dp_trace_data.count++; + if (g_cdf_dp_trace_data.proto_bitmap != 0) { + if (cds_pkt_get_proto_type(nbuf, + g_cdf_dp_trace_data.proto_bitmap, 0)) { + CDF_NBUF_SET_DP_TRACE(nbuf, 1); + } + } + if ((g_cdf_dp_trace_data.no_of_record != 0) && + (g_cdf_dp_trace_data.count % + g_cdf_dp_trace_data.no_of_record == 0)) { + CDF_NBUF_SET_DP_TRACE(nbuf, 1); + } + spin_unlock_bh(&l_dp_trace_lock); + return; +} + +/** + * dump_hex_trace() - Display the data in buffer + * @buf: buffer which contains data to be displayed + * @buf_len: defines the size of the data to be displayed + * + * Return: None + */ +static void dump_hex_trace(uint8_t *buf, uint8_t buf_len) +{ + uint8_t i = 0; + /* Dump the bytes in the last line */ + cdf_print("DATA: "); + for (i = 0; i < buf_len; i++) + cdf_print("%02x ", buf[i]); + cdf_print("\n"); +} + +/** + * cdf_dp_display_trace() - Displays a record in DP trace + * @pRecord : pointer to a record in DP trace + * @recIndex : record index + * + * Return: None + */ +void cdf_dp_display_record(struct cdf_dp_trace_record_s *pRecord , + uint16_t recIndex) +{ + cdf_print("INDEX: %04d TIME: %012llu CODE: %02d\n", recIndex, + pRecord->time, pRecord->code); + switch (pRecord->code) { + case CDF_DP_TRACE_HDD_TX_TIMEOUT: + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "HDD TX Timeout\n"); + break; + case CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "HDD SoftAP TX Timeout\n"); + break; + case CDF_DP_TRACE_VDEV_PAUSE: + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "VDEV Pause\n"); + break; + case CDF_DP_TRACE_VDEV_UNPAUSE: + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "VDEV UnPause\n"); + break; + default: + dump_hex_trace(pRecord->data, pRecord->size); + } + return; +} + +/** + * cdf_dp_trace() - Stores the data in buffer + * @nbuf : defines the netbuf + * @code : defines the event + * @data : defines the data to be stored + * @size : defines the size of the data record + * + * Return: None + */ +void cdf_dp_trace(cdf_nbuf_t nbuf, enum CDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size) +{ + struct cdf_dp_trace_record_s *rec = NULL; + + /* Return when Dp trace is not enabled */ + if (!g_cdf_dp_trace_data.enable) + return; + + /* If nbuf is NULL, check for VDEV PAUSE, UNPAUSE, TIMEOUT */ + if (!nbuf) { + switch (code) { + case CDF_DP_TRACE_HDD_TX_TIMEOUT: + case CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + case CDF_DP_TRACE_VDEV_PAUSE: + case CDF_DP_TRACE_VDEV_UNPAUSE: + if (cdf_dp_trace_enable_track(code)) + goto register_record; + else + return; + + default: + return; + } + } + + /* Return when the packet is not a data packet */ + if (NBUF_GET_PACKET_TRACK(nbuf) != NBUF_TX_PKT_DATA_TRACK) + return; + + /* Return when nbuf is not marked for dp tracing or + * verbosity does not allow + */ + if (cdf_dp_trace_enable_track(code) == false || + !CDF_NBUF_GET_DP_TRACE(nbuf)) + return; + + /* Acquire the lock so that only one thread at a time can fill the ring + * buffer + */ + +register_record: + + spin_lock_bh(&l_dp_trace_lock); + + g_cdf_dp_trace_data.num++; + + if (g_cdf_dp_trace_data.num > MAX_CDF_DP_TRACE_RECORDS) + g_cdf_dp_trace_data.num = MAX_CDF_DP_TRACE_RECORDS; + + if (INVALID_CDF_DP_TRACE_ADDR == g_cdf_dp_trace_data.head) { + /* first record */ + g_cdf_dp_trace_data.head = 0; + g_cdf_dp_trace_data.tail = 0; + } else { + /* queue is not empty */ + g_cdf_dp_trace_data.tail++; + + if (MAX_CDF_DP_TRACE_RECORDS == g_cdf_dp_trace_data.tail) + g_cdf_dp_trace_data.tail = 0; + + if (g_cdf_dp_trace_data.head == g_cdf_dp_trace_data.tail) { + /* full */ + if (MAX_CDF_DP_TRACE_RECORDS == + ++g_cdf_dp_trace_data.head) + g_cdf_dp_trace_data.head = 0; + } + } + + rec = &g_cdf_dp_trace_tbl[g_cdf_dp_trace_data.tail]; + rec->code = code; + rec->size = 0; + if (data != NULL && size > 0) { + if (size > CDF_DP_TRACE_RECORD_SIZE) + size = CDF_DP_TRACE_RECORD_SIZE; + + rec->size = size; + switch (code) { + case CDF_DP_TRACE_HDD_PACKET_PTR_RECORD: + case CDF_DP_TRACE_CE_PACKET_PTR_RECORD: + case CDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD: + case CDF_DP_TRACE_TXRX_PACKET_PTR_RECORD: + case CDF_DP_TRACE_HTT_PACKET_PTR_RECORD: + case CDF_DP_TRACE_HTC_PACKET_PTR_RECORD: + case CDF_DP_TRACE_HIF_PACKET_PTR_RECORD: + cdf_mem_copy(rec->data, (uint8_t *)(&data), size); + break; + + case CDF_DP_TRACE_DROP_PACKET_RECORD: + case CDF_DP_TRACE_HDD_PACKET_RECORD: + case CDF_DP_TRACE_CE_PACKET_RECORD: + cdf_mem_copy(rec->data, data, size); + break; + default: + break; + } + } + rec->time = cdf_get_log_timestamp(); + rec->pid = (in_interrupt() ? 0 : current->pid); + spin_unlock_bh(&l_dp_trace_lock); +} + +/** + * cdf_dp_trace_spin_lock_init() - initializes the lock variable before use + * This function will be called from cds_alloc_global_context, we will have lock + * available to use ASAP + * + * Return : nothing + */ +void cdf_dp_trace_spin_lock_init(void) +{ + spin_lock_init(&l_dp_trace_lock); + + return; +} + +/** + * cdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions + * registered with CDF + * @code : Reason code + * @count : Number of lines to dump starting from tail to head + * + * Return : nothing + */ +void cdf_dp_trace_dump_all(uint32_t count) +{ + struct cdf_dp_trace_record_s pRecord; + int32_t i, tail; + + if (!g_cdf_dp_trace_data.enable) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, "Tracing Disabled"); + return; + } + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Total Records: %d, Head: %d, Tail: %d", + g_cdf_dp_trace_data.num, g_cdf_dp_trace_data.head, + g_cdf_dp_trace_data.tail); + + /* aquire the lock so that only one thread at a time can read + * the ring buffer + */ + spin_lock_bh(&l_dp_trace_lock); + + if (g_cdf_dp_trace_data.head != INVALID_CDF_DP_TRACE_ADDR) { + i = g_cdf_dp_trace_data.head; + tail = g_cdf_dp_trace_data.tail; + + if (count) { + if (count > g_cdf_dp_trace_data.num) + count = g_cdf_dp_trace_data.num; + if (tail >= (count - 1)) + i = tail - count + 1; + else if (count != MAX_CDF_DP_TRACE_RECORDS) + i = MAX_CDF_DP_TRACE_RECORDS - ((count - 1) - + tail); + } + + pRecord = g_cdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + for (;; ) { + + cdf_dp_trace_cb_table[pRecord. + code] (&pRecord, (uint16_t)i); + if (i == tail) + break; + i += 1; + + spin_lock_bh(&l_dp_trace_lock); + if (MAX_CDF_DP_TRACE_RECORDS == i) + i = 0; + + pRecord = g_cdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + } + } else { + spin_unlock_bh(&l_dp_trace_lock); + } +} diff --git a/core/cdf/src/i_cdf_atomic.h b/core/cdf/src/i_cdf_atomic.h new file mode 100644 index 0000000000..f74b7dfd47 --- /dev/null +++ b/core/cdf/src/i_cdf_atomic.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef I_CDF_ATOMIC_H +#define I_CDF_ATOMIC_H + +#include /* CDF_STATUS */ + +#include + +typedef atomic_t __cdf_atomic_t; + +static inline CDF_STATUS __cdf_atomic_init(__cdf_atomic_t *v) +{ + atomic_set(v, 0); + + return CDF_STATUS_SUCCESS; +} + +static inline uint32_t __cdf_atomic_read(__cdf_atomic_t *v) +{ + return atomic_read(v); +} + +static inline void __cdf_atomic_inc(__cdf_atomic_t *v) +{ + atomic_inc(v); +} + +static inline void __cdf_atomic_dec(__cdf_atomic_t *v) +{ + atomic_dec(v); +} + +static inline void __cdf_atomic_add(int i, __cdf_atomic_t *v) +{ + atomic_add(i, v); +} + +static inline uint32_t __cdf_atomic_dec_and_test(__cdf_atomic_t *v) +{ + return atomic_dec_and_test(v); +} + +static inline void __cdf_atomic_set(__cdf_atomic_t *v, int i) +{ + atomic_set(v, i); +} + +static inline uint32_t __cdf_atomic_inc_return(__cdf_atomic_t *v) +{ + return atomic_inc_return(v); +} + +#endif diff --git a/core/cdf/src/i_cdf_defer.h b/core/cdf/src/i_cdf_defer.h new file mode 100644 index 0000000000..fc9bd7796e --- /dev/null +++ b/core/cdf/src/i_cdf_defer.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _I_CDF_DEFER_H +#define _I_CDF_DEFER_H + +#include +#include +#include +#ifdef CONFIG_CNSS +#include +#endif +#include +#include +#include + +typedef struct tasklet_struct __cdf_bh_t; + +typedef void (*__cdf_bh_fn_t)(unsigned long arg); + +/* wrapper around the real task func */ +typedef struct { + struct work_struct work; + cdf_defer_fn_t fn; + void *arg; +} __cdf_work_t; + +extern void __cdf_defer_func(struct work_struct *work); + +static inline CDF_STATUS +__cdf_init_work(cdf_handle_t hdl, + __cdf_work_t *work, cdf_defer_fn_t func, void *arg) +{ + /*Initilize func and argument in work struct */ + work->fn = func; + work->arg = arg; +#ifdef CONFIG_CNSS + cnss_init_work(&work->work, __cdf_defer_func); +#else + INIT_WORK(&work->work, __cdf_defer_func); +#endif + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS __cdf_sched_work(cdf_handle_t hdl, __cdf_work_t *work) +{ + schedule_work(&work->work); + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS +__cdf_disable_work(cdf_handle_t hdl, __cdf_work_t *work) +{ + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS __cdf_init_bh(cdf_handle_t hdl, + struct tasklet_struct *bh, + cdf_defer_fn_t func, void *arg) +{ + tasklet_init(bh, (__cdf_bh_fn_t) func, (unsigned long)arg); + + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS +__cdf_sched_bh(cdf_handle_t hdl, struct tasklet_struct *bh) +{ + tasklet_schedule(bh); + + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS +__cdf_disable_bh(cdf_handle_t hdl, struct tasklet_struct *bh) +{ + tasklet_kill(bh); + + return CDF_STATUS_SUCCESS; +} + +#endif /*_I_CDF_DEFER_H*/ diff --git a/core/cdf/src/i_cdf_event.h b/core/cdf/src/i_cdf_event.h new file mode 100644 index 0000000000..beac5d93fd --- /dev/null +++ b/core/cdf/src/i_cdf_event.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_CDF_EVENT_H) +#define __I_CDF_EVENT_H + +/** + * DOC: i_cdf_event.h + * + * Linux-specific definitions for CDF Events + */ + +/* Include Files */ +#include +#include + +/* Preprocessor definitions and constants */ +#define LINUX_EVENT_COOKIE 0x12341234 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +#define INIT_COMPLETION(event) reinit_completion(&event) +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Type declarations */ + +typedef struct evt { + struct completion complete; + uint32_t cookie; +} cdf_event_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_CDF_EVENT_H */ diff --git a/core/cdf/src/i_cdf_lock.h b/core/cdf/src/i_cdf_lock.h new file mode 100644 index 0000000000..634728db05 --- /dev/null +++ b/core/cdf/src/i_cdf_lock.h @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_CDF_LOCK_H) +#define __I_CDF_LOCK_H + +/** + * DOC: i_cdf_lock.h + * + * Linux-specific definitions for CDF Locks + * + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif + +/* Preprocessor definitions and constants */ + +/* define for flag */ +#define ADF_OS_LINUX_UNLOCK_BH 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * typedef struct - cdf_mutex_t + * @m_lock: Mutex lock + * @cookie: Lock cookie + * @processID: Process ID to track lock + * @state: Lock status + * @refcount: Reference count for recursive lock + */ +typedef struct cdf_lock_s { + struct mutex m_lock; + uint32_t cookie; + int processID; + uint32_t state; + uint8_t refcount; +} cdf_mutex_t; + +/** + * typedef struct - cdf_spinlock_t + * @spinlock: Spin lock + * @flags: Lock flag + * @_flags: Internal lock flag + */ +typedef struct __cdf_spinlock { + spinlock_t spinlock; + unsigned int flags; + unsigned long _flags; +} cdf_spinlock_t; + +typedef cdf_spinlock_t __cdf_spinlock_t; +typedef struct semaphore __cdf_semaphore_t; + +#if defined CONFIG_CNSS +typedef struct wakeup_source cdf_wake_lock_t; +#elif defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +typedef struct wake_lock cdf_wake_lock_t; +#else +typedef int cdf_wake_lock_t; +#endif + +/* Function declarations and documenation */ + +/** + * __cdf_semaphore_init() - initialize the semaphore + * @m: Semaphore object + * + * Return: CDF_STATUS_SUCCESS + */ +static inline CDF_STATUS __cdf_semaphore_init(struct semaphore *m) +{ + sema_init(m, 1); + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_semaphore_acquire() - acquire semaphore + * @m: Semaphore object + * + * Return: 0 + */ +static inline int +__cdf_semaphore_acquire(cdf_device_t osdev, struct semaphore *m) +{ + down(m); + return 0; +} + +/** + * __cdf_semaphore_release() - release semaphore + * @m: Semaphore object + * + * Return: result of UP operation in integer + */ +static inline void +__cdf_semaphore_release(cdf_device_t osdev, struct semaphore *m) +{ + up(m); +} + +/** + * __cdf_spinlock_init() - initialize spin lock + * @lock: Spin lock object + * + * Return: CDF_STATUS_SUCCESS + */ +static inline CDF_STATUS __cdf_spinlock_init(__cdf_spinlock_t *lock) +{ + spin_lock_init(&lock->spinlock); + lock->flags = 0; + + return CDF_STATUS_SUCCESS; +} + +#define __cdf_spinlock_destroy(lock) +/** + * __cdf_spin_lock() - Acquire a Spinlock(SMP) & disable Preemption (Preemptive) + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_lock(__cdf_spinlock_t *lock) +{ + spin_lock(&lock->spinlock); +} + +/** + * __cdf_spin_unlock() - Unlock the spinlock and enables the Preemption + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_unlock(__cdf_spinlock_t *lock) +{ + spin_unlock(&lock->spinlock); +} + +/** + * __cdf_spin_lock_irqsave() - Acquire a Spinlock (SMP) & disable Preemption + * (Preemptive) and disable IRQs + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_lock_irqsave(__cdf_spinlock_t *lock) +{ + spin_lock_irqsave(&lock->spinlock, lock->_flags); +} +/** + * __cdf_spin_unlock_irqrestore() - Unlock the spinlock and enables the + * Preemption and enable IRQ + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_unlock_irqrestore(__cdf_spinlock_t *lock) +{ + spin_unlock_irqrestore(&lock->spinlock, lock->_flags); +} + +/* + * Synchronous versions - only for OS' that have interrupt disable + */ +#define __cdf_spin_lock_irq(_pLock, _flags) spin_lock_irqsave(_pLock, _flags) +#define __cdf_spin_unlock_irq(_pLock, _flags) spin_unlock_irqrestore(_pLock, _flags) + +/** + * __cdf_spin_lock_bh() - Acquire the spinlock and disable bottom halves + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_lock_bh(__cdf_spinlock_t *lock) +{ + if (likely(irqs_disabled() || in_softirq())) { + spin_lock(&lock->spinlock); + } else { + spin_lock_bh(&lock->spinlock); + lock->flags |= ADF_OS_LINUX_UNLOCK_BH; + } + +} + +/** + * __cdf_spin_unlock_bh() - Release the spinlock and enable bottom halves + * @lock: Lock object + * + * Return: none + */ +static inline void +__cdf_spin_unlock_bh(__cdf_spinlock_t *lock) +{ + if (unlikely(lock->flags & ADF_OS_LINUX_UNLOCK_BH)) { + lock->flags &= ~ADF_OS_LINUX_UNLOCK_BH; + spin_unlock_bh(&lock->spinlock); + } else + spin_unlock(&lock->spinlock); +} + +/** + * __cdf_in_softirq() - in soft irq context + * + * Return: true if in softirs context else false + */ +static inline bool __cdf_in_softirq(void) +{ + return in_softirq(); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __I_CDF_LOCK_H */ diff --git a/core/cdf/src/i_cdf_mc_timer.h b/core/cdf/src/i_cdf_mc_timer.h new file mode 100644 index 0000000000..95634ff895 --- /dev/null +++ b/core/cdf/src/i_cdf_mc_timer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_CDF_MC_TIMER_H) +#define __I_CDF_MC_TIMER_H + +/** + * DOC: i_cdf_mc_timer.h + * + * Linux-specific definitions for CDF timers serialized to MC thread + */ + +/* Include Files */ +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +/* Type declarations */ + +typedef struct cdf_mc_timer_platform_s { + struct timer_list Timer; + int threadID; + uint32_t cookie; + spinlock_t spinlock; +} cdf_mc_timer_platform_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_CDF_MC_TIMER_H */ diff --git a/core/cdf/src/i_cdf_nbuf.h b/core/cdf/src/i_cdf_nbuf.h new file mode 100644 index 0000000000..75536f09ff --- /dev/null +++ b/core/cdf/src/i_cdf_nbuf.h @@ -0,0 +1,1092 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_cdf_nbuf.h + * + * Linux implementation of skbuf + */ +#ifndef _I_CDF_NET_BUF_H +#define _I_CDF_NET_BUF_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __CDF_NBUF_NULL NULL + + +/* + * Use socket buffer as the underlying implentation as skbuf . + * Linux use sk_buff to represent both packet and data, + * so we use sk_buffer to represent both skbuf . + */ +typedef struct sk_buff *__cdf_nbuf_t; + +typedef void (*__cdf_nbuf_callback_fn)(struct sk_buff *skb); +#define OSDEP_EAPOL_TID 6 /* send it on VO queue */ + +/* CVG_NBUF_MAX_OS_FRAGS - + * max tx fragments provided by the OS + */ +#define CVG_NBUF_MAX_OS_FRAGS 1 + +/* CVG_NBUF_MAX_EXTRA_FRAGS - + * max tx fragments added by the driver + * The driver will always add one tx fragment (the tx descriptor) and may + * add a second tx fragment (e.g. a TSO segment's modified IP header). + */ +#define CVG_NBUF_MAX_EXTRA_FRAGS 2 + +typedef void (*cdf_nbuf_trace_update_t)(char *); + +/** + * struct cvg_nbuf_cb - network buffer control block + * @data_attr: Value that is programmed in CE descriptor, contains: + * 1) CE classification enablement bit + * 2) Pkt type (802.3 or Ethernet Type II) + * 3) Pkt Offset (Usually the length of HTT/HTC desc.) + * @trace: info for DP tracing + * @mapped_paddr_lo: DMA mapping info + * @extra_frags: Extra tx fragments + * @owner_id: Owner id + * @cdf_nbuf_callback_fn: Callback function + * @priv_data: IPA specific priv data + * @proto_type: Protocol type + * @vdev_id: vdev id + * @tx_htt2_frm: HTT 2 frame + * @tx_htt2_reserved: HTT 2 reserved bits + */ +struct cvg_nbuf_cb { + uint32_t data_attr; + /* + * Store info for data path tracing + */ + struct { + uint8_t packet_state; + uint8_t packet_track; + uint8_t dp_trace; + } trace; + + /* + * Store the DMA mapping info for the network buffer fragments + * provided by the OS. + */ + uint32_t mapped_paddr_lo[CVG_NBUF_MAX_OS_FRAGS]; + + /* store extra tx fragments provided by the driver */ + struct { + /* vaddr - + * CPU address (a.k.a. virtual address) of the tx fragments + * added by the driver + */ + unsigned char *vaddr[CVG_NBUF_MAX_EXTRA_FRAGS]; + /* paddr_lo - + * bus address (a.k.a. physical address) of the tx fragments + * added by the driver + */ + uint32_t paddr_lo[CVG_NBUF_MAX_EXTRA_FRAGS]; + uint16_t len[CVG_NBUF_MAX_EXTRA_FRAGS]; + uint8_t num; /* how many extra frags has the driver added */ + uint8_t + /* + * Store a wordstream vs. bytestream flag for each extra + * fragment, plus one more flag for the original fragment(s) + * of the netbuf. + */ +wordstream_flags:CVG_NBUF_MAX_EXTRA_FRAGS + 1; + } extra_frags; + uint32_t owner_id; + __cdf_nbuf_callback_fn cdf_nbuf_callback_fn; + unsigned long priv_data; +#ifdef QCA_PKT_PROTO_TRACE + unsigned char proto_type; + unsigned char vdev_id; +#endif /* QCA_PKT_PROTO_TRACE */ +#ifdef QCA_TX_HTT2_SUPPORT + unsigned char tx_htt2_frm:1; + unsigned char tx_htt2_reserved:7; +#endif /* QCA_TX_HTT2_SUPPORT */ +}; +#define NBUF_OWNER_ID(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->owner_id) +#define NBUF_OWNER_PRIV_DATA(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->priv_data) +#define NBUF_CALLBACK_FN(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->cdf_nbuf_callback_fn) +#define NBUF_CALLBACK_FN_EXEC(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->cdf_nbuf_callback_fn)(skb) +#define NBUF_MAPPED_PADDR_LO(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->mapped_paddr_lo[0]) +#define NBUF_NUM_EXTRA_FRAGS(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->extra_frags.num) +#define NBUF_EXTRA_FRAG_VADDR(skb, frag_num) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->extra_frags.vaddr[(frag_num)]) +#define NBUF_EXTRA_FRAG_PADDR_LO(skb, frag_num) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->extra_frags.paddr_lo[(frag_num)]) +#define NBUF_EXTRA_FRAG_LEN(skb, frag_num) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->extra_frags.len[(frag_num)]) +#define NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->extra_frags.wordstream_flags) + +#ifdef QCA_PKT_PROTO_TRACE +#define NBUF_SET_PROTO_TYPE(skb, proto_type) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->proto_type = proto_type) +#define NBUF_GET_PROTO_TYPE(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->proto_type) +#else +#define NBUF_SET_PROTO_TYPE(skb, proto_type); +#define NBUF_GET_PROTO_TYPE(skb) 0; +#endif /* QCA_PKT_PROTO_TRACE */ + +#ifdef QCA_TX_HTT2_SUPPORT +#define NBUF_SET_TX_HTT2_FRM(skb, candi) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->tx_htt2_frm = candi) +#define NBUF_GET_TX_HTT2_FRM(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->tx_htt2_frm) +#else +#define NBUF_SET_TX_HTT2_FRM(skb, candi) +#define NBUF_GET_TX_HTT2_FRM(skb) 0 +#endif /* QCA_TX_HTT2_SUPPORT */ + +#define NBUF_DATA_ATTR_SET(skb, data_attr) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->data_attr = data_attr) + +#define NBUF_DATA_ATTR_GET(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->data_attr) + +#if defined(FEATURE_LRO) +/** + * struct nbuf_rx_cb - network buffer control block + * on the receive path of the skb + * @lro_eligible: indicates whether the msdu is LRO eligible + * @tcp_proto: indicates if this is a TCP packet + * @ipv6_proto: indicates if this is an IPv6 packet + * @ip_offset: offset to the IP header + * @tcp_offset: offset to the TCP header + * @tcp_udp_chksum: TCP payload checksum + * @tcp_seq_num: TCP sequence number + * @tcp_ack_num: TCP acknowledgement number + * @flow_id_toeplitz: 32 bit 5-tuple flow id toeplitz hash + */ +struct nbuf_rx_cb { + uint32_t lro_eligible:1, + tcp_proto:1, + tcp_pure_ack:1, + ipv6_proto:1, + ip_offset:7, + tcp_offset:7; + uint32_t tcp_udp_chksum:16, + tcp_win:16; + uint32_t tcp_seq_num; + uint32_t tcp_ack_num; + uint32_t flow_id_toeplitz; +}; + +#define NBUF_LRO_ELIGIBLE(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->lro_eligible) +#define NBUF_TCP_PROTO(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_proto) +#define NBUF_TCP_PURE_ACK(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_pure_ack) +#define NBUF_IPV6_PROTO(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->ipv6_proto) +#define NBUF_IP_OFFSET(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->ip_offset) +#define NBUF_TCP_OFFSET(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_offset) +#define NBUF_TCP_CHKSUM(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_udp_chksum) +#define NBUF_TCP_SEQ_NUM(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_seq_num) +#define NBUF_TCP_ACK_NUM(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_ack_num) +#define NBUF_TCP_WIN(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->tcp_win) +#define NBUF_FLOW_ID_TOEPLITZ(skb) \ + (((struct nbuf_rx_cb *)((skb)->cb))->flow_id_toeplitz) + +/** + * cdf_print_lro_info() - prints the LRO information + * @skb : network buffer + * + * This function prints out the LRO related fields in the rx + * descriptor + * + * Return: none + */ +static inline void cdf_print_lro_info(struct sk_buff *skb) +{ + cdf_print("NBUF_LRO_ELIGIBLE 0x%x\n" + "NBUF_TCP_PROTO 0x%x\n" + "NBUF_TCP_PURE_ACK 0x%x\n" + "NBUF_TCP_CHKSUM 0x%x\n" + "NBUF_IPV6_PROTO 0x%x\n" + "NBUF_IP_OFFSET 0x%x\n" + "NBUF_TCP_OFFSET 0x%x\n" + "NBUF_TCP_SEQ_NUM 0x%x\n" + "NBUF_TCP_ACK_NUM 0x%x\n" + "NBUF_TCP_WIN 0x%x\n" + "NBUF_FLOW_ID_TOEPLITZ 0x%x\n", + NBUF_LRO_ELIGIBLE(skb), + NBUF_TCP_PROTO(skb), + NBUF_TCP_PURE_ACK(skb), + NBUF_TCP_CHKSUM(skb), + NBUF_IPV6_PROTO(skb), + NBUF_IP_OFFSET(skb), + NBUF_TCP_OFFSET(skb), + NBUF_TCP_SEQ_NUM(skb), + NBUF_TCP_ACK_NUM(skb), + NBUF_TCP_WIN(skb), + NBUF_FLOW_ID_TOEPLITZ(skb)); +} +#endif /* FEATURE_LRO */ + +#define NBUF_SET_PACKET_STATE(skb, pkt_state) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.packet_state = \ + pkt_state) +#define NBUF_GET_PACKET_STATE(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.packet_state) + +#define NBUF_SET_PACKET_TRACK(skb, pkt_track) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.packet_track = \ + pkt_track) +#define NBUF_GET_PACKET_TRACK(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.packet_track) + +#define NBUF_UPDATE_TX_PKT_COUNT(skb, PACKET_STATE) \ + cdf_nbuf_set_state(skb, PACKET_STATE) + +#define CDF_NBUF_SET_DP_TRACE(skb, enable) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.dp_trace \ + = enable) +#define CDF_NBUF_GET_DP_TRACE(skb) \ + (((struct cvg_nbuf_cb *)((skb)->cb))->trace.dp_trace) + +#define __cdf_nbuf_get_num_frags(skb) \ + /* assume the OS provides a single fragment */ \ + (NBUF_NUM_EXTRA_FRAGS(skb) + 1) + +#if defined(FEATURE_TSO) +#define __cdf_nbuf_dec_num_frags(skb) \ + (NBUF_NUM_EXTRA_FRAGS(skb)--) +#endif + +#define __cdf_nbuf_frag_push_head( \ + skb, frag_len, frag_vaddr, frag_paddr_lo, frag_paddr_hi) \ + do { \ + int frag_num = NBUF_NUM_EXTRA_FRAGS(skb)++; \ + NBUF_EXTRA_FRAG_VADDR(skb, frag_num) = frag_vaddr; \ + NBUF_EXTRA_FRAG_PADDR_LO(skb, frag_num) = frag_paddr_lo; \ + NBUF_EXTRA_FRAG_LEN(skb, frag_num) = frag_len; \ + } while (0) + +#define __cdf_nbuf_get_frag_len(skb, frag_num) \ + ((frag_num < NBUF_NUM_EXTRA_FRAGS(skb)) ? \ + NBUF_EXTRA_FRAG_LEN(skb, frag_num) : (skb)->len) + +#define __cdf_nbuf_get_frag_vaddr(skb, frag_num) \ + ((frag_num < NBUF_NUM_EXTRA_FRAGS(skb)) ? \ + NBUF_EXTRA_FRAG_VADDR(skb, frag_num) : ((skb)->data)) + +#define __cdf_nbuf_get_frag_paddr_lo(skb, frag_num) \ + ((frag_num < NBUF_NUM_EXTRA_FRAGS(skb)) ? \ + NBUF_EXTRA_FRAG_PADDR_LO(skb, frag_num) : \ + /* assume that the OS only provides a single fragment */ \ + NBUF_MAPPED_PADDR_LO(skb)) + +#define __cdf_nbuf_get_frag_is_wordstream(skb, frag_num) \ + ((frag_num < NBUF_NUM_EXTRA_FRAGS(skb)) ? \ + (NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) >> \ + (frag_num)) & 0x1 : \ + (NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) >> \ + (CVG_NBUF_MAX_EXTRA_FRAGS)) & 0x1) + +#define __cdf_nbuf_set_frag_is_wordstream(skb, frag_num, is_wordstream) \ + do { \ + if (frag_num >= NBUF_NUM_EXTRA_FRAGS(skb)) { \ + frag_num = CVG_NBUF_MAX_EXTRA_FRAGS; \ + } \ + /* clear the old value */ \ + NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) &= ~(1 << frag_num); \ + /* set the new value */ \ + NBUF_EXTRA_FRAG_WORDSTREAM_FLAGS(skb) |= \ + ((is_wordstream) << frag_num); \ + } while (0) + +#define __cdf_nbuf_trace_set_proto_type(skb, proto_type) \ + NBUF_SET_PROTO_TYPE(skb, proto_type) +#define __cdf_nbuf_trace_get_proto_type(skb) \ + NBUF_GET_PROTO_TYPE(skb); + +/** + * __cdf_nbuf_data_attr_get() - Retrieves the data_attr value + * from cvg_nbuf_cb (skb->cb) + * @skb: Pointer to struct sk_buff + * + * Return: data_attr + */ +#define __cdf_nbuf_data_attr_get(skb) \ + NBUF_DATA_ATTR_GET(skb) + +/** + * __cdf_nbuf_data_attr_set() - Sets the data_attr value + * in cvg_nbuf_cb (skb->cb) + * @skb: Pointer to struct sk_buff + * @data_attr: packet type from the enum cdf_txrx_pkt_type + * + * Return: + */ +static inline void +__cdf_nbuf_data_attr_set(struct sk_buff *skb, + uint32_t data_attr) +{ + NBUF_DATA_ATTR_SET(skb, data_attr); +} + +/** + * typedef struct __cdf_nbuf_queue_t - network buffer queue + * @head: Head pointer + * @tail: Tail pointer + * @qlen: Queue length + */ +typedef struct __cdf_nbuf_qhead { + struct sk_buff *head; + struct sk_buff *tail; + unsigned int qlen; +} __cdf_nbuf_queue_t; + +/* + * Use sk_buff_head as the implementation of cdf_nbuf_queue_t. + * Because the queue head will most likely put in some structure, + * we don't use pointer type as the definition. + */ + +/* + * prototypes. Implemented in cdf_nbuf.c + */ +__cdf_nbuf_t __cdf_nbuf_alloc(__cdf_device_t osdev, size_t size, int reserve, + int align, int prio); +void __cdf_nbuf_free(struct sk_buff *skb); +CDF_STATUS __cdf_nbuf_map(__cdf_device_t osdev, + struct sk_buff *skb, cdf_dma_dir_t dir); +void __cdf_nbuf_unmap(__cdf_device_t osdev, + struct sk_buff *skb, cdf_dma_dir_t dir); +CDF_STATUS __cdf_nbuf_map_single(__cdf_device_t osdev, + struct sk_buff *skb, cdf_dma_dir_t dir); +void __cdf_nbuf_unmap_single(__cdf_device_t osdev, + struct sk_buff *skb, cdf_dma_dir_t dir); +void __cdf_nbuf_reg_trace_cb(cdf_nbuf_trace_update_t cb_func_ptr); + +#ifdef QCA_PKT_PROTO_TRACE +void __cdf_nbuf_trace_update(struct sk_buff *buf, char *event_string); +#else +#define __cdf_nbuf_trace_update(skb, event_string) +#endif /* QCA_PKT_PROTO_TRACE */ + +/** + * __cdf_os_to_status() - OS to CDF status conversion + * @error : OS error + * + * Return: CDF status + */ +static inline CDF_STATUS __cdf_os_to_status(signed int error) +{ + switch (error) { + case 0: + return CDF_STATUS_SUCCESS; + case ENOMEM: + case -ENOMEM: + return CDF_STATUS_E_NOMEM; + default: + return CDF_STATUS_E_NOSUPPORT; + } +} + +/** + * __cdf_nbuf_len() - return the amount of valid data in the skb + * @skb: Pointer to network buffer + * + * This API returns the amount of valid data in the skb, If there are frags + * then it returns total length. + * + * Return: network buffer length + */ +static inline size_t __cdf_nbuf_len(struct sk_buff *skb) +{ + int i, extra_frag_len = 0; + + i = NBUF_NUM_EXTRA_FRAGS(skb); + while (i-- > 0) + extra_frag_len += NBUF_EXTRA_FRAG_LEN(skb, i); + + return extra_frag_len + skb->len; +} + +/** + * __cdf_nbuf_cat() - link two nbufs + * @dst: Buffer to piggyback into + * @src: Buffer to put + * + * Link tow nbufs the new buf is piggybacked into the older one. The older + * (src) skb is released. + * + * Return: CDF_STATUS (status of the call) if failed the src skb + * is released + */ +static inline CDF_STATUS +__cdf_nbuf_cat(struct sk_buff *dst, struct sk_buff *src) +{ + CDF_STATUS error = 0; + + cdf_assert(dst && src); + + /* + * Since pskb_expand_head unconditionally reallocates the skb->head + * buffer, first check whether the current buffer is already large + * enough. + */ + if (skb_tailroom(dst) < src->len) { + error = pskb_expand_head(dst, 0, src->len, GFP_ATOMIC); + if (error) + return __cdf_os_to_status(error); + } + memcpy(skb_tail_pointer(dst), src->data, src->len); + + skb_put(dst, src->len); + dev_kfree_skb_any(src); + + return __cdf_os_to_status(error); +} + +/**************************nbuf manipulation routines*****************/ + +/** + * __cdf_nbuf_headroom() - return the amount of tail space available + * @buf: Pointer to network buffer + * + * Return: amount of tail room + */ +static inline int __cdf_nbuf_headroom(struct sk_buff *skb) +{ + return skb_headroom(skb); +} + +/** + * __cdf_nbuf_tailroom() - return the amount of tail space available + * @buf: Pointer to network buffer + * + * Return: amount of tail room + */ +static inline uint32_t __cdf_nbuf_tailroom(struct sk_buff *skb) +{ + return skb_tailroom(skb); +} + +/** + * __cdf_nbuf_push_head() - Push data in the front + * @skb: Pointer to network buffer + * @size: size to be pushed + * + * Return: New data pointer of this buf after data has been pushed, + * or NULL if there is not enough room in this buf. + */ +static inline uint8_t *__cdf_nbuf_push_head(struct sk_buff *skb, size_t size) +{ + if (NBUF_MAPPED_PADDR_LO(skb)) + NBUF_MAPPED_PADDR_LO(skb) -= size; + + return skb_push(skb, size); +} + +/** + * __cdf_nbuf_put_tail() - Puts data in the end + * @skb: Pointer to network buffer + * @size: size to be pushed + * + * Return: data pointer of this buf where new data has to be + * put, or NULL if there is not enough room in this buf. + */ +static inline uint8_t *__cdf_nbuf_put_tail(struct sk_buff *skb, size_t size) +{ + if (skb_tailroom(skb) < size) { + if (unlikely(pskb_expand_head(skb, 0, + size - skb_tailroom(skb), GFP_ATOMIC))) { + dev_kfree_skb_any(skb); + return NULL; + } + } + return skb_put(skb, size); +} + +/** + * __cdf_nbuf_pull_head() - pull data out from the front + * @skb: Pointer to network buffer + * @size: size to be popped + * + * Return: New data pointer of this buf after data has been popped, + * or NULL if there is not sufficient data to pull. + */ +static inline uint8_t *__cdf_nbuf_pull_head(struct sk_buff *skb, size_t size) +{ + if (NBUF_MAPPED_PADDR_LO(skb)) + NBUF_MAPPED_PADDR_LO(skb) += size; + + return skb_pull(skb, size); +} + +/** + * __cdf_nbuf_trim_tail() - trim data out from the end + * @skb: Pointer to network buffer + * @size: size to be popped + * + * Return: none + */ +static inline void __cdf_nbuf_trim_tail(struct sk_buff *skb, size_t size) +{ + return skb_trim(skb, skb->len - size); +} + +/*********************nbuf private buffer routines*************/ + +/** + * __cdf_nbuf_peek_header() - return the header's addr & m_len + * @skb: Pointer to network buffer + * @addr: Pointer to store header's addr + * @m_len: network buffer length + * + * Return: none + */ +static inline void +__cdf_nbuf_peek_header(struct sk_buff *skb, uint8_t **addr, uint32_t *len) +{ + *addr = skb->data; + *len = skb->len; +} + +/******************Custom queue*************/ + +/** + * __cdf_nbuf_queue_init() - initiallize the queue head + * @qhead: Queue head + * + * Return: CDF status + */ +static inline CDF_STATUS __cdf_nbuf_queue_init(__cdf_nbuf_queue_t *qhead) +{ + memset(qhead, 0, sizeof(struct __cdf_nbuf_qhead)); + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_nbuf_queue_add() - add an skb in the tail of the queue + * @qhead: Queue head + * @skb: Pointer to network buffer + * + * This is a lockless version, driver must acquire locks if it + * needs to synchronize + * + * Return: none + */ +static inline void +__cdf_nbuf_queue_add(__cdf_nbuf_queue_t *qhead, struct sk_buff *skb) +{ + skb->next = NULL; /*Nullify the next ptr */ + + if (!qhead->head) + qhead->head = skb; + else + qhead->tail->next = skb; + + qhead->tail = skb; + qhead->qlen++; +} + +/** + * __cdf_nbuf_queue_insert_head() - add an skb at the head of the queue + * @qhead: Queue head + * @skb: Pointer to network buffer + * + * This is a lockless version, driver must acquire locks if it needs to + * synchronize + * + * Return: none + */ +static inline void +__cdf_nbuf_queue_insert_head(__cdf_nbuf_queue_t *qhead, __cdf_nbuf_t skb) +{ + if (!qhead->head) { + /*Empty queue Tail pointer Must be updated */ + qhead->tail = skb; + } + skb->next = qhead->head; + qhead->head = skb; + qhead->qlen++; +} + +/** + * __cdf_nbuf_queue_remove() - remove a skb from the head of the queue + * @qhead: Queue head + * + * This is a lockless version. Driver should take care of the locks + * + * Return: skb or NULL + */ +static inline +struct sk_buff *__cdf_nbuf_queue_remove(__cdf_nbuf_queue_t *qhead) +{ + __cdf_nbuf_t tmp = NULL; + + if (qhead->head) { + qhead->qlen--; + tmp = qhead->head; + if (qhead->head == qhead->tail) { + qhead->head = NULL; + qhead->tail = NULL; + } else { + qhead->head = tmp->next; + } + tmp->next = NULL; + } + return tmp; +} + +/** + * __cdf_nbuf_queue_len() - return the queue length + * @qhead: Queue head + * + * Return: Queue length + */ +static inline uint32_t __cdf_nbuf_queue_len(__cdf_nbuf_queue_t *qhead) +{ + return qhead->qlen; +} + +/** + * __cdf_nbuf_queue_next() - return the next skb from packet chain + * @skb: Pointer to network buffer + * + * This API returns the next skb from packet chain, remember the skb is + * still in the queue + * + * Return: NULL if no packets are there + */ +static inline struct sk_buff *__cdf_nbuf_queue_next(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __cdf_nbuf_is_queue_empty() - check if the queue is empty or not + * @qhead: Queue head + * + * Return: true if length is 0 else false + */ +static inline bool __cdf_nbuf_is_queue_empty(__cdf_nbuf_queue_t *qhead) +{ + return qhead->qlen == 0; +} + +/* + * Use sk_buff_head as the implementation of cdf_nbuf_queue_t. + * Because the queue head will most likely put in some structure, + * we don't use pointer type as the definition. + */ + +/* + * prototypes. Implemented in cdf_nbuf.c + */ +cdf_nbuf_tx_cksum_t __cdf_nbuf_get_tx_cksum(struct sk_buff *skb); +CDF_STATUS __cdf_nbuf_set_rx_cksum(struct sk_buff *skb, + cdf_nbuf_rx_cksum_t *cksum); +uint8_t __cdf_nbuf_get_tid(struct sk_buff *skb); +void __cdf_nbuf_set_tid(struct sk_buff *skb, uint8_t tid); +uint8_t __cdf_nbuf_get_exemption_type(struct sk_buff *skb); + +/* + * cdf_nbuf_pool_delete() implementation - do nothing in linux + */ +#define __cdf_nbuf_pool_delete(osdev) + +/** + * __cdf_nbuf_clone() - clone the nbuf (copy is readonly) + * @skb: Pointer to network buffer + * + * if GFP_ATOMIC is overkill then we can check whether its + * called from interrupt context and then do it or else in + * normal case use GFP_KERNEL + * + * example use "in_irq() || irqs_disabled()" + * + * Return: cloned skb + */ +static inline struct sk_buff *__cdf_nbuf_clone(struct sk_buff *skb) +{ + return skb_clone(skb, GFP_ATOMIC); +} + +/** + * __cdf_nbuf_copy() - returns a private copy of the skb + * @skb: Pointer to network buffer + * + * This API returns a private copy of the skb, the skb returned is completely + * modifiable by callers + * + * Return: skb or NULL + */ +static inline struct sk_buff *__cdf_nbuf_copy(struct sk_buff *skb) +{ + return skb_copy(skb, GFP_ATOMIC); +} + +#define __cdf_nbuf_reserve skb_reserve + +/***********************XXX: misc api's************************/ + +/** + * __cdf_nbuf_head() - return the pointer the skb's head pointer + * @skb: Pointer to network buffer + * + * Return: Pointer to head buffer + */ +static inline uint8_t *__cdf_nbuf_head(struct sk_buff *skb) +{ + return skb->head; +} + +/** + * __cdf_nbuf_data() - return the pointer to data header in the skb + * @skb: Pointer to network buffer + * + * Return: Pointer to skb data + */ +static inline uint8_t *__cdf_nbuf_data(struct sk_buff *skb) +{ + return skb->data; +} + +/** + * __cdf_nbuf_get_protocol() - return the protocol value of the skb + * @skb: Pointer to network buffer + * + * Return: skb protocol + */ +static inline uint16_t __cdf_nbuf_get_protocol(struct sk_buff *skb) +{ + return skb->protocol; +} + +/** + * __cdf_nbuf_get_ip_summed() - return the ip checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: skb ip_summed + */ +static inline uint8_t __cdf_nbuf_get_ip_summed(struct sk_buff *skb) +{ + return skb->ip_summed; +} + +/** + * __cdf_nbuf_set_ip_summed() - sets the ip_summed value of the skb + * @skb: Pointer to network buffer + * @ip_summed: ip checksum + * + * Return: none + */ +static inline void __cdf_nbuf_set_ip_summed(struct sk_buff *skb, uint8_t ip_summed) +{ + skb->ip_summed = ip_summed; +} + +/** + * __cdf_nbuf_get_priority() - return the priority value of the skb + * @skb: Pointer to network buffer + * + * Return: skb priority + */ +static inline uint32_t __cdf_nbuf_get_priority(struct sk_buff *skb) +{ + return skb->priority; +} + +/** + * __cdf_nbuf_set_priority() - sets the priority value of the skb + * @skb: Pointer to network buffer + * @p: priority + * + * Return: none + */ +static inline void __cdf_nbuf_set_priority(struct sk_buff *skb, uint32_t p) +{ + skb->priority = p; +} + +/** + * __cdf_nbuf_set_next() - sets the next skb pointer of the current skb + * @skb: Current skb + * @next_skb: Next skb + * + * Return: void + */ +static inline void +__cdf_nbuf_set_next(struct sk_buff *skb, struct sk_buff *skb_next) +{ + skb->next = skb_next; +} + +/** + * __cdf_nbuf_next() - return the next skb pointer of the current skb + * @skb: Current skb + * + * Return: the next skb pointed to by the current skb + */ +static inline struct sk_buff *__cdf_nbuf_next(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __cdf_nbuf_set_next_ext() - sets the next skb pointer of the current skb + * @skb: Current skb + * @next_skb: Next skb + * + * This fn is used to link up extensions to the head skb. Does not handle + * linking to the head + * + * Return: none + */ +static inline void +__cdf_nbuf_set_next_ext(struct sk_buff *skb, struct sk_buff *skb_next) +{ + skb->next = skb_next; +} + +/** + * __cdf_nbuf_next_ext() - return the next skb pointer of the current skb + * @skb: Current skb + * + * Return: the next skb pointed to by the current skb + */ +static inline struct sk_buff *__cdf_nbuf_next_ext(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __cdf_nbuf_append_ext_list() - link list of packet extensions to the head + * @skb_head: head_buf nbuf holding head segment (single) + * @ext_list: nbuf list holding linked extensions to the head + * @ext_len: Total length of all buffers in the extension list + * + * This function is used to link up a list of packet extensions (seg1, 2,* ...) + * to the nbuf holding the head segment (seg0) + * + * Return: none + */ +static inline void +__cdf_nbuf_append_ext_list(struct sk_buff *skb_head, + struct sk_buff *ext_list, size_t ext_len) +{ + skb_shinfo(skb_head)->frag_list = ext_list; + skb_head->data_len = ext_len; + skb_head->len += skb_head->data_len; +} + +/** + * __cdf_nbuf_tx_free() - free skb list + * @skb: Pointer to network buffer + * @tx_err: TX error + * + * Return: none + */ +static inline void __cdf_nbuf_tx_free(struct sk_buff *bufs, int tx_err) +{ + while (bufs) { + struct sk_buff *next = __cdf_nbuf_next(bufs); + __cdf_nbuf_free(bufs); + bufs = next; + } +} + +/** + * __cdf_nbuf_get_age() - return the checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: checksum value + */ +static inline uint32_t __cdf_nbuf_get_age(struct sk_buff *skb) +{ + return skb->csum; +} + +/** + * __cdf_nbuf_set_age() - sets the checksum value of the skb + * @skb: Pointer to network buffer + * @v: Value + * + * Return: none + */ +static inline void __cdf_nbuf_set_age(struct sk_buff *skb, uint32_t v) +{ + skb->csum = v; +} + +/** + * __cdf_nbuf_adj_age() - adjusts the checksum/age value of the skb + * @skb: Pointer to network buffer + * @adj: Adjustment value + * + * Return: none + */ +static inline void __cdf_nbuf_adj_age(struct sk_buff *skb, uint32_t adj) +{ + skb->csum -= adj; +} + +/** + * __cdf_nbuf_copy_bits() - return the length of the copy bits for skb + * @skb: Pointer to network buffer + * @offset: Offset value + * @len: Length + * @to: Destination pointer + * + * Return: length of the copy bits for skb + */ +static inline int32_t +__cdf_nbuf_copy_bits(struct sk_buff *skb, int32_t offset, int32_t len, void *to) +{ + return skb_copy_bits(skb, offset, to, len); +} + +/** + * __cdf_nbuf_set_pktlen() - sets the length of the skb and adjust the tail + * @skb: Pointer to network buffer + * @len: Packet length + * + * Return: none + */ +static inline void __cdf_nbuf_set_pktlen(struct sk_buff *skb, uint32_t len) +{ + if (skb->len > len) { + skb_trim(skb, len); + } else { + if (skb_tailroom(skb) < len - skb->len) { + if (unlikely(pskb_expand_head(skb, 0, + len - skb->len - skb_tailroom(skb), + GFP_ATOMIC))) { + dev_kfree_skb_any(skb); + cdf_assert(0); + } + } + skb_put(skb, (len - skb->len)); + } +} + +/** + * __cdf_nbuf_set_protocol() - sets the protocol value of the skb + * @skb: Pointer to network buffer + * @protocol: Protocol type + * + * Return: none + */ +static inline void +__cdf_nbuf_set_protocol(struct sk_buff *skb, uint16_t protocol) +{ + skb->protocol = protocol; +} + +#define __cdf_nbuf_set_tx_htt2_frm(skb, candi) \ + NBUF_SET_TX_HTT2_FRM(skb, candi) +#define __cdf_nbuf_get_tx_htt2_frm(skb) \ + NBUF_GET_TX_HTT2_FRM(skb) + +#if defined(FEATURE_TSO) +uint32_t __cdf_nbuf_get_tso_info(cdf_device_t osdev, struct sk_buff *skb, + struct cdf_tso_info_t *tso_info); + +uint32_t __cdf_nbuf_get_tso_num_seg(struct sk_buff *skb); + +static inline uint8_t __cdf_nbuf_is_tso(struct sk_buff *skb) +{ + return skb_is_gso(skb); +} + +struct sk_buff *__cdf_nbuf_inc_users(struct sk_buff *skb); +#endif /* TSO */ + +/** + * __cdf_nbuf_tx_info_get() - Modify pkt_type, set pkt_subtype, + * and get hw_classify by peeking + * into packet + * @nbuf: Network buffer (skb on Linux) + * @pkt_type: Pkt type (from enum htt_pkt_type) + * @pkt_subtype: Bit 4 of this field in HTT descriptor + * needs to be set in case of CE classification support + * Is set by this macro. + * @hw_classify: This is a flag which is set to indicate + * CE classification is enabled. + * Do not set this bit for VLAN packets + * OR for mcast / bcast frames. + * + * This macro parses the payload to figure out relevant Tx meta-data e.g. + * whether to enable tx_classify bit in CE. + * + * Overrides pkt_type only if required for 802.3 frames (original ethernet) + * If protocol is less than ETH_P_802_3_MIN (0x600), then + * it is the length and a 802.3 frame else it is Ethernet Type II + * (RFC 894). + * Bit 4 in pkt_subtype is the tx_classify bit + * + * Return: void + */ +#define __cdf_nbuf_tx_info_get(skb, pkt_type, \ + pkt_subtype, hw_classify) \ +do { \ + struct ethhdr *eh = (struct ethhdr *)skb->data; \ + uint16_t ether_type = ntohs(eh->h_proto); \ + bool is_mc_bc; \ + \ + is_mc_bc = is_broadcast_ether_addr((uint8_t *)eh) || \ + is_multicast_ether_addr((uint8_t *)eh); \ + \ + if (likely((ether_type != ETH_P_8021Q) && !is_mc_bc)) { \ + hw_classify = 1; \ + pkt_subtype = 0x01 << \ + HTT_TX_CLASSIFY_BIT_S; \ + } \ + \ + if (unlikely(ether_type < ETH_P_802_3_MIN)) \ + pkt_type = htt_pkt_type_ethernet; \ + \ +} while (0) +#endif /*_I_CDF_NET_BUF_H */ diff --git a/core/cdf/src/i_cdf_softirq_timer.h b/core/cdf/src/i_cdf_softirq_timer.h new file mode 100644 index 0000000000..31cbd68e59 --- /dev/null +++ b/core/cdf/src/i_cdf_softirq_timer.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _I_CDF_SOFTIRQ_TIMER_H +#define _I_CDF_SOFTIRQ_TIMER_H + +#include +#include +#include +#include +#include + +/* timer data type */ +typedef struct timer_list __cdf_softirq_timer_t; + +/* ugly - but every other OS takes, sanely, a void */ + +typedef void (*cdf_dummy_timer_func_t)(unsigned long arg); + +/** + * __cdf_softirq_timer_init() - initialize a softirq timer + * @hdl: OS handle + * @timer: Pointer to timer object + * @func: Function pointer + * @arg: Arguement + * @type: deferrable or non deferrable timer type + * + * Timer type CDF_TIMER_TYPE_SW means its a deferrable sw timer which will + * not cause CPU wake upon expiry + * Timer type CDF_TIMER_TYPE_WAKE_APPS means its a non-deferrable timer which + * will cause CPU wake up on expiry + * + * Return: none + */ +static inline CDF_STATUS +__cdf_softirq_timer_init(cdf_handle_t hdl, + struct timer_list *timer, + cdf_softirq_timer_func_t func, void *arg, + CDF_TIMER_TYPE type) +{ + if (CDF_TIMER_TYPE_SW == type) + init_timer_deferrable(timer); + else + init_timer(timer); + timer->function = (cdf_dummy_timer_func_t) func; + timer->data = (unsigned long)arg; + + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_softirq_timer_start() - start a cdf softirq timer + * @timer: Pointer to timer object + * @delay: Delay in milli seconds + * + * Return: none + */ +static inline CDF_STATUS +__cdf_softirq_timer_start(struct timer_list *timer, uint32_t delay) +{ + timer->expires = jiffies + msecs_to_jiffies(delay); + add_timer(timer); + + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_softirq_timer_mod() - modify a timer + * @timer: Pointer to timer object + * @delay: Delay in milli seconds + * + * Return: none + */ +static inline CDF_STATUS +__cdf_softirq_timer_mod(struct timer_list *timer, uint32_t delay) +{ + mod_timer(timer, jiffies + msecs_to_jiffies(delay)); + + return CDF_STATUS_SUCCESS; +} + +/** + * __cdf_softirq_timer_cancel() - cancel a timer + * @timer: Pointer to timer object + * + * Return: true if timer was cancelled and deactived, + * false if timer was cancelled but already got fired. + */ +static inline bool __cdf_softirq_timer_cancel(struct timer_list *timer) +{ + if (likely(del_timer(timer))) + return 1; + else + return 0; +} + +/** + * __cdf_softirq_timer_free() - free a cdf timer + * @timer: Pointer to timer object + * + * Return: true if timer was cancelled and deactived, + * false if timer was cancelled but already got fired. + */ +static inline void __cdf_softirq_timer_free(struct timer_list *timer) +{ + del_timer_sync(timer); +} + +/** + * __cdf_sostirq_timer_sync_cancel() - Synchronously canel a timer + * @timer: Pointer to timer object + * + * Synchronization Rules: + * 1. caller must make sure timer function will not use + * cdf_softirq_set_timer to add iteself again. + * 2. caller must not hold any lock that timer function + * is likely to hold as well. + * 3. It can't be called from interrupt context. + * + * Return: true if timer was cancelled and deactived, + * false if timer was cancelled but already got fired. + */ +static inline bool __cdf_sostirq_timer_sync_cancel(struct timer_list *timer) +{ + return del_timer_sync(timer); +} + +#endif /*_ADF_OS_TIMER_PVT_H*/ diff --git a/core/cdf/src/i_cdf_time.h b/core/cdf/src/i_cdf_time.h new file mode 100644 index 0000000000..08cf5b4a15 --- /dev/null +++ b/core/cdf/src/i_cdf_time.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_cdf_time.h + * + * Linux specific CDF timing APIs implementation + */ + +#ifndef _I_CDF_TIME_H +#define _I_CDF_TIME_H + +#include +#include +#include +#ifdef CONFIG_CNSS +#include +#endif + +typedef unsigned long __cdf_time_t; + +/** + * __cdf_system_ticks() - get system ticks + * + * Return: system tick in jiffies + */ +static inline __cdf_time_t __cdf_system_ticks(void) +{ + return jiffies; +} + +/** + * __cdf_system_ticks_to_msecs() - convert system ticks into milli seconds + * @ticks: System ticks + * + * Return: system tick converted into milli seconds + */ +static inline uint32_t __cdf_system_ticks_to_msecs(unsigned long ticks) +{ + return jiffies_to_msecs(ticks); +} + +/** + * __cdf_system_msecs_to_ticks() - convert milli seconds into system ticks + * @msecs: Milli seconds + * + * Return: milli seconds converted into system ticks + */ +static inline __cdf_time_t __cdf_system_msecs_to_ticks(uint32_t msecs) +{ + return msecs_to_jiffies(msecs); +} + +/** + * __cdf_get_system_uptime() - get system uptime + * + * Return: system uptime in jiffies + */ +static inline __cdf_time_t __cdf_get_system_uptime(void) +{ + return jiffies; +} + +static inline __cdf_time_t __cdf_get_system_timestamp(void) +{ + return (jiffies / HZ) * 1000 + (jiffies % HZ) * (1000 / HZ); +} + +/** + * __cdf_udelay() - delay execution for given microseconds + * @usecs: Micro seconds to delay + * + * Return: none + */ +static inline void __cdf_udelay(uint32_t usecs) +{ +#ifdef CONFIG_ARM + /* + * This is in support of XScale build. They have a limit on the udelay + * value, so we have to make sure we don't approach the limit + */ + + uint32_t mticks; + uint32_t leftover; + int i; + + /* slice into 1024 usec chunks (simplifies calculation) */ + + mticks = usecs >> 10; + leftover = usecs - (mticks << 10); + + for (i = 0; i < mticks; i++) + udelay(1024); + + udelay(leftover); + +#else + /* Normal Delay functions. Time specified in microseconds */ + udelay(usecs); + +#endif +} + +/** + * __cdf_mdelay() - delay execution for given milli seconds + * @usecs: Milli seconds to delay + * + * Return: none + */ +static inline void __cdf_mdelay(uint32_t msecs) +{ + mdelay(msecs); +} + +/** + * __cdf_system_time_after() - Check if a is later than b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a < b else false + */ +static inline bool __cdf_system_time_after(__cdf_time_t a, __cdf_time_t b) +{ + return (long)(b) - (long)(a) < 0; +} + +/** + * __cdf_system_time_before() - Check if a is before b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a is before b else false + */ +static inline bool __cdf_system_time_before(__cdf_time_t a, __cdf_time_t b) +{ + return __cdf_system_time_after(b, a); +} + +/** + * __cdf_system_time_before() - Check if a atleast as recent as b, if not + * later + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a >= b else false + */ +static inline bool __cdf_system_time_after_eq(__cdf_time_t a, __cdf_time_t b) +{ + return (long)(a) - (long)(b) >= 0; +} + +/** + * __cdf_get_monotonic_boottime() - get monotonic kernel boot time + * This API is similar to cdf_get_system_boottime but it includes + * time spent in suspend. + * + * Return: Time in microseconds + */ +#ifdef CONFIG_CNSS +static inline uint64_t __cdf_get_monotonic_boottime(void) +{ + struct timespec ts; + + cnss_get_monotonic_boottime(&ts); + + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +} +#else +static inline uint64_t __cdf_get_monotonic_boottime(void) +{ + return __cdf_system_ticks_to_msecs(__cdf_system_ticks()) * 1000; +} +#endif /* CONFIG_CNSS */ + +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * __cdf_get_qtimer_ticks() - get QTIMER ticks + * + * Returns QTIMER(19.2 MHz) clock ticks. To convert it into seconds + * divide it by 19200. + * + * Return: QTIMER(19.2 MHz) clock ticks + */ +static inline uint64_t __cdf_get_qtimer_ticks(void) +{ + return arch_counter_get_cntpct(); +} +#endif /* QCA_WIFI_3_0_ADRASTEA */ + +#endif diff --git a/core/cdf/src/i_cdf_trace.h b/core/cdf/src/i_cdf_trace.h new file mode 100644 index 0000000000..a3b36ee8c5 --- /dev/null +++ b/core/cdf/src/i_cdf_trace.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_CDF_TRACE_H) +#define __I_CDF_TRACE_H + +#if !defined(__printf) +#define __printf(a, b) +#endif + +/** + * DOC: i_cdf_trace.h + * + * Linux-specific definitions for CDF trace + * + */ + +/* Include Files */ + +/** + * cdf_trace_msg()- logging API + * @module: Module identifier. A member of the CDF_MODULE_ID enumeration that + * identifies the module issuing the trace message. + * @level: Trace level. A member of the CDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * @strFormat: Format string. The message to be logged. This format string + * contains printf-like replacement parameters, which follow this + * parameter in the variable argument list. + * + * Users wishing to add tracing information to their code should use + * CDF_TRACE. CDF_TRACE() will compile into a call to cdf_trace_msg() when + * tracing is enabled. + * + * Return: nothing + * + */ +void __printf(3, 4) cdf_trace_msg(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + char *strFormat, ...); + +void cdf_trace_hex_dump(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + void *data, int buf_len); + +void cdf_trace_display(void); + +void cdf_trace_set_value(CDF_MODULE_ID module, CDF_TRACE_LEVEL level, + uint8_t on); + +void cdf_trace_set_module_trace_level(CDF_MODULE_ID module, uint32_t level); + +/* CDF_TRACE is the macro invoked to add trace messages to code. See the + * documenation for cdf_trace_msg() for the parameters etc. for this function. + * + * NOTE: Code CDF_TRACE() macros into the source code. Do not code directly + * to the cdf_trace_msg() function. + * + * NOTE 2: cdf tracing is totally turned off if WLAN_DEBUG is *not* defined. + * This allows us to build 'performance' builds where we can measure performance + * without being bogged down by all the tracing in the code + */ + +#if defined(WLAN_DEBUG) +#define CDF_TRACE cdf_trace_msg +#define CDF_TRACE_HEX_DUMP cdf_trace_hex_dump +#else +#define CDF_TRACE(arg ...) +#define CDF_TRACE_HEX_DUMP(arg ...) +#endif + +void __printf(3, 4) cdf_snprintf(char *strBuffer, unsigned int size, + char *strFormat, ...); +#define CDF_SNPRINTF cdf_snprintf + +#ifdef CDF_ENABLE_TRACING + +#define CDF_ASSERT(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("CDF ASSERT in %s Line %d\n", \ + __func__, __LINE__); \ + WARN_ON(1); \ + } \ + } while (0) + +#else + +/* This code will be used for compilation if tracing is to be compiled out */ +/* of the code so these functions/macros are 'do nothing' */ +CDF_INLINE_FN void cdf_trace_msg(CDF_MODULE_ID module, ...) +{ +} + +#define CDF_ASSERT(_condition) + +#endif + +#ifdef PANIC_ON_BUG + +#define CDF_BUG(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("CDF BUG in %s Line %d\n", \ + __func__, __LINE__); \ + BUG_ON(1); \ + } \ + } while (0) + +#else + +#define CDF_BUG(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("CDF BUG in %s Line %d\n", \ + __func__, __LINE__); \ + WARN_ON(1); \ + } \ + } while (0) + +#endif + +#endif diff --git a/core/cdf/src/i_cdf_types.h b/core/cdf/src/i_cdf_types.h new file mode 100644 index 0000000000..febbaff235 --- /dev/null +++ b/core/cdf/src/i_cdf_types.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_cdf_types.h + * + * Connectivity driver framework (CDF) types + */ + +#if !defined(__I_CDF_TYPES_H) +#define __I_CDF_TYPES_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __KERNEL__ +#define __iomem +#endif +#include +#include +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#else + +/* + * Hack - coexist with prior defs of dma_addr_t. + * Eventually all other defs of dma_addr_t should be removed. + * At that point, the "already_defined" wrapper can be removed. + */ +#ifndef __dma_addr_t_already_defined__ +#define __dma_addr_t_already_defined__ +typedef unsigned long dma_addr_t; +#endif + +#define SIOCGIWAP 0 +#define IWEVCUSTOM 0 +#define IWEVREGISTERED 0 +#define IWEVEXPIRED 0 +#define SIOCGIWSCAN 0 +#define DMA_TO_DEVICE 0 +#define DMA_FROM_DEVICE 0 +#define __iomem +#endif /* __KERNEL__ */ + +/** + * max sg that we support + */ +#define __CDF_OS_MAX_SCATTER 1 + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define CDF_LITTLE_ENDIAN_MACHINE +#elif defined (__BIG_ENDIAN_BITFIELD) +#define CDF_BIG_ENDIAN_MACHINE +#else +#error "Please fix " +#endif + +#define __cdf_packed __attribute__ ((packed)) + +typedef int (*__cdf_os_intr)(void *); +/** + * Private definitions of general data types + */ +typedef dma_addr_t __cdf_dma_addr_t; +typedef dma_addr_t __cdf_dma_context_t; + +#define cdf_dma_mem_context(context) dma_addr_t context +#define cdf_get_dma_mem_context(var, field) ((cdf_dma_context_t)(var->field)) + +/** + * typedef struct __cdf_resource_t - cdf resource type + * @paddr: Physical address + * @paddr: Virtual address + * @len: Length + */ +typedef struct __cdf_os_resource { + unsigned long paddr; + void __iomem *vaddr; + unsigned long len; +} __cdf_resource_t; + +/** + * struct __cdf_device - generic cdf device type + * @drv: Pointer to driver + * @drv_hdl: Pointer to driver handle + * @drv_name: Pointer to driver name + * @irq: IRQ + * @dev: Pointer to device + * @res: CDF resource + * @func: Interrupt handler + */ +struct __cdf_device { + void *drv; + void *drv_hdl; + char *drv_name; + int irq; + struct device *dev; + __cdf_resource_t res; + __cdf_os_intr func; +}; + +typedef struct __cdf_device *__cdf_device_t; + +typedef size_t __cdf_size_t; +typedef uint8_t __iomem *__cdf_iomem_t; + +/** + * typedef struct __cdf_segment_t - cdf segment + * @daddr: DMA address + * @len: Length + */ +typedef struct __cdf_segment { + dma_addr_t daddr; + uint32_t len; +} __cdf_segment_t; + +/** + * struct __cdf_dma_map - dma map + * @mapped: dma is mapped or not + * @nsegs: Number of segments + * @coherent: Coherent + * @seg: Segment array + */ +struct __cdf_dma_map { + uint32_t mapped; + uint32_t nsegs; + uint32_t coherent; + __cdf_segment_t seg[__CDF_OS_MAX_SCATTER]; +}; +typedef struct __cdf_dma_map *__cdf_dma_map_t; +typedef uint32_t ath_dma_addr_t; + +#define __cdf_print printk +#define __cdf_vprint vprintk +#define __cdf_snprint snprintf +#define __cdf_vsnprint vsnprintf + +#define __CDF_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL +#define __CDF_DMA_TO_DEVICE DMA_TO_DEVICE +#define __CDF_DMA_FROM_DEVICE DMA_FROM_DEVICE +#define __cdf_inline inline + +/* + * 1. GNU C/C++ Compiler + * + * How to detect gcc : __GNUC__ + * How to detect gcc version : + * major version : __GNUC__ (2 = 2.x, 3 = 3.x, 4 = 4.x) + * minor version : __GNUC_MINOR__ + * + * 2. Microsoft C/C++ Compiler + * + * How to detect msc : _MSC_VER + * How to detect msc version : + * _MSC_VER (1200 = MSVC 6.0, 1300 = MSVC 7.0, ...) + * + */ + +/* MACROs to help with compiler and OS specifics. May need to get a little + * more sophisticated than this and define these to specific 'VERSIONS' of + * the compiler and OS. Until we have a need for that, lets go with this + */ +#if defined(_MSC_VER) + +#define CDF_COMPILER_MSC +/* assuming that if we build with MSC, OS is WinMobile */ +#define CDF_OS_WINMOBILE + +#elif defined(__GNUC__) + +#define CDF_COMPILER_GNUC +#define CDF_OS_LINUX /* assuming if building with GNUC, OS is Linux */ + +#endif + +#if defined(CDF_COMPILER_MSC) + +#define CDF_INLINE_FN __inline + +/* Does nothing on Windows. packing individual structs is not + * supported on the Windows compiler + */ +#define CDF_PACK_STRUCT_1 +#define CDF_PACK_STRUCT_2 +#define CDF_PACK_STRUCT_4 +#define CDF_PACK_STRUCT_8 +#define CDF_PACK_STRUCT_16 + +#elif defined(CDF_COMPILER_GNUC) + +#define CDF_INLINE_FN static inline + +#else +#error "Compiling with an unknown compiler!!" +#endif + +#endif /* __I_CDF_TYPES_H */ diff --git a/core/cdf/src/i_cdf_util.h b/core/cdf/src/i_cdf_util.h new file mode 100644 index 0000000000..db2f11fa7e --- /dev/null +++ b/core/cdf/src/i_cdf_util.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _I_CDF_UTIL_H +#define _I_CDF_UTIL_H + +#include +#include +#include +#include + +#include + +#include +#include +#include +/* + * Generic compiler-dependent macros if defined by the OS + */ + +#define __cdf_unlikely(_expr) unlikely(_expr) +#define __cdf_likely(_expr) likely(_expr) + +/** + * cdf_status_to_os_return(): translates cdf_status types to linux return types + * @status: status to translate + * + * Translates error types that linux may want to handle specially. + * + * return: 0 or the linux error code that most closely matches the CDF_STATUS. + * defaults to -1 (EPERM) + */ +static inline int __cdf_status_to_os_return(CDF_STATUS status) +{ + switch (status) { + case CDF_STATUS_SUCCESS: + return 0; + case CDF_STATUS_E_NULL_VALUE: + case CDF_STATUS_E_FAULT: + return -EFAULT; + case CDF_STATUS_E_TIMEOUT: + case CDF_STATUS_E_BUSY: + return -EBUSY; + case CDF_STATUS_NOT_INITIALIZED: + case CDF_STATUS_E_AGAIN: + return -EAGAIN; + case CDF_STATUS_E_NOSUPPORT: + return -ENOSYS; + case CDF_STATUS_E_ALREADY: + return -EALREADY; + case CDF_STATUS_E_NOMEM: + return -ENOMEM; + default: + return -EPERM; + } +} + + +/** + * @brief memory barriers. + */ + +#define __cdf_min(_a, _b) ((_a) < (_b) ? _a : _b) +#define __cdf_max(_a, _b) ((_a) > (_b) ? _a : _b) + +/** + * @brief Assert + */ +#define __cdf_assert(expr) do { \ + if (unlikely(!(expr))) { \ + pr_err("Assertion failed! %s:%s %s:%d\n", \ + # expr, __func__, __FILE__, __LINE__); \ + dump_stack(); \ + panic("Take care of the assert first\n"); \ + } \ +} while (0) + +#define __cdf_os_cpu_to_le64 cpu_to_le64 +#define __cdf_le16_to_cpu le16_to_cpu +#define __cdf_le32_to_cpu le32_to_cpu +#define __cdf_container_of(ptr, type, member) container_of(ptr, type, member) + +#endif /*_I_CDF_UTIL_H*/ diff --git a/core/cds/inc/cds_api.h b/core/cds/inc/cds_api.h new file mode 100644 index 0000000000..01618a5783 --- /dev/null +++ b/core/cds/inc/cds_api.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#if !defined(__CDS_API_H) +#define __CDS_API_H + +/** + * DOC: cds_api.h + * + * Connectivity driver services public API + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amount of time to wait for WMA to perform an asynchronous activity. + * This value should be larger than the timeout used by WMI to wait for + * a response from target + */ +#define CDS_WMA_TIMEOUT (15000) + +CDF_STATUS cds_alloc_global_context(v_CONTEXT_t *p_cds_context); + +CDF_STATUS cds_free_global_context(v_CONTEXT_t *p_cds_context); + +CDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context); + +CDF_STATUS cds_open(v_CONTEXT_t *p_cds_context, uint32_t hddContextSize); + +CDF_STATUS cds_enable(v_CONTEXT_t cds_context); + +CDF_STATUS cds_disable(v_CONTEXT_t cds_context); + +CDF_STATUS cds_close(v_CONTEXT_t cds_context); + +CDF_STATUS cds_shutdown(v_CONTEXT_t cds_context); + +void cds_core_return_msg(void *pVContext, p_cds_msg_wrapper pMsgWrapper); + +void *cds_get_context(CDF_MODULE_ID moduleId); + +v_CONTEXT_t cds_get_global_context(void); + +uint8_t cds_is_logp_in_progress(void); +void cds_set_logp_in_progress(uint8_t value); + +uint8_t cds_is_load_unload_in_progress(void); +void cds_set_load_unload_in_progress(uint8_t value); + +CDF_STATUS cds_alloc_context(void *p_cds_context, CDF_MODULE_ID moduleID, + void **ppModuleContext, uint32_t size); + +CDF_STATUS cds_free_context(void *p_cds_context, CDF_MODULE_ID moduleID, + void *pModuleContext); + +CDF_STATUS cds_get_vdev_types(tCDF_CON_MODE mode, uint32_t *type, + uint32_t *subType); + +void cds_flush_work(void *work); +void cds_flush_delayed_work(void *dwork); + +bool cds_is_packet_log_enabled(void); + +uint64_t cds_get_monotonic_boottime(void); + +void cds_trigger_recovery(void); + +void cds_set_wakelock_logging(bool value); +bool cds_is_wakelock_enabled(void); +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level); +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id); +void cds_set_multicast_logging(uint8_t value); +uint8_t cds_is_multicast_logging(void); +CDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t type, + uint32_t sub_type); +void cds_get_log_completion(uint32_t *is_fatal, + uint32_t *type, + uint32_t *sub_type); +bool cds_is_log_report_in_progress(void); +void cds_init_log_completion(void); +void cds_deinit_log_completion(void); +CDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code); +void cds_logging_set_fw_flush_complete(void); +#endif /* if !defined __CDS_API_H */ diff --git a/core/cds/inc/cds_concurrency.h b/core/cds/inc/cds_concurrency.h new file mode 100644 index 0000000000..972941c078 --- /dev/null +++ b/core/cds/inc/cds_concurrency.h @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CDS_CONCURRENCY_H +#define __CDS_CONCURRENCY_H + +/** + * DOC: cds_concurrency.h + * + * CDS Concurrenct Connection Management entity + */ + +/* Include files */ + +#include "wlan_hdd_main.h" + +#define MAX_NUMBER_OF_CONC_CONNECTIONS 3 +#define MAX_NUM_CHAN 128 +#define DBS_OPPORTUNISTIC_TIME 10 + +/** + * enum cds_chain_mode - Chain Mask tx & rx combination. + * + * @CDS_ONE_ONE: One for Tx, One for Rx + * @CDS_TWO_TWO: Two for Tx, Two for Rx + * @CDS_MAX_NO_OF_CHAIN_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_chain_mode { + CDS_ONE_ONE = 0, + CDS_TWO_TWO, + CDS_MAX_NO_OF_CHAIN_MODE +}; + +/** + * enum cds_conc_priority_mode - t/p, powersave, latency. + * + * @CDS_THROUGHPUT: t/p is the priority + * @CDS_POWERSAVE: powersave is the priority + * @CDS_LATENCY: latency is the priority + * @CDS_MAX_CONC_PRIORITY_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_conc_priority_mode { + CDS_THROUGHPUT = 0, + CDS_POWERSAVE, + CDS_LATENCY, + CDS_MAX_CONC_PRIORITY_MODE +}; + +/** + * enum cds_con_mode - concurrency mode for PCL table + * + * @CDS_STA_MODE: station mode + * @CDS_SAP_MODE: SAP mode + * @CDS_P2P_CLIENT_MODE: P2P client mode + * @CDS_P2P_GO_MODE: P2P Go mode + * @CDS_IBSS_MODE: IBSS mode + * @CDS_MAX_NUM_OF_MODE: max value place holder + */ +enum cds_con_mode { + CDS_STA_MODE = 0, + CDS_SAP_MODE, + CDS_P2P_CLIENT_MODE, + CDS_P2P_GO_MODE, + CDS_IBSS_MODE, + CDS_MAX_NUM_OF_MODE +}; + +/** + * enum cds_pcl_type - Various types of Preferred channel list (PCL). + * + * @CDS_NONE: No channel preference + * @CDS_24G: 2.4 Ghz channels only + * @CDS_5G: 5 Ghz channels only + * @CDS_SCC_CH: SCC channel only + * @CDS_MCC_CH: MCC channels only + * @CDS_SCC_CH_24G: SCC channel & 2.4 Ghz channels + * @CDS_SCC_CH_5G: SCC channel & 5 Ghz channels + * @CDS_24G_SCC_CH: 2.4 Ghz channels & SCC channel + * @CDS_5G_SCC_CH: 5 Ghz channels & SCC channel + * @CDS_SCC_ON_5_SCC_ON_24_24G: SCC channel on 5 Ghz, SCC + * channel on 2.4 Ghz & 2.4 Ghz channels + * @CDS_SCC_ON_5_SCC_ON_24_5G: SCC channel on 5 Ghz, SCC channel + * on 2.4 Ghz & 5 Ghz channels + * @CDS_SCC_ON_24_SCC_ON_5_24G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 2.4 Ghz channels + * @CDS_SCC_ON_24_SCC_ON_5_5G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 5 Ghz channels + * @CDS_SCC_ON_5_SCC_ON_24: SCC channel on 5 Ghz, SCC channel on + * 2.4 Ghz + * @CDS_SCC_ON_24_SCC_ON_5: SCC channel on 2.4 Ghz, SCC channel + * on 5 Ghz + * @CDS_MCC_CH_24G: MCC channels & 2.4 Ghz channels + * @CDS_MCC_CH_5G: MCC channels & 5 Ghz channels + * @CDS_24G_MCC_CH: 2.4 Ghz channels & MCC channels + * @CDS_5G_MCC_CH: 5 Ghz channels & MCC channels + * @CDS_MAX_PCL_TYPE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_pcl_type { + CDS_NONE = 0, + CDS_24G, + CDS_5G, + CDS_SCC_CH, + CDS_MCC_CH, + CDS_SCC_CH_24G, + CDS_SCC_CH_5G, + CDS_24G_SCC_CH, + CDS_5G_SCC_CH, + CDS_SCC_ON_5_SCC_ON_24_24G, + CDS_SCC_ON_5_SCC_ON_24_5G, + CDS_SCC_ON_24_SCC_ON_5_24G, + CDS_SCC_ON_24_SCC_ON_5_5G, + CDS_SCC_ON_5_SCC_ON_24, + CDS_SCC_ON_24_SCC_ON_5, + CDS_MCC_CH_24G, + CDS_MCC_CH_5G, + CDS_24G_MCC_CH, + CDS_5G_MCC_CH, + + CDS_MAX_PCL_TYPE +}; + +/** + * enum cds_one_connection_mode - Combination of first connection + * type, band & spatial stream used. + * + * @CDS_STA_24_1x1: STA connection using 1x1@2.4 Ghz + * @CDS_STA_24_2x2: STA connection using 2x2@2.4 Ghz + * @CDS_STA_5_1x1: STA connection using 1x1@5 Ghz + * @CDS_STA_5_2x2: STA connection using 2x2@5 Ghz + * @CDS_P2P_CLI_24_1x1: P2P Client connection using 1x1@2.4 Ghz + * @CDS_P2P_CLI_24_2x2: P2P Client connection using 2x2@2.4 Ghz + * @CDS_P2P_CLI_5_1x1: P2P Client connection using 1x1@5 Ghz + * @CDS_P2P_CLI_5_2x2: P2P Client connection using 2x2@5 Ghz + * @CDS_P2P_GO_24_1x1: P2P GO connection using 1x1@2.4 Ghz + * @CDS_P2P_GO_24_2x2: P2P GO connection using 2x2@2.4 Ghz + * @CDS_P2P_GO_5_1x1: P2P GO connection using 1x1@5 Ghz + * @CDS_P2P_GO_5_2x2: P2P GO connection using 2x2@5 Ghz + * @CDS_SAP_24_1x1: SAP connection using 1x1@2.4 Ghz + * @CDS_SAP_24_2x2: SAP connection using 2x2@2.4 Ghz + * @CDS_SAP_5_1x1: SAP connection using 1x1@5 Ghz + * @CDS_SAP_5_1x1: SAP connection using 2x2@5 Ghz + * @CDS_IBSS_24_1x1: IBSS connection using 1x1@2.4 Ghz + * @CDS_IBSS_24_2x2: IBSS connection using 2x2@2.4 Ghz + * @CDS_IBSS_5_1x1: IBSS connection using 1x1@5 Ghz + * @CDS_IBSS_5_2x2: IBSS connection using 2x2@5 Ghz + * @CDS_MAX_ONE_CONNECTION_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_one_connection_mode { + CDS_STA_24_1x1 = 0, + CDS_STA_24_2x2, + CDS_STA_5_1x1, + CDS_STA_5_2x2, + CDS_P2P_CLI_24_1x1, + CDS_P2P_CLI_24_2x2, + CDS_P2P_CLI_5_1x1, + CDS_P2P_CLI_5_2x2, + CDS_P2P_GO_24_1x1, + CDS_P2P_GO_24_2x2, + CDS_P2P_GO_5_1x1, + CDS_P2P_GO_5_2x2, + CDS_SAP_24_1x1, + CDS_SAP_24_2x2, + CDS_SAP_5_1x1, + CDS_SAP_5_2x2, + CDS_IBSS_24_1x1, + CDS_IBSS_24_2x2, + CDS_IBSS_5_1x1, + CDS_IBSS_5_2x2, + + CDS_MAX_ONE_CONNECTION_MODE +}; + +/** + * enum cds_two_connection_mode - Combination of first two + * connections type, concurrency state, band & spatial stream + * used. + * + * @CDS_STA_SAP_SCC_24_1x1: STA & SAP connection on SCC using + * 1x1@2.4 Ghz + * @CDS_STA_SAP_SCC_24_2x2: STA & SAP connection on SCC using + * 2x2@2.4 Ghz + * @CDS_STA_SAP_MCC_24_1x1: STA & SAP connection on MCC using + * 1x1@2.4 Ghz + * @CDS_STA_SAP_MCC_24_2x2: STA & SAP connection on MCC using + * 2x2@2.4 Ghz + * @CDS_STA_SAP_SCC_5_1x1: STA & SAP connection on SCC using + * 1x1@5 Ghz + * @CDS_STA_SAP_SCC_5_2x2: STA & SAP connection on SCC using + * 2x2@5 Ghz + * @CDS_STA_SAP_MCC_5_1x1: STA & SAP connection on MCC using + * 1x1@5 Ghz + * @CDS_STA_SAP_MCC_5_2x2: STA & SAP connection on MCC using + * 2x2@5 Ghz + * @CDS_STA_SAP_DBS_1x1,: STA & SAP connection on DBS using 1x1 + * @CDS_STA_P2P_GO_SCC_24_1x1: STA & P2P GO connection on SCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_GO_SCC_24_2x2: STA & P2P GO connection on SCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_GO_MCC_24_1x1: STA & P2P GO connection on MCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_GO_MCC_24_2x2: STA & P2P GO connection on MCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_GO_SCC_5_1x1: STA & P2P GO connection on SCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_GO_SCC_5_2x2: STA & P2P GO connection on SCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_GO_MCC_5_1x1: STA & P2P GO connection on MCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_GO_MCC_5_2x2: STA & P2P GO connection on MCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_GO_DBS_1x1: STA & P2P GO connection on DBS using + * 1x1 + * @CDS_STA_P2P_CLI_SCC_24_1x1: STA & P2P CLI connection on SCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_CLI_SCC_24_2x2: STA & P2P CLI connection on SCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_CLI_MCC_24_1x1: STA & P2P CLI connection on MCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_CLI_MCC_24_2x2: STA & P2P CLI connection on MCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_CLI_SCC_5_1x1: STA & P2P CLI connection on SCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_CLI_SCC_5_2x2: STA & P2P CLI connection on SCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_CLI_MCC_5_1x1: STA & P2P CLI connection on MCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_CLI_MCC_5_2x2: STA & P2P CLI connection on MCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_CLI_DBS_1x1: STA & P2P CLI connection on DBS + * using 1x1 + * @CDS_P2P_GO_P2P_CLI_SCC_24_1x1: P2P GO & CLI connection on + * SCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_24_2x2: P2P GO & CLI connection on + * SCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_24_1x1: P2P GO & CLI connection on + * MCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_24_2x2: P2P GO & CLI connection on + * MCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_5_1x1: P2P GO & CLI connection on + * SCC using 1x1@5 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_5_2x2: P2P GO & CLI connection on + * SCC using 2x2@5 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_5_1x1: P2P GO & CLI connection on + * MCC using 1x1@5 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_5_2x2: P2P GO & CLI connection on + * MCC using 2x2@5 Ghz + * @CDS_P2P_GO_P2P_CLI_DBS_1x1: P2P GO & CLI connection on DBS + * using 1x1 + * @CDS_P2P_GO_SAP_SCC_24_1x1: P2P GO & SAP connection on + * SCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_SAP_SCC_24_2x2: P2P GO & SAP connection on + * SCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_SAP_MCC_24_1x1: P2P GO & SAP connection on + * MCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_SAP_MCC_24_2x2: P2P GO & SAP connection on + * MCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_SAP_SCC_5_1x1: P2P GO & SAP connection on + * SCC using 1x1@5 Ghz + * @CDS_P2P_GO_SAP_SCC_5_2x2: P2P GO & SAP connection on + * SCC using 2x2@5 Ghz + * @CDS_P2P_GO_SAP_MCC_5_1x1: P2P GO & SAP connection on + * MCC using 1x1@5 Ghz + * @CDS_P2P_GO_SAP_MCC_5_2x2: P2P GO & SAP connection on + * MCC using 2x2@5 Ghz + * @CDS_P2P_GO_SAP_DBS_1x1: P2P GO & SAP connection on DBS using + * 1x1 + * @CDS_MAX_TWO_CONNECTION_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_two_connection_mode { + CDS_STA_SAP_SCC_24_1x1 = 0, + CDS_STA_SAP_SCC_24_2x2, + CDS_STA_SAP_MCC_24_1x1, + CDS_STA_SAP_MCC_24_2x2, + CDS_STA_SAP_SCC_5_1x1, + CDS_STA_SAP_SCC_5_2x2, + CDS_STA_SAP_MCC_5_1x1, + CDS_STA_SAP_MCC_5_2x2, + CDS_STA_SAP_MCC_24_5_1x1, + CDS_STA_SAP_MCC_24_5_2x2, + CDS_STA_SAP_DBS_1x1, + CDS_STA_P2P_GO_SCC_24_1x1, + CDS_STA_P2P_GO_SCC_24_2x2, + CDS_STA_P2P_GO_MCC_24_1x1, + CDS_STA_P2P_GO_MCC_24_2x2, + CDS_STA_P2P_GO_SCC_5_1x1, + CDS_STA_P2P_GO_SCC_5_2x2, + CDS_STA_P2P_GO_MCC_5_1x1, + CDS_STA_P2P_GO_MCC_5_2x2, + CDS_STA_P2P_GO_MCC_24_5_1x1, + CDS_STA_P2P_GO_MCC_24_5_2x2, + CDS_STA_P2P_GO_DBS_1x1, + CDS_STA_P2P_CLI_SCC_24_1x1, + CDS_STA_P2P_CLI_SCC_24_2x2, + CDS_STA_P2P_CLI_MCC_24_1x1, + CDS_STA_P2P_CLI_MCC_24_2x2, + CDS_STA_P2P_CLI_SCC_5_1x1, + CDS_STA_P2P_CLI_SCC_5_2x2, + CDS_STA_P2P_CLI_MCC_5_1x1, + CDS_STA_P2P_CLI_MCC_5_2x2, + CDS_STA_P2P_CLI_MCC_24_5_1x1, + CDS_STA_P2P_CLI_MCC_24_5_2x2, + CDS_STA_P2P_CLI_DBS_1x1, + CDS_P2P_GO_P2P_CLI_SCC_24_1x1, + CDS_P2P_GO_P2P_CLI_SCC_24_2x2, + CDS_P2P_GO_P2P_CLI_MCC_24_1x1, + CDS_P2P_GO_P2P_CLI_MCC_24_2x2, + CDS_P2P_GO_P2P_CLI_SCC_5_1x1, + CDS_P2P_GO_P2P_CLI_SCC_5_2x2, + CDS_P2P_GO_P2P_CLI_MCC_5_1x1, + CDS_P2P_GO_P2P_CLI_MCC_5_2x2, + CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1, + CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2, + CDS_P2P_GO_P2P_CLI_DBS_1x1, + CDS_P2P_GO_SAP_SCC_24_1x1, + CDS_P2P_GO_SAP_SCC_24_2x2, + CDS_P2P_GO_SAP_MCC_24_1x1, + CDS_P2P_GO_SAP_MCC_24_2x2, + CDS_P2P_GO_SAP_SCC_5_1x1, + CDS_P2P_GO_SAP_SCC_5_2x2, + CDS_P2P_GO_SAP_MCC_5_1x1, + CDS_P2P_GO_SAP_MCC_5_2x2, + CDS_P2P_GO_SAP_MCC_24_5_1x1, + CDS_P2P_GO_SAP_MCC_24_5_2x2, + CDS_P2P_GO_SAP_DBS_1x1, + + CDS_MAX_TWO_CONNECTION_MODE +}; + +/** + * enum cds_conc_next_action - actions to be taken on old + * connections. + * + * @CDS_NOP: No action + * @CDS_DBS: switch to DBS mode + * @CDS_DBS_DOWNGRADE: switch to DBS mode & downgrade to 1x1 + * @CDS_MCC: switch to MCC/SCC mode + * @CDS_MCC_UPGRADE: switch to MCC/SCC mode & upgrade to 2x2 + * @CDS_MAX_CONC_PRIORITY_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_conc_next_action { + CDS_NOP = 0, + CDS_DBS, + CDS_DBS_DOWNGRADE, + CDS_MCC, + CDS_MCC_UPGRADE, + CDS_MAX_CONC_NEXT_ACTION +}; + +/** + * enum cds_band - wifi band. + * + * @CDS_BAND_24: 2.4 Ghz band + * @CDS_BAND_5: 5 Ghz band + * @CDS_MAX_BAND: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_band { + CDS_BAND_24 = 0, + CDS_BAND_5, + CDS_MAX_BAND +}; + +/** + * struct cds_conc_connection_info - information of all existing + * connections in the wlan system + * + * @mode: connection type + * @chan: channel of the connection + * @mac: The HW mac it is running + * @tx_spatial_stream: Tx spatial stream used by the connection + * @rx_spatial_stream: Tx spatial stream used by the connection + * @original_nss: nss negotiated at connection time + * @vdev_id: vdev id of the connection + * @in_use: if the table entry is active + */ +struct cds_conc_connection_info { + enum cds_con_mode mode; + uint8_t chan; + uint8_t mac; + enum cds_chain_mode chain_mask; + uint8_t tx_spatial_stream; + uint8_t rx_spatial_stream; + uint32_t original_nss; + uint32_t vdev_id; + bool in_use; +}; + +bool cds_is_connection_in_progress(hdd_context_t *hdd_ctx); +void cds_dump_concurrency_info(hdd_context_t *pHddCtx); +void cds_set_concurrency_mode(hdd_context_t *pHddCtx, tCDF_CON_MODE mode); +void cds_clear_concurrency_mode(hdd_context_t *pHddCtx, + tCDF_CON_MODE mode); +uint32_t cds_get_connection_count(hdd_context_t *hdd_ctx); +/** + * cds_is_sta_connection_pending() - This function will check if sta connection + * is pending or not. + * @hdd_ctx: pointer to hdd context + * + * This function will return the status of flag is_sta_connection_pending + * + * Return: true or false + */ +static inline bool +cds_is_sta_connection_pending(hdd_context_t *hdd_ctx) +{ + bool status; + spin_lock(&hdd_ctx->sta_update_info_lock); + status = hdd_ctx->is_sta_connection_pending; + spin_unlock(&hdd_ctx->sta_update_info_lock); + return status; +} + +/** + * cds_change_sta_conn_pending_status() - This function will change the value + * of is_sta_connection_pending + * @hdd_ctx: pointer to hdd context + * @value: value to set + * + * This function will change the value of is_sta_connection_pending + * + * Return: none + */ +static inline void +cds_change_sta_conn_pending_status(hdd_context_t *hdd_ctx, + bool value) +{ + spin_lock(&hdd_ctx->sta_update_info_lock); + hdd_ctx->is_sta_connection_pending = value; + spin_unlock(&hdd_ctx->sta_update_info_lock); +} + +/** + * cds_is_sap_restart_required() - This function will check if sap restart + * is pending or not. + * @hdd_ctx: pointer to hdd context. + * + * This function will return the status of flag is_sap_restart_required. + * + * Return: true or false + */ +static inline bool +cds_is_sap_restart_required(hdd_context_t *hdd_ctx) +{ + bool status; + spin_lock(&hdd_ctx->sap_update_info_lock); + status = hdd_ctx->is_sap_restart_required; + spin_unlock(&hdd_ctx->sap_update_info_lock); + return status; +} + +/** + * cds_change_sap_restart_required_status() - This function will change the + * value of is_sap_restart_required + * @hdd_ctx: pointer to hdd context + * @value: value to set + * + * This function will change the value of is_sap_restart_required + * + * Return: none + */ +static inline void +cds_change_sap_restart_required_status(hdd_context_t *hdd_ctx, + bool value) +{ + spin_lock(&hdd_ctx->sap_update_info_lock); + hdd_ctx->is_sap_restart_required = value; + spin_unlock(&hdd_ctx->sap_update_info_lock); +} + +/** + * cds_set_connection_in_progress() - to set the connection in progress flag + * @hdd_ctx: pointer to hdd context + * @value: value to set + * + * This function will set the passed value to connection in progress flag. + * If value is previously being set to true then no need to set it again. + * + * Return: true if value is being set correctly and false otherwise. + */ +static inline bool +cds_set_connection_in_progress(hdd_context_t *hdd_ctx, + bool value) +{ + bool status = true; + spin_lock(&hdd_ctx->connection_status_lock); + /* + * if the value is set to true previously and if someone is + * trying to make it true again then it could be some race + * condition being triggered. Avoid this situation by returning + * false + */ + if (hdd_ctx->connection_in_progress && value) + status = false; + else + hdd_ctx->connection_in_progress = value; + spin_unlock(&hdd_ctx->connection_status_lock); + return status; +} + + +int cds_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +uint32_t cds_get_concurrency_mode(void); +CDF_STATUS cds_check_and_restart_sap(hdd_context_t *hdd_ctx, + eCsrRoamResult roam_result, + hdd_station_ctx_t *hdd_sta_ctx); +void cds_handle_conc_rule1(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile); +#ifdef FEATURE_WLAN_CH_AVOID +bool cds_handle_conc_rule2(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id); +#else +static inline bool cds_handle_conc_rule2(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + return true; +} +#endif /* FEATURE_WLAN_CH_AVOID */ +bool cds_handle_conc_multiport(uint8_t session_id, uint8_t channel); + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +void cds_force_sap_on_scc(hdd_context_t *hdd_ctx, eCsrRoamResult roam_result); +#else +static inline void cds_force_sap_on_scc(hdd_context_t *hdd_ctx, + eCsrRoamResult roam_result) +{ + +} +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void cds_check_concurrent_intf_and_restart_sap( + hdd_context_t *hdd_ctx, + hdd_station_ctx_t *hdd_sta_ctx, + hdd_adapter_t *adapter); +#else +static inline void cds_check_concurrent_intf_and_restart_sap( + hdd_context_t *hdd_ctx, + hdd_station_ctx_t *hdd_sta_ctx, + hdd_adapter_t *adapter) +{ + +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ +uint8_t cds_is_mcc_in_24G(hdd_context_t *hdd_ctx); +int32_t cds_set_mas(hdd_adapter_t *adapter, uint8_t mas_value); +int cds_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value); +CDF_STATUS cds_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter); +int cds_go_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value); +void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value); +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \ + defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) +void cds_restart_sap(hdd_adapter_t *ap_adapter); +#else +static inline void cds_restart_sap(hdd_adapter_t *ap_adapter) +{ + +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH || + * FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + */ + +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE +void cds_check_and_restart_sap_with_non_dfs_acs(hdd_context_t *hdd_ctx); +#else +static inline void cds_check_and_restart_sap_with_non_dfs_acs( + hdd_context_t *hdd_ctx) +{ + +} +#endif /* FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE */ +void cds_incr_active_session(hdd_context_t *pHddCtx, tCDF_CON_MODE mode, + uint8_t sessionId); +void cds_decr_active_session(hdd_context_t *pHddCtx, tCDF_CON_MODE mode, + uint8_t sessionId); +void cds_decr_session_set_pcl(hdd_context_t *hdd_ctx, + tCDF_CON_MODE mode, + uint8_t session_id); +CDF_STATUS cds_init_policy_mgr(hdd_context_t *hdd_ctx); +CDF_STATUS cds_get_pcl(hdd_context_t *hdd_ctx, enum cds_con_mode mode, + uint8_t *pcl_Channels, uint32_t *len); +bool cds_allow_concurrency(hdd_context_t *hdd_ctx, enum cds_con_mode mode, + uint8_t channel, enum hw_mode_bandwidth bw); +enum cds_conc_priority_mode cds_get_first_connection_pcl_table_index( + hdd_context_t *hdd_ctx); +enum cds_one_connection_mode cds_get_second_connection_pcl_table_index( + hdd_context_t *hdd_ctx); +enum cds_two_connection_mode cds_get_third_connection_pcl_table_index( + hdd_context_t *hdd_ctx); +CDF_STATUS cds_mode_switch_dbs_to_mcc(hdd_context_t *hdd_ctx); +CDF_STATUS cds_mode_switch_mcc_to_dbs(hdd_context_t *hdd_ctx); +CDF_STATUS cds_incr_connection_count(hdd_context_t *hdd_ctx, + uint32_t vdev_id); +CDF_STATUS cds_update_connection_info(hdd_context_t *hdd_ctx, + uint32_t vdev_id); +CDF_STATUS cds_decr_connection_count(hdd_context_t *hdd_ctx, + uint32_t vdev_id); +CDF_STATUS cds_current_connections_update( + hdd_context_t *hdd_ctx, uint8_t channel); +#ifdef MPC_UT_FRAMEWORK +CDF_STATUS cds_incr_connection_count_utfw(hdd_context_t *hdd_ctx, + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id); +CDF_STATUS cds_update_connection_info_utfw(hdd_context_t *hdd_ctx, + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id); +CDF_STATUS cds_decr_connection_count_utfw(hdd_context_t *hdd_ctx, + uint32_t del_all, uint32_t vdev_id); +struct cds_conc_connection_info *cds_get_conn_info(hdd_context_t *hdd_ctx, + uint32_t *len); +enum cds_pcl_type get_pcl_from_first_conn_table( + enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref); +enum cds_pcl_type get_pcl_from_second_conn_table( + enum cds_one_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable); +enum cds_pcl_type get_pcl_from_third_conn_table( + enum cds_two_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable); +#else +static inline CDF_STATUS cds_incr_connection_count_utfw( + hdd_context_t *hdd_ctx, uint32_t vdev_id, + uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + return CDF_STATUS_SUCCESS; +} +static inline CDF_STATUS cds_update_connection_info_utfw( + hdd_context_t *hdd_ctx, uint32_t vdev_id, + uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + return CDF_STATUS_SUCCESS; +} +static inline CDF_STATUS cds_decr_connection_count_utfw( + hdd_context_t *hdd_ctx, + uint32_t del_all, uint32_t vdev_id) +{ + return CDF_STATUS_SUCCESS; +} +static inline struct cds_conc_connection_info *cds_get_conn_info( + hdd_context_t *hdd_ctx, uint32_t *len) +{ + return NULL; +} +#endif +enum cds_con_mode cds_convert_device_mode_to_hdd_type( + device_mode_t device_mode); +uint32_t cds_get_connection_count(hdd_context_t *hdd_ctx); +CDF_STATUS cds_soc_set_hw_mode(hdd_context_t *hdd_ctx, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs); +enum cds_conc_next_action cds_need_opportunistic_upgrade( + hdd_context_t *hdd_ctx); +CDF_STATUS cds_next_actions( + hdd_context_t *hdd_ctx, enum cds_conc_next_action action); +void cds_set_dual_mac_scan_config(hdd_context_t *hdd_ctx, + uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val); +void cds_set_dual_mac_fw_mode_config(hdd_context_t *hdd_ctx, + uint8_t dbs, + uint8_t dfs); +void cds_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config); +bool cds_map_concurrency_mode(hdd_context_t *hdd_ctx, + tCDF_CON_MODE *old_mode, enum cds_con_mode *new_mode); +CDF_STATUS cds_get_channel_from_scan_result(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, uint8_t *channel); +#endif /* __CDS_CONCURRENCY_H */ diff --git a/core/cds/inc/cds_crypto.h b/core/cds/inc/cds_crypto.h new file mode 100644 index 0000000000..7df3b7dd70 --- /dev/null +++ b/core/cds/inc/cds_crypto.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#if !defined(__CDS_CRYPTO_H) +#define __CDS_CRYPTO_H + +/** + * DOC: cds_crypto.h + * + * Crypto APIs + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_CNSS +#include +#include +#endif + +#ifdef CONFIG_CNSS +static inline struct crypto_ahash *cds_crypto_alloc_ahash(const char *alg_name, + u32 type, u32 mask) +{ + return wcnss_wlan_crypto_alloc_ahash(alg_name, type, mask); +} +#else +static inline struct crypto_ahash *cds_crypto_alloc_ahash(const char *alg_name, + u32 type, u32 mask) +{ + return crypto_alloc_ahash(alg_name, type, mask); +} +#endif + +#ifdef CONFIG_CNSS +static inline struct crypto_cipher * +cds_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask) +{ + return wcnss_wlan_crypto_alloc_cipher(alg_name, type, mask); +} +#else +static inline struct crypto_cipher * +cds_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_cipher(alg_name, type, mask); +} +#endif + +#ifdef CONFIG_CNSS +static inline void cds_cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, + u16 length, u8 *mac) +{ + wcnss_wlan_cmac_calc_mic(tfm, m, length, mac); +} +#endif + +#ifdef CONFIG_CNSS +static inline void cds_crypto_free_cipher(struct crypto_cipher *tfm) +{ + wcnss_wlan_crypto_free_cipher(tfm); +} +#else +static inline void cds_crypto_free_cipher(struct crypto_cipher *tfm) +{ + crypto_free_cipher(tfm); +} +#endif + +#ifdef CONFIG_CNSS +static inline void cds_crypto_free_ahash(struct crypto_ahash *tfm) +{ + wcnss_wlan_crypto_free_ahash(tfm); +} +#else +static inline void cds_crypto_free_ahash(struct crypto_ahash *tfm) +{ + crypto_free_ahash(tfm); +} +#endif + +#ifdef CONFIG_CNSS +static inline int cds_crypto_ahash_setkey(struct crypto_ahash *tfm, + const u8 *key, unsigned int keylen) +{ + return wcnss_wlan_crypto_ahash_setkey(tfm, key, keylen); +} +#else +static inline int cds_crypto_ahash_setkey(struct crypto_ahash *tfm, + const u8 *key, unsigned int keylen) +{ + return crypto_ahash_setkey(tfm, key, keylen); +} +#endif + +#ifdef CONFIG_CNSS +static inline int cds_crypto_ahash_digest(struct ahash_request *req) +{ + return wcnss_wlan_crypto_ahash_digest(req); +} +#else +static inline int cds_crypto_ahash_digest(struct ahash_request *req) +{ + return crypto_ahash_digest(req); +} +#endif + +#ifdef CONFIG_CNSS +static inline struct crypto_ablkcipher * +cds_crypto_alloc_ablkcipher(const char *alg_name, u32 type, u32 mask) +{ + return wcnss_wlan_crypto_alloc_ablkcipher(alg_name, type, mask); +} +#else +static inline struct crypto_ablkcipher * +cds_crypto_alloc_ablkcipher(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_ablkcipher(alg_name, type, mask); +} +#endif + +#ifdef CONFIG_CNSS +static inline void cds_ablkcipher_request_free(struct ablkcipher_request *req) +{ + wcnss_wlan_ablkcipher_request_free(req); +} +#else +static inline void cds_ablkcipher_request_free(struct ablkcipher_request *req) +{ + ablkcipher_request_free(req); +} +#endif + +#ifdef CONFIG_CNSS +static inline void cds_crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) +{ + wcnss_wlan_crypto_free_ablkcipher(tfm); +} +#else +static inline void cds_crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) +{ + crypto_free_ablkcipher(tfm); +} +#endif + +#endif /* if !defined __CDS_CRYPTO_H */ diff --git a/core/cds/inc/cds_get_bin.h b/core/cds/inc/cds_get_bin.h new file mode 100644 index 0000000000..a561e95514 --- /dev/null +++ b/core/cds/inc/cds_get_bin.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_GETBIN_H ) +#define __CDS_GETBIN_H + +/**========================================================================= + + \file cds_getBin.h + + \brief Connectivity driver services (CDS) binary APIs + + Binary retrieval definitions and APIs. + + These APIs allow components to retrieve binary contents (firmware, + configuration data, etc.) from a storage medium on the platform. + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/**---------------------------------------------------------------------------- + \brief cds_get_conparam()- function to read the insmod parameters + -----------------------------------------------------------------------------*/ +tCDF_CON_MODE cds_get_conparam(void); +bool cds_concurrent_open_sessions_running(void); +bool cds_max_concurrent_connections_reached(void); +void cds_clear_concurrent_session_count(void); +bool cds_is_multiple_active_sta_sessions(void); +bool cds_is_sta_active_connection_exists(void); + +#ifdef WLAN_FEATURE_MBSSID +bool cds_concurrent_beaconing_sessions_running(void); +#endif +#endif /* !defined __CDS_GETBIN_H */ diff --git a/core/cds/inc/cds_ieee80211_common.h b/core/cds/inc/cds_ieee80211_common.h new file mode 100644 index 0000000000..9b8faf7575 --- /dev/null +++ b/core/cds/inc/cds_ieee80211_common.h @@ -0,0 +1,2105 @@ +/* + * Copyright (c) 2011,2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EXTERNAL_USE_ONLY +#include "osdep.h" +#endif /* EXTERNAL_USE_ONLY */ +#include "cds_ieee80211_common_i.h" + +#ifndef CDS_COMMON_IEEE80211_H_ +#define CDS_COMMON_IEEE80211_H_ + +/* + * 802.11 protocol definitions. + */ + +/* is 802.11 address multicast/broadcast? */ +#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01) + +#define IEEE80211_IS_IPV4_MULTICAST(_a) (*(_a) == 0x01) + +#define IEEE80211_IS_IPV6_MULTICAST(_a) \ + ((_a)[0] == 0x33 && \ + (_a)[1] == 0x33) + +#define IEEE80211_IS_BROADCAST(_a) \ + ((_a)[0] == 0xff && \ + (_a)[1] == 0xff && \ + (_a)[2] == 0xff && \ + (_a)[3] == 0xff && \ + (_a)[4] == 0xff && \ + (_a)[5] == 0xff) + +/* IEEE 802.11 PLCP header */ +struct ieee80211_plcp_hdr { + uint16_t i_sfd; + uint8_t i_signal; + uint8_t i_service; + uint16_t i_length; + uint16_t i_crc; +} __packed; + +#define IEEE80211_PLCP_SFD 0xF3A0 +#define IEEE80211_PLCP_SERVICE 0x00 + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + union { + struct { + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + }; + uint8_t i_addr_all[3 * IEEE80211_ADDR_LEN]; + }; + uint8_t i_seq[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; + +struct ieee80211_qosframe { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; + +struct ieee80211_qoscntl { + uint8_t i_qos[2]; +}; + +struct ieee80211_frame_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; +} __packed; + +struct ieee80211_qosframe_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + uint8_t i_qos[2]; +} __packed; + +/* HTC frame for TxBF*/ +/* for TxBF RC */ +struct ieee80211_frame_min_one { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + +} __packed; /* For TxBF RC */ + +struct ieee80211_qosframe_htc { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; +struct ieee80211_qosframe_htc_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; +} __packed; +struct ieee80211_htc { + uint8_t i_htc[4]; +}; +/*HTC frame for TxBF*/ + +struct ieee80211_ctlframe_addr2 { + uint8_t i_fc[2]; + uint8_t i_aidordur[2]; /* AID or duration */ + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; +} __packed; + +#define IEEE80211_WHQ(wh) ((struct ieee80211_qosframe *)(wh)) +#define IEEE80211_WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) +#define IEEE80211_WHQ4(wh) ((struct ieee80211_qosframe_addr4 *)(wh)) + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 +#define IEEE80211_FCO_SUBTYPE_ACTION_NO_ACK 0xe0 +/* for TYPE_CTL */ +#define IEEE80211_FCO_SUBTYPE_Control_Wrapper 0x70 /* For TxBF RC */ +#define IEEE80211_FC0_SUBTYPE_BAR 0x80 +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 +#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 +#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 +#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 + +#define IEEE80211_SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) + +#define IEEE80211_QOS_TXOP 0x00ff + +#define IEEE80211_QOS_AMSDU 0x80 +#define IEEE80211_QOS_AMSDU_S 7 +#define IEEE80211_QOS_ACKPOLICY 0x60 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_EOSP 0x10 +#define IEEE80211_QOS_EOSP_S 4 +#define IEEE80211_QOS_TID 0x0f +#define IEEE80211_MFP_TID 0xff + +#define IEEE80211_HTC0_TRQ 0x02 +#define IEEE80211_HTC2_CalPos 0x03 +#define IEEE80211_HTC2_CalSeq 0x0C +#define IEEE80211_HTC2_CSI_NONCOMP_BF 0x80 +#define IEEE80211_HTC2_CSI_COMP_BF 0xc0 + +/* Set bits 14 and 15 to 1 when duration field carries Association ID */ +#define IEEE80211_FIELD_TYPE_AID 0xC000 + +#define IEEE80211_IS_BEACON(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BEACON)) +#define IEEE80211_IS_DATA(_frame) (((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) + +#define IEEE80211_IS_MFP_FRAME(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + ((_frame)->i_fc[1] & IEEE80211_FC1_WEP) && \ + ((((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DEAUTH) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DISASSOC) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_ACTION))) +#define IEEE80211_IS_AUTH(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_AUTH)) + +/* MCS Set */ +#define IEEE80211_RX_MCS_1_STREAM_BYTE_OFFSET 0 +#define IEEE80211_RX_MCS_2_STREAM_BYTE_OFFSET 1 +#define IEEE80211_RX_MCS_3_STREAM_BYTE_OFFSET 2 +#define IEEE80211_RX_MCS_ALL_NSTREAM_RATES 0xff +#define IEEE80211_TX_MCS_OFFSET 12 + +#define IEEE80211_TX_MCS_SET_DEFINED 0x80 +#define IEEE80211_TX_RX_MCS_SET_NOT_EQUAL 0x40 +#define IEEE80211_TX_1_SPATIAL_STREAMS 0x0 +#define IEEE80211_TX_2_SPATIAL_STREAMS 0x10 +#define IEEE80211_TX_3_SPATIAL_STREAMS 0x20 +#define IEEE80211_TX_4_SPATIAL_STREAMS 0x30 + +#define IEEE80211_TX_MCS_SET 0xf8 + +/* + * Subtype data: If bit 6 is set then the data frame contains no actual data. + */ +#define IEEE80211_FC0_SUBTYPE_NO_DATA_MASK 0x40 +#define IEEE80211_CONTAIN_DATA(_subtype) \ + (!((_subtype) & IEEE80211_FC0_SUBTYPE_NO_DATA_MASK)) + +#define IEEE8023_MAX_LEN 0x600 /* 1536 - larger is Ethernet II */ +#define RFC1042_SNAP_ORGCODE_0 0x00 +#define RFC1042_SNAP_ORGCODE_1 0x00 +#define RFC1042_SNAP_ORGCODE_2 0x00 + +#define BTEP_SNAP_ORGCODE_0 0x00 +#define BTEP_SNAP_ORGCODE_1 0x00 +#define BTEP_SNAP_ORGCODE_2 0xf8 + +/* BT 3.0 */ +#define BTAMP_SNAP_ORGCODE_0 0x00 +#define BTAMP_SNAP_ORGCODE_1 0x19 +#define BTAMP_SNAP_ORGCODE_2 0x58 + +/* Aironet OUI Codes */ +#define AIRONET_SNAP_CODE_0 0x00 +#define AIRONET_SNAP_CODE_1 0x40 +#define AIRONET_SNAP_CODE_2 0x96 + +#define IEEE80211_LSIG_LEN 3 +#define IEEE80211_HTSIG_LEN 6 +#define IEEE80211_SB_LEN 2 + +/* + * Information element header format + */ +struct ieee80211_ie_header { + uint8_t element_id; /* Element Id */ + uint8_t length; /* IE Length */ +} __packed; + +/* + * Country information element. + */ +#define IEEE80211_COUNTRY_MAX_TRIPLETS (83) +struct ieee80211_ie_country { + uint8_t country_id; + uint8_t country_len; + uint8_t country_str[3]; + uint8_t country_triplet[IEEE80211_COUNTRY_MAX_TRIPLETS * 3]; +} __packed; + +/* does frame have QoS sequence control data */ +#define IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +#define WME_QOSINFO_UAPSD 0x80 /* Mask for U-APSD field */ +#define WME_QOSINFO_COUNT 0x0f /* Mask for Param Set Count field */ +/* + * WME/802.11e information element. + */ +struct ieee80211_ie_wme { + uint8_t wme_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wme_len; /* length in bytes */ + uint8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wme_type; /* OUI type */ + uint8_t wme_subtype; /* OUI subtype */ + uint8_t wme_version; /* spec revision */ + uint8_t wme_info; /* QoS info */ +} __packed; + +/* + * TS INFO part of the tspec element is a collection of bit flags + */ +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_tsinfo_bitmap { + uint8_t one : 1, direction : 2, tid : 4, reserved1 : 1; + uint8_t reserved2 : 2, dot1Dtag : 3, psb : 1, reserved3 : 1, zero : 1; + uint8_t reserved5 : 7, reserved4 : 1; +} __packed; +#else +struct ieee80211_tsinfo_bitmap { + uint8_t reserved1 : 1, tid : 4, direction : 2, one : 1; + uint8_t zero : 1, reserved3 : 1, psb : 1, dot1Dtag : 3, reserved2 : 2; + uint8_t reserved4 : 1, reserved5 : 7; +} __packed; +#endif + +/* + * WME/802.11e Tspec Element + */ +struct ieee80211_wme_tspec { + uint8_t ts_id; + uint8_t ts_len; + uint8_t ts_oui[3]; + uint8_t ts_oui_type; + uint8_t ts_oui_subtype; + uint8_t ts_version; + uint8_t ts_tsinfo[3]; + uint8_t ts_nom_msdu[2]; + uint8_t ts_max_msdu[2]; + uint8_t ts_min_svc[4]; + uint8_t ts_max_svc[4]; + uint8_t ts_inactv_intv[4]; + uint8_t ts_susp_intv[4]; + uint8_t ts_start_svc[4]; + uint8_t ts_min_rate[4]; + uint8_t ts_mean_rate[4]; + uint8_t ts_peak_rate[4]; + uint8_t ts_max_burst[4]; + uint8_t ts_delay[4]; + uint8_t ts_min_phy[4]; + uint8_t ts_surplus[2]; + uint8_t ts_medium_time[2]; +} __packed; + +/* + * WME AC parameter field + */ +struct ieee80211_wme_acparams { + uint8_t acp_aci_aifsn; + uint8_t acp_logcwminmax; + uint16_t acp_txop; +} __packed; + +#define IEEE80211_WME_PARAM_LEN 24 +#define WME_NUM_AC 4 /* 4 AC categories */ + +#define WME_PARAM_ACI 0x60 /* Mask for ACI field */ +#define WME_PARAM_ACI_S 5 /* Shift for ACI field */ +#define WME_PARAM_ACM 0x10 /* Mask for ACM bit */ +#define WME_PARAM_ACM_S 4 /* Shift for ACM bit */ +#define WME_PARAM_AIFSN 0x0f /* Mask for aifsn field */ +#define WME_PARAM_AIFSN_S 0 /* Shift for aifsn field */ +#define WME_PARAM_LOGCWMIN 0x0f /* Mask for CwMin field (in log) */ +#define WME_PARAM_LOGCWMIN_S 0 /* Shift for CwMin field */ +#define WME_PARAM_LOGCWMAX 0xf0 /* Mask for CwMax field (in log) */ +#define WME_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */ + +#define WME_AC_TO_TID(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define TID_TO_WME_AC(_tid) ( \ + (((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +/* + * WME Parameter Element + */ +struct ieee80211_wme_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_qosInfo; + uint8_t param_reserved; + struct ieee80211_wme_acparams params_acParams[WME_NUM_AC]; +} __packed; + +/* + * WME U-APSD qos info field defines + */ +#define WME_CAPINFO_UAPSD_EN 0x00000080 +#define WME_CAPINFO_UAPSD_VO 0x00000001 +#define WME_CAPINFO_UAPSD_VI 0x00000002 +#define WME_CAPINFO_UAPSD_BK 0x00000004 +#define WME_CAPINFO_UAPSD_BE 0x00000008 +#define WME_CAPINFO_UAPSD_ACFLAGS_SHIFT 0 +#define WME_CAPINFO_UAPSD_ACFLAGS_MASK 0xF +#define WME_CAPINFO_UAPSD_MAXSP_SHIFT 5 +#define WME_CAPINFO_UAPSD_MAXSP_MASK 0x3 +#define WME_CAPINFO_IE_OFFSET 8 +#define WME_UAPSD_MAXSP(_qosinfo) (((_qosinfo) >> WME_CAPINFO_UAPSD_MAXSP_SHIFT) & WME_CAPINFO_UAPSD_MAXSP_MASK) +#define WME_UAPSD_AC_ENABLED(_ac, _qosinfo) ( (1<<(3 - (_ac))) & \ + (((_qosinfo) >> WME_CAPINFO_UAPSD_ACFLAGS_SHIFT) & WME_CAPINFO_UAPSD_ACFLAGS_MASK) ) + +/* Mask used to determined whether all queues are UAPSD-enabled */ +#define WME_CAPINFO_UAPSD_ALL (WME_CAPINFO_UAPSD_VO | \ + WME_CAPINFO_UAPSD_VI | \ + WME_CAPINFO_UAPSD_BK | \ + WME_CAPINFO_UAPSD_BE) +#define WME_CAPINFO_UAPSD_NONE 0 + +#define WME_UAPSD_AC_MAX_VAL 1 +#define WME_UAPSD_AC_INVAL WME_UAPSD_AC_MAX_VAL+1 + +/* + * Atheros Advanced Capability information element. + */ +struct ieee80211_ie_athAdvCap { + uint8_t athAdvCap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t athAdvCap_len; /* length in bytes */ + uint8_t athAdvCap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t athAdvCap_type; /* OUI type */ + uint16_t athAdvCap_version; /* spec revision */ + uint8_t athAdvCap_capability; /* Capability info */ + uint16_t athAdvCap_defKeyIndex; +} __packed; + +/* + * Atheros Extended Capability information element. + */ +struct ieee80211_ie_ath_extcap { + uint8_t ath_extcap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ath_extcap_len; /* length in bytes */ + uint8_t ath_extcap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t ath_extcap_type; /* OUI type */ + uint8_t ath_extcap_subtype; /* OUI subtype */ + uint8_t ath_extcap_version; /* spec revision */ + uint32_t ath_extcap_extcap : 16, /* B0-15 extended capabilities */ + ath_extcap_weptkipaggr_rxdelim : 8, /* B16-23 num delimiters for receiving WEP/TKIP aggregates */ + ath_extcap_reserved : 8; /* B24-31 reserved */ +} __packed; + +/* + * Atheros XR information element. + */ +struct ieee80211_xr_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_Info; + uint8_t param_base_bssid[IEEE80211_ADDR_LEN]; + uint8_t param_xr_bssid[IEEE80211_ADDR_LEN]; + uint16_t param_xr_beacon_interval; + uint8_t param_base_ath_capability; + uint8_t param_xr_ath_capability; +} __packed; + +/* + * SFA information element. + */ +struct ieee80211_ie_sfa { + uint8_t sfa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t sfa_len; /* length in bytes */ + uint8_t sfa_oui[3]; /* 0x00, 0x40, 0x96 */ + uint8_t sfa_type; /* OUI type */ + uint8_t sfa_caps; /* Capabilities */ +} __packed; + +/* Atheros capabilities */ +#define IEEE80211_ATHC_TURBOP 0x0001 /* Turbo Prime */ +#define IEEE80211_ATHC_COMP 0x0002 /* Compression */ +#define IEEE80211_ATHC_FF 0x0004 /* Fast Frames */ +#define IEEE80211_ATHC_XR 0x0008 /* Xtended Range support */ +#define IEEE80211_ATHC_AR 0x0010 /* Advanced Radar support */ +#define IEEE80211_ATHC_BURST 0x0020 /* Bursting - not negotiated */ +#define IEEE80211_ATHC_WME 0x0040 /* CWMin tuning */ +#define IEEE80211_ATHC_BOOST 0x0080 /* Boost */ +#define IEEE80211_ATHC_TDLS 0x0100 /* TDLS */ + +/* Atheros extended capabilities */ +/* OWL device capable of WDS workaround */ +#define IEEE80211_ATHEC_OWLWDSWAR 0x0001 +#define IEEE80211_ATHEC_WEPTKIPAGGR 0x0002 +#define IEEE80211_ATHEC_EXTRADELIMWAR 0x0004 +/* + * Management Frames + */ + +/* + * *** Platform-specific code?? *** + * In Vista one must use bit fields of type (unsigned short = uint16_t) to + * ensure data structure is of the correct size. ANSI C used to specify only + * "int" bit fields, which led to a larger structure size in Windows (32 bits). + * + * We must make sure the following construction is valid in all OS's. + */ +union ieee80211_capability { + struct { + uint16_t ess : 1; + uint16_t ibss : 1; + uint16_t cf_pollable : 1; + uint16_t cf_poll_request : 1; + uint16_t privacy : 1; + uint16_t short_preamble : 1; + uint16_t pbcc : 1; + uint16_t channel_agility : 1; + uint16_t spectrum_management : 1; + uint16_t qos : 1; + uint16_t short_slot_time : 1; + uint16_t apsd : 1; + uint16_t reserved2 : 1; + uint16_t dsss_ofdm : 1; + uint16_t del_block_ack : 1; + uint16_t immed_block_ack : 1; + }; + + uint16_t value; +} __packed; + +struct ieee80211_beacon_frame { + uint8_t timestamp[8]; /* the value of sender's TSFTIMER */ + uint16_t beacon_interval; /* the number of time units between target beacon transmission times */ + union ieee80211_capability capability; +/* Value of capability for every bit + #define IEEE80211_CAPINFO_ESS 0x0001 + #define IEEE80211_CAPINFO_IBSS 0x0002 + #define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 + #define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 + #define IEEE80211_CAPINFO_PRIVACY 0x0010 + #define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 + #define IEEE80211_CAPINFO_PBCC 0x0040 + #define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 + #define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 + #define IEEE80211_CAPINFO_QOS 0x0200 + #define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 + #define IEEE80211_CAPINFO_APSD 0x0800 + #define IEEE80211_CAPINFO_RADIOMEAS 0x1000 + #define IEEE80211_CAPINFO_DSSSOFDM 0x2000 + bits 14-15 are reserved + */ + struct ieee80211_ie_header info_elements; +} __packed; + +/* + * Management Action Frames + */ + +/* generic frame format */ +struct ieee80211_action { + uint8_t ia_category; + uint8_t ia_action; +} __packed; + +/* spectrum action frame header */ +struct ieee80211_action_measrep_header { + struct ieee80211_action action_header; + uint8_t dialog_token; +} __packed; + +/* categories */ +#define IEEE80211_ACTION_CAT_SPECTRUM 0 /* Spectrum management */ +#define IEEE80211_ACTION_CAT_QOS 1 /* IEEE QoS */ +#define IEEE80211_ACTION_CAT_DLS 2 /* DLS */ +#define IEEE80211_ACTION_CAT_BA 3 /* BA */ +#define IEEE80211_ACTION_CAT_PUBLIC 4 /* Public Action Frame */ +#define IEEE80211_ACTION_CAT_HT 7 /* HT per IEEE802.11n-D1.06 */ +#define IEEE80211_ACTION_CAT_SA_QUERY 8 /* SA Query per IEEE802.11w, PMF */ +#define IEEE80211_ACTION_CAT_WMM_QOS 17 /* QoS from WMM specification */ +#define IEEE80211_ACTION_CAT_VHT 21 /* VHT Action */ + +/* Spectrum Management actions */ +#define IEEE80211_ACTION_MEAS_REQUEST 0 /* Measure channels */ +#define IEEE80211_ACTION_MEAS_REPORT 1 +#define IEEE80211_ACTION_TPC_REQUEST 2 /* Transmit Power control */ +#define IEEE80211_ACTION_TPC_REPORT 3 +#define IEEE80211_ACTION_CHAN_SWITCH 4 /* 802.11h Channel Switch Announcement */ + +/* HT actions */ +#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended transmission channel width */ +#define IEEE80211_ACTION_HT_SMPOWERSAVE 1 /* Spatial Multiplexing (SM) Power Save */ +#define IEEE80211_ACTION_HT_CSI 4 /* CSI Frame */ +#define IEEE80211_ACTION_HT_NONCOMP_BF 5 /* Non-compressed Beamforming */ +#define IEEE80211_ACTION_HT_COMP_BF 6 /* Compressed Beamforming */ + +/* VHT actions */ +#define IEEE80211_ACTION_VHT_OPMODE 2 /* Operating mode notification */ + +/* Spectrum channel switch action frame after IE*/ +/* Public Actions*/ +#define IEEE80211_ACTION_TDLS_DISCRESP 14 /* TDLS Discovery Response frame */ + +/* HT - recommended transmission channel width */ +struct ieee80211_action_ht_txchwidth { + struct ieee80211_action at_header; + uint8_t at_chwidth; +} __packed; + +#define IEEE80211_A_HT_TXCHWIDTH_20 0 +#define IEEE80211_A_HT_TXCHWIDTH_2040 1 + +/* HT - Spatial Multiplexing (SM) Power Save */ +struct ieee80211_action_ht_smpowersave { + struct ieee80211_action as_header; + uint8_t as_control; +} __packed; + +/*HT - CSI Frame */ /* for TxBF RC */ +#define MIMO_CONTROL_LEN 6 +struct ieee80211_action_ht_CSI { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/*HT - V/CV report frame*/ +struct ieee80211_action_ht_txbf_rpt { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/* + * 802.11ac Operating Mode Notification + */ +struct ieee80211_ie_op_mode { +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t rx_nss_type : 1, rx_nss : 3, reserved : 2, ch_width : 2; +#else + uint8_t ch_width : 2, reserved : 2, rx_nss : 3, rx_nss_type : 1; +#endif +} __packed; + +struct ieee80211_ie_op_mode_ntfy { + uint8_t elem_id; + uint8_t elem_len; + struct ieee80211_ie_op_mode opmode; +} __packed; + +/* VHT - recommended Channel width and Nss */ +struct ieee80211_action_vht_opmode { + struct ieee80211_action at_header; + struct ieee80211_ie_op_mode at_op_mode; +} __packed; + +/* values defined for 'as_control' field per 802.11n-D1.06 */ +#define IEEE80211_A_HT_SMPOWERSAVE_DISABLED 0x00 /* SM Power Save Disabled, SM packets ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_ENABLED 0x01 /* SM Power Save Enabled bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_MODE 0x02 /* SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_RESERVED 0xFC /* SM Power Save Reserved bits */ + +/* values defined for SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_STATIC 0x00 /* Static, SM packets not ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_DYNAMIC 0x02 /* Dynamic, SM packets ok if preceded by RTS */ + +/* DLS actions */ +#define IEEE80211_ACTION_DLS_REQUEST 0 +#define IEEE80211_ACTION_DLS_RESPONSE 1 +#define IEEE80211_ACTION_DLS_TEARDOWN 2 + +struct ieee80211_dls_request { + struct ieee80211_action hdr; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; + uint16_t capa_info; + uint16_t timeout; +} __packed; + +struct ieee80211_dls_response { + struct ieee80211_action hdr; + uint16_t statuscode; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; +} __packed; + +/* BA actions */ +#define IEEE80211_ACTION_BA_ADDBA_REQUEST 0 /* ADDBA request */ +#define IEEE80211_ACTION_BA_ADDBA_RESPONSE 1 /* ADDBA response */ +#define IEEE80211_ACTION_BA_DELBA 2 /* DELBA */ + +struct ieee80211_ba_parameterset { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t buffersize : 10, /* B6-15 buffer size */ + tid : 4, /* B2-5 TID */ + bapolicy : 1, /* B1 block ack policy */ + amsdusupported : 1; /* B0 amsdu supported */ +#else + uint16_t amsdusupported : 1, /* B0 amsdu supported */ + bapolicy : 1, /* B1 block ack policy */ + tid : 4, /* B2-5 TID */ + buffersize : 10; /* B6-15 buffer size */ +#endif +} __packed; + +#define IEEE80211_BA_POLICY_DELAYED 0 +#define IEEE80211_BA_POLICY_IMMEDIATE 1 +#define IEEE80211_BA_AMSDU_SUPPORTED 1 + +struct ieee80211_ba_seqctrl { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t startseqnum : 12, /* B4-15 starting sequence number */ + fragnum : 4; /* B0-3 fragment number */ +#else + uint16_t fragnum : 4, /* B0-3 fragment number */ + startseqnum : 12; /* B4-15 starting sequence number */ +#endif +} __packed; + +struct ieee80211_delba_parameterset { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t tid : 4, /* B12-15 tid */ + initiator : 1, /* B11 initiator */ + reserved0 : 11; /* B0-10 reserved */ +#else + uint16_t reserved0 : 11, /* B0-10 reserved */ + initiator : 1, /* B11 initiator */ + tid : 4; /* B12-15 tid */ +#endif +} __packed; + +/* BA - ADDBA request */ +struct ieee80211_action_ba_addbarequest { + struct ieee80211_action rq_header; + uint8_t rq_dialogtoken; + struct ieee80211_ba_parameterset rq_baparamset; + uint16_t rq_batimeout; /* in TUs */ + struct ieee80211_ba_seqctrl rq_basequencectrl; +} __packed; + +/* BA - ADDBA response */ +struct ieee80211_action_ba_addbaresponse { + struct ieee80211_action rs_header; + uint8_t rs_dialogtoken; + uint16_t rs_statuscode; + struct ieee80211_ba_parameterset rs_baparamset; + uint16_t rs_batimeout; /* in TUs */ +} __packed; + +/* BA - DELBA */ +struct ieee80211_action_ba_delba { + struct ieee80211_action dl_header; + struct ieee80211_delba_parameterset dl_delbaparamset; + uint16_t dl_reasoncode; +} __packed; + +/* MGT Notif actions */ +#define IEEE80211_WMM_QOS_ACTION_SETUP_REQ 0 +#define IEEE80211_WMM_QOS_ACTION_SETUP_RESP 1 +#define IEEE80211_WMM_QOS_ACTION_TEARDOWN 2 + +#define IEEE80211_WMM_QOS_DIALOG_TEARDOWN 0 +#define IEEE80211_WMM_QOS_DIALOG_SETUP 1 + +#define IEEE80211_WMM_QOS_TSID_DATA_TSPEC 6 +#define IEEE80211_WMM_QOS_TSID_SIG_TSPEC 7 + +struct ieee80211_action_wmm_qos { + struct ieee80211_action ts_header; + uint8_t ts_dialogtoken; + uint8_t ts_statuscode; + struct ieee80211_wme_tspec ts_tspecie; +} __packed; + +/* + * Control frames. + */ +struct ieee80211_frame_min { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BAR frame format + */ +#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ +#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ +#define IEEE80211_BAR_CTL_NOACK 0x0001 /* no-ack policy */ +#define IEEE80211_BAR_CTL_COMBA 0x0004 /* compressed block-ack */ + +/* + * SA Query Action mgmt Frame + */ +struct ieee80211_action_sa_query { + struct ieee80211_action sa_header; + uint16_t sa_transId; +}; + +typedef enum ieee80211_action_sa_query_type { + IEEE80211_ACTION_SA_QUERY_REQUEST, + IEEE80211_ACTION_SA_QUERY_RESPONSE +} ieee80211_action_sa_query_type_t; + +struct ieee80211_frame_bar { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + uint16_t i_ctl; + uint16_t i_seq; + /* FCS */ +} __packed; + +struct ieee80211_frame_rts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_ack { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_pspoll { + uint8_t i_fc[2]; + uint8_t i_aid[2]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */ + uint8_t i_fc[2]; + uint8_t i_dur[2]; /* should be zero */ + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BEACON management packets + * + * octet timestamp[8] + * octet beacon interval[2] + * octet capability information[2] + * information element + * octet elemid + * octet length + * octet information[length] + */ + +typedef uint8_t *ieee80211_mgt_beacon_t; + +#define IEEE80211_BEACON_INTERVAL(beacon) \ + ((beacon)[8] | ((beacon)[9] << 8)) +#define IEEE80211_BEACON_CAPABILITY(beacon) \ + ((beacon)[10] | ((beacon)[11] << 8)) + +#define IEEE80211_CAPINFO_ESS 0x0001 +#define IEEE80211_CAPINFO_IBSS 0x0002 +#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 +#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 +#define IEEE80211_CAPINFO_PRIVACY 0x0010 +#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 +#define IEEE80211_CAPINFO_PBCC 0x0040 +#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 +#define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 +#define IEEE80211_CAPINFO_QOS 0x0200 +#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 +#define IEEE80211_CAPINFO_APSD 0x0800 +#define IEEE80211_CAPINFO_RADIOMEAS 0x1000 +#define IEEE80211_CAPINFO_DSSSOFDM 0x2000 +/* bits 14-15 are reserved */ + +/* + * 802.11i/WPA information element (maximally sized). + */ +struct ieee80211_ie_wpa { + uint8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wpa_len; /* length in bytes */ + uint8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wpa_type; /* OUI type */ + uint16_t wpa_version; /* spec revision */ + uint32_t wpa_mcipher[1]; /* multicast/group key cipher */ + uint16_t wpa_uciphercnt; /* # pairwise key ciphers */ + uint32_t wpa_uciphers[8]; /* ciphers */ + uint16_t wpa_authselcnt; /* authentication selector cnt */ + uint32_t wpa_authsels[8]; /* selectors */ + uint16_t wpa_caps; /* 802.11i capabilities */ + uint16_t wpa_pmkidcnt; /* 802.11i pmkid count */ + uint16_t wpa_pmkids[8]; /* 802.11i pmkids */ +} __packed; + +#ifndef _BYTE_ORDER +#error "Don't know native byte order" +#endif + +#ifndef IEEE80211N_IE +/* Temporary vendor specific IE for 11n pre-standard interoperability */ +#define VENDOR_HT_OUI 0x00904c +#define VENDOR_HT_CAP_ID 51 +#define VENDOR_HT_INFO_ID 52 +#endif + +#ifdef ATH_SUPPORT_TxBF +union ieee80211_hc_txbf { + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t reserved : 3, + channel_estimation_cap : 2, + csi_max_rows_bfer : 2, + comp_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + csi_bfer_antennas : 2, + minimal_grouping : 2, + explicit_comp_bf : 2, + explicit_noncomp_bf : 2, + explicit_csi_feedback : 2, + explicit_comp_steering : 1, + explicit_noncomp_steering : 1, + explicit_csi_txbf_capable : 1, + calibration : 2, + implicit_txbf_capable : 1, + tx_ndp_capable : 1, + rx_ndp_capable : 1, + tx_staggered_sounding : 1, + rx_staggered_sounding : 1, implicit_rx_capable : 1; +#else + uint32_t implicit_rx_capable : 1, + rx_staggered_sounding : 1, + tx_staggered_sounding : 1, + rx_ndp_capable : 1, + tx_ndp_capable : 1, + implicit_txbf_capable : 1, + calibration : 2, + explicit_csi_txbf_capable : 1, + explicit_noncomp_steering : 1, + explicit_comp_steering : 1, + explicit_csi_feedback : 2, + explicit_noncomp_bf : 2, + explicit_comp_bf : 2, + minimal_grouping : 2, + csi_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + comp_bfer_antennas : 2, + csi_max_rows_bfer : 2, channel_estimation_cap : 2, reserved : 3; +#endif + }; + + uint32_t value; +} __packed; +#endif + +struct ieee80211_ie_htcap_cmn { + uint16_t hc_cap; /* HT capabilities */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hc_reserved : 3, /* B5-7 reserved */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_maxampdu : 2; /* B0-1 maximum rx A-MPDU factor */ +#else + uint8_t hc_maxampdu : 2, /* B0-1 maximum rx A-MPDU factor */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_reserved : 3; /* B5-7 reserved */ +#endif + uint8_t hc_mcsset[16]; /* supported MCS set */ + uint16_t hc_extcap; /* extended HT capabilities */ +#ifdef ATH_SUPPORT_TxBF + union ieee80211_hc_txbf hc_txbf; /* txbf capabilities */ +#else + uint32_t hc_txbf; /* txbf capabilities */ +#endif + uint8_t hc_antenna; /* antenna capabilities */ +} __packed; + +/* + * 802.11n HT Capability IE + */ +struct ieee80211_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* + * Temporary vendor private HT Capability IE + */ +struct vendor_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + uint8_t hc_oui[3]; + uint8_t hc_ouitype; + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* HT capability flags */ +#define IEEE80211_HTCAP_C_ADVCODING 0x0001 +#define IEEE80211_HTCAP_C_CHWIDTH40 0x0002 +#define IEEE80211_HTCAP_C_SMPOWERSAVE_STATIC 0x0000 /* Capable of SM Power Save (Static) */ +#define IEEE80211_HTCAP_C_SMPOWERSAVE_DYNAMIC 0x0004 /* Capable of SM Power Save (Dynamic) */ +#define IEEE80211_HTCAP_C_SM_RESERVED 0x0008 /* Reserved */ +#define IEEE80211_HTCAP_C_SM_ENABLED 0x000c /* SM enabled, no SM Power Save */ +#define IEEE80211_HTCAP_C_GREENFIELD 0x0010 +#define IEEE80211_HTCAP_C_SHORTGI20 0x0020 +#define IEEE80211_HTCAP_C_SHORTGI40 0x0040 +#define IEEE80211_HTCAP_C_TXSTBC 0x0080 +#define IEEE80211_HTCAP_C_TXSTBC_S 7 +#define IEEE80211_HTCAP_C_RXSTBC 0x0300 /* 2 bits */ +#define IEEE80211_HTCAP_C_RXSTBC_S 8 +#define IEEE80211_HTCAP_C_DELAYEDBLKACK 0x0400 +#define IEEE80211_HTCAP_C_MAXAMSDUSIZE 0x0800 /* 1 = 8K, 0 = 3839B */ +#define IEEE80211_HTCAP_C_DSSSCCK40 0x1000 +#define IEEE80211_HTCAP_C_PSMP 0x2000 +#define IEEE80211_HTCAP_C_INTOLERANT40 0x4000 +#define IEEE80211_HTCAP_C_LSIGTXOPPROT 0x8000 + +#define IEEE80211_HTCAP_C_SM_MASK 0x000c /* Spatial Multiplexing (SM) capabitlity bitmask */ + +/* B0-1 maximum rx A-MPDU factor 2^(13+Max Rx A-MPDU Factor) */ +enum { + IEEE80211_HTCAP_MAXRXAMPDU_8192, /* 2 ^ 13 */ + IEEE80211_HTCAP_MAXRXAMPDU_16384, /* 2 ^ 14 */ + IEEE80211_HTCAP_MAXRXAMPDU_32768, /* 2 ^ 15 */ + IEEE80211_HTCAP_MAXRXAMPDU_65536, /* 2 ^ 16 */ +}; +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* B2-4 MPDU density (usec) */ +enum { + IEEE80211_HTCAP_MPDUDENSITY_NA, /* No time restriction */ + IEEE80211_HTCAP_MPDUDENSITY_0_25, /* 1/4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_0_5, /* 1/2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_1, /* 1 usec */ + IEEE80211_HTCAP_MPDUDENSITY_2, /* 2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_4, /* 4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_8, /* 8 usec */ + IEEE80211_HTCAP_MPDUDENSITY_16, /* 16 usec */ +}; + +/* HT extended capability flags */ +#define IEEE80211_HTCAP_EXTC_PCO 0x0001 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_RSVD 0x0000 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_400 0x0002 /* 20-40 switch time */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_1500 0x0004 /* in us */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_5000 0x0006 +#define IEEE80211_HTCAP_EXTC_RSVD_1 0x00f8 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_NONE 0x0000 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_RSVD 0x0100 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_UNSOL 0x0200 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_FULL 0x0300 +#define IEEE80211_HTCAP_EXTC_RSVD_2 0xfc00 +#ifdef ATH_SUPPORT_TxBF +#define IEEE80211_HTCAP_EXTC_HTC_SUPPORT 0x0400 +#endif + +struct ieee80211_ie_htinfo_cmn { + uint8_t hi_ctrlchannel; /* control channel */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hi_serviceinterval : 3, /* B5-7 svc interval granularity */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_extchoff : 2; /* B0-1 extension channel offset */ + +/* + + * The following 2 consecutive bytes are defined in word in 80211n spec. + + * Some processors store MSB byte into lower memory address which causes wrong + + * wrong byte sequence in beacon. Thus we break into byte definition which should + + * avoid the problem for all processors + + */ + + uint8_t hi_reserved3 : 3, /* B5-7 reserved */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_opmode : 2; /* B0-1 operating mode */ + + uint8_t hi_reserved0; /* B0-7 (B8-15 in 11n) reserved */ + +/* The following 2 consecutive bytes are defined in word in 80211n spec. */ + + uint8_t hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_reserved2 : 6; /* B0-5 reserved */ + uint8_t hi_reserved1 : 4, /* B4-7 (B12-15 in 11n) reserved */ + hi_pcophase : 1, /* B3 (B11 in 11n) pco phase */ + hi_pcoactive : 1, /* B2 (B10 in 11n) pco active */ + hi_lsigtxopprot : 1, /* B1 (B9 in 11n) l-sig txop protection full support */ + hi_stbcbeacon : 1; /* B0 (B8 in 11n) STBC beacon */ +#else + uint8_t hi_extchoff : 2, /* B0-1 extension channel offset */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_serviceinterval : 3; /* B5-7 svc interval granularity */ + uint16_t hi_opmode : 2, /* B0-1 operating mode */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_reserved0 : 11; /* B5-15 reserved */ + uint16_t hi_reserved2 : 6, /* B0-5 reserved */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_stbcbeacon : 1, /* B8 STBC beacon */ + hi_lsigtxopprot : 1, /* B9 l-sig txop protection full support */ + hi_pcoactive : 1, /* B10 pco active */ + hi_pcophase : 1, /* B11 pco phase */ + hi_reserved1 : 4; /* B12-15 reserved */ +#endif + uint8_t hi_basicmcsset[16]; /* basic MCS set */ +} __packed; + +/* + * 802.11n HT Information IE + */ +struct ieee80211_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* + * Temporary vendor private HT Information IE + */ +struct vendor_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + uint8_t hi_oui[3]; + uint8_t hi_ouitype; + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* extension channel offset (2 bit signed number) */ +enum { + IEEE80211_HTINFO_EXTOFFSET_NA = 0, /* 0 no extension channel is present */ + IEEE80211_HTINFO_EXTOFFSET_ABOVE = 1, /* +1 extension channel above control channel */ + IEEE80211_HTINFO_EXTOFFSET_UNDEF = 2, /* -2 undefined */ + IEEE80211_HTINFO_EXTOFFSET_BELOW = 3 /* -1 extension channel below control channel */ +}; + +/* recommended transmission width set */ +enum { + IEEE80211_HTINFO_TXWIDTH_20, + IEEE80211_HTINFO_TXWIDTH_2040 +}; + +/* operating flags */ +#define IEEE80211_HTINFO_OPMODE_PURE 0x00 /* no protection */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_OPT 0x01 /* prot optional (legacy device maybe present) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_40 0x02 /* prot required (20 MHz) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_ALL 0x03 /* prot required (legacy devices present) */ +#define IEEE80211_HTINFO_OPMODE_NON_GF_PRESENT 0x04 /* non-greenfield devices present */ + +#define IEEE80211_HTINFO_OPMODE_MASK 0x03 /* For protection 0x00-0x03 */ + +/* Non-greenfield STAs present */ +enum { + IEEE80211_HTINFO_NON_GF_NOT_PRESENT, /* Non-greenfield STAs not present */ + IEEE80211_HTINFO_NON_GF_PRESENT, /* Non-greenfield STAs present */ +}; + +/* Transmit Burst Limit */ +enum { + IEEE80211_HTINFO_TXBURST_UNLIMITED, /* Transmit Burst is unlimited */ + IEEE80211_HTINFO_TXBURST_LIMITED, /* Transmit Burst is limited */ +}; + +/* OBSS Non-HT STAs present */ +enum { + IEEE80211_HTINFO_OBSS_NONHT_NOT_PRESENT, /* OBSS Non-HT STAs not present */ + IEEE80211_HTINFO_OBSS_NONHT_PRESENT, /* OBSS Non-HT STAs present */ +}; + +/* misc flags */ +#define IEEE80211_HTINFO_DUALBEACON 0x0040 /* B6 dual beacon */ +#define IEEE80211_HTINFO_DUALCTSPROT 0x0080 /* B7 dual stbc protection */ +#define IEEE80211_HTINFO_STBCBEACON 0x0100 /* B8 secondary beacon */ +#define IEEE80211_HTINFO_LSIGTXOPPROT 0x0200 /* B9 lsig txop prot full support */ +#define IEEE80211_HTINFO_PCOACTIVE 0x0400 /* B10 pco active */ +#define IEEE80211_HTINFO_PCOPHASE 0x0800 /* B11 pco phase */ + +/* Secondary Channel offset for for 40MHz direct link */ +#define IEEE80211_SECONDARY_CHANNEL_ABOVE 1 +#define IEEE80211_SECONDARY_CHANNEL_BELOW 3 + +#define IEEE80211_TDLS_CHAN_SX_PROHIBIT 0x00000002 /* bit-2 TDLS Channel Switch Prohibit */ + +/* RIFS mode */ +enum { + IEEE80211_HTINFO_RIFSMODE_PROHIBITED, /* use of rifs prohibited */ + IEEE80211_HTINFO_RIFSMODE_ALLOWED, /* use of rifs permitted */ +}; + +/* + * Management information element payloads. + */ +enum { + IEEE80211_ELEMID_SSID = 0, + IEEE80211_ELEMID_RATES = 1, + IEEE80211_ELEMID_FHPARMS = 2, + IEEE80211_ELEMID_DSPARMS = 3, + IEEE80211_ELEMID_CFPARMS = 4, + IEEE80211_ELEMID_TIM = 5, + IEEE80211_ELEMID_IBSSPARMS = 6, + IEEE80211_ELEMID_COUNTRY = 7, + IEEE80211_ELEMID_REQINFO = 10, + IEEE80211_ELEMID_QBSS_LOAD = 11, + IEEE80211_ELEMID_TCLAS = 14, + IEEE80211_ELEMID_CHALLENGE = 16, + /* 17-31 reserved for challenge text extension */ + IEEE80211_ELEMID_PWRCNSTR = 32, + IEEE80211_ELEMID_PWRCAP = 33, + IEEE80211_ELEMID_TPCREQ = 34, + IEEE80211_ELEMID_TPCREP = 35, + IEEE80211_ELEMID_SUPPCHAN = 36, + IEEE80211_ELEMID_CHANSWITCHANN = 37, + IEEE80211_ELEMID_MEASREQ = 38, + IEEE80211_ELEMID_MEASREP = 39, + IEEE80211_ELEMID_QUIET = 40, + IEEE80211_ELEMID_IBSSDFS = 41, + IEEE80211_ELEMID_ERP = 42, + IEEE80211_ELEMID_TCLAS_PROCESS = 44, + IEEE80211_ELEMID_HTCAP_ANA = 45, + IEEE80211_ELEMID_RESERVED_47 = 47, + IEEE80211_ELEMID_RSN = 48, + IEEE80211_ELEMID_XRATES = 50, + IEEE80211_ELEMID_HTCAP = 51, + IEEE80211_ELEMID_HTINFO = 52, + IEEE80211_ELEMID_MOBILITY_DOMAIN = 54, + IEEE80211_ELEMID_FT = 55, + IEEE80211_ELEMID_TIMEOUT_INTERVAL = 56, + IEEE80211_ELEMID_EXTCHANSWITCHANN = 60, + IEEE80211_ELEMID_HTINFO_ANA = 61, + IEEE80211_ELEMID_SECCHANOFFSET = 62, + IEEE80211_ELEMID_WAPI = 68, /*IE for WAPI */ + IEEE80211_ELEMID_TIME_ADVERTISEMENT = 69, + IEEE80211_ELEMID_RRM = 70, /* Radio resource measurement */ + IEEE80211_ELEMID_2040_COEXT = 72, + IEEE80211_ELEMID_2040_INTOL = 73, + IEEE80211_ELEMID_OBSS_SCAN = 74, + IEEE80211_ELEMID_MMIE = 76, /* 802.11w Management MIC IE */ + IEEE80211_ELEMID_FMS_DESCRIPTOR = 86, /* 802.11v FMS descriptor IE */ + IEEE80211_ELEMID_FMS_REQUEST = 87, /* 802.11v FMS request IE */ + IEEE80211_ELEMID_FMS_RESPONSE = 88, /* 802.11v FMS response IE */ + IEEE80211_ELEMID_BSSMAX_IDLE_PERIOD = 90, /* BSS MAX IDLE PERIOD */ + IEEE80211_ELEMID_TFS_REQUEST = 91, + IEEE80211_ELEMID_TFS_RESPONSE = 92, + IEEE80211_ELEMID_TIM_BCAST_REQUEST = 94, + IEEE80211_ELEMID_TIM_BCAST_RESPONSE = 95, + IEEE80211_ELEMID_INTERWORKING = 107, + IEEE80211_ELEMID_XCAPS = 127, + IEEE80211_ELEMID_RESERVED_133 = 133, + IEEE80211_ELEMID_TPC = 150, + IEEE80211_ELEMID_CCKM = 156, + IEEE80211_ELEMID_VHTCAP = 191, /* VHT Capabilities */ + IEEE80211_ELEMID_VHTOP = 192, /* VHT Operation */ + IEEE80211_ELEMID_EXT_BSS_LOAD = 193, /* Extended BSS Load */ + IEEE80211_ELEMID_WIDE_BAND_CHAN_SWITCH = 194, /* Wide Band Channel Switch */ + IEEE80211_ELEMID_VHT_TX_PWR_ENVLP = 195, /* VHT Transmit Power Envelope */ + IEEE80211_ELEMID_CHAN_SWITCH_WRAP = 196, /* Channel Switch Wrapper */ + IEEE80211_ELEMID_AID = 197, /* AID */ + IEEE80211_ELEMID_QUIET_CHANNEL = 198, /* Quiet Channel */ + IEEE80211_ELEMID_OP_MODE_NOTIFY = 199, /* Operating Mode Notification */ + IEEE80211_ELEMID_VENDOR = 221, /* vendor private */ +}; + +#define IEEE80211_MAX_IE_LEN 255 +#define IEEE80211_RSN_IE_LEN 22 + +#define IEEE80211_CHANSWITCHANN_BYTES 5 +#define IEEE80211_EXTCHANSWITCHANN_BYTES 6 + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_tim_ie { + uint8_t tim_ie; /* IEEE80211_ELEMID_TIM */ + uint8_t tim_len; + uint8_t tim_count; /* DTIM count */ + uint8_t tim_period; /* DTIM period */ + uint8_t tim_bitctl; /* bitmap control */ + uint8_t tim_bitmap[1]; /* variable-length bitmap */ +} __packed; +#endif + +/* Country IE channel triplet */ +struct country_ie_triplet { + union { + uint8_t schan; /* starting channel */ + uint8_t regextid; /* Regulatory Extension Identifier */ + }; + union { + uint8_t nchan; /* number of channels */ + uint8_t regclass; /* Regulatory Class */ + }; + union { + uint8_t maxtxpwr; /* tx power */ + uint8_t coverageclass; /* Coverage Class */ + }; +} __packed; + +struct ieee80211_country_ie { + uint8_t ie; /* IEEE80211_ELEMID_COUNTRY */ + uint8_t len; + uint8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */ + struct country_ie_triplet triplet[1]; +} __packed; + +struct ieee80211_fh_ie { + uint8_t ie; /* IEEE80211_ELEMID_FHPARMS */ + uint8_t len; + uint16_t dwell_time; /* endianess?? */ + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} __packed; + +struct ieee80211_ds_ie { + uint8_t ie; /* IEEE80211_ELEMID_DSPARMS */ + uint8_t len; + uint8_t current_channel; +} __packed; + +struct ieee80211_erp_ie { + uint8_t ie; /* IEEE80211_ELEMID_ERP */ + uint8_t len; + uint8_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_quiet_ie { + uint8_t ie; /* IEEE80211_ELEMID_QUIET */ + uint8_t len; + uint8_t tbttcount; /* quiet start */ + uint8_t period; /* beacon intervals between quiets */ + uint16_t duration; /* TUs of each quiet */ + uint16_t offset; /* TUs of from TBTT of quiet start */ +} __packed; +#endif + +struct ieee80211_channelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_CHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +/* channel switch action frame format definition */ +struct ieee80211_action_spectrum_channel_switch { + struct ieee80211_action csa_header; + struct ieee80211_channelswitch_ie csa_element; +} __packed; + +struct ieee80211_extendedchannelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_EXTCHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newClass; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +struct ieee80211_tpc_ie { + uint8_t ie; + uint8_t len; + uint8_t pwrlimit; +} __packed; + +/* + * MHDRIE included in TKIP MFP protected management frames + */ +struct ieee80211_ese_mhdr_ie { + uint8_t mhdr_id; + uint8_t mhdr_len; + uint8_t mhdr_oui[3]; + uint8_t mhdr_oui_type; + uint8_t mhdr_fc[2]; + uint8_t mhdr_bssid[IEEE80211_ADDR_LEN]; +} __packed; + +/* + * SSID IE + */ +struct ieee80211_ie_ssid { + uint8_t ssid_id; + uint8_t ssid_len; + uint8_t ssid[32]; +} __packed; + +/* + * Supported rates + */ +#define IEEE80211_MAX_SUPPORTED_RATES 8 + +struct ieee80211_ie_rates { + uint8_t rate_id; /* Element Id */ + uint8_t rate_len; /* IE Length */ + uint8_t rate[IEEE80211_MAX_SUPPORTED_RATES]; /* IE Length */ +} __packed; + +/* + * Extended rates + */ +#define IEEE80211_MAX_EXTENDED_RATES 256 + +struct ieee80211_ie_xrates { + uint8_t xrate_id; /* Element Id */ + uint8_t xrate_len; /* IE Length */ + uint8_t xrate[IEEE80211_MAX_EXTENDED_RATES]; /* IE Length */ +} __packed; + +/* + * WPS SSID list information element (maximally sized). + */ +struct ieee80211_ie_ssidl { + uint8_t ssidl_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ssidl_len; /* length in bytes */ + uint8_t ssidl_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t ssidl_type; /* OUI type */ + uint8_t ssidl_prim_cap; /* Primary capabilities */ + uint8_t ssidl_count; /* # of secondary SSIDs */ + uint16_t ssidl_value[248]; +} __packed; + +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_sec_ssid_cap { + uint32_t reserved0 : 1, + akmlist : 6, reserved1 : 4, reeserved2 : 2, ucipher : 15, mcipher : 4; +}; +#else +struct ieee80211_sec_ssid_cap { + uint32_t mcipher : 4, + ucipher : 15, reserved2 : 2, reserved1 : 4, akmlist : 6, reserved0 : 1; +}; +#endif + +struct ieee80211_ie_qbssload { + uint8_t elem_id; /* IEEE80211_ELEMID_QBSS_LOAD */ + uint8_t length; /* length in bytes */ + uint16_t station_count; /* number of station associated */ + uint8_t channel_utilization; /* channel busy time in 0-255 scale */ + uint16_t aac; /* available admission capacity */ +} __packed; + +#define SEC_SSID_HEADER_LEN 6 +#define SSIDL_IE_HEADER_LEN 6 + +struct ieee80211_sec_ssid { + uint8_t sec_ext_cap; + struct ieee80211_sec_ssid_cap sec_cap; + uint8_t sec_ssid_len; + uint8_t sec_ssid[32]; +} __packed; + +/* Definitions of SSIDL IE */ +enum { + CAP_MCIPHER_ENUM_NONE = 0, + CAP_MCIPHER_ENUM_WEP40, + CAP_MCIPHER_ENUM_WEP104, + CAP_MCIPHER_ENUM_TKIP, + CAP_MCIPHER_ENUM_CCMP, + CAP_MCIPHER_ENUM_CKIP_CMIC, + CAP_MCIPHER_ENUM_CKIP, + CAP_MCIPHER_ENUM_CMIC +}; + +#define CAP_UCIPHER_BIT_NONE 0x0001 +#define CAP_UCIPHER_BIT_WEP40 0x0002 +#define CAP_UCIPHER_BIT_WEP104 0x0004 +#define CAP_UCIPHER_BIT_TKIP 0x0008 +#define CAP_UCIPHER_BIT_CCMP 0x0010 +#define CAP_UCIPHER_BIT_CKIP_CMIC 0x0020 +#define CAP_UCIPHER_BIT_CKIP 0x0040 +#define CAP_UCIPHER_BIT_CMIC 0x0080 +#define CAP_UCIPHER_BIT_WPA2_WEP40 0x0100 +#define CAP_UCIPHER_BIT_WPA2_WEP104 0x0200 +#define CAP_UCIPHER_BIT_WPA2_TKIP 0x0400 +#define CAP_UCIPHER_BIT_WPA2_CCMP 0x0800 +#define CAP_UCIPHER_BIT_WPA2_CKIP_CMIC 0x1000 +#define CAP_UCIPHER_BIT_WPA2_CKIP 0x2000 +#define CAP_UCIPHER_BIT_WPA2_CMIC 0x4000 + +#define CAP_AKM_BIT_WPA1_1X 0x01 +#define CAP_AKM_BIT_WPA1_PSK 0x02 +#define CAP_AKM_BIT_WPA2_1X 0x04 +#define CAP_AKM_BIT_WPA2_PSK 0x08 +#define CAP_AKM_BIT_WPA1_CCKM 0x10 +#define CAP_AKM_BIT_WPA2_CCKM 0x20 + +#define IEEE80211_CHALLENGE_LEN 128 + +#define IEEE80211_SUPPCHAN_LEN 26 + +#define IEEE80211_RATE_BASIC 0x80 +#define IEEE80211_RATE_VAL 0x7f + +/* EPR information element flags */ +#define IEEE80211_ERP_NON_ERP_PRESENT 0x01 +#define IEEE80211_ERP_USE_PROTECTION 0x02 +#define IEEE80211_ERP_LONG_PREAMBLE 0x04 + +/* Atheros private advanced capabilities info */ +#define ATHEROS_CAP_TURBO_PRIME 0x01 +#define ATHEROS_CAP_COMPRESSION 0x02 +#define ATHEROS_CAP_FAST_FRAME 0x04 +/* bits 3-6 reserved */ +#define ATHEROS_CAP_BOOST 0x80 + +#define ATH_OUI 0x7f0300 /* Atheros OUI */ +#define ATH_OUI_TYPE 0x01 +#define ATH_OUI_SUBTYPE 0x01 +#define ATH_OUI_VERSION 0x00 +#define ATH_OUI_TYPE_XR 0x03 +#define ATH_OUI_VER_XR 0x01 +#define ATH_OUI_EXTCAP_TYPE 0x04 /* Atheros Extended Cap Type */ +#define ATH_OUI_EXTCAP_SUBTYPE 0x01 /* Atheros Extended Cap Sub-type */ +#define ATH_OUI_EXTCAP_VERSION 0x00 /* Atheros Extended Cap Version */ + +#define WPA_OUI 0xf25000 +#define WPA_VERSION 1 /* current supported version */ +#define CSCO_OUI 0x964000 /* Cisco OUI */ +#define AOW_OUI 0x4a0100 /* AoW OUI, workaround */ +#define AOW_OUI_TYPE 0x01 +#define AOW_OUI_VERSION 0x01 + +#define WSC_OUI 0x0050f204 + +#define WPA_CSE_NULL 0x00 +#define WPA_CSE_WEP40 0x01 +#define WPA_CSE_TKIP 0x02 +#define WPA_CSE_CCMP 0x04 +#define WPA_CSE_WEP104 0x05 + +#define WPA_ASE_NONE 0x00 +#define WPA_ASE_8021X_UNSPEC 0x01 +#define WPA_ASE_8021X_PSK 0x02 +#define WPA_ASE_FT_IEEE8021X 0x20 +#define WPA_ASE_FT_PSK 0x40 +#define WPA_ASE_SHA256_IEEE8021X 0x80 +#define WPA_ASE_SHA256_PSK 0x100 +#define WPA_ASE_WPS 0x200 + +#define RSN_OUI 0xac0f00 +#define RSN_VERSION 1 /* current supported version */ + +#define RSN_CSE_NULL 0x00 +#define RSN_CSE_WEP40 0x01 +#define RSN_CSE_TKIP 0x02 +#define RSN_CSE_WRAP 0x03 +#define RSN_CSE_CCMP 0x04 +#define RSN_CSE_WEP104 0x05 +#define RSN_CSE_AES_CMAC 0x06 + +#define RSN_ASE_NONE 0x00 +#define RSN_ASE_8021X_UNSPEC 0x01 +#define RSN_ASE_8021X_PSK 0x02 +#define RSN_ASE_FT_IEEE8021X 0x20 +#define RSN_ASE_FT_PSK 0x40 +#define RSN_ASE_SHA256_IEEE8021X 0x80 +#define RSN_ASE_SHA256_PSK 0x100 +#define RSN_ASE_WPS 0x200 + +#define AKM_SUITE_TYPE_IEEE8021X 0x01 +#define AKM_SUITE_TYPE_PSK 0x02 +#define AKM_SUITE_TYPE_FT_IEEE8021X 0x03 +#define AKM_SUITE_TYPE_FT_PSK 0x04 +#define AKM_SUITE_TYPE_SHA256_IEEE8021X 0x05 +#define AKM_SUITE_TYPE_SHA256_PSK 0x06 + +#define RSN_CAP_PREAUTH 0x01 +#define RSN_CAP_PTKSA_REPLAYCOUNTER 0x0c +#define RSN_CAP_GTKSA_REPLAYCOUNTER 0x30 +#define RSN_CAP_MFP_REQUIRED 0x40 +#define RSN_CAP_MFP_ENABLED 0x80 + +#define CCKM_OUI 0x964000 +#define CCKM_ASE_UNSPEC 0 +#define WPA_CCKM_AKM 0x00964000 +#define RSN_CCKM_AKM 0x00964000 + +#define WME_OUI 0xf25000 +#define WME_OUI_TYPE 0x02 +#define WME_INFO_OUI_SUBTYPE 0x00 +#define WME_PARAM_OUI_SUBTYPE 0x01 +#define WME_TSPEC_OUI_SUBTYPE 0x02 + +#define WME_PARAM_OUI_VERSION 1 +#define WME_TSPEC_OUI_VERSION 1 +#define WME_VERSION 1 + +/* WME stream classes */ +#define WME_AC_BE 0 /* best effort */ +#define WME_AC_BK 1 /* background */ +#define WME_AC_VI 2 /* video */ +#define WME_AC_VO 3 /* voice */ + +/* WCN IE */ +#define WCN_OUI 0xf25000 /* Microsoft OUI */ +#define WCN_OUI_TYPE 0x04 /* WCN */ + +/* Atheros htoui for ht vender ie; use Epigram OUI for compatibility with pre11n devices */ +#define ATH_HTOUI 0x00904c + +#define SFA_OUI 0x964000 +#define SFA_OUI_TYPE 0x14 +#define SFA_IE_CAP_MFP 0x01 +#define SFA_IE_CAP_DIAG_CHANNEL 0x02 +#define SFA_IE_CAP_LOCATION_SVCS 0x04 +#define SFA_IE_CAP_EXP_BANDWIDTH 0x08 + +#define WPA_OUI_BYTES 0x00, 0x50, 0xf2 +#define RSN_OUI_BYTES 0x00, 0x0f, 0xac +#define WME_OUI_BYTES 0x00, 0x50, 0xf2 +#define ATH_OUI_BYTES 0x00, 0x03, 0x7f +#define SFA_OUI_BYTES 0x00, 0x40, 0x96 +#define CCKM_OUI_BYTES 0x00, 0x40, 0x96 +#define WPA_SEL(x) (((x)<<24)|WPA_OUI) +#define RSN_SEL(x) (((x)<<24)|RSN_OUI) +#define SFA_SEL(x) (((x)<<24)|SFA_OUI) +#define CCKM_SEL(x) (((x)<<24)|CCKM_OUI) + +#define IEEE80211_RV(v) ((v) & IEEE80211_RATE_VAL) + +/* + * AUTH management packets + * + * octet algo[2] + * octet seq[2] + * octet status[2] + * octet chal.id + * octet chal.length + * octet chal.text[253] + */ + +typedef uint8_t *ieee80211_mgt_auth_t; + +#define IEEE80211_AUTH_ALGORITHM(auth) \ + ((auth)[0] | ((auth)[1] << 8)) +#define IEEE80211_AUTH_TRANSACTION(auth) \ + ((auth)[2] | ((auth)[3] << 8)) +#define IEEE80211_AUTH_STATUS(auth) \ + ((auth)[4] | ((auth)[5] << 8)) + +#define IEEE80211_AUTH_ALG_OPEN 0x0000 +#define IEEE80211_AUTH_ALG_SHARED 0x0001 +#define IEEE80211_AUTH_ALG_FT 0x0002 +#define IEEE80211_AUTH_ALG_LEAP 0x0080 + +enum { + IEEE80211_AUTH_OPEN_REQUEST = 1, + IEEE80211_AUTH_OPEN_RESPONSE = 2, +}; + +enum { + IEEE80211_AUTH_SHARED_REQUEST = 1, + IEEE80211_AUTH_SHARED_CHALLENGE = 2, + IEEE80211_AUTH_SHARED_RESPONSE = 3, + IEEE80211_AUTH_SHARED_PASS = 4, +}; + +/* + * Reason codes + * + * Unlisted codes are reserved + */ + +enum { + IEEE80211_REASON_UNSPECIFIED = 1, + IEEE80211_REASON_AUTH_EXPIRE = 2, + IEEE80211_REASON_AUTH_LEAVE = 3, + IEEE80211_REASON_ASSOC_EXPIRE = 4, + IEEE80211_REASON_ASSOC_TOOMANY = 5, + IEEE80211_REASON_NOT_AUTHED = 6, + IEEE80211_REASON_NOT_ASSOCED = 7, + IEEE80211_REASON_ASSOC_LEAVE = 8, + IEEE80211_REASON_ASSOC_NOT_AUTHED = 9, + + IEEE80211_REASON_RSN_REQUIRED = 11, + IEEE80211_REASON_RSN_INCONSISTENT = 12, + IEEE80211_REASON_IE_INVALID = 13, + IEEE80211_REASON_MIC_FAILURE = 14, + + IEEE80211_REASON_QOS = 32, + IEEE80211_REASON_QOS_BANDWITDH = 33, + IEEE80211_REASON_QOS_CH_CONDITIONS = 34, + IEEE80211_REASON_QOS_TXOP = 35, + IEEE80211_REASON_QOS_LEAVE = 36, + IEEE80211_REASON_QOS_DECLINED = 37, + IEEE80211_REASON_QOS_SETUP_REQUIRED = 38, + IEEE80211_REASON_QOS_TIMEOUT = 39, + IEEE80211_REASON_QOS_CIPHER = 45, + + IEEE80211_STATUS_SUCCESS = 0, + IEEE80211_STATUS_UNSPECIFIED = 1, + IEEE80211_STATUS_CAPINFO = 10, + IEEE80211_STATUS_NOT_ASSOCED = 11, + IEEE80211_STATUS_OTHER = 12, + IEEE80211_STATUS_ALG = 13, + IEEE80211_STATUS_SEQUENCE = 14, + IEEE80211_STATUS_CHALLENGE = 15, + IEEE80211_STATUS_TIMEOUT = 16, + IEEE80211_STATUS_TOOMANY = 17, + IEEE80211_STATUS_BASIC_RATE = 18, + IEEE80211_STATUS_SP_REQUIRED = 19, + IEEE80211_STATUS_PBCC_REQUIRED = 20, + IEEE80211_STATUS_CA_REQUIRED = 21, + IEEE80211_STATUS_TOO_MANY_STATIONS = 22, + IEEE80211_STATUS_RATES = 23, + IEEE80211_STATUS_SHORTSLOT_REQUIRED = 25, + IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26, + IEEE80211_STATUS_NO_HT = 27, + IEEE80211_STATUS_REJECT_TEMP = 30, + IEEE80211_STATUS_MFP_VIOLATION = 31, + IEEE80211_STATUS_REFUSED = 37, + IEEE80211_STATUS_INVALID_PARAM = 38, + + IEEE80211_STATUS_DLS_NOT_ALLOWED = 48, +}; + +/* private IEEE80211_STATUS */ +#define IEEE80211_STATUS_CANCEL -1 +#define IEEE80211_STATUS_INVALID_IE -2 +#define IEEE80211_STATUS_INVALID_CHANNEL -3 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ +#define IEEE80211_WEP_EXTIV 0x20 +#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */ +#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */ + +#define IEEE80211_CCMP_HEADERLEN 8 +#define IEEE80211_CCMP_MICLEN 8 + +/* + * 802.11w defines a MMIE chunk to be attached at the end of + * any outgoing broadcast or multicast robust management frame. + * MMIE field is total 18 bytes in size. Following the diagram of MMIE + * + * <------------ 18 Bytes MMIE -----------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * bytes 1 1 2 6 8 + * + */ +#define IEEE80211_MMIE_LEN 18 +#define IEEE80211_MMIE_ELEMENTIDLEN 1 +#define IEEE80211_MMIE_LENGTHLEN 1 +#define IEEE80211_MMIE_KEYIDLEN 2 +#define IEEE80211_MMIE_IPNLEN 6 +#define IEEE80211_MMIE_MICLEN 8 + +#define IEEE80211_CRC_LEN 4 + +#define IEEE80211_8021Q_HEADER_LEN 4 +/* + * Maximum acceptable MTU is: + * IEEE80211_MAX_LEN - WEP overhead - CRC - + * QoS overhead - RSN/WPA overhead + * Min is arbitrarily chosen > IEEE80211_MIN_LEN. The default + * mtu is Ethernet-compatible; it's set by ether_ifattach. + */ +#define IEEE80211_MTU_MAX 2290 +#define IEEE80211_MTU_MIN 32 + +/* Rather than using this default value, customer platforms can provide a custom value for this constant. + Coustomer platform will use the different define value by themself */ +#ifndef IEEE80211_MAX_MPDU_LEN +#define IEEE80211_MAX_MPDU_LEN (3840 + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) +#endif +#define IEEE80211_ACK_LEN \ + (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) +#define IEEE80211_MIN_LEN \ + (sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN) + +/* An 802.11 data frame can be one of three types: + 1. An unaggregated frame: The maximum length of an unaggregated data frame is 2324 bytes + headers. + 2. A data frame that is part of an AMPDU: The maximum length of an AMPDU may be upto 65535 bytes, but data frame is limited to 2324 bytes + header. + 3. An AMSDU: The maximum length of an AMSDU is eihther 3839 or 7095 bytes. + The maximum frame length supported by hardware is 4095 bytes. + A length of 3839 bytes is chosen here to support unaggregated data frames, any size AMPDUs and 3839 byte AMSDUs. + */ +#define IEEE80211N_MAX_FRAMELEN 3839 +#define IEEE80211N_MAX_LEN (IEEE80211N_MAX_FRAMELEN + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) + +#define IEEE80211_TX_CHAINMASK_MIN 1 +#define IEEE80211_TX_CHAINMASK_MAX 7 + +#define IEEE80211_RX_CHAINMASK_MIN 1 +#define IEEE80211_RX_CHAINMASK_MAX 7 + +/* + * The 802.11 spec says at most 2007 stations may be + * associated at once. For most AP's this is way more + * than is feasible so we use a default of 128. This + * number may be overridden by the driver and/or by + * user configuration. + */ +#define IEEE80211_AID_MAX 2007 +#define IEEE80211_AID_DEF 128 + +#define IEEE80211_AID(b) ((b) &~0xc000) + +/* + * RTS frame length parameters. The default is specified in + * the 802.11 spec. The max may be wrong for jumbo frames. + */ +#define IEEE80211_RTS_DEFAULT 512 +#define IEEE80211_RTS_MIN 0 +#define IEEE80211_RTS_MAX 2347 + +/* + * Fragmentation limits + */ +#define IEEE80211_FRAGMT_THRESHOLD_MIN 540 /* min frag threshold */ +#define IEEE80211_FRAGMT_THRESHOLD_MAX 2346 /* max frag threshold */ + +/* + * Regulatory extention identifier for country IE. + */ +#define IEEE80211_REG_EXT_ID 201 + +/* + * overlapping BSS + */ +#define IEEE80211_OBSS_SCAN_PASSIVE_DWELL_DEF 20 +#define IEEE80211_OBSS_SCAN_ACTIVE_DWELL_DEF 10 +#define IEEE80211_OBSS_SCAN_INTERVAL_DEF 300 +#define IEEE80211_OBSS_SCAN_PASSIVE_TOTAL_DEF 200 +#define IEEE80211_OBSS_SCAN_ACTIVE_TOTAL_DEF 20 +#define IEEE80211_OBSS_SCAN_THRESH_DEF 25 +#define IEEE80211_OBSS_SCAN_DELAY_DEF 5 + +/* + * overlapping BSS scan ie + */ +struct ieee80211_ie_obss_scan { + uint8_t elem_id; + uint8_t elem_len; + uint16_t scan_passive_dwell; + uint16_t scan_active_dwell; + uint16_t scan_interval; + uint16_t scan_passive_total; + uint16_t scan_active_total; + uint16_t scan_delay; + uint16_t scan_thresh; +} __packed; + +/* + * Extended capability ie + */ +struct ieee80211_ie_ext_cap { + uint8_t elem_id; + uint8_t elem_len; + uint32_t ext_capflags; + uint32_t ext_capflags2; +} __packed; + +/* Extended capability IE flags */ +#define IEEE80211_EXTCAPIE_2040COEXTMGMT 0x00000001 +#define IEEE80211_EXTCAPIE_TFS 0x00010000 +#define IEEE80211_EXTCAPIE_FMS 0x00000800 +#define IEEE80211_EXTCAPIE_WNMSLEEPMODE 0x00020000 +#define IEEE80211_EXTCAPIE_TIMBROADCAST 0x00040000 +#define IEEE80211_EXTCAPIE_PROXYARP 0x00001000 +#define IEEE80211_EXTCAPIE_BSSTRANSITION 0x00080000 +/* Tunneled Direct Link Setup (TDLS) extended capability bits */ +#define IEEE80211_EXTCAPIE_PEER_UAPSD_BUF_STA 0x10000000 +#define IEEE80211_EXTCAPIE_TDLS_PEER_PSM 0x20000000 +#define IEEE80211_EXTCAPIE_TDLS_CHAN_SX 0x40000000 +/* 2nd Extended capability IE flags bit32-bit63*/ +#define IEEE80211_EXTCAPIE_TDLSSUPPORT 0x00000020 /* bit-37 TDLS Support */ +#define IEEE80211_EXTCAPIE_TDLSPROHIBIT 0x00000040 /* bit-38 TDLS Prohibit Support */ +#define IEEE80211_EXTCAPIE_TDLSCHANSXPROHIBIT 0x00000080 /* bit-39 TDLS Channel Switch Prohibit */ +#define IEEE80211_EXTCAPIE_TDLS_WIDE_BAND 0x20000080 /* bit-61 TDLS Wide Bandwidth support */ +#define IEEE80211_EXTCAPIE_OP_MODE_NOTIFY 0x40000000 /* bit-62 Operating Mode notification */ + +/* + * These caps are populated when we recieve beacon/probe response + * This is used to maintain local TDLS cap bit masks + */ + +#define IEEE80211_TDLS_PROHIBIT 0x00000001 /* bit-1 TDLS Prohibit Support */ + +/* + * 20/40 BSS coexistence ie + */ +struct ieee80211_ie_bss_coex { + uint8_t elem_id; + uint8_t elem_len; +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t reserved1 : 1, + reserved2 : 1, + reserved3 : 1, + obss_exempt_grant : 1, + obss_exempt_req : 1, + ht20_width_req : 1, ht40_intolerant : 1, inf_request : 1; +#else + uint8_t inf_request : 1, + ht40_intolerant : 1, + ht20_width_req : 1, + obss_exempt_req : 1, + obss_exempt_grant : 1, reserved3 : 1, reserved2 : 1, reserved1 : 1; +#endif +} __packed; + +/* + * 20/40 BSS intolerant channel report ie + */ +struct ieee80211_ie_intolerant_report { + uint8_t elem_id; + uint8_t elem_len; + uint8_t reg_class; + uint8_t chan_list[1]; /* variable-length channel list */ +} __packed; + +/* + * 20/40 coext management action frame + */ +struct ieee80211_action_bss_coex_frame { + struct ieee80211_action ac_header; + struct ieee80211_ie_bss_coex coex; + struct ieee80211_ie_intolerant_report chan_report; +} __packed; + +typedef enum ieee80211_tie_interval_type { + IEEE80211_TIE_INTERVAL_TYPE_RESERVED = 0, + IEEE80211_TIE_INTERVAL_TYPE_REASSOC_DEADLINE_INTERVAL = 1, + IEEE80211_TIE_INTERVAL_TYPE_KEY_LIFETIME_INTERVAL = 2, + IEEE80211_TIE_INTERVAL_TYPE_ASSOC_COMEBACK_TIME = 3, +} ieee80211_tie_interval_type_t; + +struct ieee80211_ie_timeout_interval { + uint8_t elem_id; + uint8_t elem_len; + uint8_t interval_type; + uint32_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +/* Management MIC information element (IEEE 802.11w) */ +struct ieee80211_mmie { + uint8_t element_id; + uint8_t length; + uint16_t key_id; + uint8_t sequence_number[6]; + uint8_t mic[8]; +} __packed; +#endif + +/* + * 802.11n Secondary Channel Offset element + */ +#define IEEE80211_SEC_CHAN_OFFSET_SCN 0 /* no secondary channel */ +#define IEEE80211_SEC_CHAN_OFFSET_SCA 1 /* secondary channel above */ +#define IEEE80211_SEC_CHAN_OFFSET_SCB 3 /* secondary channel below */ + +struct ieee80211_ie_sec_chan_offset { + uint8_t elem_id; + uint8_t len; + uint8_t sec_chan_offset; +} __packed; + +/* + * 802.11ac Transmit Power Envelope element + */ +#define IEEE80211_VHT_TXPWR_IS_SUB_ELEMENT 1 /* It checks whether its sub element */ +#define IEEE80211_VHT_TXPWR_MAX_POWER_COUNT 4 /* Max TX power elements valid */ +#define IEEE80211_VHT_TXPWR_NUM_POWER_SUPPORTED 3 /* Max TX power elements supported */ +#define IEEE80211_VHT_TXPWR_LCL_MAX_PWR_UNITS_SHFT 3 /* B3-B5 Local Max transmit power units */ + +struct ieee80211_ie_vht_txpwr_env { + uint8_t elem_id; + uint8_t elem_len; + uint8_t txpwr_info; /* Transmit Power Information */ + uint8_t local_max_txpwr[4]; /* Local Max TxPower for 20,40,80,160MHz */ +} __packed; + +/* + * 802.11ac Wide Bandwidth Channel Switch Element + */ + +#define IEEE80211_VHT_EXTCH_SWITCH 1 /* For extension channel switch */ +#define CHWIDTH_VHT20 20 /* Channel width 20 */ +#define CHWIDTH_VHT40 40 /* Channel width 40 */ +#define CHWIDTH_VHT80 80 /* Channel width 80 */ +#define CHWIDTH_VHT160 160 /* Channel width 160 */ + +struct ieee80211_ie_wide_bw_switch { + uint8_t elem_id; + uint8_t elem_len; + uint8_t new_ch_width; /* New channel width */ + uint8_t new_ch_freq_seg1; /* Channel Center frequency 1 */ + uint8_t new_ch_freq_seg2; /* Channel Center frequency 2 */ +} __packed; + +#define IEEE80211_RSSI_RX 0x00000001 +#define IEEE80211_RSSI_TX 0x00000002 +#define IEEE80211_RSSI_EXTCHAN 0x00000004 +#define IEEE80211_RSSI_BEACON 0x00000008 +#define IEEE80211_RSSI_RXDATA 0x00000010 + +#define IEEE80211_RATE_TX 0 +#define IEEE80211_RATE_RX 1 +#define IEEE80211_LASTRATE_TX 2 +#define IEEE80211_LASTRATE_RX 3 +#define IEEE80211_RATECODE_TX 4 +#define IEEE80211_RATECODE_RX 5 + +#define IEEE80211_MAX_RATE_PER_CLIENT 8 +/* Define for the P2P Wildcard SSID */ +#define IEEE80211_P2P_WILDCARD_SSID "DIRECT-" + +#define IEEE80211_P2P_WILDCARD_SSID_LEN (sizeof(IEEE80211_P2P_WILDCARD_SSID) - 1) + +#endif /* CDS_COMMON_IEEE80211_H_ */ diff --git a/core/cds/inc/cds_ieee80211_defines.h b/core/cds/inc/cds_ieee80211_defines.h new file mode 100644 index 0000000000..037ad42950 --- /dev/null +++ b/core/cds/inc/cds_ieee80211_defines.h @@ -0,0 +1,1374 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef CDS_IEEE80211_DEFINES_H_ +#define CDS_IEEE80211_DEFINES_H_ + +#include "cds_ieee80211_common.h" + +/* + * Public defines for Atheros Upper MAC Layer + */ + +/** + * @brief Opaque handle of 802.11 protocal layer. + */ +struct ieee80211com; +typedef struct ieee80211com *wlan_dev_t; + +/** + * @brief Opaque handle to App IE module. + */ +struct wlan_mlme_app_ie; +typedef struct wlan_mlme_app_ie *wlan_mlme_app_ie_t; + +/** + * @brief Opaque handle of network instance (vap) in 802.11 protocal layer. + */ +struct ieee80211vap; +typedef struct ieee80211vap *wlan_if_t; + +struct ieee80211vapprofile; +typedef struct ieee80211vapprofile *wlan_if_info_t; + +/** + * @brief Opaque handle of a node in the wifi network. + */ +struct ieee80211_node; +typedef struct ieee80211_node *wlan_node_t; + +/** + * @brief Opaque handle of OS interface (ifp in the case of unix ). + */ +struct _os_if_t; +typedef struct _os_if_t *os_if_t; + +/** + * + * @brief Opaque handle. + */ +typedef void *os_handle_t; + +/** + * @brief Opaque handle of a channel. + */ +struct ieee80211_channel; +typedef struct ieee80211_channel *wlan_chan_t; + +/** + * @brief Opaque handle scan_entry. + */ +struct ieee80211_scan_entry; +typedef struct ieee80211_scan_entry *wlan_scan_entry_t; + +/* AoW related defines */ +#define AOW_MAX_RECEIVER_COUNT 10 + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_ISO_COUNTRY_LENGTH 3 /* length of 11d ISO country string */ + +typedef struct _ieee80211_ssid { + int len; + uint8_t ssid[IEEE80211_NWID_LEN]; +} ieee80211_ssid; + +typedef struct ieee80211_tx_status { + int ts_flags; +#define IEEE80211_TX_ERROR 0x01 +#define IEEE80211_TX_XRETRY 0x02 + + int ts_retries; /* number of retries to successfully transmit this frame */ +#ifdef ATH_SUPPORT_TxBF + uint8_t ts_txbfstatus; +#define AR_BW_Mismatch 0x1 +#define AR_Stream_Miss 0x2 +#define AR_CV_Missed 0x4 +#define AR_Dest_Miss 0x8 +#define AR_Expired 0x10 +#define AR_TxBF_Valid_HW_Status (AR_BW_Mismatch|AR_Stream_Miss|AR_CV_Missed|AR_Dest_Miss|AR_Expired) +#define TxBF_STATUS_Sounding_Complete 0x20 +#define TxBF_STATUS_Sounding_Request 0x40 +#define TxBF_Valid_SW_Status (TxBF_STATUS_Sounding_Complete | TxBF_STATUS_Sounding_Request) +#define TxBF_Valid_Status (AR_TxBF_Valid_HW_Status | TxBF_Valid_SW_Status) + uint32_t ts_tstamp; /* tx time stamp */ +#endif +#ifdef ATH_SUPPORT_FLOWMAC_MODULE + uint8_t ts_flowmac_flags; +#define IEEE80211_TX_FLOWMAC_DONE 0x01 +#endif + uint32_t ts_rateKbps; +} ieee80211_xmit_status; + +#ifndef EXTERNAL_USE_ONLY +typedef struct ieee80211_rx_status { + int rs_numchains; + int rs_flags; +#define IEEE80211_RX_FCS_ERROR 0x01 +#define IEEE80211_RX_MIC_ERROR 0x02 +#define IEEE80211_RX_DECRYPT_ERROR 0x04 +/* holes in flags here between, ATH_RX_XXXX to IEEE80211_RX_XXX */ +#define IEEE80211_RX_KEYMISS 0x200 + int rs_rssi; /* RSSI (noise floor ajusted) */ + int rs_abs_rssi; /* absolute RSSI */ + int rs_datarate; /* data rate received */ + int rs_rateieee; + int rs_ratephy; + +#define IEEE80211_MAX_ANTENNA 3 /* Keep the same as ATH_MAX_ANTENNA */ + uint8_t rs_rssictl[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_rssiextn[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_isvalidrssi; /* rs_rssi is valid or not */ + + enum ieee80211_phymode rs_phymode; + int rs_freq; + + union { + uint8_t data[8]; + uint64_t tsf; + } rs_tstamp; + + /* + * Detail channel structure of recv frame. + * It could be NULL if not available + */ + struct ieee80211_channel *rs_full_chan; + + uint8_t rs_isaggr; + uint8_t rs_isapsd; + int16_t rs_noisefloor; + uint16_t rs_channel; +#ifdef ATH_SUPPORT_TxBF + uint32_t rs_rpttstamp; /* txbf report time stamp */ +#endif + + /* The following counts are meant to assist in stats calculation. + These variables are incremented only in specific situations, and + should not be relied upon for any purpose other than the original + stats related purpose they have been introduced for. */ + + uint16_t rs_cryptodecapcount; /* Crypto bytes decapped/demic'ed. */ + uint8_t rs_padspace; /* No. of padding bytes present after header + in wbuf. */ + uint8_t rs_qosdecapcount; /* QoS/HTC bytes decapped. */ + + /* End of stats calculation related counts. */ + + uint8_t rs_lsig[IEEE80211_LSIG_LEN]; + uint8_t rs_htsig[IEEE80211_HTSIG_LEN]; + uint8_t rs_servicebytes[IEEE80211_SB_LEN]; + +} ieee80211_recv_status; +#endif /* EXTERNAL_USE_ONLY */ + +/* + * flags to be passed to ieee80211_vap_create function . + */ +#define IEEE80211_CLONE_BSSID 0x0001 /* allocate unique mac/bssid */ +#define IEEE80211_CLONE_NOBEACONS 0x0002 /* don't setup beacon timers */ +#define IEEE80211_CLONE_WDS 0x0004 /* enable WDS processing */ +#define IEEE80211_CLONE_WDSLEGACY 0x0008 /* legacy WDS operation */ +#define IEEE80211_PRIMARY_VAP 0x0010 /* primary vap */ +#define IEEE80211_P2PDEV_VAP 0x0020 /* p2pdev vap */ +#define IEEE80211_P2PGO_VAP 0x0040 /* p2p-go vap */ +#define IEEE80211_P2PCLI_VAP 0x0080 /* p2p-client vap */ +#define IEEE80211_CLONE_MACADDR 0x0100 /* create vap w/ specified mac/bssid */ +#define IEEE80211_CLONE_MATADDR 0x0200 /* create vap w/ specified MAT addr */ +#define IEEE80211_WRAP_VAP 0x0400 /* wireless repeater ap vap */ + +/* + * For the new multi-vap scan feature, there is a set of default priority tables + * for each OpMode. + * The following are the default list of the VAP Scan Priority Mapping based on OpModes. + * NOTE: the following are only used when "#if ATH_SUPPORT_MULTIPLE_SCANS" is true. + */ +/* For IBSS opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_IBSS_BASE 0 +/* For STA opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_P2P_CLIENT 1 +/* For HostAp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_GO 1 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_DEVICE 2 +/* For BTAmp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_BTAMP_BASE 0 + +typedef enum _ieee80211_dev_vap_event { + IEEE80211_VAP_CREATED = 1, + IEEE80211_VAP_STOPPED, + IEEE80211_VAP_DELETED +} ieee80211_dev_vap_event; + +typedef struct _wlan_dev_event_handler_table { + void (*wlan_dev_vap_event)(void *event_arg, wlan_dev_t, os_if_t, ieee80211_dev_vap_event); /* callback to receive vap events */ +#ifdef ATH_SUPPORT_SPECTRAL + void (*wlan_dev_spectral_indicate)(void *, void *, uint32_t); +#endif +} wlan_dev_event_handler_table; + +typedef enum _ieee80211_ap_stopped_reason { + IEEE80211_AP_STOPPED_REASON_DUMMY = 0, /* Dummy placeholder. Should not use */ + IEEE80211_AP_STOPPED_REASON_CHANNEL_DFS = 1, +} ieee80211_ap_stopped_reason; + +typedef int IEEE80211_REASON_CODE; +typedef int IEEE80211_STATUS; + +/* + * scan API related structs. + */ +typedef enum _ieee80211_scan_type { + IEEE80211_SCAN_BACKGROUND, + IEEE80211_SCAN_FOREGROUND, + IEEE80211_SCAN_SPECTRAL, + IEEE80211_SCAN_REPEATER_BACKGROUND, + IEEE80211_SCAN_REPEATER_EXT_BACKGROUND, + IEEE80211_SCAN_RADIO_MEASUREMENTS, +} ieee80211_scan_type; + +/* + * Priority numbers must be sequential, starting with 0. + */ +typedef enum ieee80211_scan_priority_t { + IEEE80211_SCAN_PRIORITY_VERY_LOW = 0, + IEEE80211_SCAN_PRIORITY_LOW, + IEEE80211_SCAN_PRIORITY_MEDIUM, + IEEE80211_SCAN_PRIORITY_HIGH, + IEEE80211_SCAN_PRIORITY_VERY_HIGH, + + IEEE80211_SCAN_PRIORITY_COUNT /* number of priorities supported */ +} IEEE80211_SCAN_PRIORITY; + +typedef uint16_t IEEE80211_SCAN_REQUESTOR; +typedef uint32_t IEEE80211_SCAN_ID; + +#define IEEE80211_SCAN_ID_NONE 0 + +/* All P2P scans currently use medium priority */ +#define IEEE80211_P2P_DEFAULT_SCAN_PRIORITY IEEE80211_SCAN_PRIORITY_MEDIUM +#define IEEE80211_P2P_SCAN_PRIORITY_HIGH IEEE80211_SCAN_PRIORITY_HIGH + +/* Masks identifying types/ID of scans */ +#define IEEE80211_SPECIFIC_SCAN 0x00000000 +#define IEEE80211_VAP_SCAN 0x01000000 +#define IEEE80211_ALL_SCANS 0x04000000 + +/** + * host scan bit. only relevant for host/target architecture. + * do not reuse this bit definition. target uses this . + * + */ +#define IEEE80211_HOST_SCAN 0x80000000 +#define IEEE80211_SCAN_CLASS_MASK 0xFF000000 + +#define IEEE80211_SCAN_PASSIVE 0x0001 /* passively scan all the channels */ +#define IEEE80211_SCAN_ACTIVE 0x0002 /* actively scan all the channels (regdomain rules still apply) */ +#define IEEE80211_SCAN_2GHZ 0x0004 /* scan 2GHz band */ +#define IEEE80211_SCAN_5GHZ 0x0008 /* scan 5GHz band */ +#define IEEE80211_SCAN_ALLBANDS (IEEE80211_SCAN_5GHZ | IEEE80211_SCAN_2GHZ) +#define IEEE80211_SCAN_CONTINUOUS 0x0010 /* keep scanning until maxscantime expires */ +#define IEEE80211_SCAN_FORCED 0x0020 /* forced scan (OS request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_NOW 0x0040 /* scan now (User request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_ADD_BCAST_PROBE 0x0080 /* add wildcard ssid and broadcast probe request if there is none */ +#define IEEE80211_SCAN_EXTERNAL 0x0100 /* scan requested by OS */ +#define IEEE80211_SCAN_BURST 0x0200 /* scan multiple channels before returning to BSS channel */ +#define IEEE80211_SCAN_CHAN_EVENT 0x0400 /* scan chan event for offload architectures */ +#define IEEE80211_SCAN_FILTER_PROBE_REQ 0x0800 /* Filter probe requests- applicable only for offload architectures */ + +#define IEEE80211_SCAN_PARAMS_MAX_SSID 10 +#define IEEE80211_SCAN_PARAMS_MAX_BSSID 10 + +/* flag definitions passed to scan_cancel API */ + +#define IEEE80211_SCAN_CANCEL_ASYNC 0x0 /* asynchronouly wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_WAIT 0x1 /* wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_SYNC 0x2 /* synchronously execute cancel scan */ + +#ifndef EXTERNAL_USE_ONLY +typedef bool (*ieee80211_scan_termination_check)(void *arg); + +typedef struct _ieee80211_scan_params { + ieee80211_scan_type type; + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channels (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channels (if no response) */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int idle_time; /* time in msec on bss channel before switching channel */ + int max_scan_time; /* maximum time in msec allowed for scan */ + int probe_delay; /* delay in msec before sending probe request */ + int offchan_retry_delay; /* delay in msec before retrying off-channel switch */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int max_offchan_retries; /* maximum number of times to retry off-channel switch */ + int beacon_timeout; /* maximum time to wait for beacons */ + int flags; /* scan flags */ + int num_channels; /* number of channels to scan */ + bool multiple_ports_active; /* driver has multiple ports active in the home channel */ + bool restricted_scan; /* Perform restricted scan */ + bool chan_list_allocated; + IEEE80211_SCAN_PRIORITY p2p_scan_priority; /* indicates the scan priority if this is a P2P-related scan */ + uint32_t *chan_list; /* array of ieee channels (or) frequencies to scan */ + int num_ssid; /* number of desired ssids */ + ieee80211_ssid ssid_list[IEEE80211_SCAN_PARAMS_MAX_SSID]; + int num_bssid; /* number of desired bssids */ + uint8_t bssid_list[IEEE80211_SCAN_PARAMS_MAX_BSSID][IEEE80211_ADDR_LEN]; + struct ieee80211_node *bss_node; /* BSS node */ + int ie_len; /* length of the ie data to be added to probe req */ + uint8_t *ie_data; /* pointer to ie data */ + ieee80211_scan_termination_check check_termination_function; /* function checking for termination condition */ + void *check_termination_context; /* context passed to function above */ +} ieee80211_scan_params; + +/* Data types used to specify scan priorities */ +typedef uint32_t IEEE80211_PRIORITY_MAPPING[IEEE80211_SCAN_PRIORITY_COUNT]; + +/************************************** + * Called before attempting to roam. Modifies the rssiAdder of a BSS + * based on the preferred status of a BSS. + * + * According to CCX spec, AP in the neighbor list is not meant for giving extra + * weightage in roaming. By doing so, roaming becomes sticky. See bug 21220. + * Change the weightage to 0. Cisco may ask in future for a user control of + * this weightage. + */ +#define PREFERRED_BSS_RANK 20 +#define NEIGHBOR_BSS_RANK 0 /* must be less than preferred BSS rank */ + +/* + * The utility of the BSS is the metric used in the selection + * of a BSS. The Utility of the BSS is reduced if we just left the BSS. + * The Utility of the BSS is not reduced if we have left the + * BSS for 8 seconds (8000ms) or more. + * 2^13 milliseconds is a close approximation to avoid expensive division + */ +#define LAST_ASSOC_TIME_DELTA_REQUIREMENT (1 << 13) /* 8192 */ + +#define QBSS_SCALE_MAX 255 /* Qbss channel load Max value */ +#define QBSS_SCALE_DOWN_FACTOR 2 /* scale factor to reduce Qbss channel load */ +#define QBSS_HYST_ADJ 60 /* Qbss Weightage factor for the current AP */ + +/* + * Flags used to set field APState + */ +#define AP_STATE_GOOD 0x00 +#define AP_STATE_BAD 0x01 +#define AP_STATE_RETRY 0x10 +#define BAD_AP_TIMEOUT 6000 /* In milli seconds */ +/* + * To disable BAD_AP status check on any scan entry + */ +#define BAD_AP_TIMEOUT_DISABLED 0 + +/* + * BAD_AP timeout specified in seconds + */ +#define BAD_AP_TIMEOUT_IN_SECONDS 10 + +/* + * State values used to represent our assoc_state with ap (discrete, not bitmasks) + */ +#define AP_ASSOC_STATE_NONE 0 +#define AP_ASSOC_STATE_AUTH 1 +#define AP_ASSOC_STATE_ASSOC 2 + +/* + * Entries in the scan list are considered obsolete after 75 seconds. + */ +#define IEEE80211_SCAN_ENTRY_EXPIRE_TIME 75000 + +/* + * idle time is only valid for scan type IEEE80211_SCAN_BACKGROUND. + * if idle time is set then the scanner would change channel from BSS + * channel to foreign channel only if both resttime is expired and + * the theres was not traffic for idletime msec on the bss channel. + * value of 0 for idletime would cause the channel to switch from BSS + * channel to foreign channel as soon as the resttime is expired. + * + * if maxscantime is nonzero and if the scanner can not complete the + * scan in maxscantime msec then the scanner will cancel the scan and + * post IEEE80211_SCAN_COMPLETED event with reason SCAN_TIMEDOUT. + * + */ + +/* + * chanlist can be either ieee channels (or) frequencies. + * if a value is less than 1000 implementation assumes it + * as ieee channel # otherwise implementation assumes it + * as frequency in Mhz. + */ + +typedef enum _ieee80211_scan_event_type { + IEEE80211_SCAN_STARTED, + IEEE80211_SCAN_COMPLETED, + IEEE80211_SCAN_RADIO_MEASUREMENT_START, + IEEE80211_SCAN_RADIO_MEASUREMENT_END, + IEEE80211_SCAN_RESTARTED, + IEEE80211_SCAN_HOME_CHANNEL, + IEEE80211_SCAN_FOREIGN_CHANNEL, + IEEE80211_SCAN_BSSID_MATCH, + IEEE80211_SCAN_FOREIGN_CHANNEL_GET_NF, + IEEE80211_SCAN_DEQUEUED, + IEEE80211_SCAN_PREEMPTED, + + IEEE80211_SCAN_EVENT_COUNT +} ieee80211_scan_event_type; + +typedef enum ieee80211_scan_completion_reason { + IEEE80211_REASON_NONE, + IEEE80211_REASON_COMPLETED, + IEEE80211_REASON_CANCELLED, + IEEE80211_REASON_TIMEDOUT, + IEEE80211_REASON_TERMINATION_FUNCTION, + IEEE80211_REASON_MAX_OFFCHAN_RETRIES, + IEEE80211_REASON_PREEMPTED, + IEEE80211_REASON_RUN_FAILED, + IEEE80211_REASON_INTERNAL_STOP, + + IEEE80211_REASON_COUNT +} ieee80211_scan_completion_reason; + +typedef struct _ieee80211_scan_event { + ieee80211_scan_event_type type; + ieee80211_scan_completion_reason reason; + wlan_chan_t chan; + IEEE80211_SCAN_REQUESTOR requestor; /* Requestor ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ +} ieee80211_scan_event; + +typedef enum _ieee80211_scan_request_status { + IEEE80211_SCAN_STATUS_QUEUED, + IEEE80211_SCAN_STATUS_RUNNING, + IEEE80211_SCAN_STATUS_PREEMPTED, + IEEE80211_SCAN_STATUS_COMPLETED +} ieee80211_scan_request_status; + +/* + * the sentry field of tht ieee80211_scan_event is only valid if the + * event type is IEEE80211_SCAN_BSSID_MATCH. + */ + +typedef void (*ieee80211_scan_event_handler)(wlan_if_t vaphandle, + ieee80211_scan_event *event, + void *arg); + +typedef struct _ieee80211_scan_info { + ieee80211_scan_type type; + IEEE80211_SCAN_REQUESTOR requestor; /* Originator ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ + IEEE80211_SCAN_PRIORITY priority; /* Requested priority level (low/medium/high) */ + ieee80211_scan_request_status scheduling_status; /* Queued/running/preempted/completed */ + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channel (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channel */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int flags; /* scan flags */ + systime_t scan_start_time; /* system time when last scani started */ + int scanned_channels; /* number of scanned channels */ + int default_channel_list_length; /* number of channels in the default channel list */ + int channel_list_length; /* number of channels in the channel list used for the current scan */ + uint8_t in_progress : 1, /* if the scan is in progress */ + cancelled : 1, /* if the scan is cancelled */ + preempted : 1, /* if the scan is preempted */ + restricted : 1; /* if the scan is restricted */ +} ieee80211_scan_info; + +typedef struct _ieee80211_scan_request_info { + wlan_if_t vaphandle; + IEEE80211_SCAN_REQUESTOR requestor; + IEEE80211_SCAN_PRIORITY requested_priority; + IEEE80211_SCAN_PRIORITY absolute_priority; + IEEE80211_SCAN_ID scan_id; + ieee80211_scan_request_status scheduling_status; + ieee80211_scan_params params; + systime_t request_timestamp; + uint32_t maximum_duration; +} ieee80211_scan_request_info; + +#endif /* EXTERNAL_USE_ONLY */ + +#ifndef EXTERNAL_USE_ONLY +typedef void (*ieee80211_acs_event_handler)(void *arg, wlan_chan_t channel); +#endif /* EXTERNAL_USE_ONLY */ + +#define MAX_CHAINS 3 + +typedef struct _wlan_rssi_info { + int8_t avg_rssi; /* average rssi */ + uint8_t valid_mask; /* bitmap of valid elements in rssi_ctrl/ext array */ + int8_t rssi_ctrl[MAX_CHAINS]; + int8_t rssi_ext[MAX_CHAINS]; +} wlan_rssi_info; + +typedef enum _wlan_rssi_type { + WLAN_RSSI_TX, + WLAN_RSSI_RX, + WLAN_RSSI_BEACON, /* rssi of the beacon, only valid for STA/IBSS vap */ + WLAN_RSSI_RX_DATA +} wlan_rssi_type; + +typedef enum _ieee80211_rate_type { + IEEE80211_RATE_TYPE_LEGACY, + IEEE80211_RATE_TYPE_MCS, +} ieee80211_rate_type; + +typedef struct _ieee80211_rate_info { + ieee80211_rate_type type; + uint32_t rate; /* average rate in kbps */ + uint32_t lastrate; /* last packet rate in kbps */ + uint8_t mcs; /* mcs index . is valid if rate type is MCS20 or MCS40 */ + uint8_t maxrate_per_client; +} ieee80211_rate_info; + +typedef enum _ieee80211_node_param_type { + IEEE80211_NODE_PARAM_TX_POWER, + IEEE80211_NODE_PARAM_ASSOCID, + IEEE80211_NODE_PARAM_INACT, /* inactivity timer value */ + IEEE80211_NODE_PARAM_AUTH_MODE, /* auth mode */ + IEEE80211_NODE_PARAM_CAP_INFO, /* auth mode */ +} ieee80211_node_param_type; + +/* + * Per/node (station) statistics available when operating as an AP. + */ +struct ieee80211_nodestats { + uint32_t ns_rx_data; /* rx data frames */ + uint32_t ns_rx_mgmt; /* rx management frames */ + uint32_t ns_rx_ctrl; /* rx control frames */ + uint32_t ns_rx_ucast; /* rx unicast frames */ + uint32_t ns_rx_mcast; /* rx multi/broadcast frames */ + uint64_t ns_rx_bytes; /* rx data count (bytes) */ + uint64_t ns_rx_beacons; /* rx beacon frames */ + uint32_t ns_rx_proberesp; /* rx probe response frames */ + + uint32_t ns_rx_dup; /* rx discard 'cuz dup */ + uint32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t ns_rx_wepfail; /* rx wep processing failed */ + uint32_t ns_rx_demicfail; /* rx demic failed */ + + /* We log MIC and decryption failures against Transmitter STA stats. + Though the frames may not actually be sent by STAs corresponding + to TA, the stats are still valuable for some customers as a sort + of rough indication. + Also note that the mapping from TA to STA may fail sometimes. */ + uint32_t ns_rx_tkipmic; /* rx TKIP MIC failure */ + uint32_t ns_rx_ccmpmic; /* rx CCMP MIC failure */ + uint32_t ns_rx_wpimic; /* rx WAPI MIC failure */ + uint32_t ns_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint32_t ns_rx_decap; /* rx decapsulation failed */ + uint32_t ns_rx_defrag; /* rx defragmentation failed */ + uint32_t ns_rx_disassoc; /* rx disassociation */ + uint32_t ns_rx_deauth; /* rx deauthentication */ + uint32_t ns_rx_action; /* rx action */ + uint32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */ + uint32_t ns_rx_unauth; /* rx on unauthorized port */ + uint32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */ + + uint32_t ns_tx_data; /* tx data frames */ + uint32_t ns_tx_data_success; /* tx data frames successfully + transmitted (unicast only) */ + uint32_t ns_tx_mgmt; /* tx management frames */ + uint32_t ns_tx_ucast; /* tx unicast frames */ + uint32_t ns_tx_mcast; /* tx multi/broadcast frames */ + uint64_t ns_tx_bytes; /* tx data count (bytes) */ + uint64_t ns_tx_bytes_success; /* tx success data count - unicast only + (bytes) */ + uint32_t ns_tx_probereq; /* tx probe request frames */ + uint32_t ns_tx_uapsd; /* tx on uapsd queue */ + uint32_t ns_tx_discard; /* tx dropped by NIC */ + + uint32_t ns_tx_novlantag; /* tx discard 'cuz no tag */ + uint32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */ + + uint32_t ns_tx_eosplost; /* uapsd EOSP retried out */ + + uint32_t ns_ps_discard; /* ps discard 'cuz of age */ + + uint32_t ns_uapsd_triggers; /* uapsd triggers */ + uint32_t ns_uapsd_duptriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_ignoretriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_active; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_triggerenabled; /* uapsd duplicate triggers */ + + /* MIB-related state */ + uint32_t ns_tx_assoc; /* [re]associations */ + uint32_t ns_tx_assoc_fail; /* [re]association failures */ + uint32_t ns_tx_auth; /* [re]authentications */ + uint32_t ns_tx_auth_fail; /* [re]authentication failures */ + uint32_t ns_tx_deauth; /* deauthentications */ + uint32_t ns_tx_deauth_code; /* last deauth reason */ + uint32_t ns_tx_disassoc; /* disassociations */ + uint32_t ns_tx_disassoc_code; /* last disassociation reason */ + uint32_t ns_psq_drops; /* power save queue drops */ +}; + +/* + * station power save mode. + */ +typedef enum ieee80211_psmode { + IEEE80211_PWRSAVE_NONE = 0, /* no power save */ + IEEE80211_PWRSAVE_LOW, + IEEE80211_PWRSAVE_NORMAL, + IEEE80211_PWRSAVE_MAXIMUM, + IEEE80211_PWRSAVE_WNM /* WNM-Sleep Mode */ +} ieee80211_pwrsave_mode; + +/* station power save pspoll handling */ +typedef enum { + IEEE80211_CONTINUE_PSPOLL_FOR_MORE_DATA, + IEEE80211_WAKEUP_FOR_MORE_DATA, +} ieee80211_pspoll_moredata_handling; + +/* + * apps power save state. + */ +typedef enum { + APPS_AWAKE = 0, + APPS_PENDING_SLEEP, + APPS_SLEEP, + APPS_FAKE_SLEEP, /* Pending blocking sleep */ + APPS_FAKING_SLEEP, /* Blocking sleep */ + APPS_UNKNOWN_PWRSAVE, +} ieee80211_apps_pwrsave_state; + +typedef enum _iee80211_mimo_powersave_mode { + IEEE80211_MIMO_POWERSAVE_NONE, /* no mimo power save */ + IEEE80211_MIMO_POWERSAVE_STATIC, /* static mimo power save */ + IEEE80211_MIMO_POWERSAVE_DYNAMIC /* dynamic mimo powersave */ +} ieee80211_mimo_powersave_mode; + +#ifdef ATH_COALESCING +typedef enum _ieee80211_coalescing_state { + IEEE80211_COALESCING_DISABLED = 0, /* Coalescing is disabled */ + IEEE80211_COALESCING_DYNAMIC = 1, /* Dynamically move to Enabled state based on Uruns */ + IEEE80211_COALESCING_ENABLED = 2, /* Coalescing is enabled */ +} ieee80211_coalescing_state; + +#define IEEE80211_TX_COALESCING_THRESHOLD 5 /* Number of underrun errors to trigger coalescing */ +#endif + +typedef enum _ieee80211_cap { + IEEE80211_CAP_SHSLOT, /* CAPABILITY: short slot */ + IEEE80211_CAP_SHPREAMBLE, /* CAPABILITY: short premable */ + IEEE80211_CAP_MULTI_DOMAIN, /* CAPABILITY: multiple domain */ + IEEE80211_CAP_WMM, /* CAPABILITY: WMM */ + IEEE80211_CAP_HT, /* CAPABILITY: HT */ + IEEE80211_CAP_PERF_PWR_OFLD, /* CAPABILITY: power performance offload support */ + IEEE80211_CAP_11AC, /* CAPABILITY: 11ac support */ +} ieee80211_cap; + +typedef enum _ieee80211_device_param { + IEEE80211_DEVICE_RSSI_CTL, + IEEE80211_DEVICE_NUM_TX_CHAIN, + IEEE80211_DEVICE_NUM_RX_CHAIN, + IEEE80211_DEVICE_TX_CHAIN_MASK, + IEEE80211_DEVICE_RX_CHAIN_MASK, + IEEE80211_DEVICE_TX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_RX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_BMISS_LIMIT, /* # of beacon misses for HW to generate BMISS intr */ + IEEE80211_DEVICE_PROTECTION_MODE, /* protection mode */ + IEEE80211_DEVICE_BLKDFSCHAN, /* block the use of DFS channels */ + IEEE80211_DEVICE_GREEN_AP_PS_ENABLE, + IEEE80211_DEVICE_GREEN_AP_PS_TIMEOUT, + IEEE80211_DEVICE_GREEN_AP_PS_ON_TIME, + IEEE80211_DEVICE_CWM_EXTPROTMODE, + IEEE80211_DEVICE_CWM_EXTPROTSPACING, + IEEE80211_DEVICE_CWM_ENABLE, + IEEE80211_DEVICE_CWM_EXTBUSYTHRESHOLD, + IEEE80211_DEVICE_DOTH, + IEEE80211_DEVICE_ADDBA_MODE, + IEEE80211_DEVICE_COUNTRYCODE, + IEEE80211_DEVICE_MULTI_CHANNEL, /* turn on/off off channel support */ + IEEE80211_DEVICE_MAX_AMSDU_SIZE, /* Size of AMSDU to be sent on the air */ + IEEE80211_DEVICE_P2P, /* Enable or Disable P2P */ + IEEE80211_DEVICE_OVERRIDE_SCAN_PROBERESPONSE_IE, /* Override scan Probe response IE, 0: Don't over-ride */ + IEEE80211_DEVICE_2G_CSA, + IEEE80211_DEVICE_PWRTARGET, + IEEE80211_DEVICE_OFF_CHANNEL_SUPPORT, +} ieee80211_device_param; + +typedef enum _ieee80211_param { + IEEE80211_BEACON_INTVAL, /* in TUs */ + IEEE80211_LISTEN_INTVAL, /* number of beacons */ + IEEE80211_DTIM_INTVAL, /* number of beacons */ + IEEE80211_BMISS_COUNT_RESET, /* number of beacon miss intrs before reset */ + IEEE80211_BMISS_COUNT_MAX, /* number of beacon miss intrs for bmiss notificationst */ + IEEE80211_ATIM_WINDOW, /* ATIM window */ + IEEE80211_SHORT_SLOT, /* short slot on/off */ + IEEE80211_SHORT_PREAMBLE, /* short preamble on/off */ + IEEE80211_RTS_THRESHOLD, /* rts threshold, 0 means no rts threshold */ + IEEE80211_FRAG_THRESHOLD, /* fragmentation threshold, 0 means no rts threshold */ + IEEE80211_FIXED_RATE, /* + * rate code series(0: auto rate, 32 bit value: rate + * codes for 4 rate series. each byte for one rate series) + */ + IEEE80211_MCAST_RATE, /* rate in Kbps */ + IEEE80211_TXPOWER, /* in 0.5db units */ + IEEE80211_AMPDU_DENCITY, /* AMPDU dencity */ + IEEE80211_AMPDU_LIMIT, /* AMPDU limit */ + IEEE80211_MAX_AMPDU, /* Max AMPDU Exp */ + IEEE80211_VHT_MAX_AMPDU, /* VHT Max AMPDU Exp */ + IEEE80211_WPS_MODE, /* WPS mode */ + IEEE80211_TSN_MODE, /* TSN mode */ + IEEE80211_MULTI_DOMAIN, /* Multiple domain */ + IEEE80211_SAFE_MODE, /* Safe mode */ + IEEE80211_NOBRIDGE_MODE, /* No bridging done, all frames sent up the stack */ + IEEE80211_PERSTA_KEYTABLE_SIZE, /* IBSS-only, read-only: persta key table size */ + IEEE80211_RECEIVE_80211, /* deliver std 802.11 frames 802.11 instead of ethernet frames on the rx */ + IEEE80211_SEND_80211, /* OS sends std 802.11 frames 802.11 instead of ethernet frames on tx side */ + IEEE80211_MIN_BEACON_COUNT, /* minumum number beacons to tx/rx before vap can pause */ + IEEE80211_IDLE_TIME, /* minimun no activity time before vap can pause */ + IEEE80211_MIN_FRAMESIZE, /* smallest frame size we are allowed to receive */ + /* features. 0:feature is off. 1:feature is on. */ + IEEE80211_FEATURE_WMM, /* WMM */ + IEEE80211_FEATURE_WMM_PWRSAVE, /* WMM Power Save */ + IEEE80211_FEATURE_UAPSD, /* UAPSD setting (BE/BK/VI/VO) */ + IEEE80211_FEATURE_WDS, /* dynamic WDS feature */ + IEEE80211_FEATURE_PRIVACY, /* encryption */ + IEEE80211_FEATURE_DROP_UNENC, /* drop un encrypted frames */ + IEEE80211_FEATURE_COUNTER_MEASURES, /* turn on couter measures */ + IEEE80211_FEATURE_HIDE_SSID, /* turn on hide ssid feature */ + IEEE80211_FEATURE_APBRIDGE, /* turn on internal mcast traffic bridging for AP */ + IEEE80211_FEATURE_PUREB, /* turn on pure B mode for AP */ + IEEE80211_FEATURE_PUREG, /* turn on pure G mode for AP */ + IEEE80211_FEATURE_REGCLASS, /* add regulatory class IE in AP */ + IEEE80211_FEATURE_COUNTRY_IE, /* add country IE for vap in AP */ + IEEE80211_FEATURE_IC_COUNTRY_IE, /* add country IE for ic in AP */ + IEEE80211_FEATURE_DOTH, /* enable 802.11h */ + IEEE80211_FEATURE_PURE11N, /* enable pure 11n mode */ + IEEE80211_FEATURE_PRIVATE_RSNIE, /* enable OS shim to setup RSN IE */ + IEEE80211_FEATURE_COPY_BEACON, /* keep a copy of beacon */ + IEEE80211_FEATURE_PSPOLL, /* enable/disable pspoll mode in power save SM */ + IEEE80211_FEATURE_CONTINUE_PSPOLL_FOR_MOREDATA, /* enable/disable option to contunue sending ps polls when there is more data */ + IEEE80211_FEATURE_AMPDU, /* Enable or Disable Aggregation */ +#ifdef ATH_COALESCING + IEEE80211_FEATURE_TX_COALESCING, /* enable tx coalescing */ +#endif + IEEE80211_FEATURE_VAP_IND, /* Repeater independant VAP */ + IEEE80211_FIXED_RETRIES, /* fixed retries 0-4 */ + IEEE80211_SHORT_GI, /* short gi on/off */ + IEEE80211_HT40_INTOLERANT, + IEEE80211_CHWIDTH, + IEEE80211_CHEXTOFFSET, + IEEE80211_DISABLE_2040COEXIST, + IEEE80211_DISABLE_HTPROTECTION, + IEEE80211_STA_QUICKKICKOUT, + IEEE80211_CHSCANINIT, + IEEE80211_FEATURE_STAFWD, /* dynamic AP Client feature */ + IEEE80211_DRIVER_CAPS, + IEEE80211_UAPSD_MAXSP, /* UAPSD service period setting (0:unlimited, 2,4,6) */ + IEEE80211_WEP_MBSSID, + IEEE80211_MGMT_RATE, /* ieee rate to be used for management */ + IEEE80211_RESMGR_VAP_AIR_TIME_LIMIT, /* When multi-channel enabled, restrict air-time allocated to a VAP */ + IEEE80211_TDLS_MACADDR1, /* Upper 4 bytes of device's MAC address */ + IEEE80211_TDLS_MACADDR2, /* Lower 2 bytes of device's MAC address */ + IEEE80211_TDLS_ACTION, /* TDLS action requested */ + IEEE80211_AUTO_ASSOC, + IEEE80211_PROTECTION_MODE, /* per VAP protection mode */ + IEEE80211_AUTH_INACT_TIMEOUT, /* inactivity time while waiting for 802.11x auth to complete */ + IEEE80211_INIT_INACT_TIMEOUT, /* inactivity time while waiting for 802.11 auth/assoc to complete */ + IEEE80211_RUN_INACT_TIMEOUT, /* inactivity time when fully authed */ + IEEE80211_PROBE_INACT_TIMEOUT, /* inactivity counter value below which starts probing */ + IEEE80211_QBSS_LOAD, + IEEE80211_WNM_CAP, + IEEE80211_WNM_BSS_CAP, + IEEE80211_WNM_TFS_CAP, + IEEE80211_WNM_TIM_CAP, + IEEE80211_WNM_SLEEP_CAP, + IEEE80211_WNM_FMS_CAP, + IEEE80211_AP_REJECT_DFS_CHAN, /* AP to reject resuming on DFS Channel */ + IEEE80211_ABOLT, + IEEE80211_COMP, + IEEE80211_FF, + IEEE80211_TURBO, + IEEE80211_BURST, + IEEE80211_AR, + IEEE80211_SLEEP, + IEEE80211_EOSPDROP, + IEEE80211_MARKDFS, + IEEE80211_WDS_AUTODETECT, + IEEE80211_WEP_TKIP_HT, + IEEE80211_ATH_RADIO, + IEEE80211_IGNORE_11DBEACON, + /* Video debug feature */ + IEEE80211_VI_DBG_CFG, /* Video debug configuration - Bit0- enable dbg, Bit1 - enable stats log */ + IEEE80211_VI_DBG_NUM_STREAMS, /* Total number of receive streams */ + IEEE80211_VI_STREAM_NUM, /* the stream number whose marker parameters are being set */ + IEEE80211_VI_DBG_NUM_MARKERS, /* total number of markers used to filter pkts */ + IEEE80211_VI_MARKER_NUM, /* the marker number whose parameters (offset, size & match) are being set */ + IEEE80211_VI_MARKER_OFFSET_SIZE, /* byte offset from skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_MARKER_MATCH, /* marker pattern match used in filtering */ + IEEE80211_VI_RXSEQ_OFFSET_SIZE, /* Rx Seq num offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RX_SEQ_RSHIFT, /* right-shift value in case field is not word aligned */ + IEEE80211_VI_RX_SEQ_MAX, /* maximum Rx Seq number (to check wrap around) */ + IEEE80211_VI_RX_SEQ_DROP, /* Indicator to the debug app that a particular seq num has been dropped */ + IEEE80211_VI_TIME_OFFSET_SIZE, /* Timestamp offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RESTART, /* If set to 1 resets all internal variables/counters & restarts debug tool */ + IEEE80211_VI_RXDROP_STATUS, /* Total RX drops in wireless */ + IEEE80211_TRIGGER_MLME_RESP, /* Option for App to trigger mlme response */ +#ifdef ATH_SUPPORT_TxBF + IEEE80211_TXBF_AUTO_CVUPDATE, /* auto CV update enable */ + IEEE80211_TXBF_CVUPDATE_PER, /* per threshold to initial CV update */ +#endif + IEEE80211_MAX_CLIENT_NUMBERS, + IEEE80211_SMARTNET, + IEEE80211_FEATURE_MFP_TEST, /* MFP test */ + IEEE80211_WEATHER_RADAR, /* weather radar channel skip */ + IEEE80211_WEP_KEYCACHE, /* WEP KEYCACHE is enable */ + IEEE80211_SEND_DEAUTH, /* send deauth instead of disassoc while doing interface down */ + IEEE80211_SET_TXPWRADJUST, + IEEE80211_RRM_CAP, + IEEE80211_RRM_DEBUG, + IEEE80211_RRM_STATS, + IEEE80211_RRM_SLWINDOW, + IEEE80211_FEATURE_OFF_CHANNEL_SUPPORT, + IEEE80211_FIXED_VHT_MCS, /* VHT mcs index */ + IEEE80211_FIXED_NSS, /* Spatial Streams count */ + IEEE80211_SUPPORT_LDPC, /* LDPC Support */ + IEEE80211_SUPPORT_TX_STBC, /* TX STBC enable/disable */ + IEEE80211_SUPPORT_RX_STBC, /* RX STBC enable/disable */ + IEEE80211_DEFAULT_KEYID, /* XMIT default key */ + IEEE80211_OPMODE_NOTIFY_ENABLE, /* Op mode notification enable/disable */ + IEEE80211_ENABLE_RTSCTS, /* Enable/Disable RTS-CTS */ + IEEE80211_VHT_MCSMAP, /* VHT MCS Map */ + IEEE80211_GET_ACS_STATE, /* get acs state */ + IEEE80211_GET_CAC_STATE, /* get cac state */ +} ieee80211_param; + +#define IEEE80211_PROTECTION_NONE 0 +#define IEEE80211_PROTECTION_CTSTOSELF 1 +#define IEEE80211_PROTECTION_RTS_CTS 2 + +typedef enum _ieee80211_privacy_filter { + IEEE80211_PRIVACY_FILTER_ALLWAYS, + IEEE80211_PRIVACY_FILTER_KEY_UNAVAILABLE, +} ieee80211_privacy_filter; + +typedef enum _ieee80211_privacy_filter_packet_type { + IEEE80211_PRIVACY_FILTER_PACKET_UNICAST, + IEEE80211_PRIVACY_FILTER_PACKET_MULTICAST, + IEEE80211_PRIVACY_FILTER_PACKET_BOTH +} ieee80211_privacy_filter_packet_type; + +typedef struct _ieee80211_privacy_excemption_filter { + uint16_t ether_type; /* type of ethernet to apply this filter, in host byte order */ + ieee80211_privacy_filter filter_type; + ieee80211_privacy_filter_packet_type packet_type; +} ieee80211_privacy_exemption; + +/* + * Authentication mode. + * NB: the usage of auth modes NONE, AUTO are deprecated, + * they are implemented through combinations of other auth modes + * and cipher types. The deprecated values are preserved here to + * maintain binary compatibility with applications like + * wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_auth_mode { + IEEE80211_AUTH_NONE = 0, /* deprecated */ + IEEE80211_AUTH_OPEN = 1, /* open */ + IEEE80211_AUTH_SHARED = 2, /* shared-key */ + IEEE80211_AUTH_8021X = 3, /* 802.1x */ + IEEE80211_AUTH_AUTO = 4, /* deprecated */ + IEEE80211_AUTH_WPA = 5, /* WPA */ + IEEE80211_AUTH_RSNA = 6, /* WPA2/RSNA */ + IEEE80211_AUTH_CCKM = 7, /* CCK */ + IEEE80211_AUTH_WAPI = 8, /* WAPI */ +} ieee80211_auth_mode; + +#define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WAPI+1) + +/* + * Cipher types. + * NB: The values are preserved here to maintain binary compatibility + * with applications like wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_cipher_type { + IEEE80211_CIPHER_WEP = 0, + IEEE80211_CIPHER_TKIP = 1, + IEEE80211_CIPHER_AES_OCB = 2, + IEEE80211_CIPHER_AES_CCM = 3, + IEEE80211_CIPHER_WAPI = 4, + IEEE80211_CIPHER_CKIP = 5, + IEEE80211_CIPHER_AES_CMAC = 6, + IEEE80211_CIPHER_NONE = 7, +} ieee80211_cipher_type; + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1) + +/* key direction */ +typedef enum _ieee80211_key_direction { + IEEE80211_KEY_DIR_TX, + IEEE80211_KEY_DIR_RX, + IEEE80211_KEY_DIR_BOTH +} ieee80211_key_direction; + +#define IEEE80211_KEYIX_NONE ((uint16_t) -1) + +typedef struct _ieee80211_keyval { + ieee80211_cipher_type keytype; + ieee80211_key_direction keydir; + u_int persistent : 1, /* persistent key */ + mfp : 1; /* management frame protection */ + uint16_t keylen; /* length of the key data fields */ + uint8_t *macaddr; /* mac address of length IEEE80211_ADDR_LEN . all bytes are 0xff for multicast key */ + uint64_t keyrsc; + uint64_t keytsc; + uint16_t txmic_offset; /* TKIP/SMS4 only: offset to tx mic key */ + uint16_t rxmic_offset; /* TKIP/SMS4 only: offset to rx mic key */ + uint8_t *keydata; +#ifdef ATH_SUPPORT_WAPI + uint8_t key_used; /*index for WAPI rekey labeling */ +#endif +} ieee80211_keyval; + +#define IEEE80211_AES_CMAC_LEN 128 +typedef enum _ieee80211_rsn_param { + IEEE80211_UCAST_CIPHER_LEN, + IEEE80211_MCAST_CIPHER_LEN, + IEEE80211_MCASTMGMT_CIPHER_LEN, + IEEE80211_KEYMGT_ALGS, + IEEE80211_RSN_CAPS +} ieee80211_rsn_param; + +#define IEEE80211_PMKID_LEN 16 + +typedef struct _ieee80211_pmkid_entry { + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t pmkid[IEEE80211_PMKID_LEN]; +} ieee80211_pmkid_entry; + +typedef enum _wlan_wme_param { + WLAN_WME_CWMIN, + WLAN_WME_CWMAX, + WLAN_WME_AIFS, + WLAN_WME_TXOPLIMIT, + WLAN_WME_ACM, /*bss only */ + WLAN_WME_ACKPOLICY /*bss only */ +} wlan_wme_param; + +typedef enum _ieee80211_frame_type { + IEEE80211_FRAME_TYPE_PROBEREQ, + IEEE80211_FRAME_TYPE_BEACON, + IEEE80211_FRAME_TYPE_PROBERESP, + IEEE80211_FRAME_TYPE_ASSOCREQ, + IEEE80211_FRAME_TYPE_ASSOCRESP, + IEEE80211_FRAME_TYPE_AUTH +} ieee80211_frame_type; + +#define IEEE80211_FRAME_TYPE_MAX (IEEE80211_FRAME_TYPE_AUTH+1) + +typedef enum _ieee80211_ampdu_mode { + IEEE80211_AMPDU_MODE_OFF, /* disable AMPDU */ + IEEE80211_AMPDU_MODE_ON, /* enable AMPDU */ + IEEE80211_AMPDU_MODE_WDSVAR /* enable AMPDU with 4addr WAR */ +} ieee80211_ampdu_mode; + +typedef enum _ieee80211_reset_type { + IEEE80211_RESET_TYPE_DEVICE = 0, /* device reset on error: tx timeout and etc. */ + IEEE80211_RESET_TYPE_DOT11_INTF, /* dot11 reset: only reset one network interface (vap) */ + IEEE80211_RESET_TYPE_INTERNAL, /* internal reset */ +} ieee80211_reset_type; + +typedef struct _ieee80211_reset_request { + ieee80211_reset_type type; + + u_int reset_hw : 1, /* reset the actual H/W */ + /* + * The following fields are only valid for DOT11 reset, i.e., + * IEEE80211_RESET_TYPE_DOT11_INTF + */ + reset_phy : 1, /* reset PHY */ + reset_mac : 1, /* reset MAC */ + set_default_mib : 1, /* set default MIB variables */ + no_flush : 1; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + enum ieee80211_phymode phy_mode; +} ieee80211_reset_request; + +#define IEEE80211_MSG_MAX 63 +#define IEEE80211_MSG_SMARTANT 7 /* Bit 7 (0x80)for Smart Antenna debug */ +enum { + /* IEEE80211_PARAM_DBG_LVL */ + IEEE80211_MSG_TDLS = 0, /* TDLS */ + IEEE80211_MSG_ACS, /* auto channel selection */ + IEEE80211_MSG_SCAN_SM, /* scan state machine */ + IEEE80211_MSG_SCANENTRY, /* scan entry */ + IEEE80211_MSG_WDS, /* WDS handling */ + IEEE80211_MSG_ACTION, /* action management frames */ + IEEE80211_MSG_ROAM, /* sta-mode roaming */ + IEEE80211_MSG_INACT, /* inactivity handling */ + IEEE80211_MSG_DOTH = 8, /* 11.h */ + IEEE80211_MSG_IQUE, /* IQUE features */ + IEEE80211_MSG_WME, /* WME protocol */ + IEEE80211_MSG_ACL, /* ACL handling */ + IEEE80211_MSG_WPA, /* WPA/RSN protocol */ + IEEE80211_MSG_RADKEYS, /* dump 802.1x keys */ + IEEE80211_MSG_RADDUMP, /* dump 802.1x radius packets */ + IEEE80211_MSG_RADIUS, /* 802.1x radius client */ + IEEE80211_MSG_DOT1XSM = 16, /* 802.1x state machine */ + IEEE80211_MSG_DOT1X, /* 802.1x authenticator */ + IEEE80211_MSG_POWER, /* power save handling */ + IEEE80211_MSG_STATE, /* state machine */ + IEEE80211_MSG_OUTPUT, /* output handling */ + IEEE80211_MSG_SCAN, /* scanning */ + IEEE80211_MSG_AUTH, /* authentication handling */ + IEEE80211_MSG_ASSOC, /* association handling */ + IEEE80211_MSG_NODE = 24, /* node handling */ + IEEE80211_MSG_ELEMID, /* element id parsing */ + IEEE80211_MSG_XRATE, /* rate set handling */ + IEEE80211_MSG_INPUT, /* input handling */ + IEEE80211_MSG_CRYPTO, /* crypto work */ + IEEE80211_MSG_DUMPPKTS, /* IFF_LINK2 equivalant */ + IEEE80211_MSG_DEBUG, /* IFF_DEBUG equivalent */ + IEEE80211_MSG_MLME, /* MLME */ + /* IEEE80211_PARAM_DBG_LVL_HIGH */ + IEEE80211_MSG_RRM = 32, /* Radio resource measurement */ + IEEE80211_MSG_WNM, /* Wireless Network Management */ + IEEE80211_MSG_P2P_PROT, /* P2P Protocol driver */ + IEEE80211_MSG_PROXYARP, /* 11v Proxy ARP */ + IEEE80211_MSG_L2TIF, /* Hotspot 2.0 L2 TIF */ + IEEE80211_MSG_WIFIPOS, /* WifiPositioning Feature */ + IEEE80211_MSG_WRAP, /* WRAP or Wireless ProxySTA */ + IEEE80211_MSG_DFS, /* DFS debug mesg */ + + IEEE80211_MSG_NUM_CATEGORIES, /* total ieee80211 messages */ + IEEE80211_MSG_UNMASKABLE = IEEE80211_MSG_MAX, /* anything */ + IEEE80211_MSG_ANY = IEEE80211_MSG_MAX, /* anything */ +}; + +/* verbosity levels */ +#define IEEE80211_VERBOSE_OFF 100 +#define IEEE80211_VERBOSE_FORCE 1 +#define IEEE80211_VERBOSE_SERIOUS 2 +#define IEEE80211_VERBOSE_NORMAL 3 +#define IEEE80211_VERBOSE_LOUD 4 +#define IEEE80211_VERBOSE_DETAILED 5 +#define IEEE80211_VERBOSE_COMPLEX 6 +#define IEEE80211_VERBOSE_FUNCTION 7 +#define IEEE80211_VERBOSE_TRACE 8 + +#define IEEE80211_DEBUG_DEFAULT IEEE80211_MSG_DEBUG + +/* + * the lower 4 bits of the msg flags are used for extending the + * debug flags. + */ + +/* + * flag defintions for wlan_mlme_stop_bss(vap) API. + */ +#define WLAN_MLME_STOP_BSS_F_SEND_DEAUTH 0x01 +#define WLAN_MLME_STOP_BSS_F_CLEAR_ASSOC_STATE 0x02 +#define WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET 0x04 +#define WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE 0x08 +#define WLAN_MLME_STOP_BSS_F_NO_RESET 0x10 +#define WLAN_MLME_STOP_BSS_F_STANDBY 0x20 + +/* + * WAPI commands to authenticator + */ +#define WAPI_WAI_REQUEST (uint16_t)0x00F1 +#define WAPI_UNICAST_REKEY (uint16_t)0x00F2 +#define WAPI_STA_AGING (uint16_t)0x00F3 +#define WAPI_MULTI_REKEY (uint16_t)0x00F4 +#define WAPI_STA_STATS (uint16_t)0x00F5 + +/* + * IEEE80211 PHY Statistics. + */ +struct ieee80211_phy_stats { + uint64_t ips_tx_packets; /* frames successfully transmitted */ + uint64_t ips_tx_multicast; /* multicast/broadcast frames successfully transmitted */ + uint64_t ips_tx_fragments; /* fragments successfully transmitted */ + uint64_t ips_tx_xretries; /* frames that are xretried. NB: not number of retries */ + uint64_t ips_tx_retries; /* frames transmitted after retries. NB: not number of retries */ + uint64_t ips_tx_multiretries; /* frames transmitted after more than one retry. */ + uint64_t ips_tx_timeout; /* frames that expire the dot11MaxTransmitMSDULifetime */ + uint64_t ips_rx_packets; /* frames successfully received */ + uint64_t ips_rx_multicast; /* multicast/broadcast frames successfully received */ + uint64_t ips_rx_fragments; /* fragments successfully received */ + uint64_t ips_rx_timeout; /* frmaes that expired the dot11MaxReceiveLifetime */ + uint64_t ips_rx_dup; /* duplicated fragments */ + uint64_t ips_rx_mdup; /* multiple duplicated fragments */ + uint64_t ips_rx_promiscuous; /* frames that are received only because promiscuous filter is on */ + uint64_t ips_rx_promiscuous_fragments; /* fragments that are received only because promiscuous filter is on */ + uint64_t ips_tx_rts; /* RTS success count */ + uint64_t ips_tx_shortretry; /* tx on-chip retries (short). RTSFailCnt */ + uint64_t ips_tx_longretry; /* tx on-chip retries (long). DataFailCnt */ + uint64_t ips_rx_crcerr; /* rx failed 'cuz of bad CRC */ + uint64_t ips_rx_fifoerr; /* rx failed 'cuz of FIFO overrun */ + uint64_t ips_rx_decrypterr; /* rx decryption error */ +}; + +struct ieee80211_chan_stats { + uint32_t chan_clr_cnt; + uint32_t cycle_cnt; + uint32_t phy_err_cnt; +}; + +struct ieee80211_mac_stats { + uint64_t ims_tx_packets; /* frames successfully transmitted */ + uint64_t ims_rx_packets; /* frames successfully received */ + uint64_t ims_tx_bytes; /* bytes successfully transmitted */ + uint64_t ims_rx_bytes; /* bytes successfully received */ + + /* TODO: For the byte counts below, we need to handle some scenarios + such as encryption related decaps, etc */ + uint64_t ims_tx_data_packets; /* data frames successfully transmitted */ + uint64_t ims_rx_data_packets; /* data frames successfully received */ + uint64_t ims_tx_data_bytes; /* data bytes successfully transmitted, + inclusive of FCS. */ + uint64_t ims_rx_data_bytes; /* data bytes successfully received, + inclusive of FCS. */ + + uint64_t ims_tx_datapyld_bytes; /* data payload bytes successfully + transmitted */ + uint64_t ims_rx_datapyld_bytes; /* data payload successfully + received */ + + /* Decryption errors */ + uint64_t ims_rx_unencrypted; /* rx w/o wep and privacy on */ + uint64_t ims_rx_badkeyid; /* rx w/ incorrect keyid */ + uint64_t ims_rx_decryptok; /* rx decrypt okay */ + uint64_t ims_rx_decryptcrc; /* rx decrypt failed on crc */ + uint64_t ims_rx_wepfail; /* rx wep processing failed */ + uint64_t ims_rx_tkipreplay; /* rx seq# violation (TKIP) */ + uint64_t ims_rx_tkipformat; /* rx format bad (TKIP) */ + uint64_t ims_rx_tkipmic; /* rx MIC check failed (TKIP) */ + uint64_t ims_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint64_t ims_rx_ccmpreplay; /* rx seq# violation (CCMP) */ + uint64_t ims_rx_ccmpformat; /* rx format bad (CCMP) */ + uint64_t ims_rx_ccmpmic; /* rx MIC check failed (CCMP) */ +/*this file can be included by applications as 80211stats that has no such MACRO definition*/ +/* #if ATH_SUPPORT_WAPI */ + uint64_t ims_rx_wpireplay; /* rx seq# violation (WPI) */ + uint64_t ims_rx_wpimic; /* rx MIC check failed (WPI) */ +/* #endif */ + /* Other Tx/Rx errors */ + uint64_t ims_tx_discard; /* tx dropped by NIC */ + uint64_t ims_rx_discard; /* rx dropped by NIC */ + + uint64_t ims_rx_countermeasure; /* rx TKIP countermeasure activation count */ +}; + +/* + * Summary statistics. + */ +struct ieee80211_stats { + uint32_t is_rx_badversion; /* rx frame with bad version */ + uint32_t is_rx_tooshort; /* rx frame too short */ + uint32_t is_rx_wrongbss; /* rx from wrong bssid */ + uint32_t is_rx_wrongdir; /* rx w/ wrong direction */ + uint32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */ + uint32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */ + uint32_t is_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t is_rx_decap; /* rx decapsulation failed */ + uint32_t is_rx_mgtdiscard; /* rx discard mgt frames */ + uint32_t is_rx_ctl; /* rx discard ctrl frames */ + uint32_t is_rx_beacon; /* rx beacon frames */ + uint32_t is_rx_rstoobig; /* rx rate set truncated */ + uint32_t is_rx_elem_missing; /* rx required element missing */ + uint32_t is_rx_elem_toobig; /* rx element too big */ + uint32_t is_rx_elem_toosmall; /* rx element too small */ + uint32_t is_rx_elem_unknown; /* rx element unknown */ + uint32_t is_rx_badchan; /* rx frame w/ invalid chan */ + uint32_t is_rx_chanmismatch; /* rx frame chan mismatch */ + uint32_t is_rx_nodealloc; /* rx frame dropped */ + uint32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */ + uint32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */ + uint32_t is_rx_auth_fail; /* rx sta auth failure */ + uint32_t is_rx_auth_countermeasures; /* rx auth discard 'cuz CM */ + uint32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */ + uint32_t is_rx_assoc_notauth; /* rx assoc w/o auth */ + uint32_t is_rx_assoc_capmismatch; /* rx assoc w/ cap mismatch */ + uint32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */ + uint32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */ + uint32_t is_rx_deauth; /* rx deauthentication */ + uint32_t is_rx_disassoc; /* rx disassociation */ + uint32_t is_rx_action; /* rx action mgt */ + uint32_t is_rx_badsubtype; /* rx frame w/ unknown subtype */ + uint32_t is_rx_nobuf; /* rx failed for lack of buf */ + uint32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame */ + uint32_t is_rx_bad_auth; /* rx bad auth request */ + uint32_t is_rx_unauth; /* rx on unauthorized port */ + uint32_t is_rx_badcipher; /* rx failed 'cuz key type */ + uint32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */ + uint32_t is_tx_noheadroom; /* tx failed 'cuz no space */ + uint32_t is_rx_nocipherctx; /* rx failed 'cuz key !setup */ + uint32_t is_rx_acl; /* rx discard 'cuz acl policy */ + uint32_t is_rx_ffcnt; /* rx fast frames */ + uint32_t is_rx_badathtnl; /* driver key alloc failed */ + uint32_t is_rx_nowds; /* 4-addr packets received with no wds enabled */ + uint32_t is_tx_nobuf; /* tx failed for lack of buf */ + uint32_t is_tx_nonode; /* tx failed for no node */ + uint32_t is_tx_unknownmgt; /* tx of unknown mgt frame */ + uint32_t is_tx_badcipher; /* tx failed 'cuz key type */ + uint32_t is_tx_ffokcnt; /* tx fast frames sent success */ + uint32_t is_tx_fferrcnt; /* tx fast frames sent success */ + uint32_t is_scan_active; /* active scans started */ + uint32_t is_scan_passive; /* passive scans started */ + uint32_t is_node_timeout; /* nodes timed out inactivity */ + uint32_t is_crypto_nomem; /* no memory for crypto ctx */ + uint32_t is_crypto_tkip; /* tkip crypto done in s/w */ + uint32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */ + uint32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */ + uint32_t is_crypto_tkipcm; /* tkip counter measures */ + uint32_t is_crypto_ccmp; /* ccmp crypto done in s/w */ + uint32_t is_crypto_wep; /* wep crypto done in s/w */ + uint32_t is_crypto_setkey_cipher; /* cipher rejected key */ + uint32_t is_crypto_setkey_nokey; /* no key index for setkey */ + uint32_t is_crypto_delkey; /* driver key delete failed */ + uint32_t is_crypto_badcipher; /* unknown cipher */ + uint32_t is_crypto_nocipher; /* cipher not available */ + uint32_t is_crypto_attachfail; /* cipher attach failed */ + uint32_t is_crypto_swfallback; /* cipher fallback to s/w */ + uint32_t is_crypto_keyfail; /* driver key alloc failed */ + uint32_t is_crypto_enmicfail; /* en-MIC failed */ + uint32_t is_ibss_capmismatch; /* merge failed-cap mismatch */ + uint32_t is_ibss_norate; /* merge failed-rate mismatch */ + uint32_t is_ps_unassoc; /* ps-poll for unassoc. sta */ + uint32_t is_ps_badaid; /* ps-poll w/ incorrect aid */ + uint32_t is_ps_qempty; /* ps-poll w/ nothing to send */ +}; + +typedef enum _ieee80211_send_frame_type { + IEEE80211_SEND_NULL, + IEEE80211_SEND_QOSNULL, +} ieee80211_send_frame_type; + +typedef struct _ieee80211_tspec_info { + uint8_t traffic_type; + uint8_t direction; + uint8_t dot1Dtag; + uint8_t tid; + uint8_t acc_policy_edca; + uint8_t acc_policy_hcca; + uint8_t aggregation; + uint8_t psb; + uint8_t ack_policy; + uint16_t norminal_msdu_size; + uint16_t max_msdu_size; + uint32_t min_srv_interval; + uint32_t max_srv_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t srv_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw; + uint16_t medium_time; +} ieee80211_tspec_info; + +#ifndef EXTERNAL_USE_ONLY +/* + * Manual ADDBA support + */ +enum { + ADDBA_SEND = 0, + ADDBA_STATUS = 1, + DELBA_SEND = 2, + ADDBA_RESP = 3, + ADDBA_CLR_RESP = 4, + SINGLE_AMSDU = 5, +}; + +enum { + ADDBA_MODE_AUTO = 0, + ADDBA_MODE_MANUAL = 1, +}; + +struct ieee80211_addba_delba_request { + wlan_dev_t ic; + uint8_t action; + uint8_t tid; + uint16_t status; + uint16_t aid; + uint32_t arg1; + uint32_t arg2; +}; +#endif /* EXTERNAL_USE_ONLY */ + +#ifdef ATH_BT_COEX +typedef enum _ieee80211_bt_coex_info_type { + IEEE80211_BT_COEX_INFO_SCHEME = 0, + IEEE80211_BT_COEX_INFO_BTBUSY = 1, +} ieee80211_bt_coex_info_type; +#endif + +struct tkip_countermeasure { + uint16_t mic_count_in_60s; + uint32_t timestamp; +}; + +enum _ieee80211_qos_frame_direction { + IEEE80211_RX_QOS_FRAME = 0, + IEEE80211_TX_QOS_FRAME = 1, + IEEE80211_TX_COMPLETE_QOS_FRAME = 2 +}; + +typedef struct ieee80211_vap_opmode_count { + int total_vaps; + int ibss_count; + int sta_count; + int wds_count; + int ahdemo_count; + int ap_count; + int monitor_count; + int btamp_count; + int unknown_count; +} ieee80211_vap_opmode_count; + +struct ieee80211_app_ie_t { + uint32_t length; + uint8_t *ie; +}; + +/* + * MAC ACL operations. + */ +enum { + IEEE80211_MACCMD_POLICY_OPEN = 0, /* set policy: no ACL's */ + IEEE80211_MACCMD_POLICY_ALLOW = 1, /* set policy: allow traffic */ + IEEE80211_MACCMD_POLICY_DENY = 2, /* set policy: deny traffic */ + IEEE80211_MACCMD_FLUSH = 3, /* flush ACL database */ + IEEE80211_MACCMD_DETACH = 4, /* detach ACL policy */ + IEEE80211_MACCMD_POLICY_RADIUS = 5, /* set policy: RADIUS managed ACLs */ +}; + +#endif diff --git a/core/cds/inc/cds_if_upperproto.h b/core/cds/inc/cds_if_upperproto.h new file mode 100644 index 0000000000..072c6bca2e --- /dev/null +++ b/core/cds/inc/cds_if_upperproto.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* #ifndef _NET_IF_ETHERSUBR_H_ */ +/* #define _NET_IF_ETHERSUBR_H_ */ +#ifndef _NET_IF_UPPERPROTO_H_ +#define _NET_IF_UPPERPROTO_H_ + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHER_TYPE_LEN 2 /* length of the Ethernet type field */ +#define ETHER_CRC_LEN 4 /* length of the Ethernet CRC */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) +#define ETHER_MAX_LEN 1518 + +#define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +/* + * Structure of a 10Mb/s Ethernet header. + */ +#ifndef _NET_ETHERNET_H_ +struct ether_header { + uint8_t ether_dhost[ETHER_ADDR_LEN]; + uint8_t ether_shost[ETHER_ADDR_LEN]; + uint16_t ether_type; +} __packed; +#endif + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 /* Appletalk AARP protocol */ +#endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 /* IPX over DIX protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* ARP protocol */ +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd /* IPv6 */ +#endif +#ifndef ETHERTYPE_8021Q +#define ETHERTYPE_8021Q 0x8100 /* 802.1Q vlan protocol */ +#endif +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* VLAN TAG protocol */ +#endif +#ifndef TX_QUEUE_FOR_EAPOL_FRAME +#define TX_QUEUE_FOR_EAPOL_FRAME 0x7 /* queue eapol frame to queue 7 to avoid aggregation disorder */ +#endif + +/* + * define WAI ethertype + */ +#ifndef ETHERTYPE_WAI +#define ETHERTYPE_WAI 0x88b4 /* WAI/WAPI */ +#endif + +#define ETHERTYPE_OCB_TX 0x8151 +#define ETHERTYPE_OCB_RX 0x8152 + +/* + * Structure of a 48-bit Ethernet address. + */ +#if 0 +#ifndef _NET_ETHERNET_H_ +struct ether_addr { + uint8_t octet[ETHER_ADDR_LEN]; +} __packed; +#endif +#endif + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ +#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ + +/* + * Structure of the IP frame + */ +struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /*The options start here. */ +}; +#ifndef IP_PROTO_TCP +#define IP_PROTO_TCP 0x6 /* TCP protocol */ +#endif +#ifndef IP_PROTO_UDP +#define IP_PROTO_UDP 17 +#endif + +/* + * IGMP protocol structures + */ + +/* IGMP record type */ +#define IGMP_QUERY_TYPE 0x11 +#define IGMPV1_REPORT_TYPE 0x12 +#define IGMPV2_REPORT_TYPE 0x16 +#define IGMPV2_LEAVE_TYPE 0x17 +#define IGMPV3_REPORT_TYPE 0x22 + +/* Is packet type is either leave or report */ +#define IS_IGMP_REPORT_LEAVE_PACKET(type) ( \ + (IGMPV1_REPORT_TYPE == type) \ + || (IGMPV2_REPORT_TYPE == type) \ + || (IGMPV2_LEAVE_TYPE == type) \ + || (IGMPV3_REPORT_TYPE == type) \ + ) +/* + * Header in on cable format + */ + +struct igmp_header { + uint8_t type; + uint8_t code; /* For newer IGMP */ + uint16_t csum; + uint32_t group; +}; + +/* V3 group record types [grec_type] */ +#define IGMPV3_MODE_IS_INCLUDE 1 +#define IGMPV3_MODE_IS_EXCLUDE 2 +#define IGMPV3_CHANGE_TO_INCLUDE 3 +#define IGMPV3_CHANGE_TO_EXCLUDE 4 +#define IGMPV3_ALLOW_NEW_SOURCES 5 +#define IGMPV3_BLOCK_OLD_SOURCES 6 + +/* Group record format + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Type | Aux Data Len | Number of Sources (N) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Multicast Address | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Address [1] | + ||+- -+ + | Source Address [2] | + ||+- -+ + . . . + . . . + . . . + ||+- -+ + | Source Address [N] | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Auxiliary Data . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_grec { + uint8_t grec_type; + uint8_t grec_auxwords; + uint16_t grec_nsrcs; + uint32_t grec_mca; +}; + +/* IGMPv3 report format + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type = 0x22 | Reserved | Checksum | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reserved | Number of Group Records (M) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [1] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [2] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | . | + . . . + | . | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [M] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_report { + uint8_t type; + uint8_t resv1; + uint16_t csum; + uint16_t resv2; + uint16_t ngrec; +}; + +/* Calculate the group record length*/ +#define IGMPV3_GRP_REC_LEN(x) (8 + (4 * x->grec_nsrcs) + (4 * x->grec_auxwords) ) + +#endif /* _NET_IF_ETHERSUBR_H_ */ diff --git a/core/cds/inc/cds_mq.h b/core/cds/inc/cds_mq.h new file mode 100644 index 0000000000..8f76bee224 --- /dev/null +++ b/core/cds/inc/cds_mq.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_MQ_H ) +#define __CDS_MQ_H + +/**========================================================================= + + \file cds_mq.h + + \brief virtual Operating System Services (CDF) message queue APIs + + Message Queue Definitions and API + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/* cds Message Type. + This represnets a message that can be posted to another module through + the cds Message Queues. + \note This is mapped directly to the tSirMsgQ for backward + compatibility with the legacy MAC code */ + +typedef struct cds_msg_s { + uint16_t type; + /* + * This field can be used as sequence number/dialog token for matching + * requests and responses. + */ + uint16_t reserved; + /** + * Based on the type either a bodyptr pointer into + * memory or bodyval as a 32 bit data is used. + * bodyptr: is always a freeable pointer, one should always + * make sure that bodyptr is always freeable. + * + * Messages should use either bodyptr or bodyval; not both !!!. + */ + void *bodyptr; + + uint32_t bodyval; + + /* + * Some messages provide a callback function. The function signature + * must be agreed upon between the two entities exchanging the message + */ + void *callback; + +} cds_msg_t; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/* Message Queue IDs */ +typedef enum { + /* Message Queue ID for messages bound for SME */ + CDS_MQ_ID_SME = CDF_MODULE_ID_SME, + + /* Message Queue ID for messages bound for PE */ + CDS_MQ_ID_PE = CDF_MODULE_ID_PE, + + /* Message Queue ID for messages bound for WMA */ + CDS_MQ_ID_WMA = CDF_MODULE_ID_WMA, + + /* Message Queue ID for messages bound for the SYS module */ + CDS_MQ_ID_SYS = CDF_MODULE_ID_SYS, + +} CDS_MQ_ID; + +/**--------------------------------------------------------------------------- + + \brief cds_mq_post_message() - post a message to a message queue + + This API allows messages to be posted to a specific message queue. Messages + can be posted to the following message queues: + +
    +
  • SME +
  • PE +
  • HAL +
  • TL +
+ + \param msgQueueId - identifies the message queue upon which the message + will be posted. + + \param message - a pointer to a message buffer. Memory for this message + buffer is allocated by the caller and free'd by the CDF after the + message is posted to the message queue. If the consumer of the + message needs anything in this message, it needs to copy the contents + before returning from the message queue handler. + + \return CDF_STATUS_SUCCESS - the message has been successfully posted + to the message queue. + + CDF_STATUS_E_INVAL - The value specified by msgQueueId does not + refer to a valid Message Queue Id. + + CDF_STATUS_E_FAULT - message is an invalid pointer. + + CDF_STATUS_E_FAILURE - the message queue handler has reported + an unknown failure. + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS cds_mq_post_message(CDS_MQ_ID msgQueueId, cds_msg_t *message); + +/**--------------------------------------------------------------------------- + + \brief cds_send_mb_message_to_mac() - post a message to a message queue + + \param pBuf is a buffer allocated by caller. The actual structure varies + base on message type + + \return CDF_STATUS_SUCCESS - the message has been successfully posted + to the message queue. + + CDF_STATUS_E_FAILURE - the message queue handler has reported + an unknown failure. + + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS cds_send_mb_message_to_mac(void *pBuf); + +#endif /* if !defined __CDS_MQ_H */ diff --git a/core/cds/inc/cds_pack_align.h b/core/cds/inc/cds_pack_align.h new file mode 100644 index 0000000000..f213115d2c --- /dev/null +++ b/core/cds/inc/cds_pack_align.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_PACK_ALIGN_H ) +#define __CDS_PACK_ALIGN_H + +/**========================================================================= + + \file cds_pack_align.h + + \brief Connectivity driver services (CDS) pack and align primitives + + Definitions for platform independent means of packing and aligning + data structures + + ========================================================================*/ + +/* + + Place the macro CDS_PACK_START above a structure declaration to pack. We + are not going to allow modifying the pack size because pack size cannot be + specified in AMSS and GNU. Place the macro CDS_PACK_END below a structure + declaration to stop the pack. This requirement is necessitated by Windows + which need pragma based prolog and epilog. + + Pack-size > 1-byte is not supported since gcc and arm do not support that. + + Here are some examples + + 1. Pack-size 1-byte foo_t across all platforms + + CDS_PACK_START + typedef CDS_PACK_PRE struct foo_s { ... } CDS_PACK_POST foo_t; + CDS_PACK_END + + 2. 2-byte alignment for foo_t across all platforms + + typedef CDS_ALIGN_PRE(2) struct foo_s { ... } CDS_ALIGN_POST(2) foo_t; + + 3. Pack-size 1-byte and 2-byte alignment for foo_t across all platforms + + CDS_PACK_START + typedef CDS_PACK_PRE CDS_ALIGN_PRE(2) struct foo_s { ... } CDS_ALIGN_POST(2) CDS_PACK_POST foo_t; + CDS_PACK_END + + */ + +#if defined __GNUC__ + +#define CDS_PACK_START +#define CDS_PACK_END + +#define CDS_PACK_PRE +#define CDS_PACK_POST __attribute__((__packed__)) + +#define CDS_ALIGN_PRE(__value) +#define CDS_ALIGN_POST(__value) __attribute__((__aligned__(__value))) + +#elif defined __arm + +#define CDS_PACK_START +#define CDS_PACK_END + +#define CDS_PACK_PRE __packed +#define CDS_PACK_POST + +#define CDS_ALIGN_PRE(__value) __align(__value) +#define CDS_ALIGN_POST(__value) + +#elif defined _MSC_VER + +#define CDS_PACK_START __pragma(pack(push,1)) +#define CDS_PACK_END __pragma(pack(pop)) + +#define CDS_PACK_PRE +#define CDS_PACK_POST + +#define CDS_ALIGN_PRE(__value) __declspec(align(__value)) +#define CDS_ALIGN_POST(__value) + +#else + +#error Unsupported compiler!!! + +#endif + +#endif /* __CDS_PACK_ALIGN_H */ diff --git a/core/cds/inc/cds_packet.h b/core/cds/inc/cds_packet.h new file mode 100644 index 0000000000..f3a87d3e64 --- /dev/null +++ b/core/cds/inc/cds_packet.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_PKT_H ) +#define __CDS_PKT_H + +/**========================================================================= + + \file cds_packet.h + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +struct cds_pkt_t; +typedef struct cds_pkt_t cds_pkt_t; + +#include "cdf_nbuf.h" + +#define CDS_PKT_TRAC_TYPE_EAPOL NBUF_PKT_TRAC_TYPE_EAPOL +#define CDS_PKT_TRAC_TYPE_DHCP NBUF_PKT_TRAC_TYPE_DHCP +#define CDS_PKT_TRAC_TYPE_MGMT_ACTION NBUF_PKT_TRAC_TYPE_MGMT_ACTION /* Managment action frame */ + +#define CDS_PKT_TRAC_DUMP_CMD 9999 + +/*--------------------------------------------------------------------------- + +* brief cds_pkt_get_proto_type() - + Find protoco type from packet contents + +* skb Packet Pointer +* tracking_map packet type want to track +* dot11_type, frame type when the frame is in dot11 format + + ---------------------------------------------------------------------------*/ +uint8_t cds_pkt_get_proto_type + (struct sk_buff *skb, uint8_t tracking_map, uint8_t dot11_type); + +#ifdef QCA_PKT_PROTO_TRACE +/*--------------------------------------------------------------------------- + +* brief cds_pkt_trace_buf_update() - + Update storage buffer with interest event string + +* event_string Event String may packet type or outstanding event + + ---------------------------------------------------------------------------*/ +void cds_pkt_trace_buf_update(char *event_string); + +/*--------------------------------------------------------------------------- + +* brief cds_pkt_trace_buf_dump() - + Dump stored information into kernel log + + ---------------------------------------------------------------------------*/ +void cds_pkt_trace_buf_dump(void); + +/*--------------------------------------------------------------------------- + +* brief cds_pkt_proto_trace_init() - + Initialize protocol trace functionality, allocate required resource + + ---------------------------------------------------------------------------*/ +void cds_pkt_proto_trace_init(void); + +/*--------------------------------------------------------------------------- + +* brief cds_pkt_proto_trace_close() - + Free required resource + + ---------------------------------------------------------------------------*/ +void cds_pkt_proto_trace_close(void); +#endif /* QCA_PKT_PROTO_TRACE */ + +/** + * cds_pkt_return_packet Free the cds Packet + * @ cds Packet + */ +CDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet); + +/** + * cds_pkt_get_packet_length Returns the packet length + * @ cds Packet + */ +CDF_STATUS cds_pkt_get_packet_length(cds_pkt_t *pPacket, + uint16_t *pPacketSize); + +/* + * TODO: Remove later + * All the below difinitions are not + * required for Host Driver 2.0 + * once corresponding references are removed + * from HDD and other layers + * below code will be removed + */ +/* The size of AMSDU frame per spec can be a max of 3839 bytes + in BD/PDUs that means 30 (one BD = 128 bytes) + we must add the size of the 802.11 header to that */ +#define CDS_PKT_SIZE_BUFFER ((30 * 128) + 32) + +/* cds Packet Types */ +typedef enum { + /* cds Packet is used to transmit 802.11 Management frames. */ + CDS_PKT_TYPE_TX_802_11_MGMT, + + /* cds Packet is used to transmit 802.11 Data frames. */ + CDS_PKT_TYPE_TX_802_11_DATA, + + /* cds Packet is used to transmit 802.3 Data frames. */ + CDS_PKT_TYPE_TX_802_3_DATA, + + /* cds Packet contains Received data of an unknown frame type */ + CDS_PKT_TYPE_RX_RAW, + + /* Invalid sentinel value */ + CDS_PKT_TYPE_MAXIMUM +} CDS_PKT_TYPE; + +/* user IDs. These IDs are needed on the cds_pkt_get/set_user_data_ptr() + to identify the user area in the cds Packet. */ +typedef enum { + CDS_PKT_USER_DATA_ID_TL = 0, + CDS_PKT_USER_DATA_ID_BAL, + CDS_PKT_USER_DATA_ID_WMA, + CDS_PKT_USER_DATA_ID_HDD, + CDS_PKT_USER_DATA_ID_BSL, + + CDS_PKT_USER_DATA_ID_MAX +} CDS_PKT_USER_DATA_ID; + +#ifdef MEMORY_DEBUG +#define cds_packet_alloc(s, d, p) \ + cds_packet_alloc_debug(s, d, p, __FILE__, __LINE__) + +CDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_name, uint32_t line_num); +#else +CDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket); +#endif + +void cds_packet_free(void *pPacket); + +typedef CDF_STATUS (*cds_pkt_get_packet_callback)(cds_pkt_t *pPacket, + void *userData); + +#endif /* !defined( __CDS_PKT_H ) */ diff --git a/core/cds/inc/cds_queue.h b/core/cds/inc/cds_queue.h new file mode 100644 index 0000000000..030ff2536d --- /dev/null +++ b/core/cds/inc/cds_queue.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _CDS_QUEUE_H +#define _CDS_QUEUE_H + +#include /* include BSD queue */ + +#endif /* end of _CDS_QUEUE_H */ diff --git a/core/cds/inc/cds_reg_service.h b/core/cds/inc/cds_reg_service.h new file mode 100644 index 0000000000..02a6965c5c --- /dev/null +++ b/core/cds/inc/cds_reg_service.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined __CDS_REG_SERVICE_H +#define __CDS_REG_SERVICE_H + +/**========================================================================= + + \file cds_reg_service.h + + \brief Connectivity driver services (CDS): Non-Volatile storage API + + ========================================================================*/ + +#include "cdf_status.h" + +#define CDS_COUNTRY_CODE_LEN 2 +#define CDS_MAC_ADDRESS_LEN 6 + +typedef enum { + REGDOMAIN_FCC, + REGDOMAIN_ETSI, + REGDOMAIN_JAPAN, + REGDOMAIN_WORLD, + REGDOMAIN_COUNT +} v_REGDOMAIN_t; + +typedef enum { + /* 2.4GHz Band */ + RF_CHAN_1 = 0, + RF_CHAN_2, + RF_CHAN_3, + RF_CHAN_4, + RF_CHAN_5, + RF_CHAN_6, + RF_CHAN_7, + RF_CHAN_8, + RF_CHAN_9, + RF_CHAN_10, + RF_CHAN_11, + RF_CHAN_12, + RF_CHAN_13, + RF_CHAN_14, + + /* 4.9GHz Band */ + RF_CHAN_240, + RF_CHAN_244, + RF_CHAN_248, + RF_CHAN_252, + RF_CHAN_208, + RF_CHAN_212, + RF_CHAN_216, + + /* 5GHz Low & Mid U-NII Band */ + RF_CHAN_36, + RF_CHAN_40, + RF_CHAN_44, + RF_CHAN_48, + RF_CHAN_52, + RF_CHAN_56, + RF_CHAN_60, + RF_CHAN_64, + + /* 5GHz Mid Band - ETSI & FCC */ + RF_CHAN_100, + RF_CHAN_104, + RF_CHAN_108, + RF_CHAN_112, + RF_CHAN_116, + RF_CHAN_120, + RF_CHAN_124, + RF_CHAN_128, + RF_CHAN_132, + RF_CHAN_136, + RF_CHAN_140, + + RF_CHAN_144, + + /* 5GHz High U-NII Band */ + RF_CHAN_149, + RF_CHAN_153, + RF_CHAN_157, + RF_CHAN_161, + RF_CHAN_165, + + /* 802.11p */ + RF_CHAN_170, + RF_CHAN_171, + RF_CHAN_172, + RF_CHAN_173, + RF_CHAN_174, + RF_CHAN_175, + RF_CHAN_176, + RF_CHAN_177, + RF_CHAN_178, + RF_CHAN_179, + RF_CHAN_180, + RF_CHAN_181, + RF_CHAN_182, + RF_CHAN_183, + RF_CHAN_184, + + /* CHANNEL BONDED CHANNELS */ + RF_CHAN_BOND_3, + RF_CHAN_BOND_4, + RF_CHAN_BOND_5, + RF_CHAN_BOND_6, + RF_CHAN_BOND_7, + RF_CHAN_BOND_8, + RF_CHAN_BOND_9, + RF_CHAN_BOND_10, + RF_CHAN_BOND_11, + RF_CHAN_BOND_242, /* 4.9GHz Band */ + RF_CHAN_BOND_246, + RF_CHAN_BOND_250, + RF_CHAN_BOND_210, + RF_CHAN_BOND_214, + RF_CHAN_BOND_38, /* 5GHz Low & Mid U-NII Band */ + RF_CHAN_BOND_42, + RF_CHAN_BOND_46, + RF_CHAN_BOND_50, + RF_CHAN_BOND_54, + RF_CHAN_BOND_58, + RF_CHAN_BOND_62, + RF_CHAN_BOND_102, /* 5GHz Mid Band - ETSI & FCC */ + RF_CHAN_BOND_106, + RF_CHAN_BOND_110, + RF_CHAN_BOND_114, + RF_CHAN_BOND_118, + RF_CHAN_BOND_122, + RF_CHAN_BOND_126, + RF_CHAN_BOND_130, + RF_CHAN_BOND_134, + RF_CHAN_BOND_138, + + RF_CHAN_BOND_142, + + RF_CHAN_BOND_151, /* 5GHz High U-NII Band */ + RF_CHAN_BOND_155, + RF_CHAN_BOND_159, + RF_CHAN_BOND_163, + + NUM_RF_CHANNELS, + + MIN_2_4GHZ_CHANNEL = RF_CHAN_1, + MAX_2_4GHZ_CHANNEL = RF_CHAN_14, + NUM_24GHZ_CHANNELS = (MAX_2_4GHZ_CHANNEL - MIN_2_4GHZ_CHANNEL + 1), + + MIN_5GHZ_CHANNEL = RF_CHAN_240, + MAX_5GHZ_CHANNEL = RF_CHAN_184, + NUM_5GHZ_CHANNELS = (MAX_5GHZ_CHANNEL - MIN_5GHZ_CHANNEL + 1), + + MIN_20MHZ_RF_CHANNEL = RF_CHAN_1, + MAX_20MHZ_RF_CHANNEL = RF_CHAN_184, + NUM_20MHZ_RF_CHANNELS = + (MAX_20MHZ_RF_CHANNEL - MIN_20MHZ_RF_CHANNEL + 1), + + MIN_40MHZ_RF_CHANNEL = RF_CHAN_BOND_3, + MAX_40MHZ_RF_CHANNEL = RF_CHAN_BOND_163, + NUM_40MHZ_RF_CHANNELS = + (MAX_40MHZ_RF_CHANNEL - MIN_40MHZ_RF_CHANNEL + 1), + + MIN_5_9GHZ_CHANNEL = RF_CHAN_170, + MAX_5_9GHZ_CHANNEL = RF_CHAN_184, + + INVALID_RF_CHANNEL = 0xBAD, + RF_CHANNEL_INVALID_MAX_FIELD = 0x7FFFFFFF +} eRfChannels; + +typedef enum { + CHANNEL_STATE_DISABLE, + CHANNEL_STATE_ENABLE, + CHANNEL_STATE_DFS, + CHANNEL_STATE_INVALID +} CHANNEL_STATE; + +typedef int8_t tPowerdBm; + +typedef struct { + uint32_t enabled:4; + uint32_t flags:28; + tPowerdBm pwrLimit; +} sRegulatoryChannel; + +typedef struct { + sRegulatoryChannel channels[NUM_RF_CHANNELS]; +} sRegulatoryDomain; + +typedef struct { + uint16_t targetFreq; + uint16_t channelNum; +} tRfChannelProps; + +typedef struct { + uint8_t chanId; + tPowerdBm pwr; +} tChannelListWithPower; + +typedef enum { + COUNTRY_INIT, + COUNTRY_IE, + COUNTRY_USER, + COUNTRY_QUERY, + COUNTRY_MAX = COUNTRY_QUERY +} v_CountryInfoSource_t; + +/** + * enum chan_width: channel width + * + * @CHAN_WIDTH_0MHZ: channel disabled or invalid + * @CHAN_WIDTH_5MHZ: channel width 5 MHZ + * @CHAN_WIDTH_10MHZ: channel width 10 MHZ + * @CHAN_WIDTH_20MHZ: channel width 20 MHZ + * @CHAN_WIDTH_40MHZ: channel width 40 MHZ + * @CHAN_WIDTH_80MHZ: channel width 80MHZ + * @CHAN_WIDTH_160MHZ: channel width 160 MHZ + */ +enum channel_width { + CHAN_WIDTH_0MHZ, + CHAN_WIDTH_5MHZ, + CHAN_WIDTH_10MHZ, + CHAN_WIDTH_20MHZ, + CHAN_WIDTH_40MHZ, + CHAN_WIDTH_80MHZ, + CHAN_WIDTH_160MHZ +}; + +/** + * @country_code_t : typedef for country code. One extra + * char for holding null character + */ +typedef uint8_t country_code_t[CDS_COUNTRY_CODE_LEN + 1]; + +typedef struct { + sRegulatoryDomain regDomains[REGDOMAIN_COUNT]; + country_code_t default_country; +} t_reg_table; + + +CDF_STATUS cds_get_reg_domain_from_country_code(v_REGDOMAIN_t *pRegDomain, + const country_code_t countryCode, + v_CountryInfoSource_t source); + +CDF_STATUS cds_read_default_country(country_code_t default_country); + +CDF_STATUS cds_get_channel_list_with_power(tChannelListWithPower + *pChannels20MHz, + uint8_t *pNum20MHzChannelsFound, + tChannelListWithPower + *pChannels40MHz, + uint8_t *pNum40MHzChannelsFound); + +CDF_STATUS cds_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId); + +CHANNEL_STATE cds_get_channel_state(uint32_t rfChannel); + +#define CDS_IS_DFS_CH(channel) (cds_get_channel_state((channel)) == \ + CHANNEL_STATE_DFS) + +#define CDS_IS_PASSIVE_OR_DISABLE_CH(channel) \ + (cds_get_channel_state((channel)) != CHANNEL_STATE_ENABLE) + +#define CDS_MAX_24GHz_CHANNEL_NUMBER \ + (rf_channels[MAX_2_4GHZ_CHANNEL].channelNum) +#define CDS_MIN_5GHz_CHANNEL_NUMBER (rf_channels[RF_CHAN_36].channelNum) +#define CDS_MAX_5GHz_CHANNEL_NUMBER (rf_channels[MAX_5GHZ_CHANNEL].channelNum) + +#define CDS_IS_CHANNEL_5GHZ(chnNum) \ + (((chnNum) >= CDS_MIN_5GHz_CHANNEL_NUMBER) && ((chnNum) <= CDS_MAX_5GHz_CHANNEL_NUMBER)) + +#define CDS_IS_CHANNEL_24GHZ(chnNum) \ + (((chnNum) > 0) && ((chnNum) <= CDS_MAX_24GHz_CHANNEL_NUMBER)) + +#define CDS_IS_SAME_BAND_CHANNELS(ch1, ch2) \ + (ch1 && ch2 && \ + (CDS_IS_CHANNEL_5GHZ(ch1) == CDS_IS_CHANNEL_5GHZ(ch2))) + +CDF_STATUS cds_regulatory_init(void); +CDF_STATUS cds_get_dfs_region(uint8_t *dfs_region); +CDF_STATUS cds_set_dfs_region(uint8_t dfs_region); +bool cds_is_dsrc_channel(uint16_t); +CHANNEL_STATE cds_get_bonded_channel_state(uint32_t chan_num, + enum channel_width ch_width); +enum channel_width cds_get_max_channel_bw(uint32_t chan_num); + +#endif /* __CDS_REG_SERVICE_H */ diff --git a/core/cds/inc/cds_regdomain.h b/core/cds/inc/cds_regdomain.h new file mode 100644 index 0000000000..262677f201 --- /dev/null +++ b/core/cds/inc/cds_regdomain.h @@ -0,0 +1,1098 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * This module contains the regulatory domain private structure definitions . + * + */ + +#ifndef REGULATORY_H +#define REGULATORY_H + +enum { + CTRY_DEBUG = 0x1ff, /* debug country code */ + CTRY_DEFAULT = 0 /* default country code */ +}; + +#define BMLEN 2 /* Use 2 64 bit uint for channel bitmask */ + +/* + * The following table is the master list for all different freqeuncy + * bands with the complete matrix of all possible flags and settings + * for each band if it is used in ANY reg domain. + */ + +#define DEF_REGDMN FCC3_FCCA +#define DEF_DMN_5 FCC1 +#define DEF_DMN_2 FCCA +#define COUNTRY_ERD_FLAG 0x8000 +#define WORLDWIDE_ROAMING_FLAG 0x4000 +#define SUPER_DOMAIN_MASK 0x0fff +#define COUNTRY_CODE_MASK 0x3fff +#define CF_INTERFERENCE (CHANNEL_CW_INT | CHANNEL_RADAR_INT) + +/* + * The following describe the bit masks for different passive scan + * capability/requirements per regdomain. + */ +#define NO_PSCAN 0x0ULL +#define PSCAN_FCC 0x0000000000000001ULL +#define PSCAN_FCC_T 0x0000000000000002ULL +#define PSCAN_ETSI 0x0000000000000004ULL +#define PSCAN_MKK1 0x0000000000000008ULL +#define PSCAN_MKK2 0x0000000000000010ULL +#define PSCAN_MKKA 0x0000000000000020ULL +#define PSCAN_MKKA_G 0x0000000000000040ULL +#define PSCAN_ETSIA 0x0000000000000080ULL +#define PSCAN_ETSIB 0x0000000000000100ULL +#define PSCAN_ETSIC 0x0000000000000200ULL +#define PSCAN_WWR 0x0000000000000400ULL +#define PSCAN_MKKA1 0x0000000000000800ULL +#define PSCAN_MKKA1_G 0x0000000000001000ULL +#define PSCAN_MKKA2 0x0000000000002000ULL +#define PSCAN_MKKA2_G 0x0000000000004000ULL +#define PSCAN_MKK3 0x0000000000008000ULL +#define PSCAN_EXT_CHAN 0x0000000000010000ULL +#define PSCAN_DEFER 0x7FFFFFFFFFFFFFFFULL +#define IS_ECM_CHAN 0x8000000000000000ULL + +/* define in ah_eeprom.h */ +#define SD_NO_CTL 0xf0 +#define NO_CTL 0xff +#define CTL_MODE_M 0x0f +#define CTL_11A 0 +#define CTL_11B 1 +#define CTL_11G 2 +#define CTL_TURBO 3 +#define CTL_108G 4 +#define CTL_2GHT20 5 +#define CTL_5GHT20 6 +#define CTL_2GHT40 7 +#define CTL_5GHT40 8 +#define CTL_5GVHT80 9 + +#ifndef ATH_NO_5G_SUPPORT +#define REGDMN_MODE_11A_TURBO REGDMN_MODE_108A +#define CHAN_11A_BMZERO BMZERO, +#define CHAN_11A_BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) \ + BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l), +#else +/* remove 11a channel info if 11a is not supported */ +#define CHAN_11A_BMZERO +#define CHAN_11A_BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) +#endif +#ifndef ATH_REMOVE_2G_TURBO_RD_TABLE +#define REGDMN_MODE_11G_TURBO REGDMN_MODE_108G +#define CHAN_TURBO_G_BMZERO BMZERO, +#define CHAN_TURBO_G_BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) \ + BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l), +#else +/* remove turbo-g channel info if turbo-g is not supported */ +#define CHAN_TURBO_G(a, b) +#define CHAN_TURBO_G_BMZERO +#define CHAN_TURBO_G_BM(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) +#endif + +#define BMLEN 2 /* Use 2 64 bit uint for channel bitmask + NB: Must agree with macro below (BM) */ +#define BMZERO {(uint64_t) 0, (uint64_t) 0} /* BMLEN zeros */ + +#ifndef SUPPRESS_SHIFT_WARNING +#define SUPPRESS_SHIFT_WARNING +#endif + +/* Suppress MS warning "C4293: 'operator' : shift count negative or too big, + * undefined behavior" + * This is safe below because the the operand is properly range-checked, but + * the compiler can't reason that out before it spits the warning. + * Using suppress, so the warning can still be enabled globally to catch other + * incorrect uses. + */ +#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \ + SUPPRESS_SHIFT_WARNING \ + {((((_fa >= 0) && (_fa < 64)) ? (((uint64_t) 1) << _fa) : (uint64_t) 0) | \ + (((_fb >= 0) && (_fb < 64)) ? (((uint64_t) 1) << _fb) : (uint64_t) 0) | \ + (((_fc >= 0) && (_fc < 64)) ? (((uint64_t) 1) << _fc) : (uint64_t) 0) | \ + (((_fd >= 0) && (_fd < 64)) ? (((uint64_t) 1) << _fd) : (uint64_t) 0) | \ + (((_fe >= 0) && (_fe < 64)) ? (((uint64_t) 1) << _fe) : (uint64_t) 0) | \ + (((_ff >= 0) && (_ff < 64)) ? (((uint64_t) 1) << _ff) : (uint64_t) 0) | \ + (((_fg >= 0) && (_fg < 64)) ? (((uint64_t) 1) << _fg) : (uint64_t) 0) | \ + (((_fh >= 0) && (_fh < 64)) ? (((uint64_t) 1) << _fh) : (uint64_t) 0) | \ + (((_fi >= 0) && (_fi < 64)) ? (((uint64_t) 1) << _fi) : (uint64_t) 0) | \ + (((_fj >= 0) && (_fj < 64)) ? (((uint64_t) 1) << _fj) : (uint64_t) 0) | \ + (((_fk >= 0) && (_fk < 64)) ? (((uint64_t) 1) << _fk) : (uint64_t) 0) | \ + (((_fl >= 0) && (_fl < 64)) ? (((uint64_t) 1) << _fl) : (uint64_t) 0) ) \ + ,(((((_fa > 63) && (_fa < 128)) ? (((uint64_t) 1) << (_fa - 64)) : (uint64_t) 0) | \ + (((_fb > 63) && (_fb < 128)) ? (((uint64_t) 1) << (_fb - 64)) : (uint64_t) 0) | \ + (((_fc > 63) && (_fc < 128)) ? (((uint64_t) 1) << (_fc - 64)) : (uint64_t) 0) | \ + (((_fd > 63) && (_fd < 128)) ? (((uint64_t) 1) << (_fd - 64)) : (uint64_t) 0) | \ + (((_fe > 63) && (_fe < 128)) ? (((uint64_t) 1) << (_fe - 64)) : (uint64_t) 0) | \ + (((_ff > 63) && (_ff < 128)) ? (((uint64_t) 1) << (_ff - 64)) : (uint64_t) 0) | \ + (((_fg > 63) && (_fg < 128)) ? (((uint64_t) 1) << (_fg - 64)) : (uint64_t) 0) | \ + (((_fh > 63) && (_fh < 128)) ? (((uint64_t) 1) << (_fh - 64)) : (uint64_t) 0) | \ + (((_fi > 63) && (_fi < 128)) ? (((uint64_t) 1) << (_fi - 64)) : (uint64_t) 0) | \ + (((_fj > 63) && (_fj < 128)) ? (((uint64_t) 1) << (_fj - 64)) : (uint64_t) 0) | \ + (((_fk > 63) && (_fk < 128)) ? (((uint64_t) 1) << (_fk - 64)) : (uint64_t) 0) | \ + (((_fl > 63) && (_fl < 128)) ? (((uint64_t) 1) << (_fl - 64)) : (uint64_t) 0)))} + +/* + * THE following table is the mapping of regdomain pairs specified by + * an 8 bit regdomain value to the individual unitary reg domains + */ + +typedef struct reg_dmn_pair_mapping { + uint16_t regDmnEnum; /* 16 bit reg domain pair */ + uint16_t regDmn5GHz; /* 5GHz reg domain */ + uint16_t regDmn2GHz; /* 2GHz reg domain */ + uint32_t flags5GHz; /* Requirements flags (AdHoc + disallow, noise floor cal needed, + etc) */ + uint32_t flags2GHz; /* Requirements flags (AdHoc + disallow, noise floor cal needed, + etc) */ + uint64_t pscanMask; /* Passive Scan flags which + can override unitary domain + passive scan flags. This + value is used as a mask on + the unitary flags */ + uint16_t singleCC; /* Country code of single country if + a one-on-one mapping exists */ +} REG_DMN_PAIR_MAPPING; + +typedef struct { + uint16_t countryCode; + uint16_t regDmnEnum; + const char *isoName; + const char *name; + uint16_t allow11g : 1, allow11aTurbo : 1, allow11gTurbo : 1, allow11ng20 : 1, /* HT-20 allowed in 2GHz? */ + allow11ng40 : 1, /* HT-40 allowed in 2GHz? */ + allow11na20 : 1, /* HT-20 allowed in 5GHz? */ + allow11na40 : 1, /* HT-40 VHT-40 allowed in 5GHz? */ + allow11na80 : 1; /* VHT-80 allowed in 5GHz */ + uint16_t outdoorChanStart; +} COUNTRY_CODE_TO_ENUM_RD; + +typedef struct RegDmnFreqBand { + uint16_t lowChannel; /* Low channel center in MHz */ + uint16_t highChannel; /* High Channel center in MHz */ + uint8_t powerDfs; /* Max power (dBm) for channel + range when using DFS */ + uint8_t antennaMax; /* Max allowed antenna gain */ + uint8_t channelBW; /* Bandwidth of the channel */ + uint8_t channelSep; /* Channel separation within + the band */ + uint64_t useDfs; /* Use DFS in the RegDomain + if corresponding bit is set */ + uint64_t usePassScan; /* Use Passive Scan in the RegDomain + if corresponding bit is set */ + uint8_t regClassId; /* Regulatory class id */ +} REG_DMN_FREQ_BAND; + +typedef struct reg_domain { + uint16_t regDmnEnum; /* value from EnumRd table */ + uint8_t conformance_test_limit; + uint64_t dfsMask; /* DFS bitmask for 5Ghz tables */ + uint64_t pscan; /* Bitmask for passive scan */ + uint32_t flags; /* Requirement flags (AdHoc disallow, noise + floor cal needed, etc) */ + uint64_t chan11a[BMLEN]; /* 128 bit bitmask for channel/band selection */ + uint64_t chan11a_turbo[BMLEN]; /* 128 bit bitmask for channel/band select */ + uint64_t chan11a_dyn_turbo[BMLEN]; /* 128 bit mask for chan/band select */ + + uint64_t chan11b[BMLEN]; /* 128 bit bitmask for channel/band selection */ + uint64_t chan11g[BMLEN]; /* 128 bit bitmask for channel/band selection */ + uint64_t chan11g_turbo[BMLEN]; +} REG_DOMAIN; + +struct cmode { + uint32_t mode; + uint32_t flags; +}; + +#define YES true +#define NO false + +/* mapping of old skus to new skus for Japan */ +typedef struct { + uint16_t domain; + uint16_t newdomain_pre53; /* pre eeprom version 5.3 */ + uint16_t newdomain_post53; /* post eeprom version 5.3 */ +} JAPAN_SKUMAP; + +/* mapping of countrycode to new skus for Japan */ +typedef struct { + uint16_t ccode; + uint16_t newdomain_pre53; /* pre eeprom version 5.3 */ + uint16_t newdomain_post53; /* post eeprom version 5.3 */ +} JAPAN_COUNTRYMAP; + +/* check rd flags in eeprom for japan */ +typedef struct { + uint16_t freqbandbit; + uint32_t eepromflagtocheck; +} JAPAN_BANDCHECK; + +/* Common mode power table for 5Ghz */ +typedef struct { + uint16_t lchan; + uint16_t hchan; + uint8_t pwrlvl; +} COMMON_MODE_POWER; + +typedef enum { + COUNTRY_CODE_SET_BY_CORE, + COUNTRY_CODE_SET_BY_DRIVER, + COUNTRY_CODE_SET_BY_USER +} COUNTRY_CODE_SOURCE; + +struct regulatory { + uint32_t reg_domain; + uint32_t eeprom_rd_ext; + uint16_t country_code; + uint8_t alpha2[3]; + uint8_t dfs_region; + uint8_t ctl_2g; + uint8_t ctl_5g; + const void *regpair; + COUNTRY_CODE_SOURCE cc_src; + uint32_t reg_flags; +}; +/* Multi-Device RegDomain Support */ +typedef struct ath_hal_reg_dmn_tables { + /* regDomainPairs: Map of 8-bit regdomain values to unitary reg domain */ + const REG_DMN_PAIR_MAPPING *regDomainPairs; + /* allCountries: Master list of freq. bands (flags, settings) */ + const COUNTRY_CODE_TO_ENUM_RD *allCountries; + /* regDomains: Array of supported reg domains */ + const REG_DOMAIN *regDomains; + + uint16_t regDomainPairsCt; /* Num reg domain pair entries */ + uint16_t allCountriesCt; /* Num country entries */ + uint16_t regDomainsCt; /* Num reg domain entries */ +} HAL_REG_DMN_TABLES; + +/* + * Country/Region Codes from MS WINNLS.H + * Numbering from ISO 3166 + */ +/** @brief country code definitions + * - country definition: CTRY_DEBUG + * - country string: DB + * - country ID: 0 + * - country definition: CTRY_DEFAULT + * - country string: NA + * - country ID: 0 + * - country definition: CTRY_ALBANIA + * - country string: AL + * - country ID: 8 + * - country definition: CTRY_ALGERIA + * - country string: DZ + * - country ID: 12 + * - country definition: CTRY_ARGENTINA + * - country string: AR + * - country ID: 32 + * - country definition: CTRY_ARMENIA + * - country string: AM + * - country ID: 51 + * - country definition: CTRY_AUSTRALIA + * - country string: AU + * - country ID: 36 + * - country definition: CTRY_AUSTRALIA2 + * - country string: AU2 + * - country ID: 5000 + * - country definition: CTRY_AUSTRIA + * - country string: AT + * - country ID: 40 + * - country definition: CTRY_AZERBAIJAN + * - country string: AZ + * - country ID: 31 + * - country definition: CTRY_BAHAMAS + * - country string: BS + * - country ID: 44 + * - country definition: CTRY_BAHRAIN + * - country string: BH + * - country ID: 48 + * - country definition: CTRY_BELARUS + * - country string: BY + * - country ID: 112 + * - country definition: CTRY_BELGIUM + * - country string: BE + * - country ID: 56 + * - country definition: CTRY_BELIZE + * - country string: BZ + * - country ID: 84 + * - country definition: CTRY_BERMUDA + * - country string: BM + * - country ID: 60 + * - country definition: CTRY_BOLIVIA + * - country string: BO + * - country ID: 68 + * - country definition: CTRY_BOSNIA_HERZEGOWINA + * - country string: 70 + * - country ID: BA + * - country definition: CTRY_BRAZIL + * - country string: BR + * - country ID: 76 + * - country definition: CTRY_BRUNEI_DARUSSALAM + * - country string: BN + * - country ID: 96 + * - country definition: CTRY_BULGARIA + * - country string: BG + * - country ID: 100 + * - country definition: CTRY_CANADA + * - country string: CA + * - country ID: 124 + * - country definition: CTRY_CANADA2 + * - country string: CA2 + * - country ID: 5001 + * - country definition: CTRY_CHILE + * - country string: CL + * - country ID: 152 + * - country definition: CTRY_CHINA + * - country string: CN + * - country ID: 152 + * - country definition: CTRY_COLOMBIA + * - country string: CO + * - country ID: 170 + * - country definition: CTRY_COSTA_RICA + * - country string: CR + * - country ID: 191 + * - country definition: CTRY_CROATIA + * - country string: HR + * - country ID: 191 + * - country definition: CTRY_CYPRUS + * - country string: CY + * - country ID: 196 + * - country definition: CTRY_CZECH + * - country string: CZ + * - country ID: 203 + * - country definition: CTRY_DENMARK + * - country string: DK + * - country ID: 208 + * - country definition: CTRY_DOMINICAN_REPUBLIC + * - country string: DO + * - country ID: 214 + * - country definition: CTRY_ECUADOR + * - country string: EC + * - country ID: 218 + * - country definition: CTRY_EGYPT + * - country string: EG + * - country ID: 818 + * - country definition: CTRY_EL_SALVADOR + * - country string: SV + * - country ID: 222 + * - country definition: CTRY_ESTONIA + * - country string: EE + * - country ID: 233 + * - country definition: CTRY_FAEROE_ISLANDS + * - country string: FO + * - country ID: 234 + * - country definition: CTRY_FINLAND + * - country string: FI + * - country ID: 246 + * - country definition: CTRY_FRANCE + * - country string: FR + * - country ID: 250 + * - country definition: CTRY_FRANCE2 + * - country string: F2 + * - country ID: 255 + * - country definition: CTRY_GEORGIA + * - country string: GE + * - country ID: 268 + * - country definition: CTRY_GERMANY + * - country string: DE + * - country ID: 276 + * - country definition: CTRY_GREECE + * - country string: GR + * - country ID: 300 + * - country definition: CTRY_GUATEMALA + * - country string: GT + * - country ID: 320 + * - country definition: CTRY_HONDURAS + * - country string: HN + * - country ID: 340 + * - country definition: CTRY_HONG_KONG + * - country string: HK + * - country ID: 344 + * - country definition: CTRY_HUNGARY + * - country string: HU + * - country ID: 348 + * - country definition: CTRY_ICELAND + * - country string: IS + * - country ID: 352 + * - country definition: CTRY_INDIA + * - country string: IN + * - country ID: 356 + * - country definition: CTRY_INDONESIA + * - country string: ID + * - country ID: 360 + * - country definition: CTRY_IRAN + * - country string: IR + * - country ID: 364 + * - country definition: CTRY_IRAQ + * - country string: IQ + * - country ID: 368 + * - country definition: CTRY_IRELAND + * - country string: IE + * - country ID: 372 + * - country definition: CTRY_ISRAEL + * - country string: IL + * - country ID: 376 + * - country definition: CTRY_ITALY + * - country string: IT + * - country ID: 380 + * - country definition: CTRY_JAMAICA + * - country string: JM + * - country ID: 388 + * - country definition: CTRY_JAPAN + * - country string: JP + * - country ID: 392 + * - country definition: CTRY_JAPAN1 + * - country string: JP1 + * - country ID: 393 + * - country definition: CTRY_JAPAN2 + * - country string: JP2 + * - country ID: 394 + * - country definition: CTRY_JAPAN3 + * - country string: JP3 + * - country ID: 395 + * - country definition: CTRY_JAPAN4 + * - country string: JP4 + * - country ID: 396 + * - country definition: CTRY_JAPAN5 + * - country string: JP5 + * - country ID: 397 + * - country definition: CTRY_JAPAN6 + * - country string: JP6 + * - country ID: 399 + * - country definition: CTRY_JAPAN7 + * - country string: JP7 + * - country ID: 4007 + * - country definition: CTRY_JAPAN8 + * - country string: JP8 + * - country ID: 4008 + * - country definition: CTRY_JAPAN9 + * - country string: JP9 + * - country ID: 4009 + * - country definition: CTRY_JAPAN10 + * - country string: JP10 + * - country ID: 4010 + * - country definition: CTRY_JAPAN11 + * - country string: JP11 + * - country ID: 4011 + * - country definition: CTRY_JAPAN12 + * - country string: JP12 + * - country ID: 4012 + * - country definition: CTRY_JAPAN13 + * - country string: JP13 + * - country ID: 4013 + * - country definition: CTRY_JAPAN14 + * - country string: JP14 + * - country ID: 4014 + * - country definition: CTRY_JAPAN15 + * - country string: JP15 + * - country ID: 4015 + * - country definition: CTRY_JAPAN16 + * - country string: JP16 + * - country ID: 4016 + * - country definition: CTRY_JAPAN17 + * - country string: JP17 + * - country ID: 4017 + * - country definition: CTRY_JAPAN18 + * - country string: JP18 + * - country ID: 4018 + * - country definition: CTRY_JAPAN19 + * - country string: JP19 + * - country ID: 4019 + * - country definition: CTRY_JAPAN20 + * - country string: JP20 + * - country ID: 4020 + * - country definition: CTRY_JAPAN21 + * - country string: JP21 + * - country ID: 4021 + * - country definition: CTRY_JAPAN22 + * - country string: JP22 + * - country ID: 4022 + * - country definition: CTRY_JAPAN23 + * - country string: JP23 + * - country ID: 4023 + * - country definition: CTRY_JAPAN24 + * - country string: JP24 + * - country ID: 4024 + * - country definition: CTRY_JAPAN25 + * - country string: JP25 + * - country ID: 4025 + * - country definition: CTRY_JAPAN26 + * - country string: JP26 + * - country ID: 4026 + * - country definition: CTRY_JAPAN27 + * - country string: JP27 + * - country ID: 4027 + * - country definition: CTRY_JAPAN28 + * - country string: JP28 + * - country ID: 4028 + * - country definition: CTRY_JAPAN29 + * - country string: JP29 + * - country ID: 4029 + * - country definition: CTRY_JAPAN30 + * - country string: JP30 + * - country ID: 4030 + * - country definition: CTRY_JAPAN31 + * - country string: JP31 + * - country ID: 4031 + * - country definition: CTRY_JAPAN32 + * - country string: JP32 + * - country ID: 4032 + * - country definition: CTRY_JAPAN33 + * - country string: JP33 + * - country ID: 4033 + * - country definition: CTRY_JAPAN34 + * - country string: JP34 + * - country ID: 4034 + * - country definition: CTRY_JAPAN35 + * - country string: JP35 + * - country ID: 4035 + * - country definition: CTRY_JAPAN36 + * - country string: JP36 + * - country ID: 4036 + * - country definition: CTRY_JAPAN37 + * - country string: JP37 + * - country ID: 4037 + * - country definition: CTRY_JAPAN38 + * - country string: JP38 + * - country ID: 4038 + * - country definition: CTRY_JAPAN39 + * - country string: JP39 + * - country ID: 4039 + * - country definition: CTRY_JAPAN40 + * - country string: JP40 + * - country ID: 4040 + * - country definition: CTRY_JAPAN41 + * - country string: JP41 + * - country ID: 4041 + * - country definition: CTRY_JAPAN42 + * - country string: JP42 + * - country ID: 4042 + * - country definition: CTRY_JAPAN43 + * - country string: JP43 + * - country ID: 4043 + * - country definition: CTRY_JAPAN44 + * - country string: JP44 + * - country ID: 4044 + * - country definition: CTRY_JAPAN45 + * - country string: JP45 + * - country ID: 4045 + * - country definition: CTRY_JAPAN46 + * - country string: JP46 + * - country ID: 4046 + * - country definition: CTRY_JAPAN47 + * - country string: JP47 + * - country ID: 4047 + * - country definition: CTRY_JAPAN48 + * - country string: JP48 + * - country ID: 4048 + * - country definition: CTRY_JAPAN49 + * - country string: JP49 + * - country ID: 4049 + * - country definition: CTRY_JAPAN50 + * - country string: JP50 + * - country ID: 4050 + * - country definition: CTRY_JAPAN51 + * - country string: JP51 + * - country ID: 4051 + * - country definition: CTRY_JAPAN52 + * - country string: JP52 + * - country ID: 4052 + * - country definition: CTRY_JAPAN53 + * - country string: JP53 + * - country ID: 4053 + * - country definition: CTRY_JAPAN54 + * - country string: JP54 + * - country ID: 4054 + * - country definition: CTRY_JAPAN55 + * - country string: JP55 + * - country ID: 4055 + * - country definition: CTRY_JAPAN56 + * - country string: JP56 + * - country ID: 4056 + * - country definition: CTRY_JORDAN + * - country string: JO + * - country ID: 400 + * - country definition: CTRY_KAZAKHSTAN + * - country string: KZ + * - country ID: 398 + * - country definition: CTRY_KENYA + * - country string: KE + * - country ID: 404 + * - country definition: CTRY_KOREA_NORTH + * - country string: KP + * - country ID: 408 + * - country definition: CTRY_KOREA_ROC + * - country string: KR + * - country ID: 410 + * - country definition: CTRY_KOREA_ROC2 + * - country string: KR2 + * - country ID: 411 + * - country definition: CTRY_KOREA_ROC3 + * - country string: KR3 + * - country ID: 412 + * - country definition: CTRY_KUWAIT + * - country string: KW + * - country ID: 414 + * - country definition: CTRY_LATVIA + * - country string: LV + * - country ID: 428 + * - country definition: CTRY_LEBANON + * - country string: LB + * - country ID: 422 + * - country definition: CTRY_LIBYA + * - country string: LY + * - country ID: 434 + * - country definition: CTRY_LIECHTENSTEIN + * - country string: LI + * - country ID: 438 + * - country definition: CTRY_LITHUANIA + * - country string: LT + * - country ID: 440 + * - country definition: CTRY_LUXEMBOURG + * - country string: LU + * - country ID: 442 + * - country definition: CTRY_MACAU + * - country string: MO + * - country ID: 446 + * - country definition: CTRY_MACEDONIA + * - country string: MK + * - country ID: 807 + * - country definition: CTRY_MALAYSIA + * - country string: MY + * - country ID: 458 + * - country definition: CTRY_MALTA + * - country string: MT + * - country ID: 470 + * - country definition: CTRY_MAURITIUS + * - country string: MU + * - country ID: 480 + * - country definition: CTRY_MEXICO + * - country string: MX + * - country ID: 484 + * - country definition: CTRY_MONACO + * - country string: MC + * - country ID: 492 + * - country definition: CTRY_MOROCCO + * - country string: MA + * - country ID: 504 + * - country definition: CTRY_NETHERLANDS + * - country string: NL + * - country ID: 528 + * - country definition: CTRY_NEW_ZEALAND + * - country string: NZ + * - country ID: 554 + * - country definition: CTRY_NICARAGUA + * - country string: NI + * - country ID: 558 + * - country definition: CTRY_NORWAY + * - country string: NO + * - country ID: 578 + * - country definition: CTRY_OMAN + * - country string: OM + * - country ID: 512 + * - country definition: CTRY_PAKISTAN + * - country string: PK + * - country ID: 586 + * - country definition: CTRY_PANAMA + * - country string: PA + * - country ID: 591 + * - country definition: CTRY_PARAGUAY + * - country string: PY + * - country ID: 600 + * - country definition: CTRY_PERU + * - country string: PE + * - country ID: 604 + * - country definition: CTRY_PHILIPPINES + * - country string: PH + * - country ID: 608 + * - country definition: CTRY_POLAND + * - country string: PL + * - country ID: 616 + * - country definition: CTRY_PORTUGAL + * - country string: PT + * - country ID: 620 + * - country definition: CTRY_PUERTO_RICO + * - country string: PR + * - country ID: 630 + * - country definition: CTRY_QATAR + * - country string: QA + * - country ID: 634 + * - country definition: CTRY_ROMANIA + * - country string: RO + * - country ID: 642 + * - country definition: CTRY_RUSSIA + * - country string: RU + * - country ID: 643 + * - country definition: CTRY_SAUDI_ARABIA + * - country string: SA + * - country ID: 682 + * - country definition: CTRY_SERBIA + * - country string: RS + * - country ID: 688 + * - country definition: CTRY_MONTENEGRO + * - country string: ME + * - country ID: 499 + * - country definition: CTRY_SINGAPORE + * - country string: SG + * - country ID: 702 + * - country definition: CTRY_SLOVAKIA + * - country string: SK + * - country ID: 703 + * - country definition: CTRY_SLOVENIA + * - country string: SI + * - country ID: 705 + * - country definition: CTRY_SOUTH_AFRICA + * - country string: ZA + * - country ID: 710 + * - country definition: CTRY_SPAIN + * - country string: ES + * - country ID: 724 + * - country definition: CTRY_SRI_LANKA + * - country string: LK + * - country ID: 144 + * - country definition: CTRY_SWEDEN + * - country string: SE + * - country ID: 752 + * - country definition: CTRY_SWITZERLAND + * - country string: CH + * - country ID: 756 + * - country definition: CTRY_SYRIA + * - country string: SY + * - country ID: 760 + * - country definition: CTRY_TAIWAN + * - country string: TW + * - country ID: 158 + * - country definition: CTRY_TANZANIA + * - country string: TZ + * - country ID: 834 + * - country definition: CTRY_THAILAND + * - country string: TH + * - country ID: 764 + * - country definition: CTRY_TRINIDAD_Y_TOBAGO + * - country string: TT + * - country ID: 780 + * - country definition: CTRY_TUNISIA + * - country string: TN + * - country ID: 788 + * - country definition: CTRY_TURKEY + * - country string: TR + * - country ID: 792 + * - country definition: CTRY_UAE + * - country string: AE + * - country ID: 784 + * - country definition: CTRY_UKRAINE + * - country string: UA + * - country ID: 804 + * - country definition: CTRY_UNITED_KINGDOM + * - country string: GB + * - country ID: 826 + * - country definition: CTRY_UNITED_STATES + * - country string: US + * - country ID: 840 + * - country definition: CTRY_UNITED_STATES_FCC49 + * - country string: US + * - country ID: 842 + * - country definition: CTRY_URUGUAY + * - country string: UY + * - country ID: 858 + * - country definition: CTRY_UZBEKISTAN + * - country string: UZ + * - country ID: 860 + * - country definition: CTRY_VENEZUELA + * - country string: VE + * - country ID: 862 + * - country definition: CTRY_VIET_NAM + * - country string: VN + * - country ID: 704 + * - country definition: CTRY_YEMEN + * - country string: YE + * - country ID: 887 + * - country definition: CTRY_ZIMBABWE + * - country string: ZW + * - country ID: 716 + */ +enum CountryCode { + CTRY_ALBANIA = 8, /* Albania */ + CTRY_ALGERIA = 12, /* Algeria */ + CTRY_ARGENTINA = 32, /* Argentina */ + CTRY_ARMENIA = 51, /* Armenia */ + CTRY_AUSTRALIA = 36, /* Australia */ + CTRY_AUSTRIA = 40, /* Austria */ + CTRY_AZERBAIJAN = 31, /* Azerbaijan */ + CTRY_BAHAMAS = 44, /* Bahamas */ + CTRY_BAHRAIN = 48, /* Bahrain */ + CTRY_BANGLADESH = 50, /* Bangladesh */ + CTRY_BARBADOS = 52, /* Barbados */ + CTRY_BELARUS = 112, /* Belarus */ + CTRY_BELGIUM = 56, /* Belgium */ + CTRY_BELIZE = 84, /* Belize */ + CTRY_BERMUDA = 60, /* Berumuda */ + CTRY_BOLIVIA = 68, /* Bolivia */ + CTRY_BOSNIA_HERZ = 70, /* Bosnia and Herzegowina */ + CTRY_BRAZIL = 76, /* Brazil */ + CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ + CTRY_BULGARIA = 100, /* Bulgaria */ + CTRY_CAMBODIA = 116, /* Cambodia */ + CTRY_CANADA = 124, /* Canada */ + CTRY_CHILE = 152, /* Chile */ + CTRY_CHINA = 156, /* People's Republic of China */ + CTRY_COLOMBIA = 170, /* Colombia */ + CTRY_COSTA_RICA = 188, /* Costa Rica */ + CTRY_CROATIA = 191, /* Croatia */ + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, /* Czech Republic */ + CTRY_DENMARK = 208, /* Denmark */ + CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ + CTRY_ECUADOR = 218, /* Ecuador */ + CTRY_EGYPT = 818, /* Egypt */ + CTRY_EL_SALVADOR = 222, /* El Salvador */ + CTRY_ESTONIA = 233, /* Estonia */ + CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ + CTRY_FINLAND = 246, /* Finland */ + CTRY_FRANCE = 250, /* France */ + CTRY_GEORGIA = 268, /* Georgia */ + CTRY_GERMANY = 276, /* Germany */ + CTRY_GREECE = 300, /* Greece */ + CTRY_GREENLAND = 304, /* Greenland */ + CTRY_GRENADA = 308, /* Grenada */ + CTRY_GUAM = 316, /* Guam */ + CTRY_GUATEMALA = 320, /* Guatemala */ + CTRY_HAITI = 332, /* Haiti */ + CTRY_HONDURAS = 340, /* Honduras */ + CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ + CTRY_HUNGARY = 348, /* Hungary */ + CTRY_ICELAND = 352, /* Iceland */ + CTRY_INDIA = 356, /* India */ + CTRY_INDONESIA = 360, /* Indonesia */ + CTRY_IRAN = 364, /* Iran */ + CTRY_IRAQ = 368, /* Iraq */ + CTRY_IRELAND = 372, /* Ireland */ + CTRY_ISRAEL = 376, /* Israel */ + CTRY_ITALY = 380, /* Italy */ + CTRY_JAMAICA = 388, /* Jamaica */ + CTRY_JAPAN = 392, /* Japan */ + CTRY_JORDAN = 400, /* Jordan */ + CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ + CTRY_KENYA = 404, /* Kenya */ + CTRY_KOREA_NORTH = 408, /* North Korea */ + CTRY_KOREA_ROC = 410, /* South Korea */ + CTRY_KOREA_ROC3 = 412, /* South Korea */ + CTRY_KUWAIT = 414, /* Kuwait */ + CTRY_LATVIA = 428, /* Latvia */ + CTRY_LEBANON = 422, /* Lebanon */ + CTRY_LIBYA = 434, /* Libya */ + CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ + CTRY_LITHUANIA = 440, /* Lithuania */ + CTRY_LUXEMBOURG = 442, /* Luxembourg */ + CTRY_MACAU = 446, /* Macau SAR */ + CTRY_MACEDONIA = 807, /* the Former Yugoslav Republic of Macedonia */ + CTRY_MALAYSIA = 458, /* Malaysia */ + CTRY_MALDIVES = 462, /* Maldives */ + CTRY_MALTA = 470, /* Malta */ + CTRY_MAURITIUS = 480, /* Mauritius */ + CTRY_MEXICO = 484, /* Mexico */ + CTRY_MONACO = 492, /* Principality of Monaco */ + CTRY_MOROCCO = 504, /* Morocco */ + CTRY_NEPAL = 524, /* Nepal */ + CTRY_NETHERLANDS = 528, /* Netherlands */ + CTRY_NETHERLANDS_ANTILLES = 530, /* Netherlands-Antilles */ + CTRY_ARUBA = 533, /* Aruba */ + CTRY_NEW_ZEALAND = 554, /* New Zealand */ + CTRY_NICARAGUA = 558, /* Nicaragua */ + CTRY_NORWAY = 578, /* Norway */ + CTRY_OMAN = 512, /* Oman */ + CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ + CTRY_PANAMA = 591, /* Panama */ + CTRY_PAPUA_NEW_GUINEA = 598, /* Papua New Guinea */ + CTRY_PARAGUAY = 600, /* Paraguay */ + CTRY_PERU = 604, /* Peru */ + CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ + CTRY_POLAND = 616, /* Poland */ + CTRY_PORTUGAL = 620, /* Portugal */ + CTRY_PUERTO_RICO = 630, /* Puerto Rico */ + CTRY_QATAR = 634, /* Qatar */ + CTRY_ROMANIA = 642, /* Romania */ + CTRY_RUSSIA = 643, /* Russia */ + CTRY_RWANDA = 646, /* Rwanda */ + CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ + CTRY_SERBIA = 688, /* Republic of Serbia */ + CTRY_MONTENEGRO = 499, /* Montenegro */ + CTRY_SINGAPORE = 702, /* Singapore */ + CTRY_SLOVAKIA = 703, /* Slovak Republic */ + CTRY_SLOVENIA = 705, /* Slovenia */ + CTRY_SOUTH_AFRICA = 710, /* South Africa */ + CTRY_SPAIN = 724, /* Spain */ + CTRY_SRI_LANKA = 144, /* Sri Lanka */ + CTRY_SWEDEN = 752, /* Sweden */ + CTRY_SWITZERLAND = 756, /* Switzerland */ + CTRY_SYRIA = 760, /* Syria */ + CTRY_TAIWAN = 158, /* Taiwan */ + CTRY_TANZANIA = 834, /* Tanzania */ + CTRY_THAILAND = 764, /* Thailand */ + CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ + CTRY_TUNISIA = 788, /* Tunisia */ + CTRY_TURKEY = 792, /* Turkey */ + CTRY_UAE = 784, /* U.A.E. */ + CTRY_UGANDA = 800, /* Uganda */ + CTRY_UKRAINE = 804, /* Ukraine */ + CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ + CTRY_UNITED_STATES = 840, /* United States */ + CTRY_UNITED_STATES2 = 841, /* United States for AP */ + CTRY_UNITED_STATES_FCC49 = 842, /* United States (Public Safety) */ + CTRY_URUGUAY = 858, /* Uruguay */ + CTRY_UZBEKISTAN = 860, /* Uzbekistan */ + CTRY_VENEZUELA = 862, /* Venezuela */ + CTRY_VIET_NAM = 704, /* Viet Nam */ + CTRY_YEMEN = 887, /* Yemen */ + CTRY_ZIMBABWE = 716, /* Zimbabwe */ + + /* + ** Japan special codes. Boy, do they have a lot + */ + + CTRY_JAPAN1 = 393, /* Japan (JP1) */ + CTRY_JAPAN2 = 394, /* Japan (JP0) */ + CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ + CTRY_JAPAN4 = 396, /* Japan (JE1) */ + CTRY_JAPAN5 = 397, /* Japan (JE2) */ + CTRY_JAPAN6 = 4006, /* Japan (JP6) */ + CTRY_JAPAN7 = 4007, /* Japan (J7) */ + CTRY_JAPAN8 = 4008, /* Japan (J8) */ + CTRY_JAPAN9 = 4009, /* Japan (J9) */ + CTRY_JAPAN10 = 4010, /* Japan (J10) */ + CTRY_JAPAN11 = 4011, /* Japan (J11) */ + CTRY_JAPAN12 = 4012, /* Japan (J12) */ + CTRY_JAPAN13 = 4013, /* Japan (J13) */ + CTRY_JAPAN14 = 4014, /* Japan (J14) */ + CTRY_JAPAN15 = 4015, /* Japan (J15) */ + CTRY_JAPAN16 = 4016, /* Japan (J16) */ + CTRY_JAPAN17 = 4017, /* Japan (J17) */ + CTRY_JAPAN18 = 4018, /* Japan (J18) */ + CTRY_JAPAN19 = 4019, /* Japan (J19) */ + CTRY_JAPAN20 = 4020, /* Japan (J20) */ + CTRY_JAPAN21 = 4021, /* Japan (J21) */ + CTRY_JAPAN22 = 4022, /* Japan (J22) */ + CTRY_JAPAN23 = 4023, /* Japan (J23) */ + CTRY_JAPAN24 = 4024, /* Japan (J24) */ + CTRY_JAPAN25 = 4025, /* Japan (J25) */ + CTRY_JAPAN26 = 4026, /* Japan (J26) */ + CTRY_JAPAN27 = 4027, /* Japan (J27) */ + CTRY_JAPAN28 = 4028, /* Japan (J28) */ + CTRY_JAPAN29 = 4029, /* Japan (J29) */ + CTRY_JAPAN30 = 4030, /* Japan (J30) */ + CTRY_JAPAN31 = 4031, /* Japan (J31) */ + CTRY_JAPAN32 = 4032, /* Japan (J32) */ + CTRY_JAPAN33 = 4033, /* Japan (J33) */ + CTRY_JAPAN34 = 4034, /* Japan (J34) */ + CTRY_JAPAN35 = 4035, /* Japan (J35) */ + CTRY_JAPAN36 = 4036, /* Japan (J36) */ + CTRY_JAPAN37 = 4037, /* Japan (J37) */ + CTRY_JAPAN38 = 4038, /* Japan (J38) */ + CTRY_JAPAN39 = 4039, /* Japan (J39) */ + CTRY_JAPAN40 = 4040, /* Japan (J40) */ + CTRY_JAPAN41 = 4041, /* Japan (J41) */ + CTRY_JAPAN42 = 4042, /* Japan (J42) */ + CTRY_JAPAN43 = 4043, /* Japan (J43) */ + CTRY_JAPAN44 = 4044, /* Japan (J44) */ + CTRY_JAPAN45 = 4045, /* Japan (J45) */ + CTRY_JAPAN46 = 4046, /* Japan (J46) */ + CTRY_JAPAN47 = 4047, /* Japan (J47) */ + CTRY_JAPAN48 = 4048, /* Japan (J48) */ + CTRY_JAPAN49 = 4049, /* Japan (J49) */ + CTRY_JAPAN50 = 4050, /* Japan (J50) */ + CTRY_JAPAN51 = 4051, /* Japan (J51) */ + CTRY_JAPAN52 = 4052, /* Japan (J52) */ + CTRY_JAPAN53 = 4053, /* Japan (J53) */ + CTRY_JAPAN54 = 4054, /* Japan (J54) */ + CTRY_JAPAN55 = 4055, /* Japan (J55) */ + CTRY_JAPAN56 = 4056, /* Japan (J56) */ + CTRY_JAPAN57 = 4057, /* Japan (J57) */ + CTRY_JAPAN58 = 4058, /* Japan (J58) */ + CTRY_JAPAN59 = 4059, /* Japan (J59) */ + + /* + ** "Special" codes for multiply defined countries, with the exception + ** of Japan and US. + */ + + CTRY_AUSTRALIA2 = 5000, /* Australia for AP only */ + CTRY_CANADA2 = 5001, /* Canada for AP only */ + CTRY_BELGIUM2 = 5002 /* Belgium/Cisco implementation */ +}; + +int32_t cds_fill_some_regulatory_info(struct regulatory *reg); +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg); +int32_t cds_get_country_from_alpha2(uint8_t *alpha2); +void cds_fill_send_ctl_info_to_fw(struct regulatory *reg, uint32_t modesAvail, + uint32_t modeSelect); +void cds_set_wma_dfs_region(struct regulatory *reg); + +#endif /* REGULATORY_H */ diff --git a/core/cds/inc/cds_regdomain_common.h b/core/cds/inc/cds_regdomain_common.h new file mode 100644 index 0000000000..7feaf55c39 --- /dev/null +++ b/core/cds/inc/cds_regdomain_common.h @@ -0,0 +1,2218 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2011 Atheros Communications, Inc. + * 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. + * + * $FreeBSD: release/9.0.0/sys/dev/ath/ath_hal/ah_regdomain/ah_rd_regenum.h 224226 2011-07-20 12:46:58Z adrian $ + */ +/* + * This module contains the common regulatory domain database tables: + * + * - reg domain enum constants + * - reg domain enum to reg domain pair mappings + * - country to regdomain mappings + * - channel tag enums and the frequency-to-frequency band mappings + * for all the modes + * + * "The country table and respective Regulatory Domain channel and power + * settings are based on available knowledge as of software release. The + * underlying global regulatory and spectrum rules change on a regular basis, + * therefore, no warranty is given that the channel and power information + * herein is complete, accurate or up to date. Developers are responsible + * for regulatory compliance of end-products developed using the enclosed + * data per all applicable national requirements. Furthermore, data in this + * table does not guarantee that spectrum is available and that regulatory + * approval is possible in every case. Knowldegable regulatory compliance + * or government contacts should be consulted by the manufacturer to ensure + * that the most current and accurate settings are used in each end-product. + * This table was designed so that developers are able to update the country + * table mappings as well as the Regulatory Domain definitions in order to + * incorporate the most current channel and power settings in the end-product." + * + */ + +/* Enumerated Regulatory Domain Information 8 bit values indicate that + * the regdomain is really a pair of unitary regdomains. 12 bit values + * are the real unitary regdomains and are the only ones which have the + * frequency bitmasks and flags set. + */ + +#include "cds_ieee80211_common.h" +#include +#include "wlan_defs.h" + +#define MAX_CHANNELS_PER_OPERATING_CLASS 25 + +enum EnumRd { + /* + * The following regulatory domain definitions are + * found in the EEPROM. Each regulatory domain + * can operate in either a 5GHz or 2.4GHz wireless mode or + * both 5GHz and 2.4GHz wireless modes. + * In general, the value holds no special + * meaning and is used to decode into either specific + * 2.4GHz or 5GHz wireless mode for that particular + * regulatory domain. + */ + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, /* For 11b-only countries (no 11a allowed) */ + NULL1_ETSIB = 0x07, /* Israel */ + NULL1_ETSIC = 0x08, + FCC1_FCCA = 0x10, /* USA */ + FCC1_WORLD = 0x11, /* Hong Kong */ + FCC4_FCCA = 0x12, /* USA - Public Safety */ + FCC5_FCCA = 0x13, /* US with no DFS (UNII-1 + UNII-3 Only) */ + FCC6_FCCA = 0x14, /* Canada for AP only */ + + FCC2_FCCA = 0x20, /* Canada */ + FCC2_WORLD = 0x21, /* Australia & HK */ + FCC2_ETSIC = 0x22, + FCC6_WORLD = 0x23, /* Australia for AP only */ + FRANCE_RES = 0x31, /* Legacy France for OEM */ + FCC3_FCCA = 0x3A, /* USA & Canada w/5470 band, 11h, DFS enabled */ + FCC3_WORLD = 0x3B, /* USA & Canada w/5470 band, 11h, DFS enabled */ + FCC3_ETSIC = 0x3F, /* New Zealand, DFS enabled */ + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, /* France (optional) */ + ETSI2_WORLD = 0x35, /* Hungary & others */ + ETSI3_WORLD = 0x36, /* France & others */ + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, /* Bulgaria */ + ETSI8_WORLD = 0x3D, /* Russia */ + ETSI9_WORLD = 0x3E, /* Ukraine */ + ETSI_RESERVED = 0x33, /* Reserved (Do not used) */ + + MKK1_MKKA = 0x40, /* Japan (JP1) */ + MKK1_MKKB = 0x41, /* Japan (JP0) */ + APL4_WORLD = 0x42, /* Singapore and Morocco */ + MKK2_MKKA = 0x43, /* Japan with 4.9G channels */ + APL_RESERVED = 0x44, /* Reserved (Do not used) */ + APL2_WORLD = 0x45, /* Korea */ + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + MKK1_FCCA = 0x48, /* Japan (JP1-1) */ + APL2_APLD = 0x49, /* Korea with 2.3G channels */ + MKK1_MKKA1 = 0x4A, /* Japan (JE1) */ + MKK1_MKKA2 = 0x4B, /* Japan (JE2) */ + MKK1_MKKC = 0x4C, /* Japan (MKK1_MKKA,except Ch14) */ + APL2_FCCA = 0x4D, /* Mobile customer */ + APL11_FCCA = 0x4F, /* Specific AP Customer 5GHz, For APs Only */ + + APL3_FCCA = 0x50, + APL12_WORLD = 0x51, + APL1_WORLD = 0x52, /* Latin America */ + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, /* Venezuela */ + APL5_WORLD = 0x58, /* Chile */ + APL13_WORLD = 0x5A, /* Algeria */ + APL6_WORLD = 0x5B, /* Singapore */ + APL7_FCCA = 0x5C, /* Taiwan 5.47 Band */ + APL8_WORLD = 0x5D, /* Malaysia 5GHz */ + APL9_MKKC = 0x5E, /* Korea 5GHz, Before 11/2007. Now used only by APs */ + APL10_MKKC = 0x5F, /* Korea 5GHz, After 11/2007. For STAs only */ + + /* + * World mode SKUs + */ + WOR0_WORLD = 0x60, /* World0 (WO0 SKU) */ + WOR1_WORLD = 0x61, /* World1 (WO1 SKU) */ + WOR2_WORLD = 0x62, /* World2 (WO2 SKU) */ + WOR3_WORLD = 0x63, /* World3 (WO3 SKU) */ + WOR4_WORLD = 0x64, /* World4 (WO4 SKU) */ + WOR5_ETSIC = 0x65, /* World5 (WO5 SKU) */ + + WOR01_WORLD = 0x66, /* World0-1 (WW0-1 SKU) */ + WOR02_WORLD = 0x67, /* World0-2 (WW0-2 SKU) */ + EU1_WORLD = 0x68, /* Same as World0-2 (WW0-2 SKU), except active scan ch1-13. No ch14 */ + + WOR9_WORLD = 0x69, /* World9 (WO9 SKU) */ + WORA_WORLD = 0x6A, /* WorldA (WOA SKU) */ + WORB_WORLD = 0x6B, /* WorldB (WOB SKU) */ + WORC_WORLD = 0x6C, /* WorldC (WOC SKU) */ + + MKK3_MKKB = 0x80, /* Japan UNI-1 even + MKKB */ + MKK3_MKKA2 = 0x81, /* Japan UNI-1 even + MKKA2 */ + MKK3_MKKC = 0x82, /* Japan UNI-1 even + MKKC */ + + MKK4_MKKB = 0x83, /* Japan UNI-1 even + UNI-2 + MKKB */ + MKK4_MKKA2 = 0x84, /* Japan UNI-1 even + UNI-2 + MKKA2 */ + MKK4_MKKC = 0x85, /* Japan UNI-1 even + UNI-2 + MKKC */ + + MKK5_MKKB = 0x86, /* Japan UNI-1 even + UNI-2 + mid-band + MKKB */ + MKK5_MKKA2 = 0x87, /* Japan UNI-1 even + UNI-2 + mid-band + MKKA2 */ + MKK5_MKKC = 0x88, /* Japan UNI-1 even + UNI-2 + mid-band + MKKC */ + MKK5_FCCA = 0x9A, + + MKK6_MKKB = 0x89, /* Japan UNI-1 even + UNI-1 odd MKKB */ + MKK6_MKKA2 = 0x8A, /* Japan UNI-1 even + UNI-1 odd + MKKA2 */ + MKK6_MKKC = 0x8B, /* Japan UNI-1 even + UNI-1 odd + MKKC */ + + MKK7_MKKB = 0x8C, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKB */ + MKK7_MKKA2 = 0x8D, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA2 */ + MKK7_MKKC = 0x8E, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKC */ + + MKK8_MKKB = 0x8F, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB */ + MKK8_MKKA2 = 0x90, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKA2 */ + MKK8_MKKC = 0x91, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKC */ + + MKK14_MKKA1 = 0x92, /* Japan UNI-1 even + UNI-1 odd + 4.9GHz + MKKA1 */ + MKK15_MKKA1 = 0x93, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + 4.9GHz + MKKA1 */ + + MKK10_FCCA = 0xD0, /* Japan UNI-1 even + UNI-2 + 4.9GHz + FCCA */ + MKK10_MKKA1 = 0xD1, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA1 */ + MKK10_MKKC = 0xD2, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKC */ + MKK10_MKKA2 = 0xD3, /* Japan UNI-1 even + UNI-2 + 4.9GHz + MKKA2 */ + + MKK11_MKKA = 0xD4, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA */ + MKK11_FCCA = 0xD5, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + FCCA */ + MKK11_MKKA1 = 0xD6, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA1 */ + MKK11_MKKC = 0xD7, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKC */ + MKK11_MKKA2 = 0xD8, /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz + MKKA2 */ + + MKK12_MKKA = 0xD9, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA */ + MKK12_FCCA = 0xDA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + FCCA */ + MKK12_MKKA1 = 0xDB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA1 */ + MKK12_MKKC = 0xDC, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKC */ + MKK12_MKKA2 = 0xDD, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz + MKKA2 */ + + MKK13_MKKB = 0xDE, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + MKKB + All passive + no adhoc */ + + /* Following definitions are used only by s/w to map old + * Japan SKUs. + */ + MKK3_MKKA = 0xF0, /* Japan UNI-1 even + MKKA */ + MKK3_MKKA1 = 0xF1, /* Japan UNI-1 even + MKKA1 */ + MKK3_FCCA = 0xF2, /* Japan UNI-1 even + FCCA */ + MKK4_MKKA = 0xF3, /* Japan UNI-1 even + UNI-2 + MKKA */ + MKK4_MKKA1 = 0xF4, /* Japan UNI-1 even + UNI-2 + MKKA1 */ + MKK4_FCCA = 0xF5, /* Japan UNI-1 even + UNI-2 + FCCA */ + MKK9_MKKA = 0xF6, /* Japan UNI-1 even + 4.9GHz */ + MKK10_MKKA = 0xF7, /* Japan UNI-1 even + UNI-2 + 4.9GHz */ + MKK6_MKKA1 = 0xF8, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA1 */ + MKK6_FCCA = 0xF9, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + FCCA */ + MKK7_MKKA1 = 0xFA, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + MKKA1 */ + MKK7_FCCA = 0xFB, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + FCCA */ + MKK9_FCCA = 0xFC, /* Japan UNI-1 even + 4.9GHz + FCCA */ + MKK9_MKKA1 = 0xFD, /* Japan UNI-1 even + 4.9GHz + MKKA1 */ + MKK9_MKKC = 0xFE, /* Japan UNI-1 even + 4.9GHz + MKKC */ + MKK9_MKKA2 = 0xFF, /* Japan UNI-1 even + 4.9GHz + MKKA2 */ + + /* + * Regulator domains ending in a number (e.g. APL1, + * MK1, ETSI4, etc) apply to 5GHz channel and power + * information. Regulator domains ending in a letter + * (e.g. APLA, FCCA, etc) apply to 2.4GHz channel and + * power information. + */ + APL1 = 0x0150, /* LAT & Asia */ + APL2 = 0x0250, /* LAT & Asia */ + APL3 = 0x0350, /* Taiwan */ + APL4 = 0x0450, /* Jordan */ + APL5 = 0x0550, /* Chile */ + APL6 = 0x0650, /* Singapore */ + APL7 = 0x0750, /* Taiwan, disable ch52 */ + APL8 = 0x0850, /* Malaysia */ + APL9 = 0x0950, /* Korea. Before 11/2007. Now used only by APs */ + APL10 = 0x1050, /* Korea. After 11/2007. For STAs only */ + APL11 = 0x1150, /* Specific AP Customer 5GHz, For APs Only */ + APL12 = 0x1160, /* Kenya */ + + ETSI1 = 0x0130, /* Europe & others */ + ETSI2 = 0x0230, /* Europe & others */ + ETSI3 = 0x0330, /* Europe & others */ + ETSI4 = 0x0430, /* Europe & others */ + ETSI5 = 0x0530, /* Europe & others */ + ETSI6 = 0x0630, /* Europe & others */ + ETSI8 = 0x0830, /* Russia */ + ETSI9 = 0x0930, /* Ukraine */ + ETSIA = 0x0A30, /* France */ + ETSIB = 0x0B30, /* Israel */ + ETSIC = 0x0C30, /* Latin America */ + + FCC1 = 0x0110, /* US & others */ + FCC2 = 0x0120, /* Canada, Australia & New Zealand */ + FCC3 = 0x0160, /* US w/new middle band & DFS */ + FCC4 = 0x0165, /* US Public Safety */ + FCC5 = 0x0510, + FCC6 = 0x0610, /* Canada & Australia */ + FCCA = 0x0A10, + + APLD = 0x0D50, /* South Korea */ + + MKK1 = 0x0140, /* Japan (UNI-1 odd) */ + MKK2 = 0x0240, /* Japan (4.9 GHz + UNI-1 odd) */ + MKK3 = 0x0340, /* Japan (UNI-1 even) */ + MKK4 = 0x0440, /* Japan (UNI-1 even + UNI-2) */ + MKK5 = 0x0540, /* Japan (UNI-1 even + UNI-2 + mid-band) */ + MKK6 = 0x0640, /* Japan (UNI-1 odd + UNI-1 even) */ + MKK7 = 0x0740, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 */ + MKK8 = 0x0840, /* Japan (UNI-1 odd + UNI-1 even + UNI-2 + mid-band) */ + MKK9 = 0x0940, /* Japan (UNI-1 even + 4.9 GHZ) */ + MKK10 = 0x0B40, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK11 = 0x1140, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK12 = 0x1240, /* Japan (UNI-1 even + UNI-2 + 4.9 GHZ) */ + MKK13 = 0x0C40, /* Same as MKK8 but all passive and no adhoc 11a */ + MKK14 = 0x1440, /* Japan UNI-1 even + UNI-1 odd + 4.9GHz */ + MKK15 = 0x1540, /* Japan UNI-1 even + UNI-1 odd + UNI-2 + 4.9GHz */ + MKKA = 0x0A40, /* Japan */ + MKKC = 0x0A50, + + NULL1 = 0x0198, + WORLD = 0x0199, + DEBUG_REG_DMN = 0x01ff, +}; + +enum { /* conformance test limits */ + FCC = 0x10, + MKK = 0x40, + ETSI = 0x30, +}; +/* + * The following are flags for different requirements per reg domain. + * These requirements are either inhereted from the reg domain pair or + * from the unitary reg domain if the reg domain pair flags value is + * 0 + */ + +enum { + NO_REQ = 0x00000000, + DISALLOW_ADHOC_11A = 0x00000001, + DISALLOW_ADHOC_11A_TURB = 0x00000002, + NEED_NFC = 0x00000004, + + ADHOC_PER_11D = 0x00000008, /* Start Ad-Hoc mode */ + ADHOC_NO_11A = 0x00000010, + + PUBLIC_SAFETY_DOMAIN = 0x00000020, /* public safety domain */ + LIMIT_FRAME_4MS = 0x00000040, /* 4msec limit on the frame length */ + + NO_HOSTAP = 0x00000080, /* No HOSTAP mode opereation */ + + REQ_MASK = 0x000000FF, /* Requirements bit mask */ +}; + +static const REG_DMN_PAIR_MAPPING ah_cmn_reg_domain_pairs[] = { + {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN, NO_REQ, NO_REQ, PSCAN_DEFER, + 0}, + {NULL1_WORLD, NULL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {NULL1_ETSIB, NULL1, ETSIB, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {NULL1_ETSIC, NULL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + + {FCC2_FCCA, FCC2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC2_WORLD, FCC2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC2_ETSIC, FCC2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC3_FCCA, FCC3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC3_ETSIC, FCC3, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC4_FCCA, FCC4, FCCA, DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + NO_REQ, PSCAN_DEFER, 0}, + {FCC5_FCCA, FCC5, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC6_FCCA, FCC6, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC6_WORLD, FCC6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + + {ETSI1_WORLD, ETSI1, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI2_WORLD, ETSI2, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI3_WORLD, ETSI3, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI4_WORLD, ETSI4, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI5_WORLD, ETSI5, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI6_WORLD, ETSI6, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI8_WORLD, ETSI8, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {ETSI9_WORLD, ETSI9, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + + {ETSI3_ETSIA, ETSI3, WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {FRANCE_RES, ETSI3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + + {FCC1_WORLD, FCC1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {FCC1_FCCA, FCC1, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL1_WORLD, APL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL2_WORLD, APL2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL2_FCCA, APL2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL3_WORLD, APL3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL4_WORLD, APL4, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL5_WORLD, APL5, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL6_WORLD, APL6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL7_FCCA, APL7, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL8_WORLD, APL8, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL9_MKKC, APL9, MKKC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL10_MKKC, APL10, MKKC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL3_FCCA, APL3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL1_ETSIC, APL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {APL2_ETSIC, APL2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + + {MKK1_MKKA, MKK1, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA, CTRY_JAPAN}, + {MKK1_MKKB, MKK1, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, + CTRY_JAPAN1}, + {MKK1_FCCA, MKK1, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1, CTRY_JAPAN2}, + {MKK1_MKKA1, MKK1, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN4}, + {MKK1_MKKA2, MKK1, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN5}, + {MKK1_MKKC, MKK1, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1, CTRY_JAPAN6}, + + /* MKK2 */ + {MKK2_MKKA, MKK2, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKKA | PSCAN_MKKA_G, + CTRY_JAPAN3}, + + /* MKK3 */ + {MKK3_MKKA, MKK3, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKKA, CTRY_JAPAN25}, + {MKK3_MKKB, MKK3, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN7}, + {MKK3_MKKA1, MKK3, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN26}, + {MKK3_MKKA2, MKK3, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN8}, + {MKK3_MKKC, MKK3, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + NO_PSCAN, CTRY_JAPAN9}, + {MKK3_FCCA, MKK3, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + NO_PSCAN, CTRY_JAPAN27}, + + /* MKK4 */ + {MKK4_MKKA, MKK4, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN36}, + {MKK4_MKKB, MKK4, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, + CTRY_JAPAN10}, + {MKK4_MKKA1, MKK4, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN28}, + {MKK4_MKKA2, MKK4, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN11}, + {MKK4_MKKC, MKK4, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN12}, + {MKK4_FCCA, MKK4, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN29}, + + /* MKK5 */ +/* {MKK5_MKKA, MKK5, MKKA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN56 },*/ + {MKK5_MKKB, MKK5, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, + CTRY_JAPAN13}, + {MKK5_MKKA2, MKK5, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN14}, + {MKK5_MKKC, MKK5, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN15}, + {MKK5_FCCA, MKK5, FCCA, DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN56 }, + + /* MKK6 */ + {MKK6_MKKB, MKK6, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN16}, + {MKK6_MKKA1, MKK6, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN30}, + {MKK6_MKKA2, MKK6, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN17}, + {MKK6_MKKC, MKK6, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1, CTRY_JAPAN18}, + {MKK6_FCCA, MKK6, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1, CTRY_JAPAN31}, + + /* MKK7 */ + {MKK7_MKKB, MKK7, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN19}, + {MKK7_MKKA1, MKK7, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN32}, + {MKK7_MKKA2, MKK7, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN20}, + {MKK7_MKKC, MKK7, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN21}, + {MKK7_FCCA, MKK7, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN33}, + + /* MKK8 */ + {MKK8_MKKB, MKK8, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN22}, + {MKK8_MKKA2, MKK8, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN23}, + {MKK8_MKKC, MKK8, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN24}, + + {MKK9_MKKA, MKK9, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN34}, + {MKK9_FCCA, MKK9, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + NO_PSCAN, CTRY_JAPAN37}, + {MKK9_MKKA1, MKK9, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN38}, + {MKK9_MKKA2, MKK9, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN40}, + {MKK9_MKKC, MKK9, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + NO_PSCAN, CTRY_JAPAN39}, + + {MKK10_MKKA, MKK10, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3, CTRY_JAPAN35}, + {MKK10_FCCA, MKK10, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN41}, + {MKK10_MKKA1, MKK10, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN42}, + {MKK10_MKKA2, MKK10, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN44}, + {MKK10_MKKC, MKK10, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN43}, + + {MKK11_MKKA, MKK11, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN45}, + {MKK11_FCCA, MKK11, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN46}, + {MKK11_MKKA1, MKK11, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN47}, + {MKK11_MKKA2, MKK11, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN49}, + {MKK11_MKKC, MKK11, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK3, CTRY_JAPAN48}, + + {MKK12_MKKA, MKK12, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN50}, + {MKK12_FCCA, MKK12, FCCA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN51}, + {MKK12_MKKA1, MKK12, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN52}, + {MKK12_MKKA2, MKK12, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN54}, + {MKK12_MKKC, MKK12, MKKC, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN53}, + + {MKK13_MKKB, MKK13, MKKA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC | + LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN57}, + + {MKK14_MKKA1, MKK14, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN58}, + {MKK15_MKKA1, MKK15, MKKA, + DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC, + PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN59}, + + /* These are super domains */ + {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, DISALLOW_ADHOC_11A_TURB, NO_REQ, + PSCAN_DEFER, 0}, + {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {WOR4_WORLD, WOR4_WORLD, WOR4_WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {EU1_WORLD, EU1_WORLD, EU1_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, + {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WORA_WORLD, WORA_WORLD, WORA_WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WORB_WORLD, WORB_WORLD, WORB_WORLD, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER, 0}, + {WORC_WORLD, WORC_WORLD, WORC_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0}, +}; + +static const COUNTRY_CODE_TO_ENUM_RD ah_cmn_all_countries[] = { + {CTRY_DEBUG, NO_ENUMRD, "DB", "DEBUG", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_DEFAULT, DEF_REGDMN, "NA", "NO_COUNTRY_SET", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_ALBANIA, NULL1_WORLD, "AL", "ALBANIA", YES, NO, YES, YES, YES, NO, + NO, NO, 7000}, + {CTRY_ALGERIA, NULL1_WORLD, "DZ", "ALGERIA", YES, NO, YES, YES, YES, NO, + NO, NO, 7000}, + {CTRY_ARGENTINA, FCC3_WORLD, "AR", "ARGENTINA", YES, NO, NO, YES, YES, + YES, YES, YES, 7000}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA", YES, NO, YES, YES, YES, + YES, NO, NO, 7000}, + {CTRY_ARUBA, ETSI1_WORLD, "AW", "ARUBA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_AUSTRALIA, FCC3_WORLD, "AU", "AUSTRALIA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_AUSTRALIA2, FCC6_WORLD, "AU", "AUSTRALIA2", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS", "BAHAMAS", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BAHRAIN, APL6_WORLD, "BH", "BAHRAIN", YES, NO, YES, YES, YES, YES, + NO, NO, 7000}, + {CTRY_BANGLADESH, NULL1_WORLD, "BD", "BANGLADESH", YES, NO, YES, YES, + YES, NO, NO, NO, 7000}, + {CTRY_BARBADOS, FCC2_WORLD, "BB", "BARBADOS", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BELGIUM2, ETSI4_WORLD, "BE", "BELGIUM2", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BELIZE, APL1_ETSIC, "BZ", "BELIZE", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_BERMUDA, FCC3_FCCA, "BM", "BERMUDA", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_BOLIVIA, APL1_ETSIC, "BO", "BOLIVIA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA", "BOSNIA AND HERZEGOVINA", YES, NO, + YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_BRAZIL, FCC3_WORLD, "BR", "BRAZIL", YES, NO, NO, YES, YES, YES, + YES, YES, 7000}, + {CTRY_BRUNEI_DARUSSALAM, APL6_WORLD, "BN", "BRUNEI DARUSSALAM", YES, + YES, YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_BULGARIA, ETSI1_WORLD, "BG", "BULGARIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_CAMBODIA, ETSI1_WORLD, "KH", "CAMBODIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_CANADA, FCC3_FCCA, "CA", "CANADA", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_CANADA2, FCC6_FCCA, "CA", "CANADA2", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_CHILE, APL6_WORLD, "CL", "CHILE", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_CHINA, APL1_WORLD, "CN", "CHINA", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_COLOMBIA, FCC1_FCCA, "CO", "COLOMBIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_COSTA_RICA, FCC1_WORLD, "CR", "COSTA RICA", YES, NO, YES, YES, + YES, YES, NO, NO, 7000}, + {CTRY_CROATIA, ETSI1_WORLD, "HR", "CROATIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_CZECH, ETSI1_WORLD, "CZ", "CZECH REPUBLIC", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO", "DOMINICAN REPUBLIC", YES, + YES, YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_ECUADOR, FCC1_WORLD, "EC", "ECUADOR", YES, NO, NO, YES, YES, YES, + NO, NO, 7000}, + {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT", YES, NO, YES, YES, YES, YES, + NO, NO, 7000}, + {CTRY_EL_SALVADOR, FCC1_WORLD, "SV", "EL SALVADOR", YES, NO, YES, YES, + YES, YES, NO, NO, 7000}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_GREENLAND, ETSI1_WORLD, "GL", "GREENLAND", YES, NO, YES, YES, YES, + YES, NO, NO, 7000}, + {CTRY_GRENADA, FCC3_FCCA, "GD", "GRENADA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_GUAM, FCC1_FCCA, "GU", "GUAM", YES, NO, YES, YES, YES, YES, NO, + NO, 7000}, + {CTRY_GUATEMALA, FCC1_FCCA, "GT", "GUATEMALA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_HAITI, ETSI1_WORLD, "HT", "HAITI", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_HONDURAS, FCC3_WORLD, "HN", "HONDURAS", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_HONG_KONG, FCC3_WORLD, "HK", "HONG KONG", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_INDIA, APL6_WORLD, "IN", "INDIA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_INDONESIA, APL2_WORLD, "ID", "INDONESIA", YES, NO, YES, YES, YES, + YES, NO, NO, 7000}, + {CTRY_IRAN, APL1_WORLD, "IR", "IRAN", YES, YES, YES, YES, YES, YES, YES, + YES, 7000}, + {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_ISRAEL, ETSI3_WORLD, "IL", "ISRAEL", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_JAMAICA, FCC3_WORLD, "JM", "JAMAICA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_JAPAN, MKK5_MKKA2, "JP", "JAPAN", YES, NO, NO, YES, YES, YES, NO, + NO, 7000}, + {CTRY_JAPAN1, MKK1_MKKB, "JP", "JAPAN1", YES, NO, NO, YES, YES, YES, NO, + NO, 7000}, + {CTRY_JAPAN2, MKK1_FCCA, "JP", "JAPAN2", YES, NO, NO, YES, YES, YES, NO, + NO, 7000}, + {CTRY_JAPAN3, MKK2_MKKA, "JP", "JAPAN3", YES, NO, NO, YES, YES, YES, NO, + NO, 7000}, + {CTRY_JAPAN4, MKK1_MKKA1, "JP", "JAPAN4", YES, NO, NO, YES, YES, YES, + NO, NO, 7000}, + {CTRY_JAPAN5, MKK1_MKKA2, "JP", "JAPAN5", YES, NO, NO, YES, YES, YES, + NO, NO, 7000}, + {CTRY_JAPAN6, MKK1_MKKC, "JP", "JAPAN6", YES, NO, NO, YES, YES, YES, NO, + NO, 7000}, + {CTRY_JAPAN7, MKK3_MKKB, "JP", "JAPAN7", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN8, MKK3_MKKA2, "JP", "JAPAN8", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN9, MKK3_MKKC, "JP", "JAPAN9", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN10, MKK4_MKKB, "JP", "JAPAN10", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN11, MKK4_MKKA2, "JP", "JAPAN11", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN12, MKK4_MKKC, "JP", "JAPAN12", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN13, MKK5_MKKB, "JP", "JAPAN13", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN14, MKK5_MKKA2, "JP", "JAPAN14", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN15, MKK5_MKKC, "JP", "JAPAN15", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN16, MKK6_MKKB, "JP", "JAPAN16", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN17, MKK6_MKKA2, "JP", "JAPAN17", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN18, MKK6_MKKC, "JP", "JAPAN18", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN19, MKK7_MKKB, "JP", "JAPAN19", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN20, MKK7_MKKA2, "JP", "JAPAN20", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN21, MKK7_MKKC, "JP", "JAPAN21", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN22, MKK8_MKKB, "JP", "JAPAN22", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN23, MKK8_MKKA2, "JP", "JAPAN23", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN24, MKK8_MKKC, "JP", "JAPAN24", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN25, MKK3_MKKA, "JP", "JAPAN25", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN26, MKK3_MKKA1, "JP", "JAPAN26", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN27, MKK3_FCCA, "JP", "JAPAN27", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN28, MKK4_MKKA1, "JP", "JAPAN28", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN29, MKK4_FCCA, "JP", "JAPAN29", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN30, MKK6_MKKA1, "JP", "JAPAN30", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN31, MKK6_FCCA, "JP", "JAPAN31", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN32, MKK7_MKKA1, "JP", "JAPAN32", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN33, MKK7_FCCA, "JP", "JAPAN33", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN34, MKK9_MKKA, "JP", "JAPAN34", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN35, MKK10_MKKA, "JP", "JAPAN35", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN36, MKK4_MKKA, "JP", "JAPAN36", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN37, MKK9_FCCA, "JP", "JAPAN37", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN38, MKK9_MKKA1, "JP", "JAPAN38", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN39, MKK9_MKKC, "JP", "JAPAN39", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN40, MKK9_MKKA2, "JP", "JAPAN40", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN41, MKK10_FCCA, "JP", "JAPAN41", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN42, MKK10_MKKA1, "JP", "JAPAN42", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN43, MKK10_MKKC, "JP", "JAPAN43", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN44, MKK10_MKKA2, "JP", "JAPAN44", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN45, MKK11_MKKA, "JP", "JAPAN45", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN46, MKK11_FCCA, "JP", "JAPAN46", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN47, MKK11_MKKA1, "JP", "JAPAN47", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN48, MKK11_MKKC, "JP", "JAPAN48", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN49, MKK11_MKKA2, "JP", "JAPAN49", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN50, MKK12_MKKA, "JP", "JAPAN50", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN51, MKK12_FCCA, "JP", "JAPAN51", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN52, MKK12_MKKA1, "JP", "JAPAN52", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN53, MKK12_MKKC, "JP", "JAPAN53", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN54, MKK12_MKKA2, "JP", "JAPAN54", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, +/* {CTRY_JAPAN55, MKK5_MKKA, "JP", "JAPAN55", YES, NO, NO, YES, YES, YES, YES, NO, 7000 },*/ + {CTRY_JAPAN56, MKK5_FCCA, "JP", "JAPAN56", YES, NO, NO, + YES, YES, YES, YES, NO, 7000 }, + {CTRY_JAPAN57, MKK13_MKKB, "JP", "JAPAN57", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN58, MKK14_MKKA1, "JP", "JAPAN58", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JAPAN59, MKK15_MKKA1, "JP", "JAPAN59", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_JORDAN, ETSI2_WORLD, "JO", "JORDAN", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN", YES, NO, YES, YES, + YES, NO, NO, NO, 7000}, + {CTRY_KENYA, APL1_WORLD, "KE", "KENYA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_KOREA_NORTH, APL9_MKKC, "KP", "NORTH KOREA", YES, NO, NO, YES, + NO, YES, NO, NO, 7000}, + {CTRY_KOREA_ROC, APL10_MKKC, "KR", "KOREA REPUBLIC", YES, NO, NO, YES, + YES, YES, YES, YES, 7000}, + {CTRY_KOREA_ROC3, APL9_MKKC, "KR", "KOREA REPUBLIC3", YES, NO, NO, YES, + NO, YES, NO, NO, 7000}, + {CTRY_KUWAIT, ETSI3_WORLD, "KW", "KUWAIT", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_LEBANON, APL1_WORLD, "LB", "LEBANON", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI", "LIECHTENSTEIN", YES, NO, YES, + YES, YES, YES, YES, YES, 7000}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_MACAU, FCC2_WORLD, "MO", "MACAU SAR", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_MACEDONIA, ETSI1_WORLD, "MK", "MACEDONIA, FYRO", YES, NO, YES, + YES, YES, YES, YES, YES, 7000}, + {CTRY_MALAYSIA, FCC1_WORLD, "MY", "MALAYSIA", YES, NO, NO, YES, YES, + YES, YES, YES, 7000}, + {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_MAURITIUS, ETSI1_WORLD, "MU", "MAURITIUS", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_MEXICO, FCC1_WORLD, "MX", "MEXICO", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_MONACO, ETSI4_WORLD, "MC", "MONACO", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_MOROCCO, APL4_WORLD, "MA", "MOROCCO", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_NEPAL, APL1_WORLD, "NP", "NEPAL", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN", "NETHERLANDS ANTILLES", + YES, NO, YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_NEW_ZEALAND, FCC3_ETSIC, "NZ", "NEW ZEALAND", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_NICARAGUA, FCC3_FCCA, "NI", "NICARAGUA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_OMAN, FCC3_WORLD, "OM", "OMAN", YES, NO, YES, YES, YES, YES, YES, + YES, 7000}, + {CTRY_PAKISTAN, APL1_WORLD, "PK", "PAKISTAN", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG", "PAPUA NEW GUINEA", YES, YES, + YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_PARAGUAY, FCC3_WORLD, "PY", "PARAGUAY", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_PERU, FCC3_WORLD, "PE", "PERU", YES, NO, YES, YES, YES, YES, YES, + YES, 7000}, + {CTRY_PHILIPPINES, FCC3_WORLD, "PH", "PHILIPPINES", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_PUERTO_RICO, FCC1_FCCA, "PR", "PUERTO RICO", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_QATAR, APL1_WORLD, "QA", "QATAR", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_ROMANIA, ETSI1_WORLD, "RO", "ROMANIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_RUSSIA, ETSI8_WORLD, "RU", "RUSSIA", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_RWANDA, APL1_WORLD, "RW", "RWANDA", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_SAUDI_ARABIA, FCC2_WORLD, "SA", "SAUDI ARABIA", YES, NO, YES, YES, + YES, YES, NO, NO, 7000}, + {CTRY_SERBIA, ETSI1_WORLD, "RS", "REPUBLIC OF SERBIA", YES, NO, YES, + YES, YES, YES, YES, YES, 7000}, + {CTRY_MONTENEGRO, ETSI1_WORLD, "ME", "MONTENEGRO", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_SINGAPORE, FCC3_WORLD, "SG", "SINGAPORE", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAKIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA", "SOUTH AFRICA", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK", "SRI LANKA", YES, NO, YES, YES, YES, + YES, NO, NO, 7000}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIAN ARAB REPUBLIC", YES, NO, YES, + YES, YES, NO, NO, NO, 7000}, + {CTRY_TAIWAN, APL7_FCCA, "TW", "TAIWAN", YES, YES, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_TANZANIA, APL1_WORLD, "TZ", "TANZANIA", YES, YES, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_THAILAND, FCC3_WORLD, "TH", "THAILAND", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT", "TRINIDAD AND TOBAGO", YES, + NO, YES, YES, YES, YES, YES, YES, 7000}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA", YES, NO, YES, YES, YES, + YES, NO, NO, 7000}, + {CTRY_TURKEY, ETSI3_WORLD, "TR", "TURKEY", YES, NO, YES, YES, YES, YES, + NO, NO, 7000}, + {CTRY_UGANDA, FCC3_WORLD, "UG", "UGANDA", YES, NO, NO, YES, YES, YES, + YES, YES, 7000}, + {CTRY_UKRAINE, ETSI9_WORLD, "UA", "UKRAINE", YES, NO, NO, YES, YES, YES, + YES, NO, 7000}, + {CTRY_UAE, ETSI1_WORLD, "AE", "UNITED ARAB EMIRATES", YES, NO, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB", "UNITED KINGDOM", YES, NO, YES, + YES, YES, YES, YES, YES, 7000}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US", "UNITED STATES", YES, YES, YES, + YES, YES, YES, YES, YES, 5825}, + {CTRY_UNITED_STATES2, FCC6_FCCA, "US", "UNITED STATES2", YES, YES, YES, + YES, YES, YES, YES, YES, 7000}, + {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS", + "UNITED STATES (PUBLIC SAFETY)", YES, YES, YES, YES, YES, YES, YES, + YES, 7000}, + {CTRY_URUGUAY, FCC3_WORLD, "UY", "URUGUAY", YES, NO, YES, YES, YES, YES, + YES, YES, 7000}, + {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ", "UZBEKISTAN", YES, YES, YES, YES, + YES, YES, YES, YES, 7000}, + {CTRY_VENEZUELA, FCC1_WORLD, "VE", "VENEZUELA", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_VIET_NAM, ETSI3_WORLD, "VN", "VIET NAM", YES, NO, YES, YES, YES, + YES, YES, YES, 7000}, + {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN", YES, NO, YES, YES, YES, NO, NO, + NO, 7000}, + {CTRY_ZIMBABWE, NULL1_WORLD, "ZW", "ZIMBABWE", YES, NO, YES, YES, YES, + NO, NO, NO, 7000} +}; + +/* Bit masks for DFS per regdomain */ + +enum { + NO_DFS = 0x0000000000000000ULL, + DFS_FCC3 = 0x0000000000000001ULL, + DFS_ETSI = 0x0000000000000002ULL, + DFS_MKK4 = 0x0000000000000004ULL, +}; + +/* The table of frequency bands is indexed by a bitmask. The ordering + * must be consistent with the enum below. When adding a new + * frequency band, be sure to match the location in the enum with the + * comments + */ + +/* + * 5GHz 11A channel tags + */ +enum { + F1_4912_4947, + F1_4915_4925, + F2_4915_4925, + F1_4935_4945, + F2_4935_4945, + F1_4920_4980, + F2_4920_4980, + F1_4942_4987, + F1_4945_4985, + F1_4950_4980, + F1_5032_5057, + F1_5035_5040, + F2_5035_5040, + F1_5035_5045, + F1_5040_5040, + F1_5040_5080, + F2_5040_5080, + F1_5055_5055, + F2_5055_5055, + + F1_5120_5240, + + F1_5170_5230, + F2_5170_5230, + + F1_5180_5240, + F2_5180_5240, + F3_5180_5240, + F4_5180_5240, + F5_5180_5240, + F6_5180_5240, + F7_5180_5240, + F8_5180_5240, + F9_5180_5240, + F10_5180_5240, + + F1_5240_5280, + + F1_5260_5280, + + F1_5260_5320, + F2_5260_5320, + F3_5260_5320, + F4_5260_5320, + F5_5260_5320, + F6_5260_5320, + F7_5260_5320, + + F1_5260_5700, + + F1_5280_5320, + F2_5280_5320, + F1_5500_5560, + + F1_5500_5580, + F2_5500_5580, + + F1_5500_5620, + + F1_5500_5660, + + F1_5500_5720, + F2_5500_5700, + F3_5500_5700, + F4_5500_5700, + F5_5500_5700, + F6_5500_5700, + + F1_5660_5700, + F2_5660_5720, + F3_5660_5720, + + F1_5745_5765, + + F1_5745_5805, + F2_5745_5805, + F3_5745_5805, + F4_5745_5805, + + F1_5745_5825, + F2_5745_5825, + F3_5745_5825, + F4_5745_5825, + F5_5745_5825, + F6_5745_5825, + F7_5745_5825, + F8_5745_5825, + F9_5745_5825, + + F1_5845_5865, + + W1_4920_4980, + W1_5040_5080, + W1_5170_5230, + W1_5180_5240, + W1_5260_5320, + W1_5745_5825, + W1_5500_5700, + A_DEMO_ALL_CHANNELS +}; + +static const REG_DMN_FREQ_BAND reg_dmn5_ghz_freq[] = { + {4915, 4925, 20, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, /* F1_4915_4925 */ + {4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, /* F2_4915_4925 */ + {4935, 4945, 20, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, /* F1_4935_4945 */ + {4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16}, /* F2_4935_4945 */ + {4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7}, /* F1_4920_4980 */ + {4920, 4980, 20, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7}, /* F2_4920_4980 */ + {4942, 4987, 27, 6, 5, 5, NO_DFS, PSCAN_FCC, 0}, /* F1_4942_4987 */ + {4945, 4985, 30, 6, 10, 5, NO_DFS, PSCAN_FCC, 0}, /* F1_4945_4985 */ + {4950, 4980, 33, 6, 20, 5, NO_DFS, PSCAN_FCC, 0}, /* F1_4950_4980 */ + {5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, /* F1_5035_5040 */ + {5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, /* F2_5035_5040 */ + {5040, 5040, 20, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, /* F1_5040_5040 */ + {5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2}, /* F1_5040_5080 */ + {5040, 5080, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 6}, /* F2_5040_5080 */ + {5055, 5055, 20, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, /* F1_5055_5055 */ + {5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12}, /* F2_5055_5055 */ + + {5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, /* F1_5120_5240 */ + + {5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1}, /* F1_5170_5230 */ + {5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1}, /* F2_5170_5230 */ + + {5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 1}, /* F1_5180_5240 */ + {5180, 5240, 17, 6, 20, 20, NO_DFS, NO_PSCAN, 1}, /* F2_5180_5240 */ + {5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 1}, /* F3_5180_5240 */ + {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 1}, /* F4_5180_5240 */ + {5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 1}, /* F5_5180_5240 */ + {5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 1}, /* F6_5180_5240 */ + {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK3, 0}, /* F7_5180_5240 */ + {5180, 5240, 23, 6, 20, 20, NO_DFS, NO_PSCAN, 1}, /* F8_5180_5240 */ + {5180, 5240, 20, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, /* F9_5180_5240 */ + {5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 1}, /* F10_5180_5240 */ + + {5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0}, /* F1_5240_5280 */ + + {5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 2}, /* F1_5260_5280 */ + + {5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 2}, /* F1_5260_5320 */ + + {5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, + PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3, 0}, + /* F2_5260_5320 */ + + {5260, 5320, 24, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 2}, /* F3_5260_5320 */ + {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2}, /* F4_5260_5320 */ + {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2}, /* F5_5260_5320 */ + {5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 2}, /* F6_5260_5320 */ + {5260, 5320, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, + PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3, 0}, + /* F7_5260_5320 */ + + {5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0}, /* F1_5260_5700 */ + + {5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2}, /* F1_5280_5320 */ + + {5500, 5580, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 4}, /* F1_5500_5580 */ + {5500, 5580, 30, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 4}, /* F2_5500_5580 */ + + {5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 3}, /* F1_5500_5620 */ + + {5500, 5660, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 0}, /* F1_5500_5660 */ + + {5500, 5720, 24, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4}, /* F1_5500_5720 */ + {5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 3}, /* F2_5500_5700 */ + {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 3}, /* F3_5500_5700 */ + {5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC, 0}, /* F4_5500_5700 */ + {5500, 5700, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0}, /* F5_5500_5700 */ + {5500, 5700, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4, PSCAN_MKK3 | PSCAN_FCC, 0}, /* F6_5500_5700 */ + + {5660, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 4}, /* F1_5660_5700 */ + {5660, 5700, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 4}, /* F2_5660_5700 */ + {5660, 5700, 30, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, 4}, /* F3_5660_5700 */ + + {5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 3}, /* F1_5745_5805 */ + {5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3}, /* F2_5745_5805 */ + {5745, 5805, 30, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, /* F3_5745_5805 */ + {5745, 5805, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, /* F4_5745_5805 */ + + {5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 5}, /* F1_5745_5825 */ + {5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 5}, /* F2_5745_5825 */ + {5745, 5825, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, /* F3_5745_5825 */ + {5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0}, /* F4_5745_5825 */ + {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 5}, /* F5_5745_5825 */ + {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 5}, /* F6_5745_5825 */ + {5745, 5825, 30, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, /* F7_5745_5825 */ + {5745, 5825, 20, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0}, /* F8_5745_5825 */ + + /* + * Below are the world roaming channels + * All WWR domains have no power limit, instead use the card's CTL + * or max power settings. + */ + {4920, 4980, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, /* W1_4920_4980 */ + {5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, /* W1_5040_5080 */ + {5170, 5230, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, /* W1_5170_5230 */ + {5180, 5240, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, /* W1_5180_5240 */ + {5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, /* W1_5260_5320 */ + {5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0}, /* W1_5745_5825 */ + {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0}, /* W1_5500_5700 */ + {4920, 6100, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0}, /* A_DEMO_ALL_CHANNELS */ +}; + +/* + * 2GHz 11b channel tags + */ +enum { + F1_2312_2372, + F2_2312_2372, + + F1_2412_2472, + F2_2412_2472, + F3_2412_2472, + F4_2412_2472, + + F1_2412_2462, + F2_2412_2462, + + F1_2432_2442, + + F1_2457_2472, + + F1_2467_2472, + + F1_2484_2484, + F2_2484_2484, + + F1_2512_2732, + + W1_2312_2372, + W1_2412_2412, + W1_2417_2432, + W1_2437_2442, + W1_2447_2457, + W1_2462_2462, + W1_2467_2467, + W2_2467_2467, + W1_2472_2472, + W2_2472_2472, + W1_2484_2484, + W2_2484_2484, +}; + +static const REG_DMN_FREQ_BAND reg_dmn2_ghz_freq[] = { + {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2312_2372 */ + {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F2_2312_2372 */ + + {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2412_2472 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 30}, /* F2_2412_2472 */ + {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 4}, /* F3_2412_2472 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0}, /* F4_2412_2472 */ + + {2412, 2462, 30, 6, 20, 5, NO_DFS, NO_PSCAN, 12}, /* F1_2412_2462 */ + {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 30}, /* F2_2412_2462 */ + + {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 4}, /* F1_2432_2442 */ + + {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2457_2472 */ + + {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 30}, /* F1_2467_2472 */ + + {2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2484_2484 */ + {2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 31}, /* F2_2484_2484 */ + + {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* F1_2512_2732 */ + + /* + * WWR have powers opened up to 20dBm. Limits should often come from CTL/Max powers + */ + + {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2312_2372 */ + {2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2412_2412 */ + {2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2417_2432 */ + {2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2437_2442 */ + {2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2447_2457 */ + {2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* W1_2462_2462 */ + {2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2467_2467 */ + {2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2467_2467 */ + {2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2472_2472 */ + {2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2472_2472 */ + {2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0}, /* W1_2484_2484 */ + {2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* W2_2484_2484 */ +}; + +/* + * 2GHz 11g channel tags + */ + +enum { + G1_2312_2372, + G2_2312_2372, + + G1_2412_2472, + G2_2412_2472, + G3_2412_2472, + G4_2412_2472, + + G1_2412_2462, + G2_2412_2462, + + G1_2432_2442, + + G1_2457_2472, + + G1_2512_2732, + + G1_2467_2472, + G2_2467_2472, + + G1_2484_2484, + + WG1_2312_2372, + WG1_2412_2462, + WG1_2412_2472, + WG2_2412_2472, + G_DEMO_ALMOST_ALL_CHANNELS, + G_DEMO_ALL_CHANNELS, +}; + +static const REG_DMN_FREQ_BAND reg_dmn2_ghz11g_freq[] = { + {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2312_2372 */ + {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G2_2312_2372 */ + + {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2412_2472 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G | PSCAN_MKKA2 | PSCAN_MKKA | PSCAN_EXT_CHAN, 30}, /* G2_2412_2472 */ + {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 4}, /* G3_2412_2472 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G | PSCAN_MKKA2 | PSCAN_MKKA | PSCAN_EXT_CHAN, 0}, /* G4_2412_2472 */ + + {2412, 2462, 30, 6, 20, 5, NO_DFS, NO_PSCAN, 12}, /* G1_2412_2462 */ + {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 30}, /* G2_2412_2462 */ + + {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 4}, /* G1_2432_2442 */ + + {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2457_2472 */ + + {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2512_2732 */ + + {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 30}, /* G1_2467_2472 */ + {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G | PSCAN_MKKA2, 0}, /* G2_2467_2472 */ + + {2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G1_2484_2484 */ + /* + * WWR open up the power to 20dBm + */ + + {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2312_2372 */ + {2412, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0}, /* WG1_2412_2462 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN | PSCAN_EXT_CHAN, 0}, /* WG1_2412_2472 */ + {2412, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0}, /* WG2_2412_2472 */ + {2312, 2532, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G_DEMO_ALMOST_ALL_CHANNELS */ + {2312, 2732, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0}, /* G_DEMO_ALL_CHANNELS */ +}; + +/* regulatory capabilities */ +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 + +static const JAPAN_BANDCHECK j_bandcheck[] = { + {F1_5170_5230, REGDMN_EEPROM_EEREGCAP_EN_KK_U1_ODD}, + {F4_5180_5240, REGDMN_EEPROM_EEREGCAP_EN_KK_U1_EVEN}, + {F2_5260_5320, REGDMN_EEPROM_EEREGCAP_EN_KK_U2}, + {F4_5500_5700, REGDMN_EEPROM_EEREGCAP_EN_KK_MIDBAND} +}; + +static const COMMON_MODE_POWER common_mode_pwrtbl[] = { + {4900, 5000, 17}, + {5000, 5100, 17}, + {5150, 5250, 17}, /* ETSI & MKK */ + {5250, 5350, 18}, /* ETSI */ + {5470, 5725, 20}, /* ETSI */ + {5725, 5825, 20}, /* Singapore */ + {5825, 5850, 23} /* Korea */ +}; + +/* + * 5GHz Turbo (dynamic & static) tags + */ + +enum { + T1_5130_5650, + T1_5150_5670, + + T1_5200_5200, + T2_5200_5200, + T3_5200_5200, + T4_5200_5200, + T5_5200_5200, + T6_5200_5200, + T7_5200_5200, + T8_5200_5200, + + T1_5200_5280, + T2_5200_5280, + T3_5200_5280, + T4_5200_5280, + T5_5200_5280, + T6_5200_5280, + + T1_5200_5240, + T1_5210_5210, + T2_5210_5210, + T3_5210_5210, + T4_5210_5210, + T5_5210_5210, + T6_5210_5210, + T7_5210_5210, + T8_5210_5210, + T9_5210_5210, + T10_5210_5210, + T1_5240_5240, + + T1_5210_5250, + T1_5210_5290, + T2_5210_5290, + T3_5210_5290, + + T1_5280_5280, + T2_5280_5280, + T1_5290_5290, + T2_5290_5290, + T3_5290_5290, + T1_5250_5290, + T2_5250_5290, + T3_5250_5290, + T4_5250_5290, + + T1_5540_5660, + T2_5540_5660, + T3_5540_5660, + T1_5760_5800, + T2_5760_5800, + T3_5760_5800, + T4_5760_5800, + T5_5760_5800, + T6_5760_5800, + T7_5760_5800, + + T1_5765_5805, + T2_5765_5805, + T3_5765_5805, + T4_5765_5805, + T5_5765_5805, + T6_5765_5805, + T7_5765_5805, + T8_5765_5805, + T9_5765_5805, + + WT1_5210_5250, + WT1_5290_5290, + WT1_5540_5660, + WT1_5760_5800, +}; + +/* + * 2GHz Dynamic turbo tags + */ +#ifndef ATH_REMOVE_2G_TURBO_RD_TABLE +enum { + T1_2312_2372, + T1_2437_2437, + T2_2437_2437, + T3_2437_2437, + T1_2512_2732 +}; + +static const REG_DMN_FREQ_BAND reg_dmn2_ghz11g_turbo_freq[] = { + {2312, 2372, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2312_2372 */ + {2437, 2437, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2437_2437 */ + {2437, 2437, 20, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T2_2437_2437 */ + {2437, 2437, 18, 6, 40, 40, NO_DFS, PSCAN_WWR, 0}, /* T3_2437_2437 */ + {2512, 2732, 5, 6, 40, 40, NO_DFS, NO_PSCAN, 0}, /* T1_2512_2732 */ +}; +#endif /* ATH_REMOVE_2G_TURBO_RD_TABLE */ + +static const REG_DOMAIN ah_cmn_reg_domains[] = { + + {DEBUG_REG_DMN, FCC, DFS_FCC3, NO_PSCAN, NO_REQ, + CHAN_11A_BM(A_DEMO_ALL_CHANNELS, F6_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(T1_5130_5650, T1_5150_5670, F6_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(T1_5200_5240, T1_5280_5280, T1_5540_5660, T1_5765_5805, + -1, -1, -1, -1, -1, -1, -1, -1) + BM(F1_2312_2372, F1_2412_2472, F1_2484_2484, F1_2512_2732, + -1, -1, -1, -1, -1, -1, -1, -1), + BM(G_DEMO_ALMOST_ALL_CHANNELS, + G1_2484_2484, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T1_2312_2372, T1_2437_2437, T1_2512_2732, + -1, -1, -1, -1, -1, -1, -1, -1, -1)}, + + {APL1, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL2, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F1_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL3, FCC, DFS_FCC3, PSCAN_FCC, NO_REQ, + BM(F1_5280_5320, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5290_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL4, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F5_5180_5240, F9_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5210_5210, T3_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5200, T3_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL5, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F2_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T4_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T4_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL6, ETSI, DFS_ETSI, PSCAN_FCC_T | PSCAN_FCC, NO_REQ, + BM(F9_5180_5240, F2_5260_5320, F3_5745_5825, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T2_5210_5210, T1_5250_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T1_5200_5280, T5_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL7, FCC, DFS_FCC3 | DFS_ETSI, PSCAN_FCC | PSCAN_ETSI, NO_REQ, + BM(F2_5280_5320, F2_5500_5580, F3_5660_5720, F7_5745_5825, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL8, ETSI, NO_DFS, NO_PSCAN, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F6_5260_5320, F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5290_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL9, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F9_5180_5240, F2_5260_5320, F1_5500_5620, F3_5745_5805, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL10, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F9_5180_5240, F2_5260_5320, F5_5500_5700, F3_5745_5805, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL11, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F9_5180_5240, F2_5260_5320, F5_5500_5700, F7_5745_5825, + F1_5845_5865, -1, -1, -1, -1, -1, -1, -1), + BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {APL12, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F5_5180_5240, F1_5500_5560, F1_5745_5765, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI1, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F2_5180_5240, F2_5260_5320, F2_5500_5700, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5200_5280, T2_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI2, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F3_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI3, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI4, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F3_5180_5240, F1_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T3_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI5, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F1_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T4_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T3_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI6, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F5_5180_5240, F1_5260_5280, F3_5500_5700, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T1_5210_5250, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T4_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {ETSI8, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, F2_5260_5320, F1_5660_5700, F4_5745_5825, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5200_5280, T2_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + BMZERO}, + + {ETSI9, ETSI, DFS_ETSI, PSCAN_ETSI, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, F2_5260_5320, F1_5500_5660, F8_5745_5825, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T2_5200_5280, T2_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + BMZERO}, + + {FCC1, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F2_5180_5240, F4_5260_5320, F5_5745_5825, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T6_5210_5210, T2_5250_5290, T6_5760_5800, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T1_5200_5240, T2_5280_5280, T7_5765_5805, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {FCC2, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F6_5180_5240, F5_5260_5320, F6_5745_5825, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1, -1, + -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {FCC3, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, + BM(F2_5180_5240, F3_5260_5320, F1_5500_5720, F5_5745_5825, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T4_5200_5200, T8_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + /* + + Bug Fix: EV 98583 Public Safety channel + Exclude the following channel in FCC Public safety domain + Uni-1: 5180, 5200, 5220, 5240 + Uni-2: 5260, 5280, 5300, 5320 + Uni-3: 5745, 5765, 5785, 5805, 5825 + */ + {FCC4, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ, + BM(F1_4942_4987, F1_4945_4985, F1_4950_4980, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T8_5210_5210, T4_5250_5290, T7_5760_5800, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T1_5200_5240, T1_5280_5280, T9_5765_5805, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {FCC5, FCC, NO_DFS, NO_PSCAN, NO_REQ, + BM(F2_5180_5240, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T8_5200_5200, T7_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {FCC6, FCC, DFS_FCC3, PSCAN_FCC, NO_REQ, + BM(F8_5180_5240, F5_5260_5320, F1_5500_5580, F2_5660_5720, + F6_5745_5825, -1, -1, -1, -1, -1, -1, -1), + BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1, -1, + -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {MKK1, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_5170_5230, F10_5180_5240, F7_5260_5320, F4_5500_5700, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + {MKK2, MKK, DFS_MKK4, PSCAN_MKK2 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F2_4915_4925, F2_4935_4945, F1_4920_4980, F1_5035_5040, + F2_5055_5055, F1_5040_5080, F1_5170_5230, F10_5180_5240, -1, -1, -1, + -1), + BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 even */ + {MKK3, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 even + UNI-2 */ + {MKK4, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T10_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 even + UNI-2 + mid-band */ + {MKK5, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F4_5180_5240, F2_5260_5320, F6_5500_5700, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + even */ + {MKK6, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, + BM(F2_5170_5230, F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + UNI-1 even + UNI-2 */ + {MKK7, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F2_5170_5230, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, + -1, -1, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T5_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + UNI-1 even + UNI-2 + mid-band */ + {MKK8, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F2_5170_5230, F4_5180_5240, F2_5260_5320, F6_5500_5700, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 even + 4.9 GHZ */ + {MKK9, MKK, NO_DFS, PSCAN_MKK2 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_4912_4947, F1_5032_5057, F1_4915_4925, F1_4935_4945, + F2_4920_4980, F1_5035_5045, F1_5055_5055, F2_5040_5080, + F4_5180_5240, -1, -1, -1), + BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 even + UNI-2 + 4.9 GHZ */ + {MKK10, MKK, DFS_MKK4, PSCAN_MKK2 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_4912_4947, F1_5032_5057, F1_4915_4925, F1_4935_4945, + F2_4920_4980, F1_5035_5045, F1_5055_5055, F2_5040_5080, + F4_5180_5240, F2_5260_5320, -1, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* Japan UNI-1 even + UNI-2 + mid-band + 4.9GHz */ + {MKK11, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_4912_4947, F1_5032_5057, F1_4915_4925, F1_4935_4945, + F2_4920_4980, F1_5035_5045, F1_5055_5055, F2_5040_5080, + F4_5180_5240, F2_5260_5320, F6_5500_5700, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* Japan UNI-1 even + UNI-1 odd + UNI-2 + mid-band + 4.9GHz */ + {MKK12, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_4915_4925, F1_4935_4945, F2_4920_4980, F1_5040_5040, + F1_5055_5055, F2_5040_5080, F2_5170_5230, F4_5180_5240, + F2_5260_5320, F6_5500_5700, -1, -1), + BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + UNI-1 even + UNI-2 + mid-band */ + {MKK13, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + BM(F2_5170_5230, F7_5180_5240, F2_5260_5320, F6_5500_5700, -1, -1, -1, + -1, -1, -1, -1, -1), + BMZERO, + BMZERO, + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + UNI-1 even + 4.9GHz */ + {MKK14, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB, + BM(F1_4915_4925, F1_4935_4945, F2_4920_4980, F1_5040_5040, + F2_5040_5080, F1_5055_5055, F2_5170_5230, F4_5180_5240, -1, -1, -1, + -1), + BMZERO, + BMZERO, + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /* UNI-1 odd + UNI-1 even + UNI-2 + 4.9GHz */ + {MKK15, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB, + BM(F1_4915_4925, F1_4935_4945, F2_4920_4980, F1_5040_5040, + F2_5040_5080, F1_5055_5055, F2_5170_5230, F4_5180_5240, + F2_5260_5320, -1, -1, -1), + BMZERO, + BMZERO, + BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, + + /*=== 2 GHz ===*/ + + /* Defined here to use when 2G channels are authorised for country K2 */ + {APLD, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, + CHAN_11A_BMZERO + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(F2_2312_2372, F4_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(G2_2312_2372, G4_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BMZERO}, + + {ETSIA, NO_CTL, NO_DFS, PSCAN_ETSIA, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + CHAN_11A_BMZERO CHAN_11A_BMZERO CHAN_11A_BMZERO BM(F1_2457_2472, -1, + -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(G1_2457_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {ETSIB, ETSI, NO_DFS, PSCAN_ETSIB, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + CHAN_11A_BMZERO CHAN_11A_BMZERO CHAN_11A_BMZERO BM(F1_2432_2442, -1, + -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(G1_2432_2442, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {ETSIC, ETSI, NO_DFS, PSCAN_ETSIC, + DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, + CHAN_11A_BMZERO CHAN_11A_BMZERO CHAN_11A_BMZERO BM(F3_2412_2472, -1, + -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1), + BM(G3_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {FCCA, FCC, NO_DFS, NO_PSCAN, NO_REQ, + CHAN_11A_BMZERO + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(F1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(G1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {MKKA, MKK, NO_DFS, + PSCAN_MKKA | PSCAN_MKKA_G | PSCAN_MKKA1 | PSCAN_MKKA1_G | PSCAN_MKKA2 | + PSCAN_MKKA2_G, DISALLOW_ADHOC_11A_TURB, + CHAN_11A_BMZERO CHAN_11A_BMZERO CHAN_11A_BMZERO BM(F2_2412_2462, + F1_2467_2472, + F2_2484_2484, + -1, -1, -1, -1, -1, + -1, -1, -1, -1), + BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {MKKC, MKK, NO_DFS, NO_PSCAN, NO_REQ, + CHAN_11A_BMZERO + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WORLD, ETSI, NO_DFS, NO_PSCAN, NO_REQ, + CHAN_11A_BMZERO + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(F4_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + BM(G4_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR0_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, + -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR01_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + W1_5500_5700, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, + W1_2447_2457, + -1, -1, -1, -1, -1, -1, -1), + BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR02_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + W1_5500_5700, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {EU1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + W1_5500_5700, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W2_2472_2472, + W1_2417_2432, + W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1), + BM(WG2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + W1_5500_5700, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR2_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + W1_5500_5700, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR3_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR4_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, + W1_2447_2457, + -1, -1, -1, -1, -1, -1, -1), + BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR5_ETSIC, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WOR9_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, + -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432, + W1_2447_2457, + -1, -1, -1, -1, -1, -1, -1), + BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WORA_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, + -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WORB_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5500_5700, + -1, -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {WORC_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D, + CHAN_11A_BM(W1_5260_5320, W1_5180_5240, W1_5500_5700, W1_5745_5825, + -1, -1, -1, -1, -1, -1, -1, -1) + CHAN_11A_BMZERO + CHAN_11A_BMZERO + BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472, + W1_2417_2432, + W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1), + BM(WG1_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1), + CHAN_TURBO_G_BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1)}, + + {NULL1, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ, + CHAN_11A_BMZERO CHAN_11A_BMZERO CHAN_11A_BMZERO BMZERO, + BMZERO, + CHAN_TURBO_G_BMZERO}, +}; + +static const struct cmode modes[] = { + {REGDMN_MODE_TURBO, IEEE80211_CHAN_ST}, /* TURBO means 11a Static Turbo */ + {REGDMN_MODE_11A, IEEE80211_CHAN_A}, + {REGDMN_MODE_11B, IEEE80211_CHAN_B}, + {REGDMN_MODE_11G, IEEE80211_CHAN_PUREG}, + {REGDMN_MODE_11G_TURBO, IEEE80211_CHAN_108G}, + {REGDMN_MODE_11A_TURBO, IEEE80211_CHAN_108A}, + {REGDMN_MODE_11NG_HT20, IEEE80211_CHAN_11NG_HT20}, + {REGDMN_MODE_11NG_HT40PLUS, IEEE80211_CHAN_11NG_HT40PLUS}, + {REGDMN_MODE_11NG_HT40MINUS, IEEE80211_CHAN_11NG_HT40MINUS}, + {REGDMN_MODE_11NA_HT20, IEEE80211_CHAN_11NA_HT20}, + {REGDMN_MODE_11NA_HT40PLUS, IEEE80211_CHAN_11NA_HT40PLUS}, + {REGDMN_MODE_11NA_HT40MINUS, IEEE80211_CHAN_11NA_HT40MINUS}, + {REGDMN_MODE_11AC_VHT20, IEEE80211_CHAN_11AC_VHT20}, + {REGDMN_MODE_11AC_VHT40PLUS, IEEE80211_CHAN_11AC_VHT40PLUS}, + {REGDMN_MODE_11AC_VHT40MINUS, IEEE80211_CHAN_11AC_VHT40MINUS}, + {REGDMN_MODE_11AC_VHT80, IEEE80211_CHAN_11AC_VHT80}, + {REGDMN_MODE_11AC_VHT20_2G, IEEE80211_CHAN_11AC_VHT20_2G}, + {REGDMN_MODE_11AC_VHT40_2G, IEEE80211_CHAN_11AC_VHT40_2G}, + {REGDMN_MODE_11AC_VHT80_2G, IEEE80211_CHAN_11AC_VHT80_2G}, +}; + +typedef enum offset { + BW20 = 0, + BW40_LOW_PRIMARY = 1, + BW40_HIGH_PRIMARY = 3, + BW80, + BWALL +} offset_t; + +typedef struct _regdm_op_class_map { + uint8_t op_class; + uint8_t ch_spacing; + offset_t offset; + uint8_t channels[MAX_CHANNELS_PER_OPERATING_CLASS]; +} regdm_op_class_map_t; + +typedef struct _regdm_supp_op_classes { + uint8_t num_classes; + uint8_t classes[SIR_MAC_MAX_SUPP_OPER_CLASSES]; +} regdm_supp_op_classes; + +uint16_t cds_regdm_get_opclass_from_channel(uint8_t *country, uint8_t channel, + uint8_t offset); +uint16_t cds_regdm_set_curr_opclasses(uint8_t num_classes, uint8_t *class); +uint16_t cds_regdm_get_curr_opclasses(uint8_t *num_classes, uint8_t *class); diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h new file mode 100644 index 0000000000..c9acbdce02 --- /dev/null +++ b/core/cds/inc/cds_sched.h @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_SCHED_H ) +#define __CDS_SCHED_H + +/**========================================================================= + + \file cds_sched.h + + \brief Connectivity driver services scheduler + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include "i_cdf_types.h" +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#include +#include "cdf_lock.h" + +#define TX_POST_EVENT_MASK 0x001 +#define TX_SUSPEND_EVENT_MASK 0x002 +#define MC_POST_EVENT_MASK 0x001 +#define MC_SUSPEND_EVENT_MASK 0x002 +#define RX_POST_EVENT_MASK 0x001 +#define RX_SUSPEND_EVENT_MASK 0x002 +#define TX_SHUTDOWN_EVENT_MASK 0x010 +#define MC_SHUTDOWN_EVENT_MASK 0x010 +#define RX_SHUTDOWN_EVENT_MASK 0x010 +#define WD_POST_EVENT_MASK 0x001 +#define WD_SHUTDOWN_EVENT_MASK 0x002 +#define WD_CHIP_RESET_EVENT_MASK 0x004 +#define WD_WLAN_SHUTDOWN_EVENT_MASK 0x008 +#define WD_WLAN_REINIT_EVENT_MASK 0x010 + +/* + * Maximum number of messages in the system + * These are buffers to account for all current messages + * with some accounting of what we think is a + * worst-case scenario. Must be able to handle all + * incoming frames, as well as overhead for internal + * messaging + * + * Increased to 8000 to handle more RX frames + */ +#define CDS_CORE_MAX_MESSAGES 8000 + +#ifdef QCA_CONFIG_SMP +/* +** Maximum number of cds messages to be allocated for +** OL Rx thread. +*/ +#define CDS_MAX_OL_RX_PKT 4000 + +typedef void (*cds_ol_rx_thread_cb)(void *context, void *rxpkt, uint16_t staid); +#endif + +/* +** CDF Message queue definition. +*/ +typedef struct _cds_mq_type { + /* Lock use to synchronize access to this message queue */ + spinlock_t mqLock; + + /* List of vOS Messages waiting on this queue */ + struct list_head mqList; + +} cds_mq_type, *p_cds_mq_type; + +#ifdef QCA_CONFIG_SMP +/* +** CDS message wrapper for data rx from TXRX +*/ +struct cds_ol_rx_pkt { + struct list_head list; + void *context; + + /* Rx skb */ + void *Rxpkt; + + /* Station id to which this packet is destined */ + uint16_t staId; + + /* Call back to further send this packet to txrx layer */ + cds_ol_rx_thread_cb callback; + +}; +#endif + +/* +** CDS Scheduler context +** The scheduler context contains the following: +** ** the messages queues +** ** the handle to the tread +** ** pointer to the events that gracefully shutdown the MC and Tx threads +** +*/ +typedef struct _cds_sched_context { + /* Place holder to the CDS Context */ + void *pVContext; + /* WMA Message queue on the Main thread */ + cds_mq_type wmaMcMq; + + /* PE Message queue on the Main thread */ + cds_mq_type peMcMq; + + /* SME Message queue on the Main thread */ + cds_mq_type smeMcMq; + + /* SYS Message queue on the Main thread */ + cds_mq_type sysMcMq; + + /* Handle of Event for MC thread to signal startup */ + struct completion McStartEvent; + + struct task_struct *McThread; + + /* completion object for MC thread shutdown */ + struct completion McShutdown; + + /* Wait queue for MC thread */ + wait_queue_head_t mcWaitQueue; + + unsigned long mcEventFlag; + + /* Completion object to resume Mc thread */ + struct completion ResumeMcEvent; + + /* lock to make sure that McThread suspend/resume mechanism is in sync */ + spinlock_t McThreadLock; +#ifdef QCA_CONFIG_SMP + spinlock_t ol_rx_thread_lock; + + /* OL Rx thread handle */ + struct task_struct *ol_rx_thread; + + /* Handle of Event for Rx thread to signal startup */ + struct completion ol_rx_start_event; + + /* Completion object to suspend OL rx thread */ + struct completion ol_suspend_rx_event; + + /* Completion objext to resume OL rx thread */ + struct completion ol_resume_rx_event; + + /* Completion object for OL Rxthread shutdown */ + struct completion ol_rx_shutdown; + + /* Waitq for OL Rx thread */ + wait_queue_head_t ol_rx_wait_queue; + + unsigned long ol_rx_event_flag; + + /* Rx buffer queue */ + struct list_head ol_rx_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t ol_rx_queue_lock; + + /* Rx queue length */ + unsigned int ol_rx_queue_len; + + /* Lock to synchronize free buffer queue access */ + spinlock_t cds_ol_rx_pkt_freeq_lock; + + /* Free message queue for OL Rx processing */ + struct list_head cds_ol_rx_pkt_freeq; + + /* cpu hotplug notifier */ + struct notifier_block *cpu_hot_plug_notifier; +#endif +} cds_sched_context, *p_cds_sched_context; + +/** + * struct cds_log_complete - Log completion internal structure + * @is_fatal: Type is fatal or not + * @indicator: Source of bug report + * @reason_code: Reason code for bug report + * @is_report_in_progress: If bug report is in progress + * + * This structure internally stores the log related params + */ +struct cds_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + bool is_report_in_progress; +}; + +/* +** CDS Sched Msg Wrapper +** Wrapper messages so that they can be chained to their respective queue +** in the scheduler. +*/ +typedef struct _cds_msg_wrapper { + /* Message node */ + struct list_head msgNode; + + /* the Vos message it is associated to */ + cds_msg_t *pVosMsg; + +} cds_msg_wrapper, *p_cds_msg_wrapper; + +typedef struct _cds_context_type { + /* Messages buffers */ + cds_msg_t aMsgBuffers[CDS_CORE_MAX_MESSAGES]; + + cds_msg_wrapper aMsgWrappers[CDS_CORE_MAX_MESSAGES]; + + /* Free Message queue */ + cds_mq_type freeVosMq; + + /* Scheduler Context */ + cds_sched_context cdf_sched; + + /* HDD Module Context */ + void *pHDDContext; + + /* MAC Module Context */ + void *pMACContext; + +#ifndef WLAN_FEATURE_MBSSID + /* SAP Context */ + void *pSAPContext; +#endif + + cdf_event_t ProbeEvent; + + volatile uint8_t isLogpInProgress; + + cdf_event_t wmaCompleteEvent; + + /* WMA Context */ + void *pWMAContext; + + void *pHIFContext; + + void *htc_ctx; + + void *epping_ctx; + /* + * cdf_ctx will be used by cdf + * while allocating dma memory + * to access dev information. + */ + cdf_device_t cdf_ctx; + + void *pdev_txrx_ctx; + + /* Configuration handle used to get system configuration */ + void *cfg_ctx; + + volatile uint8_t isLoadUnloadInProgress; + + bool is_wakelock_log_enabled; + uint32_t wakelock_log_level; + uint32_t connectivity_log_level; + uint32_t packet_stats_log_level; + uint32_t driver_debug_log_level; + uint32_t fw_debug_log_level; + struct cds_log_complete log_complete; + cdf_spinlock_t bug_report_lock; + cdf_event_t connection_update_done_evt; + +} cds_context_type, *p_cds_contextType; + +/*--------------------------------------------------------------------------- + Function declarations and documenation + ---------------------------------------------------------------------------*/ + +#ifdef QCA_CONFIG_SMP +/*--------------------------------------------------------------------------- + \brief cds_drop_rxpkt_by_staid() - API to drop pending Rx packets for a sta + The \a cds_drop_rxpkt_by_staid() drops queued packets for a station, to drop + all the pending packets the caller has to send WLAN_MAX_STA_COUNT as staId. + \param pSchedContext - pointer to the global CDS Sched Context + \param staId - Station Id + + \return Nothing + \sa cds_drop_rxpkt_by_staid() + -------------------------------------------------------------------------*/ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId); + +/*--------------------------------------------------------------------------- + \brief cds_indicate_rxpkt() - API to Indicate rx data packet + The \a cds_indicate_rxpkt() enqueues the rx packet onto ol_rx_thread_queue + and notifies cds_ol_rx_thread(). + \param Arg - pointer to the global CDS Sched Context + \param pkt - Vos data message buffer + + \return Nothing + \sa cds_indicate_rxpkt() + -------------------------------------------------------------------------*/ +void cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); + +/*--------------------------------------------------------------------------- + \brief cds_alloc_ol_rx_pkt() - API to return next available cds message + The \a cds_alloc_ol_rx_pkt() returns next available cds message buffer + used for Rx Data processing. + \param pSchedContext - pointer to the global CDS Sched Context + + \return pointer to cds message buffer + \sa cds_alloc_ol_rx_pkt() + -------------------------------------------------------------------------*/ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext); + +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt() - API to release cds message to the freeq + The \a cds_free_ol_rx_pkt() returns the cds message used for Rx data + to the free queue. + \param pSchedContext - pointer to the global CDS Sched Context + \param pkt - Vos message buffer to be returned to free queue. + + \return Nothing + \sa cds_free_ol_rx_pkt() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt_freeq() - Free cdss buffer free queue + The \a cds_free_ol_rx_pkt_freeq() does mem free of the buffers + available in free cds buffer queue which is used for Data rx processing + from Tlshim. + \param pSchedContext - pointer to the global CDS Sched Context + + \return Nothing + \sa cds_free_ol_rx_pkt_freeq() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); +#endif + +/*--------------------------------------------------------------------------- + + \brief cds_sched_open() - initialize the CDS Scheduler + + The \a cds_sched_open() function initializes the CDS Scheduler + Upon successful initialization: + + - All the message queues are initialized + + - The Main Controller thread is created and ready to receive and + dispatch messages. + + - The Tx thread is created and ready to receive and dispatch messages + + \param p_cds_context - pointer to the global CDF Context + + \param p_cds_sched_context - pointer to a previously allocated buffer big + enough to hold a scheduler context. + \ + + \return CDF_STATUS_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + CDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable to initilize the scheduler + + CDF_STATUS_E_NOMEM - insufficient memory exists to initialize + the scheduler + + CDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + CDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_open() + + -------------------------------------------------------------------------*/ +CDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedCxt, uint32_t SchedCtxSize); + +/*--------------------------------------------------------------------------- + + \brief cds_sched_close() - Close the CDS Scheduler + + The \a cds_sched_closes() function closes the CDS Scheduler + Upon successful closing: + + - All the message queues are flushed + + - The Main Controller thread is closed + + - The Tx thread is closed + + \param p_cds_context - pointer to the global CDF Context + + \return CDF_STATUS_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + CDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + CDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_close() + + ---------------------------------------------------------------------------*/ +CDF_STATUS cds_sched_close(void *p_cds_context); + +/* Helper routines provided to other CDS API's */ +CDF_STATUS cds_mq_init(p_cds_mq_type pMq); +void cds_mq_deinit(p_cds_mq_type pMq); +void cds_mq_put(p_cds_mq_type pMq, p_cds_msg_wrapper pMsgWrapper); +p_cds_msg_wrapper cds_mq_get(p_cds_mq_type pMq); +bool cds_is_mq_empty(p_cds_mq_type pMq); +p_cds_sched_context get_cds_sched_ctxt(void); +CDF_STATUS cds_sched_init_mqs(p_cds_sched_context pSchedContext); +void cds_sched_deinit_mqs(p_cds_sched_context pSchedContext); +void cds_sched_flush_mc_mqs(p_cds_sched_context pSchedContext); + +void cdf_timer_module_init(void); +void cds_ssr_protect_init(void); +void cds_ssr_protect(const char *caller_func); +void cds_ssr_unprotect(const char *caller_func); +bool cds_is_ssr_ready(const char *caller_func); + +#define cds_wait_for_work_thread_completion(func) cds_is_ssr_ready(func) + +#endif /* #if !defined __CDS_SCHED_H */ diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h new file mode 100644 index 0000000000..5e4b2f61d6 --- /dev/null +++ b/core/cds/inc/cds_utils.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_UTILS_H ) +#define __CDS_UTILS_H + +/**========================================================================= + + \file cds_utils.h + + \brief Connectivity driver services (CDS) utility APIs + + Various utility functions + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include "ani_global.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define CDS_DIGEST_SHA1_SIZE (20) +#define CDS_DIGEST_MD5_SIZE (16) +#define CDS_BAND_2GHZ (1) +#define CDS_BAND_5GHZ (2) + +#define CDS_24_GHZ_BASE_FREQ (2407) +#define CDS_5_GHZ_BASE_FREQ (5000) +#define CDS_24_GHZ_CHANNEL_14 (14) +#define CDS_24_GHZ_CHANNEL_15 (15) +#define CDS_24_GHZ_CHANNEL_27 (27) +#define CDS_5_GHZ_CHANNEL_170 (170) +#define CDS_CHAN_SPACING_5MHZ (5) +#define CDS_CHAN_SPACING_20MHZ (20) +#define CDS_CHAN_14_FREQ (2484) +#define CDS_CHAN_15_FREQ (2512) +#define CDS_CHAN_170_FREQ (5852) + +#define cds_log(level, args...) CDF_TRACE(CDF_MODULE_ID_CDF, level, ## args) +#define cds_logfl(level, format, args...) cds_log(level, FL(format), ## args) + +#define cds_alert(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_FATAL, format, ## args) +#define cds_err(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_ERROR, format, ## args) +#define cds_warn(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_WARN, format, ## args) +#define cds_notice(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_INFO, format, ## args) +#define cds_info(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define cds_debug(format, args...) \ + cds_logfl(CDF_TRACE_LEVEL_DEBUG, format, ## args) +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +CDF_STATUS cds_crypto_init(uint32_t *phCryptProv); + +CDF_STATUS cds_crypto_deinit(uint32_t hCryptProv); + +/** + * cds_rand_get_bytes + + * FUNCTION: + * Returns cryptographically secure pseudo-random bytes. + * + * + * @param pbBuf - the caller allocated location where the bytes should be copied + * @param numBytes the number of bytes that should be generated and + * copied + * + * @return CDF_STATUS_SUCCSS if the operation succeeds + */ +CDF_STATUS cds_rand_get_bytes(uint32_t handle, uint8_t *pbBuf, + uint32_t numBytes); + +/** + * cds_sha1_hmac_str + * + * FUNCTION: + * Generate the HMAC-SHA1 of a string given a key. + * + * LOGIC: + * Standard HMAC processing from RFC 2104. The code is provided in the + * appendix of the RFC. + * + * ASSUMPTIONS: + * The RFC is correct. + * + * @param text text to be hashed + * @param textLen length of text + * @param key key to use for HMAC + * @param keyLen length of key + * @param digest holds resultant SHA1 HMAC (20B) + * + * @return CDF_STATUS_SUCCSS if the operation succeeds + * + */ +CDF_STATUS cds_sha1_hmac_str(uint32_t cryptHandle, /* Handle */ + uint8_t * text, /* pointer to data stream */ + uint32_t textLen, /* length of data stream */ + uint8_t * key, /* pointer to authentication key */ + uint32_t keyLen, /* length of authentication key */ + uint8_t digest[CDS_DIGEST_SHA1_SIZE]); /* caller digest to be filled in */ + +/** + * cds_md5_hmac_str + * + * FUNCTION: + * Generate the HMAC-MD5 of a string given a key. + * + * LOGIC: + * Standard HMAC processing from RFC 2104. The code is provided in the + * appendix of the RFC. + * + * ASSUMPTIONS: + * The RFC is correct. + * + * @param text text to be hashed + * @param textLen length of text + * @param key key to use for HMAC + * @param keyLen length of key + * @param digest holds resultant MD5 HMAC (16B) + * + * @return CDF_STATUS_SUCCSS if the operation succeeds + * + */ +CDF_STATUS cds_md5_hmac_str(uint32_t cryptHandle, /* Handle */ + uint8_t * text, /* pointer to data stream */ + uint32_t textLen, /* length of data stream */ + uint8_t * key, /* pointer to authentication key */ + uint32_t keyLen, /* length of authentication key */ + uint8_t digest[CDS_DIGEST_MD5_SIZE]); /* caller digest to be filled in */ + +CDF_STATUS cds_encrypt_aes(uint32_t cryptHandle, /* Handle */ + uint8_t *pText, /* pointer to data stream */ + uint8_t *Encrypted, uint8_t *pKey); /* pointer to authentication key */ + +CDF_STATUS cds_decrypt_aes(uint32_t cryptHandle, /* Handle */ + uint8_t *pText, /* pointer to data stream */ + uint8_t *pDecrypted, uint8_t *pKey); /* pointer to authentication key */ + +uint32_t cds_chan_to_freq(uint8_t chan); +uint8_t cds_freq_to_chan(uint32_t freq); +uint8_t cds_chan_to_band(uint32_t chan); +#ifdef WLAN_FEATURE_11W +bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn, + uint8_t *frm, uint8_t *efrm); +bool cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen); +uint8_t cds_get_mmie_size(void); +#endif /* WLAN_FEATURE_11W */ +CDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal pMac); +#endif /* #if !defined __CDS_UTILS_H */ diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c new file mode 100644 index 0000000000..ffcb5edb75 --- /dev/null +++ b/core/cds/src/cds_api.c @@ -0,0 +1,2085 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_api.c + * + * Connectivity driver services APIs + */ + +#include +#include "cds_sched.h" +#include +#include "sir_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "wlan_hdd_misc.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wma_types.h" +#include "wlan_hdd_main.h" +#include +#ifdef CONFIG_CNSS +#include +#endif + +#include "sap_api.h" +#include "cdf_trace.h" +#include "bmi.h" +#include "ol_fw.h" +#include "ol_if_athvar.h" +#include "hif.h" + +#include "cds_utils.h" +#include "wlan_logging_sock_svc.h" +#include "wma.h" + +#include "wlan_hdd_ipa.h" +/* Preprocessor Definitions and Constants */ + +/* Maximum number of cds message queue get wrapper failures to cause panic */ +#define CDS_WRAPPER_MAX_FAIL_COUNT (CDS_CORE_MAX_MESSAGES * 3) + +#ifdef IPA_OFFLOAD +#define CDS_IPA_CE_SR_BASE_PADDR \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->ce_sr_base_paddr) +#define CDS_IPA_CE_RING_SIZE \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->ce_sr_ring_size) +#define CDS_IPA_CE_REG_PADDR \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->ce_reg_paddr) +#define CDS_IPA_TX_COMP_BASE_PADDR \ + (&((hdd_context_t *) \ + (gp_cds_context->pHDDContext))->tx_comp_ring_base_paddr) +#define CDS_IPA_TX_COMP_RING_SIZE \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->tx_comp_ring_size) +#define CDS_IPA_TX_NUM_BUFF \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->tx_num_alloc_buffer) +#define CDS_IPA_RX_RDY_RING_BASE_PADDR \ + (&((hdd_context_t *) \ + (gp_cds_context->pHDDContext))->rx_rdy_ring_base_paddr) +#define CDS_IPA_RX_RDY_RING_SIZE \ + (&((hdd_context_t *)(gp_cds_context->pHDDContext))->rx_rdy_ring_size) +#define CDS_IPA_RX_PROC_DONE_IDX_PADDR \ + (&((hdd_context_t *) \ + (gp_cds_context->pHDDContext))->rx_proc_done_idx_paddr) +#else +#define CDS_IPA_CE_SR_BASE_PADDR (NULL) +#define CDS_IPA_CE_RING_SIZE (NULL) +#define CDS_IPA_CE_REG_PADDR (NULL) +#define CDS_IPA_TX_COMP_BASE_PADDR (NULL) +#define CDS_IPA_TX_COMP_RING_SIZE (NULL) +#define CDS_IPA_TX_NUM_BUFF (NULL) +#define CDS_IPA_RX_RDY_RING_BASE_PADDR (NULL) +#define CDS_IPA_RX_RDY_RING_SIZE (NULL) +#define CDS_IPA_RX_PROC_DONE_IDX_PADDR (NULL) +#endif /* IPA_OFFLOAD */ + +/* Data definitions */ +static cds_context_type g_cds_context; +static p_cds_contextType gp_cds_context; +static struct __cdf_device g_cdf_ctx; + +/* Debug variable to detect MC thread stuck */ +static atomic_t cds_wrapper_empty_count; + +static uint8_t cds_multicast_logging; + +void cds_sys_probe_thread_cback(void *pUserData); + +/** + * cds_alloc_global_context() - allocate CDS global context + * @p_cds_context: A pointer to where to store the CDS Context + * + * cds_alloc_global_context() function allocates the CDS global Context, + * but does not initialize all the members. This overal initialization will + * happen at cds_open(). + * + * Return: CDF status + */ +CDF_STATUS cds_alloc_global_context(v_CONTEXT_t *p_cds_context) +{ + if (p_cds_context == NULL) + return CDF_STATUS_E_FAILURE; + + /* allocate the CDS Context */ + *p_cds_context = NULL; + gp_cds_context = &g_cds_context; + + cdf_mem_zero(gp_cds_context, sizeof(cds_context_type)); + *p_cds_context = gp_cds_context; + + gp_cds_context->cdf_ctx = &g_cdf_ctx; + cdf_mem_zero(&g_cdf_ctx, sizeof(g_cdf_ctx)); + + /* initialize the spinlock */ + cdf_trace_spin_lock_init(); + /* it is the right time to initialize MTRACE structures */ +#if defined(TRACE_RECORD) + cdf_trace_init(); +#endif + + cdf_dp_trace_init(); + return CDF_STATUS_SUCCESS; +} /* cds_alloc_global_context() */ + +/** + * cds_free_global_context() - free CDS global context + * @p_cds_context: A pointer to where the CDS Context was stored + * + * cds_free_global_context() function frees the CDS Context. + * + * Return: CDF status + */ +CDF_STATUS cds_free_global_context(v_CONTEXT_t *p_cds_context) +{ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: De-allocating the CDS Context", __func__); + + if ((p_cds_context == NULL) || (*p_cds_context == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: vOS Context is Null", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (gp_cds_context != *p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Context mismatch", __func__); + return CDF_STATUS_E_FAILURE; + } + gp_cds_context->cdf_ctx = NULL; + *p_cds_context = gp_cds_context = NULL; + + return CDF_STATUS_SUCCESS; +} /* cds_free_global_context() */ + +#ifdef WLAN_FEATURE_NAN +/** + * cds_set_nan_enable() - set nan enable flag in mac open param + * @wma_handle: Pointer to mac open param + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void cds_set_nan_enable(tMacOpenParameters *param, + hdd_context_t *hdd_ctx) +{ + param->is_nan_enabled = hdd_ctx->config->enable_nan_support; +} +#else +static void cds_set_nan_enable(tMacOpenParameters *param, + hdd_context_t *pHddCtx) +{ +} +#endif + +/** + * cds_open() - open the CDS Module + * @p_cds_context: A pointer to where the CDS Context was stored + * @hddContextSize: Size of the HDD context to allocate. + * + * cds_open() function opens the CDS Scheduler + * Upon successful initialization: + * - All CDS submodules should have been initialized + * + * - The CDS scheduler should have opened + * + * - All the WLAN SW components should have been opened. This includes + * SYS, MAC, SME, WMA and TL. + * + * Return: CDF status + */ +CDF_STATUS cds_open(v_CONTEXT_t *p_cds_context, uint32_t hddContextSize) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int iter = 0; + tSirRetStatus sirStatus = eSIR_SUCCESS; + tMacOpenParameters mac_openParms; + cdf_device_t cdf_ctx; + HTC_INIT_INFO htcInfo; + struct ol_softc *scn; + void *HTCHandle; + hdd_context_t *pHddCtx; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening CDS", __func__); + + if (NULL == gp_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Trying to open CDS without a PreOpen", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* Initialize the timer module */ + cdf_timer_module_init(); + + /* Initialize bug reporting structure */ + cds_init_log_completion(); + + /* Initialize the probe event */ + if (cdf_event_init(&gp_cds_context->ProbeEvent) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Unable to init probeEvent", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + if (cdf_event_init(&(gp_cds_context->wmaCompleteEvent)) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Unable to init wmaCompleteEvent", __func__); + CDF_ASSERT(0); + goto err_probe_event; + } + + /* Initialize the free message queue */ + cdf_status = cds_mq_init(&gp_cds_context->freeVosMq); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to initialize CDS free message queue", + __func__); + CDF_ASSERT(0); + goto err_wma_complete_event; + } + + for (iter = 0; iter < CDS_CORE_MAX_MESSAGES; iter++) { + (gp_cds_context->aMsgWrappers[iter]).pVosMsg = + &(gp_cds_context->aMsgBuffers[iter]); + INIT_LIST_HEAD(&gp_cds_context->aMsgWrappers[iter].msgNode); + cds_mq_put(&gp_cds_context->freeVosMq, + &(gp_cds_context->aMsgWrappers[iter])); + } + + /* Now Open the CDS Scheduler */ + cdf_status = cds_sched_open(gp_cds_context, &gp_cds_context->cdf_sched, + sizeof(cds_sched_context)); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to open CDS Scheduler", __func__); + CDF_ASSERT(0); + goto err_msg_queue; + } + + pHddCtx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if ((NULL == pHddCtx) || (NULL == pHddCtx->config)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Hdd Context is Null", __func__); + CDF_ASSERT(0); + goto err_sched_close; + } + + scn = cds_get_context(CDF_MODULE_ID_HIF); + if (!scn) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + goto err_sched_close; + } + scn->enableuartprint = pHddCtx->config->enablefwprint; + scn->enablefwlog = pHddCtx->config->enablefwlog; + scn->max_no_of_peers = pHddCtx->config->maxNumberOfPeers; +#ifdef WLAN_FEATURE_LPSS + scn->enablelpasssupport = pHddCtx->config->enablelpasssupport; +#endif + scn->enable_ramdump_collection = + pHddCtx->config->is_ramdump_enabled; + scn->enable_self_recovery = pHddCtx->config->enableSelfRecovery; + + /* Initialize BMI and Download firmware */ + cdf_status = bmi_download_firmware(scn); + if (cdf_status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "BMI FIALED status:%d", cdf_status); + goto err_bmi_close; + } + + htcInfo.pContext = gp_cds_context->pHIFContext; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge; + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + + /* Create HTC */ + gp_cds_context->htc_ctx = + htc_create(htcInfo.pContext, &htcInfo, cdf_ctx); + if (!gp_cds_context->htc_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to Create HTC", __func__); + goto err_bmi_close; + } + + if (bmi_done(scn)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_htc_close; + } + + /* + ** Need to open WMA first because it calls WDI_Init, which calls wpalOpen + ** The reason that is needed becasue cds_packet_open need to use PAL APIs + */ + + /*Open the WMA module */ + cdf_mem_set(&mac_openParms, sizeof(mac_openParms), 0); + /* UMA is supported in hardware for performing the + ** frame translation 802.11 <-> 802.3 + */ + mac_openParms.frameTransRequired = 1; + mac_openParms.driverType = eDRIVER_TYPE_PRODUCTION; + mac_openParms.powersaveOffloadEnabled = + pHddCtx->config->enablePowersaveOffload; + mac_openParms.staDynamicDtim = pHddCtx->config->enableDynamicDTIM; + mac_openParms.staModDtim = pHddCtx->config->enableModulatedDTIM; + mac_openParms.staMaxLIModDtim = pHddCtx->config->fMaxLIModulatedDTIM; + mac_openParms.wowEnable = pHddCtx->config->wowEnable; + mac_openParms.maxWoWFilters = pHddCtx->config->maxWoWFilters; + /* Here olIniInfo is used to store ini status of arp offload + * ns offload and others. Currently 1st bit is used for arp + * off load and 2nd bit for ns offload currently, rest bits are unused + */ + if (pHddCtx->config->fhostArpOffload) + mac_openParms.olIniInfo = mac_openParms.olIniInfo | 0x1; + if (pHddCtx->config->fhostNSOffload) + mac_openParms.olIniInfo = mac_openParms.olIniInfo | 0x2; + /* + * Copy the DFS Phyerr Filtering Offload status. + * This parameter reflects the value of the + * dfsPhyerrFilterOffload flag as set in the ini. + */ + mac_openParms.dfsPhyerrFilterOffload = + pHddCtx->config->fDfsPhyerrFilterOffload; + if (pHddCtx->config->ssdp) + mac_openParms.ssdp = pHddCtx->config->ssdp; +#ifdef FEATURE_WLAN_RA_FILTERING + mac_openParms.RArateLimitInterval = + pHddCtx->config->RArateLimitInterval; + mac_openParms.IsRArateLimitEnabled = + pHddCtx->config->IsRArateLimitEnabled; +#endif + + mac_openParms.apMaxOffloadPeers = pHddCtx->config->apMaxOffloadPeers; + + mac_openParms.apMaxOffloadReorderBuffs = + pHddCtx->config->apMaxOffloadReorderBuffs; + + mac_openParms.apDisableIntraBssFwd = + pHddCtx->config->apDisableIntraBssFwd; + + mac_openParms.dfsRadarPriMultiplier = + pHddCtx->config->dfsRadarPriMultiplier; + mac_openParms.reorderOffload = pHddCtx->config->reorderOffloadSupport; + + /* IPA micro controller data path offload resource config item */ + mac_openParms.ucOffloadEnabled = hdd_ipa_uc_is_enabled(pHddCtx); + mac_openParms.ucTxBufCount = pHddCtx->config->IpaUcTxBufCount; + mac_openParms.ucTxBufSize = pHddCtx->config->IpaUcTxBufSize; + mac_openParms.ucRxIndRingCount = pHddCtx->config->IpaUcRxIndRingCount; + mac_openParms.ucTxPartitionBase = pHddCtx->config->IpaUcTxPartitionBase; + mac_openParms.max_scan = pHddCtx->config->max_scan_count; + + mac_openParms.ip_tcp_udp_checksum_offload = + pHddCtx->config->enable_ip_tcp_udp_checksum_offload; + mac_openParms.enable_rxthread = pHddCtx->config->enableRxThread; + mac_openParms.ce_classify_enabled = + pHddCtx->config->ce_classify_enabled; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + mac_openParms.tx_flow_stop_queue_th = + pHddCtx->config->TxFlowStopQueueThreshold; + mac_openParms.tx_flow_start_queue_offset = + pHddCtx->config->TxFlowStartQueueOffset; +#endif + cds_set_nan_enable(&mac_openParms, pHddCtx); + + mac_openParms.tx_chain_mask_cck = pHddCtx->config->tx_chain_mask_cck; + mac_openParms.self_gen_frm_pwr = pHddCtx->config->self_gen_frm_pwr; + + cdf_status = wma_open(gp_cds_context, + hdd_update_tgt_cfg, + hdd_dfs_indicate_radar, &mac_openParms); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to open WMA module", __func__); + CDF_ASSERT(0); + goto err_htc_close; + } + + /* Number of peers limit differs in each chip version. If peer max + * limit configured in ini exceeds more than supported, WMA adjusts + * and keeps correct limit in mac_openParms.maxStation. So, make sure + * config entry pHddCtx->config->maxNumberOfPeers has adjusted value + */ + pHddCtx->config->maxNumberOfPeers = mac_openParms.maxStation; + HTCHandle = cds_get_context(CDF_MODULE_ID_HTC); + if (!HTCHandle) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: HTCHandle is null!", __func__); + goto err_wma_close; + } + if (htc_wait_target(HTCHandle)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_wma_close; + } + + /* Now proceed to open the MAC */ + + /* UMA is supported in hardware for performing the + * frame translation 802.11 <-> 802.3 + */ + mac_openParms.frameTransRequired = 1; + + sirStatus = + mac_open(&(gp_cds_context->pMACContext), gp_cds_context->pHDDContext, + &mac_openParms); + + if (eSIR_SUCCESS != sirStatus) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to open MAC", __func__); + CDF_ASSERT(0); + goto err_wma_close; + } + + /* Now proceed to open the SME */ + cdf_status = sme_open(gp_cds_context->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to open SME", __func__); + CDF_ASSERT(0); + goto err_mac_close; + } + + gp_cds_context->pdev_txrx_ctx = + ol_txrx_pdev_alloc(gp_cds_context->cfg_ctx, + gp_cds_context->htc_ctx, + gp_cds_context->cdf_ctx); + if (!gp_cds_context->pdev_txrx_ctx) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to open TXRX", __func__); + CDF_ASSERT(0); + goto err_sme_close; + } + + ol_txrx_ipa_uc_get_resource(gp_cds_context->pdev_txrx_ctx, + CDS_IPA_CE_SR_BASE_PADDR, + CDS_IPA_CE_RING_SIZE, + CDS_IPA_CE_REG_PADDR, + CDS_IPA_TX_COMP_BASE_PADDR, + CDS_IPA_TX_COMP_RING_SIZE, + CDS_IPA_TX_NUM_BUFF, + CDS_IPA_RX_RDY_RING_BASE_PADDR, + CDS_IPA_RX_RDY_RING_SIZE, + CDS_IPA_RX_PROC_DONE_IDX_PADDR); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS successfully Opened", __func__); + + *p_cds_context = gp_cds_context; + + return CDF_STATUS_SUCCESS; + +err_sme_close: + sme_close(gp_cds_context->pMACContext); + +err_mac_close: + mac_close(gp_cds_context->pMACContext); + +err_wma_close: + wma_close(gp_cds_context); + + wma_wmi_service_close(gp_cds_context); + +err_htc_close: + if (gp_cds_context->htc_ctx) { + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + +err_bmi_close: + bmi_cleanup(scn); + +err_sched_close: + cds_sched_close(gp_cds_context); + +err_msg_queue: + cds_mq_deinit(&gp_cds_context->freeVosMq); + +err_wma_complete_event: + cdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + +err_probe_event: + cdf_event_destroy(&gp_cds_context->ProbeEvent); + + return CDF_STATUS_E_FAILURE; +} /* cds_open() */ + +/** + * cds_pre_enable() - pre enable cds + * @cds_context: CDS context + * + * Return: CDF status + */ +CDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + p_cds_contextType p_cds_context = (p_cds_contextType) cds_context; + void *scn; + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, "cds prestart"); + + if (gp_cds_context != p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Context mismatch", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + if (p_cds_context->pMACContext == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: MAC NULL context", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + if (p_cds_context->pWMAContext == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: WMA NULL context", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + + scn = cds_get_context(CDF_MODULE_ID_HIF); + if (!scn) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + return CDF_STATUS_E_FAILURE; + } + + /* Reset wma wait event */ + cdf_event_reset(&gp_cds_context->wmaCompleteEvent); + + /*call WMA pre start */ + cdf_status = wma_pre_start(gp_cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_FATAL, + "Failed to WMA prestart"); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* Need to update time out of complete */ + cdf_status = cdf_wait_single_event(&gp_cds_context->wmaCompleteEvent, + CDS_WMA_TIMEOUT); + if (cdf_status != CDF_STATUS_SUCCESS) { + if (cdf_status == CDF_STATUS_E_TIMEOUT) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Timeout occurred before WMA complete", + __func__); + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: wma_pre_start reporting other error", + __func__); + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Test MC thread by posting a probe message to SYS", + __func__); + wlan_sys_probe(); + + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + cdf_status = htc_start(gp_cds_context->htc_ctx); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_FATAL, + "Failed to Start HTC"); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + cdf_status = wma_wait_for_ready_event(gp_cds_context->pWMAContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Failed to get ready event from target firmware"); + htc_set_target_to_sleep(scn); + htc_stop(gp_cds_context->htc_ctx); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + if (ol_txrx_pdev_attach(gp_cds_context->pdev_txrx_ctx)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "Failed to attach pdev"); + htc_set_target_to_sleep(scn); + htc_stop(gp_cds_context->htc_ctx); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + htc_set_target_to_sleep(scn); + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_enable() - start/enable cds module + * @cds_context: CDS context + * + * Return: CDF status + */ +CDF_STATUS cds_enable(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tSirRetStatus sirStatus = eSIR_SUCCESS; + p_cds_contextType p_cds_context = (p_cds_contextType) cds_context; + tHalMacStartParameters halStartParams; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Starting Libra SW", __func__); + + /* We support only one instance for now ... */ + if (gp_cds_context != p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: mismatch in context", __func__); + return CDF_STATUS_E_FAILURE; + } + + if ((p_cds_context->pWMAContext == NULL) || + (p_cds_context->pMACContext == NULL)) { + if (p_cds_context->pWMAContext == NULL) + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: WMA NULL context", __func__); + else + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: MAC NULL context", __func__); + + return CDF_STATUS_E_FAILURE; + } + + /* Start the wma */ + cdf_status = wma_start(p_cds_context); + if (cdf_status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to start wma", __func__); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: wma correctly started", __func__); + + /* Start the MAC */ + cdf_mem_zero(&halStartParams, + sizeof(tHalMacStartParameters)); + + /* Start the MAC */ + sirStatus = + mac_start(p_cds_context->pMACContext, &halStartParams); + + if (eSIR_SUCCESS != sirStatus) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to start MAC", __func__); + goto err_wma_stop; + } + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: MAC correctly started", __func__); + + /* START SME */ + cdf_status = sme_start(p_cds_context->pMACContext); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to start SME", __func__); + goto err_mac_stop; + } + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: SME correctly started", __func__); + + if (ol_txrx_pdev_attach_target + (p_cds_context->pdev_txrx_ctx) != A_OK) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed attach target", __func__); + goto err_sme_stop; + } + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "TL correctly started"); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: CDS Start is successful!!", __func__); + + return CDF_STATUS_SUCCESS; + +err_sme_stop: + sme_stop(p_cds_context->pMACContext, HAL_STOP_TYPE_SYS_RESET); + +err_mac_stop: + mac_stop(p_cds_context->pMACContext, HAL_STOP_TYPE_SYS_RESET); + +err_wma_stop: + cdf_event_reset(&(gp_cds_context->wmaCompleteEvent)); + cdf_status = wma_stop(p_cds_context, HAL_STOP_TYPE_RF_KILL); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop wma", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + wma_setneedshutdown(cds_context); + } else { + cdf_status = + cdf_wait_single_event(&(gp_cds_context->wmaCompleteEvent), + CDS_WMA_TIMEOUT); + if (cdf_status != CDF_STATUS_SUCCESS) { + if (cdf_status == CDF_STATUS_E_TIMEOUT) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "%s: Timeout occurred before WMA_stop complete", + __func__); + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_FATAL, + "%s: WMA_stop reporting other error", + __func__); + } + CDF_ASSERT(0); + wma_setneedshutdown(cds_context); + } + } + + return CDF_STATUS_E_FAILURE; +} /* cds_enable() */ + +/** + * cds_disable() - stop/disable cds module + * @cds_context: CDS context + * + * Return: CDF status + */ +CDF_STATUS cds_disable(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status; + + /* wma_stop is called before the SYS so that the processing of target + * pending responses will not be handled during uninitialization of + * WLAN driver + */ + cdf_event_reset(&(gp_cds_context->wmaCompleteEvent)); + + cdf_status = wma_stop(cds_context, HAL_STOP_TYPE_RF_KILL); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop wma", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + wma_setneedshutdown(cds_context); + } + + hif_disable_isr(((cds_context_type *) cds_context)->pHIFContext); + hif_reset_soc(((cds_context_type *) cds_context)->pHIFContext); + + /* SYS STOP will stop SME and MAC */ + cdf_status = sys_stop(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop SYS", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_close() - close cds module + * @cds_context: CDS context + * + * Return: CDF status + */ +CDF_STATUS cds_close(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status; + + if (gp_cds_context->htc_ctx) { + htc_stop(gp_cds_context->htc_ctx); + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + + ol_txrx_pdev_detach(gp_cds_context->pdev_txrx_ctx, 1); + cds_free_context(cds_context, CDF_MODULE_ID_TXRX, + gp_cds_context->pdev_txrx_ctx); + + cdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close SME", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close MAC", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + ((p_cds_contextType) cds_context)->pMACContext = NULL; + + if (true == wma_needshutdown(cds_context)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to shutdown wma", __func__); + } else { + cdf_status = wma_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + } + + cdf_status = wma_wmi_service_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma_wmi_service", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq); + + cdf_status = cdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy wmaCompleteEvent", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cdf_status = cdf_event_destroy(&gp_cds_context->ProbeEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy ProbeEvent", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cds_deinit_log_completion(); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_context() - get context data area + * + * @moduleId: ID of the module who's context data is being retrived. + * + * Each module in the system has a context / data area that is allocated + * and managed by CDS. This API allows any user to get a pointer to its + * allocated context data area from the CDS global context. + * + * Return: pointer to the context data area of the module ID + * specified, or NULL if the context data is not allocated for + * the module ID specified + */ +void *cds_get_context(CDF_MODULE_ID moduleId) +{ + void *pModContext = NULL; + + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: cds context pointer is null", __func__); + return NULL; + } + + switch (moduleId) { +#ifndef WLAN_FEATURE_MBSSID + case CDF_MODULE_ID_SAP: + { + pModContext = gp_cds_context->pSAPContext; + break; + } +#endif + + case CDF_MODULE_ID_HDD: + { + pModContext = gp_cds_context->pHDDContext; + break; + } + + case CDF_MODULE_ID_SME: + case CDF_MODULE_ID_PE: + { + /* In all these cases, we just return the MAC Context */ + pModContext = gp_cds_context->pMACContext; + break; + } + + case CDF_MODULE_ID_WMA: + { + /* For wma module */ + pModContext = gp_cds_context->pWMAContext; + break; + } + + case CDF_MODULE_ID_CDF: + { + /* For SYS this is CDS itself */ + pModContext = gp_cds_context; + break; + } + + case CDF_MODULE_ID_HIF: + { + pModContext = gp_cds_context->pHIFContext; + break; + } + + case CDF_MODULE_ID_HTC: + { + pModContext = gp_cds_context->htc_ctx; + break; + } + + case CDF_MODULE_ID_CDF_DEVICE: + { + pModContext = gp_cds_context->cdf_ctx; + break; + } + + case CDF_MODULE_ID_TXRX: + { + pModContext = gp_cds_context->pdev_txrx_ctx; + break; + } + + case CDF_MODULE_ID_CFG: + { + pModContext = gp_cds_context->cfg_ctx; + break; + } + + default: + { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i does not have its context maintained by CDS", + __func__, moduleId); + CDF_ASSERT(0); + return NULL; + } + } + + if (pModContext == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i context is Null", __func__, + moduleId); + } + + return pModContext; +} /* cds_get_context() */ + +/** + * cds_get_global_context() - get CDS global Context + * + * This API allows any user to get the CDS Global Context pointer from a + * module context data area. + * + * Return: pointer to the CDS global context, NULL if the function is + * unable to retreive the CDS context. + */ +v_CONTEXT_t cds_get_global_context(void) +{ + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + } + + return gp_cds_context; +} /* cds_get_global_context() */ + +/** + * cds_is_logp_in_progress() - check if ssr/self recovery is going on + * + * Return: true if ssr/self recvoery is going on else false + */ +uint8_t cds_is_logp_in_progress(void) +{ + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + return 1; + } + + return gp_cds_context->isLogpInProgress; +} + +/** + * cds_set_logp_in_progress() - set ssr/self recovery in progress + * @value: value to set + * + * Return: none + */ +void cds_set_logp_in_progress(uint8_t value) +{ + hdd_context_t *pHddCtx = NULL; + + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + return; + } + gp_cds_context->isLogpInProgress = value; + + /* HDD uses it's own context variable to check if SSR in progress, + * instead of modifying all HDD APIs set the HDD context variable + * here + */ + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return; + } + pHddCtx->isLogpInProgress = value; +} + +/** + * cds_is_load_unload_in_progress() - check if driver load/unload in progress + * + * Return: true if load/unload is going on else false + */ +uint8_t cds_is_load_unload_in_progress(void) +{ + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + return 0; + } + + return gp_cds_context->isLoadUnloadInProgress; +} + +/** + * cds_set_load_unload_in_progress() - set load/unload in progress + * @value: value to set + * + * Return: none + */ +void cds_set_load_unload_in_progress(uint8_t value) +{ + if (gp_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + return; + } + gp_cds_context->isLoadUnloadInProgress = value; + +#ifdef CONFIG_CNSS + if (value) + cnss_set_driver_status(CNSS_LOAD_UNLOAD); + else + cnss_set_driver_status(CNSS_INITIALIZED); +#endif +} + +/** + * cds_alloc_context() - allocate a context within the CDS global Context + * @p_cds_context: pointer to the global Vos context + * @moduleId: module ID who's context area is being allocated. + * @ppModuleContext: pointer to location where the pointer to the + * allocated context is returned. Note this output pointer + * is valid only if the API returns CDF_STATUS_SUCCESS + * @param size: size of the context area to be allocated. + * + * This API allows any user to allocate a user context area within the + * CDS Global Context. + * + * Return: CDF status + */ +CDF_STATUS cds_alloc_context(void *p_cds_context, CDF_MODULE_ID moduleID, + void **ppModuleContext, uint32_t size) +{ + void **pGpModContext = NULL; + + if (p_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is null", __func__); + return CDF_STATUS_E_FAILURE; + } + + if ((gp_cds_context != p_cds_context) || (ppModuleContext == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: context mismatch or null param passed", + __func__); + return CDF_STATUS_E_FAILURE; + } + + switch (moduleID) { + +#ifndef WLAN_FEATURE_MBSSID + case CDF_MODULE_ID_SAP: + { + pGpModContext = &(gp_cds_context->pSAPContext); + break; + } +#endif + + case CDF_MODULE_ID_WMA: + { + pGpModContext = &(gp_cds_context->pWMAContext); + break; + } + + case CDF_MODULE_ID_HIF: + { + pGpModContext = &(gp_cds_context->pHIFContext); + break; + } + + case CDF_MODULE_ID_EPPING: + { + pGpModContext = &(gp_cds_context->epping_ctx); + break; + } + case CDF_MODULE_ID_SME: + case CDF_MODULE_ID_PE: + case CDF_MODULE_ID_HDD: + case CDF_MODULE_ID_HDD_SOFTAP: + default: + { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "does not have its context allocated by CDS", + __func__, moduleID); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + } + + if (NULL != *pGpModContext) { + /* Context has already been allocated! + * Prevent double allocation + */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i context has already been allocated", + __func__, moduleID); + return CDF_STATUS_E_EXISTS; + } + + /* Dynamically allocate the context for module */ + + *ppModuleContext = cdf_mem_malloc(size); + + if (*ppModuleContext == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to " "allocate Context for module ID %i", + __func__, moduleID); + CDF_ASSERT(0); + return CDF_STATUS_E_NOMEM; + } + + if (moduleID == CDF_MODULE_ID_TLSHIM) + cdf_mem_zero(*ppModuleContext, size); + + *pGpModContext = *ppModuleContext; + + return CDF_STATUS_SUCCESS; +} /* cds_alloc_context() */ + +/** + * cds_free_context() - free an allocated context within the + * CDS global Context + * @p_cds_context: pointer to the global Vos context + * @moduleId: module ID who's context area is being free + * @pModuleContext: pointer to module context area to be free'd. + * + * This API allows a user to free the user context area within the + * CDS Global Context. + * + * Return: CDF status + */ +CDF_STATUS cds_free_context(void *p_cds_context, CDF_MODULE_ID moduleID, + void *pModuleContext) +{ + void **pGpModContext = NULL; + + if ((p_cds_context == NULL) || (gp_cds_context != p_cds_context) || + (pModuleContext == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null params or context mismatch", __func__); + return CDF_STATUS_E_FAILURE; + } + + switch (moduleID) { +#ifndef WLAN_FEATURE_MBSSID + case CDF_MODULE_ID_SAP: + { + pGpModContext = &(gp_cds_context->pSAPContext); + break; + } +#endif + + case CDF_MODULE_ID_WMA: + { + pGpModContext = &(gp_cds_context->pWMAContext); + break; + } + + case CDF_MODULE_ID_HIF: + { + pGpModContext = &(gp_cds_context->pHIFContext); + break; + } + + case CDF_MODULE_ID_EPPING: + { + pGpModContext = &(gp_cds_context->epping_ctx); + break; + } + + case CDF_MODULE_ID_TXRX: + { + pGpModContext = &(gp_cds_context->pdev_txrx_ctx); + break; + } + + case CDF_MODULE_ID_HDD: + case CDF_MODULE_ID_SME: + case CDF_MODULE_ID_PE: + case CDF_MODULE_ID_HDD_SOFTAP: + default: + { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "does not have its context allocated by CDS", + __func__, moduleID); + CDF_ASSERT(0); + return CDF_STATUS_E_INVAL; + } + } + + if (NULL == *pGpModContext) { + /* Context has not been allocated or freed already! */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "context has not been allocated or freed already", + __func__, moduleID); + return CDF_STATUS_E_FAILURE; + } + + if (*pGpModContext != pModuleContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: pGpModContext != pModuleContext", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (pModuleContext != NULL) + cdf_mem_free(pModuleContext); + + *pGpModContext = NULL; + + return CDF_STATUS_SUCCESS; +} /* cds_free_context() */ + +/** + * cds_mq_post_message() - post a message to a message queue + * @msgQueueId: identifies the message queue upon which the message + * will be posted. + * @message: a pointer to a message buffer. Memory for this message + * buffer is allocated by the caller and free'd by the CDF after the + * message is posted to the message queue. If the consumer of the + * message needs anything in this message, it needs to copy the contents + * before returning from the message queue handler. + * + * Return: CDF status + */ +CDF_STATUS cds_mq_post_message(CDS_MQ_ID msgQueueId, cds_msg_t *pMsg) +{ + p_cds_mq_type pTargetMq = NULL; + p_cds_msg_wrapper pMsgWrapper = NULL; + uint32_t debug_count = 0; + + if ((gp_cds_context == NULL) || (pMsg == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null params or global cds context is null", + __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + switch (msgQueueId) { + /* Message Queue ID for messages bound for SME */ + case CDS_MQ_ID_SME: + { + pTargetMq = &(gp_cds_context->cdf_sched.smeMcMq); + break; + } + + /* Message Queue ID for messages bound for PE */ + case CDS_MQ_ID_PE: + { + pTargetMq = &(gp_cds_context->cdf_sched.peMcMq); + break; + } + + /* Message Queue ID for messages bound for wma */ + case CDS_MQ_ID_WMA: + { + pTargetMq = &(gp_cds_context->cdf_sched.wmaMcMq); + break; + } + + /* Message Queue ID for messages bound for the SYS module */ + case CDS_MQ_ID_SYS: + { + pTargetMq = &(gp_cds_context->cdf_sched.sysMcMq); + break; + } + + default: + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("%s: Trying to queue msg into unknown MC Msg queue ID %d"), + __func__, msgQueueId); + + return CDF_STATUS_E_FAILURE; + } + + CDF_ASSERT(NULL != pTargetMq); + if (pTargetMq == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: pTargetMq == NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + /* Try and get a free Msg wrapper */ + pMsgWrapper = cds_mq_get(&gp_cds_context->freeVosMq); + + if (NULL == pMsgWrapper) { + debug_count = atomic_inc_return(&cds_wrapper_empty_count); + if (1 == debug_count) + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: CDS Core run out of message wrapper %d", + __func__, debug_count); + + if (CDS_WRAPPER_MAX_FAIL_COUNT == debug_count) + CDF_BUG(0); + + return CDF_STATUS_E_RESOURCES; + } + + atomic_set(&cds_wrapper_empty_count, 0); + + /* Copy the message now */ + cdf_mem_copy((void *)pMsgWrapper->pVosMsg, + (void *)pMsg, sizeof(cds_msg_t)); + + cds_mq_put(pTargetMq, pMsgWrapper); + + set_bit(MC_POST_EVENT_MASK, &gp_cds_context->cdf_sched.mcEventFlag); + wake_up_interruptible(&gp_cds_context->cdf_sched.mcWaitQueue); + + return CDF_STATUS_SUCCESS; +} /* cds_mq_post_message() */ + +/** + * cds_sys_probe_thread_cback() - probe mc thread callback + * @pUserData: pointer to user data + * + * Return: none + */ +void cds_sys_probe_thread_cback(void *pUserData) +{ + if (gp_cds_context != pUserData) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != pUserData", __func__); + return; + } + + if (cdf_event_set(&gp_cds_context->ProbeEvent) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: cdf_event_set failed", __func__); + return; + } +} /* cds_sys_probe_thread_cback() */ + +/** + * cds_wma_complete_cback() - wma complete callback + * @pUserData: pointer to user data + * + * Return: none + */ +void cds_wma_complete_cback(void *pUserData) +{ + if (gp_cds_context != pUserData) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != pUserData", __func__); + return; + } + + if (cdf_event_set(&gp_cds_context->wmaCompleteEvent) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: cdf_event_set failed", __func__); + return; + } +} /* cds_wma_complete_cback() */ + +/** + * cds_core_return_msg() - return core message + * @pVContext: pointer to cds context + * @pMsgWrapper: pointer to message wrapper + * + * Return: none + */ +void cds_core_return_msg(void *pVContext, p_cds_msg_wrapper pMsgWrapper) +{ + p_cds_contextType p_cds_context = (p_cds_contextType) pVContext; + + CDF_ASSERT(gp_cds_context == p_cds_context); + + if (gp_cds_context != p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != p_cds_context", __func__); + return; + } + + CDF_ASSERT(NULL != pMsgWrapper); + + if (pMsgWrapper == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper == NULL in function", __func__); + return; + } + + /* + ** Return the message on the free message queue + */ + INIT_LIST_HEAD(&pMsgWrapper->msgNode); + cds_mq_put(&p_cds_context->freeVosMq, pMsgWrapper); +} /* cds_core_return_msg() */ + + +/** + * cds_shutdown() - shutdown CDS + * @cds_context: global cds context + * + * Return: CDF status + */ +CDF_STATUS cds_shutdown(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status; + tpAniSirGlobal pmac = (((p_cds_contextType)cds_context)->pMACContext); + + ol_txrx_pdev_detach(gp_cds_context->pdev_txrx_ctx, 1); + cds_free_context(cds_context, CDF_MODULE_ID_TXRX, + gp_cds_context->pdev_txrx_ctx); + + cdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close SME", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + /* + * CAC timer will be initiated and started only when SAP starts on + * DFS channel and it will be stopped and destroyed immediately once the + * radar detected or timedout. So as per design CAC timer should be + * destroyed after stop + */ + if (pmac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + cdf_mc_timer_stop(&pmac->sap.SapDfsInfo.sap_dfs_cac_timer); + pmac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + cdf_mc_timer_destroy(&pmac->sap.SapDfsInfo.sap_dfs_cac_timer); + } + + cdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close MAC", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + ((p_cds_contextType) cds_context)->pMACContext = NULL; + + if (false == wma_needshutdown(cds_context)) { + + cdf_status = wma_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma!", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + } + + if (gp_cds_context->htc_ctx) { + htc_stop(gp_cds_context->htc_ctx); + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + + cdf_status = wma_wmi_service_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma_wmi_service!", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq); + + cdf_status = cdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy wmaCompleteEvent", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cdf_status = cdf_event_destroy(&gp_cds_context->ProbeEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy ProbeEvent", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_vdev_types() - get vdev type + * @mode: mode + * @type: type + * @sub_type: sub_type + * + * Return: WMI vdev type + */ +CDF_STATUS cds_get_vdev_types(tCDF_CON_MODE mode, uint32_t *type, + uint32_t *sub_type) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + *type = 0; + *sub_type = 0; + + switch (mode) { + case CDF_STA_MODE: + *type = WMI_VDEV_TYPE_STA; + break; + case CDF_SAP_MODE: + *type = WMI_VDEV_TYPE_AP; + break; + case CDF_P2P_DEVICE_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE; + break; + case CDF_P2P_CLIENT_MODE: + *type = WMI_VDEV_TYPE_STA; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT; + break; + case CDF_P2P_GO_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO; + break; + case CDF_OCB_MODE: + *type = WMI_VDEV_TYPE_OCB; + break; + default: + hddLog(CDF_TRACE_LEVEL_ERROR, "Invalid device mode %d", mode); + status = CDF_STATUS_E_INVAL; + break; + } + return status; +} + +/** + * cds_flush_work() - flush pending works + * @work: pointer to work + * + * Return: none + */ +void cds_flush_work(void *work) +{ +#if defined (CONFIG_CNSS) + cnss_flush_work(work); +#elif defined (WLAN_OPEN_SOURCE) + cancel_work_sync(work); +#endif +} + +/** + * cds_flush_delayed_work() - flush delayed works + * @dwork: pointer to delayed work + * + * Return: none + */ +void cds_flush_delayed_work(void *dwork) +{ +#if defined (CONFIG_CNSS) + cnss_flush_delayed_work(dwork); +#elif defined (WLAN_OPEN_SOURCE) + cancel_delayed_work_sync(dwork); +#endif +} + +/** + * cds_is_packet_log_enabled() - check if packet log is enabled + * + * Return: true if packet log is enabled else false + */ +bool cds_is_packet_log_enabled(void) +{ + hdd_context_t *pHddCtx; + + pHddCtx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if ((NULL == pHddCtx) || (NULL == pHddCtx->config)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Hdd Context is Null", __func__); + return false; + } + + return pHddCtx->config->enablePacketLog; +} + +/** + * cds_trigger_recovery() - trigger self recovery + * + * Return: none + */ +void cds_trigger_recovery(void) +{ + tp_wma_handle wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (!wma_handle) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "WMA context is invald!"); + return; + } + + wma_crash_inject(wma_handle, RECOVERY_SIM_SELF_RECOVERY, 0); + + status = cdf_wait_single_event(&wma_handle->recovery_event, + WMA_CRASH_INJECT_TIMEOUT); + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "CRASH_INJECT command is timed out!"); + #ifdef CONFIG_CNSS + if (cds_is_logp_in_progress()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "LOGP is in progress, ignore!"); + return; + } + cds_set_logp_in_progress(true); + cnss_schedule_recovery_work(); + #endif + + return; + } +} + +/** + * cds_get_monotonic_boottime() - Get kernel boot time. + * + * Return: Time in microseconds + */ + +uint64_t cds_get_monotonic_boottime(void) +{ +#ifdef CONFIG_CNSS + struct timespec ts; + + cnss_get_monotonic_boottime(&ts); + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +#else + return ((uint64_t)cdf_system_ticks_to_msecs(cdf_system_ticks()) * + 1000); +#endif +} + +/** + * cds_set_wakelock_logging() - Logging of wakelock enabled/disabled + * @value: Boolean value + * + * This function is used to set the flag which will indicate whether + * logging of wakelock is enabled or not + * + * Return: None + */ +void cds_set_wakelock_logging(bool value) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "cds context is Invald"); + return; + } + p_cds_context->is_wakelock_log_enabled = value; +} + +/** + * cds_is_wakelock_enabled() - Check if logging of wakelock is enabled/disabled + * @value: Boolean value + * + * This function is used to check whether logging of wakelock is enabled or not + * + * Return: true if logging of wakelock is enabled + */ +bool cds_is_wakelock_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "cds context is Invald"); + return false; + } + return p_cds_context->is_wakelock_log_enabled; +} + +/** + * cds_set_ring_log_level() - Sets the log level of a particular ring + * @ring_id: ring_id + * @log_levelvalue: Log level specificed + * + * This function converts HLOS values to driver log levels and sets the log + * level of a particular ring accordingly. + * + * Return: None + */ +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level) +{ + p_cds_contextType p_cds_context; + uint32_t log_val; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invald", __func__); + return; + } + + switch (log_level) { + case LOG_LEVEL_NO_COLLECTION: + log_val = WLAN_LOG_LEVEL_OFF; + break; + case LOG_LEVEL_NORMAL_COLLECT: + log_val = WLAN_LOG_LEVEL_NORMAL; + break; + case LOG_LEVEL_ISSUE_REPRO: + log_val = WLAN_LOG_LEVEL_REPRO; + break; + case LOG_LEVEL_ACTIVE: + default: + log_val = WLAN_LOG_LEVEL_ACTIVE; + break; + } + + if (ring_id == RING_ID_WAKELOCK) { + p_cds_context->wakelock_log_level = log_val; + return; + } else if (ring_id == RING_ID_CONNECTIVITY) { + p_cds_context->connectivity_log_level = log_val; + return; + } else if (ring_id == RING_ID_PER_PACKET_STATS) { + p_cds_context->packet_stats_log_level = log_val; + return; + } else if (ring_id == RIND_ID_DRIVER_DEBUG) { + p_cds_context->driver_debug_log_level = log_val; + return; + } else if (ring_id == RING_ID_FIRMWARE_DEBUG) { + p_cds_context->fw_debug_log_level = log_val; + return; + } +} + +/** + * cds_get_ring_log_level() - Get the a ring id's log level + * @ring_id: Ring id + * + * Fetch and return the log level corresponding to a ring id + * + * Return: Log level corresponding to the ring ID + */ +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invald", __func__); + return WLAN_LOG_LEVEL_OFF; + } + + if (ring_id == RING_ID_WAKELOCK) + return p_cds_context->wakelock_log_level; + else if (ring_id == RING_ID_CONNECTIVITY) + return p_cds_context->connectivity_log_level; + else if (ring_id == RING_ID_PER_PACKET_STATS) + return p_cds_context->packet_stats_log_level; + else if (ring_id == RIND_ID_DRIVER_DEBUG) + return p_cds_context->driver_debug_log_level; + else if (ring_id == RING_ID_FIRMWARE_DEBUG) + return p_cds_context->fw_debug_log_level; + + return WLAN_LOG_LEVEL_OFF; +} + +/** + * cds_set_multicast_logging() - Set mutlicast logging value + * @value: Value of multicast logging + * + * Set the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: None + */ +void cds_set_multicast_logging(uint8_t value) +{ + cds_multicast_logging = value; +} + +/** + * cds_is_multicast_logging() - Get multicast logging value + * + * Get the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: 0 - Multicast logging disabled, 1 - Multicast logging enabled + */ +uint8_t cds_is_multicast_logging(void) +{ + return cds_multicast_logging; +} + +/* + * cds_init_log_completion() - Initialize log param structure + * + * This function is used to initialize the logging related + * parameters + * + * Return: None + */ +void cds_init_log_completion(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + + p_cds_context->log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + p_cds_context->log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + p_cds_context->log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + p_cds_context->log_complete.is_report_in_progress = false; + /* Attempting to initialize an already initialized lock + * results in a failure. This must be ok here. + */ + cdf_spinlock_init(&p_cds_context->bug_report_lock); +} + +/** + * cds_deinit_log_completion() - Deinitialize log param structure + * + * This function is used to deinitialize the logging related + * parameters + * + * Return: None + */ +void cds_deinit_log_completion(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + + cdf_spinlock_destroy(&p_cds_context->bug_report_lock); +} + +/** + * cds_set_log_completion() - Store the logging params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * + * This function is used to set the logging parameters based on the + * caller + * + * Return: 0 if setting of params is successful + */ +CDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return CDF_STATUS_E_FAILURE; + } + + cdf_spinlock_acquire(&p_cds_context->bug_report_lock); + p_cds_context->log_complete.is_fatal = is_fatal; + p_cds_context->log_complete.indicator = indicator; + p_cds_context->log_complete.reason_code = reason_code; + p_cds_context->log_complete.is_report_in_progress = true; + cdf_spinlock_release(&p_cds_context->bug_report_lock); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_log_completion() - Get the logging related params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * + * This function is used to get the logging related parameters + * + * Return: None + */ +void cds_get_log_completion(uint32_t *is_fatal, + uint32_t *indicator, + uint32_t *reason_code) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + + cdf_spinlock_acquire(&p_cds_context->bug_report_lock); + *is_fatal = p_cds_context->log_complete.is_fatal; + *indicator = p_cds_context->log_complete.indicator; + *reason_code = p_cds_context->log_complete.reason_code; + p_cds_context->log_complete.is_report_in_progress = false; + cdf_spinlock_release(&p_cds_context->bug_report_lock); +} + +/** + * cds_is_log_report_in_progress() - Check if bug reporting is in progress + * + * This function is used to check if the bug reporting is already in progress + * + * Return: true if the bug reporting is in progress + */ +bool cds_is_log_report_in_progress(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return true; + } + return p_cds_context->log_complete.is_report_in_progress; +} + +/** + * cds_flush_logs() - Report fatal event to userspace + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * + * This function sets the log related params and send the WMI command to the + * FW to flush its logs. On receiving the flush completion event from the FW + * the same will be conveyed to userspace + * + * Return: 0 on success + */ +CDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code) +{ + uint32_t ret; + CDF_STATUS status; + + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (cds_is_log_report_in_progress() == true) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, is_fatal, indicator, reason_code); + return CDF_STATUS_E_FAILURE; + } + + status = cds_set_log_completion(is_fatal, indicator, reason_code); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to set log trigger params", __func__); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Triggering bug report: type:%d, indicator=%d reason_code=%d", + __func__, is_fatal, indicator, reason_code); + + ret = sme_send_flush_logs_cmd_to_fw(p_cds_context->pMACContext); + if (0 != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to send flush FW log", __func__); + cds_init_log_completion(); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_logging_set_fw_flush_complete() - Wrapper for FW log flush completion + * + * This function is used to send signal to the logger thread to indicate + * that the flushing of FW logs is complete by the FW + * + * Return: None + * + */ +void cds_logging_set_fw_flush_complete(void) +{ + wlan_logging_set_fw_flush_complete(); +} diff --git a/core/cds/src/cds_concurrency.c b/core/cds/src/cds_concurrency.c new file mode 100644 index 0000000000..71a0464baa --- /dev/null +++ b/core/cds/src/cds_concurrency.c @@ -0,0 +1,6823 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_concurrency.c + * + * WLAN Concurrenct Connection Management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_hostapd.h" +#include "cds_concurrency.h" +#include "cdf_types.h" +#include "cdf_trace.h" + +#include +#include +#include +#include +#include +#include +#include "sap_api.h" +#include +#include +#include +#include "cfg_api.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_api.h" +#include "cds_utils.h" +#include "cds_reg_service.h" +#include "wlan_hdd_ipa.h" + +#define CDS_MAX_FEATURE_SET 8 +static struct cds_conc_connection_info + conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + +#define CONC_CONNECTION_LIST_VALID_INDEX(index) \ + ((MAX_NUMBER_OF_CONC_CONNECTIONS > index) && \ + (conc_connection_list[index].in_use)) + +#define CDS_MAX_CON_STRING_LEN 50 +/** + * first_connection_pcl_table - table which provides PCL for the + * very first connection in the system + */ +static const enum cds_pcl_type +first_connection_pcl_table[CDS_MAX_NUM_OF_MODE] + [CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE}, + [CDS_SAP_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_IBSS_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE}, +}; + +/** + * second_connection_pcl_dbs_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS supported by HW) + */ +static const enum cds_pcl_type +second_connection_pcl_dbs_table[CDS_MAX_ONE_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = {CDS_5G, CDS_5G, CDS_5G } }, + + [CDS_STA_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = {CDS_5G, CDS_5G, CDS_5G } }, + + [CDS_STA_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_24G, CDS_24G, CDS_24G } }, + + [CDS_STA_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_24G, CDS_24G, CDS_24G } }, + + [CDS_P2P_CLI_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_1x1] = { + [CDS_STA_MODE] = {CDS_24G_SCC_CH, CDS_24G_SCC_CH, CDS_24G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_2x2] = { + [CDS_STA_MODE] = {CDS_24G_SCC_CH, CDS_24G_SCC_CH, CDS_24G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +}; + +/** + * second_connection_pcl_nodbs_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS not supported by HW) + */ +static const enum cds_pcl_type +second_connection_pcl_nodbs_table[CDS_MAX_ONE_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +}; + +/** + * third_connection_pcl_dbs_table - table which provides PCL for + * the 3rd connection, when we have two connections already in + * the system (with DBS supported by HW) + */ +static const enum cds_pcl_type +third_connection_pcl_dbs_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#ifndef QCA_WIFI_3_0_EMU + [CDS_STA_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#else + [CDS_STA_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#endif + [CDS_STA_P2P_GO_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#ifndef QCA_WIFI_3_0_EMU + [CDS_STA_P2P_GO_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#else + [CDS_STA_P2P_GO_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#endif + [CDS_STA_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#ifndef QCA_WIFI_3_0_EMU + [CDS_STA_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#else + [CDS_STA_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#endif + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#ifndef QCA_WIFI_3_0_EMU + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#else + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#endif + [CDS_P2P_GO_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#ifndef QCA_WIFI_3_0_EMU + [CDS_P2P_GO_SAP_DBS_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_ON_5_SCC_ON_24_5G, + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_SCC_ON_5_SCC_ON_24_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#else + [CDS_P2P_GO_SAP_DBS_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_ON_5_SCC_ON_24, + CDS_SCC_ON_5_SCC_ON_24, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +#endif +}; + +/** + * third_connection_pcl_nodbs_table - table which provides PCL + * for the 3rd connection, when we have two connections already + * in the system (with DBS not supported by HW) + */ +static const enum cds_pcl_type +third_connection_pcl_nodbs_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_5G, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH_5G, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +}; + +/** + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static const enum cds_conc_next_action +next_action_two_connection_table[CDS_MAX_ONE_CONNECTION_MODE][CDS_MAX_BAND] = { + [CDS_STA_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_CLI_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_CLI_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_CLI_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_CLI_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_SAP_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_SAP_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_SAP_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_SAP_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_IBSS_24_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_IBSS_24_2x2] = {CDS_NOP, CDS_NOP}, + [CDS_IBSS_5_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_IBSS_5_2x2] = {CDS_NOP, CDS_NOP}, +}; + +/** + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static const enum cds_conc_next_action +next_action_three_connection_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_BAND] = { + [CDS_STA_SAP_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_SAP_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_SAP_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_SAP_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_SAP_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_SAP_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_SAP_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_SAP_MCC_24_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_STA_P2P_GO_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_GO_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_GO_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_GO_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_STA_P2P_CLI_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_CLI_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_P2P_GO_SAP_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_SAP_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_SAP_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_SAP_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_DBS_1x1] = {CDS_NOP, CDS_NOP}, +}; + +/** + * cds_update_conc_list() - Update the concurrent connection list + * @conn_index: Connection index + * @mode: Mode + * @chan: Channel + * @mac: Mac id + * @chain_mask: Chain mask + * @tx_spatial_stream: Tx spatial stream + * @rx_spatial_stream: Rx spatial stream + * @vdev_id: vdev id + * @in_use: Flag to indicate if the index is in use or not + * + * Updates the index value of the concurrent connection list + * + * Return: None + */ +static void cds_update_conc_list(uint32_t conn_index, + enum cds_con_mode mode, + uint8_t chan, + uint8_t mac, + enum cds_chain_mode chain_mask, + uint8_t tx_spatial_stream, + uint8_t rx_spatial_stream, + uint32_t original_nss, + uint32_t vdev_id, + bool in_use) +{ + if (conn_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) { + cds_err("Number of connections exceeded conn_index: %d", + conn_index); + return; + } + conc_connection_list[conn_index].mode = mode; + conc_connection_list[conn_index].chan = chan; + conc_connection_list[conn_index].mac = mac; + conc_connection_list[conn_index].chain_mask = chain_mask; + conc_connection_list[conn_index].tx_spatial_stream = tx_spatial_stream; + conc_connection_list[conn_index].rx_spatial_stream = rx_spatial_stream; + conc_connection_list[conn_index].original_nss = original_nss; + conc_connection_list[conn_index].vdev_id = vdev_id; + conc_connection_list[conn_index].in_use = in_use; +} + +/** + * cds_mode_specific_connection_count() - provides the + * count of connections of specific mode + * @hdd_ctx: HDD Context + * @mode: type of connection + * @list: To provide the indices on conc_connection_list + * (optional) + * + * This function provides the count of current connections + * + * Return: connection count of specific type + */ +static uint32_t cds_mode_specific_connection_count(hdd_context_t *hdd_ctx, + enum cds_con_mode mode, + uint32_t *list) +{ + uint32_t conn_index = 0, count = 0; + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].mode == mode) && + conc_connection_list[conn_index].in_use) { + if (list != NULL) + list[count] = conn_index; + count++; + } + } + return count; +} + +/** + * cds_store_and_del_conn_info() - Store and del a connection info + * @hdd_ctx: HDD context + * @mode: Mode whose entry has to be deleted + * @info: Struture pointer where the connection info will be saved + * + * Saves the connection info corresponding to the provided mode + * and deleted that corresponding entry based on vdev from the + * connection info structure + * + * Return: None + */ +static void cds_store_and_del_conn_info(hdd_context_t *hdd_ctx, + enum cds_con_mode mode, + struct cds_conc_connection_info *info) +{ + uint32_t conn_index = 0; + bool found = false; + + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (mode == conc_connection_list[conn_index].mode) { + found = true; + break; + } + conn_index++; + } + + if (!found) { + cds_err("Mode:%d not available in the conn info", mode); + return; + } + + /* Storing the STA entry which will be temporarily deleted */ + *info = conc_connection_list[conn_index]; + + /* Deleting the STA entry */ + cds_decr_connection_count(hdd_ctx, info->vdev_id); + + cds_info("Stored %d (%d), deleted STA entry with vdev id %d, index %d", + info->vdev_id, info->mode, info->vdev_id, conn_index); + + /* Caller should set the PCL and restore the STA entry in conn info */ +} + +/** + * cds_restore_deleted_conn_info() - Restore connection info + * @hdd_ctx: HDD context + * @info: Saved connection info that is to be restored + * + * Restores the connection info of STA that was saved before + * updating the PCL to the FW + * + * Return: None + */ +static void cds_restore_deleted_conn_info(hdd_context_t *hdd_ctx, + struct cds_conc_connection_info *info) +{ + uint32_t conn_index; + + conn_index = cds_get_connection_count(hdd_ctx); + if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) { + cds_err("Failed to restore the deleted information %d/%d", + conn_index, MAX_NUMBER_OF_CONC_CONNECTIONS); + return; + } + + conc_connection_list[conn_index] = *info; + + cds_info("Restored the deleleted conn info, vdev:%d, index:%d", + info->vdev_id, conn_index); +} + +/** + * cds_update_hw_mode_conn_info() - Update connection info based on HW mode + * @num_vdev_mac_entries: Number of vdev-mac id entries that follow + * @vdev_mac_map: Mapping of vdev-mac id + * @hw_mode: HW mode + * + * Updates the connection info parameters based on the new HW mode + * + * Return: None + */ +static void cds_update_hw_mode_conn_info(uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map, + struct sir_hw_mode_params hw_mode) +{ + uint32_t i, conn_index, found; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + cds_err("Invalid HDD Context"); + return; + } + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + for (i = 0; i < num_vdev_mac_entries; i++) { + conn_index = 0; + found = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_mac_map[i].vdev_id == + conc_connection_list[conn_index].vdev_id) { + found = 1; + break; + } + conn_index++; + } + if (found) { + conc_connection_list[conn_index].mac = + vdev_mac_map[i].mac_id; + if (vdev_mac_map[i].mac_id == 0) { + conc_connection_list[conn_index]. + tx_spatial_stream = hw_mode.mac0_tx_ss; + conc_connection_list[conn_index]. + rx_spatial_stream = hw_mode.mac0_rx_ss; + } else { + conc_connection_list[conn_index]. + tx_spatial_stream = hw_mode.mac1_tx_ss; + conc_connection_list[conn_index]. + rx_spatial_stream = hw_mode.mac1_rx_ss; + } + cds_info("vdev:%d, mac:%d, tx ss:%d, rx ss;%d", + conc_connection_list[conn_index].vdev_id, + conc_connection_list[conn_index].mac, + conc_connection_list[conn_index].tx_spatial_stream, + conc_connection_list[conn_index].rx_spatial_stream); + } + } + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); +} + +/** + * cds_soc_set_dual_mac_cfg_cb() - Callback for set dual mac config + * @status: Status of set dual mac config + * @scan_config: Current scan config whose status is the first param + * @fw_mode_config: Current FW mode config whose status is the first param + * + * Callback on setting the dual mac configuration + * + * Return: None + */ +void cds_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config) +{ + cds_info("Status:%d for scan_config:%x fw_mode_config:%x", + status, scan_config, fw_mode_config); +} + +/** + * cds_set_dual_mac_scan_config() - Set the dual MAC scan config + * @hdd_ctx: HDD context + * @dbs_val: Value of DBS bit + * @dbs_plus_agile_scan_val: Value of DBS plus agile scan bit + * @single_mac_scan_with_dbs_val: Value of Single MAC scan with DBS + * + * Set the values of scan config. For FW mode config, the existing values + * will be retained + * + * Return: None + */ +void cds_set_dual_mac_scan_config(hdd_context_t *hdd_ctx, + uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val) +{ + struct sir_dual_mac_config cfg; + CDF_STATUS status; + + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs_val != 0) + dbs_val = 1; + if (dbs_plus_agile_scan_val != 0) + dbs_plus_agile_scan_val = 1; + if (single_mac_scan_with_dbs_val != 0) + single_mac_scan_with_dbs_val = 1; + + status = wma_get_updated_scan_config(&cfg.scan_config, + dbs_val, + dbs_plus_agile_scan_val, + single_mac_scan_with_dbs_val); + if (status != CDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_scan_config failed %d", status); + return; + } + + status = wma_get_updated_fw_mode_config(&cfg.fw_mode_config, + wma_get_dbs_config(), + wma_get_agile_dfs_config()); + if (status != CDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_fw_mode_config failed %d", status); + return; + } + + cfg.set_dual_mac_cb = (void *)cds_soc_set_dual_mac_cfg_cb; + + cds_info("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != CDF_STATUS_SUCCESS) { + cds_err("sme_soc_set_dual_mac_config failed %d", status); + return; + } +} + +/** + * cds_set_dual_mac_fw_mode_config() - Set the dual mac FW mode config + * @hdd_ctx: HDD context + * @dbs: DBS bit + * @dfs: Agile DFS bit + * + * Set the values of fw mode config. For scan config, the existing values + * will be retain. + * + * Return: None + */ +void cds_set_dual_mac_fw_mode_config(hdd_context_t *hdd_ctx, + uint8_t dbs, + uint8_t dfs) +{ + struct sir_dual_mac_config cfg; + CDF_STATUS status; + + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs != 0) + dbs = 1; + if (dfs != 0) + dfs = 1; + + status = wma_get_updated_scan_config(&cfg.scan_config, + wma_get_dbs_scan_config(), + wma_get_dbs_plus_agile_scan_config(), + wma_get_single_mac_scan_with_dfs_config()); + if (status != CDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_scan_config failed %d", status); + return; + } + + status = wma_get_updated_fw_mode_config(&cfg.fw_mode_config, + dbs, dfs); + if (status != CDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_fw_mode_config failed %d", status); + return; + } + + cfg.set_dual_mac_cb = (void *)cds_soc_set_dual_mac_cfg_cb; + + cds_info("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != CDF_STATUS_SUCCESS) { + cds_err("sme_soc_set_dual_mac_config failed %d", status); + return; + } +} + +/** + * cds_soc_set_hw_mode_cb() - Callback for set hw mode + * @status: Status + * @cfgd_hw_mode_index: Configured HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * + * Provides the status and configured hw mode index set + * by the FW + * + * Return: None + */ +static void cds_soc_set_hw_mode_cb(uint32_t status, + uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map) +{ + CDF_STATUS ret; + struct sir_hw_mode_params hw_mode; + uint32_t i; + p_cds_contextType cds_context; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return; + } + + if (status != SET_HW_MODE_STATUS_OK) { + cds_err("Set HW mode failed with status %d", status); + return; + } + + if (!vdev_mac_map) { + cds_err("vdev_mac_map is NULL"); + return; + } + + cds_info("cfgd_hw_mode_index=%d", cfgd_hw_mode_index); + + for (i = 0; i < num_vdev_mac_entries; i++) + cds_info("vdev_id:%d mac_id:%d", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + + ret = wma_get_hw_mode_from_idx(cfgd_hw_mode_index, &hw_mode); + if (ret != CDF_STATUS_SUCCESS) { + cds_err("Get HW mode failed: %d", ret); + return; + } + + cds_info("MAC0: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, hw_mode.mac0_bw); + cds_info("MAC1: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, hw_mode.mac1_bw); + cds_info("DBS:%d, Agile DFS:%d", + hw_mode.dbs_cap, hw_mode.agile_dfs_cap); + + /* update conc_connection_list */ + cds_update_hw_mode_conn_info(num_vdev_mac_entries, + vdev_mac_map, + hw_mode); + + ret = cdf_event_set(&cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(ret)) + cds_err("ERROR: set connection_update_done event failed"); + + return; +} + +/** + * cds_hw_mode_transition_cb() - Callback for HW mode transition from FW + * @old_hw_mode_index: Old HW mode index + * @new_hw_mode_index: New HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * + * Provides the old and new HW mode index set by the FW + * + * Return: None + */ +static void cds_hw_mode_transition_cb(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map) +{ + CDF_STATUS status; + struct sir_hw_mode_params hw_mode; + uint32_t i; + + if (!vdev_mac_map) { + cds_err("vdev_mac_map is NULL"); + return; + } + + cds_info("old_hw_mode_index=%d, new_hw_mode_index=%d", + old_hw_mode_index, new_hw_mode_index); + + for (i = 0; i < num_vdev_mac_entries; i++) + cds_info("vdev_id:%d mac_id:%d", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + + status = wma_get_hw_mode_from_idx(new_hw_mode_index, &hw_mode); + if (status != CDF_STATUS_SUCCESS) { + cds_err("Get HW mode failed: %d", status); + return; + } + + cds_info("MAC0: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, hw_mode.mac0_bw); + cds_info("MAC1: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, hw_mode.mac1_bw); + cds_info("DBS:%d, Agile DFS:%d", + hw_mode.dbs_cap, hw_mode.agile_dfs_cap); + + /* update conc_connection_list */ + cds_update_hw_mode_conn_info(num_vdev_mac_entries, + vdev_mac_map, + hw_mode); + + return; +} + +/** + * cds_soc_set_hw_mode() - Set HW mode command to SME + * @hdd_ctx: HDD context + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * + * Sends the set hw mode to the SME module which will pass on + * this message to WMA layer + * + * e.g.: To configure 2x2_80 + * mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_0x0, mac1_bw = HW_MODE_BW_NONE + * dbs = HW_MODE_DBS_NONE, dfs = HW_MODE_AGILE_DFS_NONE + * e.g.: To configure 1x1_80_1x1_40 (DBS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE + * e.g.: To configure 1x1_80_1x1_40 (Agile DFS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS + * + * Return: Success if the message made it down to the next layer + */ +CDF_STATUS cds_soc_set_hw_mode(hdd_context_t *hdd_ctx, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs) +{ + int8_t hw_mode_index; + struct sir_hw_mode msg; + CDF_STATUS status; + + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return CDF_STATUS_E_FAILURE; + } + + hw_mode_index = wma_get_hw_mode_idx_from_dbs_hw_list(mac0_ss, + mac0_bw, mac1_ss, mac1_bw, dbs, dfs); + if (hw_mode_index < 0) { + cds_err("Invalid HW mode index obtained"); + return CDF_STATUS_E_FAILURE; + } + + msg.hw_mode_index = hw_mode_index; + msg.set_hw_mode_cb = (void *)cds_soc_set_hw_mode_cb; + + cds_info("set hw mode to sme: hw_mode_index: %d", + msg.hw_mode_index); + + status = sme_soc_set_hw_mode(hdd_ctx->hHal, msg); + if (status != CDF_STATUS_SUCCESS) { + cds_err("Failed to set hw mode to SME"); + return status; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_is_connection_in_progress() - check if connection is in progress + * @hdd_ctx - HDD context + * + * Go through each adapter and check if Connection is in progress + * + * Return: true if connection is in progress else false + */ +bool cds_is_connection_in_progress(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_station_ctx_t *hdd_sta_ctx = NULL; + hdd_adapter_t *adapter = NULL; + CDF_STATUS status = 0; + uint8_t sta_id = 0; + uint8_t *sta_mac = NULL; + + if (true == hdd_ctx->btCoexModeSet) { + cds_info("BTCoex Mode operation in progress"); + return true; + } + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && CDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (!adapter) + goto end; + + cds_info("Adapter with device mode %s(%d) exists", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + if (((WLAN_HDD_INFRA_STATION == adapter->device_mode) + || (WLAN_HDD_P2P_CLIENT == adapter->device_mode) + || (WLAN_HDD_P2P_DEVICE == adapter->device_mode)) + && (eConnectionState_Connecting == + (WLAN_HDD_GET_STATION_CTX_PTR(adapter))-> + conn_info.connState)) { + cds_err("%p(%d) Connection is in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->sessionId); + return true; + } + if ((WLAN_HDD_INFRA_STATION == adapter->device_mode) && + sme_neighbor_middle_of_roaming( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId)) { + cds_err("%p(%d) Reassociation in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->sessionId); + return true; + } + if ((WLAN_HDD_INFRA_STATION == adapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == adapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == adapter->device_mode)) { + hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((eConnectionState_Associated == + hdd_sta_ctx->conn_info.connState) + && (false == + hdd_sta_ctx->conn_info.uIsAuthenticated)) { + sta_mac = (uint8_t *) + &(adapter->macAddressCurrent.bytes[0]); + cds_err("client " MAC_ADDRESS_STR + " is in middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(sta_mac)); + return true; + } + } else if ((WLAN_HDD_SOFTAP == adapter->device_mode) || + (WLAN_HDD_P2P_GO == adapter->device_mode)) { + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; + sta_id++) { + if (!((adapter->aStaInfo[sta_id].isUsed) + && (ol_txrx_peer_state_conn == + adapter->aStaInfo[sta_id].tlSTAState))) + continue; + + sta_mac = (uint8_t *) + &(adapter->aStaInfo[sta_id]. + macAddrSTA.bytes[0]); + cds_err("client " MAC_ADDRESS_STR + " of SAP/GO is in middle of WPS/EAPOL exchange", + MAC_ADDR_ARRAY(sta_mac)); + return true; + } + if (hdd_ctx->connection_in_progress) { + cds_err("AP/GO: connection is in progress"); + return true; + } + } +end: + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + return false; +} + +/** + * cds_dump_current_concurrency_one_connection() - To dump the + * current concurrency info with one connection + * @hdd_ctx: HDD context + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_one_connection( + hdd_context_t *hdd_ctx, char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + + switch (conc_connection_list[0].mode) { + case CDS_STA_MODE: + count = strlcat(cc_mode, "STA", + length); + break; + case CDS_SAP_MODE: + count = strlcat(cc_mode, "SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = strlcat(cc_mode, "P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = strlcat(cc_mode, "P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = strlcat(cc_mode, "IBSS", + length); + break; + default: + /* err msg */ + cds_err("unexpected mode %d", conc_connection_list[0].mode); + break; + } + return count; +} + +/** + * cds_dump_current_concurrency_two_connection() - To dump the + * current concurrency info with two connections + * @hdd_ctx: HDD context + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_two_connection( + hdd_context_t *hdd_ctx, char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + + switch (conc_connection_list[1].mode) { + case CDS_STA_MODE: + count = cds_dump_current_concurrency_one_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case CDS_SAP_MODE: + count = cds_dump_current_concurrency_one_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = cds_dump_current_concurrency_one_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = cds_dump_current_concurrency_one_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = cds_dump_current_concurrency_one_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + /* err msg */ + cds_err("unexpected mode %d", conc_connection_list[1].mode); + break; + } + return count; +} + +/** + * cds_dump_current_concurrency_three_connection() - To dump the + * current concurrency info with three connections + * @hdd_ctx: HDD context + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_three_connection( + hdd_context_t *hdd_ctx, char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + + switch (conc_connection_list[2].mode) { + case CDS_STA_MODE: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case CDS_SAP_MODE: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + /* err msg */ + cds_err("unexpected mode %d", conc_connection_list[2].mode); + break; + } + return count; +} + +/** + * cds_dump_dbs_concurrency() - To dump the dbs concurrency + * combination + * @cc_mode: connection string + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void cds_dump_dbs_concurrency(char *cc_mode, uint32_t length) +{ + strlcat(cc_mode, " DBS", length); + if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (0 == conc_connection_list[0].mac) + strlcat(cc_mode, " with SCC on mac0", + length); + else + strlcat(cc_mode, " with SCC on mac1", + length); + } else { + if (0 == conc_connection_list[0].mac) + strlcat(cc_mode, " with MCC on mac0", + length); + else + strlcat(cc_mode, " with MCC on mac1", + length); + } + } + if (conc_connection_list[0].mac == conc_connection_list[2].mac) { + if (conc_connection_list[0].chan == + conc_connection_list[2].chan) { + if (0 == conc_connection_list[0].mac) + strlcat(cc_mode, " with SCC on mac0", + length); + else + strlcat(cc_mode, " with SCC on mac1", + length); + } else { + if (0 == conc_connection_list[0].mac) + strlcat(cc_mode, " with MCC on mac0", + length); + else + strlcat(cc_mode, " with MCC on mac1", + length); + } + } + if (conc_connection_list[1].mac == conc_connection_list[2].mac) { + if (conc_connection_list[1].chan == + conc_connection_list[2].chan) { + if (0 == conc_connection_list[1].mac) + strlcat(cc_mode, " with SCC on mac0", + length); + else + strlcat(cc_mode, " with SCC on mac1", + length); + } else { + if (0 == conc_connection_list[1].mac) + strlcat(cc_mode, " with MCC on mac0", + length); + else + strlcat(cc_mode, " with MCC on mac1", + length); + } + } +} + +/** + * cds_dump_current_concurrency() - To dump the current + * concurrency combination + * @hdd_ctx: HDD context + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void cds_dump_current_concurrency(hdd_context_t *hdd_ctx) +{ + uint32_t num_connections = 0; + char cc_mode[CDS_MAX_CON_STRING_LEN] = {0}; + uint32_t count = 0; + + num_connections = cds_get_connection_count(hdd_ctx); + + switch (num_connections) { + case 1: + cds_dump_current_concurrency_one_connection(hdd_ctx, cc_mode, + sizeof(cc_mode)); + cds_err("%s Standalone", cc_mode); + break; + case 2: + count = cds_dump_current_concurrency_two_connection( + hdd_ctx, cc_mode, sizeof(cc_mode)); + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + strlcat(cc_mode, " SCC", sizeof(cc_mode)); + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + strlcat(cc_mode, " MCC", sizeof(cc_mode)); + } else + strlcat(cc_mode, " DBS", sizeof(cc_mode)); + cds_err("%s", cc_mode); + break; + case 3: + count = cds_dump_current_concurrency_three_connection( + hdd_ctx, cc_mode, sizeof(cc_mode)); + if ((conc_connection_list[0].chan == + conc_connection_list[1].chan) && + (conc_connection_list[0].chan == + conc_connection_list[2].chan)){ + strlcat(cc_mode, " SCC", + sizeof(cc_mode)); + } else if ((conc_connection_list[0].mac == + conc_connection_list[1].mac) + && (conc_connection_list[0].mac == + conc_connection_list[2].mac)) { + strlcat(cc_mode, " MCC on single MAC", + sizeof(cc_mode)); + } else { + cds_dump_dbs_concurrency(cc_mode, sizeof(cc_mode)); + } + cds_err("%s", cc_mode); + break; + default: + /* err msg */ + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + return; +} + +/** + * cds_current_concurrency_is_scc() - To check the current + * concurrency combination if it is doing SCC + * @hdd_ctx: HDD context + * + * This routine is called to check if it is doing SCC + * + * Return: True - SCC, False - Otherwise + */ +static bool cds_current_concurrency_is_scc(hdd_context_t *hdd_ctx) +{ + uint32_t num_connections = 0; + bool is_scc = false; + + num_connections = cds_get_connection_count(hdd_ctx); + + switch (num_connections) { + case 1: + is_scc = true; + break; + case 2: + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + is_scc = true; + } + break; + case 3: + if ((conc_connection_list[0].chan == + conc_connection_list[1].chan) && + (conc_connection_list[0].chan == + conc_connection_list[2].chan)){ + is_scc = true; + } + break; + default: + /* err msg */ + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + return is_scc; +} + +/** + * cds_dump_legacy_concurrency() - To dump the current + * concurrency combination + * @hdd_ctx: HDD context + * @sta_channel: Channel STA connection has come up + * @ap_channel: Channel SAP connection has come up + * @p2p_channel: Channel P2P connection has come up + * @sta_bssid: BSSID to which STA is connected to + * @p2p_bssid: BSSID to which P2P is connected to + * @ap_bssid: BSSID of the AP + * @p2p_mode: P2P Client or GO + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void cds_dump_legacy_concurrency(hdd_context_t *hdd_ctx, + uint8_t sta_channel, uint8_t ap_channel, uint8_t p2p_channel, + struct cdf_mac_addr sta_bssid, struct cdf_mac_addr p2p_bssid, + struct cdf_mac_addr ap_bssid, const char *p2p_mode) +{ + const char *cc_mode = "Standalone"; + + if (sta_channel > 0) { + if (ap_channel > 0) { + if (p2p_channel > 0) { + /* STA + AP + P2P */ + if (p2p_channel == sta_channel + && ap_channel == sta_channel) { + cc_mode = "STA+AP+P2P SCC"; + } else { + if (p2p_channel == sta_channel) + cc_mode = + "STA+P2P SCC, SAP MCC"; + else if (ap_channel == sta_channel) + cc_mode = + "STA+SAP SCC, P2P MCC"; + else if (ap_channel == p2p_channel) + cc_mode = + "P2P+SAP SCC, STA MCC"; + } + } else { + /* STA + AP */ + cc_mode = (ap_channel == sta_channel) ? + "SCC" : "MCC"; + } + } else { + if (p2p_channel > 0) { + /* STA + P2P */ + cc_mode = (p2p_channel == sta_channel) ? + "SCC" : "MCC"; + } + } + } else { + if (ap_channel > 0) { + if (p2p_channel > 0) { + /* AP + P2P */ + cc_mode = (p2p_channel == ap_channel) ? + "SCC" : "MCC"; + } + } + } + if (sta_channel > 0) + cds_err("wlan(%d) " MAC_ADDRESS_STR " %s", + sta_channel, MAC_ADDR_ARRAY(sta_bssid.bytes), cc_mode); + + if (p2p_channel > 0) + cds_err("p2p-%s(%d) " MAC_ADDRESS_STR " %s", + p2p_mode, p2p_channel, MAC_ADDR_ARRAY(p2p_bssid.bytes), + cc_mode); + + if (ap_channel > 0) + cds_err("AP(%d) " MAC_ADDRESS_STR " %s", + ap_channel, MAC_ADDR_ARRAY(ap_bssid.bytes), cc_mode); + + hdd_ctx->mcc_mode = strcmp(cc_mode, "SCC"); +} + +/** + * cds_dump_concurrency_info() - To dump concurrency info + * @hdd_ctx: HDD context + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +void cds_dump_concurrency_info(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + hdd_station_ctx_t *pHddStaCtx; + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + struct cdf_mac_addr staBssid = CDF_MAC_ADDR_ZERO_INITIALIZER; + struct cdf_mac_addr p2pBssid = CDF_MAC_ADDR_ZERO_INITIALIZER; + struct cdf_mac_addr apBssid = CDF_MAC_ADDR_ZERO_INITIALIZER; + uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0; + const char *p2pMode = "DEV"; + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint8_t targetChannel = 0; + uint8_t preAdapterChannel = 0; + uint8_t channel24; + uint8_t channel5; + hdd_adapter_t *preAdapterContext = NULL; + hdd_adapter_t *adapter2_4 = NULL; + hdd_adapter_t *adapter5 = NULL; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + staChannel = + pHddStaCtx->conn_info.operationChannel; + cdf_copy_macaddr(&staBssid, + &pHddStaCtx->conn_info.bssId); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = staChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case WLAN_HDD_P2P_CLIENT: + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + p2pChannel = + pHddStaCtx->conn_info.operationChannel; + cdf_copy_macaddr(&p2pBssid, + &pHddStaCtx->conn_info.bssId); + p2pMode = "CLI"; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case WLAN_HDD_P2P_GO: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bssState == BSS_START + && hostapd_state->cdf_status == + CDF_STATUS_SUCCESS) { + p2pChannel = hdd_ap_ctx->operatingChannel; + cdf_copy_macaddr(&p2pBssid, + &adapter->macAddressCurrent); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + p2pMode = "GO"; + break; + case WLAN_HDD_SOFTAP: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bssState == BSS_START + && hostapd_state->cdf_status == + CDF_STATUS_SUCCESS) { + apChannel = hdd_ap_ctx->operatingChannel; + cdf_copy_macaddr(&apBssid, + &adapter->macAddressCurrent); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = apChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case WLAN_HDD_IBSS: + return; /* skip printing station message below */ + default: + break; + } +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (targetChannel) { + /* + * This is first adapter detected as active + * set as default for none concurrency case + */ + if (!preAdapterChannel) { + /* If IPA UC data path is enabled, + * target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX + * packet pumping in case IPA + * data path enabled + */ + if (hdd_ipa_uc_is_enabled(hdd_ctx) && + (WLAN_HDD_SOFTAP == adapter->device_mode)) { + adapter->tx_flow_low_watermark = + hdd_ctx->config->TxFlowLowWaterMark + + WLAN_TFC_IPAUC_TX_DESC_RESERVE; + } else { + adapter->tx_flow_low_watermark = + hdd_ctx->config-> + TxFlowLowWaterMark; + } + adapter->tx_flow_high_watermark_offset = + hdd_ctx->config->TxFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter->sessionId, + hdd_ctx->config->TxFlowMaxQueueDepth); + /* Temporary set log level as error + * TX Flow control feature settled down, + * will lower log level + */ + cds_err("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d", + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter->tx_flow_high_watermark_offset, + hdd_ctx->config->TxFlowMaxQueueDepth); + preAdapterChannel = targetChannel; + preAdapterContext = adapter; + } else { + /* + * SCC, disable TX flow control for both + * SCC each adapter cannot reserve dedicated + * channel resource, as a result, if any adapter + * blocked OS Q by flow control, + * blocked adapter will lost chance to recover + */ + if (preAdapterChannel == targetChannel) { + /* Current adapter */ + adapter->tx_flow_low_watermark = 0; + adapter-> + tx_flow_high_watermark_offset = 0; + ol_txrx_ll_set_tx_pause_q_depth( + adapter->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + cds_err("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter->device_mode), + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!preAdapterContext) { + cds_err("SCC: Previous adapter context NULL"); + continue; + } + + /* Previous adapter */ + preAdapterContext-> + tx_flow_low_watermark = 0; + preAdapterContext-> + tx_flow_high_watermark_offset = 0; + ol_txrx_ll_set_tx_pause_q_depth( + preAdapterContext->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + /* + * Temporary set log level as error + * TX Flow control feature settled down, + * will lower log level + */ + cds_err("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + preAdapterContext->device_mode + ), + preAdapterContext->device_mode, + targetChannel, + preAdapterContext-> + tx_flow_low_watermark, + preAdapterContext-> + tx_flow_low_watermark + + preAdapterContext-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + } + /* + * MCC, each adapter will have dedicated + * resource + */ + else { + /* current channel is 2.4 */ + if (targetChannel <= + WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) { + channel24 = targetChannel; + channel5 = preAdapterChannel; + adapter2_4 = adapter; + adapter5 = preAdapterContext; + } else { + /* Current channel is 5 */ + channel24 = preAdapterChannel; + channel5 = targetChannel; + adapter2_4 = preAdapterContext; + adapter5 = adapter; + } + + if (!adapter5) { + cds_err("MCC: 5GHz adapter context NULL"); + continue; + } + adapter5->tx_flow_low_watermark = + hdd_ctx->config-> + TxHbwFlowLowWaterMark; + adapter5-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxHbwFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter5->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + /* + * Temporary set log level as error + * TX Flow control feature settled down, + * will lower log level + */ + cds_err("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter5->device_mode), + adapter5->device_mode, + channel5, + adapter5->tx_flow_low_watermark, + adapter5-> + tx_flow_low_watermark + + adapter5-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!adapter2_4) { + cds_err("MCC: 2.4GHz adapter context NULL"); + continue; + } + adapter2_4->tx_flow_low_watermark = + hdd_ctx->config-> + TxLbwFlowLowWaterMark; + adapter2_4-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxLbwFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter2_4->sessionId, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + /* + * Temporary set log level as error + * TX Flow control feature settled down, + * will lower log level + */ + cds_err("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter2_4->device_mode), + adapter2_4->device_mode, + channel24, + adapter2_4-> + tx_flow_low_watermark, + adapter2_4-> + tx_flow_low_watermark + + adapter2_4-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + + } + } + } + targetChannel = 0; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + if (hdd_ctx->config->policy_manager_enabled) { + cds_dump_current_concurrency(hdd_ctx); + hdd_ctx->mcc_mode = !cds_current_concurrency_is_scc(hdd_ctx); + } else { + /* hdd_ctx->mcc_mode gets updated inside below function, which + * gets used by IPA + */ + cds_dump_legacy_concurrency(hdd_ctx, + staChannel, apChannel, p2pChannel, + staBssid, p2pBssid, apBssid, p2pMode); + } +} + +/** + * cds_set_concurrency_mode() - To set concurrency mode + * @hdd_ctx: HDD context + * @mode: Concurrency mode + * + * This routine is called to set the concurrency mode + * + * Return: NONE + */ +void cds_set_concurrency_mode(hdd_context_t *hdd_ctx, tCDF_CON_MODE mode) +{ + switch (mode) { + case CDF_STA_MODE: + case CDF_P2P_CLIENT_MODE: + case CDF_P2P_GO_MODE: + case CDF_SAP_MODE: + hdd_ctx->concurrency_mode |= (1 << mode); + hdd_ctx->no_of_open_sessions[mode]++; + break; + default: + break; + } + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + hdd_ctx->concurrency_mode, mode, + hdd_ctx->no_of_open_sessions[mode]); +} + +/** + * cds_clear_concurrency_mode() - To clear concurrency mode + * @hdd_ctx: HDD context + * @mode: Concurrency mode + * + * This routine is called to clear the concurrency mode + * + * Return: NONE + */ +void cds_clear_concurrency_mode(hdd_context_t *hdd_ctx, + tCDF_CON_MODE mode) +{ + switch (mode) { + case CDF_STA_MODE: + case CDF_P2P_CLIENT_MODE: + case CDF_P2P_GO_MODE: + case CDF_SAP_MODE: + hdd_ctx->no_of_open_sessions[mode]--; + if (!(hdd_ctx->no_of_open_sessions[mode])) + hdd_ctx->concurrency_mode &= (~(1 << mode)); + break; + default: + break; + } + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + hdd_ctx->concurrency_mode, mode, + hdd_ctx->no_of_open_sessions[mode]); +} + +/** + * cds_soc_set_pcl() - Sets PCL to FW + * @hdd_ctx: HDD context + * @mode: Connection mode + * + * Fetches the PCL and sends the PCL to SME + * module which in turn will send the WMI + * command WMI_SOC_SET_PCL_CMDID to the fw + * + * Return: None + */ +static void cds_soc_set_pcl(hdd_context_t *hdd_ctx, tCDF_CON_MODE mode) +{ + CDF_STATUS status; + enum cds_con_mode con_mode; + struct sir_pcl_list pcl; + pcl.pcl_len = 0; + + switch (mode) { + case CDF_STA_MODE: + con_mode = CDS_STA_MODE; + break; + case CDF_P2P_CLIENT_MODE: + con_mode = CDS_P2P_CLIENT_MODE; + break; + case CDF_P2P_GO_MODE: + con_mode = CDS_P2P_GO_MODE; + break; + case CDF_SAP_MODE: + con_mode = CDS_SAP_MODE; + break; + case CDF_IBSS_MODE: + con_mode = CDS_IBSS_MODE; + break; + default: + cds_err("Unable to set PCL to FW: %d", mode); + return; + } + + cds_debug("get pcl to set it to the FW"); + + status = cds_get_pcl(hdd_ctx, con_mode, + pcl.pcl_list, &pcl.pcl_len); + if (status != CDF_STATUS_SUCCESS) { + cds_err("Unable to set PCL to FW, Get PCL failed"); + return; + } + + status = sme_soc_set_pcl(hdd_ctx->hHal, pcl); + if (status != CDF_STATUS_SUCCESS) + cds_err("Send soc set PCL to SME failed"); + else + cds_info("Set PCL to FW for mode:%d", mode); +} + +/** + * cds_incr_active_session() - increments the number of active sessions + * @hdd_ctx: HDD Context + * @mode: Device mode + * @session_id: session ID for the connection session + * + * This function increments the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon connection indication it is + * incremented; In the case of SAP/P2P GO upon bss start it is incremented + * + * Return: None + */ +void cds_incr_active_session(hdd_context_t *hdd_ctx, tCDF_CON_MODE mode, + uint8_t session_id) +{ + switch (mode) { + case CDF_STA_MODE: + case CDF_P2P_CLIENT_MODE: + case CDF_P2P_GO_MODE: + case CDF_SAP_MODE: + hdd_ctx->no_of_active_sessions[mode]++; + break; + default: + break; + } + cds_info("No.# of active sessions for mode %d = %d", + mode, hdd_ctx->no_of_active_sessions[mode]); + /* + * Get PCL logic makes use of the connection info structure. + * Let us set the PCL to the FW before updating the connection + * info structure about the new connection. + */ + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + if (mode == CDF_STA_MODE) { + /* Set PCL of STA to the FW */ + cds_soc_set_pcl(hdd_ctx, mode); + cds_info("Set PCL of STA to FW"); + } + cds_incr_connection_count(hdd_ctx, session_id); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); +} + +/** + * cds_need_opportunistic_upgrade() - Tells us if we really + * need an upgrade to 2x2 + * @hdd_ctx: HDD context + * + * This function returns if updrade to 2x2 is needed + * + * Return: CDS_NOP = upgrade is not needed, otherwise upgrade is + * needed + */ +enum cds_conc_next_action cds_need_opportunistic_upgrade( + hdd_context_t *hdd_ctx) +{ + uint32_t conn_index; + enum cds_conc_next_action upgrade = CDS_NOP; + uint8_t mac = 0; + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return upgrade; + } + + /* Are both mac's still in use*/ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].mac == 0) && + conc_connection_list[conn_index].in_use) { + mac |= 1; + if (3 == mac) + goto done; + } else if ((conc_connection_list[conn_index].mac == 1) && + conc_connection_list[conn_index].in_use) { + mac |= 2; + if (3 == mac) + goto done; + } + } +#ifdef QCA_WIFI_3_0_EMU + /* For emulation only: if we have a connection on 2.4, stay in DBS */ + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) + goto done; +#endif + /* Let's request for single MAC mode */ + upgrade = CDS_MCC; + /* Is there any connection had an initial connection with 2x2 */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].original_nss == 1) && + conc_connection_list[conn_index].in_use) { + upgrade = CDS_MCC_UPGRADE; + goto done; + } + } + +done: + return upgrade; +} + + +/** + * cds_set_pcl_for_existing_combo() - Set PCL for existing connection + * @hdd_ctx: HDD context + * @mode: Connection mode of type 'cds_con_mode' + * + * Set the PCL for an existing connection + * + * Return: None + */ +static void cds_set_pcl_for_existing_combo(hdd_context_t *hdd_ctx, + enum cds_con_mode mode) +{ + struct cds_conc_connection_info info; + tCDF_CON_MODE pcl_mode; + + switch (mode) { + case CDS_STA_MODE: + pcl_mode = CDF_STA_MODE; + break; + case CDS_SAP_MODE: + pcl_mode = CDF_SAP_MODE; + break; + case CDS_P2P_CLIENT_MODE: + pcl_mode = CDF_P2P_CLIENT_MODE; + break; + case CDS_P2P_GO_MODE: + pcl_mode = CDF_P2P_GO_MODE; + break; + case CDS_IBSS_MODE: + pcl_mode = CDF_IBSS_MODE; + break; + default: + cds_err("Invalid mode to set PCL"); + return; + }; + + if (cds_mode_specific_connection_count( + hdd_ctx, mode, NULL) > 0) { + /* Check, store and temp delete the mode's parameter */ + cds_store_and_del_conn_info(hdd_ctx, mode, + &info); + /* Set the PCL to the FW since connection got updated */ + cds_soc_set_pcl(hdd_ctx, pcl_mode); + cds_info("Set PCL to FW for mode:%d", mode); + /* Restore the connection info */ + cds_restore_deleted_conn_info(hdd_ctx, &info); + } +} + +/** + * cds_decr_session_set_pcl() - Decrement session count and set PCL + * @hdd_ctx: HDD context + * @mode: Connection mode + * @session_id: Session id + * + * Decrements the active session count and sets the PCL if a STA connection + * exists + * + * Return: None + */ +void cds_decr_session_set_pcl(hdd_context_t *hdd_ctx, + tCDF_CON_MODE mode, + uint8_t session_id) +{ + CDF_STATUS cdf_status; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + cds_decr_active_session(hdd_ctx, mode, session_id); + /* + * After the removal of this connection, we need to check if + * a STA connection still exists. The reason for this is that + * if one or more STA exists, we need to provide the updated + * PCL to the FW for cases like LFR. + * + * Since cds_get_pcl provides PCL list based on the new + * connection that is going to come up, we will find the + * existing STA entry, save it and delete it temporarily. + * After this we will get PCL as though as new STA connection + * is coming up. This will give the exact PCL that needs to be + * given to the FW. After setting the PCL, we need to restore + * the entry that we have saved before. + */ + cds_set_pcl_for_existing_combo(hdd_ctx, CDS_STA_MODE); + /* do we need to change the HW mode */ + if (cds_need_opportunistic_upgrade(hdd_ctx)) { + /* let's start the timer */ + cdf_mc_timer_stop(&hdd_ctx->dbs_opportunistic_timer); + cdf_status = cdf_mc_timer_start( + &hdd_ctx->dbs_opportunistic_timer, + DBS_OPPORTUNISTIC_TIME * + 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cds_err("Failed to start dbs opportunistic timer"); + } + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + + return; +} + + +/** + * cds_decr_active_session() - decrements the number of active sessions + * @hdd_ctx: HDD Context + * @mode: Device mode + * @session_id: session ID for the connection session + * + * This function decrements the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon disconnection it is decremented + * In the case of SAP/P2P GO upon bss stop it is decremented + * + * Return: None + */ +void cds_decr_active_session(hdd_context_t *hdd_ctx, tCDF_CON_MODE mode, + uint8_t session_id) +{ + switch (mode) { + case CDF_STA_MODE: + case CDF_P2P_CLIENT_MODE: + case CDF_P2P_GO_MODE: + case CDF_SAP_MODE: + if (hdd_ctx->no_of_active_sessions[mode]) + hdd_ctx->no_of_active_sessions[mode]--; + break; + default: + break; + } + cds_info("No.# of active sessions for mode %d = %d", + mode, hdd_ctx->no_of_active_sessions[mode]); + cds_decr_connection_count(hdd_ctx, session_id); +} + +/** + * cds_dbs_opportunistic_timer_handler() - handler of + * dbs_opportunistic_timer + * @data: HDD context + * + * handler for dbs_opportunistic_timer + * + * Return: None + */ +void cds_dbs_opportunistic_timer_handler(void *data) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) data; + enum cds_conc_next_action action = CDS_NOP; + + if (NULL == hdd_ctx) { + cds_err("hdd_ctx is NULL"); + return; + } + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + /* if we still need it */ + action = cds_need_opportunistic_upgrade(hdd_ctx); + if (action) { + /* lets call for action */ + cds_next_actions(hdd_ctx, action); + } + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + +} + +/** + * cds_init_policy_mgr() - Initialize the policy manager + * related data structures + * @hdd_ctx: HDD Context + * + * Initialize the policy manager related data structures + * + * Return: Success if the policy manager is initialized completely + */ +CDF_STATUS cds_init_policy_mgr(hdd_context_t *hdd_ctx) +{ + CDF_STATUS status; + p_cds_contextType p_cds_context; + + cds_debug("Initializing the policy manager"); + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("Invalid CDS context"); + return CDF_STATUS_E_FAILURE; + } + + /* init conc_connection_list */ + cdf_mem_zero(conc_connection_list, sizeof(conc_connection_list)); + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_init( + &hdd_ctx->hdd_conc_list_lock))) { + cds_err("Failed to init hdd_conc_list_lock"); + /* Lets us not proceed further */ + return CDF_STATUS_E_FAILURE; + } + + sme_register_hw_mode_trans_cb(hdd_ctx->hHal, + cds_hw_mode_transition_cb); + status = cdf_mc_timer_init(&hdd_ctx->dbs_opportunistic_timer, + CDF_TIMER_TYPE_SW, + cds_dbs_opportunistic_timer_handler, + (void *)hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("Failed to init DBS opportunistic timer"); + return status; + } + + status = cdf_event_init(&p_cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("connection_update_done_evt init failed"); + return status; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_connection_for_vdev_id() - provides the + * perticular connection with the requested vdev id + * @hdd_ctx: HDD Context + * @vdev_id: vdev id of the connection + * + * This function provides the specific connection with the + * requested vdev id + * + * Return: index in the connection table + */ +uint32_t cds_get_connection_for_vdev_id(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + uint32_t conn_index = 0; + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].vdev_id == vdev_id) && + conc_connection_list[conn_index].in_use) { + break; + } + } + return conn_index; +} + + +/** + * cds_get_connection_count() - provides the count of + * current connections + * @hdd_ctx: HDD Context + * + * + * This function provides the count of current connections + * + * Return: connection count + */ +uint32_t cds_get_connection_count(hdd_context_t *hdd_ctx) +{ + uint32_t conn_index, count = 0; + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (conc_connection_list[conn_index].in_use) + count++; + } + return count; +} + +/** + * cds_get_mode() - Get mode from type and subtype + * @type: type + * @subtype: subtype + * + * Get the concurrency mode from the type and subtype + * of the interface + * + * Return: cds_con_mode + */ +enum cds_con_mode cds_get_mode(uint8_t type, uint8_t subtype) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + if (type == WMI_VDEV_TYPE_AP) { + switch (subtype) { + case 0: + mode = CDS_SAP_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + mode = CDS_P2P_GO_MODE; + break; + default: + /* err msg*/ + cds_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_STA) { + switch (subtype) { + case 0: + mode = CDS_STA_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT: + mode = CDS_P2P_CLIENT_MODE; + break; + default: + /* err msg*/ + cds_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_IBSS) { + mode = CDS_IBSS_MODE; + } else { + /* err msg */ + cds_err("Unknown type %d", type); + } + + return mode; +} + +/** + * cds_incr_connection_count() - adds the new connection to + * the current connections list + * @hdd_ctx: HDD Context + * + * + * This function adds the new connection to the current + * connections list + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_incr_connection_count(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t conn_index; + struct wma_txrx_node *wma_conn_table_entry; + + conn_index = cds_get_connection_count(hdd_ctx); + if (hdd_ctx->config->gMaxConcurrentActiveSessions < conn_index) { + /* err msg */ + cds_err("exceeded max connection limit %d", + hdd_ctx->config->gMaxConcurrentActiveSessions); + return status; + } + + wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id); + + if (NULL == wma_conn_table_entry) { + /* err msg*/ + cds_err("can't find vdev_id %d in WMA table", vdev_id); + return status; + } + + /* add the entry */ + cds_update_conc_list(conn_index, + cds_get_mode(wma_conn_table_entry->type, + wma_conn_table_entry->sub_type), + cds_freq_to_chan(wma_conn_table_entry->mhz), + wma_conn_table_entry->mac_id, + wma_conn_table_entry->chain_mask, + wma_conn_table_entry->tx_streams, + wma_conn_table_entry->rx_streams, + wma_conn_table_entry->nss, vdev_id, true); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_update_connection_info() - updates the existing + * connection in the current connections list + * @hdd_ctx: HDD Context + * + * + * This function adds the new connection to the current + * connections list + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_update_connection_info(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + bool found = false; + struct wma_txrx_node *wma_conn_table_entry; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + if (!found) { + /* err msg */ + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + return status; + } + + wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id); + + if (NULL == wma_conn_table_entry) { + /* err msg*/ + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + cds_err("can't find vdev_id %d in WMA table", vdev_id); + return status; + } + + /* add the entry */ + cds_update_conc_list(conn_index, + cds_get_mode(wma_conn_table_entry->type, + wma_conn_table_entry->sub_type), + cds_freq_to_chan(wma_conn_table_entry->mhz), + wma_conn_table_entry->mac_id, + wma_conn_table_entry->chain_mask, + wma_conn_table_entry->tx_streams, + wma_conn_table_entry->rx_streams, + wma_conn_table_entry->nss, vdev_id, true); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_decr_connection_count() - remove the old connection + * from the current connections list + * @hdd_ctx: HDD Context + * @vdev_id: vdev id of the old connection + * + * + * This function removes the old connection from the current + * connections list + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_decr_connection_count(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, next_conn_index = 0; + bool found = false; + + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + if (!found) { + /* err msg */ + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + return status; + } + next_conn_index = conn_index + 1; + while (CONC_CONNECTION_LIST_VALID_INDEX(next_conn_index)) { + conc_connection_list[conn_index].vdev_id = + conc_connection_list[next_conn_index].vdev_id; + conc_connection_list[conn_index].tx_spatial_stream = + conc_connection_list[next_conn_index].tx_spatial_stream; + conc_connection_list[conn_index].rx_spatial_stream = + conc_connection_list[next_conn_index].rx_spatial_stream; + conc_connection_list[conn_index].mode = + conc_connection_list[next_conn_index].mode; + conc_connection_list[conn_index].mac = + conc_connection_list[next_conn_index].mac; + conc_connection_list[conn_index].chan = + conc_connection_list[next_conn_index].chan; + conc_connection_list[conn_index].chain_mask = + conc_connection_list[next_conn_index].chain_mask; + conc_connection_list[conn_index].original_nss = + conc_connection_list[next_conn_index].original_nss; + conc_connection_list[conn_index].in_use = + conc_connection_list[next_conn_index].in_use; + conn_index++; + next_conn_index++; + } + + /* clean up the entry */ + cdf_mem_zero(&conc_connection_list[next_conn_index - 1], + sizeof(*conc_connection_list)); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_connection_channels() - provides the channel(s) + * on which current connection(s) is + * @hdd_ctx: HDD Context + * @channels: the channel(s) on which current connection(s) is + * @len: Number of channels + * @order: no order OR 2.4 Ghz channel followed by 5 Ghz + * channel OR 5 Ghz channel followed by 2.4 Ghz channel + * + * + * This function provides the channel(s) on which current + * connection(s) is/are + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_get_connection_channels(hdd_context_t *hdd_ctx, + uint8_t *channels, uint32_t *len, uint8_t order) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t conn_index = 0, num_channels = 0; + + if (NULL == hdd_ctx) { + /* err msg*/ + cds_err("hdd_ctx is NULL"); + status = CDF_STATUS_E_FAILURE; + return status; + } + + if ((NULL == channels) || (NULL == len)) { + /* err msg*/ + cds_err("channels or len is NULL"); + status = CDF_STATUS_E_FAILURE; + return status; + } + + if (0 == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + } + *len = num_channels; + } else if (1 == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[conn_index].chan)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + } else + conn_index++; + } + conn_index = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[conn_index].chan)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + } else + conn_index++; + } + *len = num_channels; + } else if (2 == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[conn_index].chan)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + } else + conn_index++; + } + conn_index = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[conn_index].chan)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + } else + conn_index++; + } + *len = num_channels; + } else { + cds_err("unknown order %d", order); + status = CDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * cds_update_with_safe_channel_list() - provides the safe + * channel list + * @hdd_ctx: HDD Context + * @pcl_channels: channel list + * @len: length of the list + * + * This function provides the safe channel list from the list + * provided after consulting the channel avoidance list + * + * Return: None + */ +#ifdef CONFIG_CNSS +void cds_update_with_safe_channel_list(hdd_context_t *hdd_ctx, + uint8_t *pcl_channels, uint32_t *len) +{ + uint16_t unsafe_channel_list[MAX_NUM_CHAN]; + uint8_t current_channel_list[MAX_NUM_CHAN]; + uint16_t unsafe_channel_count = 0; + uint8_t is_unsafe = 1; + uint8_t i, j; + uint32_t safe_channel_count = 0, current_channel_count = 0; + + if (len) { + current_channel_count = CDF_MIN(*len, MAX_NUM_CHAN); + } else { + cds_err("invalid number of channel length"); + return; + } + + cnss_get_wlan_unsafe_channel(unsafe_channel_list, + &unsafe_channel_count, + sizeof(unsafe_channel_list)); + + if (unsafe_channel_count) { + cdf_mem_copy(current_channel_list, pcl_channels, + current_channel_count); + cdf_mem_zero(pcl_channels, + sizeof(*pcl_channels)*current_channel_count); + + for (i = 0; i < current_channel_count; i++) { + is_unsafe = 0; + for (j = 0; j < unsafe_channel_count; j++) { + if (current_channel_list[i] == + unsafe_channel_list[j]) { + /* Found unsafe channel, update it */ + is_unsafe = 1; + cds_warn("CH %d is not safe", + current_channel_list[i]); + break; + } + } + if (!is_unsafe) { + pcl_channels[safe_channel_count++] = + current_channel_list[i]; + } + } + *len = safe_channel_count; + } + return; +} +#else +void cds_update_with_safe_channel_list(hdd_context_t *hdd_ctx, + uint8_t *pcl_channels, uint32_t *len) +{ + return; +} +#endif +/** + * cds_get_channel_list() - provides the channel list + * suggestion for new connection + * @hdd_ctx: HDD Context + * @pcl: The preferred channel list enum + * @pcl_channels: PCL channels + * @len: lenght of the PCL + * + * This function provides the actual channel list based on the + * current regulatory domain derived using preferred channel + * list enum obtained from one of the pcl_table + * + * Return: Channel List + */ +CDF_STATUS cds_get_channel_list(hdd_context_t *hdd_ctx, + enum cds_pcl_type pcl, + uint8_t *pcl_channels, uint32_t *len) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t num_channels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint32_t chan_index = 0, chan_index_24 = 0, chan_index_5 = 0; + uint8_t channel_list[MAX_NUM_CHAN] = {0}; + uint8_t channel_list_24[MAX_NUM_CHAN] = {0}; + uint8_t channel_list_5[MAX_NUM_CHAN] = {0}; + + if (NULL == hdd_ctx) { + /* err msg*/ + cds_err("hdd_ctx is NULL"); + return status; + } + + if ((NULL == pcl_channels) || (NULL == len)) { + /* err msg*/ + cds_err("pcl_channels or len is NULL"); + return status; + } + + if (CDS_MAX_PCL_TYPE == pcl) { + /* msg */ + cds_err("pcl is invalid"); + return status; + } + + if (CDS_NONE == pcl) { + /* msg */ + cds_err("pcl is 0"); + return CDF_STATUS_SUCCESS; + } + /* get the channel list for current domain */ + status = sme_get_cfg_valid_channels(hdd_ctx->hHal, channel_list, + &num_channels); + if (CDF_STATUS_SUCCESS != status) { + /* err msg*/ + cds_err("No valid channel"); + return status; + } + /* Let's divide the list in 2.4 & 5 Ghz lists */ + while ((channel_list[chan_index] <= 11) && + (chan_index_24 < MAX_NUM_CHAN)) + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if (channel_list[chan_index] == 12) { + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if (channel_list[chan_index] == 13) { + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + if (channel_list[chan_index] == 14) + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + } + } + while ((chan_index < num_channels) && + (chan_index_5 < MAX_NUM_CHAN)) + channel_list_5[chan_index_5++] = channel_list[chan_index++]; + + num_channels = 0; + switch (pcl) { + case CDS_24G: + cdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + status = CDF_STATUS_SUCCESS; + break; + case CDS_5G: + cdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH: + case CDS_MCC_CH: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 0); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH_24G: + case CDS_MCC_CH_24G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 0); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH_5G: + case CDS_MCC_CH_5G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 0); + cdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + status = CDF_STATUS_SUCCESS; + break; + case CDS_24G_SCC_CH: + case CDS_24G_MCC_CH: + cdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 0); + cdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + status = CDF_STATUS_SUCCESS; + break; + case CDS_5G_SCC_CH: + case CDS_5G_MCC_CH: + cdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 0); + cdf_mem_copy(&pcl_channels[chan_index_5], + channel_list, num_channels); + *len += num_channels; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 1); + cdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 2); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5_24G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 1); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5_5G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 1); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24_24G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 2); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + status = CDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24_5G: + cds_get_connection_channels(hdd_ctx, + channel_list, &num_channels, 2); + cdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + cdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + status = CDF_STATUS_SUCCESS; + break; + default: + /* err msg */ + cds_err("unknown pcl value %d", pcl); + break; + } + + /* check the channel avoidance list */ + cds_update_with_safe_channel_list(hdd_ctx, pcl_channels, len); + + return status; +} + +/** + * cds_map_concurrency_mode() - to map concurrency mode between sme and hdd + * @hdd_ctx: hdd context + * @old_mode: sme provided concurrency mode + * @new_mode: hdd provided concurrency mode + * + * This routine will map concurrency mode between sme and hdd + * + * Return: true or false + */ +bool cds_map_concurrency_mode(hdd_context_t *hdd_ctx, + tCDF_CON_MODE *old_mode, enum cds_con_mode *new_mode) +{ + bool status = true; + + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + switch (*old_mode) { + + case CDF_STA_MODE: + *new_mode = CDS_STA_MODE; + break; + case CDF_SAP_MODE: + *new_mode = CDS_SAP_MODE; + break; + case CDF_P2P_CLIENT_MODE: + *new_mode = CDS_P2P_CLIENT_MODE; + break; + case CDF_P2P_GO_MODE: + *new_mode = CDS_P2P_GO_MODE; + break; + case CDF_IBSS_MODE: + *new_mode = CDS_IBSS_MODE; + break; + default: + *new_mode = CDS_MAX_NUM_OF_MODE; + status = false; + break; + } + return status; +} + +/** + * cds_get_pcl() - provides the preferred channel list for + * new connection + * @hdd_ctx: HDD Context + * @mode: Device mode + * @pcl_channels: PCL channels + * @len: lenght of the PCL + * + * This function provides the preferred channel list on which + * policy manager wants the new connection to come up. Various + * connection decision making entities will using this function + * to query the PCL info + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_get_pcl(hdd_context_t *hdd_ctx, enum cds_con_mode mode, + uint8_t *pcl_channels, uint32_t *len) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t num_connections = 0; + enum cds_conc_priority_mode first_index = 0; + enum cds_one_connection_mode second_index = 0; + enum cds_two_connection_mode third_index = 0; + enum cds_pcl_type pcl = CDS_NONE; + enum cds_conc_priority_mode conc_system_pref = 0; + /* find the current connection state from conc_connection_list*/ + num_connections = cds_get_connection_count(hdd_ctx); + cds_debug("connections:%d pref:%d requested mode:%d", + num_connections, hdd_ctx->config->conc_system_pref, mode); + + switch (hdd_ctx->config->conc_system_pref) { + case 0: + conc_system_pref = CDS_THROUGHPUT; + break; + case 1: + conc_system_pref = CDS_POWERSAVE; + break; + case 2: + conc_system_pref = CDS_LATENCY; + break; + default: + /* err msg */ + cds_err("unknown conc_system_pref value %d", + hdd_ctx->config->conc_system_pref); + break; + } + + switch (num_connections) { + case 0: + first_index = + cds_get_first_connection_pcl_table_index(hdd_ctx); + pcl = first_connection_pcl_table[mode][first_index]; + break; + case 1: + second_index = + cds_get_second_connection_pcl_table_index(hdd_ctx); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + /* err msg */ + cds_err("couldn't find index for 2nd connection pcl table"); + return status; + } + if (wma_is_hw_dbs_capable() == true) { + pcl = second_connection_pcl_dbs_table + [second_index][mode][conc_system_pref]; + } else { + pcl = second_connection_pcl_nodbs_table + [second_index][mode][conc_system_pref]; + } + + break; + case 2: + third_index = + cds_get_third_connection_pcl_table_index(hdd_ctx); + if (CDS_MAX_TWO_CONNECTION_MODE == third_index) { + /* err msg */ + cds_err("couldn't find index for 3rd connection pcl table"); + return status; + } + if (wma_is_hw_dbs_capable() == true) { + pcl = third_connection_pcl_dbs_table + [third_index][mode][conc_system_pref]; + } else { + pcl = third_connection_pcl_nodbs_table + [third_index][mode][conc_system_pref]; + } + break; + default: + /* err msg */ + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + cds_debug("index1:%d index2:%d index3:%d pcl:%d dbs:%d", + first_index, second_index, third_index, + pcl, wma_is_hw_dbs_capable()); + + /* once the PCL enum is obtained find out the exact channel list with + * help from sme_get_cfg_valid_channels + */ + status = cds_get_channel_list(hdd_ctx, pcl, pcl_channels, len); + if (status == CDF_STATUS_SUCCESS) { + uint32_t i; + cds_debug("pcl len:%d", *len); + for (i = 0; i < *len; i++) + cds_debug("chan:%d", pcl_channels[i]); + } + + return status; +} + +/** + * cds_disallow_mcc() - Check for mcc + * + * @hdd_ctx: HDD Context + * @channel: channel on which new connection is coming up + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * causing MCC + * + * Return: True/False + */ +bool cds_disallow_mcc(hdd_context_t *hdd_ctx, uint8_t channel) +{ + uint32_t index = 0; + bool match = false; + while (CONC_CONNECTION_LIST_VALID_INDEX(index)) { + if (wma_is_hw_dbs_capable() == false) { + if (conc_connection_list[index].chan != + channel) { + match = true; + break; + } + } else if (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[index].chan)) { + if (conc_connection_list[index].chan != channel) { + match = true; + break; + } + } + index++; + } + return match; +} + +/** + * cds_allow_new_home_channel() - Check for allowed number of + * home channels + * + * @hdd_ctx: HDD Context + * @channel: channel on which new connection is coming up + * @num_connections: number of current connections + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False + */ +bool cds_allow_new_home_channel(hdd_context_t *hdd_ctx, + uint8_t channel, uint32_t num_connections) +{ + bool status = true; + + if ((num_connections == 2) && + (conc_connection_list[0].chan != conc_connection_list[1].chan) + && + (conc_connection_list[0].mac == conc_connection_list[1].mac)) { + if (wma_is_hw_dbs_capable() == false) { + if ((channel != conc_connection_list[0].chan) && + (channel != conc_connection_list[1].chan)) { + /* err msg */ + cds_err("don't allow 3rd home channel on same MAC"); + status = false; + } + } else if (((CDS_IS_CHANNEL_24GHZ(channel)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) || + ((CDS_IS_CHANNEL_5GHZ(channel)) && + (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[1].chan)))) { + /* err msg */ + cds_err("don't allow 3rd home channel on same MAC"); + status = false; + } +#ifndef QCA_WIFI_3_0_EMU + } +#else + } else if ((num_connections == 1) && + (conc_connection_list[0].chan != channel)) { + if (((CDS_IS_CHANNEL_24GHZ(channel)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan))) || + ((CDS_IS_CHANNEL_5GHZ(channel)) && + (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[0].chan)))) { + /* err msg */ + cds_err("don't allow 2nd home channel on same MAC"); + status = false; + } + } +#endif + return status; +} + +/** + * cds_allow_concurrency() - Check for allowed concurrency + * combination + * + * @hdd_ctx: HDD Context + * @mode: new connection mode + * @channel: channel on which new connection is coming up + * @bw: Bandwidth requested by the connection (optional) + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False + */ +bool cds_allow_concurrency(hdd_context_t *hdd_ctx, enum cds_con_mode mode, + uint8_t channel, enum hw_mode_bandwidth bw) +{ + uint32_t num_connections = 0, count = 0, index = 0; + bool status = false, match = false; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + /* find the current connection state from conc_connection_list*/ + num_connections = cds_get_connection_count(hdd_ctx); + + if (cds_max_concurrent_connections_reached()) { + cds_err("Reached max concurrent connections: %d", + hdd_ctx->config->gMaxConcurrentActiveSessions); + goto done; + } + + if (channel) { + /* don't allow 3rd home channel on same MAC */ + if (!cds_allow_new_home_channel(hdd_ctx, channel, + num_connections)) + goto done; + + /* don't allow MCC if SAP/GO on DFS channel or about to come up + * on DFS channel + */ + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_P2P_GO_MODE, list); + while (index < count) { + if ((CDS_IS_DFS_CH( + conc_connection_list[list[index]].chan)) && + (CDS_IS_CHANNEL_5GHZ(channel)) && + (channel != + conc_connection_list[list[index]].chan)) { + /* err msg */ + cds_err("don't allow MCC if SAP/GO on DFS channel"); + goto done; + } + index++; + } + + index = 0; + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_SAP_MODE, list); + while (index < count) { + if ((CDS_IS_DFS_CH( + conc_connection_list[list[index]].chan)) && + (CDS_IS_CHANNEL_5GHZ(channel)) && + (channel != + conc_connection_list[list[index]].chan)) { + /* err msg */ + cds_err("don't allow MCC if SAP/GO on DFS channel"); + goto done; + } + index++; + } + + index = 0; + if ((CDS_P2P_GO_MODE == mode) || (CDS_SAP_MODE == mode)) { + if (CDS_IS_DFS_CH(channel)) + match = cds_disallow_mcc(hdd_ctx, channel); + } + if (true == match) { + cds_err("No MCC, SAP/GO about to come up on DFS channel"); + goto done; + } + } + + /* don't allow IBSS + STA MCC */ + /* don't allow IBSS + STA SCC if IBSS is on DFS channel */ + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_STA_MODE, list); + if ((CDS_IBSS_MODE == mode) && + (cds_mode_specific_connection_count(hdd_ctx, + CDS_IBSS_MODE, list)) && count) { + /* err msg */ + cds_err("No 2nd IBSS, we already have STA + IBSS"); + goto done; + } + if ((CDS_IBSS_MODE == mode) && + (CDS_IS_DFS_CH(channel)) && count) { + /* err msg */ + cds_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel"); + goto done; + } + if (CDS_IBSS_MODE == mode) { + if (wma_is_hw_dbs_capable() == true) { + if (num_connections > 1) { + /* err msg */ + cds_err("No IBSS, we have concurrent connections already"); + goto done; + } + if (CDS_STA_MODE != conc_connection_list[0].mode) { + /* err msg */ + cds_err("No IBSS, we have a non STA connection"); + goto done; + } + if (channel && + (conc_connection_list[0].chan != channel) && + CDS_IS_SAME_BAND_CHANNELS( + conc_connection_list[0].chan, channel)) { + /* err msg */ + cds_err("No IBSS + STA MCC"); + goto done; + } + } else if (num_connections) { + /* err msg */ + cds_err("No IBSS, we have one connection already"); + goto done; + } + } + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_STA_MODE, list); + if ((CDS_STA_MODE == mode) && + (cds_mode_specific_connection_count(hdd_ctx, + CDS_IBSS_MODE, list)) && count) { + /* err msg */ + cds_err("No 2nd STA, we already have STA + IBSS"); + goto done; + } + + if ((CDS_STA_MODE == mode) && + (cds_mode_specific_connection_count(hdd_ctx, + CDS_IBSS_MODE, list))) { + if (wma_is_hw_dbs_capable() == true) { + if (num_connections > 1) { + /* err msg */ + cds_err("No 2nd STA, we already have IBSS concurrency"); + goto done; + } + if (channel && + (CDS_IS_DFS_CH(conc_connection_list[0].chan)) + && (CDS_IS_CHANNEL_5GHZ(channel))) { + /* err msg */ + cds_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel"); + goto done; + } + if ((conc_connection_list[0].chan != channel) && + CDS_IS_SAME_BAND_CHANNELS( + conc_connection_list[0].chan, channel)) { + /* err msg */ + cds_err("No IBSS + STA MCC"); + goto done; + } + } else { + /* err msg */ + cds_err("No STA, we have IBSS connection already"); + goto done; + } + } + + /* can we allow vht160 */ + if (num_connections && + ((bw == HW_MODE_80_PLUS_80_MHZ) || (bw == HW_MODE_160_MHZ))) { + /* err msg */ + cds_err("No VHT160, we have one connection already"); + goto done; + } + status = true; + +done: + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + return status; +} + +/** + * cds_get_first_connection_pcl_table_index() - provides the + * row index to firstConnectionPclTable to get to the correct + * pcl + * @hdd_ctx: HDD Context + * + * This function provides the row index to + * firstConnectionPclTable. The index is the preference config. + * + * Return: table index + */ +enum cds_conc_priority_mode cds_get_first_connection_pcl_table_index( + hdd_context_t *hdd_ctx) +{ + if (hdd_ctx->config->conc_system_pref >= CDS_MAX_CONC_PRIORITY_MODE) + return CDS_THROUGHPUT; + return hdd_ctx->config->conc_system_pref; +} + +/** + * cds_get_second_connection_pcl_table_index() - provides the + * row index to secondConnectionPclTable to get to the correct + * pcl + * @hdd_ctx: HDD Context + * + * This function provides the row index to + * secondConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from conc_connection_list. + * + * Return: table index + */ +enum cds_one_connection_mode cds_get_second_connection_pcl_table_index( + hdd_context_t *hdd_ctx) +{ + enum cds_one_connection_mode index = CDS_MAX_ONE_CONNECTION_MODE; + + if (CDS_STA_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_STA_24_1x1; + else + index = CDS_STA_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_STA_5_1x1; + else + index = CDS_STA_5_2x2; + } + } else if (CDS_SAP_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_SAP_24_1x1; + else + index = CDS_SAP_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_SAP_5_1x1; + else + index = CDS_SAP_5_2x2; + } + } else if (CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_24_1x1; + else + index = CDS_P2P_CLI_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_5_1x1; + else + index = CDS_P2P_CLI_5_2x2; + } + } else if (CDS_P2P_GO_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_24_1x1; + else + index = CDS_P2P_GO_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_5_1x1; + else + index = CDS_P2P_GO_5_2x2; + } + } else if (CDS_IBSS_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_IBSS_24_1x1; + else + index = CDS_IBSS_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_IBSS_5_1x1; + else + index = CDS_IBSS_5_2x2; + } + } + + cds_debug("mode:%d chan:%d chain:%d index:%d", + conc_connection_list[0].mode, conc_connection_list[0].chan, + conc_connection_list[0].chain_mask, index); + + return index; +} + +/** + * cds_get_third_connection_pcl_table_index() - provides the + * row index to thirdConnectionPclTable to get to the correct + * pcl + * @hdd_ctx: HDD Context + * + * This function provides the row index to + * thirdConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from conc_connection_list. + * + * Return: table index + */ +enum cds_two_connection_mode cds_get_third_connection_pcl_table_index( + hdd_context_t *hdd_ctx) +{ + enum cds_one_connection_mode index = CDS_MAX_TWO_CONNECTION_MODE; + + /* STA + SAP */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_SAP_MODE == conc_connection_list[1].mode)) || + ((CDS_SAP_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_SCC_24_1x1; + else + index = CDS_STA_SAP_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_SCC_5_1x1; + else + index = CDS_STA_SAP_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_24_1x1; + else + index = CDS_STA_SAP_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_5_1x1; + else + index = CDS_STA_SAP_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_24_5_1x1; + else + index = CDS_STA_SAP_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_SAP_DBS_1x1; + } else /* STA + P2P GO */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_SCC_24_1x1; + else + index = CDS_STA_P2P_GO_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_SCC_5_1x1; + else + index = CDS_STA_P2P_GO_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_24_1x1; + else + index = CDS_STA_P2P_GO_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_5_1x1; + else + index = CDS_STA_P2P_GO_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_24_5_1x1; + else + index = CDS_STA_P2P_GO_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_P2P_GO_DBS_1x1; + } else /* STA + P2P CLI */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_P2P_CLIENT_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_SCC_24_1x1; + else + index = CDS_STA_P2P_CLI_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_SCC_5_1x1; + else + index = CDS_STA_P2P_CLI_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_24_1x1; + else + index = CDS_STA_P2P_CLI_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_5_1x1; + else + index = CDS_STA_P2P_CLI_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_24_5_1x1; + else + index = CDS_STA_P2P_CLI_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_P2P_CLI_DBS_1x1; + } else /* P2P GO + P2P CLI */ + if (((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_P2P_CLIENT_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_SCC_24_1x1; + else + index = CDS_P2P_GO_P2P_CLI_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_SCC_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_24_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_P2P_GO_P2P_CLI_DBS_1x1; + } else /* STA + P2P CLI */ + if (((CDS_SAP_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_SAP_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_SCC_24_1x1; + else + index = CDS_P2P_GO_SAP_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_SCC_5_1x1; + else + index = CDS_P2P_GO_SAP_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_24_1x1; + else + index = CDS_P2P_GO_SAP_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_5_1x1; + else + index = CDS_P2P_GO_SAP_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_24_5_1x1; + else + index = CDS_P2P_GO_SAP_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_P2P_GO_SAP_DBS_1x1; + } + + cds_debug("mode0:%d mode1:%d chan0:%d chan1:%d chain:%d index:%d", + conc_connection_list[0].mode, conc_connection_list[1].mode, + conc_connection_list[0].chan, conc_connection_list[1].chan, + conc_connection_list[0].chain_mask, index); + + return index; +} + +/** + * cds_mode_switch_dbs_to_mcc() - initiates a mode switch + * from DBS to MCC + * @hdd_ctx: HDD Context + * + * This function initiates a mode switch from DBS to MCC if any + * change in concurrency scenario or some other external entity + * (looking for range, thermal mitigation etc.) made an explicit + * request. Notifies FW as well + * + * Return: CDF_STATUS enum + */ +CDF_STATUS cds_mode_switch_dbs_to_mcc(hdd_context_t *hdd_ctx) +{ + return CDF_STATUS_SUCCESS; +} + +/** + * cds_mode_switch_mcc_to_dbs() - initiates a mode switch + * from MCC to DBS + * @hdd_ctx: HDD Context + * + * This function initiates a mode switch from MCC to DBS if any + * change in concurrency scenario or some other external entity + * (powersave, thermal mitigation etc.) made an explicit + * request. Notifies FW as well + * + * Return: CDF_STATUS enum + */ +CDF_STATUS cds_mode_switch_mcc_to_dbs(hdd_context_t *hdd_ctx) +{ + return CDF_STATUS_SUCCESS; +} + +/** + * cds_current_connections_update() - initiates actions + * needed on current connections once channel has been decided + * for the new connection + * @hdd_ctx: HDD Context + * @channel: Channel on which new connection will be + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: CDF_STATUS enum + */ +CDF_STATUS cds_current_connections_update( + hdd_context_t *hdd_ctx, + uint8_t channel) +{ + enum cds_conc_next_action next_action = CDS_NOP; + uint32_t num_connections = 0; + enum cds_one_connection_mode second_index = 0; + enum cds_two_connection_mode third_index = 0; + enum cds_band band; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return CDF_STATUS_E_NOSUPPORT; + } + if (CDS_IS_CHANNEL_24GHZ(channel)) + band = CDS_BAND_24; + else + band = CDS_BAND_5; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + num_connections = cds_get_connection_count(hdd_ctx); + + cds_debug("num_connections=%d channel=%d", + num_connections, channel); + + switch (num_connections) { + case 0: + next_action = CDS_NOP; +#ifdef QCA_WIFI_3_0_EMU + /* For emulation only: if it is a connection on 2.4, + * request DBS + */ + if (CDS_IS_CHANNEL_24GHZ(channel)) + next_action = CDS_DBS; +#endif + break; + case 1: + second_index = + cds_get_second_connection_pcl_table_index(hdd_ctx); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + /* err msg */ + cds_err("couldn't find index for 2nd connection next action table"); + goto done; + } + next_action = + next_action_two_connection_table[second_index][band]; + break; + case 2: + third_index = + cds_get_third_connection_pcl_table_index(hdd_ctx); + if (CDS_MAX_TWO_CONNECTION_MODE == third_index) { + /* err msg */ + cds_err("couldn't find index for 3rd connection next action table"); + goto done; + } + next_action = + next_action_three_connection_table[third_index][band]; + break; + default: + /* err msg */ + cds_err("unexpected num_connections value %d", num_connections); + break; + } + + if (CDS_NOP != next_action) + status = cds_next_actions(hdd_ctx, next_action); + else + status = CDF_STATUS_E_NOSUPPORT; + + cds_debug("index2=%d index3=%d next_action=%d, band=%d status=%d", + second_index, third_index, next_action, band, status); + +done: + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + return status; +} + +/** + * cds_wait_for_nss_update() - finds out if we need to wait + * for all nss update to finish before requesting for HW mode + * update + * @hdd_ctx: HDD Context + * @action: next action to happen at policy mgr after + * beacon update + * + * This function finds out if we need to wait + * for all nss update to finish before requesting for HW mode + * update + * + * Return: boolean. True = wait for nss update, False = go ahead + * with HW mode update + */ +bool cds_wait_for_nss_update(hdd_context_t *hdd_ctx, uint8_t action) +{ + uint32_t conn_index = 0; + bool wait = false; + if (CDS_DBS == action) { + for (conn_index = 0; + conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list + [conn_index].original_nss == 1) && + (conc_connection_list + [conn_index].tx_spatial_stream == 2) && + (conc_connection_list + [conn_index].rx_spatial_stream == 2) && + conc_connection_list[conn_index].in_use) { + wait = true; + break; + } + } + } else if (CDS_MCC == action) { + for (conn_index = 0; + conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list + [conn_index].original_nss == 1) && + (conc_connection_list + [conn_index].tx_spatial_stream == 1) && + (conc_connection_list + [conn_index].rx_spatial_stream == 1) && + conc_connection_list[conn_index].in_use) { + wait = true; + break; + } + } + } + return wait; +} + +/** + * cds_nss_update_cb() - callback from SME confirming nss + * update + * @hdd_ctx: HDD Context + * @tx_status: tx completion status for updated beacon with new + * nss value + * @vdev_id: vdev id for the specific connection + * @next_action: next action to happen at policy mgr after + * beacon update + * + * This function is the callback registered with SME at nss + * update request time + * + * Return: None + */ +void cds_nss_update_cb(void *context, uint8_t tx_status, uint8_t vdev_id, + uint8_t next_action) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context; + uint32_t conn_index = 0; + bool wait = true; + + if (CDF_STATUS_E_FAILURE == tx_status) { + cds_err("nss update failed for vdev %d", vdev_id); + return; + } + if (NULL == hdd_ctx) { + cds_err("NULL hdd_ctx"); + return; + } + + /** + * Check if we are ok to request for HW mode change now + */ + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + conn_index = cds_get_connection_for_vdev_id(hdd_ctx, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + cds_err("connection not found for vdev %d", vdev_id); + return; + } + switch (next_action) { + case CDS_DBS: + conc_connection_list[conn_index].tx_spatial_stream = 1; + conc_connection_list[conn_index].rx_spatial_stream = 1; + wait = cds_wait_for_nss_update(hdd_ctx, next_action); + break; + case CDS_MCC: + conc_connection_list[conn_index].tx_spatial_stream = 2; + conc_connection_list[conn_index].rx_spatial_stream = 2; + wait = cds_wait_for_nss_update(hdd_ctx, next_action); + break; + default: + cds_err("unexpected action %d", next_action); + break; + } + if (!wait) + cds_next_actions(hdd_ctx, next_action); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + return; +} + +/** + * cds_complete_action() - initiates actions needed on + * current connections once channel has been decided for the new + * connection + * @hdd_ctx: HDD Context + * @new_nss: the new nss value + * @next_action: next action to happen at policy mgr after + * beacon update + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: CDF_STATUS enum + */ +CDF_STATUS cds_complete_action(hdd_context_t *hdd_ctx, + uint8_t new_nss, uint8_t next_action) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t index = 0, count = 0; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_index = 0; + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return CDF_STATUS_E_NOSUPPORT; + } + + /* cds_complete_action() is called by cds_next_actions(). + * All other callers of cds_next_actions() have taken mutex + * protection. So, not taking any lock inside cds_complete_action() + * during conc_connection_list access. + */ + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_P2P_GO_MODE, list); + while (index < count) { + conn_index = cds_get_connection_for_vdev_id(hdd_ctx, + conc_connection_list[list[index]].vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + cds_err("connection not found for vdev %d", + conc_connection_list[list[index]].vdev_id); + continue; + } + + if (1 == conc_connection_list[list[index]].original_nss) { + status = sme_nss_update_request(hdd_ctx->hHal, + conc_connection_list + [list[index]].vdev_id, new_nss, + cds_nss_update_cb, + next_action, hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("sme_nss_update_request() failed for vdev %d", + conc_connection_list[list[index]].vdev_id); + } + } + index++; + } + + index = 0; + count = cds_mode_specific_connection_count(hdd_ctx, + CDS_SAP_MODE, list); + while (index < count) { + if (1 == conc_connection_list[list[index]].original_nss) { + status = sme_nss_update_request(hdd_ctx->hHal, + conc_connection_list + [list[index]].vdev_id, new_nss, + cds_nss_update_cb, + next_action, hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("sme_nss_update_request() failed for vdev %d", + conc_connection_list[list[index]].vdev_id); + } + } + index++; + } + if (!CDF_IS_STATUS_SUCCESS(status)) + status = cds_next_actions(hdd_ctx, next_action); + + return status; +} + +/** + * cds_next_actions() - initiates actions needed on current + * connections once channel has been decided for the new + * connection + * @hdd_ctx: HDD Context + * @action: action to be executed + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: CDF_STATUS enum + */ +CDF_STATUS cds_next_actions(hdd_context_t *hdd_ctx, + enum cds_conc_next_action action) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + struct sir_hw_mode_params hw_mode; + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return CDF_STATUS_E_NOSUPPORT; + } + + /* check for the current HW index to see if really need any action */ + status = wma_get_current_hw_mode(&hw_mode); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("wma_get_current_hw_mode failed"); + return status; + } + /** + * if already in DBS no need to request DBS or if already in + * non dbs no need request for non dbs again. Might be needed + * to extend the logic when multiple dbs HW mode is available + */ + if ((((CDS_DBS_DOWNGRADE == action) || (CDS_DBS == action)) + && hw_mode.dbs_cap) || + (((CDS_MCC_UPGRADE == action) || (CDS_MCC == action)) + && !hw_mode.dbs_cap)) { + cds_err("driver is already in %s mode, no further action needed", + (hw_mode.dbs_cap) ? "dbs" : "non dbs"); + return CDF_STATUS_E_ALREADY; + } + + switch (action) { + case CDS_DBS_DOWNGRADE: + /* + * check if we have a beaconing entity that is using 2x2. If yes, + * update the beacon template & notify FW. Once FW confirms + * beacon updated, send down the HW mode change req + */ + status = cds_complete_action(hdd_ctx, 1, CDS_DBS); + break; + case CDS_DBS: + status = cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE); + break; + case CDS_MCC_UPGRADE: + /* + * check if we have a beaconing entity that advertised 2x2 + * intially. If yes, update the beacon template & notify FW. + * Once FW confirms beacon updated, send the HW mode change req + */ + status = cds_complete_action(hdd_ctx, 0, CDS_MCC); + break; + case CDS_MCC: + status = cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE); + break; + default: + /* err msg */ + cds_err("unexpected action value %d", action); + status = CDF_STATUS_E_FAILURE; + break; + } + + return status; +} + +/** + * cds_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix + * @wiphy: pointer phy adapter + * @wdev: pointer to wireless device structure + * @data: pointer to data buffer + * @data_len: length of data + * + * This routine will give concurrency matrix + * + * Return: int status code + */ +static int __cds_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0}; + uint8_t i, feature_sets, max_feature_sets; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX + 1]; + struct sk_buff *reply_skb; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + cds_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + cds_err("HDD context is not valid"); + return ret; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX, + data, data_len, NULL)) { + cds_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch max feature set */ + if (!tb[QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) { + cds_err("Attr max feature set size failed"); + return -EINVAL; + } + max_feature_sets = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX]); + cds_info("Max feature set size (%d)", max_feature_sets); + + /* Fill feature combination matrix */ + feature_sets = 0; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_P2P; + /* Add more feature combinations here */ + + feature_sets = CDF_MIN(feature_sets, max_feature_sets); + cds_info("Number of feature sets (%d)", feature_sets); + cds_info("Feature set matrix"); + for (i = 0; i < feature_sets; i++) + cds_info("[%d] 0x%02X", i, feature_set_matrix[i]); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * feature_sets + NLMSG_HDRLEN); + + if (reply_skb) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE, + feature_sets) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET, + sizeof(u32) * feature_sets, + feature_set_matrix)) { + cds_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + return cfg80211_vendor_cmd_reply(reply_skb); + } + cds_err("Feature set matrix: buffer alloc fail"); + return -ENOMEM; +} + +/** + * cds_cfg80211_get_concurrency_matrix() - get concurrency matrix + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int +cds_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __cds_cfg80211_get_concurrency_matrix(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * cds_get_concurrency_mode() - return concurrency mode + * + * This routine is used to retrieve concurrency mode + * + * Return: uint32_t value of concurrency mask + */ +uint32_t cds_get_concurrency_mode(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != hdd_ctx) { + cds_info("concurrency_mode = 0x%x", + hdd_ctx->concurrency_mode); + return hdd_ctx->concurrency_mode; + } + + /* we are in an invalid state :( */ + cds_err("Invalid context"); + return CDF_STA_MASK; +} + +/** + * cds_sap_restart_handle() - to handle restarting of SAP + * @work: name of the work + * + * Purpose of this function is to trigger sap start. this function + * will be called from workqueue. + * + * Return: void. + */ +static void cds_sap_restart_handle(struct work_struct *work) +{ + hdd_adapter_t *sap_adapter; + hdd_context_t *hdd_ctx = container_of(work, hdd_context_t, + sap_start_work); + cds_ssr_protect(__func__); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + cds_err("HDD context is not valid"); + cds_ssr_unprotect(__func__); + return; + } + sap_adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (sap_adapter == NULL) { + cds_err("sap_adapter is NULL"); + cds_ssr_unprotect(__func__); + return; + } + wlan_hdd_start_sap(sap_adapter); + + cds_change_sap_restart_required_status(hdd_ctx, false); + cds_ssr_unprotect(__func__); +} + +/** + * cds_check_and_restart_sap() - Check and restart sap if required + * @hdd_ctx: pointer to HDD context + * @roam_result: Roam result + * @hdd_sta_ctx: HDD station context + * + * This routine will restart the SAP if restart is pending + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_check_and_restart_sap(hdd_context_t *hdd_ctx, + eCsrRoamResult roam_result, + hdd_station_ctx_t *hdd_sta_ctx) +{ + hdd_adapter_t *sap_adapter = NULL; + hdd_ap_ctx_t *hdd_ap_ctx = NULL; + uint8_t default_sap_channel = 6; + + if (!(hdd_ctx->config->conc_custom_rule1 && + (true == cds_is_sap_restart_required(hdd_ctx)))) + return CDF_STATUS_SUCCESS; + + sap_adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (sap_adapter == NULL) { + cds_err("sap_adapter is NULL"); + return CDF_STATUS_E_FAILURE; + } + + if (test_bit(SOFTAP_BSS_STARTED, &sap_adapter->event_flags)) { + cds_err("SAP is already in started state"); + return CDF_STATUS_E_FAILURE; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(sap_adapter); + if (hdd_ap_ctx == NULL) { + cds_err("HDD sap context is NULL"); + return CDF_STATUS_E_FAILURE; + } + if ((eCSR_ROAM_RESULT_ASSOCIATED == roam_result) && + hdd_sta_ctx->conn_info.operationChannel < + SIR_11A_CHANNEL_BEGIN) { + cds_err("Starting SAP on chnl [%d] after STA assoc complete", + hdd_sta_ctx->conn_info.operationChannel); + hdd_ap_ctx->operatingChannel = + hdd_sta_ctx->conn_info.operationChannel; + } else { + /* start on default SAP channel */ + hdd_ap_ctx->operatingChannel = + default_sap_channel; + cds_err("Starting SAP on channel [%d] after STA assoc failed", + default_sap_channel); + } + hdd_ap_ctx->sapConfig.ch_params.ch_width = + hdd_ap_ctx->sapConfig.ch_width_orig; + sme_set_ch_params(WLAN_HDD_GET_HAL_CTX(sap_adapter), + hdd_ap_ctx->sapConfig.SapHw_mode, + hdd_ap_ctx->operatingChannel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); + /* + * Create a workqueue and let the workqueue handle the restart + * of sap task. if we directly call sap restart function without + * creating workqueue then our main thread might go to sleep + * which is not acceptable. + */ +#ifdef CONFIG_CNSS + cnss_init_work(&hdd_ctx->sap_start_work, + cds_sap_restart_handle); +#else + INIT_WORK(&hdd_ctx->sap_start_work, + cds_sap_restart_handle); +#endif + schedule_work(&hdd_ctx->sap_start_work); + return CDF_STATUS_SUCCESS; +} + +/** + * cds_sta_sap_concur_handle() - This function will handle Station and sap + * concurrency. + * @hdd_ctx: pointer to hdd context. + * @sta_adapter: pointer to station adapter. + * @roam_profile: pointer to station's roam profile. + * + * This function will find the AP to which station is likely to make the + * the connection, if that AP's channel happens to be different than + * SAP's channel then this function will stop the SAP. + * + * Return: true or false based on function's overall success. + */ +static bool cds_sta_sap_concur_handle(hdd_context_t *hdd_ctx, + hdd_adapter_t *sta_adapter, + tCsrRoamProfile *roam_profile) +{ + hdd_adapter_t *ap_adapter = hdd_get_adapter(hdd_ctx, + WLAN_HDD_SOFTAP); + bool are_cc_channels_same = false; + tScanResultHandle scan_cache = NULL; + CDF_STATUS status; + + if ((ap_adapter != NULL) && + test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + status = + wlan_hdd_check_custom_con_channel_rules(sta_adapter, + ap_adapter, roam_profile, &scan_cache, + &are_cc_channels_same); + if (CDF_STATUS_SUCCESS != status) { + cds_err("wlan_hdd_check_custom_con_channel_rules failed!"); + /* Not returning */ + } + status = sme_scan_result_purge( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + scan_cache); + if (CDF_STATUS_SUCCESS != status) { + cds_err("sme_scan_result_purge failed!"); + /* Not returning */ + } + /* + * are_cc_channels_same will be false incase if SAP and STA + * channel is different or STA channel is zero. + * incase if STA channel is zero then lets stop the AP and + * restart flag set, so later whenever STA channel is defined + * we can restart our SAP in that channel. + */ + if (false == are_cc_channels_same) { + cds_info("Stop AP due to mismatch with STA channel"); + wlan_hdd_stop_sap(ap_adapter); + cds_change_sap_restart_required_status(hdd_ctx, true); + return false; + } else { + cds_info("sap channels are same"); + } + } + return true; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * cds_sta_p2pgo_concur_handle() - This function will handle Station and GO + * concurrency. + * @hdd_ctx: pointer to hdd context. + * @sta_adapter: pointer to station adapter. + * @roam_profile: pointer to station's roam profile. + * @roam_id: reference to roam_id variable being passed. + * + * This function will find the AP to which station is likely to make the + * the connection, if that AP's channel happens to be different than our + * P2PGO's channel then this function will send avoid frequency event to + * framework to make P2PGO stop and also caches station's connect request. + * + * Return: true or false based on function's overall success. + */ +static bool cds_sta_p2pgo_concur_handle(hdd_context_t *hdd_ctx, + hdd_adapter_t *sta_adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + hdd_adapter_t *p2pgo_adapter = hdd_get_adapter(hdd_ctx, + WLAN_HDD_P2P_GO); + bool are_cc_channels_same = false; + tScanResultHandle scan_cache = NULL; + uint32_t p2pgo_channel_num, freq; + tHddAvoidFreqList hdd_avoid_freq_list; + CDF_STATUS status; + bool ret; + + if ((p2pgo_adapter != NULL) && + test_bit(SOFTAP_BSS_STARTED, &p2pgo_adapter->event_flags)) { + status = + wlan_hdd_check_custom_con_channel_rules(sta_adapter, + p2pgo_adapter, roam_profile, + &scan_cache, &are_cc_channels_same); + if (CDF_STATUS_SUCCESS != status) { + cds_err("wlan_hdd_check_custom_con_channel_rules failed"); + /* Not returning */ + } + /* + * are_cc_channels_same will be false incase if P2PGO and STA + * channel is different or STA channel is zero. + */ + if (false == are_cc_channels_same) { + if (true == cds_is_sta_connection_pending(hdd_ctx)) { + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CLEAR_JOIN_REQ, + sta_adapter->sessionId, *roam_id)); + ret = sme_clear_joinreq_param( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + sta_adapter->sessionId); + if (true != ret) { + cds_err("sme_clear_joinreq_param failed"); + /* Not returning */ + } + cds_change_sta_conn_pending_status(hdd_ctx, + false); + cds_info("===>Clear pending join req"); + } + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_STORE_JOIN_REQ, + sta_adapter->sessionId, *roam_id)); + /* store the scan cache here */ + ret = sme_store_joinreq_param( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + roam_profile, + scan_cache, + roam_id, + sta_adapter->sessionId); + if (true != ret) { + cds_err("sme_store_joinreq_param failed"); + /* Not returning */ + } + cds_change_sta_conn_pending_status(hdd_ctx, true); + /* + * fill frequency avoidance event and send it up, so + * p2pgo stop event should get trigger from upper layer + */ + p2pgo_channel_num = + WLAN_HDD_GET_AP_CTX_PTR(p2pgo_adapter)-> + operatingChannel; + if (p2pgo_channel_num <= 14) { + freq = ieee80211_channel_to_frequency( + p2pgo_channel_num, + IEEE80211_BAND_2GHZ); + } else { + freq = ieee80211_channel_to_frequency( + p2pgo_channel_num, + IEEE80211_BAND_5GHZ); + } + cdf_mem_zero(&hdd_avoid_freq_list, + sizeof(hdd_avoid_freq_list)); + hdd_avoid_freq_list.avoidFreqRangeCount = 1; + hdd_avoid_freq_list.avoidFreqRange[0].startFreq = freq; + hdd_avoid_freq_list.avoidFreqRange[0].endFreq = freq; + wlan_hdd_send_avoid_freq_event(hdd_ctx, + &hdd_avoid_freq_list); + cds_info("===>Sending chnl_avoid ch[%d] freq[%d]", + p2pgo_channel_num, freq); + cds_info("=>Stop GO due to mismatch with STA channel"); + return false; + } else { + cds_info("===>p2pgo channels are same"); + status = sme_scan_result_purge( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + scan_cache); + if (CDF_STATUS_SUCCESS != status) { + cds_err("sme_scan_result_purge failed"); + /* Not returning */ + } + } + } + return true; +} +#endif + +/** + * cds_handle_conc_rule1() - Check if concurrency rule1 is enabled + * @hdd_ctx: HDD context + * @adapter: HDD adpater + * @roam_profile: Profile for connection + * + * Check if concurrency rule1 is enabled. As per rule1, if station is trying to + * connect to some AP in 2.4Ghz and SAP is already in started state then SAP + * should restart in station's + * + * Return: None + */ +void cds_handle_conc_rule1(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile) +{ + bool ret; + + /* + * Custom concurrency rule1: As per this rule if station is + * trying to connect to some AP in 2.4Ghz and SAP is already + * in started state then SAP should restart in station's + * channel. + */ + if (hdd_ctx->config->conc_custom_rule1 && + (WLAN_HDD_INFRA_STATION == adapter->device_mode)) { + ret = cds_sta_sap_concur_handle(hdd_ctx, adapter, + roam_profile); + if (true != ret) { + cds_err("cds_sta_sap_concur_handle failed"); + /* Nothing to do for now */ + } + } +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * cds_handle_conc_rule2() - Check if concurrency rule2 is enabled + * @hdd_ctx: HDD context + * @adapter: HDD adpater + * @roam_profile: Profile for connection + * + * Check if concurrency rule1 is enabled. As per rule1, if station is trying to + * connect to some AP in 5Ghz and P2PGO is already in started state then P2PGO + * should restart in station's channel + * + * Return: None + */ +bool cds_handle_conc_rule2(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + /* + * Custom concurrency rule2: As per this rule if station is + * trying to connect to some AP in 5Ghz and P2PGO is already in + * started state then P2PGO should restart in station's channel. + */ + if (hdd_ctx->config->conc_custom_rule2 && + (WLAN_HDD_INFRA_STATION == adapter->device_mode)) { + if (false == cds_sta_p2pgo_concur_handle(hdd_ctx, + adapter, roam_profile, roam_id)) { + cds_err("P2PGO-STA chnl diff, cache join req"); + return false; + } + } + return true; +} +#endif + +/** + * cds_get_channel_from_scan_result() - to get channel from scan result + * @adapter: station adapter + * @roam_profile: pointer to roam profile + * @channel: channel to be filled + * + * This routine gets channel which most likely a candidate to which STA + * will make connection. + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_get_channel_from_scan_result(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, uint8_t *channel) +{ + CDF_STATUS status; + tScanResultHandle scan_cache = NULL; + + status = sme_get_ap_channel_from_scan_cache( + WLAN_HDD_GET_HAL_CTX(adapter), + roam_profile, &scan_cache, + channel); + sme_scan_result_purge(WLAN_HDD_GET_HAL_CTX(adapter), scan_cache); + return status; +} + +/** + * cds_handle_conc_multiport() - to handle multiport concurrency + * @session_id: Session ID + * @channel: Channel number + * + * This routine will handle STA side concurrency when policy manager + * is enabled. + * + * Return: true or false + */ +bool cds_handle_conc_multiport(uint8_t session_id, + uint8_t channel) +{ + bool ret = true; + CDF_STATUS status; + p_cds_contextType cds_context; + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return false; + } + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return false; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id); + if (!adapter) { + cds_err("Invalid HDD adapter"); + return false; + } + + if (channel == 0) { + cds_err("Invalid channel number 0"); + return false; + } + /* Take care of 160MHz and 80+80Mhz later */ + ret = cds_allow_concurrency(hdd_ctx, + cds_convert_device_mode_to_hdd_type( + adapter->device_mode), + channel, HW_MODE_20_MHZ); + if (false == ret) { + cds_err("Connection failed due to conc check fail"); + return false; + } + + status = cdf_event_reset(&cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(status)) + cds_err("clearing event failed"); + + status = cds_current_connections_update(hdd_ctx, channel); + if (CDF_STATUS_E_FAILURE == status) { + cds_err("connections update failed"); + return false; + } + /* + * wait only if status is successful. connection update API + * will return success only in case if DBS update is required. + */ + if (CDF_STATUS_SUCCESS == status) { + status = cdf_wait_single_event( + &cds_context->connection_update_done_evt, 500); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("wait for event failed"); + return false; + } + } + return true; +} + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +/** + * cds_restart_softap() - restart SAP on STA channel to support + * STA + SAP concurrency. + * + * @hdd_ctx: pointer to hdd context + * @pHostapdAdapter: pointer to hdd adapter + * + * Return: None + */ +void cds_restart_softap(hdd_context_t *hdd_ctx, + hdd_adapter_t *pHostapdAdapter) +{ + tHddAvoidFreqList hdd_avoid_freq_list; + + /* generate vendor specific event */ + cdf_mem_zero((void *)&hdd_avoid_freq_list, sizeof(tHddAvoidFreqList)); + hdd_avoid_freq_list.avoidFreqRange[0].startFreq = + cds_chan_to_freq(pHostapdAdapter->sessionCtx.ap. + operatingChannel); + hdd_avoid_freq_list.avoidFreqRange[0].endFreq = + cds_chan_to_freq(pHostapdAdapter->sessionCtx.ap. + operatingChannel); + hdd_avoid_freq_list.avoidFreqRangeCount = 1; + wlan_hdd_send_avoid_freq_event(hdd_ctx, &hdd_avoid_freq_list); +} + +/** + * cds_force_sap_on_scc() - Force SAP on SCC + * @hdd_ctx: Pointer to HDD context + * @roam_result: Roam result + * + * Restarts SAP on SCC if its operating channel is different from that of the + * STA-AP interface + * + * Return: None + */ +void cds_force_sap_on_scc(hdd_context_t *hdd_ctx, eCsrRoamResult roam_result) +{ + hdd_adapter_t *hostapd_adapter; + + if (!(eCSR_ROAM_RESULT_ASSOCIATED == roam_result && + hdd_ctx->config->SapSccChanAvoidance)) { + cds_err("Not able to force SAP on SCC"); + return; + } + hostapd_adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (hostapd_adapter != NULL) { + /* Restart SAP if its operating channel is different + * from AP channel. + */ + if (hostapd_adapter->sessionCtx.ap.operatingChannel != + pRoamInfo->pBssDesc->channelId) { + cds_err("Restart SAP: SAP channel-%d, STA channel-%d", + hostapd_adapter->sessionCtx.ap.operatingChannel, + pRoamInfo->pBssDesc->channelId); + cds_restart_softap(hdd_ctx, hostapd_adapter); + } + } +} +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + +/** + * cds_check_sta_ap_concurrent_ch_intf() - Restart SAP in STA-AP case + * @data: Pointer to STA adapter + * + * Restarts the SAP interface in STA-AP concurrency scenario + * + * Restart: None + */ +static void cds_check_sta_ap_concurrent_ch_intf(void *data) +{ + hdd_adapter_t *ap_adapter = NULL, *sta_adapter = (hdd_adapter_t *) data; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(sta_adapter); + tHalHandle *hal_handle; + hdd_ap_ctx_t *hdd_ap_ctx; + uint16_t intf_ch = 0; + + if ((hdd_ctx->config->WlanMccToSccSwitchMode == + CDF_MCC_TO_SCC_SWITCH_DISABLE) + || !(cds_concurrent_open_sessions_running() + || !(cds_get_concurrency_mode() == + (CDF_STA_MASK | CDF_SAP_MASK)))) + return; + + ap_adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (ap_adapter == NULL) + return; + + if (!test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + return; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hal_handle = WLAN_HDD_GET_HAL_CTX(ap_adapter); + + if (hal_handle == NULL) + return; + +#ifdef WLAN_FEATURE_MBSSID + intf_ch = wlansap_check_cc_intf(hdd_ap_ctx->sapContext); +#else + intf_ch = wlansap_check_cc_intf(hdd_ctx->pcds_context); +#endif + if (intf_ch == 0) + return; + + hdd_ap_ctx->sapConfig.channel = intf_ch; + hdd_ap_ctx->sapConfig.ch_params.ch_width = + hdd_ap_ctx->sapConfig.ch_width_orig; + sme_set_ch_params(hal_handle, + hdd_ap_ctx->sapConfig.SapHw_mode, + hdd_ap_ctx->sapConfig.channel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); + cds_restart_sap(ap_adapter); +} +/** + * cds_check_concurrent_intf_and_restart_sap() - Check concurrent change intf + * @hdd_ctx: Pointer to HDD context + * @hdd_sta_ctx: Pointer to HDD STA context + * + * Checks the concurrent change interface and restarts SAP + * Return: None + */ +void cds_check_concurrent_intf_and_restart_sap(hdd_context_t *hdd_ctx, + hdd_station_ctx_t *hdd_sta_ctx, hdd_adapter_t *adapter) +{ + if ((hdd_ctx->config->WlanMccToSccSwitchMode + != CDF_MCC_TO_SCC_SWITCH_DISABLE) && + ((0 == hdd_ctx->config->conc_custom_rule1) && + (0 == hdd_ctx->config->conc_custom_rule2)) +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + && !CDS_IS_DFS_CH(hdd_sta_ctx->conn_info. + operationChannel) +#endif + ) { + cdf_create_work(0, &hdd_ctx->sta_ap_intf_check_work, + cds_check_sta_ap_concurrent_ch_intf, + (void *)adapter); + cdf_sched_work(0, &hdd_ctx->sta_ap_intf_check_work); + cds_info("Checking for Concurrent Change interference"); + } +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ + +/** + * cds_is_mcc_in_24G() - Function to check for MCC in 2.4GHz + * @hdd_ctx: Pointer to HDD context + * + * This function is used to check for MCC operation in 2.4GHz band. + * STA, P2P and SAP adapters are only considered. + * + * Return: Non zero value if MCC is detected in 2.4GHz band + * + */ +uint8_t cds_is_mcc_in_24G(hdd_context_t *hdd_ctx) +{ + CDF_STATUS status; + hdd_adapter_t *hdd_adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + uint8_t ret = 0; + hdd_station_ctx_t *sta_ctx; + hdd_ap_ctx_t *ap_ctx; + uint8_t ch1 = 0, ch2 = 0; + uint8_t channel = 0; + hdd_hostapd_state_t *hostapd_state; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + /* loop through all adapters and check MCC for STA,P2P,SAP adapters */ + while (NULL != adapter_node && CDF_STATUS_SUCCESS == status) { + hdd_adapter = adapter_node->pAdapter; + + if (!((hdd_adapter->device_mode >= WLAN_HDD_INFRA_STATION) + || (hdd_adapter->device_mode + <= WLAN_HDD_P2P_GO))) { + /* skip for other adapters */ + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + continue; + } + if (WLAN_HDD_INFRA_STATION == + hdd_adapter->device_mode || + WLAN_HDD_P2P_CLIENT == + hdd_adapter->device_mode) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR( + hdd_adapter); + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) + channel = + sta_ctx->conn_info. + operationChannel; + } else if (WLAN_HDD_P2P_GO == + hdd_adapter->device_mode || + WLAN_HDD_SOFTAP == + hdd_adapter->device_mode) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(hdd_adapter); + hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR( + hdd_adapter); + if (hostapd_state->bssState == BSS_START && + hostapd_state->cdf_status == + CDF_STATUS_SUCCESS) + channel = ap_ctx->operatingChannel; + } + + if ((ch1 == 0) || + ((ch2 != 0) && (ch2 != channel))) { + ch1 = channel; + } else if ((ch2 == 0) || + ((ch1 != 0) && (ch1 != channel))) { + ch2 = channel; + } + + if ((ch1 != 0 && ch2 != 0) && (ch1 != ch2) && + ((ch1 <= SIR_11B_CHANNEL_END) && + (ch2 <= SIR_11B_CHANNEL_END))) { + cds_err("MCC in 2.4Ghz on channels %d and %d", + ch1, ch2); + return 1; + } + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + } + return ret; +} + +/** + * cds_set_mas() - Function to set MAS value to UMAC + * @adapter: Pointer to HDD adapter + * @mas_value: 0-Disable, 1-Enable MAS + * + * This function passes down the value of MAS to UMAC + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_set_mas(hdd_adapter_t *adapter, uint8_t mas_value) +{ + hdd_context_t *hdd_ctx = NULL; + CDF_STATUS ret_status; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return -EFAULT; + + if (mas_value) { + /* Miracast is ON. Disable MAS and configure P2P quota */ + if (hdd_ctx->config->enableMCCAdaptiveScheduler) { + if (cfg_set_int(hdd_ctx->hHal, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, 0) + != eSIR_SUCCESS) { + cds_err("Could not pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CCM"); + } + ret_status = sme_set_mas(false); + if (CDF_STATUS_SUCCESS != ret_status) { + cds_err("Failed to disable MAS"); + return -EBUSY; + } + } + + /* Config p2p quota */ + if (adapter->device_mode == WLAN_HDD_INFRA_STATION) + cds_set_mcc_p2p_quota(adapter, + 100 - HDD_DEFAULT_MCC_P2P_QUOTA); + else if (adapter->device_mode == WLAN_HDD_P2P_GO) + cds_go_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + else + cds_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + } else { + /* Reset p2p quota */ + if (adapter->device_mode == WLAN_HDD_P2P_GO) + cds_go_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + else + cds_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + + /* Miracast is OFF. Enable MAS and reset P2P quota */ + if (hdd_ctx->config->enableMCCAdaptiveScheduler) { + if (cfg_set_int(hdd_ctx->hHal, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, 1) + != eSIR_SUCCESS) { + cds_err("Could not pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CCM"); + } + + /* Enable MAS */ + ret_status = sme_set_mas(true); + if (CDF_STATUS_SUCCESS != ret_status) { + cds_err("Unable to enable MAS"); + return -EBUSY; + } + } + } + + return 0; +} + +/** + * cds_set_mcc_p2p_quota() - Function to set quota for P2P + * @hostapd_adapter: Pointer to HDD adapter + * @set_value: Qouta value for the interface + * + * This function is used to set the quota for P2P cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapater, + uint32_t set_value) +{ + uint8_t first_adapter_operating_channel = 0; + uint8_t second_adapter_opertaing_channel = 0; + hdd_adapter_t *sta_adapter = NULL; + int32_t ret = 0; /* success */ + + uint32_t concurrent_state = cds_get_concurrency_mode(); + + /* + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + if ((concurrent_state == (CDF_STA_MASK | CDF_P2P_CLIENT_MASK)) || + (concurrent_state == (CDF_STA_MASK | CDF_P2P_GO_MASK))) { + cds_info("STA & P2P are both enabled"); + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector then passed on to WMA + * +***********************************************************+ + * |bit 31-24 | bit 23-16 | bits 15-8 | bits 7-0 | + * | Unused | Quota for | chan. # for | chan. # for | + * | | 1st chan. | 1st chan. | 2nd chan. | + * +***********************************************************+ + */ + /* Get the operating channel of the specified vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel + ( + hostapd_adapater->pHddCtx, + hostapd_adapater->device_mode + ); + cds_info("1st channel No.:%d and quota:%dms", + first_adapter_operating_channel, set_value); + /* Move the time quota for first channel to bits 15-8 */ + set_value = set_value << 8; + /* + * Store the channel number of 1st channel at bits 7-0 + * of the bit vector + */ + set_value = set_value | first_adapter_operating_channel; + /* Find out the 2nd MCC adapter and its operating channel */ + if (hostapd_adapater->device_mode == WLAN_HDD_INFRA_STATION) { + /* + * iwpriv cmd was issued on wlan0; + * get p2p0 vdev channel + */ + if ((concurrent_state & CDF_P2P_CLIENT_MASK) != 0) { + /* The 2nd MCC vdev is P2P client */ + sta_adapter = hdd_get_adapter( + hostapd_adapater->pHddCtx, + WLAN_HDD_P2P_CLIENT); + } else { + /* The 2nd MCC vdev is P2P GO */ + sta_adapter = hdd_get_adapter( + hostapd_adapater->pHddCtx, + WLAN_HDD_P2P_GO); + } + } else { + /* + * iwpriv cmd was issued on p2p0; + * get wlan0 vdev channel + */ + sta_adapter = hdd_get_adapter(hostapd_adapater->pHddCtx, + WLAN_HDD_INFRA_STATION); + } + if (sta_adapter != NULL) { + second_adapter_opertaing_channel = + hdd_get_operating_channel + ( + sta_adapter->pHddCtx, + sta_adapter->device_mode + ); + cds_info("2nd vdev channel No. is:%d", + second_adapter_opertaing_channel); + + if (second_adapter_opertaing_channel == 0 || + first_adapter_operating_channel == 0) { + cds_err("Invalid channel"); + return -EINVAL; + } + /* + * Now move the time quota and channel number of the + * 1st adapter to bits 23-16 and bits 15-8 of the bit + * vector, respectively. + */ + set_value = set_value << 8; + /* + * Store the channel number for 2nd MCC vdev at bits + * 7-0 of set_value + */ + set_value = set_value | + second_adapter_opertaing_channel; + ret = wma_cli_set_command(hostapd_adapater->sessionId, + WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + } else { + cds_err("NULL adapter handle. Exit"); + } + } else { + cds_info("MCC is not active. Exit w/o setting latency"); + } + return ret; +} + +/** + * cds_change_mcc_go_beacon_interval() - Change MCC beacon interval + * @pHostapdAdapter: HDD adapter + * + * Updates the beacon parameters of the GO in MCC scenario + * + * Return: Success or Failure depending on the overall function behavior + */ +CDF_STATUS cds_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal; + + cds_info("UPDATE Beacon Params"); + + if (CDF_SAP_MODE == cds_get_conparam()) { + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (NULL == hHal) { + cds_err("Hal ctx is null"); + return CDF_STATUS_E_FAULT; + } + cdf_ret_status = + sme_change_mcc_beacon_interval(hHal, + pHostapdAdapter-> + sessionId); + if (cdf_ret_status == CDF_STATUS_E_FAILURE) { + cds_err("Failed to update Beacon Params"); + return CDF_STATUS_E_FAILURE; + } + } + return CDF_STATUS_SUCCESS; +} + +/** + * cds_go_set_mcc_p2p_quota() - Function to set quota for P2P GO + * @hostapd_adapter: Pointer to HDD adapter + * @set_value: Qouta value for the interface + * + * This function is used to set the quota for P2P GO cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_go_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value) +{ + uint8_t first_adapter_operating_channel = 0; + uint8_t second_adapter_opertaing_channel = 0; + uint32_t concurrent_state = 0; + hdd_adapter_t *sta_adapter = NULL; + int32_t ret = 0; /* success */ + + /* + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than + * STA/P2P GO + */ + + concurrent_state = cds_get_concurrency_mode(); + if (concurrent_state == (CDF_STA_MASK | CDF_P2P_GO_MASK)) { + cds_info("STA & P2P are both enabled"); + + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector then passed on to WMA + * +************************************************+ + * |bit 31-24 |bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for| chan. # for |chan. # for| + * | | 1st chan.| 1st chan. |2nd chan. | + * +************************************************+ + */ + + /* Get the operating channel of the specified vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel(hostapd_adapter->pHddCtx, + hostapd_adapter->device_mode); + + cds_info("1st channel No.:%d and quota:%dms", + first_adapter_operating_channel, set_value); + + /* Move the time quota for first adapter to bits 15-8 */ + set_value = set_value << 8; + /* + * Store the operating channel number of 1st adapter at + * the lower 8-bits of bit vector. + */ + set_value = set_value | first_adapter_operating_channel; + if (hostapd_adapter->device_mode == + WLAN_HDD_INFRA_STATION) { + /* iwpriv cmd issued on wlan0; get p2p0 vdev chan */ + if ((concurrent_state & CDF_P2P_CLIENT_MASK) != 0) { + /* The 2nd MCC vdev is P2P client */ + sta_adapter = hdd_get_adapter + ( + hostapd_adapter->pHddCtx, + WLAN_HDD_P2P_CLIENT + ); + } else { + /* The 2nd MCC vdev is P2P GO */ + sta_adapter = hdd_get_adapter + ( + hostapd_adapter->pHddCtx, + WLAN_HDD_P2P_GO + ); + } + } else { + /* iwpriv cmd issued on p2p0; get channel for wlan0 */ + sta_adapter = hdd_get_adapter + ( + hostapd_adapter->pHddCtx, + WLAN_HDD_INFRA_STATION + ); + } + if (sta_adapter != NULL) { + second_adapter_opertaing_channel = + hdd_get_operating_channel + ( + sta_adapter->pHddCtx, + sta_adapter->device_mode + ); + cds_info("2nd vdev channel No. is:%d", + second_adapter_opertaing_channel); + + if (second_adapter_opertaing_channel == 0 || + first_adapter_operating_channel == 0) { + cds_err("Invalid channel"); + return -EINVAL; + } + + /* + * Move the time quota and operating channel number + * for the first adapter to bits 23-16 & bits 15-8 + * of set_value vector, respectively. + */ + set_value = set_value << 8; + /* + * Store the channel number for 2nd MCC vdev at bits + * 7-0 of set_value vector as per the bit format above. + */ + set_value = set_value | + second_adapter_opertaing_channel; + ret = wma_cli_set_command(hostapd_adapter->sessionId, + WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + } else { + cds_err("NULL adapter handle. Exit"); + } + } else { + cds_info("MCC is not active. Exit w/o setting latency"); + } + return ret; +} + +/** + * cds_set_mcc_latency() - Set MCC latency + * @adapter: Pointer to HDD adapter + * @set_value: Latency value + * + * Sets the MCC latency value during STA-P2P concurrency + * + * Return: None + */ +void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value) +{ + uint32_t concurrent_state = 0; + uint8_t first_adapter_operating_channel = 0; + int ret = 0; /* success */ + + cds_info("iwpriv cmd to set MCC latency with val %dms", + set_value); + /** + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + concurrent_state = cds_get_concurrency_mode(); + if ((concurrent_state == (CDF_STA_MASK | CDF_P2P_CLIENT_MASK)) || + (concurrent_state == (CDF_STA_MASK | CDF_P2P_GO_MASK))) { + cds_info("STA & P2P are both enabled"); + /* + * The channel number and latency are formatted in + * a bit vector then passed on to WMA layer. + * +**********************************************+ + * |bits 31-16 | bits 15-8 | bits 7-0 | + * | Unused | latency - Chan. 1 | channel no. | + * +**********************************************+ + */ + /* Get the operating channel of the designated vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel + (adapter->pHddCtx, adapter->device_mode); + /* Move the time latency for the adapter to bits 15-8 */ + set_value = set_value << 8; + /* Store the channel number at bits 7-0 of the bit vector */ + set_value = + set_value | first_adapter_operating_channel; + /* Send command to WMA */ + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_MCC_SET_TIME_LATENCY, + set_value, VDEV_CMD); + } else { + cds_info("%s: MCC is not active. Exit w/o setting latency", + __func__); + } +} + +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \ + defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) +/** + * cds_restart_sap() - This function is used to restart SAP in + * driver internally + * + * @ap_adapter: Pointer to SAP hdd_adapter_t structure + * + * Return: None + */ +void cds_restart_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + CDF_STATUS cdf_status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); +#ifdef CFG80211_DEL_STA_V2 + struct tagCsrDelStaParams delStaParams; +#endif + tsap_Config_t *sap_config; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + sap_config = &ap_adapter->sessionCtx.ap.sapConfig; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { +#ifdef CFG80211_DEL_STA_V2 + delStaParams.mac = NULL; + delStaParams.subtype = SIR_MAC_MGMT_DEAUTH >> 4; + delStaParams.reason_code = eCsrForcedDeauthSta; + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, + ap_adapter->dev, + &delStaParams); +#else + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, + ap_adapter->dev, NULL); +#endif + hdd_cleanup_actionframe(hdd_ctx, ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + cdf_event_reset(&hostapd_state->cdf_stop_bss_event); + if (CDF_STATUS_SUCCESS == wlansap_stop_bss( +#ifdef WLAN_FEATURE_MBSSID + hdd_ap_ctx->sapContext +#else + hdd_ctx->pcds_context +#endif + )) { + cdf_status = + cdf_wait_single_event(&hostapd_state-> + cdf_stop_bss_event, + BSS_WAIT_TIMEOUT); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cds_err("SAP Stop Failed"); + goto end; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_decr_session_set_pcl(hdd_ctx, + ap_adapter->device_mode, ap_adapter->sessionId); + cds_err("SAP Stop Success"); + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + cds_err("SAP Not able to set AP IEs"); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + goto end; + } + + if (wlansap_start_bss( +#ifdef WLAN_FEATURE_MBSSID + hdd_ap_ctx->sapContext, +#else + hdd_ctx->pcds_context, +#endif + hdd_hostapd_sap_event_cb, + &hdd_ap_ctx->sapConfig, + ap_adapter->dev) != + CDF_STATUS_SUCCESS) { + cds_err("SAP Start Bss fail"); + goto end; + } + + cds_info("Waiting for SAP to start"); + cdf_status = + cdf_wait_single_event(&hostapd_state->cdf_event, + BSS_WAIT_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cds_err("SAP Start failed"); + goto end; + } + cds_err("SAP Start Success"); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_incr_active_session(hdd_ctx, ap_adapter->device_mode, + ap_adapter->sessionId); + hostapd_state->bCommit = true; + } +end: + mutex_unlock(&hdd_ctx->sap_lock); + return; +} +#endif + +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE +/** + * cds_check_and_restart_sap_with_non_dfs_acs() - Restart SAP with non dfs acs + * @hdd_ctx: HDD context + * + * Restarts SAP in non-DFS ACS mode when STA-AP mode DFS is not supported + * + * Return: None + */ +void cds_check_and_restart_sap_with_non_dfs_acs(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *ap_adapter; + + if (cds_get_concurrency_mode() != (CDF_STA_MASK | CDF_SAP_MASK)) { + cds_info("Concurrency mode is not SAP"); + return; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (ap_adapter != NULL && + test_bit(SOFTAP_BSS_STARTED, + &ap_adapter->event_flags) + && CDS_IS_DFS_CH(ap_adapter->sessionCtx.ap. + operatingChannel)) { + + cds_warn("STA-AP Mode DFS not supported. Restart SAP with Non DFS ACS"); + ap_adapter->sessionCtx.ap.sapConfig.channel = + AUTO_CHANNEL_SELECT; + ap_adapter->sessionCtx.ap.sapConfig. + acs_cfg.acs_mode = true; + + cds_restart_sap(ap_adapter); + } +} +#endif +#ifdef MPC_UT_FRAMEWORK +CDF_STATUS cds_update_connection_info_utfw(hdd_context_t *hdd_ctx, + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, found = 0; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = 1; + break; + } + conn_index++; + } + if (!found) { + /* err msg */ + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + return status; + } + cds_info("--> updating entry at index[%d]", conn_index); + + cds_update_conc_list(conn_index, + cds_get_mode(type, sub_type), + channelid, mac_id, chain_mask, tx_streams, + rx_streams, 0, vdev_id, true); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS cds_incr_connection_count_utfw(hdd_context_t *hdd_ctx, + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + conn_index = cds_get_connection_count(hdd_ctx); + if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) { + /* err msg */ + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + cds_err("exceeded max connection limit %d", + MAX_NUMBER_OF_CONC_CONNECTIONS); + return status; + } + cds_info("--> filling entry at index[%d]", conn_index); + + cds_update_conc_list(conn_index, + cds_get_mode(type, sub_type), + channelid, mac_id, chain_mask, tx_streams, + rx_streams, 0, vdev_id, true); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS cds_decr_connection_count_utfw(hdd_context_t *hdd_ctx, + uint32_t del_all, uint32_t vdev_id) +{ + CDF_STATUS status; + + if (del_all) { + status = cds_init_policy_mgr(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cds_err("Policy manager initialization failed"); + return CDF_STATUS_E_FAILURE; + } + } else { + cdf_mutex_acquire(&hdd_ctx->hdd_conc_list_lock); + cds_decr_connection_count(hdd_ctx, vdev_id); + cdf_mutex_release(&hdd_ctx->hdd_conc_list_lock); + } + + return CDF_STATUS_SUCCESS; +} + +struct cds_conc_connection_info *cds_get_conn_info(hdd_context_t *hdd_ctx, + uint32_t *len) +{ + struct cds_conc_connection_info *conn_ptr = &conc_connection_list[0]; + *len = MAX_NUMBER_OF_CONC_CONNECTIONS; + + return conn_ptr; +} + +enum cds_pcl_type get_pcl_from_first_conn_table( + enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref) +{ + if ((sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + return first_connection_pcl_table[type][sys_pref]; +} + +enum cds_pcl_type get_pcl_from_second_conn_table( + enum cds_one_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable) +{ + if ((idx >= CDS_MAX_ONE_CONNECTION_MODE) || + (sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + if (dbs_capable) + return second_connection_pcl_dbs_table[idx][type][sys_pref]; + else + return second_connection_pcl_nodbs_table[idx][type][sys_pref]; +} + +enum cds_pcl_type get_pcl_from_third_conn_table( + enum cds_two_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable) +{ + if ((idx >= CDS_MAX_TWO_CONNECTION_MODE) || + (sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + if (dbs_capable) + return third_connection_pcl_dbs_table[idx][type][sys_pref]; + else + return third_connection_pcl_nodbs_table[idx][type][sys_pref]; +} +#endif + +/** + * cds_convert_device_mode_to_hdd_type() - provides the + * type translation from HDD to policy manager type + * @device_mode: Generic connection mode type + * + * + * This function provides the type translation + * + * Return: cds_con_mode enum + */ +enum cds_con_mode cds_convert_device_mode_to_hdd_type( + device_mode_t device_mode) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + switch (device_mode) { + case WLAN_HDD_INFRA_STATION: + mode = CDS_STA_MODE; + break; + case WLAN_HDD_P2P_CLIENT: + mode = CDS_P2P_CLIENT_MODE; + break; + case WLAN_HDD_P2P_GO: + mode = CDS_P2P_GO_MODE; + break; + case WLAN_HDD_SOFTAP: + mode = CDS_SAP_MODE; + break; + case WLAN_HDD_IBSS: + mode = CDS_IBSS_MODE; + break; + default: + cds_err("Unsupported mode (%d)", + device_mode); + } + return mode; +} diff --git a/core/cds/src/cds_get_bin.c b/core/cds/src/cds_get_bin.c new file mode 100644 index 0000000000..ac87dd5db8 --- /dev/null +++ b/core/cds/src/cds_get_bin.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include + +tCDF_CON_MODE cds_get_conparam(void) +{ + tCDF_CON_MODE con_mode; + con_mode = hdd_get_conparam(); + return con_mode; +} + +bool cds_concurrent_open_sessions_running(void) +{ + uint8_t i = 0; + uint8_t j = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < CDF_MAX_NO_OF_MODE; i++) { + j += pHddCtx->no_of_open_sessions[i]; + } + } + + return j > 1; +} + +#ifdef WLAN_FEATURE_MBSSID +bool cds_concurrent_beaconing_sessions_running(void) +{ + uint8_t i = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + i = pHddCtx->no_of_open_sessions[CDF_SAP_MODE] + + pHddCtx->no_of_open_sessions[CDF_P2P_GO_MODE] + + pHddCtx->no_of_open_sessions[CDF_IBSS_MODE]; + } + return i > 1; +} +#endif + +/**--------------------------------------------------------------------------- +* +* \brief cds_max_concurrent_connections_reached() +* +* This function checks for presence of concurrency where more than +* one connection exists and it returns true if the max concurrency is +* reached. +* +* Example: +* STA + STA (wlan0 and wlan1 are connected) - returns true +* STA + STA (wlan0 connected and wlan1 disconnected) - returns false +* DUT with P2P-GO + P2P-CLIENT connection) - returns true +* +* \param - None +* +* \return - true or false +* +* --------------------------------------------------------------------------*/ +bool cds_max_concurrent_connections_reached(void) +{ + uint8_t i = 0, j = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < CDF_MAX_NO_OF_MODE; i++) + j += pHddCtx->no_of_active_sessions[i]; + return j > + (pHddCtx->config-> + gMaxConcurrentActiveSessions - 1); + } + + return false; +} + +void cds_clear_concurrent_session_count(void) +{ + uint8_t i = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < CDF_MAX_NO_OF_MODE; i++) + pHddCtx->no_of_active_sessions[i] = 0; + } +} + +/**--------------------------------------------------------------------------- +* +* \brief cds_is_multiple_active_sta_sessions() +* +* This function checks for presence of multiple active sta connections +* and it returns true if the more than 1 active sta connection exists. +* +* \param - None +* +* \return - true or false +* +* --------------------------------------------------------------------------*/ +bool cds_is_multiple_active_sta_sessions(void) +{ + hdd_context_t *pHddCtx; + uint8_t j = 0; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) + j = pHddCtx->no_of_active_sessions[CDF_STA_MODE]; + + return j > 1; +} + +/**--------------------------------------------------------------------------- +* +* \brief cds_is_sta_active_connection_exists() +* +* This function checks for the presence of active sta connection +* and it returns true if exists. +* +* \param - None +* +* \return - true or false +* +* --------------------------------------------------------------------------*/ +bool cds_is_sta_active_connection_exists(void) +{ + hdd_context_t *pHddCtx; + uint8_t j = 0; + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL != pHddCtx) + j = pHddCtx->no_of_active_sessions[CDF_STA_MODE]; + + return j ? true : false; +} diff --git a/core/cds/src/cds_ieee80211_common_i.h b/core/cds/src/cds_ieee80211_common_i.h new file mode 100644 index 0000000000..166c8e6ff7 --- /dev/null +++ b/core/cds/src/cds_ieee80211_common_i.h @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef CDS_COMMON__IEEE80211_I_H_ +#define CDS_COMMON__IEEE80211_I_H_ + +/* These defines should match the table from ah_internal.h */ +typedef enum { + DFS_UNINIT_DOMAIN = 0, /* Uninitialized dfs domain */ + DFS_FCC_DOMAIN = 1, /* FCC3 dfs domain */ + DFS_ETSI_DOMAIN = 2, /* ETSI dfs domain */ + DFS_MKK4_DOMAIN = 3 /* Japan dfs domain */ +} HAL_DFS_DOMAIN; + +/* XXX not really a mode; there are really multiple PHY's */ +enum ieee80211_phymode { + IEEE80211_MODE_AUTO = 0, /* autoselect */ + IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */ + IEEE80211_MODE_11B = 2, /* 2GHz, CCK */ + IEEE80211_MODE_11G = 3, /* 2GHz, OFDM */ + IEEE80211_MODE_FH = 4, /* 2GHz, GFSK */ + IEEE80211_MODE_TURBO_A = 5, /* 5GHz, OFDM, 2x clock dynamic turbo */ + IEEE80211_MODE_TURBO_G = 6, /* 2GHz, OFDM, 2x clock dynamic turbo */ + IEEE80211_MODE_11NA_HT20 = 7, /* 5Ghz, HT20 */ + IEEE80211_MODE_11NG_HT20 = 8, /* 2Ghz, HT20 */ + IEEE80211_MODE_11NA_HT40PLUS = 9, /* 5Ghz, HT40 (ext ch +1) */ + IEEE80211_MODE_11NA_HT40MINUS = 10, /* 5Ghz, HT40 (ext ch -1) */ + IEEE80211_MODE_11NG_HT40PLUS = 11, /* 2Ghz, HT40 (ext ch +1) */ + IEEE80211_MODE_11NG_HT40MINUS = 12, /* 2Ghz, HT40 (ext ch -1) */ + IEEE80211_MODE_11NG_HT40 = 13, /* 2Ghz, Auto HT40 */ + IEEE80211_MODE_11NA_HT40 = 14, /* 2Ghz, Auto HT40 */ + IEEE80211_MODE_11AC_VHT20 = 15, /* 5Ghz, VHT20 */ + IEEE80211_MODE_11AC_VHT40PLUS = 16, /* 5Ghz, VHT40 (Ext ch +1) */ + IEEE80211_MODE_11AC_VHT40MINUS = 17, /* 5Ghz VHT40 (Ext ch -1) */ + IEEE80211_MODE_11AC_VHT40 = 18, /* 5Ghz, VHT40 */ + IEEE80211_MODE_11AC_VHT80 = 19, /* 5Ghz, VHT80 */ + IEEE80211_MODE_2G_AUTO = 20, /* 2G 11 b/g/n autoselect */ + IEEE80211_MODE_5G_AUTO = 21, /* 5G 11 a/n/ac autoselect */ + IEEE80211_MODE_11AGN = 22, /* Support 11N in both 2G and 5G */ +}; +#define IEEE80211_MODE_MAX (IEEE80211_MODE_11AC_VHT80 + 1) + +enum ieee80211_opmode { + IEEE80211_M_STA = 1, /* infrastructure station */ + IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ + IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ + IEEE80211_M_HOSTAP = 6, /* Software Access Point */ + IEEE80211_M_MONITOR = 8, /* Monitor mode */ + IEEE80211_M_WDS = 2, /* WDS link */ + IEEE80211_M_BTAMP = 9, /* VAP for BT AMP */ + + IEEE80211_M_P2P_GO = 33, /* P2P GO */ + IEEE80211_M_P2P_CLIENT = 34, /* P2P Client */ + IEEE80211_M_P2P_DEVICE = 35, /* P2P Device */ + + IEEE80211_OPMODE_MAX = IEEE80211_M_BTAMP, /* Highest numbered opmode in the list */ + + IEEE80211_M_ANY = 0xFF /* Any of the above; used by NDIS 6.x */ +}; + +/* + * 802.11n + */ +#define IEEE80211_CWM_EXTCH_BUSY_THRESHOLD 30 + +enum ieee80211_cwm_mode { + IEEE80211_CWM_MODE20, + IEEE80211_CWM_MODE2040, + IEEE80211_CWM_MODE40, + IEEE80211_CWM_MODEMAX +}; + +enum ieee80211_cwm_extprotspacing { + IEEE80211_CWM_EXTPROTSPACING20, + IEEE80211_CWM_EXTPROTSPACING25, + IEEE80211_CWM_EXTPROTSPACINGMAX +}; + +enum ieee80211_cwm_width { + IEEE80211_CWM_WIDTH20, + IEEE80211_CWM_WIDTH40, + IEEE80211_CWM_WIDTH80, + IEEE80211_CWM_WIDTHINVALID = 0xff /* user invalid value */ +}; + +enum ieee80211_cwm_extprotmode { + IEEE80211_CWM_EXTPROTNONE, /* no protection */ + IEEE80211_CWM_EXTPROTCTSONLY, /* CTS to self */ + IEEE80211_CWM_EXTPROTRTSCTS, /* RTS-CTS */ + IEEE80211_CWM_EXTPROTMAX +}; + +enum ieee80211_fixed_rate_mode { + IEEE80211_FIXED_RATE_NONE = 0, + IEEE80211_FIXED_RATE_MCS = 1, /* HT rates */ + IEEE80211_FIXED_RATE_LEGACY = 2, /* legacy rates */ + IEEE80211_FIXED_RATE_VHT = 3 /* VHT rates */ +}; + +/* Holds the fixed rate information for each VAP */ +struct ieee80211_fixed_rate { + enum ieee80211_fixed_rate_mode mode; + uint32_t series; + uint32_t retries; +}; + +/* + * 802.11g protection mode. + */ +enum ieee80211_protmode { + IEEE80211_PROT_NONE = 0, /* no protection */ + IEEE80211_PROT_CTSONLY = 1, /* CTS to self */ + IEEE80211_PROT_RTSCTS = 2, /* RTS-CTS */ +}; + +/* + * Roaming mode is effectively who controls the operation + * of the 802.11 state machine when operating as a station. + * State transitions are controlled either by the driver + * (typically when management frames are processed by the + * hardware/firmware), the host (auto/normal operation of + * the 802.11 layer), or explicitly through ioctl requests + * when applications like wpa_supplicant want control. + */ +enum ieee80211_roamingmode { + IEEE80211_ROAMING_DEVICE = 0, /* driver/hardware control */ + IEEE80211_ROAMING_AUTO = 1, /* 802.11 layer control */ + IEEE80211_ROAMING_MANUAL = 2, /* application control */ +}; + +/* + * Scanning mode controls station scanning work; this is + * used only when roaming mode permits the host to select + * the bss to join/channel to use. + */ +enum ieee80211_scanmode { + IEEE80211_SCAN_DEVICE = 0, /* driver/hardware control */ + IEEE80211_SCAN_BEST = 1, /* 802.11 layer selects best */ + IEEE80211_SCAN_FIRST = 2, /* take first suitable candidate */ +}; + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_CHAN_MAX 255 +#define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */ +#define IEEE80211_CHAN_ANY (-1) /* token for ``any channel'' */ +#define IEEE80211_CHAN_ANYC \ + ((struct ieee80211_channel *) IEEE80211_CHAN_ANY) + +#define IEEE80211_CHAN_DEFAULT 11 +#define IEEE80211_CHAN_DEFAULT_11A 52 +#define IEEE80211_CHAN_ADHOC_DEFAULT1 10 +#define IEEE80211_CHAN_ADHOC_DEFAULT2 11 + +#define IEEE80211_RADAR_11HCOUNT 5 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11A 36 /* Move to channel 36 for mute test */ +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT20 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40U 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40D 40 /* Move to channel 40 for HT40D mute test */ +#define IEEE80211_RADAR_DETECT_DEFAULT_DELAY 60000 /* STA ignore AP beacons during this period in millisecond */ + +#define IEEE80211_2GCSA_TBTTCOUNT 3 + +/* bits 0-3 are for private use by drivers */ +/* channel attributes */ +#define IEEE80211_CHAN_TURBO 0x00000010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x00000020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x00000040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x00000080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x00000100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x00000200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x00000400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x00000800 /* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_RADAR_DFS 0x00001000 /* Radar found on channel */ +#define IEEE80211_CHAN_STURBO 0x00002000 /* 11a static turbo channel only */ +#define IEEE80211_CHAN_HALF 0x00004000 /* Half rate channel */ +#define IEEE80211_CHAN_QUARTER 0x00008000 /* Quarter rate channel */ +#define IEEE80211_CHAN_HT20 0x00010000 /* HT 20 channel */ +#define IEEE80211_CHAN_HT40PLUS 0x00020000 /* HT 40 with extension channel above */ +#define IEEE80211_CHAN_HT40MINUS 0x00040000 /* HT 40 with extension channel below */ +#define IEEE80211_CHAN_HT40INTOL 0x00080000 /* HT 40 Intolerant */ +#define IEEE80211_CHAN_VHT20 0x00100000 /* VHT 20 channel */ +#define IEEE80211_CHAN_VHT40PLUS 0x00200000 /* VHT 40 with extension channel above */ +#define IEEE80211_CHAN_VHT40MINUS 0x00400000 /* VHT 40 with extension channel below */ +#define IEEE80211_CHAN_VHT80 0x00800000 /* VHT 80 channel */ + +/* flagext */ +#define IEEE80211_CHAN_RADAR_FOUND 0x01 +#define IEEE80211_CHAN_DFS 0x0002 /* DFS required on channel */ +#define IEEE80211_CHAN_DFS_CLEAR 0x0008 /* if channel has been checked for DFS */ +#define IEEE80211_CHAN_11D_EXCLUDED 0x0010 /* excluded in 11D */ +#define IEEE80211_CHAN_CSA_RECEIVED 0x0020 /* Channel Switch Announcement received on this channel */ +#define IEEE80211_CHAN_DISALLOW_ADHOC 0x0040 /* ad-hoc is not allowed */ +#define IEEE80211_CHAN_DISALLOW_HOSTAP 0x0080 /* Station only channel */ + +/* + * Useful combinations of channel characteristics. + */ +#define IEEE80211_CHAN_FHSS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) +#define IEEE80211_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define IEEE80211_CHAN_PUREG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) +#define IEEE80211_CHAN_108A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_108G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_ST \ + (IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_11AC_2G(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c))) +#define IEEE80211_CHAN_11AC_VHT20_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT80) + +#define IEEE80211_IS_CHAN_11AC_VHT20_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20_2G) == IEEE80211_CHAN_11AC_VHT20_2G) +#define IEEE80211_IS_CHAN_11AC_VHT40_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40_2G) != 0) +#define IEEE80211_IS_CHAN_11AC_VHT80_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80_2G) == IEEE80211_CHAN_11AC_VHT80_2G) + +#define IEEE80211_CHAN_11NG_HT20 \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NA_HT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NG_HT40PLUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NG_HT40MINUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_CHAN_11NA_HT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NA_HT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40MINUS) + +#define IEEE80211_CHAN_ALL \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \ + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \ + IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS | \ + IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80 | \ + IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER) +#define IEEE80211_CHAN_ALLTURBO \ + (IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_FHSS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) +#define IEEE80211_IS_CHAN_A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) +#define IEEE80211_IS_CHAN_B(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) +#define IEEE80211_IS_CHAN_PUREG(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) +#define IEEE80211_IS_CHAN_G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) +#define IEEE80211_IS_CHAN_ANYG(_c) \ + (IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c)) +#define IEEE80211_IS_CHAN_ST(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) +#define IEEE80211_IS_CHAN_108A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) +#define IEEE80211_IS_CHAN_108G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) + +#define IEEE80211_IS_CHAN_2GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) +#define IEEE80211_IS_CHAN_5GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) +#define IEEE80211_IS_CHAN_OFDM(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0) +#define IEEE80211_IS_CHAN_CCK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) +#define IEEE80211_IS_CHAN_GFSK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0) +#define IEEE80211_IS_CHAN_TURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0) +#define IEEE80211_IS_CHAN_WEATHER_RADAR(_c) \ + ((((_c)->ic_freq >= 5600) && ((_c)->ic_freq <= 5650)) \ + || (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) && (5580 == (_c)->ic_freq))) +#define IEEE80211_IS_CHAN_STURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_STURBO) != 0) +#define IEEE80211_IS_CHAN_DTURBO(_c) \ + (((_c)->ic_flags & \ + (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) == IEEE80211_CHAN_TURBO) +#define IEEE80211_IS_CHAN_HALF(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) +#define IEEE80211_IS_CHAN_QUARTER(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0) +#define IEEE80211_IS_CHAN_PASSIVE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0) + +#define IEEE80211_IS_CHAN_DFS(_c) \ + (((_c)->ic_flagext & (IEEE80211_CHAN_DFS|IEEE80211_CHAN_DFS_CLEAR)) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DFSFLAG(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DFS) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DISALLOW_ADHOC(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_ADHOC) != 0) +#define IEEE80211_IS_CHAN_11D_EXCLUDED(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_11D_EXCLUDED) != 0) +#define IEEE80211_IS_CHAN_CSA(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_CSA_RECEIVED) != 0) +#define IEEE80211_IS_CHAN_ODD(_c) \ + (((_c)->ic_freq == 5170) || ((_c)->ic_freq == 5190) || \ + ((_c)->ic_freq == 5210) || ((_c)->ic_freq == 5230)) +#define IEEE80211_IS_CHAN_DISALLOW_HOSTAP(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_HOSTAP) != 0) + +#define IEEE80211_IS_CHAN_11NG_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT20) == IEEE80211_CHAN_11NG_HT20) +#define IEEE80211_IS_CHAN_11NA_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT20) == IEEE80211_CHAN_11NA_HT20) +#define IEEE80211_IS_CHAN_11NG_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40PLUS) == IEEE80211_CHAN_11NG_HT40PLUS) +#define IEEE80211_IS_CHAN_11NG_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40MINUS) == IEEE80211_CHAN_11NG_HT40MINUS) +#define IEEE80211_IS_CHAN_11NA_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40PLUS) == IEEE80211_CHAN_11NA_HT40PLUS) +#define IEEE80211_IS_CHAN_11NA_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40MINUS) == IEEE80211_CHAN_11NA_HT40MINUS) + +#define IEEE80211_IS_CHAN_11N(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11N_HT20(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20)) != 0) +#define IEEE80211_IS_CHAN_11N_HT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11NG(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11NA(_c) \ + (IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11N_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) != 0) +#define IEEE80211_IS_CHAN_11N_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) != 0) + +#define IEEE80211_IS_CHAN_HT20_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT20) == IEEE80211_CHAN_HT20) +#define IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_HT40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_HT_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT20_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_11N_CTL_CAPABLE(_c) IEEE80211_IS_CHAN_HT20_CAPABLE(_c) +#define IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_11N_CTL_40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE((_c)) || IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE((_c))) + +#define IEEE80211_IS_CHAN_VHT(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT20 | \ + IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80)) != 0) +#define IEEE80211_IS_CHAN_11AC(_c) \ + ( IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c)) ) +#define IEEE80211_CHAN_11AC_VHT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS ) +#define IEEE80211_CHAN_11AC_VHT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS) +#define IEEE80211_CHAN_11AC_VHT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT80) +#define IEEE80211_IS_CHAN_11AC_VHT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20) == IEEE80211_CHAN_11AC_VHT20) + +#define IEEE80211_IS_CHAN_11AC_VHT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS)) !=0) +#define IEEE80211_IS_CHAN_11AC_VHT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40PLUS) == IEEE80211_CHAN_11AC_VHT40PLUS) +#define IEEE80211_IS_CHAN_11AC_VHT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40MINUS) == IEEE80211_CHAN_11AC_VHT40MINUS) +#define IEEE80211_IS_CHAN_11AC_VHT80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80) == IEEE80211_CHAN_11AC_VHT80) + +#define IEEE80211_IS_CHAN_RADAR(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_RADAR_DFS) == IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_RADAR(_c) \ + ((_c)->ic_flags |= IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_CLR_RADAR(_c) \ + ((_c)->ic_flags &= ~IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_DISALLOW_ADHOC(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_ADHOC) +#define IEEE80211_CHAN_SET_DISALLOW_HOSTAP(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_HOSTAP) +#define IEEE80211_CHAN_SET_DFS(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS) +#define IEEE80211_CHAN_SET_DFS_CLEAR(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS_CLEAR) +#define IEEE80211_CHAN_EXCLUDE_11D(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_11D_EXCLUDED) + +/* channel encoding for FH phy */ +#define IEEE80211_FH_CHANMOD 80 +#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat)) +#define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1) +#define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD) + +/* + * 802.11 rate set. + */ +#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ +#define IEEE80211_RATE_MAXSIZE 36 /* max rates we'll handle */ +#define IEEE80211_HT_RATE_SIZE 128 +#define IEEE80211_RATE_SINGLE_STREAM_MCS_MAX 7 /* MCS7 */ + +#define IEEE80211_RATE_MCS 0x8000 +#define IEEE80211_RATE_MCS_VAL 0x7FFF + +#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) + +/* + * RSSI range + */ +#define IEEE80211_RSSI_MAX -10 /* in db */ +#define IEEE80211_RSSI_MIN -200 + +/* + * 11n A-MPDU & A-MSDU limits + */ +#define IEEE80211_AMPDU_LIMIT_MIN (1 * 1024) +#define IEEE80211_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define IEEE80211_AMPDU_LIMIT_DEFAULT IEEE80211_AMPDU_LIMIT_MAX +#define IEEE80211_AMPDU_SUBFRAME_MIN 2 +#define IEEE80211_AMPDU_SUBFRAME_MAX 64 +#define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_AMSDU_LIMIT_MAX 4096 +#define IEEE80211_RIFS_AGGR_DIV 10 +#define IEEE80211_MAX_AMPDU_MIN 0 +#define IEEE80211_MAX_AMPDU_MAX 3 + +/* + * 11ac A-MPDU limits + */ +#define IEEE80211_VHT_MAX_AMPDU_MIN 0 +#define IEEE80211_VHT_MAX_AMPDU_MAX 7 + +struct ieee80211_rateset { + uint8_t rs_nrates; + uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; +}; + +struct ieee80211_beacon_info { + uint8_t essid[IEEE80211_NWID_LEN + 1]; + uint8_t esslen; + uint8_t rssi_ctl_0; + uint8_t rssi_ctl_1; + uint8_t rssi_ctl_2; + int numchains; +}; + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +struct ieee80211_ibss_peer_list { + uint8_t bssid[IEEE80211_ADDR_LEN]; +}; + +struct ieee80211_roam { + int8_t rssi11a; /* rssi thresh for 11a bss */ + int8_t rssi11b; /* for 11g sta in 11b bss */ + int8_t rssi11bOnly; /* for 11b sta */ + uint8_t pad1; + uint8_t rate11a; /* rate thresh for 11a bss */ + uint8_t rate11b; /* for 11g sta in 11b bss */ + uint8_t rate11bOnly; /* for 11b sta */ + uint8_t pad2; +}; + +#define IEEE80211_TID_SIZE 17 /* total number of TIDs */ +#define IEEE80211_NON_QOS_SEQ 16 /* index for non-QoS (including management) sequence number space */ +#define IEEE80211_SEQ_MASK 0xfff /* sequence generator mask */ +#define MIN_SW_SEQ 0x100 /* minimum sequence for SW generate packect */ + +/* crypto related defines*/ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ + +enum ieee80211_clist_cmd { + CLIST_UPDATE, + CLIST_DFS_UPDATE, + CLIST_NEW_COUNTRY, + CLIST_NOL_UPDATE +}; + +enum ieee80211_nawds_param { + IEEE80211_NAWDS_PARAM_NUM = 0, + IEEE80211_NAWDS_PARAM_MODE, + IEEE80211_NAWDS_PARAM_DEFCAPS, + IEEE80211_NAWDS_PARAM_OVERRIDE, +}; + +struct ieee80211_mib_cycle_cnts { + uint32_t tx_frame_count; + uint32_t rx_frame_count; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t is_rx_active; + uint8_t is_tx_active; +}; + +struct ieee80211_chanutil_info { + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t value; + uint32_t beacon_count; + uint8_t beacon_intervals; +}; + +#endif /* CDS_COMMON__IEEE80211_I_H_ */ diff --git a/core/cds/src/cds_mq.c b/core/cds/src/cds_mq.c new file mode 100644 index 0000000000..6354e04dc9 --- /dev/null +++ b/core/cds/src/cds_mq.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_mq.c + * + * Connectivity driver services (CDS) message queue APIs + * + * Message Queue Definitions and API + */ + +/* Include Files */ +#include +#include "cds_sched.h" +#include +#include "sir_types.h" + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, void *pMb); + +/** + * cds_mq_init() - initialize cds message queue + * @pMq: Pointer to the message queue + * + * This function initializes the Message queue. + * + * Return: cdf status + */ +inline CDF_STATUS cds_mq_init(p_cds_mq_type pMq) +{ + + if (pMq == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return CDF_STATUS_E_FAILURE; + } + + /* Now initialize the lock */ + spin_lock_init(&pMq->mqLock); + + /* Now initialize the List data structure */ + INIT_LIST_HEAD(&pMq->mqList); + + return CDF_STATUS_SUCCESS; +} /* cds_mq_init() */ + +/** + * cds_mq_deinit() - de-initialize cds message queue + * @pMq: Pointer to the message queue + * + * This function de-initializes cds message queue + * + * Return: none + */ +inline void cds_mq_deinit(p_cds_mq_type pMq) +{ + if (pMq == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return; + } + + /* we don't have to do anything with the embedded list or spinlock */ +} /* cds_mq_deinit() */ + +/** + * cds_mq_put() - add a message to the message queue + * @pMq: Pointer to the message queue + * @pMsgWrapper: Msg wrapper containing the message + * + * Return: none + */ +inline void cds_mq_put(p_cds_mq_type pMq, p_cds_msg_wrapper pMsgWrapper) +{ + unsigned long flags; + + if ((pMq == NULL) || (pMsgWrapper == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + + list_add_tail(&pMsgWrapper->msgNode, &pMq->mqList); + + spin_unlock_irqrestore(&pMq->mqLock, flags); + +} /* cds_mq_put() */ + +/** + * cds_mq_get() - get a message with its wrapper from a message queue + * @pMq: Pointer to the message queue + * + * Return: pointer to the message wrapper + */ +inline p_cds_msg_wrapper cds_mq_get(p_cds_mq_type pMq) +{ + p_cds_msg_wrapper pMsgWrapper = NULL; + + struct list_head *listptr; + unsigned long flags; + + if (pMq == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return NULL; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + + if (list_empty(&pMq->mqList)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_WARN, + "%s: CDS Message Queue is empty", __func__); + } else { + listptr = pMq->mqList.next; + pMsgWrapper = + (p_cds_msg_wrapper) list_entry(listptr, cds_msg_wrapper, + msgNode); + list_del(pMq->mqList.next); + } + + spin_unlock_irqrestore(&pMq->mqLock, flags); + + return pMsgWrapper; + +} /* cds_mq_get() */ + +/** + * cds_is_mq_empty() - check if the message queue is empty + * @pMq: Pointer to the message queue + * + * Return: true if message queue is emtpy + * false otherwise + */ +inline bool cds_is_mq_empty(p_cds_mq_type pMq) +{ + bool state = false; + unsigned long flags; + + if (pMq == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return CDF_STATUS_E_FAILURE; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + state = list_empty(&pMq->mqList) ? true : false; + spin_unlock_irqrestore(&pMq->mqLock, flags); + + return state; +} /* cds_mq_get() */ + +/** + * cds_send_mb_message_to_mac() - post a message to a message queue + * @pBuf: Pointer to buffer allocated by caller + * + * Return: cdf status + */ +CDF_STATUS cds_send_mb_message_to_mac(void *pBuf) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + tSirRetStatus sirStatus; + v_CONTEXT_t cds_context; + void *hHal; + + cds_context = cds_get_global_context(); + if (NULL == cds_context) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "%s: invalid cds_context", __func__); + } else { + hHal = cds_get_context(CDF_MODULE_ID_SME); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "%s: invalid hHal", __func__); + } else { + sirStatus = u_mac_post_ctrl_msg(hHal, pBuf); + if (eSIR_SUCCESS == sirStatus) + cdf_ret_status = CDF_STATUS_SUCCESS; + } + } + + cdf_mem_free(pBuf); + + return cdf_ret_status; +} diff --git a/core/cds/src/cds_packet.c b/core/cds/src/cds_packet.c new file mode 100644 index 0000000000..70e5fc1073 --- /dev/null +++ b/core/cds/src/cds_packet.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file cds_packet.c + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "cdf_nbuf.h" +#include "cdf_memory.h" + +#define TX_PKT_MIN_HEADROOM (64) + +/* Protocol specific packet tracking feature */ +#define CDS_PKT_TRAC_ETH_TYPE_OFFSET (12) +#define CDS_PKT_TRAC_IP_OFFSET (14) +#define CDS_PKT_TRAC_IP_HEADER_SIZE (20) +#define CDS_PKT_TRAC_DHCP_SRV_PORT (67) +#define CDS_PKT_TRAC_DHCP_CLI_PORT (68) +#define CDS_PKT_TRAC_EAPOL_ETH_TYPE (0x888E) +#ifdef QCA_PKT_PROTO_TRACE +#define CDS_PKT_TRAC_MAX_STRING_LEN (12) +#define CDS_PKT_TRAC_MAX_TRACE_BUF (50) +#define CDS_PKT_TRAC_MAX_STRING_BUF (64) + +/* protocol Storage Structure */ +typedef struct { + uint32_t order; + v_TIME_t event_time; + char event_string[CDS_PKT_TRAC_MAX_STRING_LEN]; +} cds_pkt_proto_trace_t; + +cds_pkt_proto_trace_t *trace_buffer = NULL; +unsigned int trace_buffer_order = 0; +cdf_spinlock_t trace_buffer_lock; +#endif /* QCA_PKT_PROTO_TRACE */ + +/** + * cds_pkt_return_packet Free the cds Packet + * @ cds Packet + */ +CDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet) +{ + /* Validate the input parameter pointer */ + if (unlikely(packet == NULL)) { + return CDF_STATUS_E_INVAL; + } + + /* Free up the Adf nbuf */ + cdf_nbuf_free(packet->pkt_buf); + + packet->pkt_buf = NULL; + + /* Free up the Rx packet */ + cdf_mem_free(packet); + + return CDF_STATUS_SUCCESS; +} + +/**-------------------------------------------------------------------------- + + \brief cds_pkt_get_packet_length() - Get packet length for a cds Packet + + This API returns the total length of the data in a cds Packet. + + \param pPacket - the cds Packet to get the packet length from. + + \param pPacketSize - location to return the total size of the data contained + in the cds Packet. + \return + + \sa + + ---------------------------------------------------------------------------*/ +CDF_STATUS +cds_pkt_get_packet_length(cds_pkt_t *pPacket, uint16_t *pPacketSize) +{ + /* Validate the parameter pointers */ + if (unlikely((pPacket == NULL) || (pPacketSize == NULL)) || + (pPacket->pkt_buf == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "VPKT [%d]: NULL pointer", __LINE__); + return CDF_STATUS_E_INVAL; + } + /* return the requested information */ + *pPacketSize = cdf_nbuf_len(pPacket->pkt_buf); + return CDF_STATUS_SUCCESS; +} + +/*--------------------------------------------------------------------------- +* @brief cds_pkt_get_proto_type() - + Find protoco type from packet contents + +* skb Packet Pointer +* tracking_map packet type want to track +* dot11_type, type of dot11 frame + ---------------------------------------------------------------------------*/ +uint8_t cds_pkt_get_proto_type(struct sk_buff *skb, uint8_t tracking_map, + uint8_t dot11_type) +{ + uint8_t pkt_proto_type = 0; + uint16_t ether_type; + uint16_t SPort; + uint16_t DPort; + + if (dot11_type) { + if (dot11_type == + (CDS_PKT_TRAC_TYPE_MGMT_ACTION & tracking_map)) + pkt_proto_type |= CDS_PKT_TRAC_TYPE_MGMT_ACTION; + + /* Protocol type map */ + return pkt_proto_type; + } + + /* EAPOL Tracking enabled */ + if (CDS_PKT_TRAC_TYPE_EAPOL & tracking_map) { + ether_type = (uint16_t) (*(uint16_t *) + (skb->data + + CDS_PKT_TRAC_ETH_TYPE_OFFSET)); + if (CDS_PKT_TRAC_EAPOL_ETH_TYPE == CDF_SWAP_U16(ether_type)) { + pkt_proto_type |= CDS_PKT_TRAC_TYPE_EAPOL; + } + } + + /* DHCP Tracking enabled */ + if (CDS_PKT_TRAC_TYPE_DHCP & tracking_map) { + SPort = (uint16_t) (*(uint16_t *) + (skb->data + CDS_PKT_TRAC_IP_OFFSET + + CDS_PKT_TRAC_IP_HEADER_SIZE)); + DPort = (uint16_t) (*(uint16_t *) + (skb->data + CDS_PKT_TRAC_IP_OFFSET + + CDS_PKT_TRAC_IP_HEADER_SIZE + + sizeof(uint16_t))); + if (((CDS_PKT_TRAC_DHCP_SRV_PORT == CDF_SWAP_U16(SPort)) + && (CDS_PKT_TRAC_DHCP_CLI_PORT == CDF_SWAP_U16(DPort))) + || ((CDS_PKT_TRAC_DHCP_CLI_PORT == CDF_SWAP_U16(SPort)) + && (CDS_PKT_TRAC_DHCP_SRV_PORT == CDF_SWAP_U16(DPort)))) { + pkt_proto_type |= CDS_PKT_TRAC_TYPE_DHCP; + } + } + + /* Protocol type map */ + return pkt_proto_type; +} + +#ifdef QCA_PKT_PROTO_TRACE +/*--------------------------------------------------------------------------- +* @brief cds_pkt_trace_buf_update() - + Update storage buffer with interest event string + +* event_string Event String may packet type or outstanding event + ---------------------------------------------------------------------------*/ +void cds_pkt_trace_buf_update(char *event_string) +{ + uint32_t slot; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s %d, %s", __func__, __LINE__, event_string); + cdf_spinlock_acquire(&trace_buffer_lock); + slot = trace_buffer_order % CDS_PKT_TRAC_MAX_TRACE_BUF; + trace_buffer[slot].order = trace_buffer_order; + trace_buffer[slot].event_time = cdf_mc_timer_get_system_time(); + cdf_mem_zero(trace_buffer[slot].event_string, + sizeof(trace_buffer[slot].event_string)); + cdf_mem_copy(trace_buffer[slot].event_string, + event_string, + (CDS_PKT_TRAC_MAX_STRING_LEN < strlen(event_string)) ? + CDS_PKT_TRAC_MAX_STRING_LEN : strlen(event_string)); + trace_buffer_order++; + cdf_spinlock_release(&trace_buffer_lock); + + return; +} + +/*--------------------------------------------------------------------------- +* @brief cds_pkt_trace_buf_dump() - + Dump stored information into kernel log + ---------------------------------------------------------------------------*/ +void cds_pkt_trace_buf_dump(void) +{ + uint32_t slot, idx; + + cdf_spinlock_acquire(&trace_buffer_lock); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "PACKET TRACE DUMP START Current Timestamp %u", + (unsigned int)cdf_mc_timer_get_system_time()); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "ORDER : TIME : EVT"); + if (CDS_PKT_TRAC_MAX_TRACE_BUF > trace_buffer_order) { + for (slot = 0; slot < trace_buffer_order; slot++) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%5d :%12u : %s", + trace_buffer[slot].order, + (unsigned int)trace_buffer[slot].event_time, + trace_buffer[slot].event_string); + } + } else { + for (idx = 0; idx < CDS_PKT_TRAC_MAX_TRACE_BUF; idx++) { + slot = + (trace_buffer_order + + idx) % CDS_PKT_TRAC_MAX_TRACE_BUF; + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%5d :%12u : %s", trace_buffer[slot].order, + (unsigned int)trace_buffer[slot].event_time, + trace_buffer[slot].event_string); + } + } + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "PACKET TRACE DUMP END"); + cdf_spinlock_release(&trace_buffer_lock); + + return; +} + +/*--------------------------------------------------------------------------- +* @brief cds_pkt_proto_trace_init() - + Initialize protocol trace functionality, allocate required resource + ---------------------------------------------------------------------------*/ +void cds_pkt_proto_trace_init(void) +{ + /* Init spin lock to protect global memory */ + cdf_spinlock_init(&trace_buffer_lock); + trace_buffer_order = 0; + trace_buffer = + cdf_mem_malloc(CDS_PKT_TRAC_MAX_TRACE_BUF * + sizeof(cds_pkt_proto_trace_t)); + cdf_mem_zero((void *)trace_buffer, + CDS_PKT_TRAC_MAX_TRACE_BUF * + sizeof(cds_pkt_proto_trace_t)); + + /* Register callback function to NBUF + * Lower layer event also will be reported to here */ + cdf_nbuf_reg_trace_cb(cds_pkt_trace_buf_update); + return; +} + +/*--------------------------------------------------------------------------- +* @brief cds_pkt_proto_trace_close() - + Free required resource + ---------------------------------------------------------------------------*/ +void cds_pkt_proto_trace_close(void) +{ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s %d", __func__, __LINE__); + cdf_mem_free(trace_buffer); + cdf_spinlock_destroy(&trace_buffer_lock); + + return; +} +#endif /* QCA_PKT_PROTO_TRACE */ + +#ifdef MEMORY_DEBUG +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc_debug() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +CDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_name, uint32_t line_num) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + cdf_nbuf_t nbuf; + + nbuf = + cdf_nbuf_alloc_debug(NULL, roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false, + file_name, line_num); + + if (nbuf != NULL) { + cdf_nbuf_put_tail(nbuf, size); + cdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = cdf_nbuf_data(nbuf); + cdf_ret_status = CDF_STATUS_SUCCESS; + } + + return cdf_ret_status; +} +#else +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +CDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + cdf_nbuf_t nbuf; + + nbuf = cdf_nbuf_alloc(NULL, roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false); + + if (nbuf != NULL) { + cdf_nbuf_put_tail(nbuf, size); + cdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = cdf_nbuf_data(nbuf); + cdf_ret_status = CDF_STATUS_SUCCESS; + } + + return cdf_ret_status; +} + +#endif +/*--------------------------------------------------------------------------- +* @brief cds_packet_free() - + Free input network buffer + ---------------------------------------------------------------------------*/ +void cds_packet_free(void *pPacket) +{ + cdf_nbuf_free((cdf_nbuf_t) pPacket); +} diff --git a/core/cds/src/cds_reg_service.c b/core/cds/src/cds_reg_service.c new file mode 100644 index 0000000000..f8d2751132 --- /dev/null +++ b/core/cds/src/cds_reg_service.c @@ -0,0 +1,1439 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: cds_reg_service.c + OVERVIEW: This source file contains definitions for CDS regulatory APIs + DEPENDENCIES: None + ============================================================================*/ + +#include +#include "cdf_types.h" +#include "cds_reg_service.h" +#include "cdf_trace.h" +#include "sme_api.h" +#include "wlan_hdd_main.h" +#include "cds_regdomain.h" +#include "cds_regdomain_common.h" + +#define WORLD_SKU_MASK 0x00F0 +#define WORLD_SKU_PREFIX 0x0060 +#define MAX_COUNTRY_COUNT 300 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#endif + +static v_REGDOMAIN_t temp_reg_domain = REGDOMAIN_COUNT; + +/* true if init happens thru init time driver hint */ +static bool init_by_driver = false; +/* true if init happens thru init time callback from regulatory core. + this should be set to true during driver reload */ +static bool init_by_reg_core = false; + +#define REG_WAIT_TIME 50 + +#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN) + +#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) + +#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 80, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 80, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +static const struct ieee80211_regdomain cds_world_regdom_60_61_62 = { + .n_reg_rules = 6, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_2484, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain cds_world_regdom_63_65 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain cds_world_regdom_64 = { + .n_reg_rules = 3, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain cds_world_regdom_66_69 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain cds_world_regdom_67_68_6A_6C = { + .n_reg_rules = 5, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +typedef struct { + uint8_t regDomain; + country_code_t countryCode; +} CountryInfo_t; + +typedef struct { + uint16_t countryCount; + CountryInfo_t countryInfo[MAX_COUNTRY_COUNT]; +} CountryInfoTable_t; + +static CountryInfoTable_t country_info_table = { + /* the first entry in the table is always the world domain */ + 138, + { + {REGDOMAIN_WORLD, {'0', '0'}}, /* WORLD DOMAIN */ + {REGDOMAIN_FCC, {'A', 'D'}}, /* ANDORRA */ + {REGDOMAIN_ETSI, {'A', 'E'}}, /* UAE */ + {REGDOMAIN_ETSI, {'A', 'L'}}, /* ALBANIA */ + {REGDOMAIN_ETSI, {'A', 'M'}}, /* ARMENIA */ + {REGDOMAIN_ETSI, {'A', 'N'}}, /* NETHERLANDS ANTILLES */ + {REGDOMAIN_FCC, {'A', 'R'}}, /* ARGENTINA */ + {REGDOMAIN_FCC, {'A', 'S'}}, /* AMERICAN SOMOA */ + {REGDOMAIN_ETSI, {'A', 'T'}}, /* AUSTRIA */ + {REGDOMAIN_FCC, {'A', 'U'}}, /* AUSTRALIA */ + {REGDOMAIN_ETSI, {'A', 'W'}}, /* ARUBA */ + {REGDOMAIN_ETSI, {'A', 'Z'}}, /* AZERBAIJAN */ + {REGDOMAIN_ETSI, {'B', 'A'}}, /* BOSNIA AND HERZEGOVINA */ + {REGDOMAIN_FCC, {'B', 'B'}}, /* BARBADOS */ + {REGDOMAIN_ETSI, {'B', 'D'}}, /* BANGLADESH */ + {REGDOMAIN_ETSI, {'B', 'E'}}, /* BELGIUM */ + {REGDOMAIN_ETSI, {'B', 'G'}}, /* BULGARIA */ + {REGDOMAIN_ETSI, {'B', 'H'}}, /* BAHRAIN */ + {REGDOMAIN_ETSI, {'B', 'L'}}, /* */ + {REGDOMAIN_FCC, {'B', 'M'}}, /* BERMUDA */ + {REGDOMAIN_ETSI, {'B', 'N'}}, /* BRUNEI DARUSSALAM */ + {REGDOMAIN_ETSI, {'B', 'O'}}, /* BOLIVIA */ + {REGDOMAIN_ETSI, {'B', 'R'}}, /* BRAZIL */ + {REGDOMAIN_FCC, {'B', 'S'}}, /* BAHAMAS */ + {REGDOMAIN_ETSI, {'B', 'Y'}}, /* BELARUS */ + {REGDOMAIN_ETSI, {'B', 'Z'}}, /* BELIZE */ + {REGDOMAIN_FCC, {'C', 'A'}}, /* CANADA */ + {REGDOMAIN_ETSI, {'C', 'H'}}, /* SWITZERLAND */ + {REGDOMAIN_ETSI, {'C', 'L'}}, /* CHILE */ + {REGDOMAIN_FCC, {'C', 'N'}}, /* CHINA */ + {REGDOMAIN_FCC, {'C', 'O'}}, /* COLOMBIA */ + {REGDOMAIN_ETSI, {'C', 'R'}}, /* COSTA RICA */ + {REGDOMAIN_ETSI, {'C', 'S'}}, + {REGDOMAIN_ETSI, {'C', 'Y'}}, /* CYPRUS */ + {REGDOMAIN_ETSI, {'C', 'Z'}}, /* CZECH REPUBLIC */ + {REGDOMAIN_ETSI, {'D', 'E'}}, /* GERMANY */ + {REGDOMAIN_ETSI, {'D', 'K'}}, /* DENMARK */ + {REGDOMAIN_FCC, {'D', 'O'}}, /* DOMINICAN REPUBLIC */ + {REGDOMAIN_ETSI, {'D', 'Z'}}, /* ALGERIA */ + {REGDOMAIN_ETSI, {'E', 'C'}}, /* ECUADOR */ + {REGDOMAIN_ETSI, {'E', 'E'}}, /* ESTONIA */ + {REGDOMAIN_ETSI, {'E', 'G'}}, /* EGYPT */ + {REGDOMAIN_ETSI, {'E', 'S'}}, /* SPAIN */ + {REGDOMAIN_ETSI, {'F', 'I'}}, /* FINLAND */ + {REGDOMAIN_ETSI, {'F', 'R'}}, /* FRANCE */ + {REGDOMAIN_ETSI, {'G', 'B'}}, /* UNITED KINGDOM */ + {REGDOMAIN_FCC, {'G', 'D'}}, /* GRENADA */ + {REGDOMAIN_ETSI, {'G', 'E'}}, /* GEORGIA */ + {REGDOMAIN_ETSI, {'G', 'F'}}, /* FRENCH GUIANA */ + {REGDOMAIN_ETSI, {'G', 'L'}}, /* GREENLAND */ + {REGDOMAIN_ETSI, {'G', 'P'}}, /* GUADELOUPE */ + {REGDOMAIN_ETSI, {'G', 'R'}}, /* GREECE */ + {REGDOMAIN_FCC, {'G', 'T'}}, /* GUATEMALA */ + {REGDOMAIN_FCC, {'G', 'U'}}, /* GUAM */ + {REGDOMAIN_ETSI, {'H', 'U'}}, /* HUNGARY */ + {REGDOMAIN_FCC, {'I', 'D'}}, /* INDONESIA */ + {REGDOMAIN_ETSI, {'I', 'E'}}, /* IRELAND */ + {REGDOMAIN_ETSI, {'I', 'L'}}, /* ISRAEL */ + {REGDOMAIN_ETSI, {'I', 'N'}}, /* INDIA */ + {REGDOMAIN_ETSI, {'I', 'R'}}, /* IRAN, ISLAMIC REPUBLIC OF */ + {REGDOMAIN_ETSI, {'I', 'S'}}, /* ICELNAD */ + {REGDOMAIN_ETSI, {'I', 'T'}}, /* ITALY */ + {REGDOMAIN_FCC, {'J', 'M'}}, /* JAMAICA */ + {REGDOMAIN_JAPAN, {'J', 'P'}}, /* JAPAN */ + {REGDOMAIN_ETSI, {'J', 'O'}}, /* JORDAN */ + {REGDOMAIN_ETSI, {'K', 'E'}}, /* KENYA */ + {REGDOMAIN_ETSI, {'K', 'H'}}, /* CAMBODIA */ + {REGDOMAIN_ETSI, {'K', 'P'}}, /* KOREA, DEMOCRATIC PEOPLE's REPUBLIC OF */ + {REGDOMAIN_ETSI, {'K', 'R'}}, /* KOREA, REPUBLIC OF */ + {REGDOMAIN_ETSI, {'K', 'W'}}, /* KUWAIT */ + {REGDOMAIN_ETSI, {'K', 'Z'}}, /* KAZAKHSTAN */ + {REGDOMAIN_ETSI, {'L', 'B'}}, /* LEBANON */ + {REGDOMAIN_ETSI, {'L', 'I'}}, /* LIECHTENSTEIN */ + {REGDOMAIN_ETSI, {'L', 'K'}}, /* SRI-LANKA */ + {REGDOMAIN_ETSI, {'L', 'T'}}, /* LITHUANIA */ + {REGDOMAIN_ETSI, {'L', 'U'}}, /* LUXEMBOURG */ + {REGDOMAIN_ETSI, {'L', 'V'}}, /* LATVIA */ + {REGDOMAIN_ETSI, {'M', 'A'}}, /* MOROCCO */ + {REGDOMAIN_ETSI, {'M', 'C'}}, /* MONACO */ + {REGDOMAIN_ETSI, {'M', 'K'}}, /* MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF */ + {REGDOMAIN_FCC, {'M', 'N'}}, /* MONGOLIA */ + {REGDOMAIN_FCC, {'M', 'O'}}, /* MACAO */ + {REGDOMAIN_FCC, {'M', 'P'}}, /* NORTHERN MARIANA ISLANDS */ + {REGDOMAIN_ETSI, {'M', 'Q'}}, /* MARTINIQUE */ + {REGDOMAIN_FCC, {'M', 'T'}}, /* MALTA */ + {REGDOMAIN_ETSI, {'M', 'U'}}, /* MAURITIUS */ + {REGDOMAIN_ETSI, {'M', 'W'}}, /* MALAWI */ + {REGDOMAIN_FCC, {'M', 'X'}}, /* MEXICO */ + {REGDOMAIN_ETSI, {'M', 'Y'}}, /* MALAYSIA */ + {REGDOMAIN_ETSI, {'N', 'G'}}, /* NIGERIA */ + {REGDOMAIN_FCC, {'N', 'I'}}, /* NICARAGUA */ + {REGDOMAIN_ETSI, {'N', 'L'}}, /* NETHERLANDS */ + {REGDOMAIN_ETSI, {'N', 'O'}}, /* NORWAY */ + {REGDOMAIN_ETSI, {'N', 'P'}}, /* NEPAL */ + {REGDOMAIN_FCC, {'N', 'Z'}}, /* NEW-ZEALAND */ + {REGDOMAIN_FCC, {'O', 'M'}}, /* OMAN */ + {REGDOMAIN_FCC, {'P', 'A'}}, /* PANAMA */ + {REGDOMAIN_ETSI, {'P', 'E'}}, /* PERU */ + {REGDOMAIN_ETSI, {'P', 'F'}}, /* FRENCH POLYNESIA */ + {REGDOMAIN_ETSI, {'P', 'G'}}, /* PAPUA NEW GUINEA */ + {REGDOMAIN_FCC, {'P', 'H'}}, /* PHILIPPINES */ + {REGDOMAIN_ETSI, {'P', 'K'}}, /* PAKISTAN */ + {REGDOMAIN_ETSI, {'P', 'L'}}, /* POLAND */ + {REGDOMAIN_FCC, {'P', 'R'}}, /* PUERTO RICO */ + {REGDOMAIN_FCC, {'P', 'S'}}, /* PALESTINIAN TERRITORY, OCCUPIED */ + {REGDOMAIN_ETSI, {'P', 'T'}}, /* PORTUGAL */ + {REGDOMAIN_FCC, {'P', 'Y'}}, /* PARAGUAY */ + {REGDOMAIN_ETSI, {'Q', 'A'}}, /* QATAR */ + {REGDOMAIN_ETSI, {'R', 'E'}}, /* REUNION */ + {REGDOMAIN_ETSI, {'R', 'O'}}, /* ROMAINIA */ + {REGDOMAIN_ETSI, {'R', 'S'}}, /* SERBIA */ + {REGDOMAIN_ETSI, {'R', 'U'}}, /* RUSSIA */ + {REGDOMAIN_FCC, {'R', 'W'}}, /* RWANDA */ + {REGDOMAIN_ETSI, {'S', 'A'}}, /* SAUDI ARABIA */ + {REGDOMAIN_ETSI, {'S', 'E'}}, /* SWEDEN */ + {REGDOMAIN_ETSI, {'S', 'G'}}, /* SINGAPORE */ + {REGDOMAIN_ETSI, {'S', 'I'}}, /* SLOVENNIA */ + {REGDOMAIN_ETSI, {'S', 'K'}}, /* SLOVAKIA */ + {REGDOMAIN_ETSI, {'S', 'V'}}, /* EL SALVADOR */ + {REGDOMAIN_ETSI, {'S', 'Y'}}, /* SYRIAN ARAB REPUBLIC */ + {REGDOMAIN_ETSI, {'T', 'H'}}, /* THAILAND */ + {REGDOMAIN_ETSI, {'T', 'N'}}, /* TUNISIA */ + {REGDOMAIN_ETSI, {'T', 'R'}}, /* TURKEY */ + {REGDOMAIN_ETSI, {'T', 'T'}}, /* TRINIDAD AND TOBAGO */ + {REGDOMAIN_FCC, {'T', 'W'}}, /* TAIWAN, PRIVINCE OF CHINA */ + {REGDOMAIN_FCC, {'T', 'Z'}}, /* TANZANIA, UNITED REPUBLIC OF */ + {REGDOMAIN_ETSI, {'U', 'A'}}, /* UKRAINE */ + {REGDOMAIN_ETSI, {'U', 'G'}}, /* UGANDA */ + {REGDOMAIN_FCC, {'U', 'S'}}, /* USA */ + {REGDOMAIN_ETSI, {'U', 'Y'}}, /* URUGUAY */ + {REGDOMAIN_FCC, {'U', 'Z'}}, /* UZBEKISTAN */ + {REGDOMAIN_ETSI, {'V', 'E'}}, /* VENEZUELA */ + {REGDOMAIN_FCC, {'V', 'I'}}, /* VIRGIN ISLANDS, US */ + {REGDOMAIN_ETSI, {'V', 'N'}}, /* VIETNAM */ + {REGDOMAIN_ETSI, {'Y', 'E'}}, /* YEMEN */ + {REGDOMAIN_ETSI, {'Y', 'T'}}, /* MAYOTTE */ + {REGDOMAIN_ETSI, {'Z', 'A'}}, /* SOUTH AFRICA */ + {REGDOMAIN_ETSI, {'Z', 'W'}}, /* ZIMBABWE */ + } +}; + +const tRfChannelProps rf_channels[NUM_RF_CHANNELS] = { + {2412, 1}, + {2417, 2}, + {2422, 3}, + {2427, 4}, + {2432, 5}, + {2437, 6}, + {2442, 7}, + {2447, 8}, + {2452, 9}, + {2457, 10}, + {2462, 11}, + {2467, 12}, + {2472, 13}, + {2484, 14}, + {4920, 240}, + {4940, 244}, + {4960, 248}, + {4980, 252}, + {5040, 208}, + {5060, 212}, + {5080, 216}, + {5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52}, + {5280, 56}, + {5300, 60}, + {5320, 64}, + {5500, 100}, + {5520, 104}, + {5540, 108}, + {5560, 112}, + {5580, 116}, + {5600, 120}, + {5620, 124}, + {5640, 128}, + {5660, 132}, + {5680, 136}, + {5700, 140}, + {5720, 144}, + {5745, 149}, + {5765, 153}, + {5785, 157}, + {5805, 161}, + {5825, 165}, + {5852, 170}, + {5855, 171}, + {5860, 172}, + {5865, 173}, + {5870, 174}, + {5875, 175}, + {5880, 176}, + {5885, 177}, + {5890, 178}, + {5895, 179}, + {5900, 180}, + {5905, 181}, + {5910, 182}, + {5915, 183}, + {5920, 184}, + {2422, 3}, + {2427, 4}, + {2432, 5}, + {2437, 6}, + {2442, 7}, + {2447, 8}, + {2452, 9}, + {2457, 10}, + {2462, 11}, + {4930, 242}, + {4950, 246}, + {4970, 250}, + {5050, 210}, + {5070, 214}, + {5190, 38}, + {5210, 42}, + {5230, 46}, + {5250, 50}, + {5270, 54}, + {5290, 58}, + {5310, 62}, + {5510, 102}, + {5530, 106}, + {5550, 110}, + {5570, 114}, + {5590, 118}, + {5610, 122}, + {5630, 126}, + {5650, 130}, + {5670, 134}, + {5690, 138}, + {5710, 142}, + {5755, 151}, + {5775, 155}, + {5795, 159}, + {5815, 163, }, +}; + +static t_reg_table reg_table; + +const sRegulatoryChannel *reg_channels = + reg_table.regDomains[0].channels; + + +/** + * cds_is_wwr_sku() - is regdomain world sku + * @regd: integer regulatory domain + * + * Return: bool + */ +static inline bool cds_is_wwr_sku(u16 regd) +{ + return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && + (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || + (regd == WORLD)); +} + +/** + * cds_is_world_regdomain() - whether world regdomain + * @regd: integer regulatory domain + * + * Return: bool + */ +bool cds_is_world_regdomain(uint32_t regd) +{ + return cds_is_wwr_sku(regd & ~WORLDWIDE_ROAMING_FLAG); +} + + +/** + * cds_world_regdomain() - which constant world regdomain + * @reg: regulatory data + * + * Return: regdomain ptr + */ +static const struct ieee80211_regdomain +*cds_world_regdomain(struct regulatory *reg) +{ + REG_DMN_PAIR_MAPPING *regpair = + (REG_DMN_PAIR_MAPPING *)reg->regpair; + + switch (regpair->regDmnEnum) { + case 0x60: + case 0x61: + case 0x62: + return &cds_world_regdom_60_61_62; + case 0x63: + case 0x65: + return &cds_world_regdom_63_65; + case 0x64: + return &cds_world_regdom_64; + case 0x66: + case 0x69: + return &cds_world_regdom_66_69; + case 0x67: + case 0x68: + case 0x6A: + case 0x6C: + return &cds_world_regdom_67_68_6A_6C; + default: + WARN_ON(1); + return &cds_world_regdom_60_61_62; + } +} + +/** + * cds_regulatory_wiphy_init() - regulatory wiphy init + * @hdd_ctx: hdd context + * @reg: regulatory data + * @wiphy: wiphy structure + * + * Return: int + */ +static int cds_regulatory_wiphy_init(hdd_context_t *hdd_ctx, + struct regulatory *reg, + struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *reg_domain; + + if (cds_is_world_regdomain(reg->reg_domain)) { + reg_domain = cds_world_regdomain(reg); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +#else + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +#endif + } else if (hdd_ctx->config->fRegChangeDefCountry) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; +#else + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +#endif + reg_domain = &cds_world_regdom_60_61_62; + } else { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; +#else + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; +#endif + reg_domain = &cds_world_regdom_60_61_62; + } + + /* + * save the original driver regulatory flags + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + hdd_ctx->reg.reg_flags = wiphy->regulatory_flags; +#else + hdd_ctx->reg.reg_flags = wiphy->flags; +#endif + wiphy_apply_custom_regulatory(wiphy, reg_domain); + + /* + * restore the driver regulatory flags since + * wiphy_apply_custom_regulatory may have + * changed them + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + wiphy->regulatory_flags = hdd_ctx->reg.reg_flags; +#else + wiphy->flags = hdd_ctx->reg.reg_flags; +#endif + + return 0; +} + +/** + * cds_update_regulatory_info() - update regulatory info + * @hdd_ctx: hdd context + * + * Return: CDF_STATUS + */ +static void cds_update_regulatory_info(hdd_context_t *hdd_ctx) +{ + uint32_t country_code; + + country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2); + + hdd_ctx->reg.reg_domain = COUNTRY_ERD_FLAG; + hdd_ctx->reg.reg_domain |= country_code; + + cds_fill_some_regulatory_info(&hdd_ctx->reg); + + return; +} + + +/** + * cds_get_channel_list_with_power() - retrieve channel list with power + * @base_channels: base channels + * @num_base_channels: number of base channels + * @channels_40mhz: 40 MHz channels + * @num_40mhz_channels: number of 40 Mhz channels + * + * Return: CDF_STATUS_SUCCESS + */ +CDF_STATUS cds_get_channel_list_with_power(tChannelListWithPower * + base_channels, + uint8_t *num_base_channels, + tChannelListWithPower * + channels_40mhz, + uint8_t *num_40mhz_channels) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + int i, count; + + if (base_channels && num_base_channels) { + count = 0; + for (i = 0; i <= RF_CHAN_14; i++) { + if (reg_channels[i].enabled) { + base_channels[count].chanId = + rf_channels[i].channelNum; + base_channels[count++].pwr = + reg_channels[i].pwrLimit; + } + } + for (i = RF_CHAN_36; i <= RF_CHAN_184; i++) { + if (reg_channels[i].enabled) { + base_channels[count].chanId = + rf_channels[i].channelNum; + base_channels[count++].pwr = + reg_channels[i].pwrLimit; + } + } + *num_base_channels = count; + } + + if (channels_40mhz && num_40mhz_channels) { + count = 0; + + for (i = RF_CHAN_BOND_3; i <= RF_CHAN_BOND_11; i++) { + if (reg_channels[i].enabled) { + channels_40mhz[count].chanId = + rf_channels[i].channelNum; + channels_40mhz[count++].pwr = + reg_channels[i].pwrLimit; + } + } + + for (i = RF_CHAN_BOND_38; i <= RF_CHAN_BOND_163; i++) { + if (reg_channels[i].enabled) { + channels_40mhz[count].chanId = + rf_channels[i].channelNum; + channels_40mhz[count++].pwr = + reg_channels[i].pwrLimit; + } + } + *num_40mhz_channels = count; + } + + return status; +} + +/** + * cds_read_default_country() - set the default country + * @default_country: default country + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_read_default_country(country_code_t default_country) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + memcpy(default_country, + reg_table.default_country, + sizeof(country_code_t)); + + pr_info("DefaultCountry is %c%c\n", + default_country[0], + default_country[1]); + + return status; +} + +/** + * cds_get_channel_enum() - get the channel enumeration + * @chan_num: channel number + * + * Return: enum for the channel + */ +static eRfChannels cds_get_channel_enum(uint32_t chan_num) +{ + uint32_t loop; + + for (loop = 0; loop <= RF_CHAN_184; loop++) + if (rf_channels[loop].channelNum == chan_num) + return loop; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "invalid channel number %d", chan_num); + + return INVALID_RF_CHANNEL; +} + + +/** + * cds_get_channel_state() - get the channel state + * @channel_num: channel number + * + * Return: CHANNEL_STATE + */ +CHANNEL_STATE cds_get_channel_state(uint32_t chan_num) +{ + eRfChannels chan_enum; + + chan_enum = cds_get_channel_enum(chan_num); + if (INVALID_RF_CHANNEL == chan_enum) + return CHANNEL_STATE_INVALID; + else + return reg_channels[chan_enum].enabled; +} + + +/** + * cds_get_bonded_channel_state() - get the bonded channel state + * @channel_num: channel number + * + * Return: CHANNEL_STATE + */ +CHANNEL_STATE cds_get_bonded_channel_state(uint32_t chan_num, + enum channel_width ch_width) +{ + eRfChannels chan_enum; + bool bw_enabled = false; + + chan_enum = cds_get_channel_enum(chan_num); + if (INVALID_RF_CHANNEL == chan_enum) + return CHANNEL_STATE_INVALID; + + if (reg_channels[chan_enum].enabled) { + if (CHAN_WIDTH_5MHZ == ch_width) + bw_enabled = 1; + else if (CHAN_WIDTH_10MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_10MHZ); + else if (CHAN_WIDTH_20MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_20MHZ); + else if (CHAN_WIDTH_40MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40); + else if (CHAN_WIDTH_80MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_80MHZ); + else if (CHAN_WIDTH_160MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_160MHZ); + } + + if (bw_enabled) + return reg_channels[chan_enum].enabled; + else + return CHANNEL_STATE_DISABLE; +} + +/** + * cds_get_max_channel_bw() - get the max channel bandwidth + * @channel_num: channel number + * + * Return: channel_width + */ +enum channel_width cds_get_max_channel_bw(uint32_t chan_num) +{ + eRfChannels chan_enum; + enum channel_width chan_bw = CHAN_WIDTH_0MHZ; + + chan_enum = cds_get_channel_enum(chan_num); + + if ((INVALID_RF_CHANNEL != chan_enum) && + (CHANNEL_STATE_DISABLE != reg_channels[chan_enum].enabled)) { + + if (!(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_160MHZ)) + chan_bw = CHAN_WIDTH_160MHZ; + else if (!(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_80MHZ)) + chan_bw = CHAN_WIDTH_80MHZ; + else if (!(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40)) + chan_bw = CHAN_WIDTH_40MHZ; + else if (!(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_20MHZ)) + chan_bw = CHAN_WIDTH_20MHZ; + else if (!(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_10MHZ)) + chan_bw = CHAN_WIDTH_10MHZ; + else + chan_bw = CHAN_WIDTH_5MHZ; + } + + return chan_bw; + +} + +static int cds_bw20_ch_index_to_bw40_ch_index(int k) +{ + int m = -1; + if (k >= RF_CHAN_1 && k <= RF_CHAN_14) { + m = k - RF_CHAN_1 + RF_CHAN_BOND_3; + if (m > RF_CHAN_BOND_11) + m = RF_CHAN_BOND_11; + } else if (k >= RF_CHAN_240 && k <= RF_CHAN_216) { + m = k - RF_CHAN_240 + RF_CHAN_BOND_242; + if (m > RF_CHAN_BOND_214) + m = RF_CHAN_BOND_214; + } else if (k >= RF_CHAN_36 && k <= RF_CHAN_64) { + m = k - RF_CHAN_36 + RF_CHAN_BOND_38; + if (m > RF_CHAN_BOND_62) + m = RF_CHAN_BOND_62; + } + else if (k >= RF_CHAN_100 && k <= RF_CHAN_144) + { + m = k - RF_CHAN_100 + RF_CHAN_BOND_102; + if (m > RF_CHAN_BOND_142) + m = RF_CHAN_BOND_142; + } else if (k >= RF_CHAN_149 && k <= RF_CHAN_165) { + m = k - RF_CHAN_149 + RF_CHAN_BOND_151; + if (m > RF_CHAN_BOND_163) + m = RF_CHAN_BOND_163; + } + return m; +} + +/** + * cds_set_dfs_region() - set the dfs_region + * @dfs_region: the dfs_region to set + * + * Return: CDF_STATUS_SUCCESS if dfs_region set correctly + * CDF_STATUS_E_EXISTS if hdd context not found + */ +CDF_STATUS cds_set_dfs_region(uint8_t dfs_region) +{ + hdd_context_t *hdd_ctx_ptr = NULL; + + hdd_ctx_ptr = cds_get_context(CDF_MODULE_ID_HDD); + + if (NULL == hdd_ctx_ptr) + return CDF_STATUS_E_EXISTS; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + hdd_ctx_ptr->reg.dfs_region = dfs_region; +#else + + /* remap the ctl code to dfs region code */ + switch (hdd_ctx_ptr->reg.ctl_5g) { + case FCC: + hdd_ctx_ptr->reg.dfs_region = DFS_FCC_DOMAIN; + break; + case ETSI: + hdd_ctx_ptr->reg.dfs_region = DFS_ETSI_DOMAIN; + break; + case MKK: + hdd_ctx_ptr->reg.dfs_region = DFS_MKK4_DOMAIN; + break; + default: + /* set default dfs_region to FCC */ + hdd_ctx_ptr->reg.dfs_region = DFS_FCC_DOMAIN; + break; + } +#endif + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_dfs_region() - get the dfs_region + * @dfs_region: the dfs_region to return + * + * Return: CDF_STATUS_SUCCESS if dfs_region set correctly + * CDF_STATUS_E_EXISTS if hdd context not found + */ +CDF_STATUS cds_get_dfs_region(uint8_t *dfs_region) +{ + hdd_context_t *hdd_ctx_ptr = NULL; + + hdd_ctx_ptr = cds_get_context(CDF_MODULE_ID_HDD); + + if (NULL == hdd_ctx_ptr) + return CDF_STATUS_E_EXISTS; + + *dfs_region = hdd_ctx_ptr->reg.dfs_region; + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_get_reg_domain_from_country_code() - get the regulatory domain + * @reg_domain_ptr: ptr to store regulatory domain + * + * Return: CDF_STATUS_SUCCESS on success + * CDF_STATUS_E_FAULT on error + * CDF_STATUS_E_EMPTY country table empty + */ +CDF_STATUS cds_get_reg_domain_from_country_code(v_REGDOMAIN_t *reg_domain_ptr, + const country_code_t + country_code, + v_CountryInfoSource_t source) +{ + v_CONTEXT_t cds_context = NULL; + hdd_context_t *hdd_ctx = NULL; + struct wiphy *wiphy = NULL; + int i; + + if (NULL == reg_domain_ptr) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Invalid reg domain pointer")); + return CDF_STATUS_E_FAULT; + } + + *reg_domain_ptr = REGDOMAIN_COUNT; + + if (NULL == country_code) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Country code array is NULL")); + return CDF_STATUS_E_FAULT; + } + + if (0 == country_info_table.countryCount) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Reg domain table is empty")); + return CDF_STATUS_E_EMPTY; + } + + cds_context = cds_get_global_context(); + + if (NULL != cds_context) + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + else + return CDF_STATUS_E_EXISTS; + + if (NULL == hdd_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Invalid pHddCtx pointer")); + return CDF_STATUS_E_FAULT; + } + + wiphy = hdd_ctx->wiphy; + + if (cds_is_logp_in_progress()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "SSR in progress, return"); + *reg_domain_ptr = temp_reg_domain; + return CDF_STATUS_SUCCESS; + } + + temp_reg_domain = REGDOMAIN_COUNT; + for (i = 0; i < country_info_table.countryCount && + REGDOMAIN_COUNT == temp_reg_domain; i++) { + if (memcmp(country_code, + country_info_table.countryInfo[i].countryCode, + CDS_COUNTRY_CODE_LEN) == 0) { + + temp_reg_domain = + country_info_table.countryInfo[i].regDomain; + break; + } + } + + if (REGDOMAIN_COUNT == temp_reg_domain) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Country does not map to any Regulatory domain")); + temp_reg_domain = REGDOMAIN_WORLD; + } + + if (COUNTRY_QUERY == source) { + *reg_domain_ptr = temp_reg_domain; + return CDF_STATUS_SUCCESS; + } + + if ((COUNTRY_INIT == source) && (false == init_by_reg_core)) { + init_by_driver = true; + if (('0' != country_code[0]) || ('0' != country_code[1])) { + INIT_COMPLETION(hdd_ctx->reg_init); + regulatory_hint(wiphy, country_code); + wait_for_completion_timeout(&hdd_ctx->reg_init, + msecs_to_jiffies(REG_WAIT_TIME)); + } + } else if (COUNTRY_IE == source || COUNTRY_USER == source) { + regulatory_hint_user(country_code, + NL80211_USER_REG_HINT_USER); + } + + *reg_domain_ptr = temp_reg_domain; + return CDF_STATUS_SUCCESS; +} + +/* + * cds_is_dsrc_channel() - is the channel DSRC + * @center_freq: center freq of the channel + * + * Return: true if dsrc channel + * false otherwise + */ +bool cds_is_dsrc_channel(uint16_t center_freq) +{ + switch (center_freq) { + case 5852: + case 5860: + case 5870: + case 5880: + case 5890: + case 5900: + case 5910: + case 5920: + case 5875: + case 5905: + return 1; + } + return 0; +} + +#ifdef FEATURE_STATICALLY_ADD_11P_CHANNELS +#define DEFAULT_11P_POWER (30) +#endif + +/** + * cds_process_regulatory_data() - process regulatory data + * @wiphy: wiphy + * @band_capability: band_capability + * + * Return: int + */ +static int cds_process_regulatory_data(struct wiphy *wiphy, + uint8_t band_capability, bool reset) +{ + int i, j, m; + int k = 0, n = 0; + hdd_context_t *hdd_ctx; + const struct ieee80211_reg_rule *reg_rule; + struct ieee80211_channel *chan; + sRegulatoryChannel *temp_chan_k; + sRegulatoryChannel *temp_chan_n; + sRegulatoryChannel *temp_chan; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL == hdd_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "invalid hdd_ctx pointer"); + return CDF_STATUS_E_FAULT; + } + + hdd_ctx->isVHT80Allowed = 0; + + if (band_capability == eCSR_BAND_24) + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "band capability is set to 2G only"); + + for (i = 0, m = 0; i < IEEE80211_NUM_BANDS; i++) { + + if (i == IEEE80211_BAND_2GHZ && band_capability == eCSR_BAND_5G) + continue; + + else if (i == IEEE80211_BAND_5GHZ + && band_capability == eCSR_BAND_24) + continue; + + if (wiphy->bands[i] == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "error: wiphy->bands is NULL, i = %d", i); + continue; + } + + if (i == 0) + m = 0; + else + m = wiphy->bands[i-1]->n_channels + m; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + + k = m + j; + n = cds_bw20_ch_index_to_bw40_ch_index(k); + + chan = &(wiphy->bands[i]->channels[j]); + temp_chan_k = + &(reg_table.regDomains[temp_reg_domain]. + channels[k]); + + temp_chan_n = + &(reg_table.regDomains[temp_reg_domain]. + channels[n]); + + if ((!reset) && +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + (wiphy->regulatory_flags & + REGULATORY_CUSTOM_REG)) { +#else + (wiphy->flags & + WIPHY_FLAG_CUSTOM_REGULATORY)) { +#endif + reg_rule = freq_reg_info(wiphy, + MHZ_TO_KHZ(chan-> + center_freq)); + + if (!IS_ERR(reg_rule)) { + chan->flags &= + ~IEEE80211_CHAN_DISABLED; + + if (!(reg_rule->flags & + NL80211_RRF_DFS)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Remove passive scan restriction for %u", + __func__, + chan->center_freq); + chan->flags &= + ~IEEE80211_CHAN_RADAR; + } + + if (!(reg_rule->flags & + NL80211_RRF_PASSIVE_SCAN)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Remove passive scan restriction for %u", + __func__, + chan->center_freq); + chan->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + if (!(reg_rule->flags & + NL80211_RRF_NO_IBSS)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Remove no ibss restriction for %u", + __func__, + chan->center_freq); + chan->flags &= + ~IEEE80211_CHAN_NO_IBSS; + } + + chan->max_power = MBM_TO_DBM(reg_rule-> + power_rule. + max_eirp); + } + } + +#ifdef FEATURE_STATICALLY_ADD_11P_CHANNELS + if (is_dsrc_channel(chan->center_freq)) { + temp_chan_k->enabled = + CHANNEL_STATE_ENABLE; + temp_chan_k->pwrLimit = + DEFAULT_11P_POWER; + temp_chan_k->flags = chan->flags; + } else +#endif + if (chan->flags & IEEE80211_CHAN_DISABLED) { + temp_chan_k->enabled = + CHANNEL_STATE_DISABLE; + temp_chan_k->flags = chan->flags; + if (n != -1) { + temp_chan_n->enabled = + CHANNEL_STATE_DISABLE; + temp_chan_n->flags = chan->flags; + } + } else if (chan->flags & + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_PASSIVE_SCAN +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + | + IEEE80211_CHAN_INDOOR_ONLY +#endif + )) { + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + if (chan->flags & + IEEE80211_CHAN_INDOOR_ONLY) + chan->flags |= + IEEE80211_CHAN_PASSIVE_SCAN; +#endif + temp_chan_k->enabled = CHANNEL_STATE_DFS; + temp_chan_k->pwrLimit = + chan->max_power; + temp_chan_k->flags = chan->flags; + + if (n != -1) { + if ((chan->flags & + IEEE80211_CHAN_NO_HT40) == + IEEE80211_CHAN_NO_HT40) { + temp_chan_n->enabled = + CHANNEL_STATE_DISABLE; + } else { + temp_chan_n->enabled = + CHANNEL_STATE_DFS; + temp_chan_n->pwrLimit = + chan->max_power-3; + } + temp_chan_n->flags = chan->flags; + } + if ((chan->flags & + IEEE80211_CHAN_NO_80MHZ) == 0) + hdd_ctx->isVHT80Allowed = 1; + } else { + temp_chan_k->enabled = CHANNEL_STATE_ENABLE; + temp_chan_k->pwrLimit = chan->max_power; + temp_chan_k->flags = chan->flags; + if (n != -1) { + if ((chan->flags & + IEEE80211_CHAN_NO_HT40) == + IEEE80211_CHAN_NO_HT40) { + temp_chan_n->enabled = + CHANNEL_STATE_DISABLE; + } else { + temp_chan_n->enabled = + CHANNEL_STATE_ENABLE; + temp_chan_n->pwrLimit = + chan->max_power - 3; + } + temp_chan_n->flags = chan->flags; + } + if ((chan->flags & + IEEE80211_CHAN_NO_80MHZ) == 0) + hdd_ctx->isVHT80Allowed = 1; + } + } + } + + if (0 == (hdd_ctx->reg.eeprom_rd_ext & + (1 << WHAL_REG_EXT_FCC_CH_144))) { + temp_chan = &(reg_table.regDomains[temp_reg_domain]. + channels[RF_CHAN_144]); + temp_chan->enabled = + CHANNEL_STATE_DISABLE; + } + + if (k == 0) + return -1; + + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) && !defined(WITH_BACKPORTS) +/** + * restore_custom_reg_settings() - restore custom reg settings + * @wiphy: wiphy structure + * + * Return: void + */ +static void restore_custom_reg_settings(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + enum ieee80211_band band; + struct ieee80211_channel *chan; + int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + chan->flags = chan->orig_flags; + chan->max_antenna_gain = chan->orig_mag; + chan->max_power = chan->orig_mpwr; + } + } +} +#endif + +/** + * hdd_reg_notifier() - regulatory notifier + * @wiphy: wiphy + * @request: regulatory request + * + * Return: void or int + */ +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + eCsrBand band_capability = eCSR_BAND_ALL; + country_code_t country_code; + int i; + bool vht80_allowed; + bool reset = false; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + FL("country: %c%c, initiator %d, dfs_region: %d"), + request->alpha2[0], + request->alpha2[1], + request->initiator, + request->dfs_region); + + if (NULL == hdd_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Invalid pHddCtx pointer")); + return; + } + + if (hdd_ctx->isUnloadInProgress || hdd_ctx->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Unloading or SSR in Progress, Ignore!!!", + __func__); + return; + } + + sme_get_freq_band(hdd_ctx->hHal, &band_capability); + + /* first check if this callback is in response to the driver callback */ + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + + if ((false == init_by_driver) && + (false == init_by_reg_core)) { + + if (NL80211_REGDOM_SET_BY_CORE == request->initiator) { + return; + } + init_by_reg_core = true; + } + + if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) && + (true == init_by_driver)) { + + /* + * restore the driver regulatory flags since + * regulatory_hint may have + * changed them + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + wiphy->regulatory_flags = hdd_ctx->reg.reg_flags; +#else + wiphy->flags = hdd_ctx->reg.reg_flags; +#endif + } + + if (NL80211_REGDOM_SET_BY_CORE == request->initiator) { + hdd_ctx->reg.cc_src = COUNTRY_CODE_SET_BY_CORE; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) + if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) +#else + if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) +#endif + reset = true; + } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) + hdd_ctx->reg.cc_src = COUNTRY_CODE_SET_BY_DRIVER; + else { + hdd_ctx->reg.cc_src = COUNTRY_CODE_SET_BY_USER; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) && !defined(WITH_BACKPORTS) + if ((request->alpha2[0] == '0') && + (request->alpha2[1] == '0') && + (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) { + restore_custom_reg_settings(wiphy); + reset = true; + } +#endif + } + + /* first lookup the country in the local database */ + country_code[0] = request->alpha2[0]; + country_code[1] = request->alpha2[1]; + + hdd_ctx->reg.alpha2[0] = request->alpha2[0]; + hdd_ctx->reg.alpha2[1] = request->alpha2[1]; + + cds_update_regulatory_info(hdd_ctx); + + temp_reg_domain = REGDOMAIN_COUNT; + for (i = 0; i < country_info_table.countryCount && + REGDOMAIN_COUNT == temp_reg_domain; i++) { + if (memcmp(country_code, + country_info_table.countryInfo[i].countryCode, + CDS_COUNTRY_CODE_LEN) == 0) { + + temp_reg_domain = + country_info_table.countryInfo[i].regDomain; + break; + } + } + + if (REGDOMAIN_COUNT == temp_reg_domain) + temp_reg_domain = REGDOMAIN_WORLD; + + vht80_allowed = hdd_ctx->isVHT80Allowed; + if (cds_process_regulatory_data(wiphy, band_capability, + reset) == 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + (" regulatory entry created")); + } + if (hdd_ctx->isVHT80Allowed != vht80_allowed) + hdd_checkandupdate_phymode(hdd_ctx); + + if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) + complete(&hdd_ctx->reg_init); + + if (request->alpha2[0] == '0' + && request->alpha2[1] == '0') { + sme_generic_change_country_code(hdd_ctx->hHal, + country_code, + REGDOMAIN_COUNT); + } else { + sme_generic_change_country_code(hdd_ctx->hHal, + country_code, + temp_reg_domain); + } + + cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg); + + cds_set_dfs_region(request->dfs_region); + + cds_set_wma_dfs_region(&hdd_ctx->reg); + default: + break; + } + + return; +} + +/** + * cds_regulatory_init() - regulatory_init + * Return: CDF_STATUS + */ +CDF_STATUS cds_regulatory_init(void) +{ + v_CONTEXT_t cds_context = NULL; + hdd_context_t *hdd_ctx = NULL; + struct wiphy *wiphy = NULL; + int ret_val = 0; + struct regulatory *reg_info; + + cds_context = cds_get_global_context(); + + if (!cds_context) + return CDF_STATUS_E_FAULT; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Invalid pHddCtx pointer")); + return CDF_STATUS_E_FAULT; + } + + wiphy = hdd_ctx->wiphy; + + reg_info = &hdd_ctx->reg; + + cds_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy); + + temp_reg_domain = REGDOMAIN_WORLD; + + if (cds_process_regulatory_data(wiphy, + hdd_ctx->config-> + nBandCapability, true) != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + ("Error while creating regulatory entry")); + return CDF_STATUS_E_FAULT; + } + + reg_info->cc_src = COUNTRY_CODE_SET_BY_DRIVER; + + ret_val = cds_fill_some_regulatory_info(reg_info); + if (ret_val) { + cdf_print(KERN_ERR "Error in getting country code\n"); + return ret_val; + } + + reg_table.default_country[0] = reg_info->alpha2[0]; + reg_table.default_country[1] = reg_info->alpha2[1]; + + init_completion(&hdd_ctx->reg_init); + + cds_fill_and_send_ctl_to_fw(reg_info); + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_set_reg_domain() - set regulatory domain + * @client_ctxt: client context + * @reg_domain: regulatory domain + * + * Return: CDF_STATUS + */ +CDF_STATUS cds_set_reg_domain(void *client_ctxt, v_REGDOMAIN_t reg_domain) +{ + if (reg_domain >= REGDOMAIN_COUNT) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "CDS set reg domain, invalid REG domain ID %d", + reg_domain); + return CDF_STATUS_E_INVAL; + } + + reg_channels = reg_table.regDomains[reg_domain].channels; + + return CDF_STATUS_SUCCESS; +} diff --git a/core/cds/src/cds_regdomain.c b/core/cds/src/cds_regdomain.c new file mode 100644 index 0000000000..3a935293c2 --- /dev/null +++ b/core/cds/src/cds_regdomain.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2011,2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#include +#include "wma.h" +#include "cds_regdomain.h" +#include "cds_regdomain_common.h" + +static regdm_supp_op_classes regdm_curr_supp_opp_classes = { 0 }; + +/* Global Operating Classes */ +regdm_op_class_map_t global_op_class[] = { + {81, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, + {82, 25, BW20, {14}}, + {83, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {84, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13}}, + {115, 20, BW20, {36, 40, 44, 48}}, + {116, 40, BW40_LOW_PRIMARY, {36, 44}}, + {117, 40, BW40_HIGH_PRIMARY, {40, 48}}, + {118, 20, BW20, {52, 56, 60, 64}}, + {119, 40, BW40_LOW_PRIMARY, {52, 60}}, + {120, 40, BW40_HIGH_PRIMARY, {56, 64}}, + {121, 20, BW20, + {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}}, + {122, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132}}, + {123, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136}}, + {125, 20, BW20, {149, 153, 157, 161, 165, 169}}, + {126, 40, BW40_LOW_PRIMARY, {149, 157}}, + {127, 40, BW40_HIGH_PRIMARY, {153, 161}}, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161} }, + {0, 0, 0, {0}}, +}; + +/* Operating Classes in US */ +regdm_op_class_map_t us_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48}}, + {2, 20, BW20, {52, 56, 60, 64}}, + {4, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, + 144} }, + {5, 20, BW20, {149, 153, 157, 161, 165}}, + {12, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}, + {22, 40, BW40_LOW_PRIMARY, {36, 44}}, + {23, 40, BW40_LOW_PRIMARY, {52, 60}}, + {24, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132}}, + {26, 40, BW40_LOW_PRIMARY, {149, 157}}, + {27, 40, BW40_HIGH_PRIMARY, {40, 48}}, + {28, 40, BW40_HIGH_PRIMARY, {56, 64}}, + {29, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136}}, + {31, 40, BW40_HIGH_PRIMARY, {153, 161}}, + {32, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7}}, + {33, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11}}, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161} }, + {0, 0, 0, {0}}, +}; + +/* Operating Classes in Europe */ +regdm_op_class_map_t euro_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48}}, + {2, 20, BW20, {52, 56, 60, 64}}, + {3, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}}, + {4, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, + {5, 40, BW40_LOW_PRIMARY, {36, 44}}, + {6, 40, BW40_LOW_PRIMARY, {52, 60}}, + {7, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132}}, + {8, 40, BW40_HIGH_PRIMARY, {40, 48}}, + {9, 40, BW40_HIGH_PRIMARY, {56, 64}}, + {10, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136}}, + {11, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {12, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13}}, + {17, 20, BW20, {149, 153, 157, 161, 165, 169}}, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, + 116, 120, 124, 128} }, + {0, 0, 0, {0}}, +}; + +/* Operating Classes in Japan */ +regdm_op_class_map_t japan_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48}}, + {30, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, + {31, 25, BW20, {14}}, + {32, 20, BW20, {52, 56, 60, 64}}, + {34, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}}, + {36, 40, BW40_LOW_PRIMARY, {36, 44}}, + {37, 40, BW40_LOW_PRIMARY, {52, 60}}, + {39, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132}}, + {41, 40, BW40_HIGH_PRIMARY, {40, 48}}, + {42, 40, BW40_HIGH_PRIMARY, {56, 64}}, + {44, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136}}, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, + 116, 120, 124, 128} }, + {0, 0, 0, {0}}, +}; + +/* + * By default, the regdomain tables reference the common tables + * from regdomain_common.h. These default tables can be replaced + * by calls to populate_regdomain_tables functions. + */ +HAL_REG_DMN_TABLES ol_regdmn_rdt = { + ah_cmn_reg_domain_pairs, /* regDomainPairs */ + ah_cmn_all_countries, /* allCountries */ + ah_cmn_reg_domains, /* allRegDomains */ + CDF_ARRAY_SIZE(ah_cmn_reg_domain_pairs), /* regDomainPairsCt */ + CDF_ARRAY_SIZE(ah_cmn_all_countries), /* allCountriesCt */ + CDF_ARRAY_SIZE(ah_cmn_reg_domains), /* allRegDomainCt */ +}; + +static uint16_t get_eeprom_rd(uint16_t rd) +{ + return rd & ~WORLDWIDE_ROAMING_FLAG; +} + +/* + * Return whether or not the regulatory domain/country in EEPROM + * is acceptable. + */ +static bool regdmn_is_eeprom_valid(uint16_t rd) +{ + int32_t i; + + if (rd & COUNTRY_ERD_FLAG) { + uint16_t cc = rd & ~COUNTRY_ERD_FLAG; + for (i = 0; i < ol_regdmn_rdt.allCountriesCt; i++) + if (ol_regdmn_rdt.allCountries[i].countryCode == cc) + return true; + } else { + for (i = 0; i < ol_regdmn_rdt.regDomainPairsCt; i++) + if (ol_regdmn_rdt.regDomainPairs[i].regDmnEnum == rd) + return true; + } + /* TODO: Bring it under debug level */ + cdf_print("%s: invalid regulatory domain/country code 0x%x\n", + __func__, rd); + return false; +} + +/* + * Find the pointer to the country element in the country table + * corresponding to the country code + */ +static const COUNTRY_CODE_TO_ENUM_RD *find_country(uint16_t country_code) +{ + int32_t i; + + for (i = 0; i < ol_regdmn_rdt.allCountriesCt; i++) { + if (ol_regdmn_rdt.allCountries[i].countryCode == country_code) + return &ol_regdmn_rdt.allCountries[i]; + } + return NULL; /* Not found */ +} + +int32_t cds_get_country_from_alpha2(uint8_t *alpha2) +{ + int32_t i; + + for (i = 0; i < ol_regdmn_rdt.allCountriesCt; i++) { + if (ol_regdmn_rdt.allCountries[i].isoName[0] == alpha2[0] && + ol_regdmn_rdt.allCountries[i].isoName[1] == alpha2[1]) + return ol_regdmn_rdt.allCountries[i].countryCode; + } + return CTRY_DEFAULT; +} + +static uint16_t regdmn_get_default_country(uint16_t rd) +{ + int32_t i; + + if (rd & COUNTRY_ERD_FLAG) { + const COUNTRY_CODE_TO_ENUM_RD *country = NULL; + uint16_t cc = rd & ~COUNTRY_ERD_FLAG; + + country = find_country(cc); + if (country) + return cc; + } + + /* + * Check reg domains that have only one country + */ + for (i = 0; i < ol_regdmn_rdt.regDomainPairsCt; i++) { + if (ol_regdmn_rdt.regDomainPairs[i].regDmnEnum == rd) { + if (ol_regdmn_rdt.regDomainPairs[i].singleCC != 0) + return ol_regdmn_rdt.regDomainPairs[i].singleCC; + else + i = ol_regdmn_rdt.regDomainPairsCt; + } + } + return CTRY_DEFAULT; +} + +static const REG_DMN_PAIR_MAPPING *get_regdmn_pair(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < ol_regdmn_rdt.regDomainPairsCt; i++) { + if (ol_regdmn_rdt.regDomainPairs[i].regDmnEnum == reg_dmn) + return &ol_regdmn_rdt.regDomainPairs[i]; + } + return NULL; +} + +static const REG_DOMAIN *get_regdmn(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < ol_regdmn_rdt.regDomainsCt; i++) { + if (ol_regdmn_rdt.regDomains[i].regDmnEnum == reg_dmn) + return &ol_regdmn_rdt.regDomains[i]; + } + return NULL; +} + +static const COUNTRY_CODE_TO_ENUM_RD *get_country_from_rd(uint16_t regdmn) +{ + int32_t i; + + for (i = 0; i < ol_regdmn_rdt.allCountriesCt; i++) { + if (ol_regdmn_rdt.allCountries[i].regDmnEnum == regdmn) + return &ol_regdmn_rdt.allCountries[i]; + } + return NULL; /* Not found */ +} + +/* + * Some users have reported their EEPROM programmed with + * 0x8000 set, this is not a supported regulatory domain + * but since we have more than one user with it we need + * a solution for them. We default to WOR0_WORLD + */ +static void regd_sanitize(struct regulatory *reg) +{ + if (reg->reg_domain != COUNTRY_ERD_FLAG) + return; + reg->reg_domain = WOR0_WORLD; +} + +/* + * Returns country string for the given regulatory domain. + */ +int32_t cds_fill_some_regulatory_info(struct regulatory *reg) +{ + uint16_t country_code; + uint16_t regdmn, rd; + const COUNTRY_CODE_TO_ENUM_RD *country = NULL; + + regd_sanitize(reg); + rd = reg->reg_domain; + + if (!regdmn_is_eeprom_valid(rd)) + return -EINVAL; + + regdmn = get_eeprom_rd(rd); + + country_code = regdmn_get_default_country(regdmn); + if (country_code == CTRY_DEFAULT && regdmn == CTRY_DEFAULT) { + /* Set to CTRY_UNITED_STATES for testing */ + country_code = CTRY_UNITED_STATES; + } + + if (country_code != CTRY_DEFAULT) { + country = find_country(country_code); + if (!country) { + /* TODO: Bring it under debug level */ + cdf_print(KERN_ERR "Not a valid country code\n"); + return -EINVAL; + } + regdmn = country->regDmnEnum; + } + + reg->regpair = get_regdmn_pair(regdmn); + if (!reg->regpair) { + /* TODO: Bring it under debug level */ + cdf_print(KERN_ERR "No regpair is found, can not proceeed\n"); + return -EINVAL; + } + reg->country_code = country_code; + + if (!country) + country = get_country_from_rd(regdmn); + + if (country) { + reg->alpha2[0] = country->isoName[0]; + reg->alpha2[1] = country->isoName[1]; + } else { + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; + } + + return 0; +} + +/* + * Returns regulatory domain for given country string + */ +int32_t regdmn_get_regdmn_for_country(uint8_t *alpha2) +{ + uint8_t i; + + for (i = 0; i < ol_regdmn_rdt.allCountriesCt; i++) { + if ((ol_regdmn_rdt.allCountries[i].isoName[0] == alpha2[0]) && + (ol_regdmn_rdt.allCountries[i].isoName[1] == alpha2[1])) + return ol_regdmn_rdt.allCountries[i].regDmnEnum; + } + return -1; +} + +/* + * Test to see if the bitmask array is all zeros + */ +static bool is_chan_bit_mask_zero(const uint64_t *bitmask) +{ + int i; + + for (i = 0; i < BMLEN; i++) { + if (bitmask[i] != 0) + return false; + } + return true; +} + +/* + * Return the mask of available modes based on the hardware + * capabilities and the specified country code and reg domain. + */ +static uint32_t regdmn_getwmodesnreg(uint32_t modesAvail, + const COUNTRY_CODE_TO_ENUM_RD *country, + const REG_DOMAIN *rd5GHz) +{ + + /* Check country regulations for allowed modes */ + if ((modesAvail & (REGDMN_MODE_11A_TURBO | REGDMN_MODE_TURBO)) && + (!country->allow11aTurbo)) + modesAvail &= ~(REGDMN_MODE_11A_TURBO | REGDMN_MODE_TURBO); + + if ((modesAvail & REGDMN_MODE_11G_TURBO) && (!country->allow11gTurbo)) + modesAvail &= ~REGDMN_MODE_11G_TURBO; + + if ((modesAvail & REGDMN_MODE_11G) && (!country->allow11g)) + modesAvail &= ~REGDMN_MODE_11G; + + if ((modesAvail & REGDMN_MODE_11A) && + (is_chan_bit_mask_zero(rd5GHz->chan11a))) + modesAvail &= ~REGDMN_MODE_11A; + + if ((modesAvail & REGDMN_MODE_11NG_HT20) && (!country->allow11ng20)) + modesAvail &= ~REGDMN_MODE_11NG_HT20; + + if ((modesAvail & REGDMN_MODE_11NA_HT20) && (!country->allow11na20)) + modesAvail &= ~REGDMN_MODE_11NA_HT20; + + if ((modesAvail & REGDMN_MODE_11NG_HT40PLUS) && (!country->allow11ng40)) + modesAvail &= ~REGDMN_MODE_11NG_HT40PLUS; + + if ((modesAvail & REGDMN_MODE_11NG_HT40MINUS) && + (!country->allow11ng40)) + modesAvail &= ~REGDMN_MODE_11NG_HT40MINUS; + + if ((modesAvail & REGDMN_MODE_11NA_HT40PLUS) && (!country->allow11na40)) + modesAvail &= ~REGDMN_MODE_11NA_HT40PLUS; + + if ((modesAvail & REGDMN_MODE_11NA_HT40MINUS) && + (!country->allow11na40)) + modesAvail &= ~REGDMN_MODE_11NA_HT40MINUS; + + if ((modesAvail & REGDMN_MODE_11AC_VHT20) && (!country->allow11na20)) + modesAvail &= ~REGDMN_MODE_11AC_VHT20; + + if ((modesAvail & REGDMN_MODE_11AC_VHT40PLUS) && + (!country->allow11na40)) + modesAvail &= ~REGDMN_MODE_11AC_VHT40PLUS; + + if ((modesAvail & REGDMN_MODE_11AC_VHT40MINUS) && + (!country->allow11na40)) + modesAvail &= ~REGDMN_MODE_11AC_VHT40MINUS; + + if ((modesAvail & REGDMN_MODE_11AC_VHT80) && (!country->allow11na80)) + modesAvail &= ~REGDMN_MODE_11AC_VHT80; + + if ((modesAvail & REGDMN_MODE_11AC_VHT20_2G) && (!country->allow11ng20)) + modesAvail &= ~REGDMN_MODE_11AC_VHT20_2G; + + return modesAvail; +} + +void cds_fill_send_ctl_info_to_fw(struct regulatory *reg, uint32_t modesAvail, + uint32_t modeSelect) +{ + const REG_DOMAIN *regdomain2G = NULL; + const REG_DOMAIN *regdomain5G = NULL; + int8_t ctl_2g, ctl_5g, ctl; + const REG_DOMAIN *rd = NULL; + const struct cmode *cm; + const COUNTRY_CODE_TO_ENUM_RD *country; + const REG_DMN_PAIR_MAPPING *regpair; + + regpair = reg->regpair; + regdomain2G = get_regdmn(regpair->regDmn2GHz); + if (!regdomain2G) { + cdf_print(KERN_ERR "Failed to get regdmn 2G"); + return; + } + + regdomain5G = get_regdmn(regpair->regDmn5GHz); + if (!regdomain5G) { + cdf_print(KERN_ERR "Failed to get regdmn 5G"); + return; + } + + /* find first nible of CTL */ + ctl_2g = regdomain2G->conformance_test_limit; + ctl_5g = regdomain5G->conformance_test_limit; + + /* find second nible of CTL */ + country = find_country(reg->country_code); + if (country != NULL) + modesAvail = + regdmn_getwmodesnreg(modesAvail, country, regdomain5G); + + for (cm = modes; cm < &modes[CDF_ARRAY_SIZE(modes)]; cm++) { + + if ((cm->mode & modeSelect) == 0) + continue; + + if ((cm->mode & modesAvail) == 0) + continue; + + switch (cm->mode) { + case REGDMN_MODE_TURBO: + rd = regdomain5G; + ctl = rd->conformance_test_limit | CTL_TURBO; + break; + case REGDMN_MODE_11A: + case REGDMN_MODE_11NA_HT20: + case REGDMN_MODE_11NA_HT40PLUS: + case REGDMN_MODE_11NA_HT40MINUS: + case REGDMN_MODE_11AC_VHT20: + case REGDMN_MODE_11AC_VHT40PLUS: + case REGDMN_MODE_11AC_VHT40MINUS: + case REGDMN_MODE_11AC_VHT80: + rd = regdomain5G; + ctl = rd->conformance_test_limit; + break; + case REGDMN_MODE_11B: + rd = regdomain2G; + ctl = rd->conformance_test_limit | CTL_11B; + break; + case REGDMN_MODE_11G: + case REGDMN_MODE_11NG_HT20: + case REGDMN_MODE_11NG_HT40PLUS: + case REGDMN_MODE_11NG_HT40MINUS: + case REGDMN_MODE_11AC_VHT20_2G: + case REGDMN_MODE_11AC_VHT40_2G: + case REGDMN_MODE_11AC_VHT80_2G: + rd = regdomain2G; + ctl = rd->conformance_test_limit | CTL_11G; + break; + case REGDMN_MODE_11G_TURBO: + rd = regdomain2G; + ctl = rd->conformance_test_limit | CTL_108G; + break; + case REGDMN_MODE_11A_TURBO: + rd = regdomain5G; + ctl = rd->conformance_test_limit | CTL_108G; + break; + default: + cdf_print(KERN_ERR "%s: Unkonwn HAL mode 0x%x\n", + __func__, cm->mode); + continue; + } + + if (rd == regdomain2G) + ctl_2g = ctl; + + if (rd == regdomain5G) + ctl_5g = ctl; + } + + /* save the ctl information for future reference */ + reg->ctl_5g = ctl_5g; + reg->ctl_2g = ctl_2g; + + wma_send_regdomain_info_to_fw(reg->reg_domain, regpair->regDmn2GHz, + regpair->regDmn5GHz, ctl_2g, ctl_5g); +} + +/* cds_set_wma_dfs_region() - to set the dfs region to wma + * + * @reg: the regulatory handle + * + * Return: none + */ +void cds_set_wma_dfs_region(struct regulatory *reg) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + + if (!wma) { + cdf_print(KERN_ERR "%s: Unable to get WMA handle", __func__); + return; + } + + cdf_print("%s: dfs_region: %d", __func__, reg->dfs_region); + wma_set_dfs_region(wma, reg->dfs_region); +} + +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + uint32_t modeSelect = 0xFFFFFFFF; + + if (!wma) { + WMA_LOGE("%s: Unable to get WMA handle", __func__); + return; + } + + wma_get_modeselect(wma, &modeSelect); + + cds_fill_send_ctl_info_to_fw(reg, wma->reg_cap.wireless_modes, + modeSelect); + return; +} + +/* get the ctl from regdomain */ +uint8_t cds_get_ctl_for_regdmn(uint32_t reg_dmn) +{ + uint8_t i; + uint8_t default_regdmn_ctl = FCC; + + if (reg_dmn == CTRY_DEFAULT) { + return default_regdmn_ctl; + } else { + for (i = 0; i < ol_regdmn_rdt.regDomainsCt; i++) { + if (ol_regdmn_rdt.regDomains[i].regDmnEnum == reg_dmn) + return ol_regdmn_rdt.regDomains[i]. + conformance_test_limit; + } + } + return -1; +} + +/* + * Get the 5G reg domain value for reg doamin + */ +uint16_t cds_get_regdmn_5g(uint32_t reg_dmn) +{ + uint16_t i; + + for (i = 0; i < ol_regdmn_rdt.regDomainPairsCt; i++) { + if (ol_regdmn_rdt.regDomainPairs[i].regDmnEnum == reg_dmn) { + return ol_regdmn_rdt.regDomainPairs[i].regDmn5GHz; + } + } + cdf_print("%s: invalid regulatory domain/country code 0x%x\n", + __func__, reg_dmn); + return 0; +} + +/* + * Get operating class for a given channel + */ +uint16_t cds_regdm_get_opclass_from_channel(uint8_t *country, uint8_t channel, + uint8_t offset) +{ + regdm_op_class_map_t *class = NULL; + uint16_t i = 0; + + if (true == cdf_mem_compare(country, "US", 2)) { + class = us_op_class; + } else if (true == cdf_mem_compare(country, "EU", 2)) { + class = euro_op_class; + } else if (true == cdf_mem_compare(country, "JP", 2)) { + class = japan_op_class; + } else { + class = global_op_class; + } + + while (class->op_class) { + if ((offset == class->offset) || (offset == BWALL)) { + for (i = 0; + (i < MAX_CHANNELS_PER_OPERATING_CLASS && + class->channels[i]); i++) { + if (channel == class->channels[i]) + return class->op_class; + } + } + class++; + } + return 0; +} + +/* + * Set current operating classes per country, regdomain + */ +uint16_t cds_regdm_set_curr_opclasses(uint8_t num_classes, uint8_t *class) +{ + uint8_t i; + + if (SIR_MAC_MAX_SUPP_OPER_CLASSES < num_classes) { + cdf_print(KERN_ERR "%s: Invalid numClasses (%d)\n", + __func__, num_classes); + return -1; + } + + for (i = 0; i < num_classes; i++) { + regdm_curr_supp_opp_classes.classes[i] = class[i]; + } + regdm_curr_supp_opp_classes.num_classes = num_classes; + + return 0; +} + +/* + * Get current operating classes + */ +uint16_t cds_regdm_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) +{ + uint8_t i; + + if (!num_classes || !class) { + cdf_print(KERN_ERR "%s: Either num_classes or class is null\n", + __func__); + return -1; + } + + for (i = 0; i < regdm_curr_supp_opp_classes.num_classes; i++) { + class[i] = regdm_curr_supp_opp_classes.classes[i]; + } + + *num_classes = regdm_curr_supp_opp_classes.num_classes; + + return 0; +} diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c new file mode 100644 index 0000000000..07c8df060a --- /dev/null +++ b/core/cds/src/cds_sched.c @@ -0,0 +1,1270 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * File: cds_sched.c + * + * DOC: CDS Scheduler Implementation + */ + + /* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "cds_sched.h" +#include +#include "wma_types.h" +#include +#include +#include +#if defined(QCA_CONFIG_SMP) && defined(CONFIG_CNSS) +#include +#endif +/* Preprocessor Definitions and Constants */ +#define CDS_SCHED_THREAD_HEART_BEAT INFINITE +/* Milli seconds to delay SSR thread when an Entry point is Active */ +#define SSR_WAIT_SLEEP_TIME 200 +/* MAX iteration count to wait for Entry point to exit before + * we proceed with SSR in WD Thread + */ +#define MAX_SSR_WAIT_ITERATIONS 200 +#define MAX_SSR_PROTECT_LOG (16) + +static atomic_t ssr_protect_entry_count; + +/** + * struct ssr_protect - sub system restart(ssr) protection tracking table + * @func: Function which needs ssr protection + * @free: Flag to tell whether entry is free in table or not + * @pid: Process id which needs ssr protection + */ +struct ssr_protect { + const char *func; + bool free; + uint32_t pid; +}; + +static spinlock_t ssr_protect_lock; +static struct ssr_protect ssr_protect_log[MAX_SSR_PROTECT_LOG]; + +static p_cds_sched_context gp_cds_sched_context; + +static int cds_mc_thread(void *Arg); +#ifdef QCA_CONFIG_SMP +static int cds_ol_rx_thread(void *arg); +static unsigned long affine_cpu; +static CDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); +#endif + +#ifdef QCA_CONFIG_SMP +#define CDS_CORE_PER_CLUSTER (4) +static int cds_set_cpus_allowed_ptr(struct task_struct *task, unsigned long cpu) +{ +#ifdef WLAN_OPEN_SOURCE + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +#elif defined(CONFIG_CNSS) + return cnss_set_cpus_allowed_ptr(task, cpu); +#else + return 0; +#endif +} + +/** + * cds_cpu_hotplug_notify() - hot plug notify + * @block: Pointer to block + * @state: State + * @hcpu: Pointer to hotplug cpu + * + * Return: NOTIFY_OK + */ +static int +cds_cpu_hotplug_notify(struct notifier_block *block, + unsigned long state, void *hcpu) +{ + unsigned long cpu = (unsigned long)hcpu; + unsigned long pref_cpu = 0; + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + int i; + unsigned int multi_cluster; + unsigned int num_cpus; + + if ((NULL == pSchedContext) || (NULL == pSchedContext->ol_rx_thread)) + return NOTIFY_OK; + + if (cds_is_load_unload_in_progress()) + return NOTIFY_OK; + + num_cpus = num_possible_cpus(); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_LOW, + "%s: RX CORE %d, STATE %d, NUM CPUS %d", + __func__, (int)affine_cpu, (int)state, num_cpus); + multi_cluster = (num_cpus > CDS_CORE_PER_CLUSTER) ? 1 : 0; + + switch (state) { + case CPU_ONLINE: + if ((!multi_cluster) && (affine_cpu != 0)) + return NOTIFY_OK; + + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + if (!multi_cluster) + break; + } + break; + case CPU_DEAD: + if (cpu != affine_cpu) + return NOTIFY_OK; + + affine_cpu = 0; + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + if (!multi_cluster) + break; + } + } + + if (pref_cpu == 0) + return NOTIFY_OK; + + if (!cds_set_cpus_allowed_ptr(pSchedContext->ol_rx_thread, pref_cpu)) + affine_cpu = pref_cpu; + + return NOTIFY_OK; +} + +static struct notifier_block cds_cpu_hotplug_notifier = { + .notifier_call = cds_cpu_hotplug_notify, +}; +#endif + +/** + * cds_sched_open() - initialize the CDS Scheduler + * @p_cds_context: Pointer to the global CDS Context + * @pSchedContext: Pointer to a previously allocated buffer big + * enough to hold a scheduler context. + * @SchedCtxSize: CDS scheduler context size + * + * This function initializes the CDS Scheduler + * Upon successful initialization: + * - All the message queues are initialized + * - The Main Controller thread is created and ready to receive and + * dispatch messages. + * + * + * Return: CDF status + */ +CDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedContext, + uint32_t SchedCtxSize) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening the CDS Scheduler", __func__); + /* Sanity checks */ + if ((p_cds_context == NULL) || (pSchedContext == NULL)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return CDF_STATUS_E_FAILURE; + } + if (sizeof(cds_sched_context) != SchedCtxSize) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Incorrect CDS Sched Context size passed", + __func__); + return CDF_STATUS_E_INVAL; + } + cdf_mem_zero(pSchedContext, sizeof(cds_sched_context)); + pSchedContext->pVContext = p_cds_context; + vStatus = cds_sched_init_mqs(pSchedContext); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to initialize CDS Scheduler MQs", + __func__); + return vStatus; + } + /* Initialize the helper events and event queues */ + init_completion(&pSchedContext->McStartEvent); + init_completion(&pSchedContext->McShutdown); + init_completion(&pSchedContext->ResumeMcEvent); + + spin_lock_init(&pSchedContext->McThreadLock); +#ifdef QCA_CONFIG_SMP + spin_lock_init(&pSchedContext->ol_rx_thread_lock); +#endif + + init_waitqueue_head(&pSchedContext->mcWaitQueue); + pSchedContext->mcEventFlag = 0; + +#ifdef QCA_CONFIG_SMP + init_waitqueue_head(&pSchedContext->ol_rx_wait_queue); + init_completion(&pSchedContext->ol_rx_start_event); + init_completion(&pSchedContext->ol_suspend_rx_event); + init_completion(&pSchedContext->ol_resume_rx_event); + init_completion(&pSchedContext->ol_rx_shutdown); + pSchedContext->ol_rx_event_flag = 0; + spin_lock_init(&pSchedContext->ol_rx_queue_lock); + spin_lock_init(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->ol_rx_thread_queue); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (cds_alloc_ol_rx_pkt_freeq(pSchedContext) != CDF_STATUS_SUCCESS) { + return CDF_STATUS_E_FAILURE; + } + register_hotcpu_notifier(&cds_cpu_hotplug_notifier); + pSchedContext->cpu_hot_plug_notifier = &cds_cpu_hotplug_notifier; +#endif + gp_cds_sched_context = pSchedContext; + + /* Create the CDS Main Controller thread */ + pSchedContext->McThread = kthread_create(cds_mc_thread, pSchedContext, + "cds_mc_thread"); + if (IS_ERR(pSchedContext->McThread)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Could not Create CDS Main Thread Controller", + __func__); + goto MC_THREAD_START_FAILURE; + } + wake_up_process(pSchedContext->McThread); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS Main Controller thread Created", __func__); + +#ifdef QCA_CONFIG_SMP + pSchedContext->ol_rx_thread = kthread_create(cds_ol_rx_thread, + pSchedContext, + "cds_ol_rx_thread"); + if (IS_ERR(pSchedContext->ol_rx_thread)) { + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Could not Create CDS OL RX Thread", + __func__); + goto OL_RX_THREAD_START_FAILURE; + + } + wake_up_process(pSchedContext->ol_rx_thread); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + ("CDS OL RX thread Created")); +#endif + /* + * Now make sure all threads have started before we exit. + * Each thread should normally ACK back when it starts. + */ + wait_for_completion_interruptible(&pSchedContext->McStartEvent); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS MC Thread has started", __func__); +#ifdef QCA_CONFIG_SMP + wait_for_completion_interruptible(&pSchedContext->ol_rx_start_event); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS OL Rx Thread has started", __func__); +#endif + /* We're good now: Let's get the ball rolling!!! */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS Scheduler successfully Opened", __func__); + return CDF_STATUS_SUCCESS; + +#ifdef QCA_CONFIG_SMP +OL_RX_THREAD_START_FAILURE: + /* Try and force the Main thread controller to exit */ + set_bit(MC_SHUTDOWN_EVENT_MASK, &pSchedContext->mcEventFlag); + set_bit(MC_POST_EVENT_MASK, &pSchedContext->mcEventFlag); + wake_up_interruptible(&pSchedContext->mcWaitQueue); + /* Wait for MC to exit */ + wait_for_completion_interruptible(&pSchedContext->McShutdown); +#endif + +MC_THREAD_START_FAILURE: + /* De-initialize all the message queues */ + cds_sched_deinit_mqs(pSchedContext); + +#ifdef QCA_CONFIG_SMP + unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); +#endif + + return CDF_STATUS_E_RESOURCES; + +} /* cds_sched_open() */ + +/** + * cds_mc_thread() - cds main controller thread execution handler + * @Arg: Pointer to the global CDS Sched Context + * + * Return: thread exit code + */ +static int cds_mc_thread(void *Arg) +{ + p_cds_sched_context pSchedContext = (p_cds_sched_context) Arg; + p_cds_msg_wrapper pMsgWrapper = NULL; + tpAniSirGlobal pMacContext = NULL; + tSirRetStatus macStatus = eSIR_SUCCESS; + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + int retWaitStatus = 0; + bool shutdown = false; + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t p_cds_context = NULL; + + if (Arg == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Bad Args passed", __func__); + return 0; + } + set_user_nice(current, -2); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + daemonize("MC_Thread"); +#endif + + /* Ack back to the context from which the main controller thread + * has been created + */ + complete(&pSchedContext->McStartEvent); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: MC Thread %d (%s) starting up", __func__, current->pid, + current->comm); + + /* Get the Global CDS Context */ + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Global CDS context is Null", + __func__); + return 0; + } + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD context is Null", + __func__); + return 0; + } + + while (!shutdown) { + /* This implements the execution model algorithm */ + retWaitStatus = + wait_event_interruptible(pSchedContext->mcWaitQueue, + test_bit(MC_POST_EVENT_MASK, + &pSchedContext->mcEventFlag) + || test_bit(MC_SUSPEND_EVENT_MASK, + &pSchedContext->mcEventFlag)); + + if (retWaitStatus == -ERESTARTSYS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: wait_event_interruptible returned -ERESTARTSYS", + __func__); + CDF_BUG(0); + } + clear_bit(MC_POST_EVENT_MASK, &pSchedContext->mcEventFlag); + + while (1) { + /* Check if MC needs to shutdown */ + if (test_bit + (MC_SHUTDOWN_EVENT_MASK, + &pSchedContext->mcEventFlag)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: MC thread signaled to shutdown", + __func__); + shutdown = true; + /* Check for any Suspend Indication */ + if (test_bit + (MC_SUSPEND_EVENT_MASK, + &pSchedContext->mcEventFlag)) { + clear_bit(MC_SUSPEND_EVENT_MASK, + &pSchedContext->mcEventFlag); + + /* Unblock anyone waiting on suspend */ + complete(&pHddCtx->mc_sus_event_var); + } + break; + } + /* Check the SYS queue first */ + if (!cds_is_mq_empty(&pSchedContext->sysMcMq)) { + /* Service the SYS message queue */ + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Servicing the CDS SYS MC Message queue", + __func__); + pMsgWrapper = + cds_mq_get(&pSchedContext->sysMcMq); + if (pMsgWrapper == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + CDF_ASSERT(0); + break; + } + vStatus = + sys_mc_process_msg(pSchedContext->pVContext, + pMsgWrapper->pVosMsg); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing SYS message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check the WMA queue */ + if (!cds_is_mq_empty(&pSchedContext->wmaMcMq)) { + /* Service the WMA message queue */ + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Servicing the CDS WMA MC Message queue", + __func__); + pMsgWrapper = + cds_mq_get(&pSchedContext->wmaMcMq); + if (pMsgWrapper == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + CDF_ASSERT(0); + break; + } + vStatus = + wma_mc_process_msg(pSchedContext->pVContext, + pMsgWrapper->pVosMsg); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing WMA message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check the PE queue */ + if (!cds_is_mq_empty(&pSchedContext->peMcMq)) { + /* Service the PE message queue */ + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Servicing the CDS PE MC Message queue", + __func__); + pMsgWrapper = + cds_mq_get(&pSchedContext->peMcMq); + if (NULL == pMsgWrapper) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + CDF_ASSERT(0); + break; + } + + /* Need some optimization */ + pMacContext = + cds_get_context(CDF_MODULE_ID_PE); + if (NULL == pMacContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "MAC Context not ready yet"); + cds_core_return_msg + (pSchedContext->pVContext, + pMsgWrapper); + continue; + } + + macStatus = + pe_process_messages(pMacContext, + (tSirMsgQ *) + pMsgWrapper->pVosMsg); + if (eSIR_SUCCESS != macStatus) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing PE message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /** Check the SME queue **/ + if (!cds_is_mq_empty(&pSchedContext->smeMcMq)) { + /* Service the SME message queue */ + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Servicing the CDS SME MC Message queue", + __func__); + pMsgWrapper = + cds_mq_get(&pSchedContext->smeMcMq); + if (NULL == pMsgWrapper) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + CDF_ASSERT(0); + break; + } + + /* Need some optimization */ + pMacContext = + cds_get_context(CDF_MODULE_ID_SME); + if (NULL == pMacContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "MAC Context not ready yet"); + cds_core_return_msg + (pSchedContext->pVContext, + pMsgWrapper); + continue; + } + + vStatus = + sme_process_msg((tHalHandle) pMacContext, + pMsgWrapper->pVosMsg); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing SME message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check for any Suspend Indication */ + if (test_bit + (MC_SUSPEND_EVENT_MASK, + &pSchedContext->mcEventFlag)) { + clear_bit(MC_SUSPEND_EVENT_MASK, + &pSchedContext->mcEventFlag); + spin_lock(&pSchedContext->McThreadLock); + + /* Mc Thread Suspended */ + complete(&pHddCtx->mc_sus_event_var); + + INIT_COMPLETION(pSchedContext->ResumeMcEvent); + spin_unlock(&pSchedContext->McThreadLock); + + /* Wait foe Resume Indication */ + wait_for_completion_interruptible + (&pSchedContext->ResumeMcEvent); + } + break; /* All queues are empty now */ + } /* while message loop processing */ + } /* while true */ + /* If we get here the MC thread must exit */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: MC Thread exiting!!!!", __func__); + complete_and_exit(&pSchedContext->McShutdown, 0); +} /* cds_mc_thread() */ + +#ifdef QCA_CONFIG_SMP +/** + * cds_free_ol_rx_pkt_freeq() - free cds buffer free queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API does mem free of the buffers available in free cds buffer + * queue which is used for Data rx processing. + * + * Return: none + */ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt, *tmp; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_rx_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + cdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_rx_pkt_freeq() - Function to allocate free buffer queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API allocates CDS_MAX_OL_RX_PKT number of cds message buffers + * which are used for Rx data processing. + * + * Return: status of memory allocation + */ +static CDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt, *tmp; + int i; + + for (i = 0; i < CDS_MAX_OL_RX_PKT; i++) { + pkt = cdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s Vos packet allocation for ol rx thread failed", + __func__); + goto free; + } + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + + return CDF_STATUS_SUCCESS; + +free: + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_rx_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + cdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return CDF_STATUS_E_NOMEM; +} + +/** + * cds_free_ol_rx_pkt() - api to release cds message to the freeq + * This api returns the cds message used for Rx data to the free queue + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * Return: none + */ +void +cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_rx_pkt() - API to return next available cds message + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api returns next available cds message buffer used for rx data + * processing + * + * Return: Pointer to cds message buffer + */ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) { + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return NULL; + } + pkt = list_first_entry(&pSchedContext->cds_ol_rx_pkt_freeq, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return pkt; +} + +/** + * cds_indicate_rxpkt() - indicate rx data packet + * @Arg: Pointer to the global CDS Sched Context + * @pkt: CDS data message buffer + * + * This api enqueues the rx packet into ol_rx_thread_queue and notifies + * cds_ol_rx_thread() + * + * Return: none + */ +void +cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + list_add_tail(&pkt->list, &pSchedContext->ol_rx_thread_queue); + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + set_bit(RX_POST_EVENT_MASK, &pSchedContext->ol_rx_event_flag); + wake_up_interruptible(&pSchedContext->ol_rx_wait_queue); +} + +/** + * cds_drop_rxpkt_by_staid() - api to drop pending rx packets for a sta + * @pSchedContext: Pointer to the global CDS Sched Context + * @staId: Station Id + * + * This api drops queued packets for a station, to drop all the pending + * packets the caller has to send WLAN_MAX_STA_COUNT as staId. + * + * Return: none + */ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ + struct list_head local_list; + struct cds_ol_rx_pkt *pkt, *tmp; + cdf_nbuf_t buf, next_buf; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + if (list_empty(&pSchedContext->ol_rx_thread_queue)) { + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, &pSchedContext->ol_rx_thread_queue, + list) { + if (pkt->staId == staId || staId == WLAN_MAX_STA_COUNT) + list_move_tail(&pkt->list, &local_list); + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + + list_for_each_entry(pkt, &local_list, list) { + list_del(&pkt->list); + buf = pkt->Rxpkt; + while (buf) { + next_buf = cdf_nbuf_queue_next(buf); + cdf_nbuf_free(buf); + buf = next_buf; + } + cds_free_ol_rx_pkt(pSchedContext, pkt); + } +} + +/** + * cds_rx_from_queue() - function to process pending Rx packets + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api traverses the pending buffer list and calling the callback. + * This callback would essentially send the packet to HDD. + * + * Return: none + */ +static void cds_rx_from_queue(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + uint16_t sta_id; + + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + while (!list_empty(&pSchedContext->ol_rx_thread_queue)) { + pkt = list_first_entry(&pSchedContext->ol_rx_thread_queue, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + sta_id = pkt->staId; + pkt->callback(pkt->context, pkt->Rxpkt, sta_id); + cds_free_ol_rx_pkt(pSchedContext, pkt); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); +} + +/** + * cds_ol_rx_thread() - cds main tlshim rx thread + * @Arg: pointer to the global CDS Sched Context + * + * This api is the thread handler for Tlshim Data packet processing. + * + * Return: thread exit code + */ +static int cds_ol_rx_thread(void *arg) +{ + p_cds_sched_context pSchedContext = (p_cds_sched_context) arg; + unsigned long pref_cpu = 0; + bool shutdown = false; + int status, i; + unsigned int num_cpus; + + set_user_nice(current, -1); +#ifdef MSM_PLATFORM + set_wake_up_idle(true); +#endif + + num_cpus = num_possible_cpus(); + /* Find the available cpu core other than cpu 0 and + * bind the thread + */ + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + if (num_cpus <= CDS_CORE_PER_CLUSTER) + break; + } + if (pref_cpu != 0 && (!cds_set_cpus_allowed_ptr(current, pref_cpu))) + affine_cpu = pref_cpu; + + if (!arg) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Bad Args passed", __func__); + return 0; + } + + complete(&pSchedContext->ol_rx_start_event); + + while (!shutdown) { + status = + wait_event_interruptible(pSchedContext->ol_rx_wait_queue, + test_bit(RX_POST_EVENT_MASK, + &pSchedContext->ol_rx_event_flag) + || test_bit(RX_SUSPEND_EVENT_MASK, + &pSchedContext->ol_rx_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(RX_POST_EVENT_MASK, &pSchedContext->ol_rx_event_flag); + while (true) { + if (test_bit(RX_SHUTDOWN_EVENT_MASK, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SHUTDOWN_EVENT_MASK, + &pSchedContext->ol_rx_event_flag); + if (test_bit(RX_SUSPEND_EVENT_MASK, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT_MASK, + &pSchedContext->ol_rx_event_flag); + complete + (&pSchedContext->ol_suspend_rx_event); + } + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Shutting down OL RX Thread", + __func__); + shutdown = true; + break; + } + cds_rx_from_queue(pSchedContext); + + if (test_bit(RX_SUSPEND_EVENT_MASK, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT_MASK, + &pSchedContext->ol_rx_event_flag); + spin_lock(&pSchedContext->ol_rx_thread_lock); + complete(&pSchedContext->ol_suspend_rx_event); + INIT_COMPLETION + (pSchedContext->ol_resume_rx_event); + spin_unlock(&pSchedContext->ol_rx_thread_lock); + wait_for_completion_interruptible + (&pSchedContext->ol_resume_rx_event); + } + break; + } + } + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Exiting CDS OL rx thread", __func__); + complete_and_exit(&pSchedContext->ol_rx_shutdown, 0); +} +#endif + +/** + * cds_sched_close() - close the cds scheduler + * @p_cds_context: Pointer to the global CDS Context + * + * This api closes the CDS Scheduler upon successful closing: + * - All the message queues are flushed + * - The Main Controller thread is closed + * - The Tx thread is closed + * + * + * Return: cdf status + */ +CDF_STATUS cds_sched_close(void *p_cds_context) +{ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: invoked", __func__); + if (gp_cds_sched_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_sched_context == NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + /* shut down MC Thread */ + set_bit(MC_SHUTDOWN_EVENT_MASK, &gp_cds_sched_context->mcEventFlag); + set_bit(MC_POST_EVENT_MASK, &gp_cds_sched_context->mcEventFlag); + wake_up_interruptible(&gp_cds_sched_context->mcWaitQueue); + /* Wait for MC to exit */ + wait_for_completion(&gp_cds_sched_context->McShutdown); + gp_cds_sched_context->McThread = 0; + + /* Clean up message queues of MC thread */ + cds_sched_flush_mc_mqs(gp_cds_sched_context); + + /* Deinit all the queues */ + cds_sched_deinit_mqs(gp_cds_sched_context); + +#ifdef QCA_CONFIG_SMP + /* Shut down Tlshim Rx thread */ + set_bit(RX_SHUTDOWN_EVENT_MASK, &gp_cds_sched_context->ol_rx_event_flag); + set_bit(RX_POST_EVENT_MASK, &gp_cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&gp_cds_sched_context->ol_rx_wait_queue); + wait_for_completion_interruptible + (&gp_cds_sched_context->ol_rx_shutdown); + gp_cds_sched_context->ol_rx_thread = NULL; + cds_drop_rxpkt_by_staid(gp_cds_sched_context, WLAN_MAX_STA_COUNT); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); + unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier); +#endif + return CDF_STATUS_SUCCESS; +} /* cds_sched_close() */ + +/** + * cds_sched_init_mqs() - initialize the cds scheduler message queues + * @p_cds_sched_context: Pointer to the Scheduler Context. + * + * This api initializes the cds scheduler message queues. + * + * Return: CDF status + */ +CDF_STATUS cds_sched_init_mqs(p_cds_sched_context pSchedContext) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + /* Now intialize all the message queues */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the WMA MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->wmaMcMq); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to init WMA MC Message queue", __func__); + CDF_ASSERT(0); + return vStatus; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the PE MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->peMcMq); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to init PE MC Message queue", __func__); + CDF_ASSERT(0); + return vStatus; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the SME MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->smeMcMq); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to init SME MC Message queue", __func__); + CDF_ASSERT(0); + return vStatus; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the SYS MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->sysMcMq); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to init SYS MC Message queue", __func__); + CDF_ASSERT(0); + return vStatus; + } + + return CDF_STATUS_SUCCESS; +} /* cds_sched_init_mqs() */ + +/** + * cds_sched_deinit_mqs() - Deinitialize the cds scheduler message queues + * @p_cds_sched_context: Pointer to the Scheduler Context. + * + * Return: none + */ +void cds_sched_deinit_mqs(p_cds_sched_context pSchedContext) +{ + /* Now de-intialize all message queues */ + + /* MC WMA */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the WMA MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->wmaMcMq); + /* MC PE */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the PE MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->peMcMq); + /* MC SME */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the SME MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->smeMcMq); + /* MC SYS */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the SYS MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->sysMcMq); + +} /* cds_sched_deinit_mqs() */ + +/** + * cds_sched_flush_mc_mqs() - flush all the MC thread message queues + * @pSchedContext: Pointer to global cds context + * + * Return: none + */ +void cds_sched_flush_mc_mqs(p_cds_sched_context pSchedContext) +{ + p_cds_msg_wrapper pMsgWrapper = NULL; + p_cds_contextType cds_ctx; + + /* Here each of the MC thread MQ shall be drained and returned to the + * Core. Before returning a wrapper to the Core, the CDS message shall + * be freed first + */ + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + ("Flushing the MC Thread message queue")); + + if (NULL == pSchedContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: pSchedContext is NULL", __func__); + return; + } + + cds_ctx = (p_cds_contextType) (pSchedContext->pVContext); + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: cds_ctx is NULL", __func__); + return; + } + + /* Flush the SYS Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->sysMcMq))) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Freeing MC SYS message type %d ", __func__, + pMsgWrapper->pVosMsg->type); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + /* Flush the WMA Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->wmaMcMq))) { + if (pMsgWrapper->pVosMsg != NULL) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Freeing MC WMA MSG message type %d", + __func__, pMsgWrapper->pVosMsg->type); + if (pMsgWrapper->pVosMsg->bodyptr) { + cdf_mem_free((void *)pMsgWrapper-> + pVosMsg->bodyptr); + } + + pMsgWrapper->pVosMsg->bodyptr = NULL; + pMsgWrapper->pVosMsg->bodyval = 0; + pMsgWrapper->pVosMsg->type = 0; + } + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + + /* Flush the PE Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->peMcMq))) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Freeing MC PE MSG message type %d", __func__, + pMsgWrapper->pVosMsg->type); + pe_free_msg(cds_ctx->pMACContext, + (tSirMsgQ *) pMsgWrapper->pVosMsg); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + /* Flush the SME Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->smeMcMq))) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_INFO, + "%s: Freeing MC SME MSG message type %d", __func__, + pMsgWrapper->pVosMsg->type); + sme_free_msg(cds_ctx->pMACContext, pMsgWrapper->pVosMsg); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } +} /* cds_sched_flush_mc_mqs() */ + +/** + * get_cds_sched_ctxt() - get cds scheduler context + * + * Return: none + */ +p_cds_sched_context get_cds_sched_ctxt(void) +{ + /* Make sure that Vos Scheduler context has been initialized */ + if (gp_cds_sched_context == NULL) + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_sched_context == NULL", __func__); + + return gp_cds_sched_context; +} + +/** + * cds_ssr_protect_init() - initialize ssr protection debug functionality + * + * Return: + * void + */ +void cds_ssr_protect_init(void) +{ + int i = 0; + + spin_lock_init(&ssr_protect_lock); + + while (i < MAX_SSR_PROTECT_LOG) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + i++; + } +} + +/** + * cds_print_external_threads() - print external threads stuck in driver + * + * Return: + * void + */ + +static void cds_print_external_threads(void) +{ + int i = 0; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "PID %d is stuck at %s", ssr_protect_log[i].pid, + ssr_protect_log[i].func); + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +/** + * cds_ssr_protect() - start ssr protection + * @caller_func: name of calling function. + * + * This function is called to keep track of active driver entry points + * + * Return: none + */ +void cds_ssr_protect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_inc_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (ssr_protect_log[i].free) { + ssr_protect_log[i].func = caller_func; + ssr_protect_log[i].free = false; + ssr_protect_log[i].pid = current->pid; + status = true; + break; + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + if (!status) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Could not track PID %d call %s: log is full", + current->pid, caller_func); +} + +/** + * cds_ssr_unprotect() - stop ssr protection + * @caller_func: name of calling function. + * + * Return: none + */ +void cds_ssr_unprotect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_dec_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + if ((ssr_protect_log[i].pid == current->pid) && + !strcmp(ssr_protect_log[i].func, caller_func)) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + status = true; + break; + } + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + if (!status) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Untracked call %s", caller_func); +} + +/** + * cds_is_ssr_ready() - check if the calling execution can proceed with ssr + * + * @caller_func: name of calling function. + * + * Return: true if there is no active entry points in driver + * false if there is at least one active entry in driver + */ +bool cds_is_ssr_ready(const char *caller_func) +{ + int count = MAX_SSR_WAIT_ITERATIONS; + + while (count) { + + if (!atomic_read(&ssr_protect_entry_count)) + break; + + if (--count) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Waiting for active entry points to exit", + __func__); + msleep(SSR_WAIT_SLEEP_TIME); + } + } + /* at least one external thread is executing */ + if (!count) { + cds_print_external_threads(); + return false; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "Allowing SSR for %s", caller_func); + + return true; +} diff --git a/core/cds/src/cds_utils.c b/core/cds/src/cds_utils.c new file mode 100644 index 0000000000..fd186ae6bb --- /dev/null +++ b/core/cds/src/cds_utils.c @@ -0,0 +1,1135 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: cds_utils.c + + OVERVIEW: This source file contains definitions for CDS crypto APIs + The four APIs mentioned in this file are used for + initializing, and de-initializing a crypto context, and + obtaining truly random data (for keys), as well as + SHA1 HMAC, and AES encrypt and decrypt routines. + + The routines include: + cds_crypto_init() - Initializes Crypto module + cds_crypto_deinit() - De-initializes Crypto module + cds_rand_get_bytes() - Generates random byte + cds_sha1_hmac_str() - Generate the HMAC-SHA1 of a string given a key + cds_encrypt_aes() - Generate AES Encrypted byte stream + cds_decrypt_aes() - Decrypts an AES Encrypted byte stream + + DEPENDENCIES: + ============================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ + +#include "cdf_trace.h" +#include "cds_utils.h" +#include "cdf_memory.h" +#include "cds_crypto.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_ieee80211_common.h" +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define AAD_LEN 20 +#define IV_SIZE_AES_128 16 +#define CMAC_IPN_LEN 6 +#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Function Definitions and Documentation + * -------------------------------------------------------------------------*/ +#ifdef CONFIG_ICNSS +#ifdef WLAN_FEATURE_11W +static inline void xor_128(const u8 *a, const u8 *b, u8 *out) +{ + u8 i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) + out[i] = a[i] ^ b[i]; +} + +static inline void leftshift_onebit(const u8 *input, u8 *output) +{ + int i, overflow = 0; + + for (i = (AES_BLOCK_SIZE - 1); i >= 0; i--) { + output[i] = input[i] << 1; + output[i] |= overflow; + overflow = (input[i] & 0x80) ? 1 : 0; + } + return; +} + +static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) +{ + u8 l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 const_rb[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 + }; + u8 const_zero[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + crypto_cipher_encrypt_one(tfm, l, const_zero); + + if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */ + leftshift_onebit(l, k1); + } else { /* Else k1 = ( l << 1 ) (+) Rb */ + leftshift_onebit(l, tmp); + xor_128(tmp, const_rb, k1); + } + + if ((k1[0] & 0x80) == 0) { + leftshift_onebit(k1, k2); + } else { + leftshift_onebit(k1, tmp); + xor_128(tmp, const_rb, k2); + } +} + +static inline void padding(u8 *lastb, u8 *pad, u16 length) +{ + u8 j; + + /* original last block */ + for (j = 0; j < AES_BLOCK_SIZE; j++) { + if (j < length) + pad[j] = lastb[j]; + else if (j == length) + pad[j] = 0x80; + else + pad[j] = 0x00; + } +} + +static void cds_cmac_calc_mic(struct crypto_cipher *tfm, + u8 *m, u16 length, u8 *mac) +{ + u8 x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE]; + u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; + u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; + int cmpBlk; + int i, nBlocks = (length + 15) / AES_BLOCK_SIZE; + + generate_subkey(tfm, k1, k2); + + if (nBlocks == 0) { + nBlocks = 1; + cmpBlk = 0; + } else { + cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; + } + + if (cmpBlk) { /* Last block is complete block */ + xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); + } else { /* Last block is not complete block */ + padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, + length % AES_BLOCK_SIZE); + xor_128(padded, k2, m_last); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + x[i] = 0; + + for (i = 0; i < (nBlocks - 1); i++) { + xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ + crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ + } + + xor_128(x, m_last, y); + crypto_cipher_encrypt_one(tfm, x, y); + + memcpy(mac, x, CMAC_TLEN); +} +#endif +#endif + +/*-------------------------------------------------------------------------- + + \brief cds_crypto_init() - Initializes Crypto module + + The cds_crypto_init() function initializes Crypto module. + + \param phCryptProv - pointer to the Crypt handle + + \return CDF_STATUS_SUCCESS - Successfully generated random memory. + + CDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + CDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***CDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +CDF_STATUS cds_crypto_init(uint32_t *phCryptProv) +{ + CDF_STATUS uResult = CDF_STATUS_E_FAILURE; + + /* This implementation doesn't require a crypto context */ + *phCryptProv = 0; + uResult = CDF_STATUS_SUCCESS; + return (uResult); +} + +CDF_STATUS cds_crypto_deinit(uint32_t hCryptProv) +{ + CDF_STATUS uResult = CDF_STATUS_E_FAILURE; + + /* CryptReleaseContext succeeded */ + uResult = CDF_STATUS_SUCCESS; + + return (uResult); +} + +/*-------------------------------------------------------------------------- + + \brief cds_rand_get_bytes() - Generates random byte + + The cds_rand_get_bytes() function generate random bytes. + + Buffer should be allocated before calling cds_rand_get_bytes(). + + Attempting to initialize an already initialized lock results in + a failure. + + \param lock - pointer to the opaque lock object to initialize + + \return CDF_STATUS_SUCCESS - Successfully generated random memory. + + CDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + CDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***CDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +CDF_STATUS +cds_rand_get_bytes(uint32_t cryptHandle, uint8_t *pbBuf, uint32_t numBytes) +{ + CDF_STATUS uResult = CDF_STATUS_E_FAILURE; + + /* check for invalid pointer */ + if (NULL == pbBuf) { + uResult = CDF_STATUS_E_FAULT; + return (uResult); + } + + get_random_bytes(pbBuf, numBytes); + /* "Random sequence generated." */ + uResult = CDF_STATUS_SUCCESS; + return (uResult); +} + +#ifdef WLAN_FEATURE_11W +uint8_t cds_get_mmie_size() +{ + return sizeof(struct ieee80211_mmie); +} + +/*-------------------------------------------------------------------------- + + \brief cds_increase_seq() - Increase the IPN aka Sequence number by one unit + + The cds_increase_seq() function increases the IPN by one unit. + + \param ipn - pointer to the IPN aka Sequence number [6 bytes] + + --------------------------------------------------------------------------*/ +static void cds_increase_seq(uint8_t *ipn) +{ + uint64_t value = 0; + if (ipn) { + value = (0xffffffffffff) & (*((uint64_t *) ipn)); + value = value + 1; + cdf_mem_copy(ipn, &value, IEEE80211_MMIE_IPNLEN); + } +} + +/*-------------------------------------------------------------------------- + + \brief cds_attach_mmie() - attches the complete MMIE at the end of frame + + The cds_attach_mmie() calculates the entire MMIE and attaches at the end + of Broadcast/Multicast robust management frames. + + \param igtk - pointer group key which will be used to calculate + the 8 byte MIC. + \param ipn - pointer ipn, it is also known as sequence number + \param key_id - key identication number + \param frm - pointer to the start of the frame. + \param efrm - pointer to the end of the frame. + \param frmLen - size of the entire frame. + + \return - this function will return true on success and false on + failure. + + --------------------------------------------------------------------------*/ + +bool +cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t aad[AAD_LEN], mic[CMAC_TLEN], *input = NULL; + uint8_t previous_ipn[IEEE80211_MMIE_IPNLEN] = { 0 }; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* This is how received frame look like + * + * <------------frmLen----------------------------> + * + * +---------------+----------------------+-------+ + * | 802.11 HEADER | Management framebody | MMIE | + * +---------------+----------------------+-------+ + * ^ + * | + * efrm + * This is how MMIE from above frame look like + * + * + * <------------ 18 Bytes-----------------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * Octet 1 1 2 6 8 + * + */ + + /* Check if frame is invalid length */ + if (((efrm - frm) != frmLen) || (frmLen < sizeof(*wh))) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid frame length", __func__); + return false; + } + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Copy Element id */ + mmie->element_id = IEEE80211_ELEMID_MMIE; + + /* Copy Length */ + mmie->length = sizeof(*mmie) - 2; + + /* Copy Key id */ + mmie->key_id = key_id; + + /* + * In case of error, revert back to original IPN + * to do that copy the original IPN into previous_ipn + */ + cdf_mem_copy(&previous_ipn[0], ipn, IEEE80211_MMIE_IPNLEN); + cds_increase_seq(ipn); + cdf_mem_copy(mmie->sequence_number, ipn, IEEE80211_MMIE_IPNLEN); + + /* + * Calculate MIC and then copy + */ + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: crypto_alloc_cipher failed (%d)", __func__, ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: crypto_cipher_setkey failed (%d)", __func__, + ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + cdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (frmLen - sizeof(struct ieee80211_frame)); + input = (uint8_t *) cdf_mem_malloc(nBytes); + if (NULL == input) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed", __func__); + ret = CDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* + * Copy the AAD, Management frame body, and + * MMIE with 8 bit MIC zeroed out + */ + cdf_mem_zero(input, nBytes); + cdf_mem_copy(input, aad, AAD_LEN); + /* Copy Management Frame Body and MMIE without MIC */ + cdf_mem_copy(input + AAD_LEN, + (uint8_t *) (efrm - + (frmLen - sizeof(struct ieee80211_frame))), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + cdf_mem_free(input); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + cdf_mem_copy(mmie->mic, mic, IEEE80211_MMIE_MICLEN); + +err_tfm: + if (ret) { + cdf_mem_copy(ipn, previous_ipn, IEEE80211_MMIE_IPNLEN); + } + + if (tfm) + cds_crypto_free_cipher(tfm); + return !ret ? true : false; +} + +bool +cds_is_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, uint8_t *efrm) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* Check if frame is invalid length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Invalid frame length"); + return false; + } + + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Check Element ID */ + if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || + (mmie->length != (sizeof(*mmie) - 2))) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "IE is not Mgmt MIC IE or Invalid length"); + /* IE is not Mgmt MIC IE or invalid length */ + return false; + } + + /* Validate IPN */ + rx_ipn = mmie->sequence_number; + if (OS_MEMCMP(rx_ipn, ipn, CMAC_IPN_LEN) <= 0) { + /* Replay error */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Replay error mmie ipn %02X %02X %02X %02X %02X %02X" + " drvr ipn %02X %02X %02X %02X %02X %02X", + rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], + rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], + ipn[5]); + return false; + } + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_alloc_cipher failed (%d)", ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_cipher_setkey failed (%d)", ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + cdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (efrm - (uint8_t *) (wh + 1)); + input = (uint8_t *) cdf_mem_malloc(nBytes); + if (NULL == input) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Memory allocation failed"); + ret = CDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* Copy the AAD, MMIE with 8 bit MIC zeroed out */ + cdf_mem_zero(input, nBytes); + cdf_mem_copy(input, aad, AAD_LEN); + cdf_mem_copy(input + AAD_LEN, (uint8_t *) (wh + 1), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + cdf_mem_free(input); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + + if (OS_MEMCMP(mic, mmie->mic, CMAC_TLEN) != 0) { + /* MMIE MIC mismatch */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "BC/MC MGMT frame MMIE MIC check Failed" + " rmic %02X %02X %02X %02X %02X %02X %02X %02X" + " cmic %02X %02X %02X %02X %02X %02X %02X %02X", + mmie->mic[0], mmie->mic[1], mmie->mic[2], + mmie->mic[3], mmie->mic[4], mmie->mic[5], + mmie->mic[6], mmie->mic[7], mic[0], mic[1], mic[2], + mic[3], mic[4], mic[5], mic[6], mic[7]); + return false; + } + + /* Update IPN */ + cdf_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN); + +err_tfm: + if (tfm) + cds_crypto_free_cipher(tfm); + + return !ret ? true : false; +} + +#endif /* WLAN_FEATURE_11W */ +/** + * cds_sha1_hmac_str + * + * FUNCTION: + * Generate the HMAC-SHA1 of a string given a key. + * + * LOGIC: + * Standard HMAC processing from RFC 2104. The code is provided in the + * appendix of the RFC. + * + * ASSUMPTIONS: + * The RFC is correct. + * + * @param text text to be hashed + * @param textLen length of text + * @param key key to use for HMAC + * @param keyLen length of key + * @param digest holds resultant SHA1 HMAC (20B) + * + * @return CDF_STATUS_SUCCSS if the operation succeeds + * + */ + +struct hmac_sha1_result { + struct completion completion; + int err; +}; + +static void hmac_sha1_complete(struct crypto_async_request *req, int err) +{ + struct hmac_sha1_result *r = req->data; + if (err == -EINPROGRESS) + return; + r->err = err; + complete(&r->completion); +} + +int +hmac_sha1(uint8_t *key, uint8_t ksize, char *plaintext, uint8_t psize, + uint8_t *output, uint8_t outlen) +{ + int ret = 0; + struct crypto_ahash *tfm; + struct scatterlist sg; + struct ahash_request *req; + struct hmac_sha1_result tresult; + void *hash_buff = NULL; + + unsigned char hash_result[64]; + int i; + + memset(output, 0, outlen); + + init_completion(&tresult.completion); + + tfm = cds_crypto_alloc_ahash("hmac(sha1)", CRYPTO_ALG_TYPE_AHASH, + CRYPTO_ALG_TYPE_AHASH_MASK); + if (IS_ERR(tfm)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_alloc_ahash failed"); + ret = PTR_ERR(tfm); + goto err_tfm; + } + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "failed to allocate request for hmac(sha1)"); + ret = -ENOMEM; + goto err_req; + } + + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + hmac_sha1_complete, &tresult); + + hash_buff = kzalloc(psize, GFP_KERNEL); + if (!hash_buff) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "failed to kzalloc hash_buff"); + ret = -ENOMEM; + goto err_hash_buf; + } + + memset(hash_result, 0, 64); + memcpy(hash_buff, plaintext, psize); + sg_init_one(&sg, hash_buff, psize); + + if (ksize) { + crypto_ahash_clear_flags(tfm, ~0); + ret = cds_crypto_ahash_setkey(tfm, key, ksize); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_ahash_setkey failed"); + goto err_setkey; + } + } + + ahash_request_set_crypt(req, &sg, hash_result, psize); + ret = cds_crypto_ahash_digest(req); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, "ret 0x%x", ret); + + switch (ret) { + case 0: + for (i = 0; i < outlen; i++) + output[i] = hash_result[i]; + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible(&tresult.completion); + if (!ret && !tresult.err) { + INIT_COMPLETION(tresult.completion); + break; + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "wait_for_completion_interruptible failed"); + if (!ret) + ret = tresult.err; + goto out; + } + default: + goto out; + } + +out: +err_setkey: + kfree(hash_buff); +err_hash_buf: + ahash_request_free(req); +err_req: + cds_crypto_free_ahash(tfm); +err_tfm: + return ret; +} + +CDF_STATUS cds_sha1_hmac_str(uint32_t cryptHandle, /* Handle */ + uint8_t *pText, /* pointer to data stream */ + uint32_t textLen, /* length of data stream */ + uint8_t *pKey, /* pointer to authentication key */ + uint32_t keyLen, /* length of authentication key */ + uint8_t digest[CDS_DIGEST_SHA1_SIZE]) +{ /* caller digest to be filled in */ + int ret = 0; + + ret = hmac_sha1(pKey, /* uint8_t *key, */ + (uint8_t) keyLen, /* uint8_t ksize, */ + (char *)pText, /* char *plaintext, */ + (uint8_t) textLen, /* uint8_t psize, */ + digest, /* uint8_t *output, */ + CDS_DIGEST_SHA1_SIZE /* uint8_t outlen */ + ); + + if (ret != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "hmac_sha1() call failed"); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_md5_hmac_str + * + * FUNCTION: + * Generate the HMAC-MD5 of a string given a key. + * + * LOGIC: + * Standard HMAC processing from RFC 2104. The code is provided in the + * appendix of the RFC. + * + * ASSUMPTIONS: + * The RFC is correct. + * + * @param text text to be hashed + * @param textLen length of text + * @param key key to use for HMAC + * @param keyLen length of key + * @param digest holds resultant MD5 HMAC (20B) + * + * @return CDF_STATUS_SUCCSS if the operation succeeds + * + */ +struct hmac_md5_result { + struct completion completion; + int err; +}; + +static void hmac_md5_complete(struct crypto_async_request *req, int err) +{ + struct hmac_md5_result *r = req->data; + if (err == -EINPROGRESS) + return; + r->err = err; + complete(&r->completion); +} + +int +hmac_md5(uint8_t *key, uint8_t ksize, char *plaintext, uint8_t psize, + uint8_t *output, uint8_t outlen) +{ + int ret = 0; + struct crypto_ahash *tfm; + struct scatterlist sg; + struct ahash_request *req; + struct hmac_md5_result tresult = {.err = 0 }; + void *hash_buff = NULL; + + unsigned char hash_result[64]; + int i; + + memset(output, 0, outlen); + + init_completion(&tresult.completion); + + tfm = cds_crypto_alloc_ahash("hmac(md5)", CRYPTO_ALG_TYPE_AHASH, + CRYPTO_ALG_TYPE_AHASH_MASK); + if (IS_ERR(tfm)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_alloc_ahash failed"); + ret = PTR_ERR(tfm); + goto err_tfm; + } + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "failed to allocate request for hmac(md5)"); + ret = -ENOMEM; + goto err_req; + } + + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + hmac_md5_complete, &tresult); + + hash_buff = kzalloc(psize, GFP_KERNEL); + if (!hash_buff) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "failed to kzalloc hash_buff"); + ret = -ENOMEM; + goto err_hash_buf; + } + + memset(hash_result, 0, 64); + memcpy(hash_buff, plaintext, psize); + sg_init_one(&sg, hash_buff, psize); + + if (ksize) { + crypto_ahash_clear_flags(tfm, ~0); + ret = cds_crypto_ahash_setkey(tfm, key, ksize); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_ahash_setkey failed"); + goto err_setkey; + } + } + + ahash_request_set_crypt(req, &sg, hash_result, psize); + ret = cds_crypto_ahash_digest(req); + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, "ret 0x%x", ret); + + switch (ret) { + case 0: + for (i = 0; i < outlen; i++) + output[i] = hash_result[i]; + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible(&tresult.completion); + if (!ret && !tresult.err) { + INIT_COMPLETION(tresult.completion); + break; + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "wait_for_completion_interruptible failed"); + if (!ret) + ret = tresult.err; + goto out; + } + default: + goto out; + } + +out: +err_setkey: + kfree(hash_buff); +err_hash_buf: + ahash_request_free(req); +err_req: + cds_crypto_free_ahash(tfm); +err_tfm: + return ret; +} + +CDF_STATUS cds_md5_hmac_str(uint32_t cryptHandle, /* Handle */ + uint8_t *pText, /* pointer to data stream */ + uint32_t textLen, /* length of data stream */ + uint8_t *pKey, /* pointer to authentication key */ + uint32_t keyLen, /* length of authentication key */ + uint8_t digest[CDS_DIGEST_MD5_SIZE]) +{ /* caller digest to be filled in */ + int ret = 0; + + ret = hmac_md5(pKey, /* uint8_t *key, */ + (uint8_t) keyLen, /* uint8_t ksize, */ + (char *)pText, /* char *plaintext, */ + (uint8_t) textLen, /* uint8_t psize, */ + digest, /* uint8_t *output, */ + CDS_DIGEST_MD5_SIZE /* uint8_t outlen */ + ); + + if (ret != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "hmac_md5() call failed"); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} + +struct ecb_aes_result { + struct completion completion; + int err; +}; + +static void ecb_aes_complete(struct crypto_async_request *req, int err) +{ + struct ecb_aes_result *r = req->data; + if (err == -EINPROGRESS) + return; + r->err = err; + complete(&r->completion); +} + +/*-------------------------------------------------------------------------- + + \brief cds_encrypt_aes() - Generate AES Encrypted byte stream + + The cds_encrypt_aes() function generates the encrypted byte stream for given text. + + Buffer should be allocated before calling cds_rand_get_bytes(). + + Attempting to initialize an already initialized lock results in + a failure. + + \param lock - pointer to the opaque lock object to initialize + + \return CDF_STATUS_SUCCESS - Successfully generated random memory. + + CDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + CDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***CDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ + +CDF_STATUS cds_encrypt_aes(uint32_t cryptHandle, /* Handle */ + uint8_t *pPlainText, /* pointer to data stream */ + uint8_t *pCiphertext, uint8_t *pKey) +{ /* pointer to authentication key */ + struct ecb_aes_result result; + struct ablkcipher_request *req; + struct crypto_ablkcipher *tfm; + int ret = 0; + char iv[IV_SIZE_AES_128]; + struct scatterlist sg_in; + struct scatterlist sg_out; + + init_completion(&result.completion); + + tfm = cds_crypto_alloc_ablkcipher("cbc(aes)", 0, 0); + if (IS_ERR(tfm)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_alloc_ablkcipher failed"); + ret = PTR_ERR(tfm); + goto err_tfm; + } + + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Failed to allocate request for cbc(aes)"); + ret = -ENOMEM; + goto err_req; + } + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + ecb_aes_complete, &result); + + crypto_ablkcipher_clear_flags(tfm, ~0); + + ret = crypto_ablkcipher_setkey(tfm, pKey, AES_KEYSIZE_128); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_cipher_setkey failed"); + goto err_setkey; + } + + memset(iv, 0, IV_SIZE_AES_128); + + sg_init_one(&sg_in, pPlainText, AES_BLOCK_SIZE); + + sg_init_one(&sg_out, pCiphertext, AES_BLOCK_SIZE); + + ablkcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv); + + crypto_ablkcipher_encrypt(req); + +/* ------------------------------------- */ +err_setkey: + cds_ablkcipher_request_free(req); +err_req: + cds_crypto_free_ablkcipher(tfm); +err_tfm: + /* return ret; */ + if (ret != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s() call failed", __func__); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + + \brief cds_decrypt_aes() - Decrypts an AES Encrypted byte stream + + The cds_decrypt_aes() function decrypts the encrypted byte stream. + + Buffer should be allocated before calling cds_rand_get_bytes(). + + Attempting to initialize an already initialized lock results in + a failure. + + \param lock - pointer to the opaque lock object to initialize + + \return CDF_STATUS_SUCCESS - Successfully generated random memory. + + CDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + CDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***CDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ + +CDF_STATUS cds_decrypt_aes(uint32_t cryptHandle, /* Handle */ + uint8_t *pText, /* pointer to data stream */ + uint8_t *pDecrypted, uint8_t *pKey) +{ /* pointer to authentication key */ +/* CDF_STATUS uResult = CDF_STATUS_E_FAILURE; */ + struct ecb_aes_result result; + struct ablkcipher_request *req; + struct crypto_ablkcipher *tfm; + int ret = 0; + char iv[IV_SIZE_AES_128]; + struct scatterlist sg_in; + struct scatterlist sg_out; + + init_completion(&result.completion); + + tfm = cds_crypto_alloc_ablkcipher("cbc(aes)", 0, 0); + if (IS_ERR(tfm)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_alloc_ablkcipher failed"); + ret = PTR_ERR(tfm); + goto err_tfm; + } + + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Failed to allocate request for cbc(aes)"); + ret = -ENOMEM; + goto err_req; + } + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + ecb_aes_complete, &result); + + crypto_ablkcipher_clear_flags(tfm, ~0); + + ret = crypto_ablkcipher_setkey(tfm, pKey, AES_KEYSIZE_128); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "crypto_cipher_setkey failed"); + goto err_setkey; + } + + memset(iv, 0, IV_SIZE_AES_128); + + sg_init_one(&sg_in, pText, AES_BLOCK_SIZE); + + sg_init_one(&sg_out, pDecrypted, AES_BLOCK_SIZE); + + ablkcipher_request_set_crypt(req, &sg_in, &sg_out, AES_BLOCK_SIZE, iv); + + crypto_ablkcipher_decrypt(req); + +/* ------------------------------------- */ +err_setkey: + cds_ablkcipher_request_free(req); +err_req: + cds_crypto_free_ablkcipher(tfm); +err_tfm: + /* return ret; */ + if (ret != 0) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s() call failed", __func__); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} + +uint32_t cds_chan_to_freq(uint8_t chan) +{ + if (chan < CDS_24_GHZ_CHANNEL_14) /* ch 0 - ch 13 */ + return CDS_24_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; + else if (chan == CDS_24_GHZ_CHANNEL_14) /* ch 14 */ + return CDS_CHAN_14_FREQ; + else if (chan < CDS_24_GHZ_CHANNEL_27) /* ch 15 - ch 26 */ + return CDS_CHAN_15_FREQ + + (chan - CDS_24_GHZ_CHANNEL_15) * CDS_CHAN_SPACING_20MHZ; + else if (chan == CDS_5_GHZ_CHANNEL_170) + return CDS_CHAN_170_FREQ; + else + return CDS_5_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; +} + +uint8_t cds_freq_to_chan(uint32_t freq) +{ + uint8_t chan; + + if (freq > CDS_24_GHZ_BASE_FREQ && freq < CDS_CHAN_14_FREQ) + chan = ((freq - CDS_24_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ); + else if (freq == CDS_CHAN_14_FREQ) + chan = CDS_24_GHZ_CHANNEL_14; + else if ((freq > CDS_24_GHZ_BASE_FREQ) && (freq < CDS_5_GHZ_BASE_FREQ)) + chan = (((freq - CDS_CHAN_15_FREQ) / CDS_CHAN_SPACING_20MHZ) + + CDS_24_GHZ_CHANNEL_15); + else + chan = (freq - CDS_5_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ; + return chan; +} + +uint8_t cds_chan_to_band(uint32_t chan) +{ + if (chan <= CDS_24_GHZ_CHANNEL_14) + return CDS_BAND_2GHZ; + + return CDS_BAND_5GHZ; +} diff --git a/core/cds/src/i_cds_packet.h b/core/cds/src/i_cds_packet.h new file mode 100644 index 0000000000..23858fedd2 --- /dev/null +++ b/core/cds/src/i_cds_packet.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __I_CDS_PACKET_H ) +#define __I_CDS_PACKET_H + +/**========================================================================= + + \file i_cds_packet.h + + \brief Connectivity driver services network packet APIs + + Network Protocol packet/buffer internal include file + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_types.h" +/* + * Rx Packet Struct + */ +typedef struct { + uint8_t channel; + uint8_t snr; + uint32_t rssi; + uint32_t timestamp; + uint8_t *mpdu_hdr_ptr; + uint8_t *mpdu_data_ptr; + uint32_t mpdu_len; + uint32_t mpdu_hdr_len; + uint32_t mpdu_data_len; + uint8_t offloadScanLearn : 1; + uint8_t roamCandidateInd : 1; + uint8_t scan : 1; + uint8_t scan_src; + uint8_t dpuFeedback; + uint8_t sessionId; + uint32_t tsf_delta; +} t_packetmeta, *tp_packetmeta; + +/* implementation specific cds packet type */ +struct cds_pkt_t { + /* Packet Meta Information */ + t_packetmeta pkt_meta; + + /* Pointer to Packet */ + void *pkt_buf; +}; + +#endif /* !defined( __I_CDS_PACKET_H ) */ diff --git a/core/cds/src/queue.h b/core/cds/src/queue.h new file mode 100644 index 0000000000..73200429ea --- /dev/null +++ b/core/cds/src/queue.h @@ -0,0 +1,571 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ + */ + +#if !defined(__NetBSD__) +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char *lastfile; + int lastline; + char *prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)NULL; } while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) do {(x) = (void *)0; } while (0) +#endif /* QUEUE_MACRO_DEBUG */ + +#ifdef ATHR_RNWF +/* NDIS contains a defn for SLIST_ENTRY and SINGLE_LIST_ENTRY */ +#endif + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ + struct name { \ + struct type *slh_first; /* first element */ \ + } + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SING_LIST_ENTRY(type) \ + struct { \ + struct type *sle_next; /* next element */ \ + } + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ + struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ + } + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ + struct { \ + struct type *stqe_next; /* next element */ \ + } + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((curelm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if (STAILQ_NEXT(elm, field)) { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define ATH_LIST_HEAD(name, type) \ + struct name { \ + struct type *lh_first; /* first element */ \ + } + +#ifndef LIST_HEAD +#define LIST_HEAD ATH_LIST_HEAD +#endif + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ + struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ + } + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define HEADNAME +#define COPY_HEADNAME(head) + +#define TAILQ_HEAD(name, type) \ + struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + HEADNAME \ + TRACEBUF \ + } + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ + struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ + } + +/* + * Tail queue functions. + */ + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + COPY_HEADNAME(head); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +static __inline void insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !(__GNUC__ || __INTEL_COMPILER) */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ +#else /* !__NetBSD__ */ +#include_next +#endif /* __NetBSD__ */ diff --git a/core/dp/htt/htt.c b/core/dp/htt/htt.c new file mode 100644 index 0000000000..06d0a7ea1e --- /dev/null +++ b/core/dp/htt/htt.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt.c + * @brief Provide functions to create+init and destroy a HTT instance. + * @details + * This file contains functions for creating a HTT instance; initializing + * the HTT instance, e.g. by allocating a pool of HTT tx descriptors and + * connecting the HTT service with HTC; and deleting a HTT instance. + */ + +#include /* cdf_mem_malloc */ +#include /* cdf_device_t, cdf_print */ + +#include /* htt_tx_msdu_desc_t */ +#include +#include /* ol_tx_dowload_done_ll, etc. */ +#include + +#include +#include "hif.h" + +#define HTT_HTC_PKT_POOL_INIT_SIZE 100 /* enough for a large A-MPDU */ + +A_STATUS(*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); + +#ifdef IPA_OFFLOAD +A_STATUS htt_ipa_config(htt_pdev_handle pdev, A_STATUS status) +{ + if ((A_OK == status) && + ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + status = htt_h2t_ipa_uc_rsc_cfg_msg(pdev); + return status; +} + +#define HTT_IPA_CONFIG htt_ipa_config +#else +#define HTT_IPA_CONFIG(pdev, status) status /* no-op */ +#endif /* IPA_OFFLOAD */ + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt = NULL; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_freelist) { + pkt = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = pdev->htt_htc_pkt_freelist->u.next; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + if (pkt == NULL) + pkt = cdf_mem_malloc(sizeof(*pkt)); + + return &pkt->u.pkt; /* not actually a dereference */ +} + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + u_pkt->u.next = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = u_pkt; + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + pkt = pdev->htt_htc_pkt_freelist; + while (pkt) { + next = pkt->u.next; + cdf_mem_free(pkt); + pkt = next; + } + pdev->htt_htc_pkt_freelist = NULL; +} + +#ifdef ATH_11AC_TXCOMPACT +void htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_misclist) { + u_pkt->u.next = pdev->htt_htc_pkt_misclist; + pdev->htt_htc_pkt_misclist = u_pkt; + } else { + pdev->htt_htc_pkt_misclist = u_pkt; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + cdf_nbuf_t netbuf; + pkt = pdev->htt_htc_pkt_misclist; + + while (pkt) { + next = pkt->u.next; + netbuf = (cdf_nbuf_t) (pkt->u.pkt.htc_pkt.pNetBufContext); + cdf_nbuf_unmap(pdev->osdev, netbuf, CDF_DMA_TO_DEVICE); + cdf_nbuf_free(netbuf); + cdf_mem_free(pkt); + pkt = next; + } + pdev->htt_htc_pkt_misclist = NULL; +} +#endif + +/** + * htt_pdev_alloc() - allocate HTT pdev + * @txrx_pdev: txrx pdev + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os device + * + * Return: HTT pdev handle + */ +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, cdf_device_t osdev) +{ + struct htt_pdev_t *pdev; + + pdev = cdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail1; + + pdev->osdev = osdev; + pdev->ctrl_pdev = ctrl_pdev; + pdev->txrx_pdev = txrx_pdev; + pdev->htc_pdev = htc_pdev; + + cdf_mem_set(&pdev->stats, sizeof(pdev->stats), 0); + pdev->htt_htc_pkt_freelist = NULL; +#ifdef ATH_11AC_TXCOMPACT + pdev->htt_htc_pkt_misclist = NULL; +#endif + pdev->cfg.default_tx_comp_req = + !ol_cfg_tx_free_at_download(pdev->ctrl_pdev); + + pdev->cfg.is_full_reorder_offload = + ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev); + cdf_print("is_full_reorder_offloaded? %d\n", + (int)pdev->cfg.is_full_reorder_offload); + + pdev->cfg.ce_classify_enabled = + ol_cfg_is_ce_classify_enabled(ctrl_pdev); + cdf_print("ce_classify_enabled %d\n", + pdev->cfg.ce_classify_enabled); + + pdev->targetdef = htc_get_targetdef(htc_pdev); +#if defined(HELIUMPLUS_PADDR64) + /* TODO: OKA: Remove hard-coding */ + HTT_SET_WIFI_IP(pdev, 2, 0); +#endif /* defined(HELIUMPLUS_PADDR64) */ + + /* + * Connect to HTC service. + * This has to be done before calling htt_rx_attach, + * since htt_rx_attach involves sending a rx ring configure + * message to the target. + */ +/* AR6004 don't need HTT layer. */ +#ifndef AR6004_HW + if (htt_htc_attach(pdev)) + goto fail2; +#endif + + return pdev; + +fail2: + cdf_mem_free(pdev); + +fail1: + return NULL; + +} + +/** + * htt_attach() - Allocate and setup HTT TX/RX descriptors + * @pdev: pdev ptr + * @desc_pool_size: size of tx descriptors + * + * Return: 0 for success or error code. + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size) +{ + int i; + enum wlan_frm_fmt frm_type; + int ret = 0; + + ret = htt_tx_attach(pdev, desc_pool_size); + if (ret) + goto fail1; + + ret = htt_rx_attach(pdev); + if (ret) + goto fail2; + + HTT_TX_MUTEX_INIT(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_INIT(pdev); + + /* pre-allocate some HTC_PACKET objects */ + for (i = 0; i < HTT_HTC_PKT_POOL_INIT_SIZE; i++) { + struct htt_htc_pkt_union *pkt; + pkt = cdf_mem_malloc(sizeof(*pkt)); + if (!pkt) + break; + htt_htc_pkt_free(pdev, &pkt->u.pkt); + } + + /* + * LL - download just the initial portion of the frame. + * Download enough to cover the encapsulation headers checked + * by the target's tx classification descriptor engine. + */ + + /* account for the 802.3 or 802.11 header */ + frm_type = ol_cfg_frame_type(pdev->ctrl_pdev); + if (frm_type == wlan_frm_fmt_native_wifi) { + pdev->download_len = HTT_TX_HDR_SIZE_NATIVE_WIFI; + } else if (frm_type == wlan_frm_fmt_802_3) { + pdev->download_len = HTT_TX_HDR_SIZE_ETHERNET; + } else { + cdf_print("Unexpected frame type spec: %d\n", frm_type); + HTT_ASSERT0(0); + } + /* + * Account for the optional L2 / ethernet header fields: + * 802.1Q, LLC/SNAP + */ + pdev->download_len += + HTT_TX_HDR_SIZE_802_1Q + HTT_TX_HDR_SIZE_LLC_SNAP; + + /* + * Account for the portion of the L3 (IP) payload that the + * target needs for its tx classification. + */ + pdev->download_len += ol_cfg_tx_download_size(pdev->ctrl_pdev); + + /* + * Account for the HTT tx descriptor, including the + * HTC header + alignment padding. + */ + pdev->download_len += sizeof(struct htt_host_tx_desc_t); + + /* + * The TXCOMPACT htt_tx_sched function uses pdev->download_len + * to apply for all requeued tx frames. Thus, + * pdev->download_len has to be the largest download length of + * any tx frame that will be downloaded. + * This maximum download length is for management tx frames, + * which have an 802.11 header. + */ +#ifdef ATH_11AC_TXCOMPACT + pdev->download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); +#endif + pdev->tx_send_complete_part2 = ol_tx_download_done_ll; + + /* + * For LL, the FW rx desc is alongside the HW rx desc fields in + * the htt_host_rx_desc_base struct/. + */ + pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; + + return 0; + +fail2: + htt_tx_detach(pdev); + +fail1: + return ret; +} + +A_STATUS htt_attach_target(htt_pdev_handle pdev) +{ + A_STATUS status; + + status = htt_h2t_ver_req_msg(pdev); + if (status != A_OK) + return status; + +#if defined(HELIUMPLUS_PADDR64) + /* + * Send the frag_desc info to target. + */ + htt_h2t_frag_desc_bank_cfg_msg(pdev); +#endif /* defined(HELIUMPLUS_PADDR64) */ + + + /* + * If applicable, send the rx ring config message to the target. + * The host could wait for the HTT version number confirmation message + * from the target before sending any further HTT messages, but it's + * reasonable to assume that the host and target HTT version numbers + * match, and proceed immediately with the remaining configuration + * handshaking. + */ + + status = htt_h2t_rx_ring_cfg_msg(pdev); + status = HTT_IPA_CONFIG(pdev, status); + + return status; +} + +void htt_detach(htt_pdev_handle pdev) +{ + htt_rx_detach(pdev); + htt_tx_detach(pdev); + htt_htc_pkt_pool_free(pdev); +#ifdef ATH_11AC_TXCOMPACT + htt_htc_misc_pkt_pool_free(pdev); +#endif + HTT_TX_MUTEX_DESTROY(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(pdev); +} + +/** + * htt_pdev_free() - Free HTT pdev + * @pdev: htt pdev + * + * Return: none + */ +void htt_pdev_free(htt_pdev_handle pdev) +{ + cdf_mem_free(pdev); +} + +void htt_detach_target(htt_pdev_handle pdev) +{ +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * htt_pkt_dl_len_get() HTT packet download length for fastpath case + * + * @htt_dev: pointer to htt device. + * + * As fragment one already downloaded HTT/HTC header, download length is + * remaining bytes. + * + * Return: download length + */ +int htt_pkt_dl_len_get(struct htt_pdev_t *htt_dev) +{ + return htt_dev->download_len - sizeof(struct htt_host_tx_desc_t); +} +#else +int htt_pkt_dl_len_get(struct htt_pdev_t *htt_dev) +{ + return 0; +} +#endif + +int htt_htc_attach(struct htt_pdev_t *pdev) +{ + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP response; + A_STATUS status; + + cdf_mem_set(&connect, sizeof(connect), 0); + cdf_mem_set(&response, sizeof(response), 0); + + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + connect.EpCallbacks.pContext = pdev; + connect.EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect.EpCallbacks.EpTxCompleteMultiple = NULL; + connect.EpCallbacks.EpRecv = htt_t2h_msg_handler; + + /* rx buffers currently are provided by HIF, not by EpRecvRefill */ + connect.EpCallbacks.EpRecvRefill = NULL; + connect.EpCallbacks.RecvRefillWaterMark = 1; + /* N/A, fill is done by HIF */ + + connect.EpCallbacks.EpSendFull = htt_h2t_full; + /* + * Specify how deep to let a queue get before htc_send_pkt will + * call the EpSendFull function due to excessive send queue depth. + */ + connect.MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + + /* disable flow control for HTT data message service */ +#ifndef HIF_SDIO + connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; +#endif + + /* connect to control service */ + connect.ServiceID = HTT_DATA_MSG_SVC; + + status = htc_connect_service(pdev->htc_pdev, &connect, &response); + + if (status != A_OK) + return -EIO; /* failure */ + + pdev->htc_endpoint = response.Endpoint; +#if defined(HIF_PCI) + hif_save_htc_htt_config_endpoint(pdev->htc_endpoint); +#endif + + return 0; /* success */ +} + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent) +{ + cdf_print("%*s%s:\n", indent, " ", "HTT"); + cdf_print("%*stx desc pool: %d elems of %d bytes, %d allocated\n", + indent + 4, " ", + pdev->tx_descs.pool_elems, + pdev->tx_descs.size, pdev->tx_descs.alloc_cnt); + cdf_print("%*srx ring: space for %d elems, filled with %d buffers\n", + indent + 4, " ", + pdev->rx_ring.size, pdev->rx_ring.fill_level); + cdf_print("%*sat %p (%#x paddr)\n", indent + 8, " ", + pdev->rx_ring.buf.paddrs_ring, pdev->rx_ring.base_paddr); + cdf_print("%*snetbuf ring @ %p\n", indent + 8, " ", + pdev->rx_ring.buf.netbufs_ring); + cdf_print("%*sFW_IDX shadow register: vaddr = %p, paddr = %#x\n", + indent + 8, " ", + pdev->rx_ring.alloc_idx.vaddr, pdev->rx_ring.alloc_idx.paddr); + cdf_print("%*sSW enqueue idx= %d, SW dequeue idx: desc= %d, buf= %d\n", + indent + 8, " ", *pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.sw_rd_idx.msdu_desc, + pdev->rx_ring.sw_rd_idx.msdu_payld); +} +#endif + +/* Disable ASPM : Disable PCIe low power */ +void htt_htc_disable_aspm(void) +{ + htc_disable_aspm(); +} + +#ifdef IPA_OFFLOAD +/* + * Attach resource for micro controller data path + */ +int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + int error; + + /* TX resource attach */ + error = htt_tx_ipa_uc_attach( + pdev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_partition_base(pdev->ctrl_pdev)); + if (error) { + cdf_print("HTT IPA UC TX attach fail code %d\n", error); + HTT_ASSERT0(0); + return error; + } + + /* RX resource attach */ + error = htt_rx_ipa_uc_attach( + pdev, + ol_cfg_ipa_uc_rx_ind_ring_size(pdev->ctrl_pdev)); + if (error) { + cdf_print("HTT IPA UC RX attach fail code %d\n", error); + htt_tx_ipa_uc_detach(pdev); + HTT_ASSERT0(0); + return error; + } + + return 0; /* success */ +} + +void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + /* TX IPA micro controller detach */ + htt_tx_ipa_uc_detach(pdev); + + /* RX IPA micro controller detach */ + htt_rx_ipa_uc_detach(pdev); +} + +/* + * Distribute micro controller resource to control module + */ +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr) +{ + /* Release allocated resource to client */ + *tx_comp_ring_base_paddr = + (uint32_t) pdev->ipa_uc_tx_rsc.tx_comp_base.paddr; + *tx_comp_ring_size = + (uint32_t) ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev); + *tx_num_alloc_buffer = (uint32_t) pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; + *rx_rdy_ring_base_paddr = + (uint32_t) pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr; + *rx_rdy_ring_size = (uint32_t) pdev->ipa_uc_rx_rsc.rx_ind_ring_size; + *rx_proc_done_idx_paddr = + (uint32_t) pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr; + + /* Get copy engine, bus resource */ + htc_ipa_get_ce_resource(pdev->htc_pdev, + ce_sr_base_paddr, + ce_sr_ring_size, ce_reg_paddr); + + return 0; +} + +/* + * Distribute micro controller doorbell register to firmware + */ +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + uint32_t ipa_uc_tx_doorbell_paddr, + uint32_t ipa_uc_rx_doorbell_paddr) +{ + pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr = ipa_uc_tx_doorbell_paddr; + pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr = ipa_uc_rx_doorbell_paddr; + return 0; +} +#endif /* IPA_OFFLOAD */ diff --git a/core/dp/htt/htt_fw_stats.c b/core/dp/htt/htt_fw_stats.c new file mode 100644 index 0000000000..aee627d0e6 --- /dev/null +++ b/core/dp/htt/htt_fw_stats.c @@ -0,0 +1,1155 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_fw_stats.c + * @brief Provide functions to process FW status retrieved from FW. + */ + +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* cdf_nbuf_t */ +#include /* cdf_mem_set */ +#include /* ol_fw_tx_dbg_ppdu_base */ + +#include +#include /* htt_tx_status */ + +#include + +#include + +#define ROUND_UP_TO_4(val) (((val) + 3) & ~0x3) + + +static char *bw_str_arr[] = {"20MHz", "40MHz", "80MHz", "160MHz"}; + +/* + * Defined the macro tx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_tx_rate_stats_print() & + * htt_t2h_stats_tx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures--so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define tx_rate_stats_print_cmn(_tx_rate_info, _concise) \ +{ \ + int i; \ + \ + cdf_print("TX Rate Info:\n"); \ + \ + /* MCS */ \ + cdf_print("MCS counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _tx_rate_info->mcs[0], \ + _tx_rate_info->mcs[1], \ + _tx_rate_info->mcs[2], \ + _tx_rate_info->mcs[3], \ + _tx_rate_info->mcs[4], \ + _tx_rate_info->mcs[5], \ + _tx_rate_info->mcs[6], \ + _tx_rate_info->mcs[7], \ + _tx_rate_info->mcs[8], \ + _tx_rate_info->mcs[9]); \ + \ + /* SGI */ \ + cdf_print("SGI counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _tx_rate_info->sgi[0], \ + _tx_rate_info->sgi[1], \ + _tx_rate_info->sgi[2], \ + _tx_rate_info->sgi[3], \ + _tx_rate_info->sgi[4], \ + _tx_rate_info->sgi[5], \ + _tx_rate_info->sgi[6], \ + _tx_rate_info->sgi[7], \ + _tx_rate_info->sgi[8], \ + _tx_rate_info->sgi[9]); \ + \ + /* NSS */ \ + cdf_print("NSS counts: "); \ + cdf_print("1x1 %d, 2x2 %d, 3x3 %d\n", \ + _tx_rate_info->nss[0], \ + _tx_rate_info->nss[1], _tx_rate_info->nss[2]);\ + \ + /* BW */ \ + cdf_print("BW counts: "); \ + \ + for (i = 0; \ + i < sizeof(_tx_rate_info->bw) / sizeof(_tx_rate_info->bw[0]);\ + i++) { \ + cdf_print("%s %d ", bw_str_arr[i], _tx_rate_info->bw[i]);\ + } \ + cdf_print("\n"); \ + \ + /* Preamble */ \ + cdf_print("Preamble (O C H V) counts: "); \ + cdf_print("%d, %d, %d, %d\n", \ + _tx_rate_info->pream[0], \ + _tx_rate_info->pream[1], \ + _tx_rate_info->pream[2], \ + _tx_rate_info->pream[3]); \ + \ + /* STBC rate counts */ \ + cdf_print("STBC rate counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _tx_rate_info->stbc[0], \ + _tx_rate_info->stbc[1], \ + _tx_rate_info->stbc[2], \ + _tx_rate_info->stbc[3], \ + _tx_rate_info->stbc[4], \ + _tx_rate_info->stbc[5], \ + _tx_rate_info->stbc[6], \ + _tx_rate_info->stbc[7], \ + _tx_rate_info->stbc[8], \ + _tx_rate_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + cdf_print("LDPC Counts: "); \ + cdf_print("%d\n", _tx_rate_info->ldpc); \ + cdf_print("RTS Counts: "); \ + cdf_print("%d\n", _tx_rate_info->rts_cnt); \ + /* RSSI Values for last ack frames */ \ + cdf_print("Ack RSSI: %d\n", _tx_rate_info->ack_rssi);\ +} + +static void htt_t2h_stats_tx_rate_stats_print(wlan_dbg_tx_rate_info_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +static void htt_t2h_stats_tx_rate_stats_print_v2(wlan_dbg_tx_rate_info_v2_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +/* + * Defined the macro rx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_rx_rate_stats_print() & + * htt_t2h_stats_rx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures -- so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define rx_rate_stats_print_cmn(_rx_phy_info, _concise) \ +{ \ + int i; \ + \ + cdf_print("RX Rate Info:\n"); \ + \ + /* MCS */ \ + cdf_print("MCS counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _rx_phy_info->mcs[0], \ + _rx_phy_info->mcs[1], \ + _rx_phy_info->mcs[2], \ + _rx_phy_info->mcs[3], \ + _rx_phy_info->mcs[4], \ + _rx_phy_info->mcs[5], \ + _rx_phy_info->mcs[6], \ + _rx_phy_info->mcs[7], \ + _rx_phy_info->mcs[8], \ + _rx_phy_info->mcs[9]); \ + \ + /* SGI */ \ + cdf_print("SGI counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _rx_phy_info->sgi[0], \ + _rx_phy_info->sgi[1], \ + _rx_phy_info->sgi[2], \ + _rx_phy_info->sgi[3], \ + _rx_phy_info->sgi[4], \ + _rx_phy_info->sgi[5], \ + _rx_phy_info->sgi[6], \ + _rx_phy_info->sgi[7], \ + _rx_phy_info->sgi[8], \ + _rx_phy_info->sgi[9]); \ + \ + /* NSS */ \ + cdf_print("NSS counts: "); \ + /* nss[0] just holds the count of non-stbc frames that were sent at 1x1 \ + * rates and nsts holds the count of frames sent with stbc. \ + * It was decided to not include PPDUs sent w/ STBC in nss[0]\ + * since it would be easier to change the value that needs to be\ + * printed (from "stbc+non-stbc count to only non-stbc count")\ + * if needed in the future. Hence the addition in the host code\ + * at this line. */ \ + cdf_print("1x1 %d, 2x2 %d, 3x3 %d, 4x4 %d\n", \ + _rx_phy_info->nss[0] + _rx_phy_info->nsts, \ + _rx_phy_info->nss[1], \ + _rx_phy_info->nss[2], \ + _rx_phy_info->nss[3]); \ + \ + /* NSTS */ \ + cdf_print("NSTS count: "); \ + cdf_print("%d\n", _rx_phy_info->nsts); \ + \ + /* BW */ \ + cdf_print("BW counts: "); \ + for (i = 0; \ + i < sizeof(_rx_phy_info->bw) / sizeof(_rx_phy_info->bw[0]); \ + i++) { \ + cdf_print("%s %d ", bw_str_arr[i], _rx_phy_info->bw[i]);\ + } \ + cdf_print("\n"); \ + \ + /* Preamble */ \ + cdf_print("Preamble counts: "); \ + cdf_print("%d, %d, %d, %d, %d, %d\n", \ + _rx_phy_info->pream[0], \ + _rx_phy_info->pream[1], \ + _rx_phy_info->pream[2], \ + _rx_phy_info->pream[3], \ + _rx_phy_info->pream[4], \ + _rx_phy_info->pream[5]); \ + \ + /* STBC rate counts */ \ + cdf_print("STBC rate counts (0..9): "); \ + cdf_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",\ + _rx_phy_info->stbc[0], \ + _rx_phy_info->stbc[1], \ + _rx_phy_info->stbc[2], \ + _rx_phy_info->stbc[3], \ + _rx_phy_info->stbc[4], \ + _rx_phy_info->stbc[5], \ + _rx_phy_info->stbc[6], \ + _rx_phy_info->stbc[7], \ + _rx_phy_info->stbc[8], \ + _rx_phy_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + cdf_print("LDPC TXBF Counts: "); \ + cdf_print("%d, %d\n", _rx_phy_info->ldpc, _rx_phy_info->txbf);\ + /* RSSI Values for last received frames */ \ + cdf_print("RSSI (data, mgmt): %d, %d\n", _rx_phy_info->data_rssi,\ + _rx_phy_info->mgmt_rssi); \ + \ + cdf_print("RSSI Chain 0 (0x%02x 0x%02x 0x%02x 0x%02x)\n",\ + ((_rx_phy_info->rssi_chain0 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 0) & 0xff)); \ + \ + cdf_print("RSSI Chain 1 (0x%02x 0x%02x 0x%02x 0x%02x)\n",\ + ((_rx_phy_info->rssi_chain1 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 0) & 0xff)); \ + \ + cdf_print("RSSI Chain 2 (0x%02x 0x%02x 0x%02x 0x%02x)\n",\ + ((_rx_phy_info->rssi_chain2 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 0) & 0xff)); \ +} + +static void htt_t2h_stats_rx_rate_stats_print(wlan_dbg_rx_rate_info_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void htt_t2h_stats_rx_rate_stats_print_v2(wlan_dbg_rx_rate_info_v2_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void +htt_t2h_stats_pdev_stats_print(struct wlan_dbg_stats *wlan_pdev_stats, + int concise) +{ + struct wlan_dbg_tx_stats *tx = &wlan_pdev_stats->tx; + struct wlan_dbg_rx_stats *rx = &wlan_pdev_stats->rx; + + cdf_print("WAL Pdev stats:\n"); + cdf_print("\n### Tx ###\n"); + + /* Num HTT cookies queued to dispatch list */ + cdf_print("comp_queued :\t%d\n", tx->comp_queued); + /* Num HTT cookies dispatched */ + cdf_print("comp_delivered :\t%d\n", tx->comp_delivered); + /* Num MSDU queued to WAL */ + cdf_print("msdu_enqued :\t%d\n", tx->msdu_enqued); + /* Num MPDU queued to WAL */ + cdf_print("mpdu_enqued :\t%d\n", tx->mpdu_enqued); + /* Num MSDUs dropped by WMM limit */ + cdf_print("wmm_drop :\t%d\n", tx->wmm_drop); + /* Num Local frames queued */ + cdf_print("local_enqued :\t%d\n", tx->local_enqued); + /* Num Local frames done */ + cdf_print("local_freed :\t%d\n", tx->local_freed); + /* Num queued to HW */ + cdf_print("hw_queued :\t%d\n", tx->hw_queued); + /* Num PPDU reaped from HW */ + cdf_print("hw_reaped :\t%d\n", tx->hw_reaped); + /* Num underruns */ + cdf_print("mac underrun :\t%d\n", tx->underrun); + /* Num underruns */ + cdf_print("phy underrun :\t%d\n", tx->phy_underrun); + /* Num PPDUs cleaned up in TX abort */ + cdf_print("tx_abort :\t%d\n", tx->tx_abort); + /* Num MPDUs requed by SW */ + cdf_print("mpdus_requed :\t%d\n", tx->mpdus_requed); + /* Excessive retries */ + cdf_print("excess retries :\t%d\n", tx->tx_ko); + /* last data rate */ + cdf_print("last rc :\t%d\n", tx->data_rc); + /* scheduler self triggers */ + cdf_print("sched self trig :\t%d\n", tx->self_triggers); + /* SW retry failures */ + cdf_print("ampdu retry failed:\t%d\n", tx->sw_retry_failure); + /* ilegal phy rate errirs */ + cdf_print("illegal rate errs :\t%d\n", tx->illgl_rate_phy_err); + /* pdev continous excessive retries */ + cdf_print("pdev cont xretry :\t%d\n", tx->pdev_cont_xretry); + /* pdev continous excessive retries */ + cdf_print("pdev tx timeout :\t%d\n", tx->pdev_tx_timeout); + /* pdev resets */ + cdf_print("pdev resets :\t%d\n", tx->pdev_resets); + /* PPDU > txop duration */ + cdf_print("ppdu txop ovf :\t%d\n", tx->txop_ovf); + + cdf_print("\n### Rx ###\n"); + /* Cnts any change in ring routing mid-ppdu */ + cdf_print("ppdu_route_change :\t%d\n", rx->mid_ppdu_route_change); + /* Total number of statuses processed */ + cdf_print("status_rcvd :\t%d\n", rx->status_rcvd); + /* Extra frags on rings 0-3 */ + cdf_print("r0_frags :\t%d\n", rx->r0_frags); + cdf_print("r1_frags :\t%d\n", rx->r1_frags); + cdf_print("r2_frags :\t%d\n", rx->r2_frags); + cdf_print("r3_frags :\t%d\n", rx->r3_frags); + /* MSDUs / MPDUs delivered to HTT */ + cdf_print("htt_msdus :\t%d\n", rx->htt_msdus); + cdf_print("htt_mpdus :\t%d\n", rx->htt_mpdus); + /* MSDUs / MPDUs delivered to local stack */ + cdf_print("loc_msdus :\t%d\n", rx->loc_msdus); + cdf_print("loc_mpdus :\t%d\n", rx->loc_mpdus); + /* AMSDUs that have more MSDUs than the status ring size */ + cdf_print("oversize_amsdu :\t%d\n", rx->oversize_amsdu); + /* Number of PHY errors */ + cdf_print("phy_errs :\t%d\n", rx->phy_errs); + /* Number of PHY errors dropped */ + cdf_print("phy_errs dropped :\t%d\n", rx->phy_err_drop); + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + cdf_print("mpdu_errs :\t%d\n", rx->mpdu_errs); + +} + +static void +htt_t2h_stats_rx_reorder_stats_print(struct rx_reorder_stats *stats_ptr, + int concise) +{ + cdf_print("Rx reorder statistics:\n"); + cdf_print(" %u non-QoS frames received\n", stats_ptr->deliver_non_qos); + cdf_print(" %u frames received in-order\n", + stats_ptr->deliver_in_order); + cdf_print(" %u frames flushed due to timeout\n", + stats_ptr->deliver_flush_timeout); + cdf_print(" %u frames flushed due to moving out of window\n", + stats_ptr->deliver_flush_oow); + cdf_print(" %u frames flushed due to receiving DELBA\n", + stats_ptr->deliver_flush_delba); + cdf_print(" %u frames discarded due to FCS error\n", + stats_ptr->fcs_error); + cdf_print(" %u frames discarded due to invalid peer\n", + stats_ptr->invalid_peer); + cdf_print + (" %u frames discarded due to duplication (non aggregation)\n", + stats_ptr->dup_non_aggr); + cdf_print(" %u frames discarded due to duplication in reorder queue\n", + stats_ptr->dup_in_reorder); + cdf_print(" %u frames discarded due to processed before\n", + stats_ptr->dup_past); + cdf_print(" %u times reorder timeout happened\n", + stats_ptr->reorder_timeout); + cdf_print(" %u times incorrect bar received\n", + stats_ptr->invalid_bar_ssn); + cdf_print(" %u times bar ssn reset happened\n", + stats_ptr->ssn_reset); + cdf_print(" %u times flushed due to peer delete\n", + stats_ptr->deliver_flush_delpeer); + cdf_print(" %u times flushed due to offload\n", + stats_ptr->deliver_flush_offload); + cdf_print(" %u times flushed due to ouf of buffer\n", + stats_ptr->deliver_flush_oob); + cdf_print(" %u MPDU's dropped due to PN check fail\n", + stats_ptr->pn_fail); + cdf_print(" %u MPDU's dropped due to lack of memory\n", + stats_ptr->store_fail); + cdf_print(" %u times tid pool alloc succeeded\n", + stats_ptr->tid_pool_alloc_succ); + cdf_print(" %u times MPDU pool alloc succeeded\n", + stats_ptr->mpdu_pool_alloc_succ); + cdf_print(" %u times MSDU pool alloc succeeded\n", + stats_ptr->msdu_pool_alloc_succ); + cdf_print(" %u times tid pool alloc failed\n", + stats_ptr->tid_pool_alloc_fail); + cdf_print(" %u times MPDU pool alloc failed\n", + stats_ptr->mpdu_pool_alloc_fail); + cdf_print(" %u times MSDU pool alloc failed\n", + stats_ptr->msdu_pool_alloc_fail); + cdf_print(" %u times tid pool freed\n", + stats_ptr->tid_pool_free); + cdf_print(" %u times MPDU pool freed\n", + stats_ptr->mpdu_pool_free); + cdf_print(" %u times MSDU pool freed\n", + stats_ptr->msdu_pool_free); + cdf_print(" %u MSDUs undelivered to HTT, queued to Rx MSDU free list\n", + stats_ptr->msdu_queued); + cdf_print(" %u MSDUs released from Rx MSDU list to MAC ring\n", + stats_ptr->msdu_recycled); + cdf_print(" %u MPDUs with invalid peer but A2 found in AST\n", + stats_ptr->invalid_peer_a2_in_ast); + cdf_print(" %u MPDUs with invalid peer but A3 found in AST\n", + stats_ptr->invalid_peer_a3_in_ast); + cdf_print(" %u MPDUs with invalid peer, Broadcast or Mulitcast frame\n", + stats_ptr->invalid_peer_bmc_mpdus); + cdf_print(" %u MSDUs with err attention word\n", + stats_ptr->rxdesc_err_att); + cdf_print(" %u MSDUs with flag of peer_idx_invalid\n", + stats_ptr->rxdesc_err_peer_idx_inv); + cdf_print(" %u MSDUs with flag of peer_idx_timeout\n", + stats_ptr->rxdesc_err_peer_idx_to); + cdf_print(" %u MSDUs with flag of overflow\n", + stats_ptr->rxdesc_err_ov); + cdf_print(" %u MSDUs with flag of msdu_length_err\n", + stats_ptr->rxdesc_err_msdu_len); + cdf_print(" %u MSDUs with flag of mpdu_length_err\n", + stats_ptr->rxdesc_err_mpdu_len); + cdf_print(" %u MSDUs with flag of tkip_mic_err\n", + stats_ptr->rxdesc_err_tkip_mic); + cdf_print(" %u MSDUs with flag of decrypt_err\n", + stats_ptr->rxdesc_err_decrypt); + cdf_print(" %u MSDUs with flag of fcs_err\n", + stats_ptr->rxdesc_err_fcs); + cdf_print(" %u Unicast frames with invalid peer handler\n", + stats_ptr->rxdesc_uc_msdus_inv_peer); + cdf_print(" %u unicast frame directly to DUT with invalid peer handler\n", + stats_ptr->rxdesc_direct_msdus_inv_peer); + cdf_print(" %u Broadcast/Multicast frames with invalid peer handler\n", + stats_ptr->rxdesc_bmc_msdus_inv_peer); + cdf_print(" %u MSDUs dropped due to no first MSDU flag\n", + stats_ptr->rxdesc_no_1st_msdu); + cdf_print(" %u MSDUs dropped due to ring overflow\n", + stats_ptr->msdu_drop_ring_ov); + cdf_print(" %u MSDUs dropped due to FC mismatch\n", + stats_ptr->msdu_drop_fc_mismatch); + cdf_print(" %u MSDUs dropped due to mgt frame in Remote ring\n", + stats_ptr->msdu_drop_mgmt_remote_ring); + cdf_print(" %u MSDUs dropped due to misc non error\n", + stats_ptr->msdu_drop_misc); + cdf_print(" %u MSDUs go to offload before reorder\n", + stats_ptr->offload_msdu_wal); + cdf_print(" %u data frame dropped by offload after reorder\n", + stats_ptr->offload_msdu_reorder); + cdf_print(" %u MPDUs with SN in the past & within BA window\n", + stats_ptr->dup_past_within_window); + cdf_print(" %u MPDUs with SN in the past & outside BA window\n", + stats_ptr->dup_past_outside_window); +} + +static void +htt_t2h_stats_rx_rem_buf_stats_print( + struct rx_remote_buffer_mgmt_stats *stats_ptr, int concise) +{ + cdf_print("Rx Remote Buffer Statistics:\n"); + cdf_print(" %u MSDU's reaped for Rx processing\n", + stats_ptr->remote_reaped); + cdf_print(" %u MSDU's recycled within firmware\n", + stats_ptr->remote_recycled); + cdf_print(" %u MSDU's stored by Data Rx\n", + stats_ptr->data_rx_msdus_stored); + cdf_print(" %u HTT indications from WAL Rx MSDU\n", + stats_ptr->wal_rx_ind); + cdf_print(" %u HTT indications unconsumed from WAL Rx MSDU\n", + stats_ptr->wal_rx_ind_unconsumed); + cdf_print(" %u HTT indications from Data Rx MSDU\n", + stats_ptr->data_rx_ind); + cdf_print(" %u HTT indications unconsumed from Data Rx MSDU\n", + stats_ptr->data_rx_ind_unconsumed); + cdf_print(" %u HTT indications from ATHBUF\n", + stats_ptr->athbuf_rx_ind); + cdf_print(" %u Remote buffers requested for refill\n", + stats_ptr->refill_buf_req); + cdf_print(" %u Remote buffers filled by host\n", + stats_ptr->refill_buf_rsp); + cdf_print(" %u times MAC has no buffers\n", + stats_ptr->mac_no_bufs); + cdf_print(" %u times f/w write & read indices on MAC ring are equal\n", + stats_ptr->fw_indices_equal); + cdf_print(" %u times f/w has no remote buffers to post to MAC\n", + stats_ptr->host_no_bufs); +} + +static void +htt_t2h_stats_txbf_info_buf_stats_print( + struct wlan_dbg_txbf_data_stats *stats_ptr) +{ + cdf_print("TXBF data Statistics:\n"); + cdf_print("tx_txbf_vht (0..9): "); + cdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %d\n", + stats_ptr->tx_txbf_vht[0], + stats_ptr->tx_txbf_vht[1], + stats_ptr->tx_txbf_vht[2], + stats_ptr->tx_txbf_vht[3], + stats_ptr->tx_txbf_vht[4], + stats_ptr->tx_txbf_vht[5], + stats_ptr->tx_txbf_vht[6], + stats_ptr->tx_txbf_vht[7], + stats_ptr->tx_txbf_vht[8], + stats_ptr->tx_txbf_vht[9]); + cdf_print("rx_txbf_vht (0..9): "); + cdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u\n", + stats_ptr->rx_txbf_vht[0], + stats_ptr->rx_txbf_vht[1], + stats_ptr->rx_txbf_vht[2], + stats_ptr->rx_txbf_vht[3], + stats_ptr->rx_txbf_vht[4], + stats_ptr->rx_txbf_vht[5], + stats_ptr->rx_txbf_vht[6], + stats_ptr->rx_txbf_vht[7], + stats_ptr->rx_txbf_vht[8], + stats_ptr->rx_txbf_vht[9]); + cdf_print("tx_txbf_ht (0..7): "); + cdf_print("%u, %u, %u, %u, %u, %u, %u, %u\n", + stats_ptr->tx_txbf_ht[0], + stats_ptr->tx_txbf_ht[1], + stats_ptr->tx_txbf_ht[2], + stats_ptr->tx_txbf_ht[3], + stats_ptr->tx_txbf_ht[4], + stats_ptr->tx_txbf_ht[5], + stats_ptr->tx_txbf_ht[6], + stats_ptr->tx_txbf_ht[7]); + cdf_print("tx_txbf_ofdm (0..7): "); + cdf_print("%u, %u, %u, %u, %u, %u, %u, %u\n", + stats_ptr->tx_txbf_ofdm[0], + stats_ptr->tx_txbf_ofdm[1], + stats_ptr->tx_txbf_ofdm[2], + stats_ptr->tx_txbf_ofdm[3], + stats_ptr->tx_txbf_ofdm[4], + stats_ptr->tx_txbf_ofdm[5], + stats_ptr->tx_txbf_ofdm[6], + stats_ptr->tx_txbf_ofdm[7]); + cdf_print("tx_txbf_cck (0..6): "); + cdf_print("%u, %u, %u, %u, %u, %u, %u\n", + stats_ptr->tx_txbf_cck[0], + stats_ptr->tx_txbf_cck[1], + stats_ptr->tx_txbf_cck[2], + stats_ptr->tx_txbf_cck[3], + stats_ptr->tx_txbf_cck[4], + stats_ptr->tx_txbf_cck[5], + stats_ptr->tx_txbf_cck[6]); +} + +static void +htt_t2h_stats_txbf_snd_buf_stats_print( + struct wlan_dbg_txbf_snd_stats *stats_ptr) +{ + cdf_print("TXBF snd Buffer Statistics:\n"); + cdf_print("cbf_20: "); + cdf_print("%u, %u, %u, %u\n", + stats_ptr->cbf_20[0], + stats_ptr->cbf_20[1], + stats_ptr->cbf_20[2], + stats_ptr->cbf_20[3]); + cdf_print("cbf_40: "); + cdf_print("%u, %u, %u, %u\n", + stats_ptr->cbf_40[0], + stats_ptr->cbf_40[1], + stats_ptr->cbf_40[2], + stats_ptr->cbf_40[3]); + cdf_print("cbf_80: "); + cdf_print("%u, %u, %u, %u\n", + stats_ptr->cbf_80[0], + stats_ptr->cbf_80[1], + stats_ptr->cbf_80[2], + stats_ptr->cbf_80[3]); + cdf_print("sounding: "); + cdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u\n", + stats_ptr->sounding[0], + stats_ptr->sounding[1], + stats_ptr->sounding[2], + stats_ptr->sounding[3], + stats_ptr->sounding[4], + stats_ptr->sounding[5], + stats_ptr->sounding[6], + stats_ptr->sounding[7], + stats_ptr->sounding[8]); +} + +static void +htt_t2h_stats_tx_selfgen_buf_stats_print( + struct wlan_dbg_tx_selfgen_stats *stats_ptr) +{ + cdf_print("Tx selfgen Buffer Statistics:\n"); + cdf_print(" %u su_ndpa\n", + stats_ptr->su_ndpa); + cdf_print(" %u mu_ndp\n", + stats_ptr->mu_ndp); + cdf_print(" %u mu_ndpa\n", + stats_ptr->mu_ndpa); + cdf_print(" %u mu_ndp\n", + stats_ptr->mu_ndp); + cdf_print(" %u mu_brpoll_1\n", + stats_ptr->mu_brpoll_1); + cdf_print(" %u mu_brpoll_2\n", + stats_ptr->mu_brpoll_2); + cdf_print(" %u mu_bar_1\n", + stats_ptr->mu_bar_1); + cdf_print(" %u mu_bar_2\n", + stats_ptr->mu_bar_2); + cdf_print(" %u cts_burst\n", + stats_ptr->cts_burst); + cdf_print(" %u su_ndp_err\n", + stats_ptr->su_ndp_err); + cdf_print(" %u su_ndpa_err\n", + stats_ptr->su_ndpa_err); + cdf_print(" %u mu_ndp_err\n", + stats_ptr->mu_ndp_err); + cdf_print(" %u mu_brp1_err\n", + stats_ptr->mu_brp1_err); + cdf_print(" %u mu_brp2_err\n", + stats_ptr->mu_brp2_err); +} + +static void +htt_t2h_stats_wifi2_error_stats_print( + struct wlan_dbg_wifi2_error_stats *stats_ptr) +{ + int i; + + cdf_print("Scheduler error Statistics:\n"); + cdf_print("urrn_stats: "); + cdf_print("%d, %d, %d\n", + stats_ptr->urrn_stats[0], + stats_ptr->urrn_stats[1], + stats_ptr->urrn_stats[2]); + cdf_print("flush_errs (0..%d): ", + WHAL_DBG_FLUSH_REASON_MAXCNT); + for (i = 0; i < WHAL_DBG_FLUSH_REASON_MAXCNT; i++) + cdf_print(" %u", stats_ptr->flush_errs[i]); + cdf_print("\n"); + cdf_print("schd_stall_errs (0..3): "); + cdf_print("%d, %d, %d, %d\n", + stats_ptr->schd_stall_errs[0], + stats_ptr->schd_stall_errs[1], + stats_ptr->schd_stall_errs[2], + stats_ptr->schd_stall_errs[3]); + cdf_print("schd_cmd_result (0..%d): ", + WHAL_DBG_CMD_RESULT_MAXCNT); + for (i = 0; i < WHAL_DBG_CMD_RESULT_MAXCNT; i++) + cdf_print(" %u", stats_ptr->schd_cmd_result[i]); + cdf_print("\n"); + cdf_print("sifs_status (0..%d): ", + WHAL_DBG_SIFS_STATUS_MAXCNT); + for (i = 0; i < WHAL_DBG_SIFS_STATUS_MAXCNT; i++) + cdf_print(" %u", stats_ptr->sifs_status[i]); + cdf_print("\n"); + cdf_print("phy_errs (0..%d): ", + WHAL_DBG_PHY_ERR_MAXCNT); + for (i = 0; i < WHAL_DBG_PHY_ERR_MAXCNT; i++) + cdf_print(" %u", stats_ptr->phy_errs[i]); + cdf_print("\n"); + cdf_print(" %u rx_rate_inval\n", + stats_ptr->rx_rate_inval); +} + +static void +htt_t2h_rx_musu_ndpa_pkts_stats_print( + struct rx_txbf_musu_ndpa_pkts_stats *stats_ptr) +{ + cdf_print("Rx TXBF MU/SU Packets and NDPA Statistics:\n"); + cdf_print(" %u Number of TXBF MU packets received\n", + stats_ptr->number_mu_pkts); + cdf_print(" %u Number of TXBF SU packets received\n", + stats_ptr->number_su_pkts); + cdf_print(" %u Number of TXBF directed NDPA\n", + stats_ptr->txbf_directed_ndpa_count); + cdf_print(" %u Number of TXBF retried NDPA\n", + stats_ptr->txbf_ndpa_retry_count); + cdf_print(" %u Total number of TXBF NDPA\n", + stats_ptr->txbf_total_ndpa_count); +} + +#define HTT_TICK_TO_USEC(ticks, microsec_per_tick) (ticks * microsec_per_tick) +static inline int htt_rate_flags_to_mhz(uint8_t rate_flags) +{ + if (rate_flags & 0x20) + return 40; /* WHAL_RC_FLAG_40MHZ */ + if (rate_flags & 0x40) + return 80; /* WHAL_RC_FLAG_80MHZ */ + if (rate_flags & 0x80) + return 160; /* WHAL_RC_FLAG_160MHZ */ + return 20; +} + +#define HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW 64 + +static void +htt_t2h_tx_ppdu_bitmaps_pr(uint32_t *queued_ptr, uint32_t *acked_ptr) +{ + char queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + char acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + int i, j, word; + + cdf_mem_set(queued_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '0'); + cdf_mem_set(acked_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '-'); + i = 0; + for (word = 0; word < 2; word++) { + uint32_t queued = *(queued_ptr + word); + uint32_t acked = *(acked_ptr + word); + for (j = 0; j < 32; j++, i++) { + if (queued & (1 << j)) { + queued_str[i] = '1'; + acked_str[i] = (acked & (1 << j)) ? 'y' : 'N'; + } + } + } + queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + cdf_print("%s\n", queued_str); + cdf_print("%s\n", acked_str); +} + +static inline uint16_t htt_msg_read16(uint16_t *p16) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. This results in the lower and upper bytes + * of each uint16_t to be in the correct big-endian order with + * respect to each other, but for each even-index uint16_t to + * have its position switched with its successor neighbor uint16_t. + * Undo this uint16_t position swapping. + */ + return (((size_t) p16) & 0x2) ? *(p16 - 1) : *(p16 + 1); +#else + return *p16; +#endif +} + +static inline uint8_t htt_msg_read8(uint8_t *p8) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. + * Undo this byte swapping. + */ + switch (((size_t) p8) & 0x3) { + case 0: + return *(p8 + 3); + case 1: + return *(p8 + 1); + case 2: + return *(p8 - 1); + default /* 3 */: + return *(p8 - 3); + } +#else + return *p8; +#endif +} + +void htt_make_u8_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint8_t *p8 = (uint8_t *) aligned_data; + char *buf_p = buffer; + while (max_elems-- > 0) { + int bytes; + uint8_t val; + + val = htt_msg_read8(p8); + if (val == 0) + /* not enough data to fill the reserved msg buffer*/ + break; + + bytes = cdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + p8++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ + +} + +void htt_make_u16_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint16_t *p16 = (uint16_t *) aligned_data; + char *buf_p = buffer; + while (max_elems-- > 0) { + int bytes; + uint16_t val; + + val = htt_msg_read16(p16); + if (val == 0) + /* not enough data to fill the reserved msg buffer */ + break; + bytes = cdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + + p16++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ +} + +void +htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr, + struct ol_fw_tx_dbg_ppdu_base *record, + int length, int concise) +{ + int i; + int record_size; + int num_records; + + record_size = + sizeof(*record) + + hdr->mpdu_bytes_array_len * sizeof(uint16_t) + + hdr->mpdu_msdus_array_len * sizeof(uint8_t) + + hdr->msdu_bytes_array_len * sizeof(uint16_t); + num_records = (length - sizeof(*hdr)) / record_size; + cdf_print("Tx PPDU log elements:\n"); + + for (i = 0; i < num_records; i++) { + uint16_t start_seq_num; + uint16_t start_pn_lsbs; + uint8_t num_mpdus; + uint16_t peer_id; + uint8_t ext_tid; + uint8_t rate_code; + uint8_t rate_flags; + uint8_t tries; + uint8_t complete; + uint32_t time_enqueue_us; + uint32_t time_completion_us; + uint32_t *msg_word = (uint32_t *) record; + + /* fields used for both concise and complete printouts */ + start_seq_num = + ((*(msg_word + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_16)) & + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M) >> + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S; + complete = + ((*(msg_word + OL_FW_TX_DBG_PPDU_COMPLETE_16)) & + OL_FW_TX_DBG_PPDU_COMPLETE_M) >> + OL_FW_TX_DBG_PPDU_COMPLETE_S; + + /* fields used only for complete printouts */ + if (!concise) { +#define BUF_SIZE 80 + char buf[BUF_SIZE]; + uint8_t *p8; + time_enqueue_us = + HTT_TICK_TO_USEC(record->timestamp_enqueue, + hdr->microsec_per_tick); + time_completion_us = + HTT_TICK_TO_USEC(record->timestamp_completion, + hdr->microsec_per_tick); + + start_pn_lsbs = + ((* + (msg_word + + OL_FW_TX_DBG_PPDU_START_PN_LSBS_16)) & + OL_FW_TX_DBG_PPDU_START_PN_LSBS_M) >> + OL_FW_TX_DBG_PPDU_START_PN_LSBS_S; + num_mpdus = + ((*(msg_word + OL_FW_TX_DBG_PPDU_NUM_MPDUS_16))& + OL_FW_TX_DBG_PPDU_NUM_MPDUS_M) >> + OL_FW_TX_DBG_PPDU_NUM_MPDUS_S; + peer_id = + ((*(msg_word + OL_FW_TX_DBG_PPDU_PEER_ID_16)) & + OL_FW_TX_DBG_PPDU_PEER_ID_M) >> + OL_FW_TX_DBG_PPDU_PEER_ID_S; + ext_tid = + ((*(msg_word + OL_FW_TX_DBG_PPDU_EXT_TID_16)) & + OL_FW_TX_DBG_PPDU_EXT_TID_M) >> + OL_FW_TX_DBG_PPDU_EXT_TID_S; + rate_code = + ((*(msg_word + OL_FW_TX_DBG_PPDU_RATE_CODE_16))& + OL_FW_TX_DBG_PPDU_RATE_CODE_M) >> + OL_FW_TX_DBG_PPDU_RATE_CODE_S; + rate_flags = + ((*(msg_word + OL_FW_TX_DBG_PPDU_RATEFLAGS_16))& + OL_FW_TX_DBG_PPDU_RATE_FLAGS_M) >> + OL_FW_TX_DBG_PPDU_RATE_FLAGS_S; + tries = + ((*(msg_word + OL_FW_TX_DBG_PPDU_TRIES_16)) & + OL_FW_TX_DBG_PPDU_TRIES_M) >> + OL_FW_TX_DBG_PPDU_TRIES_S; + + cdf_print(" - PPDU tx to peer %d, TID %d\n", peer_id, + ext_tid); + cdf_print + (" start seq num= %u, start PN LSBs= %#04x\n", + start_seq_num, start_pn_lsbs); + cdf_print + (" PPDU: %d MPDUs, (?) MSDUs, %d bytes\n", + num_mpdus, + /* num_msdus - not yet computed in target */ + record->num_bytes); + if (complete) { + cdf_print + (" enqueued: %u, completed: %u usec)\n", + time_enqueue_us, time_completion_us); + cdf_print + (" %d tries, last tx used rate %d ", + tries, rate_code); + cdf_print("on %d MHz chan (flags = %#x)\n", + htt_rate_flags_to_mhz + (rate_flags), rate_flags); + cdf_print + (" enqueued and acked MPDU bitmaps:\n"); + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_16, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_16); + } else { + cdf_print + (" enqueued: %d us, not yet completed\n", + time_enqueue_us); + } + /* skip the regular msg fields to reach the tail area */ + p8 = (uint8_t *) record; + p8 += sizeof(struct ol_fw_tx_dbg_ppdu_base); + if (hdr->mpdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + mpdu_bytes_array_len); + cdf_print(" MPDU bytes: %s\n", buf); + } + p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t); + if (hdr->mpdu_msdus_array_len) { + htt_make_u8_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr->mpdu_msdus_array_len); + cdf_print(" MPDU MSDUs: %s\n", buf); + } + p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t); + if (hdr->msdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + msdu_bytes_array_len); + cdf_print(" MSDU bytes: %s\n", buf); + } + } else { + /* concise */ + cdf_print("start seq num = %u ", start_seq_num); + cdf_print("enqueued and acked MPDU bitmaps:\n"); + if (complete) { + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_16, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_16); + } else { + cdf_print("(not completed)\n"); + } + } + record = (struct ol_fw_tx_dbg_ppdu_base *) + (((uint8_t *) record) + record_size); + } +} + +void htt_t2h_stats_print(uint8_t *stats_data, int concise) +{ + uint32_t *msg_word = (uint32_t *) stats_data; + enum htt_dbg_stats_type type; + enum htt_dbg_stats_status status; + int length; + + type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + length = HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); + + /* check that we've been given a valid stats type */ + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) { + return; + } else if (status == HTT_DBG_STATS_STATUS_INVALID) { + cdf_print("Target doesn't support stats type %d\n", type); + return; + } else if (status == HTT_DBG_STATS_STATUS_ERROR) { + cdf_print("Target couldn't upload stats type %d (no mem?)\n", + type); + return; + } + /* got valid (though perhaps partial) stats - process them */ + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + { + struct wlan_dbg_stats *wlan_dbg_stats_ptr; + + wlan_dbg_stats_ptr = + (struct wlan_dbg_stats *)(msg_word + 1); + htt_t2h_stats_pdev_stats_print(wlan_dbg_stats_ptr, + concise); + break; + } + case HTT_DBG_STATS_RX_REORDER: + { + struct rx_reorder_stats *rx_reorder_stats_ptr; + + rx_reorder_stats_ptr = + (struct rx_reorder_stats *)(msg_word + 1); + htt_t2h_stats_rx_reorder_stats_print + (rx_reorder_stats_ptr, concise); + break; + } + + case HTT_DBG_STATS_RX_RATE_INFO: + { + wlan_dbg_rx_rate_info_t *rx_phy_info; + rx_phy_info = + (wlan_dbg_rx_rate_info_t *) (msg_word + 1); + + htt_t2h_stats_rx_rate_stats_print(rx_phy_info, concise); + + break; + } + case HTT_DBG_STATS_RX_RATE_INFO_V2: + { + wlan_dbg_rx_rate_info_v2_t *rx_phy_info; + rx_phy_info = + (wlan_dbg_rx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_rx_rate_stats_print_v2(rx_phy_info, concise); + break; + } + case HTT_DBG_STATS_TX_PPDU_LOG: + { + struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr; + struct ol_fw_tx_dbg_ppdu_base *record; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL + && length == 0) { + cdf_print + ("HTT_DBG_STATS_TX_PPDU_LOG -- length = 0!\n"); + break; + } + hdr = + (struct ol_fw_tx_dbg_ppdu_msg_hdr *)(msg_word + 1); + record = (struct ol_fw_tx_dbg_ppdu_base *)(hdr + 1); + htt_t2h_tx_ppdu_log_print(hdr, record, length, concise); + } + break; + case HTT_DBG_STATS_TX_RATE_INFO: + { + wlan_dbg_tx_rate_info_t *tx_rate_info; + tx_rate_info = + (wlan_dbg_tx_rate_info_t *) (msg_word + 1); + + htt_t2h_stats_tx_rate_stats_print(tx_rate_info, concise); + + break; + } + case HTT_DBG_STATS_TX_RATE_INFO_V2: + { + wlan_dbg_tx_rate_info_v2_t *tx_rate_info; + tx_rate_info = + (wlan_dbg_tx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_tx_rate_stats_print_v2(tx_rate_info, concise); + break; + } + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + { + struct rx_remote_buffer_mgmt_stats *rx_rem_buf; + + rx_rem_buf = (struct rx_remote_buffer_mgmt_stats *)(msg_word + 1); + htt_t2h_stats_rx_rem_buf_stats_print(rx_rem_buf, concise); + break; + } + case HTT_DBG_STATS_TXBF_INFO: + { + struct wlan_dbg_txbf_data_stats *txbf_info_buf; + + txbf_info_buf = + (struct wlan_dbg_txbf_data_stats *)(msg_word + 1); + htt_t2h_stats_txbf_info_buf_stats_print(txbf_info_buf); + break; + } + case HTT_DBG_STATS_SND_INFO: + { + struct wlan_dbg_txbf_snd_stats *txbf_snd_buf; + + txbf_snd_buf = + (struct wlan_dbg_txbf_snd_stats *)(msg_word + 1); + htt_t2h_stats_txbf_snd_buf_stats_print(txbf_snd_buf); + break; + } + case HTT_DBG_STATS_TX_SELFGEN_INFO: + { + struct wlan_dbg_tx_selfgen_stats *tx_selfgen_buf; + + tx_selfgen_buf = + (struct wlan_dbg_tx_selfgen_stats *)(msg_word + 1); + htt_t2h_stats_tx_selfgen_buf_stats_print(tx_selfgen_buf); + break; + } + case HTT_DBG_STATS_ERROR_INFO: + { + struct wlan_dbg_wifi2_error_stats *wifi2_error_buf; + + wifi2_error_buf = + (struct wlan_dbg_wifi2_error_stats *)(msg_word + 1); + htt_t2h_stats_wifi2_error_stats_print(wifi2_error_buf); + break; + } + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + { + struct rx_txbf_musu_ndpa_pkts_stats *rx_musu_ndpa_stats; + + rx_musu_ndpa_stats = (struct rx_txbf_musu_ndpa_pkts_stats *) + (msg_word + 1); + htt_t2h_rx_musu_ndpa_pkts_stats_print(rx_musu_ndpa_stats); + break; + } + default: + break; + } +} diff --git a/core/dp/htt/htt_h2t.c b/core/dp/htt/htt_h2t.c new file mode 100644 index 0000000000..437460ca0d --- /dev/null +++ b/core/dp/htt/htt_h2t.c @@ -0,0 +1,904 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_h2t.c + * @brief Provide functions to send host->target HTT messages. + * @details + * This file contains functions related to host->target HTT messages. + * There are a couple aspects of this host->target messaging: + * 1. This file contains the function that is called by HTC when + * a host->target send completes. + * This send-completion callback is primarily relevant to HL, + * to invoke the download scheduler to set up a new download, + * and optionally free the tx frame whose download is completed. + * For both HL and LL, this completion callback frees up the + * HTC_PACKET object used to specify the download. + * 2. This file contains functions for creating messages to send + * from the host to the target. + */ + +#include /* cdf_mem_copy */ +#include /* cdf_nbuf_map_single */ +#include /* HTC_PACKET */ +#include /* HTC_HDR_ALIGNMENT_PADDING */ +#include /* HTT host->target msg defs */ +#include /* ol_tx_completion_handler, htt_tx_status */ +#include + +#include + +#define HTT_MSG_BUF_SIZE(msg_bytes) \ + ((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING) + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +static void +htt_h2t_send_complete_free_netbuf(void *pdev, A_STATUS status, + cdf_nbuf_t netbuf, uint16_t msdu_id) +{ + cdf_nbuf_free(netbuf); +} + +void htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) +{ + void (*send_complete_part2)(void *pdev, A_STATUS status, + cdf_nbuf_t msdu, uint16_t msdu_id); + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + struct htt_htc_pkt *htt_pkt; + cdf_nbuf_t netbuf; + + send_complete_part2 = htc_pkt->pPktContext; + + htt_pkt = container_of(htc_pkt, struct htt_htc_pkt, htc_pkt); + + /* process (free or keep) the netbuf that held the message */ + netbuf = (cdf_nbuf_t) htc_pkt->pNetBufContext; + if (send_complete_part2 != NULL) { + send_complete_part2(htt_pkt->pdev_ctxt, htc_pkt->Status, netbuf, + htt_pkt->msdu_id); + } + /* free the htt_htc_pkt / HTC_PACKET object */ + htt_htc_pkt_free(pdev, htt_pkt); +} + +HTC_SEND_FULL_ACTION htt_h2t_full(void *context, HTC_PACKET *pkt) +{ +/* FIX THIS */ + return HTC_SEND_FULL_KEEP; +} + +#if defined(HELIUMPLUS_PADDR64) +A_STATUS htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev) +{ + A_STATUS rc = A_OK; + + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + u_int32_t *msg_word; + struct htt_tx_frag_desc_bank_cfg_t *bank_cfg; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = cdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(sizeof(struct htt_tx_frag_desc_bank_cfg_t)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + cdf_nbuf_put_tail(msg, sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + + /* fill in the message contents */ + msg_word = (u_int32_t *) cdf_nbuf_data(msg); + + memset(msg_word, 0 , sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG); + + bank_cfg = (struct htt_tx_frag_desc_bank_cfg_t *)msg_word; + + /** @note @todo Hard coded to 0 Assuming just one pdev for now.*/ + HTT_H2T_FRAG_DESC_BANK_PDEVID_SET(*msg_word, 0); + /** @note Hard coded to 1.*/ + HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_SET(*msg_word, 1); + HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_SET(*msg_word, pdev->frag_descs.size); + HTT_H2T_FRAG_DESC_BANK_SWAP_SET(*msg_word, 0); + + /** Bank specific data structure.*/ +#if HTT_PADDR64 + bank_cfg->bank_base_address[0].lo = pdev->frag_descs.pool_paddr; + bank_cfg->bank_base_address[0].hi = 0; +#else /* ! HTT_PADDR64 */ + bank_cfg->bank_base_address[0] = pdev->frag_descs.pool_paddr; +#endif /* HTT_PADDR64 */ + /* Logical Min index */ + HTT_H2T_FRAG_DESC_BANK_MIN_IDX_SET(bank_cfg->bank_info[0], 0); + /* Logical Max index */ + HTT_H2T_FRAG_DESC_BANK_MAX_IDX_SET(bank_cfg->bank_info[0], + pdev->frag_descs.pool_elems-1); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + rc = htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); + + return rc; +} + +#endif /* defined(HELIUMPLUS_PADDR64) */ + +A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to cdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + cdf_nbuf_put_tail(msg, HTT_VER_REQ_BYTES); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + return A_OK; +} + +A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + int enable_ctrl_data, enable_mgmt_data, + enable_null_data, enable_phy_data, enable_hdr, + enable_ppdu_start, enable_ppdu_end; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to cdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + cdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_SET(*msg_word, + pdev->rx_ring.alloc_idx.paddr); + msg_word++; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_SET(*msg_word, 0); +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET(*msg_word, + pdev->rx_ring.alloc_idx.paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_BASE_PADDR_LO_SET(*msg_word, + pdev->rx_ring.base_paddr); + msg_word++; + HTT_RX_RING_CFG_BASE_PADDR_HI_SET(*msg_word, 0); +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + +/* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. + */ + msg_word++; + *msg_word = 0; +#ifndef REMOVE_PKT_LOG + if (ol_cfg_is_packet_log_enabled(pdev->ctrl_pdev)) { + enable_ctrl_data = 1; + enable_mgmt_data = 1; + enable_null_data = 1; + enable_phy_data = 1; + enable_hdr = 1; + enable_ppdu_start = 1; + enable_ppdu_end = 1; + /* Disable ASPM when pkt log is enabled */ + cdf_print("Pkt log is enabled\n"); + htt_htc_disable_aspm(); + } else { + cdf_print("Pkt log is disabled\n"); + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; + } +#else + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; +#endif + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, enable_hdr); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, enable_ppdu_start); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, enable_ppdu_end); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 1); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, enable_ctrl_data); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, enable_mgmt_data); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, enable_null_data); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, enable_phy_data); + HTT_RX_RING_CFG_IDX_INIT_VAL_SET(*msg_word, + *pdev->rx_ring.alloc_idx.vaddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + RX_DESC_HDR_STATUS_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + HTT_RX_DESC_RESERVATION32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + RX_DESC_PPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + RX_DESC_PPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + RX_DESC_MPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + RX_DESC_MPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + RX_DESC_MSDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + RX_DESC_MSDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + RX_DESC_ATTN_OFFSET32); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + RX_DESC_FRAG_INFO_OFFSET32); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + return A_OK; +} + +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stat_type, uint32_t cfg_val, uint64_t cookie) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + if (stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + /* FIX THIS - add more details? */ + cdf_print("%#x %#x stats not supported\n", + stats_type_upload_mask, stats_type_reset_mask); + return -EINVAL; /* failure */ + } + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + + msg = cdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_H2T_STATS_REQ_MSG_SZ), + /* reserve room for HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_H2T_STATS_REQ_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_STATS_REQ); + HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(*msg_word, stats_type_upload_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_RESET_TYPES_SET(*msg_word, stats_type_reset_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_CFG_VAL_SET(*msg_word, cfg_val); + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(*msg_word, cfg_stat_type); + + /* cookie LSBs */ + msg_word++; + *msg_word = cookie & 0xffffffff; + + /* cookie MSBs */ + msg_word++; + *msg_word = cookie >> 32; + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + return 0; +} + +A_STATUS htt_h2t_sync_msg(struct htt_pdev_t *pdev, uint8_t sync_cnt) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_H2T_SYNC_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_H2T_SYNC_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_SYNC); + HTT_H2T_SYNC_COUNT_SET(*msg_word, sync_cnt); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + return A_OK; +} + +int +htt_h2t_aggr_cfg_msg(struct htt_pdev_t *pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_AGGR_CFG_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_AGGR_CFG_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_AGGR_CFG); + + if (max_subfrms_ampdu && (max_subfrms_ampdu <= 64)) { + HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_SET(*msg_word, + max_subfrms_ampdu); + } + + if (max_subfrms_amsdu && (max_subfrms_amsdu < 32)) { + HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_SET(*msg_word, + max_subfrms_amsdu); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + return 0; +} + +#ifdef IPA_OFFLOAD +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); + + msg_word++; + *msg_word = 0; + /* TX COMP RING BASE LO */ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_base.paddr); + msg_word++; + *msg_word = 0; + /* TX COMP RING BASE HI, NONE */ + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(*msg_word, + (unsigned int)ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + msg_word++; + *msg_word = 0; + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr); + msg_word++; + *msg_word = 0; + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, + (unsigned int)ol_cfg_ipa_uc_rx_ind_ring_size(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_SIZE_SET(*msg_word, + (unsigned int)ol_cfg_ipa_uc_rx_ind_ring_size(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx2_rdy_idx_paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_SET(*msg_word, + 0); + + cdf_trace_hex_dump(CDF_MODULE_ID_HTT, CDF_TRACE_LEVEL_FATAL, + (void *)cdf_nbuf_data(msg), 40); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); + + return A_OK; +} + +int htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, + bool uc_active, bool is_tx) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + uint8_t active_target = 0; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + if (uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_RESUME; + else if (!uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_SUSPEND; + else if (uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_RESUME; + else if (!uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_SUSPEND; + + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, active_target); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); + + return A_OK; +} + +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + cdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = cdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + cdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) cdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + cdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_DBG_STATS); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + cdf_nbuf_data(msg), + cdf_nbuf_len(msg), + pdev->htc_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); + + return A_OK; +} +#endif /* IPA_OFFLOAD */ diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h new file mode 100644 index 0000000000..1bc710f736 --- /dev/null +++ b/core/dp/htt/htt_internal.h @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTT_INTERNAL__H_ +#define _HTT_INTERNAL__H_ + +#include /* A_STATUS */ +#include /* cdf_nbuf_t */ +#include /* cdf_assert */ +#include /* HTC_PACKET */ + +#include + +#ifndef offsetof +#define offsetof(type, field) ((size_t)(&((type *)0)->field)) +#endif + +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) + +#include +#include /* struct rx_attention, etc */ + +struct htt_host_fw_desc_base { + union { + struct fw_rx_desc_base val; + A_UINT32 dummy_pad; /* make sure it is DOWRD aligned */ + } u; +}; + +/* + * This struct defines the basic descriptor information used by host, + * which is written either by the 11ac HW MAC into the host Rx data + * buffer ring directly or generated by FW and copied from Rx indication + */ +#define RX_HTT_HDR_STATUS_LEN 64 +struct htt_host_rx_desc_base { + struct htt_host_fw_desc_base fw_desc; + struct rx_attention attention; + struct rx_frag_info frag_info; + struct rx_mpdu_start mpdu_start; + struct rx_msdu_start msdu_start; + struct rx_msdu_end msdu_end; + struct rx_mpdu_end mpdu_end; + struct rx_ppdu_start ppdu_start; + struct rx_ppdu_end ppdu_end; + char rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; +}; + +#define RX_STD_DESC_ATTN_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, attention)) +#define RX_STD_DESC_FRAG_INFO_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, frag_info)) +#define RX_STD_DESC_MPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_start)) +#define RX_STD_DESC_MSDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_start)) +#define RX_STD_DESC_MSDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_end)) +#define RX_STD_DESC_MPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_end)) +#define RX_STD_DESC_PPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_start)) +#define RX_STD_DESC_PPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_end)) +#define RX_STD_DESC_HDR_STATUS_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, rx_hdr_status)) + +#define RX_STD_DESC_FW_MSDU_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, fw_desc)) + +#define RX_STD_DESC_SIZE (sizeof(struct htt_host_rx_desc_base)) + +#define RX_DESC_ATTN_OFFSET32 (RX_STD_DESC_ATTN_OFFSET >> 2) +#define RX_DESC_FRAG_INFO_OFFSET32 (RX_STD_DESC_FRAG_INFO_OFFSET >> 2) +#define RX_DESC_MPDU_START_OFFSET32 (RX_STD_DESC_MPDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_START_OFFSET32 (RX_STD_DESC_MSDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_END_OFFSET32 (RX_STD_DESC_MSDU_END_OFFSET >> 2) +#define RX_DESC_MPDU_END_OFFSET32 (RX_STD_DESC_MPDU_END_OFFSET >> 2) +#define RX_DESC_PPDU_START_OFFSET32 (RX_STD_DESC_PPDU_START_OFFSET >> 2) +#define RX_DESC_PPDU_END_OFFSET32 (RX_STD_DESC_PPDU_END_OFFSET >> 2) +#define RX_DESC_HDR_STATUS_OFFSET32 (RX_STD_DESC_HDR_STATUS_OFFSET >> 2) + +#define RX_STD_DESC_SIZE_DWORD (RX_STD_DESC_SIZE >> 2) + +/* + * Make sure there is a minimum headroom provided in the rx netbufs + * for use by the OS shim and OS and rx data consumers. + */ +#define HTT_RX_BUF_OS_MIN_HEADROOM 32 +#define HTT_RX_STD_DESC_RESERVATION \ + ((HTT_RX_BUF_OS_MIN_HEADROOM > RX_STD_DESC_SIZE) ? \ + HTT_RX_BUF_OS_MIN_HEADROOM : RX_STD_DESC_SIZE) +#define HTT_RX_DESC_RESERVATION32 \ + (HTT_RX_STD_DESC_RESERVATION >> 2) + +#define HTT_RX_DESC_ALIGN_MASK 7 /* 8-byte alignment */ +static inline struct htt_host_rx_desc_base *htt_rx_desc(cdf_nbuf_t msdu) +{ + return (struct htt_host_rx_desc_base *) + (((size_t) (cdf_nbuf_head(msdu) + HTT_RX_DESC_ALIGN_MASK)) & + ~HTT_RX_DESC_ALIGN_MASK); +} + +#if defined(FEATURE_LRO) +/** + * htt_print_rx_desc_lro() - print LRO information in the rx + * descriptor + * @rx_desc: HTT rx descriptor + * + * Prints the LRO related fields in the HTT rx descriptor + * + * Return: none + */ +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{ + cdf_print + ("----------------------RX DESC LRO----------------------\n"); + cdf_print("msdu_end.lro_eligible:0x%x\n", + rx_desc->msdu_end.lro_eligible); + cdf_print("msdu_start.tcp_only_ack:0x%x\n", + rx_desc->msdu_start.tcp_only_ack); + cdf_print("msdu_end.tcp_udp_chksum:0x%x\n", + rx_desc->msdu_end.tcp_udp_chksum); + cdf_print("msdu_end.tcp_seq_number:0x%x\n", + rx_desc->msdu_end.tcp_seq_number); + cdf_print("msdu_end.tcp_ack_number:0x%x\n", + rx_desc->msdu_end.tcp_ack_number); + cdf_print("msdu_start.tcp_proto:0x%x\n", + rx_desc->msdu_start.tcp_proto); + cdf_print("msdu_start.ipv6_proto:0x%x\n", + rx_desc->msdu_start.ipv6_proto); + cdf_print("msdu_start.ipv4_proto:0x%x\n", + rx_desc->msdu_start.ipv4_proto); + cdf_print("msdu_start.l3_offset:0x%x\n", + rx_desc->msdu_start.l3_offset); + cdf_print("msdu_start.l4_offset:0x%x\n", + rx_desc->msdu_start.l4_offset); + cdf_print("msdu_start.flow_id_toeplitz:0x%x\n", + rx_desc->msdu_start.flow_id_toeplitz); + cdf_print + ("---------------------------------------------------------\n"); +} + +/** + * htt_print_rx_desc_lro() - extract LRO information from the rx + * descriptor + * @msdu: network buffer + * @rx_desc: HTT rx descriptor + * + * Extracts the LRO related fields from the HTT rx descriptor + * and stores them in the network buffer's control block + * + * Return: none + */ +static inline void htt_rx_extract_lro_info(cdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + NBUF_LRO_ELIGIBLE(msdu) = rx_desc->msdu_end.lro_eligible; + if (rx_desc->msdu_end.lro_eligible) { + NBUF_TCP_PURE_ACK(msdu) = rx_desc->msdu_start.tcp_only_ack; + NBUF_TCP_CHKSUM(msdu) = rx_desc->msdu_end.tcp_udp_chksum; + NBUF_TCP_SEQ_NUM(msdu) = rx_desc->msdu_end.tcp_seq_number; + NBUF_TCP_ACK_NUM(msdu) = rx_desc->msdu_end.tcp_ack_number; + NBUF_TCP_WIN(msdu) = rx_desc->msdu_end.window_size; + NBUF_TCP_PROTO(msdu) = rx_desc->msdu_start.tcp_proto; + NBUF_IPV6_PROTO(msdu) = rx_desc->msdu_start.ipv6_proto; + NBUF_IP_OFFSET(msdu) = rx_desc->msdu_start.l3_offset; + NBUF_TCP_OFFSET(msdu) = rx_desc->msdu_start.l4_offset; + NBUF_FLOW_ID_TOEPLITZ(msdu) = + rx_desc->msdu_start.flow_id_toeplitz; + } +} +#else +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{} +static inline void htt_rx_extract_lro_info(cdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) {} +#endif /* FEATURE_LRO */ + +static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc) +{ + cdf_print + ("----------------------RX DESC----------------------------\n"); + cdf_print("attention: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->attention)); + cdf_print("frag_info: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->frag_info)); + cdf_print("mpdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[2])); + cdf_print("msdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[2])); + cdf_print("msdu_end: %#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[0]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[1]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[2]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[3]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[4])); + cdf_print("mpdu_end: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->mpdu_end)); + cdf_print("ppdu_start: " "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[2]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[3]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[4]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[5]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[6]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[7]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[8]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[9])); + cdf_print("ppdu_end:" "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x,%#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" "%#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[0]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[1]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[2]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[3]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[4]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[5]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[6]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[7]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[8]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[9]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[10]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[11]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[12]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[13]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[14]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[15]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[16]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[17]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[18]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[19]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[20]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[21])); + cdf_print + ("---------------------------------------------------------\n"); +} + +#ifndef HTT_ASSERT_LEVEL +#define HTT_ASSERT_LEVEL 3 +#endif + +#define HTT_ASSERT_ALWAYS(condition) cdf_assert_always((condition)) + +#define HTT_ASSERT0(condition) cdf_assert((condition)) +#if HTT_ASSERT_LEVEL > 0 +#define HTT_ASSERT1(condition) cdf_assert((condition)) +#else +#define HTT_ASSERT1(condition) +#endif + +#if HTT_ASSERT_LEVEL > 1 +#define HTT_ASSERT2(condition) cdf_assert((condition)) +#else +#define HTT_ASSERT2(condition) +#endif + +#if HTT_ASSERT_LEVEL > 2 +#define HTT_ASSERT3(condition) cdf_assert((condition)) +#else +#define HTT_ASSERT3(condition) +#endif + +#define HTT_MAC_ADDR_LEN 6 + +/* + * HTT_MAX_SEND_QUEUE_DEPTH - + * How many packets HTC should allow to accumulate in a send queue + * before calling the EpSendFull callback to see whether to retain + * or drop packets. + * This is not relevant for LL, where tx descriptors should be immediately + * downloaded to the target. + * This is not very relevant for HL either, since it is anticipated that + * the HL tx download scheduler will not work this far in advance - rather, + * it will make its decisions just-in-time, so it can be responsive to + * changing conditions. + * Hence, this queue depth threshold spec is mostly just a formality. + */ +#define HTT_MAX_SEND_QUEUE_DEPTH 64 + +#define IS_PWR2(value) (((value) ^ ((value)-1)) == ((value) << 1) - 1) + +/* FIX THIS + * Should be: sizeof(struct htt_host_rx_desc) + max rx MSDU size, + * rounded up to a cache line size. + */ +#define HTT_RX_BUF_SIZE 1920 +/* + * DMA_MAP expects the buffer to be an integral number of cache lines. + * Rather than checking the actual cache line size, this code makes a + * conservative estimate of what the cache line size could be. + */ +#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ +#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) + +#ifdef BIG_ENDIAN_HOST +/* + * big-endian: bytes within a 4-byte "word" are swapped: + * pre-swap post-swap + * index index + * 0 3 + * 1 2 + * 2 1 + * 3 0 + * 4 7 + * 5 6 + * etc. + * To compute the post-swap index from the pre-swap index, compute + * the byte offset for the start of the word (index & ~0x3) and add + * the swapped byte offset within the word (3 - (index & 0x3)). + */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) (((idx) & ~0x3) + (3 - ((idx) & 0x3))) +#else +/* little-endian: no adjustment needed */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) idx +#endif + +#define HTT_TX_MUTEX_INIT(_mutex) \ + cdf_spinlock_init(_mutex) + +#define HTT_TX_MUTEX_ACQUIRE(_mutex) \ + cdf_spin_lock_bh(_mutex) + +#define HTT_TX_MUTEX_RELEASE(_mutex) \ + cdf_spin_unlock_bh(_mutex) + +#define HTT_TX_MUTEX_DESTROY(_mutex) \ + cdf_spinlock_destroy(_mutex) + +#define HTT_TX_DESC_PADDR(_pdev, _tx_desc_vaddr) \ + ((_pdev)->tx_descs.pool_paddr + (uint32_t) \ + ((char *)(_tx_desc_vaddr) - \ + (char *)((_pdev)->tx_descs.pool_vaddr))) + +#ifdef ATH_11AC_TXCOMPACT + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) \ + cdf_spinlock_init(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) \ + HTT_TX_MUTEX_DESTROY(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + _msdu = cdf_nbuf_queue_remove(&_pdev->txnbufq);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + cdf_nbuf_queue_add(&_pdev->txnbufq, _msdu); \ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + cdf_nbuf_queue_insert_head(&_pdev->txnbufq, _msdu);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) +#else + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) + +#endif + +#ifdef ATH_11AC_TXCOMPACT +#define HTT_TX_SCHED htt_tx_sched +#else +#define HTT_TX_SCHED(pdev) /* no-op */ +#endif + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems); + +void htt_tx_detach(struct htt_pdev_t *pdev); + +int htt_rx_attach(struct htt_pdev_t *pdev); + +void htt_rx_detach(struct htt_pdev_t *pdev); + +int htt_htc_attach(struct htt_pdev_t *pdev); + +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt); + +void htt_h2t_send_complete(void *context, HTC_PACKET *pkt); + +A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev); + +#if defined(HELIUMPLUS_PADDR64) +A_STATUS +htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev); +#endif /* defined(HELIUMPLUS_PADDR64) */ + +extern A_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); +extern A_STATUS (*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); + +HTC_SEND_FULL_ACTION htt_h2t_full(void *context, HTC_PACKET *pkt); + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev); + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev); + +#ifdef ATH_11AC_TXCOMPACT +void +htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev); +#endif + +void htt_htc_disable_aspm(void); + +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, uint32_t paddr, + cdf_nbuf_t netbuf); + +cdf_nbuf_t htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, uint32_t paddr); + +#ifdef IPA_OFFLOAD +int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base); + +int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size); + +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev); + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev); +#else +static inline int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + return 0; +} + +static inline int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size) +{ + return 0; +} + +static inline int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} +#endif /* IPA_OFFLOAD */ +#endif /* _HTT_INTERNAL__H_ */ diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c new file mode 100644 index 0000000000..697763d091 --- /dev/null +++ b/core/dp/htt/htt_rx.c @@ -0,0 +1,2444 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_rx.c + * @brief Implement receive aspects of HTT. + * @details + * This file contains three categories of HTT rx code: + * 1. An abstraction of the rx descriptor, to hide the + * differences between the HL vs. LL rx descriptor. + * 2. Functions for providing access to the (series of) + * rx descriptor(s) and rx frame(s) associated with + * an rx indication message. + * 3. Functions for setting up and using the MAC DMA + * rx ring (applies to LL only). + */ + +#include /* cdf_mem_malloc,free, etc. */ +#include /* cdf_print, bool */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_softirq_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include /* ieee80211_rx_status */ + +#ifdef DEBUG_DMA_DONE +#include +#include +#endif + +/* AR9888v1 WORKAROUND for EV#112367 */ +/* FIX THIS - remove this WAR when the bug is fixed */ +#define PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR + +/*--- setup / tear-down functions -------------------------------------------*/ + +#ifndef HTT_RX_RING_SIZE_MIN +#define HTT_RX_RING_SIZE_MIN 128 /* slightly > than one large A-MPDU */ +#endif + +#ifndef HTT_RX_RING_SIZE_MAX +#define HTT_RX_RING_SIZE_MAX 2048 /* ~20 ms @ 1 Gbps of 1500B MSDUs */ +#endif + +#ifndef HTT_RX_AVG_FRM_BYTES +#define HTT_RX_AVG_FRM_BYTES 1000 +#endif + +#ifndef HTT_RX_HOST_LATENCY_MAX_MS +#define HTT_RX_HOST_LATENCY_MAX_MS 20 /* ms */ /* very conservative */ +#endif + +#ifndef HTT_RX_HOST_LATENCY_WORST_LIKELY_MS +#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10 /* ms */ /* conservative */ +#endif + +#ifndef HTT_RX_RING_REFILL_RETRY_TIME_MS +#define HTT_RX_RING_REFILL_RETRY_TIME_MS 50 +#endif + +/*--- RX In Order Definitions ------------------------------------------------*/ + +/* Number of buckets in the hash table */ +#define RX_NUM_HASH_BUCKETS 1024 /* This should always be a power of 2 */ +#define RX_NUM_HASH_BUCKETS_MASK (RX_NUM_HASH_BUCKETS - 1) + +/* Number of hash entries allocated per bucket */ +#define RX_ENTRIES_SIZE 10 + +#define RX_HASH_FUNCTION(a) (((a >> 14) ^ (a >> 4)) & RX_NUM_HASH_BUCKETS_MASK) + +#ifdef RX_HASH_DEBUG_LOG +#define RX_HASH_LOG(x) x +#else +#define RX_HASH_LOG(x) /* no-op */ +#endif + +/* De -initialization function of the rx buffer hash table. This function will + free up the hash table which includes freeing all the pending rx buffers*/ +void htt_rx_hash_deinit(struct htt_pdev_t *pdev) +{ + + uint32_t i; + struct htt_rx_hash_entry *hash_entry; + struct htt_list_node *list_iter = NULL; + + if (NULL == pdev->rx_ring.hash_table) + return; + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + /* Free the hash entries in hash bucket i */ + list_iter = pdev->rx_ring.hash_table[i].listhead.next; + while (list_iter != &pdev->rx_ring.hash_table[i].listhead) { + hash_entry = + (struct htt_rx_hash_entry *)((char *)list_iter - + pdev->rx_ring. + listnode_offset); + if (hash_entry->netbuf) { + cdf_nbuf_free(hash_entry->netbuf); + hash_entry->paddr = 0; + } + list_iter = list_iter->next; + + if (!hash_entry->fromlist) + cdf_mem_free(hash_entry); + } + + cdf_mem_free(pdev->rx_ring.hash_table[i].entries); + + } + cdf_mem_free(pdev->rx_ring.hash_table); + pdev->rx_ring.hash_table = NULL; +} + +static int ceil_pwr2(int value) +{ + int log2; + if (IS_PWR2(value)) + return value; + + log2 = 0; + while (value) { + value >>= 1; + log2++; + } + return 1 << log2; +} + +static bool +htt_rx_msdu_first_msdu_flag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> + RX_MSDU_END_4_FIRST_MSDU_LSB); +} + +static int htt_rx_ring_size(struct htt_pdev_t *pdev) +{ + int size; + + /* + * It is expected that the host CPU will typically be able to service + * the rx indication from one A-MPDU before the rx indication from + * the subsequent A-MPDU happens, roughly 1-2 ms later. + * However, the rx ring should be sized very conservatively, to + * accomodate the worst reasonable delay before the host CPU services + * a rx indication interrupt. + * The rx ring need not be kept full of empty buffers. In theory, + * the htt host SW can dynamically track the low-water mark in the + * rx ring, and dynamically adjust the level to which the rx ring + * is filled with empty buffers, to dynamically meet the desired + * low-water mark. + * In contrast, it's difficult to resize the rx ring itself, once + * it's in use. + * Thus, the ring itself should be sized very conservatively, while + * the degree to which the ring is filled with empty buffers should + * be sized moderately conservatively. + */ + size = + ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; + + if (size < HTT_RX_RING_SIZE_MIN) + size = HTT_RX_RING_SIZE_MIN; + else if (size > HTT_RX_RING_SIZE_MAX) + size = HTT_RX_RING_SIZE_MAX; + + size = ceil_pwr2(size); + return size; +} + +static int htt_rx_ring_fill_level(struct htt_pdev_t *pdev) +{ + int size; + + size = ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + 8 * HTT_RX_AVG_FRM_BYTES * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; + /* + * Make sure the fill level is at least 1 less than the ring size. + * Leaving 1 element empty allows the SW to easily distinguish + * between a full ring vs. an empty ring. + */ + if (size >= pdev->rx_ring.size) + size = pdev->rx_ring.size - 1; + + return size; +} + +static void htt_rx_ring_refill_retry(void *arg) +{ + htt_pdev_handle pdev = (htt_pdev_handle) arg; + htt_rx_msdu_buff_replenish(pdev); +} + +void htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num) +{ + int idx; + CDF_STATUS status; + struct htt_host_rx_desc_base *rx_desc; + + idx = *(pdev->rx_ring.alloc_idx.vaddr); + while (num > 0) { + uint32_t paddr; + cdf_nbuf_t rx_netbuf; + int headroom; + + rx_netbuf = + cdf_nbuf_alloc(pdev->osdev, HTT_RX_BUF_SIZE, + 0, 4, false); + if (!rx_netbuf) { + cdf_softirq_timer_cancel(&pdev->rx_ring. + refill_retry_timer); + /* + * Failed to fill it to the desired level - + * we'll start a timer and try again next time. + * As long as enough buffers are left in the ring for + * another A-MPDU rx, no special recovery is needed. + */ +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_refill_cnt++; +#endif + cdf_softirq_timer_start( + &pdev->rx_ring.refill_retry_timer, + HTT_RX_RING_REFILL_RETRY_TIME_MS); + goto fail; + } + + /* Clear rx_desc attention word before posting to Rx ring */ + rx_desc = htt_rx_desc(rx_netbuf); + *(uint32_t *) &rx_desc->attention = 0; + +#ifdef DEBUG_DMA_DONE + *(uint32_t *) &rx_desc->msdu_end = 1; + +#define MAGIC_PATTERN 0xDEADBEEF + *(uint32_t *) &rx_desc->msdu_start = MAGIC_PATTERN; + + /* To ensure that attention bit is reset and msdu_end is set + before calling dma_map */ + smp_mb(); +#endif + /* + * Adjust cdf_nbuf_data to point to the location in the buffer + * where the rx descriptor will be filled in. + */ + headroom = cdf_nbuf_data(rx_netbuf) - (uint8_t *) rx_desc; + cdf_nbuf_push_head(rx_netbuf, headroom); + +#ifdef DEBUG_DMA_DONE + status = + cdf_nbuf_map(pdev->osdev, rx_netbuf, + CDF_DMA_BIDIRECTIONAL); +#else + status = + cdf_nbuf_map(pdev->osdev, rx_netbuf, + CDF_DMA_FROM_DEVICE); +#endif + if (status != CDF_STATUS_SUCCESS) { + cdf_nbuf_free(rx_netbuf); + goto fail; + } + paddr = cdf_nbuf_get_frag_paddr_lo(rx_netbuf, 0); + if (pdev->cfg.is_full_reorder_offload) { + if (cdf_unlikely + (htt_rx_hash_list_insert(pdev, paddr, + rx_netbuf))) { + cdf_print("%s: hash insert failed!\n", + __func__); +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, rx_netbuf, + CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, rx_netbuf, + CDF_DMA_FROM_DEVICE); +#endif + cdf_nbuf_free(rx_netbuf); + goto fail; + } + } else { + pdev->rx_ring.buf.netbufs_ring[idx] = rx_netbuf; + } +#if HTT_PADDR64 + pdev->rx_ring.buf.paddrs_ring[idx] = 0; + pdev->rx_ring.buf.paddrs_ring[idx] = (uint32_t)paddr; +#else + pdev->rx_ring.buf.paddrs_ring[idx] = paddr; +#endif /* HTT_PADDR64 */ + pdev->rx_ring.fill_cnt++; + + num--; + idx++; + idx &= pdev->rx_ring.size_mask; + } + +fail: + *(pdev->rx_ring.alloc_idx.vaddr) = idx; + return; +} + +unsigned htt_rx_ring_elems(struct htt_pdev_t *pdev) +{ + return + (*pdev->rx_ring.alloc_idx.vaddr - + pdev->rx_ring.sw_rd_idx.msdu_payld) & pdev->rx_ring.size_mask; +} + +unsigned int htt_rx_in_order_ring_elems(struct htt_pdev_t *pdev) +{ + return + (*pdev->rx_ring.alloc_idx.vaddr - + *pdev->rx_ring.target_idx.vaddr) & + pdev->rx_ring.size_mask; +} + +void htt_rx_detach(struct htt_pdev_t *pdev) +{ + cdf_softirq_timer_cancel(&pdev->rx_ring.refill_retry_timer); + cdf_softirq_timer_free(&pdev->rx_ring.refill_retry_timer); + + if (pdev->cfg.is_full_reorder_offload) { + cdf_os_mem_free_consistent(pdev->osdev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + cdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + htt_rx_hash_deinit(pdev); + } else { + int sw_rd_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + + while (sw_rd_idx != *(pdev->rx_ring.alloc_idx.vaddr)) { +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + CDF_DMA_FROM_DEVICE); +#endif + cdf_nbuf_free(pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx]); + sw_rd_idx++; + sw_rd_idx &= pdev->rx_ring.size_mask; + } + cdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + } + + cdf_os_mem_free_consistent(pdev->osdev, + sizeof(uint32_t), + pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.alloc_idx.paddr, + cdf_get_dma_mem_context((&pdev->rx_ring. + alloc_idx), + memctx)); + + cdf_os_mem_free_consistent(pdev->osdev, + pdev->rx_ring.size * sizeof(uint32_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + cdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); +} + +/*--- rx descriptor field access functions ----------------------------------*/ +/* + * These functions need to use bit masks and shifts to extract fields + * from the rx descriptors, rather than directly using the bitfields. + * For example, use + * (desc & FIELD_MASK) >> FIELD_LSB + * rather than + * desc.field + * This allows the functions to work correctly on either little-endian + * machines (no endianness conversion needed) or big-endian machines + * (endianness conversion provided automatically by the HW DMA's + * byte-swizzling). + */ +/* FIX THIS: APPLIES TO LL ONLY */ + +/** + * htt_rx_mpdu_desc_retry_ll() - Returns the retry bit from the Rx descriptor + * for the Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * Return: boolean -- true if retry is set, false otherwise + */ +bool +htt_rx_mpdu_desc_retry_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *) mpdu_desc; + + return + (bool)(((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_RETRY_MASK) >> + RX_MPDU_START_0_RETRY_LSB); +} + +uint16_t htt_rx_mpdu_desc_seq_num_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return + (uint16_t) (((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_SEQ_NUM_MASK) >> + RX_MPDU_START_0_SEQ_NUM_LSB); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +void +htt_rx_mpdu_desc_pn_ll(htt_pdev_handle pdev, + void *mpdu_desc, union htt_rx_pn_t *pn, int pn_len_bits) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + switch (pn_len_bits) { + case 24: + /* bits 23:0 */ + pn->pn24 = rx_desc->mpdu_start.pn_31_0 & 0xffffff; + break; + case 48: + /* bits 31:0 */ + pn->pn48 = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn48 |= ((uint64_t) + ((*(((uint32_t *) &rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + break; + case 128: + /* bits 31:0 */ + pn->pn128[0] = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn128[0] |= + ((uint64_t) ((*(((uint32_t *)&rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + /* bits 63:48 */ + pn->pn128[0] |= + ((uint64_t) ((*(((uint32_t *) &rx_desc->msdu_end) + 2)) + & RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK)) + << (48 - RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB); + /* bits 95:64 */ + pn->pn128[1] = rx_desc->msdu_end.ext_wapi_pn_95_64; + /* bits 127:96 */ + pn->pn128[1] |= + ((uint64_t) rx_desc->msdu_end.ext_wapi_pn_127_96) << 32; + break; + default: + cdf_print("Error: invalid length spec (%d bits) for PN\n", + pn_len_bits); + }; +} + +/** + * htt_rx_mpdu_desc_tid_ll() - Returns the TID value from the Rx descriptor + * for Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * + * Return: Actual TID set in the packet header. + */ +uint8_t +htt_rx_mpdu_desc_tid_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *) mpdu_desc; + + return + (uint8_t)(((*(((uint32_t *) &rx_desc->mpdu_start) + 2)) & + RX_MPDU_START_2_TID_MASK) >> + RX_MPDU_START_2_TID_LSB); +} + +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc) +{ +/* FIX THIS */ + return 0; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + return rx_desc->rx_hdr_status; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +bool htt_rx_msdu_desc_completes_mpdu_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> RX_MSDU_END_4_LAST_MSDU_LSB); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +int htt_rx_msdu_has_wlan_mcast_flag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + /* HW rx desc: the mcast_bcast flag is only valid + if first_msdu is set */ + return + ((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> RX_MSDU_END_4_FIRST_MSDU_LSB; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +bool htt_rx_msdu_is_wlan_mcast_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return + ((*((uint32_t *) &rx_desc->attention)) & + RX_ATTENTION_0_MCAST_BCAST_MASK) + >> RX_ATTENTION_0_MCAST_BCAST_LSB; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +int htt_rx_msdu_is_frag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return + ((*((uint32_t *) &rx_desc->attention)) & + RX_ATTENTION_0_FRAGMENT_MASK) >> RX_ATTENTION_0_FRAGMENT_LSB; +} + +static inline +uint8_t htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev, void *msdu_desc) +{ + /* + * HL and LL use the same format for FW rx desc, but have the FW rx desc + * in different locations. + * In LL, the FW rx descriptor has been copied into the same + * htt_host_rx_desc_base struct that holds the HW rx desc. + * In HL, the FW rx descriptor, along with the MSDU payload, + * is in the same buffer as the rx indication message. + * + * Use the FW rx desc offset configured during startup to account for + * this difference between HL vs. LL. + * + * An optimization would be to define the LL and HL msdu_desc pointer + * in such a way that they both use the same offset to the FW rx desc. + * Then the following functions could be converted to macros, without + * needing to expose the htt_pdev_t definition outside HTT. + */ + return *(((uint8_t *) msdu_desc) + pdev->rx_fw_desc_offset); +} + +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_DISCARD_M; +} + +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_FORWARD_M; +} + +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_INSPECT_M; +} + +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect) +{ + uint8_t rx_msdu_fw_desc = htt_rx_msdu_fw_desc_get(pdev, msdu_desc); +#ifdef HTT_DEBUG_DATA + HTT_PRINT("act:0x%x ", rx_msdu_fw_desc); +#endif + *discard = rx_msdu_fw_desc & FW_RX_DESC_DISCARD_M; + *forward = rx_msdu_fw_desc & FW_RX_DESC_FORWARD_M; + *inspect = rx_msdu_fw_desc & FW_RX_DESC_INSPECT_M; +} + +static inline cdf_nbuf_t htt_rx_netbuf_pop(htt_pdev_handle pdev) +{ + int idx; + cdf_nbuf_t msdu; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx++; + pdev->rx_ring.dbg_ring_idx &= pdev->rx_ring.size_mask; +#endif + + idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[idx]; + idx++; + idx &= pdev->rx_ring.size_mask; + pdev->rx_ring.sw_rd_idx.msdu_payld = idx; + pdev->rx_ring.fill_cnt--; + return msdu; +} + +static inline cdf_nbuf_t +htt_rx_in_order_netbuf_pop(htt_pdev_handle pdev, uint32_t paddr) +{ + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + pdev->rx_ring.fill_cnt--; + return htt_rx_hash_list_lookup(pdev, paddr); +} + +/* FIX ME: this function applies only to LL rx descs. + An equivalent for HL rx descs is needed. */ +#ifdef CHECKSUM_OFFLOAD +static inline +void +htt_set_checksum_result_ll(htt_pdev_handle pdev, cdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +#define MAX_IP_VER 2 +#define MAX_PROTO_VAL 4 + struct rx_msdu_start *rx_msdu = &rx_desc->msdu_start; + unsigned int proto = (rx_msdu->tcp_proto) | (rx_msdu->udp_proto << 1); + + /* + * HW supports TCP & UDP checksum offload for ipv4 and ipv6 + */ + static const cdf_nbuf_l4_rx_cksum_type_t + cksum_table[][MAX_PROTO_VAL][MAX_IP_VER] = { + { + /* non-fragmented IP packet */ + /* non TCP/UDP packet */ + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + /* TCP packet */ + {CDF_NBUF_RX_CKSUM_TCP, CDF_NBUF_RX_CKSUM_TCPIPV6}, + /* UDP packet */ + {CDF_NBUF_RX_CKSUM_UDP, CDF_NBUF_RX_CKSUM_UDPIPV6}, + /* invalid packet type */ + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + }, + { + /* fragmented IP packet */ + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + {CDF_NBUF_RX_CKSUM_NONE, CDF_NBUF_RX_CKSUM_NONE}, + } + }; + + cdf_nbuf_rx_cksum_t cksum = { + cksum_table[rx_msdu->ip_frag][proto][rx_msdu->ipv6_proto], + CDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + if (cksum.l4_type != + (cdf_nbuf_l4_rx_cksum_type_t) CDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = + ((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) ? + CDF_NBUF_RX_CKSUM_NONE : + CDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + cdf_nbuf_set_rx_cksum(msdu, &cksum); +#undef MAX_IP_VER +#undef MAX_PROTO_VAL +} +#else +#define htt_set_checksum_result_ll(pdev, msdu, rx_desc) /* no-op */ +#endif + +#ifdef DEBUG_DMA_DONE +void htt_rx_print_rx_indication(cdf_nbuf_t rx_ind_msg, htt_pdev_handle pdev) +{ + uint32_t *msg_word; + int byte_offset; + int mpdu_range, num_mpdu_range; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + + cdf_print + ("------------------HTT RX IND-----------------------------\n"); + cdf_print("alloc idx paddr %x (*vaddr) %d\n", + pdev->rx_ring.alloc_idx.paddr, + *pdev->rx_ring.alloc_idx.vaddr); + + cdf_print("sw_rd_idx msdu_payld %d msdu_desc %d\n", + pdev->rx_ring.sw_rd_idx.msdu_payld, + pdev->rx_ring.sw_rd_idx.msdu_desc); + + cdf_print("dbg_ring_idx %d\n", pdev->rx_ring.dbg_ring_idx); + + cdf_print("fill_level %d fill_cnt %d\n", pdev->rx_ring.fill_level, + pdev->rx_ring.fill_cnt); + + cdf_print("initial msdu_payld %d curr mpdu range %d curr mpdu cnt %d\n", + pdev->rx_ring.dbg_initial_msdu_payld, + pdev->rx_ring.dbg_mpdu_range, pdev->rx_ring.dbg_mpdu_count); + + /* Print the RX_IND contents */ + + cdf_print("peer id %x RV %x FV %x ext_tid %x msg_type %x\n", + HTT_RX_IND_PEER_ID_GET(*msg_word), + HTT_RX_IND_REL_VALID_GET(*msg_word), + HTT_RX_IND_FLUSH_VALID_GET(*msg_word), + HTT_RX_IND_EXT_TID_GET(*msg_word), + HTT_T2H_MSG_TYPE_GET(*msg_word)); + + cdf_print("num_mpdu_ranges %x rel_seq_num_end %x rel_seq_num_start %x\n" + " flush_seq_num_end %x flush_seq_num_start %x\n", + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1)), + HTT_RX_IND_REL_SEQ_NUM_END_GET(*(msg_word + 1)), + HTT_RX_IND_REL_SEQ_NUM_START_GET(*(msg_word + 1)), + HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1)), + HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1))); + + cdf_print("fw_rx_desc_bytes %x\n", + HTT_RX_IND_FW_RX_DESC_BYTES_GET(* + (msg_word + 2 + + HTT_RX_PPDU_DESC_SIZE32))); + + /* receive MSDU desc for current frame */ + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + + pdev->rx_ind_msdu_byte_idx); + + cdf_print("msdu byte idx %x msdu desc %x\n", pdev->rx_ind_msdu_byte_idx, + HTT_RX_IND_FW_RX_DESC_BYTES_GET(* + (msg_word + 2 + + HTT_RX_PPDU_DESC_SIZE32))); + + num_mpdu_range = HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1)); + + for (mpdu_range = 0; mpdu_range < num_mpdu_range; mpdu_range++) { + enum htt_rx_status status; + int num_mpdus; + + htt_rx_ind_mpdu_range_info(pdev, rx_ind_msg, mpdu_range, + &status, &num_mpdus); + + cdf_print("mpdu_range %x status %x num_mpdus %x\n", + pdev->rx_ind_msdu_byte_idx, status, num_mpdus); + } + cdf_print + ("---------------------------------------------------------\n"); +} +#endif + +#ifdef DEBUG_DMA_DONE +#define MAX_DONE_BIT_CHECK_ITER 5 +#endif + +int +htt_rx_amsdu_pop_ll(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu) +{ + int msdu_len, msdu_chaining = 0; + cdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + uint8_t *rx_ind_data; + uint32_t *msg_word, num_msdu_bytes; + enum htt_t2h_msg_type msg_type; + uint8_t pad_bytes = 0; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + rx_ind_data = cdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *) rx_ind_data; + + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + if (cdf_unlikely(HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) { + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + } else { + num_msdu_bytes = HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + + HTT_RX_IND_HDR_PREFIX_SIZE32 + + HTT_RX_PPDU_DESC_SIZE32)); + } + msdu = *head_msdu = htt_rx_netbuf_pop(pdev); + while (1) { + int last_msdu, msdu_len_invalid, msdu_chained; + int byte_offset; + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + cdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE); +#endif + + /* cache consistency has been taken care of by cdf_nbuf_unmap */ + + /* + * Now read the rx descriptor. + * Set the length to the appropriate value. + * Check if this MSDU completes a MPDU. + */ + rx_desc = htt_rx_desc(msdu); +#if defined(HELIUMPLUS_PADDR64) + if (HTT_WIFI_IP(pdev, 2, 0)) + pad_bytes = rx_desc->msdu_end.l3_header_padding; +#endif /* defined(HELIUMPLUS_PADDR64) */ + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + + cdf_nbuf_pull_head(msdu, + HTT_RX_STD_DESC_RESERVATION + pad_bytes); + + /* + * Sanity check - confirm the HW is finished filling in + * the rx data. + * If the HW and SW are working correctly, then it's guaranteed + * that the HW's MAC DMA is done before this point in the SW. + * To prevent the case that we handle a stale Rx descriptor, + * just assert for now until we have a way to recover. + */ + +#ifdef DEBUG_DMA_DONE + if (cdf_unlikely(!((*(uint32_t *) &rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { + + int dbg_iter = MAX_DONE_BIT_CHECK_ITER; + + cdf_print("malformed frame\n"); + + while (dbg_iter && + (!((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK))) { + cdf_mdelay(1); + + cdf_invalidate_range((void *)rx_desc, + (void *)((char *)rx_desc + + HTT_RX_STD_DESC_RESERVATION)); + + cdf_print("debug iter %d success %d\n", + dbg_iter, + pdev->rx_ring.dbg_sync_success); + + dbg_iter--; + } + + if (cdf_unlikely(!((*(uint32_t *) &rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { + +#ifdef HTT_RX_RESTORE + cdf_print("RX done bit error detected!\n"); + cdf_nbuf_set_next(msdu, NULL); + *tail_msdu = msdu; + pdev->rx_ring.rx_reset = 1; + return msdu_chaining; +#else + wma_cli_set_command(0, GEN_PARAM_CRASH_INJECT, + 0, GEN_CMD); + HTT_ASSERT_ALWAYS(0); +#endif + } + pdev->rx_ring.dbg_sync_success++; + cdf_print("debug iter %d success %d\n", dbg_iter, + pdev->rx_ring.dbg_sync_success); + } +#else + HTT_ASSERT_ALWAYS((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK); +#endif + /* + * Copy the FW rx descriptor for this MSDU from the rx + * indication message into the MSDU's netbuf. + * HL uses the same rx indication message definition as LL, and + * simply appends new info (fields from the HW rx desc, and the + * MSDU payload itself). + * So, the offset into the rx indication message only has to + * account for the standard offset of the per-MSDU FW rx + * desc info within the message, and how many bytes of the + * per-MSDU FW rx desc info have already been consumed. + * (And the endianness of the host, + * since for a big-endian host, the rx ind message contents, + * including the per-MSDU rx desc bytes, were byteswapped during + * upload.) + */ + if (pdev->rx_ind_msdu_byte_idx < num_msdu_bytes) { + if (cdf_unlikely + (HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET); + else + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + + pdev->rx_ind_msdu_byte_idx); + + *((uint8_t *) &rx_desc->fw_desc.u.val) = + rx_ind_data[byte_offset]; + /* + * The target is expected to only provide the basic + * per-MSDU rx descriptors. Just to be sure, + * verify that the target has not attached + * extension data (e.g. LRO flow ID). + */ + /* + * The assertion below currently doesn't work for + * RX_FRAG_IND messages, since their format differs + * from the RX_IND format (no FW rx PPDU desc in + * the current RX_FRAG_IND message). + * If the RX_FRAG_IND message format is updated to match + * the RX_IND message format, then the following + * assertion can be restored. + */ + /* cdf_assert((rx_ind_data[byte_offset] & + FW_RX_DESC_EXT_M) == 0); */ + pdev->rx_ind_msdu_byte_idx += 1; + /* or more, if there's ext data */ + } else { + /* + * When an oversized AMSDU happened, FW will lost some + * of MSDU status - in this case, the FW descriptors + * provided will be less than the actual MSDUs + * inside this MPDU. + * Mark the FW descriptors so that it will still + * deliver to upper stack, if no CRC error for the MPDU. + * + * FIX THIS - the FW descriptors are actually for MSDUs + * in the end of this A-MSDU instead of the beginning. + */ + *((uint8_t *) &rx_desc->fw_desc.u.val) = 0; + } + + /* + * TCP/UDP checksum offload support + */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + msdu_len_invalid = (*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + msdu_chained = (((*(uint32_t *) &rx_desc->frag_info) & + RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) >> + RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB); + msdu_len = + ((*((uint32_t *) &rx_desc->msdu_start)) & + RX_MSDU_START_0_MSDU_LENGTH_MASK) >> + RX_MSDU_START_0_MSDU_LENGTH_LSB; + + do { + if (!msdu_len_invalid && !msdu_chained) { +#if defined(PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR) + if (msdu_len > 0x3000) + break; +#endif + cdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } while (0); + + while (msdu_chained--) { + cdf_nbuf_t next = htt_rx_netbuf_pop(pdev); + cdf_nbuf_set_pktlen(next, HTT_RX_BUF_SIZE); + msdu_len -= HTT_RX_BUF_SIZE; + cdf_nbuf_set_next(msdu, next); + msdu = next; + msdu_chaining = 1; + + if (msdu_chained == 0) { + /* Trim the last one to the correct size - + * accounting for inconsistent HW lengths + * causing length overflows and underflows + */ + if (((unsigned)msdu_len) > + ((unsigned) + (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE))) { + msdu_len = + (HTT_RX_BUF_SIZE - + RX_STD_DESC_SIZE); + } + + cdf_nbuf_trim_tail(next, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } + + last_msdu = + ((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> + RX_MSDU_END_4_LAST_MSDU_LSB; + + if (last_msdu) { + cdf_nbuf_set_next(msdu, NULL); + break; + } else { + cdf_nbuf_t next = htt_rx_netbuf_pop(pdev); + cdf_nbuf_set_next(msdu, next); + msdu = next; + } + } + *tail_msdu = msdu; + + /* + * Don't refill the ring yet. + * First, the elements popped here are still in use - it is + * not safe to overwrite them until the matching call to + * mpdu_desc_list_next. + * Second, for efficiency it is preferable to refill the rx ring + * with 1 PPDU's worth of rx buffers (something like 32 x 3 buffers), + * rather than one MPDU's worth of rx buffers (sth like 3 buffers). + * Consequently, we'll rely on the txrx SW to tell us when it is done + * pulling all the PPDU's rx buffers out of the rx ring, and then + * refill it just once. + */ + return msdu_chaining; +} + +int +htt_rx_offload_msdu_pop_ll(htt_pdev_handle pdev, + cdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + cdf_nbuf_t *head_buf, cdf_nbuf_t *tail_buf) +{ + cdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + + *head_buf = *tail_buf = buf = htt_rx_netbuf_pop(pdev); + /* Fake read mpdu_desc to keep desc ptr in sync */ + htt_rx_mpdu_desc_list_next(pdev, NULL); + cdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, buf, CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, buf, CDF_DMA_FROM_DEVICE); +#endif + msdu_hdr = (uint32_t *) cdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + cdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + cdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} + +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + cdf_nbuf_t *head_buf, cdf_nbuf_t *tail_buf) +{ + cdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + uint32_t *curr_msdu; + uint32_t paddr; + + curr_msdu = + msg_word + (msdu_iter * HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS); + paddr = HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*curr_msdu); + *head_buf = *tail_buf = buf = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (cdf_unlikely(NULL == buf)) { + cdf_print("%s: netbuf pop failed!\n", __func__); + return 0; + } + cdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, buf, CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, buf, CDF_DMA_FROM_DEVICE); +#endif + msdu_hdr = (uint32_t *) cdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + cdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + cdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} + +extern void +dump_pkt(cdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len); + +#ifdef RX_HASH_DEBUG +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) HTT_ASSERT_ALWAYS(msdu_count) +#else +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) /* no-op */ +#endif + +/* Return values: 1 - success, 0 - failure */ +int +htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu) +{ + cdf_nbuf_t msdu, next, prev = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + unsigned int msdu_count = 0; + uint8_t offload_ind; + struct htt_host_rx_desc_base *rx_desc; + + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + + rx_ind_data = cdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *) rx_ind_data; + + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + HTT_RX_CHECK_MSDU_COUNT(msdu_count); + + msg_word = + (uint32_t *) (rx_ind_data + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); + if (offload_ind) { + ol_rx_offload_paddr_deliver_ind_handler(pdev, msdu_count, + msg_word); + *head_msdu = *tail_msdu = NULL; + return 0; + } + + (*head_msdu) = msdu = htt_rx_in_order_netbuf_pop( + pdev, + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*msg_word)); + + if (cdf_unlikely(NULL == msdu)) { + cdf_print("%s: netbuf pop failed!\n", __func__); + *tail_msdu = NULL; + return 0; + } + + while (msdu_count > 0) { + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + cdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_BIDIRECTIONAL); +#else + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE); +#endif + + /* cache consistency has been taken care of by cdf_nbuf_unmap */ + rx_desc = htt_rx_desc(msdu); + + htt_rx_extract_lro_info(msdu, rx_desc); + + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + cdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION); +#if HTT_PADDR64 +#define NEXT_FIELD_OFFSET_IN32 2 +#else /* ! HTT_PADDR64 */ +#define NEXT_FIELD_OFFSET_IN32 1 +#endif /* HTT_PADDR64 */ +# + cdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET( + *(msg_word + NEXT_FIELD_OFFSET_IN32)))); +#if defined(HELIUMPLUS_DEBUG) + dump_pkt(msdu, 0, 64); +#endif + *((uint8_t *) &rx_desc->fw_desc.u.val) = + HTT_RX_IN_ORD_PADDR_IND_FW_DESC_GET(*(msg_word + NEXT_FIELD_OFFSET_IN32)); +#undef NEXT_FIELD_OFFSET_IN32 + + msdu_count--; + + if (cdf_unlikely((*((u_int8_t *) &rx_desc->fw_desc.u.val)) & + FW_RX_DESC_MIC_ERR_M)) { + u_int8_t tid = + HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET( + *(u_int32_t *)rx_ind_data); + u_int16_t peer_id = + HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET( + *(u_int32_t *)rx_ind_data); + ol_rx_mic_error_handler(pdev->txrx_pdev, tid, peer_id, + rx_desc, msdu); + + htt_rx_desc_frame_free(pdev, msdu); + /* if this is the last msdu */ + if (!msdu_count) { + /* if this is the only msdu */ + if (!prev) { + *head_msdu = *tail_msdu = NULL; + return 0; + } else { + *tail_msdu = prev; + cdf_nbuf_set_next(prev, NULL); + return 1; + } + } else { /* if this is not the last msdu */ + /* get the next msdu */ + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + next = htt_rx_in_order_netbuf_pop( + pdev, + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET( + *msg_word)); + if (cdf_unlikely(NULL == next)) { + cdf_print("%s: netbuf pop failed!\n", + __func__); + *tail_msdu = NULL; + return 0; + } + + /* if this is not the first msdu, update the + * next pointer of the preceding msdu + */ + if (prev) { + cdf_nbuf_set_next(prev, next); + } else { + /* if this is the first msdu, update the + * head pointer + */ + *head_msdu = next; + } + msdu = next; + continue; + } + } + + /* Update checksum result */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + /* check if this is the last msdu */ + if (msdu_count) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + next = htt_rx_in_order_netbuf_pop( + pdev, + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*msg_word)); + if (cdf_unlikely(NULL == next)) { + cdf_print("%s: netbuf pop failed!\n", + __func__); + *tail_msdu = NULL; + return 0; + } + cdf_nbuf_set_next(msdu, next); + prev = msdu; + msdu = next; + } else { + *tail_msdu = msdu; + cdf_nbuf_set_next(msdu, NULL); + } + } + + return 1; +} + +/* Util fake function that has same prototype as cdf_nbuf_clone that just + * retures the same nbuf + */ +cdf_nbuf_t htt_rx_cdf_noclone_buf(cdf_nbuf_t buf) +{ + return buf; +} + +/* FIXME: This is a HW definition not provded by HW, where does it go ? */ +enum { + HW_RX_DECAP_FORMAT_RAW = 0, + HW_RX_DECAP_FORMAT_NWIFI, + HW_RX_DECAP_FORMAT_8023, + HW_RX_DECAP_FORMAT_ETH2, +}; + +#define HTT_FCS_LEN (4) + +static void +htt_rx_parse_ppdu_start_status(struct htt_host_rx_desc_base *rx_desc, + struct ieee80211_rx_status *rs) +{ + + struct rx_ppdu_start *ppdu_start = &rx_desc->ppdu_start; + + /* RSSI */ + rs->rs_rssi = ppdu_start->rssi_comb; + + /* PHY rate */ + /* rs_ratephy coding + [b3 - b0] + 0 -> OFDM + 1 -> CCK + 2 -> HT + 3 -> VHT + OFDM / CCK + [b7 - b4 ] => LSIG rate + [b23 - b8 ] => service field + (b'12 static/dynamic, + b'14..b'13 BW for VHT) + [b31 - b24 ] => Reserved + HT / VHT + [b15 - b4 ] => SIG A_2 12 LSBs + [b31 - b16] => SIG A_1 16 LSBs + + */ + if (ppdu_start->preamble_type == 0x4) { + rs->rs_ratephy = ppdu_start->l_sig_rate_select; + rs->rs_ratephy |= ppdu_start->l_sig_rate << 4; + rs->rs_ratephy |= ppdu_start->service << 8; + } else { + rs->rs_ratephy = (ppdu_start->preamble_type & 0x4) ? 3 : 2; +#ifdef HELIUMPLUS + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_1 & 0xFFFF) << 16; +#else + rs->rs_ratephy |= (ppdu_start->ht_sig_vht_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_a_1 & 0xFFFF) << 16; +#endif + } + + return; +} + +/* This function is used by montior mode code to restitch an MSDU list + * corresponding to an MPDU back into an MPDU by linking up the skbs. + */ +cdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + cdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd) +{ + + cdf_nbuf_t msdu, mpdu_buf, prev_buf, msdu_orig, head_frag_list_cloned; + cdf_nbuf_t (*clone_nbuf_fn)(cdf_nbuf_t buf); + unsigned decap_format, wifi_hdr_len, sec_hdr_len, msdu_llc_len, + mpdu_buf_len, decap_hdr_pull_bytes, frag_list_sum_len, dir, + is_amsdu, is_first_frag, amsdu_pad, msdu_len; + struct htt_host_rx_desc_base *rx_desc; + char *hdr_desc; + unsigned char *dest; + struct ieee80211_frame *wh; + struct ieee80211_qoscntl *qos; + + /* If this packet does not go up the normal stack path we dont need to + * waste cycles cloning the packets + */ + clone_nbuf_fn = + clone_not_reqd ? htt_rx_cdf_noclone_buf : cdf_nbuf_clone; + + /* The nbuf has been pulled just beyond the status and points to the + * payload + */ + msdu_orig = head_msdu; + rx_desc = htt_rx_desc(msdu_orig); + + /* Fill out the rx_status from the PPDU start and end fields */ + if (rx_desc->attention.first_mpdu) { + htt_rx_parse_ppdu_start_status(rx_desc, rx_status); + + /* The timestamp is no longer valid - It will be valid only for + * the last MPDU + */ + rx_status->rs_tstamp.tsf = ~0; + } + + decap_format = + GET_FIELD(&rx_desc->msdu_start, RX_MSDU_START_2_DECAP_FORMAT); + + head_frag_list_cloned = NULL; + + /* Easy case - The MSDU status indicates that this is a non-decapped + * packet in RAW mode. + * return + */ + if (decap_format == HW_RX_DECAP_FORMAT_RAW) { + /* Note that this path might suffer from headroom unavailabilty, + * but the RX status is usually enough + */ + mpdu_buf = clone_nbuf_fn(head_msdu); + + prev_buf = mpdu_buf; + + frag_list_sum_len = 0; + is_first_frag = 1; + msdu_len = cdf_nbuf_len(mpdu_buf); + + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + msdu_orig = cdf_nbuf_next(head_msdu); + + while (msdu_orig) { + + /* TODO: intra AMSDU padding - do we need it ??? */ + msdu = clone_nbuf_fn(msdu_orig); + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } + + msdu_len = cdf_nbuf_len(msdu); + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + frag_list_sum_len += msdu_len; + + /* Maintain the linking of the cloned MSDUS */ + cdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = cdf_nbuf_next(msdu_orig); + } + + /* The last msdu length need be larger than HTT_FCS_LEN */ + if (msdu_len < HTT_FCS_LEN) + goto mpdu_stitch_fail; + + cdf_nbuf_trim_tail(prev_buf, HTT_FCS_LEN); + + /* If there were more fragments to this RAW frame */ + if (head_frag_list_cloned) { + cdf_nbuf_append_ext_list(mpdu_buf, + head_frag_list_cloned, + frag_list_sum_len); + } + + goto mpdu_stitch_done; + } + + /* Decap mode: + * Calculate the amount of header in decapped packet to knock off based + * on the decap type and the corresponding number of raw bytes to copy + * status header + */ + + hdr_desc = &rx_desc->rx_hdr_status[0]; + + /* Base size */ + wifi_hdr_len = sizeof(struct ieee80211_frame); + wh = (struct ieee80211_frame *)hdr_desc; + + dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + if (dir == IEEE80211_FC1_DIR_DSTODS) + wifi_hdr_len += 6; + + is_amsdu = 0; + if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + qos = (struct ieee80211_qoscntl *) + (hdr_desc + wifi_hdr_len); + wifi_hdr_len += 2; + + is_amsdu = (qos->i_qos[0] & IEEE80211_QOS_AMSDU); + } + + /* TODO: Any security headers associated with MPDU */ + sec_hdr_len = 0; + + /* MSDU related stuff LLC - AMSDU subframe header etc */ + msdu_llc_len = is_amsdu ? (14 + 8) : 8; + + mpdu_buf_len = wifi_hdr_len + sec_hdr_len + msdu_llc_len; + + /* "Decap" header to remove from MSDU buffer */ + decap_hdr_pull_bytes = 14; + + /* Allocate a new nbuf for holding the 802.11 header retrieved from the + * status of the now decapped first msdu. Leave enough headroom for + * accomodating any radio-tap /prism like PHY header + */ +#define HTT_MAX_MONITOR_HEADER (512) + mpdu_buf = cdf_nbuf_alloc(pdev->osdev, + HTT_MAX_MONITOR_HEADER + mpdu_buf_len, + HTT_MAX_MONITOR_HEADER, 4, false); + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + /* Copy the MPDU related header and enc headers into the first buffer + * - Note that there can be a 2 byte pad between heaader and enc header + */ + + prev_buf = mpdu_buf; + dest = cdf_nbuf_put_tail(prev_buf, wifi_hdr_len); + if (!dest) + goto mpdu_stitch_fail; + cdf_mem_copy(dest, hdr_desc, wifi_hdr_len); + hdr_desc += wifi_hdr_len; + + /* NOTE - This padding is present only in the RAW header status - not + * when the MSDU data payload is in RAW format. + */ + /* Skip the "IV pad" */ + if (wifi_hdr_len & 0x3) + hdr_desc += 2; + + /* The first LLC len is copied into the MPDU buffer */ + frag_list_sum_len = 0; + frag_list_sum_len -= msdu_llc_len; + + msdu_orig = head_msdu; + is_first_frag = 1; + amsdu_pad = 0; + + while (msdu_orig) { + + /* TODO: intra AMSDU padding - do we need it ??? */ + + msdu = clone_nbuf_fn(msdu_orig); + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } else { + + /* Maintain the linking of the cloned MSDUS */ + cdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Reload the hdr ptr only on non-first MSDUs */ + rx_desc = htt_rx_desc(msdu_orig); + hdr_desc = &rx_desc->rx_hdr_status[0]; + + } + + /* Copy this buffers MSDU related status into the prev buffer */ + dest = cdf_nbuf_put_tail(prev_buf, msdu_llc_len + amsdu_pad); + dest += amsdu_pad; + cdf_mem_copy(dest, hdr_desc, msdu_llc_len); + + /* Push the MSDU buffer beyond the decap header */ + cdf_nbuf_pull_head(msdu, decap_hdr_pull_bytes); + frag_list_sum_len += + msdu_llc_len + cdf_nbuf_len(msdu) + amsdu_pad; + + /* Set up intra-AMSDU pad to be added to start of next buffer - + * AMSDU pad is 4 byte pad on AMSDU subframe */ + amsdu_pad = (msdu_llc_len + cdf_nbuf_len(msdu)) & 0x3; + amsdu_pad = amsdu_pad ? (4 - amsdu_pad) : 0; + + /* TODO FIXME How do we handle MSDUs that have fraglist - Should + * probably iterate all the frags cloning them along the way and + * and also updating the prev_buf pointer + */ + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = cdf_nbuf_next(msdu_orig); + + } + + /* TODO: Convert this to suitable cdf routines */ + cdf_nbuf_append_ext_list(mpdu_buf, head_frag_list_cloned, + frag_list_sum_len); + +mpdu_stitch_done: + /* Check if this buffer contains the PPDU end status for TSF */ + if (rx_desc->attention.last_mpdu) +#ifdef HELIUMPLUS + rx_status->rs_tstamp.tsf = + rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32; +#else + rx_status->rs_tstamp.tsf = rx_desc->ppdu_end.tsf_timestamp; +#endif + /* All the nbufs have been linked into the ext list and + then unlink the nbuf list */ + if (clone_not_reqd) { + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = cdf_nbuf_next(msdu); + cdf_nbuf_set_next(msdu_orig, NULL); + } + } + + return mpdu_buf; + +mpdu_stitch_fail: + /* Free these alloced buffers and the orig buffers in non-clone case */ + if (!clone_not_reqd) { + /* Free the head buffer */ + if (mpdu_buf) + cdf_nbuf_free(mpdu_buf); + + /* Free the partial list */ + while (head_frag_list_cloned) { + msdu = head_frag_list_cloned; + head_frag_list_cloned = + cdf_nbuf_next_ext(head_frag_list_cloned); + cdf_nbuf_free(msdu); + } + } else { + /* Free the alloced head buffer */ + if (decap_format != HW_RX_DECAP_FORMAT_RAW) + if (mpdu_buf) + cdf_nbuf_free(mpdu_buf); + + /* Free the orig buffers */ + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = cdf_nbuf_next(msdu); + cdf_nbuf_free(msdu_orig); + } + } + + return NULL; +} + +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc) +{ + /* + * Currently the RSSI is provided only as a field in the + * HTT_T2H_RX_IND message, rather than in each rx descriptor. + */ + return HTT_RSSI_INVALID; +} + +/* + * htt_rx_amsdu_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll or htt_rx_amsdu_rx_in_order_pop_ll. + */ +int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu); + +/* + * htt_rx_frag_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll + */ +int (*htt_rx_frag_pop)(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu); + +int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + cdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + cdf_nbuf_t *head_buf, cdf_nbuf_t *tail_buf); + +void * (*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg); + +bool (*htt_rx_mpdu_desc_retry)( + htt_pdev_handle pdev, void *mpdu_desc); + +uint16_t (*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc); + +void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +uint8_t (*htt_rx_mpdu_desc_tid)( + htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +void * (*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, cdf_nbuf_t msdu); + +bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +void *htt_rx_mpdu_desc_list_next_ll(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + int idx = pdev->rx_ring.sw_rd_idx.msdu_desc; + cdf_nbuf_t netbuf = pdev->rx_ring.buf.netbufs_ring[idx]; + pdev->rx_ring.sw_rd_idx.msdu_desc = pdev->rx_ring.sw_rd_idx.msdu_payld; + return (void *)htt_rx_desc(netbuf); +} + +bool (*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +bool (*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +void *htt_rx_in_ord_mpdu_desc_list_next_ll(htt_pdev_handle pdev, + cdf_nbuf_t netbuf) +{ + return (void *)htt_rx_desc(netbuf); +} + +void *htt_rx_msdu_desc_retrieve_ll(htt_pdev_handle pdev, cdf_nbuf_t msdu) +{ + return htt_rx_desc(msdu); +} + +bool htt_rx_mpdu_is_encrypted_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return (((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_ENCRYPTED_MASK) >> + RX_MPDU_START_0_ENCRYPTED_LSB) ? true : false; +} + +bool htt_rx_msdu_chan_info_present_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +bool htt_rx_msdu_center_freq_ll(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +bool +htt_rx_msdu_desc_key_id_ll(htt_pdev_handle pdev, void *mpdu_desc, + uint8_t *key_id) +{ + struct htt_host_rx_desc_base *rx_desc = (struct htt_host_rx_desc_base *) + mpdu_desc; + + if (!htt_rx_msdu_first_msdu_flag_ll(pdev, mpdu_desc)) + return false; + + *key_id = ((*(((uint32_t *) &rx_desc->msdu_end) + 1)) & + (RX_MSDU_END_1_KEY_ID_OCT_MASK >> + RX_MSDU_END_1_KEY_ID_OCT_LSB)); + + return true; +} + +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, cdf_nbuf_t msdu) +{ + cdf_nbuf_free(msdu); +} + +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, cdf_nbuf_t msdu) +{ + /* + * The rx descriptor is in the same buffer as the rx MSDU payload, + * and does not need to be freed separately. + */ +} + +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev) +{ + if (cdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) { + int num_to_fill; + num_to_fill = pdev->rx_ring.fill_level - + pdev->rx_ring.fill_cnt; + + htt_rx_ring_fill_n(pdev, + num_to_fill /* okay if <= 0 */); + } + cdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); +} + +#define AR600P_ASSEMBLE_HW_RATECODE(_rate, _nss, _pream) \ + (((_pream) << 6) | ((_nss) << 4) | (_rate)) + +enum AR600P_HW_RATECODE_PREAM_TYPE { + AR600P_HW_RATECODE_PREAM_OFDM, + AR600P_HW_RATECODE_PREAM_CCK, + AR600P_HW_RATECODE_PREAM_HT, + AR600P_HW_RATECODE_PREAM_VHT, +}; + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* Initializes the circular linked list */ +static inline void htt_list_init(struct htt_list_node *head) +{ + head->prev = head; + head->next = head; +} + +/* Adds entry to the end of the linked list */ +static inline void htt_list_add_tail(struct htt_list_node *head, + struct htt_list_node *node) +{ + head->prev->next = node; + node->prev = head->prev; + node->next = head; + head->prev = node; +} + +/* Removes the entry corresponding to the input node from the linked list */ +static inline void htt_list_remove(struct htt_list_node *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/* Helper macro to iterate through the linked list */ +#define HTT_LIST_ITER_FWD(iter, head) for (iter = (head)->next; \ + (iter) != (head); \ + (iter) = (iter)->next) \ + +#ifdef RX_HASH_DEBUG +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE 0xDEED + +#define HTT_RX_HASH_COOKIE_SET(hash_element) \ + ((hash_element)->cookie = HTT_RX_HASH_COOKIE) + +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) \ + HTT_ASSERT_ALWAYS((hash_element)->cookie == HTT_RX_HASH_COOKIE) + +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) \ + ((hash_bucket).count++) + +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) \ + ((hash_bucket).count--) + +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) ((hash_bucket).count = 0) + +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) \ + RX_HASH_LOG(cdf_print(" count %d\n", (hash_bucket).count)) +#else /* RX_HASH_DEBUG */ +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE_SET(hash_element) /* no-op */ +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) /* no-op */ +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) /* no-op */ +#endif /* RX_HASH_DEBUG */ + +/* Inserts the given "physical address - network buffer" pair into the + hash table for the given pdev. This function will do the following: + 1. Determine which bucket to insert the pair into + 2. First try to allocate the hash entry for this pair from the pre-allocated + entries list + 3. If there are no more entries in the pre-allocated entries list, allocate + the hash entry from the hash memory pool + Note: this function is not thread-safe + Returns 0 - success, 1 - failure */ +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, uint32_t paddr, + cdf_nbuf_t netbuf) +{ + int i; + struct htt_rx_hash_entry *hash_element = NULL; + + i = RX_HASH_FUNCTION(paddr); + + /* Check if there are any entries in the pre-allocated free list */ + if (pdev->rx_ring.hash_table[i].freepool.next != + &pdev->rx_ring.hash_table[i].freepool) { + + hash_element = + (struct htt_rx_hash_entry *)( + (char *) + pdev->rx_ring.hash_table[i].freepool.next - + pdev->rx_ring.listnode_offset); + if (cdf_unlikely(NULL == hash_element)) { + HTT_ASSERT_ALWAYS(0); + return 1; + } + + htt_list_remove(pdev->rx_ring.hash_table[i].freepool.next); + } else { + hash_element = cdf_mem_malloc(sizeof(struct htt_rx_hash_entry)); + if (cdf_unlikely(NULL == hash_element)) { + HTT_ASSERT_ALWAYS(0); + return 1; + } + hash_element->fromlist = 0; + } + + hash_element->netbuf = netbuf; + hash_element->paddr = paddr; + HTT_RX_HASH_COOKIE_SET(hash_element); + + htt_list_add_tail(&pdev->rx_ring.hash_table[i].listhead, + &hash_element->listnode); + + RX_HASH_LOG(cdf_print("rx hash: %s: paddr 0x%x netbuf %p bucket %d\n", + __func__, paddr, netbuf, (int)i)); + + HTT_RX_HASH_COUNT_INCR(pdev->rx_ring.hash_table[i]); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + + return 0; +} + +/* Given a physical address this function will find the corresponding network + buffer from the hash table. + Note: this function is not thread-safe */ +cdf_nbuf_t htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, uint32_t paddr) +{ + uint32_t i; + struct htt_list_node *list_iter = NULL; + cdf_nbuf_t netbuf = NULL; + struct htt_rx_hash_entry *hash_entry; + + i = RX_HASH_FUNCTION(paddr); + + HTT_LIST_ITER_FWD(list_iter, &pdev->rx_ring.hash_table[i].listhead) { + hash_entry = (struct htt_rx_hash_entry *) + ((char *)list_iter - + pdev->rx_ring.listnode_offset); + + HTT_RX_HASH_COOKIE_CHECK(hash_entry); + + if (hash_entry->paddr == paddr) { + /* Found the entry corresponding to paddr */ + netbuf = hash_entry->netbuf; + htt_list_remove(&hash_entry->listnode); + HTT_RX_HASH_COUNT_DECR(pdev->rx_ring.hash_table[i]); + /* if the rx entry is from the pre-allocated list, + return it */ + if (hash_entry->fromlist) + htt_list_add_tail(&pdev->rx_ring.hash_table[i]. + freepool, + &hash_entry->listnode); + else + cdf_mem_free(hash_entry); + + break; + } + } + + RX_HASH_LOG(cdf_print("rx hash: %s: paddr 0x%x, netbuf %p, bucket %d\n", + __func__, paddr, netbuf, (int)i)); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + + if (netbuf == NULL) { + cdf_print("rx hash: %s: no entry found for 0x%x!!!\n", + __func__, paddr); + HTT_ASSERT_ALWAYS(0); + } + + return netbuf; +} + +/* Initialization function of the rx buffer hash table. This function will + allocate a hash table of a certain pre-determined size and initialize all + the elements */ +int htt_rx_hash_init(struct htt_pdev_t *pdev) +{ + int i, j; + + HTT_ASSERT2(IS_PWR2(RX_NUM_HASH_BUCKETS)); + + pdev->rx_ring.hash_table = + cdf_mem_malloc(RX_NUM_HASH_BUCKETS * + sizeof(struct htt_rx_hash_bucket)); + + if (NULL == pdev->rx_ring.hash_table) { + cdf_print("rx hash table allocation failed!\n"); + return 1; + } + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + HTT_RX_HASH_COUNT_RESET(pdev->rx_ring.hash_table[i]); + + /* initialize the hash table buckets */ + htt_list_init(&pdev->rx_ring.hash_table[i].listhead); + + /* initialize the hash table free pool per bucket */ + htt_list_init(&pdev->rx_ring.hash_table[i].freepool); + + /* pre-allocate a pool of entries for this bucket */ + pdev->rx_ring.hash_table[i].entries = + cdf_mem_malloc(RX_ENTRIES_SIZE * + sizeof(struct htt_rx_hash_entry)); + + if (NULL == pdev->rx_ring.hash_table[i].entries) { + cdf_print("rx hash bucket %d entries alloc failed\n", + (int)i); + while (i) { + i--; + cdf_mem_free(pdev->rx_ring.hash_table[i]. + entries); + } + cdf_mem_free(pdev->rx_ring.hash_table); + pdev->rx_ring.hash_table = NULL; + return 1; + } + + /* initialize the free list with pre-allocated entries */ + for (j = 0; j < RX_ENTRIES_SIZE; j++) { + pdev->rx_ring.hash_table[i].entries[j].fromlist = 1; + htt_list_add_tail(&pdev->rx_ring.hash_table[i].freepool, + &pdev->rx_ring.hash_table[i]. + entries[j].listnode); + } + } + + pdev->rx_ring.listnode_offset = + cdf_offsetof(struct htt_rx_hash_entry, listnode); + + return 0; +} + +void htt_rx_hash_dump_table(struct htt_pdev_t *pdev) +{ + uint32_t i; + struct htt_rx_hash_entry *hash_entry; + struct htt_list_node *list_iter = NULL; + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + HTT_LIST_ITER_FWD(list_iter, + &pdev->rx_ring.hash_table[i].listhead) { + hash_entry = + (struct htt_rx_hash_entry *)((char *)list_iter - + pdev->rx_ring. + listnode_offset); + cdf_print("hash_table[%d]: netbuf %p paddr 0x%x\n", i, + hash_entry->netbuf, hash_entry->paddr); + } + } +} + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* move the function to the end of file + * to omit ll/hl pre-declaration + */ +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + cdf_dma_addr_t paddr; +#if HTT_PADDR64 + uint32_t ring_elem_size = sizeof(uint64_t); +#else + uint32_t ring_elem_size = sizeof(uint32_t); +#endif /* HTT_PADDR64 */ + pdev->rx_ring.size = htt_rx_ring_size(pdev); + HTT_ASSERT2(IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + + /* + * Set the initial value for the level to which the rx ring + * should be filled, based on the max throughput and the worst + * likely latency for the host to fill the rx ring. + * In theory, this fill level can be dynamically adjusted from + * the initial value set here to reflect the actual host latency + * rather than a conservative assumption. + */ + pdev->rx_ring.fill_level = htt_rx_ring_fill_level(pdev); + + if (pdev->cfg.is_full_reorder_offload) { + if (htt_rx_hash_init(pdev)) + goto fail1; + + /* allocate the target index */ + pdev->rx_ring.target_idx.vaddr = + cdf_os_mem_alloc_consistent(pdev->osdev, + sizeof(uint32_t), + &paddr, + cdf_get_dma_mem_context( + (&pdev->rx_ring.target_idx), + memctx)); + + if (!pdev->rx_ring.target_idx.vaddr) + goto fail1; + + pdev->rx_ring.target_idx.paddr = paddr; + *pdev->rx_ring.target_idx.vaddr = 0; + } else { + pdev->rx_ring.buf.netbufs_ring = + cdf_mem_malloc(pdev->rx_ring.size * sizeof(cdf_nbuf_t)); + if (!pdev->rx_ring.buf.netbufs_ring) + goto fail1; + + pdev->rx_ring.sw_rd_idx.msdu_payld = 0; + pdev->rx_ring.sw_rd_idx.msdu_desc = 0; + } + + pdev->rx_ring.buf.paddrs_ring = + cdf_os_mem_alloc_consistent( + pdev->osdev, + pdev->rx_ring.size * ring_elem_size, + &paddr, + cdf_get_dma_mem_context( + (&pdev->rx_ring.buf), + memctx)); + if (!pdev->rx_ring.buf.paddrs_ring) + goto fail2; + + pdev->rx_ring.base_paddr = paddr; + pdev->rx_ring.alloc_idx.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + sizeof(uint32_t), + &paddr, + cdf_get_dma_mem_context( + (&pdev->rx_ring.alloc_idx), + memctx)); + + if (!pdev->rx_ring.alloc_idx.vaddr) + goto fail3; + + pdev->rx_ring.alloc_idx.paddr = paddr; + *pdev->rx_ring.alloc_idx.vaddr = 0; + + /* + * Initialize the Rx refill reference counter to be one so that + * only one thread is allowed to refill the Rx ring. + */ + cdf_atomic_init(&pdev->rx_ring.refill_ref_cnt); + cdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); + + /* Initialize the Rx refill retry timer */ + cdf_softirq_timer_init(pdev->osdev, + &pdev->rx_ring.refill_retry_timer, + htt_rx_ring_refill_retry, (void *)pdev, + CDF_TIMER_TYPE_SW); + + pdev->rx_ring.fill_cnt = 0; +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx = 0; + pdev->rx_ring.dbg_refill_cnt = 0; + pdev->rx_ring.dbg_sync_success = 0; +#endif +#ifdef HTT_RX_RESTORE + pdev->rx_ring.rx_reset = 0; + pdev->rx_ring.htt_rx_restore = 0; +#endif + htt_rx_ring_fill_n(pdev, pdev->rx_ring.fill_level); + + if (pdev->cfg.is_full_reorder_offload) { + cdf_print("HTT: full reorder offload enabled\n"); + htt_rx_amsdu_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_mpdu_desc_list_next = + htt_rx_in_ord_mpdu_desc_list_next_ll; + } else { + htt_rx_amsdu_pop = htt_rx_amsdu_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_pop_ll; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_ll; + } + + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_ll; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_ll; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_ll; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_ll; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_ll; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_ll; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_ll; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_ll; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_ll; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_ll; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_ll; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_ll; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_ll; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_ll; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_ll; + + return 0; /* success */ + +fail3: + cdf_os_mem_free_consistent(pdev->osdev, + pdev->rx_ring.size * sizeof(uint32_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + cdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); + +fail2: + if (pdev->cfg.is_full_reorder_offload) { + cdf_os_mem_free_consistent(pdev->osdev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + cdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + htt_rx_hash_deinit(pdev); + } else { + cdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + } + +fail1: + return 1; /* failure */ +} + +#ifdef IPA_OFFLOAD +int htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + /* Allocate RX indication ring */ + /* RX IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length */ + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + rx_ind_ring_elements * + sizeof(struct ipa_uc_rx_ring_elem_t), + &pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ind_ring_base), + memctx)); + if (!pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr) { + cdf_print("%s: RX IND RING alloc fail", __func__); + return -ENOBUFS; + } + + /* RX indication ring size, by bytes */ + pdev->ipa_uc_rx_rsc.rx_ind_ring_size = + rx_ind_ring_elements * sizeof(struct ipa_uc_rx_ring_elem_t); + cdf_mem_zero(pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size); + + /* Allocate RX process done index */ + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + 4, + &pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx), + memctx)); + if (!pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr) { + cdf_print("%s: RX PROC DONE IND alloc fail", __func__); + cdf_os_mem_free_consistent( + pdev->osdev, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ind_ring_base), + memctx)); + return -ENOBUFS; + } + cdf_mem_zero(pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr, 4); + + /* Allocate RX2 indication ring */ + /* RX2 IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length */ + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + rx_ind_ring_elements * + sizeof(struct ipa_uc_rx_ring_elem_t), + &pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ind_ring_base), + memctx)); + if (!pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr) { + cdf_print("%s: RX IND RING alloc fail", __func__); + return -ENOBUFS; + } + + /* RX indication ring size, by bytes */ + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size = + rx_ind_ring_elements * sizeof(struct ipa_uc_rx_ring_elem_t); + cdf_mem_zero(pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size); + + /* Allocate RX process done index */ + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + 4, + &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx), + memctx)); + if (!pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr) { + cdf_print("%s: RX PROC DONE IND alloc fail", __func__); + cdf_os_mem_free_consistent( + pdev->osdev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ind_ring_base), + memctx)); + return -ENOBUFS; + } + cdf_mem_zero(pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr, 4); + return 0; +} + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + if (pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ind_ring_base), + memctx)); + } + + if (pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + 4, + pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx.vaddr, + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx), + memctx)); + } + if (pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ind_ring_base), + memctx)); + } + + if (pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + 4, + pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx), + memctx)); + } + return 0; +} +#endif /* IPA_OFFLOAD */ diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c new file mode 100644 index 0000000000..92d847285c --- /dev/null +++ b/core/dp/htt/htt_t2h.c @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_t2h.c + * @brief Provide functions to process target->host HTT messages. + * @details + * This file contains functions related to target->host HTT messages. + * There are two categories of functions: + * 1. A function that receives a HTT message from HTC, and dispatches it + * based on the HTT message type. + * 2. functions that provide the info elements from specific HTT messages. + */ + +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* cdf_nbuf_t */ + +#include +#include +#include /* htt_tx_status */ + +#include /* HTT_TX_SCHED, etc. */ +#include +#include +#include +#include +/*--- target->host HTT message dispatch function ----------------------------*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, + uint8_t *buffer) +{ +#ifdef BIG_ENDIAN_HOST + /* + * The host endianness is opposite of the target endianness. + * To make uint32_t elements come out correctly, the target->host + * upload has swizzled the bytes in each uint32_t element of the + * message. + * For byte-array message fields like the MAC address, this + * upload swizzling puts the bytes in the wrong order, and needs + * to be undone. + */ + buffer[0] = tgt_mac_addr[3]; + buffer[1] = tgt_mac_addr[2]; + buffer[2] = tgt_mac_addr[1]; + buffer[3] = tgt_mac_addr[0]; + buffer[4] = tgt_mac_addr[7]; + buffer[5] = tgt_mac_addr[6]; + return buffer; +#else + /* + * The host endianness matches the target endianness - + * we can use the mac addr directly from the message buffer. + */ + return tgt_mac_addr; +#endif +} + +static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, cdf_nbuf_t msg) +{ + uint32_t *msg_word; + unsigned num_msdu_bytes; + cdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + int start_idx; + uint8_t *p_fw_msdu_rx_desc = 0; + + msg_word = (uint32_t *) cdf_nbuf_data(msg); + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + /* + * 1 word for the message header, + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2); + pdev->rx_ind_msdu_byte_idx = 0; + + p_fw_msdu_rx_desc = ((uint8_t *) (msg_word) + + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET)); + + /* + * Fix for EV126710, in which BSOD occurs due to last_msdu bit + * not set while the next pointer is deliberately set to NULL + * before calling ol_rx_pn_check_base() + * + * For fragment frames, the HW may not have set the last_msdu bit + * in the rx descriptor, but the SW expects this flag to be set, + * since each fragment is in a separate MPDU. Thus, set the flag here, + * just in case the HW didn't. + */ + start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[start_idx]; + cdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE); + rx_desc = htt_rx_desc(msdu); + *((uint8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc; + rx_desc->msdu_end.last_msdu = 1; + cdf_nbuf_map(pdev->osdev, msdu, CDF_DMA_FROM_DEVICE); +} + +/* Target to host Msg/event handler for low priority messages*/ +void htt_t2h_lp_msg_handler(void *context, cdf_nbuf_t htt_t2h_msg) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + msg_word = (uint32_t *) cdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + switch (msg_type) { + case HTT_T2H_MSG_TYPE_VERSION_CONF: + { + pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word); + pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word); + cdf_print + ("target uses HTT version %d.%d; host uses %d.%d\n", + pdev->tgt_ver.major, pdev->tgt_ver.minor, + HTT_CURRENT_VERSION_MAJOR, + HTT_CURRENT_VERSION_MINOR); + if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR) + cdf_print + ("*** Incompatible host/target HTT versions!\n"); + /* abort if the target is incompatible with the host */ + cdf_assert(pdev->tgt_ver.major == + HTT_CURRENT_VERSION_MAJOR); + if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) { + cdf_print("*** Warning: host/target HTT versions are "); + cdf_print(" different, though compatible!\n"); + } + break; + } + case HTT_T2H_MSG_TYPE_RX_FLUSH: + { + uint16_t peer_id; + uint8_t tid; + int seq_num_start, seq_num_end; + enum htt_rx_flush_action action; + + peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); + tid = HTT_RX_FLUSH_TID_GET(*msg_word); + seq_num_start = + HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1)); + seq_num_end = + HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1)); + action = + HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word + 1)) == + 1 ? htt_rx_flush_release : htt_rx_flush_discard; + ol_rx_flush_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, action); + break; + } + case HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND: + { + int msdu_cnt; + msdu_cnt = + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word); + ol_rx_offload_deliver_ind_handler(pdev->txrx_pdev, + htt_t2h_msg, + msdu_cnt); + break; + } + case HTT_T2H_MSG_TYPE_RX_FRAG_IND: + { + uint16_t peer_id; + uint8_t tid; + + peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word); + htt_rx_frag_set_last_msdu(pdev, htt_t2h_msg); + + ol_rx_frag_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, + peer_id, tid); + break; + } + case HTT_T2H_MSG_TYPE_RX_ADDBA: + { + uint16_t peer_id; + uint8_t tid; + uint8_t win_sz; + uint16_t start_seq_num; + + /* + * FOR NOW, the host doesn't need to know the initial + * sequence number for rx aggregation. + * Thus, any value will do - specify 0. + */ + start_seq_num = 0; + peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_ADDBA_TID_GET(*msg_word); + win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word); + ol_rx_addba_handler(pdev->txrx_pdev, peer_id, tid, + win_sz, start_seq_num, + 0 /* success */); + break; + } + case HTT_T2H_MSG_TYPE_RX_DELBA: + { + uint16_t peer_id; + uint8_t tid; + + peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_DELBA_TID_GET(*msg_word); + ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid); + break; + } + case HTT_T2H_MSG_TYPE_PEER_MAP: + { + uint8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN]; + uint8_t *peer_mac_addr; + uint16_t peer_id; + uint8_t vdev_id; + + peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word); + vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word); + peer_mac_addr = htt_t2h_mac_addr_deswizzle( + (uint8_t *) (msg_word + 1), + &mac_addr_deswizzle_buf[0]); + + ol_rx_peer_map_handler(pdev->txrx_pdev, peer_id, + vdev_id, peer_mac_addr, + 1 /*can tx */); + break; + } + case HTT_T2H_MSG_TYPE_PEER_UNMAP: + { + uint16_t peer_id; + peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); + + ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id); + break; + } + case HTT_T2H_MSG_TYPE_SEC_IND: + { + uint16_t peer_id; + enum htt_sec_type sec_type; + int is_unicast; + + peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word); + sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word); + is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word); + msg_word++; /* point to the first part of the Michael key */ + ol_rx_sec_ind_handler(pdev->txrx_pdev, peer_id, + sec_type, is_unicast, msg_word, + msg_word + 2); + break; + } + case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND: + { + struct htt_mgmt_tx_compl_ind *compl_msg; + + compl_msg = + (struct htt_mgmt_tx_compl_ind *)(msg_word + 1); + + ol_tx_single_completion_handler(pdev->txrx_pdev, + compl_msg->status, + compl_msg->desc_id); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_STATS_CONF: + { + uint64_t cookie; + uint8_t *stats_info_list; + + cookie = *(msg_word + 1); + cookie |= ((uint64_t) (*(msg_word + 2))) << 32; + + stats_info_list = (uint8_t *) (msg_word + 3); + ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie, + stats_info_list); + break; + } +#ifndef REMOVE_PKT_LOG + case HTT_T2H_MSG_TYPE_PKTLOG: + { + uint32_t *pl_hdr; + uint32_t log_type; + pl_hdr = (msg_word + 1); + log_type = + (*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + if ((log_type == PKTLOG_TYPE_TX_CTRL) + || (log_type == PKTLOG_TYPE_TX_STAT) + || (log_type == PKTLOG_TYPE_TX_MSDU_ID) + || (log_type == PKTLOG_TYPE_TX_FRM_HDR) + || (log_type == PKTLOG_TYPE_TX_VIRT_ADDR)) + wdi_event_handler(WDI_EVENT_TX_STATUS, + pdev->txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RC_FIND) + wdi_event_handler(WDI_EVENT_RATE_FIND, + pdev->txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RC_UPDATE) + wdi_event_handler(WDI_EVENT_RATE_UPDATE, + pdev->txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RX_STAT) + wdi_event_handler(WDI_EVENT_RX_DESC, + pdev->txrx_pdev, pl_hdr); + + break; + } +#endif + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: + { + uint32_t htt_credit_delta_abs; + int32_t htt_credit_delta; + int sign; + + htt_credit_delta_abs = + HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word); + sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1; + htt_credit_delta = sign * htt_credit_delta_abs; + ol_tx_credit_completion_handler(pdev->txrx_pdev, + htt_credit_delta); + break; + } + + case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE: + { + uint8_t op_code; + uint16_t len; + uint8_t *op_msg_buffer; + uint8_t *msg_start_ptr; + + msg_start_ptr = (uint8_t *) msg_word; + op_code = + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word); + msg_word++; + len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word); + + op_msg_buffer = + cdf_mem_malloc(sizeof + (struct htt_wdi_ipa_op_response_t) + + len); + if (!op_msg_buffer) { + cdf_print("OPCODE messsage buffer alloc fail"); + break; + } + cdf_mem_copy(op_msg_buffer, + msg_start_ptr, + sizeof(struct htt_wdi_ipa_op_response_t) + + len); + ol_txrx_ipa_uc_op_response(pdev->txrx_pdev, + op_msg_buffer); + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP: + { + uint8_t num_flows; + struct htt_flow_pool_map_payload_t *pool_map_payoad; + + num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word); + + msg_word++; + while (num_flows) { + pool_map_payoad = (struct htt_flow_pool_map_payload_t *) + msg_word; + ol_tx_flow_pool_map_handler(pool_map_payoad->flow_id, + pool_map_payoad->flow_type, + pool_map_payoad->flow_pool_id, + pool_map_payoad->flow_pool_size); + + msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ / + HTT_FLOW_POOL_MAP_HEADER_SZ); + num_flows--; + } + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP: + { + struct htt_flow_pool_unmap_t *pool_numap_payload; + + pool_numap_payload = (struct htt_flow_pool_unmap_t *)msg_word; + ol_tx_flow_pool_unmap_handler(pool_numap_payload->flow_id, + pool_numap_payload->flow_type, + pool_numap_payload->flow_pool_id); + break; + } + + default: + break; + }; + /* Free the indication buffer */ + cdf_nbuf_free(htt_t2h_msg); +} + +/* Generic Target to host Msg/event handler for low priority messages + Low priority message are handler in a different handler called from + this function . So that the most likely succes path like Rx and + Tx comp has little code foot print + */ +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + cdf_nbuf_t htt_t2h_msg = (cdf_nbuf_t) pkt->pPktContext; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + /* check for successful message reception */ + if (pkt->Status != A_OK) { + if (pkt->Status != A_ECANCELED) + pdev->stats.htc_err_cnt++; + cdf_nbuf_free(htt_t2h_msg); + return; + } +#ifdef HTT_RX_RESTORE + if (cdf_unlikely(pdev->rx_ring.rx_reset)) { + cdf_print("rx restore ..\n"); + cdf_nbuf_free(htt_t2h_msg); + return; + } +#endif + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long)cdf_nbuf_data(htt_t2h_msg)) & 0x3) == 0); + + msg_word = (uint32_t *) cdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s %d: msg_word 0x%x msg_type %d\n", + __func__, __LINE__, *msg_word, msg_type); +#endif + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned num_mpdu_ranges; + unsigned num_msdu_bytes; + uint16_t peer_id; + uint8_t tid; + + if (cdf_unlikely(pdev->cfg.is_full_reorder_offload)) { + cdf_print("HTT_T2H_MSG_TYPE_RX_IND not supported "); + cdf_print("with full reorder offload\n"); + break; + } + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW rx PPDU desc + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3) >> 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + + ol_rx_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, peer_id, + tid, num_mpdu_ranges); + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int num_msdus; + enum htt_tx_status status; + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word + 1); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + uint16_t peer_id; + uint8_t tid, pn_ie_cnt, *pn_ie = NULL; + int seq_num_start, seq_num_end; + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + msg_word++; + /*Third dword */ + if (pn_ie_cnt) + pn_ie = (uint8_t *) msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, + pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message handler + * function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, num_msdus, + msg_word + 1); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + uint16_t peer_id; + uint8_t tid; + uint8_t offload_ind, frag_ind; + + if (cdf_unlikely(!pdev->cfg.is_full_reorder_offload)) { + cdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not "); + cdf_print("supported when full reorder offload is "); + cdf_print("disabled in the configuration.\n"); + break; + } + + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(*msg_word); + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word); + +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s %d: peerid %d tid %d offloadind %d fragind %d\n", + __func__, __LINE__, peer_id, tid, offload_ind, + frag_ind); +#endif + if (cdf_unlikely(frag_ind)) { + ol_rx_frag_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, + peer_id, tid); + break; + } + + ol_rx_in_order_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, peer_id, + tid, offload_ind); + break; + } + + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg); + return; + + }; + + /* Free the indication buffer */ + cdf_nbuf_free(htt_t2h_msg); +} + +/*--- target->host HTT message Info Element access methods ------------------*/ + +/*--- tx completion message ---*/ + +uint16_t htt_tx_compl_desc_id(void *iterator, int num) +{ + /* + * The MSDU IDs are packed , 2 per 32-bit word. + * Iterate on them as an array of 16-bit elements. + * This will work fine if the host endianness matches + * the target endianness. + * If the host endianness is opposite of the target's, + * this iterator will produce descriptor IDs in a different + * order than the target inserted them into the message - + * if the target puts in [0, 1, 2, 3, ...] the host will + * put out [1, 0, 3, 2, ...]. + * This is fine, except for the last ID if there are an + * odd number of IDs. But the TX_COMPL_IND handling code + * in the htt_t2h_msg_handler already added a duplicate + * of the final ID, if there were an odd number of IDs, + * so this function can safely treat the IDs as an array + * of 16-bit elements. + */ + return *(((uint16_t *) iterator) + num); +} + +/*--- rx indication message ---*/ + +int htt_rx_ind_flush(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_FLUSH_VALID_GET(*msg_word); +} + +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} + +int htt_rx_ind_release(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_REL_VALID_GET(*msg_word); +} + +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_REL_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_REL_SEQ_NUM_END_GET(*msg_word); +} + +void +htt_rx_ind_mpdu_range_info(struct htt_pdev_t *pdev, + cdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_ind_msg); + msg_word += pdev->rx_mpdu_range_offset_words + mpdu_range_num; + *status = HTT_RX_IND_MPDU_STATUS_GET(*msg_word); + *mpdu_count = HTT_RX_IND_MPDU_COUNT_GET(*msg_word); +} + +/** + * htt_rx_ind_rssi_dbm() - Return the RSSI provided in a rx indication message. + * + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the RSSI from an rx indication message, in dBm units. + * + * Return: RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + int8_t rssi; + uint32_t *msg_word; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + rssi = HTT_RX_IND_RSSI_CMB_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : rssi; +} + +/** + * htt_rx_ind_rssi_dbm_chain() - Return the RSSI for a chain provided in a rx + * indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @chain: the index of the chain (0-4) + * + * Return the RSSI for a chain from an rx indication message, in dBm units. + * + * Return: RSSI, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + int8_t chain) +{ + int8_t rssi; + uint32_t *msg_word; + + if (chain < 0 || chain > 3) + return HTT_RSSI_INVALID; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + msg_word += 1 + chain; + + rssi = HTT_RX_IND_RSSI_PRI20_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : + rssi; +} + +/** + * htt_rx_ind_legacy_rate() - Return the data rate + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @legacy_rate: (output) the data rate + * The legacy_rate parameter's value depends on the + * legacy_rate_sel value. + * If legacy_rate_sel is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If legacy_rate_sel is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * -1 on error. + * @legacy_rate_sel: (output) 0 to indicate OFDM, 1 to indicate CCK. + * -1 on error. + * + * Return the data rate provided in a rx indication message. + */ +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) { + *legacy_rate = -1; + *legacy_rate_sel = -1; + return; + } + + *legacy_rate = HTT_RX_IND_LEGACY_RATE_GET(*msg_word); + *legacy_rate_sel = HTT_RX_IND_LEGACY_RATE_SEL_GET(*msg_word); +} + +/** + * htt_rx_ind_timestamp() - Return the timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @timestamp_microsec: (output) the timestamp to microsecond resolution. + * -1 on error. + * @timestamp_submicrosec: the submicrosecond portion of the + * timestamp. -1 on error. + * + * Return the timestamp provided in a rx indication message. + */ +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) { + *timestamp_microsec = -1; + *timestamp_submicrosec = -1; + return; + } + + *timestamp_microsec = *(msg_word + 6); + *timestamp_submicrosec = + HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(*msg_word); +} + +#define INVALID_TSF -1 +/** + * htt_rx_ind_tsf32() - Return the TSF timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the TSF timestamp provided in a rx indication message. + * + * Return: TSF timestamp + */ +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) + return INVALID_TSF; + + return *(msg_word + 5); +} + +/** + * htt_rx_ind_ext_tid() - Return the extended traffic ID provided in a rx indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the extended traffic ID in a rx indication message. + * + * Return: Extended TID + */ +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (cdf_nbuf_data(rx_ind_msg)); + + return HTT_RX_IND_EXT_TID_GET(*msg_word); +} + +/*--- stats confirmation message ---*/ + +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data) +{ + uint32_t *msg_word = (uint32_t *) stats_info_list; + *type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + *status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + *length = HTT_T2H_STATS_CONF_TLV_HDR_SIZE + /* header length */ + HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); /* data len */ + *stats_data = stats_info_list + HTT_T2H_STATS_CONF_TLV_HDR_SIZE; +} + +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_frag_ind_msg, + int *seq_num_start, int *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) cdf_nbuf_data(rx_frag_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} diff --git a/core/dp/htt/htt_tx.c b/core/dp/htt/htt_tx.c new file mode 100644 index 0000000000..dc25cbc2e0 --- /dev/null +++ b/core/dp/htt/htt_tx.c @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_tx.c + * @brief Implement transmit aspects of HTT. + * @details + * This file contains three categories of HTT tx code: + * 1. An abstraction of the tx descriptor, to hide the + * differences between the HL vs. LL tx descriptor. + * 2. Functions for allocating and freeing HTT tx descriptors. + * 3. The function that accepts a tx frame from txrx and sends the + * tx frame to HTC. + */ +#include /* uint32_t, offsetof, etc. */ +#include /* cdf_dma_addr_t */ +#include /* cdf_os_mem_alloc_consistent et al */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_mdelay */ + +#include /* htt_tx_msdu_desc_t */ +#include /* HTC_HDR_LENGTH */ +#include /* htc_flush_surprise_remove */ +#include /* ol_cfg_netbuf_frags_max, etc. */ +#include /* HTT_TX_DESC_VADDR_OFFSET */ +#include /* ol_tx_msdu_id_storage */ +#include + +/* IPA Micro controler TX data packet HTT Header Preset */ +/* 31 | 30 29 | 28 | 27 | 26 22 | 21 16 | 15 13 | 12 8 | 7 0 + *---------------------------------------------------------------------------- + * R | CS OL | R | PP | ext TID | vdev ID | pkt type | pkt subtyp | msg type + * 0 | 0 | 0 | | 0x1F | 0 | 2 | 0 | 0x01 + ***---------------------------------------------------------------------------- + * pkt ID | pkt length + ***---------------------------------------------------------------------------- + * frag_desc_ptr + ***---------------------------------------------------------------------------- + * peer_id + ***---------------------------------------------------------------------------- + */ +#define HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT 0x07C04001 + +/*--- setup / tear-down functions -------------------------------------------*/ + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +uint32_t *g_dbg_htt_desc_end_addr, *g_dbg_htt_desc_start_addr; +#endif + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, pool_size; + uint32_t **p; + cdf_dma_addr_t pool_paddr; + +#if defined(HELIUMPLUS_PADDR64) + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + + if (HTT_WIFI_IP_VERSION(pdev->wifi_ip_ver.major, 0x2)) { + /* + * sizeof MSDU_EXT/Fragmentation descriptor. + */ + pdev->frag_descs.size = sizeof(struct msdu_ext_desc_t); + } else { + /* + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->frag_descs.size = + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev)+1) * 8 + + 4; + } +#else /* ! defined(HELIUMPLUS_PADDR64) */ + /* + * Start with the size of the base struct + * that actually gets downloaded. + * + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->tx_descs.size = + sizeof(struct htt_host_tx_desc_t) + + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev) + 1) * 8 + /* 2x uint32_t */ + + 4; /* uint32_t fragmentation list terminator */ + + if (pdev->tx_descs.size < sizeof(uint32_t *)) + pdev->tx_descs.size = sizeof(uint32_t *); +#endif /* defined(HELIUMPLUS_PADDR64) */ + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + + pdev->tx_descs.pool_vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, pool_size, + &pool_paddr, + cdf_get_dma_mem_context((&pdev->tx_descs), memctx)); + + pdev->tx_descs.pool_paddr = pool_paddr; + + if (!pdev->tx_descs.pool_vaddr) + return -ENOBUFS; /* failure */ + + cdf_print("%s:htt_desc_start:0x%p htt_desc_end:0x%p\n", __func__, + pdev->tx_descs.pool_vaddr, + (uint32_t *) (pdev->tx_descs.pool_vaddr + pool_size)); + +#if defined(HELIUMPLUS_PADDR64) + pdev->frag_descs.pool_elems = desc_pool_elems; + /* + * Allocate space for MSDU extension descriptor + * H/W expects this in contiguous memory + */ + pool_size = pdev->frag_descs.pool_elems * pdev->frag_descs.size; + + pdev->frag_descs.pool_vaddr = cdf_os_mem_alloc_consistent( + pdev->osdev, pool_size, &pool_paddr, + cdf_get_dma_mem_context((&pdev->frag_descs), memctx)); + + if (!pdev->frag_descs.pool_vaddr) + return -ENOBUFS; /* failure */ + + pdev->frag_descs.pool_paddr = pool_paddr; + + cdf_print("%s:MSDU Ext.Table Start:0x%p MSDU Ext.Table End:0x%p\n", + __func__, pdev->frag_descs.pool_vaddr, + (u_int32_t *) (pdev->frag_descs.pool_vaddr + pool_size)); +#endif /* defined(HELIUMPLUS_PADDR64) */ + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + g_dbg_htt_desc_end_addr = (uint32_t *) + (pdev->tx_descs.pool_vaddr + pool_size); + g_dbg_htt_desc_start_addr = (uint32_t *) pdev->tx_descs.pool_vaddr; +#endif + + /* link tx descriptors into a freelist */ + pdev->tx_descs.freelist = (uint32_t *) pdev->tx_descs.pool_vaddr; + p = (uint32_t **) pdev->tx_descs.freelist; + for (i = 0; i < desc_pool_elems - 1; i++) { + *p = (uint32_t *) (((char *)p) + pdev->tx_descs.size); + p = (uint32_t **) *p; + } + *p = NULL; + + return 0; /* success */ +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (pdev) { + cdf_os_mem_free_consistent( + pdev->osdev, + /* pool_size */ + pdev->tx_descs.pool_elems * pdev->tx_descs.size, + pdev->tx_descs.pool_vaddr, + pdev->tx_descs.pool_paddr, + cdf_get_dma_mem_context((&pdev->tx_descs), memctx)); +#if defined(HELIUMPLUS_PADDR64) + cdf_os_mem_free_consistent( + pdev->osdev, + /* pool_size */ + pdev->frag_descs.pool_elems * + pdev->frag_descs.size, + pdev->frag_descs.pool_vaddr, + pdev->frag_descs.pool_paddr, + cdf_get_dma_mem_context((&pdev->frag_descs), memctx)); +#endif /* defined(HELIUMPLUS_PADDR64) */ + } +} + +/*--- descriptor allocation functions ---------------------------------------*/ + +void *htt_tx_desc_alloc(htt_pdev_handle pdev, uint32_t *paddr_lo) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; /* includes HTC hdr */ + struct htt_tx_msdu_desc_t *htt_tx_desc; /* doesn't include HTC hdr */ + uint16_t index; + uint32_t *fragmentation_descr_field_ptr; + + htt_host_tx_desc = (struct htt_host_tx_desc_t *)pdev->tx_descs.freelist; + if (!htt_host_tx_desc) + return NULL; /* pool is exhausted */ + + htt_tx_desc = &htt_host_tx_desc->align32.tx_desc; + + if (pdev->tx_descs.freelist) { + pdev->tx_descs.freelist = + *((uint32_t **) pdev->tx_descs.freelist); + pdev->tx_descs.alloc_cnt++; + } + /* + * For LL, set up the fragmentation descriptor address. + * Currently, this HTT tx desc allocation is performed once up front. + * If this is changed to have the allocation done during tx, then it + * would be helpful to have separate htt_tx_desc_alloc functions for + * HL vs. LL, to remove the below conditional branch. + */ + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *) htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + + index = ((char *)htt_host_tx_desc - + (char *)(((struct htt_host_tx_desc_t *) + pdev->tx_descs.pool_vaddr))) / + pdev->tx_descs.size; + /* + * The fragmentation descriptor is allocated from consistent + * memory. Therefore, we can use the address directly rather + * than having to map it from a virtual/CPU address to a + * physical/bus address. + */ +#if defined(HELIUMPLUS_PADDR64) +#if HTT_PADDR64 + /* this is: frags_desc_ptr.lo */ + *fragmentation_descr_field_ptr = (uint32_t) + (pdev->frag_descs.pool_paddr + + (pdev->frag_descs.size * index)); + fragmentation_descr_field_ptr++; + /* frags_desc_ptr.hi */ + *fragmentation_descr_field_ptr = 0; +#else /* ! HTT_PADDR64 */ + *fragmentation_descr_field_ptr = (uint32_t) + (pdev->frag_descs.pool_paddr + + (pdev->frag_descs.size * index)); + cdf_print("%s %d: i %d frag_paddr 0x%x\n", + __func__, __LINE__, index, + (*fragmentation_descr_field_ptr)); +#endif /* HTT_PADDR64 */ +#else /* !HELIUMPLUS_PADDR64 */ + *fragmentation_descr_field_ptr = + HTT_TX_DESC_PADDR(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; +#endif /* HELIUMPLUS_PADDR64 */ + + /* + * Include the headroom for the HTC frame header when specifying the + * physical address for the HTT tx descriptor. + */ + *paddr_lo = (uint32_t) HTT_TX_DESC_PADDR(pdev, htt_host_tx_desc); + /* + * The allocated tx descriptor space includes headroom for a + * HTC frame header. Hide this headroom, so that we don't have + * to jump past the headroom each time we program a field within + * the tx desc, but only once when we download the tx desc (and + * the headroom) to the target via HTC. + * Skip past the headroom and return the address of the HTT tx desc. + */ + return (void *)htt_tx_desc; +} + +void htt_tx_desc_free(htt_pdev_handle pdev, void *tx_desc) +{ + char *htt_host_tx_desc = tx_desc; + /* rewind over the HTC frame header space */ + htt_host_tx_desc -= + offsetof(struct htt_host_tx_desc_t, align32.tx_desc); + *((uint32_t **) htt_host_tx_desc) = pdev->tx_descs.freelist; + pdev->tx_descs.freelist = (uint32_t *) htt_host_tx_desc; + pdev->tx_descs.alloc_cnt--; +} + +/*--- descriptor field access methods ---------------------------------------*/ + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *htt_tx_desc, + uint32_t paddr, + uint32_t frag_desc_paddr_lo, + int reset) +{ + uint32_t *fragmentation_descr_field_ptr; + + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *) htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + if (reset) { +#if defined(HELIUMPLUS_PADDR64) + *fragmentation_descr_field_ptr = frag_desc_paddr_lo; +#else + *fragmentation_descr_field_ptr = + HTT_TX_DESC_PADDR(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; +#endif + } else { + *fragmentation_descr_field_ptr = paddr; + } +} + +#if defined(HELIUMPLUS_PADDR64) +void * +htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, + u_int32_t *frag_paddr_lo) +{ + /** Index should never be 0, since its used by the hardware + to terminate the link. */ + if (index >= pdev->tx_descs.pool_elems) + return NULL; + + *frag_paddr_lo = (uint32_t) + (pdev->frag_descs.pool_paddr + (pdev->frag_descs.size * index)); + + return ((char *) pdev->frag_descs.pool_vaddr) + + (pdev->frag_descs.size * index); +} +#endif /* defined(HELIUMPLUS_PADDR64) */ + +/* PUT THESE AS INLINE IN ol_htt_tx_api.h */ + +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc) +{ +} + +void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + htc_flush_surprise_remove(pdev->htc_pdev); +} + +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc) +{ +} + +/*--- tx send function ------------------------------------------------------*/ + +#ifdef ATH_11AC_TXCOMPACT + +/* Scheduling the Queued packets in HTT which could not be sent out + because of No CE desc*/ +void htt_tx_sched(htt_pdev_handle pdev) +{ + cdf_nbuf_t msdu; + int download_len = pdev->download_len; + int packet_len; + + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + while (msdu != NULL) { + int not_accepted; + /* packet length includes HTT tx desc frag added above */ + packet_len = cdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the + * nominal download length can happen for a couple + * of reasons: + * In HL, the nominal download length is a large + * artificial value. + * In LL, the frame may not have the optional header + * fields accounted for in the nominal download size + * (LLC/SNAP header, IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + not_accepted = + htc_send_data_pkt(pdev->htc_pdev, msdu, + pdev->htc_endpoint, + download_len); + if (not_accepted) { + HTT_TX_NBUF_QUEUE_INSERT_HEAD(pdev, msdu); + return; + } + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + } +} + +int htt_tx_send_std(htt_pdev_handle pdev, cdf_nbuf_t msdu, uint16_t msdu_id) +{ + + int download_len = pdev->download_len; + + int packet_len; + + /* packet length includes HTT tx desc frag added above */ + packet_len = cdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple of reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + NBUF_UPDATE_TX_PKT_COUNT(msdu, NBUF_TX_PKT_HTT); + DPTRACE(cdf_dp_trace(msdu, CDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(msdu)), + sizeof(cdf_nbuf_data(msdu)))); + if (cdf_nbuf_queue_len(&pdev->txnbufq) > 0) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + htt_tx_sched(pdev); + return 0; + } + + cdf_nbuf_trace_update(msdu, "HT:T:"); + if (htc_send_data_pkt + (pdev->htc_pdev, msdu, pdev->htc_endpoint, download_len)) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + } + + return 0; /* success */ + +} + +cdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, cdf_nbuf_t head_msdu, int num_msdus) +{ + cdf_print("*** %s curently only applies for HL systems\n", __func__); + cdf_assert(0); + return head_msdu; + +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + cdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + cdf_assert(download_len <= pdev->download_len); + return htt_tx_send_std(pdev, msdu, msdu_id); +} + +#else /*ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_HTT2_SUPPORT +static inline HTC_ENDPOINT_ID +htt_tx_htt2_get_ep_id(htt_pdev_handle pdev, cdf_nbuf_t msdu) +{ + /* + * TX HTT2 service mainly for small sized frame and check if + * this candidate frame allow or not. + */ + if ((pdev->htc_tx_htt2_endpoint != ENDPOINT_UNUSED) && + cdf_nbuf_get_tx_parallel_dnload_frm(msdu) && + (cdf_nbuf_len(msdu) < pdev->htc_tx_htt2_max_size)) + return pdev->htc_tx_htt2_endpoint; + else + return pdev->htc_endpoint; +} +#else +#define htt_tx_htt2_get_ep_id(pdev, msdu) (pdev->htc_endpoint) +#endif /* QCA_TX_HTT2_SUPPORT */ + +static inline int +htt_tx_send_base(htt_pdev_handle pdev, + cdf_nbuf_t msdu, + uint16_t msdu_id, int download_len, uint8_t more_data) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; + struct htt_htc_pkt *pkt; + int packet_len; + HTC_ENDPOINT_ID ep_id; + + /* + * The HTT tx descriptor was attached as the prefix fragment to the + * msdu netbuf during the call to htt_tx_desc_init. + * Retrieve it so we can provide its HTC header space to HTC. + */ + htt_host_tx_desc = (struct htt_host_tx_desc_t *) + cdf_nbuf_get_frag_vaddr(msdu, 0); + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -ENOBUFS; /* failure */ + + pkt->msdu_id = msdu_id; + pkt->pdev_ctxt = pdev->txrx_pdev; + + /* packet length includes HTT tx desc frag added above */ + packet_len = cdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + pdev->tx_send_complete_part2, + (unsigned char *)htt_host_tx_desc, + download_len - HTC_HDR_LENGTH, + ep_id, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); + + cdf_nbuf_trace_update(msdu, "HT:T:"); + NBUF_UPDATE_TX_PKT_COUNT(msdu, NBUF_TX_PKT_HTT); + DPTRACE(cdf_dp_trace(msdu, CDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(msdu)), + sizeof(cdf_nbuf_data(msdu)))); + htc_send_data_pkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); + + return 0; /* success */ +} + +cdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, cdf_nbuf_t head_msdu, int num_msdus) +{ + cdf_nbuf_t rejected = NULL; + uint16_t *msdu_id_storage; + uint16_t msdu_id; + cdf_nbuf_t msdu; + /* + * FOR NOW, iterate through the batch, sending the frames singly. + * Eventually HTC and HIF should be able to accept a batch of + * data frames rather than singles. + */ + msdu = head_msdu; + while (num_msdus--) { + cdf_nbuf_t next_msdu = cdf_nbuf_next(msdu); + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + msdu_id = *msdu_id_storage; + + /* htt_tx_send_base returns 0 as success and 1 as failure */ + if (htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, + num_msdus)) { + cdf_nbuf_set_next(msdu, rejected); + rejected = msdu; + } + msdu = next_msdu; + } + return rejected; +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + cdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + return htt_tx_send_base(pdev, msdu, msdu_id, download_len, 0); +} + +int htt_tx_send_std(htt_pdev_handle pdev, cdf_nbuf_t msdu, uint16_t msdu_id) +{ + return htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, 0); +} + +#endif /*ATH_11AC_TXCOMPACT */ +#ifdef HTT_DBG +void htt_tx_desc_display(void *tx_desc) +{ + struct htt_tx_msdu_desc_t *htt_tx_desc; + + htt_tx_desc = (struct htt_tx_msdu_desc_t *)tx_desc; + + /* only works for little-endian */ + cdf_print("HTT tx desc (@ %p):\n", htt_tx_desc); + cdf_print(" msg type = %d\n", htt_tx_desc->msg_type); + cdf_print(" pkt subtype = %d\n", htt_tx_desc->pkt_subtype); + cdf_print(" pkt type = %d\n", htt_tx_desc->pkt_type); + cdf_print(" vdev ID = %d\n", htt_tx_desc->vdev_id); + cdf_print(" ext TID = %d\n", htt_tx_desc->ext_tid); + cdf_print(" postponed = %d\n", htt_tx_desc->postponed); +#if HTT_PADDR64 + cdf_print(" reserved_dword0_bits28 = %d\n", htt_tx_desc->reserved_dword0_bits28); + cdf_print(" cksum_offload = %d\n", htt_tx_desc->cksum_offload); + cdf_print(" tx_compl_req= %d\n", htt_tx_desc->tx_compl_req); +#else /* !HTT_PADDR64 */ + cdf_print(" batch more = %d\n", htt_tx_desc->more_in_batch); +#endif /* HTT_PADDR64 */ + cdf_print(" length = %d\n", htt_tx_desc->len); + cdf_print(" id = %d\n", htt_tx_desc->id); +#if HTT_PADDR64 + cdf_print(" frag desc addr.lo = %#x\n", + htt_tx_desc->frags_desc_ptr.lo); + cdf_print(" frag desc addr.hi = %#x\n", + htt_tx_desc->frags_desc_ptr.hi); + cdf_print(" peerid = %d\n", htt_tx_desc->peerid); + cdf_print(" chanfreq = %d\n", htt_tx_desc->chanfreq); +#else /* ! HTT_PADDR64 */ + cdf_print(" frag desc addr = %#x\n", htt_tx_desc->frags_desc_ptr); +#endif /* HTT_PADDR64 */ +} +#endif + +#ifdef IPA_OFFLOAD +int htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + unsigned int tx_buffer_count; + cdf_nbuf_t buffer_vaddr; + uint32_t buffer_paddr; + uint32_t *header_ptr; + uint32_t *ring_vaddr; + int return_code = 0; + unsigned int tx_comp_ring_size; + + /* Allocate CE Write Index WORD */ + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + 4, + &pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr, + cdf_get_dma_mem_context( + (&pdev->ipa_uc_tx_rsc.tx_ce_idx), + memctx)); + if (!pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr) { + cdf_print("%s: CE Write Index WORD alloc fail", __func__); + return -ENOBUFS; + } + + /* Allocate TX COMP Ring */ + tx_comp_ring_size = uc_tx_buf_cnt * sizeof(cdf_nbuf_t); + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr = + cdf_os_mem_alloc_consistent( + pdev->osdev, + tx_comp_ring_size, + &pdev->ipa_uc_tx_rsc.tx_comp_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_tx_rsc. + tx_comp_base), + memctx)); + if (!pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr) { + cdf_print("%s: TX COMP ring alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_ce_idx; + } + + cdf_mem_zero(pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, tx_comp_ring_size); + + /* Allocate TX BUF vAddress Storage */ + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg = + (cdf_nbuf_t *) cdf_mem_malloc(uc_tx_buf_cnt * + sizeof(cdf_nbuf_t)); + if (!pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg) { + cdf_print("%s: TX BUF POOL vaddr storage alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_comp_base; + } + cdf_mem_zero(pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg, + uc_tx_buf_cnt * sizeof(cdf_nbuf_t)); + + ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr; + /* Allocate TX buffers as many as possible */ + for (tx_buffer_count = 0; + tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { + buffer_vaddr = cdf_nbuf_alloc(pdev->osdev, + uc_tx_buf_sz, 0, 4, false); + if (!buffer_vaddr) { + cdf_print("%s: TX BUF alloc fail, loop index: %d", + __func__, tx_buffer_count); + return 0; + } + + /* Init buffer */ + cdf_mem_zero(cdf_nbuf_data(buffer_vaddr), uc_tx_buf_sz); + header_ptr = (uint32_t *) cdf_nbuf_data(buffer_vaddr); + + /* HTT control header */ + *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; + header_ptr++; + + /* PKT ID */ + *header_ptr |= ((uint16_t) uc_tx_partition_base + + tx_buffer_count) << 16; + + cdf_nbuf_map(pdev->osdev, buffer_vaddr, CDF_DMA_BIDIRECTIONAL); + buffer_paddr = cdf_nbuf_get_frag_paddr_lo(buffer_vaddr, 0); + header_ptr++; + + /* Frag Desc Pointer */ + /* 64bits descriptor, Low 32bits */ + *header_ptr = (uint32_t) (buffer_paddr + 20); + header_ptr++; + + /* 64bits descriptor, high 32bits */ + *header_ptr = 0; + header_ptr++; + + /* chanreq, peerid */ + *header_ptr = 0xFFFFFFFF; + + /* FRAG Header */ + /* 6 words TSO header */ + header_ptr += 6; + *header_ptr = buffer_paddr + 64; + + *ring_vaddr = buffer_paddr; + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[tx_buffer_count] = + buffer_vaddr; + /* Memory barrier to ensure actual value updated */ + + ring_vaddr += 2; + } + + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt = tx_buffer_count; + + return 0; + +free_tx_comp_base: + cdf_os_mem_free_consistent(pdev->osdev, + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev-> + ctrl_pdev) * 4, + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, + pdev->ipa_uc_tx_rsc.tx_comp_base.paddr, + cdf_get_dma_mem_context((&pdev-> + ipa_uc_tx_rsc. + tx_comp_base), + memctx)); +free_tx_ce_idx: + cdf_os_mem_free_consistent(pdev->osdev, + 4, + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr, + pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr, + cdf_get_dma_mem_context((&pdev-> + ipa_uc_tx_rsc. + tx_ce_idx), + memctx)); + return return_code; +} + +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + uint16_t idx; + + if (pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + 4, + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr, + pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr, + cdf_get_dma_mem_context( + (&pdev->ipa_uc_tx_rsc.tx_ce_idx), + memctx)); + } + + if (pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr) { + cdf_os_mem_free_consistent( + pdev->osdev, + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev) * 4, + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, + pdev->ipa_uc_tx_rsc.tx_comp_base.paddr, + cdf_get_dma_mem_context((&pdev->ipa_uc_tx_rsc. + tx_comp_base), + memctx)); + } + + /* Free each single buffer */ + for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) { + cdf_nbuf_unmap(pdev->osdev, + pdev->ipa_uc_tx_rsc. + tx_buf_pool_vaddr_strg[idx], + CDF_DMA_FROM_DEVICE); + cdf_nbuf_free(pdev->ipa_uc_tx_rsc. + tx_buf_pool_vaddr_strg[idx]); + } + } + + /* Free storage */ + cdf_mem_free(pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg); + + return 0; +} +#endif /* IPA_OFFLOAD */ + +#if defined(FEATURE_TSO) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct cdf_tso_info_t *tso_info) +{ + u_int32_t *word; + int i; + struct cdf_tso_seg_elem_t *tso_seg = tso_info->curr_seg; + struct msdu_ext_desc_t *msdu_ext_desc = (struct msdu_ext_desc_t *)desc; + + word = (u_int32_t *)(desc); + + /* Initialize the TSO flags per MSDU */ + ((struct msdu_ext_desc_t *)msdu_ext_desc)->tso_flags = + tso_seg->seg.tso_flags; + + /* First 24 bytes (6*4) contain the TSO flags */ + word += 6; + + for (i = 0; i < tso_seg->seg.num_frags; i++) { + /* [31:0] first 32 bits of the buffer pointer */ + *word = tso_seg->seg.tso_frags[i].paddr_low_32; + word++; + /* [15:0] the upper 16 bits of the first buffer pointer */ + /* [31:16] length of the first buffer */ + *word = (tso_seg->seg.tso_frags[i].length << 16); + word++; + } + + if (tso_seg->seg.num_frags < FRAG_NUM_MAX) { + *word = 0; + word++; + *word = 0; + } +} +#endif /* FEATURE_TSO */ diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h new file mode 100644 index 0000000000..4082a850e2 --- /dev/null +++ b/core/dp/htt/htt_types.h @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTT_TYPES__H_ +#define _HTT_TYPES__H_ + +#include /* uint16_t, dma_addr_t */ +#include /* cdf_device_t */ +#include /* cdf_spinlock_t */ +#include /* cdf_softirq_timer_t */ +#include /* cdf_atomic_inc */ +#include /* cdf_nbuf_t */ +#include /* HTC_PACKET */ + +#include /* ol_pdev_handle */ +#include /* ol_txrx_pdev_handle */ + +#define DEBUG_DMA_DONE + +#define HTT_TX_MUTEX_TYPE cdf_spinlock_t + +#ifdef QCA_TX_HTT2_SUPPORT +#ifndef HTC_TX_HTT2_MAX_SIZE +/* Should sync to the target's implementation. */ +#define HTC_TX_HTT2_MAX_SIZE (120) +#endif +#endif /* QCA_TX_HTT2_SUPPORT */ + + +struct htt_htc_pkt { + void *pdev_ctxt; + dma_addr_t nbuf_paddr; + HTC_PACKET htc_pkt; + uint16_t msdu_id; +}; + +struct htt_htc_pkt_union { + union { + struct htt_htc_pkt pkt; + struct htt_htc_pkt_union *next; + } u; +}; + +/* + * HTT host descriptor: + * Include the htt_tx_msdu_desc that gets downloaded to the target, + * but also include the HTC_FRAME_HDR and alignment padding that + * precede the htt_tx_msdu_desc. + * htc_send_data_pkt expects this header space at the front of the + * initial fragment (i.e. tx descriptor) that is downloaded. + */ +struct htt_host_tx_desc_t { + uint8_t htc_header[HTC_HEADER_LEN]; + /* force the tx_desc field to begin on a 4-byte boundary */ + union { + uint32_t dummy_force_align; + struct htt_tx_msdu_desc_t tx_desc; + } align32; +}; + +struct htt_tx_mgmt_desc_buf { + cdf_nbuf_t msg_buf; + A_BOOL is_inuse; + cdf_nbuf_t mgmt_frm; +}; + +struct htt_tx_mgmt_desc_ctxt { + struct htt_tx_mgmt_desc_buf *pool; + A_UINT32 pending_cnt; +}; + +struct htt_list_node { + struct htt_list_node *prev; + struct htt_list_node *next; +}; + +struct htt_rx_hash_entry { + A_UINT32 paddr; + cdf_nbuf_t netbuf; + A_UINT8 fromlist; + struct htt_list_node listnode; +#ifdef RX_HASH_DEBUG + A_UINT32 cookie; +#endif +}; + +struct htt_rx_hash_bucket { + struct htt_list_node listhead; + struct htt_rx_hash_entry *entries; + struct htt_list_node freepool; +#ifdef RX_HASH_DEBUG + A_UINT32 count; +#endif +}; + +/* IPA micro controller + wlan host driver + firmware shared memory structure */ +struct uc_shared_mem_t { + uint32_t *vaddr; + cdf_dma_addr_t paddr; + cdf_dma_mem_context(memctx); +}; + +/* Micro controller datapath offload + * WLAN TX resources */ +struct htt_ipa_uc_tx_resource_t { + struct uc_shared_mem_t tx_ce_idx; + struct uc_shared_mem_t tx_comp_base; + + uint32_t tx_comp_idx_paddr; + cdf_nbuf_t *tx_buf_pool_vaddr_strg; + uint32_t alloc_tx_buf_cnt; +}; + +/* Micro controller datapath offload + * WLAN RX resources */ +struct htt_ipa_uc_rx_resource_t { + cdf_dma_addr_t rx_rdy_idx_paddr; + struct uc_shared_mem_t rx_ind_ring_base; + struct uc_shared_mem_t rx_ipa_prc_done_idx; + uint32_t rx_ind_ring_size; + + /* 2nd RX ring */ + cdf_dma_addr_t rx2_rdy_idx_paddr; + struct uc_shared_mem_t rx2_ind_ring_base; + struct uc_shared_mem_t rx2_ipa_prc_done_idx; + uint32_t rx2_ind_ring_size; +}; + +struct ipa_uc_rx_ring_elem_t { + uint32_t rx_packet_paddr; + uint16_t vdev_id; + uint16_t rx_packet_leng; +}; + +#if defined(HELIUMPLUS_PADDR64) +struct msdu_ext_desc_t { +#if defined(FEATURE_TSO) + struct cdf_tso_flags_t tso_flags; +#else + u_int32_t tso_flag0; + u_int32_t tso_flag1; + u_int32_t tso_flag2; + u_int32_t tso_flag3; + u_int32_t tso_flag4; + u_int32_t tso_flag5; +#endif + u_int32_t frag_ptr0; + u_int32_t frag_len0; + u_int32_t frag_ptr1; + u_int32_t frag_len1; + u_int32_t frag_ptr2; + u_int32_t frag_len2; + u_int32_t frag_ptr3; + u_int32_t frag_len3; + u_int32_t frag_ptr4; + u_int32_t frag_len4; + u_int32_t frag_ptr5; + u_int32_t frag_len5; +}; +#endif /* defined(HELIUMPLUS_PADDR64) */ + +struct htt_pdev_t { + ol_pdev_handle ctrl_pdev; + ol_txrx_pdev_handle txrx_pdev; + HTC_HANDLE htc_pdev; + cdf_device_t osdev; + + HTC_ENDPOINT_ID htc_endpoint; + +#ifdef QCA_TX_HTT2_SUPPORT + HTC_ENDPOINT_ID htc_tx_htt2_endpoint; + uint16_t htc_tx_htt2_max_size; +#endif /* QCA_TX_HTT2_SUPPORT */ + +#ifdef ATH_11AC_TXCOMPACT + HTT_TX_MUTEX_TYPE txnbufq_mutex; + cdf_nbuf_queue_t txnbufq; + struct htt_htc_pkt_union *htt_htc_pkt_misclist; +#endif + + struct htt_htc_pkt_union *htt_htc_pkt_freelist; + struct { + int is_full_reorder_offload; + int default_tx_comp_req; + int ce_classify_enabled; + } cfg; + struct { + uint8_t major; + uint8_t minor; + } tgt_ver; +#if defined(HELIUMPLUS_PADDR64) + struct { + u_int8_t major; + u_int8_t minor; + } wifi_ip_ver; +#endif /* defined(HELIUMPLUS_PADDR64) */ + struct { + struct { + /* + * Ring of network buffer objects - + * This ring is used exclusively by the host SW. + * This ring mirrors the dev_addrs_ring that is shared + * between the host SW and the MAC HW. + * The host SW uses this netbufs ring to locate the nw + * buffer objects whose data buffers the HW has filled. + */ + cdf_nbuf_t *netbufs_ring; + /* + * Ring of buffer addresses - + * This ring holds the "physical" device address of the + * rx buffers the host SW provides for MAC HW to fill. + */ +#if HTT_PADDR64 + uint64_t *paddrs_ring; +#else /* ! HTT_PADDR64 */ + uint32_t *paddrs_ring; +#endif + cdf_dma_mem_context(memctx); + } buf; + /* + * Base address of ring, as a "physical" device address rather + * than a CPU address. + */ + uint32_t base_paddr; + int size; /* how many elems in the ring (power of 2) */ + unsigned size_mask; /* size - 1 */ + + int fill_level; /* how many rx buffers to keep in the ring */ + int fill_cnt; /* # of rx buffers (full+empty) in the ring */ + + /* + * target_idx - + * Without reorder offload: + * not used + * With reorder offload: + * points to the location in the rx ring from which rx buffers + * are available to copy into the MAC DMA ring + */ + struct { + uint32_t *vaddr; + uint32_t paddr; + cdf_dma_mem_context(memctx); + } target_idx; + + /* + * alloc_idx/host_idx - + * Without reorder offload: + * where HTT SW has deposited empty buffers + * This is allocated in consistent mem, so that the FW can read + * this variable, and program the HW's FW_IDX reg with the value + * of this shadow register + * With reorder offload: + * points to the end of the available free rx buffers + */ + struct { + uint32_t *vaddr; + uint32_t paddr; + cdf_dma_mem_context(memctx); + } alloc_idx; + + /* sw_rd_idx - + * where HTT SW has processed bufs filled by rx MAC DMA */ + struct { + unsigned msdu_desc; + unsigned msdu_payld; + } sw_rd_idx; + + /* + * refill_retry_timer - timer triggered when the ring is not + * refilled to the level expected + */ + cdf_softirq_timer_t refill_retry_timer; + + /* + * refill_ref_cnt - ref cnt for Rx buffer replenishment - this + * variable is used to guarantee that only one thread tries + * to replenish Rx ring. + */ + cdf_atomic_t refill_ref_cnt; +#ifdef DEBUG_DMA_DONE + uint32_t dbg_initial_msdu_payld; + uint32_t dbg_mpdu_range; + uint32_t dbg_mpdu_count; + uint32_t dbg_ring_idx; + uint32_t dbg_refill_cnt; + uint32_t dbg_sync_success; +#endif +#ifdef HTT_RX_RESTORE + int rx_reset; + uint8_t htt_rx_restore; +#endif + struct htt_rx_hash_bucket *hash_table; + uint32_t listnode_offset; + } rx_ring; + long rx_fw_desc_offset; + int rx_mpdu_range_offset_words; + int rx_ind_msdu_byte_idx; + + struct { + int size; /* of each HTT tx desc */ + int pool_elems; + int alloc_cnt; + char *pool_vaddr; + uint32_t pool_paddr; + uint32_t *freelist; + cdf_dma_mem_context(memctx); + } tx_descs; +#if defined(HELIUMPLUS_PADDR64) + struct { + int size; /* of each Fragment/MSDU-Ext descriptor */ + int pool_elems; + char *pool_vaddr; + uint32_t pool_paddr; + cdf_dma_mem_context(memctx); + } frag_descs; +#endif /* defined(HELIUMPLUS_PADDR64) */ + + int download_len; + void (*tx_send_complete_part2)(void *pdev, A_STATUS status, + cdf_nbuf_t msdu, uint16_t msdu_id); + + HTT_TX_MUTEX_TYPE htt_tx_mutex; + + struct { + int htc_err_cnt; + } stats; + + struct htt_tx_mgmt_desc_ctxt tx_mgmt_desc_ctxt; + struct targetdef_s *targetdef; + struct ce_reg_def *target_ce_def; + + struct htt_ipa_uc_tx_resource_t ipa_uc_tx_rsc; + struct htt_ipa_uc_rx_resource_t ipa_uc_rx_rsc; +}; + +#define HTT_EPID_GET(_htt_pdev_hdl) \ + (((struct htt_pdev_t *)(_htt_pdev_hdl))->htc_endpoint) + +#if defined(HELIUMPLUS_PADDR64) +#define HTT_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major == (x)) && \ + ((pdev)->wifi_ip_ver.minor == (y))) + +#define HTT_SET_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major = (x)) && \ + ((pdev)->wifi_ip_ver.minor = (y))) +#endif /* defined(HELIUMPLUS_PADDR64) */ + +#endif /* _HTT_TYPES__H_ */ diff --git a/core/dp/htt/rx_desc.h b/core/dp/htt/rx_desc.h new file mode 100644 index 0000000000..66963d1e2b --- /dev/null +++ b/core/dp/htt/rx_desc.h @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _RX_DESC_H_ +#define _RX_DESC_H_ + +/* + * REMIND: Copy one of rx_desc related structures here for export, + * hopes they are always the same between Peregrine and Rome in future + */ +struct rx_attention { + volatile + uint32_t first_mpdu:1, /* [0] */ + last_mpdu:1, /* [1] */ + mcast_bcast:1, /* [2] */ + peer_idx_invalid:1, /* [3] */ + peer_idx_timeout:1, /* [4] */ + power_mgmt:1, /* [5] */ + non_qos:1, /* [6] */ + null_data:1, /* [7] */ + mgmt_type:1, /* [8] */ + ctrl_type:1, /* [9] */ + more_data:1, /* [10] */ + eosp:1, /* [11] */ + u_apsd_trigger:1, /* [12] */ + fragment:1, /* [13] */ + order:1, /* [14] */ + classification:1, /* [15] */ + overflow_err:1, /* [16] */ + msdu_length_err:1, /* [17] */ + tcp_udp_chksum_fail:1, /* [18] */ + ip_chksum_fail:1, /* [19] */ + sa_idx_invalid:1, /* [20] */ + da_idx_invalid:1, /* [21] */ + sa_idx_timeout:1, /* [22] */ + da_idx_timeout:1, /* [23] */ + encrypt_required:1, /* [24] */ + directed:1, /* [25] */ + buffer_fragment:1, /* [26] */ + mpdu_length_err:1, /* [27] */ + tkip_mic_err:1, /* [28] */ + decrypt_err:1, /* [29] */ + fcs_err:1, /* [30] */ + msdu_done:1; /* [31] */ +}; + +struct rx_frag_info { + volatile + uint32_t ring0_more_count:8, /* [7:0] */ + ring1_more_count:8, /* [15:8] */ + ring2_more_count:8, /* [23:16] */ + ring3_more_count:8; /* [31:24] */ + volatile + uint32_t ring4_more_count:8, /* [7:0] */ + ring5_more_count:8, /* [15:8] */ + ring6_more_count:8, /* [23:16] */ + ring7_more_count:8; /* [31:24] */ +}; + +struct rx_msdu_start { + volatile + uint32_t msdu_length:14, /* [13:0] */ +#if defined(HELIUMPLUS) + l3_offset:7, /* [20:14] */ + ipsec_ah:1, /* [21] */ + reserved_0a:2, /* [23:22] */ + l4_offset:7, /* [30:24] */ + ipsec_esp:1; /* [31] */ +#else + ip_offset:6, /* [19:14] */ + ring_mask:4, /* [23:20] */ + tcp_udp_offset:7, /* [30:24] */ + reserved_0c:1; /* [31] */ +#endif /* defined(HELIUMPLUS) */ +#if defined(HELIUMPLUS) + volatile uint32_t flow_id_toeplitz:32; /* [31:0] */ +#else + volatile uint32_t flow_id_crc:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS) */ + volatile + uint32_t msdu_number:8, /* [7:0] */ + decap_format:2, /* [9:8] */ + ipv4_proto:1, /* [10] */ + ipv6_proto:1, /* [11] */ + tcp_proto:1, /* [12] */ + udp_proto:1, /* [13] */ + ip_frag:1, /* [14] */ + tcp_only_ack:1, /* [15] */ + sa_idx:11, /* [26:16] */ + reserved_2b:5; /* [31:27] */ +#if defined(HELIUMPLUS_PADDR64) + volatile + uint32_t da_idx:11, /* [10:0] */ + da_is_bcast_mcast:1, /* [11] */ + reserved_3a:4, /* [15:12] */ + ip4_protocol_ip6_next_header:8, /* [23:16] */ + ring_mask:8; /* [31:24] */ + volatile uint32_t toeplitz_hash_2_or_4:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS_PADDR64) */ +}; + +struct rx_msdu_end { + volatile + uint32_t ip_hdr_chksum:16, /* [15:0] */ + tcp_udp_chksum:16; /* [31:16] */ + volatile + uint32_t key_id_octet:8, /* [7:0] */ +#if defined(HELIUMPLUS) + classification_rule:6, /* [13:8] */ + classify_not_done_truncate:1, /* [14] */ + classify_not_done_cce_dis:1, /* [15] */ +#else + classification_filter:8, /* [15:8] */ +#endif /* defined(HELIUMPLUS) */ + ext_wapi_pn_63_48:16; /* [31:16] */ + volatile uint32_t ext_wapi_pn_95_64:32; /* [31:0] */ + volatile uint32_t ext_wapi_pn_127_96:32; /* [31:0] */ + volatile + uint32_t reported_mpdu_length:14, /* [13:0] */ + first_msdu:1, /* [14] */ + last_msdu:1, /* [15] */ +#if defined(HELIUMPLUS) + sa_idx_timeout:1, /* [16] */ + da_idx_timeout:1, /* [17] */ + msdu_limit_error:1, /* [18] */ + classify_ring_mask:8, /* [26:19] */ +#endif /* defined(HELIUMPLUS) */ + reserved_3a:3, /* [29:27] */ + pre_delim_err:1, /* [30] */ + reserved_3b:1; /* [31] */ +#if defined(HELIUMPLUS_PADDR64) + volatile uint32_t ipv6_options_crc:32; + volatile uint32_t tcp_seq_number:32; + volatile uint32_t tcp_ack_number:32; + volatile + uint32_t tcp_flag:9, /* [8:0] */ + lro_eligible:1, /* [9] */ + l3_header_padding:3, /* [12:10] */ + reserved_8a:3, /* [15:13] */ + window_size:16; /* [31:16] */ + volatile + uint32_t da_offset:6, /* [5:0] */ + sa_offset:6, /* [11:6] */ + da_offset_valid:1, /* [12] */ + sa_offset_valid:1, /* [13] */ + type_offset:7, /* [20:14] */ + reserved_9a:11; /* [31:21] */ + volatile uint32_t rule_indication_31_0:32; + volatile uint32_t rule_indication_63_32:32; + volatile uint32_t rule_indication_95_64:32; + volatile uint32_t rule_indication_127_96:32; +#endif /* defined(HELIUMPLUS_PADDR64) */ +}; + +struct rx_mpdu_end { + volatile + uint32_t reserved_0:13, /* [12:0] */ + overflow_err:1, /* [13] */ + last_mpdu:1, /* [14] */ + post_delim_err:1, /* [15] */ + post_delim_cnt:12, /* [27:16] */ + mpdu_length_err:1, /* [28] */ + tkip_mic_err:1, /* [29] */ + decrypt_err:1, /* [30] */ + fcs_err:1; /* [31] */ +}; + + +#if defined(HELIUMPLUS) + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + reserved:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + toeplitz_hash:2, /* [17:16] */ + reserved_2:10, /* [27:18] */ + tid:4; /* [31:28] */ +}; + + +struct rx_ppdu_start { + volatile + uint32_t rssi_pri_chain0:8, /* [7:0] */ + rssi_sec20_chain0:8, /* [15:8] */ + rssi_sec40_chain0:8, /* [23:16] */ + rssi_sec80_chain0:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain1:8, /* [7:0] */ + rssi_sec20_chain1:8, /* [15:8] */ + rssi_sec40_chain1:8, /* [23:16] */ + rssi_sec80_chain1:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain2:8, /* [7:0] */ + rssi_sec20_chain2:8, /* [15:8] */ + rssi_sec40_chain2:8, /* [23:16] */ + rssi_sec80_chain2:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain3:8, /* [7:0] */ + rssi_sec20_chain3:8, /* [15:8] */ + rssi_sec40_chain3:8, /* [23:16] */ + rssi_sec80_chain3:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + bandwidth:3, /* [10:8] */ + reserved_4a:5, /* [15:11] */ + rssi_comb_ht:8, /* [23:16] */ + reserved_4b:8; /* [31:24] */ + volatile + uint32_t l_sig_rate:4, /*[3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_1:24, /* [23:0] */ + captured_implicit_sounding:1, /* [24] */ + reserved_6:7; /* [31:25] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_2:24, /* [23:0] */ + reserved_7:8; /* [31:24] */ + volatile uint32_t vht_sig_b:32; /* [31:0] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; +struct rx_location_info { + volatile + uint32_t rtt_fac_legacy:14, /* [13:0] */ + rtt_fac_legacy_status:1, /* [14] */ + rtt_fac_vht:14, /* [28:15] */ + rtt_fac_vht_status:1, /* [29] */ + rtt_cfr_status:1, /* [30] */ + rtt_cir_status:1; /* [31] */ + volatile + uint32_t rtt_fac_sifs:10, /* [9:0] */ + rtt_fac_sifs_status:2, /* [11:10] */ + rtt_channel_dump_size:11, /* [22:12] */ + rtt_mac_phy_phase:2, /* [24:23] */ + rtt_hw_ifft_mode:1, /* [25] */ + rtt_btcf_status:1, /* [26] */ + rtt_preamble_type:2, /* [28:27] */ + rtt_pkt_bw:2, /* [30:29] */ + rtt_gi_type:1; /* [31] */ + volatile + uint32_t rtt_mcs_rate:4, /* [3:0] */ + rtt_strongest_chain:2, /* [5:4] */ + rtt_phase_jump:7, /* [12:6] */ + rtt_rx_chain_mask:4, /* [16:13] */ + rtt_tx_data_start_x_phase:1, /* [17] */ + reserved_2:13, /* [30:18] */ + rx_location_info_valid:1; /* [31] */ +}; + +struct rx_pkt_end { + volatile + uint32_t rx_success:1, /* [0] */ + reserved_0a:2, /* [2:1] */ + error_tx_interrupt_rx:1, /* [3] */ + error_ofdm_power_drop:1, /* [4] */ + error_ofdm_restart:1, /* [5] */ + error_cck_power_drop:1, /* [6] */ + error_cck_restart:1, /* [7] */ + reserved_0b:24; /* [31:8] */ + volatile uint32_t phy_timestamp_1_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_1_upper_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_upper_32:32; /* [31:0] */ + struct rx_location_info rx_location_info; +}; + +struct rx_phy_ppdu_end { + volatile + uint32_t reserved_0a:2, /* [1:0] */ + error_radar:1, /* [2] */ + error_rx_abort:1, /* [3] */ + error_rx_nap:1, /* [4] */ + error_ofdm_timing:1, /* [5] */ + error_ofdm_signal_parity:1, /* [6] */ + error_ofdm_rate_illegal:1, /* [7] */ + error_ofdm_length_illegal:1, /* [8] */ + error_ppdu_ofdm_restart:1, /* [9] */ + error_ofdm_service:1, /* [10] */ + error_ppdu_ofdm_power_drop:1, /* [11] */ + error_cck_blocker:1, /* [12] */ + error_cck_timing:1, /* [13] */ + error_cck_header_crc:1, /* [14] */ + error_cck_rate_illegal:1, /* [15] */ + error_cck_length_illegal:1, /* [16] */ + error_ppdu_cck_restart:1, /* [17] */ + error_cck_service:1, /* [18] */ + error_ppdu_cck_power_drop:1, /* [19] */ + error_ht_crc_err:1, /* [20] */ + error_ht_length_illegal:1, /* [21] */ + error_ht_rate_illegal:1, /* [22] */ + error_ht_zlf:1, /* [23] */ + error_false_radar_ext:1, /* [24] */ + error_green_field:1, /* [25] */ + error_spectral_scan:1, /* [26] */ + error_rx_bw_gt_dyn_bw:1, /* [27] */ + error_leg_ht_mismatch:1, /* [28] */ + error_vht_crc_error:1, /* [29] */ + error_vht_siga_unsupported:1, /* [30] */ + error_vht_lsig_len_invalid:1; /* [31] */ + volatile + uint32_t error_vht_ndp_or_zlf:1, /* [0] */ + error_vht_nsym_lt_zero:1, /* [1] */ + error_vht_rx_extra_symbol_mismatch:1, /* [2] */ + error_vht_rx_skip_group_id0:1, /* [3] */ + error_vht_rx_skip_group_id1to62:1, /* [4] */ + error_vht_rx_skip_group_id63:1, /* [5] */ + error_ofdm_ldpc_decoder_disabled:1, /* [6] */ + error_defer_nap:1, /* [7] */ + error_fdomain_timeout:1, /* [8] */ + error_lsig_rel_check:1, /* [9] */ + error_bt_collision:1, /* [10] */ + error_unsupported_mu_feedback:1, /* [11] */ + error_ppdu_tx_interrupt_rx:1, /* [12] */ + error_rx_unsupported_cbf:1, /* [13] */ + reserved_1:18; /* [31:14] */ +}; + +struct rx_timing_offset { + volatile + uint32_t timing_offset:12, /* [11:0] */ + reserved:20; /* [31:12] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; + volatile uint32_t evm_p1:32; + volatile uint32_t evm_p2:32; + volatile uint32_t evm_p3:32; + volatile uint32_t evm_p4:32; + volatile uint32_t evm_p5:32; + volatile uint32_t evm_p6:32; + volatile uint32_t evm_p7:32; + volatile uint32_t evm_p8:32; + volatile uint32_t evm_p9:32; + volatile uint32_t evm_p10:32; + volatile uint32_t evm_p11:32; + volatile uint32_t evm_p12:32; + volatile uint32_t evm_p13:32; + volatile uint32_t evm_p14:32; + volatile uint32_t evm_p15:32; + volatile uint32_t reserved_16:32; + volatile uint32_t reserved_17:32; + volatile uint32_t wb_timestamp_lower_32:32; + volatile uint32_t wb_timestamp_upper_32:32; + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + struct rx_timing_offset rx_timing_offset; + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + rx_pkt_end_valid:1, /* [25] */ + rx_phy_ppdu_end_valid:1, /* [26] */ + rx_timing_offset_valid:1, /* [27] */ + bb_captured_channel:1, /* [28] */ + unsupported_mu_nc:1, /* [29] */ + otp_txbf_disable:1, /* [30] */ + reserved_31:1; /* [31] */ + volatile + uint32_t coex_bt_tx_from_start_of_rx:1, /* [0] */ + coex_bt_tx_after_start_of_rx:1, /* [1] */ + coex_wan_tx_from_start_of_rx:1, /* [2] */ + coex_wan_tx_after_start_of_rx:1, /* [3] */ + coex_wlan_tx_from_start_of_rx:1, /* [4] */ + coex_wlan_tx_after_start_of_rx:1, /* [5] */ + mpdu_delimiter_errors_seen:1, /* [6] */ + ftm:1, /* [7] */ + ftm_dialog_token:8, /* [15:8] */ + ftm_follow_up_dialog_token:8, /* [23:16] */ + reserved_32:8; /* [31:24] */ + volatile + uint32_t before_mpdu_cnt_passing_fcs:8, /* [7:0] */ + before_mpdu_cnt_failing_fcs:8, /* [15:8] */ + after_mpdu_cnt_passing_fcs:8, /* [23:16] */ + after_mpdu_cnt_failing_fcs:8; /* [31:24] */ + volatile uint32_t phy_timestamp_tx_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_tx_upper_32:32; /* [31:0] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + bb_data:1, /* [16] */ + peer_idx_valid:1, /* [17] */ + peer_idx:11, /* [28:18] */ + reserved_26:2, /* [30:29] */ + ppdu_done:1; /* [31] */ +}; +#else +struct rx_ppdu_start { + volatile + uint32_t rssi_chain0_pri20:8, /* [7:0] */ + rssi_chain0_sec20:8, /* [15:8] */ + rssi_chain0_sec40:8, /* [23:16] */ + rssi_chain0_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain1_pri20:8, /* [7:0] */ + rssi_chain1_sec20:8, /* [15:8] */ + rssi_chain1_sec40:8, /* [23:16] */ + rssi_chain1_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain2_pri20:8, /* [7:0] */ + rssi_chain2_sec20:8, /* [15:8] */ + rssi_chain2_sec40:8, /* [23:16] */ + rssi_chain2_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain3_pri20:8, /* [7:0] */ + rssi_chain3_sec20:8, /* [15:8] */ + rssi_chain3_sec40:8, /* [23:16] */ + rssi_chain3_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + reserved_4a:16, /* [23:8] */ + is_greenfield:1, /* [24] */ + reserved_4b:7; /* [31:25] */ + volatile + uint32_t l_sig_rate:4, /* [3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_1:24, /* [23:0] */ + reserved_6:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_2:24, /* [23:0] */ + txbf_h_info:1, /* [24] */ + reserved_7:7; /* [31:25] */ + volatile + uint32_t vht_sig_b:29, /* [28:0] */ + reserved_8:3; /* [31:29] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; + + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + txbf_h_info:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + directed:1, /* [16] */ + reserved_2:11, /* [27:17] */ + tid:4; /* [31:28] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; /* [31:0] */ + volatile uint32_t evm_p1:32; /* [31:0] */ + volatile uint32_t evm_p2:32; /* [31:0] */ + volatile uint32_t evm_p3:32; /* [31:0] */ + volatile uint32_t evm_p4:32; /* [31:0] */ + volatile uint32_t evm_p5:32; /* [31:0] */ + volatile uint32_t evm_p6:32; /* [31:0] */ + volatile uint32_t evm_p7:32; /* [31:0] */ + volatile uint32_t evm_p8:32; /* [31:0] */ + volatile uint32_t evm_p9:32; /* [31:0] */ + volatile uint32_t evm_p10:32; /* [31:0] */ + volatile uint32_t evm_p11:32; /* [31:0] */ + volatile uint32_t evm_p12:32; /* [31:0] */ + volatile uint32_t evm_p13:32; /* [31:0] */ + volatile uint32_t evm_p14:32; /* [31:0] */ + volatile uint32_t evm_p15:32; /* [31:0] */ + volatile uint32_t tsf_timestamp:32; /* [31:0] */ + volatile uint32_t wb_timestamp:32; /* [31:0] */ + volatile + uint32_t locationing_timestamp:8, /* [7:0] */ + phy_err_code:8, /* [15:8] */ + phy_err:1, /* [16] */ + rx_location:1, /* [17] */ + txbf_h_info:1, /* [18] */ + reserved_18:13; /* [31:19] */ + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + bb_captured_channel:1, /* [25] */ + reserved_19:6; /* [31:26] */ + volatile + uint32_t rtt_correction_value:24, /* [23:0] */ + reserved_20:7, /* [30:24] */ + rtt_normal_mode:1; /* [31] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + reserved_21:15, /* [30:16] */ + ppdu_done:1; /* [31] */ +}; +#endif /* defined(HELIUMPLUS) */ + +#endif /*_RX_DESC_H_*/ diff --git a/core/dp/ol/inc/ol_cfg.h b/core/dp/ol/inc/ol_cfg.h new file mode 100644 index 0000000000..4e59ea397d --- /dev/null +++ b/core/dp/ol/inc/ol_cfg.h @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_CFG__H_ +#define _OL_CFG__H_ + +#include /* uint32_t */ +#include /* ol_pdev_handle */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* LLC_SNAP_HDR_LEN */ +#include "wlan_tgt_def_config.h" + +/** + * @brief format of data frames delivered to/from the WLAN driver by/to the OS + */ +enum wlan_frm_fmt { + wlan_frm_fmt_unknown, + wlan_frm_fmt_raw, + wlan_frm_fmt_native_wifi, + wlan_frm_fmt_802_3, +}; + +struct wlan_ipa_uc_rsc_t { + u8 uc_offload_enabled; + u32 tx_max_buf_cnt; + u32 tx_buf_size; + u32 rx_ind_ring_size; + u32 tx_partition_base; +}; + +/* Config parameters for txrx_pdev */ +struct txrx_pdev_cfg_t { + u8 is_high_latency; + u8 defrag_timeout_check; + u8 rx_pn_check; + u8 pn_rx_fwd_check; + u8 host_addba; + u8 tx_free_at_download; + u8 rx_fwd_inter_bss; + u32 max_thruput_mbps; + u32 target_tx_credit; + u32 vow_config; + u32 tx_download_size; + u32 max_peer_id; + u32 max_vdev; + u32 max_nbuf_frags; + u32 throttle_period_ms; + enum wlan_frm_fmt frame_type; + u8 rx_fwd_disabled; + u8 is_packet_log_enabled; + u8 is_full_reorder_offload; + struct wlan_ipa_uc_rsc_t ipa_uc_rsc; + bool ip_tcp_udp_checksum_offload; + bool enable_rxthread; + bool ce_classify_enabled; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint32_t tx_flow_stop_queue_th; + uint32_t tx_flow_start_queue_offset; +#endif +}; + +/** + * @brief Specify whether the system is high-latency or low-latency. + * @details + * Indicate whether the system is operating in high-latency (message + * based, e.g. USB) mode or low-latency (memory-mapped, e.g. PCIe) mode. + * Some chips support just one type of host / target interface. + * Other chips support both LL and HL interfaces (e.g. PCIe and USB), + * so the selection will be made based on which bus HW is present, or + * which is preferred if both are present. + * + * @param pdev - handle to the physical device + * @return 1 -> high-latency -OR- 0 -> low-latency + */ +int ol_cfg_is_high_latency(ol_pdev_handle pdev); + +/** + * @brief Specify the range of peer IDs. + * @details + * Specify the maximum peer ID. This is the maximum number of peers, + * minus one. + * This is used by the host to determine the size of arrays indexed by + * peer ID. + * + * @param pdev - handle to the physical device + * @return maximum peer ID + */ +int ol_cfg_max_peer_id(ol_pdev_handle pdev); + +/** + * @brief Specify the max number of virtual devices within a physical device. + * @details + * Specify how many virtual devices may exist within a physical device. + * + * @param pdev - handle to the physical device + * @return maximum number of virtual devices + */ +int ol_cfg_max_vdevs(ol_pdev_handle pdev); + +/** + * @brief Check whether host-side rx PN check is enabled or disabled. + * @details + * Choose whether to allocate rx PN state information and perform + * rx PN checks (if applicable, based on security type) on the host. + * If the rx PN check is specified to be done on the host, the host SW + * will determine which peers are using a security type (e.g. CCMP) that + * requires a PN check. + * + * @param pdev - handle to the physical device + * @return 1 -> host performs rx PN check -OR- 0 -> no host-side rx PN check + */ +int ol_cfg_rx_pn_check(ol_pdev_handle pdev); + +/** + * @brief Check whether host-side rx forwarding is enabled or disabled. + * @details + * Choose whether to check whether to forward rx frames to tx on the host. + * For LL systems, this rx -> tx host-side forwarding check is typically + * enabled. + * For HL systems, the rx -> tx forwarding check is typically done on the + * target. However, even in HL systems, the host-side rx -> tx forwarding + * will typically be enabled, as a second-tier safety net in case the + * target doesn't have enough memory to store all rx -> tx forwarded frames. + * + * @param pdev - handle to the physical device + * @return 1 -> host does rx->tx forward -OR- 0 -> no host-side rx->tx forward + */ +int ol_cfg_rx_fwd_check(ol_pdev_handle pdev); + +/** + * @brief set rx fwd disable/enable. + * @details + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * currently only intra-bss fwd is supported. + * + * @param pdev - handle to the physical device + * @param disable_rx_fwd 1 -> no rx->tx forward -> rx->tx forward + */ +void ol_set_cfg_rx_fwd_disabled(ol_pdev_handle pdev, uint8_t disalbe_rx_fwd); + +/** + * @brief Check whether rx forwarding is enabled or disabled. + * @details + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * + * @param pdev - handle to the physical device + * @return 1 -> no rx->tx forward -OR- 0 -> rx->tx forward (in host or target) + */ +int ol_cfg_rx_fwd_disabled(ol_pdev_handle pdev); + +/** + * @brief Check whether to perform inter-BSS or intra-BSS rx->tx forwarding. + * @details + * Check whether data received by an AP on one virtual device destined + * to a STA associated with a different virtual device within the same + * physical device should be forwarded within the driver, or whether + * forwarding should only be done within a virtual device. + * + * @param pdev - handle to the physical device + * @return + * 1 -> forward both within and between vdevs + * -OR- + * 0 -> forward only within a vdev + */ +int ol_cfg_rx_fwd_inter_bss(ol_pdev_handle pdev); + +/** + * @brief Specify data frame format used by the OS. + * @details + * Specify what type of frame (802.3 or native WiFi) the host data SW + * should expect from and provide to the OS shim. + * + * @param pdev - handle to the physical device + * @return enumerated data frame format + */ +enum wlan_frm_fmt ol_cfg_frame_type(ol_pdev_handle pdev); + +/** + * @brief Specify the peak throughput. + * @details + * Specify the peak throughput that a system is expected to support. + * The data SW uses this configuration to help choose the size for its + * tx descriptor pool and rx buffer ring. + * The data SW assumes that the peak throughput applies to either rx or tx, + * rather than having separate specs of the rx max throughput vs. the tx + * max throughput. + * + * @param pdev - handle to the physical device + * @return maximum supported throughput in Mbps (not MBps) + */ +int ol_cfg_max_thruput_mbps(ol_pdev_handle pdev); + +/** + * @brief Specify the maximum number of fragments per tx network buffer. + * @details + * Specify the maximum number of fragments that a tx frame provided to + * the WLAN driver by the OS may contain. + * In LL systems, the host data SW uses this maximum fragment count to + * determine how many elements to allocate in the fragmentation descriptor + * it creates to specify to the tx MAC DMA where to locate the tx frame's + * data. + * This maximum fragments count is only for regular frames, not TSO frames, + * since TSO frames are sent in segments with a limited number of fragments + * per segment. + * + * @param pdev - handle to the physical device + * @return maximum number of fragments that can occur in a regular tx frame + */ +int ol_cfg_netbuf_frags_max(ol_pdev_handle pdev); + +/** + * @brief For HL systems, specify when to free tx frames. + * @details + * In LL systems, the host's tx frame is referenced by the MAC DMA, and + * thus cannot be freed until the target indicates that it is finished + * transmitting the frame. + * In HL systems, the entire tx frame is downloaded to the target. + * Consequently, the target has its own copy of the tx frame, and the + * host can free the tx frame as soon as the download completes. + * Alternatively, the HL host can keep the frame allocated until the + * target explicitly tells the HL host it is done transmitting the frame. + * This gives the target the option of discarding its copy of the tx + * frame, and then later getting a new copy from the host. + * This function tells the host whether it should retain its copy of the + * transmit frames until the target explicitly indicates it is finished + * transmitting them, or if it should free its copy as soon as the + * tx frame is downloaded to the target. + * + * @param pdev - handle to the physical device + * @return + * 0 -> retain the tx frame until the target indicates it is done + * transmitting the frame + * -OR- + * 1 -> free the tx frame as soon as the download completes + */ +int ol_cfg_tx_free_at_download(ol_pdev_handle pdev); + +/** + * @brief Low water mark for target tx credit. + * Tx completion handler is invoked to reap the buffers when the target tx + * credit goes below Low Water Mark. + */ +#define OL_CFG_NUM_MSDU_REAP 512 +#define ol_cfg_tx_credit_lwm(pdev) \ + ((CFG_TGT_NUM_MSDU_DESC > OL_CFG_NUM_MSDU_REAP) ? \ + (CFG_TGT_NUM_MSDU_DESC - OL_CFG_NUM_MSDU_REAP) : 0) + +/** + * @brief In a HL system, specify the target initial credit count. + * @details + * The HL host tx data SW includes a module for determining which tx frames + * to download to the target at a given time. + * To make this judgement, the HL tx download scheduler has to know + * how many buffers the HL target has available to hold tx frames. + * Due to the possibility that a single target buffer pool can be shared + * between rx and tx frames, the host may not be able to obtain a precise + * specification of the tx buffer space available in the target, but it + * uses the best estimate, as provided by this configuration function, + * to determine how best to schedule the tx frame downloads. + * + * @param pdev - handle to the physical device + * @return the number of tx buffers available in a HL target + */ +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev); + +/** + * @brief Specify the LL tx MSDU header download size. + * @details + * In LL systems, determine how many bytes from a tx frame to download, + * in order to provide the target FW's Descriptor Engine with enough of + * the packet's payload to interpret what kind of traffic this is, + * and who it is for. + * This download size specification does not include the 802.3 / 802.11 + * frame encapsulation headers; it starts with the encapsulated IP packet + * (or whatever ethertype is carried within the ethernet-ish frame). + * The LL host data SW will determine how many bytes of the MSDU header to + * download by adding this download size specification to the size of the + * frame header format specified by the ol_cfg_frame_type configuration + * function. + * + * @param pdev - handle to the physical device + * @return the number of bytes beyond the 802.3 or native WiFi header to + * download to the target for tx classification + */ +int ol_cfg_tx_download_size(ol_pdev_handle pdev); + +/** + * brief Specify where defrag timeout and duplicate detection is handled + * @details + * non-aggregate duplicate detection and timing out stale fragments + * requires additional target memory. To reach max client + * configurations (128+), non-aggregate duplicate detection and the + * logic to time out stale fragments is moved to the host. + * + * @param pdev - handle to the physical device + * @return + * 0 -> target is responsible non-aggregate duplicate detection and + * timing out stale fragments. + * + * 1 -> host is responsible non-aggregate duplicate detection and + * timing out stale fragments. + */ +int ol_cfg_rx_host_defrag_timeout_duplicate_check(ol_pdev_handle pdev); + +/** + * brief Query for the period in ms used for throttling for + * thermal mitigation + * @details + * In LL systems, transmit data throttling is used for thermal + * mitigation where data is paused and resumed during the + * throttle period i.e. the throttle period consists of an + * "on" phase when transmit is allowed and an "off" phase when + * transmit is suspended. This function returns the total + * period used for throttling. + * + * @param pdev - handle to the physical device + * @return the total throttle period in ms + */ +int ol_cfg_throttle_period_ms(ol_pdev_handle pdev); + +/** + * brief Check whether full reorder offload is + * enabled/disable by the host + * @details + * If the host does not support receive reorder (i.e. the + * target performs full receive re-ordering) this will return + * "enabled" + * + * @param pdev - handle to the physical device + * @return 1 - enable, 0 - disable + */ +int ol_cfg_is_full_reorder_offload(ol_pdev_handle pdev); + +int ol_cfg_is_rx_thread_enabled(ol_pdev_handle pdev); + +/** + * ol_cfg_is_ip_tcp_udp_checksum_offload_enabled() - return + * ip_tcp_udp_checksum_offload is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +static inline +int ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ip_tcp_udp_checksum_offload; +} + + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +int ol_cfg_get_tx_flow_stop_queue_th(ol_pdev_handle pdev); + +int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev); +#endif + +bool ol_cfg_is_ce_classify_enabled(ol_pdev_handle pdev); + +enum wlan_target_fmt_translation_caps { + wlan_frm_tran_cap_raw = 0x01, + wlan_frm_tran_cap_native_wifi = 0x02, + wlan_frm_tran_cap_8023 = 0x04, +}; + +/** + * @brief Specify the maximum header size added by SW tx encapsulation + * @details + * This function returns the maximum size of the new L2 header, not the + * difference between the new and old L2 headers. + * Thus, this function returns the maximum 802.11 header size that the + * tx SW may need to add to tx data frames. + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_sw_encap_hdr_max_size(ol_pdev_handle pdev) +{ + /* + * 24 byte basic 802.11 header + * + 6 byte 4th addr + * + 2 byte QoS control + * + 4 byte HT control + * + 8 byte LLC/SNAP + */ + return sizeof(struct ieee80211_qosframe_htc_addr4) + LLC_SNAP_HDR_LEN; +} + +static inline uint8_t ol_cfg_tx_encap(ol_pdev_handle pdev) +{ + /* tx encap done in HW */ + return 0; +} + +static inline int ol_cfg_host_addba(ol_pdev_handle pdev) +{ + /* + * ADDBA negotiation is handled by the target FW for Peregrine + Rome. + */ + return 0; +} + +/** + * @brief If the host SW's ADDBA negotiation fails, should it be retried? + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_addba_retry(ol_pdev_handle pdev) +{ + return 0; /* disabled for now */ +} + +/** + * @brief How many frames to hold in a paused vdev's tx queue in LL systems + */ +static inline int ol_tx_cfg_max_tx_queue_depth_ll(ol_pdev_handle pdev) +{ + /* + * Store up to 1500 frames for a paused vdev. + * For example, if the vdev is sending 300 Mbps of traffic, and the + * PHY is capable of 600 Mbps, then it will take 56 ms for the PHY to + * drain both the 700 frames that are queued initially, plus the next + * 700 frames that come in while the PHY is catching up. + * So in this example scenario, the PHY will remain fully utilized + * in a MCC system that has a channel-switching period of 56 ms or less. + * 700 frames calculation was correct when FW drain packet without + * any overhead. Actual situation drain overhead will slowdown drain + * speed. And channel period is less than 56 msec + * Worst scenario, 1500 frames should be stored in host. + */ + return 1500; +} + +/** + * @brief Set packet log config in HTT config based on CFG ini configuration + */ +void ol_set_cfg_packet_log_enabled(ol_pdev_handle pdev, uint8_t val); + +/** + * @brief Get packet log config from HTT config + */ +uint8_t ol_cfg_is_packet_log_enabled(ol_pdev_handle pdev); + +#ifdef IPA_OFFLOAD +/** + * @brief IPA micro controller data path offload enable or not + * @detail + * This function returns IPA micro controller data path offload + * feature enabled or not + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_offload_enabled(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer size which should be pre-allocated by driver. + * Default buffer size is 2K + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_buf_size(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer count which should be pre-allocated by driver. + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * RX indication ring size which will notified by WLAN FW to IPA + * micro controller + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_partition_base(ol_pdev_handle pdev); +#else +static inline unsigned int ol_cfg_ipa_uc_offload_enabled( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_buf_size( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_rx_ind_ring_size( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_partition_base( + ol_pdev_handle pdev) +{ + return 0; +} +#endif /* IPA_OFFLOAD */ +#endif /* _OL_CFG__H_ */ diff --git a/core/dp/ol/inc/ol_ctrl_addba_api.h b/core/dp/ol/inc/ol_ctrl_addba_api.h new file mode 100644 index 0000000000..31854e6108 --- /dev/null +++ b/core/dp/ol/inc/ol_ctrl_addba_api.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_CTRL_ADDBA_API_H_ +#define _OL_CTRL_ADDBA_API_H_ +#define ol_ctrl_addba_attach(a, b, c, d, e) 0 +#define ol_ctrl_addba_detach(a) 0 +#define ol_ctrl_addba_init(a, b, c, d, e) 0 +#define ol_ctrl_addba_cleanup(a) 0 +#define ol_ctrl_addba_request_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_response_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_request_process(a, b, c, d, e) 0 +#define ol_ctrl_addba_response_process(a, b, c, d) 0 +#define ol_ctrl_addba_clear(a) 0 +#define ol_ctrl_delba_process(a, b, c) 0 +#define ol_ctrl_addba_get_status(a, b) 0 +#define ol_ctrl_addba_set_response(a, b, c) 0 +#define ol_ctrl_addba_clear_response(a) 0 +#endif diff --git a/core/dp/ol/inc/ol_ctrl_api.h b/core/dp/ol/inc/ol_ctrl_api.h new file mode 100644 index 0000000000..c3e6eb3474 --- /dev/null +++ b/core/dp/ol/inc/ol_ctrl_api.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_ctrl_api.h + * @brief Definitions used in multiple external interfaces to the control SW. + */ +#ifndef _OL_CTRL_API__H_ +#define _OL_CTRL_API__H_ + +struct ol_pdev_t; +typedef struct ol_pdev_t *ol_pdev_handle; + +struct ol_vdev_t; +typedef struct ol_vdev_t *ol_vdev_handle; + +struct ol_peer_t; +typedef struct ol_peer_t *ol_peer_handle; + +#endif /* _OL_CTRL_API__H_ */ diff --git a/core/dp/ol/inc/ol_defines.h b/core/dp/ol/inc/ol_defines.h new file mode 100644 index 0000000000..8b83adb85f --- /dev/null +++ b/core/dp/ol/inc/ol_defines.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Offload specific Opaque Data types. + */ +#ifndef _DEV_OL_DEFINES_H +#define _DEV_OL_DEFINES_H + +/** + * @brief Opaque handle of wmi structure + */ +struct wmi_unified; +typedef struct wmi_unified *wmi_unified_t; + +typedef void *ol_scn_t; +/** + * @wmi_event_handler function prototype + */ +typedef int (*wmi_unified_event_handler)(ol_scn_t scn_handle, + uint8_t *event_buf, uint32_t len); + +#endif /* _DEV_OL_DEFINES_H */ diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h new file mode 100644 index 0000000000..4e9e58f1a0 --- /dev/null +++ b/core/dp/ol/inc/ol_htt_api.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_api.h + * @brief Specify the general HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are not specific to + * either tx nor rx. + */ +#ifndef _OL_HTT_API__H_ +#define _OL_HTT_API__H_ + +#include /* cdf_device_t */ +#include /* cdf_nbuf_t */ +#include /* A_STATUS */ +#include /* HTC_HANDLE */ +#include /* ol_pdev_handle */ +#include /* ol_txrx_pdev_handle */ +#include "htt.h" /* htt_dbg_stats_type, etc. */ + +/* TID */ +#define OL_HTT_TID_NON_QOS_UNICAST 16 +#define OL_HTT_TID_NON_QOS_MCAST_BCAST 18 + +struct htt_pdev_t; +typedef struct htt_pdev_t *htt_pdev_handle; + +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, cdf_device_t osdev); + +/** + * @brief Allocate and initialize a HTT instance. + * @details + * This function allocates and initializes an HTT instance. + * This involves allocating a pool of HTT tx descriptors in + * consistent memory, allocating and filling a rx ring (LL only), + * and connecting the HTC's HTT_DATA_MSG service. + * The HTC service connect call will block, so this function + * needs to be called in passive context. + * Because HTC setup has not been completed at the time this function + * is called, this function cannot send any HTC messages to the target. + * Messages to configure the target are instead sent in the + * htc_attach_target function. + * + * @param pdev - data SW's physical device handle + * (used as context pointer during HTT -> txrx calls) + * @param desc_pool_size - number of HTT descriptors to (pre)allocate + * @return success -> HTT pdev handle; failure -> NULL + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size); + +/** + * @brief Send HTT configuration messages to the target. + * @details + * For LL only, this function sends a rx ring configuration message to the + * target. For HL, this function is a no-op. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +A_STATUS htt_attach_target(htt_pdev_handle htt_pdev); + +/** + * enum htt_op_mode - Virtual device operation mode + * + * @htt_op_mode_unknown: Unknown mode + * @htt_op_mode_ap: AP mode + * @htt_op_mode_ibss: IBSS mode + * @htt_op_mode_sta: STA (client) mode + * @htt_op_mode_monitor: Monitor mode + * @htt_op_mode_ocb: OCB mode + */ +enum htt_op_mode { + htt_op_mode_unknown, + htt_op_mode_ap, + htt_op_mode_ibss, + htt_op_mode_sta, + htt_op_mode_monitor, + htt_op_mode_ocb, +}; + +/* no-ops */ +#define htt_vdev_attach(htt_pdev, vdev_id, op_mode) +#define htt_vdev_detach(htt_pdev, vdev_id) +#define htt_peer_qos_update(htt_pdev, peer_id, qos_capable) +#define htt_peer_uapsdmask_update(htt_pdev, peer_id, uapsd_mask) + +void htt_pdev_free(htt_pdev_handle pdev); + +/** + * @brief Deallocate a HTT instance. + * + * @param htt_pdev - handle to the HTT instance being torn down + */ +void htt_detach(htt_pdev_handle htt_pdev); + +/** + * @brief Stop the communication between HTT and target + * @details + * For ISOC solution, this function stop the communication between HTT and + * target. + * For Peregrine/Rome, it's already stopped by ol_ath_disconnect_htc + * before ol_txrx_pdev_detach called in ol_ath_detach. So this function is + * a no-op. + * Peregrine/Rome HTT layer is on top of HTC while ISOC solution HTT layer is + * on top of DXE layer. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +void htt_detach_target(htt_pdev_handle htt_pdev); + +/* + * @brief Tell the target side of HTT to suspend H2T processing until synced + * @param htt_pdev - the host HTT object + * @param sync_cnt - what sync count value the target HTT FW should wait for + * before resuming H2T processing + */ +A_STATUS htt_h2t_sync_msg(htt_pdev_handle htt_pdev, uint8_t sync_cnt); + +int +htt_h2t_aggr_cfg_msg(htt_pdev_handle htt_pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu); + +/** + * @brief Get the FW status + * @details + * Trigger FW HTT to retrieve FW status. + * A separate HTT message will come back with the statistics we want. + * + * @param pdev - handle to the HTT instance + * @param stats_type_upload_mask - bitmask identifying which stats to upload + * @param stats_type_reset_mask - bitmask identifying which stats to reset + * @param cookie - unique value to distinguish and identify stats requests + * @return 0 - succeed to send the request to FW; otherwise, failed to do so. + */ +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stats_type, + uint32_t cfg_val, uint64_t cookie); + +/** + * @brief Get the fields from HTT T2H stats upload message's stats info header + * @details + * Parse the a HTT T2H message's stats info tag-length-value header, + * to obtain the stats type, status, data lenght, and data address. + * + * @param stats_info_list - address of stats record's header + * @param[out] type - which type of FW stats are contained in the record + * @param[out] status - whether the stats are (fully) present in the record + * @param[out] length - how large the data portion of the stats record is + * @param[out] stats_data - where the data portion of the stats record is + */ +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data); + +/** + * @brief Display a stats record from the HTT T2H STATS_CONF message. + * @details + * Parse the stats type and status, and invoke a type-specified printout + * to display the stats values. + * + * @param stats_data - buffer holding the stats record from the STATS_CONF msg + * @param concise - whether to do a verbose or concise printout + */ +void htt_t2h_stats_print(uint8_t *stats_data, int concise); + +#ifndef HTT_DEBUG_LEVEL +#if defined(DEBUG) +#define HTT_DEBUG_LEVEL 10 +#else +#define HTT_DEBUG_LEVEL 0 +#endif +#endif + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent); +#else +#define htt_display(pdev, indent) +#endif + +#define HTT_DXE_RX_LOG 0 +#define htt_rx_reorder_log_print(pdev) + +#ifdef IPA_OFFLOAD +/** + * @brief send IPA UC resource config message to firmware with HTT message + * @details + * send IPA UC resource config message to firmware with HTT message + * + * @param pdev - handle to the HTT instance + */ +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev); + +/** + * @brief Client request resource information + * @details + * OL client will reuqest IPA UC related resource information + * Resource information will be distributted to IPA module + * All of the required resources should be pre-allocated + * + * @param pdev - handle to the HTT instance + * @param ce_sr_base_paddr - copy engine source ring base physical address + * @param ce_sr_ring_size - copy engine source ring size + * @param ce_reg_paddr - copy engine register physical address + * @param tx_comp_ring_base_paddr - tx comp ring base physical address + * @param tx_comp_ring_size - tx comp ring size + * @param tx_num_alloc_buffer - number of allocated tx buffer + * @param rx_rdy_ring_base_paddr - rx ready ring base physical address + * @param rx_rdy_ring_size - rx ready ring size + * @param rx_proc_done_idx_paddr - rx process done index physical address + */ +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr); + +/** + * @brief Client set IPA UC doorbell register + * @details + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * @param pdev - handle to the HTT instance + * @param ipa_uc_tx_doorbell_paddr - tx comp doorbell physical address + * @param ipa_uc_rx_doorbell_paddr - rx ready doorbell physical address + */ +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + uint32_t ipa_uc_tx_doorbell_paddr, + uint32_t ipa_uc_rx_doorbell_paddr); + +/** + * @brief Client notify IPA UC data path active or not + * + * @param pdev - handle to the HTT instance + * @param uc_active - UC data path is active or not + * @param is_tx - UC TX is active or not + */ +int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, bool is_tx); + +/** + * @brief query uc data path stats + * + * @param pdev - handle to the HTT instance + */ +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev); + +/** + * @brief Attach IPA UC data path + * + * @param pdev - handle to the HTT instance + */ +int htt_ipa_uc_attach(struct htt_pdev_t *pdev); + +/** + * @brief detach IPA UC data path + * + * @param pdev - handle to the HTT instance + */ +void htt_ipa_uc_detach(struct htt_pdev_t *pdev); +#else +static inline int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr) +{ + return 0; +} + +static inline int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + uint32_t ipa_uc_tx_doorbell_paddr, + uint32_t ipa_uc_rx_doorbell_paddr) +{ + return 0; +} + +static inline int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, + bool is_tx) +{ + return 0; +} + +static inline int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +#endif /* _OL_HTT_API__H_ */ diff --git a/core/dp/ol/inc/ol_htt_rx_api.h b/core/dp/ol/inc/ol_htt_rx_api.h new file mode 100644 index 0000000000..d94c707da4 --- /dev/null +++ b/core/dp/ol/inc/ol_htt_rx_api.h @@ -0,0 +1,863 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_rx_api.h + * @brief Specify the rx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to receive processing. + * In particular, this file specifies methods of the abstract HTT rx + * descriptor, and functions to iterate though a series of rx descriptors + * and rx MSDU buffers. + */ +#ifndef _OL_HTT_RX_API__H_ +#define _OL_HTT_RX_API__H_ + +/* #include / * uint16_t, etc. * / */ +#include /* uint16_t, etc. */ +#include /* cdf_nbuf_t */ +#include /* bool */ + +#include /* HTT_RX_IND_MPDU_STATUS */ +#include /* htt_pdev_handle */ + +#include /* ieee80211_rx_status */ +#include + +/*================ constants and types used in the rx API ===================*/ + +#define HTT_RSSI_INVALID 0x7fff + +/** + * struct ocb_rx_stats_hdr_t - RX stats header + * @version: The version must be 1. + * @length: The length of this structure + * @channel_freq: The center frequency for the packet + * @rssi_cmb: combined RSSI from all chains + * @rssi[4]: rssi for chains 0 through 3 (for 20 MHz bandwidth) + * @tsf32: timestamp in TSF units + * @timestamp_microsec: timestamp in microseconds + * @datarate: MCS index + * @timestamp_submicrosec: submicrosecond portion of the timestamp + * @ext_tid: Extended TID + * @reserved: Ensure the size of the structure is a multiple of 4. + * Must be 0. + * + * When receiving an OCB packet, the RX stats is sent to the user application + * so that the user application can do processing based on the RX stats. + * This structure will be preceded by an ethernet header with + * the proto field set to 0x8152. This struct includes various RX + * paramaters including RSSI, data rate, and center frequency. + */ +PREPACK struct ocb_rx_stats_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + int16_t rssi_cmb; + int16_t rssi[4]; + uint32_t tsf32; + uint32_t timestamp_microsec; + uint8_t datarate; + uint8_t timestamp_submicrosec; + uint8_t ext_tid; + uint8_t reserved; +}; + +/*================ rx indication message field access methods ===============*/ + +/** + * @brief Check if a rx indication message has a rx reorder flush command. + * @details + * Space is reserved in each rx indication message for a rx reorder flush + * command, to release specified MPDUs from the rx reorder holding array + * before processing the new MPDUs referenced by the rx indication message. + * This rx reorder flush command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * flush command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx flush command is valid and should be processed + * before processing new rx MPDUs, + * -OR- + * 0 - the message's rx flush command is invalid and should be ignored + */ +int htt_rx_ind_flush(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to flush. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to flush from the rx reorder holding array + * and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to flush includes the one specified by the start + * sequence number. + * The series of MPDUs to flush excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be flushed. + * These start and end seq num fields are only valid if the "flush valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end); + +/** + * @brief Check if a rx indication message has a rx reorder release command. + * @details + * Space is reserved in each rx indication message for a rx reorder release + * command, to release specified MPDUs from the rx reorder holding array + * after processing the new MPDUs referenced by the rx indication message. + * This rx reorder release command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * release command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx release command is valid and should be processed + * after processing new rx MPDUs, + * -OR- + * 0 - the message's rx release command is invalid and should be ignored + */ +int htt_rx_ind_release(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to release. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to release from the rx reorder holding + * array and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to release includes the one specified by the start + * sequence number. + * The series of MPDUs to release excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be released. + * These start and end seq num fields are only valid if the "release valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to release + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to release + */ +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, + unsigned *seq_num_end); + +/* + * For now, the host HTT -> host data rx status enum + * exactly matches the target HTT -> host HTT rx status enum; + * no translation is required. + * However, the host data SW should only use the htt_rx_status, + * so that in the future a translation from target HTT rx status + * to host HTT rx status can be added, if the need ever arises. + */ +enum htt_rx_status { + htt_rx_status_unknown = HTT_RX_IND_MPDU_STATUS_UNKNOWN, + htt_rx_status_ok = HTT_RX_IND_MPDU_STATUS_OK, + htt_rx_status_err_fcs = HTT_RX_IND_MPDU_STATUS_ERR_FCS, + htt_rx_status_err_dup = HTT_RX_IND_MPDU_STATUS_ERR_DUP, + htt_rx_status_err_replay = HTT_RX_IND_MPDU_STATUS_ERR_REPLAY, + htt_rx_status_err_inv_peer = HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER, + htt_rx_status_ctrl_mgmt_null = HTT_RX_IND_MPDU_STATUS_MGMT_CTRL, + htt_rx_status_tkip_mic_err = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR, + + htt_rx_status_err_misc = HTT_RX_IND_MPDU_STATUS_ERR_MISC +}; + +/** + * @brief Check the status MPDU range referenced by a rx indication message. + * @details + * Check the status of a range of MPDUs referenced by a rx indication message. + * This status determines whether the MPDUs should be processed or discarded. + * If the status is OK, then the MPDUs within the range should be processed + * as usual. + * Otherwise (FCS error, duplicate error, replay error, unknown sender error, + * etc.) the MPDUs within the range should be discarded. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param mpdu_range_num - which MPDU range within the rx ind msg to check, + * starting from 0 + * @param status - (call-by-reference output) MPDU status + * @param mpdu_count - (call-by-reference output) count of MPDUs comprising + * the specified MPDU range + */ +void +htt_rx_ind_mpdu_range_info(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count); + +/** + * @brief Return the RSSI provided in a rx indication message. + * @details + * Return the RSSI from an rx indication message, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + int8_t chain); + +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel); + + +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec); + +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + + +/*==================== rx MPDU descriptor access methods ====================*/ + +/** + * @brief Check if the retry bit is set in Rx-descriptor + * @details + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return boolean -- true if retry is set, false otherwise + */ +extern +bool (*htt_rx_mpdu_desc_retry)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return a rx MPDU's sequence number. + * @details + * This function returns the LSBs of the 802.11 sequence number for the + * provided rx MPDU descriptor. + * Depending on the system, 6-12 LSBs from the 802.11 sequence number are + * returned. (Typically, either the 8 or 12 LSBs are returned.) + * This sequence number is masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the LSBs of the sequence number for the MPDU + */ +extern uint16_t +(*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return a rx MPDU's rx reorder array index, based on sequence number. + * @details + * This function returns a sequence-number based index into the rx + * reorder array for the specified MPDU. + * In some systems, this rx reorder array is simply the LSBs of the + * sequence number, or possibly even the full sequence number. + * To support such systems, the returned index has to be masked with + * the power-of-two array size before using the value to index the + * rx reorder array. + * In other systems, this rx reorder array index is + * (sequence number) % (block ack window size) + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the rx reorder array index the MPDU goes into + */ +/* use sequence number (or LSBs thereof) as rx reorder array index */ +#define htt_rx_mpdu_desc_reorder_idx htt_rx_mpdu_desc_seq_num + +union htt_rx_pn_t { + /* WEP: 24-bit PN */ + uint32_t pn24; + + /* TKIP or CCMP: 48-bit PN */ + uint64_t pn48; + + /* WAPI: 128-bit PN */ + uint64_t pn128[2]; +}; + +/** + * @brief Find the packet number (PN) for a MPDU. + * @details + * This function only applies when the rx PN check is configured to be + * performed in the host rather than the target, and on peers using a + * security type for which a PN check applies. + * The pn_len_bits argument is used to determine which element of the + * htt_rx_pn_t union to deposit the PN value read from the MPDU descriptor + * into. + * A 24-bit PN is deposited into pn->pn24. + * A 48-bit PN is deposited into pn->pn48. + * A 128-bit PN is deposited in little-endian order into pn->pn128. + * Specifically, bits 63:0 of the PN are copied into pn->pn128[0], while + * bits 127:64 of the PN are copied into pn->pn128[1]. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @param pn - the location to copy the packet number into + * @param pn_len_bits - the PN size, in bits + */ +extern void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +/** + * @brief This function Returns the TID value from the Rx descriptor + * for Low Latency driver + * @details + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * @pdev: Handle (pointer) to HTT pdev. + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return: Actual TID set in the packet header. + */ +extern +uint8_t (*htt_rx_mpdu_desc_tid)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the TSF timestamp indicating when a MPDU was received. + * @details + * This function provides the timestamp indicating when the PPDU that + * the specified MPDU belongs to was received. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 32 LSBs of TSF time at which the MPDU's PPDU was received + */ +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the 802.11 header of the MPDU + * @details + * This function provides a pointer to the start of the 802.11 header + * of the Rx MPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return pointer to 802.11 header of the received MPDU + */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the RSSI provided in a rx descriptor. + * @details + * Return the RSSI from a rx descriptor, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc); + +/*==================== rx MSDU descriptor access methods ====================*/ + +/** + * @brief Check if a MSDU completes a MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the final MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - there are subsequent MSDUs within the A-MSDU / MPDU + * -OR- + * 1 - this is the last MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Check if a MSDU is first msdu of MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the first MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - this is interior MSDU in the A-MSDU / MPDU + * -OR- + * 1 - this is the first MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Retrieve encrypt bit from a mpdu desc. + * @details + * Fw will pass all the frame to the host whether encrypted or not, and will + * indicate the encrypt flag in the desc, this function is to get the info + * and used to make a judge whether should make pn check, because + * non-encrypted frames always get the same pn number 0. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 0 - the frame was not encrypted + * 1 - the frame was encrypted + */ +extern bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Indicate whether a rx desc has a WLAN unicast vs. mcast/bcast flag. + * @details + * A flag indicating whether a MPDU was delivered over WLAN as unicast or + * multicast/broadcast may be only valid once per MPDU (LL), or within each + * rx descriptor for the MSDUs within the MPDU (HL). (In practice, it is + * unlikely that A-MSDU aggregation will be used in HL, so typically HL will + * only have one MSDU per MPDU anyway.) + * This function indicates whether the specified rx descriptor contains + * a WLAN ucast vs. mcast/bcast flag. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The rx descriptor does not contain a WLAN ucast vs. mcast flag. + * -OR- + * 1 - The rx descriptor has a valid WLAN ucast vs. mcast flag. + */ +extern int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as unicast or mcast/bcast + * @details + * Indicate whether the MPDU that the specified MSDU belonged to was + * delivered over the WLAN as unicast, or as multicast/broadcast. + * This query can only be performed on rx descriptors for which + * htt_rx_msdu_has_wlan_mcast_flag is true. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was delivered over the WLAN as unicast. + * -OR- + * 1 - The MSDU was delivered over the WLAN as broadcast or multicast. + */ +extern bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as a fragmented frame + * @details + * This query can only be performed on LL system. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was a non-fragmented frame. + * -OR- + * 1 - The MSDU was fragmented frame. + */ +extern int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate if a MSDU should be delivered to the OS shim or discarded. + * @details + * Indicate whether a MSDU should be discarded or delivered to the OS shim. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should be delivered to the OS + * -OR- + * non-zero - The MSDU should not be delivered to the OS. + * If the "forward" flag is set, it should be forwarded to tx. + * Else, it should be discarded. + */ +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU should be forwarded to tx. + * @details + * Indicate whether a MSDU should be forwarded to tx, e.g. for intra-BSS + * STA-to-STA forwarding in an AP, or for multicast echo in an AP. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should not be forwarded + * -OR- + * non-zero - The MSDU should be forwarded. + * If the "discard" flag is set, then the original MSDU can be + * directly forwarded into the tx path. + * Else, a copy (clone?) of the rx MSDU needs to be created to + * send to the tx path. + */ +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU's contents need to be inspected. + * @details + * Indicate whether the host data SW needs to examine the contents of the + * received MSDU, and based on the packet type infer what special handling + * to provide for the MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - No inspection + special handling is required. + * -OR- + * non-zero - Inspect the MSDU contents to infer what special handling + * to apply to the MSDU. + */ +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Provide all action specifications for a rx MSDU + * @details + * Provide all action specifications together. This provides the same + * information in a single function call as would be provided by calling + * the functions htt_rx_msdu_discard, htt_rx_msdu_forward, and + * htt_rx_msdu_inspect. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @param[out] discard - 1: discard the MSDU, 0: deliver the MSDU to the OS + * @param[out] forward - 1: forward the rx MSDU to tx, 0: no rx->tx forward + * @param[out] inspect - 1: process according to MSDU contents, 0: no inspect + */ +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect); + +/** + * @brief Get the key id sent in IV of the frame + * @details + * Provide the key index octet which is taken from IV. + * This is valid only for the first MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @key_id - Key id octet + * @return indication of whether key id access is successful + * true - Success + * false - if this is not first msdu + */ +extern bool +(*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +extern bool +(*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +extern bool +(*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +/*====================== rx MSDU + descriptor delivery ======================*/ + +/** + * @brief Return a linked-list of network buffer holding the next rx A-MSDU. + * @details + * In some systems, the rx MSDUs are uploaded along with the rx + * indication message, while in other systems the rx MSDUs are uploaded + * out of band, via MAC DMA. + * This function provides an abstract way to obtain a linked-list of the + * next MSDUs, regardless of whether the MSDU was delivered in-band with + * the rx indication message, or out of band through MAC DMA. + * In a LL system, this function returns a linked list of the one or more + * MSDUs that together comprise an A-MSDU. + * In a HL system, this function returns a degenerate linked list consisting + * of a single MSDU (head_msdu == tail_msdu). + * This function also makes sure each MSDU's rx descriptor can be found + * through the MSDU's network buffer. + * In most systems, this is trivial - a single network buffer stores both + * the MSDU rx descriptor and the MSDU payload. + * In systems where the rx descriptor is in a separate buffer from the + * network buffer holding the MSDU payload, a pointer to the rx descriptor + * has to be stored in the network buffer. + * After this function call, the descriptor for a given MSDU can be + * obtained via the htt_rx_msdu_desc_retrieve function. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param head_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the head MSDU of the A-MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the tail MSDU of the A-MSDU, or the + * same MSDU that the head_msdu points to if only a single MSDU is + * delivered at a time. + * @return indication of whether any MSDUs in the AMSDU use chaining: + * 0 - no buffer chaining + * 1 - buffers are chained + */ +extern int +(*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu); + +extern int +(*htt_rx_frag_pop)(htt_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + cdf_nbuf_t *head_msdu, cdf_nbuf_t *tail_msdu); + +/** + * @brief Return a linked list of buffers holding one MSDU + * In some systems the buffers are delivered along with offload delivery + * indication message itself, while in other systems the buffers are uploaded + * out of band, via MAC DMA. + * @details + * This function provides an abstract way to obtain a linked-list of the + * buffers corresponding to an msdu, regardless of whether the MSDU was + * delivered in-band with the rx indication message, or out of band through + * MAC DMA. + * In a LL system, this function returns a linked list of one or more + * buffers corresponding to an MSDU + * In a HL system , TODO + * + * @param pdev - the HTT instance the rx data was received on + * @param offload_deliver_msg - the nebuf containing the offload deliver message + * @param head_msdu - call-by-reference network buffer handle, which gets set in this + * function to the head buffer of this MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set in this + * function to the tail buffer of this MSDU + */ +extern int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + cdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + cdf_nbuf_t *head_buf, cdf_nbuf_t *tail_buf); + +/** + * @brief Return the rx descriptor for the next rx MPDU. + * @details + * The rx MSDU descriptors may be uploaded as part of the rx indication + * message, or delivered separately out of band. + * This function provides an abstract way to obtain the next MPDU descriptor, + * regardless of whether the MPDU descriptors are delivered in-band with + * the rx indication message, or out of band. + * This is used to iterate through the series of MPDU descriptors referenced + * by a rx indication message. + * The htt_rx_amsdu_pop function should be called before this function + * (or at least before using the returned rx descriptor handle), so that + * the cache location for the rx descriptor will be flushed before the + * rx descriptor gets used. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return next abstract rx descriptor from the series of MPDUs referenced + * by an rx ind msg + */ +extern void * +(*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, cdf_nbuf_t rx_ind_msg); + +/** + * @brief Retrieve a previously-stored rx descriptor from a MSDU buffer. + * @details + * The data SW will call the htt_rx_msdu_desc_link macro/function to + * link a MSDU's rx descriptor with the buffer holding the MSDU payload. + * This function retrieves the rx MSDU descriptor. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu - the buffer containing the MSDU payload + * @return the corresponding abstract rx MSDU descriptor + */ +extern void * +(*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, cdf_nbuf_t msdu); + +/** + * @brief Free both an rx MSDU descriptor and the associated MSDU buffer. + * @details + * Usually the WLAN driver does not free rx MSDU buffers, but needs to + * do so when an invalid frame (e.g. FCS error) was deposited into the + * queue of rx buffers. + * This function frees both the rx descriptor and the rx frame. + * On some systems, the rx descriptor and rx frame are stored in the + * same buffer, and thus one free suffices for both objects. + * On other systems, the rx descriptor and rx frame are stored + * separately, so distinct frees are internally needed. + * However, in either case, the rx descriptor has been associated with + * the MSDU buffer, and can be retrieved by htt_rx_msdu_desc_retrieve. + * Hence, it is only necessary to provide the MSDU buffer; the HTT SW + * internally finds the corresponding MSDU rx descriptor. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param rx_msdu_desc - rx descriptor for the MSDU being freed + * @param msdu - rx frame buffer for the MSDU being freed + */ +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, cdf_nbuf_t msdu); + +/** + * @brief Look up and free the rx descriptor for a MSDU. + * @details + * When the driver delivers rx frames to the OS, it first needs + * to free the associated rx descriptors. + * In some systems the rx descriptors are allocated in the same + * buffer as the rx frames, so this operation is a no-op. + * In other systems, the rx descriptors are stored separately + * from the rx frames, so the rx descriptor has to be freed. + * The descriptor is located from the MSDU buffer with the + * htt_rx_desc_frame_free macro/function. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param msdu - rx frame buffer for the rx MSDU descriptor being freed + */ +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, cdf_nbuf_t msdu); + +/** + * @brief Add new MSDU buffers for the target to fill. + * @details + * In some systems, the underlying upload mechanism (HIF) allocates new rx + * buffers itself. In other systems, the underlying upload mechanism + * (MAC DMA) needs to be provided with new rx buffers. + * This function is used as an abstract method to indicate to the underlying + * data upload mechanism when it is an appropriate time to allocate new rx + * buffers. + * If the allocation is automatically handled, a la HIF, then this function + * call is ignored. + * If the allocation has to be done explicitly, a la MAC DMA, then this + * function provides the context and timing for such replenishment + * allocations. + * + * @param pdev - the HTT instance the rx data will be received on + */ +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev); + +/** + * @brief Links list of MSDUs into an single MPDU. Updates RX stats + * @details + * When HW MSDU splitting is turned on each MSDU in an AMSDU MPDU occupies + * a separate wbuf for delivery to the network stack. For delivery to the + * monitor mode interface they need to be restitched into an MPDU. This + * function does this. Also updates the RX status if the MPDU starts + * a new PPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param head_msdu - network buffer handle, which points to the first MSDU + * in the list. This is a NULL terminated list + * @param rx_staus - pointer to the status associated with this MPDU. + * Updated only if there is a new PPDU and new status associated with it + * @param clone_not_reqd - If set the MPDU linking destroys the passed in + * list, else operates on a cloned nbuf + * @return network buffer handle to the MPDU + */ +cdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + cdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd); + +/** + * @brief Return the sequence number of MPDUs to flush. + * @param pdev - the HTT instance the rx data was received on + * @param rx_frag_ind_msg - the netbuf containing the rx fragment indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + cdf_nbuf_t rx_frag_ind_msg, + int *seq_num_start, int *seq_num_end); +/** + * @brief Return the HL rx desc size + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the hl rx desc pointer + * + */ +uint16_t htt_rx_msdu_rx_desc_size_hl(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief populates vowext stats by processing RX desc. + * @param msdu - network buffer handle + * @param vowstats - handle to vow ext stats. + */ +void htt_rx_get_vowext_stats(cdf_nbuf_t msdu, struct vow_extstats *vowstats); + +/** + * @brief parses the offload message passed by the target. + * @param pdev - pdev handle + * @param paddr - physical address of the rx buffer + * @param vdev_id - reference to vdev id to be filled + * @param peer_id - reference to the peer id to be filled + * @param tid - reference to the tid to be filled + * @param fw_desc - reference to the fw descriptor to be filled + * @param peer_id - reference to the peer id to be filled + * @param head_buf - reference to the head buffer + * @param tail_buf - reference to the tail buffer + */ +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + cdf_nbuf_t *head_buf, cdf_nbuf_t *tail_buf); +#endif /* _OL_HTT_RX_API__H_ */ diff --git a/core/dp/ol/inc/ol_htt_tx_api.h b/core/dp/ol/inc/ol_htt_tx_api.h new file mode 100644 index 0000000000..58ebabc47c --- /dev/null +++ b/core/dp/ol/inc/ol_htt_tx_api.h @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_tx_api.h + * @brief Specify the tx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to transmit processing. + * In particular, the methods of the abstract HTT tx descriptor are + * specified. + */ +#ifndef _OL_HTT_TX_API__H_ +#define _OL_HTT_TX_API__H_ + +/* #include / * uint16_t, etc. * / */ +#include /* uint16_t, etc. */ +#include /* cdf_nbuf_t */ +#include /* wlan_frm_fmt */ + +#include /* needed by inline functions */ +#include +#include /* htt_pdev_handle */ +#include +#include + +/* Remove these macros when they get added to htt.h. */ +#ifndef HTT_TX_DESC_EXTENSION_GET +#define HTT_TX_DESC_EXTENSION_OFFSET_BYTES 0 +#define HTT_TX_DESC_EXTENSION_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXTENSION_M 0x10000000 +#define HTT_TX_DESC_EXTENSION_S 28 + +#define HTT_TX_DESC_EXTENSION_GET(_var) \ + (((_var) & HTT_TX_DESC_EXTENSION_M) >> HTT_TX_DESC_EXTENSION_S) +#define HTT_TX_DESC_EXTENSION_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXTENSION, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXTENSION_S)); \ + } while (0) +#endif + +/*================ meta-info about tx MSDUs =================================*/ + +/* + * For simplicity, use the IEEE 802.11 frame type values. + */ +enum htt_frm_type { + htt_frm_type_mgmt = 0, + htt_frm_type_ctrl = 1, + htt_frm_type_data = 2 +}; + +/* + * For simplicity, use the IEEE 802.11 frame sub-type values. + */ +enum htt_frm_subtype { + htt_frm_subtype_mgmt_assoc_req = 0, + htt_frm_subtype_mgmt_assoc_resp = 1, + htt_frm_subtype_mgmt_reassoc_req = 2, + htt_frm_subtype_mgmt_reassoc_resp = 3, + htt_frm_subtype_mgmt_probe_req = 4, + htt_frm_subtype_mgmt_probe_resp = 5, + htt_frm_subtype_mgmt_timing_adv = 6, + htt_frm_subtype_mgmt_beacon = 8, + htt_frm_subtype_mgmt_atim = 9, + htt_frm_subtype_mgmt_disassoc = 10, + htt_frm_subtype_mgmt_auth = 11, + htt_frm_subtype_mgmt_deauth = 12, + htt_frm_subtype_mgmt_action = 13, + htt_frm_subtype_mgmt_action_no_ack = 14, + + htt_frm_subtype_data_data = 0, + htt_frm_subtype_data_data_cf_ack = 1, + htt_frm_subtype_data_data_cf_poll = 2, + htt_frm_subtype_data_data_cf_ack_cf_poll = 3, + htt_frm_subtype_data_null = 4, + htt_frm_subtype_data_cf_ack = 5, + htt_frm_subtype_data_cf_poll = 6, + htt_frm_subtype_data_cf_ack_cf_poll = 7, + htt_frm_subtype_data_QoS_data = 8, + htt_frm_subtype_data_QoS_data_cf_ack = 9, + htt_frm_subtype_data_QoS_data_cf_poll = 10, + htt_frm_subtype_data_QoS_data_cf_ack_cf_poll = 11, + htt_frm_subtype_data_QoS_null = 12, + htt_frm_subtype_data_QoS_cf_poll = 14, + htt_frm_subtype_data_QoS_cf_ack_cf_poll = 15, +}; + +enum htt_ofdm_datarate { /* Value MBPS Modulation Coding*/ + htt_ofdm_datarate_6_mbps = 0, /* 0 6 BPSK 1/2 */ + htt_ofdm_datarate_9_mbps = 1, /* 1 9 BPSK 3/4 */ + htt_ofdm_datarate_12_mbps = 2, /* 2 12 QPSK 1/2 */ + htt_ofdm_datarate_18_mbps = 3, /* 3 18 QPSK 3/4 */ + htt_ofdm_datarate_24_mbps = 4, /* 4 24 16-QAM 1/2 */ + htt_ofdm_datarate_36_mbps = 5, /* 5 36 16-QAM 3/4 */ + htt_ofdm_datarate_48_mbps = 6, /* 6 48 64-QAM 1/2 */ + htt_ofdm_datarate_54_mbps = 7, /* 7 54 64-QAM 3/4 */ + htt_ofdm_datarate_max = 7, +}; + +/** + * struct ocb_tx_ctrl_hdr_t - TX control header + * @version: must be 1 + * @length: length of this structure + * @channel_freq: channel on which to transmit the packet + * @valid_pwr: bit 0: if set, tx pwr spec is valid + * @valid_datarate: bit 1: if set, tx MCS mask spec is valid + * @valid_retries: bit 2: if set, tx retries spec is valid + * @valid_chain_mask: bit 3: if set, chain mask is valid + * @valid_expire_tsf: bit 4: if set, tx expire TSF spec is valid + * @valid_tid: bit 5: if set, TID is valid + * @reserved0_15_6: bits 15:6 - unused, set to 0x0 + * @all_flags: union of all the flags + * @expire_tsf_lo: TX expiry time (TSF) LSBs + * @expire_tsf_hi: TX expiry time (TSF) MSBs + * @pwr: Specify what power the tx frame needs to be transmitted + * at. The power a signed (two's complement) value is in + * units of 0.5 dBm. The value needs to be appropriately + * sign-extended when extracting the value from the message + * and storing it in a variable that is larger than A_INT8. + * If the transmission uses multiple tx chains, this power + * spec is the total transmit power, assuming incoherent + * combination of per-chain power to produce the total + * power. + * @datarate: The desired modulation and coding scheme. + * VALUE DATA RATE MODULATION CODING RATE + * @ 20 MHz + * (MBPS) + * 0 6 BPSK 1/2 + * 1 9 BPSK 3/4 + * 2 12 QPSK 1/2 + * 3 18 QPSK 3/4 + * 4 24 16-QAM 1/2 + * 5 36 16-QAM 3/4 + * 6 48 64-QAM 1/2 + * 7 54 64-QAM 3/4 + * @retry_limit: Specify the maximum number of transmissions, including + * the initial transmission, to attempt before giving up if + * no ack is received. + * If the tx rate is specified, then all retries shall use + * the same rate as the initial transmission. + * If no tx rate is specified, the target can choose + * whether to retain the original rate during the + * retransmissions, or to fall back to a more robust rate. + * @chain_mask: specify which chains to transmit from + * @ext_tid: Extended Traffic ID (0-15) + * @reserved: Ensure that the size of the structure is a multiple of + * 4. Must be 0. + * + * When sending an OCB packet, the user application has + * the option of including the following struct following an ethernet header + * with the proto field set to 0x8151. This struct includes various TX + * paramaters including the TX power and MCS. + */ +PREPACK struct ocb_tx_ctrl_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + + union { + struct { + uint16_t + valid_pwr:1, + valid_datarate:1, + valid_retries:1, + valid_chain_mask:1, + valid_expire_tsf:1, + valid_tid:1, + reserved0_15_6:10; + }; + uint16_t all_flags; + }; + + uint32_t expire_tsf_lo; + uint32_t expire_tsf_hi; + int8_t pwr; + uint8_t datarate; + uint8_t retry_limit; + uint8_t chain_mask; + uint8_t ext_tid; + uint8_t reserved[3]; +} POSTPACK; + +/** + * @brief tx MSDU meta-data that HTT may use to program the FW/HW tx descriptor + */ +struct htt_msdu_info_t { + /* the info sub-struct specifies the characteristics of the MSDU */ + struct { + uint16_t ethertype; +#define HTT_INVALID_PEER_ID 0xffff + uint16_t peer_id; + uint8_t vdev_id; + uint8_t ext_tid; + /* + * l2_hdr_type - L2 format (802.3, native WiFi 802.11, + * or raw 802.11) + * Based on attach-time configuration, the tx frames provided + * by the OS to the tx data SW are expected to be either + * 802.3 format or the "native WiFi" variant of 802.11 format. + * Internally, the driver may also inject tx frames into the tx + * datapath, and these frames may be either 802.3 format or + * 802.11 "raw" format, with no further 802.11 encapsulation + * needed. + * The tx frames are tagged with their frame format, so target + * FW/HW will know how to interpret the packet's encapsulation + * headers when doing tx classification, and what form of 802.11 + * header encapsulation is needed, if any. + */ + uint8_t l2_hdr_type; /* enum htt_pkt_type */ + /* + * frame_type - is the tx frame management or data? + * Just to avoid confusion, the enum values for this frame type + * field use the 802.11 frame type values, although it is + * unexpected for control frames to be sent through the host + * data path. + */ + uint8_t frame_type; /* enum htt_frm_type */ + /* + * frame subtype - this field specifies the sub-type of + * management frames + * Just to avoid confusion, the enum values for this frame + * subtype field use the 802.11 management frame subtype values. + */ + uint8_t frame_subtype; /* enum htt_frm_subtype */ + uint8_t is_unicast; + + /* dest_addr is not currently used. + * It could be used as an input to a Tx BD (Riva tx descriptor) + * signature computation. + uint8_t *dest_addr; + */ + + uint8_t l3_hdr_offset; /* wrt cdf_nbuf_data(msdu), in bytes */ + + /* l4_hdr_offset is not currently used. + * It could be used to specify to a TCP/UDP checksum computation + * engine where the TCP/UDP header starts. + */ + /* uint8_t l4_hdr_offset; - wrt cdf_nbuf_data(msdu), in bytes */ + } info; + /* the action sub-struct specifies how to process the MSDU */ + struct { + uint8_t use_6mbps; /* mgmt frames: option to force + 6 Mbps rate */ + uint8_t do_encrypt; + uint8_t do_tx_complete; + uint8_t tx_comp_req; + + /* + * cksum_offload - Specify whether checksum offload is + * enabled or not + * Target FW uses this flag to turn on HW checksumming + * 0x0 - No checksum offload + * 0x1 - L3 header checksum only + * 0x2 - L4 checksum only + * 0x3 - L3 header checksum + L4 checksum + */ + cdf_nbuf_tx_cksum_t cksum_offload; + } action; +}; + +static inline void htt_msdu_info_dump(struct htt_msdu_info_t *msdu_info) +{ + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "HTT MSDU info object (%p)\n", msdu_info); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " ethertype: %#x\n", msdu_info->info.ethertype); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " peer_id: %d\n", msdu_info->info.peer_id); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " vdev_id: %d\n", msdu_info->info.vdev_id); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " ext_tid: %d\n", msdu_info->info.ext_tid); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " l2_hdr_type: %d\n", msdu_info->info.l2_hdr_type); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " frame_type: %d\n", msdu_info->info.frame_type); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " frame_subtype: %d\n", msdu_info->info.frame_subtype); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " l3_hdr_offset: %u\n", msdu_info->info.l3_hdr_offset); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " use 6 Mbps: %d\n", msdu_info->action.use_6mbps); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " do_encrypt: %d\n", msdu_info->action.do_encrypt); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " do_tx_complete: %d\n", msdu_info->action.do_tx_complete); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); +} + +/*================ tx completion message field access methods ===============*/ + +/** + * @brief Look up the descriptor ID of the nth MSDU from a tx completion msg. + * @details + * A tx completion message tells the host that the target is done + * transmitting a series of MSDUs. The message uses a descriptor ID + * to identify each such MSDU. This function/macro is used to + * find the ID of one such MSDU referenced by the tx completion message. + * + * @param iterator - tx completion message context provided by HTT to the + * tx completion message handler. This abstract reference to the + * HTT tx completion message's payload allows the data SW's tx + * completion handler to not care about the format of the HTT + * tx completion message. + * @param num - (zero-based) index to specify a single MSDU within the + * series of MSDUs referenced by the tx completion message + * @return descriptor ID for the specified MSDU + */ +uint16_t htt_tx_compl_desc_id(void *iterator, int num); + +/*========================= tx descriptor operations ========================*/ + +/** + * @brief Allocate a HTT abstract tx descriptor. + * @details + * Allocate a HTT abstract tx descriptor from a pool within "consistent" + * memory, which is accessible by HIF and/or MAC DMA as well as by the + * host CPU. + * It is expected that the tx datapath will allocate HTT tx descriptors + * and link them with datapath SW tx descriptors up front as the driver + * is loaded. Thereafter, the link from datapath SW tx descriptor to + * HTT tx descriptor will be maintained until the driver is unloaded. + * + * @param htt_pdev - handle to the HTT instance making the allocation + * @param[OUT] paddr_lo - physical address of the HTT descriptor + * @return success -> descriptor handle, -OR- failure -> NULL + */ +void *htt_tx_desc_alloc(htt_pdev_handle htt_pdev, uint32_t *paddr_lo); + +/** + * @brief Free a HTT abstract tx descriptor. + * + * @param htt_pdev - handle to the HTT instance that made the allocation + * @param htt_tx_desc - the descriptor to free + */ +void htt_tx_desc_free(htt_pdev_handle htt_pdev, void *htt_tx_desc); + +#if defined(HELIUMPLUS_PADDR64) +/* TODO: oka: use kernel-doc format */ +/** + * @brief Free a HTT abstract tx descriptor. + * + * @param htt_pdev - handle to the HTT instance that made the allocation + * @param htt_tx_desc - the descriptor to free + */ +void * +htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, + u_int32_t *frag_paddr_lo); +#endif /* defined(HELIUMPLUS_PADDR64) */ +/** + * @brief Discard all tx frames in the process of being downloaded. + * @details + * This function dicards any tx frames queued in HTT or the layers + * under HTT. + * The download completion callback is invoked on these frames. + * + * @param htt_pdev - handle to the HTT instance + * @param[OUT] frag_paddr_lo - physical address of the fragment descriptor + * (MSDU Link Extension Descriptor) + */ +void htt_tx_pending_discard(htt_pdev_handle pdev); + +/** + * @brief Download a MSDU descriptor and (a portion of) the MSDU payload. + * @details + * This function is used within LL systems to download a tx descriptor and + * the initial portion of the tx MSDU payload, and within HL systems to + * download the tx descriptor and the entire tx MSDU payload. + * The HTT layer determines internally how much of the tx descriptor + * actually needs to be downloaded. In particular, the HTT layer does not + * download the fragmentation descriptor, and only for the LL case downloads + * the physical address of the fragmentation descriptor. + * In HL systems, the tx descriptor and the entire frame are downloaded. + * In LL systems, only the tx descriptor and the header of the frame are + * downloaded. To determine how much of the tx frame to download, this + * function assumes the tx frame is the default frame type, as specified + * by ol_cfg_frame_type. "Raw" frames need to be transmitted through the + * alternate htt_tx_send_nonstd function. + * The tx descriptor has already been attached to the cdf_nbuf object during + * a preceding call to htt_tx_desc_init. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param msdu - the frame being transmitted + * @param msdu_id - unique ID for the frame being transmitted + * @return 0 -> success, -OR- 1 -> failure + */ +int +htt_tx_send_std(htt_pdev_handle htt_pdev, cdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Download a Batch Of Tx MSDUs + * @details + * Each MSDU already has the MSDU ID stored in the headroom of the + * netbuf data buffer, and has the HTT tx descriptor already attached + * as a prefix fragment to the netbuf. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param head_msdu - the MSDU Head for Tx batch being transmitted + * @param num_msdus - The total Number of MSDU's provided for batch tx + * @return null-terminated linked-list of unaccepted frames + */ +cdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle htt_pdev, + cdf_nbuf_t head_msdu, int num_msdus); + +/* The htt scheduler for queued packets in htt + * htt when unable to send to HTC because of lack of resource + * forms a nbuf queue which is flushed when tx completion event from + * target is recieved + */ + +void htt_tx_sched(htt_pdev_handle pdev); + +/** + * @brief Same as htt_tx_send_std, but can handle raw frames. + */ +int +htt_tx_send_nonstd(htt_pdev_handle htt_pdev, + cdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type); + +/** + * htt_pkt_dl_len_get() Gets the HTT PKT download length. + * @pdev: pointer to struct htt_pdev_t + * + * Return: size of HTT packet download length. + */ +int +htt_pkt_dl_len_get(struct htt_pdev_t *pdev); + +#define HTT_TX_CLASSIFY_BIT_S 4 /* Used to set + * classify bit in HTT desc.*/ + +/** + * enum htt_ce_tx_pkt_type - enum of packet types to be set in CE + * descriptor + * @tx_pkt_type_raw: Value set for RAW frames + * @tx_pkt_type_native_wifi: Value set for NATIVE WIFI frames + * @tx_pkt_type_eth2: Value set for Ethernet II frames (mostly default) + * @tx_pkt_type_802_3: Value set for 802.3 / original ethernet frames + * @tx_pkt_type_mgmt: Value set for MGMT frames over HTT + * + */ +enum htt_ce_tx_pkt_type { + tx_pkt_type_raw = 0, + tx_pkt_type_native_wifi = 1, + tx_pkt_type_eth2 = 2, + tx_pkt_type_802_3 = 3, + tx_pkt_type_mgmt = 4 +}; + + +extern const uint32_t htt_to_ce_pkt_type[]; + +/** + * Provide a constant to specify the offset of the HTT portion of the + * HTT tx descriptor, to avoid having to export the descriptor defintion. + * The htt module checks internally that this exported offset is consistent + * with the private tx descriptor definition. + * + * Similarly, export a definition of the HTT tx descriptor size, and then + * check internally that this exported constant matches the private tx + * descriptor definition. + */ +#define HTT_TX_DESC_VADDR_OFFSET 8 + +/** + * htt_tx_desc_init() - Initialize the per packet HTT Tx descriptor + * @pdev: The handle of the physical device sending the + * tx data + * @htt_tx_desc: Abstract handle to the tx descriptor + * @htt_tx_desc_paddr_lo: Physical address of the HTT tx descriptor + * @msdu_id: ID to tag the descriptor with. + * The FW sends this ID back to host as a cookie + * during Tx completion, which the host uses to + * identify the MSDU. + * This ID is an index into the OL Tx desc. array. + * @msdu: The MSDU that is being prepared for transmission + * @msdu_info: Tx MSDU meta-data + * @tso_info: Storage for TSO meta-data + * + * This function initializes the HTT tx descriptor. + * HTT Tx descriptor is a host-f/w interface structure, and meta-data + * accompanying every packet downloaded to f/w via the HTT interface. + */ +static inline +void +htt_tx_desc_init(htt_pdev_handle pdev, + void *htt_tx_desc, + uint32_t htt_tx_desc_paddr_lo, + uint16_t msdu_id, + cdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, + struct cdf_tso_info_t *tso_info, + struct ocb_tx_ctrl_hdr_t *tx_ctrl, + uint8_t is_dsrc) +{ + uint8_t pkt_type, pkt_subtype = 0, ce_pkt_type = 0; + uint32_t hw_classify = 0, data_attr = 0; + uint32_t *word0, *word1, local_word3; +#if HTT_PADDR64 + uint32_t *word4; +#else /* ! HTT_PADDR64 */ + uint32_t *word3; +#endif /* HTT_PADDR64 */ + uint32_t local_word0, local_word1; + struct htt_host_tx_desc_t *htt_host_tx_desc = + (struct htt_host_tx_desc_t *) + (((char *)htt_tx_desc) - HTT_TX_DESC_VADDR_OFFSET); + bool desc_ext_required = (tx_ctrl && tx_ctrl->all_flags != 0); + + word0 = (uint32_t *) htt_tx_desc; + word1 = word0 + 1; + /* + * word2 is frag desc pointer + * word3 or 4 is peer_id + */ +#if HTT_PADDR64 + word4 = word0 + 4; /* Dword 3 */ +#else /* ! HTT_PADDR64 */ + word3 = word0 + 3; /* Dword 3 */ +#endif /* HTT_PADDR64 */ + + pkt_type = msdu_info->info.l2_hdr_type; + + if (cdf_likely(pdev->cfg.ce_classify_enabled)) { + if (cdf_likely(pkt_type == htt_pkt_type_eth2 || + pkt_type == htt_pkt_type_ethernet)) + cdf_nbuf_tx_info_get(msdu, pkt_type, pkt_subtype, + hw_classify); + + ce_pkt_type = htt_to_ce_pkt_type[pkt_type]; + if (0xffffffff == ce_pkt_type) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_DEBUG, + "Invalid HTT pkt type %d\n", pkt_type); + return; + } + } + + /* + * HTT Tx Desc is in uncached memory. Used cached writes per word, to + * reduce unnecessary memory access. + */ + + local_word0 = 0; + if (msdu_info) { + HTT_H2T_MSG_TYPE_SET(local_word0, HTT_H2T_MSG_TYPE_TX_FRM); + HTT_TX_DESC_PKT_TYPE_SET(local_word0, pkt_type); + HTT_TX_DESC_PKT_SUBTYPE_SET(local_word0, pkt_subtype); + HTT_TX_DESC_VDEV_ID_SET(local_word0, msdu_info->info.vdev_id); + if (tx_ctrl && tx_ctrl->valid_tid) + HTT_TX_DESC_EXT_TID_SET(local_word0, tx_ctrl->ext_tid); + else + HTT_TX_DESC_EXT_TID_SET(local_word0, + msdu_info->info.ext_tid); + HTT_TX_DESC_EXTENSION_SET(local_word0, desc_ext_required); + HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid); + HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, + msdu_info->action.cksum_offload); + HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, + msdu_info->action.do_encrypt ? + 0 : 1); + } + + *word0 = local_word0; + + local_word1 = 0; + +#if defined(FEATURE_TSO) + if (tso_info->is_tso) + HTT_TX_DESC_FRM_LEN_SET(local_word1, tso_info->total_len); + else +#endif + HTT_TX_DESC_FRM_LEN_SET(local_word1, cdf_nbuf_len(msdu)); + + HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id); + *word1 = local_word1; + + /* Initialize peer_id to INVALID_PEER because + this is NOT Reinjection path */ + local_word3 = HTT_INVALID_PEER; + if (tx_ctrl && tx_ctrl->channel_freq) + HTT_TX_DESC_CHAN_FREQ_SET(local_word3, tx_ctrl->channel_freq); +#if HTT_PADDR64 + *word4 = local_word3; +#else /* ! HTT_PADDR64 */ + *word3 = local_word3; +#endif /* HTT_PADDR64 */ + + /* + * If any of the tx control flags are set, then we need the extended + * HTT header. + */ + if (desc_ext_required) { + struct htt_tx_msdu_desc_ext_t local_desc_ext = {0}; + + /* + * Copy the info that was read from TX control header from the + * user application to the extended HTT header. + * First copy everything + * to a local temp structure, and then copy everything to the + * actual uncached structure in one go to save memory writes. + */ + local_desc_ext.valid_pwr = tx_ctrl->valid_pwr; + local_desc_ext.valid_mcs_mask = tx_ctrl->valid_datarate; + local_desc_ext.valid_retries = tx_ctrl->valid_retries; + local_desc_ext.valid_expire_tsf = tx_ctrl->valid_expire_tsf; + local_desc_ext.valid_chainmask = tx_ctrl->valid_chain_mask; + + local_desc_ext.pwr = tx_ctrl->pwr; + if (tx_ctrl->valid_datarate && + tx_ctrl->datarate <= htt_ofdm_datarate_max) + local_desc_ext.mcs_mask = + (1 << (tx_ctrl->datarate + 4)); + local_desc_ext.retry_limit = tx_ctrl->retry_limit; + local_desc_ext.expire_tsf_lo = tx_ctrl->expire_tsf_lo; + local_desc_ext.expire_tsf_hi = tx_ctrl->expire_tsf_hi; + local_desc_ext.chain_mask = tx_ctrl->chain_mask; + + local_desc_ext.is_dsrc = (is_dsrc != 0); + + cdf_nbuf_push_head(msdu, sizeof(local_desc_ext)); + cdf_mem_copy(cdf_nbuf_data(msdu), &local_desc_ext, + sizeof(local_desc_ext)); + } + + /* + * Specify that the data provided by the OS is a bytestream, + * and thus should not be byte-swapped during the HIF download + * even if the host is big-endian. + * There could be extra fragments added before the OS's fragments, + * e.g. for TSO, so it's incorrect to clear the frag 0 wordstream flag. + * Instead, clear the wordstream flag for the final fragment, which + * is certain to be (one of the) fragment(s) provided by the OS. + * Setting the flag for this final fragment suffices for specifying + * all fragments provided by the OS rather than added by the driver. + */ + cdf_nbuf_set_frag_is_wordstream(msdu, cdf_nbuf_get_num_frags(msdu) - 1, + 0); + + /* store a link to the HTT tx descriptor within the netbuf */ + cdf_nbuf_frag_push_head(msdu, sizeof(struct htt_host_tx_desc_t), + (char *)htt_host_tx_desc, /* virtual addr */ + htt_tx_desc_paddr_lo, + 0 /* phys addr MSBs - n/a */); + + /* + * Indicate that the HTT header (and HTC header) is a meta-data + * "wordstream", i.e. series of uint32_t, rather than a data + * bytestream. + * This allows the HIF download to byteswap the HTT + HTC headers if + * the host is big-endian, to convert to the target's little-endian + * format. + */ + cdf_nbuf_set_frag_is_wordstream(msdu, 0, 1); + + if (cdf_likely(pdev->cfg.ce_classify_enabled && + (msdu_info->info.l2_hdr_type != htt_pkt_type_mgmt))) { + uint32_t pkt_offset = cdf_nbuf_get_frag_len(msdu, 0); + data_attr = hw_classify << CDF_CE_TX_CLASSIFY_BIT_S; + data_attr |= ce_pkt_type << CDF_CE_TX_PKT_TYPE_BIT_S; + data_attr |= pkt_offset << CDF_CE_TX_PKT_OFFSET_BIT_S; + } + + cdf_nbuf_data_attr_set(msdu, data_attr); +} + +/** + * @brief Set a flag to indicate that the MSDU in question was postponed. + * @details + * In systems in which the host retains its tx frame until the target sends + * a tx completion, the target has the option of discarding it's copy of + * the tx descriptor (and frame, for HL) and sending a "postpone" message + * to the host, to inform the host that it must eventually download the + * tx descriptor (and frame, for HL). + * Before the host downloads the postponed tx desc/frame again, it will use + * this function to set a flag in the HTT tx descriptor indicating that this + * is a re-send of a postponed frame, rather than a new frame. The target + * uses this flag to keep the correct order between re-sent and new tx frames. + * This function is relevant for LL systems. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc); + +/** + * @brief Set a flag to tell the target that more tx downloads are en route. + * @details + * At times, particularly in response to a U-APSD trigger in a HL system, the + * host will download multiple tx descriptors (+ frames, in HL) in a batch. + * The host will use this function to set a "more" flag in the initial + * and interior frames of the batch, to tell the target that more tx frame + * downloads within the batch are imminent. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc); + +/** + * @brief Specify the number of fragments in the fragmentation descriptor. + * @details + * Specify the number of fragments within the MSDU, i.e. the number of + * elements within the fragmentation descriptor. + * For LL, this is used to terminate the list of fragments used by the + * HW's tx MAC DMA. + * For HL, this is used to terminate the list of fragments provided to + * HTC for download. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + * @param num_frags - the number of fragments comprising the MSDU + */ +static inline +void +htt_tx_desc_num_frags(htt_pdev_handle pdev, void *desc, uint32_t num_frags) +{ + /* + * Set the element after the valid frag elems to 0x0, + * to terminate the list of fragments. + */ +#if defined(HELIUMPLUS_PADDR64) + if (HTT_WIFI_IP(pdev, 2, 0)) { + /** Skip TSO related 4 dwords WIFI2.0*/ + desc = (void *)&(((struct msdu_ext_desc_t *)desc)->frag_ptr0); + /* Frag ptr is 48 bit wide so clear the next dword as well */ + *((uint32_t *)(((char *)desc) + (num_frags << 3))) = 0; + *((uint32_t *) + (((char *)desc) + (num_frags << 3) + sizeof(uint32_t))) = 0; + /* TODO: OKA: remove the magic constants */ + } else { + /* XXXOKA -- Looks like a bug, called with htt_frag_desc */ + *((u_int32_t *) + (((char *) desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; + } +#else /* ! HELIUMPLUS_PADDR64 */ + *((uint32_t *) + (((char *)desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; +#endif /* HELIUMPLUS_PADDR64 */ +} + +/* checksum offload flags for hw */ +#define IPV4_CSUM_EN 0x00010000 +#define UDP_IPV4_CSUM_EN 0x00020000 +#define UDP_IPV6_CSUM_EN 0x00040000 +#define TCP_IPV4_CSUM_EN 0x00080000 +#define TCP_IPV6_CSUM_EN 0x00100000 +#define PARTIAL_CSUM_EN 0x00200000 + +/** + * @brief Specify the location and size of a fragment of a tx MSDU. + * @details + * In LL systems, the tx MAC DMA needs to know how the MSDU is constructed + * from fragments. + * In LL and HL systems, the HIF's download DMA to the target (LL: tx desc + * + header of tx payload; HL: tx desc + entire tx payload) needs to know + * where to find the fragments to download. + * The tx data SW uses this function to specify the location and size of + * each of the MSDU's fragments. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the HTT tx descriptor + * @param frag_num - which fragment is being specified (zero-based indexing) + * @param frag_phys_addr - DMA/physical address of the fragment + * @param frag_len - number of bytes within the fragment + */ +static inline +void +htt_tx_desc_frag(htt_pdev_handle pdev, + void *desc, + int frag_num, uint32_t frag_phys_addr, uint16_t frag_len) +{ + u_int32_t *word; + +#if defined(HELIUMPLUS_PADDR64) + if (HTT_WIFI_IP(pdev, 2, 0)) { + word = (u_int32_t *)(desc); + /* Initialize top 6 words of TSO flags per packet */ + *word++ = 0; + *word++ = 0; + *word++ = 0; + if (((struct txrx_pdev_cfg_t *)(pdev->ctrl_pdev)) + ->ip_tcp_udp_checksum_offload) + *word |= (IPV4_CSUM_EN | TCP_IPV4_CSUM_EN | + TCP_IPV6_CSUM_EN | UDP_IPV4_CSUM_EN | + UDP_IPV6_CSUM_EN); + else + *word = 0; + word++; + *word++ = 0; + *word++ = 0; + + cdf_assert_always(word == &(((struct msdu_ext_desc_t *) + desc)->frag_ptr0)); + + /* Each fragment consumes 2 DWORDS */ + word += (frag_num << 1); + *word = frag_phys_addr; + + word++; + *word = (frag_len<<16); + + } else { + /* For Helium+, this block cannot exist */ + CDF_ASSERT(0); + } +#else /* !defined(HELIUMPLUS_PADDR64) */ + word = (uint32_t *) (((char *)desc) + HTT_TX_DESC_LEN + frag_num * 8); + *word = frag_phys_addr; + word++; + *word = frag_len; +#endif /* defined(HELIUMPLUS_PADDR64) */ +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + uint32_t paddr, + uint32_t frag_desc_paddr_lo, + int reset); + +/** + * @brief Specify the type and subtype of a tx frame. + * + * @param pdev - the handle of the physical device sending the tx data + * @param type - format of the MSDU (802.3, native WiFi, raw, or mgmt) + * @param sub_type - sub_type (relevant for raw frames) + */ +static inline +void +htt_tx_desc_type(htt_pdev_handle pdev, + void *htt_tx_desc, enum wlan_frm_fmt type, uint8_t sub_type) +{ + uint32_t *word0; + + word0 = (uint32_t *) htt_tx_desc; + /* clear old values */ + *word0 &= ~(HTT_TX_DESC_PKT_TYPE_M | HTT_TX_DESC_PKT_SUBTYPE_M); + /* write new values */ + HTT_TX_DESC_PKT_TYPE_SET(*word0, type); + HTT_TX_DESC_PKT_SUBTYPE_SET(*word0, sub_type); +} + +/***** TX MGMT DESC management APIs ****/ + +/* Number of mgmt descriptors in the pool */ +#define HTT_MAX_NUM_MGMT_DESCS 32 + +/** htt_tx_mgmt_desc_pool_alloc + * @description - allocates the memory for mgmt frame descriptors + * @param - htt pdev object + * @param - num of descriptors to be allocated in the pool + */ +void htt_tx_mgmt_desc_pool_alloc(struct htt_pdev_t *pdev, A_UINT32 num_elems); + +/** htt_tx_mgmt_desc_alloc + * @description - reserves a mgmt descriptor from the pool + * @param - htt pdev object + * @param - pointer to variable to hold the allocated desc id + * @param - pointer to the mamangement from UMAC + * @return - pointer the allocated mgmt descriptor + */ +cdf_nbuf_t +htt_tx_mgmt_desc_alloc(struct htt_pdev_t *pdev, A_UINT32 *desc_id, + cdf_nbuf_t mgmt_frm); + +/** htt_tx_mgmt_desc_free + * @description - releases the management descriptor back to the pool + * @param - htt pdev object + * @param - descriptor ID + */ +void +htt_tx_mgmt_desc_free(struct htt_pdev_t *pdev, A_UINT8 desc_id, + A_UINT32 status); + +/** htt_tx_mgmt_desc_pool_free + * @description - releases all the resources allocated for mgmt desc pool + * @param - htt pdev object + */ +void htt_tx_mgmt_desc_pool_free(struct htt_pdev_t *pdev); + +/** + * @brief Provide a buffer to store a 802.11 header added by SW tx encap + * + * @param htt_tx_desc - which frame the 802.11 header is being added to + * @param new_l2_hdr_size - how large the buffer needs to be + */ +#define htt_tx_desc_mpdu_header(htt_tx_desc, new_l2_hdr_size) /*NULL*/ +/** + * @brief How many tx credits would be consumed by the specified tx frame. + * + * @param msdu - the tx frame in question + * @return number of credits used for this tx frame + */ +#define htt_tx_msdu_credit(msdu) 1 /* 1 credit per buffer */ +#ifdef HTT_DBG +void htt_tx_desc_display(void *tx_desc); +#else +#define htt_tx_desc_display(tx_desc) +#endif + +static inline void htt_tx_desc_set_peer_id(void *htt_tx_desc, uint16_t peer_id) +{ + uint16_t *peer_id_field_ptr; + + peer_id_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES); + + *peer_id_field_ptr = peer_id; +} + +static inline +void htt_tx_desc_set_chanfreq(void *htt_tx_desc, uint16_t chanfreq) +{ + uint16_t *chanfreq_field_ptr; + + /* The reason we dont use CHAN_FREQ_OFFSET_BYTES is because + it uses DWORD as unit */ + /* The reason we dont use the SET macro in htt.h is because + htt_tx_desc is incomplete type */ + chanfreq_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES + + sizeof(A_UINT16)); + + *chanfreq_field_ptr = chanfreq; +} + +#if defined(FEATURE_TSO) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct cdf_tso_info_t *tso_info); +#else +#define htt_tx_desc_fill_tso_info(pdev, desc, tso_info) +#endif +#endif /* _OL_HTT_TX_API__H_ */ diff --git a/core/dp/ol/inc/ol_osif_api.h b/core/dp/ol/inc/ol_osif_api.h new file mode 100644 index 0000000000..9344a5fa5f --- /dev/null +++ b/core/dp/ol/inc/ol_osif_api.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_osif_api.h + * @brief Definitions used in multiple external interfaces to the txrx SW. + */ +#ifndef _OL_OSIF_API__H_ +#define _OL_OSIF_API__H_ + +/** + * @typedef ol_osif_vdev_handle + * @brief opaque handle for OS shim virtual device object + */ +struct ol_osif_vdev_t; +typedef struct ol_osif_vdev_t *ol_osif_vdev_handle; + +#endif /* _OL_OSIF_API__H_ */ diff --git a/core/dp/ol/inc/ol_params.h b/core/dp/ol/inc/ol_params.h new file mode 100644 index 0000000000..89eff22faa --- /dev/null +++ b/core/dp/ol/inc/ol_params.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_PARAMS_H +#define _DEV_OL_PARAMS_H +#include "ol_txrx_stats.h" +#include "wlan_defs.h" /* for wlan statst definitions */ +/* +** Enumeration of PDEV Configuration parameter +*/ + +enum ol_ath_param_t { + OL_ATH_PARAM_TXCHAINMASK = 0, + OL_ATH_PARAM_RXCHAINMASK, + OL_ATH_PARAM_TXCHAINMASKLEGACY, + OL_ATH_PARAM_RXCHAINMASKLEGACY, + OL_ATH_PARAM_CHAINMASK_SEL, + OL_ATH_PARAM_AMPDU, + OL_ATH_PARAM_AMPDU_LIMIT, + OL_ATH_PARAM_AMPDU_SUBFRAMES, + OL_ATH_PARAM_LDPC, + OL_ATH_PARAM_NON_AGG_SW_RETRY_TH, + OL_ATH_PARAM_AGG_SW_RETRY_TH, + OL_ATH_PARAM_STA_KICKOUT_TH, + OL_ATH_PARAM_WLAN_PROF_ENABLE, + OL_ATH_PARAM_LTR_ENABLE, + OL_ATH_PARAM_LTR_AC_LATENCY_BE, + OL_ATH_PARAM_LTR_AC_LATENCY_BK, + OL_ATH_PARAM_LTR_AC_LATENCY_VI, + OL_ATH_PARAM_LTR_AC_LATENCY_VO, + OL_ATH_PARAM_LTR_AC_LATENCY_TIMEOUT, + OL_ATH_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + OL_ATH_PARAM_LTR_SLEEP_OVERRIDE, + OL_ATH_PARAM_LTR_RX_OVERRIDE, + OL_ATH_PARAM_L1SS_ENABLE, + OL_ATH_PARAM_DSLEEP_ENABLE, + OL_ATH_PARAM_PCIELP_TXBUF_FLUSH, + OL_ATH_PARAM_PCIELP_TXBUF_WATERMARK, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_EN, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_VALUE, + OL_ATH_PARAM_BCN_BURST, + OL_ATH_PARAM_ARP_AC_OVERRIDE, + OL_ATH_PARAM_TXPOWER_LIMIT2G, + OL_ATH_PARAM_TXPOWER_LIMIT5G, + OL_ATH_PARAM_TXPOWER_SCALE, + OL_ATH_PARAM_DCS, + OL_ATH_PARAM_ANI_ENABLE, + OL_ATH_PARAM_ANI_POLL_PERIOD, + OL_ATH_PARAM_ANI_LISTEN_PERIOD, + OL_ATH_PARAM_ANI_OFDM_LEVEL, + OL_ATH_PARAM_ANI_CCK_LEVEL, + OL_ATH_PARAM_PROXYSTA, + OL_ATH_PARAM_DYN_TX_CHAINMASK, + OL_ATH_PARAM_VOW_EXT_STATS, + OL_ATH_PARAM_PWR_GATING_ENABLE, + OL_ATH_PARAM_CHATTER, +}; + +/* +** Enumeration of PDEV Configuration parameter +*/ + +enum ol_hal_param_t { + OL_HAL_CONFIG_DMA_BEACON_RESPONSE_TIME = 0 +}; + +/* +** structure to hold all stats information +** for offload device interface +*/ +struct ol_stats { + int txrx_stats_level; + struct ol_txrx_stats txrx_stats; + struct wlan_dbg_stats stats; +}; +#endif /* _DEV_OL_PARAMS_H */ diff --git a/core/dp/ol/inc/ol_txrx_api.h b/core/dp/ol/inc/ol_txrx_api.h new file mode 100644 index 0000000000..289d49e323 --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_api.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_api.h + * @brief Definitions used in multiple external interfaces to the txrx SW. + */ +#ifndef _OL_TXRX_API__H_ +#define _OL_TXRX_API__H_ + +/** + * @typedef ol_txrx_pdev_handle + * @brief opaque handle for txrx physical device object + */ +struct ol_txrx_pdev_t; +typedef struct ol_txrx_pdev_t *ol_txrx_pdev_handle; + +/** + * @typedef ol_txrx_vdev_handle + * @brief opaque handle for txrx virtual device object + */ +struct ol_txrx_vdev_t; +typedef struct ol_txrx_vdev_t *ol_txrx_vdev_handle; + +/** + * @typedef ol_txrx_peer_handle + * @brief opaque handle for txrx peer object + */ +struct ol_txrx_peer_t; +typedef struct ol_txrx_peer_t *ol_txrx_peer_handle; + +/** + * @brief ADDBA negotiation status, used both during requests and confirmations + */ +enum ol_addba_status { + /* status: negotiation started or completed successfully */ + ol_addba_success, + + /* reject: aggregation is not applicable - don't try again */ + ol_addba_reject, + + /* busy: ADDBA negotiation couldn't be performed - try again later */ + ol_addba_busy, +}; + +enum ol_sec_type { + ol_sec_type_none, + ol_sec_type_wep128, + ol_sec_type_wep104, + ol_sec_type_wep40, + ol_sec_type_tkip, + ol_sec_type_tkip_nomic, + ol_sec_type_aes_ccmp, + ol_sec_type_wapi, + + /* keep this last! */ + ol_sec_type_types +}; + +/** + * @enum ol_tx_spec + * @brief indicate what non-standard transmission actions to apply + * @details + * Indicate one or more of the following: + * - The tx frame already has a complete 802.11 header. + * Thus, skip 802.3/native-WiFi to 802.11 header encapsulation and + * A-MSDU aggregation. + * - The tx frame should not be aggregated (A-MPDU or A-MSDU) + * - The tx frame is already encrypted - don't attempt encryption. + * - The tx frame is a segment of a TCP jumbo frame. + * - This tx frame should not be unmapped and freed by the txrx layer + * after transmission, but instead given to a registered tx completion + * callback. + * More than one of these specification can apply, though typically + * only a single specification is applied to a tx frame. + * A compound specification can be created, as a bit-OR of these + * specifications. + */ +enum ol_tx_spec { + ol_tx_spec_std = 0x0, /* do regular processing */ + ol_tx_spec_raw = 0x1, /* skip encap + A-MSDU aggr */ + ol_tx_spec_no_aggr = 0x2, /* skip encap + all aggr */ + ol_tx_spec_no_encrypt = 0x4, /* skip encap + encrypt */ + ol_tx_spec_tso = 0x8, /* TCP segmented */ + ol_tx_spec_nwifi_no_encrypt = 0x10, /* skip encrypt for nwifi */ + ol_tx_spec_no_free = 0x20, /* give to cb rather than free */ +}; + +#endif /* _OL_TXRX_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_ctrl_api.h b/core/dp/ol/inc/ol_txrx_ctrl_api.h new file mode 100644 index 0000000000..44d5cf100d --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -0,0 +1,1312 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_ctrl_api.h + * @brief Define the host data API functions called by the host control SW. + */ +#ifndef _OL_TXRX_CTRL_API__H_ +#define _OL_TXRX_CTRL_API__H_ + +#include /* A_STATUS */ +#include /* cdf_nbuf_t */ +#include /* cdf_device_t */ +#include /* HTC_HANDLE */ + +#include /* ol_osif_vdev_handle */ +#include /* ol_txrx_pdev_handle, etc. */ +#include /* ol_pdev_handle, ol_vdev_handle */ + +#include /* MAX_SPATIAL_STREAM */ + +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 + +/* Maximum number of station supported by data path, including BC. */ +#define WLAN_MAX_STA_COUNT (HAL_NUM_STA) + +/* The symbolic station ID return to HDD to specify the packet is bc/mc */ +#define WLAN_RX_BCMC_STA_ID (WLAN_MAX_STA_COUNT + 1) + +/* The symbolic station ID return to HDD to specify the packet is + to soft-AP itself */ +#define WLAN_RX_SAP_SELF_STA_ID (WLAN_MAX_STA_COUNT + 2) + +/** + * enum wlan_op_mode - Virtual device operation mode + * + * @wlan_op_mode_unknown: Unknown mode + * @wlan_op_mode_ap: AP mode + * @wlan_op_mode_ibss: IBSS mode + * @wlan_op_mode_sta: STA (client) mode + * @wlan_op_mode_monitor: Monitor mode + * @wlan_op_mode_ocb: OCB mode + */ +enum wlan_op_mode { + wlan_op_mode_unknown, + wlan_op_mode_ap, + wlan_op_mode_ibss, + wlan_op_mode_sta, + wlan_op_mode_monitor, + wlan_op_mode_ocb, +}; + +#define OL_TXQ_PAUSE_REASON_FW (1 << 0) +#define OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED (1 << 1) +#define OL_TXQ_PAUSE_REASON_TX_ABORT (1 << 2) +#define OL_TXQ_PAUSE_REASON_VDEV_STOP (1 << 3) +#define OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION (1 << 4) + + +/** + * enum netif_action_type - Type of actions on netif queues + * @WLAN_STOP_ALL_NETIF_QUEUE: stop all netif queues + * @WLAN_START_ALL_NETIF_QUEUE: start all netif queues + * @WLAN_WAKE_ALL_NETIF_QUEUE: wake all netif queues + * @WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: stop all queues and off carrier + * @WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: start all queues and on carrier + * @WLAN_NETIF_TX_DISABLE: disable tx + * @WLAN_NETIF_TX_DISABLE_N_CARRIER: disable tx and off carrier + * @WLAN_NETIF_CARRIER_ON: on carrier + * @WLAN_NETIF_CARRIER_OFF: off carrier + */ +enum netif_action_type { + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_NETIF_TX_DISABLE, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_NETIF_CARRIER_ON, + WLAN_NETIF_CARRIER_OFF, + WLAN_NETIF_ACTION_TYPE_MAX, +}; + +/** + * enum netif_reason_type - reason for netif queue action + * @WLAN_CONTROL_PATH: action from control path + * @WLAN_DATA_FLOW_CONTROL: because of flow control + * @WLAN_FW_PAUSE: because of firmware pause + * @WLAN_TX_ABORT: because of tx abort + * @WLAN_VDEV_STOP: because of vdev stop + * @WLAN_PEER_UNAUTHORISED: because of peer is unauthorised + * @WLAN_THERMAL_MITIGATION: because of thermal mitigation + */ +enum netif_reason_type { + WLAN_CONTROL_PATH, + WLAN_DATA_FLOW_CONTROL, + WLAN_FW_PAUSE, + WLAN_TX_ABORT, + WLAN_VDEV_STOP, + WLAN_PEER_UNAUTHORISED, + WLAN_THERMAL_MITIGATION, + WLAN_REASON_TYPE_MAX, +}; + + +/* command options for dumpStats*/ +#define WLAN_HDD_STATS 0 +#define WLAN_TXRX_STATS 1 +#define WLAN_TXRX_HIST_STATS 2 +#define WLAN_TXRX_TSO_STATS 3 +#define WLAN_HDD_NETIF_OPER_HISTORY 4 +#define WLAN_DUMP_TX_FLOW_POOL_INFO 5 +#define WLAN_TXRX_DESC_STATS 6 + +ol_txrx_pdev_handle +ol_txrx_pdev_alloc(ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, cdf_device_t osdev); + +/** + * @brief Set up the data SW subsystem. + * @details + * As part of the WLAN device attach, the data SW subsystem has + * to be attached as a component within the WLAN device. + * This attach allocates and initializes the physical device object + * used by the data SW. + * The data SW subsystem attach needs to happen after the target has + * be started, and host / target parameter negotiation has completed, + * since the host data SW uses some of these host/target negotiated + * parameters (e.g. peer ID range) during the initializations within + * its attach function. + * However, the host data SW is not allowed to send HTC messages to the + * target within this pdev_attach function call, since the HTC setup + * has not complete at this stage of initializations. Any messaging + * to the target has to be done in the separate pdev_attach_target call + * that is invoked after HTC setup is complete. + * + * @param pdev - txrx_pdev handle + * @return 0 for success or error code + */ +int +ol_txrx_pdev_attach(ol_txrx_pdev_handle pdev); + +/** + * @brief Do final steps of data SW setup that send messages to the target. + * @details + * The majority of the data SW setup are done by the pdev_attach function, + * but this function completes the data SW setup by sending datapath + * configuration messages to the target. + * + * @param data_pdev - the physical device being initialized + */ +A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle data_pdev); + +/** + * @brief Allocate and initialize the data object for a new virtual device. + * @param data_pdev - the physical device the virtual device belongs to + * @param vdev_mac_addr - the MAC address of the virtual device + * @param vdev_id - the ID used to identify the virtual device to the target + * @param op_mode - whether this virtual device is operating as an AP, + * an IBSS, or a STA + * @return + * success: handle to new data vdev object, -OR- + * failure: NULL + */ +ol_txrx_vdev_handle +ol_txrx_vdev_attach(ol_txrx_pdev_handle data_pdev, + uint8_t *vdev_mac_addr, + uint8_t vdev_id, enum wlan_op_mode op_mode); + +/** + * @brief Allocate and set up references for a data peer object. + * @details + * When an association with a peer starts, the host's control SW + * uses this function to inform the host data SW. + * The host data SW allocates its own peer object, and stores a + * reference to the control peer object within the data peer object. + * The host data SW also stores a reference to the virtual device + * that the peer is associated with. This virtual device handle is + * used when the data SW delivers rx data frames to the OS shim layer. + * The host data SW returns a handle to the new peer data object, + * so a reference within the control peer object can be set to the + * data peer object. + * + * @param data_pdev - data physical device object that will indirectly + * own the data_peer object + * @param data_vdev - data virtual device object that will directly + * own the data_peer object + * @param peer_mac_addr - MAC address of the new peer + * @return handle to new data peer object, or NULL if the attach fails + */ +ol_txrx_peer_handle +ol_txrx_peer_attach(ol_txrx_pdev_handle data_pdev, + ol_txrx_vdev_handle data_vdev, uint8_t *peer_mac_addr); + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This struct is union,to be used to specify various informations to update + * txrx peer object. + */ +union ol_txrx_peer_update_param_t { + uint8_t qos_capable; + uint8_t uapsd_mask; + enum ol_sec_type sec_type; +}; + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This enum is used to specify what exact information in + * ol_txrx_peer_update_param_t + * is used to update the txrx peer object. + */ +enum ol_txrx_peer_update_select_t { + ol_txrx_peer_update_qos_capable = 1, + ol_txrx_peer_update_uapsdMask, + ol_txrx_peer_update_peer_security, +}; + +/** + * @brief Update the data peer object as some informaiton changed in node. + * @details + * Only a single prarameter can be changed for each call to this func. + * + * @param peer - pointer to the node's object + * @param param - new param to be upated in peer object. + * @param select - specify what's parameter needed to be update + */ +void +ol_txrx_peer_update(ol_txrx_vdev_handle data_vdev, uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select); + +enum { + OL_TX_WMM_AC_BE, + OL_TX_WMM_AC_BK, + OL_TX_WMM_AC_VI, + OL_TX_WMM_AC_VO, + + OL_TX_NUM_WMM_AC +}; + +/** + * @brief Parameter type to pass WMM setting to ol_txrx_set_wmm_param + * @details + * The struct is used to specify informaiton to update TX WMM scheduler. + */ +struct ol_tx_ac_param_t { + uint32_t aifs; + uint32_t cwmin; + uint32_t cwmax; +}; + +struct ol_tx_wmm_param_t { + struct ol_tx_ac_param_t ac[OL_TX_NUM_WMM_AC]; +}; + +/** + * @brief Set paramters of WMM scheduler per AC settings. . + * @details + * This function applies only to HL systems. + * + * @param data_pdev - the physical device being paused + * @param wmm_param - the wmm parameters + */ +#define ol_txrx_set_wmm_param(data_pdev, wmm_param) /* no-op */ + +/** + * @brief notify tx data SW that a peer's transmissions are suspended. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * The HL host tx data SW is doing tx classification and tx download + * scheduling, and therefore also needs to actively participate in tx + * flow control. Specifically, the HL tx data SW needs to check whether a + * given peer is available to transmit to, or is paused. + * This function is used to tell the HL tx data SW when a peer is paused, + * so the host tx data SW can hold the tx frames for that SW. + * + * @param data_peer - which peer is being paused + */ +#define ol_txrx_peer_pause(data_peer) /* no-op */ + +/** + * @brief notify tx data SW that a peer-TID is ready to transmit to. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * If a peer-TID has tx paused, then the tx datapath will end up queuing + * any tx frames that arrive from the OS shim for that peer-TID. + * In a HL system, the host tx data SW itself will classify the tx frame, + * and determine that it needs to be queued rather than downloaded to the + * target for transmission. + * Once the peer-TID is ready to accept data, the host control SW will call + * this function to notify the host data SW that the queued frames can be + * enabled for transmission, or specifically to download the tx frames + * to the target to transmit. + * The TID parameter is an extended version of the QoS TID. Values 0-15 + * indicate a regular QoS TID, and the value 16 indicates either non-QoS + * data, multicast data, or broadcast data. + * + * @param data_peer - which peer is being unpaused + * @param tid - which TID within the peer is being unpaused, or -1 as a + * wildcard to unpause all TIDs within the peer + */ +#define ol_txrx_peer_tid_unpause(data_peer, tid) /* no-op */ + +/** + * @brief Tell a paused peer to release a specified number of tx frames. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * Download up to a specified maximum number of tx frames from the tx + * queues of the specified TIDs within the specified paused peer, usually + * in response to a U-APSD trigger from the peer. + * It is up to the host data SW to determine how to choose frames from the + * tx queues of the specified TIDs. However, the host data SW does need to + * provide long-term fairness across the U-APSD enabled TIDs. + * The host data SW will notify the target data FW when it is done downloading + * the batch of U-APSD triggered tx frames, so the target data FW can + * differentiate between an in-progress download versus a case when there are + * fewer tx frames available than the specified limit. + * This function is relevant primarily to HL U-APSD, where the frames are + * held in the host. + * + * @param peer - which peer sent the U-APSD trigger + * @param tid_mask - bitmask of U-APSD enabled TIDs from whose tx queues + * tx frames can be released + * @param max_frms - limit on the number of tx frames to release from the + * specified TID's queues within the specified peer + */ +#define ol_txrx_tx_release(peer, tid_mask, max_frms) /* no-op */ + +/** + * @brief Suspend all tx data for the specified virtual device. + * @details + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * As an example, this function could be used when a single-channel physical + * device supports multiple channels by jumping back and forth between the + * channels in a time-shared manner. As the device is switched from channel + * A to channel B, the virtual devices that operate on channel A will be + * paused. + * + * @param data_vdev - the virtual device being paused + * @param reason - the reason for which vdev queue is getting paused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason); +#else +static inline +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * @brief Drop all tx data for the specified virtual device. + * @details + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * This function would typically be used by the ctrl SW after it parks + * a STA vdev and then resumes it, but to a new AP. In this case, though + * the same vdev can be used, any old tx frames queued inside it would be + * stale, and would need to be discarded. + * + * @param data_vdev - the virtual device being flushed + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) +void ol_txrx_vdev_flush(ol_txrx_vdev_handle data_vdev); +#else +#define ol_txrx_vdev_flush(data_vdev) /* no-op */ +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * @brief Resume tx for the specified virtual device. + * @details + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * + * @param data_vdev - the virtual device being unpaused + * @param reason - the reason for which vdev queue is getting unpaused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle data_vdev, uint32_t reason); +#else +static inline +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle data_vdev, uint32_t reason) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * @brief Suspend all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +#define ol_txrx_throttle_pause(data_pdev) /* no-op */ + +/** + * @brief Resume all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +#define ol_txrx_throttle_unpause(data_pdev) /* no-op */ + +/** + * @brief Suspend all tx data for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * In some systems it is necessary to be able to temporarily + * suspend all WLAN traffic, e.g. to allow another device such as bluetooth + * to temporarily have exclusive access to shared RF chain resources. + * This function suspends tx traffic within the specified physical device. + * + * @param data_pdev - the physical device being paused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason) +{ + return; +} +#endif + +/** + * @brief Resume tx for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * + * @param data_pdev - the physical device being unpaused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + return; +} +#endif + +/** + * @brief Synchronize the data-path tx with a control-path target download + * @dtails + * @param data_pdev - the data-path physical device object + * @param sync_cnt - after the host data-path SW downloads this sync request + * to the target data-path FW, the target tx data-path will hold itself + * in suspension until it is given an out-of-band sync counter value that + * is equal to or greater than this counter value + */ +void ol_txrx_tx_sync(ol_txrx_pdev_handle data_pdev, uint8_t sync_cnt); + +/** + * @brief Delete a peer's data object. + * @details + * When the host's control SW disassociates a peer, it calls this + * function to delete the peer's data object. + * The reference stored in the control peer object to the data peer + * object (set up by a call to ol_peer_store()) is provided. + * + * @param data_peer - the object to delete + */ +void ol_txrx_peer_detach(ol_txrx_peer_handle data_peer); + +typedef void (*ol_txrx_vdev_delete_cb)(void *context); + +/** + * @brief Deallocate the specified data virtual device object. + * @details + * All peers associated with the virtual device need to be deleted + * (ol_txrx_peer_detach) before the virtual device itself is deleted. + * However, for the peers to be fully deleted, the peer deletion has to + * percolate through the target data FW and back up to the host data SW. + * Thus, even though the host control SW may have issued a peer_detach + * call for each of the vdev's peers, the peer objects may still be + * allocated, pending removal of all references to them by the target FW. + * In this case, though the vdev_detach function call will still return + * immediately, the vdev itself won't actually be deleted, until the + * deletions of all its peers complete. + * The caller can provide a callback function pointer to be notified when + * the vdev deletion actually happens - whether it's directly within the + * vdev_detach call, or if it's deferred until all in-progress peer + * deletions have completed. + * + * @param data_vdev - data object for the virtual device in question + * @param callback - function to call (if non-NULL) once the vdev has + * been wholly deleted + * @param callback_context - context to provide in the callback + */ +void +ol_txrx_vdev_detach(ol_txrx_vdev_handle data_vdev, + ol_txrx_vdev_delete_cb callback, void *callback_context); + +/** + * @brief Delete the data SW state. + * @details + * This function is used when the WLAN driver is being removed to + * remove the host data component within the driver. + * All virtual devices within the physical device need to be deleted + * (ol_txrx_vdev_detach) before the physical device itself is deleted. + * + * @param data_pdev - the data physical device object being removed + * @param force - delete the pdev (and its vdevs and peers) even if there + * are outstanding references by the target to the vdevs and peers + * within the pdev + */ +void ol_txrx_pdev_detach(ol_txrx_pdev_handle data_pdev, int force); + +typedef void +(*ol_txrx_data_tx_cb)(void *ctxt, cdf_nbuf_t tx_frm, int had_error); + +/** + * @brief Store a delivery notification callback for specific data frames. + * @details + * Through a non-std tx function, the txrx SW can be given tx data frames + * that are specially marked to not be unmapped and freed by the tx SW + * when transmission completes. Rather, these specially-marked frames + * are provided to the callback registered with this function. + * + * @param data_vdev - which vdev the callback is being registered with + * (Currently the callback is stored in the pdev rather than the vdev.) + * @param callback - the function to call when tx frames marked as "no free" + * are done being transmitted + * @param ctxt - the context argument provided to the callback function + */ +void +ol_txrx_data_tx_cb_set(ol_txrx_vdev_handle data_vdev, + ol_txrx_data_tx_cb callback, void *ctxt); + +/** + * @brief Allow the control-path SW to send data frames. + * @details + * Generally, all tx data frames come from the OS shim into the txrx layer. + * However, there are rare cases such as TDLS messaging where the UMAC + * control-path SW creates tx data frames. + * This UMAC SW can call this function to provide the tx data frames to + * the txrx layer. + * The UMAC SW can request a callback for these data frames after their + * transmission completes, by using the ol_txrx_data_tx_cb_set function + * to register a tx completion callback, and by specifying + * ol_tx_spec_no_free as the tx_spec arg when giving the frames to + * ol_tx_non_std. + * The MSDUs need to have the appropriate L2 header type (802.3 vs. 802.11), + * as specified by ol_cfg_frame_type(). + * + * @param data_vdev - which vdev should transmit the tx data frames + * @param tx_spec - what non-standard handling to apply to the tx data frames + * @param msdu_list - NULL-terminated list of tx MSDUs + */ +cdf_nbuf_t +ol_tx_non_std(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, cdf_nbuf_t msdu_list); + +typedef void +(*ol_txrx_mgmt_tx_cb)(void *ctxt, cdf_nbuf_t tx_mgmt_frm, int had_error); + +/** + * @brief Store a callback for delivery notifications for management frames. + * @details + * When the txrx SW receives notifications from the target that a tx frame + * has been delivered to its recipient, it will check if the tx frame + * is a management frame. If so, the txrx SW will check the management + * frame type specified when the frame was submitted for transmission. + * If there is a callback function registered for the type of managment + * frame in question, the txrx code will invoke the callback to inform + * the management + control SW that the mgmt frame was delivered. + * This function is used by the control SW to store a callback pointer + * for a given type of management frame. + * + * @param pdev - the data physical device object + * @param type - the type of mgmt frame the callback is used for + * @param download_cb - the callback for notification of delivery to the target + * @param ota_ack_cb - the callback for notification of delivery to the peer + * @param ctxt - context to use with the callback + */ +void +ol_txrx_mgmt_tx_cb_set(ol_txrx_pdev_handle pdev, + uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt); + +/** + * @brief Transmit a management frame. + * @details + * Send the specified management frame from the specified virtual device. + * The type is used for determining whether to invoke a callback to inform + * the sender that the tx mgmt frame was delivered, and if so, which + * callback to use. + * + * @param vdev - virtual device transmitting the frame + * @param tx_mgmt_frm - management frame to transmit + * @param type - the type of managment frame (determines what callback to use) + * @param use_6mbps - specify whether management frame to transmit should use 6 Mbps + * rather than 1 Mbps min rate(for 5GHz band or P2P) + * @return + * 0 -> the frame is accepted for transmission, -OR- + * 1 -> the frame was not accepted + */ +int +ol_txrx_mgmt_send(ol_txrx_vdev_handle vdev, + cdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq); + +/** + * @brief Setup the monitor mode vap (vdev) for this pdev + * @details + * When a non-NULL vdev handle is registered as the monitor mode vdev, all + * packets received by the system are delivered to the OS stack on this + * interface in 802.11 MPDU format. Only a single monitor mode interface + * can be up at any timer. When the vdev handle is set to NULL the monitor + * mode delivery is stopped. This handle may either be a unique vdev + * object that only receives monitor mode packets OR a point to a a vdev + * object that also receives non-monitor traffic. In the second case the + * OS stack is responsible for delivering the two streams using approprate + * OS APIs + * + * @param pdev - the data physical device object + * @param vdev - the data virtual device object to deliver monitor mode + * packets on + * @return + * 0 -> the monitor mode vap was sucessfully setup + * -1 -> Unable to setup monitor mode + */ +int +ol_txrx_set_monitor_mode_vap(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev); + +/** + * @brief Setup the current operating channel of the device + * @details + * Mainly used when populating monitor mode status that requires the + * current operating channel + * + * @param pdev - the data physical device object + * @param chan_mhz - the channel frequency (mhz) + * packets on + * @return - void + */ +void ol_txrx_set_curchan(ol_txrx_pdev_handle pdev, uint32_t chan_mhz); + +CDF_STATUS ol_txrx_bus_suspend(void); +CDF_STATUS ol_txrx_bus_resume(void); +CDF_STATUS ol_txrx_wait_for_pending_tx(int timeout); + +/** + * @brief Get the number of pending transmit frames that are awaiting completion. + * @details + * Mainly used in clean up path to make sure all buffers have been free'ed + * + * @param pdev - the data physical device object + * @return - count of pending frames + */ +int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev); + +/** + * @brief Discard all tx frames that are pending in txrx. + * @details + * Mainly used in clean up path to make sure all pending tx packets + * held by txrx are returned back to OS shim immediately. + * + * @param pdev - the data physical device object + * @return - void + */ +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev); + +/** + * @brief set the safemode of the device + * @details + * This flag is used to bypass the encrypt and decrypt processes when send and + * receive packets. It works like open AUTH mode, HW will treate all packets + * as non-encrypt frames because no key installed. For rx fragmented frames, + * it bypasses all the rx defragmentaion. + * + * @param vdev - the data virtual device object + * @param val - the safemode state + * @return - void + */ +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val); + +/** + * @brief set the privacy filter + * @details + * Rx related. Set the privacy filters. When rx packets, check + * the ether type, filter type and packet type + * to decide whether discard these packets. + * + * @param vdev - the data virtual device object + * @param filter - filters to be set + * @param num - the number of filters + * @return - void + */ +void +ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev, + void *filter, uint32_t num); + +/** + * @brief configure the drop unencrypted frame flag + * @details + * Rx related. When set this flag, all the unencrypted frames + * received over a secure connection will be discarded + * + * @param vdev - the data virtual device object + * @param val - flag + * @return - void + */ +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val); + +enum ol_txrx_peer_state { + ol_txrx_peer_state_invalid, + ol_txrx_peer_state_disc, /* initial state */ + ol_txrx_peer_state_conn, /* authentication in progress */ + ol_txrx_peer_state_auth, /* authentication successful */ +}; + +/** + * @brief specify the peer's authentication state + * @details + * Specify the peer's authentication state (none, connected, authenticated) + * to allow the data SW to determine whether to filter out invalid data frames. + * (In the "connected" state, where security is enabled, but authentication + * has not completed, tx and rx data frames other than EAPOL or WAPI should + * be discarded.) + * This function is only relevant for systems in which the tx and rx filtering + * are done in the host rather than in the target. + * + * @param data_peer - which peer has changed its state + * @param state - the new state of the peer + * + * Return: CDF Status + */ +CDF_STATUS +ol_txrx_peer_state_update(ol_txrx_pdev_handle pdev, uint8_t *peer_addr, + enum ol_txrx_peer_state state); + +void +ol_txrx_peer_keyinstalled_state_update(ol_txrx_peer_handle data_peer, + uint8_t val); + +#define ol_tx_addba_conf(data_peer, tid, status) /* no-op */ + +/** + * @brief Find a txrx peer handle from the peer's MAC address + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain the peer's MAC address, + * this function allows the peer handled to be retrieved, based on the peer's + * MAC address. + * In cases where there are multiple peer objects with the same MAC address, + * it is undefined which such object is returned. + * This function does not increment the peer's reference count. Thus, it is + * only suitable for use as long as the control SW has assurance that it has + * not deleted the peer object, by calling ol_txrx_peer_detach. + * + * @param pdev - the data physical device object + * @param peer_mac_addr - MAC address of the peer in question + * @return handle to the txrx peer object + */ +ol_txrx_peer_handle +ol_txrx_peer_find_by_addr(ol_txrx_pdev_handle pdev, uint8_t *peer_mac_addr); + +/** + * @brief Find a txrx peer handle from a peer's local ID + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain a small integer local peer ID, + * this function allows the peer handled to be retrieved, based on the local + * peer ID. + * + * @param pdev - the data physical device object + * @param local_peer_id - the ID txrx assigned locally to the peer in question + * @return handle to the txrx peer object + */ +#if QCA_SUPPORT_TXRX_LOCAL_PEER_ID +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(ol_txrx_pdev_handle pdev, uint8_t local_peer_id); +#else +#define ol_txrx_peer_find_by_local_id(pdev, local_peer_id) NULL +#endif + +struct ol_txrx_peer_stats_t { + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } tx; + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } rx; +}; + +/** + * @brief Provide a snapshot of the txrx counters for the specified peer + * @details + * The txrx layer optionally maintains per-peer stats counters. + * This function provides the caller with a consistent snapshot of the + * txrx stats counters for the specified peer. + * + * @param pdev - the data physical device object + * @param peer - which peer's stats counters are requested + * @param stats - buffer for holding the stats counters snapshot + * @return success / failure status + */ +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats); +#else +#define ol_txrx_peer_stats_copy(pdev, peer, stats) A_ERROR /* failure */ +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + +/* Config parameters for txrx_pdev */ +struct txrx_pdev_cfg_param_t { + uint8_t is_full_reorder_offload; + /* IPA Micro controller data path offload enable flag */ + uint8_t is_uc_offload_enabled; + /* IPA Micro controller data path offload TX buffer count */ + uint32_t uc_tx_buffer_count; + /* IPA Micro controller data path offload TX buffer size */ + uint32_t uc_tx_buffer_size; + /* IPA Micro controller data path offload RX indication ring count */ + uint32_t uc_rx_indication_ring_count; + /* IPA Micro controller data path offload TX partition base */ + uint32_t uc_tx_partition_base; + /* IP, TCP and UDP checksum offload */ + bool ip_tcp_udp_checksum_offload; + /* Rx processing in thread from TXRX */ + bool enable_rxthread; + /* CE classification enabled through INI */ + bool ce_classify_enabled; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + /* Threshold to stop queue in percentage */ + uint32_t tx_flow_stop_queue_th; + /* Start queue offset in percentage */ + uint32_t tx_flow_start_queue_offset; +#endif +}; + +/** + * @brief Setup configuration parameters + * @details + * Allocation configuration context that will be used across data path + * + * @param osdev - OS handle needed as an argument for some OS primitives + * @return the control device object + */ +ol_pdev_handle ol_pdev_cfg_attach(cdf_device_t osdev, + struct txrx_pdev_cfg_param_t cfg_param); + +CDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id); +void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id); + + +#define OL_TXRX_INVALID_LOCAL_PEER_ID 0xffff +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer); +ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id); +ol_txrx_peer_handle +ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_addr, uint8_t *peer_id); +#else +#define ol_txrx_local_peer_id(peer) OL_TXRX_INVALID_LOCAL_PEER_ID +#define ol_txrx_find_peer_by_addr(pdev, peer_addr, peer_id) NULL +#define ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, peer_addr, peer_id) NULL +#endif + +#define OL_TXRX_RSSI_INVALID 0xffff +/** + * @brief Provide the current RSSI average from data frames sent by a peer. + * @details + * If a peer has sent data frames, the data SW will optionally keep + * a running average of the RSSI observed for those data frames. + * This function returns that time-average RSSI if is it available, + * or OL_TXRX_RSSI_INVALID if either RSSI tracking is disabled or if + * no data frame indications with valid RSSI meta-data have been received. + * The RSSI is in approximate dBm units, and is normalized with respect + * to a 20 MHz channel. For example, if a data frame is received on a + * 40 MHz channel, wherein both the primary 20 MHz channel and the + * secondary 20 MHz channel have an RSSI of -77 dBm, the reported RSSI + * will be -77 dBm, rather than the actual -74 dBm RSSI from the + * combination of the primary + extension 20 MHz channels. + * Alternatively, the RSSI may be evaluated only on the primary 20 MHz + * channel. + * + * @param peer - which peer's RSSI is desired + * @return RSSI evaluted from frames sent by the specified peer + */ +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer); +#else +#define ol_txrx_peer_rssi(peer) OL_TXRX_RSSI_INVALID +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +#define OL_TXRX_INVALID_LOCAL_PEER_ID 0xffff +#if QCA_SUPPORT_TXRX_LOCAL_PEER_ID +uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer); +#else +#define ol_txrx_local_peer_id(peer) OL_TXRX_INVALID_LOCAL_PEER_ID +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +/** + * @brief updates the compute interval period for TSM stats. + * @details + * @param interval - interval for stats computation + */ +void ol_tx_set_compute_interval(ol_txrx_pdev_handle pdev, uint32_t interval); + +/** + * @brief Return the uplink (transmitted) packet count and loss count. + * @details + * This function will be called for getting uplink packet count and + * loss count for given stream (access category) a regular interval. + * This also resets the counters hence, the value returned is packets + * counted in last 5(default) second interval. These counter are + * incremented per access category in ol_tx_completion_handler() + * + * @param category - access category of interest + * @param out_packet_count - number of packets transmitted + * @param out_packet_loss_count - number of packets lost + */ +void +ol_tx_packet_count(ol_txrx_pdev_handle pdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category); +#endif + +/** + * @brief Return the average delays for tx frames. + * @details + * Return the average of the total time tx frames spend within the driver + * and the average time tx frames take to be transmitted. + * These averages are computed over a 5 second time interval. + * These averages are computed separately for separate access categories, + * if the QCA_COMPUTE_TX_DELAY_PER_AC flag is set. + * + * @param pdev - the data physical device instance + * @param queue_delay_microsec - average time tx frms spend in the WLAN driver + * @param tx_delay_microsec - average time for frames to be transmitted + * @param category - category (TID) of interest + */ +#ifdef QCA_COMPUTE_TX_DELAY +void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category); +#else +static inline void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + /* no-op version if QCA_COMPUTE_TX_DELAY is not set */ + *queue_delay_microsec = *tx_delay_microsec = 0; +} +#endif + +/* + * Bins used for reporting delay histogram: + * bin 0: 0 - 10 ms delay + * bin 1: 10 - 20 ms delay + * bin 2: 20 - 40 ms delay + * bin 3: 40 - 80 ms delay + * bin 4: 80 - 160 ms delay + * bin 5: > 160 ms delay + */ +#define QCA_TX_DELAY_HIST_REPORT_BINS 6 +/** + * @brief Provide a histogram of tx queuing delays. + * @details + * Return a histogram showing the number of tx frames of the specified + * category for each of the delay levels in the histogram bin spacings + * listed above. + * These histograms are computed over a 5 second time interval. + * These histograms are computed separately for separate access categories, + * if the QCA_COMPUTE_TX_DELAY_PER_AC flag is set. + * + * @param pdev - the data physical device instance + * @param bin_values - an array of QCA_TX_DELAY_HIST_REPORT_BINS elements + * This array gets filled in with the histogram bin counts. + * @param category - category (TID) of interest + */ +#ifdef QCA_COMPUTE_TX_DELAY +void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, uint16_t *bin_values, int category); +#else +static inline void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, uint16_t *bin_values, int category) +{ + /* no-op version if QCA_COMPUTE_TX_DELAY is not set */ + cdf_assert(bin_values); + cdf_mem_zero(bin_values, + QCA_TX_DELAY_HIST_REPORT_BINS * sizeof(*bin_values)); +} +#endif + +#if defined(QCA_SUPPORT_TX_THROTTLE) +/** + * @brief Set the thermal mitgation throttling level. + * @details + * This function applies only to LL systems. This function is used set the + * tx throttle level used for thermal mitigation + * + * @param pdev - the physics device being throttled + */ +void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level); +#else +static inline void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, + int level) +{ + /* no-op */ +} +#endif /* QCA_SUPPORT_TX_THROTTLE */ + +#if defined(QCA_SUPPORT_TX_THROTTLE) +/** + * @brief Configure the thermal mitgation throttling period. + * @details + * This function applies only to LL systems. This function is used set the + * period over which data will be throttled + * + * @param pdev - the physics device being throttled + */ +void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, int period); +#else +static inline void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, + int period) +{ + /* no-op */ +} +#endif /* QCA_SUPPORT_TX_THROTTLE */ + +void ol_vdev_rx_set_intrabss_fwd(ol_txrx_vdev_handle vdev, bool val); + + +#ifdef IPA_OFFLOAD +/** + * @brief Client request resource information + * @details + * OL client will reuqest IPA UC related resource information + * Resource information will be distributted to IPA module + * All of the required resources should be pre-allocated + * + * @param pdev - handle to the HTT instance + * @param ce_sr_base_paddr - copy engine source ring base physical address + * @param ce_sr_ring_size - copy engine source ring size + * @param ce_reg_paddr - copy engine register physical address + * @param tx_comp_ring_base_paddr - tx comp ring base physical address + * @param tx_comp_ring_size - tx comp ring size + * @param tx_num_alloc_buffer - number of allocated tx buffer + * @param rx_rdy_ring_base_paddr - rx ready ring base physical address + * @param rx_rdy_ring_size - rx ready ring size + * @param rx_proc_done_idx_paddr - rx process done index physical address + */ +void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr); + +/** + * @brief Client set IPA UC doorbell register + * @details + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * @param pdev - handle to the HTT instance + * @param ipa_uc_tx_doorbell_paddr - tx comp doorbell physical address + * @param ipa_uc_rx_doorbell_paddr - rx ready doorbell physical address + */ +void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + uint32_t ipa_tx_uc_doorbell_paddr, + uint32_t ipa_rx_uc_doorbell_paddr); + +/** + * @brief Client notify IPA UC data path active or not + * + * @param pdev - handle to the HTT instance + * @param uc_active - UC data path is active or not + * @param is_tx - UC TX is active or not + */ +void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, bool uc_active, bool is_tx); + +/** + * @brief Offload data path activation notificaiton + * @details + * Firmware notification handler for offload datapath activity + * + * @param pdev - handle to the HTT instance + * @param op_code - activated for tx or rx data patrh + */ +void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg); + +/** + * @brief callback function registration + * @details + * OSIF layer callback function registration API + * OSIF layer will register firmware offload datapath activity + * notification callback + * + * @param pdev - handle to the HTT instance + * @param ipa_uc_op_cb_type - callback function pointer should be registered + * @param osif_dev - osif instance pointer + */ +void ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + void (*ipa_uc_op_cb_type)(uint8_t *op_msg, + void *osif_ctxt), + void *osif_dev); + +/** + * @brief query uc data path stats + * @details + * Query uc data path stats from firmware + * + * @param pdev - handle to the HTT instance + */ +void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev); +#else +static inline void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + uint32_t ipa_tx_uc_doorbell_paddr, + uint32_t ipa_rx_uc_doorbell_paddr) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, + bool uc_active, bool is_tx) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + void (*ipa_uc_op_cb_type)(uint8_t *op_msg, + void *osif_ctxt), + void *osif_dev) +{ + return; +} + +static inline void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +void ol_txrx_display_stats(uint16_t bitmap); +void ol_txrx_clear_stats(uint16_t bitmap); +int ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len); + +CDF_STATUS ol_txrx_register_ocb_peer(void *cds_ctx, uint8_t *mac_addr, + uint8_t *peer_id); + +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer); + +/* TX FLOW Control related functions */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#define TX_FLOW_MGMT_POOL_ID 0xEF + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_SIZE 32 +#else +#define TX_FLOW_MGMT_POOL_SIZE 0 +#endif + +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_dump_flow_pool_info(void); +void ol_tx_clear_flow_pool_stats(void); +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size); +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id); +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size); +int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool); +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc); +#else + +static inline void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void ol_tx_dump_flow_pool_info(void) +{ + return; +} +static inline void ol_tx_clear_flow_pool_stats(void) +{ + return; +} +static inline void ol_tx_flow_pool_map_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + return; +} +static inline void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id) +{ + return; +} +static inline struct ol_tx_flow_pool_t *ol_tx_create_flow_pool( + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + return NULL; +} +static inline int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + return 0; +} +static inline void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + return; +} +#endif + +#endif /* _OL_TXRX_CTRL_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_dbg.h b/core/dp/ol/inc/ol_txrx_dbg.h new file mode 100644 index 0000000000..0350109365 --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_dbg.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_dbg.h + * @brief Functions provided for visibility and debugging. + */ +#ifndef _OL_TXRX_DBG__H_ +#define _OL_TXRX_DBG__H_ + +#include /* A_STATUS, uint64_t */ +#include /* cdf_semaphore_t */ +#include /* htt_dbg_stats_type */ +#include /* ol_txrx_stats */ + +typedef void (*ol_txrx_stats_callback)(void *ctxt, + enum htt_dbg_stats_type type, + uint8_t *buf, int bytes); + +struct ol_txrx_stats_req { + uint32_t stats_type_upload_mask; /* which stats to upload */ + uint32_t stats_type_reset_mask; /* which stats to reset */ + + /* stats will be printed if either print element is set */ + struct { + int verbose; /* verbose stats printout */ + int concise; /* concise stats printout (takes precedence) */ + } print; /* print uploaded stats */ + + /* stats notify callback will be invoked if fp is non-NULL */ + struct { + ol_txrx_stats_callback fp; + void *ctxt; + } callback; + + /* stats will be copied into the specified buffer if buf is non-NULL */ + struct { + uint8_t *buf; + int byte_limit; /* don't copy more than this */ + } copy; + + /* + * If blocking is true, the caller will take the specified semaphore + * to wait for the stats to be uploaded, and the driver will release + * the semaphore when the stats are done being uploaded. + */ + struct { + int blocking; + cdf_semaphore_t *sem_ptr; + } wait; +}; + +#ifndef TXRX_DEBUG_LEVEL +#define TXRX_DEBUG_LEVEL 0 /* no debug info */ +#endif + +#ifndef ATH_PERF_PWR_OFFLOAD /*---------------------------------------------*/ + +#define ol_txrx_debug(vdev, debug_specs) 0 +#define ol_txrx_fw_stats_cfg(vdev, type, val) 0 +#define ol_txrx_fw_stats_get(vdev, req) 0 +#define ol_txrx_aggr_cfg(vdev, max_subfrms_ampdu, max_subfrms_amsdu) 0 + +#else /*---------------------------------------------------------------------*/ + +#include /* ol_txrx_pdev_handle, etc. */ + +int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs); + +void ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev, + uint8_t cfg_stats_type, uint32_t cfg_val); + +int ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, + struct ol_txrx_stats_req *req); + +int ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev, + int max_subfrms_ampdu, int max_subfrms_amsdu); + +enum { + TXRX_DBG_MASK_OBJS = 0x01, + TXRX_DBG_MASK_STATS = 0x02, + TXRX_DBG_MASK_PROT_ANALYZE = 0x04, + TXRX_DBG_MASK_RX_REORDER_TRACE = 0x08, + TXRX_DBG_MASK_RX_PN_TRACE = 0x10 +}; + +/*--- txrx printouts ---*/ + +/* + * Uncomment this to enable txrx printouts with dynamically adjustable + * verbosity. These printouts should not impact performance. + */ +#define TXRX_PRINT_ENABLE 1 +/* uncomment this for verbose txrx printouts (may impact performance) */ +/* #define TXRX_PRINT_VERBOSE_ENABLE 1 */ + +void ol_txrx_print_level_set(unsigned level); + +/*--- txrx object (pdev, vdev, peer) display debug functions ---*/ + +#if TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent); +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent); +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent); +#else +#define ol_txrx_pdev_display(pdev, indent) +#define ol_txrx_vdev_display(vdev, indent) +#define ol_txrx_peer_display(peer, indent) +#endif + +/*--- txrx stats display debug functions ---*/ + + +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev); + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev); + + +/*--- txrx protocol analyzer debug feature ---*/ + +/* uncomment this to enable the protocol analzyer feature */ +/* #define ENABLE_TXRX_PROT_ANALYZE 1 */ + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev); + +#else + +#define ol_txrx_prot_ans_display(pdev) + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +/*--- txrx sequence number trace debug feature ---*/ + +/* uncomment this to enable the rx reorder trace feature */ +/* #define ENABLE_RX_REORDER_TRACE 1 */ + +#define ol_txrx_seq_num_trace_display(pdev) \ + ol_rx_reorder_trace_display(pdev, 0, 0) + +#if defined(ENABLE_RX_REORDER_TRACE) + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit); + +#else + +#define ol_rx_reorder_trace_display(pdev, just_once, limit) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace debug feature ---*/ + +/* uncomment this to enable the rx PN trace feature */ +/* #define ENABLE_RX_PN_TRACE 1 */ + +#define ol_txrx_pn_trace_display(pdev) ol_rx_pn_trace_display(pdev, 0) + +#if defined(ENABLE_RX_PN_TRACE) + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once); + +#else + +#define ol_rx_pn_trace_display(pdev, just_once) + +#endif /* ENABLE_RX_PN_TRACE */ + +/*--- tx queue log debug feature ---*/ +/* uncomment this to enable the tx queue log feature */ +/* #define ENABLE_TX_QUEUE_LOG 1 */ + +#define ol_tx_queue_log_display(pdev) + +#endif /* ATH_PERF_PWR_OFFLOAD */ +/*----------------------------------------*/ + +#endif /* _OL_TXRX_DBG__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_htt_api.h b/core/dp/ol/inc/ol_txrx_htt_api.h new file mode 100644 index 0000000000..09041cadf3 --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_htt_api.h @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_htt_api.h + * @brief Define the host data API functions called by the host HTT SW. + */ +#ifndef _OL_TXRX_HTT_API__H_ +#define _OL_TXRX_HTT_API__H_ + +#include /* HTT_TX_COMPL_IND_STAT */ +#include /* A_STATUS */ +#include /* cdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ + +static inline uint16_t *ol_tx_msdu_id_storage(cdf_nbuf_t msdu) +{ + cdf_assert(cdf_nbuf_headroom(msdu) >= (sizeof(uint16_t) * 2 - 1)); + return (uint16_t *) (((cdf_size_t) (cdf_nbuf_head(msdu) + 1)) & ~0x1); +} + +/** + * @brief Tx MSDU download completion for a LL system + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, cdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system without tx completion msgs + * @details + * Free the tx descriptor and tx frame. + * Invoke the HL tx download scheduler. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_free(void *pdev, + A_STATUS status, cdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system with tx completion msgs + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * Optionally, invoke the HL tx download scheduler. (It is probable that + * the HL tx download scheduler would operate in response to tx completion + * messages rather than download completion events.) + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_retain(void *pdev, + A_STATUS status, + cdf_nbuf_t msdu, uint16_t msdu_id); + +/* + * For now, make the host HTT -> host txrx tx completion status + * match the target HTT -> host HTT tx completion status, so no + * translation is needed. + */ +/* + * host-only statuses use a different part of the number space + * than host-target statuses + */ +#define HTT_HOST_ONLY_STATUS_CODE_START 128 +enum htt_tx_status { + /* ok - successfully sent + acked */ + htt_tx_status_ok = HTT_TX_COMPL_IND_STAT_OK, + + /* discard - not sent (congestion control) */ + htt_tx_status_discard = HTT_TX_COMPL_IND_STAT_DISCARD, + + /* no_ack - sent, but no ack */ + htt_tx_status_no_ack = HTT_TX_COMPL_IND_STAT_NO_ACK, + + /* download_fail - host could not deliver the tx frame to target */ + htt_tx_status_download_fail = HTT_HOST_ONLY_STATUS_CODE_START, +}; + +/** + * @brief Process a tx completion message sent by the target. + * @details + * When the target is done transmitting a tx frame (either because + * the frame was sent + acknowledged, or because the target gave up) + * it sends a tx completion message to the host. + * This notification function is used regardless of whether the + * transmission succeeded or not; the status argument indicates whether + * the transmission succeeded. + * This tx completion message indicates via the descriptor ID which + * tx frames were completed, and indicates via the status whether the + * frames were transmitted successfully. + * The host frees the completed descriptors / frames (updating stats + * in the process). + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param status - whether transmission was successful + * @param tx_msdu_id_iterator - abstract method of finding the IDs for the + * individual MSDUs referenced by the tx completion message, via the + * htt_tx_compl_desc_id API function + */ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *tx_msdu_id_iterator); + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits); + +/** + * @brief Init the total amount of target credit. + * @details + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process a tx completion message for a single MSDU. + * @details + * The ol_tx_single_completion_handler function performs the same tx + * completion processing as the ol_tx_completion_handler, but for a + * single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + * + * @param pdev - the data physical device that sent the tx frames + * @param status - whether transmission was successful + * @param tx_msdu_id - ID of the frame which completed transmission + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id); + +/** + * @brief Update the amount of target credit. + * @details + * When the target finishes with an old transmit frame, it can use the + * space that was occupied by the old tx frame to store a new tx frame. + * This function is used to inform the txrx layer, where the HL tx download + * scheduler resides, about such updates to the target's tx credit. + * This credit update is done explicitly, rather than having the txrx layer + * update the credit count itself inside the ol_tx_completion handler + * function. This provides HTT with the flexibility to limit the rate of + * downloads from the TXRX layer's download scheduler, by controlling how + * much credit the download scheduler gets, and also provides the flexibility + * to account for a change in the tx memory pool size within the target. + * This function is only used for HL systems; in LL systems, each tx frame + * is assumed to use exactly one credit (for its target-side tx descriptor), + * and any rate limiting is managed within the target. + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * (For LL, the rx descriptors and frames are delivered directly + * to the host via MAC DMA, while for HL the rx descriptor and + * frame for individual frames are combined with the rx indication + * message.) + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * (For HL, this netbuf also holds the rx desc and rx payload, but + * the data SW is agnostic to whether the desc and payload are + * piggybacked with the rx indication message.) + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param num_mpdu_ranges - how many ranges of MPDUs does the message describe. + * Each MPDU within the range has the same rx status. + */ +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges); + +/** + * @brief Process an rx fragment indication message sent by the target. + * @details + * The target sends a rx fragment indication message to the host as a + * notification that there are new rx fragment available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx fragment + * associated with the indication, and calls this function to + * invoke the rx fragment data processing on the new fragment. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_frag_ind_msg - the network buffer holding the rx fragment indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + */ +void ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid); + +/** + * @brief Process rx offload deliver indication message sent by the target. + * @details + * When the target exits offload mode, target delivers packets that it has + * held in its memory to the host using this message. + * Low latency case: + * The message contains the number of MSDUs that are being delivered by the + * target to the host. The packet itself resides in host ring along with some + * metadata describing the peer id, vdev id, tid, FW desc and length of + * the packet being delivered. + * Hight letency case: + * The message itself contains the payload of the MSDU being delivered by + * the target to the host. The message also contains meta data describing + * the packet such as peer id, vdev id, tid, FW desc and length of the packet + * being delivered. Refer to htt.h for the exact structure of the message. + * @param pdev - the data physical device that received the frame. + * @param msg - offload deliver indication message + * @param msdu_cnt - number of MSDUs being delivred. + */ +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t msg, int msdu_cnt); + +/** + * @brief Process a peer map message sent by the target. + * @details + * Each time the target allocates a new peer ID, it will inform the + * host via the "peer map" message. This function processes that + * message. The host data SW looks for a peer object whose MAC address + * matches the MAC address specified in the peer map message, and then + * sets up a mapping between the peer ID specified in the message and + * the peer object that was found. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID generated by the target to refer to the peer in question + * The target may create multiple IDs for a single peer. + * @param vdev_id - Reference to the virtual device the peer is associated with + * @param peer_mac_addr - MAC address of the peer in question + * @param tx_ready - whether transmits to this peer can be done already, or + * need to wait for a call to peer_tx_ready (only applies to HL systems) + */ +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready); + +/** + * @brief notify the host that the target is ready to transmit to a new peer. + * @details + * Some targets can immediately accept tx frames for a new peer, as soon as + * the peer's association completes. Other target need a short setup time + * before they are ready to accept tx frames for the new peer. + * If the target needs time for setup, it will provide a peer_tx_ready + * message when it is done with the setup. This function forwards this + * notification from the target to the host's tx queue manager. + * This function only applies for HL systems, in which the host determines + * which peer a given tx frame is for, and stores the tx frames in queues. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID for the new peer which can now accept tx frames + */ +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a peer unmap message sent by the target. + * @details + * Each time the target frees a peer ID, it will inform the host via the + * "peer unmap" message. This function processes that message. + * The host data SW uses the peer ID from the message to find the peer + * object from peer_map[peer_id], then invalidates peer_map[peer_id] + * (by setting it to NULL), and checks whether there are any remaining + * references to the peer object. If not, the function deletes the + * peer object. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID that is being freed. + * The target may create multiple IDs for a single peer. + */ +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a security indication message sent by the target. + * @details + * When a key is assigned to a peer, the target will inform the host + * with a security indication message. + * The host remembers the security type, and infers whether a rx PN + * check is needed. + * + * @param pdev - data physical device handle + * @param peer_id - which peer the security info is for + * @param sec_type - which type of security / key the peer is using + * @param is_unicast - whether security spec is for a unicast or multicast key + * @param michael_key - key used for TKIP MIC (if sec_type == TKIP) + * @param rx_pn - RSC used for WAPI PN replay check (if sec_type == WAPI) + */ +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn); + +/** + * @brief Process an ADDBA message sent by the target. + * @details + * When the target notifies the host of an ADDBA event for a specified + * peer-TID, the host will set up the rx reordering state for the peer-TID. + * Specifically, the host will create a rx reordering array whose length + * is based on the window size specified in the ADDBA. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + * @param win_sz - how many sequence numbers are in the ARQ block ack window + * set up by the ADDBA event + * @param start_seq_num - the initial value of the sequence number during the + * block ack agreement, as specified by the ADDBA request. + * @param failed - indicate whether the target's ADDBA setup succeeded: + * 0 -> success, 1 -> fail + */ +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed); + +/** + * @brief Process a DELBA message sent by the target. + * @details + * When the target notifies the host of a DELBA event for a specified + * peer-TID, the host will clean up the rx reordering state for the peer-TID. + * Specifically, the host will remove the rx reordering array, and will + * set the reorder window size to be 1 (stop and go ARQ). + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + */ +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid); + +enum htt_rx_flush_action { + htt_rx_flush_release, + htt_rx_flush_discard, +}; + +/** + * @brief Process a rx reorder flush message sent by the target. + * @details + * The target's rx reorder logic can send a flush indication to the + * host's rx reorder buffering either as a flush IE within a rx + * indication message, or as a standalone rx reorder flush message. + * This ol_rx_flush_handler function processes the standalone rx + * reorder flush message from the target. + * The flush message specifies a range of sequence numbers whose + * rx frames are flushed. + * Some sequence numbers within the specified range may not have + * rx frames; the host needs to check for each sequence number in + * the specified range whether there are rx frames held for that + * sequence number. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer has the rx data being flushed + * @param seq_num_start - Which sequence number within the rx reordering + * buffer the flushing should start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush includes this initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer the flushing should stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush excludes this final sequence number. + * @param action - whether to release or discard the rx frames + */ +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t seq_num_start, + uint16_t seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief Process a rx pn indication message + * @details + * When the peer is configured to get PN checking done in target, + * the target instead of sending reorder flush/release messages + * sends PN indication messages which contain the start and end + * sequence numbers to be flushed/released along with the sequence + * numbers of MPDUs that failed the PN check in target. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer + * @param seq_num_start - Which sequence number within the rx reordering + * buffer to start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * This is the initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer to stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The processing stops right before this sequence number + * @param pn_ie_cnt - Indicates the number of PN information elements. + * @param pn_ie - Pointer to the array of PN information elements. Each + * PN information element contains the LSBs of the 802.11 sequence number + * of the MPDU that failed the PN checking in target. + */ +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + int seq_num_start, + int seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie); + +/** + * @brief Process a stats message sent by the target. + * @details + * The host can request target for stats. + * The target sends the stats to the host via a confirmation message. + * This ol_txrx_fw_stats_handler function processes the confirmation message. + * Currently, this processing consists of copying the stats from the message + * buffer into the txrx pdev object, and waking the sleeping host context + * that requested the stats. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param cookie - Value echoed from the cookie in the stats request + * message. This allows the host SW to find the stats request object. + * (Currently, this cookie is unused.) + * @param stats_info_list - stats confirmation message contents, containing + * a list of the stats requested from the target + */ +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint64_t cookie, uint8_t *stats_info_list); + +/** + * @brief Process a tx inspect message sent by the target. + * @details: + * TODO: update + * This tx inspect message indicates via the descriptor ID + * which tx frames are to be inspected by host. The host + * re-injects the packet back to the host for a number of + * cases. + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param tx_msdu_id_iterator - abstract method of finding the IDs for the + * individual MSDUs referenced by the tx completion message, via the + * htt_tx_compl_desc_id API function + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator); + +/** + * @brief Get the UAPSD mask. + * @details + * This function will return the UAPSD TID mask. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return uapsd mask value + */ +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +/** + * @brief Get the Qos Capable. + * @details + * This function will return the txrx_peer qos_capable. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return qos_capable value + */ +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. The frames indicated have been re-ordered by + * the target. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param is_offload - is this an offload indication? + */ +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload); + +#endif /* _OL_TXRX_HTT_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_osif_api.h b/core/dp/ol/inc/ol_txrx_osif_api.h new file mode 100644 index 0000000000..69b6dcf6d1 --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_osif_api.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_osif_api.h + * @brief Define the host data API functions called by the host OS shim SW. + */ +#ifndef _OL_TXRX_OSIF_API__H_ +#define _OL_TXRX_OSIF_API__H_ + +#include /* cdf_nbuf_t */ + +#include /* ol_osif_vdev_handle */ +#include /* ol_txrx_pdev_handle, etc. */ +#include +#include "cds_sched.h" + +/** + * struct ol_rx_cached_buf - rx cached buffer + * @list: linked list + * @buf: skb buffer + */ +struct ol_rx_cached_buf { + struct list_head list; + cdf_nbuf_t buf; +}; + +/** + * @typedef ol_txrx_rx_fp + * @brief receive function to hand batches of data frames from txrx to OS shim + */ +typedef void (*ol_txrx_rx_fp)(void *osif_dev, cdf_nbuf_t msdus); + +/** + * @typedef ol_txrx_tx_fp + * @brief top-level transmit function + */ +typedef cdf_nbuf_t (*ol_txrx_tx_fp)(ol_txrx_vdev_handle data_vdev, + cdf_nbuf_t msdu_list); + +/** + * @typedef ol_txrx_tx_non_std_fp + * @brief top-level transmit function for non-standard tx frames + * @details + * This function pointer provides an alternative to the ol_txrx_tx_fp + * to support non-standard transmits. In particular, this function + * supports transmission of: + * 1. "Raw" frames + * These raw frames already have an 802.11 header; the usual + * 802.11 header encapsulation by the driver does not apply. + * 2. TSO segments + * During tx completion, the txrx layer needs to reclaim the buffer + * that holds the ethernet/IP/TCP header created for the TSO segment. + * Thus, these tx frames need to be marked as TSO, to show that they + * need this special handling during tx completion. + * + * @param data_vdev - which virtual device should transmit the frame + * @param tx_spec - what non-standard operations to apply to the tx frame + * @param msdu_list - tx frame(s), in a null-terminated list + */ +typedef cdf_nbuf_t (*ol_txrx_tx_non_std_fp)(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, + cdf_nbuf_t msdu_list); + +struct txrx_rx_metainfo; + +/** + * @typedef ol_txrx_tx_fc_fp + * @brief tx flow control notification function from txrx to OS shim + * @param osif_dev - the virtual device's OS shim object + * @param tx_resume - tx os q should be resumed or not + */ +typedef void (*ol_txrx_tx_flow_control_fp)(void *osif_dev, + bool tx_resume); + +/** + * struct ol_txrx_desc_type - txrx descriptor type + * @sta_id: sta id + * @is_qos_enabled: is station qos enabled + * @is_wapi_supported: is station wapi supported + */ +struct ol_txrx_desc_type { + uint8_t sta_id; + uint8_t is_qos_enabled; + uint8_t is_wapi_supported; +}; + + +typedef CDF_STATUS (*ol_rx_callback_fp)(void *p_cds_gctx, + cdf_nbuf_t pDataBuff, + uint8_t ucSTAId); + +typedef void (*ol_tx_pause_callback_fp)(uint8_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +CDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb); +#else +static inline +CDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb) +{ + return CDF_STATUS_SUCCESS; + +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +int ol_txrx_register_tx_flow_control (uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx); + +int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id); + +void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev, + bool tx_resume); +bool +ol_txrx_get_tx_resource(uint8_t sta_id, + unsigned int low_watermark, + unsigned int high_watermark_offset); + +int +ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * @typedef ol_txrx_rx_fp + * @brief receive function to hand batches of data frames from txrx to OS shim + */ + +struct ol_txrx_osif_ops { + /* tx function pointers - specified by txrx, stored by OS shim */ + struct { + ol_txrx_tx_fp std; + ol_txrx_tx_non_std_fp non_std; + ol_txrx_tx_flow_control_fp flow_control_cb; + } tx; + + /* rx function pointers - specified by OS shim, stored by txrx */ + struct { + ol_txrx_rx_fp std; + } rx; +}; + +/** + * @brief Link a vdev's data object with the matching OS shim vdev object. + * @details + * The data object for a virtual device is created by the function + * ol_txrx_vdev_attach. However, rather than fully linking the + * data vdev object with the vdev objects from the other subsystems + * that the data vdev object interacts with, the txrx_vdev_attach + * function focuses primarily on creating the data vdev object. + * After the creation of both the data vdev object and the OS shim + * vdev object, this txrx_osif_vdev_attach function is used to connect + * the two vdev objects, so the data SW can use the OS shim vdev handle + * when passing rx data received by a vdev up to the OS shim. + * + * @param txrx_vdev - the virtual device's data object + * @param osif_vdev - the virtual device's OS shim object + * @param txrx_ops - (pointers to) the functions used for tx and rx data xfer + * There are two portions of these txrx operations. + * The rx portion is filled in by OSIF SW before calling + * ol_txrx_osif_vdev_register; inside the ol_txrx_osif_vdev_register + * the txrx SW stores a copy of these rx function pointers, to use + * as it delivers rx data frames to the OSIF SW. + * The tx portion is filled in by the txrx SW inside + * ol_txrx_osif_vdev_register; when the function call returns, + * the OSIF SW stores a copy of these tx functions to use as it + * delivers tx data frames to the txrx SW. + * The rx function pointer inputs consist of the following: + * rx: the OS shim rx function to deliver rx data frames to. + * This can have different values for different virtual devices, + * e.g. so one virtual device's OS shim directly hands rx frames to + * the OS, but another virtual device's OS shim filters out P2P + * messages before sending the rx frames to the OS. + * The netbufs delivered to the osif_rx function are in the format + * specified by the OS to use for tx and rx frames (either 802.3 or + * native WiFi). + * rx_mon: the OS shim rx monitor function to deliver monitor data to + * Though in practice, it is probable that the same function will + * be used for delivering rx monitor data for all virtual devices, + * in theory each different virtual device can have a different + * OS shim function for accepting rx monitor data. + * The netbufs delivered to the osif_rx_mon function are in 802.11 + * format. Each netbuf holds a 802.11 MPDU, not an 802.11 MSDU. + * Depending on compile-time configuration, each netbuf may also + * have a monitor-mode encapsulation header such as a radiotap + * header added before the MPDU contents. + * The tx function pointer outputs consist of the following: + * tx: the tx function pointer for standard data frames + * This function pointer is set by the txrx SW to perform + * host-side transmit operations based on whether a HL or LL + * host/target interface is in use. + * tx_non_std: the tx function pointer for non-standard data frames, + * such as TSO frames, explicitly-prioritized frames, or "raw" + * frames which skip some of the tx operations, such as 802.11 + * MAC header encapsulation. + */ +void +ol_txrx_osif_vdev_register(ol_txrx_vdev_handle txrx_vdev, + void *osif_vdev, struct ol_txrx_osif_ops *txrx_ops); + +/** + * @brief Divide a jumbo TCP frame into smaller segments. + * @details + * For efficiency, the protocol stack above the WLAN driver may operate + * on jumbo tx frames, which are larger than the 802.11 MTU. + * The OSIF SW uses this txrx API function to divide the jumbo tx TCP frame + * into a series of segment frames. + * The segments are created as clones of the input jumbo frame. + * The txrx SW generates a new encapsulation header (ethernet + IP + TCP) + * for each of the output segment frames. The exact format of this header, + * e.g. 802.3 vs. Ethernet II, and IPv4 vs. IPv6, is chosen to match the + * header format of the input jumbo frame. + * The input jumbo frame is not modified. + * After the ol_txrx_osif_tso_segment returns, the OSIF SW needs to perform + * DMA mapping on each of the segment network buffers, and also needs to + * + * @param txrx_vdev - which virtual device will transmit the TSO segments + * @param max_seg_payload_bytes - the maximum size for the TCP payload of + * each segment frame. + * This does not include the ethernet + IP + TCP header sizes. + * @param jumbo_tcp_frame - jumbo frame which needs to be cloned+segmented + * @return + * NULL if the segmentation fails, - OR - + * a NULL-terminated list of segment network buffers + */ +cdf_nbuf_t ol_txrx_osif_tso_segment(ol_txrx_vdev_handle txrx_vdev, + int max_seg_payload_bytes, + cdf_nbuf_t jumbo_tcp_frame); + +cdf_nbuf_t ol_tx_send_data_frame(uint8_t sta_id, cdf_nbuf_t skb, + uint8_t proto_type); + +#ifdef IPA_OFFLOAD +cdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev, + cdf_nbuf_t skb); +#endif + +CDF_STATUS ol_txrx_register_peer(ol_rx_callback_fp rxcb, + struct ol_txrx_desc_type *sta_desc); + +CDF_STATUS ol_txrx_clear_peer(uint8_t sta_id); + +CDF_STATUS ol_txrx_change_peer_state(uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress); + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + cdf_nbuf_t rx_buf_list); + +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop); + +#if defined(FEATURE_LRO) +void ol_register_lro_flush_cb(void (handler)(void *), void *data); +#endif +#endif /* _OL_TXRX_OSIF_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_stats.h b/core/dp/ol/inc/ol_txrx_stats.h new file mode 100644 index 0000000000..44b384d5b2 --- /dev/null +++ b/core/dp/ol/inc/ol_txrx_stats.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_status.h + * @brief Functions provided for visibility and debugging. + * NOTE: This file is used by both kernel driver SW and userspace SW. + * Thus, do not reference use any kernel header files or defs in this file! + */ +#ifndef _OL_TXRX_STATS__H_ +#define _OL_TXRX_STATS__H_ + +#include /* uint64_t */ + + + +struct ol_txrx_stats_elem { + uint64_t pkts; + uint64_t bytes; +}; + +#define NUM_MAX_TSO_SEGS 8 +#define NUM_MAX_TSO_SEGS_MASK (NUM_MAX_TSO_SEGS - 1) + +#define NUM_MAX_TSO_MSDUS 128 +#define NUM_MAX_TSO_MSDUS_MASK (NUM_MAX_TSO_MSDUS - 1) + +struct ol_txrx_stats_tso_msdu { + struct cdf_tso_seg_t tso_segs[NUM_MAX_TSO_SEGS]; + uint32_t num_seg; + uint32_t tso_seg_idx; +}; + +struct ol_txrx_stats_tso_info { + struct ol_txrx_stats_tso_msdu tso_msdu_info[NUM_MAX_TSO_MSDUS]; + uint32_t tso_msdu_idx; +}; + +/** + * @brief data stats published by the host txrx layer + */ +struct ol_txrx_stats { + struct { + /* MSDUs given to the txrx layer by the management stack */ + struct ol_txrx_stats_elem mgmt; + /* MSDUs successfully sent across the WLAN */ + struct ol_txrx_stats_elem delivered; + struct { + /* MSDUs that the host did not accept */ + struct ol_txrx_stats_elem host_reject; + /* MSDUs which could not be downloaded to the target */ + struct ol_txrx_stats_elem download_fail; + /* MSDUs which the target discarded + (lack of memory or old age) */ + struct ol_txrx_stats_elem target_discard; + /* MSDUs which the target sent but + couldn't get an ack for */ + struct ol_txrx_stats_elem no_ack; + } dropped; + /* contains information of packets recevied per tx completion*/ + struct { + uint32_t pkts_1; + uint32_t pkts_2_10; + uint32_t pkts_11_20; + uint32_t pkts_21_30; + uint32_t pkts_31_40; + uint32_t pkts_41_50; + uint32_t pkts_51_60; + uint32_t pkts_61_plus; + } comp_histogram; + /* TSO (TCP segmentation offload) information */ + struct { + struct ol_txrx_stats_elem tso_pkts; +#if defined(FEATURE_TSO) + struct ol_txrx_stats_tso_info tso_info; +#endif + } tso; + } tx; + struct { + /* MSDUs given to the OS shim */ + struct ol_txrx_stats_elem delivered; + struct { + /* MSDUs forwarded to network stack */ + u_int32_t packets_stack; + /* MSDUs forwarded from the rx path to the tx path */ + u_int32_t packets_fwd; + /* MSDUs forwarded to stack and tx path */ + u_int32_t packets_stack_n_fwd; + } intra_bss_fwd; + } rx; +}; + +/* + * Structure to consolidate host stats + */ +struct ieee80211req_ol_ath_host_stats { + struct ol_txrx_stats txrx_stats; + struct { + int pkt_q_fail_count; + int pkt_q_empty_count; + int send_q_empty_count; + } htc; + struct { + int pipe_no_resrc_count; + int ce_ring_delta_fail_count; + } hif; +}; + +#endif /* _OL_TXRX_STATS__H_ */ diff --git a/core/dp/ol/inc/ol_vowext_dbg_defs.h b/core/dp/ol/inc/ol_vowext_dbg_defs.h new file mode 100644 index 0000000000..3be07aca63 --- /dev/null +++ b/core/dp/ol/inc/ol_vowext_dbg_defs.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _VOW_DEFINES__H_ +#define _VOW_DEFINES__H_ + +#define UDP_CKSUM_OFFSET 40 /* UDP check sum offset in network buffer */ +#define RTP_HDR_OFFSET 42 /* RTP header offset in network buffer */ +#define EXT_HDR_OFFSET 54 /* Extension header offset in network buffer */ +#define UDP_PDU_RTP_EXT 0x90 /* ((2 << 6) | (1 << 4)) RTP V2 + X bit */ +#define IP_VER4_N_NO_EXTRA_HEADERS 0x45 +#define IPERF3_DATA_OFFSET 12 /* iperf3 data offset from EXT_HDR_OFFSET */ +#define HAL_RX_40 0x08 /* 40 Mhz */ +#define HAL_RX_GI 0x04 /* full gi */ + +struct vow_extstats { + uint8_t rx_rssi_ctl0; /* control channel chain0 rssi */ + uint8_t rx_rssi_ctl1; /* control channel chain1 rssi */ + uint8_t rx_rssi_ctl2; /* control channel chain2 rssi */ + uint8_t rx_rssi_ext0; /* extention channel chain0 rssi */ + uint8_t rx_rssi_ext1; /* extention channel chain1 rssi */ + uint8_t rx_rssi_ext2; /* extention channel chain2 rssi */ + uint8_t rx_rssi_comb; /* combined RSSI value */ + uint8_t rx_bw; /* Band width 0-20, 1-40, 2-80 */ + uint8_t rx_sgi; /* Guard interval, 0-Long GI, 1-Short GI */ + uint8_t rx_nss; /* Number of spatial streams */ + uint8_t rx_mcs; /* Rate MCS value */ + uint8_t rx_ratecode; /* Hardware rate code */ + uint8_t rx_rs_flags; /* Recieve misc flags */ + uint8_t rx_moreaggr; /* 0 - non aggr frame */ + uint32_t rx_macTs; /* Time stamp */ + uint16_t rx_seqno; /* rx sequence number */ +}; + +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, cdf_nbuf_t msdu); + +#endif /* _VOW_DEFINES__H_ */ diff --git a/core/dp/txrx/ipv6_defs.h b/core/dp/txrx/ipv6_defs.h new file mode 100644 index 0000000000..c1c52babe4 --- /dev/null +++ b/core/dp/txrx/ipv6_defs.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IPV6__H_ +#define _IPV6__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +/* utilities for converting between network byte order and native endianness */ +#ifndef BYTESWAP32 +#define BYTESWAP32(x) \ + ((((x) & 0x000000ff) << 24) /* byte 0 -> byte 3 */ | \ + (((x) & 0x0000ff00) << 8) /* byte 1 -> byte 2 */ | \ + (((x) & 0x00ff0000) >> 8) /* byte 2 -> byte 1 */ | \ + (((x) & 0xff000000) >> 24) /* byte 3 -> byte 0 */) +#endif /* BYTESWAP32 */ + +#ifndef BE_TO_CPU32 +#if defined(ATH_TARGET) +/* assume target is little-endian */ +#define BE_TO_CPU32(x) BYTESWAP32(x) +#else +#ifdef BIG_ENDIAN_HOST +#define BE_TO_CPU32(x) (x) +#else +#define BE_TO_CPU32(x) BYTESWAP32(x) +#endif +#endif +#endif /* BE_TO_CPU32 */ + +/* IPv6 header definition */ + +#define IPV6_ADDR_LEN 4 /* bytes */ +struct ipv6_hdr_t { + A_UINT32 ver_tclass_flowlabel; /* version, traffic class, and flow label */ + A_UINT8 pyld_len[2]; /* payload length */ + A_UINT8 next_hdr; + A_UINT8 hop_limit; + A_UINT8 src_addr[IPV6_ADDR_LEN]; + A_UINT8 dst_addr[IPV6_ADDR_LEN]; +}; + +#define IPV6_HDR_LEN (sizeof(struct ipv6_hdr_t)) +#define IPV6_HDR_OFFSET_NEXT_HDR (offsetof(struct ipv6_hdr_t, next_hdr)) +#define IPV6_HDR_OFFSET_DST_ADDR (offsetof(struct ipv6_hdr_t, dst_addr[0])) + +/* IPv6 header field access macros */ + +#define IPV6_HDR_VERSION_M 0xF0000000 +#define IPV6_HDR_VERSION_S 28 + +#define IPV6_HDR_TRAFFIC_CLASS_M 0x0FF00000 +#define IPV6_HDR_TRAFFIC_CLASS_S 20 + +#define IPV6_HDR_FLOW_LABEL_M 0x000FFFFF +#define IPV6_HDR_FLOW_LABEL_S 0 + +static inline A_UINT8 ipv6_version(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_VERSION_M) >> IPV6_HDR_VERSION_S; +} + +static inline A_UINT8 ipv6_traffic_class(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (A_UINT8) ((BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_TRAFFIC_CLASS_M) >> IPV6_HDR_TRAFFIC_CLASS_S); +} + +static inline A_UINT32 ipv6_flow_label(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_FLOW_LABEL_M) >> IPV6_HDR_FLOW_LABEL_S; +} + +#endif /* _IPV6__H_ */ diff --git a/core/dp/txrx/ol_cfg.c b/core/dp/txrx/ol_cfg.c new file mode 100644 index 0000000000..2e6a8e767f --- /dev/null +++ b/core/dp/txrx/ol_cfg.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include + +unsigned int vow_config = 0; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_set_flow_control_parameters() - set flow control parameters + * @cfg_ctx: cfg context + * @cfg_param: cfg parameters + * + * Return: none + */ +static +void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t cfg_param) +{ + cfg_ctx->tx_flow_start_queue_offset = + cfg_param.tx_flow_start_queue_offset; + cfg_ctx->tx_flow_stop_queue_th = + cfg_param.tx_flow_stop_queue_th; +} +#else +static +void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t cfg_param) +{ + return; +} +#endif + +/* FIX THIS - + * For now, all these configuration parameters are hardcoded. + * Many of these should actually be determined dynamically instead. + */ + +ol_pdev_handle ol_pdev_cfg_attach(cdf_device_t osdev, + struct txrx_pdev_cfg_param_t cfg_param) +{ + struct txrx_pdev_cfg_t *cfg_ctx; + + cfg_ctx = cdf_mem_malloc(sizeof(*cfg_ctx)); + if (!cfg_ctx) { + printk(KERN_ERR "cfg ctx allocation failed\n"); + return NULL; + } + + /* + * Need to change HTT_LL_TX_HDR_SIZE_IP accordingly. + * Include payload, up to the end of UDP header for IPv4 case + */ + cfg_ctx->tx_download_size = 16; + /* temporarily diabled PN check for Riva/Pronto */ + cfg_ctx->rx_pn_check = 1; +#if CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK + cfg_ctx->defrag_timeout_check = 1; +#endif + cfg_ctx->max_peer_id = 511; + cfg_ctx->max_vdev = CFG_TGT_NUM_VDEV; + cfg_ctx->pn_rx_fwd_check = 1; + cfg_ctx->frame_type = wlan_frm_fmt_802_3; + cfg_ctx->max_thruput_mbps = 800; + cfg_ctx->max_nbuf_frags = 1; + cfg_ctx->vow_config = vow_config; + cfg_ctx->target_tx_credit = CFG_TGT_NUM_MSDU_DESC; + cfg_ctx->throttle_period_ms = 40; + cfg_ctx->rx_fwd_disabled = 0; + cfg_ctx->is_packet_log_enabled = 0; + cfg_ctx->is_full_reorder_offload = cfg_param.is_full_reorder_offload; + cfg_ctx->ipa_uc_rsc.uc_offload_enabled = + cfg_param.is_uc_offload_enabled; + cfg_ctx->ipa_uc_rsc.tx_max_buf_cnt = cfg_param.uc_tx_buffer_count; + cfg_ctx->ipa_uc_rsc.tx_buf_size = cfg_param.uc_tx_buffer_size; + cfg_ctx->ipa_uc_rsc.rx_ind_ring_size = + cfg_param.uc_rx_indication_ring_count; + cfg_ctx->ipa_uc_rsc.tx_partition_base = cfg_param.uc_tx_partition_base; + cfg_ctx->enable_rxthread = cfg_param.enable_rxthread; + cfg_ctx->ip_tcp_udp_checksum_offload = + cfg_param.ip_tcp_udp_checksum_offload; + cfg_ctx->ce_classify_enabled = cfg_param.ce_classify_enabled; + + ol_tx_set_flow_control_parameters(cfg_ctx, cfg_param); + return (ol_pdev_handle) cfg_ctx; +} + +int ol_cfg_is_high_latency(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_high_latency; +} + +int ol_cfg_max_peer_id(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + /* + * TBDXXX - this value must match the peer table + * size allocated in FW + */ + return cfg->max_peer_id; +} + +int ol_cfg_max_vdevs(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_vdev; +} + +int ol_cfg_rx_pn_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_pn_check; +} + +int ol_cfg_rx_fwd_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->pn_rx_fwd_check; +} + +void ol_set_cfg_rx_fwd_disabled(ol_pdev_handle pdev, uint8_t disable_rx_fwd) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->rx_fwd_disabled = disable_rx_fwd; +} + +void ol_set_cfg_packet_log_enabled(ol_pdev_handle pdev, uint8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->is_packet_log_enabled = val; +} + +uint8_t ol_cfg_is_packet_log_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_packet_log_enabled; +} + +int ol_cfg_rx_fwd_disabled(ol_pdev_handle pdev) +{ +#if defined(ATHR_WIN_NWF) + /* for Windows, let the OS handle the forwarding */ + return 1; +#else + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_fwd_disabled; +#endif +} + +int ol_cfg_rx_fwd_inter_bss(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_fwd_inter_bss; +} + +enum wlan_frm_fmt ol_cfg_frame_type(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->frame_type; +} + +int ol_cfg_max_thruput_mbps(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_thruput_mbps; +} + +int ol_cfg_netbuf_frags_max(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_nbuf_frags; +} + +int ol_cfg_tx_free_at_download(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_free_at_download; +} + +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + uint16_t rc; + uint16_t vow_max_sta = (cfg->vow_config & 0xffff0000) >> 16; + uint16_t vow_max_desc_persta = cfg->vow_config & 0x0000ffff; + + rc = (cfg->target_tx_credit + (vow_max_sta * vow_max_desc_persta)); + + return rc; +} + +int ol_cfg_tx_download_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_download_size; +} + +int ol_cfg_rx_host_defrag_timeout_duplicate_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->defrag_timeout_check; +} + +int ol_cfg_throttle_period_ms(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->throttle_period_ms; +} + +int ol_cfg_is_full_reorder_offload(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_full_reorder_offload; +} + +/** + * ol_cfg_is_rx_thread_enabled() - return rx_thread is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +int ol_cfg_is_rx_thread_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->enable_rxthread; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_cfg_get_tx_flow_stop_queue_th() - return stop queue threshold + * @pdev : handle to the physical device + * + * Return: stop queue threshold + */ +int ol_cfg_get_tx_flow_stop_queue_th(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_flow_stop_queue_th; +} + +/** + * ol_cfg_get_tx_flow_start_queue_offset() - return start queue offset + * @pdev : handle to the physical device + * + * Return: start queue offset + */ +int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_flow_start_queue_offset; +} +#endif + +#ifdef IPA_OFFLOAD +unsigned int ol_cfg_ipa_uc_offload_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return (unsigned int)cfg->ipa_uc_rsc.uc_offload_enabled; +} + +unsigned int ol_cfg_ipa_uc_tx_buf_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_buf_size; +} + +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_max_buf_cnt; +} + +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.rx_ind_ring_size; +} + +unsigned int ol_cfg_ipa_uc_tx_partition_base(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_partition_base; +} +#endif /* IPA_OFFLOAD */ + +/** + * ol_cfg_is_ce_classify_enabled() - Return if CE classification is enabled + * or disabled + * @pdev : handle to the physical device + * + * Return: 1 - enabled, 0 - disabled + */ +bool ol_cfg_is_ce_classify_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ce_classify_enabled; +} diff --git a/core/dp/txrx/ol_ctrl_txrx_api.h b/core/dp/txrx/ol_ctrl_txrx_api.h new file mode 100644 index 0000000000..49a952e273 --- /dev/null +++ b/core/dp/txrx/ol_ctrl_txrx_api.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_ctrl_txrx_api.h + * @brief Define the host control API functions called by the host data SW. + */ +#ifndef _OL_CTRL_TXRX_API__H_ +#define _OL_CTRL_TXRX_API__H_ + +/* #include / * uint8_t * / */ +#include /* uint8_t */ +#include /* cdf_nbuf_t */ + +#include /* ol_vdev_handle */ +#include /* ol_txrx_peer_handle, etc. */ +#include /* ieee80211_frame */ + +enum ol_rx_err_type { + OL_RX_ERR_DEFRAG_MIC, + OL_RX_ERR_PN, + OL_RX_ERR_UNKNOWN_PEER, + OL_RX_ERR_MALFORMED, + OL_RX_ERR_TKIP_MIC, + OL_RX_ERR_DECRYPT, + OL_RX_ERR_MPDU_LENGTH, + OL_RX_ERR_ENCRYPT_REQUIRED, + OL_RX_ERR_DUP, + OL_RX_ERR_UNKNOWN, + OL_RX_ERR_FCS, + OL_RX_ERR_PRIVACY, + OL_RX_ERR_NONE_FRAG, + OL_RX_ERR_NONE = 0xFF +}; + +#ifdef SUPPORT_HOST_STATISTICS +/** * @brief Update tx statistics + * @details + * Update tx statistics after tx complete. + * + * @param pdev - ol_pdev_handle instance + * @param vdev_id - ID of the virtual device that tx frame + * @param had_error - whether there is error when tx + */ +void ol_tx_statistics(ol_pdev_handle pdev, uint16_t vdev_id, int had_error); +#else +#define ol_tx_statistics(pdev, vdev_id, had_error) +#endif + +/** * @brief Count on received packets for invalid peer case + * + * @param pdev - txrx pdev handle + * @param wh - received frame + * @param err_type - what kind of error occurred + */ +void ol_rx_err_inv_peer_statistics(ol_pdev_handle pdev, + struct ieee80211_frame *wh, + enum ol_rx_err_type err_type); + +/** + * @brief Count on received packets, both success and failed + * + * @param pdev - ol_pdev_handle handle + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param err_type - what kind of error occurred + * @param sec_type - The cipher type the peer is using + * @param is_mcast - whether this is one multi cast frame + */ +void ol_rx_err_statistics(ol_pdev_handle pdev, + uint8_t vdev_id, + enum ol_rx_err_type err_type, + enum ol_sec_type sec_type, int is_mcast); + +/** + * @brief Provide notification of failure during host rx processing + * @details + * Indicate an error during host rx data processing, including what + * kind of error happened, when it happened, which peer and TID the + * erroneous rx frame is from, and what the erroneous rx frame itself + * is. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param peer_mac_addr - MAC address of the peer that sent the erroneous + * rx frame + * @param tid - which TID within the peer sent the erroneous rx frame + * @param tsf32 - the timstamp in TSF units of the erroneous rx frame, or + * one of the fragments that when reassembled, constitute the rx frame + * @param err_type - what kind of error occurred + * @param rx_frame - the rx frame that had an error + * @pn - Packet sequence number + * @key_id - Key index octet received in IV of the frame + */ +void +ol_rx_err(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_err_type err_type, + cdf_nbuf_t rx_frame, uint64_t *pn, uint8_t key_id); + +enum ol_rx_notify_type { + OL_RX_NOTIFY_IPV4_IGMP, +}; + +/** + * @brief Provide notification of reception of data of special interest. + * @details + * Indicate when "special" data has been received. The nature of the + * data that results in it being considered special is specified in the + * notify_type argument. + * This function is currently used by the data-path SW to notify the + * control path SW when the following types of rx data are received: + * + IPv4 IGMP frames + * The control SW can use these to learn about multicast group + * membership, if it so chooses. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the special data + * @param peer_mac_addr - MAC address of the peer that sent the special data + * @param tid - which TID within the peer sent the special data + * @param tsf32 - the timstamp in TSF units of the special data + * @param notify_type - what kind of special data was received + * @param rx_frame - the rx frame containing the special data + */ +void +ol_rx_notify(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, cdf_nbuf_t rx_frame); + +/** + * @brief Indicate when a paused STA has tx data available. + * @details + * Indicate to the control SW when a paused peer that previously + * has all its peer-TID queues empty gets a MSDU to transmit. + * Conversely, indicate when a paused peer that had data in one or more of + * its peer-TID queues has all queued data removed (e.g. due to a U-APSD + * triggered transmission), but is still paused. + * It is up to the control SW to determine whether the peer is paused due to + * being in power-save sleep, or some other reason, and thus whether it is + * necessary to set the TIM in beacons to notify a sleeping STA that it has + * data. + * The data SW will also issue this ol_tx_paused_peer_data call when an + * unpaused peer that currently has tx data in one or more of its + * peer-TID queues becomes paused. + * The data SW will not issue this ol_tx_paused_peer_data call when a + * peer with data in one or more of its peer-TID queues becomes unpaused. + * + * @param peer - the paused peer + * @param has_tx_data - + * 1 -> a paused peer that previously had no tx data now does, -OR- + * 0 -> a paused peer that previously had tx data now doesnt + */ +void ol_tx_paused_peer_data(ol_peer_handle peer, int has_tx_data); + +#define ol_ctrl_addba_req(pdev, peer_mac_addr, tid) ol_addba_req_reject +#define ol_ctrl_rx_addba_complete(pdev, peer_mac_addr, tid, failed) /* no-op */ + +void ol_txrx_set_peer_authorized_event(struct ol_txrx_vdev_t *vdev); + + +#endif /* _OL_CTRL_TXRX_API__H_ */ diff --git a/core/dp/txrx/ol_osif_txrx_api.h b/core/dp/txrx/ol_osif_txrx_api.h new file mode 100644 index 0000000000..b47a0b6cdb --- /dev/null +++ b/core/dp/txrx/ol_osif_txrx_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_osif_txrx_api.h + * @brief Define the OS specific API functions called by txrx SW. + */ +#ifndef _OL_OSIF_TXRX_API_H_ +#define _OL_OSIF_TXRX_API_H_ + +#include /* cdf_nbuf_t */ + +/** + * @brief Call tx completion handler to release the buffers + * @details + * + * Invoke tx completion handler when the tx credit goes below low water mark. + * This eliminate the packet drop in the host driver due to send routine not + * yielding the cpu when the amount of traffic pumped from the network layer + * is very high. + * + * @param osdev + */ + +void ol_osif_ath_tasklet(cdf_device_t osdev); + +#endif /* _OL_OSIF_TXRX_API_H_ */ diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c new file mode 100644 index 0000000000..7d007aaab8 --- /dev/null +++ b/core/dp/txrx/ol_rx.c @@ -0,0 +1,1493 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_os_cpu_to_le64 */ +#include /* bool */ +#include /* ieee80211_frame */ + +/* external API header files */ +#include /* ol_rx_notify */ +#include /* htt_pdev_handle */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_indication_handler */ +#include /* htt_rx_peer_id, etc. */ + +/* internal API header files */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* ol_txrx_peer_find_by_id */ +#include /* ol_rx_reorder_store, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_UPDATE */ +#include /* ol_rx_defrag_waitlist_flush */ +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* ol_rx_decap_info_t, etc */ +#endif + +/* FIX THIS: txrx should not include private header files of other modules */ +#include +#include +#include /* ethernet + SNAP/LLC header defs and + ethertype values */ +#include /* IP protocol values */ +#include /* IPv4 header defs */ +#include /* IPv6 header defs */ +#include +#include +#include + +#ifdef HTT_RX_RESTORE +#if defined(CONFIG_CNSS) +#include +#endif +#endif + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + cdf_nbuf_t rx_buf_list); + + +#ifdef HTT_RX_RESTORE + +static void ol_rx_restore_handler(struct work_struct *htt_rx) +{ + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "Enter: %s", __func__); + cnss_device_self_recovery(); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "Exit: %s", __func__); +} + +static DECLARE_WORK(ol_rx_restore_work, ol_rx_restore_handler); + +void ol_rx_trigger_restore(htt_pdev_handle htt_pdev, cdf_nbuf_t head_msdu, + cdf_nbuf_t tail_msdu) +{ + cdf_nbuf_t next; + + while (head_msdu) { + next = cdf_nbuf_next(head_msdu); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "freeing %p\n", head_msdu); + cdf_nbuf_free(head_msdu); + head_msdu = next; + } + + if (!htt_pdev->rx_ring.htt_rx_restore) { + cds_set_logp_in_progress(true); + htt_pdev->rx_ring.htt_rx_restore = 1; + schedule_work(&ol_rx_restore_work); + } +} +#endif + +static void ol_rx_process_inv_peer(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, cdf_nbuf_t msdu) +{ + uint8_t a1[IEEE80211_ADDR_LEN]; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + struct ol_txrx_vdev_t *vdev = NULL; + struct ieee80211_frame *wh; + struct wdi_event_rx_peer_invalid_msg msg; + + wh = (struct ieee80211_frame *) + htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev, rx_mpdu_desc); + /* + * Klocwork issue #6152 + * All targets that send a "INVALID_PEER" rx status provide a + * 802.11 header for each rx MPDU, so it is certain that + * htt_rx_mpdu_wifi_hdr_retrieve will succeed. + * However, both for robustness, e.g. if this function is given a + * MSDU descriptor rather than a MPDU descriptor, and to make it + * clear to static analysis that this code is safe, add an explicit + * check that htt_rx_mpdu_wifi_hdr_retrieve provides a non-NULL value. + */ + if (wh == NULL || !IEEE80211_IS_DATA(wh)) + return; + + /* ignore frames for non-existent bssids */ + cdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (cdf_mem_compare(a1, vdev->mac_addr.raw, IEEE80211_ADDR_LEN) + == 0) { + break; + } + } + if (!vdev) + return; + + msg.wh = wh; + msg.msdu = msdu; + msg.vdev_id = vdev->vdev_id; +#ifdef WDI_EVENT_ENABLE + wdi_event_handler(WDI_EVENT_RX_PEER_INVALID, pdev, &msg); +#endif +} + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +static inline int16_t +ol_rx_rssi_avg(struct ol_txrx_pdev_t *pdev, int16_t rssi_old, int16_t rssi_new) +{ + int rssi_old_weight; + + if (rssi_new == HTT_RSSI_INVALID) + return rssi_old; + if (rssi_old == HTT_RSSI_INVALID) + return rssi_new; + + rssi_old_weight = + (1 << pdev->rssi_update_shift) - pdev->rssi_new_weight; + return (rssi_new * pdev->rssi_new_weight + + rssi_old * rssi_old_weight) >> pdev->rssi_update_shift; +} + +static void +ol_rx_ind_rssi_update(struct ol_txrx_peer_t *peer, cdf_nbuf_t rx_ind_msg) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_ind_rssi_dbm(pdev->htt_pdev, + rx_ind_msg)); +} + +static void +ol_rx_mpdu_rssi_update(struct ol_txrx_peer_t *peer, void *rx_mpdu_desc) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + if (!peer) + return; + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_mpdu_desc_rssi_dbm( + pdev->htt_pdev, + rx_mpdu_desc)); +} + +#else +#define ol_rx_ind_rssi_update(peer, rx_ind_msg) /* no-op */ +#define ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc) /* no-op */ +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +void discard_msdus(htt_pdev_handle htt_pdev, + cdf_nbuf_t head_msdu, + cdf_nbuf_t tail_msdu) +{ + while (1) { + cdf_nbuf_t next; + next = cdf_nbuf_next( + head_msdu); + htt_rx_desc_frame_free + (htt_pdev, + head_msdu); + if (head_msdu == + tail_msdu) { + break; + } + head_msdu = next; + } + return; +} + +void chain_msdus(htt_pdev_handle htt_pdev, + cdf_nbuf_t head_msdu, + cdf_nbuf_t tail_msdu) +{ + while (1) { + cdf_nbuf_t next; + next = cdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free( + htt_pdev, + head_msdu); + if (head_msdu == tail_msdu) + break; + head_msdu = next; + } + return; +} + +void process_reorder(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, + uint8_t tid, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t head_msdu, + cdf_nbuf_t tail_msdu, + int num_mpdu_ranges, + int num_pdus, + bool rx_ind_release + ) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + enum htt_rx_status mpdu_status; + int reorder_idx; + reorder_idx = htt_rx_mpdu_desc_reorder_idx(htt_pdev, rx_mpdu_desc); + OL_RX_REORDER_TRACE_ADD(pdev, tid, + reorder_idx, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_mpdu_desc), + 1); + ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc); + /* + * In most cases, out-of-bounds and duplicate sequence number detection + * is performed by the target, but in some cases it is done by the host. + * Specifically, the host does rx out-of-bounds sequence number + * detection for: + * 1. Peregrine or Rome target + * for peer-TIDs that do not have aggregation enabled, if the + * RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK flag + * is set during the driver build. + * 2. Riva-family targets, which have rx reorder timeouts handled by + * the host rather than the target. + * (The target already does duplicate detection, but the host + * may have given up waiting for a particular sequence number before + * it arrives. In this case, the out-of-bounds sequence number + * of the late frame allows the host to discard it, rather than + * sending it out of order. + */ + mpdu_status = OL_RX_SEQ_NUM_CHECK(pdev, + peer, + tid, + rx_mpdu_desc); + if (mpdu_status != htt_rx_status_ok) { + /* + * If the sequence number was out of bounds, the MPDU needs + * to be discarded. + */ + discard_msdus(htt_pdev, head_msdu, tail_msdu); + /* + * For Peregrine and Rome, + * OL_RX_REORDER_SEQ_NUM_CHECK should only fail for the case + * of (duplicate) non-aggregates. + * + * For Riva, Pronto and Northstar, + * there should be only one MPDU delivered at a time. + * Thus, there are no further MPDUs that need to be + * processed here. + * Just to be sure this is true, check the assumption + * that this was the only MPDU referenced by the rx + * indication. + */ + TXRX_ASSERT2((num_mpdu_ranges == 1) && num_mpdus == 1); + + /* + * The MPDU was not stored in the rx reorder array, so + * there's nothing to release. + */ + rx_ind_release = false; + } else { + ol_rx_reorder_store(pdev, peer, tid, + reorder_idx, head_msdu, tail_msdu); + if (peer->tids_rx_reorder[tid].win_sz_mask == 0) { + peer->tids_last_seq[tid] = htt_rx_mpdu_desc_seq_num( + htt_pdev, + rx_mpdu_desc); + } + } + return; +} /* process_reorder */ + +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges) +{ + int mpdu_range, i; + unsigned seq_num_start = 0, seq_num_end = 0; + bool rx_ind_release = false; + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + uint16_t center_freq; + uint16_t chan1; + uint16_t chan2; + uint8_t phymode; + bool ret; + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) { + vdev = peer->vdev; + ol_rx_ind_rssi_update(peer, rx_ind_msg); + + if (vdev->opmode == wlan_op_mode_ocb) { + htt_rx_ind_legacy_rate(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_legacy_rate, + &peer->last_pkt_legacy_rate_sel); + peer->last_pkt_rssi_cmb = htt_rx_ind_rssi_dbm( + pdev->htt_pdev, rx_ind_msg); + for (i = 0; i < 4; i++) + peer->last_pkt_rssi[i] = + htt_rx_ind_rssi_dbm_chain( + pdev->htt_pdev, rx_ind_msg, i); + htt_rx_ind_timestamp(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_timestamp_microsec, + &peer->last_pkt_timestamp_submicrosec); + peer->last_pkt_tsf = htt_rx_ind_tsf32(pdev->htt_pdev, + rx_ind_msg); + peer->last_pkt_tid = htt_rx_ind_ext_tid(pdev->htt_pdev, + rx_ind_msg); + } + } + + TXRX_STATS_INCR(pdev, priv.rx.normal.ppdus); + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + if (htt_rx_ind_flush(pdev->htt_pdev, rx_ind_msg) && peer) { + htt_rx_ind_flush_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + if (tid == HTT_INVALID_TID) { + /* + * host/FW reorder state went out-of sync + * for a while because FW ran out of Rx indication + * buffer. We have to discard all the buffers in + * reorder queue. + */ + ol_rx_reorder_peer_cleanup(vdev, peer); + } else { + ol_rx_reorder_flush(vdev, peer, tid, seq_num_start, + seq_num_end, htt_rx_flush_release); + } + } + + if (htt_rx_ind_release(pdev->htt_pdev, rx_ind_msg)) { + /* the ind info of release is saved here and do release at the + * end. This is for the reason of in HL case, the cdf_nbuf_t + * for msg and payload are the same buf. And the buf will be + * changed during processing */ + rx_ind_release = true; + htt_rx_ind_release_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + } +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_initial_msdu_payld = + pdev->htt_pdev->rx_ring.sw_rd_idx.msdu_payld; +#endif + + for (mpdu_range = 0; mpdu_range < num_mpdu_ranges; mpdu_range++) { + enum htt_rx_status status; + int i, num_mpdus; + cdf_nbuf_t head_msdu, tail_msdu, msdu; + void *rx_mpdu_desc; + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_range = mpdu_range; +#endif + + htt_rx_ind_mpdu_range_info(pdev->htt_pdev, rx_ind_msg, + mpdu_range, &status, &num_mpdus); + if ((status == htt_rx_status_ok) && peer) { + TXRX_STATS_ADD(pdev, priv.rx.normal.mpdus, num_mpdus); + /* valid frame - deposit it into rx reordering buffer */ + for (i = 0; i < num_mpdus; i++) { + int msdu_chaining; + /* + * Get a linked list of the MSDUs that comprise + * this MPDU. + * This also attaches each rx MSDU descriptor to + * the corresponding rx MSDU network buffer. + * (In some systems, the rx MSDU desc is already + * in the same buffer as the MSDU payload; in + * other systems they are separate, so a pointer + * needs to be set in the netbuf to locate the + * corresponding rx descriptor.) + * + * It is neccessary to call htt_rx_amsdu_pop + * before htt_rx_mpdu_desc_list_next, because + * the (MPDU) rx descriptor has DMA unmapping + * done during the htt_rx_amsdu_pop call. + * The rx desc should not be accessed until this + * DMA unmapping has been done, since the DMA + * unmapping involves making sure the cache area + * for the mapped buffer is flushed, so the data + * written by the MAC DMA into memory will be + * fetched, rather than garbage from the cache. + */ + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_count = i; +#endif + + msdu_chaining = + htt_rx_amsdu_pop(htt_pdev, + rx_ind_msg, + &head_msdu, + &tail_msdu); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, + head_msdu, + tail_msdu); + return; + } +#endif + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + ret = htt_rx_msdu_center_freq(htt_pdev, peer, + rx_mpdu_desc, ¢er_freq, &chan1, + &chan2, &phymode); + if (ret == true) { + peer->last_pkt_center_freq = + center_freq; + } else { + peer->last_pkt_center_freq = 0; + } + + /* Pktlog */ +#ifdef WDI_EVENT_ENABLE + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, + pdev, head_msdu); +#endif + + if (msdu_chaining) { + /* + * TBDXXX - to deliver SDU with + * chaining, we need to stitch those + * scattered buffers into one single + * buffer. + * Just discard it now. + */ + chain_msdus(htt_pdev, + head_msdu, + tail_msdu); + } else { + process_reorder(pdev, rx_mpdu_desc, + tid, peer, + head_msdu, tail_msdu, + num_mpdu_ranges, + num_mpdus, + rx_ind_release); + } + + } + } else { + /* invalid frames - discard them */ + OL_RX_REORDER_TRACE_ADD(pdev, tid, + TXRX_SEQ_NUM_ERR(status), + TXRX_SEQ_NUM_ERR(status), + num_mpdus); + TXRX_STATS_ADD(pdev, priv.rx.err.mpdu_bad, num_mpdus); + for (i = 0; i < num_mpdus; i++) { + /* pull the MPDU's MSDUs off the buffer queue */ + htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &msdu, + &tail_msdu); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, msdu, + tail_msdu); + return; + } +#endif + /* pull the MPDU desc off the desc queue */ + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, + rx_mpdu_desc, msdu, + status); + + if (status == htt_rx_status_tkip_mic_err && + vdev != NULL && peer != NULL) { + union htt_rx_pn_t pn; + uint8_t key_id; + htt_rx_mpdu_desc_pn( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), &pn, 48); + if (htt_rx_msdu_desc_key_id( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), + &key_id) == true) { + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, 0, + OL_RX_ERR_TKIP_MIC, + msdu, &pn.pn48, + key_id); + } + } +#ifdef WDI_EVENT_ENABLE + if (status != htt_rx_status_ctrl_mgmt_null) { + /* Pktlog */ + wdi_event_handler( + WDI_EVENT_RX_DESC_REMOTE, pdev, + msdu); + } +#endif + if (status == htt_rx_status_err_inv_peer) { + /* once per mpdu */ + ol_rx_process_inv_peer(pdev, + rx_mpdu_desc, + msdu); + } + while (1) { + /* Free the nbuf */ + cdf_nbuf_t next; + next = cdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == tail_msdu) + break; + msdu = next; + } + } + } + } + /* + * Now that a whole batch of MSDUs have been pulled out of HTT + * and put into the rx reorder array, it is an appropriate time + * to request HTT to provide new rx MSDU buffers for the target + * to fill. + * This could be done after the end of this function, but it's + * better to do it now, rather than waiting until after the driver + * and OS finish processing the batch of rx MSDUs. + */ + htt_rx_msdu_buff_replenish(htt_pdev); + + if ((true == rx_ind_release) && peer && vdev) { + ol_rx_reorder_release(vdev, peer, tid, seq_num_start, + seq_num_end); + } + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_flush(pdev); +} + +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn) +{ + struct ol_txrx_peer_t *peer; + int sec_index, i; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Couldn't find peer from ID %d - skipping security inits\n", + peer_id); + return; + } + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "sec spec for peer %p (%02x:%02x:%02x:%02x:%02x:%02x): " + "%s key of type %d\n", + peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + is_unicast ? "ucast" : "mcast", sec_type); + sec_index = is_unicast ? txrx_sec_ucast : txrx_sec_mcast; + peer->security[sec_index].sec_type = sec_type; + /* michael key only valid for TKIP + but for simplicity, copy it anyway */ + cdf_mem_copy(&peer->security[sec_index].michael_key[0], + michael_key, + sizeof(peer->security[sec_index].michael_key)); + + if (sec_type != htt_sec_type_wapi) { + cdf_mem_set(peer->tids_last_pn_valid, + OL_TXRX_NUM_EXT_TIDS, 0x00); + } else if (sec_index == txrx_sec_mcast || peer->tids_last_pn_valid[0]) { + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + /* + * Setting PN valid bit for WAPI sec_type, + * since WAPI PN has to be started with predefined value + */ + peer->tids_last_pn_valid[i] = 1; + cdf_mem_copy((uint8_t *) &peer->tids_last_pn[i], + (uint8_t *) rx_pn, + sizeof(union htt_rx_pn_t)); + peer->tids_last_pn[i].pn128[1] = + cdf_os_cpu_to_le64( + peer->tids_last_pn[i].pn128[1]); + peer->tids_last_pn[i].pn128[0] = + cdf_os_cpu_to_le64( + peer->tids_last_pn[i].pn128[0]); + } + } +} + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + +#include + +static void transcap_nwifi_to_8023(cdf_nbuf_t msdu) +{ + struct ieee80211_frame *wh; + uint32_t hdrsize; + struct llc *llchdr; + struct ether_header *eth_hdr; + uint16_t ether_type = 0; + uint8_t a1[IEEE80211_ADDR_LEN]; + uint8_t a2[IEEE80211_ADDR_LEN]; + uint8_t a3[IEEE80211_ADDR_LEN]; + uint8_t fc1; + + wh = (struct ieee80211_frame *)cdf_nbuf_data(msdu); + cdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + cdf_mem_copy(a2, wh->i_addr2, IEEE80211_ADDR_LEN); + cdf_mem_copy(a3, wh->i_addr3, IEEE80211_ADDR_LEN); + fc1 = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + /* Native Wifi header is 80211 non-QoS header */ + hdrsize = sizeof(struct ieee80211_frame); + + llchdr = (struct llc *)(((uint8_t *) cdf_nbuf_data(msdu)) + hdrsize); + ether_type = llchdr->llc_un.type_snap.ether_type; + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + cdf_nbuf_pull_head(msdu, + (hdrsize + sizeof(struct llc) - + sizeof(struct ether_header))); + eth_hdr = (struct ether_header *)(cdf_nbuf_data(msdu)); + switch (fc1) { + case IEEE80211_FC1_DIR_NODS: + cdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + cdf_mem_copy(eth_hdr->ether_dhost, a3, IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + cdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->ether_shost, a3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + eth_hdr->ether_type = ether_type; +} +#endif + +void ol_rx_notify(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, cdf_nbuf_t rx_frame) +{ + /* + * NOTE: This is used in qca_main for AP mode to handle IGMP + * packets specially. Umac has a corresponding handler for this + * not sure if we need to have this for CLD as well. + */ +} + +/** + * @brief Look into a rx MSDU to see what kind of special handling it requires + * @details + * This function is called when the host rx SW sees that the target + * rx FW has marked a rx MSDU as needing inspection. + * Based on the results of the inspection, the host rx SW will infer + * what special handling to perform on the rx frame. + * Currently, the only type of frames that require special handling + * are IGMP frames. The rx data-path SW checks if the frame is IGMP + * (it should be, since the target would not have set the inspect flag + * otherwise), and then calls the ol_rx_notify function so the + * control-path SW can perform multicast group membership learning + * by sniffing the IGMP frame. + */ +#define SIZEOF_80211_HDR (sizeof(struct ieee80211_frame)) +void +ol_rx_inspect(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu, void *rx_desc) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + uint8_t *data, *l3_hdr; + uint16_t ethertype; + int offset; + + data = cdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + l3_hdr = data + SIZEOF_80211_HDR + LLC_SNAP_HDR_LEN; + } else { + offset = ETHERNET_ADDR_LEN * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + } + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if (l3_hdr[offset] == IP_PROTOCOL_IGMP) { + ol_rx_notify(pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), + OL_RX_NOTIFY_IPV4_IGMP, msdu); + } + } +} + +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t msg, int msdu_cnt) +{ + int vdev_id, peer_id, tid; + cdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + while (msdu_cnt) { + htt_rx_offload_msdu_pop(htt_pdev, msg, &vdev_id, &peer_id, + &tid, &fw_desc, &head_buf, &tail_buf); + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + cdf_nbuf_t next; + next = cdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + msdu_cnt--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + cdf_nbuf_t msdu) +{ + union htt_rx_pn_t pn = {0}; + u_int8_t key_id = 0; + + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_vdev_t *vdev = NULL; + + if (pdev) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + vdev = peer->vdev; + if (vdev) { + htt_rx_mpdu_desc_pn(vdev->pdev->htt_pdev, + msdu_desc, &pn, 48); + + if (htt_rx_msdu_desc_key_id( + vdev->pdev->htt_pdev, msdu_desc, + &key_id) == true) { + ol_rx_err(vdev->pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, tid, 0, + OL_RX_ERR_TKIP_MIC, msdu, + &pn.pn48, key_id); + } + } + } + } +} + +/** + * @brief Check the first msdu to decide whether the a-msdu should be accepted. + */ +bool +ol_rx_filter(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, cdf_nbuf_t msdu, void *rx_desc) +{ +#define FILTER_STATUS_REJECT 1 +#define FILTER_STATUS_ACCEPT 0 + uint8_t *wh; + uint32_t offset = 0; + uint16_t ether_type = 0; + bool is_encrypted = false, is_mcast = false; + uint8_t i; + enum privacy_filter_packet_type packet_type = + PRIVACY_FILTER_PACKET_UNICAST; + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + int sec_idx; + + /* + * Safemode must avoid the PrivacyExemptionList and + * ExcludeUnencrypted checking + */ + if (vdev->safemode) + return FILTER_STATUS_ACCEPT; + + is_mcast = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc); + if (vdev->num_filters > 0) { + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + } else { + offset = ETHERNET_ADDR_LEN * 2; + } + /* get header info from msdu */ + wh = cdf_nbuf_data(msdu); + + /* get ether type */ + ether_type = (wh[offset] << 8) | wh[offset + 1]; + /* get packet type */ + if (true == is_mcast) + packet_type = PRIVACY_FILTER_PACKET_MULTICAST; + else + packet_type = PRIVACY_FILTER_PACKET_UNICAST; + } + /* get encrypt info */ + is_encrypted = htt_rx_mpdu_is_encrypted(htt_pdev, rx_desc); +#ifdef ATH_SUPPORT_WAPI + if ((true == is_encrypted) && (ETHERTYPE_WAI == ether_type)) { + /* We expect the WAI frames to be always unencrypted when + the UMAC gets it.*/ + return FILTER_STATUS_REJECT; + } +#endif /* ATH_SUPPORT_WAPI */ + + for (i = 0; i < vdev->num_filters; i++) { + enum privacy_filter filter_type; + enum privacy_filter_packet_type filter_packet_type; + + /* skip if the ether type does not match */ + if (vdev->privacy_filters[i].ether_type != ether_type) + continue; + + /* skip if the packet type does not match */ + filter_packet_type = vdev->privacy_filters[i].packet_type; + if (filter_packet_type != packet_type && + filter_packet_type != PRIVACY_FILTER_PACKET_BOTH) { + continue; + } + + filter_type = vdev->privacy_filters[i].filter_type; + if (filter_type == PRIVACY_FILTER_ALWAYS) { + /* + * In this case, we accept the frame if and only if + * it was originally NOT encrypted. + */ + if (true == is_encrypted) + return FILTER_STATUS_REJECT; + else + return FILTER_STATUS_ACCEPT; + + } else if (filter_type == PRIVACY_FILTER_KEY_UNAVAILABLE) { + /* + * In this case, we reject the frame if it was + * originally NOT encrypted but we have the key mapping + * key for this frame. + */ + if (!is_encrypted && + !is_mcast && + (peer->security[txrx_sec_ucast].sec_type != + htt_sec_type_none) && + (peer->keyinstalled || !ETHERTYPE_IS_EAPOL_WAPI( + ether_type))) { + return FILTER_STATUS_REJECT; + } else { + return FILTER_STATUS_ACCEPT; + } + } else { + /* + * The privacy exemption does not apply to this frame. + */ + break; + } + } + + /* + * If the privacy exemption list does not apply to the frame, + * check ExcludeUnencrypted. + * If ExcludeUnencrypted is not set, or if this was oringially + * an encrypted frame, it will be accepted. + */ + if (!vdev->drop_unenc || (true == is_encrypted)) + return FILTER_STATUS_ACCEPT; + + /* + * If this is a open connection, it will be accepted. + */ + sec_idx = (true == is_mcast) ? txrx_sec_mcast : txrx_sec_ucast; + if (peer->security[sec_idx].sec_type == htt_sec_type_none) + return FILTER_STATUS_ACCEPT; + + if ((false == is_encrypted) && vdev->drop_unenc) { + OL_RX_ERR_STATISTICS(pdev, vdev, OL_RX_ERR_PRIVACY, + pdev->sec_types[htt_sec_type_none], + is_mcast); + } + return FILTER_STATUS_REJECT; +} + +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + cdf_nbuf_t deliver_list_head = NULL; + cdf_nbuf_t deliver_list_tail = NULL; + cdf_nbuf_t msdu; + bool filter = false; +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + struct ol_rx_decap_info_t info; + cdf_mem_set(&info, sizeof(info), 0); +#endif + + msdu = msdu_list; + /* + * Check each MSDU to see whether it requires special handling, + * and free each MSDU's rx descriptor + */ + while (msdu) { + void *rx_desc; + int discard, inspect, dummy_fwd; + cdf_nbuf_t next = cdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + info.is_msdu_cmpl_mpdu = + htt_rx_msdu_desc_completes_mpdu(htt_pdev, rx_desc); + info.is_first_subfrm = + htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc); + if (OL_RX_DECAP(vdev, peer, msdu, &info) != A_OK) { + discard = 1; + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "decap error %p from peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x) len %d\n", + msdu, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + cdf_nbuf_len(msdu)); + goto DONE; + } +#endif + htt_rx_msdu_actions(pdev->htt_pdev, rx_desc, &discard, + &dummy_fwd, &inspect); + if (inspect) + ol_rx_inspect(vdev, peer, tid, msdu, rx_desc); + + /* + * Check the first msdu in the mpdu, if it will be filtered out, + * then discard the entire mpdu. + */ + if (htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc)) + filter = ol_rx_filter(vdev, peer, msdu, rx_desc); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +DONE: +#endif + htt_rx_msdu_desc_free(htt_pdev, msdu); + if (discard || (true == filter)) { + ol_txrx_frms_dump("rx discarding:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | + ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + cdf_nbuf_free(msdu); + /* If discarding packet is last packet of the delivery + list, NULL terminator should be added + for delivery list. */ + if (next == NULL && deliver_list_head) { + /* add NULL terminator */ + cdf_nbuf_set_next(deliver_list_tail, NULL); + } + } else { + /* + * If this is for OCB, + * then prepend the RX stats header. + */ + if (vdev->opmode == wlan_op_mode_ocb) { + int i; + struct ol_txrx_ocb_chan_info *chan_info = 0; + int packet_freq = peer->last_pkt_center_freq; + for (i = 0; i < vdev->ocb_channel_count; i++) { + if (vdev->ocb_channel_info[i]. + chan_freq == packet_freq) { + chan_info = &vdev-> + ocb_channel_info[i]; + break; + } + } + if (!chan_info || !chan_info-> + disable_rx_stats_hdr) { + struct ether_header eth_header = { + {0} }; + struct ocb_rx_stats_hdr_t rx_header = { + 0}; + + /* + * Construct the RX stats header and + * push that to the frontof the packet. + */ + rx_header.version = 1; + rx_header.length = sizeof(rx_header); + rx_header.channel_freq = + peer->last_pkt_center_freq; + rx_header.rssi_cmb = + peer->last_pkt_rssi_cmb; + cdf_mem_copy(rx_header.rssi, + peer->last_pkt_rssi, + sizeof(rx_header.rssi)); + if (peer->last_pkt_legacy_rate_sel == + 0) { + switch (peer-> + last_pkt_legacy_rate) { + case 0x8: + rx_header.datarate = 6; + break; + case 0x9: + rx_header.datarate = 4; + break; + case 0xA: + rx_header.datarate = 2; + break; + case 0xB: + rx_header.datarate = 0; + break; + case 0xC: + rx_header.datarate = 7; + break; + case 0xD: + rx_header.datarate = 5; + break; + case 0xE: + rx_header.datarate = 3; + break; + case 0xF: + rx_header.datarate = 1; + break; + default: + rx_header.datarate = + 0xFF; + break; + } + } else { + rx_header.datarate = 0xFF; + } + + rx_header.timestamp_microsec = peer-> + last_pkt_timestamp_microsec; + rx_header.timestamp_submicrosec = peer-> + last_pkt_timestamp_submicrosec; + rx_header.tsf32 = peer->last_pkt_tsf; + rx_header.ext_tid = peer->last_pkt_tid; + + cdf_nbuf_push_head(msdu, + sizeof(rx_header)); + cdf_mem_copy(cdf_nbuf_data(msdu), + &rx_header, sizeof(rx_header)); + + /* Construct the ethernet header with + type 0x8152 and push that to the + front of the packet to indicate the + RX stats header. */ + eth_header.ether_type = CDF_SWAP_U16( + ETHERTYPE_OCB_RX); + cdf_nbuf_push_head(msdu, + sizeof(eth_header)); + cdf_mem_copy(cdf_nbuf_data(msdu), + ð_header, + sizeof(eth_header)); + } + } + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + } + msdu = next; + } + /* sanity check - are there any frames left to give to the OS shim? */ + if (!deliver_list_head) + return; + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + if (pdev->host_80211_enable) + for (msdu = deliver_list_head; msdu; msdu = cdf_nbuf_next(msdu)) + transcap_nwifi_to_8023(msdu); +#endif + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, deliver_list_head); +} + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + while (msdu_list) { + cdf_nbuf_t msdu = msdu_list; + + msdu_list = cdf_nbuf_next(msdu_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "discard rx %p from partly-deleted peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n", + msdu, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + htt_rx_desc_frame_free(htt_pdev, msdu); + } +} + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer) +{ + uint8_t tid; + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_init(&peer->tids_rx_reorder[tid], tid); + + /* invalid sequence number */ + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; + } + /* + * Set security defaults: no PN check, no security. + * The target may send a HTT SEC_IND message to overwrite + * these defaults. + */ + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = htt_sec_type_none; + peer->keyinstalled = 0; + cdf_atomic_init(&peer->fw_pn_check); +} + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer) +{ + peer->keyinstalled = 0; + ol_rx_reorder_peer_cleanup(vdev, peer); +} + +/* + * Free frames including both rx descriptors and buffers + */ +void ol_rx_frames_free(htt_pdev_handle htt_pdev, cdf_nbuf_t frames) +{ + cdf_nbuf_t next, frag = frames; + + while (frag) { + next = cdf_nbuf_next(frag); + htt_rx_desc_frame_free(htt_pdev, frag); + frag = next; + } +} + +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + htt_pdev_handle htt_pdev = NULL; + int status; + cdf_nbuf_t head_msdu, tail_msdu = NULL; + + if (pdev) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + htt_pdev = pdev->htt_pdev; + } else { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Invalid pdev passed!\n", __func__); + cdf_assert_always(pdev); + return; + } + +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s %d: rx_ind_msg 0x%p peer_id %d tid %d is_offload %d\n", + __func__, __LINE__, rx_ind_msg, peer_id, tid, is_offload); +#endif + + /* + * Get a linked list of the MSDUs in the rx in order indication. + * This also attaches each rx MSDU descriptor to the + * corresponding rx MSDU network buffer. + */ + status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu, &tail_msdu); + if (cdf_unlikely(0 == status)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: Pop status is 0, returning here\n", __func__); + return; + } + + /* Replenish the rx buffer ring first to provide buffers to the target + rather than waiting for the indeterminate time taken by the OS + to consume the rx frames */ + htt_rx_msdu_buff_replenish(htt_pdev); + + /* Send the chain of MSDUs to the OS */ + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + cdf_nbuf_set_next(tail_msdu, NULL); + + /* Pktlog */ +#ifdef WDI_EVENT_ENABLE + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, pdev, head_msdu); +#endif + + /* if this is an offload indication, peer id is carried in the + rx buffer */ + if (peer) { + vdev = peer->vdev; + } else { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: Couldn't find peer from ID 0x%x\n", + __func__, peer_id); + while (head_msdu) { + cdf_nbuf_t msdu = head_msdu; + head_msdu = cdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + } + return; + } + + peer->rx_opt_proc(vdev, peer, tid, head_msdu); +} + +/* the msdu_list passed here must be NULL terminated */ +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu; + + msdu = msdu_list; + /* + * Currently, this does not check each MSDU to see whether it requires + * special handling. MSDUs that need special handling (example: IGMP + * frames) should be sent via a seperate HTT message. Also, this does + * not do rx->tx forwarding or filtering. + */ + + while (msdu) { + cdf_nbuf_t next = cdf_nbuf_next(msdu); + + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(vdev->pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + + msdu = next; + } + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, msdu_list); +} + +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word) +{ + int vdev_id, peer_id, tid; + cdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + int msdu_iter = 0; + + while (msdu_count) { + htt_rx_offload_paddr_msdu_pop_ll(htt_pdev, msg_word, msdu_iter, + &vdev_id, &peer_id, &tid, + &fw_desc, &head_buf, + &tail_buf); + + peer = ol_txrx_peer_find_by_id(htt_pdev->txrx_pdev, peer_id); + if (peer) { + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + cdf_nbuf_t next; + next = cdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + msdu_iter++; + msdu_count--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} + + +#ifdef NEVERDEFINED +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, cdf_nbuf_t msdu) +{ + /* FIX THIS: + * txrx should not be directly using data types (scn) + * that are internal to other modules. + */ + struct ol_ath_softc_net80211 *scn = + (struct ol_ath_softc_net80211 *)pdev->ctrl_pdev; + + if (scn->vow_extstats == 0) { + return; + } else { + uint8_t *data, *l3_hdr, *bp; + uint16_t ethertype; + int offset; + struct vow_extstats vowstats; + + data = cdf_nbuf_data(msdu); + + offset = ETHERNET_ADDR_LEN * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if ((l3_hdr[offset] == IP_PROTOCOL_UDP) && + (l3_hdr[0] == IP_VER4_N_NO_EXTRA_HEADERS)) { + bp = data + EXT_HDR_OFFSET; + + if ((data[RTP_HDR_OFFSET] == UDP_PDU_RTP_EXT) && + (bp[0] == 0x12) && + (bp[1] == 0x34) && + (bp[2] == 0x00) && (bp[3] == 0x08)) { + /* + * Clear UDP checksum so we do not have + * to recalculate it + * after filling in status fields. + */ + data[UDP_CKSUM_OFFSET] = 0; + data[(UDP_CKSUM_OFFSET + 1)] = 0; + + bp += IPERF3_DATA_OFFSET; + + htt_rx_get_vowext_stats(msdu, + &vowstats); + + /* control channel RSSI */ + *bp++ = vowstats.rx_rssi_ctl0; + *bp++ = vowstats.rx_rssi_ctl1; + *bp++ = vowstats.rx_rssi_ctl2; + + /* rx rate info */ + *bp++ = vowstats.rx_bw; + *bp++ = vowstats.rx_sgi; + *bp++ = vowstats.rx_nss; + + *bp++ = vowstats.rx_rssi_comb; + /* rsflags */ + *bp++ = vowstats.rx_rs_flags; + + /* Time stamp Lo */ + *bp++ = (uint8_t) + ((vowstats. + rx_macTs & 0x0000ff00) >> 8); + *bp++ = (uint8_t) + (vowstats.rx_macTs & 0x0000ff); + /* rx phy errors */ + *bp++ = (uint8_t) + ((scn->chan_stats. + phy_err_cnt >> 8) & 0xff); + *bp++ = + (uint8_t) (scn->chan_stats. + phy_err_cnt & 0xff); + /* rx clear count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + rx_clear_count & 0xff); + /* rx cycle count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + cycle_count & 0xff); + + *bp++ = vowstats.rx_ratecode; + *bp++ = vowstats.rx_moreaggr; + + /* sequence number */ + *bp++ = (uint8_t) + ((vowstats.rx_seqno >> 8) & + 0xff); + *bp++ = (uint8_t) + (vowstats.rx_seqno & 0xff); + } + } + } + } +} + +#endif diff --git a/core/dp/txrx/ol_rx.h b/core/dp/txrx/ol_rx.h new file mode 100644 index 0000000000..33d749fccf --- /dev/null +++ b/core/dp/txrx/ol_rx.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX__H_ +#define _OL_RX__H_ + +#include /* cdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ + +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t head_msdu); + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t head_msdu); + +void ol_rx_frames_free(htt_pdev_handle htt_pdev, cdf_nbuf_t frames); + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer); + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer); + +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t head_msdu); + +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word); + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + cdf_nbuf_t msdu); + +#endif /* _OL_RX__H_ */ diff --git a/core/dp/txrx/ol_rx_defrag.c b/core/dp/txrx/ol_rx_defrag.c new file mode 100644 index 0000000000..4fb2cbc2e4 --- /dev/null +++ b/core/dp/txrx/ol_rx_defrag.c @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*- + * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* cdf_system_time */ + +#define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \ + (cdf_mem_compare(a1, a2, IEEE80211_ADDR_LEN) == 0) + +#define DEFRAG_IEEE80211_ADDR_COPY(dst, src) \ + cdf_mem_copy(dst, src, IEEE80211_ADDR_LEN) + +#define DEFRAG_IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +#define DEFRAG_IEEE80211_QOS_GET_TID(_x) \ + ((_x)->i_qos[0] & IEEE80211_QOS_TID) + +const struct ol_rx_defrag_cipher f_ccmp = { + "AES-CCM", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_MICLEN, + 0, +}; + +const struct ol_rx_defrag_cipher f_tkip = { + "TKIP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_CRCLEN, + IEEE80211_WEP_MICLEN, +}; + +const struct ol_rx_defrag_cipher f_wep = { + "WEP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN, + IEEE80211_WEP_CRCLEN, + 0, +}; + +inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, + cdf_nbuf_t frag) +{ + return + (struct ieee80211_frame *) cdf_nbuf_data(frag); +} +#define ol_rx_frag_pull_hdr(pdev, frag, hdrsize) \ + cdf_nbuf_pull_head(frag, hdrsize); +#define OL_RX_FRAG_CLONE(frag) NULL /* no-op */ + +static inline void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + cdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = NULL; + *ind_old_position = NULL; + *rx_desc_len = 0; +} + +/* + * Process incoming fragments + */ +void +ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + cdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid) +{ + uint16_t seq_num; + int seq_num_start, seq_num_end; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + cdf_nbuf_t head_msdu, tail_msdu; + void *rx_mpdu_desc; + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) && + htt_rx_ind_flush(pdev->htt_pdev, rx_frag_ind_msg) && peer) { + htt_rx_frag_ind_flush_seq_num_range(pdev->htt_pdev, + rx_frag_ind_msg, + &seq_num_start, + &seq_num_end); + /* + * Assuming flush indication for frags sent from target is + * separate from normal frames + */ + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, seq_num_start); + } + if (peer) { + htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, + &tail_msdu); + cdf_assert(head_msdu == tail_msdu); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, head_msdu); + } else { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_frag_ind_msg); + } + seq_num = htt_rx_mpdu_desc_seq_num(htt_pdev, rx_mpdu_desc); + OL_RX_ERR_STATISTICS_1(pdev, peer->vdev, peer, rx_mpdu_desc, + OL_RX_ERR_NONE_FRAG); + ol_rx_reorder_store_frag(pdev, peer, tid, seq_num, head_msdu); + } else { + /* invalid frame - discard it */ + htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, + &tail_msdu); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu); + else + htt_rx_mpdu_desc_list_next(htt_pdev, rx_frag_ind_msg); + + htt_rx_desc_frame_free(htt_pdev, head_msdu); + } + /* request HTT to provide new rx MSDU buffers for the target to fill. */ + htt_rx_msdu_buff_replenish(htt_pdev); +} + +/* + * Flushing fragments + */ +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, unsigned tid, int seq_num) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + int seq; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + if (rx_reorder_array_elem->head) { + ol_rx_frames_free(htt_pdev, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } +} + +/* + * Reorder and store fragments + */ +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, uint16_t seq_num, cdf_nbuf_t frag) +{ + struct ieee80211_frame *fmac_hdr, *mac_hdr; + uint8_t fragno, more_frag, all_frag_present = 0; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + uint16_t frxseq, rxseq, seq; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + cdf_assert(seq == 0); + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + rxseq = cdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + fragno = cdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + more_frag = mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + + if ((!more_frag) && (!fragno) && (!rx_reorder_array_elem->head)) { + rx_reorder_array_elem->head = frag; + rx_reorder_array_elem->tail = frag; + cdf_nbuf_set_next(frag, NULL); + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + return; + } + if (rx_reorder_array_elem->head) { + fmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, + rx_reorder_array_elem->head); + frxseq = cdf_le16_to_cpu(*(uint16_t *) fmac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + if (rxseq != frxseq + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr1, + fmac_hdr->i_addr1) + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr2, + fmac_hdr->i_addr2)) { + ol_rx_frames_free(htt_pdev, + rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_reorder_store: %s mismatch \n", + (rxseq == frxseq) + ? "address" + : "seq number"); + } + } + + ol_rx_fraglist_insert(htt_pdev, &rx_reorder_array_elem->head, + &rx_reorder_array_elem->tail, frag, + &all_frag_present); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_remove(peer, tid); + + if (all_frag_present) { + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + peer->tids_rx_reorder[tid].defrag_timeout_ms = 0; + peer->tids_last_seq[tid] = seq_num; + } else if (pdev->rx.flags.defrag_timeout_check) { + uint32_t now_ms = cdf_system_ticks_to_msecs(cdf_system_ticks()); + + peer->tids_rx_reorder[tid].defrag_timeout_ms = + now_ms + pdev->rx.defrag.timeout_ms; + ol_rx_defrag_waitlist_add(peer, tid); + } +} + +/* + * Insert and store fragments + */ +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + cdf_nbuf_t *head_addr, + cdf_nbuf_t *tail_addr, + cdf_nbuf_t frag, uint8_t *all_frag_present) +{ + cdf_nbuf_t next, prev = NULL, cur = *head_addr; + struct ieee80211_frame *mac_hdr, *cmac_hdr, *next_hdr, *lmac_hdr; + uint8_t fragno, cur_fragno, lfragno, next_fragno; + uint8_t last_morefrag = 1, count = 0; + cdf_nbuf_t frag_clone; + + cdf_assert(frag); + frag_clone = OL_RX_FRAG_CLONE(frag); + frag = frag_clone ? frag_clone : frag; + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + fragno = cdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + + if (!(*head_addr)) { + *head_addr = frag; + *tail_addr = frag; + cdf_nbuf_set_next(*tail_addr, NULL); + return; + } + /* For efficiency, compare with tail first */ + lmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, *tail_addr); + lfragno = cdf_le16_to_cpu(*(uint16_t *) lmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + if (fragno > lfragno) { + cdf_nbuf_set_next(*tail_addr, frag); + *tail_addr = frag; + cdf_nbuf_set_next(*tail_addr, NULL); + } else { + do { + cmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, cur); + cur_fragno = + cdf_le16_to_cpu(*(uint16_t *) cmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + prev = cur; + cur = cdf_nbuf_next(cur); + } while (fragno > cur_fragno); + + if (fragno == cur_fragno) { + htt_rx_desc_frame_free(htt_pdev, frag); + *all_frag_present = 0; + return; + } else { + cdf_nbuf_set_next(prev, frag); + cdf_nbuf_set_next(frag, cur); + } + } + next = cdf_nbuf_next(*head_addr); + lmac_hdr = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + *tail_addr); + last_morefrag = lmac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + if (!last_morefrag) { + do { + next_hdr = + (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, next); + next_fragno = + cdf_le16_to_cpu(*(uint16_t *) next_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + count++; + if (next_fragno != count) + break; + + next = cdf_nbuf_next(next); + } while (next); + + if (!next) { + *all_frag_present = 1; + return; + } + } + *all_frag_present = 0; +} + +/* + * add tid to pending fragment wait list + */ +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + TAILQ_INSERT_TAIL(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); +} + +/* + * remove tid from pending fragment wait list + */ +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + if (rx_reorder->defrag_waitlist_elem.tqe_next != NULL || + rx_reorder->defrag_waitlist_elem.tqe_prev != NULL) { + + TAILQ_REMOVE(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; + } +} + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +/* + * flush stale fragments from the waitlist + */ +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_rx_reorder_t *rx_reorder, *tmp; + uint32_t now_ms = cdf_system_ticks_to_msecs(cdf_system_ticks()); + + TAILQ_FOREACH_SAFE(rx_reorder, &pdev->rx.defrag.waitlist, + defrag_waitlist_elem, tmp) { + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder_base; + unsigned tid; + + if (rx_reorder->defrag_timeout_ms > now_ms) + break; + + tid = rx_reorder->tid; + /* get index 0 of the rx_reorder array */ + rx_reorder_base = rx_reorder - tid; + peer = + container_of(rx_reorder_base, struct ol_txrx_peer_t, + tids_rx_reorder[0]); + + ol_rx_defrag_waitlist_remove(peer, tid); + ol_rx_reorder_flush_frag(pdev->htt_pdev, peer, tid, + 0 /* frags always stored at seq 0 */); + } +} + +/* + * Handling security checking and processing fragments + */ +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t frag_list) +{ + struct ol_txrx_vdev_t *vdev = NULL; + cdf_nbuf_t tmp_next, msdu, prev = NULL, cur = frag_list; + uint8_t index, tkip_demic = 0; + uint16_t hdr_space; + void *rx_desc; + struct ieee80211_frame *wh; + uint8_t key[DEFRAG_IEEE80211_KEY_LEN]; + + htt_pdev_handle htt_pdev = pdev->htt_pdev; + vdev = peer->vdev; + + /* bypass defrag for safe mode */ + if (vdev->safemode) { + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + ol_rx_in_order_deliver(vdev, peer, tid, frag_list); + else + ol_rx_deliver(vdev, peer, tid, frag_list); + return; + } + + while (cur) { + tmp_next = cdf_nbuf_next(cur); + cdf_nbuf_set_next(cur, NULL); + if (!ol_rx_pn_check_base(vdev, peer, tid, cur)) { + /* PN check failed,discard frags */ + if (prev) { + cdf_nbuf_set_next(prev, NULL); + ol_rx_frames_free(htt_pdev, frag_list); + } + ol_rx_frames_free(htt_pdev, tmp_next); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "ol_rx_defrag: PN Check failed\n"); + return; + } + /* remove FCS from each fragment */ + cdf_nbuf_trim_tail(cur, DEFRAG_IEEE80211_FCS_LEN); + prev = cur; + cdf_nbuf_set_next(cur, tmp_next); + cur = tmp_next; + } + cur = frag_list; + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, cur); + hdr_space = ol_rx_frag_hdrsize(wh); + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag_list); + cdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + switch (peer->security[index].sec_type) { + case htt_sec_type_tkip: + tkip_demic = 1; + /* fall-through to rest of tkip ops */ + case htt_sec_type_tkip_nomic: + while (cur) { + tmp_next = cdf_nbuf_next(cur); + if (!ol_rx_frag_tkip_decap(pdev, cur, hdr_space)) { + /* TKIP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: TKIP decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_aes_ccmp: + while (cur) { + tmp_next = cdf_nbuf_next(cur); + if (!ol_rx_frag_ccmp_demic(pdev, cur, hdr_space)) { + /* CCMP demic failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: CCMP demic failed\n"); + return; + } + if (!ol_rx_frag_ccmp_decap(pdev, cur, hdr_space)) { + /* CCMP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: CCMP decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_wep40: + case htt_sec_type_wep104: + case htt_sec_type_wep128: + while (cur) { + tmp_next = cdf_nbuf_next(cur); + if (!ol_rx_frag_wep_decap(pdev, cur, hdr_space)) { + /* wep decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: wep decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + default: + break; + } + + msdu = ol_rx_defrag_decap_recombine(htt_pdev, frag_list, hdr_space); + if (!msdu) + return; + + if (tkip_demic) { + cdf_mem_copy(key, + peer->security[index].michael_key, + sizeof(peer->security[index].michael_key)); + if (!ol_rx_frag_tkip_demic(pdev, key, msdu, hdr_space)) { + htt_rx_desc_frame_free(htt_pdev, msdu); + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, 0, + OL_RX_DEFRAG_ERR, msdu, NULL, 0); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: TKIP demic failed\n"); + return; + } + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, msdu); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) + ol_rx_defrag_qos_decap(pdev, msdu, hdr_space); + if (ol_cfg_frame_type(pdev->ctrl_pdev) == wlan_frm_fmt_802_3) + ol_rx_defrag_nwifi_to_8023(pdev, msdu); + + ol_rx_fwd_check(vdev, peer, tid, msdu); +} + +/* + * Handling TKIP processing for defragmentation + */ +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + /* Header should have extended IV */ + origHdr = (uint8_t *) (cdf_nbuf_data(msdu) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + cdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen); + cdf_nbuf_pull_head(msdu, f_tkip.ic_header); + cdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling WEP processing for defragmentation + */ +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, cdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + origHdr = (uint8_t *) (cdf_nbuf_data(msdu) + rx_desc_len); + cdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen); + cdf_nbuf_pull_head(msdu, f_wep.ic_header); + cdf_nbuf_trim_tail(msdu, f_wep.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, const uint8_t *key, + cdf_nbuf_t msdu, uint16_t hdrlen) +{ + int status; + uint32_t pktlen; + uint8_t mic[IEEE80211_WEP_MICLEN]; + uint8_t mic0[IEEE80211_WEP_MICLEN]; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + pktlen = ol_rx_defrag_len(msdu) - rx_desc_len; + + status = ol_rx_defrag_mic(pdev, key, msdu, hdrlen, + pktlen - (hdrlen + f_tkip.ic_miclen), mic); + if (status != OL_RX_DEFRAG_OK) + return OL_RX_DEFRAG_ERR; + + ol_rx_defrag_copydata(msdu, pktlen - f_tkip.ic_miclen + rx_desc_len, + f_tkip.ic_miclen, (caddr_t) mic0); + if (cdf_mem_compare(mic, mic0, f_tkip.ic_miclen)) + return OL_RX_DEFRAG_ERR; + + cdf_nbuf_trim_tail(msdu, f_tkip.ic_miclen); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling CCMP processing for defragmentation + */ +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t nbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (cdf_nbuf_data(nbuf) + rx_desc_len); + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + cdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen); + cdf_nbuf_pull_head(nbuf, f_ccmp.ic_header); + + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + cdf_nbuf_t wbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (cdf_nbuf_data(wbuf) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + cdf_nbuf_trim_tail(wbuf, f_ccmp.ic_trailer); + + return OL_RX_DEFRAG_OK; +} + +/* + * Craft pseudo header used to calculate the MIC. + */ +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]) +{ + const struct ieee80211_frame_addr4 *wh = + (const struct ieee80211_frame_addr4 *)wh0; + + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_TODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_FROMDS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr3); + break; + case IEEE80211_FC1_DIR_DSTODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr4); + break; + } + /* + * Bit 7 is IEEE80211_FC0_SUBTYPE_QOS for data frame, but + * it could also be set for deauth, disassoc, action, etc. for + * a mgt type frame. It comes into picture for MFP. + */ + if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + const struct ieee80211_qosframe *qwh = + (const struct ieee80211_qosframe *)wh; + hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID; + } else { + hdr[12] = 0; + } + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +/* + * Michael_mic for defragmentation + */ +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + cdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]) +{ + uint8_t hdr[16] = { 0, }; + uint32_t l, r; + const uint8_t *data; + uint32_t space; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + ol_rx_defrag_michdr((struct ieee80211_frame *)(cdf_nbuf_data(wbuf) + + rx_desc_len), hdr); + l = get_le32(key); + r = get_le32(key + 4); + + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + l ^= get_le32(hdr); + michael_block(l, r); + l ^= get_le32(&hdr[4]); + michael_block(l, r); + l ^= get_le32(&hdr[8]); + michael_block(l, r); + l ^= get_le32(&hdr[12]); + michael_block(l, r); + + /* first buffer has special handling */ + data = (uint8_t *) cdf_nbuf_data(wbuf) + rx_desc_len + off; + space = ol_rx_defrag_len(wbuf) - rx_desc_len - off; + for (;; ) { + if (space > data_len) + space = data_len; + + /* collect 32-bit blocks from current buffer */ + while (space >= sizeof(uint32_t)) { + l ^= get_le32(data); + michael_block(l, r); + data += sizeof(uint32_t); + space -= sizeof(uint32_t); + data_len -= sizeof(uint32_t); + } + if (data_len < sizeof(uint32_t)) + break; + + wbuf = cdf_nbuf_next(wbuf); + if (wbuf == NULL) + return OL_RX_DEFRAG_ERR; + + rx_desc_len = 0; + + if (space != 0) { + const uint8_t *data_next; + /* + * Block straddles buffers, split references. + */ + data_next = + (uint8_t *) cdf_nbuf_data(wbuf) + rx_desc_len; + if ((ol_rx_defrag_len(wbuf) - rx_desc_len) < + sizeof(uint32_t) - space) { + return OL_RX_DEFRAG_ERR; + } + switch (space) { + case 1: + l ^= get_le32_split(data[0], data_next[0], + data_next[1], data_next[2]); + data = data_next + 3; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 3; + break; + case 2: + l ^= get_le32_split(data[0], data[1], + data_next[0], data_next[1]); + data = data_next + 2; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 2; + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], + data_next[0]); + data = data_next + 1; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 1; + break; + } + michael_block(l, r); + data_len -= sizeof(uint32_t); + } else { + /* + * Setup for next buffer. + */ + data = (uint8_t *) cdf_nbuf_data(wbuf) + rx_desc_len; + space = ol_rx_defrag_len(wbuf) - rx_desc_len; + } + } + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (data_len) { + case 0: + l ^= get_le32_split(0x5a, 0, 0, 0); + break; + case 1: + l ^= get_le32_split(data[0], 0x5a, 0, 0); + break; + case 2: + l ^= get_le32_split(data[0], data[1], 0x5a, 0); + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], 0x5a); + break; + } + michael_block(l, r); + michael_block(l, r); + put_le32(mic, l); + put_le32(mic + 4, r); + + return OL_RX_DEFRAG_OK; +} + +/* + * Calculate headersize + */ +uint16_t ol_rx_frag_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + uint16_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/* + * Recombine and decap fragments + */ +cdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + cdf_nbuf_t frag_list, uint16_t hdrsize) +{ + cdf_nbuf_t tmp; + cdf_nbuf_t msdu = frag_list; + cdf_nbuf_t rx_nbuf = frag_list; + struct ieee80211_frame *wh; + + msdu = cdf_nbuf_next(msdu); + cdf_nbuf_set_next(rx_nbuf, NULL); + while (msdu) { + htt_rx_msdu_desc_free(htt_pdev, msdu); + tmp = cdf_nbuf_next(msdu); + cdf_nbuf_set_next(msdu, NULL); + ol_rx_frag_pull_hdr(htt_pdev, msdu, hdrsize); + if (!ol_rx_defrag_concat(rx_nbuf, msdu)) { + ol_rx_frames_free(htt_pdev, tmp); + htt_rx_desc_frame_free(htt_pdev, rx_nbuf); + cdf_nbuf_free(msdu); + /* msdu rx desc already freed above */ + return NULL; + } + msdu = tmp; + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + rx_nbuf); + wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; + *(uint16_t *) wh->i_seq &= ~IEEE80211_SEQ_FRAG_MASK; + + return rx_nbuf; +} + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, cdf_nbuf_t msdu) +{ + struct ieee80211_frame wh; + uint32_t hdrsize; + struct llc_snap_hdr_t llchdr; + struct ethernet_hdr_t *eth_hdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + struct ieee80211_frame *wh_ptr; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh_ptr = (struct ieee80211_frame *)(cdf_nbuf_data(msdu) + rx_desc_len); + cdf_mem_copy(&wh, wh_ptr, sizeof(wh)); + hdrsize = sizeof(struct ieee80211_frame); + cdf_mem_copy(&llchdr, ((uint8_t *) (cdf_nbuf_data(msdu) + + rx_desc_len)) + hdrsize, + sizeof(struct llc_snap_hdr_t)); + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + cdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize + + sizeof(struct llc_snap_hdr_t) - + sizeof(struct ethernet_hdr_t))); + eth_hdr = (struct ethernet_hdr_t *)(cdf_nbuf_data(msdu)); + switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + cdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + cdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3, + IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + cdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + IEEE80211_ADDR_LEN); + cdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + + cdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype, + sizeof(llchdr.ethertype)); +} + +/* + * Handling QOS for defragmentation + */ +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t nbuf, uint16_t hdrlen) +{ + struct ieee80211_frame *wh; + uint16_t qoslen; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh = (struct ieee80211_frame *)(cdf_nbuf_data(nbuf) + rx_desc_len); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + qoslen = sizeof(struct ieee80211_qoscntl); + /* Qos frame with Order bit set indicates a HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + qoslen += sizeof(struct ieee80211_htc); + + /* remove QoS filed from header */ + hdrlen -= qoslen; + cdf_mem_move((uint8_t *) wh + qoslen, wh, hdrlen); + wh = (struct ieee80211_frame *)cdf_nbuf_pull_head(nbuf, + rx_desc_len + + qoslen); + /* clear QoS bit */ + /* + * KW# 6154 'cdf_nbuf_pull_head' in turn calls + * __cdf_nbuf_pull_head, + * which returns NULL if there is not sufficient data to pull. + * It's guaranteed that cdf_nbuf_pull_head will succeed rather + * than returning NULL, since the entire rx frame is already + * present in the rx buffer. + * However, to make it obvious to static analyzers that this + * code is safe, add an explicit check that cdf_nbuf_pull_head + * returns a non-NULL value. + * Since this part of the code is not performance-critical, + * adding this explicit check is okay. + */ + if (wh) + wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; + + } +} diff --git a/core/dp/txrx/ol_rx_defrag.h b/core/dp/txrx/ol_rx_defrag.h new file mode 100644 index 0000000000..512fa5dacb --- /dev/null +++ b/core/dp/txrx/ol_rx_defrag.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_DEFRAG_H_ +#define _OL_RX_DEFRAG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFRAG_IEEE80211_ADDR_LEN 6 +#define DEFRAG_IEEE80211_KEY_LEN 8 +#define DEFRAG_IEEE80211_FCS_LEN 4 + +struct ol_rx_defrag_cipher { + const char *ic_name; + uint16_t ic_header; + uint8_t ic_trailer; + uint8_t ic_miclen; +}; + +enum { + OL_RX_DEFRAG_ERR, + OL_RX_DEFRAG_OK, + OL_RX_DEFRAG_PN_ERR +}; + +#define ol_rx_defrag_copydata(buf, offset, len, _to) \ + cdf_nbuf_copy_bits(buf, offset, len, _to) + +#define ol_rx_defrag_len(buf) \ + cdf_nbuf_len(buf) + +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + cdf_nbuf_t *head_addr, + cdf_nbuf_t *tail_addr, + cdf_nbuf_t frag, uint8_t *all_frag_present); + +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned tid); + +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned tid); + +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev); + +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t frag_list); + +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t nbuf, uint16_t hdrlen); + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, cdf_nbuf_t msdu); + +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, + const uint8_t *key, cdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + cdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + cdf_nbuf_t wbuf, uint16_t hdrlen); + +uint16_t ol_rx_frag_hdrsize(const void *data); + +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]); + +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, uint16_t seq_num, cdf_nbuf_t frag); + +cdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + cdf_nbuf_t frag_list, uint16_t hdrsize); + +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + cdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]); + +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, int seq_num); + +static inline void xor_block(uint8_t *b, const uint8_t *a, cdf_size_t len) +{ + cdf_size_t i; + + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + +static inline uint32_t rotl(uint32_t val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + +static inline uint32_t rotr(uint32_t val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +static inline uint32_t xswap(uint32_t val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); +} + +static inline uint32_t +get_le32_split(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) +{ + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); +} + +static inline uint32_t get_le32(const uint8_t *p) +{ + return get_le32_split(p[0], p[1], p[2], p[3]); +} + +static inline void put_le32(uint8_t *p, uint32_t v) +{ + p[0] = (v) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +static inline uint8_t ol_rx_defrag_concat(cdf_nbuf_t dst, cdf_nbuf_t src) +{ + /* + * Inside cdf_nbuf_cat, if it is necessary to reallocate dst + * to provide space for src, the headroom portion is copied from + * the original dst buffer to the larger new dst buffer. + * (This is needed, because the headroom of the dst buffer + * contains the rx desc.) + */ + if (cdf_nbuf_cat(dst, src)) + return OL_RX_DEFRAG_ERR; + + return OL_RX_DEFRAG_OK; +} + +#define michael_block(l, r) \ + do { \ + r ^= rotl(l, 17); \ + l += r; \ + r ^= xswap(l); \ + l += r; \ + r ^= rotl(l, 3); \ + l += r; \ + r ^= rotr(l, 2); \ + l += r; \ + } while (0) + +#endif diff --git a/core/dp/txrx/ol_rx_fwd.c b/core/dp/txrx/ol_rx_fwd.c new file mode 100644 index 0000000000..e97f34f057 --- /dev/null +++ b/core/dp/txrx/ol_rx_fwd.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* standard header files */ +#include /* cdf_nbuf_map */ +#include /* cdf_mem_compare */ + +/* external header files */ +#include /* wlan_op_mode_ap, etc. */ +#include /* htt_rx_msdu_desc_retrieve */ +#include /* ieee80211_frame, etc. */ + +/* internal header files */ +#include /* ol_txrx_dev_t, etc. */ +#include /* our own defs */ +#include /* ol_rx_deliver */ +#include /* TXRX_ASSERT1 */ +#include +/* + * Porting from Ap11PrepareForwardedPacket. + * This routine is called when a RX data frame from an associated station is + * to be forwarded to another associated station. We will prepare the + * received packet so that it is suitable for transmission again. + * Check that this Packet is suitable for forwarding. If yes, then + * prepare the new 802.11 header. + */ +static inline void ol_ap_fwd_check(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu) +{ + struct ieee80211_frame *mac_header; + unsigned char tmp_addr[IEEE80211_ADDR_LEN]; + unsigned char type; + unsigned char subtype; + unsigned char fromds; + unsigned char tods; + + mac_header = (struct ieee80211_frame *)(cdf_nbuf_data(msdu)); + TXRX_ASSERT1(mac_header); + + type = mac_header->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + subtype = mac_header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + tods = mac_header->i_fc[1] & IEEE80211_FC1_DIR_TODS; + fromds = mac_header->i_fc[1] & IEEE80211_FC1_DIR_FROMDS; + + /* + * Make sure no QOS or any other non-data subtype + * Should be a ToDs data frame. + * Make sure that this frame is unicast and not for us. + * These packets should come up through the normal rx path and + * not forwarded. + */ + if (type != IEEE80211_FC0_TYPE_DATA || + subtype != 0x0 || + ((tods != 1) || (fromds != 0)) || + (cdf_mem_compare + (mac_header->i_addr3, vdev->mac_addr.raw, + IEEE80211_ADDR_LEN) == 0)) { +#ifdef DEBUG_HOST_RC + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "Exit: %s | Unnecessary to adjust mac header\n", + __func__); +#endif + } else { + /* Flip the ToDs bit to FromDs */ + mac_header->i_fc[1] &= 0xfe; + mac_header->i_fc[1] |= 0x2; + + /* + * Flip the addresses + * (ToDs, addr1, RA=BSSID) move to (FrDs, addr2, TA=BSSID) + * (ToDs, addr2, SA) move to (FrDs, addr3, SA) + * (ToDs, addr3, DA) move to (FrDs, addr1, DA) + */ + + memcpy(tmp_addr, mac_header->i_addr2, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr2, + mac_header->i_addr1, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr1, + mac_header->i_addr3, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr3, tmp_addr, sizeof(tmp_addr)); + } +} + +static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + ol_ap_fwd_check(vdev, msdu); + + /* + * Map the netbuf, so it's accessible to the DMA that + * sends it to the target. + */ + cdf_nbuf_map_single(pdev->osdev, msdu, CDF_DMA_TO_DEVICE); + cdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */ + + msdu = OL_TX_LL(vdev, msdu); + + if (msdu) { + /* + * The frame was not accepted by the tx. + * We could store the frame and try again later, + * but the simplest solution is to discard the frames. + */ + cdf_nbuf_unmap_single(pdev->osdev, msdu, CDF_DMA_TO_DEVICE); + cdf_nbuf_tx_free(msdu, NBUF_PKT_ERROR); + } +} + +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + cdf_nbuf_t deliver_list_head = NULL; + cdf_nbuf_t deliver_list_tail = NULL; + cdf_nbuf_t msdu; + + msdu = msdu_list; + while (msdu) { + struct ol_txrx_vdev_t *tx_vdev; + void *rx_desc; + /* + * Remember the next list elem, because our processing + * may cause the MSDU to get linked into a different list. + */ + msdu_list = cdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + + if (!vdev->disable_intrabss_fwd && + htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) { + /* + * Use the same vdev that received the frame to + * transmit the frame. + * This is exactly what we want for intra-BSS + * forwarding, like STA-to-STA forwarding and + * multicast echo. + * If this is a intra-BSS forwarding case (which is not + * currently supported), then the tx vdev is different + * from the rx vdev. + * On the LL host the vdevs are not actually used + * for tx, so it would still work to use the rx vdev + * rather than the tx vdev. + * For HL, the tx classification searches for the DA + * within the given vdev, so we would want to get the DA + * peer ID from the target, so we can locate + * the tx vdev. + */ + tx_vdev = vdev; + /* + * Copying TID value of RX packet to forwarded + * packet if the tid is other than non qos tid. + * But for non qos tid fill invalid tid so that + * Fw will take care of filling proper tid. + */ + if (tid != HTT_NON_QOS_TID) { + cdf_nbuf_set_tid(msdu, tid); + } else { + cdf_nbuf_set_tid(msdu, + ADF_NBUF_TX_EXT_TID_INVALID); + } + /* + * This MSDU needs to be forwarded to the tx path. + * Check whether it also needs to be sent to the OS + * shim, in which case we need to make a copy + * (or clone?). + */ + if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) { + htt_rx_msdu_desc_free(pdev->htt_pdev, msdu); + cdf_net_buf_debug_release_skb(msdu); + ol_rx_fwd_to_tx(tx_vdev, msdu); + msdu = NULL; /* already handled this MSDU */ + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_fwd, 1); + } else { + cdf_nbuf_t copy; + copy = cdf_nbuf_copy(msdu); + if (copy) + ol_rx_fwd_to_tx(tx_vdev, copy); + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1); + } + } else { + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack, 1); + } + if (msdu) { + /* send this frame to the OS */ + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + } + msdu = msdu_list; + } + if (deliver_list_head) { + /* add NULL terminator */ + cdf_nbuf_set_next(deliver_list_tail, NULL); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + ol_rx_in_order_deliver(vdev, peer, tid, + deliver_list_head); + } else { + ol_rx_deliver(vdev, peer, tid, deliver_list_head); + } + } +} diff --git a/core/dp/txrx/ol_rx_fwd.h b/core/dp/txrx/ol_rx_fwd.h new file mode 100644 index 0000000000..fe570c5acb --- /dev/null +++ b/core/dp/txrx/ol_rx_fwd.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_FWD_H_ +#define _OL_RX_FWD_H_ + +#include /* cdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +cdf_nbuf_t +ol_rx_fwd_mcast_check_sta(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +cdf_nbuf_t +ol_rx_fwd_mcast_check_ap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +/** + * @brief Check if rx frames should be transmitted over WLAN. + * @details + * Check if rx frames should be transmitted back over WLAN, instead of + * or in addition to delivering the rx frames to the OS. + * Rx frames will be forwarded to the transmit path under the following + * conditions: + * 1. If the destination is a STA associated to the same virtual device + * within this physical device, the rx frame will be forwarded to the + * tx path rather than being sent to the OS. If the destination is a + * STA associated to a different virtual device within this physical + * device, then the rx frame will optionally be forwarded to the tx path. + * 2. If the frame is received by an AP, but the destination is for another + * AP that the current AP is associated with for WDS forwarding, the + * intermediate AP will forward the rx frame to the tx path to transmit + * to send to the destination AP, rather than sending it to the OS. + * 3. If the AP receives a multicast frame, it will retransmit the frame + * within the BSS, in addition to sending the frame to the OS. + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform the rx->tx + * forwarding check on + */ +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list); + +#endif /* _OL_RX_FWD_H_ */ diff --git a/core/dp/txrx/ol_rx_pn.c b/core/dp/txrx/ol_rx_pn.c new file mode 100644 index 0000000000..362616c71f --- /dev/null +++ b/core/dp/txrx/ol_rx_pn.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2011, 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* cdf_nbuf_t */ + +#include /* htt_rx_pn_t, etc. */ +#include /* ol_rx_err */ + +#include /* ol_rx_mpdu_list_next */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* our own defs */ +#include /* ol_rx_fwd_check */ +#include /* ol_rx_deliver */ + +/* add the MSDUs from this MPDU to the list of good frames */ +#define ADD_MPDU_TO_LIST(head, tail, mpdu, mpdu_tail) do { \ + if (!head) { \ + head = mpdu; \ + } else { \ + cdf_nbuf_set_next(tail, mpdu); \ + } \ + tail = mpdu_tail; \ + } while (0) + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int rc = ((new_pn->pn24 & 0xffffff) <= (old_pn->pn24 & 0xffffff)); + return rc; +} + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int rc = ((new_pn->pn48 & 0xffffffffffffULL) <= + (old_pn->pn48 & 0xffffffffffffULL)); + return rc; +} + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int pn_is_replay = 0; + + if (new_pn->pn128[1] == old_pn->pn128[1]) + pn_is_replay = (new_pn->pn128[0] <= old_pn->pn128[0]); + else + pn_is_replay = (new_pn->pn128[1] < old_pn->pn128[1]); + + if (is_unicast) { + if (opmode == wlan_op_mode_ap) + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 0); + else + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 1); + } + return pn_is_replay; +} + +cdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + union htt_rx_pn_t *last_pn; + cdf_nbuf_t out_list_head = NULL; + cdf_nbuf_t out_list_tail = NULL; + cdf_nbuf_t mpdu; + int index; /* unicast vs. multicast */ + int pn_len; + void *rx_desc; + int last_pn_valid; + + /* Make sure host pn check is not redundant */ + if (cdf_atomic_read(&peer->fw_pn_check)) + return msdu_list; + + /* First, check whether the PN check applies */ + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu_list); + cdf_assert(htt_rx_msdu_has_wlan_mcast_flag(pdev->htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index].sec_type].len; + if (pn_len == 0) + return msdu_list; + + last_pn_valid = peer->tids_last_pn_valid[tid]; + last_pn = &peer->tids_last_pn[tid]; + mpdu = msdu_list; + while (mpdu) { + cdf_nbuf_t mpdu_tail, next_mpdu; + union htt_rx_pn_t new_pn; + int pn_is_replay = 0; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, mpdu); + + /* + * Find the last MSDU within this MPDU, and + * the find the first MSDU within the next MPDU. + */ + ol_rx_mpdu_list_next(pdev, mpdu, &mpdu_tail, &next_mpdu); + + /* Don't check the PN replay for non-encrypted frames */ + if (!htt_rx_mpdu_is_encrypted(pdev->htt_pdev, rx_desc)) { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, mpdu, + mpdu_tail); + mpdu = next_mpdu; + continue; + } + + /* retrieve PN from rx descriptor */ + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &new_pn, pn_len); + + /* if there was no prior PN, there's nothing to check */ + if (last_pn_valid) { + pn_is_replay = + pdev->rx_pn[peer->security[index].sec_type]. + cmp(&new_pn, last_pn, index == txrx_sec_ucast, + vdev->opmode); + } else { + last_pn_valid = peer->tids_last_pn_valid[tid] = 1; + } + + if (pn_is_replay) { + cdf_nbuf_t msdu; + static uint32_t last_pncheck_print_time /* = 0 */; + int log_level; + uint32_t current_time_ms; + + /* + * This MPDU failed the PN check: + * 1. notify the control SW of the PN failure + * (so countermeasures can be taken, if necessary) + * 2. Discard all the MSDUs from this MPDU. + */ + msdu = mpdu; + current_time_ms = + cdf_system_ticks_to_msecs(cdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - last_pncheck_print_time)) { + last_pncheck_print_time = current_time_ms; + log_level = TXRX_PRINT_LEVEL_WARN; + } else { + log_level = TXRX_PRINT_LEVEL_INFO2; + } + + TXRX_PRINT(log_level, + "PN check failed - TID %d, peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x) %s\n" + " old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + (index == + txrx_sec_ucast) ? "ucast" : "mcast", + last_pn->pn128[1], last_pn->pn128[0], + last_pn->pn128[0] & 0xffffffffffffULL, + new_pn.pn128[1], new_pn.pn128[0], + new_pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, + rx_desc)); +#if defined(ENABLE_RX_PN_TRACE) + ol_rx_pn_trace_display(pdev, 1); +#endif /* ENABLE_RX_PN_TRACE */ + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), OL_RX_ERR_PN, + mpdu, NULL, 0); + /* free all MSDUs within this MPDU */ + do { + cdf_nbuf_t next_msdu; + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, + rx_desc, OL_RX_ERR_PN); + next_msdu = cdf_nbuf_next(msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + else + msdu = next_msdu; + } while (1); + } else { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, mpdu, + mpdu_tail); + /* + * Remember the new PN. + * For simplicity, just do 2 64-bit word copies to + * cover the worst case (WAPI), regardless of the length + * of the PN. + * This is more efficient than doing a conditional + * branch to copy only the relevant portion. + */ + last_pn->pn128[0] = new_pn.pn128[0]; + last_pn->pn128[1] = new_pn.pn128[1]; + OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc); + } + + mpdu = next_mpdu; + } + /* make sure the list is null-terminated */ + if (out_list_tail) + cdf_nbuf_set_next(out_list_tail, NULL); + + return out_list_head; +} + +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list); + ol_rx_fwd_check(vdev, peer, tid, msdu_list); +} + +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list); + ol_rx_deliver(vdev, peer, tid, msdu_list); +} + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_PN_TRACE_SIZE_LOG2; + pdev->rx_pn_trace.idx = 0; + pdev->rx_pn_trace.cnt = 0; + pdev->rx_pn_trace.mask = num_elems - 1; + pdev->rx_pn_trace.data = + cdf_mem_malloc(sizeof(*pdev->rx_pn_trace.data) * num_elems); + if (!pdev->rx_pn_trace.data) + return A_NO_MEMORY; + return A_OK; +} + +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev) +{ + cdf_mem_free(pdev->rx_pn_trace.data); +} + +void +ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, uint16_t tid, void *rx_desc) +{ + uint32_t idx = pdev->rx_pn_trace.idx; + union htt_rx_pn_t pn; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &pn, 48); + pn32 = pn.pn48 & 0xffffffff; + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_desc); + unicast = !htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc); + + pdev->rx_pn_trace.data[idx].peer = peer; + pdev->rx_pn_trace.data[idx].tid = tid; + pdev->rx_pn_trace.data[idx].seq_num = seq_num; + pdev->rx_pn_trace.data[idx].unicast = unicast; + pdev->rx_pn_trace.data[idx].pn32 = pn32; + pdev->rx_pn_trace.cnt++; + idx++; + pdev->rx_pn_trace.idx = idx & pdev->rx_pn_trace.mask; +} + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once) +{ + static int print_count /* = 0 */; + uint32_t i, start, end; + uint64_t cnt; + int elems; + int limit = 0; /* move this to the arg list? */ + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_pn_trace.idx; + if (pdev->rx_pn_trace.cnt <= pdev->rx_pn_trace.mask) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_pn_trace.cnt - (pdev->rx_pn_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_pn_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + delta = elems - limit; + start += delta; + start &= pdev->rx_pn_trace.mask; + cnt += delta; + } + + i = start; + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " seq PN"); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " count idx peer tid uni num LSBs"); + do { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " %6lld %4d %p %2d %d %4d %8d", + cnt, i, + pdev->rx_pn_trace.data[i].peer, + pdev->rx_pn_trace.data[i].tid, + pdev->rx_pn_trace.data[i].unicast, + pdev->rx_pn_trace.data[i].seq_num, + pdev->rx_pn_trace.data[i].pn32); + cnt++; + i++; + i &= pdev->rx_pn_trace.mask; + } while (i != end); +} +#endif /* ENABLE_RX_PN_TRACE */ diff --git a/core/dp/txrx/ol_rx_pn.h b/core/dp/txrx/ol_rx_pn.h new file mode 100644 index 0000000000..845dc91773 --- /dev/null +++ b/core/dp/txrx/ol_rx_pn.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_PN_H_ +#define _OL_RX_PN_H_ + +#include /* cdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, call the next stage of rx processing (rx --> tx + * forwarding check). + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, cdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, deliver the valid rx frames to the OS shim. + * (Don't perform a rx --> tx forwarding check.) + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Same as ol_rx_pn_check but return valid rx netbufs + * rather than invoking the rx --> tx forwarding check. + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + * @return list of netbufs that didn't fail the PN check + */ +cdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list); + +#endif /* _OL_RX_PN_H_ */ diff --git a/core/dp/txrx/ol_rx_reorder.c b/core/dp/txrx/ol_rx_reorder.c new file mode 100644 index 0000000000..da0d486ddd --- /dev/null +++ b/core/dp/txrx/ol_rx_reorder.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_mem_malloc */ + +#include /* IEEE80211_SEQ_MAX */ + +/* external interfaces */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_addba_handler, etc. */ +#include /* ol_ctrl_rx_addba_complete */ +#include /* htt_rx_desc_frame_free */ +#include /* ol_rx_err */ + +/* datapath internal interfaces */ +#include /* ol_txrx_peer_find_by_id */ +#include /* TXRX_ASSERT */ +#include /* OL_RX_REORDER_TIMEOUT_REMOVE, etc. */ +#include +#include + +/*=== data types and defines ===*/ +#define OL_RX_REORDER_ROUND_PWR2(value) g_log2ceil[value] + +/*=== global variables ===*/ + +static char g_log2ceil[] = { + 1, /* 0 -> 1 */ + 1, /* 1 -> 1 */ + 2, /* 2 -> 2 */ + 4, 4, /* 3-4 -> 4 */ + 8, 8, 8, 8, /* 5-8 -> 8 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 9-16 -> 16 */ + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, /* 17-32 -> 32 */ + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, /* 33-64 -> 64 */ +}; + +/*=== function definitions ===*/ + +/*---*/ + +#define QCA_SUPPORT_RX_REORDER_RELEASE_CHECK 0 +#define OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, idx_start) /* no-op */ +#define OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask) { idx &= win_sz_mask; } +#define OL_RX_REORDER_IDX_MAX(win_sz, win_sz_mask) win_sz_mask +#define OL_RX_REORDER_IDX_INIT(seq_num, win_sz, win_sz_mask) 0 /* n/a */ +#define OL_RX_REORDER_NO_HOLES(rx_reorder) 0 +#define OL_RX_REORDER_MPDU_CNT_INCR(rx_reorder, incr) /* n/a */ +#define OL_RX_REORDER_MPDU_CNT_DECR(rx_reorder, decr) /* n/a */ + +/*---*/ + +/* reorder array elements are known to be non-NULL */ +#define OL_RX_REORDER_PTR_CHECK(ptr) /* no-op */ +#define OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, rx_reorder_array_elem) \ + do { \ + if (tail_msdu) { \ + cdf_nbuf_set_next(tail_msdu, \ + rx_reorder_array_elem->head); \ + } \ + } while (0) + +/* functions called by txrx components */ + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid) +{ + rx_reorder->win_sz = 1; + rx_reorder->win_sz_mask = 0; + rx_reorder->array = &rx_reorder->base; + rx_reorder->base.head = rx_reorder->base.tail = NULL; + rx_reorder->tid = tid; + rx_reorder->defrag_timeout_ms = 0; + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; +} + +static enum htt_rx_status +ol_rx_reorder_seq_num_check( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, unsigned seq_num) +{ + unsigned seq_num_delta; + + /* don't check the new seq_num against last_seq + if last_seq is not valid */ + if (peer->tids_last_seq[tid] == IEEE80211_SEQ_MAX) + return htt_rx_status_ok; + + /* + * For duplicate detection, it might be helpful to also check + * whether the retry bit is set or not - a strict duplicate packet + * should be the one with retry bit set. + * However, since many implementations do not set the retry bit, + * and since this same function is also used for filtering out + * late-arriving frames (frames that arive after their rx reorder + * timeout has expired) which are not retries, don't bother checking + * the retry bit for now. + */ + /* note: if new seq_num == old seq_num, seq_num_delta = 4095 */ + seq_num_delta = (seq_num - 1 - peer->tids_last_seq[tid]) & + (IEEE80211_SEQ_MAX - 1); /* account for wraparound */ + + if (seq_num_delta > (IEEE80211_SEQ_MAX >> 1)) { + return htt_rx_status_err_replay; + /* or maybe htt_rx_status_err_dup */ + } + return htt_rx_status_ok; +} + +/** + * ol_rx_seq_num_check() - Does duplicate detection for mcast packets and + * duplicate detection & check for out-of-order + * packets for unicast packets. + * @pdev: Pointer to pdev maintained by OL + * @peer: Pointer to peer structure maintained by OL + * @tid: TID value passed as part of HTT msg by f/w + * @rx_mpdu_desc: Pointer to Rx Descriptor for the given MPDU + * + * This function + * 1) For Multicast Frames -- does duplicate detection + * A frame is considered duplicate & dropped if it has a seq.number + * which is received twice in succession and with the retry bit set + * in the second case. + * A frame which is older than the last sequence number received + * is not considered duplicate but out-of-order. This function does + * perform out-of-order check for multicast frames, which is in + * keeping with the 802.11 2012 spec section 9.3.2.10 + * 2) For Unicast Frames -- does duplicate detection & out-of-order check + * only for non-aggregation tids. + * + * Return: Returns htt_rx_status_err_replay, if packet needs to be + * dropped, htt_rx_status_ok otherwise. + */ +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, + void *rx_mpdu_desc) +{ + uint16_t pkt_tid = 0xffff; + uint16_t seq_num = IEEE80211_SEQ_MAX; + bool retry = 0; + + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_mpdu_desc); + + /* For mcast packets, we only the dup-detection, not re-order check */ + + if (cdf_unlikely(OL_RX_MCAST_TID == tid)) { + + pkt_tid = htt_rx_mpdu_desc_tid(pdev->htt_pdev, rx_mpdu_desc); + + /* Invalid packet TID, expected only for HL */ + /* Pass the packet on */ + if (cdf_unlikely(pkt_tid >= OL_TXRX_NUM_EXT_TIDS)) + return htt_rx_status_ok; + + retry = htt_rx_mpdu_desc_retry(pdev->htt_pdev, rx_mpdu_desc); + + /* + * At this point, we define frames to be duplicate if they arrive + * "ONLY" in succession with the same sequence number and the last + * one has the retry bit set. For an older frame, we consider that + * as an out of order frame, and hence do not perform the dup-detection + * or out-of-order check for multicast frames as per discussions & spec + * Hence "seq_num <= last_seq_num" check is not necessary. + */ + if (cdf_unlikely(retry && + (seq_num == peer->tids_mcast_last_seq[pkt_tid]))) {/* drop mcast */ + TXRX_STATS_INCR(pdev, priv.rx.err.msdu_mc_dup_drop); + return htt_rx_status_err_replay; + } else { + /* + * This is a multicast packet likely to be passed on... + * Set the mcast last seq number here + * This is fairly accurate since: + * a) f/w sends multicast as separate PPDU/HTT messages + * b) Mcast packets are not aggregated & hence single + * c) Result of b) is that, flush / release bit is set always + * on the mcast packets, so likely to be immediatedly released. + */ + peer->tids_mcast_last_seq[pkt_tid] = seq_num; + return htt_rx_status_ok; + } + } else + return ol_rx_reorder_seq_num_check(pdev, peer, tid, seq_num); +} + + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned idx, cdf_nbuf_t head_msdu, cdf_nbuf_t tail_msdu) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + + idx &= peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + cdf_nbuf_set_next(rx_reorder_array_elem->tail, head_msdu); + } else { + rx_reorder_array_elem->head = head_msdu; + OL_RX_REORDER_MPDU_CNT_INCR(&peer->tids_rx_reorder[tid], 1); + } + rx_reorder_array_elem->tail = tail_msdu; +} + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, unsigned idx_start, unsigned idx_end) +{ + unsigned idx; + unsigned win_sz, win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + cdf_nbuf_t head_msdu; + cdf_nbuf_t tail_msdu; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* may get reset below */ + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx_start]; + + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = NULL; + OL_RX_REORDER_PTR_CHECK(head_msdu) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], 1); + } + + idx = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + while (idx != idx_end) { + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + OL_RX_REORDER_PTR_CHECK(rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, + rx_reorder_array_elem); + tail_msdu = rx_reorder_array_elem->tail; + } + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = + NULL; + idx++; + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + } + OL_RX_REORDER_PTR_CHECK(head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + /* + * This logic is not quite correct - the last_seq value should + * be the sequence number of the final MPDU released rather than + * the initial MPDU released. + * However, tracking the sequence number of the first MPDU in + * the released batch works well enough: + * For Peregrine and Rome, the last_seq is checked only for + * non-aggregate cases, where only one MPDU at a time is + * released. + * For Riva, Pronto, and Northstar, the last_seq is checked to + * filter out late-arriving rx frames, whose sequence number + * will be less than the first MPDU in this release batch. + */ + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, + head_msdu)); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + cdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } + /* + * If the rx reorder timeout is handled by host SW rather than the + * target's rx reorder logic, then stop the timer here. + * (If there are remaining rx holes, then the timer will be restarted.) + */ + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned idx_start, + unsigned idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_pdev_t *pdev; + unsigned win_sz; + uint8_t win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + cdf_nbuf_t head_msdu = NULL; + cdf_nbuf_t tail_msdu = NULL; + + pdev = vdev->pdev; + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* a idx_end value of 0xffff means to flush the entire array */ + if (idx_end == 0xffff) { + idx_end = idx_start; + /* + * The array is being flushed in entirety because the block + * ack window has been shifted to a new position that does not + * overlap with the old position. (Or due to reception of a + * DELBA.) + * Thus, since the block ack window is essentially being reset, + * reset the "next release index". + */ + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(0 /*n/a */, win_sz, win_sz_mask); + } else { + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + } + + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[idx_start]; + idx_start = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx_start, win_sz, win_sz_mask); + + if (rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + if (head_msdu == NULL) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + continue; + } + cdf_nbuf_set_next(tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = + rx_reorder_array_elem->tail = NULL; + } + } while (idx_start != idx_end); + + ol_rx_defrag_waitlist_remove(peer, tid); + + if (head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu)); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + cdf_nbuf_set_next(tail_msdu, NULL); + if (action == htt_rx_flush_release) { + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } else { + do { + cdf_nbuf_t next; + next = cdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, + head_msdu); + head_msdu = next; + } while (head_msdu); + } + } + /* + * If the rx reorder array is empty, then reset the last_seq value - + * it is likely that a BAR or a sequence number shift caused the + * sequence number to jump, so the old last_seq value is not relevant. + */ + if (OL_RX_REORDER_NO_HOLES(&peer->tids_rx_reorder[tid])) + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned tid, unsigned *idx_end) +{ + unsigned win_sz, win_sz_mask; + unsigned idx_start = 0, tmp_idx = 0; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + /* bypass the initial hole */ + while (tmp_idx != idx_start && + !peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* bypass the present frames following the initial hole */ + while (tmp_idx != idx_start && + peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* + * idx_end is exclusive rather than inclusive. + * In other words, it is the index of the first slot of the second + * hole, rather than the index of the final present frame following + * the first hole. + */ + *idx_end = tmp_idx; +} + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer) +{ + int tid; + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_flush(vdev, peer, tid, 0, 0, + htt_rx_flush_discard); + } + OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer); +} + +/* functions called by HTT */ + +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed) +{ + uint8_t round_pwr2_win_sz; + unsigned array_size; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer == NULL) + return; + + if (pdev->cfg.host_addba) { + ol_ctrl_rx_addba_complete(pdev->ctrl_pdev, + &peer->mac_addr.raw[0], tid, failed); + } + if (failed) + return; + + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + rx_reorder = &peer->tids_rx_reorder[tid]; + + TXRX_ASSERT2(win_sz <= 64); + rx_reorder->win_sz = win_sz; + round_pwr2_win_sz = OL_RX_REORDER_ROUND_PWR2(win_sz); + array_size = + round_pwr2_win_sz * sizeof(struct ol_rx_reorder_array_elem_t); + rx_reorder->array = cdf_mem_malloc(array_size); + TXRX_ASSERT1(rx_reorder->array); + cdf_mem_set(rx_reorder->array, array_size, 0x0); + + rx_reorder->win_sz_mask = round_pwr2_win_sz - 1; + rx_reorder->num_mpdus = 0; + + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(start_seq_num, rx_reorder->win_sz, + rx_reorder->win_sz_mask); +} + +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid) +{ + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer == NULL) + return; + + peer->tids_next_rel_idx[tid] = 0xffff; /* invalid value */ + rx_reorder = &peer->tids_rx_reorder[tid]; + + /* check that there really was a block ack agreement */ + TXRX_ASSERT1(rx_reorder->win_sz_mask != 0); + /* + * Deallocate the old rx reorder array. + * The call to ol_rx_reorder_init below + * will reset rx_reorder->array to point to + * the single-element statically-allocated reorder array + * used for non block-ack cases. + */ + if (rx_reorder->array != &rx_reorder->base) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s, delete reorder array, tid:%d\n", __func__, tid); + cdf_mem_free(rx_reorder->array); + } + + /* set up the TID with default parameters (ARQ window size = 1) */ + ol_rx_reorder_init(rx_reorder, tid); +} + +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t idx_start, + uint16_t idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + int idx; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + vdev = peer->vdev; + else + return; + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + idx = idx_start & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + rx_desc = + htt_rx_msdu_desc_retrieve(htt_pdev, + rx_reorder_array_elem->head); + if (htt_rx_msdu_is_frag(htt_pdev, rx_desc)) { + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, + idx_start); + /* + * Assuming flush message sent seperately for frags + * and for normal frames + */ + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + return; + } + } + ol_rx_reorder_flush(vdev, peer, tid, idx_start, idx_end, action); + /* + * If the rx reorder timeout is handled by host SW, see if there are + * remaining rx holes that require the timer to be restarted. + */ + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); +} + +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + int seq_num_start, + int seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + unsigned win_sz_mask; + cdf_nbuf_t head_msdu = NULL; + cdf_nbuf_t tail_msdu = NULL; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + int seq_num, i = 0; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) + vdev = peer->vdev; + else + return; + + cdf_atomic_set(&peer->fw_pn_check, 1); + /*TODO: Fragmentation case */ + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + seq_num_start &= win_sz_mask; + seq_num_end &= win_sz_mask; + seq_num = seq_num_start; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[seq_num]; + + if (rx_reorder_array_elem->head) { + if (pn_ie_cnt && seq_num == (int)(pn_ie[i])) { + cdf_nbuf_t msdu, next_msdu, mpdu_head, + mpdu_tail; + static uint32_t last_pncheck_print_time; + /* Do not need to initialize as C does it */ + + int log_level; + uint32_t current_time_ms; + union htt_rx_pn_t pn = { 0 }; + int index, pn_len; + + mpdu_head = msdu = rx_reorder_array_elem->head; + mpdu_tail = rx_reorder_array_elem->tail; + + pn_ie_cnt--; + i++; + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, + msdu); + index = htt_rx_msdu_is_wlan_mcast( + pdev->htt_pdev, rx_desc) + ? txrx_sec_mcast + : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index]. + sec_type].len; + htt_rx_mpdu_desc_pn(htt_pdev, rx_desc, &pn, + pn_len); + + current_time_ms = cdf_system_ticks_to_msecs( + cdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - + last_pncheck_print_time)) { + last_pncheck_print_time = + current_time_ms; + log_level = TXRX_PRINT_LEVEL_WARN; + } else { + log_level = TXRX_PRINT_LEVEL_INFO2; + } + TXRX_PRINT(log_level, + "Tgt PN check failed - TID %d, peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5], pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc)); + ol_rx_err(pdev->ctrl_pdev, vdev->vdev_id, + peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(htt_pdev, + rx_desc), + OL_RX_ERR_PN, mpdu_head, NULL, 0); + + /* free all MSDUs within this MPDU */ + do { + next_msdu = cdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + else + msdu = next_msdu; + } while (1); + + } else { + if (head_msdu == NULL) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + } else { + cdf_nbuf_set_next( + tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + } + } + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } + seq_num = (seq_num + 1) & win_sz_mask; + } while (seq_num != seq_num_end); + + if (head_msdu) { + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + cdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } +} + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_REORDER_TRACE_SIZE_LOG2; + pdev->rx_reorder_trace.idx = 0; + pdev->rx_reorder_trace.cnt = 0; + pdev->rx_reorder_trace.mask = num_elems - 1; + pdev->rx_reorder_trace.data = cdf_mem_malloc( + sizeof(*pdev->rx_reorder_trace.data) * num_elems); + if (!pdev->rx_reorder_trace.data) + return A_NO_MEMORY; + + while (--num_elems >= 0) + pdev->rx_reorder_trace.data[num_elems].seq_num = 0xffff; + + return A_OK; +} + +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev) +{ + cdf_mem_free(pdev->rx_reorder_trace.data); +} + +void +ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, uint16_t seq_num, int num_mpdus) +{ + uint32_t idx = pdev->rx_reorder_trace.idx; + + pdev->rx_reorder_trace.data[idx].tid = tid; + pdev->rx_reorder_trace.data[idx].reorder_idx = reorder_idx; + pdev->rx_reorder_trace.data[idx].seq_num = seq_num; + pdev->rx_reorder_trace.data[idx].num_mpdus = num_mpdus; + pdev->rx_reorder_trace.cnt++; + idx++; + pdev->rx_reorder_trace.idx = idx & pdev->rx_reorder_trace.mask; +} + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit) +{ + static int print_count; + uint32_t i, start, end; + uint64_t cnt; + int elems; + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_reorder_trace.idx; + if (pdev->rx_reorder_trace.data[end].seq_num == 0xffff) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_reorder_trace.cnt - + (pdev->rx_reorder_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_reorder_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + delta = elems - limit; + start += delta; + start &= pdev->rx_reorder_trace.mask; + cnt += delta; + } + + i = start; + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " log array seq"); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " count idx tid idx num (LSBs)"); + do { + uint16_t seq_num, reorder_idx; + seq_num = pdev->rx_reorder_trace.data[i].seq_num; + reorder_idx = pdev->rx_reorder_trace.data[i].reorder_idx; + if (seq_num < (1 << 14)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " %6lld %4d %3d %4d %4d (%d)", + cnt, i, pdev->rx_reorder_trace.data[i].tid, + reorder_idx, seq_num, seq_num & 63); + } else { + int err = TXRX_SEQ_NUM_ERR(seq_num); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " %6lld %4d err %d (%d MPDUs)", + cnt, i, err, + pdev->rx_reorder_trace.data[i].num_mpdus); + } + cnt++; + i++; + i &= pdev->rx_reorder_trace.mask; + } while (i != end); +} + +#endif /* ENABLE_RX_REORDER_TRACE */ diff --git a/core/dp/txrx/ol_rx_reorder.h b/core/dp/txrx/ol_rx_reorder.h new file mode 100644 index 0000000000..7629c6a9b2 --- /dev/null +++ b/core/dp/txrx/ol_rx_reorder.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_REORDER__H_ +#define _OL_RX_REORDER__H_ + +#include /* cdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +#include /* ol_rx_reorder_t */ + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned reorder_array_index, + cdf_nbuf_t head_msdu, cdf_nbuf_t tail_msdu); + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned seq_num_start, unsigned seq_num_end); + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned seq_num_start, + unsigned seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief - find end of first range of present MPDUs after the initial rx hole + * @param[in] peer - which sender's data is being checked + * @param[in] tid - which type of data is being checked + * @param[out] idx_end - the reorder array index holding the last MPDU in the + * range of in-order MPDUs that following the initial hole. + * Note that this is the index of the last in-order MPDU following the + * first hole, rather than the starting index of the second hole. + */ +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned tid, unsigned *idx_end); + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer); + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid); + +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, void *rx_mpdu_desc); + +/* + * Peregrine and Rome: do sequence number checking in the host + * for peer-TIDs without aggregation enabled + */ + +#define OL_RX_SEQ_NUM_CHECK(pdev, peer, tid, rx_mpdu_desc) \ + (pdev->rx.flags.dup_check && peer->tids_rx_reorder[tid].win_sz_mask == 0) ? \ + ol_rx_seq_num_check( \ + pdev, peer, tid, \ + rx_mpdu_desc) : \ + htt_rx_status_ok + +#endif /* _OL_RX_REORDER__H_ */ diff --git a/core/dp/txrx/ol_rx_reorder_timeout.c b/core/dp/txrx/ol_rx_reorder_timeout.c new file mode 100644 index 0000000000..cc2e2a32c7 --- /dev/null +++ b/core/dp/txrx/ol_rx_reorder_timeout.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* cdf_nbuf_t, etc. */ +#include +#include + +/* datapath internal interfaces */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_ASSERT, etc. */ +#include /* ol_rx_reorder_flush, etc. */ + +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + if (!list_elem->active) { + /* this element has already been removed */ + return; + } + list_elem->active = 0; + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, list_elem, + reorder_timeout_list_elem); +} + +static void +ol_rx_reorder_timeout_start(struct ol_tx_reorder_cat_timeout_t + *rx_reorder_timeout_ac, uint32_t time_now_ms) +{ + uint32_t duration_ms; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + + list_elem = TAILQ_FIRST(&rx_reorder_timeout_ac->virtual_timer_list); + + duration_ms = list_elem->timestamp_ms - time_now_ms; + cdf_softirq_timer_start(&rx_reorder_timeout_ac->timer, duration_ms); +} + +static inline void +ol_rx_reorder_timeout_add(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + uint32_t time_now_ms; + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + int start; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + + list_elem->active = 1; + list_elem->peer = peer; + list_elem->tid = tid; + + /* set the expiration timestamp */ + time_now_ms = cdf_system_ticks_to_msecs(cdf_system_ticks()); + list_elem->timestamp_ms = + time_now_ms + rx_reorder_timeout_ac->duration_ms; + + /* add to the queue */ + start = TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list); + TAILQ_INSERT_TAIL(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + if (start) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); +} + +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + if (!peer) + return; + + /* + * If there are no holes, i.e. no queued frames, + * then timeout doesn't apply. + */ + if (peer->tids_rx_reorder[tid].num_mpdus == 0) + return; + + /* + * If the virtual timer for this peer-TID is already running, + * then leave it. + */ + if (peer->tids_rx_reorder[tid].timeout.active) + return; + + ol_rx_reorder_timeout_add(peer, tid); +} + +static void ol_rx_reorder_timeout(void *arg) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_rx_reorder_timeout_list_elem_t *list_elem, *tmp; + uint32_t time_now_ms; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + + rx_reorder_timeout_ac = (struct ol_tx_reorder_cat_timeout_t *)arg; + time_now_ms = cdf_system_ticks_to_msecs(cdf_system_ticks()); + + pdev = rx_reorder_timeout_ac->pdev; + cdf_spin_lock(&pdev->rx.mutex); +/* TODO: conditionally take mutex lock during regular rx */ + TAILQ_FOREACH_SAFE(list_elem, + &rx_reorder_timeout_ac->virtual_timer_list, + reorder_timeout_list_elem, tmp) { + unsigned idx_start, idx_end; + struct ol_txrx_peer_t *peer; + + if (list_elem->timestamp_ms > time_now_ms) + break; /* time has not expired yet for this element */ + + list_elem->active = 0; + /* remove the expired element from the list */ + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + + peer = list_elem->peer; + + idx_start = 0xffff; /* start from next_rel_idx */ + ol_rx_reorder_first_hole(peer, list_elem->tid, &idx_end); + ol_rx_reorder_flush(peer->vdev, + peer, + list_elem->tid, + idx_start, idx_end, htt_rx_flush_release); + } + /* restart the timer if unexpired elements are left in the list */ + if (!TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list)) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); + + cdf_spin_unlock(&pdev->rx.mutex); +} + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < CDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + /* init the per-AC timers */ + cdf_softirq_timer_init(pdev->osdev, + &rx_reorder_timeout_ac->timer, + ol_rx_reorder_timeout, + rx_reorder_timeout_ac); + /* init the virtual timer list */ + TAILQ_INIT(&rx_reorder_timeout_ac->virtual_timer_list); + rx_reorder_timeout_ac->pdev = pdev; + } + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VO].duration_ms = 40; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VI].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BE].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BK].duration_ms = 100; +} + +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer) +{ + int tid; + + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + if (peer->tids_rx_reorder[tid].timeout.active) + ol_rx_reorder_timeout_remove(peer, tid); + } +} + +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < CDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + cdf_softirq_timer_cancel(&rx_reorder_timeout_ac->timer); + cdf_softirq_timer_free(&rx_reorder_timeout_ac->timer); + } +} + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ diff --git a/core/dp/txrx/ol_rx_reorder_timeout.h b/core/dp/txrx/ol_rx_reorder_timeout.h new file mode 100644 index 0000000000..1f43871eeb --- /dev/null +++ b/core/dp/txrx/ol_rx_reorder_timeout.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_REORDER_TIMEOUT__H_ +#define _OL_RX_REORDER_TIMEOUT__H_ + +#include /* ol_txrx_pdev_t, etc. */ + +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, unsigned tid); +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid); +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer); + +#define OL_RX_REORDER_TIMEOUT_INIT ol_rx_reorder_timeout_init +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP ol_rx_reorder_timeout_peer_cleanup +#define OL_RX_REORDER_TIMEOUT_CLEANUP ol_rx_reorder_timeout_cleanup +#define OL_RX_REORDER_TIMEOUT_REMOVE ol_rx_reorder_timeout_remove +#define OL_RX_REORDER_TIMEOUT_UPDATE ol_rx_reorder_timeout_update +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) \ + (peer)->tids_rx_reorder[(tid)].timeout.active = 0 +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) \ + cdf_spin_lock(&(pdev)->rx.mutex) +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) \ + cdf_spin_unlock(&(pdev)->rx.mutex) + +#else + +#define OL_RX_REORDER_TIMEOUT_INIT(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_CLEANUP(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) /* no-op */ + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ + +#endif /* _OL_RX_REORDER_TIMEOUT__H_ */ diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c new file mode 100644 index 0000000000..f1941c2cba --- /dev/null +++ b/core/dp/txrx/ol_tx.c @@ -0,0 +1,1364 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* OS abstraction libraries */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_atomic_read, etc. */ +#include /* cdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* pdev stats */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_enqueue */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include + +#ifdef WLAN_FEATURE_FASTPATH +#include /* HIF_DEVICE */ +#include /* Layering violation, but required for fast path */ +#include +#include /* htc_endpoint */ + +int ce_send_fast(struct CE_handle *copyeng, cdf_nbuf_t *msdus, + unsigned int num_msdus, unsigned int transfer_id); +#endif /* WLAN_FEATURE_FASTPATH */ + +/* + * The TXRX module doesn't accept tx frames unless the target has + * enough descriptors for them. + * For LL, the TXRX descriptor pool is sized to match the target's + * descriptor pool. Hence, if the descriptor allocation in TXRX + * succeeds, that guarantees that the target has room to accept + * the new tx frame. + */ +#define ol_tx_prepare_ll(tx_desc, vdev, msdu, msdu_info) \ + do { \ + struct ol_txrx_pdev_t *pdev = vdev->pdev; \ + (msdu_info)->htt.info.frame_type = pdev->htt_pkt_type; \ + tx_desc = ol_tx_desc_ll(pdev, vdev, msdu, msdu_info); \ + if (cdf_unlikely(!tx_desc)) { \ + TXRX_STATS_MSDU_LIST_INCR( \ + pdev, tx.dropped.host_reject, msdu); \ + return msdu; /* the list of unaccepted MSDUs */ \ + } \ + } while (0) + +#define ol_tx_prepare_tso(vdev, msdu, msdu_info) \ + do { \ + msdu_info.tso_info.curr_seg = NULL; \ + if (cdf_nbuf_is_tso(msdu)) { \ + int num_seg = cdf_nbuf_get_tso_num_seg(msdu); \ + msdu_info.tso_info.tso_seg_list = NULL; \ + msdu_info.tso_info.num_segs = num_seg; \ + while (num_seg) { \ + struct cdf_tso_seg_elem_t *tso_seg = \ + ol_tso_alloc_segment(vdev->pdev); \ + if (tso_seg) { \ + tso_seg->next = \ + msdu_info.tso_info.tso_seg_list; \ + msdu_info.tso_info.tso_seg_list \ + = tso_seg; \ + num_seg--; \ + } else {\ + cdf_print("TSO seg alloc failed!\n"); \ + } \ + } \ + cdf_nbuf_get_tso_info(vdev->pdev->osdev, \ + msdu, &msdu_info.tso_info); \ + msdu_info.tso_info.curr_seg = \ + msdu_info.tso_info.tso_seg_list; \ + num_seg = msdu_info.tso_info.num_segs; \ + } else { \ + msdu_info.tso_info.is_tso = 0; \ + msdu_info.tso_info.num_segs = 1; \ + } \ + } while (0) + +/** + * ol_tx_send_data_frame() - send data frame + * @sta_id: sta id + * @skb: skb + * @proto_type: proto type + * + * Return: skb/NULL for success + */ +cdf_nbuf_t ol_tx_send_data_frame(uint8_t sta_id, cdf_nbuf_t skb, + uint8_t proto_type) +{ + void *cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_txrx_peer_t *peer; + cdf_nbuf_t ret; + CDF_STATUS status; + + if (cdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s:pdev is null", __func__); + return skb; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s:Invalid sta id", __func__); + return skb; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s:Invalid peer", __func__); + return skb; + } + + if (peer->state < ol_txrx_peer_state_conn) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: station to be yet registered..dropping pkt", __func__); + return skb; + } + + status = cdf_nbuf_map_single(cdf_ctx, skb, CDF_DMA_TO_DEVICE); + if (cdf_unlikely(status != CDF_STATUS_SUCCESS)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: nbuf map failed", __func__); + return skb; + } + + cdf_nbuf_trace_set_proto_type(skb, proto_type); + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (cdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (cdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + cdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + cdf_nbuf_set_next(skb, NULL); + ret = OL_TX_LL(peer->vdev, skb); + if (ret) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: Failed to tx", __func__); + cdf_nbuf_unmap_single(cdf_ctx, ret, CDF_DMA_TO_DEVICE); + return ret; + } + + return NULL; +} + +#ifdef IPA_OFFLOAD +/** + * ol_tx_send_ipa_data_frame() - send IPA data frame + * @vdev: vdev + * @skb: skb + * + * Return: skb/ NULL is for success + */ +cdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev, + cdf_nbuf_t skb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + cdf_nbuf_t ret; + + if (cdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return skb; + } + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (cdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (cdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + cdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + cdf_nbuf_set_next(skb, NULL); + ret = OL_TX_LL((struct ol_txrx_vdev_t *)vdev, skb); + if (ret) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: Failed to tx", __func__); + return ret; + } + + return NULL; +} +#endif + + +#if defined(FEATURE_TSO) +cdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + cdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + int segments = 1; + + msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + ol_tx_prepare_tso(vdev, msdu, msdu_info); + segments = msdu_info.tso_info.num_segs; + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = cdf_nbuf_next(msdu); + /* init the current segment to the 1st segment in the list */ + while (segments) { + + if (msdu_info.tso_info.curr_seg) + NBUF_MAPPED_PADDR_LO(msdu) = msdu_info.tso_info. + curr_seg->seg.tso_frags[0].paddr_low_32; + + segments--; + + /** + * if this is a jumbo nbuf, then increment the number + * of nbuf users for each additional segment of the msdu. + * This will ensure that the skb is freed only after + * receiving tx completion for all segments of an nbuf + */ + if (segments) + cdf_nbuf_inc_users(msdu); + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_send(vdev->pdev, tx_desc, msdu); + + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg = + msdu_info.tso_info.curr_seg->next; + } + + cdf_nbuf_dec_num_frags(msdu); + + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_SEG(vdev->pdev); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev); + } + } /* while segments */ + + msdu = next; + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_MSDU_IDX(vdev->pdev); + TXRX_STATS_TSO_RESET_MSDU(vdev->pdev); + } + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else /* TSO */ + +cdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + cdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = cdf_nbuf_next(msdu); + ol_tx_send(vdev->pdev, tx_desc, msdu); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} +#endif /* TSO */ + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ol_tx_prepare_ll_fast() Alloc and prepare Tx descriptor + * + * Allocate and prepare Tx descriptor with msdu and fragment descritor + * inforamtion. + * + * @pdev: pointer to ol pdev handle + * @vdev: pointer to ol vdev handle + * @msdu: linked list of msdu packets + * @pkt_download_len: packet download length + * @ep_id: endpoint ID + * @msdu_info: Handle to msdu_info + * + * Return: Pointer to Tx descriptor + */ +static inline struct ol_tx_desc_t * +ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev, + ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu, + uint32_t pkt_download_len, uint32_t ep_id, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + uint32_t *htt_tx_desc; + void *htc_hdr_vaddr; + u_int32_t num_frags, i; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (cdf_unlikely(!tx_desc)) + return NULL; + + tx_desc->netbuf = msdu; + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + tx_desc->pkt_type = ol_tx_frm_tso; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu); + } else { + tx_desc->pkt_type = ol_tx_frm_std; + } + + htt_tx_desc = tx_desc->htt_tx_desc; + + /* Make sure frags num is set to 0 */ + /* + * Do this here rather than in hardstart, so + * that we can hopefully take only one cache-miss while + * accessing skb->cb. + */ + + /* HTT Header */ + /* TODO : Take care of multiple fragments */ + + /* TODO: Precompute and store paddr in ol_tx_desc_t */ + /* Virtual address of the HTT/HTC header, added by driver */ + htc_hdr_vaddr = (char *)htt_tx_desc - HTC_HEADER_LEN; + htt_tx_desc_init(pdev->htt_pdev, htt_tx_desc, + tx_desc->htt_tx_desc_paddr, tx_desc->id, msdu, + &msdu_info->htt, &msdu_info->tso_info, + NULL, vdev->opmode == wlan_op_mode_ocb); + + num_frags = cdf_nbuf_get_num_frags(msdu); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > CVG_NBUF_MAX_EXTRA_FRAGS) ? + CVG_NBUF_MAX_EXTRA_FRAGS : num_frags; +#if defined(HELIUMPLUS_PADDR64) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUSPADDR64) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags-1); +#endif /* defined(HELIUMPLUS_PADDR64) */ + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + cdf_size_t frag_len; + u_int32_t frag_paddr; + + frag_len = cdf_nbuf_get_frag_len(msdu, i); + frag_paddr = cdf_nbuf_get_frag_paddr_lo(msdu, i); +#if defined(HELIUMPLUS_PADDR64) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, + i - 1, frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s:%d: htt_fdesc=%p frag_paddr=%u len=%zu\n", + __func__, __LINE__, tx_desc->htt_frag_desc, + frag_paddr, frag_len); + dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUSPADDR64) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, + i - 1, frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS_PADDR64) */ + } + } + + /* + * Do we want to turn on word_stream bit-map here ? For linux, non-TSO + * this is not required. We still have to mark the swap bit correctly, + * when posting to the ring + */ + /* Check to make sure, data download length is correct */ + + /* + * TODO : Can we remove this check and always download a fixed length ? + * */ + if (cdf_unlikely(cdf_nbuf_len(msdu) < pkt_download_len)) + pkt_download_len = cdf_nbuf_len(msdu); + + /* Fill the HTC header information */ + /* + * Passing 0 as the seq_no field, we can probably get away + * with it for the time being, since this is not checked in f/w + */ + /* TODO : Prefill this, look at multi-fragment case */ + HTC_TX_DESC_FILL(htc_hdr_vaddr, pkt_download_len, ep_id, 0); + + return tx_desc; +} +#if defined(FEATURE_TSO) +/** + * ol_tx_ll_fast() Update metadata information and send msdu to HIF/CE + * + * @vdev: handle to ol_txrx_vdev_t + * @msdu_list: msdu list to be sent out. + * + * Return: on success return NULL, pointer to nbuf when it fails to send. + */ +cdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len = + ((struct htt_pdev_t *)(pdev->htt_pdev))->download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + cdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + int segments = 1; + + msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + ol_tx_prepare_tso(vdev, msdu, msdu_info); + segments = msdu_info.tso_info.num_segs; + + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = cdf_nbuf_next(msdu); + /* init the current segment to the 1st segment in the list */ + while (segments) { + + if (msdu_info.tso_info.curr_seg) + NBUF_MAPPED_PADDR_LO(msdu) = msdu_info.tso_info. + curr_seg->seg.tso_frags[0].paddr_low_32; + + segments--; + + /** + * if this is a jumbo nbuf, then increment the number + * of nbuf users for each additional segment of the msdu. + * This will ensure that the skb is freed only after + * receiving tx completion for all segments of an nbuf + */ + if (segments) + cdf_nbuf_inc_users(msdu); + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + cdf_nbuf_get_tx_cksum(msdu); + switch (cdf_nbuf_get_exemption_type(msdu)) { + case CDF_NBUF_EXEMPT_NO_EXEMPTION: + case CDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case CDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + cdf_assert(0); + break; + } + + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + pkt_download_len, ep_id, + &msdu_info); + + if (cdf_likely(tx_desc)) { + /* + * If debug display is enabled, show the meta + * data being downloaded to the target via the + * HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + if ((0 == ce_send_fast(pdev->ce_tx_hdl, &msdu, + 1, ep_id))) { + /* + * The packet could not be sent. + * Free the descriptor, return the + * packet to the caller. + */ + ol_tx_desc_free(pdev, tx_desc); + return msdu; + } + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg = + msdu_info.tso_info.curr_seg->next; + } + + if (msdu_info.tso_info.is_tso) { + cdf_nbuf_dec_num_frags(msdu); + TXRX_STATS_TSO_INC_SEG(vdev->pdev); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev); + } + } else { + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + /* the list of unaccepted MSDUs */ + return msdu; + } + } /* while segments */ + + msdu = next; + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_MSDU_IDX(vdev->pdev); + TXRX_STATS_TSO_RESET_MSDU(vdev->pdev); + } + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else +cdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len = + ((struct htt_pdev_t *)(pdev->htt_pdev))->download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + cdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + cdf_nbuf_get_tx_cksum(msdu); + switch (cdf_nbuf_get_exemption_type(msdu)) { + case CDF_NBUF_EXEMPT_NO_EXEMPTION: + case CDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case CDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + cdf_assert(0); + break; + } + + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + pkt_download_len, ep_id, + &msdu_info); + + if (cdf_likely(tx_desc)) { + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = cdf_nbuf_next(msdu); + if ((0 == ce_send_fast(pdev->ce_tx_hdl, &msdu, 1, + ep_id))) { + /* The packet could not be sent */ + /* Free the descriptor, return the packet to the + * caller */ + ol_tx_desc_free(pdev, tx_desc); + return msdu; + } + msdu = next; + } else { + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + } + + return NULL; /* all MSDUs were accepted */ +} +#endif /* FEATURE_TSO */ +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ol_tx_ll_wrapper() wrapper to ol_tx_ll + * + */ +static inline cdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + struct ol_softc *hif_device = + (struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF); + + if (cdf_likely(hif_device && hif_device->fastpath_mode_on)) + msdu_list = ol_tx_ll_fast(vdev, msdu_list); + else + msdu_list = ol_tx_ll(vdev, msdu_list); + + return msdu_list; +} +#else +static inline cdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + return ol_tx_ll(vdev, msdu_list); +} +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN 400 +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS 5 +static void ol_tx_vdev_ll_pause_queue_send_base(struct ol_txrx_vdev_t *vdev) +{ + int max_to_accept; + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason) { + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + + /* + * Send as much of the backlog as possible, but leave some margin + * of unallocated tx descriptors that can be used for new frames + * being transmitted by other vdevs. + * Ideally there would be a scheduler, which would not only leave + * some margin for new frames for other vdevs, but also would + * fairly apportion the tx descriptors between multiple vdevs that + * have backlogs in their pause queues. + * However, the fairness benefit of having a scheduler for frames + * from multiple vdev's pause queues is not sufficient to outweigh + * the extra complexity. + */ + max_to_accept = vdev->pdev->tx_desc.num_free - + OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN; + while (max_to_accept > 0 && vdev->ll_pause.txq.depth) { + cdf_nbuf_t tx_msdu; + max_to_accept--; + vdev->ll_pause.txq.depth--; + tx_msdu = vdev->ll_pause.txq.head; + if (tx_msdu) { + vdev->ll_pause.txq.head = cdf_nbuf_next(tx_msdu); + if (NULL == vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + cdf_nbuf_set_next(tx_msdu, NULL); + NBUF_UPDATE_TX_PKT_COUNT(tx_msdu, + NBUF_TX_PKT_TXRX_DEQUEUE); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject the frame + * since we checked that there's room for it, though + * there's an infinitesimal possibility that between the + * time we checked the room available and now, a + * concurrent batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + cdf_nbuf_unmap(vdev->pdev->osdev, tx_msdu, + CDF_DMA_TO_DEVICE); + cdf_nbuf_tx_free(tx_msdu, NBUF_PKT_ERROR); + } + } + } + if (vdev->ll_pause.txq.depth) { + cdf_softirq_timer_cancel(&vdev->ll_pause.timer); + cdf_softirq_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + if (vdev->ll_pause.txq.depth >= vdev->ll_pause.max_q_depth) + vdev->ll_pause.q_overflow_cnt++; + } + + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} + +static cdf_nbuf_t +ol_tx_vdev_pause_queue_append(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu_list, uint8_t start_timer) +{ + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + while (msdu_list && + vdev->ll_pause.txq.depth < vdev->ll_pause.max_q_depth) { + cdf_nbuf_t next = cdf_nbuf_next(msdu_list); + NBUF_UPDATE_TX_PKT_COUNT(msdu_list, NBUF_TX_PKT_TXRX_ENQUEUE); + DPTRACE(cdf_dp_trace(msdu_list, + CDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(msdu_list)), + sizeof(cdf_nbuf_data(msdu_list)))); + + vdev->ll_pause.txq.depth++; + if (!vdev->ll_pause.txq.head) { + vdev->ll_pause.txq.head = msdu_list; + vdev->ll_pause.txq.tail = msdu_list; + } else { + cdf_nbuf_set_next(vdev->ll_pause.txq.tail, msdu_list); + } + vdev->ll_pause.txq.tail = msdu_list; + + msdu_list = next; + } + if (vdev->ll_pause.txq.tail) + cdf_nbuf_set_next(vdev->ll_pause.txq.tail, NULL); + + if (start_timer) { + cdf_softirq_timer_cancel(&vdev->ll_pause.timer); + cdf_softirq_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + } + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return msdu_list; +} + +/* + * Store up the tx frame in the vdev's tx queue if the vdev is paused. + * If there are too many frames in the tx queue, reject it. + */ +cdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list) +{ + uint16_t eth_type; + uint32_t paused_reason; + + if (msdu_list == NULL) + return NULL; + + paused_reason = vdev->ll_pause.paused_reason; + if (paused_reason) { + if (cdf_unlikely((paused_reason & + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED) == + paused_reason)) { + eth_type = (((struct ethernet_hdr_t *) + cdf_nbuf_data(msdu_list))-> + ethertype[0] << 8) | + (((struct ethernet_hdr_t *) + cdf_nbuf_data(msdu_list))->ethertype[1]); + if (ETHERTYPE_IS_EAPOL_WAPI(eth_type)) { + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + return msdu_list; + } + } + msdu_list = ol_tx_vdev_pause_queue_append(vdev, msdu_list, 1); + } else { + if (vdev->ll_pause.txq.depth > 0 || + vdev->pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + /* not paused, but there is a backlog of frms + from a prior pause or throttle off phase */ + msdu_list = ol_tx_vdev_pause_queue_append( + vdev, msdu_list, 0); + /* if throttle is disabled or phase is "on", + send the frame */ + if (vdev->pdev->tx_throttle.current_throttle_level == + THROTTLE_LEVEL_0 || + vdev->pdev->tx_throttle.current_throttle_phase == + THROTTLE_PHASE_ON) { + /* send as many frames as possible + from the vdevs backlog */ + ol_tx_vdev_ll_pause_queue_send_base(vdev); + } + } else { + /* not paused, no throttle and no backlog - + send the new frames */ + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + } + } + return msdu_list; +} + +/* + * Run through the transmit queues for all the vdevs and + * send the pending frames + */ +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + int max_to_send; /* tracks how many frames have been sent */ + cdf_nbuf_t tx_msdu; + struct ol_txrx_vdev_t *vdev = NULL; + uint8_t more; + + if (NULL == pdev) + return; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + + /* ensure that we send no more than tx_threshold frames at once */ + max_to_send = pdev->tx_throttle.tx_threshold; + + /* round robin through the vdev queues for the given pdev */ + + /* Potential improvement: download several frames from the same vdev + at a time, since it is more likely that those frames could be + aggregated together, remember which vdev was serviced last, + so the next call this function can resume the round-robin + traversing where the current invocation left off */ + do { + more = 0; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + if (vdev->ll_pause.paused_reason) { + cdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + tx_msdu = vdev->ll_pause.txq.head; + if (NULL == tx_msdu) { + cdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + max_to_send--; + vdev->ll_pause.txq.depth--; + + vdev->ll_pause.txq.head = + cdf_nbuf_next(tx_msdu); + + if (NULL == vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + + cdf_nbuf_set_next(tx_msdu, NULL); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject + * the frame, since we checked that there's + * room for it, though there's an infinitesimal + * possibility that between the time we checked + * the room available and now, a concurrent + * batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + cdf_nbuf_unmap(pdev->osdev, tx_msdu, + CDF_DMA_TO_DEVICE); + cdf_nbuf_tx_free(tx_msdu, + NBUF_PKT_ERROR); + } + } + /*check if there are more msdus to transmit */ + if (vdev->ll_pause.txq.depth) + more = 1; + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } while (more && max_to_send); + + vdev = NULL; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + cdf_softirq_timer_cancel(&pdev->tx_throttle.tx_timer); + cdf_softirq_timer_start( + &pdev->tx_throttle.tx_timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } +} + +void ol_tx_vdev_ll_pause_queue_send(void *context) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)context; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->tx_throttle.current_throttle_level != THROTTLE_LEVEL_0 && + pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + ol_tx_vdev_ll_pause_queue_send_base(vdev); +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +static inline int ol_txrx_tx_is_raw(enum ol_tx_spec tx_spec) +{ + return + tx_spec & + (ol_tx_spec_raw | ol_tx_spec_no_aggr | ol_tx_spec_no_encrypt); +} + +static inline uint8_t ol_txrx_tx_raw_subtype(enum ol_tx_spec tx_spec) +{ + uint8_t sub_type = 0x1; /* 802.11 MAC header present */ + + if (tx_spec & ol_tx_spec_no_aggr) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_S; + if (tx_spec & ol_tx_spec_no_encrypt) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + if (tx_spec & ol_tx_spec_nwifi_no_encrypt) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + return sub_type; +} + +cdf_nbuf_t +ol_tx_non_std_ll(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, cdf_nbuf_t msdu_list) +{ + cdf_nbuf_t msdu = msdu_list; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + cdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = cdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + msdu_info.tso_info.is_tso = 0; + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = cdf_nbuf_next(msdu); + + if (tx_spec != ol_tx_spec_std) { + if (tx_spec & ol_tx_spec_no_free) { + tx_desc->pkt_type = ol_tx_frm_no_free; + } else if (tx_spec & ol_tx_spec_tso) { + tx_desc->pkt_type = ol_tx_frm_tso; + } else if (tx_spec & ol_tx_spec_nwifi_no_encrypt) { + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_native_wifi, + sub_type); + } else if (ol_txrx_tx_is_raw(tx_spec)) { + /* different types of raw frames */ + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_raw, sub_type); + } + } + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + ol_tx_send(vdev->pdev, tx_desc, msdu); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#define OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, tx_msdu_info) \ + do { \ + if (OL_TX_ENCAP(vdev, tx_desc, msdu, &tx_msdu_info) != A_OK) { \ + cdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); \ + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); \ + if (tx_msdu_info.peer) { \ + /* remove the peer reference added above */ \ + ol_txrx_peer_unref_delete(tx_msdu_info.peer); \ + } \ + goto MSDU_LOOP_BOTTOM; \ + } \ + } while (0) +#else +#define OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, tx_msdu_info) /* no-op */ +#endif + +/* tx filtering is handled within the target FW */ +#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */ + +/** + * parse_ocb_tx_header() - Function to check for OCB + * TX control header on a packet and extract it if present + * + * @msdu: Pointer to OS packet (cdf_nbuf_t) + */ +#define OCB_HEADER_VERSION 1 +bool parse_ocb_tx_header(cdf_nbuf_t msdu, + struct ocb_tx_ctrl_hdr_t *tx_ctrl) +{ + struct ether_header *eth_hdr_p; + struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; + + /* Check if TX control header is present */ + eth_hdr_p = (struct ether_header *) cdf_nbuf_data(msdu); + if (eth_hdr_p->ether_type != CDF_SWAP_U16(ETHERTYPE_OCB_TX)) + /* TX control header is not present. Nothing to do.. */ + return true; + + /* Remove the ethernet header */ + cdf_nbuf_pull_head(msdu, sizeof(struct ether_header)); + + /* Parse the TX control header */ + tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *) cdf_nbuf_data(msdu); + + if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) { + if (tx_ctrl) + cdf_mem_copy(tx_ctrl, tx_ctrl_hdr, + sizeof(*tx_ctrl_hdr)); + } else { + /* The TX control header is invalid. */ + return false; + } + + /* Remove the TX control header */ + cdf_nbuf_pull_head(msdu, tx_ctrl_hdr->length); + return true; +} + +cdf_nbuf_t +ol_tx_non_std(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, cdf_nbuf_t msdu_list) +{ + return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); +} + +void +ol_txrx_data_tx_cb_set(ol_txrx_vdev_handle vdev, + ol_txrx_data_tx_cb callback, void *ctxt) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + pdev->tx_data_callback.func = callback; + pdev->tx_data_callback.ctxt = ctxt; +} + +void +ol_txrx_mgmt_tx_cb_set(ol_txrx_pdev_handle pdev, + uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt) +{ + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + pdev->tx_mgmt.callbacks[type].download_cb = download_cb; + pdev->tx_mgmt.callbacks[type].ota_ack_cb = ota_ack_cb; + pdev->tx_mgmt.callbacks[type].ctxt = ctxt; +} + +#if defined(HELIUMPLUS_PADDR64) +void dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc) +{ + uint32_t *frag_ptr_i_p; + int i; + + cdf_print("OL TX Descriptor 0x%p msdu_id %d\n", + tx_desc, tx_desc->index); + cdf_print("HTT TX Descriptor vaddr: 0x%p paddr: 0x%x\n", + tx_desc->htt_tx_desc, tx_desc->htt_tx_desc_paddr); + cdf_print("%s %d: Fragment Descriptor 0x%p\n", + __func__, __LINE__, tx_desc->htt_frag_desc); + + /* it looks from htt_tx_desc_frag() that tx_desc->htt_frag_desc + is already de-referrable (=> in virtual address space) */ + frag_ptr_i_p = tx_desc->htt_frag_desc; + + /* Dump 6 words of TSO flags */ + print_hex_dump(KERN_DEBUG, "MLE Desc:TSO Flags: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 24, true); + + frag_ptr_i_p += 6; /* Skip 6 words of TSO flags */ + + i = 0; + while (*frag_ptr_i_p) { + print_hex_dump(KERN_DEBUG, "MLE Desc:Frag Ptr: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 8, true); + i++; + if (i > 5) /* max 6 times: frag_ptr0 to frag_ptr5 */ + break; + else /* jump to next pointer - skip length */ + frag_ptr_i_p += 2; + } + return; +} +#endif /* HELIUMPLUS_PADDR64 */ + +int +ol_txrx_mgmt_send(ol_txrx_vdev_handle vdev, + cdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t tx_msdu_info; + + tx_msdu_info.tso_info.is_tso = 0; + + tx_msdu_info.htt.action.use_6mbps = use_6mbps; + tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.action.do_tx_complete = + pdev->tx_mgmt.callbacks[type].ota_ack_cb ? 1 : 0; + + /* + * FIX THIS: l2_hdr_type should only specify L2 header type + * The Peregrine/Rome HTT layer provides the FW with a "pkt type" + * that is a combination of L2 header type and 802.11 frame type. + * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt". + * But if the 802.11 frame type is "data", then the HTT pkt type is + * the L2 header type (more or less): 802.3 vs. Native WiFi + * (basic 802.11). + * (Or the header type can be "raw", which is any version of the 802.11 + * header, and also implies that some of the offloaded tx data + * processing steps may not apply.) + * For efficiency, the Peregrine/Rome HTT uses the msdu_info's + * l2_hdr_type field to program the HTT pkt type. Thus, this txrx SW + * needs to overload the l2_hdr_type to indicate whether the frame is + * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header. + * To fix this, the msdu_info's l2_hdr_type should be left specifying + * just the L2 header type. For mgmt frames, there should be a + * separate function to patch the HTT pkt type to store a "mgmt" value + * rather than the L2 header type. Then the HTT pkt type can be + * programmed efficiently for data frames, and the msdu_info's + * l2_hdr_type field won't be confusingly overloaded to hold the 802.11 + * frame type rather than the L2 header type. + */ + /* + * FIX THIS: remove duplication of htt_frm_type_mgmt and + * htt_pkt_type_mgmt + * The htt module expects a "enum htt_pkt_type" value. + * The htt_dxe module expects a "enum htt_frm_type" value. + * This needs to be cleaned up, so both versions of htt use a + * consistent method of specifying the frame type. + */ +#ifdef QCA_SUPPORT_INTEGRATED_SOC + /* tx mgmt frames always come with a 802.11 header */ + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt; +#else + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt; + tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt; +#endif + + tx_msdu_info.peer = NULL; + + cdf_nbuf_map_single(pdev->osdev, tx_mgmt_frm, CDF_DMA_TO_DEVICE); + /* For LL tx_comp_req is not used so initialized to 0 */ + tx_msdu_info.htt.action.tx_comp_req = 0; + tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, &tx_msdu_info); + /* FIX THIS - + * The FW currently has trouble using the host's fragments table + * for management frames. Until this is fixed, rather than + * specifying the fragment table to the FW, specify just the + * address of the initial fragment. + */ +#if defined(HELIUMPLUS_PADDR64) + /* dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll", + tx_desc); */ +#endif /* defined(HELIUMPLUS_PADDR64) */ + if (tx_desc) { + /* + * Following the call to ol_tx_desc_ll, frag 0 is the + * HTT tx HW descriptor, and the frame payload is in + * frag 1. + */ + htt_tx_desc_frags_table_set( + pdev->htt_pdev, + tx_desc->htt_tx_desc, + cdf_nbuf_get_frag_paddr_lo(tx_mgmt_frm, 1), + 0, 0); +#if defined(HELIUMPLUS_PADDR64) && defined(HELIUMPLUS_DEBUG) + dump_frag_desc( + "after htt_tx_desc_frags_table_set", + tx_desc); +#endif /* defined(HELIUMPLUS_PADDR64) */ + } + if (!tx_desc) { + cdf_nbuf_unmap_single(pdev->osdev, tx_mgmt_frm, + CDF_DMA_TO_DEVICE); + return -EINVAL; /* can't accept the tx mgmt frame */ + } + TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm); + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE; + + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + NBUF_SET_PACKET_TRACK(tx_desc->netbuf, NBUF_TX_PKT_MGMT_TRACK); + ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm, + htt_pkt_type_mgmt); + + return 0; /* accepted the tx mgmt frame */ +} + +void ol_txrx_sync(ol_txrx_pdev_handle pdev, uint8_t sync_cnt) +{ + htt_h2t_sync_msg(pdev->htt_pdev, sync_cnt); +} + +cdf_nbuf_t ol_tx_reinject(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu, uint16_t peer_id) +{ + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_INVALID; + msdu_info.peer = NULL; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + HTT_TX_DESC_POSTPONED_SET(*((uint32_t *) (tx_desc->htt_tx_desc)), true); + + htt_tx_desc_set_peer_id(tx_desc->htt_tx_desc, peer_id); + + ol_tx_send(vdev->pdev, tx_desc, msdu); + + return NULL; +} + +#if defined(FEATURE_TSO) +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) +{ + int i; + pdev->tso_seg_pool.pool_size = num_seg; + pdev->tso_seg_pool.num_free = num_seg; + + pdev->tso_seg_pool.array = NULL; + pdev->tso_seg_pool.array = cdf_mem_malloc(num_seg * + sizeof(struct cdf_tso_seg_elem_t)); + if (!pdev->tso_seg_pool.array) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s Could not allocate TSO array!\n", __func__); + return; + } + + pdev->tso_seg_pool.freelist = &pdev->tso_seg_pool.array[0]; + + for (i = 0; i < (num_seg - 1); i++) + pdev->tso_seg_pool.array[i].next = + &pdev->tso_seg_pool.array[i + 1]; + + pdev->tso_seg_pool.array[i].next = NULL; + + cdf_spinlock_init(&pdev->tso_seg_pool.tso_mutex); +} + +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + cdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (pdev->tso_seg_pool.array) { + cdf_mem_free(pdev->tso_seg_pool.array); + pdev->tso_seg_pool.array = NULL; + } + + pdev->tso_seg_pool.freelist = NULL; + pdev->tso_seg_pool.num_free = 0; + pdev->tso_seg_pool.pool_size = 0; + cdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + cdf_spinlock_destroy(&pdev->tso_seg_pool.tso_mutex); +} +#endif /* FEATURE_TSO */ diff --git a/core/dp/txrx/ol_tx.h b/core/dp/txrx/ol_tx.h new file mode 100644 index 0000000000..8f4bbfe3a5 --- /dev/null +++ b/core/dp/txrx/ol_tx.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx.h + * @brief Internal definitions for the high-level tx module. + */ +#ifndef _OL_TX__H_ +#define _OL_TX__H_ + +#include /* cdf_nbuf_t */ +#include +#include /* ol_txrx_vdev_handle */ + +#include /* ol_tx_desc_t, ol_txrx_msdu_info_t */ + +cdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list); +#ifdef WLAN_FEATURE_FASTPATH +cdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list); +#endif + +cdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, cdf_nbuf_t msdu_list); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define OL_TX_LL ol_tx_ll_queue +#else +#define OL_TX_LL ol_tx_ll +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void ol_tx_vdev_ll_pause_queue_send(void *context); +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tx_vdev_ll_pause_queue_send(void *context) +{ + return; +} +static inline +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif +cdf_nbuf_t +ol_tx_non_std_ll(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, cdf_nbuf_t msdu_list); + +cdf_nbuf_t +ol_tx_reinject(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu, uint16_t peer_id); + +void ol_txrx_mgmt_tx_complete(void *ctxt, cdf_nbuf_t netbuf, int err); + + +#if defined(FEATURE_TSO) +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg); +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev); +#endif +#endif /* _OL_TX__H_ */ diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c new file mode 100644 index 0000000000..3395b9103a --- /dev/null +++ b/core/dp/txrx/ol_tx_desc.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* CDF_NBUF_EXEMPT_NO_EXEMPTION, etc. */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_assert */ +#include /* cdf_spinlock */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* cdf_system_ticks */ +#endif + +#include /* htt_tx_desc_id */ + +#include /* ol_txrx_pdev_t */ +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +extern uint32_t *g_dbg_htt_desc_end_addr, *g_dbg_htt_desc_start_addr; +#endif + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->pkt_type != 0xff) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s Potential tx_desc corruption pkt_type:0x%x pdev:0x%p", + __func__, tx_desc->pkt_type, pdev); + cdf_assert(0); + } + if ((uint32_t *) tx_desc->htt_tx_desc < + g_dbg_htt_desc_start_addr + || (uint32_t *) tx_desc->htt_tx_desc > + g_dbg_htt_desc_end_addr) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s Potential htt_desc curruption:0x%p pdev:0x%p\n", + __func__, tx_desc->htt_tx_desc, pdev); + cdf_assert(0); + } +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->pkt_type = 0xff; +} +#ifdef QCA_COMPUTE_TX_DELAY +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->entry_timestamp_ticks != 0xffffffff) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s Timestamp:0x%x\n", + __func__, tx_desc->entry_timestamp_ticks); + cdf_assert(0); + } + tx_desc->entry_timestamp_ticks = cdf_system_ticks(); +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->entry_timestamp_ticks = 0xffffffff; +} +#endif +#else +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ + return; +} +#endif + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_desc_alloc() - allocate descriptor from freelist + * @pdev: pdev handle + * @vdev: vdev handle + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + cdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.freelist) { + pdev->tx_desc.num_free--; + tx_desc = &pdev->tx_desc.freelist->tx_desc; + pdev->tx_desc.freelist = pdev->tx_desc.freelist->next; + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + + } + cdf_spin_unlock_bh(&pdev->tx_mutex); + if (!tx_desc) + return NULL; + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + tx_desc->vdev = vdev; + cdf_atomic_inc(&vdev->tx_desc_count); +#endif + + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev); +} + +#else +/** + * ol_tx_desc_alloc() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @pool: flow pool + * + * Return: tx descriptor or NULL + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_tx_flow_pool_t *pool) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (pool) { + cdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc) { + tx_desc = &pool->freelist->tx_desc; + pool->freelist = pool->freelist->next; + if (cdf_unlikely(--pool->avail_desc < pool->stop_th)) { + pool->status = FLOW_POOL_ACTIVE_PAUSED; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + /* pause network queues */ + pdev->pause_cb(vdev->vdev_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } else { + cdf_spin_unlock_bh(&pool->flow_pool_lock); + } + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + } else { + cdf_spin_unlock_bh(&pool->flow_pool_lock); + pdev->pool_stats.pkt_drop_no_desc++; + } + } else { + pdev->pool_stats.pkt_drop_no_pool++; + } + + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + if (cdf_unlikely(msdu_info->htt.info.frame_type == htt_pkt_type_mgmt)) + return ol_tx_desc_alloc(pdev, vdev, pdev->mgmt_pool); + else + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#else +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#endif +#endif + +/* TBD: make this inline in the .h file? */ +struct ol_tx_desc_t *ol_tx_desc_find(struct ol_txrx_pdev_t *pdev, + uint16_t tx_desc_id) +{ + return &pdev->tx_desc.array[tx_desc_id].tx_desc; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_desc_free() - put descriptor to freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + cdf_spin_lock_bh(&pdev->tx_mutex); +#if defined(FEATURE_TSO) + if (tx_desc->pkt_type == ol_tx_frm_tso) { + if (cdf_unlikely(tx_desc->tso_desc == NULL)) + cdf_print("%s %d TSO desc is NULL!\n", + __func__, __LINE__); + else + ol_tso_free_segment(pdev, tx_desc->tso_desc); + } +#endif + ol_tx_desc_reset_pkt_type(tx_desc); + ol_tx_desc_reset_timestamp(tx_desc); + + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + pdev->tx_desc.freelist; + pdev->tx_desc.freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + pdev->tx_desc.num_free++; +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if ((cdf_atomic_read(&tx_desc->vdev->os_q_paused)) && + (cdf_atomic_read(&tx_desc->vdev->tx_desc_count) < + TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK)) { + /* wakeup netif_queue */ + cdf_atomic_set(&tx_desc->vdev->os_q_paused, 0); + ol_txrx_flow_control_cb(tx_desc->vdev, true); + } +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + cdf_atomic_dec(&tx_desc->vdev->tx_desc_count); + tx_desc->vdev = NULL; +#endif + cdf_spin_unlock_bh(&pdev->tx_mutex); +} + +#else +/** + * ol_tx_desc_free() - put descriptor to pool freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + struct ol_tx_flow_pool_t *pool = tx_desc->pool; + +#if defined(FEATURE_TSO) + if (tx_desc->pkt_type == ol_tx_frm_tso) { + if (cdf_unlikely(tx_desc->tso_desc == NULL)) + cdf_print("%s %d TSO desc is NULL!\n", + __func__, __LINE__); + else + ol_tso_free_segment(pdev, tx_desc->tso_desc); + } +#endif + ol_tx_desc_reset_pkt_type(tx_desc); + ol_tx_desc_reset_timestamp(tx_desc); + + cdf_spin_lock_bh(&pool->flow_pool_lock); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + pool->freelist; + pool->freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + pool->avail_desc++; + switch (pool->status) { + case FLOW_POOL_ACTIVE_PAUSED: + if (pool->avail_desc > pool->start_th) { + pdev->pause_cb(pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + } + break; + case FLOW_POOL_INVALID: + if (pool->avail_desc == pool->flow_pool_size) { + cdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_tx_free_invalid_flow_pool(pool); + cdf_print("%s %d pool is INVALID State!!\n", + __func__, __LINE__); + return; + } + break; + case FLOW_POOL_ACTIVE_UNPAUSED: + break; + default: + cdf_print("%s %d pool is INACTIVE State!!\n", + __func__, __LINE__); + break; + }; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + +} +#endif + +extern void +dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc); + +void +dump_pkt(cdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len) +{ + cdf_print("%s: Pkt: VA 0x%p PA 0x%x len %d\n", __func__, + cdf_nbuf_data(nbuf), nbuf_paddr, len); + print_hex_dump(KERN_DEBUG, "Pkt: ", DUMP_PREFIX_NONE, 16, 4, + cdf_nbuf_data(nbuf), len, true); +} + +const uint32_t htt_to_ce_pkt_type[] = { + [htt_pkt_type_raw] = tx_pkt_type_raw, + [htt_pkt_type_native_wifi] = tx_pkt_type_native_wifi, + [htt_pkt_type_ethernet] = tx_pkt_type_802_3, + [htt_pkt_type_mgmt] = tx_pkt_type_mgmt, + [htt_pkt_type_eth2] = tx_pkt_type_eth2, + [htt_pkt_num_types] = 0xffffffff +}; + +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + unsigned int i; + uint32_t num_frags; + + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.action.cksum_offload = cdf_nbuf_get_tx_cksum(netbuf); + switch (cdf_nbuf_get_exemption_type(netbuf)) { + case CDF_NBUF_EXEMPT_NO_EXEMPTION: + case CDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case CDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + cdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + tx_desc->pkt_type = ol_tx_frm_tso; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, netbuf); + } else { + tx_desc->pkt_type = ol_tx_frm_std; + } + + /* initialize the HW tx descriptor */ + + htt_tx_desc_init(pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), netbuf, &msdu_info->htt, + &msdu_info->tso_info, + NULL, vdev->opmode == wlan_op_mode_ocb); + + /* + * Initialize the fragmentation descriptor. + * Skip the prefix fragment (HTT tx descriptor) that was added + * during the call to htt_tx_desc_init above. + */ + num_frags = cdf_nbuf_get_num_frags(netbuf); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > CVG_NBUF_MAX_EXTRA_FRAGS) + ? CVG_NBUF_MAX_EXTRA_FRAGS + : num_frags; +#if defined(HELIUMPLUS_PADDR64) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUSPADDR64) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags - 1); +#endif /* defined(HELIUMPLUS_PADDR64) */ + + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + cdf_size_t frag_len; + uint32_t frag_paddr; + + frag_len = cdf_nbuf_get_frag_len(netbuf, i); + frag_paddr = cdf_nbuf_get_frag_paddr_lo(netbuf, i); +#if defined(HELIUMPLUS_PADDR64) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, i - 1, + frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s:%d: htt_fdesc=%p frag_paddr=%u len=%zu\n", + __func__, __LINE__, tx_desc->htt_frag_desc, + frag_paddr, frag_len); + dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUSPADDR64) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, i - 1, + frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS_PADDR64) */ + } + } + +#if defined(HELIUMPLUS_DEBUG) + dump_frag_desc("ol_tx_desc_ll()", tx_desc); +#endif + return tx_desc; +} + +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error) +{ + struct ol_tx_desc_t *tx_desc, *tmp; + cdf_nbuf_t msdus = NULL; + + TAILQ_FOREACH_SAFE(tx_desc, tx_descs, tx_desc_list_elem, tmp) { + cdf_nbuf_t msdu = tx_desc->netbuf; + + cdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, msdu); +#endif + cdf_nbuf_unmap(pdev->osdev, msdu, CDF_DMA_TO_DEVICE); + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); + /* link the netbuf into a list to free as a batch */ + cdf_nbuf_set_next(msdu, msdus); + msdus = msdu; + } + /* free the netbufs as a batch */ + cdf_nbuf_tx_free(msdus, had_error); +} + +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error) +{ + int mgmt_type; + ol_txrx_mgmt_tx_cb ota_ack_cb; + char *trace_str; + + cdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, (tx_desc->netbuf)); +#endif + trace_str = (had_error) ? "OT:C:F:" : "OT:C:S:"; + cdf_nbuf_trace_update(tx_desc->netbuf, trace_str); + if (tx_desc->pkt_type == ol_tx_frm_no_free) { + /* free the tx desc but don't unmap or free the frame */ + if (pdev->tx_data_callback.func) { + cdf_nbuf_set_next(tx_desc->netbuf, NULL); + pdev->tx_data_callback.func(pdev->tx_data_callback.ctxt, + tx_desc->netbuf, had_error); + ol_tx_desc_free(pdev, tx_desc); + return; + } + /* let the code below unmap and free the frame */ + } + cdf_nbuf_unmap(pdev->osdev, tx_desc->netbuf, CDF_DMA_TO_DEVICE); + /* check the frame type to see what kind of special steps are needed */ + if ((tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) && + (tx_desc->pkt_type != 0xff)) { + uint32_t frag_desc_paddr_lo = 0; + +#if defined(HELIUMPLUS_PADDR64) + frag_desc_paddr_lo = tx_desc->htt_frag_desc_paddr; + /* FIX THIS - + * The FW currently has trouble using the host's fragments + * table for management frames. Until this is fixed, + * rather than specifying the fragment table to the FW, + * the host SW will specify just the address of the initial + * fragment. + * Now that the mgmt frame is done, the HTT tx desc's frags + * table pointer needs to be reset. + */ +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s %d: Frag Descriptor Reset [%d] to 0x%x\n", + __func__, __LINE__, tx_desc->index, + frag_desc_paddr_lo); +#endif /* HELIUMPLUS_DEBUG */ +#endif /* HELIUMPLUS_PADDR64 */ + htt_tx_desc_frags_table_set(pdev->htt_pdev, + tx_desc->htt_tx_desc, 0, + frag_desc_paddr_lo, 1); + + mgmt_type = tx_desc->pkt_type - OL_TXRX_MGMT_TYPE_BASE; + /* + * we already checked the value when the mgmt frame was + * provided to the txrx layer. + * no need to check it a 2nd time. + */ + ota_ack_cb = pdev->tx_mgmt.callbacks[mgmt_type].ota_ack_cb; + if (ota_ack_cb) { + void *ctxt; + ctxt = pdev->tx_mgmt.callbacks[mgmt_type].ctxt; + ota_ack_cb(ctxt, tx_desc->netbuf, had_error); + } + /* free the netbuf */ + cdf_nbuf_free(tx_desc->netbuf); + } else { + /* single regular frame */ + cdf_nbuf_set_next(tx_desc->netbuf, NULL); + cdf_nbuf_tx_free(tx_desc->netbuf, had_error); + } + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); +} + +#if defined(FEATURE_TSO) +/** + * htt_tso_alloc_segment() - function to allocate a TSO segment + * element + * @pdev: HTT pdev + * @tso_seg: This is the output. The TSO segment element. + * + * Allocates a TSO segment element from the free list held in + * the HTT pdev + * + * Return: none + */ +struct cdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev) +{ + struct cdf_tso_seg_elem_t *tso_seg = NULL; + + cdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (pdev->tso_seg_pool.freelist) { + pdev->tso_seg_pool.num_free--; + tso_seg = pdev->tso_seg_pool.freelist; + pdev->tso_seg_pool.freelist = pdev->tso_seg_pool.freelist->next; + } + cdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + if (!tso_seg) + return NULL; + + return tso_seg; +} + +/** + * ol_tso_free_segment() - function to free a TSO segment + * element + * @pdev: HTT pdev + * @tso_seg: The TSO segment element to be freed + * + * Returns a TSO segment element to the free list held in the + * HTT pdev + * + * Return: none + */ + +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct cdf_tso_seg_elem_t *tso_seg) +{ + cdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + tso_seg->next = pdev->tso_seg_pool.freelist; + pdev->tso_seg_pool.freelist = tso_seg; + pdev->tso_seg_pool.num_free++; + cdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); +} +#endif diff --git a/core/dp/txrx/ol_tx_desc.h b/core/dp/txrx/ol_tx_desc.h new file mode 100644 index 0000000000..5094c4236c --- /dev/null +++ b/core/dp/txrx/ol_tx_desc.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_desc.h + * @brief API definitions for the tx descriptor module within the data SW. + */ +#ifndef _OL_TX_DESC__H_ +#define _OL_TX_DESC__H_ + +#include /* TAILQ_HEAD */ +#include /* cdf_nbuf_t */ +#include /* ol_tx_desc_t */ +#include /*TXRX_ASSERT2 */ + +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Allocate and initialize a tx descriptor for a LL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * For LL, this includes filling in a fragmentation descriptor to + * specify to the MAC HW where to find the tx frame's fragments. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + +/** + * @brief Use a tx descriptor ID to find the corresponding desriptor object. + * + * @param pdev - the data physical device sending the data + * @param tx_desc_id - the ID of the descriptor in question + * @return the descriptor object that has the specified ID + */ +struct ol_tx_desc_t *ol_tx_desc_find(struct ol_txrx_pdev_t *pdev, + uint16_t tx_desc_id); + +/** + * @brief Free a list of tx descriptors and the tx frames they refer to. + * @details + * Free a batch of "standard" tx descriptors and their tx frames. + * Free each tx descriptor, by returning it to the freelist. + * Unmap each netbuf, and free the netbufs as a batch. + * Irregular tx frames like TSO or managment frames that require + * special handling are processed by the ol_tx_desc_frame_free_nonstd + * function rather than this function. + * + * @param pdev - the data physical device that sent the data + * @param tx_descs - a list of SW tx descriptors for the tx frames + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error); + +/** + * @brief Free a non-standard tx frame and its tx descriptor. + * @details + * Check the tx frame type (e.g. TSO vs. management) to determine what + * special steps, if any, need to be performed prior to freeing the + * tx frame and its tx descriptor. + * This function can also be used to free single standard tx frames. + * After performing any special steps based on tx frame type, free the + * tx descriptor, i.e. return it to the freelist, and unmap and + * free the netbuf referenced by the tx descriptor. + * + * @param pdev - the data physical device that sent the data + * @param tx_desc - the SW tx descriptor for the tx frame that was sent + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error); + +/* + * @brief Determine the ID of a tx descriptor. + * + * @param pdev - the physical device that is sending the data + * @param tx_desc - the descriptor whose ID is being determined + * @return numeric ID that uniquely identifies the tx descriptor + */ +static inline uint16_t +ol_tx_desc_id(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + TXRX_ASSERT2(((union ol_tx_desc_list_elem_t *)tx_desc - + pdev->tx_desc.array) < pdev->tx_desc.pool_size); + return (uint16_t) + ((union ol_tx_desc_list_elem_t *)tx_desc - pdev->tx_desc.array); +} + +/* + * @brief Retrieves the beacon headr for the vdev + * @param pdev - opaque pointe to scn + * @param vdevid - vdev id + * @return void pointer to the beacon header for the given vdev + */ + +void *ol_ath_get_bcn_header(ol_pdev_handle pdev, A_UINT32 vdev_id); + +/* + * @brief Free a tx descriptor, without freeing the matching frame. + * @details + * This function is using during the function call that submits tx frames + * into the txrx layer, for cases where a tx descriptor is successfully + * allocated, but for other reasons the frame could not be accepted. + * + * @param pdev - the data physical device that is sending the data + * @param tx_desc - the descriptor being freed + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc); + +#if defined(FEATURE_TSO) +struct cdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev); + +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct cdf_tso_seg_elem_t *tso_seg); +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool); +#else +static inline int ol_tx_free_invalid_flow_pool(void *pool) +{ + return 0; +} +#endif + +#endif /* _OL_TX_DESC__H_ */ diff --git a/core/dp/txrx/ol_tx_queue.c b/core/dp/txrx/ol_tx_queue.c new file mode 100644 index 0000000000..d24ae0bb2f --- /dev/null +++ b/core/dp/txrx/ol_tx_queue.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_atomic_read, etc. */ +#include /* ol_cfg_addba_retry */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync, ol_tx_addba_conf */ +#include /* ol_ctrl_addba_req */ +#include /* TXRX_ASSERT1, etc. */ +#include /* pdev stats */ +#include /* ol_tx_desc, ol_tx_desc_frame_list_free */ +#include /* ol_tx_vdev_ll_pause_queue_send */ +#include +#include /* ENABLE_TX_QUEUE_LOG */ +#include /* bool */ + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason |= reason; + vdev->ll_pause.q_pause_cnt++; + vdev->ll_pause.is_q_paused = true; + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_VDEV_PAUSE, + NULL, 0)); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason & reason) { + vdev->ll_pause.paused_reason &= ~reason; + if (!vdev->ll_pause.paused_reason) { + vdev->ll_pause.is_q_paused = false; + vdev->ll_pause.q_unpause_cnt++; + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + ol_tx_vdev_ll_pause_queue_send(vdev); + } else { + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } else { + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_VDEV_UNPAUSE, + NULL, 0)); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void ol_txrx_vdev_flush(ol_txrx_vdev_handle vdev) +{ + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + cdf_softirq_timer_cancel(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + cdf_nbuf_t next = + cdf_nbuf_next(vdev->ll_pause.txq.head); + cdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + cdf_nbuf_unmap(vdev->pdev->osdev, + vdev->ll_pause.txq.head, + CDF_DMA_TO_DEVICE); + cdf_nbuf_tx_free(vdev->ll_pause.txq.head, + NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} + +#endif /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +/** + * ol_txrx_map_to_netif_reason_type() - map to netif_reason_type + * @reason: reason + * + * Return: netif_reason_type + */ +enum netif_reason_type +ol_txrx_map_to_netif_reason_type(uint32_t reason) +{ + switch (reason) { + case OL_TXQ_PAUSE_REASON_FW: + return WLAN_FW_PAUSE; + case OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED: + return WLAN_PEER_UNAUTHORISED; + case OL_TXQ_PAUSE_REASON_TX_ABORT: + return WLAN_TX_ABORT; + case OL_TXQ_PAUSE_REASON_VDEV_STOP: + return WLAN_VDEV_STOP; + case OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION: + return WLAN_THERMAL_MITIGATION; + default: + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: reason not supported %d\n", + __func__, reason); + return WLAN_REASON_TYPE_MAX; + } +} + +/** + * ol_txrx_vdev_pause() - pause vdev network queues + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (cdf_unlikely((!pdev) || (!pdev->pause_cb))) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pdev\n", __func__); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_NETIF_TX_DISABLE, netif_reason); +} + +/** + * ol_txrx_vdev_unpause() - unpause vdev network queues + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (cdf_unlikely((!pdev) || (!pdev->pause_cb))) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pdev\n", __func__); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_WAKE_ALL_NETIF_QUEUE, + netif_reason); + +} + +/** + * ol_txrx_pdev_pause() - pause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_pause(vdev, reason); + } + +} + +/** + * ol_txrx_pdev_unpause() - unpause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_pause(vdev, reason); + } + +} +#endif + +/*--- LL tx throttle queue code --------------------------------------------*/ +#if defined(QCA_SUPPORT_TX_THROTTLE) +uint8_t ol_tx_pdev_is_target_empty(void) +{ + /* TM TODO */ + return 1; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); + return; +} +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); + return; +} +#else +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_pdev_ll_pause_queue_send_all(pdev); + return; +} +#endif + +void ol_tx_pdev_throttle_phase_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + int ms; + enum throttle_level cur_level; + enum throttle_phase cur_phase; + + /* update the phase */ + pdev->tx_throttle.current_throttle_phase++; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX) + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) { + /* Traffic is stopped */ + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "throttle phase --> OFF\n"); + ol_txrx_thermal_pause(pdev); + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "start timer %d ms\n", ms); + cdf_softirq_timer_start(&pdev->tx_throttle. + phase_timer, ms); + } + } else { + /* Traffic can go */ + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "throttle phase --> ON\n"); + ol_txrx_thermal_unpause(pdev); + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "start timer %d ms\n", + ms); + cdf_softirq_timer_start(&pdev->tx_throttle.phase_timer, + ms); + } + } +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void ol_tx_pdev_throttle_tx_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + ol_tx_pdev_ll_pause_queue_send_all(pdev); +} +#endif + +void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level) +{ + int ms = 0; + + if (level >= THROTTLE_LEVEL_MAX) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s invalid throttle level set %d, ignoring\n", + __func__, level); + return; + } + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Setting throttle level %d\n", level); + + /* Set the current throttle level */ + pdev->tx_throttle.current_throttle_level = (enum throttle_level) level; + + /* Reset the phase */ + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + /* Start with the new time */ + ms = pdev->tx_throttle. + throttle_time_ms[level][THROTTLE_PHASE_OFF]; + + cdf_softirq_timer_cancel(&pdev->tx_throttle.phase_timer); + + if (level != THROTTLE_LEVEL_0) + cdf_softirq_timer_start(&pdev->tx_throttle.phase_timer, ms); +} + +/* This table stores the duty cycle for each level. + Example "on" time for level 2 with duty period 100ms is: + "on" time = duty_period_ms >> throttle_duty_cycle_table[2] + "on" time = 100 ms >> 2 = 25ms */ +static uint8_t g_throttle_duty_cycle_table[THROTTLE_LEVEL_MAX] = { 0, 1, 2, 4 }; + +void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, int period) +{ + int i; + + /* Set the current throttle level */ + pdev->tx_throttle.throttle_period_ms = period; + + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "level OFF ON\n"); + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) { + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] = + pdev->tx_throttle.throttle_period_ms >> + g_throttle_duty_cycle_table[i]; + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] = + pdev->tx_throttle.throttle_period_ms - + pdev->tx_throttle.throttle_time_ms[ + i][THROTTLE_PHASE_ON]; + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "%d %d %d\n", i, + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_OFF], + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_ON]); + } +} + +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) +{ + uint32_t throttle_period; + + pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0; + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + cdf_spinlock_init(&pdev->tx_throttle.mutex); + + throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev); + + ol_tx_throttle_init_period(pdev, throttle_period); + + cdf_softirq_timer_init(pdev->osdev, + &pdev->tx_throttle.phase_timer, + ol_tx_pdev_throttle_phase_timer, pdev, + CDF_TIMER_TYPE_SW); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + cdf_softirq_timer_init(pdev->osdev, + &pdev->tx_throttle.tx_timer, + ol_tx_pdev_throttle_tx_timer, pdev, + CDF_TIMER_TYPE_SW); +#endif + + pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD; +} +#endif /* QCA_SUPPORT_TX_THROTTLE */ +/*--- End of LL tx throttle queue code ---------------------------------------*/ diff --git a/core/dp/txrx/ol_tx_queue.h b/core/dp/txrx/ol_tx_queue.h new file mode 100644 index 0000000000..be809134a1 --- /dev/null +++ b/core/dp/txrx/ol_tx_queue.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_queue.h + * @brief API definitions for the tx frame queue module within the data SW. + */ +#ifndef _OL_TX_QUEUE__H_ +#define _OL_TX_QUEUE__H_ + +#include /* cdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* bool */ + +/*--- function prototypes for optional queue log feature --------------------*/ +#if defined(ENABLE_TX_QUEUE_LOG) + +void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes); +void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes); +void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes); +#define OL_TX_QUEUE_LOG_ENQUEUE ol_tx_queue_log_enqueue +#define OL_TX_QUEUE_LOG_DEQUEUE ol_tx_queue_log_dequeue +#define OL_TX_QUEUE_LOG_FREE ol_tx_queue_log_free + +#else + +#define OL_TX_QUEUE_LOG_ENQUEUE(pdev, msdu_info, frms, bytes) /* no-op */ +#define OL_TX_QUEUE_LOG_DEQUEUE(pdev, txq, frms, bytes) /* no-op */ +#define OL_TX_QUEUE_LOG_FREE(pdev, txq, tid, frms, bytes) /* no-op */ + +#endif /* TXRX_DEBUG_LEVEL > 5 */ + +#define ol_tx_enqueue(pdev, txq, tx_desc, tx_msdu_info) /* no-op */ +#define ol_tx_dequeue(pdev, ext_tid, txq, head, num_frames, credit, bytes) 0 +#define ol_tx_queue_free(pdev, txq, tid) /* no-op */ +#define ol_tx_queue_discard(pdev, flush, tx_descs) /* no-op */ + +void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data); + +#define OL_TX_QUEUE_LOG_SCHED( \ + pdev, credit, num_active_tids, active_bitmap, data) + +#define ol_tx_queues_display(pdev) /* no-op */ + +#define ol_tx_queue_decs_reinit(peer, peer_id) /* no-op */ + +#ifdef QCA_SUPPORT_TX_THROTTLE +/** + * @brief - initialize the throttle context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev); +#else +#define ol_tx_throttle_init(pdev) /*no op */ +#endif +#endif /* _OL_TX_QUEUE__H_ */ diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c new file mode 100644 index 0000000000..b4ba774bd2 --- /dev/null +++ b/core/dp/txrx/ol_tx_send.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* cdf_atomic_inc, etc. */ +#include /* cdf_os_spinlock */ +#include /* cdf_system_ticks, etc. */ +#include /* cdf_nbuf_t */ +#include /* ADF_NBUF_TX_EXT_TID_INVALID */ + +#include /* TAILQ */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ieee80211_frame, etc. */ +#include /* ethernet_hdr_t, etc. */ +#include /* ipv6_traffic_class */ +#endif + +#include /* ol_txrx_vdev_handle, etc. */ +#include /* htt_tx_compl_desc_id */ +#include /* htt_tx_status */ + +#include +#include /* ol_txrx_vdev_t, etc */ +#include /* ol_tx_desc_find, ol_tx_desc_frame_free */ +#ifdef QCA_COMPUTE_TX_DELAY +#endif +#include /* OL_TX_DESC_NO_REFS, etc. */ +#include +#include /* ol_tx_reinject */ + +#include /* ol_cfg_is_high_latency */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif + +#ifdef TX_CREDIT_RECLAIM_SUPPORT + +#define OL_TX_CREDIT_RECLAIM(pdev) \ + do { \ + if (cdf_atomic_read(&pdev->target_tx_credit) < \ + ol_cfg_tx_credit_lwm(pdev->ctrl_pdev)) { \ + ol_osif_ath_tasklet(pdev->osdev); \ + } \ + } while (0) + +#else + +#define OL_TX_CREDIT_RECLAIM(pdev) + +#endif /* TX_CREDIT_RECLAIM_SUPPORT */ + +#if defined(TX_CREDIT_RECLAIM_SUPPORT) +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ +#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) \ + cdf_atomic_add( \ + factor * htt_tx_msdu_credit(msdu), &pdev->target_tx_credit) +#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) \ + OL_TX_TARGET_CREDIT_ADJUST(-1, pdev, msdu) +#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) \ + OL_TX_TARGET_CREDIT_ADJUST(1, pdev, msdu) +#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) \ + cdf_atomic_add(-1 * delta, &pdev->target_tx_credit) +#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) \ + cdf_atomic_add(delta, &pdev->target_tx_credit) +#else +/* + * LL does not need to keep track of target credit. + * Since the host tx descriptor pool size matches the target's, + * we know the target has space for the new tx frame if the host's + * tx descriptor allocation succeeded. + */ +#define OL_TX_TARGET_CREDIT_ADJUST(factor, pdev, msdu) /* no-op */ +#define OL_TX_TARGET_CREDIT_DECR(pdev, msdu) /* no-op */ +#define OL_TX_TARGET_CREDIT_INCR(pdev, msdu) /* no-op */ +#define OL_TX_TARGET_CREDIT_DECR_INT(pdev, delta) /* no-op */ +#define OL_TX_TARGET_CREDIT_INCR_INT(pdev, delta) /* no-op */ +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev) \ + do { \ + struct ol_txrx_vdev_t *vdev; \ + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { \ + if (cdf_atomic_read(&vdev->os_q_paused) && \ + (vdev->tx_fl_hwm != 0)) { \ + cdf_spin_lock(&pdev->tx_mutex); \ + if (pdev->tx_desc.num_free > \ + vdev->tx_fl_hwm) { \ + cdf_atomic_set(&vdev->os_q_paused, 0); \ + cdf_spin_unlock(&pdev->tx_mutex); \ + ol_txrx_flow_control_cb(vdev, true);\ + } \ + else { \ + cdf_spin_unlock(&pdev->tx_mutex); \ + } \ + } \ + } \ + } while (0) +#else +#define OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev) +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +static inline uint16_t +ol_tx_send_base(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, cdf_nbuf_t msdu) +{ + int msdu_credit_consumed; + + TX_CREDIT_DEBUG_PRINT("TX %d bytes\n", cdf_nbuf_len(msdu)); + TX_CREDIT_DEBUG_PRINT(" Decrease credit %d - 1 = %d, len:%d.\n", + cdf_atomic_read(&pdev->target_tx_credit), + cdf_atomic_read(&pdev->target_tx_credit) - 1, + cdf_nbuf_len(msdu)); + + msdu_credit_consumed = htt_tx_msdu_credit(msdu); + OL_TX_TARGET_CREDIT_DECR_INT(pdev, msdu_credit_consumed); + OL_TX_CREDIT_RECLAIM(pdev); + + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is processed + * before the tx completion message. However, under exceptional + * conditions the tx completion may be processed first. Thus, rather + * that assuming that reference (1) is done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + + OL_TX_DESC_REF_INIT(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + + return msdu_credit_consumed; +} + +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, cdf_nbuf_t msdu) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + NBUF_UPDATE_TX_PKT_COUNT(msdu, NBUF_TX_PKT_TXRX); + DPTRACE(cdf_dp_trace(msdu, CDF_DP_TRACE_TXRX_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(msdu)), + sizeof(cdf_nbuf_data(msdu)))); + failed = htt_tx_send_std(pdev->htt_pdev, msdu, id); + if (cdf_unlikely(failed)) { + OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +void +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + cdf_nbuf_t head_msdu, int num_msdus) +{ + cdf_nbuf_t rejected; + OL_TX_CREDIT_RECLAIM(pdev); + + rejected = htt_tx_send_batch(pdev->htt_pdev, head_msdu, num_msdus); + while (cdf_unlikely(rejected)) { + struct ol_tx_desc_t *tx_desc; + uint16_t *msdu_id_storage; + cdf_nbuf_t next; + + next = cdf_nbuf_next(rejected); + msdu_id_storage = ol_tx_msdu_id_storage(rejected); + tx_desc = ol_tx_desc_find(pdev, *msdu_id_storage); + + OL_TX_TARGET_CREDIT_INCR(pdev, rejected); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + + rejected = next; + } +} + +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, enum htt_pkt_type pkt_type) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + NBUF_UPDATE_TX_PKT_COUNT(msdu, NBUF_TX_PKT_TXRX); + failed = htt_tx_send_nonstd(pdev->htt_pdev, msdu, id, pkt_type); + if (failed) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Error: freeing tx frame after htt_tx failed"); + OL_TX_TARGET_CREDIT_INCR_INT(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +static inline void +ol_tx_download_done_base(struct ol_txrx_pdev_t *pdev, + A_STATUS status, cdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + cdf_assert(tx_desc); + + /* + * If the download is done for + * the Management frame then + * call the download callback if registered + */ + if (tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) { + int tx_mgmt_index = tx_desc->pkt_type - OL_TXRX_MGMT_TYPE_BASE; + ol_txrx_mgmt_tx_cb download_cb = + pdev->tx_mgmt.callbacks[tx_mgmt_index].download_cb; + + if (download_cb) { + download_cb(pdev->tx_mgmt.callbacks[tx_mgmt_index].ctxt, + tx_desc->netbuf, status != A_OK); + } + } + + if (status != A_OK) { + OL_TX_TARGET_CREDIT_INCR(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* download err */); + } else { + if (OL_TX_DESC_NO_REFS(tx_desc)) { + /* + * The decremented value was zero - free the frame. + * Use the tx status recorded previously during + * tx completion handling. + */ + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + tx_desc->status != + htt_tx_status_ok); + } + } +} + +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, cdf_nbuf_t msdu, uint16_t msdu_id) +{ + ol_tx_download_done_base((struct ol_txrx_pdev_t *)pdev, status, msdu, + msdu_id); +} + +void +ol_tx_download_done_hl_retain(void *txrx_pdev, + A_STATUS status, + cdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + ol_tx_download_done_base(pdev, status, msdu, msdu_id); +} + +void +ol_tx_download_done_hl_free(void *txrx_pdev, + A_STATUS status, cdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + cdf_assert(tx_desc); + + ol_tx_download_done_base(pdev, status, msdu, msdu_id); + + if ((tx_desc->pkt_type != ol_tx_frm_no_free) && + (tx_desc->pkt_type < OL_TXRX_MGMT_TYPE_BASE)) { + cdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, status != A_OK); + } +} + +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + cdf_atomic_add(credit_delta, &pdev->orig_target_tx_credit); +} + +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + cdf_atomic_read(&pdev->target_tx_credit), + credit_delta, + cdf_atomic_read(&pdev->target_tx_credit) + + credit_delta); + cdf_atomic_add(credit_delta, &pdev->target_tx_credit); +} + +#ifdef QCA_COMPUTE_TX_DELAY + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus); +#define OL_TX_DELAY_COMPUTE ol_tx_delay_compute +#else +#define OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus) /* no-op */ +#endif /* QCA_COMPUTE_TX_DELAY */ + +#ifndef OL_TX_RESTORE_HDR +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +/* + * The following macros could have been inline functions too. + * The only rationale for choosing macros, is to force the compiler to inline + * the implementation, which cannot be controlled for actual "inline" functions, + * since "inline" is only a hint to the compiler. + * In the performance path, we choose to force the inlining, in preference to + * type-checking offered by the actual inlined functions. + */ +#define ol_tx_msdu_complete_batch(_pdev, _tx_desc, _tx_descs, _status) \ + TAILQ_INSERT_TAIL(&(_tx_descs), (_tx_desc), tx_desc_list_elem) +#ifndef ATH_11AC_TXCOMPACT +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + cdf_atomic_init(&(_tx_desc)->ref_cnt); \ + /* restore orginal hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + cdf_nbuf_unmap((_pdev)->osdev, (_netbuf), CDF_DMA_TO_DEVICE); \ + cdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (cdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) +#else /*!ATH_11AC_TXCOMPACT */ +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + /* restore orginal hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + cdf_nbuf_unmap((_pdev)->osdev, (_netbuf), CDF_DMA_TO_DEVICE); \ + cdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (cdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) + +#endif /*!ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_SINGLE_COMPLETIONS +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc), \ + (_netbuf), (_lcl_freelist), \ + _tx_desc_last) +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + do { \ + if (cdf_likely((_tx_desc)->pkt_type == ol_tx_frm_std)) { \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc),\ + (_netbuf), (_lcl_freelist), \ + (_tx_desc_last)); \ + } else { \ + ol_tx_desc_frame_free_nonstd( \ + (_pdev), (_tx_desc), \ + (_status) != htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#else /* !QCA_TX_SINGLE_COMPLETIONS */ +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + ol_tx_msdus_complete_batch((_pdev), (_tx_desc), (_tx_descs), (_status)) +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + do { \ + if (cdf_likely((_tx_desc)->pkt_type == ol_tx_frm_std)) { \ + ol_tx_msdu_complete_batch((_pdev), (_tx_desc), \ + (_tx_descs), (_status)); \ + } else { \ + ol_tx_desc_frame_free_nonstd((_pdev), (_tx_desc), \ + (_status) != \ + htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#endif /* QCA_TX_SINGLE_COMPLETIONS */ + +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ + int i = 0; + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + */ + if (cdf_atomic_read(&pdev->tx_desc.array[i].tx_desc.ref_cnt)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "Warning: freeing tx frame " + "(no tx completion from the target)\n"); + ol_tx_desc_frame_free_nonstd(pdev, + &pdev->tx_desc.array[i]. + tx_desc, 1); + } + } +} + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits) +{ + ol_tx_target_credit_update(pdev, credits); + + /* UNPAUSE OS Q */ + OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev); +} + +/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of + ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored in + ol_tx_inspect_handler(). +*/ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *tx_desc_id_iterator) +{ + int i; + uint16_t *desc_ids = (uint16_t *) tx_desc_id_iterator; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + char *trace_str; + + uint32_t byte_cnt = 0; + union ol_tx_desc_list_elem_t *td_array = pdev->tx_desc.array; + cdf_nbuf_t netbuf; + + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + + OL_TX_DELAY_COMPUTE(pdev, status, desc_ids, num_msdus); + + trace_str = (status) ? "OT:C:F:" : "OT:C:S:"; + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + tx_desc = &td_array[tx_desc_id].tx_desc; + tx_desc->status = status; + netbuf = tx_desc->netbuf; + + cdf_nbuf_trace_update(netbuf, trace_str); + /* Per SDU update of byte count */ + byte_cnt += cdf_nbuf_len(netbuf); + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_statistics( + pdev->ctrl_pdev, + HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc-> + htt_tx_desc))), + status != htt_tx_status_ok); + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, status); + } + NBUF_UPDATE_TX_PKT_COUNT(netbuf, NBUF_TX_PKT_FREE); +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + tx_desc->pkt_type = 0xff; +#ifdef QCA_COMPUTE_TX_DELAY + tx_desc->entry_timestamp_ticks = 0xffffffff; +#endif +#endif + } + + /* One shot protected access to pdev freelist, when setup */ + if (lcl_freelist) { + cdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + pdev->tx_desc.num_free += (uint16_t) num_msdus; + cdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + status != htt_tx_status_ok); + } + + OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL); + + /* UNPAUSE OS Q */ + OL_TX_FLOW_CT_UNPAUSE_OS_Q(pdev); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, num_msdus, byte_cnt); +} + +/* + * ol_tx_single_completion_handler performs the same tx completion + * processing as ol_tx_completion_handler, but for a single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *td_array = pdev->tx_desc.array; + cdf_nbuf_t netbuf; + + tx_desc = &td_array[tx_desc_id].tx_desc; + tx_desc->status = status; + netbuf = tx_desc->netbuf; + + NBUF_UPDATE_TX_PKT_COUNT(netbuf, NBUF_TX_PKT_FREE); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, cdf_nbuf_len(netbuf)); + + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + status != htt_tx_status_ok); + } + + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + cdf_atomic_read(&pdev->target_tx_credit), + 1, cdf_atomic_read(&pdev->target_tx_credit) + 1); + + + cdf_atomic_add(1, &pdev->target_tx_credit); +} + +/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of + ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored here. + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator) +{ + uint16_t vdev_id, i; + struct ol_txrx_vdev_t *vdev; + uint16_t *desc_ids = (uint16_t *) tx_desc_id_iterator; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *td_array = pdev->tx_desc.array; + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + cdf_nbuf_t netbuf; + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + tx_desc = &td_array[tx_desc_id].tx_desc; + netbuf = tx_desc->netbuf; + + /* find the "vdev" this tx_desc belongs to */ + vdev_id = HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc->htt_tx_desc))); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + /* vdev now points to the vdev for this descriptor. */ + +#ifndef ATH_11AC_TXCOMPACT + /* save this multicast packet to local free list */ + if (cdf_atomic_dec_and_test(&tx_desc->ref_cnt)) +#endif + { + /* for this function only, force htt status to be + "htt_tx_status_ok" + * for graceful freeing of this multicast frame + */ + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, + htt_tx_status_ok); + } + } + + if (lcl_freelist) { + cdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + cdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + htt_tx_status_discard); + } + TX_CREDIT_DEBUG_PRINT(" Increase HTT credit %d + %d = %d..\n", + cdf_atomic_read(&pdev->target_tx_credit), + num_msdus, + cdf_atomic_read(&pdev->target_tx_credit) + + num_msdus); + + OL_TX_TARGET_CREDIT_ADJUST(num_msdus, pdev, NULL); +} + +#ifdef QCA_COMPUTE_TX_DELAY + +void ol_tx_set_compute_interval(ol_txrx_pdev_handle pdev, uint32_t interval) +{ + pdev->tx_delay.avg_period_ticks = cdf_system_msecs_to_ticks(interval); +} + +void +ol_tx_packet_count(ol_txrx_pdev_handle pdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category) +{ + *out_packet_count = pdev->packet_count[category]; + *out_packet_loss_count = pdev->packet_loss_count[category]; + pdev->packet_count[category] = 0; + pdev->packet_loss_count[category] = 0; +} + +uint32_t ol_tx_delay_avg(uint64_t sum, uint32_t num) +{ + uint32_t sum32; + int shift = 0; + /* + * To avoid doing a 64-bit divide, shift the sum down until it is + * no more than 32 bits (and shift the denominator to match). + */ + while ((sum >> 32) != 0) { + sum >>= 1; + shift++; + } + sum32 = (uint32_t) sum; + num >>= shift; + return (sum32 + (num >> 1)) / num; /* round to nearest */ +} + +void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + int index; + uint32_t avg_delay_ticks; + struct ol_tx_delay_data *data; + + cdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + cdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + if (data->avgs.transmit_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.transmit_sum_ticks, + data->avgs.transmit_num); + *tx_delay_microsec = + cdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *tx_delay_microsec = 0; + } + if (data->avgs.queue_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.queue_sum_ticks, + data->avgs.queue_num); + *queue_delay_microsec = + cdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *queue_delay_microsec = 0; + } + + cdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, + uint16_t *report_bin_values, int category) +{ + int index, i, j; + struct ol_tx_delay_data *data; + + cdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + cdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + for (i = 0, j = 0; i < QCA_TX_DELAY_HIST_REPORT_BINS - 1; i++) { + uint16_t internal_bin_sum = 0; + while (j < (1 << i)) + internal_bin_sum += data->hist_bins_queue[j++]; + + report_bin_values[i] = internal_bin_sum; + } + report_bin_values[i] = data->hist_bins_queue[j]; /* overflow */ + + cdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID +static inline uint8_t *ol_tx_dest_addr_find(struct ol_txrx_pdev_t *pdev, + cdf_nbuf_t tx_nbuf) +{ + uint8_t *hdr_ptr; + void *datap = cdf_nbuf_data(tx_nbuf); + + if (pdev->frame_format == wlan_frm_fmt_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + hdr_ptr = datap; + } else { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid standard frame type: %d", + pdev->frame_format); + cdf_assert(0); + hdr_ptr = NULL; + } + return hdr_ptr; +} + +static uint8_t +ol_tx_delay_tid_from_l3_hdr(struct ol_txrx_pdev_t *pdev, + cdf_nbuf_t msdu, struct ol_tx_desc_t *tx_desc) +{ + uint16_t ethertype; + uint8_t *dest_addr, *l3_hdr; + int is_mgmt, is_mcast; + int l2_hdr_size; + + dest_addr = ol_tx_dest_addr_find(pdev, msdu); + if (NULL == dest_addr) + return ADF_NBUF_TX_EXT_TID_INVALID; + + is_mcast = IEEE80211_IS_MULTICAST(dest_addr); + is_mgmt = tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE; + if (is_mgmt) { + return (is_mcast) ? + OL_TX_NUM_TIDS + OL_TX_VDEV_DEFAULT_MGMT : + HTT_TX_EXT_TID_MGMT; + } + if (is_mcast) + return OL_TX_NUM_TIDS + OL_TX_VDEV_MCAST_BCAST; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr; + enet_hdr = (struct ethernet_hdr_t *)cdf_nbuf_data(msdu); + l2_hdr_size = sizeof(struct ethernet_hdr_t); + ethertype = + (enet_hdr->ethertype[0] << 8) | enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + struct llc_snap_hdr_t *llc_hdr; + llc_hdr = (struct llc_snap_hdr_t *) + (cdf_nbuf_data(msdu) + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr-> + ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *)(cdf_nbuf_data(msdu) + + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + } + l3_hdr = cdf_nbuf_data(msdu) + l2_hdr_size; + if (ETHERTYPE_IPV4 == ethertype) { + return (((struct ipv4_hdr_t *)l3_hdr)->tos >> 5) & 0x7; + } else if (ETHERTYPE_IPV6 == ethertype) { + return (ipv6_traffic_class((struct ipv6_hdr_t *)l3_hdr) >> 5) & + 0x7; + } else { + return ADF_NBUF_TX_EXT_TID_INVALID; + } +} +#endif + +static int ol_tx_delay_category(struct ol_txrx_pdev_t *pdev, uint16_t msdu_id) +{ +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID + struct ol_tx_desc_t *tx_desc = &pdev->tx_desc.array[msdu_id].tx_desc; + uint8_t tid; + + cdf_nbuf_t msdu = tx_desc->netbuf; + tid = cdf_nbuf_get_tid(msdu); + if (tid == ADF_NBUF_TX_EXT_TID_INVALID) { + tid = ol_tx_delay_tid_from_l3_hdr(pdev, msdu, tx_desc); + if (tid == ADF_NBUF_TX_EXT_TID_INVALID) { + /* TID could not be determined + (this is not an IP frame?) */ + return -EINVAL; + } + } + return tid; +#else + return 0; +#endif +} + +static inline int +ol_tx_delay_hist_bin(struct ol_txrx_pdev_t *pdev, uint32_t delay_ticks) +{ + int bin; + /* + * For speed, multiply and shift to approximate a divide. This causes + * a small error, but the approximation error should be much less + * than the other uncertainties in the tx delay computation. + */ + bin = (delay_ticks * pdev->tx_delay.hist_internal_bin_width_mult) >> + pdev->tx_delay.hist_internal_bin_width_shift; + if (bin >= QCA_TX_DELAY_HIST_INTERNAL_BINS) + bin = QCA_TX_DELAY_HIST_INTERNAL_BINS - 1; + + return bin; +} + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ + int i, index, cat; + uint32_t now_ticks = cdf_system_ticks(); + uint32_t tx_delay_transmit_ticks, tx_delay_queue_ticks; + uint32_t avg_time_ticks; + struct ol_tx_delay_data *data; + + cdf_assert(num_msdus > 0); + + /* + * keep static counters for total packet and lost packets + * reset them in ol_tx_delay(), function used to fetch the stats + */ + + cat = ol_tx_delay_category(pdev, desc_ids[0]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + + pdev->packet_count[cat] = pdev->packet_count[cat] + num_msdus; + if (status != htt_tx_status_ok) { + for (i = 0; i < num_msdus; i++) { + cat = ol_tx_delay_category(pdev, desc_ids[i]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + pdev->packet_loss_count[cat]++; + } + return; + } + + /* since we may switch the ping-pong index, provide mutex w. readers */ + cdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = pdev->tx_delay.cats[cat].in_progress_idx; + + data = &pdev->tx_delay.cats[cat].copies[index]; + + if (pdev->tx_delay.tx_compl_timestamp_ticks != 0) { + tx_delay_transmit_ticks = + now_ticks - pdev->tx_delay.tx_compl_timestamp_ticks; + /* + * We'd like to account for the number of MSDUs that were + * transmitted together, but we don't know this. All we know + * is the number of MSDUs that were acked together. + * Since the frame error rate is small, this is nearly the same + * as the number of frames transmitted together. + */ + data->avgs.transmit_sum_ticks += tx_delay_transmit_ticks; + data->avgs.transmit_num += num_msdus; + } + pdev->tx_delay.tx_compl_timestamp_ticks = now_ticks; + + for (i = 0; i < num_msdus; i++) { + uint16_t id = desc_ids[i]; + struct ol_tx_desc_t *tx_desc = &pdev->tx_desc.array[id].tx_desc; + int bin; + + tx_delay_queue_ticks = + now_ticks - tx_desc->entry_timestamp_ticks; + + data->avgs.queue_sum_ticks += tx_delay_queue_ticks; + data->avgs.queue_num++; + bin = ol_tx_delay_hist_bin(pdev, tx_delay_queue_ticks); + data->hist_bins_queue[bin]++; + } + + /* check if it's time to start a new average */ + avg_time_ticks = + now_ticks - pdev->tx_delay.cats[cat].avg_start_time_ticks; + if (avg_time_ticks > pdev->tx_delay.avg_period_ticks) { + pdev->tx_delay.cats[cat].avg_start_time_ticks = now_ticks; + index = 1 - index; + pdev->tx_delay.cats[cat].in_progress_idx = index; + cdf_mem_zero(&pdev->tx_delay.cats[cat].copies[index], + sizeof(pdev->tx_delay.cats[cat].copies[index])); + } + + cdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#endif /* QCA_COMPUTE_TX_DELAY */ diff --git a/core/dp/txrx/ol_tx_send.h b/core/dp/txrx/ol_tx_send.h new file mode 100644 index 0000000000..db48812023 --- /dev/null +++ b/core/dp/txrx/ol_tx_send.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_send.h + * @brief API definitions for the tx sendriptor module within the data SW. + */ +#ifndef _OL_TX_SEND__H_ +#define _OL_TX_SEND__H_ + +#include /* cdf_nbuf_t */ +#include /* ol_tx_send_t */ + +/** + * @flush the ol tx when surprise remove. + * + */ +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev); + +/** + * @brief Send a tx frame to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + */ +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, cdf_nbuf_t msdu); + +/** + * @brief Send a tx batch download to the target. + * @details + * This function is different from above in that + * it accepts a list of msdu's to be downloaded as a batch + * + * @param pdev - the phy dev + * @param msdu_list - the Head pointer to the Tx Batch + * @param num_msdus - Total msdus chained in msdu_list + */ + +int +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + cdf_nbuf_t msdu_list, int num_msdus); + +/** + * @brief Send a tx frame with a non-std header or payload type to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param pkt_type - what kind of non-std frame is being sent + */ +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, enum htt_pkt_type pkt_type); +#endif /* _OL_TX_SEND__H_ */ diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c new file mode 100644 index 0000000000..566a5ced16 --- /dev/null +++ b/core/dp/txrx/ol_txrx.c @@ -0,0 +1,3173 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* cdf_mem_malloc,free */ +#include /* cdf_device_t, cdf_print */ +#include /* cdf_spinlock */ +#include /* cdf_atomic_read */ + +/* Required for WLAN_FEATURE_FASTPATH */ +#include +/* header files for utilities */ +#include /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_is_high_latency */ +#include + +/* header files for HTT API */ +#include +#include + +/* header files for OS shim API */ +#include + +/* header files for our own APIs */ +#include +#include +#include +#include +/* header files for our internal definitions */ +#include /* TXRX_ASSERT, etc. */ +#include /* WDI events */ +#include /* ol_txrx_pdev_t, etc. */ +#include +#include /* ol_tx_ll */ +#include /* ol_rx_deliver */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include /* ol_rx_pn_check, etc. */ +#include /* ol_rx_fwd_check, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_INIT, etc. */ +#include +#include /* ol_tx_discard_target_frms */ +#include /* ol_tx_desc_frame_free */ +#include +#include +#include "wma.h" + + + +/*=== function definitions ===*/ + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +ol_txrx_peer_handle +ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_addr, uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_vdev_find_hash(pdev, vdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + cdf_atomic_dec(&peer->ref_cnt); + return peer; +} + +CDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id) +{ + if (!peer) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "peer argument is null!!"); + return CDF_STATUS_E_FAILURE; + } + + *vdev_id = peer->vdev->vdev_id; + return CDF_STATUS_SUCCESS; +} + +void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pdev_handle pdev = NULL; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid sta id passed"); + return NULL; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "PDEV not found for sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "PEER [%d] not found", sta_id); + return NULL; + } + + return peer->vdev; +} + +ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find(pdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + cdf_atomic_dec(&peer->ref_cnt); + return peer; +} + +uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer) +{ + return peer->local_id; +} + +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(struct ol_txrx_pdev_t *pdev, + uint8_t local_peer_id) +{ + struct ol_txrx_peer_t *peer; + if ((local_peer_id == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (local_peer_id >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return NULL; + } + + cdf_spin_lock_bh(&pdev->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[local_peer_id]; + cdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + return peer; +} + +static void ol_txrx_local_peer_id_pool_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + /* point the freelist to the first ID */ + pdev->local_peer_ids.freelist = 0; + + /* link each ID to the next one */ + for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) { + pdev->local_peer_ids.pool[i] = i + 1; + pdev->local_peer_ids.map[i] = NULL; + } + + /* link the last ID to itself, to mark the end of the list */ + i = OL_TXRX_NUM_LOCAL_PEER_IDS; + pdev->local_peer_ids.pool[i] = i; + + cdf_spinlock_init(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + cdf_spin_lock_bh(&pdev->local_peer_ids.lock); + i = pdev->local_peer_ids.freelist; + if (pdev->local_peer_ids.pool[i] == i) { + /* the list is empty, except for the list-end marker */ + peer->local_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } else { + /* take the head ID and advance the freelist */ + peer->local_id = i; + pdev->local_peer_ids.freelist = pdev->local_peer_ids.pool[i]; + pdev->local_peer_ids.map[i] = peer; + } + cdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i = peer->local_id; + if ((i == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (i >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return; + } + /* put this ID on the head of the freelist */ + cdf_spin_lock_bh(&pdev->local_peer_ids.lock); + pdev->local_peer_ids.pool[i] = pdev->local_peer_ids.freelist; + pdev->local_peer_ids.freelist = i; + pdev->local_peer_ids.map[i] = NULL; + cdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void ol_txrx_local_peer_id_cleanup(struct ol_txrx_pdev_t *pdev) +{ + cdf_spinlock_destroy(&pdev->local_peer_ids.lock); +} + +#else +#define ol_txrx_local_peer_id_pool_init(pdev) /* no-op */ +#define ol_txrx_local_peer_id_alloc(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_free(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_cleanup(pdev) /* no-op */ +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * setup_fastpath_ce_handles() Update pdev with ce_handle for fastpath use. + * + * @osc: pointer to HIF context + * @pdev: pointer to ol pdev + * + * Return: void + */ +static inline void +setup_fastpath_ce_handles(struct ol_softc *osc, struct ol_txrx_pdev_t *pdev) +{ + /* + * Before the HTT attach, set up the CE handles + * CE handles are (struct CE_state *) + * This is only required in the fast path + */ + pdev->ce_tx_hdl = (struct CE_handle *) + osc->ce_id_to_state[CE_HTT_H2T_MSG]; + +} + +/** + * init_txdesc_id() initialize Tx desc with id + * + * @pdev: handle OL pdev + * @desc_num: Tx descriptor number + * + * Return: void + */ +static inline void +init_txdesc_id(struct ol_txrx_pdev_t *pdev, int desc_num) +{ + pdev->tx_desc.array[desc_num].tx_desc.id = desc_num; + cdf_atomic_init(&pdev->tx_desc.array[desc_num].tx_desc.ref_cnt); +} +#else /* not WLAN_FEATURE_FASTPATH */ +static inline void +setup_fastpath_ce_handles(struct ol_softc *osc, struct ol_txrx_pdev_t *pdev) +{ +} +static inline void +init_txdesc_id(struct ol_txrx_pdev_t *pdev, int desc_num) +{ +} +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_set_desc_global_pool_size() - set global pool size + * @num_msdu_desc: total number of descriptors + * + * Return: none + */ +inline +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + cdf_print("%s: pdev is NULL\n", __func__); + return; + } + pdev->num_msdu_desc = num_msdu_desc + TX_FLOW_MGMT_POOL_SIZE; + return; +} + +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return pdev->num_msdu_desc; +} +#else +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return ol_cfg_target_tx_credit(pdev->ctrl_pdev); +} +#endif + +/** + * ol_txrx_pdev_alloc() - allocate txrx pdev + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os dev + * + * Return: txrx pdev handle + * NULL for failure + */ +ol_txrx_pdev_handle +ol_txrx_pdev_alloc(ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, cdf_device_t osdev) +{ + struct ol_txrx_pdev_t *pdev; + int i; + + pdev = cdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail0; + cdf_mem_zero(pdev, sizeof(*pdev)); + + pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(ctrl_pdev); + + /* store provided params */ + pdev->ctrl_pdev = ctrl_pdev; + pdev->osdev = osdev; + + for (i = 0; i < htt_num_sec_types; i++) + pdev->sec_types[i] = (enum ol_sec_type)i; + + TXRX_STATS_INIT(pdev); + + TAILQ_INIT(&pdev->vdev_list); + + /* do initial set up of the peer ID -> peer object lookup map */ + if (ol_txrx_peer_find_attach(pdev)) + goto fail1; + + pdev->htt_pdev = + htt_pdev_alloc(pdev, ctrl_pdev, htc_pdev, osdev); + if (!pdev->htt_pdev) + goto fail2; + + return pdev; + +fail2: + ol_txrx_peer_find_detach(pdev); + +fail1: + cdf_mem_free(pdev); + +fail0: + return NULL; +} + +/** + * ol_txrx_pdev_attach() - attach txrx pdev + * @pdev: txrx pdev + * + * Return: 0 for success + */ +int +ol_txrx_pdev_attach(ol_txrx_pdev_handle pdev) +{ + int i; + int ret = 0; + uint16_t desc_pool_size; + struct ol_softc *osc = cds_get_context(CDF_MODULE_ID_HIF); + + if (!osc) { + ret = -EINVAL; + goto fail0; + } + + /* + * For LL, limit the number of host's tx descriptors to match + * the number of target FW tx descriptors. + * This simplifies the FW, by ensuring the host will never + * download more tx descriptors than the target has space for. + * The FW will drop/free low-priority tx descriptors when it + * starts to run low, so that in theory the host should never + * run out of tx descriptors. + */ + + /* initialize the counter of the target's tx buffer availability */ + cdf_atomic_init(&pdev->target_tx_credit); + cdf_atomic_init(&pdev->orig_target_tx_credit); + /* + * LL - initialize the target credit outselves. + * HL - wait for a HTT target credit initialization during htt_attach. + */ + + cdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), + &pdev->target_tx_credit); + + desc_pool_size = ol_tx_get_desc_global_pool_size(pdev); + + setup_fastpath_ce_handles(osc, pdev); + + ret = htt_attach(pdev->htt_pdev, desc_pool_size); + if (ret) + goto fail0; + + /* Update CE's pkt download length */ + ce_pkt_dl_len_set((void *)osc, htt_pkt_dl_len_get(pdev->htt_pdev)); + + /* Attach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + if (htt_ipa_uc_attach(pdev->htt_pdev)) + goto fail1; + + pdev->tx_desc.array = + cdf_mem_malloc(desc_pool_size * + sizeof(union ol_tx_desc_list_elem_t)); + if (!pdev->tx_desc.array) + goto fail2; + cdf_mem_set(pdev->tx_desc.array, + desc_pool_size * sizeof(union ol_tx_desc_list_elem_t), 0); + + /* + * Each SW tx desc (used only within the tx datapath SW) has a + * matching HTT tx desc (used for downloading tx meta-data to FW/HW). + * Go ahead and allocate the HTT tx desc and link it with the SW tx + * desc now, to avoid doing it during time-critical transmit. + */ + pdev->tx_desc.pool_size = desc_pool_size; + for (i = 0; i < desc_pool_size; i++) { + void *htt_tx_desc; +#if defined(HELIUMPLUS_PADDR64) + void *htt_frag_desc; + uint32_t frag_paddr_lo; +#endif /* defined(HELIUMPLUS_PADDR64) */ + uint32_t paddr_lo; + + htt_tx_desc = htt_tx_desc_alloc(pdev->htt_pdev, &paddr_lo); + if (!htt_tx_desc) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL, + "%s: failed to alloc HTT tx desc (%d of %d)", + __func__, i, desc_pool_size); + while (--i >= 0) { + htt_tx_desc_free(pdev->htt_pdev, + pdev->tx_desc.array[i]. + tx_desc.htt_tx_desc); + } + goto fail3; + } + pdev->tx_desc.array[i].tx_desc.htt_tx_desc = htt_tx_desc; + pdev->tx_desc.array[i].tx_desc.htt_tx_desc_paddr = paddr_lo; + +#if defined(HELIUMPLUS_PADDR64) + htt_frag_desc = htt_tx_frag_alloc(pdev->htt_pdev, i, + &frag_paddr_lo); + if (!htt_frag_desc) { + cdf_print("%s: failed to alloc HTT frag dsc (%d/%d)\n", + __func__, i, desc_pool_size); + /* Is there a leak here, is this handling correct? */ + goto fail3; + } + /* Initialize the first 6 words (TSO flags) + of the frag descriptor */ + memset(htt_frag_desc, 0, 6*sizeof(uint32_t)); + + pdev->tx_desc.array[i].tx_desc.htt_frag_desc = htt_frag_desc; +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s:%d %d %p\n", __func__, __LINE__, + i, pdev->tx_desc.array[i].tx_desc.htt_frag_desc); +#endif /* HELIUMPLUS_DEBUG */ + pdev->tx_desc.array[i].tx_desc.htt_frag_desc_paddr = + frag_paddr_lo; +#if defined(HELIUMPLUS_DEBUG) + cdf_print("%s:%d - %d FRAG VA 0x%p FRAG PA 0x%x\n", + __func__, __LINE__, i, + pdev->tx_desc.array[i].tx_desc.htt_frag_desc, + pdev->tx_desc.array[i].tx_desc.htt_frag_desc_paddr); +#endif /* HELIUMPLUS_DEBUG */ +#endif /* defined(HELIUMPLUS_PADDR64) */ + + pdev->tx_desc.array[i].tx_desc.index = i; +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + pdev->tx_desc.array[i].tx_desc.pkt_type = 0xff; +#ifdef QCA_COMPUTE_TX_DELAY + pdev->tx_desc.array[i].tx_desc.entry_timestamp_ticks = + 0xffffffff; +#endif +#endif + init_txdesc_id(pdev, i); + } + + /* link SW tx descs into a freelist */ + pdev->tx_desc.num_free = desc_pool_size; + pdev->tx_desc.freelist = &pdev->tx_desc.array[0]; + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s first tx_desc:0x%p Last tx desc:0x%p\n", __func__, + (uint32_t *) pdev->tx_desc.freelist, + (uint32_t *) (pdev->tx_desc.freelist + desc_pool_size)); + for (i = 0; i < desc_pool_size - 1; i++) + pdev->tx_desc.array[i].next = &pdev->tx_desc.array[i + 1]; + + pdev->tx_desc.array[i].next = NULL; + + /* check what format of frames are expected to be delivered by the OS */ + pdev->frame_format = ol_cfg_frame_type(pdev->ctrl_pdev); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + pdev->htt_pkt_type = htt_pkt_type_native_wifi; + else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (ol_cfg_is_ce_classify_enabled(pdev->ctrl_pdev)) + pdev->htt_pkt_type = htt_pkt_type_eth2; + else + pdev->htt_pkt_type = htt_pkt_type_ethernet; + } else { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s Invalid standard frame type: %d", + __func__, pdev->frame_format); + goto fail4; + } + + /* setup the global rx defrag waitlist */ + TAILQ_INIT(&pdev->rx.defrag.waitlist); + + /* configure where defrag timeout and duplicate detection is handled */ + pdev->rx.flags.defrag_timeout_check = + pdev->rx.flags.dup_check = + ol_cfg_rx_host_defrag_timeout_duplicate_check(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* Need to revisit this part. Currently,hardcode to riva's caps */ + pdev->target_tx_tran_caps = wlan_frm_tran_cap_raw; + pdev->target_rx_tran_caps = wlan_frm_tran_cap_raw; + /* + * The Riva HW de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. + */ + pdev->sw_subfrm_hdr_recovery_enable = 1; + /* + * The Riva HW doesn't have the capability to set Protected Frame bit + * in the MAC header for encrypted data frame. + */ + pdev->sw_pf_proc_enable = 1; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + /* sw llc process is only needed in + 802.3 to 802.11 transform case */ + pdev->sw_tx_llc_proc_enable = 1; + pdev->sw_rx_llc_proc_enable = 1; + } else { + pdev->sw_tx_llc_proc_enable = 0; + pdev->sw_rx_llc_proc_enable = 0; + } + + switch (pdev->frame_format) { + case wlan_frm_fmt_raw: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + break; + case wlan_frm_fmt_native_wifi: + pdev->sw_tx_encap = + pdev-> + target_tx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + pdev->sw_rx_decap = + pdev-> + target_rx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + break; + case wlan_frm_fmt_802_3: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + break; + default: + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid std frame type; [en/de]cap: f:%x t:%x r:%x", + pdev->frame_format, + pdev->target_tx_tran_caps, pdev->target_rx_tran_caps); + goto fail4; + } +#endif + + /* + * Determine what rx processing steps are done within the host. + * Possibilities: + * 1. Nothing - rx->tx forwarding and rx PN entirely within target. + * (This is unlikely; even if the target is doing rx->tx forwarding, + * the host should be doing rx->tx forwarding too, as a back up for + * the target's rx->tx forwarding, in case the target runs short on + * memory, and can't store rx->tx frames that are waiting for + * missing prior rx frames to arrive.) + * 2. Just rx -> tx forwarding. + * This is the typical configuration for HL, and a likely + * configuration for LL STA or small APs (e.g. retail APs). + * 3. Both PN check and rx -> tx forwarding. + * This is the typical configuration for large LL APs. + * Host-side PN check without rx->tx forwarding is not a valid + * configuration, since the PN check needs to be done prior to + * the rx->tx forwarding. + */ + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + /* PN check, rx-tx forwarding and rx reorder is done by + the target */ + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) + pdev->rx_opt_proc = ol_rx_in_order_deliver; + else + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + if (ol_cfg_rx_pn_check(pdev->ctrl_pdev)) { + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) { + /* + * PN check done on host, + * rx->tx forwarding not done at all. + */ + pdev->rx_opt_proc = ol_rx_pn_check_only; + } else if (ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * Both PN check and rx->tx forwarding done + * on host. + */ + pdev->rx_opt_proc = ol_rx_pn_check; + } else { +#define TRACESTR01 "invalid config: if rx PN check is on the host,"\ +"rx->tx forwarding check needs to also be on the host" + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_ERROR, + "%s: %s", __func__, TRACESTR01); +#undef TRACESTR01 + goto fail4; + } + } else { + /* PN check done on target */ + if ((!ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) && + ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * rx->tx forwarding done on host (possibly as + * back-up for target-side primary rx->tx + * forwarding) + */ + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + /* rx->tx forwarding either done in target, + * or not done at all */ + pdev->rx_opt_proc = ol_rx_deliver; + } + } + } + + /* initialize mutexes for tx desc alloc and peer lookup */ + cdf_spinlock_init(&pdev->tx_mutex); + cdf_spinlock_init(&pdev->peer_ref_mutex); + cdf_spinlock_init(&pdev->rx.mutex); + cdf_spinlock_init(&pdev->last_real_peer_mutex); + OL_TXRX_PEER_STATS_MUTEX_INIT(pdev); + + if (OL_RX_REORDER_TRACE_ATTACH(pdev) != A_OK) + goto fail5; + + if (OL_RX_PN_TRACE_ATTACH(pdev) != A_OK) + goto fail6; + +#ifdef PERE_IP_HDR_ALIGNMENT_WAR + pdev->host_80211_enable = ol_scn_host_80211_enable_get(pdev->ctrl_pdev); +#endif + + /* + * WDI event attach + */ + wdi_event_attach(pdev); + + /* + * Initialize rx PN check characteristics for different security types. + */ + cdf_mem_set(&pdev->rx_pn[0], sizeof(pdev->rx_pn), 0); + + /* TKIP: 48-bit TSC, CCMP: 48-bit PN */ + pdev->rx_pn[htt_sec_type_tkip].len = + pdev->rx_pn[htt_sec_type_tkip_nomic].len = + pdev->rx_pn[htt_sec_type_aes_ccmp].len = 48; + pdev->rx_pn[htt_sec_type_tkip].cmp = + pdev->rx_pn[htt_sec_type_tkip_nomic].cmp = + pdev->rx_pn[htt_sec_type_aes_ccmp].cmp = ol_rx_pn_cmp48; + + /* WAPI: 128-bit PN */ + pdev->rx_pn[htt_sec_type_wapi].len = 128; + pdev->rx_pn[htt_sec_type_wapi].cmp = ol_rx_pn_wapi_cmp; + + OL_RX_REORDER_TIMEOUT_INIT(pdev); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Created pdev %p\n", pdev); + + pdev->cfg.host_addba = ol_cfg_host_addba(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +#define OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT 3 + +/* #if 1 -- TODO: clean this up */ +#define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT \ + /* avg = 100% * new + 0% * old */ \ + (1 << OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT) +/* +#else +#define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT + //avg = 25% * new + 25% * old + (1 << (OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT-2)) +#endif +*/ + pdev->rssi_update_shift = OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT; + pdev->rssi_new_weight = OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT; +#endif + + ol_txrx_local_peer_id_pool_init(pdev); + + pdev->cfg.ll_pause_txq_limit = + ol_tx_cfg_max_tx_queue_depth_ll(pdev->ctrl_pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + cdf_mem_zero(&pdev->tx_delay, sizeof(pdev->tx_delay)); + cdf_spinlock_init(&pdev->tx_delay.mutex); + + /* initialize compute interval with 5 seconds (ESE default) */ + pdev->tx_delay.avg_period_ticks = cdf_system_msecs_to_ticks(5000); + { + uint32_t bin_width_1000ticks; + bin_width_1000ticks = + cdf_system_msecs_to_ticks + (QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS + * 1000); + /* + * Compute a factor and shift that together are equal to the + * inverse of the bin_width time, so that rather than dividing + * by the bin width time, approximately the same result can be + * obtained much more efficiently by a multiply + shift. + * multiply_factor >> shift = 1 / bin_width_time, so + * multiply_factor = (1 << shift) / bin_width_time. + * + * Pick the shift semi-arbitrarily. + * If we knew statically what the bin_width would be, we could + * choose a shift that minimizes the error. + * Since the bin_width is determined dynamically, simply use a + * shift that is about half of the uint32_t size. This should + * result in a relatively large multiplier value, which + * minimizes error from rounding the multiplier to an integer. + * The rounding error only becomes significant if the tick units + * are on the order of 1 microsecond. In most systems, it is + * expected that the tick units will be relatively low-res, + * on the order of 1 millisecond. In such systems the rounding + * error is negligible. + * It would be more accurate to dynamically try out different + * shifts and choose the one that results in the smallest + * rounding error, but that extra level of fidelity is + * not needed. + */ + pdev->tx_delay.hist_internal_bin_width_shift = 16; + pdev->tx_delay.hist_internal_bin_width_mult = + ((1 << pdev->tx_delay.hist_internal_bin_width_shift) * + 1000 + (bin_width_1000ticks >> 1)) / + bin_width_1000ticks; + } +#endif /* QCA_COMPUTE_TX_DELAY */ + +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + ol_tx_throttle_init(pdev); +#endif + + +#if defined(FEATURE_TSO) + ol_tso_seg_list_init(pdev, desc_pool_size); +#endif + + ol_tx_register_flow_control(pdev); + + return 0; /* success */ + +fail6: + OL_RX_REORDER_TRACE_DETACH(pdev); + +fail5: + cdf_spinlock_destroy(&pdev->tx_mutex); + cdf_spinlock_destroy(&pdev->peer_ref_mutex); + cdf_spinlock_destroy(&pdev->rx.mutex); + cdf_spinlock_destroy(&pdev->last_real_peer_mutex); + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + +fail4: + for (i = 0; i < desc_pool_size; i++) + htt_tx_desc_free(pdev->htt_pdev, + pdev->tx_desc.array[i].tx_desc.htt_tx_desc); + +fail3: + cdf_mem_free(pdev->tx_desc.array); + +fail2: + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); +fail1: + htt_detach(pdev->htt_pdev); + +fail0: + return ret; /* fail */ +} + +A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev) +{ + return htt_attach_target(pdev->htt_pdev); +} + +void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force) +{ + int i; + /*checking to ensure txrx pdev structure is not NULL */ + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "NULL pdev passed to %s\n", __func__); + return; + } + /* preconditions */ + TXRX_ASSERT2(pdev); + + /* check that the pdev has no vdevs allocated */ + TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); + + OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); + +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + cdf_softirq_timer_cancel(&pdev->tx_throttle.phase_timer); + cdf_softirq_timer_free(&pdev->tx_throttle.phase_timer); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + cdf_softirq_timer_cancel(&pdev->tx_throttle.tx_timer); + cdf_softirq_timer_free(&pdev->tx_throttle.tx_timer); +#endif +#endif + + ol_tx_deregister_flow_control(pdev); + + if (force) { + /* + * The assertion above confirms that all vdevs within this pdev + * were detached. However, they may not have actually been + * deleted. + * If the vdev had peers which never received a PEER_UNMAP msg + * from the target, then there are still zombie peer objects, + * and the vdev parents of the zombie peers are also zombies, + * hanging around until their final peer gets deleted. + * Go through the peer hash table and delete any peers left. + * As a side effect, this will complete the deletion of any + * vdevs that are waiting for their peers to finish deletion. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Force delete for pdev %p\n", + pdev); + ol_txrx_peer_find_hash_erase(pdev); + } + + /* Stop the communication between HTT and target at first */ + htt_detach_target(pdev->htt_pdev); + + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + void *htt_tx_desc; + + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + */ + if (cdf_atomic_read(&pdev->tx_desc.array[i].tx_desc.ref_cnt)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "Warning: freeing tx frame (no compltn)\n"); + ol_tx_desc_frame_free_nonstd(pdev, + &pdev->tx_desc.array[i]. + tx_desc, 1); + } + htt_tx_desc = pdev->tx_desc.array[i].tx_desc.htt_tx_desc; + htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc); + } + + cdf_mem_free(pdev->tx_desc.array); + + /* Detach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); + + htt_detach(pdev->htt_pdev); + htt_pdev_free(pdev->htt_pdev); + + ol_txrx_peer_find_detach(pdev); + + cdf_spinlock_destroy(&pdev->tx_mutex); + cdf_spinlock_destroy(&pdev->peer_ref_mutex); + cdf_spinlock_destroy(&pdev->last_real_peer_mutex); + cdf_spinlock_destroy(&pdev->rx.mutex); +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + cdf_spinlock_destroy(&pdev->tx_throttle.mutex); +#endif + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + + OL_RX_REORDER_TRACE_DETACH(pdev); + OL_RX_PN_TRACE_DETACH(pdev); + /* + * WDI event detach + */ + wdi_event_detach(pdev); + ol_txrx_local_peer_id_cleanup(pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + cdf_spinlock_destroy(&pdev->tx_delay.mutex); +#endif +} + +ol_txrx_vdev_handle +ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev, + uint8_t *vdev_mac_addr, + uint8_t vdev_id, enum wlan_op_mode op_mode) +{ + struct ol_txrx_vdev_t *vdev; + + /* preconditions */ + TXRX_ASSERT2(pdev); + TXRX_ASSERT2(vdev_mac_addr); + + vdev = cdf_mem_malloc(sizeof(*vdev)); + if (!vdev) + return NULL; /* failure */ + + /* store provided params */ + vdev->pdev = pdev; + vdev->vdev_id = vdev_id; + vdev->opmode = op_mode; + + vdev->delete.pending = 0; + vdev->safemode = 0; + vdev->drop_unenc = 1; + vdev->num_filters = 0; +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + cdf_atomic_init(&vdev->tx_desc_count); +#endif + + cdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + TAILQ_INIT(&vdev->peer_list); + vdev->last_real_peer = NULL; + +#ifdef QCA_IBSS_SUPPORT + vdev->ibss_peer_num = 0; + vdev->ibss_peer_heart_beat_timer = 0; +#endif + + cdf_spinlock_init(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason = 0; + vdev->ll_pause.txq.head = vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + cdf_softirq_timer_init(pdev->osdev, + &vdev->ll_pause.timer, + ol_tx_vdev_ll_pause_queue_send, vdev, + CDF_TIMER_TYPE_SW); + cdf_atomic_init(&vdev->os_q_paused); + cdf_atomic_set(&vdev->os_q_paused, 0); + vdev->tx_fl_lwm = 0; + vdev->tx_fl_hwm = 0; + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + cdf_spinlock_init(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + + /* Default MAX Q depth for every VDEV */ + vdev->ll_pause.max_q_depth = + ol_tx_cfg_max_tx_queue_depth_ll(vdev->pdev->ctrl_pdev); + /* add this vdev into the pdev's list */ + TAILQ_INSERT_TAIL(&pdev->vdev_list, vdev, vdev_list_elem); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "Created vdev %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + + /* + * We've verified that htt_op_mode == wlan_op_mode, + * so no translation is needed. + */ + htt_vdev_attach(pdev->htt_pdev, vdev_id, op_mode); + + return vdev; +} + +void ol_txrx_osif_vdev_register(ol_txrx_vdev_handle vdev, + void *osif_vdev, + struct ol_txrx_osif_ops *txrx_ops) +{ + vdev->osif_dev = osif_vdev; + txrx_ops->tx.std = vdev->tx = OL_TX_LL; + txrx_ops->tx.non_std = ol_tx_non_std_ll; +} + +void ol_txrx_set_curchan(ol_txrx_pdev_handle pdev, uint32_t chan_mhz) +{ + return; +} + +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->safemode = val; +} + +void +ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev, + void *filters, uint32_t num) +{ + cdf_mem_copy(vdev->privacy_filters, filters, + num * sizeof(struct privacy_exemption)); + vdev->num_filters = num; +} + +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->drop_unenc = val; +} + +void +ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_delete_cb callback, void *context) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + /* preconditions */ + TXRX_ASSERT2(vdev); + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + cdf_softirq_timer_cancel(&vdev->ll_pause.timer); + cdf_softirq_timer_free(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + cdf_nbuf_t next = cdf_nbuf_next(vdev->ll_pause.txq.head); + cdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + cdf_nbuf_unmap(pdev->osdev, vdev->ll_pause.txq.head, + CDF_DMA_TO_DEVICE); + cdf_nbuf_tx_free(vdev->ll_pause.txq.head, NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + cdf_spinlock_destroy(&vdev->ll_pause.mutex); + + cdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + cdf_spin_unlock_bh(&vdev->flow_control_lock); + cdf_spinlock_destroy(&vdev->flow_control_lock); + + /* remove the vdev from its parent pdev's list */ + TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem); + + /* + * Use peer_ref_mutex while accessing peer_list, in case + * a peer is in the process of being removed from the list. + */ + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check that the vdev has no peers allocated */ + if (!TAILQ_EMPTY(&vdev->peer_list)) { + /* debug print - will be removed later */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: not deleting vdev object %p (%02x:%02x:%02x:%02x:%02x:%02x)" + "until deletion finishes for all its peers\n", + __func__, vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + /* indicate that the vdev needs to be deleted */ + vdev->delete.pending = 1; + vdev->delete.callback = callback; + vdev->delete.context = context; + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return; + } + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: deleting vdev obj %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + __func__, vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + + htt_vdev_detach(pdev->htt_pdev, vdev->vdev_id); + + /* + * Doesn't matter if there are outstanding tx frames - + * they will be freed once the target sends a tx completion + * message for them. + */ + cdf_mem_free(vdev); + if (callback) + callback(context); +} + +/** + * ol_txrx_flush_rx_frames() - flush cached rx frames + * @peer: peer + * @drop: set flag to drop frames + * + * Return: None + */ +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop) +{ + struct ol_rx_cached_buf *cache_buf; + CDF_STATUS ret; + ol_rx_callback_fp data_rx = NULL; + void *cds_ctx = cds_get_global_context(); + + if (cdf_atomic_inc_return(&peer->flush_in_progress) > 1) { + cdf_atomic_dec(&peer->flush_in_progress); + return; + } + + cdf_assert(cds_ctx); + cdf_spin_lock_bh(&peer->peer_info_lock); + if (peer->state >= ol_txrx_peer_state_conn) + data_rx = peer->osif_rx; + else + drop = true; + cdf_spin_unlock_bh(&peer->peer_info_lock); + + cdf_spin_lock_bh(&peer->bufq_lock); + cache_buf = list_entry((&peer->cached_bufq)->next, + typeof(*cache_buf), list); + while (!list_empty(&peer->cached_bufq)) { + list_del(&cache_buf->list); + cdf_spin_unlock_bh(&peer->bufq_lock); + if (drop) { + cdf_nbuf_free(cache_buf->buf); + } else { + /* Flush the cached frames to HDD */ + ret = data_rx(cds_ctx, cache_buf->buf, peer->local_id); + if (ret != CDF_STATUS_SUCCESS) + cdf_nbuf_free(cache_buf->buf); + } + cdf_mem_free(cache_buf); + cdf_spin_lock_bh(&peer->bufq_lock); + cache_buf = list_entry((&peer->cached_bufq)->next, + typeof(*cache_buf), list); + } + cdf_spin_unlock_bh(&peer->bufq_lock); + cdf_atomic_dec(&peer->flush_in_progress); +} + +ol_txrx_peer_handle +ol_txrx_peer_attach(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_peer_t *temp_peer; + uint8_t i; + int differs; + bool wait_on_deletion = false; + unsigned long rc; + + /* preconditions */ + TXRX_ASSERT2(pdev); + TXRX_ASSERT2(vdev); + TXRX_ASSERT2(peer_mac_addr); + + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check for duplicate exsisting peer */ + TAILQ_FOREACH(temp_peer, &vdev->peer_list, peer_list_elem) { + if (!ol_txrx_peer_find_mac_addr_cmp(&temp_peer->mac_addr, + (union ol_txrx_align_mac_addr_t *)peer_mac_addr)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "vdev_id %d (%02x:%02x:%02x:%02x:%02x:%02x) already exsist.\n", + vdev->vdev_id, + peer_mac_addr[0], peer_mac_addr[1], + peer_mac_addr[2], peer_mac_addr[3], + peer_mac_addr[4], peer_mac_addr[5]); + if (cdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + cdf_event_init(&vdev->wait_delete_comp); + wait_on_deletion = true; + } else { + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; + } + } + } + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + if (wait_on_deletion) { + /* wait for peer deletion */ + rc = cdf_wait_single_event(&vdev->wait_delete_comp, + cdf_system_msecs_to_ticks(PEER_DELETION_TIMEOUT)); + if (!rc) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "timedout waiting for peer(%d) deletion\n", + vdev->wait_on_peer_id); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + return NULL; + } + } + + peer = cdf_mem_malloc(sizeof(*peer)); + if (!peer) + return NULL; /* failure */ + cdf_mem_zero(peer, sizeof(*peer)); + + /* store provided params */ + peer->vdev = vdev; + cdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + INIT_LIST_HEAD(&peer->cached_bufq); + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* add this peer into the vdev's list */ + TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem); + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* check whether this is a real peer (peer mac addr != vdev mac addr) */ + if (ol_txrx_peer_find_mac_addr_cmp(&vdev->mac_addr, &peer->mac_addr)) + vdev->last_real_peer = peer; + + peer->rx_opt_proc = pdev->rx_opt_proc; + + ol_rx_peer_init(pdev, peer); + + /* initialize the peer_id */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) + peer->peer_ids[i] = HTT_INVALID_PEER; + + + peer->osif_rx = NULL; + cdf_spinlock_init(&peer->peer_info_lock); + cdf_spinlock_init(&peer->bufq_lock); + + cdf_atomic_init(&peer->delete_in_progress); + cdf_atomic_init(&peer->flush_in_progress); + + cdf_atomic_init(&peer->ref_cnt); + + /* keep one reference for attach */ + cdf_atomic_inc(&peer->ref_cnt); + + /* keep one reference for ol_rx_peer_map_handler */ + cdf_atomic_inc(&peer->ref_cnt); + + peer->valid = 1; + + ol_txrx_peer_find_hash_add(pdev, peer); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "vdev %p created peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + /* + * For every peer MAp message search and set if bss_peer + */ + differs = + cdf_mem_compare(peer->mac_addr.raw, vdev->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN); + if (!differs) + peer->bss_peer = 1; + + /* + * The peer starts in the "disc" state while association is in progress. + * Once association completes, the peer will get updated to "auth" state + * by a call to ol_txrx_peer_state_update if the peer is in open mode, + * or else to the "conn" state. For non-open mode, the peer will + * progress to "auth" state once the authentication completes. + */ + peer->state = ol_txrx_peer_state_invalid; + ol_txrx_peer_state_update(pdev, peer->mac_addr.raw, + ol_txrx_peer_state_disc); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI + peer->rssi_dbm = HTT_RSSI_INVALID; +#endif + + ol_txrx_local_peer_id_alloc(pdev, peer); + + return peer; +} + +/* + * Discarding tx filter - removes all data frames (disconnected state) + */ +static A_STATUS ol_tx_filter_discard(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_ERROR; +} + +/* + * Non-autentication tx filter - filters out data frames that are not + * related to authentication, but allows EAPOL (PAE) or WAPI (WAI) + * data frames (connected state) + */ +static A_STATUS ol_tx_filter_non_auth(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return + (tx_msdu_info->htt.info.ethertype == ETHERTYPE_PAE || + tx_msdu_info->htt.info.ethertype == + ETHERTYPE_WAI) ? A_OK : A_ERROR; +} + +/* + * Pass-through tx filter - lets all data frames through (authenticated state) + */ +static A_STATUS ol_tx_filter_pass_thru(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_OK; +} + +CDF_STATUS +ol_txrx_peer_state_update(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + struct ol_txrx_peer_t *peer; + + if (cdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL"); + cdf_assert(0); + return CDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_hash_find(pdev, peer_mac, 0, 1); + if (NULL == peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null for peer_mac" + " 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5]); + return CDF_STATUS_E_INVAL; + } + + /* TODO: Should we send WMI command of the connection state? */ + /* avoid multiple auth state change. */ + if (peer->state == state) { +#ifdef TXRX_PRINT_VERBOSE_ENABLE + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO3, + "%s: no state change, returns directly\n", + __func__); +#endif + cdf_atomic_dec(&peer->ref_cnt); + return CDF_STATUS_SUCCESS; + } + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: change from %d to %d\n", + __func__, peer->state, state); + + peer->tx_filter = (state == ol_txrx_peer_state_auth) + ? ol_tx_filter_pass_thru + : ((state == ol_txrx_peer_state_conn) + ? ol_tx_filter_non_auth + : ol_tx_filter_discard); + + if (peer->vdev->pdev->cfg.host_addba) { + if (state == ol_txrx_peer_state_auth) { + int tid; + /* + * Pause all regular (non-extended) TID tx queues until + * data arrives and ADDBA negotiation has completed. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: pause peer and unpause mgmt/non-qos\n", + __func__); + ol_txrx_peer_pause(peer); /* pause all tx queues */ + /* unpause mgmt and non-QoS tx queues */ + for (tid = OL_TX_NUM_QOS_TIDS; + tid < OL_TX_NUM_TIDS; tid++) + ol_txrx_peer_tid_unpause(peer, tid); + } + } + cdf_atomic_dec(&peer->ref_cnt); + + /* Set the state after the Pause to avoid the race condiction + with ADDBA check in tx path */ + peer->state = state; + return CDF_STATUS_SUCCESS; +} + +void +ol_txrx_peer_keyinstalled_state_update(struct ol_txrx_peer_t *peer, uint8_t val) +{ + peer->keyinstalled = val; +} + +void +ol_txrx_peer_update(ol_txrx_vdev_handle vdev, + uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find(vdev->pdev, peer_mac, 0, 1); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null", + __func__); + return; + } + + switch (select) { + case ol_txrx_peer_update_qos_capable: + { + /* save qos_capable here txrx peer, + * when HTT_ISOC_T2H_MSG_TYPE_PEER_INFO comes then save. + */ + peer->qos_capable = param->qos_capable; + /* + * The following function call assumes that the peer has a + * single ID. This is currently true, and + * is expected to remain true. + */ + htt_peer_qos_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->qos_capable); + break; + } + case ol_txrx_peer_update_uapsdMask: + { + peer->uapsd_mask = param->uapsd_mask; + htt_peer_uapsdmask_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->uapsd_mask); + break; + } + case ol_txrx_peer_update_peer_security: + { + enum ol_sec_type sec_type = param->sec_type; + enum htt_sec_type peer_sec_type = htt_sec_type_none; + + switch (sec_type) { + case ol_sec_type_none: + peer_sec_type = htt_sec_type_none; + break; + case ol_sec_type_wep128: + peer_sec_type = htt_sec_type_wep128; + break; + case ol_sec_type_wep104: + peer_sec_type = htt_sec_type_wep104; + break; + case ol_sec_type_wep40: + peer_sec_type = htt_sec_type_wep40; + break; + case ol_sec_type_tkip: + peer_sec_type = htt_sec_type_tkip; + break; + case ol_sec_type_tkip_nomic: + peer_sec_type = htt_sec_type_tkip_nomic; + break; + case ol_sec_type_aes_ccmp: + peer_sec_type = htt_sec_type_aes_ccmp; + break; + case ol_sec_type_wapi: + peer_sec_type = htt_sec_type_wapi; + break; + default: + peer_sec_type = htt_sec_type_none; + break; + } + + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = + peer_sec_type; + + break; + } + default: + { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "ERROR: unknown param %d in %s", select, + __func__); + break; + } + } + cdf_atomic_dec(&peer->ref_cnt); +} + +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer) + return peer->uapsd_mask; + return 0; +} + +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer_t = + ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer_t != NULL) + return peer_t->qos_capable; + return 0; +} + +void ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer) +{ + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_pdev_t *pdev; + int i; + + /* preconditions */ + TXRX_ASSERT2(peer); + + vdev = peer->vdev; + if (NULL == vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "The vdev is not present anymore\n"); + return; + } + + pdev = vdev->pdev; + if (NULL == pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "The pdev is not present anymore\n"); + return; + } + + /* + * Check for the reference count before deleting the peer + * as we noticed that sometimes we are re-entering this + * function again which is leading to dead-lock. + * (A double-free should never happen, so assert if it does.) + */ + + if (0 == cdf_atomic_read(&(peer->ref_cnt))) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "The Peer is not present anymore\n"); + cdf_assert(0); + return; + } + + /* + * Hold the lock all the way from checking if the peer ref count + * is zero until the peer references are removed from the hash + * table and vdev list (if the peer ref count is zero). + * This protects against a new HL tx operation starting to use the + * peer object just after this function concludes it's done being used. + * Furthermore, the lock needs to be held while checking whether the + * vdev's list of peers is empty, to make sure that list is not modified + * concurrently with the empty check. + */ + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + if (cdf_atomic_dec_and_test(&peer->ref_cnt)) { + u_int16_t peer_id; + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Deleting peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + + peer_id = peer->local_id; + /* remove the reference to the peer from the hash table */ + ol_txrx_peer_find_hash_remove(pdev, peer); + + /* remove the peer from its parent vdev's list */ + TAILQ_REMOVE(&peer->vdev->peer_list, peer, peer_list_elem); + + /* cleanup the Rx reorder queues for this peer */ + ol_rx_peer_cleanup(vdev, peer); + + /* peer is removed from peer_list */ + cdf_atomic_set(&peer->delete_in_progress, 0); + + /* + * Set wait_delete_comp event if the current peer id matches + * with registered peer id. + */ + if (peer_id == vdev->wait_on_peer_id) { + cdf_event_set(&vdev->wait_delete_comp); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } + + /* check whether the parent vdev has no peers left */ + if (TAILQ_EMPTY(&vdev->peer_list)) { + /* + * Now that there are no references to the peer, we can + * release the peer reference lock. + */ + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* + * Check if the parent vdev was waiting for its peers + * to be deleted, in order for it to be deleted too. + */ + if (vdev->delete.pending) { + ol_txrx_vdev_delete_cb vdev_delete_cb = + vdev->delete.callback; + void *vdev_delete_context = + vdev->delete.context; + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: deleting vdev object %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)" + " - its last peer is done\n", + __func__, vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + /* all peers are gone, go ahead and delete it */ + cdf_mem_free(vdev); + if (vdev_delete_cb) + vdev_delete_cb(vdev_delete_context); + } + } else + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + /* + * 'array' is allocated in addba handler and is supposed to be + * freed in delba handler. There is the case (for example, in + * SSR) where delba handler is not called. Because array points + * to address of 'base' by default and is reallocated in addba + * handler later, only free the memory when the array does not + * point to base. + */ + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + if (peer->tids_rx_reorder[i].array != + &peer->tids_rx_reorder[i].base) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s, delete reorder arr, tid:%d\n", + __func__, i); + cdf_mem_free(peer->tids_rx_reorder[i].array); + ol_rx_reorder_init(&peer->tids_rx_reorder[i], + (uint8_t) i); + } + } + + cdf_mem_free(peer); + } else { + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } +} + +void ol_txrx_peer_detach(ol_txrx_peer_handle peer) +{ + struct ol_txrx_vdev_t *vdev = peer->vdev; + + /* redirect peer's rx delivery function to point to a discard func */ + peer->rx_opt_proc = ol_rx_discard; + + peer->valid = 0; + + ol_txrx_local_peer_id_free(peer->vdev->pdev, peer); + + /* debug print to dump rx reorder state */ + /* htt_rx_reorder_log_print(vdev->pdev->htt_pdev); */ + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s:peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + __func__, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + ol_txrx_flush_rx_frames(peer, 1); + + if (peer->vdev->last_real_peer == peer) + peer->vdev->last_real_peer = NULL; + + cdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + if (vdev->last_real_peer == peer) + vdev->last_real_peer = NULL; + cdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + htt_rx_reorder_log_print(peer->vdev->pdev->htt_pdev); + + cdf_spinlock_destroy(&peer->peer_info_lock); + cdf_spinlock_destroy(&peer->bufq_lock); + /* set delete_in_progress to identify that wma + * is waiting for unmap massage for this peer */ + cdf_atomic_set(&peer->delete_in_progress, 1); + /* + * Remove the reference added during peer_attach. + * The peer will still be left allocated until the + * PEER_UNMAP message arrives to remove the other + * reference, added by the PEER_MAP message. + */ + ol_txrx_peer_unref_delete(peer); +} + +ol_txrx_peer_handle +ol_txrx_peer_find_by_addr(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr) +{ + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_hash_find(pdev, peer_mac_addr, 0, 0); + if (peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Delete extra reference %p\n", __func__, peer); + /* release the extra reference */ + ol_txrx_peer_unref_delete(peer); + } + return peer; +} + +/** + * ol_txrx_dump_tx_desc() - dump tx desc total and free count + * @txrx_pdev: Pointer to txrx pdev + * + * Return: none + */ +static void ol_txrx_dump_tx_desc(ol_txrx_pdev_handle pdev_handle) +{ + struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; + uint32_t total; + + total = ol_tx_get_desc_global_pool_size(pdev); + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "total tx credit %d num_free %d", + total, pdev->tx_desc.num_free); + + return; +} + +/** + * ol_txrx_wait_for_pending_tx() - wait for tx queue to be empty + * @timeout: timeout in ms + * + * Wait for tx queue to be empty, return timeout error if + * queue doesn't empty before timeout occurs. + * + * Return: + * CDF_STATUS_SUCCESS if the queue empties, + * CDF_STATUS_E_TIMEOUT in case of timeout, + * CDF_STATUS_E_FAULT in case of missing handle + */ +CDF_STATUS ol_txrx_wait_for_pending_tx(int timeout) +{ + ol_txrx_pdev_handle txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (txrx_pdev == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: txrx context is null", __func__); + return CDF_STATUS_E_FAULT; + } + + while (ol_txrx_get_tx_pending(txrx_pdev)) { + cdf_sleep(OL_ATH_TX_DRAIN_WAIT_DELAY); + if (timeout <= 0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: tx frames are pending", __func__); + ol_txrx_dump_tx_desc(txrx_pdev); + return CDF_STATUS_E_TIMEOUT; + } + timeout = timeout - OL_ATH_TX_DRAIN_WAIT_DELAY; + } + return CDF_STATUS_SUCCESS; +} + +#ifndef QCA_WIFI_3_0_EMU +#define SUSPEND_DRAIN_WAIT 500 +#else +#define SUSPEND_DRAIN_WAIT 3000 +#endif + +/** + * ol_txrx_bus_suspend() - bus suspend + * + * Ensure that ol_txrx is ready for bus suspend + * + * Return: CDF_STATUS + */ +CDF_STATUS ol_txrx_bus_suspend(void) +{ + return ol_txrx_wait_for_pending_tx(SUSPEND_DRAIN_WAIT); +} + +/** + * ol_txrx_bus_resume() - bus resume + * + * Dummy function for symetry + * + * Return: CDF_STATUS_SUCCESS + */ +CDF_STATUS ol_txrx_bus_resume(void) +{ + return CDF_STATUS_SUCCESS; +} + +int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev_handle) +{ + struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; + uint32_t total; + + total = ol_tx_get_desc_global_pool_size(pdev); + + return total - pdev->tx_desc.num_free; +} + +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev_handle) +{ + ol_tx_desc_list tx_descs; + /* First let hif do the cdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * then let htt do the cdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * which is tha same with normal data send complete path*/ + htt_tx_pending_discard(pdev_handle->htt_pdev); + + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev_handle, true, &tx_descs); + /* Discard Frames in Discard List */ + ol_tx_desc_frame_list_free(pdev_handle, &tx_descs, 1 /* error */); + + ol_tx_discard_target_frms(pdev_handle); +} + +/*--- debug features --------------------------------------------------------*/ + +unsigned g_txrx_print_level = TXRX_PRINT_LEVEL_ERR; /* default */ + +void ol_txrx_print_level_set(unsigned level) +{ +#ifndef TXRX_PRINT_ENABLE + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL, + "The driver is compiled without TXRX prints enabled.\n" + "To enable them, recompile with TXRX_PRINT_ENABLE defined"); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "TXRX printout level changed from %d to %d", + g_txrx_print_level, level); + g_txrx_print_level = level; +#endif +} + +struct ol_txrx_stats_req_internal { + struct ol_txrx_stats_req base; + int serviced; /* state of this request */ + int offset; +}; + +static inline +uint64_t ol_txrx_stats_ptr_to_u64(struct ol_txrx_stats_req_internal *req) +{ + return (uint64_t) ((size_t) req); +} + +static inline +struct ol_txrx_stats_req_internal *ol_txrx_u64_to_stats_ptr(uint64_t cookie) +{ + return (struct ol_txrx_stats_req_internal *)((size_t) cookie); +} + +#ifdef ATH_PERF_PWR_OFFLOAD +void +ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev, + uint8_t cfg_stats_type, uint32_t cfg_val) +{ + uint64_t dummy_cookie = 0; + htt_h2t_dbg_stats_get(vdev->pdev->htt_pdev, 0 /* upload mask */, + 0 /* reset mask */, + cfg_stats_type, cfg_val, dummy_cookie); +} + +A_STATUS +ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint64_t cookie; + struct ol_txrx_stats_req_internal *non_volatile_req; + + if (!pdev || + req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + req->stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + return A_ERROR; + } + + /* + * Allocate a non-transient stats request object. + * (The one provided as an argument is likely allocated on the stack.) + */ + non_volatile_req = cdf_mem_malloc(sizeof(*non_volatile_req)); + if (!non_volatile_req) + return A_NO_MEMORY; + + /* copy the caller's specifications */ + non_volatile_req->base = *req; + non_volatile_req->serviced = 0; + non_volatile_req->offset = 0; + + /* use the non-volatile request object's address as the cookie */ + cookie = ol_txrx_stats_ptr_to_u64(non_volatile_req); + + if (htt_h2t_dbg_stats_get(pdev->htt_pdev, + req->stats_type_upload_mask, + req->stats_type_reset_mask, + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0, + cookie)) { + cdf_mem_free(non_volatile_req); + return A_ERROR; + } + + if (req->wait.blocking) + while (cdf_semaphore_acquire(pdev->osdev, req->wait.sem_ptr)) + ; + + return A_OK; +} +#endif +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint64_t cookie, uint8_t *stats_info_list) +{ + enum htt_dbg_stats_type type; + enum htt_dbg_stats_status status; + int length; + uint8_t *stats_data; + struct ol_txrx_stats_req_internal *req; + int more = 0; + + req = ol_txrx_u64_to_stats_ptr(cookie); + + do { + htt_t2h_dbg_stats_hdr_parse(stats_info_list, &type, &status, + &length, &stats_data); + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) + break; + if (status == HTT_DBG_STATS_STATUS_PRESENT || + status == HTT_DBG_STATS_STATUS_PARTIAL) { + uint8_t *buf; + int bytes = 0; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL) + more = 1; + if (req->base.print.verbose || req->base.print.concise) + /* provide the header along with the data */ + htt_t2h_stats_print(stats_info_list, + req->base.print.concise); + + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + bytes = sizeof(struct wlan_dbg_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct wlan_dbg_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_REORDER: + bytes = sizeof(struct rx_reorder_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct rx_reorder_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_RATE_INFO: + bytes = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_RATE_INFO: + bytes = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_PPDU_LOG: + bytes = 0; + /* TO DO: specify how many bytes are present */ + /* TO DO: add copying to the requestor's buf */ + + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + bytes = sizeof(struct rx_remote_buffer_mgmt_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct rx_remote_buffer_mgmt_stats); + if (req->base.copy.byte_limit < limit) { + limit = req->base.copy.byte_limit; + } + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_INFO: + bytes = sizeof(struct wlan_dbg_txbf_data_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_txbf_data_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_SND_INFO: + bytes = sizeof(struct wlan_dbg_txbf_snd_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_txbf_snd_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TX_SELFGEN_INFO: + bytes = sizeof(struct wlan_dbg_tx_selfgen_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_tx_selfgen_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_ERROR_INFO: + bytes = + sizeof(struct wlan_dbg_wifi2_error_stats); + if (req->base.copy.buf) { + int limit; + + limit = + sizeof(struct wlan_dbg_wifi2_error_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + bytes = + sizeof(struct rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.byte_limit < limit) + limit = + req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + cdf_mem_copy(buf, stats_data, limit); + } + break; + + default: + break; + } + buf = req->base.copy.buf + ? req->base.copy.buf + : stats_data; + if (req->base.callback.fp) + req->base.callback.fp(req->base.callback.ctxt, + type, buf, bytes); + } + stats_info_list += length; + } while (1); + + if (!more) { + if (req->base.wait.blocking) + cdf_semaphore_release(pdev->osdev, + req->base.wait.sem_ptr); + cdf_mem_free(req); + } +} + +#ifndef ATH_PERF_PWR_OFFLOAD /*---------------------------------------------*/ +int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) +{ + if (debug_specs & TXRX_DBG_MASK_OBJS) { +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 + ol_txrx_pdev_display(vdev->pdev, 0); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL, + "The pdev,vdev,peer display functions are disabled.\n" + "To enable them, recompile with TXRX_DEBUG_LEVEL > 5"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_STATS) { + ol_txrx_stats_display(vdev->pdev); + } + if (debug_specs & TXRX_DBG_MASK_PROT_ANALYZE) { +#if defined(ENABLE_TXRX_PROT_ANALYZE) + ol_txrx_prot_ans_display(vdev->pdev); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL, + "txrx protocol analysis is disabled.\n" + "To enable it, recompile with " + "ENABLE_TXRX_PROT_ANALYZE defined"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_RX_REORDER_TRACE) { +#if defined(ENABLE_RX_REORDER_TRACE) + ol_rx_reorder_trace_display(vdev->pdev, 0, 0); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL, + "rx reorder seq num trace is disabled.\n" + "To enable it, recompile with " + "ENABLE_RX_REORDER_TRACE defined"); +#endif + + } + return 0; +} +#endif + +int ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + return htt_h2t_aggr_cfg_msg(vdev->pdev->htt_pdev, + max_subfrms_ampdu, max_subfrms_amsdu); +} + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent) +{ + struct ol_txrx_vdev_t *vdev; + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*s%s:\n", indent, " ", "txrx pdev"); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*spdev object: %p", indent + 4, " ", pdev); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*svdev list:", indent + 4, " "); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_txrx_vdev_display(vdev, indent + 8); + } + ol_txrx_peer_find_display(pdev, indent + 4); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*stx desc pool: %d elems @ %p", indent + 4, " ", + pdev->tx_desc.pool_size, pdev->tx_desc.array); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, " "); + htt_display(pdev->htt_pdev, indent); +} + +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent) +{ + struct ol_txrx_peer_t *peer; + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx vdev: %p\n", indent, " ", vdev); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d\n", indent + 4, " ", vdev->vdev_id); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*sMAC addr: %d:%d:%d:%d:%d:%d", + indent + 4, " ", + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*speer list:", indent + 4, " "); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_peer_display(peer, indent + 8); + } +} + +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent) +{ + int i; + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx peer: %p", indent, " ", peer); + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] != HTT_INVALID_PEER) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d", indent + 4, " ", + peer->peer_ids[i]); + } + } +} +#endif /* TXRX_DEBUG_LEVEL */ + +#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) +void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + int msdu_idx; + int seg_idx; + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "TSO pkts %lld, bytes %lld\n", + pdev->stats.pub.tx.tso.tso_pkts.pkts, + pdev->stats.pub.tx.tso.tso_pkts.bytes); + + for (msdu_idx = 0; msdu_idx < NUM_MAX_TSO_MSDUS; msdu_idx++) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "curr msdu idx: %d curr seg idx: %d num segs %d\n", + TXRX_STATS_TSO_MSDU_IDX(pdev), + TXRX_STATS_TSO_SEG_IDX(pdev), + TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)); + for (seg_idx = 0; + ((seg_idx < TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)) && + (seg_idx < NUM_MAX_TSO_SEGS)); + seg_idx++) { + struct cdf_tso_seg_t tso_seg = + TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx); + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "msdu idx: %d seg idx: %d\n", + msdu_idx, seg_idx); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "tso_enable: %d\n", + tso_seg.tso_flags.tso_enable); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "fin %d syn %d rst %d psh %d ack %d\n" + "urg %d ece %d cwr %d ns %d\n", + tso_seg.tso_flags.fin, tso_seg.tso_flags.syn, + tso_seg.tso_flags.rst, tso_seg.tso_flags.psh, + tso_seg.tso_flags.ack, tso_seg.tso_flags.urg, + tso_seg.tso_flags.ece, tso_seg.tso_flags.cwr, + tso_seg.tso_flags.ns); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "tcp_seq_num: 0x%x ip_id: %d\n", + tso_seg.tso_flags.tcp_seq_num, + tso_seg.tso_flags.ip_id); + } + } +} +#endif + +/** + * ol_txrx_stats() - update ol layer stats + * @vdev_id: vdev_id + * @buffer: pointer to buffer + * @buf_len: length of the buffer + * + * Return: length of string + */ +int +ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len) +{ + uint32_t len = 0; + + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: vdev is NULL", __func__); + snprintf(buffer, buf_len, "vdev not found"); + return len; + } + + len = scnprintf(buffer, buf_len, + "\nTXRX stats:\n" + "\nllQueue State : %s" + "\n pause %u unpause %u" + "\n overflow %u" + "\nllQueue timer state : %s\n", + ((vdev->ll_pause.is_q_paused == false) ? "UNPAUSED" : "PAUSED"), + vdev->ll_pause.q_pause_cnt, + vdev->ll_pause.q_unpause_cnt, + vdev->ll_pause.q_overflow_cnt, + ((vdev->ll_pause.is_q_timer_on == false) + ? "NOT-RUNNING" : "RUNNING")); + return len; +} + +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) +{ + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, "txrx stats:"); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + " tx: sent %lld msdus (%lld B), " + " rejected %lld (%lld B), dropped %lld (%lld B)", + pdev->stats.pub.tx.delivered.pkts, + pdev->stats.pub.tx.delivered.bytes, + pdev->stats.pub.tx.dropped.host_reject.pkts, + pdev->stats.pub.tx.dropped.host_reject.bytes, + pdev->stats.pub.tx.dropped.download_fail.pkts + + pdev->stats.pub.tx.dropped.target_discard.pkts + + pdev->stats.pub.tx.dropped.no_ack.pkts, + pdev->stats.pub.tx.dropped.download_fail.bytes + + pdev->stats.pub.tx.dropped.target_discard.bytes + + pdev->stats.pub.tx.dropped.no_ack.bytes); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + " download fail: %lld (%lld B), " + "target discard: %lld (%lld B), " + "no ack: %lld (%lld B)", + pdev->stats.pub.tx.dropped.download_fail.pkts, + pdev->stats.pub.tx.dropped.download_fail.bytes, + pdev->stats.pub.tx.dropped.target_discard.pkts, + pdev->stats.pub.tx.dropped.target_discard.bytes, + pdev->stats.pub.tx.dropped.no_ack.pkts, + pdev->stats.pub.tx.dropped.no_ack.bytes); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Tx completion per interrupt:\n" + "Single Packet %d\n" + " 2-10 Packets %d\n" + "11-20 Packets %d\n" + "21-30 Packets %d\n" + "31-40 Packets %d\n" + "41-50 Packets %d\n" + "51-60 Packets %d\n" + " 60+ Packets %d\n", + pdev->stats.pub.tx.comp_histogram.pkts_1, + pdev->stats.pub.tx.comp_histogram.pkts_2_10, + pdev->stats.pub.tx.comp_histogram.pkts_11_20, + pdev->stats.pub.tx.comp_histogram.pkts_21_30, + pdev->stats.pub.tx.comp_histogram.pkts_31_40, + pdev->stats.pub.tx.comp_histogram.pkts_41_50, + pdev->stats.pub.tx.comp_histogram.pkts_51_60, + pdev->stats.pub.tx.comp_histogram.pkts_61_plus); + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + " rx: %lld ppdus, %lld mpdus, %lld msdus, %lld bytes, %lld errs", + pdev->stats.priv.rx.normal.ppdus, + pdev->stats.priv.rx.normal.mpdus, + pdev->stats.pub.rx.delivered.pkts, + pdev->stats.pub.rx.delivered.bytes, + pdev->stats.priv.rx.err.mpdu_bad); + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + " fwd to stack %d, fwd to fw %d, fwd to stack & fw %d\n", + pdev->stats.pub.rx.intra_bss_fwd.packets_stack, + pdev->stats.pub.rx.intra_bss_fwd.packets_fwd, + pdev->stats.pub.rx.intra_bss_fwd.packets_stack_n_fwd); +} + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev) +{ + cdf_mem_zero(&pdev->stats, sizeof(pdev->stats)); +} + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev) +{ + ol_txrx_prot_an_display(pdev->prot_an_tx_sent); + ol_txrx_prot_an_display(pdev->prot_an_rx_sent); +} + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer) +{ + return (peer->rssi_dbm == HTT_RSSI_INVALID) ? + OL_TXRX_RSSI_INVALID : peer->rssi_dbm; +} +#endif /* #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats) +{ + cdf_assert(pdev && peer && stats); + cdf_spin_lock_bh(&pdev->peer_stat_mutex); + cdf_mem_copy(stats, &peer->stats, sizeof(*stats)); + cdf_spin_unlock_bh(&pdev->peer_stat_mutex); + return A_OK; +} +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + +void ol_vdev_rx_set_intrabss_fwd(ol_txrx_vdev_handle vdev, bool val) +{ + if (NULL == vdev) + return; + + vdev->disable_intrabss_fwd = val; +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +/** + * ol_txrx_get_vdev_from_sta_id() - get vdev from sta_id + * @sta_id: sta_id + * + * Return: vdev handle + * NULL if not found. + */ +static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pdev_handle pdev = NULL; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid sta id passed"); + return NULL; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "PDEV not found for sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + + if (!peer) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "PEER [%d] not found", sta_id); + return NULL; + } + + return peer->vdev; +} + +/** + * ol_txrx_register_tx_flow_control() - register tx flow control callback + * @vdev_id: vdev_id + * @flowControl: flow control callback + * @osif_fc_ctx: callback context + * + * Return: 0 for sucess or error code + */ +int ol_txrx_register_tx_flow_control (uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + cdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = flowControl; + vdev->osif_fc_ctx = osif_fc_ctx; + cdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +/** + * ol_txrx_de_register_tx_flow_control_cb() - deregister tx flow control callback + * @vdev_id: vdev_id + * + * Return: 0 for success or error code + */ +int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id", __func__); + return -EINVAL; + } + + cdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + cdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +/** + * ol_txrx_get_tx_resource() - if tx resource less than low_watermark + * @sta_id: sta id + * @low_watermark: low watermark + * @high_watermark_offset: high watermark offset value + * + * Return: true/false + */ +bool +ol_txrx_get_tx_resource(uint8_t sta_id, + unsigned int low_watermark, + unsigned int high_watermark_offset) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_sta_id(sta_id); + if (NULL == vdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid sta_id %d", __func__, sta_id); + /* Return true so caller do not understand that resource + * is less than low_watermark. + * sta_id validation will be done in ol_tx_send_data_frame + * and if sta_id is not registered then host will drop + * packet. + */ + return true; + } + + cdf_spin_lock_bh(&vdev->pdev->tx_mutex); + if (vdev->pdev->tx_desc.num_free < (uint16_t) low_watermark) { + vdev->tx_fl_lwm = (uint16_t) low_watermark; + vdev->tx_fl_hwm = + (uint16_t) (low_watermark + high_watermark_offset); + /* Not enough free resource, stop TX OS Q */ + cdf_atomic_set(&vdev->os_q_paused, 1); + cdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return false; + } + cdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return true; +} + +/** + * ol_txrx_ll_set_tx_pause_q_depth() - set pause queue depth + * @vdev_id: vdev id + * @pause_q_depth: pause queue depth + * + * Return: 0 for success or error code + */ +int +ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + cdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.max_q_depth = pause_q_depth; + cdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return 0; +} + +/** + * ol_txrx_flow_control_cb() - call osif flow control callback + * @vdev: vdev handle + * @tx_resume: tx resume flag + * + * Return: none + */ +inline void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev, + bool tx_resume) +{ + cdf_spin_lock_bh(&vdev->flow_control_lock); + if ((vdev->osif_flow_control_cb) && (vdev->osif_fc_ctx)) + vdev->osif_flow_control_cb(vdev->osif_fc_ctx, tx_resume); + cdf_spin_unlock_bh(&vdev->flow_control_lock); + + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef IPA_OFFLOAD +void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + uint32_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + uint32_t *rx_proc_done_idx_paddr) +{ + htt_ipa_uc_get_resource(pdev->htt_pdev, + ce_sr_base_paddr, + ce_sr_ring_size, + ce_reg_paddr, + tx_comp_ring_base_paddr, + tx_comp_ring_size, + tx_num_alloc_buffer, + rx_rdy_ring_base_paddr, + rx_rdy_ring_size, rx_proc_done_idx_paddr); +} + +void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + uint32_t ipa_tx_uc_doorbell_paddr, + uint32_t ipa_rx_uc_doorbell_paddr) +{ + htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev, + ipa_tx_uc_doorbell_paddr, + ipa_rx_uc_doorbell_paddr); +} + +void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, bool uc_active, bool is_tx) +{ + htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx); +} + +/** + * ol_txrx_ipa_uc_fw_op_event_handler() - opcode event handler + * @context: pdev context + * @rxpkt: received packet + * @staid: peer id + * + * Return: None + */ +void ol_txrx_ipa_uc_fw_op_event_handler(void *context, + void *rxpkt, + uint16_t staid) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context; + + if (cdf_unlikely(!pdev)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid context", __func__); + return; + } + + if (pdev->ipa_uc_op_cb) + pdev->ipa_uc_op_cb(rxpkt, pdev->osif_dev); + else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: ipa_uc_op_cb NULL", __func__); +} + + +void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + + if (cdf_unlikely(!sched_ctx)) + return; + + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (cdf_unlikely(!pkt)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate context", __func__); + return; + } + + pkt->callback = (cds_ol_rx_thread_cb) ol_txrx_ipa_uc_fw_op_event_handler; + pkt->context = pdev; + pkt->Rxpkt = (void *)op_msg; + pkt->staId = 0; + cds_indicate_rxpkt(sched_ctx, pkt); +} + +void ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + ipa_uc_op_cb_type op_cb, void *osif_dev) +{ + pdev->ipa_uc_op_cb = op_cb; + pdev->osif_dev = osif_dev; +} + +void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev) +{ + htt_h2t_ipa_uc_get_stats(pdev->htt_pdev); +} +#endif /* IPA_UC_OFFLOAD */ + +void ol_txrx_display_stats(uint16_t value) +{ + ol_txrx_pdev_handle pdev; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return; + } + + switch (value) { + case WLAN_TXRX_STATS: + ol_txrx_stats_display(pdev); + break; + case WLAN_TXRX_TSO_STATS: +#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) + ol_txrx_stats_display_tso(pdev); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: TSO not supported", __func__); +#endif + break; + case WLAN_DUMP_TX_FLOW_POOL_INFO: + ol_tx_dump_flow_pool_info(); + break; + case WLAN_TXRX_DESC_STATS: + cdf_nbuf_tx_desc_count_display(); + break; + default: + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Unknown value", __func__); + break; + } +} + +void ol_txrx_clear_stats(uint16_t value) +{ + ol_txrx_pdev_handle pdev; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return; + } + + switch (value) { + case WLAN_TXRX_STATS: + ol_txrx_stats_clear(pdev); + break; + case WLAN_DUMP_TX_FLOW_POOL_INFO: + ol_tx_clear_flow_pool_stats(); + break; + case WLAN_TXRX_DESC_STATS: + cdf_nbuf_tx_desc_count_clear(); + break; + default: + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Unknown value", __func__); + break; + } +} + +/** + * ol_rx_data_cb() - data rx callback + * @peer: peer + * @buf_list: buffer list + * + * Return: None + */ +static void ol_rx_data_cb(struct ol_txrx_peer_t *peer, + cdf_nbuf_t buf_list) +{ + void *cds_ctx = cds_get_global_context(); + cdf_nbuf_t buf, next_buf; + CDF_STATUS ret; + ol_rx_callback_fp data_rx = NULL; + + if (cdf_unlikely(!cds_ctx)) + goto free_buf; + + cdf_spin_lock_bh(&peer->peer_info_lock); + if (cdf_unlikely(!(peer->state >= ol_txrx_peer_state_conn))) { + cdf_spin_unlock_bh(&peer->peer_info_lock); + goto free_buf; + } + data_rx = peer->osif_rx; + cdf_spin_unlock_bh(&peer->peer_info_lock); + + cdf_spin_lock_bh(&peer->bufq_lock); + if (!list_empty(&peer->cached_bufq)) { + cdf_spin_unlock_bh(&peer->bufq_lock); + /* Flush the cached frames to HDD before passing new rx frame */ + ol_txrx_flush_rx_frames(peer, 0); + } else + cdf_spin_unlock_bh(&peer->bufq_lock); + + buf = buf_list; + while (buf) { + next_buf = cdf_nbuf_queue_next(buf); + cdf_nbuf_set_next(buf, NULL); /* Add NULL terminator */ + ret = data_rx(cds_ctx, buf, peer->local_id); + if (ret != CDF_STATUS_SUCCESS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Frame Rx to HDD failed"); + cdf_nbuf_free(buf); + } + buf = next_buf; + } + return; + +free_buf: + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "%s:Dropping frames", __func__); + buf = buf_list; + while (buf) { + next_buf = cdf_nbuf_queue_next(buf); + cdf_nbuf_free(buf); + buf = next_buf; + } +} + +/** + * ol_rx_data_process() - process rx frame + * @peer: peer + * @rx_buf_list: rx buffer list + * + * Return: None + */ +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + cdf_nbuf_t rx_buf_list) +{ + /* Firmware data path active response will use shim RX thread + * T2H MSG running on SIRQ context, + * IPA kernel module API should not be called on SIRQ CTXT */ + cdf_nbuf_t buf, next_buf; + ol_rx_callback_fp data_rx = NULL; + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if ((!peer) || (!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "peer/pdev is NULL"); + goto drop_rx_buf; + } + + cdf_spin_lock_bh(&peer->peer_info_lock); + if (peer->state >= ol_txrx_peer_state_conn) + data_rx = peer->osif_rx; + cdf_spin_unlock_bh(&peer->peer_info_lock); + + /* + * If there is a data frame from peer before the peer is + * registered for data service, enqueue them on to pending queue + * which will be flushed to HDD once that station is registered. + */ + if (!data_rx) { + struct ol_rx_cached_buf *cache_buf; + buf = rx_buf_list; + while (buf) { + next_buf = cdf_nbuf_queue_next(buf); + cache_buf = cdf_mem_malloc(sizeof(*cache_buf)); + if (!cache_buf) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Failed to allocate buf to cache the rx frames"); + cdf_nbuf_free(buf); + } else { + /* Add NULL terminator */ + cdf_nbuf_set_next(buf, NULL); + cache_buf->buf = buf; + cdf_spin_lock_bh(&peer->bufq_lock); + list_add_tail(&cache_buf->list, + &peer->cached_bufq); + cdf_spin_unlock_bh(&peer->bufq_lock); + } + buf = next_buf; + } + } else { +#ifdef QCA_CONFIG_SMP + /* + * If the kernel is SMP, schedule rx thread to + * better use multicores. + */ + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_rx_data_cb(peer, rx_buf_list); + } else { + p_cds_sched_context sched_ctx = + get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + + if (unlikely(!sched_ctx)) + goto drop_rx_buf; + + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (!pkt) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "No available Rx message buffer"); + goto drop_rx_buf; + } + pkt->callback = (cds_ol_rx_thread_cb) + ol_rx_data_cb; + pkt->context = (void *)peer; + pkt->Rxpkt = (void *)rx_buf_list; + pkt->staId = peer->local_id; + cds_indicate_rxpkt(sched_ctx, pkt); + } +#else /* QCA_CONFIG_SMP */ + ol_rx_data_cb(peer, rx_buf_list, 0); +#endif /* QCA_CONFIG_SMP */ + } + + return; + +drop_rx_buf: + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Dropping rx packets"); + buf = rx_buf_list; + while (buf) { + next_buf = cdf_nbuf_queue_next(buf); + cdf_nbuf_free(buf); + buf = next_buf; + } +} + +/** + * ol_txrx_register_peer() - register peer + * @rxcb: rx callback + * @sta_desc: sta descriptor + * + * Return: CDF Status + */ +CDF_STATUS ol_txrx_register_peer(ol_rx_callback_fp rxcb, + struct ol_txrx_desc_type *sta_desc) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + union ol_txrx_peer_update_param_t param; + struct privacy_exemption privacy_filter; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL"); + return CDF_STATUS_E_INVAL; + } + + if (sta_desc->sta_id >= WLAN_MAX_STA_COUNT) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id :%d", + sta_desc->sta_id); + return CDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_desc->sta_id); + if (!peer) + return CDF_STATUS_E_FAULT; + + cdf_spin_lock_bh(&peer->peer_info_lock); + peer->osif_rx = rxcb; + peer->state = ol_txrx_peer_state_conn; + cdf_spin_unlock_bh(&peer->peer_info_lock); + + param.qos_capable = sta_desc->is_qos_enabled; + ol_txrx_peer_update(peer->vdev, peer->mac_addr.raw, ¶m, + ol_txrx_peer_update_qos_capable); + + if (sta_desc->is_wapi_supported) { + /*Privacy filter to accept unencrypted WAI frames */ + privacy_filter.ether_type = ETHERTYPE_WAI; + privacy_filter.filter_type = PRIVACY_FILTER_ALWAYS; + privacy_filter.packet_type = PRIVACY_FILTER_PACKET_BOTH; + ol_txrx_set_privacy_filters(peer->vdev, &privacy_filter, 1); + } + + ol_txrx_flush_rx_frames(peer, 0); + return CDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_clear_peer() - clear peer + * @sta_id: sta id + * + * Return: CDF Status + */ +CDF_STATUS ol_txrx_clear_peer(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!", + __func__); + return CDF_STATUS_E_FAILURE; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id %d", sta_id); + return CDF_STATUS_E_INVAL; + } + +#ifdef QCA_CONFIG_SMP + { + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + /* Drop pending Rx frames in CDS */ + if (sched_ctx) + cds_drop_rxpkt_by_staid(sched_ctx, sta_id); + } +#endif + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) + return CDF_STATUS_E_FAULT; + + /* Purge the cached rx frame queue */ + ol_txrx_flush_rx_frames(peer, 1); + + cdf_spin_lock_bh(&peer->peer_info_lock); + peer->osif_rx = NULL; + peer->state = ol_txrx_peer_state_disc; + cdf_spin_unlock_bh(&peer->peer_info_lock); + + return CDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_register_ocb_peer - Function to register the OCB peer + * @cds_ctx: Pointer to the global OS context + * @mac_addr: MAC address of the self peer + * @peer_id: Pointer to the peer ID + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS ol_txrx_register_ocb_peer(void *cds_ctx, uint8_t *mac_addr, + uint8_t *peer_id) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + + if (!cds_ctx) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Invalid context", + __func__); + return CDF_STATUS_E_FAILURE; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!", + __func__); + return CDF_STATUS_E_FAILURE; + } + + peer = ol_txrx_find_peer_by_addr(pdev, mac_addr, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find OCB peer!", + __func__); + return CDF_STATUS_E_FAILURE; + } + + ol_txrx_set_ocb_peer(pdev, peer); + + /* Set peer state to connected */ + ol_txrx_peer_state_update(pdev, peer->mac_addr.raw, + ol_txrx_peer_state_auth); + + return CDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_set_ocb_peer - Function to store the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the peer + */ +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + if (pdev == NULL) + return; + + pdev->ocb_peer = peer; + pdev->ocb_peer_valid = (NULL != peer); +} + +/** + * ol_txrx_get_ocb_peer - Function to retrieve the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the returned peer + * + * Return: true if the peer is valid, false if not + */ +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer) +{ + int rc; + + if ((pdev == NULL) || (peer == NULL)) { + rc = false; + goto exit; + } + + if (pdev->ocb_peer_valid) { + *peer = pdev->ocb_peer; + rc = true; + } else { + rc = false; + } + +exit: + return rc; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_txrx_register_pause_cb() - register pause callback + * @pause_cb: pause callback + * + * Return: CDF status + */ +CDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev || !pause_cb) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "pdev or pause_cb is NULL"); + return CDF_STATUS_E_INVAL; + } + pdev->pause_cb = pause_cb; + return CDF_STATUS_SUCCESS; +} +#endif + +#if defined(FEATURE_LRO) +void ol_txrx_lro_flush_handler(void *context, + void *rxpkt, + uint16_t staid) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context; + + if (cdf_unlikely(!pdev)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid context", __func__); + cdf_assert(0); + return; + } + + if (pdev->lro_info.lro_flush_cb) + pdev->lro_info.lro_flush_cb(pdev->lro_info.lro_data); + else + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: lro_flush_cb NULL", __func__); +} + +void ol_txrx_lro_flush(void *data) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)data; + + if (cdf_unlikely(!sched_ctx)) + return; + + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_txrx_lro_flush_handler((void *)pdev, NULL, 0); + } else { + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (cdf_unlikely(!pkt)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate context", __func__); + return; + } + + pkt->callback = (cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler; + pkt->context = pdev; + pkt->Rxpkt = NULL; + pkt->staId = 0; + cds_indicate_rxpkt(sched_ctx, pkt); + } +} + +void ol_register_lro_flush_cb(void (handler)(void *), void *data) +{ + struct ol_softc *hif_device = + (struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF); + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + pdev->lro_info.lro_flush_cb = handler; + pdev->lro_info.lro_data = data; + + ce_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, pdev); +} +#endif /* FEATURE_LRO */ diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h new file mode 100644 index 0000000000..0159009352 --- /dev/null +++ b/core/dp/txrx/ol_txrx.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_TXRX__H_ +#define _OL_TXRX__H_ + +#include /* cdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* ol_pdev_handle */ +#include "cds_sched.h" + +void ol_txrx_peer_unref_delete(struct ol_txrx_peer_t *peer); + +#ifndef OL_TX_AVG_FRM_BYTES +#define OL_TX_AVG_FRM_BYTES 1000 +#endif + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL +#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 +#endif + +/** + * ol_txrx_get_vdev_from_vdev_id() - get vdev from vdev_id + * @vdev_id: vdev_id + * + * Return: vdev handle + * NULL if not found. + */ +static inline ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id) +{ + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + ol_txrx_vdev_handle vdev = NULL; + + if (cdf_unlikely(!pdev)) { + return NULL; + } + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + return vdev; +} + +#endif /* _OL_TXRX__H_ */ diff --git a/core/dp/txrx/ol_txrx_encap.c b/core/dp/txrx/ol_txrx_encap.c new file mode 100644 index 0000000000..a7471da737 --- /dev/null +++ b/core/dp/txrx/ol_txrx_encap.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_encap.c + * @brief Provide functions to encap/decap on txrx frames. + * @details + * This file contains functions for data frame encap/decap: + * ol_tx_encap: encap outgoing data frames. + * ol_rx_decap: decap incoming data frames. + */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* cdf_nbuf_t, etc. */ +#include /* ieee80211_frame */ +#include /* struct llc, struct ether_header, etc. */ +#include /* TXRX_ASSERT1 */ +#include /* struct ol_txrx_vdev_t, ol_txrx_pdev_t,etc. */ +#include /* struct ol_rx_decap_info_t */ + +#define OL_TX_COPY_NATIVE_WIFI_HEADER(wh, msdu, hdsize, localbuf) \ + do { \ + wh = (struct ieee80211_frame *)cdf_nbuf_data(msdu); \ + if ((wh->i_fc[1] & \ + IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { \ + hdsize = sizeof(struct ieee80211_frame_addr4); \ + } else { \ + hdsize = sizeof(struct ieee80211_frame); \ + } \ + if (cdf_nbuf_len(msdu) < hdsize) { \ + return A_ERROR; \ + } \ + cdf_mem_copy(localbuf, wh, hdsize); \ + wh = (struct ieee80211_frame *)localbuf; \ + } while (0) + +static inline A_STATUS +ol_tx_copy_native_wifi_header(cdf_nbuf_t msdu, + uint8_t *hdsize, uint8_t *localbuf) +{ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)cdf_nbuf_data(msdu); + if ((wh->i_fc[1] & + IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { + *hdsize = sizeof(struct ieee80211_frame_addr4); + } else { + *hdsize = sizeof(struct ieee80211_frame); + } + if (cdf_nbuf_len(msdu) < *hdsize) + return A_ERROR; + + cdf_mem_copy(localbuf, wh, *hdsize); + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_native_wifi(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)]; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + struct ol_txrx_peer_t *peer; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + peer = tx_msdu_info->peer; + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *)localbuf; + + /*add qos cntl */ + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + + qos_cntl->i_qos[1] = 0; + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; + /* count for qos field */ + new_hdsize = + hdsize + sizeof(struct ieee80211_qosframe) - + sizeof(struct ieee80211_frame); + + /*add ht control field if needed */ + + /* copy new hd to bd */ + cdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_hdsize), localbuf, + new_hdsize); + cdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + if (tx_desc->orig_l2_hdr_bytes) { + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + tx_msdu_info->htt.info. + l3_hdr_offset); + } else { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, + localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + hdsize); + cdf_mem_copy((void *)wh, localbuf, hdsize); + cdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_8023(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + struct llc_snap_hdr_t *llc_hdr; + struct ethernet_hdr_t *eth_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_l2_hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + struct ol_txrx_peer_t *peer; + uint16_t ether_type; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + peer = tx_msdu_info->peer; + + eth_hdr = (struct ethernet_hdr_t *)cdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(uint16_t *) wh->i_dur = 0; + new_hdsize = 0; + + switch (vdev->opmode) { + case wlan_op_mode_ap: + /* DA , BSSID , SA */ + cdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + cdf_mem_copy(wh->i_addr2, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + cdf_mem_copy(wh->i_addr3, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_ibss: + /* DA, SA, BSSID */ + cdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + cdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + /* need to check the bssid behaviour for IBSS vdev */ + cdf_mem_copy(wh->i_addr3, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_sta: + /* BSSID, SA , DA */ + cdf_mem_copy(wh->i_addr1, &peer->mac_addr.raw, + IEEE80211_ADDR_LEN); + cdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + cdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_monitor: + default: + return A_ERROR; + } + /*add qos cntl */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + new_hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + + /*add ht control field if needed */ + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + new_l2_hdsize = new_hdsize; + /* add llc snap if needed */ + if (vdev->pdev->sw_tx_llc_proc_enable) { + llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize); + ether_type = + (eth_hdr->ethertype[0] << 8) | (eth_hdr->ethertype[1]); + if (ether_type >= IEEE8023_MAX_LEN) { + cdf_mem_copy(llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP + || ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } else { + /*llc ready, and it's in payload pdu, + do we need to move to BD pdu? */ + } + } + cdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_l2_hdsize), localbuf, + new_hdsize); + cdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_l2_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + return A_OK; +} + +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + return ol_tx_encap_from_native_wifi(vdev, tx_desc, msdu, + msdu_info); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + return ol_tx_encap_from_8023(vdev, tx_desc, msdu, msdu_info); + } else { + /* todo for other types */ + return A_ERROR; + } +} + +static inline void +ol_rx_decap_to_native_wifi(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct ieee80211_frame_addr4 *wh; + uint16_t hdsize; + + /* + * we need to remove Qos control field and HT control. + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx + */ + wh = (struct ieee80211_frame_addr4 *)info->hdr; + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + hdsize = sizeof(struct ieee80211_frame_addr4); + else + hdsize = sizeof(struct ieee80211_frame); + + wh = (struct ieee80211_frame_addr4 *)cdf_nbuf_push_head(msdu, hdsize); + TXRX_ASSERT2(wh != NULL); + TXRX_ASSERT2(hdsize <= info->hdr_len); + cdf_mem_copy((uint8_t *) wh, info->hdr, hdsize); + + /* amsdu subfrm handling if ethr_hdr is not NULL */ + if (ethr_hdr != NULL) { + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + cdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + cdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + cdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + cdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + cdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + cdf_mem_copy(wh->i_addr3, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + cdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + cdf_mem_copy(wh->i_addr4, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + } + } + if (IEEE80211_QOS_HAS_SEQ(wh)) { + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + wh->i_fc[1] &= ~IEEE80211_FC1_ORDER; + wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; + } +} + +static inline void +ol_rx_decap_to_8023(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_frame_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + + /* + * populate Ethernet header, + * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled) + * if ethr_hdr is not null, rx frame is "subfrm of amsdu". + */ + buf = (uint8_t *) cdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) + buf = cdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + else if (l2_hdr_space < ETHERNET_HDR_LEN) + buf = cdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + + /* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */ + if (ethr_hdr == NULL) { + /* mpdu hdr should be present in info, + re-create ethr_hdr based on mpdu hdr */ + TXRX_ASSERT2(info->hdr_len != 0); + wh = (struct ieee80211_frame_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + } + if (llc_hdr == NULL) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + cdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + TXRX_ASSERT2(pktlen <= ETHERNET_MTU); + ether_type = (uint16_t) pktlen; + ether_type = cdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + cdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +static inline A_STATUS +ol_rx_decap_subfrm_amsdu(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint8_t *subfrm_hdr; + uint8_t localbuf[ETHERNET_HDR_LEN]; + struct ethernet_hdr_t *ether_hdr = (struct ethernet_hdr_t *)localbuf; + + subfrm_hdr = (uint8_t *) cdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* decap to native wifi */ + cdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + cdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_native_wifi(vdev, msdu, info, ether_hdr); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + cdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + cdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_8023(vdev, msdu, info, ether_hdr); + } else { + /* subfrm of A-MSDU is already in 802.3 format. + * if target HW or FW has done LLC rmv process, + * we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +static inline A_STATUS +ol_rx_decap_msdu(struct ol_txrx_vdev_t *vdev, + cdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ieee80211_frame *wh; + wh = (struct ieee80211_frame *)cdf_nbuf_data(msdu); + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* Decap to native wifi because according to MSFT( + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx), + * we need to remove Qos and HTC field before indicate to OS. + */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + cdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + cdf_nbuf_pull_head(msdu, info->hdr_len); + ol_rx_decap_to_native_wifi(vdev, msdu, info, NULL); + /* 802.11 hdr^ eth_hdr^ */ + } + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + cdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + cdf_nbuf_pull_head(msdu, info->hdr_len); + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + ol_rx_decap_to_8023(vdev, msdu, info, /* 802.11 hdr */ + NULL); /* ethernet hdr */ + } else { + /* Subfrm of A-MSDU is already in 802.3 format. + * And if target HW or FW has done LLC rmv process ( + * sw_rx_lc_proc_enable == 0), we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + A_STATUS status; + uint8_t *mpdu_hdr; + + if (!info->is_subfrm) { + if (info->is_msdu_cmpl_mpdu && !info->is_first_subfrm) { + /* It's normal MSDU. */ + } else { + /* It's a first subfrm of A-MSDU and + may also be the last subfrm of A-MSDU */ + info->is_subfrm = 1; + info->hdr_len = 0; + if (vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* we save the first subfrm mpdu hdr for + * subsequent subfrm 802.11 header recovery + * in certain chip(such as Riva). + */ + mpdu_hdr = cdf_nbuf_data(msdu); + info->hdr_len = + ol_txrx_ieee80211_hdrsize(mpdu_hdr); + TXRX_ASSERT2(info->hdr_len <= + sizeof(info->hdr)); + cdf_mem_copy(info->hdr, mpdu_hdr, + info->hdr_len); + cdf_nbuf_pull_head(msdu, info->hdr_len); + } + } + } + + if (info->is_subfrm && vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* + * This case is enabled for some HWs (such as Riva). The HW + * de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. That means sw needs + * to cache the first subfrm mpdu header to generate the + * subsequent subfrm's 802.11 header. + */ + TXRX_ASSERT2(info->hdr_len != 0); + status = ol_rx_decap_subfrm_amsdu(vdev, msdu, info); + } else { + status = ol_rx_decap_msdu(vdev, msdu, info); + } + + if (info->is_msdu_cmpl_mpdu) + info->is_subfrm = info->is_first_subfrm = info->hdr_len = 0; + + return status; +} +#endif diff --git a/core/dp/txrx/ol_txrx_encap.h b/core/dp/txrx/ol_txrx_encap.h new file mode 100644 index 0000000000..5795b3bbd4 --- /dev/null +++ b/core/dp/txrx/ol_txrx_encap.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_encap.h + * @brief definitions for txrx encap/decap function and struct + */ +#ifndef _OL_TXRX_ENCAP__H_ +#define _OL_TXRX_ENCAP__H_ + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* cdf_nbuf_t */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* ol_tx_desc_t, ol_txrx_msdu_info_t */ + +/** + * @brief Encap outgoing frm from OS dependent format to Target + * acceptable frm format + * @details + * For native wifi format, the function will add Qos control field + * based on peer's QOS capbabilities . + * For 802.3 format, the function will transform to 802.11 format + * with or without QOS control field based on peer's QOS capabilites. + * @param vdev - handle to vdev object + * @param tx_desc - tx desc struct,some fields will be updated. + * @param msdu - cdf_nbuf_t + * @param msdu_info - informations from tx classification. + * @return + * A_OK: encap operation sucessful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info); + +struct ol_rx_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_htc_addr4)]; + int hdr_len; + uint8_t is_subfrm:1, is_first_subfrm:1, is_msdu_cmpl_mpdu:1; +}; + +/** + * @brief decap incoming frm from Target to Host OS + * acceptable frm format + * @details + * For native wifi format, the function will remove Qos control field + * and HT control field if any. + * For 802.3 format, the function will will do llc snap header process + * if Target haven't done that. + * @param vdev - handle to vdev object + * @param peer - the peer object. + * @param msdu - cdf_nbuf_t + * @param info - ol_rx_decap_info_t: context info for decap + * @return + * A_OK: decap operation sucessful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t msdu, struct ol_rx_decap_info_t *info); + +static inline A_STATUS +OL_TX_ENCAP(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + cdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + if (vdev->pdev->sw_tx_encap) + return ol_tx_encap(vdev, tx_desc, msdu, msdu_info); + return A_OK; +} + +static inline A_STATUS +OL_RX_DECAP(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + cdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + if (vdev->pdev->sw_rx_decap) + return ol_rx_decap(vdev, peer, msdu, info); + return A_OK; +} + +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) \ + do { \ + if (__tx_desc->orig_l2_hdr_bytes != 0) \ + cdf_nbuf_push_head(__msdu, \ + __tx_desc->orig_l2_hdr_bytes); \ + } while (0) +#else +#define OL_TX_ENCAP(vdev, tx_desc, msdu, msdu_info) A_OK +#define OL_RX_DECAP(vdev, peer, msdu, info) A_OK +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +#endif /* _OL_TXRX_ENCAP__H_ */ diff --git a/core/dp/txrx/ol_txrx_event.c b/core/dp/txrx/ol_txrx_event.c new file mode 100644 index 0000000000..3410a14083 --- /dev/null +++ b/core/dp/txrx/ol_txrx_event.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ol_txrx_types.h" + +#ifdef WDI_EVENT_ENABLE + +static inline wdi_event_subscribe *wdi_event_next_sub(wdi_event_subscribe * + wdi_sub) +{ + if (!wdi_sub) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid subscriber in %s\n", __func__); + return NULL; + } + return wdi_sub->priv.next; +} + +static inline void +wdi_event_del_subs(wdi_event_subscribe *wdi_sub, int event_index) +{ + wdi_event_notify deallocate_sub; + while (wdi_sub) { + wdi_event_subscribe *next = wdi_event_next_sub(wdi_sub); + /* + * Context is NULL for static allocation of subs + * In dynamic allocation case notify the user + */ + if (wdi_sub->context) { + deallocate_sub = wdi_sub->context; + deallocate_sub(WDI_EVENT_SUB_DEALLOCATE, + WDI_EVENT_BASE + event_index); + } + wdi_sub = next; + } + /* cdf_mem_free(wdi_sub); */ +} + +static inline void +wdi_event_iter_sub(struct ol_txrx_pdev_t *pdev, + uint32_t event_index, + wdi_event_subscribe *wdi_sub, void *data) +{ + enum WDI_EVENT event = event_index + WDI_EVENT_BASE; + + if (wdi_sub) { + do { + wdi_sub->callback(pdev, event, data); + } while ((wdi_sub = wdi_event_next_sub(wdi_sub))); + } +} + +void +wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + /* + * Input validation + */ + if (!event) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid WDI event in %s\n", __func__); + return; + } + if (!txrx_pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid pdev in WDI event handler\n"); + return; + } + /* + * There can be NULL data, so no validation for the data + * Subscribers must do the sanity based on the requirements + */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + + /* Find the subscriber */ + wdi_event_iter_sub(txrx_pdev, event_index, wdi_sub, data); +} + +A_STATUS +wdi_event_sub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, enum WDI_EVENT event) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + /* Input validation */ + if (!txrx_pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid txrx_pdev in %s", __func__); + return A_ERROR; + } + if (!event_cb_sub) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return A_ERROR; + } + if ((!event) || (event >= WDI_EVENT_LAST) || (event < WDI_EVENT_BASE)) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid event in %s", __func__); + return A_ERROR; + } + /* Input validation */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + /* + * Check if it is the first subscriber of the event + */ + if (!wdi_sub) { + wdi_sub = event_cb_sub; + wdi_sub->priv.next = NULL; + wdi_sub->priv.prev = NULL; + txrx_pdev->wdi_event_list[event_index] = wdi_sub; + return A_OK; + } + event_cb_sub->priv.next = wdi_sub; + event_cb_sub->priv.prev = NULL; + wdi_sub->priv.prev = event_cb_sub; + txrx_pdev->wdi_event_list[event_index] = event_cb_sub; + + return A_OK; +} + +A_STATUS +wdi_event_unsub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, enum WDI_EVENT event) +{ + uint32_t event_index = event - WDI_EVENT_BASE; + + /* Input validation */ + if (!event_cb_sub) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return A_ERROR; + } + if (!event_cb_sub->priv.prev) { + txrx_pdev->wdi_event_list[event_index] = + event_cb_sub->priv.next; + } else { + event_cb_sub->priv.prev->priv.next = event_cb_sub->priv.next; + } + if (event_cb_sub->priv.next) + event_cb_sub->priv.next->priv.prev = event_cb_sub->priv.prev; + + /* cdf_mem_free(event_cb_sub); */ + + return A_OK; +} + +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + /* Input validation */ + if (!txrx_pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI event attach failed", + __func__); + return A_ERROR; + } + /* Separate subscriber list for each event */ + txrx_pdev->wdi_event_list = (wdi_event_subscribe **) + cdf_mem_malloc( + sizeof(wdi_event_subscribe *) * + WDI_NUM_EVENTS); + if (!txrx_pdev->wdi_event_list) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Insufficient memory for the WDI event lists\n"); + return A_NO_MEMORY; + } + return A_OK; +} + +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + int i; + wdi_event_subscribe *wdi_sub; + if (!txrx_pdev) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI detach failed", + __func__); + return A_ERROR; + } + if (!txrx_pdev->wdi_event_list) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, + "%s: wdi_event_list is NULL", __func__); + return A_ERROR; + } + + for (i = 0; i < WDI_NUM_EVENTS; i++) { + wdi_sub = txrx_pdev->wdi_event_list[i]; + if (wdi_sub) { + /* Delete all the subscribers */ + wdi_event_del_subs(wdi_sub, i); + } + } + /* txrx_pdev->wdi_event_list would be non-null */ + cdf_mem_free(txrx_pdev->wdi_event_list); + return A_OK; +} + +#endif /* WDI_EVENT_ENABLE */ diff --git a/core/dp/txrx/ol_txrx_flow_control.c b/core/dp/txrx/ol_txrx_flow_control.c new file mode 100644 index 0000000000..fd759baee8 --- /dev/null +++ b/core/dp/txrx/ol_txrx_flow_control.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* OS abstraction libraries */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_atomic_read, etc. */ +#include /* cdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* pdev stats */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_enqueue */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include + +#define TX_FLOW_START_TH 25 +#define TX_FLOW_STOP_TH 10 +#define INVALID_FLOW_ID 0xFF +#define MAX_INVALID_BIN 3 + + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_ID 0xEF +#define TX_FLOW_MGMT_POOL_SIZE 32 + +/** + * ol_tx_register_global_mgmt_pool() - register global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + pdev->mgmt_pool = ol_tx_create_flow_pool(TX_FLOW_MGMT_POOL_ID, + TX_FLOW_MGMT_POOL_SIZE); + if (!pdev->mgmt_pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Management pool creation failed\n"); + } + return; +} + +/** + * ol_tx_deregister_global_mgmt_pool() - Deregister global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_delete_flow_pool(pdev->mgmt_pool); + return; +} +#else +static inline void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +/** + * ol_tx_register_flow_control() - Register fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ + cdf_spinlock_init(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INIT(&pdev->tx_desc.flow_pool_list); + + ol_tx_register_global_mgmt_pool(pdev); +} + +/** + * ol_tx_deregister_flow_control() - Deregister fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_deregister_global_mgmt_pool(pdev); + + cdf_spinlock_destroy(&pdev->tx_desc.flow_pool_list_lock); + if (!TAILQ_EMPTY(&pdev->tx_desc.flow_pool_list)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "flow pool list is not empty!!!\n"); + } +} + +/** + * ol_tx_dump_flow_pool_info() - dump global_pool and flow_pool info + * + * Return: none + */ +void ol_tx_dump_flow_pool_info(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL; + struct ol_tx_flow_pool_t tmp_pool; + + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global Pool\n"); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Total %d :: Available %d\n", + pdev->tx_desc.pool_size, pdev->tx_desc.num_free); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid flow_pool %d\n", + pdev->tx_desc.num_invalid_bin); + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool map received %d\n", + pdev->pool_stats.pool_map_count); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool unmap received %d\n", + pdev->pool_stats.pool_unmap_count); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Pkt dropped due to unavailablity of pool %d\n", + pdev->pool_stats.pkt_drop_no_pool); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Pkt dropped due to unavailablity of descriptors %d\n", + pdev->pool_stats.pkt_drop_no_desc); + + /* + * Nested spin lock. + * Always take in below order. + * flow_pool_list_lock -> flow_pool_lock + */ + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + cdf_spin_lock_bh(&pool->flow_pool_lock); + cdf_mem_copy(&tmp_pool, pool, sizeof(tmp_pool)); + cdf_spin_unlock_bh(&pool->flow_pool_lock); + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Flow_pool_id %d :: status %d\n", + tmp_pool.flow_pool_id, tmp_pool.status); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Total %d :: Available %d :: Deficient %d\n", + tmp_pool.flow_pool_size, tmp_pool.avail_desc, + tmp_pool.deficient_desc); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Start_TH %d :: Stop_TH %d\n", + tmp_pool.start_th, tmp_pool.stop_th); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Member flow_id %d :: flow_type %d\n", + tmp_pool.member_flow_id, tmp_pool.flow_type); + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return; +} + +/** + * ol_tx_clear_flow_pool_stats() - clear flow pool statistics + * + * Return: none + */ +void ol_tx_clear_flow_pool_stats(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev is null\n", + __func__); + return; + } + cdf_mem_zero(&pdev->pool_stats, sizeof(pdev->pool_stats)); +} + +/** + * ol_tx_move_desc_n() - Move n descriptors from src_pool to dst_pool. + * @src_pool: source pool + * @dst_pool: destination pool + * @desc_move_count: descriptor move count + * + * Return: actual descriptors moved + */ +static int ol_tx_move_desc_n(struct ol_tx_flow_pool_t *src_pool, + struct ol_tx_flow_pool_t *dst_pool, + int desc_move_count) +{ + uint16_t count = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + + /* Take descriptors from source pool and put it in temp_list */ + cdf_spin_lock_bh(&src_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + tx_desc = &src_pool->freelist->tx_desc; + src_pool->freelist = src_pool->freelist->next; + src_pool->avail_desc--; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + cdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + /* Take descriptors from temp_list and put it in destination pool */ + cdf_spin_lock_bh(&dst_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + if (dst_pool->deficient_desc) + dst_pool->deficient_desc--; + else + break; + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + tx_desc->pool = dst_pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + dst_pool->freelist; + dst_pool->freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + dst_pool->avail_desc++; + count++; + } + cdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + + /* If anything is there in temp_list put it back to source pool */ + cdf_spin_lock_bh(&src_pool->flow_pool_lock); + while (temp_list) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + tx_desc->pool = src_pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + src_pool->freelist; + src_pool->freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + src_pool->avail_desc++; + } + cdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + return count; +} + + +/** + * ol_tx_distribute_descs_to_deficient_pools() - Distribute descriptors + * @src_pool: source pool + * + * Distribute all descriptors of source pool to all + * deficient pools as per flow_pool_list. + * + * Return: 0 for sucess + */ +int +ol_tx_distribute_descs_to_deficient_pools(struct ol_tx_flow_pool_t *src_pool) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *dst_pool = NULL; + uint16_t desc_count = src_pool->avail_desc; + uint16_t desc_move_count = 0; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + return -EINVAL; + } + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(dst_pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + cdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->deficient_desc) { + desc_move_count = + (dst_pool->deficient_desc > desc_count) ? + desc_count : dst_pool->deficient_desc; + cdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + desc_move_count = ol_tx_move_desc_n(src_pool, + dst_pool, desc_move_count); + desc_count -= desc_move_count; + cdf_spin_lock_bh(&dst_pool->flow_pool_lock); + } + cdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + if (desc_count == 0) + break; + } + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return 0; +} + + +/** + * ol_tx_create_flow_pool() - create flow pool + * @flow_pool_id: flow pool id + * @flow_pool_size: flow pool size + * + * Return: flow_pool pointer / NULL for error + */ +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + uint16_t size = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + uint32_t stop_threshold = + ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + uint32_t start_threshold = stop_threshold + + ol_cfg_get_tx_flow_start_queue_offset(pdev->ctrl_pdev); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + return NULL; + } + + pool = cdf_mem_malloc(sizeof(*pool)); + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: malloc failed\n", __func__); + return NULL; + } + + pool->flow_pool_id = flow_pool_id; + pool->flow_pool_size = flow_pool_size; + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + pool->start_th = (start_threshold * flow_pool_size)/100; + pool->stop_th = (stop_threshold * flow_pool_size)/100; + cdf_spinlock_init(&pool->flow_pool_lock); + + /* Take TX descriptor from global_pool and put it in temp_list*/ + cdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.num_free >= pool->flow_pool_size) + size = pool->flow_pool_size; + else + size = pdev->tx_desc.num_free; + + for (i = 0; i < size; i++) { + pdev->tx_desc.num_free--; + tx_desc = &pdev->tx_desc.freelist->tx_desc; + pdev->tx_desc.freelist = pdev->tx_desc.freelist->next; + tx_desc->pool = pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + cdf_spin_unlock_bh(&pdev->tx_mutex); + + /* put temp_list to flow_pool */ + pool->freelist = temp_list; + pool->avail_desc = size; + pool->deficient_desc = pool->flow_pool_size - pool->avail_desc; + + /* Add flow_pool to flow_pool_list */ + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return pool; +} + +/** + * ol_tx_delete_flow_pool() - delete flow pool + * @pool: flow pool pointer + * + * Delete flow_pool if all tx descriptors are available. + * Otherwise put it in FLOW_POOL_INVALID state. + * + * Return: 0 for success or error + */ +int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + uint16_t i, size; + union ol_tx_desc_list_elem_t *temp_list = NULL; + struct ol_tx_desc_t *tx_desc = NULL; + + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pool is NULL\n", __func__); + return -ENOMEM; + } + + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_REMOVE(&pdev->tx_desc.flow_pool_list, pool, flow_pool_list_elem); + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + cdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc == pool->flow_pool_size) + pool->status = FLOW_POOL_INACTIVE; + else + pool->status = FLOW_POOL_INVALID; + + /* Take all free descriptors and put it in temp_list */ + temp_list = pool->freelist; + size = pool->avail_desc; + pool->freelist = NULL; + pool->avail_desc = 0; + + if (pool->status == FLOW_POOL_INACTIVE) { + cdf_spin_unlock_bh(&pool->flow_pool_lock); + /* Free flow_pool */ + cdf_spinlock_destroy(&pool->flow_pool_lock); + cdf_mem_free(pool); + } else { /* FLOW_POOL_INVALID case*/ + pool->flow_pool_size -= size; + pool->flow_pool_id = INVALID_FLOW_ID; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + + pdev->tx_desc.num_invalid_bin++; + if (pdev->tx_desc.num_invalid_bin > MAX_INVALID_BIN) + ASSERT(0); + + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + + /* put free descriptors to global pool */ + cdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < size; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + pdev->tx_desc.freelist; + pdev->tx_desc.freelist = + (union ol_tx_desc_list_elem_t *)tx_desc; + pdev->tx_desc.num_free++; + + } + cdf_spin_unlock_bh(&pdev->tx_mutex); + + return 0; +} + + +/** + * ol_tx_free_invalid_flow_pool() - free invalid pool + * @pool: pool + * + * Return: 0 for success or failure + */ +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if ((!pdev) || (!pool) || (pool->status != FLOW_POOL_INVALID)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Invalid pool/pdev\n", __func__); + return -EINVAL; + } + + /* direclty distribute to other deficient pools */ + ol_tx_distribute_descs_to_deficient_pools(pool); + + cdf_spin_lock_bh(&pool->flow_pool_lock); + pool->flow_pool_size = pool->avail_desc; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + + pdev->tx_desc.num_invalid_bin--; + + return ol_tx_delete_flow_pool(pool); +} + +/** + * ol_tx_get_flow_pool() - get flow_pool from flow_pool_id + * @flow_pool_id: flow pool id + * + * Return: flow_pool ptr / NULL if not found + */ +struct ol_tx_flow_pool_t *ol_tx_get_flow_pool(uint8_t flow_pool_id) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL; + bool is_found = false; + + cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + cdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_id == flow_pool_id) { + cdf_spin_unlock_bh(&pool->flow_pool_lock); + is_found = true; + break; + } + cdf_spin_unlock_bh(&pool->flow_pool_lock); + } + cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (is_found == false) + pool = NULL; + + return pool; + +} + + +/** + * ol_tx_flow_pool_vdev_map() - Map flow_pool with vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +void ol_tx_flow_pool_vdev_map(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + + vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid vdev_id %d\n", + __func__, vdev_id); + return; + } + + vdev->pool = pool; + cdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = vdev_id; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + + return; +} + +/** + * ol_tx_flow_pool_vdev_unmap() - Unmap flow_pool from vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +void ol_tx_flow_pool_vdev_unmap(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + + vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid vdev_id %d\n", + __func__, vdev_id); + return; + } + + vdev->pool = NULL; + cdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = INVALID_FLOW_ID; + cdf_spin_unlock_bh(&pool->flow_pool_lock); + + return; +} + +/** + * ol_tx_flow_pool_map_handler() - Map flow_id with pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * @flow_pool_size: pool size + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_MAP + * + * Return: none + */ +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + uint8_t pool_create = 0; + enum htt_flow_type type = flow_type; + + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: flow_id %d flow_type %d flow_pool_id %d flow_pool_size %d\n", + __func__, flow_id, flow_type, flow_pool_id, flow_pool_size); + + if (cdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_map_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + pool = ol_tx_create_flow_pool(flow_pool_id, flow_pool_size); + if (pool == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: creation of flow_pool %d size %d failed\n", + __func__, flow_pool_id, flow_pool_size); + return; + } + pool_create = 1; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_map(pool, flow_id); + break; + default: + if (pool_create) + ol_tx_delete_flow_pool(pool); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow type %d not supported !!!\n", + __func__, type); + break; + } + + return; +} + +/** + * ol_tx_flow_pool_unmap_handler() - Unmap flow_id from pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * + * Return: none + */ +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + enum htt_flow_type type = flow_type; + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: flow_id %d flow_type %d flow_pool_id %d\n", + __func__, flow_id, flow_type, flow_pool_id); + + if (cdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_unmap_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow_pool not available flow_pool_id %d\n", + __func__, type); + return; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_unmap(pool, flow_id); + break; + default: + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow type %d not supported !!!\n", + __func__, type); + return; + } + + /* only delete if all descriptors are available */ + ol_tx_delete_flow_pool(pool); + + return; +} + + diff --git a/core/dp/txrx/ol_txrx_internal.h b/core/dp/txrx/ol_txrx_internal.h new file mode 100644 index 0000000000..30315e64ce --- /dev/null +++ b/core/dp/txrx/ol_txrx_internal.h @@ -0,0 +1,737 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_TXRX_INTERNAL__H_ +#define _OL_TXRX_INTERNAL__H_ + +#include /* cdf_assert */ +#include /* cdf_nbuf_t */ +#include /* cdf_mem_set */ +#include /* ieee80211_frame */ +#include /* htt_rx_msdu_desc_completes_mpdu, etc. */ + +#include + +#include +#include /* ETHERNET_HDR_LEN, etc. */ +#include /* IPV4_HDR_LEN, etc. */ +#include /* IPV6_HDR_LEN, etc. */ +#include /* IP_PROTOCOL_TCP, etc. */ + +#ifdef ATH_11AC_TXCOMPACT +#define OL_TX_DESC_NO_REFS(tx_desc) 1 +#define OL_TX_DESC_REF_INIT(tx_desc) /* no-op */ +#define OL_TX_DESC_REF_INC(tx_desc) /* no-op */ +#else +#define OL_TX_DESC_NO_REFS(tx_desc) \ + cdf_atomic_dec_and_test(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INIT(tx_desc) cdf_atomic_init(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INC(tx_desc) cdf_atomic_inc(&tx_desc->ref_cnt) +#endif + +#ifndef TXRX_ASSERT_LEVEL +#define TXRX_ASSERT_LEVEL 3 +#endif + +#ifdef __KLOCWORK__ +#define TXRX_ASSERT1(x) do { if (!(x)) abort(); } while (0) +#define TXRX_ASSERT2(x) do { if (!(x)) abort(); } while (0) +#else /* #ifdef __KLOCWORK__ */ + +#if TXRX_ASSERT_LEVEL > 0 +#define TXRX_ASSERT1(condition) cdf_assert((condition)) +#else +#define TXRX_ASSERT1(condition) +#endif + +#if TXRX_ASSERT_LEVEL > 1 +#define TXRX_ASSERT2(condition) cdf_assert((condition)) +#else +#define TXRX_ASSERT2(condition) +#endif +#endif /* #ifdef __KLOCWORK__ */ +enum { + /* FATAL_ERR - print only irrecoverable error messages */ + TXRX_PRINT_LEVEL_FATAL_ERR, + + /* ERR - include non-fatal err messages */ + TXRX_PRINT_LEVEL_ERR, + + /* WARN - include warnings */ + TXRX_PRINT_LEVEL_WARN, + + /* INFO1 - include fundamental, infrequent events */ + TXRX_PRINT_LEVEL_INFO1, + + /* INFO2 - include non-fundamental but infrequent events */ + TXRX_PRINT_LEVEL_INFO2, + + /* INFO3 - include frequent events */ + /* to avoid performance impact, don't use INFO3 + unless explicitly enabled */ +#ifdef TXRX_PRINT_VERBOSE_ENABLE + TXRX_PRINT_LEVEL_INFO3, +#endif /* TXRX_PRINT_VERBOSE_ENABLE */ +}; + +extern unsigned g_txrx_print_level; + +#ifdef TXRX_PRINT_ENABLE + +#include /* va_list */ +#include /* cdf_vprint */ + +/* Supress 4296 - expression is always true +* It will fire if level is TXRX_PRINT_LEVEL_FATAL_ERR (0) +* because g_txrx_print_level is unsigned */ +#define ol_txrx_print(level, fmt, ...) { \ + if (level <= g_txrx_print_level) \ + cdf_print(fmt, ## __VA_ARGS__); } +#define TXRX_PRINT(level, fmt, ...) \ + ol_txrx_print(level, "TXRX: " fmt, ## __VA_ARGS__) + +#ifdef TXRX_PRINT_VERBOSE_ENABLE + +#define ol_txrx_print_verbose(fmt, ...) { \ + if (TXRX_PRINT_LEVEL_INFO3 <= g_txrx_print_level) \ + cdf_print(fmt, ## __VA_ARGS__); } +#define TXRX_PRINT_VERBOSE(fmt, ...) \ + ol_txrx_print_verbose("TXRX: " fmt, ## __VA_ARGS__) +#else +#define TXRX_PRINT_VERBOSE(fmt, ...) +#endif /* TXRX_PRINT_VERBOSE_ENABLE */ + +/* define PN check failure message print rate + as 1 second */ +#define TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS 1000 + +#else +#define TXRX_PRINT(level, fmt, ...) +#define TXRX_PRINT_VERBOSE(fmt, ...) +#endif /* TXRX_PRINT_ENABLE */ + +/*--- tx credit debug printouts ---*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if DEBUG_CREDIT +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) cdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) +#endif + +/*--- tx scheduler debug printouts ---*/ + +#ifdef HOST_TX_SCHED_DEBUG +#define TX_SCHED_DEBUG_PRINT(fmt, ...) cdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_SCHED_DEBUG_PRINT(fmt, ...) +#endif +#define TX_SCHED_DEBUG_PRINT_ALWAYS(fmt, ...) cdf_print(fmt, ## __VA_ARGS__) + +#define OL_TXRX_LIST_APPEND(head, tail, elem) \ + do { \ + if (!(head)) { \ + (head) = (elem); \ + } else { \ + cdf_nbuf_set_next((tail), (elem)); \ + } \ + (tail) = (elem); \ + } while (0) + +static inline void +ol_rx_mpdu_list_next(struct ol_txrx_pdev_t *pdev, + void *mpdu_list, + cdf_nbuf_t *mpdu_tail, cdf_nbuf_t *next_mpdu) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + cdf_nbuf_t msdu; + + /* + * For now, we use a simply flat list of MSDUs. + * So, traverse the list until we reach the last MSDU within the MPDU. + */ + TXRX_ASSERT2(mpdu_list); + msdu = mpdu_list; + while (!htt_rx_msdu_desc_completes_mpdu + (htt_pdev, htt_rx_msdu_desc_retrieve(htt_pdev, msdu))) { + msdu = cdf_nbuf_next(msdu); + TXRX_ASSERT2(msdu); + } + /* msdu now points to the last MSDU within the first MPDU */ + *mpdu_tail = msdu; + *next_mpdu = cdf_nbuf_next(msdu); +} + +/*--- txrx stats macros ---*/ + +/* unconditional defs */ +#define TXRX_STATS_INCR(pdev, field) TXRX_STATS_ADD(pdev, field, 1) + +/* default conditional defs (may be undefed below) */ + +#define TXRX_STATS_INIT(_pdev) \ + cdf_mem_set(&((_pdev)->stats), sizeof((_pdev)->stats), 0x0) +#define TXRX_STATS_ADD(_pdev, _field, _delta) { \ + _pdev->stats._field += _delta; } +#define TXRX_STATS_MSDU_INCR(pdev, field, netbuf) \ + do { \ + TXRX_STATS_INCR((pdev), pub.field.pkts); \ + TXRX_STATS_ADD((pdev), pub.field.bytes, cdf_nbuf_len(netbuf)); \ + } while (0) + +/* conditional defs based on verbosity level */ + + +#define TXRX_STATS_MSDU_LIST_INCR(pdev, field, netbuf_list) \ + do { \ + cdf_nbuf_t tmp_list = netbuf_list; \ + while (tmp_list) { \ + TXRX_STATS_MSDU_INCR(pdev, field, tmp_list); \ + tmp_list = cdf_nbuf_next(tmp_list); \ + } \ + } while (0) + +#define TXRX_STATS_MSDU_INCR_TX_STATUS(status, pdev, netbuf) do { \ + if (status == htt_tx_status_ok) \ + TXRX_STATS_MSDU_INCR(pdev, tx.delivered, netbuf); \ + else if (status == htt_tx_status_discard) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.target_discard, \ + netbuf); \ + else if (status == htt_tx_status_no_ack) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.no_ack, netbuf); \ + else if (status == htt_tx_status_download_fail) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.download_fail, \ + netbuf); \ + else \ + /* NO-OP */; \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.comp_histogram.pkts_1, 1);\ + } else if (_p_cntrs > 2 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_2_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_11_20, 1); \ + } else if (_p_cntrs > 20 && _p_cntrs <= 30) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_21_30, 1); \ + } else if (_p_cntrs > 30 && _p_cntrs <= 40) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_31_40, 1); \ + } else if (_p_cntrs > 40 && _p_cntrs <= 50) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_41_50, 1); \ + } else if (_p_cntrs > 50 && _p_cntrs <= 60) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_51_60, 1); \ + } else { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_61_plus, 1); \ + } \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_STATS(_pdev, _status, _p_cntrs, _b_cntrs) \ + do { \ + switch (status) { \ + case htt_tx_status_ok: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.bytes, _b_cntrs); \ + break; \ + case htt_tx_status_discard: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.pkts, _p_cntrs);\ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.bytes, _b_cntrs);\ + break; \ + case htt_tx_status_no_ack: \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.pkts, \ + _p_cntrs); \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.bytes, \ + _b_cntrs); \ + break; \ + case htt_tx_status_download_fail: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.bytes, _b_cntrs);\ + break; \ + default: \ + break; \ + } \ + TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs); \ + } while (0) + + +/*--- txrx sequence number trace macros ---*/ + +#define TXRX_SEQ_NUM_ERR(_status) (0xffff - _status) + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, + uint16_t seq_num, int num_mpdus); + +#define OL_RX_REORDER_TRACE_ATTACH ol_rx_reorder_trace_attach +#define OL_RX_REORDER_TRACE_DETACH ol_rx_reorder_trace_detach +#define OL_RX_REORDER_TRACE_ADD ol_rx_reorder_trace_add + +#else + +#define OL_RX_REORDER_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_REORDER_TRACE_DETACH(_pdev) +#define OL_RX_REORDER_TRACE_ADD(pdev, tid, reorder_idx, seq_num, num_mpdus) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace macros ---*/ + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint16_t tid, void *rx_desc); + +#define OL_RX_PN_TRACE_ATTACH ol_rx_pn_trace_attach +#define OL_RX_PN_TRACE_DETACH ol_rx_pn_trace_detach +#define OL_RX_PN_TRACE_ADD ol_rx_pn_trace_add + +#else + +#define OL_RX_PN_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_PN_TRACE_DETACH(_pdev) +#define OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc) + +#endif /* ENABLE_RX_PN_TRACE */ + +static inline int ol_txrx_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int size = sizeof(struct ieee80211_frame); + + /* NB: we don't handle control frames */ + TXRX_ASSERT1((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != + IEEE80211_FC0_TYPE_CTL); + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + if (IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + /* Qos frame with Order bit set indicates an HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/*--- frame display utility ---*/ + +enum ol_txrx_frm_dump_options { + ol_txrx_frm_dump_contents = 0x1, + ol_txrx_frm_dump_tcp_seq = 0x2, +}; + +#ifdef TXRX_DEBUG_DATA +static inline void +ol_txrx_frms_dump(const char *name, + struct ol_txrx_pdev_t *pdev, + cdf_nbuf_t frm, + enum ol_txrx_frm_dump_options display_options, int max_len) +{ +#define TXRX_FRM_DUMP_MAX_LEN 128 + uint8_t local_buf[TXRX_FRM_DUMP_MAX_LEN] = { 0 }; + uint8_t *p; + + if (name) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, "%s\n", + name); + } + while (frm) { + p = cdf_nbuf_data(frm); + if (display_options & ol_txrx_frm_dump_tcp_seq) { + int tcp_offset; + int l2_hdr_size; + uint16_t ethtype; + uint8_t ip_prot; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr = + (struct ethernet_hdr_t *)p; + l2_hdr_size = ETHERNET_HDR_LEN; + + /* + * LLC/SNAP present? + */ + ethtype = (enet_hdr->ethertype[0] << 8) | + enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 format */ + struct llc_snap_hdr_t *llc_hdr; + + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + /* (generic?) 802.11 */ + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + if (ethtype == ETHERTYPE_IPV4) { + struct ipv4_hdr_t *ipv4_hdr; + ipv4_hdr = + (struct ipv4_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv4_hdr->protocol; + tcp_offset = l2_hdr_size + IPV4_HDR_LEN; + } else if (ethtype == ETHERTYPE_IPV6) { + struct ipv6_hdr_t *ipv6_hdr; + ipv6_hdr = + (struct ipv6_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv6_hdr->next_hdr; + tcp_offset = l2_hdr_size + IPV6_HDR_LEN; + } else { + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, + "frame %p non-IP ethertype (%x)\n", + frm, ethtype); + goto NOT_IP_TCP; + } + if (ip_prot == IP_PROTOCOL_TCP) { +#if NEVERDEFINED + struct tcp_hdr_t *tcp_hdr; + uint32_t tcp_seq_num; + tcp_hdr = (struct tcp_hdr_t *)(p + tcp_offset); + tcp_seq_num = + (tcp_hdr->seq_num[0] << 24) | + (tcp_hdr->seq_num[1] << 16) | + (tcp_hdr->seq_num[1] << 8) | + (tcp_hdr->seq_num[1] << 0); + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, + "frame %p: TCP seq num = %d\n", frm, + tcp_seq_num); +#else + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, + "frame %p: TCP seq num = %d\n", frm, + ((*(p + tcp_offset + 4)) << 24) | + ((*(p + tcp_offset + 5)) << 16) | + ((*(p + tcp_offset + 6)) << 8) | + (*(p + tcp_offset + 7))); +#endif + } else { + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, + "frame %p non-TCP IP protocol (%x)\n", + frm, ip_prot); + } + } +NOT_IP_TCP: + if (display_options & ol_txrx_frm_dump_contents) { + int i, frag_num, len_lim; + len_lim = max_len; + if (len_lim > cdf_nbuf_len(frm)) + len_lim = cdf_nbuf_len(frm); + if (len_lim > TXRX_FRM_DUMP_MAX_LEN) + len_lim = TXRX_FRM_DUMP_MAX_LEN; + + /* + * Gather frame contents from netbuf fragments + * into a contiguous buffer. + */ + frag_num = 0; + i = 0; + while (i < len_lim) { + int frag_bytes; + frag_bytes = + cdf_nbuf_get_frag_len(frm, frag_num); + if (frag_bytes > len_lim - i) + frag_bytes = len_lim - i; + if (frag_bytes > 0) { + p = cdf_nbuf_get_frag_vaddr(frm, + frag_num); + cdf_mem_copy(&local_buf[i], p, + frag_bytes); + } + frag_num++; + i += frag_bytes; + } + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "frame %p data (%p), hex dump of bytes 0-%d of %d:\n", + frm, p, len_lim - 1, (int)cdf_nbuf_len(frm)); + p = local_buf; + while (len_lim > 16) { + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, + " " /* indent */ + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + *(p + 0), *(p + 1), *(p + 2), + *(p + 3), *(p + 4), *(p + 5), + *(p + 6), *(p + 7), *(p + 8), + *(p + 9), *(p + 10), *(p + 11), + *(p + 12), *(p + 13), *(p + 14), + *(p + 15)); + p += 16; + len_lim -= 16; + } + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + " " /* indent */); + while (len_lim > 0) { + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO, "%02x ", *p); + p++; + len_lim--; + } + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO, + "\n"); + } + frm = cdf_nbuf_next(frm); + } +} +#else +#define ol_txrx_frms_dump(name, pdev, frms, display_options, max_len) +#endif /* TXRX_DEBUG_DATA */ + +#ifdef SUPPORT_HOST_STATISTICS + +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) \ + ol_rx_err_statistics(pdev->ctrl_pdev, vdev->vdev_id, err_type, \ + sec_type, is_mcast); + +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) \ + do { \ + int is_mcast; \ + enum htt_sec_type sec_type; \ + is_mcast = htt_rx_msdu_is_wlan_mcast( \ + pdev->htt_pdev, rx_desc); \ + sec_type = peer->security[is_mcast \ + ? txrx_sec_mcast \ + : txrx_sec_ucast].sec_type; \ + OL_RX_ERR_STATISTICS(pdev, vdev, err_type, \ + pdev->sec_types[sec_type], \ + is_mcast); \ + } while (false) + +#define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \ + do { \ + struct ieee80211_frame *wh = NULL; \ + /*FIX THIS : */ \ + /* Here htt_rx_mpdu_wifi_hdr_retrieve should be used. */ \ + /*But at present it seems it does not work.*/ \ + /*wh = (struct ieee80211_frame *) */ \ + /*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \ + /* this only apply to LL device.*/ \ + if (ol_cfg_frame_type(pdev->ctrl_pdev) == \ + wlan_frm_fmt_native_wifi) { \ + /* For windows, it is always native wifi header .*/ \ + wh = (struct ieee80211_frame *)cdf_nbuf_data(rx_msdu); \ + } \ + ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \ + wh, OL_RX_ERR_UNKNOWN_PEER); \ + } while (false) + +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) \ + do { \ + enum ol_rx_err_type err_type = OL_RX_ERR_NONE; \ + if (rx_status == htt_rx_status_decrypt_err) \ + err_type = OL_RX_ERR_DECRYPT; \ + else if (rx_status == htt_rx_status_tkip_mic_err) \ + err_type = OL_RX_ERR_TKIP_MIC; \ + else if (rx_status == htt_rx_status_mpdu_length_err) \ + err_type = OL_RX_ERR_MPDU_LENGTH; \ + else if (rx_status == htt_rx_status_mpdu_encrypt_required_err) \ + err_type = OL_RX_ERR_ENCRYPT_REQUIRED; \ + else if (rx_status == htt_rx_status_err_dup) \ + err_type = OL_RX_ERR_DUP; \ + else if (rx_status == htt_rx_status_err_fcs) \ + err_type = OL_RX_ERR_FCS; \ + else \ + err_type = OL_RX_ERR_UNKNOWN; \ + \ + if (vdev != NULL && peer != NULL) { \ + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, \ + rx_mpdu_desc, err_type); \ + } else { \ + OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu); \ + } \ + } while (false) +#else +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) +#endif /* SUPPORT_HOST_STATISTICS */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +#define OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, type, msdu) \ + do { \ + cdf_spin_lock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + peer->stats.tx_or_rx.frms.type += 1; \ + peer->stats.tx_or_rx.bytes.type += cdf_nbuf_len(msdu); \ + cdf_spin_unlock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + } while (0) +#define OL_TXRX_PEER_STATS_UPDATE(peer, tx_or_rx, msdu) \ + do { \ + struct ol_txrx_vdev_t *vdev = peer->vdev; \ + struct ol_txrx_pdev_t *pdev = vdev->pdev; \ + uint8_t *dest_addr; \ + if (pdev->frame_format == wlan_frm_fmt_802_3) { \ + dest_addr = cdf_nbuf_data(msdu); \ + } else { /* 802.11 format */ \ + struct ieee80211_frame *frm; \ + frm = (struct ieee80211_frame *) cdf_nbuf_data(msdu); \ + if (vdev->opmode == wlan_op_mode_ap) { \ + dest_addr = (uint8_t *) &(frm->i_addr1[0]); \ + } else { \ + dest_addr = (uint8_t *) &(frm->i_addr3[0]); \ + } \ + } \ + if (cdf_unlikely(IEEE80211_IS_BROADCAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + bcast, msdu); \ + } else if (cdf_unlikely(IEEE80211_IS_MULTICAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + mcast, msdu); \ + } else { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + ucast, msdu); \ + } \ + } while (0) +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, tx, msdu) +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, rx, msdu) +#define OL_TXRX_PEER_STATS_MUTEX_INIT(pdev) \ + cdf_spinlock_init(&pdev->peer_stat_mutex) +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev) \ + cdf_spinlock_destroy(&pdev->peer_stat_mutex) +#else +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_INIT(peer) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(peer) /* no-op */ +#endif + +#ifndef DEBUG_HTT_CREDIT +#define DEBUG_HTT_CREDIT 0 +#endif + +#if defined(FEATURE_TSO_DEBUG) +#define TXRX_STATS_TSO_RESET_MSDU(pdev) \ + do { \ + int idx = TXRX_STATS_TSO_MSDU_IDX(pdev);\ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg = 0; \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].tso_seg_idx = 0; \ + } while (0) + +#define TXRX_STATS_TSO_MSDU_IDX(pdev) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx + +#define TXRX_STATS_TSO_MSDU(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx] + +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg + +#define TXRX_STATS_TSO_CURR_MSDU(pdev) \ + TXRX_STATS_TSO_MSDU(pdev, TXRX_STATS_TSO_MSDU_IDX(pdev)) + +#define TXRX_STATS_TSO_INC_MSDU_IDX(pdev) \ + do { \ + TXRX_STATS_TSO_MSDU_IDX(pdev)++; \ + TXRX_STATS_TSO_MSDU_IDX(pdev) &= NUM_MAX_TSO_MSDUS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_SEG_IDX(pdev) \ + TXRX_STATS_TSO_CURR_MSDU(pdev).tso_seg_idx + +#define TXRX_STATS_TSO_INC_SEG(pdev) \ + TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg++ + +#define TXRX_STATS_TSO_RST_SEG(pdev) \ + TXRX_STATS_TSO_CURR_MSDU(pdev).num_seg = 0 + +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev) \ + TXRX_STATS_TSO_CURR_MSDU(pdev).tso_seg_idx = 0 + +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) \ + TXRX_STATS_TSO_MSDU(pdev, msdu_idx).tso_segs[seg_idx] + +#define TXRX_STATS_TSO_CURR_SEG(pdev) \ + TXRX_STATS_TSO_SEG(pdev, TXRX_STATS_TSO_MSDU_IDX(pdev), \ + TXRX_STATS_TSO_SEG_IDX(pdev)) \ + +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev) \ + do { \ + TXRX_STATS_TSO_SEG_IDX(pdev)++; \ + TXRX_STATS_TSO_SEG_IDX(pdev) &= NUM_MAX_TSO_SEGS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, tso_seg) \ + (TXRX_STATS_TSO_CURR_SEG(pdev) = tso_seg) + +#else +#define TXRX_STATS_TSO_RESET_MSDU(pdev) /* no-op */ +#define TXRX_STATS_TSO_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_MSDU(pdev) /* no-op */ +#define TXRX_STATS_TSO_INC_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_SEG_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_SEG(pdev) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, tso_seg) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG(pdev) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG(pdev) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev) /* no-op */ + +#endif /* FEATURE_TSO_DEBUG */ + +#endif /* _OL_TXRX_INTERNAL__H_ */ diff --git a/core/dp/txrx/ol_txrx_peer_find.c b/core/dp/txrx/ol_txrx_peer_find.c new file mode 100644 index 0000000000..1c743f7d5c --- /dev/null +++ b/core/dp/txrx/ol_txrx_peer_find.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* cdf_mem_malloc, etc. */ +#include /* cdf_device_t, cdf_print */ +/* header files for utilities */ +#include /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_max_peer_id */ + +/* header files for our internal definitions */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_DEBUG_LEVEL */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* ol_txrx_peer_unref_delete */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include + +/*=== misc. / utility function definitions ==================================*/ + +static int ol_txrx_log2_ceil(unsigned value) +{ + /* need to switch to unsigned math so that negative values + * will right-shift towards 0 instead of -1 + */ + unsigned tmp = value; + int log2 = -1; + + if (value == 0) { + TXRX_ASSERT2(0); + return 0; + } + + while (tmp) { + log2++; + tmp >>= 1; + } + if (1U << log2 != value) + log2++; + + return log2; +} + +static int +ol_txrx_peer_find_add_id_to_obj(struct ol_txrx_peer_t *peer, uint16_t peer_id) +{ + int i; + + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] == HTT_INVALID_PEER) { + peer->peer_ids[i] = peer_id; + return 0; /* success */ + } + } + return 1; /* failure */ +} + +/*=== function definitions for peer MAC addr --> peer object hash table =====*/ + +/* + * TXRX_PEER_HASH_LOAD_FACTOR: + * Multiply by 2 and divide by 2^0 (shift by 0), then round up to a + * power of two. + * This provides at least twice as many bins in the peer hash table + * as there will be entries. + * Having substantially more bins than spaces minimizes the probability of + * having to compare MAC addresses. + * Because the MAC address comparison is fairly efficient, it is okay if the + * hash table is sparsely loaded, but it's generally better to use extra mem + * to keep the table sparse, to keep the lookups as fast as possible. + * An optimization would be to apply a more conservative loading factor for + * high latency, where the lookup happens during the tx classification of + * every tx frame, than for low-latency, where the lookup only happens + * during association, when the PEER_MAP message is received. + */ +#define TXRX_PEER_HASH_LOAD_MULT 2 +#define TXRX_PEER_HASH_LOAD_SHIFT 0 + +static int ol_txrx_peer_find_hash_attach(struct ol_txrx_pdev_t *pdev) +{ + int i, hash_elems, log2; + + /* allocate the peer MAC address -> peer object hash table */ + hash_elems = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + hash_elems *= TXRX_PEER_HASH_LOAD_MULT; + hash_elems >>= TXRX_PEER_HASH_LOAD_SHIFT; + log2 = ol_txrx_log2_ceil(hash_elems); + hash_elems = 1 << log2; + + pdev->peer_hash.mask = hash_elems - 1; + pdev->peer_hash.idx_bits = log2; + /* allocate an array of TAILQ peer object lists */ + pdev->peer_hash.bins = + cdf_mem_malloc(hash_elems * + sizeof(TAILQ_HEAD(anonymous_tail_q, + ol_txrx_peer_t))); + if (!pdev->peer_hash.bins) + return 1; /* failure */ + + for (i = 0; i < hash_elems; i++) + TAILQ_INIT(&pdev->peer_hash.bins[i]); + + return 0; /* success */ +} + +static void ol_txrx_peer_find_hash_detach(struct ol_txrx_pdev_t *pdev) +{ + cdf_mem_free(pdev->peer_hash.bins); +} + +static inline unsigned +ol_txrx_peer_find_hash_index(struct ol_txrx_pdev_t *pdev, + union ol_txrx_align_mac_addr_t *mac_addr) +{ + unsigned index; + + index = + mac_addr->align2.bytes_ab ^ + mac_addr->align2.bytes_cd ^ mac_addr->align2.bytes_ef; + index ^= index >> pdev->peer_hash.idx_bits; + index &= pdev->peer_hash.mask; + return index; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* + * It is important to add the new peer at the tail of the peer list + * with the bin index. Together with having the hash_find function + * search from head to tail, this ensures that if two entries with + * the same MAC address are stored, the one added first will be + * found first. + */ + TAILQ_INSERT_TAIL(&pdev->peer_hash.bins[index], peer, hash_list_elem); + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); +} + +struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + cdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid) + && peer->vdev == vdev) { + /* found it - increment the ref count before releasing + the lock */ + cdf_atomic_inc(&peer->ref_cnt); + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + cdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + cdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid)) { + /* found it - increment the ref count before + releasing the lock */ + cdf_atomic_inc(&peer->ref_cnt); + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + cdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + /* + * DO NOT take the peer_ref_mutex lock here - it needs to be taken + * by the caller. + * The caller needs to hold the lock from the time the peer object's + * reference count is decremented and tested up through the time the + * reference to the peer object is removed from the hash table, by + * this function. + * Holding the lock only while removing the peer object reference + * from the hash table keeps the hash table consistent, but does not + * protect against a new HL tx context starting to use the peer object + * if it looks up the peer object from its MAC address just after the + * peer ref count is decremented to zero, but just before the peer + * object reference is removed from the hash table. + */ + /* cdf_spin_lock_bh(&pdev->peer_ref_mutex); */ + TAILQ_REMOVE(&pdev->peer_hash.bins[index], peer, hash_list_elem); + /* cdf_spin_unlock_bh(&pdev->peer_ref_mutex); */ +} + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev) +{ + unsigned i; + /* + * Not really necessary to take peer_ref_mutex lock - by this point, + * it's known that the pdev is no longer in use. + */ + + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer, *peer_next; + + /* + * TAILQ_FOREACH_SAFE must be used here to avoid any + * memory access violation after peer is freed + */ + TAILQ_FOREACH_SAFE(peer, &pdev->peer_hash.bins[i], + hash_list_elem, peer_next) { + /* + * Don't remove the peer from the hash table - + * that would modify the list we are currently + * traversing, + * and it's not necessary anyway. + */ + /* + * Artificially adjust the peer's ref count to + * 1, so it will get deleted by + * ol_txrx_peer_unref_delete. + */ + cdf_atomic_init(&peer->ref_cnt); /* set to 0 */ + cdf_atomic_inc(&peer->ref_cnt); /* incr to 1 */ + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Delete Peer %p\n", __func__, + peer); + ol_txrx_peer_unref_delete(peer); + } + } + } +} + +/*=== function definitions for peer id --> peer object map ==================*/ + +static int ol_txrx_peer_find_map_attach(struct ol_txrx_pdev_t *pdev) +{ + int max_peers, peer_map_size; + + /* allocate the peer ID -> peer object map */ + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + peer_map_size = max_peers * sizeof(pdev->peer_id_to_obj_map[0]); + pdev->peer_id_to_obj_map = cdf_mem_malloc(peer_map_size); + if (!pdev->peer_id_to_obj_map) + return 1; /* failure */ + + /* + * The peer_id_to_obj_map doesn't really need to be initialized, + * since elements are only used after they have been individually + * initialized. + * However, it is convenient for debugging to have all elements + * that are not in use set to 0. + */ + cdf_mem_set(pdev->peer_id_to_obj_map, peer_map_size, 0); + + return 0; /* success */ +} + +static void ol_txrx_peer_find_map_detach(struct ol_txrx_pdev_t *pdev) +{ + cdf_mem_free(pdev->peer_id_to_obj_map); +} + +static inline void +ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + + /* check if there's already a peer object with this MAC address */ + peer = + ol_txrx_peer_find_hash_find(pdev, peer_mac_addr, + 1 /* is aligned */, 0); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "%s: peer %p ID %d\n", __func__, + peer, peer_id); + if (peer) { + /* peer's ref count was already incremented by + peer_find_hash_find */ + pdev->peer_id_to_obj_map[peer_id] = peer; + /* + * remove the reference added in ol_txrx_peer_find_hash_find. + * the reference for the first peer id is already added in + * ol_txrx_peer_attach. + * Riva/Pronto has one peer id for each peer. + * Peregrine/Rome has two peer id for each peer. + */ + if (peer->peer_ids[0] == HTT_INVALID_PEER) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Delete Peer %p\n", + __func__, peer); + ol_txrx_peer_unref_delete(peer); + } + if (ol_txrx_peer_find_add_id_to_obj(peer, peer_id)) { + /* TBDXXX: assert for now */ + cdf_assert(0); + } + return; + } + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then we will fail to find a peer + * with a matching MAC address. + */ + /* TXRX_ASSERT2(0); */ +} + +/*=== allocation / deallocation function definitions ========================*/ + +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev) +{ + if (ol_txrx_peer_find_map_attach(pdev)) + return 1; + if (ol_txrx_peer_find_hash_attach(pdev)) { + ol_txrx_peer_find_map_detach(pdev); + return 1; + } + return 0; /* success */ +} + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_peer_find_map_detach(pdev); + ol_txrx_peer_find_hash_detach(pdev); +} + +/*=== function definitions for message handling =============================*/ + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ +} + +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + peer = (peer_id == HTT_INVALID_PEER) ? NULL : + pdev->peer_id_to_obj_map[peer_id]; + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: peer %p with ID %d to be unmapped.\n", __func__, peer, + peer_id); + pdev->peer_id_to_obj_map[peer_id] = NULL; + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then the peer pointer stored + * in peer_id_to_obj_map will be NULL. + */ + if (!peer) + return; + /* + * Remove a reference to the peer. + * If there are no more references, delete the peer object. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Remove the ID %d reference to peer %p\n", + __func__, peer_id, peer); + ol_txrx_peer_unref_delete(peer); +} + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_peer_t *peer; + + cdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + /* + * Check the TXRX Peer is itself valid And also + * if HTT Peer ID has been setup for this peer + */ + if (vdev->last_real_peer + && vdev->last_real_peer->peer_ids[0] != HTT_INVALID_PEER_ID) { + cdf_atomic_inc(&vdev->last_real_peer->ref_cnt); + peer = vdev->last_real_peer; + } else { + peer = NULL; + } + cdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + return peer; +} + +/*=== function definitions for debug ========================================*/ + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent) +{ + int i, max_peers; + + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*speer map:\n", indent, " "); + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + for (i = 0; i < max_peers; i++) { + if (pdev->peer_id_to_obj_map[i]) { + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*sid %d -> %p\n", + indent + 4, " ", i, + pdev->peer_id_to_obj_map[i]); + } + } + CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, + "%*speer hash table:\n", indent, " "); + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer; + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[i], + hash_list_elem) { + CDF_TRACE(CDF_MODULE_ID_TXRX, + CDF_TRACE_LEVEL_INFO_LOW, + "%*shash idx %d -> %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + indent + 4, " ", i, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + } + } + } +} +#endif /* if TXRX_DEBUG_LEVEL */ diff --git a/core/dp/txrx/ol_txrx_peer_find.h b/core/dp/txrx/ol_txrx_peer_find.h new file mode 100644 index 0000000000..25886cae1c --- /dev/null +++ b/core/dp/txrx/ol_txrx_peer_find.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_peer_find.h + * @brief Define the API for the rx peer lookup datapath module. + */ +#ifndef _OL_TXRX_PEER_FIND__H_ +#define _OL_TXRX_PEER_FIND__H_ + +#include /* HTT_INVALID_PEER */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_ASSERT */ + +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev); + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev); + +static inline +int +ol_txrx_peer_find_mac_addr_cmp(union ol_txrx_align_mac_addr_t *mac_addr1, + union ol_txrx_align_mac_addr_t *mac_addr2) +{ + return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd) + /* + * Intentionally use & rather than &&. + * because the operands are binary rather than generic bool, + * the functionality is equivalent. + * Using && has the advantage of short-circuited evaluation, + * but using & has the advantage of no conditional branching, + * which is a more significant benefit. + */ + & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); +} + +static inline +struct ol_txrx_peer_t *ol_txrx_peer_find_by_id(struct ol_txrx_pdev_t *pdev, + uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + peer = (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) ? NULL : + pdev->peer_id_to_obj_map[peer_id]; + /* + * Currently, peer IDs are assigned to vdevs as well as peers. + * If the peer ID is for a vdev, the peer_id_to_obj_map entry + * will hold NULL rather than a valid peer pointer. + */ + /* TXRX_ASSERT2(peer != NULL); */ + /* + * Only return the peer object if it is valid, + * i.e. it has not already been detached. + * If it has already been detached, then returning the + * peer object could result in unpausing the peer's tx queues + * in HL systems, which is an invalid operation following peer_detach. + */ + if (peer && peer->valid) + return peer; + + return NULL; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid); + +struct +ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid); + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev); + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev); + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent); +#else +#define ol_txrx_peer_find_display(pdev, indent) +#endif /* TXRX_DEBUG_LEVEL */ + +#endif /* _OL_TXRX_PEER_FIND__H_ */ diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h new file mode 100644 index 0000000000..50a4bd9eeb --- /dev/null +++ b/core/dp/txrx/ol_txrx_types.h @@ -0,0 +1,1018 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_types.h + * @brief Define the major data types used internally by the host datapath SW. + */ +#ifndef _OL_TXRX_TYPES__H_ +#define _OL_TXRX_TYPES__H_ + +#include /* cdf_nbuf_t */ +#include /* TAILQ */ +#include /* A_UINT8 */ +#include /* htt_sec_type, htt_pkt_type, etc. */ +#include /* cdf_atomic_t */ +#include /* wdi_event_subscribe */ +#include /* cdf_softirq_timer_t */ +#include /* cdf_spinlock */ +#include /* ol_pktlog_dev_handle */ +#include +#include +#include "ol_txrx_htt_api.h" +#include "ol_htt_tx_api.h" +#include "ol_htt_rx_api.h" +#include +#include + + +/* + * The target may allocate multiple IDs for a peer. + * In particular, the target may allocate one ID to represent the + * multicast key the peer uses, and another ID to represent the + * unicast key the peer uses. + */ +#define MAX_NUM_PEER_ID_PER_PEER 8 + +#define OL_TXRX_MAC_ADDR_LEN 6 + +/* OL_TXRX_NUM_EXT_TIDS - + * 16 "real" TIDs + 3 pseudo-TIDs for mgmt, mcast/bcast & non-QoS data + */ +#define OL_TXRX_NUM_EXT_TIDS 19 + +#define OL_TX_NUM_QOS_TIDS 16 /* 16 regular TIDs */ +#define OL_TX_NON_QOS_TID 16 +#define OL_TX_MGMT_TID 17 +#define OL_TX_NUM_TIDS 18 +#define OL_RX_MCAST_TID 18 /* Mcast TID only between f/w & host */ + +#define OL_TX_VDEV_MCAST_BCAST 0 // HTT_TX_EXT_TID_MCAST_BCAST +#define OL_TX_VDEV_DEFAULT_MGMT 1 // HTT_TX_EXT_TID_DEFALT_MGMT +#define OL_TX_VDEV_NUM_QUEUES 2 + +#define OL_TXRX_MGMT_TYPE_BASE htt_pkt_num_types +#define OL_TXRX_MGMT_NUM_TYPES 8 + +#define OL_TX_MUTEX_TYPE cdf_spinlock_t +#define OL_RX_MUTEX_TYPE cdf_spinlock_t + +/* TXRX Histogram defines */ +#define TXRX_DATA_HISTROGRAM_GRANULARITY 1000 +#define TXRX_DATA_HISTROGRAM_NUM_INTERVALS 100 + +struct ol_txrx_pdev_t; +struct ol_txrx_vdev_t; +struct ol_txrx_peer_t; + +struct ol_pdev_t; +typedef struct ol_pdev_t *ol_pdev_handle; + +struct ol_vdev_t; +typedef struct ol_vdev_t *ol_vdev_handle; + +struct ol_peer_t; +typedef struct ol_peer_t *ol_peer_handle; + +/* rx filter related */ +#define MAX_PRIVACY_FILTERS 4 /* max privacy filters */ + +enum privacy_filter { + PRIVACY_FILTER_ALWAYS, + PRIVACY_FILTER_KEY_UNAVAILABLE, +}; + +enum privacy_filter_packet_type { + PRIVACY_FILTER_PACKET_UNICAST, + PRIVACY_FILTER_PACKET_MULTICAST, + PRIVACY_FILTER_PACKET_BOTH +}; + +struct privacy_exemption { + /* ethertype - + * type of ethernet frames this filter applies to, in host byte order + */ + uint16_t ether_type; + enum privacy_filter filter_type; + enum privacy_filter_packet_type packet_type; +}; + +enum ol_tx_frm_type { + ol_tx_frm_std = 0, /* regular frame - no added header fragments */ + ol_tx_frm_tso, /* TSO segment, with a modified IP header added */ + ol_tx_frm_audio, /* audio frames, with a custom LLC/SNAP hdr added */ + ol_tx_frm_no_free, /* frame requires special tx completion callback */ +}; + +struct ol_tx_desc_t { + cdf_nbuf_t netbuf; + void *htt_tx_desc; +#ifdef WLAN_FEATURE_FASTPATH + uint16_t id; +#endif /* WLAN_FEATURE_FASTPATH */ + uint32_t htt_tx_desc_paddr; +#if defined(HELIUMPLUS_PADDR64) + void *htt_frag_desc; /* struct msdu_ext_desc_t * */ + uint32_t htt_frag_desc_paddr; +#endif /* defined(HELIUMPLUS_PADDR64) */ + uint32_t index; + cdf_atomic_t ref_cnt; + enum htt_tx_status status; + +#ifdef QCA_COMPUTE_TX_DELAY + uint32_t entry_timestamp_ticks; +#endif + /* + * Allow tx descriptors to be stored in (doubly-linked) lists. + * This is mainly used for HL tx queuing and scheduling, but is + * also used by LL+HL for batch processing of tx frames. + */ + TAILQ_ENTRY(ol_tx_desc_t) tx_desc_list_elem; + + /* + * Remember whether the tx frame is a regular packet, or whether + * the driver added extra header fragments (e.g. a modified IP header + * for TSO fragments, or an added LLC/SNAP header for audio interworking + * data) that need to be handled in a special manner. + * This field is filled in with the ol_tx_frm_type enum. + */ + uint8_t pkt_type; +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* used by tx encap, to restore the os buf start offset + after tx complete */ + uint8_t orig_l2_hdr_bytes; +#endif +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + struct ol_txrx_vdev_t *vdev; +#endif +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif + void *tso_desc; +}; + +typedef TAILQ_HEAD(some_struct_name, ol_tx_desc_t) ol_tx_desc_list; + +union ol_tx_desc_list_elem_t { + union ol_tx_desc_list_elem_t *next; + struct ol_tx_desc_t tx_desc; +}; + +union ol_txrx_align_mac_addr_t { + uint8_t raw[OL_TXRX_MAC_ADDR_LEN]; + struct { + uint16_t bytes_ab; + uint16_t bytes_cd; + uint16_t bytes_ef; + } align2; + struct { + uint32_t bytes_abcd; + uint16_t bytes_ef; + } align4; +}; + +struct ol_rx_reorder_timeout_list_elem_t { + TAILQ_ENTRY(ol_rx_reorder_timeout_list_elem_t) + reorder_timeout_list_elem; + uint32_t timestamp_ms; + struct ol_txrx_peer_t *peer; + uint8_t tid; + uint8_t active; +}; + +#define TXRX_TID_TO_WMM_AC(_tid) ( \ + (((_tid) >> 1) == 3) ? TXRX_WMM_AC_VO : \ + (((_tid) >> 1) == 2) ? TXRX_WMM_AC_VI : \ + (((_tid) ^ ((_tid) >> 1)) & 0x1) ? TXRX_WMM_AC_BK : \ + TXRX_WMM_AC_BE) + +struct ol_tx_reorder_cat_timeout_t { + TAILQ_HEAD(, ol_rx_reorder_timeout_list_elem_t) virtual_timer_list; + cdf_softirq_timer_t timer; + uint32_t duration_ms; + struct ol_txrx_pdev_t *pdev; +}; + +enum ol_tx_queue_status { + ol_tx_queue_empty = 0, + ol_tx_queue_active, + ol_tx_queue_paused, +}; + +struct ol_txrx_msdu_info_t { + struct htt_msdu_info_t htt; + struct ol_txrx_peer_t *peer; + struct cdf_tso_info_t tso_info; +}; + +enum { + ol_tx_aggr_untried = 0, + ol_tx_aggr_enabled, + ol_tx_aggr_disabled, + ol_tx_aggr_retry, + ol_tx_aggr_in_progress, +}; + +struct ol_tx_frms_queue_t { + /* list_elem - + * Allow individual tx frame queues to be linked together into + * scheduler queues of tx frame queues + */ + TAILQ_ENTRY(ol_tx_frms_queue_t) list_elem; + uint8_t aggr_state; + struct { + uint8_t total; + /* pause requested by ctrl SW rather than txrx SW */ + uint8_t by_ctrl; + } paused_count; + uint8_t ext_tid; + uint16_t frms; + uint32_t bytes; + ol_tx_desc_list head; + enum ol_tx_queue_status flag; +}; + +enum { + ol_tx_log_entry_type_invalid, + ol_tx_log_entry_type_queue_state, + ol_tx_log_entry_type_enqueue, + ol_tx_log_entry_type_dequeue, + ol_tx_log_entry_type_drop, + ol_tx_log_entry_type_queue_free, + + ol_tx_log_entry_type_wrap, +}; + +struct ol_tx_log_queue_state_var_sz_t { + uint32_t active_bitmap; + uint16_t credit; + uint8_t num_cats_active; + uint8_t data[1]; +}; + +struct ol_tx_log_queue_add_t { + uint8_t num_frms; + uint8_t tid; + uint16_t peer_id; + uint16_t num_bytes; +}; + +struct ol_mac_addr { + uint8_t mac_addr[OL_TXRX_MAC_ADDR_LEN]; +}; + +#ifndef OL_TXRX_NUM_LOCAL_PEER_IDS +#define OL_TXRX_NUM_LOCAL_PEER_IDS 33 /* default */ +#endif + +#ifndef ol_txrx_local_peer_id_t +#define ol_txrx_local_peer_id_t uint8_t /* default */ +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +/* + * Delay histogram bins: 16 bins of 10 ms each to count delays + * from 0-160 ms, plus one overflow bin for delays > 160 ms. + */ +#define QCA_TX_DELAY_HIST_INTERNAL_BINS 17 +#define QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS 10 + +struct ol_tx_delay_data { + struct { + uint64_t transmit_sum_ticks; + uint64_t queue_sum_ticks; + uint32_t transmit_num; + uint32_t queue_num; + } avgs; + uint16_t hist_bins_queue[QCA_TX_DELAY_HIST_INTERNAL_BINS]; +}; + +#endif /* QCA_COMPUTE_TX_DELAY */ + +/* Thermal Mitigation */ + +enum throttle_level { + THROTTLE_LEVEL_0, + THROTTLE_LEVEL_1, + THROTTLE_LEVEL_2, + THROTTLE_LEVEL_3, + /* Invalid */ + THROTTLE_LEVEL_MAX, +}; + +enum throttle_phase { + THROTTLE_PHASE_OFF, + THROTTLE_PHASE_ON, + /* Invalid */ + THROTTLE_PHASE_MAX, +}; + +#define THROTTLE_TX_THRESHOLD (100) + +typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *osif_ctxt); + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +/** + * enum flow_pool_status - flow pool status + * @FLOW_POOL_ACTIVE_UNPAUSED : pool is active (can take/put descriptors) + * and network queues are unpaused + * @FLOW_POOL_ACTIVE_PAUSED: pool is active (can take/put descriptors) + * and network queues are paused + * @FLOW_POOL_INVALID: pool is invalid (put descriptor) + * @FLOW_POOL_INACTIVE: pool is inactive (pool is free) + */ +enum flow_pool_status { + FLOW_POOL_ACTIVE_UNPAUSED = 0, + FLOW_POOL_ACTIVE_PAUSED = 1, + FLOW_POOL_INVALID = 2, + FLOW_POOL_INACTIVE = 3, +}; + +/** + * struct ol_txrx_pool_stats - flow pool related statistics + * @pool_map_count: flow pool map received + * @pool_unmap_count: flow pool unmap received + * @pkt_drop_no_pool: packets dropped due to unavailablity of pool + * @pkt_drop_no_desc: packets dropped due to unavailablity of descriptors + */ +struct ol_txrx_pool_stats { + uint16_t pool_map_count; + uint16_t pool_unmap_count; + uint16_t pkt_drop_no_pool; + uint16_t pkt_drop_no_desc; +}; + +/** + * struct ol_tx_flow_pool_t - flow_pool info + * @flow_pool_list_elem: flow_pool_list element + * @flow_pool_lock: flow_pool lock + * @flow_pool_id: flow_pool id + * @flow_pool_size: flow_pool size + * @avail_desc: available descriptors + * @deficient_desc: deficient descriptors + * @status: flow pool status + * @flow_type: flow pool type + * @member_flow_id: member flow id + * @stop_th: stop threshold + * @start_th: start threshold + * @freelist: tx descriptor freelist + */ +struct ol_tx_flow_pool_t { + TAILQ_ENTRY(ol_tx_flow_pool_t) flow_pool_list_elem; + cdf_spinlock_t flow_pool_lock; + uint8_t flow_pool_id; + uint16_t flow_pool_size; + uint16_t avail_desc; + uint16_t deficient_desc; + enum flow_pool_status status; + enum htt_flow_type flow_type; + uint8_t member_flow_id; + uint16_t stop_th; + uint16_t start_th; + union ol_tx_desc_list_elem_t *freelist; +}; + +#endif + +/* + * As depicted in the diagram below, the pdev contains an array of + * NUM_EXT_TID ol_tx_active_queues_in_tid_t elements. + * Each element identifies all the tx queues that are active for + * the TID, from the different peers. + * + * Each peer contains an array of NUM_EXT_TID ol_tx_frms_queue_t elements. + * Each element identifies the tx frames for the TID that need to be sent + * to the peer. + * + * + * pdev: ol_tx_active_queues_in_tid_t active_in_tids[NUM_EXT_TIDS] + * TID + * 0 1 2 17 + * +============+============+============+== ==+============+ + * | active (y) | active (n) | active (n) | | active (y) | + * |------------+------------+------------+-- --+------------| + * | queues | queues | queues | | queues | + * +============+============+============+== ==+============+ + * | | + * .--+-----------------------------------------------' + * | | + * | | peer X: peer Y: + * | | ol_tx_frms_queue_t ol_tx_frms_queue_t + * | | tx_queues[NUM_EXT_TIDS] tx_queues[NUM_EXT_TIDS] + * | | TID +======+ TID +======+ + * | `---->| next |-------------------------->| next |--X + * | 0 | prev | .------. .------. 0 | prev | .------. + * | | txq |-->|txdesc|-->|txdesc| | txq |-->|txdesc| + * | +======+ `------' `------' +======+ `------' + * | | next | | | 1 | next | | + * | 1 | prev | v v | prev | v + * | | txq | .------. .------. | txq | .------. + * | +======+ |netbuf| |netbuf| +======+ |netbuf| + * | | next | `------' `------' | next | `------' + * | 2 | prev | 2 | prev | + * | | txq | | txq | + * | +======+ +======+ + * | | | | | + * | + * | + * | | | | | + * | +======+ +======+ + * `------->| next |--X | next | + * 17 | prev | .------. 17 | prev | + * | txq |-->|txdesc| | txq | + * +======+ `------' +======+ + * | + * v + * .------. + * |netbuf| + * `------' + */ +struct ol_txrx_pdev_t { + /* ctrl_pdev - handle for querying config info */ + ol_pdev_handle ctrl_pdev; + + /* osdev - handle for mem alloc / free, map / unmap */ + cdf_device_t osdev; + + htt_pdev_handle htt_pdev; + +#ifdef WLAN_FEATURE_FASTPATH + struct CE_handle *ce_tx_hdl; /* Handle to Tx packet posting CE */ + struct CE_handle *ce_htt_msg_hdl; /* Handle to TxRx completion CE */ +#endif /* WLAN_FEATURE_FASTPATH */ + + struct { + int is_high_latency; + int host_addba; + int ll_pause_txq_limit; + int default_tx_comp_req; + } cfg; + + /* WDI subscriber's event list */ + wdi_event_subscribe **wdi_event_list; + +#ifndef REMOVE_PKT_LOG + /* Pktlog pdev */ + struct ol_pktlog_dev_t *pl_dev; +#endif /* #ifndef REMOVE_PKT_LOG */ + + enum ol_sec_type sec_types[htt_num_sec_types]; + /* standard frame type */ + enum wlan_frm_fmt frame_format; + enum htt_pkt_type htt_pkt_type; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* txrx encap/decap */ + uint8_t sw_tx_encap; + uint8_t sw_rx_decap; + uint8_t target_tx_tran_caps; + uint8_t target_rx_tran_caps; + /* llc process */ + uint8_t sw_tx_llc_proc_enable; + uint8_t sw_rx_llc_proc_enable; + /* A-MSDU */ + uint8_t sw_subfrm_hdr_recovery_enable; + /* Protected Frame bit handling */ + uint8_t sw_pf_proc_enable; +#endif + /* + * target tx credit - + * not needed for LL, but used for HL download scheduler to keep + * track of roughly how much space is available in the target for + * tx frames + */ + cdf_atomic_t target_tx_credit; + cdf_atomic_t orig_target_tx_credit; + + /* Peer mac address to staid mapping */ + struct ol_mac_addr mac_to_staid[WLAN_MAX_STA_COUNT + 3]; + + /* ol_txrx_vdev list */ + TAILQ_HEAD(, ol_txrx_vdev_t) vdev_list; + + /* peer ID to peer object map (array of pointers to peer objects) */ + struct ol_txrx_peer_t **peer_id_to_obj_map; + + struct { + unsigned mask; + unsigned idx_bits; + TAILQ_HEAD(, ol_txrx_peer_t) * bins; + } peer_hash; + + /* rx specific processing */ + struct { + struct { + TAILQ_HEAD(, ol_rx_reorder_t) waitlist; + uint32_t timeout_ms; + } defrag; + struct { + int defrag_timeout_check; + int dup_check; + } flags; + + struct { + struct ol_tx_reorder_cat_timeout_t + access_cats[TXRX_NUM_WMM_AC]; + } reorder_timeout; + cdf_spinlock_t mutex; + } rx; + + /* rx proc function */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list); + + /* tx data delivery notification callback function */ + struct { + ol_txrx_data_tx_cb func; + void *ctxt; + } tx_data_callback; + + /* tx management delivery notification callback functions */ + struct { + struct { + ol_txrx_mgmt_tx_cb download_cb; + ol_txrx_mgmt_tx_cb ota_ack_cb; + void *ctxt; + } callbacks[OL_TXRX_MGMT_NUM_TYPES]; + } tx_mgmt; + + struct { + uint16_t pool_size; + uint16_t num_free; + union ol_tx_desc_list_elem_t *array; + union ol_tx_desc_list_elem_t *freelist; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint8_t num_invalid_bin; + cdf_spinlock_t flow_pool_list_lock; + TAILQ_HEAD(flow_pool_list_t, ol_tx_flow_pool_t) flow_pool_list; +#endif + } tx_desc; + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) + struct ol_txrx_pool_stats pool_stats; + uint32_t num_msdu_desc; +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL + struct ol_tx_flow_pool_t *mgmt_pool; +#endif +#endif + + struct { + int (*cmp)(union htt_rx_pn_t *new, + union htt_rx_pn_t *old, + int is_unicast, int opmode); + int len; + } rx_pn[htt_num_sec_types]; + + /* tx mutex */ + OL_TX_MUTEX_TYPE tx_mutex; + + /* + * peer ref mutex: + * 1. Protect peer object lookups until the returned peer object's + * reference count is incremented. + * 2. Provide mutex when accessing peer object lookup structures. + */ + OL_RX_MUTEX_TYPE peer_ref_mutex; + + /* + * last_real_peer_mutex: + * Protect lookups of any vdev's last_real_peer pointer until the + * reference count for the pointed-to peer object is incremented. + * This mutex could be in the vdev struct, but it's slightly simpler + * to have a single lock in the pdev struct. Since the lock is only + * held for an extremely short time, and since it's very unlikely for + * two vdev's to concurrently access the lock, there's no real + * benefit to having a per-vdev lock. + */ + OL_RX_MUTEX_TYPE last_real_peer_mutex; + + struct { + struct { + struct { + struct { + uint64_t ppdus; + uint64_t mpdus; + } normal; + struct { + /* + * mpdu_bad is general - + * replace it with the specific counters + * below + */ + uint64_t mpdu_bad; + /* uint64_t mpdu_fcs; */ + /* uint64_t mpdu_duplicate; */ + /* uint64_t mpdu_pn_replay; */ + /* uint64_t mpdu_bad_sender; */ + /* ^ comment: peer not found */ + /* uint64_t mpdu_flushed; */ + /* uint64_t msdu_defrag_mic_err; */ + uint64_t msdu_mc_dup_drop; + } err; + } rx; + } priv; + struct ol_txrx_stats pub; + } stats; + +#if defined(ENABLE_RX_REORDER_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_REORDER_TRACE_SIZE_LOG2 8 /* 256 entries */ + struct { + uint16_t reorder_idx; + uint16_t seq_num; + uint8_t num_mpdus; + uint8_t tid; + } *data; + } rx_reorder_trace; +#endif /* ENABLE_RX_REORDER_TRACE */ + +#if defined(ENABLE_RX_PN_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_PN_TRACE_SIZE_LOG2 5 /* 32 entries */ + struct { + struct ol_txrx_peer_t *peer; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + uint8_t tid; + } *data; + } rx_pn_trace; +#endif /* ENABLE_RX_PN_TRACE */ + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + bool host_80211_enable; +#endif + + /* + * tx_queue only applies for HL, but is defined unconditionally to avoid + * wrapping references to tx_queue in "defined(CONFIG_HL_SUPPORT)" + * conditional compilation. + */ + struct { + cdf_atomic_t rsrc_cnt; + /* threshold_lo - when to start tx desc margin replenishment */ + uint16_t rsrc_threshold_lo; + /* threshold_hi - where to stop during tx desc margin + replenishment */ + uint16_t rsrc_threshold_hi; + } tx_queue; + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + cdf_spinlock_t peer_stat_mutex; +#endif + + int rssi_update_shift; + int rssi_new_weight; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + struct { + ol_txrx_local_peer_id_t pool[OL_TXRX_NUM_LOCAL_PEER_IDS + 1]; + ol_txrx_local_peer_id_t freelist; + cdf_spinlock_t lock; + ol_txrx_peer_handle map[OL_TXRX_NUM_LOCAL_PEER_IDS]; + } local_peer_ids; +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID +#define QCA_TX_DELAY_NUM_CATEGORIES \ + (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) +#else +#define QCA_TX_DELAY_NUM_CATEGORIES 1 +#endif + struct { + cdf_spinlock_t mutex; + struct { + struct ol_tx_delay_data copies[2]; /* ping-pong */ + int in_progress_idx; + uint32_t avg_start_time_ticks; + } cats[QCA_TX_DELAY_NUM_CATEGORIES]; + uint32_t tx_compl_timestamp_ticks; + uint32_t avg_period_ticks; + uint32_t hist_internal_bin_width_mult; + uint32_t hist_internal_bin_width_shift; + } tx_delay; + + uint16_t packet_count[QCA_TX_DELAY_NUM_CATEGORIES]; + uint16_t packet_loss_count[QCA_TX_DELAY_NUM_CATEGORIES]; + +#endif /* QCA_COMPUTE_TX_DELAY */ + + struct { + cdf_spinlock_t mutex; + /* timer used to monitor the throttle "on" phase and + "off" phase */ + cdf_softirq_timer_t phase_timer; + /* timer used to send tx frames */ + cdf_softirq_timer_t tx_timer; + /* This is the time in ms of the throttling window, it will + * include an "on" phase and an "off" phase */ + uint32_t throttle_period_ms; + /* Current throttle level set by the client ex. level 0, + level 1, etc */ + enum throttle_level current_throttle_level; + /* Index that points to the phase within the throttle period */ + enum throttle_phase current_throttle_phase; + /* Maximum number of frames to send to the target at one time */ + uint32_t tx_threshold; + /* stores time in ms of on/off phase for each throttle level */ + int throttle_time_ms[THROTTLE_LEVEL_MAX][THROTTLE_PHASE_MAX]; + /* mark true if traffic is paused due to thermal throttling */ + bool is_paused; + } tx_throttle; + +#ifdef IPA_OFFLOAD + ipa_uc_op_cb_type ipa_uc_op_cb; + void *osif_dev; +#endif /* IPA_UC_OFFLOAD */ + +#if defined(FEATURE_TSO) + struct { + uint16_t pool_size; + uint16_t num_free; + struct cdf_tso_seg_elem_t *array; + struct cdf_tso_seg_elem_t *freelist; + /* tso mutex */ + OL_TX_MUTEX_TYPE tso_mutex; + } tso_seg_pool; +#endif + uint8_t ocb_peer_valid; + struct ol_txrx_peer_t *ocb_peer; + ol_tx_pause_callback_fp pause_cb; + + struct { + void *lro_data; + void (*lro_flush_cb)(void *); + } lro_info; +}; + +struct ol_txrx_ocb_chan_info { + uint32_t chan_freq; + uint16_t disable_rx_stats_hdr:1; +}; + +struct ol_txrx_vdev_t { + struct ol_txrx_pdev_t *pdev; /* pdev - the physical device that is + the parent of this virtual device */ + uint8_t vdev_id; /* ID used to specify a particular vdev + to the target */ + void *osif_dev; + union ol_txrx_align_mac_addr_t mac_addr; /* MAC address */ + /* tx paused - NO LONGER NEEDED? */ + TAILQ_ENTRY(ol_txrx_vdev_t) vdev_list_elem; /* node in the pdev's list + of vdevs */ + TAILQ_HEAD(peer_list_t, ol_txrx_peer_t) peer_list; + struct ol_txrx_peer_t *last_real_peer; /* last real peer created for + this vdev (not "self" + pseudo-peer) */ + ol_txrx_tx_fp tx; /* transmit function used by this vdev */ + + struct { + /* + * If the vdev object couldn't be deleted immediately because + * it still had some peer objects left, remember that a delete + * was requested, so it can be deleted once all its peers have + * been deleted. + */ + int pending; + /* + * Store a function pointer and a context argument to provide a + * notification for when the vdev is deleted. + */ + ol_txrx_vdev_delete_cb callback; + void *context; + } delete; + + /* safe mode control to bypass the encrypt and decipher process */ + uint32_t safemode; + + /* rx filter related */ + uint32_t drop_unenc; + struct privacy_exemption privacy_filters[MAX_PRIVACY_FILTERS]; + uint32_t num_filters; + + enum wlan_op_mode opmode; + +#ifdef QCA_IBSS_SUPPORT + /* ibss mode related */ + int16_t ibss_peer_num; /* the number of active peers */ + int16_t ibss_peer_heart_beat_timer; /* for detecting peer departure */ +#endif + + struct { + struct { + cdf_nbuf_t head; + cdf_nbuf_t tail; + int depth; + } txq; + uint32_t paused_reason; + cdf_spinlock_t mutex; + cdf_softirq_timer_t timer; + int max_q_depth; + bool is_q_paused; + bool is_q_timer_on; + uint32_t q_pause_cnt; + uint32_t q_unpause_cnt; + uint32_t q_overflow_cnt; + } ll_pause; + bool disable_intrabss_fwd; + cdf_atomic_t os_q_paused; + uint16_t tx_fl_lwm; + uint16_t tx_fl_hwm; + cdf_spinlock_t flow_control_lock; + ol_txrx_tx_flow_control_fp osif_flow_control_cb; + void *osif_fc_ctx; + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + cdf_atomic_t tx_desc_count; +#endif + uint16_t wait_on_peer_id; + cdf_event_t wait_delete_comp; +#if defined(FEATURE_TSO) + struct { + int pool_elems; /* total number of elements in the pool */ + int alloc_cnt; /* number of allocated elements */ + uint32_t *freelist; /* free list of cdf_tso_seg_elem_t */ + } tso_pool_t; +#endif + + /* last channel change event recieved */ + struct { + bool is_valid; /* whether the rest of the members are valid */ + uint16_t mhz; + uint16_t band_center_freq1; + uint16_t band_center_freq2; + WLAN_PHY_MODE phy_mode; + } ocb_channel_event; + + /* Information about the schedules in the schedule */ + struct ol_txrx_ocb_chan_info *ocb_channel_info; + uint32_t ocb_channel_count; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif +}; + +struct ol_rx_reorder_array_elem_t { + cdf_nbuf_t head; + cdf_nbuf_t tail; +}; + +struct ol_rx_reorder_t { + uint8_t win_sz; + uint8_t win_sz_mask; + uint8_t num_mpdus; + struct ol_rx_reorder_array_elem_t *array; + /* base - single rx reorder element used for non-aggr cases */ + struct ol_rx_reorder_array_elem_t base; +#if defined(QCA_SUPPORT_OL_RX_REORDER_TIMEOUT) + struct ol_rx_reorder_timeout_list_elem_t timeout; +#endif + /* only used for defrag right now */ + TAILQ_ENTRY(ol_rx_reorder_t) defrag_waitlist_elem; + uint32_t defrag_timeout_ms; + /* get back to parent ol_txrx_peer_t when ol_rx_reorder_t is in a + * waitlist */ + uint16_t tid; +}; + +enum { + txrx_sec_mcast = 0, + txrx_sec_ucast +}; + +typedef A_STATUS (*ol_tx_filter_func)(struct ol_txrx_msdu_info_t * + tx_msdu_info); + +struct ol_txrx_peer_t { + struct ol_txrx_vdev_t *vdev; + + cdf_atomic_t ref_cnt; + cdf_atomic_t delete_in_progress; + cdf_atomic_t flush_in_progress; + + /* The peer state tracking is used for HL systems + * that don't support tx and rx filtering within the target. + * In such systems, the peer's state determines what kind of + * tx and rx filtering, if any, is done. + * This variable doesn't apply to LL systems, or to HL systems for + * which the target handles tx and rx filtering. However, it is + * simplest to declare and update this variable unconditionally, + * for all systems. + */ + enum ol_txrx_peer_state state; + cdf_spinlock_t peer_info_lock; + ol_rx_callback_fp osif_rx; + cdf_spinlock_t bufq_lock; + struct list_head cached_bufq; + + ol_tx_filter_func tx_filter; + + /* peer ID(s) for this peer */ + uint16_t peer_ids[MAX_NUM_PEER_ID_PER_PEER]; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + uint16_t local_id; +#endif + + union ol_txrx_align_mac_addr_t mac_addr; + + /* node in the vdev's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) peer_list_elem; + /* node in the hash table bin's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) hash_list_elem; + + /* + * per TID info - + * stored in separate arrays to avoid alignment padding mem overhead + */ + struct ol_rx_reorder_t tids_rx_reorder[OL_TXRX_NUM_EXT_TIDS]; + union htt_rx_pn_t tids_last_pn[OL_TXRX_NUM_EXT_TIDS]; + uint8_t tids_last_pn_valid[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_next_rel_idx[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_last_seq[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_mcast_last_seq[OL_TXRX_NUM_EXT_TIDS]; + + struct { + enum htt_sec_type sec_type; + uint32_t michael_key[2]; /* relevant for TKIP */ + } security[2]; /* 0 -> multicast, 1 -> unicast */ + + /* + * rx proc function: this either is a copy of pdev's rx_opt_proc for + * regular rx processing, or has been redirected to a /dev/null discard + * function when peer deletion is in progress. + */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, cdf_nbuf_t msdu_list); + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + ol_txrx_peer_stats_t stats; +#endif + int16_t rssi_dbm; + + /* NAWDS Flag and Bss Peer bit */ + uint16_t nawds_enabled:1, bss_peer:1, valid:1; + + /* QoS info */ + uint8_t qos_capable; + /* U-APSD tid mask */ + uint8_t uapsd_mask; + /*flag indicating key installed */ + uint8_t keyinstalled; + + /* Bit to indicate if PN check is done in fw */ + cdf_atomic_t fw_pn_check; + +#ifdef WLAN_FEATURE_11W + /* PN counter for Robust Management Frames */ + uint64_t last_rmf_pn; + uint32_t rmf_pn_replays; + uint8_t last_rmf_pn_valid; +#endif + + /* Properties of the last received PPDU */ + int16_t last_pkt_rssi_cmb; + int16_t last_pkt_rssi[4]; + uint8_t last_pkt_legacy_rate; + uint8_t last_pkt_legacy_rate_sel; + uint32_t last_pkt_timestamp_microsec; + uint8_t last_pkt_timestamp_submicrosec; + uint32_t last_pkt_tsf; + uint8_t last_pkt_tid; + uint16_t last_pkt_center_freq; +}; + +#endif /* _OL_TXRX_TYPES__H_ */ diff --git a/core/dp/txrx/txrx.h b/core/dp/txrx/txrx.h new file mode 100644 index 0000000000..a9808f19be --- /dev/null +++ b/core/dp/txrx/txrx.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef TXRX_H +#define TXRX_H + +#include "cds_api.h" +#include "cdf_nbuf.h" +#include "csr_api.h" +#include "sap_api.h" +#include "cdf_nbuf.h" +#include "ol_txrx_osif_api.h" + +/* wait on peer deletion timeout value in milliseconds */ +#define PEER_DELETION_TIMEOUT 500 + +enum txrx_wmm_ac { + TXRX_WMM_AC_VO, + TXRX_WMM_AC_VI, + TXRX_WMM_AC_BK, + TXRX_WMM_AC_BE, + + TXRX_NUM_WMM_AC +}; + +struct txrx_rx_metainfo { + u8 up; + u16 dest_staid; +}; + +enum bt_frame_type { + /* BT-AMP packet of type data */ + TXRX_BT_AMP_TYPE_DATA = 0x0001, + + /* BT-AMP packet of type activity report */ + TXRX_BT_AMP_TYPE_AR = 0x0002, + + /* BT-AMP packet of type security frame */ + TXRX_BT_AMP_TYPE_SEC = 0x0003, + + /* BT-AMP packet of type Link Supervision request frame */ + TXRX_BT_AMP_TYPE_LS_REQ = 0x0004, + + /* BT-AMP packet of type Link Supervision reply frame */ + TXRX_BT_AMP_TYPE_LS_REP = 0x0005, + + /* Invalid Frame */ + TXRX_BAP_INVALID_FRAME +}; + +enum wlan_ts_direction { + /* uplink */ + WLAN_TX_DIR = 0, + + /* downlink */ + WLAN_RX_DIR = 1, + + /*bidirectional */ + WLAN_BI_DIR = 2, +}; + +enum wlan_sta_state { + /* Transition in this state made upon creation */ + WLAN_STA_INIT = 0, + + /* Transition happens after Assoc success if second level authentication + is needed */ + WLAN_STA_CONNECTED, + + /* Transition happens when second level auth is successful and keys are + properly installed */ + WLAN_STA_AUTHENTICATED, + + /* Transition happens when connectivity is lost */ + WLAN_STA_DISCONNECTED, + + WLAN_STA_MAX_STATE +}; + +struct wlan_txrx_stats { + /* Define various txrx stats here */ +}; + +struct ol_txrx_vdev_t; + +CDF_STATUS wlan_register_mgmt_client(void *pdev_txrx, + CDF_STATUS (*rx_mgmt)(void *g_cdsctx, + void *buf)); + +typedef void (*ol_txrx_vdev_delete_cb)(void *context); + +/** + * @typedef ol_txrx_tx_fp + * @brief top-level transmit function + */ +typedef cdf_nbuf_t +(*ol_txrx_tx_fp)(struct ol_txrx_vdev_t *vdev, cdf_nbuf_t msdu_list); + +typedef void +(*ol_txrx_mgmt_tx_cb)(void *ctxt, cdf_nbuf_t tx_mgmt_frm, int had_error); + +/* If RSSI realm is changed, send notification to Clients, SME, HDD */ +typedef CDF_STATUS (*wlan_txrx_rssi_cross_thresh)(void *adapter, u8 rssi, + void *usr_ctx, + int8_t avg_rssi); + +struct wlan_txrx_ind_req { + u16 msgType; /* message type is same as the request type */ + u16 msgLen; /* length of the entire request */ + u8 sessionId; /* sme Session Id */ + u8 rssiNotification; + u8 avgRssi; + void *tlCallback; + void *pAdapter; + void *pUserCtxt; +}; + + +/* Rx callback registered with txrx */ +typedef int (*wlan_txrx_cb_type)(void *g_cdsctx, cdf_nbuf_t buf, u8 sta_id, + struct txrx_rx_metainfo *rx_meta_info); + +static inline int wlan_txrx_get_rssi(void *g_cdsctx, u8 sta_id, int8_t *rssi) +{ + return 0; +} + +static inline int wlan_txrx_enable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac, u8 tid, u8 up, + u32 srv_int, u32 suspend_int, + enum wlan_ts_direction ts_dir) +{ + return 0; +} + +static inline int wlan_txrx_disable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac) +{ + return 0; +} + +static inline int wlan_change_sta_state(void *g_cdsctx, u8 sta_id, + enum wlan_sta_state state) +{ + return 0; +} + +static inline int wlan_deregister_mgmt_client(void *g_cdsctx) +{ + return 0; +} + +static inline void wlan_assoc_failed(u8 staid) +{ +} + +static inline int wlan_get_ap_stats(void *g_cdsctx, tSap_SoftapStats *buf, + bool reset) +{ + return 0; +} + +static inline int wlan_get_txrx_stats(void *g_cdsctx, + struct wlan_txrx_stats *stats, u8 sta_id) +{ + return 0; +} + +static inline int wlan_txrx_update_rssi_bmps(void *g_cdsctx, u8 sta_id, + int8_t rssi) +{ + return 0; +} + +static inline int wlan_txrx_deregister_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh + cb, int mod_id) +{ + return 0; +} + +static inline int wlan_txrx_register_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh cb, + int mod_id, void *usr_ctx) +{ + return 0; +} + +/* FIXME: The following stubs will be removed eventually */ +static inline int wlan_txrx_mc_process_msg(void *g_cdsctx, cds_msg_t *msg) +{ + return 0; +} + +static inline int wlan_txrx_tx_process_msg(void *g_cdsctx, cds_msg_t *msg) +{ + return 0; +} + +static inline void wlan_txrx_mc_free_msg(void *g_cdsctx, cds_msg_t *msg) +{ +} + +static inline void wlan_txrx_tx_free_msg(void *g_cdsctx, cds_msg_t *msg) +{ +} +#endif diff --git a/core/dp/txrx/wdi_event.h b/core/dp/txrx/wdi_event.h new file mode 100644 index 0000000000..d1019eefb0 --- /dev/null +++ b/core/dp/txrx/wdi_event.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WDI_EVENT_H_ +#define _WDI_EVENT_H_ + +#include "athdefs.h" +#include "cdf_nbuf.h" +#define WDI_EVENT_BASE 0x100 /* Event starting number */ + +enum WDI_EVENT { + WDI_EVENT_TX_STATUS = WDI_EVENT_BASE, + WDI_EVENT_RX_DESC, + WDI_EVENT_RX_DESC_REMOTE, + WDI_EVENT_RATE_FIND, + WDI_EVENT_RATE_UPDATE, + WDI_EVENT_RX_PEER_INVALID, + /* End of new event items */ + + WDI_EVENT_LAST +}; + +struct wdi_event_rx_peer_invalid_msg { + cdf_nbuf_t msdu; + struct ieee80211_frame *wh; + uint8_t vdev_id; +}; + +#define WDI_NUM_EVENTS (WDI_EVENT_LAST - WDI_EVENT_BASE) + +#define WDI_EVENT_NOTIFY_BASE 0x200 +enum WDI_EVENT_NOTIFY { + WDI_EVENT_SUB_DEALLOCATE = WDI_EVENT_NOTIFY_BASE, + /* End of new notification types */ + + WDI_EVENT_NOTIFY_LAST +}; + +/* Opaque event callback */ +typedef void (*wdi_event_cb)(void *pdev, enum WDI_EVENT event, void *data); + +/* Opaque event notify */ +typedef void (*wdi_event_notify)(enum WDI_EVENT_NOTIFY notify, + enum WDI_EVENT event); + +/** + * @typedef wdi_event_subscribe + * @brief Used by consumers to subscribe to WDI event notifications. + * @details + * The event_subscribe struct includes pointers to other event_subscribe + * objects. These pointers are simply to simplify the management of + * lists of event subscribers. These pointers are set during the + * event_sub() function, and shall not be modified except by the + * WDI event management SW, until after the object's event subscription + * is canceled by calling event_unsub(). + */ + +typedef struct wdi_event_subscribe_t { + wdi_event_cb callback; /* subscriber event callback structure head */ + void *context; /* subscriber object that processes the event callback */ + struct { + /* private - the event subscriber SW shall not use this struct */ + struct wdi_event_subscribe_t *next; + struct wdi_event_subscribe_t *prev; + } priv; +} wdi_event_subscribe; + +#endif diff --git a/core/dp/txrx/wdi_event_api.h b/core/dp/txrx/wdi_event_api.h new file mode 100644 index 0000000000..5e2ce5471b --- /dev/null +++ b/core/dp/txrx/wdi_event_api.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WDI_EVENT_API_H_ +#define _WDI_EVENT_API_H_ + +#include "wdi_event.h" + +struct ol_txrx_pdev_t; + +/** + * @brief Subscribe to a specified WDI event. + * @details + * This function adds the provided wdi_event_subscribe object to a list of + * subscribers for the specified WDI event. + * When the event in question happens, each subscriber for the event will + * have their callback function invoked. + * The order in which callback functions from multiple subscribers are + * invoked is unspecified. + * + * @param pdev - the event physical device, that maintains the event lists + * @param event_cb_sub - the callback and context for the event subscriber + * @param event - which event's notifications are being subscribed to + * @return error code, or A_OK for success + */ +A_STATUS wdi_event_sub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, + enum WDI_EVENT event); + +/** + * @brief Unsubscribe from a specified WDI event. + * @details + * This function removes the provided event subscription object from the + * list of subscribers for its event. + * This function shall only be called if there was a successful prior call + * to event_sub() on the same wdi_event_subscribe object. + * + * @param pdev - the event physical device with the list of event subscribers + * @param event_cb_sub - the event subscription object + * @param event - which event is being unsubscribed + * @return error code, or A_OK for success + */ +A_STATUS wdi_event_unsub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, + enum WDI_EVENT event); + +#ifdef WDI_EVENT_ENABLE + +void wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data); +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev); +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev); + +#else + +static inline void wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + return; +} +static inline A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} +static inline A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} +#endif /* WDI_EVENT_ENABLE */ + +#endif /* _WDI_EVENT_API_H_ */ diff --git a/core/hdd/inc/qc_sap_ioctl.h b/core/hdd/inc/qc_sap_ioctl.h new file mode 100644 index 0000000000..5fee04fcc6 --- /dev/null +++ b/core/hdd/inc/qc_sap_ioctl.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _QC_SAP_IOCTL_H_ +#define _QC_SAP_IOCTL_H_ + +/* + * QCSAP ioctls. + */ + +/* + * Max size of optional information elements. We artificially + * constrain this; it's limited only by the max frame size (and + * the max parameter size of the wireless extensions). + */ +#define QCSAP_MAX_OPT_IE 256 +#define QCSAP_MAX_WSC_IE 256 +#define QCSAP_MAX_GET_STA_INFO 512 + +typedef struct sSSID { + uint8_t length; + uint8_t ssId[32]; +} tSSID; + +typedef struct sSSIDInfo { + tSSID ssid; + uint8_t ssidHidden; +} tSSIDInfo; + +typedef enum { + eQC_DOT11_MODE_ALL = 0, + eQC_DOT11_MODE_ABG = 0x0001, /* 11a/b/g only, no HT, no proprietary */ + eQC_DOT11_MODE_11A = 0x0002, + eQC_DOT11_MODE_11B = 0x0004, + eQC_DOT11_MODE_11G = 0x0008, + eQC_DOT11_MODE_11N = 0x0010, + eQC_DOT11_MODE_11G_ONLY = 0x0020, + eQC_DOT11_MODE_11N_ONLY = 0x0040, + eQC_DOT11_MODE_11B_ONLY = 0x0080, + eQC_DOT11_MODE_11A_ONLY = 0x0100, + /* This is for WIFI test. It is same as eWNIAPI_MAC_PROTOCOL_ALL except when it starts IBSS in 11B of 2.4GHz */ + /* It is for CSR internal use */ + eQC_DOT11_MODE_AUTO = 0x0200, + +} tQcPhyMode; + +#define QCSAP_ADDR_LEN 6 + +typedef uint8_t qcmacaddr[QCSAP_ADDR_LEN]; + +struct qc_mac_acl_entry { + qcmacaddr addr; + int vlan_id; +}; + +typedef enum { + eQC_AUTH_TYPE_OPEN_SYSTEM, + eQC_AUTH_TYPE_SHARED_KEY, + eQC_AUTH_TYPE_AUTO_SWITCH +} eQcAuthType; + +typedef enum { + eQC_WPS_BEACON_IE, + eQC_WPS_PROBE_RSP_IE, + eQC_WPS_ASSOC_RSP_IE +} eQCWPSType; + +/* + * Retrieve the WPA/RSN information element for an associated station. + */ +struct sQcSapreq_wpaie { + uint8_t wpa_ie[QCSAP_MAX_OPT_IE]; + uint8_t wpa_macaddr[QCSAP_ADDR_LEN]; +}; + +/* + * Retrieve the WSC information element for an associated station. + */ +struct sQcSapreq_wscie { + uint8_t wsc_macaddr[QCSAP_ADDR_LEN]; + uint8_t wsc_ie[QCSAP_MAX_WSC_IE]; +}; + +/* + * Retrieve the WPS PBC Probe Request IEs. + */ +typedef struct sQcSapreq_WPSPBCProbeReqIES { + uint8_t macaddr[QCSAP_ADDR_LEN]; + uint16_t probeReqIELen; + uint8_t probeReqIE[512]; +} sQcSapreq_WPSPBCProbeReqIES_t; + +/* + * Channel List Info + */ + +typedef struct { + uint8_t num_channels; + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tChannelListInfo, *tpChannelListInfo; + +#ifdef __linux__ +/* + * Wireless Extensions API, private ioctl interfaces. + * + * NB: Even-numbered ioctl numbers have set semantics and are privileged! + * (regardless of the incorrect comment in wireless.h!) + */ + +#define QCSAP_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0) +#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) +/* (SIOCIWFIRSTPRIV+2) is unused */ +/* (SIOCIWFIRSTPRIV+3) is unused */ +#define QCSAP_IOCTL_GET_STAWPAIE (SIOCIWFIRSTPRIV+4) +#define QCSAP_IOCTL_SETWPAIE (SIOCIWFIRSTPRIV+5) +#define QCSAP_IOCTL_STOPBSS (SIOCIWFIRSTPRIV+6) +#define QCSAP_IOCTL_VERSION (SIOCIWFIRSTPRIV+7) +#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES (SIOCIWFIRSTPRIV+8) +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV+9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV+10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV+11) +/* (SIOCIWFIRSTPRIV+12) is unused */ +/* Private ioctls and their sub-ioctls */ +#define QCSAP_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 13) +#define QCSAP_GET_STATS 1 +#define QCSAP_IOCTL_CLR_STATS (SIOCIWFIRSTPRIV+14) + +#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV+15) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define WE_SET_SAP_CHANNELS 3 +#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV+16) +#define WE_UNIT_TEST_CMD 7 +#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV+17) + +#define WE_P2P_NOA_CMD 2 + +#define QCSAP_IOCTL_MODIFY_ACL (SIOCIWFIRSTPRIV+18) +#define QCSAP_IOCTL_GET_CHANNEL_LIST (SIOCIWFIRSTPRIV+19) +#define QCSAP_IOCTL_SET_TX_POWER (SIOCIWFIRSTPRIV+20) +#define QCSAP_IOCTL_GET_STA_INFO (SIOCIWFIRSTPRIV+21) +#define QCSAP_IOCTL_SET_MAX_TX_POWER (SIOCIWFIRSTPRIV+22) +#define QCSAP_IOCTL_GET_INI_CFG (SIOCIWFIRSTPRIV+25) +#define QCSAP_IOCTL_SET_INI_CFG (SIOCIWFIRSTPRIV+26) +#define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#ifdef DEBUG +#define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1 +#endif +#define QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL 2 + +#define MAX_VAR_ARGS 7 +#define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#define QCSAP_IOCTL_MAX_STR_LEN 1024 + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) + +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +enum { + QCSAP_PARAM_MAX_ASSOC = 1, + QCSAP_PARAM_GET_WLAN_DBG, + QCSAP_PARAM_CLR_ACL = 4, + QCSAP_PARAM_ACL_MODE, + QCSAP_PARAM_HIDE_SSID, + QCSAP_PARAM_AUTO_CHANNEL, + QCSAP_PARAM_SET_MC_RATE, + QCSAP_PARAM_SET_TXRX_FW_STATS, + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + QCSAP_DBGLOG_LOG_LEVEL, + QCSAP_DBGLOG_VAP_ENABLE, + QCSAP_DBGLOG_VAP_DISABLE, + QCSAP_DBGLOG_MODULE_ENABLE, + QCSAP_DBGLOG_MODULE_DISABLE, + QCSAP_DBGLOG_MOD_LOG_LEVEL, + QCSAP_DBGLOG_TYPE, + QCSAP_DBGLOG_REPORT_ENABLE, + QCASAP_TXRX_FWSTATS_RESET, + QCSAP_PARAM_RTSCTS, + QCASAP_SET_11N_RATE, + QCASAP_SET_VHT_RATE, + QCASAP_SHORT_GI, + QCSAP_SET_AMPDU, + QCSAP_SET_AMSDU, + QCSAP_GTX_HT_MCS, + QCSAP_GTX_VHT_MCS, + QCSAP_GTX_USRCFG, + QCSAP_GTX_THRE, + QCSAP_GTX_MARGIN, + QCSAP_GTX_STEP, + QCSAP_GTX_MINTPC, + QCSAP_GTX_BWMASK, +#ifdef QCA_PKT_PROTO_TRACE + QCASAP_SET_DEBUG_LOG, +#endif + QCASAP_SET_TM_LEVEL, + QCASAP_SET_DFS_IGNORE_CAC, + QCASAP_GET_DFS_NOL, + QCASAP_SET_DFS_NOL, + QCSAP_PARAM_SET_CHANNEL_CHANGE, + QCASAP_SET_DFS_TARGET_CHNL, + QCASAP_SET_RADAR_CMD, + QCSAP_GET_ACL, + QCASAP_TX_CHAINMASK_CMD, + QCASAP_RX_CHAINMASK_CMD, + QCASAP_NSS_CMD, + QCSAP_IPA_UC_STAT, + QCASAP_SET_PHYMODE, + QCASAP_GET_TEMP_CMD, + QCASAP_DUMP_STATS, + QCASAP_CLEAR_STATS, + QCASAP_SET_RADAR_DBG, +}; + +int iw_softap_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +#endif /* __linux__ */ + +#endif /*_QC_SAP_IOCTL_H_*/ diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h new file mode 100644 index 0000000000..cf136b4325 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_ASSOC_H__) +#define WLAN_HDD_ASSOC_H__ + +/** + * DOC: wlan_hdd_assoc.h + * + */ + +/* Include files */ +#include +#include +#include +#include "ol_txrx_ctrl_api.h" + +/* Preprocessor Definitions and Constants */ +#ifdef FEATURE_WLAN_TDLS +#define HDD_MAX_NUM_TDLS_STA 8 +#define HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN 1 +#define TDLS_STA_INDEX_VALID(staId) \ + (((staId) >= 1) && ((staId) < 0xFF)) +#endif +#define TKIP_COUNTER_MEASURE_STARTED 1 +#define TKIP_COUNTER_MEASURE_STOPED 0 +/* Timeout (in ms) for Link to Up before Registering Station */ +#define ASSOC_LINKUP_TIMEOUT 60 + +/* In pronto case, IBSS owns the first peer for bss peer. + In Rome case, IBSS uses the 2nd peer as bss peer */ +#define IBSS_BROADCAST_STAID 1 + +/* Type Declarations */ +/** + * typedef eConnectionState - Connection states + * @eConnectionState_NotConnected: Not associated in Infra or participating + * in an IBSS / Ad-hoc network + * @eConnectionState_Connecting: While connection in progress + * @eConnectionState_Associated: Associated in an Infrastructure network + * @eConnectionState_IbssDisconnected: Participating in an IBSS network though + * disconnected (no partner stations in the IBSS) + * @eConnectionState_IbssConnected: Participating in an IBSS network with + * partner stations also present + * eConnectionState_Disconnecting: Disconnecting in an Infrastructure network + */ +typedef enum { + eConnectionState_NotConnected, + eConnectionState_Connecting, + eConnectionState_Associated, + eConnectionState_IbssDisconnected, + eConnectionState_IbssConnected, + eConnectionState_Disconnecting +} eConnectionState; + +/** + * typedef ePeerStatus - Peer status + * @ePeerConnected: peer connected + * @ePeerDisconnected: peer disconnected + */ +typedef enum { + ePeerConnected = 1, + ePeerDisconnected +} ePeerStatus; + +/** + * typedef connection_info_t - structure to store connection information + * @connState: connection state of the NIC + * @connDot11DesiredBssType: BSS type of the current connection. + * Comes from the MIB at the time the connect request is issued + * in combination with the BssDescription from the + * associated entity + * @bssId: BSSID + * @SSID: SSID Info + * @staId: Station ID + * @peerMacAddress:Peer Mac Address of the IBSS Stations + * @authType: Auth Type + * @ucEncryptionType: Unicast Encryption Type + * @mcEncryptionType: Multicast Encryption Type + * @Keys: Keys + * @operationChannel: Operation Channel + * @uIsAuthenticated: Remembers authenticated state + * @dot11Mode: dot11Mode + * @proxyARPService: proxy arp service + */ +typedef struct connection_info_s { + eConnectionState connState; + eMib_dot11DesiredBssType connDot11DesiredBssType; + struct cdf_mac_addr bssId; + tCsrSSIDInfo SSID; + uint8_t staId[MAX_IBSS_PEERS]; + struct cdf_mac_addr peerMacAddress[MAX_IBSS_PEERS]; + eCsrAuthType authType; + eCsrEncryptionType ucEncryptionType; + eCsrEncryptionType mcEncryptionType; + tCsrKeys Keys; + uint8_t operationChannel; + uint8_t uIsAuthenticated; + uint32_t dot11Mode; + uint8_t proxyARPService; +} connection_info_t; + +/* Forward declarations */ +typedef struct hdd_adapter_s hdd_adapter_t; +typedef struct hdd_context_s hdd_context_t; +typedef struct hdd_station_ctx hdd_station_ctx_t; +typedef struct hdd_ap_ctx_s hdd_ap_ctx_t; +typedef struct hdd_mon_ctx_s hdd_mon_ctx_t; + +/** + * hdd_is_connecting() - Function to check connection progress + * @hdd_sta_ctx: pointer to global HDD Station context + * + * Return: true if connecting, false otherwise + */ +bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx); + +/** + * hdd_conn_is_connected() - Function to check connection status + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_conn_is_connected(hdd_station_ctx_t *pHddStaCtx); + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: eCSR_BAND_24 or eCSR_BAND_5G based on current AP connection + * eCSR_BAND_ALL if not connected + */ +eCsrBand hdd_conn_get_connected_band(hdd_station_ctx_t *pHddStaCtx); + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); + +/** + * hdd_conn_get_connected_bss_type() - get current bss type + * @pHddStaCtx: pointer to global HDD Station context + * @pConnectedBssType: pointer to connected bss type + * + * Return: false if any errors encountered, true otherwise + */ +bool +hdd_conn_get_connected_bss_type(hdd_station_ctx_t *pHddStaCtx, + eMib_dot11DesiredBssType *pConnectedBssType); + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @pAdapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType); + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @pAdapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType); + +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @pAdapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @staId: station identifier + * @ucastSig: unicast signature + * + * Construct the staDesc and register with TL the new STA. + * This is called as part of ADD_STA in the TDLS setup. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_roam_register_tdlssta(hdd_adapter_t *pAdapter, + const uint8_t *peerMac, uint16_t staId, + uint8_t ucastSig); + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @pAdapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @pAdapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const hdd_adapter_t *pAdapter, + const uint16_t measurementToken, + const bool flag, + const uint8_t numBss); +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +CDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress); +#endif diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h new file mode 100644 index 0000000000..9b8095a43e --- /dev/null +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -0,0 +1,3351 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(HDD_CONFIG_H__) +#define HDD_CONFIG_H__ + +/** + * + * DOC: wlan_hdd_config.h + * + * WLAN Adapter Configuration functions + */ + +/* $HEADER$ */ + +/* Include files */ +#include +#include +#include +#include +#include +#include + +#define FW_MODULE_LOG_LEVEL_STRING_LENGTH (255) + +#ifdef DHCP_SERVER_OFFLOAD +#define IPADDR_NUM_ENTRIES (4) +#define IPADDR_STRING_LENGTH (16) +#endif + +/* Number of items that can be configured */ +#define MAX_CFG_INI_ITEMS 512 + +/* Defines for all of the things we read from the configuration (registry). */ + +#define CFG_RTS_THRESHOLD_NAME "RTSThreshold" +#define CFG_RTS_THRESHOLD_MIN WNI_CFG_RTS_THRESHOLD_STAMIN /* min is 0, meaning always use RTS. */ +#define CFG_RTS_THRESHOLD_MAX WNI_CFG_RTS_THRESHOLD_STAMAX /* max is the max frame size */ +#define CFG_RTS_THRESHOLD_DEFAULT WNI_CFG_RTS_THRESHOLD_STADEF + +#define CFG_FRAG_THRESHOLD_NAME "gFragmentationThreshold" +#define CFG_FRAG_THRESHOLD_MIN WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN +#define CFG_FRAG_THRESHOLD_MAX WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX +#define CFG_FRAG_THRESHOLD_DEFAULT WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF + +#define CFG_OPERATING_CHANNEL_NAME "gOperatingChannel" +#define CFG_OPERATING_CHANNEL_MIN (0) +#define CFG_OPERATING_CHANNEL_MAX (14) +#define CFG_OPERATING_CHANNEL_DEFAULT (1) + +#define CFG_SHORT_SLOT_TIME_ENABLED_NAME "gShortSlotTimeEnabled" +#define CFG_SHORT_SLOT_TIME_ENABLED_MIN WNI_CFG_SHORT_SLOT_TIME_STAMIN +#define CFG_SHORT_SLOT_TIME_ENABLED_MAX WNI_CFG_SHORT_SLOT_TIME_STAMAX +#define CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT WNI_CFG_SHORT_SLOT_TIME_STADEF + +#define CFG_11D_SUPPORT_ENABLED_NAME "g11dSupportEnabled" +#define CFG_11D_SUPPORT_ENABLED_MIN WNI_CFG_11D_ENABLED_STAMIN +#define CFG_11D_SUPPORT_ENABLED_MAX WNI_CFG_11D_ENABLED_STAMAX +#define CFG_11D_SUPPORT_ENABLED_DEFAULT WNI_CFG_11D_ENABLED_STADEF /* Default is ON */ + +#define CFG_11H_SUPPORT_ENABLED_NAME "g11hSupportEnabled" +#define CFG_11H_SUPPORT_ENABLED_MIN (0) +#define CFG_11H_SUPPORT_ENABLED_MAX (1) +#define CFG_11H_SUPPORT_ENABLED_DEFAULT (1) /* Default is ON */ + +/* COUNTRY Code Priority */ +#define CFG_COUNTRY_CODE_PRIORITY_NAME "gCountryCodePriority" +#define CFG_COUNTRY_CODE_PRIORITY_MIN (0) +#define CFG_COUNTRY_CODE_PRIORITY_MAX (1) +#define CFG_COUNTRY_CODE_PRIORITY_DEFAULT (0) + +#define CFG_HEARTBEAT_THRESH_24_NAME "gHeartbeat24" +#define CFG_HEARTBEAT_THRESH_24_MIN WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN +#define CFG_HEARTBEAT_THRESH_24_MAX WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX +#define CFG_HEARTBEAT_THRESH_24_DEFAULT WNI_CFG_HEART_BEAT_THRESHOLD_STADEF + +#define CFG_POWER_USAGE_NAME "gPowerUsage" +#define CFG_POWER_USAGE_MIN "Min" /* Minimum Power Save */ +#define CFG_POWER_USAGE_MAX "Max" /* Maximum Power Save */ +#define CFG_POWER_USAGE_DEFAULT "Mod" /* Moderate Power Save */ + +#define CFG_WOWL_PATTERN_NAME "gWowlPattern" +#define CFG_WOWL_PATTERN_DEFAULT "" + +/* IMPS = IdleModePowerSave */ +#define CFG_ENABLE_IMPS_NAME "gEnableImps" +#define CFG_ENABLE_IMPS_MIN (0) +#define CFG_ENABLE_IMPS_MAX (1) +#define CFG_ENABLE_IMPS_DEFAULT (1) + +/* PS = PowerSave */ +#define CFG_ENABLE_PS_NAME "gEnableBmps" +#define CFG_ENABLE_PS_MIN (0) +#define CFG_ENABLE_PS_MAX (1) +#define CFG_ENABLE_PS_DEFAULT (1) + +#define CFG_BMPS_MINIMUM_LI_NAME "gBmpsMinListenInterval" +#define CFG_BMPS_MINIMUM_LI_MIN (1) +#define CFG_BMPS_MINIMUM_LI_MAX (65535) +#define CFG_BMPS_MINIMUM_LI_DEFAULT (1) + +#define CFG_BMPS_MODERATE_LI_NAME "gBmpsModListenInterval" +#define CFG_BMPS_MODERATE_LI_MIN (1) +#define CFG_BMPS_MODERATE_LI_MAX (65535) +#define CFG_BMPS_MODERATE_LI_DEFAULT (1) + +#define CFG_BMPS_MAXIMUM_LI_NAME "gBmpsMaxListenInterval" +#define CFG_BMPS_MAXIMUM_LI_MIN (1) +#define CFG_BMPS_MAXIMUM_LI_MAX (65535) +#define CFG_BMPS_MAXIMUM_LI_DEFAULT (1) + +#define CFG_MAX_RX_AMPDU_FACTOR_NAME "gMaxRxAmpduFactor" +#define CFG_MAX_RX_AMPDU_FACTOR_MIN WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN +#define CFG_MAX_RX_AMPDU_FACTOR_MAX WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX +#define CFG_MAX_RX_AMPDU_FACTOR_DEFAULT WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF + +/* Configuration added to enable/disable CTS2SELF in */ +/* Adaptive RX drain feature */ +#define CFG_ENABLE_ADAPT_RX_DRAIN_NAME "gEnableAdaptRxDrain" +#define CFG_ENABLE_ADAPT_RX_DRAIN_MIN WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN +#define CFG_ENABLE_ADAPT_RX_DRAIN_MAX WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX +#define CFG_ENABLE_ADAPT_RX_DRAIN_DEFAULT WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF + +#define CFG_REG_CHANGE_DEF_COUNTRY_NAME "gRegulatoryChangeCountry" +#define CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MIN (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MAX (1) + +#define CFG_ADVERTISE_CONCURRENT_OPERATION_NAME "gAdvertiseConcurrentOperation" +#define CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT (1) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MIN (0) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MAX (1) + +typedef enum { + eHDD_DOT11_MODE_AUTO = 0, /* covers all things we support */ + eHDD_DOT11_MODE_abg, /* 11a/b/g only, no HT, no proprietary */ + eHDD_DOT11_MODE_11b, + eHDD_DOT11_MODE_11g, + eHDD_DOT11_MODE_11n, + eHDD_DOT11_MODE_11g_ONLY, + eHDD_DOT11_MODE_11n_ONLY, + eHDD_DOT11_MODE_11b_ONLY, + eHDD_DOT11_MODE_11ac_ONLY, + eHDD_DOT11_MODE_11ac, + eHDD_DOT11_MODE_11a, +} eHddDot11Mode; + +#define CFG_DOT11_MODE_NAME "gDot11Mode" +#define CFG_DOT11_MODE_MIN eHDD_DOT11_MODE_AUTO +#ifdef WLAN_FEATURE_11AC +#define CFG_DOT11_MODE_DEFAULT eHDD_DOT11_MODE_11ac +#else +#define CFG_DOT11_MODE_DEFAULT eHDD_DOT11_MODE_11n +#endif +#define CFG_DOT11_MODE_MAX eHDD_DOT11_MODE_11a + +#define CFG_CHANNEL_BONDING_MODE_24GHZ_NAME "gChannelBondingMode24GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +#define CFG_CHANNEL_BONDING_MODE_5GHZ_NAME "gChannelBondingMode5GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +#define CFG_FIXED_RATE_NAME "gFixedRate" +#define CFG_FIXED_RATE_MIN WNI_CFG_FIXED_RATE_STAMIN +#define CFG_FIXED_RATE_MAX WNI_CFG_FIXED_RATE_STAMAX +#define CFG_FIXED_RATE_DEFAULT WNI_CFG_FIXED_RATE_STADEF + +#define CFG_SHORT_GI_20MHZ_NAME "gShortGI20Mhz" +#define CFG_SHORT_GI_20MHZ_MIN WNI_CFG_SHORT_GI_20MHZ_STAMIN +#define CFG_SHORT_GI_20MHZ_MAX WNI_CFG_SHORT_GI_20MHZ_STAMAX +#define CFG_SHORT_GI_20MHZ_DEFAULT WNI_CFG_SHORT_GI_20MHZ_STADEF + +#define CFG_SCAN_RESULT_AGE_COUNT_NAME "gScanResultAgeCount" +#define CFG_SCAN_RESULT_AGE_COUNT_MIN (1) +#define CFG_SCAN_RESULT_AGE_COUNT_MAX (100) +#define CFG_SCAN_RESULT_AGE_COUNT_DEFAULT (3) + +/* All in seconds */ +/* Not Connect, No Power Save */ +#define CFG_SCAN_RESULT_AGE_TIME_NCNPS_NAME "gScanResultAgeNCNPS" +#define CFG_SCAN_RESULT_AGE_TIME_NCNPS_MIN (10) +#define CFG_SCAN_RESULT_AGE_TIME_NCNPS_MAX (10000) +#define CFG_SCAN_RESULT_AGE_TIME_NCNPS_DEFAULT (50) +/* Not Connect, Power Save */ +#define CFG_SCAN_RESULT_AGE_TIME_NCPS_NAME "gScanResultAgeNCPS" +#define CFG_SCAN_RESULT_AGE_TIME_NCPS_MIN (10) +#define CFG_SCAN_RESULT_AGE_TIME_NCPS_MAX (10000) +#define CFG_SCAN_RESULT_AGE_TIME_NCPS_DEFAULT (300) +/* Connect, No Power Save */ +#define CFG_SCAN_RESULT_AGE_TIME_CNPS_NAME "gScanResultAgeCNPS" +#define CFG_SCAN_RESULT_AGE_TIME_CNPS_MIN (10) +#define CFG_SCAN_RESULT_AGE_TIME_CNPS_MAX (10000) +#define CFG_SCAN_RESULT_AGE_TIME_CNPS_DEFAULT (150) +/* Connect, Power Save */ +#define CFG_SCAN_RESULT_AGE_TIME_CPS_NAME "gScanResultAgeCPS" +#define CFG_SCAN_RESULT_AGE_TIME_CPS_MIN (10) +#define CFG_SCAN_RESULT_AGE_TIME_CPS_MAX (10000) +#define CFG_SCAN_RESULT_AGE_TIME_CPS_DEFAULT (600) + +#define CFG_RSSI_CATEGORY_GAP_NAME "gRssiCatGap" +#define CFG_RSSI_CATEGORY_GAP_MIN (5) +#define CFG_RSSI_CATEGORY_GAP_MAX (100) +#define CFG_RSSI_CATEGORY_GAP_DEFAULT (5) + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +#define CFG_ROAM_PREFER_5GHZ "gRoamPrefer5GHz" +#define CFG_ROAM_PREFER_5GHZ_MIN (0) +#define CFG_ROAM_PREFER_5GHZ_MAX (1) +#define CFG_ROAM_PREFER_5GHZ_DEFAULT (1) + +/* + To enable, set gRoamIntraBand=1 (Roaming within band) + To disable, set gRoamIntraBand=0 (Roaming across band) + */ +#define CFG_ROAM_INTRA_BAND "gRoamIntraBand" +#define CFG_ROAM_INTRA_BAND_MIN (0) +#define CFG_ROAM_INTRA_BAND_MAX (1) +#define CFG_ROAM_INTRA_BAND_DEFAULT (0) +#endif + +#define CFG_SHORT_PREAMBLE_NAME "gShortPreamble" +#define CFG_SHORT_PREAMBLE_MIN WNI_CFG_SHORT_PREAMBLE_STAMIN +#define CFG_SHORT_PREAMBLE_MAX WNI_CFG_SHORT_PREAMBLE_STAMAX +#define CFG_SHORT_PREAMBLE_DEFAULT WNI_CFG_SHORT_PREAMBLE_STADEF + +#define CFG_IBSS_BSSID_NAME "gIbssBssid" +#define CFG_IBSS_BSSID_MIN "000000000000" +#define CFG_IBSS_BSSID_MAX "ffffffffffff" +#define CFG_IBSS_BSSID_DEFAULT "000AF5040506" + +#define CFG_INTF0_MAC_ADDR_NAME "Intf0MacAddress" +#define CFG_INTF0_MAC_ADDR_MIN "000000000000" +#define CFG_INTF0_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF0_MAC_ADDR_DEFAULT "000AF5898980" + +#define CFG_INTF1_MAC_ADDR_NAME "Intf1MacAddress" +#define CFG_INTF1_MAC_ADDR_MIN "000000000000" +#define CFG_INTF1_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF1_MAC_ADDR_DEFAULT "000AF5898981" + +#define CFG_INTF2_MAC_ADDR_NAME "Intf2MacAddress" +#define CFG_INTF2_MAC_ADDR_MIN "000000000000" +#define CFG_INTF2_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF2_MAC_ADDR_DEFAULT "000AF5898982" + +#define CFG_INTF3_MAC_ADDR_NAME "Intf3MacAddress" +#define CFG_INTF3_MAC_ADDR_MIN "000000000000" +#define CFG_INTF3_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF3_MAC_ADDR_DEFAULT "000AF5898983" + +#define CFG_AP_QOS_UAPSD_MODE_NAME "gEnableApUapsd" /* ACs to setup U-APSD for at assoc */ +#define CFG_AP_QOS_UAPSD_MODE_MIN (0) +#define CFG_AP_QOS_UAPSD_MODE_MAX (1) +#define CFG_AP_QOS_UAPSD_MODE_DEFAULT (1) + +#define CFG_AP_ENABLE_RANDOM_BSSID_NAME "gEnableApRandomBssid" +#define CFG_AP_ENABLE_RANDOM_BSSID_MIN (0) +#define CFG_AP_ENABLE_RANDOM_BSSID_MAX (1) +#define CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT (0) + +#define CFG_AP_ENABLE_PROTECTION_MODE_NAME "gEnableApProt" +#define CFG_AP_ENABLE_PROTECTION_MODE_MIN (0) +#define CFG_AP_ENABLE_PROTECTION_MODE_MAX (1) +#define CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT (1) + +/* Bit map for CFG_AP_PROTECTION_MODE_DEFAULT */ +/* LOWER byte for associated stations */ +/* UPPER byte for overlapping stations */ +/* each byte will have the following info */ +/* bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8 */ +/* OBSS RIFS LSIG_TXOP NON_GF HT20 FROM_11G FROM_11B FROM_11A */ +/* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 */ +/* OBSS RIFS LSIG_TXOP NON_GF HT_20 FROM_11G FROM_11B FROM_11A */ +#define CFG_AP_PROTECTION_MODE_NAME "gApProtection" +#define CFG_AP_PROTECTION_MODE_MIN (0x0) +#define CFG_AP_PROTECTION_MODE_MAX (0xFFFF) +#define CFG_AP_PROTECTION_MODE_DEFAULT (0xBFFF) + +#define CFG_AP_OBSS_PROTECTION_MODE_NAME "gEnableApOBSSProt" +#define CFG_AP_OBSS_PROTECTION_MODE_MIN (0) +#define CFG_AP_OBSS_PROTECTION_MODE_MAX (1) +#define CFG_AP_OBSS_PROTECTION_MODE_DEFAULT (0) + +#define CFG_AP_STA_SECURITY_SEPERATION_NAME "gDisableIntraBssFwd" +#define CFG_AP_STA_SECURITY_SEPERATION_MIN (0) +#define CFG_AP_STA_SECURITY_SEPERATION_MAX (1) +#define CFG_AP_STA_SECURITY_SEPERATION_DEFAULT (0) + +#define CFG_AP_LISTEN_MODE_NAME "gEnablePhyAgcListenMode" +#define CFG_AP_LISTEN_MODE_MIN (0) +#define CFG_AP_LISTEN_MODE_MAX (128) +#define CFG_AP_LISTEN_MODE_DEFAULT (128) + +#define CFG_AP_AUTO_SHUT_OFF "gAPAutoShutOff" +#define CFG_AP_AUTO_SHUT_OFF_MIN (0) +#define CFG_AP_AUTO_SHUT_OFF_MAX (4294967295UL) +#define CFG_AP_AUTO_SHUT_OFF_DEFAULT (0) + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define CFG_WLAN_AUTO_SHUTDOWN "gWlanAutoShutdown" +#define CFG_WLAN_AUTO_SHUTDOWN_MIN (0) +#define CFG_WLAN_AUTO_SHUTDOWN_MAX (86400) /* Max 1 day timeout */ +#define CFG_WLAN_AUTO_SHUTDOWN_DEFAULT (0) +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE "gWlanMccToSccSwitchMode" +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN (CDF_MCC_TO_SCC_SWITCH_DISABLE) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX (CDF_MCC_TO_SCC_SWITCH_FORCE) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT (CDF_MCC_TO_SCC_SWITCH_DISABLE) +#endif + +#define CFG_DISABLE_PACKET_FILTER "gDisablePacketFilter" +#define CFG_DISABLE_PACKET_FILTER_MIN (0) +#define CFG_DISABLE_PACKET_FILTER_MAX (0x1) +#define CFG_DISABLE_PACKET_FILTER_DEFAULT (0) + +#define CFG_ENABLE_LTE_COEX "gEnableLTECoex" +#define CFG_ENABLE_LTE_COEX_MIN (0) +#define CFG_ENABLE_LTE_COEX_MAX (1) +#define CFG_ENABLE_LTE_COEX_DEFAULT (0) + +#define CFG_AP_KEEP_ALIVE_PERIOD_NAME "gApKeepAlivePeriod" +#define CFG_AP_KEEP_ALIVE_PERIOD_MIN WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_AP_KEEP_ALIVE_PERIOD_MAX WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF + +#define CFG_GO_KEEP_ALIVE_PERIOD_NAME "gGoKeepAlivePeriod" +#define CFG_GO_KEEP_ALIVE_PERIOD_MIN WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_GO_KEEP_ALIVE_PERIOD_MAX WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF + +#define CFG_AP_LINK_MONITOR_PERIOD_NAME "gApLinkMonitorPeriod" +#define CFG_AP_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_AP_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_AP_LINK_MONITOR_PERIOD_DEFAULT (10) + +/* gGoLinkMonitorPeriod is period where link is idle and where + * we send NULL frame + */ +#define CFG_GO_LINK_MONITOR_PERIOD_NAME "gGoLinkMonitorPeriod" +#define CFG_GO_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_GO_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_GO_LINK_MONITOR_PERIOD_DEFAULT (10) + +#define CFG_BEACON_INTERVAL_NAME "gBeaconInterval" +#define CFG_BEACON_INTERVAL_MIN WNI_CFG_BEACON_INTERVAL_STAMIN +#define CFG_BEACON_INTERVAL_MAX WNI_CFG_BEACON_INTERVAL_STAMAX +#define CFG_BEACON_INTERVAL_DEFAULT WNI_CFG_BEACON_INTERVAL_STADEF + +/* Additional Handoff related Parameters */ +#define CFG_ROAMING_TIME_NAME "gRoamingTime" +#define CFG_ROAMING_TIME_MIN (0) +#define CFG_ROAMING_TIME_MAX (4294967UL) +#define CFG_ROAMING_TIME_DEFAULT (10) + +#define CFG_VCC_RSSI_TRIGGER_NAME "gVccRssiTrigger" +#define CFG_VCC_RSSI_TRIGGER_MIN (0) +#define CFG_VCC_RSSI_TRIGGER_MAX (80) +#define CFG_VCC_RSSI_TRIGGER_DEFAULT (80) + +#define CFG_VCC_UL_MAC_LOSS_THRESH_NAME "gVccUlMacLossThresh" +#define CFG_VCC_UL_MAC_LOSS_THRESH_MIN (0) +#define CFG_VCC_UL_MAC_LOSS_THRESH_MAX (9) +#define CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT (9) + +#define CFG_PASSIVE_MAX_CHANNEL_TIME_NAME "gPassiveMaxChannelTime" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +#define CFG_PASSIVE_MIN_CHANNEL_TIME_NAME "gPassiveMinChannelTime" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +#define CFG_ACTIVE_MAX_CHANNEL_TIME_NAME "gActiveMaxChannelTime" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +#define CFG_ACTIVE_MIN_CHANNEL_TIME_NAME "gActiveMinChannelTime" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) + +#define CFG_RETRY_LIMIT_ZERO_NAME "gRetryLimitZero" +#define CFG_RETRY_LIMIT_ZERO_MIN (0) +#define CFG_RETRY_LIMIT_ZERO_MAX (15) +#define CFG_RETRY_LIMIT_ZERO_DEFAULT (5) + +#define CFG_RETRY_LIMIT_ONE_NAME "gRetryLimitOne" +#define CFG_RETRY_LIMIT_ONE_MIN (0) +#define CFG_RETRY_LIMIT_ONE_MAX (15) +#define CFG_RETRY_LIMIT_ONE_DEFAULT (10) + +#define CFG_RETRY_LIMIT_TWO_NAME "gRetryLimitTwo" +#define CFG_RETRY_LIMIT_TWO_MIN (0) +#define CFG_RETRY_LIMIT_TWO_MAX (15) +#define CFG_RETRY_LIMIT_TWO_DEFAULT (15) + +#ifdef WLAN_AP_STA_CONCURRENCY + +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME "gPassiveMaxChannelTimeConc" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (110) + +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME "gPassiveMinChannelTimeConc" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (60) + +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME "gActiveMaxChannelTimeConc" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (40) + +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME "gActiveMinChannelTimeConc" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (20) + +#define CFG_REST_TIME_CONC_NAME "gRestTimeConc" +#define CFG_REST_TIME_CONC_MIN (0) +#define CFG_REST_TIME_CONC_MAX (10000) +#define CFG_REST_TIME_CONC_DEFAULT (100) + +#define CFG_NUM_STA_CHAN_COMBINED_CONC_NAME "gNumStaChanCombinedConc" +#define CFG_NUM_STA_CHAN_COMBINED_CONC_MIN (1) +#define CFG_NUM_STA_CHAN_COMBINED_CONC_MAX (255) +#define CFG_NUM_STA_CHAN_COMBINED_CONC_DEFAULT (3) + +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_NAME "gNumP2PChanCombinedConc" +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_MIN (1) +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_MAX (255) +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_DEFAULT (1) +#endif + +#define CFG_MAX_PS_POLL_NAME "gMaxPsPoll" +#define CFG_MAX_PS_POLL_MIN WNI_CFG_MAX_PS_POLL_STAMIN +#define CFG_MAX_PS_POLL_MAX WNI_CFG_MAX_PS_POLL_STAMAX +#define CFG_MAX_PS_POLL_DEFAULT WNI_CFG_MAX_PS_POLL_STADEF + +#define CFG_MAX_TX_POWER_NAME "gTxPowerCap" +#define CFG_MAX_TX_POWER_MIN WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN +#define CFG_MAX_TX_POWER_MAX WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX +/* Not to use CFG default because if no registry setting, this is ignored by SME. */ +#define CFG_MAX_TX_POWER_DEFAULT WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX + +#define CFG_LOW_GAIN_OVERRIDE_NAME "gLowGainOverride" +#define CFG_LOW_GAIN_OVERRIDE_MIN WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN +#define CFG_LOW_GAIN_OVERRIDE_MAX WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX +#define CFG_LOW_GAIN_OVERRIDE_DEFAULT WNI_CFG_LOW_GAIN_OVERRIDE_STADEF + +#define CFG_RSSI_FILTER_PERIOD_NAME "gRssiFilterPeriod" +#define CFG_RSSI_FILTER_PERIOD_MIN WNI_CFG_RSSI_FILTER_PERIOD_STAMIN +#define CFG_RSSI_FILTER_PERIOD_MAX WNI_CFG_RSSI_FILTER_PERIOD_STAMAX +/* Increased this value for Non-ESE AP. This is cause FW RSSI Monitoring */ +/* the consumer of this value is ON by default. So to impact power numbers */ +/* we are setting this to a high value. */ +#define CFG_RSSI_FILTER_PERIOD_DEFAULT WNI_CFG_RSSI_FILTER_PERIOD_STADEF + +#define CFG_IGNORE_DTIM_NAME "gIgnoreDtim" +#define CFG_IGNORE_DTIM_MIN WNI_CFG_IGNORE_DTIM_STAMIN +#define CFG_IGNORE_DTIM_MAX WNI_CFG_IGNORE_DTIM_STAMAX +#define CFG_IGNORE_DTIM_DEFAULT WNI_CFG_IGNORE_DTIM_STADEF + +#define CFG_MAX_LI_MODULATED_DTIM_NAME "gMaxLIModulatedDTIM" +#define CFG_MAX_LI_MODULATED_DTIM_MIN (1) +#define CFG_MAX_LI_MODULATED_DTIM_MAX (10) +#define CFG_MAX_LI_MODULATED_DTIM_DEFAULT (10) + +#define CFG_RX_ANT_CONFIGURATION_NAME "gNumRxAnt" +#define CFG_RX_ANT_CONFIGURATION_NAME_MIN (1) +#define CFG_RX_ANT_CONFIGURATION_NAME_MAX (2) +#define CFG_RX_ANT_CONFIGURATION_NAME_DEFAULT (2) + +#define CFG_FW_HEART_BEAT_MONITORING_NAME "gEnableFWHeartBeatMonitoring" +#define CFG_FW_HEART_BEAT_MONITORING_MIN (0) +#define CFG_FW_HEART_BEAT_MONITORING_MAX (1) +#define CFG_FW_HEART_BEAT_MONITORING_DEFAULT (1) + +#define CFG_FW_BEACON_FILTERING_NAME "gEnableFWBeaconFiltering" +#define CFG_FW_BEACON_FILTERING_MIN (0) +#define CFG_FW_BEACON_FILTERING_MAX (1) +#define CFG_FW_BEACON_FILTERING_DEFAULT (1) + +#define CFG_FW_RSSI_MONITORING_NAME "gEnableFWRssiMonitoring" +#define CFG_FW_RSSI_MONITORING_MIN (0) +#define CFG_FW_RSSI_MONITORING_MAX (1) +#define CFG_FW_RSSI_MONITORING_DEFAULT (1) + +/* enable use of long duration RTS-CTS protection when SAP goes off channel + * in MCC mode + */ +#define CFG_FW_MCC_RTS_CTS_PROT_NAME "gFWMccRtsCtsProtection" +#define CFG_FW_MCC_RTS_CTS_PROT_MIN (0) +#define CFG_FW_MCC_RTS_CTS_PROT_MAX (1) +#define CFG_FW_MCC_RTS_CTS_PROT_DEFAULT (0) + +/* Enable use of broadcast probe response to increase the detectability of + * SAP in MCC mode + */ +#define CFG_FW_MCC_BCAST_PROB_RESP_NAME "gFWMccBCastProbeResponse" +#define CFG_FW_MCC_BCAST_PROB_RESP_MIN (0) +#define CFG_FW_MCC_BCAST_PROB_RESP_MAX (1) +#define CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT (0) + +#define CFG_DATA_INACTIVITY_TIMEOUT_NAME "gDataInactivityTimeout" +#define CFG_DATA_INACTIVITY_TIMEOUT_MIN (1) +#define CFG_DATA_INACTIVITY_TIMEOUT_MAX (255) +#define CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT (20) + +#define CFG_RF_SETTLING_TIME_CLK_NAME "rfSettlingTimeUs" +#define CFG_RF_SETTLING_TIME_CLK_MIN (0) +#define CFG_RF_SETTLING_TIME_CLK_MAX (60000) +#define CFG_RF_SETTLING_TIME_CLK_DEFAULT (1500) + +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME "gStaKeepAlivePeriod" +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN (0) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX (65535) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT (0) + +/* WMM configuration */ +#define CFG_QOS_WMM_MODE_NAME "WmmIsEnabled" +#define CFG_QOS_WMM_MODE_MIN (0) +#define CFG_QOS_WMM_MODE_MAX (2) /* HDD_WMM_NO_QOS */ +#define CFG_QOS_WMM_MODE_DEFAULT (0) /* HDD_WMM_AUTO */ + +#define CFG_QOS_WMM_80211E_ENABLED_NAME "80211eIsEnabled" +#define CFG_QOS_WMM_80211E_ENABLED_MIN (0) +#define CFG_QOS_WMM_80211E_ENABLED_MAX (1) +#define CFG_QOS_WMM_80211E_ENABLED_DEFAULT (0) + +#define CFG_QOS_WMM_UAPSD_MASK_NAME "UapsdMask" /* ACs to setup U-APSD for at assoc */ +#define CFG_QOS_WMM_UAPSD_MASK_MIN (0x00) +#define CFG_QOS_WMM_UAPSD_MASK_MAX (0xFF) +#define CFG_QOS_WMM_UAPSD_MASK_DEFAULT (0x00) + +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME "InfraUapsdVoSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT (20) + +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME "InfraUapsdVoSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT (2000) + +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME "InfraUapsdViSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT (300) + +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME "InfraUapsdViSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT (2000) + +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME "InfraUapsdBeSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT (300) + +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME "InfraUapsdBeSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT (2000) + +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME "InfraUapsdBkSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT (300) + +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME "InfraUapsdBkSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT (2000) + +#ifdef FEATURE_WLAN_ESE +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME "InfraInactivityInterval" +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN (0) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT (0) /* disabled */ + +#define CFG_ESE_FEATURE_ENABLED_NAME "EseEnabled" +#define CFG_ESE_FEATURE_ENABLED_MIN (0) +#define CFG_ESE_FEATURE_ENABLED_MAX (1) +#define CFG_ESE_FEATURE_ENABLED_DEFAULT (0) /* disabled */ +#endif /* FEATURE_WLAN_ESE */ + +#ifdef FEATURE_WLAN_LFR +#define CFG_LFR_FEATURE_ENABLED_NAME "FastRoamEnabled" +#define CFG_LFR_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_FEATURE_ENABLED_DEFAULT (0) /* disabled */ + +#define CFG_LFR_MAWC_FEATURE_ENABLED_NAME "MAWCEnabled" +#define CFG_LFR_MAWC_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_MAWC_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT (0) /* disabled */ +#endif /* FEATURE_WLAN_LFR */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/* This flag will control fasttransition in case of 11r and ese. */ +/* Basically with this the whole neighbor roam, pre-auth, reassoc */ +/* can be turned ON/OFF. */ +/* With this turned OFF 11r will completely not work. */ +/* For 11r this flag has to be ON. */ +/* For ESE fastroam will not work. */ +#define CFG_FAST_TRANSITION_ENABLED_NAME "FastTransitionEnabled" +#define CFG_FAST_TRANSITION_ENABLED_NAME_MIN (0) +#define CFG_FAST_TRANSITION_ENABLED_NAME_MAX (1) +#define CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT (1) /* Enabled */ + +/* This parameter is used to decide whether to Roam or not. + * AP1 is the currently associated AP and AP2 is chosen for roaming. + * The Roaming will happen only if AP2 has better Signal Quality and it has a RSSI better than AP1 + * in terms of RoamRssiDiff,and RoamRssiDiff is the number of units (typically measured in dB) AP2 + * is better than AP1. + * This check is not done if the value is Zero */ +#define CFG_ROAM_RSSI_DIFF_NAME "RoamRssiDiff" +#define CFG_ROAM_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RSSI_DIFF_MAX (30) +#define CFG_ROAM_RSSI_DIFF_DEFAULT (5) + +/*This parameter is used to set Wireless Extended Security Mode.*/ +#define CFG_ENABLE_WES_MODE_NAME "gWESModeEnabled" +#define CFG_ENABLE_WES_MODE_NAME_MIN (0) +#define CFG_ENABLE_WES_MODE_NAME_MAX (1) +#define CFG_ENABLE_WES_MODE_NAME_DEFAULT (0) + +#define CFG_ROAM_SCAN_N_PROBES "gRoamScanNProbes" +#define CFG_ROAM_SCAN_N_PROBES_MIN (1) +#define CFG_ROAM_SCAN_N_PROBES_MAX (10) +#define CFG_ROAM_SCAN_N_PROBES_DEFAULT (2) + +#define CFG_ROAM_SCAN_HOME_AWAY_TIME "gRoamScanHomeAwayTime" +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN (0) /* 0 for disable */ +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX (300) +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT (CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) +/* disabled by default */ + +#endif /* (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) */ + +#ifdef FEATURE_WLAN_OKC +#define CFG_OKC_FEATURE_ENABLED_NAME "OkcEnabled" +#define CFG_OKC_FEATURE_ENABLED_MIN (0) +#define CFG_OKC_FEATURE_ENABLED_MAX (1) +#define CFG_OKC_FEATURE_ENABLED_DEFAULT (1) +#endif + +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED "gRoamScanOffloadEnabled" +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN (0) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX (1) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT (1) + +#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME "PktClassificationBasis" /* DSCP or 802.1Q */ +#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MIN (0) +#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MAX (1) +#define CFG_QOS_WMM_PKT_CLASSIFY_BASIS_DEFAULT (0) /* DSCP */ + +/* default TSPEC parameters for AC_VO */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME "InfraDirAcVo" +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT (3) /* WLAN_QCT_CUST_WMM_TSDIR_BOTH */ + +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME "InfraNomMsduSizeAcVo" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT (0x80D0) + +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME "InfraMeanDataRateAcVo" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT (0x14500) + +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME "InfraMinPhyRateAcVo" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT (0x5B8D80) + +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME "InfraSbaAcVo" +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_VI */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME "InfraDirAcVi" +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT (3) /* WLAN_QCT_CUST_WMM_TSDIR_BOTH */ + +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME "InfraNomMsduSizeAcVi" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT (0x85DC) + +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME "InfraMeanDataRateAcVi" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT (0x57E40) + +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME "InfraMinPhyRateAcVi" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT (0x5B8D80) + +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME "InfraSbaAcVi" +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_BE*/ +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME "InfraDirAcBe" +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT (3) /* WLAN_QCT_CUST_WMM_TSDIR_BOTH */ + +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME "InfraNomMsduSizeAcBe" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT (0x85DC) + +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME "InfraMeanDataRateAcBe" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT (0x493E0) + +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME "InfraMinPhyRateAcBe" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT (0x5B8D80) + +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME "InfraSbaAcBe" +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_Bk*/ +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME "InfraDirAcBk" +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT (3) /* WLAN_QCT_CUST_WMM_TSDIR_BOTH */ + +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME "InfraNomMsduSizeAcBk" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT (0x85DC) + +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME "InfraMeanDataRateAcBk" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT (0x493E0) + +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME "InfraMinPhyRateAcBk" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT (0x5B8D80) + +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME "InfraSbaAcBk" +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT (0x2001) + +#define CFG_TL_DELAYED_TRGR_FRM_INT_NAME "DelayedTriggerFrmInt" +#define CFG_TL_DELAYED_TRGR_FRM_INT_MIN 1 +#define CFG_TL_DELAYED_TRGR_FRM_INT_MAX (4294967295UL) +#define CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT 3000 + +#if defined WLAN_FEATURE_VOWIFI +#define CFG_RRM_ENABLE_NAME "gRrmEnable" +#define CFG_RRM_ENABLE_MIN (0) +#define CFG_RRM_ENABLE_MAX (1) +#define CFG_RRM_ENABLE_DEFAULT (0) + +#define CFG_RRM_OPERATING_CHAN_MAX_DURATION_NAME "gRrmOperChanMax" /* section 11.10.3 IEEE std. 802.11k-2008 */ +#define CFG_RRM_OPERATING_CHAN_MAX_DURATION_MIN (0) /* Maxduration = 2^(maxDuration - 4) * bcnIntvl. */ +#define CFG_RRM_OPERATING_CHAN_MAX_DURATION_MAX (8) +#define CFG_RRM_OPERATING_CHAN_MAX_DURATION_DEFAULT (3) /* max duration = 2^-1 * bcnIntvl (50% of bcn intvl) */ + +#define CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_NAME "gRrmNonOperChanMax" /* Same as above. */ +#define CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_MIN (0) +#define CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_MAX (8) +#define CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_DEFAULT (3) + +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_NAME "gRrmRandnIntvl" +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN (10) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX (100) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT (100) +#endif + +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME "ImplicitQosIsEnabled" +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN (0) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX (1) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT (1) + +#define CFG_ENABLE_LOGP_NAME "gEnableLogp" +#define CFG_ENABLE_LOGP_MIN (0) +#define CFG_ENABLE_LOGP_MAX (1) +#define CFG_ENABLE_LOGP_DEFAULT (0) + +#if defined WLAN_FEATURE_VOWIFI_11R +#define CFG_FT_RESOURCE_REQ_NAME "gFTResourceReqSupported" +#define CFG_FT_RESOURCE_REQ_MIN (0) +#define CFG_FT_RESOURCE_REQ_MAX (1) +#define CFG_FT_RESOURCE_REQ_DEFAULT (0) +#endif + +#define CFG_TELE_BCN_TRANS_LI_NAME "telescopicBeaconTransListenInterval" +#define CFG_TELE_BCN_TRANS_LI_MIN (0) +#define CFG_TELE_BCN_TRANS_LI_MAX (7) +#define CFG_TELE_BCN_TRANS_LI_DEFAULT (3) + +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_NAME "telescopicBeaconTransListenIntervalNumIdleBcns" +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MIN (5) +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MAX (255) +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_DEFAULT (10) + +#define CFG_TELE_BCN_MAX_LI_NAME "telescopicBeaconMaxListenInterval" +#define CFG_TELE_BCN_MAX_LI_MIN (0) +#define CFG_TELE_BCN_MAX_LI_MAX (7) +#define CFG_TELE_BCN_MAX_LI_DEFAULT (5) + +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_NAME "telescopicBeaconMaxListenIntervalNumIdleBcns" +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MIN (5) +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MAX (255) +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_DEFAULT (15) + +#define CFG_BCN_EARLY_TERM_WAKE_NAME "beaconEarlyTerminationWakeInterval" +#define CFG_BCN_EARLY_TERM_WAKE_MIN (2) +#define CFG_BCN_EARLY_TERM_WAKE_MAX (255) +#define CFG_BCN_EARLY_TERM_WAKE_DEFAULT (3) + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME "gNeighborScanTimerPeriod" +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN (3) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX (300) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT (200) + +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME "gNeighborLookupThreshold" +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN (10) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX (120) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT (78) + +#define CFG_DELAY_BEFORE_VDEV_STOP_NAME "gDelayBeforeVdevStop" +#define CFG_DELAY_BEFORE_VDEV_STOP_MIN (2) +#define CFG_DELAY_BEFORE_VDEV_STOP_MAX (200) +#define CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT (20) + +/* + * This parameter is the drop in RSSI value that will trigger a precautionary + * scan by firmware. + * MAX value is choose so that this type of scan can be disabled by user. + */ +#define CFG_ROAM_RESCAN_RSSI_DIFF_NAME "gRoamRescanRssiDiff" +#define CFG_ROAM_RESCAN_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RESCAN_RSSI_DIFF_MAX (100) +#define CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT (5) + +/* + * This parameter is the RSSI diff above neighbor lookup threshold, when + * opportunistic scan should be triggered. + * MAX value is choose so that this type of scan can be always enabled by user. + * MIN value will cause opportunistic scan to be triggered in neighbor lookup + * RSSI range. + */ +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME "gOpportunisticThresholdDiff" +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN (0) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX (127) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT (0) + +#define CFG_NEIGHBOR_SCAN_CHAN_LIST_NAME "gNeighborScanChannelList" +#define CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT "" + +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME "gNeighborScanChannelMinTime" +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN (10) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX (40) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT (20) + +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME "gNeighborScanChannelMaxTime" +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN (3) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX (300) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT (30) + +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME "gMaxNeighborReqTries" +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN (1) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX (4) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT (3) + +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME "gNeighborScanRefreshPeriod" +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN (1000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX (60000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT (20000) + +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_NAME "gEmptyScanRefreshPeriod" +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN (0) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX (60000) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT (0) + +#define CFG_ROAM_BMISS_FIRST_BCNT_NAME "gRoamBmissFirstBcnt" +#define CFG_ROAM_BMISS_FIRST_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FIRST_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT (10) + +#define CFG_ROAM_BMISS_FINAL_BCNT_NAME "gRoamBmissFinalBcnt" +#define CFG_ROAM_BMISS_FINAL_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FINAL_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT (10) + +#define CFG_ROAM_BEACON_RSSI_WEIGHT_NAME "gRoamBeaconRssiWeight" +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MIN (0) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MAX (16) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT (14) +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ + +#define CFG_QOS_WMM_BURST_SIZE_DEFN_NAME "burstSizeDefinition" +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MIN (0) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MAX (1) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT (0) + +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME "tsInfoAckPolicy" +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN (0x00) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX (0x01) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT (0x00) + +#define CFG_SINGLE_TID_RC_NAME "SingleTIDRC" +#define CFG_SINGLE_TID_RC_MIN (0) /* Seperate replay counter for all TID */ +#define CFG_SINGLE_TID_RC_MAX (1) /* Single replay counter for all TID */ +#define CFG_SINGLE_TID_RC_DEFAULT (1) +#define CFG_MCAST_BCAST_FILTER_SETTING_NAME "McastBcastFilter" +#define CFG_MCAST_BCAST_FILTER_SETTING_MIN (0) +#define CFG_MCAST_BCAST_FILTER_SETTING_MAX (3) +#define CFG_MCAST_BCAST_FILTER_SETTING_DEFAULT (0) + +#define CFG_DYNAMIC_PSPOLL_VALUE_NAME "gDynamicPSPollvalue" +#define CFG_DYNAMIC_PSPOLL_VALUE_MIN (0) +#define CFG_DYNAMIC_PSPOLL_VALUE_MAX (255) +#define CFG_DYNAMIC_PSPOLL_VALUE_DEFAULT (0) + +#define CFG_TELE_BCN_WAKEUP_EN_NAME "gTelescopicBeaconWakeupEn" +#define CFG_TELE_BCN_WAKEUP_EN_MIN (0) +#define CFG_TELE_BCN_WAKEUP_EN_MAX (1) +#define CFG_TELE_BCN_WAKEUP_EN_DEFAULT (0) + +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME "gAddTSWhenACMIsOff" +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN (0) +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX (1) /* Send AddTs even when ACM is not set for the AC */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT (0) + +#define CFG_VALIDATE_SCAN_LIST_NAME "gValidateScanList" +#define CFG_VALIDATE_SCAN_LIST_MIN (0) +#define CFG_VALIDATE_SCAN_LIST_MAX (1) +#define CFG_VALIDATE_SCAN_LIST_DEFAULT (0) + +#define CFG_NULLDATA_AP_RESP_TIMEOUT_NAME "gNullDataApRespTimeout" +#define CFG_NULLDATA_AP_RESP_TIMEOUT_MIN (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN) +#define CFG_NULLDATA_AP_RESP_TIMEOUT_MAX (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX) +#define CFG_NULLDATA_AP_RESP_TIMEOUT_DEFAULT (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF) + +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME "gApDataAvailPollInterval" +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF) + +#define CFG_ENABLE_HOST_ARPOFFLOAD_NAME "hostArpOffload" +#define CFG_ENABLE_HOST_ARPOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_ARPOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT (0) + +#define CFG_ENABLE_HOST_SSDP_NAME "ssdp" +#define CFG_ENABLE_HOST_SSDP_MIN (0) +#define CFG_ENABLE_HOST_SSDP_MAX (1) +#define CFG_ENABLE_HOST_SSDP_DEFAULT (1) + +#define CFG_ENABLE_HOST_NSOFFLOAD_NAME "hostNSOffload" +#define CFG_ENABLE_HOST_NSOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_NSOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT (0) + +#define CFG_BAND_CAPABILITY_NAME "BandCapability" +#define CFG_BAND_CAPABILITY_MIN (0) +#define CFG_BAND_CAPABILITY_MAX (2) +#define CFG_BAND_CAPABILITY_DEFAULT (0) + +#define CFG_ENABLE_BEACON_EARLY_TERMINATION_NAME "enableBeaconEarlyTermination" +#define CFG_ENABLE_BEACON_EARLY_TERMINATION_MIN (0) +#define CFG_ENABLE_BEACON_EARLY_TERMINATION_MAX (1) +#define CFG_ENABLE_BEACON_EARLY_TERMINATION_DEFAULT (0) + +#define CFG_ENABLE_CLOSE_LOOP_NAME "gEnableCloseLoop" +#define CFG_ENABLE_CLOSE_LOOP_MIN WNI_CFG_FIXED_RATE_STAMIN +#define CFG_ENABLE_CLOSE_LOOP_MAX WNI_CFG_FIXED_RATE_STAMAX +#define CFG_ENABLE_CLOSE_LOOP_DEFAULT WNI_CFG_FIXED_RATE_STADEF + +#define CFG_ENABLE_BYPASS_11D_NAME "gEnableBypass11d" +#define CFG_ENABLE_BYPASS_11D_MIN (0) +#define CFG_ENABLE_BYPASS_11D_MAX (1) +#define CFG_ENABLE_BYPASS_11D_DEFAULT (1) + +#define CFG_ENABLE_DFS_CHNL_SCAN_NAME "gEnableDFSChnlScan" +#define CFG_ENABLE_DFS_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT (1) + +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME "gEnableDFSPnoChnlScan" +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT (1) + +#define CFG_ENABLE_RAMDUMP_COLLECTION "gEnableDumpCollect" +#define CFG_ENABLE_RAMDUMP_COLLECTION_MIN (0) +#define CFG_ENABLE_RAMDUMP_COLLECTION_MAX (1) +#define CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT (1) + +typedef enum { + eHDD_LINK_SPEED_REPORT_ACTUAL = 0, + eHDD_LINK_SPEED_REPORT_MAX = 1, + eHDD_LINK_SPEED_REPORT_MAX_SCALED = 2, +} eHddLinkSpeedReportType; +#ifdef WLAN_FEATURE_11AC +#define CFG_VHT_CHANNEL_WIDTH "gVhtChannelWidth" +#define CFG_VHT_CHANNEL_WIDTH_MIN (0) +#define CFG_VHT_CHANNEL_WIDTH_MAX (4) +#define CFG_VHT_CHANNEL_WIDTH_DEFAULT (3) + +#define CFG_VHT_ENABLE_RX_MCS_8_9 "gVhtRxMCS" +#define CFG_VHT_ENABLE_RX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT (0) + +#define CFG_VHT_ENABLE_TX_MCS_8_9 "gVhtTxMCS" +#define CFG_VHT_ENABLE_TX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT (0) + +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9 "gVhtRxMCS2x2" +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT (0) + +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9 "gVhtTxMCS2x2" +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT (0) + +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE "gEnable2x2" +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE "gEnableMuBformee" +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_PAID_FEATURE "gEnablePAID" +#define CFG_VHT_ENABLE_PAID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_PAID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_GID_FEATURE "gEnableGID" +#define CFG_VHT_ENABLE_GID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_GID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_GID_FEATURE_DEFAULT (0) +#endif + +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK "gSetTxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN (1) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX (2) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT (1) + +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK "gSetRxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN (1) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX (2) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT (1) + +#define CFG_ENABLE_AMPDUPS_FEATURE "gEnableAMPDUPS" +#define CFG_ENABLE_AMPDUPS_FEATURE_MIN (0) +#define CFG_ENABLE_AMPDUPS_FEATURE_MAX (1) +#define CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT (0) + +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE "gEnableHtSMPS" +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX (1) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT (0) + +#define CFG_HT_SMPS_CAP_FEATURE "gHtSMPS" +#define CFG_HT_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_SMPS_CAP_FEATURE_MAX (3) +#define CFG_HT_SMPS_CAP_FEATURE_DEFAULT (3) + +#define CFG_DISABLE_DFS_CH_SWITCH "gDisableDFSChSwitch" +#define CFG_DISABLE_DFS_CH_SWITCH_MIN (0) +#define CFG_DISABLE_DFS_CH_SWITCH_MAX (1) +#define CFG_DISABLE_DFS_CH_SWITCH_DEFAULT (0) + +#define CFG_ENABLE_DFS_MASTER_CAPABILITY "gEnableDFSMasterCap" +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN (0) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX (1) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT (0) + +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION "gSapPreferredChanLocation" +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN (0) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX (2) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT (0) + +#define CFG_DISABLE_DFS_JAPAN_W53 "gDisableDfsJapanW53" +#define CFG_DISABLE_DFS_JAPAN_W53_MIN (0) +#define CFG_DISABLE_DFS_JAPAN_W53_MAX (1) +#define CFG_DISABLE_DFS_JAPAN_W53_DEFAULT (0) + +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME "dfsPhyerrFilterOffload" +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN (0) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX (1) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT (0) + +#define CFG_REPORT_MAX_LINK_SPEED "gReportMaxLinkSpeed" +#define CFG_REPORT_MAX_LINK_SPEED_MIN (eHDD_LINK_SPEED_REPORT_ACTUAL) +#define CFG_REPORT_MAX_LINK_SPEED_MAX (eHDD_LINK_SPEED_REPORT_MAX_SCALED) +#define CFG_REPORT_MAX_LINK_SPEED_DEFAULT (eHDD_LINK_SPEED_REPORT_MAX_SCALED) + +/* + * RSSI Thresholds + * Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + */ +#define CFG_LINK_SPEED_RSSI_HIGH "gLinkSpeedRssiHigh" +#define CFG_LINK_SPEED_RSSI_HIGH_MIN (-127) +#define CFG_LINK_SPEED_RSSI_HIGH_MAX (0) +#define CFG_LINK_SPEED_RSSI_HIGH_DEFAULT (-55) + +#define CFG_LINK_SPEED_RSSI_MID "gLinkSpeedRssiMed" +#define CFG_LINK_SPEED_RSSI_MID_MIN (-127) +#define CFG_LINK_SPEED_RSSI_MID_MAX (0) +#define CFG_LINK_SPEED_RSSI_MID_DEFAULT (-65) + +#define CFG_LINK_SPEED_RSSI_LOW "gLinkSpeedRssiLow" +#define CFG_LINK_SPEED_RSSI_LOW_MIN (-127) +#define CFG_LINK_SPEED_RSSI_LOW_MAX (0) +#define CFG_LINK_SPEED_RSSI_LOW_DEFAULT (-80) + +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME "isP2pDeviceAddrAdministrated" +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN (0) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX (1) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT (1) + +#define CFG_ENABLE_SSR "gEnableSSR" +#define CFG_ENABLE_SSR_MIN (0) +#define CFG_ENABLE_SSR_MAX (1) +#define CFG_ENABLE_SSR_DEFAULT (1) + +#define CFG_ENABLE_OVERLAP_CH "gEnableOverLapCh" +#define CFG_ENABLE_OVERLAP_CH_MIN (0) +#define CFG_ENABLE_OVERLAP_CH_MAX (1) +#define CFG_ENABLE_OVERLAP_CH_DEFAULT (0) + +#define CFG_PPS_ENABLE_5G_EBT "gEnable5gEBT" +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN (0) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX (1) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT (0) + +#define CFG_ENABLE_MEMORY_DEEP_SLEEP "gEnableMemDeepSleep" +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN (0) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX (1) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT (1) + +/* In cfg.dat 1=1MBPS, 2=2MBPS, 3=5_5MBPS, 4=11MBPS, 5=6MBPS, 6=9MBPS, + * 7=12MBPS, 8=18MBPS, 9=24MBPS. But 6=9MBPS and 8=18MBPS are not basic + * 11g rates and should not be set by gDefaultRateIndex24Ghz. + */ + +#define CFG_DEFAULT_RATE_INDEX_24GH "gDefaultRateIndex24Ghz" +#define CFG_DEFAULT_RATE_INDEX_24GH_MIN (1) +#define CFG_DEFAULT_RATE_INDEX_24GH_MAX (9) +#define CFG_DEFAULT_RATE_INDEX_24GH_DEFAULT (1) + +#define CFG_ENABLE_PACKET_LOG "gEnablePacketLog" +#define CFG_ENABLE_PACKET_LOG_MIN (0) +#define CFG_ENABLE_PACKET_LOG_MAX (1) +#define CFG_ENABLE_PACKET_LOG_DEFAULT (1) + +/* gFwDebugLogType takes values from enum dbglog_process_t, + * make default value as DBGLOG_PROCESS_NET_RAW to give the + * logs to net link since cnss_diag service is started at boot + * time by default. + */ +#define CFG_ENABLE_FW_LOG_TYPE "gFwDebugLogType" +#define CFG_ENABLE_FW_LOG_TYPE_MIN (0) +#define CFG_ENABLE_FW_LOG_TYPE_MAX (255) +#define CFG_ENABLE_FW_LOG_TYPE_DEFAULT (3) + +/* gFwDebugLogLevel takes values from enum DBGLOG_LOG_LVL, + * make default value as DBGLOG_WARN to enable error and + * warning logs by default. + */ +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL "gFwDebugLogLevel" +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN (0) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX (255) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT (4) + +/* For valid values of log levels check enum DBGLOG_LOG_LVL and + * for valid values of module ids check enum WLAN_MODULE_ID. + */ +#define CFG_ENABLE_FW_MODULE_LOG_LEVEL "gFwDebugModuleLoglevel" +#define CFG_ENABLE_FW_MODULE_LOG_DEFAULT "" + +#ifdef FEATURE_GREEN_AP +#define CFG_ENABLE_GREEN_AP_FEATURE "gEnableGreenAp" +#define CFG_ENABLE_GREEN_AP_FEATURE_MIN (0) +#define CFG_ENABLE_GREEN_AP_FEATURE_MAX (1) +#define CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT (1) +#endif + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +#define CFG_SAP_SCC_CHAN_AVOIDANCE "gSapSccChanAvoidance" +#define CFG_SAP_SCC_CHAN_AVOIDANCE_MIN (0) +#define CFG_SAP_SCC_CHAN_AVOIDANCE_MAX (1) +#define CFG_SAP_SCC_CHAN_AVOIDANCE_DEFAULT (0) +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +/* + * CDF Trace Enable Control + * Notes: + * the MIN/MAX/DEFAULT values apply for all modules + * the DEFAULT value is outside the valid range. if the DEFAULT + * value is not overridden, then no change will be made to the + * "built in" default values compiled into the code + * values are a bitmap indicating which log levels are to enabled + * (must match order of cdf_trace_level enumerations) + * 00000001 FATAL + * 00000010 ERROR + * 00000100 WARN + * 00001000 INFO + * 00010000 INFO HIGH + * 00100000 INFO MED + * 01000000 INFO LOW + * 10000000 DEBUG + * + * hence a value of 0xFF would set all bits (enable all logs) + */ + +#define CFG_CDF_TRACE_ENABLE_WDI_NAME "cdf_trace_enable_wdi" +#define CFG_CDF_TRACE_ENABLE_HDD_NAME "cdf_trace_enable_hdd" +#define CFG_CDF_TRACE_ENABLE_SME_NAME "cdf_trace_enable_sme" +#define CFG_CDF_TRACE_ENABLE_PE_NAME "cdf_trace_enable_pe" +#define CFG_CDF_TRACE_ENABLE_PMC_NAME "cdf_trace_enable_pmc" +#define CFG_CDF_TRACE_ENABLE_WMA_NAME "cdf_trace_enable_wma" +#define CFG_CDF_TRACE_ENABLE_SYS_NAME "cdf_trace_enable_sys" +#define CFG_CDF_TRACE_ENABLE_CDF_NAME "cdf_trace_enable_cdf" +#define CFG_CDF_TRACE_ENABLE_SAP_NAME "cdf_trace_enable_sap" +#define CFG_CDF_TRACE_ENABLE_HDD_SAP_NAME "cdf_trace_enable_hdd_sap" +#define CFG_CDF_TRACE_ENABLE_BMI_NAME "cdf_trace_enable_bmi" + +#define CFG_CDF_TRACE_ENABLE_MIN (0) +#define CFG_CDF_TRACE_ENABLE_MAX (0xff) +#define CFG_CDF_TRACE_ENABLE_DEFAULT (0xffff) + +#define HDD_MCASTBCASTFILTER_FILTER_NONE 0x00 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST 0x01 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST 0x02 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST 0x03 +#define HDD_MULTICAST_FILTER_LIST 0x04 +#define HDD_MULTICAST_FILTER_LIST_CLEAR 0x05 + +/*BMPS Logic + * Notes: + * 1 - Then Host driver and above layers control the PS mechanism + * 0 - Diver/Core Stack internally control the Power saving mechanism + */ +#define CFG_ANDRIOD_POWER_SAVE_NAME "isAndroidPsEn" +#define CFG_ANDRIOD_POWER_SAVE_MIN (0) +#define CFG_ANDRIOD_POWER_SAVE_MAX (1) +#define CFG_ANDRIOD_POWER_SAVE_DEFAULT (0) + +/* + * Enable Dynamic DTIM + * Options + * 0 -Disable DynamicDTIM + * 1 to 5 - SLM will switch to DTIM specified here when host suspends and + * switch DTIM1 when host resumes */ +#define CFG_ENABLE_DYNAMIC_DTIM_NAME "gEnableDynamicDTIM" +#define CFG_ENABLE_DYNAMIC_DTIM_MIN (0) +#define CFG_ENABLE_DYNAMIC_DTIM_MAX (5) +#define CFG_ENABLE_DYNAMIC_DTIM_DEFAULT (0) + +/* + * Enable First Scan 2G Only + * Options + * 0 - Disable First Scan 2G Option + * 1 - Enable First Scan 2G Option + */ +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME "gEnableFirstScan2GOnly" +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN (0) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX (1) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT (0) + +/* + * Driver Force ACS is reintroduced for android SAP legacy configuration method. + * If Driver force acs is enabled, channel/ hw config from hostapd is ignored. + * Driver uses INI params dot11Mode, channel bonding mode and vht chan width + * to derive ACS HW mode and operating BW. + * + * Non android platforms shall not use force ACS method and rely on hostapd + * driven ACS method for concurrent SAP ACS configuration, OBSS etc. + */ +#define CFG_FORCE_SAP_ACS "gApAutoChannelSelection" +#define CFG_FORCE_SAP_ACS_MIN (0) +#define CFG_FORCE_SAP_ACS_MAX (1) +#define CFG_FORCE_SAP_ACS_DEFAULT (0) + +#define CFG_FORCE_SAP_ACS_START_CH "gAPChannelSelectStartChannel" +#define CFG_FORCE_SAP_ACS_START_CH_MIN (0) +#define CFG_FORCE_SAP_ACS_START_CH_MAX (0xFF) +#define CFG_FORCE_SAP_ACS_START_CH_DEFAULT (1) + +#define CFG_FORCE_SAP_ACS_END_CH "gAPChannelSelectEndChannel" +#define CFG_FORCE_SAP_ACS_END_CH_MIN (0) +#define CFG_FORCE_SAP_ACS_END_CH_MAX (0xFF) +#define CFG_FORCE_SAP_ACS_END_CH_DEFAULT (11) + +/* + * Skip DFS Channel in case of P2P Search + * Options + * 0 - Don't Skip DFS Channel in case of P2P Search + * 1 - Skip DFS Channel in case of P2P Search + */ +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME "gSkipDfsChannelInP2pSearch" +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN (0) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX (1) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT (1) + +/* + * Ignore Dynamic Dtim in case of P2P + * Options + * 0 - Consider Dynamic Dtim incase of P2P + * 1 - Ignore Dynamic Dtim incase of P2P + */ +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME "gIgnoreDynamicDtimInP2pMode" +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN (0) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX (1) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT (0) + +#define CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_NAME "gEnableAutomaticTxPowerControl" +#define CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_MIN (0) +#define CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_MAX (1) +#define CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_DEFAULT (1) + +#define CFG_SHORT_GI_40MHZ_NAME "gShortGI40Mhz" +#define CFG_SHORT_GI_40MHZ_MIN 0 +#define CFG_SHORT_GI_40MHZ_MAX 1 +#define CFG_SHORT_GI_40MHZ_DEFAULT 1 + +/* + * Enable / Disable MCC feature + * Default: Enable + */ +#define CFG_ENABLE_MCC_ENABLED_NAME "gEnableMCCMode" +#define CFG_ENABLE_MCC_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ENABLED_DEFAULT (1) + +/* + * Allow GO in MCC mode to accept different beacon interval than STA's. + * Added for Wi-Fi Cert. 5.1.12 + * Default: gAllowMCCGODiffBI = 2 + * If gAllowMCCGODiffBI = 1 // Set to 1 for WFA certification. GO Beacon + * interval is not changed. MCC GO + * doesn't work well in optimized way. + * In worst scenario, it may invite STA + * disconnection. + * gAllowMCCGODiffBI = 2 //If set to 2 workaround 1 disassoc all the clients + * and update beacon Interval + * gAllowMCCGODiffBI = 3 //If set to 3 tear down the P2P link in auto/ + * Non-autonomous -GO case + * gAllowMCCGODiffBI = 4 //If set to 4 don't disconnect the P2P client + * in autonomous/Non-autonomous -GO case update + * the BI dynamically + */ +#define CFG_ALLOW_MCC_GO_DIFF_BI_NAME "gAllowMCCGODiffBI" +#define CFG_ALLOW_MCC_GO_DIFF_BI_MIN (0) +#define CFG_ALLOW_MCC_GO_DIFF_BI_MAX (4) +#define CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT (4) + +/* + * Enable/Disable Thermal Mitigation feature + * Default: Enable + */ +#define CFG_THERMAL_MIGRATION_ENABLE_NAME "gThermalMitigationEnable" +#define CFG_THERMAL_MIGRATION_ENABLE_MIN (0) +#define CFG_THERMAL_MIGRATION_ENABLE_MAX (1) +#define CFG_THERMAL_MIGRATION_ENABLE_DEFAULT (1) + +#define CFG_THROTTLE_PERIOD_NAME "gThrottlePeriod" +#define CFG_THROTTLE_PERIOD_MIN (10) +#define CFG_THROTTLE_PERIOD_MAX (10000) +#define CFG_THROTTLE_PERIOD_DEFAULT (4000) + +#define CFG_THERMAL_TEMP_MIN_LEVEL0_NAME "gThermalTempMinLevel0" +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT (0) + +#define CFG_THERMAL_TEMP_MAX_LEVEL0_NAME "gThermalTempMaxLevel0" +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MIN_LEVEL1_NAME "gThermalTempMinLevel1" +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT (70) + +#define CFG_THERMAL_TEMP_MAX_LEVEL1_NAME "gThermalTempMaxLevel1" +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MIN_LEVEL2_NAME "gThermalTempMinLevel2" +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MAX_LEVEL2_NAME "gThermalTempMaxLevel2" +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT (125) + +#define CFG_THERMAL_TEMP_MIN_LEVEL3_NAME "gThermalTempMinLevel3" +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MAX_LEVEL3_NAME "gThermalTempMaxLevel3" +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT (0) + +/* + * Enable/Disable Modulated DTIM feature + * Default: Disable + */ +#define CFG_ENABLE_MODULATED_DTIM_NAME "gEnableModulatedDTIM" +#define CFG_ENABLE_MODULATED_DTIM_MIN (0) +#define CFG_ENABLE_MODULATED_DTIM_MAX (5) +#define CFG_ENABLE_MODULATED_DTIM_DEFAULT (0) + +/* + * Enable/Disable Multicast MAC Address List feature + * Default: Disable + */ +#define CFG_MC_ADDR_LIST_ENABLE_NAME "gMCAddrListEnable" +#define CFG_MC_ADDR_LIST_ENABLE_MIN (0) +#define CFG_MC_ADDR_LIST_ENABLE_MAX (1) +#define CFG_MC_ADDR_LIST_ENABLE_DEFAULT (0) + +#define CFG_ENABLE_RX_STBC "gEnableRXSTBC" +#define CFG_ENABLE_RX_STBC_MIN (0) +#define CFG_ENABLE_RX_STBC_MAX (1) +#define CFG_ENABLE_RX_STBC_DEFAULT (1) + +#define CFG_ENABLE_TX_STBC "gEnableTXSTBC" +#define CFG_ENABLE_TX_STBC_MIN (0) +#define CFG_ENABLE_TX_STBC_MAX (1) +#define CFG_ENABLE_TX_STBC_DEFAULT (0) + +#define CFG_ENABLE_RX_LDPC "gEnableRXLDPC" +#define CFG_ENABLE_RX_LDPC_MIN (0) +#define CFG_ENABLE_RX_LDPC_MAX (1) +#define CFG_ENABLE_RX_LDPC_DEFAULT (0) + +/* + * Enable/Disable vsta based on MAX Assoc limit + * defined in WCNSS_qcom_cfg.ini. + */ +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define CFG_VSTA_SUPPORT_ENABLE "gEnableVSTASupport" +#define CFG_VSTA_SUPPORT_ENABLE_MIN (0) +#define CFG_VSTA_SUPPORT_ENABLE_MAX (1) +#define CFG_VSTA_SUPPORT_ENABLE_DEFAULT (0) +#endif + +#ifdef FEATURE_WLAN_TDLS +#define CFG_TDLS_SUPPORT_ENABLE "gEnableTDLSSupport" +#define CFG_TDLS_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_SUPPORT_ENABLE_DEFAULT (0) + +#define CFG_TDLS_IMPLICIT_TRIGGER "gEnableTDLSImplicitTrigger" +#define CFG_TDLS_IMPLICIT_TRIGGER_MIN (0) +#define CFG_TDLS_IMPLICIT_TRIGGER_MAX (1) +#define CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT (0) + +#define CFG_TDLS_TX_STATS_PERIOD "gTDLSTxStatsPeriod" +#define CFG_TDLS_TX_STATS_PERIOD_MIN (10) +#define CFG_TDLS_TX_STATS_PERIOD_MAX (4294967295UL) +#define CFG_TDLS_TX_STATS_PERIOD_DEFAULT (5000) + +#define CFG_TDLS_TX_PACKET_THRESHOLD "gTDLSTxPacketThreshold" +#define CFG_TDLS_TX_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_TX_PACKET_THRESHOLD_MAX (4294967295UL) +#define CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT (100) + +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT "gTDLSMaxDiscoveryAttempt" +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN (1) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX (100) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT (5) + +#define CFG_TDLS_IDLE_PACKET_THRESHOLD "gTDLSIdlePacketThreshold" +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX (40000) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT (5) + +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD "gTDLSRSSITriggerThreshold" +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT (-75) + +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD "gTDLSRSSITeardownThreshold" +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT (-75) + +#define CFG_TDLS_RSSI_DELTA "gTDLSRSSIDelta" +#define CFG_TDLS_RSSI_DELTA_MIN (-30) +#define CFG_TDLS_RSSI_DELTA_MAX (0) +#define CFG_TDLS_RSSI_DELTA_DEFAULT (-20) + +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_NAME "gTDLSUapsdMask" /* ACs to setup U-APSD for TDLS Sta */ +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN (0) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX (0x0F) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT (0x0F) + +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE "gEnableTDLSBufferSta" +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX (1) +/* Buffer STA is not enabled in CLD 2.0 yet */ +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT (1) + +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME "gTDLSPuapsdInactivityTime" +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN (0) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX (10) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT (0) + +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD "gTDLSPuapsdRxFrameThreshold" +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN (10) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX (20) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT (10) + +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW "gTDLSPuapsdPTIWindow" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN (1) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX (5) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT (2) + +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT "gTDLSPuapsdPTRTimeout" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN (0) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX (10000) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT (5000) + +#define CFG_TDLS_EXTERNAL_CONTROL "gTDLSExternalControl" +#define CFG_TDLS_EXTERNAL_CONTROL_MIN (0) +#define CFG_TDLS_EXTERNAL_CONTROL_MAX (1) +#define CFG_TDLS_EXTERNAL_CONTROL_DEFAULT (0) + +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE "gEnableTDLSOffChannel" +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT (0) + +#define CFG_TDLS_WMM_MODE_ENABLE "gEnableTDLSWmmMode" +#define CFG_TDLS_WMM_MODE_ENABLE_MIN (0) +#define CFG_TDLS_WMM_MODE_ENABLE_MAX (1) +#define CFG_TDLS_WMM_MODE_ENABLE_DEFAULT (1) + +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM "gTDLSPrefOffChanNum" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN (1) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX (165) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT (36) + +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW "gTDLSPrefOffChanBandwidth" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN (0) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX (0x0F) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT (0x07) + +/* Enable TDLS Scan: Allow scan and maintain TDLS link. + * 0: If peer is not buffer STA capable and device is not sleep STA + * capable, then teardown TDLS link when scan is initiated. If peer + * is buffer STA and we can be sleep STA then TDLS link is maintained + * during scan. + * 1: Maintain TDLS link and allow scan even if peer is not buffer STA + * capable and device is not sleep STA capable. There will be loss of + * Rx pkts since peer would not know when device moves away from tdls + * channel. Tx on TDLS link would stop when device moves away from tdls + * channel. + */ +#define CFG_TDLS_SCAN_ENABLE "gEnableTDLSScan" +#define CFG_TDLS_SCAN_ENABLE_MIN (0) +#define CFG_TDLS_SCAN_ENABLE_MAX (1) +#define CFG_TDLS_SCAN_ENABLE_DEFAULT (0) +#endif + +/* Enable/Disable LPWR Image(cMEM uBSP) Transition */ +#define CFG_ENABLE_LPWR_IMG_TRANSITION_NAME "gEnableLpwrImgTransition" +#define CFG_ENABLE_LPWR_IMG_TRANSITION_MIN (0) +#define CFG_ENABLE_LPWR_IMG_TRANSITION_MAX (1) +#define CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT (0) + +/* + * Scan Aging timeout value in seconds + */ +#define CFG_SCAN_AGING_PARAM_NAME "gScanAgingTime" +#define CFG_SCAN_AGING_PARAM_MIN (0) +#define CFG_SCAN_AGING_PARAM_MAX (200) +#define CFG_SCAN_AGING_PARAM_DEFAULT (60) + +/* Config Param to enable the txLdpc capability + * 0 - disable + * 1 - HT LDPC enable + * 2 - VHT LDPC enable + * 3 - HT & VHT LDPC enable */ +#define CFG_TX_LDPC_ENABLE_FEATURE "gTxLdpcEnable" +#define CFG_TX_LDPC_ENABLE_FEATURE_MIN (0) +#define CFG_TX_LDPC_ENABLE_FEATURE_MAX (3) +#define CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT (0) + +/* + * Enable / Disable MCC Adaptive Scheduler feature + * Default: Enable + */ +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME "gEnableMCCAdaptiveScheduler" +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT (1) + +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE "gTxBFEnable" +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF) + +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED "gTxBFCsnValue" +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX - 1) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX - 1) + +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ "gEnableTxBFin20MHz" +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN (0) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX (1) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT (0) + +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER "gEnableTxSUBeamformer" +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN (0) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX (1) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT (0) + +/* Enable debug for remain on channel issues */ +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME "gDebugP2pRemainOnChannel" +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX (1) + +/* + * SAP ALLOW All Channels + */ +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME "gSapAllowAllChannel" +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN (0) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX (1) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT (0) + +#ifdef WLAN_FEATURE_11AC +#define CFG_DISABLE_LDPC_WITH_TXBF_AP "gDisableLDPCWithTxbfAP" +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN (0) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX (1) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT (0) +#endif + +/* + * IBSS Operating Channels for 2.4G and 5GHz channels + */ +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME "gAdHocChannel5G" +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN (36) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX (165) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT (44) + +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME "gAdHocChannel24G" +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN (1) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX (14) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT (6) + +/* Parameter to control VHT support in 2.4 GHz band */ +#define CFG_ENABLE_VHT_FOR_24GHZ_NAME "gEnableVhtFor24GHzBand" +#define CFG_ENABLE_VHT_FOR_24GHZ_MIN (0) +#define CFG_ENABLE_VHT_FOR_24GHZ_MAX (1) +#define CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT (0) + +#define CFG_MAX_MEDIUM_TIME "gMaxMediumTime" +#define CFG_MAX_MEDIUM_TIME_STAMIN WNI_CFG_MAX_MEDIUM_TIME_STAMIN +#define CFG_MAX_MEDIUM_TIME_STAMAX WNI_CFG_MAX_MEDIUM_TIME_STAMAX +#define CFG_MAX_MEDIUM_TIME_STADEFAULT WNI_CFG_MAX_MEDIUM_TIME_STADEF + +/* + * Enable legacy fast roaming (LFR) on STA link during concurrent sessions + */ +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY "gEnableFastRoamInConcurrency" +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN (0) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX (1) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT (1) + +/* + * FlexConnectPowerFactor parameter + * Default: Disable (0) + */ +#define CFG_FLEX_CONNECT_POWER_FACTOR_NAME "gFlexConnectPowerFactor" +#define CFG_FLEX_CONNECT_POWER_FACTOR_MIN (0) +#define CFG_FLEX_CONNECT_POWER_FACTOR_MAX (9) +#define CFG_FLEX_CONNECT_POWER_FACTOR_DEFAULT (0) + +/* + * Enable heart beat monitoring offload to FW + */ +#define CFG_ENABLE_HEART_BEAT_OFFLOAD "gEnableIbssHeartBeatOffload" +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_MIN (0) +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_MAX (1) +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_DEFAULT (1) + +#define CFG_ANTENNA_DIVERSITY_PARAM_NAME "gAntennaDiversity" +#define CFG_ANTENNA_DIVERSITY_PARAM_MIN (0) +#define CFG_ANTENNA_DIVERSITY_PARAM_MAX (3) +#define CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT (0) + +#define CFG_ENABLE_SNR_MONITORING_NAME "gEnableSNRMonitoring" +#define CFG_ENABLE_SNR_MONITORING_MIN (0) +#define CFG_ENABLE_SNR_MONITORING_MAX (1) +#define CFG_ENABLE_SNR_MONITORING_DEFAULT (0) + +#ifdef FEATURE_WLAN_SCAN_PNO +#define CFG_PNO_SCAN_SUPPORT "gPNOScanSupport" +#define CFG_PNO_SCAN_SUPPORT_ENABLE (1) +#define CFG_PNO_SCAN_SUPPORT_DISABLE (0) +#define CFG_PNO_SCAN_SUPPORT_DEFAULT (1) + +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE "gPNOScanTimerRepeatValue" +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT (6) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN (0) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX (0xffffffff) +#endif + +#define CFG_AMSDU_SUPPORT_IN_AMPDU_NAME "gAmsduSupportInAMPDU" +#define CFG_AMSDU_SUPPORT_IN_AMPDU_MIN (0) +#define CFG_AMSDU_SUPPORT_IN_AMPDU_MAX (1) +#define CFG_AMSDU_SUPPORT_IN_AMPDU_DEFAULT (0) /* disabled */ + +/* Prefer connecting to 5G AP even if its RSSI is lower by + gSelect5GHzMargin dBm than 2.4G AP. + This feature requires the dependent cfg.ini "gRoamPrefer5GHz" set to 1 */ +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN "gSelect5GHzMargin" +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN (0) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX (60) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT (0) /* set 0 to disable */ + +/* It enables IP, TCP and UDP checksum offload in hardware + * and also advertise same to network stack. + */ +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD "gEnableIpTcpUdpChecksumOffload" +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE (0) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE (1) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT (CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE) + +/* + * Power Save Offload + * Power Save Offload configuration: + * Current values of gEnablePowerSaveOffload: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + */ +#define CFG_POWERSAVE_OFFLOAD_NAME "gEnablePowerSaveOffload" +#define CFG_POWERSAVE_OFFLOAD_MIN (0) +#define CFG_POWERSAVE_OFFLOAD_MAX (PS_DUTY_CYCLING_QPOWER) +#define CFG_POWERSAVE_OFFLOAD_DEFAULT (CFG_POWERSAVE_OFFLOAD_MIN) + +#ifdef WLAN_FEATURE_FASTPATH +#define CFG_ENABLE_FASTPATH "gEnableFastPath" +#define CFG_ENABLE_FASTPATH_MIN (0) +#define CFG_ENABLE_FASTPATH_MAX (1) +#define CFG_ENABLE_FASTPATH_DEFAULT (CFG_ENABLE_FASTPATH_MIN) +#endif /* WLAN_FEATURE_FASTPATH */ + +/* + * IPA Offload configuration - Each bit enables a feature + * bit0 - IPA Enable + * bit1 - IPA Pre filter enable + * bit2 - IPv6 enable + * bit3 - IPA Resource Manager (RM) enable + * bit4 - IPA Clock scaling enable + */ +#define CFG_IPA_OFFLOAD_CONFIG_NAME "gIPAConfig" +#define CFG_IPA_OFFLOAD_CONFIG_MIN (0) +#define CFG_IPA_OFFLOAD_CONFIG_MAX (0xFFFFFFFF) +#define CFG_IPA_OFFLOAD_CONFIG_DEFAULT (CFG_IPA_OFFLOAD_CONFIG_MIN) + +/* + * IPA DESC SIZE + */ +#define CFG_IPA_DESC_SIZE_NAME "gIPADescSize" +#define CFG_IPA_DESC_SIZE_MIN (800) +#define CFG_IPA_DESC_SIZE_MAX (8000) +#define CFG_IPA_DESC_SIZE_DEFAULT (800) + +#define CFG_IPA_HIGH_BANDWIDTH_MBPS "gIPAHighBandwidthMbps" +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN (200) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX (1000) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT (400) + +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS "gIPAMediumBandwidthMbps" +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN (100) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX (400) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT (200) + +#define CFG_IPA_LOW_BANDWIDTH_MBPS "gIPALowBandwidthMbps" +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MIN (0) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MAX (100) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT (100) + +/* + * Firmware uart print + */ +#define CFG_ENABLE_FW_UART_PRINT_NAME "gEnablefwprint" +#define CFG_ENABLE_FW_UART_PRINT_DISABLE (0) +#define CFG_ENABLE_FW_UART_PRINT_ENABLE (1) +#define CFG_ENABLE_FW_UART_PRINT_DEFAULT (CFG_ENABLE_FW_UART_PRINT_DISABLE) + +/* + * Firmware log + */ +#define CFG_ENABLE_FW_LOG_NAME "gEnablefwlog" +#define CFG_ENABLE_FW_LOG_DISABLE (0) +#define CFG_ENABLE_FW_LOG_ENABLE (1) +#define CFG_ENABLE_FW_LOG_DEFAULT (CFG_ENABLE_FW_LOG_DISABLE) + +/* + * Enable/Disable SSR for USB + */ +#define CFG_ENABLE_FW_SELF_RECOVERY_NAME "gEnableFwSelfRecovery" +#define CFG_ENABLE_FW_SELF_RECOVERY_DISABLE (0) +#define CFG_ENABLE_FW_SELF_RECOVERY_ENABLE (1) +#define CFG_ENABLE_FW_SELF_RECOVERY_DEFAULT (CFG_ENABLE_FW_SELF_RECOVERY_DISABLE) + +#ifdef WLAN_FEATURE_11AC +/* Macro to handle maximum receive AMPDU size configuration */ +#define CFG_VHT_AMPDU_LEN_EXPONENT_NAME "gVhtAmpduLenExponent" +#define CFG_VHT_AMPDU_LEN_EXPONENT_MIN (0) +#define CFG_VHT_AMPDU_LEN_EXPONENT_MAX (7) +#define CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT (3) + +#define CFG_VHT_MPDU_LEN_NAME "gVhtMpduLen" +#define CFG_VHT_MPDU_LEN_MIN (0) +#define CFG_VHT_MPDU_LEN_MAX (2) +#define CFG_VHT_MPDU_LEN_DEFAULT (0) +#endif + +#define CFG_MAX_WOW_FILTERS_NAME "gMaxWoWFilters" +#define CFG_MAX_WOW_FILTERS_MIN (0) +#define CFG_MAX_WOW_FILTERS_MAX (WOW_MAX_BITMAP_FILTERS) +#define CFG_MAX_WOW_FILTERS_DEFAULT (WOW_MAX_BITMAP_FILTERS) + +/* + * WOW Enable/Disable. + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic patter and pattern byte match on all interfaces. + */ +#define CFG_WOW_STATUS_NAME "gEnableWoW" +#define CFG_WOW_ENABLE_MIN (0) +#define CFG_WOW_ENABLE_MAX (3) +#define CFG_WOW_STATUS_DEFAULT (3) + +#define CFG_COALESING_IN_IBSS_NAME "gCoalesingInIBSS" +#define CFG_COALESING_IN_IBSS_MIN (0) +#define CFG_COALESING_IN_IBSS_MAX (1) +#define CFG_COALESING_IN_IBSS_DEFAULT (0) /* disabled */ + +#define CFG_IBSS_ATIM_WIN_SIZE_NAME "gIbssATIMWinSize" +#define CFG_IBSS_ATIM_WIN_SIZE_MIN (0) +#define CFG_IBSS_ATIM_WIN_SIZE_MAX (50) +#define CFG_IBSS_ATIM_WIN_SIZE_DEFAULT (0) + +/* + * Indicates if IBSS Power Save is + * supported or not. When not allowed, + * IBSS station has to stay awake all + * the time and should never set PM=1 + * in its transmitted frames. This + * parameter is meaningful/valid only + * when gIbssATIMWinSize is non-zero + */ +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME "gIbssIsPowerSaveAllowed" +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT (1) + +/* + * Indicates if IBSS Power Collapse + * is allowed or not. + */ +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME "gIbssIsPowerCollapseAllowed" +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT (1) + +/* + * This parameter indicates whether IBSS station + * can exit power save mode and enter power active + * state whenever there is a TX/RX activity. + */ +#define CFG_IBSS_AWAKE_ON_TX_RX_NAME "gIbssAwakeOnTxRx" +#define CFG_IBSS_AWAKE_ON_TX_RX_MIN (0) +#define CFG_IBSS_AWAKE_ON_TX_RX_MAX (1) +#define CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT (0) + +/* + * In IBSS mode if Awake on TX/RX activity is enabled + * Ibss Inactivity parameter indicates the data + * inactivity time in number of beacon intervals + * after which IBSS station re-inters power save + * by sending Null frame with PM=1 + */ +#define CFG_IBSS_INACTIVITY_TIME_NAME "gIbssInactivityTime" +#define CFG_IBSS_INACTIVITY_TIME_MIN (1) +#define CFG_IBSS_INACTIVITY_TIME_MAX (10) +#define CFG_IBSS_INACTIVITY_TIME_DEFAULT (1) + +/* + * In IBSS mode Tx Service Period Inactivity + * time in msecs indicates the time after + * which TX Service Period is terminated by + * sending a Qos Null frame with EOSP. + * If value is 0, TX SP is terminated with the + * last buffered packet itself instead of waiting + * for the inactivity + */ +#define CFG_IBSS_TXSP_END_INACTIVITY_NAME "gIbssTxSpEndInactivityTime" +#define CFG_IBSS_TXSP_END_INACTIVITY_MIN (0) +#define CFG_IBSS_TXSP_END_INACTIVITY_MAX (100) +#define CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT (0) + +/* + * When IBSS network is initialized, PS-supporting device + * does not enter protocol sleep state during first + * gIbssPsWarmupTime seconds. + */ +#define CFG_IBSS_PS_WARMUP_TIME_NAME "gIbssPsWarmupTime" +#define CFG_IBSS_PS_WARMUP_TIME_MIN (0) +/* Allow unsigned Int Max for now */ +#define CFG_IBSS_PS_WARMUP_TIME_MAX (65535) +#define CFG_IBSS_PS_WARMUP_TIME_DEFAULT (0) + +/* + * IBSS Power Save Enable/Disable 1 RX + * chain usage during the ATIM window + */ +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME "gIbssPs1RxChainInAtim" +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN (0) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX (1) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT (0) + +#define CFG_SAP_MAX_NO_PEERS "gSoftApMaxPeers" +#define CFG_SAP_MAX_NO_PEERS_MIN (1) +#define CFG_SAP_MAX_NO_PEERS_MAX (32) +#define CFG_SAP_MAX_NO_PEERS_DEFAULT (32) + +/* + * Connection related log Enable/Disable. + * 0x1 - Enable mgmt pkt logs (no probe req/rsp). + * 0x2 - Enable EAPOL pkt logs. + * 0x4 - Enable DHCP pkt logs. + * 0x0 - Disable all the above connection related logs. + */ +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE "gEnableDebugLog" +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN (0) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX (0xFF) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT (0) + +/* This will be used only for debugging purpose, will be removed after sometime */ +#define CFG_ENABLE_RX_THREAD "gEnableRxThread" +#define CFG_ENABLE_RX_THREAD_MIN (0) +#define CFG_ENABLE_RX_THREAD_MAX (1) +#define CFG_ENABLE_RX_THREAD_DEFAULT (1) + +/* SAR Thermal limit values for 2g and 5g */ + +#define CFG_SET_TXPOWER_LIMIT2G_NAME "TxPower2g" +#define CFG_SET_TXPOWER_LIMIT2G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT2G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT2G_DEFAULT (15) + +#define CFG_SET_TXPOWER_LIMIT5G_NAME "TxPower5g" +#define CFG_SET_TXPOWER_LIMIT5G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT5G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT5G_DEFAULT (15) + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define CFG_LL_TX_FLOW_LWM "TxFlowLowWaterMark" +#define CFG_LL_TX_FLOW_LWM_MIN (0) +#define CFG_LL_TX_FLOW_LWM_MAX (1000) + +#define CFG_LL_TX_FLOW_LWM_DEFAULT (300) + +#define CFG_LL_TX_FLOW_HWM_OFFSET "TxFlowHighWaterMarkOffset" +#define CFG_LL_TX_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_HWM_OFFSET_MAX (300) + +#define CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT (94) + +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH "TxFlowMaxQueueDepth" +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT (1500) + +#define CFG_LL_TX_LBW_FLOW_LWM "TxLbwFlowLowWaterMark" +#define CFG_LL_TX_LBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_LBW_FLOW_LWM_MAX (1000) + +#define CFG_LL_TX_LBW_FLOW_LWM_DEFAULT (450) + +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET "TxLbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX (300) + +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT (50) + +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH "TxLbwFlowMaxQueueDepth" +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT (750) + +#define CFG_LL_TX_HBW_FLOW_LWM "TxHbwFlowLowWaterMark" +#define CFG_LL_TX_HBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_HBW_FLOW_LWM_MAX (1000) + +#define CFG_LL_TX_HBW_FLOW_LWM_DEFAULT (406) + +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET "TxHbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX (300) + +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT (94) + +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH "TxHbwFlowMaxQueueDepth" +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT (1500) +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH "TxFlowStopQueueThreshold" +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT (15) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN (0) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX (50) + +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET "TxFlowStartQueueOffset" +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT (10) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX (30) + +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ + +#define CFG_SAP_MAX_OFFLOAD_PEERS "gMaxOffloadPeers" +#define CFG_SAP_MAX_OFFLOAD_PEERS_MIN (2) +#define CFG_SAP_MAX_OFFLOAD_PEERS_MAX (5) +#define CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT (2) + +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS "gMaxOffloadReorderBuffs" +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN (0) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX (3) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT (2) + +#ifdef FEATURE_WLAN_RA_FILTERING +#define CFG_RA_FILTER_ENABLE_NAME "gRAFilterEnable" +#define CFG_RA_FILTER_ENABLE_MIN (0) +#define CFG_RA_FILTER_ENABLE_MAX (1) +#define CFG_RA_FILTER_ENABLE_DEFAULT (0) + +#define CFG_RA_RATE_LIMIT_INTERVAL_NAME "gRArateLimitInterval" +#define CFG_RA_RATE_LIMIT_INTERVAL_MIN (60) +#define CFG_RA_RATE_LIMIT_INTERVAL_MAX (3600) +#define CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT (60) /*60 SEC */ +#endif + +#define CFG_IGNORE_PEER_ERP_INFO_NAME "gIgnorePeerErpInfo" +#define CFG_IGNORE_PEER_ERP_INFO_MIN (0) +#define CFG_IGNORE_PEER_ERP_INFO_MAX (1) +#define CFG_IGNORE_PEER_ERP_INFO_DEFAULT (0) + +/* Enable Memory Debug */ +#ifdef MEMORY_DEBUG +#define CFG_ENABLE_MEMORY_DEBUG_NAME "gEnableMemoryDebug" +#define CFG_ENABLE_MEMORY_DEBUG_MIN (0) +#define CFG_ENABLE_MEMORY_DEBUG_MAX (1) +#define CFG_ENABLE_MEMORY_DEBUG_DEFAULT (1) +#endif + +#define CFG_INITIAL_DWELL_TIME_NAME "gInitialDwellTime" +#define CFG_INITIAL_DWELL_TIME_DEFAULT (0) +#define CFG_INITIAL_DWELL_TIME_MIN (0) +#define CFG_INITIAL_DWELL_TIME_MAX (100) + +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME "gInitialScanNoDFSChnl" +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX (1) + +#define CFG_ROAMING_DFS_CHANNEL_NAME "gAllowDFSChannelRoam" +#define CFG_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) +#define CFG_ROAMING_DFS_CHANNEL_MIN (CFG_ROAMING_DFS_CHANNEL_DISABLED) +#define CFG_ROAMING_DFS_CHANNEL_MAX (CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE) +#define CFG_ROAMING_DFS_CHANNEL_DEFAULT (CFG_ROAMING_DFS_CHANNEL_DISABLED) + +#ifdef MSM_PLATFORM +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD "gBusBandwidthHighThreshold" +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT (2000) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD "gBusBandwidthMediumThreshold" +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT (500) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD "gBusBandwidthLowThreshold" +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT (150) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL "gBusBandwidthComputeInterval" +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT (100) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN (0) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX (10000) + +#define CFG_TCP_DELACK_THRESHOLD_HIGH "gTcpDelAckThresholdHigh" +#define CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT (500) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MAX (16000) + +#define CFG_TCP_DELACK_THRESHOLD_LOW "gTcpDelAckThresholdLow" +#define CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT (1000) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MAX (10000) +#endif /* MSM_PLATFORM */ + +#ifdef WLAN_FEATURE_11W +#define CFG_PMF_SA_QUERY_MAX_RETRIES_NAME "pmfSaQueryMaxRetries" +#define CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT (5) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MIN (0) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MAX (20) + +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME "pmfSaQueryRetryInterval" +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT (200) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN (0) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX (2000) +#endif + +#define CFG_MAX_CONCURRENT_CONNECTIONS_NAME "gMaxConcurrentActiveSessions" +#define CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT (2) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MIN (1) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MAX (4) + +#define CFG_IGNORE_CAC_NAME "gIgnoreCAC" +#define CFG_IGNORE_CAC_MIN (0) +#define CFG_IGNORE_CAC_MAX (1) +#define CFG_IGNORE_CAC_DEFAULT (0) + +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_NAME "gEnableSAPDfsChSifsBurst" +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MIN (0) +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MAX (1) +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_DEFAULT (1) + +#define CFG_DFS_RADAR_PRI_MULTIPLIER_NAME "gDFSradarMappingPriMultiplier" +#define CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT (4) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MIN (0) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MAX (10) +#define CFG_REORDER_OFFLOAD_SUPPORT_NAME "gReorderOffloadSupported" +#define CFG_REORDER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_REORDER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT (0) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define CFG_ROAMING_OFFLOAD_NAME "gRoamOffloadEnabled" +#define CFG_ROAMING_OFFLOAD_MIN (0) +#define CFG_ROAMING_OFFLOAD_MAX (1) +#define CFG_ROAMING_OFFLOAD_DEFAULT (0) +#endif + +#define CFG_IPA_UC_TX_BUF_COUNT_NAME "IpaUcTxBufCount" +#define CFG_IPA_UC_TX_BUF_COUNT_MIN (0) +#define CFG_IPA_UC_TX_BUF_COUNT_MAX (2048) +#define CFG_IPA_UC_TX_BUF_COUNT_DEFAULT (512) + +#define CFG_IPA_UC_TX_BUF_SIZE_NAME "IpaUcTxBufSize" +#define CFG_IPA_UC_TX_BUF_SIZE_MIN (0) +#define CFG_IPA_UC_TX_BUF_SIZE_MAX (4096) +#define CFG_IPA_UC_TX_BUF_SIZE_DEFAULT (2048) + +#define CFG_IPA_UC_RX_IND_RING_COUNT_NAME "IpaUcRxIndRingCount" +#define CFG_IPA_UC_RX_IND_RING_COUNT_MIN (0) +#define CFG_IPA_UC_RX_IND_RING_COUNT_MAX (2048) +#define CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT (1024) + +#define CFG_IPA_UC_TX_PARTITION_BASE_NAME "IpaUcTxPartitionBase" +#define CFG_IPA_UC_TX_PARTITION_BASE_MIN (0) +#define CFG_IPA_UC_TX_PARTITION_BASE_MAX (9000) +#define CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT (3000) + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/* Enable WLAN Logging to app space */ +#define CFG_WLAN_LOGGING_SUPPORT_NAME "wlanLoggingEnable" +#define CFG_WLAN_LOGGING_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_SUPPORT_DEFAULT (1) + +/* Enable FATAL and ERROR logs for kmsg console */ +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME "wlanLoggingFEToConsole" +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT (1) + +/* Number of buffers to be used for WLAN logging */ +#define CFG_WLAN_LOGGING_NUM_BUF_NAME "wlanLoggingNumBuf" +#define CFG_WLAN_LOGGING_NUM_BUF_MIN (4) +#define CFG_WLAN_LOGGING_NUM_BUF_MAX (512) +#define CFG_WLAN_LOGGING_NUM_BUF_DEFAULT (256) +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#define CFG_ENABLE_SIFS_BURST "gEnableSifsBurst" +#define CFG_ENABLE_SIFS_BURST_MIN (0) +#define CFG_ENABLE_SIFS_BURST_MAX (1) +#define CFG_ENABLE_SIFS_BURST_DEFAULT (0) + +#ifdef WLAN_FEATURE_LPSS +#define CFG_ENABLE_LPASS_SUPPORT "gEnableLpassSupport" +#define CFG_ENABLE_LPASS_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_LPASS_SUPPORT_MIN (0) +#define CFG_ENABLE_LPASS_SUPPORT_MAX (1) +#endif + +/* + * NaN feature support configuration + * gEnableNanSupport = 0 means NaN is not supported + * gEnableNanSupport = 1 means NaN is supported + */ +#ifdef WLAN_FEATURE_NAN +#define CFG_ENABLE_NAN_SUPPORT "gEnableNanSupport" +#define CFG_ENABLE_NAN_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_NAN_SUPPORT_MIN (0) +#define CFG_ENABLE_NAN_SUPPORT_MAX (1) +#endif + +#define CFG_ENABLE_SELF_RECOVERY "gEnableSelfRecovery" +#define CFG_ENABLE_SELF_RECOVERY_MIN (0) +#define CFG_ENABLE_SELF_RECOVERY_MAX (1) +#define CFG_ENABLE_SELF_RECOVERY_DEFAULT (0) + +#define CFG_ENABLE_SAP_SUSPEND "gEnableSapSuspend" +#define CFG_ENABLE_SAP_SUSPEND_MIN (0) +#define CFG_ENABLE_SAP_SUSPEND_MAX (1) +#define CFG_ENABLE_SAP_SUSPEND_DEFAULT (1) + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define CFG_EXTWOW_GO_TO_SUSPEND "gExtWoWgotoSuspend" +#define CFG_EXTWOW_GO_TO_SUSPEND_MIN (0) +#define CFG_EXTWOW_GO_TO_SUSPEND_MAX (1) +#define CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT (1) + +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER "gExtWowApp1WakeupPinNumber" +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT (12) + +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER "gExtWowApp2WakeupPinNumber" +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT (16) + +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL "gExtWoWApp2KAInitPingInterval" +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT (240) + +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL "gExtWoWApp2KAMinPingInterval" +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT (240) + +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL "gExtWoWApp2KAMaxPingInterval" +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT (1280) + +#define CFG_EXTWOW_KA_INC_PING_INTERVAL "gExtWoWApp2KAIncPingInterval" +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT (4) + +#define CFG_EXTWOW_TCP_SRC_PORT "gExtWoWApp2TcpSrcPort" +#define CFG_EXTWOW_TCP_SRC_PORT_MIN (0) +#define CFG_EXTWOW_TCP_SRC_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_SRC_PORT_DEFAULT (5000) + +#define CFG_EXTWOW_TCP_DST_PORT "gExtWoWApp2TcpDstPort" +#define CFG_EXTWOW_TCP_DST_PORT_MIN (0) +#define CFG_EXTWOW_TCP_DST_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_DST_PORT_DEFAULT (5001) + +#define CFG_EXTWOW_TCP_TX_TIMEOUT "gExtWoWApp2TcpTxTimeout" +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT (200) + +#define CFG_EXTWOW_TCP_RX_TIMEOUT "gExtWoWApp2TcpRxTimeout" +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT (200) +#endif + +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME "gEnableDeauthToDisassocMap" +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN (0) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX (1) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT (0) + +#ifdef DHCP_SERVER_OFFLOAD +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME "gDHCPServerOffloadEnable" +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN) + +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME "gDHCPMaxNumClients" +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN (1) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX (8) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX) + +#define CFG_DHCP_SERVER_IP_NAME "gDHCPServerIP" +#define CFG_DHCP_SERVER_IP_DEFAULT "" +#endif /* DHCP_SERVER_OFFLOAD */ + +/* + * If last disconnection was due to HB failure and we reconnect + * to same AP next time, send Deauth before starting connection + */ +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION "gSendDeauthBeforeCon" +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN (0) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX (1) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT (0) + +/* + * Custom concurrency rule1: + * If SAP comes up first and STA comes up later then SAP + * needs to follow STA's channel. + */ +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME "gEnableCustomConcRule1" +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT (0) + +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME "gEnableCustomConcRule2" +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT (0) + +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ "gEnableStaConnectionIn5Ghz" +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN (0) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX (1) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT (1) + +#define CFG_ENABLE_MAC_ADDR_SPOOFING "gEnableMacAddrSpoof" +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MIN (0) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MAX (1) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT (1) + +#define CFG_P2P_LISTEN_DEFER_INTERVAL_NAME "gP2PListenDeferInterval" +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MIN (100) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MAX (200) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_DEFAULT (100) + +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL "gStaMiracastMccRestTimeVal" +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN (100) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX (500) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT (400) + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_NAME "gSapChannelAvoidance" +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN (0) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX (1) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT (0) +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#define CFG_SAP_P2P_11AC_OVERRIDE_NAME "gAP11ACOverride" +#define CFG_SAP_P2P_11AC_OVERRIDE_MIN (0) +#define CFG_SAP_P2P_11AC_OVERRIDE_MAX (1) +#define CFG_SAP_P2P_11AC_OVERRIDE_DEFAULT (1) + +#define CFG_SAP_DOT11MC "gSapDot11mc" +#define CFG_SAP_DOT11MC_MIN (0) +#define CFG_SAP_DOT11MC_MAX (1) +#define CFG_SAP_DOT11MC_DEFAULT (0) + +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR "gPreferNonDfsChanOnRadar" +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN (0) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX (1) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT (0) + +#define CFG_MULTICAST_HOST_FW_MSGS "gMulticastHostFwMsgs" +#define CFG_MULTICAST_HOST_FW_MSGS_MIN (0) +#define CFG_MULTICAST_HOST_FW_MSGS_MAX (1) +#define CFG_MULTICAST_HOST_FW_MSGS_DEFAULT (1) + +/* + * wlan system preference option to help policy manager decide + * on Preferred Channel List for a new connection. For possible + * values refer to enum hdd_conc_priority_mode + */ +#define CFG_CONC_SYSTEM_PREF "gSystemPref" +#define CFG_CONC_SYSTEM_PREF_MIN (0) +#define CFG_CONC_SYSTEM_PREF_MAX (2) +#define CFG_CONC_SYSTEM_PREF_DEFAULT (0) + +#define CFG_POLICY_MNGR_ENABLE "gPolicyManagerEnable" +#define CFG_POLICY_MNGR_ENABLE_MIN (0) +#define CFG_POLICY_MNGR_ENABLE_MAX (1) +#define CFG_POLICY_MNGR_ENABLE_DEFAULT (1) + +#define CFG_TSO_ENABLED_NAME "TSOEnable" +#define CFG_TSO_ENABLED_MIN (0) +#define CFG_TSO_ENABLED_MAX (1) +#define CFG_TSO_ENABLED_DEFAULT (0) + +/* + * Configuration option to enable or disable LRO (Large Receive Offload) + * in the WLAN driver + * Set 1 - enable, 0 - disable + */ +#define CFG_LRO_ENABLED_NAME "LROEnable" +#define CFG_LRO_ENABLED_MIN (0) +#define CFG_LRO_ENABLED_MAX (1) +#define CFG_LRO_ENABLED_DEFAULT (0) + +/* + * In static display use case when APPS is in stand alone power save mode enable + * active offload mode which helps FW to filter out MC/BC data packets to avoid + * APPS wake up and save more power. + * + * By default enable active mode offload as it helps to save more power in + * static display usecase(APPS stand alone power collapse). + * + * If active mode offload(gActiveModeOffload=1) is enabled then all applicable + * data offload/filtering is enabled immediately in FW once config is available + * in WLAN driver and FW caches this configuration accross suspend/resume + * + * If active mode offload is disabled(gActiveModeOffload=0) then all applicable + * data offload/filtering is enabled during cfg80211 suspend and disabled + * during cfg80211 resume + * + * Active mode offload feature is bydefault enabled for adrastea and disabled + * for non adrastea targets like ROME + */ + +#define CFG_ACTIVE_MODE_OFFLOAD "gActiveModeOffload" +#define CFG_ACTIVE_MODE_OFFLOAD_MIN (0) +#define CFG_ACTIVE_MODE_OFFLOAD_MAX (1) +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CFG_ACTIVE_MODE_OFFLOAD_DEFAULT (1) +#else +#define CFG_ACTIVE_MODE_OFFLOAD_DEFAULT (0) +#endif + +/* + * 0: disable the cck tx chain mask (default) + * 1: enable the cck tx chain mask + */ +#define CFG_TX_CHAIN_MASK_CCK "gCckChainMaskEnable" +#define CFG_TX_CHAIN_MASK_CCK_MIN (0) +#define CFG_TX_CHAIN_MASK_CCK_MAX (1) +#define CFG_TX_CHAIN_MASK_CCK_DEFAULT (0) + +#define CFG_TX_CHAIN_MASK_1SS "gTxChainMask1ss" +#define CFG_TX_CHAIN_MASK_1SS_MIN (0) +#define CFG_TX_CHAIN_MASK_1SS_MAX (3) +#define CFG_TX_CHAIN_MASK_1SS_DEFAULT (1) + +/* + * set the self gen power value from + * 0 to 0xffff + */ +#define CFG_SELF_GEN_FRM_PWR "gSelfGenFrmPwr" +#define CFG_SELF_GEN_FRM_PWR_MIN (0) +#define CFG_SELF_GEN_FRM_PWR_MAX (0xffff) +#define CFG_SELF_GEN_FRM_PWR_DEFAULT (0) + +/* + * fine timing measurement capability information + * + * <----- fine_time_meas_cap (in bits) -----> + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| 9-31 | 8 | 7 | 5 | 4 | 3 | 2 | 1 | 0 | + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| reserved | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA | + *| |resp |init |resp |init |resp |init |resp |init | + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + * + * resp - responder role; init- initiator role + * + * CFG_FINE_TIME_MEAS_CAPABILITY_MAX computed based on the table + * +-----------------+-----------------+-----------+ + * | Device Role | Initiator | Responder | + * +-----------------+-----------------+-----------+ + * | Station | Y | N | + * | P2P-CLI | Y | Y | + * | P2P-GO | Y | Y | + * | SAP | N | Y | + * +-----------------+-----------------+-----------+ + */ +#define CFG_FINE_TIME_MEAS_CAPABILITY "gfine_time_meas_cap" +#define CFG_FINE_TIME_MEAS_CAPABILITY_MIN (0x0000) +#define CFG_FINE_TIME_MEAS_CAPABILITY_MAX (0x00BD) +#define CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT (0x000D) + +/* + * Maximum number of scans that host can queue at firmware is controlled + * through the configuration item 'max_scan_count'. + * + * Rome - Rome firmware support 8 scan queue size and 4 are reserved + * for internal scan requests like roaming. So host can send 4 + * scan requests. + * + * ihelium - There is no constraint in number of scan queue size at + * firmware but the current uses cases needs support of maximum + * of 4 scan request from host. + */ +#define CFG_MAX_SCAN_COUNT_NAME "max_scan_count" +#define CFG_MAX_SCAN_COUNT_MIN (1) +#define CFG_MAX_SCAN_COUNT_MAX (8) +#define CFG_MAX_SCAN_COUNT_DEFAULT (4) + +/** + * enum dot11p_mode - The 802.11p mode of operation + * @WLAN_HDD_11P_DISABLED: 802.11p mode is disabled + * @WLAN_HDD_11P_STANDALONE: 802.11p-only operation + * @WLAN_HDD_11P_CONCURRENT: 802.11p and WLAN operate concurrently + */ +enum dot11p_mode { + WLAN_HDD_11P_DISABLED = 0, + WLAN_HDD_11P_STANDALONE, + WLAN_HDD_11P_CONCURRENT, +}; + +#define CFG_DOT11P_MODE_NAME "gDot11PMode" +#define CFG_DOT11P_MODE_DEFAULT (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MIN (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MAX (WLAN_HDD_11P_CONCURRENT) + +#define CFG_NAPI_NAME "gEnableNAPI" +#define CFG_NAPI_MIN (0) +#define CFG_NAPI_MAX (1) +#define CFG_NAPI_DEFAULT (0) + +#ifdef FEATURE_WLAN_EXTSCAN +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME "gExtScanPassiveMaxChannelTime" +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN (110) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME "gExtScanPassiveMinChannelTime" +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN (60) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME "gExtScanActiveMaxChannelTime" +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN (40) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME "gExtScanActiveMinChannelTime" +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN (20) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) +#endif + +#define CFG_CE_CLASSIFY_ENABLE_NAME "gCEClassifyEnable" +#define CFG_CE_CLASSIFY_ENABLE_MIN (0) +#define CFG_CE_CLASSIFY_ENABLE_MAX (1) +#define CFG_CE_CLASSIFY_ENABLE_DEFAULT (0) + +#define CFG_DUAL_MAC_FEATURE_DISABLE "gDualMacFeatureDisable" +#define CFG_DUAL_MAC_FEATURE_DISABLE_MIN (0) +#define CFG_DUAL_MAC_FEATURE_DISABLE_MAX (1) +#define CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT (0) + +/* Parameters for roaming scans performed at high RSSI */ + +/* Maximum number of scans after RSSI change */ +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME "gRoamScanHiRssiMaxCount" +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX (10) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT (5) + +/* Change in RSSI at which scan is triggered */ +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_NAME "gRoamScanHiRssiDelta" +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX (16) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT (0) + +/* Delay between consecutive scans in milliseconds */ +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_NAME "gRoamScanHiRssiDelay" +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN (5000) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX (15000) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT (5000) + +/* Upper bound after which scan will not be performed */ +#define CFG_ROAM_SCAN_HI_RSSI_UB_NAME "gRoamScanHiRssiUpperBound" +#define CFG_ROAM_SCAN_HI_RSSI_UB_MIN (-76) +#define CFG_ROAM_SCAN_HI_RSSI_UB_MAX (-30) +#define CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT (-45) + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +struct hdd_config { + /* Bitmap to track what is explicitly configured */ + DECLARE_BITMAP(bExplicitCfg, MAX_CFG_INI_ITEMS); + + /* Config parameters */ + uint32_t RTSThreshold; + uint32_t FragmentationThreshold; + uint8_t OperatingChannel; + bool ShortSlotTimeEnabled; + bool Is11dSupportEnabled; + bool Is11hSupportEnabled; + bool fSupplicantCountryCodeHasPriority; + uint32_t HeartbeatThresh24; + char PowerUsageControl[4]; + bool fIsLogpEnabled; + bool fIsImpsEnabled; + bool is_ps_enabled; + uint32_t nBmpsModListenInterval; + uint32_t nBmpsMaxListenInterval; + uint32_t nBmpsMinListenInterval; + eHddDot11Mode dot11Mode; + uint32_t nChannelBondingMode24GHz; + uint32_t nChannelBondingMode5GHz; + uint32_t MaxRxAmpduFactor; + uint16_t TxRate; + uint32_t ShortGI20MhzEnable; + uint32_t ScanResultAgeCount; + uint32_t nScanAgeTimeNCNPS; + uint32_t nScanAgeTimeNCPS; + uint32_t nScanAgeTimeCNPS; + uint32_t nScanAgeTimeCPS; + uint8_t nRssiCatGap; + bool fIsShortPreamble; + struct cdf_mac_addr IbssBssid; + uint32_t AdHocChannel5G; + uint32_t AdHocChannel24G; + uint8_t intfAddrMask; + struct cdf_mac_addr intfMacAddr[CDF_MAX_CONCURRENCY_PERSONA]; + + bool apUapsdEnabled; + bool apRandomBssidEnabled; + bool apProtEnabled; + uint16_t apProtection; + bool apOBSSProtEnabled; + bool apDisableIntraBssFwd; + uint8_t nEnableListenMode; + uint32_t nAPAutoShutOff; + uint8_t enableLTECoex; + uint32_t apKeepAlivePeriod; + uint32_t goKeepAlivePeriod; + uint32_t apLinkMonitorPeriod; + uint32_t goLinkMonitorPeriod; + uint32_t nBeaconInterval; + uint8_t nTxPowerCap; /* In dBm */ + bool fIsLowGainOverride; + uint8_t disablePacketFilter; +#if defined WLAN_FEATURE_VOWIFI + bool fRrmEnable; + uint8_t nInChanMeasMaxDuration; + uint8_t nOutChanMeasMaxDuration; + uint16_t nRrmRandnIntvl; +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Vowifi 11r params */ + bool fFTResourceReqSupported; +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + uint16_t nNeighborScanPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint8_t delay_before_vdev_stop; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t neighborScanChanList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + uint16_t nMaxNeighborReqTries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +#endif + + /* Additional Handoff params */ + uint32_t nRoamingTime; + uint16_t nVccRssiTrigger; + uint32_t nVccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; + +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + uint8_t nNumStaChanCombinedConc; /* number of channels combined for */ + /* STA in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; /* number of channels combined for */ + /* P2P in each split scan operation */ +#endif + + uint8_t nMaxPsPoll; + + uint8_t nRssiFilterPeriod; + bool fIgnoreDtim; + uint8_t fMaxLIModulatedDTIM; + + uint8_t nRxAnt; + uint8_t fEnableFwHeartBeatMonitoring; + uint8_t fEnableFwBeaconFiltering; + bool fEnableFwRssiMonitoring; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint8_t nDataInactivityTimeout; + + /* WMM QoS Configuration */ + hdd_wmm_user_mode_t WmmMode; + bool b80211eIsEnabled; + uint8_t UapsdMask; /* what ACs to setup U-APSD for at assoc */ + uint32_t InfraUapsdVoSrvIntv; + uint32_t InfraUapsdVoSuspIntv; + uint32_t InfraUapsdViSrvIntv; + uint32_t InfraUapsdViSuspIntv; + uint32_t InfraUapsdBeSrvIntv; + uint32_t InfraUapsdBeSuspIntv; + uint32_t InfraUapsdBkSrvIntv; + uint32_t InfraUapsdBkSuspIntv; +#ifdef FEATURE_WLAN_LFR + bool isFastRoamIniFeatureEnabled; + bool MAWCEnabled; +#endif +#ifdef FEATURE_WLAN_ESE + uint32_t InfraInactivityInterval; + bool isEseIniFeatureEnabled; +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + bool isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool isWESModeEnabled; +#endif +#ifdef FEATURE_WLAN_OKC + bool isOkcIniFeatureEnabled; +#endif + bool isRoamOffloadScanEnabled; + hdd_wmm_classification_t PktClassificationBasis; /* DSCP or 802.1Q */ + bool bImplicitQosEnabled; + + /* default TSPEC parameters for AC_VO */ + sme_QosWmmDirType InfraDirAcVo; + uint16_t InfraNomMsduSizeAcVo; + uint32_t InfraMeanDataRateAcVo; + uint32_t InfraMinPhyRateAcVo; + uint16_t InfraSbaAcVo; + + /* default TSPEC parameters for AC_VI */ + sme_QosWmmDirType InfraDirAcVi; + uint16_t InfraNomMsduSizeAcVi; + uint32_t InfraMeanDataRateAcVi; + uint32_t InfraMinPhyRateAcVi; + uint16_t InfraSbaAcVi; + + /* default TSPEC parameters for AC_BE */ + sme_QosWmmDirType InfraDirAcBe; + uint16_t InfraNomMsduSizeAcBe; + uint32_t InfraMeanDataRateAcBe; + uint32_t InfraMinPhyRateAcBe; + uint16_t InfraSbaAcBe; + + /* default TSPEC parameters for AC_BK */ + sme_QosWmmDirType InfraDirAcBk; + uint16_t InfraNomMsduSizeAcBk; + uint32_t InfraMeanDataRateAcBk; + uint32_t InfraMinPhyRateAcBk; + uint16_t InfraSbaAcBk; + + uint32_t DelayedTriggerFrmInt; + + /* Wowl pattern */ + char wowlPattern[1024]; + + /* Control for Replay counetr. value 1 means + single replay counter for all TID */ + bool bSingleTidRc; + uint8_t mcastBcastFilterSetting; + bool fhostArpOffload; + bool ssdp; +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + bool PnoOffload; +#endif + bool fhostNSOffload; + bool burstSizeDefinition; + uint8_t tsInfoAckPolicy; + + /* RF Settling Time Clock */ + uint32_t rfSettlingTimeUs; + + uint8_t dynamicPsPollValue; + bool AddTSWhenACMIsOff; + bool fValidateScanList; + + uint32_t infraStaKeepAlivePeriod; + uint8_t nNullDataApRespTimeout; + uint8_t nBandCapability; + + uint32_t apDataAvailPollPeriodInMs; + bool fEnableBeaconEarlyTermination; + bool teleBcnWakeupEn; + +/* CDF Trace Control*/ + uint16_t cdf_trace_enable_wdi; + uint16_t cdf_trace_enable_hdd; + uint16_t cdf_trace_enable_sme; + uint16_t cdf_trace_enable_pe; + uint16_t cdf_trace_enable_pmc; + uint16_t cdf_trace_enable_wma; + uint16_t cdf_trace_enable_sys; + uint16_t cdf_trace_enable_cdf; + uint16_t cdf_trace_enable_sap; + uint16_t cdf_trace_enable_hdd_sap; + uint16_t cdf_trace_enable_bmi; + + uint16_t nTeleBcnTransListenInterval; + uint16_t nTeleBcnMaxListenInterval; + uint16_t nTeleBcnTransLiNumIdleBeacons; + uint16_t nTeleBcnMaxLiNumIdleBeacons; + uint8_t bcnEarlyTermWakeInterval; + uint32_t enableCloseLoop; + uint8_t enableBypass11d; + uint8_t enableDFSChnlScan; + uint8_t enable_dfs_pno_chnl_scan; + uint8_t enableDynamicDTIM; + uint8_t enableAutomaticTxPowerControl; + uint8_t ShortGI40MhzEnable; + eHddLinkSpeedReportType reportMaxLinkSpeed; + int32_t linkSpeedRssiHigh; + int32_t linkSpeedRssiMid; + int32_t linkSpeedRssiLow; +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; +#endif + uint8_t enableMCC; + uint8_t allowMCCGODiffBI; + bool isP2pDeviceAddrAdministrated; + uint8_t thermalMitigationEnable; + uint32_t throttlePeriod; + uint8_t vhtChannelWidth; + uint8_t vhtRxMCS; + uint8_t vhtTxMCS; + bool enableTxBF; + uint8_t txBFCsnValue; + bool enable_su_tx_bformer; + uint8_t vhtRxMCS2x2; + uint8_t vhtTxMCS2x2; + bool enable2x2; + bool txchainmask1x1; + bool rxchainmask1x1; + bool enableMuBformee; + bool enableVhtpAid; + bool enableVhtGid; + bool enableTxBFin20MHz; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + uint8_t enableModulatedDTIM; + uint32_t fEnableMCAddrList; + bool enableFirstScan2GOnly; + bool skipDfsChnlInP2pSearch; + bool ignoreDynamicDtimInP2pMode; + bool enableRxSTBC; + bool enableTxSTBC; + bool enableRxLDPC; + bool enable5gEBT; +#ifdef FEATURE_WLAN_TDLS + bool fEnableTDLSSupport; + bool fEnableTDLSImplicitTrigger; + uint32_t fTDLSTxStatsPeriod; + uint32_t fTDLSTxPacketThreshold; + uint32_t fTDLSMaxDiscoveryAttempt; + uint32_t fTDLSIdlePacketThreshold; + int32_t fTDLSRSSITriggerThreshold; + int32_t fTDLSRSSITeardownThreshold; + int32_t fTDLSRSSIDelta; + uint32_t fTDLSUapsdMask; /* what ACs to setup U-APSD for TDLS */ + uint32_t fEnableTDLSBufferSta; + uint32_t fEnableTDLSSleepSta; + uint32_t fTDLSPuapsdInactivityTimer; + uint32_t fTDLSRxFrameThreshold; + uint32_t fTDLSPuapsdPTIWindow; + uint32_t fTDLSPuapsdPTRTimeout; + bool fTDLSExternalControl; + uint32_t fEnableTDLSOffChannel; + uint32_t fEnableTDLSWmmMode; + uint8_t fTDLSPrefOffChanNum; + uint8_t fTDLSPrefOffChanBandwidth; + uint8_t enable_tdls_scan; +#endif +#ifdef WLAN_SOFTAP_VSTA_FEATURE + bool fEnableVSTASupport; +#endif + uint32_t enableLpwrImgTransition; + uint8_t scanAgingTimeout; + bool enableTxLdpc; + uint8_t disableLDPCWithTxbfAP; + uint8_t enableMCCAdaptiveScheduler; + bool isAndroidPsEn; + bool sapAllowAllChannel; + uint8_t retryLimitZero; + uint8_t retryLimitOne; + uint8_t retryLimitTwo; + bool enableSSR; + uint32_t cfgMaxMediumTime; + bool enableVhtFor24GHzBand; + /* Flag indicating whether legacy fast roam during concurrency is enabled in cfg.ini or not */ + bool bFastRoamInConIniFeatureEnabled; + bool fEnableAdaptRxDrain; + uint8_t flexConnectPowerFactor; + bool enableIbssHeartBeatOffload; + uint32_t antennaDiversity; + bool fEnableSNRMonitoring; + /*PNO related parameters */ +#ifdef FEATURE_WLAN_SCAN_PNO + bool configPNOScanSupport; + uint32_t configPNOScanTimerRepeatValue; +#endif + uint8_t isAmsduSupportInAMPDU; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; + + /* IBSS Power Save related parameters */ + uint32_t ibssATIMWinSize; + uint8_t isIbssPowerSaveAllowed; + uint8_t isIbssPowerCollapseAllowed; + uint8_t isIbssAwakeOnTxRx; + uint32_t ibssInactivityCount; + uint32_t ibssTxSpEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; + + bool enable_ip_tcp_udp_checksum_offload; + bool enablePowersaveOffload; + bool enablefwprint; + bool enablefwlog; +#ifdef WLAN_FEATURE_11AC + uint8_t fVhtAmpduLenExponent; + uint32_t vhtMpduLen; +#endif + uint32_t IpaConfig; + bool IpaClkScalingEnable; + uint32_t IpaDescSize; + uint32_t IpaHighBandwidthMbps; + uint32_t IpaMediumBandwidthMbps; + uint32_t IpaLowBandwidthMbps; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint32_t WlanMccToSccSwitchMode; +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + uint32_t WlanAutoShutdown; +#endif + uint8_t maxWoWFilters; + uint8_t wowEnable; + uint8_t maxNumberOfPeers; + uint8_t disableDFSChSwitch; + uint8_t enableDFSMasterCap; + uint16_t thermalTempMinLevel0; + uint16_t thermalTempMaxLevel0; + uint16_t thermalTempMinLevel1; + uint16_t thermalTempMaxLevel1; + uint16_t thermalTempMinLevel2; + uint16_t thermalTempMaxLevel2; + uint16_t thermalTempMinLevel3; + uint16_t thermalTempMaxLevel3; + uint32_t TxPower2g; + uint32_t TxPower5g; + uint32_t gEnableDebugLog; + uint8_t enableRxThread; + bool fDfsPhyerrFilterOffload; + uint8_t gSapPreferredChanLocation; + uint8_t gDisableDfsJapanW53; + bool gEnableOverLapCh; + bool fRegChangeDefCountry; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint32_t TxFlowLowWaterMark; + uint32_t TxFlowHighWaterMarkOffset; + uint32_t TxFlowMaxQueueDepth; + uint32_t TxLbwFlowLowWaterMark; + uint32_t TxLbwFlowHighWaterMarkOffset; + uint32_t TxLbwFlowMaxQueueDepth; + uint32_t TxHbwFlowLowWaterMark; + uint32_t TxHbwFlowHighWaterMarkOffset; + uint32_t TxHbwFlowMaxQueueDepth; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint32_t TxFlowStopQueueThreshold; + uint32_t TxFlowStartQueueOffset; +#endif + uint8_t apMaxOffloadPeers; + uint8_t apMaxOffloadReorderBuffs; + bool advertiseConcurrentOperation; + bool enableMemDeepSleep; + + uint32_t defaultRateIndex24Ghz; +#ifdef MEMORY_DEBUG + bool IsMemoryDebugSupportEnabled; +#endif + + uint8_t allowDFSChannelRoam; + + bool debugP2pRemainOnChannel; + + bool enablePacketLog; +#ifdef MSM_PLATFORM + uint32_t busBandwidthHighThreshold; + uint32_t busBandwidthMediumThreshold; + uint32_t busBandwidthLowThreshold; + uint32_t busBandwidthComputeInterval; + uint32_t tcpDelackThresholdHigh; + uint32_t tcpDelackThresholdLow; +#endif /* MSM_PLATFORM */ + + /* FW debug log parameters */ + uint32_t enableFwLogType; + uint32_t enableFwLogLevel; + uint8_t enableFwModuleLogLevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + +#ifdef WLAN_FEATURE_11W + uint32_t pmfSaQueryMaxRetries; + uint32_t pmfSaQueryRetryInterval; +#endif + + uint8_t gMaxConcurrentActiveSessions; + + uint8_t ignoreCAC; + bool IsSapDfsChSifsBurstEnabled; + +#ifdef FEATURE_GREEN_AP + bool enableGreenAP; +#endif + uint8_t force_sap_acs; + uint8_t force_sap_acs_st_ch; + uint8_t force_sap_acs_end_ch; + + int32_t dfsRadarPriMultiplier; + uint8_t reorderOffloadSupport; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + + uint32_t IpaUcTxBufCount; + uint32_t IpaUcTxBufSize; + uint32_t IpaUcRxIndRingCount; + uint32_t IpaUcTxPartitionBase; +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + /* WLAN Logging */ + uint32_t wlanLoggingEnable; + uint32_t wlanLoggingFEToConsole; + uint32_t wlanLoggingNumBuf; +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + + bool enableSifsBurst; + +#ifdef WLAN_FEATURE_LPSS + bool enablelpasssupport; +#endif +#ifdef WLAN_FEATURE_NAN + bool enable_nan_support; +#endif + bool enableSelfRecovery; +#ifdef FEATURE_WLAN_FORCE_SAP_SCC + uint8_t SapSccChanAvoidance; +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + + bool enableSapSuspend; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + uint8_t extWowGotoSuspend; + uint8_t extWowApp1WakeupPinNumber; + uint8_t extWowApp2WakeupPinNumber; + uint32_t extWowApp2KAInitPingInterval; + uint32_t extWowApp2KAMinPingInterval; + uint32_t extWowApp2KAMaxPingInterval; + uint32_t extWowApp2KAIncPingInterval; + uint16_t extWowApp2TcpSrcPort; + uint16_t extWowApp2TcpDstPort; + uint32_t extWowApp2TcpTxTimeout; + uint32_t extWowApp2TcpRxTimeout; +#endif + bool gEnableDeauthToDisassocMap; +#ifdef DHCP_SERVER_OFFLOAD + bool enableDHCPServerOffload; + uint32_t dhcpMaxNumClients; + uint8_t dhcpServerIP[IPADDR_STRING_LENGTH]; +#endif /* DHCP_SERVER_OFFLOAD */ + bool enable_mac_spoofing; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + uint16_t p2p_listen_defer_interval; + uint32_t sta_miracast_mcc_rest_time_val; + bool is_ramdump_enabled; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t sap_p2p_11ac_override; + uint8_t sap_dot11mc; + uint8_t prefer_non_dfs_on_radar; + bool ignore_peer_erp_info; + uint8_t multicast_host_fw_msgs; + uint8_t conc_system_pref; + bool sendDeauthBeforeCon; + bool policy_manager_enabled; + bool tso_enable; + bool lro_enable; + bool active_mode_offload; + uint32_t fine_time_meas_cap; + uint8_t max_scan_count; +#ifdef WLAN_FEATURE_FASTPATH + bool fastpath_enable; +#endif + uint8_t dot11p_mode; +#ifdef FEATURE_NAPI + bool napi_enable; +#endif +#ifdef FEATURE_WLAN_EXTSCAN + uint32_t extscan_passive_max_chn_time; + uint32_t extscan_passive_min_chn_time; + uint32_t extscan_active_max_chn_time; + uint32_t extscan_active_min_chn_time; +#endif + bool ce_classify_enabled; + uint32_t dual_mac_feature_disable; + bool tx_chain_mask_cck; + uint8_t tx_chain_mask_1ss; + uint16_t self_gen_frm_pwr; +}; + +#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) +#define VAR_SIZE(_Struct, _Var) (sizeof(((_Struct *)0)->_Var)) + +#define VAR_FLAGS_NONE (0) + +/* bit 0 is Required or Optional */ +#define VAR_FLAGS_REQUIRED (1 << 0) +#define VAR_FLAGS_OPTIONAL (0 << 0) + +/* + * bit 1 tells if range checking is required. + * If less than MIN, assume MIN. + * If greater than MAX, assume MAX. + */ +#define VAR_FLAGS_RANGE_CHECK (1 << 1) +#define VAR_FLAGS_RANGE_CHECK_ASSUME_MINMAX (VAR_FLAGS_RANGE_CHECK) + +/* + * bit 2 is range checking that assumes the DEFAULT value + * If less than MIN, assume DEFAULT, + * If greater than MAX, assume DEFAULT. + */ +#define VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT (1 << 2) + +/* + * Bit 3 indicates that the config item can be modified dynamicially + * on a running system + */ +#define VAR_FLAGS_DYNAMIC_CFG (1 << 3) + +typedef enum { + WLAN_PARAM_Integer, + WLAN_PARAM_SignedInteger, + WLAN_PARAM_HexInteger, + WLAN_PARAM_String, + WLAN_PARAM_MacAddr, +} WLAN_PARAMETER_TYPE; + +#define REG_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + NULL, \ + 0 \ + } + +#define REG_DYNAMIC_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max, \ + _CBFunc, _CBParam) \ + { \ + (_Name), \ + (_Type), \ + (VAR_FLAGS_DYNAMIC_CFG | (_Flags)), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + (_CBFunc), \ + (_CBParam) \ + } + +#define REG_VARIABLE_STRING(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (unsigned long)(_Default), \ + 0, \ + 0, \ + NULL, \ + 0 \ + } + +typedef struct tREG_TABLE_ENTRY { + + char *RegName; /* variable name in the qcom_cfg.ini file */ + WLAN_PARAMETER_TYPE RegType; /* variable type in the hdd_config_t structure */ + unsigned long Flags; /* Specify optional parms and if RangeCheck is performed */ + unsigned short VarOffset; /* offset to field from the base address of the structure */ + unsigned short VarSize; /* size (in bytes) of the field */ + unsigned long VarDefault; /* default value to use */ + unsigned long VarMin; /* minimum value, for range checking */ + unsigned long VarMax; /* maximum value, for range checking */ + /* Dynamic modification notifier */ + void (*pfnDynamicnotify)(hdd_context_t *pHddCtx, + unsigned long notifyId); + unsigned long notifyId; /* Dynamic modification identifier */ +} REG_TABLE_ENTRY; + +static __inline unsigned long util_min(unsigned long a, unsigned long b) +{ + unsigned long r; + + r = ((a < b) ? a : b); + return r; +} + +/* Function declarations and documenation */ +CDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx); +CDF_STATUS hdd_update_mac_config(hdd_context_t *pHddCtx); +CDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx); +CDF_STATUS hdd_set_sme_chan_list(hdd_context_t *hdd_ctx); +bool hdd_update_config_dat(hdd_context_t *pHddCtx); +CDF_STATUS hdd_cfg_get_global_config(hdd_context_t *pHddCtx, char *pBuf, + int buflen); + +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(eHddDot11Mode dot11Mode); +CDF_STATUS hdd_execute_global_config_command(hdd_context_t *pHddCtx, + char *command); + +bool hdd_is_okc_mode_enabled(hdd_context_t *pHddCtx); +CDF_STATUS hdd_set_idle_ps_config(hdd_context_t *pHddCtx, uint32_t val); + +void hdd_update_tgt_cfg(void *context, void *param); +void hdd_dfs_indicate_radar(void *context, void *param); + +CDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *intArray, uint8_t *len, + uint8_t intArrayMaxLen); +void hdd_cfg_print(hdd_context_t *pHddCtx); + +CDF_STATUS hdd_update_nss(hdd_context_t *hdd_ctx, uint8_t nss); + +#endif diff --git a/core/hdd/inc/wlan_hdd_conc_ut.h b/core/hdd/inc/wlan_hdd_conc_ut.h new file mode 100644 index 0000000000..95e13f344c --- /dev/null +++ b/core/hdd/inc/wlan_hdd_conc_ut.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_CONC_UT_H +#define __WLAN_HDD_CONC_UT_H + +/* Include files */ + +#include "wlan_hdd_main.h" +#include "cds_concurrency.h" +#ifdef MPC_UT_FRAMEWORK +void clean_report(hdd_context_t *hdd_ctx); +void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum cds_pcl_type pcl_type, char *reason, uint8_t *pcl); +void print_report(hdd_context_t *hdd_ctx); +void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx); +void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum cds_chain_mode first_chain_mask); +void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum cds_chain_mode chain_mask, uint8_t use_same_mac); +#else +static inline void clean_report(hdd_context_t *hdd_ctx) +{ +} + +static inline void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum hdd_pcl_type pcl_type, char *reason, uint8_t *pcl) +{ +} + +static inline void print_report(hdd_context_t *hdd_ctx) +{ +} + +static inline void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx) +{ +} + +static inline void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum hdd_chain_mode first_chain_mask) +{ +} + +static inline void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum hdd_chain_mode chain_mask, uint8_t use_same_mac) +{ +} +#endif +#endif diff --git a/core/hdd/inc/wlan_hdd_debugfs.h b/core/hdd/inc/wlan_hdd_debugfs.h new file mode 100644 index 0000000000..be513177f8 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_debugfs.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_DEBUGFS_H +#define _WLAN_HDD_DEBUGFS_H + +#ifdef WLAN_OPEN_SOURCE +CDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter); +void hdd_debugfs_exit(hdd_context_t *pHddCtx); +#else +inline CDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter) +{ + return CDF_STATUS_SUCCESS; +} + +inline void hdd_debugfs_exit(hdd_context_t *pHddCtx) +{ +} +#endif /* #ifdef WLAN_OPEN_SOURCE */ +#endif /* #ifndef _WLAN_HDD_DEBUGFS_H */ diff --git a/core/hdd/inc/wlan_hdd_driver_ops.h b/core/hdd/inc/wlan_hdd_driver_ops.h new file mode 100644 index 0000000000..4619cf8a77 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_driver_ops.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_DRIVER_OPS_H__ +#define __WLAN_HDD_DRIVER_OPS_H__ + +/** + * DOC: wlan_hdd_driver_ops.h + * + * Functions to register the wlan driver. +*/ +int wlan_hdd_register_driver(void); +void wlan_hdd_unregister_driver(void); +int wlan_hdd_bus_suspend(pm_message_t state); +#endif /* __WLAN_HDD_DRIVER_OPS_H__ */ diff --git a/core/hdd/inc/wlan_hdd_ether.h b/core/hdd/inc/wlan_hdd_ether.h new file mode 100644 index 0000000000..cc20ad9b2f --- /dev/null +++ b/core/hdd/inc/wlan_hdd_ether.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_ETHER_H +#define _WLAN_HDD_ETHER_H +/*============================================================================ + @file wlan_hdd_ether.h + + This module describes Ethernet packet formats for processing by HDD. + ============================================================================*/ +/* $Header$ */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include +#include +#include +#include + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define WLAN_SNAP_OUI_LEN 3 +#define WLAN_SNAP_DSAP 0xAAU +#define WLAN_SNAP_SSAP 0xAAU +#define WLAN_SNAP_CTRL 0x03 +#define WLAN_MIN_PROTO 0x0600 + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +struct wlan_snap_hdr { + unsigned char dsap; + unsigned char ssap; + unsigned char ctrl; + unsigned char oui[WLAN_SNAP_OUI_LEN]; +} __packed; + +struct wlan_8023 { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +struct wlan_8023_vlan { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +union generic_ethhdr { + struct ethhdr eth_II; + struct vlan_ethhdr eth_IIv; + struct wlan_8023 eth_8023; + struct wlan_8023_vlan eth_8023v; +}; + +#endif /* #ifndef _WLAN_HDD_ETHER_H */ diff --git a/core/hdd/inc/wlan_hdd_ftm.h b/core/hdd/inc/wlan_hdd_ftm.h new file mode 100644 index 0000000000..c9ed355705 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_ftm.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_HDD_FTM_H +#define WLAN_HDD_FTM_H + +/** + * DOC: wlan_hdd_ftm.h + * + * WLAN Host Device Driver Factory Test Mode header file + */ + +#include "cdf_status.h" +#include "cds_mq.h" +#include "cds_api.h" +#include "msg.h" +#include "cdf_types.h" +#include + +enum wlan_hdd_ftm_state { + WLAN_FTM_INITIALIZED, + WLAN_FTM_STOPPED, + WLAN_FTM_STARTED, +}; + +/** + * struct wlan_hdd_ftm_status - FTM status + * @ftm_state: The current state of the FTM process + */ +struct wlan_hdd_ftm_status { + enum wlan_hdd_ftm_state ftm_state; +}; + +int wlan_hdd_ftm_open(hdd_context_t *hdd_ctx); +int wlan_hdd_ftm_close(hdd_context_t *hdd_ctx); + +#if defined(QCA_WIFI_FTM) +CDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len); +int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr); +int hdd_ftm_start(hdd_context_t *hdd_ctx); +int hdd_ftm_stop(hdd_context_t *hdd_ctx); +#endif + +#endif diff --git a/core/hdd/inc/wlan_hdd_host_offload.h b/core/hdd/inc/wlan_hdd_host_offload.h new file mode 100644 index 0000000000..515a828551 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_host_offload.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_HOST_OFFLOAD_H__ +#define __WLAN_HDD_HOST_OFFLOAD_H__ + +/**=========================================================================== + + \file wlan_hdd_host_offload.h + + \brief Android WLAN HDD Host Offload API + + ==========================================================================*/ + +/* Offload types. */ +#define WLAN_IPV4_ARP_REPLY_OFFLOAD 0 +#define WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 + +/* Enable or disable offload. */ +#define WLAN_OFFLOAD_DISABLE 0 +#define WLAN_OFFLOAD_ENABLE 0x1 +#define WLAN_OFFLOAD_BC_FILTER_ENABLE 0x2 +#define WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE (WLAN_OFFLOAD_ENABLE | WLAN_OFFLOAD_BC_FILTER_ENABLE) + +/* Offload request. */ +typedef struct { + uint8_t offloadType; + uint8_t enableOrDisable; + union { + uint8_t hostIpv4Addr[4]; + uint8_t hostIpv6Addr[16]; + } params; + struct cdf_mac_addr bssId; +} tHostOffloadRequest, *tpHostOffloadRequest; + +#endif /* __WLAN_HDD_HOST_OFFLOAD_H__ */ diff --git a/core/hdd/inc/wlan_hdd_includes.h b/core/hdd/inc/wlan_hdd_includes.h new file mode 100644 index 0000000000..cb2e63e858 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_includes.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(HDD_INCLUDES_H__) +#define HDD_INCLUDES_H__ + +/**=========================================================================== + + \file wlan_hdd_includes.h + + \brief Internal includes for the Linux HDD + + ==========================================================================*/ + +/* $HEADER$ */ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +/* throw all the includes in here f to get the .c files in the HDD to compile. */ + +#include +#include +#include +#include +#include +#include +#include "ol_txrx_ctrl_api.h" +#include +#include +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_mib.h" +#include "wlan_hdd_wext.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_tx_rx.h" + + +#ifdef FEATURE_OEM_DATA_SUPPORT +/*include for oem data req specific structures*/ +/*and function declarations*/ +#include "wlan_hdd_oemdata.h" +#endif + +#endif /* end #if !defined(HDD_INCLUDES_H__) */ diff --git a/core/hdd/inc/wlan_hdd_ipa.h b/core/hdd/inc/wlan_hdd_ipa.h new file mode 100644 index 0000000000..a2f5fb32e1 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_ipa.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HDD_IPA_H__ +#define HDD_IPA_H__ + +/** + * DOC: wlan_hdd_ipa.h + * + * WLAN IPA interface module headers + * Originally written by Qualcomm Atheros, Inc + */ + +#include + +#ifdef IPA_OFFLOAD +/* Include files */ +CDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx); +CDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx); +CDF_STATUS hdd_ipa_process_rxt(void *cds_context, cdf_nbuf_t rxBuf, + uint8_t sta_id); +int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum ipa_wlan_event type, uint8_t *mac_addr); +int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, + uint64_t rx_packets); +int hdd_ipa_suspend(hdd_context_t *hdd_ctx); +int hdd_ipa_resume(hdd_context_t *hdd_ctx); +void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, uint32_t *ipa_tx_diff, + uint32_t *ipa_rx_diff); +void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx); +void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason); +bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx); +bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx); +int hdd_ipa_send_mcc_scc_msg(hdd_context_t *pHddCtx, bool mcc_mode); +#else +static inline CDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) +{ + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) +{ + return CDF_STATUS_SUCCESS; +} + +static inline CDF_STATUS hdd_ipa_process_rxt(void *cds_context, + cdf_nbuf_t rxBuf, uint8_t sta_id) +{ + return CDF_STATUS_SUCCESS; +} + +static inline int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum ipa_wlan_event type, uint8_t *mac_addr) +{ + return 0; +} + +static inline int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, + bool mcc_mode) +{ + return 0; +} + +static inline int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + return 0; +} + +static inline int hdd_ipa_suspend(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline int hdd_ipa_resume(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, + uint32_t *ipa_tx_diff, + uint32_t *ipa_rx_diff) +{ + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + return; +} + +static inline void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, + uint8_t reason) +{ + return; +} + +static void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx) +{ + return false; +} + +static inline bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx) +{ + return false; +} +#endif /* IPA_OFFLOAD */ + +#ifdef IPA_UC_OFFLOAD +int hdd_ipa_uc_ssr_reinit(void); +int hdd_ipa_uc_ssr_deinit(void); +#else +static inline int hdd_ipa_uc_ssr_reinit(void) +{ + return false; +} + +static inline int hdd_ipa_uc_ssr_deinit(void) +{ + return false; +} +#endif + +#endif /* #ifndef HDD_IPA_H__ */ diff --git a/core/hdd/inc/wlan_hdd_lro.h b/core/hdd/inc/wlan_hdd_lro.h new file mode 100644 index 0000000000..db4ea27781 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_lro.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_LRO_H__ +#define __WLAN_HDD_LRO_H__ +/** + * DOC: wlan_hdd_lro.h + * + * WLAN LRO interface module headers + */ + +/** + * enum hdd_lro_rx_status - LRO receive frame status + * @HDD_LRO_RX: frame sent over the LRO interface + * @HDD_LRO_NO_RX: frame not sent over the LRO interface + */ +enum hdd_lro_rx_status { + HDD_LRO_RX = 0, + HDD_LRO_NO_RX = 1, +}; + +#if defined(FEATURE_LRO) + +#include +#include + +/* LRO_DESC_TABLE_SZ must be a power of 2 */ +#define LRO_DESC_TABLE_SZ 16 +#define LRO_DESC_TABLE_SZ_MASK (LRO_DESC_TABLE_SZ - 1) +#define LRO_DESC_POOL_SZ 10 + +/** + * hdd_lro_desc_entry - defines the LRO descriptor + * element stored in the list + * @lro_node: node of the list + * @lro_desc: the LRO descriptor contained in this list entry + */ +struct hdd_lro_desc_entry { + struct list_head lro_node; + struct net_lro_desc *lro_desc; +}; + +/** + * hdd_lro_desc_pool - pool of free LRO descriptors + * @lro_desc_array: array of LRO descriptors allocated + * @lro_free_list_head: head of the list + * @lro_pool_lock: lock to protect access to the list + */ +struct hdd_lro_desc_pool { + struct hdd_lro_desc_entry *lro_desc_array; + struct list_head lro_free_list_head; + cdf_spinlock_t lro_pool_lock; +}; + +/** + * hdd_lro_desc_table - defines each entry of the LRO + * hash table + * @lro_desc_list: list of LRO descriptors + */ +struct hdd_lro_desc_table { + struct list_head lro_desc_list; +}; + +/** + * hdd_lro_desc_info - structure containing the LRO + * descriptor information + * @lro_hash_table: hash table used for a quick desc. look-up + * @lro_hash_lock: lock to protect access to the hash table + * @lro_desc_pool: Free pool of LRO descriptors + */ +struct hdd_lro_desc_info { + struct hdd_lro_desc_table *lro_hash_table; + cdf_spinlock_t lro_hash_lock; + struct hdd_lro_desc_pool lro_desc_pool; +}; + +/** + * hdd_lro_s - LRO information per HDD adapter + * @lro_mgr: LRO manager + * @lro_desc_info: LRO descriptor information + */ +struct hdd_lro_s { + struct net_lro_mgr *lro_mgr; + struct hdd_lro_desc_info lro_desc_info; +}; + +int hdd_lro_init(hdd_context_t *hdd_ctx); + +int hdd_lro_enable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter); + +void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); + +enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb); + +void hdd_lro_flush_all(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter); +#else +struct hdd_lro_s {}; + +static inline int hdd_lro_enable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + return 0; +} + +static inline enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb) +{ + return HDD_LRO_NO_RX; +} + +static inline int hdd_lro_init(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline void hdd_lro_disable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter){} +#endif /* FEATURE_LRO */ +#endif /* __WLAN_HDD_LRO_H__ */ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h new file mode 100644 index 0000000000..3e4ad444ec --- /dev/null +++ b/core/hdd/inc/wlan_hdd_main.h @@ -0,0 +1,1529 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_MAIN_H) +#define WLAN_HDD_MAIN_H +/**=========================================================================== + + \file WLAN_HDD_MAIN_H.h + + \brief Linux HDD Adapter Type + + ==========================================================================*/ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include "sir_mac_prot_def.h" +#include "csr_api.h" +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif +#include "wlan_hdd_cfg80211.h" +#include +#ifdef WLAN_FEATURE_MBSSID +#include "sap_api.h" +#endif +#include "ol_txrx_osif_api.h" +#include "ol_txrx_ctrl_api.h" +#include + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ +/** Number of Tx Queues */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#define NUM_TX_QUEUES 5 +#else +#define NUM_TX_QUEUES 4 +#endif +/** Bytes to reserve in the headroom */ +#define LIBRA_HW_NEEDED_HEADROOM 128 +/** Hdd Tx Time out value */ +#ifdef LIBRA_LINUX_PC +#define HDD_TX_TIMEOUT (8000) +#else +#define HDD_TX_TIMEOUT msecs_to_jiffies(5000) +#endif +/** Hdd Default MTU */ +#define HDD_DEFAULT_MTU (1500) + +#ifdef QCA_CONFIG_SMP +#define NUM_CPUS NR_CPUS +#else +#define NUM_CPUS 1 +#endif + +/**event flags registered net device*/ +#define NET_DEVICE_REGISTERED (0) +#define SME_SESSION_OPENED (1) +#define INIT_TX_RX_SUCCESS (2) +#define WMM_INIT_DONE (3) +#define SOFTAP_BSS_STARTED (4) +#define DEVICE_IFACE_OPENED (5) +#define TDLS_INIT_DONE (6) +#define ACS_PENDING (7) + +/* HDD global event flags */ +#define ACS_IN_PROGRESS (0) + +/** Maximum time(ms)to wait for disconnect to complete **/ +#ifdef QCA_WIFI_3_0_EMU +#define WLAN_WAIT_TIME_DISCONNECT 3000 +#else +#define WLAN_WAIT_TIME_DISCONNECT 2000 +#endif +#define WLAN_WAIT_TIME_STATS 800 +#define WLAN_WAIT_TIME_POWER 800 +#define WLAN_WAIT_TIME_COUNTRY 1000 +#define WLAN_WAIT_TIME_LINK_STATUS 800 +/* Amount of time to wait for sme close session callback. + This value should be larger than the timeout used by WDI to wait for + a response from WCNSS */ +#define WLAN_WAIT_TIME_SESSIONOPENCLOSE 15000 +#define WLAN_WAIT_TIME_ABORTSCAN 2000 + +/** Maximum time(ms) to wait for mc thread suspend **/ +#define WLAN_WAIT_TIME_MCTHREAD_SUSPEND 1200 + +/** Maximum time(ms) to wait for target to be ready for suspend **/ +#define WLAN_WAIT_TIME_READY_TO_SUSPEND 2000 + +/** Maximum time(ms) to wait for tdls add sta to complete **/ +#define WAIT_TIME_TDLS_ADD_STA 1500 + +/** Maximum time(ms) to wait for tdls del sta to complete **/ +#define WAIT_TIME_TDLS_DEL_STA 1500 + +/** Maximum time(ms) to wait for Link Establish Req to complete **/ +#define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ 1500 + +/** Maximum time(ms) to wait for tdls mgmt to complete **/ +#define WAIT_TIME_TDLS_MGMT 11000 + +/* Scan Req Timeout */ +#define WLAN_WAIT_TIME_SCAN_REQ 100 + +#define MAX_NUMBER_OF_ADAPTERS 4 + +#define MAX_CFG_STRING_LEN 255 + +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +/** Mac Address string **/ +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ADDRESS_STR_LEN 18 /* Including null terminator */ +#define MAX_GENIE_LEN 255 + +#define WLAN_CHIP_VERSION "WCNSS" + +#define hddLog(level, args ...) CDF_TRACE(CDF_MODULE_ID_HDD, level, ## args) + +#define hdd_log(level, args...) CDF_TRACE(CDF_MODULE_ID_HDD, level, ## args) +#define hdd_logfl(level, format, args...) hdd_log(level, FL(format), ## args) + +#define hdd_alert(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_FATAL, format, ## args) +#define hdd_err(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_ERROR, format, ## args) +#define hdd_warn(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_WARN, format, ## args) +#define hdd_notice(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_INFO, format, ## args) +#define hdd_info(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define hdd_debug(format, args...) \ + hdd_logfl(CDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define ENTER() hdd_logfl(CDF_TRACE_LEVEL_INFO_LOW, "enter") +#define EXIT() hdd_logfl(CDF_TRACE_LEVEL_INFO_LOW, "exit") + +#define WLAN_HDD_GET_PRIV_PTR(__dev__) (hdd_adapter_t *)(netdev_priv((__dev__))) + +#define MAX_NO_OF_2_4_CHANNELS 14 + +#define WLAN_HDD_PUBLIC_ACTION_FRAME 4 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET 30 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET 0 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET 2 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET 5 +#define WLAN_HDD_VENDOR_SPECIFIC_ACTION 0x09 +#define WLAN_HDD_WFA_OUI 0x506F9A +#define WLAN_HDD_WFA_P2P_OUI_TYPE 0x09 +#define WLAN_HDD_P2P_SOCIAL_CHANNELS 3 +#define WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET 6 + +#define WLAN_HDD_IS_SOCIAL_CHANNEL(center_freq) \ + (((center_freq) == 2412) || ((center_freq) == 2437) || ((center_freq) == 2462)) + +#define WLAN_HDD_CHANNEL_IN_UNII_1_BAND(center_freq) \ + (((center_freq) == 5180) || ((center_freq) == 5200) \ + || ((center_freq) == 5220) || ((center_freq) == 5240)) + +#ifdef WLAN_FEATURE_11W +#define WLAN_HDD_SA_QUERY_ACTION_FRAME 8 +#endif + +#define WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP 14 +#define WLAN_HDD_TDLS_ACTION_FRAME 12 +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK +#define HDD_WAKE_LOCK_DURATION 50 /* in msecs */ +#endif + +#define WLAN_HDD_QOS_ACTION_FRAME 1 +#define WLAN_HDD_QOS_MAP_CONFIGURE 4 +#define HDD_SAP_WAKE_LOCK_DURATION 10000 /* in msecs */ + +#define HDD_MOD_EXIT_SSR_MAX_RETRIES 75 + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define GTK_OFFLOAD_ENABLE 0 +#define GTK_OFFLOAD_DISABLE 1 +#endif + +#ifdef FEATURE_WLAN_SCAN_PNO +#define HDD_PNO_SCAN_TIMERS_SET_ONE 1 +/* value should not be greater than PNO_MAX_SCAN_TIMERS */ +#define HDD_PNO_SCAN_TIMERS_SET_MULTIPLE 6 +#endif + +#define MAX_USER_COMMAND_SIZE 4096 + +#define HDD_MIN_TX_POWER (-100) /* minimum tx power */ +#define HDD_MAX_TX_POWER (+100) /* maximum tx power */ + +/* If IPA UC data path is enabled, target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX packet pumping in case + * IPA data path enabled + */ +#define WLAN_TFC_IPAUC_TX_DESC_RESERVE 100 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +#ifdef CONFIG_CNSS +#define cfg80211_vendor_cmd_reply(skb) cnss_vendor_cmd_reply(skb) +#endif +#endif + +#define BSS_WAIT_TIMEOUT 10000 + +/* + * Generic asynchronous request/response support + * + * Many of the APIs supported by HDD require a call to SME to + * perform an action or to retrieve some data. In most cases SME + * performs the operation asynchronously, and will execute a provided + * callback function when the request has completed. In order to + * synchronize this the HDD API allocates a context which is then + * passed to SME, and which is then, in turn, passed back to the + * callback function when the operation completes. The callback + * function then sets a completion variable inside the context which + * the HDD API is waiting on. In an ideal world the HDD API would + * wait forever (or at least for a long time) for the response to be + * received and for the completion variable to be set. However in + * most cases these HDD APIs are being invoked in the context of a + * user space thread which has invoked either a cfg80211 API or a + * wireless extensions ioctl and which has taken the kernel rtnl_lock. + * Since this lock is used to synchronize many of the kernel tasks, we + * do not want to hold it for a long time. In addition we do not want + * to block user space threads (such as the wpa supplicant's main + * thread) for an extended time. Therefore we only block for a short + * time waiting for the response before we timeout. This means that + * it is possible for the HDD API to timeout, and for the callback to + * be invoked afterwards. In order for the callback function to + * determine if the HDD API is still waiting, a magic value is also + * stored in the shared context. Only if the context has a valid + * magic will the callback routine do any work. In order to further + * synchronize these activities a spinlock is used so that if any HDD + * API timeout coincides with its callback, the operations of the two + * threads will be serialized. + */ + +struct statsContext { + struct completion completion; + hdd_adapter_t *pAdapter; + unsigned int magic; +}; + +struct linkspeedContext { + struct completion completion; + hdd_adapter_t *pAdapter; + unsigned int magic; +}; + +extern spinlock_t hdd_context_lock; + +#define STATS_CONTEXT_MAGIC 0x53544154 /* STAT */ +#define RSSI_CONTEXT_MAGIC 0x52535349 /* RSSI */ +#define POWER_CONTEXT_MAGIC 0x504F5752 /* POWR */ +#define SNR_CONTEXT_MAGIC 0x534E5200 /* SNR */ +#define LINK_CONTEXT_MAGIC 0x4C494E4B /* LINKSPEED */ +#define LINK_STATUS_MAGIC 0x4C4B5354 /* LINKSTATUS(LNST) */ +#define TEMP_CONTEXT_MAGIC 0x74656d70 /* TEMP (temperature) */ + +/* MAX OS Q block time value in msec + * Prevent from permanent stall, resume OS Q if timer expired */ +#define WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 1000 +#define WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 100 +#define WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH 14 + +#define HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 +#define HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 + + +#define NUM_TX_RX_HISTOGRAM 1024 +#define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1) + +struct hdd_tx_rx_histogram { + uint64_t interval_rx; + uint64_t interval_tx; + uint64_t total_rx; + uint64_t total_tx; + uint32_t next_vote_level; + uint32_t next_rx_level; +}; + +typedef struct hdd_tx_rx_stats_s { + /* start_xmit stats */ + __u32 txXmitCalled; + __u32 txXmitDropped; + __u32 txXmitClassifiedAC[NUM_TX_QUEUES]; + __u32 txXmitDroppedAC[NUM_TX_QUEUES]; + /* complete_cbk_stats */ + __u32 txCompleted; + /* rx stats */ + __u32 rxPackets[NUM_CPUS]; + __u32 rxDropped[NUM_CPUS]; + __u32 rxDelivered[NUM_CPUS]; + __u32 rxRefused[NUM_CPUS]; + + /* txflow stats */ + bool is_txflow_paused; + __u32 txflow_pause_cnt; + __u32 txflow_unpause_cnt; + __u32 txflow_timer_cnt; +} hdd_tx_rx_stats_t; + +#ifdef WLAN_FEATURE_11W +typedef struct hdd_pmf_stats_s { + uint8_t numUnprotDeauthRx; + uint8_t numUnprotDisassocRx; +} hdd_pmf_stats_t; +#endif + +typedef struct hdd_stats_s { + tCsrSummaryStatsInfo summary_stat; + tCsrGlobalClassAStatsInfo ClassA_stat; + tCsrGlobalClassBStatsInfo ClassB_stat; + tCsrGlobalClassCStatsInfo ClassC_stat; + tCsrGlobalClassDStatsInfo ClassD_stat; + tCsrPerStaStatsInfo perStaStats; + hdd_tx_rx_stats_t hddTxRxStats; +#ifdef WLAN_FEATURE_11W + hdd_pmf_stats_t hddPmfStats; +#endif +} hdd_stats_t; + +typedef enum { + HDD_ROAM_STATE_NONE, + + /* Issuing a disconnect due to transition into low power states. */ + HDD_ROAM_STATE_DISCONNECTING_POWER, + + /* move to this state when HDD sets a key with SME/CSR. Note this is */ + /* an important state to get right because we will get calls into our SME */ + /* callback routine for SetKey activity that we did not initiate! */ + HDD_ROAM_STATE_SETTING_KEY, +} HDD_ROAM_STATE; + +typedef struct roaming_info_s { + HDD_ROAM_STATE roamingState; + cdf_event_t roamingEvent; + + tSirMacAddr bssid; + tSirMacAddr peerMac; + uint32_t roamId; + eRoamCmdStatus roamStatus; + bool deferKeyComplete; + +} roaming_info_t; + +#ifdef FEATURE_WLAN_WAPI +/* Define WAPI macros for Length, BKID count etc*/ +#define MAX_WPI_KEY_LENGTH 16 +#define MAX_NUM_PN 16 +#define MAC_ADDR_LEN 6 +#define MAX_ADDR_INDEX 12 +#define MAX_NUM_AKM_SUITES 16 +#define MAX_NUM_UNI_SUITES 16 +#define MAX_NUM_BKIDS 16 + +/** WAPI AUTH mode definition */ +enum _WAPIAuthMode { + WAPI_AUTH_MODE_OPEN = 0, + WAPI_AUTH_MODE_PSK = 1, + WAPI_AUTH_MODE_CERT +} __packed; +typedef enum _WAPIAuthMode WAPIAuthMode; + +/** WAPI Work mode structure definition */ +#define WZC_ORIGINAL 0 +#define WAPI_EXTENTION 1 + +struct _WAPI_FUNCTION_MODE { + unsigned char wapiMode; +} __packed; + +typedef struct _WAPI_FUNCTION_MODE WAPI_FUNCTION_MODE; + +typedef struct _WAPI_BKID { + uint8_t bkid[16]; +} WAPI_BKID, *pWAPI_BKID; + +/** WAPI Association information structure definition */ +struct _WAPI_AssocInfo { + uint8_t elementID; + uint8_t length; + uint16_t version; + uint16_t akmSuiteCount; + uint32_t akmSuite[MAX_NUM_AKM_SUITES]; + uint16_t unicastSuiteCount; + uint32_t unicastSuite[MAX_NUM_UNI_SUITES]; + uint32_t multicastSuite; + uint16_t wapiCability; + uint16_t bkidCount; + WAPI_BKID bkidList[MAX_NUM_BKIDS]; +} __packed; + +typedef struct _WAPI_AssocInfo WAPI_AssocInfo; +typedef struct _WAPI_AssocInfo *pWAPI_IEAssocInfo; + +/** WAPI KEY Type definition */ +enum _WAPIKeyType { + PAIRWISE_KEY, /* 0 */ + GROUP_KEY /* 1 */ +} __packed; +typedef enum _WAPIKeyType WAPIKeyType; + +/** WAPI KEY Direction definition */ +enum _KEY_DIRECTION { + None, + Rx, + Tx, + Rx_Tx +} __packed; + +typedef enum _KEY_DIRECTION WAPI_KEY_DIRECTION; + +/* WAPI KEY structure definition */ +struct WLAN_WAPI_KEY { + WAPIKeyType keyType; + WAPI_KEY_DIRECTION keyDirection; /*reserved for future use */ + uint8_t keyId; + uint8_t addrIndex[MAX_ADDR_INDEX]; /*reserved for future use */ + int wpiekLen; + uint8_t wpiek[MAX_WPI_KEY_LENGTH]; + int wpickLen; + uint8_t wpick[MAX_WPI_KEY_LENGTH]; + uint8_t pn[MAX_NUM_PN]; /*reserved for future use */ +} __packed; + +typedef struct WLAN_WAPI_KEY WLAN_WAPI_KEY; +typedef struct WLAN_WAPI_KEY *pWLAN_WAPI_KEY; + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_GET_BE24(a) ((u32) ((a[0] << 16) | (a[1] << 8) | a[2])) +#define WLAN_EID_WAPI 68 +#define WAPI_PSK_AKM_SUITE 0x02721400 +#define WAPI_CERT_AKM_SUITE 0x01721400 + +/* WAPI BKID List structure definition */ +struct _WLAN_BKID_LIST { + uint32_t length; + uint32_t BKIDCount; + WAPI_BKID BKID[1]; +} __packed; + +typedef struct _WLAN_BKID_LIST WLAN_BKID_LIST; +typedef struct _WLAN_BKID_LIST *pWLAN_BKID_LIST; + +/* WAPI Information structure definition */ +struct hdd_wapi_info_s { + uint32_t nWapiMode; + bool fIsWapiSta; + struct cdf_mac_addr cachedMacAddr; + uint8_t wapiAuthMode; +} __packed; +typedef struct hdd_wapi_info_s hdd_wapi_info_t; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct beacon_data_s { + u8 *head; + u8 *tail; + u8 *proberesp_ies; + u8 *assocresp_ies; + int head_len; + int tail_len; + int proberesp_ies_len; + int assocresp_ies_len; + int dtim_period; +} beacon_data_t; + +/* MAINTAIN 1 - 1 CORRESPONDENCE WITH tCDF_CON_MODE */ +typedef enum device_mode { + WLAN_HDD_INFRA_STATION, + WLAN_HDD_SOFTAP, + WLAN_HDD_P2P_CLIENT, + WLAN_HDD_P2P_GO, + /* Mode 5 is reserved for FTM */ + WLAN_HDD_FTM = 5, + WLAN_HDD_IBSS, + WLAN_HDD_P2P_DEVICE, + WLAN_HDD_OCB +} device_mode_t; + +typedef enum rem_on_channel_request_type { + REMAIN_ON_CHANNEL_REQUEST, + OFF_CHANNEL_ACTION_TX, +} rem_on_channel_request_type_t; + +typedef struct action_pkt_buffer { + uint8_t *frame_ptr; + uint32_t frame_length; + uint16_t freq; +} action_pkt_buffer_t; + +typedef struct hdd_remain_on_chan_ctx { + struct net_device *dev; + struct ieee80211_channel chan; + enum nl80211_channel_type chan_type; + unsigned int duration; + u64 cookie; + rem_on_channel_request_type_t rem_on_chan_request; + cdf_mc_timer_t hdd_remain_on_chan_timer; + action_pkt_buffer_t action_pkt_buff; + bool hdd_remain_on_chan_cancel_in_progress; + uint32_t scan_id; +} hdd_remain_on_chan_ctx_t; + +/* RoC Request entry */ +typedef struct hdd_roc_req { + cdf_list_node_t node; /* MUST be first element */ + hdd_adapter_t *pAdapter; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; +} hdd_roc_req_t; + +/** + * struct hdd_scan_req - Scan Request entry + * @node : List entry element + * @adapter: Adapter address + * @scan_request: scan request holder + * @scan_id: scan identifier used across host layers which is generated at WMI + * @cookie: scan request identifier sent to userspace + * @source: scan request originator (NL/Vendor scan) + * @timestamp: scan request timestamp + * + * Scan request linked list element + */ +struct hdd_scan_req { + cdf_list_node_t node; + hdd_adapter_t *adapter; + struct cfg80211_scan_request *scan_request; + uint32_t scan_id; + uint8_t source; + uint32_t timestamp; +}; + +typedef enum { + HDD_IDLE, + HDD_PD_REQ_ACK_PENDING, + HDD_GO_NEG_REQ_ACK_PENDING, + HDD_INVALID_STATE, +} eP2PActionFrameState; + +typedef enum { + WLAN_HDD_GO_NEG_REQ, + WLAN_HDD_GO_NEG_RESP, + WLAN_HDD_GO_NEG_CNF, + WLAN_HDD_INVITATION_REQ, + WLAN_HDD_INVITATION_RESP, + WLAN_HDD_DEV_DIS_REQ, + WLAN_HDD_DEV_DIS_RESP, + WLAN_HDD_PROV_DIS_REQ, + WLAN_HDD_PROV_DIS_RESP, +} tActionFrmType; + +typedef struct hdd_cfg80211_state_s { + uint16_t current_freq; + u64 action_cookie; + uint8_t *buf; + size_t len; + hdd_remain_on_chan_ctx_t *remain_on_chan_ctx; + struct mutex remain_on_chan_ctx_lock; + eP2PActionFrameState actionFrmState; +} hdd_cfg80211_state_t; + +typedef enum { + HDD_SSR_NOT_REQUIRED, + HDD_SSR_REQUIRED, + HDD_SSR_DISABLED, +} e_hdd_ssr_required; + +struct hdd_station_ctx { + /** Handle to the Wireless Extension State */ + hdd_wext_state_t WextState; + +#ifdef FEATURE_WLAN_TDLS + tdlsCtx_t *pHddTdlsCtx; +#endif + + /**Connection information*/ + connection_info_t conn_info; + + roaming_info_t roam_info; + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + int ft_carrier_on; +#endif + +#ifdef WLAN_FEATURE_GTK_OFFLOAD + tSirGtkOffloadParams gtkOffloadReqParams; +#endif + /*Increment whenever ibss New peer joins and departs the network */ + int ibss_sta_generation; + + /* Indication of wep/wpa-none keys installation */ + bool ibss_enc_key_installed; + + /*Save the wep/wpa-none keys */ + tCsrRoamSetKey ibss_enc_key; + + bool hdd_ReassocScenario; + + /* STA ctx debug variables */ + int staDebugState; +}; + +#define BSS_STOP 0 +#define BSS_START 1 +typedef struct hdd_hostapd_state_s { + int bssState; + cdf_event_t cdf_event; + cdf_event_t cdf_stop_bss_event; + CDF_STATUS cdf_status; + bool bCommit; + +} hdd_hostapd_state_t; + +/* + * Per station structure kept in HDD for multiple station support for SoftAP + */ +typedef struct { + /** The station entry is used or not */ + bool isUsed; + + /** Station ID reported back from HAL (through SAP). Broadcast + * uses station ID zero by default in both libra and volans. */ + uint8_t ucSTAId; + + /** MAC address of the station */ + struct cdf_mac_addr macAddrSTA; + + /** Current Station state so HDD knows how to deal with packet + * queue. Most recent states used to change TLSHIM STA state */ + enum ol_txrx_peer_state tlSTAState; + + /** Track QoS status of station */ + bool isQosEnabled; + + /** The station entry for which Deauth is in progress */ + bool isDeauthInProgress; +} hdd_station_info_t; + +struct hdd_ap_ctx_s { + hdd_hostapd_state_t HostapdState; + + /* Memory differentiation mode is enabled */ + /* uint16_t uMemoryDiffThreshold; */ + /* uint8_t uNumActiveAC; */ + /* uint8_t uActiveACMask; */ + + /** Packet Count to update uNumActiveAC and uActiveACMask */ + /* uint16_t uUpdatePktCount; */ + + /** Station ID assigned after BSS starts */ + uint8_t uBCStaId; + + uint8_t uPrivacy; /* The privacy bits of configuration */ + + tSirWPSPBCProbeReq WPSPBCProbeReq; + + tsap_Config_t sapConfig; + + struct semaphore semWpsPBCOverlapInd; + + bool apDisableIntraBssFwd; + + cdf_mc_timer_t hdd_ap_inactivity_timer; + + uint8_t operatingChannel; + + bool uIsAuthenticated; + + eCsrEncryptionType ucEncryptType; + + /* This will point to group key data, if it is received before start bss. */ + tCsrRoamSetKey groupKey; + /* This will have WEP key data, if it is received before start bss */ + tCsrRoamSetKey wepKey[CSR_MAX_NUM_KEY]; + + beacon_data_t *beacon; + + bool bApActive; +#ifdef WLAN_FEATURE_MBSSID + /* SAP Context */ + void *sapContext; +#endif + bool dfs_cac_block_tx; +}; + +typedef struct hdd_scaninfo_s { + /* The scan pending */ + uint32_t mScanPending; + + /* Counter for mScanPending so that the scan pending + error log is not printed for more than 5 times */ + uint32_t mScanPendingCounter; + + /* Additional IE for scan */ + tSirAddie scanAddIE; + + /* Scan mode */ + tSirScanType scan_mode; + + /* completion variable for abortscan */ + struct completion abortscan_event_var; + +} hdd_scaninfo_t; + +#define WLAN_HDD_MAX_MC_ADDR_LIST 10 + +#ifdef WLAN_FEATURE_PACKET_FILTERING +typedef struct multicast_addr_list { + uint8_t isFilterApplied; + uint8_t mc_cnt; + uint8_t addr[WLAN_HDD_MAX_MC_ADDR_LIST][ETH_ALEN]; +} t_multicast_add_list; +#endif + +#define WLAN_HDD_MAX_HISTORY_ENTRY 10 + +/** + * struct hdd_netif_queue_stats - netif queue operation statistics + * @pause_count - pause counter + * @unpause_count - unpause counter + */ +struct hdd_netif_queue_stats { + uint16_t pause_count; + uint16_t unpause_count; +}; + +/** + * struct hdd_netif_queue_history - netif queue operation history + * @time: timestamp + * @netif_action: action type + * @netif_reason: reason type + * @pause_map: pause map + */ +struct hdd_netif_queue_history { + cdf_time_t time; + uint16_t netif_action; + uint16_t netif_reason; + uint32_t pause_map; +}; + + +#define WLAN_HDD_ADAPTER_MAGIC 0x574c414e /* ASCII "WLAN" */ + + +struct hdd_adapter_s { + void *pHddCtx; + + device_mode_t device_mode; + + /** Handle to the network device */ + struct net_device *dev; + + /** IPv4 notifier callback for handling ARP offload on change in IP */ + struct work_struct ipv4NotifierWorkQueue; +#ifdef WLAN_NS_OFFLOAD + /** IPv6 notifier callback for handling NS offload on change in IP */ + struct work_struct ipv6NotifierWorkQueue; +#endif + + /* TODO Move this to sta Ctx */ + struct wireless_dev wdev; + struct cfg80211_scan_request *request; + + /** ops checks if Opportunistic Power Save is Enable or Not + * ctw stores ctWindow value once we receive Opps command from + * wpa_supplicant then using ctWindow value we need to Enable + * Opportunistic Power Save + */ + uint8_t ops; + uint32_t ctw; + + /** Current MAC Address for the adapter */ + struct cdf_mac_addr macAddressCurrent; + + /**Event Flags*/ + unsigned long event_flags; + + /**Device TX/RX statistics*/ + struct net_device_stats stats; + /** HDD statistics*/ + hdd_stats_t hdd_stats; + /** linkspeed statistics */ + tSirLinkSpeedInfo ls_stats; + /**Mib information*/ + sHddMib_t hdd_mib; + + uint8_t sessionId; + + /* Completion variable for session close */ + struct completion session_close_comp_var; + + /* Completion variable for session open */ + struct completion session_open_comp_var; + + /* TODO: move these to sta ctx. These may not be used in AP */ + /** completion variable for disconnect callback */ + struct completion disconnect_comp_var; + + /** Completion of change country code */ + struct completion change_country_code; + + /* completion variable for Linkup Event */ + struct completion linkup_event_var; + + /* completion variable for cancel remain on channel Event */ + struct completion cancel_rem_on_chan_var; + + /* completion variable for off channel remain on channel Event */ + struct completion offchannel_tx_event; + /* Completion variable for action frame */ + struct completion tx_action_cnf_event; + /* Completion variable for remain on channel ready */ + struct completion rem_on_chan_ready_event; + + struct completion sta_authorized_event; +#ifdef FEATURE_WLAN_TDLS + struct completion tdls_add_station_comp; + struct completion tdls_del_station_comp; + struct completion tdls_mgmt_comp; + struct completion tdls_link_establish_req_comp; + CDF_STATUS tdlsAddStaStatus; +#endif + + /* Track whether the linkup handling is needed */ + bool isLinkUpSvcNeeded; + + /* Mgmt Frames TX completion status code */ + uint32_t mgmtTxCompletionStatus; + + /* WMM Status */ + hdd_wmm_status_t hddWmmStatus; +/************************************************************* + */ +/************************************************************* + * TODO - Remove it later + */ + /** Multiple station supports */ + /** Per-station structure */ + spinlock_t staInfo_lock; /* To protect access to station Info */ + hdd_station_info_t aStaInfo[WLAN_MAX_STA_COUNT]; + /* uint8_t uNumActiveStation; */ + +/************************************************************* + */ + +#ifdef FEATURE_WLAN_WAPI + hdd_wapi_info_t wapi_info; +#endif + + int8_t rssi; +#ifdef WLAN_FEATURE_LPSS + bool rssi_send; +#endif + + uint8_t snr; + + struct work_struct monTxWorkQueue; + struct sk_buff *skb_to_tx; + + union { + hdd_station_ctx_t station; + hdd_ap_ctx_t ap; + } sessionCtx; + + hdd_cfg80211_state_t cfg80211State; + +#ifdef WLAN_FEATURE_PACKET_FILTERING + t_multicast_add_list mc_addr_list; +#endif + uint8_t addr_filter_pattern; + + /* Magic cookie for adapter sanity verification */ + uint32_t magic; + bool higherDtimTransition; + bool survey_idx; + + hdd_scaninfo_t scan_info; +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + tAniTrafStrmMetrics tsmStats; +#endif + /* Flag to ensure PSB is configured through framework */ + uint8_t psbChanged; + /* UAPSD psb value configured through framework */ + uint8_t configuredPsb; +#ifdef IPA_OFFLOAD + void *ipa_context; +#endif + /* Use delayed work for Sec AP ACS as Pri AP Startup need to complete + * since CSR (PMAC Struct) Config is same for both AP + */ + struct delayed_work acs_pending_work; + + struct work_struct scan_block_work; +#ifdef MSM_PLATFORM + unsigned long prev_rx_packets; + unsigned long prev_tx_packets; + int connection; +#endif + bool is_roc_inprogress; + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + cdf_mc_timer_t tx_flow_control_timer; + bool tx_flow_timer_initialized; + unsigned int tx_flow_low_watermark; + unsigned int tx_flow_high_watermark_offset; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + bool offloads_configured; + + /* DSCP to UP QoS Mapping */ + sme_QosWmmUpType hddWmmDscpToUpMap[WLAN_HDD_MAX_DSCP + 1]; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + bool isLinkLayerStatsSet; +#endif + uint8_t linkStatus; + + /* variable for temperature in Celsius */ + int temperature; + + /* Time stamp for last completed RoC request */ + v_TIME_t last_roc_ts; + + /* Time stamp for start RoC request */ + v_TIME_t start_roc_ts; + + /* State for synchronous OCB requests to WMI */ + struct sir_ocb_set_config_response ocb_set_config_resp; + struct sir_ocb_get_tsf_timer_response ocb_get_tsf_timer_resp; + struct sir_dcc_get_stats_response *dcc_get_stats_resp; + struct sir_dcc_update_ndl_response dcc_update_ndl_resp; + + /* MAC addresses used for OCB interfaces */ + tSirMacAddr ocb_mac_address[CDF_MAX_CONCURRENCY_PERSONA]; + int ocb_mac_addr_count; + + /* BITMAP indicating pause reason */ + uint32_t pause_map; + spinlock_t pause_map_lock; + + uint8_t history_index; + struct hdd_netif_queue_history + queue_oper_history[WLAN_HDD_MAX_HISTORY_ENTRY]; + struct hdd_netif_queue_stats queue_oper_stats[WLAN_REASON_TYPE_MAX]; + struct hdd_lro_s lro_info; +}; + +#define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) +#define WLAN_HDD_GET_AP_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.ap) +#define WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter) (&(pAdapter)->sessionCtx.station.WextState) +#define WLAN_HDD_GET_CTX(pAdapter) ((hdd_context_t *)pAdapter->pHddCtx) +#define WLAN_HDD_GET_HAL_CTX(pAdapter) (((hdd_context_t *)(pAdapter->pHddCtx))->hHal) +#define WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter) (&(pAdapter)->sessionCtx.ap.HostapdState) +#define WLAN_HDD_GET_CFG_STATE_PTR(pAdapter) (&(pAdapter)->cfg80211State) +#ifdef WLAN_FEATURE_MBSSID +#define WLAN_HDD_GET_SAP_CTX_PTR(pAdapter) (pAdapter->sessionCtx.ap.sapContext) +#endif +#ifdef FEATURE_WLAN_TDLS +#define WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter) \ + (((WLAN_HDD_INFRA_STATION != pAdapter->device_mode) && \ + (WLAN_HDD_P2P_CLIENT != pAdapter->device_mode)) ? 0 : 1) +#define WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter) \ + ((WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter)) ? \ + (tdlsCtx_t *)(pAdapter)->sessionCtx.station.pHddTdlsCtx : NULL) +#endif + +/* Set mac address locally administered bit */ +#define WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macaddr) (macaddr[0] &= 0xFD) + +#define HDD_DEFAULT_MCC_P2P_QUOTA 70 +#define HDD_RESET_MCC_P2P_QUOTA 50 + +typedef struct hdd_adapter_list_node { + cdf_list_node_t node; /* MUST be first element */ + hdd_adapter_t *pAdapter; +} hdd_adapter_list_node_t; + +typedef struct hdd_priv_data_s { + uint8_t *buf; + int used_len; + int total_len; +} hdd_priv_data_t; + +#define MAX_MOD_LOGLEVEL 10 +typedef struct { + uint8_t enable; + uint8_t dl_type; + uint8_t dl_report; + uint8_t dl_loglevel; + uint8_t index; + uint32_t dl_mod_loglevel[MAX_MOD_LOGLEVEL]; + +} fw_log_info; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * struct hdd_offloaded_packets - request id to pattern id mapping + * @request_id: request id + * @pattern_id: pattern id + * + */ +struct hdd_offloaded_packets { + uint32_t request_id; + uint8_t pattern_id; +}; + +/** + * struct hdd_offloaded_packets_ctx - offloaded packets context + * @op_table: request id to pattern id table + * @op_lock: mutex lock + */ +struct hdd_offloaded_packets_ctx { + struct hdd_offloaded_packets op_table[MAXNUM_PERIODIC_TX_PTRNS]; + struct mutex op_lock; +}; +#endif + +/** Adapter structure definition */ + +struct hdd_context_s { + /** Global CDS context */ + v_CONTEXT_t pcds_context; + + /** HAL handle...*/ + tHalHandle hHal; + + struct wiphy *wiphy; + /* TODO Remove this from here. */ + + cdf_spinlock_t hdd_adapter_lock; + cdf_list_t hddAdapters; /* List of adapters */ + + /* One per STA: 1 for BCMC_STA_ID, 1 for each SAP_SELF_STA_ID, 1 for WDS_STAID */ + hdd_adapter_t *sta_to_adapter[WLAN_MAX_STA_COUNT + CDF_MAX_NO_OF_SAP_MODE + 2]; /* One per sta. For quick reference. */ + + /** Pointer for firmware image data */ + const struct firmware *fw; + + /** Pointer for configuration data */ + const struct firmware *cfg; + + /** Pointer to the parent device */ + struct device *parent_dev; + + /** Config values read from qcom_cfg.ini file */ + struct hdd_config *config; + + struct wlan_hdd_ftm_status ftm; + + /* Completion variable to indicate Mc Thread Suspended */ + struct completion mc_sus_event_var; + + struct completion reg_init; + + bool isMcThreadSuspended; + +#ifdef QCA_CONFIG_SMP + bool is_ol_rx_thread_suspended; +#endif + + volatile bool isLogpInProgress; + + bool isLoadInProgress; + + bool isUnloadInProgress; + + /* Track whether Mcast/Bcast Filter is enabled. */ + bool hdd_mcastbcast_filter_set; + + bool hdd_wlan_suspended; + bool suspended; + + /* Lock to avoid race condition during start/stop bss */ + struct mutex sap_lock; + +#ifdef WLAN_KD_READY_NOTIFIER + bool kd_nl_init; +#endif /* WLAN_KD_READY_NOTIFIER */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + /* OEM App registered or not */ + bool oem_app_registered; + + /* OEM App Process ID */ + int32_t oem_pid; +#endif + + /** Concurrency Parameters*/ + uint32_t concurrency_mode; + + uint8_t no_of_open_sessions[CDF_MAX_NO_OF_MODE]; + uint8_t no_of_active_sessions[CDF_MAX_NO_OF_MODE]; + + /** P2P Device MAC Address for the adapter */ + struct cdf_mac_addr p2pDeviceAddress; + +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK + cdf_wake_lock_t rx_wake_lock; +#endif + + cdf_wake_lock_t sap_wake_lock; + +#ifdef FEATURE_WLAN_TDLS + eTDLSSupportMode tdls_mode; + eTDLSSupportMode tdls_mode_last; + tdlsConnInfo_t tdlsConnInfo[HDD_MAX_NUM_TDLS_STA]; + /* maximum TDLS station number allowed upon runtime condition */ + uint16_t max_num_tdls_sta; + /* TDLS peer connected count */ + uint16_t connected_peer_count; + tdls_scan_context_t tdls_scan_ctxt; + /* Lock to avoid race condition during TDLS operations */ + struct mutex tdls_lock; + uint8_t tdls_off_channel; + uint16_t tdls_channel_offset; +#endif + +#ifdef IPA_OFFLOAD + void *hdd_ipa; + /* CE resources */ + uint32_t ce_sr_base_paddr; + uint32_t ce_sr_ring_size; + cdf_dma_addr_t ce_reg_paddr; + + /* WLAN TX:IPA->WLAN */ + uint32_t tx_comp_ring_base_paddr; + uint32_t tx_comp_ring_size; + uint32_t tx_num_alloc_buffer; + + /* WLAN RX:WLAN->IPA */ + uint32_t rx_rdy_ring_base_paddr; + uint32_t rx_rdy_ring_size; + uint32_t rx_proc_done_idx_paddr; + + /* IPA UC doorbell registers paddr */ + uint32_t tx_comp_doorbell_paddr; + uint32_t rx_ready_doorbell_paddr; +#endif /* IPA_OFFLOAD */ + + /* MC/BC Filter state variable + * This always contains the value that is currently + * configured + * */ + uint8_t configuredMcastBcastFilter; + + uint8_t sus_res_mcastbcast_filter; + + bool sus_res_mcastbcast_filter_valid; + + /* debugfs entry */ + struct dentry *debugfs_phy; + + /* Use below lock to protect access to isSchedScanUpdatePending + * since it will be accessed in two different contexts. + */ + spinlock_t schedScan_lock; + + /* Flag keeps track of wiphy suspend/resume */ + bool isWiphySuspended; + + /* Indicates about pending sched_scan results */ + bool isSchedScanUpdatePending; + +#ifdef MSM_PLATFORM + /* DDR bus bandwidth compute timer + */ + cdf_mc_timer_t bus_bw_timer; + int cur_vote_level; + spinlock_t bus_bw_lock; + int cur_rx_level; + uint64_t prev_rx; +#endif + /* VHT80 allowed */ + bool isVHT80Allowed; + + struct completion ready_to_suspend; + /* defining the solution type */ + uint32_t target_type; + + /* defining the firmware version */ + uint32_t target_fw_version; + uint32_t dfs_radar_found; + + /* defining the chip/rom version */ + uint32_t target_hw_version; + /* defining the chip/rom revision */ + uint32_t target_hw_revision; + /* chip/rom name */ + const char *target_hw_name; + struct regulatory reg; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t unsafe_channel_count; + uint16_t unsafe_channel_list[NUM_20MHZ_RF_CHANNELS]; +#endif /* FEATURE_WLAN_CH_AVOID */ + + uint8_t max_intf_count; + uint8_t current_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + tSirScanType ioctl_scan_mode; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + cdf_work_t sta_ap_intf_check_work; +#endif + + struct work_struct sap_start_work; + bool is_sap_restart_required; + bool is_sta_connection_pending; + spinlock_t sap_update_info_lock; + spinlock_t sta_update_info_lock; + + uint8_t dev_dfs_cac_status; + + bool btCoexModeSet; +#ifdef FEATURE_GREEN_AP + struct hdd_green_ap_ctx *green_ap_ctx; +#endif + fw_log_info fw_log_settings; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + cdf_mc_timer_t skip_acs_scan_timer; + uint8_t skip_acs_scan_status; +#endif + + cdf_wake_lock_t sap_dfs_wakelock; + atomic_t sap_dfs_ref_cnt; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + bool is_extwow_app_type1_param_set; + bool is_extwow_app_type2_param_set; + bool ext_wow_should_suspend; + struct completion ready_to_extwow; +#endif + + /* Time since boot up to extscan start (in micro seconds) */ + uint64_t ext_scan_start_since_boot; + unsigned long g_event_flags; + /* RoC request queue and work */ + struct delayed_work roc_req_work; + cdf_spinlock_t hdd_roc_req_q_lock; + cdf_list_t hdd_roc_req_q; + cdf_spinlock_t hdd_scan_req_q_lock; + cdf_list_t hdd_scan_req_q; + uint8_t miracast_value; +#ifdef WLAN_NS_OFFLOAD + /* IPv6 notifier callback for handling NS offload on change in IP */ + struct notifier_block ipv6_notifier; +#endif + /* IPv4 notifier callback for handling ARP offload on change in IP */ + struct notifier_block ipv4_notifier; + + /* number of rf chains supported by target */ + uint32_t num_rf_chains; + /* Is htTxSTBC supported by target */ + uint8_t ht_tx_stbc_supported; +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + struct hdd_offloaded_packets_ctx op_ctx; +#endif + bool mcc_mode; +#ifdef WLAN_FEATURE_MEMDUMP + uint8_t *fw_dump_loc; + uint32_t dump_loc_paddr; + cdf_mc_timer_t memdump_cleanup_timer; + struct mutex memdump_lock; + bool memdump_in_progress; +#endif /* WLAN_FEATURE_MEMDUMP */ + + cdf_mc_timer_t dbs_opportunistic_timer; + bool connection_in_progress; + spinlock_t connection_status_lock; + cdf_mutex_t hdd_conc_list_lock; + + uint16_t hdd_txrx_hist_idx; + struct hdd_tx_rx_histogram hdd_txrx_hist[NUM_TX_RX_HISTOGRAM]; +}; + +/*--------------------------------------------------------------------------- + Function declarations and documentation + -------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void wlan_hdd_check_sta_ap_concurrent_ch_intf(void *sta_pAdapter); +#endif + +const char *hdd_device_mode_to_string(uint8_t device_mode); + +CDF_STATUS hdd_get_front_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t **ppAdapterNode); + +CDF_STATUS hdd_get_next_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode, + hdd_adapter_list_node_t **pNextAdapterNode); + +CDF_STATUS hdd_remove_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +CDF_STATUS hdd_remove_front_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t **ppAdapterNode); + +CDF_STATUS hdd_add_adapter_back(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +CDF_STATUS hdd_add_adapter_front(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +hdd_adapter_t *hdd_open_adapter(hdd_context_t *pHddCtx, uint8_t session_type, + const char *name, tSirMacAddr macAddr, + uint8_t rtnl_held); +CDF_STATUS hdd_close_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + uint8_t rtnl_held); +CDF_STATUS hdd_close_all_adapters(hdd_context_t *pHddCtx); +CDF_STATUS hdd_stop_all_adapters(hdd_context_t *pHddCtx); +CDF_STATUS hdd_reset_all_adapters(hdd_context_t *pHddCtx); +CDF_STATUS hdd_start_all_adapters(hdd_context_t *pHddCtx); +hdd_adapter_t *hdd_get_adapter_by_vdev(hdd_context_t *pHddCtx, + uint32_t vdev_id); +hdd_adapter_t *hdd_get_adapter_by_macaddr(hdd_context_t *pHddCtx, + tSirMacAddr macAddr); +CDF_STATUS hdd_init_station_mode(hdd_adapter_t *pAdapter); +hdd_adapter_t *hdd_get_adapter(hdd_context_t *pHddCtx, device_mode_t mode); +void hdd_deinit_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + bool rtnl_held); +CDF_STATUS hdd_stop_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + const bool bCloseSession); +void hdd_set_station_ops(struct net_device *pWlanDev); +uint8_t *wlan_hdd_get_intf_addr(hdd_context_t *pHddCtx); +void wlan_hdd_release_intf_addr(hdd_context_t *pHddCtx, uint8_t *releaseAddr); +uint8_t hdd_get_operating_channel(hdd_context_t *pHddCtx, device_mode_t mode); + +void hdd_set_conparam(uint32_t newParam); +tCDF_CON_MODE hdd_get_conparam(void); + +void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId, + eCsrAbortReason reason); +void hdd_cleanup_actionframe(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); + +void crda_regulatory_entry_default(uint8_t *countryCode, int domain_id); +void wlan_hdd_reset_prob_rspies(hdd_adapter_t *pHostapdAdapter); +void hdd_prevent_suspend(uint32_t reason); +void hdd_allow_suspend(uint32_t reason); +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason); +bool hdd_is_ssr_required(void); +void hdd_set_ssr_required(e_hdd_ssr_required value); + +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy); +CDF_STATUS hdd_set_ibss_power_save_params(hdd_adapter_t *pAdapter); +CDF_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx); +void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx); +int wlan_hdd_validate_context(hdd_context_t *pHddCtx); +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr); +CDF_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx); + +void hdd_checkandupdate_phymode(hdd_context_t *pHddCtx); + +#ifdef MSM_PLATFORM +void hdd_start_bus_bw_compute_timer(hdd_adapter_t *pAdapter); +void hdd_stop_bus_bw_compute_timer(hdd_adapter_t *pAdapter); +#else +static inline void hdd_start_bus_bw_compute_timer(hdd_adapter_t *pAdapter) +{ + return; +} + +static inline void hdd_stop_bus_bw_computer_timer(hdd_adapter_t *pAdapter) +{ + return; +} +#endif + +int hdd_wlan_startup(struct device *dev, void *hif_sc); +void __hdd_wlan_exit(void); +int hdd_wlan_notify_modem_power_state(int state); +#ifdef QCA_HT_2040_COEX +int hdd_wlan_set_ht2040_mode(hdd_adapter_t *pAdapter, uint16_t staId, + struct cdf_mac_addr macAddrSTA, int width); +#endif + +#ifdef WLAN_FEATURE_LPSS +void wlan_hdd_send_status_pkg(hdd_adapter_t *pAdapter, + hdd_station_ctx_t *pHddStaCtx, + uint8_t is_on, uint8_t is_connected); +void wlan_hdd_send_version_pkg(uint32_t fw_version, + uint32_t chip_id, const char *chip_name); +void wlan_hdd_send_all_scan_intf_info(hdd_context_t *pHddCtx); +#endif +void wlan_hdd_send_svc_nlink_msg(int type, void *data, int len); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_enable(hdd_context_t *hdd_ctx, bool enable); +#endif + +hdd_adapter_t *hdd_get_con_sap_adapter(hdd_adapter_t *this_sap_adapter, + bool check_start_bss); + +bool hdd_is_5g_supported(hdd_context_t *pHddCtx); + +int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter); + +#ifdef WLAN_FEATURE_STATS_EXT +void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx); +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wlan_hdd_cfg80211_link_layer_stats_init(hdd_context_t *pHddCtx); +static inline bool hdd_link_layer_stats_supported(void) +{ + return true; +} +#else +static inline bool hdd_link_layer_stats_supported(void) +{ + return false; +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +void hdd_get_fw_version(hdd_context_t *hdd_ctx, + uint32_t *major_spid, uint32_t *minor_spid, + uint32_t *siid, uint32_t *crmid); + +#ifdef WLAN_FEATURE_MEMDUMP +/** + * hdd_is_memdump_supported() - to check if memdump feature support + * + * This function is used to check if memdump feature is supported in + * the host driver + * + * Return: true if supported and false otherwise + */ +static inline bool hdd_is_memdump_supported(void) +{ + return true; +} +#else +static inline bool hdd_is_memdump_supported(void) +{ + return false; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +void hdd_update_macaddr(struct hdd_config *config, + struct cdf_mac_addr hw_macaddr); +#if defined(FEATURE_WLAN_LFR) +void wlan_hdd_disable_roaming(hdd_adapter_t *pAdapter); +void wlan_hdd_enable_roaming(hdd_adapter_t *pAdapter); +#endif + +CDF_STATUS hdd_post_cds_enable_config(hdd_context_t *pHddCtx); + +CDF_STATUS hdd_abort_mac_scan_all_adapters(hdd_context_t *hdd_ctx); + +CDF_STATUS wlan_hdd_check_custom_con_channel_rules(hdd_adapter_t *sta_adapter, + hdd_adapter_t *ap_adapter, + tCsrRoamProfile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same); +#ifdef WLAN_FEATURE_MBSSID +void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter); +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter); +#else +static inline void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter) {} +static inline void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter) {} +#endif +cdf_wake_lock_t *hdd_wlan_get_wake_lock_ptr(void); + +#ifdef QCA_CONFIG_SMP +int wlan_hdd_get_cpu(void); +#else +static inline int wlan_hdd_get_cpu(void) +{ + return 0; +} +#endif + +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason); + +void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value); +void wlan_hdd_display_tx_rx_histogram(hdd_context_t *pHddCtx); +void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *pHddCtx); +void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx); +void wlan_hdd_clear_netif_queue_history(hdd_context_t *hdd_ctx); +const char *hdd_get_fwpath(void); + +#endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/inc/wlan_hdd_memdump.h b/core/hdd/inc/wlan_hdd_memdump.h new file mode 100644 index 0000000000..c3fa8391a9 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_memdump.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC : wlan_hdd_memdump.h + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#if !defined(WLAN_HDD_MEMDUMP_H) +#define WLAN_HDD_MEMDUMP_H + +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_MEMDUMP +/** + * enum qca_wlan_vendor_attr_memory_dump - values for memory dump attributes + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_REQUEST_ID - Indicate request ID + * @QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE - Indicate size of the memory dump + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP sub command. + */ +enum qca_wlan_vendor_attr_memory_dump { + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_REQUEST_ID = 1, + QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE = 2, + + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX = + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - 1, +}; + +/* Size of fw memory dump is estimated to be 327680 bytes */ +#define FW_MEM_DUMP_SIZE 327680 +#define FW_DRAM_LOCATION 0x00400000 +#define FW_MEM_DUMP_REQ_ID 1 +#define FW_MEM_DUMP_NUM_SEG 1 +#define MEMDUMP_COMPLETION_TIME_MS 5000 + +int memdump_init(void); +void memdump_deinit(void); +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#else +static inline int memdump_init(void) +{ + return -ENOTSUPP; +} + +static inline void memdump_deinit(void) +{ +} + +static inline int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} +#endif + +#endif /* if !defined(WLAN_HDD_MEMDUMP_H)*/ diff --git a/core/hdd/inc/wlan_hdd_mib.h b/core/hdd/inc/wlan_hdd_mib.h new file mode 100644 index 0000000000..8fe44a8e96 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_mib.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_MIB_h__) +#define WLAN_HDD_MIB_h__ + +#include + +typedef enum { + eMib_dot11DesiredBssType_infrastructure = 1, + eMib_dot11DesiredBssType_independent = 2, + eMib_dot11DesiredBssType_infra_ap = 3, + eMib_dot11DesiredBssType_any = 4 +} eMib_dot11DesiredBssType; + +/** This is the maximum number of BSSIDs supported in the + dot11DesiredBssidList. All the code operates off of + this maximum BSSID list count. */ +#define MIB_DOT11_DESIRED_BSSID_LIST_MAX_COUNT 1 + +typedef struct { + uint32_t cEntries; + + struct cdf_mac_addr BSSIDs[MIB_DOT11_DESIRED_BSSID_LIST_MAX_COUNT]; + +} sMib_dot11DesiredBssidList; + +/** This is the maximum number of SSIDs supported in the + dot11DesiredSsidList. All the code operates off of + this maximum SSID list count. */ + +#define MIB_DOT11_DESIRED_SSID_LIST_MAX_COUNT 1 + +#define MIB_DOT11_SSID_MAX_LENGTH 32 + +typedef struct { + uint32_t ssidLength; + uint8_t ssid[MIB_DOT11_SSID_MAX_LENGTH]; + +} sDot11Ssid; + +typedef struct { + uint32_t cEntries; + + sDot11Ssid SSIDs[MIB_DOT11_DESIRED_SSID_LIST_MAX_COUNT]; + +} sMib_dot11DesiredSsidList; + +typedef enum { + /* these are bitmasks.... */ + eMib_dot11AutoConfigEnabled_None = 0U, + eMib_dot11AutoConfigEnabled_Phy = 0x00000001U, + eMib_dot11AutoConfigEnabled_Mac = 0x00000002U +} eMib_dot11AutoConfigEnabled; + +#define MIB_DOT11_SUPPORTED_PHY_TYPES_MAX_COUNT 3 + +typedef enum tagMib_dot11PhyType { + eMib_dot11PhyType_11b, + eMib_dot11PhyType_11a, + eMib_dot11PhyType_11g, + eMib_dot11PhyType_all +} eMib_dot11PhyType; + +typedef struct tagMib_dot11SupportedPhyTypes { + uint32_t cEntries; + eMib_dot11PhyType phyTypes[MIB_DOT11_SUPPORTED_PHY_TYPES_MAX_COUNT]; +} sMib_dot11SupportedPhyTypes; + +typedef enum { + eMib_DevicePowerState_D0, + eMib_DevicePowerState_D1, + eMib_DevicePowerState_D2, + eMib_DevicePowerState_D3 +} eMib_DevicePowerState; + +typedef enum { + eMib_dot11NICPowerState_OFF = false, + eMib_dot11NICPowerState_ON = true +} eMib_dot11NICPowerState; + +typedef enum { + eMib_dot11HardwarePHYState_OFF = false, + eMib_dot11HardwarePHYState_ON = true +} eMib_dot11HardwarePHYState; + +typedef enum { + eMib_dot11PowerSavingLevel_None, + eMib_dot11PowerSavingLevel_MaxPS, + eMib_dot11PowerSavingLevel_FastPS, + eMib_dot11PowerSavingLevel_MaximumLevel +} eMib_dot11PowerSavingLevel; + +#define MIB_DOT11_MAC_EXCLUSION_LIST_MAX_COUNT 4 +typedef struct { + uint32_t cEntries; + + struct cdf_mac_addr macAddrs[MIB_DOT11_MAC_EXCLUSION_LIST_MAX_COUNT]; + +} sMib_dot11MacExcludeList; + +#define MIB_DOT11_PRIVACY_EXEMPT_LIST_MAX_COUNT 32 + +typedef enum { + eMib_dot11ExemptionAction_Always, + eMib_dot11ExemptionAction_OnKeyMapUnavailable +} eMib_dot11ExemptAction; + +typedef enum { + eMib_dot11ExemptPacket_Unicast, + eMib_dot11ExemptPacket_Multicast, + eMib_dot11ExemptPacket_Both +} eMib_dot11ExemptPacket; + +typedef struct { + uint16_t uEtherType; + eMib_dot11ExemptAction exemptAction; + eMib_dot11ExemptPacket exemptPacket; + +} sMib_dot11PrivacyExemption; + +typedef struct { + uint32_t cEntries; + + sMib_dot11PrivacyExemption + privacyExemptList[MIB_DOT11_PRIVACY_EXEMPT_LIST_MAX_COUNT]; + +} sMib_dot11PrivacyExemptionList; + +typedef struct sHddMib_s { + eMib_dot11DesiredBssType mibDot11DesiredBssType; + + sMib_dot11DesiredBssidList mibDot11DesiredBssidList; + + sMib_dot11DesiredSsidList mibDot11DesiredSsidList; + + eMib_dot11AutoConfigEnabled mibDot11AutoConfigEnabled; + + /* the device power state for the device (the D-state... you know D0, D1, D2, etc. */ + eMib_DevicePowerState mibDevicePowerState; + + /* dot11NICPowerState is really the on/off state of the PHY. This can be */ + /* mamipulated through OIDs like a software control for radio on/off. */ + eMib_dot11NICPowerState mibDot11NICPowerState; + + /* Hardware PHY state is the on/off state of the hardware PHY. */ + eMib_dot11HardwarePHYState mibDot11HardwarePHYState; + + /* dot11 Power Saving level is the 802.11 power saving level/state for the 802.11 */ + /* NIC. Typically this is mapped to 802.11 BMPS in some fashion. We are not going */ + /* to disappoint; the Libra NIC maps these to different BMPS settings. */ + eMib_dot11PowerSavingLevel mibDot11PowerSavingLevel; + + sMib_dot11MacExcludeList mibDot11MacExcludeList; + + sMib_dot11PrivacyExemptionList mibDot11PrivacyExemptionList; + + sMib_dot11SupportedPhyTypes mibDot11SupportedPhyTypes; + eMib_dot11PhyType mibDot11CurrentPhyType; + + bool dot11IbssJoinOnly; + bool HiddenNetworkEnabled; + +} sHddMib_t; + +#endif diff --git a/core/hdd/inc/wlan_hdd_misc.h b/core/hdd/inc/wlan_hdd_misc.h new file mode 100644 index 0000000000..e0a0db23ce --- /dev/null +++ b/core/hdd/inc/wlan_hdd_misc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_HDD_MISC_H +#define WLAN_HDD_MISC_H + +#ifdef MSM_PLATFORM +#define WLAN_INI_FILE "wlan/qca_cld/WCNSS_qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/qca_cld/wlan_mac.bin" +#else +#define WLAN_INI_FILE "wlan/qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/wlan_mac.bin" +#endif /* MSM_PLATFORM */ + +#endif /* WLAN_HDD_MISC_H */ diff --git a/core/hdd/inc/wlan_hdd_nan.h b/core/hdd/inc/wlan_hdd_nan.h new file mode 100644 index 0000000000..ac2f62f38b --- /dev/null +++ b/core/hdd/inc/wlan_hdd_nan.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_NAN_H +#define __WLAN_HDD_NAN_H + +/** + * DOC: wlan_hdd_nan.h + * + * WLAN Host Device Driver NAN API specification + */ + +struct hdd_context_s; + +#ifdef WLAN_FEATURE_NAN +struct wiphy; +struct wireless_dev; + +int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +bool wlan_hdd_nan_is_supported(void); +void wlan_hdd_nan_init(struct hdd_context_s *hdd_ctx); +#else +static inline bool wlan_hdd_nan_is_supported(void) +{ + return false; +} +static inline void wlan_hdd_nan_init(struct hdd_context_s *hdd_ctx) +{ +} +#endif /* WLAN_FEATURE_NAN */ +#endif /* __WLAN_HDD_NAN_H */ diff --git a/core/hdd/inc/wlan_hdd_napi.h b/core/hdd/inc/wlan_hdd_napi.h new file mode 100644 index 0000000000..3c1683ded8 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_napi.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HDD_NAPI_H__ +#define __HDD_NAPI_H__ + +#ifdef FEATURE_NAPI +/** + * DOC: wlan_hdd_napi.h + * + * WLAN NAPI interface module headers + */ + +/* CLD headers */ +#include "hif_napi.h" +/* Linux headers */ +#include /* net_device */ + +#define HDD_NAPI_ANY (-1) + +int hdd_napi_enabled(int id); +int hdd_napi_create(void); +int hdd_napi_destroy(int force); + +int hdd_napi_stats(char *buf, + int max, + char *indp, + struct qca_napi_data *napid); + +/* the following triggers napi_enable/disable as required */ +int hdd_napi_event(enum qca_napi_event event, void *data); + +int hdd_napi_poll(struct napi_struct *napi, int budget); + +struct qca_napi_data *hdd_napi_get_all(void); + +#else /* ! defined(FEATURE_NAPI) */ +#include "hif_napi.h" +/** + * Stub API + * + */ + +#define HDD_NAPI_ANY (-1) + +static inline int hdd_napi_enabled(int id) { return 0; } +static inline int hdd_napi_create(void) { return -EPERM; } +static inline int hdd_napi_destroy(int force) { return 0; } +static inline int hdd_napi_stats(char *buf, int max, char *indp, + struct qca_napi_data *napid) +{ return 0; } +static inline int hdd_napi_event(enum qca_napi_event event, void *data) +{ return 0; } +static inline struct qca_napi_data *hdd_napi_get_all(void) { return NULL; } + +#endif /* FEATURE_NAPI */ + +#endif /* HDD_NAPI_H__ */ diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h new file mode 100644 index 0000000000..9107dc315a --- /dev/null +++ b/core/hdd/inc/wlan_hdd_oemdata.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * DOC: wlan_hdd_oemdata.h + * + * Internal includes for the oem data + */ + +#ifndef __WLAN_HDD_OEM_DATA_H__ +#define __WLAN_HDD_OEM_DATA_H__ + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 280 +#endif + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +#define OEM_APP_SIGNATURE_LEN 16 +#define OEM_APP_SIGNATURE_STR "QUALCOMM-OEM-APP" + +#define OEM_TARGET_SIGNATURE_LEN 8 +#define OEM_TARGET_SIGNATURE "QUALCOMM" + +#define OEM_CAP_MAX_NUM_CHANNELS 128 + +/** + * typedef eOemErrorCode - OEM error codes + * @OEM_ERR_NULL_CONTEXT: %NULL context + * @OEM_ERR_APP_NOT_REGISTERED: OEM App is not registered + * @OEM_ERR_INVALID_SIGNATURE: Invalid signature + * @OEM_ERR_NULL_MESSAGE_HEADER: Invalid message header + * @OEM_ERR_INVALID_MESSAGE_TYPE: Invalid message type + * @OEM_ERR_INVALID_MESSAGE_LENGTH: Invalid length in message body + */ +typedef enum { + OEM_ERR_NULL_CONTEXT = 1, + OEM_ERR_APP_NOT_REGISTERED, + OEM_ERR_INVALID_SIGNATURE, + OEM_ERR_NULL_MESSAGE_HEADER, + OEM_ERR_INVALID_MESSAGE_TYPE, + OEM_ERR_INVALID_MESSAGE_LENGTH +} eOemErrorCode; + +/** + * typedef tDriverVersion - Driver version identifier (w.x.y.z) + * @major: Version ID major number + * @minor: Version ID minor number + * @patch: Version ID patch number + * @build: Version ID build number + */ +typedef struct cdf_packed { + uint8_t major; + uint8_t minor; + uint8_t patch; + uint8_t build; +} tDriverVersion; + +/** + * typedef t_iw_oem_data_cap - OEM Data Capabilities + * @oem_target_signature: Signature of chipset vendor, e.g. QUALCOMM + * @oem_target_type: Chip type + * @oem_fw_version: Firmware version + * @driver_version: Host software version + * @allowed_dwell_time_min: Channel dwell time - allowed minimum + * @allowed_dwell_time_max: Channel dwell time - allowed maximum + * @curr_dwell_time_min: Channel dwell time - current minimim + * @curr_dwell_time_max: Channel dwell time - current maximum + * @supported_bands: Supported bands, 2.4G or 5G Hz + * @num_channels: Num of channels IDs to follow + * @channel_list: List of channel IDs + */ +typedef struct cdf_packed { + uint8_t oem_target_signature[OEM_TARGET_SIGNATURE_LEN]; + uint32_t oem_target_type; + uint32_t oem_fw_version; + tDriverVersion driver_version; + uint16_t allowed_dwell_time_min; + uint16_t allowed_dwell_time_max; + uint16_t curr_dwell_time_min; + uint16_t curr_dwell_time_max; + uint16_t supported_bands; + uint16_t num_channels; + uint8_t channel_list[OEM_CAP_MAX_NUM_CHANNELS]; +} t_iw_oem_data_cap; + +/** + * typedef tHddChannelInfo - Channel information + * @chan_id: channel id + * @reserved0: reserved for padding and future use + * @mhz: primary 20 MHz channel frequency in mhz + * @band_center_freq1: Center frequency 1 in MHz + * @band_center_freq2: Center frequency 2 in MHz, valid only for 11ac + * VHT 80+80 mode + * @info: channel info + * @reg_info_1: regulatory information field 1 which contains min power, + * max power, reg power and reg class id + * @reg_info_2: regulatory information field 2 which contains antennamax + */ +typedef struct cdf_packed { + uint32_t chan_id; + uint32_t reserved0; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; +} tHddChannelInfo; + +/** + * typedef tPeerStatusInfo - Status information for a given peer + * @peer_mac_addr: peer mac address + * @peer_status: peer status: 1: CONNECTED, 2: DISCONNECTED + * @vdev_id: vdev_id for the peer mac + * @peer_capability: peer capability: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @reserved0: reserved0 + * @peer_chan_info: channel info on which peer is connected + */ +typedef struct cdf_packed { + uint8_t peer_mac_addr[ETH_ALEN]; + uint8_t peer_status; + uint8_t vdev_id; + uint32_t peer_capability; + uint32_t reserved0; + tHddChannelInfo peer_chan_info; +} tPeerStatusInfo; + +void hdd_send_peer_status_ind_to_oem_app(struct cdf_mac_addr *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + tSirSmeChanInfo *chan_info); + +int iw_get_oem_data_cap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int oem_activate_service(struct hdd_context_s *hdd_ctx); + +void hdd_send_oem_data_rsp_msg(int length, uint8_t *oemDataRsp); + +#endif /* __WLAN_HDD_OEM_DATA_H__ */ + +#endif /* FEATURE_OEM_DATA_SUPPORT */ diff --git a/core/hdd/inc/wlan_hdd_p2p.h b/core/hdd/inc/wlan_hdd_p2p.h new file mode 100644 index 0000000000..b9ef3445f6 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_p2p.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __P2P_H +#define __P2P_H +/**=========================================================================== + + \file wlan_hdd_p2p.h + + \brief Linux HDD P2P include file + + ==========================================================================*/ +#define ACTION_FRAME_TX_TIMEOUT 2000 +#define WAIT_CANCEL_REM_CHAN 1000 +#define WAIT_REM_CHAN_READY 1000 +#define WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX 3000 +#define ESTIMATED_ROC_DUR_REQD_FOR_ACTION_TX 20 +#define COMPLETE_EVENT_PROPOGATE_TIME 10 + +#ifdef QCA_WIFI_3_0_EMU +#define ACTION_FRAME_DEFAULT_WAIT 500 +#else +#define ACTION_FRAME_DEFAULT_WAIT 200 +#endif + +#define WLAN_HDD_GET_TYPE_FRM_FC(__fc__) (((__fc__) & 0x0F) >> 2) +#define WLAN_HDD_GET_SUBTYPE_FRM_FC(__fc__) (((__fc__) & 0xF0) >> 4) +#define WLAN_HDD_80211_FRM_DA_OFFSET 4 +#define P2P_WILDCARD_SSID_LEN 7 +#define P2P_WILDCARD_SSID "DIRECT-" + +#ifdef QCA_WIFI_3_0_EMU +#define P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT 2 +#define P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT 3 +#else +#define P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT 2 +#define P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT 5 +#endif + +#ifdef WLAN_FEATURE_11W +#define WLAN_HDD_SET_WEP_FRM_FC(__fc__) ((__fc__) = ((__fc__) | 0x40)) +#endif /* WLAN_FEATURE_11W */ + +#define HDD_P2P_MAX_ROC_DURATION 1000 +#define MAX_ROC_REQ_QUEUE_ENTRY 10 + +enum hdd_rx_flags { + HDD_RX_FLAG_DECRYPTED = 1 << 0, + HDD_RX_FLAG_MMIC_STRIPPED = 1 << 1, + HDD_RX_FLAG_IV_STRIPPED = 1 << 2, +}; + +#define P2P_POWER_SAVE_TYPE_OPPORTUNISTIC (1 << 0) +#define P2P_POWER_SAVE_TYPE_PERIODIC_NOA (1 << 1) +#define P2P_POWER_SAVE_TYPE_SINGLE_NOA (1 << 2) + +#ifdef WLAN_FEATURE_P2P_DEBUG +typedef enum { P2P_NOT_ACTIVE, + P2P_GO_NEG_PROCESS, + P2P_GO_NEG_COMPLETED, + P2P_CLIENT_CONNECTING_STATE_1, + P2P_GO_COMPLETED_STATE, + P2P_CLIENT_CONNECTED_STATE_1, + P2P_CLIENT_DISCONNECTED_STATE, + P2P_CLIENT_CONNECTING_STATE_2, + P2P_CLIENT_COMPLETED_STATE} tP2PConnectionStatus; + +extern tP2PConnectionStatus global_p2p_connection_status; +#endif + +typedef struct p2p_app_setP2pPs { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; +} p2p_app_setP2pPs_t; + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + struct ieee80211_channel *chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type, +#endif + unsigned int duration, u64 *cookie); + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + u64 cookie); + +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + u64 cookie); + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData); +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command); +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command); + +void hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, + uint32_t nFrameLength, uint8_t *pbFrames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi); + +void hdd_remain_chan_ready_handler(hdd_adapter_t *pAdapter, + uint32_t scan_id); +void hdd_send_action_cnf(hdd_adapter_t *pAdapter, bool actionSendSuccess); +int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter); +void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type, + bool channel_type_valid, +#endif + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, u64 *cookie); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#else +struct net_device *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); +#else +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); +#endif + +void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter); + +void wlan_hdd_roc_request_dequeue(struct work_struct *work); +#endif /* __P2P_H */ diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h new file mode 100644 index 0000000000..c6157f0375 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_power.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_POWER_H +#define __WLAN_HDD_POWER_H + +/** + * DOC: wlan_hdd_power.h + * + * HDD Power Management API + */ + +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_PACKET_FILTERING + +#define HDD_MAX_CMP_PER_PACKET_FILTER 5 +#define HDD_FILTER_IPV6_MC_UC 1 +#define HDD_FILTER_IPV6_MC 0 +#define HDD_FILTER_ID_IPV6_MC 10 +#define HDD_FILTER_ID_IPV6_UC 11 + +#define HDD_IPV6_MC_CMP_DATA 0x33 +#define HDD_IPV6_UC_CMP_DATA 0x01 +#define HDD_IPV6_CMP_DATA_0 0x86 +#define HDD_IPV6_CMP_DATA_1 0xDD + +#define HDD_WLAN_MAC_ADDR_LEN 6 +#define HDD_MAX_NUM_MULTICAST_ADDRESS 10 + +/** + * enum pkt_filter_protocol_layer - packet filter protocol layer + * @HDD_FILTER_PROTO_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_PROTO_TYPE_MAC: MAC protocol + * @HDD_FILTER_PROTO_TYPE_ARP: ARP protocol + * @HDD_FILTER_PROTO_TYPE_IPV4: IP V4 protocol + * @HDD_FILTER_PROTO_TYPE_IPV6: IP V6 protocol + * @HDD_FILTER_PROTO_TYPE_UDP: UDP protocol + * @HDD_FILTER_PROTO_TYPE_INVALID: Max place holder value + */ +enum pkt_filter_protocol_layer { + HDD_FILTER_PROTO_TYPE_INVALID = 0, + HDD_FILTER_PROTO_TYPE_MAC = 1, + HDD_FILTER_PROTO_TYPE_ARP = 2, + HDD_FILTER_PROTO_TYPE_IPV4 = 3, + HDD_FILTER_PROTO_TYPE_IPV6 = 4, + HDD_FILTER_PROTO_TYPE_UDP = 5, + HDD_FILTER_PROTO_TYPE_MAX +}; + +/** + * enum pkt_filter_action - packet filter action + * @HDD_RCV_FILTER_INVALID: Invalid initial value + * @HDD_RCV_FILTER_SET: Packet filter set + * @HDD_RCV_FILTER_CLEAR: Packet filter clear + * @HDD_RCV_FILTER_MAX: Max place holder value + */ +enum pkt_filter_action { + HDD_RCV_FILTER_INVALID = 0, + HDD_RCV_FILTER_SET = 1, + HDD_RCV_FILTER_CLEAR = 2, + HDD_RCV_FILTER_MAX +}; + +/** + * enum pkt_filter_compare_flag - packet filter compare flag + * @HDD_FILTER_CMP_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_CMP_TYPE_EQUAL: Compare if filter is equal + * @HDD_FILTER_CMP_TYPE_MASK_EQUAL: Compare if filter mask is equal + * @HDD_FILTER_CMP_TYPE_NOT_EQUAL: Compare if filter is not equal + * @HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL: Compare if filter mask is not equal + * @HDD_FILTER_CMP_TYPE_MAX: Max place holder value + */ +enum pkt_filter_compare_flag { + HDD_FILTER_CMP_TYPE_INVALID = 0, + HDD_FILTER_CMP_TYPE_EQUAL = 1, + HDD_FILTER_CMP_TYPE_MASK_EQUAL = 2, + HDD_FILTER_CMP_TYPE_NOT_EQUAL = 3, + HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL = 4, + HDD_FILTER_CMP_TYPE_MAX +}; + +/** + * struct pkt_filter_param_cfg - packet filter parameter config + * @protocol_layer: Protocol layer + * @compare_flag: Compare flag + * @data_fffset: Data offset + * @data_length: Data length + * @compare_data: Compare data + * @data_mask: Data mask + */ +struct pkt_filter_param_cfg { + uint8_t protocol_layer; + uint8_t compare_flag; + uint8_t data_offset; + uint8_t data_length; + uint8_t compare_data[SIR_MAX_FILTER_TEST_DATA_LEN]; + uint8_t data_mask[SIR_MAX_FILTER_TEST_DATA_LEN]; +}; + +/** + * struct pkt_filter_cfg - packet filter config received from user space + * @filter_action: Filter action + * @filter_id: Filter id + * @num_params: Number of parameters + * @params_data: Packet filter parameters detail + */ +struct pkt_filter_cfg { + uint8_t filter_action; + uint8_t filter_id; + uint8_t num_params; + struct pkt_filter_param_cfg params_data[HDD_MAX_CMP_PER_PACKET_FILTER]; +}; + +#endif + + +/* SSR shutdown & re-init functions */ +CDF_STATUS hdd_wlan_shutdown(void); +CDF_STATUS hdd_wlan_re_init(void *hif_sc); + +void hdd_conf_mcastbcast_filter(hdd_context_t *pHddCtx, bool setfilter); +CDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable); +void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable); + +#ifdef WLAN_FEATURE_PACKET_FILTERING +void wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set); +#else +static inline void +wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set) +{ +} +#endif + +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow); + +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy); + +void hdd_ipv4_notifier_work_queue(struct work_struct *work); +#ifdef WLAN_NS_OFFLOAD +void hdd_ipv6_notifier_work_queue(struct work_struct *work); +#endif + +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + struct wireless_dev *wdev, +#endif + int *dbm); +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + struct wireless_dev *wdev, +#endif + enum nl80211_tx_power_setting type, + int dbm); +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool mode, + int timeout); + +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +#endif /* __WLAN_HDD_POWER_H */ diff --git a/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/core/hdd/inc/wlan_hdd_softap_tx_rx.h new file mode 100644 index 0000000000..2061ec72c6 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_softap_tx_rx.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_SOFTAP_TX_RX_H) +#define WLAN_HDD_SOFTAP_TX_RX_H + +/** + * DOC: wlan_hdd_softap_tx_rx.h + * + *Linux HDD SOFTAP Tx/RX APIs + */ + +#include + +int hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); +void hdd_softap_tx_timeout(struct net_device *dev); +CDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter); +CDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter); +CDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, + uint8_t STAId, + struct cdf_mac_addr *pmacAddrSTA); +CDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, + uint8_t STAId); +CDF_STATUS hdd_softap_rx_packet_cbk(void *cds_context, + cdf_nbuf_t rxBufChain, + uint8_t staId); +#ifdef IPA_OFFLOAD +CDF_STATUS hdd_softap_rx_mul_packet_cbk(void *cds_context, + cdf_nbuf_t rx_buf_list, uint8_t staId); +#endif /* IPA_OFFLOAD */ + +CDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, + uint8_t staId); +CDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter, + bool fAuthRequired, + bool fPrivacyBit, + uint8_t staId, + uint8_t ucastSig, + uint8_t bcastSig, + struct cdf_mac_addr *pPeerMacAddress, + bool fWmmEnabled); +CDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter, + bool fPrivacyBit); +CDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter); +CDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pHostapdAdapter); +CDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter, + struct cdf_mac_addr *pDestMacAddress, + enum ol_txrx_peer_state state); +CDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter, + struct cdf_mac_addr *pMacAddress, + uint8_t *staId); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context); +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume); +#else +static inline +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ + return; +} +static inline +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#endif /* end #if !defined(WLAN_HDD_SOFTAP_TX_RX_H) */ diff --git a/core/hdd/inc/wlan_hdd_tdls.h b/core/hdd/inc/wlan_hdd_tdls.h new file mode 100644 index 0000000000..285bb78567 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_tdls.h @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HDD_TDLS_H +#define __HDD_TDLS_H +/** + * DOC: wlan_hdd_tdls.h + * WLAN Host Device Driver TDLS include file + */ + +#ifdef FEATURE_WLAN_TDLS + +#define TDLS_SUB_DISCOVERY_PERIOD 100 + +#define TDLS_MAX_DISCOVER_REQS_PER_TIMER 1 + +#define TDLS_DISCOVERY_PERIOD 3600000 + +#define TDLS_TX_STATS_PERIOD 3600000 + +#define TDLS_IMPLICIT_TRIGGER_PKT_THRESHOLD 100 + +#define TDLS_RX_IDLE_TIMEOUT 5000 + +#define TDLS_RSSI_TRIGGER_HYSTERESIS 50 + +/* + * Before UpdateTimer expires, we want to timeout discovery response + * should not be more than 2000. + */ +#define TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE 1000 + +#define TDLS_CTX_MAGIC 0x54444c53 /* "TDLS" */ + +#define TDLS_MAX_SCAN_SCHEDULE 10 +#define TDLS_MAX_SCAN_REJECT 5 +#define TDLS_DELAY_SCAN_PER_CONNECTION 100 +#define TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN 1 + +#define TDLS_IS_CONNECTED(peer) \ + ((eTDLS_LINK_CONNECTED == (peer)->link_status) || \ + (eTDLS_LINK_TEARING == (peer)->link_status)) + +/* Bit mask flag for tdls_option to FW */ +#define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ +#define ENA_TDLS_BUFFER_STA (1 << 1) /* TDLS Buffer STA support */ +#define ENA_TDLS_SLEEP_STA (1 << 2) /* TDLS Sleep STA support */ +#define TDLS_SEC_OFFCHAN_OFFSET_0 0 +#define TDLS_SEC_OFFCHAN_OFFSET_40PLUS 40 +#define TDLS_SEC_OFFCHAN_OFFSET_40MINUS (-40) +#define TDLS_SEC_OFFCHAN_OFFSET_80 80 +#define TDLS_SEC_OFFCHAN_OFFSET_160 160 + +#define TDLS_PEER_LIST_SIZE 256 + +#define EXTTDLS_EVENT_BUF_SIZE (4096) + +/** + * struct tdls_config_params_t - tdls config params + * + * @tdls: tdls + * @tx_period_t: tx period + * @tx_packet_n: tx packets number + * @discovery_tries_n: discovery tries + * @idle_packet_n: idle packet number + * @rssi_trigger_threshold: rssi trigger threshold + * @rssi_teardown_threshold: rssi tear down threshold + * @rssi_delta: rssi delta + */ +typedef struct { + uint32_t tdls; + uint32_t tx_period_t; + uint32_t tx_packet_n; + uint32_t discovery_tries_n; + uint32_t idle_packet_n; + int32_t rssi_trigger_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; +} tdls_config_params_t; + +/** + * struct tdls_scan_context_t - tdls scan context + * + * @wiphy: pointer to wiphy structure + * @dev: pointer to netdev + * @scan_request: scan request + * @magic: magic + * @attempt: attempt + * @reject: reject + * @tdls_scan_work: delayed tdls scan work + */ +typedef struct { + struct wiphy *wiphy; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev; +#endif + struct cfg80211_scan_request *scan_request; + int magic; + int attempt; + int reject; + struct delayed_work tdls_scan_work; +} tdls_scan_context_t; + +/** + * enum eTDLSSupportMode - tdls support mode + * + * @eTDLS_SUPPORT_NOT_ENABLED: tdls support not enabled + * @eTDLS_SUPPORT_DISABLED: suppress implicit trigger and not + * respond to the peer + * @eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY: suppress implicit trigger, + * but respond to the peer + * @eTDLS_SUPPORT_ENABLED: implicit trigger + */ +typedef enum { + eTDLS_SUPPORT_NOT_ENABLED = 0, + eTDLS_SUPPORT_DISABLED, + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY, + eTDLS_SUPPORT_ENABLED, +} eTDLSSupportMode; + +/** + * enum tTDLSCapType - tdls capability type + * + * @eTDLS_CAP_NOT_SUPPORTED: tdls not supported + * @eTDLS_CAP_UNKNOWN: unknown capability + * @eTDLS_CAP_SUPPORTED: tdls capability supported + */ +typedef enum eTDLSCapType { + eTDLS_CAP_NOT_SUPPORTED = -1, + eTDLS_CAP_UNKNOWN = 0, + eTDLS_CAP_SUPPORTED = 1, +} tTDLSCapType; + +/** + * enum tTDLSLinkStatus - tdls link status + * + * @eTDLS_LINK_IDLE: tdls link idle + * @eTDLS_LINK_DISCOVERING: tdls link discovering + * @eTDLS_LINK_DISCOVERED: tdls link discovered + * @eTDLS_LINK_CONNECTING: tdls link connecting + * @eTDLS_LINK_CONNECTED: tdls link connected + * @eTDLS_LINK_TEARING: tdls link tearing + */ +typedef enum eTDLSLinkStatus { + eTDLS_LINK_IDLE = 0, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_DISCOVERED, + eTDLS_LINK_CONNECTING, + eTDLS_LINK_CONNECTED, + eTDLS_LINK_TEARING, +} tTDLSLinkStatus; + +/** + * enum tTDLSLinkReason - tdls link reason + * + * @eTDLS_LINK_SUCCESS: Success + * @eTDLS_LINK_UNSPECIFIED: Unspecified reason + * @eTDLS_LINK_NOT_SUPPORTED: Remote side doesn't support TDLS + * @eTDLS_LINK_UNSUPPORTED_BAND: Remote side doesn't support this band + * @eTDLS_LINK_NOT_BENEFICIAL: Going to AP is better than direct + * @eTDLS_LINK_DROPPED_BY_REMOTE: Remote side doesn't want it anymore + */ +typedef enum { + eTDLS_LINK_SUCCESS, + eTDLS_LINK_UNSPECIFIED = -1, + eTDLS_LINK_NOT_SUPPORTED = -2, + eTDLS_LINK_UNSUPPORTED_BAND = -3, + eTDLS_LINK_NOT_BENEFICIAL = -4, + eTDLS_LINK_DROPPED_BY_REMOTE = -5 +} tTDLSLinkReason; + +/** + * struct tdls_req_params_t - tdls request parameters + * + * @channel: channel hint, in channel number (NOT frequency) + * @global_operating_class: operating class to use + * @max_latency_ms: max latency that can be tolerated by apps + * @min_bandwidth_kbps: bandwidth required by apps, in kilo bits per second + */ +typedef struct { + int channel; + int global_operating_class; + int max_latency_ms; + int min_bandwidth_kbps; +} tdls_req_params_t; + +/** + * enum tdls_state_t - tdls state + * + * @QCA_WIFI_HAL_TDLS_DISABLED: TDLS is not enabled, or is disabled now + * @QCA_WIFI_HAL_TDLS_ENABLED: TDLS is enabled, but not yet tried + * @QCA_WIFI_HAL_TDLS_ESTABLISHED: Direct link is established + * @QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL: Direct link established using MCC + * @QCA_WIFI_HAL_TDLS_DROPPED: Direct link was established, but is now dropped + * @QCA_WIFI_HAL_TDLS_FAILED: Direct link failed + */ +typedef enum { + QCA_WIFI_HAL_TDLS_DISABLED = 1, + QCA_WIFI_HAL_TDLS_ENABLED, + QCA_WIFI_HAL_TDLS_ESTABLISHED, + QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL, + QCA_WIFI_HAL_TDLS_DROPPED, + QCA_WIFI_HAL_TDLS_FAILED +} tdls_state_t; + +typedef int (*cfg80211_exttdls_callback)(const uint8_t *mac, + uint32_t state, + int32_t reason, void *ctx); + +/** + * struct tdls_tx_tput_config_t - tdls tx throughput config + * + * @period: period + * @bytes: bytes + */ +typedef struct { + uint16_t period; + uint16_t bytes; +} tdls_tx_tput_config_t; + +/** + * struct tdls_discovery_config_t - tdls discovery config + * + * @period: period + * @tries: number of tries + */ +typedef struct { + uint16_t period; + uint16_t tries; +} tdls_discovery_config_t; + +/** + * struct tdls_rx_idle_config_t - tdls rx idle config + * + * @timeout: timeout + */ +typedef struct { + uint16_t timeout; +} tdls_rx_idle_config_t; + +/** + * struct tdls_rssi_config_t - tdls rssi config + * + * @rssi_thres: rssi_thres + */ +typedef struct { + uint16_t rssi_thres; +} tdls_rssi_config_t; + +struct _hddTdlsPeer_t; + +/** + * struct tdlsCtx_t - tdls context + * + * @peer_list: peer list + * @pAdapter: pointer to adapter + * @peerDiscoverTimer: peer discovery timer + * @peerDiscoveryTimeoutTimer: peer discovery timeout timer + * @threshold_config: threshold config + * @discovery_peer_cnt: discovery peer count + * @discovery_sent_cnt: discovery sent count + * @ap_rssi: ap rssi + * @curr_candidate: current candidate + * @implicit_setup: implicit setup work queue + * @magic: magic + * + */ +typedef struct { + struct list_head peer_list[TDLS_PEER_LIST_SIZE]; + hdd_adapter_t *pAdapter; + cdf_mc_timer_t peerDiscoveryTimeoutTimer; + tdls_config_params_t threshold_config; + int32_t discovery_peer_cnt; + uint32_t discovery_sent_cnt; + int8_t ap_rssi; + struct _hddTdlsPeer_t *curr_candidate; + struct work_struct implicit_setup; + uint32_t magic; +} tdlsCtx_t; + +/** + * struct hddTdlsPeer_t - tdls peer data + * + * @node: node + * @pHddTdlsCtx: pointer to tdls context + * @peerMac: peer mac address + * @staId: station identifier + * @rssi: rssi + * @tdls_support: tdls support + * @link_status: tdls link status + * @signature: signature + * @is_responder: is responder + * @discovery_processed: discovery processed flag + * @discovery_attempt: discovery attempt + * @tx_pkt: tx packet + * @rx_pkt: rx packet + * @uapsdQueues: uapsd queues + * @maxSp: max sp + * @isBufSta: is buffer sta + * @isOffChannelSupported: is offchannel supported flag + * @supported_channels_len: supported channels length + * @supported_channels: supported channels + * @supported_oper_classes_len: supported operation classes length + * @supported_oper_classes: supported operation classes + * @isForcedPeer: is forced peer + * @op_class_for_pref_off_chan: op class for preferred off channel + * @pref_off_chan_num: preferred off channel number + * @op_class_for_pref_off_chan_is_set: op class for preferred off channel set + * @reason: reason + * @state_change_notification: state change notification + */ +typedef struct _hddTdlsPeer_t { + struct list_head node; + tdlsCtx_t *pHddTdlsCtx; + tSirMacAddr peerMac; + uint16_t staId; + int8_t rssi; + tTDLSCapType tdls_support; + tTDLSLinkStatus link_status; + uint8_t signature; + uint8_t is_responder; + uint8_t discovery_processed; + uint16_t discovery_attempt; + uint16_t tx_pkt; + uint16_t rx_pkt; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t supported_channels_len; + uint8_t supported_channels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[SIR_MAC_MAX_SUPP_OPER_CLASSES]; + bool isForcedPeer; + uint8_t op_class_for_pref_off_chan; + uint8_t pref_off_chan_num; + uint8_t op_class_for_pref_off_chan_is_set; + tTDLSLinkReason reason; + cfg80211_exttdls_callback state_change_notification; +} hddTdlsPeer_t; + +/** + * struct tdlsConnInfo_t - tdls connection info + * + * @sessionId: Session ID + * @staId: TDLS peer station id + * @peerMac: peer mac address + */ +typedef struct { + uint8_t sessionId; + uint8_t staId; + struct cdf_mac_addr peerMac; +} tdlsConnInfo_t; + +/** + * struct tdlsInfo_t - tdls info + * + * @vdev_id: vdev id + * @tdls_state: tdls state + * @notification_interval_ms: notification interval in ms + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threshold + * @rssi_teardown_threshold: rx teardown threshold + * @rssi_delta: rssi delta + * @tdls_options: tdls options + * @peer_traffic_ind_window: peer traffic indication window + * @peer_traffic_response_timeout: peer traffic response timeout + * @puapsd_mask: puapsd mask + * @puapsd_inactivity_time: puapsd inactivity time + * @puapsd_rx_frame_threshold: puapsd rx frame threshold + */ +typedef struct { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; +} tdlsInfo_t; + +int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_extract_da(struct sk_buff *skb, uint8_t *mac); + +void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, uint8_t *mac); + +int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, + const uint8_t *mac, uint8_t tx); + +int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t staId); + +hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac, bool mutexLock); + +hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, + const uint8_t *mac); + +int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams); +hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac); + +int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, + tTDLSCapType cap); + +void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, + tTDLSLinkStatus status, + tTDLSLinkReason reason); +void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tTDLSLinkStatus linkStatus, + tTDLSLinkReason reason); + +int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, + const uint8_t *mac); + +int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrStaParams *StaParams, + bool isBufSta, bool isOffChannelSupported); + +int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, const uint8_t *mac, + int8_t rxRssi); + +int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t responder); + +int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t uSignature); + +int wlan_hdd_tdls_set_params(struct net_device *dev, + tdls_config_params_t *config); + +int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac); + +uint16_t wlan_hdd_tdls_connected_peers(hdd_adapter_t *pAdapter); + +int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, + int buflen); + +void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter, + uint32_t statusCode); + +void wlan_hdd_tdls_tncrement_peer_count(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter); + +hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, + const uint8_t *mac, uint8_t skip_self); + +int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request); + +int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request); + +void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter, + cdf_mc_timer_t *timer, + uint32_t expirationTime); +void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, + hddTdlsPeer_t *curr_peer, + uint16_t reason); + +void wlan_hdd_tdls_pre_setup_init_work(tdlsCtx_t *pHddTdlsCtx, + hddTdlsPeer_t *curr_candidate); + +int wlan_hdd_tdls_set_extctrl_param(hdd_adapter_t *pAdapter, + const uint8_t *mac, + uint32_t chan, + uint32_t max_latency, + uint32_t op_class, uint32_t min_bandwidth); +int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, const uint8_t *mac, + bool forcePeer); + +int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer); +int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + uint32_t chan, + uint32_t max_latency, + uint32_t op_class, + uint32_t min_bandwidth); +int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, int32_t *state, + int32_t *reason); +void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, + int32_t *state, int32_t *reason); +int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, + cfg80211_exttdls_callback callback); +void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited, + bool tdls_chan_swit_prohibited); + +int wlan_hdd_tdls_add_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + bool update, tCsrStaParams *StaParams); + +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper); +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper); +#endif + +#ifdef TDLS_MGMT_VERSION2 +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, u8 *peer, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len); +#endif +#endif + +void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, + hdd_context_t *hddctx); +void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx); + +hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter); +int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel); +int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset); +int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode); +int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val); + +#else +static inline void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, + hdd_context_t *hddctx) +{ +} +static inline void +wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) +{ +} +static inline void wlan_hdd_tdls_exit(hdd_adapter_t *adapter) +{ +} +#endif /* End of FEATURE_WLAN_TDLS */ + +#endif /* __HDD_TDLS_H */ diff --git a/core/hdd/inc/wlan_hdd_trace.h b/core/hdd/inc/wlan_hdd_trace.h new file mode 100644 index 0000000000..52208168d0 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_trace.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_TRACE_H__ +#define __WLAN_HDD_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF + +#undef ENUMS +#define ENUMS \ + ENUM(TRACE_CODE_HDD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETBAND_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST) \ + ENUM(TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL) \ + ENUM(TRACE_CODE_HDD_ADD_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_DEL_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CFG80211_START_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_STOP_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_CONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DISCONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_JOIN_IBSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_LEAVE_IBSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_CHANNEL) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_IFACE) \ + ENUM(TRACE_CODE_HDD_CHANGE_STATION) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCAN) \ + ENUM(TRACE_CODE_HDD_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_REMAINCHANREADYHANDLER) \ + ENUM(TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_ACTION) \ + ENUM(TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DEL_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_PMKSA) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_OPER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA) \ + ENUM(TRACE_CODE_HDD_UNSUPPORTED_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_STORE_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_CLEAR_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_ISSUE_JOIN_REQ) + +enum { +#undef ENUM +#define ENUM(enum) enum, + ENUMS +}; + +/** + * hdd_trace_event_string() - Convert trace event to string + * @code: trace event enumeration to convert + * + * Return: string representation of the input enumeration + */ +static inline const char *hdd_trace_event_string(uint32_t code) +{ + switch (code) { + default: + return "UNKNOWN"; + break; +#undef ENUM +#define ENUM(enum) CASE_RETURN_STRING(enum) + ENUMS + } +} + +#undef ENUMS +#undef ENUM + +#ifdef HDD_TRACE_RECORD +void hdd_trace_init(void); +#else +static inline void hdd_trace_init(void) {} +#endif + +#endif diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h new file mode 100644 index 0000000000..b4b29cca5a --- /dev/null +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_TX_RX_H) +#define WLAN_HDD_TX_RX_H + +/** + * + * DOC: wlan_hdd_tx_rx.h + * + * Linux HDD Tx/RX APIs + */ + +#include +#include +#include +#include "ol_txrx_osif_api.h" + +#define HDD_ETHERTYPE_802_1_X 0x888E +#define HDD_ETHERTYPE_802_1_X_FRAME_OFFSET 12 +#define HDD_ETHERTYPE_802_1_X_SIZE 2 +#ifdef FEATURE_WLAN_WAPI +#define HDD_ETHERTYPE_WAI 0x88b4 +#endif + +#define HDD_80211_HEADER_LEN 24 +#define HDD_80211_HEADER_QOS_CTL 2 +#define HDD_LLC_HDR_LEN 6 +#define HDD_FRAME_TYPE_MASK 0x0c +#define HDD_FRAME_SUBTYPE_MASK 0xf0 +#define HDD_FRAME_TYPE_DATA 0x08 +#define HDD_FRAME_TYPE_MGMT 0x00 +#define HDD_FRAME_SUBTYPE_QOSDATA 0x80 +#define HDD_FRAME_SUBTYPE_DEAUTH 0xC0 +#define HDD_FRAME_SUBTYPE_DISASSOC 0xA0 +#define HDD_DEST_ADDR_OFFSET 6 + +#define HDD_MAC_HDR_SIZE 6 + +#define HDD_PSB_CFG_INVALID 0xFF +#define HDD_PSB_CHANGED 0xFF +#define SME_QOS_UAPSD_CFG_BK_CHANGED_MASK 0xF1 +#define SME_QOS_UAPSD_CFG_BE_CHANGED_MASK 0xF2 +#define SME_QOS_UAPSD_CFG_VI_CHANGED_MASK 0xF4 +#define SME_QOS_UAPSD_CFG_VO_CHANGED_MASK 0xF8 + +#define HDD_ETH_HEADER_LEN 14 + +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +void hdd_tx_timeout(struct net_device *dev); +CDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter); +CDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter); +CDF_STATUS hdd_rx_packet_cbk(void *cds_context, cdf_nbuf_t rxBufChain, + uint8_t staId); + +#ifdef IPA_OFFLOAD +CDF_STATUS hdd_rx_mul_packet_cbk(void *cds_context, + cdf_nbuf_t rx_buf_list, uint8_t staId); +#endif /* IPA_OFFLOAD */ + +CDF_STATUS hdd_ibss_get_sta_id(hdd_station_ctx_t *pHddStaCtx, + struct cdf_mac_addr *pMacAddress, + uint8_t *staId); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume); +void hdd_tx_resume_timer_expired_handler(void *adapter_context); +void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + cdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flowControl); +void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter); +void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value); + +#else +static inline void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + return; +} +static inline void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + return; +} +static inline void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + cdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flowControl) +{ + return; +} +static inline void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter) +{ + return; +} +static inline void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wlan_hdd_log_eapol() - Function to check and extract EAPOL params + * @skb: skb data + * @event_type: One of enum wifi_connectivity_events to indicate Tx/Rx + * + * This function parses the input skb data to get the EAPOL params,if the + * packet is EAPOL and store it in the pointer passed as input + * + * Return: None + * + */ +void wlan_hdd_log_eapol(struct sk_buff *skb, + uint8_t event_type); +#else +static inline void wlan_hdd_log_eapol(struct sk_buff *skb, + uint8_t event_type) +{ + +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + +const char *hdd_reason_type_to_string(enum netif_reason_type reason); +const char *hdd_action_type_to_string(enum netif_action_type action); +void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason); + + +#endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h new file mode 100644 index 0000000000..de61e903e6 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_wext.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WEXT_IW_H__ +#define __WEXT_IW_H__ + +#include +#include +#include +#include +#include +#include +#include "cdf_event.h" + +/* + * order of parameters in addTs private ioctl + */ +#define HDD_WLAN_WMM_PARAM_HANDLE 0 +#define HDD_WLAN_WMM_PARAM_TID 1 +#define HDD_WLAN_WMM_PARAM_DIRECTION 2 +#define HDD_WLAN_WMM_PARAM_APSD 3 +#define HDD_WLAN_WMM_PARAM_USER_PRIORITY 4 +#define HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE 5 +#define HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE 6 +#define HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE 7 +#define HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE 8 +#define HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE 9 +#define HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE 10 +#define HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE 11 +#define HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE 12 +#define HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL 13 +#define HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL 14 +#define HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN 15 +#define HDD_WLAN_WMM_PARAM_ACK_POLICY 16 +#define HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL 17 +#define HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL 18 +#define HDD_WLAN_WMM_PARAM_COUNT 19 + +#define MHZ 6 + +#define WE_MAX_STR_LEN IW_PRIV_SIZE_MASK +#define WLAN_HDD_UI_BAND_AUTO 0 +#define WLAN_HDD_UI_BAND_5_GHZ 1 +#define WLAN_HDD_UI_BAND_2_4_GHZ 2 +/* SETBAND x */ +/* 012345678 */ +#define WLAN_HDD_UI_SET_BAND_VALUE_OFFSET 8 + +typedef enum { + HDD_WLAN_WMM_DIRECTION_UPSTREAM = 0, + HDD_WLAN_WMM_DIRECTION_DOWNSTREAM = 1, + HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL = 2, +} hdd_wlan_wmm_direction_e; + +typedef enum { + HDD_WLAN_WMM_POWER_SAVE_LEGACY = 0, + HDD_WLAN_WMM_POWER_SAVE_UAPSD = 1, +} hdd_wlan_wmm_power_save_e; + +typedef enum { + /* TSPEC/re-assoc done, async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS = 0, + /* no need to setup TSPEC since ACM=0 and no UAPSD desired, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD = 1, + /* no need to setup TSPEC since ACM=0 and UAPSD already exists, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING = 2, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_SETUP_PENDING = 3, + /* TSPEC/re-assoc failed, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED = 4, + /* Request rejected due to invalid params, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM = 5, + /* TSPEC request rejected since AP!=QAP, sync */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM = 6, + + /* TSPEC modification/re-assoc successful, async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS = 7, + /* TSPEC modification a no-op since ACM=0 and no change in UAPSD, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD = 8, + /* TSPEC modification a no-op since ACM=0 and requested U-APSD already exists, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING = 9, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_MODIFY_PENDING = 10, + /* TSPEC modification failed, prev TSPEC in effect, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED = 11, + /* TSPEC modification request rejected due to invalid params, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM = 12, + + /* TSPEC release successful, sync and also async */ + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS = 13, + /* TSPEC release pending, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_PENDING = 14, + /* TSPEC release failed, sync + async */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED = 15, + /* TSPEC release rejected due to invalid params, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM = 16, + /* TSPEC modified due to the mux'ing of requests on ACs, async */ + + HDD_WLAN_WMM_STATUS_MODIFIED = 17, + /* TSPEC revoked by AP, async */ + HDD_WLAN_WMM_STATUS_LOST = 18, + /* some internal failure like memory allocation failure, etc, sync */ + HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE = 19, + + /* U-APSD failed during setup but OTA setup (whether TSPEC exchnage or */ + /* re-assoc) was done so app should release this QoS, async */ + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED = 20, + /* U-APSD failed during modify, but OTA setup (whether TSPEC exchnage or */ + /* re-assoc) was done so app should release this QoS, async */ + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED = 21 +} hdd_wlan_wmm_status_e; + +/** TS Info Ack Policy */ +typedef enum { + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK = 0, + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 1, +} hdd_wlan_wmm_ts_info_ack_policy_e; + +/** Maximum Length of WPA/RSN IE */ +#define MAX_WPA_RSN_IE_LEN 40 + +/** Maximum Number of WEP KEYS */ +#define MAX_WEP_KEYS 4 + +/** Ether Address Length */ +#define ETHER_ADDR_LEN 6 + +/** Enable 11d */ +#define ENABLE_11D 1 + +/** Disable 11d */ +#define DISABLE_11D 0 + +/* + refer wpa.h in wpa supplicant code for REASON_MICHAEL_MIC_FAILURE + + supplicant sets REASON_MICHAEL_MIC_FAILURE as the reason code when it sends the MLME deauth IOCTL + for TKIP counter measures + */ +#define HDD_REASON_MICHAEL_MIC_FAILURE 14 + +/* + * These are for TLV fields in WPS IE + */ +#define HDD_WPS_UUID_LEN 16 +#define HDD_WPS_ELEM_VERSION 0x104a +#define HDD_WPS_ELEM_REQUEST_TYPE 0x103a +#define HDD_WPS_ELEM_CONFIG_METHODS 0x1008 +#define HDD_WPS_ELEM_UUID_E 0x1047 +#define HDD_WPS_ELEM_PRIMARY_DEVICE_TYPE 0x1054 +#define HDD_WPS_ELEM_RF_BANDS 0x103c +#define HDD_WPS_ELEM_ASSOCIATION_STATE 0x1002 +#define HDD_WPS_ELEM_CONFIGURATION_ERROR 0x1009 +#define HDD_WPS_ELEM_DEVICE_PASSWORD_ID 0x1012 + +#define HDD_WPA_ELEM_VENDOR_EXTENSION 0x1049 + +#define HDD_WPS_MANUFACTURER_LEN 64 +#define HDD_WPS_MODEL_NAME_LEN 32 +#define HDD_WPS_MODEL_NUM_LEN 32 +#define HDD_WPS_SERIAL_NUM_LEN 32 +#define HDD_WPS_DEVICE_OUI_LEN 4 +#define HDD_WPS_DEVICE_NAME_LEN 32 + +#define HDD_WPS_ELEM_WPS_STATE 0x1044 +#define HDD_WPS_ELEM_APSETUPLOCK 0x1057 +#define HDD_WPS_ELEM_SELECTEDREGISTRA 0x1041 +#define HDD_WPS_ELEM_RSP_TYPE 0x103B +#define HDD_WPS_ELEM_MANUFACTURER 0x1021 +#define HDD_WPS_ELEM_MODEL_NAME 0x1023 +#define HDD_WPS_ELEM_MODEL_NUM 0x1024 +#define HDD_WPS_ELEM_SERIAL_NUM 0x1042 +#define HDD_WPS_ELEM_DEVICE_NAME 0x1011 +#define HDD_WPS_ELEM_REGISTRA_CONF_METHODS 0x1053 + +#define HDD_RTSCTS_EN_MASK 0xF +#define HDD_RTSCTS_ENABLE 1 +#define HDD_CTS_ENABLE 2 + +#define WPS_OUI_TYPE "\x00\x50\xf2\x04" +#define WPS_OUI_TYPE_SIZE 4 + +#define SS_OUI_TYPE "\x00\x16\x32" +#define SS_OUI_TYPE_SIZE 3 + +#define P2P_OUI_TYPE "\x50\x6f\x9a\x09" +#define P2P_OUI_TYPE_SIZE 4 + +#define HS20_OUI_TYPE "\x50\x6f\x9a\x10" +#define HS20_OUI_TYPE_SIZE 4 + +#define OSEN_OUI_TYPE "\x50\x6f\x9a\x12" +#define OSEN_OUI_TYPE_SIZE 4 + +#ifdef WLAN_FEATURE_WFD +#define WFD_OUI_TYPE "\x50\x6f\x9a\x0a" +#define WFD_OUI_TYPE_SIZE 4 +#endif + +typedef enum { + eWEXT_WPS_OFF = 0, + eWEXT_WPS_ON = 1, +} hdd_wps_mode_e; + +/* + * This structure contains the interface level (granularity) + * configuration information in support of wireless extensions. + */ +typedef struct hdd_wext_state_s { + /** The CSR "desired" Profile */ + tCsrRoamProfile roamProfile; + + /** BSSID to which connect request is received */ + struct cdf_mac_addr req_bssId; + + /** The association status code */ + uint32_t statusCode; + + /** wpa version WPA/WPA2/None*/ + int32_t wpaVersion; + + /**WPA or RSN IE*/ + uint8_t WPARSNIE[MAX_WPA_RSN_IE_LEN]; + + /**gen IE */ + tSirAddie genIE; + + /**Additional IE for assoc */ + tSirAddie assocAddIE; + + /**auth key mgmt */ + int32_t authKeyMgmt; + + /* cdf event */ + cdf_event_t hdd_cdf_event; + + cdf_event_t scanevent; + + /**Counter measure state, Started/Stopped*/ + bool mTKIPCounterMeasures; + + /**Completion Variable*/ + struct completion completion_var; + +#ifdef FEATURE_WLAN_ESE + /* ESE state variables */ + bool isESEConnection; + eCsrAuthType collectedAuthType; /* Collected from ALL SIOCSIWAUTH Ioctls. Will be negotiatedAuthType - in tCsrProfile */ +#endif +} hdd_wext_state_t; + +typedef struct ccp_freq_chan_map_s { + /* List of frequencies */ + uint32_t freq; + uint32_t chan; +} hdd_freq_chan_map_t; + +/* Packet Types. */ +#define WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 +#define WLAN_KEEP_ALIVE_NULL_PKT 1 + +/* Offload request. */ +typedef struct { + uint8_t packetType; + uint32_t timePeriod; + uint8_t hostIpv4Addr[4]; + uint8_t destIpv4Addr[4]; + uint8_t destMacAddr[ETH_ALEN]; + uint8_t bssIdx; +} tKeepAliveRequest, *tpKeepAliveRequest; + +#define wlan_hdd_get_wps_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE, ie, ie_len) + +#define wlan_hdd_get_p2p_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE, ie, ie_len) + +#ifdef WLAN_FEATURE_WFD +#define wlan_hdd_get_wfd_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE, ie, ie_len) +#endif + +extern int hdd_unregister_wext(struct net_device *dev); +extern int hdd_register_wext(struct net_device *dev); +extern int hdd_wlan_get_freq(uint32_t chan, uint32_t *freq); +extern int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu); +extern int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu); +extern void hdd_wlan_get_version(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu, char *extra); + +extern void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length, + char *buffer, uint16_t buf_len); + +extern int iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra); + +extern int iw_set_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int hdd_priv_get_data(struct iw_point *p_priv_data, + union iwreq_data *wrqu); + +extern void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len); + +extern CDF_STATUS wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, + tSirMacAddr macAddress); +void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter); + +uint8_t *wlan_hdd_get_vendor_oui_ie_ptr(uint8_t *oui, uint8_t oui_size, + uint8_t *ie, int ie_len); + +CDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter); + +CDF_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter); + +CDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value); + +CDF_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, int8_t *snr); + +#ifdef FEATURE_WLAN_TDLS +CDF_STATUS iw_set_tdls_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra, int nOffset); +#endif + +void wlan_hdd_change_country_code_callback(void *pAdapter); + +int hdd_set_band(struct net_device *dev, u8 ui_band); +int hdd_set_band_helper(struct net_device *dev, const char *command); +int wlan_hdd_update_phymode(struct net_device *net, tHalHandle hal, + int new_phymode, hdd_context_t *phddctx); + +int wlan_hdd_get_temperature(hdd_adapter_t *pAdapter, int *temperature); +int wlan_hdd_get_link_speed(hdd_adapter_t *sta_adapter, uint32_t *link_speed); +#endif /* __WEXT_IW_H__ */ diff --git a/core/hdd/inc/wlan_hdd_wmm.h b/core/hdd/inc/wlan_hdd_wmm.h new file mode 100644 index 0000000000..864a1e73fc --- /dev/null +++ b/core/hdd/inc/wlan_hdd_wmm.h @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2011-2012,2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_WMM_H +#define _WLAN_HDD_WMM_H + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include + +/*Maximum number of ACs */ +#define WLAN_MAX_AC 4 + + +/* Preprocessor Definitions and Constants */ + +/* #define HDD_WMM_DEBUG 1 */ + +#define HDD_WMM_CTX_MAGIC 0x574d4d58 /* "WMMX" */ + +#define HDD_WMM_HANDLE_IMPLICIT 0xFFFFFFFF + +#define HDD_WLAN_INVALID_STA_ID 0xFF + +/* Type Declarations */ + +/** + * enum hdd_wmm_classification: types of classification supported + */ +typedef enum hdd_wmm_classification { + HDD_WMM_CLASSIFICATION_DSCP = 0, + HDD_WMM_CLASSIFICATION_802_1Q = 1 +} hdd_wmm_classification_t; + +/** + * enum hdd_wmm_user_mode - WMM modes of operation + * + * @HDD_WMM_USER_MODE_AUTO: STA can associate with any AP, & HDD looks at + * the SME notification after association to find out if associated + * with QAP and acts accordingly + * @HDD_WMM_USER_MODE_QBSS_ONLY - SME will add the extra logic to make sure + * STA associates with a QAP only + * @HDD_WMM_USER_MODE_NO_QOS - SME will not join a QoS AP, unless the phy + * mode setting says "Auto". In that case, STA is free to join 11n AP. + * Although from HDD point of view, it will not be doing any packet + * classifications. + */ +typedef enum hdd_wmm_user_mode { + HDD_WMM_USER_MODE_AUTO = 0, + HDD_WMM_USER_MODE_QBSS_ONLY = 1, + HDD_WMM_USER_MODE_NO_QOS = 2, +} hdd_wmm_user_mode_t; + +/* UAPSD Mask bits */ +/* (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) */ +#define HDD_AC_VO 0x1 +#define HDD_AC_VI 0x2 +#define HDD_AC_BK 0x4 +#define HDD_AC_BE 0x8 + +/** + * struct hdd_wmm_qos_context - HDD WMM QoS Context + * + * This structure holds the context for a single flow which has either + * been confgured explicitly from userspace or implicitly via the + * Implicit QoS feature. + * + * @node: list node which can be used to put the context into a list + * of contexts + * @handle: identifer which uniquely identifies this context to userspace + * @qosFlowID: identifier which uniquely identifies this flow to SME + * @pAdapter: adapter upon which this flow was configured + * @acType: access category for this flow + * @lastStatus: the status of the last operation performed on this flow by SME + * @wmmAcSetupImplicitQos: work structure used for deferring implicit QoS work + * from softirq context to thread context + * @magic: magic number used to verify that this is a valid context when + * referenced anonymously + */ +typedef struct hdd_wmm_qos_context { + struct list_head node; + uint32_t handle; + uint32_t qosFlowId; + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wlan_wmm_status_e lastStatus; + struct work_struct wmmAcSetupImplicitQos; + uint32_t magic; + bool is_inactivity_timer_running; +} hdd_wmm_qos_context_t; + +/** + * struct hdd_wmm_ac_status - WMM related per-AC state & status info + * @wmmAcAccessRequired - does the AP require access to this AC? + * @wmmAcAccessNeeded - does the worker thread need to acquire access to + * this AC? + * @wmmAcAccessPending - is implicit QoS negotiation currently taking place? + * @wmmAcAccessFailed - has implicit QoS negotiation already failed? + * @wmmAcAccessGranted - has implicit QoS negotiation already succeeded? + * @wmmAcAccessAllowed - is access to this AC allowed, either because we + * are not doing WMM, we are not doing implicit QoS, implict QoS has + * completed, or explicit QoS has completed? + * @wmmAcTspecValid - is the wmmAcTspecInfo valid? + * @wmmAcUapsdInfoValid - are the wmmAcUapsd* fields valid? + * @wmmAcTspecInfo - current (possibly aggregate) Tspec for this AC + * @wmmAcIsUapsdEnabled - is UAPSD enabled on this AC? + * @wmmAcUapsdServiceInterval - service interval for this AC + * @wmmAcUapsdSuspensionInterval - suspension interval for this AC + * @wmmAcUapsdDirection - direction for this AC + * @wmmInactivityTime - inactivity time for this AC + * @wmmPrevTrafficCnt - TX counter used for inactivity detection + * @wmmInactivityTimer - timer used for inactivity detection + */ +typedef struct hdd_wmm_ac_status { + bool wmmAcAccessRequired; + bool wmmAcAccessNeeded; + bool wmmAcAccessPending; + bool wmmAcAccessFailed; + bool wmmAcAccessGranted; + bool wmmAcAccessAllowed; + bool wmmAcTspecValid; + bool wmmAcUapsdInfoValid; + sme_QosWmmTspecInfo wmmAcTspecInfo; + bool wmmAcIsUapsdEnabled; + uint32_t wmmAcUapsdServiceInterval; + uint32_t wmmAcUapsdSuspensionInterval; + sme_QosWmmDirType wmmAcUapsdDirection; + +#ifdef FEATURE_WLAN_ESE + uint32_t wmmInactivityTime; + uint32_t wmmPrevTrafficCnt; + cdf_mc_timer_t wmmInactivityTimer; +#endif + +} hdd_wmm_ac_status_t; + +/** + * struct hdd_wmm_status - WMM status maintained per-adapter + * @wmmContextList - list of WMM contexts active on the adapter + * @wmmLock - mutex used for exclusive access to this adapter's WMM status + * @wmmACStatus - per-AC WMM status + * @wmmQap - is this connected to a QoS-enabled AP? + * @wmmQosConnection - is this a QoS connection? + */ +typedef struct hdd_wmm_status { + struct list_head wmmContextList; + struct mutex wmmLock; + hdd_wmm_ac_status_t wmmAcStatus[WLAN_MAX_AC]; + bool wmmQap; + bool wmmQosConnection; +} hdd_wmm_status_t; + +extern const uint8_t hdd_qdisc_ac_to_tl_ac[]; +extern const uint8_t hdd_wmm_up_to_ac_map[]; +extern const uint8_t hdd_linux_up_to_ac_map[]; + +#define WLAN_HDD_MAX_DSCP 0x3f + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @pAdapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr); + +/** + * hdd_wmm_init() - initialize the WMM DSCP configuation + * @pAdapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @pAdapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuation and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_close() - WMM close function + * @pAdapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb); + +/** + * hdd_hostapd_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif +); + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @pAdapter: [in] pointer to adapter structure + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType); + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @pAdapter: [in] pointer to adapter context + * @acType: [in] WMM AC type of OS packet + * @pGranted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType, bool *pGranted); + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @pAdapter: [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType); + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @pAdapter : [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType : [in] type of BSS + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType); + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @pAdapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter, + uint8_t *pUapsdMask); + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @pAdapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_addts() - Function which will add a traffic spec at the + * request of an application + * + * @pAdapter : [in] pointer to adapter context + * @handle : [in] handle to uniquely identify a TS + * @pTspec : [in] pointer to the traffic spec + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter, + uint32_t handle, + sme_QosWmmTspecInfo *pTspec); + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle); + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, + uint32_t handle); +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @pAdapter: [in] pointer to Adapter context + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter); + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter); +#endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/core/hdd/inc/wlan_hdd_wowl.h b/core/hdd/inc/wlan_hdd_wowl.h new file mode 100644 index 0000000000..3230f6a787 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_wowl.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_WOWL_H +#define _WLAN_HDD_WOWL_H + +/** + * DOC: wlan_hdd_wowl + * + * This module houses all the logic for WOWL in HDD. + * + * It provides the following APIs + * + * - Ability to enable/disable following WoWL modes + * 1) Magic packet (MP) mode + * 2) Pattern Byte Matching (PBM) mode + * - Ability to add/remove patterns for PBM + * + * A Magic Packet is a packet that contains 6 0xFFs followed by 16 + * contiguous copies of the receiving NIC's Ethernet address. There is + * no API to configure Magic Packet Pattern. + * + * Wakeup pattern (used for PBM) is defined as following: + * typedef struct + * { + * U8 PatternSize; // Non-Zero pattern size + * U8 PatternMaskSize; // Non-zero pattern mask size + * U8 PatternMask[PatternMaskSize]; // Pattern mask + * U8 Pattern[PatternSize]; // Pattern + * } hdd_wowl_ptrn_t; + * + * PatternSize and PatternMaskSize indicate size of the variable + * length Pattern and PatternMask. PatternMask indicates which bytes + * of an incoming packet should be compared with corresponding bytes + * in the pattern. + * + * Maximum allowed pattern size is 128 bytes. Maximum allowed + * PatternMaskSize is 16 bytes. + * + * Maximum number of patterns that can be configured is 8 + * + * HDD will add following 2 commonly used patterns for PBM by default: + * 1) ARP Broadcast Pattern + * 2) Unicast Pattern + * + * However note that WoWL will not be enabled by default by HDD. WoWL + * needs to enabled explcitly by exercising the iwpriv command. + * + * HDD will expose an API that accepts patterns as Hex string in the + * following format: + * "PatternSize:PatternMaskSize:PatternMask:Pattern" + * + * Multiple patterns can be specified by deleimiting each pattern with + * the ';' token: + * "PatternSize1:PatternMaskSize1:PatternMask1:Pattern1;PatternSize2:..." + * + * Patterns can be configured dynamically via iwpriv cmd or statically + * via qcom_cfg.ini file + * + * PBM (when enabled) can perform filtering on unicast data or + * broadcast data or both. These configurations are part of factory + * defaults (cfg.dat) and the deafult behavior is to perform filtering + * on both unicast and data frames. + * + * MP filtering (when enabled) is performed ALWAYS on both unicast and + * broadcast data frames. + * + * Mangement frames are not subjected to WoWL filtering and are + * discarded when WoWL is enabled. + * + * Whenever a patern match succeeds, RX path is restored and packets + * (both management and data) will be pushed to the host from that + * point onwards. Therefore, exit from WoWL is implicit and happens + * automatically when the first packet match succeeds. + * + * WoWL works on top of BMPS. So when WoWL is requested, SME will + * attempt to put the device in BMPS mode (if not already in BMPS). If + * attempt to BMPS fails, request for WoWL will be rejected. + */ + +#include + +#define WOWL_PTRN_MAX_SIZE 146 +#define WOWL_PTRN_MASK_MAX_SIZE 19 +#define WOWL_MAX_PTRNS_ALLOWED CFG_MAX_WOW_FILTERS_MAX + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn); + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn); + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask); + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx); + +/** + * hdd_enter_wowl() - Function which will enable WoWL. At least one + * of MP and PBM must be enabled + * @pAdapter: pointer to the adapter + * @enable_mp: Whether to enable magic packet WoWL mode + * @enable_pbm: Whether to enable pattern byte matching WoWL mode + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_enter_wowl(hdd_adapter_t *pAdapter, bool enable_mp, bool enable_pbm); + +/** + * hdd_exit_wowl() - Function which will disable WoWL + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_exit_wowl(hdd_adapter_t *pAdapter); + +/** + * hdd_init_wowl() - Init function which will initialize the WoWL module + * and perform any required initial configuration + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_init_wowl(hdd_adapter_t *pAdapter); + +#endif /* #ifndef _WLAN_HDD_WOWL_H */ diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c new file mode 100644 index 0000000000..ea597dbe04 --- /dev/null +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -0,0 +1,5426 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_assoc.c + * + * WLAN Host Device Driver implementation + * + */ + +#include "wlan_hdd_includes.h" +#include +#include "dot11f.h" +#include "wlan_hdd_power.h" +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "csr_inside_api.h" +#include "wlan_hdd_p2p.h" +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif +#include "sme_api.h" +#include "wlan_hdd_hostapd.h" +#include +#include +#include "cds_concurrency.h" +#include "sme_power_save_api.h" +#include "ol_txrx_ctrl_api.h" +#include "ol_txrx_types.h" + +/* These are needed to recognize WPA and RSN suite types */ +#define HDD_WPA_OUI_SIZE 4 +#define HDD_RSN_OUI_SIZE 4 +uint8_t ccp_wpa_oui00[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x00 }; +uint8_t ccp_wpa_oui01[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x01 }; +uint8_t ccp_wpa_oui02[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t ccp_wpa_oui03[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x03 }; +uint8_t ccp_wpa_oui04[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x04 }; +uint8_t ccp_wpa_oui05[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x05 }; + +#ifdef FEATURE_WLAN_ESE +/* CCKM */ +uint8_t ccp_wpa_oui06[HDD_WPA_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +/* CCKM */ +uint8_t ccp_rsn_oui06[HDD_RSN_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +#endif /* FEATURE_WLAN_ESE */ + +/* group cipher */ +uint8_t ccp_rsn_oui00[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x00 }; + +/* WEP-40 or RSN */ +uint8_t ccp_rsn_oui01[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x01 }; + +/* TKIP or RSN-PSK */ +uint8_t ccp_rsn_oui02[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x02 }; + +/* Reserved */ +uint8_t ccp_rsn_oui03[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x03 }; + +/* AES-CCMP */ +uint8_t ccp_rsn_oui04[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x04 }; + +/* WEP-104 */ +uint8_t ccp_rsn_oui05[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; + +#ifdef WLAN_FEATURE_11W +/* RSN-PSK-SHA256 */ +uint8_t ccp_rsn_oui07[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x06 }; + +/* RSN-8021X-SHA256 */ +uint8_t ccp_rsn_oui08[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; +#endif + +#if defined(WLAN_FEATURE_VOWIFI_11R) +/* Offset where the EID-Len-IE, start. */ +#define FT_ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2) */ +#define FT_ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */ +#endif + +#define BEACON_FRAME_IES_OFFSET 12 +#define HDD_PEER_AUTHORIZE_WAIT 10 + +/** + * hdd_conn_set_authenticated() - set authentication state + * @pAdapter: pointer to the adapter + * @authState: authentication state + * + * This function updates the global HDD station context + * authentication state. + * + * Return: none + */ +static void +hdd_conn_set_authenticated(hdd_adapter_t *pAdapter, uint8_t authState) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ + hddLog(LOG1, + FL("Authenticated state Changed from oldState:%d to State:%d"), + pHddStaCtx->conn_info.uIsAuthenticated, authState); + pHddStaCtx->conn_info.uIsAuthenticated = authState; + + /* Check is pending ROC request or not when auth state changed */ + schedule_delayed_work(&pHddCtx->roc_req_work, 0); +} + +/** + * hdd_conn_set_connection_state() - set connection state + * @pAdapter: pointer to the adapter + * @connState: connection state + * + * This function updates the global HDD station context connection state. + * + * Return: none + */ +void hdd_conn_set_connection_state(hdd_adapter_t *pAdapter, + eConnectionState connState) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ + hddLog(LOG1, FL("ConnectionState Changed from oldState:%d to State:%d"), + pHddStaCtx->conn_info.connState, connState); + pHddStaCtx->conn_info.connState = connState; + + /* Check is pending ROC request or not when connection state changed */ + schedule_delayed_work(&pHddCtx->roc_req_work, 0); +} + +/** + * hdd_conn_get_connection_state() - get connection state + * @pAdapter: pointer to the adapter + * @pConnState: pointer to connection state + * + * This function updates the global HDD station context connection state. + * + * Return: true if (Infra Associated or IBSS Connected) + * and sets output parameter pConnState; + * false otherwise + */ +static inline bool hdd_conn_get_connection_state(hdd_station_ctx_t *pHddStaCtx, + eConnectionState *pConnState) +{ + bool fConnected = false; + eConnectionState connState; + + /* get the connection state. */ + connState = pHddStaCtx->conn_info.connState; + + if (eConnectionState_Associated == connState || + eConnectionState_IbssConnected == connState || + eConnectionState_IbssDisconnected == connState) { + fConnected = true; + } + + if (pConnState) + *pConnState = connState; + + return fConnected; +} + +/** + * hdd_is_connecting() - Function to check connection progress + * @hdd_sta_ctx: pointer to global HDD Station context + * + * Return: true if connecting, false otherwise + */ +bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx) +{ + return hdd_sta_ctx->conn_info.connState == + eConnectionState_Connecting; +} + +/** + * hdd_conn_is_connected() - Function to check connection status + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_conn_is_connected(hdd_station_ctx_t *pHddStaCtx) +{ + return hdd_conn_get_connection_state(pHddStaCtx, NULL); +} + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: eCSR_BAND_24 or eCSR_BAND_5G based on current AP connection + * eCSR_BAND_ALL if not connected + */ +eCsrBand hdd_conn_get_connected_band(hdd_station_ctx_t *pHddStaCtx) +{ + uint8_t staChannel = 0; + + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) + staChannel = pHddStaCtx->conn_info.operationChannel; + + if (staChannel > 0 && staChannel < 14) + return eCSR_BAND_24; + else if (staChannel >= 36 && staChannel <= 184) + return eCSR_BAND_5G; + else /* If station is not connected return as eCSR_BAND_ALL */ + return eCSR_BAND_ALL; +} + +/** + * hdd_conn_get_connected_cipher_algo() - get current connection cipher type + * @pHddStaCtx: pointer to global HDD Station context + * @pConnectedCipherAlgo: pointer to connected cipher algo + * + * Return: false if any errors encountered, true otherwise + */ +static inline bool +hdd_conn_get_connected_cipher_algo(hdd_station_ctx_t *pHddStaCtx, + eCsrEncryptionType *pConnectedCipherAlgo) +{ + bool fConnected = false; + + fConnected = hdd_conn_get_connection_state(pHddStaCtx, NULL); + + if (pConnectedCipherAlgo) + *pConnectedCipherAlgo = pHddStaCtx->conn_info.ucEncryptionType; + + return fConnected; +} + +/** + * hdd_conn_get_connected_bss_type() - get current bss type + * @pHddStaCtx: pointer to global HDD Station context + * @pConnectedBssType: pointer to connected bss type + * + * Return: false if any errors encountered, true otherwise + */ +inline bool +hdd_conn_get_connected_bss_type(hdd_station_ctx_t *pHddStaCtx, + eMib_dot11DesiredBssType *pConnectedBssType) +{ + bool fConnected = false; + + fConnected = hdd_conn_get_connection_state(pHddStaCtx, NULL); + + if (pConnectedBssType) { + *pConnectedBssType = + pHddStaCtx->conn_info.connDot11DesiredBssType; + } + + return fConnected; +} + +/** + * hdd_conn_save_connected_bss_type() - set connected bss type + * @pHddStaCtx: pointer to global HDD Station context + * @csr_roamBssType: bss type + * + * Return: none + */ +static inline void +hdd_conn_save_connected_bss_type(hdd_station_ctx_t *pHddStaCtx, + eCsrRoamBssType csr_roamBssType) +{ + switch (csr_roamBssType) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + pHddStaCtx->conn_info.connDot11DesiredBssType = + eMib_dot11DesiredBssType_infrastructure; + break; + + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + pHddStaCtx->conn_info.connDot11DesiredBssType = + eMib_dot11DesiredBssType_independent; + break; + + /** We will never set the BssType to 'any' when attempting a connection + so CSR should never send this back to us.*/ + case eCSR_BSS_TYPE_ANY: + default: + CDF_ASSERT(0); + break; + } +} + +/** + * hdd_conn_save_connect_info() - save current connection information + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @eBssType: bss type + * + * Return: none + */ +static void +hdd_conn_save_connect_info(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo, + eCsrRoamBssType eBssType) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + eCsrEncryptionType encryptType = eCSR_ENCRYPT_TYPE_NONE; + + CDF_ASSERT(pRoamInfo); + + if (pRoamInfo) { + /* Save the BSSID for the connection */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) { + CDF_ASSERT(pRoamInfo->pBssDesc); + cdf_copy_macaddr(&pHddStaCtx->conn_info.bssId, + &pRoamInfo->bssid); + + /* + * Save the Station ID for this station from + * the 'Roam Info'. For IBSS mode, staId is + * assigned in NEW_PEER_IND. For reassoc, + * the staID doesn't change and it may be invalid + * in this structure so no change here. + */ + if (!pRoamInfo->fReassocReq) { + pHddStaCtx->conn_info.staId[0] = + pRoamInfo->staId; + } + } else if (eCSR_BSS_TYPE_IBSS == eBssType) { + cdf_copy_macaddr(&pHddStaCtx->conn_info.bssId, + &pRoamInfo->bssid); + } else { + /* + * can't happen. We need a valid IBSS or Infra setting + * in the BSSDescription or we can't function. + */ + CDF_ASSERT(0); + } + + /* notify WMM */ + hdd_wmm_connect(pAdapter, pRoamInfo, eBssType); + + if (!pRoamInfo->u.pConnectedProfile) { + CDF_ASSERT(pRoamInfo->u.pConnectedProfile); + } else { + /* Get Multicast Encryption Type */ + encryptType = + pRoamInfo->u.pConnectedProfile->mcEncryptionType; + pHddStaCtx->conn_info.mcEncryptionType = encryptType; + /* Get Unicast Encryption Type */ + encryptType = + pRoamInfo->u.pConnectedProfile->EncryptionType; + pHddStaCtx->conn_info.ucEncryptionType = encryptType; + + pHddStaCtx->conn_info.authType = + pRoamInfo->u.pConnectedProfile->AuthType; + + pHddStaCtx->conn_info.operationChannel = + pRoamInfo->u.pConnectedProfile->operationChannel; + + /* Save the ssid for the connection */ + cdf_mem_copy(&pHddStaCtx->conn_info.SSID.SSID, + &pRoamInfo->u.pConnectedProfile->SSID, + sizeof(tSirMacSSid)); + + /* Save dot11mode in which STA associated to AP */ + pHddStaCtx->conn_info.dot11Mode = + pRoamInfo->u.pConnectedProfile->dot11Mode; + + pHddStaCtx->conn_info.proxyARPService = + pRoamInfo->u.pConnectedProfile->proxyARPService; + } + } + /* save the connected BssType */ + hdd_conn_save_connected_bss_type(pHddStaCtx, eBssType); +} + +#if defined(WLAN_FEATURE_VOWIFI_11R) +/** + * hdd_send_ft_assoc_response() - send fast transition assoc response + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the 11R key information to the supplicant. Only then can the supplicant + * generate the PMK-R1. (BTW, the ESE supplicant also needs the Assoc Resp IEs + * for the same purpose.) + * + * Mainly the Assoc Rsp IEs are passed here. For the IMDA this contains the + * R1KHID, R0KHID and the MDID. For FT, this consists of the Reassoc Rsp FTIEs. + * This is the Assoc Response. + * + * Return: none + */ +static void +hdd_send_ft_assoc_response(struct net_device *dev, + hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + char *buff; + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hddLog(LOGE, + FL("pCsrRoamInfo->nAssocRspLength=%d"), + (int)pCsrRoamInfo->nAssocRspLength); + return; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) { + hddLog(LOGE, FL("AssocReq or AssocRsp is NULL")); + return; + } + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hddLog(LOG1, FL("AssocRsp is now at %02x%02x"), + (unsigned int)pFTAssocRsp[0], (unsigned int)pFTAssocRsp[1]); + + /* We need to send the IEs to the supplicant. */ + buff = kmalloc(IW_GENERIC_IE_MAX, GFP_ATOMIC); + if (buff == NULL) { + hddLog(LOGE, FL("kmalloc unable to allocate memory")); + return; + } + /* Send the Assoc Resp, the supplicant needs this for initial Auth. */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + wrqu.data.length = len; + memset(buff, 0, IW_GENERIC_IE_MAX); + memcpy(buff, pFTAssocRsp, len); + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, buff); + + kfree(buff); +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +#ifdef WLAN_FEATURE_VOWIFI_11R +/** + * hdd_send_ft_event() - send fast transition event + * @pAdapter: pointer to adapter + * + * Send the FTIEs, RIC IEs during FT. This is eventually used to send the + * FT events to the supplicant. At the reception of Auth2 we send the RIC + * followed by the auth response IEs to the supplicant. + * Once both are received in the supplicant, an FT event is generated + * to the supplicant. + * + * Return: none + */ +static void hdd_send_ft_event(hdd_adapter_t *pAdapter) +{ + uint16_t auth_resp_len = 0; + uint32_t ric_ies_length = 0; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + +#if defined(KERNEL_SUPPORT_11R_CFG80211) + struct cfg80211_ft_event_params ftEvent; + uint8_t ftIe[DOT11F_IE_FTINFO_MAX_LEN]; + uint8_t ricIe[DOT11F_IE_RICDESCRIPTOR_MAX_LEN]; + struct net_device *dev = pAdapter->dev; +#else + char *buff; + union iwreq_data wrqu; + uint16_t str_len; +#endif + +#if defined(KERNEL_SUPPORT_11R_CFG80211) + cdf_mem_zero(ftIe, DOT11F_IE_FTINFO_MAX_LEN); + cdf_mem_zero(ricIe, DOT11F_IE_RICDESCRIPTOR_MAX_LEN); + + sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId, (u8 *) ricIe, + DOT11F_IE_RICDESCRIPTOR_MAX_LEN, &ric_ies_length); + if (ric_ies_length == 0) { + hddLog(LOGW, + FL("RIC IEs is of length 0 not sending RIC Information for now")); + } + + ftEvent.ric_ies = ricIe; + ftEvent.ric_ies_len = ric_ies_length; + hddLog(LOG1, FL("RIC IEs is of length %d"), (int)ric_ies_length); + + sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) ftIe, DOT11F_IE_FTINFO_MAX_LEN, + &auth_resp_len); + + if (auth_resp_len == 0) { + hddLog(LOGE, FL("AuthRsp FTIES is of length 0")); + return; + } + + sme_set_ft_pre_auth_state(pHddCtx->hHal, pAdapter->sessionId, true); + + ftEvent.target_ap = ftIe; + + ftEvent.ies = (u8 *) (ftIe + CDF_MAC_ADDR_SIZE); + ftEvent.ies_len = auth_resp_len - CDF_MAC_ADDR_SIZE; + + hddLog(LOG1, FL("ftEvent.ies_len %zu"), ftEvent.ies_len); + hddLog(LOG1, FL("ftEvent.ric_ies_len %zu"), ftEvent.ric_ies_len); + hddLog(LOG1, FL("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x"), + ftEvent.target_ap[0], ftEvent.target_ap[1], + ftEvent.target_ap[2], ftEvent.target_ap[3], ftEvent.target_ap[4], + ftEvent.target_ap[5]); + + (void)cfg80211_ft_event(dev, &ftEvent); + +#else + /* We need to send the IEs to the supplicant */ + buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC); + if (buff == NULL) { + hddLog(LOGE, FL("kmalloc unable to allocate memory")); + return; + } + cdf_mem_zero(buff, IW_CUSTOM_MAX); + + /* Sme needs to send the RIC IEs first */ + str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX); + sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) &(buff[str_len]), (IW_CUSTOM_MAX - str_len), + &ric_ies_length); + if (ric_ies_length == 0) { + hddLog(LOGW, + FL("RIC IEs is of length 0 not sending RIC Information for now")); + } else { + wrqu.data.length = str_len + ric_ies_length; + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + } + + /* Sme needs to provide the Auth Resp */ + cdf_mem_zero(buff, IW_CUSTOM_MAX); + str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX); + sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) &buff[str_len], + (IW_CUSTOM_MAX - str_len), &auth_resp_len); + + if (auth_resp_len == 0) { + kfree(buff); + hddLog(LOGE, FL("AuthRsp FTIES is of length 0")); + return; + } + + wrqu.data.length = str_len + auth_resp_len; + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + + kfree(buff); +#endif +} + +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_send_new_ap_channel_info() - send new ap channel info + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the ESE required "new AP Channel info" to the supplicant. + * (This keeps the supplicant "up to date" on the current channel.) + * + * The current (new AP) channel information is passed in. + * + * Return: none + */ +static void +hdd_send_new_ap_channel_info(struct net_device *dev, hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + tSirBssDescription *descriptor = pCsrRoamInfo->pBssDesc; + + if (descriptor == NULL) { + hddLog(LOGE, FL("pCsrRoamInfo->pBssDesc(%p)"), descriptor); + return; + } + /* + * Send the Channel event, the supplicant needs this to generate + * the Adjacent AP report. + */ + hddLog(LOGW, FL("Sending up an SIOCGIWFREQ, channelId(%d)"), + descriptor->channelId); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.freq.m = descriptor->channelId; + wrqu.freq.e = 0; + wrqu.freq.i = 0; + wireless_send_event(pAdapter->dev, SIOCGIWFREQ, &wrqu, NULL); +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_send_update_beacon_ies_event() - send update beacons ie event + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void +hdd_send_update_beacon_ies_event(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + u8 *pBeaconIes; + u8 currentLen = 0; + char *buff; + int totalIeLen = 0, currentOffset = 0, strLen; + + memset(&wrqu, '\0', sizeof(wrqu)); + + if (0 == pCsrRoamInfo->nBeaconLength) { + hddLog(LOGW, FL("pCsrRoamInfo->nBeaconFrameLength = 0")); + return; + } + pBeaconIes = (u8 *) (pCsrRoamInfo->pbFrames + BEACON_FRAME_IES_OFFSET); + if (pBeaconIes == NULL) { + hddLog(LOGW, FL("Beacon IEs is NULL")); + return; + } + /* pBeaconIes needs to point to the IEs */ + hddLog(LOG1, FL("Beacon IEs is now at %02x%02x"), + (unsigned int)pBeaconIes[0], (unsigned int)pBeaconIes[1]); + hddLog(LOG1, FL("Beacon IEs length = %d"), + pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET); + + /* We need to send the IEs to the supplicant. */ + buff = kmalloc(IW_CUSTOM_MAX, GFP_ATOMIC); + if (buff == NULL) { + hddLog(LOGE, FL("kmalloc unable to allocate memory")); + return; + } + cdf_mem_zero(buff, IW_CUSTOM_MAX); + + strLen = strlcpy(buff, "BEACONIEs=", IW_CUSTOM_MAX); + currentLen = strLen + 1; + + totalIeLen = pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET; + do { + /* + * If the beacon size exceeds max CUSTOM event size, break it + * into chunks of CUSTOM event max size and send it to + * supplicant. Changes are done in supplicant to handle this. + */ + cdf_mem_zero(&buff[strLen + 1], IW_CUSTOM_MAX - (strLen + 1)); + currentLen = + CDF_MIN(totalIeLen, IW_CUSTOM_MAX - (strLen + 1) - 1); + cdf_mem_copy(&buff[strLen + 1], pBeaconIes + currentOffset, + currentLen); + currentOffset += currentLen; + totalIeLen -= currentLen; + wrqu.data.length = strLen + 1 + currentLen; + if (totalIeLen) + buff[strLen] = 1; /* more chunks pending */ + else + buff[strLen] = 0; /* last chunk */ + + hddLog(LOG1, FL("Beacon IEs length to supplicant = %d"), + currentLen); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + } while (totalIeLen > 0); + + kfree(buff); +} + +/** + * hdd_send_association_event() - send association event + * @dev: pointer to net device + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_send_association_event(struct net_device *dev, + tCsrRoamInfo *pCsrRoamInfo) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + union iwreq_data wrqu; + int we_event; + char *msg; + struct cdf_mac_addr peerMacAddr; + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Added to find the auth type on the fly at run time */ + /* rather than with cfg to see if FT is enabled */ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); +#endif + + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + we_event = SIOCGIWAP; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (NULL != pCsrRoamInfo) + if (pCsrRoamInfo->roamSynchInProgress) + /* change logging before release */ + hddLog(LOG4, "LFR3:hdd_send_association_event"); +#endif + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) { + if (!pCsrRoamInfo) { + hddLog(LOGE, FL("STA in associated state but pCsrRoamInfo is null")); + return; + } + + cds_incr_active_session(pHddCtx, pAdapter->device_mode, + pAdapter->sessionId); + memcpy(wrqu.ap_addr.sa_data, pCsrRoamInfo->pBssDesc->bssId, + sizeof(pCsrRoamInfo->pBssDesc->bssId)); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) { + if (global_p2p_connection_status == + P2P_CLIENT_CONNECTING_STATE_1) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTED_STATE_1; + hddLog(LOGE, + "[P2P State] Changing state from Connecting state to Connected State for 8-way Handshake"); + } else if (global_p2p_connection_status == + P2P_CLIENT_CONNECTING_STATE_2) { + global_p2p_connection_status = + P2P_CLIENT_COMPLETED_STATE; + hddLog(LOGE, + "[P2P State] Changing state from Connecting state to P2P Client Connection Completed"); + } + } +#endif + pr_info("wlan: " MAC_ADDRESS_STR " connected to " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes), + MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data)); + hdd_send_update_beacon_ies_event(pAdapter, pCsrRoamInfo); + + /* + * Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS + * is Enabled Or Send IWEVASSOCRESPIE Event if + * WLAN_FEATURE_VOWIFI_11R is Enabled and fFTEnable is true. + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Send FT Keys to the supplicant when FT is enabled */ + if ((pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN_PSK) + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN) +#ifdef FEATURE_WLAN_ESE + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA) +#endif + ) { + hdd_send_ft_assoc_response(dev, pAdapter, pCsrRoamInfo); + } +#endif + if (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) { + tSirSmeChanInfo chan_info; + cdf_copy_macaddr(&peerMacAddr, + &pHddStaCtx->conn_info.bssId); + chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id; + chan_info.mhz = pCsrRoamInfo->chan_info.mhz; + chan_info.info = pCsrRoamInfo->chan_info.info; + chan_info.band_center_freq1 = + pCsrRoamInfo->chan_info.band_center_freq1; + chan_info.band_center_freq2 = + pCsrRoamInfo->chan_info.band_center_freq2; + chan_info.reg_info_1 = + pCsrRoamInfo->chan_info.reg_info_1; + chan_info.reg_info_2 = + pCsrRoamInfo->chan_info.reg_info_2; + + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, + ePeerConnected, + pCsrRoamInfo-> + timingMeasCap, + pAdapter->sessionId, + &chan_info); + } +#ifdef MSM_PLATFORM +#ifdef CONFIG_CNSS + /* start timer in sta/p2p_cli */ + spin_lock_bh(&pHddCtx->bus_bw_lock); + pAdapter->prev_tx_packets = pAdapter->stats.tx_packets; + pAdapter->prev_rx_packets = pAdapter->stats.rx_packets; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_start_bus_bw_compute_timer(pAdapter); +#endif +#endif + } else if (eConnectionState_IbssConnected == /* IBss Associated */ + pHddStaCtx->conn_info.connState) { + cds_incr_active_session(pHddCtx, pAdapter->device_mode, + pAdapter->sessionId); + memcpy(wrqu.ap_addr.sa_data, pHddStaCtx->conn_info.bssId.bytes, + ETH_ALEN); + pr_info("wlan: new IBSS connection to " MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes)); + } else { /* Not Associated */ + + pr_info("wlan: disconnected\n"); + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + cds_decr_session_set_pcl( + pHddCtx, pAdapter->device_mode, + pAdapter->sessionId); +#if defined(FEATURE_WLAN_LFR) + wlan_hdd_enable_roaming(pAdapter); +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + if (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) { + cdf_copy_macaddr(&peerMacAddr, + &pHddStaCtx->conn_info.bssId); + + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, + ePeerDisconnected, 0, + pAdapter->sessionId, + NULL); + } +#ifdef WLAN_FEATURE_LPSS + pAdapter->rssi_send = false; + wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 0); +#endif +#ifdef FEATURE_WLAN_TDLS + if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) && + (pCsrRoamInfo)) { + hddLog(LOG4, + FL("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d"), + pCsrRoamInfo->tdls_prohibited, + pCsrRoamInfo->tdls_chan_swit_prohibited); + + wlan_hdd_update_tdls_info(pAdapter, + pCsrRoamInfo->tdls_prohibited, + pCsrRoamInfo->tdls_chan_swit_prohibited); + } +#endif +#ifdef MSM_PLATFORM + /* stop timer in sta/p2p_cli */ + spin_lock_bh(&pHddCtx->bus_bw_lock); + pAdapter->prev_tx_packets = 0; + pAdapter->prev_rx_packets = 0; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_stop_bus_bw_compute_timer(pAdapter); +#endif + } + cds_dump_concurrency_info(pHddCtx); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + + msg = NULL; + /*During the WLAN uninitialization,supplicant is stopped before the + driver so not sending the status of the connection to supplicant */ + if ((pHddCtx->isLoadInProgress != true) && + (pHddCtx->isUnloadInProgress != true)) { + wireless_send_event(dev, we_event, &wrqu, msg); +#ifdef FEATURE_WLAN_ESE + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + if ((pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) || + (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA)) + hdd_send_new_ap_channel_info(dev, pAdapter, + pCsrRoamInfo); + } +#endif + } +} + +/** + * hdd_conn_remove_connect_info() - remove connection info + * @pHddStaCtx: pointer to global HDD station context + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_conn_remove_connect_info(hdd_station_ctx_t *pHddStaCtx) +{ + /* Remove staId, bssId and peerMacAddress */ + pHddStaCtx->conn_info.staId[0] = 0; + cdf_mem_zero(&pHddStaCtx->conn_info.bssId, CDF_MAC_ADDR_SIZE); + cdf_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[0], + CDF_MAC_ADDR_SIZE); + + /* Clear all security settings */ + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + pHddStaCtx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + pHddStaCtx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + + cdf_mem_zero(&pHddStaCtx->conn_info.Keys, sizeof(tCsrKeys)); + cdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + + /* Set not-connected state */ + pHddStaCtx->conn_info.connDot11DesiredBssType = eCSR_BSS_TYPE_ANY; + pHddStaCtx->conn_info.proxyARPService = 0; + + cdf_mem_zero(&pHddStaCtx->conn_info.SSID, sizeof(tCsrSSIDInfo)); +} + +/** + * hdd_roam_deregister_sta() - deregister station + * @pAdapter: pointer to adapter + * @staId: station identifier + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +hdd_roam_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) +{ + CDF_STATUS cdf_status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_IbssDisconnected == + pHddStaCtx->conn_info.connState) { + /* + * Do not set the carrier off when the last peer leaves. + * We will set the carrier off while stopping the IBSS. + */ + } + + cdf_status = ol_txrx_clear_peer(staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, + FL("ol_txrx_clear_peer() failed for staID %d. Status(%d) [0x%08X]"), + staId, cdf_status, cdf_status); + } + return cdf_status; +} + +/** + * hdd_dis_connect_handler() - disconnect event handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam identifier + * @roamStatus: roam status + * @roamResult: roam result + * + * This function handles disconnect event: + * 1. Disable transmit queues; + * 2. Clean up internal connection states and data structures; + * 3. Send disconnect indication to supplicant. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS vstatus; + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint8_t sta_id; + bool sendDisconInd = true; + + if (dev == NULL) { + hddLog(LOGE, FL("net_dev is released return")); + return CDF_STATUS_E_FAILURE; + } + /* notify apps that we can't pass traffic anymore */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (hdd_ipa_is_enabled(pHddCtx)) + hdd_ipa_wlan_evt(pAdapter, pHddStaCtx->conn_info.staId[0], + WLAN_STA_DISCONNECT, + pHddStaCtx->conn_info.bssId.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + +#ifdef QCA_PKT_PROTO_TRACE + /* STA disconnected, update into trace buffer */ + if (pHddCtx->config->gEnableDebugLog) + cds_pkt_trace_buf_update("ST:DISASC"); +#endif /* QCA_PKT_PROTO_TRACE */ + + /* HDD has initiated disconnect, do not send disconnect indication + * to kernel. Sending disconnected event to kernel for userspace + * initiated disconnect will be handled by hdd_DisConnectHandler call + * to cfg80211_disconnected. + */ + if ((eConnectionState_Disconnecting == + pHddStaCtx->conn_info.connState) || + (eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState)) { + hddLog(LOG1, + FL("HDD has initiated a disconnect, no need to send disconnect indication to kernel")); + sendDisconInd = false; + } + + if (pHddStaCtx->conn_info.connState != eConnectionState_Disconnecting) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_Disconnecting")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + } + + hdd_clear_roam_profile_ie(pAdapter); + hdd_wmm_init(pAdapter); + + /* indicate 'disconnect' status to wpa_supplicant... */ + hdd_send_association_event(dev, pRoamInfo); + /* indicate disconnected event to nl80211 */ + if (roamStatus != eCSR_ROAM_IBSS_LEAVE) { + /* + * Only send indication to kernel if not initiated + * by kernel + */ + if (sendDisconInd) { + /* + * To avoid wpa_supplicant sending "HANGED" CMD + * to ICS UI. + */ + if (eCSR_ROAM_LOSTLINK == roamStatus) + cfg80211_disconnected(dev, pRoamInfo-> + reasonCode, NULL, + 0, GFP_KERNEL); + else + cfg80211_disconnected(dev, + WLAN_REASON_UNSPECIFIED, + NULL, 0, + GFP_KERNEL); + + hdd_info("sent disconnected event to nl80211, rssi: %d", + pAdapter->rssi); + } + /* + * During the WLAN uninitialization,supplicant is stopped + * before the driver so not sending the status of the + * connection to supplicant. + */ + if ((pHddCtx->isLoadInProgress != true) && + (pHddCtx->isUnloadInProgress != true)) { +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) { + if (global_p2p_connection_status == + P2P_CLIENT_CONNECTED_STATE_1) { + global_p2p_connection_status = + P2P_CLIENT_DISCONNECTED_STATE; + hddLog(LOGE, + "[P2P State] 8 way Handshake completed and moved to disconnected state"); + } else if (global_p2p_connection_status == + P2P_CLIENT_COMPLETED_STATE) { + global_p2p_connection_status = + P2P_NOT_ACTIVE; + hddLog(LOGE, + "[P2P State] P2P Client is removed and moved to inactive state"); + } + } +#endif + + } + } + + hdd_wmm_adapter_clear(pAdapter); +#if defined(WLAN_FEATURE_VOWIFI_11R) + sme_ft_reset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId); +#endif + if (eCSR_ROAM_IBSS_LEAVE == roamStatus) { + sta_id = IBSS_BROADCAST_STAID; + vstatus = hdd_roam_deregister_sta(pAdapter, sta_id); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(LOGE, + FL("hdd_roam_deregister_sta() failed for staID %d Status=%d [0x%x]"), + sta_id, status, status); + status = CDF_STATUS_E_FAILURE; + } + pHddCtx->sta_to_adapter[sta_id] = NULL; + } + sta_id = pHddStaCtx->conn_info.staId[0]; + + /* We should clear all sta register with TL, for now, only one. */ + vstatus = hdd_roam_deregister_sta(pAdapter, sta_id); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(LOGE, + "hdd_roam_deregister_sta() failed to for staID %d. Status= %d [0x%x]", + sta_id, status, status); + status = CDF_STATUS_E_FAILURE; + } + + pHddCtx->sta_to_adapter[sta_id] = NULL; + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info(pHddStaCtx); + hddLog(LOG1, FL("Set HDD connState to eConnectionState_NotConnected")); + hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected); +#ifdef WLAN_FEATURE_GTK_OFFLOAD + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + memset(&pHddStaCtx->gtkOffloadReqParams, 0, + sizeof(tSirGtkOffloadParams)); + pHddStaCtx->gtkOffloadReqParams.ulFlags = GTK_OFFLOAD_DISABLE; + } +#endif + +#ifdef FEATURE_WLAN_TDLS + if (eCSR_ROAM_IBSS_LEAVE != roamStatus) + wlan_hdd_tdls_disconnection_callback(pAdapter); +#endif + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId); + } + /* Unblock anyone waiting for disconnect to complete */ + complete(&pAdapter->disconnect_comp_var); + return status; +} + +/** + * hdd_set_peer_authorized_event() - set peer_authorized_event + * @vdev_id: vdevid + * + * Return: None + */ +void hdd_set_peer_authorized_event(uint32_t vdev_id) +{ + hdd_context_t *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + hdd_adapter_t *adapter = NULL; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hddLog(LOGE, + "%s: Invalid vdev_id", __func__); + } + complete(&adapter->sta_authorized_event); +} + +/** + * hdd_change_peer_state() - change peer state + * @pAdapter: HDD adapter + * @sta_state: peer state + * @roam_synch_in_progress: roam synch in progress + * + * Return: CDF status + */ +CDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress) +{ + struct ol_txrx_peer_t *peer; + CDF_STATUS err; + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (!pdev) { + hdd_err("Failed to get txrx context"); + return CDF_STATUS_E_FAULT; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hddLog(LOGE, "Invalid sta id :%d", sta_id); + return CDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) + return CDF_STATUS_E_FAULT; + + err = ol_txrx_peer_state_update(pdev, + (u_int8_t *) peer->mac_addr.raw, sta_state); + if (err != CDF_STATUS_SUCCESS) { + hddLog(LOGE, "peer state update failed"); + return CDF_STATUS_E_FAULT; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_synch_in_progress) + return CDF_STATUS_SUCCESS; +#endif + + if (sta_state == ol_txrx_peer_state_auth) { +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + /* make sure event is reset */ + INIT_COMPLETION(pAdapter->sta_authorized_event); +#endif + + err = sme_set_peer_authorized(peer->mac_addr.raw, + hdd_set_peer_authorized_event, + pAdapter->sessionId); + if (err != CDF_STATUS_SUCCESS) { + hddLog(LOGE, "Failed to set the peer state to authorized"); + return CDF_STATUS_E_FAULT; + } + + if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION || + pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + unsigned long rc; + + /* wait for event from firmware to set the event */ + rc = wait_for_completion_timeout( + &pAdapter->sta_authorized_event, + msecs_to_jiffies(HDD_PEER_AUTHORIZE_WAIT)); + if (!rc) { + hddLog(LOG1, "%s: timeout waiting for sta_authorized_event", + __func__); + } + ol_txrx_vdev_unpause(peer->vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + } + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_register_sta() - register station + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @staId: station identifier + * @pPeerMacAddress: peer MAC address + * @pBssDesc: pointer to BSS description + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_roam_register_sta(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint8_t staId, + struct cdf_mac_addr *pPeerMacAddress, + tSirBssDescription *pBssDesc) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (NULL == pBssDesc) + return CDF_STATUS_E_FAILURE; + + /* Get the Station ID from the one saved during the association */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately */ + if (hdd_wmm_is_active(pAdapter)) + staDesc.is_qos_enabled = 1; + else + staDesc.is_qos_enabled = 0; + +#ifdef FEATURE_WLAN_WAPI + hddLog(LOG1, FL("WAPI STA Registered: %d"), + pAdapter->wapi_info.fIsWapiSta); + if (pAdapter->wapi_info.fIsWapiSta) + staDesc.is_wapi_supported = 1; + else + staDesc.is_wapi_supported = 0; +#endif /* FEATURE_WLAN_WAPI */ + + cdf_status = ol_txrx_register_peer(hdd_rx_packet_cbk, + &staDesc); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGW, + "ol_txrx_register_peer() failed to register. Status=%d [0x%08X]", + cdf_status, cdf_status); + return cdf_status; + } + + if (!pRoamInfo->fAuthRequired) { + /* + * Connections that do not need Upper layer auth, transition + * TLSHIM directly to 'Authenticated' state + */ + cdf_status = + hdd_change_peer_state(pAdapter, staDesc.sta_id, + ol_txrx_peer_state_auth, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + + hdd_conn_set_authenticated(pAdapter, true); + } else { + hddLog(LOG3, + "ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + pHddStaCtx->conn_info.staId[0]); + cdf_status = + hdd_change_peer_state(pAdapter, staDesc.sta_id, + ol_txrx_peer_state_conn, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, false); + } + return cdf_status; +} + +/** + * hdd_send_re_assoc_event() - send reassoc event + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * @reqRsnIe: pointer to RSN Information element + * @reqRsnLength: length of RSN IE + * + * Return: none + */ +static void hdd_send_re_assoc_event(struct net_device *dev, + hdd_adapter_t *pAdapter, tCsrRoamInfo *pCsrRoamInfo, + uint8_t *reqRsnIe, uint32_t reqRsnLength) +{ + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + uint8_t *rspRsnIe = kmalloc(IW_GENERIC_IE_MAX, GFP_KERNEL); + uint32_t rspRsnLength = 0; + struct ieee80211_channel *chan; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint8_t buf_ssid_ie[2 + SIR_MAC_SSID_EID_MAX]; /* 2 bytes-EID and len */ + uint8_t *buf_ptr, ssid_ie_len; + struct cfg80211_bss *bss = NULL; + uint8_t *final_req_ie = NULL; + tCsrRoamConnectedProfile roam_profile; + tHalHandle hal_handle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + if (!rspRsnIe) { + hddLog(LOGE, FL("Unable to allocate RSN IE")); + return; + } + + if (pCsrRoamInfo == NULL) { + hddLog(LOGE, FL("Invalid CSR roam info")); + goto done; + } + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hddLog(LOGE, FL("Invalid assoc response length")); + goto done; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) + goto done; + + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hddLog(LOG1, FL("AssocRsp is now at %02x%02x"), + (unsigned int)pFTAssocRsp[0], (unsigned int)pFTAssocRsp[1]); + + /* + * Active session count is decremented upon disconnection, but during + * roaming, there is no disconnect indication and hence active session + * count is not decremented. + * After roaming is completed, active session count is incremented + * as a part of connect indication but effectively after roaming the + * active session count should still be the same and hence upon + * successful reassoc decrement the active session count here. + */ + cds_decr_session_set_pcl( + pHddCtx, pAdapter->device_mode, + pAdapter->sessionId); + + /* Send the Assoc Resp, the supplicant needs this for initial Auth */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + rspRsnLength = len; + cdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + cdf_mem_zero(rspRsnIe + len, IW_GENERIC_IE_MAX - len); + + chan = ieee80211_get_channel(pAdapter->wdev.wiphy, + (int)pCsrRoamInfo->pBssDesc->channelId); + cdf_mem_zero(&roam_profile, sizeof(tCsrRoamConnectedProfile)); + sme_roam_get_connect_profile(hal_handle, pAdapter->sessionId, + &roam_profile); + bss = cfg80211_get_bss(pAdapter->wdev.wiphy, chan, + pCsrRoamInfo->bssid.bytes, + &roam_profile.SSID.ssId[0], roam_profile.SSID.length, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + + if (bss == NULL) + hddLog(LOGE, FL("Get BSS returned NULL")); + buf_ptr = buf_ssid_ie; + *buf_ptr = SIR_MAC_SSID_EID; + buf_ptr++; + *buf_ptr = roam_profile.SSID.length; /*len of ssid*/ + buf_ptr++; + cdf_mem_copy(buf_ptr, &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + ssid_ie_len = 2 + roam_profile.SSID.length; + hddLog(LOG2, FL("SSIDIE:")); + hddLog(CDF_TRACE_LEVEL_DEBUG, buf_ssid_ie, ssid_ie_len); + final_req_ie = kmalloc(IW_GENERIC_IE_MAX, GFP_KERNEL); + if (final_req_ie == NULL) + goto done; + buf_ptr = final_req_ie; + cdf_mem_copy(buf_ptr, buf_ssid_ie, ssid_ie_len); + buf_ptr += ssid_ie_len; + cdf_mem_copy(buf_ptr, reqRsnIe, reqRsnLength); + cdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + cdf_mem_zero(final_req_ie + (ssid_ie_len + reqRsnLength), + IW_GENERIC_IE_MAX - (ssid_ie_len + reqRsnLength)); + hddLog(LOG2, FL("Req RSN IE:")); + hddLog(CDF_TRACE_LEVEL_DEBUG, final_req_ie, + (ssid_ie_len + reqRsnLength)); + cfg80211_roamed_bss(dev, bss, + final_req_ie, (ssid_ie_len + reqRsnLength), + rspRsnIe, rspRsnLength, GFP_KERNEL); + + if (pHddCtx->config->isRoamOffloadEnabled && + pCsrRoamInfo->roamSynchInProgress) + wlan_hdd_send_roam_auth_event(pHddCtx, + pCsrRoamInfo->bssid.bytes, + reqRsnIe, reqRsnLength, rspRsnIe, + rspRsnLength, pCsrRoamInfo); +done: + sme_roam_free_connect_profile(hal_handle, &roam_profile); + if (final_req_ie) + kfree(final_req_ie); + kfree(rspRsnIe); +} + +/** + * hdd_roam_set_key_complete_handler() - Update the security parameters + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_roam_set_key_complete_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + eCsrEncryptionType connectedCipherAlgo; + bool fConnected = false; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + ENTER(); + + if (NULL == pRoamInfo) { + hddLog(LOG2, FL("pRoamInfo is NULL")); + return CDF_STATUS_E_FAILURE; + } + /* + * if (WPA), tell TL to go to 'authenticated' after the keys are set. + * then go to 'authenticated'. For all other authentication types + * (those that do not require upper layer authentication) we can put TL + * directly into 'authenticated' state. + */ + hddLog(LOG2, "Set Key completion roamStatus =%d roamResult=%d " + MAC_ADDRESS_STR, roamStatus, roamResult, + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes)); + + fConnected = hdd_conn_get_connected_cipher_algo(pHddStaCtx, + &connectedCipherAlgo); + if (fConnected) { + if (WLAN_HDD_IBSS == pAdapter->device_mode) { + uint8_t staId; + + if (cdf_is_macaddr_broadcast(&pRoamInfo->peerMac)) { + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } else { + cdf_status = hdd_ibss_get_sta_id( + pHddStaCtx, + &pRoamInfo->peerMac, + &staId); + if (CDF_STATUS_SUCCESS == cdf_status) { + hddLog(LOG2, + "WLAN TL STA Ptk Installed for STAID=%d", + staId); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } + } + } else { + /* + * TODO: Considering getting a state machine in + * HDD later. This routine is invoked twice. + * 1)set PTK 2)set GTK. + * The following if statement will be true when + * setting GTK. At this time we don't handle the state + * in detail. Related CR: 174048 - TL not in + * authenticated state + */ + cdf_status = + hdd_change_peer_state(pAdapter, pHddStaCtx->conn_info.staId[0], + ol_txrx_peer_state_auth, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, true); + if ((eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) && + (pRoamInfo != NULL) && !pRoamInfo->fAuthRequired) { + hddLog(LOG3, + "Key set for StaId= %d. Changing TL state to AUTHENTICATED", + pHddStaCtx->conn_info.staId[0]); + + /* + * Connections that do not need Upper layer + * authentication, transition TL to + * 'Authenticated' state after the keys are set. + */ + cdf_status = + hdd_change_peer_state(pAdapter, + pHddStaCtx->conn_info.staId[0], + ol_txrx_peer_state_auth, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + + hdd_conn_set_authenticated(pAdapter, true); + if ((WLAN_HDD_INFRA_STATION == + pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == + pAdapter->device_mode)) { + sme_ps_enable_auto_ps_timer + (WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + pHddStaCtx->hdd_ReassocScenario); + } + } + + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } + } else { + /* + * possible disassoc after issuing set key and waiting + * set key complete. + */ + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } + + EXIT(); + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @pAdapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamInfo roamInfo; + roamInfo.fAuthRequired = false; + cdf_mem_copy(roamInfo.bssid.bytes, + pHddStaCtx->roam_info.bssid, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(roamInfo.peerMac.bytes, + pHddStaCtx->roam_info.peerMac, CDF_MAC_ADDR_SIZE); + + cdf_ret_status = + hdd_roam_set_key_complete_handler(pAdapter, + &roamInfo, + pHddStaCtx->roam_info.roamId, + pHddStaCtx->roam_info.roamStatus, + eCSR_ROAM_RESULT_AUTHENTICATED); + if (cdf_ret_status != CDF_STATUS_SUCCESS) + hddLog(LOGE, FL("Set Key complete failure")); + + pHddStaCtx->roam_info.deferKeyComplete = false; +} + +/** + * hdd_association_completion_handler() - association completion handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + uint8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN; +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) || \ +defined(WLAN_FEATURE_VOWIFI_11R) + int ft_carrier_on = false; +#endif + bool hddDisconInProgress = false; + unsigned long rc; + + if (!pHddCtx) { + hdd_err("HDD context is NULL"); + return CDF_STATUS_E_FAILURE; + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo && pRoamInfo->roamSynchInProgress) { + /* change logging before release */ + hddLog(LOG3, "LFR3:hdd_association_completion_handler"); + } +#endif + + /* HDD has initiated disconnect, do not send connect result indication + * to kernel as it will be handled by __cfg80211_disconnect. + */ + if ((eConnectionState_Disconnecting == pHddStaCtx->conn_info.connState) + && ((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) + || (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus))) { + hddLog(LOG1, FL("Disconnect from HDD in progress")); + hddDisconInProgress = true; + } + + if (eCSR_ROAM_RESULT_ASSOCIATED == roamResult) { + if (NULL == pRoamInfo) { + hddLog(LOGE, FL("pRoamInfo is NULL")); + return CDF_STATUS_E_FAILURE; + } + if (!hddDisconInProgress) { + hddLog(LOG1, FL("Set HDD connState to eConnectionState_Associated")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Associated); + } + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); +#ifdef FEATURE_WLAN_WAPI + if (pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE + || pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_PSK) { + pAdapter->wapi_info.fIsWapiSta = 1; + } else { + pAdapter->wapi_info.fIsWapiSta = 0; + } +#endif /* FEATURE_WLAN_WAPI */ + + /* Indicate 'connect' status to user space */ + hdd_send_association_event(dev, pRoamInfo); + + if (cds_is_mcc_in_24G(pHddCtx)) { + if (pHddCtx->miracast_value) + cds_set_mas(pAdapter, pHddCtx->miracast_value); + } + + /* Initialize the Linkup event completion variable */ + INIT_COMPLETION(pAdapter->linkup_event_var); + + /* + * Sometimes Switching ON the Carrier is taking time to activate + * the device properly. Before allowing any packet to go up to + * the application, device activation has to be ensured for + * proper queue mapping by the kernel. we have registered net + * device notifier for device change notification. With this we + * will come to know that the device is getting + * activated properly. + */ +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR) + if (pHddStaCtx->ft_carrier_on == false) { +#endif + /* + * Enable Linkup Event Servicing which allows the net device + * notifier to set the linkup event variable. + */ + pAdapter->isLinkUpSvcNeeded = true; + + /* + * Enable Linkup Event Servicing which allows the net device + * notifier to set the linkup event variable. + */ + pAdapter->isLinkUpSvcNeeded = true; + + /* Switch on the Carrier to activate the device */ + wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_CARRIER_ON, + WLAN_CONTROL_PATH); + + /* + * Wait for the Link to up to ensure all the queues are set + * properly by the kernel. + */ + rc = wait_for_completion_timeout(&pAdapter-> + linkup_event_var, + msecs_to_jiffies + (ASSOC_LINKUP_TIMEOUT)); + if (!rc) + hddLog(LOGW, FL("Warning:ASSOC_LINKUP_TIMEOUT")); + + /* + * Disable Linkup Event Servicing - no more service required + * from the net device notifier call. + */ + pAdapter->isLinkUpSvcNeeded = false; +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR) + } else { + pHddStaCtx->ft_carrier_on = false; + ft_carrier_on = true; + } +#endif + if ((WLAN_MAX_STA_COUNT + 3) > pRoamInfo->staId) + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + else + hddLog(LOGE, "%s: Wrong Staid: %d", __func__, + pRoamInfo->staId); + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + + if (hdd_ipa_is_enabled(pHddCtx)) + hdd_ipa_wlan_evt(pAdapter, pRoamInfo->staId, + WLAN_STA_CONNECT, + pRoamInfo->bssid.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, false); +#endif + + cds_check_concurrent_intf_and_restart_sap(pHddCtx, + pHddStaCtx, + pAdapter); + +#ifdef FEATURE_WLAN_TDLS + wlan_hdd_tdls_connection_callback(pAdapter); +#endif + +#ifdef QCA_PKT_PROTO_TRACE + /* STA Associated, update into trace buffer */ + if (pHddCtx->config->gEnableDebugLog) + cds_pkt_trace_buf_update("ST:ASSOC"); +#endif /* QCA_PKT_PROTO_TRACE */ + /* + * For reassoc, the station is already registered, all we need + * is to change the state of the STA in TL. + * If authentication is required (WPA/WPA2/DWEP), change TL to + * CONNECTED instead of AUTHENTICATED. + */ + if (!pRoamInfo->fReassocReq) { + struct cfg80211_bss *bss; +#ifdef WLAN_FEATURE_VOWIFI_11R + u8 *pFTAssocRsp = NULL; + unsigned int assocRsplen = 0; + u8 *pFTAssocReq = NULL; + unsigned int assocReqlen = 0; + struct ieee80211_channel *chan; +#endif + uint8_t rspRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t rspRsnLength = DOT11F_IE_RSN_MAX_LEN; + + /* add bss_id to cfg80211 data base */ + bss = + wlan_hdd_cfg80211_update_bss_db(pAdapter, + pRoamInfo); + if (NULL == bss) { + pr_err("wlan: Not able to create BSS entry\n"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + return CDF_STATUS_E_FAILURE; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN + || pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN_PSK) { + + /* Association Response */ + pFTAssocRsp = + (u8 *) (pRoamInfo->pbFrames + + pRoamInfo->nBeaconLength + + pRoamInfo->nAssocReqLength); + if (pFTAssocRsp != NULL) { + /* + * pFTAssocRsp needs to point to the IEs + */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hddLog(LOG1, + FL("AssocRsp is now at %02x%02x"), + (unsigned int)pFTAssocRsp[0], + (unsigned int)pFTAssocRsp[1]); + assocRsplen = + pRoamInfo->nAssocRspLength - + FT_ASSOC_RSP_IES_OFFSET; + } else { + hddLog(LOGE, FL("AssocRsp is NULL")); + assocRsplen = 0; + } + + /* Association Request */ + pFTAssocReq = (u8 *) (pRoamInfo->pbFrames + + pRoamInfo->nBeaconLength); + if (pFTAssocReq != NULL) { + if (!ft_carrier_on) { + /* + * pFTAssocReq needs to point to + * the IEs + */ + pFTAssocReq += + FT_ASSOC_REQ_IES_OFFSET; + hddLog(LOG1, + FL("pFTAssocReq is now at %02x%02x"), + (unsigned int) + pFTAssocReq[0], + (unsigned int) + pFTAssocReq[1]); + assocReqlen = + pRoamInfo->nAssocReqLength - + FT_ASSOC_REQ_IES_OFFSET; + } else { + /* + * This should contain only the + * FTIEs + */ + assocReqlen = + pRoamInfo->nAssocReqLength; + } + } else { + hddLog(LOGE, FL("AssocReq is NULL")); + assocReqlen = 0; + } + + if (ft_carrier_on) { + if (!hddDisconInProgress) { + /* + * After roaming is completed, + * active session count is + * incremented as a part of + * connect indication but + * effectively the active + * session count should still + * be the same and hence upon + * successful reassoc + * decrement the active session + * count here. + */ + cds_decr_session_set_pcl + (pHddCtx, + pAdapter->device_mode, + pAdapter->sessionId); + hddLog(LOG1, + FL("ft_carrier_on is %d, sending roamed indication"), + ft_carrier_on); + chan = + ieee80211_get_channel + (pAdapter->wdev.wiphy, + (int)pRoamInfo->pBssDesc-> + channelId); + hddLog(LOG1, + "assocReqlen %d assocRsplen %d", + assocReqlen, + assocRsplen); + cfg80211_roamed(dev, chan, + pRoamInfo-> + bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + GFP_KERNEL); + if (pRoamInfo->roamSynchInProgress) + wlan_hdd_send_roam_auth_event( + pHddCtx, + pRoamInfo->bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + pRoamInfo); + } + if (sme_get_ftptk_state + (WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId)) { + sme_set_ftptk_state + (WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + false); + pRoamInfo->fAuthRequired = + false; + + cdf_mem_copy(pHddStaCtx-> + roam_info.bssid, + pRoamInfo->bssid.bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(pHddStaCtx-> + roam_info.peerMac, + pRoamInfo->peerMac.bytes, + CDF_MAC_ADDR_SIZE); + pHddStaCtx->roam_info.roamId = + roamId; + pHddStaCtx->roam_info. + roamStatus = roamStatus; + pHddStaCtx->roam_info. + deferKeyComplete = true; + } + } else if (!hddDisconInProgress) { + hddLog(LOG1, + FL("ft_carrier_on is %d, sending connect indication"), + ft_carrier_on); + cfg80211_connect_result(dev, + pRoamInfo-> + bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + } + } else +#endif + { + /* + * wpa supplicant expecting WPA/RSN IE in + * connect result. + */ + csr_roam_get_wpa_rsn_req_ie(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &reqRsnLength, + reqRsnIe); + + csr_roam_get_wpa_rsn_rsp_ie(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &rspRsnLength, + rspRsnIe); + if (!hddDisconInProgress) { +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (ft_carrier_on) + hdd_send_re_assoc_event(dev, + pAdapter, + pRoamInfo, + reqRsnIe, + reqRsnLength); + else +#endif /* FEATURE_WLAN_ESE */ + + { + hddLog(LOG1, + FL("sending connect indication to nl80211:for bssid " + MAC_ADDRESS_STR + " reason:%d and Status:%d"), + MAC_ADDR_ARRAY + (pRoamInfo->bssid.bytes), + roamResult, roamStatus); + + /* inform connect result to nl80211 */ + cfg80211_connect_result(dev, + pRoamInfo-> + bssid.bytes, + reqRsnIe, + reqRsnLength, + rspRsnIe, + rspRsnLength, + WLAN_STATUS_SUCCESS, + GFP_KERNEL); + } + } + } + if (!hddDisconInProgress) { + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + pHddCtx->wiphy, +#endif + bss); + + /* + * Perform any WMM-related association + * processing. + */ + hdd_wmm_assoc(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); + + /* + * Start the Queue - Start tx queues before + * hdd_roam_register_sta, since + * hdd_roam_register_sta will flush any cached + * data frames immediately. + */ + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + /* + * Register the Station with TL after associated + */ + cdf_status = hdd_roam_register_sta(pAdapter, + pRoamInfo, + pHddStaCtx-> + conn_info. + staId[0], + NULL, + pRoamInfo-> + pBssDesc); + } + } else { + /* + * wpa supplicant expecting WPA/RSN IE in connect result + * in case of reassociation also need to indicate it to + * supplicant. + */ + csr_roam_get_wpa_rsn_req_ie( + WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &reqRsnLength, reqRsnIe); + + hdd_send_re_assoc_event(dev, pAdapter, pRoamInfo, + reqRsnIe, reqRsnLength); + /* Reassoc successfully */ + if (pRoamInfo->fAuthRequired) { + cdf_status = + hdd_change_peer_state(pAdapter, + pHddStaCtx->conn_info.staId[0], + ol_txrx_peer_state_conn, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, false); + } else { + hddLog(LOG2, + FL("staId: %d Changing TL state to AUTHENTICATED"), + pHddStaCtx->conn_info.staId[0]); + cdf_status = + hdd_change_peer_state(pAdapter, + pHddStaCtx->conn_info.staId[0], + ol_txrx_peer_state_auth, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, true); + } + + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + /* + * Perform any WMM-related association + * processing + */ + hdd_wmm_assoc(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); + } + + /* Start the tx queues */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo->roamSynchInProgress) + hddLog(LOG3, "LFR3:netif_tx_wake_all_queues"); +#endif + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, + "STA register with TL failed. status(=%d) [%08X]", + cdf_status, cdf_status); + } +#ifdef WLAN_FEATURE_11W + cdf_mem_zero(&pAdapter->hdd_stats.hddPmfStats, + sizeof(pAdapter->hdd_stats.hddPmfStats)); +#endif + } else { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + if (pRoamInfo) + pr_info("wlan: connection failed with " MAC_ADDRESS_STR + " reason:%d and Status:%d\n", + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + roamResult, roamStatus); + else + pr_info("wlan: connection failed with " MAC_ADDRESS_STR + " reason:%d and Status:%d\n", + MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), + roamResult, roamStatus); + + /* + * CR465478: Only send up a connection failure result when CSR + * has completed operation - with a ASSOCIATION_FAILURE status. + */ + if (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus + && !hddDisconInProgress) { + if (pRoamInfo) + hddLog(LOGE, + FL("send connect failure to nl80211: for bssid " + MAC_ADDRESS_STR + " reason:%d and Status:%d "), + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + roamResult, roamStatus); + else + hddLog(LOGE, + FL("connect failed: for bssid " + MAC_ADDRESS_STR + " reason:%d and Status:%d "), + MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), + roamResult, roamStatus); + + hdd_clear_roam_profile_ie(pAdapter); + + /* inform association failure event to nl80211 */ + if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == + roamResult) { + if (pRoamInfo) + cfg80211_connect_result(dev, + pRoamInfo->bssid.bytes, + NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL); + else + cfg80211_connect_result(dev, + pWextState->req_bssId.bytes, + NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL); + } else { + if (pRoamInfo) { + eCsrAuthType authType = + pWextState->roamProfile.AuthType. + authType[0]; + bool isWep = + (authType == + eCSR_AUTH_TYPE_OPEN_SYSTEM) + || (authType == + eCSR_AUTH_TYPE_SHARED_KEY); + + /* + * In case of OPEN-WEP or SHARED-WEP + * authentication, send exact protocol + * reason code. This enables user + * applications to reconnect the station + * with correct configuration. + */ + cfg80211_connect_result(dev, + pRoamInfo->bssid.bytes, NULL, 0, + NULL, 0, + isWep ? pRoamInfo->reasonCode : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } else + cfg80211_connect_result(dev, + pWextState->req_bssId.bytes, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } + } + + if (pRoamInfo) { + if ((eSIR_SME_JOIN_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode) + || (eSIR_SME_AUTH_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode) + || (eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode)) { + wlan_hdd_cfg80211_update_bss_list(pAdapter, + pRoamInfo); + } + } + + /* + * Set connection state to eConnectionState_NotConnected only + * when CSR has completed operation - with a + * ASSOCIATION_FAILURE status. + */ + if (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus + && !hddDisconInProgress) { + hddLog(LOG1, + FL("state to eConnectionState_NotConnected")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + } + hdd_wmm_init(pAdapter); + + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + if (CDF_STATUS_SUCCESS != cds_check_and_restart_sap(pHddCtx, + roamResult, pHddStaCtx)) + return CDF_STATUS_E_FAILURE; + + cds_force_sap_on_scc(pHddCtx, roamResult); + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_ibss_indication_handler() - update the status of the IBSS + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Here we update the status of the Ibss when we receive information that we + * have started/joined an ibss session. + * + * Return: none + */ +static void hdd_roam_ibss_indication_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hddLog(LOG1, "%s: id %d, status %d, result %d", + pAdapter->dev->name, roamId, roamStatus, roamResult); + + switch (roamResult) { + /* both IBSS Started and IBSS Join should come in here. */ + case eCSR_ROAM_RESULT_IBSS_STARTED: + case eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS: + case eCSR_ROAM_RESULT_IBSS_COALESCED: + { + hdd_context_t *pHddCtx = + (hdd_context_t *) pAdapter->pHddCtx; + struct cdf_mac_addr broadcastMacAddr = + CDF_MAC_ADDR_BROADCAST_INITIALIZER; + + if (NULL == pRoamInfo) { + CDF_ASSERT(0); + return; + } + + /* When IBSS Started comes from CSR, we need to move + * connection state to IBSS Disconnected (meaning no peers + * are in the IBSS). + */ + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_IbssDisconnected")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_IbssDisconnected); + /* notify wmm */ + hdd_wmm_connect(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_IBSS); + pHddCtx->sta_to_adapter[IBSS_BROADCAST_STAID] = + pAdapter; + hdd_roam_register_sta(pAdapter, pRoamInfo, + IBSS_BROADCAST_STAID, + &broadcastMacAddr, + pRoamInfo->pBssDesc); + + if (pRoamInfo->pBssDesc) { + struct cfg80211_bss *bss; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + struct ieee80211_channel *chan; + int chan_no; + unsigned int freq; +#endif + /* we created the IBSS, notify supplicant */ + hddLog(LOG1, + FL("%s: created ibss " MAC_ADDRESS_STR), + pAdapter->dev->name, + MAC_ADDR_ARRAY(pRoamInfo->pBssDesc->bssId)); + + /* we must first give cfg80211 the BSS information */ + bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, + pRoamInfo); + if (NULL == bss) { + hddLog(LOGE, + FL("%s: unable to create IBSS entry"), + pAdapter->dev->name); + return; + } + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + chan_no = pRoamInfo->pBssDesc->channelId; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_5GHZ); + + chan = ieee80211_get_channel(pAdapter->wdev.wiphy, freq); + + if (chan) + cfg80211_ibss_joined(pAdapter->dev, + bss->bssid, chan, + GFP_KERNEL); + else + hddLog(LOGE, FL("%s: chanId: %d, can't find channel"), + pAdapter->dev->name, + (int)pRoamInfo->pBssDesc->channelId); +#else + cfg80211_ibss_joined(pAdapter->dev, bss->bssid, + GFP_KERNEL); +#endif + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + pHddCtx->wiphy, +#endif + bss); + } + + break; + } + + case eCSR_ROAM_RESULT_IBSS_START_FAILED: + { + hddLog(LOGE, + FL("%s: unable to create IBSS"), pAdapter->dev->name); + break; + } + + default: + hddLog(LOGE, FL("%s: unexpected result %d"), + pAdapter->dev->name, (int)roamResult); + break; + } + + return; +} + +/** + * roam_save_ibss_station() - Save the IBSS peer MAC address in the adapter + * @pHddStaCtx: pointer to global HDD station context + * @staId: station id + * @peerMacAddress: pointer to peer MAC address + * + * This information is passed to iwconfig later. The peer that joined + * last is passed as information to iwconfig. + * + * Return: + * true if we add MAX_IBSS_PEERS or less STA + * false otherwise. + */ +static bool roam_save_ibss_station(hdd_station_ctx_t *pHddStaCtx, uint8_t staId, + struct cdf_mac_addr *peerMacAddress) +{ + bool fSuccess = false; + int idx = 0; + + for (idx = 0; idx < MAX_IBSS_PEERS; idx++) { + if (0 == pHddStaCtx->conn_info.staId[idx]) { + pHddStaCtx->conn_info.staId[idx] = staId; + + cdf_copy_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[idx], peerMacAddress); + + fSuccess = true; + break; + } + } + + return fSuccess; +} + +/** + * roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter + * @pAdapter: pointer to adapter + * @staId: station id + * + * Return: + * true if we remove MAX_IBSS_PEERS or less STA + * false otherwise. + */ +static bool roam_remove_ibss_station(hdd_adapter_t *pAdapter, uint8_t staId) +{ + bool fSuccess = false; + int idx = 0; + uint8_t valid_idx = 0; + uint8_t del_idx = 0; + uint8_t empty_slots = 0; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + for (idx = 0; idx < MAX_IBSS_PEERS; idx++) { + if (staId == pHddStaCtx->conn_info.staId[idx]) { + pHddStaCtx->conn_info.staId[idx] = 0; + + cdf_zero_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[idx]); + + fSuccess = true; + + /* + * Note the deleted Index, if its 0 we need special + * handling. + */ + del_idx = idx; + + empty_slots++; + } else { + if (pHddStaCtx->conn_info.staId[idx] != 0) { + valid_idx = idx; + } else { + /* Found an empty slot */ + empty_slots++; + } + } + } + + if (MAX_IBSS_PEERS == empty_slots) { + /* Last peer departed, set the IBSS state appropriately */ + pHddStaCtx->conn_info.connState = + eConnectionState_IbssDisconnected; + hddLog(LOGE, "Last IBSS Peer Departed!!!"); + } + /* Find next active staId, to have a valid sta trigger for TL. */ + if (fSuccess == true) { + if (del_idx == 0) { + if (pHddStaCtx->conn_info.staId[valid_idx] != 0) { + pHddStaCtx->conn_info.staId[0] = + pHddStaCtx->conn_info.staId[valid_idx]; + cdf_copy_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[0], + &pHddStaCtx->conn_info. + peerMacAddress[valid_idx]); + + pHddStaCtx->conn_info.staId[valid_idx] = 0; + cdf_zero_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[valid_idx]); + } + } + } + return fSuccess; +} + +/** + * roam_ibss_connect_handler() - IBSS connection handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * We update the status of the IBSS to connected in this function. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS roam_ibss_connect_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + struct cfg80211_bss *bss; + hddLog(LOG1, FL("IBSS Connect Indication from SME. Set HDD connState to eConnectionState_IbssConnected")); + /* + * Set the internal connection state to show 'IBSS Connected' (IBSS with + * a partner stations). + */ + hdd_conn_set_connection_state(pAdapter, eConnectionState_IbssConnected); + + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(pAdapter->dev, pRoamInfo); + /* add bss_id to cfg80211 data base */ + bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo); + if (NULL == bss) { + hddLog(LOGE, + FL("%s: unable to create IBSS entry"), + pAdapter->dev->name); + return CDF_STATUS_E_FAILURE; + } + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + WLAN_HDD_GET_CTX(pAdapter)->wiphy, +#endif + bss); + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_mic_error_indication_handler() - MIC error indication handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * This function indicates the Mic failure to the supplicant + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +hdd_roam_mic_error_indication_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState && + TKIP_COUNTER_MEASURE_STOPED == + pHddStaCtx->WextState.mTKIPCounterMeasures) { + struct iw_michaelmicfailure msg; + union iwreq_data wreq; + memset(&msg, '\0', sizeof(msg)); + msg.src_addr.sa_family = ARPHRD_ETHER; + memcpy(msg.src_addr.sa_data, + pRoamInfo->u.pMICFailureInfo->taMacAddr, + sizeof(pRoamInfo->u.pMICFailureInfo->taMacAddr)); + hddLog(LOG1, "MIC MAC " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg.src_addr.sa_data)); + + if (pRoamInfo->u.pMICFailureInfo->multicast == eSIR_TRUE) + msg.flags = IW_MICFAILURE_GROUP; + else + msg.flags = IW_MICFAILURE_PAIRWISE; + memset(&wreq, 0, sizeof(wreq)); + wreq.data.length = sizeof(msg); + wireless_send_event(pAdapter->dev, IWEVMICHAELMICFAILURE, &wreq, + (char *)&msg); + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(pAdapter->dev, + pRoamInfo->u.pMICFailureInfo-> + taMacAddr, + ((pRoamInfo->u.pMICFailureInfo-> + multicast == + eSIR_TRUE) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + pRoamInfo->u.pMICFailureInfo-> + keyId, + pRoamInfo->u.pMICFailureInfo->TSC, + GFP_KERNEL); + + } + + return CDF_STATUS_SUCCESS; +} + +/** + * roam_roam_connect_status_update_handler() - IBSS connect status update + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * The Ibss connection status is updated regularly here in this function. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +roam_roam_connect_status_update_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + CDF_STATUS cdf_status; + + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + switch (roamResult) { + case eCSR_ROAM_RESULT_IBSS_NEW_PEER: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct station_info staInfo; + + pr_info("IBSS New Peer indication from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes), + pRoamInfo->staId); + + if (!roam_save_ibss_station + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), + pRoamInfo->staId, + &pRoamInfo->peerMac)) { + hddLog(LOGW, "Max reached: Can't register new IBSS peer"); + break; + } + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + + pHddCtx->sta_to_adapter[IBSS_BROADCAST_STAID] = + pAdapter; + + /* Register the Station with TL for the new peer. */ + cdf_status = hdd_roam_register_sta(pAdapter, + pRoamInfo, + pRoamInfo->staId, + &pRoamInfo->peerMac, + pRoamInfo->pBssDesc); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, + "Cannot register STA with TL for IBSS. Failed with cdf_status = %d [%08X]", + cdf_status, cdf_status); + } + pHddStaCtx->ibss_sta_generation++; + memset(&staInfo, 0, sizeof(staInfo)); + staInfo.filled = 0; + staInfo.generation = pHddStaCtx->ibss_sta_generation; + + cfg80211_new_sta(pAdapter->dev, + (const u8 *)pRoamInfo->peerMac.bytes, + &staInfo, GFP_KERNEL); + + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_TKIP == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_AES == + pHddStaCtx->ibss_enc_key.encType) { + pHddStaCtx->ibss_enc_key.keyDirection = + eSIR_TX_RX; + cdf_copy_macaddr(&pHddStaCtx->ibss_enc_key.peerMac, + &pRoamInfo->peerMac); + + hddLog(LOG2, "New peer joined set PTK encType=%d", + pHddStaCtx->ibss_enc_key.encType); + + cdf_status = + sme_roam_set_key(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &pHddStaCtx->ibss_enc_key, + &roamId); + + if (CDF_STATUS_SUCCESS != cdf_status) { + hddLog(LOGE, + FL("sme_roam_set_key failed, status=%d"), + cdf_status); + return CDF_STATUS_E_FAILURE; + } + } + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + + case eCSR_ROAM_RESULT_IBSS_CONNECT: + { + + roam_ibss_connect_handler(pAdapter, pRoamInfo); + + break; + } + case eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (!roam_remove_ibss_station(pAdapter, pRoamInfo->staId)) + hddLog(LOGW, + "IBSS peer departed by cannot find peer in our registration table with TL"); + + pr_info("IBSS Peer Departed from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes), + pRoamInfo->staId); + + hdd_roam_deregister_sta(pAdapter, pRoamInfo->staId); + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = NULL; + pHddStaCtx->ibss_sta_generation++; + + cfg80211_del_sta(pAdapter->dev, + (const u8 *)&pRoamInfo->peerMac.bytes, + GFP_KERNEL); + break; + } + case eCSR_ROAM_RESULT_IBSS_INACTIVE: + { + hddLog(LOG3, + "Received eCSR_ROAM_RESULT_IBSS_INACTIVE from SME"); + /* Stop only when we are inactive */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_NotConnected")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(pAdapter->dev, pRoamInfo); + break; + } + default: + break; + + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_TDLS +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @pAdapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @staId: station identifier + * @ucastSig: unicast signature + * + * Construct the staDesc and register with TL the new STA. + * This is called as part of ADD_STA in the TDLS setup. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_roam_register_tdlssta(hdd_adapter_t *pAdapter, + const uint8_t *peerMac, uint16_t staId, + uint8_t ucastSig) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + + /* + * TDLS sta in BSS should be set as STA type TDLS and STA MAC should + * be peer MAC, here we are working on direct Link + */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately .. */ + (hdd_wmm_is_active(pAdapter)) ? (staDesc.is_qos_enabled = 1) + : (staDesc.is_qos_enabled = 0); + + + /* Register the Station with TL... */ + cdf_status = ol_txrx_register_peer(hdd_rx_packet_cbk, + &staDesc); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("ol_txrx_register_peer() failed to register. Status=%d [0x%08X]"), + cdf_status, cdf_status); + return cdf_status; + } + + return cdf_status; +} + +/** + * hdd_roam_deregister_tdlssta() - deregister new TDLS station + * @pAdapter: pointer to adapter + * @staId: station identifier + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter, + uint8_t staId) +{ + CDF_STATUS cdf_status; + cdf_status = ol_txrx_clear_peer(staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGW, FL("ol_txrx_clear_peer() failed for staID %d. Status=%d [0x%08X]"), + staId, cdf_status, cdf_status); + } + return cdf_status; +} + +/** + * hdd_roam_tdls_status_update_handler() - TDLS status update handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * HDD interface between SME and TL to ensure TDLS client registration with + * TL in case of new TDLS client is added and deregistration at the time + * TDLS client is deleted. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + tSmeTdlsPeerStateParams smeTdlsPeerStateParams; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint8_t staIdx; + hddTdlsPeer_t *curr_peer; + uint32_t reason; + + hddLog(LOG2, + ("hdd_tdlsStatusUpdate: %s staIdx %d " MAC_ADDRESS_STR), + roamResult == + eCSR_ROAM_RESULT_ADD_TDLS_PEER ? "ADD_TDLS_PEER" : roamResult + == + eCSR_ROAM_RESULT_DELETE_TDLS_PEER ? "DEL_TDLS_PEER" : + roamResult == + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND ? "DEL_TDLS_PEER_IND" + : roamResult == + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND ? + "DEL_ALL_TDLS_PEER_IND" : roamResult == + eCSR_ROAM_RESULT_UPDATE_TDLS_PEER ? "UPDATE_TDLS_PEER" : + roamResult == + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP ? + "LINK_ESTABLISH_REQ_RSP" : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER ? "TDLS_SHOULD_DISCOVER" + : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN ? "TDLS_SHOULD_TEARDOWN" + : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED ? + "TDLS_SHOULD_PEER_DISCONNECTED" : "UNKNOWN", pRoamInfo->staId, + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes)); + + if (!pHddTdlsCtx) { + hddLog(LOG1, + FL("TDLS ctx is null, ignore roamResult (%d)"), + roamResult); + return status; + } + + switch (roamResult) { + case eCSR_ROAM_RESULT_ADD_TDLS_PEER: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hddLog(LOGE, FL("Add Sta failed. status code(=%d)"), + pRoamInfo->statusCode); + } else { + /* + * Check if there is available index for this new TDLS + * STA. + */ + for (staIdx = 0; + staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if (0 == + pHddCtx->tdlsConnInfo[staIdx]. + staId) { + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = + pRoamInfo->sessionId; + pHddCtx->tdlsConnInfo[staIdx]. + staId = pRoamInfo->staId; + + hddLog(LOGW, + ("TDLS: STA IDX at %d is %d " + "of mac " + MAC_ADDRESS_STR), + staIdx, + pHddCtx-> + tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY + (pRoamInfo->peerMac.bytes)); + + cdf_copy_macaddr(&pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac, + &pRoamInfo-> + peerMac); + status = CDF_STATUS_SUCCESS; + break; + } + } + if (staIdx < pHddCtx->max_num_tdls_sta) { + if (-1 == + wlan_hdd_tdls_set_sta_id(pAdapter, + pRoamInfo-> + peerMac.bytes, + pRoamInfo-> + staId)) { + hddLog(LOGE, + "wlan_hdd_tdls_set_sta_id() failed"); + return CDF_STATUS_E_FAILURE; + } + + (WLAN_HDD_GET_CTX(pAdapter))-> + sta_to_adapter[pRoamInfo->staId] = + pAdapter; + /* + * store the ucast signature, + * if required for further reference. + */ + + wlan_hdd_tdls_set_signature(pAdapter, + pRoamInfo-> + peerMac.bytes, + pRoamInfo-> + ucastSig); + } else { + status = CDF_STATUS_E_FAILURE; + hddLog(LOGE, + FL("no available slot in conn_info. staId %d cannot be stored"), + pRoamInfo->staId); + } + pAdapter->tdlsAddStaStatus = status; + } + complete(&pAdapter->tdls_add_station_comp); + break; + } + case eCSR_ROAM_RESULT_UPDATE_TDLS_PEER: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hddLog(LOGE, + FL("Add Sta failed. status code(=%d)"), + pRoamInfo->statusCode); + } + /* store the ucast signature which will be used later when + * registering to TL + */ + pAdapter->tdlsAddStaStatus = pRoamInfo->statusCode; + complete(&pAdapter->tdls_add_station_comp); + break; + } + case eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hddLog(LOGE, + FL("Link Establish Request failed. status(=%d)"), + pRoamInfo->statusCode); + } + complete(&pAdapter->tdls_link_establish_req_comp); + break; + } + case eCSR_ROAM_RESULT_DELETE_TDLS_PEER: + { + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pRoamInfo->sessionId) + && pRoamInfo->staId == + pHddCtx->tdlsConnInfo[staIdx].staId) { + hddLog(LOGW, + ("HDD: del STA IDX = %x"), + pRoamInfo->staId); + + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo-> + peerMac.bytes, + true); + if (NULL != curr_peer + && TDLS_IS_CONNECTED(curr_peer)) { + hdd_roam_deregister_tdlssta + (pAdapter, + pRoamInfo->staId); + wlan_hdd_tdls_decrement_peer_count + (pAdapter); + } + wlan_hdd_tdls_reset_peer(pAdapter, + pRoamInfo-> + peerMac.bytes); + + pHddCtx->tdlsConnInfo[staIdx].staId = 0; + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = 255; + cdf_mem_zero(&pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac, + CDF_MAC_ADDR_SIZE); + status = CDF_STATUS_SUCCESS; + break; + } + } + complete(&pAdapter->tdls_del_station_comp); + } + break; + case eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND: + { + hddLog(LOGE, + FL("Sending teardown to supplicant with reason code %u"), + pRoamInfo->reasonCode); + + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes, true); + wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, + pRoamInfo->reasonCode); + status = CDF_STATUS_SUCCESS; + break; + } + case eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND: + { + /* 0 staIdx is assigned to AP we dont want to touch that */ + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pRoamInfo->sessionId) + && pHddCtx->tdlsConnInfo[staIdx].staId) { + hddLog(LOGW, + ("hdd_tdlsStatusUpdate: staIdx %d " + MAC_ADDRESS_STR), + pHddCtx->tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY(pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes)); + wlan_hdd_tdls_reset_peer(pAdapter, + pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac.bytes); + hdd_roam_deregister_tdlssta(pAdapter, + pHddCtx-> + tdlsConnInfo + [staIdx]. + staId); + cdf_mem_zero(&smeTdlsPeerStateParams, + sizeof + (smeTdlsPeerStateParams)); + smeTdlsPeerStateParams.vdevId = + pHddCtx->tdlsConnInfo[staIdx]. + sessionId; + cdf_mem_copy(&smeTdlsPeerStateParams. + peerMacAddr, + &pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac.bytes, + CDF_MAC_ADDR_SIZE); + smeTdlsPeerStateParams.peerState = + eSME_TDLS_PEER_STATE_TEARDOWN; + + hddLog(LOG1, + FL("calling sme_update_tdls_peer_state for staIdx %d " + MAC_ADDRESS_STR), + pHddCtx->tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY(pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes)); + status = + sme_update_tdls_peer_state( + pHddCtx->hHal, + &smeTdlsPeerStateParams); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, + FL("sme_update_tdls_peer_state failed for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY + (pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac.bytes)); + } + wlan_hdd_tdls_decrement_peer_count + (pAdapter); + + cdf_mem_zero(&pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac, + CDF_MAC_ADDR_SIZE); + pHddCtx->tdlsConnInfo[staIdx].staId = 0; + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = 255; + + status = CDF_STATUS_SUCCESS; + } + } + break; + } + case eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER: + { + /* ignore TDLS_SHOULD_DISCOVER if any concurrency detected */ + if (((1 << CDF_STA_MODE) != pHddCtx->concurrency_mode) || + (pHddCtx->no_of_active_sessions[CDF_STA_MODE] > 1)) { + hddLog(LOG2, + FL("concurrency detected. ignore SHOULD_DISCOVER concurrency_mode: 0x%x, active_sessions: %d"), + pHddCtx->concurrency_mode, + pHddCtx->no_of_active_sessions[CDF_STA_MODE]); + status = CDF_STATUS_E_FAILURE; + break; + } + + curr_peer = + wlan_hdd_tdls_get_peer(pAdapter, + pRoamInfo->peerMac.bytes); + if (!curr_peer) { + hddLog(LOGE, FL("curr_peer is null")); + status = CDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hddLog(LOGE, + FL("TDLS link status is connected, ignore SHOULD_DISCOVER")); + } else { + /* + * If external control is enabled then initiate + * TDLS only if forced peer is set otherwise + * ignore should Discover trigger from fw. + */ + if (pHddCtx->config-> + fTDLSExternalControl + && (false == + curr_peer->isForcedPeer)) { + hddLog(LOG2, + FL + ("TDLS ExternalControl enabled but curr_peer is not forced, ignore SHOULD_DISCOVER")); + status = CDF_STATUS_SUCCESS; + break; + } else { + hddLog(LOG2, + FL + ("initiate TDLS setup on SHOULD_DISCOVER, fTDLSExternalControl: %d, curr_peer->isForcedPeer: %d, reason: %d"), + pHddCtx->config-> + fTDLSExternalControl, + curr_peer->isForcedPeer, + pRoamInfo->reasonCode); + } + wlan_hdd_tdls_pre_setup_init_work + (pHddTdlsCtx, curr_peer); + } + status = CDF_STATUS_SUCCESS; + } + break; + } + + case eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN: + { + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes, true); + if (!curr_peer) { + hddLog(LOGE, FL("curr_peer is null")); + status = CDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hddLog(LOGE, + FL + ("Received SHOULD_TEARDOWN for peer " + MAC_ADDRESS_STR + " staId: %d, reason: %d"), + MAC_ADDR_ARRAY(pRoamInfo-> + peerMac.bytes), + pRoamInfo->staId, + pRoamInfo->reasonCode); + + if (pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_RSSI || + pRoamInfo->reasonCode == + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) { + reason = + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE; + } else + reason = + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON; + + wlan_hdd_tdls_indicate_teardown + (pHddTdlsCtx->pAdapter, curr_peer, + reason); + } else { + hddLog(LOGE, + FL + ("TDLS link is not connected, ignore SHOULD_TEARDOWN, reason: %d"), + pRoamInfo->reasonCode); + } + status = CDF_STATUS_SUCCESS; + } + break; + } + + case eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED: + { + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes, true); + if (!curr_peer) { + hddLog(LOGE, FL("curr_peer is null")); + status = CDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hddLog(LOGE, + FL + ("Received SHOULD_PEER_DISCONNECTED for peer " + MAC_ADDRESS_STR + " staId: %d, reason: %d"), + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + pRoamInfo->staId, + pRoamInfo->reasonCode); + + if (pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_RSSI || + pRoamInfo->reasonCode == + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) { + reason = + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE; + } else + reason = + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON; + + wlan_hdd_tdls_indicate_teardown + (pHddTdlsCtx->pAdapter, curr_peer, + reason); + } else { + hddLog(LOGE, + FL + ("TDLS link is not connected, ignore SHOULD_PEER_DISCONNECTED, reason: %d"), + pRoamInfo->reasonCode); + } + status = CDF_STATUS_SUCCESS; + } + break; + } + default: + { + break; + } + } + + return status; +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame + * @pAdapter: pointer to the adapter + * @nFrameLength: Length of the unprotected frame being passed + * @pbFrames: Pointer to the frame buffer + * @frameType: 802.11 frame type + * + * This function forwards the unprotected management frame to the supplicant. + * + * Return: nothing + */ +static void +hdd_indicate_unprot_mgmt_frame(hdd_adapter_t *pAdapter, uint32_t nFrameLength, + uint8_t *pbFrames, uint8_t frameType) +{ + uint8_t type = 0; + uint8_t subType = 0; + + hddLog(LOG1, FL("Frame Type = %d Frame Length = %d"), + frameType, nFrameLength); + + /* Sanity Checks */ + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL")); + return; + } + + if (NULL == pAdapter->dev) { + hddLog(LOGE, FL("pAdapter->dev is NULL")); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hddLog(LOGE, FL("pAdapter has invalid magic")); + return; + } + + if (!nFrameLength) { + hddLog(LOGE, FL("Frame Length is Invalid ZERO")); + return; + } + + if (NULL == pbFrames) { + hddLog(LOGE, FL("pbFrames is NULL")); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]); + + /* Get pAdapter from Destination mac address of the frame */ + if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DISASSOC) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_disassoc(pAdapter->dev, pbFrames, + nFrameLength); +#endif + pAdapter->hdd_stats.hddPmfStats.numUnprotDisassocRx++; + } else if (type == SIR_MAC_MGMT_FRAME && + subType == SIR_MAC_MGMT_DEAUTH) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_deauth(pAdapter->dev, pbFrames, + nFrameLength); +#endif + pAdapter->hdd_stats.hddPmfStats.numUnprotDeauthRx++; + } else { + hddLog(LOGE, FL("Frame type %d and subtype %d are not valid"), + type, subType); + return; + } +} +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * hdd_indicate_tsm_ie() - send traffic stream metrics ie + * @pAdapter: pointer to adapter + * @tid: traffic identifier + * @state: state + * @measInterval: measurement interval + * + * This function sends traffic stream metrics IE information to + * the supplicant via wireless event. + * + * Return: none + */ +static void +hdd_indicate_tsm_ie(hdd_adapter_t *pAdapter, uint8_t tid, + uint8_t state, uint16_t measInterval) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if (NULL == pAdapter) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hddLog(LOG1, "TSM Ind tid(%d) state(%d) MeasInt(%d)", + tid, state, measInterval); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "TSMIE=%d:%d:%d", tid, state, + measInterval); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_cckm_pre_auth() - send cckm preauth indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * This function sends cckm preauth indication to the supplicant + * via wireless custom event. + * + * Return: none + */ +static void +hdd_indicate_cckm_pre_auth(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + /* Timestamp0 is lower 32 bits and Timestamp1 is upper 32 bits */ + hddLog(LOG1, + "CCXPREAUTHNOTIFY=" MAC_ADDRESS_STR " %d:%d", + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]); + + nBytes = snprintf(pos, freeBytes, "CCXPREAUTHNOTIFY="); + pos += nBytes; + freeBytes -= nBytes; + + cdf_mem_copy(pos, pRoamInfo->bssid.bytes, CDF_MAC_ADDR_SIZE); + pos += CDF_MAC_ADDR_SIZE; + freeBytes -= CDF_MAC_ADDR_SIZE; + + nBytes = snprintf(pos, freeBytes, " %u:%u", + pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]); + freeBytes -= nBytes; + + wrqu.data.pointer = buf; + wrqu.data.length = (IW_CUSTOM_MAX - freeBytes); + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_adj_ap_rep_ind() - send adjacent AP report indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * Return: none + */ +static void +hdd_indicate_ese_adj_ap_rep_ind(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hddLog(LOG1, "CCXADJAPREP=%u", pRoamInfo->tsmRoamDelay); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "CCXADJAPREP=%u", + pRoamInfo->tsmRoamDelay); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @pAdapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const hdd_adapter_t *pAdapter, + const uint16_t measurementToken, + const bool flag, const uint8_t numBss) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hddLog(LOG1, FL("CCXBCNREP=%d %d %d"), measurementToken, + flag, numBss); + + nBytes = + snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d", measurementToken, + flag, numBss); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_ind() - send beacon report indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +static void +hdd_indicate_ese_bcn_report_ind(const hdd_adapter_t *pAdapter, + const tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + uint8_t i = 0, len = 0; + uint8_t tot_bcn_ieLen = 0; /* total size of the beacon report data */ + uint8_t lastSent = 0, sendBss = 0; + int bcnRepFieldSize = + sizeof(pRoamInfo->pEseBcnReportRsp->bcnRepBssInfo[0]. + bcnReportFields); + uint8_t ieLenByte = 1; + /* + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ +#define ESEBCNREPHEADER_LEN (18) + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* + * Custom event can pass maximum of 256 bytes of data, + * based on the IE len we need to identify how many BSS info can + * be filled in to custom event data. + */ + /* + * meas_tokflagno_of_bsstot_bcn_ie_len bcn_rep_data + * bcn_rep_data will have bcn_rep_fields,ie_len,ie without any spaces + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ + + if ((pRoamInfo->pEseBcnReportRsp->flag >> 1) + && (!pRoamInfo->pEseBcnReportRsp->numBss)) { + hddLog(LOG1, + "Measurement Done but no scan results"); + /* If the measurement is none and no scan results found, + indicate the supplicant about measurement done */ + hdd_indicate_ese_bcn_report_no_results( + pAdapter, + pRoamInfo->pEseBcnReportRsp-> + measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, + pRoamInfo->pEseBcnReportRsp->numBss); + } else { + while (lastSent < pRoamInfo->pEseBcnReportRsp->numBss) { + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + tot_bcn_ieLen = 0; + sendBss = 0; + pos = buf; + freeBytes = IW_CUSTOM_MAX; + + for (i = lastSent; + i < pRoamInfo->pEseBcnReportRsp->numBss; i++) { + len = + bcnRepFieldSize + ieLenByte + + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen; + if ((len + tot_bcn_ieLen) > + (IW_CUSTOM_MAX - ESEBCNREPHEADER_LEN)) { + break; + } + tot_bcn_ieLen += len; + sendBss++; + hddLog(LOG1, "i(%d) sizeof bcnReportFields(%d) IeLength(%d) Length of Ie(%d) totLen(%d)", + i, bcnRepFieldSize, 1, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen, tot_bcn_ieLen); + } + + hddLog(LOG1, "Sending %d BSS Info", + sendBss); + hddLog(LOG1, "CCXBCNREP=%d %d %d %d", + pRoamInfo->pEseBcnReportRsp->measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, sendBss, + tot_bcn_ieLen); + + nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d ", + pRoamInfo->pEseBcnReportRsp-> + measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, + sendBss); + pos += nBytes; + freeBytes -= nBytes; + + /* Copy total Beacon report data length */ + cdf_mem_copy(pos, (char *)&tot_bcn_ieLen, + sizeof(tot_bcn_ieLen)); + pos += sizeof(tot_bcn_ieLen); + freeBytes -= sizeof(tot_bcn_ieLen); + + for (i = 0; i < sendBss; i++) { + hddLog(LOG1, + "ChanNum(%d) Spare(%d) MeasDuration(%d)" + " PhyType(%d) RecvSigPower(%d) ParentTSF(%u)" + " TargetTSF[0](%u) TargetTSF[1](%u) BeaconInterval(%u)" + " CapabilityInfo(%d) BSSID(%02X:%02X:%02X:%02X:%02X:%02X)", + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ChanNum, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Spare, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + MeasDuration, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + PhyType, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + RecvSigPower, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ParentTsf, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[0], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[1], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + BcnInterval, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + CapabilityInfo, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[0], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[1], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[2], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[3], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[4], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[5]); + + /* bcn report fields are copied */ + len = + sizeof(pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent]. + bcnReportFields); + cdf_mem_copy(pos, + (char *)&pRoamInfo-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + bcnReportFields, len); + pos += len; + freeBytes -= len; + + /* Add 1 byte of ie len */ + len = + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + lastSent].ieLen; + cdf_mem_copy(pos, (char *)&len, sizeof(len)); + pos += sizeof(len); + freeBytes -= sizeof(len); + + /* copy IE from scan results */ + cdf_mem_copy(pos, + (char *)pRoamInfo-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + pBuf, len); + pos += len; + freeBytes -= len; + } + + wrqu.data.pointer = buf; + wrqu.data.length = IW_CUSTOM_MAX - freeBytes; + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + buf); + lastSent += sendBss; + } + } +} + +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS +hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus roamStatus, eCsrRoamResult roamResult) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pContext; + hdd_wext_state_t *pWextState = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_context_t *pHddCtx = NULL; + + hddLog(LOG2, + "CSR Callback: status= %d result= %d roamID=%d", + roamStatus, roamResult, roamId); + + /* Sanity check */ + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hddLog(LOGP, "invalid adapter or adapter has invalid magic"); + return CDF_STATUS_E_FAILURE; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + switch (roamStatus) { + case eCSR_ROAM_SESSION_OPENED: + if (pAdapter != NULL) { + set_bit(SME_SESSION_OPENED, &pAdapter->event_flags); + complete(&pAdapter->session_open_comp_var); + } + break; + +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR) + /* + * We did pre-auth,then we attempted a 11r or ese reassoc. + * reassoc failed due to failure, timeout, reject from ap + * in any case tell the OS, our carrier is off and mark + * interface down. + */ + case eCSR_ROAM_FT_REASSOC_FAILED: + hddLog(LOGE, + FL + ("Reassoc Failed with roamStatus: %d roamResult: %d SessionID: %d"), + roamStatus, roamResult, pAdapter->sessionId); + cdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + /* + * Check if Mcast/Bcast Filters are set, if yes + * clear the filters here. + */ + if ((WLAN_HDD_GET_CTX(pAdapter))->hdd_mcastbcast_filter_set == + true) { + (WLAN_HDD_GET_CTX(pAdapter))-> + hdd_mcastbcast_filter_set = false; + } + pHddStaCtx->ft_carrier_on = false; + pHddStaCtx->hdd_ReassocScenario = false; + hddLog(LOG1, + FL("hdd_ReassocScenario set to: %d, ReAssoc Failed, session: %d"), + pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId); + break; + + case eCSR_ROAM_FT_START: + /* + * When we roam for ESE and 11r, we dont want the OS to be + * informed that the link is down. So mark the link ready for + * ft_start. After this the eCSR_ROAM_SHOULD_ROAM will + * be received. Where in we will not mark the link down + * Also we want to stop tx at this point when we will be + * doing disassoc at this time. This saves 30-60 msec + * after reassoc. + */ + { + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE, + WLAN_CONTROL_PATH); + status = + hdd_roam_deregister_sta(pAdapter, + pHddStaCtx->conn_info. + staId[0]); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGW, + FL + ("hdd_roam_deregister_sta() failed to for staID %d. Status=%d [0x%x]"), + pHddStaCtx->conn_info.staId[0], + status, status); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + } + pHddStaCtx->ft_carrier_on = true; + pHddStaCtx->hdd_ReassocScenario = true; + hddLog(LOG1, + FL("hdd_ReassocScenario set to: %d, due to eCSR_ROAM_FT_START, session: %d"), + pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId); + break; +#endif + + case eCSR_ROAM_SHOULD_ROAM: + /* Dont need to do anything */ + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + /* notify apps that we can't pass traffic anymore */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE, + WLAN_CONTROL_PATH); +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR) + if (pHddStaCtx->ft_carrier_on == false) { +#endif + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR) + } +#endif + +#if !(defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ +defined(FEATURE_WLAN_LFR)) + /* + * We should clear all sta register with TL, for now, only one. + */ + status = + hdd_roam_deregister_sta(pAdapter, + pHddStaCtx->conn_info. + staId[0]); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGW, + FL + ("hdd_roam_deregister_sta() failed to for staID %d. Status=%d [0x%x]"), + pHddStaCtx->conn_info.staId[0], + status, status); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } +#endif + } + break; + case eCSR_ROAM_LOSTLINK: + if (roamResult == eCSR_ROAM_RESULT_LOSTLINK) { + hddLog(LOG2, "Roaming started due to connection lost"); + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + case eCSR_ROAM_DISASSOCIATED: + { + hddLog(LOG1, "****eCSR_ROAM_DISASSOCIATED****"); + cdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + /* Check if Mcast/Bcast Filters are set, if yes clear the filters here */ + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (pHddCtx->hdd_mcastbcast_filter_set == true) { + hdd_conf_mcastbcast_filter(pHddCtx, false); + + if (true == + pHddCtx->sus_res_mcastbcast_filter_valid) { + pHddCtx->configuredMcastBcastFilter = + pHddCtx->sus_res_mcastbcast_filter; + pHddCtx-> + sus_res_mcastbcast_filter_valid = + false; + } + + hddLog(LOG1, + "offload: disassociation happening, restoring configuredMcastBcastFilter"); + hddLog(LOG1, + "McastBcastFilter = %d", + pHddCtx->configuredMcastBcastFilter); + hddLog(LOG1, + "offload: already called mcastbcast filter"); + (WLAN_HDD_GET_CTX(pAdapter))-> + hdd_mcastbcast_filter_set = false; + } + /* Call to clear any MC Addr List filter applied after + * successful connection. + */ + wlan_hdd_set_mc_addr_list(pAdapter, false); + } + break; + case eCSR_ROAM_IBSS_LEAVE: + hddLog(LOG1, "****eCSR_ROAM_IBSS_LEAVE****"); + cdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + break; + case eCSR_ROAM_ASSOCIATION_COMPLETION: + hddLog(LOG1, "****eCSR_ROAM_ASSOCIATION_COMPLETION****"); + /* + * To Do - address probable memory leak with WEP encryption upon + * successful association. + */ + if (eCSR_ROAM_RESULT_ASSOCIATED != roamResult) { + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info( + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)); + } + cdf_ret_status = + hdd_association_completion_handler(pAdapter, pRoamInfo, + roamId, roamStatus, + roamResult); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo) + pRoamInfo->roamSynchInProgress = false; +#endif + break; + case eCSR_ROAM_ASSOCIATION_FAILURE: + cdf_ret_status = hdd_association_completion_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + case eCSR_ROAM_IBSS_IND: + hdd_roam_ibss_indication_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + break; + + case eCSR_ROAM_CONNECT_STATUS_UPDATE: + cdf_ret_status = + roam_roam_connect_status_update_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + + case eCSR_ROAM_MIC_ERROR_IND: + cdf_ret_status = + hdd_roam_mic_error_indication_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + + case eCSR_ROAM_SET_KEY_COMPLETE: + { + cdf_ret_status = + hdd_roam_set_key_complete_handler(pAdapter, pRoamInfo, + roamId, roamStatus, + roamResult); + if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) { + pHddStaCtx->hdd_ReassocScenario = false; + hddLog(LOG1, + FL("hdd_ReassocScenario set to: %d, set key complete, session: %d"), + pHddStaCtx->hdd_ReassocScenario, + pAdapter->sessionId); + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo != NULL) + pRoamInfo->roamSynchInProgress = false; +#endif + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_ROAM_FT_RESPONSE: + hdd_send_ft_event(pAdapter); + break; +#endif +#if defined(FEATURE_WLAN_LFR) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + case eCSR_ROAM_PMK_NOTIFY: + if (eCSR_AUTH_TYPE_RSN == pHddStaCtx->conn_info.authType || + eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + pHddStaCtx->conn_info.authType) { + /* notify the supplicant of a new candidate */ + cdf_ret_status = + wlan_hdd_cfg80211_pmksa_candidate_notify( + pAdapter, pRoamInfo, 1, false); + } + break; +#endif + +#ifdef FEATURE_WLAN_LFR_METRICS + case eCSR_ROAM_PREAUTH_INIT_NOTIFY: + /* This event is to notify pre-auth initiation */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth(pAdapter, + pRoamInfo)) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_SUCCESS: + /* + * This event will notify pre-auth completion in case of success + */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter, + pRoamInfo, 1)) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_FAILURE: + /* + * This event will notify pre-auth completion incase of failure. + */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter, + pRoamInfo, 0)) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_HANDOVER_SUCCESS: + /* This event is to notify handover success. + It will be only invoked on success */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_handover(pAdapter, + pRoamInfo)) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; +#endif + + case eCSR_ROAM_INDICATE_MGMT_FRAME: + hdd_indicate_mgmt_frame(pAdapter, + pRoamInfo->nFrameLength, + pRoamInfo->pbFrames, + pRoamInfo->frameType, + pRoamInfo->rxChan, pRoamInfo->rxRssi); + break; + case eCSR_ROAM_REMAIN_CHAN_READY: + hdd_remain_chan_ready_handler(pAdapter, pRoamInfo->roc_scan_id); + break; + case eCSR_ROAM_SEND_ACTION_CNF: + hdd_send_action_cnf(pAdapter, + (roamResult == + eCSR_ROAM_RESULT_NONE) ? true : false); + break; +#ifdef FEATURE_WLAN_TDLS + case eCSR_ROAM_TDLS_STATUS_UPDATE: + cdf_ret_status = + hdd_roam_tdls_status_update_handler(pAdapter, pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + case eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND: + wlan_hdd_tdls_mgmt_completion_callback(pAdapter, + pRoamInfo->reasonCode); + break; +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_ROAM_UNPROT_MGMT_FRAME_IND: + hdd_indicate_unprot_mgmt_frame(pAdapter, + pRoamInfo->nFrameLength, + pRoamInfo->pbFrames, + pRoamInfo->frameType); + break; +#endif +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eCSR_ROAM_TSM_IE_IND: + hdd_indicate_tsm_ie(pAdapter, pRoamInfo->tsmIe.tsid, + pRoamInfo->tsmIe.state, + pRoamInfo->tsmIe.msmt_interval); + break; + + case eCSR_ROAM_CCKM_PREAUTH_NOTIFY: + { + if (eCSR_AUTH_TYPE_CCKM_WPA == + pHddStaCtx->conn_info.authType + || eCSR_AUTH_TYPE_CCKM_RSN == + pHddStaCtx->conn_info.authType) { + hdd_indicate_cckm_pre_auth(pAdapter, pRoamInfo); + } + break; + } + + case eCSR_ROAM_ESE_ADJ_AP_REPORT_IND: + { + hdd_indicate_ese_adj_ap_rep_ind(pAdapter, pRoamInfo); + break; + } + + case eCSR_ROAM_ESE_BCN_REPORT_IND: + { + hdd_indicate_ese_bcn_report_ind(pAdapter, pRoamInfo); + break; + } +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + default: + break; + } + return cdf_ret_status; +} + +/** + * hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType auth_type; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_rsn_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN; + } else if (memcmp(auth_suite, ccp_rsn_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK; + } else +#ifdef WLAN_FEATURE_VOWIFI_11R + if (memcmp(auth_suite, ccp_rsn_oui04, 4) == 0) { + /* Check for 11r FT Authentication with PSK */ + auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK; + } else if (memcmp(auth_suite, ccp_rsn_oui03, 4) == 0) { + /* Check for 11R FT Authentication with 802.1X */ + auth_type = eCSR_AUTH_TYPE_FT_RSN; + } else +#endif +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_rsn_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + if (memcmp(auth_suite, ccp_rsn_oui07, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (memcmp(auth_suite, ccp_rsn_oui08, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else +#endif + { + auth_type = eCSR_AUTH_TYPE_UNKNOWN; + } + return auth_type; +} + +/** + * hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType auth_type; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_wpa_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA; + } else if (memcmp(auth_suite, ccp_wpa_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA_PSK; + } else +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_wpa_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif /* FEATURE_WLAN_ESE */ + { + auth_type = eCSR_AUTH_TYPE_UNKNOWN; + } + hddLog(LOG1, FL("auth_type: %d"), auth_type); + return auth_type; +} + +/** + * hdd_translate_rsn_to_csr_encryption_type() - + * Translate RSN to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_rsn_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_rsn_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_rsn_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_rsn_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_rsn_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + hddLog(LOG1, FL("cipher_type: %d"), cipher_type); + return cipher_type; +} + +/** + * hdd_translate_wpa_to_csr_encryption_type() - + * Translate WPA to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_wpa_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_wpa_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_wpa_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_wpa_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_wpa_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + hddLog(LOG1, FL("cipher_type: %d"), cipher_type); + return cipher_type; +} + +/** + * hdd_process_genie() - process gen ie + * @pAdapter: pointer to adapter + * @bssid: pointer to mac address + * @pEncryptType: pointer to encryption type + * @mcEncryptType: pointer to multicast encryption type + * @pAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +static int32_t hdd_process_genie(hdd_adapter_t *pAdapter, + u8 *bssid, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, +#ifdef WLAN_FEATURE_11W + uint8_t *pMfpRequired, uint8_t *pMfpCapable, +#endif + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + CDF_STATUS result; + tDot11fIERSN dot11RSNIE; + tDot11fIEWPA dot11WPAIE; + uint32_t i; + uint8_t *pRsnIe; + uint16_t RSNIeLen; + tPmkidCacheInfo PMKIDCache[4]; /* Local transfer memory */ + bool updatePMKCache = false; + + /* + * Clear struct of tDot11fIERSN and tDot11fIEWPA specifically + * setting present flag to 0. + */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + + /* Type check */ + if (gen_ie[0] == DOT11F_EID_RSN) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) || + (gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) { + hddLog(LOGE, FL("Invalid DOT11F RSN IE length :%d"), + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID byte and length byte */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + dot11f_unpack_ie_rsn((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11RSNIE); + /* Copy out the encryption and authentication types */ + hddLog(LOG1, FL("pairwise cipher suite count: %d"), + dot11RSNIE.pwise_cipher_suite_count); + hddLog(LOG1, FL("authentication suite count: %d"), + dot11RSNIE.akm_suite_count); + /*Here we have followed the apple base code, + but probably I suspect we can do something different */ + /* dot11RSNIE.akm_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type( + dot11RSNIE.akm_suites[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.gp_cipher_suite); +#ifdef WLAN_FEATURE_11W + *pMfpRequired = (dot11RSNIE.RSN_Cap[0] >> 6) & 0x1; + *pMfpCapable = (dot11RSNIE.RSN_Cap[0] >> 7) & 0x1; +#endif + /* Set the PMKSA ID Cache for this interface */ + for (i = 0; i < dot11RSNIE.pmkid_count; i++) { + if (is_zero_ether_addr(bssid)) { + hddLog(LOGE, FL("MAC address is all zeroes")); + break; + } + updatePMKCache = true; + /* + * For right now, I assume setASSOCIATE() has passed + * in the bssid. + */ + cdf_mem_copy(PMKIDCache[i].BSSID.bytes, + bssid, ETHER_ADDR_LEN); + cdf_mem_copy(PMKIDCache[i].PMKID, + dot11RSNIE.pmkid[i], CSR_RSN_PMKID_SIZE); + } + + if (updatePMKCache) { + /* + * Calling csr_roam_set_pmkid_cache to configure the + * PMKIDs into the cache. + */ + hddLog(LOG1, + FL("Calling sme_roam_set_pmkid_cache with cache entry %d."), + i); + /* Finally set the PMKSA ID Cache in CSR */ + result = + sme_roam_set_pmkid_cache(halHandle, + pAdapter->sessionId, + PMKIDCache, + dot11RSNIE.pmkid_count, + false); + } + } else if (gen_ie[0] == DOT11F_EID_WPA) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) { + hddLog(LOGE, FL("Invalid DOT11F WPA IE length :%d"), + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID and length byte - and four byte WiFi OUI */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11WPAIE); + /* Copy out the encryption and authentication types */ + hddLog(LOG1, FL("WPA unicast cipher suite count: %d"), + dot11WPAIE.unicast_cipher_count); + hddLog(LOG1, FL("WPA authentication suite count: %d"), + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type( + dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.multicast_cipher); + } else { + hddLog(LOGW, FL("gen_ie[0]: %d"), gen_ie[0]); + return -EINVAL; + } + return 0; +} + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @pAdapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + uint32_t status = 0; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; +#ifdef WLAN_FEATURE_11W + uint8_t RSNMfpRequired = 0; + uint8_t RSNMfpCapable = 0; +#endif + u8 bssid[ETH_ALEN]; /* MAC address of assoc peer */ + /* MAC address of assoc peer */ + /* But, this routine is only called when we are NOT associated. */ + cdf_mem_copy(bssid, + pWextState->roamProfile.BSSIDs.bssid, + sizeof(bssid)); + if (pWextState->WPARSNIE[0] == DOT11F_EID_RSN + || pWextState->WPARSNIE[0] == DOT11F_EID_WPA) { + /* continue */ + } else { + return 0; + } + /* The actual processing may eventually be more extensive than this. */ + /* Right now, just consume any PMKIDs that are sent in by the app. */ + status = hdd_process_genie(pAdapter, bssid, + &RSNEncryptType, + &mcRSNEncryptType, RSNAuthType, +#ifdef WLAN_FEATURE_11W + &RSNMfpRequired, &RSNMfpCapable, +#endif + pWextState->WPARSNIE[1] + 2, + pWextState->WPARSNIE); + if (status == 0) { + /* + * Now copy over all the security attributes + * you have parsed out. + */ + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + + pWextState->roamProfile.EncryptionType.encryptionType[0] = RSNEncryptType; /* Use the cipher type in the RSN IE */ + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + mcRSNEncryptType; + + if ((WLAN_HDD_IBSS == pAdapter->device_mode) && + ((eCSR_ENCRYPT_TYPE_AES == mcRSNEncryptType) || + (eCSR_ENCRYPT_TYPE_TKIP == mcRSNEncryptType))) { + /* + * For wpa none supplicant sends the WPA IE with unicast + * cipher as eCSR_ENCRYPT_TYPE_NONE ,where as the + * multicast cipher as either AES/TKIP based on group + * cipher configuration mentioned in the + * wpa_supplicant.conf. + */ + + /* Set the unicast cipher same as multicast cipher */ + pWextState->roamProfile.EncryptionType.encryptionType[0] + = mcRSNEncryptType; + } +#ifdef WLAN_FEATURE_11W + hddLog(LOG1, FL("RSNMfpRequired = %d, RSNMfpCapable = %d"), + RSNMfpRequired, RSNMfpCapable); + pWextState->roamProfile.MFPRequired = RSNMfpRequired; + pWextState->roamProfile.MFPCapable = RSNMfpCapable; +#endif + hddLog(LOG1, + FL("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d"), + *RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + return 0; +} + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @pAdapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + ENTER(); + + pRoamProfile->AuthType.numEntries = 1; + hddLog(LOG1, FL("pHddStaCtx->conn_info.authType = %d"), + pHddStaCtx->conn_info.authType); + + switch (pHddStaCtx->conn_info.authType) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif + if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_DISABLED) { + + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA) { + +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) && + ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + hddLog(LOG1, + FL("set authType to CCKM WPA. AKM also 802.1X.")); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) { + hddLog(LOG1, + FL("Last chance to set authType to CCKM WPA.")); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif + if ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA; + } else + if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_PSK; + } else { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_NONE; + } + } + if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA2) { +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) && + ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + hddLog(LOG1, + FL("set authType to CCKM RSN. AKM also 802.1X.")); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) { + hddLog(LOG1, + FL("Last chance to set authType to CCKM RSN.")); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) && + ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN; + } else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN_PSK) + && + ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK)) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN_PSK; + } else +#endif + +#ifdef WLAN_FEATURE_11W + if (RSNAuthType == eCSR_AUTH_TYPE_RSN_PSK_SHA256) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (RSNAuthType == + eCSR_AUTH_TYPE_RSN_8021X_SHA256) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else +#endif + + if ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN; + } else + if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK; + } else { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_UNKNOWN; + } + } + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + + pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + break; + default: + +#ifdef FEATURE_WLAN_ESE + hddLog(LOG1, FL("In default, unknown auth type.")); +#endif /* FEATURE_WLAN_ESE */ + pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_UNKNOWN; + break; + } + + hddLog(LOG1, FL("Set roam Authtype to %d"), + pWextState->roamProfile.AuthType.authType[0]); + + EXIT(); + return 0; +} + +/** + * __iw_set_essid() - This function sets the ssid received from wpa_supplicant + * to the CSR roam profile. + * + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +static int __iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + unsigned long rc; + uint32_t status = 0; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + uint32_t roamId; + tCsrRoamProfile *pRoamProfile; + eMib_dot11DesiredBssType connectedBssType; + eCsrAuthType RSNAuthType; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION && + pAdapter->device_mode != WLAN_HDD_P2P_CLIENT) { + hddLog(LOGW, FL("device mode %s(%d) is not allowed"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (pWextState->mTKIPCounterMeasures == TKIP_COUNTER_MEASURE_STARTED) { + hddLog(LOG2, FL("Counter measure is in progress")); + return -EBUSY; + } + if (SIR_MAC_MAX_SSID_LENGTH < wrqu->essid.length) + return -EINVAL; + + pRoamProfile = &pWextState->roamProfile; + if (hdd_conn_get_connected_bss_type(pHddStaCtx, &connectedBssType) || + (eMib_dot11DesiredBssType_independent == + pHddStaCtx->conn_info.connDot11DesiredBssType)) { + CDF_STATUS cdf_status; + + /* Need to issue a disconnect to CSR. */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + cdf_status = sme_roam_disconnect(hHal, pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if (CDF_STATUS_SUCCESS == cdf_status) { + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hddLog(LOGE, FL("Disconnect event timed out")); + } + } + + /* + * when cfg80211 defined, wpa_supplicant wext driver uses + * zero-length, null-string ssid for force disconnection. + * after disconnection (if previously connected) and cleaning ssid, + * driver MUST return success. + */ + if (0 == wrqu->essid.length) + return 0; + + status = hdd_wmm_get_uapsd_mask(pAdapter, + &pWextState->roamProfile.uapsd_mask); + if (CDF_STATUS_SUCCESS != status) + pWextState->roamProfile.uapsd_mask = 0; + + pWextState->roamProfile.SSIDs.numOfSSIDs = 1; + + pWextState->roamProfile.SSIDs.SSIDList->SSID.length = + wrqu->essid.length; + + cdf_mem_zero(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId, + sizeof(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId)); + cdf_mem_copy((void *)(pWextState->roamProfile.SSIDs.SSIDList->SSID. + ssId), extra, wrqu->essid.length); + if (IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion + || IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion) { + + /* set gen ie */ + hdd_set_genie_to_csr(pAdapter, &RSNAuthType); + + /* set auth */ + hdd_set_csr_auth_type(pAdapter, RSNAuthType); + } +#ifdef FEATURE_WLAN_WAPI + hddLog(LOG1, FL("Setting WAPI AUTH Type and Encryption Mode values")); + if (pAdapter->wapi_info.nWapiMode) { + switch (pAdapter->wapi_info.wapiAuthMode) { + case WAPI_AUTH_MODE_PSK: + { + hddLog(LOG1, FL("WAPI AUTH TYPE: PSK: %d"), + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_PSK; + break; + } + case WAPI_AUTH_MODE_CERT: + { + hddLog(LOG1, FL("WAPI AUTH TYPE: CERT: %d"), + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + break; + } + } /* End of switch */ + if (pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_PSK || + pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_CERT) { + hddLog(LOG1, FL("WAPI PAIRWISE/GROUP ENCRYPTION: WPI")); + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + } + } +#endif /* FEATURE_WLAN_WAPI */ + /* if previous genIE is not NULL, update AssocIE */ + if (0 != pWextState->genIE.length) { + memset(&pWextState->assocAddIE, 0, + sizeof(pWextState->assocAddIE)); + memcpy(pWextState->assocAddIE.addIEdata, + pWextState->genIE.addIEdata, pWextState->genIE.length); + pWextState->assocAddIE.length = pWextState->genIE.length; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + + /* clear previous genIE after use it */ + memset(&pWextState->genIE, 0, sizeof(pWextState->genIE)); + } + + /* + * Assumes it is not WPS Association by default, except when + * pAddIEAssoc has WPS IE. + */ + pWextState->roamProfile.bWPSAssociation = false; + + if (NULL != wlan_hdd_get_wps_ie_ptr(pWextState->roamProfile.pAddIEAssoc, + pWextState->roamProfile. + nAddIEAssocLength)) + pWextState->roamProfile.bWPSAssociation = true; + + /* Disable auto BMPS entry by PMC until DHCP is done */ + sme_set_dhcp_till_power_active_flag(WLAN_HDD_GET_HAL_CTX(pAdapter), + true); + + pWextState->roamProfile.csrPersona = pAdapter->device_mode; + + if (eCSR_BSS_TYPE_START_IBSS == pRoamProfile->BSSType) { + hdd_select_cbmode(pAdapter, + (WLAN_HDD_GET_CTX(pAdapter))->config-> + AdHocChannel5G); + } + status = sme_roam_connect(hHal, pAdapter->sessionId, + &(pWextState->roamProfile), &roamId); + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + + EXIT(); + return status; +} + +/** + * iw_set_essid() - set essid handler function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +int iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_essid(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_essid() - This function returns the essid to the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @dwrq: pointer to iw_point + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *wextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated && + wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0) || + ((pHddStaCtx->conn_info.connState == eConnectionState_IbssConnected + || pHddStaCtx->conn_info.connState == + eConnectionState_IbssDisconnected) + && wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0)) { + dwrq->length = pHddStaCtx->conn_info.SSID.SSID.length; + memcpy(extra, pHddStaCtx->conn_info.SSID.SSID.ssId, + dwrq->length); + dwrq->flags = 1; + } else { + memset(extra, 0, dwrq->length); + dwrq->length = 0; + dwrq->flags = 0; + } + EXIT(); + return 0; +} + +/** + * iw_get_essid() - get essid handler function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +int iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_essid(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_auth() - + * This function sets the auth type received from the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + eCsrEncryptionType mcEncryptionType; + eCsrEncryptionType ucEncryptionType; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + pWextState->wpaVersion = wrqu->param.value; + break; + + case IW_AUTH_CIPHER_PAIRWISE: + { + if (wrqu->param.value & IW_AUTH_CIPHER_NONE) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_TKIP; + } else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + /*Dynamic WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40; + else + /*Static WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + /*Dynamic WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104; + else + /*Static WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } else { + hddLog(LOGW, FL("value %d UNKNOWN IW_AUTH_CIPHER"), + wrqu->param.value); + return -EINVAL; + } + + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + ucEncryptionType; + } + break; + case IW_AUTH_CIPHER_GROUP: + { + if (wrqu->param.value & IW_AUTH_CIPHER_NONE) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_TKIP; + } else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40; + else + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { + /* Dynamic WEP keys won't work with shared keys */ + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104; + } else { + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } else { + hddLog(LOGW, FL("value %d UNKNOWN IW_AUTH_CIPHER"), + wrqu->param.value); + return -EINVAL; + } + + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType.encryptionType[0] = + mcEncryptionType; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + { + /* Save the auth algo here and set auth type to SME Roam profile + in the iw_set_ap_address */ + if (wrqu->param.value & IW_AUTH_ALG_OPEN_SYSTEM) + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + else if (wrqu->param.value & IW_AUTH_ALG_SHARED_KEY) + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_SHARED_KEY; + + else if (wrqu->param.value & IW_AUTH_ALG_LEAP) + /*Not supported */ + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType; + } + break; + + case IW_AUTH_KEY_MGMT: + { +#ifdef FEATURE_WLAN_ESE +#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */ + /*Check for CCKM AKM type */ + if (wrqu->param.value & IW_AUTH_KEY_MGMT_CCKM) { + hddLog(LOG1, FL("CCKM AKM Set %d"), wrqu->param.value); + /* Set the CCKM bit in authKeyMgmt */ + /* + * Right now, this breaks all ref to authKeyMgmt because + * our code doesn't realize it is a "bitfield" + */ + pWextState->authKeyMgmt |= + IW_AUTH_KEY_MGMT_CCKM; + /* Set the key management to 802.1X */ + /* pWextState->authKeyMgmt = IW_AUTH_KEY_MGMT_802_1X; */ + pWextState->isESEConnection = true; + /* + * This is test code. I need to actually KNOW whether + * this is an RSN Assoc or WPA. + */ + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_CCKM_RSN; + } else if (wrqu->param.value & IW_AUTH_KEY_MGMT_PSK) { + /* Save the key management */ + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK; + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_RSN; + } else + if (!(wrqu->param.value & IW_AUTH_KEY_MGMT_802_1X)) { + pWextState->collectedAuthType = eCSR_AUTH_TYPE_NONE; + /* Save the key management anyway */ + pWextState->authKeyMgmt = wrqu->param.value; + } else { /* It must be IW_AUTH_KEY_MGMT_802_1X */ + /* Save the key management */ + pWextState->authKeyMgmt |= + IW_AUTH_KEY_MGMT_802_1X; + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_RSN; + } +#else + /* Save the key management */ + pWextState->authKeyMgmt = wrqu->param.value; +#endif /* FEATURE_WLAN_ESE */ + } + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + { + if (wrqu->param.value) { + hddLog(LOG2, + "Counter Measure started %d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STARTED; + } else { + hddLog(LOG2, + "Counter Measure stopped=%d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STOPED; + } + } + break; + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + + default: + + hddLog(LOGW, FL("called with unsupported auth type %d"), + wrqu->param.flags & IW_AUTH_INDEX); + break; + } + + EXIT(); + return 0; +} + +/** + * iw_set_auth() - set auth callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_auth(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_auth() - + * This function returns the auth type to the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (pRoamProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WPA_NONE: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_DISABLED; + break; + case eCSR_AUTH_TYPE_WPA: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_WPA; + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN: +#endif + case eCSR_AUTH_TYPE_RSN: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_WPA2; + break; + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + wrqu->param.value = IW_AUTH_ALG_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_UNKNOWN: + hddLog(LOG1, FL("called with unknown auth type")); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + hddLog(LOG1, FL("called with WPA PSK auth type")); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN_PSK: +#endif + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + hddLog(LOG1, FL("called with RSN PSK auth type")); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; + default: + hddLog(LOGE, FL("called with unknown auth type")); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; + } + if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_PAIRWISE)) { + switch (pRoamProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + wrqu->param.value = IW_AUTH_CIPHER_NONE; + break; + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP40; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + wrqu->param.value = IW_AUTH_CIPHER_TKIP; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP104; + break; + case eCSR_ENCRYPT_TYPE_AES: + wrqu->param.value = IW_AUTH_CIPHER_CCMP; + break; + default: + hddLog(LOG1, FL("called with unknown auth type %d"), + pRoamProfile->negotiatedUCEncryptionType); + return -EIO; + } + } + + if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_GROUP)) { + switch (pRoamProfile->negotiatedMCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + wrqu->param.value = IW_AUTH_CIPHER_NONE; + break; + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP40; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + wrqu->param.value = IW_AUTH_CIPHER_TKIP; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP104; + break; + case eCSR_ENCRYPT_TYPE_AES: + wrqu->param.value = IW_AUTH_CIPHER_CCMP; + break; + default: + hddLog(LOG1, FL("called with unknown auth type %d"), + pRoamProfile->negotiatedMCEncryptionType); + return -EIO; + } + } + + hddLog(LOG1, FL("called with auth type %d"), + pRoamProfile->AuthType.authType[0]); + EXIT(); + return 0; +} + +/** + * iw_get_auth() - get auth callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_auth(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_address() - set ap address + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * This function updates the HDD global station context connection info + * BSSID with the MAC address received from the wpa_supplicant. + * + * Return: 0 on success, error number otherwise + */ +static int __iw_set_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(WLAN_HDD_GET_PRIV_PTR(dev)); + uint8_t *pMacAddress = NULL; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pMacAddress = (uint8_t *) wrqu->ap_addr.sa_data; + hddLog(LOG1, FL(" " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMacAddress)); + cdf_mem_copy(pHddStaCtx->conn_info.bssId.bytes, pMacAddress, + sizeof(struct cdf_mac_addr)); + EXIT(); + + return 0; +} + +/** + * iw_set_ap_address() - set ap addresses callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_set_ap_address(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_address(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_address() - get ap address + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * This function returns currently associated BSSID. + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (pHddStaCtx->conn_info.connState == eConnectionState_Associated || + eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState) { + cdf_mem_copy(wrqu->ap_addr.sa_data, + pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + } else { + memset(wrqu->ap_addr.sa_data, 0, sizeof(wrqu->ap_addr.sa_data)); + } + EXIT(); + return 0; +} + +/** + * iw_get_ap_address() - get ap addresses callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_get_ap_address(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_address(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c new file mode 100644 index 0000000000..734bd4ba4e --- /dev/null +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -0,0 +1,6612 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg.c + * + * WLAN Host Device Driver configuration interface implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +static void +cb_notify_set_roam_prefer5_g_hz(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_prefer5_g_hz(pHddCtx->hHal, + pHddCtx->config->nRoamPrefer5GHz); +} + +static void +cb_notify_set_roam_rssi_diff(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_rssi_diff(pHddCtx->hHal, + 0, pHddCtx->config->RoamRssiDiff); +} + +static void +cb_notify_set_fast_transition_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_fast_transition_enabled(pHddCtx->hHal, + pHddCtx->config-> + isFastTransitionEnabled); +} + +static void +cb_notify_set_roam_intra_band(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_set_roam_intra_band(pHddCtx->hHal, pHddCtx->config->nRoamIntraBand); +} + +static void cb_notify_set_wes_mode(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_wes_mode(pHddCtx->hHal, pHddCtx->config->isWESModeEnabled, 0); +} + +static void +cb_notify_set_roam_scan_n_probes(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_scan_n_probes(pHddCtx->hHal, 0, pHddCtx->config->nProbes); +} + +static void +cb_notify_set_roam_scan_home_away_time(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_scan_home_away_time(pHddCtx->hHal, 0, + pHddCtx->config->nRoamScanHomeAwayTime, + true); +} +#endif + +#ifdef FEATURE_WLAN_OKC +static void +cb_notify_set_okc_feature_enabled(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ +} +#endif + +#ifdef FEATURE_WLAN_LFR +static void +notify_is_fast_roam_ini_feature_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_fast_roam_ini_feature_enabled(pHddCtx->hHal, 0, + pHddCtx->config-> + isFastRoamIniFeatureEnabled); +} + +static void +notify_is_mawc_ini_feature_enabled(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_mawc_ini_feature_enabled(pHddCtx->hHal, + pHddCtx->config->MAWCEnabled); +} +#endif + +#ifdef FEATURE_WLAN_ESE +static void +cb_notify_set_ese_feature_enabled(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_ese_feature_enabled(pHddCtx->hHal, 0, + pHddCtx->config->isEseIniFeatureEnabled); +} +#endif + +static void +cb_notify_set_fw_rssi_monitoring(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_config_fw_rssi_monitoring(pHddCtx->hHal, + pHddCtx->config-> + fEnableFwRssiMonitoring); +} + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +static void cb_notify_set_opportunistic_scan_threshold_diff(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_opportunistic_scan_threshold_diff(pHddCtx->hHal, 0, + pHddCtx->config-> + nOpportunisticThresholdDiff); +} + +static void cb_notify_set_roam_rescan_rssi_diff(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_rescan_rssi_diff(pHddCtx->hHal, + 0, pHddCtx->config->nRoamRescanRssiDiff); +} + +static void +cb_notify_set_neighbor_lookup_rssi_threshold(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_lookup_rssi_threshold(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborLookupRssiThreshold); +} + +static void +cb_notify_set_delay_before_vdev_stop(hdd_context_t *hdd_ctx, + unsigned long notify_id) +{ + /* + * At the point this routine is called, the value in the cfg_ini + * table has already been updated + */ + sme_set_delay_before_vdev_stop(hdd_ctx->hHal, 0, + hdd_ctx->config->delay_before_vdev_stop); +} + +static void +cb_notify_set_neighbor_scan_period(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_period(pHddCtx->hHal, 0, + pHddCtx->config->nNeighborScanPeriod); +} + +static void +cb_notify_set_neighbor_results_refresh_period(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_refresh_period(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborResultsRefreshPeriod); +} + +static void +cb_notify_set_empty_scan_refresh_period(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_empty_scan_refresh_period(pHddCtx->hHal, 0, + pHddCtx->config-> + nEmptyScanRefreshPeriod); +} + +static void +cb_notify_set_neighbor_scan_min_chan_time(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_min_chan_time(pHddCtx->hHal, + pHddCtx->config-> + nNeighborScanMinChanTime, 0); +} + +static void +cb_notify_set_neighbor_scan_max_chan_time(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_neighbor_scan_max_chan_time(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborScanMaxChanTime); +} + +static void cb_notify_set_roam_bmiss_first_bcnt(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_bmiss_first_bcnt(pHddCtx->hHal, + 0, pHddCtx->config->nRoamBmissFirstBcnt); +} + +static void cb_notify_set_roam_bmiss_final_bcnt(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_roam_bmiss_final_bcnt(pHddCtx->hHal, 0, + pHddCtx->config->nRoamBmissFinalBcnt); +} + +static void cb_notify_set_roam_beacon_rssi_weight(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_roam_beacon_rssi_weight(pHddCtx->hHal, 0, + pHddCtx->config->nRoamBeaconRssiWeight); +} + +static void +cb_notify_set_dfs_scan_mode(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_dfs_scan_mode(pHddCtx->hHal, 0, + pHddCtx->config->allowDFSChannelRoam); +} + +#endif + +static void cb_notify_set_enable_ssr(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_enable_ssr(pHddCtx->hHal, pHddCtx->config->enableSSR); +} + +static void cb_notify_set_g_sap_preferred_chan_location(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + wlansap_set_dfs_preferred_channel_location(pHddCtx->hHal, + pHddCtx->config-> + gSapPreferredChanLocation); +} +static void ch_notify_set_g_disable_dfs_japan_w53(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + wlansap_set_dfs_restrict_japan_w53(pHddCtx->hHal, + pHddCtx->config-> + gDisableDfsJapanW53); +} +static void +cb_notify_update_roam_scan_offload_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_roam_scan_offload_enabled(pHddCtx->hHal, + pHddCtx->config-> + isRoamOffloadScanEnabled); + if (0 == pHddCtx->config->isRoamOffloadScanEnabled) { + pHddCtx->config->bFastRoamInConIniFeatureEnabled = 0; + sme_update_enable_fast_roam_in_concurrency(pHddCtx->hHal, + pHddCtx->config-> + bFastRoamInConIniFeatureEnabled); + } +} + +static void +cb_notify_set_enable_fast_roam_in_concurrency(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_enable_fast_roam_in_concurrency(pHddCtx->hHal, + pHddCtx->config-> + bFastRoamInConIniFeatureEnabled); +} + +/** + * cb_notify_set_roam_scan_hi_rssi_scan_params() - configure hi rssi + * scan params from cfg to sme. + * @hdd_ctx: HDD context data structure + * @notify_id: Identifies 1 of the 4 parameters to be modified + * + * Picks up the value from hdd configuration and passes it to SME. + * Return: void + */ + +static void +cb_notify_set_roam_scan_hi_rssi_scan_params(hdd_context_t *hdd_ctx, + unsigned long notify_id) +{ + int32_t val; + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is invalid")); + return; + } + + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + val = hdd_ctx->config->nhi_rssi_scan_max_count; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_delta; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + val = hdd_ctx->config->nhi_rssi_scan_delay; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_ub; + break; + + default: + return; + } + + sme_update_roam_scan_hi_rssi_scan_params(hdd_ctx->hHal, 0, + notify_id, val); +} + + +REG_TABLE_ENTRY g_registry_table[] = { + REG_VARIABLE(CFG_RTS_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, RTSThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RTS_THRESHOLD_DEFAULT, + CFG_RTS_THRESHOLD_MIN, + CFG_RTS_THRESHOLD_MAX), + + REG_VARIABLE(CFG_FRAG_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, FragmentationThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FRAG_THRESHOLD_DEFAULT, + CFG_FRAG_THRESHOLD_MIN, + CFG_FRAG_THRESHOLD_MAX), + + REG_VARIABLE(CFG_OPERATING_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, OperatingChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPERATING_CHANNEL_DEFAULT, + CFG_OPERATING_CHANNEL_MIN, + CFG_OPERATING_CHANNEL_MAX), + + REG_VARIABLE(CFG_SHORT_SLOT_TIME_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortSlotTimeEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT, + CFG_SHORT_SLOT_TIME_ENABLED_MIN, + CFG_SHORT_SLOT_TIME_ENABLED_MAX), + + REG_VARIABLE(CFG_11D_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11dSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11D_SUPPORT_ENABLED_DEFAULT, + CFG_11D_SUPPORT_ENABLED_MIN, + CFG_11D_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_11H_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11hSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11H_SUPPORT_ENABLED_DEFAULT, + CFG_11H_SUPPORT_ENABLED_MIN, + CFG_11H_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_COUNTRY_CODE_PRIORITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fSupplicantCountryCodeHasPriority, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_COUNTRY_CODE_PRIORITY_DEFAULT, + CFG_COUNTRY_CODE_PRIORITY_MIN, + CFG_COUNTRY_CODE_PRIORITY_MAX), + + REG_VARIABLE(CFG_HEARTBEAT_THRESH_24_NAME, WLAN_PARAM_Integer, + struct hdd_config, HeartbeatThresh24, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HEARTBEAT_THRESH_24_DEFAULT, + CFG_HEARTBEAT_THRESH_24_MIN, + CFG_HEARTBEAT_THRESH_24_MAX), + + REG_VARIABLE_STRING(CFG_POWER_USAGE_NAME, WLAN_PARAM_String, + struct hdd_config, PowerUsageControl, + VAR_FLAGS_OPTIONAL, + (void *)CFG_POWER_USAGE_DEFAULT), + + REG_VARIABLE(CFG_ENABLE_LOGP_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsLogpEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LOGP_DEFAULT, + CFG_ENABLE_LOGP_MIN, + CFG_ENABLE_LOGP_MAX), + + REG_VARIABLE(CFG_ENABLE_IMPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsImpsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_IMPS_DEFAULT, + CFG_ENABLE_IMPS_MIN, + CFG_ENABLE_IMPS_MAX), + + REG_VARIABLE(CFG_ENABLE_PS_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_ps_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PS_DEFAULT, + CFG_ENABLE_PS_MIN, + CFG_ENABLE_PS_MAX), + + REG_VARIABLE(CFG_BMPS_MINIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMinListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MINIMUM_LI_DEFAULT, + CFG_BMPS_MINIMUM_LI_MIN, + CFG_BMPS_MINIMUM_LI_MAX), + + REG_VARIABLE(CFG_BMPS_MAXIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MAXIMUM_LI_DEFAULT, + CFG_BMPS_MAXIMUM_LI_MIN, + CFG_BMPS_MAXIMUM_LI_MAX), + + REG_VARIABLE(CFG_BMPS_MODERATE_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsModListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MODERATE_LI_DEFAULT, + CFG_BMPS_MODERATE_LI_MIN, + CFG_BMPS_MODERATE_LI_MAX), + + REG_VARIABLE(CFG_DOT11_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11Mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_DOT11_MODE_DEFAULT, + CFG_DOT11_MODE_MIN, + CFG_DOT11_MODE_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode24GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode5GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_MAX_RX_AMPDU_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, MaxRxAmpduFactor, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_MAX_RX_AMPDU_FACTOR_DEFAULT, + CFG_MAX_RX_AMPDU_FACTOR_MIN, + CFG_MAX_RX_AMPDU_FACTOR_MAX), + + REG_VARIABLE(CFG_FIXED_RATE_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxRate, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_FIXED_RATE_DEFAULT, + CFG_FIXED_RATE_MIN, + CFG_FIXED_RATE_MAX), + + REG_VARIABLE(CFG_SHORT_GI_20MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI20MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_20MHZ_DEFAULT, + CFG_SHORT_GI_20MHZ_MIN, + CFG_SHORT_GI_20MHZ_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, ScanResultAgeCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_COUNT_DEFAULT, + CFG_SCAN_RESULT_AGE_COUNT_MIN, + CFG_SCAN_RESULT_AGE_COUNT_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_TIME_NCNPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nScanAgeTimeNCNPS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_TIME_NCNPS_DEFAULT, + CFG_SCAN_RESULT_AGE_TIME_NCNPS_MIN, + CFG_SCAN_RESULT_AGE_TIME_NCNPS_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_TIME_NCPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nScanAgeTimeNCPS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_TIME_NCPS_DEFAULT, + CFG_SCAN_RESULT_AGE_TIME_NCPS_MIN, + CFG_SCAN_RESULT_AGE_TIME_NCPS_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_TIME_CNPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nScanAgeTimeCNPS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_TIME_CNPS_DEFAULT, + CFG_SCAN_RESULT_AGE_TIME_CNPS_MIN, + CFG_SCAN_RESULT_AGE_TIME_CNPS_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_TIME_CPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nScanAgeTimeCPS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_TIME_CPS_DEFAULT, + CFG_SCAN_RESULT_AGE_TIME_CPS_MIN, + CFG_SCAN_RESULT_AGE_TIME_CPS_MAX), + + REG_VARIABLE(CFG_RSSI_CATEGORY_GAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRssiCatGap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_CATEGORY_GAP_DEFAULT, + CFG_RSSI_CATEGORY_GAP_MIN, + CFG_RSSI_CATEGORY_GAP_MAX), + + REG_VARIABLE(CFG_SHORT_PREAMBLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsShortPreamble, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_PREAMBLE_DEFAULT, + CFG_SHORT_PREAMBLE_MIN, + CFG_SHORT_PREAMBLE_MAX), + + REG_VARIABLE_STRING(CFG_IBSS_BSSID_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, IbssBssid, + VAR_FLAGS_OPTIONAL, + (void *)CFG_IBSS_BSSID_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF0_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[0], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF0_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF1_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[1], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF1_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF2_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[2], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF2_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF3_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[3], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF3_MAC_ADDR_DEFAULT), + + REG_VARIABLE(CFG_AP_QOS_UAPSD_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apUapsdEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_MIN, + CFG_AP_QOS_UAPSD_MODE_MAX), + + + REG_VARIABLE(CFG_AP_ENABLE_RANDOM_BSSID_NAME, WLAN_PARAM_Integer, + struct hdd_config, apRandomBssidEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_MIN, + CFG_AP_ENABLE_RANDOM_BSSID_MAX), + + REG_VARIABLE(CFG_AP_ENABLE_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_MIN, + CFG_AP_ENABLE_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_PROTECTION_MODE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, apProtection, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_PROTECTION_MODE_DEFAULT, + CFG_AP_PROTECTION_MODE_MIN, + CFG_AP_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_OBSS_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apOBSSProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_MIN, + CFG_AP_OBSS_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_STA_SECURITY_SEPERATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDisableIntraBssFwd, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_MIN, + CFG_AP_STA_SECURITY_SEPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_LTE_COEX, WLAN_PARAM_Integer, + struct hdd_config, enableLTECoex, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LTE_COEX_DEFAULT, + CFG_ENABLE_LTE_COEX_MIN, + CFG_ENABLE_LTE_COEX_MAX), + REG_VARIABLE(CFG_FORCE_SAP_ACS, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_DEFAULT, + CFG_FORCE_SAP_ACS_MIN, + CFG_FORCE_SAP_ACS_MAX), + + REG_VARIABLE(CFG_FORCE_SAP_ACS_START_CH, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs_st_ch, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_START_CH_DEFAULT, + CFG_FORCE_SAP_ACS_START_CH_MIN, + CFG_FORCE_SAP_ACS_START_CH_MAX), + + REG_VARIABLE(CFG_FORCE_SAP_ACS_END_CH, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs_end_ch, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_END_CH_DEFAULT, + CFG_FORCE_SAP_ACS_END_CH_MIN, + CFG_FORCE_SAP_ACS_END_CH_MAX), + + REG_VARIABLE(CFG_AP_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_MIN, + CFG_AP_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_MIN, + CFG_GO_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_AP_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_MIN, + CFG_AP_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_MIN, + CFG_GO_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_DISABLE_PACKET_FILTER, WLAN_PARAM_Integer, + struct hdd_config, disablePacketFilter, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_PACKET_FILTER_DEFAULT, + CFG_DISABLE_PACKET_FILTER_MIN, + CFG_DISABLE_PACKET_FILTER_MAX), + + REG_VARIABLE(CFG_BEACON_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBeaconInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_BEACON_INTERVAL_DEFAULT, + CFG_BEACON_INTERVAL_MIN, + CFG_BEACON_INTERVAL_MAX), + + REG_VARIABLE(CFG_ROAMING_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamingTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAMING_TIME_DEFAULT, + CFG_ROAMING_TIME_MIN, + CFG_ROAMING_TIME_MAX), + + REG_VARIABLE(CFG_VCC_RSSI_TRIGGER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccRssiTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_RSSI_TRIGGER_DEFAULT, + CFG_VCC_RSSI_TRIGGER_MIN, + CFG_VCC_RSSI_TRIGGER_MAX), + + REG_VARIABLE(CFG_VCC_UL_MAC_LOSS_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccUlMacLossThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_MIN, + CFG_VCC_UL_MAC_LOSS_THRESH_MAX), + + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_ZERO_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitZero, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_ZERO_DEFAULT, + CFG_RETRY_LIMIT_ZERO_MIN, + CFG_RETRY_LIMIT_ZERO_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_ONE_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitOne, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_ONE_DEFAULT, + CFG_RETRY_LIMIT_ONE_MIN, + CFG_RETRY_LIMIT_ONE_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_TWO_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitTwo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_TWO_DEFAULT, + CFG_RETRY_LIMIT_TWO_MIN, + CFG_RETRY_LIMIT_TWO_MAX), + +#ifdef WLAN_AP_STA_CONCURRENCY + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_REST_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRestTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REST_TIME_CONC_DEFAULT, + CFG_REST_TIME_CONC_MIN, + CFG_REST_TIME_CONC_MAX), + + REG_VARIABLE(CFG_NUM_STA_CHAN_COMBINED_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNumStaChanCombinedConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_STA_CHAN_COMBINED_CONC_DEFAULT, + CFG_NUM_STA_CHAN_COMBINED_CONC_MIN, + CFG_NUM_STA_CHAN_COMBINED_CONC_MAX), + + REG_VARIABLE(CFG_NUM_P2P_CHAN_COMBINED_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNumP2PChanCombinedConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_P2P_CHAN_COMBINED_CONC_DEFAULT, + CFG_NUM_P2P_CHAN_COMBINED_CONC_MIN, + CFG_NUM_P2P_CHAN_COMBINED_CONC_MAX), +#endif + + REG_VARIABLE(CFG_MAX_PS_POLL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxPsPoll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_PS_POLL_DEFAULT, + CFG_MAX_PS_POLL_MIN, + CFG_MAX_PS_POLL_MAX), + + REG_VARIABLE(CFG_MAX_TX_POWER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTxPowerCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_TX_POWER_DEFAULT, + CFG_MAX_TX_POWER_MIN, + CFG_MAX_TX_POWER_MAX), + + REG_VARIABLE(CFG_LOW_GAIN_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsLowGainOverride, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LOW_GAIN_OVERRIDE_DEFAULT, + CFG_LOW_GAIN_OVERRIDE_MIN, + CFG_LOW_GAIN_OVERRIDE_MAX), + + REG_VARIABLE(CFG_RSSI_FILTER_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRssiFilterPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_FILTER_PERIOD_DEFAULT, + CFG_RSSI_FILTER_PERIOD_MIN, + CFG_RSSI_FILTER_PERIOD_MAX), + + REG_VARIABLE(CFG_IGNORE_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIgnoreDtim, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_DTIM_DEFAULT, + CFG_IGNORE_DTIM_MIN, + CFG_IGNORE_DTIM_MAX), + + REG_VARIABLE(CFG_MAX_LI_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, fMaxLIModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_MIN, + CFG_MAX_LI_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_RX_ANT_CONFIGURATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRxAnt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_ANT_CONFIGURATION_NAME_DEFAULT, + CFG_RX_ANT_CONFIGURATION_NAME_MIN, + CFG_RX_ANT_CONFIGURATION_NAME_MAX), + + REG_VARIABLE(CFG_FW_HEART_BEAT_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwHeartBeatMonitoring, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_HEART_BEAT_MONITORING_DEFAULT, + CFG_FW_HEART_BEAT_MONITORING_MIN, + CFG_FW_HEART_BEAT_MONITORING_MAX), + + REG_VARIABLE(CFG_FW_BEACON_FILTERING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwBeaconFiltering, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_BEACON_FILTERING_DEFAULT, + CFG_FW_BEACON_FILTERING_MIN, + CFG_FW_BEACON_FILTERING_MAX), + + REG_DYNAMIC_VARIABLE(CFG_FW_RSSI_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwRssiMonitoring, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_RSSI_MONITORING_DEFAULT, + CFG_FW_RSSI_MONITORING_MIN, + CFG_FW_RSSI_MONITORING_MAX, + cb_notify_set_fw_rssi_monitoring, 0), + + REG_VARIABLE(CFG_FW_MCC_RTS_CTS_PROT_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_rts_cts_prot_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_MIN, + CFG_FW_MCC_RTS_CTS_PROT_MAX), + + REG_VARIABLE(CFG_FW_MCC_BCAST_PROB_RESP_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_bcast_prob_resp_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_MIN, + CFG_FW_MCC_BCAST_PROB_RESP_MAX), + + REG_VARIABLE(CFG_DATA_INACTIVITY_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nDataInactivityTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_MIN, + CFG_DATA_INACTIVITY_TIMEOUT_MAX), + + REG_VARIABLE(CFG_QOS_WMM_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, WmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_MODE_DEFAULT, + CFG_QOS_WMM_MODE_MIN, + CFG_QOS_WMM_MODE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_80211E_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, b80211eIsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_MIN, + CFG_QOS_WMM_80211E_ENABLED_MAX), + + REG_VARIABLE(CFG_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, UapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_MIN, + CFG_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX), + +#ifdef FEATURE_WLAN_ESE + REG_VARIABLE(CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraInactivityInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ESE_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isEseIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESE_FEATURE_ENABLED_DEFAULT, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX, + cb_notify_set_ese_feature_enabled, 0), +#endif /* FEATURE_WLAN_ESE */ + +#ifdef FEATURE_WLAN_LFR + /* flag to turn ON/OFF Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isFastRoamIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_FEATURE_ENABLED_DEFAULT, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX, + notify_is_fast_roam_ini_feature_enabled, 0), + + /* flag to turn ON/OFF Motion assistance for Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_MAWC_FEATURE_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, MAWCEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_MIN, + CFG_LFR_MAWC_FEATURE_ENABLED_MAX, + notify_is_mawc_ini_feature_enabled, 0), + +#endif /* FEATURE_WLAN_LFR */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + /* flag to turn ON/OFF 11r and ESE FastTransition */ + REG_DYNAMIC_VARIABLE(CFG_FAST_TRANSITION_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isFastTransitionEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX, + cb_notify_set_fast_transition_enabled, 0), + + /* Variable to specify the delta/difference between the RSSI of current AP + * and roamable AP while roaming */ + REG_DYNAMIC_VARIABLE(CFG_ROAM_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, RoamRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RSSI_DIFF_DEFAULT, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX, + cb_notify_set_roam_rssi_diff, 0), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_WES_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, isWESModeEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX, + cb_notify_set_wes_mode, 0), +#endif +#ifdef FEATURE_WLAN_OKC + REG_DYNAMIC_VARIABLE(CFG_OKC_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isOkcIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OKC_FEATURE_ENABLED_DEFAULT, + CFG_OKC_FEATURE_ENABLED_MIN, + CFG_OKC_FEATURE_ENABLED_MAX, + cb_notify_set_okc_feature_enabled, 0), +#endif + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_OFFLOAD_ENABLED, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadScanEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX, + cb_notify_update_roam_scan_offload_enabled, 0), + REG_VARIABLE(CFG_QOS_WMM_PKT_CLASSIFY_BASIS_NAME, WLAN_PARAM_Integer, + struct hdd_config, PktClassificationBasis, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_PKT_CLASSIFY_BASIS_DEFAULT, + CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MIN, + CFG_QOS_WMM_PKT_CLASSIFY_BASIS_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX), + + REG_VARIABLE(CFG_TL_DELAYED_TRGR_FRM_INT_NAME, WLAN_PARAM_Integer, + struct hdd_config, DelayedTriggerFrmInt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_MIN, + CFG_TL_DELAYED_TRGR_FRM_INT_MAX), + + REG_VARIABLE_STRING(CFG_WOWL_PATTERN_NAME, WLAN_PARAM_String, + struct hdd_config, wowlPattern, + VAR_FLAGS_OPTIONAL, + (void *)CFG_WOWL_PATTERN_DEFAULT), + + REG_VARIABLE(CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, bImplicitQosEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX), + + REG_VARIABLE(CFG_AP_LISTEN_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, nEnableListenMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_LISTEN_MODE_DEFAULT, + CFG_AP_LISTEN_MODE_MIN, + CFG_AP_LISTEN_MODE_MAX), + + REG_VARIABLE(CFG_AP_AUTO_SHUT_OFF, WLAN_PARAM_Integer, + struct hdd_config, nAPAutoShutOff, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_AUTO_SHUT_OFF_DEFAULT, + CFG_AP_AUTO_SHUT_OFF_MIN, + CFG_AP_AUTO_SHUT_OFF_MAX), + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + REG_VARIABLE(CFG_WLAN_MCC_TO_SCC_SWITCH_MODE, WLAN_PARAM_Integer, + struct hdd_config, WlanMccToSccSwitchMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX), +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + REG_VARIABLE(CFG_WLAN_AUTO_SHUTDOWN, WLAN_PARAM_Integer, + struct hdd_config, WlanAutoShutdown, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_MIN, + CFG_WLAN_AUTO_SHUTDOWN_MAX), +#endif +#if defined WLAN_FEATURE_VOWIFI + REG_VARIABLE(CFG_RRM_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRrmEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_ENABLE_DEFAULT, + CFG_RRM_ENABLE_MIN, + CFG_RRM_ENABLE_MAX), + + REG_VARIABLE(CFG_RRM_OPERATING_CHAN_MAX_DURATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nInChanMeasMaxDuration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_OPERATING_CHAN_MAX_DURATION_DEFAULT, + CFG_RRM_OPERATING_CHAN_MAX_DURATION_MIN, + CFG_RRM_OPERATING_CHAN_MAX_DURATION_MAX), + + REG_VARIABLE(CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nOutChanMeasMaxDuration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_DEFAULT, + CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_MIN, + CFG_RRM_NON_OPERATING_CHAN_MAX_DURATION_MAX), + + REG_VARIABLE(CFG_RRM_MEAS_RANDOMIZATION_INTVL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRrmRandnIntvl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX), +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + REG_VARIABLE(CFG_FT_RESOURCE_REQ_NAME, WLAN_PARAM_Integer, + struct hdd_config, fFTResourceReqSupported, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FT_RESOURCE_REQ_DEFAULT, + CFG_FT_RESOURCE_REQ_MIN, + CFG_FT_RESOURCE_REQ_MAX), +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX, + cb_notify_set_neighbor_scan_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborLookupRssiThreshold, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX, + cb_notify_set_neighbor_lookup_rssi_threshold, 0), + + REG_DYNAMIC_VARIABLE(CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nOpportunisticThresholdDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX, + cb_notify_set_opportunistic_scan_threshold_diff, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_RESCAN_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamRescanRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_MIN, + CFG_ROAM_RESCAN_RSSI_DIFF_MAX, + cb_notify_set_roam_rescan_rssi_diff, 0), + + REG_VARIABLE_STRING(CFG_NEIGHBOR_SCAN_CHAN_LIST_NAME, WLAN_PARAM_String, + struct hdd_config, neighborScanChanList, + VAR_FLAGS_OPTIONAL, + (void *)CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMinChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_min_chan_time, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMaxChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_max_chan_time, 0), + + REG_VARIABLE(CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxNeighborReqTries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborResultsRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX, + cb_notify_set_neighbor_results_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_EMPTY_SCAN_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nEmptyScanRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX, + cb_notify_set_empty_scan_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FIRST_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFirstBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_MIN, + CFG_ROAM_BMISS_FIRST_BCNT_MAX, + cb_notify_set_roam_bmiss_first_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FINAL_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFinalBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_MIN, + CFG_ROAM_BMISS_FINAL_BCNT_MAX, + cb_notify_set_roam_bmiss_final_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BEACON_RSSI_WEIGHT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nRoamBeaconRssiWeight, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_MIN, + CFG_ROAM_BEACON_RSSI_WEIGHT_MAX, + cb_notify_set_roam_beacon_rssi_weight, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAMING_DFS_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowDFSChannelRoam, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX, + cb_notify_set_dfs_scan_mode, 0), + + REG_DYNAMIC_VARIABLE(CFG_DELAY_BEFORE_VDEV_STOP_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + delay_before_vdev_stop, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_MIN, + CFG_DELAY_BEFORE_VDEV_STOP_MAX, + cb_notify_set_delay_before_vdev_stop, + 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_max_count, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELTA_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_rssi_delta, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_delay, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_DELAY_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_UB_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, + nhi_rssi_scan_rssi_ub, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_MIN, + CFG_ROAM_SCAN_HI_RSSI_UB_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID), + +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ + + REG_VARIABLE(CFG_QOS_WMM_BURST_SIZE_DEFN_NAME, WLAN_PARAM_Integer, + struct hdd_config, burstSizeDefinition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_MIN, + CFG_QOS_WMM_BURST_SIZE_DEFN_MAX), + + REG_VARIABLE(CFG_MCAST_BCAST_FILTER_SETTING_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcastBcastFilterSetting, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MCAST_BCAST_FILTER_SETTING_DEFAULT, + CFG_MCAST_BCAST_FILTER_SETTING_MIN, + CFG_MCAST_BCAST_FILTER_SETTING_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_ARPOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostArpOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_MIN, + CFG_ENABLE_HOST_ARPOFFLOAD_MAX), + +#ifdef FEATURE_WLAN_RA_FILTERING + REG_VARIABLE(CFG_RA_FILTER_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsRArateLimitEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_FILTER_ENABLE_DEFAULT, + CFG_RA_FILTER_ENABLE_MIN, + CFG_RA_FILTER_ENABLE_MAX), + + REG_VARIABLE(CFG_RA_RATE_LIMIT_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, RArateLimitInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_MIN, + CFG_RA_RATE_LIMIT_INTERVAL_MAX), +#endif + + REG_VARIABLE(CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignore_peer_erp_info, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_MIN, + CFG_IGNORE_PEER_ERP_INFO_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_SSDP_NAME, WLAN_PARAM_Integer, + struct hdd_config, ssdp, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_SSDP_DEFAULT, + CFG_ENABLE_HOST_SSDP_MIN, + CFG_ENABLE_HOST_SSDP_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_NSOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostNSOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_MIN, + CFG_ENABLE_HOST_NSOFFLOAD_MAX), + + REG_VARIABLE(CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, tsInfoAckPolicy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX), + + REG_VARIABLE(CFG_SINGLE_TID_RC_NAME, WLAN_PARAM_Integer, + struct hdd_config, bSingleTidRc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SINGLE_TID_RC_DEFAULT, + CFG_SINGLE_TID_RC_MIN, + CFG_SINGLE_TID_RC_MAX), + + REG_VARIABLE(CFG_DYNAMIC_PSPOLL_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dynamicPsPollValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DYNAMIC_PSPOLL_VALUE_DEFAULT, + CFG_DYNAMIC_PSPOLL_VALUE_MIN, + CFG_DYNAMIC_PSPOLL_VALUE_MAX), + + REG_VARIABLE(CFG_TELE_BCN_WAKEUP_EN_NAME, WLAN_PARAM_Integer, + struct hdd_config, teleBcnWakeupEn, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_MIN, + CFG_TELE_BCN_WAKEUP_EN_MAX), + + REG_VARIABLE(CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, infraStaKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, AddTSWhenACMIsOff, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX), + + REG_VARIABLE(CFG_VALIDATE_SCAN_LIST_NAME, WLAN_PARAM_Integer, + struct hdd_config, fValidateScanList, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VALIDATE_SCAN_LIST_DEFAULT, + CFG_VALIDATE_SCAN_LIST_MIN, + CFG_VALIDATE_SCAN_LIST_MAX), + + REG_VARIABLE(CFG_NULLDATA_AP_RESP_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNullDataApRespTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NULLDATA_AP_RESP_TIMEOUT_DEFAULT, + CFG_NULLDATA_AP_RESP_TIMEOUT_MIN, + CFG_NULLDATA_AP_RESP_TIMEOUT_MAX), + + REG_VARIABLE(CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDataAvailPollPeriodInMs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX), + + REG_VARIABLE(CFG_BAND_CAPABILITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBandCapability, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAND_CAPABILITY_DEFAULT, + CFG_BAND_CAPABILITY_MIN, + CFG_BAND_CAPABILITY_MAX), + + REG_VARIABLE(CFG_ENABLE_BEACON_EARLY_TERMINATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, fEnableBeaconEarlyTermination, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BEACON_EARLY_TERMINATION_DEFAULT, + CFG_ENABLE_BEACON_EARLY_TERMINATION_MIN, + CFG_ENABLE_BEACON_EARLY_TERMINATION_MAX), + +/* CFG_CDF_TRACE_ENABLE Parameters */ + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_WDI_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_wdi, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_HDD_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_hdd, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_BMI_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_bmi, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_SME_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_sme, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_PE_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_pe, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_WMA_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_wma, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_SYS_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_sys, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_CDF_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_cdf, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_sap, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDF_TRACE_ENABLE_HDD_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, cdf_trace_enable_hdd_sap, + VAR_FLAGS_OPTIONAL, + CFG_CDF_TRACE_ENABLE_DEFAULT, + CFG_CDF_TRACE_ENABLE_MIN, + CFG_CDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_TELE_BCN_TRANS_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnTransListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_TRANS_LI_DEFAULT, + CFG_TELE_BCN_TRANS_LI_MIN, + CFG_TELE_BCN_TRANS_LI_MAX), + + REG_VARIABLE(CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnTransLiNumIdleBeacons, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_DEFAULT, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MIN, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MAX), + + REG_VARIABLE(CFG_TELE_BCN_MAX_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_MAX_LI_DEFAULT, + CFG_TELE_BCN_MAX_LI_MIN, + CFG_TELE_BCN_MAX_LI_MAX), + + REG_VARIABLE(CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnMaxLiNumIdleBeacons, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_DEFAULT, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MIN, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MAX), + + REG_VARIABLE(CFG_BCN_EARLY_TERM_WAKE_NAME, WLAN_PARAM_Integer, + struct hdd_config, bcnEarlyTermWakeInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BCN_EARLY_TERM_WAKE_DEFAULT, + CFG_BCN_EARLY_TERM_WAKE_MIN, + CFG_BCN_EARLY_TERM_WAKE_MAX), + + REG_VARIABLE(CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDataAvailPollPeriodInMs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX), + + REG_VARIABLE(CFG_ENABLE_CLOSE_LOOP_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableCloseLoop, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CLOSE_LOOP_DEFAULT, + CFG_ENABLE_CLOSE_LOOP_MIN, + CFG_ENABLE_CLOSE_LOOP_MAX), + + REG_VARIABLE(CFG_ENABLE_BYPASS_11D_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableBypass11d, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BYPASS_11D_DEFAULT, + CFG_ENABLE_BYPASS_11D_MIN, + CFG_ENABLE_BYPASS_11D_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDFSChnlScan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_dfs_pno_chnl_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DYNAMIC_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDynamicDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_MIN, + CFG_ENABLE_DYNAMIC_DTIM_MAX), + + REG_VARIABLE(CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enableAutomaticTxPowerControl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_DEFAULT, + CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_MIN, + CFG_ENABLE_AUTOMATIC_TX_POWER_CONTROL_MAX), + + REG_VARIABLE(CFG_SHORT_GI_40MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI40MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_40MHZ_DEFAULT, + CFG_SHORT_GI_40MHZ_MIN, + CFG_SHORT_GI_40MHZ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_REPORT_MAX_LINK_SPEED, WLAN_PARAM_Integer, + struct hdd_config, reportMaxLinkSpeed, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_MIN, + CFG_REPORT_MAX_LINK_SPEED_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_HIGH, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiHigh, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_MIN, + CFG_LINK_SPEED_RSSI_HIGH_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_MID, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiMid, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_MIN, + CFG_LINK_SPEED_RSSI_MID_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_LOW, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiLow, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_MIN, + CFG_LINK_SPEED_RSSI_LOW_MAX, + NULL, 0), + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + REG_DYNAMIC_VARIABLE(CFG_ROAM_PREFER_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, nRoamPrefer5GHz, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_PREFER_5GHZ_DEFAULT, + CFG_ROAM_PREFER_5GHZ_MIN, + CFG_ROAM_PREFER_5GHZ_MAX, + cb_notify_set_roam_prefer5_g_hz, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_INTRA_BAND, WLAN_PARAM_Integer, + struct hdd_config, nRoamIntraBand, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_INTRA_BAND_DEFAULT, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX, + cb_notify_set_roam_intra_band, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_N_PROBES, WLAN_PARAM_Integer, + struct hdd_config, nProbes, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX, + cb_notify_set_roam_scan_n_probes, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HOME_AWAY_TIME, WLAN_PARAM_Integer, + struct hdd_config, nRoamScanHomeAwayTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX, + cb_notify_set_roam_scan_home_away_time, 0), + +#endif + + REG_VARIABLE(CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isP2pDeviceAddrAdministrated, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableMCC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ENABLED_MIN, + CFG_ENABLE_MCC_ENABLED_MAX), + + REG_VARIABLE(CFG_ALLOW_MCC_GO_DIFF_BI_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowMCCGODiffBI, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_MIN, + CFG_ALLOW_MCC_GO_DIFF_BI_MAX), + + REG_VARIABLE(CFG_THERMAL_MIGRATION_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalMitigationEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_MIN, + CFG_THERMAL_MIGRATION_ENABLE_MAX), + + REG_VARIABLE(CFG_THROTTLE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttlePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_PERIOD_DEFAULT, + CFG_THROTTLE_PERIOD_MIN, + CFG_THROTTLE_PERIOD_MAX), + + REG_VARIABLE(CFG_ENABLE_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_MIN, + CFG_ENABLE_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_MC_ADDR_LIST_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableMCAddrList, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_MIN, + CFG_MC_ADDR_LIST_ENABLE_MAX), + +#ifdef WLAN_FEATURE_11AC + REG_VARIABLE(CFG_VHT_CHANNEL_WIDTH, WLAN_PARAM_Integer, + struct hdd_config, vhtChannelWidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_CHANNEL_WIDTH_DEFAULT, + CFG_VHT_CHANNEL_WIDTH_MIN, + CFG_VHT_CHANNEL_WIDTH_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_2x2_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enable2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableMuBformee, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_PAID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtpAid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_MIN, + CFG_VHT_ENABLE_PAID_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_GID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtGid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_MIN, + CFG_VHT_ENABLE_GID_FEATURE_MAX), +#endif + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_TX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, txchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_RX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, rxchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_ENABLE_AMPDUPS_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableAmpduPs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_MIN, + CFG_ENABLE_AMPDUPS_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_ENABLE_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableHtSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, htSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_MIN, + CFG_HT_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_DISABLE_DFS_CH_SWITCH, WLAN_PARAM_Integer, + struct hdd_config, disableDFSChSwitch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_MIN, + CFG_DISABLE_DFS_CH_SWITCH_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_MASTER_CAPABILITY, WLAN_PARAM_Integer, + struct hdd_config, enableDFSMasterCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX), + + REG_DYNAMIC_VARIABLE(CFG_SAP_PREFERRED_CHANNEL_LOCATION, + WLAN_PARAM_Integer, + struct hdd_config, gSapPreferredChanLocation, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX, + cb_notify_set_g_sap_preferred_chan_location, 0), + REG_DYNAMIC_VARIABLE(CFG_DISABLE_DFS_JAPAN_W53, WLAN_PARAM_Integer, + struct hdd_config, gDisableDfsJapanW53, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_MIN, + CFG_DISABLE_DFS_JAPAN_W53_MAX, + ch_notify_set_g_disable_dfs_japan_w53, 0), + REG_VARIABLE(CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableFirstScan2GOnly, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX), + + REG_VARIABLE(CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME, WLAN_PARAM_Integer, + struct hdd_config, skipDfsChnlInP2pSearch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX), + + REG_VARIABLE(CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ignoreDynamicDtimInP2pMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableRxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_STBC_DEFAULT, + CFG_ENABLE_RX_STBC_MIN, + CFG_ENABLE_RX_STBC_MAX), + + REG_VARIABLE(CFG_ENABLE_TX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableTxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TX_STBC_DEFAULT, + CFG_ENABLE_TX_STBC_MIN, + CFG_ENABLE_TX_STBC_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_LDPC, WLAN_PARAM_Integer, + struct hdd_config, enableRxLDPC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_LDPC_DEFAULT, + CFG_ENABLE_RX_LDPC_MIN, + CFG_ENABLE_RX_LDPC_MAX), + + REG_VARIABLE(CFG_PPS_ENABLE_5G_EBT, WLAN_PARAM_Integer, + struct hdd_config, enable5gEBT, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX), + +#ifdef FEATURE_WLAN_TDLS + REG_VARIABLE(CFG_TDLS_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_MIN, + CFG_TDLS_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_IMPLICIT_TRIGGER, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSImplicitTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_MIN, + CFG_TDLS_IMPLICIT_TRIGGER_MAX), + + REG_VARIABLE(CFG_TDLS_TX_STATS_PERIOD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxStatsPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_MIN, + CFG_TDLS_TX_STATS_PERIOD_MAX), + + REG_VARIABLE(CFG_TDLS_TX_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxPacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_MIN, + CFG_TDLS_TX_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_MAX_DISCOVERY_ATTEMPT, WLAN_PARAM_Integer, + struct hdd_config, fTDLSMaxDiscoveryAttempt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX), + + REG_VARIABLE(CFG_TDLS_IDLE_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSIdlePacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TRIGGER_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITriggerThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TEARDOWN_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITeardownThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_DELTA, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSIDelta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_DELTA_DEFAULT, + CFG_TDLS_RSSI_DELTA_MIN, + CFG_TDLS_RSSI_DELTA_MAX), + + REG_VARIABLE(CFG_TDLS_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, fTDLSUapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSBufferSta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSOffChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanNum, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_BW, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanBandwidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_INACTIVITY_TIME, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdInactivityTimer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSRxFrameThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTIWindow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTRTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX), + + REG_VARIABLE(CFG_TDLS_EXTERNAL_CONTROL, WLAN_PARAM_Integer, + struct hdd_config, fTDLSExternalControl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_MIN, + CFG_TDLS_EXTERNAL_CONTROL_MAX), + REG_VARIABLE(CFG_TDLS_WMM_MODE_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSWmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_MIN, + CFG_TDLS_WMM_MODE_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, enable_tdls_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SCAN_ENABLE_DEFAULT, + CFG_TDLS_SCAN_ENABLE_MIN, + CFG_TDLS_SCAN_ENABLE_MAX), +#endif + +#ifdef WLAN_SOFTAP_VSTA_FEATURE + REG_VARIABLE(CFG_VSTA_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableVSTASupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VSTA_SUPPORT_ENABLE_DEFAULT, + CFG_VSTA_SUPPORT_ENABLE_MIN, + CFG_VSTA_SUPPORT_ENABLE_MAX), +#endif + REG_VARIABLE(CFG_ENABLE_LPWR_IMG_TRANSITION_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableLpwrImgTransition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, + CFG_ENABLE_LPWR_IMG_TRANSITION_MAX), + + REG_VARIABLE(CFG_ENABLE_LPWR_IMG_TRANSITION_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableLpwrImgTransition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, + CFG_ENABLE_LPWR_IMG_TRANSITION_MAX), + + REG_VARIABLE(CFG_SCAN_AGING_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, scanAgingTimeout, + VAR_FLAGS_OPTIONAL, + CFG_SCAN_AGING_PARAM_DEFAULT, + CFG_SCAN_AGING_PARAM_MIN, + CFG_SCAN_AGING_PARAM_MAX), + + REG_VARIABLE(CFG_TX_LDPC_ENABLE_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableTxLdpc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_MIN, + CFG_TX_LDPC_ENABLE_FEATURE_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enableMCCAdaptiveScheduler, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX), + + REG_VARIABLE(CFG_ANDRIOD_POWER_SAVE_NAME, WLAN_PARAM_Integer, + struct hdd_config, isAndroidPsEn, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ANDRIOD_POWER_SAVE_DEFAULT, + CFG_ANDRIOD_POWER_SAVE_MIN, + CFG_ANDRIOD_POWER_SAVE_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel5G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel24G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX), + + REG_VARIABLE(CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableTxBF, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TXBF_IN_20MHZ, WLAN_PARAM_Integer, + struct hdd_config, enableTxBFin20MHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX), + + REG_VARIABLE(CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, WLAN_PARAM_Integer, + struct hdd_config, txBFCsnValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_SU_BEAM_FORMER, WLAN_PARAM_Integer, + struct hdd_config, enable_su_tx_bformer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX), + + REG_VARIABLE(CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, sapAllowAllChannel, + VAR_FLAGS_OPTIONAL, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX), + +#ifdef WLAN_FEATURE_11AC + REG_VARIABLE(CFG_DISABLE_LDPC_WITH_TXBF_AP, WLAN_PARAM_Integer, + struct hdd_config, disableLDPCWithTxbfAP, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX), +#endif + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_SSR, WLAN_PARAM_Integer, + struct hdd_config, enableSSR, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SSR_DEFAULT, + CFG_ENABLE_SSR_MIN, + CFG_ENABLE_SSR_MAX, + cb_notify_set_enable_ssr, 0), + + REG_VARIABLE(CFG_MAX_MEDIUM_TIME, WLAN_PARAM_Integer, + struct hdd_config, cfgMaxMediumTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_MEDIUM_TIME_STADEFAULT, + CFG_MAX_MEDIUM_TIME_STAMIN, + CFG_MAX_MEDIUM_TIME_STAMAX), + + + +#ifdef WLAN_FEATURE_11AC + REG_VARIABLE(CFG_ENABLE_VHT_FOR_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableVhtFor24GHzBand, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT, + CFG_ENABLE_VHT_FOR_24GHZ_MIN, + CFG_ENABLE_VHT_FOR_24GHZ_MAX), +#endif + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY, + WLAN_PARAM_Integer, + struct hdd_config, bFastRoamInConIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX, + cb_notify_set_enable_fast_roam_in_concurrency, 0), + + REG_VARIABLE(CFG_ENABLE_ADAPT_RX_DRAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableAdaptRxDrain, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_ADAPT_RX_DRAIN_DEFAULT, + CFG_ENABLE_ADAPT_RX_DRAIN_MIN, + CFG_ENABLE_ADAPT_RX_DRAIN_MAX), + + REG_VARIABLE(CFG_FLEX_CONNECT_POWER_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, flexConnectPowerFactor, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_MINMAX, + CFG_FLEX_CONNECT_POWER_FACTOR_DEFAULT, + CFG_FLEX_CONNECT_POWER_FACTOR_MIN, + CFG_FLEX_CONNECT_POWER_FACTOR_MAX), + + REG_VARIABLE(CFG_ENABLE_HEART_BEAT_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, enableIbssHeartBeatOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HEART_BEAT_OFFLOAD_DEFAULT, + CFG_ENABLE_HEART_BEAT_OFFLOAD_MIN, + CFG_ENABLE_HEART_BEAT_OFFLOAD_MAX), + + REG_VARIABLE(CFG_ANTENNA_DIVERSITY_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, antennaDiversity, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT, + CFG_ANTENNA_DIVERSITY_PARAM_MIN, + CFG_ANTENNA_DIVERSITY_PARAM_MAX), + + REG_VARIABLE(CFG_ENABLE_SNR_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableSNRMonitoring, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_SNR_MONITORING_DEFAULT, + CFG_ENABLE_SNR_MONITORING_MIN, + CFG_ENABLE_SNR_MONITORING_MAX), + +#ifdef FEATURE_WLAN_SCAN_PNO + REG_VARIABLE(CFG_PNO_SCAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DISABLE, + CFG_PNO_SCAN_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_PNO_SCAN_TIMER_REPEAT_VALUE, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanTimerRepeatValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX), +#endif + REG_VARIABLE(CFG_AMSDU_SUPPORT_IN_AMPDU_NAME, WLAN_PARAM_Integer, + struct hdd_config, isAmsduSupportInAMPDU, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AMSDU_SUPPORT_IN_AMPDU_DEFAULT, + CFG_AMSDU_SUPPORT_IN_AMPDU_MIN, + CFG_AMSDU_SUPPORT_IN_AMPDU_MAX), + + REG_VARIABLE(CFG_STRICT_5GHZ_PREF_BY_MARGIN, WLAN_PARAM_Integer, + struct hdd_config, nSelect5GHzMargin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX), + + REG_VARIABLE(CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, enable_ip_tcp_udp_checksum_offload, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE), + + REG_VARIABLE(CFG_POWERSAVE_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablePowersaveOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_POWERSAVE_OFFLOAD_DEFAULT, + CFG_POWERSAVE_OFFLOAD_MIN, + CFG_POWERSAVE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_UART_PRINT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablefwprint, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DISABLE, + CFG_ENABLE_FW_UART_PRINT_ENABLE), + + REG_VARIABLE(CFG_ENABLE_FW_LOG_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablefwlog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_DEFAULT, + CFG_ENABLE_FW_LOG_DISABLE, + CFG_ENABLE_FW_LOG_ENABLE), + +#ifdef IPA_OFFLOAD + REG_VARIABLE(CFG_IPA_OFFLOAD_CONFIG_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, IpaConfig, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_MIN, + CFG_IPA_OFFLOAD_CONFIG_MAX), + + REG_VARIABLE(CFG_IPA_DESC_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaDescSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_DESC_SIZE_DEFAULT, + CFG_IPA_DESC_SIZE_MIN, + CFG_IPA_DESC_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_HIGH_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaHighBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_MEDIUM_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaMediumBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_LOW_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaLowBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_MIN, + CFG_IPA_LOW_BANDWIDTH_MBPS_MAX), +#endif + +#ifdef WLAN_FEATURE_11AC + REG_VARIABLE(CFG_VHT_AMPDU_LEN_EXPONENT_NAME, WLAN_PARAM_Integer, + struct hdd_config, fVhtAmpduLenExponent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT, + CFG_VHT_AMPDU_LEN_EXPONENT_MIN, + CFG_VHT_AMPDU_LEN_EXPONENT_MAX), + + REG_VARIABLE(CFG_VHT_MPDU_LEN_NAME, WLAN_PARAM_Integer, + struct hdd_config, vhtMpduLen, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_MPDU_LEN_DEFAULT, + CFG_VHT_MPDU_LEN_MIN, + CFG_VHT_MPDU_LEN_MAX), +#endif + + REG_VARIABLE(CFG_MAX_WOW_FILTERS_NAME, WLAN_PARAM_Integer, + struct hdd_config, maxWoWFilters, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_MAX_WOW_FILTERS_DEFAULT, + CFG_MAX_WOW_FILTERS_MIN, + CFG_MAX_WOW_FILTERS_MAX), + + REG_VARIABLE(CFG_WOW_STATUS_NAME, WLAN_PARAM_Integer, + struct hdd_config, wowEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_STATUS_DEFAULT, + CFG_WOW_ENABLE_MIN, + CFG_WOW_ENABLE_MAX), + + REG_VARIABLE(CFG_COALESING_IN_IBSS_NAME, WLAN_PARAM_Integer, + struct hdd_config, isCoalesingInIBSSAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_COALESING_IN_IBSS_DEFAULT, + CFG_COALESING_IN_IBSS_MIN, + CFG_COALESING_IN_IBSS_MAX), + + REG_VARIABLE(CFG_IBSS_ATIM_WIN_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssATIMWinSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_MIN, + CFG_IBSS_ATIM_WIN_SIZE_MAX), + + REG_VARIABLE(CFG_SAP_MAX_NO_PEERS, WLAN_PARAM_Integer, + struct hdd_config, maxNumberOfPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_NO_PEERS_DEFAULT, + CFG_SAP_MAX_NO_PEERS_MIN, + CFG_SAP_MAX_NO_PEERS_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerSaveAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerCollapseAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_AWAKE_ON_TX_RX_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssAwakeOnTxRx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_MIN, + CFG_IBSS_AWAKE_ON_TX_RX_MAX), + + REG_VARIABLE(CFG_IBSS_INACTIVITY_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssInactivityCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_MIN, + CFG_IBSS_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_TXSP_END_INACTIVITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssTxSpEndInactivityTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_MIN, + CFG_IBSS_TXSP_END_INACTIVITY_MAX), + + REG_VARIABLE(CFG_IBSS_PS_WARMUP_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssPsWarmupTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_MIN, + CFG_IBSS_PS_WARMUP_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ibssPs1RxChainInAtimEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL3_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL3_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT2G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_MIN, + CFG_SET_TXPOWER_LIMIT2G_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT5G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_MIN, + CFG_SET_TXPOWER_LIMIT5G_MAX), + + REG_VARIABLE(CFG_ENABLE_DEBUG_CONNECT_ISSUE, WLAN_PARAM_Integer, + struct hdd_config, gEnableDebugLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_THREAD, WLAN_PARAM_Integer, + struct hdd_config, enableRxThread, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_THREAD_DEFAULT, + CFG_ENABLE_RX_THREAD_MIN, + CFG_ENABLE_RX_THREAD_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, fDfsPhyerrFilterOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_OVERLAP_CH, WLAN_PARAM_Integer, + struct hdd_config, gEnableOverLapCh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_OVERLAP_CH_DEFAULT, + CFG_ENABLE_OVERLAP_CH_MIN, + CFG_ENABLE_OVERLAP_CH_MAX), + + REG_VARIABLE(CFG_REG_CHANGE_DEF_COUNTRY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRegChangeDefCountry, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_MIN, + CFG_REG_CHANGE_DEF_COUNTRY_MAX), + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + REG_VARIABLE(CFG_LL_TX_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_LWM_DEFAULT, + CFG_LL_TX_FLOW_LWM_MIN, + CFG_LL_TX_FLOW_LWM_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_FLOW_HWM_OFFSET_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX), + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_MIN, + CFG_LL_TX_LBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_MIN, + CFG_LL_TX_HBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX), +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + + REG_VARIABLE(CFG_LL_TX_FLOW_STOP_QUEUE_TH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStopQueueThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX), + + REG_VARIABLE(CFG_LL_TX_FLOW_START_QUEUE_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStartQueueOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX), + +#endif + REG_VARIABLE(CFG_INITIAL_DWELL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nInitialDwellTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_DWELL_TIME_DEFAULT, + CFG_INITIAL_DWELL_TIME_MIN, + CFG_INITIAL_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME, WLAN_PARAM_Integer, + struct hdd_config, initial_scan_no_dfs_chnl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_PEERS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_PEERS_MIN, + CFG_SAP_MAX_OFFLOAD_PEERS_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadReorderBuffs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX), + + REG_VARIABLE(CFG_ADVERTISE_CONCURRENT_OPERATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, advertiseConcurrentOperation, + VAR_FLAGS_OPTIONAL, + CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT, + CFG_ADVERTISE_CONCURRENT_OPERATION_MIN, + CFG_ADVERTISE_CONCURRENT_OPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_MEMORY_DEEP_SLEEP, WLAN_PARAM_Integer, + struct hdd_config, enableMemDeepSleep, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX), + + REG_VARIABLE(CFG_DEFAULT_RATE_INDEX_24GH, WLAN_PARAM_Integer, + struct hdd_config, defaultRateIndex24Ghz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DEFAULT_RATE_INDEX_24GH_DEFAULT, + CFG_DEFAULT_RATE_INDEX_24GH_MIN, + CFG_DEFAULT_RATE_INDEX_24GH_MAX), + +#ifdef MEMORY_DEBUG + REG_VARIABLE(CFG_ENABLE_MEMORY_DEBUG_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsMemoryDebugSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MEMORY_DEBUG_DEFAULT, + CFG_ENABLE_MEMORY_DEBUG_MIN, + CFG_ENABLE_MEMORY_DEBUG_MAX), +#endif + + REG_VARIABLE(CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, debugP2pRemainOnChannel, + VAR_FLAGS_OPTIONAL, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX), + + REG_VARIABLE(CFG_ENABLE_PACKET_LOG, WLAN_PARAM_Integer, + struct hdd_config, enablePacketLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_LOG_DEFAULT, + CFG_ENABLE_PACKET_LOG_MIN, + CFG_ENABLE_PACKET_LOG_MAX), + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + REG_VARIABLE(CFG_ROAMING_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ROAMING_OFFLOAD_DEFAULT, + CFG_ROAMING_OFFLOAD_MIN, + CFG_ROAMING_OFFLOAD_MAX), +#endif +#ifdef MSM_PLATFORM + REG_VARIABLE(CFG_BUS_BANDWIDTH_HIGH_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthHighThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthMediumThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_LOW_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthLowThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthComputeInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX), + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_HIGH, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdHigh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_MIN, + CFG_TCP_DELACK_THRESHOLD_HIGH_MAX), + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_LOW, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdLow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_MIN, + CFG_TCP_DELACK_THRESHOLD_LOW_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_FW_LOG_TYPE, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogType, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_MIN, + CFG_ENABLE_FW_LOG_TYPE_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_DEBUG_LOG_LEVEL, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogLevel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX), + + REG_VARIABLE_STRING(CFG_ENABLE_FW_MODULE_LOG_LEVEL, WLAN_PARAM_String, + struct hdd_config, enableFwModuleLogLevel, + VAR_FLAGS_OPTIONAL, + (void *)CFG_ENABLE_FW_MODULE_LOG_DEFAULT), + +#ifdef WLAN_FEATURE_11W + REG_VARIABLE(CFG_PMF_SA_QUERY_MAX_RETRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryMaxRetries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_MIN, + CFG_PMF_SA_QUERY_MAX_RETRIES_MAX), + + REG_VARIABLE(CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryRetryInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX), +#endif + REG_VARIABLE(CFG_MAX_CONCURRENT_CONNECTIONS_NAME, WLAN_PARAM_Integer, + struct hdd_config, gMaxConcurrentActiveSessions, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_MIN, + CFG_MAX_CONCURRENT_CONNECTIONS_MAX), + +#ifdef FEATURE_GREEN_AP + REG_VARIABLE(CFG_ENABLE_GREEN_AP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableGreenAP, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT, + CFG_ENABLE_GREEN_AP_FEATURE_MIN, + CFG_ENABLE_GREEN_AP_FEATURE_MAX), +#endif + + REG_VARIABLE(CFG_IGNORE_CAC_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignoreCAC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_CAC_DEFAULT, + CFG_IGNORE_CAC_MIN, + CFG_IGNORE_CAC_MAX), + + REG_VARIABLE(CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsSapDfsChSifsBurstEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_DEFAULT, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MIN, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MAX), + + REG_VARIABLE(CFG_DFS_RADAR_PRI_MULTIPLIER_NAME, WLAN_PARAM_Integer, + struct hdd_config, dfsRadarPriMultiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_MIN, + CFG_DFS_RADAR_PRI_MULTIPLIER_MAX), + + REG_VARIABLE(CFG_REORDER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, reorderOffloadSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_MIN, + CFG_REORDER_OFFLOAD_SUPPORT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_COUNT_DEFAULT, + CFG_IPA_UC_TX_BUF_COUNT_MIN, + CFG_IPA_UC_TX_BUF_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_SIZE_DEFAULT, + CFG_IPA_UC_TX_BUF_SIZE_MIN, + CFG_IPA_UC_TX_BUF_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_UC_RX_IND_RING_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcRxIndRingCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT, + CFG_IPA_UC_RX_IND_RING_COUNT_MIN, + CFG_IPA_UC_RX_IND_RING_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_PARTITION_BASE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxPartitionBase, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT, + CFG_IPA_UC_TX_PARTITION_BASE_MIN, + CFG_IPA_UC_TX_PARTITION_BASE_MAX), +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + REG_VARIABLE(CFG_WLAN_LOGGING_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingFEToConsole, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_WLAN_LOGGING_NUM_BUF_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingNumBuf, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_NUM_BUF_DEFAULT, + CFG_WLAN_LOGGING_NUM_BUF_MIN, + CFG_WLAN_LOGGING_NUM_BUF_MAX), +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + + REG_VARIABLE(CFG_ENABLE_SIFS_BURST, WLAN_PARAM_Integer, + struct hdd_config, enableSifsBurst, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SIFS_BURST_DEFAULT, + CFG_ENABLE_SIFS_BURST_MIN, + CFG_ENABLE_SIFS_BURST_MAX), + +#ifdef WLAN_FEATURE_LPSS + REG_VARIABLE(CFG_ENABLE_LPASS_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enablelpasssupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_MIN, + CFG_ENABLE_LPASS_SUPPORT_MAX), +#endif + +#ifdef WLAN_FEATURE_NAN + REG_VARIABLE(CFG_ENABLE_NAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_nan_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_MIN, + CFG_ENABLE_NAN_SUPPORT_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_SELF_RECOVERY, WLAN_PARAM_Integer, + struct hdd_config, enableSelfRecovery, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_MIN, + CFG_ENABLE_SELF_RECOVERY_MAX), + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC + REG_VARIABLE(CFG_SAP_SCC_CHAN_AVOIDANCE, WLAN_PARAM_Integer, + struct hdd_config, SapSccChanAvoidance, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_SCC_CHAN_AVOIDANCE_DEFAULT, + CFG_SAP_SCC_CHAN_AVOIDANCE_MIN, + CFG_SAP_SCC_CHAN_AVOIDANCE_MAX), +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + + REG_VARIABLE(CFG_ENABLE_SAP_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, enableSapSuspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_MIN, + CFG_ENABLE_SAP_SUSPEND_MAX), + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + REG_VARIABLE(CFG_EXTWOW_GO_TO_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, extWowGotoSuspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_MIN, + CFG_EXTWOW_GO_TO_SUSPEND_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP1_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp1WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP2_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INIT_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAInitPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MIN_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMinPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MAX_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMaxPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INC_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAIncPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_SRC_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpSrcPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_MIN, + CFG_EXTWOW_TCP_SRC_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_DST_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpDstPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_MIN, + CFG_EXTWOW_TCP_DST_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_TX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpTxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_TX_TIMEOUT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_RX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpRxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_RX_TIMEOUT_MAX), +#endif + REG_VARIABLE(CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, gEnableDeauthToDisassocMap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX), +#ifdef DHCP_SERVER_OFFLOAD + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDHCPServerOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX), + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, dhcpMaxNumClients, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX), + REG_VARIABLE_STRING(CFG_DHCP_SERVER_IP_NAME, WLAN_PARAM_String, + struct hdd_config, dhcpServerIP, + VAR_FLAGS_OPTIONAL, + (void *)CFG_DHCP_SERVER_IP_DEFAULT), +#endif /* DHCP_SERVER_OFFLOAD */ + + REG_VARIABLE(CFG_ENABLE_DEAUTH_BEFORE_CONNECTION, WLAN_PARAM_Integer, + struct hdd_config, sendDeauthBeforeCon, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX), + + REG_VARIABLE(CFG_ENABLE_MAC_ADDR_SPOOFING, WLAN_PARAM_Integer, + struct hdd_config, enable_mac_spoofing, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, + CFG_ENABLE_MAC_ADDR_SPOOFING_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE1_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE2_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_STA_CONNECTION_IN_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, is_sta_connection_in_5gz_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX), + + REG_VARIABLE(CFG_STA_MIRACAST_MCC_REST_TIME_VAL, WLAN_PARAM_Integer, + struct hdd_config, sta_miracast_mcc_rest_time_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX), + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + REG_VARIABLE(CFG_SAP_MCC_CHANNEL_AVOIDANCE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + sap_channel_avoidance, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX), +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + REG_VARIABLE(CFG_SAP_P2P_11AC_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_p2p_11ac_override, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_P2P_11AC_OVERRIDE_DEFAULT, + CFG_SAP_P2P_11AC_OVERRIDE_MIN, + CFG_SAP_P2P_11AC_OVERRIDE_MAX), + + REG_VARIABLE(CFG_ENABLE_RAMDUMP_COLLECTION, WLAN_PARAM_Integer, + struct hdd_config, is_ramdump_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_MIN, + CFG_ENABLE_RAMDUMP_COLLECTION_MAX), + + REG_VARIABLE(CFG_SAP_DOT11MC, WLAN_PARAM_Integer, + struct hdd_config, sap_dot11mc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_DOT11MC_DEFAULT, + CFG_SAP_DOT11MC_MIN, + CFG_SAP_DOT11MC_MAX), + + REG_VARIABLE(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR, WLAN_PARAM_Integer, + struct hdd_config, prefer_non_dfs_on_radar, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX), + + REG_VARIABLE(CFG_MULTICAST_HOST_FW_MSGS, WLAN_PARAM_Integer, + struct hdd_config, multicast_host_fw_msgs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_MIN, + CFG_MULTICAST_HOST_FW_MSGS_MAX), + + REG_VARIABLE(CFG_CONC_SYSTEM_PREF, WLAN_PARAM_Integer, + struct hdd_config, conc_system_pref, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CONC_SYSTEM_PREF_DEFAULT, + CFG_CONC_SYSTEM_PREF_MIN, + CFG_CONC_SYSTEM_PREF_MAX), + + REG_VARIABLE(CFG_POLICY_MNGR_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, policy_manager_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_POLICY_MNGR_ENABLE_DEFAULT, + CFG_POLICY_MNGR_ENABLE_MIN, + CFG_POLICY_MNGR_ENABLE_MAX), + + REG_VARIABLE(CFG_TSO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, tso_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TSO_ENABLED_DEFAULT, + CFG_TSO_ENABLED_MIN, + CFG_TSO_ENABLED_MAX), + + REG_VARIABLE(CFG_LRO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, lro_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LRO_ENABLED_DEFAULT, + CFG_LRO_ENABLED_MIN, + CFG_LRO_ENABLED_MAX), + + REG_VARIABLE(CFG_ACTIVE_MODE_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, active_mode_offload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_MIN, + CFG_ACTIVE_MODE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_FINE_TIME_MEAS_CAPABILITY, WLAN_PARAM_HexInteger, + struct hdd_config, fine_time_meas_cap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_MIN, + CFG_FINE_TIME_MEAS_CAPABILITY_MAX), + +#ifdef WLAN_FEATURE_FASTPATH + REG_VARIABLE(CFG_ENABLE_FASTPATH, WLAN_PARAM_Integer, + struct hdd_config, fastpath_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FASTPATH_DEFAULT, + CFG_ENABLE_FASTPATH_MIN, + CFG_ENABLE_FASTPATH_MAX), +#endif + REG_VARIABLE(CFG_MAX_SCAN_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_scan_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCAN_COUNT_DEFAULT, + CFG_MAX_SCAN_COUNT_MIN, + CFG_MAX_SCAN_COUNT_MAX), + + REG_VARIABLE(CFG_DOT11P_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11p_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DOT11P_MODE_DEFAULT, + CFG_DOT11P_MODE_MIN, + CFG_DOT11P_MODE_MAX), + +#ifdef FEATURE_NAPI + REG_VARIABLE(CFG_NAPI_NAME, WLAN_PARAM_Integer, + struct hdd_config, napi_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NAPI_DEFAULT, + CFG_NAPI_MIN, + CFG_NAPI_MAX), +#endif /* FEATURE_NAPI */ + +#ifdef FEATURE_WLAN_EXTSCAN + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX), +#endif + + REG_VARIABLE(CFG_CE_CLASSIFY_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ce_classify_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_MIN, + CFG_CE_CLASSIFY_ENABLE_MAX), + + REG_VARIABLE(CFG_DUAL_MAC_FEATURE_DISABLE, WLAN_PARAM_HexInteger, + struct hdd_config, dual_mac_feature_disable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_MIN, + CFG_DUAL_MAC_FEATURE_DISABLE_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_CCK, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_cck, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_MIN, + CFG_TX_CHAIN_MASK_CCK_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_1SS, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_1ss, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_MIN, + CFG_TX_CHAIN_MASK_1SS_MAX), + + REG_VARIABLE(CFG_SELF_GEN_FRM_PWR, WLAN_PARAM_Integer, + struct hdd_config, self_gen_frm_pwr, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SELF_GEN_FRM_PWR_DEFAULT, + CFG_SELF_GEN_FRM_PWR_MIN, + CFG_SELF_GEN_FRM_PWR_MAX), + +}; + + +/** + * get_next_line() - find and locate the new line pointer + * @str: pointer to string + * + * This function returns a pointer to the character after the occurence + * of a new line character. It also modifies the original string by replacing + * the '\n' character with the null character. + * + * Return: the pointer to the character at new line, + * or NULL if no new line character was found + */ +static char *get_next_line(char *str) +{ + char c; + + if (str == NULL || *str == '\0') { + return NULL; + } + + c = *str; + while (c != '\n' && c != '\0' && c != 0xd) { + str = str + 1; + c = *str; + } + + if (c == '\0') { + return NULL; + } else { + *str = '\0'; + return str + 1; + } + + return NULL; +} + +/** look for space. Ascii values to look are + * 0x09 == horizontal tab + * 0x0a == Newline ("\n") + * 0x0b == vertical tab + * 0x0c == Newpage or feed form. + * 0x0d == carriage return (CR or "\r") + * Null ('\0') should not considered as space. + */ +#define i_isspace(ch) (((ch) >= 0x09 && (ch) <= 0x0d) || (ch) == ' ') + +/** + * i_trim() - trims any leading and trailing white spaces + * @str: pointer to string + * + * Return: the pointer of the string + */ +static char *i_trim(char *str) +{ + char *ptr; + + if (*str == '\0') + return str; + + /* Find the first non white-space */ + ptr = str; + while (i_isspace(*ptr)) + ptr++; + + if (*ptr == '\0') + return str; + + /* This is the new start of the string */ + str = ptr; + + /* Find the last non white-space */ + ptr += strlen(ptr) - 1; + + while (ptr != str && i_isspace(*ptr)) + ptr--; + + /* Null terminate the following character */ + ptr[1] = '\0'; + + return str; +} + +/* Maximum length of the confgiuration name and value */ +#define CFG_VALUE_MAX_LEN 256 +#define CFG_ENTRY_MAX_LEN (32+CFG_VALUE_MAX_LEN) + +/** + * hdd_cfg_get_config() - get the configuration content + * @reg_table: pointer to configuration table + * @cRegTableEntries: number of the configuration entries + * @ini_struct: pointer to the hdd config knob + * @pHddCtx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: CDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise CDF_STATUS_E_RESOURCES + */ +static CDF_STATUS hdd_cfg_get_config(REG_TABLE_ENTRY *reg_table, + unsigned long cRegTableEntries, + uint8_t *ini_struct, + hdd_context_t *pHddCtx, char *pBuf, + int buflen) +{ + unsigned int idx; + REG_TABLE_ENTRY *pRegEntry = reg_table; + uint32_t value; + char valueStr[CFG_VALUE_MAX_LEN]; + char configStr[CFG_ENTRY_MAX_LEN]; + char *fmt; + void *pField; + struct cdf_mac_addr *pMacAddr; + char *pCur = pBuf; + int curlen; + + /* start with an empty string */ + *pCur = '\0'; + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + pField = ini_struct + pRegEntry->VarOffset; + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_SignedInteger == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + value = 0; + memcpy(&value, pField, pRegEntry->VarSize); + if (WLAN_PARAM_HexInteger == pRegEntry->RegType) { + fmt = "%x"; + } else if (WLAN_PARAM_SignedInteger == + pRegEntry->RegType) { + fmt = "%d"; + } else { + fmt = "%u"; + } + snprintf(valueStr, CFG_VALUE_MAX_LEN, fmt, value); + } else if (WLAN_PARAM_String == pRegEntry->RegType) { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "%s", + (char *)pField); + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + pMacAddr = (struct cdf_mac_addr *) pField; + snprintf(valueStr, CFG_VALUE_MAX_LEN, + "%02x:%02x:%02x:%02x:%02x:%02x", + pMacAddr->bytes[0], + pMacAddr->bytes[1], + pMacAddr->bytes[2], + pMacAddr->bytes[3], + pMacAddr->bytes[4], pMacAddr->bytes[5]); + } else { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "(unhandled)"); + } + curlen = scnprintf(configStr, CFG_ENTRY_MAX_LEN, + "%s=[%s]%s\n", + pRegEntry->RegName, + valueStr, + test_bit(idx, + (void *)&pHddCtx->config-> + bExplicitCfg) ? "*" : ""); + + /* Ideally we want to return the config to the application, + * however the config is too big so we just printk() for now + */ +#ifdef RETURN_IN_BUFFER + if (curlen <= buflen) { + /* copy string + '\0' */ + memcpy(pCur, configStr, curlen + 1); + + /* account for addition; */ + pCur += curlen; + buflen -= curlen; + } else { + /* buffer space exhausted, return what we have */ + return CDF_STATUS_E_RESOURCES; + } +#else + printk(KERN_INFO "%s", configStr); +#endif /* RETURN_IN_BUFFER */ + + } + +#ifndef RETURN_IN_BUFFER + /* notify application that output is in system log */ + snprintf(pCur, buflen, "WLAN configuration written to system log"); +#endif /* RETURN_IN_BUFFER */ + + return CDF_STATUS_SUCCESS; +} + +/** struct tCfgIniEntry - ini configuration entry + * + * @name: name of the entry + * @value: value of the entry + */ +typedef struct { + char *name; + char *value; +} tCfgIniEntry; + +/** + * find_cfg_item() - find the configuration item + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * @name: the interested configuration to find + * @value: the value to read back + * + * Return: CDF_STATUS_SUCCESS if the interested configuration is found, + * otherwise CDF_STATUS_E_FAILURE + */ +static CDF_STATUS find_cfg_item(tCfgIniEntry *iniTable, unsigned long entries, + char *name, char **value) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + unsigned long i; + + for (i = 0; i < entries; i++) { + if (strcmp(iniTable[i].name, name) == 0) { + *value = iniTable[i].value; + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Found %s entry for Name=[%s] Value=[%s] ", + WLAN_INI_FILE, name, *value); + return CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/** + * parse_hex_digit() - conversion to hex value + * @c: the character to convert + * + * Return: the hex value, otherwise 0 + */ +static int parse_hex_digit(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return 0; +} + +/** + * update_mac_from_string() - convert string to 6 bytes mac address + * @pHddCtx: the pointer to hdd context + * @macTable: the macTable to carry the conversion + * @num: number of the interface + * + * 00AA00BB00CC -> 0x00 0xAA 0x00 0xBB 0x00 0xCC + * + * Return: None + */ +static void update_mac_from_string(hdd_context_t *pHddCtx, + tCfgIniEntry *macTable, int num) +{ + int i = 0, j = 0, res = 0; + char *candidate = NULL; + struct cdf_mac_addr macaddr[CDF_MAX_CONCURRENCY_PERSONA]; + + memset(macaddr, 0, sizeof(macaddr)); + + for (i = 0; i < num; i++) { + candidate = macTable[i].value; + for (j = 0; j < CDF_MAC_ADDR_SIZE; j++) { + res = + hex2bin(&macaddr[i].bytes[j], &candidate[(j << 1)], + 1); + if (res < 0) + break; + } + if (res == 0 && !cdf_is_macaddr_zero(&macaddr[i])) { + cdf_mem_copy((uint8_t *) &pHddCtx->config-> + intfMacAddr[i].bytes[0], + (uint8_t *) &macaddr[i].bytes[0], + CDF_MAC_ADDR_SIZE); + } + } +} + +/** + * hdd_apply_cfg_ini() - apply the ini configuration file + * @pHddCtx: the pointer to hdd context + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * It overwrites the MAC address if config file exist. + * + * Return: CDF_STATUS_SUCCESS if the ini configuration file is correctly parsed, + * otherwise CDF_STATUS_E_INVAL + */ +static CDF_STATUS hdd_apply_cfg_ini(hdd_context_t *pHddCtx, + tCfgIniEntry *iniTable, + unsigned long entries) +{ + CDF_STATUS match_status = CDF_STATUS_E_FAILURE; + CDF_STATUS ret_status = CDF_STATUS_SUCCESS; + unsigned int idx; + void *pField; + char *value_str = NULL; + unsigned long len_value_str; + char *candidate; + uint32_t value; + int32_t svalue; + void *pStructBase = pHddCtx->config; + REG_TABLE_ENTRY *pRegEntry = g_registry_table; + unsigned long cRegTableEntries = CDF_ARRAY_SIZE(g_registry_table); + uint32_t cbOutString; + int i; + int rv; + + /* sanity test */ + if (MAX_CFG_INI_ITEMS < cRegTableEntries) { + hddLog(LOGE, + "%s: MAX_CFG_INI_ITEMS too small, must be at least %ld", + __func__, cRegTableEntries); + } + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + /* Calculate the address of the destination field in the structure. */ + pField = ((uint8_t *) pStructBase) + pRegEntry->VarOffset; + + match_status = + find_cfg_item(iniTable, entries, pRegEntry->RegName, + &value_str); + + if ((match_status != CDF_STATUS_SUCCESS) + && (pRegEntry->Flags & VAR_FLAGS_REQUIRED)) { + /* If we could not read the cfg item and it is required, this is an error. */ + hddLog(LOGE, + "%s: Failed to read required config parameter %s", + __func__, pRegEntry->RegName); + ret_status = CDF_STATUS_E_FAILURE; + break; + } + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (match_status == CDF_STATUS_SUCCESS + && (WLAN_PARAM_Integer == pRegEntry->RegType)) { + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) { + hddLog(LOGE, + "%s: Reg Parameter %s invalid. Enforcing default", + __func__, pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else if (match_status == CDF_STATUS_SUCCESS + && (WLAN_PARAM_HexInteger == + pRegEntry->RegType)) { + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) { + hddLog(LOGE, + "%s: Reg paramter %s invalid. Enforcing default", + __func__, pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else { + value = pRegEntry->VarDefault; + } + + /* If this parameter needs range checking, do it here. */ + if (pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (value > pRegEntry->VarMax) { + hddLog(LOGE, + "%s: Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Maximum", + __func__, pRegEntry->RegName, + value, pRegEntry->VarMax); + value = pRegEntry->VarMax; + } + + if (value < pRegEntry->VarMin) { + hddLog(LOGE, + "%s: Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Minimum", + __func__, pRegEntry->RegName, + value, pRegEntry->VarMin); + value = pRegEntry->VarMin; + } + } + /* If this parameter needs range checking, do it here. */ + else if (pRegEntry-> + Flags & VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (value > pRegEntry->VarMax) { + hddLog(LOGE, + "%s: Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Default= %lu", + __func__, pRegEntry->RegName, + value, pRegEntry->VarMax, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + + if (value < pRegEntry->VarMin) { + hddLog(LOGE, + "%s: Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Default= %lu", + __func__, pRegEntry->RegName, + value, pRegEntry->VarMin, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &value, pRegEntry->VarSize); + } else if (WLAN_PARAM_SignedInteger == pRegEntry->RegType) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (CDF_STATUS_SUCCESS == match_status) { + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) { + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Reg Parameter %s invalid. Enforcing Default", + __func__, pRegEntry->RegName); + svalue = + (int32_t) pRegEntry->VarDefault; + } + } else { + svalue = (int32_t) pRegEntry->VarDefault; + } + + /* If this parameter needs range checking, do it here. */ + if (pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hddLog(LOGE, + "%s: Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Maximum", + __func__, pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax); + svalue = (int32_t) pRegEntry->VarMax; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hddLog(LOGE, + "%s: Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Minimum", + __func__, pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin); + svalue = (int32_t) pRegEntry->VarMin; + } + } + /* If this parameter needs range checking, do it here. */ + else if (pRegEntry-> + Flags & VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hddLog(LOGE, + "%s: Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Default= %d", + __func__, pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax, + (int)pRegEntry->VarDefault); + svalue = + (int32_t) pRegEntry->VarDefault; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hddLog(LOGE, + "%s: Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Default= %d", + __func__, pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin, + (int)pRegEntry->VarDefault); + svalue = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &svalue, pRegEntry->VarSize); + } + /* Handle string parameters */ + else if (WLAN_PARAM_String == pRegEntry->RegType) { +#ifdef WLAN_CFG_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "RegName = %s, VarOffset %u VarSize %u VarDefault %s", + pRegEntry->RegName, pRegEntry->VarOffset, + pRegEntry->VarSize, + (char *)pRegEntry->VarDefault); +#endif + + if (match_status == CDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + + if (len_value_str > (pRegEntry->VarSize - 1)) { + hddLog(LOGE, + "%s: Invalid Value=[%s] specified for Name=[%s] in %s", + __func__, value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + cbOutString = + util_min(strlen + ((char *)pRegEntry-> + VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, + (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = + '\0'; + } else { + memcpy(pField, (void *)(value_str), + len_value_str); + ((uint8_t *) pField)[len_value_str] = + '\0'; + } + } else { + /* Failed to read the string parameter from the registry. Use the default. */ + cbOutString = + util_min(strlen((char *)pRegEntry->VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = '\0'; + } + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + if (pRegEntry->VarSize != CDF_MAC_ADDR_SIZE) { + hddLog(LOGE, + "%s: Invalid VarSize %u for Name=[%s]", + __func__, pRegEntry->VarSize, + pRegEntry->RegName); + continue; + } + candidate = (char *)pRegEntry->VarDefault; + if (match_status == CDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + if (len_value_str != (CDF_MAC_ADDR_SIZE * 2)) { + hddLog(LOGE, + "%s: Invalid MAC addr [%s] specified for Name=[%s] in %s", + __func__, value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + } else + candidate = value_str; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < CDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = + (char)(parse_hex_digit(candidate[i * 2]) * + 16 + + parse_hex_digit(candidate[i * 2 + 1])); + } + } else { + hddLog(LOGE, + "%s: Unknown param type for name[%s] in registry table", + __func__, pRegEntry->RegName); + } + + /* did we successfully parse a cfg item for this parameter? */ + if ((match_status == CDF_STATUS_SUCCESS) && + (idx < MAX_CFG_INI_ITEMS)) { + set_bit(idx, (void *)&pHddCtx->config->bExplicitCfg); + } + } + + return ret_status; +} + +/** + * hdd_execute_config_command() - executes an arbitrary configuration command + * @reg_table: the pointer to configuration table + * @tableSize: the size of the configuration table + * @ini_struct: pointer to the hdd config knob + * @pHddCtx: the pointer to hdd context + * @command: the command to run + * + * Return: CDF_STATUS_SUCCESS if the command is found and able to execute, + * otherwise the appropriate CDF_STATUS will be returned + */ +static CDF_STATUS hdd_execute_config_command(REG_TABLE_ENTRY *reg_table, + unsigned long tableSize, + uint8_t *ini_struct, + hdd_context_t *pHddCtx, + char *command) +{ + REG_TABLE_ENTRY *pRegEntry; + char *clone; + char *pCmd; + void *pField; + char *name; + char *value_str; + uint32_t value; + int32_t svalue; + size_t len_value_str; + unsigned int idx; + unsigned int i; + CDF_STATUS vstatus; + int rv; + + /* assume failure until proven otherwise */ + vstatus = CDF_STATUS_E_FAILURE; + + /* clone the command so that we can manipulate it */ + clone = kstrdup(command, GFP_ATOMIC); + if (NULL == clone) { + hddLog(LOGE, + "%s: memory allocation failure, unable to process [%s]", + __func__, command); + return vstatus; + } + /* 'clone' will point to the beginning of the string so it can be freed + * 'pCmd' will be used to walk/parse the command + */ + pCmd = clone; + + /* get rid of leading/trailing whitespace */ + pCmd = i_trim(pCmd); + if ('\0' == *pCmd) { + /* only whitespace */ + hddLog(LOGE, "%s: invalid command, only whitespace:[%s]", + __func__, command); + goto done; + } + /* parse the = */ + name = pCmd; + while (('=' != *pCmd) && ('\0' != *pCmd)) { + pCmd++; + } + if ('\0' == *pCmd) { + /* did not find '=' */ + hddLog(LOGE, "%s: invalid command, no '=':[%s]", + __func__, command); + goto done; + } + /* replace '=' with NUL to terminate the */ + *pCmd++ = '\0'; + name = i_trim(name); + if ('\0' == *name) { + /* did not find a name */ + hddLog(LOGE, "%s: invalid command, no :[%s]", + __func__, command); + goto done; + } + + value_str = i_trim(pCmd); + if ('\0' == *value_str) { + /* did not find a value */ + hddLog(LOGE, "%s: invalid command, no :[%s]", + __func__, command); + goto done; + } + /* lookup the configuration item */ + for (idx = 0; idx < tableSize; idx++) { + if (0 == strcmp(name, reg_table[idx].RegName)) { + /* found a match */ + break; + } + } + if (tableSize == idx) { + /* did not match the name */ + hddLog(LOGE, + "%s: invalid command, unknown configuration item:[%s]", + __func__, command); + goto done; + } + + pRegEntry = ®_table[idx]; + if (!(pRegEntry->Flags & VAR_FLAGS_DYNAMIC_CFG)) { + /* does not support dynamic configuration */ + hddLog(LOGE, "%s: Global_Registry_Table.%s does not support " + "dynamic configuration", __func__, name); + vstatus = CDF_STATUS_E_PERM; + goto done; + } + + pField = ini_struct + pRegEntry->VarOffset; + + switch (pRegEntry->RegType) { + case WLAN_PARAM_Integer: + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %u < min value %lu", + __func__, value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %u > max value %lu", + __func__, value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_HexInteger: + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %x < min value %lx", + __func__, value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %x > max value %lx", + __func__, value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_SignedInteger: + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) + goto done; + if (svalue < (int32_t) pRegEntry->VarMin) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %d < min value %d", + __func__, svalue, (int)pRegEntry->VarMin); + goto done; + } + if (svalue > (int32_t) pRegEntry->VarMax) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, value %d > max value %d", + __func__, svalue, (int)pRegEntry->VarMax); + goto done; + } + memcpy(pField, &svalue, pRegEntry->VarSize); + break; + + case WLAN_PARAM_String: + len_value_str = strlen(value_str); + if (len_value_str > (pRegEntry->VarSize - 1)) { + /* too big */ + hddLog(LOGE, + "%s: invalid command, string [%s] length " + "%zu exceeds maximum length %u", + __func__, value_str, + len_value_str, (pRegEntry->VarSize - 1)); + goto done; + } + /* copy string plus NUL */ + memcpy(pField, value_str, (len_value_str + 1)); + break; + + case WLAN_PARAM_MacAddr: + len_value_str = strlen(value_str); + if (len_value_str != (CDF_MAC_ADDR_SIZE * 2)) { + /* out of range */ + hddLog(LOGE, + "%s: invalid command, MAC address [%s] length " + "%zu is not expected length %u", + __func__, value_str, + len_value_str, (CDF_MAC_ADDR_SIZE * 2)); + goto done; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < CDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = (char) + ((parse_hex_digit(value_str[(i * 2)]) * 16) + + parse_hex_digit(value_str[(i * 2) + 1])); + } + break; + + default: + goto done; + } + + /* if we get here, we had a successful modification */ + vstatus = CDF_STATUS_SUCCESS; + + /* config table has been modified, is there a notifier? */ + if (NULL != pRegEntry->pfnDynamicnotify) { + (pRegEntry->pfnDynamicnotify)(pHddCtx, pRegEntry->notifyId); + } + /* note that this item was explicitly configured */ + if (idx < MAX_CFG_INI_ITEMS) { + set_bit(idx, (void *)&pHddCtx->config->bExplicitCfg); + } +done: + kfree(clone); + return vstatus; +} + +/** + * hdd_set_power_save_offload_config() - set power save offload configuration + * @pHddCtx: the pointer to hdd context + * + * Return: none + */ +static void hdd_set_power_save_offload_config(hdd_context_t *pHddCtx) +{ + struct hdd_config *pConfig = pHddCtx->config; + uint32_t listenInterval = 0; + + if (strcmp(pConfig->PowerUsageControl, "Min") == 0) { + listenInterval = pConfig->nBmpsMinListenInterval; + } else if (strcmp(pConfig->PowerUsageControl, "Max") == 0) { + listenInterval = pConfig->nBmpsMaxListenInterval; + } else if (strcmp(pConfig->PowerUsageControl, "Mod") == 0) { + listenInterval = pConfig->nBmpsModListenInterval; + } + + /* + * Based on Mode Set the LI + * Otherwise default LI value of 1 will + * be taken + */ + if (listenInterval) { + /* + * setcfg for listenInterval. + * Make sure CFG is updated because PE reads this + * from CFG at the time of assoc or reassoc + */ + sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, + listenInterval); + } + +} + +/** + * hdd_cfg_print() - print the hdd configuration + * @iniTable: pointer to hdd context + * + * Return: None + */ +void hdd_cfg_print(hdd_context_t *pHddCtx) +{ + int i; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "*********Config values in HDD Adapter*******"); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [RTSThreshold] Value = %u", + pHddCtx->config->RTSThreshold); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [OperatingChannel] Value = [%u]", + pHddCtx->config->OperatingChannel); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [PowerUsageControl] Value = [%s]", + pHddCtx->config->PowerUsageControl); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fIsImpsEnabled] Value = [%u]", + pHddCtx->config->fIsImpsEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nVccRssiTrigger] Value = [%u]", + pHddCtx->config->nVccRssiTrigger); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssBssid] Value =[" MAC_ADDRESS_STR "]", + MAC_ADDR_ARRAY(pHddCtx->config->IbssBssid.bytes)); + + for (i = 0; i < CDF_MAX_CONCURRENCY_PERSONA; i++) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [Intf%dMacAddress] Value =[" MAC_ADDRESS_STR "]", + i, MAC_ADDR_ARRAY(pHddCtx->config->intfMacAddr[i].bytes)); + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApEnableUapsd] value = [%u]", + pHddCtx->config->apUapsdEnabled); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableApProt] value = [%u]", + pHddCtx->config->apProtEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gAPAutoShutOff] Value = [%u]", + pHddCtx->config->nAPAutoShutOff); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gWlanMccToSccSwitchMode] Value = [%u]", + pHddCtx->config->WlanMccToSccSwitchMode); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gWlanAutoShutdown] Value = [%u]", + pHddCtx->config->WlanAutoShutdown); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableListenMode] Value = [%u]", + pHddCtx->config->nEnableListenMode); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApProtection] value = [%u]", + pHddCtx->config->apProtection); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableApOBSSProt] value = [%u]", + pHddCtx->config->apOBSSProtEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS, + pHddCtx->config->force_sap_acs); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS_START_CH, + pHddCtx->config->force_sap_acs_st_ch); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS_END_CH, + pHddCtx->config->force_sap_acs_end_ch); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [sap_channel_avoidance] value = [%u]", + pHddCtx->config->sap_channel_avoidance); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] value = [%u]", CFG_SAP_P2P_11AC_OVERRIDE_NAME, + pHddCtx->config->sap_p2p_11ac_override); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [ChannelBondingMode] Value = [%u]", + pHddCtx->config->nChannelBondingMode24GHz); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [ChannelBondingMode] Value = [%u]", + pHddCtx->config->nChannelBondingMode5GHz); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [dot11Mode] Value = [%u]", + pHddCtx->config->dot11Mode); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [WmmMode] Value = [%u] ", pHddCtx->config->WmmMode); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [UapsdMask] Value = [0x%x] ", + pHddCtx->config->UapsdMask); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [PktClassificationBasis] Value = [%u] ", + pHddCtx->config->PktClassificationBasis); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [ImplicitQosIsEnabled] Value = [%u]", + (int)pHddCtx->config->bImplicitQosEnabled); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdVoSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdVoSrvIntv); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdVoSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdVoSuspIntv); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdViSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdViSrvIntv); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdViSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdViSuspIntv); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdBeSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBeSrvIntv); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdBeSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBeSuspIntv); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdBkSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBkSrvIntv); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraUapsdBkSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBkSuspIntv); +#ifdef FEATURE_WLAN_ESE + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraInactivityInterval] Value = [%u] ", + pHddCtx->config->InfraInactivityInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [EseEnabled] Value = [%u] ", + pHddCtx->config->isEseIniFeatureEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [FastTransitionEnabled] Value = [%u] ", + pHddCtx->config->isFastTransitionEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gTxPowerCap] Value = [%u] dBm ", + pHddCtx->config->nTxPowerCap); +#endif +#ifdef FEATURE_WLAN_LFR + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [FastRoamEnabled] Value = [%u] ", + pHddCtx->config->isFastRoamIniFeatureEnabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [MAWCEnabled] Value = [%u] ", + pHddCtx->config->MAWCEnabled); +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [RoamRssiDiff] Value = [%u] ", + pHddCtx->config->RoamRssiDiff); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [isWESModeEnabled] Value = [%u] ", + pHddCtx->config->isWESModeEnabled); +#endif +#ifdef FEATURE_WLAN_OKC + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [OkcEnabled] Value = [%u] ", + pHddCtx->config->isOkcIniFeatureEnabled); +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [configPNOScanSupport] Value = [%u] ", + pHddCtx->config->configPNOScanSupport); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [configPNOScanTimerRepeatValue] Value = [%u] ", + pHddCtx->config->configPNOScanTimerRepeatValue); +#endif +#ifdef FEATURE_WLAN_TDLS + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fEnableTDLSSupport] Value = [%u] ", + pHddCtx->config->fEnableTDLSSupport); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fEnableTDLSImplicitTrigger] Value = [%u] ", + pHddCtx->config->fEnableTDLSImplicitTrigger); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fTDLSExternalControl] Value = [%u] ", + pHddCtx->config->fTDLSExternalControl); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fTDLSUapsdMask] Value = [%u] ", + pHddCtx->config->fTDLSUapsdMask); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fEnableTDLSBufferSta] Value = [%u] ", + pHddCtx->config->fEnableTDLSBufferSta); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fEnableTDLSWmmMode] Value = [%u] ", + pHddCtx->config->fEnableTDLSWmmMode); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [enable_tdls_scan] Value = [%u]", + pHddCtx->config->enable_tdls_scan); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraDirAcVo] Value = [%u] ", + pHddCtx->config->InfraDirAcVo); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraNomMsduSizeAcVo] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcVo); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMeanDataRateAcVo] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcVo); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMinPhyRateAcVo] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcVo); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraSbaAcVo] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcVo); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraDirAcVi] Value = [%u] ", + pHddCtx->config->InfraDirAcVi); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraNomMsduSizeAcVi] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcVi); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMeanDataRateAcVi] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcVi); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMinPhyRateAcVi] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcVi); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraSbaAcVi] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcVi); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraDirAcBe] Value = [%u] ", + pHddCtx->config->InfraDirAcBe); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraNomMsduSizeAcBe] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcBe); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMeanDataRateAcBe] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcBe); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMinPhyRateAcBe] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcBe); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraSbaAcBe] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcBe); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraDirAcBk] Value = [%u] ", + pHddCtx->config->InfraDirAcBk); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraNomMsduSizeAcBk] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcBk); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMeanDataRateAcBk] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcBk); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraMinPhyRateAcBk] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcBk); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [InfraSbaAcBk] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcBk); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [DelayedTriggerFrmInt] Value = [%u] ", + pHddCtx->config->DelayedTriggerFrmInt); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [mcastBcastFilterSetting] Value = [%u] ", + pHddCtx->config->mcastBcastFilterSetting); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fhostArpOffload] Value = [%u] ", + pHddCtx->config->fhostArpOffload); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [ssdp] Value = [%u] ", pHddCtx->config->ssdp); +#ifdef FEATURE_WLAN_RA_FILTERING + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [RArateLimitInterval] Value = [%u] ", + pHddCtx->config->RArateLimitInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [IsRArateLimitEnabled] Value = [%u] ", + pHddCtx->config->IsRArateLimitEnabled); +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fFTResourceReqSupported] Value = [%u] ", + pHddCtx->config->fFTResourceReqSupported); +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nNeighborLookupRssiThreshold] Value = [%u] ", + pHddCtx->config->nNeighborLookupRssiThreshold); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [delay_before_vdev_stop] Value = [%u] ", + pHddCtx->config->delay_before_vdev_stop); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nOpportunisticThresholdDiff] Value = [%u] ", + pHddCtx->config->nOpportunisticThresholdDiff); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nRoamRescanRssiDiff] Value = [%u] ", + pHddCtx->config->nRoamRescanRssiDiff); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nNeighborScanMinChanTime] Value = [%u] ", + pHddCtx->config->nNeighborScanMinChanTime); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nNeighborScanMaxChanTime] Value = [%u] ", + pHddCtx->config->nNeighborScanMaxChanTime); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nMaxNeighborRetries] Value = [%u] ", + pHddCtx->config->nMaxNeighborReqTries); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nNeighborScanPeriod] Value = [%u] ", + pHddCtx->config->nNeighborScanPeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nNeighborScanResultsRefreshPeriod] Value = [%u] ", + pHddCtx->config->nNeighborResultsRefreshPeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nEmptyScanRefreshPeriod] Value = [%u] ", + pHddCtx->config->nEmptyScanRefreshPeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nRoamBmissFirstBcnt] Value = [%u] ", + pHddCtx->config->nRoamBmissFirstBcnt); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nRoamBmissFinalBcnt] Value = [%u] ", + pHddCtx->config->nRoamBmissFinalBcnt); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nRoamBeaconRssiWeight] Value = [%u] ", + pHddCtx->config->nRoamBeaconRssiWeight); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [allowDFSChannelRoam] Value = [%u] ", + pHddCtx->config->allowDFSChannelRoam); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nhi_rssi_scan_max_count] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_max_count); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nhi_rssi_scan_rssi_delta] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_rssi_delta); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nhi_rssi_scan_delay] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_delay); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nhi_rssi_scan_rssi_ub] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_rssi_ub); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [burstSizeDefinition] Value = [0x%x] ", + pHddCtx->config->burstSizeDefinition); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [tsInfoAckPolicy] Value = [0x%x] ", + pHddCtx->config->tsInfoAckPolicy); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [rfSettlingTimeUs] Value = [%u] ", + pHddCtx->config->rfSettlingTimeUs); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [bSingleTidRc] Value = [%u] ", + pHddCtx->config->bSingleTidRc); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gDynamicPSPollvalue] Value = [%u] ", + pHddCtx->config->dynamicPsPollValue); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gAddTSWhenACMIsOff] Value = [%u] ", + pHddCtx->config->AddTSWhenACMIsOff); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gValidateScanList] Value = [%u] ", + pHddCtx->config->fValidateScanList); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gStaKeepAlivePeriod] Value = [%u] ", + pHddCtx->config->infraStaKeepAlivePeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApDataAvailPollInterVal] Value = [%u] ", + pHddCtx->config->apDataAvailPollPeriodInMs); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [BandCapability] Value = [%u] ", + pHddCtx->config->nBandCapability); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fEnableBeaconEarlyTermination] Value = [%u] ", + pHddCtx->config->fEnableBeaconEarlyTermination); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [teleBcnWakeupEnable] Value = [%u] ", + pHddCtx->config->teleBcnWakeupEn); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [transListenInterval] Value = [%u] ", + pHddCtx->config->nTeleBcnTransListenInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [transLiNumIdleBeacons] Value = [%u] ", + pHddCtx->config->nTeleBcnTransLiNumIdleBeacons); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [maxListenInterval] Value = [%u] ", + pHddCtx->config->nTeleBcnMaxListenInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [maxLiNumIdleBeacons] Value = [%u] ", + pHddCtx->config->nTeleBcnMaxLiNumIdleBeacons); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [bcnEarlyTermWakeInterval] Value = [%u] ", + pHddCtx->config->bcnEarlyTermWakeInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApDataAvailPollInterVal] Value = [%u] ", + pHddCtx->config->apDataAvailPollPeriodInMs); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableBypass11d] Value = [%u] ", + pHddCtx->config->enableBypass11d); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableDFSChnlScan] Value = [%u] ", + pHddCtx->config->enableDFSChnlScan); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableDFSPnoChnlScan] Value = [%u] ", + pHddCtx->config->enable_dfs_pno_chnl_scan); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gReportMaxLinkSpeed] Value = [%u] ", + pHddCtx->config->reportMaxLinkSpeed); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [thermalMitigationEnable] Value = [%u] ", + pHddCtx->config->thermalMitigationEnable); +#ifdef WLAN_FEATURE_11AC + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gVhtChannelWidth] value = [%u]", + pHddCtx->config->vhtChannelWidth); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [enableFirstScan2GOnly] Value = [%u] ", + pHddCtx->config->enableFirstScan2GOnly); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [skipDfsChnlInP2pSearch] Value = [%u] ", + pHddCtx->config->skipDfsChnlInP2pSearch); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [ignoreDynamicDtimInP2pMode] Value = [%u] ", + pHddCtx->config->ignoreDynamicDtimInP2pMode); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [enableRxSTBC] Value = [%u] ", + pHddCtx->config->enableRxSTBC); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableLpwrImgTransition] Value = [%u] ", + pHddCtx->config->enableLpwrImgTransition); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableSSR] Value = [%u] ", + pHddCtx->config->enableSSR); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableVhtFor24GHzBand] Value = [%u] ", + pHddCtx->config->enableVhtFor24GHzBand); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gFlexConnectPowerFactor] Value = [%u] ", + pHddCtx->config->flexConnectPowerFactor); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableIbssHeartBeatOffload] Value = [%u] ", + pHddCtx->config->enableIbssHeartBeatOffload); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gAntennaDiversity] Value = [%u] ", + pHddCtx->config->antennaDiversity); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gGoLinkMonitorPeriod] Value = [%u]", + pHddCtx->config->goLinkMonitorPeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApLinkMonitorPeriod] Value = [%u]", + pHddCtx->config->apLinkMonitorPeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gGoKeepAlivePeriod] Value = [%u]", + pHddCtx->config->goKeepAlivePeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gApKeepAlivePeriod]Value = [%u]", + pHddCtx->config->apKeepAlivePeriod); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gAmsduSupportInAMPDU] Value = [%u] ", + pHddCtx->config->isAmsduSupportInAMPDU); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [nSelect5GHzMargin] Value = [%u] ", + pHddCtx->config->nSelect5GHzMargin); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gCoalesingInIBSS] Value = [%u] ", + pHddCtx->config->isCoalesingInIBSSAllowed); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssATIMWinSize] Value = [%u] ", + pHddCtx->config->ibssATIMWinSize); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssIsPowerSaveAllowed] Value = [%u] ", + pHddCtx->config->isIbssPowerSaveAllowed); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssIsPowerCollapseAllowed] Value = [%u] ", + pHddCtx->config->isIbssPowerCollapseAllowed); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssAwakeOnTxRx] Value = [%u] ", + pHddCtx->config->isIbssAwakeOnTxRx); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssInactivityTime] Value = [%u] ", + pHddCtx->config->ibssInactivityCount); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssTxSpEndInactivityTime] Value = [%u] ", + pHddCtx->config->ibssTxSpEndInactivityTime); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssPsWarmupTime] Value = [%u] ", + pHddCtx->config->ibssPsWarmupTime); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIbssPs1RxChainInAtim] Value = [%u] ", + pHddCtx->config->ibssPs1RxChainInAtimEnable); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fDfsPhyerrFilterOffload] Value = [%u] ", + pHddCtx->config->fDfsPhyerrFilterOffload); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIgnorePeerErpInfo] Value = [%u] ", + pHddCtx->config->ignore_peer_erp_info); +#ifdef IPA_OFFLOAD + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIPAConfig] Value = [0x%x] ", + pHddCtx->config->IpaConfig); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIPADescSize] Value = [%u] ", + pHddCtx->config->IpaDescSize); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [IpaHighBandwidthMbpsg] Value = [%u] ", + pHddCtx->config->IpaHighBandwidthMbps); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [IpaMediumBandwidthMbps] Value = [%u] ", + pHddCtx->config->IpaMediumBandwidthMbps); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [IpaLowBandwidthMbps] Value = [%u] ", + pHddCtx->config->IpaLowBandwidthMbps); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableOverLapCh] Value = [%u] ", + pHddCtx->config->gEnableOverLapCh); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gMaxOffloadPeers] Value = [%u] ", + pHddCtx->config->apMaxOffloadPeers); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gMaxOffloadReorderBuffs] value = [%u] ", + pHddCtx->config->apMaxOffloadReorderBuffs); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gAllowDFSChannelRoam] Value = [%u] ", + pHddCtx->config->allowDFSChannelRoam); + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gMaxConcurrentActiveSessions] Value = [%u] ", + pHddCtx->config->gMaxConcurrentActiveSessions); + +#ifdef MSM_PLATFORM + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gBusBandwidthHighThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthHighThreshold); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gBusBandwidthMediumThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthMediumThreshold); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gBusBandwidthLowThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthLowThreshold); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gbusBandwidthComputeInterval] Value = [%u] ", + pHddCtx->config->busBandwidthComputeInterval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gTcpDelAckThresholdHigh] Value = [%u] ", + pHddCtx->config->tcpDelackThresholdHigh); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gTcpDelAckThresholdLow] Value = [%u] ", + pHddCtx->config->tcpDelackThresholdLow); +#endif + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gIgnoreCAC] Value = [%u] ", + pHddCtx->config->ignoreCAC); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gSapPreferredChanLocation] Value = [%u] ", + pHddCtx->config->gSapPreferredChanLocation); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gDisableDfsJapanW53] Value = [%u] ", + pHddCtx->config->gDisableDfsJapanW53); +#ifdef FEATURE_GREEN_AP + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableGreenAp] Value = [%u] ", + pHddCtx->config->enableGreenAP); +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [isRoamOffloadEnabled] Value = [%u]", + pHddCtx->config->isRoamOffloadEnabled); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableSifsBurst] Value = [%u]", + pHddCtx->config->enableSifsBurst); + +#ifdef WLAN_FEATURE_LPSS + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableLpassSupport] Value = [%u] ", + pHddCtx->config->enablelpasssupport); +#endif + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableSelfRecovery] Value = [%u]", + pHddCtx->config->enableSelfRecovery); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableSapSuspend] Value = [%u]", + pHddCtx->config->enableSapSuspend); + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWgotoSuspend] Value = [%u]", + pHddCtx->config->extWowGotoSuspend); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWowApp1WakeupPinNumber] Value = [%u]", + pHddCtx->config->extWowApp1WakeupPinNumber); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWowApp2WakeupPinNumber] Value = [%u]", + pHddCtx->config->extWowApp2WakeupPinNumber); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2KAInitPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAInitPingInterval); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2KAMinPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAMinPingInterval); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2KAMaxPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAMaxPingInterval); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2KAIncPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAIncPingInterval); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2TcpSrcPort] Value = [%u]", + pHddCtx->config->extWowApp2TcpSrcPort); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2TcpDstPort] Value = [%u]", + pHddCtx->config->extWowApp2TcpDstPort); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2TcpTxTimeout] Value = [%u]", + pHddCtx->config->extWowApp2TcpTxTimeout); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gExtWoWApp2TcpRxTimeout] Value = [%u]", + pHddCtx->config->extWowApp2TcpRxTimeout); +#endif + +#ifdef DHCP_SERVER_OFFLOAD + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gDHCPServerOffloadEnable] Value = [%u]", + pHddCtx->config->enableDHCPServerOffload); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gDHCPMaxNumClients] Value = [%u]", + pHddCtx->config->dhcpMaxNumClients); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gDHCPServerIP] Value = [%s]", + pHddCtx->config->dhcpServerIP); +#endif + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gEnableDumpCollect] Value = [%u]", + pHddCtx->config->is_ramdump_enabled); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [gP2PListenDeferInterval] Value = [%u]", + pHddCtx->config->p2p_listen_defer_interval); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [is_ps_enabled] value = [%d]", + pHddCtx->config->is_ps_enabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [policy_manager_enabled] value = [%d]", + pHddCtx->config->policy_manager_enabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [tso_enable] value = [%d]", + pHddCtx->config->tso_enable); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [LROEnable] value = [%d]", + pHddCtx->config->lro_enable); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [active_mode_offload] value = [%d]", + pHddCtx->config->active_mode_offload); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [gfine_time_meas_cap] value = [%u]", + pHddCtx->config->fine_time_meas_cap); +#ifdef WLAN_FEATURE_FASTPATH + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [fastpath_enable] Value = [%u]", + pHddCtx->config->fastpath_enable); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [max_scan_count] value = [%d]", + pHddCtx->config->max_scan_count); +#ifdef FEATURE_NAPI_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [%s] value = [%d]", + CFG_ENABLE_RX_THREAD, pHddCtx->config->enableRxThread); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [%s] value = [%d]", + CFG_NAPI_NAME, pHddCtx->config->napi_enable); +#endif + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Name = [%s] Value = [%u]", + CFG_CE_CLASSIFY_ENABLE_NAME, + pHddCtx->config->ce_classify_enabled); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Name = [%s] value = [%u]", + CFG_DUAL_MAC_FEATURE_DISABLE, + pHddCtx->config->dual_mac_feature_disable); +} + + +/** + * hdd_update_mac_config() - update MAC address from cfg file + * @pHddCtx: the pointer to hdd context + * + * It overwrites the MAC address if config file exist. + * + * Return: CDF_STATUS_SUCCESS if the MAC address is found from cfg file + * and overwritten, otherwise CDF_STATUS_E_INVAL + */ +CDF_STATUS hdd_update_mac_config(hdd_context_t *pHddCtx) +{ + int status, i = 0; + const struct firmware *fw = NULL; + char *line, *buffer = NULL; + char *name, *value; + tCfgIniEntry macTable[CDF_MAX_CONCURRENCY_PERSONA]; + tSirMacAddr customMacAddr; + + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + memset(macTable, 0, sizeof(macTable)); + status = request_firmware(&fw, WLAN_MAC_FILE, pHddCtx->parent_dev); + + if (status) { + hddLog(CDF_TRACE_LEVEL_WARN, "%s: request_firmware failed %d", + __func__, status); + cdf_status = CDF_STATUS_E_FAILURE; + return cdf_status; + } + if (!fw || !fw->data || !fw->size) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: invalid firmware", __func__); + cdf_status = CDF_STATUS_E_INVAL; + goto config_exit; + } + + buffer = (char *)fw->data; + + /* data format: + * Intf0MacAddress=00AA00BB00CC + * Intf1MacAddress=00AA00BB00CD + * END + */ + while (buffer != NULL) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } + if (strncmp(buffer, "END", 3) == 0) + break; + + name = buffer; + buffer = strnchr(buffer, strlen(buffer), '='); + if (buffer) { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) == 12) { + value = buffer; + macTable[i].name = name; + macTable[i++].value = value; + if (i >= CDF_MAX_CONCURRENCY_PERSONA) + break; + } + } + } + buffer = line; + } + if (i <= CDF_MAX_CONCURRENCY_PERSONA) { + hddLog(CDF_TRACE_LEVEL_INFO, "%s: %d Mac addresses provided", + __func__, i); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: invalid number of Mac address provided, nMac = %d", + __func__, i); + cdf_status = CDF_STATUS_E_INVAL; + goto config_exit; + } + + update_mac_from_string(pHddCtx, &macTable[0], i); + + cdf_mem_copy(&customMacAddr, + &pHddCtx->config->intfMacAddr[0].bytes[0], + sizeof(tSirMacAddr)); + sme_set_custom_mac_addr(customMacAddr); + +config_exit: + release_firmware(fw); + return cdf_status; +} + +/** + * hdd_parse_config_ini() - parse the ini configuration file + * @pHddCtx: the pointer to hdd context + * + * This function reads the qcom_cfg.ini file and + * parses each 'Name=Value' pair in the ini file + * + * Return: CDF_STATUS_SUCCESS if the qcom_cfg.ini is correctly read, + * otherwise CDF_STATUS_E_INVAL + */ +CDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx) +{ + int status, i = 0; + /** Pointer for firmware image data */ + const struct firmware *fw = NULL; + char *buffer, *line, *pTemp = NULL; + size_t size; + char *name, *value; + /* cfgIniTable is static to avoid excess stack usage */ + static tCfgIniEntry cfgIniTable[MAX_CFG_INI_ITEMS]; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + memset(cfgIniTable, 0, sizeof(cfgIniTable)); + + status = request_firmware(&fw, WLAN_INI_FILE, pHddCtx->parent_dev); + + if (status) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: request_firmware failed %d", + __func__, status); + cdf_status = CDF_STATUS_E_FAILURE; + goto config_exit; + } + if (!fw || !fw->data || !fw->size) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: %s download failed", + __func__, WLAN_INI_FILE); + cdf_status = CDF_STATUS_E_FAILURE; + goto config_exit; + } + + hddLog(LOG1, "%s: qcom_cfg.ini Size %zu", __func__, fw->size); + + buffer = (char *)cdf_mem_malloc(fw->size); + + if (NULL == buffer) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("cdf_mem_malloc failure")); + release_firmware(fw); + return CDF_STATUS_E_NOMEM; + } + pTemp = buffer; + + cdf_mem_copy((void *)buffer, (void *)fw->data, fw->size); + size = fw->size; + + while (buffer != NULL) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + hddLog(LOG1, "%s: item", buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } else if (strncmp(buffer, "END", 3) == 0) { + break; + } else { + name = buffer; + while (*buffer != '=' && *buffer != '\0') + buffer++; + if (*buffer != '\0') { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) > 0) { + value = buffer; + while (!i_isspace(*buffer) + && *buffer != '\0') + buffer++; + *buffer = '\0'; + cfgIniTable[i].name = name; + cfgIniTable[i++].value = value; + if (i >= MAX_CFG_INI_ITEMS) { + hddLog(LOGE, + "%s: Number of items in %s > %d", + __func__, + WLAN_INI_FILE, + MAX_CFG_INI_ITEMS); + break; + } + } + } + } + } + buffer = line; + } + + /* Loop through the registry table and apply all these configs */ + cdf_status = hdd_apply_cfg_ini(pHddCtx, cfgIniTable, i); +#ifdef FEATURE_NAPI + if (CDF_STATUS_SUCCESS == cdf_status) + hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)pHddCtx->config->napi_enable); +#endif /* FEATURE_NAPI */ + +config_exit: + release_firmware(fw); + cdf_mem_free(pTemp); + return cdf_status; +} + +/** + * hdd_cfg_xlate_to_csr_phy_mode() - convert PHY mode + * @dot11Mode: the mode to convert + * + * Convert the configuration PHY mode to CSR PHY mode + * + * Return: the CSR phy mode value + */ +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(eHddDot11Mode dot11Mode) +{ + switch (dot11Mode) { + case (eHDD_DOT11_MODE_abg): + return eCSR_DOT11_MODE_abg; + case (eHDD_DOT11_MODE_11b): + return eCSR_DOT11_MODE_11b; + case (eHDD_DOT11_MODE_11g): + return eCSR_DOT11_MODE_11g; + default: + case (eHDD_DOT11_MODE_11n): + return eCSR_DOT11_MODE_11n; + case (eHDD_DOT11_MODE_11g_ONLY): + return eCSR_DOT11_MODE_11g_ONLY; + case (eHDD_DOT11_MODE_11n_ONLY): + return eCSR_DOT11_MODE_11n_ONLY; + case (eHDD_DOT11_MODE_11b_ONLY): + return eCSR_DOT11_MODE_11b_ONLY; +#ifdef WLAN_FEATURE_11AC + case (eHDD_DOT11_MODE_11ac_ONLY): + return eCSR_DOT11_MODE_11ac_ONLY; + case (eHDD_DOT11_MODE_11ac): + return eCSR_DOT11_MODE_11ac; +#else + /* If 11AC support is not compiled set Auto mode */ + case (eHDD_DOT11_MODE_11ac): + case (eHDD_DOT11_MODE_11ac_ONLY): + return eCSR_DOT11_MODE_AUTO; +#endif + case (eHDD_DOT11_MODE_AUTO): + return eCSR_DOT11_MODE_AUTO; + case (eHDD_DOT11_MODE_11a): + return eCSR_DOT11_MODE_11a; + } + +} + +/** + * hdd_set_idle_ps_config() - set idle power save configuration + * @pHddCtx: the pointer to hdd context + * @val: the value to configure + * + * Return: CDF_STATUS_SUCCESS if command set correctly, + * otherwise the CDF_STATUS return from SME layer + */ +CDF_STATUS hdd_set_idle_ps_config(hdd_context_t *pHddCtx, uint32_t val) +{ + struct hdd_config *pConfig = pHddCtx->config; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + hddLog(LOG1, "hdd_set_idle_ps_config: Enter Val %d", val); + + if (pConfig->fIsImpsEnabled) { + status = sme_set_idle_powersave_config(pHddCtx->pcds_context, + pHddCtx->hHal, val); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, "Fail to Set Idle PS Config val %d", val); + } + } else { + hddLog(LOG1, "hdd_set_idle_ps_config: IMPS not enabled in ini"); + } + return status; +} + +/** + * hdd_set_fine_time_meas_cap() - set fine timing measurement capability + * @hdd_ctx: HDD context + * @sme_config: pointer to SME config + * + * This function is used to pass fine timing measurement capability coming + * from INI to SME. This function make sure that configure INI is supported + * by the device. Use bit mask to mask out the unsupported capabilities. + * + * Return: None + */ +static void hdd_set_fine_time_meas_cap(hdd_context_t *hdd_ctx, + tSmeConfigParams *sme_config) +{ + struct hdd_config *config = hdd_ctx->config; + uint32_t capability = config->fine_time_meas_cap; + + /* Make sure only supported capabilities are enabled in INI */ + capability &= CFG_FINE_TIME_MEAS_CAPABILITY_MAX; + sme_config->fine_time_meas_cap = capability; + + hddLog(LOG1, FL("fine time meas capability - INI: %04x Enabled: %04x"), + config->fine_time_meas_cap, sme_config->fine_time_meas_cap); + + return; +} + +/** + * hdd_string_to_u8_array() - scan the string and convert to u8 array + * @str: the pointer to the string + * @intArray: the pointer of buffer to store the u8 value + * @len: size of the buffer + * + * Return: CDF_STATUS_SUCCESS if the conversion is done, + * otherwise CDF_STATUS_E_INVAL + */ +CDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *intArray, uint8_t *len, + uint8_t intArrayMaxLen) +{ + char *s = str; + + if (str == NULL || intArray == NULL || len == NULL) { + return CDF_STATUS_E_INVAL; + } + *len = 0; + + while ((s != NULL) && (*len < intArrayMaxLen)) { + int val; + /* Increment length only if sscanf succesfully extracted one element. + * Any other return value means error. Ignore it. + */ + if (sscanf(s, "%d", &val) == 1) { + intArray[*len] = (uint8_t) val; + *len += 1; + } + s = strpbrk(s, ","); + if (s) + s++; + } + + return CDF_STATUS_SUCCESS; + +} + +/** + * hdd_update_config_dat() - scan the string and convery to u8 array + * @str: the pointer to the string + * @intArray: the pointer of buffer to store the u8 value + * @len: size of the buffer + * + * Return: CDF_STATUS_SUCCESS if the configuration could be updated corectly, + * otherwise CDF_STATUS_E_INVAL + */ +bool hdd_update_config_dat(hdd_context_t *pHddCtx) +{ + bool fStatus = true; + uint32_t val; + uint16_t val16; + + struct hdd_config *pConfig = pHddCtx->config; + tSirMacHTCapabilityInfo *phtCapInfo; + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_SHORT_GI_20MHZ, + pConfig->ShortGI20MhzEnable) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_SHORT_GI_20MHZ to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_FIXED_RATE, pConfig->TxRate) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_FIXED_RATE to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_MAX_RX_AMPDU_FACTOR, + pConfig->MaxRxAmpduFactor) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_SHORT_PREAMBLE, + pConfig->fIsShortPreamble) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_SHORT_PREAMBLE to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + pConfig->nPassiveMinChnTime) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME" + " to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pConfig->nPassiveMaxChnTime) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME" + " to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_BEACON_INTERVAL, + pConfig->nBeaconInterval) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_BEACON_INTERVAL to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_MAX_PS_POLL, + pConfig->nMaxPsPoll) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_MAX_PS_POLL to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_CURRENT_RX_ANTENNA, + pConfig->nRxAnt) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_CURRENT_RX_ANTENNA to CFG"); + } + + if (sme_cfg_set_int (pHddCtx->hHal, WNI_CFG_LOW_GAIN_OVERRIDE, + pConfig->fIsLowGainOverride) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_LOW_GAIN_OVERRIDE to HAL"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RSSI_FILTER_PERIOD, + pConfig->nRssiFilterPeriod) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RSSI_FILTER_PERIOD to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_IGNORE_DTIM, + pConfig->fIgnoreDtim) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_IGNORE_DTIM to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_PS_ENABLE_HEART_BEAT, + pConfig->fEnableFwHeartBeatMonitoring) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PS_HEART_BEAT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_PS_ENABLE_BCN_FILTER, + pConfig->fEnableFwBeaconFiltering) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PS_BCN_FILTER to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_PS_ENABLE_RSSI_MONITOR, + pConfig->fEnableFwRssiMonitoring) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PS_RSSI_MONITOR to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + pConfig->nDataInactivityTimeout) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_ENABLE_LTE_COEX, + pConfig->enableLTECoex) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_LTE_COEX to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE, + pConfig->nEnableListenMode) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + pConfig->apKeepAlivePeriod) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_AP_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + pConfig->goKeepAlivePeriod) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_GO_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + pConfig->apLinkMonitorPeriod) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_AP_LINK_MONITOR_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + pConfig->goLinkMonitorPeriod) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_GO_LINK_MONITOR_TIMEOUT to CFG"); + } + +#if defined WLAN_FEATURE_VOWIFI + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RRM_ENABLED, pConfig->fRrmEnable) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RRM_ENABLE to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RRM_OPERATING_CHAN_MAX, + pConfig->nInChanMeasMaxDuration) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RRM_OPERATING_CHAN_MAX to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RRM_NON_OPERATING_CHAN_MAX, + pConfig->nOutChanMeasMaxDuration) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RRM_OUT_CHAN_MAX to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_MCAST_BCAST_FILTER_SETTING, + pConfig->mcastBcastFilterSetting) == CDF_STATUS_E_FAILURE) + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_MCAST_BCAST_FILTER_SETTING to CFG"); +#endif + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_SINGLE_TID_RC, + pConfig->bSingleTidRc) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_SINGLE_TID_RC to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_TELE_BCN_WAKEUP_EN, + pConfig->teleBcnWakeupEn) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TELE_BCN_WAKEUP_EN to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_TELE_BCN_TRANS_LI, + pConfig->nTeleBcnTransListenInterval) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TELE_BCN_TRANS_LI to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_TELE_BCN_MAX_LI, + pConfig->nTeleBcnMaxListenInterval) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TELE_BCN_MAX_LI to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + pConfig->nTeleBcnTransLiNumIdleBeacons) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + pConfig->nTeleBcnMaxLiNumIdleBeacons) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RF_SETTLING_TIME_CLK, + pConfig->rfSettlingTimeUs) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RF_SETTLING_TIME_CLK to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + pConfig->infraStaKeepAlivePeriod) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD to CFG"); + } + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_DYNAMIC_PS_POLL_VALUE, + pConfig->dynamicPsPollValue) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DYNAMIC_PS_POLL_VALUE to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + pConfig->nNullDataApRespTimeout) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_PS_NULLDATA_DELAY_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + pConfig->apDataAvailPollPeriodInMs) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD to CFG"); + } + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, + pConfig->FragmentationThreshold) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_FRAGMENTATION_THRESHOLD to CFG"); + } + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_RTS_THRESHOLD, + pConfig->RTSThreshold) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_RTS_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_11D_ENABLED, + pConfig->Is11dSupportEnabled) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_11D_ENABLED to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_DFS_MASTER_ENABLED, + pConfig->enableDFSMasterCap) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Failure: Could not set value for WNI_CFG_DFS_MASTER_ENABLED"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + pConfig->enableTxBFin20MHz) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not set value for WNI_CFG_VHT_ENABLE_TXBF_20MHZ"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_HEART_BEAT_THRESHOLD, + pConfig->HeartbeatThresh24) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_HEART_BEAT_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + pConfig->apDataAvailPollPeriodInMs) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_ENABLE_CLOSE_LOOP, + pConfig->enableCloseLoop) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_CLOSE_LOOP to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TX_PWR_CTRL_ENABLE, + pConfig->enableAutomaticTxPowerControl) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TX_PWR_CTRL_ENABLE to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_SHORT_GI_40MHZ, + pConfig->ShortGI40MhzEnable) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_SHORT_GI_40MHZ to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_ENABLE_MC_ADDR_LIST, + pConfig->fEnableMCAddrList) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CFG"); + } + /* Based on cfg.ini, update the Basic MCS set, RX/TX MCS map + * in the cfg.dat. Valid values are 0(MCS0-7), 1(MCS0-8), 2(MCS0-9) + * we update only the least significant 2 bits in the + * corresponding fields. + */ + if ((pConfig->dot11Mode == eHDD_DOT11_MODE_AUTO) || + (pConfig->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || + (pConfig->dot11Mode == eHDD_DOT11_MODE_11ac)) { + uint32_t temp = 0; + + sme_cfg_get_int(pHddCtx->hHal, + WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & 0xFFFC) | pConfig->vhtRxMCS; + if (pConfig->enable2x2) + temp = (temp & 0xFFF3) | (pConfig->vhtRxMCS2x2 << 2); + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_BASIC_MCS_SET, temp) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_BASIC_MCS_SET to CFG"); + } + + sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_VHT_RX_MCS_MAP, + &temp); + temp = (temp & 0xFFFC) | pConfig->vhtRxMCS; + if (pConfig->enable2x2) + temp = (temp & 0xFFF3) | (pConfig->vhtRxMCS2x2 << 2); + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_RX_MCS_MAP, temp) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_RX_MCS_MAP to CFG"); + } + sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | pConfig->vhtTxMCS; + if (pConfig->enable2x2) + temp = (temp & 0xFFF3) | (pConfig->vhtTxMCS2x2 << 2); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "vhtRxMCS2x2 - %x temp - %u enable2x2 %d", + pConfig->vhtRxMCS2x2, temp, + pConfig->enable2x2); + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_TX_MCS_MAP, + temp) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_TX_MCS_MAP to CFG"); + } + /* Currently shortGI40Mhz is used for shortGI80Mhz */ + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_VHT_SHORT_GI_80MHZ, + pConfig->ShortGI40MhzEnable) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass WNI_VHT_SHORT_GI_80MHZ to CFG"); + } + /* Hardware is capable of doing + * 128K AMPDU in 11AC mode */ + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + pConfig->fVhtAmpduLenExponent) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_AMPDU_LEN_EXPONENT to CFG"); + } + /* Change MU Bformee only when TxBF is enabled */ + if (pConfig->enableTxBF) { + sme_cfg_get_int(pHddCtx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &temp); + + if (temp != pConfig->enableMuBformee) { + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + pConfig->enableMuBformee + ) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_MU_BEAMFORMEE_CAP to CFG"); + } + } + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_MAX_MPDU_LENGTH, + pConfig->vhtMpduLen) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_MAX_MPDU_LENGTH to CFG"); + } + + if (pConfig->enable2x2 && pConfig->enable_su_tx_bformer) { + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + pConfig->enable_su_tx_bformer) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hdd_err("set SU_BEAMFORMER_CAP to CFG failed"); + } + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + NUM_OF_SOUNDING_DIMENSIONS) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hdd_err("failed to set NUM_OF_SOUNDING_DIM"); + } + } + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_HT_RX_STBC, + pConfig->enableRxSTBC) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_HT_RX_STBC to CFG"); + } + + sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_HT_CAP_INFO, &val); + val16 = (uint16_t) val; + phtCapInfo = (tSirMacHTCapabilityInfo *) &val16; + phtCapInfo->rxSTBC = pConfig->enableRxSTBC; + phtCapInfo->advCodingCap = pConfig->enableRxLDPC; + val = val16; + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_HT_CAP_INFO, val) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_HT_CAP_INFO to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_RXSTBC, + pConfig->enableRxSTBC) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_VHT_RXSTBC to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_TXSTBC, + pConfig->enableTxSTBC) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Could not pass on WNI_CFG_VHT_TXSTBC to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, + pConfig->enableRxLDPC) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_LDPC_CODING_CAP to CFG"); + } +#ifdef WLAN_SOFTAP_VSTA_FEATURE + if (pConfig->fEnableVSTASupport) { + sme_cfg_get_int(pHddCtx->hHal, WNI_CFG_ASSOC_STA_LIMIT, &val); + if (val <= WNI_CFG_ASSOC_STA_LIMIT_STADEF) + val = WNI_CFG_ASSOC_STA_LIMIT_STAMAX; + } else { + val = pConfig->maxNumberOfPeers; + + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_ASSOC_STA_LIMIT, val) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ASSOC_STA_LIMIT to CFG"); + } +#endif + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + pConfig->enableLpwrImgTransition) + == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_LPWR_IMG_TRANSITION to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + pConfig->enableMCCAdaptiveScheduler) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CFG"); + } + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + pConfig->disableLDPCWithTxbfAP) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + pConfig->retryLimitZero) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DYNAMIC_THRESHOLD_ZERO to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_ONE, + pConfig->retryLimitOne) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DYNAMIC_THRESHOLD_ONE to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_TWO, + pConfig->retryLimitTwo) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DYNAMIC_THRESHOLD_TWO to CFG"); + } + + if (sme_cfg_set_int + (pHddCtx->hHal, WNI_CFG_MAX_MEDIUM_TIME, + pConfig->cfgMaxMediumTime) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_MAX_MEDIUM_TIME to CFG"); + } +#ifdef FEATURE_WLAN_TDLS + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + pConfig->fTDLSUapsdMask) == CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK to CFG"); + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_BUF_STA_ENABLED, + pConfig->fEnableTDLSBufferSta) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_PUAPSD_INACT_TIME, + pConfig->fTDLSPuapsdInactivityTimer) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_PUAPSD_INACT_TIME to CFG"); + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + pConfig->fTDLSRxFrameThreshold) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_RX_FRAME_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + pConfig->fEnableTDLSOffChannel) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_TDLS_WMM_MODE_ENABLED, + pConfig->fEnableTDLSWmmMode) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_TDLS_WMM_MODE_ENABLED to CFG"); + } +#endif + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + pConfig->fEnableAdaptRxDrain) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ENABLE_ADAPT_RX_DRAIN to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_FLEX_CONNECT_POWER_FACTOR, + pConfig->flexConnectPowerFactor) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, "Failure: Could not pass on " + "WNI_CFG_FLEX_CONNECT_POWER_FACTOR to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_ANTENNA_DIVESITY, + pConfig->antennaDiversity) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_ANTENNA_DIVESITY to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + pConfig->defaultRateIndex24Ghz) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DEFAULT_RATE_INDEX_24GHZ to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + pConfig->debugP2pRemainOnChannel) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL to CFG"); + } +#ifdef WLAN_FEATURE_11W + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + pConfig->pmfSaQueryMaxRetries) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_SA_QUERY_MAX_RETRIES to CFG"); + } + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + pConfig->pmfSaQueryRetryInterval) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_SA_QUERY_RETRY_INTERVAL to CFG"); + } +#endif + + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_ATIM_WIN_SIZE, + pConfig->ibssATIMWinSize) == + CDF_STATUS_E_FAILURE) { + fStatus = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CFG"); + } + return fStatus; +} + +/** + * hdd_set_sme_config() -initializes the sme configuration parameters + * + * @pHddCtx: the pointer to hdd context + * + * Return: CDF_STATUS_SUCCESS if configuration is correctly applied, + * otherwise the appropriate CDF_STATUS would be returned + */ +CDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeConfigParams *smeConfig; + + struct hdd_config *pConfig = pHddCtx->config; + + smeConfig = cdf_mem_malloc(sizeof(*smeConfig)); + if (NULL == smeConfig) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: unable to allocate smeConfig", __func__); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(smeConfig, sizeof(*smeConfig)); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s bWmmIsEnabled=%d 802_11e_enabled=%d dot11Mode=%d", + __func__, pConfig->WmmMode, pConfig->b80211eIsEnabled, + pConfig->dot11Mode); + + /* Config params obtained from the registry + * To Do: set regulatory information here + */ + + smeConfig->csrConfig.RTSThreshold = pConfig->RTSThreshold; + smeConfig->csrConfig.FragmentationThreshold = + pConfig->FragmentationThreshold; + smeConfig->csrConfig.shortSlotTime = pConfig->ShortSlotTimeEnabled; + smeConfig->csrConfig.Is11dSupportEnabled = pConfig->Is11dSupportEnabled; + smeConfig->csrConfig.HeartbeatThresh24 = pConfig->HeartbeatThresh24; + + smeConfig->csrConfig.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + + if (pConfig->dot11Mode == eHDD_DOT11_MODE_abg || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b_ONLY || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g_ONLY) { + smeConfig->csrConfig.channelBondingMode24GHz = 0; + smeConfig->csrConfig.channelBondingMode5GHz = 0; + } else { + smeConfig->csrConfig.channelBondingMode24GHz = + pConfig->nChannelBondingMode24GHz; + smeConfig->csrConfig.channelBondingMode5GHz = + pConfig->nChannelBondingMode5GHz; + } + smeConfig->csrConfig.TxRate = pConfig->TxRate; + smeConfig->csrConfig.nScanResultAgeCount = pConfig->ScanResultAgeCount; + smeConfig->csrConfig.scanAgeTimeNCNPS = pConfig->nScanAgeTimeNCNPS; + smeConfig->csrConfig.scanAgeTimeNCPS = pConfig->nScanAgeTimeNCPS; + smeConfig->csrConfig.scanAgeTimeCNPS = pConfig->nScanAgeTimeCNPS; + smeConfig->csrConfig.scanAgeTimeCPS = pConfig->nScanAgeTimeCPS; + smeConfig->csrConfig.AdHocChannel24 = pConfig->OperatingChannel; + smeConfig->csrConfig.fSupplicantCountryCodeHasPriority = + pConfig->fSupplicantCountryCodeHasPriority; + smeConfig->csrConfig.bCatRssiOffset = pConfig->nRssiCatGap; + smeConfig->csrConfig.vccRssiThreshold = pConfig->nVccRssiTrigger; + smeConfig->csrConfig.vccUlMacLossThreshold = + pConfig->nVccUlMacLossThreshold; + smeConfig->csrConfig.nRoamingTime = pConfig->nRoamingTime; + smeConfig->csrConfig.nInitialDwellTime = pConfig->nInitialDwellTime; + smeConfig->csrConfig.initial_scan_no_dfs_chnl = + pConfig->initial_scan_no_dfs_chnl; + smeConfig->csrConfig.nActiveMaxChnTime = pConfig->nActiveMaxChnTime; + smeConfig->csrConfig.nActiveMinChnTime = pConfig->nActiveMinChnTime; + smeConfig->csrConfig.nPassiveMaxChnTime = pConfig->nPassiveMaxChnTime; + smeConfig->csrConfig.nPassiveMinChnTime = pConfig->nPassiveMinChnTime; +#ifdef WLAN_AP_STA_CONCURRENCY + smeConfig->csrConfig.nActiveMaxChnTimeConc = + pConfig->nActiveMaxChnTimeConc; + smeConfig->csrConfig.nActiveMinChnTimeConc = + pConfig->nActiveMinChnTimeConc; + smeConfig->csrConfig.nPassiveMaxChnTimeConc = + pConfig->nPassiveMaxChnTimeConc; + smeConfig->csrConfig.nPassiveMinChnTimeConc = + pConfig->nPassiveMinChnTimeConc; + smeConfig->csrConfig.nRestTimeConc = pConfig->nRestTimeConc; + smeConfig->csrConfig.nNumStaChanCombinedConc = + pConfig->nNumStaChanCombinedConc; + smeConfig->csrConfig.nNumP2PChanCombinedConc = + pConfig->nNumP2PChanCombinedConc; + +#endif + smeConfig->csrConfig.Is11eSupportEnabled = pConfig->b80211eIsEnabled; + smeConfig->csrConfig.WMMSupportMode = pConfig->WmmMode; + +#if defined WLAN_FEATURE_VOWIFI + smeConfig->rrmConfig.rrmEnabled = pConfig->fRrmEnable; + smeConfig->rrmConfig.maxRandnInterval = pConfig->nRrmRandnIntvl; +#endif + /* Remaining config params not obtained from registry + * On RF EVB beacon using channel 1. + */ +#ifdef WLAN_FEATURE_11AC + smeConfig->csrConfig.nVhtChannelWidth = pConfig->vhtChannelWidth; + smeConfig->csrConfig.enableTxBF = pConfig->enableTxBF; + smeConfig->csrConfig.txBFCsnValue = pConfig->txBFCsnValue; + smeConfig->csrConfig.enable2x2 = pConfig->enable2x2; + smeConfig->csrConfig.enableVhtFor24GHz = pConfig->enableVhtFor24GHzBand; + smeConfig->csrConfig.enableMuBformee = pConfig->enableMuBformee; + smeConfig->csrConfig.enableVhtpAid = pConfig->enableVhtpAid; + smeConfig->csrConfig.enableVhtGid = pConfig->enableVhtGid; +#endif + smeConfig->csrConfig.enableAmpduPs = pConfig->enableAmpduPs; + smeConfig->csrConfig.enableHtSmps = pConfig->enableHtSmps; + smeConfig->csrConfig.htSmps = pConfig->htSmps; + smeConfig->csrConfig.AdHocChannel5G = pConfig->AdHocChannel5G; + smeConfig->csrConfig.AdHocChannel24 = pConfig->AdHocChannel24G; + smeConfig->csrConfig.ProprietaryRatesEnabled = 0; + smeConfig->csrConfig.HeartbeatThresh50 = 40; + smeConfig->csrConfig.bandCapability = pConfig->nBandCapability; + if (pConfig->nBandCapability == eCSR_BAND_24) { + smeConfig->csrConfig.Is11hSupportEnabled = 0; + } else { + smeConfig->csrConfig.Is11hSupportEnabled = + pConfig->Is11hSupportEnabled; + } + smeConfig->csrConfig.cbChoice = 0; + smeConfig->csrConfig.eBand = pConfig->nBandCapability; + smeConfig->csrConfig.nTxPowerCap = pConfig->nTxPowerCap; + smeConfig->csrConfig.fEnableBypass11d = pConfig->enableBypass11d; + smeConfig->csrConfig.fEnableDFSChnlScan = pConfig->enableDFSChnlScan; +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + smeConfig->csrConfig.nRoamPrefer5GHz = pConfig->nRoamPrefer5GHz; + smeConfig->csrConfig.nRoamIntraBand = pConfig->nRoamIntraBand; + smeConfig->csrConfig.nProbes = pConfig->nProbes; + + smeConfig->csrConfig.nRoamScanHomeAwayTime = + pConfig->nRoamScanHomeAwayTime; +#endif + smeConfig->csrConfig.fFirstScanOnly2GChnl = + pConfig->enableFirstScan2GOnly; + + /* FIXME 11d config is hardcoded */ + if (CDF_SAP_MODE != hdd_get_conparam()) + smeConfig->csrConfig.Csr11dinfo.Channels.numChannels = 0; + + hdd_set_power_save_offload_config(pHddCtx); + +#ifdef WLAN_FEATURE_VOWIFI_11R + smeConfig->csrConfig.csr11rConfig.IsFTResourceReqSupported = + pConfig->fFTResourceReqSupported; +#endif +#ifdef FEATURE_WLAN_LFR + smeConfig->csrConfig.isFastRoamIniFeatureEnabled = + pConfig->isFastRoamIniFeatureEnabled; + smeConfig->csrConfig.MAWCEnabled = pConfig->MAWCEnabled; +#endif +#ifdef FEATURE_WLAN_ESE + smeConfig->csrConfig.isEseIniFeatureEnabled = + pConfig->isEseIniFeatureEnabled; + if (pConfig->isEseIniFeatureEnabled) { + pConfig->isFastTransitionEnabled = true; + } +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + smeConfig->csrConfig.isFastTransitionEnabled = + pConfig->isFastTransitionEnabled; + smeConfig->csrConfig.RoamRssiDiff = pConfig->RoamRssiDiff; + smeConfig->csrConfig.isWESModeEnabled = pConfig->isWESModeEnabled; +#endif + smeConfig->csrConfig.isRoamOffloadScanEnabled = + pConfig->isRoamOffloadScanEnabled; + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = + pConfig->bFastRoamInConIniFeatureEnabled; + + if (0 == smeConfig->csrConfig.isRoamOffloadScanEnabled) { + /* Disable roaming in concurrency if roam scan offload is disabled */ + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = 0; + } +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + smeConfig->csrConfig.neighborRoamConfig.nNeighborLookupRssiThreshold = + pConfig->nNeighborLookupRssiThreshold; + smeConfig->csrConfig.neighborRoamConfig.delay_before_vdev_stop = + pConfig->delay_before_vdev_stop; + smeConfig->csrConfig.neighborRoamConfig.nOpportunisticThresholdDiff = + pConfig->nOpportunisticThresholdDiff; + smeConfig->csrConfig.neighborRoamConfig.nRoamRescanRssiDiff = + pConfig->nRoamRescanRssiDiff; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMaxChanTime = + pConfig->nNeighborScanMaxChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMinChanTime = + pConfig->nNeighborScanMinChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanTimerPeriod = + pConfig->nNeighborScanPeriod; + smeConfig->csrConfig.neighborRoamConfig.nMaxNeighborRetries = + pConfig->nMaxNeighborReqTries; + smeConfig->csrConfig.neighborRoamConfig.nNeighborResultsRefreshPeriod = + pConfig->nNeighborResultsRefreshPeriod; + smeConfig->csrConfig.neighborRoamConfig.nEmptyScanRefreshPeriod = + pConfig->nEmptyScanRefreshPeriod; + hdd_string_to_u8_array(pConfig->neighborScanChanList, + smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.channelList, + &smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFirstBcnt = + pConfig->nRoamBmissFirstBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFinalBcnt = + pConfig->nRoamBmissFinalBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBeaconRssiWeight = + pConfig->nRoamBeaconRssiWeight; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_max_count = + pConfig->nhi_rssi_scan_max_count; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_delta = + pConfig->nhi_rssi_scan_rssi_delta; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_delay = + pConfig->nhi_rssi_scan_delay; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_ub = + pConfig->nhi_rssi_scan_rssi_ub; +#endif + smeConfig->csrConfig.addTSWhenACMIsOff = pConfig->AddTSWhenACMIsOff; + smeConfig->csrConfig.fValidateList = pConfig->fValidateScanList; + smeConfig->csrConfig.allowDFSChannelRoam = pConfig->allowDFSChannelRoam; + + /* Enable/Disable MCC */ + smeConfig->csrConfig.fEnableMCCMode = pConfig->enableMCC; + smeConfig->csrConfig.mcc_rts_cts_prot_enable = + pConfig->mcc_rts_cts_prot_enable; + smeConfig->csrConfig.mcc_bcast_prob_resp_enable = + pConfig->mcc_bcast_prob_resp_enable; + smeConfig->csrConfig.fAllowMCCGODiffBI = pConfig->allowMCCGODiffBI; + + /* Scan Results Aging Time out value */ + smeConfig->csrConfig.scanCfgAgingTime = pConfig->scanAgingTimeout; + + smeConfig->csrConfig.enableTxLdpc = pConfig->enableTxLdpc; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + smeConfig->csrConfig.cc_switch_mode = pConfig->WlanMccToSccSwitchMode; +#endif + + smeConfig->csrConfig.isAmsduSupportInAMPDU = + pConfig->isAmsduSupportInAMPDU; + smeConfig->csrConfig.nSelect5GHzMargin = pConfig->nSelect5GHzMargin; + + smeConfig->csrConfig.isCoalesingInIBSSAllowed = + pHddCtx->config->isCoalesingInIBSSAllowed; + smeConfig->csrConfig.ignore_peer_erp_info = + pConfig->ignore_peer_erp_info; + /* update SSR config */ + sme_update_enable_ssr((tHalHandle) (pHddCtx->hHal), + pHddCtx->config->enableSSR); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* Update PNO offoad status */ + smeConfig->pnoOffload = pHddCtx->config->PnoOffload; +#endif + + /* Update maximum interfaces information */ + smeConfig->max_intf_count = pHddCtx->max_intf_count; + + smeConfig->fEnableDebugLog = pHddCtx->config->gEnableDebugLog; + + smeConfig->enable5gEBT = pHddCtx->config->enable5gEBT; + + smeConfig->enableSelfRecovery = pHddCtx->config->enableSelfRecovery; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + smeConfig->csrConfig.isRoamOffloadEnabled = + pHddCtx->config->isRoamOffloadEnabled; +#endif + smeConfig->csrConfig.conc_custom_rule1 = + pHddCtx->config->conc_custom_rule1; + smeConfig->csrConfig.conc_custom_rule2 = + pHddCtx->config->conc_custom_rule2; + smeConfig->csrConfig.is_sta_connection_in_5gz_enabled = + pHddCtx->config->is_sta_connection_in_5gz_enabled; + + smeConfig->f_sta_miracast_mcc_rest_time_val = + pHddCtx->config->sta_miracast_mcc_rest_time_val; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + smeConfig->sap_channel_avoidance = + pHddCtx->config->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + smeConfig->f_prefer_non_dfs_on_radar = + pHddCtx->config->prefer_non_dfs_on_radar; + + smeConfig->is_ps_enabled = pHddCtx->config->is_ps_enabled; + hdd_set_fine_time_meas_cap(pHddCtx, smeConfig); + + cds_set_multicast_logging(pHddCtx->config->multicast_host_fw_msgs); + + smeConfig->csrConfig.sendDeauthBeforeCon = pConfig->sendDeauthBeforeCon; + + smeConfig->policy_manager_enabled = + pHddCtx->config->policy_manager_enabled; + smeConfig->csrConfig.max_scan_count = + pHddCtx->config->max_scan_count; + + /* Update 802.11p config */ + smeConfig->csrConfig.enable_dot11p = + (pHddCtx->config->dot11p_mode != WLAN_HDD_11P_DISABLED); + + smeConfig->dual_mac_feature_disable = + pHddCtx->config->dual_mac_feature_disable; + + status = sme_update_config(pHddCtx->hHal, smeConfig); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, "sme_update_config() return failure %d", + status); + } + + cdf_mem_free(smeConfig); + return status; +} + +/** + * hdd_execute_global_config_command() - execute the global config command + * @pHddCtx: the pointer to hdd context + * @command: the command to run + * + * Return: the CDF_STATUS return from hdd_execute_config_command + */ +CDF_STATUS hdd_execute_global_config_command(hdd_context_t *pHddCtx, + char *command) +{ + return hdd_execute_config_command(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) pHddCtx->config, + pHddCtx, command); +} + +/** + * hdd_cfg_get_global_config() - get the configuration table + * @pHddCtx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: CDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise CDF_STATUS_E_RESOURCES + */ +CDF_STATUS hdd_cfg_get_global_config(hdd_context_t *pHddCtx, char *pBuf, + int buflen) +{ + return hdd_cfg_get_config(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) pHddCtx->config, pHddCtx, pBuf, + buflen); +} + +/** + * hdd_is_okc_mode_enabled() - returns whether OKC mode is enabled or not + * @pHddCtx: the pointer to hdd context + * + * Return: true if OKC is enabled, otherwise false + */ +bool hdd_is_okc_mode_enabled(hdd_context_t *pHddCtx) +{ + if (NULL == pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: pHddCtx is NULL", __func__); + return -EINVAL; + } +#ifdef FEATURE_WLAN_OKC + return pHddCtx->config->isOkcIniFeatureEnabled; +#else + return false; +#endif +} + +/** + * hdd_update_nss() - Update the number of spatial streams supported. + * Ensure that nss is either 1 or 2 before calling this. + * + * @hdd_ctx: the pointer to hdd context + * @nss: the number of spatial streams to be updated + * + * This function is used to modify the number of spatial streams + * supported when not in connected state. + * + * Return: CDF_STATUS_SUCCESS if nss is correctly updated, + * otherwise CDF_STATUS_E_FAILURE would be returned + */ +CDF_STATUS hdd_update_nss(hdd_context_t *hdd_ctx, uint8_t nss) +{ + struct hdd_config *hdd_config = hdd_ctx->config; + uint32_t temp = 0; + uint32_t rx_supp_data_rate, tx_supp_data_rate; + bool status = true; + tSirMacHTCapabilityInfo *ht_cap_info; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET] = {0}; + uint8_t mcs_set_temp[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t val; + uint16_t val16; + uint8_t enable2x2; + + if ((nss == 2) && (hdd_ctx->num_rf_chains != 2)) { + hddLog(LOGE, "No support for 2 spatial streams"); + return CDF_STATUS_E_INVAL; + } + + enable2x2 = (nss == 1) ? 0 : 1; + + if (hdd_config->enable2x2 == enable2x2) { + hddLog(LOGE, "NSS same as requested"); + return CDF_STATUS_SUCCESS; + } + + if (true == sme_is_any_session_in_connected_state(hdd_ctx->hHal)) { + hddLog(LOGE, "Connected sessions present, Do not change NSS"); + return CDF_STATUS_E_INVAL; + } + + hdd_config->enable2x2 = enable2x2; + + if (!hdd_config->enable2x2) { + /* 1x1 */ + rx_supp_data_rate = HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + tx_supp_data_rate = HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } else { + /* 2x2 */ + rx_supp_data_rate = HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + tx_supp_data_rate = HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + } + + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + rx_supp_data_rate) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + tx_supp_data_rate) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, &temp); + val16 = (uint16_t)temp; + ht_cap_info = (tSirMacHTCapabilityInfo *)&val16; + if (!(hdd_ctx->ht_tx_stbc_supported && hdd_config->enable2x2)) + ht_cap_info->txSTBC = 0; + else + ht_cap_info->txSTBC = hdd_config->enableTxSTBC; + temp = val16; + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, + temp) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, "Could not pass on WNI_CFG_HT_CAP_INFO to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, + temp) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, + "Could not pass on WNI_CFG_VHT_BASIC_MCS_SET to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, + temp) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, "Could not pass on WNI_CFG_VHT_RX_MCS_MAP to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtTxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtTxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, + temp) == CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, "Could not pass on WNI_CFG_VHT_TX_MCS_MAP to CFG"); + } + +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + val = SIZE_OF_SUPPORTED_MCS_SET; + sme_cfg_get_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set_temp, &val); + + mcs_set[0] = mcs_set_temp[0]; + if (hdd_config->enable2x2) + for (val = 0; val < nss; val++) + mcs_set[val] = WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + if (sme_cfg_set_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET) == + CDF_STATUS_E_FAILURE) { + status = false; + hddLog(LOGE, "Could not pass on MCS SET to CFG"); + } +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES + + if (CDF_STATUS_SUCCESS != sme_update_nss(hdd_ctx->hHal, nss)) + status = false; + + return (status == false) ? CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS; +} diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c new file mode 100644 index 0000000000..9012628af8 --- /dev/null +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -0,0 +1,10706 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg80211.c + * + * WLAN Host Device Driver cfg80211 APIs implementation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_CNSS +#include +#endif +#include +#include +#include "sir_params.h" +#include "dot11f.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_wext.h" +#include "sme_api.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_hdd_softap_tx_rx.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_trace.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cds_utils.h" +#include "cds_sched.h" +#include "wlan_hdd_scan.h" +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_wmm.h" +#include "wma_types.h" +#include "wlan_hdd_misc.h" +#include "wlan_hdd_nan.h" +#include +#include "wlan_logging_sock_svc.h" + +#ifdef FEATURE_WLAN_EXTSCAN +#include "wlan_hdd_ext_scan.h" +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#include "wlan_hdd_stats.h" +#endif +#include "cds_concurrency.h" +#include "qwlan_version.h" +#include "wlan_hdd_memdump.h" + +#include "wlan_hdd_ocb.h" + +#define g_mode_rates_size (12) +#define a_mode_rates_size (8) +#define FREQ_BASE_80211G (2407) +#define FREQ_BAND_DIFF_80211G (5) +#define GET_IE_LEN_IN_BSS_DESC(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields))) + +/* + * Android CTS verifier needs atleast this much wait time (in msec) + */ +#define MAX_REMAIN_ON_CHANNEL_DURATION (5000) + +/* + * Refer @tCfgProtection structure for definition of the bit map. + * below value is obtained by setting the following bit-fields. + * enable obss, fromllb, overlapOBSS and overlapFromllb protection. + */ +#define IBSS_CFG_PROTECTION_ENABLE_MASK 0x8282 + +#define HDD2GHZCHAN(freq, chan, flag) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define HDD5GHZCHAN(freq, chan, flag) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define HDD_G_MODE_RATETAB(rate, rate_id, flag) \ + { \ + .bitrate = rate, \ + .hw_value = rate_id, \ + .flags = flag, \ + } + +#ifdef WLAN_FEATURE_VOWIFI_11R +#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03 +#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04 +#endif + +#define HDD_CHANNEL_14 14 +#define CONNECTION_UPDATE_TIMEOUT 500 + +static const u32 hdd_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, +#ifdef FEATURE_WLAN_ESE +#define WLAN_CIPHER_SUITE_BTK 0x004096fe /* use for BTK */ +#define WLAN_CIPHER_SUITE_KRK 0x004096ff /* use for KRK */ + WLAN_CIPHER_SUITE_BTK, + WLAN_CIPHER_SUITE_KRK, + WLAN_CIPHER_SUITE_CCMP, +#else + WLAN_CIPHER_SUITE_CCMP, +#endif +#ifdef FEATURE_WLAN_WAPI + WLAN_CIPHER_SUITE_SMS4, +#endif +#ifdef WLAN_FEATURE_11W + WLAN_CIPHER_SUITE_AES_CMAC, +#endif +}; + +static struct ieee80211_channel hdd_channels_2_4_ghz[] = { + HDD2GHZCHAN(2412, 1, 0), + HDD2GHZCHAN(2417, 2, 0), + HDD2GHZCHAN(2422, 3, 0), + HDD2GHZCHAN(2427, 4, 0), + HDD2GHZCHAN(2432, 5, 0), + HDD2GHZCHAN(2437, 6, 0), + HDD2GHZCHAN(2442, 7, 0), + HDD2GHZCHAN(2447, 8, 0), + HDD2GHZCHAN(2452, 9, 0), + HDD2GHZCHAN(2457, 10, 0), + HDD2GHZCHAN(2462, 11, 0), + HDD2GHZCHAN(2467, 12, 0), + HDD2GHZCHAN(2472, 13, 0), + HDD2GHZCHAN(2484, 14, 0), +}; + +static struct ieee80211_channel hdd_social_channels_2_4_ghz[] = { + HDD2GHZCHAN(2412, 1, 0), + HDD2GHZCHAN(2437, 6, 0), + HDD2GHZCHAN(2462, 11, 0), +}; + +static struct ieee80211_channel hdd_channels_5_ghz[] = { + HDD5GHZCHAN(4920, 240, 0), + HDD5GHZCHAN(4940, 244, 0), + HDD5GHZCHAN(4960, 248, 0), + HDD5GHZCHAN(4980, 252, 0), + HDD5GHZCHAN(5040, 208, 0), + HDD5GHZCHAN(5060, 212, 0), + HDD5GHZCHAN(5080, 216, 0), + HDD5GHZCHAN(5180, 36, 0), + HDD5GHZCHAN(5200, 40, 0), + HDD5GHZCHAN(5220, 44, 0), + HDD5GHZCHAN(5240, 48, 0), + HDD5GHZCHAN(5260, 52, 0), + HDD5GHZCHAN(5280, 56, 0), + HDD5GHZCHAN(5300, 60, 0), + HDD5GHZCHAN(5320, 64, 0), + HDD5GHZCHAN(5500, 100, 0), + HDD5GHZCHAN(5520, 104, 0), + HDD5GHZCHAN(5540, 108, 0), + HDD5GHZCHAN(5560, 112, 0), + HDD5GHZCHAN(5580, 116, 0), + HDD5GHZCHAN(5600, 120, 0), + HDD5GHZCHAN(5620, 124, 0), + HDD5GHZCHAN(5640, 128, 0), + HDD5GHZCHAN(5660, 132, 0), + HDD5GHZCHAN(5680, 136, 0), + HDD5GHZCHAN(5700, 140, 0), + HDD5GHZCHAN(5720, 144, 0), + HDD5GHZCHAN(5745, 149, 0), + HDD5GHZCHAN(5765, 153, 0), + HDD5GHZCHAN(5785, 157, 0), + HDD5GHZCHAN(5805, 161, 0), + HDD5GHZCHAN(5825, 165, 0), +#ifndef FEATURE_STATICALLY_ADD_11P_CHANNELS + HDD5GHZCHAN(5852, 170, 0), + HDD5GHZCHAN(5855, 171, 0), + HDD5GHZCHAN(5860, 172, 0), + HDD5GHZCHAN(5865, 173, 0), + HDD5GHZCHAN(5870, 174, 0), + HDD5GHZCHAN(5875, 175, 0), + HDD5GHZCHAN(5880, 176, 0), + HDD5GHZCHAN(5885, 177, 0), + HDD5GHZCHAN(5890, 178, 0), + HDD5GHZCHAN(5895, 179, 0), + HDD5GHZCHAN(5900, 180, 0), + HDD5GHZCHAN(5905, 181, 0), + HDD5GHZCHAN(5910, 182, 0), + HDD5GHZCHAN(5915, 183, 0), + HDD5GHZCHAN(5920, 184, 0), +#endif +}; + +static struct ieee80211_rate g_mode_rates[] = { + HDD_G_MODE_RATETAB(10, 0x1, 0), + HDD_G_MODE_RATETAB(20, 0x2, 0), + HDD_G_MODE_RATETAB(55, 0x4, 0), + HDD_G_MODE_RATETAB(110, 0x8, 0), + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_rate a_mode_rates[] = { + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_supported_band wlan_hdd_band_2_4_ghz = { + .channels = hdd_channels_2_4_ghz, + .n_channels = ARRAY_SIZE(hdd_channels_2_4_ghz), + .band = IEEE80211_BAND_2GHZ, + .bitrates = g_mode_rates, + .n_bitrates = g_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +}; + +static struct ieee80211_supported_band wlan_hdd_band_p2p_2_4_ghz = { + .channels = hdd_social_channels_2_4_ghz, + .n_channels = ARRAY_SIZE(hdd_social_channels_2_4_ghz), + .band = IEEE80211_BAND_2GHZ, + .bitrates = g_mode_rates, + .n_bitrates = g_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_LSIG_TXOP_PROT, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +}; + +static struct ieee80211_supported_band wlan_hdd_band_5_ghz = { + .channels = hdd_channels_5_ghz, + .n_channels = ARRAY_SIZE(hdd_channels_5_ghz), + .band = IEEE80211_BAND_5GHZ, + .bitrates = a_mode_rates, + .n_bitrates = a_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, + .vht_cap.vht_supported = 1, +}; + +/* This structure contain information what kind of frame are expected in + TX/RX direction for each kind of interface */ +static const struct ieee80211_txrx_stypes + wlan_hdd_txrx_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_PROBE_REQ), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_PROBE_REQ), + }, + [NL80211_IFTYPE_P2P_GO] = { + /* This is also same as for SoftAP */ + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +/* Interface limits and combinations registered by the driver */ + +/* STA ( + STA ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_iface_limit[] = { + { + .max = 3, /* p2p0 is a STA as well */ + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +/* ADHOC (IBSS) limit */ +static const struct ieee80211_iface_limit + wlan_hdd_adhoc_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +/* AP ( + AP ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_ap_iface_limit[] = { + { + .max = (CDF_MAX_NO_OF_SAP_MODE + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* P2P limit */ +static const struct ieee80211_iface_limit + wlan_hdd_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO), + }, +}; + +static const struct ieee80211_iface_limit + wlan_hdd_sta_ap_iface_limit[] = { + { + /* We need 1 extra STA interface for OBSS scan when SAP starts + * with HT40 in STA+SAP concurrency mode + */ + .max = (1 + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = CDF_MAX_NO_OF_SAP_MODE, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* STA + P2P combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_p2p_iface_limit[] = { + { + /* One reserved for dedicated P2PDEV usage */ + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* Support for two identical (GO + GO or CLI + CLI) + * or dissimilar (GO + CLI) P2P interfaces + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +/* STA + AP + P2PGO combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_p2pgo_iface_limit[] = { + /* Support for AP+P2PGO interfaces */ + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* SAP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sap_p2p_iface_limit[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* The p2p interface in SAP+P2P can be GO/CLI. + * The p2p connection can be formed on p2p0 or p2p-p2p0-x. + */ + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, + { + /* SAP+GO to support only one SAP interface */ + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* P2P + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_p2p_p2p_iface_limit[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* The p2p interface in P2P+P2P can be GO/CLI. + * For P2P+P2P, the new interfaces are formed on p2p-p2p0-x. + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, +}; + +static struct ieee80211_iface_combination + wlan_hdd_iface_combination[] = { + /* STA */ + { + .limits = wlan_hdd_sta_iface_limit, + .num_different_channels = 2, + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit), + }, + /* ADHOC */ + { + .limits = wlan_hdd_adhoc_iface_limit, + .num_different_channels = 1, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_adhoc_iface_limit), + }, + /* AP */ + { + .limits = wlan_hdd_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (SAP_MAX_OBSS_STA_CNT + CDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit), + }, + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + /* STA + AP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (1 + SAP_MAX_OBSS_STA_CNT + CDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P GO + SAP */ + { + .limits = wlan_hdd_sta_ap_p2pgo_iface_limit, + /* we can allow 3 channels for three different persona + * but due to firmware limitation, allow max 2 concrnt channels. + */ + .num_different_channels = 2, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2pgo_iface_limit), + .beacon_int_infra_match = true, + }, + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-p2p0 + 1-SAP + 1-P2P (on p2p0 or p2p-p2p0-x) */ + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* P2P + P2P */ + { + .limits = wlan_hdd_p2p_p2p_iface_limit, + .num_different_channels = 2, + /* 1-p2p0 + 2-P2P (on p2p-p2p0-x) */ + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */ + +static struct cfg80211_ops wlan_hdd_cfg80211_ops; + + +#ifdef WLAN_NL80211_TESTMODE +enum wlan_hdd_tm_attr { + WLAN_HDD_TM_ATTR_INVALID = 0, + WLAN_HDD_TM_ATTR_CMD = 1, + WLAN_HDD_TM_ATTR_DATA = 2, + WLAN_HDD_TM_ATTR_STREAM_ID = 3, + WLAN_HDD_TM_ATTR_TYPE = 4, + /* keep last */ + WLAN_HDD_TM_ATTR_AFTER_LAST, + WLAN_HDD_TM_ATTR_MAX = WLAN_HDD_TM_ATTR_AFTER_LAST - 1, +}; + +enum wlan_hdd_tm_cmd { + WLAN_HDD_TM_CMD_WLAN_FTM = 0, + WLAN_HDD_TM_CMD_WLAN_HB = 1, +}; + +#define WLAN_HDD_TM_DATA_MAX_LEN 5000 + +static const struct nla_policy wlan_hdd_tm_policy[WLAN_HDD_TM_ATTR_MAX + 1] = { + [WLAN_HDD_TM_ATTR_CMD] = {.type = NLA_U32}, + [WLAN_HDD_TM_ATTR_DATA] = {.type = NLA_BINARY, + .len = WLAN_HDD_TM_DATA_MAX_LEN}, +}; +#endif /* WLAN_NL80211_TESTMODE */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_cfg80211_init = { + .flags = WIPHY_WOWLAN_MAGIC_PKT, + .n_patterns = WOWL_MAX_PTRNS_ALLOWED, + .pattern_min_len = 1, + .pattern_max_len = WOWL_PTRN_MAX_SIZE, +}; +#endif + +#ifdef FEATURE_WLAN_TDLS + +/* TDLS capabilities params */ +#define PARAM_MAX_TDLS_SESSION \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS +#define PARAM_TDLS_FEATURE_SUPPORT \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED + +/** + * __wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + uint32_t set = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (2 * sizeof(u32)) + + NLMSG_HDRLEN); + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + goto fail; + } + + if (false == hdd_ctx->config->fEnableTDLSSupport) { + hddLog(LOGE, + FL("TDLS feature not Enabled or Not supported in FW")); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, 0) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, 0)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + } else { + set = set | WIFI_TDLS_SUPPORT; + set = set | (hdd_ctx->config->fTDLSExternalControl ? + WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT : 0); + set = set | (hdd_ctx->config->fEnableTDLSOffChannel ? + WIIF_TDLS_OFFCHANNEL_SUPPORT : 0); + hddLog(LOG1, FL("TDLS Feature supported value %x"), set); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, + hdd_ctx->max_num_tdls_sta) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, + set)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + } + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int +wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_tdls_capabilities(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef QCA_HT_2040_COEX +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +/* + * FUNCTION: wlan_hdd_send_avoid_freq_event + * This is called when wlan driver needs to send vendor specific + * avoid frequency range event to userspace + */ +int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx, + tHddAvoidFreqList *pAvoidFreqList) +{ + struct sk_buff *vendor_event; + + ENTER(); + + if (!pHddCtx) { + hddLog(LOGE, FL("HDD context is null")); + return -EINVAL; + } + + if (!pAvoidFreqList) { + hddLog(LOGE, FL("pAvoidFreqList is null")); + return -EINVAL; + } + + vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + sizeof(tHddAvoidFreqList), + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return -EINVAL; + } + + memcpy(skb_put(vendor_event, sizeof(tHddAvoidFreqList)), + (void *)pAvoidFreqList, sizeof(tHddAvoidFreqList)); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + EXIT(); + return 0; +} +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +/* vendor specific events */ +static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = { +#ifdef FEATURE_WLAN_CH_AVOID + [QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY + }, +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef WLAN_FEATURE_NAN + [QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_NAN + }, +#endif + +#ifdef WLAN_FEATURE_STATS_EXT + [QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT + }, +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + [QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE + }, + [QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + [QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH + }, +#endif + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED + }, +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI + }, +#ifdef WLAN_FEATURE_MEMDUMP + [QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP + }, +#endif /* WLAN_FEATURE_MEMDUMP */ + [QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE + }, + [QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN + }, + /* OCB events */ + [QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT + }, +}; + +/** + * __is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. + * + * Return: 0 on success, negative errno on failure + */ +static int __is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + u32 dfs_capability = 0; + struct sk_buff *temp_skbuff; + int ret_val; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)) + dfs_capability = !!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD); +#endif + + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + NLMSG_HDRLEN); + + if (temp_skbuff != NULL) { + ret_val = nla_put_u32(temp_skbuff, QCA_WLAN_VENDOR_ATTR_DFS, + dfs_capability); + if (ret_val) { + hddLog(LOGE, FL("QCA_WLAN_VENDOR_ATTR_DFS put fail")); + kfree_skb(temp_skbuff); + + return ret_val; + } + + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + + hddLog(LOGE, FL("dfs capability: buffer alloc fail")); + return -ENOMEM; +} + +/** + * is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. This is an SSR-protected + * wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +static int is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __is_driver_dfs_capable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_sap_cfg_dfs_override() - DFS MCC restriction check + * + * @adapter: SAP adapter pointer + * + * DFS in MCC is not supported for Multi bssid SAP mode due to single physical + * radio. So in case of DFS MCC scenario override current SAP given config + * to follow concurrent SAP DFS config + * + * Return: 0 - No DFS issue, 1 - Override done and negative error codes + */ + +#ifdef WLAN_FEATURE_MBSSID +int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter) +{ + hdd_adapter_t *con_sap_adapter; + tsap_Config_t *sap_config, *con_sap_config; + int con_ch; + + /* + * Check if AP+AP case, once primary AP chooses a DFS + * channel secondary AP should always follow primary APs channel + */ + if (!cds_concurrent_beaconing_sessions_running()) + return 0; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, true); + if (!con_sap_adapter) + return 0; + + sap_config = &adapter->sessionCtx.ap.sapConfig; + con_sap_config = &con_sap_adapter->sessionCtx.ap.sapConfig; + con_ch = con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (!CDS_IS_DFS_CH(con_ch)) + return 0; + + hddLog(LOGE, FL("Only SCC AP-AP DFS Permitted (ch=%d, con_ch=%d)"), + sap_config->channel, con_ch); + hddLog(LOG1, FL("Overriding guest AP's channel")); + sap_config->channel = con_ch; + + if (con_sap_config->acs_cfg.acs_mode == true) { + if (con_ch != con_sap_config->acs_cfg.pri_ch && + con_ch != con_sap_config->acs_cfg.ht_sec_ch) { + hddLog(LOGE, FL("Primary AP channel config error")); + hddLog(LOGE, FL("Operating ch: %d ACS ch: %d %d"), + con_ch, con_sap_config->acs_cfg.pri_ch, + con_sap_config->acs_cfg.ht_sec_ch); + return -EINVAL; + } + /* Sec AP ACS info is overwritten with Pri AP due to DFS + * MCC restriction. So free ch list allocated in do_acs + * func for Sec AP and realloc for Pri AP ch list size + */ + if (sap_config->acs_cfg.ch_list) + cdf_mem_free(sap_config->acs_cfg.ch_list); + + cdf_mem_copy(&sap_config->acs_cfg, + &con_sap_config->acs_cfg, + sizeof(struct sap_acs_cfg)); + sap_config->acs_cfg.ch_list = cdf_mem_malloc( + sizeof(uint8_t) * + con_sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list) { + hddLog(LOGE, FL("ACS config alloc fail")); + return -ENOMEM; + } + + cdf_mem_copy(sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list_count); + + } else { + sap_config->acs_cfg.pri_ch = con_ch; + if (sap_config->acs_cfg.ch_width > eHT_CHANNEL_WIDTH_20MHZ) + sap_config->acs_cfg.ht_sec_ch = con_sap_config->sec_ch; + } + + return con_ch; +} +#else +int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter) +{ + return 0; +} +#endif + +/** + * wlan_hdd_set_acs_ch_range : Start ACS channel range values + * @sap_cfg: pointer to SAP config struct + * + * This function sets the default ACS start and end channel for the given band + * and also parses the given ACS channel list. + * + * Return: None + */ + +static void wlan_hdd_set_acs_ch_range(tsap_Config_t *sap_cfg, bool ht_enabled, + bool vht_enabled) +{ + int i; + if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211B) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11b; + sap_cfg->acs_cfg.start_ch = rf_channels[RF_CHAN_1].channelNum; + sap_cfg->acs_cfg.end_ch = rf_channels[RF_CHAN_14].channelNum; + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211G) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11g; + sap_cfg->acs_cfg.start_ch = rf_channels[RF_CHAN_1].channelNum; + sap_cfg->acs_cfg.end_ch = rf_channels[RF_CHAN_13].channelNum; + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211A) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11a; + sap_cfg->acs_cfg.start_ch = rf_channels[RF_CHAN_36].channelNum; + sap_cfg->acs_cfg.end_ch = rf_channels[RF_CHAN_165].channelNum; + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211ANY) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_abg; + sap_cfg->acs_cfg.start_ch = rf_channels[RF_CHAN_1].channelNum; + sap_cfg->acs_cfg.end_ch = rf_channels[RF_CHAN_165].channelNum; + } + + if (ht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11n; + + if (vht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + + + /* Parse ACS Chan list from hostapd */ + if (!sap_cfg->acs_cfg.ch_list) + return; + + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[0]; + sap_cfg->acs_cfg.end_ch = + sap_cfg->acs_cfg.ch_list[sap_cfg->acs_cfg.ch_list_count - 1]; + for (i = 0; i < sap_cfg->acs_cfg.ch_list_count; i++) { + if (sap_cfg->acs_cfg.start_ch > sap_cfg->acs_cfg.ch_list[i]) + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[i]; + if (sap_cfg->acs_cfg.end_ch < sap_cfg->acs_cfg.ch_list[i]) + sap_cfg->acs_cfg.end_ch = sap_cfg->acs_cfg.ch_list[i]; + } +} + + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); + +/** + * wlan_hdd_cfg80211_start_acs : Start ACS Procedure for SAP + * @adapter: pointer to SAP adapter struct + * + * This function starts the ACS procedure if there are no + * constraints like MBSSID DFS restrictions. + * + * Return: Status of ACS Start procedure + */ + +static int wlan_hdd_cfg80211_start_acs(hdd_adapter_t *adapter) +{ + + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tsap_Config_t *sap_config; + tpWLAN_SAPEventCB acs_event_callback; + int status; + + sap_config = &adapter->sessionCtx.ap.sapConfig; + sap_config->channel = AUTO_CHANNEL_SELECT; + + status = wlan_hdd_sap_cfg_dfs_override(adapter); + if (status < 0) { + return status; + } else { + if (status > 0) { + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + return 0; + } + } + status = wlan_hdd_config_acs(hdd_ctx, adapter); + if (status) { + hddLog(LOGE, FL("ACS config failed")); + return -EINVAL; + } + + acs_event_callback = hdd_hostapd_sap_event_cb; + + cdf_mem_copy(sap_config->self_macaddr.bytes, + adapter->macAddressCurrent.bytes, sizeof(struct cdf_mac_addr)); + hddLog(LOG1, FL("ACS Started for wlan%d"), adapter->dev->ifindex); + status = wlansap_acs_chselect( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR(adapter), +#else + hdd_ctx->pcds_context, +#endif + acs_event_callback, sap_config, adapter->dev); + + + if (status) { + hddLog(LOGE, FL("ACS channel select failed")); + return -EINVAL; + } + sap_config->acs_cfg.acs_mode = true; + set_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information length + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ + +static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + tsap_Config_t *sap_config; + struct sk_buff *temp_skbuff; + int status = -EINVAL, i = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; + bool ht_enabled, ht40_enabled, vht_enabled; + uint8_t ch_width; + + /* ***Note*** Donot set SME config related to ACS operation here because + * ACS operation is not synchronouse and ACS for Second AP may come when + * ACS operation for first AP is going on. So only do_acs is split to + * seperate start_acs routine. Also SME-PMAC struct that is used to + * pass paremeters from HDD to SAP is global. Thus All ACS related SME + * config shall be set only from start_acs. + */ + + /* nla_policy Policy template. Policy not applied as some attributes are + * optional and QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST has variable length + * + * [QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 }, + * [QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG }, + * [QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG }, + * [QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG }, + * [QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 }, + * [QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_NESTED }, + */ + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_ctx->config->force_sap_acs) { + hddLog(LOGE, FL("Hostapd ACS rejected as Driver ACS enabled")); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + goto out; + } + sap_config = &adapter->sessionCtx.ap.sapConfig; + cdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg)); + + status = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, data_len, + NULL); + if (status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); + goto out; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Attr hw_mode failed")); + goto out; + } + sap_config->acs_cfg.hw_mode = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]) + ht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]); + else + ht_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]) + ht40_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]); + else + ht40_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]) + vht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]); + else + vht_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) { + ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + } else { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + } + if (ch_width == 80) + sap_config->acs_cfg.ch_width = CH_WIDTH_80MHZ; + else if (ch_width == 40) + sap_config->acs_cfg.ch_width = CH_WIDTH_40MHZ; + else + sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; + + /* hw_mode = a/b/g: QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST and + * QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attrs are present, and + * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is used for obtaining the + * channel list, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST is ignored + * since it contains the frequency values of the channels in + * the channel list. + * hw_mode = any: only QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attr + * is present + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) { + char *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.ch_list = cdf_mem_malloc( + sizeof(uint8_t) * + sap_config->acs_cfg.ch_list_count); + if (sap_config->acs_cfg.ch_list == NULL) + goto out; + + cdf_mem_copy(sap_config->acs_cfg.ch_list, tmp, + sap_config->acs_cfg.ch_list_count); + } + } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) { + uint32_t *freq = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]); + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) / + sizeof(uint32_t); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.ch_list = cdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + if (sap_config->acs_cfg.ch_list == NULL) { + hddLog(LOGE, FL("ACS config alloc fail")); + status = -ENOMEM; + goto out; + } + + /* convert frequency to channel */ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + sap_config->acs_cfg.ch_list[i] = + ieee80211_frequency_to_channel(freq[i]); + } + } + + hdd_debug("get pcl for DO_ACS vendor command"); + + /* consult policy manager to get PCL */ + status = cds_get_pcl(hdd_ctx, CDS_SAP_MODE, + sap_config->acs_cfg.pcl_channels, + &sap_config->acs_cfg.pcl_ch_count); + if (CDF_STATUS_SUCCESS != status) + hddLog(LOGE, FL("Get PCL failed")); + + wlan_hdd_set_acs_ch_range(sap_config, ht_enabled, vht_enabled); + + /* ACS override for android */ + if (hdd_ctx->config->sap_p2p_11ac_override && ht_enabled) { + hddLog(LOG1, FL("ACS Config override for 11AC")); + vht_enabled = 1; + sap_config->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + sap_config->acs_cfg.ch_width = + hdd_ctx->config->vhtChannelWidth; + /* No VHT80 in 2.4G so perform ACS accordingly */ + if (sap_config->acs_cfg.end_ch <= 14 && + sap_config->acs_cfg.ch_width == eHT_CHANNEL_WIDTH_80MHZ) + sap_config->acs_cfg.ch_width = eHT_CHANNEL_WIDTH_40MHZ; + } + + hddLog(LOG1, FL("ACS Config for wlan%d: HW_MODE: %d ACS_BW: %d HT: %d VHT: %d START_CH: %d END_CH: %d"), + adapter->dev->ifindex, sap_config->acs_cfg.hw_mode, + ch_width, ht_enabled, vht_enabled, + sap_config->acs_cfg.start_ch, sap_config->acs_cfg.end_ch); + + if (sap_config->acs_cfg.ch_list_count) { + hddLog(LOG1, FL("ACS channel list: len: %d"), + sap_config->acs_cfg.ch_list_count); + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + hddLog(LOG1, "%d ", sap_config->acs_cfg.ch_list[i]); + } + sap_config->acs_cfg.acs_mode = true; + if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { + /* ***Note*** Completion variable usage is not allowed here since + * ACS scan operation may take max 2.2 sec for 5G band. + * 9 Active channel X 40 ms active scan time + + * 16 Passive channel X 110ms passive scan time + * Since this CFG80211 call lock rtnl mutex, we cannot hold on + * for this long. So we split up the scanning part. + */ + set_bit(ACS_PENDING, &adapter->event_flags); + hddLog(LOG1, FL("ACS Pending for wlan%d"), + adapter->dev->ifindex); + status = 0; + } else { + status = wlan_hdd_cfg80211_start_acs(adapter); + } + +out: + if (0 == status) { + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + NLMSG_HDRLEN); + if (temp_skbuff != NULL) + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + return status; +} + + /** + * wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information len + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ + +static int wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_start_pending_acs : Start pending ACS procedure for SAP + * @work: Linux workqueue struct pointer for ACS work + * + * This function starts the ACS procedure which was marked pending when an ACS + * procedure was in progress for a concurrent SAP interface. + * + * Return: None + */ + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work) +{ + hdd_adapter_t *adapter = container_of(work, hdd_adapter_t, + acs_pending_work.work); + wlan_hdd_cfg80211_start_acs(adapter); +} + +/** + * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt + * @adapter: Pointer to SAP adapter struct + * @pri_channel: SAP ACS procedure selected Primary channel + * @sec_channel: SAP ACS procedure selected secondary channel + * + * This is a callback function from SAP module on ACS procedure is completed. + * This function send the ACS selected channel information to hostapd + * + * Return: None + */ + +void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tsap_Config_t *sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(adapter))->sapConfig; + struct sk_buff *vendor_event; + int ret_val; + hdd_adapter_t *con_sap_adapter; + uint16_t ch_width; + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + 4 * sizeof(u8) + 1 * sizeof(u16) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + ret_val = hdd_vendor_put_ifindex(vendor_event, adapter->dev->ifindex); + if (ret_val) { + hddLog(LOGE, FL("NL80211_ATTR_IFINDEX put fail")); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + sap_cfg->acs_cfg.pri_ch); + if (ret_val) { + hddLog(LOGE, + FL("QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail")); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + sap_cfg->acs_cfg.ht_sec_ch); + if (ret_val) { + hddLog(LOGE, + FL( + "QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail")); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg0_center_ch); + if (ret_val) { + hddLog(LOGE, + FL( + "QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL put fail")); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg1_center_ch); + if (ret_val) { + hddLog(LOGE, + FL( + "QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL put fail")); + kfree_skb(vendor_event); + return; + } + + if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_80MHZ) + ch_width = 80; + else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_40MHZ) + ch_width = 40; + else + ch_width = 20; + + ret_val = nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + ch_width); + if (ret_val) { + hddLog(LOGE, + FL( + "QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH put fail")); + kfree_skb(vendor_event); + return; + } + if (sap_cfg->acs_cfg.pri_ch > 14) + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211A); + else + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211G); + + if (ret_val) { + hddLog(LOGE, + FL( + "QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail")); + kfree_skb(vendor_event); + return; + } + + hddLog(LOG1, + FL("ACS result for wlan%d: PRI_CH: %d SEC_CH: %d VHT_SEG0: %d VHT_SEG1: %d ACS_BW: %d"), + adapter->dev->ifindex, sap_cfg->acs_cfg.pri_ch, + sap_cfg->acs_cfg.ht_sec_ch, sap_cfg->acs_cfg.vht_seg0_center_ch, + sap_cfg->acs_cfg.vht_seg1_center_ch, ch_width); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + /* ***Note*** As already mentioned Completion variable usage is not + * allowed here since ACS scan operation may take max 2.2 sec. + * Further in AP-AP mode pending ACS is resumed here to serailize ACS + * operation. + * TODO: Delayed operation is used since SME-PMAC strut is global. Thus + * when Primary AP ACS is complete and secondary AP ACS is started here + * immediately, Primary AP start_bss may come inbetween ACS operation + * and overwrite Sec AP ACS paramters. Thus Sec AP ACS is executed with + * delay. This path and below constraint will be removed on sessionizing + * SAP acs parameters and decoupling SAP from PMAC (WIP). + * As per design constraint user space control application must take + * care of serailizing hostapd start for each VIF in AP-AP mode to avoid + * this code path. Sec AP hostapd should be started after Primary AP + * start beaconing which can be confirmed by getchannel iwpriv command + */ + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + if (con_sap_adapter && + test_bit(ACS_PENDING, &con_sap_adapter->event_flags)) { +#ifdef CONFIG_CNSS + cnss_init_delayed_work(&con_sap_adapter->acs_pending_work, + wlan_hdd_cfg80211_start_pending_acs); +#else + INIT_DELAYED_WORK(&con_sap_adapter->acs_pending_work, + wlan_hdd_cfg80211_start_pending_acs); +#endif + /* Lets give 500ms for OBSS + START_BSS to complete */ + schedule_delayed_work(&con_sap_adapter->acs_pending_work, + msecs_to_jiffies(500)); + clear_bit(ACS_PENDING, &con_sap_adapter->event_flags); + } + + return; +} + +static int +__wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct sk_buff *skb = NULL; + uint32_t fset = 0; + int ret; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("Hdd context not valid")); + return -EINVAL; + } + + if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { + hddLog(LOG1, FL("Infra Station mode is supported by driver")); + fset |= WIFI_FEATURE_INFRA; + } + if (true == hdd_is_5g_supported(pHddCtx)) { + hddLog(LOG1, FL("INFRA_5G is supported by firmware")); + fset |= WIFI_FEATURE_INFRA_5G; + } +#ifdef WLAN_FEATURE_P2P + if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) && + (wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO))) { + hddLog(LOG1, FL("WiFi-Direct is supported by driver")); + fset |= WIFI_FEATURE_P2P; + } +#endif + fset |= WIFI_FEATURE_SOFT_AP; + + /* HOTSPOT is a supplicant feature, enable it by default */ + fset |= WIFI_FEATURE_HOTSPOT; + +#ifdef FEATURE_WLAN_EXTSCAN + if (sme_is_feature_supported_by_fw(EXTENDED_SCAN)) { + hddLog(LOG1, FL("EXTScan is supported by firmware")); + fset |= WIFI_FEATURE_EXTSCAN | WIFI_FEATURE_HAL_EPNO; + } +#endif + if (wlan_hdd_nan_is_supported()) { + hddLog(LOG1, FL("NAN is supported by firmware")); + fset |= WIFI_FEATURE_NAN; + } + if (sme_is_feature_supported_by_fw(RTT)) { + hddLog(LOG1, FL("RTT is supported by firmware")); + fset |= WIFI_FEATURE_D2D_RTT; + fset |= WIFI_FEATURE_D2AP_RTT; + } +#ifdef FEATURE_WLAN_SCAN_PNO + if (pHddCtx->config->configPNOScanSupport && + sme_is_feature_supported_by_fw(PNO)) { + hddLog(LOG1, FL("PNO is supported by firmware")); + fset |= WIFI_FEATURE_PNO; + } +#endif + fset |= WIFI_FEATURE_ADDITIONAL_STA; +#ifdef FEATURE_WLAN_TDLS + if ((true == pHddCtx->config->fEnableTDLSSupport) && + sme_is_feature_supported_by_fw(TDLS)) { + hddLog(LOG1, FL("TDLS is supported by firmware")); + fset |= WIFI_FEATURE_TDLS; + } + if (sme_is_feature_supported_by_fw(TDLS) && + (true == pHddCtx->config->fEnableTDLSOffChannel) && + sme_is_feature_supported_by_fw(TDLS_OFF_CHANNEL)) { + hddLog(LOG1, FL("TDLS off-channel is supported by firmware")); + fset |= WIFI_FEATURE_TDLS_OFFCHANNEL; + } +#endif +#ifdef WLAN_AP_STA_CONCURRENCY + fset |= WIFI_FEATURE_AP_STA; +#endif + fset |= WIFI_FEATURE_RSSI_MONITOR; + + if (hdd_link_layer_stats_supported()) + fset |= WIFI_FEATURE_LINK_LAYER_STATS; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) + + NLMSG_HDRLEN); + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -EINVAL; + } + hddLog(LOG1, FL("Supported Features : 0x%x"), fset); + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_SET, fset)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + return cfg80211_vendor_cmd_reply(skb); +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_supported_features() - get supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_supported_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC address that is to be used for scanning. + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tpSirScanMacOui pReqMsg = NULL; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX + 1]; + CDF_STATUS status; + int ret; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (false == pHddCtx->config->enable_mac_spoofing) { + hddLog(LOGW, FL("MAC address spoofing is not enabled")); + return -ENOTSUPP; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX, + data, data_len, NULL)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) { + hddLog(LOGE, FL("attr mac oui failed")); + goto fail; + } + nla_memcpy(&pReqMsg->oui[0], + tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI], + sizeof(pReqMsg->oui)); + hddLog(LOG1, FL("Oui (%02x:%02x:%02x)"), pReqMsg->oui[0], + pReqMsg->oui[1], pReqMsg->oui[2]); + status = sme_set_scanning_mac_oui(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("sme_set_scanning_mac_oui failed(err=%d)"), status); + goto fail; + } + return 0; +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC address that is to be used for scanning. This is an + * SSR-protecting wrapper function. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_scanning_mac_oui(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_feature() - Set the bitmask for supported features + * @feature_flags: pointer to the byte array of features. + * @feature: Feature to be turned ON in the byte array. + * + * Return: None + * + * This is called to turn ON or SET the feature flag for the requested feature. + **/ +#define NUM_BITS_IN_BYTE 8 +void wlan_hdd_cfg80211_set_feature(uint8_t *feature_flags, uint8_t feature) +{ + uint32_t index; + uint8_t bit_mask; + + index = feature / NUM_BITS_IN_BYTE; + bit_mask = 1 << (feature % NUM_BITS_IN_BYTE); + feature_flags[index] |= bit_mask; +} + +/** + * __wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + **/ +#define MAX_CONCURRENT_CHAN_ON_24G 2 +#define MAX_CONCURRENT_CHAN_ON_5G 2 +static int +__wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct sk_buff *skb = NULL; + uint32_t dbs_capability = 0; + bool one_by_one_dbs, two_by_two_dbs; + CDF_STATUS ret = CDF_STATUS_E_FAILURE; + int ret_val; + + uint8_t feature_flags[(NUM_QCA_WLAN_VENDOR_FEATURES + 7) / 8] = {0}; + hdd_context_t *hdd_ctx_ptr = wiphy_priv(wiphy); + + ret_val = wlan_hdd_validate_context(hdd_ctx_ptr); + if (ret_val) + return ret_val; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_ctx_ptr->config->isRoamOffloadEnabled) { + hddLog(LOG1, FL("Key Mgmt Offload is supported")); + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD); + } + + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY); + if (wma_is_scan_simultaneous_capable()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS); + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(feature_flags) + + NLMSG_HDRLEN); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS, + sizeof(feature_flags), feature_flags)) + goto nla_put_failure; + + ret = wma_get_dbs_hw_modes(&one_by_one_dbs, &two_by_two_dbs); + if (CDF_STATUS_SUCCESS == ret) { + if (one_by_one_dbs) + dbs_capability = DRV_DBS_CAPABILITY_1X1; + + if (two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_2X2; + + if (!one_by_one_dbs && !two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } else { + hdd_err("wma_get_dbs_hw_mode failed"); + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } + + hdd_info("dbs_capability is %d", dbs_capability); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND, + MAX_CONCURRENT_CHAN_ON_24G)) + goto nla_put_failure; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND, + MAX_CONCURRENT_CHAN_ON_5G)) + goto nla_put_failure; + + return cfg80211_vendor_cmd_reply(skb); + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __wlan_hdd_cfg80211_set_ext_roam_params() - Settings for roaming parameters + * @wiphy: The wiphy structure + * @wdev: The wireless device + * @data: Data passed by framework + * @data_len: Parameters to be configured passed as data + * + * The roaming related parameters are configured by the framework + * using this interface. + * + * Return: Return either success or failure code. + */ +static int +__wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + uint8_t session_id; + struct roam_ext_params roam_params; + uint32_t cmd_type, req_id; + struct nlattr *curr_attr; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1]; + int rem, i; + uint32_t buf_len = 0; + int ret; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + data, data_len, + NULL)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + /* Parse and fetch Command Type*/ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]) { + hddLog(LOGE, FL("roam cmd type failed")); + goto fail; + } + session_id = pAdapter->sessionId; + cdf_mem_set(&roam_params, sizeof(roam_params), 0); + cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]); + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + req_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Req Id (%d)"), req_id); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Cmd Type (%d)"), cmd_type); + switch (cmd_type) { + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST: + i = 0; + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST], + rem) { + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX, + nla_data(curr_attr), nla_len(curr_attr), + NULL)) { + hddLog(LOGE, + FL("nla_parse failed")); + goto fail; + } + /* Parse and Fetch allowed SSID list*/ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID]) { + hddLog(LOGE, FL("attr allowed ssid failed")); + goto fail; + } + buf_len = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID]); + /* + * Upper Layers include a null termination character. + * Check for the actual permissible length of SSID and + * also ensure not to copy the NULL termination + * character to the driver buffer. + */ + if (buf_len && (i < MAX_SSID_ALLOWED_LIST) && + ((buf_len - 1) <= SIR_MAC_MAX_SSID_LENGTH)) { + nla_memcpy( + roam_params.ssid_allowed_list[i].ssId, + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID], + buf_len - 1); + roam_params.ssid_allowed_list[i].length = + buf_len - 1; + hddLog(CDF_TRACE_LEVEL_DEBUG, + FL("SSID[%d]: %.*s,length = %d"), i, + roam_params.ssid_allowed_list[i].length, + roam_params.ssid_allowed_list[i].ssId, + roam_params.ssid_allowed_list[i].length); + i++; + } else { + hddLog(LOGE, FL("Invalid buffer length")); + } + } + roam_params.num_ssid_allowed_list = i; + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of Allowed SSID %d"), + roam_params.num_ssid_allowed_list); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_SSID_ALLOWED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS: + /* Parse and fetch 5G Boost Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]) { + hddLog(LOGE, FL("5G boost threshold failed")); + goto fail; + } + roam_params.raise_rssi_thresh_5g = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Boost Threshold (%d)"), + roam_params.raise_rssi_thresh_5g); + /* Parse and fetch 5G Penalty Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]) { + hddLog(LOGE, FL("5G penalty threshold failed")); + goto fail; + } + roam_params.drop_rssi_thresh_5g = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Penalty Threshold (%d)"), + roam_params.drop_rssi_thresh_5g); + /* Parse and fetch 5G Boost Factor */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]) { + hddLog(LOGE, FL("5G boost Factor failed")); + goto fail; + } + roam_params.raise_factor_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Boost Factor (%d)"), + roam_params.raise_factor_5g); + /* Parse and fetch 5G Penalty factor */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]) { + hddLog(LOGE, FL("5G Penalty Factor failed")); + goto fail; + } + roam_params.drop_factor_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Penalty factor (%d)"), + roam_params.drop_factor_5g); + /* Parse and fetch 5G Max Boost */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]) { + hddLog(LOGE, FL("5G Max Boost failed")); + goto fail; + } + roam_params.max_raise_rssi_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Max Boost (%d)"), + roam_params.max_raise_rssi_5g); + /* Parse and fetch Rssi Diff */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]) { + hddLog(LOGE, FL("Rssi Diff failed")); + goto fail; + } + roam_params.rssi_diff = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("RSSI Diff (%d)"), + roam_params.rssi_diff); + /* Parse and fetch Alert Rssi Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]) { + hddLog(LOGE, FL("Alert Rssi Threshold failed")); + goto fail; + } + roam_params.alert_rssi_threshold = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Alert RSSI Threshold (%d)"), + roam_params.alert_rssi_threshold); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, + REASON_ROAM_EXT_SCAN_PARAMS_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM: + /* Parse and fetch Activate Good Rssi Roam */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]) { + hddLog(LOGE, FL("Activate Good Rssi Roam failed")); + goto fail; + } + roam_params.good_rssi_roam = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Activate Good Rssi Roam (%d)"), + roam_params.good_rssi_roam); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_GOOD_RSSI_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS: + /* Parse and fetch number of preferred BSSID */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]) { + hddLog(LOGE, FL("attr num of preferred bssid failed")); + goto fail; + } + roam_params.num_bssid_favored = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of Preferred BSSID (%d)"), + roam_params.num_bssid_favored); + i = 0; + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS], + rem) { + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), nla_len(curr_attr), + NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID]) { + hddLog(LOGE, FL("attr mac address failed")); + goto fail; + } + nla_memcpy(roam_params.bssid_favored[i], + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID], + sizeof(tSirMacAddr)); + hddLog(CDF_TRACE_LEVEL_DEBUG, MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_params.bssid_favored[i])); + /* Parse and fetch preference factor*/ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]) { + hddLog(LOGE, FL("BSSID Preference score failed")); + goto fail; + } + roam_params.bssid_favored_factor[i] = nla_get_u32( + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("BSSID Preference score (%d)"), + roam_params.bssid_favored_factor[i]); + i++; + } + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_FAVORED_BSSID); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID: + /* Parse and fetch number of blacklist BSSID */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]) { + hddLog(LOGE, FL("attr num of blacklist bssid failed")); + goto fail; + } + roam_params.num_bssid_avoid_list = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]); + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of blacklist BSSID (%d)"), + roam_params.num_bssid_avoid_list); + i = 0; + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS], + rem) { + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), nla_len(curr_attr), + NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID]) { + hddLog(LOGE, FL("attr blacklist addr failed")); + goto fail; + } + nla_memcpy(roam_params.bssid_avoid_list[i], + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID], + sizeof(tSirMacAddr)); + hddLog(CDF_TRACE_LEVEL_DEBUG, MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + roam_params.bssid_avoid_list[i])); + i++; + } + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_BLACKLIST_BSSID); + break; + } + return 0; +fail: + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_ext_roam_params() - set ext scan roam params + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ext_roam_params(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy +wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + +1] = { + [QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG] = {.type = NLA_U32 }, +}; + +/** + * wlan_hdd_check_dfs_channel_for_adapter() - check dfs channel in adapter + * @hdd_ctx: HDD context + * @device_mode: device mode + * Return: bool + */ +static bool wlan_hdd_check_dfs_channel_for_adapter(hdd_context_t *hdd_ctx, + device_mode_t device_mode) +{ + hdd_adapter_t *adapter; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_ap_ctx_t *ap_ctx; + hdd_station_ctx_t *sta_ctx; + CDF_STATUS cdf_status; + + cdf_status = hdd_get_front_adapter(hdd_ctx, + &adapter_node); + + while ((NULL != adapter_node) && + (CDF_STATUS_SUCCESS == cdf_status)) { + adapter = adapter_node->pAdapter; + + if ((device_mode == adapter->device_mode) && + (device_mode == WLAN_HDD_SOFTAP)) { + ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + + /* + * if there is SAP already running on DFS channel, + * do not disable scan on dfs channels. Note that + * with SAP on DFS, there cannot be conurrency on + * single radio. But then we can have multiple + * radios !! + */ + if (CHANNEL_STATE_DFS == + cds_get_channel_state( + ap_ctx->operatingChannel)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SAP running on DFS channel")); + return true; + } + } + + if ((device_mode == adapter->device_mode) && + (device_mode == WLAN_HDD_INFRA_STATION)) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* + * if STA is already connected on DFS channel, + * do not disable scan on dfs channels + */ + if (hdd_conn_is_connected(sta_ctx) && + (CHANNEL_STATE_DFS == + cds_get_channel_state( + sta_ctx->conn_info.operationChannel))) { + hddLog(LOGE, + FL("client connected on DFS channel")); + return true; + } + } + + cdf_status = hdd_get_next_adapter(hdd_ctx, + adapter_node, + &next); + adapter_node = next; + } + + return false; +} + +/** + * __wlan_hdd_cfg80211_disable_dfs_chan_scan() - DFS channel configuration + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * Return: success(0) or reason code for failure + */ +static int __wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle h_hal = WLAN_HDD_GET_HAL_CTX(adapter); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1]; + CDF_STATUS status; + int ret_val = -EPERM; + uint32_t no_dfs_flag = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX, + data, data_len, + wlan_hdd_set_no_dfs_flag_config_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("invalid attr")); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr dfs flag failed")); + return -EINVAL; + } + + no_dfs_flag = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]); + + hddLog(CDF_TRACE_LEVEL_INFO, FL(" DFS flag = %d"), + no_dfs_flag); + + if (no_dfs_flag > 1) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("invalid value of dfs flag")); + return -EINVAL; + } + + if (no_dfs_flag == hdd_ctx->config->enableDFSChnlScan) { + if (no_dfs_flag) { + status = wlan_hdd_check_dfs_channel_for_adapter( + hdd_ctx, WLAN_HDD_INFRA_STATION); + + if (true == status) + return -EOPNOTSUPP; + + status = wlan_hdd_check_dfs_channel_for_adapter( + hdd_ctx, WLAN_HDD_SOFTAP); + + if (true == status) + return -EOPNOTSUPP; + } + + hdd_ctx->config->enableDFSChnlScan = !no_dfs_flag; + + hdd_abort_mac_scan_all_adapters(hdd_ctx); + + /* + * call the SME API to tunnel down the new channel list + * to the firmware + */ + status = sme_handle_dfs_chan_scan( + h_hal, hdd_ctx->config->enableDFSChnlScan); + + if (CDF_STATUS_SUCCESS == status) { + ret_val = 0; + + /* + * Clear the SME scan cache also. Note that the + * clearing of scan results is independent of session; + * so no need to iterate over + * all sessions + */ + status = sme_scan_flush_result(h_hal); + if (CDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + } else { + hddLog(CDF_TRACE_LEVEL_INFO, + FL(" the DFS flag has not changed")); + ret_val = 0; + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_disable_dfs_chan_scan () - DFS scan vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendof command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX. Validate it and + * call wlan_hdd_disable_dfs_chan_scan to send it to firmware. + * + * Return: EOK or other error codes. + */ + +static int wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disable_dfs_chan_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * __wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int __wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + uint8_t local_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *hdd_adapter_ptr = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx_ptr; + int status; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if ((data == NULL) || (data_len == 0) || + (data_len > SIR_ROAM_SCAN_PSK_SIZE)) { + hddLog(LOGE, FL("Invalid data")); + return -EINVAL; + } + + hdd_ctx_ptr = WLAN_HDD_GET_CTX(hdd_adapter_ptr); + if (!hdd_ctx_ptr) { + hddLog(LOGE, FL("HDD context is null")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx_ptr); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return status; + } + sme_update_roam_key_mgmt_offload_enabled(hdd_ctx_ptr->hHal, + hdd_adapter_ptr->sessionId, + true); + cdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE); + cdf_mem_copy(local_pmk, data, data_len); + sme_roam_set_psk_pmk(WLAN_HDD_GET_HAL_CTX(hdd_adapter_ptr), + hdd_adapter_ptr->sessionId, local_pmk, data_len); + return 0; +} + +/** + * wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_keymgmt_set_key(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy qca_wlan_vendor_get_wifi_info_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; + tSirVersionString version; + uint32_t version_len; + uint32_t major_spid = 0, minor_spid = 0, siid = 0, crmid = 0; + uint8_t attr; + int status; + struct sk_buff *reply_skb = NULL; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, data, + data_len, qca_wlan_vendor_get_wifi_info_policy)) { + hddLog(LOGE, FL("WIFI_INFO_GET NL CMD parsing failed")); + return -EINVAL; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + hddLog(LOG1, FL("Rcvd req for Driver version")); + strlcpy(version, QWLAN_VERSIONSTR, sizeof(version)); + attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION; + } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + hddLog(LOG1, FL("Rcvd req for FW version")); + hdd_get_fw_version(hdd_ctx, &major_spid, &minor_spid, &siid, + &crmid); + snprintf(version, sizeof(version), "%d:%d:%d:%d", + major_spid, minor_spid, siid, crmid); + attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION; + } else { + hddLog(LOGE, FL("Invalid attribute in get wifi info request")); + return -EINVAL; + } + + version_len = strlen(version); + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + version_len + NLA_HDRLEN + NLMSG_HDRLEN); + if (!reply_skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (nla_put(reply_skb, attr, version_len, version)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wifi_info(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int status; + uint32_t features; + struct sk_buff *reply_skb = NULL; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + features = 0; + + if (hdd_is_memdump_supported()) + features |= WIFI_LOGGER_MEMORY_DUMP_SUPPORTED; + features |= WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED; + features |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED; + features |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED; + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN); + if (!reply_skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + hddLog(LOG1, FL("Supported logger features: 0x%0x"), features); + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED, + features)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_logger_supp_feature(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event + * @hdd_ctx_ptr: pointer to HDD Context. + * @bssid: pointer to bssid of roamed AP. + * @req_rsn_ie: Pointer to request RSN IE + * @req_rsn_len: Length of the request RSN IE + * @rsp_rsn_ie: Pointer to response RSN IE + * @rsp_rsn_len: Length of the response RSN IE + * @roam_info_ptr: Pointer to the roaming related information + * + * This is called when wlan driver needs to send the roaming and + * authorization information after roaming. + * + * The information that would be sent is the request RSN IE, response + * RSN IE and BSSID of the newly roamed AP. + * + * If the Authorized status is authenticated, then additional parameters + * like PTK's KCK and KEK and Replay Counter would also be passed to the + * supplicant. + * + * The supplicant upon receiving this event would ignore the legacy + * cfg80211_roamed call and use the entire information from this event. + * The cfg80211_roamed should still co-exist since the kernel will + * make use of the parameters even if the supplicant ignores it. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_send_roam_auth_event(hdd_context_t *hdd_ctx_ptr, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_len, uint8_t *rsp_rsn_ie, + uint32_t rsp_rsn_len, tCsrRoamInfo *roam_info_ptr) +{ + struct sk_buff *skb = NULL; + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx_ptr)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid ")); + return -EINVAL; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx_ptr->wiphy, + NULL, + ETH_ALEN + req_rsn_len + rsp_rsn_len + + sizeof(uint8_t) + SIR_REPLAY_CTR_LEN + + SIR_KCK_KEY_LEN + SIR_KCK_KEY_LEN + + (7 * NLMSG_HDRLEN), + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_event_alloc failed")); + return -EINVAL; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + ETH_ALEN, bssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + req_rsn_len, req_rsn_ie) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + rsp_rsn_len, rsp_rsn_ie)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Auth Status = %d"), + roam_info_ptr->synchAuthStatus); + if (roam_info_ptr->synchAuthStatus == + CSR_ROAM_AUTH_STATUS_AUTHENTICATED) { + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Include Auth Params TLV's")); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + true) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + SIR_REPLAY_CTR_LEN, roam_info_ptr->replay_ctr) + || nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + SIR_KCK_KEY_LEN, roam_info_ptr->kck) + || nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + SIR_KEK_KEY_LEN, roam_info_ptr->kek)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } + } else { + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("No Auth Params TLV's")); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + false)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +#endif + +static const struct nla_policy +wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { + + [QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR] = {.type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME] = {.type = NLA_U32 }, +}; + + +/** + * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + int ret_val = 0; + u32 modulated_dtim; + u16 stats_avg_factor; + u32 guard_time; + CDF_STATUS status; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret_val; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, + data, data_len, + wlan_hdd_wifi_config_policy)) { + hddLog(LOGE, FL("invalid attr")); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]) { + modulated_dtim = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]); + + status = sme_configure_modulated_dtim(hdd_ctx->hHal, + adapter->sessionId, + modulated_dtim); + + if (CDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]) { + stats_avg_factor = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]); + status = sme_configure_stats_avg_factor(hdd_ctx->hHal, + adapter->sessionId, + stats_avg_factor); + + if (CDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]) { + guard_time = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]); + status = sme_configure_guard_time(hdd_ctx->hHal, + adapter->sessionId, + guard_time); + + if (CDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_start_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function enables or disables the collection of packet statistics from + * the firmware + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + CDF_STATUS status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1]; + struct sir_wifi_start_log start_log; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_start_policy)) { + hddLog(LOGE, FL("Invalid attribute")); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) { + hddLog(LOGE, FL("attr ATTR failed")); + return -EINVAL; + } + start_log.ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]); + hddLog(LOGE, FL("Ring ID=%d"), start_log.ring_id); + + /* Parse and fetch verbose level */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) { + hddLog(LOGE, FL("attr verbose_level failed")); + return -EINVAL; + } + start_log.verbose_level = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]); + hddLog(LOGE, FL("verbose_level=%d"), start_log.verbose_level); + + /* Parse and fetch flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) { + hddLog(LOGE, FL("attr flag failed")); + return -EINVAL; + } + start_log.flag = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]); + hddLog(LOGE, FL("flag=%d"), start_log.flag); + + cds_set_ring_log_level(start_log.ring_id, start_log.verbose_level); + + if (start_log.ring_id == RING_ID_WAKELOCK) { + /* Start/stop wakelock events */ + if (start_log.verbose_level > WLAN_LOG_LEVEL_OFF) + cds_set_wakelock_logging(true); + else + cds_set_wakelock_logging(false); + return 0; + } + + status = sme_wifi_start_logger(hdd_ctx->hHal, start_log); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("sme_wifi_start_logger failed(err=%d)"), + status); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_get_ring_data_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Flush per packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + CDF_STATUS status; + uint32_t ring_id; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1]; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_get_ring_data_policy)) { + hddLog(LOGE, FL("Invalid attribute")); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) { + hddLog(LOGE, FL("attr ATTR failed")); + return -EINVAL; + } + + ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]); + + if (ring_id == RING_ID_PER_PACKET_STATS) { + wlan_logging_set_per_pkt_stats(); + hddLog(LOG1, FL("Flushing/Retrieving packet stats")); + } + + hddLog(LOG1, FL("Bug report triggered by framework")); + + status = cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("Failed to trigger bug report")); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Wrapper to flush packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_map_req_id_to_pattern_id() - map request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * if the slot is available, store the request id and return pattern id + * if entry exists, return the pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_map_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == MAX_REQUEST_ID) { + hdd_ctx->op_ctx.op_table[i].request_id = request_id; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } else if (hdd_ctx->op_ctx.op_table[i].request_id == + request_id) { + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + +/** + * hdd_unmap_req_id_to_pattern_id() - unmap request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * reset request id to 0 (slot available again) and + * return pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_unmap_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == request_id) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID +#define PARAM_CONTROL \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL +#define PARAM_IP_PACKET \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA +#define PARAM_SRC_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR +#define PARAM_DST_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR +#define PARAM_PERIOD QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD + +/** + * wlan_hdd_add_tx_ptrn() - add tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a AddTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirAddPeriodicTxPtrn *add_req; + CDF_STATUS status; + uint32_t request_id, ret, len; + uint8_t pattern_id = 0; + struct cdf_mac_addr dst_addr; + uint16_t eth_type = htons(ETH_P_IP); + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hddLog(LOGE, FL("Not in Connected state!")); + return -ENOTSUPP; + } + + add_req = cdf_mem_malloc(sizeof(*add_req)); + if (!add_req) { + hddLog(LOGE, FL("memory allocation failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hddLog(LOGE, FL("request_id cannot be MAX")); + return -EINVAL; + } + hddLog(LOG1, FL("Request Id: %u"), request_id); + + if (!tb[PARAM_PERIOD]) { + hddLog(LOGE, FL("attr period failed")); + goto fail; + } + add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]); + hddLog(LOG1, FL("Period: %u ms"), add_req->usPtrnIntervalMs); + if (add_req->usPtrnIntervalMs == 0) { + hddLog(LOGE, FL("Invalid interval zero, return failure")); + goto fail; + } + + if (!tb[PARAM_SRC_MAC_ADDR]) { + hddLog(LOGE, FL("attr source mac address failed")); + goto fail; + } + nla_memcpy(add_req->macAddress, tb[PARAM_SRC_MAC_ADDR], + CDF_MAC_ADDR_SIZE); + hddLog(LOG1, "input src mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(add_req->macAddress)); + + if (memcmp(add_req->macAddress, adapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE)) { + hddLog(LOGE, FL("input src mac address and connected ap bssid are different")); + goto fail; + } + + if (!tb[PARAM_DST_MAC_ADDR]) { + hddLog(LOGE, FL("attr dst mac address failed")); + goto fail; + } + nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], CDF_MAC_ADDR_SIZE); + hddLog(LOG1, "input dst mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(dst_addr.bytes)); + + if (!tb[PARAM_IP_PACKET]) { + hddLog(LOGE, FL("attr ip packet failed")); + goto fail; + } + add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]); + hddLog(LOG1, FL("IP packet len: %u"), add_req->ucPtrnSize); + + if (add_req->ucPtrnSize < 0 || + add_req->ucPtrnSize > (PERIODIC_TX_PTRN_MAX_SIZE - + ETH_HLEN)) { + hddLog(LOGE, FL("Invalid IP packet len: %d"), + add_req->ucPtrnSize); + goto fail; + } + + len = 0; + cdf_mem_copy(&add_req->ucPattern[0], dst_addr.bytes, CDF_MAC_ADDR_SIZE); + len += CDF_MAC_ADDR_SIZE; + cdf_mem_copy(&add_req->ucPattern[len], add_req->macAddress, + CDF_MAC_ADDR_SIZE); + len += CDF_MAC_ADDR_SIZE; + cdf_mem_copy(&add_req->ucPattern[len], ð_type, 2); + len += 2; + + /* + * This is the IP packet, add 14 bytes Ethernet (802.3) header + * ------------------------------------------------------------ + * | 14 bytes Ethernet (802.3) header | IP header and payload | + * ------------------------------------------------------------ + */ + cdf_mem_copy(&add_req->ucPattern[len], + nla_data(tb[PARAM_IP_PACKET]), + add_req->ucPtrnSize); + add_req->ucPtrnSize += len; + + ret = hdd_map_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret); + goto fail; + } + add_req->ucPtrnId = pattern_id; + hddLog(LOG1, FL("pattern id: %d"), add_req->ucPtrnId); + + status = sme_add_periodic_tx_ptrn(hdd_ctx->hHal, add_req); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_add_periodic_tx_ptrn failed (err=%d)"), status); + goto fail; + } + + EXIT(); + cdf_mem_free(add_req); + return 0; + +fail: + cdf_mem_free(add_req); + return -EINVAL; +} + +/** + * wlan_hdd_del_tx_ptrn() - delete tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a DelTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_del_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirDelPeriodicTxPtrn *del_req; + CDF_STATUS status; + uint32_t request_id, ret; + uint8_t pattern_id = 0; + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hddLog(LOGE, FL("request_id cannot be MAX")); + return -EINVAL; + } + + ret = hdd_unmap_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret); + return -EINVAL; + } + + del_req = cdf_mem_malloc(sizeof(*del_req)); + if (!del_req) { + hddLog(LOGE, FL("memory allocation failed")); + return -ENOMEM; + } + + cdf_mem_copy(del_req->macAddress, adapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + hddLog(LOG1, MAC_ADDRESS_STR, MAC_ADDR_ARRAY(del_req->macAddress)); + del_req->ucPtrnId = pattern_id; + hddLog(LOG1, FL("Request Id: %u Pattern id: %d"), + request_id, del_req->ucPtrnId); + + status = sme_del_periodic_tx_ptrn(hdd_ctx->hHal, del_req); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_del_periodic_tx_ptrn failed (err=%d)"), status); + goto fail; + } + + EXIT(); + cdf_mem_free(del_req); + return 0; + +fail: + cdf_mem_free(del_req); + return -EINVAL; +} + + +/** + * __wlan_hdd_cfg80211_offloaded_packets() - send offloaded packets + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + uint8_t control; + int ret; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_SRC_MAC_ADDR] = { .type = NLA_BINARY, + .len = CDF_MAC_ADDR_SIZE }, + [PARAM_DST_MAC_ADDR] = { .type = NLA_BINARY, + .len = CDF_MAC_ADDR_SIZE }, + [PARAM_PERIOD] = { .type = NLA_U32 }, + }; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + hddLog(LOGE, + FL("Periodic Tx Pattern Offload feature is not supported in FW!")); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hddLog(LOGE, FL("attr control failed")); + return -EINVAL; + } + control = nla_get_u32(tb[PARAM_CONTROL]); + hddLog(LOG1, FL("Control: %d"), control); + + if (control == WLAN_START_OFFLOADED_PACKETS) + return wlan_hdd_add_tx_ptrn(adapter, hdd_ctx, tb); + else if (control == WLAN_STOP_OFFLOADED_PACKETS) + return wlan_hdd_del_tx_ptrn(adapter, hdd_ctx, tb); + else { + hddLog(LOGE, FL("Invalid control: %d"), control); + return -EINVAL; + } +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_CONTROL +#undef PARAM_IP_PACKET +#undef PARAM_SRC_MAC_ADDR +#undef PARAM_DST_MAC_ADDR +#undef PARAM_PERIOD + +/** + * wlan_hdd_cfg80211_offloaded_packets() - Wrapper to offload packets + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_offloaded_packets(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX +#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID +#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL +#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI +#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI + +/** + * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct rssi_monitor_req req; + CDF_STATUS status; + int ret; + uint32_t control; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_MIN_RSSI] = { .type = NLA_S8 }, + [PARAM_MAX_RSSI] = { .type = NLA_S8 }, + }; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hddLog(LOGE, FL("Not in Connected state!")); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hddLog(LOGE, FL("attr control failed")); + return -EINVAL; + } + + req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + req.session_id = adapter->sessionId; + control = nla_get_u32(tb[PARAM_CONTROL]); + + if (control == QCA_WLAN_RSSI_MONITORING_START) { + req.control = true; + if (!tb[PARAM_MIN_RSSI]) { + hddLog(LOGE, FL("attr min rssi failed")); + return -EINVAL; + } + + if (!tb[PARAM_MAX_RSSI]) { + hddLog(LOGE, FL("attr max rssi failed")); + return -EINVAL; + } + + req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); + req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); + + if (!(req.min_rssi < req.max_rssi)) { + hddLog(LOGW, FL("min_rssi: %d must be less than max_rssi: %d"), + req.min_rssi, req.max_rssi); + return -EINVAL; + } + hddLog(LOG1, FL("Min_rssi: %d Max_rssi: %d"), + req.min_rssi, req.max_rssi); + + } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) + req.control = false; + else { + hddLog(LOGE, FL("Invalid control cmd: %d"), control); + return -EINVAL; + } + hddLog(LOG1, FL("Request Id: %u Session_id: %d Control: %d"), + req.request_id, req.session_id, req.control); + + status = sme_set_rssi_monitoring(hdd_ctx->hHal, &req); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_set_rssi_monitoring failed(err=%d)"), status); + return -EINVAL; + } + + return 0; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#undef PARAM_MAX +#undef PARAM_CONTROL +#undef PARAM_REQUEST_ID +#undef PARAM_MAX_RSSI +#undef PARAM_MIN_RSSI + +/** + * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_rssi_threshold_breached() - rssi breached NL event + * @hddctx: HDD context + * @data: rssi breached event data + * + * This function reads the rssi breached event %data and fill in the skb with + * NL attributes and send up the NL event. + * + * Return: none + */ +void hdd_rssi_threshold_breached(void *hddctx, + struct rssi_breach_event *data) +{ + hdd_context_t *hdd_ctx = hddctx; + struct sk_buff *skb; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !data) { + hddLog(LOGE, FL("HDD context is invalid or data(%p) is null"), + data); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + hddLog(LOG1, "Req Id: %u Current rssi: %d", + data->request_id, data->curr_rssi); + hddLog(LOG1, "Current BSSID: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(data->curr_bssid.bytes)); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + data->request_id) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + sizeof(data->curr_bssid), data->curr_bssid.bytes) || + nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + data->curr_rssi)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +/** __wlan_hdd_cfg80211_get_preferred_freq_list() - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int __wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int i, ret = 0; + CDF_STATUS status; + uint8_t pcl[MAX_NUM_CHAN]; + uint32_t pcl_len = 0; + uint32_t freq_list[MAX_NUM_CHAN]; + enum cds_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1]; + struct sk_buff *reply_skb; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]); + + if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + hdd_debug("Userspace requested pref freq list"); + + status = cds_get_pcl(hdd_ctx, intf_mode, pcl, &pcl_len); + if (status != CDF_STATUS_SUCCESS) { + hdd_err("Get pcl failed"); + return -EINVAL; + } + + /* convert channel number to frequency */ + for (i = 0; i < pcl_len; i++) { + if (pcl[i] <= ARRAY_SIZE(hdd_channels_2_4_ghz)) + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + IEEE80211_BAND_2GHZ); + else + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + IEEE80211_BAND_5GHZ); + } + + /* send the freq_list back to supplicant */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + pcl_len + + NLMSG_HDRLEN); + + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + return -EINVAL; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + intf_mode) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST, + sizeof(uint32_t) * pcl_len, + freq_list)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** wlan_hdd_cfg80211_get_preferred_freq_list () - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_preferred_freq_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + enum cds_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1]; + uint32_t channel_hint; + p_cds_contextType p_cds_context; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("Invalid CDS context"); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]); + + if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]) { + hdd_err("attr probable freq failed"); + return -EINVAL; + } + + channel_hint = cds_freq_to_chan(nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ])); + + /* check pcl table */ + if (!cds_allow_concurrency(hdd_ctx, intf_mode, + channel_hint, HW_MODE_20_MHZ)) { + hdd_err("Set channel hint failed due to concurrency check"); + return -EINVAL; + } + + if (hdd_ctx->config->policy_manager_enabled) { + ret = cdf_event_reset( + &p_cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(ret)) + hdd_err("clearing event failed"); + + ret = cds_current_connections_update(hdd_ctx, + channel_hint); + if (CDF_STATUS_E_FAILURE == ret) { + /* return in the failure case */ + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (CDF_STATUS_SUCCESS == ret) { + /* + * Success is the only case for which we expect hw mode + * change to take place, hence we need to wait. + * For any other return value it should be a pass + * through + */ + ret = cdf_wait_single_event( + &p_cds_context->connection_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("ERROR: cdf wait for event failed!!"); + return -EINVAL; + } + + } + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_probable_oper_channel(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = is_driver_dfs_capable + }, + +#ifdef WLAN_FEATURE_NAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_nan_request + }, +#endif + +#ifdef WLAN_FEATURE_STATS_EXT + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_stats_ext_request + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_stop + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_extscan_get_valid_channels + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_get_capabilities + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_get_cached_results + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_set_bssid_hotlist + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_reset_bssid_hotlist + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE, + .flags = + WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_set_significant_change + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE, + .flags = + WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_reset_significant_change + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_epno_list + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_clear + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_set + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_get + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_exttdls_enable + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_exttdls_disable + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_exttdls_get_status + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_supported_features + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_set_scanning_mac_oui + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = cds_cfg80211_get_concurrency_matrix + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_disable_dfs_chan_scan + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_do_acs + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_features + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_keymgmt_set_key + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_passpoint_list + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_reset_passpoint_list + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_set_ssid_hotlist + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_reset_ssid_hotlist + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_wifi_info + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_set + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_set_ext_roam_params + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_wifi_logger_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_preferred_freq_list + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_probable_oper_channel + }, +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_tdls_capabilities + }, +#endif +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_offloaded_packets + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_monitor_rssi + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_logger_supp_feature + }, +#ifdef WLAN_FEATURE_MEMDUMP + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_fw_mem_dump + }, +#endif /* WLAN_FEATURE_MEMDUMP */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_vendor_scan + }, + + /* OCB commands */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_set_config + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_set_utc_time + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_start_timing_advert + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_stop_timing_advert + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_get_tsf_timer + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_get_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_clear_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_update_ndl + }, +}; + +/* + * FUNCTION: wlan_hdd_cfg80211_wiphy_alloc + * This function is called by hdd_wlan_startup() + * during initialization. + * This function is used to allocate wiphy structure. + */ +struct wiphy *wlan_hdd_cfg80211_wiphy_alloc(int priv_size) +{ + struct wiphy *wiphy; + ENTER(); + + /* + * Create wiphy device + */ + wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, priv_size); + + if (!wiphy) { + /* Print error and jump into err label and free the memory */ + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: wiphy init failed", + __func__); + return NULL; + } + + return wiphy; +} + +/* + * FUNCTION: wlan_hdd_cfg80211_update_band + * This function is called from the supplicant through a + * private ioctl to change the band value + */ +int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, eCsrBand eBand) +{ + int i, j; + CHANNEL_STATE channelEnabledState; + + ENTER(); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + + if (NULL == wiphy->bands[i]) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: wiphy->bands[i] is NULL, i = %d", __func__, + i); + continue; + } + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + channelEnabledState = + cds_get_channel_state(band->channels[j]. + hw_value); + + if (IEEE80211_BAND_2GHZ == i && eCSR_BAND_5G == eBand) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable Social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq) + && CHANNEL_STATE_ENABLE == + channelEnabledState) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (IEEE80211_BAND_5GHZ == i && + eCSR_BAND_24 == eBand) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + + if (CHANNEL_STATE_DISABLE == channelEnabledState || + CHANNEL_STATE_INVALID == channelEnabledState) { + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + } else if (CHANNEL_STATE_DFS == channelEnabledState) { + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + band->channels[j].flags |= IEEE80211_CHAN_RADAR; + } else { + band->channels[j].flags &= + ~(IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_RADAR); + } + } + } + return 0; +} + +/* + * FUNCTION: wlan_hdd_cfg80211_init + * This function is called by hdd_wlan_startup() + * during initialization. + * This function is used to initialize and register wiphy structure. + */ +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *pCfg) +{ + int i, j; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + ENTER(); + + /* Now bind the underlying wlan device with wiphy */ + set_wiphy_dev(wiphy, dev); + + wiphy->mgmt_stypes = wlan_hdd_txrx_stypes; + + /* This will disable updating of NL channels from passive to + * active if a beacon is received on passive channel. */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; +#else + wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME + | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD + | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL +#ifdef FEATURE_WLAN_STA_4ADDR_SCHEME + | WIPHY_FLAG_4ADDR_STATION +#endif + | WIPHY_FLAG_OFFCHAN_TX; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + wiphy->regulatory_flags = REGULATORY_COUNTRY_IE_IGNORE; +#else + wiphy->country_ie_pref = NL80211_COUNTRY_IE_IGNORE_CORE; +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_cfg80211_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; + wiphy->wowlan.n_patterns = WOWL_MAX_PTRNS_ALLOWED; + wiphy->wowlan.pattern_min_len = 1; + wiphy->wowlan.pattern_max_len = WOWL_PTRN_MAX_SIZE; +#endif + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (pCfg->isFastTransitionEnabled +#ifdef FEATURE_WLAN_LFR + || pCfg->isFastRoamIniFeatureEnabled +#endif +#ifdef FEATURE_WLAN_ESE + || pCfg->isEseIniFeatureEnabled +#endif + ) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + } +#endif +#ifdef FEATURE_WLAN_TDLS + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS + | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; +#endif + + wiphy->features |= NL80211_FEATURE_HT_IBSS; + +#ifdef FEATURE_WLAN_SCAN_PNO + if (pCfg->configPNOScanSupport) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS; + wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS; + wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH; + } +#endif /*FEATURE_WLAN_SCAN_PNO */ + +#if defined QCA_WIFI_FTM + if (cds_get_conparam() != CDF_FTM_MODE) { +#endif + + /* even with WIPHY_FLAG_CUSTOM_REGULATORY, + driver can still register regulatory callback and + it will get regulatory settings in wiphy->band[], but + driver need to determine what to do with both + regulatory settings */ + + wiphy->reg_notifier = hdd_reg_notifier; + +#if defined QCA_WIFI_FTM +} +#endif + + wiphy->max_scan_ssids = MAX_SCAN_SSID; + + wiphy->max_scan_ie_len = SIR_MAC_MAX_ADD_IE_LENGTH; + + wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS; + + /* Supports STATION & AD-HOC modes right now */ + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_AP); + + if (pCfg->advertiseConcurrentOperation) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + if (pCfg->enableMCC) { + int i; + for (i = 0; i < ARRAY_SIZE(wlan_hdd_iface_combination); + i++) { + if (!pCfg->allowMCCGODiffBI) + wlan_hdd_iface_combination[i]. + beacon_int_infra_match = true; + } + } + wiphy->n_iface_combinations = + ARRAY_SIZE(wlan_hdd_iface_combination); + wiphy->iface_combinations = wlan_hdd_iface_combination; +#endif + } + + /* Before registering we need to update the ht capabilitied based + * on ini values*/ + if (!pCfg->ShortGI20MhzEnable) { + wlan_hdd_band_2_4_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + wlan_hdd_band_p2p_2_4_ghz.ht_cap.cap &= + ~IEEE80211_HT_CAP_SGI_20; + } + + if (!pCfg->ShortGI40MhzEnable) { + wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + if (!pCfg->nChannelBondingMode5GHz) { + wlan_hdd_band_5_ghz.ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + + wiphy->bands[IEEE80211_BAND_2GHZ] = &wlan_hdd_band_2_4_ghz; + if (true == hdd_is_5g_supported(pHddCtx)) { + wiphy->bands[IEEE80211_BAND_5GHZ] = &wlan_hdd_band_5_ghz; + } + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + + if (NULL == wiphy->bands[i]) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: wiphy->bands[i] is NULL, i = %d", __func__, + i); + continue; + } + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + if (IEEE80211_BAND_2GHZ == i && + eCSR_BAND_5G == pCfg->nBandCapability) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq)) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (IEEE80211_BAND_5GHZ == i && + eCSR_BAND_24 == pCfg->nBandCapability) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + } + } + /*Initialise the supported cipher suite details */ + wiphy->cipher_suites = hdd_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(hdd_cipher_suites); + + /*signal strength in mBm (100*dBm) */ + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION; + + if (cds_get_conparam() != CDF_FTM_MODE) { + wiphy->n_vendor_commands = + ARRAY_SIZE(hdd_wiphy_vendor_commands); + wiphy->vendor_commands = hdd_wiphy_vendor_commands; + + wiphy->vendor_events = wlan_hdd_cfg80211_vendor_events; + wiphy->n_vendor_events = + ARRAY_SIZE(wlan_hdd_cfg80211_vendor_events); + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)) + if (pCfg->enableDFSMasterCap) { + wiphy->flags |= WIPHY_FLAG_DFS_OFFLOAD; + } +#endif + + wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers; + +#ifdef QCA_HT_2040_COEX + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; +#endif + + EXIT(); + return 0; +} + +/* + * In this function, wiphy structure is updated after CDF + * initialization. In wlan_hdd_cfg80211_init, only the + * default values will be initialized. The final initialization + * of all required members can be done here. + */ +void wlan_hdd_update_wiphy(struct wiphy *wiphy, struct hdd_config *pCfg) +{ + wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers; +} + +/* In this function we are registering wiphy. */ +int wlan_hdd_cfg80211_register(struct wiphy *wiphy) +{ + ENTER(); + /* Register our wiphy dev with cfg80211 */ + if (0 > wiphy_register(wiphy)) { + /* print error */ + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: wiphy register failed", + __func__); + return -EIO; + } + + EXIT(); + return 0; +} + +/* + HDD function to update wiphy capability based on target offload status. + + wlan_hdd_cfg80211_init() does initialization of all wiphy related + capability even before downloading firmware to the target. In discrete + case, host will get know certain offload capability (say sched_scan + caps) only after downloading firmware to the target and target boots up. + This function is used to override setting done in wlan_hdd_cfg80211_init() + based on target capability. + */ +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy) +{ +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct hdd_config *pCfg = pHddCtx->config; + + /* wlan_hdd_cfg80211_init() sets sched_scan caps already in wiphy before + * control comes here. Here just we need to clear it if firmware doesn't + * have PNO support. */ + if (!pCfg->PnoOffload) { + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_ie_len = 0; + } +#endif +} + +/* This function registers for all frame which supplicant is interested in */ +void wlan_hdd_cfg80211_register_frames(hdd_adapter_t *pAdapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + /* Register for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + + ENTER(); + + /* Right now we are registering these frame when driver is getting + initialized. Once we will move to 2.6.37 kernel, in which we have + frame register ops, we will move this code as a part of that */ + /* GAS Initial Request */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + + /* GAS Initial Response */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + + /* GAS Comeback Request */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + + /* GAS Comeback Response */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + + /* P2P Public Action */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_PUBLIC_ACTION_FRAME, + P2P_PUBLIC_ACTION_FRAME_SIZE); + + /* P2P Action */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_ACTION_FRAME, + P2P_ACTION_FRAME_SIZE); + + /* WNM BSS Transition Request frame */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) WNM_BSS_ACTION_FRAME, + WNM_BSS_ACTION_FRAME_SIZE); + + /* WNM-Notification */ + sme_register_mgmt_frame(hHal, pAdapter->sessionId, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +void wlan_hdd_cfg80211_deregister_frames(hdd_adapter_t *pAdapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + /* Register for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + + ENTER(); + + /* Right now we are registering these frame when driver is getting + initialized. Once we will move to 2.6.37 kernel, in which we have + frame register ops, we will move this code as a part of that */ + /* GAS Initial Request */ + + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + + /* GAS Initial Response */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + + /* GAS Comeback Request */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + + /* GAS Comeback Response */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + + /* P2P Public Action */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_PUBLIC_ACTION_FRAME, + P2P_PUBLIC_ACTION_FRAME_SIZE); + + /* P2P Action */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_ACTION_FRAME, + P2P_ACTION_FRAME_SIZE); + + /* WNM-Notification */ + sme_deregister_mgmt_frame(hHal, pAdapter->sessionId, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +#ifdef FEATURE_WLAN_WAPI +void wlan_hdd_cfg80211_set_key_wapi(hdd_adapter_t *pAdapter, uint8_t key_index, + const uint8_t *mac_addr, const uint8_t *key, + int key_Len) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamSetKey setKey; + bool isConnected = true; + int status = 0; + uint32_t roamId = 0xFF; + uint8_t *pKeyPtr = NULL; + int n = 0; + + hddLog(LOG1, "Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; /* Store Key ID */ + setKey.encType = eCSR_ENCRYPT_TYPE_WPI; /* SET WAPI Encryption */ + setKey.keyDirection = eSIR_TX_RX; /* Key Directionn both TX and RX */ + setKey.paeRole = 0; /* the PAE role */ + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + cdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + cdf_mem_copy(setKey.peerMac.bytes, mac_addr, CDF_MAC_ADDR_SIZE); + } + setKey.keyLength = key_Len; + pKeyPtr = setKey.Key; + memcpy(pKeyPtr, key, key_Len); + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: WAPI KEY LENGTH:0x%04x", + __func__, key_Len); + for (n = 0; n < key_Len; n++) + hddLog(CDF_TRACE_LEVEL_INFO, "%s WAPI KEY Data[%d]:%02x ", + __func__, n, setKey.Key[n]); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + if (isConnected) { + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + } + if (status != 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "[%4d] sme_roam_set_key returned ERROR status= %d", + __LINE__, status); + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } +} +#endif /* FEATURE_WLAN_WAPI */ + +uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length, + uint8_t eid) +{ + int left = length; + uint8_t *ptr = (uint8_t *)ies_ptr; + uint8_t elem_id, elem_len; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Invalid IEs eid = %d elem_len=%d left=%d"), + eid, elem_len, left); + return NULL; + } + if (elem_id == eid) { + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} + +/* + * FUNCTION: wlan_hdd_validate_operation_channel + * called by wlan_hdd_cfg80211_start_bss() and + * wlan_hdd_set_channel() + * This function validates whether given channel is part of valid + * channel list. + */ +CDF_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter, + int channel) +{ + + uint32_t num_ch = 0; + u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + u32 indx = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t fValidChannel = false, count = 0; + struct hdd_config *hdd_pConfig_ini = (WLAN_HDD_GET_CTX(pAdapter))->config; + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (hdd_pConfig_ini->sapAllowAllChannel) { + /* Validate the channel */ + for (count = RF_CHAN_1; count <= RF_CHAN_165; count++) { + if (channel == rf_channels[count].channelNum) { + fValidChannel = true; + break; + } + } + if (fValidChannel != true) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Invalid Channel [%d]", __func__, channel); + return CDF_STATUS_E_FAILURE; + } + } else { + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + valid_ch, &num_ch)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: failed to get valid channel list", + __func__); + return CDF_STATUS_E_FAILURE; + } + for (indx = 0; indx < num_ch; indx++) { + if (channel == valid_ch[indx]) { + break; + } + } + + if (indx >= num_ch) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Invalid Channel [%d]", __func__, channel); + return CDF_STATUS_E_FAILURE; + } + } + return CDF_STATUS_SUCCESS; + +} + +#ifdef DHCP_SERVER_OFFLOAD +static void wlan_hdd_set_dhcp_server_offload(hdd_adapter_t *pHostapdAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + tpSirDhcpSrvOffloadInfo pDhcpSrvInfo; + uint8_t numEntries = 0; + uint8_t srv_ip[IPADDR_NUM_ENTRIES]; + uint8_t num; + uint32_t temp; + pDhcpSrvInfo = cdf_mem_malloc(sizeof(*pDhcpSrvInfo)); + if (NULL == pDhcpSrvInfo) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: could not allocate tDhcpSrvOffloadInfo!", __func__); + return; + } + cdf_mem_zero(pDhcpSrvInfo, sizeof(*pDhcpSrvInfo)); + pDhcpSrvInfo->vdev_id = pHostapdAdapter->sessionId; + pDhcpSrvInfo->dhcpSrvOffloadEnabled = true; + pDhcpSrvInfo->dhcpClientNum = pHddCtx->config->dhcpMaxNumClients; + hdd_string_to_u8_array(pHddCtx->config->dhcpServerIP, + srv_ip, &numEntries, IPADDR_NUM_ENTRIES); + if (numEntries != IPADDR_NUM_ENTRIES) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: incorrect IP address (%s) assigned for DHCP server!", + __func__, pHddCtx->config->dhcpServerIP); + goto end; + } + if ((srv_ip[0] >= 224) && (srv_ip[0] <= 239)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: invalid IP address (%s)! It could NOT be multicast IP address!", + __func__, pHddCtx->config->dhcpServerIP); + goto end; + } + if (srv_ip[IPADDR_NUM_ENTRIES - 1] >= 100) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: invalid IP address (%s)! The last field must be less than 100!", + __func__, pHddCtx->config->dhcpServerIP); + goto end; + } + for (num = 0; num < numEntries; num++) { + temp = srv_ip[num]; + pDhcpSrvInfo->dhcpSrvIP |= (temp << (8 * num)); + } + if (CDF_STATUS_SUCCESS != + sme_set_dhcp_srv_offload(pHddCtx->hHal, pDhcpSrvInfo)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: sme_setDHCPSrvOffload fail!", __func__); + goto end; + } + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + "%s: enable DHCP Server offload successfully!", __func__); +end: + cdf_mem_free(pDhcpSrvInfo); + return; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +static int __wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int ret = 0; + CDF_STATUS cdf_ret_status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BSS, + pAdapter->sessionId, params->ap_isolate)); + hddLog(LOG1, FL("Device_mode %s(%d), ap_isolate = %d"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, params->ap_isolate); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return ret; + } + + if (!(pAdapter->device_mode == WLAN_HDD_SOFTAP || + pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + return -EOPNOTSUPP; + } + + /* ap_isolate == -1 means that in change bss, upper layer doesn't + * want to update this parameter */ + if (-1 != params->ap_isolate) { + pAdapter->sessionCtx.ap.apDisableIntraBssFwd = + !!params->ap_isolate; + + cdf_ret_status = sme_ap_disable_intra_bss_fwd(pHddCtx->hHal, + pAdapter->sessionId, + pAdapter->sessionCtx. + ap. + apDisableIntraBssFwd); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + ret = -EINVAL; + } + } + + EXIT(); + return ret; +} + +static int +wlan_hdd_change_iface_to_adhoc(struct net_device *ndev, + tCsrRoamProfile *pRoamProfile, + enum nl80211_iftype type) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct hdd_config *pConfig = pHddCtx->config; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + pRoamProfile->BSSType = eCSR_BSS_TYPE_START_IBSS; + pRoamProfile->phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + pAdapter->device_mode = WLAN_HDD_IBSS; + wdev->iftype = type; + + return 0; +} + +static int wlan_hdd_change_iface_to_sta_mode(struct net_device *ndev, + enum nl80211_iftype type) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_wext_state_t *wext; + struct wireless_dev *wdev; + CDF_STATUS status; + + ENTER(); + + if (test_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags)) { + hddLog(LOG1, FL("ACS is in progress, don't change iface!")); + return 0; + } + + wdev = ndev->ieee80211_ptr; + hdd_stop_adapter(pHddCtx, pAdapter, true); + hdd_deinit_adapter(pHddCtx, pAdapter, true); + wdev->iftype = type; + /*Check for sub-string p2p to confirm its a p2p interface */ + if (NULL != strnstr(ndev->name, "p2p", 3)) { + pAdapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + WLAN_HDD_P2P_DEVICE : WLAN_HDD_P2P_CLIENT; + } else { + pAdapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + WLAN_HDD_INFRA_STATION : WLAN_HDD_P2P_CLIENT; + } + + /* set con_mode to STA only when no SAP concurrency mode */ + if (!(cds_get_concurrency_mode() & (CDF_SAP_MASK | CDF_P2P_GO_MASK))) + hdd_set_conparam(0); + memset(&pAdapter->sessionCtx, 0, sizeof(pAdapter->sessionCtx)); + hdd_set_station_ops(pAdapter->dev); + status = hdd_init_station_mode(pAdapter); + wext = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + wext->roamProfile.pAddIEScan = pAdapter->scan_info.scanAddIE.addIEdata; + wext->roamProfile.nAddIEScanLength = + pAdapter->scan_info.scanAddIE.length; + EXIT(); + return status; +} + +static int wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_bss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* FUNCTION: wlan_hdd_change_country_code_cd + * to wait for contry code completion + */ +void *wlan_hdd_change_country_code_cb(void *pAdapter) +{ + hdd_adapter_t *call_back_pAdapter = pAdapter; + complete(&call_back_pAdapter->change_country_code); + return NULL; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_change_iface + * This function is used to set the interface type (INFRASTRUCTURE/ADHOC) + */ +static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + tCsrRoamProfile *pRoamProfile = NULL; + eCsrRoamBssType LastBSSType; + struct hdd_config *pConfig = NULL; + eMib_dot11DesiredBssType connectedBssType; + unsigned long rc; + CDF_STATUS vstatus; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, + pAdapter->sessionId, type)); + + hddLog(CDF_TRACE_LEVEL_INFO, FL("Device_mode = %d, IFTYPE = 0x%x"), + pAdapter->device_mode, type); + + if (!cds_allow_concurrency(pHddCtx, + wlan_hdd_convert_nl_iftype_to_hdd_type(type), + 0, HW_MODE_20_MHZ)) { + hddLog(CDF_TRACE_LEVEL_DEBUG, + FL("This concurrency combination is not allowed")); + return -EINVAL; + } + + pConfig = pHddCtx->config; + wdev = ndev->ieee80211_ptr; + + /* Reset the current device mode bit mask */ + cds_clear_concurrency_mode(pHddCtx, pAdapter->device_mode); + + hdd_tdls_notify_mode_change(pAdapter, pHddCtx); + + if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || + (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) || + (pAdapter->device_mode == WLAN_HDD_P2P_DEVICE)) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + LastBSSType = pRoamProfile->BSSType; + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + vstatus = wlan_hdd_change_iface_to_sta_mode(ndev, type); + if (vstatus != CDF_STATUS_SUCCESS) + return -EINVAL; + + hdd_register_tx_flow_control(pAdapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + + goto done; + + case NL80211_IFTYPE_ADHOC: + wlan_hdd_tdls_exit(pAdapter); + hddLog(LOG1, FL("Setting interface Type to ADHOC")); + wlan_hdd_change_iface_to_adhoc(ndev, pRoamProfile, + type); + break; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + { + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Setting interface Type to %s"), + (type == + NL80211_IFTYPE_AP) ? "SoftAP" : + "P2pGo"); + + /* Cancel any remain on channel for GO mode */ + if (NL80211_IFTYPE_P2P_GO == type) { + wlan_hdd_cancel_existing_remain_on_channel + (pAdapter); + } + + if (NL80211_IFTYPE_AP == type) { + /* As Loading WLAN Driver one interface being created for + * p2p device address. This will take one HW STA and the + * max number of clients that can connect to softAP will be + * reduced by one. so while changing the interface type to + * NL80211_IFTYPE_AP (SoftAP) remove p2p0 interface as it is + * not required in SoftAP mode. + */ + + /* Get P2P Adapter */ + hdd_adapter_t *pP2pAdapter = NULL; + pP2pAdapter = + hdd_get_adapter(pHddCtx, + WLAN_HDD_P2P_DEVICE); + + if (pP2pAdapter) { + hdd_stop_adapter(pHddCtx, + pP2pAdapter, + true); + hdd_deinit_adapter(pHddCtx, + pP2pAdapter, true); + hdd_close_adapter(pHddCtx, + pP2pAdapter, + true); + } + } + hdd_stop_adapter(pHddCtx, pAdapter, true); + + /* De-init the adapter */ + hdd_deinit_adapter(pHddCtx, pAdapter, true); + memset(&pAdapter->sessionCtx, 0, + sizeof(pAdapter->sessionCtx)); + pAdapter->device_mode = + (type == + NL80211_IFTYPE_AP) ? WLAN_HDD_SOFTAP : + WLAN_HDD_P2P_GO; + + /* + * Fw will take care incase of concurrency + */ + + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) + && (pConfig->apRandomBssidEnabled)) { + /* To meet Android requirements create a randomized + MAC address of the form 02:1A:11:Fx:xx:xx */ + get_random_bytes(&ndev->dev_addr[3], 3); + ndev->dev_addr[0] = 0x02; + ndev->dev_addr[1] = 0x1A; + ndev->dev_addr[2] = 0x11; + ndev->dev_addr[3] |= 0xF0; + memcpy(pAdapter->macAddressCurrent. + bytes, ndev->dev_addr, + CDF_MAC_ADDR_SIZE); + pr_info("wlan: Generated HotSpot BSSID " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(ndev->dev_addr)); + } + + hdd_set_ap_ops(pAdapter->dev); + + vstatus = hdd_init_ap_mode(pAdapter); + if (vstatus != CDF_STATUS_SUCCESS) { + hddLog(LOGP, + FL + ("Error initializing the ap mode")); + return -EINVAL; + } + hdd_set_conparam(1); + + hdd_register_tx_flow_control(pAdapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb); + + /* Interface type changed update in wiphy structure */ + if (wdev) { + wdev->iftype = type; + } else { + hddLog(LOGE, + FL("Wireless dev is NULL")); + return -EINVAL; + } + goto done; + } + + default: + hddLog(LOGE, FL("Unsupported interface type (%d)"), + type); + return -EOPNOTSUPP; + } + } else if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) || + (pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + status = wlan_hdd_change_iface_to_sta_mode(ndev, type); + if (status != CDF_STATUS_SUCCESS) + return status; + + if ((NL80211_IFTYPE_P2P_CLIENT == type) || + (NL80211_IFTYPE_STATION == type)) { + + hdd_register_tx_flow_control(pAdapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + } + goto done; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + wdev->iftype = type; + pAdapter->device_mode = (type == NL80211_IFTYPE_AP) ? + WLAN_HDD_SOFTAP : WLAN_HDD_P2P_GO; + + hdd_register_tx_flow_control(pAdapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb); + goto done; + + default: + hddLog(LOGE, FL("Unsupported interface type(%d)"), + type); + return -EOPNOTSUPP; + } + } else { + hddLog(LOGE, FL("Unsupported device mode(%d)"), + pAdapter->device_mode); + return -EOPNOTSUPP; + } + + if (LastBSSType != pRoamProfile->BSSType) { + /* Interface type changed update in wiphy structure */ + wdev->iftype = type; + + /* The BSS mode changed, We need to issue disconnect + if connected or in IBSS disconnect state */ + if (hdd_conn_get_connected_bss_type + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), &connectedBssType) + || (eCSR_BSS_TYPE_START_IBSS == LastBSSType)) { + /* Need to issue a disconnect to CSR. */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + if (CDF_STATUS_SUCCESS == + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED)) { + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hddLog(LOGE, + FL + ("Wait on disconnect_comp_var failed")); + } + } + } + } + +done: + /* Set bitmask based on updated value */ + cds_set_concurrency_mode(pHddCtx, pAdapter->device_mode); + +#ifdef WLAN_FEATURE_LPSS + wlan_hdd_send_all_scan_intf_info(pHddCtx); +#endif + + EXIT(); + return 0; +} + +/* + * FUNCTION: wlan_hdd_cfg80211_change_iface + * wrapper function to protect the actual implementation from SSR. + */ +static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, flags, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_TDLS +static bool wlan_hdd_is_duplicate_channel(uint8_t *arr, + int index, uint8_t match) +{ + int i; + for (i = 0; i < index; i++) { + if (arr[i] == match) + return true; + } + return false; +} +#endif + +/** + * __wlan_hdd_change_station() - change station + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac, + struct station_parameters *params) +#endif +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + struct cdf_mac_addr STAMacAddress; +#ifdef FEATURE_WLAN_TDLS + tCsrStaParams StaParams = { 0 }; + uint8_t isBufSta = 0; + uint8_t isOffChannelSupported = 0; +#endif + int ret; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CHANGE_STATION, + pAdapter->sessionId, params->listen_interval)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return ret; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + cdf_mem_copy(STAMacAddress.bytes, mac, CDF_MAC_ADDR_SIZE); + + if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) || + (pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) { + status = + hdd_softap_change_sta_state(pAdapter, + &STAMacAddress, + ol_txrx_peer_state_auth); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL + ("Not able to change TL state to AUTHENTICATED")); + return -EINVAL; + } + } + } else if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || + (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { +#ifdef FEATURE_WLAN_TDLS + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + StaParams.capability = params->capability; + StaParams.uapsd_queues = params->uapsd_queues; + StaParams.max_sp = params->max_sp; + + /* Convert (first channel , number of channels) tuple to + * the total list of channels. This goes with the assumption + * that if the first channel is < 14, then the next channels + * are an incremental of 1 else an incremental of 4 till the number + * of channels. + */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: params->supported_channels_len: %d", + __func__, params->supported_channels_len); + if (0 != params->supported_channels_len) { + int i = 0, j = 0, k = 0, no_of_channels = 0; + int num_unique_channels; + int next; + for (i = 0; + i < params->supported_channels_len + && j < SIR_MAC_MAX_SUPP_CHANNELS; i += 2) { + int wifi_chan_index; + if (!wlan_hdd_is_duplicate_channel + (StaParams.supported_channels, j, + params->supported_channels[i])) { + StaParams. + supported_channels[j] = + params-> + supported_channels[i]; + } else { + continue; + } + wifi_chan_index = + ((StaParams.supported_channels[j] <= + HDD_CHANNEL_14) ? 1 : 4); + no_of_channels = + params->supported_channels[i + 1]; + + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d, wifi_chan_index: %d, no_of_channels: %d", + __func__, i, j, k, j, + StaParams. + supported_channels[j], + wifi_chan_index, + no_of_channels); + for (k = 1; k <= no_of_channels && + j < SIR_MAC_MAX_SUPP_CHANNELS - 1; + k++) { + next = + StaParams. + supported_channels[j] + + wifi_chan_index; + if (!wlan_hdd_is_duplicate_channel(StaParams.supported_channels, j + 1, next)) { + StaParams. + supported_channels[j + + + 1] + = next; + } else { + continue; + } + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d", + __func__, i, j, k, + j + 1, + StaParams. + supported_channels[j + + 1]); + j += 1; + } + } + num_unique_channels = j + 1; + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: Unique Channel List", __func__); + for (i = 0; i < num_unique_channels; i++) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: StaParams.supported_channels[%d]: %d,", + __func__, i, + StaParams. + supported_channels[i]); + } + if (MAX_CHANNEL < num_unique_channels) + num_unique_channels = MAX_CHANNEL; + StaParams.supported_channels_len = + num_unique_channels; + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: After removing duplcates StaParams.supported_channels_len: %d", + __func__, + StaParams.supported_channels_len); + } + cdf_mem_copy(StaParams.supported_oper_classes, + params->supported_oper_classes, + params->supported_oper_classes_len); + StaParams.supported_oper_classes_len = + params->supported_oper_classes_len; + + if (0 != params->ext_capab_len) + cdf_mem_copy(StaParams.extn_capability, + params->ext_capab, + sizeof(StaParams.extn_capability)); + + if (NULL != params->ht_capa) { + StaParams.htcap_present = 1; + cdf_mem_copy(&StaParams.HTCap, params->ht_capa, + sizeof(tSirHTCap)); + } + + StaParams.supported_rates_len = + params->supported_rates_len; + + /* Note : The Maximum sizeof supported_rates sent by the Supplicant is 32. + * The supported_rates array , for all the structures propogating till Add Sta + * to the firmware has to be modified , if the supplicant (ieee80211) is + * modified to send more rates. + */ + + /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES + */ + if (StaParams.supported_rates_len > + SIR_MAC_MAX_SUPP_RATES) + StaParams.supported_rates_len = + SIR_MAC_MAX_SUPP_RATES; + + if (0 != StaParams.supported_rates_len) { + int i = 0; + cdf_mem_copy(StaParams.supported_rates, + params->supported_rates, + StaParams.supported_rates_len); + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "Supported Rates with Length %d", + StaParams.supported_rates_len); + for (i = 0; i < StaParams.supported_rates_len; + i++) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "[%d]: %0x", i, + StaParams.supported_rates[i]); + } + + if (NULL != params->vht_capa) { + StaParams.vhtcap_present = 1; + cdf_mem_copy(&StaParams.VHTCap, + params->vht_capa, + sizeof(tSirVHTCap)); + } + + if (0 != params->ext_capab_len) { + /*Define A Macro : TODO Sunil */ + if ((1 << 4) & StaParams.extn_capability[3]) { + isBufSta = 1; + } + /* TDLS Channel Switching Support */ + if ((1 << 6) & StaParams.extn_capability[3]) { + isOffChannelSupported = 1; + } + } + + status = wlan_hdd_tdls_set_peer_caps(pAdapter, mac, + &StaParams, + isBufSta, + isOffChannelSupported); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL + ("wlan_hdd_tdls_set_peer_caps failed!")); + return -EINVAL; + } + + status = + wlan_hdd_tdls_add_station(wiphy, dev, mac, 1, + &StaParams); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("wlan_hdd_tdls_add_station failed!")); + return -EINVAL; + } + } +#endif + } + EXIT(); + return ret; +} + +/** + * wlan_hdd_change_station() - cfg80211 change station handler function + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * This is the cfg80211 change station handler function which invokes + * the internal function @__wlan_hdd_change_station with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) || defined(WITH_BACKPORTS) +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const u8 *mac, + struct station_parameters *params) +#else +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + u8 *mac, + struct station_parameters *params) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_change_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_add_key + * This function is used to initialize the key information + */ +static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + tCsrRoamSetKey setKey; + int status; + uint32_t roamId = 0xFF; +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(pAdapter))->pcds_context; +#endif + hdd_hostapd_state_t *pHostapdState; + CDF_STATUS cdf_ret_status; + hdd_context_t *pHddCtx; + hdd_ap_ctx_t *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_KEY, + pAdapter->sessionId, params->key_len)); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return status; + } + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + if (CSR_MAX_NUM_KEY <= key_index) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Invalid key index %d", + __func__, key_index); + + return -EINVAL; + } + + if (CSR_MAX_KEY_LEN < params->key_len) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Invalid key length %d", + __func__, params->key_len); + + return -EINVAL; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: called with key index = %d & key length %d", + __func__, key_index, params->key_len); + + /*extract key idx, key len and key */ + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = params->key_len; + cdf_mem_copy(&setKey.Key[0], params->key, params->key_len); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_WEP104: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_TKIP: + { + u8 *pKey = &setKey.Key[0]; + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + cdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /*Supplicant sends the 32bytes key in this order + + |--------------|----------|----------| + | Tk1 |TX-MIC | RX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + + */ + /*Sme expects the 32 bytes key to be in the below order + + |--------------|----------|----------| + | Tk1 |RX-MIC | TX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + */ + /* Copy the Temporal Key 1 (TK1) */ + cdf_mem_copy(pKey, params->key, 16); + + /*Copy the rx mic first */ + cdf_mem_copy(&pKey[16], ¶ms->key[24], 8); + + /*Copy the tx mic */ + cdf_mem_copy(&pKey[24], ¶ms->key[16], 8); + + break; + } + + case WLAN_CIPHER_SUITE_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + { + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + wlan_hdd_cfg80211_set_key_wapi(pAdapter, key_index, + mac_addr, params->key, + params->key_len); + return 0; + } +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + setKey.encType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + setKey.encType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + +#ifdef WLAN_FEATURE_11W + case WLAN_CIPHER_SUITE_AES_CMAC: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_CMAC; + break; +#endif + + default: + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: unsupported cipher type %u", + __func__, params->cipher); + return -EOPNOTSUPP; + } + + hddLog(CDF_TRACE_LEVEL_INFO_MED, "%s: encryption type %d", + __func__, setKey.encType); + + if (!pairwise) { + /* set group key */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s- %d: setting Broadcast key", __func__, __LINE__); + setKey.keyDirection = eSIR_RX_ONLY; + cdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + /* set pairwise key */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s- %d: setting pairwise key", __func__, __LINE__); + setKey.keyDirection = eSIR_TX_RX; + cdf_mem_copy(setKey.peerMac.bytes, mac_addr, CDF_MAC_ADDR_SIZE); + } + if ((WLAN_HDD_IBSS == pAdapter->device_mode) && !pairwise) { + /* if a key is already installed, block all subsequent ones */ + if (pAdapter->sessionCtx.station.ibss_enc_key_installed) { + hddLog(CDF_TRACE_LEVEL_INFO_MED, + "%s: IBSS key installed already", __func__); + return 0; + } + + setKey.keyDirection = eSIR_TX_RX; + /*Set the group key */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: sme_roam_set_key failed, returned %d", + __func__, status); + return -EINVAL; + } + /*Save the keys here and call sme_roam_set_key for setting + the PTK after peer joins the IBSS network */ + cdf_mem_copy(&pAdapter->sessionCtx.station.ibss_enc_key, + &setKey, sizeof(tCsrRoamSetKey)); + + pAdapter->sessionCtx.station.ibss_enc_key_installed = 1; + return status; + } + if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) || + (pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + if (pHostapdState->bssState == BSS_START) { +#ifdef WLAN_FEATURE_MBSSID + status = + wlansap_set_key_sta(WLAN_HDD_GET_SAP_CTX_PTR + (pAdapter), &setKey); +#else + status = wlansap_set_key_sta(p_cds_context, &setKey); +#endif + if (status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "[%4d] wlansap_set_key_sta returned ERROR status= %d", + __LINE__, status); + } + } + + /* Save the key in ap ctx for use on START_BASS and restart */ + if (pairwise || + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == setKey.encType || + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == setKey.encType) + cdf_mem_copy(&ap_ctx->wepKey[key_index], &setKey, + sizeof(tCsrRoamSetKey)); + else + cdf_mem_copy(&ap_ctx->groupKey, &setKey, + sizeof(tCsrRoamSetKey)); + + } else if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || + (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (!pairwise) { + /* set group key */ + if (pHddStaCtx->roam_info.deferKeyComplete) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s- %d: Perform Set key Complete", + __func__, __LINE__); + hdd_perform_roam_set_key_complete(pAdapter); + } + } + + pWextState->roamProfile.Keys.KeyLength[key_index] = + (u8) params->key_len; + + pWextState->roamProfile.Keys.defaultIndex = key_index; + + cdf_mem_copy(&pWextState->roamProfile.Keys. + KeyMaterial[key_index][0], params->key, + params->key_len); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + + hddLog(LOG2, + FL("Set key for peerMac "MAC_ADDRESS_STR" direction %d"), + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* The supplicant may attempt to set the PTK once pre-authentication + is done. Save the key in the UMAC and include it in the ADD BSS + request */ + cdf_ret_status = sme_ft_update_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey); + if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_INFO_MED, + "%s: Update PreAuth Key success", __func__); + return 0; + } else if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_FAILED) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Update PreAuth Key failed", __func__); + return -EINVAL; + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + /* issue set key request to SME */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: sme_roam_set_key failed, returned %d", + __func__, status); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + return -EINVAL; + } + + /* in case of IBSS as there was no information available about WEP keys during + * IBSS join, group key intialized with NULL key, so re-initialize group key + * with correct value*/ + if ((eCSR_BSS_TYPE_START_IBSS == + pWextState->roamProfile.BSSType) + && + !((IW_AUTH_KEY_MGMT_802_1X == + (pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType) + ) + && ((WLAN_CIPHER_SUITE_WEP40 == params->cipher) + || (WLAN_CIPHER_SUITE_WEP104 == params->cipher) + ) + ) { + setKey.keyDirection = eSIR_RX_ONLY; + cdf_set_macaddr_broadcast(&setKey.peerMac); + + hddLog(LOG2, + FL("Set key peerMac "MAC_ADDRESS_STR" direction %d"), + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, + &roamId); + + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: sme_roam_set_key failed for group key (IBSS), returned %d", + __func__, status); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + return -EINVAL; + } + } + } + + return 0; +} + +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_get_key + * This function is used to get the key information + */ +static int __wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + struct key_params params; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + memset(¶ms, 0, sizeof(params)); + + if (CSR_MAX_NUM_KEY <= key_index) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("invalid key index %d"), + key_index); + return -EINVAL; + } + + switch (pRoamProfile->EncryptionType.encryptionType[0]) { + case eCSR_ENCRYPT_TYPE_NONE: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + params.cipher = WLAN_CIPHER_SUITE_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + params.cipher = WLAN_CIPHER_SUITE_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + + default: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_KEY, + pAdapter->sessionId, params.cipher)); + + params.key_len = pRoamProfile->Keys.KeyLength[key_index]; + params.seq_len = 0; + params.seq = NULL; + params.key = &pRoamProfile->Keys.KeyMaterial[key_index][0]; + callback(cookie, ¶ms); + + EXIT(); + return 0; +} + +static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_key(wiphy, ndev, key_index, pairwise, + mac_addr, cookie, callback); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_key() - Delete the encryption key for station + * @wiphy: wiphy interface context + * @ndev: pointer to net device + * @key_index: Key index used in 802.11 frames + * @unicast: true if it is unicast key + * @multicast: true if it is multicast key + * + * This function is required for cfg80211_ops API. + * It is used to delete the key information + * Underlying hardware implementation does not have API to delete the + * encryption key. It is automatically deleted when the peer is + * removed. Hence this function currently does nothing. + * Future implementation may interprete delete key operation to + * replacing the key with a random junk value, effectively making it + * useless. + * + * Return: status code, always 0. + */ + +static int __wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_del_key() - cfg80211 delete key handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device structure. + * @key_index: key index + * @pairwise: pairwise + * @mac_addr: mac address + * + * This is the cfg80211 delete key handler function which invokes + * the internal function @__wlan_hdd_cfg80211_del_key with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index, + pairwise, mac_addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_set_default_key + * This function is used to set the default tx key index + */ +static int __wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY, + pAdapter->sessionId, key_index)); + + hddLog(LOG1, FL("Device_mode %s(%d) key_index = %d"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, key_index); + + if (CSR_MAX_NUM_KEY <= key_index) { + hddLog(LOGE, FL("Invalid key index %d"), key_index); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) || + (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + if ((eCSR_ENCRYPT_TYPE_TKIP != + pHddStaCtx->conn_info.ucEncryptionType) && + (eCSR_ENCRYPT_TYPE_AES != + pHddStaCtx->conn_info.ucEncryptionType)) { + /* If default key index is not same as previous one, + * then update the default key index */ + + tCsrRoamSetKey setKey; + uint32_t roamId = 0xFF; + tCsrKeys *Keys = &pWextState->roamProfile.Keys; + + hddLog(LOG2, FL("Default tx key index %d"), key_index); + + Keys->defaultIndex = (u8) key_index; + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = Keys->KeyLength[key_index]; + + cdf_mem_copy(&setKey.Key[0], + &Keys->KeyMaterial[key_index][0], + Keys->KeyLength[key_index]); + + setKey.keyDirection = eSIR_TX_RX; + + cdf_copy_macaddr(&setKey.peerMac, + &pHddStaCtx->conn_info.bssId); + + if (Keys->KeyLength[key_index] == CSR_WEP40_KEY_LEN && + pWextState->roamProfile.EncryptionType. + encryptionType[0] == eCSR_ENCRYPT_TYPE_WEP104) { + /* In the case of dynamic wep supplicant hardcodes DWEP type + * to eCSR_ENCRYPT_TYPE_WEP104 even though ap is configured for + * WEP-40 encryption. In this canse the key length is 5 but the + * encryption type is 104 hence checking the key langht(5) and + * encryption type(104) and switching encryption type to 40*/ + pWextState->roamProfile.EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + pWextState->roamProfile.mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + } + + setKey.encType = + pWextState->roamProfile.EncryptionType. + encryptionType[0]; + + /* Issue set key request */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, + &roamId); + + if (0 != status) { + hddLog(LOGE, + FL("sme_roam_set_key failed, returned %d"), + status); + return -EINVAL; + } + } + } else if (WLAN_HDD_SOFTAP == pAdapter->device_mode) { + /* In SoftAp mode setting key direction for default mode */ + if ((eCSR_ENCRYPT_TYPE_TKIP != + pWextState->roamProfile.EncryptionType.encryptionType[0]) + && (eCSR_ENCRYPT_TYPE_AES != + pWextState->roamProfile.EncryptionType. + encryptionType[0])) { + /* Saving key direction for default key index to TX default */ + hdd_ap_ctx_t *pAPCtx = + WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + pAPCtx->wepKey[key_index].keyDirection = + eSIR_TX_DEFAULT; + } + } + + EXIT(); + return status; +} + +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + int ret; + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, key_index, unicast, + multicast); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_update_bss_list() - update bss list to NL80211 + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_list(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + struct net_device *dev = pAdapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + tSirBssDescription *pBssDesc = pRoamInfo->pBssDesc; + int chan_no; + unsigned int freq; + struct ieee80211_channel *chan; + struct cfg80211_bss *bss = NULL; + + ENTER(); + + if (NULL == pBssDesc) { + hddLog(LOGE, FL("pBssDesc is NULL")); + return bss; + } + + if (NULL == pRoamInfo->pProfile) { + hddLog(LOGE, FL("Roam profile is NULL")); + return bss; + } + + chan_no = pBssDesc->channelId; + + if (chan_no <= ARRAY_SIZE(hdd_channels_2_4_ghz)) { + freq = + ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_2GHZ); + } else { + freq = + ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_5GHZ); + } + + chan = __ieee80211_get_channel(wiphy, freq); + + if (!chan) { + hddLog(LOGE, FL("chan pointer is NULL")); + return NULL; + } + + bss = cfg80211_get_bss(wiphy, chan, pBssDesc->bssId, + &pRoamInfo->pProfile->SSIDs.SSIDList->SSID. + ssId[0], + pRoamInfo->pProfile->SSIDs.SSIDList->SSID.length, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (bss == NULL) { + hddLog(LOGE, FL("BSS not present")); + } else { + hddLog(LOG1, FL("cfg80211_unlink_bss called for BSSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pBssDesc->bssId)); + cfg80211_unlink_bss(wiphy, bss); + } + return bss; +} + +/** + * wlan_hdd_cfg80211_inform_bss_frame() - inform bss details to NL80211 + * @pAdapter: Pointer to adapter + * @bss_desc: Pointer to bss descriptor + * + * This function is used to inform the BSS details to nl80211 interface. + * + * Return: struct cfg80211_bss pointer + */ +static struct cfg80211_bss * +wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, + tSirBssDescription *bss_desc) +{ + /* + * cfg80211_inform_bss() is not updating ie field of bss entry, if entry + * already exists in bss data base of cfg80211 for that particular BSS + * ID. Using cfg80211_inform_bss_frame to update the bss entry instead + * of cfg80211_inform_bss, But this call expects mgmt packet as input. + * As of now there is no possibility to get the mgmt(probe response) + * frame from PE, converting bss_desc to ieee80211_mgmt(probe response) + * and passing to cfg80211_inform_bss_frame. + */ + struct net_device *dev = pAdapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + int chan_no = bss_desc->channelId; +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS + qcom_ie_age *qie_age = NULL; + int ie_length = + GET_IE_LEN_IN_BSS_DESC(bss_desc->length) + sizeof(qcom_ie_age); +#else + int ie_length = GET_IE_LEN_IN_BSS_DESC(bss_desc->length); +#endif + const char *ie = + ((ie_length != 0) ? (const char *)&bss_desc->ieFields : NULL); + unsigned int freq; + struct ieee80211_channel *chan; + struct ieee80211_mgmt *mgmt = NULL; + struct cfg80211_bss *bss_status = NULL; + size_t frame_len = sizeof(struct ieee80211_mgmt) + ie_length; + int rssi = 0; + hdd_context_t *pHddCtx; + int status; +#ifdef CONFIG_CNSS + struct timespec ts; +#endif + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return NULL; + } + + mgmt = kzalloc((sizeof(struct ieee80211_mgmt) + ie_length), GFP_KERNEL); + if (!mgmt) { + hddLog(LOGE, FL("memory allocation failed")); + return NULL; + } + + memcpy(mgmt->bssid, bss_desc->bssId, ETH_ALEN); + +#ifdef CONFIG_CNSS + /* Android does not want the timestamp from the frame. + Instead it wants a monotonic increasing value */ + cnss_get_monotonic_boottime(&ts); + mgmt->u.probe_resp.timestamp = + ((u64) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +#else + /* keep old behavior for non-open source (for now) */ + memcpy(&mgmt->u.probe_resp.timestamp, bss_desc->timeStamp, + sizeof(bss_desc->timeStamp)); + +#endif + + mgmt->u.probe_resp.beacon_int = bss_desc->beaconInterval; + mgmt->u.probe_resp.capab_info = bss_desc->capabilityInfo; + +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS + /* GPS Requirement: need age ie per entry. Using vendor specific. */ + /* Assuming this is the last IE, copy at the end */ + ie_length -= sizeof(qcom_ie_age); + qie_age = (qcom_ie_age *) (mgmt->u.probe_resp.variable + ie_length); + qie_age->element_id = QCOM_VENDOR_IE_ID; + qie_age->len = QCOM_VENDOR_IE_AGE_LEN; + qie_age->oui_1 = QCOM_OUI1; + qie_age->oui_2 = QCOM_OUI2; + qie_age->oui_3 = QCOM_OUI3; + qie_age->type = QCOM_VENDOR_IE_AGE_TYPE; + qie_age->age = + cdf_mc_timer_get_system_ticks() - bss_desc->nReceivedTime; + qie_age->tsf_delta = bss_desc->tsf_delta; +#endif + + memcpy(mgmt->u.probe_resp.variable, ie, ie_length); + if (bss_desc->fProbeRsp) { + mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); + } else { + mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); + } + + if (chan_no <= ARRAY_SIZE(hdd_channels_2_4_ghz) && + (wiphy->bands[IEEE80211_BAND_2GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_2GHZ); + } else if ((chan_no > ARRAY_SIZE(hdd_channels_2_4_ghz)) + && (wiphy->bands[IEEE80211_BAND_5GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(chan_no, + IEEE80211_BAND_5GHZ); + } else { + hddLog(LOGE, FL("Invalid chan_no %d"), chan_no); + kfree(mgmt); + return NULL; + } + + chan = __ieee80211_get_channel(wiphy, freq); + /* When the band is changed on the fly using the GUI, three things are done + * 1. scan abort + * 2. flush scan results from cache + * 3. update the band with the new band user specified (refer to the + * hdd_set_band_helper function) as part of the scan abort, message will be + * queued to PE and we proceed with flushing and changinh the band. + * PE will stop the scanning further and report back the results what ever + * it had till now by calling the call back function. + * if the time between update band and scandone call back is sufficient + * enough the band change reflects in SME, SME validates the channels + * and discards the channels correponding to previous band and calls back + * with zero bss results. but if the time between band update and scan done + * callback is very small then band change will not reflect in SME and SME + * reports to HDD all the channels correponding to previous band.this is due + * to race condition.but those channels are invalid to the new band and so + * this function __ieee80211_get_channel will return NULL.Each time we + * report scan result with this pointer null warning kernel trace is printed. + * if the scan results contain large number of APs continuosly kernel + * warning trace is printed and it will lead to apps watch dog bark. + * So drop the bss and continue to next bss. + */ + if (chan == NULL) { + hddLog(LOGE, FL("chan pointer is NULL")); + kfree(mgmt); + return NULL; + } + + /* Supplicant takes the signal strength in terms of mBm(100*dBm) */ + rssi = (CDF_MIN((bss_desc->rssi + bss_desc->sinr), 0)) * 100; + + hddLog(LOG1, FL("BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d"), + MAC_ADDR_ARRAY(mgmt->bssid), chan->center_freq, + (int)(rssi / 100)); + + bss_status = + cfg80211_inform_bss_frame(wiphy, chan, mgmt, frame_len, rssi, + GFP_KERNEL); + kfree(mgmt); + return bss_status; +} + +/** + * wlan_hdd_cfg80211_update_bss_db() - update bss database of CF80211 + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * This function is used to update the BSS data base of CFG8011 + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + tCsrRoamConnectedProfile roamProfile; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + struct cfg80211_bss *bss = NULL; + + ENTER(); + + memset(&roamProfile, 0, sizeof(tCsrRoamConnectedProfile)); + sme_roam_get_connect_profile(hHal, pAdapter->sessionId, &roamProfile); + + if (NULL != roamProfile.pBssDesc) { + bss = wlan_hdd_cfg80211_inform_bss_frame(pAdapter, + roamProfile.pBssDesc); + + if (NULL == bss) + hddLog(LOG1, + FL("wlan_hdd_cfg80211_inform_bss_frame returned NULL")); + + sme_roam_free_connect_profile(hHal, &roamProfile); + } else { + hddLog(LOGE, FL("roamProfile.pBssDesc is NULL")); + } + EXIT(); + return bss; +} +/** + * wlan_hdd_cfg80211_update_bss() - update bss + * @wiphy: Pointer to wiphy + * @pAdapter: Pointer to adapter + * @scan_time: scan request timestamp + * + * Return: zero if success, non-zero otherwise + */ +int wlan_hdd_cfg80211_update_bss(struct wiphy *wiphy, + hdd_adapter_t *pAdapter, + uint32_t scan_time) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tCsrScanResultInfo *pScanResult; + CDF_STATUS status = 0; + tScanResultHandle pResult; + struct cfg80211_bss *bss_status = NULL; + hdd_context_t *pHddCtx; + int ret; + + ENTER(); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_BSS, + NO_SESSION, pAdapter->sessionId)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + /* start getting scan results and populate cgf80211 BSS database */ + status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult); + + /* no scan results */ + if (NULL == pResult) { + hddLog(LOGE, FL("No scan result Status %d"), status); + return status; + } + + pScanResult = sme_scan_result_get_first(hHal, pResult); + + while (pScanResult) { + /* + * - cfg80211_inform_bss() is not updating ie field of bss + * entry if entry already exists in bss data base of cfg80211 + * for that particular BSS ID. Using cfg80211_inform_bss_frame + * to update thebss entry instead of cfg80211_inform_bss, + * But this call expects mgmt packet as input. As of now + * there is no possibility to get the mgmt(probe response) + * frame from PE, converting bss_desc to + * ieee80211_mgmt(probe response) and passing to c + * fg80211_inform_bss_frame. + * - Update BSS only if beacon timestamp is later than + * scan request timestamp. + */ + if ((scan_time == 0) || + (scan_time < + pScanResult->BssDescriptor.nReceivedTime)) { + bss_status = + wlan_hdd_cfg80211_inform_bss_frame(pAdapter, + &pScanResult->BssDescriptor); + + if (NULL == bss_status) { + hdd_info("NULL returned by cfg80211_inform_bss_frame"); + } else { + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) + wiphy, +#endif + bss_status); + } + } else { + hdd_info("BSSID: " MAC_ADDRESS_STR " Skipped", + MAC_ADDR_ARRAY(pScanResult->BssDescriptor.bssId)); + } + pScanResult = sme_scan_result_get_next(hHal, pResult); + } + + sme_scan_result_purge(hHal, pResult); + /* + * For SAP mode, scan is invoked by hostapd during SAP start + * if hostapd is restarted, we need to flush previous scan + * result so that it will reflect environment change + */ + if (pAdapter->device_mode == WLAN_HDD_SOFTAP +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + && pHddCtx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN +#endif + ) + sme_scan_flush_result(hHal); + + EXIT(); + return 0; +} + +#if defined(FEATURE_WLAN_LFR) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +/** + * wlan_hdd_cfg80211_pmksa_candidate_notify() - notify a new PMSKA candidate + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * @index: Index + * @preauth: Preauth flag + * + * This function is used to notify the supplicant of a new PMKSA candidate. + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_pmksa_candidate_notify(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + int index, bool preauth) +{ +#ifdef FEATURE_WLAN_OKC + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx; + + ENTER(); + hddLog(LOG1, FL("is going to notify supplicant of:")); + + if (NULL == pRoamInfo) { + hddLog(LOGP, FL("pRoamInfo is NULL")); + return -EINVAL; + } + + if (true == hdd_is_okc_mode_enabled(pHddCtx)) { + hddLog(LOG1, MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes)); + cfg80211_pmksa_candidate_notify(dev, index, + pRoamInfo->bssid.bytes, + preauth, GFP_KERNEL); + } +#endif /* FEATURE_WLAN_OKC */ + return 0; +} +#endif /* FEATURE_WLAN_LFR */ + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * wlan_hdd_cfg80211_roam_metrics_preauth() - roam metrics preauth + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report preauth initiation + * + * Return: CDF status + */ +#define MAX_LFR_METRICS_EVENT_LENGTH 100 +CDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL!")); + return CDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_INIT " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid)); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * @preauth_status: Preauth status + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: CDF status + */ +CDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth_status(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + bool preauth_status) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL!")); + return CDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + scnprintf(metrics_notification, sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_STATUS " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid)); + + if (1 == preauth_status) + strlcat(metrics_notification, " true", + sizeof(metrics_notification)); + else + strlcat(metrics_notification, " false", + sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = strlen(metrics_notification); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: CDF status + */ +CDF_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL!")); + return CDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_HANDOVER " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid)); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_select_cbmode() - select channel bonding mode + * @pAdapter: Pointer to adapter + * @operatingChannel: Operating channel + * + * Return: none + */ +void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel) +{ + uint8_t iniDot11Mode = (WLAN_HDD_GET_CTX(pAdapter))->config->dot11Mode; + eHddDot11Mode hddDot11Mode = iniDot11Mode; + chan_params_t ch_params; + ch_params.ch_width = + (WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth; + + hddLog(LOG1, FL("Channel Bonding Mode Selected is %u"), iniDot11Mode); + switch (iniDot11Mode) { + case eHDD_DOT11_MODE_AUTO: + case eHDD_DOT11_MODE_11ac: + case eHDD_DOT11_MODE_11ac_ONLY: +#ifdef WLAN_FEATURE_11AC + if (sme_is_feature_supported_by_fw(DOT11AC)) + hddDot11Mode = eHDD_DOT11_MODE_11ac; + else + hddDot11Mode = eHDD_DOT11_MODE_11n; +#else + hddDot11Mode = eHDD_DOT11_MODE_11n; +#endif + break; + case eHDD_DOT11_MODE_11n: + case eHDD_DOT11_MODE_11n_ONLY: + hddDot11Mode = eHDD_DOT11_MODE_11n; + break; + default: + hddDot11Mode = iniDot11Mode; + break; + } + /* This call decides required channel bonding mode */ + sme_set_ch_params((WLAN_HDD_GET_CTX(pAdapter)->hHal), + hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode), + operationChannel, 0, + &ch_params); +} + + +/* + * FUNCTION: wlan_hdd_cfg80211_connect_start + * wlan_hdd_cfg80211_connect_start() - start connection + * @pAdapter: Pointer to adapter + * @ssid: Pointer ot ssid + * @ssid_len: Length of ssid + * @bssid: Pointer to bssid + * @operatingChannel: Operating channel + * + * This function is used to start the association process + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter, + const u8 *ssid, size_t ssid_len, + const u8 *bssid_hint, const u8 *bssid, + u8 operatingChannel) +{ + int status = 0; + hdd_wext_state_t *pWextState; + hdd_context_t *pHddCtx; + uint32_t roamId; + tCsrRoamProfile *pRoamProfile; + eCsrAuthType RSNAuthType; + tSmeConfigParams *sme_config; + + ENTER(); + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + status = wlan_hdd_validate_context(pHddCtx); + if (status) { + hddLog(LOGE, + FL("HDD context is not valid!")); + return status; + } + + if (SIR_MAC_MAX_SSID_LENGTH < ssid_len) { + hddLog(LOGE, FL("wrong SSID len")); + return -EINVAL; + } + + pRoamProfile = &pWextState->roamProfile; + + if (pRoamProfile) { + hdd_station_ctx_t *pHddStaCtx; + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) { + /*QoS not enabled in cfg file */ + pRoamProfile->uapsd_mask = 0; + } else { + /*QoS enabled, update uapsd mask from cfg file */ + pRoamProfile->uapsd_mask = + (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask; + } + + pRoamProfile->SSIDs.numOfSSIDs = 1; + pRoamProfile->SSIDs.SSIDList->SSID.length = ssid_len; + cdf_mem_zero(pRoamProfile->SSIDs.SSIDList->SSID.ssId, + sizeof(pRoamProfile->SSIDs.SSIDList->SSID.ssId)); + cdf_mem_copy((void *)(pRoamProfile->SSIDs.SSIDList->SSID.ssId), + ssid, ssid_len); + + if (bssid) { + pRoamProfile->BSSIDs.numOfBSSIDs = 1; + cdf_mem_copy((void *)(pRoamProfile->BSSIDs.bssid), + bssid, CDF_MAC_ADDR_SIZE); + /* Save BSSID in seperate variable as well, as RoamProfile + BSSID is getting zeroed out in the association process. And in + case of join failure we should send valid BSSID to supplicant + */ + cdf_mem_copy((void *)(pWextState->req_bssId.bytes), + bssid, CDF_MAC_ADDR_SIZE); + } else if (bssid_hint) { + pRoamProfile->BSSIDs.numOfBSSIDs = 1; + cdf_mem_copy((void *)(pRoamProfile->BSSIDs.bssid), + bssid_hint, CDF_MAC_ADDR_SIZE); + /* Save BSSID in separate variable as well, as + RoamProfile BSSID is getting zeroed out in the + association process. And in case of join failure + we should send valid BSSID to supplicant + */ + cdf_mem_copy((void *)(pWextState->req_bssId.bytes), + bssid_hint, CDF_MAC_ADDR_SIZE); + hddLog(LOGW, FL(" bssid_hint "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(bssid_hint)); + } else { + cdf_mem_zero((void *)(pRoamProfile->BSSIDs.bssid), + CDF_MAC_ADDR_SIZE); + } + + hddLog(LOG1, FL("Connect to SSID: %.*s operating Channel: %u"), + pRoamProfile->SSIDs.SSIDList->SSID.length, + pRoamProfile->SSIDs.SSIDList->SSID.ssId, + operatingChannel); + + if ((IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion) || + (IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion)) { + /*set gen ie */ + hdd_set_genie_to_csr(pAdapter, &RSNAuthType); + /*set auth */ + hdd_set_csr_auth_type(pAdapter, RSNAuthType); + } +#ifdef FEATURE_WLAN_WAPI + if (pAdapter->wapi_info.nWapiMode) { + hddLog(LOG1, + FL("Setting WAPI AUTH Type and Encryption Mode values")); + switch (pAdapter->wapi_info.wapiAuthMode) { + case WAPI_AUTH_MODE_PSK: + { + hddLog(LOG1, + FL("WAPI AUTH TYPE: PSK: %d"), + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_PSK; + break; + } + case WAPI_AUTH_MODE_CERT: + { + hddLog(LOG1, + FL("WAPI AUTH TYPE: CERT: %d"), + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + break; + } + } /* End of switch */ + if (pAdapter->wapi_info.wapiAuthMode == + WAPI_AUTH_MODE_PSK + || pAdapter->wapi_info.wapiAuthMode == + WAPI_AUTH_MODE_CERT) { + hddLog(LOG1, + FL("WAPI PAIRWISE/GROUP ENCRYPTION: WPI")); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WPI; + } + } +#endif /* FEATURE_WLAN_WAPI */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD + /* Initializing gtkOffloadReqParams */ + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + memset(&pHddStaCtx->gtkOffloadReqParams, 0, + sizeof(tSirGtkOffloadParams)); + pHddStaCtx->gtkOffloadReqParams.ulFlags = + GTK_OFFLOAD_DISABLE; + } +#endif + pRoamProfile->csrPersona = pAdapter->device_mode; + + if (operatingChannel) { + pRoamProfile->ChannelInfo.ChannelList = + &operatingChannel; + pRoamProfile->ChannelInfo.numOfChannels = 1; + } else { + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + } + if ((WLAN_HDD_IBSS == pAdapter->device_mode) + && operatingChannel) { + /* + * Need to post the IBSS power save parameters + * to WMA. WMA will configure this parameters + * to firmware if power save is enabled by the + * firmware. + */ + status = hdd_set_ibss_power_save_params(pAdapter); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, + FL("Set IBSS Power Save Params Failed")); + return -EINVAL; + } + hdd_select_cbmode(pAdapter, operatingChannel); + } + + if (pHddCtx->config->policy_manager_enabled && + (true == cds_is_connection_in_progress(pHddCtx))) { + hdd_err("Connection refused: conn in progress"); + return -EINVAL; + } + + /* change conn_state to connecting before sme_roam_connect(), because sme_roam_connect() + * has a direct path to call hdd_sme_roam_callback(), which will change the conn_state + * If direct path, conn_state will be accordingly changed to NotConnected or Associated + * by either hdd_association_completion_handler() or hdd_dis_connect_handler() in sme_RoamCallback() + * if sme_RomConnect is to be queued, Connecting state will remain until it is completed. + */ + if (WLAN_HDD_INFRA_STATION == pAdapter->device_mode || + WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) { + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_Connecting")); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Connecting); + } + + /* After 8-way handshake supplicant should give the scan command + * in that it update the additional IEs, But because of scan + * enhancements, the supplicant is not issuing the scan command now. + * So the unicast frames which are sent from the host are not having + * the additional IEs. If it is P2P CLIENT and there is no additional + * IE present in roamProfile, then use the addtional IE form scan_info + */ + + if ((pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) && + (!pRoamProfile->pAddIEScan)) { + pRoamProfile->pAddIEScan = + &pAdapter->scan_info.scanAddIE.addIEdata[0]; + pRoamProfile->nAddIEScanLength = + pAdapter->scan_info.scanAddIE.length; + } + /* + * When policy manager is enabled from ini file, we shouldn't + * check for other concurrency rules. + */ + if (!pHddCtx->config->policy_manager_enabled) { + cds_handle_conc_rule1(pHddCtx, pAdapter, + pRoamProfile); + if (true != cds_handle_conc_rule2(pHddCtx, + pAdapter, pRoamProfile, &roamId)) + return 0; + } + + sme_config = cdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("unable to allocate sme_config"); + return -ENOMEM; + } + cdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(pHddCtx->hHal, sme_config); + /* These values are not sessionized. So, any change in these SME + * configs on an older or parallel interface will affect the + * cb mode. So, restoring the default INI params before starting + * interfaces such as sta, cli etc., + */ + sme_config->csrConfig.channelBondingMode5GHz = + pHddCtx->config->nChannelBondingMode5GHz; + sme_config->csrConfig.channelBondingMode24GHz = + pHddCtx->config->nChannelBondingMode24GHz; + sme_update_config(pHddCtx->hHal, sme_config); + cdf_mem_free(sme_config); + + status = sme_roam_connect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, pRoamProfile, + &roamId); + + if ((CDF_STATUS_SUCCESS != status) && + (WLAN_HDD_INFRA_STATION == pAdapter->device_mode || + WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + hddLog(LOGE, + FL("sme_roam_connect (session %d) failed with " + "status %d. -> NotConnected"), + pAdapter->sessionId, status); + /* change back to NotAssociated */ + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + } + + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + + } else { + hddLog(LOGE, FL("No valid Roam profile")); + return -EINVAL; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_auth_type() - set auth type + * @pAdapter: Pointer to adapter + * @auth_type: Auth type + * + * This function is used to set the authentication type (OPEN/SHARED). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter, + enum nl80211_auth_type auth_type) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + /*set authentication type */ + switch (auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + hddLog(LOG1, + FL("set authentication type to AUTOSWITCH")); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_AUTOSWITCH; + break; + + case NL80211_AUTHTYPE_OPEN_SYSTEM: +#ifdef WLAN_FEATURE_VOWIFI_11R + case NL80211_AUTHTYPE_FT: +#endif /* WLAN_FEATURE_VOWIFI_11R */ + hddLog(LOG1, + FL("set authentication type to OPEN")); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + hddLog(LOG1, + FL("set authentication type to SHARED")); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_SHARED_KEY; + break; +#ifdef FEATURE_WLAN_ESE + case NL80211_AUTHTYPE_NETWORK_EAP: + hddLog(LOG1, + FL("set authentication type to CCKM WPA")); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA; + break; +#endif + + default: + hddLog(LOGE, + FL("Unsupported authentication type %d"), auth_type); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN; + return -EINVAL; + } + + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType; + return 0; +} + +/** + * wlan_hdd_set_akm_suite() - set key management type + * @pAdapter: Pointer to adapter + * @key_mgmt: Key management type + * + * This function is used to set the key mgmt type(PSK/8021x). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + ENTER(); + +#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05 +#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06 + /*set key mgmt type */ + switch (key_mgmt) { + case WLAN_AKM_SUITE_PSK: + case WLAN_AKM_SUITE_PSK_SHA256: +#ifdef WLAN_FEATURE_VOWIFI_11R + case WLAN_AKM_SUITE_FT_PSK: +#endif + hddLog(LOG1, FL("setting key mgmt type to PSK")); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK; + break; + + case WLAN_AKM_SUITE_8021X_SHA256: + case WLAN_AKM_SUITE_8021X: +#ifdef WLAN_FEATURE_VOWIFI_11R + case WLAN_AKM_SUITE_FT_8021X: +#endif + hddLog(LOG1, + FL("setting key mgmt type to 8021x")); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + break; +#ifdef FEATURE_WLAN_ESE +#define WLAN_AKM_SUITE_CCKM 0x00409600 /* Should be in ieee802_11_defs.h */ +#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */ + case WLAN_AKM_SUITE_CCKM: + hddLog(LOG1, + FL("setting key mgmt type to CCKM")); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_CCKM; + break; +#endif +#ifndef WLAN_AKM_SUITE_OSEN +#define WLAN_AKM_SUITE_OSEN 0x506f9a01 /* Should be in ieee802_11_defs.h */ +#endif + case WLAN_AKM_SUITE_OSEN: + hddLog(LOG1, + FL("setting key mgmt type to OSEN")); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + break; + + default: + hddLog(LOGE, + FL("Unsupported key mgmt type %d"), key_mgmt); + return -EINVAL; + + } + return 0; +} + +/** + * wlan_hdd_cfg80211_set_cipher() - set encryption type + * @pAdapter: Pointer to adapter + * @cipher: Cipher type + * @ucast: Unicast flag + * + * This function is used to set the encryption type + * (NONE/WEP40/WEP104/TKIP/CCMP). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_cipher(hdd_adapter_t *pAdapter, + u32 cipher, bool ucast) +{ + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + if (!cipher) { + hddLog(LOGE, + FL("received cipher %d - considering none"), cipher); + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else { + + /*set encryption method */ + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case WLAN_CIPHER_SUITE_WEP40: + encryptionType = eCSR_ENCRYPT_TYPE_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + encryptionType = eCSR_ENCRYPT_TYPE_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + encryptionType = eCSR_ENCRYPT_TYPE_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + encryptionType = eCSR_ENCRYPT_TYPE_AES; + break; +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + encryptionType = eCSR_ENCRYPT_TYPE_WPI; + break; +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + encryptionType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + encryptionType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + default: + hddLog(LOGE, + FL("Unsupported cipher type %d"), cipher); + return -EOPNOTSUPP; + } + } + + if (ucast) { + hddLog(LOG1, + FL("setting unicast cipher type to %d"), encryptionType); + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + } else { + hddLog(LOG1, + FL("setting mcast cipher type to %d"), encryptionType); + pHddStaCtx->conn_info.mcEncryptionType = encryptionType; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + encryptionType; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ie() - set IEs + * @pAdapter: Pointer to adapter + * @ie: Pointer ot ie + * @ie: IE length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_ie(hdd_adapter_t *pAdapter, const uint8_t *ie, + size_t ie_len) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + const uint8_t *genie = ie; + uint16_t remLen = ie_len; +#ifdef FEATURE_WLAN_WAPI + uint32_t akmsuite[MAX_NUM_AKM_SUITES]; + u16 *tmp; + uint16_t akmsuiteCount; + int *akmlist; +#endif + ENTER(); + + /* clear previous assocAddIE */ + pWextState->assocAddIE.length = 0; + pWextState->roamProfile.bWPSAssociation = false; + pWextState->roamProfile.bOSENAssociation = false; + + while (remLen >= 2) { + uint16_t eLen = 0; + uint8_t elementId; + elementId = *genie++; + eLen = *genie++; + remLen -= 2; + + hddLog(LOG1, FL("IE[0x%X], LEN[%d]"), elementId, eLen); + + switch (elementId) { + case DOT11F_EID_WPA: + if (4 > eLen) { /* should have at least OUI which is 4 bytes so extra 2 bytes not needed */ + hddLog(LOGE, FL("Invalid WPA IE")); + return -EINVAL; + } else if (0 == + memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set WPS IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, + FL("Cannot accommodate assocAddIE. Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + /* WSC IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.bWPSAssociation = true; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) { + hddLog(LOG1, + FL("Set WPA IE (len %d)"), eLen + 2); + memset(pWextState->WPARSNIE, 0, + MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pWPAReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nWPAReqIELength = eLen + 2; /* ie_len; */ + } else if ((0 == memcmp(&genie[0], P2P_OUI_TYPE, + P2P_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set P2P IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, + FL("Cannot accommodate assocAddIE Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + /* P2P IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } +#ifdef WLAN_FEATURE_WFD + else if ((0 == memcmp(&genie[0], WFD_OUI_TYPE, + WFD_OUI_TYPE_SIZE)) && + /* Consider WFD IE, only for P2P Client */ + (WLAN_HDD_P2P_CLIENT == + pAdapter->device_mode)) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set WFD IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, + FL("Cannot accommodate assocAddIE Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + /* WFD IE is saved to Additional IE ; it should + * be accumulated to handle WPS IE + P2P IE + + * WFD IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } +#endif + /* Appending HS 2.0 Indication Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], HS20_OUI_TYPE, + HS20_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set HS20 IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, + FL("Cannot accommodate assocAddIE Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } + /* Appending OSEN Information Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], OSEN_OUI_TYPE, + OSEN_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set OSEN IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, + FL("Cannot accommodate assocAddIE Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.bOSENAssociation = true; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } else { + uint16_t add_ie_len = + pWextState->assocAddIE.length; + + hdd_info("Set OSEN IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + CDF_ASSERT(0); + return -ENOMEM; + } + + memcpy(pWextState->assocAddIE.addIEdata + + add_ie_len, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } + break; + case DOT11F_EID_RSN: + hddLog(LOG1, FL("Set RSN IE(len %d)"), eLen + 2); + memset(pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pRSNReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nRSNReqIELength = eLen + 2; /* ie_len; */ + break; + /* + * Appending Extended Capabilities with Interworking bit set + * in Assoc Req. + * + * In assoc req this EXT Cap will only be taken into account if + * interworkingService bit is set to 1. Currently + * driver is only interested in interworkingService capability + * from supplicant. If in future any other EXT Cap info is + * required from supplicat, it needs to be handled while + * sending Assoc Req in LIM. + */ + case DOT11F_EID_EXTCAP: + { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hddLog(LOG1, + FL("Set Extended CAPS IE(len %d)"), eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hddLog(LOGE, FL("Cannot accommodate assocAddIE Need bigger buffer space")); + CDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + break; + } +#ifdef FEATURE_WLAN_WAPI + case WLAN_EID_WAPI: + /* Setting WAPI Mode to ON=1 */ + pAdapter->wapi_info.nWapiMode = 1; + hddLog(LOG1, + FL("WAPI MODE IS %u"), pAdapter->wapi_info.nWapiMode); + tmp = (u16 *) ie; + tmp = tmp + 2; /* Skip element Id and Len, Version */ + akmsuiteCount = WPA_GET_LE16(tmp); + tmp = tmp + 1; + akmlist = (int *)(tmp); + if (akmsuiteCount <= MAX_NUM_AKM_SUITES) { + memcpy(akmsuite, akmlist, (4 * akmsuiteCount)); + } else { + hddLog(LOGE, + FL("Invalid akmSuite count")); + CDF_ASSERT(0); + return -EINVAL; + } + + if (WAPI_PSK_AKM_SUITE == akmsuite[0]) { + hddLog(LOG1, + FL("WAPI AUTH MODE SET TO PSK")); + pAdapter->wapi_info.wapiAuthMode = + WAPI_AUTH_MODE_PSK; + } + if (WAPI_CERT_AKM_SUITE == akmsuite[0]) { + hddLog(LOG1, + FL("WAPI AUTH MODE SET TO CERTIFICATE")); + pAdapter->wapi_info.wapiAuthMode = + WAPI_AUTH_MODE_CERT; + } + break; +#endif + default: + hddLog(LOGE, + FL("Set UNKNOWN IE %X"), elementId); + /* when Unknown IE is received we should break and continue + * to the next IE in the buffer instead we were returning + * so changing this to break */ + break; + } + genie += eLen; + remLen -= eLen; + } + EXIT(); + return 0; +} + +/** + * hdd_is_wpaie_present() - check for WPA ie + * @ie: Pointer to ie + * @ie_len: Ie length + * + * Parse the received IE to find the WPA IE + * + * Return: true if wpa ie is found else false + */ +static bool hdd_is_wpaie_present(const uint8_t *ie, uint8_t ie_len) +{ + uint8_t eLen = 0; + uint16_t remLen = ie_len; + uint8_t elementId = 0; + + while (remLen >= 2) { + elementId = *ie++; + eLen = *ie++; + remLen -= 2; + if (eLen > remLen) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: IE length is wrong %d", __func__, eLen); + return false; + } + if ((elementId == DOT11F_EID_WPA) && (remLen > 5)) { + /* OUI - 0x00 0X50 0XF2 + * WPA Information Element - 0x01 + * WPA version - 0x01 + */ + if (0 == memcmp(&ie[0], "\x00\x50\xf2\x01\x01", 5)) + return true; + } + ie += eLen; + remLen -= eLen; + } + return false; +} + +/** + * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection + * @pAdapter: Pointer to adapter + * @req: Pointer to security parameters + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_privacy(hdd_adapter_t *pAdapter, + struct cfg80211_connect_params *req) +{ + int status = 0; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + ENTER(); + + /*set wpa version */ + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + + if (req->crypto.wpa_versions) { + if (NL80211_WPA_VERSION_1 == req->crypto.wpa_versions) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA; + } else if (NL80211_WPA_VERSION_2 == req->crypto.wpa_versions) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2; + } + } + + hddLog(LOG1, FL("set wpa version to %d"), pWextState->wpaVersion); + + /*set authentication type */ + status = wlan_hdd_cfg80211_set_auth_type(pAdapter, req->auth_type); + + if (0 > status) { + hddLog(LOGE, FL("failed to set authentication type ")); + return status; + } + + /*set key mgmt type */ + if (req->crypto.n_akm_suites) { + status = + wlan_hdd_set_akm_suite(pAdapter, req->crypto.akm_suites[0]); + if (0 > status) { + hddLog(LOGE, FL("failed to set akm suite")); + return status; + } + } + + /*set pairwise cipher type */ + if (req->crypto.n_ciphers_pairwise) { + status = wlan_hdd_cfg80211_set_cipher(pAdapter, + req->crypto. + ciphers_pairwise[0], + true); + if (0 > status) { + hddLog(LOGE, FL("failed to set unicast cipher type")); + return status; + } + } else { + /*Reset previous cipher suite to none */ + status = wlan_hdd_cfg80211_set_cipher(pAdapter, 0, true); + if (0 > status) { + hddLog(LOGE, FL("failed to set unicast cipher type")); + return status; + } + } + + /*set group cipher type */ + status = + wlan_hdd_cfg80211_set_cipher(pAdapter, req->crypto.cipher_group, + false); + + if (0 > status) { + hddLog(LOGE, FL("failed to set mcast cipher type")); + return status; + } +#ifdef WLAN_FEATURE_11W + pWextState->roamProfile.MFPEnabled = (req->mfp == NL80211_MFP_REQUIRED); +#endif + + /*parse WPA/RSN IE, and set the correspoing fileds in Roam profile */ + if (req->ie_len) { + status = + wlan_hdd_cfg80211_set_ie(pAdapter, req->ie, req->ie_len); + if (0 > status) { + hddLog(LOGE, FL("failed to parse the WPA/RSN IE")); + return status; + } + } + + /*incase of WEP set default key information */ + if (req->key && req->key_len) { + if ((WLAN_CIPHER_SUITE_WEP40 == req->crypto.ciphers_pairwise[0]) + || (WLAN_CIPHER_SUITE_WEP104 == + req->crypto.ciphers_pairwise[0]) + ) { + if (IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) { + hddLog(LOGE, + FL("Dynamic WEP not supported")); + return -EOPNOTSUPP; + } else { + u8 key_len = req->key_len; + u8 key_idx = req->key_idx; + + if ((eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES >= + key_len) + && (CSR_MAX_NUM_KEY > key_idx) + ) { + hddLog(LOG1, + FL("setting default wep key, key_idx = %hu key_len %hu"), + key_idx, key_len); + cdf_mem_copy(&pWextState->roamProfile. + Keys. + KeyMaterial[key_idx][0], + req->key, key_len); + pWextState->roamProfile.Keys. + KeyLength[key_idx] = (u8) key_len; + pWextState->roamProfile.Keys. + defaultIndex = (u8) key_idx; + } + } + } + } + + return status; +} + +/** + * wlan_hdd_try_disconnect() - try disconnnect from previous connection + * @pAdapter: Pointer to adapter + * + * This function is used to disconnect from previous connection + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter) +{ + unsigned long rc; + hdd_station_ctx_t *pHddStaCtx; + eMib_dot11DesiredBssType connectedBssType; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + hdd_conn_get_connected_bss_type(pHddStaCtx, &connectedBssType); + + if ((eMib_dot11DesiredBssType_independent == connectedBssType) || + (eConnectionState_Associated == pHddStaCtx->conn_info.connState) || + (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)) { + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + /* Issue disconnect to CSR */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + if (CDF_STATUS_SUCCESS == + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED)) { + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hddLog(LOGE, + FL("Sme disconnect event timed out session Id %d staDebugState %d"), + pAdapter->sessionId, + pHddStaCtx->staDebugState); + return -EALREADY; + } + } + } else if (eConnectionState_Disconnecting == + pHddStaCtx->conn_info.connState) { + rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hddLog(LOGE, + FL("Disconnect event timed out session Id %d staDebugState %d"), + pAdapter->sessionId, pHddStaCtx->staDebugState); + return -EALREADY; + } + } + + return 0; +} + +/** + * __wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * This function is used to start the association process + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int status; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CONNECT, + pAdapter->sessionId, pAdapter->device_mode)); + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION && + pAdapter->device_mode != WLAN_HDD_P2P_CLIENT) { + hddLog(LOGE, FL("Device_mode %s(%d) is not supported"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) { + hddLog(LOGE, FL("HDD context is null")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + if (req->channel) { + if (!cds_allow_concurrency(pHddCtx, + cds_convert_device_mode_to_hdd_type( + pAdapter->device_mode), + req->channel->hw_value, HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + } else { + if (!cds_allow_concurrency(pHddCtx, + cds_convert_device_mode_to_hdd_type( + pAdapter->device_mode), 0, HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + } +#if defined(FEATURE_WLAN_LFR) + wlan_hdd_disable_roaming(pAdapter); +#endif + + /*Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(pAdapter); + if (0 > status) { + hddLog(LOGE, + FL("Failed to disconnect the existing connection")); + return -EALREADY; + } + + /*initialise security parameters */ + status = wlan_hdd_cfg80211_set_privacy(pAdapter, req); + + if (0 > status) { + hddLog(LOGE, + FL("failed to set security params")); + return status; + } + + if (req->channel) { + status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, + req->ssid_len, + req->bssid, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || \ + defined(CFG80211_BSSID_HINT_BACKPORT) + req->bssid_hint, +#else + NULL, +#endif + req->channel-> + hw_value); + } else { + status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, + req->ssid_len, + req->bssid, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || \ + defined(CFG80211_BSSID_HINT_BACKPORT) + req->bssid_hint, +#else + NULL, +#endif + 0); + } + + if (0 > status) { + hddLog(LOGE, FL("connect failed")); + return status; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_connect(wiphy, ndev, req); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_disconnect() - hdd disconnect api + * @pAdapter: Pointer to adapter + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) +{ + int status, result = 0; + unsigned long rc; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, + FL("HDD context is not valid")); + return status; + } + + /*stop tx queues */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_Disconnecting")); + pHddStaCtx->conn_info.connState = eConnectionState_Disconnecting; + INIT_COMPLETION(pAdapter->disconnect_comp_var); + + /*issue disconnect */ + + status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, reason); + if (CDF_STATUS_CMD_NOT_QUEUED == status) { + hddLog(LOG1, FL("status = %d, already disconnected"), + (int)status); + goto disconnected; + } else if (0 != status) { + hddLog(LOGE, + FL("csr_roam_disconnect failure, returned %d"), + (int)status); + pHddStaCtx->staDebugState = status; + result = -EINVAL; + goto disconnected; + } + rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + + if (!rc) { + hddLog(LOGE, + FL("Failed to disconnect, timed out")); + result = -ETIMEDOUT; + } +disconnected: + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_NotConnected")); + hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + /* Sending disconnect event to userspace for kernel version < 3.11 + * is handled by __cfg80211_disconnect call to __cfg80211_disconnected + */ + hddLog(LOG1, FL("Send disconnected event to userspace")); + cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED, + NULL, 0, GFP_KERNEL); +#endif + + return result; +} + +/** + * __wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); +#ifdef FEATURE_WLAN_TDLS + uint8_t staIdx; +#endif + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DISCONNECT, + pAdapter->sessionId, reason)); + hddLog(LOG1, FL("Device_mode %s(%d) reason code(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, reason); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + /* Issue disconnect request to SME, if station is in connected state */ + if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated) || + (pHddStaCtx->conn_info.connState == eConnectionState_Connecting)) { + eCsrRoamDisconnectReason reasonCode = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + hdd_scaninfo_t *pScanInfo; + + switch (reason) { + case WLAN_REASON_MIC_FAILURE: + reasonCode = eCSR_DISCONNECT_REASON_MIC_ERROR; + break; + + case WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY: + case WLAN_REASON_DISASSOC_AP_BUSY: + case WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA: + reasonCode = eCSR_DISCONNECT_REASON_DISASSOC; + break; + + case WLAN_REASON_PREV_AUTH_NOT_VALID: + case WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA: + reasonCode = eCSR_DISCONNECT_REASON_DEAUTH; + break; + + case WLAN_REASON_DEAUTH_LEAVING: + reasonCode = + pHddCtx->config-> + gEnableDeauthToDisassocMap ? + eCSR_DISCONNECT_REASON_STA_HAS_LEFT : + eCSR_DISCONNECT_REASON_DEAUTH; + break; + case WLAN_REASON_DISASSOC_STA_HAS_LEFT: + reasonCode = eCSR_DISCONNECT_REASON_STA_HAS_LEFT; + break; + default: + reasonCode = eCSR_DISCONNECT_REASON_UNSPECIFIED; + break; + } + hddLog(LOG1, + FL("convert to internal reason %d to reasonCode %d"), + reason, reasonCode); + pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; + pScanInfo = &pAdapter->scan_info; + if (pScanInfo->mScanPending) { + hddLog(LOG1, + FL("Disconnect is in progress, Aborting Scan")); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + } +#ifdef FEATURE_WLAN_TDLS + /* First clean up the tdls peers if any */ + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pAdapter->sessionId) + && (pHddCtx->tdlsConnInfo[staIdx].staId)) { + uint8_t *mac; + mac = + pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes; + hddLog(LOG1, + "%s: call sme_delete_tdls_peer_sta staId %d sessionId %d " + MAC_ADDRESS_STR, __func__, + pHddCtx->tdlsConnInfo[staIdx].staId, + pAdapter->sessionId, + MAC_ADDR_ARRAY(mac)); + sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, mac); + } + } +#endif + hddLog(LOG1, FL("Disconnecting with reasoncode:%u"), + reasonCode); + status = wlan_hdd_disconnect(pAdapter, reasonCode); + if (0 != status) { + hddLog(LOGE, + FL("failure, returned %d"), status); + return -EINVAL; + } + } else { + hddLog(LOGE, + FL("unexpected cfg disconnect called while in state (%d)"), + pHddStaCtx->conn_info.connState); + } + + return status; +} + +/** + * wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disconnect(wiphy, dev, reason); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_privacy_ibss() - set ibss privacy + * @pAdapter: Pointer to adapter + * @param: Pointer to IBSS parameters + * + * This function is used to initialize the security settings in IBSS mode + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_privacy_ibss(hdd_adapter_t *pAdapter, + struct cfg80211_ibss_params + *params) +{ + int status = 0; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + cdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + pHddStaCtx->ibss_enc_key_installed = 0; + + if (params->ie_len && (NULL != params->ie)) { + if (wlan_hdd_cfg80211_get_ie_ptr(params->ie, + params->ie_len, WLAN_EID_RSN)) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2; + encryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (hdd_is_wpaie_present(params->ie, params->ie_len)) { + tDot11fIEWPA dot11WPAIE; + tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + u8 *ie; + + memset(&dot11WPAIE, 0, sizeof(dot11WPAIE)); + ie = wlan_hdd_cfg80211_get_ie_ptr(params->ie, + params->ie_len, + DOT11F_EID_WPA); + if (NULL != ie) { + pWextState->wpaVersion = + IW_AUTH_WPA_VERSION_WPA; + /* Unpack the WPA IE */ + /* Skip past the EID byte and length byte - and four byte WiFi OUI */ + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + &ie[2 + 4], + ie[1] - 4, &dot11WPAIE); + /*Extract the multicast cipher, the encType for unicast + cipher for wpa-none is none */ + encryptionType = + hdd_translate_wpa_to_csr_encryption_type + (dot11WPAIE.multicast_cipher); + } + } + + status = + wlan_hdd_cfg80211_set_ie(pAdapter, params->ie, + params->ie_len); + + if (0 > status) { + hddLog(LOGE, FL("failed to parse WPA/RSN IE")); + return status; + } + } + + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (params->privacy) { + /* Security enabled IBSS, At this time there is no information + * available about the security paramters, so initialise the + * encryption type to eCSR_ENCRYPT_TYPE_WEP40_STATICKEY. + * The correct security parameters will be updated later in + * wlan_hdd_cfg80211_add_key Hal expects encryption type to be + * set inorder enable privacy bit in beacons + */ + + encryptionType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + hddLog(LOG2, FL("encryptionType=%d"), encryptionType); + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + return status; +} + +/** + * __wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + int status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct cdf_mac_addr bssid; + u8 channelNum = 0; + p_cds_contextType p_cds_context; + + ENTER(); + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("Invalid CDS context"); + return -EINVAL; + } + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_JOIN_IBSS, + pAdapter->sessionId, pAdapter->device_mode)); + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if (NULL != +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + params->chandef.chan) +#else + params->channel) +#endif + { + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int indx; + + /* Get channel number */ + channelNum = ieee80211_frequency_to_channel( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + params-> + chandef. + chan-> + center_freq); +#else + params-> + channel-> + center_freq); +#endif + + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans)) { + hddLog(LOGE, FL("No valid channel list")); + return -EOPNOTSUPP; + } + + for (indx = 0; indx < numChans; indx++) { + if (channelNum == validChan[indx]) { + break; + } + } + if (indx >= numChans) { + hddLog(LOGE, + FL("Not valid Channel %d"), channelNum); + return -EINVAL; + } + } + + if (!cds_allow_concurrency(pHddCtx, CDS_IBSS_MODE, channelNum, + HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + if (pHddCtx->config->policy_manager_enabled) { + status = cdf_event_reset( + &p_cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(status)) + hdd_err("ERR: clear event failed"); + + status = cds_current_connections_update(pHddCtx, + channelNum); + if (CDF_STATUS_E_FAILURE == status) { + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (CDF_STATUS_SUCCESS == status) { + status = cdf_wait_single_event( + &p_cds_context->connection_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: cdf wait for event failed!!"); + return -EINVAL; + } + } + } + + /*Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(pAdapter); + if (0 > status) { + hddLog(LOGE, + FL("Failed to disconnect the existing IBSS connection")); + return -EALREADY; + } + + pRoamProfile = &pWextState->roamProfile; + + if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) { + hddLog(LOGE, + FL("Interface type is not set to IBSS")); + return -EINVAL; + } + + /* enable selected protection checks in IBSS mode */ + pRoamProfile->cfg_protection = IBSS_CFG_PROTECTION_ENABLE_MASK; + + if (CDF_STATUS_E_FAILURE == sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + pHddCtx->config-> + ibssATIMWinSize)) { + hddLog(LOGE, + FL("Could not pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CCM")); + } + + /* BSSID is provided by upper layers hence no need to AUTO generate */ + if (NULL != params->bssid) { + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0) + == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID")); + return -EIO; + } + cdf_mem_copy(bssid.bytes, params->bssid, CDF_MAC_ADDR_SIZE); + } else if (pHddCtx->config->isCoalesingInIBSSAllowed == 0) { + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0) + == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID")); + return -EIO; + } + cdf_copy_macaddr(&bssid, &pHddCtx->config->IbssBssid); + } + if ((params->beacon_interval > CFG_BEACON_INTERVAL_MIN) + && (params->beacon_interval <= CFG_BEACON_INTERVAL_MAX)) + pRoamProfile->beaconInterval = params->beacon_interval; + else { + pRoamProfile->beaconInterval = CFG_BEACON_INTERVAL_DEFAULT; + hddLog(LOG2, + FL("input beacon interval %d TU is invalid, use default %d TU"), + params->beacon_interval, pRoamProfile->beaconInterval); + } + + /* Set Channel */ + if (channelNum) { + /* Set the Operational Channel */ + hddLog(LOG2, FL("set channel %d"), channelNum); + pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = channelNum; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + } + + /* Initialize security parameters */ + status = wlan_hdd_cfg80211_set_privacy_ibss(pAdapter, params); + if (status < 0) { + hddLog(LOGE, + FL("failed to set security parameters")); + return status; + } + + /* Issue connect start */ + status = wlan_hdd_cfg80211_connect_start(pAdapter, params->ssid, + params->ssid_len, + bssid.bytes, + NULL, + pHddStaCtx->conn_info. + operationChannel); + + if (0 > status) { + hddLog(LOGE, FL("connect failed")); + return status; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_join_ibss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + CDF_STATUS hal_status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_LEAVE_IBSS, + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE)); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + if (NULL == pWextState) { + hddLog(LOGE, FL("Data Storage Corruption")); + return -EIO; + } + + pRoamProfile = &pWextState->roamProfile; + + /* Issue disconnect only if interface type is set to IBSS */ + if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) { + hddLog(LOGE, + FL("BSS Type is not set to IBSS")); + return -EINVAL; + } + + /* Issue Disconnect request */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hal_status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + if (!CDF_IS_STATUS_SUCCESS(hal_status)) { + hddLog(LOGE, + FL("sme_roam_disconnect failed hal_status(%d)"), + hal_status); + return -EAGAIN; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_leave_ibss(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * This function is used to set the phy parameters. RTS Threshold/FRAG + * Threshold/Retry Count etc. + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, + u32 changed) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + tHalHandle hHal = pHddCtx->hHal; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS, + NO_SESSION, wiphy->rts_threshold)); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, + FL("HDD context is not valid")); + return status; + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + u32 rts_threshold = (wiphy->rts_threshold == -1) ? + WNI_CFG_RTS_THRESHOLD_STAMAX : wiphy->rts_threshold; + + if ((WNI_CFG_RTS_THRESHOLD_STAMIN > rts_threshold) || + (WNI_CFG_RTS_THRESHOLD_STAMAX < rts_threshold)) { + hddLog(LOGE, + FL("Invalid RTS Threshold value %u"), + rts_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_RTS_THRESHOLD, + rts_threshold)) { + hddLog(LOGE, + FL("sme_cfg_set_int failed for rts_threshold value %u"), + rts_threshold); + return -EIO; + } + + hddLog(LOG2, FL("set rts threshold %u"), rts_threshold); + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + u16 frag_threshold = (wiphy->frag_threshold == -1) ? + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX : + wiphy->frag_threshold; + + if ((WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN > frag_threshold) || + (WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX < frag_threshold)) { + hddLog(LOGE, + FL("Invalid frag_threshold value %hu"), + frag_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, + frag_threshold)) { + hddLog(LOGE, + FL("sme_cfg_set_int failed for frag_threshold value %hu"), + frag_threshold); + return -EIO; + } + + hddLog(LOG2, FL("set frag threshold %hu"), frag_threshold); + } + + if ((changed & WIPHY_PARAM_RETRY_SHORT) + || (changed & WIPHY_PARAM_RETRY_LONG)) { + u8 retry_value = (changed & WIPHY_PARAM_RETRY_SHORT) ? + wiphy->retry_short : wiphy->retry_long; + + if ((WNI_CFG_LONG_RETRY_LIMIT_STAMIN > retry_value) || + (WNI_CFG_LONG_RETRY_LIMIT_STAMAX < retry_value)) { + hddLog(LOGE, + FL("Invalid Retry count %hu"), retry_value); + return -EINVAL; + } + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + if (0 != sme_cfg_set_int(hHal, + WNI_CFG_LONG_RETRY_LIMIT, + retry_value)) { + hddLog(LOGE, + FL("sme_cfg_set_int failed for long retry count %hu"), + retry_value); + return -EIO; + } + hddLog(LOG2, + FL("set long retry count %hu"), retry_value); + } else if (changed & WIPHY_PARAM_RETRY_SHORT) { + if (0 != sme_cfg_set_int(hHal, + WNI_CFG_SHORT_RETRY_LIMIT, + retry_value)) { + hddLog(LOGE, + FL("sme_cfg_set_int failed for short retry count %hu"), + retry_value); + return -EIO; + } + hddLog(LOG2, + FL("set short retry count %hu"), retry_value); + } + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_wiphy_params(wiphy, changed); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_set_default_mgmt_key() - dummy implementation of set default mgmt + * key + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @key_index: Key index + * + * Return: 0 + */ +static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + ENTER(); + return 0; +} + +/** + * wlan_hdd_set_default_mgmt_key() - SSR wrapper for + * wlan_hdd_set_default_mgmt_key + * @wiphy: pointer to wiphy + * @netdev: pointer to net_device structure + * @key_index: key index + * + * Return: 0 on success, error number on failure + */ +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) +/** + * __wlan_hdd_set_txq_params() - dummy implementation of set tx queue params + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @params: Pointer to tx queue parameters + * + * Return: 0 + */ +static int __wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + ENTER(); + return 0; +} +#else +/** + * __wlan_hdd_set_txq_params() - dummy implementation of set tx queue params + * @wiphy: Pointer to wiphy + * @params: Pointer to tx queue parameters + * + * Return: 0 + */ +static int __wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct ieee80211_txq_params *params) +{ + ENTER(); + return 0; +} +#endif /* LINUX_VERSION_CODE */ + +/** + * wlan_hdd_set_txq_params() - SSR wrapper for wlan_hdd_set_txq_params + * @wiphy: pointer to wiphy + * @netdev: pointer to net_device structure + * @params: pointer to ieee80211_txq_params + * + * Return: 0 on success, error number on failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WITH_BACKPORTS) +static int wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_txq_params(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} +#else +static int wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct ieee80211_txq_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_txq_params(wiphy, params); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* LINUX_VERSION_CODE */ + +/** + * __wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +static +int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct tagCsrDelStaParams *pDelStaParams) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + hdd_hostapd_state_t *hapd_state; + int status; + uint8_t staId; + uint8_t *mac; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_STA, + pAdapter->sessionId, pAdapter->device_mode)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + mac = (uint8_t *) pDelStaParams->peerMacAddr.bytes; + + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode)) { + + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + if (!hapd_state) { + hddLog(LOGE, "%s: Hostapd State is Null", __func__); + return 0; + } + + if (cdf_is_macaddr_broadcast((struct cdf_mac_addr *) mac)) { + uint16_t i; + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if ((pAdapter->aStaInfo[i].isUsed) && + (!pAdapter->aStaInfo[i]. + isDeauthInProgress)) { + cdf_mem_copy( + mac, + pAdapter->aStaInfo[i]. + macAddrSTA.bytes, + ETHER_ADDR_LEN); + if (hdd_ipa_uc_is_enabled(pHddCtx)) { + hdd_ipa_wlan_evt(pAdapter, + pAdapter-> + aStaInfo[i]. + ucSTAId, + WLAN_CLIENT_DISCONNECT, + mac); + } + hddLog(LOG1, + FL("Delete STA with MAC::" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac)); + + if (pHddCtx->dev_dfs_cac_status == + DFS_CAC_IN_PROGRESS) + goto fn_end; + + cdf_event_reset(&hapd_state->cdf_event); + hdd_softap_sta_disassoc(pAdapter, + mac); + cdf_status = + hdd_softap_sta_deauth(pAdapter, + pDelStaParams); + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + pAdapter->aStaInfo[i]. + isDeauthInProgress = true; + cdf_status = + cdf_wait_single_event( + &hapd_state->cdf_event, + 1000); + if (!CDF_IS_STATUS_SUCCESS( + cdf_status)) + hddLog(LOGE, + "%s: Deauth wait time expired", + __func__); + } + } + } + } else { + cdf_status = + hdd_softap_get_sta_id(pAdapter, + (struct cdf_mac_addr *) mac, + &staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOG1, + FL("Skip DEL STA as this is not used::" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + if (hdd_ipa_uc_is_enabled(pHddCtx)) { + hdd_ipa_wlan_evt(pAdapter, staId, + WLAN_CLIENT_DISCONNECT, mac); + } + + if (pAdapter->aStaInfo[staId].isDeauthInProgress == + true) { + hddLog(LOG1, + FL("Skip DEL STA as deauth is in progress::" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + pAdapter->aStaInfo[staId].isDeauthInProgress = true; + + hddLog(LOG1, + FL("Delete STA with MAC::" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac)); + + /* Case: SAP in ACS selected DFS ch and client connected + * Now Radar detected. Then if random channel is another + * DFS ch then new CAC is initiated and no TX allowed. + * So do not send any mgmt frames as it will timeout + * during CAC. + */ + + if (pHddCtx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) + goto fn_end; + + cdf_event_reset(&hapd_state->cdf_event); + hdd_softap_sta_disassoc(pAdapter, mac); + cdf_status = hdd_softap_sta_deauth(pAdapter, + pDelStaParams); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pAdapter->aStaInfo[staId].isDeauthInProgress = + false; + hddLog(LOG1, + FL("STA removal failed for ::" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } else { + cdf_status = cdf_wait_single_event( + &hapd_state->cdf_event, + 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, + "%s: Deauth wait time expired", + __func__); + } + } + } + +fn_end: + EXIT(); + return 0; +} + +#ifdef CFG80211_DEL_STA_V2 +/** + * wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param) +#else +/** + * wlan_hdd_cfg80211_del_station() - delete station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac) +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac) +#endif +#endif +{ + int ret; + struct tagCsrDelStaParams delStaParams; + + cds_ssr_protect(__func__); +#ifdef CFG80211_DEL_STA_V2 + if (NULL == param) { + hddLog(LOGE, FL("Invalid argumet passed")); + return -EINVAL; + } + wlansap_populate_del_sta_params(param->mac, param->reason_code, + param->subtype, &delStaParams); +#else + wlansap_populate_del_sta_params(mac, eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); +#endif + ret = __wlan_hdd_cfg80211_del_station(wiphy, dev, &delStaParams); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +{ + int status = -EPERM; +#ifdef FEATURE_WLAN_TDLS + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + u32 mask, set; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_STA, + pAdapter->sessionId, params->listen_interval)); + + if (0 != wlan_hdd_validate_context(pHddCtx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + mask = params->sta_flags_mask; + + set = params->sta_flags_set; + + hddLog(LOG1, FL("mask 0x%x set 0x%x " MAC_ADDRESS_STR), mask, set, + MAC_ADDR_ARRAY(mac)); + + if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + status = + wlan_hdd_tdls_add_station(wiphy, dev, mac, 0, NULL); + } + } +#endif + return status; +} + +/** + * wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_parameters *params) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_LFR +/** + * __wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + CDF_STATUS result = CDF_STATUS_SUCCESS; + int status; + tPmkidCacheInfo pmk_id; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + if (!pmksa) { + hddLog(LOGE, FL("pmksa is NULL")); + return -EINVAL; + } + + if (!pmksa->bssid || !pmksa->pmkid) { + hddLog(LOGE, FL("pmksa->bssid(%p) or pmksa->pmkid(%p) is NULL"), + pmksa->bssid, pmksa->pmkid); + return -EINVAL; + } + + hddLog(LOGW, FL("set PMKSA for " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pmksa->bssid)); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + cdf_mem_copy(pmk_id.BSSID.bytes, pmksa->bssid, ETHER_ADDR_LEN); + cdf_mem_copy(pmk_id.PMKID, pmksa->pmkid, CSR_RSN_PMKID_SIZE); + + /* Add to the PMKSA ID Cache in CSR */ + result = sme_roam_set_pmkid_cache(halHandle, pAdapter->sessionId, + &pmk_id, 1, false); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_PMKSA, + pAdapter->sessionId, result)); + + return CDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + int status = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + if (!pmksa) { + hddLog(LOGE, FL("pmksa is NULL")); + return -EINVAL; + } + + if (!pmksa->bssid) { + hddLog(LOGE, FL("pmksa->bssid is NULL")); + return -EINVAL; + } + + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Deleting PMKSA for " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pmksa->bssid)); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + /* Delete the PMKID CSR cache */ + if (CDF_STATUS_SUCCESS != + sme_roam_del_pmkid_from_cache(halHandle, + pAdapter->sessionId, pmksa->bssid, + false)) { + hddLog(LOGE, FL("Failed to delete PMKSA for " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pmksa->bssid)); + status = -EINVAL; + } + + return status; +} + +/** + * wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; + +} + +/** + * __wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + int status = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + hddLog(LOGW, FL("Flushing PMKSA")); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + /* Retrieve halHandle */ + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + /* Flush the PMKID cache in CSR */ + if (CDF_STATUS_SUCCESS != + sme_roam_del_pmkid_from_cache(halHandle, pAdapter->sessionId, NULL, + true)) { + hddLog(LOGE, FL("Cannot flush PMKIDCache")); + status = -EINVAL; + } + + return status; +} + +/** + * wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_flush_pmksa(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#if defined(WLAN_FEATURE_VOWIFI_11R) && defined(KERNEL_SUPPORT_11R_CFG80211) +/** + * __wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES, + pAdapter->sessionId, pHddStaCtx->conn_info.connState)); + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(LOGE, + FL("Called with Ie of length = %zu when not associated"), + ftie->ie_len); + hddLog(LOGE, FL("Should be Re-assoc Req IEs")); + } +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + hddLog(LOG1, FL("%s called with Ie of length = %zu"), __func__, + ftie->ie_len); +#endif + + /* Pass the received FT IEs to SME */ + sme_set_ft_ies(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, + (const u8 *)ftie->ie, ftie->ie_len); + return 0; +} + +/** + * wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_update_ft_ies(wiphy, dev, ftie); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * wlan_hdd_cfg80211_update_replay_counter_callback() - replay counter callback + * @callbackContext: Callback context + * @pGtkOffloadGetInfoRsp: Pointer to gtk offload response parameter + * + * Callback rountine called upon receiving response for get offload info + * + * Return: none + */ +void wlan_hdd_cfg80211_update_replay_counter_callback(void *callbackContext, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + uint8_t tempReplayCounter[8]; + hdd_station_ctx_t *pHddStaCtx; + + ENTER(); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("HDD adapter is Null")); + return; + } + + if (NULL == pGtkOffloadGetInfoRsp) { + hddLog(LOGE, FL("pGtkOffloadGetInfoRsp is Null")); + return; + } + + if (CDF_STATUS_SUCCESS != pGtkOffloadGetInfoRsp->ulStatus) { + hddLog(LOGE, FL("wlan Failed to get replay counter value")); + return; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + /* Update replay counter */ + pHddStaCtx->gtkOffloadReqParams.ullKeyReplayCounter = + pGtkOffloadGetInfoRsp->ullKeyReplayCounter; + + { + /* changing from little to big endian since supplicant + * works on big endian format + */ + int i; + uint8_t *p = + (uint8_t *) &pGtkOffloadGetInfoRsp->ullKeyReplayCounter; + + for (i = 0; i < 8; i++) { + tempReplayCounter[7 - i] = (uint8_t) p[i]; + } + } + + /* Update replay counter to NL */ + cfg80211_gtk_rekey_notify(pAdapter->dev, pGtkOffloadGetInfoRsp->bssId, + tempReplayCounter, GFP_KERNEL); +} + +/** + * __wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_station_ctx_t *pHddStaCtx; + tHalHandle hHal; + int result; + tSirGtkOffloadParams hddGtkOffloadReqParams; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA, + pAdapter->sessionId, pAdapter->device_mode)); + + result = wlan_hdd_validate_context(pHddCtx); + + if (0 != result) { + hddLog(LOGE, FL("HDD context is not valid")); + return result; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) { + hddLog(LOGE, FL("HAL context is Null!!!")); + return -EAGAIN; + } + + pHddStaCtx->gtkOffloadReqParams.ulFlags = GTK_OFFLOAD_ENABLE; + memcpy(pHddStaCtx->gtkOffloadReqParams.aKCK, data->kck, + NL80211_KCK_LEN); + memcpy(pHddStaCtx->gtkOffloadReqParams.aKEK, data->kek, + NL80211_KEK_LEN); + memcpy(pHddStaCtx->gtkOffloadReqParams.bssId, + &pHddStaCtx->conn_info.bssId, CDF_MAC_ADDR_SIZE); + { + /* changing from big to little endian since driver + * works on little endian format + */ + uint8_t *p = + (uint8_t *) &pHddStaCtx->gtkOffloadReqParams. + ullKeyReplayCounter; + int i; + + for (i = 0; i < 8; i++) { + p[7 - i] = data->replay_ctr[i]; + } + } + + if (true == pHddCtx->hdd_wlan_suspended) { + /* if wlan is suspended, enable GTK offload directly from here */ + memcpy(&hddGtkOffloadReqParams, + &pHddStaCtx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + status = + sme_set_gtk_offload(hHal, &hddGtkOffloadReqParams, + pAdapter->sessionId); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("sme_set_gtk_offload failed, status(%d)"), + status); + return -EINVAL; + } + hddLog(LOG1, FL("sme_set_gtk_offload successful")); + } else { + hddLog(LOG1, + FL("wlan not suspended GTKOffload request is stored")); + } + + return result; +} + +/** + * wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_rekey_data(wiphy, dev, data); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /*WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * __wlan_hdd_cfg80211_set_mac_acl() - set access control policy + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to access control parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int i; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_hostapd_state_t *pHostapdState; + tsap_Config_t *pConfig; + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx; + int status; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + if (NULL == params) { + hddLog(LOGE, FL("params is Null")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + p_cds_context = pHddCtx->pcds_context; + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + if (NULL == pHostapdState) { + hddLog(LOGE, FL("pHostapdState is Null")); + return -EINVAL; + } + + hddLog(LOGE, "acl policy: = %d no acl entries = %d", params->acl_policy, + params->n_acl_entries); + + if (WLAN_HDD_SOFTAP == pAdapter->device_mode) { + pConfig = &pAdapter->sessionCtx.ap.sapConfig; + + /* default value */ + pConfig->num_accept_mac = 0; + pConfig->num_deny_mac = 0; + + /** + * access control policy + * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are + * listed in hostapd.deny file. + * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow stations which are + * listed in hostapd.accept file. + */ + if (NL80211_ACL_POLICY_DENY_UNLESS_LISTED == params->acl_policy) { + pConfig->SapMacaddr_acl = eSAP_DENY_UNLESS_ACCEPTED; + } else if (NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED == + params->acl_policy) { + pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + } else { + hddLog(LOGE, FL("Acl Policy : %d is not supported"), + params->acl_policy); + return -ENOTSUPP; + } + + if (eSAP_DENY_UNLESS_ACCEPTED == pConfig->SapMacaddr_acl) { + pConfig->num_accept_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hddLog(LOG1, + FL("** Add ACL MAC entry %i in WhiletList :" + MAC_ADDRESS_STR), i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + cdf_mem_copy(&pConfig->accept_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } else if (eSAP_ACCEPT_UNLESS_DENIED == pConfig->SapMacaddr_acl) { + pConfig->num_deny_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hddLog(LOG1, + FL("** Add ACL MAC entry %i in BlackList :" + MAC_ADDRESS_STR), i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + cdf_mem_copy(&pConfig->deny_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } +#ifdef WLAN_FEATURE_MBSSID + cdf_status = + wlansap_set_mac_acl(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + pConfig); +#else + cdf_status = wlansap_set_mac_acl(p_cds_context, pConfig); +#endif + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("SAP Set Mac Acl fail")); + return -EINVAL; + } + } else { + hddLog(LOG1, FL("Invalid device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mac_acl() - SSR wrapper for + * __wlan_hdd_cfg80211_set_mac_acl + * @wiphy: pointer to wiphy structure + * @dev: pointer to net_device + * @params: pointer to cfg80211_acl_data + * + * Return; 0 on success, error number otherwise + */ +static int +wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mac_acl(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_NL80211_TESTMODE +#ifdef FEATURE_WLAN_LPHB +/** + * wlan_hdd_cfg80211_lphb_ind_handler() - handle low power heart beat indication + * @pHddCtx: Pointer to hdd context + * @lphbInd: Pointer to low power heart beat indication parameter + * + * Return: none + */ +void wlan_hdd_cfg80211_lphb_ind_handler(void *pHddCtx, tSirLPHBInd *lphbInd) +{ + struct sk_buff *skb; + + hddLog(LOGE, FL("LPHB indication arrived")); + + if (0 != wlan_hdd_validate_context((hdd_context_t *) pHddCtx)) { + hddLog(LOGE, FL("invalid argument pHddCtx")); + return; + } + + if (NULL == lphbInd) { + hddLog(LOGE, FL("invalid argument lphbInd")); + return; + } + + skb = cfg80211_testmode_alloc_event_skb(((hdd_context_t *) pHddCtx)-> + wiphy, sizeof(tSirLPHBInd), + GFP_ATOMIC); + if (!skb) { + hddLog(LOGE, FL("LPHB timeout, NL buffer alloc fail")); + return; + } + + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_HB)) { + hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_CMD put fail")); + goto nla_put_failure; + } + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_TYPE, lphbInd->protocolType)) { + hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_TYPE put fail")); + goto nla_put_failure; + } + if (nla_put(skb, WLAN_HDD_TM_ATTR_DATA, sizeof(tSirLPHBInd), lphbInd)) { + hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_DATA put fail")); + goto nla_put_failure; + } + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + hddLog(LOGE, FL("NLA Put fail")); + kfree_skb(skb); + + return; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * __wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, + void *data, int len) +{ + struct nlattr *tb[WLAN_HDD_TM_ATTR_MAX + 1]; + int err; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + err = wlan_hdd_validate_context(pHddCtx); + if (err) + return err; + + err = nla_parse(tb, WLAN_HDD_TM_ATTR_MAX, data, + len, wlan_hdd_tm_policy); + if (err) { + hddLog(LOGE, FL("Testmode INV ATTR")); + return err; + } + + if (!tb[WLAN_HDD_TM_ATTR_CMD]) { + hddLog(LOGE, FL("Testmode INV CMD")); + return -EINVAL; + } + + switch (nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])) { +#ifdef FEATURE_WLAN_LPHB + /* Low Power Heartbeat configuration request */ + case WLAN_HDD_TM_CMD_WLAN_HB: + { + int buf_len; + void *buf; + tSirLPHBReq *hb_params = NULL; + tSirLPHBReq *hb_params_temp = NULL; + CDF_STATUS smeStatus; + + if (!tb[WLAN_HDD_TM_ATTR_DATA]) { + hddLog(LOGE, FL("Testmode INV DATA")); + return -EINVAL; + } + + buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]); + buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]); + + hb_params_temp = (tSirLPHBReq *) buf; + if ((hb_params_temp->cmd == LPHB_SET_TCP_PARAMS_INDID) + && (hb_params_temp->params.lphbTcpParamReq. + timePeriodSec == 0)) + return -EINVAL; + + hb_params = + (tSirLPHBReq *) cdf_mem_malloc(sizeof(tSirLPHBReq)); + if (NULL == hb_params) { + hddLog(LOGE, FL("Request Buffer Alloc Fail")); + return -ENOMEM; + } + + cdf_mem_copy(hb_params, buf, buf_len); + smeStatus = + sme_lphb_config_req((tHalHandle) (pHddCtx->hHal), + hb_params, + wlan_hdd_cfg80211_lphb_ind_handler); + if (CDF_STATUS_SUCCESS != smeStatus) { + hddLog(LOGE, "LPHB Config Fail, disable"); + cdf_mem_free(hb_params); + } + return 0; + } +#endif /* FEATURE_WLAN_LPHB */ + +#if defined(QCA_WIFI_FTM) + case WLAN_HDD_TM_CMD_WLAN_FTM: + { + int buf_len; + void *buf; + CDF_STATUS status; + if (!tb[WLAN_HDD_TM_ATTR_DATA]) { + hddLog(LOGE, + FL + ("WLAN_HDD_TM_ATTR_DATA attribute is invalid")); + return -EINVAL; + } + + buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]); + buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]); + + pr_info("****FTM Tx cmd len = %d*****\n", buf_len); + + status = wlan_hdd_ftm_testmode_cmd(buf, buf_len); + + if (status != CDF_STATUS_SUCCESS) + err = -EBUSY; + break; + } +#endif + + default: + hddLog(LOGE, FL("command %d not supported"), + nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])); + return -EOPNOTSUPP; + } + + return err; +} + +/** + * wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + struct wireless_dev *wdev, +#endif + void *data, int len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_testmode(wiphy, data, len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if defined(QCA_WIFI_FTM) +/** + * wlan_hdd_testmode_rx_event() - test mode rx event handler + * @buf: Pointer to buffer + * @buf_len: Buffer length + * + * Return: none + */ +void wlan_hdd_testmode_rx_event(void *buf, size_t buf_len) +{ + struct sk_buff *skb; + hdd_context_t *hdd_ctx; + + if (!buf || !buf_len) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: buf or buf_len invalid, buf = %p buf_len = %zu", + __func__, buf, buf_len); + return; + } + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: hdd context invalid", __func__); + return; + } + + skb = cfg80211_testmode_alloc_event_skb(hdd_ctx->wiphy, + buf_len, GFP_KERNEL); + if (!skb) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: failed to allocate testmode rx skb!", __func__); + return; + } + + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_FTM) || + nla_put(skb, WLAN_HDD_TM_ATTR_DATA, buf_len, buf)) + goto nla_put_failure; + + pr_info("****FTM Rx cmd len = %zu*****\n", buf_len); + + cfg80211_testmode_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: nla_put failed on testmode rx skb!", __func__); +} +#endif +#endif /* CONFIG_NL80211_TESTMODE */ + +#ifdef QCA_HT_2040_COEX +/** + * __wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + CDF_STATUS status; + tSmeConfigParams sme_config; + bool cbModeChange; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + cdf_mem_zero(&sme_config, sizeof(tSmeConfigParams)); + sme_get_config_param(pHddCtx->hHal, &sme_config); + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + if (sme_config.csrConfig.channelBondingMode24GHz != + eCSR_INI_SINGLE_CHANNEL_CENTERED) { + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_SINGLE_CHANNEL_CENTERED; + sme_update_config(pHddCtx->hHal, &sme_config); + cbModeChange = true; + } + break; + + case NL80211_CHAN_WIDTH_40: + if (sme_config.csrConfig.channelBondingMode24GHz == + eCSR_INI_SINGLE_CHANNEL_CENTERED) { + if (NL80211_CHAN_HT40MINUS == + cfg80211_get_chandef_type(chandef)) + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + else + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + sme_update_config(pHddCtx->hHal, &sme_config); + cbModeChange = true; + } + break; + + default: + hddLog(LOGE, FL("Error!!! Invalid HT20/40 mode !")); + return -EINVAL; + } + + if (!cbModeChange) + return 0; + + if (WLAN_HDD_SOFTAP != pAdapter->device_mode) + return 0; + + hddLog(LOG1, FL("Channel bonding changed to %d"), + sme_config.csrConfig.channelBondingMode24GHz); + + /* Change SAP ht2040 mode */ + status = hdd_set_sap_ht2040_mode(pAdapter, + cfg80211_get_chandef_type(chandef)); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error!!! Cannot set SAP HT20/40 mode!")); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ap_channel_width(wiphy, dev, chandef); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * wlan_hdd_convert_nl_iftype_to_hdd_type() - provides the type + * translation from NL to policy manager type + * @type: Generic connection mode type defined in NL + * + * + * This function provides the type translation + * + * Return: cds_con_mode enum + */ +enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + switch (type) { + case NL80211_IFTYPE_STATION: + mode = CDS_STA_MODE; + break; + case NL80211_IFTYPE_P2P_CLIENT: + mode = CDS_P2P_CLIENT_MODE; + break; + case NL80211_IFTYPE_P2P_GO: + mode = CDS_P2P_GO_MODE; + break; + case NL80211_IFTYPE_AP: + mode = CDS_SAP_MODE; + break; + case NL80211_IFTYPE_ADHOC: + mode = CDS_IBSS_MODE; + break; + default: + hddLog(LOGE, FL("Unsupported interface type (%d)"), + type); + } + return mode; +} + +/** + * struct cfg80211_ops - cfg80211_ops + * + * @add_virtual_intf: Add virtual interface + * @del_virtual_intf: Delete virtual interface + * @change_virtual_intf: Change virtual interface + * @change_station: Change station + * @add_beacon: Add beacon in sap mode + * @del_beacon: Delete beacon in sap mode + * @set_beacon: Set beacon in sap mode + * @start_ap: Start ap + * @change_beacon: Change beacon + * @stop_ap: Stop ap + * @change_bss: Change bss + * @add_key: Add key + * @get_key: Get key + * @del_key: Delete key + * @set_default_key: Set default key + * @set_channel: Set channel + * @scan: Scan + * @connect: Connect + * @disconnect: Disconnect + * @join_ibss = Join ibss + * @leave_ibss = Leave ibss + * @set_wiphy_params = Set wiphy params + * @set_tx_power = Set tx power + * @get_tx_power = get tx power + * @remain_on_channel = Remain on channel + * @cancel_remain_on_channel = Cancel remain on channel + * @mgmt_tx = Tx management frame + * @mgmt_tx_cancel_wait = Cancel management tx wait + * @set_default_mgmt_key = Set default management key + * @set_txq_params = Set tx queue parameters + * @get_station = Get station + * @set_power_mgmt = Set power management + * @del_station = Delete station + * @add_station = Add station + * @set_pmksa = Set pmksa + * @del_pmksa = Delete pmksa + * @flush_pmksa = Flush pmksa + * @update_ft_ies = Update FT IEs + * @tdls_mgmt = Tdls management + * @tdls_oper = Tdls operation + * @set_rekey_data = Set rekey data + * @sched_scan_start = Scheduled scan start + * @sched_scan_stop = Scheduled scan stop + * @resume = Resume wlan + * @suspend = Suspend wlan + * @set_mac_acl = Set mac acl + * @testmode_cmd = Test mode command + * @set_ap_chanwidth = Set AP channel bandwidth + * @dump_survey = Dump survey + * @key_mgmt_set_pmk = Set pmk key management + */ +static struct cfg80211_ops wlan_hdd_cfg80211_ops = { + .add_virtual_intf = wlan_hdd_add_virtual_intf, + .del_virtual_intf = wlan_hdd_del_virtual_intf, + .change_virtual_intf = wlan_hdd_cfg80211_change_iface, + .change_station = wlan_hdd_change_station, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) + .add_beacon = wlan_hdd_cfg80211_add_beacon, + .del_beacon = wlan_hdd_cfg80211_del_beacon, + .set_beacon = wlan_hdd_cfg80211_set_beacon, +#else + .start_ap = wlan_hdd_cfg80211_start_ap, + .change_beacon = wlan_hdd_cfg80211_change_beacon, + .stop_ap = wlan_hdd_cfg80211_stop_ap, +#endif + .change_bss = wlan_hdd_cfg80211_change_bss, + .add_key = wlan_hdd_cfg80211_add_key, + .get_key = wlan_hdd_cfg80211_get_key, + .del_key = wlan_hdd_cfg80211_del_key, + .set_default_key = wlan_hdd_cfg80211_set_default_key, + .scan = wlan_hdd_cfg80211_scan, + .connect = wlan_hdd_cfg80211_connect, + .disconnect = wlan_hdd_cfg80211_disconnect, + .join_ibss = wlan_hdd_cfg80211_join_ibss, + .leave_ibss = wlan_hdd_cfg80211_leave_ibss, + .set_wiphy_params = wlan_hdd_cfg80211_set_wiphy_params, + .set_tx_power = wlan_hdd_cfg80211_set_txpower, + .get_tx_power = wlan_hdd_cfg80211_get_txpower, + .remain_on_channel = wlan_hdd_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wlan_hdd_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wlan_hdd_mgmt_tx, + .mgmt_tx_cancel_wait = wlan_hdd_cfg80211_mgmt_tx_cancel_wait, + .set_default_mgmt_key = wlan_hdd_set_default_mgmt_key, + .set_txq_params = wlan_hdd_set_txq_params, + .get_station = wlan_hdd_cfg80211_get_station, + .set_power_mgmt = wlan_hdd_cfg80211_set_power_mgmt, + .del_station = wlan_hdd_cfg80211_del_station, + .add_station = wlan_hdd_cfg80211_add_station, +#ifdef FEATURE_WLAN_LFR + .set_pmksa = wlan_hdd_cfg80211_set_pmksa, + .del_pmksa = wlan_hdd_cfg80211_del_pmksa, + .flush_pmksa = wlan_hdd_cfg80211_flush_pmksa, +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) && defined(KERNEL_SUPPORT_11R_CFG80211) + .update_ft_ies = wlan_hdd_cfg80211_update_ft_ies, +#endif +#ifdef FEATURE_WLAN_TDLS + .tdls_mgmt = wlan_hdd_cfg80211_tdls_mgmt, + .tdls_oper = wlan_hdd_cfg80211_tdls_oper, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + .set_rekey_data = wlan_hdd_cfg80211_set_rekey_data, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_WLAN_SCAN_PNO + .sched_scan_start = wlan_hdd_cfg80211_sched_scan_start, + .sched_scan_stop = wlan_hdd_cfg80211_sched_scan_stop, +#endif /*FEATURE_WLAN_SCAN_PNO */ + .resume = wlan_hdd_cfg80211_resume_wlan, + .suspend = wlan_hdd_cfg80211_suspend_wlan, + .set_mac_acl = wlan_hdd_cfg80211_set_mac_acl, +#ifdef WLAN_NL80211_TESTMODE + .testmode_cmd = wlan_hdd_cfg80211_testmode, +#endif +#ifdef QCA_HT_2040_COEX + .set_ap_chanwidth = wlan_hdd_cfg80211_set_ap_channel_width, +#endif + .dump_survey = wlan_hdd_cfg80211_dump_survey, +}; diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h new file mode 100644 index 0000000000..7357451f4c --- /dev/null +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -0,0 +1,2279 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg80211.h + * + * WLAN host device driver cfg80211 functions declaration + */ + +#if !defined(HDD_CFG80211_H__) +#define HDD_CFG80211_H__ + +/* value for initial part of frames and number of bytes to be compared */ +#define GAS_INITIAL_REQ "\x04\x0a" +#define GAS_INITIAL_REQ_SIZE 2 + +#define GAS_INITIAL_RSP "\x04\x0b" +#define GAS_INITIAL_RSP_SIZE 2 + +#define GAS_COMEBACK_REQ "\x04\x0c" +#define GAS_COMEBACK_REQ_SIZE 2 + +#define GAS_COMEBACK_RSP "\x04\x0d" +#define GAS_COMEBACK_RSP_SIZE 2 + +#define P2P_PUBLIC_ACTION_FRAME "\x04\x09\x50\x6f\x9a\x09" +#define P2P_PUBLIC_ACTION_FRAME_SIZE 6 + +#define P2P_ACTION_FRAME "\x7f\x50\x6f\x9a\x09" +#define P2P_ACTION_FRAME_SIZE 5 + +#define SA_QUERY_FRAME_REQ "\x08\x00" +#define SA_QUERY_FRAME_REQ_SIZE 2 + +#define SA_QUERY_FRAME_RSP "\x08\x01" +#define SA_QUERY_FRAME_RSP_SIZE 2 + +#define HDD_P2P_WILDCARD_SSID "DIRECT-" +#define HDD_P2P_WILDCARD_SSID_LEN 7 + +#define WNM_BSS_ACTION_FRAME "\x0a\x07" +#define WNM_BSS_ACTION_FRAME_SIZE 2 + +#define WNM_NOTIFICATION_FRAME "\x0a\x1a" +#define WNM_NOTIFICATION_FRAME_SIZE 2 + +#define WPA_OUI_TYPE "\x00\x50\xf2\x01" +#define BLACKLIST_OUI_TYPE "\x00\x50\x00\x00" +#define WHITELIST_OUI_TYPE "\x00\x50\x00\x01" +#define WPA_OUI_TYPE_SIZE 4 +#define WMM_OUI_TYPE "\x00\x50\xf2\x02\x01" +#define WMM_OUI_TYPE_SIZE 5 + +#define WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 +#define WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 +#define BASIC_RATE_MASK 0x80 +#define RATE_MASK 0x7f + +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS +/* GPS application requirement */ +#define QCOM_VENDOR_IE_ID 221 +#define QCOM_OUI1 0x00 +#define QCOM_OUI2 0xA0 +#define QCOM_OUI3 0xC6 +#define QCOM_VENDOR_IE_AGE_TYPE 0x100 +#define QCOM_VENDOR_IE_AGE_LEN (sizeof(qcom_ie_age) - 2) + +#ifdef FEATURE_WLAN_TDLS +#define WLAN_IS_TDLS_SETUP_ACTION(action) \ + ((SIR_MAC_TDLS_SETUP_REQ <= action) && \ + (SIR_MAC_TDLS_SETUP_CNF >= action)) +#if !defined (TDLS_MGMT_VERSION2) +#define TDLS_MGMT_VERSION2 0 +#endif +#endif + +#define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) +#define MAX_SCAN_SSID 10 + +/** + * typedef struct qcom_ie_age - age ie + * + * @element_id: Element id + * @len: Length + * @oui_1: OUI 1 + * @oui_2: OUI 2 + * @oui_3: OUI 3 + * @type: Type + * @age: Age + * @tsf_delta: tsf delta from FW + */ +typedef struct { + u8 element_id; + u8 len; + u8 oui_1; + u8 oui_2; + u8 oui_3; + u32 type; + u32 age; + u32 tsf_delta; +} __attribute__ ((packed)) qcom_ie_age; +#endif + +/** + * enum eDFS_CAC_STATUS: CAC status + * + * @DFS_CAC_NEVER_DONE: CAC never done + * @DFS_CAC_IN_PROGRESS: CAC is in progress + * @DFS_CAC_IN_PROGRESS: CAC already done + */ +typedef enum { + DFS_CAC_NEVER_DONE, + DFS_CAC_IN_PROGRESS, + DFS_CAC_ALREADY_DONE, +} eDFS_CAC_STATUS; + +/* Vendor id to be used in vendor specific command and events + * to user space. + * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, + * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and + * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in + * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that + */ + +#define QCA_NL80211_VENDOR_ID 0x001374 +#define MAX_REQUEST_ID 0xFFFFFFFF + +/** + * enum qca_nl80211_vendor_subcmds: NL 80211 vendor sub command + * + * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Unspecified + * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test + * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Avoid frequency. + * Sub commands 2 to 9 are not used + * @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: DFS capability + * @QCA_NL80211_VENDOR_SUBCMD_NAN: Nan + * @QCA_NL80211_VENDOR_SUBCMD_STATS_EXT: Ext stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET: Link layer stats set + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET: Link layer stats get + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR: Link layer stats clear + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS: Link layer stats radio + * results + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS: Link layer stats interface + * results + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS: Link layer stats peer + * results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START: Ext scan start + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP: Ext scan stop + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS: Ext scan get valid + * channels + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES: Ext scan get capability + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS: Ext scan get cached + * results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE: Ext scan results + * available. Used when report_threshold is reached in scan cache. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT: Ext scan full scan + * result. Used to report scan results when each probe rsp. is received, + * if report_events enabled in wifi_scan_cmd_params. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT: Ext scan event from target. + * Indicates progress of scanning state-machine. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND: Ext scan hotlist + * ap found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST: Ext scan set hotlist + * bssid + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST: Ext scan reset + * hotlist bssid + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE: Ext scan significant + * change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE: Ext scan set + * significant change + * ap found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE: Ext scan reset + * significant change + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE: Ext tdls enable + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE: Ext tdls disable + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS: Ext tdls get status + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE: Ext tdls state + * @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES: Get supported features + * @QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI: Set scanning_mac_oui + * @QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG: No DFS flag + * @QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX: Get Concurrency Matrix + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Get the key mgmt offload keys + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: After roaming, send the + * roaming and auth information. + * @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED: Set OCB schedule + * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS offload flag + * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Get the supported features by the + * driver. + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Indicate that driver + * started CAC on DFS channel + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Indicate that driver + * completed the CAC check on DFS channel + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Indicate that the CAC + * check was aborted by the driver + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Indicate that the + * driver completed NOP + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Indicate that the + * driver detected radar signal on the current operating channel + * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: get wlan driver information + * @QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START: start wifi logger + * @QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP: memory dump request + * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: get logger feature set + * @QCA_NL80211_VENDOR_SUBCMD_ROAM: roam + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST: extscan set ssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST: + * extscan reset ssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND: hotlist ssid found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST: hotlist ssid lost + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST: set pno list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST: set passpoint list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST: + * reset passpoint list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND: pno network found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND: + * passpoint network found + * @QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: set wifi config + * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION: get wifi config + * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: get logging features + * @QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: venodr scan command + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: vendor scan complete + */ + +enum qca_nl80211_vendor_subcmds { + QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, + QCA_NL80211_VENDOR_SUBCMD_TEST = 1, + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10, + QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11, + QCA_NL80211_VENDOR_SUBCMD_NAN = 12, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT = 13, + + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS = 17, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS = 18, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS = 19, + + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START = 20, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP = 21, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS = 22, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES = 23, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS = 24, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE = 25, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT = 26, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT = 27, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND = 28, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST = 29, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST = 30, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE = 31, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE = 32, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE = 33, + + QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34, + QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35, + QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36, + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37, + + QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38, + + QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI = 39, + QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG = 40, + + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST = 41, + + /* Get Concurrency Matrix */ + QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42, + + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50, + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51, + + /* Deprecated */ + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED = 53, + + QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54, + + QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55, + + /* Off loaded DFS events */ + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60, + + QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61, + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62, + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP = 63, + QCA_NL80211_VENDOR_SUBCMD_ROAM = 64, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST = 65, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST = 66, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND = 67, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST = 68, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST = 69, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST = 70, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST = 71, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND = 72, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND = 73, + + /* Wi-Fi Configuration subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74, + QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75, + QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET = 76, + QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77, + + QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES = 78, + QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS = 79, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80, + + /* OCB commands */ + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92, + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93, + QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94, + QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95, + QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96, + QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97, + QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98, + QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99, + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100, + + /* DBS subcommands */ + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103, + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104, + + /* Vendor scan commands */ + QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN = 106, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE = 107, +}; + +/** + * enum qca_nl80211_vendor_subcmds_index - vendor sub commands index + * + * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX: Avoid frequency + * @QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX: Nan + * @QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX: Ext stats + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX: Ext scan start + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX: Ext scan stop + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX: Ext scan get + * capability + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX: Ext scan get + * cached results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX: Ext scan + * results available + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX: Ext scan full + * scan result + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX: Ext scan event + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX: Ext scan hot list + * AP found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX: Ext scan set + * bssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX: Ext scan reset + * bssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX: Ext scan + * significant change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX: Ext scan + * set significant change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX: Ext scan + * reset significant change + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX: Set stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX: Get stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX: Clear stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX: Radio stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX: Iface stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX: Peer info stats + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX: Ext tdls state change + * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX: ACS command + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX: Pass Roam and Auth info + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX: hotlist ap lost + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX: + * pno network found index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX: + * passpoint match found index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST_INDEX: + * set ssid hotlist index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST_INDEX: + * reset ssid hotlist index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX: + * hotlist ssid found index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX: + * hotlist ssid lost index + * @QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX + * dcc stats event index + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX: vendor scan index + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX: + * vendor scan complete event index + */ + +enum qca_nl80211_vendor_subcmds_index { +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX = 0, +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef WLAN_FEATURE_NAN + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX, +#endif /* WLAN_FEATURE_NAN */ + +#ifdef WLAN_FEATURE_STATS_EXT + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX, +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef FEATURE_WLAN_EXTSCAN + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, +#endif + /* DFS */ + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX, +#ifdef FEATURE_WLAN_EXTSCAN + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX, +#endif /* FEATURE_WLAN_EXTSCAN */ + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, +#ifdef WLAN_FEATURE_MEMDUMP + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX, +#endif /* WLAN_FEATURE_MEMDUMP */ + /* OCB events */ + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_enable - TDLS enable attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR: An array of 6 x Unsigned 8-bit + * value + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL: Signed 32-bit value, but lets + * keep as unsigned for now + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS: operating class + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS: Enable max latency in ms + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS: Enable min bandwidth + * in KBPS + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_enable { + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_disable: tdls disable attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_disable { + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_get_status - tdls get status attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE: get status state, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON: get status reason + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL: get status channel, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS: get operating + * class, unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_get_status { + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_state - tdls state attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE: TDLS new state, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON: TDLS state reason + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL: TDLS state channel, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS: TDLS state + * operating class, unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_state { + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST - 1, +}; + +/* enum's to provide TDLS capabilites */ +enum qca_wlan_vendor_attr_get_tdls_capabilities { + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS = 1, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr - wlan vendor attribute + * + * @QCA_WLAN_VENDOR_ATTR_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_DFS: DFS attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY + * @QCA_WLAN_VENDOR_ATTR_NAN: NAN attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_NAN + * @QCA_WLAN_VENDOR_ATTR_STATS_EXT: Ext stats attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_STATS_EXT + * @QCA_WLAN_VENDOR_ATTR_IFINDEX: After IFINDEX + * @QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS: Supported Features + * @QCA_WLAN_VENDOR_ATTR_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_MAX: Max value + */ +enum qca_wlan_vendor_attr { + QCA_WLAN_VENDOR_ATTR_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DFS = 1, + QCA_WLAN_VENDOR_ATTR_NAN = 2, + QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3, + QCA_WLAN_VENDOR_ATTR_IFINDEX = 4, + QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7, + QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1 +}; + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * enum qca_wlan_vendor_attr_extscan_config_params - ext scan config params + * + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_INVALID: Invalid initial + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID: + * Unsigned 32-bit value; Middleware provides it to the driver. Middle ware + * either gets it from caller, e.g., framework, or generates one if + * framework doesn't provide it. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND: + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS sub command. + * It is unsigned 32-bit value. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL: + * NL attributes for input params used by + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START sub command. Unsigned 32-bit + * value; channel frequency + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME: Unsigned 32-bit value; + * dwell time in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE: Unsigned 8-bit value: + * 0: active; 1: passive; N/A for DFS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS: Unsigned 8-bit value + * channel class + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX: Unsigned 8-bit value + * bucket index, 0 based + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND: Unsigned 8-bit value; band + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD: Unsigned 32-bit value; + * desired period, in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS: Unsigned 8-bit + * value; report events semantics + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS: Unsigned 32-bit + * value. Followed by a nested array of EXTSCAN_CHANNEL_SPEC_* attributes. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC: + * Array of QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_* attributes. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD: Unsigned 32-bit + * value; base timer period in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN: Unsigned + * 32-bit value; number of APs to store in each scan in the + * BSSID/RSSI history buffer (keep the highest RSSI APs) + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT: + * Unsigned 8-bit value; in %, when scan buffer is this much full, + * wake up APPS. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS: Unsigned 8-bit + * value; number of scan bucket specs; followed by a nested array + * of_EXTSCAN_BUCKET_SPEC_* attributes and values. The size of the array + * is determined by NUM_BUCKETS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC: Array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_* attributes. Array size: + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH: + * Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX: + * Unsigned 32-bit value; maximum number of results to be returned + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID: An array of + * 6 x Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP: Number of hotlist + * APs as unsigned 32-bit value, followed by a nested array of + * AP_THRESHOLD_PARAM attributes and values. The size of the array is + * determined by NUM_AP. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM: Array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_* attributes. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples for averaging RSSI + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm AP loss + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING: + * Unsigned 32bit value; number of APs breaching threshold. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP: + * Unsigned 32bit value; number of APs. Followed by an array of + * AP_THRESHOLD_PARAM attributes. Size of the array is NUM_AP. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm AP loss. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD: + * Unsigned 32-bit value. If max_period is non zero or different than + * period, then this bucket is an exponential backoff bucket. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT: + * Unsigned 32-bit value. For exponential back off bucket, + * number of scans performed at a given period and until the + * exponent is applied. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT: + * Unsigned 8-bit value; in number of scans, wake up AP after these + * many scans. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS: + * Unsigned 8-bit value; in number of scans, wake up AP after these + * many scans. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm SSID loss + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID: + * Number of hotlist SSIDs as unsigned 32-bit value, followed by a nested + * array of SSID_THRESHOLD_PARAM_* attributes and values. The size of the + * array is determined by NUM_SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM: + * Array of QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_* attributes + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID: + * An array of 33 x Unsigned 8-bit value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND: + * Signed 32-bit value; band + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW: + * Signed 32-bit value; low rssi + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH: + * Signed 32-bit value; high rssi + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS: + * Unsigned 32-bit value; a bitmask w/additional extscan config flag. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX: Max value + */ +enum qca_wlan_vendor_attr_extscan_config_params { + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_extscan_results - vendor attribute ext scan results + * + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID: Unsigned 32-bit value + * must match the request Id supplied by Wi-Fi HAL in the corresponding + * subcmd NL msg + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS: Unsigned 32-bit value used to + * indicate the status response from firmware/driver for the vendor + * sub-command + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS: EXTSCAN Valid Channels + * attributes. Unsigned 32bit value followed by a nested array of CHANNELS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS: An array of NUM_CHANNELS x + * Unsigned 32bit value integers representing channel numbers. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_APS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST: An array of + * NUM_RESULTS_AVAILABLE x QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_* + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP: Unsigned + * 64-bit value age of sample at the time of retrieval + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID: 33 x unsigned 8-bit + * value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID: An array of 6 x + * Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL: Unsigned 32-bit + * value; channel frequency in MHz + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI: Signed 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT: Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD: + * Unsigned 16-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY: + * Unsigned 16-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH: + * Unsigned 32-bit value; size of the IE DATA blob + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA: + * An array of IE_LENGTH x Unsigned 8-bit value; blob of all the + * information elements found in the beacon; this data should be + * a packed list of wifi_information_element objects, one after + * the other. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA: + * Unsigned 8-bit value; set by driver to indicate more scan results are + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE: Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID: + * An array of 6 x Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST: + * A nested array of signed 32-bit RSSI values. Size of the array is + * determined by (NUM_RSSI of SIGNIFICANT_CHANGE_RESULT_NUM_RSSI. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST: + * An array of NUM_RESULTS_AVAILABLE x + * QCA_NL80211_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_* + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID: + * Unsigned 32-bit value; a unique identifier for the scan unit + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS: + * Unsigned 32-bit value; a bitmask w/additional information about scan + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES: + * Unsigned 32-bit value; number of found network matches + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST: + * A nested array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_* + * attributes. Array size = + * *_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID: + * Unsigned 32-bit value; network block id for the matched network + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN: + * Unsigned 32-bit value; ANQP length + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP: + * An array size of PASSPOINT_MATCH_ANQP_LEN of unsigned 8-bit values; + * ANQP data in the information_element format. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS: + * Unsigned 32bit value; Max hotlist ssids. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS: + * Unsigned 32bit value; Max number of epno networks + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID: + * Unsigned 32bit value; Max number of epno networks by ssid + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID: + * Unsigned 32bit value; Max number of whitelisted ssids + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX: Max value + */ +enum qca_wlan_vendor_attr_extscan_results { + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of wifi scan results/bssids retrieved by the scan. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the + * list of wifi scan results returned for each cached result block. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS, + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND sub-command. + */ + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of results. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, + + /* EXTSCAN attributes used with + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS sub-command. + */ + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of gscan cached results returned. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST to + * indicate the list of gscan cached results. + */ + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of wifi scan results/bssids retrieved by the scan. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the + * list of wifi scan results returned for each cached result block. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND sub-command. + */ + /* Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE for number + * of results. + * Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the nested + * list of wifi scan results returned for each + * wifi_passpoint_match_result block. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, + /* Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the nested + * list of wifi scan results returned for each + * wifi_passpoint_match_result block. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID, + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND sub-command & + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST sub-command + */ + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of results. + */ + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX = + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST - 1, +}; + +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * enum qca_wlan_vendor_attr_ll_stats_set - vendor attribute set stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD: Size threshold + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING: + * Aggresive stats gathering + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_set { + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD = 1, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_get - vendor attribute get stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID: Unsigned 32bit value + * provided by the caller issuing the GET stats command. When reporting + * the stats results, the driver uses the same value to indicate which + * GET request the results correspond to. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK: Get config request mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK: Config response mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP: Config stop response + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_get { + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_clr - vendor attribute clear stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK: Config request mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ: Config stop mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK: Config response mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP: Config stop response + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_clr { + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_results_type - ll stats result type + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO: Link layer stats type radio + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE: Link layer stats type interface + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER: Link layer stats type peer + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_results_type { + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO = 1, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_results - vendor attribute stats results + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could be nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* are nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_* could be nested + * within the peer info stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_* could be + * nested within the channel stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ could be nested + * within the radio stats. + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE: Interface mode, e.g., STA, + * SOFTAP, IBSS, etc. Type = enum wifi_interface_mode + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR: Interface MAC address. + * An array of 6 Unsigned int8_t + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE: + * Type = enum wifi_connection_state, e.g., DISCONNECTED, AUTHENTICATING, + * etc. Valid for STA, CLI only + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING: + * Type = enum wifi_roam_state. Roaming state, e.g., IDLE or ACTIVE + * (is that valid for STA only?) + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES: Unsigned 32bit value. + * WIFI_CAPABILITY_XXX + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID: NULL terminated SSID. An + * array of 33 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID: BSSID. An array of 6 + * Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR: Country string + * advertised by AP. An array of 3 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR: Country string for + * this association. An array of 3 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC: Type = enum wifi_traffic_ac e.g. + * V0, VI, BE and BK + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE: Type = enum wifi_peer_type + * Peer type, e.g., STA, AP, P2P GO etc + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS: MAC addr corresponding + * to respective peer. An array of 6 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES: Unsigned int 32bit + * value representing capabilities corresponding to respective peer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES: Unsigned 32bit value. + * Number of rates + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE: Unsigned int 8bit value: + * 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS: Unsigned int 8bit value: + * 0:1x1, 1:2x2, 3:3x3, 4:4x4 + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW: Unsigned int 8bit value: + * 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX: Unsigned int 8bit value: + * OFDM/CCK rate code would be as per IEEE Std in the units of 0.5mbps + * HT/VHT it would be mcs index + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE: Unsigned 32bit value. + * Bit rate in units of 100Kbps + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU: Unsigned int 32bit value. + * Number of successfully transmitted data pkts i.e., with ACK received + * corresponding to the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU: Unsigned int 32bit value. + * Number of received data pkts corresponding to the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST: Unsigned int 32bit value. + * Number of data pkts losses, i.e., no ACK received corresponding to + * the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES: Unsigned int 32bit value. + * Total number of data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT: Unsigned int 32bit value. + * Total number of short data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG: Unsigned int 32bit value. + * Total number of long data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID: Radio id + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME: Unsigned 32bit value. + * Total number of msecs the radio is awake accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME: Unsigned 32bit value. + * Total number of msecs the radio is transmitting accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME: Unsigned 32bit value. + * Total number of msecs the radio is in active receive accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to all scan accruing + * over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD: Unsigned 32bit value. + * Total number of msecs the radio is awake due to NAN accruing over time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to GSCAN accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to roam scan accruing over + * time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to PNO scan accruing over + * time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20: Unsigned 32bit value. + * Total number of msecs the radio is awake due to HS2.0 scans and GAS + * exchange accruing over time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS: Unsigned 32bit value. + * Number of channels + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH: + * Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80, etc. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ: + * Unsigned 32bit value. Primary 20MHz channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0: + * Unsigned 32bit value. Center frequency (MHz) first segment. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1: + * Unsigned 32bit value. Center frequency (MHz) second segment. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME: Unsigned int 32bit value + * representing total number of msecs the radio is awake on that channel + * accruing over time, corresponding to the respective channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME: Unsigned int 32bit + * value representing total number of msecs the CCA register is busy + * accruing over time corresponding to the respective channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS: Number of radios + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO: Channel info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO: Peer info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO: Peer rate info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO: WMM info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA: Unsigned 8bit value. + * Used by the driver; if set to 1, it indicates that more stats, e.g., + * peers or radio, are to follow in the next + * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_*_RESULTS event. Otherwise, it + * is set to 0. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET: tsf offset + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED: leaky ap detected + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED: + * average number of frames leaked + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX: Max value + */ + +enum qca_wlan_vendor_attr_ll_stats_results { + QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + + /* Unsigned 32bit value to indicate ll stats result type */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1 +}; + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * enum qca_wlan_vendor_attr_get_supported_features - get supported feature + * + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX: Max value + */ +enum qca_wlan_vendor_attr_get_supported_features { + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET = 1, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX = + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_set_scanning_mac_oui - set scanning mac oui + * + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI: An array of 3 x Unsigned 8-bit + * value + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX: Max value + */ +enum qca_wlan_vendor_attr_set_scanning_mac_oui { + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI = 1, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX = + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes + * + * @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan + * @QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES: Nested unsigned 32-bit attributes + * with frequencies to be scanned (in MHz) + * @QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS: Nested attribute with SSIDs to be scanned + * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported + * rates to be included + * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests + * at non CCK rate in 2GHz band + * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags + * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the + * driver for the specific scan request + * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan + * request decoded as in enum scan_status + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation + * scan flag is set + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with + * randomisation + */ +enum qca_wlan_vendor_attr_scan { + QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0, + QCA_WLAN_VENDOR_ATTR_SCAN_IE, + QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES, + QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS, + QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES, + QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE, + QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, + QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK, + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SCAN_MAX = + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1 +}; + +/** + * enum scan_status - Specifies the valid values the vendor scan attribute + * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take + * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with + * new scan results + * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between + */ +enum scan_status { + VENDOR_SCAN_STATUS_NEW_RESULTS, + VENDOR_SCAN_STATUS_ABORTED, + VENDOR_SCAN_STATUS_MAX, +}; + +/** + * enum qca_wlan_vendor_attr_get_concurrency_matrix - get concurrency matrix + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX sub command. + * + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET: Set results. An + * array of SET_SIZE x Unsigned 32bit values representing concurrency + * combinations + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX: Max value + */ +enum qca_wlan_vendor_attr_get_concurrency_matrix { + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX + = 1, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE = 2, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET = 3, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX = + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_set_no_dfs_flag - vendor attribute set no dfs flag + * + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG: Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX: Max value + */ +enum qca_wlan_vendor_attr_set_no_dfs_flag { + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG = 1, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX = + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST - 1, +}; + + +/** + * enum qca_wlan_vendor_attr_roam_auth - vendor event for roaming + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID: BSSID of the roamed AP + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE: Request IE + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE: Response IE + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED: Authorization Status + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR: Replay Counter + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK: KCK of the PTK + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK: KEK of the PTK + */ +enum qca_wlan_vendor_attr_roam_auth { + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_wifi_config - wifi config + * + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM: dynamic DTIM + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR: avg factor + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_MAX: max value + */ +enum qca_wlan_vendor_attr_wifi_config { + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR = 2, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_epno_type - the type of request to the EPNO command + * @QCA_WLAN_EPNO: epno type request + * @QCA_WLAN_PNO: pno type request + */ +enum qca_wlan_epno_type { + QCA_WLAN_EPNO, + QCA_WLAN_PNO +}; + +/** + * enum qca_wlan_vendor_attr_pno_config_params - pno config params + * + * @QCA_WLAN_VENDOR_ATTR_PNO_INVALID - Invalid initial value + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST sub command. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM: + * Unsigned 32-bit value; pno passpoint number of networks + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY: + * Array of nested QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_* + * attributes. Array size = + * QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID: + * Unsigned 32-bit value; network id + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM: + * An array of 256 x Unsigned 8-bit value; NULL terminated UTF8 encoded + * realm, 0 if unspecified. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID: + * An array of 16 x Unsigned 32-bit value; roaming consortium ids + * to match, 0 if unspecified. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN: + * An array of 6 x Unsigned 8-bit value; mcc/mnc combination, 0s if + * unspecified. + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST sub command. + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS: + * Unsigned 32-bit value; set pno number of networks + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST: + * Array of nested + * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_* + * attributes. Array size = + * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID: + * An array of 33 x Unsigned 8-bit value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD: + * Signed 8-bit value; threshold for considering this SSID as found, + * required granularity for this threshold is 4dBm to 8dBm + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS: + * Unsigned 8-bit value; WIFI_PNO_FLAG_XXX + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT: + * Unsigned 8-bit value; auth bit field for matching WPA IE + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE + * Unsigned 8-bit to indicate ePNO type; values from qca_wlan_epno_type + * @QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_PNO_MAX: max + */ +enum qca_wlan_vendor_attr_pno_config_params { + QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM = 1, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY = 2, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID = 3, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM = 4, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID = 5, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN = 6, + + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS = 7, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST = 8, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID = 9, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD = 10, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS = 11, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT = 12, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE = 13, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PNO_MAX = + QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roaming_config_params - roaming config params + * + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: roaming sub command + * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Request id + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: + * number of whitelist networks + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: + * Whitelist ssid list + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: + * white list ssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: + * 'a' band boost threshold + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: + * 'a' band penalty threshold + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: + * 'a' band boost factor + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: + * 'a' band penalty factor + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: + * 'a' band max boost + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: + * lazy roam histeresys + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: + * alert roam rssi trigger + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: + * set lazy roam enable + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: + * set bssid preference + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: + * set lazy roam number of bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: + * set lazy roam bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: + * set lazy roam rssi modifier + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: + * set bssid params + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: + * set bssid params num bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: + * set bssid params bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX: Max + */ +enum qca_wlan_vendor_attr_roaming_config_params { + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1, + QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD = 7, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR = 8, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR = 9, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST = 10, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS = 11, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER = 12, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE = 13, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS = 14, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID = 15, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roam_subcmd - roam sub commands + * + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST: ssid white list + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS: roam params + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM: set lazy roam + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS: set bssid prefs + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS: set bssid params + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID: set blacklist bssid + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX: subcmd max + */ +enum qca_wlan_vendor_attr_roam_subcmd { + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS = 2, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6, + + /* KEEP LAST */ + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_get_wifi_info - wifi driver information + * + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION: get host driver version + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION: ger firmware version + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX: subcmd max + */ +enum qca_wlan_vendor_attr_get_wifi_info { + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2, + + /* KEEP LAST */ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_get_logger_features - value for logger + * supported features + * @QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED - Indicate the supported features + * @QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_LOGGER_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET sub command. + */ +enum qca_wlan_vendor_attr_get_logger_features { + QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LOGGER_MAX = + QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_features - vendor device/driver features + * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key + * management offload, a mechanism where the station's firmware + * does the exchange with the AP to establish the temporal keys + * after roaming, rather than having the supplicant do it. + * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports + * simultaneous off-channel operations. + */ +enum qca_wlan_vendor_features { + QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0, + QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2, + /* Additional features need to be added above this */ + NUM_QCA_WLAN_VENDOR_FEATURES +}; + +/* Feature defines */ +#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ +#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ +#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ +#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ +#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ +#define WIFI_FEATURE_EXTSCAN 0x0020 /* Extended Scan APIs */ +#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness + Networking */ +#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ +#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ +#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ +#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ +#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ +#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link + setup */ +#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off + channel */ +#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ +#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA + Concurrency */ +#define WIFI_FEATURE_LINK_LAYER_STATS 0x10000 /* Link layer stats */ +#define WIFI_FEATURE_LOGGER 0x20000 /* WiFi Logger */ +#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ +#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ + +/** + * enum wifi_logger_supported_features - values for supported logger features + * @WIFI_LOGGER_MEMORY_DUMP_SUPPORTED - Memory dump of FW + * @WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED - Per packet statistics + * @WIFI_LOGGER_CONNECT_EVENT_SUPPORTED - Logging of Connectivity events + * @WIFI_LOGGER_POWER_EVENT_SUPPORTED - Power of driver + * @WIFI_LOGGER_WAKE_LOCK_SUPPORTED - Wakelock of driver + * @WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED - monitor FW health + */ +enum wifi_logger_supported_features { + WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), + WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), + WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), + WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), + WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), + WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), + WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)), +}; + +/* Add more features here */ +#define WIFI_TDLS_SUPPORT BIT(0) +#define WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT BIT(1) +#define WIIF_TDLS_OFFCHANNEL_SUPPORT BIT(2) + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +#define HDD_MAX_AVOID_FREQ_RANGES 4 +/** + * typedef struct sHddAvoidFreqRange - avoid frequency range + * + * @startFreq: Start frequency range + * @endFreq: End frequency range + */ +typedef struct sHddAvoidFreqRange { + u32 startFreq; + u32 endFreq; +} tHddAvoidFreqRange; + +/** + * typedef struct sHddAvoidFreqList - avoid frequency list + * + * @avoidFreqRangeCount: Avoid frequency range count + * @avoidFreqRange: Avoid frequency list + */ +typedef struct sHddAvoidFreqList { + u32 avoidFreqRangeCount; + tHddAvoidFreqRange avoidFreqRange[HDD_MAX_AVOID_FREQ_RANGES]; +} tHddAvoidFreqList; +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +/** + * enum qca_wlan_vendor_attr_acs_offload + * + * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: ACS selected primary channel + * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: ACS selected secondary channel + * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: hw_mode for ACS + * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: indicate if HT capability is enabled + * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: indicate HT capability + */ +enum qca_wlan_vendor_attr_acs_offload { + QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ACS_MAX = + QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_acs_hw_mode + * + * @QCA_ACS_MODE_IEEE80211B: 11b mode + * @QCA_ACS_MODE_IEEE80211G: 11g mode + * @QCA_ACS_MODE_IEEE80211A: 11a mode + * @QCA_ACS_MODE_IEEE80211AD: 11ad mode + */ +enum qca_wlan_vendor_acs_hw_mode { + QCA_ACS_MODE_IEEE80211B, + QCA_ACS_MODE_IEEE80211G, + QCA_ACS_MODE_IEEE80211A, + QCA_ACS_MODE_IEEE80211AD, + QCA_ACS_MODE_IEEE80211ANY, +}; + +/** + * enum qca_wlan_vendor_config: wifi config attr + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID: invalid config + * @QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM: modulated dtim + * @QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR: stats avg. factor + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_CONFIG_LAST: last config + * @QCA_WLAN_VENDOR_ATTR_CONFIG_MAX: max config + */ +enum qca_wlan_vendor_config { + QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM, + QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR, + QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_CONFIG_LAST, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_CONFIG_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_wifi_logger_start - Enum for wifi logger starting + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID: Invalid attribute + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID: Ring ID + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL: Verbose level + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS: Flag + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX: Max value + */ +enum qca_wlan_vendor_attr_wifi_logger_start { + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1, +}; + +/* + * enum qca_wlan_vendor_attr_wifi_logger_get_ring_data - Get ring data + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID: Invalid attribute + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID: Ring ID + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX: Max value + */ +enum qca_wlan_vendor_attr_wifi_logger_get_ring_data { + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID = 1, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST - 1, +}; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * enum wlan_offloaded_packets_control - control commands + * @WLAN_START_OFFLOADED_PACKETS: start offloaded packets + * @WLAN_STOP_OFFLOADED_PACKETS: stop offloaded packets + * + */ +enum wlan_offloaded_packets_control { + WLAN_START_OFFLOADED_PACKETS = 1, + WLAN_STOP_OFFLOADED_PACKETS = 2 +}; + +/** + * enum qca_wlan_vendor_attr_offloaded_packets - offloaded packets + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID: invalid + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL: control + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID: request id + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA: ip packet data + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR: src mac address + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR: destination mac address + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD: period in milli seconds + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX: max + */ +enum qca_wlan_vendor_attr_offloaded_packets { + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID, + + /* Packet in hex format */ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX = + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST - 1, +}; +#endif + +/** + * enum qca_wlan_rssi_monitoring_control - rssi control commands + * @QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID: invalid + * @QCA_WLAN_RSSI_MONITORING_START: rssi monitoring start + * @QCA_WLAN_RSSI_MONITORING_STOP: rssi monitoring stop + */ +enum qca_wlan_rssi_monitoring_control { + QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID = 0, + QCA_WLAN_RSSI_MONITORING_START, + QCA_WLAN_RSSI_MONITORING_STOP, +}; + +/** + * enum qca_wlan_vendor_attr_rssi_monitoring - rssi monitoring + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL: control + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI: max rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI: min rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID: current bssid + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI: current rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX: max + */ +enum qca_wlan_vendor_attr_rssi_monitoring { + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI, + + /* attributes to be used/received in callback */ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX = + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST - 1, +}; + +/** + * enum qca_vendor_attr_get_preferred_freq_list - get preferred channel list + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE: interface type + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST: preferred frequency list + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX: max + */ +enum qca_vendor_attr_get_preferred_freq_list { + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID, + /* A 32-unsigned value; the interface type/mode for which the preferred + * frequency list is requested (see enum qca_iface_type for possible + * values); used in both south- and north-bound. + */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + /* An array of 32-unsigned values; values are frequency (MHz); used + * in north-bound only. + */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX = + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_probable_oper_channel - channel hint + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE: interface type + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ: frequency hint value + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST: last + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX: max + */ +enum qca_vendor_attr_probable_oper_channel { + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID, + /* 32-bit unsigned value; indicates the connection/iface type likely to + * come on this channel (see enum qca_iface_type). + */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE, + /* 32-bit unsigned value; the frequency (MHz) of the probable channel */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX = + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST - 1 +}; + +/** + * enum drv_dbs_capability - DBS capability + * @DRV_DBS_CAPABILITY_DISABLED: DBS disabled + * @DRV_DBS_CAPABILITY_1X1: 1x1 + * @DRV_DBS_CAPABILITY_2X2: 2x2 + */ +enum drv_dbs_capability { + DRV_DBS_CAPABILITY_DISABLED, /* not supported or disabled */ + DRV_DBS_CAPABILITY_1X1, + DRV_DBS_CAPABILITY_2X2, +}; + +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); + +#ifdef FEATURE_WLAN_LFR +int wlan_hdd_cfg80211_pmksa_candidate_notify(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + int index, bool preauth); +#endif + +#ifdef FEATURE_WLAN_LFR_METRICS +CDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); + +CDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth_status(hdd_adapter_t * + pAdapter, + tCsrRoamInfo * + pRoamInfo, + bool preauth_status); + +CDF_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); +#endif + +#ifdef FEATURE_WLAN_WAPI +void wlan_hdd_cfg80211_set_key_wapi(hdd_adapter_t *pAdapter, uint8_t key_index, + const uint8_t *mac_addr, const uint8_t *key, + int key_Len); +#endif +struct wiphy *wlan_hdd_cfg80211_wiphy_alloc(int priv_size); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request); + +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *pCfg); + +void wlan_hdd_update_wiphy(struct wiphy *wiphy, struct hdd_config *pCfg); + +int wlan_hdd_cfg80211_register(struct wiphy *wiphy); +void wlan_hdd_cfg80211_register_frames(hdd_adapter_t *pAdapter); + +void wlan_hdd_cfg80211_deregister_frames(hdd_adapter_t *pAdapter); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request); +#else +int hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request); +#endif + +extern void hdd_conn_set_connection_state(hdd_adapter_t *pAdapter, + eConnectionState connState); +CDF_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter, + int channel); +#ifdef FEATURE_WLAN_TDLS +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer); +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD +extern void wlan_hdd_cfg80211_update_replay_counter_callback(void + *callbackContext, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp); +#endif +void *wlan_hdd_change_country_code_cb(void *pAdapter); +void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel); + +uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length, + uint8_t eid); + +#ifdef CFG80211_DEL_STA_V2 +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac); +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac); +#endif +#endif + +#if defined(QCA_WIFI_FTM) && defined(CONFIG_NL80211_TESTMODE) +void wlan_hdd_testmode_rx_event(void *buf, size_t buf_len); +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx, + tHddAvoidFreqList * pAvoidFreqList); +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_EXTSCAN +void wlan_hdd_cfg80211_extscan_callback(void *ctx, + const uint16_t evType, void *pMsg); +#endif /* FEATURE_WLAN_EXTSCAN */ + +void hdd_rssi_threshold_breached(void *hddctx, + struct rssi_breach_event *data); + +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_list(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); + +int wlan_hdd_cfg80211_update_bss(struct wiphy *wiphy, + hdd_adapter_t *pAdapter, + uint32_t scan_timestamp); + +void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +int wlan_hdd_send_roam_auth_event(hdd_context_t *hdd_ctx_ptr, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_length, + uint8_t *rsp_rsn_ie, uint32_t rsp_rsn_length, + tCsrRoamInfo *roam_info_ptr); +#endif + +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *adapter); + +#if !(defined (SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) +static inline struct sk_buff * +backported_cfg80211_vendor_event_alloc(struct wiphy *wiphy, + struct wireless_dev *wdev, + int approxlen, + int event_idx, gfp_t gfp) +{ + return cfg80211_vendor_event_alloc(wiphy, approxlen, event_idx, gfp); +} +#define cfg80211_vendor_event_alloc backported_cfg80211_vendor_event_alloc +#endif +int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter); + +enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type); +#endif + diff --git a/core/hdd/src/wlan_hdd_conc_ut.c b/core/hdd/src/wlan_hdd_conc_ut.c new file mode 100644 index 0000000000..8ed71dd233 --- /dev/null +++ b/core/hdd/src/wlan_hdd_conc_ut.c @@ -0,0 +1,865 @@ +/* + * Copyright (c)2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include files */ + +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "cds_concurrency.h" +#include "wlan_hdd_conc_ut.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cds_utils.h" +#include "cds_reg_service.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_api.h" + +#define NUMBER_OF_SCENARIO 300 +#define MAX_ALLOWED_CHAR_IN_REPORT 50 + +/** + * struct report_t: Data structure to fill report + * + * @title: title of the concurrency case scenario + * @first_persona: device type of first persona + * @second_persona: device type of second persona + * @third_persona: device type of third persona + * @dbs_value: string to mention whether dbs enable or disable + * @system_conf: string to mention what is system's configuration + * @status: status field + * @result_code: string to mention whether test case passed or failed + * @reason: reason why test case failed + * @pcl: preferred channel list + * + * This structure will be used by unit test framework to fill + * report after running various concurrency scenarios. + */ +struct report_t { + char title[2 * MAX_ALLOWED_CHAR_IN_REPORT]; + char first_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char second_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char third_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char dbs_value[MAX_ALLOWED_CHAR_IN_REPORT]; + char system_conf[MAX_ALLOWED_CHAR_IN_REPORT]; + bool status; + char result_code[MAX_ALLOWED_CHAR_IN_REPORT]; + char reason[MAX_ALLOWED_CHAR_IN_REPORT]; + char pcl[2 * MAX_NUM_CHAN]; +}; + +static struct report_t report[NUMBER_OF_SCENARIO]; +static uint32_t report_idx; + +static uint8_t wlan_hdd_valid_type_of_persona(uint32_t sub_type) +{ + switch (sub_type) { + case CDS_STA_MODE: + return WMI_VDEV_TYPE_STA; + case CDS_IBSS_MODE: + return WMI_VDEV_TYPE_IBSS; + case CDS_SAP_MODE: + case CDS_P2P_CLIENT_MODE: + case CDS_P2P_GO_MODE: + return WMI_VDEV_TYPE_AP; + default: + return WMI_VDEV_TYPE_STA; + } +} + +static const char *system_config_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_THROUGHPUT); + CASE_RETURN_STRING(CDS_POWERSAVE); + CASE_RETURN_STRING(CDS_LATENCY); + default: + return "Unknown"; + } + +} + +static const char *device_mode_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_STA_MODE); + CASE_RETURN_STRING(CDS_SAP_MODE); + CASE_RETURN_STRING(CDS_P2P_CLIENT_MODE); + CASE_RETURN_STRING(CDS_P2P_GO_MODE); + CASE_RETURN_STRING(CDS_IBSS_MODE); + default: + return "none"; + } +} + +static const char *pcl_type_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_NONE); + CASE_RETURN_STRING(CDS_24G); + CASE_RETURN_STRING(CDS_5G); + CASE_RETURN_STRING(CDS_SCC_CH); + CASE_RETURN_STRING(CDS_MCC_CH); + CASE_RETURN_STRING(CDS_SCC_CH_24G); + CASE_RETURN_STRING(CDS_SCC_CH_5G); + CASE_RETURN_STRING(CDS_24G_SCC_CH); + CASE_RETURN_STRING(CDS_5G_SCC_CH); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24_24G); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24_5G); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5_24G); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5_5G); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5); + CASE_RETURN_STRING(CDS_MCC_CH_24G); + CASE_RETURN_STRING(CDS_MCC_CH_5G); + CASE_RETURN_STRING(CDS_24G_MCC_CH); + CASE_RETURN_STRING(CDS_5G_MCC_CH); + default: + return "Unknown"; + } +} + +void clean_report(hdd_context_t *hdd_ctx) +{ + uint32_t idx = 0; + while (idx < NUMBER_OF_SCENARIO) { + cdf_mem_zero(&report[idx], sizeof(struct report_t)); + idx++; + } + report_idx = 0; +} + +void print_report(hdd_context_t *hdd_ctx) +{ + uint32_t idx = 0; + pr_info("+----------Report start -----------+\n"); + while (idx < report_idx) { + pr_info("Idx:[%d]\nTitle:%s\nResult:[%s]\n\t1st_person[%s]\n\t2nd_persona[%s]\n\t3rd_persona[%s]\n\tDBS[%s]\n\tsystem_config[%s]\n\treason[%s]\n\tpcl[%s]\n", + idx, + report[idx].title, report[idx].result_code, + report[idx].first_persona, report[idx].second_persona, + report[idx].third_persona, report[idx].dbs_value, + report[idx].system_conf, report[idx].reason, + report[idx].pcl); + idx++; + } + pr_info("+----------Report end -----------+\n"); +} + +void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum cds_pcl_type pcl_type, char *reason, uint8_t *pcl) +{ + int i; + char buf[4] = {0}; + + if (report_idx >= NUMBER_OF_SCENARIO) + return; + snprintf(report[report_idx].title, + 2 * MAX_ALLOWED_CHAR_IN_REPORT, "pcl for[%s] pcl_type[%s]", + title, pcl_type_to_string(pcl_type)); + if (chnl_1st_conn == 0) + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + device_mode_to_string(first_persona)); + else + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(first_persona), chnl_1st_conn); + if (chnl_2nd_conn == 0) + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + device_mode_to_string(second_persona)); + else + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(second_persona), chnl_2nd_conn); + if (chnl_3rd_conn == 0) + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + device_mode_to_string(third_persona)); + else + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(third_persona), chnl_3rd_conn); + + report[report_idx].status = status; + snprintf(report[report_idx].dbs_value, + MAX_ALLOWED_CHAR_IN_REPORT, + wma_is_hw_dbs_capable() ? "enable" : "disable"); + snprintf(report[report_idx].system_conf, + MAX_ALLOWED_CHAR_IN_REPORT, + system_config_to_string(hdd_ctx->config->conc_system_pref)); + snprintf(report[report_idx].result_code, + MAX_ALLOWED_CHAR_IN_REPORT, + status ? "PASS" : "FAIL"); + snprintf(report[report_idx].reason, + MAX_ALLOWED_CHAR_IN_REPORT, + reason); + if (pcl) { + cdf_mem_zero(report[report_idx].pcl, + sizeof(report[report_idx].pcl)); + for (i = 0; i < MAX_NUM_CHAN; i++) { + if (pcl[i] == 0) + break; + cdf_mem_zero(buf, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d ", pcl[i]); + strlcat(report[report_idx].pcl, buf, + sizeof(report[report_idx].pcl)); + strlcat(report[report_idx].pcl, ", ", + sizeof(report[report_idx].pcl)); + } + } + report_idx++; +} + +static bool wlan_hdd_validate_pcl(hdd_context_t *hdd_ctx, + enum cds_pcl_type pcl_type, uint8_t *pcl, uint32_t pcl_len, + uint8_t first_connection_chnl, uint8_t second_connection_chnl, + char *reason, uint32_t reason_length) +{ + bool status = true; + uint32_t first_idx = 0; + + if ((pcl_type != CDS_NONE) && (pcl_len == 0)) { + snprintf(reason, reason_length, "no of channels = 0"); + return false; + } + + switch (pcl_type) { + case CDS_NONE: + if (pcl_len != 0) { + snprintf(reason, reason_length, "no of channels>0"); + return false; + } + break; + case CDS_5G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!CDS_IS_CHANNEL_5GHZ(pcl[first_idx])) { + snprintf(reason, reason_length, + "2G channel found"); + return false; + } + } + break; + case CDS_24G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!CDS_IS_CHANNEL_24GHZ(pcl[first_idx])) { + snprintf(reason, reason_length, + "5G channel found"); + return false; + } + } + break; + case CDS_SCC_CH: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_MCC_CH: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_SCC_CH_24G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + break; + case CDS_SCC_CH_5G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case CDS_24G_SCC_CH: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_5G_SCC_CH: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_MCC_CH_24G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + break; + case CDS_MCC_CH_5G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case CDS_24G_MCC_CH: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_5G_MCC_CH: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24_24G: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24_5G: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5_24G: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5_5G: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + default: + snprintf(reason, reason_length, + "Unknown option"); + status = false; + } + if (status == true) { + snprintf(reason, reason_length, + "success"); + } + return status; +} + +static void wlan_hdd_map_subtypes_hdd_wma(enum cds_con_mode *dst, + enum cds_con_mode *src) +{ + /* + * wma defined sap subtype as 0 + * Rest of the mappings are same + * In future, if mapping gets changed then re-map it here + */ + if (*src == CDS_SAP_MODE) + *dst = 0; + else + *dst = *src; +} + +void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx) +{ + enum cds_con_mode sub_type; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + uint8_t pcl[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + bool status = false; + enum cds_pcl_type pcl_type; + char reason[20] = {0}; + CDF_STATUS ret; + + /* flush the entire table first */ + ret = cds_init_policy_mgr(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + for (sub_type = 0; sub_type < CDS_MAX_NUM_OF_MODE; sub_type++) { + /* validate one connection is created or no */ + if (cds_get_connection_count(hdd_ctx) != 0) { + hddLog(LOGE, + FL("Test failed - No. of connection is not 0")); + return; + } + cdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = get_pcl_from_first_conn_table(sub_type, system_pref); + + /* check PCL value for second connection is correct or no */ + cds_get_pcl(hdd_ctx, sub_type, pcl, &pcl_len); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, 0, 0, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && (pcl[0] == 0)) + continue; + + fill_report(hdd_ctx, "1 connection", sub_type, + CDS_MAX_NUM_OF_MODE, + CDS_MAX_NUM_OF_MODE, + 0, 0, 0, + status, pcl_type, reason, pcl); + } +} + +void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum cds_chain_mode first_chain_mask) +{ + uint8_t vdevid = 0, tx_stream = 2, rx_stream = 2; + uint8_t type = WMI_VDEV_TYPE_STA, channel_id = first_chnl, mac_id = 1; + uint8_t pcl[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum cds_chain_mode chain_mask = first_chain_mask; + enum cds_con_mode sub_type, next_sub_type, dummy_type; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum cds_pcl_type pcl_type; + enum cds_one_connection_mode second_index; + char reason[20] = {0}; + bool status = false; + CDF_STATUS ret; + + for (sub_type = CDS_STA_MODE; + sub_type < CDS_MAX_NUM_OF_MODE; sub_type++) { + type = wlan_hdd_valid_type_of_persona(sub_type); + + /* flush the entire table first */ + ret = cds_init_policy_mgr(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type, &sub_type); + /* add first connection as STA */ + cds_incr_connection_count_utfw(hdd_ctx, vdevid, tx_stream, + rx_stream, chain_mask, type, dummy_type, + channel_id, mac_id); + /* validate one connection is created or no */ + if (cds_get_connection_count(hdd_ctx) != 1) { + hddLog(LOGE, + FL("Test failed - No. of connection is not 1")); + return; + } + next_sub_type = CDS_STA_MODE; + while (next_sub_type < CDS_MAX_NUM_OF_MODE) { + /* get the PCL value & check the channels accordingly */ + second_index = + cds_get_second_connection_pcl_table_index( + hdd_ctx); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + /* not valid combination*/ + hddLog(LOGE, FL("couldn't find index for 2nd connection pcl table")); + next_sub_type++; + continue; + } + cdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = get_pcl_from_second_conn_table(second_index, + next_sub_type, system_pref, + wma_is_hw_dbs_capable()); + /* check PCL for second connection is correct or no */ + cds_get_pcl(hdd_ctx, next_sub_type, pcl, &pcl_len); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, channel_id, 0, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "2 connections", sub_type, + next_sub_type, + CDS_MAX_NUM_OF_MODE, first_chnl, + 0, 0, status, pcl_type, reason, pcl); + next_sub_type++; + } + } +} + +void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum cds_chain_mode chain_mask, uint8_t use_same_mac) +{ + uint8_t vdevid_1 = 0, tx_stream_1 = 2, rx_stream_1 = 2; + uint8_t vdevid_2 = 1, tx_stream_2 = 2, rx_stream_2 = 2; + uint8_t channel_id_1 = first_chnl, channel_id_2 = second_chnl; + uint8_t mac_id_1, mac_id_2; + uint8_t type_1 = WMI_VDEV_TYPE_STA, type_2 = WMI_VDEV_TYPE_STA; + uint8_t pcl[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum cds_chain_mode chain_mask_1; + enum cds_chain_mode chain_mask_2; + enum cds_con_mode sub_type_1, sub_type_2, next_sub_type; + enum cds_con_mode dummy_type_1, dummy_type_2; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum cds_pcl_type pcl_type; + enum cds_two_connection_mode third_index; + char reason[20] = {0}; + bool status = false; + CDF_STATUS ret; + + /* let's set the chain_mask, mac_ids*/ + if (chain_mask == CDS_TWO_TWO) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = CDS_TWO_TWO; + chain_mask_2 = CDS_TWO_TWO; + } else if (use_same_mac == 1) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = CDS_ONE_ONE; + chain_mask_2 = CDS_ONE_ONE; + } else { + mac_id_1 = 1; + mac_id_2 = 2; + chain_mask_1 = CDS_ONE_ONE; + chain_mask_2 = CDS_ONE_ONE; + } + + for (sub_type_1 = CDS_STA_MODE; + sub_type_1 < CDS_MAX_NUM_OF_MODE; sub_type_1++) { + + type_1 = wlan_hdd_valid_type_of_persona(sub_type_1); + /* flush the entire table first */ + ret = cds_init_policy_mgr(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_1, &sub_type_1); + /* add first connection as STA */ + cds_incr_connection_count_utfw(hdd_ctx, vdevid_1, + tx_stream_1, rx_stream_1, chain_mask_1, type_1, + dummy_type_1, channel_id_1, mac_id_1); + /* validate one connection is created or no */ + if (cds_get_connection_count(hdd_ctx) != 1) { + hddLog(LOGE, + FL("Test fail - No. of connection not 1")); + return; + } + for (sub_type_2 = CDS_STA_MODE; + sub_type_2 < CDS_MAX_NUM_OF_MODE; sub_type_2++) { + + type_2 = wlan_hdd_valid_type_of_persona(sub_type_2); + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_2, + &sub_type_2); + cds_incr_connection_count_utfw(hdd_ctx, vdevid_2, + tx_stream_2, rx_stream_2, chain_mask_2, type_2, + dummy_type_2, channel_id_2, mac_id_2); + /* validate two connections are created or no */ + if (cds_get_connection_count(hdd_ctx) != 2) { + hddLog(LOGE, + FL("Test fail - No. connection not 2")); + return; + } + next_sub_type = CDS_STA_MODE; + while (next_sub_type < CDS_MAX_NUM_OF_MODE) { + third_index = + cds_get_third_connection_pcl_table_index( + hdd_ctx); + if (CDS_MAX_TWO_CONNECTION_MODE == + third_index) { + /* not valid combination */ + next_sub_type++; + continue; + } + cdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = + get_pcl_from_third_conn_table( + third_index, next_sub_type, + system_pref, + wma_is_hw_dbs_capable()); + cds_get_pcl(hdd_ctx, next_sub_type, + pcl, &pcl_len); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, + channel_id_1, channel_id_2, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && + (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "3 connections", + sub_type_1, sub_type_2, + next_sub_type, first_chnl, + second_chnl, 0, status, + pcl_type, reason, pcl); + next_sub_type++; + } + /* remove entry to make a room for next iteration */ + cds_decr_connection_count(hdd_ctx, vdevid_2); + } + next_sub_type = CDS_STA_MODE; + } +} diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c new file mode 100644 index 0000000000..cf7747ee45 --- /dev/null +++ b/core/hdd/src/wlan_hdd_debugfs.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_debugfs.c + * + * This driver currently supports the following debugfs files: + * wlan_wcnss/wow_enable to enable/disable WoWL. + * wlan_wcnss/wow_pattern to configure WoWL patterns. + * wlan_wcnss/pattern_gen to configure periodic TX patterns. + */ + +#ifdef WLAN_OPEN_SOURCE +#include +#include +#include + +#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8 +#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512 +#define MAX_USER_COMMAND_SIZE_FRAME 4096 + +/** + * __wcnss_wowenable_write() - wow_enable debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_wowenable_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter; + hdd_context_t *hdd_ctx; + char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1]; + char *sptr, *token; + uint8_t wow_enable = 0; + uint8_t wow_mp = 0; + uint8_t wow_pbm = 0; + int ret; + + pAdapter = (hdd_adapter_t *)file->private_data; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: Invalid adapter or adapter has invalid magic.", + __func__); + + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + + if (!sme_is_feature_supported_by_fw(WOW)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Wake-on-Wireless feature is not supported in firmware!", + __func__); + + return -EINVAL; + } + + if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Command length is larger than %d bytes.", + __func__, MAX_USER_COMMAND_SIZE_WOWL_ENABLE); + + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(cmd, buf, count)) + return -EFAULT; + cmd[count] = '\0'; + sptr = cmd; + + /* Get enable or disable wow */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_enable)) + return -EINVAL; + + /* Disable wow */ + if (!wow_enable) { + if (!hdd_exit_wowl(pAdapter)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: hdd_exit_wowl failed!", __func__); + + return -EFAULT; + } + + return count; + } + + /* Get enable or disable magic packet mode */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_mp)) + return -EINVAL; + if (wow_mp > 1) + wow_mp = 1; + + /* Get enable or disable pattern byte matching mode */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_pbm)) + return -EINVAL; + if (wow_pbm > 1) + wow_pbm = 1; + + if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: hdd_enter_wowl failed!", __func__); + + return -EFAULT; + } + + return count; +} + +/** + * wcnss_wowenable_write() - SSR wrapper for wcnss_wowenable_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_wowenable_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_wowenable_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wcnss_wowpattern_write() - wow_pattern debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_wowpattern_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) file->private_data; + hdd_context_t *hdd_ctx; + char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1]; + char *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_offset = 0; + char *pattern_buf; + char *pattern_mask; + int ret; + + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: Invalid adapter or adapter has invalid magic.", + __func__); + + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!sme_is_feature_supported_by_fw(WOW)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Wake-on-Wireless feature is not supported in firmware!", + __func__); + + return -EINVAL; + } + + if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Command length is larger than %d bytes.", + __func__, MAX_USER_COMMAND_SIZE_WOWL_PATTERN); + + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(cmd, buf, count)) + return -EFAULT; + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + if (kstrtou8(token, 0, &pattern_idx)) + return -EINVAL; + + /* Get pattern offset */ + token = strsep(&sptr, " "); + + /* Delete pattern if no further argument */ + if (!token) { + hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx); + + return count; + } + + if (kstrtou8(token, 0, &pattern_offset)) + return -EINVAL; + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_buf = token; + + /* Get pattern mask */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_mask = token; + pattern_mask[strlen(pattern_mask) - 1] = '\0'; + + hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset, + pattern_buf, pattern_mask); + + return count; +} + +/** + * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_wowpattern_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_wowpattern_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wcnss_patterngen_write() - pattern_gen debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_patterngen_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter; + hdd_context_t *pHddCtx; + tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams; + tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams; + + char *cmd, *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_duration = 0; + char *pattern_buf; + uint16_t pattern_len = 0; + uint16_t i = 0; + CDF_STATUS status; + int ret; + + + pAdapter = (hdd_adapter_t *)file->private_data; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: Invalid adapter or adapter has invalid magic.", + __func__); + + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Periodic Tx Pattern Offload feature is not supported in firmware!", + __func__); + return -EINVAL; + } + + /* Get command from user */ + if (count <= MAX_USER_COMMAND_SIZE_FRAME) + cmd = cdf_mem_malloc(count + 1); + else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Command length is larger than %d bytes.", + __func__, MAX_USER_COMMAND_SIZE_FRAME); + + return -EINVAL; + } + + if (!cmd) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation for cmd failed!")); + return -ENOMEM; + } + + if (copy_from_user(cmd, buf, count)) { + cdf_mem_free(cmd); + return -EFAULT; + } + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_idx)) + goto failure; + + if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Pattern index %d is not in the range (0 ~ %d).", + __func__, pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1); + + goto failure; + } + + /* Get pattern duration */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_duration)) + goto failure; + + /* Delete pattern using index if duration is 0 */ + if (!pattern_duration) { + delPeriodicTxPtrnParams = + cdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn)); + if (!delPeriodicTxPtrnParams) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failed!")); + cdf_mem_free(cmd); + return -ENOMEM; + } + delPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx; + cdf_mem_copy(delPeriodicTxPtrnParams->macAddress, + pAdapter->macAddressCurrent.bytes, 6); + + /* Delete pattern */ + status = sme_del_periodic_tx_ptrn(pHddCtx->hHal, + delPeriodicTxPtrnParams); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_del_periodic_tx_ptrn() failed!", + __func__); + + cdf_mem_free(delPeriodicTxPtrnParams); + goto failure; + } + cdf_mem_free(cmd); + cdf_mem_free(delPeriodicTxPtrnParams); + return count; + } + + /* + * In SAP mode allow configuration without any connection check + * In STA mode check if it's in connected state before adding + * patterns + */ + hdd_info("device mode %d", pAdapter->device_mode); + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && + (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Not in Connected state!", __func__); + goto failure; + } + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + + pattern_buf = token; + pattern_buf[strlen(pattern_buf) - 1] = '\0'; + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed pattern!", __func__); + + goto failure; + } else + pattern_len >>= 1; + + if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Not an 802.3 frame!", __func__); + + goto failure; + } + + addPeriodicTxPtrnParams = cdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn)); + if (!addPeriodicTxPtrnParams) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failed!")); + cdf_mem_free(cmd); + return -ENOMEM; + } + + addPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500; + addPeriodicTxPtrnParams->ucPtrnSize = pattern_len; + cdf_mem_copy(addPeriodicTxPtrnParams->macAddress, + pAdapter->macAddressCurrent.bytes, 6); + + /* Extract the pattern */ + for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) { + addPeriodicTxPtrnParams->ucPattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Add pattern */ + status = sme_add_periodic_tx_ptrn(pHddCtx->hHal, + addPeriodicTxPtrnParams); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_add_periodic_tx_ptrn() failed!", __func__); + + cdf_mem_free(addPeriodicTxPtrnParams); + goto failure; + } + cdf_mem_free(cmd); + cdf_mem_free(addPeriodicTxPtrnParams); + return count; + +failure: + cdf_mem_free(cmd); + return -EINVAL; +} + +/** + * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_patterngen_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_patterngen_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wcnss_debugfs_open() - Generic debugfs open() handler + * @inode: inode of the debugfs file + * @file: file handle of the debugfs file + * + * Return: 0 + */ +static int __wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + if (inode->i_private) + file->private_data = inode->i_private; + + adapter = (hdd_adapter_t *)file->private_data; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: Invalid adapter or adapter has invalid magic.", + __func__); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return 0; +} + +/** + * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open + * @inode: inode pointer + * @file: file pointer + * + * Return: 0 on success, error number otherwise + */ +static int wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wcnss_debugfs_open(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct file_operations fops_wowenable = { + .write = wcnss_wowenable_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_wowpattern = { + .write = wcnss_wowpattern_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_patterngen = { + .write = wcnss_patterngen_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/** + * hdd_debugfs_init() - Initialize debugfs interface + * @pAdapter: primary wlan adapter + * + * Register support for the debugfs files supported by the driver. + * + * NB: The current implementation only supports debugfs operations + * on the primary interface, i.e. wlan0 + * + * Return: CDF_STATUS_SUCCESS if all files registered, + * CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + pHddCtx->debugfs_phy = debugfs_create_dir("wlan_wcnss", 0); + + if (NULL == pHddCtx->debugfs_phy) + return CDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR, + pHddCtx->debugfs_phy, pAdapter, + &fops_wowenable)) + return CDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR, + pHddCtx->debugfs_phy, pAdapter, + &fops_wowpattern)) + return CDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR, + pHddCtx->debugfs_phy, pAdapter, + &fops_patterngen)) + return CDF_STATUS_E_FAILURE; + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_debugfs_exit() - Shutdown debugfs interface + * @pHddCtx: the global HDD context + * + * Unregister support for the debugfs files supported by the driver. + * + * Return: None + */ +void hdd_debugfs_exit(hdd_context_t *pHddCtx) +{ + debugfs_remove_recursive(pHddCtx->debugfs_phy); +} +#endif /* #ifdef WLAN_OPEN_SOURCE */ diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c new file mode 100644 index 0000000000..d8a1f67364 --- /dev/null +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#ifdef HIF_PCI +#ifdef CONFIG_CNSS +#include +#endif /* CONFIG_CNSS */ +#else +#include +#endif /* HIF_PCI */ +#include "cds_api.h" +#include "cdf_status.h" +#include "cdf_lock.h" +#include "cds_sched.h" +#include "osdep.h" +#include "hif.h" +#include "epping_main.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_logging_sock_svc.h" +#include "wma_api.h" +#include "wlan_hdd_napi.h" + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#ifdef HIF_PCI +#ifdef CONFIG_CNSS +#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \ + cnss_wlan_register_driver(wlan_drv_ops) +#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \ + cnss_wlan_unregister_driver(wlan_drv_ops) +#else +#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \ + pci_register_driver(wlan_drv_ops) +#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \ + pci_unregister_driver(wlan_drv_ops) +#endif /* CONFIG_CNSS */ +#else +#define WLAN_HDD_REGISTER_DRIVER(wlan_drv_ops) \ + icnss_register_driver(wlan_drv_ops) +#define WLAN_HDD_UNREGISTER_DRIVER(wlan_drv_ops) \ + icnss_unregister_driver(wlan_drv_ops) +#endif /* HIF_PCI */ + +/** + * wlan_hdd_probe() - handles probe request + * + * This function is called to probe the wlan driver + * + * @dev: wlan device structure + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * @reinit: true if we are reinitiallizing the driver after a subsystem restart + * + * Return: 0 on successfull probe + */ +static int wlan_hdd_probe(struct device *dev, void *bdev, const hif_bus_id *bid, + enum ath_hal_bus_type bus_type, bool reinit) +{ + void *hif_ctx; + CDF_STATUS status; + int ret; + + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + status = epping_open(); + if (status != CDF_STATUS_SUCCESS) + return status; + } + + status = hif_open(); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("hif_open error = %d"), status); + return -EFAULT; + } + hif_ctx = cds_get_context(CDF_MODULE_ID_HIF); + if (reinit) + hdd_napi_destroy(true); + status = hdd_napi_create(); + if (hdd_napi_enabled(HDD_NAPI_ANY)) { + hdd_info("hdd_napi_create returned: %d\n", status); + if (status <= 0) { + hdd_err("NAPI creation error, rc: 0x%x, reinit = %d", + status, reinit); + return -EFAULT; + } + } + + status = hif_enable(hif_ctx, dev, bdev, bid, + bus_type, (reinit == true) ? + HIF_ENABLE_TYPE_REINIT : HIF_ENABLE_TYPE_PROBE); + if (status != CDF_STATUS_SUCCESS) { + hdd_err("hif_enable error = %d, reinit = %d", + status, reinit); + ret = -EIO; + goto end; + } + + if (reinit) + ret = hdd_wlan_re_init(hif_ctx); + else + ret = hdd_wlan_startup(dev, hif_ctx); + +end: + if (ret) { + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + hif_pktlogmod_exit(hif_ctx); + epping_disable(); + htc_destroy(cds_get_context(CDF_MODULE_ID_HTC)); + hif_disable(hif_ctx, (reinit == true) ? + HIF_ENABLE_TYPE_REINIT : HIF_ENABLE_TYPE_PROBE); + cds_free_context(NULL, CDF_MODULE_ID_HTC, NULL); + epping_close(); + } else { + hif_pktlogmod_exit(hif_ctx); + __hdd_wlan_exit(); + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + } + hif_close(hif_ctx); + } + + if (reinit) + cds_set_logp_in_progress(false); + + return ret; +} + +/** + * wlan_hdd_remove() - wlan_hdd_remove + * + * This function is called by the platform driver to remove the + * driver + * + * Return: void + */ +static void wlan_hdd_remove(void) +{ + void *hif_ctx; + v_CONTEXT_t p_cds_context = NULL; + + /* Get the global cds context */ + p_cds_context = cds_get_global_context(); + + hif_ctx = cds_get_context(CDF_MODULE_ID_HIF); + + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + hif_pktlogmod_exit(hif_ctx); + epping_disable(); + htc_destroy(cds_get_context(CDF_MODULE_ID_HTC)); + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + cds_free_context(NULL, CDF_MODULE_ID_HTC, NULL); + epping_close(); + } else { + hif_pktlogmod_exit(hif_ctx); + __hdd_wlan_exit(); + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + } + + hdd_napi_destroy(true); + hif_close(hif_ctx); + + cds_free_global_context(&p_cds_context); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_deinit_svc(); +#endif + + cdf_wake_lock_destroy(hdd_wlan_get_wake_lock_ptr()); + + pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME); +} + +/** + * wlan_hdd_shutdown() - wlan_hdd_shutdown + * + * This is routine is called by platform driver to shutdown the + * driver + * + * Return: void + */ +static void wlan_hdd_shutdown(void) +{ + void *hif_ctx = cds_get_context(CDF_MODULE_ID_HIF); + + if (cds_is_load_unload_in_progress()) { + hddLog(LOGE, + FL("Load/unload in progress, ignore SSR shutdown")); + return; + } + /* this is for cases, where shutdown invoked from CNSS */ + cds_set_logp_in_progress(true); + + if (cds_get_conparam() != CDF_FTM_MODE && + !WLAN_IS_EPPING_ENABLED(cds_get_conparam())) + hif_pktlogmod_exit(hif_ctx); + + if (!cds_is_ssr_ready(__func__)) + hddLog(LOGE, + FL("Host is not ready for SSR, attempting anyway")); + + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam())) + hdd_wlan_shutdown(); + + hif_disable(hif_ctx, HIF_DISABLE_TYPE_SHUTDOWN); + hif_close(hif_ctx); +} + +/** + * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown + * + * HDD crash shutdown funtion: This function is called by + * platfrom driver's crash shutdown routine + * + * Return: void + */ +void wlan_hdd_crash_shutdown(void) +{ + hif_crash_shutdown(cds_get_context(CDF_MODULE_ID_HIF)); +} + +/** + * wlan_hdd_notify_handler() - wlan_hdd_notify_handler + * + * This function is called by the platform driver to notify the + * COEX + * + * @state: state + * + * Return: void + */ +void wlan_hdd_notify_handler(int state) +{ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + int ret = 0; + ret = hdd_wlan_notify_modem_power_state(state); + if (ret < 0) + hddLog(LOGE, FL("Fail to send notify")); + } +} + +/** + * __wlan_hdd_bus_suspend() - handles platform supsend + * @state: suspend message from the kernel + * + * Does precondtion validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. + * Calls ol_txrx_bus_suspend to ensure the layer is ready for a bus suspend. + * Calls wma_suspend to configure offloads. + * Calls hif_suspend to suspend the bus. + * + * Return: 0 for success, -EFAULT for null pointers, + * -EBUSY or -EAGAIN if another opperation is in progress and + * wlan will not be ready to suspend in time. + */ +static int __wlan_hdd_bus_suspend(pm_message_t state) +{ + void *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + int err = wlan_hdd_validate_context(hdd_ctx); + int status; + + hdd_info("event %d", state.event); + + if (err) + goto done; + + err = cdf_status_to_os_return( + ol_txrx_bus_suspend()); + if (err) + goto done; + + err = wma_bus_suspend(); + if (err) + goto resume_oltxrx; + + err = hif_bus_suspend(); + if (err) + goto resume_wma; + + hdd_info("suspend done, status = %d", err); + return err; + +resume_wma: + status = wma_bus_resume(); + CDF_BUG(!status); +resume_oltxrx: + status = ol_txrx_bus_resume(); + CDF_BUG(!status); +done: + hdd_err("suspend done, status = %d", err); + return err; +} + +/** + * wlan_hdd_bus_suspend() - suspend the wlan bus + * + * This function is called by the platform driver to suspend the + * wlan bus + * + * @state: state + * + * Return: CDF_STATUS + */ +int wlan_hdd_bus_suspend(pm_message_t state) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend(state); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_bus_resume() - handles platform resume + * + * Does precondtion validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. Ensures that + * it has valid pointers for the required contexts. + * Calls into hif to resume the bus opperation. + * Calls into wma to handshake with firmware and notify it that the bus is up. + * Calls into ol_txrx for symetry. + * Failures are treated as catastrophic. + * + * return: error code or 0 for success + */ +static int __wlan_hdd_bus_resume(void) +{ + void *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + int status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + status = hif_bus_resume(); + CDF_BUG(!status); + + status = wma_bus_resume(); + CDF_BUG(!status); + + status = ol_txrx_bus_resume(); + CDF_BUG(!status); + + hdd_info("resume done"); + return status; +} + +/** + * wlan_hdd_bus_resume(): wake up the bus + * + * This function is called by the platform driver to resume wlan + * bus + * + * Return: void + */ +static int wlan_hdd_bus_resume(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_resume(); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef HIF_PCI +/** + * wlan_hdd_pci_probe() - probe callback for pci platform driver + * @pdev: bus dev + * + * Return: void + */ +static int wlan_hdd_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + return wlan_hdd_probe(&pdev->dev, pdev, (void *)id, + HAL_BUS_TYPE_PCI, false); +} + +/** + * wlan_hdd_pci_remove() - wlan_hdd_pci_remove + * + * Return: void + */ +void wlan_hdd_pci_remove(struct pci_dev *pdev) +{ + wlan_hdd_remove(); +} + +/** + * wlan_hdd_pci_reinit() - wlan_hdd_pci_reinit + * @pdev: bus dev + * @id: bus id + * + * Return: int + */ +int wlan_hdd_pci_reinit(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + return wlan_hdd_probe(&pdev->dev, pdev, id, + HAL_BUS_TYPE_PCI, true); +} + +/** + * wlan_hdd_pci_shutdown() - wlan_hdd_pci_shutdown + * @pdev: pdev + * + * Return: void + */ +void wlan_hdd_pci_shutdown(struct pci_dev *pdev) +{ + wlan_hdd_shutdown(); +} + +/** + * wlan_hdd_pci_crash_shutdown() - wlan_hdd_pci_crash_shutdown + * @pdev: pdev + * + * Return: void + */ +void wlan_hdd_pci_crash_shutdown(struct pci_dev *pdev) +{ + wlan_hdd_crash_shutdown(); +} + +/** + * wlan_hdd_pci_notify_handler() - wlan_hdd_pci_notify_handler + * @pdev: pdev + * @state: state + * + * Return: void + */ +void wlan_hdd_pci_notify_handler(struct pci_dev *pdev, int state) +{ + wlan_hdd_notify_handler(state); +} + +/** + * wlan_hdd_pci_suspend() - wlan_hdd_pci_suspend + * @pdev: pdev + * @state: state + * + * Return: void + */ +static int wlan_hdd_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + return wlan_hdd_bus_suspend(state); +} + +/** + * wlan_hdd_pci_resume() - wlan_hdd_pci_resume + * @pdev: pdev + * + * Return: void + */ +static int wlan_hdd_pci_resume(struct pci_dev *pdev) +{ + return wlan_hdd_bus_resume(); +} +#else +/** + * wlan_hdd_snoc_probe() - wlan_hdd_snoc_probe + * @dev: dev + * + * Return: int + */ +static int wlan_hdd_snoc_probe(struct device *dev) +{ + return wlan_hdd_probe(dev, NULL, NULL, HAL_BUS_TYPE_SNOC, false); +} + +/** + * wlan_hdd_snoc_remove() - wlan_hdd_snoc_remove + * @dev: dev + * + * Return: void + */ +void wlan_hdd_snoc_remove(struct device *dev) +{ + wlan_hdd_remove(); +} + +/** + * wlan_hdd_snoc_shutdown() - wlan_hdd_snoc_shutdown + * @dev: dev + * + * Return: void + */ +void wlan_hdd_snoc_shutdown(struct device *dev) +{ + wlan_hdd_shutdown(); +} + +/** + * wlan_hdd_snoc_reinit() - wlan_hdd_snoc_reinit + * @dev: dev + * + * Return: int + */ +int wlan_hdd_snoc_reinit(struct device *dev) +{ + return wlan_hdd_probe(dev, NULL, NULL, HAL_BUS_TYPE_SNOC, true); +} + +/** + * wlan_hdd_snoc_crash_shutdown() - wlan_hdd_snoc_crash_shutdown + * @dev: dev + * + * Return: void + */ +void wlan_hdd_snoc_crash_shutdown(void *pdev) +{ + wlan_hdd_crash_shutdown(); +} + +/** + * wlan_hdd_snoc_suspend() - wlan_hdd_snoc_suspend + * @dev: dev + * @state: state + * + * Return: int + */ +static int wlan_hdd_snoc_suspend(struct device *dev, pm_message_t state) +{ + return wlan_hdd_bus_suspend(state); +} + +/** + * wlan_hdd_snoc_resume() - wlan_hdd_snoc_resume + * @dev: dev + * + * Return: int + */ +static int wlan_hdd_snoc_resume(struct device *dev) +{ + return wlan_hdd_bus_resume(); +} +#endif /* HIF_PCI */ + +#ifdef HIF_PCI +static struct pci_device_id wlan_hdd_pci_id_table[] = { + { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +#ifdef CONFIG_CNSS +struct cnss_wlan_driver wlan_drv_ops = { + .name = "wlan_hdd_pci", + .id_table = wlan_hdd_pci_id_table, + .probe = wlan_hdd_pci_probe, + .remove = wlan_hdd_pci_remove, + .reinit = wlan_hdd_pci_reinit, + .shutdown = wlan_hdd_pci_shutdown, + .crash_shutdown = wlan_hdd_pci_crash_shutdown, + .modem_status = wlan_hdd_pci_notify_handler, +#ifdef ATH_BUS_PM + .suspend = wlan_hdd_pci_suspend, + .resume = wlan_hdd_pci_resume, +#endif /* ATH_BUS_PM */ +}; +#else +MODULE_DEVICE_TABLE(pci, wlan_hdd_pci_id_table); +struct pci_driver wlan_drv_ops = { + .name = "wlan_hdd_pci", + .id_table = wlan_hdd_pci_id_table, + .probe = wlan_hdd_pci_probe, + .remove = wlan_hdd_pci_remove, +#ifdef ATH_BUS_PM + .suspend = wlan_hdd_pci_suspend, + .resume = wlan_hdd_pci_resume, +#endif /* ATH_BUS_PM */ +}; +#endif /* CONFIG_CNSS */ +#else +struct icnss_driver_ops wlan_drv_ops = { + .name = "wlan_hdd_drv", + .probe = wlan_hdd_snoc_probe, + .remove = wlan_hdd_snoc_remove, + .shutdown = wlan_hdd_snoc_shutdown, + .reinit = wlan_hdd_snoc_reinit, + .crash_shutdown = wlan_hdd_snoc_crash_shutdown, + .suspend = wlan_hdd_snoc_suspend, + .resume = wlan_hdd_snoc_resume, +}; +#endif + +/** + * wlan_hdd_register_driver() - wlan_hdd_register_driver + * + * Return: int + */ +int wlan_hdd_register_driver(void) +{ + return WLAN_HDD_REGISTER_DRIVER(&wlan_drv_ops); +} + +/** + * wlan_hdd_unregister_driver() - wlan_hdd_unregister_driver + * + * Return: void + */ +void wlan_hdd_unregister_driver(void) +{ + WLAN_HDD_UNREGISTER_DRIVER(&wlan_drv_ops); +} diff --git a/core/hdd/src/wlan_hdd_ext_scan.c b/core/hdd/src/wlan_hdd_ext_scan.c new file mode 100644 index 0000000000..e5cf724e45 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ext_scan.c @@ -0,0 +1,4605 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_ext_scan.c + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_ext_scan.h" +#include "cds_utils.h" +#include "cds_sched.h" + +/* amount of time to wait for a synchronous request/response operation */ +#define WLAN_WAIT_TIME_EXTSCAN 1000 + +/** + * struct hdd_ext_scan_context - hdd ext scan context + * @request_id: userspace-assigned ID associated with the request + * @response_event: Ext scan wait event + * @response_status: Status returned by FW in response to a request + * @ignore_cached_results: Flag to ignore cached results or not + * @context_lock: Spinlock to serialize all context accesses + * @capability_response: Ext scan capability response data from target + */ +struct hdd_ext_scan_context { + uint32_t request_id; + int response_status; + bool ignore_cached_results; + struct completion response_event; + spinlock_t context_lock; + struct ext_scan_capabilities_response capability_response; +}; +static struct hdd_ext_scan_context ext_scan_context; + +static const struct nla_policy wlan_hdd_extscan_config_policy +[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = { + .type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] = { + .type = NLA_UNSPEC}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD] = { + .type = NLA_S8 }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = { + .type = NLA_U32 }, +}; + +static const struct nla_policy +wlan_hdd_extscan_results_policy[QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD] = { + .type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY] = { + .type = NLA_U16}, +}; + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target + * @ctx: Pointer to hdd context + * @data: Pointer to ext scan capabilities response from fw + * + * Return: None + */ +static void +wlan_hdd_cfg80211_extscan_get_capabilities_rsp(void *ctx, + struct ext_scan_capabilities_response *data) +{ + struct hdd_ext_scan_context *context; + hdd_context_t *hdd_ctx = ctx; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !data) { + hddLog(LOGE, FL("HDD context is invalid or data(%p) is null"), + data); + return; + } + + context = &ext_scan_context; + + spin_lock(&context->context_lock); + /* validate response received from target*/ + if (context->request_id != data->requestId) { + spin_unlock(&context->context_lock); + hddLog(LOGE, + FL("Target response id did not match: request_id %d response_id %d"), + context->request_id, data->requestId); + return; + } else { + context->capability_response = *data; + complete(&context->response_event); + } + + spin_unlock(&context->context_lock); + + return; +} + +/* + * define short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#define PARAM_TIME_STAMP \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP +#define PARAM_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID +#define PARAM_BSSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID +#define PARAM_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL +#define PARAM_RSSI \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI +#define PARAM_RTT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT +#define PARAM_RTT_SD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD +#define PARAM_BEACON_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD +#define PARAM_CAPABILITY \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY +#define PARAM_IE_LENGTH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH +#define PARAM_IE_DATA \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA + +/** hdd_extscan_nl_fill_bss() - extscan nl fill bss + * @skb: socket buffer + * @ap: bss information + * @idx: nesting index + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap, + int idx) +{ + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, idx); + if (!nla_ap) + return -EINVAL; + + if (nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) || + nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) || + nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) || + nla_put_u32(skb, PARAM_CHANNEL, ap->channel) || + nla_put_s32(skb, PARAM_RSSI, ap->rssi) || + nla_put_u32(skb, PARAM_RTT, ap->rtt) || + nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) || + nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) || + nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) || + nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) { + hddLog(LOGE, FL("put fail")); + return -EINVAL; + } + + if (ap->ieLength) + if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) { + hddLog(LOGE, FL("put fail")); + return -EINVAL; + } + + nla_nest_end(skb, nla_ap); + + return 0; +} +/* + * done with short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#undef PARAM_TIME_STAMP +#undef PARAM_SSID +#undef PARAM_BSSID +#undef PARAM_CHANNEL +#undef PARAM_RSSI +#undef PARAM_RTT +#undef PARAM_RTT_SD +#undef PARAM_BEACON_PERIOD +#undef PARAM_CAPABILITY +#undef PARAM_IE_LENGTH +#undef PARAM_IE_DATA + +/** wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results + * @ctx: hdd global context + * @data: cached results + * + * This function reads the cached results %data, populated the NL + * attributes and sends the NL event to the upper layer. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_cached_results_ind(void *ctx, + struct extscan_cached_scan_results *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + struct hdd_ext_scan_context *context; + struct extscan_cached_scan_result *result; + tSirWifiScanResult *ap; + uint32_t i, j, nl_buf_len; + bool ignore_cached_results = false; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !data) { + hddLog(LOGE, FL("HDD ctx invalid or data(%p) is null"), data); + return; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + ignore_cached_results = context->ignore_cached_results; + spin_unlock(&context->context_lock); + + if (ignore_cached_results) { + hddLog(LOGE, + FL("Ignore the cached results received after timeout")); + return; + } + +#define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN +#define EXTSCAN_CACHED_NL_FIXED_TLV \ + ((sizeof(data->request_id) + NLA_HDRLEN) + \ + (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \ + (sizeof(data->more_data) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_ID_TLV \ + ((sizeof(result->scan_id) + NLA_HDRLEN) + \ + (sizeof(result->flags) + NLA_HDRLEN) + \ + (sizeof(result->num_results) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \ + ((sizeof(ap->ts) + NLA_HDRLEN) + \ + (sizeof(ap->ssid) + NLA_HDRLEN) + \ + (sizeof(ap->bssid) + NLA_HDRLEN) + \ + (sizeof(ap->channel) + NLA_HDRLEN) + \ + (sizeof(ap->rssi) + NLA_HDRLEN) + \ + (sizeof(ap->rtt) + NLA_HDRLEN) + \ + (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \ + (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \ + (sizeof(ap->capability) + NLA_HDRLEN) + \ + (sizeof(ap->ieLength) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \ + (ap->ieLength + NLA_HDRLEN) + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV; + if (data->num_scan_ids) { + nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV; + if (ap->ieLength) + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV; + ap++; + } + result++; + } + } + + hddLog(LOG1, FL("nl_buf_len = %u"), nl_buf_len); + skb = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, nl_buf_len); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + goto fail; + } + hddLog(LOG1, "Req Id %u Num_scan_ids %u More Data %u", + data->request_id, data->num_scan_ids, data->more_data); + + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + hddLog(LOG1, "[i=%d] scan_id %u flags %u num_results %u", + i, result->scan_id, result->flags, result->num_results); + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + /* + * Firmware returns timestamp from ext scan start till + * BSSID was cached (in micro seconds). Add this with + * time gap between system boot up to ext scan start + * to derive the time since boot when the + * BSSID was cached. + */ + ap->ts += pHddCtx->ext_scan_start_since_boot; + hddLog(LOG1, "Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Beacon Period %u " + "Capability 0x%x " + "Ie length %d", + ap->ts, + ap->ssid, + MAC_ADDR_ARRAY(ap->bssid.bytes), + ap->channel, + ap->rssi, + ap->rtt, + ap->rtt_sd, + ap->beaconPeriod, + ap->capability, + ap->ieLength); + ap++; + } + result++; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->num_scan_ids) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + if (data->num_scan_ids) { + struct nlattr *nla_results; + result = &data->result[0]; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + nla_results = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST); + if (!nla_results) + goto fail; + + for (i = 0; i < data->num_scan_ids; i++) { + struct nlattr *nla_result; + struct nlattr *nla_aps; + + nla_result = nla_nest_start(skb, i); + if (!nla_result) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + result->flags) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + result->num_results)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + if (hdd_extscan_nl_fill_bss(skb, ap, j)) + goto fail; + + ap++; + } + nla_nest_end(skb, nla_aps); + nla_nest_end(skb, nla_result); + result++; + } + nla_nest_end(skb, nla_results); + } + + cfg80211_vendor_cmd_reply(skb); + + if (!data->more_data) { + spin_lock(&context->context_lock); + context->response_status = 0; + complete(&context->response_event); + spin_unlock(&context->context_lock); + } + return; + +fail: + if (skb) + kfree_skb(skb); + + spin_lock(&context->context_lock); + context->response_status = -EINVAL; + spin_unlock(&context->context_lock); + + return; +} + +/** + * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind + * @ctx: Pointer to hdd context + * @pData: Pointer to ext scan result event + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, + struct extscan_hotlist_match *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + uint32_t i, index; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !data) { + hddLog(LOGE, FL("HDD ctx invalid or data(%p) is null"), data); + return; + } + + if (data->ap_found) + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX; + else + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX; + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + hdd_info("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u", + data->requestId, data->numOfAps, data->moreData, + data->ap_found); + + for (i = 0; i < data->numOfAps; i++) { + data->ap[i].ts = cdf_get_monotonic_boottime(); + + hddLog(LOG1, "[i=%d] Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u", + i, + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(data->ap[i].bssid.bytes), + data->ap[i].channel, + data->ap[i].rssi, + data->ap[i].rtt, data->ap[i].rtt_sd); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->numOfAps)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + if (data->numOfAps) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + for (i = 0; i < data->numOfAps; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + data->ap[i].ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(data->ap[i].ssid), + data->ap[i].ssid) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(data->ap[i].bssid), + data->ap[i].bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + data->ap[i].channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + data->ap[i].rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + data->ap[i].rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + data->ap[i].rtt_sd)) + goto fail; + + nla_nest_end(skb, ap); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->moreData)) + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() - + * significant wifi change results indication + * @ctx: Pointer to hdd context + * @pData: Pointer to signif wifi change event + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind( + void *ctx, + tpSirWifiSignificantChangeEvent pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + tSirWifiSignificantChange *ap_info; + int32_t *rssi; + uint32_t i, j; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !pData) { + hddLog(LOGE, FL("HDD ctx invalid or pData(%p) is null"), pData); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + hddLog(LOG1, "Req Id %u Num results %u More Data %u", + pData->requestId, pData->numResults, pData->moreData); + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->numResults; i++) { + hddLog(LOG1, "[i=%d] " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "numOfRssi %d", + i, + MAC_ADDR_ARRAY(ap_info->bssid.bytes), + ap_info->channel, ap_info->numOfRssi); + rssi = &(ap_info)->rssi[0]; + for (j = 0; j < ap_info->numOfRssi; j++) + hddLog(LOG1, "Rssi %d", *rssi++); + + ap_info += ap_info->numOfRssi * sizeof(*rssi); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + pData->numResults)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + if (pData->numResults) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->numResults; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, + CDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, + ap_info->channel) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, + ap_info->numOfRssi) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, + sizeof(s32) * ap_info->numOfRssi, + &(ap_info)->rssi[0])) + goto fail; + + nla_nest_end(skb, ap); + + ap_info += ap_info->numOfRssi * sizeof(*rssi); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; + +} + +/** + * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event + * @ctx: Pointer to hdd context + * @pData: Pointer to full scan result event + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, + tpSirWifiFullScanResultEvent + pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; +#ifdef CONFIG_CNSS + struct timespec ts; +#endif + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !pData) { + hddLog(LOGE, FL("HDD ctx invalid or pData(%p) is null"), pData); + return; + } + + if ((sizeof(*pData) + pData->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { + hddLog(LOGE, + FL("Frame exceeded NL size limitation, drop it!!")); + return; + } + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + pData->ap.channel = cds_chan_to_freq(pData->ap.channel); +#ifdef CONFIG_CNSS + /* Android does not want the time stamp from the frame. + Instead it wants a monotonic increasing value since boot */ + cnss_get_monotonic_boottime(&ts); + pData->ap.ts = ((u64)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +#endif + hddLog(LOG1, "Req Id %u More Data %u", pData->requestId, + pData->moreData); + hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + pData->ap.ts, + pData->ap.ssid, + MAC_ADDR_ARRAY(pData->ap.bssid.bytes), + pData->ap.channel, + pData->ap.rssi, + pData->ap.rtt, + pData->ap.rtt_sd, + pData->ap.beaconPeriod, + pData->ap.capability, pData->ap.ieLength); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + pData->ap.ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(pData->ap.ssid), + pData->ap.ssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(pData->ap.bssid), + pData->ap.bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + pData->ap.channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + pData->ap.rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + pData->ap.rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + pData->ap.rtt_sd) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + pData->ap.beaconPeriod) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + pData->ap.capability) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + pData->ap.ieLength) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + if (pData->ap.ieLength) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + pData->ap.ieLength, pData->ap.ieData)) + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event + * @ctx: Pointer to hdd context + * @pData: Pointer to scan results available indication param + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_res_available_event( + void *ctx, + tpSirExtScanResultsAvailableIndParams pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !pData) { + hddLog(LOGE, FL("HDD ctx invalid or pData(%p) is null"), pData); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + hddLog(LOG1, "Req Id %u Num results %u", + pData->requestId, pData->numResultsAvailable); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + pData->numResultsAvailable)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event + * @ctx: Pointer to hdd context + * @pData: Pointer to scan event indication param + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx, + tpSirExtScanOnScanEventIndParams + pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !pData) { + hddLog(LOGE, FL("HDD ctx invalid or pData(%p) is null"), pData); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + hddLog(LOG1, "Req Id %u Scan event type %u Scan event status %u", + pData->requestId, pData->scanEventType, pData->status); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + pData->scanEventType) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS, + pData->status)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found + * @hddctx: HDD context + * @data: matched network data + * + * This function reads the matched network data and fills NL vendor attributes + * and send it to upper layer. + * + * Return: 0 on success, error number otherwise + */ +static void +wlan_hdd_cfg80211_extscan_epno_match_found(void *ctx, + struct pno_match_found *data) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + struct sk_buff *skb = NULL; + uint32_t len, i; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !data) { + hddLog(LOGE, FL("HDD context is invalid or data(%p) is null"), + data); + return; + } + + /* + * If the number of match found APs including IE data exceeds NL 4K size + * limitation, drop that beacon/probe rsp frame. + */ + len = sizeof(*data) + + (data->num_results + sizeof(tSirWifiScanResult)); + for (i = 0; i < data->num_results; i++) + len += data->ap[i].ieLength; + + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hddLog(LOGE, FL("Frame exceeded NL size limitation, drop it!")); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + hddLog(LOG1, "Req Id %u More Data %u num_results %d", + data->request_id, data->more_data, data->num_results); + for (i = 0; i < data->num_results; i++) { + data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel); + hddLog(LOG1, "AP Info: Timestamp %llu) Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(data->ap[i].bssid.bytes), + data->ap[i].channel, + data->ap[i].rssi, + data->ap[i].rtt, + data->ap[i].rtt_sd, + data->ap[i].beaconPeriod, + data->ap[i].capability, + data->ap[i].ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->num_results) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + + if (data->num_results) { + struct nlattr *nla_aps; + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < data->num_results; i++) { + if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i)) + goto fail; + } + nla_nest_end(skb, nla_aps); + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found + * @hddctx: HDD context + * @data: matched network data + * + * This function reads the match network %data and fill in the skb with + * NL attributes and send up the NL event + * + * Return: none + */ +static void +wlan_hdd_cfg80211_passpoint_match_found(void *ctx, + struct wifi_passpoint_match *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + uint32_t len, i, num_matches = 1, more_data = 0; + struct nlattr *nla_aps; + struct nlattr *nla_bss; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx) || !data) { + hddLog(LOGE, FL("HDD context is invalid or data(%p) is null"), + data); + return; + } + + len = sizeof(*data) + data->ap.ieLength + data->anqp_len; + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hddLog(LOGE, FL("Result exceeded NL size limitation, drop it")); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + hddLog(LOG1, "Req Id %u Id %u ANQP length %u num_matches %u", + data->request_id, data->id, data->anqp_len, num_matches); + for (i = 0; i < num_matches; i++) { + hddLog(LOG1, "AP Info: Timestamp %llu Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap.ts, + data->ap.ssid, + MAC_ADDR_ARRAY(data->ap.bssid.bytes), + data->ap.channel, + data->ap.rssi, + data->ap.rtt, + data->ap.rtt_sd, + data->ap.beaconPeriod, + data->ap.capability, + data->ap.ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, + num_matches) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + more_data)) { + hddLog(LOGE, FL("nla put fail")); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < num_matches; i++) { + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, i); + if (!nla_ap) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, + data->id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, + data->anqp_len)) { + goto fail; + } + + if (data->anqp_len) + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, + data->anqp_len, data->anqp)) + goto fail; + + nla_bss = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_bss) + goto fail; + + if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0)) + goto fail; + + nla_nest_end(skb, nla_bss); + nla_nest_end(skb, nla_ap); + } + nla_nest_end(skb, nla_aps); + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind() - + * Handle an SSID hotlist match event + * @ctx: HDD context registered with SME + * @event: The SSID hotlist match event + * + * This function will take an SSID match event that was generated by + * firmware and will convert it into a cfg80211 vendor event which is + * sent to userspace. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(void *ctx, + tpSirWifiScanResultEvent event) +{ + hdd_context_t *hdd_ctx = ctx; + struct sk_buff *skb; + uint32_t i, index; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !event) { + hddLog(LOGE, + FL("HDD context is not valid or event(%p) is null"), + event); + return; + } + + if (event->ap_found) { + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX; + hddLog(LOG1, "SSID hotlist found"); + } else { + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX; + hddLog(LOG1, "SSID hotlist lost"); + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + hddLog(LOG1, "Req Id %u, Num results %u, More Data %u", + event->requestId, event->numOfAps, event->moreData); + + for (i = 0; i < event->numOfAps; i++) { + hddLog(LOG1, "[i=%d] Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u", + i, + event->ap[i].ts, + event->ap[i].ssid, + MAC_ADDR_ARRAY(event->ap[i].bssid.bytes), + event->ap[i].channel, + event->ap[i].rssi, + event->ap[i].rtt, + event->ap[i].rtt_sd); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + event->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + event->numOfAps)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + + if (event->numOfAps) { + struct nlattr *aps; + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) { + hddLog(LOGE, FL("nest fail")); + goto fail; + } + + for (i = 0; i < event->numOfAps; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) { + hddLog(LOGE, FL("nest fail")); + goto fail; + } + + if (nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + event->ap[i].ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(event->ap[i].ssid), + event->ap[i].ssid) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(event->ap[i].bssid), + event->ap[i].bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + event->ap[i].channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + event->ap[i].rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + event->ap[i].rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + event->ap[i].rtt_sd)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + nla_nest_end(skb, ap); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + event->moreData)) { + hddLog(LOGE, FL("put fail")); + goto fail; + } + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_generic_rsp() - + * Handle a generic ExtScan Response message + * @ctx: HDD context registered with SME + * @response: The ExtScan response from firmware + * + * This function will handle a generic ExtScan response message from + * firmware and will communicate the result to the userspace thread + * that is waiting for the response. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_generic_rsp + (void *ctx, + struct sir_extscan_generic_response *response) +{ + hdd_context_t *hdd_ctx = ctx; + struct hdd_ext_scan_context *context; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !response) { + hddLog(LOGE, + FL("HDD context is not valid or response(%p) is null"), + response); + return; + } + + hddLog(LOG1, FL("request %u status %u"), + response->request_id, response->status); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (context->request_id == response->request_id) { + context->response_status = response->status ? -EINVAL : 0; + complete(&context->response_event); + } + spin_unlock(&context->context_lock); + + return; +} + +/** + * wlan_hdd_cfg80211_extscan_callback() - ext scan callback + * @ctx: Pointer to hdd context + * @evType: Event type + * @pMag: Pointer to message + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_callback(void *ctx, const uint16_t evType, + void *pMsg) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + + if (wlan_hdd_validate_context(pHddCtx)) { + hddLog(LOGE, FL("HDD ctx invalid received event: %d"), evType); + return; + } + + hddLog(LOG1, FL("Rcvd Event %d"), evType); + + switch (evType) { + case eSIR_EXTSCAN_CACHED_RESULTS_RSP: + /* There is no need to send this response to upper layer + Just log the message */ + hddLog(LOG1, + FL("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP")); + break; + + case eSIR_EXTSCAN_GET_CAPABILITIES_IND: + wlan_hdd_cfg80211_extscan_get_capabilities_rsp(ctx, + (struct ext_scan_capabilities_response *) pMsg); + break; + + case eSIR_EXTSCAN_HOTLIST_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND: + wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx, + (tpSirWifiSignificantChangeEvent) pMsg); + break; + + case eSIR_EXTSCAN_CACHED_RESULTS_IND: + wlan_hdd_cfg80211_extscan_cached_results_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND: + wlan_hdd_cfg80211_extscan_scan_res_available_event(ctx, + (tpSirExtScanResultsAvailableIndParams) pMsg); + break; + + case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND: + wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx, + (tpSirWifiFullScanResultEvent) pMsg); + break; + + case eSIR_EPNO_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_extscan_epno_match_found(ctx, + (struct pno_match_found *)pMsg); + break; + + case eSIR_EXTSCAN_HOTLIST_SSID_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_ssid_match_ind(ctx, + (tpSirWifiScanResultEvent)pMsg); + break; + + case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND: + wlan_hdd_cfg80211_extscan_scan_progress_event(ctx, + (tpSirExtScanOnScanEventIndParams) pMsg); + break; + + case eSIR_PASSPOINT_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_passpoint_match_found(ctx, + (struct wifi_passpoint_match *) pMsg); + break; + + case eSIR_EXTSCAN_START_RSP: + case eSIR_EXTSCAN_STOP_RSP: + case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP: + wlan_hdd_cfg80211_extscan_generic_rsp(ctx, pMsg); + break; + + default: + hddLog(LOGE, FL("Unknown event type %u"), evType); + break; + } +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_STATUS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS +#define MAX_SCAN_CACHE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE +#define MAX_SCAN_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS +#define MAX_AP_CACHE_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN +#define MAX_RSSI_SAMPLE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE +#define MAX_SCAN_RPT_THRHOLD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD +#define MAX_HOTLIST_BSSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS +#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS +#define MAX_BSSID_HISTORY_ENTRIES \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES +#define MAX_HOTLIST_SSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS +#define MAX_NUM_EPNO_NETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS +#define MAX_NUM_EPNO_NETS_BY_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID +#define MAX_NUM_WHITELISTED_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID + +/** + * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_send_ext_scan_capability(hdd_context_t *hdd_ctx) +{ + int ret; + struct sk_buff *skb; + struct ext_scan_capabilities_response *data; + uint32_t nl_buf_len; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("hdd_context is invalid")); + return ret; + } + + data = &(ext_scan_context.capability_response); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) + + (sizeof(data->status) + NLA_HDRLEN) + + (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_buckets) + NLA_HDRLEN) + + (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) + + (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) + + (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) + + (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_white_listed_ssid) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + + hddLog(LOG1, "Req Id %u", data->requestId); + hddLog(LOG1, "Status %u", data->status); + hddLog(LOG1, "Scan cache size %u", + data->max_scan_cache_size); + hddLog(LOG1, "Scan buckets %u", data->max_scan_buckets); + hddLog(LOG1, "Max AP per scan %u", + data->max_ap_cache_per_scan); + hddLog(LOG1, "max_rssi_sample_size %u", + data->max_rssi_sample_size); + hddLog(LOG1, "max_scan_reporting_threshold %u", + data->max_scan_reporting_threshold); + hddLog(LOG1, "max_hotlist_bssids %u", + data->max_hotlist_bssids); + hddLog(LOG1, "max_significant_wifi_change_aps %u", + data->max_significant_wifi_change_aps); + hddLog(LOG1, "max_bssid_history_entries %u", + data->max_bssid_history_entries); + hddLog(LOG1, "max_hotlist_ssids %u", data->max_hotlist_ssids); + hddLog(LOG1, "max_number_epno_networks %u", + data->max_number_epno_networks); + hddLog(LOG1, "max_number_epno_networks_by_ssid %u", + data->max_number_epno_networks_by_ssid); + hddLog(LOG1, "max_number_of_white_listed_ssid %u", + data->max_number_of_white_listed_ssid); + + if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) || + nla_put_u32(skb, PARAM_STATUS, data->status) || + nla_put_u32(skb, MAX_SCAN_CACHE_SIZE, data->max_scan_cache_size) || + nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) || + nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN, + data->max_ap_cache_per_scan) || + nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE, + data->max_rssi_sample_size) || + nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD, + data->max_scan_reporting_threshold) || + nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) || + nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS, + data->max_significant_wifi_change_aps) || + nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES, + data->max_bssid_history_entries) || + nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS, + data->max_number_epno_networks) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID, + data->max_number_epno_networks_by_ssid) || + nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID, + data->max_number_of_white_listed_ssid)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#undef PARAM_REQUEST_ID +#undef PARAM_STATUS +#undef MAX_SCAN_CACHE_SIZE +#undef MAX_SCAN_BUCKETS +#undef MAX_AP_CACHE_PER_SCAN +#undef MAX_RSSI_SAMPLE_SIZE +#undef MAX_SCAN_RPT_THRHOLD +#undef MAX_HOTLIST_BSSIDS +#undef MAX_SIGNIFICANT_WIFI_CHANGE_APS +#undef MAX_BSSID_HISTORY_ENTRIES +#undef MAX_HOTLIST_SSIDS +#undef MAX_NUM_EPNO_NETS +#undef MAX_NUM_EPNO_NETS_BY_SSID +#undef MAX_NUM_WHITELISTED_SSID + +/** + * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + unsigned long rc; + struct hdd_ext_scan_context *context; + tpSirGetExtScanCapabilitiesReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + CDF_STATUS status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_ext_scan_get_capabilities(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("sme_ext_scan_get_capabilities failed(err=%d)"), + status); + goto fail; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("Target response timed out")); + return -ETIMEDOUT; + } + + ret = wlan_hdd_send_ext_scan_capability(pHddCtx); + if (ret) + hddLog(LOGE, FL("Failed to send ext scan capability to user space")); + + return ret; +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_FLUSH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH +/** + * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanGetCachedResultsReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + CDF_STATUS status; + int retval = 0; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, pReqMsg->sessionId); + + /* Parse and fetch flush parameter */ + if (!tb[PARAM_FLUSH]) { + hddLog(LOGE, FL("attr flush failed")); + goto fail; + } + pReqMsg->flush = nla_get_u8(tb[PARAM_FLUSH]); + hddLog(LOG1, FL("Flush %d"), pReqMsg->flush); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + context->ignore_cached_results = false; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_get_cached_results(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_get_cached_results failed(err=%d)"), status); + goto fail; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("Target response timed out")); + retval = -ETIMEDOUT; + spin_lock(&context->context_lock); + context->ignore_cached_results = true; + spin_unlock(&context->context_lock); + } else { + spin_lock(&context->context_lock); + retval = context->response_status; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_FLUSH + +/** + * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanSetBssidHotListReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *apTh; + struct hdd_ext_scan_context *context; + uint32_t request_id; + CDF_STATUS status; + uint8_t i; + int rem, retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId); + + /* Parse and fetch number of APs */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]) { + hddLog(LOGE, FL("attr number of AP failed")); + goto fail; + } + pReqMsg->numAp = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Number of AP %d Session Id %d"), + pReqMsg->numAp, pReqMsg->sessionId); + + /* Parse and fetch lost ap sample size */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr lost ap sample size failed")); + goto fail; + } + + pReqMsg->lost_ap_sample_size = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]); + hddLog(LOG1, FL("Lost ap sample size %d"), + pReqMsg->lost_ap_sample_size); + + i = 0; + nla_for_each_nested(apTh, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], + rem) { + if (nla_parse + (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(apTh), nla_len(apTh), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); + goto fail; + } + + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) { + hddLog(LOGE, FL("attr mac address failed")); + goto fail; + } + nla_memcpy(pReqMsg->ap[i].bssid.bytes, + tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID], + CDF_MAC_ADDR_SIZE); + hddLog(LOG1, MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes)); + + /* Parse and fetch low RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) { + hddLog(LOGE, FL("attr low RSSI failed")); + goto fail; + } + pReqMsg->ap[i].low = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]); + hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low); + + /* Parse and fetch high RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) { + hddLog(LOGE, FL("attr high RSSI failed")); + goto fail; + } + pReqMsg->ap[i].high = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); + hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high); + + i++; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_set_bss_hotlist(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("sme_set_bss_hotlist failed(err=%d)"), status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_set_bss_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __wlan_hdd_cfg80211_extscan_set_significant_change () - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanSetSigChangeReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *apTh; + struct hdd_ext_scan_context *context; + uint32_t request_id; + CDF_STATUS status; + uint8_t i; + int rem, retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Req Id %d"), pReqMsg->requestId); + + /* Parse and fetch RSSI sample size */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr RSSI sample size failed")); + goto fail; + } + pReqMsg->rssiSampleSize = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]); + hddLog(LOG1, FL("RSSI sample size %u"), pReqMsg->rssiSampleSize); + + /* Parse and fetch lost AP sample size */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr lost AP sample size failed")); + goto fail; + } + pReqMsg->lostApSampleSize = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]); + hddLog(LOG1, FL("Lost AP sample size %u"), pReqMsg->lostApSampleSize); + + /* Parse and fetch AP min breacing */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]) { + hddLog(LOGE, FL("attr AP min breaching")); + goto fail; + } + pReqMsg->minBreaching = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]); + hddLog(LOG1, FL("AP min breaching %u"), pReqMsg->minBreaching); + + /* Parse and fetch number of APs */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]) { + hddLog(LOGE, FL("attr number of AP failed")); + goto fail; + } + pReqMsg->numAp = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Number of AP %d Session Id %d"), + pReqMsg->numAp, pReqMsg->sessionId); + + i = 0; + nla_for_each_nested(apTh, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], + rem) { + if (nla_parse + (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(apTh), nla_len(apTh), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); + goto fail; + } + + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) { + hddLog(LOGE, FL("attr mac address failed")); + goto fail; + } + nla_memcpy(pReqMsg->ap[i].bssid.bytes, + tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID], + CDF_MAC_ADDR_SIZE); + hddLog(LOG1, MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes)); + + /* Parse and fetch low RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) { + hddLog(LOGE, FL("attr low RSSI failed")); + goto fail; + } + pReqMsg->ap[i].low = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]); + hddLog(LOG1, FL("RSSI low %d"), pReqMsg->ap[i].low); + + /* Parse and fetch high RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) { + hddLog(LOGE, FL("attr high RSSI failed")); + goto fail; + } + pReqMsg->ap[i].high = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); + hddLog(LOG1, FL("RSSI High %d"), pReqMsg->ap[i].high); + + i++; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_set_significant_change(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_set_significant_change failed(err=%d)"), status); + cdf_mem_free(pReqMsg); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_set_significant_change timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_remove_dsrc_channels () - remove dsrc chanels + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +void hdd_remove_dsrc_channels(struct wiphy *wiphy, uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i; + + for (i = 0; i < *num_channels; i++) { + if (!cds_is_dsrc_channel(chan_list[i])) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + + *num_channels = num_chan_temp; +} + +/** + * hdd_remove_indoor_channels () - remove indoor channels + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i, j, k; + + for (i = 0; i < *num_channels; i++) + for (j = 0; j < IEEE80211_NUM_BANDS; j++) { + if (wiphy->bands[j] == NULL) + continue; + for (k = 0; k < wiphy->bands[j]->n_channels; k++) { + if ((chan_list[i] == + wiphy->bands[j]->channels[k].center_freq) + && (!(wiphy->bands[j]->channels[k].flags & + IEEE80211_CHAN_INDOOR_ONLY)) + ) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + } + + *num_channels = num_chan_temp; +} +#else +void hdd_remove_indoor_channels(struct wiphy *wiphy, uint32_t *chan_list, + uint8_t *num_channels) +{ + *num_channels = 0; +} +#endif + +/** + * __wlan_hdd_cfg80211_extscan_get_valid_channels () - get valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t num_channels = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + uint32_t requestId, maxChannels; + tWifiBand wifiBand; + CDF_STATUS status; + struct sk_buff *reply_skb; + uint8_t i; + int ret; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + return -EINVAL; + } + requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Req Id %d"), requestId); + + /* Parse and fetch wifi band */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]) { + hddLog(LOGE, FL("attr wifi band failed")); + return -EINVAL; + } + wifiBand = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]); + hddLog(LOG1, FL("Wifi band %d"), wifiBand); + + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) { + hddLog(LOGE, FL("attr max channels failed")); + return -EINVAL; + } + maxChannels = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]); + hddLog(LOG1, FL("Max channels %d"), maxChannels); + status = sme_get_valid_channels_by_band((tHalHandle) (pHddCtx->hHal), + wifiBand, chan_list, + &num_channels); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, + FL("sme_get_valid_channels_by_band failed (err=%d)"), + status); + return -EINVAL; + } + + num_channels = CDF_MIN(num_channels, maxChannels); + + hdd_remove_dsrc_channels(wiphy, chan_list, &num_channels); + + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + !strncmp(hdd_get_fwpath(), "ap", 2)) + hdd_remove_indoor_channels(wiphy, chan_list, &num_channels); + + hddLog(LOG1, FL("Number of channels %d"), num_channels); + for (i = 0; i < num_channels; i++) + hddLog(LOG1, "Channel: %u ", chan_list[i]); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + num_channels + + NLMSG_HDRLEN); + + if (reply_skb) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, + num_channels) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, + sizeof(u32) * num_channels, chan_list)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); + } + + hddLog(LOGE, FL("valid channels: buffer alloc fail")); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_get_valid_channels() - get ext scan valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_extscan_update_dwell_time_limits() - update dwell times + * @req_msg: Pointer to request message + * @bkt_idx: Index of current bucket being processed + * @active_min: minimum active dwell time + * @active_max: maximum active dwell time + * @passive_min: minimum passive dwell time + * @passive_max: maximum passive dwell time + * + * Return: none + */ +static void hdd_extscan_update_dwell_time_limits( + tpSirWifiScanCmdReqParams req_msg, uint32_t bkt_idx, + uint32_t active_min, uint32_t active_max, + uint32_t passive_min, uint32_t passive_max) +{ + /* update per-bucket dwell times */ + if (req_msg->buckets[bkt_idx].min_dwell_time_active > + active_min) { + req_msg->buckets[bkt_idx].min_dwell_time_active = + active_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_active < + active_max) { + req_msg->buckets[bkt_idx].max_dwell_time_active = + active_max; + } + if (req_msg->buckets[bkt_idx].min_dwell_time_passive > + passive_min) { + req_msg->buckets[bkt_idx].min_dwell_time_passive = + passive_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_passive < + passive_max) { + req_msg->buckets[bkt_idx].max_dwell_time_passive = + passive_max; + } + /* update dwell-time across all buckets */ + if (req_msg->min_dwell_time_active > + req_msg->buckets[bkt_idx].min_dwell_time_active) { + req_msg->min_dwell_time_active = + req_msg->buckets[bkt_idx].min_dwell_time_active; + } + if (req_msg->max_dwell_time_active < + req_msg->buckets[bkt_idx].max_dwell_time_active) { + req_msg->max_dwell_time_active = + req_msg->buckets[bkt_idx].max_dwell_time_active; + } + if (req_msg->min_dwell_time_passive > + req_msg->buckets[bkt_idx].min_dwell_time_passive) { + req_msg->min_dwell_time_passive = + req_msg->buckets[bkt_idx].min_dwell_time_passive; + } + if (req_msg->max_dwell_time_passive > + req_msg->buckets[bkt_idx].max_dwell_time_passive) { + req_msg->max_dwell_time_passive = + req_msg->buckets[bkt_idx].max_dwell_time_passive; + } +} + +/** + * hdd_extscan_channel_max_reached() - channel max reached + * @req: extscan request structure + * @total_channels: total number of channels + * + * Return: true if total channels reached max, false otherwise + */ +static bool hdd_extscan_channel_max_reached(tSirWifiScanCmdReqParams *req, + uint8_t total_channels) +{ + if (total_channels == WLAN_EXTSCAN_MAX_CHANNELS) { + hdd_warn( + "max #of channels %d reached, take only first %d bucket(s)", + total_channels, req->numBuckets); + return true; + } + return false; +} + +/** + * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec + * @hdd_ctx: HDD global context + * @req_msg: Pointer to request structure + * @tb: pointer to NL attributes + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_start_fill_bucket_channel_spec( + hdd_context_t *hdd_ctx, + tpSirWifiScanCmdReqParams req_msg, + struct nlattr **tb) +{ + struct nlattr *bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *buckets; + struct nlattr *channels; + int rem1, rem2; + CDF_STATUS status; + uint8_t bkt_index, j, num_channels, total_channels = 0; + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + + uint32_t min_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t max_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t min_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + uint32_t max_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + + bkt_index = 0; + req_msg->min_dwell_time_active = + req_msg->max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->min_dwell_time_passive = + req_msg->max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + req_msg->numBuckets = 0; + + nla_for_each_nested(buckets, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) { + if (nla_parse(bucket, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(buckets), nla_len(buckets), NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } + + /* Parse and fetch bucket spec */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) { + hddLog(LOGE, FL("attr bucket index failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].bucket = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]); + hddLog(LOG1, FL("Bucket spec Index %d"), + req_msg->buckets[bkt_index].bucket); + + /* Parse and fetch wifi band */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) { + hddLog(LOGE, FL("attr wifi band failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].band = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]); + hddLog(LOG1, FL("Wifi band %d"), + req_msg->buckets[bkt_index].band); + + /* Parse and fetch period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) { + hddLog(LOGE, FL("attr period failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]); + hddLog(LOG1, FL("period %d"), + req_msg->buckets[bkt_index].period); + + /* Parse and fetch report events */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) { + hddLog(LOGE, FL("attr report events failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].reportEvents = nla_get_u8( + bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]); + hddLog(LOG1, FL("report events %d"), + req_msg->buckets[bkt_index].reportEvents); + + /* Parse and fetch max period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) { + hddLog(LOGE, FL("attr max period failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].max_period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]); + hddLog(LOG1, FL("max period %u"), + req_msg->buckets[bkt_index].max_period); + + /* Parse and fetch exponent */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]) { + hddLog(LOGE, FL("attr exponent failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].exponent = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_EXPONENT]); + hddLog(LOG1, FL("exponent %u"), + req_msg->buckets[bkt_index].exponent); + + /* Parse and fetch step count */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) { + hddLog(LOGE, FL("attr step count failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].step_count = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]); + hddLog(LOG1, FL("Step count %u"), + req_msg->buckets[bkt_index].step_count); + + /* start with known good values for bucket dwell times */ + req_msg->buckets[bkt_index].min_dwell_time_active = + req_msg->buckets[bkt_index].max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->buckets[bkt_index].min_dwell_time_passive = + req_msg->buckets[bkt_index].max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + + /* Framework shall pass the channel list if the input WiFi band + * is WIFI_BAND_UNSPECIFIED. + * If the input WiFi band is specified (any value other than + * WIFI_BAND_UNSPECIFIED) then driver populates the channel list + */ + if (req_msg->buckets[bkt_index].band != WIFI_BAND_UNSPECIFIED) { + if (hdd_extscan_channel_max_reached(req_msg, + total_channels)) + return 0; + + num_channels = 0; + hddLog(LOG1, "WiFi band is specified, driver to fill channel list"); + status = sme_get_valid_channels_by_band(hdd_ctx->hHal, + req_msg->buckets[bkt_index].band, + chan_list, &num_channels); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_GetValidChannelsByBand failed (err=%d)"), + status); + return -EINVAL; + } + hddLog(LOG1, FL("before trimming, num_channels: %d"), + num_channels); + + req_msg->buckets[bkt_index].numChannels = + CDF_MIN(num_channels, + (WLAN_EXTSCAN_MAX_CHANNELS - + total_channels)); + hdd_info("Adj Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + total_channels += + req_msg->buckets[bkt_index].numChannels; + + for (j = 0; j < req_msg->buckets[bkt_index].numChannels; + j++) { + req_msg->buckets[bkt_index].channels[j].channel = + chan_list[j]; + req_msg->buckets[bkt_index].channels[j]. + chnlClass = 0; + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan(chan_list[j]))) { + req_msg->buckets[bkt_index].channels[j]. + passive = 1; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config-> + extscan_passive_max_chn_time; + /* reconfigure per-bucket dwell time */ + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } else { + req_msg->buckets[bkt_index].channels[j]. + passive = 0; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + /* reconfigure per-bucket dwell times */ + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } + + hddLog(LOG1, + "Channel: %u Passive: %u Dwell time: %u ms Class: %u", + req_msg->buckets[bkt_index].channels[j].channel, + req_msg->buckets[bkt_index].channels[j].passive, + req_msg->buckets[bkt_index].channels[j].dwellTimeMs, + req_msg->buckets[bkt_index].channels[j].chnlClass); + } + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hddLog(LOG1, FL("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"), + bkt_index, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + continue; + } + + /* Parse and fetch number of channels */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) { + hddLog(LOGE, FL("attr num channels failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].numChannels = + nla_get_u32(bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]); + hdd_info("before trimming: num channels %d", + req_msg->buckets[bkt_index].numChannels); + + req_msg->buckets[bkt_index].numChannels = + CDF_MIN(req_msg->buckets[bkt_index].numChannels, + (WLAN_EXTSCAN_MAX_CHANNELS - total_channels)); + hdd_info("Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + if (hdd_extscan_channel_max_reached(req_msg, total_channels)) + return 0; + + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) { + hddLog(LOGE, FL("attr channel spec failed")); + return -EINVAL; + } + + j = 0; + nla_for_each_nested(channels, + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) { + if (nla_parse(channel, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(channels), nla_len(channels), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } + + if (hdd_extscan_channel_max_reached(req_msg, + total_channels)) + break; + + /* Parse and fetch channel */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { + hddLog(LOGE, FL("attr channel failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].channel = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); + hddLog(LOG1, FL("channel %u"), + req_msg->buckets[bkt_index].channels[j].channel); + + /* Parse and fetch dwell time */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { + hddLog(LOGE, FL("attr dwelltime failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); + + /* Override dwell time if required */ + if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs < + hdd_ctx->config->extscan_active_min_chn_time || + req_msg->buckets[bkt_index].channels[j].dwellTimeMs > + hdd_ctx->config->extscan_active_max_chn_time) { + hddLog(LOG1, FL("WiFi band is unspecified, dwellTime:%d"), + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_passive_max_chn_time; + } else { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + } + } + + hddLog(LOG1, FL("New Dwell time %u ms"), + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } else { + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } + + /* Parse and fetch channel spec passive */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { + hddLog(LOGE, + FL("attr channel spec passive failed")); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].passive = + nla_get_u8(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); + hddLog(LOG1, FL("Chnl spec passive %u"), + req_msg->buckets[bkt_index].channels[j].passive); + /* Override scan type if required */ + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + req_msg->buckets[bkt_index].channels[j].passive = true; + } else { + req_msg->buckets[bkt_index].channels[j].passive = false; + } + j++; + total_channels++; + } + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hddLog(LOG1, FL("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d"), + bkt_index, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + } + + hddLog(LOG1, FL("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d"), + req_msg->min_dwell_time_active, + req_msg->max_dwell_time_active, + req_msg->min_dwell_time_passive, + req_msg->max_dwell_time_passive); + + return 0; +} + +/* + * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags + * @config_flags - [input] configuration flags. + * + * This function maps user space received configuration flags to + * driver representation. + * + * Return: configuration flags + */ +static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags) +{ + uint32_t configuration_flags = 0; + + if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING) + configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING; + + return configuration_flags; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_BASE_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD +#define PARAM_MAX_AP_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN +#define PARAM_RPT_THRHLD_PERCENT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT +#define PARAM_RPT_THRHLD_NUM_SCANS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS +#define PARAM_NUM_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS +#define PARAM_CONFIG_FLAGS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS + +/** + * __wlan_hdd_cfg80211_extscan_start() - ext scan start + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success; error number otherwise + */ +static int +__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tpSirWifiScanCmdReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id, num_buckets; + CDF_STATUS status; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("memory allocation failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, + pReqMsg->sessionId); + + /* Parse and fetch base period */ + if (!tb[PARAM_BASE_PERIOD]) { + hddLog(LOGE, FL("attr base period failed")); + goto fail; + } + pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]); + hddLog(LOG1, FL("Base Period %d"), + pReqMsg->basePeriod); + + /* Parse and fetch max AP per scan */ + if (!tb[PARAM_MAX_AP_PER_SCAN]) { + hddLog(LOGE, FL("attr max_ap_per_scan failed")); + goto fail; + } + pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]); + hddLog(LOG1, FL("Max AP per Scan %d"), pReqMsg->maxAPperScan); + + /* Parse and fetch report threshold percent */ + if (!tb[PARAM_RPT_THRHLD_PERCENT]) { + hddLog(LOGE, FL("attr report_threshold percent failed")); + goto fail; + } + pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]); + hddLog(LOG1, FL("Report Threshold percent %d"), + pReqMsg->report_threshold_percent); + + /* Parse and fetch report threshold num scans */ + if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) { + hddLog(LOGE, FL("attr report_threshold num scans failed")); + goto fail; + } + pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]); + hddLog(LOG1, FL("Report Threshold num scans %d"), + pReqMsg->report_threshold_num_scans); + + /* Parse and fetch number of buckets */ + if (!tb[PARAM_NUM_BUCKETS]) { + hddLog(LOGE, FL("attr number of buckets failed")); + goto fail; + } + num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]); + if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) { + hdd_warn("Exceeded MAX number of buckets: %d", + WLAN_EXTSCAN_MAX_BUCKETS); + } + hdd_info("Input: Number of Buckets %d", num_buckets); + + /* This is optional attribute, if not present set it to 0 */ + if (!tb[PARAM_CONFIG_FLAGS]) + pReqMsg->configuration_flags = 0; + else + pReqMsg->configuration_flags = + hdd_extscan_map_usr_drv_config_flags( + nla_get_u32(tb[PARAM_CONFIG_FLAGS])); + + hddLog(LOG1, FL("Configuration flags: %u"), + pReqMsg->configuration_flags); + + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) { + hddLog(LOGE, FL("attr bucket spec failed")); + goto fail; + } + + if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb)) + goto fail; + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_start(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_ext_scan_start failed(err=%d)"), status); + goto fail; + } + + pHddCtx->ext_scan_start_since_boot = cdf_get_monotonic_boottime(); + hddLog(LOG1, FL("Timestamp since boot: %llu"), + pHddCtx->ext_scan_start_since_boot); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_ext_scan_start timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_BASE_PERIOD +#undef PARAMS_MAX_AP_PER_SCAN +#undef PARAMS_RPT_THRHLD_PERCENT +#undef PARAMS_RPT_THRHLD_NUM_SCANS +#undef PARAMS_NUM_BUCKETS +#undef PARAM_CONFIG_FLAGS + +/** + * wlan_hdd_cfg80211_extscan_start() - start extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_stop() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID + +/** + * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + tpSirExtScanStopReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + CDF_STATUS status; + uint32_t request_id; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_stop(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_ext_scan_stop failed(err=%d)"), status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_ext_scan_stop timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_stop() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID + + +/** + * wlan_hdd_cfg80211_extscan_stop() - stop extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanResetBssidHotlistReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + CDF_STATUS status; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_reset_bss_hotlist(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_reset_bss_hotlist failed(err=%d)"), status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_reset_bss_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_extscan_reset_significant_change() - + * reset significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy + *wiphy, + struct + wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanResetSignificantChangeReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + CDF_STATUS status; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hddLog(LOG1, FL("Req Id %d Session Id %d"), + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_reset_significant_change(pHddCtx->hHal, pReqMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("sme_reset_significant_change failed(err=%d)"), + status); + cdf_mem_free(pReqMsg); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hddLog(LOGE, FL("sme_ResetSignificantChange timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant + * change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * hdd_extscan_epno_fill_network_list() - epno fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_epno_fill_network_list( + hdd_context_t *hddctx, + struct wifi_epno_params *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *networks; + int rem1, ssid_len; + uint8_t index, *ssid; + + index = 0; + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST], + rem1) { + if (nla_parse(network, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(networks), nla_len(networks), NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } + + /* Parse and fetch ssid */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) { + hddLog(LOGE, FL("attr network ssid failed")); + return -EINVAL; + } + ssid_len = nla_len( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + + /* Decrement by 1, don't count null character */ + ssid_len--; + + req_msg->networks[index].ssid.length = ssid_len; + hddLog(LOG1, FL("network ssid length %d"), ssid_len); + ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + cdf_mem_copy(req_msg->networks[index].ssid.ssId, + ssid, ssid_len); + hddLog(LOG1, FL("Ssid (%.*s)"), + req_msg->networks[index].ssid.length, + req_msg->networks[index].ssid.ssId); + + /* Parse and fetch rssi threshold */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]) { + hddLog(LOGE, FL("attr rssi threshold failed")); + return -EINVAL; + } + req_msg->networks[index].rssi_threshold = nla_get_s8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD]); + hddLog(LOG1, FL("rssi threshold %d"), + req_msg->networks[index].rssi_threshold); + + /* Parse and fetch epno flags */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) { + hddLog(LOGE, FL("attr epno flags failed")); + return -EINVAL; + } + req_msg->networks[index].flags = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]); + hddLog(LOG1, FL("flags %u"), req_msg->networks[index].flags); + + /* Parse and fetch auth bit */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) { + hddLog(LOGE, FL("attr auth bit failed")); + return -EINVAL; + } + req_msg->networks[index].auth_bit_field = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]); + hddLog(LOG1, FL("auth bit %u"), + req_msg->networks[index].auth_bit_field); + + index++; + } + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_epno_params *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[ + QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + CDF_STATUS status; + uint32_t num_networks, len; + int ret_val; + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) { + hddLog(LOGE, FL("attr num networks failed")); + return -EINVAL; + } + num_networks = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]); + hddLog(LOG1, FL("num networks %u"), num_networks); + + len = sizeof(*req_msg) + + (num_networks * sizeof(struct wifi_epno_network)); + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + cdf_mem_zero(req_msg, len); + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Req Id %u"), req_msg->request_id); + + req_msg->session_id = adapter->sessionId; + hddLog(LOG1, FL("Session Id %d"), req_msg->session_id); + + if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb)) + goto fail; + + status = sme_set_epno_list(hdd_ctx->hHal, req_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("sme_set_epno_list failed(err=%d)"), status); + goto fail; + } + + EXIT(); + cdf_mem_free(req_msg); + return 0; + +fail: + cdf_mem_free(req_msg); + return -EINVAL; +} + + /** + * wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_passpoint_fill_network_list( + hdd_context_t *hddctx, + struct wifi_passpoint_req *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + int rem1, len; + uint8_t index; + + index = 0; + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY], + rem1) { + if (nla_parse(network, + QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(networks), nla_len(networks), NULL)) { + hddLog(LOGE, FL("nla_parse failed")); + return -EINVAL; + } + + /* Parse and fetch identifier */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) { + hddLog(LOGE, FL("attr passpoint id failed")); + return -EINVAL; + } + req_msg->networks[index].id = nla_get_u32( + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]); + hddLog(LOG1, FL("Id %u"), req_msg->networks[index].id); + + /* Parse and fetch realm */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) { + hddLog(LOGE, FL("attr realm failed")); + return -EINVAL; + } + len = nla_len( + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]); + if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) { + hddLog(LOGE, FL("Invalid realm size %d"), len); + return -EINVAL; + } + cdf_mem_copy(req_msg->networks[index].realm, + nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]), + len); + hddLog(LOG1, FL("realm len %d"), len); + hddLog(LOG1, FL("realm: %s"), req_msg->networks[index].realm); + + /* Parse and fetch roaming consortium ids */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) { + hddLog(LOGE, FL("attr roaming consortium ids failed")); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].roaming_consortium_ids, + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID], + sizeof(req_msg->networks[0].roaming_consortium_ids)); + hddLog(LOG1, FL("roaming consortium ids")); + + /* Parse and fetch plmn */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) { + hddLog(LOGE, FL("attr plmn failed")); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].plmn, + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN], + SIR_PASSPOINT_PLMN_LEN); + hddLog(LOG1, FL("plmn %02x:%02x:%02x)"), + req_msg->networks[index].plmn[0], + req_msg->networks[index].plmn[1], + req_msg->networks[index].plmn[2]); + + index++; + } + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + CDF_STATUS status; + uint32_t num_networks = 0; + int ret; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) { + hddLog(LOGE, FL("attr num networks failed")); + return -EINVAL; + } + num_networks = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]); + hddLog(LOG1, FL("num networks %u"), num_networks); + + req_msg = cdf_mem_malloc(sizeof(*req_msg) + + (num_networks * sizeof(req_msg->networks[0]))); + if (!req_msg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->sessionId; + hddLog(LOG1, FL("Req Id %u Session Id %d"), req_msg->request_id, + req_msg->session_id); + + if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb)) + goto fail; + + status = sme_set_passpoint_list(hdd_ctx->hHal, req_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_set_passpoint_list failed(err=%d)"), status); + goto fail; + } + + EXIT(); + cdf_mem_free(req_msg); + return 0; + +fail: + cdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + CDF_STATUS status; + int ret; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + req_msg = cdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->sessionId; + hddLog(LOG1, FL("Req Id %u Session Id %d"), + req_msg->request_id, req_msg->session_id); + + status = sme_reset_passpoint_list(hdd_ctx->hHal, req_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_reset_passpoint_list failed(err=%d)"), status); + goto fail; + } + + EXIT(); + cdf_mem_free(req_msg); + return 0; + +fail: + cdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAMS_LOST_SSID_SAMPLE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE +#define PARAMS_NUM_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID +#define THRESHOLD_PARAM \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM +#define PARAM_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID +#define PARAM_BAND \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND +#define PARAM_RSSI_LOW \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW +#define PARAM_RSSI_HIGH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH + +/** + * __wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct sir_set_ssid_hotlist_request *request; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct nlattr *tb2[PARAM_MAX + 1]; + struct nlattr *ssids; + struct hdd_ext_scan_context *context; + uint32_t request_id; + char ssid_string[SIR_MAC_MAX_SSID_LENGTH + 1]; + int ssid_len, i, rem; + CDF_STATUS status; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + request = cdf_mem_malloc(sizeof(*request)); + if (!request) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Request Id %d"), request->request_id); + + /* Parse and fetch lost SSID sample size */ + if (!tb[PARAMS_LOST_SSID_SAMPLE_SIZE]) { + hddLog(LOGE, FL("attr number of Ssid failed")); + goto fail; + } + request->lost_ssid_sample_size = + nla_get_u32(tb[PARAMS_LOST_SSID_SAMPLE_SIZE]); + hddLog(LOG1, FL("Lost SSID Sample Size %d"), + request->lost_ssid_sample_size); + + /* Parse and fetch number of hotlist SSID */ + if (!tb[PARAMS_NUM_SSID]) { + hddLog(LOGE, FL("attr number of Ssid failed")); + goto fail; + } + request->ssid_count = nla_get_u32(tb[PARAMS_NUM_SSID]); + hddLog(LOG1, FL("Number of SSID %d"), request->ssid_count); + + request->session_id = adapter->sessionId; + hddLog(LOG1, FL("Session Id %d"), request->session_id); + + i = 0; + nla_for_each_nested(ssids, tb[THRESHOLD_PARAM], rem) { + if (i >= WLAN_EXTSCAN_MAX_HOTLIST_SSIDS) { + hddLog(LOGE, + FL("Too Many SSIDs, %d exceeds %d"), + i, WLAN_EXTSCAN_MAX_HOTLIST_SSIDS); + break; + } + if (nla_parse(tb2, PARAM_MAX, + nla_data(ssids), nla_len(ssids), + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("nla_parse failed")); + goto fail; + } + + /* Parse and fetch SSID */ + if (!tb2[PARAM_SSID]) { + hddLog(LOGE, FL("attr ssid failed")); + goto fail; + } + nla_memcpy(ssid_string, + tb2[PARAM_SSID], + sizeof(ssid_string)); + hddLog(LOG1, FL("SSID %s"), + ssid_string); + ssid_len = strlen(ssid_string); + memcpy(request->ssids[i].ssid.ssId, ssid_string, ssid_len); + request->ssids[i].ssid.length = ssid_len; + + /* Parse and fetch low RSSI */ + if (!tb2[PARAM_BAND]) { + hddLog(LOGE, FL("attr band failed")); + goto fail; + } + request->ssids[i].band = nla_get_u8(tb2[PARAM_BAND]); + hddLog(LOG1, FL("band %d"), request->ssids[i].band); + + /* Parse and fetch low RSSI */ + if (!tb2[PARAM_RSSI_LOW]) { + hddLog(LOGE, FL("attr low RSSI failed")); + goto fail; + } + request->ssids[i].rssi_low = nla_get_s32(tb2[PARAM_RSSI_LOW]); + hddLog(LOG1, FL("RSSI low %d"), request->ssids[i].rssi_low); + + /* Parse and fetch high RSSI */ + if (!tb2[PARAM_RSSI_HIGH]) { + hddLog(LOGE, FL("attr high RSSI failed")); + goto fail; + } + request->ssids[i].rssi_high = nla_get_u32(tb2[PARAM_RSSI_HIGH]); + hddLog(LOG1, FL("RSSI high %d"), request->ssids[i].rssi_high); + i++; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = request->request_id; + spin_unlock(&context->context_lock); + + status = sme_set_ssid_hotlist(hdd_ctx->hHal, request); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_set_ssid_hotlist failed(err=%d)"), status); + goto fail; + } + + cdf_mem_free(request); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies + (WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_set_ssid_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(request); + return -EINVAL; +} + +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_set_ssid_hotlist() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAMS_NUM_SSID +#undef THRESHOLD_PARAM +#undef PARAM_SSID +#undef PARAM_BAND +#undef PARAM_RSSI_LOW +#undef PARAM_RSSI_HIGH + +/** + * wlan_hdd_cfg80211_extscan_set_ssid_hotlist() - set ssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int +wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_ssid_hotlist(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID + +/** + * __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct sir_set_ssid_hotlist_request *request; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + CDF_STATUS status; + int retval; + unsigned long rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb, PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + request = cdf_mem_malloc(sizeof(*request)); + if (!request) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hddLog(LOGE, FL("attr request id failed")); + goto fail; + } + + request->request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + hddLog(LOG1, FL("Request Id %d"), request->request_id); + + request->session_id = adapter->sessionId; + hddLog(LOG1, FL("Session Id %d"), request->session_id); + + request->lost_ssid_sample_size = 0; + request->ssid_count = 0; + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = request->request_id; + spin_unlock(&context->context_lock); + + status = sme_set_ssid_hotlist(hdd_ctx->hHal, request); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("sme_reset_ssid_hotlist failed(err=%d)"), status); + goto fail; + } + + cdf_mem_free(request); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies + (WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hddLog(LOGE, FL("sme_reset_ssid_hotlist timed out")); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + + return retval; + +fail: + cdf_mem_free(request); + return -EINVAL; +} + +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID + +/** + * wlan_hdd_cfg80211_extscan_reset_ssid_hotlist() - reset ssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int +wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_init_completion_extwow() - Initialize ext wow variable + * @hdd_ctx: Global HDD context + * + * Return: none + */ +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx) +{ + init_completion(&pHddCtx->ready_to_extwow); +} +#else +static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx) +{ + return; +} +#endif + +/** + * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature + * @hdd_ctx: Global HDD context + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx) +{ + wlan_hdd_init_completion_extwow(hdd_ctx); + init_completion(&ext_scan_context.response_event); + spin_lock_init(&ext_scan_context.context_lock); +} + +#endif /* FEATURE_WLAN_EXTSCAN */ diff --git a/core/hdd/src/wlan_hdd_ext_scan.h b/core/hdd/src/wlan_hdd_ext_scan.h new file mode 100644 index 0000000000..0772a67a94 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ext_scan.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +#if !defined(WLAN_HDD_EXT_SCAN_H) +#define WLAN_HDD_EXT_SCAN_H + +/** + * DOC: wlan_hdd_ext_scan.h + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_main.h" + +/* + * Used to allocate the size of 4096 for the EXTScan NL data. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements. + */ + +#define EXTSCAN_EVENT_BUF_SIZE 4096 + +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy + *wiphy, + struct + wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int +wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int +wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx); + +#else /* FEATURE_WLAN_EXTSCAN */ + +static void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx) +{ +} + +#endif /* End of FEATURE_WLAN_EXTSCAN */ + +#endif /* end #if !defined(WLAN_HDD_EXT_SCAN_H) */ + diff --git a/core/hdd/src/wlan_hdd_ftm.c b/core/hdd/src/wlan_hdd_ftm.c new file mode 100644 index 0000000000..c002991115 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ftm.c @@ -0,0 +1,1061 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ftm.c + * + * This file contains the WLAN factory test mode implementation + */ + +#include +#include "cds_sched.h" +#include +#include "sir_types.h" +#include "cdf_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "wlan_hdd_misc.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wlan_hdd_main.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "cfg_api.h" + +#if defined(QCA_WIFI_FTM) +#include "bmi.h" +#include "ol_fw.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_main.h" +#include "hif.h" +#endif + +#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */ + +#if defined(QCA_WIFI_FTM) +#if defined(LINUX_QCMBR) +#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000 +#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001 +#define MAX_UTF_LENGTH 1024 +typedef struct qcmbr_data_s { + unsigned int cmd; + unsigned int length; + unsigned char buf[MAX_UTF_LENGTH + 4]; + unsigned int copy_to_user; +} qcmbr_data_t; +typedef struct qcmbr_queue_s { + unsigned char utf_buf[MAX_UTF_LENGTH + 4]; + struct list_head list; +} qcmbr_queue_t; +LIST_HEAD(qcmbr_queue_head); +DEFINE_SPINLOCK(qcmbr_queue_lock); +#endif +#endif + +/** + * wlan_ftm_postmsg() - Post FTM message + * @cmd_ptr: Pointer to FTM command buffer + * @cmd_len: Length of command in @cmd_ptr + * + * This function is used to send FTM commands to firmware + * + * Return: 0 for success, non zero for failure + */ +static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len) +{ + cds_msg_t ftmMsg; + + ENTER(); + + ftmMsg.type = WMA_FTM_CMD_REQ; + ftmMsg.reserved = 0; + ftmMsg.bodyptr = (uint8_t *) cmd_ptr; + ftmMsg.bodyval = 0; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, + &ftmMsg)) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: : Failed to post Msg to HAL", + __func__); + + return CDF_STATUS_E_FAILURE; + } + + EXIT(); + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_ftm_update_tgt_cfg() - Update target configuration + * @context: context registered with WMA + * @param: target configuration + * + * This function is registered with WMA via wma_open(), and is + * invoked via callback when target parameters are received + * from firmware. + * + * Return: None + */ +static void wlan_hdd_ftm_update_tgt_cfg(void *context, void *param) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) context; + struct wma_tgt_cfg *cfg = (struct wma_tgt_cfg *)param; + + if (!cdf_is_macaddr_zero(&cfg->hw_macaddr)) { + hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC passed from target, using MAC from ini file" + MAC_ADDRESS_STR, __func__, + MAC_ADDR_ARRAY(hdd_ctx->config->intfMacAddr[0].bytes)); + } +} + +/** + * wlan_ftm_cds_open() - Open the CDS Module in FTM mode + * @p_cds_context: pointer to the global CDS context + * @hddContextSize: Size of the HDD context to allocate. + * + * The wlan_ftm_cds_open() function opens the CDF Scheduler + * Upon successful initialization: + * - All CDS submodules should have been initialized + * - The CDS scheduler should have opened + * - All the WLAN SW components should have been opened. This includes MAC. + * + * Returns: + * CDF_STATUS_SUCCESS - Scheduler was successfully initialized and + * is ready to be used. + * CDF_STATUS_E_RESOURCES - System resources (other than memory) + * are unavailable to initialize the scheduler + * CDF_STATUS_E_FAILURE - Failure to initialize the scheduler + */ +static CDF_STATUS wlan_ftm_cds_open(v_CONTEXT_t p_cds_context, + uint32_t hddContextSize) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + int iter = 0; + tSirRetStatus sirStatus = eSIR_SUCCESS; + tMacOpenParameters mac_openParms; + p_cds_contextType gp_cds_context = (p_cds_contextType) p_cds_context; +#if defined(QCA_WIFI_FTM) + cdf_device_t cdf_ctx; + HTC_INIT_INFO htcInfo; + void *pHifContext = NULL; + void *pHtcContext = NULL; +#endif + hdd_context_t *hdd_ctx; + + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening CDS", __func__); + + if (NULL == gp_cds_context) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Trying to open CDS without a PreOpen", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* Initialize the probe event */ + if (cdf_event_init(&gp_cds_context->ProbeEvent) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Unable to init probeEvent", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + if (cdf_event_init(&(gp_cds_context->wmaCompleteEvent)) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Unable to init wmaCompleteEvent", __func__); + CDF_ASSERT(0); + + goto err_probe_event; + } + + /* Initialize the free message queue */ + vStatus = cds_mq_init(&gp_cds_context->freeVosMq); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to initialize CDS free message queue %d", + __func__, vStatus); + CDF_ASSERT(0); + goto err_wma_complete_event; + } + + for (iter = 0; iter < CDS_CORE_MAX_MESSAGES; iter++) { + (gp_cds_context->aMsgWrappers[iter]).pVosMsg = + &(gp_cds_context->aMsgBuffers[iter]); + INIT_LIST_HEAD(&gp_cds_context->aMsgWrappers[iter].msgNode); + cds_mq_put(&gp_cds_context->freeVosMq, + &(gp_cds_context->aMsgWrappers[iter])); + } + + /* Now Open the CDS Scheduler */ + vStatus = cds_sched_open(gp_cds_context, &gp_cds_context->cdf_sched, + sizeof(cds_sched_context)); + + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to open CDS Scheduler %d", __func__, + vStatus); + CDF_ASSERT(0); + goto err_msg_queue; + } +#if defined(QCA_WIFI_FTM) + /* Initialize BMI and Download firmware */ + pHifContext = cds_get_context(CDF_MODULE_ID_HIF); + if (!pHifContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: failed to get HIF context", __func__); + goto err_sched_close; + } + + if (bmi_download_firmware(pHifContext)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: BMI failed to download target", __func__); + goto err_bmi_close; + } + htcInfo.pContext = gp_cds_context->pHIFContext; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge; + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + + /* Create HTC */ + gp_cds_context->htc_ctx = + htc_create(htcInfo.pContext, &htcInfo, cdf_ctx); + if (!gp_cds_context->htc_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to Create HTC", __func__); + goto err_bmi_close; + } + + if (bmi_done(pHifContext)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_htc_close; + } +#endif /* QCA_WIFI_FTM */ + + /*Open the WMA module */ + cdf_mem_set(&mac_openParms, sizeof(mac_openParms), 0); + mac_openParms.driverType = eDRIVER_TYPE_MFG; + + hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if ((NULL == hdd_ctx) || (NULL == hdd_ctx->config)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Hdd Context is Null", __func__); + CDF_ASSERT(0); + goto err_htc_close; + } + + mac_openParms.powersaveOffloadEnabled = + hdd_ctx->config->enablePowersaveOffload; + +#ifdef WLAN_FEATURE_LPSS + mac_openParms.is_lpass_enabled = hdd_ctx->config->enablelpasssupport; +#endif + + vStatus = wma_open(gp_cds_context, + wlan_hdd_ftm_update_tgt_cfg, NULL, &mac_openParms); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to open WMA module %d", __func__, + vStatus); + CDF_ASSERT(0); + goto err_htc_close; + } +#if defined(QCA_WIFI_FTM) + ((struct ol_softc *)pHifContext)->enable_ramdump_collection = + hdd_ctx->config->is_ramdump_enabled; + + pHtcContext = cds_get_context(CDF_MODULE_ID_HTC); + if (!pHtcContext) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: failed to get HTC context", __func__); + goto err_wma_close; + } + if (htc_wait_target(pHtcContext)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_wma_close; + } +#endif + + /* Now proceed to open the MAC */ + + /* UMA is supported in hardware for performing the + * frame translation 802.11 <-> 802.3 + */ + mac_openParms.frameTransRequired = 1; + + sirStatus = + mac_open(&(gp_cds_context->pMACContext), + gp_cds_context->pHDDContext, + &mac_openParms); + + if (eSIR_SUCCESS != sirStatus) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to open MAC %d", __func__, sirStatus); + CDF_ASSERT(0); + goto err_wma_close; + } +#ifndef QCA_WIFI_FTM + /* Now proceed to open the SME */ + vStatus = sme_open(gp_cds_context->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + /* Critical Error ... Cannot proceed further */ + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to open SME %d", __func__, vStatus); + goto err_mac_close; + } + + vStatus = sme_init_chan_list(gp_cds_context->pMACContext, + hdd_ctx->reg.alpha2, hdd_ctx->reg.cc_src); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to init sme channel list", __func__); + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS successfully Opened", __func__); + return CDF_STATUS_SUCCESS; + } +#else + return CDF_STATUS_SUCCESS; +#endif + +#ifndef QCA_WIFI_FTM +err_mac_close: +#endif + mac_close(gp_cds_context->pMACContext); + +err_wma_close: + wma_close(gp_cds_context); + +err_htc_close: +#if defined(QCA_WIFI_FTM) + if (gp_cds_context->htc_ctx) { + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + +err_bmi_close: + bmi_cleanup(pHifContext); +#endif /* QCA_WIFI_FTM */ + +err_sched_close: + cds_sched_close(gp_cds_context); +err_msg_queue: + cds_mq_deinit(&gp_cds_context->freeVosMq); + +err_wma_complete_event: + cdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + +err_probe_event: + cdf_event_destroy(&gp_cds_context->ProbeEvent); + + return CDF_STATUS_E_FAILURE; + +} /* wlan_ftm_cds_open() */ + +/** + * wlan_ftm_cds_close() - Close the CDF Module in FTM mode + * @cds_context: context of cds + * + * The wlan_ftm_cds_close() function closes the CDF Module + * + * Return: CDF_STATUS_SUCCESS - successfully closed + */ +static CDF_STATUS wlan_ftm_cds_close(v_CONTEXT_t cds_context) +{ + CDF_STATUS cdf_status; + p_cds_contextType gp_cds_context = (p_cds_contextType) cds_context; + +#ifndef QCA_WIFI_FTM + cdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close SME %d", __func__, cdf_status); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } +#endif + + cdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close MAC %d", __func__, cdf_status); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + ((p_cds_contextType) cds_context)->pMACContext = NULL; + + + cdf_status = wma_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close WMA %d", __func__, cdf_status); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } +#if defined(QCA_WIFI_FTM) + if (gp_cds_context->htc_ctx) { + htc_stop(gp_cds_context->htc_ctx); + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + cdf_status = wma_wmi_service_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma_wmi_service", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + hif_disable_isr(gp_cds_context->pHIFContext); +#endif + + cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq); + + cdf_status = cdf_event_destroy(&gp_cds_context->ProbeEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to destroy ProbeEvent %d", __func__, + cdf_status); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + cdf_status = cdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to destroy wmaCompleteEvent %d", __func__, + cdf_status); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * cds_ftm_pre_start() - Pre-start CDS Module in FTM Mode + * @cds_context: The CDS context + * + * The cds_ftm_pre_start() function performs all pre-start activities + * in FTM mode. + * + * Return: CDF_STATUS_SUCCESS if pre-start was successful, an + * appropriate CDF_STATUS_E_* error code otherwise + */ +static CDF_STATUS cds_ftm_pre_start(v_CONTEXT_t cds_context) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + p_cds_contextType p_cds_context = (p_cds_contextType) cds_context; +#if defined(QCA_WIFI_FTM) + p_cds_contextType gp_cds_context = + cds_get_global_context(); +#endif + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, "cds prestart"); + if (NULL == p_cds_context->pWMAContext) { + CDF_ASSERT(0); + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "%s: WMA NULL context", __func__); + return CDF_STATUS_E_FAILURE; + } + + /* Reset WMA wait event */ + cdf_event_reset(&p_cds_context->wmaCompleteEvent); + + /*call WMA pre start */ + vStatus = wma_pre_start(p_cds_context); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Failed to WMA prestart "); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* Need to update time out of complete */ + vStatus = cdf_wait_single_event(&p_cds_context->wmaCompleteEvent, + HDD_FTM_WMA_PRE_START_TIMEOUT); + if (vStatus != CDF_STATUS_SUCCESS) { + if (vStatus == CDF_STATUS_E_TIMEOUT) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Timeout occurred before WMA complete", + __func__); + } else { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: wma_pre_start reporting other error", + __func__); + } + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } +#if defined(QCA_WIFI_FTM) + vStatus = htc_start(gp_cds_context->htc_ctx); + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_FATAL, + "Failed to Start HTC"); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + wma_wait_for_ready_event(gp_cds_context->pWMAContext); +#endif /* QCA_WIFI_FTM */ + + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_ftm_open() - Open HDD in FTM Mode + * @hdd_ctx: global HDD context + * + * The function hdd_wlan_startup calls this function to initialize the + * FTM specific modules. + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_ftm_open(hdd_context_t *hdd_ctx) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + p_cds_contextType p_cds_context = NULL; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening CDS", __func__); + + p_cds_context = cds_get_global_context(); + + if (NULL == p_cds_context) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Trying to open CDS without a PreOpen", __func__); + CDF_ASSERT(0); + goto err_cdf_status_failure; + } + + vStatus = wlan_ftm_cds_open(p_cds_context, 0); + + if (!CDF_IS_STATUS_SUCCESS(vStatus)) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_open failed", __func__); + goto err_cdf_status_failure; + } + + /* + * only needed to start WMA, which happens in wlan_hdd_ftm_start() + */ + + /* Save the hal context in Adapter */ + hdd_ctx->hHal = + (tHalHandle) cds_get_context(CDF_MODULE_ID_SME); + + if (NULL == hdd_ctx->hHal) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: HAL context is null", + __func__); + goto err_ftm_close; + } + + return 0; + +err_ftm_close: + wlan_ftm_cds_close(p_cds_context); + +err_cdf_status_failure: + return -EPERM; +} + +/** + * hdd_ftm_service_registration() - Register FTM service + * @hdd_ctx: global HDD context + * + * Return: 0 on success, non-zero on failure + */ +static int hdd_ftm_service_registration(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter; + adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_FTM, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), false); + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: hdd_open_adapter failed", + __func__); + goto err_adapter_open_failure; + } + + hdd_ctx->ftm.ftm_state = WLAN_FTM_INITIALIZED; + + return 0; + +err_adapter_open_failure: + + return -EPERM; +} + +/** + * wlan_ftm_stop() - Stop HDD in FTM mode + * @hdd_ctx: pointer to HDD context + * + * This function stops the following modules + * 1. MAC + * 2. WMA + * + * Return: 0 on success, non-zero on failure + */ +static int wlan_ftm_stop(hdd_context_t *hdd_ctx) +{ + CDF_STATUS cdf_status; + + if (hdd_ctx->ftm.ftm_state != WLAN_FTM_STARTED) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:Ftm has not started. Please start the ftm. ", + __func__); + return -EPERM; + } + + { + /* STOP MAC only */ + void *hHal; + hHal = cds_get_context(CDF_MODULE_ID_SME); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: NULL hHal", __func__); + } else { + cdf_status = + mac_stop(hHal, HAL_STOP_TYPE_SYS_DEEP_SLEEP); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop SYS", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + } + wma_stop(hdd_ctx->pcds_context, HAL_STOP_TYPE_RF_KILL); + } + return 0; +} + +/** + * wlan_hdd_ftm_close() - Close HDD in FTM mode + * @hdd_ctx: pointer to HDD context + * + * Return: 0 on success, non-zero on failure + */ +int wlan_hdd_ftm_close(hdd_context_t *hdd_ctx) +{ + CDF_STATUS cdf_status; + v_CONTEXT_t cds_context = hdd_ctx->pcds_context; + + hdd_adapter_t *adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_FTM); + ENTER(); + if (adapter == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:adapter is NULL", __func__); + return -ENXIO; + } + + if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: Ftm has been started. stopping ftm", __func__); + wlan_ftm_stop(hdd_ctx); + } + + hdd_close_all_adapters(hdd_ctx); + + cdf_status = cds_sched_close(cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to close CDS Scheduler", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + /* Close CDS */ + wlan_ftm_cds_close(cds_context); + +#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR) + spin_lock_bh(&qcmbr_queue_lock); + if (!list_empty(&qcmbr_queue_head)) { + qcmbr_queue_t *msg_buf, *tmp_buf; + list_for_each_entry_safe(msg_buf, tmp_buf, &qcmbr_queue_head, + list) { + list_del(&msg_buf->list); + kfree(msg_buf); + } + } + spin_unlock_bh(&qcmbr_queue_lock); +#endif + + return 0; + +} + + +/** + * hdd_ftm_mc_process_msg() - Process FTM mailbox message + * @message: FTM response message + * + * Process FTM mailbox message + * + * Return: void + */ +static void hdd_ftm_mc_process_msg(void *message) +{ + void *data; + uint32_t data_len; + + if (!message) { + hdd_err("Message is NULL, nothing to process."); + return; + } + + data_len = *((uint32_t *) message); + data = (uint32_t *) message + 1; + +#if defined(LINUX_QCMBR) + wlanqcmbr_mc_process_msg(message); +#else +#ifdef CONFIG_NL80211_TESTMODE + wlan_hdd_testmode_rx_event(data, (size_t) data_len); +#endif +#endif + return; +} + +/** + * wlan_hdd_ftm_start() - Start HDD in FTM mode + * @hdd_ctx: Global HDD context + * + * This function starts the following modules. + * 1) WMA Start. + * 2) HTC Start. + * 3) MAC Start to download the firmware. + * + * Return: 0 for success, non zero for failure + */ +static int wlan_hdd_ftm_start(hdd_context_t *hdd_ctx) +{ + CDF_STATUS vStatus = CDF_STATUS_SUCCESS; + p_cds_contextType p_cds_context = + (p_cds_contextType) (hdd_ctx->pcds_context); + + if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) { + return 0; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Starting CLD SW", __func__); + + /* We support only one instance for now ... */ + if (p_cds_context == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: mismatch in context", __func__); + goto err_status_failure; + } + + if (p_cds_context->pMACContext == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: MAC NULL context", __func__); + goto err_status_failure; + } + + /* Vos preStart is calling */ + if (!CDF_IS_STATUS_SUCCESS(cds_ftm_pre_start(hdd_ctx->pcds_context))) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_pre_enable failed", + __func__); + goto err_status_failure; + } + + sme_register_ftm_msg_processor(hdd_ctx->hHal, hdd_ftm_mc_process_msg); + + vStatus = wma_start(p_cds_context); + if (vStatus != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to start WMA", __func__); + goto err_status_failure; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: MAC correctly started", __func__); + + if (hdd_ftm_service_registration(hdd_ctx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: failed", __func__); + goto err_ftm_service_reg; + } + + hdd_ctx->ftm.ftm_state = WLAN_FTM_STARTED; + + return 0; + +err_ftm_service_reg: + wlan_hdd_ftm_close(hdd_ctx); + +err_status_failure: + + return -EPERM; + +} + +#if defined(QCA_WIFI_FTM) +/** + * hdd_ftm_start() - Start HDD in FTM mode + * @hdd_ctx: Global HDD context + * + * Return: 0 for success, non zero for failure + */ +int hdd_ftm_start(hdd_context_t *hdd_ctx) +{ + return wlan_hdd_ftm_start(hdd_ctx); +} +#endif + +#if defined(QCA_WIFI_FTM) +/** + * hdd_ftm_stop() - Stop HDD in FTM mode + * @hdd_ctx: Global HDD context + * + * Return: 0 for success, non zero for failure + */ +int hdd_ftm_stop(hdd_context_t *hdd_ctx) +{ + return wlan_ftm_stop(hdd_ctx); +} +#endif + +#if defined(QCA_WIFI_FTM) +#if defined(LINUX_QCMBR) +/** + * wlan_hdd_qcmbr_command() - QCMBR command handler + * @adapter: adapter upon which the command was received + * @pqcmbr_data: QCMBR command + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter, + qcmbr_data_t *pqcmbr_data) +{ + int ret = 0; + qcmbr_queue_t *qcmbr_buf = NULL; + + switch (pqcmbr_data->cmd) { + case ATH_XIOCTL_UNIFIED_UTF_CMD: { + pqcmbr_data->copy_to_user = 0; + if (pqcmbr_data->length) { + if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf, + pqcmbr_data-> + length) + != CDF_STATUS_SUCCESS) { + ret = -EBUSY; + } else { + ret = 0; + } + } + } + break; + + case ATH_XIOCTL_UNIFIED_UTF_RSP: { + pqcmbr_data->copy_to_user = 1; + if (!list_empty(&qcmbr_queue_head)) { + spin_lock_bh(&qcmbr_queue_lock); + qcmbr_buf = list_first_entry(&qcmbr_queue_head, + qcmbr_queue_t, + list); + list_del(&qcmbr_buf->list); + spin_unlock_bh(&qcmbr_queue_lock); + ret = 0; + } else { + ret = -1; + } + + if (!ret) { + memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf, + (MAX_UTF_LENGTH + 4)); + kfree(qcmbr_buf); + } else { + ret = -EAGAIN; + } + } + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +/** + * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter, + struct ifreq *ifr) +{ + qcmbr_data_t *qcmbr_data; + int ret = 0; + + qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if (qcmbr_data->copy_to_user) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (MAX_UTF_LENGTH + 4)); + } + +exit: + kfree(qcmbr_data); + return ret; +} +#else /* CONFIG_COMPAT */ +static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter, + struct ifreq *ifr) +{ + return 0; +} +#endif /* CONFIG_COMPAT */ + +/** + * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + qcmbr_data_t *qcmbr_data; + int ret = 0; + + qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if (qcmbr_data->copy_to_user) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (MAX_UTF_LENGTH + 4)); + } + +exit: + kfree(qcmbr_data); + return ret; +} + +/** + * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + int ret = 0; + + if (is_compat_task()) { + ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr); + } else { + ret = wlan_hdd_qcmbr_ioctl(adapter, ifr); + } + + return ret; +} + +/** + * wlanqcmbr_mc_process_msg() - Process QCMBR response message + * @message: QCMBR message + * + * Return: None + */ +static void wlanqcmbr_mc_process_msg(void *message) +{ + qcmbr_queue_t *qcmbr_buf = NULL; + uint32_t data_len; + + data_len = *((uint32_t *) message) + sizeof(uint32_t); + qcmbr_buf = kzalloc(sizeof(qcmbr_queue_t), GFP_KERNEL); + if (qcmbr_buf != NULL) { + memcpy(qcmbr_buf->utf_buf, message, data_len); + spin_lock_bh(&qcmbr_queue_lock); + list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head); + spin_unlock_bh(&qcmbr_queue_lock); + } +} +#endif /*LINUX_QCMBR */ + +/** + * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command + * @data: FTM testmode command + * @len: length of @data + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len) +{ + struct ar6k_testmode_cmd_data *cmd_data; + + cmd_data = (struct ar6k_testmode_cmd_data *) + cdf_mem_malloc(sizeof(*cmd_data)); + + if (!cmd_data) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("Failed to allocate FTM command data")); + return CDF_STATUS_E_NOMEM; + } + + cmd_data->data = cdf_mem_malloc(len); + + if (!cmd_data->data) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("Failed to allocate FTM command data buffer")); + cdf_mem_free(cmd_data); + return CDF_STATUS_E_NOMEM; + } + + cmd_data->len = len; + cdf_mem_copy(cmd_data->data, data, len); + + if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) { + cdf_mem_free(cmd_data->data); + cdf_mem_free(cmd_data); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif /*QCA_WIFI_FTM */ diff --git a/core/hdd/src/wlan_hdd_green_ap.c b/core/hdd/src/wlan_hdd_green_ap.c new file mode 100644 index 0000000000..7cf2c23212 --- /dev/null +++ b/core/hdd/src/wlan_hdd_green_ap.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_green_ap.c + * + * WLAN Host Device Driver Green AP implementation + * + */ + +/* Include Files */ +#include +#include +#include "wlan_hdd_green_ap.h" +#include "wma_api.h" +#include "cds_concurrency.h" + +#define GREEN_AP_PS_ON_TIME (0) +#define GREEN_AP_PS_DELAY_TIME (20) + +/** + * enum hdd_green_ap_ps_state - Green-AP power save states + * @GREEN_AP_PS_IDLE_STATE: the Green_AP is not enabled + * @GREEN_AP_PS_OFF_STATE: in Power Saving OFF state + * @GREEN_AP_PS_WAIT_STATE: in transition to Power Saving ON state + * @GREEN_AP_PS_ON_STATE: in Power Saving ON state + */ +enum hdd_green_ap_ps_state { + GREEN_AP_PS_IDLE_STATE = 1, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_ON_STATE, +}; + +/** + * enum hdd_green_ap_event - Green-AP power save events + * @GREEN_AP_PS_START_EVENT: event to indicate to enable Green_AP + * @GREEN_AP_PS_START_EVENT: event to indicate to disable Green_AP + * @GREEN_AP_ADD_STA_EVENT: event to indicate a new STA connected + * @GREEN_AP_DEL_STA_EVENT: event to indicate a STA disconnected + * @GREEN_AP_PS_ON_EVENT: event to indicate to enter Power Saving state + * @GREEN_AP_PS_WAIT_EVENT: event to indicate in the transition to Power Saving + */ +enum hdd_green_ap_event { + GREEN_AP_PS_START_EVENT = 1, + GREEN_AP_PS_STOP_EVENT, + GREEN_AP_ADD_STA_EVENT, + GREEN_AP_DEL_STA_EVENT, + GREEN_AP_PS_ON_EVENT, + GREEN_AP_PS_WAIT_EVENT, +}; + +/** + * struct hdd_green_ap_ctx - Green-AP context + * @ps_enable: Whether or not Green AP is enabled + * @ps_on_time: Amount of time to stay in Green AP power saving state + * @ps_delay_time: Amount of time to delay when changing states + * @num_nodes: Number of connected clients + * @ps_state: Current state + * @ps_event: Event to trigger when timer expires + * @ps_timer: Event timer + */ +struct hdd_green_ap_ctx { + uint8_t ps_enable; + uint32_t ps_on_time; + uint32_t ps_delay_time; + uint32_t num_nodes; + + enum hdd_green_ap_ps_state ps_state; + enum hdd_green_ap_event ps_event; + + cdf_mc_timer_t ps_timer; +}; + +/** + * hdd_wlan_green_ap_update() - update the current State and Event + * @hdd_ctx: Global HDD context + * @state: New state + * @event: New event + * + * Return: none + */ +static void hdd_wlan_green_ap_update(struct hdd_context_s *hdd_ctx, + enum hdd_green_ap_ps_state state, + enum hdd_green_ap_event event) +{ + struct hdd_green_ap_ctx *green_ap = hdd_ctx->green_ap_ctx; + + green_ap->ps_state = state; + green_ap->ps_event = event; +} + +/** + * hdd_wlan_green_ap_enable() - Send Green AP configuration to firmware + * @adapter: Adapter upon which Green AP is being configured + * @enable: Flag which indicates if Green AP is being enabled or disabled + * + * Return: 0 upon success, non-zero upon failure + */ +static int hdd_wlan_green_ap_enable(hdd_adapter_t *adapter, + uint8_t enable) +{ + int ret; + + hddLog(LOG1, FL("Set Green-AP val: %d"), enable); + + ret = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID, + enable, DBG_CMD); + + return ret; +} + +/** + * hdd_wlan_green_ap_mc() - Green AP state machine + * @hdd_ctx: HDD global context + * @event: New event being processed + * + * Return: none + */ +static void hdd_wlan_green_ap_mc(struct hdd_context_s *hdd_ctx, + enum hdd_green_ap_event event) +{ + struct hdd_green_ap_ctx *green_ap; + hdd_adapter_t *adapter; + + green_ap = hdd_ctx->green_ap_ctx; + if (green_ap == NULL) + return; + + hddLog(LOG1, FL("Green-AP event: %d, state: %d, num_nodes: %d"), + event, green_ap->ps_state, green_ap->num_nodes); + + /* handle the green ap ps event */ + switch (event) { + case GREEN_AP_PS_START_EVENT: + green_ap->ps_enable = 1; + break; + + case GREEN_AP_PS_STOP_EVENT: + if (!(cds_get_concurrency_mode() & CDF_SAP_MASK)) + green_ap->ps_enable = 0; + break; + + case GREEN_AP_ADD_STA_EVENT: + green_ap->num_nodes++; + break; + + case GREEN_AP_DEL_STA_EVENT: + if (green_ap->num_nodes) + green_ap->num_nodes--; + break; + + case GREEN_AP_PS_ON_EVENT: + case GREEN_AP_PS_WAIT_EVENT: + break; + + default: + hddLog(LOGE, FL("invalid event %d"), event); + break; + } + + /* Confirm that power save is enabled before doing state transitions */ + if (!green_ap->ps_enable) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("Green-AP is disabled")); + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_IDLE_STATE, + GREEN_AP_PS_WAIT_EVENT); + goto done; + } + + adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP); + if (adapter == NULL) { + hddLog(LOGE, FL("Green-AP no SAP adapter")); + goto done; + } + + /* handle the green ap ps state */ + switch (green_ap->ps_state) { + case GREEN_AP_PS_IDLE_STATE: + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + break; + + case GREEN_AP_PS_OFF_STATE: + if (!green_ap->num_nodes) { + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_WAIT_EVENT); + cdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_delay_time); + } + break; + + case GREEN_AP_PS_WAIT_STATE: + if (!green_ap->num_nodes) { + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_ON_STATE, + GREEN_AP_PS_WAIT_EVENT); + + hdd_wlan_green_ap_enable(adapter, 1); + + if (green_ap->ps_on_time) { + hdd_wlan_green_ap_update(hdd_ctx, + 0, + GREEN_AP_PS_WAIT_EVENT); + cdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_on_time); + } + } else { + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + } + break; + + case GREEN_AP_PS_ON_STATE: + if (green_ap->num_nodes) { + if (hdd_wlan_green_ap_enable(adapter, 0)) { + hddLog(LOGE, FL("FAILED TO SET GREEN-AP mode")); + goto done; + } + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + } else if ((green_ap->ps_event == GREEN_AP_PS_WAIT_EVENT) + && (green_ap->ps_on_time)) { + + /* ps_on_time timeout, switch to ps off */ + hdd_wlan_green_ap_update(hdd_ctx, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_ON_EVENT); + + if (hdd_wlan_green_ap_enable(adapter, 0)) { + hddLog(LOGE, FL("FAILED TO SET GREEN-AP mode")); + goto done; + } + + cdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_delay_time); + } + break; + + default: + hddLog(LOGE, FL("invalid state %d"), green_ap->ps_state); + hdd_wlan_green_ap_update(hdd_ctx, GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + break; + } + +done: + return; +} + +/** + * hdd_wlan_green_ap_timer_fn() - Green AP Timer handler + * @ctx: Global HDD context + * + * Return: none + */ +static void hdd_wlan_green_ap_timer_fn(void *ctx) +{ + struct hdd_context_s *hdd_ctx = ctx; + struct hdd_green_ap_ctx *green_ap; + + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + + green_ap = hdd_ctx->green_ap_ctx; + if (green_ap) + hdd_wlan_green_ap_mc(hdd_ctx, green_ap->ps_event); +} + +/** + * hdd_wlan_green_ap_attach() - Attach Green AP context to HDD context + * @hdd_ctx: Global HDD contect + * + * Return: CDF_STATUS_SUCCESS on success, otherwise CDF_STATUS_E_* error + */ +static CDF_STATUS hdd_wlan_green_ap_attach(struct hdd_context_s *hdd_ctx) +{ + struct hdd_green_ap_ctx *green_ap; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + ENTER(); + + green_ap = cdf_mem_malloc(sizeof(*green_ap)); + if (!green_ap) { + hddLog(LOGP, FL("Memory allocation for Green-AP failed!")); + status = CDF_STATUS_E_NOMEM; + goto error; + } + + cdf_mem_zero(green_ap, sizeof(*green_ap)); + green_ap->ps_state = GREEN_AP_PS_OFF_STATE; + green_ap->ps_event = 0; + green_ap->num_nodes = 0; + green_ap->ps_on_time = GREEN_AP_PS_ON_TIME; + green_ap->ps_delay_time = GREEN_AP_PS_DELAY_TIME; + + cdf_mc_timer_init(&green_ap->ps_timer, + CDF_TIMER_TYPE_SW, + hdd_wlan_green_ap_timer_fn, hdd_ctx); + +error: + hdd_ctx->green_ap_ctx = green_ap; + + EXIT(); + return status; +} + +/** + * hdd_wlan_green_ap_deattach() - Detach Green AP context from HDD context + * @hdd_ctx: Global HDD contect + * + * Return: CDF_STATUS_SUCCESS on success, otherwise CDF_STATUS_E_* error + */ +static CDF_STATUS hdd_wlan_green_ap_deattach(struct hdd_context_s *hdd_ctx) +{ + struct hdd_green_ap_ctx *green_ap = hdd_ctx->green_ap_ctx; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + ENTER(); + + if (green_ap == NULL) { + hddLog(LOG1, FL("Green-AP is not enabled")); + status = CDF_STATUS_E_NOSUPPORT; + goto done; + } + + /* check if the timer status is destroyed */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&green_ap->ps_timer)) + cdf_mc_timer_stop(&green_ap->ps_timer); + + /* Destroy the Green AP timer */ + if (!CDF_IS_STATUS_SUCCESS(cdf_mc_timer_destroy(&green_ap->ps_timer))) + hddLog(LOG1, FL("Cannot deallocate Green-AP's timer")); + + /* release memory */ + cdf_mem_zero(green_ap, sizeof(*green_ap)); + cdf_mem_free(green_ap); + hdd_ctx->green_ap_ctx = NULL; + +done: + + EXIT(); + return status; +} + +/** + * hdd_wlan_green_ap_init() - Initialize Green AP feature + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_init(struct hdd_context_s *hdd_ctx) +{ + if (!CDF_IS_STATUS_SUCCESS(hdd_wlan_green_ap_attach(hdd_ctx))) + hddLog(LOGE, FL("Failed to allocate Green-AP resource")); +} + +/** + * hdd_wlan_green_ap_deinit() - De-initialize Green AP feature + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_deinit(struct hdd_context_s *hdd_ctx) +{ + if (!CDF_IS_STATUS_SUCCESS(hdd_wlan_green_ap_deattach(hdd_ctx))) + hddLog(LOGE, FL("Cannot deallocate Green-AP resource")); +} + +/** + * hdd_wlan_green_ap_start_bss() - Notify Green AP of Start BSS event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_start_bss(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg = hdd_ctx->config; + + if (!(CDF_STA_MASK & hdd_ctx->concurrency_mode) && + cfg->enable2x2 && cfg->enableGreenAP) { + hdd_wlan_green_ap_mc(hdd_ctx, GREEN_AP_PS_START_EVENT); + } else { + hdd_wlan_green_ap_mc(hdd_ctx, GREEN_AP_PS_STOP_EVENT); + hddLog(LOG1, + "Green-AP: is disabled, due to sta_concurrency: %d, enable2x2: %d, enableGreenAP: %d", + CDF_STA_MASK & hdd_ctx->concurrency_mode, + cfg->enable2x2, cfg->enableGreenAP); + } +} + +/** + * hdd_wlan_green_ap_stop_bss() - Notify Green AP of Stop BSS event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_stop_bss(struct hdd_context_s *hdd_ctx) +{ + hdd_wlan_green_ap_mc(hdd_ctx, GREEN_AP_PS_STOP_EVENT); +} + +/** + * hdd_wlan_green_ap_add_sta() - Notify Green AP of Add Station event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_add_sta(struct hdd_context_s *hdd_ctx) +{ + hdd_wlan_green_ap_mc(hdd_ctx, GREEN_AP_ADD_STA_EVENT); +} + +/** + * hdd_wlan_green_ap_del_sta() - Notify Green AP of Delete Station event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_wlan_green_ap_del_sta(struct hdd_context_s *hdd_ctx) +{ + hdd_wlan_green_ap_mc(hdd_ctx, GREEN_AP_DEL_STA_EVENT); +} diff --git a/core/hdd/src/wlan_hdd_green_ap.h b/core/hdd/src/wlan_hdd_green_ap.h new file mode 100644 index 0000000000..8844d71d87 --- /dev/null +++ b/core/hdd/src/wlan_hdd_green_ap.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_GREEN_AP_H +#define __WLAN_HDD_GREEN_AP_H + +/** + * DOC: wlan_hdd_green_ap.h + * + * WLAN Host Device Driver Green AP API specification + */ + +struct hdd_context_s; + +#ifdef FEATURE_GREEN_AP +void hdd_wlan_green_ap_init(struct hdd_context_s *hdd_ctx); +void hdd_wlan_green_ap_deinit(struct hdd_context_s *hdd_ctx); +void hdd_wlan_green_ap_start_bss(struct hdd_context_s *hdd_ctx); +void hdd_wlan_green_ap_stop_bss(struct hdd_context_s *hdd_ctx); +void hdd_wlan_green_ap_add_sta(struct hdd_context_s *hdd_ctx); +void hdd_wlan_green_ap_del_sta(struct hdd_context_s *hdd_ctx); +#else +static inline void hdd_wlan_green_ap_init(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_wlan_green_ap_deinit(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_wlan_green_ap_start_bss(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_wlan_green_ap_stop_bss(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_wlan_green_ap_add_sta(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_wlan_green_ap_del_sta(struct hdd_context_s *hdd_ctx) {} +#endif /* FEATURE_GREEN_AP */ +#endif /* __WLAN_HDD_GREEN_AP_H */ diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c new file mode 100644 index 0000000000..6024539d8b --- /dev/null +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -0,0 +1,8421 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_hostapd.c + * + * WLAN Host Device Driver implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_p2p.h" +#include +#include "cfg_api.h" +#include "wni_cfg.h" +#include "wlan_hdd_misc.h" +#include +#if defined CONFIG_CNSS +#include +#endif + +#include "wma.h" +#ifdef DEBUG +#include "wma_api.h" +#endif +#include "wlan_hdd_trace.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "wlan_hdd_cfg.h" +#include "cds_concurrency.h" +#include "wlan_hdd_green_ap.h" + +#define IS_UP(_dev) \ + (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) +#define IS_UP_AUTO(_ic) \ + (IS_UP((_ic)->ic_dev) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO) +#define WE_WLAN_VERSION 1 +#define WE_GET_STA_INFO_SIZE 30 +/* WEXT limitation: MAX allowed buf len for any * + * IW_PRIV_TYPE_CHAR is 2Kbytes * + */ +#define WE_SAP_MAX_STA_INFO 0x7FF + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +#define SAP_24GHZ_CH_COUNT (14) +#define ACS_SCAN_EXPIRY_TIMEOUT_S 4 +#define CONNECTION_UPDATE_TIMEOUT 500 + +#define DUMP_DP_TRACE 0 + +/* Function definitions */ + +/** + * hdd_hostapd_channel_wakelock_init() - init the channel wakelock + * @pHddCtx: pointer to hdd context + * + * Return: None + */ +void hdd_hostapd_channel_wakelock_init(hdd_context_t *pHddCtx) +{ + /* Initialize the wakelock */ + cdf_wake_lock_init(&pHddCtx->sap_dfs_wakelock, "sap_dfs_wakelock"); + atomic_set(&pHddCtx->sap_dfs_ref_cnt, 0); +} + +/** + * hdd_hostapd_channel_allow_suspend() - allow suspend in a channel. + * Called when, 1. bss stopped, 2. channel switch + * + * @pAdapter: pointer to hdd adapter + * @channel: current channel + * + * Return: None + */ +void hdd_hostapd_channel_allow_suspend(hdd_adapter_t *pAdapter, + uint8_t channel) +{ + + hdd_context_t *pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + hddLog(LOG1, FL("bssState: %d, channel: %d, dfs_ref_cnt: %d"), + pHostapdState->bssState, channel, + atomic_read(&pHddCtx->sap_dfs_ref_cnt)); + + /* Return if BSS is already stopped */ + if (pHostapdState->bssState == BSS_STOP) + return; + + /* Release wakelock when no more DFS channels are used */ + if (CHANNEL_STATE_DFS == cds_get_channel_state(channel)) { + if (atomic_dec_and_test(&pHddCtx->sap_dfs_ref_cnt)) { + hddLog(LOGE, FL("DFS: allowing suspend (chan %d)"), + channel); + cdf_wake_lock_release(&pHddCtx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + } + } +} + +/** + * hdd_hostapd_channel_prevent_suspend() - prevent suspend in a channel. + * Called when, 1. bss started, 2. channel switch + * + * @pAdapter: pointer to hdd adapter + * @channel: current channel + * + * Return - None + */ +void hdd_hostapd_channel_prevent_suspend(hdd_adapter_t *pAdapter, + uint8_t channel) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + hddLog(LOG1, FL("bssState: %d, channel: %d, dfs_ref_cnt: %d"), + pHostapdState->bssState, channel, + atomic_read(&pHddCtx->sap_dfs_ref_cnt)); + + /* Return if BSS is already started && wakelock is acquired */ + if ((pHostapdState->bssState == BSS_START) && + (atomic_read(&pHddCtx->sap_dfs_ref_cnt) >= 1)) + return; + + /* Acquire wakelock if we have at least one DFS channel in use */ + if (CHANNEL_STATE_DFS == cds_get_channel_state(channel)) { + if (atomic_inc_return(&pHddCtx->sap_dfs_ref_cnt) == 1) { + hddLog(LOGE, FL("DFS: preventing suspend (chan %d)"), + channel); + cdf_wake_lock_acquire(&pHddCtx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + } + } +} + +/** + * hdd_hostapd_channel_wakelock_deinit() - destroy the channel wakelock + * + * @pHddCtx: pointer to hdd context + * + * Return: None + */ +void hdd_hostapd_channel_wakelock_deinit(hdd_context_t *pHddCtx) +{ + if (atomic_read(&pHddCtx->sap_dfs_ref_cnt)) { + /* Release wakelock */ + cdf_wake_lock_release(&pHddCtx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT); + /* Reset the reference count */ + atomic_set(&pHddCtx->sap_dfs_ref_cnt, 0); + hddLog(LOGE, FL("DFS: allowing suspend")); + } + + /* Destroy lock */ + cdf_wake_lock_destroy(&pHddCtx->sap_dfs_wakelock); +} + +/** + * __hdd_hostapd_open() - hdd open function for hostapd interface + * This is called in response to ifconfig up + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_open(struct net_device *dev) +{ + hdd_adapter_t *pAdapter = netdev_priv(dev); + + ENTER(); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST, NO_SESSION, 0)); + + if (WLAN_HDD_GET_CTX(pAdapter)->isLoadInProgress || + WLAN_HDD_GET_CTX(pAdapter)->isUnloadInProgress) { + hddLog(LOGE, + FL("Driver load/unload in progress, ignore adapter open")); + goto done; + } + /* Enable all Tx queues */ + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); +done: + EXIT(); + return 0; +} + +/** + * hdd_hostapd_open() - SSR wrapper for __hdd_hostapd_open + * @dev: pointer to net device + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_stop() - hdd stop function for hostapd interface + * This is called in response to ifconfig down + * + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_stop(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ENTER(); + + /* Stop all tx queues */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + EXIT(); + return 0; +} + +/** + * hdd_hostapd_stop() - SSR wrapper for__hdd_hostapd_stop + * @dev: pointer to net_device + * + * This is called in response to ifconfig down + * + * Return: 0 on success, error number otherwise + */ +int hdd_hostapd_stop(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_uninit() - hdd uninit function + * This is called during the netdev unregister to uninitialize all data + * associated with the device. + * + * @dev: pointer to net_device structure + * + * Return: None + */ +static void __hdd_hostapd_uninit(struct net_device *dev) +{ + hdd_adapter_t *adapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + + ENTER(); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hddLog(LOGE, FL("Invalid magic")); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hddLog(LOGE, FL("NULL hdd_ctx")); + return; + } + + hdd_deinit_adapter(hdd_ctx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->dev = NULL; + adapter->magic = 0; + + EXIT(); +} + +/** + * hdd_hostapd_uninit() - SSR wrapper for __hdd_hostapd_uninit + * @dev: pointer to net_device + * + * Return: 0 on success, error number otherwise + */ +static void hdd_hostapd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_hostapd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_hostapd_change_mtu() - change mtu + * @dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int __hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu) +{ + return 0; +} + +/** + * hdd_hostapd_change_mtu() - SSR wrapper for __hdd_hostapd_change_mtu + * @dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_change_mtu(dev, new_mtu); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef QCA_HT_2040_COEX +CDF_STATUS hdd_set_sap_ht2040_mode(hdd_adapter_t *pHostapdAdapter, + uint8_t channel_type) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + + hddLog(LOGE, FL("change HT20/40 mode")); + + if (WLAN_HDD_SOFTAP == pHostapdAdapter->device_mode) { + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (NULL == hHal) { + hddLog(LOGE, FL("Hal ctx is null")); + return CDF_STATUS_E_FAULT; + } + cdf_ret_status = + sme_set_ht2040_mode(hHal, pHostapdAdapter->sessionId, + channel_type, true); + if (cdf_ret_status == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Failed to change HT20/40 mode")); + return CDF_STATUS_E_FAILURE; + } + } + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * __hdd_hostapd_set_mac_address() - + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * @dev: pointer to the net device. + * @addr: pointer to the sockaddr. + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *psta_mac_addr = addr; + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + EXIT(); + return 0; +} + +/** + * hdd_hostapd_set_mac_address() - set mac address + * @dev: pointer to net_device + * @addr: mac address + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_hostapd_inactivity_timer_cb(void *usrDataForCallback) +{ + struct net_device *dev = (struct net_device *)usrDataForCallback; + uint8_t we_custom_event[64]; + union iwreq_data wrqu; +#ifdef DISABLE_CONCURRENCY_AUTOSAVE + CDF_STATUS cdf_status; + hdd_adapter_t *pHostapdAdapter; + hdd_ap_ctx_t *pHddApCtx; +#endif /* DISABLE_CONCURRENCY_AUTOSAVE */ + + /* event_name space-delimiter driver_module_name + * Format of the event is "AUTO-SHUT.indication" " " "module_name" + */ + char *autoShutEvent = "AUTO-SHUT.indication" " " KBUILD_MODNAME; + + /* For the NULL at the end */ + int event_len = strlen(autoShutEvent) + 1; + + ENTER(); + +#ifdef DISABLE_CONCURRENCY_AUTOSAVE + if (cds_concurrent_open_sessions_running()) { + /* + * This timer routine is going to be called only when AP + * persona is up. + * If there are concurrent sessions running we do not want + * to shut down the Bss.Instead we run the timer again so + * that if Autosave is enabled next time and other session + was down only then we bring down AP + */ + pHostapdAdapter = netdev_priv(dev); + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + cdf_status = + cdf_mc_timer_start(&pHddApCtx->hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX(pHostapdAdapter))-> + config->nAPAutoShutOff * 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("Failed to init AP inactivity timer")); + } + EXIT(); + return; + } +#endif /* DISABLE_CONCURRENCY_AUTOSAVE */ + memset(&we_custom_event, '\0', sizeof(we_custom_event)); + memcpy(&we_custom_event, autoShutEvent, event_len); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = event_len; + + hddLog(LOG1, FL("Shutting down AP interface due to inactivity")); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, (char *)we_custom_event); + + EXIT(); +} + +void hdd_clear_all_sta(hdd_adapter_t *pHostapdAdapter, + void *usrDataForCallback) +{ + uint8_t staId = 0; + struct net_device *dev; + dev = (struct net_device *)usrDataForCallback; + + hddLog(LOGE, FL("Clearing all the STA entry....")); + for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) { + if (pHostapdAdapter->aStaInfo[staId].isUsed && + (staId != + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uBCStaId)) { + /* Disconnect all the stations */ + hdd_softap_sta_disassoc(pHostapdAdapter, + &pHostapdAdapter-> + aStaInfo[staId].macAddrSTA. + bytes[0]); + } + } +} + +static int hdd_stop_bss_link(hdd_adapter_t *pHostapdAdapter, + void *usrDataForCallback) +{ + struct net_device *dev; + hdd_context_t *pHddCtx = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + dev = (struct net_device *)usrDataForCallback; + ENTER(); + + pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { +#ifdef WLAN_FEATURE_MBSSID + status = + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR( + pHostapdAdapter)); +#else + status = + wlansap_stop_bss((WLAN_HDD_GET_CTX(pHostapdAdapter))-> + pcds_context); +#endif + if (CDF_IS_STATUS_SUCCESS(status)) + hddLog(LOGE, FL("Deleting SAP/P2P link!!!!!!")); + + clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + cds_decr_session_set_pcl(pHddCtx, + pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); + } + EXIT(); + return (status == CDF_STATUS_SUCCESS) ? 0 : -EBUSY; +} + +/** + * hdd_issue_stored_joinreq() - This function will trigger stations's + * cached connect request to proceed. + * @hdd_ctx: pointer to hdd context. + * @sta_adater: pointer to station adapter. + * + * This function will call SME to release station's stored/cached connect + * request to proceed. + * + * Return: none. + */ +static void hdd_issue_stored_joinreq(hdd_adapter_t *sta_adapter, + hdd_context_t *hdd_ctx) +{ + tHalHandle hal_handle; + uint32_t roam_id; + + if (NULL == sta_adapter) { + hddLog(LOGE, + FL + ("Invalid station adapter, ignore issueing join req")); + return; + } + hal_handle = WLAN_HDD_GET_HAL_CTX(sta_adapter); + + if (true == cds_is_sta_connection_pending(hdd_ctx)) { + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ISSUE_JOIN_REQ, + sta_adapter->sessionId, roam_id)); + if (CDF_STATUS_SUCCESS != + sme_issue_stored_joinreq(hal_handle, + &roam_id, + sta_adapter->sessionId)) { + /* change back to NotAssociated */ + hdd_conn_set_connection_state(sta_adapter, + eConnectionState_NotConnected); + } + cds_change_sta_conn_pending_status(hdd_ctx, false); + } +} + +/** + * hdd_chan_change_notify() - Function to notify hostapd about channel change + * @hostapd_adapter hostapd adapter + * @dev: Net device structure + * @oper_chan: New operating channel + * + * This function is used to notify hostapd about the channel change + * + * Return: Success on intimating userspace + * + */ +CDF_STATUS hdd_chan_change_notify(hdd_adapter_t *hostapd_adapter, + struct net_device *dev, + uint8_t oper_chan) +{ + struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + eCsrPhyMode phy_mode; + ePhyChanBondState cb_mode; + uint32_t freq; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(hostapd_adapter); + + if (NULL == hal) { + hdd_err("hal is NULL"); + return CDF_STATUS_E_FAILURE; + } + + freq = cds_chan_to_freq(oper_chan); + + chan = __ieee80211_get_channel(hostapd_adapter->wdev.wiphy, freq); + + if (!chan) { + hdd_err("Invalid input frequency for channel conversion"); + return CDF_STATUS_E_FAILURE; + } + + phy_mode = sme_get_phy_mode(hal); + + if (oper_chan <= 14) + cb_mode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode24_g(hal)); + else + cb_mode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode5_g(hal)); + + switch (phy_mode) { + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + if (cb_mode == PHY_SINGLE_CHANNEL_CENTERED) + channel_type = NL80211_CHAN_HT20; + else if (cb_mode == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + channel_type = NL80211_CHAN_HT40MINUS; + else if (cb_mode == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + channel_type = NL80211_CHAN_HT40PLUS; + else + channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + + cfg80211_chandef_create(&chandef, chan, channel_type); + + cfg80211_ch_switch_notify(dev, &chandef); + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_send_radar_event() - Function to send radar events to user space + * @hdd_context: HDD context + * @event: Type of radar event + * @dfs_info: Structure containing DFS channel and country + * @wdev: Wireless device structure + * + * This function is used to send radar events such as CAC start, CAC + * end etc., to userspace + * + * Return: Success on sending notifying userspace + * + */ +CDF_STATUS hdd_send_radar_event(hdd_context_t *hdd_context, + eSapHddEvent event, + struct wlan_dfs_info dfs_info, + struct wireless_dev *wdev) +{ + + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index; + uint32_t freq, ret; + uint32_t data_size; + + if (!hdd_context) { + hddLog(LOGE, FL("HDD context is NULL")); + return CDF_STATUS_E_FAILURE; + } + + freq = cds_chan_to_freq(dfs_info.channel); + + switch (event) { + case eSAP_DFS_CAC_START: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_CAC_END: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_RADAR_DETECT: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX; + data_size = sizeof(uint32_t); + break; + default: + return CDF_STATUS_E_FAILURE; + } + + vendor_event = cfg80211_vendor_event_alloc(hdd_context->wiphy, + wdev, + data_size + NLMSG_HDRLEN, + index, + GFP_KERNEL); + if (!vendor_event) { + hddLog(LOGE, + FL("cfg80211_vendor_event_alloc failed for %d"), index); + return CDF_STATUS_E_FAILURE; + } + + ret = nla_put_u32(vendor_event, NL80211_ATTR_WIPHY_FREQ, freq); + + if (ret) { + hddLog(LOGE, FL("NL80211_ATTR_WIPHY_FREQ put fail")); + kfree_skb(vendor_event); + return CDF_STATUS_E_FAILURE; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *usrDataForCallback) +{ + hdd_adapter_t *pHostapdAdapter; + hdd_ap_ctx_t *pHddApCtx; + hdd_hostapd_state_t *pHostapdState; + struct net_device *dev; + eSapHddEvent sapEvent; + union iwreq_data wrqu; + uint8_t *we_custom_event_generic = NULL; + int we_event = 0; + int i = 0; + uint8_t staId; + CDF_STATUS cdf_status; + bool bWPSState; + bool bAuthRequired = true; + tpSap_AssocMacAddr pAssocStasArray = NULL; + char unknownSTAEvent[IW_CUSTOM_MAX + 1]; + char maxAssocExceededEvent[IW_CUSTOM_MAX + 1]; + uint8_t we_custom_start_event[64]; + char *startBssEvent; + hdd_context_t *pHddCtx; + hdd_scaninfo_t *pScanInfo = NULL; + struct iw_michaelmicfailure msg; + uint8_t ignoreCAC = 0; + struct hdd_config *cfg = NULL; + struct wlan_dfs_info dfs_info; + uint8_t cc_len = WLAN_SVC_COUNTRY_CODE_LEN; + hdd_adapter_t *con_sap_adapter; + CDF_STATUS status = CDF_STATUS_SUCCESS; +#if defined CONFIG_CNSS + int ret = 0; +#endif + + dev = (struct net_device *)usrDataForCallback; + if (!dev) { + hddLog(LOGE, FL("usrDataForCallback is null")); + return CDF_STATUS_E_FAILURE; + } + + pHostapdAdapter = netdev_priv(dev); + + if ((NULL == pHostapdAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic)) { + hddLog(LOGE, "invalid adapter or adapter has invalid magic"); + return CDF_STATUS_E_FAILURE; + } + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + + if (!pSapEvent) { + hddLog(LOGE, FL("pSapEvent is null")); + return CDF_STATUS_E_FAILURE; + } + + sapEvent = pSapEvent->sapHddEventCode; + memset(&wrqu, '\0', sizeof(wrqu)); + pHddCtx = (hdd_context_t *) (pHostapdAdapter->pHddCtx); + + if (!pHddCtx) { + hddLog(LOGE, FL("HDD context is null")); + return CDF_STATUS_E_FAILURE; + } + + cfg = pHddCtx->config; + + if (!cfg) { + hddLog(LOGE, FL("HDD config is null")); + return CDF_STATUS_E_FAILURE; + } + + dfs_info.channel = pHddApCtx->operatingChannel; + sme_get_country_code(pHddCtx->hHal, dfs_info.country_code, &cc_len); + + switch (sapEvent) { + case eSAP_START_BSS_EVENT: + hddLog(LOG1, + FL("BSS status = %s, channel = %u, bc sta Id = %d"), + pSapEvent->sapevt.sapStartBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS", + pSapEvent->sapevt.sapStartBssCompleteEvent. + operatingChannel, + pSapEvent->sapevt.sapStartBssCompleteEvent.staId); + + pHostapdAdapter->sessionId = + pSapEvent->sapevt.sapStartBssCompleteEvent.sessionId; + + pHostapdState->cdf_status = + pSapEvent->sapevt.sapStartBssCompleteEvent.status; + cdf_status = cdf_event_set(&pHostapdState->cdf_event); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status) + || pHostapdState->cdf_status) { + hddLog(LOGE, ("ERROR: startbss event failed!!")); + goto stopbss; + } else { + sme_ch_avoid_update_req(pHddCtx->hHal); + + pHddApCtx->uBCStaId = + pSapEvent->sapevt.sapStartBssCompleteEvent.staId; + + hdd_register_tx_flow_control(pHostapdAdapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb); + + /* @@@ need wep logic here to set privacy bit */ + cdf_status = + hdd_softap_register_bc_sta(pHostapdAdapter, + pHddApCtx->uPrivacy); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGW, FL("Failed to register BC STA %d"), + cdf_status); + hdd_stop_bss_link(pHostapdAdapter, + usrDataForCallback); + } + } + + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pHddApCtx->uBCStaId, + WLAN_AP_CONNECT, + pHostapdAdapter->dev->dev_addr); + if (status) { + hddLog(LOGE, + ("WLAN_AP_CONNECT event failed!!")); + goto stopbss; + } + } + + if (0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff) { + /* AP Inactivity timer init and start */ + cdf_status = + cdf_mc_timer_init(&pHddApCtx-> + hdd_ap_inactivity_timer, + CDF_TIMER_TYPE_SW, + hdd_hostapd_inactivity_timer_cb, + dev); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, + FL("Failed to init inactivity timer")); + + cdf_status = + cdf_mc_timer_start(&pHddApCtx-> + hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX + (pHostapdAdapter))->config-> + nAPAutoShutOff * 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, + FL("Failed to init inactivity timer")); + + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + pHddApCtx->operatingChannel = + pSapEvent->sapevt.sapStartBssCompleteEvent.operatingChannel; + + hdd_hostapd_channel_prevent_suspend(pHostapdAdapter, + pHddApCtx-> + operatingChannel); + + pHostapdState->bssState = BSS_START; + hdd_wlan_green_ap_start_bss(pHddCtx); + + /* Set group key / WEP key every time when BSS is restarted */ + if (pHddApCtx->groupKey.keyLength) { + status = wlansap_set_key_sta( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + (WLAN_HDD_GET_CTX + (pHostapdAdapter))-> + pcds_context, +#endif + &pHddApCtx->groupKey); + if (!CDF_IS_STATUS_SUCCESS(status)) + hddLog(LOGE, FL("wlansap_set_key_sta failed")); + } else { + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (!pHddApCtx->wepKey[i].keyLength) + continue; + + status = wlansap_set_key_sta( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + (WLAN_HDD_GET_CTX(pHostapdAdapter))-> + pcds_context, +#endif + &pHddApCtx-> + wepKey[i]); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("set_key failed idx %d"), i); + } + } + } + + pHddCtx->dfs_radar_found = false; + wlansap_get_dfs_ignore_cac(pHddCtx->hHal, &ignoreCAC); + + /* DFS requirement: DO NOT transmit during CAC. */ + if ((CHANNEL_STATE_DFS != + cds_get_channel_state(pHddApCtx->operatingChannel)) + || ignoreCAC + || pHddCtx->dev_dfs_cac_status == DFS_CAC_ALREADY_DONE) + pHddApCtx->dfs_cac_block_tx = false; + else + pHddApCtx->dfs_cac_block_tx = true; + + hddLog(LOG3, "The value of dfs_cac_block_tx[%d] for ApCtx[%p]", + pHddApCtx->dfs_cac_block_tx, pHddApCtx); + + if ((CHANNEL_STATE_DFS == + cds_get_channel_state(pHddApCtx->operatingChannel)) + && (pHddCtx->config->IsSapDfsChSifsBurstEnabled == 0)) { + + hddLog(LOG1, + FL("Set SIFS Burst disable for DFS channel %d"), + pHddApCtx->operatingChannel); + + if (wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + 0, PDEV_CMD)) { + hddLog(LOGE, + FL("Failed to Set SIFS Burst %d"), + pHddApCtx->operatingChannel); + } + } + /* Fill the params for sending IWEVCUSTOM Event with SOFTAP.enabled */ + startBssEvent = "SOFTAP.enabled"; + memset(&we_custom_start_event, '\0', + sizeof(we_custom_start_event)); + memcpy(&we_custom_start_event, startBssEvent, + strlen(startBssEvent)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(startBssEvent); + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_start_event; + cds_dump_concurrency_info(pHddCtx); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + break; /* Event will be sent after Switch-Case stmt */ + + case eSAP_STOP_BSS_EVENT: + hddLog(LOG1, FL("BSS stop status = %s"), + pSapEvent->sapevt.sapStopBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + hdd_hostapd_channel_allow_suspend(pHostapdAdapter, + pHddApCtx->operatingChannel); + + hdd_wlan_green_ap_stop_bss(pHddCtx); + + /* Free up Channel List incase if it is set */ +#ifdef WLAN_FEATURE_MBSSID + sap_cleanup_channel_list(WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter)); +#else + sap_cleanup_channel_list(); +#endif + /* Invalidate the channel info. */ + pHddApCtx->operatingChannel = 0; + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pHddApCtx->uBCStaId, + WLAN_AP_DISCONNECT, + pHostapdAdapter->dev->dev_addr); + if (status) { + hddLog(LOGE, + ("WLAN_AP_DISCONNECT event failed!!")); + goto stopbss; + } + } + + /* reset the dfs_cac_status and dfs_cac_block_tx flag only when + * the last BSS is stopped + */ + con_sap_adapter = hdd_get_con_sap_adapter(pHostapdAdapter, true); + if (!con_sap_adapter) { + pHddApCtx->dfs_cac_block_tx = true; + pHddCtx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + } + if (pHddCtx->config->conc_custom_rule2 && + (WLAN_HDD_P2P_GO == pHostapdAdapter->device_mode)) { + hdd_adapter_t *sta_adapter = hdd_get_adapter(pHddCtx, + WLAN_HDD_INFRA_STATION); + hddLog(LOG2, + FL("P2PGO is going down now")); + hdd_issue_stored_joinreq(sta_adapter, pHddCtx); + } + goto stopbss; + + case eSAP_DFS_CAC_START: + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_DFS_CAC_START_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddCtx->dev_dfs_cac_status = DFS_CAC_IN_PROGRESS; + if (CDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_START, + dfs_info, &pHostapdAdapter->wdev)) { + hddLog(LOGE, FL("Unable to indicate CAC start NL event")); + } else { + hdd_info("Sent CAC start to user space"); + } + break; + case eSAP_DFS_CAC_INTERRUPTED: + /* + * The CAC timer did not run completely and a radar was detected + * during the CAC time. This new state will keep the tx path + * blocked since we do not want any transmission on the DFS + * channel. CAC end will only be reported here since the user + * space applications are waiting on CAC end for their state + * management. + */ + if (CDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_END, + dfs_info, &pHostapdAdapter->wdev)) { + hdd_err("Unable to indicate CAC end (interrupted) event"); + } else { + hdd_info("Sent CAC end (interrupted) to user space"); + } + break; + case eSAP_DFS_CAC_END: + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_DFS_CAC_END_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddApCtx->dfs_cac_block_tx = false; + pHddCtx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + if (CDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_END, + dfs_info, &pHostapdAdapter->wdev)) { + hddLog(LOGE, FL("Unable to indicate CAC end NL event")); + } else { + hdd_info("Sent CAC end to user space"); + } + break; + + case eSAP_DFS_RADAR_DETECT: + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_DFS_RADAR_DETECT_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddCtx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + if (CDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_RADAR_DETECT, + dfs_info, &pHostapdAdapter->wdev)) { + hddLog(LOGE, FL("Unable to indicate Radar detect NL event")); + } else { + hdd_info("Sent radar detected to user space"); + } + break; + + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + wlan_hdd_send_svc_nlink_msg + (WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND, &dfs_info, + sizeof(struct wlan_dfs_info)); + break; + + case eSAP_STA_SET_KEY_EVENT: + /* TODO: + * forward the message to hostapd once implementation + * is done for now just print + */ + hddLog(LOG1, FL("SET Key: configured status = %s"), + pSapEvent->sapevt.sapStationSetKeyCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + return CDF_STATUS_SUCCESS; + case eSAP_STA_MIC_FAILURE_EVENT: + { + memset(&msg, '\0', sizeof(msg)); + msg.src_addr.sa_family = ARPHRD_ETHER; + memcpy(msg.src_addr.sa_data, + &pSapEvent->sapevt.sapStationMICFailureEvent. + staMac, CDF_MAC_ADDR_SIZE); + hddLog(LOG1, "MIC MAC " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg.src_addr.sa_data)); + if (pSapEvent->sapevt.sapStationMICFailureEvent. + multicast == eSAP_TRUE) + msg.flags = IW_MICFAILURE_GROUP; + else + msg.flags = IW_MICFAILURE_PAIRWISE; + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(msg); + we_event = IWEVMICHAELMICFAILURE; + we_custom_event_generic = (uint8_t *) &msg; + } + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(dev, + pSapEvent-> + sapevt.sapStationMICFailureEvent. + staMac.bytes, + ((pSapEvent->sapevt. + sapStationMICFailureEvent. + multicast == + eSAP_TRUE) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + pSapEvent->sapevt. + sapStationMICFailureEvent.keyId, + pSapEvent->sapevt. + sapStationMICFailureEvent.TSC, + GFP_KERNEL); + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + wrqu.addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.addr.sa_data, + &pSapEvent->sapevt.sapStationAssocReassocCompleteEvent. + staMac, CDF_MAC_ADDR_SIZE); + hddLog(LOG1, " associated " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + we_event = IWEVREGISTERED; + +#ifdef WLAN_FEATURE_MBSSID + wlansap_get_wps_state(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + &bWPSState); +#else + wlansap_get_wps_state((WLAN_HDD_GET_CTX(pHostapdAdapter))-> + pcds_context, &bWPSState); +#endif + + if ((eCSR_ENCRYPT_TYPE_NONE == pHddApCtx->ucEncryptType) || + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + pHddApCtx->ucEncryptType) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + pHddApCtx->ucEncryptType)) { + bAuthRequired = false; + } + + if (bAuthRequired || bWPSState == true) { + cdf_status = hdd_softap_register_sta( + pHostapdAdapter, + true, + pHddApCtx->uPrivacy, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, 0, 0, + (struct cdf_mac_addr *) + wrqu.addr.sa_data, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + wmmEnabled); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGW, + FL("Failed to register STA %d " + MAC_ADDRESS_STR ""), cdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } else { + cdf_status = hdd_softap_register_sta( + pHostapdAdapter, + false, + pHddApCtx->uPrivacy, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, 0, 0, + (struct cdf_mac_addr *) + wrqu.addr.sa_data, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + wmmEnabled); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGW, + FL("Failed to register STA %d " + MAC_ADDRESS_STR ""), cdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } + + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, WLAN_CLIENT_CONNECT_EX, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac.bytes); + if (status) { + hddLog(LOGE, + FL("WLAN_CLIENT_CONNECT_EX event failed")); + goto stopbss; + } + } + +#ifdef QCA_PKT_PROTO_TRACE + /* Peer associated, update into trace buffer */ + if (pHddCtx->config->gEnableDebugLog) { + cds_pkt_trace_buf_update("HA:ASSOC"); + } +#endif /* QCA_PKT_PROTO_TRACE */ + +#ifdef MSM_PLATFORM + /* start timer in sap/p2p_go */ + if (pHddApCtx->bApActive == false) { + spin_lock_bh(&pHddCtx->bus_bw_lock); + pHostapdAdapter->prev_tx_packets = + pHostapdAdapter->stats.tx_packets; + pHostapdAdapter->prev_rx_packets = + pHostapdAdapter->stats.rx_packets; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_start_bus_bw_compute_timer(pHostapdAdapter); + } +#endif + pHddApCtx->bApActive = true; + /* Stop AP inactivity timer */ + if (pHddApCtx->hdd_ap_inactivity_timer.state == + CDF_TIMER_STATE_RUNNING) { + cdf_status = + cdf_mc_timer_stop(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, + FL("Failed to start inactivity timer")); + } + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, false); +#endif + cdf_wake_lock_timeout_acquire(&pHddCtx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SAP); + { + struct station_info staInfo; + uint16_t iesLen = + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent.iesLen; + + memset(&staInfo, 0, sizeof(staInfo)); + if (iesLen <= MAX_ASSOC_IND_IE_LEN) { + staInfo.assoc_req_ies = + (const u8 *)&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent.ies[0]; + staInfo.assoc_req_ies_len = iesLen; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 31)) + staInfo.filled |= STATION_INFO_ASSOC_REQ_IES; +#endif + cfg80211_new_sta(dev, + (const u8 *)&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac.bytes[0], &staInfo, + GFP_KERNEL); + } else { + hddLog(LOGE, + FL("Assoc Ie length is too long")); + } + } + + pScanInfo = &pHostapdAdapter->scan_info; + /* Lets do abort scan to ensure smooth authentication for client */ + if ((pScanInfo != NULL) && pScanInfo->mScanPending) { + hdd_abort_mac_scan(pHddCtx, pHostapdAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + } + if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac, ePeerConnected, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + timingMeasCap, + pHostapdAdapter-> + sessionId, + &pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + chan_info); + } + hdd_wlan_green_ap_add_sta(pHddCtx); + break; + + case eSAP_STA_DISASSOC_EVENT: + memcpy(wrqu.addr.sa_data, + &pSapEvent->sapevt.sapStationDisassocCompleteEvent. + staMac, CDF_MAC_ADDR_SIZE); + hddLog(LOG1, " disassociated " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + + cdf_status = cdf_event_set(&pHostapdState->cdf_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, "ERR: Station Deauth event Set failed"); + + if (pSapEvent->sapevt.sapStationDisassocCompleteEvent.reason == + eSAP_USR_INITATED_DISASSOC) + hddLog(LOG1, " User initiated disassociation"); + else + hddLog(LOG1, " MAC initiated disassociation"); + we_event = IWEVEXPIRED; + cdf_status = + hdd_softap_get_sta_id(pHostapdAdapter, + &pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac, + &staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("ERROR: HDD Failed to find sta id!!")); + return CDF_STATUS_E_FAILURE; + } +#ifdef IPA_OFFLOAD + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, staId, + WLAN_CLIENT_DISCONNECT, + pSapEvent->sapevt. + sapStationDisassocCompleteEvent. + staMac.bytes); + + if (status) { + hddLog(LOGE, + ("ERROR: WLAN_CLIENT_DISCONNECT event failed!!")); + goto stopbss; + } + } +#endif +#ifdef QCA_PKT_PROTO_TRACE + /* Peer dis-associated, update into trace buffer */ + if (pHddCtx->config->gEnableDebugLog) { + cds_pkt_trace_buf_update("HA:DISASC"); + } +#endif /* QCA_PKT_PROTO_TRACE */ + hdd_softap_deregister_sta(pHostapdAdapter, staId); + + pHddApCtx->bApActive = false; + spin_lock_bh(&pHostapdAdapter->staInfo_lock); + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (pHostapdAdapter->aStaInfo[i].isUsed + && i != + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + uBCStaId) { + pHddApCtx->bApActive = true; + break; + } + } + spin_unlock_bh(&pHostapdAdapter->staInfo_lock); + + /* Start AP inactivity timer if no stations associated with it */ + if ((0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff)) { + if (pHddApCtx->bApActive == false) { + if (pHddApCtx->hdd_ap_inactivity_timer.state == + CDF_TIMER_STATE_STOPPED) { + cdf_status = + cdf_mc_timer_start(&pHddApCtx-> + hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX + (pHostapdAdapter))-> + config-> + nAPAutoShutOff * + 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, + FL("Failed to init AP inactivity timer")); + } else + CDF_ASSERT + (cdf_mc_timer_get_current_state + (&pHddApCtx-> + hdd_ap_inactivity_timer) == + CDF_TIMER_STATE_STOPPED); + } + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + cfg80211_del_sta(dev, + (const u8 *)&pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac. + bytes[0], GFP_KERNEL); + + /* Update the beacon Interval if it is P2P GO */ + cdf_status = cds_change_mcc_go_beacon_interval(pHostapdAdapter); + if (CDF_STATUS_SUCCESS != cdf_status) { + hddLog(LOGE, FL("failed to update Beacon interval %d"), + cdf_status); + } + if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. + sapStationDisassocCompleteEvent. + staMac, ePeerDisconnected, + 0, + pHostapdAdapter-> + sessionId, NULL); + } +#ifdef MSM_PLATFORM + /*stop timer in sap/p2p_go */ + if (pHddApCtx->bApActive == false) { + spin_lock_bh(&pHddCtx->bus_bw_lock); + pHostapdAdapter->prev_tx_packets = 0; + pHostapdAdapter->prev_rx_packets = 0; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_stop_bus_bw_compute_timer(pHostapdAdapter); + } +#endif + hdd_wlan_green_ap_del_sta(pHddCtx); + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + { + static const char *message = + "MLMEWPSPBCPROBEREQ.indication"; + union iwreq_data wreq; + + down(&pHddApCtx->semWpsPBCOverlapInd); + pHddApCtx->WPSPBCProbeReq.probeReqIELen = + pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.probeReqIELen; + + cdf_mem_copy(pHddApCtx->WPSPBCProbeReq.probeReqIE, + pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.probeReqIE, + pHddApCtx->WPSPBCProbeReq.probeReqIELen); + + cdf_mem_copy(pHddApCtx->WPSPBCProbeReq.peerMacAddr, + pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.peerMacAddr, + CDF_MAC_ADDR_SIZE); + hddLog(LOG1, "WPS PBC probe req " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHddApCtx->WPSPBCProbeReq. + peerMacAddr)); + memset(&wreq, 0, sizeof(wreq)); + wreq.data.length = strlen(message); /* This is length of message */ + wireless_send_event(dev, IWEVCUSTOM, &wreq, + (char *)message); + + return CDF_STATUS_SUCCESS; + } + case eSAP_ASSOC_STA_CALLBACK_EVENT: + pAssocStasArray = + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas; + if (pSapEvent->sapevt.sapAssocStaListEvent.noOfAssocSta != 0) { /* List of associated stations */ + for (i = 0; + i < + pSapEvent->sapevt.sapAssocStaListEvent. + noOfAssocSta; i++) { + hddLog(LOG1, + "Associated Sta Num %d:assocId=%d, staId=%d, staMac=" + MAC_ADDRESS_STR, i + 1, + pAssocStasArray->assocId, + pAssocStasArray->staId, + MAC_ADDR_ARRAY(pAssocStasArray->staMac. + bytes)); + pAssocStasArray++; + } + } + cdf_mem_free(pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas); /* Release caller allocated memory here */ + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas = NULL; + return CDF_STATUS_SUCCESS; + case eSAP_INDICATE_MGMT_FRAME: + hdd_indicate_mgmt_frame(pHostapdAdapter, + pSapEvent->sapevt.sapManagementFrameInfo. + nFrameLength, + pSapEvent->sapevt.sapManagementFrameInfo. + pbFrames, + pSapEvent->sapevt.sapManagementFrameInfo. + frameType, + pSapEvent->sapevt.sapManagementFrameInfo. + rxChan, 0); + return CDF_STATUS_SUCCESS; + case eSAP_REMAIN_CHAN_READY: + hdd_remain_chan_ready_handler(pHostapdAdapter, + pSapEvent->sapevt.sap_roc_ind.scan_id); + return CDF_STATUS_SUCCESS; + case eSAP_SEND_ACTION_CNF: + hdd_send_action_cnf(pHostapdAdapter, + (eSAP_STATUS_SUCCESS == + pSapEvent->sapevt.sapActionCnf. + actionSendSuccess) ? true : false); + return CDF_STATUS_SUCCESS; + case eSAP_UNKNOWN_STA_JOIN: + snprintf(unknownSTAEvent, IW_CUSTOM_MAX, + "JOIN_UNKNOWN_STA-%02x:%02x:%02x:%02x:%02x:%02x", + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[0], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[1], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[2], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[3], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[4], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[5]); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = unknownSTAEvent; + wrqu.data.length = strlen(unknownSTAEvent); + we_custom_event_generic = (uint8_t *) unknownSTAEvent; + hddLog(LOGE, "%s", unknownSTAEvent); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + snprintf(maxAssocExceededEvent, IW_CUSTOM_MAX, + "Peer %02x:%02x:%02x:%02x:%02x:%02x denied" + " assoc due to Maximum Mobile Hotspot connections reached. Please disconnect" + " one or more devices to enable the new device connection", + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[0], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[1], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[2], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[3], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[4], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr. + bytes[5]); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = maxAssocExceededEvent; + wrqu.data.length = strlen(maxAssocExceededEvent); + we_custom_event_generic = (uint8_t *) maxAssocExceededEvent; + hddLog(LOG1, "%s", maxAssocExceededEvent); + break; + case eSAP_STA_ASSOC_IND: + return CDF_STATUS_SUCCESS; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + hddLog(LOG1, FL(" Disconnecting all the P2P Clients....")); + hdd_clear_all_sta(pHostapdAdapter, usrDataForCallback); + return CDF_STATUS_SUCCESS; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + cdf_status = + hdd_stop_bss_link(pHostapdAdapter, usrDataForCallback); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGW, FL("hdd_stop_bss_link failed %d"), + cdf_status); + } + return CDF_STATUS_SUCCESS; + + case eSAP_CHANNEL_CHANGE_EVENT: + hddLog(LOG1, FL("Received eSAP_CHANNEL_CHANGE_EVENT event")); + /* Prevent suspend for new channel */ + hdd_hostapd_channel_prevent_suspend(pHostapdAdapter, + pSapEvent->sapevt.sap_ch_selected.pri_ch); + /* Allow suspend for old channel */ + hdd_hostapd_channel_allow_suspend(pHostapdAdapter, + pHddApCtx->operatingChannel); + /* SME/PE is already updated for new operation channel. So update + * HDD layer also here. This resolves issue in AP-AP mode where + * AP1 channel is changed due to RADAR then CAC is going on and + * START_BSS on new channel has not come to HDD. At this case if + * AP2 is start it needs current operation channel for MCC DFS + * restiction + */ + pHddApCtx->operatingChannel = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + pHddApCtx->sapConfig.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + + /* Indicate operating channel change to hostapd + * only for non driver override acs + */ + if (pHostapdAdapter->device_mode == WLAN_HDD_SOFTAP && + pHddCtx->config->force_sap_acs) + return CDF_STATUS_SUCCESS; + else + return hdd_chan_change_notify(pHostapdAdapter, dev, + pSapEvent->sapevt.sap_ch_selected.pri_ch); + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + case eSAP_ACS_SCAN_SUCCESS_EVENT: + pHddCtx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN; + hddLog(LOG1, FL("Reusing Last ACS scan result for %d sec"), + ACS_SCAN_EXPIRY_TIMEOUT_S); + cdf_mc_timer_stop(&pHddCtx->skip_acs_scan_timer); + cdf_status = cdf_mc_timer_start(&pHddCtx->skip_acs_scan_timer, + ACS_SCAN_EXPIRY_TIMEOUT_S * + 1000); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, + FL("Failed to start ACS scan expiry timer")); + return CDF_STATUS_SUCCESS; +#endif + + case eSAP_DFS_NOL_GET: + hddLog(LOG1, + FL("Received eSAP_DFS_NOL_GET event")); +#if defined CONFIG_CNSS + /* get the dfs nol from cnss */ + ret = + cnss_wlan_get_dfs_nol(pSapEvent->sapevt.sapDfsNolInfo. + pDfsList, + pSapEvent->sapevt.sapDfsNolInfo. + sDfsList); + + if (ret > 0) { + hddLog(LOG2, + FL("Get %d bytes of dfs nol from cnss"), ret); + return CDF_STATUS_SUCCESS; + } else { + hddLog(LOG2, + FL("No dfs nol entry in CNSS, ret: %d"), ret); + return CDF_STATUS_E_FAULT; + } +#else + return CDF_STATUS_E_FAILURE; +#endif + case eSAP_DFS_NOL_SET: + hddLog(LOG1, FL("Received eSAP_DFS_NOL_SET event")); +#if defined CONFIG_CNSS + /* set the dfs nol to cnss */ + ret = + cnss_wlan_set_dfs_nol(pSapEvent->sapevt.sapDfsNolInfo. + pDfsList, + pSapEvent->sapevt.sapDfsNolInfo. + sDfsList); + + if (ret) { + hddLog(LOG2, + FL("Failed to set dfs nol - ret: %d"), + ret); + } else { + hddLog(LOG2, FL(" Set %d bytes dfs nol to cnss"), + pSapEvent->sapevt.sapDfsNolInfo.sDfsList); + } +#else + return CDF_STATUS_E_FAILURE; +#endif + return CDF_STATUS_SUCCESS; + case eSAP_ACS_CHANNEL_SELECTED: + hddLog(LOG1, FL("ACS Completed for wlan%d"), + pHostapdAdapter->dev->ifindex); + clear_bit(ACS_PENDING, &pHostapdAdapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags); + pHddApCtx->sapConfig.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + pHddApCtx->sapConfig.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + /* send vendor event to hostapd only for hostapd based acs*/ + if (!pHddCtx->config->force_sap_acs) + wlan_hdd_cfg80211_acs_ch_select_evt(pHostapdAdapter); + return CDF_STATUS_SUCCESS; + default: + hddLog(LOG1, "SAP message is not handled"); + goto stopbss; + return CDF_STATUS_SUCCESS; + } + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + return CDF_STATUS_SUCCESS; + +stopbss: + { + uint8_t we_custom_event[64]; + char *stopBssEvent = "STOP-BSS.response"; /* 17 */ + int event_len = strlen(stopBssEvent); + + hddLog(LOG1, FL("BSS stop status = %s"), + pSapEvent->sapevt.sapStopBssCompleteEvent.status ? + "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + /* Change the BSS state now since, as we are shutting things down, + * we don't want interfaces to become re-enabled */ + pHostapdState->bssState = BSS_STOP; + + if (0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff) { + if (CDF_TIMER_STATE_RUNNING == + pHddApCtx->hdd_ap_inactivity_timer.state) { + cdf_status = + cdf_mc_timer_stop(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, + FL("Failed to stop AP inactivity timer")); + } + } + + cdf_status = + cdf_mc_timer_destroy(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, FL("Failed to Destroy AP inactivity timer")); + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + /* Stop the pkts from n/w stack as we are going to free all of + * the TX WMM queues for all STAID's */ + hdd_hostapd_stop(dev); + + /* reclaim all resources allocated to the BSS */ + cdf_status = hdd_softap_stop_bss(pHostapdAdapter); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGW, + FL("hdd_softap_stop_bss failed %d"), + cdf_status); + } + + /* once the event is set, structure dev/pHostapdAdapter should + * not be touched since they are now subject to being deleted + * by another thread */ + if (eSAP_STOP_BSS_EVENT == sapEvent) + cdf_event_set(&pHostapdState->cdf_stop_bss_event); + + /* notify userspace that the BSS has stopped */ + memset(&we_custom_event, '\0', sizeof(we_custom_event)); + memcpy(&we_custom_event, stopBssEvent, event_len); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = event_len; + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_event; + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + cds_dump_concurrency_info(pHddCtx); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + } + return CDF_STATUS_SUCCESS; +} + +int hdd_softap_unpack_ie(tHalHandle halHandle, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, + bool *pMFPCapable, + bool *pMFPRequired, + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + tDot11fIERSN dot11RSNIE; + tDot11fIEWPA dot11WPAIE; + + uint8_t *pRsnIe; + uint16_t RSNIeLen; + + if (NULL == halHandle) { + hddLog(LOGE, FL("Error haHandle returned NULL")); + return -EINVAL; + } + /* Validity checks */ + if ((gen_ie_len < CDF_MIN(DOT11F_IE_RSN_MIN_LEN, DOT11F_IE_WPA_MIN_LEN)) + || (gen_ie_len > + CDF_MAX(DOT11F_IE_RSN_MAX_LEN, DOT11F_IE_WPA_MAX_LEN))) + return -EINVAL; + /* Type check */ + if (gen_ie[0] == DOT11F_EID_RSN) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) || + (gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) { + return CDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + dot11f_unpack_ie_rsn((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11RSNIE); + /* Copy out the encryption and authentication types */ + hddLog(LOG1, FL("pairwise cipher suite count: %d"), + dot11RSNIE.pwise_cipher_suite_count); + hddLog(LOG1, FL("authentication suite count: %d"), + dot11RSNIE.akm_suite_count); + /*Here we have followed the apple base code, + but probably I suspect we can do something different */ + /* dot11RSNIE.akm_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type(dot11RSNIE.akm_suites[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + gp_cipher_suite); + /* Set the PMKSA ID Cache for this interface */ + *pMFPCapable = 0 != (dot11RSNIE.RSN_Cap[0] & 0x80); + *pMFPRequired = 0 != (dot11RSNIE.RSN_Cap[0] & 0x40); + /* Calling csr_roam_set_pmkid_cache to configure the PMKIDs into the cache */ + } else if (gen_ie[0] == DOT11F_EID_WPA) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) { + return CDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte - and four byte WiFi OUI */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11WPAIE); + /* Copy out the encryption and authentication types */ + hddLog(LOG1, FL("WPA unicast cipher suite count: %d"), + dot11WPAIE.unicast_cipher_count); + hddLog(LOG1, FL("WPA authentication suite count: %d"), + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type(dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + multicast_cipher); + *pMFPCapable = false; + *pMFPRequired = false; + } else { + hddLog(LOGW, FL("gen_ie[0]: %d"), gen_ie[0]); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_set_channel_change() - + * This function to support SAP channel change with CSA IE + * set in the beacons. + * + * @dev: pointer to the net device. + * @target_channel: target channel number. + * + * Return: 0 for success, non zero for failure + */ +static +int hdd_softap_set_channel_change(struct net_device *dev, int target_channel) +{ + CDF_STATUS status; + int ret = 0; + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *pHddCtx = NULL; + +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = + (WLAN_HDD_GET_CTX(pHostapdAdapter))->pcds_context; +#endif + + pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) { + hddLog(LOGE, FL("invalid HDD context")); + ret = -EBUSY; + return ret; + } + + if (pHddCtx->dfs_radar_found == true) { + hddLog(LOGE, FL("Channel switch in progress!!")); + return -EBUSY; + } + /* + * Set the dfs_radar_found flag to mimic channel change + * when a radar is found. This will enable synchronizing + * SAP and HDD states similar to that of radar indication. + * Suspend the netif queues to stop queuing Tx frames + * from upper layers. netif queues will be resumed + * once the channel change is completed and SAP will + * post eSAP_START_BSS_EVENT success event to HDD. + */ + pHddCtx->dfs_radar_found = true; + + /* + * Post the Channel Change request to SAP. + */ + status = wlansap_set_channel_change_with_csa( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + p_cds_context, +#endif + (uint32_t) + target_channel); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, + FL("SAP set channel failed for channel = %d"), + target_channel); + /* + * If channel change command fails then clear the + * radar found flag and also restart the netif + * queues. + */ + + pHddCtx->dfs_radar_found = false; + + ret = -EINVAL; + } + + return ret; +} + +int +static __iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + CDF_STATUS vstatus; + int ret = 0; /* success */ + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *pHddCtx; + + if (pAdapter == NULL) { + hddLog(LOGE, FL("pAdapter is NULL!")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret != 0) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + hddLog(LOG1, FL("Received data %s"), extra); + + vstatus = hdd_execute_global_config_command(pHddCtx, extra); + if (CDF_STATUS_SUCCESS != vstatus) { + ret = -EINVAL; + } + + return ret; +} + +int +static iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + int ret = 0; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret != 0) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + hddLog(LOG1, FL("Printing CLD global INI Config")); + hdd_cfg_get_global_config(pHddCtx, extra, QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +int +static iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret = 0; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret != 0) { + hddLog(LOGE, FL("HDD context is not valid!")); + goto out; + } + + switch (sub_cmd) { +#ifdef DEBUG + case QCSAP_IOCTL_SET_FW_CRASH_INJECT: + hddLog(LOGE, "WE_SET_FW_CRASH_INJECT: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(pAdapter->sessionId, + GEN_PARAM_CRASH_INJECT, + value[1], value[2], + GEN_CMD); + break; +#endif + case QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL: + hdd_info("WE_DUMP_DP_TRACE: %d %d", + value[1], value[2]); + if (value[1] == DUMP_DP_TRACE) + cdf_dp_trace_dump_all(value[2]); + break; + default: + hddLog(LOGE, FL("Invalid IOCTL command %d"), sub_cmd); + break; + } + +out: + return ret; +} + +static int iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static void print_mac_list(struct cdf_mac_addr *macList, uint8_t size) +{ + int i; + uint8_t *macArray; + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + pr_info("** ACL entry %i - %02x:%02x:%02x:%02x:%02x:%02x \n", + i, MAC_ADDR_ARRAY(macArray)); + } + return; +} + +static CDF_STATUS hdd_print_acl(hdd_adapter_t *pHostapdAdapter) +{ + eSapMacAddrACL acl_mode; + struct cdf_mac_addr MacList[MAX_ACL_MAC_ADDRESS]; + uint8_t listnum; + void *p_cds_gctx = NULL; + +#ifdef WLAN_FEATURE_MBSSID + p_cds_gctx = WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter); +#else + p_cds_gctx = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pcds_context; +#endif + cdf_mem_zero(&MacList[0], sizeof(MacList)); + if (CDF_STATUS_SUCCESS == wlansap_get_acl_mode(p_cds_gctx, &acl_mode)) { + pr_info("******** ACL MODE *********\n"); + switch (acl_mode) { + case eSAP_ACCEPT_UNLESS_DENIED: + pr_info("ACL Mode = ACCEPT_UNLESS_DENIED\n"); + break; + case eSAP_DENY_UNLESS_ACCEPTED: + pr_info("ACL Mode = DENY_UNLESS_ACCEPTED\n"); + break; + case eSAP_SUPPORT_ACCEPT_AND_DENY: + pr_info("ACL Mode = ACCEPT_AND_DENY\n"); + break; + case eSAP_ALLOW_ALL: + pr_info("ACL Mode = ALLOW_ALL\n"); + break; + default: + pr_info("Invalid SAP ACL Mode = %d\n", acl_mode); + return CDF_STATUS_E_FAILURE; + } + } else { + return CDF_STATUS_E_FAILURE; + } + + if (CDF_STATUS_SUCCESS == wlansap_get_acl_accept_list(p_cds_gctx, + &MacList[0], + &listnum)) { + pr_info("******* WHITE LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&MacList[0], listnum); + } else { + return CDF_STATUS_E_FAILURE; + } + + if (CDF_STATUS_SUCCESS == wlansap_get_acl_deny_list(p_cds_gctx, + &MacList[0], + &listnum)) { + pr_info("******* BLACK LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&MacList[0], listnum); + } else { + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +int +static __iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + CDF_STATUS status; + int ret = 0; /* success */ + v_CONTEXT_t p_cds_context; + hdd_context_t *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid ret:%d"), ret); + return -EINVAL; + } + + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (!hHal) { + hddLog(LOGE, FL("Hal ctx is null")); + return -EINVAL; + } + + p_cds_context = hdd_ctx->pcds_context; + if (!p_cds_context) { + hddLog(LOGE, FL("cds ctx is null")); + return -ENOENT; + } + + switch (sub_cmd) { + case QCASAP_SET_RADAR_DBG: + hddLog(LOG1, FL("QCASAP_SET_RADAR_DBG called with: value: %d"), + set_value); + wlan_sap_enable_phy_error_logs(hHal, (bool) set_value); + break; + + case QCSAP_PARAM_CLR_ACL: + if (CDF_STATUS_SUCCESS != wlansap_clear_acl( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter) +#else + p_cds_context +#endif + )) { + ret = -EIO; + } + break; + + case QCSAP_PARAM_ACL_MODE: + if ((eSAP_ALLOW_ALL < (eSapMacAddrACL) set_value) || + (eSAP_ACCEPT_UNLESS_DENIED > (eSapMacAddrACL) set_value)) { + hddLog(LOGE, FL("Invalid ACL Mode value %d"), + set_value); + ret = -EINVAL; + } else { +#ifdef WLAN_FEATURE_MBSSID + wlansap_set_mode(WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), set_value); +#else + wlansap_set_mode(p_cds_context, set_value); +#endif + + } + break; + + case QCSAP_PARAM_SET_CHANNEL_CHANGE: + if (WLAN_HDD_SOFTAP == pHostapdAdapter->device_mode) { + hddLog(LOG1, + "SET SAP Channel Change to new channel= %d", + set_value); + ret = hdd_softap_set_channel_change(dev, set_value); + } else { + hddLog(LOGE, + FL("Channel Change Failed, Device in test mode")); + ret = -EINVAL; + } + break; + case QCSAP_PARAM_AUTO_CHANNEL: + if (set_value == 0 || set_value == 1) + (WLAN_HDD_GET_CTX( + pHostapdAdapter))->config->force_sap_acs = + set_value; + else + ret = -EINVAL; + break; + + case QCSAP_PARAM_MAX_ASSOC: + if (WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) { + hddLog(LOGE, FL("Invalid setMaxAssoc value %d"), + set_value); + ret = -EINVAL; + } else { + if (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value) { + hddLog(LOGW, + FL("setMaxAssoc %d > max allowed %d."), + set_value, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX); + hddLog(LOGW, + FL("Setting it to max allowed and continuing")); + set_value = WNI_CFG_ASSOC_STA_LIMIT_STAMAX; + } + status = sme_cfg_set_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + set_value); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, + FL("setMaxAssoc failure, status %d"), + status); + ret = -EIO; + } + } + break; + + case QCSAP_PARAM_HIDE_SSID: + { + CDF_STATUS status = CDF_STATUS_SUCCESS; + status = + sme_hide_ssid(hHal, pHostapdAdapter->sessionId, + set_value); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("QCSAP_PARAM_HIDE_SSID failed")); + return status; + } + break; + } + case QCSAP_PARAM_SET_MC_RATE: + { + tSirRateUpdateInd rateUpdate = {0}; + struct hdd_config *pConfig = hdd_ctx->config; + + hddLog(LOG1, "MC Target rate %d", set_value); + memcpy(rateUpdate.bssid, + pHostapdAdapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = pHostapdAdapter->device_mode; + rateUpdate.mcastDataRate24GHz = set_value; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = set_value; + rateUpdate.bcastDataRate = -1; + status = sme_send_rate_update_ind(hHal, &rateUpdate); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("SET_MC_RATE failed")); + ret = -1; + } + break; + } + + case QCSAP_PARAM_SET_TXRX_FW_STATS: + { + hddLog(LOG1, "QCSAP_PARAM_SET_TXRX_FW_STATS val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + /* Firmware debug log */ + case QCSAP_DBGLOG_LOG_LEVEL: + { + hddLog(LOG1, "QCSAP_DBGLOG_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_ENABLE: + { + hddLog(LOG1, "QCSAP_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_DISABLE: + { + hddLog(LOG1, "QCSAP_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_ENABLE: + { + hddLog(LOG1, "QCSAP_DBGLOG_MODULE_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_DISABLE: + { + hddLog(LOG1, "QCSAP_DBGLOG_MODULE_DISABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MOD_LOG_LEVEL: + { + hddLog(LOG1, "QCSAP_DBGLOG_MOD_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_TYPE: + { + hddLog(LOG1, "QCSAP_DBGLOG_TYPE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case QCSAP_DBGLOG_REPORT_ENABLE: + { + hddLog(LOG1, "QCSAP_DBGLOG_REPORT_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + case QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY: + { + cds_set_mcc_latency(pHostapdAdapter, set_value); + break; + } + + case QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA: + { + hddLog(LOG1, + FL("iwpriv cmd to set MCC quota value %dms"), + set_value); + ret = cds_go_set_mcc_p2p_quota(pHostapdAdapter, + set_value); + break; + } + + case QCASAP_TXRX_FWSTATS_RESET: + { + hddLog(LOG1, "WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case QCSAP_PARAM_RTSCTS: + { + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + set_value, VDEV_CMD); + if (ret) { + hddLog(LOGE, "FAILED TO SET RTSCTS at SAP"); + ret = -EIO; + } + break; + } + case QCASAP_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + tsap_Config_t *pConfig = + &pHostapdAdapter->sessionCtx.ap.sapConfig; + + hddLog(LOG1, "SET_HT_RATE val %d", set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_abg + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hddLog(LOGE, + "Not valid mode for HT"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else if (set_value & 0x10) { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hddLog(LOGE, "Not valid for cck"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_CCK; + /* Enable Short preamble always + * for CCK except 1mbps + */ + if (rix != 0x3) + rix |= 0x4; + } else { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY) { + hddLog(LOGE, "Not valid for OFDM"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_OFDM; + } + set_value = (preamble << 6) | (nss << 4) | rix; + } + hddLog(LOG1, "SET_HT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + tsap_Config_t *pConfig = + &pHostapdAdapter->sessionCtx.ap.sapConfig; + + if (pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac && + pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac_ONLY) { + hddLog(LOGE, + FL("SET_VHT_RATE error: SapHw_mode= 0x%x, ch = %d"), + pConfig->SapHw_mode, pConfig->channel); + ret = -EIO; + break; + } + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX_11AC(set_value); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(set_value) - 1; + + set_value = (preamble << 6) | (nss << 4) | rix; + } + hddLog(LOG1, "SET_VHT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + hddLog(LOG1, "QCASAP_SET_SHORT_GI val %d", set_value); + + /* same as 40MHZ */ + ret = sme_update_ht_config(hHal, pHostapdAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + set_value); + if (ret) + hddLog(LOGE, + "Failed to set ShortGI value ret(%d)", ret); + break; + } + + case QCSAP_SET_AMPDU: + { + hddLog(LOG1, "QCSAP_SET_AMPDU %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case QCSAP_SET_AMSDU: + { + hddLog(LOG1, "QCSAP_SET_AMSDU %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + break; + } + case QCSAP_GTX_HT_MCS: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_HT_MCS %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_VHT_MCS %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_USR_CFG %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_THRE %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_MARGIN %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_STEP %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_MINTPC %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + set_value, GTX_CMD); + break; + } + +#ifdef QCA_PKT_PROTO_TRACE + case QCASAP_SET_DEBUG_LOG: + { + hdd_context_t *pHddCtx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + + hddLog(LOG1, "QCASAP_SET_DEBUG_LOG val %d", set_value); + /* Trace buffer dump only */ + if (CDS_PKT_TRAC_DUMP_CMD == set_value) { + cds_pkt_trace_buf_dump(); + break; + } + pHddCtx->config->gEnableDebugLog = set_value; + break; + } +#endif /* QCA_PKT_PROTO_TRACE */ + + case QCASAP_SET_TM_LEVEL: + { + hddLog(LOG1, "Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_IGNORE_CAC: + { + hddLog(LOG1, "Set Dfs ignore CAC %d", set_value); + + if (pHostapdAdapter->device_mode != WLAN_HDD_SOFTAP) + return -EINVAL; + + ret = wlansap_set_dfs_ignore_cac(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_TARGET_CHNL: + { + hddLog(LOG1, "Set Dfs target channel %d", set_value); + + if (pHostapdAdapter->device_mode != WLAN_HDD_SOFTAP) + return -EINVAL; + + ret = wlansap_set_dfs_target_chnl(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_NOL: + wlansap_set_dfs_nol( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + p_cds_context, +#endif + (eSapDfsNolType) set_value); + break; + + case QCASAP_SET_RADAR_CMD: + { + hdd_context_t *pHddCtx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + uint8_t ch = + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + operatingChannel; + bool isDfsch; + + isDfsch = (CHANNEL_STATE_DFS == + cds_get_channel_state(ch)); + + hddLog(LOG1, FL("Set QCASAP_SET_RADAR_CMD val %d"), set_value); + + if (!pHddCtx->dfs_radar_found && isDfsch) { + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_DFS_CONTROL_CMDID, + set_value, VDEV_CMD); + } else { + hddLog(LOGE, + FL("Ignore, radar_found: %d, dfs_channel: %d"), + pHddCtx->dfs_radar_found, isDfsch); + } + break; + } + case QCASAP_TX_CHAINMASK_CMD: + { + hddLog(LOG1, "QCASAP_TX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hddLog(LOG1, "QCASAP_RX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case QCASAP_NSS_CMD: + { + hddLog(LOG1, "QCASAP_NSS_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_NSS, + set_value, VDEV_CMD); + break; + } + + case QCSAP_IPA_UC_STAT: + { + /* If input value is non-zero get stats */ + switch (set_value) { + case 1: + hdd_ipa_uc_stat_request(pHostapdAdapter, set_value); + break; + case 3: + hdd_ipa_uc_rt_debug_host_dump( + WLAN_HDD_GET_CTX(pHostapdAdapter)); + break; + default: + /* place holder for stats clean up + * Stats clean not implemented yet on firmware and ipa + */ + break; + } + return ret; + } + + case QCASAP_SET_PHYMODE: + { + hdd_context_t *phddctx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + + ret = + wlan_hdd_update_phymode(dev, hHal, set_value, + phddctx); + break; + } + case QCASAP_DUMP_STATS: + { + hddLog(LOG1, "QCASAP_DUMP_STATS val %d", set_value); + hdd_wlan_dump_stats(pHostapdAdapter, set_value); + break; + } + case QCASAP_CLEAR_STATS: + { + hdd_context_t *hdd_ctx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + hddLog(LOG1, "QCASAP_CLEAR_STATS val %d", set_value); + switch (set_value) { + case WLAN_HDD_STATS: + memset(&pHostapdAdapter->stats, 0, + sizeof(pHostapdAdapter->stats)); + memset(&pHostapdAdapter->hdd_stats, 0, + sizeof(pHostapdAdapter->hdd_stats)); + break; + case WLAN_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(hdd_ctx); + break; + default: + ol_txrx_clear_stats(set_value); + } + break; + } + default: + hddLog(LOGE, FL("Invalid setparam command %d value %d"), + sub_cmd, set_value); + ret = -EINVAL; + break; + } + + return ret; +} + +int +static iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_setparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + int *value = (int *)extra; + int sub_cmd = value[0]; + CDF_STATUS status; + int ret; + hdd_context_t *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_PARAM_MAX_ASSOC: + status = + sme_cfg_get_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *) value); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, + FL("failed to get WNI_CFG_ASSOC_STA_LIMIT from cfg %d"), + status); + ret = -EIO; + } + break; + + case QCSAP_PARAM_AUTO_CHANNEL: + *value = (WLAN_HDD_GET_CTX + (pHostapdAdapter))->config->force_sap_acs; + break; + + case QCSAP_PARAM_GET_WLAN_DBG: + { + cdf_trace_display(); + *value = 0; + break; + } + + case QCSAP_PARAM_RTSCTS: + { + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + *value = (int)sme_get_ht_config(hHal, + pHostapdAdapter-> + sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ); + break; + } + + case QCSAP_GTX_HT_MCS: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_HT_MCS"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_VHT_MCS"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_USR_CFG"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_THRE"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_MARGIN"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_STEP"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_MINTPC"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_BW_MASK"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + GTX_CMD); + break; + } + + case QCASAP_GET_DFS_NOL: + { + wlansap_get_dfs_nol( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter) +#else + pHddCtx->pcds_context +#endif + ); + } + break; + + case QCSAP_GET_ACL: + { + hddLog(LOG1, FL("QCSAP_GET_ACL")); + if (hdd_print_acl(pHostapdAdapter) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, + FL + ("QCSAP_GET_ACL returned Error: not completed")); + } + *value = 0; + break; + } + + case QCASAP_TX_CHAINMASK_CMD: + { + hddLog(LOG1, "QCASAP_TX_CHAINMASK_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hddLog(LOG1, "QCASAP_RX_CHAINMASK_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case QCASAP_NSS_CMD: + { + hddLog(LOG1, "QCASAP_NSS_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_NSS, + VDEV_CMD); + break; + } + case QCASAP_GET_TEMP_CMD: + { + hddLog(LOG1, "QCASAP_GET_TEMP_CMD"); + ret = wlan_hdd_get_temperature(pHostapdAdapter, value); + break; + } + default: + hddLog(LOGE, FL("Invalid getparam command %d"), sub_cmd); + ret = -EINVAL; + break; + + } + + return ret; +} + +int +static iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Usage: + BLACK_LIST = 0 + WHITE_LIST = 1 + ADD MAC = 0 + REMOVE MAC = 1 + + mac addr will be accepted as a 6 octet mac address with each octet inputted in hex + for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33 + while using this ioctl + + Syntax: + iwpriv softap.0 modify_acl + <6 octet mac addr> + + Examples: + eg 1. to add a mac addr 00:0a:f5:89:89:90 to the black list + iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 0 0 + eg 2. to delete a mac addr 00:0a:f5:89:89:90 from white list + iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 1 1 + */ +static +int __iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t cds_ctx; +#endif + uint8_t *value = (uint8_t *) extra; + uint8_t pPeerStaMac[CDF_MAC_ADDR_SIZE]; + int listType, cmd, i; + int ret; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifndef WLAN_FEATURE_MBSSID + cds_ctx = hdd_ctx->pcds_context; + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Vos Context is NULL", __func__); + return -EINVAL; + } +#endif + + for (i = 0; i < CDF_MAC_ADDR_SIZE; i++) + pPeerStaMac[i] = *(value + i); + + listType = (int)(*(value + i)); + i++; + cmd = (int)(*(value + i)); + + hddLog(LOG1, FL("Modify ACL mac:" MAC_ADDRESS_STR " type: %d cmd: %d"), + MAC_ADDR_ARRAY(pPeerStaMac), listType, cmd); + +#ifdef WLAN_FEATURE_MBSSID + cdf_status = + wlansap_modify_acl(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + pPeerStaMac, (eSapACLType) listType, + (eSapACLCmdType) cmd); +#else + cdf_status = + wlansap_modify_acl(p_cds_context, pPeerStaMac, + (eSapACLType) listType, (eSapACLCmdType) cmd); +#endif + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("Modify ACL failed")); + ret = -EIO; + } + EXIT(); + return ret; +} + +static +int iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_modify_acl(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + int *value = (int *)extra; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + *value = 0; + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) + *value = (WLAN_HDD_GET_AP_CTX_PTR( + pHostapdAdapter))->operatingChannel; + return 0; +} + +int +static iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getchannel(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + int *value = (int *)extra; + int set_value; + tSirMacAddr bssid = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirMacAddr selfMac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + int ret; + + if (NULL == value) + return -ENOMEM; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* Assign correct slef MAC address */ + cdf_mem_copy(bssid, pHostapdAdapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(selfMac, pHostapdAdapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + + set_value = value[0]; + if (CDF_STATUS_SUCCESS != + sme_set_max_tx_power(hHal, bssid, selfMac, set_value)) { + hddLog(LOGE, FL("Setting maximum tx power failed")); + return -EIO; + } + + return 0; +} + +int +static iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_max_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int *value = (int *)extra; + int set_value; + tSirMacAddr bssid; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (NULL == value) + return -ENOMEM; + + cdf_mem_copy(bssid, pHostapdAdapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + + set_value = value[0]; + if (CDF_STATUS_SUCCESS != + sme_set_tx_power(hHal, pHostapdAdapter->sessionId, bssid, + pHostapdAdapter->device_mode, set_value)) { + hddLog(LOGE, FL("Setting tx power failed")); + return -EIO; + } + + return 0; +} + +int +static iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define IS_BROADCAST_MAC(x) (((x[0] & x[1] & x[2] & x[3] & x[4] & x[5]) == 0xff) ? 1 : 0) + +int +static __iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_station_info_t *pStaInfo = pHostapdAdapter->aStaInfo; + hdd_context_t *hdd_ctx; + char *buf; + int cnt = 0; + int left; + int ret; + /* maclist_index must be u32 to match userspace */ + u32 maclist_index; + + /* + * NOTE WELL: this is a "get" ioctl but it uses an even ioctl + * number, and even numbered iocts are supposed to have "set" + * semantics. Hence the wireless extensions support in the kernel + * won't correctly copy the result to userspace, so the ioctl + * handler itself must copy the data. Output format is 32-bit + * record length, followed by 0 or more 6-byte STA MAC addresses. + * + * Further note that due to the incorrect semantics, the "iwpriv" + * userspace application is unable to correctly invoke this API, + * hence it is not registered in the hostapd_private_args. This + * API can only be invoked by directly invoking the ioctl() system + * call. + */ + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure userspace allocated a reasonable buffer size */ + if (wrqu->data.length < sizeof(maclist_index)) { + hddLog(LOG1, FL("invalid userspace buffer")); + return -EINVAL; + } + + /* allocate local buffer to build the response */ + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (!buf) { + hddLog(LOG1, FL("failed to allocate response buffer")); + return -ENOMEM; + } + + /* start indexing beyond where the record count will be written */ + maclist_index = sizeof(maclist_index); + left = wrqu->data.length - maclist_index; + + spin_lock_bh(&pHostapdAdapter->staInfo_lock); + while ((cnt < WLAN_MAX_STA_COUNT) && (left >= CDF_MAC_ADDR_SIZE)) { + if ((pStaInfo[cnt].isUsed) && + (!IS_BROADCAST_MAC(pStaInfo[cnt].macAddrSTA.bytes))) { + memcpy(&buf[maclist_index], &(pStaInfo[cnt].macAddrSTA), + CDF_MAC_ADDR_SIZE); + maclist_index += CDF_MAC_ADDR_SIZE; + left -= CDF_MAC_ADDR_SIZE; + } + cnt++; + } + spin_unlock_bh(&pHostapdAdapter->staInfo_lock); + + *((u32 *) buf) = maclist_index; + wrqu->data.length = maclist_index; + if (copy_to_user(wrqu->data.pointer, buf, maclist_index)) { + hddLog(LOG1, FL("failed to copy response to user buffer")); + ret = -EFAULT; + } + kfree(buf); + return ret; +} + +int +static iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getassoc_stamacaddr(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Usage: + mac addr will be accepted as a 6 octet mac address with each octet inputted in hex + for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33 + while using this ioctl + + Syntax: + iwpriv softap.0 disassoc_sta <6 octet mac address> + + e.g. + disassociate sta with mac addr 00:0a:f5:11:22:33 from softap + iwpriv softap.0 disassoc_sta 0x00 0x0a 0xf5 0x11 0x22 0x33 + */ + +int +static __iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + uint8_t *peerMacAddr; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* iwpriv tool or framework calls this ioctl with + * data passed in extra (less than 16 octets); + */ + peerMacAddr = (uint8_t *) (extra); + + hddLog(LOG1, FL("data " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peerMacAddr)); + hdd_softap_sta_disassoc(pHostapdAdapter, peerMacAddr); + EXIT(); + return 0; +} + +int +static iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_disassoc_sta(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + CDF_STATUS status; + int sub_cmd = wrqu->data.flags; + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return status; + + switch (sub_cmd) { + case QCSAP_GET_STATS: + hdd_wlan_get_stats(adapter, &(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + } + + EXIT(); + return status; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int wlan_hdd_set_force_acs_ch_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int *value = (int *)extra; + + if (wlan_hdd_validate_operation_channel(adapter, value[0]) != + CDF_STATUS_SUCCESS || + wlan_hdd_validate_operation_channel(adapter, value[1]) != + CDF_STATUS_SUCCESS) { + return -EINVAL; + } else { + hdd_ctx->config->force_sap_acs_st_ch = value[0]; + hdd_ctx->config->force_sap_acs_end_ch = value[1]; + } + + return 0; +} + +static int iw_softap_set_force_acs_ch_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + cds_ssr_protect(__func__); + ret = wlan_hdd_set_force_acs_ch_range(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + return ret; +} + +static int __iw_softap_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t num_channels = 0; + uint8_t i = 0; + uint8_t bandStartChannel = RF_CHAN_1; + uint8_t bandEndChannel = RF_CHAN_184; + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + tpChannelListInfo channel_list = (tpChannelListInfo) extra; + eCsrBand curBand = eCSR_BAND_ALL; + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (CDF_STATUS_SUCCESS != sme_get_freq_band(hHal, &curBand)) { + hddLog(LOGE, FL("not able get the current frequency band")); + return -EIO; + } + wrqu->data.length = sizeof(tChannelListInfo); + ENTER(); + + if (eCSR_BAND_24 == curBand) { + bandStartChannel = RF_CHAN_1; + bandEndChannel = RF_CHAN_14; + } else if (eCSR_BAND_5G == curBand) { + bandStartChannel = RF_CHAN_36; + bandEndChannel = RF_CHAN_184; + } + + hddLog(LOG1, FL("curBand = %d, StartChannel = %hu, EndChannel = %hu "), + curBand, bandStartChannel, bandEndChannel); + + for (i = bandStartChannel; i <= bandEndChannel; i++) { + if ((CHANNEL_STATE_ENABLE == reg_channels[i].enabled) || + (CHANNEL_STATE_DFS == reg_channels[i].enabled)) { + channel_list->channels[num_channels] = + rf_channels[i].channelNum; + num_channels++; + } + } + + hddLog(LOG1, FL(" number of channels %d"), num_channels); + + if (num_channels > IW_MAX_FREQUENCIES) { + num_channels = IW_MAX_FREQUENCIES; + } + + channel_list->num_channels = num_channels; + EXIT(); + + return 0; +} + +int iw_softap_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_channel_list(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + int ret; +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t cds_ctx; +#endif + CDF_STATUS status; + uint32_t length = DOT11F_IE_RSN_MAX_LEN; + uint8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifndef WLAN_FEATURE_MBSSID + cds_ctx = hdd_ctx->pcds_context; + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: vos context is not valid ", __func__); + return -EINVAL; + } +#endif + + hddLog(LOG1, FL("getGEN_IE ioctl")); + /* + * Actually retrieve the RSN IE from CSR. + * (We previously sent it down in the CSR Roam Profile.) + */ + status = wlan_sap_getstation_ie_information( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + cds_ctx, +#endif + &length, genIeBytes); + if (status == CDF_STATUS_SUCCESS) { + length = CDF_MIN(length, DOT11F_IE_RSN_MAX_LEN); + if (wrqu->data.length < length || + copy_to_user(wrqu->data.pointer, (void *)genIeBytes, length)) { + hddLog(LOG1, FL("failed to copy data to user buffer")); + return -EFAULT; + } + wrqu->data.length = length; + hddLog(LOG1, FL(" RSN IE of %d bytes returned"), + wrqu->data.length); + } else { + wrqu->data.length = 0; + hddLog(LOG1, FL(" RSN IE failed to populate")); + } + + EXIT(); + return 0; +} + +static +int iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_wpspbc_probe_req_ies(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + sQcSapreq_WPSPBCProbeReqIES_t WPSPBCProbeReqIEs; + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hddLog(LOG1, FL("get_WPSPBCProbeReqIEs ioctl")); + memset((void *)&WPSPBCProbeReqIEs, 0, sizeof(WPSPBCProbeReqIEs)); + + WPSPBCProbeReqIEs.probeReqIELen = + pHddApCtx->WPSPBCProbeReq.probeReqIELen; + cdf_mem_copy(&WPSPBCProbeReqIEs.probeReqIE, + pHddApCtx->WPSPBCProbeReq.probeReqIE, + WPSPBCProbeReqIEs.probeReqIELen); + cdf_mem_copy(&WPSPBCProbeReqIEs.macaddr, + pHddApCtx->WPSPBCProbeReq.peerMacAddr, + CDF_MAC_ADDR_SIZE); + if (copy_to_user(wrqu->data.pointer, + (void *)&WPSPBCProbeReqIEs, + sizeof(WPSPBCProbeReqIEs))) { + hddLog(LOG1, FL("failed to copy data to user buffer")); + return -EFAULT; + } + wrqu->data.length = 12 + WPSPBCProbeReqIEs.probeReqIELen; + hddLog(LOG1, FL("Macaddress : " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(WPSPBCProbeReqIEs.macaddr)); + up(&pHddApCtx->semWpsPBCOverlapInd); + EXIT(); + return 0; +} + +static +int iw_get_wpspbc_probe_req_ies(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_wpspbc_probe_req_ies(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_auth_hostap() - + * This function sets the auth type received from the wpa_supplicant. + * + * @dev: pointer to the net device. + * @info: pointer to the iw_request_info. + * @wrqu: pointer to the iwreq_data. + * @extra: pointer to the data. + * + * Return: 0 for success, non zero for failure + */ +static +int __iw_set_auth_hostap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_TKIP_COUNTERMEASURES: + { + if (wrqu->param.value) { + hddLog(LOG2, + "Counter Measure started %d", wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STARTED; + } else { + hddLog(LOG2, + "Counter Measure stopped=%d", wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STOPED; + } + + hdd_softap_tkip_mic_fail_counter_measure(pAdapter, + wrqu->param. + value); + } + break; + + default: + + hddLog(LOGW, FL("called with unsupported auth type %d"), + wrqu->param.flags & IW_AUTH_INDEX); + break; + } + + EXIT(); + return 0; +} + +/** + * iw_set_auth_hostap() - Wrapper function to protect __iw_set_auth_hostap + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int +iw_set_auth_hostap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_auth_hostap(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_encodeext() - set ap encode + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_set_ap_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t cds_ctx; +#endif + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int ret; + CDF_STATUS vstatus; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int key_index; + struct iw_point *encoding = &wrqu->encoding; + tCsrRoamSetKey setKey; + int i; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifndef WLAN_FEATURE_MBSSID + cds_ctx = hdd_ctx->pcds_context; + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: pVosContext is NULL", __func__); + return -EINVAL; + } +#endif + + key_index = encoding->flags & IW_ENCODE_INDEX; + + if (key_index > 0) { + /*Convert from 1-based to 0-based keying */ + key_index--; + } + if (!ext->key_len) + return ret; + + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + + setKey.keyId = key_index; + setKey.keyLength = ext->key_len; + + if (ext->key_len <= CSR_MAX_KEY_LEN) { + cdf_mem_copy(&setKey.Key[0], ext->key, ext->key_len); + } + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /*Key direction for group is RX only */ + setKey.keyDirection = eSIR_RX_ONLY; + cdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + + setKey.keyDirection = eSIR_TX_RX; + cdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + CDF_MAC_ADDR_SIZE); + } + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + setKey.keyDirection = eSIR_TX_DEFAULT; + cdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + CDF_MAC_ADDR_SIZE); + } + + /*For supplicant pae role is zero */ + setKey.paeRole = 0; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case IW_ENCODE_ALG_WEP: + setKey.encType = + (ext->key_len == + 5) ? eCSR_ENCRYPT_TYPE_WEP40 : eCSR_ENCRYPT_TYPE_WEP104; + pHddApCtx->uPrivacy = 1; + hddLog(LOG1, FL("uPrivacy=%d"), pHddApCtx->uPrivacy); + break; + + case IW_ENCODE_ALG_TKIP: + { + uint8_t *pKey = &setKey.Key[0]; + + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + cdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /*Supplicant sends the 32bytes key in this order + + |--------------|----------|----------| + | Tk1 |TX-MIC | RX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + + */ + /*Sme expects the 32 bytes key to be in the below order + + |--------------|----------|----------| + | Tk1 |RX-MIC | TX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + */ + /* Copy the Temporal Key 1 (TK1) */ + cdf_mem_copy(pKey, ext->key, 16); + + /*Copy the rx mic first */ + cdf_mem_copy(&pKey[16], &ext->key[24], 8); + + /*Copy the tx mic */ + cdf_mem_copy(&pKey[24], &ext->key[16], 8); + + } + break; + + case IW_ENCODE_ALG_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + + default: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + } + + hddLog(LOG1, FL(":EncryptionType:%d key_len:%d, KeyId:%d"), + setKey.encType, setKey.keyLength, setKey.keyId); + for (i = 0; i < ext->key_len; i++) + hddLog(LOG1, "%02x", setKey.Key[i]); + +#ifdef WLAN_FEATURE_MBSSID + vstatus = + wlansap_set_key_sta(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + &setKey); +#else + vstatus = wlansap_set_key_sta(cds_ctx, &setKey); +#endif + + if (vstatus != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("wlansap_set_key_sta failed, status= %d"), + vstatus); + ret = -EINVAL; + } + + return ret; +} + +/** + * iw_set_ap_encodeext() - Wrapper function to protect __iw_set_ap_encodeext + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_set_ap_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_encodeext(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_mlme() - set ap mlme + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu; pointer to iwreq_data + * @extra: extra + * + * Return; 0 on success, error number otherwise + */ +static int __iw_set_ap_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} + +/** + * iw_set_ap_mlme() - SSR wrapper for __iw_set_ap_mlme + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu; pointer to iwreq_data + * @extra: extra + * + * Return; 0 on success, error number otherwise + */ +static int iw_set_ap_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_mlme(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_rts_threshold() - get ap rts threshold + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + int ret; + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + ret = hdd_wlan_get_rts_threshold(pHostapdAdapter, wrqu); + + return ret; +} + +/** + * iw_get_ap_rts_threshold() - Wrapper function to protect + * __iw_get_ap_rts_threshold from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_frag_threshold() - get ap fragmentation threshold + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_wlan_get_frag_threshold(pHostapdAdapter, wrqu); + + return ret; +} + +/** + * iw_get_ap_frag_threshold() - Wrapper function to protect + * __iw_get_ap_frag_threshold from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_freq() - get ap frequency + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_freq(struct net_device *dev, + struct iw_request_info *info, struct iw_freq *fwrq, + char *extra) { + uint32_t status = false, channel = 0, freq = 0; + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + tHalHandle hHal; + hdd_hostapd_state_t *pHostapdState; + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + + if (pHostapdState->bssState == BSS_STOP) { + if (sme_cfg_get_int(hHal, WNI_CFG_CURRENT_CHANNEL, &channel) + != CDF_STATUS_SUCCESS) { + return -EIO; + } else { + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) in struct + * iw_freq * iwlist & iwconfig command + * shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz) + */ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + } else { + channel = pHddApCtx->operatingChannel; + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) in struct iw_freq + * iwlist & iwconfig command shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz)*/ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + return 0; +} + +/** + * iw_get_ap_freq() - Wrapper function to protect + * __iw_get_ap_freq from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_freq(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_mode() - get mode + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + wrqu->mode = IW_MODE_MASTER; + + return ret; +} + +/** + * iw_get_mode() - Wrapper function to protect __iw_get_mode from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int +__iw_softap_setwpsie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t cds_ctx; +#endif + hdd_hostapd_state_t *pHostapdState; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + uint8_t *wps_genie; + uint8_t *fwps_genie; + uint8_t *pos; + tpSap_WPSIE pSap_WPSIe; + uint8_t WPSIeType; + uint16_t length; + struct iw_point s_priv_data; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifndef WLAN_FEATURE_MBSSID + cds_ctx = hdd_ctx->pcds_context; + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid ", __func__); + return -EINVAL; + } +#endif + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + return -EINVAL; + } + + if ((NULL == s_priv_data.pointer) || + (s_priv_data.length < QCSAP_MAX_WSC_IE)) { + return -EINVAL; + } + + wps_genie = mem_alloc_copy_from_user_helper(s_priv_data.pointer, + s_priv_data.length); + + if (NULL == wps_genie) { + hddLog(LOG1, FL("failed to alloc mem and copy data")); + return -EFAULT; + } + + fwps_genie = wps_genie; + + pSap_WPSIe = cdf_mem_malloc(sizeof(tSap_WPSIE)); + if (NULL == pSap_WPSIe) { + hddLog(LOGE, "CDF unable to allocate memory"); + kfree(fwps_genie); + return -ENOMEM; + } + cdf_mem_zero(pSap_WPSIe, sizeof(tSap_WPSIE)); + + hddLog(LOG1, FL("WPS IE type[0x%X] IE[0x%X], LEN[%d]"), + wps_genie[0], wps_genie[1], wps_genie[2]); + WPSIeType = wps_genie[0]; + if (wps_genie[0] == eQC_WPS_BEACON_IE) { + pSap_WPSIe->sapWPSIECode = eSAP_WPS_BEACON_IE; + wps_genie = wps_genie + 1; + switch (wps_genie[0]) { + case DOT11F_EID_WPA: + if (wps_genie[1] < 2 + 4) { + cdf_mem_free(pSap_WPSIe); + kfree(fwps_genie); + return -EINVAL; + } else if (memcmp(&wps_genie[2], + "\x00\x50\xf2\x04", 4) == 0) { + hddLog(LOG1, FL("Set WPS BEACON IE(len %d)"), + wps_genie[1] + 2); + pos = &wps_genie[6]; + while (((size_t) pos - + (size_t) &wps_genie[6]) < + (wps_genie[1] - 4)) { + switch ((uint16_t) (*pos << 8) | + *(pos + 1)) { + case HDD_WPS_ELEM_VERSION: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.Version = + *pos; + hddLog(LOG1, "WPS version %d", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.Version); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_VER_PRESENT; + pos += 1; + break; + + case HDD_WPS_ELEM_WPS_STATE: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.wpsState = + *pos; + hddLog(LOG1, "WPS State %d", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.wpsState); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_STATE_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_APSETUPLOCK: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + APSetupLocked = *pos; + hddLog(LOG1, "AP setup lock %d", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + APSetupLocked); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_APSETUPLOCK_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_SELECTEDREGISTRA: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + SelectedRegistra = *pos; + hddLog(LOG1, + "Selected Registra %d", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + SelectedRegistra); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_SELECTEDREGISTRA_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_DEVICE_PASSWORD_ID: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + DevicePasswordID = + (*pos << 8) | *(pos + 1); + hddLog(LOG1, "Password ID: %x", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + DevicePasswordID); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_DEVICEPASSWORDID_PRESENT; + pos += 2; + break; + case HDD_WPS_ELEM_REGISTRA_CONF_METHODS: + pos += + 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + SelectedRegistraCfgMethod = + (*pos << 8) | *(pos + 1); + hddLog(LOG1, + "Select Registra Config Methods: %x", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + SelectedRegistraCfgMethod); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT; + pos += 2; + break; + + case HDD_WPS_ELEM_UUID_E: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSBeaconIE. + UUID_E, pos, + length); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_UUIDE_PRESENT; + pos += length; + break; + case HDD_WPS_ELEM_RF_BANDS: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.RFBand = + *pos; + hddLog(LOG1, "RF band: %d", + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE.RFBand); + pSap_WPSIe->sapwpsie. + sapWPSBeaconIE. + FieldPresent |= + WPS_BEACON_RF_BANDS_PRESENT; + pos += 1; + break; + + default: + hddLog(LOGW, + "UNKNOWN TLV in WPS IE(%x)", + (*pos << 8 | + *(pos + 1))); + cdf_mem_free(pSap_WPSIe); + kfree(fwps_genie); + return -EINVAL; + } + } + } else { + hddLog(LOGE, FL("WPS IE Mismatch %X"), + wps_genie[0]); + } + break; + + default: + hddLog(LOGE, FL("Set UNKNOWN IE %X"), wps_genie[0]); + cdf_mem_free(pSap_WPSIe); + kfree(fwps_genie); + return 0; + } + } else if (wps_genie[0] == eQC_WPS_PROBE_RSP_IE) { + pSap_WPSIe->sapWPSIECode = eSAP_WPS_PROBE_RSP_IE; + wps_genie = wps_genie + 1; + switch (wps_genie[0]) { + case DOT11F_EID_WPA: + if (wps_genie[1] < 2 + 4) { + cdf_mem_free(pSap_WPSIe); + kfree(fwps_genie); + return -EINVAL; + } else if (memcmp(&wps_genie[2], "\x00\x50\xf2\x04", 4) + == 0) { + hddLog(LOG1, FL("Set WPS PROBE RSP IE(len %d)"), + wps_genie[1] + 2); + pos = &wps_genie[6]; + while (((size_t) pos - + (size_t) &wps_genie[6]) < + (wps_genie[1] - 4)) { + switch ((uint16_t) (*pos << 8) | + *(pos + 1)) { + case HDD_WPS_ELEM_VERSION: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.Version = + *pos; + hddLog(LOG1, "WPS version %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + Version); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_VER_PRESENT; + pos += 1; + break; + + case HDD_WPS_ELEM_WPS_STATE: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.wpsState = + *pos; + hddLog(LOG1, "WPS State %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + wpsState); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_STATE_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_APSETUPLOCK: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + APSetupLocked = *pos; + hddLog(LOG1, "AP setup lock %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + APSetupLocked); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_APSETUPLOCK_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_SELECTEDREGISTRA: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SelectedRegistra = *pos; + hddLog(LOG1, + "Selected Registra %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SelectedRegistra); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_SELECTEDREGISTRA_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_DEVICE_PASSWORD_ID: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + DevicePasswordID = + (*pos << 8) | *(pos + 1); + hddLog(LOG1, "Password ID: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + DevicePasswordID); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_DEVICEPASSWORDID_PRESENT; + pos += 2; + break; + case HDD_WPS_ELEM_REGISTRA_CONF_METHODS: + pos += + 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SelectedRegistraCfgMethod = + (*pos << 8) | *(pos + 1); + hddLog(LOG1, + "Select Registra Config Methods: %x", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SelectedRegistraCfgMethod); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT; + pos += 2; + break; + case HDD_WPS_ELEM_RSP_TYPE: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + ResponseType = *pos; + hddLog(LOG1, + "Config Methods: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + ResponseType); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_RESPONSETYPE_PRESENT; + pos += 1; + break; + case HDD_WPS_ELEM_UUID_E: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + UUID_E, pos, + length); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_UUIDE_PRESENT; + pos += length; + break; + + case HDD_WPS_ELEM_MANUFACTURER: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + Manufacture.num_name = + length; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + Manufacture.name, + pos, length); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_MANUFACTURE_PRESENT; + pos += length; + break; + + case HDD_WPS_ELEM_MODEL_NAME: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.ModelName. + num_text = length; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + ModelName.text, + pos, length); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_MODELNAME_PRESENT; + pos += length; + break; + case HDD_WPS_ELEM_MODEL_NUM: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + ModelNumber.num_text = + length; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + ModelNumber.text, + pos, length); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_MODELNUMBER_PRESENT; + pos += length; + break; + case HDD_WPS_ELEM_SERIAL_NUM: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SerialNumber.num_text = + length; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + SerialNumber.text, + pos, length); + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_SERIALNUMBER_PRESENT; + pos += length; + break; + case HDD_WPS_ELEM_PRIMARY_DEVICE_TYPE: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + PrimaryDeviceCategory = + (*pos << 8 | *(pos + 1)); + hddLog(LOG1, + "primary dev category: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + PrimaryDeviceCategory); + pos += 2; + + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + PrimaryDeviceOUI, + pos, + HDD_WPS_DEVICE_OUI_LEN); + hddLog(LOG1, + "primary dev oui: %02x, %02x, %02x, %02x", + pos[0], pos[1], pos[2], + pos[3]); + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + DeviceSubCategory = + (*pos << 8 | *(pos + 1)); + hddLog(LOG1, + "primary dev sub category: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + DeviceSubCategory); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT; + break; + case HDD_WPS_ELEM_DEVICE_NAME: + pos += 2; + length = *pos << 8 | *(pos + 1); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.DeviceName. + num_text = length; + cdf_mem_copy(pSap_WPSIe-> + sapwpsie. + sapWPSProbeRspIE. + DeviceName.text, + pos, length); + pos += length; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_DEVICENAME_PRESENT; + break; + case HDD_WPS_ELEM_CONFIG_METHODS: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + ConfigMethod = + (*pos << 8) | *(pos + 1); + hddLog(LOG1, + "Config Methods: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + SelectedRegistraCfgMethod); + pos += 2; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_CONFIGMETHODS_PRESENT; + break; + + case HDD_WPS_ELEM_RF_BANDS: + pos += 4; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.RFBand = + *pos; + hddLog(LOG1, "RF band: %d", + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE.RFBand); + pos += 1; + pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE. + FieldPresent |= + WPS_PROBRSP_RF_BANDS_PRESENT; + break; + } /* switch */ + } + } else { + hddLog(LOGE, + FL("WPS IE Mismatch %X"), wps_genie[0]); + } + + } /* switch */ + } +#ifdef WLAN_FEATURE_MBSSID + cdf_ret_status = + wlansap_set_wps_ie(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + pSap_WPSIe); +#else + cdf_ret_status = wlansap_set_wps_ie(p_cds_context, pSap_WPSIe); +#endif + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + if (pHostapdState->bCommit && WPSIeType == eQC_WPS_PROBE_RSP_IE) { +#ifdef WLAN_FEATURE_MBSSID + wlansap_update_wps_ie(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); +#else + wlansap_update_wps_ie(p_cds_context); +#endif + } + + cdf_mem_free(pSap_WPSIe); + kfree(fwps_genie); + EXIT(); + return cdf_ret_status; +} + +static int iw_softap_setwpsie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_setwpsie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int +__iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + + cdf_event_reset(&pHostapdState->cdf_stop_bss_event); +#ifdef WLAN_FEATURE_MBSSID + status = + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); +#else + status = + wlansap_stop_bss((WLAN_HDD_GET_CTX(pHostapdAdapter))-> + pcds_context); +#endif + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + cdf_wait_single_event(&pHostapdState-> + cdf_stop_bss_event, + 10000); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("wait for single_event failed!!")); + CDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + cds_decr_session_set_pcl(hdd_ctx, + pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); + } + EXIT(); + return (status == CDF_STATUS_SUCCESS) ? 0 : -EBUSY; +} + +static int iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_stopbss(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int +__iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_wlan_get_version(pHostapdAdapter, wrqu, extra); + EXIT(); + return 0; +} + +static int iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_version(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +CDF_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, uint8_t *pBuf, + int buf_len) { + uint8_t i; + uint8_t maxSta = 0; + int len = 0; + const char sta_info_header[] = "staId staAddress"; + hdd_context_t *hdd_ctx; + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL", __func__); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return CDF_STATUS_E_FAULT; + + len = scnprintf(pBuf, buf_len, sta_info_header); + pBuf += len; + buf_len -= len; + + maxSta = hdd_ctx->config->maxNumberOfPeers; + + for (i = 0; i <= maxSta; i++) { + if (pAdapter->aStaInfo[i].isUsed) { + len = + scnprintf(pBuf, buf_len, + "%5d .%02x:%02x:%02x:%02x:%02x:%02x", + pAdapter->aStaInfo[i].ucSTAId, + pAdapter->aStaInfo[i].macAddrSTA.bytes[0], + pAdapter->aStaInfo[i].macAddrSTA.bytes[1], + pAdapter->aStaInfo[i].macAddrSTA.bytes[2], + pAdapter->aStaInfo[i].macAddrSTA.bytes[3], + pAdapter->aStaInfo[i].macAddrSTA.bytes[4], + pAdapter->aStaInfo[i].macAddrSTA. + bytes[5]); + pBuf += len; + buf_len -= len; + } + if (WE_GET_STA_INFO_SIZE > buf_len) { + break; + } + } + return CDF_STATUS_SUCCESS; +} + +static int __iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + CDF_STATUS status; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + status = + hdd_softap_get_sta_info(pHostapdAdapter, extra, + WE_SAP_MAX_STA_INFO); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("Failed to get sta info: %d"), status); + return -EINVAL; + } + wrqu->data.length = strlen(extra); + EXIT(); + return 0; +} + +static int iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_sta_info(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_genie() - set ap wpa/rsn ie + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_set_ap_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t cds_ctx; +#endif + hdd_context_t *hdd_ctx; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + uint8_t *genie = (uint8_t *)extra; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifndef WLAN_FEATURE_MBSSID + cds_ctx = hdd_ctx->pcds_context; + if (NULL == cds_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: CDF Context is NULL", __func__); + return -EINVAL; + } +#endif + + if (!wrqu->data.length) { + EXIT(); + return 0; + } + + switch (genie[0]) { + case DOT11F_EID_WPA: + case DOT11F_EID_RSN: + if ((WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy == 0) { + hdd_softap_deregister_bc_sta(pHostapdAdapter); + hdd_softap_register_bc_sta(pHostapdAdapter, 1); + } + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy = 1; +#ifdef WLAN_FEATURE_MBSSID + cdf_ret_status = + wlansap_set_wparsn_ies(WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), genie, + wrqu->data.length); +#else + cdf_ret_status = + wlansap_set_wparsn_ies(cds_ctx, genie, + wrqu->data.length); +#endif + break; + + default: + hddLog(LOGE, FL("Set UNKNOWN IE %X"), genie[0]); + cdf_ret_status = 0; + } + + EXIT(); + return cdf_ret_status; +} + +/** + * iw_set_ap_genie() - Wrapper function to protect __iw_set_ap_genie + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int +iw_set_ap_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + char *pLinkSpeed = (char *)extra; + uint32_t link_speed = 0; + int len = sizeof(uint32_t) + 1; + tSirMacAddr macAddress; + char pmacAddress[MAC_ADDRESS_STR_LEN + 1]; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int rc, valid, i; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + valid = wlan_hdd_validate_context(hdd_ctx); + if (0 != valid) + return valid; + + hddLog(LOG1, FL("wrqu->data.length(%d)"), wrqu->data.length); + + if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) { + if (copy_from_user((void *)pmacAddress, + wrqu->data.pointer, MAC_ADDRESS_STR_LEN)) { + hddLog(LOG1, FL("failed to copy data to user buffer")); + return -EFAULT; + } + pmacAddress[MAC_ADDRESS_STR_LEN] = '\0'; + + if (!mac_pton(pmacAddress, macAddress)) { + hddLog(LOGE, FL("String to Hex conversion Failed")); + return -EINVAL; + } + } + /* If no mac address is passed and/or its length is less than 17, + * link speed for first connected client will be returned. + */ + if (wrqu->data.length < 17 || !CDF_IS_STATUS_SUCCESS(status)) { + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (pHostapdAdapter->aStaInfo[i].isUsed && + (!cdf_is_macaddr_broadcast + (&pHostapdAdapter->aStaInfo[i].macAddrSTA))) { + cdf_copy_macaddr( + (struct cdf_mac_addr *) macAddress, + &pHostapdAdapter->aStaInfo[i]. + macAddrSTA); + status = CDF_STATUS_SUCCESS; + break; + } + } + } + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("Invalid peer macaddress")); + return -EINVAL; + } + status = wlan_hdd_get_linkspeed_for_peermac(pHostapdAdapter, + macAddress); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("Unable to retrieve SME linkspeed")); + return -EINVAL; + } + + link_speed = pHostapdAdapter->ls_stats.estLinkSpeed; + + /* linkspeed in units of 500 kbps */ + link_speed = link_speed / 500; + wrqu->data.length = len; + rc = snprintf(pLinkSpeed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hddLog(LOGE, FL("Unable to encode link speed")); + return -EIO; + } + + return 0; +} + +static int +iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_softap_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const iw_handler hostapd_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) NULL, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) NULL, /* SIOCSIWFREQ */ + (iw_handler) iw_get_ap_freq, /* SIOCGIWFREQ */ + (iw_handler) NULL, /* SIOCSIWMODE */ + (iw_handler) iw_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) NULL, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) NULL, /* SIOCSIWAP */ + (iw_handler) NULL, /* SIOCGIWAP */ + (iw_handler) iw_set_ap_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ + (iw_handler) NULL, /* SIOCSIWESSID */ + (iw_handler) NULL, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) NULL, /* SIOCGIWRATE */ + (iw_handler) NULL, /* SIOCSIWRTS */ + (iw_handler) iw_get_ap_rts_threshold, /* SIOCGIWRTS */ + (iw_handler) NULL, /* SIOCSIWFRAG */ + (iw_handler) iw_get_ap_frag_threshold, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) NULL, /* SIOCSIWENCODE */ + (iw_handler) NULL, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_ap_genie, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) iw_set_auth_hostap, /* SIOCSIWAUTH */ + (iw_handler) NULL, /* SIOCGIWAUTH */ + (iw_handler) iw_set_ap_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ +}; + +/* + * Note that the following ioctls were defined with semantics which + * cannot be handled by the "iwpriv" userspace application and hence + * they are not included in the hostapd_private_args array + * QCSAP_IOCTL_ASSOC_STA_MACADDR + */ + +static const struct iw_priv_args hostapd_private_args[] = { + { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setparam" + }, { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" + }, { + QCSAP_PARAM_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMaxAssoc" + }, { + QCSAP_PARAM_HIDE_SSID, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hideSSID" + }, { + QCSAP_PARAM_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMcRate" + }, + { + QCSAP_PARAM_SET_TXRX_FW_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "txrx_fw_stats" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccLatency" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccQuota" + }, { + QCSAP_PARAM_SET_CHANNEL_CHANGE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setChanChange" + }, { + QCSAP_PARAM_AUTO_CHANNEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setAutoChannel" + }, + /* Sub-cmds DBGLOG specific commands */ + { + QCSAP_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_loglevel" + }, { + QCSAP_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_vapon" + }, { + QCSAP_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_vapoff" + }, { + QCSAP_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_modon" + }, { + QCSAP_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_modoff" + }, { + QCSAP_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_mod_loglevel" + }, { + QCSAP_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_type" + }, { + QCSAP_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_report" + }, { + QCASAP_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "txrx_fw_st_rst" + }, { + QCSAP_PARAM_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enablertscts" + }, { + QCASAP_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11NRates" + }, { + QCASAP_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11ACRates" + }, { + QCASAP_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enable_short_gi" + }, { + QCSAP_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ampdu" + }, { + QCSAP_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "amsdu" + }, { + QCSAP_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxHTMcs" + }, { + QCSAP_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxVHTMcs" + }, { + QCSAP_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxUsrCfg" + }, { + QCSAP_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxThre" + }, { + QCSAP_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMargin" + }, { + QCSAP_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxStep" + }, { + QCSAP_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMinTpc" + }, { + QCSAP_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxBWMask" + }, { + QCSAP_PARAM_CLR_ACL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setClearAcl" + }, { + QCSAP_PARAM_ACL_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAclMode" + }, +#ifdef QCA_PKT_PROTO_TRACE + { + QCASAP_SET_DEBUG_LOG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setDbgLvl" + }, +#endif /* QCA_PKT_PROTO_TRACE */ + { + QCASAP_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTmLevel" + }, { + QCASAP_SET_DFS_IGNORE_CAC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDfsIgnoreCAC" + }, { + QCASAP_SET_DFS_NOL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setdfsnol" + }, { + QCASAP_SET_DFS_TARGET_CHNL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setNextChnl" + }, { + QCASAP_SET_RADAR_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setRadar" + }, + { + QCSAP_IPA_UC_STAT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ipaucstat" + }, + { + QCASAP_TX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_rxchainmask" + }, { + QCASAP_NSS_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_nss" + }, { + QCASAP_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setphymode" + }, { + QCASAP_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats" + }, { + QCASAP_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" + }, { + QCSAP_PARAM_MAX_ASSOC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getMaxAssoc" + }, { + QCSAP_PARAM_GET_WLAN_DBG, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwlandbg" + }, { + QCSAP_PARAM_AUTO_CHANNEL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getAutoChannel" + }, { + QCSAP_GTX_BWMASK, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask" + }, { + QCSAP_GTX_MINTPC, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc" + }, { + QCSAP_GTX_STEP, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep" + }, { + QCSAP_GTX_MARGIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin" + }, { + QCSAP_GTX_THRE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre" + }, { + QCSAP_GTX_USRCFG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg" + }, { + QCSAP_GTX_VHT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs" + }, { + QCSAP_GTX_HT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs" + }, { + QCASAP_SHORT_GI, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_short_gi" + }, { + QCSAP_PARAM_RTSCTS, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rtscts" + }, { + QCASAP_GET_DFS_NOL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdfsnol" + }, { + QCSAP_GET_ACL, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_acl_list" + }, { + QCASAP_TX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask" + }, { + QCASAP_NSS_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss" + }, { + QCASAP_GET_TEMP_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp" + }, { + QCSAP_IOCTL_GET_STAWPAIE, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, + "get_staWPAIE" + }, { + QCSAP_IOCTL_SETWPAIE, + IW_PRIV_TYPE_BYTE | QCSAP_MAX_WSC_IE | + IW_PRIV_SIZE_FIXED, 0, "setwpaie" + }, { + QCSAP_IOCTL_STOPBSS, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED, 0, + "stopbss" + }, { + QCSAP_IOCTL_VERSION, 0, IW_PRIV_TYPE_CHAR | QCSAP_MAX_WSC_IE, + "version" + }, { + QCSAP_IOCTL_GET_STA_INFO, 0, + IW_PRIV_TYPE_CHAR | WE_SAP_MAX_STA_INFO, "get_sta_info" + }, { + QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES, + IW_PRIV_TYPE_BYTE | + sizeof(sQcSapreq_WPSPBCProbeReqIES_t) | + IW_PRIV_SIZE_FIXED, 0, "getProbeReqIEs" + } + , { + QCSAP_IOCTL_GET_CHANNEL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" + } + , { + QCSAP_IOCTL_DISASSOC_STA, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 6, 0, + "disassoc_sta" + } + /* handler for main ioctl */ + , { + QCSAP_PRIV_GET_CHAR_SET_NONE, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "" + } + /* handler for sub-ioctl */ + , { + QCSAP_GET_STATS, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getStats" + } + , { + QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" + } + , { + QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" + } + , + /* handlers for sub-ioctl */ + { + WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setwlandbg" + }, { + WE_SET_SAP_CHANNELS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setsapchannels" + } + , + /* handlers for sub-ioctl */ + { + WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_dp_trace" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "" + } + , { + WE_P2P_NOA_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "SetP2pPs" + } + , { + WE_UNIT_TEST_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, + "setUnitTestCmd" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_MODIFY_ACL, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 8, 0, "modify_acl" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_BYTE | sizeof(tChannelListInfo), + "getChannelList" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setTxPower" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTxMaxPower" + } + , + /* Set HDD CFG Ini param */ + { + QCSAP_IOCTL_SET_INI_CFG, + IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, 0, "setConfig" + } + , + /* Get HDD CFG Ini param */ + { + QCSAP_IOCTL_GET_INI_CFG, + 0, IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, "getConfig" + } + , + /* handlers for main ioctl */ + { + /* handlers for main ioctl */ + QCSAP_IOCTL_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "" + } + , + /* handlers for sub-ioctl */ +#ifdef DEBUG + { + QCSAP_IOCTL_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject" + } + , +#endif + { + QCASAP_SET_RADAR_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setRadarDbg" + } + , + /* dump dp trace - descriptor or dp trace records */ + { + QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace" + } + , +}; + +static const iw_handler hostapd_private[] = { + /* set priv ioctl */ + [QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam, + /* get priv ioctl */ + [QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam, + /* get station genIE */ + [QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie, + [QCSAP_IOCTL_SETWPAIE - SIOCIWFIRSTPRIV] = iw_softap_setwpsie, + /* stop bss */ + [QCSAP_IOCTL_STOPBSS - SIOCIWFIRSTPRIV] = iw_softap_stopbss, + /* get driver version */ + [QCSAP_IOCTL_VERSION - SIOCIWFIRSTPRIV] = iw_softap_version, + [QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES - SIOCIWFIRSTPRIV] = + iw_get_wpspbc_probe_req_ies, + [QCSAP_IOCTL_GET_CHANNEL - SIOCIWFIRSTPRIV] = + iw_softap_getchannel, + [QCSAP_IOCTL_ASSOC_STA_MACADDR - SIOCIWFIRSTPRIV] = + iw_softap_getassoc_stamacaddr, + [QCSAP_IOCTL_DISASSOC_STA - SIOCIWFIRSTPRIV] = + iw_softap_disassoc_sta, + [QCSAP_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = + iw_get_char_setnone, + [QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_var_ints_getnone, + [QCSAP_IOCTL_SET_CHANNEL_RANGE - SIOCIWFIRSTPRIV] = + iw_softap_set_force_acs_ch_range, + [QCSAP_IOCTL_MODIFY_ACL - SIOCIWFIRSTPRIV] = + iw_softap_modify_acl, + [QCSAP_IOCTL_GET_CHANNEL_LIST - SIOCIWFIRSTPRIV] = + iw_softap_get_channel_list, + [QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = + iw_softap_get_sta_info, + [QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED - + SIOCIWFIRSTPRIV] = + iw_get_softap_linkspeed, + [QCSAP_IOCTL_SET_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_tx_power, + [QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_max_tx_power, + [QCSAP_IOCTL_SET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_set_ini_cfg, + [QCSAP_IOCTL_GET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_get_ini_cfg, + [QCSAP_IOCTL_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_softap_set_two_ints_getnone, +}; +const struct iw_handler_def hostapd_handler_def = { + .num_standard = CDF_ARRAY_SIZE(hostapd_handler), + .num_private = CDF_ARRAY_SIZE(hostapd_private), + .num_private_args = CDF_ARRAY_SIZE(hostapd_private_args), + .standard = (iw_handler *) hostapd_handler, + .private = (iw_handler *) hostapd_private, + .private_args = hostapd_private_args, + .get_wireless_stats = NULL, +}; + +struct net_device_ops net_ops_struct = { + .ndo_open = hdd_hostapd_open, + .ndo_stop = hdd_hostapd_stop, + .ndo_uninit = hdd_hostapd_uninit, + .ndo_start_xmit = hdd_softap_hard_start_xmit, + .ndo_tx_timeout = hdd_softap_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_set_mac_address = hdd_hostapd_set_mac_address, + .ndo_do_ioctl = hdd_ioctl, + .ndo_change_mtu = hdd_hostapd_change_mtu, + .ndo_select_queue = hdd_hostapd_select_queue, +}; + +static int hdd_set_hostapd(hdd_adapter_t *pAdapter) +{ + return CDF_STATUS_SUCCESS; +} + +void hdd_set_ap_ops(struct net_device *pWlanHostapdDev) +{ + pWlanHostapdDev->netdev_ops = &net_ops_struct; +} + +CDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter) +{ + hdd_hostapd_state_t *phostapdBuf; + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + CDF_STATUS status; +#ifdef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(pAdapter))->pcds_context; + v_CONTEXT_t sapContext = NULL; +#endif + int ret; + + ENTER(); + +#ifdef WLAN_FEATURE_MBSSID + sapContext = wlansap_open(p_cds_context); + if (sapContext == NULL) { + hddLog(LOGE, ("ERROR: wlansap_open failed!!")); + return CDF_STATUS_E_FAULT; + } + + pAdapter->sessionCtx.ap.sapContext = sapContext; + + status = wlansap_start(sapContext); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, ("ERROR: wlansap_start failed!!")); + wlansap_close(sapContext); + return status; + } +#endif + + /* Allocate the Wireless Extensions state structure */ + phostapdBuf = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + sme_set_curr_device_mode(pHddCtx->hHal, pAdapter->device_mode); + + /* Zero the memory. This zeros the profile structure. */ + memset(phostapdBuf, 0, sizeof(hdd_hostapd_state_t)); + + /* Set up the pointer to the Wireless Extensions state structure */ + /* NOP */ + status = hdd_set_hostapd(pAdapter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, ("ERROR: hdd_set_hostapd failed!!")); +#ifdef WLAN_FEATURE_MBSSID + wlansap_close(sapContext); +#endif + return status; + } + + status = cdf_event_init(&phostapdBuf->cdf_event); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, ("ERROR: Hostapd HDD cdf event init failed!!")); +#ifdef WLAN_FEATURE_MBSSID + wlansap_close(sapContext); +#endif + return status; + } + + status = cdf_event_init(&phostapdBuf->cdf_stop_bss_event); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("ERROR: Hostapd HDD stop bss event init failed!!")); +#ifdef WLAN_FEATURE_MBSSID + wlansap_close(sapContext); +#endif + return status; + } + + init_completion(&pAdapter->session_close_comp_var); + init_completion(&pAdapter->session_open_comp_var); + + sema_init(&(WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->semWpsPBCOverlapInd, 1); + + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&hostapd_handler_def; + + /* Initialize the data path module */ + status = hdd_softap_init_tx_rx(pAdapter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGP, FL("hdd_softap_init_tx_rx failed")); + } + + status = hdd_wmm_adapter_init(pAdapter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + "hdd_wmm_adapter_init() failed code %08d [x%08x]", + status, status); + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &pAdapter->event_flags); + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + pHddCtx->config->enableSifsBurst, + PDEV_CMD); + + if (0 != ret) { + hddLog(LOGE, + FL("WMI_PDEV_PARAM_BURST_ENABLE set failed %d"), ret); + } + pAdapter->sessionCtx.ap.sapConfig.acs_cfg.acs_mode = false; + cdf_mem_free(pAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list); + cdf_mem_zero(&pAdapter->sessionCtx.ap.sapConfig.acs_cfg, + sizeof(struct sap_acs_cfg)); + return status; + +error_wmm_init: + hdd_softap_deinit_tx_rx(pAdapter); +#ifdef WLAN_FEATURE_MBSSID + wlansap_close(sapContext); +#endif + EXIT(); + return status; +} + +/** + * hdd_wlan_create_ap_dev() - create an AP-mode device + * @pHddCtx: Global HDD context + * @macAddr: MAC address to assign to the interface + * @iface_name: User-visible name of the interface + * + * This function will allocate a Linux net_device and configuration it + * for an AP mode of operation. Note that the device is NOT actually + * registered with the kernel at this time. + * + * Return: A pointer to the private data portion of the net_device if + * the allocation and initialization was successful, NULL otherwise. + */ +hdd_adapter_t *hdd_wlan_create_ap_dev(hdd_context_t *pHddCtx, + tSirMacAddr macAddr, + uint8_t *iface_name) { + struct net_device *pWlanHostapdDev = NULL; + hdd_adapter_t *pHostapdAdapter = NULL; + + hddLog(LOG4, FL("iface_name = %s"), iface_name); + + pWlanHostapdDev = + alloc_netdev_mq(sizeof(hdd_adapter_t), iface_name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + NET_NAME_UNKNOWN, +#endif + ether_setup, + NUM_TX_QUEUES); + + if (pWlanHostapdDev != NULL) { + pHostapdAdapter = netdev_priv(pWlanHostapdDev); + + /* Init the net_device structure */ + ether_setup(pWlanHostapdDev); + + /* Initialize the adapter context to zeros. */ + cdf_mem_zero(pHostapdAdapter, sizeof(hdd_adapter_t)); + pHostapdAdapter->dev = pWlanHostapdDev; + pHostapdAdapter->pHddCtx = pHddCtx; + pHostapdAdapter->magic = WLAN_HDD_ADAPTER_MAGIC; + + hddLog(LOG4, + FL("pWlanHostapdDev = %p, pHostapdAdapter = %p, concurrency_mode=0x%x"), + pWlanHostapdDev, + pHostapdAdapter, + (int)cds_get_concurrency_mode()); + + /* Init the net_device structure */ + strlcpy(pWlanHostapdDev->name, (const char *)iface_name, + IFNAMSIZ); + + hdd_set_ap_ops(pHostapdAdapter->dev); + + pWlanHostapdDev->watchdog_timeo = HDD_TX_TIMEOUT; + pWlanHostapdDev->mtu = HDD_DEFAULT_MTU; + + cdf_mem_copy(pWlanHostapdDev->dev_addr, (void *)macAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(pHostapdAdapter->macAddressCurrent.bytes, + (void *)macAddr, sizeof(tSirMacAddr)); + + pHostapdAdapter->offloads_configured = false; + pWlanHostapdDev->destructor = free_netdev; + pWlanHostapdDev->ieee80211_ptr = &pHostapdAdapter->wdev; + pHostapdAdapter->wdev.wiphy = pHddCtx->wiphy; + pHostapdAdapter->wdev.netdev = pWlanHostapdDev; + init_completion(&pHostapdAdapter->tx_action_cnf_event); + init_completion(&pHostapdAdapter->cancel_rem_on_chan_var); + init_completion(&pHostapdAdapter->rem_on_chan_ready_event); + init_completion(&pHostapdAdapter->sta_authorized_event); + init_completion(&pHostapdAdapter->offchannel_tx_event); + init_completion(&pHostapdAdapter->scan_info. + abortscan_event_var); + + SET_NETDEV_DEV(pWlanHostapdDev, pHddCtx->parent_dev); + spin_lock_init(&pHostapdAdapter->pause_map_lock); + } + return pHostapdAdapter; +} + +/** + * hdd_register_hostapd() - register hostapd + * @pAdapter: Pointer to hostapd adapter + * @rtnl_lock_held: RTNL lock held + * + * Return: CDF status + */ +CDF_STATUS hdd_register_hostapd(hdd_adapter_t *pAdapter, + uint8_t rtnl_lock_held) { + struct net_device *dev = pAdapter->dev; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + ENTER(); + + if (rtnl_lock_held) { + if (strnchr(dev->name, strlen(dev->name), '%')) { + if (dev_alloc_name(dev, dev->name) < 0) { + hddLog(LOGE, FL("Failed:dev_alloc_name")); + return CDF_STATUS_E_FAILURE; + } + } + if (register_netdevice(dev)) { + hddLog(LOGE, FL("Failed:register_netdevice")); + return CDF_STATUS_E_FAILURE; + } + } else { + if (register_netdev(dev)) { + hddLog(LOGE, FL("Failed:register_netdev")); + return CDF_STATUS_E_FAILURE; + } + } + set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags); + + EXIT(); + return status; +} + +/** + * hdd_unregister_hostapd() - unregister hostapd + * @pAdapter: Pointer to hostapd adapter + * @rtnl_held: true if rtnl lock held; false otherwise + * + * Return: CDF_STATUS enumaration + */ +CDF_STATUS hdd_unregister_hostapd(hdd_adapter_t *pAdapter, bool rtnl_held) +{ +#ifdef WLAN_FEATURE_MBSSID + CDF_STATUS status; + void *sapContext = WLAN_HDD_GET_SAP_CTX_PTR(pAdapter); +#endif + + ENTER(); + + hdd_softap_deinit_tx_rx(pAdapter); + + /* if we are being called during driver unload, + * then the dev has already been invalidated. + * if we are being called at other times, then we can + * detach the wireless device handlers + */ + if (pAdapter->dev) { + if (rtnl_held) + pAdapter->dev->wireless_handlers = NULL; + else { + rtnl_lock(); + pAdapter->dev->wireless_handlers = NULL; + rtnl_unlock(); + } + } + +#ifdef WLAN_FEATURE_MBSSID + status = wlansap_stop(sapContext); + if (!CDF_IS_STATUS_SUCCESS(status)) + hddLog(LOGE, FL("Failed:wlansap_stop")); + + status = wlansap_close(sapContext); + if (!CDF_IS_STATUS_SUCCESS(status)) + hddLog(LOGE, FL("Failed:WLANSAP_close")); + pAdapter->sessionCtx.ap.sapContext = NULL; +#endif + + EXIT(); + return 0; +} + +/** + * wlan_hdd_rate_is_11g() - check if rate is 11g rate or not + * @rate: Rate to be checked + * + * Return: true if rate if 11g else false + */ +static bool wlan_hdd_rate_is_11g(u8 rate) +{ + static const u8 gRateArray[8] = {12, 18, 24, 36, 48, 72, + 96, 108}; /* actual rate * 2 */ + u8 i; + for (i = 0; i < 8; i++) { + if (rate == gRateArray[i]) + return true; + } + return false; +} + +#ifdef QCA_HT_2040_COEX +/** + * wlan_hdd_get_sap_obss() - Get SAP OBSS enable config based on HT_CAPAB IE + * @pHostapdAdapter: Pointer to hostapd adapter + * + * Return: HT support channel width config value + */ +static bool wlan_hdd_get_sap_obss(hdd_adapter_t *pHostapdAdapter) +{ + uint8_t ht_cap_ie[DOT11F_IE_HTCAPS_MAX_LEN]; + tDot11fIEHTCaps dot11_ht_cap_ie = {0}; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + beacon_data_t *beacon = pHostapdAdapter->sessionCtx.ap.beacon; + uint8_t *ie = NULL; + + ie = wlan_hdd_cfg80211_get_ie_ptr(beacon->tail, beacon->tail_len, + WLAN_EID_HT_CAPABILITY); + if (ie && ie[1]) { + cdf_mem_copy(ht_cap_ie, &ie[2], DOT11F_IE_HTCAPS_MAX_LEN); + dot11f_unpack_ie_ht_caps((tpAniSirGlobal)hdd_ctx->hHal, + ht_cap_ie, ie[1], &dot11_ht_cap_ie); + return dot11_ht_cap_ie.supportedChannelWidthSet; + } + + return false; +} +#else +static bool wlan_hdd_get_sap_obss(hdd_adapter_t *pHostapdAdapter) +{ + return false; +} +#endif +/** + * wlan_hdd_set_channel() - set channel in sap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @chandef: Pointer to channel definition structure + * @channel_type: Channel type + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_set_channel(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type) +{ + hdd_adapter_t *pAdapter = NULL; + uint32_t num_ch = 0; + int channel = 0; + int channel_seg2 = 0; + hdd_context_t *pHddCtx; + int status; + + tSmeConfigParams smeConfig; + tsap_Config_t *sap_config; + + ENTER(); + + + if (NULL == dev) { + hddLog(LOGE, FL("Called with dev = NULL.")); + return -ENODEV; + } + pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_CHANNEL, + pAdapter->sessionId, channel_type)); + + hddLog(LOG1, FL("Device_mode %s(%d) freq = %d"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, chandef->chan->center_freq); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + /* + * Do freq to chan conversion + * TODO: for 11a + */ + + channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); + if (NL80211_CHAN_WIDTH_80P80 == chandef->width) + channel_seg2 = ieee80211_frequency_to_channel(chandef->center_freq2); + else + channel_seg2 = 0; + + /* Check freq range */ + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel)) { + hddLog(LOGE, + FL("Channel [%d] is outside valid range from %d to %d"), + channel, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + /* Check freq range */ + + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel_seg2) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel_seg2)) { + hddLog(LOGE, + FL("Channel [%d] is outside valid range from %d to %d"), + channel_seg2, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if ((WLAN_HDD_SOFTAP != pAdapter->device_mode) && + (WLAN_HDD_P2P_GO != pAdapter->device_mode)) { + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, channel)) { + hddLog(LOGE, FL("Invalid Channel [%d]"), channel); + return -EINVAL; + } + hddLog(LOG2, + FL("set channel to [%d] for device mode %s(%d)"), + channel, + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + } + + if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) + || (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) + ) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_IbssConnected == + pHddStaCtx->conn_info.connState) { + /* Link is up then return cant set channel */ + hddLog(LOGE, + FL("IBSS Associated, can't set the channel")); + return -EINVAL; + } + + num_ch = pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = channel; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + } else if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) + || (pAdapter->device_mode == WLAN_HDD_P2P_GO) + ) { + sap_config = &((WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->sapConfig); + if (WLAN_HDD_P2P_GO == pAdapter->device_mode) { + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, + channel)) { + hddLog(LOGE, + FL("Invalid Channel [%d]"), channel); + return -EINVAL; + } + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + } else { + /* set channel to what hostapd configured */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, + channel)) { + hddLog(LOGE, + FL("Invalid Channel [%d]"), channel); + return -EINVAL; + } + + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + + cdf_mem_zero(&smeConfig, sizeof(smeConfig)); + sme_get_config_param(pHddCtx->hHal, &smeConfig); + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + smeConfig.csrConfig.obssEnabled = false; + if (channel <= 14) + smeConfig.csrConfig. + channelBondingMode24GHz = + eCSR_INI_SINGLE_CHANNEL_CENTERED; + else + smeConfig.csrConfig. + channelBondingMode5GHz = + eCSR_INI_SINGLE_CHANNEL_CENTERED; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + sap_config->ch_width_orig = + eHT_CHANNEL_WIDTH_20MHZ; +#endif + sap_config->sec_ch = 0; + break; + + case NL80211_CHAN_HT40MINUS: + if (channel <= 14) + smeConfig.csrConfig. + channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + else + smeConfig.csrConfig. + channelBondingMode5GHz = + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + sap_config->sec_ch = sap_config->channel - 4; + break; + case NL80211_CHAN_HT40PLUS: + if (channel <= 14) + smeConfig.csrConfig. + channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + else + smeConfig.csrConfig. + channelBondingMode5GHz = + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + sap_config->sec_ch = sap_config->channel + 4; + break; + default: + hddLog(LOGE, + FL("Error!!! Invalid HT20/40 mode !")); + return -EINVAL; + } + smeConfig.csrConfig.obssEnabled = wlan_hdd_get_sap_obss( + pAdapter); + sme_update_config(pHddCtx->hHal, &smeConfig); + } + } else { + hddLog(LOGE, + FL("Invalid device mode failed to set valid channel")); + return -EINVAL; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_check_11gmode() - check for 11g mode + * @pIe: Pointer to IE + * @require_ht: Pointer to require ht + * @require_vht: Pointer to require vht + * @pCheckRatesfor11g: Pointer to check rates for 11g mode + * @pSapHw_mode: SAP HW mode + * + * Check for 11g rate and set proper 11g only mode + * + * Return: none + */ +static void wlan_hdd_check_11gmode(u8 *pIe, u8 *require_ht, u8 *require_vht, + u8 *pCheckRatesfor11g, + eCsrPhyMode *pSapHw_mode) +{ + u8 i, num_rates = pIe[0]; + + pIe += 1; + for (i = 0; i < num_rates; i++) { + if (*pCheckRatesfor11g + && (true == wlan_hdd_rate_is_11g(pIe[i] & RATE_MASK))) { + /* If rate set have 11g rate than change the mode + * to 11G + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g; + if (pIe[i] & BASIC_RATE_MASK) { + /* If we have 11g rate as basic rate, it + * means mode is 11g only mode. + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g_ONLY; + *pCheckRatesfor11g = false; + } + } else { + if ((BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY) == pIe[i]) + *require_ht = true; + else if ((BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY) == pIe[i]) + *require_vht = true; + } + } + return; +} + +/** + * wlan_hdd_add_ie() - add ie + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to ie to be added + * @total_ielen: Pointer to store total ie length + * @oui: Pointer to oui + * @oui_size: Size of oui + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_add_ie(hdd_adapter_t *pHostapdAdapter, uint8_t *genie, + uint8_t *total_ielen, uint8_t *oui, + uint8_t oui_size) +{ + uint16_t ielen = 0; + uint8_t *pIe = NULL; + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + + pIe = wlan_hdd_get_vendor_oui_ie_ptr(oui, oui_size, + pBeacon->tail, pBeacon->tail_len); + + if (pIe) { + ielen = pIe[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + cdf_mem_copy(&genie[*total_ielen], pIe, ielen); + } else { + hddLog(LOGE, + "**Ie Length is too big***"); + return -EINVAL; + } + *total_ielen += ielen; + } + return 0; +} + +/** + * wlan_hdd_add_hostapd_conf_vsie() - configure vsie in sap mode + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to vsie + * @total_ielen: Pointer to store total ie length + * + * Return: none + */ +static void wlan_hdd_add_hostapd_conf_vsie(hdd_adapter_t *pHostapdAdapter, + uint8_t *genie, + uint8_t *total_ielen) +{ + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (NULL == ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hddLog(LOGE, + FL("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + return; + } + if (IE_EID_VENDOR == elem_id) { + /* skipping the VSIE's which we don't want to include or + * it will be included by existing code + */ + if ((memcmp(&ptr[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) != + 0) && +#ifdef WLAN_FEATURE_WFD + (memcmp(&ptr[2], WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE) != + 0) && +#endif + (memcmp + (&ptr[2], WHITELIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) != 0) + && + (memcmp + (&ptr[2], BLACKLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) != 0) + && + (memcmp + (&ptr[2], "\x00\x50\xf2\x02", + WPA_OUI_TYPE_SIZE) != 0) + && (memcmp(&ptr[2], WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE) + != 0) + && (memcmp(&ptr[2], P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE) + != 0)) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + cdf_mem_copy(&genie[*total_ielen], ptr, + ielen); + *total_ielen += ielen; + } else { + hddLog(LOGE, + FL("IE Length is too big IEs eid=%d elem_len=%d total_ie_lent=%d"), + elem_id, elem_len, *total_ielen); + } + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return; +} + +/** + * wlan_hdd_add_extra_ie() - add extra ies in beacon + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to extra ie + * @total_ielen: Pointer to store total ie length + * @temp_ie_id: ID of extra ie + * + * Return: none + */ +static void wlan_hdd_add_extra_ie(hdd_adapter_t *pHostapdAdapter, + uint8_t *genie, uint8_t *total_ielen, + uint8_t temp_ie_id) +{ + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (NULL == ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hddLog(LOGE, + FL("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + return; + } + + if (temp_ie_id == elem_id) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + cdf_mem_copy(&genie[*total_ielen], ptr, ielen); + *total_ielen += ielen; + } else { + hddLog(LOGE, + FL("IE Length is too big IEs eid=%d elem_len=%d total_ie_lent=%d"), + elem_id, elem_len, *total_ielen); + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +/** + * wlan_hdd_cfg80211_alloc_new_beacon() - alloc beacon in ap mode + * @pAdapter: Pointer to hostapd adapter + * @ppBeacon: Pointer to pointer to beacon data + * @params: Pointer to beacon parameters + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, + beacon_data_t **ppBeacon, + struct beacon_parameters *params) +#else +/** + * wlan_hdd_cfg80211_alloc_new_beacon() - alloc beacon in ap mode + * @pAdapter: Pointer to hostapd adapter + * @ppBeacon: Pointer to pointer to beacon data + * @params: Pointer to beacon parameters + * @dtim_period: DTIM period + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, + beacon_data_t **ppBeacon, + struct cfg80211_beacon_data *params, + int dtim_period) +#endif +{ + int size; + beacon_data_t *beacon = NULL; + beacon_data_t *old = NULL; + int head_len, tail_len, proberesp_ies_len, assocresp_ies_len; + const u8 *head, *tail, *proberesp_ies, *assocresp_ies; + + ENTER(); + if (params->head && !params->head_len) { + hddLog(LOGE, FL("head_len is NULL")); + return -EINVAL; + } + + old = pAdapter->sessionCtx.ap.beacon; + + if (!params->head && !old) { + hddLog(LOGE, FL("session(%d) old and new heads points to NULL"), + pAdapter->sessionId); + return -EINVAL; + } + + if (params->head) { + head_len = params->head_len; + head = params->head; + } else { + head_len = old->head_len; + head = old->head; + } + + if (params->tail || !old) { + tail_len = params->tail_len; + tail = params->tail; + } else { + tail_len = old->tail_len; + tail = old->tail; + } + + if (params->proberesp_ies || !old) { + proberesp_ies_len = params->proberesp_ies_len; + proberesp_ies = params->proberesp_ies; + } else { + proberesp_ies_len = old->proberesp_ies_len; + proberesp_ies = old->proberesp_ies; + } + + if (params->assocresp_ies || !old) { + assocresp_ies_len = params->assocresp_ies_len; + assocresp_ies = params->assocresp_ies; + } else { + assocresp_ies_len = old->assocresp_ies_len; + assocresp_ies = old->assocresp_ies; + } + + size = sizeof(beacon_data_t) + head_len + tail_len + + proberesp_ies_len + assocresp_ies_len; + + beacon = kzalloc(size, GFP_KERNEL); + + if (beacon == NULL) { + hddLog(LOGE, + FL("Mem allocation for beacon failed")); + return -ENOMEM; + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) + if (params->dtim_period) + beacon->dtim_period = params->dtim_period; + else if (old) + beacon->dtim_period = old->dtim_period; +#else + if (dtim_period) + beacon->dtim_period = dtim_period; + else if (old) + beacon->dtim_period = old->dtim_period; +#endif + /* ----------------------------------------------- + * | head | tail | proberesp_ies | assocresp_ies | + * ----------------------------------------------- + */ + beacon->head = ((u8 *) beacon) + sizeof(beacon_data_t); + beacon->tail = beacon->head + head_len; + beacon->proberesp_ies = beacon->tail + tail_len; + beacon->assocresp_ies = beacon->proberesp_ies + proberesp_ies_len; + + beacon->head_len = head_len; + beacon->tail_len = tail_len; + beacon->proberesp_ies_len = proberesp_ies_len; + beacon->assocresp_ies_len = assocresp_ies_len; + + if (head && head_len) + memcpy(beacon->head, head, head_len); + if (tail && tail_len) + memcpy(beacon->tail, tail, tail_len); + if (proberesp_ies && proberesp_ies_len) + memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); + if (assocresp_ies && assocresp_ies_len) + memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); + + *ppBeacon = beacon; + + kfree(old); + + return 0; + +} + +/** + * wlan_hdd_cfg80211_update_apies() - update ap mode ies + * @adapter: Pointer to hostapd adapter + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *adapter) +{ + uint8_t *genie; + uint8_t total_ielen = 0; + int ret = 0; + tsap_Config_t *pConfig; + tSirUpdateIE updateIE; + beacon_data_t *beacon = NULL; + + pConfig = &adapter->sessionCtx.ap.sapConfig; + beacon = adapter->sessionCtx.ap.beacon; + + genie = cdf_mem_malloc(MAX_GENIE_LEN); + + if (genie == NULL) + return -ENOMEM; + + if (0 != wlan_hdd_add_ie(adapter, genie, + &total_ielen, WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE)) { + hddLog(LOGE, FL("Adding WPS IE failed")); + ret = -EINVAL; + goto done; + } +#ifdef WLAN_FEATURE_WFD + if (0 != wlan_hdd_add_ie(adapter, genie, + &total_ielen, WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE)) { + hddLog(LOGE, FL("Adding WFD IE failed")); + ret = -EINVAL; + goto done; + } +#endif + +#ifdef FEATURE_WLAN_WAPI + if (WLAN_HDD_SOFTAP == adapter->device_mode) { + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_WAPI); + } +#endif + + if (adapter->device_mode == WLAN_HDD_SOFTAP || + adapter->device_mode == WLAN_HDD_P2P_GO) + wlan_hdd_add_hostapd_conf_vsie(adapter, genie, + &total_ielen); + + if (wlan_hdd_add_ie(adapter, genie, + &total_ielen, P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE) != 0) { + hddLog(LOGE, FL("Adding P2P IE failed")); + ret = -EINVAL; + goto done; + } + +#ifdef QCA_HT_2040_COEX + if (WLAN_HDD_SOFTAP == adapter->device_mode) { + tSmeConfigParams smeConfig; + cdf_mem_zero(&smeConfig, sizeof(smeConfig)); + sme_get_config_param(WLAN_HDD_GET_HAL_CTX(adapter), + &smeConfig); + if (smeConfig.csrConfig.obssEnabled) + wlan_hdd_add_extra_ie(adapter, genie, + &total_ielen, + WLAN_EID_OVERLAP_BSS_SCAN_PARAM); + } +#endif + cdf_mem_copy(updateIE.bssid, adapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = adapter->sessionId; + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = total_ielen; + updateIE.pAdditionIEBuffer = genie; + updateIE.append = false; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == + CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL("Could not pass on Add Ie probe beacon data")); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_PROBE_BCN); + } else { + wlansap_update_sap_config_add_ie(pConfig, + genie, + total_ielen, + eUPDATE_IE_PROBE_BCN); + } + + /* Added for Probe Response IE */ + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = beacon->proberesp_ies_len; + updateIE.pAdditionIEBuffer = (uint8_t *) beacon->proberesp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_PROBE_RESP) == + CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL("Could not pass on PROBE_RESP add Ie data")); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_PROBE_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + beacon->proberesp_ies, + beacon->proberesp_ies_len, + eUPDATE_IE_PROBE_RESP); + } + + /* Assoc resp Add ie Data */ + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = beacon->assocresp_ies_len; + updateIE.pAdditionIEBuffer = (uint8_t *) beacon->assocresp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == + CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL("Could not pass on Add Ie Assoc Response data")); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ASSOC_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + beacon->assocresp_ies, + beacon->assocresp_ies_len, + eUPDATE_IE_ASSOC_RESP); + } + +done: + cdf_mem_free(genie); + return ret; +} + +/** + * wlan_hdd_set_sap_hwmode() - set sap hw mode + * @pHostapdAdapter: Pointer to hostapd adapter + * + * Return: none + */ +static void wlan_hdd_set_sap_hwmode(hdd_adapter_t *pHostapdAdapter) +{ + tsap_Config_t *pConfig = &pHostapdAdapter->sessionCtx.ap.sapConfig; + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + struct ieee80211_mgmt *pMgmt_frame = + (struct ieee80211_mgmt *)pBeacon->head; + u8 checkRatesfor11g = true; + u8 require_ht = false, require_vht = false; + u8 *pIe = NULL; + + pConfig->SapHw_mode = eCSR_DOT11_MODE_11b; + + pIe = wlan_hdd_cfg80211_get_ie_ptr(&pMgmt_frame->u.beacon.variable[0], + pBeacon->head_len, + WLAN_EID_SUPP_RATES); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_EXT_SUPP_RATES); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + if (pConfig->channel > 14) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11a; + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_HT_CAPABILITY); + + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n; + if (require_ht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n_ONLY; + } + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_VHT_CAPABILITY); + + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac; + if (require_vht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac_ONLY; + } +} + +/** + * wlan_hdd_config_acs() - config ACS needed parameters + * @hdd_ctx: HDD context + * @adapter: Adapter pointer + * + * This function get ACS related INI paramters and populated + * sap config and smeConfig for ACS needed configurations. + * + * Return: The CDF_STATUS code associated with performing the operation. + */ +CDF_STATUS wlan_hdd_config_acs(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + tsap_Config_t *sap_config; + struct hdd_config *ini_config; + tHalHandle hal; + + hal = WLAN_HDD_GET_HAL_CTX(adapter); + sap_config = &adapter->sessionCtx.ap.sapConfig; + ini_config = hdd_ctx->config; + + sap_config->enOverLapCh = !!hdd_ctx->config->gEnableOverLapCh; + +#if defined(WLAN_FEATURE_MBSSID) && defined(FEATURE_WLAN_AP_AP_ACS_OPTIMIZE) + hddLog(LOG1, FL("HDD_ACS_SKIP_STATUS = %d"), + hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN) { + hdd_adapter_t *con_sap_adapter; + tsap_Config_t *con_sap_config = NULL; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + + if (con_sap_adapter) + con_sap_config = + &con_sap_adapter->sessionCtx.ap.sapConfig; + + sap_config->acs_cfg.skip_scan_status = eSAP_DO_NEW_ACS_SCAN; + + if (con_sap_config && + con_sap_config->acs_cfg.acs_mode == true && + hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN && + con_sap_config->acs_cfg.hw_mode == + sap_config->acs_cfg.hw_mode) { + uint8_t con_sap_st_ch, con_sap_end_ch; + uint8_t cur_sap_st_ch, cur_sap_end_ch; + uint8_t bandStartChannel, bandEndChannel; + + con_sap_st_ch = + con_sap_config->acs_cfg.start_ch; + con_sap_end_ch = + con_sap_config->acs_cfg.end_ch; + cur_sap_st_ch = sap_config->acs_cfg.start_ch; + cur_sap_end_ch = sap_config->acs_cfg.end_ch; + + wlansap_extend_to_acs_range( + &cur_sap_st_ch, &cur_sap_end_ch, + &bandStartChannel, &bandEndChannel); + + wlansap_extend_to_acs_range( + &con_sap_st_ch, &con_sap_end_ch, + &bandStartChannel, &bandEndChannel); + + if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_SKIP_ACS_SCAN; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + con_sap_end_ch + 1; + sap_config->acs_cfg.skip_scan_range1_endch = + cur_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + con_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_endch = + cur_sap_end_ch + 1; + + } else + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_NEW_ACS_SCAN; + + + hddLog(LOG1, FL( + "SecAP ACS Skip=%d, ACS CH RANGE=%d-%d, %d-%d"), + sap_config->acs_cfg.skip_scan_status, + sap_config->acs_cfg.skip_scan_range1_stch, + sap_config->acs_cfg.skip_scan_range1_endch, + sap_config->acs_cfg.skip_scan_range2_stch, + sap_config->acs_cfg.skip_scan_range2_endch); + } + } +#endif + + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_setup_driver_overrides : Overrides SAP / P2P GO Params + * @adapter: pointer to adapter struct + * + * This function overrides SAP / P2P Go configuration based on driver INI + * parameters for 11AC override and ACS. This overrides are done to support + * android legacy configuration method. + * + * NOTE: Non android platform supports concurrency and these overrides shall + * not be used. Also future driver based overrides shall be consolidated in this + * function only. Avoid random overrides in other location based on ini. + * + * Return: 0 for Success or Negative error codes. + */ +int wlan_hdd_setup_driver_overrides(hdd_adapter_t *ap_adapter) +{ + tsap_Config_t *sap_cfg = &ap_adapter->sessionCtx.ap.sapConfig; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + tHalHandle h_hal = WLAN_HDD_GET_HAL_CTX(ap_adapter); + + if (ap_adapter->device_mode == WLAN_HDD_SOFTAP && + hdd_ctx->config->force_sap_acs) + goto setup_acs_overrides; + + /* Fixed channel 11AC override: + * 11AC override in qcacld is introduced for following reasons: + * 1. P2P GO also follows start_bss and since p2p GO could not be + * configured to setup VHT channel width in wpa_supplicant + * 2. Android UI does not provide advanced configuration options for SAP + * + * Default override enabled (for android). MDM shall disable this in ini + */ + if (hdd_ctx->config->sap_p2p_11ac_override && + (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY)) { + hddLog(LOG1, FL("** Driver force 11AC override for SAP/Go **")); + + /* 11n only shall not be overridden since it may be on purpose*/ + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (sap_cfg->channel >= 36) + sap_cfg->ch_width_orig = + hdd_ctx->config->vhtChannelWidth; + else + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + } + sap_cfg->ch_params.ch_width = sap_cfg->ch_width_orig; + sme_set_ch_params(h_hal, sap_cfg->SapHw_mode, sap_cfg->channel, + sap_cfg->sec_ch, &sap_cfg->ch_params); + + return 0; + +setup_acs_overrides: + hddLog(LOGE, FL("** Driver force ACS override **")); + + sap_cfg->channel = AUTO_CHANNEL_SELECT; + sap_cfg->acs_cfg.acs_mode = true; + sap_cfg->acs_cfg.start_ch = hdd_ctx->config->force_sap_acs_st_ch; + sap_cfg->acs_cfg.end_ch = hdd_ctx->config->force_sap_acs_end_ch; + + if (sap_cfg->acs_cfg.start_ch > sap_cfg->acs_cfg.end_ch) { + hddLog(LOGE, FL("Driver force ACS start ch (%d) > end ch (%d)"), + sap_cfg->acs_cfg.start_ch, sap_cfg->acs_cfg.end_ch); + return -EINVAL; + } + + /* Derive ACS HW mode */ + sap_cfg->SapHw_mode = hdd_cfg_xlate_to_csr_phy_mode( + hdd_ctx->config->dot11Mode); + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_AUTO) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if ((sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11b || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11g || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11g_ONLY) && + sap_cfg->acs_cfg.start_ch > 14) { + hddLog(LOGE, FL("Invalid ACS HW Mode %d + CH range <%d - %d>"), + sap_cfg->SapHw_mode, sap_cfg->acs_cfg.start_ch, + sap_cfg->acs_cfg.end_ch); + return -EINVAL; + } + sap_cfg->acs_cfg.hw_mode = sap_cfg->SapHw_mode; + + /* Derive ACS BW */ + sap_cfg->ch_width_orig = eHT_CHANNEL_WIDTH_20MHZ; + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) { + + sap_cfg->ch_width_orig = hdd_ctx->config->vhtChannelWidth; + /* VHT in 2.4G depends on gChannelBondingMode24GHz INI param */ + if (sap_cfg->acs_cfg.end_ch <= 14) + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + } + + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n_ONLY) { + if (sap_cfg->acs_cfg.end_ch <= 14) + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + else + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode5GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + } + sap_cfg->acs_cfg.ch_width = sap_cfg->ch_width_orig; + + hddLog(LOG1, FL("Force ACS Config: HW_MODE: %d ACS_BW: %d"), + sap_cfg->acs_cfg.hw_mode, sap_cfg->acs_cfg.ch_width); + hddLog(LOG1, FL("Force ACS Config: ST_CH: %d END_CH: %d"), + sap_cfg->acs_cfg.start_ch, sap_cfg->acs_cfg.end_ch); + + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @pHostapdAdapter: Pointer to hostapd adapter + * @params: Pointer to start bss beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, + struct beacon_parameters *params) +#else +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @pHostapdAdapter: Pointer to hostapd adapter + * @params: Pointer to start bss beacon parameters + * @ssid: Pointer ssid + * @ssid_len: Length of ssid + * @hidden_ssid: Hidden SSID parameter + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid) +#endif +{ + tsap_Config_t *pConfig; + beacon_data_t *pBeacon = NULL; + struct ieee80211_mgmt *pMgmt_frame; + uint8_t *pIe = NULL; + uint16_t capab_info; + eCsrAuthType RSNAuthType; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; + int status = CDF_STATUS_SUCCESS, ret; + tpWLAN_SAPEventCB pSapEventCallback; + hdd_hostapd_state_t *pHostapdState; +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = + (WLAN_HDD_GET_CTX(pHostapdAdapter))->pcds_context; +#endif + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + struct qc_mac_acl_entry *acl_entry = NULL; + int32_t i; + struct hdd_config *iniConfig; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + tSmeConfigParams sme_config; + bool MFPCapable = false; + bool MFPRequired = false; + uint16_t prev_rsn_length = 0; + ENTER(); + + if (cds_is_connection_in_progress(pHddCtx)) { + hdd_err("Can't start BSS: connection is in progress"); + return -EINVAL; + } + + iniConfig = pHddCtx->config; + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + + clear_bit(ACS_PENDING, &pHostapdAdapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags); + + pConfig = &pHostapdAdapter->sessionCtx.ap.sapConfig; + + pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + + pMgmt_frame = (struct ieee80211_mgmt *)pBeacon->head; + + pConfig->beacon_int = pMgmt_frame->u.beacon.beacon_int; + + pConfig->disableDFSChSwitch = iniConfig->disableDFSChSwitch; + + /* channel is already set in the set_channel Call back */ + /* pConfig->channel = pCommitConfig->channel; */ + + /* Protection parameter to enable or disable */ + pConfig->protEnabled = iniConfig->apProtEnabled; + + pConfig->dtim_period = pBeacon->dtim_period; + + hddLog(LOG2, FL("****pConfig->dtim_period=%d***"), + pConfig->dtim_period); + + if (pHostapdAdapter->device_mode == WLAN_HDD_SOFTAP) { + pIe = + wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, + pBeacon->tail_len, + WLAN_EID_COUNTRY); + if (pIe) { + pConfig->ieee80211d = 1; + cdf_mem_copy(pConfig->countryCode, &pIe[2], 3); + sme_set_reg_info(hHal, pConfig->countryCode); + sme_apply_channel_power_info_to_fw(hHal); + } else { + pConfig->countryCode[0] = pHddCtx->reg.alpha2[0]; + pConfig->countryCode[1] = pHddCtx->reg.alpha2[1]; + pConfig->ieee80211d = 0; + } + + ret = wlan_hdd_sap_cfg_dfs_override(pHostapdAdapter); + if (ret < 0) { + return ret; + } else { + if (ret == 0) { + if (CDS_IS_DFS_CH(pConfig->channel)) + pHddCtx->dev_dfs_cac_status = + DFS_CAC_NEVER_DONE; + } + } + + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pHostapdAdapter, + pConfig->channel)) { + hddLog(LOGE, FL("Invalid Channel [%d]"), + pConfig->channel); + return -EINVAL; + } + + /* reject SAP if DFS channel scan is not allowed */ + if (!(pHddCtx->config->enableDFSChnlScan) && + (CHANNEL_STATE_DFS == cds_get_channel_state( + pConfig->channel))) { + hddLog(LOGE, + FL("not allowed to start SAP on DFS channel")); + return -EOPNOTSUPP; + } + wlansap_set_dfs_ignore_cac(hHal, iniConfig->ignoreCAC); + wlansap_set_dfs_restrict_japan_w53(hHal, + iniConfig->gDisableDfsJapanW53); + wlansap_set_dfs_preferred_channel_location(hHal, + iniConfig->gSapPreferredChanLocation); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + wlan_sap_set_channel_avoidance(hHal, + iniConfig->sap_channel_avoidance); +#endif + } else if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO) { + pConfig->countryCode[0] = pHddCtx->reg.alpha2[0]; + pConfig->countryCode[1] = pHddCtx->reg.alpha2[1]; + pConfig->ieee80211d = 0; + } else { + pConfig->ieee80211d = 0; + } + + capab_info = pMgmt_frame->u.beacon.capab_info; + + pConfig->privacy = (pMgmt_frame->u.beacon.capab_info & + WLAN_CAPABILITY_PRIVACY) ? true : false; + + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy = pConfig->privacy; + + /*Set wps station to configured */ + pIe = wlan_hdd_get_wps_ie_ptr(pBeacon->tail, pBeacon->tail_len); + + if (pIe) { + if (pIe[1] < (2 + WPS_OUI_TYPE_SIZE)) { + hddLog(LOGE, + FL("**Wps Ie Length is too small***")); + return -EINVAL; + } else if (memcmp(&pIe[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) == + 0) { + hddLog(LOG1, FL("** WPS IE(len %d) ***"), (pIe[1] + 2)); + /* Check 15 bit of WPS IE as it contain information for + * wps state + */ + if (SAP_WPS_ENABLED_UNCONFIGURED == pIe[15]) { + pConfig->wps_state = + SAP_WPS_ENABLED_UNCONFIGURED; + } else if (SAP_WPS_ENABLED_CONFIGURED == pIe[15]) { + pConfig->wps_state = SAP_WPS_ENABLED_CONFIGURED; + } + } + } else { + hdd_info("WPS disabled"); + pConfig->wps_state = SAP_WPS_DISABLED; + } + /* Forward WPS PBC probe request frame up */ + pConfig->fwdWPSPBCProbeReq = 1; + + pConfig->RSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + pConfig->mcRSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->ucEncryptType = + eCSR_ENCRYPT_TYPE_NONE; + + pConfig->RSNWPAReqIELength = 0; + memset(&pConfig->RSNWPAReqIE[0], 0, sizeof(pConfig->RSNWPAReqIE)); + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_RSN); + if (pIe && pIe[1]) { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hddLog(LOGE, + FL("RSNWPA IE MAX Length exceeded; length =%d"), + pConfig->RSNWPAReqIELength); + /* The actual processing may eventually be more extensive than + * this. Right now, just consume any PMKIDs that are sent in + * by the app. + * */ + status = + hdd_softap_unpack_ie(cds_get_context + (CDF_MODULE_ID_SME), + &RSNEncryptType, &mcRSNEncryptType, + &RSNAuthType, &MFPCapable, + &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (CDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes you have + * parsed out. Use the cipher type in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + ucEncryptType = RSNEncryptType; + hddLog(LOG1, + FL("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d"), + RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + } + + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + + if (pIe && pIe[1] && (pIe[0] == DOT11F_EID_WPA)) { + if (pConfig->RSNWPAReqIE[0]) { + /*Mixed mode WPA/WPA2 */ + prev_rsn_length = pConfig->RSNWPAReqIELength; + pConfig->RSNWPAReqIELength += pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0] + + prev_rsn_length, pIe, pIe[1] + 2); + else + hddLog(LOGE, + "RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + } else { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hddLog(LOGE, + "RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + status = hdd_softap_unpack_ie + (cds_get_context(CDF_MODULE_ID_SME), + &RSNEncryptType, + &mcRSNEncryptType, &RSNAuthType, + &MFPCapable, &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (CDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes + * you have parsed out. Use the cipher type + * in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + ucEncryptType = RSNEncryptType; + hddLog(LOG1, + FL("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d"), + RSNAuthType, RSNEncryptType, + mcRSNEncryptType); + } + } + } + + if (pConfig->RSNWPAReqIELength > sizeof(pConfig->RSNWPAReqIE)) { + hddLog(LOGE, + FL("**RSNWPAReqIELength is too large***")); + return -EINVAL; + } + + pConfig->SSIDinfo.ssidHidden = false; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) + if (params->ssid != NULL) { + cdf_mem_copy(pConfig->SSIDinfo.ssid.ssId, params->ssid, + params->ssid_len); + pConfig->SSIDinfo.ssid.length = params->ssid_len; + + switch (params->hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hddLog(LOG1, "HIDDEN_SSID_NOT_IN_USE"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_NOT_IN_USE; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + hddLog(LOG1, "HIDDEN_SSID_ZERO_LEN"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_ZERO_LEN; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hddLog(LOG1, "HIDDEN_SSID_ZERO_CONTENTS"); + pConfig->SSIDinfo.ssidHidden = + eHIDDEN_SSID_ZERO_CONTENTS; + break; + default: + hddLog(LOGE, "Wrong hidden_ssid param %d", + params->hidden_ssid); + break; + } + } +#else + if (ssid != NULL) { + cdf_mem_copy(pConfig->SSIDinfo.ssid.ssId, ssid, ssid_len); + pConfig->SSIDinfo.ssid.length = ssid_len; + + switch (hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hddLog(LOG1, "HIDDEN_SSID_NOT_IN_USE"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_NOT_IN_USE; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + hddLog(LOG1, "HIDDEN_SSID_ZERO_LEN"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_ZERO_LEN; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hddLog(LOG1, "HIDDEN_SSID_ZERO_CONTENTS"); + pConfig->SSIDinfo.ssidHidden = + eHIDDEN_SSID_ZERO_CONTENTS; + break; + default: + hddLog(LOGE, "Wrong hidden_ssid param %d", hidden_ssid); + break; + } + } +#endif + + cdf_mem_copy(pConfig->self_macaddr.bytes, + pHostapdAdapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + + /* default value */ + pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + pConfig->num_accept_mac = 0; + pConfig->num_deny_mac = 0; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + /* + * We don't want P2PGO to follow STA's channel + * so lets limit the logic for SAP only. + * Later if we decide to make p2pgo follow STA's + * channel then remove this check. + */ + if ((0 == pHddCtx->config->conc_custom_rule1) || + (pHddCtx->config->conc_custom_rule1 && + WLAN_HDD_SOFTAP == pHostapdAdapter->device_mode)) + pConfig->cc_switch_mode = iniConfig->WlanMccToSccSwitchMode; +#endif + + pIe = + wlan_hdd_get_vendor_oui_ie_ptr(BLACKLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE, pBeacon->tail, + pBeacon->tail_len); + + /* pIe for black list is following form: + * type : 1 byte + * length : 1 byte + * OUI : 4 bytes + * acl type : 1 byte + * no of mac addr in black list: 1 byte + * list of mac_acl_entries: variable, 6 bytes per mac + * address + sizeof(int) for vlan id + */ + if ((pIe != NULL) && (pIe[1] != 0)) { + pConfig->SapMacaddr_acl = pIe[6]; + pConfig->num_deny_mac = pIe[7]; + hddLog(LOG1, + FL("acl type = %d no deny mac = %d"), pIe[6], pIe[7]); + if (pConfig->num_deny_mac > MAX_ACL_MAC_ADDRESS) + pConfig->num_deny_mac = MAX_ACL_MAC_ADDRESS; + acl_entry = (struct qc_mac_acl_entry *)(pIe + 8); + for (i = 0; i < pConfig->num_deny_mac; i++) { + cdf_mem_copy(&pConfig->deny_mac[i], acl_entry->addr, + sizeof(qcmacaddr)); + acl_entry++; + } + } + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WHITELIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE, pBeacon->tail, + pBeacon->tail_len); + + /* pIe for white list is following form: + * type : 1 byte + * length : 1 byte + * OUI : 4 bytes + * acl type : 1 byte + * no of mac addr in white list: 1 byte + * list of mac_acl_entries: variable, 6 bytes per mac + * address + sizeof(int) for vlan id + */ + if ((pIe != NULL) && (pIe[1] != 0)) { + pConfig->SapMacaddr_acl = pIe[6]; + pConfig->num_accept_mac = pIe[7]; + hddLog(LOG1, FL("acl type = %d no accept mac = %d"), + pIe[6], pIe[7]); + if (pConfig->num_accept_mac > MAX_ACL_MAC_ADDRESS) + pConfig->num_accept_mac = MAX_ACL_MAC_ADDRESS; + acl_entry = (struct qc_mac_acl_entry *)(pIe + 8); + for (i = 0; i < pConfig->num_accept_mac; i++) { + cdf_mem_copy(&pConfig->accept_mac[i], acl_entry->addr, + sizeof(qcmacaddr)); + acl_entry++; + } + } + + wlan_hdd_set_sap_hwmode(pHostapdAdapter); + cdf_mem_zero(&sme_config, sizeof(tSmeConfigParams)); + sme_get_config_param(pHddCtx->hHal, &sme_config); + /* Override hostapd.conf wmm_enabled only for 11n and 11AC configs (IOT) + * As per spec 11N/AC STA are QOS STA and may not connect or throughput + * may not be good with non QOS 11N AP + * Default: enable QOS for SAP unless WMM IE not present for 11bga + */ + sme_config.csrConfig.WMMSupportMode = eCsrRoamWmmAuto; + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WMM_OUI_TYPE, WMM_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + if (!pIe && (pConfig->SapHw_mode == eCSR_DOT11_MODE_11a || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11g || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11b)) + sme_config.csrConfig.WMMSupportMode = eCsrRoamWmmNoQos; + sme_update_config(pHddCtx->hHal, &sme_config); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + /* Linux kernel < 3.8 does not support ch width param. So for + * 11AC get from ch width from ini file only if ht40 is enabled + * VHT80 depends on HT40 config. + */ + if (pConfig->SapHw_mode == eCSR_DOT11_MODE_11ac) + if (pConfig->ch_width_orig == NL80211_CHAN_WIDTH_40) + pConfig->ch_width_orig = iniConfig->vhtChannelWidth; +#endif + + if (pConfig->ch_width_orig == NL80211_CHAN_WIDTH_80P80) { + if (pHddCtx->isVHT80Allowed == false) + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + else + pConfig->ch_width_orig = CH_WIDTH_80P80MHZ; + } else if (pConfig->ch_width_orig == NL80211_CHAN_WIDTH_160) { + if (pHddCtx->isVHT80Allowed == false) + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + else + pConfig->ch_width_orig = CH_WIDTH_160MHZ; + } else if (pConfig->ch_width_orig == NL80211_CHAN_WIDTH_80) { + if (pHddCtx->isVHT80Allowed == false) + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + else + pConfig->ch_width_orig = CH_WIDTH_80MHZ; + } else if (pConfig->ch_width_orig == NL80211_CHAN_WIDTH_40) { + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + } else { + pConfig->ch_width_orig = CH_WIDTH_20MHZ; + } + + if (wlan_hdd_setup_driver_overrides(pHostapdAdapter)) + return -EINVAL; + + /* ht_capab is not what the name conveys,this is used for protection + * bitmap */ + pConfig->ht_capab = iniConfig->apProtection; + + if (0 != wlan_hdd_cfg80211_update_apies(pHostapdAdapter)) { + hddLog(LOGE, FL("SAP Not able to set AP IEs")); + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + return -EINVAL; + } + /* Uapsd Enabled Bit */ + pConfig->UapsdEnable = iniConfig->apUapsdEnabled; + /* Enable OBSS protection */ + pConfig->obssProtEnabled = iniConfig->apOBSSProtEnabled; + + if (pHostapdAdapter->device_mode == WLAN_HDD_SOFTAP) + pConfig->sap_dot11mc = + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config->sap_dot11mc; + else /* for P2P-Go case */ + pConfig->sap_dot11mc = 1; + + hddLog(LOG1, FL("11MC Support Enabled : %d\n"), + pConfig->sap_dot11mc); + +#ifdef WLAN_FEATURE_11W + pConfig->mfpCapable = MFPCapable; + pConfig->mfpRequired = MFPRequired; + hddLog(LOG1, FL("Soft AP MFP capable %d, MFP required %d"), + pConfig->mfpCapable, pConfig->mfpRequired); +#endif + + hddLog(LOGW, FL("SOftAP macaddress : " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHostapdAdapter->macAddressCurrent.bytes)); + hddLog(LOGW, FL("ssid =%s, beaconint=%d, channel=%d"), + pConfig->SSIDinfo.ssid.ssId, (int)pConfig->beacon_int, + (int)pConfig->channel); + hddLog(LOGW, FL("hw_mode=%x, privacy=%d, authType=%d"), + pConfig->SapHw_mode, pConfig->privacy, pConfig->authType); + hddLog(LOGW, FL("RSN/WPALen=%d, Uapsd = %d"), + (int)pConfig->RSNWPAReqIELength, pConfig->UapsdEnable); + hddLog(LOGW, FL("ProtEnabled = %d, OBSSProtEnabled = %d"), + pConfig->protEnabled, pConfig->obssProtEnabled); + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + /* Bss already started. just return. */ + /* TODO Probably it should update some beacon params. */ + hddLog(LOGE, "Bss Already started...Ignore the request"); + EXIT(); + return 0; + } + + if (!cds_allow_concurrency(pHddCtx, + cds_convert_device_mode_to_hdd_type( + pHostapdAdapter->device_mode), + pConfig->channel, HW_MODE_20_MHZ)) { + hddLog(LOGW, + FL("This concurrency combination is not allowed")); + return -EINVAL; + } + + if (!cds_set_connection_in_progress(pHddCtx, true)) { + hdd_err("Can't start BSS: set connnection in progress failed"); + return -EINVAL; + } + + pConfig->persona = pHostapdAdapter->device_mode; + + pSapEventCallback = hdd_hostapd_sap_event_cb; + + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->dfs_cac_block_tx = true; + + cdf_event_reset(&pHostapdState->cdf_event); + status = wlansap_start_bss( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), +#else + p_cds_context, +#endif + pSapEventCallback, pConfig, + pHostapdAdapter->dev); + if (!CDF_IS_STATUS_SUCCESS(status)) { + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + cds_set_connection_in_progress(pHddCtx, false); + hddLog(LOGE, FL("SAP Start Bss fail")); + return -EINVAL; + } + + hddLog(LOG1, + FL("Waiting for Scan to complete(auto mode) and BSS to start")); + + status = cdf_wait_single_event(&pHostapdState->cdf_event, 10000); + + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("ERROR: HDD cdf wait for single_event failed!!")); + cds_set_connection_in_progress(pHddCtx, false); + sme_get_command_q_status(hHal); +#ifdef WLAN_FEATURE_MBSSID + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); +#else + wlansap_stop_bss(p_cds_context); +#endif + CDF_ASSERT(0); + return -EINVAL; + } + /* Succesfully started Bss update the state bit. */ + set_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + /* Initialize WMM configuation */ + hdd_wmm_init(pHostapdAdapter); + cds_incr_active_session(pHddCtx, pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); +#ifdef DHCP_SERVER_OFFLOAD + if (iniConfig->enableDHCPServerOffload) + wlan_hdd_set_dhcp_server_offload(pHostapdAdapter); +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO) { + if (global_p2p_connection_status == P2P_GO_NEG_COMPLETED) { + global_p2p_connection_status = P2P_GO_COMPLETED_STATE; + hddLog(LOGE, + FL("[P2P State] From Go nego completed to Non-autonomous Group started")); + } else if (global_p2p_connection_status == P2P_NOT_ACTIVE) { + global_p2p_connection_status = P2P_GO_COMPLETED_STATE; + hddLog(LOGE, + FL("[P2P State] From Inactive to Autonomous Group started")); + } + } +#endif + + cds_set_connection_in_progress(pHddCtx, false); + pHostapdState->bCommit = true; + EXIT(); + + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +/** + * __wlan_hdd_cfg80211_add_beacon() - add beacon in soft ap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to add beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_BEACON, + pAdapter->sessionId, params->interval)); + hddLog(LOG2, FL("Device mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if (!cds_allow_concurrency(pHddCtx, + cds_convert_device_mode_to_hdd_type( + pAdapter->device_mode), 0, HDD_20_MHZ)) { + hddLog(LOGE, + FL("This concurrency combination is not allowed")); + return -EINVAL; + } + + if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) || + (pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + beacon_data_t *old, *new; + + old = pAdapter->sessionCtx.ap.beacon; + + if (old) { + hddLog(LOGW, + FL("already beacon info added to session(%d)"), + pAdapter->sessionId); + return -EALREADY; + } + + status = + wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, + &new, params); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, + FL("Error!!! Allocating the new beacon")); + return -EINVAL; + } + + pAdapter->sessionCtx.ap.beacon = new; + + status = wlan_hdd_cfg80211_start_bss(pAdapter, params); + if (0 != status) { + pAdapter->sessionCtx.ap.beacon = NULL; + kfree(new); + } + } + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_add_beacon() - add beacon in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @param: Pointer to beacon parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_beacon(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_beacon() - set beacon in soft ap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to set beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_BEACON, + pAdapter->sessionId, pHddStaCtx->conn_info.authType)); + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) || + (pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + beacon_data_t *old, *new; + + old = pAdapter->sessionCtx.ap.beacon; + + if (!old) { + hddLog(LOGE, + FL("session(%d) old and new heads points to NULL"), + pAdapter->sessionId); + return -ENOENT; + } + + status = + wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, + &new, params); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, + FL("Error!!! Allocating the new beacon")); + return -EINVAL; + } + + pAdapter->sessionCtx.ap.beacon = new; + status = wlan_hdd_cfg80211_start_bss(pAdapter, params); + } + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_beacon() - set beacon in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @param: Pointer to beacon parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_beacon(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +/** + * __wlan_hdd_cfg80211_del_beacon() - stop soft ap + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_del_beacon(struct wiphy *wiphy, + struct net_device *dev) +#else +/** + * __wlan_hdd_cfg80211_stop_ap() - stop soft ap + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +#endif +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = NULL; + hdd_scaninfo_t *pScanInfo = NULL; + hdd_adapter_t *staAdapter = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSirUpdateIE updateIE; + beacon_data_t *old; + int ret; + unsigned long rc; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_STOP_AP, + pAdapter->sessionId, pAdapter->device_mode)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (!(pAdapter->device_mode == WLAN_HDD_SOFTAP || + pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + return -EOPNOTSUPP; + } + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + staAdapter = pAdapterNode->pAdapter; + + if (WLAN_HDD_INFRA_STATION == staAdapter->device_mode || + (WLAN_HDD_P2P_CLIENT == staAdapter->device_mode) || + (WLAN_HDD_P2P_GO == staAdapter->device_mode)) { + pScanInfo = &staAdapter->scan_info; + + if (pScanInfo && pScanInfo->mScanPending) { + hddLog(LOG1, FL("Aborting pending scan for device mode:%d"), + staAdapter->device_mode); + INIT_COMPLETION(pScanInfo->abortscan_event_var); + hdd_abort_mac_scan(staAdapter->pHddCtx, + staAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + rc = wait_for_completion_timeout( + &pScanInfo->abortscan_event_var, + msecs_to_jiffies( + WLAN_WAIT_TIME_ABORTSCAN)); + if (!rc) { + hddLog(LOGE, + FL("Timeout occurred while waiting for abortscan")); + CDF_ASSERT(pScanInfo->mScanPending); + } + } + } + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + /* + * When ever stop ap adapter gets called, we need to check + * whether any restart AP work is pending. If any restart is pending + * then lets finish it and go ahead from there. + */ + if (pHddCtx->config->conc_custom_rule1 && + (WLAN_HDD_SOFTAP == pAdapter->device_mode)) { + cds_flush_work(&pHddCtx->sap_start_work); + hddLog(LOGW, FL("Canceled the pending restart work")); + spin_lock(&pHddCtx->sap_update_info_lock); + pHddCtx->is_sap_restart_required = false; + spin_unlock(&pHddCtx->sap_update_info_lock); + } + pAdapter->sessionCtx.ap.sapConfig.acs_cfg.acs_mode = false; + if (pAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list) + cdf_mem_free(pAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list); + cdf_mem_zero(&pAdapter->sessionCtx.ap.sapConfig.acs_cfg, + sizeof(struct sap_acs_cfg)); + hdd_hostapd_stop(dev); + + old = pAdapter->sessionCtx.ap.beacon; + if (!old) { + hddLog(LOGE, + FL("Session(%d) beacon data points to NULL"), + pAdapter->sessionId); + return -EINVAL; + } + + hdd_cleanup_actionframe(pHddCtx, pAdapter); + + mutex_lock(&pHddCtx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags)) { + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + cdf_event_reset(&pHostapdState->cdf_stop_bss_event); +#ifdef WLAN_FEATURE_MBSSID + status = wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter)); +#else + status = wlansap_stop_bss(pHddCtx->pcds_context); +#endif + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + cdf_wait_single_event(&pHostapdState-> + cdf_stop_bss_event, + 10000); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL("HDD cdf wait for single_event failed!!")); + CDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags); + /*BSS stopped, clear the active sessions for this device mode*/ + cds_decr_session_set_pcl(pHddCtx, + pAdapter->device_mode, + pAdapter->sessionId); + pAdapter->sessionCtx.ap.beacon = NULL; + kfree(old); + } + mutex_unlock(&pHddCtx->sap_lock); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Stopping the BSS")); + return -EINVAL; + } + + cdf_mem_copy(updateIE.bssid, pAdapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = pAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Could not pass on PROBE_RSP_BCN data to PE")); + } + + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Could not pass on ASSOC_RSP data to PE")); + } + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(pAdapter); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if ((pAdapter->device_mode == WLAN_HDD_P2P_GO) && + (global_p2p_connection_status == P2P_GO_COMPLETED_STATE)) { + hddLog(LOGE, + "[P2P State] From GO completed to Inactive state GO got removed"); + global_p2p_connection_status = P2P_NOT_ACTIVE; + } +#endif + EXIT(); + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) +/** + * wlan_hdd_get_channel_bw() - get channel bandwidth + * @width: input channel width in nl80211_chan_width value + * + * Return: channel width value defined by driver + */ +static enum hw_mode_bandwidth wlan_hdd_get_channel_bw( + enum nl80211_chan_width width) +{ + enum hw_mode_bandwidth ch_bw = HW_MODE_20_MHZ; + + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + ch_bw = HW_MODE_20_MHZ; + break; + case NL80211_CHAN_WIDTH_40: + ch_bw = HW_MODE_40_MHZ; + break; + case NL80211_CHAN_WIDTH_80: + ch_bw = HW_MODE_80_MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + ch_bw = HW_MODE_80_PLUS_80_MHZ; + break; + case NL80211_CHAN_WIDTH_160: + ch_bw = HW_MODE_160_MHZ; + break; + default: + hdd_err("Invalid width: %d, using default 20MHz", width); + break; + } + + return ch_bw; +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WITH_BACKPORTS) +/** + * wlan_hdd_cfg80211_del_beacon() - delete beacon in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_del_beacon(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_beacon(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#else +/** + * wlan_hdd_cfg80211_stop_ap() - stop sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stop_ap(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)) +/** + * __wlan_hdd_cfg80211_start_ap() - start soft ap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to AP settings parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + tSirWifiChannelWidth channel_width; + int status; + uint8_t channel; + p_cds_contextType p_cds_context; + + ENTER(); + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("Invalid CDS context"); + return -EINVAL; + } + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_START_AP, pAdapter->sessionId, + params->beacon_interval)); + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hddLog(LOGE, FL("HDD adapter magic is invalid")); + return -ENODEV; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + hddLog(LOG2, FL("pAdapter = %p, Device mode %s(%d)"), pAdapter, + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + channel_width = wlan_hdd_get_channel_bw(params->chandef.width); + channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); +#else + channel_width = HW_MODE_20_MHZ; + channel = 0; +#endif + /* check if concurrency is allowed */ + if (!cds_allow_concurrency(pHddCtx, + cds_convert_device_mode_to_hdd_type( + pAdapter->device_mode), + channel, + channel_width)) { + hdd_err("Connection failed due to concurrency check failure"); + return -EINVAL; + } + if (pHddCtx->config->policy_manager_enabled) { + status = cdf_event_reset( + &p_cds_context->connection_update_done_evt); + if (!CDF_IS_STATUS_SUCCESS(status)) + hdd_err("ERR: clear event failed"); + + status = cds_current_connections_update(pHddCtx, channel); + if (CDF_STATUS_E_FAILURE == status) { + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (CDF_STATUS_SUCCESS == status) { + status = cdf_wait_single_event( + &p_cds_context->connection_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: cdf wait for event failed!!"); + return -EINVAL; + } + } + } + + if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) + || (pAdapter->device_mode == WLAN_HDD_P2P_GO) + ) { + beacon_data_t *old, *new; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type; +#endif + + old = pAdapter->sessionCtx.ap.beacon; + + if (old) + return -EALREADY; + + status = + wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, &new, + ¶ms->beacon, + params->dtim_period); + + if (status != 0) { + hddLog(LOGE, FL("Error!!! Allocating the new beacon")); + return -EINVAL; + } + pAdapter->sessionCtx.ap.beacon = new; + + if (params->chandef.width < NL80211_CHAN_WIDTH_80) + channel_type = cfg80211_get_chandef_type( + &(params->chandef)); + else + channel_type = NL80211_CHAN_HT40PLUS; + + + wlan_hdd_set_channel(wiphy, dev, + ¶ms->chandef, + channel_type); + + /* set authentication type */ + switch (params->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_OPEN_SYSTEM; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_SHARED_KEY; + break; + default: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_AUTO_SWITCH; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + pAdapter->sessionCtx.ap.sapConfig.ch_width_orig = + params->chandef.width; +#endif + status = + wlan_hdd_cfg80211_start_bss(pAdapter, + ¶ms->beacon, + params->ssid, params->ssid_len, + params->hidden_ssid); + } + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_start_ap() - start sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to start ap configuration parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_start_ap(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_change_beacon() - change beacon for sofatap/p2p go + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to change beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + beacon_data_t *old, *new; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BEACON, + pAdapter->sessionId, pAdapter->device_mode)); + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if (!(pAdapter->device_mode == WLAN_HDD_SOFTAP || + pAdapter->device_mode == WLAN_HDD_P2P_GO)) { + return -EOPNOTSUPP; + } + + old = pAdapter->sessionCtx.ap.beacon; + + if (!old) { + hddLog(LOGE, FL("session(%d) beacon data points to NULL"), + pAdapter->sessionId); + return -EINVAL; + } + + status = wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, &new, params, 0); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("new beacon alloc failed")); + return -EINVAL; + } + + pAdapter->sessionCtx.ap.beacon = new; + status = wlan_hdd_cfg80211_start_bss(pAdapter, params, NULL, 0, 0); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_change_beacon() - change beacon content in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to change beacon parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_beacon(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)) */ diff --git a/core/hdd/src/wlan_hdd_hostapd.h b/core/hdd/src/wlan_hdd_hostapd.h new file mode 100644 index 0000000000..02965d8457 --- /dev/null +++ b/core/hdd/src/wlan_hdd_hostapd.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_HOSTAPD_H) +#define WLAN_HDD_HOSTAPD_H + +/** + * DOC: wlan_hdd_hostapd.h + * + * WLAN Host Device driver hostapd header file + */ + +/* Include files */ + +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +/* max length of command string in hostapd ioctl */ +#define HOSTAPD_IOCTL_COMMAND_STRLEN_MAX 8192 + +hdd_adapter_t *hdd_wlan_create_ap_dev(hdd_context_t *pHddCtx, + tSirMacAddr macAddr, uint8_t *name); + +CDF_STATUS hdd_register_hostapd(hdd_adapter_t *pAdapter, uint8_t rtnl_held); + +CDF_STATUS hdd_unregister_hostapd(hdd_adapter_t *pAdapter, bool rtnl_held); + +eCsrAuthType +hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]); + +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +eCsrAuthType +hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]); + +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]); + +CDF_STATUS hdd_softap_sta_deauth(hdd_adapter_t *, + struct tagCsrDelStaParams *); +void hdd_softap_sta_disassoc(hdd_adapter_t *, uint8_t *); +void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *, bool); +int hdd_softap_unpack_ie(tHalHandle halHandle, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, + bool *pMFPCapable, + bool *pMFPRequired, + uint16_t gen_ie_len, uint8_t *gen_ie); + +CDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *usrDataForCallback); +CDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter); +void hdd_set_ap_ops(struct net_device *pWlanHostapdDev); +int hdd_hostapd_stop(struct net_device *dev); +void hdd_hostapd_channel_wakelock_init(hdd_context_t *pHddCtx); +void hdd_hostapd_channel_wakelock_deinit(hdd_context_t *pHddCtx); +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +void hdd_restart_softap(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ +#ifdef QCA_HT_2040_COEX +CDF_STATUS hdd_set_sap_ht2040_mode(hdd_adapter_t *pHostapdAdapter, + uint8_t channel_type); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +int wlan_hdd_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); + +int wlan_hdd_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) +int wlan_hdd_cfg80211_del_beacon(struct wiphy *wiphy, + struct net_device *dev); +#else +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev); +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)) +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params); +#endif + +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params); + +CDF_STATUS wlan_hdd_config_acs(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); +#endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c new file mode 100644 index 0000000000..43c213ffa3 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -0,0 +1,6314 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include Files */ + +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_driver_ops.h" +#include "cds_concurrency.h" + +#include "wlan_hdd_p2p.h" +#include +#include "wma.h" +#include "wlan_hdd_napi.h" + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +#include +#include +#endif +#include "hif.h" + +#if defined(LINUX_QCMBR) +#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13) +#endif + +/* + * Size of Driver command strings from upper layer + */ +#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ +#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ + + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +#define TID_MIN_VALUE 0 +#define TID_MAX_VALUE 15 +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +/* + * Maximum buffer size used for returning the data back to user space + */ +#define WLAN_MAX_BUF_SIZE 1024 +#define WLAN_PRIV_DATA_MAX_LEN 8192 + +/* + * Driver miracast parameters 0-Disabled + * 1-Source, 2-Sink + */ +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0 +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2 + +/* + * When ever we need to print IBSSPEERINFOALL for more than 16 STA + * we will split the printing. + */ +#define NUM_OF_STA_DATA_TO_PRINT 16 + +/* + * Android DRIVER command structures + */ +struct android_wifi_reassoc_params { + unsigned char bssid[18]; + int channel; +}; + +#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040 +struct android_wifi_af_params { + unsigned char bssid[18]; + int channel; + int dwell_time; + int len; + unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE]; +}; + +/* + * Define HDD driver command handling entry, each contains a command + * string and the handler. + */ +typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *cmd, + uint8_t cmd_name_len, + hdd_priv_data_t *priv_data); + +typedef struct { + const char *cmd; + hdd_drv_cmd_handler_t handler; +} hdd_drv_cmd_t; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000 +#define WLAN_HDD_MAX_TCP_PORT 65535 +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics, + const uint32_t staId, void *context) +{ + struct statsContext *stats_context = NULL; + hdd_adapter_t *adapter = NULL; + + if (NULL == context) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, context [%p]", __func__, context); + return; + } + + /* + * there is a race condition that exists between this callback + * function and the caller since the caller could time out either + * before or while this code is executing. we use a spinlock to + * serialize these actions + */ + spin_lock(&hdd_context_lock); + + stats_context = context; + adapter = stats_context->pAdapter; + if ((NULL == adapter) || + (STATS_CONTEXT_MAGIC != stats_context->magic)) { + /* + * the caller presumably timed out so there is + * nothing we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, adapter [%p] magic [%08x]", + __func__, adapter, stats_context->magic); + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + stats_context->magic = 0; + + /* copy over the tsm stats */ + adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly; + cdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist, + tsm_metrics.UplinkPktQueueDlyHist, + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) / + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0])); + adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly; + adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss; + adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount; + adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount; + adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly; + + /* notify the caller */ + complete(&stats_context->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +static +CDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter, + const uint8_t tid, + tAniTrafStrmMetrics *tsm_metrics) +{ + hdd_station_ctx_t *hdd_sta_ctx = NULL; + CDF_STATUS hstatus; + CDF_STATUS vstatus = CDF_STATUS_SUCCESS; + unsigned long rc; + struct statsContext context; + hdd_context_t *hdd_ctx = NULL; + + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: adapter is NULL", __func__); + return CDF_STATUS_E_FAULT; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* we are connected prepare our callback context */ + init_completion(&context.completion); + context.pAdapter = adapter; + context.magic = STATS_CONTEXT_MAGIC; + + /* query tsm stats */ + hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb, + hdd_sta_ctx->conn_info.staId[0], + hdd_sta_ctx->conn_info.bssId, + &context, hdd_ctx->pcds_context, tid); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve statistics", __func__); + vstatus = CDF_STATUS_E_FAULT; + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME timed out while retrieving statistics", + __func__); + vstatus = CDF_STATUS_E_TIMEOUT; + } + } + + /* + * either we never sent a request, we sent a request and received a + * response or we sent a request and timed out. if we never sent a + * request or if we sent a request and got a response, we want to + * clear the magic out of paranoia. if we timed out there is a + * race condition such that the callback function could be + * executing at the same time we are. of primary concern is if the + * callback function had already verified the "magic" but had not + * yet set the completion variable when a timeout occurred. we + * serialize these activities by invalidating the magic while + * holding a shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + if (CDF_STATUS_SUCCESS == vstatus) { + tsm_metrics->UplinkPktQueueDly = + adapter->tsmStats.UplinkPktQueueDly; + cdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist, + adapter->tsmStats.UplinkPktQueueDlyHist, + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) / + sizeof(adapter->tsmStats. + UplinkPktQueueDlyHist[0])); + tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly; + tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss; + tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount; + tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount; + tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly; + } + return vstatus; +} +#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand) +{ + eCsrBand band = -1; + sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band); + switch (band) { + case eCSR_BAND_ALL: + *pBand = WLAN_HDD_UI_BAND_AUTO; + break; + + case eCSR_BAND_24: + *pBand = WLAN_HDD_UI_BAND_2_4_GHZ; + break; + + case eCSR_BAND_5G: + *pBand = WLAN_HDD_UI_BAND_5_GHZ; + break; + + default: + hddLog(CDF_TRACE_LEVEL_WARN, "%s: Invalid Band %d", __func__, + band); + *pBand = -1; + break; + } +} + +/** + * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel + * @data: input data + * @target_ap_bssid: pointer to bssid (output parameter) + * @channel: pointer to channel (output parameter) + * + * Return: 0 if parsing is successful; -EINVAL otherwise + */ +static int _hdd_parse_bssid_and_chan(const uint8_t **data, + uint8_t *bssid, + uint8_t *channel) +{ + const uint8_t *in_ptr; + int v = 0; + int temp_int; + uint8_t temp_buf[32]; + + /* 12 hexa decimal digits, 5 ':' and '\0' */ + uint8_t mac_addr[18]; + + if (!data || !*data) + return -EINVAL; + + in_ptr = *data; + + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == in_ptr) + goto error; + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + v = sscanf(in_ptr, "%17s", mac_addr); + if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) { + hddLog(LOGE, + FL( + "Invalid MAC address or All hex inputs are not read (%d)" + ), + v); + goto error; + } + + bssid[0] = hex_to_bin(mac_addr[0]) << 4 | + hex_to_bin(mac_addr[1]); + bssid[1] = hex_to_bin(mac_addr[3]) << 4 | + hex_to_bin(mac_addr[4]); + bssid[2] = hex_to_bin(mac_addr[6]) << 4 | + hex_to_bin(mac_addr[7]); + bssid[3] = hex_to_bin(mac_addr[9]) << 4 | + hex_to_bin(mac_addr[10]); + bssid[4] = hex_to_bin(mac_addr[12]) << 4 | + hex_to_bin(mac_addr[13]); + bssid[5] = hex_to_bin(mac_addr[15]) << 4 | + hex_to_bin(mac_addr[16]); + + /* point to the next argument */ + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + /* get the next argument ie the channel number */ + v = sscanf(in_ptr, "%31s ", temp_buf); + if (1 != v) + goto error; + + v = kstrtos32(temp_buf, 10, &temp_int); + if ((v < 0) || (temp_int < 0) || + (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) + return -EINVAL; + + *channel = temp_int; + *data = in_ptr; + return 0; +error: + *data = in_ptr; + return -EINVAL; +} + +/** + * hdd_parse_send_action_frame_data() - HDD Parse send action frame data + * @pValue: Pointer to input data + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * @pDwellTime: Pointer to the time to stay off-channel + * after transmitting action frame + * @pBuf: Pointer to data + * @pBufLen: Pointer to data length + * + * This function parses the send action frame data passed in the format + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_send_action_frame_v1_data(const uint8_t *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel, uint8_t *pDwellTime, + uint8_t **pBuf, uint8_t *pBufLen) +{ + const uint8_t *inPtr = pValue; + const uint8_t *dataEnd; + int tempInt; + int j = 0; + int i = 0; + int v = 0; + uint8_t tempBuf[32]; + uint8_t tempByte = 0; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* getting the next argument ie the dwell time */ + v = sscanf(inPtr, "%31s ", tempBuf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(tempBuf, 10, &tempInt); + if (v < 0 || tempInt < 0) + return -EINVAL; + + *pDwellTime = tempInt; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) { + dataEnd++; + } + *pBufLen = dataEnd - inPtr; + if (*pBufLen <= 0) + return -EINVAL; + + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N/2 byte. + * if the number of input characters are odd, then we need do (N+1)/2 + * to compensate rounding off. + * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes + */ + *pBuf = cdf_mem_malloc((*pBufLen + 1) / 2); + if (NULL == *pBuf) { + hddLog(LOGE, FL("cdf_mem_alloc failed")); + return -ENOMEM; + } + + /* the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain 7f + * in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *pBufLen; j += 2) { + if (j + 1 == *pBufLen) { + tempByte = hex_to_bin(inPtr[j]); + } else { + tempByte = + (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + } + (*pBuf)[i++] = tempByte; + } + *pBufLen = i; + return 0; +} + +/** + * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data + * @pValue: Pointer to input data (its a NULL terminated string) + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * + * This function parses the reasoc command data passed in the format + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel) +{ + const uint8_t *inPtr = pValue; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + return 0; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || FEATURE_WLAN_ESE FEATURE_WLAN_LFR */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/** + * hdd_reassoc() - perform a userspace-directed reassoc + * @adapter: Adapter upon which the command was received + * @bssid: BSSID with which to reassociate + * @channel: channel upon which to reassociate + * + * This function performs a userspace-directed reassoc operation + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid, + const uint8_t channel) +{ + hdd_station_ctx_t *pHddStaCtx; + int ret = 0; + + if (WLAN_HDD_INFRA_STATION != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is same as currently associated AP, + * then no need to proceed with reassoc + */ + if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE)) { + hddLog(LOG1, + FL("Reassoc BSSID is same as currently associated AP bssid")); + ret = -EINVAL; + goto exit; + } + + /* Check channel number is a valid channel number */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Invalid Channel %d", + __func__, channel); + ret = -EINVAL; + goto exit; + } + + /* Proceed with reassoc */ + { + tCsrHandoffRequest handoffInfo; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + handoffInfo.channel = channel; + handoffInfo.src = REASSOC; + cdf_mem_copy(handoffInfo.bssid.bytes, bssid, CDF_MAC_ADDR_SIZE); + sme_handoff_request(hdd_ctx->hHal, adapter->sessionId, + &handoffInfo); + } +exit: + return ret; +} + +/** + * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 REASSOC command with the format + * + * REASSOC xx:xx:xx:xx:xx:xx CH + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID and CH is the ASCII representation of the channel. For + * example + * + * REASSOC 00:0a:0b:11:22:33 48 + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command) +{ + uint8_t channel = 0; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel); + if (ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse reassoc command data", __func__); + } else { + ret = hdd_reassoc(adapter, bssid, channel); + } + return ret; +} + +/** + * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 REASSOC command with the format + * + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command) +{ + struct android_wifi_reassoc_params params; + tSirMacAddr bssid; + int ret; + + /* The params are located after "REASSOC " */ + memcpy(¶ms, command + 8, sizeof(params)); + + if (!mac_pton(params.bssid, (u8 *) &bssid)) { + hddLog(LOGE, "%s: MAC address parsing failed", __func__); + ret = -EINVAL; + } else { + ret = hdd_reassoc(adapter, bssid, params.channel); + } + return ret; +} + +/** + * hdd_parse_reassoc() - parse the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the REASSOC command. Version 1 + * of the command contains a parameter list that is ASCII characters + * whereas version 2 contains a combination of ASCII and binary + * payload. Determine if a version 1 or a version 2 command is being + * parsed by examining the parameters, and then dispatch the parser + * that is appropriate for the command. + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command) +{ + int ret; + + /* both versions start with "REASSOC " + * v1 has a bssid and channel # as an ASCII string + * REASSOC xx:xx:xx:xx:xx:xx CH + * v2 has a C struct + * REASSOC + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * REASSOC xx:xx:xx:xx:xx:xx* + * 1111111111222222 + * 01234567890123456789012345 + */ + if (command[25]) { + ret = hdd_parse_reassoc_v1(adapter, command); + } else { + ret = hdd_parse_reassoc_v2(adapter, command); + } + + return ret; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || FEATURE_WLAN_ESE FEATURE_WLAN_LFR */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/** + * hdd_sendactionframe() - send a userspace-supplied action frame + * @adapter: Adapter upon which the command was received + * @bssid: BSSID target of the action frame + * @channel: Channel upon which to send the frame + * @dwell_time: Amount of time to dwell when the frame is sent + * @payload_len:Length of the payload + * @payload: Payload of the frame + * + * This function sends a userspace-supplied action frame + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid, + const uint8_t channel, const uint8_t dwell_time, + const uint8_t payload_len, const uint8_t *payload) +{ + struct ieee80211_channel chan; + uint8_t frame_len; + uint8_t *frame; + struct ieee80211_hdr_3addr *hdr; + u64 cookie; + hdd_station_ctx_t *pHddStaCtx; + hdd_context_t *hdd_ctx; + int ret = 0; + tpSirMacVendorSpecificFrameHdr pVendorSpecific = + (tpSirMacVendorSpecificFrameHdr) payload; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct cfg80211_mgmt_tx_params params; +#endif + + if (WLAN_HDD_INFRA_STATION != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* if not associated, no need to send action frame */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Not associated", __func__); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is different from currently associated AP, + * then no need to send action frame + */ + if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE)) { + hddLog(LOG1, FL("STA is not associated to this AP")); + ret = -EINVAL; + goto exit; + } + + chan.center_freq = sme_chn_to_freq(channel); + /* Check if it is specific action frame */ + if (pVendorSpecific->category == + SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) { + static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 }; + if (cdf_mem_compare(pVendorSpecific->Oui, (void *)Oui, 3)) { + /* + * if the channel number is different from operating + * channel then no need to send action frame + */ + if (channel != 0) { + if (channel != + pHddStaCtx->conn_info.operationChannel) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: channel(%d) is different from operating channel(%d)", + __func__, channel, + pHddStaCtx->conn_info. + operationChannel); + ret = -EINVAL; + goto exit; + } + /* + * If channel number is specified and same + * as home channel, ensure that action frame + * is sent immediately by cancelling + * roaming scans. Otherwise large dwell times + * may cause long delays in sending action + * frames. + */ + sme_abort_roam_scan(hdd_ctx->hHal, + adapter->sessionId); + } else { + /* + * 0 is accepted as current home channel, + * delayed transmission of action frame is ok. + */ + chan.center_freq = + sme_chn_to_freq(pHddStaCtx->conn_info. + operationChannel); + } + } + } + if (chan.center_freq == 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s:invalid channel number %d", + __func__, channel); + ret = -EINVAL; + goto exit; + } + + frame_len = payload_len + 24; + frame = cdf_mem_malloc(frame_len); + if (!frame) { + hddLog(LOGE, FL("memory allocation failed")); + ret = -ENOMEM; + goto exit; + } + cdf_mem_zero(frame, frame_len); + + hdr = (struct ieee80211_hdr_3addr *)frame; + hdr->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); + cdf_mem_copy(hdr->addr1, bssid, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(hdr->addr3, bssid, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(hdr + 1, payload, payload_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + params.chan = &chan; + params.offchan = 0; + params.wait = dwell_time; + params.buf = frame; + params.len = frame_len; + params.no_cck = 1; + params.dont_wait_for_ack = 1; + ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, ¶ms, &cookie); +#else + ret = wlan_hdd_mgmt_tx(NULL, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + &(adapter->wdev), +#else + adapter->dev, +#endif + &chan, 0, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + NL80211_CHAN_HT20, 1, +#endif + dwell_time, frame, frame_len, 1, 1, &cookie); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + + cdf_mem_free(frame); +exit: + return ret; +} + +/** + * hdd_parse_sendactionframe_v1() - parse version 1 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID, CH is the ASCII representation of the channel, DW is the + * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII + * payload. For example + * + * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command) +{ + uint8_t channel = 0; + uint8_t dwell_time = 0; + uint8_t payload_len = 0; + uint8_t *payload = NULL; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel, + &dwell_time, &payload, + &payload_len); + if (ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse send action frame data", __func__); + } else { + ret = hdd_sendactionframe(adapter, bssid, channel, + dwell_time, payload_len, payload); + cdf_mem_free(payload); + } + + return ret; +} + +/** + * hdd_parse_sendactionframe_v2() - parse version 2 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, const char *command) +{ + struct android_wifi_af_params *params; + tSirMacAddr bssid; + int ret; + + /* params are large so keep off the stack */ + params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) + return -ENOMEM; + + /* The params are located after "SENDACTIONFRAME " */ + memcpy(params, command + 16, sizeof(*params)); + + if (!mac_pton(params->bssid, (u8 *) &bssid)) { + hddLog(LOGE, "%s: MAC address parsing failed", __func__); + ret = -EINVAL; + } else { + ret = hdd_sendactionframe(adapter, bssid, params->channel, + params->dwell_time, params->len, + params->data); + } + kfree(params); + return ret; +} + +/** + * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the SENDACTIONFRAME command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a combination of ASCII and + * binary payload. Determine if a version 1 or a version 2 command is + * being parsed by examining the parameters, and then dispatch the + * parser that is appropriate for the version of the command. + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command) +{ + int ret; + + /* + * both versions start with "SENDACTIONFRAME " + * v1 has a bssid and other parameters as an ASCII string + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME + * v2 has a C struct + * SENDACTIONFRAME + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx* + * 111111111122222222223333 + * 0123456789012345678901234567890123 + */ + if (command[33]) { + ret = hdd_parse_sendactionframe_v1(adapter, command); + } else { + ret = hdd_parse_sendactionframe_v2(adapter, command); + } + + return ret; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || FEATURE_WLAN_ESE FEATURE_WLAN_LFR */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/** + * hdd_parse_channellist() - HDD Parse channel list + * @pValue: Pointer to input channel list + * @ChannelList: Pointer to local output array to record + * channel list + * @pNumChannels: Pointer to number of roam scan channels + * + * This function parses the channel list passed in the format + * SETROAMSCANCHANNELSChannel 1Channel 2Channel N + * if the Number of channels (N) does not match with the actual number + * of channels passed then take the minimum of N and count of + * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48, + * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48, + * ignore 5 and take 36, 40, 44 and 48. This function does not take care of + * removing duplicate channels from the list + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList, + uint8_t *pNumChannels) +{ + const uint8_t *inPtr = pValue; + int tempInt; + int j = 0; + int v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* get the first argument ie the number of channels */ + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) { + return -EINVAL; + } + + *pNumChannels = tempInt; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Number of channels are: %d", *pNumChannels); + + for (j = 0; j < (*pNumChannels); j++) { + /* + * inPtr pointing to the beginning of first space after number + * of channels + */ + inPtr = strpbrk(inPtr, " "); + /* no channel list after the number of channels argument */ + if (NULL == inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* + * no channel list after the number of channels + * argument and spaces + */ + if ('\0' == *inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || + (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + return -EINVAL; + } + pChannelList[j] = tempInt; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Channel %d added to preferred channel list", + pChannelList[j]); + } + + return 0; +} + +/** + * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS N C1 C2 ... Cn + * + * Where "N" is the ASCII representation of the number of channels and + * C1 thru Cn is the ASCII representation of the channels. For example + * + * SETROAMSCANCHANNELS 4 36 40 44 48 + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter, + const char *command) +{ + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t num_chan = 0; + CDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ret = hdd_parse_channellist(command, channel_list, &num_chan); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse channel list information", + __func__); + goto exit; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, num_chan)); + + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: number of channels (%d) supported exceeded max (%d)", + __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + status = + sme_change_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + channel_list, num_chan); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to update channel list information", + __func__); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS [N][C1][C2][Cn] + * + * The command begins with SETROAMSCANCHANNELS followed by a space, but + * what follows the space is an array of u08 parameters. For example + * + * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30] + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter, + const char *command) +{ + const uint8_t *value; + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t channel; + uint8_t num_chan; + int i; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + CDF_STATUS status; + int ret = 0; + + /* array of values begins after "SETROAMSCANCHANNELS " */ + value = command + 20; + + num_chan = *value++; + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: number of channels (%d) supported exceeded max (%d)", + __func__, num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, num_chan)); + + for (i = 0; i < num_chan; i++) { + channel = *value++; + if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: index %d invalid channel %d", __func__, + i, channel); + ret = -EINVAL; + goto exit; + } + channel_list[i] = channel; + } + status = + sme_change_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + channel_list, num_chan); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to update channel list information", + __func__); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels() - parse the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the SETROAMSCANCHANNELS command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a binary payload. Determine + * if a version 1 or a version 2 command is being parsed by examining + * the parameters, and then dispatch the parser that is appropriate for + * the command. + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command) +{ + const char *cursor; + char ch; + bool v1; + int ret; + + /* start after "SETROAMSCANCHANNELS " */ + cursor = command + 20; + + /* assume we have a version 1 command until proven otherwise */ + v1 = true; + + /* v1 params will only contain ASCII digits and space */ + while ((ch = *cursor++) && v1) { + if (!(isdigit(ch) || isspace(ch))) { + v1 = false; + } + } + if (v1) { + ret = hdd_parse_set_roam_scan_channels_v1(adapter, command); + } else { + ret = hdd_parse_set_roam_scan_channels_v2(adapter, command); + } + + return ret; +} +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || FEATURE_WLAN_LFR */ + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * hdd_parse_plm_cmd() - HDD Parse Plm command + * @pValue: Pointer to input data + * @pPlmRequest:Pointer to output struct tpSirPlmReq + * + * This function parses the plm command passed in the format + * CCXPLMREQ + * + * + * + * + * + * Return: 0 for success non-zero for failure + */ +CDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest) +{ + uint8_t *cmdPtr = NULL; + int count, content = 0, ret = 0; + char buf[32]; + + /* move to argument list */ + cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* START/STOP PLM req */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->enable = content; + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Dialog token of radio meas req containing meas reqIE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->diag_token = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "diag token %d", + pPlmRequest->diag_token); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* measurement token of meas req IE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->meas_token = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "meas token %d", + pPlmRequest->meas_token); + + hddLog(CDF_TRACE_LEVEL_ERROR, + "PLM req %s", pPlmRequest->enable ? "START" : "STOP"); + if (pPlmRequest->enable) { + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* total number of bursts after which STA stops sending */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->numBursts = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "num burst %d", + pPlmRequest->numBursts); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst interval in seconds */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content <= 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->burstInt = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "burst Int %d", + pPlmRequest->burstInt); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content <= 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->measDuration = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "measDur %d", + pPlmRequest->measDuration); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst length of PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content <= 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->burstLen = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "burstLen %d", + pPlmRequest->burstLen); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* desired tx power for transmission of PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content <= 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->desiredTxPwr = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, + "desiredTxPwr %d", pPlmRequest->desiredTxPwr); + + for (count = 0; count < CDF_MAC_ADDR_SIZE; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 16, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->macAddr[count] = content; + } + + hddLog(CDF_TRACE_LEVEL_DEBUG, "MC addr " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pPlmRequest->macAddr)); + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* number of channels */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content < 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->plmNumCh = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, "numch %d", + pPlmRequest->plmNumCh); + + /* Channel numbers */ + for (count = 0; count < pPlmRequest->plmNumCh; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return CDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return CDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return CDF_STATUS_E_FAILURE; + + if (content <= 0) + return CDF_STATUS_E_FAILURE; + + pPlmRequest->plmChList[count] = content; + hddLog(CDF_TRACE_LEVEL_DEBUG, " ch- %d", + pPlmRequest->plmChList[count]); + } + } + /* If PLM START */ + return CDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext; + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + hdd_ctx->ext_wow_should_suspend = is_success; + complete(&hdd_ctx->ready_to_extwow); +} + +static int hdd_enable_ext_wow(hdd_adapter_t *adapter, + tpSirExtWoWParams arg_params) +{ + tSirExtWoWParams params; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + int rc; + + cdf_mem_copy(¶ms, arg_params, sizeof(params)); + + INIT_COMPLETION(hdd_ctx->ready_to_extwow); + + cdf_ret_status = sme_configure_ext_wo_w(hHal, ¶ms, + &wlan_hdd_ready_to_extwow, + hdd_ctx); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("sme_configure_ext_wo_w returned failure %d"), + cdf_ret_status); + return -EPERM; + } + + rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow, + msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW)); + if (!rc) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to get ready to extwow", __func__); + return -EPERM; + } + + if (hdd_ctx->ext_wow_should_suspend) { + if (hdd_ctx->config->extWowGotoSuspend) { + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received ready to ExtWoW. Going to suspend", + __func__); + + rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL); + if (rc < 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: wlan_hdd_cfg80211_suspend_wlan failed, error = %d", + __func__, rc); + return rc; + } + cdf_ret_status = wlan_hdd_bus_suspend(state); + if (cdf_ret_status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: wlan_hdd_suspend failed, status = %d", + __func__, cdf_ret_status); + wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy); + return -EPERM; + } + } + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Received ready to ExtWoW failure", __func__); + return -EPERM; + } + + return 0; +} + +static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id, + int value) +{ + tSirExtWoWParams params; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (value < EXT_WOW_TYPE_APP_TYPE1 || + value > EXT_WOW_TYPE_APP_TYPE1_2) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid type")); + return -EINVAL; + } + + if (value == EXT_WOW_TYPE_APP_TYPE1 && + hdd_ctx->is_extwow_app_type1_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE2 && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE1_2 && + hdd_ctx->is_extwow_app_type1_param_set && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Set app params before enable it value %d"), value); + return -EINVAL; + } + + params.vdev_id = vdev_id; + params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber | + (hdd_ctx->config->extWowApp2WakeupPinNumber + << 8); + + return hdd_enable_ext_wow(adapter, ¶ms); +} + +static int hdd_set_app_type1_params(tHalHandle hHal, + tpSirAppType1Params arg_params) +{ + tSirAppType1Params params; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + cdf_mem_copy(¶ms, arg_params, sizeof(params)); + + cdf_ret_status = sme_configure_app_type1_params(hHal, ¶ms); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("sme_configure_app_type1_params returned failure %d"), + cdf_ret_status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type1_parser(hdd_adapter_t *adapter, + char *arg, int len) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + char id[20], password[20]; + tSirAppType1Params params; + int rc, i; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (2 != sscanf(arg, "%8s %16s", id, password)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Invalid Number of arguments")); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(tSirAppType1Params)); + params.vdev_id = adapter->sessionId; + for (i = 0; i < ETHER_ADDR_LEN; i++) + params.wakee_mac_addr[i] = + adapter->macAddressCurrent.bytes[i]; + + params.id_length = strlen(id); + cdf_mem_copy(params.identification_id, id, params.id_length); + params.pass_length = strlen(password); + cdf_mem_copy(params.password, password, params.pass_length); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: %d %pM %.8s %u %.16s %u", + __func__, params.vdev_id, params.wakee_mac_addr, + params.identification_id, params.id_length, + params.password, params.pass_length); + + return hdd_set_app_type1_params(hHal, ¶ms); +} + +static int hdd_set_app_type2_params(tHalHandle hHal, + tpSirAppType2Params arg_params) +{ + tSirAppType2Params params; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + cdf_mem_copy(¶ms, arg_params, sizeof(params)); + + cdf_ret_status = sme_configure_app_type2_params(hHal, ¶ms); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("sme_configure_app_type2_params returned failure %d"), + cdf_ret_status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type2_parser(hdd_adapter_t *adapter, + char *arg, int len) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + char mac_addr[20], rc4_key[20]; + unsigned int gateway_mac[6], i; + tSirAppType2Params params; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(tSirAppType2Params)); + + ret = sscanf(arg, "%17s %16s %x %x %x %u %u %u %u %u %u %u %u %u %u", + mac_addr, rc4_key, (unsigned int *)¶ms.ip_id, + (unsigned int *)¶ms.ip_device_ip, + (unsigned int *)¶ms.ip_server_ip, + (unsigned int *)¶ms.tcp_seq, + (unsigned int *)¶ms.tcp_ack_seq, + (unsigned int *)¶ms.tcp_src_port, + (unsigned int *)¶ms.tcp_dst_port, + (unsigned int *)¶ms.keepalive_init, + (unsigned int *)¶ms.keepalive_min, + (unsigned int *)¶ms.keepalive_max, + (unsigned int *)¶ms.keepalive_inc, + (unsigned int *)¶ms.tcp_tx_timeout_val, + (unsigned int *)¶ms.tcp_rx_timeout_val); + + if (ret != 15 && ret != 7) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Invalid Number of arguments"); + return -EINVAL; + } + + if (6 != + sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0], + &gateway_mac[1], &gateway_mac[2], &gateway_mac[3], + &gateway_mac[4], &gateway_mac[5])) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Invalid MacAddress Input %s", mac_addr); + return -EINVAL; + } + + if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT || + params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Invalid TCP Port Number"); + return -EINVAL; + } + + for (i = 0; i < ETHER_ADDR_LEN; i++) + params.gateway_mac[i] = (uint8_t) gateway_mac[i]; + + params.rc4_key_len = strlen(rc4_key); + cdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len); + + params.vdev_id = adapter->sessionId; + params.tcp_src_port = (params.tcp_src_port != 0) ? + params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort; + params.tcp_dst_port = (params.tcp_dst_port != 0) ? + params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort; + params.keepalive_init = (params.keepalive_init != 0) ? + params.keepalive_init : hdd_ctx->config-> + extWowApp2KAInitPingInterval; + params.keepalive_min = + (params.keepalive_min != 0) ? + params.keepalive_min : + hdd_ctx->config->extWowApp2KAMinPingInterval; + params.keepalive_max = + (params.keepalive_max != 0) ? + params.keepalive_max : + hdd_ctx->config->extWowApp2KAMaxPingInterval; + params.keepalive_inc = + (params.keepalive_inc != 0) ? + params.keepalive_inc : + hdd_ctx->config->extWowApp2KAIncPingInterval; + params.tcp_tx_timeout_val = + (params.tcp_tx_timeout_val != 0) ? + params.tcp_tx_timeout_val : + hdd_ctx->config->extWowApp2TcpTxTimeout; + params.tcp_rx_timeout_val = + (params.tcp_rx_timeout_val != 0) ? + params.tcp_rx_timeout_val : + hdd_ctx->config->extWowApp2TcpRxTimeout; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: %pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u", + __func__, gateway_mac, rc4_key, params.ip_id, + params.ip_device_ip, params.ip_server_ip, params.tcp_seq, + params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port, + params.keepalive_init, params.keepalive_min, + params.keepalive_max, params.keepalive_inc, + params.tcp_tx_timeout_val, params.tcp_rx_timeout_val); + + return hdd_set_app_type2_params(hHal, ¶ms); +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +/** + * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command + * @pValue: Pointer to MAXTXPOWER command + * @pDbm: Pointer to tx power + * + * This function parses the MAXTXPOWER command passed in the format + * MAXTXPOWERX(Tx power in dbm) + * + * For example input commands: + * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm + * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + *pTxPower = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return 0; + } + + v = kstrtos32(inPtr, 10, &tempInt); + + /* Range checking for passed parameter */ + if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) { + return -EINVAL; + } + + *pTxPower = tempInt; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "SETMAXTXPOWER: %d", *pTxPower); + + return 0; +} /* End of hdd_parse_setmaxtxpower_command */ + +static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command, + char *extra, uint8_t n, uint8_t *len) +{ + int ret = 0; + + if (!pCfg || !command || !extra || !len) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: argument passed for GETDWELLTIME is incorrect", + __func__); + ret = -EINVAL; + return ret; + } + + if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", + (int)pCfg->nActiveMaxChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n", + (int)pCfg->nActiveMinChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n", + (int)pCfg->nPassiveMaxChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n", + (int)pCfg->nPassiveMinChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME", 12) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME %u \n", + (int)pCfg->nActiveMaxChnTime); + return ret; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command) +{ + tHalHandle hHal; + struct hdd_config *pCfg; + uint8_t *value = command; + tSmeConfigParams smeConfig; + int val = 0, temp = 0; + + pCfg = (WLAN_HDD_GET_CTX(adapter))->config; + hHal = WLAN_HDD_GET_HAL_CTX(adapter); + if (!pCfg || !hHal) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME is incorrect")); + return -EINVAL; + } + + cdf_mem_zero(&smeConfig, sizeof(smeConfig)); + sme_get_config_param(hHal, &smeConfig); + + if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) { + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME ACTIVE MAX is incorrect")); + return -EFAULT; + } + pCfg->nActiveMaxChnTime = val; + smeConfig.csrConfig.nActiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) { + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME ACTIVE MIN is incorrect")); + return -EFAULT; + } + pCfg->nActiveMinChnTime = val; + smeConfig.csrConfig.nActiveMinChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) { + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME PASSIVE MAX is incorrect")); + return -EFAULT; + } + pCfg->nPassiveMaxChnTime = val; + smeConfig.csrConfig.nPassiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) { + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME PASSIVE MIN is incorrect")); + return -EFAULT; + } + pCfg->nPassiveMinChnTime = val; + smeConfig.csrConfig.nPassiveMinChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME", 12) == 0) { + value = value + 13; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hddLog(LOGE, + FL("argument passed for SETDWELLTIME is incorrect")); + return -EFAULT; + } + pCfg->nActiveMaxChnTime = val; + smeConfig.csrConfig.nActiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else { + return -EINVAL; + } + + return 0; +} + +static void hdd_get_link_status_cb(uint8_t status, void *context) +{ + struct statsContext *pLinkContext; + hdd_adapter_t *adapter; + + if (NULL == context) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Bad context [%p]", + __func__, context); + return; + } + + pLinkContext = context; + adapter = pLinkContext->pAdapter; + + spin_lock(&hdd_context_lock); + + if ((NULL == adapter) || + (LINK_STATUS_MAGIC != pLinkContext->magic)) { + /* + * the caller presumably timed out so there is + * nothing we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, adapter [%p] magic [%08x]", + __func__, adapter, pLinkContext->magic); + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pLinkContext->magic = 0; + + /* copy over the status */ + adapter->linkStatus = status; + + /* notify the caller */ + complete(&pLinkContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_link_status() - get link status + * @pAdapter: pointer to the adapter + * + * This function sends a request to query the link status and waits + * on a timer to invoke the callback. if the callback is invoked then + * latest link status shall be returned or otherwise cached value + * will be returned. + * + * Return: On success, link status shall be returned. + * On error or not associated, link status 0 will be returned. + */ +static int wlan_hdd_get_link_status(hdd_adapter_t *adapter) +{ + + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct statsContext context; + CDF_STATUS hstatus; + unsigned long rc; + + if (hdd_ctx->isLogpInProgress) { + hddLog(LOGW, FL("LOGP in Progress. Ignore!!!")); + return 0; + } + + if ((WLAN_HDD_INFRA_STATION != adapter->device_mode) && + (WLAN_HDD_P2P_CLIENT != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return 0; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + /* If not associated, then expected link status return + * value is 0 + */ + hddLog(LOG1, FL("Not associated!")); + return 0; + } + + init_completion(&context.completion); + context.pAdapter = adapter; + context.magic = LINK_STATUS_MAGIC; + hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter), + hdd_get_link_status_cb, + &context, adapter->sessionId); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve link status", __func__); + /* return a cached value */ + } else { + /* request is sent -- wait for the response */ + rc = wait_for_completion_timeout(&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS)); + if (!rc) + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving link status")); + } + + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + /* either callback updated adapter stats or it has cached data */ + return adapter->linkStatus; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * hdd_parse_ese_beacon_req() - Parse ese beacon request + * @pValue: Pointer to data + * @pEseBcnReq: Output pointer to store parsed ie information + * + * This function parses the ese beacon request passed in the format + * CCXBEACONREQ + * Channel 1Scan Mode Meas DurationChannel N + * Scan Mode NMeas Duration N + * + * If the Number of bcn req fields (N) does not match with the + * actual number of fields passed then take N. + * and are treated + * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40. + * This function does not take care of removing duplicate channels from the + * list + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_ese_beacon_req(uint8_t *pValue, + tCsrEseBeaconReq *pEseBcnReq) +{ + uint8_t *inPtr = pValue; + int tempInt = 0; + int j = 0, i = 0, v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* get the first argument ie measurement token */ + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + pEseBcnReq->numBcnReqIe = tempInt; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "Number of Bcn Req Ie fields(%d)", pEseBcnReq->numBcnReqIe); + + for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) { + for (i = 0; i < 4; i++) { + /* + * inPtr pointing to the beginning of 1st space + * after number of ie fields + */ + inPtr = strpbrk(inPtr, " "); + /* no ie data after the number of ie fields argument */ + if (NULL == inPtr) + return -EINVAL; + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) + && ('\0' != *inPtr)) + inPtr++; + + /* + * no ie data after the number of ie fields + * argument and spaces + */ + if ('\0' == *inPtr) + return -EINVAL; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + switch (i) { + case 0: /* Measurement token */ + if (tempInt <= 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Invalid Measurement Token(%d)", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementToken = + tempInt; + break; + + case 1: /* Channel number */ + if ((tempInt <= 0) || + (tempInt > + WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Invalid Channel Number(%d)", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].channel = tempInt; + break; + + case 2: /* Scan mode */ + if ((tempInt < eSIR_PASSIVE_SCAN) + || (tempInt > eSIR_BEACON_TABLE)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Invalid Scan Mode(%d) Expected{0|1|2}", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].scanMode = tempInt; + break; + + case 3: /* Measurement duration */ + if (((tempInt <= 0) + && (pEseBcnReq->bcnReq[j].scanMode != + eSIR_BEACON_TABLE)) || + ((tempInt < 0) && + (pEseBcnReq->bcnReq[j].scanMode == + eSIR_BEACON_TABLE))) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Invalid Measurement Duration(%d)", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementDuration = + tempInt; + break; + } + } + } + + for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "Index(%d) Measurement Token(%u) Channel(%u) Scan Mode(%u) Measurement Duration(%u)", + j, + pEseBcnReq->bcnReq[j].measurementToken, + pEseBcnReq->bcnReq[j].channel, + pEseBcnReq->bcnReq[j].scanMode, + pEseBcnReq->bcnReq[j].measurementDuration); + } + + return 0; +} +#endif /* defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) */ + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE + * @pValue: Pointer to input data + * @pCckmIe: Pointer to output cckm Ie + * @pCckmIeLen: Pointer to output cckm ie length + * + * This function parses the SETCCKM IE command + * SETCCKMIE + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe, + uint8_t *pCckmIeLen) +{ + uint8_t *inPtr = pValue; + uint8_t *dataEnd; + int j = 0; + int i = 0; + uint8_t tempByte = 0; + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) { + dataEnd++; + ++(*pCckmIeLen); + } + if (*pCckmIeLen <= 0) + return -EINVAL; + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N / 2 byte. + * if the number of input characters are odd, then we need do + * (N + 1) / 2 to compensate rounding off. + * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes + */ + *pCckmIe = cdf_mem_malloc((*pCckmIeLen + 1) / 2); + if (NULL == *pCckmIe) { + hddLog(LOGE, FL("cdf_mem_alloc failed")); + return -ENOMEM; + } + cdf_mem_zero(*pCckmIe, (*pCckmIeLen + 1) / 2); + /* + * the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain + * 7f in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *pCckmIeLen; j += 2) { + tempByte = (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + (*pCckmIe)[i++] = tempByte; + } + *pCckmIeLen = i; + return 0; +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate) +{ + tSirRateUpdateInd rateUpdate = {0}; + CDF_STATUS status; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct hdd_config *pConfig = NULL; + + if (pHddCtx == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is null", __func__); + return -EINVAL; + } + if ((WLAN_HDD_IBSS != pAdapter->device_mode) && + (WLAN_HDD_SOFTAP != pAdapter->device_mode) && + (WLAN_HDD_INFRA_STATION != pAdapter->device_mode)) { + hddLog(LOGE, + FL("Received SETMCRATE cmd in invalid mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + hddLog(LOGE, + FL("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode")); + return -EINVAL; + } + pConfig = pHddCtx->config; + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = pAdapter->device_mode; + rateUpdate.mcastDataRate24GHz = targetRate; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = targetRate; + rateUpdate.bcastDataRate = -1; + memcpy(rateUpdate.bssid, pAdapter->macAddressCurrent.bytes, + sizeof(rateUpdate.bssid)); + hddLog(LOG1, + FL("MC Target rate %d, mac = %pM, dev_mode %s(%d)"), + rateUpdate.mcastDataRate24GHz, rateUpdate.bssid, + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: SETMCRATE failed", + __func__); + return -EFAULT; + } + return 0; +} + +static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL, + adapter->sessionId, + (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2) + << 24 | *(hdd_ctx->p2pDeviceAddress.bytes + + 3) << 16 | *(hdd_ctx-> + p2pDeviceAddress.bytes + 4) << 8 | + *(hdd_ctx->p2pDeviceAddress.bytes + + 5)))); + + if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes, + sizeof(tSirMacAddr))) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +/** + * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command + * @adapter: Adapter on which the command was received + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command hander function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_p2p_noa(adapter->dev, command); +} + +/** + * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command + * @adapter: Adapter on which the command was received + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command hander function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_p2p_opps(adapter->dev, command); +} + +static int drv_cmd_set_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + + uint8_t *ptr = command; + + /* Change band request received */ + + /* + * First 8 bytes will have "SETBAND " and + * 9 byte will have band setting value + */ + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: SetBandCommand Info comm %s UL %d, TL %d", + __func__, command, priv_data->used_len, + priv_data->total_len); + + /* Change band request received */ + ret = hdd_set_band_helper(adapter->dev, ptr); + + return ret; +} + +static int drv_cmd_set_wmmps(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_wmmps_helper(adapter, command); +} + +static int drv_cmd_country(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + CDF_STATUS status; + unsigned long rc; + char *country_code; + + country_code = command + 8; + + INIT_COMPLETION(adapter->change_country_code); + + status = sme_change_country_code(hdd_ctx->hHal, + wlan_hdd_change_country_code_callback, + country_code, + adapter, + hdd_ctx->pcds_context, + eSIR_TRUE, + eSIR_TRUE); + if (status == CDF_STATUS_SUCCESS) { + rc = wait_for_completion_timeout( + &adapter->change_country_code, + msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY)); + if (!rc) + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME while setting country code timed out", + __func__); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME Change Country code fail, status=%d", + __func__, status); + ret = -EINVAL; + } + + return ret; +} + +static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + int8_t rssi = 0; + uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* Move pointer to ahead of SETROAMTRIGGER */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtos8(value, 10, &rssi); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed Input value may be out of range[%d - %d]", + __func__, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + lookUpThreshold = abs(rssi); + + if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN) + || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)", + lookUpThreshold, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL, + adapter->sessionId, lookUpThreshold)); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set Roam trigger (Neighbor lookup threshold) = %d", + __func__, + lookUpThreshold); + + hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold; + status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal, + adapter->sessionId, + lookUpThreshold); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to set roam trigger, try again", + __func__); + ret = -EPERM; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t lookUpThreshold = + sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal); + int rssi = (-1) * lookUpThreshold; + char extra[32]; + uint8_t len = 0; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL, + adapter->sessionId, lookUpThreshold)); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanPeriod = 0; + uint16_t neighborEmptyScanRefreshPeriod = + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT; + + /* input refresh period is in terms of seconds */ + + /* Move pointer to ahead of SETROAMSCANPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanPeriod); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed Input value may be out of range[%d - %d]", + __func__, + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + + if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000)) + || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Roam scan period value %d is out of range (Min: %d Max: %d)", + roamScanPeriod, + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL, + adapter->sessionId, roamScanPeriod)); + neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set roam scan period (Empty Scan refresh period) = %d", + __func__, + roamScanPeriod); + + hdd_ctx->config->nEmptyScanRefreshPeriod = + neighborEmptyScanRefreshPeriod; + sme_update_empty_scan_refresh_period(hdd_ctx->hHal, + adapter->sessionId, + neighborEmptyScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t nEmptyScanRefreshPeriod = + sme_get_empty_scan_refresh_period(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL, + adapter->sessionId, + nEmptyScanRefreshPeriod)); + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANPERIOD", + (nEmptyScanRefreshPeriod / 1000)); + /* Returned value is in units of seconds */ + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hddLog(LOGE, + FL("failed to copy data to user buffer")); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanRefreshPeriod = 0; + uint16_t neighborScanRefreshPeriod = + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT; + + /* input refresh period is in terms of seconds */ + /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanRefreshPeriod); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed Input value may be out of range[%d - %d]", + __func__, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000); + ret = -EINVAL; + goto exit; + } + + if ((roamScanRefreshPeriod < + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000)) + || (roamScanRefreshPeriod > + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)", + roamScanRefreshPeriod, + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN + / 1000), + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX + / 1000)); + ret = -EINVAL; + goto exit; + } + neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set roam scan refresh period (Scan refresh period) = %d", + __func__, + roamScanRefreshPeriod); + + hdd_ctx->config->nNeighborResultsRefreshPeriod = + neighborScanRefreshPeriod; + sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal, + adapter->sessionId, + neighborScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t value = + sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANREFRESHPERIOD", + (value / 1000)); + /* Returned value is in units of seconds */ + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + /* Move pointer to ahead of SETROAMMODE */ + value = value + SIZE_OF_SETROAMMODE + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Roam Mode value %d is out of range (Min: %d Max: %d)", + roamMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_DEBUG, + "%s: Received Command to Set Roam Mode = %d", + __func__, roamMode); + /* + * Note that + * SETROAMMODE 0 is to enable LFR while + * SETROAMMODE 1 is to disable LFR, but + * notify_is_fast_roam_ini_feature_enabled 0/1 is to + * enable/disable. So, we have to invert the value + * to call sme_update_is_fast_roam_ini_feature_enabled. + */ + if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */ + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */ + + hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode; + if (roamMode) { + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled( + (tHalHandle)(hdd_ctx->hHal), + hdd_ctx->config->isRoamOffloadScanEnabled); + sme_update_is_fast_roam_ini_feature_enabled( + hdd_ctx->hHal, + adapter->sessionId, + roamMode); + } else { + sme_update_is_fast_roam_ini_feature_enabled( + hdd_ctx->hHal, + adapter->sessionId, + roamMode); + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled( + (tHalHandle)(hdd_ctx->hHal), + hdd_ctx->config->isRoamOffloadScanEnabled); + } + + +exit: + return ret; +} + +static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + /* + * roamMode value shall be inverted because the sementics is different. + */ + if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMDELTA */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamRssiDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) || + (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Roam rssi diff value %d is out of range (Min: %d Max: %d)", + roamRssiDiff, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set roam rssi diff = %d", + __func__, roamRssiDiff); + + hdd_ctx->config->RoamRssiDiff = roamRssiDiff; + sme_update_roam_rssi_diff(hdd_ctx->hHal, + adapter->sessionId, + roamRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t roamRssiDiff = + sme_get_roam_rssi_diff(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMDELTA_IOCTL, + adapter->sessionId, roamRssiDiff)); + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamRssiDiff); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int band = -1; + char extra[32]; + uint8_t len = 0; + + hdd_get_band_helper(hdd_ctx, &band); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETBAND_IOCTL, + adapter->sessionId, band)); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, band); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_set_roam_scan_channels(adapter, command); +} + +static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + uint8_t j = 0; + char extra[128] = { 0 }; + int len; + + if (CDF_STATUS_SUCCESS != + sme_get_roam_scan_channel_list(hdd_ctx->hHal, + ChannelList, + &numChannels, + adapter->sessionId)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_FATAL, + "%s: failed to get roam scan channel list", + __func__); + ret = -EFAULT; + goto exit; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, numChannels)); + /* + * output channel list is of the format + * [Number of roam scan channels][Channel1][Channel2]... + * copy the number of channels in the 0th index + */ + len = scnprintf(extra, sizeof(extra), "%s %d", command, + numChannels); + for (j = 0; (j < numChannels); j++) + len += scnprintf(extra + len, sizeof(extra) - len, + " %d", ChannelList[j]); + + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (eseMode && + hdd_is_okc_mode_enabled(hdd_ctx) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!", + __func__); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETCCXMODE", eseMode); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool okcMode = hdd_is_okc_mode_enabled(hdd_ctx); + char extra[32]; + uint8_t len = 0; + + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (okcMode && + sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!", + __func__); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETOKCMODE", okcMode); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTROAM", lfrMode); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTTRANSITION", ft); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &minTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) || + (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "scan min channel time value %d is out of range (Min: %d Max: %d)", + minTime, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL, + adapter->sessionId, minTime)); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change channel min time = %d", + __func__, minTime); + + hdd_ctx->config->nNeighborScanMinChanTime = minTime; + sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal, + minTime, + adapter->sessionId); + +exit: + return ret; +} + +static int drv_cmd_send_action_frame(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_sendactionframe(adapter, command); +} + +static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal, + adapter->sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANCHANNELMINTIME", val); + len = CDF_MIN(priv_data->total_len, len + 1); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL, + adapter->sessionId, val)); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETSCANCHANNELTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &maxTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou16 failed range [%d - %d]", + __func__, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) || + (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "lfr mode value %d is out of range (Min: %d Max: %d)", + maxTime, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change channel max time = %d", + __func__, maxTime); + + hdd_ctx->config->nNeighborScanMaxChanTime = maxTime; + sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal, + adapter->sessionId, + maxTime); + +exit: + return ret; +} + +static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal, + adapter->sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANCHANNELTIME", val); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT; + + /* Move pointer to ahead of SETSCANHOMETIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou16 failed range [%d - %d]", + __func__, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) || + (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "scan home time value %d is out of range (Min: %d Max: %d)", + val, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change scan home time = %d", + __func__, val); + + hdd_ctx->config->nNeighborScanPeriod = val; + sme_set_neighbor_scan_period(hdd_ctx->hHal, + adapter->sessionId, val); + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal, + adapter-> + sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANHOMETIME", val); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT; + + /* Move pointer to ahead of SETROAMINTRABAND */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_ROAM_INTRA_BAND_MIN) || + (val > CFG_ROAM_INTRA_BAND_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "intra band mode value %d is out of range (Min: %d Max: %d)", + val, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change intra band = %d", + __func__, val); + + hdd_ctx->config->nRoamIntraBand = val; + sme_set_roam_intra_band(hdd_ctx->hHal, val); + +exit: + return ret; +} + +static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMINTRABAND", val); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT; + + /* Move pointer to ahead of SETSCANNPROBES */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nProbes); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) || + (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "NProbes value %d is out of range (Min: %d Max: %d)", + nProbes, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set nProbes = %d", + __func__, nProbes); + + hdd_ctx->config->nProbes = nProbes; + sme_update_roam_scan_n_probes(hdd_ctx->hHal, + adapter->sessionId, nProbes); + +exit: + return ret; +} + +static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT; + + /* input value is in units of msec */ + + /* Move pointer to ahead of SETSCANHOMEAWAYTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &homeAwayTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) || + (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "homeAwayTime value %d is out of range (Min: %d Max: %d)", + homeAwayTime, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set scan away time = %d", + __func__, homeAwayTime); + + if (hdd_ctx->config->nRoamScanHomeAwayTime != + homeAwayTime) { + hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime; + sme_update_roam_scan_home_away_time(hdd_ctx->hHal, + adapter->sessionId, + homeAwayTime, + true); + } + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_reassoc(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_reassoc(adapter, command); +} + +static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT; + + /* Move pointer to ahead of SETWESMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &wesMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) || + (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "WES Mode value %d is out of range (Min: %d Max: %d)", + wesMode, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set WES Mode rssi diff = %d", + __func__, wesMode); + + hdd_ctx->config->isWESModeEnabled = wesMode; + sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId); + +exit: + return ret; +} + +static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool wesMode = sme_get_wes_mode(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nOpportunisticThresholdDiff = + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT; + + /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed.", __func__); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set Opportunistic Threshold diff = %d", + __func__, nOpportunisticThresholdDiff); + + sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal, + adapter->sessionId, + nOpportunisticThresholdDiff); + +exit: + return ret; +} + +static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int8_t val = sme_get_roam_opportunistic_scan_threshold_diff( + hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMRESCANRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nRoamRescanRssiDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed.", __func__); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set Roam Rescan RSSI Diff = %d", + __func__, nRoamRescanRssiDiff); + + sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal, + adapter->sessionId, + nRoamRescanRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &lfrMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "lfr mode value %d is out of range (Min: %d Max: %d)", + lfrMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change lfr mode = %d", + __func__, lfrMode); + + hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode; + sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal, + adapter-> + sessionId, + lfrMode); + +exit: + return ret; +} + +static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT; + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &ft); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) || + (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "ft mode value %d is out of range (Min: %d Max: %d)", + ft, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change ft mode = %d", + __func__, ft); + + hdd_ctx->config->isFastTransitionEnabled = ft; + sme_update_fast_transition_enabled(hdd_ctx->hHal, ft); + +exit: + return ret; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void hdd_wma_send_fastreassoc_cmd(int sessionId, tSirMacAddr bssid, + int channel) +{ + struct wma_roam_invoke_cmd *fastreassoc; + cds_msg_t msg = {0}; + + fastreassoc = cdf_mem_malloc(sizeof(*fastreassoc)); + if (NULL == fastreassoc) { + hddLog(LOGE, FL("cdf_mem_alloc failed for fastreassoc")); + return; + } + fastreassoc->vdev_id = sessionId; + fastreassoc->channel = channel; + fastreassoc->bssid[0] = bssid[0]; + fastreassoc->bssid[1] = bssid[1]; + fastreassoc->bssid[2] = bssid[2]; + fastreassoc->bssid[3] = bssid[3]; + fastreassoc->bssid[4] = bssid[4]; + fastreassoc->bssid[5] = bssid[5]; + + msg.type = SIR_HAL_ROAM_INVOKE; + msg.reserved = 0; + msg.bodyptr = fastreassoc; + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, + &msg)) { + cdf_mem_free(fastreassoc); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post ROAM_INVOKE_CMD message to WMA")); + } +} +#endif +static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t channel = 0; + tSirMacAddr targetApBssid; + uint32_t roamId = 0; + tCsrRoamModifyProfileFields modProfileFields; +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + tCsrHandoffRequest handoffInfo; +#endif + hdd_station_ctx_t *pHddStaCtx; + + if (WLAN_HDD_INFRA_STATION != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s:Not associated!", __func__); + ret = -EINVAL; + goto exit; + } + + ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid, + &channel); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse reassoc command data", + __func__); + goto exit; + } + + /* + * if the target bssid is same as currently associated AP, + * issue reassoc to same AP + */ + if (true == cdf_mem_compare(targetApBssid, + pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE)) { + /* Reassoc to same AP, only supported for Open Security*/ + if ((pHddStaCtx->conn_info.ucEncryptionType || + pHddStaCtx->conn_info.mcEncryptionType)) { + hddLog(LOGE, + FL("Reassoc to same AP, only supported for Open Security")); + return -ENOTSUPP; + } + hddLog(LOG1, + FL("Reassoc BSSID is same as currently associated AP bssid")); + sme_get_modify_profile_fields(hdd_ctx->hHal, adapter->sessionId, + &modProfileFields); + sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId, + NULL, modProfileFields, &roamId, 1); + return 0; + } + + /* Check channel number is a valid channel number */ + if (CDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hddLog(LOGE, FL("Invalid Channel [%d]"), channel); + return -EINVAL; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (hdd_ctx->config->isRoamOffloadEnabled) { + hdd_wma_send_fastreassoc_cmd((int)adapter->sessionId, + targetApBssid, (int)channel); + goto exit; + } +#endif + /* Proceed with reassoc */ +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + handoffInfo.channel = channel; + handoffInfo.src = FASTREASSOC; + cdf_mem_copy(handoffInfo.bssid, targetApBssid, + sizeof(tSirMacAddr)); + sme_handoff_request(hdd_ctx->hHal, adapter->sessionId, + &handoffInfo); +#endif + +exit: + return ret; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpSirPlmReq pPlmRequest = NULL; + + pPlmRequest = cdf_mem_malloc(sizeof(tSirPlmReq)); + if (NULL == pPlmRequest) { + ret = -ENOMEM; + goto exit; + } + + status = hdd_parse_plm_cmd(value, pPlmRequest); + if (CDF_STATUS_SUCCESS != status) { + cdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + pPlmRequest->sessionId = adapter->sessionId; + + status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest); + if (CDF_STATUS_SUCCESS != status) { + cdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} +#endif + +#ifdef FEATURE_WLAN_ESE +static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT; + + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + hdd_is_okc_mode_enabled(hdd_ctx) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!", + __func__); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETCCXMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &eseMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) || + (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Ese mode value %d is out of range (Min: %d Max: %d)", + eseMode, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change ese mode = %d", + __func__, eseMode); + + hdd_ctx->config->isEseIniFeatureEnabled = eseMode; + sme_update_is_ese_feature_enabled(hdd_ctx->hHal, + adapter->sessionId, + eseMode); + +exit: + return ret; +} +#endif + +static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanControl = 0; + + /* Move pointer to ahead of SETROAMSCANCONTROL */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanControl); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed ", __func__); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set roam scan control = %d", + __func__, roamScanControl); + + if (0 != roamScanControl) { + ret = 0; /* return success but ignore param value "true" */ + goto exit; + } + + sme_set_roam_scan_control(hdd_ctx->hHal, + adapter->sessionId, + roamScanControl); + +exit: + return ret; +} + +static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t okcMode = CFG_OKC_FEATURE_ENABLED_DEFAULT; + + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + hdd_is_okc_mode_enabled(hdd_ctx) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_WARN, + "%s: OKC/ESE/11R are supported simultaneously hence this operation is not permitted!", + __func__); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETOKCMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &okcMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_OKC_FEATURE_ENABLED_MIN, + CFG_OKC_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((okcMode < CFG_OKC_FEATURE_ENABLED_MIN) || + (okcMode > CFG_OKC_FEATURE_ENABLED_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Okc mode value %d is out of range (Min: %d Max: %d)", + okcMode, + CFG_OKC_FEATURE_ENABLED_MIN, + CFG_OKC_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to change okc mode = %d", + __func__, okcMode); + + hdd_ctx->config->isOkcIniFeatureEnabled = okcMode; + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamScanControl); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + char *bcMode; + + bcMode = command + 11; + if ('1' == *bcMode) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_DEBUG, + FL("BTCOEXMODE %d"), *bcMode); + hdd_ctx->btCoexModeSet = true; + ret = wlan_hdd_scan_abort(adapter); + if (ret < 0) { + hddLog(LOGE, + FL("Failed to abort existing scan status:%d"), ret); + } + } else if ('2' == *bcMode) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_DEBUG, + FL("BTCOEXMODE %d"), *bcMode); + hdd_ctx->btCoexModeSet = false; + } + + return ret; +} + +static int drv_cmd_scan_active(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + return 0; +} + +static int drv_cmd_scan_passive(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN; + return 0; +} + +static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + struct hdd_config *pCfg = + (WLAN_HDD_GET_CTX(adapter))->config; + char extra[32]; + uint8_t len = 0; + + memset(extra, 0, sizeof(extra)); + ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len); + len = CDF_MIN(priv_data->total_len, len + 1); + if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + goto exit; + } + ret = len; +exit: + return ret; +} + +static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_dwell_time(adapter, command); +} + +static int drv_cmd_miracast(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + CDF_STATUS ret_status; + int ret = 0; + tHalHandle hHal; + uint8_t filterType = 0; + hdd_context_t *pHddCtx = NULL; + uint8_t *value; + + pHddCtx = WLAN_HDD_GET_CTX(adapter); + if (0 != wlan_hdd_validate_context(pHddCtx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s pHddCtx is not valid, Unable to set miracast mode", + __func__); + return -EINVAL; + } + + hHal = pHddCtx->hHal; + value = command + 9; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &filterType); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range ", + __func__); + ret = -EINVAL; + goto exit; + } + if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) + || (filterType > + WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink ", + __func__); + ret = -EINVAL; + goto exit; + } + /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */ + pHddCtx->miracast_value = filterType; + + ret_status = sme_set_miracast(hHal, filterType); + if (CDF_STATUS_SUCCESS != ret_status) { + hddLog(LOGE, "Failed to set miracast"); + return -EBUSY; + } + + if (cds_is_mcc_in_24G(pHddCtx)) + return cds_set_mas(adapter, filterType); + +exit: + return ret; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + CDF_STATUS status; + + ret = hdd_parse_channellist(value, ChannelList, &numChannels); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse channel list information", + __func__); + goto exit; + } + if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: number of channels (%d) supported exceeded max (%d)", + __func__, + numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + ChannelList, + numChannels); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to update channel list information", + __func__); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + char extra[128] = { 0 }; + int len = 0; + uint8_t tid = 0; + hdd_station_ctx_t *pHddStaCtx; + tAniTrafStrmMetrics tsm_metrics; + + if ((WLAN_HDD_INFRA_STATION != adapter->device_mode) && + (WLAN_HDD_P2P_CLIENT != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, return error */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s:Not associated!", __func__); + ret = -EINVAL; + goto exit; + } + + /* Move pointer to ahead of GETTSMSTATS */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &tid); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, TID_MIN_VALUE, + TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "tid value %d is out of range (Min: %d Max: %d)", + tid, TID_MIN_VALUE, TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: Received Command to get tsm stats tid = %d", + __func__, tid); + if (CDF_STATUS_SUCCESS != + hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to get tsm stats", + __func__); + ret = -EFAULT; + goto exit; + } + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)", + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + /* + * Output TSM stats is of the format + * GETTSMSTATS [PktQueueDly] + * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly] + * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800 + */ + len = scnprintf(extra, + sizeof(extra), + "%s %d %d:%d:%d:%d %u %d %d %d %d", + command, + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + uint8_t *cckmIe = NULL; + uint8_t cckmIeLen = 0; + + ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse cckm ie data", + __func__); + goto exit; + } + + if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: CCKM Ie input length is more than max[%d]", + __func__, DOT11F_IE_RSN_MAX_LEN); + if (NULL != cckmIe) { + cdf_mem_free(cckmIe); + cckmIe = NULL; + } + ret = -EINVAL; + goto exit; + } + + sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId, + cckmIe, cckmIeLen); + if (NULL != cckmIe) { + cdf_mem_free(cckmIe); + cckmIe = NULL; + } + +exit: + return ret; +} + +static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + tCsrEseBeaconReq eseBcnReq; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (WLAN_HDD_INFRA_STATION != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + ret = hdd_parse_ese_beacon_req(value, &eseBcnReq); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to parse ese beacon req", + __func__); + goto exit; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("Not associated")); + hdd_indicate_ese_bcn_report_no_results(adapter, + eseBcnReq.bcnReq[0].measurementToken, + 0x02, /* BIT(1) set for measurement done */ + 0); /* no BSS */ + goto exit; + } + + status = sme_set_ese_beacon_request(hdd_ctx->hHal, + adapter->sessionId, + &eseBcnReq); + + if (CDF_STATUS_E_RESOURCES == status) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("sme_set_ese_beacon_request failed (%d), a request already in progress"), + status); + ret = -EBUSY; + goto exit; + } else if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: sme_set_ese_beacon_request failed (%d)", + __func__, status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} +#endif /* #if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) */ + +static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + int targetRate; + + /* input value is in units of hundred kbps */ + + /* Move pointer to ahead of SETMCRATE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer, decimal base */ + ret = kstrtouint(value, 10, &targetRate); + + ret = wlan_hdd_set_mc_rate(adapter, targetRate); + return ret; +} + +static int drv_cmd_max_tx_power(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int status; + int txPower; + CDF_STATUS cdf_status; + CDF_STATUS smeStatus; + uint8_t *value = command; + tSirMacAddr bssid = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirMacAddr selfMac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + + status = hdd_parse_setmaxtxpower_command(value, &txPower); + if (status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Invalid MAXTXPOWER command "); + ret = -EINVAL; + goto exit; + } + + cdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode); + while (NULL != pAdapterNode + && CDF_STATUS_SUCCESS == cdf_status) { + adapter = pAdapterNode->pAdapter; + /* Assign correct self MAC address */ + cdf_mem_copy(bssid, + adapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(selfMac, + adapter->macAddressCurrent.bytes, + CDF_MAC_ADDR_SIZE); + + hddLog(CDF_TRACE_LEVEL_INFO, + "Device mode %d max tx power %d selfMac: " MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ", + adapter->device_mode, txPower, + MAC_ADDR_ARRAY(selfMac), + MAC_ADDR_ARRAY(bssid)); + + smeStatus = sme_set_max_tx_power((tHalHandle)(hdd_ctx->hHal), + bssid, selfMac, txPower); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s:Set max tx power failed", + __func__); + ret = -EINVAL; + goto exit; + } + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Set max tx power success", + __func__); + cdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, + &pNext); + pAdapterNode = pNext; + } + +exit: + return ret; +} + +static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT; + + /* Move pointer to ahead of SETDFSSCANMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &dfsScanMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: kstrtou8 failed range [%d - %d]", + __func__, CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) || + (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "dfsScanMode value %d is out of range (Min: %d Max: %d)", + dfsScanMode, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Command to Set DFS Scan Mode = %d", + __func__, dfsScanMode); + + hdd_ctx->config->allowDFSChannelRoam = dfsScanMode; + sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId, + dfsScanMode); + +exit: + return ret; +} + +static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_link_status(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int value = wlan_hdd_get_link_status(adapter); + char extra[32]; + uint8_t len; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, value); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", + __func__); + ret = -EFAULT; + } + + return ret; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + uint8_t *value = command; + int set_value; + + /* Move pointer to ahead of ENABLEEXTWOW */ + value = value + command_len; + + sscanf(value, "%d", &set_value); + + return hdd_enable_ext_wow_parser(adapter, + adapter->sessionId, + set_value); +} + +static int drv_cmd_set_app1_params(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP1PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type1_parser(adapter, + value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type1_param_set = true; + + return ret; +} + +static int drv_cmd_set_app2_params(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP2PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type2_parser(adapter, value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type2_param_set = true; + + return ret; +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_TDLS +/** + * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets the secondary tdls off channel + * offset + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hddLog(LOG1, FL("Tdls offchannel offset:%d"), set_value); + + ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hddLog(LOG1, FL("Tdls offchannel mode:%d"), set_value); + + ret = hdd_set_tdls_offchannelmode(adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel() - set tdls off channel number + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel number + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hddLog(LOG1, FL("Tdls offchannel num: %d"), set_value); + + ret = hdd_set_tdls_offchannel(hdd_ctx, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_scan() - set tdls scan type + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls scan type + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_scan(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hddLog(LOG1, FL("Tdls scan type val: %d"), set_value); + + ret = hdd_set_tdls_scan_type(hdd_ctx, set_value); + + return ret; +} +#endif + +static int drv_cmd_get_rssi(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + int8_t rssi = 0; + char extra[32]; + uint8_t len = 0; + + wlan_hdd_get_rssi(adapter, &rssi); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = CDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hddLog(LOGE, FL("Failed to copy data to user buffer")); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint32_t link_speed = 0; + char extra[32]; + uint8_t len = 0; + + ret = wlan_hdd_get_link_speed(adapter, &link_speed); + if (0 != ret) + return ret; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed); + len = CDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hddLog(LOGE, FL("Failed to copy data to user buffer")); + ret = -EFAULT; + } + + return ret; +} + +#ifdef FEATURE_NAPI +/** + * hdd_parse_napi() - helper functions to drv_cmd_napi + * @str : source string to parse + * @cmd : pointer to cmd part after parsing + * @sub : pointer to subcmd part after parsing + * @aux : pointer to optional aux part after parsing + * + * Example: + * NAPI SCALE +-- IN str + * | | +------ OUT aux + * | +------------ OUT subcmd + * +----------------- OUT cmd + * + * Return: ==0: success; !=0: failure + */ +static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux) +{ + int rc; + char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL; + + NAPI_DEBUG("-->\n"); + + token = strsep(str, " \t"); + if (NULL == token) { + hdd_err("cannot parse cmd"); + goto parse_end; + } + lcmd = token; + + token = strsep(str, " \t"); + if (NULL == token) { + hdd_err("cannot parse subcmd"); + goto parse_end; + } + lsub = token; + + token = strsep(str, " \t"); + if (NULL == token) + hdd_warn("cannot parse aux\n"); + else + laux = token; + +parse_end: + if ((NULL == lcmd) || (NULL == lsub)) + rc = -EINVAL; + else { + rc = 0; + *cmd = lcmd; + *sub = lsub; + if (NULL != aux) + *aux = laux; + } + NAPI_DEBUG("<--[rc=%d]\n", rc); + return rc; +} + + +/** + * hdd_parse_stats() - print NAPI stats into a buffer + * @buf : buffer to write stats into + * @max : "size of buffer" + * @idp : NULL: all stats, otherwise, ptr to the NAPI instance + * @napid: binary structure to retrieve the stats from + * + * Return: number of bytes written into the buffer + */ +int hdd_napi_stats(char *buf, + int max, + char *indp, + struct qca_napi_data *napid) +{ + int n = 0; + int i, j, k; /* NAPI, CPU, bucket indices */ + int from, to; + struct qca_napi_info *napii; + struct qca_napi_stat *napis; + + NAPI_DEBUG("-->\n"); + + if (NULL == indp) { + from = 0; + to = sizeof(uint32_t) * CE_COUNT_MAX; + } else { + if (0 > kstrtoint(indp, 10, &to)) { + from = 0; + to = sizeof(uint32_t) * CE_COUNT_MAX; + } else + from = to; + } + + for (i = from; i < to; i++) + if (napid->ce_map & (0x01 << i)) { + napii = &(napid->napis[i]); + for (j = 0; j < NR_CPUS; j++) { + napis = &(napii->stats[j]); + n += scnprintf(buf + n, max - n, + "STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ", + i, j, + napis->napi_schedules, + napis->napi_polls, + napis->napi_completes, + napis->napi_workdone); + + for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) { + n += scnprintf( + buf + n, max - n, + " %d", + napis->napi_budget_uses[k]); + } + n += scnprintf(buf+n, max - n, "\n"); + } + } + + NAPI_DEBUG("<--[n=%d]\n", n); + return n; +} + +/** + * napi_set_scale() - sets the scale attribute in all NAPI entries + * @sc : scale to set + * + * Return: void + */ +static void napi_set_scale(uint8_t sc) +{ + uint32_t i; + struct qca_napi_data *napi_data; + + napi_data = hdd_napi_get_all(); + for (i = 0; i < sizeof(uint32_t)*8; i++) + if (napi_data->ce_map & (0x01 << i)) + napi_data->napis[i].scale = sc; + + return; +} +/** + * drv_cmd_napi() - processes NAPI commands + * @adapter : net_device + * @hdd_ctx : HDD context + * @command : command string from user command (including "NAPI") + * @command_len: length of command + * @priv_data : ifr_data + * + * Commands supported: + * NAPI ENABLE : enables NAPI administratively. Note that this may not + * enable NAPI functionally, as some other conditions + * may not have been satisfied yet + * NAPI DISABLE : reverse operation of "enable" + * NAPI STATUS : get global status of NAPI instances + * NAPI STATS [] : get the stats for a given NAPI instance + * NAPI SCALE : set the scale factor + * + * Return: 0: success; 0>: failure + */ +static int drv_cmd_napi(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int rc = 0; + int n, l; + char *cmd = NULL, *subcmd = NULL, *aux = NULL; + char *synopsis = "NAPI ENABLE\n" + "NAPI DISABLE\n" + "NAPI STATUS\n" + "NAPI STATS [] -- if no then all\n" + "NAPI SCALE -- set the scale\n"; + char *reply = NULL; + + /* make a local copy, as strsep modifies the str in place */ + char *str = NULL; + + NAPI_DEBUG("-->\n"); + + /** + * NOTE TO MAINTAINER: from this point to the end of the function, + * please do not return anywhere in the code except the very end + * to avoid memory leakage (goto end_drv_napi instead) + * or make sure that reply+str is freed + */ + reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL); + if (NULL == reply) { + hdd_err("could not allocate reply buffer"); + rc = -ENOMEM; + goto end_drv_napi; + } + + str = kmalloc(strlen(command) + 1, GFP_KERNEL); + if (NULL == str) { + hdd_err("could not allocate copy of input buffer"); + rc = -ENOMEM; + goto end_drv_napi; + } + + strlcpy(str, command, strlen(command) + 1); + hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n", + cmd, subcmd, aux); + + + rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux); + + if (0 != rc) { + const char *msg = "unknown or badly formatted cmd\n%s"; + l = CDF_MIN(MAX_USER_COMMAND_SIZE, + strlen(msg)+strlen(synopsis)); + n = scnprintf(reply, l, msg, synopsis); + + if (copy_to_user(priv_data->buf, reply, + CDF_MIN(priv_data->total_len, l))) + hdd_err("failed to copy data to user buffer"); + hdd_debug("reply: %s", reply); + + rc = -EINVAL; + } else { + hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n", + cmd, subcmd, aux); + if (!strcmp(subcmd, "ENABLE")) + hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1); + else if (!strcmp(subcmd, "DISABLE")) + hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0); + else if (!strcmp(subcmd, "STATUS")) { + int n = 0; + uint32_t i; + struct qca_napi_data *napi_data; + + napi_data = hdd_napi_get_all(); + n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n, + "NAPI state: 0x%08x map: 0x%08x\n", + napi_data->state, + napi_data->ce_map); + + for (i = 0; i < sizeof(uint32_t)*8; i++) + if (napi_data->ce_map & (0x01 << i)) { + n += scnprintf( + reply + n, + MAX_USER_COMMAND_SIZE - n, + "#%d: id: %d, scale=%d\n", + i, + napi_data->napis[i].id, + napi_data->napis[i].scale); + } + hdd_info("wlan: STATUS DATA:\n%s", reply); + if (copy_to_user(priv_data->buf, reply, + CDF_MIN(n, priv_data->total_len))) + rc = -EINVAL; + } else if (!strcmp(subcmd, "STATS")) { + int n = 0; + struct qca_napi_data *napi_data; + + napi_data = hdd_napi_get_all(); + n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE, + aux, napi_data); + NAPI_DEBUG("STATS: returns %d\n", n); + + if (n > 0) { + if (copy_to_user(priv_data->buf, reply, + CDF_MIN(priv_data->total_len, + n))) + rc = -EINVAL; + hdd_info("wlan: STATS_DATA\n%s\n", reply); + } else + rc = -EINVAL; + } else if (!strcmp(subcmd, "SCALE")) { + if (NULL == aux) { + rc = -EINVAL; + hdd_err("wlan: SCALE cmd requires "); + } else { + uint8_t sc; + rc = kstrtou8(aux, 10, &sc); + if (rc) { + hdd_err("wlan: bad scale (%s)", aux); + rc = -EINVAL; + } else + napi_set_scale(sc); + } + } /* SCALE */ + } +end_drv_napi: + if (NULL != str) + kfree(str); + if (NULL != reply) + kfree(reply); + + NAPI_DEBUG("<--[rc=%d]\n", rc); + return rc; +} +#endif /* FEATURE_NAPI */ + +/** + * hdd_set_rx_filter() - set RX filter + * @adapter: Pointer to adapter + * @action: Filter action + * @pattern: Address pattern + * + * Address pattern is most significant byte of address for example + * 0x01 for IPV4 multicast address + * 0x33 for IPV6 multicast address + * 0xFF for broadcast address + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action, + uint8_t pattern) +{ + int ret; + uint8_t i; + tHalHandle handle; + tSirRcvFltMcAddrList *filter; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + handle = hdd_ctx->hHal; + + if (NULL == handle) { + hdd_err("HAL Handle is NULL"); + return -EINVAL; + } + + /* + * If action is false it means start dropping packets + * Set addr_filter_pattern which will be used when sending + * MC/BC address list to target + */ + if (!action) + adapter->addr_filter_pattern = pattern; + else + adapter->addr_filter_pattern = 0; + + if (((adapter->device_mode == WLAN_HDD_INFRA_STATION) || + (adapter->device_mode == WLAN_HDD_P2P_CLIENT)) && + adapter->mc_addr_list.mc_cnt && + hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + + + filter = cdf_mem_malloc(sizeof(*filter)); + if (NULL == filter) { + hdd_err("Could not allocate Memory"); + return -ENOMEM; + } + filter->action = action; + for (i = 0; i < adapter->mc_addr_list.mc_cnt; i++) { + if (!memcmp(adapter->mc_addr_list.addr[i], + &pattern, 1)) { + memcpy(filter->multicastAddr[i], + adapter->mc_addr_list.addr[i], + sizeof(adapter->mc_addr_list.addr[i])); + filter->ulMulticastAddrCnt++; + hdd_err("%s RX filter : addr =" + MAC_ADDRESS_STR, + action ? "setting" : "clearing", + MAC_ADDR_ARRAY(filter->multicastAddr[i])); + } + } + /* Set rx filter */ + sme_8023_multicast_list(handle, adapter->sessionId, filter); + cdf_mem_free(filter); + } else { + hdd_err("mode %d mc_cnt %d", + adapter->device_mode, adapter->mc_addr_list.mc_cnt); + } + + return 0; +} + +/** + * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler + * @command: Pointer to input string driver command + * @adapter: Pointer to adapter + * @action: Action to enable/disable filtering + * + * If action == false + * Start filtering out data packets based on type + * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets + * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets + * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets + * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets + * + * if action == true + * Stop filtering data packets based on type + * RXFILTER-ADD 0 -> Stop filtering unicast data packets + * RXFILTER-ADD 1 -> Stop filtering broadcast data packets + * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets + * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets + * + * Current implementation only supports IPV4 address filtering by + * selectively allowing IPV4 multicast data packest based on + * address list received in .ndo_set_rx_mode + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_driver_rxfilter_comand_handler(uint8_t *command, + hdd_adapter_t *adapter, + bool action) +{ + int ret = 0; + uint8_t *value; + uint8_t type; + + value = command; + /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */ + if (!action) + value = command + 16; + else + value = command + 13; + ret = kstrtou8(value, 10, &type); + if (ret < 0) { + hdd_err("kstrtou8 failed invalid input value %d", type); + return -EINVAL; + } + + switch (type) { + case 2: + /* Set rx filter for IPV4 multicast data packets */ + ret = hdd_set_rx_filter(adapter, action, 0x01); + break; + default: + hdd_info("Unsupported RXFILTER type %d", type); + break; + } + + return ret; +} + +/** + * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_driver_rxfilter_comand_handler(command, adapter, false); +} + +/** + * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_driver_rxfilter_comand_handler(command, adapter, true); +} + +/* + * dummy (no-op) hdd driver command handler + */ +static int drv_cmd_dummy(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_info("%s: Ignoring driver command \"%s\"", + adapter->dev->name, command); + return 0; +} + +/* + * handler for any unsupported wlan hdd driver command + */ +static int drv_cmd_invalid(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_UNSUPPORTED_IOCTL, + adapter->sessionId, 0)); + + hdd_warn("%s: Unsupported driver command \"%s\"", + adapter->dev->name, command); + + return -ENOTSUPP; +} + +/** + * drv_cmd_set_fcc_channel() - handle fcc constraint request + * @adapter: HDD adapter + * @hdd_ctx: HDD context + * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command + * @command_len: command len + * @priv_data: private data + * + * Return: status + */ +static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + uint8_t *value; + uint8_t fcc_constraint; + CDF_STATUS status; + int ret = 0; + + /* + * this command would be called by user-space when it detects WLAN + * ON after airplane mode is set. When APM is set, WLAN turns off. + * But it can be turned back on. Otherwise; when APM is turned back + * off, WLAN would turn back on. So at that point the command is + * expected to come down. 0 means disable, 1 means enable. The + * constraint is removed when parameter 1 is set or different + * country code is set + */ + + value = command + command_len + 1; + + ret = kstrtou8(value, 10, &fcc_constraint); + if ((ret < 0) || (fcc_constraint > 1)) { + /* + * If the input value is greater than max value of datatype, + * then also it is a failure + */ + hdd_err("value out of range"); + return -EINVAL; + } + + status = sme_disable_non_fcc_channel(hdd_ctx->hHal, !fcc_constraint); + if (status != CDF_STATUS_SUCCESS) { + hdd_err("sme disable fn. returned err"); + ret = -EPERM; + } + + return ret; +} + +/* + * The following table contains all supported WLAN HDD + * IOCTL driver commands and the handler for each of them. + */ +static const hdd_drv_cmd_t hdd_drv_cmds[] = { + {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr}, + {"P2P_SET_NOA", drv_cmd_p2p_set_noa}, + {"P2P_SET_PS", drv_cmd_p2p_set_ps}, + {"SETBAND", drv_cmd_set_band}, + {"SETWMMPS", drv_cmd_set_wmmps}, + {"COUNTRY", drv_cmd_country}, + {"SETSUSPENDMODE", drv_cmd_dummy}, + {"SET_AP_WPS_P2P_IE", drv_cmd_dummy}, + {"BTCOEXSCAN", drv_cmd_dummy}, + {"RXFILTER", drv_cmd_dummy}, +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + {"SETROAMTRIGGER", drv_cmd_set_roam_trigger}, + {"GETROAMTRIGGER", drv_cmd_get_roam_trigger}, + {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period}, + {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period}, + {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period}, + {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period}, +#ifdef FEATURE_WLAN_LFR + {"SETROAMMODE", drv_cmd_set_roam_mode}, + {"GETROAMMODE", drv_cmd_get_roam_mode}, +#endif +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + {"SETROAMDELTA", drv_cmd_set_roam_delta}, + {"GETROAMDELTA", drv_cmd_get_roam_delta}, +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + {"GETBAND", drv_cmd_get_band}, + {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels}, + {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels}, + {"GETCCXMODE", drv_cmd_get_ccx_mode}, + {"GETOKCMODE", drv_cmd_get_okc_mode}, + {"GETFASTROAM", drv_cmd_get_fast_roam}, + {"GETFASTTRANSITION", drv_cmd_get_fast_transition}, + {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time}, + {"SENDACTIONFRAME", drv_cmd_send_action_frame}, + {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time}, + {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time}, + {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time}, + {"SETSCANHOMETIME", drv_cmd_set_scan_home_time}, + {"GETSCANHOMETIME", drv_cmd_get_scan_home_time}, + {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band}, + {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band}, + {"SETSCANNPROBES", drv_cmd_set_scan_n_probes}, + {"GETSCANNPROBES", drv_cmd_get_scan_n_probes}, + {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time}, + {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time}, + {"REASSOC", drv_cmd_reassoc}, + {"SETWESMODE", drv_cmd_set_wes_mode}, + {"GETWESMODE", drv_cmd_get_wes_mode}, + {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff}, + {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff}, + {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff}, + {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff}, +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || FEATURE_WLAN_LFR */ +#ifdef FEATURE_WLAN_LFR + {"SETFASTROAM", drv_cmd_set_fast_roam}, +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + {"SETFASTTRANSITION", drv_cmd_set_fast_transition}, + {"FASTREASSOC", drv_cmd_fast_reassoc}, +#endif +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + {"CCXPLMREQ", drv_cmd_ccx_plm_req}, +#endif +#ifdef FEATURE_WLAN_ESE + {"SETCCXMODE", drv_cmd_set_ccx_mode}, +#endif + {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control}, +#ifdef FEATURE_WLAN_OKC + {"SETOKCMODE", drv_cmd_set_okc_mode}, +#endif /* FEATURE_WLAN_OKC */ + {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control}, + {"BTCOEXMODE", drv_cmd_bt_coex_mode}, + {"SCAN-ACTIVE", drv_cmd_scan_active}, + {"SCAN-PASSIVE", drv_cmd_scan_passive}, + {"GETDWELLTIME", drv_cmd_get_dwell_time}, + {"SETDWELLTIME", drv_cmd_set_dwell_time}, + {"MIRACAST", drv_cmd_miracast}, +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels}, + {"GETTSMSTATS", drv_cmd_get_tsm_stats}, + {"SETCCKMIE", drv_cmd_set_cckm_ie}, + {"CCXBEACONREQ", drv_cmd_ccx_beacon_req}, +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + {"SETMCRATE", drv_cmd_set_mc_rate}, + {"MAXTXPOWER", drv_cmd_max_tx_power}, + {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode}, + {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode}, + {"GETLINKSTATUS", drv_cmd_get_link_status}, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + {"ENABLEEXTWOW", drv_cmd_enable_ext_wow}, + {"SETAPP1PARAMS", drv_cmd_set_app1_params}, + {"SETAPP2PARAMS", drv_cmd_set_app2_params}, +#endif +#ifdef FEATURE_WLAN_TDLS + {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset}, + {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode}, + {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel}, + {"TDLSSCAN", drv_cmd_tdls_scan}, +#endif + {"RSSI", drv_cmd_get_rssi}, + {"LINKSPEED", drv_cmd_get_linkspeed}, +#ifdef FEATURE_NAPI + {"NAPI", drv_cmd_napi}, +#endif /* FEATURE_NAPI */ + {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove}, + {"RXFILTER-ADD", drv_cmd_rx_filter_add}, + {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel}, +}; + +/** + * hdd_drv_cmd_process() - chooses and runs the proper + * handler based on the input command + * @adapter: Pointer to the hdd adapter + * @cmd: Pointer to the driver command + * @priv_data: Pointer to the data associated with the command + * + * This function parses the input hdd driver command and runs + * the proper handler + * + * Return: 0 for success non-zero for failure + */ +static int hdd_drv_cmd_process(hdd_adapter_t *adapter, + uint8_t *cmd, + hdd_priv_data_t *priv_data) +{ + hdd_context_t *hdd_ctx; + int i; + const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds); + uint8_t *cmd_i = NULL; + hdd_drv_cmd_handler_t handler = NULL; + int len = 0; + + if (!adapter || !cmd || !priv_data) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: at least 1 param is NULL", __func__); + return -EINVAL; + } + + hdd_ctx = (hdd_context_t *)adapter->pHddCtx; + + for (i = 0; i < cmd_num_total; i++) { + + cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd; + handler = hdd_drv_cmds[i].handler; + len = strlen(cmd_i); + + if (!handler) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: no. %d handler is NULL", __func__, i); + return -EINVAL; + } + + if (strncasecmp(cmd, cmd_i, len) == 0) + return handler(adapter, hdd_ctx, + cmd, len, priv_data); + } + + return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data); +} + +/** + * hdd_driver_command() - top level wlan hdd driver command handler + * @adapter: Pointer to the hdd adapter + * @priv_data: Pointer to the raw command data + * + * This function is the top level wlan hdd driver command handler. It + * handles the command with the help of hdd_drv_cmd_process() + * + * Return: 0 for success non-zero for failure + */ +static int hdd_driver_command(hdd_adapter_t *adapter, + hdd_priv_data_t *priv_data) +{ + uint8_t *command = NULL; + int ret = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + /* + * Note that valid pointers are provided by caller + */ + + /* copy to local struct to avoid numerous changes to legacy code */ + if (priv_data->total_len <= 0 || + priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) { + hddLog(CDF_TRACE_LEVEL_WARN, + "%s:invalid priv_data.total_len(%d)!!!", __func__, + priv_data->total_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate +1 for '\0' */ + command = kmalloc(priv_data->total_len + 1, GFP_KERNEL); + if (!command) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: failed to allocate memory", __func__); + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(command, priv_data->buf, priv_data->total_len)) { + ret = -EFAULT; + goto exit; + } + + /* Make sure the command is NUL-terminated */ + command[priv_data->total_len] = '\0'; + + hdd_info("%s: %s", adapter->dev->name, command); + ret = hdd_drv_cmd_process(adapter, command, priv_data); + +exit: + if (command) + kfree(command); + + return ret; +} + +#ifdef CONFIG_COMPAT +static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + struct { + compat_uptr_t buf; + int used_len; + int total_len; + } compat_priv_data; + hdd_priv_data_t priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&compat_priv_data, ifr->ifr_data, + sizeof(compat_priv_data))) { + ret = -EFAULT; + goto exit; + } + priv_data.buf = compat_ptr(compat_priv_data.buf); + priv_data.used_len = compat_priv_data.used_len; + priv_data.total_len = compat_priv_data.total_len; + ret = hdd_driver_command(adapter, &priv_data); +exit: + return ret; +} +#else /* CONFIG_COMPAT */ +static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + /* will never be invoked */ + return 0; +} +#endif /* CONFIG_COMPAT */ + +static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + hdd_priv_data_t priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data))) + ret = -EFAULT; + else + ret = hdd_driver_command(adapter, &priv_data); + + return ret; +} + +/** + * __hdd_ioctl() - ioctl handler for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @cmd: ioctl command + * + * This function does initial processing of wlan device ioctls. + * Currently two flavors of ioctls are supported. The primary ioctl + * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used + * for Android "DRIVER" commands. The other ioctl that is + * conditionally supported is the SIOCIOCTLTX99 ioctl which is used + * for FTM on some platforms. This function simply verifies that the + * driver is in a sane state, and that the ioctl is one of the + * supported flavors, in which case flavor-specific handlers are + * dispatched. + * + * Return: 0 on success, non-zero on error + */ +static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + if (dev != adapter->dev) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s: HDD adapter/dev inconsistency", __func__); + ret = -ENODEV; + goto exit; + } + + if ((!ifr) || (!ifr->ifr_data)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid data", __func__); + ret = -EINVAL; + goto exit; + } +#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR) + if (CDF_FTM_MODE == hdd_get_conparam()) { + if (SIOCIOCTLTX99 == cmd) { + ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr); + goto exit; + } + } +#endif + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + ret = -EBUSY; + goto exit; + } + + switch (cmd) { + case (SIOCDEVPRIVATE + 1): + if (is_compat_task()) + ret = hdd_driver_compat_ioctl(adapter, ifr); + else + ret = hdd_driver_ioctl(adapter, ifr); + break; + default: + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d", + __func__, cmd); + ret = -EINVAL; + break; + } +exit: + return ret; +} + +/** + * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @cmd: ioctl command + * + * This function acts as an SSR-protecting wrapper to __hdd_ioctl() + * which is where the ioctls are really handled. + * + * Return: 0 on success, non-zero on error + */ +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ioctl(dev, ifr, cmd); + cds_ssr_unprotect(__func__); + return ret; +} diff --git a/core/hdd/src/wlan_hdd_ioctl.h b/core/hdd/src/wlan_hdd_ioctl.h new file mode 100644 index 0000000000..c1862ba242 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ioctl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_IOCTL_H) +#define WLAN_HDD_IOCTL_H + +#include +#include +#include "wlan_hdd_main.h" + +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate); + +#endif /* end #if !defined(WLAN_HDD_IOCTL_H) */ + diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c new file mode 100644 index 0000000000..c7efbc12fd --- /dev/null +++ b/core/hdd/src/wlan_hdd_ipa.c @@ -0,0 +1,3935 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ipa.c + * + * WLAN HDD and ipa interface implementation + * Originally written by Qualcomm Atheros, Inc + */ + +#ifdef IPA_OFFLOAD + +/* Include Files */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_sched.h" + +#include "wma.h" +#include "wma_api.h" + +#define HDD_IPA_DESC_BUFFER_RATIO 4 +#define HDD_IPA_IPV4_NAME_EXT "_ipv4" +#define HDD_IPA_IPV6_NAME_EXT "_ipv6" + +#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000 +#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET 12 +#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14 +/* WDI TX and RX PIPE */ +#define HDD_IPA_UC_NUM_WDI_PIPE 2 +#define HDD_IPA_UC_MAX_PENDING_EVENT 33 + +#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000 +#define HDD_IPA_UC_RT_DEBUG_PERIOD 300 +#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30 +#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000 + +#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0 +#define HDD_IPA_MAX_IFACE 3 +#define HDD_IPA_MAX_SYSBAM_PIPE 4 +#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE +#define HDD_IPA_ENABLE_MASK BIT(0) +#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1) +#define HDD_IPA_IPV6_ENABLE_MASK BIT(2) +#define HDD_IPA_RM_ENABLE_MASK BIT(3) +#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4) +#define HDD_IPA_UC_ENABLE_MASK BIT(5) +#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6) +#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8) + +typedef enum { + HDD_IPA_UC_OPCODE_TX_SUSPEND = 0, + HDD_IPA_UC_OPCODE_TX_RESUME = 1, + HDD_IPA_UC_OPCODE_RX_SUSPEND = 2, + HDD_IPA_UC_OPCODE_RX_RESUME = 3, + HDD_IPA_UC_OPCODE_STATS = 4, + /* keep this last */ + HDD_IPA_UC_OPCODE_MAX +} hdd_ipa_uc_op_code; + +/** + * enum - Reason codes for stat query + * + * @HDD_IPA_UC_STAT_REASON_NONE: Initial value + * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info + * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration + */ +enum { + HDD_IPA_UC_STAT_REASON_NONE, + HDD_IPA_UC_STAT_REASON_DEBUG, + HDD_IPA_UC_STAT_REASON_BW_CAL +}; + +/** + * enum hdd_ipa_rm_state - IPA resource manager state + * @HDD_IPA_RM_RELEASED: PROD pipe resource released + * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet + * @HDD_IPA_RM_GRANTED: PROD pipe resource granted + */ +enum hdd_ipa_rm_state { + HDD_IPA_RM_RELEASED, + HDD_IPA_RM_GRANT_PENDING, + HDD_IPA_RM_GRANTED, +}; + +struct llc_snap_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t resv[4]; + __be16 eth_type; +} __packed; + +struct hdd_ipa_tx_hdr { + struct ethhdr eth; + struct llc_snap_hdr llc_snap; +} __packed; + +struct frag_header { + uint32_t + length:16, /* length field is LSB of the FRAG DESC */ + reserved16:16; + uint32_t reserved32; +} __packed; + +struct ipa_header { + uint32_t + vdev_id:8, /* vdev_id field is LSB of IPA DESC */ + reserved:24; +} __packed; + +struct hdd_ipa_uc_tx_hdr { + struct frag_header frag_hd; + struct ipa_header ipa_hd; + struct ethhdr eth; +} __packed; + +#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) +#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct frag_header) + +/** + * struct hdd_ipa_cld_hdr - IPA CLD Header + * @reserved: reserved fields + * @iface_id: interface ID + * @sta_id: Station ID + * + * Packed 32-bit structure + * +----------+----------+--------------+--------+ + * | Reserved | QCMAP ID | interface id | STA ID | + * +----------+----------+--------------+--------+ + */ +struct hdd_ipa_cld_hdr { + uint8_t reserved[2]; + uint8_t iface_id; + uint8_t sta_id; +} __packed; + +struct hdd_ipa_rx_hdr { + struct hdd_ipa_cld_hdr cld_hdr; + struct ethhdr eth; +} __packed; + +struct hdd_ipa_pm_tx_cb { + struct hdd_ipa_iface_context *iface_context; + struct ipa_rx_data *ipa_tx_desc; +}; + +struct hdd_ipa_uc_rx_hdr { + struct ethhdr eth; +} __packed; + +struct hdd_ipa_sys_pipe { + uint32_t conn_hdl; + uint8_t conn_hdl_valid; + struct ipa_sys_connect_params ipa_sys_params; +}; + +struct hdd_ipa_iface_stats { + uint64_t num_tx; + uint64_t num_tx_drop; + uint64_t num_tx_err; + uint64_t num_tx_cac_drop; + uint64_t num_rx_prefilter; + uint64_t num_rx_ipa_excep; + uint64_t num_rx_recv; + uint64_t num_rx_recv_mul; + uint64_t num_rx_send_desc_err; + uint64_t max_rx_mul; +}; + +struct hdd_ipa_priv; + +struct hdd_ipa_iface_context { + struct hdd_ipa_priv *hdd_ipa; + hdd_adapter_t *adapter; + void *tl_context; + + enum ipa_client_type cons_client; + enum ipa_client_type prod_client; + + uint8_t iface_id; /* This iface ID */ + uint8_t sta_id; /* This iface station ID */ + cdf_spinlock_t interface_lock; + uint32_t ifa_address; + struct hdd_ipa_iface_stats stats; +}; + +struct hdd_ipa_stats { + uint32_t event[IPA_WLAN_EVENT_MAX]; + uint64_t num_send_msg; + uint64_t num_free_msg; + + uint64_t num_rm_grant; + uint64_t num_rm_release; + uint64_t num_rm_grant_imm; + uint64_t num_cons_perf_req; + uint64_t num_prod_perf_req; + + uint64_t num_rx_drop; + uint64_t num_rx_ipa_tx_dp; + uint64_t num_rx_ipa_splice; + uint64_t num_rx_ipa_loop; + uint64_t num_rx_ipa_tx_dp_err; + uint64_t num_rx_ipa_write_done; + uint64_t num_max_ipa_tx_mul; + uint64_t num_rx_ipa_hw_maxed_out; + uint64_t max_pend_q_cnt; + + uint64_t num_tx_comp_cnt; + uint64_t num_tx_queued; + uint64_t num_tx_dequeued; + uint64_t num_max_pm_queue; + + uint64_t num_freeq_empty; + uint64_t num_pri_freeq_empty; + uint64_t num_rx_excep; + uint64_t num_tx_bcmc; + uint64_t num_tx_bcmc_err; +}; + +struct ipa_uc_stas_map { + bool is_reserved; + uint8_t sta_id; +}; +struct op_msg_type { + uint8_t msg_t; + uint8_t rsvd; + uint16_t op_code; + uint16_t len; + uint16_t rsvd_snd; +}; + +struct ipa_uc_fw_stats { + uint32_t tx_comp_ring_base; + uint32_t tx_comp_ring_size; + uint32_t tx_comp_ring_dbell_addr; + uint32_t tx_comp_ring_dbell_ind_val; + uint32_t tx_comp_ring_dbell_cached_val; + uint32_t tx_pkts_enqueued; + uint32_t tx_pkts_completed; + uint32_t tx_is_suspend; + uint32_t tx_reserved; + uint32_t rx_ind_ring_base; + uint32_t rx_ind_ring_size; + uint32_t rx_ind_ring_dbell_addr; + uint32_t rx_ind_ring_dbell_ind_val; + uint32_t rx_ind_ring_dbell_ind_cached_val; + uint32_t rx_ind_ring_rdidx_addr; + uint32_t rx_ind_ring_rd_idx_cached_val; + uint32_t rx_refill_idx; + uint32_t rx_num_pkts_indicated; + uint32_t rx_buf_refilled; + uint32_t rx_num_ind_drop_no_space; + uint32_t rx_num_ind_drop_no_buf; + uint32_t rx_is_suspend; + uint32_t rx_reserved; +}; + +struct ipa_uc_pending_event { + cdf_list_node_t node; + hdd_adapter_t *adapter; + enum ipa_wlan_event type; + uint8_t sta_id; + uint8_t mac_addr[CDF_MAC_ADDR_SIZE]; +}; + +/** + * struct uc_rm_work_struct + * @work: uC RM work + * @event: IPA RM event + */ +struct uc_rm_work_struct { + struct work_struct work; + enum ipa_rm_event event; +}; + +/** + * struct uc_op_work_struct + * @work: uC OP work + * @msg: OP message + */ +struct uc_op_work_struct { + struct work_struct work; + struct op_msg_type *msg; +}; +static uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX]; + +/** + * struct uc_rt_debug_info + * @time: system time + * @ipa_excep_count: IPA exception packet count + * @rx_drop_count: IPA Rx drop packet count + * @net_sent_count: IPA Rx packet sent to network stack count + * @rx_discard_count: IPA Rx discard packet count + * @rx_mcbc_count: IPA Rx BCMC packet count + * @tx_mcbc_count: IPA Tx BCMC packet countt + * @tx_fwd_count: IPA Tx forward packet count + * @rx_destructor_call: IPA Rx packet destructor count + */ +struct uc_rt_debug_info { + v_TIME_t time; + uint64_t ipa_excep_count; + uint64_t rx_drop_count; + uint64_t net_sent_count; + uint64_t rx_discard_count; + uint64_t rx_mcbc_count; + uint64_t tx_mcbc_count; + uint64_t tx_fwd_count; + uint64_t rx_destructor_call; +}; + +struct hdd_ipa_priv { + struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE]; + struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE]; + uint8_t num_iface; + enum hdd_ipa_rm_state rm_state; + /* + * IPA driver can send RM notifications with IRQ disabled so using cdf + * APIs as it is taken care gracefully. Without this, kernel would throw + * an warning if spin_lock_bh is used while IRQ is disabled + */ + cdf_spinlock_t rm_lock; + struct uc_rm_work_struct uc_rm_work; + struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX]; + cdf_wake_lock_t wake_lock; + struct delayed_work wake_lock_work; + bool wake_lock_released; + + enum ipa_client_type prod_client; + + atomic_t tx_ref_cnt; + cdf_nbuf_queue_t pm_queue_head; + struct work_struct pm_work; + cdf_spinlock_t pm_lock; + bool suspended; + + uint32_t pending_hw_desc_cnt; + uint32_t hw_desc_cnt; + spinlock_t q_lock; + uint32_t freeq_cnt; + struct list_head free_desc_head; + + uint32_t pend_q_cnt; + struct list_head pend_desc_head; + + hdd_context_t *hdd_ctx; + + struct dentry *debugfs_dir; + struct hdd_ipa_stats stats; + + struct notifier_block ipv4_notifier; + uint32_t curr_prod_bw; + uint32_t curr_cons_bw; + + uint8_t activated_fw_pipe; + uint8_t sap_num_connected_sta; + uint8_t sta_connected; + uint32_t tx_pipe_handle; + uint32_t rx_pipe_handle; + bool resource_loading; + bool resource_unloading; + bool pending_cons_req; + struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT]; + cdf_list_t pending_event; + cdf_mutex_t event_lock; + uint32_t ipa_tx_packets_diff; + uint32_t ipa_rx_packets_diff; + uint32_t ipa_p_tx_packets; + uint32_t ipa_p_rx_packets; + uint32_t stat_req_reason; + uint64_t ipa_tx_forward; + uint64_t ipa_rx_discard; + uint64_t ipa_rx_net_send_count; + uint64_t ipa_rx_internel_drop_count; + uint64_t ipa_rx_destructor_count; + cdf_mc_timer_t rt_debug_timer; + struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT]; + unsigned int rt_buf_fill_index; + cdf_mc_timer_t rt_debug_fill_timer; + cdf_mutex_t rt_debug_lock; +}; + +#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr) +#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0 +#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr) +#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr) +#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr) +#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr) + +#define HDD_IPA_GET_IFACE_ID(_data) \ + (((struct hdd_ipa_cld_hdr *) (_data))->iface_id) + +#define HDD_IPA_LOG(LVL, fmt, args ...) \ + CDF_TRACE(CDF_MODULE_ID_HDD, LVL, \ + "%s:%d: "fmt, __func__, __LINE__, ## args) + +#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \ + do { \ + CDF_TRACE(CDF_MODULE_ID_HDD, _lvl, "%s:", _prefix); \ + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_HDD, _lvl, _buf, _len); \ + } while (0) + +#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \ + (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask)) + +#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \ + do { \ + hdd_ipa->ipa_rx_internel_drop_count++; \ + } while (0) +#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \ + do { \ + hdd_ipa->ipa_rx_net_send_count++; \ + } while (0) +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) + +static struct hdd_ipa_adapter_2_client { + enum ipa_client_type cons_client; + enum ipa_client_type prod_client; +} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = { + { + IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD + }, { + IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD + }, { + IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD + }, +}; + +/* For Tx pipes, use Ethernet-II Header format */ +struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = { + { + 0x00000000, + 0x00000000 + }, + { + 0x00000000 + }, + { + {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, + {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, + 0x0008 + } +}; + +/* For Tx pipes, use 802.3 Header format */ +static struct hdd_ipa_tx_hdr ipa_tx_hdr = { + { + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + 0x00 /* length can be zero */ + }, + { + /* LLC SNAP header 8 bytes */ + 0xaa, 0xaa, + {0x03, 0x00, 0x00, 0x00}, + 0x0008 /* type value(2 bytes) ,filled by wlan */ + /* 0x0800 - IPV4, 0x86dd - IPV6 */ + } +}; + +static const char *op_string[] = { + "TX_SUSPEND", + "TX_RESUME", + "RX_SUSPEND", + "RX_RESUME", + "STATS", +}; + +static struct hdd_ipa_priv *ghdd_ipa; + +/* Local Function Prototypes */ +static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data); +static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data); + +static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context); + +/** + * hdd_ipa_is_enabled() - Is IPA enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if IPA is enabled, false otherwise + */ +bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if IPA uC offload is enabled, false otherwise + */ +bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if STA mode IPA uC offload is enabled, false otherwise + */ +static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK); +} + +/** + * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if pre-filter is enabled, otherwise false + */ +static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, + HDD_IPA_PRE_FILTER_ENABLE_MASK); +} + +/** + * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if IPv6 is enabled, otherwise false + */ +static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK); +} + +/** + * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if resource manager is enabled, otherwise false + */ +static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK); +} + +/** + * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if resource manager is enabled, otherwise false + */ +static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING); +} + +/** + * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if clock scaling is enabled, otherwise false + */ +static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, + HDD_IPA_CLK_SCALING_ENABLE_MASK | + HDD_IPA_RM_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer + * @ctext: pointer to hdd context. + * + * If rt debug enabled, periodically called, and fill debug buffer + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_host_fill(void *ctext) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)ctext; + struct hdd_ipa_priv *hdd_ipa; + struct uc_rt_debug_info *dump_info = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA UC is not enabled", __func__); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + cdf_mutex_acquire(&hdd_ipa->rt_debug_lock); + dump_info = &hdd_ipa->rt_bug_buffer[ + hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT]; + + dump_info->time = cdf_mc_timer_get_system_time(); + dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep; + dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count; + dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count; + dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard; + dump_info->tx_mcbc_count = hdd_ipa->stats.num_tx_bcmc; + dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward; + dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count; + hdd_ipa->rt_buf_fill_index++; + cdf_mutex_release(&hdd_ipa->rt_debug_lock); + + cdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer, + HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL); +} + +/** + * hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer + * @hdd_ctx: pointer to hdd context. + * + * If rt debug enabled, dump debug buffer contents based on requirement + * + * Return: none + */ +void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + unsigned int dump_count; + unsigned int dump_index; + struct uc_rt_debug_info *dump_info = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = hdd_ctx->hdd_ipa; + if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA UC is not enabled", __func__); + return; + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "========= WLAN-IPA DEBUG BUF DUMP ==========\n"); + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + " TM : EXEP : DROP : NETS : MCBC : TXFD : DSTR : DSCD\n"); + + cdf_mutex_acquire(&hdd_ipa->rt_debug_lock); + for (dump_count = 0; + dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_count++) { + dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) % + HDD_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_info = &hdd_ipa->rt_bug_buffer[dump_index]; + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%12lu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n", + dump_info->time, dump_info->ipa_excep_count, + dump_info->rx_drop_count, dump_info->net_sent_count, + dump_info->tx_mcbc_count, dump_info->tx_fwd_count, + dump_info->rx_destructor_call, + dump_info->rx_discard_count); + } + cdf_mutex_release(&hdd_ipa->rt_debug_lock); + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "======= WLAN-IPA DEBUG BUF DUMP END ========\n"); +} + +/** + * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler + * @ctext: pointer to hdd context. + * + * periodically called by timer expire + * will try to alloc dummy memory and detect out of memory condition + * if out of memory detected, dump wlan-ipa stats + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_handler(void *ctext) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)ctext; + struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + void *dummy_ptr = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA RT debug is not enabled", __func__); + return; + } + + /* Allocate dummy buffer periodically and free immediately. this will + * proactively detect OOM and if allocation fails dump ipa stats + */ + dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE, + GFP_KERNEL | GFP_ATOMIC); + if (!dummy_ptr) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Dummy alloc fail", __func__); + hdd_ipa_uc_rt_debug_host_dump(hdd_ctx); + hdd_ipa_uc_stat_request( + hdd_get_adapter(hdd_ctx, WLAN_HDD_SOFTAP), 1); + } else { + kfree(dummy_ptr); + } + + cdf_mc_timer_start(&hdd_ipa->rt_debug_timer, + HDD_IPA_UC_RT_DEBUG_PERIOD); +} + +/** + * hdd_ipa_uc_rt_debug_destructor - called by data packet free + * @skb: packet pinter + * + * when free data packet, will be invoked by wlan client and will increase + * free counter + * + * Return: none + */ +void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb) +{ + if (!ghdd_ipa) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: invalid hdd context", __func__); + return; + } + + ghdd_ipa->ipa_rx_destructor_count++; +} + +/** + * hdd_ipa_uc_rt_debug_deinit - remove resources to handle rt debugging + * @hdd_ctx: hdd main context + * + * free all rt debugging resources + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + if (CDF_TIMER_STATE_STOPPED != + cdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) { + cdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer); + } + cdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer); + cdf_mutex_destroy(&hdd_ipa->rt_debug_lock); + + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA RT debug is not enabled", __func__); + return; + } + + if (CDF_TIMER_STATE_STOPPED != + cdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) { + cdf_mc_timer_stop(&hdd_ipa->rt_debug_timer); + } + cdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer); +} + +/** + * hdd_ipa_uc_rt_debug_init - intialize resources to handle rt debugging + * @hdd_ctx: hdd main context + * + * alloc and initialize all rt debugging resources + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + cdf_mutex_init(&hdd_ipa->rt_debug_lock); + cdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, CDF_TIMER_TYPE_SW, + hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx); + hdd_ipa->rt_buf_fill_index = 0; + cdf_mem_zero(hdd_ipa->rt_bug_buffer, + sizeof(struct uc_rt_debug_info) * + HDD_IPA_UC_RT_DEBUG_BUF_COUNT); + hdd_ipa->ipa_tx_forward = 0; + hdd_ipa->ipa_rx_discard = 0; + hdd_ipa->ipa_rx_net_send_count = 0; + hdd_ipa->ipa_rx_internel_drop_count = 0; + hdd_ipa->ipa_rx_destructor_count = 0; + + cdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer, + HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL); + + /* Reatime debug enable on feature enable */ + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA RT debug is not enabled", __func__); + return; + } + cdf_mc_timer_init(&hdd_ipa->rt_debug_timer, CDF_TIMER_TYPE_SW, + hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx); + cdf_mc_timer_start(&hdd_ipa->rt_debug_timer, + HDD_IPA_UC_RT_DEBUG_PERIOD); + +} + +/** + * hdd_ipa_uc_stat_query() - Query the IPA stats + * @hdd_ctx: Global HDD context + * @ipa_tx_diff: tx packet count diff from previous + * tx packet count + * @ipa_rx_diff: rx packet count diff from previous + * rx packet count + * + * Return: true if IPA is enabled, false otherwise + */ +void hdd_ipa_uc_stat_query(hdd_context_t *pHddCtx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + struct hdd_ipa_priv *hdd_ipa; + + hdd_ipa = (struct hdd_ipa_priv *)pHddCtx->hdd_ipa; + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + + if (!hdd_ipa_is_enabled(pHddCtx) || + !(hdd_ipa_uc_is_enabled(pHddCtx))) { + return; + } + + cdf_mutex_acquire(&hdd_ipa->event_lock); + if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) && + (false == hdd_ipa->resource_loading)) { + *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff; + *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff; + HDD_IPA_LOG(LOG1, "STAT Query TX DIFF %d, RX DIFF %d", + *ipa_tx_diff, *ipa_rx_diff); + } + cdf_mutex_release(&hdd_ipa->event_lock); + return; +} + +/** + * hdd_ipa_uc_stat_request() - Get IPA stats from IPA. + * @adapter: network adapter + * @reason: STAT REQ Reason + * + * Return: None + */ +void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason) +{ + hdd_context_t *pHddCtx; + struct hdd_ipa_priv *hdd_ipa; + + if (!adapter) { + return; + } + + pHddCtx = (hdd_context_t *)adapter->pHddCtx; + hdd_ipa = (struct hdd_ipa_priv *)pHddCtx->hdd_ipa; + if (!hdd_ipa_is_enabled(pHddCtx) || + !(hdd_ipa_uc_is_enabled(pHddCtx))) { + return; + } + + HDD_IPA_LOG(LOG1, "STAT REQ Reason %d", reason); + cdf_mutex_acquire(&hdd_ipa->event_lock); + if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) && + (false == hdd_ipa->resource_loading)) { + hdd_ipa->stat_req_reason = reason; + wma_cli_set_command( + (int)adapter->sessionId, + (int)WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID, + 0, VDEV_CMD); + } + cdf_mutex_release(&hdd_ipa->event_lock); +} + +/** + * hdd_ipa_uc_find_add_assoc_sta() - Find associated station + * @hdd_ipa: Global HDD IPA context + * @sta_add: Should station be added + * @sta_id: ID of the station being queried + * + * Return: true if the station was found + */ +static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, + bool sta_add, uint8_t sta_id) +{ + bool sta_found = false; + uint8_t idx; + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if ((hdd_ipa->assoc_stas_map[idx].is_reserved) && + (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) { + sta_found = true; + break; + } + } + if (sta_add && sta_found) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d already exist, cannot add", + __func__, sta_id); + return sta_found; + } + if (sta_add) { + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if (!hdd_ipa->assoc_stas_map[idx].is_reserved) { + hdd_ipa->assoc_stas_map[idx].is_reserved = true; + hdd_ipa->assoc_stas_map[idx].sta_id = sta_id; + return sta_found; + } + } + } + if (!sta_add && !sta_found) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d does not exist, cannot delete", + __func__, sta_id); + return sta_found; + } + if (!sta_add) { + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if ((hdd_ipa->assoc_stas_map[idx].is_reserved) && + (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) { + hdd_ipa->assoc_stas_map[idx].is_reserved = + false; + hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF; + return sta_found; + } + } + } + return sta_found; +} + +/** + * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; + + /* ACTIVATE TX PIPE */ + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Enable TX PIPE", __func__); + result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Enable TX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Resume TX PIPE fail, code %d", + __func__, result); + return result; + } + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, true); + + /* ACTIVATE RX PIPE */ + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Enable RX PIPE", __func__); + result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Enable RX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Resume RX PIPE fail, code %d", + __func__, result); + return result; + } + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, false); + + return 0; +} + +/** + * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__); + result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Suspend RX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Disable RX PIPE fail, code %d", + __func__, result); + return result; + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__); + result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Suspend TX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Disable TX PIPE fail, code %d", + __func__, result); + return result; + } + + return 0; +} + +/** + * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) +{ + hdd_ipa->activated_fw_pipe = 0; + hdd_ipa->resource_loading = true; + /* If RM feature enabled + * Request PROD Resource first + * PROD resource may return sync or async manners */ + if ((hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) && + (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD))) { + /* RM PROD request sync return + * enable pipe immediately */ + if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: IPA WDI Pipes activate fail", + __func__); + hdd_ipa->resource_loading = false; + return -EBUSY; + } + } else { + /* RM Disabled + * Just enabled all the PIPEs */ + if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: IPA WDI Pipes activate fail", + __func__); + hdd_ipa->resource_loading = false; + return -EBUSY; + } + hdd_ipa->resource_loading = false; + } + return 0; +} + +/** + * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) +{ + p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; + + hdd_ipa->resource_unloading = true; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__); + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, false); + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__); + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, true); +} + +/** + * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler + * @context: User context registered with TL (the IPA Global context is + * registered + * @rxpkt: Packet containing the notification + * @staid: ID of the station associated with the packet + * + * Return: None + */ +static void +hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) +{ + struct hdd_ipa_priv *hdd_ipa = context; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "HDD context is not valid"); + return; + } + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s, event code %d", + __func__, event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + /* Differed RM Granted */ + hdd_ipa_uc_enable_pipes(hdd_ipa); + cdf_mutex_acquire(&hdd_ipa->event_lock); + if ((false == hdd_ipa->resource_unloading) && + (!hdd_ipa->activated_fw_pipe)) { + hdd_ipa_uc_enable_pipes(hdd_ipa); + } + cdf_mutex_release(&hdd_ipa->event_lock); + if (hdd_ipa->pending_cons_req) { + ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED, + IPA_RM_RESOURCE_WLAN_CONS); + } + hdd_ipa->pending_cons_req = false; + break; + + case IPA_RM_RESOURCE_RELEASED: + /* Differed RM Released */ + hdd_ipa->resource_unloading = false; + if (hdd_ipa->pending_cons_req) { + ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED, + IPA_RM_RESOURCE_WLAN_CONS); + } + hdd_ipa->pending_cons_req = false; + break; + + default: + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s, invalid event code %d", __func__, event); + break; + } +} + +/** + * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification + * @hdd_ipa: Global HDD IPA context + * @event: IPA resource manager event to be deferred + * + * This function is called when a resource manager event is received + * from firmware in interrupt context. This function will defer the + * handling to the OL RX thread + * + * Return: None + */ +static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) +{ + enum ipa_rm_event event; + struct uc_rm_work_struct *uc_rm_work = container_of(work, + struct uc_rm_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work, + struct hdd_ipa_priv, uc_rm_work); + + cds_ssr_protect(__func__); + event = uc_rm_work->event; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "%s, posted event %d", __func__, event); + + hdd_ipa_uc_rm_notify_handler(hdd_ipa, event); + cds_ssr_unprotect(__func__); + + return; +} + +/** + * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa) +{ + unsigned int pending_event_count; + struct ipa_uc_pending_event *pending_event = NULL; + + cdf_list_size(&hdd_ipa->pending_event, &pending_event_count); + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s, Pending Event Count %d", __func__, pending_event_count); + if (!pending_event_count) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s, No Pending Event", __func__); + return; + } + + cdf_list_remove_front(&hdd_ipa->pending_event, + (cdf_list_node_t **)&pending_event); + while (pending_event != NULL) { + hdd_ipa_wlan_evt(pending_event->adapter, + pending_event->type, + pending_event->sta_id, + pending_event->mac_addr); + cdf_mem_free(pending_event); + pending_event = NULL; + cdf_list_remove_front(&hdd_ipa->pending_event, + (cdf_list_node_t **)&pending_event); + } +} + +/** + * hdd_ipa_uc_op_cb() - IPA uC operation callback + * @op_msg: operation message received from firmware + * @usr_ctxt: user context registered with TL (we register the HDD Global + * context) + * + * Return: None + */ +static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_fw_stats *uc_fw_stat; + struct IpaHwStatsWDIInfoData_t ipa_stat; + struct hdd_ipa_priv *hdd_ipa; + hdd_context_t *hdd_ctx; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (!op_msg || !usr_ctxt) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__); + return; + } + + if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s, INVALID OPCODE %d", __func__, msg->op_code); + return; + } + + hdd_ctx = (hdd_context_t *) usr_ctxt; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "HDD context is not valid"); + cdf_mem_free(op_msg); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_DEBUG, + "%s, OPCODE %s", __func__, op_string[msg->op_code]); + + if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) || + (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) { + cdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa->activated_fw_pipe++; + if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) { + hdd_ipa->resource_loading = false; + hdd_ipa_uc_proc_pending_event(hdd_ipa); + } + cdf_mutex_release(&hdd_ipa->event_lock); + } + + if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) || + (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) { + cdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa->activated_fw_pipe--; + if (!hdd_ipa->activated_fw_pipe) { + hdd_ipa_uc_disable_pipes(hdd_ipa); + if ((hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) && + (!ipa_rm_release_resource(IPA_RM_RESOURCE_WLAN_PROD))) { + /* Sync return success from IPA + * Enable/resume all the PIPEs */ + hdd_ipa->resource_unloading = false; + hdd_ipa_uc_proc_pending_event(hdd_ipa); + } else { + hdd_ipa->resource_unloading = false; + hdd_ipa_uc_proc_pending_event(hdd_ipa); + } + } + cdf_mutex_release(&hdd_ipa->event_lock); + } + + if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) && + (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) { + + /* STATs from host */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST CE ====\n" + "CE RING BASE: 0x%x\n" + "CE RING SIZE: %d\n" + "CE REG ADDR : 0x%llx", + hdd_ctx->ce_sr_base_paddr, + hdd_ctx->ce_sr_ring_size, + (uint64_t) hdd_ctx->ce_reg_paddr); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST TX ====\n" + "COMP RING BASE: 0x%x\n" + "COMP RING SIZE: %d\n" + "NUM ALLOC BUF: %d\n" + "COMP RING DBELL : 0x%x", + hdd_ctx->tx_comp_ring_base_paddr, + hdd_ctx->tx_comp_ring_size, + hdd_ctx->tx_num_alloc_buffer, + hdd_ctx->tx_comp_doorbell_paddr); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST RX ====\n" + "IND RING BASE: 0x%x\n" + "IND RING SIZE: %d\n" + "IND RING DBELL : 0x%x\n" + "PROC DONE IND ADDR : 0x%x\n" + "NUM EXCP PKT : %llu\n" + "NUM TX BCMC : %llu\n" + "NUM TX BCMC ERR : %llu", + hdd_ctx->rx_rdy_ring_base_paddr, + hdd_ctx->rx_rdy_ring_size, + hdd_ctx->rx_ready_doorbell_paddr, + hdd_ctx->rx_proc_done_idx_paddr, + hdd_ipa->stats.num_rx_excep, + hdd_ipa->stats.num_tx_bcmc, + hdd_ipa->stats.num_tx_bcmc_err); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST CONTROL ====\n" + "SAP NUM STAs: %d\n" + "STA CONNECTED: %d\n" + "TX PIPE HDL: %d\n" + "RX PIPE HDL : %d\n" + "RSC LOADING : %d\n" + "RSC UNLOADING : %d\n" + "PNDNG CNS RQT : %d", + hdd_ipa->sap_num_connected_sta, + hdd_ipa->sta_connected, + hdd_ipa->tx_pipe_handle, + hdd_ipa->rx_pipe_handle, + (unsigned int)hdd_ipa->resource_loading, + (unsigned int)hdd_ipa->resource_unloading, + (unsigned int)hdd_ipa->pending_cons_req); + + /* STATs from FW */ + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_FW TX ====\n" + "COMP RING BASE: 0x%x\n" + "COMP RING SIZE: %d\n" + "COMP RING DBELL : 0x%x\n" + "COMP RING DBELL IND VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "PKTS ENQ : %d\n" + "PKTS COMP : %d\n" + "IS SUSPEND : %d\n" + "RSVD : 0x%x", + uc_fw_stat->tx_comp_ring_base, + uc_fw_stat->tx_comp_ring_size, + uc_fw_stat->tx_comp_ring_dbell_addr, + uc_fw_stat->tx_comp_ring_dbell_ind_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_pkts_enqueued, + uc_fw_stat->tx_pkts_completed, + uc_fw_stat->tx_is_suspend, uc_fw_stat->tx_reserved); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_FW RX ====\n" + "IND RING BASE: 0x%x\n" + "IND RING SIZE: %d\n" + "IND RING DBELL : 0x%x\n" + "IND RING DBELL IND VAL : %d\n" + "IND RING DBELL CACHED VAL : %d\n" + "RDY IND ADDR : 0x%x\n" + "RDY IND CACHE VAL : %d\n" + "RFIL IND : %d\n" + "NUM PKT INDICAT : %d\n" + "BUF REFIL : %d\n" + "NUM DROP NO SPC : %d\n" + "NUM DROP NO BUF : %d\n" + "IS SUSPND : %d\n" + "RSVD : 0x%x\n", + uc_fw_stat->rx_ind_ring_base, + uc_fw_stat->rx_ind_ring_size, + uc_fw_stat->rx_ind_ring_dbell_addr, + uc_fw_stat->rx_ind_ring_dbell_ind_val, + uc_fw_stat->rx_ind_ring_dbell_ind_cached_val, + uc_fw_stat->rx_ind_ring_rdidx_addr, + uc_fw_stat->rx_ind_ring_rd_idx_cached_val, + uc_fw_stat->rx_refill_idx, + uc_fw_stat->rx_num_pkts_indicated, + uc_fw_stat->rx_buf_refilled, + uc_fw_stat->rx_num_ind_drop_no_space, + uc_fw_stat->rx_num_ind_drop_no_buf, + uc_fw_stat->rx_is_suspend, uc_fw_stat->rx_reserved); + /* STATs from IPA */ + ipa_get_wdi_stats(&ipa_stat); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC IPA TX ====\n" + "NUM PROCD : %d\n" + "CE DBELL : 0x%x\n" + "NUM DBELL FIRED : %d\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DBELL : %d\n" + "NUM UNEXP DBELL : %d\n" + "NUM BAM INT HDL : 0x%x\n" + "NUM BAM INT NON-RUN : 0x%x\n" + "NUM QMB INT HDL : 0x%x", + ipa_stat.tx_ch_stats.num_pkts_processed, + ipa_stat.tx_ch_stats.copy_engine_doorbell_value, + ipa_stat.tx_ch_stats.num_db_fired, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow, + ipa_stat.tx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.tx_ch_stats.num_db, + ipa_stat.tx_ch_stats.num_unexpected_db, + ipa_stat.tx_ch_stats.num_bam_int_handled, + ipa_stat.tx_ch_stats. + num_bam_int_in_non_runnning_state, + ipa_stat.tx_ch_stats.num_qmb_int_handled); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "==== IPA_UC IPA RX ====\n" + "MAX OST PKT : %d\n" + "NUM PKT PRCSD : %d\n" + "RNG RP : 0x%x\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DB : %d\n" + "NUM UNEXP DB : %d\n" + "NUM BAM INT HNDL : 0x%x\n", + ipa_stat.rx_ch_stats.max_outstanding_pkts, + ipa_stat.rx_ch_stats.num_pkts_processed, + ipa_stat.rx_ch_stats.rx_ring_rp_value, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow, + ipa_stat.rx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.rx_ch_stats.num_db, + ipa_stat.rx_ch_stats.num_unexpected_db, + ipa_stat.rx_ch_stats.num_bam_int_handled); + } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) && + (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) { + /* STATs from FW */ + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + cdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF( + uc_fw_stat->tx_pkts_completed, + hdd_ipa->ipa_p_tx_packets); + hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF( + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated), + hdd_ipa->ipa_p_rx_packets); + + hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed; + hdd_ipa->ipa_p_rx_packets = + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated); + cdf_mutex_release(&hdd_ipa->event_lock); + } else { + HDD_IPA_LOG(LOGE, "INVALID REASON %d", + hdd_ipa->stat_req_reason); + } + cdf_mem_free(op_msg); +} + + +/** + * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw + * @adapter: device adapter instance + * @offload_type: MCC or SCC + * @enable: TX offload enable or disable + * + * Return: none + */ +static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter, + uint32_t offload_type, uint32_t enable) +{ + struct sir_ipa_offload_enable_disable ipa_offload_enable_disable; + + /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during + * channel change indication. Since these indications are sent by lower + * layer as SAP updates and IPA doesn't have to do anything for these + * updates so ignoring! + */ + if (WLAN_HDD_SOFTAP == adapter->device_mode && adapter->ipa_context) + return; + + /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during + * channel change indication. Since these indications are sent by lower + * layer as SAP updates and IPA doesn't have to do anything for these + * updates so ignoring! + */ + if (adapter->ipa_context) + return; + + cdf_mem_zero(&ipa_offload_enable_disable, + sizeof(ipa_offload_enable_disable)); + ipa_offload_enable_disable.offload_type = offload_type; + ipa_offload_enable_disable.vdev_id = adapter->sessionId; + ipa_offload_enable_disable.enable = enable; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: offload_type=%d, vdev_id=%d, enable=%d", __func__, + ipa_offload_enable_disable.offload_type, + ipa_offload_enable_disable.vdev_id, + ipa_offload_enable_disable.enable); + + if (CDF_STATUS_SUCCESS != + sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, &ipa_offload_enable_disable)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Failure to enable IPA offload \ + (offload_type=%d, vdev_id=%d, enable=%d)", __func__, + ipa_offload_enable_disable.offload_type, + ipa_offload_enable_disable.vdev_id, + ipa_offload_enable_disable.enable); + } +} + +/** + * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler + * @work: uC OP work + * + * Return: None + */ +static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work) +{ + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work = container_of(work, + struct uc_op_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + + cds_ssr_protect(__func__); + + msg = uc_op_work->msg; + uc_op_work->msg = NULL; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "%s, posted msg %d", __func__, msg->op_code); + + hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx); + + cds_ssr_unprotect(__func__); + + return; +} + +/** + * hdd_ipa_uc_op_event_handler() - Adapter lookup + * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler + * @op_msg: operation message received from firmware + * @hdd_ctx: Global HDD context + * + * Return: None + */ +static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "HDD context is not valid"); + goto end; + } + + msg = (struct op_msg_type *)op_msg; + hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa; + + if (unlikely(!hdd_ipa)) + goto end; + + if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)", + __func__, msg->op_code); + goto end; + } + + uc_op_work = &hdd_ipa->uc_op_work[msg->op_code]; + if (uc_op_work->msg) + /* When the same uC OPCODE is already pended, just return */ + goto end; + + uc_op_work->msg = msg; + schedule_work(&uc_op_work->work); + return; + +end: + cdf_mem_free(op_msg); +} + +/** + * hdd_ipa_uc_ol_init() - Initialize IPA uC offload + * @hdd_ctx: Global HDD context + * + * Return: CDF_STATUS + */ +static CDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) +{ + struct ipa_wdi_in_params pipe_in; + struct ipa_wdi_out_params pipe_out; + struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + p_cds_contextType cds_ctx = hdd_ctx->pcds_context; + uint8_t i; + + cdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); + cdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); + + cdf_list_init(&ipa_ctxt->pending_event, 1000); + cdf_mutex_init(&ipa_ctxt->event_lock); + + /* TX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize; + pipe_in.sys.priv = hdd_ctx->hdd_ipa; + pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + pipe_in.sys.notify = hdd_ipa_i2w_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.dl.comp_ring_base_pa = hdd_ctx->tx_comp_ring_base_paddr; + pipe_in.u.dl.comp_ring_size = hdd_ctx->tx_comp_ring_size * 4; + pipe_in.u.dl.ce_ring_base_pa = hdd_ctx->ce_sr_base_paddr; + pipe_in.u.dl.ce_door_bell_pa = hdd_ctx->ce_reg_paddr; + pipe_in.u.dl.ce_ring_size = hdd_ctx->ce_sr_ring_size * 8; + pipe_in.u.dl.num_tx_buffers = hdd_ctx->tx_num_alloc_buffer; + + /* Connect WDI IPA PIPE */ + ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + /* Micro Controller Doorbell register */ + hdd_ctx->tx_comp_doorbell_paddr = (uint32_t) pipe_out.uc_door_bell_pa; + /* WLAN TX PIPE Handle */ + ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," + " CERZ %d, NB %d, CDBPAD 0x%x", + (unsigned int)pipe_in.u.dl.comp_ring_base_pa, + pipe_in.u.dl.comp_ring_size, + (unsigned int)pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)pipe_in.u.dl.ce_door_bell_pa, + pipe_in.u.dl.ce_ring_size, + pipe_in.u.dl.num_tx_buffers, + (unsigned int)hdd_ctx->tx_comp_doorbell_paddr); + + /* RX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize + + sizeof(struct sps_iovec); + pipe_in.sys.notify = hdd_ipa_w2i_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.ul.rdy_ring_base_pa = hdd_ctx->rx_rdy_ring_base_paddr; + pipe_in.u.ul.rdy_ring_size = hdd_ctx->rx_rdy_ring_size; + pipe_in.u.ul.rdy_ring_rp_pa = hdd_ctx->rx_proc_done_idx_paddr; + + ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + hdd_ctx->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", + (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, + pipe_in.u.ul.rdy_ring_size, + (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, + (unsigned int)hdd_ctx->rx_ready_doorbell_paddr); + + ol_txrx_ipa_uc_set_doorbell_paddr(cds_ctx->pdev_txrx_ctx, + (uint32_t) hdd_ctx->tx_comp_doorbell_paddr, + (uint32_t) hdd_ctx->rx_ready_doorbell_paddr); + + ol_txrx_ipa_uc_register_op_cb(cds_ctx->pdev_txrx_ctx, + hdd_ipa_uc_op_event_handler, (void *)hdd_ctx); + + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + cnss_init_work(&ipa_ctxt->uc_op_work[i].work, + hdd_ipa_uc_fw_op_event_handler); + ipa_ctxt->uc_op_work[i].msg = NULL; + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef IPA_UC_OFFLOAD +/** + * hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR + * + * Deinit basic IPA UC host side to be in sync reloaded FW during + * SSR + * + * Return: 0 - Success + */ +int hdd_ipa_uc_ssr_deinit(void) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int idx; + struct hdd_ipa_iface_context *iface_context; + + if (!hdd_ipa_uc_is_enabled(hdd_ipa)) + return 0; + + /* Clean up HDD IPA interfaces */ + for (idx = 0; (hdd_ipa->num_iface > 0) && + (idx < HDD_IPA_MAX_IFACE); idx++) { + iface_context = &hdd_ipa->iface_context[idx]; + if (iface_context && iface_context->adapter) + hdd_ipa_cleanup_iface(iface_context); + } + + /* After SSR, wlan driver reloads FW again. But we need to protect + * IPA submodule during SSR transient state. So deinit basic IPA + * UC host side to be in sync with reloaded FW during SSR + */ + hdd_ipa_uc_disable_pipes(hdd_ipa); + + cdf_wake_lock_acquire(&hdd_ipa->event_lock); + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + hdd_ipa->assoc_stas_map[idx].is_reserved = false; + hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF; + } + cdf_wake_lock_release(&hdd_ipa->event_lock); + + /* Full IPA driver cleanup not required since wlan driver is now + * unloaded and reloaded after SSR. + */ + return 0; +} + +/** + * hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR + * + * Init basic IPA UC host side to be in sync with reloaded FW after + * SSR to resume IPA UC operations + * + * Return: 0 - Success + */ +int hdd_ipa_uc_ssr_reinit(void) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + + if (!hdd_ipa_uc_is_enabled(hdd_ipa)) + return 0; + + /* After SSR is complete, IPA UC can resume operation. But now wlan + * driver will be unloaded and reloaded, which takes care of IPA cleanup + * and initialization. This is a placeholder func if IPA has to resume + * operations without driver reload. + */ + return 0; +} +#endif + +/** + * hdd_ipa_wake_lock_timer_func() - Wake lock work handler + * @work: scheduled work + * + * When IPA resources are released in hdd_ipa_rm_try_release() we do + * not want to immediately release the wake lock since the system + * would then potentially try to suspend when there is a healthy data + * rate. Deferred work is scheduled and this function handles the + * work. When this function is called, if the IPA resource is still + * released then we release the wake lock. + * + * Return: None + */ +static void hdd_ipa_wake_lock_timer_func(struct work_struct *work) +{ + struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work), + struct hdd_ipa_priv, + wake_lock_work); + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + + if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) + goto end; + + hdd_ipa->wake_lock_released = true; + cdf_wake_lock_release(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + +end: + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); +} + +/** + * hdd_ipa_rm_request() - Request resource from IPA + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + case HDD_IPA_RM_GRANT_PENDING: + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING; + break; + } + + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = ipa_rm_inactivity_timer_request_resource( + IPA_RM_RESOURCE_WLAN_PROD); + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (ret == 0) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + hdd_ipa->stats.num_rm_grant_imm++; + } + + cancel_delayed_work(&hdd_ipa->wake_lock_work); + if (hdd_ipa->wake_lock_released) { + cdf_wake_lock_acquire(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + hdd_ipa->wake_lock_released = false; + } + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_rm_try_release() - Attempt to release IPA resource + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 if resources released, negative errno otherwise + */ +static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + if (atomic_read(&hdd_ipa->tx_ref_cnt)) + return -EAGAIN; + + spin_lock_bh(&hdd_ipa->q_lock); + if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + (hdd_ipa->pending_hw_desc_cnt || hdd_ipa->pend_q_cnt)) { + spin_unlock_bh(&hdd_ipa->q_lock); + return -EAGAIN; + } + spin_unlock_bh(&hdd_ipa->q_lock); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + + if (!cdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) { + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + return -EAGAIN; + } + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + break; + case HDD_IPA_RM_GRANT_PENDING: + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + } + + /* IPA driver returns immediately so set the state here to avoid any + * race condition. + */ + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->stats.num_rm_release++; + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = + ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD); + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (unlikely(ret != 0)) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + WARN_ON(1); + } + + /* + * If wake_lock is released immediately, kernel would try to suspend + * immediately as well, Just avoid ping-pong between suspend-resume + * while there is healthy amount of data transfer going on by + * releasing the wake_lock after some delay. + */ + schedule_delayed_work(&hdd_ipa->wake_lock_work, + msecs_to_jiffies + (HDD_IPA_RX_INACTIVITY_MSEC_DELAY)); + + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_rm_notify() - IPA resource manager notifier callback + * @user_data: user data registered with IPA + * @event: the IPA resource manager event that occurred + * @data: the data associated with the event + * + * Return: None + */ +static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = user_data; + + if (unlikely(!hdd_ipa)) + return; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "Evt: %d", event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + /* RM Notification comes with ISR context + * it should be serialized into work queue to avoid + * ISR sleep problem + */ + hdd_ipa->uc_rm_work.event = event; + schedule_work(&hdd_ipa->uc_rm_work.work); + break; + } + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + hdd_ipa->stats.num_rm_grant++; + break; + + case IPA_RM_RESOURCE_RELEASED: + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "RM Release"); + hdd_ipa->resource_unloading = false; + break; + + default: + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event); + break; + } +} + +/** + * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler + * + * Callback function registered with IPA that is called when IPA wants + * to release the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_release(void) +{ + return 0; +} + +/** + * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler + * + * Callback function registered with IPA that is called when IPA wants + * to access the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_request(void) +{ + if ((ghdd_ipa->resource_loading) || (ghdd_ipa->resource_unloading)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: ipa resource loading/unloading in progress", + __func__); + ghdd_ipa->pending_cons_req = true; + return -EPERM; + } + return 0; +} + +/** + * hdd_ipa_set_perf_level() - Set IPA performance level + * @hdd_ctx: Global HDD context + * @tx_packets: Number of packets transmitted in the last sample period + * @rx_packets: Number of packets received in the last sample period + * + * Return: 0 on success, negative errno on error + */ +int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, + uint64_t rx_packets) +{ + uint32_t next_cons_bw, next_prod_bw; + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + struct ipa_rm_perf_profile profile; + int ret; + + if ((!hdd_ipa_is_enabled(hdd_ctx)) || + (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx))) + return 0; + + memset(&profile, 0, sizeof(profile)); + + if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2)) + next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps; + else if (tx_packets > + (hdd_ctx->config->busBandwidthMediumThreshold / 2)) + next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps; + else + next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps; + + if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2)) + next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps; + else if (rx_packets > + (hdd_ctx->config->busBandwidthMediumThreshold / 2)) + next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps; + else + next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps; + + HDD_IPA_LOG(LOG1, + "CONS perf curr: %d, next: %d", + hdd_ipa->curr_cons_bw, next_cons_bw); + HDD_IPA_LOG(LOG1, + "PROD perf curr: %d, next: %d", + hdd_ipa->curr_prod_bw, next_prod_bw); + + if (hdd_ipa->curr_cons_bw != next_cons_bw) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "Requesting CONS perf curr: %d, next: %d", + hdd_ipa->curr_cons_bw, next_cons_bw); + profile.max_supported_bandwidth_mbps = next_cons_bw; + ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS, + &profile); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "RM CONS set perf profile failed: %d", ret); + + return ret; + } + hdd_ipa->curr_cons_bw = next_cons_bw; + hdd_ipa->stats.num_cons_perf_req++; + } + + if (hdd_ipa->curr_prod_bw != next_prod_bw) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "Requesting PROD perf curr: %d, next: %d", + hdd_ipa->curr_prod_bw, next_prod_bw); + profile.max_supported_bandwidth_mbps = next_prod_bw; + ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD, + &profile); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "RM PROD set perf profile failed: %d", ret); + return ret; + } + hdd_ipa->curr_prod_bw = next_prod_bw; + hdd_ipa->stats.num_prod_perf_req++; + } + + return 0; +} + +/** + * hdd_ipa_setup_rm() - Setup IPA resource management + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_rm_create_params create_params = { 0 }; + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + cnss_init_work(&hdd_ipa->uc_rm_work.work, hdd_ipa_uc_rm_notify_defer); + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_PROD; + create_params.reg_params.user_data = hdd_ipa; + create_params.reg_params.notify_cb = hdd_ipa_rm_notify; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Create RM resource failed: %d", ret); + goto setup_rm_fail; + } + + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_CONS; + create_params.request_resource = hdd_ipa_rm_cons_request; + create_params.release_resource = hdd_ipa_rm_cons_release; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Create RM CONS resource failed: %d", ret); + goto delete_prod; + } + + ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD, + IPA_RM_RESOURCE_APPS_CONS); + + ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD, + HDD_IPA_RX_INACTIVITY_MSEC_DELAY); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "Timer init failed: %d", + ret); + goto timer_init_failed; + } + + /* Set the lowest bandwidth to start with */ + ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0); + + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Set perf level failed: %d", ret); + goto set_perf_failed; + } + + cdf_wake_lock_init(&hdd_ipa->wake_lock, "wlan_ipa"); +#ifdef CONFIG_CNSS + cnss_init_delayed_work(&hdd_ipa->wake_lock_work, + hdd_ipa_wake_lock_timer_func); +#else + INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work, + hdd_ipa_wake_lock_timer_func); +#endif + cdf_spinlock_init(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->wake_lock_released = true; + atomic_set(&hdd_ipa->tx_ref_cnt, 0); + + return ret; + +set_perf_failed: + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + +timer_init_failed: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + +delete_prod: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + +setup_rm_fail: + return ret; +} + +/** + * hdd_ipa_destroy_rm_resource() - Destroy IPA resources + * @hdd_ipa: Global HDD IPA context + * + * Destroys all resources associated with the IPA resource manager + * + * Return: None + */ +static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + cancel_delayed_work_sync(&hdd_ipa->wake_lock_work); + cdf_wake_lock_destroy(&hdd_ipa->wake_lock); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&hdd_ipa->uc_rm_work.work); +#endif + cdf_spinlock_destroy(&hdd_ipa->rm_lock); + + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + if (ret) + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "RM PROD resource delete failed %d", ret); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + if (ret) + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "RM CONS resource delete failed %d", ret); +} + +/** + * hdd_ipa_send_skb_to_network() - Send skb to kernel + * @skb: network buffer + * @adapter: network adapter + * + * Called when a network buffer is received which should not be routed + * to the IPA module. + * + * Return: None + */ +static void hdd_ipa_send_skb_to_network(cdf_nbuf_t skb, + hdd_adapter_t *adapter) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + unsigned int cpu_index; + + if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p", + adapter); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + cdf_nbuf_free(skb); + return; + } + + if (hdd_ipa->hdd_ctx->isUnloadInProgress) { + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + cdf_nbuf_free(skb); + return; + } + + skb->destructor = hdd_ipa_uc_rt_debug_destructor; + skb->dev = adapter->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + skb->ip_summed = CHECKSUM_NONE; + + cpu_index = wlan_hdd_get_cpu(); + + ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + if (netif_rx_ni(skb) == NET_RX_SUCCESS) + ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + else + ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + + HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa); + adapter->dev->last_rx = jiffies; +} + +#define FW_RX_DESC_DISCARD_M 0x1 +#define FW_RX_DESC_FORWARD_M 0x2 + +/** + * hdd_ipa_w2i_cb() - WLAN to IPA callback handler + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + hdd_adapter_t *adapter = NULL; + cdf_nbuf_t skb; + uint8_t iface_id; + uint8_t session_id; + struct hdd_ipa_iface_context *iface_context; + cdf_nbuf_t copy; + uint8_t fw_desc; + int ret; + + hdd_ipa = (struct hdd_ipa_priv *)priv; + + switch (evt) { + case IPA_RECEIVE: + skb = (cdf_nbuf_t) data; + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + session_id = (uint8_t)skb->cb[0]; + iface_id = vdev_to_iface[session_id]; + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "IPA_RECEIVE: session_id=%u, iface_id=%u", + session_id, iface_id); + } else { + iface_id = HDD_IPA_GET_IFACE_ID(skb->data); + } + + if (iface_id >= HDD_IPA_MAX_IFACE) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "IPA_RECEIVE: Invalid iface_id: %u", + iface_id); + HDD_IPA_DBG_DUMP(CDF_TRACE_LEVEL_INFO_HIGH, + "w2i -- skb", skb->data, 8); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + cdf_nbuf_free(skb); + return; + } + + iface_context = &hdd_ipa->iface_context[iface_id]; + adapter = iface_context->adapter; + + HDD_IPA_DBG_DUMP(CDF_TRACE_LEVEL_DEBUG, + "w2i -- skb", skb->data, 8); + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa->stats.num_rx_excep++; + skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN); + } else { + skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN); + } + + iface_context->stats.num_rx_ipa_excep++; + + /* Disable to forward Intra-BSS Rx packets when + * ap_isolate=1 in hostapd.conf + */ + if (adapter->sessionCtx.ap.apDisableIntraBssFwd) { + /* + * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send + * all Rx packets to IPA uC, which need to be forwarded + * to other interface. + * And, IPA driver will send back to WLAN host driver + * through exception pipe with fw_desc field set by FW. + * Here we are checking fw_desc field for FORWARD bit + * set, and forward to Tx. Then copy to kernel stack + * only when DISCARD bit is not set. + */ + fw_desc = (uint8_t)skb->cb[1]; + + if (fw_desc & FW_RX_DESC_DISCARD_M) { + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + hdd_ipa->ipa_rx_discard++; + cdf_nbuf_free(skb); + break; + } + + if (fw_desc & FW_RX_DESC_FORWARD_M) { + HDD_IPA_LOG( + CDF_TRACE_LEVEL_DEBUG, + "Forward packet to Tx (fw_desc=%d)", + fw_desc); + copy = cdf_nbuf_copy(skb); + if (copy) { + hdd_ipa->ipa_tx_forward++; + ret = hdd_softap_hard_start_xmit( + (struct sk_buff *)copy, + adapter->dev); + if (ret) { + HDD_IPA_LOG( + CDF_TRACE_LEVEL_DEBUG, + "Forward packet tx fail"); + hdd_ipa->stats. + num_tx_bcmc_err++; + } else { + hdd_ipa->stats.num_tx_bcmc++; + } + } + } + } else { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "Intra-BSS FWD is disabled-skip forward to Tx"); + } + + hdd_ipa_send_skb_to_network(skb, adapter); + break; + + default: + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "w2i cb wrong event: 0x%x", evt); + return; + } +} + +/** + * hdd_ipa_nbuf_cb() - IPA TX complete callback + * @skb: packet buffer which was transmitted + * + * Return: None + */ +static void hdd_ipa_nbuf_cb(cdf_nbuf_t skb) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_DEBUG, "%lx", NBUF_OWNER_PRIV_DATA(skb)); + ipa_free_skb((struct ipa_rx_data *)NBUF_OWNER_PRIV_DATA(skb)); + + hdd_ipa->stats.num_tx_comp_cnt++; + + atomic_dec(&hdd_ipa->tx_ref_cnt); + + hdd_ipa_rm_try_release(hdd_ipa); +} + +/** + * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL + * @iface_context: interface-specific IPA context + * @ipa_tx_desc: packet data descriptor + * + * Return: None + */ +static void hdd_ipa_send_pkt_to_tl( + struct hdd_ipa_iface_context *iface_context, + struct ipa_rx_data *ipa_tx_desc) +{ + struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa; + uint8_t interface_id; + hdd_adapter_t *adapter = NULL; + cdf_nbuf_t skb; + + cdf_spin_lock_bh(&iface_context->interface_lock); + adapter = iface_context->adapter; + if (!adapter) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_WARN, "Interface Down"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + cdf_spin_unlock_bh(&iface_context->interface_lock); + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + /* + * During CAC period, data packets shouldn't be sent over the air so + * drop all the packets here + */ + if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) { + ipa_free_skb(ipa_tx_desc); + cdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->stats.num_tx_cac_drop++; + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + interface_id = adapter->sessionId; + ++adapter->stats.tx_packets; + + cdf_spin_unlock_bh(&iface_context->interface_lock); + + skb = ipa_tx_desc->skb; + + cdf_mem_set(skb->cb, sizeof(skb->cb), 0); + NBUF_OWNER_ID(skb) = IPA_NBUF_OWNER_ID; + NBUF_CALLBACK_FN(skb) = hdd_ipa_nbuf_cb; + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + NBUF_MAPPED_PADDR_LO(skb) = ipa_tx_desc->dma_addr + + HDD_IPA_WLAN_FRAG_HEADER + + HDD_IPA_WLAN_IPA_HEADER; + ipa_tx_desc->skb->len -= + HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER; + } else + NBUF_MAPPED_PADDR_LO(skb) = ipa_tx_desc->dma_addr; + + NBUF_OWNER_PRIV_DATA(skb) = (unsigned long)ipa_tx_desc; + + adapter->stats.tx_bytes += ipa_tx_desc->skb->len; + + skb = ol_tx_send_ipa_data_frame(iface_context->tl_context, + ipa_tx_desc->skb); + if (skb) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_err++; + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + atomic_inc(&hdd_ipa->tx_ref_cnt); + + iface_context->stats.num_tx++; + +} + +/** + * hdd_ipa_pm_send_pkt_to_tl() - Send queued packets to TL + * @work: pointer to the scheduled work + * + * Called during PM resume to send packets to TL which were queued + * while host was in the process of suspending. + * + * Return: None + */ +static void hdd_ipa_pm_send_pkt_to_tl(struct work_struct *work) +{ + struct hdd_ipa_priv *hdd_ipa = container_of(work, + struct hdd_ipa_priv, + pm_work); + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + cdf_nbuf_t skb; + uint32_t dequeued = 0; + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + + while (((skb = cdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) != NULL)) { + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + + dequeued++; + + hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context, + pm_tx_cb->ipa_tx_desc); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + } + + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + hdd_ipa->stats.num_tx_dequeued += dequeued; + if (dequeued > hdd_ipa->stats.num_max_pm_queue) + hdd_ipa->stats.num_max_pm_queue = dequeued; +} + +/** + * hdd_ipa_i2w_cb() - IPA to WLAN callback + * @priv: pointer to private data registered with IPA (we register a + * pointer to the interface-specific IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + struct ipa_rx_data *ipa_tx_desc; + struct hdd_ipa_iface_context *iface_context; + cdf_nbuf_t skb; + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (evt != IPA_RECEIVE) { + skb = (cdf_nbuf_t) data; + dev_kfree_skb_any(skb); + iface_context->stats.num_tx_drop++; + return; + } + + iface_context = (struct hdd_ipa_iface_context *)priv; + ipa_tx_desc = (struct ipa_rx_data *)data; + + hdd_ipa = iface_context->hdd_ipa; + + /* + * When SSR is going on or driver is unloading, just drop the packets. + * During SSR, there is no use in queueing the packets as STA has to + * connect back any way + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "HDD context is not valid"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + return; + } + + skb = ipa_tx_desc->skb; + + HDD_IPA_DBG_DUMP(CDF_TRACE_LEVEL_DEBUG, "i2w", skb->data, 8); + + /* + * If PROD resource is not requested here then there may be cases where + * IPA hardware may be clocked down because of not having proper + * dependency graph between WLAN CONS and modem PROD pipes. Adding the + * workaround to request PROD resource while data is going over CONS + * pipe to prevent the IPA hardware clockdown. + */ + hdd_ipa_rm_request(hdd_ipa); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + /* + * If host is still suspended then queue the packets and these will be + * drained later when resume completes. When packet is arrived here and + * host is suspended, this means that there is already resume is in + * progress. + */ + if (hdd_ipa->suspended) { + cdf_mem_set(skb->cb, sizeof(skb->cb), 0); + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->iface_context = iface_context; + pm_tx_cb->ipa_tx_desc = ipa_tx_desc; + cdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb); + hdd_ipa->stats.num_tx_queued++; + + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + return; + } + + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + /* + * If we are here means, host is not suspended, wait for the work queue + * to finish. + */ +#ifdef WLAN_OPEN_SOURCE + flush_work(&hdd_ipa->pm_work); +#endif + + return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc); +} + +/** + * hdd_ipa_suspend() - Suspend IPA + * @hdd_ctx: Global HDD context + * + * Return: 0 on success, negativer errno on error + */ +int hdd_ipa_suspend(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return 0; + + /* + * Check if IPA is ready for suspend, If we are here means, there is + * high chance that suspend would go through but just to avoid any race + * condition after suspend started, these checks are conducted before + * allowing to suspend. + */ + if (atomic_read(&hdd_ipa->tx_ref_cnt)) + return -EAGAIN; + + cdf_spin_lock_bh(&hdd_ipa->rm_lock); + + if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) { + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EAGAIN; + } + cdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + hdd_ipa->suspended = true; + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + return 0; +} + +/** + * hdd_ipa_resume() - Resume IPA following suspend + * hdd_ctx: Global HDD context + * + * Return: 0 on success, negative errno on error + */ +int hdd_ipa_resume(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return 0; + + schedule_work(&hdd_ipa->pm_work); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + hdd_ipa->suspended = false; + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + return 0; +} + +/** + * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) +{ + int i, ret = 0; + struct ipa_sys_connect_params *ipa; + uint32_t desc_fifo_sz; + + /* The maximum number of descriptors that can be provided to a BAM at + * once is one less than the total number of descriptors that the buffer + * can contain. + * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof + * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can + * be provided at once. + * Because of above requirement, one extra descriptor will be added to + * make sure hardware always has one descriptor. + */ + desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize + + sizeof(struct sps_iovec); + + /*setup TX pipes */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params; + + ipa->client = hdd_ipa_adapter_2_client[i].cons_client; + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = &hdd_ipa->iface_context[i]; + ipa->notify = hdd_ipa_i2w_cb; + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + ipa->ipa_ep_cfg.hdr.hdr_len = + HDD_IPA_UC_WLAN_TX_HDR_LEN; + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + ipa->ipa_ep_cfg.hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + } else { + ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; + } + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + ipa->keep_ipa_awake = 1; + + ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "Failed for pipe %d" + " ret: %d", i, ret); + goto setup_sys_pipe_fail; + } + hdd_ipa->sys_pipe[i].conn_hdl_valid = 1; + } + + if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + /* + * Hard code it here, this can be extended if in case + * PROD pipe is also per interface. + * Right now there is no advantage of doing this. + */ + hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD; + + ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params; + + ipa->client = hdd_ipa->prod_client; + + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = hdd_ipa; + ipa->notify = hdd_ipa_w2i_cb; + + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN; + ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + ipa->keep_ipa_awake = 1; + + ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Failed for RX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1; + } + + return ret; + +setup_sys_pipe_fail: + + while (--i >= 0) { + ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl); + cdf_mem_zero(&hdd_ipa->sys_pipe[i], + sizeof(struct hdd_ipa_sys_pipe)); + } + + return ret; +} + +/** + * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0, i; + for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) { + if (hdd_ipa->sys_pipe[i].conn_hdl_valid) { + ret = + ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i]. + conn_hdl); + if (ret) + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "Failed: %d", + ret); + + hdd_ipa->sys_pipe[i].conn_hdl_valid = 0; + } + } +} + +/** + * hdd_ipa_register_interface() - register IPA interface + * @hdd_ipa: Global IPA context + * @iface_context: Per-interface IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context + *iface_context) +{ + struct ipa_tx_intf tx_intf; + struct ipa_rx_intf rx_intf; + struct ipa_ioc_tx_intf_prop *tx_prop = NULL; + struct ipa_ioc_rx_intf_prop *rx_prop = NULL; + char *ifname = iface_context->adapter->dev->name; + + char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; + char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; + + int num_prop = 1; + int ret = 0; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) + num_prop++; + + /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ + tx_prop = + cdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); + if (!tx_prop) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed"); + goto register_interface_fail; + } + + /* Allocate RX properties, 1 each for IPv4 & IPv6 */ + rx_prop = + cdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); + if (!rx_prop) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed"); + goto register_interface_fail; + } + + cdf_mem_zero(&tx_intf, sizeof(tx_intf)); + cdf_mem_zero(&rx_intf, sizeof(rx_intf)); + + snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + rx_prop[IPA_IP_v4].ip = IPA_IP_v4; + rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + + /* + * Interface ID is 3rd byte in the CLD header. Add the meta data and + * mask to identify the interface in IPA hardware + */ + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + rx_prop[IPA_IP_v6].ip = IPA_IP_v6; + rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + } + + tx_prop[IPA_IP_v4].ip = IPA_IP_v4; + tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + tx_prop[IPA_IP_v6].ip = IPA_IP_v6; + tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + } + + tx_intf.prop = tx_prop; + rx_intf.prop = rx_prop; + + /* Call the ipa api to register interface */ + ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); + +register_interface_fail: + cdf_mem_free(tx_prop); + cdf_mem_free(rx_prop); + return ret; +} + +/** + * hdd_remove_ipa_header() - Remove a specific header from IPA + * @name: Name of the header to be removed + * + * Return: None + */ +static void hdd_ipa_remove_header(char *name) +{ + struct ipa_ioc_get_hdr hdrlookup; + int ret = 0, len; + struct ipa_ioc_del_hdr *ipa_hdr; + + cdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); + strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); + ret = ipa_get_hdr(&hdrlookup); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d", + name, ret); + return; + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl); + len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; + ipa_hdr = (struct ipa_ioc_del_hdr *)cdf_mem_malloc(len); + if (ipa_hdr == NULL) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed"); + return; + } + ipa_hdr->num_hdls = 1; + ipa_hdr->commit = 0; + ipa_hdr->hdl[0].hdl = hdrlookup.hdl; + ipa_hdr->hdl[0].status = -1; + ret = ipa_del_hdr(ipa_hdr); + if (ret != 0) + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "Delete header failed: %d", + ret); + + cdf_mem_free(ipa_hdr); +} + +/** + * hdd_ipa_add_header_info() - Add IPA header for a given interface + * @hdd_ipa: Global HDD IPA context + * @iface_context: Interface-specific HDD IPA context + * @mac_addr: Interface MAC address + * + * Return: 0 on success, negativer errno value on error + */ +static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context *iface_context, + uint8_t *mac_addr) +{ + hdd_adapter_t *adapter = iface_context->adapter; + char *ifname; + struct ipa_ioc_add_hdr *ipa_hdr = NULL; + int ret = -EINVAL; + struct hdd_ipa_tx_hdr *tx_hdr = NULL; + struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL; + + ifname = adapter->dev->name; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM", + ifname, mac_addr); + + /* dynamically allocate the memory to add the hdrs */ + ipa_hdr = cdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) + + sizeof(struct ipa_hdr_add)); + if (!ipa_hdr) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: ipa_hdr allocation failed", ifname); + ret = -ENOMEM; + goto end; + } + + ipa_hdr->commit = 0; + ipa_hdr->num_hdrs = 1; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId; + HDD_IPA_LOG(CDF_TRACE_LEVEL_DEBUG, + "ifname=%s, vdev_id=%d", + ifname, uc_tx_hdr->ipa_hd.vdev_id); + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + ret = ipa_add_hdr(ipa_hdr); + } else { + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + + /* Set the Source MAC */ + memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN); + memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; + + /* Set the type to IPV4 in the header */ + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP); + + ret = ipa_add_hdr(ipa_hdr); + } + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d", + ifname, ret); + goto end; + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = + (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); + } else { + /* Set the type to IPV6 in the header */ + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6); + } + + ret = ipa_add_hdr(ipa_hdr); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: IPv6 add hdr failed: %d", ifname, ret); + goto clean_ipv4_hdr; + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + } + + cdf_mem_free(ipa_hdr); + + return ret; + +clean_ipv4_hdr: + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(ipa_hdr->hdr[0].name); +end: + if (ipa_hdr) + cdf_mem_free(ipa_hdr); + + return ret; +} + +/** + * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter + * @adapter: Adapter upon which IPA was previously configured + * + * Return: None + */ +static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int ret; + char name_ipa[IPA_RESOURCE_NAME_MAX]; + + /* Remove the headers */ + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + adapter->dev->name, HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + adapter->dev->name, HDD_IPA_IPV6_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + } + /* unregister the interface with IPA */ + ret = ipa_deregister_intf(adapter->dev->name); + if (ret) + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: ipa_deregister_intf fail: %d", + adapter->dev->name, ret); +} + +/** + * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface + * @iface_context: interface-specific IPA context + * + * Return: None + */ +static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context) +{ + if (iface_context == NULL) + return; + + hdd_ipa_clean_hdr(iface_context->adapter); + + cdf_spin_lock_bh(&iface_context->interface_lock); + iface_context->adapter->ipa_context = NULL; + iface_context->adapter = NULL; + iface_context->tl_context = NULL; + cdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->ifa_address = 0; + if (!iface_context->hdd_ipa->num_iface) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "NUM INTF 0, Invalid"); + CDF_ASSERT(0); + } + iface_context->hdd_ipa->num_iface--; +} + +/** + * hdd_ipa_setup_iface() - Setup IPA on a given interface + * @hdd_ipa: HDD IPA global context + * @adapter: Interface upon which IPA is being setup + * @sta_id: Station ID of the API instance + * + * Return: 0 on success, negative errno value on error + */ +static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa, + hdd_adapter_t *adapter, uint8_t sta_id) +{ + struct hdd_ipa_iface_context *iface_context = NULL; + void *tl_context = NULL; + int i, ret = 0; + + /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during + * channel change indication. Since these indications are sent by lower + * layer as SAP updates and IPA doesn't have to do anything for these + * updates so ignoring! + */ + if (WLAN_HDD_SOFTAP == adapter->device_mode && adapter->ipa_context) + return 0; + + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + if (hdd_ipa->iface_context[i].adapter == NULL) { + iface_context = &(hdd_ipa->iface_context[i]); + break; + } + } + + if (iface_context == NULL) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "All the IPA interfaces are in use"); + ret = -ENOMEM; + goto end; + } + + adapter->ipa_context = iface_context; + iface_context->adapter = adapter; + iface_context->sta_id = sta_id; + tl_context = ol_txrx_get_vdev_by_sta_id(sta_id); + + if (tl_context == NULL) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Not able to get TL context sta_id: %d", sta_id); + ret = -EINVAL; + goto end; + } + + iface_context->tl_context = tl_context; + + ret = hdd_ipa_add_header_info(hdd_ipa, iface_context, + adapter->dev->dev_addr); + + if (ret) + goto end; + + /* Configure the TX and RX pipes filter rules */ + ret = hdd_ipa_register_interface(hdd_ipa, iface_context); + if (ret) + goto cleanup_header; + + hdd_ipa->num_iface++; + return ret; + +cleanup_header: + + hdd_ipa_clean_hdr(adapter); +end: + if (iface_context) + hdd_ipa_cleanup_iface(iface_context); + return ret; +} + +/** + * hdd_ipa_msg_free_fn() - Free an IPA message + * @buff: pointer to the IPA message + * @len: length of the IPA message + * @type: type of IPA message + * + * Return: None + */ +static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type) +{ + hddLog(LOG1, "msg type:%d, len:%d", type, len); + ghdd_ipa->stats.num_free_msg++; + cdf_mem_free(buff); +} + +/** + * hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message + * @mcc_mode: 0=MCC/1=SCC + * + * Return: 0 on success, negative errno value on error + */ +int hdd_ipa_send_mcc_scc_msg(hdd_context_t *pHddCtx, bool mcc_mode) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + CDF_STATUS status; + hdd_adapter_t *pAdapter; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *msg; + int ret; + + if (!hdd_ipa_uc_sta_is_enabled(pHddCtx)) + return -EINVAL; + + if (!pHddCtx->mcc_mode) { + /* Flush TxRx queue for each adapter before switch to SCC */ + status = hdd_get_front_adapter(pHddCtx, &adapter_node); + while (NULL != adapter_node && CDF_STATUS_SUCCESS == status) { + pAdapter = adapter_node->pAdapter; + if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION || + pAdapter->device_mode == WLAN_HDD_SOFTAP) { + hddLog(CDF_TRACE_LEVEL_INFO, + "MCC->SCC: Flush TxRx queue(d_mode=%d)", + pAdapter->device_mode); + hdd_deinit_tx_rx(pAdapter); + } + status = hdd_get_next_adapter( + pHddCtx, adapter_node, &next); + adapter_node = next; + } + } + + /* Send SCC/MCC Switching event to IPA */ + meta.msg_len = sizeof(*msg); + msg = cdf_mem_malloc(meta.msg_len); + if (msg == NULL) { + hddLog(LOGE, "msg allocation failed"); + return -ENOMEM; + } + + meta.msg_type = mcc_mode ? + WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC; + hddLog(LOG1, "ipa_send_msg(Evt:%d)", meta.msg_type); + + ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn); + + if (ret) { + hddLog(LOGE, "ipa_send_msg(Evt:%d) - fail=%d", + meta.msg_type, ret); + cdf_mem_free(msg); + } + + return ret; +} + +/** + * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string + * @event: IPA WLAN event to be converted to a string + * + * Return: ASCII string representing the IPA WLAN event + */ +static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event) +{ + switch (event) { + case WLAN_CLIENT_CONNECT: + return "WLAN_CLIENT_CONNECT"; + case WLAN_CLIENT_DISCONNECT: + return "WLAN_CLIENT_DISCONNECT"; + case WLAN_CLIENT_POWER_SAVE_MODE: + return "WLAN_CLIENT_POWER_SAVE_MODE"; + case WLAN_CLIENT_NORMAL_MODE: + return "WLAN_CLIENT_NORMAL_MODE"; + case SW_ROUTING_ENABLE: + return "SW_ROUTING_ENABLE"; + case SW_ROUTING_DISABLE: + return "SW_ROUTING_DISABLE"; + case WLAN_AP_CONNECT: + return "WLAN_AP_CONNECT"; + case WLAN_AP_DISCONNECT: + return "WLAN_AP_DISCONNECT"; + case WLAN_STA_CONNECT: + return "WLAN_STA_CONNECT"; + case WLAN_STA_DISCONNECT: + return "WLAN_STA_DISCONNECT"; + case WLAN_CLIENT_CONNECT_EX: + return "WLAN_CLIENT_CONNECT_EX"; + + case IPA_WLAN_EVENT_MAX: + default: + return "UNKNOWN"; + } +} + +/** + * hdd_ipa_wlan_evt() - IPA event handler + * @adapter: adapter upon which the event was received + * @sta_id: station id for the event + * @type: the event type + * @mac_address: MAC address associated with the event + * + * Return: 0 on success, negative errno value on error + */ +int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum ipa_wlan_event type, uint8_t *mac_addr) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *msg; + struct ipa_wlan_msg_ex *msg_ex = NULL; + int ret; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d", + adapter->dev->name, hdd_ipa_wlan_event_to_str(type), + mac_addr, sta_id); + + if (type >= IPA_WLAN_EVENT_MAX) + return -EINVAL; + + if (WARN_ON(is_zero_ether_addr(mac_addr))) + return -EINVAL; + + if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED"); + return -EINVAL; + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) && + !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + (WLAN_HDD_SOFTAP != adapter->device_mode)) { + return 0; + } + + /* + * During IPA UC resource loading/unloading new events can be issued. + * Store the events separately and handle them later. + */ + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) && + ((hdd_ipa->resource_loading) || + (hdd_ipa->resource_unloading))) { + struct ipa_uc_pending_event *pending_evet = NULL; + + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s, RL/RUL inprogress", __func__); + pending_evet = (struct ipa_uc_pending_event *)cdf_mem_malloc( + sizeof(struct ipa_uc_pending_event)); + if (!pending_evet) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "Pending event memory alloc fail"); + return -ENOMEM; + } + pending_evet->adapter = adapter; + pending_evet->sta_id = sta_id; + pending_evet->type = type; + cdf_mem_copy(pending_evet->mac_addr, + mac_addr, + CDF_MAC_ADDR_SIZE); + cdf_list_insert_back(&hdd_ipa->pending_event, + &pending_evet->node); + return 0; + } + + hdd_ipa->stats.event[type]++; + + switch (type) { + case WLAN_STA_CONNECT: + /* STA already connected and without disconnect, connect again + * This is Roaming scenario + */ + if (hdd_ipa->sta_connected) + hdd_ipa_cleanup_iface(adapter->ipa_context); + + if ((hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) && + (!hdd_ipa->sta_connected)) + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, 1); + + cdf_mutex_acquire(&hdd_ipa->event_lock); + + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED", + msg_ex->name, meta.msg_type); + } else if ((!hdd_ipa->sap_num_connected_sta) && + (!hdd_ipa->sta_connected)) { + /* Enable IPA UC TX PIPE when STA connected */ + ret = hdd_ipa_uc_handle_first_con(hdd_ipa); + if (!ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "handle 1st con ret %d", ret); + } else { + cdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, 0); + goto end; + } + } + ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id); + if (ret) { + cdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, 0); + goto end; + +#ifdef IPA_UC_OFFLOAD + vdev_to_iface[adapter->sessionId] = + ((struct hdd_ipa_iface_context *) + (adapter->ipa_context))->iface_id; +#endif /* IPA_UC_OFFLOAD */ + } + + cdf_mutex_release(&hdd_ipa->event_lock); + + hdd_ipa->sta_connected = 1; + break; + + case WLAN_AP_CONNECT: + /* For DFS channel we get two start_bss event (before and after + * CAC). Also when ACS range includes both DFS and non DFS + * channels, we could possibly change channel many times due to + * RADAR detection and chosen channel may not be a DFS channels. + * So dont return error here. Just discard the event. + */ + if (adapter->ipa_context) + return 0; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_AP_RX_DATA_OFFLOAD, 1); + } + cdf_mutex_acquire(&hdd_ipa->event_lock); + ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id); + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, Interface setup failed", + msg_ex->name, meta.msg_type); + cdf_mutex_release(&hdd_ipa->event_lock); + goto end; + +#ifdef IPA_UC_OFFLOAD + vdev_to_iface[adapter->sessionId] = + ((struct hdd_ipa_iface_context *) + (adapter->ipa_context))->iface_id; +#endif /* IPA_UC_OFFLOAD */ + } + cdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_STA_DISCONNECT: + cdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa_cleanup_iface(adapter->ipa_context); + + if (!hdd_ipa->sta_connected) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, STA already disconnected", + msg_ex->name, meta.msg_type); + cdf_mutex_release(&hdd_ipa->event_lock); + return -EINVAL; + } + hdd_ipa->sta_connected = 0; + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + } else { + /* Disable IPA UC TX PIPE when STA disconnected */ + if ((!hdd_ipa->sap_num_connected_sta) || + ((!hdd_ipa->num_iface) && + (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe))) { + hdd_ipa_uc_handle_last_discon(hdd_ipa); + } + } + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, 0); + vdev_to_iface[adapter->sessionId] = HDD_IPA_MAX_IFACE; + } + + cdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_AP_DISCONNECT: + if (!adapter->ipa_context) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, SAP already disconnected", + msg_ex->name, meta.msg_type); + return -EINVAL; + } + + cdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa_cleanup_iface(adapter->ipa_context); + if ((!hdd_ipa->num_iface) && + (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe)) { + if (hdd_ipa->hdd_ctx->isUnloadInProgress) { + /* + * We disable WDI pipes directly here since + * IPA_OPCODE_TX/RX_SUSPEND message will not be + * processed when unloading WLAN driver is in + * progress + */ + hdd_ipa_uc_disable_pipes(hdd_ipa); + } else { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "NO INTF left but still pipe clean up"); + hdd_ipa_uc_handle_last_discon(hdd_ipa); + } + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_AP_RX_DATA_OFFLOAD, 0); + vdev_to_iface[adapter->sessionId] = HDD_IPA_MAX_IFACE; + } + cdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_CLIENT_CONNECT_EX: + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%d %d", + adapter->dev->ifindex, sta_id); + + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED", + adapter->dev->name, meta.msg_type); + return 0; + } + + cdf_mutex_acquire(&hdd_ipa->event_lock); + if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, + true, sta_id)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d found, not valid", + adapter->dev->name, sta_id); + cdf_mutex_release(&hdd_ipa->event_lock); + return 0; + } + hdd_ipa->sap_num_connected_sta++; + hdd_ipa->pending_cons_req = false; + cdf_mutex_release(&hdd_ipa->event_lock); + + meta.msg_type = type; + meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) + + sizeof(struct ipa_wlan_hdr_attrib_val)); + msg_ex = cdf_mem_malloc(meta.msg_len); + + if (msg_ex == NULL) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "msg_ex allocation failed"); + return -ENOMEM; + } + strlcpy(msg_ex->name, adapter->dev->name, + IPA_RESOURCE_NAME_MAX); + msg_ex->num_of_attribs = 1; + msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR; + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + msg_ex->attribs[0].offset = + HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + } else { + msg_ex->attribs[0].offset = + HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; + } + memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr, + IPA_MAC_ADDR_SIZE); + + ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn); + + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d", + msg_ex->name, meta.msg_type, ret); + cdf_mem_free(msg_ex); + return ret; + } + hdd_ipa->stats.num_send_msg++; + + cdf_mutex_acquire(&hdd_ipa->event_lock); + /* Enable IPA UC Data PIPEs when first STA connected */ + if ((1 == hdd_ipa->sap_num_connected_sta) + && (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) + || !hdd_ipa->sta_connected)) { + ret = hdd_ipa_uc_handle_first_con(hdd_ipa); + if (ret) { + cdf_mutex_release(&hdd_ipa->event_lock); + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: handle 1st con ret %d", + adapter->dev->name, ret); + return ret; + } + } + cdf_mutex_release(&hdd_ipa->event_lock); + + return ret; + + case WLAN_CLIENT_DISCONNECT: + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + return 0; + } + + cdf_mutex_acquire(&hdd_ipa->event_lock); + if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d NOT found, not valid", + msg_ex->name, sta_id); + cdf_mutex_release(&hdd_ipa->event_lock); + return 0; + } + hdd_ipa->sap_num_connected_sta--; + /* Disable IPA UC TX PIPE when last STA disconnected */ + if (!hdd_ipa->sap_num_connected_sta + && (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) || + !hdd_ipa->sta_connected) + && (false == hdd_ipa->resource_unloading) + && (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe)) + hdd_ipa_uc_handle_last_discon(hdd_ipa); + cdf_mutex_release(&hdd_ipa->event_lock); + break; + + default: + return 0; + } + + meta.msg_len = sizeof(struct ipa_wlan_msg); + msg = cdf_mem_malloc(meta.msg_len); + if (msg == NULL) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, "msg allocation failed"); + return -ENOMEM; + } + + meta.msg_type = type; + strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX); + memcpy(msg->mac_addr, mac_addr, ETH_ALEN); + + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Evt: %d", + msg->name, meta.msg_type); + + ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn); + + if (ret) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Evt: %d fail:%d", + msg->name, meta.msg_type, ret); + cdf_mem_free(msg); + return ret; + } + + hdd_ipa->stats.num_send_msg++; + +end: + return ret; +} + +/** + * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string + * @state: IPA RM state value + * + * Return: ASCII string representing the IPA RM state + */ +static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state) +{ + switch (state) { + case HDD_IPA_RM_RELEASED: + return "RELEASED"; + case HDD_IPA_RM_GRANT_PENDING: + return "GRANT_PENDING"; + case HDD_IPA_RM_GRANTED: + return "GRANTED"; + } + + return "UNKNOWN"; +} + +/** + * hdd_ipa_init() - IPA initialization function + * @hdd_ctx: HDD global context + * + * Allocate hdd_ipa resources, ipa pipe resource and register + * wlan interface with IPA module. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + int ret, i; + struct hdd_ipa_iface_context *iface_context = NULL; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return CDF_STATUS_SUCCESS; + + hdd_ipa = cdf_mem_malloc(sizeof(*hdd_ipa)); + if (!hdd_ipa) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed"); + goto fail_setup_rm; + } + + hdd_ctx->hdd_ipa = hdd_ipa; + ghdd_ipa = hdd_ipa; + hdd_ipa->hdd_ctx = hdd_ctx; + hdd_ipa->num_iface = 0; + + /* Create the interface context */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + iface_context = &hdd_ipa->iface_context[i]; + iface_context->hdd_ipa = hdd_ipa; + iface_context->cons_client = + hdd_ipa_adapter_2_client[i].cons_client; + iface_context->prod_client = + hdd_ipa_adapter_2_client[i].prod_client; + iface_context->iface_id = i; + iface_context->adapter = NULL; + cdf_spinlock_init(&iface_context->interface_lock); + } + +#ifdef CONFIG_CNSS + cnss_init_work(&hdd_ipa->pm_work, hdd_ipa_pm_send_pkt_to_tl); +#else + INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_send_pkt_to_tl); +#endif + cdf_spinlock_init(&hdd_ipa->pm_lock); + cdf_nbuf_queue_init(&hdd_ipa->pm_queue_head); + + ret = hdd_ipa_setup_rm(hdd_ipa); + if (ret) + goto fail_setup_rm; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa_uc_rt_debug_init(hdd_ctx); + cdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats)); + hdd_ipa->sap_num_connected_sta = 0; + hdd_ipa->ipa_tx_packets_diff = 0; + hdd_ipa->ipa_rx_packets_diff = 0; + hdd_ipa->ipa_p_tx_packets = 0; + hdd_ipa->ipa_p_rx_packets = 0; + hdd_ipa->resource_loading = false; + hdd_ipa->resource_unloading = false; + hdd_ipa->sta_connected = 0; + + /* Setup IPA sys_pipe for MCC */ + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + ret = hdd_ipa_setup_sys_pipe(hdd_ipa); + if (ret) + goto fail_create_sys_pipe; + } + hdd_ipa_uc_ol_init(hdd_ctx); + } else { + ret = hdd_ipa_setup_sys_pipe(hdd_ipa); + if (ret) + goto fail_create_sys_pipe; + } + + return CDF_STATUS_SUCCESS; + +fail_create_sys_pipe: + hdd_ipa_destroy_rm_resource(hdd_ipa); +fail_setup_rm: + if (hdd_ipa) + cdf_mem_free(hdd_ipa); + + return CDF_STATUS_E_FAILURE; +} + +/** + * hdd_ipa_cleanup - IPA cleanup function + * @hdd_ctx: HDD global context + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + int i; + struct hdd_ipa_iface_context *iface_context = NULL; + cdf_nbuf_t skb; + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return CDF_STATUS_SUCCESS; + + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) { + unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier); + hdd_ipa_teardown_sys_pipe(hdd_ipa); + } + + /* Teardown IPA sys_pipe for MCC */ + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) + hdd_ipa_teardown_sys_pipe(hdd_ipa); + + hdd_ipa_destroy_rm_resource(hdd_ipa); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&hdd_ipa->pm_work); +#endif + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + + while (((skb = cdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) != NULL)) { + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + ipa_free_skb(pm_tx_cb->ipa_tx_desc); + + cdf_spin_lock_bh(&hdd_ipa->pm_lock); + } + cdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + cdf_spinlock_destroy(&hdd_ipa->pm_lock); + + /* destory the interface lock */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + iface_context = &hdd_ipa->iface_context[i]; + cdf_spinlock_destroy(&iface_context->interface_lock); + } + + /* This should never hit but still make sure that there are no pending + * descriptor in IPA hardware + */ + if (hdd_ipa->pending_hw_desc_cnt != 0) { + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "IPA Pending write done: %d Waiting!", + hdd_ipa->pending_hw_desc_cnt); + + for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) { + usleep_range(100, 100); + } + + HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR, + "IPA Pending write done: desc: %d %s(%d)!", + hdd_ipa->pending_hw_desc_cnt, + hdd_ipa->pending_hw_desc_cnt == 0 ? "completed" + : "leak", i); + } + if (hdd_ipa_uc_is_enabled(hdd_ctx)) { + hdd_ipa_uc_rt_debug_deinit(hdd_ctx); + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Disconnect TX PIPE", __func__); + ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); + HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, + "%s: Disconnect RX PIPE", __func__); + ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + cdf_mutex_destroy(&hdd_ipa->event_lock); + cdf_list_destroy(&hdd_ipa->pending_event); + +#ifdef WLAN_OPEN_SOURCE + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + cancel_work_sync(&hdd_ipa->uc_op_work[i].work); + hdd_ipa->uc_op_work[i].msg = NULL; + } +#endif + } + + cdf_mem_free(hdd_ipa); + hdd_ctx->hdd_ipa = NULL; + + return CDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ diff --git a/core/hdd/src/wlan_hdd_lro.c b/core/hdd/src/wlan_hdd_lro.c new file mode 100644 index 0000000000..14b9be6166 --- /dev/null +++ b/core/hdd/src/wlan_hdd_lro.c @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_lro.c + * + * WLAN HDD LRO interface implementation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LRO_MAX_AGGR_SIZE 100 + +#define LRO_VALID_FIELDS \ + (LRO_DESC | LRO_ELIGIBILITY_CHECKED | LRO_TCP_ACK_NUM | \ + LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN) + +/** + * hdd_lro_get_skb_header() - LRO callback function + * @skb: network buffer + * @ip_hdr: contains a pointer to the IP header + * @tcpudp_hdr: contains a pointer to the TCP header + * @hdr_flags: indicates if this is a TCP, IPV4 frame + * @priv: private driver specific opaque pointer + * + * Get the IP and TCP headers from the skb + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_lro_get_skb_header(struct sk_buff *skb, void **ip_hdr, + void **tcpudp_hdr, u64 *hdr_flags, void *priv) +{ + if (NBUF_IPV6_PROTO(skb)) { + hdr_flags = 0; + return -EINVAL; + } + + *hdr_flags |= (LRO_IPV4 | LRO_TCP); + (*ip_hdr) = skb->data; + (*tcpudp_hdr) = skb->data + NBUF_TCP_OFFSET(skb); + return 0; +} + +/** + * hdd_lro_desc_pool_init() - Initialize the free pool of LRO + * descriptors + * @lro_desc_pool: free pool of the LRO descriptors + * @lro_mgr: LRO manager + * + * Initialize a list that holds the free LRO descriptors + * + * Return: none + */ +static void hdd_lro_desc_pool_init(struct hdd_lro_desc_pool *lro_desc_pool, + struct net_lro_mgr *lro_mgr) +{ + int i; + + INIT_LIST_HEAD(&lro_desc_pool->lro_free_list_head); + + for (i = 0; i < LRO_DESC_POOL_SZ; i++) { + lro_desc_pool->lro_desc_array[i].lro_desc = + &lro_mgr->lro_arr[i]; + list_add_tail(&lro_desc_pool->lro_desc_array[i].lro_node, + &lro_desc_pool->lro_free_list_head); + } + cdf_spinlock_init(&lro_desc_pool->lro_pool_lock); +} + +/** + * hdd_lro_desc_info_init() - Initialize the LRO descriptors + * @hdd_info: HDD LRO data structure + * + * Initialize the free pool of LRO descriptors and the entries + * of the hash table + * + * Return: none + */ +static void hdd_lro_desc_info_init(struct hdd_lro_s *hdd_info) +{ + int i; + + /* Initialize pool of free LRO desc.*/ + hdd_lro_desc_pool_init(&hdd_info->lro_desc_info.lro_desc_pool, + hdd_info->lro_mgr); + + /* Initialize the hash table of LRO desc.*/ + for (i = 0; i < LRO_DESC_TABLE_SZ; i++) { + /* initialize the flows in the hash table */ + INIT_LIST_HEAD(&hdd_info->lro_desc_info. + lro_hash_table[i].lro_desc_list); + } + + cdf_spinlock_init(&hdd_info->lro_desc_info.lro_hash_lock); +} + +/** + * hdd_lro_desc_pool_deinit() - Free the LRO descriptor list + * @hdd_info: HDD LRO data structure + * + * Free the pool of LRO descriptors + * + * Return: none + */ +static void hdd_lro_desc_pool_deinit(struct hdd_lro_desc_pool *lro_desc_pool) +{ + + if (lro_desc_pool->lro_desc_array) { + cdf_mem_free(lro_desc_pool->lro_desc_array); + lro_desc_pool->lro_desc_array = NULL; + } + + INIT_LIST_HEAD(&lro_desc_pool->lro_free_list_head); + + cdf_spinlock_destroy(&lro_desc_pool->lro_pool_lock); +} + +/** + * hdd_lro_desc_info_deinit() - Deinitialize the LRO descriptors + * + * @hdd_info: HDD LRO data structure + * + * Deinitialize the free pool of LRO descriptors and the entries + * of the hash table + * + * Return: none + */ +static void hdd_lro_desc_info_deinit(struct hdd_lro_s *hdd_info) +{ + int i; + struct hdd_lro_desc_info *desc_info = &hdd_info->lro_desc_info; + + cdf_mem_free(hdd_info->lro_mgr->lro_arr); + hdd_info->lro_mgr->lro_arr = NULL; + hdd_lro_desc_pool_deinit(&desc_info->lro_desc_pool); + /* Free the a list of LRO desc for each entry of the hash table */ + for (i = 0; i < LRO_DESC_TABLE_SZ; i++) + INIT_LIST_HEAD(&desc_info->lro_hash_table[i].lro_desc_list); + + cdf_spinlock_destroy(&desc_info->lro_hash_lock); + cdf_mem_free(desc_info->lro_hash_table); + desc_info->lro_hash_table = NULL; +} + +/** + * hdd_lro_tcp_flow_match() - function to check for a flow match + * @iph: IP header + * @tcph: TCP header + * @lro_desc: LRO decriptor + * + * Checks if the descriptor belongs to the same flow as the one + * indicated by the TCP and IP header. + * + * Return: true - flow match, false - flow does not match + */ +static inline bool hdd_lro_tcp_flow_match(struct net_lro_desc *lro_desc, + struct iphdr *iph, + struct tcphdr *tcph) +{ + if ((lro_desc->tcph->source != tcph->source) || + (lro_desc->tcph->dest != tcph->dest) || + (lro_desc->iph->saddr != iph->saddr) || + (lro_desc->iph->daddr != iph->daddr)) + return false; + + return true; + +} + +/** + * hdd_lro_desc_find() - LRO descriptor look-up function + * + * @adapter: HDD adaptor + * @skb: network buffer + * @iph: IP header + * @tcph: TCP header + * @lro_desc: contains a pointer to the LRO decriptor + * + * Look-up the LRO descriptor in the hash table based on the + * flow ID toeplitz. If the flow is not found, allocates a new + * LRO descriptor and places it in the hash table + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_lro_desc_find(hdd_adapter_t *adapter, + struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcph, + struct net_lro_desc **lro_desc) +{ + uint32_t i; + struct hdd_lro_desc_table *lro_hash_table; + struct list_head *ptr; + struct hdd_lro_desc_entry *entry; + struct hdd_lro_desc_pool free_pool; + struct hdd_lro_desc_info *desc_info = &adapter->lro_info.lro_desc_info; + + *lro_desc = NULL; + i = NBUF_FLOW_ID_TOEPLITZ(skb) & LRO_DESC_TABLE_SZ_MASK; + + lro_hash_table = &desc_info->lro_hash_table[i]; + + if (!lro_hash_table) { + hdd_err("Invalid hash entry"); + CDF_ASSERT(0); + return -EINVAL; + } + + cdf_spin_lock_bh(&desc_info->lro_hash_lock); + /* Check if this flow exists in the descriptor list */ + list_for_each(ptr, &lro_hash_table->lro_desc_list) { + struct net_lro_desc *tmp_lro_desc = NULL; + entry = list_entry(ptr, struct hdd_lro_desc_entry, lro_node); + tmp_lro_desc = entry->lro_desc; + if (tmp_lro_desc->active) { + if (hdd_lro_tcp_flow_match(tmp_lro_desc, iph, tcph)) { + *lro_desc = entry->lro_desc; + cdf_spin_unlock_bh(&desc_info->lro_hash_lock); + return 0; + } + } + } + cdf_spin_unlock_bh(&desc_info->lro_hash_lock); + + /* no existing flow found, a new LRO desc needs to be allocated */ + free_pool = adapter->lro_info.lro_desc_info.lro_desc_pool; + cdf_spin_lock_bh(&free_pool.lro_pool_lock); + entry = list_first_entry_or_null( + &free_pool.lro_free_list_head, + struct hdd_lro_desc_entry, lro_node); + if (NULL == entry) { + hdd_err("Could not allocate LRO desc!"); + cdf_spin_unlock_bh(&free_pool.lro_pool_lock); + return -ENOMEM; + } + + list_del_init(&entry->lro_node); + cdf_spin_unlock_bh(&free_pool.lro_pool_lock); + + if (NULL == entry->lro_desc) { + hdd_err("entry->lro_desc is NULL!\n"); + return -EINVAL; + } + + cdf_mem_zero((void *)entry->lro_desc, sizeof(struct net_lro_desc)); + + /* + * lro_desc->active should be 0 and lro_desc->tcp_rcv_tsval + * should be 0 for newly allocated lro descriptors + */ + cdf_spin_lock_bh(&desc_info->lro_hash_lock); + list_add_tail(&entry->lro_node, + &lro_hash_table->lro_desc_list); + cdf_spin_unlock_bh(&desc_info->lro_hash_lock); + *lro_desc = entry->lro_desc; + + return 0; +} + +/** + * hdd_lro_get_desc() - LRO descriptor look-up function + * @iph: IP header + * @tcph: TCP header + * @lro_arr: Array of LRO decriptors + * @lro_mgr: LRO manager + * + * Looks-up the LRO descriptor for a given flow + * + * Return: LRO descriptor + */ +static struct net_lro_desc *hdd_lro_get_desc(struct net_lro_mgr *lro_mgr, + struct net_lro_desc *lro_arr, + struct iphdr *iph, + struct tcphdr *tcph) +{ + int i; + + for (i = 0; i < lro_mgr->max_desc; i++) { + if (lro_arr[i].active) + if (hdd_lro_tcp_flow_match(&lro_arr[i], iph, tcph)) + return &lro_arr[i]; + } + + return NULL; +} + +/** + * hdd_lro_eligible() - LRO eligibilty check + * @iph: IP header + * @tcph: TCP header + * @adapter: HDD adaptor + * @desc: LRO descriptor + * @skb: network buffer + * + * Determines if the frame is LRO eligible + * + * Return: true - LRO eligible frame, false - frame is not LRO + * eligible + */ +static bool hdd_lro_eligible(hdd_adapter_t *adapter, struct sk_buff *skb, + struct iphdr *iph, struct tcphdr *tcph, struct net_lro_desc **desc) +{ + struct net_lro_desc *lro_desc = NULL; + int hw_lro_eligible = + NBUF_LRO_ELIGIBLE(skb) && (!NBUF_TCP_PURE_ACK(skb)); + + if (!hw_lro_eligible) + return false; + + if (0 != hdd_lro_desc_find(adapter, skb, iph, tcph, desc)) { + hdd_err("finding the LRO desc failed"); + return false; + } + + lro_desc = *desc; + if (!lro_desc) + return false; + + /* if this is not the first skb, check the timestamp option */ + if (lro_desc->tcp_rcv_tsval) { + if (tcph->doff == 8) { + __be32 *topt = (__be32 *)(tcph + 1); + + if (*topt != htonl((TCPOPT_NOP << 24) + |(TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) + | TCPOLEN_TIMESTAMP)) + return true; + + /* timestamp should be in right order */ + topt++; + if (after(ntohl(lro_desc->tcp_rcv_tsval), + ntohl(*topt))) + return false; + + /* timestamp reply should not be zero */ + topt++; + if (*topt == 0) + return false; + } + } + + return true; +} + +/** + * hdd_lro_desc_free() - Free the LRO descriptor + * @adapter: HDD adaptor + * @desc: LRO descriptor + * + * Return the LRO descriptor to the free pool + * + * Return: none + */ +static void hdd_lro_desc_free(struct net_lro_desc *desc, + hdd_adapter_t *adapter) +{ + struct hdd_lro_desc_entry *entry; + struct net_lro_desc *arr_base = adapter->lro_info.lro_mgr->lro_arr; + struct hdd_lro_desc_info *desc_info = &adapter->lro_info.lro_desc_info; + int i = desc - arr_base; + + if (i >= LRO_DESC_POOL_SZ) { + hdd_err("invalid index %d", i); + return; + } + + entry = &desc_info->lro_desc_pool.lro_desc_array[i]; + + cdf_spin_lock_bh(&desc_info->lro_hash_lock); + list_del_init(&entry->lro_node); + cdf_spin_unlock_bh(&desc_info->lro_hash_lock); + + cdf_spin_lock_bh(&desc_info->lro_desc_pool.lro_pool_lock); + list_add_tail(&entry->lro_node, &desc_info-> + lro_desc_pool.lro_free_list_head); + cdf_spin_unlock_bh(&desc_info->lro_desc_pool.lro_pool_lock); +} + +/** + * hdd_lro_flush_pkt() - function to flush the LRO flow + * @iph: IP header + * @tcph: TCP header + * @adapter: HDD adaptor + * @lro_mgr: LRO manager + * + * Flush all the packets aggregated in the LRO manager for the + * flow indicated by the TCP and IP header + * + * Return: none + */ +void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr, + struct iphdr *iph, struct tcphdr *tcph, hdd_adapter_t *adapter) +{ + struct net_lro_desc *lro_desc; + + lro_desc = hdd_lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + + if (!lro_desc) + return; + + hdd_lro_desc_free(lro_desc, adapter); + lro_flush_desc(lro_mgr, lro_desc); +} + +/** + * hdd_lro_flush() - LRO flush callback + * @data: opaque pointer containing HDD specific information + * + * Callback registered to flush all the packets aggregated in + * the LRO manager for all the flows + * + * Return: none + */ +void hdd_lro_flush(void *data) +{ + hdd_adapter_t *adapter = (hdd_adapter_t *)data; + int i; + + for (i = 0; i < adapter->lro_info.lro_mgr->max_desc; i++) { + if (adapter->lro_info.lro_mgr->lro_arr[i].active) { + hdd_lro_desc_free( + &adapter->lro_info.lro_mgr->lro_arr[i], + (void *)adapter); + lro_flush_desc(adapter->lro_info.lro_mgr, + &adapter->lro_info.lro_mgr->lro_arr[i]); + } + } +} + +/** + * hdd_lro_init() - initialization for LRO + * @hdd_ctx: HDD context + * + * This function sends the LRO configuration to the firmware + * via WMA + * + * Return: 0 - success, < 0 - failure + */ +int hdd_lro_init(hdd_context_t *hdd_ctx) +{ + struct wma_lro_config_cmd_t lro_config; + + if (!hdd_ctx->config->lro_enable) { + hdd_err(FL("LRO Disabled")); + return 0; + } + + lro_config.lro_enable = 1; + lro_config.tcp_flag = TCPHDR_ACK; + lro_config.tcp_flag_mask = TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | + TCPHDR_ACK | TCPHDR_URG | TCPHDR_ECE | TCPHDR_CWR; + + get_random_bytes(lro_config.toeplitz_hash_ipv4, + (sizeof(lro_config.toeplitz_hash_ipv4[0]) * + LRO_IPV4_SEED_ARR_SZ)); + + get_random_bytes(lro_config.toeplitz_hash_ipv6, + (sizeof(lro_config.toeplitz_hash_ipv6[0]) * + LRO_IPV6_SEED_ARR_SZ)); + + hdd_debug("sending the LRO configuration to the fw"); + if (0 != wma_lro_init(&lro_config)) { + hdd_err("Failed to send LRO configuration!"); + hdd_ctx->config->lro_enable = 0; + return -EAGAIN; + } + + return 0; +} + +/** + * hdd_lro_enable() - enable LRO + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * + * This function enables LRO in the network device attached to + * the HDD adapter. It also allocates the HDD LRO instance for + * that network device + * + * Return: 0 - success, < 0 - failure + */ +int hdd_lro_enable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + struct hdd_lro_s *hdd_lro; + struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX); + size_t lro_mgr_sz, desc_arr_sz, desc_pool_sz, hash_table_sz; + uint8_t *lro_mem_ptr; + + if (!hdd_ctx->config->lro_enable || + NL80211_IFTYPE_STATION != adapter->wdev.iftype) { + hdd_info("LRO Disabled"); + return 0; + } + + hdd_info("LRO Enabled"); + + hdd_lro = &adapter->lro_info; + cdf_mem_zero((void *)hdd_lro, sizeof(struct hdd_lro_s)); + /* + * Allocate all the LRO data structures at once and then carve + * them up as needed + */ + lro_mgr_sz = sizeof(struct net_lro_mgr); + desc_arr_sz = (LRO_DESC_POOL_SZ * sizeof(struct net_lro_desc)); + desc_pool_sz = (LRO_DESC_POOL_SZ * sizeof(struct hdd_lro_desc_entry)); + hash_table_sz = (sizeof(struct hdd_lro_desc_table) * LRO_DESC_TABLE_SZ); + + lro_mem_ptr = cdf_mem_malloc(lro_mgr_sz + desc_arr_sz + desc_pool_sz + + hash_table_sz); + + if (NULL == lro_mem_ptr) { + hdd_err("Unable to allocate memory for LRO"); + hdd_ctx->config->lro_enable = 0; + return -ENOMEM; + } + + /* LRO manager */ + hdd_lro->lro_mgr = (struct net_lro_mgr *)lro_mem_ptr; + lro_mem_ptr += lro_mgr_sz; + + /* LRO decriptor array */ + hdd_lro->lro_mgr->lro_arr = (struct net_lro_desc *)lro_mem_ptr; + lro_mem_ptr += desc_arr_sz; + + /* LRO descriptor pool */ + hdd_lro->lro_desc_info.lro_desc_pool.lro_desc_array = + (struct hdd_lro_desc_entry *)lro_mem_ptr; + lro_mem_ptr += desc_pool_sz; + + /* hash table to store the LRO descriptors */ + hdd_lro->lro_desc_info.lro_hash_table = + (struct hdd_lro_desc_table *)lro_mem_ptr; + + /* Initialize the LRO descriptors */ + hdd_lro_desc_info_init(hdd_lro); + + hdd_lro->lro_mgr->dev = adapter->dev; + if (ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) + hdd_lro->lro_mgr->features = LRO_F_NI; + + if (hdd_napi_enabled(HDD_NAPI_ANY)) + hdd_lro->lro_mgr->features |= LRO_F_NAPI; + + hdd_lro->lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + hdd_lro->lro_mgr->max_aggr = LRO_MAX_AGGR_SIZE; + hdd_lro->lro_mgr->get_skb_header = hdd_lro_get_skb_header; + hdd_lro->lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; + hdd_lro->lro_mgr->max_desc = LRO_DESC_POOL_SZ; + + adapter->dev->features |= NETIF_F_LRO; + + /* Register the flush callback */ + ol_register_lro_flush_cb(hdd_lro_flush, adapter); + + return 0; +} + +/** + * hdd_lro_disable() - disable LRO + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * + * This function frees the HDD LRO instance for the network + * device attached to the HDD adapter + * + * Return: none + */ +void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + if (!hdd_ctx->config->lro_enable || + NL80211_IFTYPE_STATION != adapter->wdev.iftype) + return; + + hdd_lro_desc_info_deinit(&adapter->lro_info); + cdf_mem_free(adapter->lro_info.lro_mgr); + adapter->lro_info.lro_mgr = NULL; + return; +} + +/** + * hdd_lro_rx() - LRO receive function + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * @skb: network buffer + * + * Delivers LRO eligible frames to the LRO manager + * + * Return: HDD_LRO_RX - frame delivered to LRO manager + * HDD_LRO_NO_RX - frame not delivered + */ +enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb) +{ + enum hdd_lro_rx_status status = HDD_LRO_NO_RX; + + if ((adapter->dev->features & NETIF_F_LRO) && + NBUF_TCP_PROTO(skb)) { + struct iphdr *iph; + struct tcphdr *tcph; + struct net_lro_desc *lro_desc = NULL; + iph = (struct iphdr *)skb->data; + tcph = (struct tcphdr *)(skb->data + NBUF_TCP_OFFSET(skb)); + if (hdd_lro_eligible(adapter, skb, iph, tcph, &lro_desc)) { + struct net_lro_info hdd_lro_info; + + hdd_lro_info.valid_fields = LRO_VALID_FIELDS; + + hdd_lro_info.lro_desc = lro_desc; + hdd_lro_info.lro_eligible = 1; + hdd_lro_info.tcp_ack_num = NBUF_TCP_ACK_NUM(skb); + hdd_lro_info.tcp_data_csum = + csum_unfold(htons(NBUF_TCP_CHKSUM(skb))); + hdd_lro_info.tcp_seq_num = NBUF_TCP_SEQ_NUM(skb); + hdd_lro_info.tcp_win = NBUF_TCP_WIN(skb); + + lro_receive_skb_ext(adapter->lro_info.lro_mgr, skb, + (void *)adapter, &hdd_lro_info); + + if (!hdd_lro_info.lro_desc->active) + hdd_lro_desc_free(lro_desc, adapter); + + status = HDD_LRO_RX; + } else { + hdd_lro_flush_pkt(adapter->lro_info.lro_mgr, + iph, tcph, adapter); + } + } + return status; +} diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c new file mode 100644 index 0000000000..64a72991cd --- /dev/null +++ b/core/hdd/src/wlan_hdd_main.c @@ -0,0 +1,6731 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_main.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include +#include +#include +#ifdef WLAN_FEATURE_LPSS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_ftm.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_stats.h" +#include "cdf_types.h" +#include "cdf_trace.h" + +#include +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_p2p.h" +#include +#include "sap_api.h" +#include +#include +#include +#ifdef MSM_PLATFORM +#ifdef CONFIG_CNSS +#include +#endif +#endif +#include +#include +#include "cfg_api.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "wlan_hdd_tdls.h" +#ifdef FEATURE_WLAN_CH_AVOID +#ifdef CONFIG_CNSS +#include +#endif + +#include "wlan_hdd_ocb.h" + +extern int hdd_hostapd_stop(struct net_device *dev); +#endif /* FEATURE_WLAN_CH_AVOID */ + +#include "wlan_hdd_nan.h" +#include "wlan_hdd_debugfs.h" +#include "wlan_hdd_driver_ops.h" +#include "epping_main.h" +#include "wlan_hdd_memdump.h" + +#include +#include "hif.h" +#include "wma.h" +#include "cds_concurrency.h" +#include "wlan_hdd_green_ap.h" + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#ifdef TIMER_MANAGER +#define TIMER_MANAGER_STR " +TIMER_MANAGER" +#else +#define TIMER_MANAGER_STR "" +#endif + +#ifdef MEMORY_DEBUG +#define MEMORY_DEBUG_STR " +MEMORY_DEBUG" +#else +#define MEMORY_DEBUG_STR "" +#endif + +#define DISABLE_KRAIT_IDLE_PS_VAL 200 +/* the Android framework expects this param even though we don't use it */ +#define BUF_LEN 20 +static char fwpath_buffer[BUF_LEN]; +static struct kparam_string fwpath = { + .string = fwpath_buffer, + .maxlen = BUF_LEN, +}; + +static char *country_code; +static int enable_11d = -1; +static int enable_dfs_chan_scan = -1; + +#ifndef MODULE +static int wlan_hdd_inited; +#endif + +/* + * spinlock for synchronizing asynchronous request/response + * (full description of use in wlan_hdd_main.h) + */ +DEFINE_SPINLOCK(hdd_context_lock); + +static cdf_wake_lock_t wlan_wake_lock; +/* set when SSR is needed after unload */ +static e_hdd_ssr_required is_ssr_required = HDD_SSR_NOT_REQUIRED; + +#define WOW_MAX_FILTER_LISTS 1 +#define WOW_MAX_FILTERS_PER_LIST 4 +#define WOW_MIN_PATTERN_SIZE 6 +#define WOW_MAX_PATTERN_SIZE 64 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_reg_init = { + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE, + .n_patterns = WOW_MAX_FILTER_LISTS * WOW_MAX_FILTERS_PER_LIST, + .pattern_min_len = WOW_MIN_PATTERN_SIZE, + .pattern_max_len = WOW_MAX_PATTERN_SIZE, +}; +#endif + +/* internal function declaration */ + +struct sock *cesium_nl_srv_sock; + +struct completion wlan_start_comp; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_cb(void); +#endif + +/** + * wlan_hdd_txrx_pause_cb() - pause callback from txrx layer + * @vdev_id: vdev_id + * @action: action type + * @reason: reason type + * + * Return: none + */ +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason) +{ + hdd_context_t *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + hdd_adapter_t *adapter; + + if (!hdd_ctx) { + hdd_err("hdd ctx is NULL"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + wlan_hdd_netif_queue_control(adapter, action, reason); + return; +} + +/* + * Store WLAN driver version info in a global variable such that crash debugger + * can extract it from driver debug symbol and crashdump for post processing + */ +uint8_t g_wlan_driver_version[] = QWLAN_VERSIONSTR; + +/** + * hdd_device_mode_to_string() - return string conversion of device mode + * @device_mode: device mode + * + * This utility function helps log string conversion of device mode. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_device_mode_to_string(uint8_t device_mode) +{ + switch (device_mode) { + CASE_RETURN_STRING(WLAN_HDD_INFRA_STATION); + CASE_RETURN_STRING(WLAN_HDD_SOFTAP); + CASE_RETURN_STRING(WLAN_HDD_P2P_CLIENT); + CASE_RETURN_STRING(WLAN_HDD_P2P_GO); + CASE_RETURN_STRING(WLAN_HDD_FTM); + CASE_RETURN_STRING(WLAN_HDD_IBSS); + CASE_RETURN_STRING(WLAN_HDD_P2P_DEVICE); + CASE_RETURN_STRING(WLAN_HDD_OCB); + default: + return "Unknown"; + } +} + +static int __hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *data) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + struct netdev_notifier_info *dev_notif_info = data; + struct net_device *dev = dev_notif_info->dev; +#else + struct net_device *dev = data; +#endif + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + + /* Make sure that this callback corresponds to our device. */ + if ((strncmp(dev->name, "wlan", 4)) && (strncmp(dev->name, "p2p", 3))) + return NOTIFY_DONE; + + if ((adapter->magic != WLAN_HDD_ADAPTER_MAGIC) && + (adapter->dev != dev)) { + hddLog(LOGE, FL("device adapter is not matching!!!")); + return NOTIFY_DONE; + } + + if (!dev->ieee80211_ptr) { + hddLog(LOGE, FL("ieee80211_ptr is NULL!!!")); + return NOTIFY_DONE; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("HDD Context Null Pointer")); + CDF_ASSERT(0); + return NOTIFY_DONE; + } + if (hdd_ctx->isLogpInProgress) + return NOTIFY_DONE; + + hddLog(CDF_TRACE_LEVEL_INFO, FL("%s New Net Device State = %lu"), + dev->name, state); + + switch (state) { + case NETDEV_REGISTER: + break; + + case NETDEV_UNREGISTER: + break; + + case NETDEV_UP: + sme_ch_avoid_update_req(hdd_ctx->hHal); + break; + + case NETDEV_DOWN: + break; + + case NETDEV_CHANGE: + if (true == adapter->isLinkUpSvcNeeded) + complete(&adapter->linkup_event_var); + break; + + case NETDEV_GOING_DOWN: + if (adapter->scan_info.mScanPending != false) { + unsigned long rc; + INIT_COMPLETION(adapter->scan_info. + abortscan_event_var); + hdd_abort_mac_scan(adapter->pHddCtx, + adapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + rc = wait_for_completion_timeout( + &adapter->scan_info.abortscan_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN)); + if (!rc) { + hddLog(LOGE, + FL("Timeout occurred while waiting for abortscan")); + } + } else { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("Scan is not Pending from user")); + } + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +/** + * hdd_netdev_notifier_call() - netdev notifier callback function + * @nb: pointer to notifier block + * @state: state + * @ndev: ndev pointer + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, + void *ndev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_netdev_notifier_call(nb, state, ndev); + cds_ssr_unprotect(__func__); + + return ret; +} + +struct notifier_block hdd_netdev_notifier = { + .notifier_call = hdd_netdev_notifier_call, +}; + +/* variable to hold the insmod parameters */ +static int con_mode; +#ifndef MODULE +/* + * current con_mode - used only for statically linked driver + * con_mode is changed by userspace to indicate a mode change which will + * result in calling the module exit and init functions. The module + * exit function will clean up based on the value of con_mode prior to it + * being changed by userspace. So curr_con_mode records the current con_mode + * for exit when con_mode becomes the next mode for init + */ +static int curr_con_mode; +#endif + +/** + * hdd_cdf_trace_enable() - configure initial CDF Trace enable + * @moduleId: Module whose trace level is being configured + * @bitmask: Bitmask of log levels to be enabled + * + * Called immediately after the cfg.ini is read in order to configure + * the desired trace levels. + * + * Return: None + */ +static void hdd_cdf_trace_enable(CDF_MODULE_ID moduleId, uint32_t bitmask) +{ + CDF_TRACE_LEVEL level; + + /* + * if the bitmask is the default value, then a bitmask was not + * specified in cfg.ini, so leave the logging level alone (it + * will remain at the "compiled in" default value) + */ + if (CFG_CDF_TRACE_ENABLE_DEFAULT == bitmask) { + return; + } + + /* a mask was specified. start by disabling all logging */ + cdf_trace_set_value(moduleId, CDF_TRACE_LEVEL_NONE, 0); + + /* now cycle through the bitmask until all "set" bits are serviced */ + level = CDF_TRACE_LEVEL_FATAL; + while (0 != bitmask) { + if (bitmask & 1) { + cdf_trace_set_value(moduleId, level, 1); + } + level++; + bitmask >>= 1; + } +} + +/** + * wlan_hdd_validate_context() - check the HDD context + * @hdd_ctx: HDD context pointer + * + * Return: 0 if the context is valid. Error code otherwise + */ +int wlan_hdd_validate_context(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (NULL == hdd_ctx || NULL == hdd_ctx->config) { + hddLog(LOGE, FL("HDD context is Null")); + return -ENODEV; + } + + if (hdd_ctx->isLogpInProgress) { + hddLog(LOGE, FL("LOGP in Progress. Ignore!!!")); + return -EAGAIN; + } + + if ((hdd_ctx->isLoadInProgress) || (hdd_ctx->isUnloadInProgress)) { + hddLog(LOGE, FL("Unloading/Loading in Progress. Ignore!!!")); + return -EAGAIN; + } + return 0; +} + +void hdd_checkandupdate_phymode(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + eCsrPhyMode phyMode; + struct hdd_config *cfg_param = NULL; + + if (NULL == hdd_ctx) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("HDD Context is null !!")); + return; + } + + adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_INFRA_STATION); + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("adapter is null !!")); + return; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + cfg_param = hdd_ctx->config; + if (NULL == cfg_param) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("cfg_params not available !!")); + return; + } + + phyMode = sme_get_phy_mode(WLAN_HDD_GET_HAL_CTX(adapter)); + + if (!hdd_ctx->isVHT80Allowed) { + if ((eCSR_DOT11_MODE_AUTO == phyMode) || + (eCSR_DOT11_MODE_11ac == phyMode) || + (eCSR_DOT11_MODE_11ac_ONLY == phyMode)) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("Setting phymode to 11n!!")); + sme_set_phy_mode(WLAN_HDD_GET_HAL_CTX(adapter), + eCSR_DOT11_MODE_11n); + } + } else { + /* + * New country Supports 11ac as well resetting value back from + * .ini + */ + sme_set_phy_mode(WLAN_HDD_GET_HAL_CTX(adapter), + hdd_cfg_xlate_to_csr_phy_mode(cfg_param-> + dot11Mode)); + return; + } + + if ((eConnectionState_Associated == pHddStaCtx->conn_info.connState) && + ((eCSR_CFG_DOT11_MODE_11AC_ONLY == pHddStaCtx->conn_info.dot11Mode) + || (eCSR_CFG_DOT11_MODE_11AC == + pHddStaCtx->conn_info.dot11Mode))) { + CDF_STATUS cdf_status; + + /* need to issue a disconnect to CSR. */ + INIT_COMPLETION(adapter->disconnect_comp_var); + cdf_status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if (CDF_STATUS_SUCCESS == cdf_status) { + unsigned long rc; + + rc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hddLog(LOGE, + FL("failure waiting for disconnect_comp_var")); + } + } +} + +/** + * hdd_set_ibss_power_save_params() - update IBSS Power Save params to WMA. + * @hdd_adapter_t Hdd adapter. + * + * This function sets the IBSS power save config parameters to WMA + * which will send it to firmware if FW supports IBSS power save + * before vdev start. + * + * Return: CDF_STATUS CDF_STATUS_SUCCESS on Success and CDF_STATUS_E_FAILURE + * on failure. + */ +CDF_STATUS hdd_set_ibss_power_save_params(hdd_adapter_t *adapter) +{ + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_ctx == NULL) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("HDD context is null")); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE, + hdd_ctx->config->ibssATIMWinSize, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE failed %d"), ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + hdd_ctx->config->isIbssPowerSaveAllowed, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED failed %d"), + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + hdd_ctx->config-> + isIbssPowerCollapseAllowed, VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED failed %d"), + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + hdd_ctx->config->isIbssAwakeOnTxRx, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX failed %d"), ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + hdd_ctx->config->ibssInactivityCount, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_SET_INACTIVITY_TIME failed %d"), ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + hdd_ctx->config->ibssTxSpEndInactivityTime, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME failed %d" + ), + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + hdd_ctx->config->ibssPsWarmupTime, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS failed %d"), + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + hdd_ctx->config->ibssPs1RxChainInAtimEnable, + VDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW failed %d" + ), + ret); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +#if defined(WLAN_FEATURE_VOWIFI_11R) ||\ + defined(FEATURE_WLAN_ESE) ||\ + defined(FEATURE_WLAN_LFR) + +#define INTF_MACADDR_MASK 0x7 + +/** + * hdd_update_macaddr() - update mac address + * @config: hdd configuration + * @hw_macaddr: mac address + * + * Mac address for multiple virtual interface is found as following + * i) The mac address of the first interface is just the actual hw mac address. + * ii) MSM 3 or 4 bits of byte5 of the actual mac address are used to + * define the mac address for the remaining interfaces and locally + * admistered bit is set. INTF_MACADDR_MASK is based on the number of + * supported virtual interfaces, right now this is 0x07 (meaning 8 + * interface). + * Byte[3] of second interface will be hw_macaddr[3](bit5..7) + 1, + * for third interface it will be hw_macaddr[3](bit5..7) + 2, etc. + * + * Return: None + */ +void hdd_update_macaddr(struct hdd_config *config, + struct cdf_mac_addr hw_macaddr) +{ + int8_t i; + uint8_t macaddr_b3, tmp_br3; + + cdf_mem_copy(config->intfMacAddr[0].bytes, hw_macaddr.bytes, + CDF_MAC_ADDR_SIZE); + for (i = 1; i < CDF_MAX_CONCURRENCY_PERSONA; i++) { + cdf_mem_copy(config->intfMacAddr[i].bytes, hw_macaddr.bytes, + CDF_MAC_ADDR_SIZE); + macaddr_b3 = config->intfMacAddr[i].bytes[3]; + tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + i) & + INTF_MACADDR_MASK; + macaddr_b3 += tmp_br3; + + /* XOR-ing bit-24 of the mac address. This will give enough + * mac address range before collision + */ + macaddr_b3 ^= (1 << 7); + + /* Set locally administered bit */ + config->intfMacAddr[i].bytes[0] |= 0x02; + config->intfMacAddr[i].bytes[3] = macaddr_b3; + hddLog(CDF_TRACE_LEVEL_INFO, "config->intfMacAddr[%d]: " + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(config->intfMacAddr[i].bytes)); + } +} + +static void hdd_update_tgt_services(hdd_context_t *hdd_ctx, + struct wma_tgt_services *cfg) +{ + struct hdd_config *config = hdd_ctx->config; + tpAniSirGlobal pMac = PMAC_STRUCT(hdd_ctx->hHal); + + /* Set up UAPSD */ + config->apUapsdEnabled &= cfg->uapsd; + +#ifdef WLAN_FEATURE_11AC + /* 11AC mode support */ + if ((config->dot11Mode == eHDD_DOT11_MODE_11ac || + config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) && !cfg->en_11ac) + config->dot11Mode = eHDD_DOT11_MODE_AUTO; +#endif /* #ifdef WLAN_FEATURE_11AC */ + + /* ARP offload: override user setting if invalid */ + config->fhostArpOffload &= cfg->arp_offload; + +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("PNO Capability in f/w = %d"), cfg->pno_offload); + if (cfg->pno_offload) + config->PnoOffload = true; +#endif + pMac->lteCoexAntShare = cfg->lte_coex_ant_share; +#ifdef FEATURE_WLAN_TDLS + config->fEnableTDLSSupport &= cfg->en_tdls; + config->fEnableTDLSOffChannel &= cfg->en_tdls_offchan; + config->fEnableTDLSBufferSta &= cfg->en_tdls_uapsd_buf_sta; + if (config->fTDLSUapsdMask && cfg->en_tdls_uapsd_sleep_sta) { + config->fEnableTDLSSleepSta = true; + } else { + config->fEnableTDLSSleepSta = false; + } +#endif + pMac->beacon_offload = cfg->beacon_offload; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + config->isRoamOffloadEnabled &= cfg->en_roam_offload; +#endif + +} + +static void hdd_update_tgt_ht_cap(hdd_context_t *hdd_ctx, + struct wma_tgt_ht_cap *cfg) +{ + CDF_STATUS status; + uint32_t value, val32; + uint16_t val16; + struct hdd_config *pconfig = hdd_ctx->config; + tSirMacHTCapabilityInfo *phtCapInfo; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t enable_tx_stbc; + + /* check and update RX STBC */ + if (pconfig->enableRxSTBC && !cfg->ht_rx_stbc) + pconfig->enableRxSTBC = cfg->ht_rx_stbc; + + /* get the MPDU density */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_MPDU_DENSITY, &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get MPDU DENSITY")); + value = 0; + } + + /* + * MPDU density: + * override user's setting if value is larger + * than the one supported by target + */ + if (value > cfg->mpdu_density) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MPDU_DENSITY, + cfg->mpdu_density); + + if (status == CDF_STATUS_E_FAILURE) + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set MPDU DENSITY to CCM")); + } + + /* get the HT capability info */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, &val32); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get HT capability info")); + return; + } + val16 = (uint16_t) val32; + phtCapInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* Set the LDPC capability */ + phtCapInfo->advCodingCap = cfg->ht_rx_ldpc; + + if (pconfig->ShortGI20MhzEnable && !cfg->ht_sgi_20) + pconfig->ShortGI20MhzEnable = cfg->ht_sgi_20; + + if (pconfig->ShortGI40MhzEnable && !cfg->ht_sgi_40) + pconfig->ShortGI40MhzEnable = cfg->ht_sgi_40; + + hdd_ctx->num_rf_chains = cfg->num_rf_chains; + hdd_ctx->ht_tx_stbc_supported = cfg->ht_tx_stbc; + + enable_tx_stbc = pconfig->enableTxSTBC; + + if (pconfig->enable2x2 && (cfg->num_rf_chains == 2)) { + pconfig->enable2x2 = 1; + } else { + pconfig->enable2x2 = 0; + enable_tx_stbc = 0; + + /* 1x1 */ + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1) + == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL( + "Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CCM" + )); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int + (hdd_ctx->hHal, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + HDD_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == + CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL( + "Could not pass on HDD_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 to CCM" + )); + } + } + if (!(cfg->ht_tx_stbc && pconfig->enable2x2)) + enable_tx_stbc = 0; + phtCapInfo->txSTBC = enable_tx_stbc; + + val32 = val16; + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, val32); + if (status != CDF_STATUS_SUCCESS) + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set HT capability to CCM")); +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + value = SIZE_OF_SUPPORTED_MCS_SET; + if (sme_cfg_get_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, mcs_set, + &value) == CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("Read MCS rate set")); + + if (pconfig->enable2x2) { + for (value = 0; value < cfg->num_rf_chains; value++) + mcs_set[value] = + WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + status = + sme_cfg_set_str(hdd_ctx->hHal, + WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET); + if (status == CDF_STATUS_E_FAILURE) + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set MCS SET to CCM")); + } + } +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES +} + +#ifdef WLAN_FEATURE_11AC +static void hdd_update_tgt_vht_cap(hdd_context_t *hdd_ctx, + struct wma_tgt_vht_cap *cfg) +{ + CDF_STATUS status; + uint32_t value = 0; + struct hdd_config *pconfig = hdd_ctx->config; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct ieee80211_supported_band *band_5g = + wiphy->bands[IEEE80211_BAND_5GHZ]; + + /* Get the current MPDU length */ + status = + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MAX_MPDU_LENGTH, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("could not get MPDU LENGTH")); + value = 0; + } + + /* + * VHT max MPDU length: + * override if user configured value is too high + * that the target cannot support + */ + if (value > cfg->vht_max_mpdu) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + cfg->vht_max_mpdu); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set VHT MAX MPDU LENGTH")); + } + } + + /* Get the current supported chan width */ + status = sme_cfg_get_int(hdd_ctx->hHal, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get MPDU LENGTH")); + value = 0; + } + + /* Get the current RX LDPC setting */ + status = + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT LDPC CODING CAP")); + value = 0; + } + + /* Set the LDPC capability */ + if (value && !cfg->vht_rx_ldpc) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_LDPC_CODING_CAP, + cfg->vht_rx_ldpc); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set VHT LDPC CODING CAP to CCM")); + } + } + + /* Get current GI 80 value */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_SHORT_GI_80MHZ, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get SHORT GI 80MHZ")); + value = 0; + } + + /* set the Guard interval 80MHz */ + if (value && !cfg->vht_short_gi_80) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SHORT_GI_80MHZ, + cfg->vht_short_gi_80); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set SHORT GI 80MHZ to CCM")); + } + } + + /* Get current GI 160 value */ + status = sme_cfg_get_int(hdd_ctx->hHal, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get SHORT GI 80 & 160")); + value = 0; + } + + /* Get VHT TX STBC cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT TX STBC")); + value = 0; + } + + /* VHT TX STBC cap */ + if (value && !cfg->vht_tx_stbc) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, + cfg->vht_tx_stbc); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set the VHT TX STBC to CCM")); + } + } + + /* Get VHT RX STBC cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RXSTBC, &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT RX STBC")); + value = 0; + } + + /* VHT RX STBC cap */ + if (value && !cfg->vht_rx_stbc) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RXSTBC, + cfg->vht_rx_stbc); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set the VHT RX STBC to CCM")); + } + } + + /* Get VHT SU Beamformer cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT SU BEAMFORMER CAP")); + value = 0; + } + + /* set VHT SU Beamformer cap */ + if (value && !cfg->vht_su_bformer) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + cfg->vht_su_bformer); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set VHT SU BEAMFORMER CAP")); + } + } + + /* check and update SU BEAMFORMEE capabality */ + if (pconfig->enableTxBF && !cfg->vht_su_bformee) + pconfig->enableTxBF = cfg->vht_su_bformee; + + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + pconfig->enableTxBF); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set VHT SU BEAMFORMEE CAP")); + } + + /* Get VHT MU Beamformer cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MU_BEAMFORMER_CAP, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT MU BEAMFORMER CAP")); + value = 0; + } + + /* set VHT MU Beamformer cap */ + if (value && !cfg->vht_mu_bformer) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + cfg->vht_mu_bformer); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "could not set the VHT MU BEAMFORMER CAP to CCM" + )); + } + } + + /* Get VHT MU Beamformee cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT MU BEAMFORMEE CAP")); + value = 0; + } + + /* set VHT MU Beamformee cap */ + if (value && !cfg->vht_mu_bformee) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + cfg->vht_mu_bformee); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set VHT MU BEAMFORMER CAP")); + } + } + + /* Get VHT MAX AMPDU Len exp */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT AMPDU LEN")); + value = 0; + } + + /* + * VHT max AMPDU len exp: + * override if user configured value is too high + * that the target cannot support. + * Even though Rome publish ampdu_len=7, it can + * only support 4 because of some h/w bug. + */ + + if (value > cfg->vht_max_ampdu_len_exp) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + cfg->vht_max_ampdu_len_exp); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set the VHT AMPDU LEN EXP")); + } + } + + /* Get VHT TXOP PS CAP */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TXOP_PS, &value); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("could not get VHT TXOP PS")); + value = 0; + } + + /* set VHT TXOP PS cap */ + if (value && !cfg->vht_txop_ps) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TXOP_PS, + cfg->vht_txop_ps); + + if (status == CDF_STATUS_E_FAILURE) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("could not set the VHT TXOP PS")); + } + } + + if (WMI_VHT_CAP_MAX_MPDU_LEN_11454 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + else if (WMI_VHT_CAP_MAX_MPDU_LEN_7935 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; + else + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; + + + if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_80P80MHZ)) { + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + } + if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_160MHZ)) { + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + } + + if (cfg->vht_rx_ldpc & WMI_VHT_CAP_RX_LDPC) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; + + if (cfg->vht_short_gi_80 & WMI_VHT_CAP_SGI_80MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (cfg->vht_short_gi_160 & WMI_VHT_CAP_SGI_160MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; + + if (cfg->vht_tx_stbc & WMI_VHT_CAP_TX_STBC) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; + + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_1SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1; + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_2SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_2; + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_3SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_3; + + band_5g->vht_cap.cap |= + (cfg->vht_max_ampdu_len_exp << + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); + + if (cfg->vht_su_bformer & WMI_VHT_CAP_SU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (cfg->vht_su_bformee & WMI_VHT_CAP_SU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + if (cfg->vht_mu_bformer & WMI_VHT_CAP_MU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + if (cfg->vht_mu_bformee & WMI_VHT_CAP_MU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if (cfg->vht_txop_ps & WMI_VHT_CAP_TXOP_PS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS; + +} +#endif /* #ifdef WLAN_FEATURE_11AC */ + +void hdd_update_tgt_cfg(void *context, void *param) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) context; + struct wma_tgt_cfg *cfg = param; + uint8_t temp_band_cap; + + /* first store the INI band capability */ + temp_band_cap = hdd_ctx->config->nBandCapability; + + hdd_ctx->config->nBandCapability = cfg->band_cap; + + /* now overwrite the target band capability with INI + setting if INI setting is a subset */ + + if ((hdd_ctx->config->nBandCapability == eCSR_BAND_ALL) && + (temp_band_cap != eCSR_BAND_ALL)) + hdd_ctx->config->nBandCapability = temp_band_cap; + else if ((hdd_ctx->config->nBandCapability != eCSR_BAND_ALL) && + (temp_band_cap != eCSR_BAND_ALL) && + (hdd_ctx->config->nBandCapability != temp_band_cap)) { + hddLog(CDF_TRACE_LEVEL_WARN, + FL("ini BandCapability not supported by the target")); + } + + if (!cds_is_logp_in_progress()) { + hdd_ctx->reg.reg_domain = cfg->reg_domain; + hdd_ctx->reg.eeprom_rd_ext = cfg->eeprom_rd_ext; + } + + /* This can be extended to other configurations like ht, vht cap... */ + + if (!cdf_is_macaddr_zero(&cfg->hw_macaddr)) { + hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "Invalid MAC passed from target, using MAC from ini file" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdd_ctx->config->intfMacAddr[0].bytes)); + } + + hdd_ctx->target_fw_version = cfg->target_fw_version; + + hdd_ctx->max_intf_count = cfg->max_intf_count; + +#ifdef WLAN_FEATURE_LPSS + hdd_ctx->lpss_support = cfg->lpss_support; +#endif + + hdd_ctx->ap_arpns_support = cfg->ap_arpns_support; + hdd_update_tgt_services(hdd_ctx, &cfg->services); + + hdd_update_tgt_ht_cap(hdd_ctx, &cfg->ht_cap); + +#ifdef WLAN_FEATURE_11AC + hdd_update_tgt_vht_cap(hdd_ctx, &cfg->vht_cap); +#endif /* #ifdef WLAN_FEATURE_11AC */ +} + +/** + * hdd_dfs_indicate_radar() - handle radar detection on current SAP channel + * @context: HDD context pointer + * @param: HDD radar indication pointer + * + * This function is invoked when a radar in found on the + * SAP current operating channel and Data Tx from netif + * has to be stopped to honor the DFS regulations. + * Actions: Stop the netif Tx queues,Indicate Radar present + * in HDD context for future usage. + * + * Return: None + */ +void hdd_dfs_indicate_radar(void *context, void *param) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) context; + struct wma_dfs_radar_ind *hdd_radar_event = + (struct wma_dfs_radar_ind *)param; + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + CDF_STATUS status; + + if (hdd_ctx == NULL) + return; + + if (hdd_radar_event == NULL) + return; + + if (hdd_ctx->config->disableDFSChSwitch) + return; + + if (true == hdd_radar_event->dfs_radar_status) { + hdd_ctx->dfs_radar_found = true; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (WLAN_HDD_SOFTAP == adapter->device_mode || + WLAN_HDD_P2P_GO == adapter->device_mode) { + WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + dfs_cac_block_tx = true; + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } +} +#endif + +/** + * hdd_is_valid_mac_address() - validate MAC address + * @pMacAddr: Pointer to the input MAC address + * + * This function validates whether the given MAC address is valid or not + * Expected MAC address is of the format XX:XX:XX:XX:XX:XX + * where X is the hexa decimal digit character and separated by ':' + * This algorithm works even if MAC address is not separated by ':' + * + * This code checks given input string mac contains exactly 12 hexadecimal + * digits and a separator colon : appears in the input string only after + * an even number of hex digits. + * + * Return: 1 for valid and 0 for invalid + */ +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr) +{ + int xdigit = 0; + int separator = 0; + while (*pMacAddr) { + if (isxdigit(*pMacAddr)) { + xdigit++; + } else if (':' == *pMacAddr) { + if (0 == xdigit || ((xdigit / 2) - 1) != separator) + break; + + ++separator; + } else { + /* Invalid MAC found */ + return 0; + } + ++pMacAddr; + } + return xdigit == 12 && (separator == 5 || separator == 0); +} + +/** + * __hdd_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_open(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, TRACE_CODE_HDD_OPEN_REQUEST, + adapter->sessionId, adapter->device_mode)); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + if (hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hddLog(LOG1, FL("Enabling Tx Queues")); + /* Enable TX queues only when we are connected */ + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + return ret; +} + +/** + * hdd_open() - Wrapper function for __hdd_open to protect it from SSR + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +int hdd_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_stop() - HDD stop function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_stop(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ENTER(); + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, TRACE_CODE_HDD_STOP_REQUEST, + adapter->sessionId, adapter->device_mode)); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + /* Nothing to be done if the interface is not opened */ + if (false == test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("NETDEV Interface is not OPENED")); + return -ENODEV; + } + + /* Make sure the interface is marked as closed */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + hddLog(CDF_TRACE_LEVEL_INFO, FL("Disabling OS Tx queues")); + + /* + * Disable TX on the interface, after this hard_start_xmit() will not + * be called on that interface + */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* + * The interface is marked as down for outside world (aka kernel) + * But the driver is pretty much alive inside. The driver needs to + * tear down the existing connection on the netdev (session) + * cleanup the data pipes and wait until the control plane is stabilized + * for this interface. The call also needs to wait until the above + * mentioned actions are completed before returning to the caller. + * Notice that the hdd_stop_adapter is requested not to close the session + * That is intentional to be able to scan if it is a STA/P2P interface + */ + hdd_stop_adapter(hdd_ctx, adapter, false); + + /* DeInit the adapter. This ensures datapath cleanup as well */ + hdd_deinit_adapter(hdd_ctx, adapter, true); + + EXIT(); + return 0; +} + +/** + * hdd_stop() - Wrapper function for __hdd_stop to protect it from SSR + * @dev: pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success and error number for failure + */ +int hdd_stop(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_uninit() - HDD uninit function + * @dev: Pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * Return: None + */ +static void __hdd_uninit(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ENTER(); + + do { + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hddLog(LOGP, FL("Invalid magic")); + break; + } + + if (NULL == adapter->pHddCtx) { + hddLog(LOGP, FL("NULL hdd_ctx")); + break; + } + + if (dev != adapter->dev) { + hddLog(LOGP, FL("Invalid device reference")); + /* + * we haven't validated all cases so let this go for + * now + */ + } + + hdd_deinit_adapter(adapter->pHddCtx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->dev = NULL; + adapter->magic = 0; + } while (0); + + EXIT(); +} + +/** + * hdd_uninit() - Wrapper function to protect __hdd_uninit from SSR + * @dev: pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * Return: none + */ +static void hdd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_set_mac_address() - set the user specified mac address + * @dev: Pointer to the net device. + * @addr: Pointer to the sockaddr. + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_set_mac_address(struct net_device *dev, void *addr) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + struct sockaddr *psta_mac_addr = addr; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + memcpy(&adapter->macAddressCurrent, psta_mac_addr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + + EXIT(); + return cdf_ret_status; +} + +/** + * hdd_set_mac_address() - Wrapper function to protect __hdd_set_mac_address() + * function from SSR + * @dev: pointer to net_device structure + * @addr: Pointer to the sockaddr + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success. + */ +static int hdd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +uint8_t *wlan_hdd_get_intf_addr(hdd_context_t *hdd_ctx) +{ + int i; + for (i = 0; i < CDF_MAX_CONCURRENCY_PERSONA; i++) { + if (0 == ((hdd_ctx->config->intfAddrMask) & (1 << i))) + break; + } + + if (CDF_MAX_CONCURRENCY_PERSONA == i) + return NULL; + + hdd_ctx->config->intfAddrMask |= (1 << i); + return &hdd_ctx->config->intfMacAddr[i].bytes[0]; +} + +void wlan_hdd_release_intf_addr(hdd_context_t *hdd_ctx, uint8_t *releaseAddr) +{ + int i; + for (i = 0; i < CDF_MAX_CONCURRENCY_PERSONA; i++) { + if (!memcmp(releaseAddr, + &hdd_ctx->config->intfMacAddr[i].bytes[0], + 6)) { + hdd_ctx->config->intfAddrMask &= ~(1 << i); + break; + } + } + return; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * __hdd_set_multicast_list() - set the multicast address list + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * + * This funciton sets the multicast address list. + * + * Return: None + */ +static void __hdd_set_multicast_list(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int mc_count; + int i = 0, status; + struct netdev_hw_addr *ha; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + static const uint8_t ipv6_router_solicitation[] + = {0x33, 0x33, 0x00, 0x00, 0x00, 0x02}; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hdd_err("hdd_ctx is not valid"); + return; + } + + if (dev->flags & IFF_ALLMULTI) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("allow all multicast frames")); + adapter->mc_addr_list.mc_cnt = 0; + } else { + mc_count = netdev_mc_count(dev); + hddLog(CDF_TRACE_LEVEL_INFO, + FL("mc_count = %u"), mc_count); + if (mc_count > WLAN_HDD_MAX_MC_ADDR_LIST) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL( + "No free filter available; allow all multicast frames" + )); + adapter->mc_addr_list.mc_cnt = 0; + return; + } + + adapter->mc_addr_list.mc_cnt = mc_count; + + netdev_for_each_mc_addr(ha, dev) { + if (i == mc_count) + break; + /* + * Skip following addresses: + * 1)IPv6 router solicitation address + * 2)Any other address pattern if its set during + * RXFILTER REMOVE driver command based on + * addr_filter_pattern + */ + if ((!memcmp(ha->addr, ipv6_router_solicitation, + ETH_ALEN)) || + (adapter->addr_filter_pattern && (!memcmp(ha->addr, + &adapter->addr_filter_pattern, 1)))) { + hdd_err("MC/BC filtering Skip addr ="MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(ha->addr)); + adapter->mc_addr_list.mc_cnt--; + continue; + } + + memset(&(adapter->mc_addr_list.addr[i][0]), 0, + ETH_ALEN); + memcpy(&(adapter->mc_addr_list.addr[i][0]), ha->addr, + ETH_ALEN); + hddLog(CDF_TRACE_LEVEL_INFO, + FL("mlist[%d] = " MAC_ADDRESS_STR), i, + MAC_ADDR_ARRAY(adapter->mc_addr_list.addr[i])); + i++; + } + } + if (hdd_ctx->config->active_mode_offload) { + hdd_info("enable mc filtering"); + wlan_hdd_set_mc_addr_list(adapter, true); + } else { + hdd_info("skip mc filtering enable it during cfg80211 suspend"); + } + return; +} + +/** + * hdd_set_multicast_list() - SSR wrapper function for __hdd_set_multicast_list + * @dev: pointer to net_device + * + * Return: none + */ +static void hdd_set_multicast_list(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_set_multicast_list(dev); + cds_ssr_unprotect(__func__); +} +#endif + +/** + * hdd_select_queue() - used by Linux OS to decide which queue to use first + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * + * This function is registered with the Linux OS for network + * core to decide which queue to use first. + * + * Return: ac, Queue Index/access category corresponding to UP in IP header + */ +static uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif +) +{ + return hdd_wmm_select_queue(dev, skb); +} + +static struct net_device_ops wlan_drv_ops = { + .ndo_open = hdd_open, + .ndo_stop = hdd_stop, + .ndo_uninit = hdd_uninit, + .ndo_start_xmit = hdd_hard_start_xmit, + .ndo_tx_timeout = hdd_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_do_ioctl = hdd_ioctl, + .ndo_set_mac_address = hdd_set_mac_address, + .ndo_select_queue = hdd_select_queue, +#ifdef WLAN_FEATURE_PACKET_FILTERING +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 1, 0)) + .ndo_set_rx_mode = hdd_set_multicast_list, +#else + .ndo_set_multicast_list = hdd_set_multicast_list, +#endif /* LINUX_VERSION_CODE */ +#endif +}; + +void hdd_set_station_ops(struct net_device *pWlanDev) +{ + pWlanDev->netdev_ops = &wlan_drv_ops; +} + +static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr, + const char *name) +{ + struct net_device *pWlanDev = NULL; + hdd_adapter_t *adapter = NULL; + /* + * cfg80211 initialization and registration.... + */ + pWlanDev = + alloc_netdev_mq(sizeof(hdd_adapter_t), name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + NET_NAME_UNKNOWN, +#endif + ether_setup, + NUM_TX_QUEUES); + + if (pWlanDev != NULL) { + + /* Save the pointer to the net_device in the HDD adapter */ + adapter = (hdd_adapter_t *) netdev_priv(pWlanDev); + + cdf_mem_zero(adapter, sizeof(hdd_adapter_t)); + + adapter->dev = pWlanDev; + adapter->pHddCtx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + + init_completion(&adapter->session_open_comp_var); + init_completion(&adapter->session_close_comp_var); + init_completion(&adapter->disconnect_comp_var); + init_completion(&adapter->linkup_event_var); + init_completion(&adapter->cancel_rem_on_chan_var); + init_completion(&adapter->rem_on_chan_ready_event); + init_completion(&adapter->sta_authorized_event); + init_completion(&adapter->offchannel_tx_event); + init_completion(&adapter->tx_action_cnf_event); +#ifdef FEATURE_WLAN_TDLS + init_completion(&adapter->tdls_add_station_comp); + init_completion(&adapter->tdls_del_station_comp); + init_completion(&adapter->tdls_mgmt_comp); + init_completion(&adapter->tdls_link_establish_req_comp); +#endif + init_completion(&adapter->change_country_code); + + + init_completion(&adapter->scan_info.abortscan_event_var); + + adapter->offloads_configured = false; + adapter->isLinkUpSvcNeeded = false; + adapter->higherDtimTransition = true; + /* Init the net_device structure */ + strlcpy(pWlanDev->name, name, IFNAMSIZ); + + cdf_mem_copy(pWlanDev->dev_addr, (void *)macAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(adapter->macAddressCurrent.bytes, macAddr, + sizeof(tSirMacAddr)); + pWlanDev->watchdog_timeo = HDD_TX_TIMEOUT; + pWlanDev->hard_header_len += LIBRA_HW_NEEDED_HEADROOM; + + if (hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) + pWlanDev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + pWlanDev->features |= NETIF_F_RXCSUM; + +#if defined(FEATURE_TSO) + if (hdd_ctx->config->tso_enable) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("TSO Enabled\n")); + pWlanDev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; + } +#endif + hdd_set_station_ops(adapter->dev); + + pWlanDev->destructor = free_netdev; + pWlanDev->ieee80211_ptr = &adapter->wdev; + adapter->wdev.wiphy = hdd_ctx->wiphy; + adapter->wdev.netdev = pWlanDev; + /* set pWlanDev's parent to underlying device */ + SET_NETDEV_DEV(pWlanDev, hdd_ctx->parent_dev); + hdd_wmm_init(adapter); + spin_lock_init(&adapter->pause_map_lock); + } + + return adapter; +} + +CDF_STATUS hdd_register_interface(hdd_adapter_t *adapter, + uint8_t rtnl_lock_held) +{ + struct net_device *pWlanDev = adapter->dev; + /* hdd_station_ctx_t *pHddStaCtx = &adapter->sessionCtx.station; */ + /* hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX( adapter ); */ + /* CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; */ + + if (rtnl_lock_held) { + if (strnchr(pWlanDev->name, strlen(pWlanDev->name), '%')) { + if (dev_alloc_name(pWlanDev, pWlanDev->name) < 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Failed:dev_alloc_name")); + return CDF_STATUS_E_FAILURE; + } + } + if (register_netdevice(pWlanDev)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Failed:register_netdev")); + return CDF_STATUS_E_FAILURE; + } + } else { + if (register_netdev(pWlanDev)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Failed:register_netdev")); + return CDF_STATUS_E_FAILURE; + } + } + set_bit(NET_DEVICE_REGISTERED, &adapter->event_flags); + + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS hdd_sme_close_session_callback(void *pContext) +{ + hdd_adapter_t *adapter = pContext; + + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("NULL adapter")); + return CDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("Invalid magic")); + return CDF_STATUS_NOT_INITIALIZED; + } + + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + +#if !defined (CONFIG_CNSS) && \ + !defined (WLAN_OPEN_SOURCE) + /* + * need to make sure all of our scheduled work has completed. + * This callback is called from MC thread context, so it is safe to + * to call below flush workqueue API from here. + * + * Even though this is called from MC thread context, if there is a faulty + * work item in the system, that can hang this call forever. So flushing + * this global work queue is not safe; and now we make sure that + * individual work queues are stopped correctly. But the cancel work queue + * is a GPL only API, so the proprietary version of the driver would still + * rely on the global work queue flush. + */ + flush_scheduled_work(); +#endif + + /* + * We can be blocked while waiting for scheduled work to be + * flushed, and the adapter structure can potentially be freed, in + * which case the magic will have been reset. So make sure the + * magic is still good, and hence the adapter structure is still + * valid, before signaling completion + */ + if (WLAN_HDD_ADAPTER_MAGIC == adapter->magic) + complete(&adapter->session_close_comp_var); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter) +{ + struct net_device *pWlanDev = adapter->dev; + hdd_station_ctx_t *pHddStaCtx = &adapter->sessionCtx.station; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t type, subType; + unsigned long rc; + int ret_val; + + INIT_COMPLETION(adapter->session_open_comp_var); + sme_set_curr_device_mode(hdd_ctx->hHal, adapter->device_mode); + status = cds_get_vdev_types(adapter->device_mode, &type, &subType); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("failed to get vdev type")); + goto error_sme_open; + } + /* Open a SME session for future operation */ + cdf_ret_status = + sme_open_session(hdd_ctx->hHal, hdd_sme_roam_callback, adapter, + (uint8_t *) &adapter->macAddressCurrent, + &adapter->sessionId, type, subType); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + hddLog(LOGP, + FL("sme_open_session() failed, status code %08d [x%08x]"), + cdf_ret_status, cdf_ret_status); + status = CDF_STATUS_E_FAILURE; + goto error_sme_open; + } + /* Block on a completion variable. Can't wait forever though. */ + rc = wait_for_completion_timeout( + &adapter->session_open_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (!rc) { + hddLog(LOGP, + FL("Session is not opened within timeout period code %ld"), + rc); + status = CDF_STATUS_E_FAILURE; + goto error_sme_open; + } + + /* Register wireless extensions */ + cdf_ret_status = hdd_register_wext(pWlanDev); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + hddLog(LOGP, + FL("hdd_register_wext() failed, status code %08d [x%08x]"), + cdf_ret_status, cdf_ret_status); + status = CDF_STATUS_E_FAILURE; + goto error_register_wext; + } + /* Set the Connection State to Not Connected */ + hddLog(LOG1, + FL("Set HDD connState to eConnectionState_NotConnected")); + pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; + + /* Set the default operation channel */ + pHddStaCtx->conn_info.operationChannel = + hdd_ctx->config->OperatingChannel; + + /* Make the default Auth Type as OPEN */ + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + status = hdd_init_tx_rx(adapter); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGP, + FL("hdd_init_tx_rx() failed, status code %08d [x%08x]"), + status, status); + goto error_init_txrx; + } + + set_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + + status = hdd_wmm_adapter_init(adapter); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGP, + FL("hdd_wmm_adapter_init() failed, status code %08d [x%08x]"), + status, status); + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + ret_val = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + hdd_ctx->config->enableSifsBurst, + PDEV_CMD); + + if (0 != ret_val) { + hddLog(LOGE, + FL("WMI_PDEV_PARAM_BURST_ENABLE set failed %d"), + ret_val); + } +#ifdef FEATURE_WLAN_TDLS + if (0 != wlan_hdd_tdls_init(adapter)) { + status = CDF_STATUS_E_FAILURE; + hddLog(LOGE, FL("wlan_hdd_tdls_init failed")); + goto error_tdls_init; + } + set_bit(TDLS_INIT_DONE, &adapter->event_flags); +#endif + + return CDF_STATUS_SUCCESS; + +#ifdef FEATURE_WLAN_TDLS +error_tdls_init: + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + hdd_wmm_adapter_close(adapter); +#endif +error_wmm_init: + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + hdd_deinit_tx_rx(adapter); +error_init_txrx: + hdd_unregister_wext(pWlanDev); +error_register_wext: + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + INIT_COMPLETION(adapter->session_close_comp_var); + if (CDF_STATUS_SUCCESS == sme_close_session(hdd_ctx->hHal, + adapter->sessionId, + hdd_sme_close_session_callback, + adapter)) { + unsigned long rc; + + /* + * Block on a completion variable. + * Can't wait forever though. + */ + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (rc <= 0) + hddLog(LOGE, + FL("Session is not opened within timeout period code %ld"), + rc); + } + } +error_sme_open: + return status; +} + +void hdd_cleanup_actionframe(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + hdd_cfg80211_state_t *cfgState; + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + + if (NULL != cfgState->buf) { + unsigned long rc; + INIT_COMPLETION(adapter->tx_action_cnf_event); + rc = wait_for_completion_timeout( + &adapter->tx_action_cnf_event, + msecs_to_jiffies(ACTION_FRAME_TX_TIMEOUT)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("HDD Wait for Action Confirmation Failed!!")); + } + } + return; +} + +void hdd_deinit_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool rtnl_held) +{ + ENTER(); + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + case WLAN_HDD_P2P_DEVICE: + { + if (test_bit + (INIT_TX_RX_SUCCESS, &adapter->event_flags)) { + hdd_deinit_tx_rx(adapter); + clear_bit(INIT_TX_RX_SUCCESS, + &adapter->event_flags); + } + + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, + &adapter->event_flags); + } + + hdd_cleanup_actionframe(hdd_ctx, adapter); + wlan_hdd_tdls_exit(adapter); + break; + } + + case WLAN_HDD_SOFTAP: + case WLAN_HDD_P2P_GO: + { + + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, + &adapter->event_flags); + } + + hdd_cleanup_actionframe(hdd_ctx, adapter); + + hdd_unregister_hostapd(adapter, rtnl_held); + + /* set con_mode to STA only when no SAP concurrency mode */ + if (! + (cds_get_concurrency_mode() & + (CDF_SAP_MASK | CDF_P2P_GO_MASK))) + hdd_set_conparam(0); + + break; + } + + default: + break; + } + + EXIT(); +} + +void hdd_cleanup_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + uint8_t rtnl_held) +{ + struct net_device *pWlanDev = NULL; + + if (adapter) + pWlanDev = adapter->dev; + else { + hddLog(LOGE, FL("adapter is Null")); + return; + } + + hdd_lro_disable(hdd_ctx, adapter); + /* + * The adapter is marked as closed. When hdd_wlan_exit() call returns, + * the driver is almost closed and cannot handle either control + * messages or data. However, unregister_netdevice() call above will + * eventually invoke hdd_stop (ndo_close) driver callback, which attempts + * to close the active connections (basically excites control path) which + * is not right. Setting this flag helps hdd_stop() to recognize that + * the interface is closed and restricts any operations on that + */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + if (test_bit(NET_DEVICE_REGISTERED, &adapter->event_flags)) { + if (rtnl_held) { + unregister_netdevice(pWlanDev); + } else { + unregister_netdev(pWlanDev); + } + /* + * Note that the adapter is no longer valid at this point + * since the memory has been reclaimed + */ + } +} + +CDF_STATUS hdd_check_for_existing_macaddr(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + CDF_STATUS status; + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter + && cdf_mem_compare(adapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr))) { + return CDF_STATUS_E_FAILURE; + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + return CDF_STATUS_SUCCESS; +} +hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, + const char *iface_name, tSirMacAddr macAddr, + uint8_t rtnl_held) +{ + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *pHddAdapterNode = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + hdd_cfg80211_state_t *cfgState; + int ret; + + hddLog(LOG2, FL("iface(%s) type(%d)"), iface_name, session_type); + + if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) { + /* + * Max limit reached on the number of vdevs configured by the + * host. Return error + */ + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "Unable to add virtual intf: currentVdevCnt=%d,hostConfiguredVdevCnt=%d" + ), + hdd_ctx->current_intf_count, hdd_ctx->max_intf_count); + return NULL; + } + + if (macAddr == NULL) { + /* Not received valid macAddr */ + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "Unable to add virtual intf: Not able to get valid mac address" + )); + return NULL; + } + status = hdd_check_for_existing_macaddr(hdd_ctx, macAddr); + if (CDF_STATUS_E_FAILURE == status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "Duplicate MAC addr: " MAC_ADDRESS_STR + " already exists", + MAC_ADDR_ARRAY(macAddr)); + return NULL; + } + + switch (session_type) { + case WLAN_HDD_INFRA_STATION: + /* Reset locally administered bit if the device mode is STA */ + WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr); + /* fall through */ + case WLAN_HDD_P2P_CLIENT: + case WLAN_HDD_P2P_DEVICE: + case WLAN_HDD_OCB: + { + adapter = + hdd_alloc_station_adapter(hdd_ctx, macAddr, iface_name); + + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("failed to allocate adapter for session %d"), + session_type); + return NULL; + } + + if (WLAN_HDD_P2P_CLIENT == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) + else if (WLAN_HDD_P2P_DEVICE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE; +#endif + else + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + + adapter->device_mode = session_type; + + status = hdd_init_station_mode(adapter); + if (CDF_STATUS_SUCCESS != status) + goto err_free_netdev; + + hdd_lro_enable(hdd_ctx, adapter); + + /* + * Workqueue which gets scheduled in IPv4 notification + * callback + */ +#ifdef CONFIG_CNSS + cnss_init_work(&adapter->ipv4NotifierWorkQueue, + hdd_ipv4_notifier_work_queue); +#else + INIT_WORK(&adapter->ipv4NotifierWorkQueue, + hdd_ipv4_notifier_work_queue); +#endif + +#ifdef WLAN_NS_OFFLOAD + /* + * Workqueue which gets scheduled in IPv6 + * notification callback. + */ +#ifdef CONFIG_CNSS + cnss_init_work(&adapter->ipv6NotifierWorkQueue, + hdd_ipv6_notifier_work_queue); +#else + INIT_WORK(&adapter->ipv6NotifierWorkQueue, + hdd_ipv6_notifier_work_queue); +#endif +#endif + status = hdd_register_interface(adapter, rtnl_held); + if (CDF_STATUS_SUCCESS != status) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + goto err_lro_cleanup; + } + + /* Stop the Interface TX queue. */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + + break; + } + + case WLAN_HDD_P2P_GO: + case WLAN_HDD_SOFTAP: + { + adapter = + hdd_wlan_create_ap_dev(hdd_ctx, macAddr, + (uint8_t *) iface_name); + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("failed to allocate adapter for session %d"), + session_type); + return NULL; + } + + adapter->wdev.iftype = + (session_type == + WLAN_HDD_SOFTAP) ? NL80211_IFTYPE_AP : + NL80211_IFTYPE_P2P_GO; + adapter->device_mode = session_type; + + status = hdd_init_ap_mode(adapter); + if (CDF_STATUS_SUCCESS != status) + goto err_free_netdev; + + status = hdd_register_hostapd(adapter, rtnl_held); + if (CDF_STATUS_SUCCESS != status) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + goto err_free_netdev; + } + + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + hdd_set_conparam(1); + + break; + } + case WLAN_HDD_FTM: + { + adapter = + hdd_alloc_station_adapter(hdd_ctx, macAddr, iface_name); + + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("failed to allocate adapter for session %d"), + session_type); + return NULL; + } + + /* + * Assign NL80211_IFTYPE_STATION as interface type to resolve + * Kernel Warning message while loading driver in FTM mode. + */ + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + adapter->device_mode = session_type; + status = hdd_register_interface(adapter, rtnl_held); + + hdd_init_tx_rx(adapter); + + /* Stop the Interface TX queue. */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + } + break; + default: + { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Invalid session type %d"), + session_type); + CDF_ASSERT(0); + return NULL; + } + } + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + mutex_init(&cfgState->remain_on_chan_ctx_lock); + + if (CDF_STATUS_SUCCESS == status) { + /* Add it to the hdd's session list. */ + pHddAdapterNode = + cdf_mem_malloc(sizeof(hdd_adapter_list_node_t)); + if (NULL == pHddAdapterNode) { + status = CDF_STATUS_E_NOMEM; + } else { + pHddAdapterNode->pAdapter = adapter; + status = hdd_add_adapter_back(hdd_ctx, pHddAdapterNode); + } + } + + if (CDF_STATUS_SUCCESS != status) { + if (NULL != adapter) { + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + adapter = NULL; + } + if (NULL != pHddAdapterNode) { + cdf_mem_free(pHddAdapterNode); + } + return NULL; + } + + if (CDF_STATUS_SUCCESS == status) { + cds_set_concurrency_mode(hdd_ctx, session_type); + + /* Initialize the WoWL service */ + if (!hdd_init_wowl(adapter)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("hdd_init_wowl failed")); + goto err_lro_cleanup; + } + + /* Adapter successfully added. Increment the vdev count */ + hdd_ctx->current_intf_count++; + + hddLog(CDF_TRACE_LEVEL_DEBUG, FL("current_intf_count=%d"), + hdd_ctx->current_intf_count); + + cds_check_and_restart_sap_with_non_dfs_acs(hdd_ctx); + } + + if ((cds_get_conparam() != CDF_FTM_MODE) + && (!hdd_ctx->config->enable2x2)) { +#define HDD_DTIM_1CHAIN_RX_ID 0x5 +#define HDD_SMPS_PARAM_VALUE_S 29 + + /* + * Disable DTIM 1 chain Rx when in 1x1, we are passing two value + * as param_id << 29 | param_value. + * Below param_value = 0(disable) + */ + ret = wma_cli_set_command(adapter->sessionId, + WMI_STA_SMPS_PARAM_CMDID, + HDD_DTIM_1CHAIN_RX_ID << + HDD_SMPS_PARAM_VALUE_S, + VDEV_CMD); + + if (ret != 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("DTIM 1 chain set failed %d"), ret); + goto err_lro_cleanup; + } + + ret = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + hdd_ctx->config->txchainmask1x1, + PDEV_CMD); + if (ret != 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMI_PDEV_PARAM_TX_CHAIN_MASK set failed %d"), + ret); + goto err_lro_cleanup; + } + ret = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + hdd_ctx->config->rxchainmask1x1, + PDEV_CMD); + if (ret != 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMI_PDEV_PARAM_RX_CHAIN_MASK set failed %d"), + ret); + goto err_lro_cleanup; + } +#undef HDD_DTIM_1CHAIN_RX_ID +#undef HDD_SMPS_PARAM_VALUE_S + } + + if (CDF_FTM_MODE != cds_get_conparam()) { + ret = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_HYST_EN, + hdd_ctx->config->enableMemDeepSleep, + PDEV_CMD); + + if (ret != 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WMI_PDEV_PARAM_HYST_EN set failed %d"), + ret); + goto err_lro_cleanup; + } + } + +#ifdef CONFIG_FW_LOGS_BASED_ON_INI + + /* Enable FW logs based on INI configuration */ + if ((CDF_FTM_MODE != cds_get_conparam()) && + (hdd_ctx->config->enablefwlog)) { + uint8_t count = 0; + uint32_t value = 0; + uint8_t numEntries = 0; + uint8_t moduleLoglevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + + hdd_ctx->fw_log_settings.dl_type = + hdd_ctx->config->enableFwLogType; + ret = wma_cli_set_command(adapter->sessionId, + WMI_DBGLOG_TYPE, + hdd_ctx->config->enableFwLogType, + DBG_CMD); + if (ret != 0) { + hddLog(LOGE, FL("Failed to enable FW log type ret %d"), + ret); + } + + hdd_ctx->fw_log_settings.dl_loglevel = + hdd_ctx->config->enableFwLogLevel; + ret = wma_cli_set_command(adapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + hdd_ctx->config->enableFwLogLevel, + DBG_CMD); + if (ret != 0) { + hddLog(LOGE, FL("Failed to enable FW log level ret %d"), + ret); + } + + hdd_string_to_u8_array(hdd_ctx->config->enableFwModuleLogLevel, + moduleLoglevel, + &numEntries, + FW_MODULE_LOG_LEVEL_STRING_LENGTH); + while (count < numEntries) { + /* + * FW module log level input string looks like below: + * gFwDebugModuleLoglevel=,,... + * For example: + * gFwDebugModuleLoglevel=1,0,2,1,3,2,4,3,5,4,6,5,7,6 + * Above input string means : + * For FW module ID 1 enable log level 0 + * For FW module ID 2 enable log level 1 + * For FW module ID 3 enable log level 2 + * For FW module ID 4 enable log level 3 + * For FW module ID 5 enable log level 4 + * For FW module ID 6 enable log level 5 + * For FW module ID 7 enable log level 6 + */ + + /* FW expects WMI command value = + * Module ID * 10 + Module Log level + */ + value = ((moduleLoglevel[count] * 10) + + moduleLoglevel[count + 1]); + ret = wma_cli_set_command(adapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + value, DBG_CMD); + if (ret != 0) { + hddLog(LOGE, + FL + ("Failed to enable FW module log level %d ret %d"), + value, ret); + } + + count += 2; + } + } +#endif + + return adapter; + +err_lro_cleanup: + hdd_lro_disable(hdd_ctx, adapter); +err_free_netdev: + free_netdev(adapter->dev); + wlan_hdd_release_intf_addr(hdd_ctx, adapter->macAddressCurrent.bytes); + + return NULL; +} + +CDF_STATUS hdd_close_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + uint8_t rtnl_held) +{ + hdd_adapter_list_node_t *adapterNode, *pCurrent, *pNext; + CDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &pCurrent); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_WARN, FL("adapter list empty %d"), + status); + return status; + } + + while (pCurrent->pAdapter != adapter) { + status = hdd_get_next_adapter(hdd_ctx, pCurrent, &pNext); + if (CDF_STATUS_SUCCESS != status) + break; + + pCurrent = pNext; + } + adapterNode = pCurrent; + if (CDF_STATUS_SUCCESS == status) { + cds_clear_concurrency_mode(hdd_ctx, adapter->device_mode); + hdd_cleanup_adapter(hdd_ctx, adapterNode->pAdapter, rtnl_held); + + hdd_remove_adapter(hdd_ctx, adapterNode); + cdf_mem_free(adapterNode); + adapterNode = NULL; + + /* Adapter removed. Decrement vdev count */ + if (hdd_ctx->current_intf_count != 0) + hdd_ctx->current_intf_count--; + + /* Fw will take care incase of concurrency */ + return CDF_STATUS_SUCCESS; + } + return CDF_STATUS_E_FAILURE; +} + +CDF_STATUS hdd_close_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *pHddAdapterNode; + CDF_STATUS status; + + ENTER(); + + do { + status = hdd_remove_front_adapter(hdd_ctx, &pHddAdapterNode); + if (pHddAdapterNode && CDF_STATUS_SUCCESS == status) { + hdd_cleanup_adapter(hdd_ctx, pHddAdapterNode->pAdapter, + false); + cdf_mem_free(pHddAdapterNode); + } + } while (NULL != pHddAdapterNode && CDF_STATUS_E_EMPTY != status); + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +void wlan_hdd_reset_prob_rspies(hdd_adapter_t *pHostapdAdapter) +{ + uint8_t *bssid = NULL; + tSirUpdateIE updateIE; + switch (pHostapdAdapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pHostapdAdapter); + bssid = (uint8_t *) &pHddStaCtx->conn_info.bssId; + break; + } + case WLAN_HDD_SOFTAP: + case WLAN_HDD_P2P_GO: + case WLAN_HDD_IBSS: + { + bssid = pHostapdAdapter->macAddressCurrent.bytes; + break; + } + case WLAN_HDD_FTM: + case WLAN_HDD_P2P_DEVICE: + default: + /* + * wlan_hdd_reset_prob_rspies should not have been called + * for these kind of devices + */ + hddLog(LOGE, + FL("Unexpected request for the current device type %d"), + pHostapdAdapter->device_mode); + return; + } + + cdf_mem_copy(updateIE.bssid, bssid, sizeof(tSirMacAddr)); + updateIE.smeSessionId = pHostapdAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pHostapdAdapter), + &updateIE, + eUPDATE_IE_PROBE_RESP) == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Could not pass on PROBE_RSP_BCN data to PE")); + } +} + +CDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + const bool bCloseSession) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + union iwreq_data wrqu; + tSirUpdateIE updateIE; + unsigned long rc; + + ENTER(); + + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + case WLAN_HDD_P2P_DEVICE: + if (hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)) || + hdd_is_connecting( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + if (pWextState->roamProfile.BSSType == + eCSR_BSS_TYPE_START_IBSS) + cdf_ret_status = + sme_roam_disconnect(hdd_ctx->hHal, + adapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + else + cdf_ret_status = + sme_roam_disconnect(hdd_ctx->hHal, + adapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + /* success implies disconnect command got queued up successfully */ + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + rc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "wait on disconnect_comp_var failed" + )); + } + } else { + hddLog(LOGE, + FL( + "failed to post disconnect event to SME" + )); + } + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, &wrqu, + NULL); + } else { + hdd_abort_mac_scan(hdd_ctx, adapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + } + + if (adapter->device_mode != WLAN_HDD_INFRA_STATION) + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4NotifierWorkQueue); +#endif + + hdd_deregister_tx_flow_control(adapter); + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6NotifierWorkQueue); +#endif +#endif + + /* + * It is possible that the caller of this function does not + * wish to close the session + */ + if (true == bCloseSession && + test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + INIT_COMPLETION(adapter->session_close_comp_var); + if (CDF_STATUS_SUCCESS == + sme_close_session(hdd_ctx->hHal, adapter->sessionId, + hdd_sme_close_session_callback, + adapter)) { + /* + * Block on a completion variable. Can't wait + * forever though. + */ + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (!rc) { + hddLog(LOGE, + FL( + "failure waiting for session_close_comp_var" + )); + } + } + } + break; + + case WLAN_HDD_SOFTAP: + case WLAN_HDD_P2P_GO: + if (hdd_ctx->config->conc_custom_rule1 && + (WLAN_HDD_SOFTAP == adapter->device_mode)) { + /* + * Before stopping the sap adapter, lets make sure there + * is no sap restart work pending. + */ + cds_flush_work(&hdd_ctx->sap_start_work); + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Canceled the pending SAP restart work")); + cds_change_sap_restart_required_status(hdd_ctx, false); + } + /* Any softap specific cleanup here... */ + if (adapter->device_mode == WLAN_HDD_P2P_GO) + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + + hdd_deregister_tx_flow_control(adapter); + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + CDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* Stop Bss. */ +#ifdef WLAN_FEATURE_MBSSID + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); +#else + status = wlansap_stop_bss(hdd_ctx->pcds_context); +#endif + + if (CDF_IS_STATUS_SUCCESS(status)) { + hdd_hostapd_state_t *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + cdf_event_reset(&hostapd_state-> + cdf_stop_bss_event); + status = + cdf_wait_single_event(&hostapd_state-> + cdf_stop_bss_event, + BSS_WAIT_TIMEOUT); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, + FL( + "failure waiting for wlansap_stop_bss %d" + ), + status); + } + } else { + hddLog(LOGE, FL("failure in wlansap_stop_bss")); + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + cds_decr_session_set_pcl(hdd_ctx, + adapter->device_mode, + adapter->sessionId); + + cdf_mem_copy(updateIE.bssid, + adapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = adapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = false; + updateIE.notify = false; + /* Probe bcn reset */ + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, eUPDATE_IE_PROBE_BCN) + == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL( + "Could not pass on PROBE_RSP_BCN data to PE" + )); + } + /* Assoc resp reset */ + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == + CDF_STATUS_E_FAILURE) { + hddLog(LOGE, + FL( + "Could not pass on ASSOC_RSP data to PE" + )); + } + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(adapter); + kfree(adapter->sessionCtx.ap.beacon); + adapter->sessionCtx.ap.beacon = NULL; + } + mutex_unlock(&hdd_ctx->sap_lock); + break; + case WLAN_HDD_OCB: + ol_txrx_clear_peer(WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.staId[0]); + break; + default: + break; + } + + EXIT(); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_stop_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + hdd_stop_adapter(hdd_ctx, adapter, true); + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_reset_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + adapter->sessionCtx.station.hdd_ReassocScenario = false; + + hdd_deinit_tx_rx(adapter); + cds_decr_session_set_pcl(hdd_ctx, + adapter->device_mode, + adapter->sessionId); + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_start_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; +#ifndef MSM_PLATFORM + struct cdf_mac_addr bcastMac = CDF_MAC_ADDR_BROADCAST_INITIALIZER; +#endif + eConnectionState connState; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + hdd_wmm_init(adapter); + + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + case WLAN_HDD_P2P_DEVICE: + + connState = (WLAN_HDD_GET_STATION_CTX_PTR(adapter)) + ->conn_info.connState; + + hdd_init_station_mode(adapter); + /* Open the gates for HDD to receive Wext commands */ + adapter->isLinkUpSvcNeeded = false; + adapter->scan_info.mScanPending = false; + + /* Indicate disconnect event to supplicant if associated previously */ + if (eConnectionState_Associated == connState || + eConnectionState_IbssConnected == connState) { + union iwreq_data wrqu; + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, + &wrqu, NULL); + adapter->sessionCtx.station. + hdd_ReassocScenario = false; + + /* indicate disconnected event to nl80211 */ + cfg80211_disconnected(adapter->dev, + WLAN_REASON_UNSPECIFIED, + NULL, 0, GFP_KERNEL); + } else if (eConnectionState_Connecting == connState) { + /* + * Indicate connect failure to supplicant if we were in the + * process of connecting + */ + cfg80211_connect_result(adapter->dev, NULL, + NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL); + } + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + + break; + + case WLAN_HDD_SOFTAP: + /* softAP can handle SSR */ + break; + + case WLAN_HDD_P2P_GO: +#ifdef MSM_PLATFORM + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("[SSR] send stop ap to supplicant")); + cfg80211_ap_stopped(adapter->dev, GFP_KERNEL); +#else + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("[SSR] send restart supplicant")); + /* event supplicant to restart */ + cfg80211_del_sta(adapter->dev, + (const u8 *)&bcastMac.bytes[0], + GFP_KERNEL); +#endif + break; + + default: + break; + } + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +bool hdd_is_ssr_required(void) +{ + return is_ssr_required == HDD_SSR_REQUIRED; +} + +/* Once SSR is disabled then it cannot be set. */ +void hdd_set_ssr_required(e_hdd_ssr_required value) +{ + if (HDD_SSR_DISABLED == is_ssr_required) + return; + + is_ssr_required = value; +} + +CDF_STATUS hdd_get_front_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t **padapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_peek_front(&hdd_ctx->hddAdapters, + (cdf_list_node_t **) padapterNode); + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +CDF_STATUS hdd_get_next_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode, + hdd_adapter_list_node_t **pNextAdapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_peek_next(&hdd_ctx->hddAdapters, + (cdf_list_node_t *) adapterNode, + (cdf_list_node_t **) pNextAdapterNode); + + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +CDF_STATUS hdd_remove_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_remove_node(&hdd_ctx->hddAdapters, + &adapterNode->node); + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +CDF_STATUS hdd_remove_front_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t **padapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_remove_front(&hdd_ctx->hddAdapters, + (cdf_list_node_t **) padapterNode); + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +CDF_STATUS hdd_add_adapter_back(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_insert_back(&hdd_ctx->hddAdapters, + (cdf_list_node_t *) adapterNode); + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +CDF_STATUS hdd_add_adapter_front(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + CDF_STATUS status; + cdf_spin_lock(&hdd_ctx->hdd_adapter_lock); + status = cdf_list_insert_front(&hdd_ctx->hddAdapters, + (cdf_list_node_t *) adapterNode); + cdf_spin_unlock(&hdd_ctx->hdd_adapter_lock); + return status; +} + +hdd_adapter_t *hdd_get_adapter_by_macaddr(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + CDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (adapter + && cdf_mem_compare(adapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr))) { + return adapter; + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return NULL; + +} + +hdd_adapter_t *hdd_get_adapter_by_vdev(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + CDF_STATUS cdf_status; + + cdf_status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while ((NULL != adapterNode) && (CDF_STATUS_SUCCESS == cdf_status)) { + adapter = adapterNode->pAdapter; + + if (adapter->sessionId == vdev_id) + return adapter; + + cdf_status = + hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("vdev_id %d does not exist with host"), vdev_id); + + return NULL; +} + +hdd_adapter_t *hdd_get_adapter(hdd_context_t *hdd_ctx, device_mode_t mode) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + CDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (adapter && (mode == adapter->device_mode)) + return adapter; + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return NULL; + +} + +/** + * hdd_get_operating_channel() - return operating channel of the device mode + * @hdd_ctx: Pointer to the HDD context. + * @mode: Device mode for which operating channel is required. + * Suported modes: + * WLAN_HDD_INFRA_STATION, + * WLAN_HDD_P2P_CLIENT, + * WLAN_HDD_SOFTAP, + * WLAN_HDD_P2P_GO. + * + * This API returns the operating channel of the requested device mode + * + * Return: channel number. "0" id the requested device is not found OR it is + * not connected. + */ +uint8_t hdd_get_operating_channel(hdd_context_t *hdd_ctx, device_mode_t mode) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + uint8_t operatingChannel = 0; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (mode == adapter->device_mode) { + switch (adapter->device_mode) { + case WLAN_HDD_INFRA_STATION: + case WLAN_HDD_P2P_CLIENT: + if (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))) { + operatingChannel = + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info. + operationChannel; + } + break; + case WLAN_HDD_SOFTAP: + case WLAN_HDD_P2P_GO: + /* softap connection info */ + if (test_bit + (SOFTAP_BSS_STARTED, + &adapter->event_flags)) + operatingChannel = + (WLAN_HDD_GET_AP_CTX_PTR + (adapter))->operatingChannel; + break; + default: + break; + } + + break; /* Found the device of interest. break the loop */ + } + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + return operatingChannel; +} + +static inline CDF_STATUS hdd_unregister_wext_all_adapters(hdd_context_t * + hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) || + (adapter->device_mode == WLAN_HDD_P2P_CLIENT) || + (adapter->device_mode == WLAN_HDD_IBSS) || + (adapter->device_mode == WLAN_HDD_P2P_DEVICE) || + (adapter->device_mode == WLAN_HDD_SOFTAP) || + (adapter->device_mode == WLAN_HDD_P2P_GO)) { + wlan_hdd_cfg80211_deregister_frames(adapter); + hdd_unregister_wext(adapter->dev); + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS hdd_abort_mac_scan_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) || + (adapter->device_mode == WLAN_HDD_P2P_CLIENT) || + (adapter->device_mode == WLAN_HDD_IBSS) || + (adapter->device_mode == WLAN_HDD_P2P_DEVICE) || + (adapter->device_mode == WLAN_HDD_SOFTAP) || + (adapter->device_mode == WLAN_HDD_P2P_GO)) { + hdd_abort_mac_scan(hdd_ctx, adapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IP6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(hdd_context_t *hdd_ctx) +{ + unregister_inet6addr_notifier(&hdd_ctx->ipv6_notifier); + + return; +} + +/** + * hdd_wlan_register_ip6_notifier() - register IP6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +static void hdd_wlan_register_ip6_notifier(hdd_context_t *hdd_ctx) +{ + int ret; + + hdd_ctx->ipv6_notifier.notifier_call = wlan_hdd_ipv6_changed; + ret = register_inet6addr_notifier(&hdd_ctx->ipv6_notifier); + if (ret) + hddLog(LOGE, FL("Failed to register IPv6 notifier")); + else + hddLog(LOGE, FL("Registered IPv6 notifier")); + + return; +} +#else +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IP6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(hdd_context_t *hdd_ctx) +{ +} +/** + * hdd_wlan_register_ip6_notifier() - register IP6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +static void hdd_wlan_register_ip6_notifier(hdd_context_t *hdd_ctx) +{ +} +#endif + +/** + * hdd_wlan_exit() - HDD WLAN exit function + * @hdd_ctx: Pointer to the HDD Context + * + * This is the driver exit point (invoked during rmmod) + * + * Return: None + */ +void hdd_wlan_exit(hdd_context_t *hdd_ctx) +{ + v_CONTEXT_t p_cds_context = hdd_ctx->pcds_context; + CDF_STATUS cdf_status; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct hdd_config *pConfig = hdd_ctx->config; + + ENTER(); + + hddLog(LOGE, FL("Unregister IPv6 notifier")); + hdd_wlan_unregister_ip6_notifier(hdd_ctx); + hddLog(LOGE, FL("Unregister IPv4 notifier")); + unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier); + + hdd_unregister_wext_all_adapters(hdd_ctx); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("FTM MODE")); +#if defined(QCA_WIFI_FTM) + if (hdd_ftm_stop(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("hdd_ftm_stop Failed")); + CDF_ASSERT(0); + } + hdd_ctx->ftm.ftm_state = WLAN_FTM_STOPPED; +#endif + wlan_hdd_ftm_close(hdd_ctx); + hddLog(CDF_TRACE_LEVEL_FATAL, FL("FTM driver unloaded")); + goto free_hdd_ctx; + } + + /* + * Cancel any outstanding scan requests. We are about to close all + * of our adapters, but an adapter structure is what SME passes back + * to our callback function. Hence if there are any outstanding scan + * requests then there is a race condition between when the adapter + * is closed and when the callback is invoked. We try to resolve that + * race condition here by canceling any outstanding scans before we + * close the adapters. + * Note that the scans may be cancelled in an asynchronous manner, so + * ideally there needs to be some kind of synchronization. Rather than + * introduce a new synchronization here, we will utilize the fact that + * we are about to Request Full Power, and since that is synchronized, + * the expectation is that by the time Request Full Power has completed, + * all scans will be cancelled + */ + hdd_abort_mac_scan_all_adapters(hdd_ctx); + +#ifdef MSM_PLATFORM + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&hdd_ctx->bus_bw_timer)) { + cdf_mc_timer_stop(&hdd_ctx->bus_bw_timer); + } + + if (!CDF_IS_STATUS_SUCCESS + (cdf_mc_timer_destroy(&hdd_ctx->bus_bw_timer))) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Cannot deallocate Bus bandwidth timer")); + } +#endif + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&hdd_ctx->skip_acs_scan_timer)) { + cdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + } + + if (!CDF_IS_STATUS_SUCCESS + (cdf_mc_timer_destroy(&hdd_ctx->skip_acs_scan_timer))) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Cannot deallocate ACS Skip timer")); + } +#endif + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &hdd_ctx->dbs_opportunistic_timer)) { + cdf_mc_timer_stop(&hdd_ctx->dbs_opportunistic_timer); + } + + if (!CDF_IS_STATUS_SUCCESS + (cdf_mc_timer_destroy( + &hdd_ctx->dbs_opportunistic_timer))) { + hdd_err("Cannot deallocate dbs opportunistic timer"); + } + + /* + * Powersave Offload Case + * Disable Idle Power Save Mode + */ + hdd_set_idle_ps_config(hdd_ctx, false); + + hdd_debugfs_exit(hdd_ctx); + + /* Unregister the Net Device Notifier */ + unregister_netdevice_notifier(&hdd_netdev_notifier); + + /* + * Stop all adapters, this will ensure the termination of active + * connections on the interface. Make sure the cds_scheduler is + * still available to handle those control messages + */ + hdd_stop_all_adapters(hdd_ctx); + + /* Stop all the modules */ + cdf_status = cds_disable(p_cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to stop CDS")); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } + + /* + * Close the scheduler before calling cds_close to make sure no thread + * is scheduled after the each module close is called i.e after all the + * data structures are freed. + */ + cdf_status = cds_sched_close(p_cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to close CDS Scheduler")); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + } +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK + /* Destroy the wake lock */ + cdf_wake_lock_destroy(&hdd_ctx->rx_wake_lock); +#endif + /* Destroy the wake lock */ + cdf_wake_lock_destroy(&hdd_ctx->sap_wake_lock); + + hdd_hostapd_channel_wakelock_deinit(hdd_ctx); + + /* + * Close CDS + * This frees pMac(HAL) context. There should not be any call + * that requires pMac access after this. + */ + cds_close(p_cds_context); + + hdd_wlan_green_ap_deinit(hdd_ctx); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + if (pConfig && pConfig->wlanLoggingEnable) { + wlan_logging_sock_deactivate_svc(); + } +#endif +#ifdef WLAN_KD_READY_NOTIFIER + cnss_diag_notify_wlan_close(); + ptt_sock_deactivate_svc(); +#endif /* WLAN_KD_READY_NOTIFIER */ + nl_srv_exit(); + + hdd_close_all_adapters(hdd_ctx); + + hdd_ipa_cleanup(hdd_ctx); + + /* Free up RoC request queue and flush workqueue */ + cds_flush_work(&hdd_ctx->roc_req_work); + cdf_list_destroy(&hdd_ctx->hdd_roc_req_q); + cdf_list_destroy(&hdd_ctx->hdd_scan_req_q); + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_destroy( + &hdd_ctx->hdd_conc_list_lock))) { + hdd_err("Failed to destroy hdd_conc_list_lock"); + /* Proceed and complete the clean up */ + } + +free_hdd_ctx: + + /* Free up dynamically allocated members inside HDD Adapter */ + if (hdd_ctx->config) { + kfree(hdd_ctx->config); + hdd_ctx->config = NULL; + } + + wiphy_unregister(wiphy); + wiphy_free(wiphy); + if (hdd_is_ssr_required()) { +#ifdef MSM_PLATFORM +#ifdef CONFIG_CNSS + /* + * WDI timeout had happened during unload, so SSR is needed + * here + */ + subsystem_restart("wcnss"); +#endif +#endif + msleep(5000); + } + hdd_set_ssr_required(false); +} + +void __hdd_wlan_exit(void) +{ + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("Invalid HDD Context")); + EXIT(); + return; + } + + /* module exit should never proceed if SSR is not completed */ + while (hdd_ctx->isLogpInProgress) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("SSR in Progress; block rmmod for 1 second!!!")); + msleep(1000); + } + + hdd_ctx->isUnloadInProgress = true; + + cds_set_load_unload_in_progress(true); + +#ifdef WLAN_FEATURE_LPSS + wlan_hdd_send_status_pkg(NULL, NULL, 0, 0); +#endif + + /* Do all the cleanup before deregistering the driver */ + hdd_wlan_exit(hdd_ctx); + EXIT(); +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +void hdd_skip_acs_scan_timer_handler(void *data) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) data; + + hddLog(LOG1, FL("ACS Scan result expired. Reset ACS scan skip")); + hdd_ctx->skip_acs_scan_status = eSAP_DO_NEW_ACS_SCAN; + + if (!hdd_ctx->hHal) + return; + sme_scan_flush_result(hdd_ctx->hHal); +} +#endif + +#ifdef QCA_HT_2040_COEX +/** + * hdd_wlan_set_ht2040_mode() - notify FW with HT20/HT40 mode + * @adapter: pointer to adapter + * @staId: station id + * @macAddrSTA: station MAC address + * @channel_type: channel type + * + * This function notifies FW with HT20/HT40 mode + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_set_ht2040_mode(hdd_adapter_t *adapter, uint16_t staId, + struct cdf_mac_addr macAddrSTA, int channel_type) +{ + int status; + CDF_STATUS cdf_status; + hdd_context_t *hdd_ctx = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + if (!hdd_ctx->hHal) + return -EINVAL; + + cdf_status = sme_notify_ht2040_mode(hdd_ctx->hHal, staId, macAddrSTA, + adapter->sessionId, channel_type); + if (CDF_STATUS_SUCCESS != cdf_status) { + hddLog(LOGE, "Fail to send notification with ht2040 mode"); + return -EINVAL; + } + + return 0; +} +#endif + +/** + * hdd_wlan_notify_modem_power_state() - notify FW with modem power status + * @state: state + * + * This function notifies FW with modem power status + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_notify_modem_power_state(int state) +{ + int status; + CDF_STATUS cdf_status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + if (!hdd_ctx->hHal) + return -EINVAL; + + cdf_status = sme_notify_modem_power_state(hdd_ctx->hHal, state); + if (CDF_STATUS_SUCCESS != cdf_status) { + hddLog(LOGE, + "Fail to send notification with modem power state %d", + state); + return -EINVAL; + } + return 0; +} + +/** + * + * hdd_post_cds_enable_config() - HDD post cds start config helper + * @adapter - Pointer to the HDD + * + * Return: None + */ +CDF_STATUS hdd_post_cds_enable_config(hdd_context_t *hdd_ctx) +{ + CDF_STATUS cdf_ret_status; + + /* + * Send ready indication to the HDD. This will kick off the MAC + * into a 'running' state and should kick off an initial scan. + */ + cdf_ret_status = sme_hdd_ready_ind(hdd_ctx->hHal); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "sme_hdd_ready_ind() failed with status code %08d [x%08x]" + ), + cdf_ret_status, cdf_ret_status); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/* wake lock APIs for HDD */ +void hdd_prevent_suspend(uint32_t reason) +{ + cdf_wake_lock_acquire(&wlan_wake_lock, reason); +} + +void hdd_allow_suspend(uint32_t reason) +{ + cdf_wake_lock_release(&wlan_wake_lock, reason); +} + +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason) +{ + cdf_wake_lock_timeout_acquire(&wlan_wake_lock, timeout, reason); +} + +/** + * hdd_exchange_version_and_caps() - exchange version and capability with target + * @hdd_ctx: Pointer to HDD context + * + * This is the HDD function to exchange version and capability information + * between Host and Target + * + * This function gets reported version of FW. + * It also finds the version of target headers used to compile the host; + * It compares the above two and prints a warning if they are different; + * It gets the SW and HW version string; + * Finally, it exchanges capabilities between host and target i.e. host + * and target exchange a msg indicating the features they support through a + * bitmap + * + * Return: None + */ +void hdd_exchange_version_and_caps(hdd_context_t *hdd_ctx) +{ + + tSirVersionType versionCompiled; + tSirVersionType versionReported; + tSirVersionString versionString; + uint8_t fwFeatCapsMsgSupported = 0; + CDF_STATUS vstatus; + + memset(&versionCompiled, 0, sizeof(versionCompiled)); + memset(&versionReported, 0, sizeof(versionReported)); + + /* retrieve and display WCNSS version information */ + do { + + vstatus = sme_get_wcnss_wlan_compiled_version(hdd_ctx->hHal, + &versionCompiled); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "unable to retrieve WCNSS WLAN compiled version" + )); + break; + } + + vstatus = sme_get_wcnss_wlan_reported_version(hdd_ctx->hHal, + &versionReported); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "unable to retrieve WCNSS WLAN reported version" + )); + break; + } + + if ((versionCompiled.major != versionReported.major) || + (versionCompiled.minor != versionReported.minor) || + (versionCompiled.version != versionReported.version) || + (versionCompiled.revision != versionReported.revision)) { + pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, " + "Host expected %u.%u.%u.%u\n", + WLAN_MODULE_NAME, + (int)versionReported.major, + (int)versionReported.minor, + (int)versionReported.version, + (int)versionReported.revision, + (int)versionCompiled.major, + (int)versionCompiled.minor, + (int)versionCompiled.version, + (int)versionCompiled.revision); + } else { + pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n", + WLAN_MODULE_NAME, + (int)versionReported.major, + (int)versionReported.minor, + (int)versionReported.version, + (int)versionReported.revision); + } + + vstatus = sme_get_wcnss_software_version(hdd_ctx->hHal, + versionString, + sizeof(versionString)); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "unable to retrieve WCNSS software version string" + )); + break; + } + + pr_info("%s: WCNSS software version %s\n", + WLAN_MODULE_NAME, versionString); + + vstatus = sme_get_wcnss_hardware_version(hdd_ctx->hHal, + versionString, + sizeof(versionString)); + if (!CDF_IS_STATUS_SUCCESS(vstatus)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "unable to retrieve WCNSS hardware version string" + )); + break; + } + + pr_info("%s: WCNSS hardware version %s\n", + WLAN_MODULE_NAME, versionString); + + /* + * 1.Check if FW version is greater than 0.1.1.0. Only then + * send host-FW capability exchange message + * 2.Host-FW capability exchange message is only present on + * target 1.1 so send the message only if it the target is 1.1 + * minor numbers for different target branches: + * 0 -> (1.0)Mainline Build + * 1 -> (1.1)Mainline Build + * 2->(1.04) Stability Build + */ + if (((versionReported.major > 0) || (versionReported.minor > 1) + || ((versionReported.minor >= 1) + && (versionReported.version >= 1))) + && ((versionReported.major == 1) + && (versionReported.minor >= 1))) + fwFeatCapsMsgSupported = 1; + + if (fwFeatCapsMsgSupported) { + /* + * Indicate if IBSS heartbeat monitoring needs to be + * offloaded + */ + if (!hdd_ctx->config->enableIbssHeartBeatOffload) { + sme_disable_feature_capablity + (IBSS_HEARTBEAT_OFFLOAD); + } + + sme_feature_caps_exchange(hdd_ctx->hHal); + } + + } while (0); + +} + +/* Initialize channel list in sme based on the country code */ +CDF_STATUS hdd_set_sme_chan_list(hdd_context_t *hdd_ctx) +{ + return sme_init_chan_list(hdd_ctx->hHal, hdd_ctx->reg.alpha2, + hdd_ctx->reg.cc_src); +} + +/** + * hdd_is_5g_supported() - check if hardware supports 5GHz + * @hdd_ctx: Pointer to the hdd context + * + * HDD function to know if hardware supports 5GHz + * + * Return: true if hardware supports 5GHz + */ +bool hdd_is_5g_supported(hdd_context_t *hdd_ctx) +{ + /* + * If wcnss_wlan_iris_xo_mode() returns WCNSS_XO_48MHZ(1); + * then hardware support 5Ghz. + */ + return true; +} + +static CDF_STATUS wlan_hdd_regulatory_init(hdd_context_t *hdd_ctx) +{ + struct wiphy *wiphy; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + wiphy = hdd_ctx->wiphy; + + /* + * The channel information in + * wiphy needs to be initialized before wiphy registration + */ + status = cds_regulatory_init(); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("cds_init_wiphy failed")); + return status; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_reg_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE; + + wiphy->wowlan.n_patterns = (WOW_MAX_FILTER_LISTS * + WOW_MAX_FILTERS_PER_LIST); + wiphy->wowlan.pattern_min_len = WOW_MIN_PATTERN_SIZE; + wiphy->wowlan.pattern_max_len = WOW_MAX_PATTERN_SIZE; +#endif + + /* registration of wiphy dev with cfg80211 */ + if (0 > wlan_hdd_cfg80211_register(wiphy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("wiphy register failed")); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +#ifdef MSM_PLATFORM +void hdd_cnss_request_bus_bandwidth(hdd_context_t *hdd_ctx, + uint64_t tx_packets, uint64_t rx_packets) +{ +#ifdef CONFIG_CNSS + uint64_t total = tx_packets + rx_packets; + enum cnss_bus_width_type next_vote_level = CNSS_BUS_WIDTH_NONE; + + uint64_t temp_rx = (rx_packets + hdd_ctx->prev_rx) / 2; + enum cnss_bus_width_type next_rx_level = CNSS_BUS_WIDTH_NONE; + if (total > hdd_ctx->config->busBandwidthHighThreshold) + next_vote_level = CNSS_BUS_WIDTH_HIGH; + else if (total > hdd_ctx->config->busBandwidthMediumThreshold) + next_vote_level = CNSS_BUS_WIDTH_MEDIUM; + else + next_vote_level = CNSS_BUS_WIDTH_LOW; + + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].next_vote_level + = next_vote_level; + + if (hdd_ctx->cur_vote_level != next_vote_level) { + hddLog(CDF_TRACE_LEVEL_DEBUG, + FL( + "trigger level %d, tx_packets: %lld, rx_packets: %lld" + ), + next_vote_level, tx_packets, rx_packets); + hdd_ctx->cur_vote_level = next_vote_level; + cnss_request_bus_bandwidth(next_vote_level); + } + hdd_ctx->prev_rx = rx_packets; + if (temp_rx > hdd_ctx->config->tcpDelackThresholdHigh) + next_rx_level = CNSS_BUS_WIDTH_HIGH; + else + next_rx_level = CNSS_BUS_WIDTH_LOW; + + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].next_rx_level + = next_rx_level; + + if (hdd_ctx->cur_rx_level != next_rx_level) { + hddLog(CDF_TRACE_LEVEL_DEBUG, + FL("TCP DELACK trigger level %d, average_rx: %llu"), + next_rx_level, temp_rx); + hdd_ctx->cur_rx_level = next_rx_level; + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_WLAN_TP_IND, + &next_rx_level, + sizeof(next_rx_level)); + } + + hdd_ctx->hdd_txrx_hist_idx++; + hdd_ctx->hdd_txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK; +#endif +} + +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) +static void hdd_bus_bw_compute_cbk(void *priv) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) priv; + hdd_adapter_t *adapter = NULL; + uint64_t tx_packets = 0, rx_packets = 0; + uint64_t total_tx = 0, total_rx = 0; + hdd_adapter_list_node_t *adapterNode = NULL; + CDF_STATUS status = 0; + bool connected = false; + uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0; + + for (status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + NULL != adapterNode && CDF_STATUS_SUCCESS == status; + status = + hdd_get_next_adapter(hdd_ctx, adapterNode, &adapterNode)) { + + if (adapterNode->pAdapter == NULL) + continue; + adapter = adapterNode->pAdapter; + + if ((adapter->device_mode == WLAN_HDD_INFRA_STATION || + adapter->device_mode == WLAN_HDD_P2P_CLIENT) && + WLAN_HDD_GET_STATION_CTX_PTR(adapter)->conn_info.connState + != eConnectionState_Associated) { + + continue; + } + + if ((adapter->device_mode == WLAN_HDD_SOFTAP || + adapter->device_mode == WLAN_HDD_P2P_GO) && + WLAN_HDD_GET_AP_CTX_PTR(adapter)->bApActive == false) { + + continue; + } + + tx_packets += HDD_BW_GET_DIFF(adapter->stats.tx_packets, + adapter->prev_tx_packets); + rx_packets += HDD_BW_GET_DIFF(adapter->stats.rx_packets, + adapter->prev_rx_packets); + + total_rx += adapter->stats.rx_packets; + total_tx += adapter->stats.tx_packets; + + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = adapter->stats.tx_packets; + adapter->prev_rx_packets = adapter->stats.rx_packets; + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + connected = true; + } + + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].total_rx = total_rx; + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].total_tx = total_tx; + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].interval_rx = + rx_packets; + hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].interval_tx = + tx_packets; + + hdd_ipa_uc_stat_query(hdd_ctx, &ipa_tx_packets, &ipa_rx_packets); + tx_packets += (uint64_t)ipa_tx_packets; + rx_packets += (uint64_t)ipa_rx_packets; + + if (!connected) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("bus bandwidth timer running in disconnected state")); + return; + } + + hdd_cnss_request_bus_bandwidth(hdd_ctx, tx_packets, rx_packets); + + hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets); + hdd_ipa_uc_stat_request(adapter, 2); + + cdf_mc_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); +} +#endif + +/** + * wlan_hdd_display_tx_rx_histogram() - display tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + int i; + +#ifdef MSM_PLATFORM + hddLog(CDF_TRACE_LEVEL_ERROR, "BW Interval: %d curr_index %d", + hdd_ctx->config->busBandwidthComputeInterval, + hdd_ctx->hdd_txrx_hist_idx); + hddLog(CDF_TRACE_LEVEL_ERROR, + "BW High TH: %d BW Med TH: %d BW Low TH: %d", + hdd_ctx->config->busBandwidthHighThreshold, + hdd_ctx->config->busBandwidthMediumThreshold, + hdd_ctx->config->busBandwidthLowThreshold); + hddLog(CDF_TRACE_LEVEL_ERROR, "TCP DEL High TH: %d TCP DEL Low TH: %d", + hdd_ctx->config->tcpDelackThresholdHigh, + hdd_ctx->config->tcpDelackThresholdLow); +#endif + + hddLog(CDF_TRACE_LEVEL_ERROR, "index, total_rx, interval_rx," + "total_tx, interval_tx, next_vote_level, next_rx_level"); + + for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%d: %llu, %llu, %llu, %llu, %d, %d", + i, hdd_ctx->hdd_txrx_hist[i].total_rx, + hdd_ctx->hdd_txrx_hist[i].interval_rx, + hdd_ctx->hdd_txrx_hist[i].total_tx, + hdd_ctx->hdd_txrx_hist[i].interval_tx, + hdd_ctx->hdd_txrx_hist[i].next_vote_level, + hdd_ctx->hdd_txrx_hist[i].next_rx_level); + } + return; +} + +/** + * wlan_hdd_clear_tx_rx_histogram() - clear tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + hdd_ctx->hdd_txrx_hist_idx = 0; + cdf_mem_zero(hdd_ctx->hdd_txrx_hist, sizeof(hdd_ctx->hdd_txrx_hist)); +} + +/** + * wlan_hdd_display_netif_queue_history() - display netif queue operation history + * @pHddCtx: hdd context + * + * Return: none + */ +void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx) +{ + + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + CDF_STATUS status; + int i; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && CDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + hddLog(CDF_TRACE_LEVEL_ERROR, + "Session_id %d device mode %d current index %d", + adapter->sessionId, adapter->device_mode, + adapter->history_index); + + hddLog(CDF_TRACE_LEVEL_ERROR, + "Netif queue operation statistics:"); + hddLog(CDF_TRACE_LEVEL_ERROR, + "Current pause_map value %x", adapter->pause_map); + hddLog(CDF_TRACE_LEVEL_ERROR, + " reason_type: pause_cnt: unpause_cnt"); + + for (i = 0; i < WLAN_REASON_TYPE_MAX; i++) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: %d: %d", + hdd_reason_type_to_string(i), + adapter->queue_oper_stats[i].pause_count, + adapter->queue_oper_stats[i].unpause_count); + } + + hddLog(CDF_TRACE_LEVEL_ERROR, + "Netif queue operation history:"); + hddLog(CDF_TRACE_LEVEL_ERROR, + "index: time: action_type: reason_type: pause_map"); + + for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%d: %u: %s: %s: %x", + i, cdf_system_ticks_to_msecs( + adapter->queue_oper_history[i].time), + hdd_action_type_to_string( + adapter->queue_oper_history[i].netif_action), + hdd_reason_type_to_string( + adapter->queue_oper_history[i].netif_reason), + adapter->queue_oper_history[i].pause_map); + } + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + +} + +/** + * wlan_hdd_clear_netif_queue_history() - clear netif queue operation history + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_netif_queue_history(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + CDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && CDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + cdf_mem_zero(adapter->queue_oper_stats, + sizeof(adapter->queue_oper_stats)); + cdf_mem_zero(adapter->queue_oper_history, + sizeof(adapter->queue_oper_history)); + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } +} + +/** + * hdd_11d_scan_done() - callback for 11d scan completion of flushing results + * @halHandle: Hal handle + * @pContext: Pointer to the context + * @sessionId: Session ID + * @scanId: Scan ID + * @status: Status + * + * This is the callback to be executed when 11d scan is completed to flush out + * the scan results + * + * 11d scan is done during driver load and is a passive scan on all + * channels supported by the device, 11d scans may find some APs on + * frequencies which are forbidden to be used in the regulatory domain + * the device is operating in. If these APs are notified to the supplicant + * it may try to connect to these APs, thus flush out all the scan results + * which are present in SME after 11d scan is done. + * + * Return: CDF_STATUS_SUCCESS + */ +static CDF_STATUS hdd_11d_scan_done(tHalHandle halHandle, void *pContext, + uint8_t sessionId, uint32_t scanId, + eCsrScanStatus status) +{ + ENTER(); + + sme_scan_flush_result(halHandle); + + EXIT(); + + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_init_offloaded_packets_ctx() - Initialize offload packets context + * @hdd_ctx: hdd global context + * + * Return: none + */ +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ + uint8_t i; + + mutex_init(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + hdd_ctx->op_ctx.op_table[i].pattern_id = i; + } +} +#else +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hdd_enable_fastpath() - Enable fastpath if enabled in config INI + * @hdd_cfg: hdd config + * @context: lower layer context + * + * Return: none + */ +static void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context) +{ + if (hdd_cfg->fastpath_enable) + hif_enable_fastpath(context); +} +#else +static void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context) +{ +} +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) && defined(CONFIG_CNSS) +/** + * hdd_set_thermal_level_cb() - set thermal level callback function + * @hdd_ctxt: hdd context pointer + * @level: thermal level + * + * Change IPA data path to SW path when the thermal throttle level greater + * than 0, and restore the original data path when throttle level is 0 + * + * Return: none + */ +static void hdd_set_thermal_level_cb(hdd_context_t *hdd_ctx, u_int8_t level) +{ + /* Change IPA to SW path when throttle level greater than 0 */ + if (level > THROTTLE_LEVEL_0) + hdd_ipa_send_mcc_scc_msg(hdd_ctx, true); + else + /* restore original concurrency mode */ + hdd_ipa_send_mcc_scc_msg(hdd_ctx, hdd_ctx->mcc_mode); +} + +/** + * hdd_find_prefd_safe_chnl() - find safe channel within preferred channel + * @hdd_ctxt: hdd context pointer + * @ap_adapter: hdd hostapd adapter pointer + * + * Try to find safe channel within preferred channel + * In case auto channel selection enabled + * - Preferred and safe channel should be used + * - If no overlapping, preferred channel should be used + * + * Return: 1: found preferred safe channel + * 0: could not found preferred safe channel + */ +static uint8_t hdd_find_prefd_safe_chnl(hdd_context_t *hdd_ctxt, + hdd_adapter_t *ap_adapter) +{ + uint16_t safe_channels[NUM_20MHZ_RF_CHANNELS]; + uint16_t safe_channel_count; + uint16_t unsafe_channel_count; + uint8_t is_unsafe = 1; + uint16_t i; + uint16_t channel_loop; + + if (!hdd_ctxt || !ap_adapter) { + hdd_err("invalid context/adapter"); + return 0; + } + + safe_channel_count = 0; + unsafe_channel_count = CDF_MIN((uint16_t)hdd_ctxt->unsafe_channel_count, + (uint16_t)NUM_20MHZ_RF_CHANNELS); + + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + is_unsafe = 0; + for (channel_loop = 0; + channel_loop < unsafe_channel_count; channel_loop++) { + if (rf_channels[i].channelNum == + hdd_ctxt->unsafe_channel_list[channel_loop]) { + is_unsafe = 1; + break; + } + } + if (!is_unsafe) { + safe_channels[safe_channel_count] = + rf_channels[i].channelNum; + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("safe channel %d"), + safe_channels[safe_channel_count]); + safe_channel_count++; + } + } + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("perferred range %d - %d"), + ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch, + ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch); + for (i = 0; i < safe_channel_count; i++) { + if (safe_channels[i] >= + ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch + && safe_channels[i] <= + ap_adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch) { + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("safe channel %d is in perferred range"), + safe_channels[i]); + return 1; + } + } + return 0; +} + +/** + * hdd_ch_avoid_cb() - Avoid notified channels from FW handler + * @adapter: HDD adapter pointer + * @indParam: Channel avoid notification parameter + * + * Avoid channel notification from FW handler. + * FW will send un-safe channel list to avoid over wrapping. + * hostapd should not use notified channel + * + * Return: None + */ +static void hdd_ch_avoid_cb(void *hdd_context, void *indi_param) +{ + hdd_adapter_t *hostapd_adapter = NULL; + hdd_context_t *hdd_ctxt; + tSirChAvoidIndType *ch_avoid_indi; + uint8_t range_loop; + eRfChannels channel_loop, start_channel_idx = INVALID_RF_CHANNEL, + end_channel_idx = INVALID_RF_CHANNEL; + uint16_t start_channel; + uint16_t end_channel; + v_CONTEXT_t cds_context; + static int restart_sap_in_progress; + tHddAvoidFreqList hdd_avoid_freq_list; + uint32_t i; + + /* Basic sanity */ + if (!hdd_context || !indi_param) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid arguments")); + return; + } + + hdd_ctxt = (hdd_context_t *) hdd_context; + ch_avoid_indi = (tSirChAvoidIndType *) indi_param; + cds_context = hdd_ctxt->pcds_context; + + /* Make unsafe channel list */ + hddLog(CDF_TRACE_LEVEL_INFO, + FL("band count %d"), + ch_avoid_indi->avoid_range_count); + + /* generate vendor specific event */ + cdf_mem_zero((void *)&hdd_avoid_freq_list, sizeof(tHddAvoidFreqList)); + for (i = 0; i < ch_avoid_indi->avoid_range_count; i++) { + hdd_avoid_freq_list.avoidFreqRange[i].startFreq = + ch_avoid_indi->avoid_freq_range[i].start_freq; + hdd_avoid_freq_list.avoidFreqRange[i].endFreq = + ch_avoid_indi->avoid_freq_range[i].end_freq; + } + hdd_avoid_freq_list.avoidFreqRangeCount = + ch_avoid_indi->avoid_range_count; + + wlan_hdd_send_avoid_freq_event(hdd_ctxt, &hdd_avoid_freq_list); + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + cdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + + for (range_loop = 0; range_loop < ch_avoid_indi->avoid_range_count; + range_loop++) { + if (hdd_ctxt->unsafe_channel_count >= NUM_20MHZ_RF_CHANNELS) { + hddLog(LOGW, FL("LTE Coex unsafe channel list full")); + break; + } + + start_channel = ieee80211_frequency_to_channel( + ch_avoid_indi->avoid_freq_range[range_loop].start_freq); + end_channel = ieee80211_frequency_to_channel( + ch_avoid_indi->avoid_freq_range[range_loop].end_freq); + hddLog(LOG1, "%s : start %d : %d, end %d : %d", __func__, + ch_avoid_indi->avoid_freq_range[range_loop].start_freq, + start_channel, + ch_avoid_indi->avoid_freq_range[range_loop].end_freq, + end_channel); + + /* do not process frequency bands that are not mapped to + * predefined channels + */ + if (start_channel == 0 || end_channel == 0) + continue; + + for (channel_loop = MIN_20MHZ_RF_CHANNEL; channel_loop <= + MAX_20MHZ_RF_CHANNEL; channel_loop++) { + if (rf_channels[channel_loop].targetFreq >= + ch_avoid_indi->avoid_freq_range[ + range_loop].start_freq) { + start_channel_idx = channel_loop; + break; + } + } + for (channel_loop = MIN_20MHZ_RF_CHANNEL; channel_loop <= + MAX_20MHZ_RF_CHANNEL; channel_loop++) { + if (rf_channels[channel_loop].targetFreq >= + ch_avoid_indi->avoid_freq_range[ + range_loop].end_freq) { + end_channel_idx = channel_loop; + if (rf_channels[channel_loop].targetFreq > + ch_avoid_indi->avoid_freq_range[ + range_loop].end_freq) + end_channel_idx--; + break; + } + } + + if (start_channel_idx == INVALID_RF_CHANNEL || + end_channel_idx == INVALID_RF_CHANNEL) + continue; + + for (channel_loop = start_channel_idx; channel_loop <= + end_channel_idx; channel_loop++) { + hdd_ctxt->unsafe_channel_list[ + hdd_ctxt->unsafe_channel_count++] = + rf_channels[channel_loop].channelNum; + if (hdd_ctxt->unsafe_channel_count >= + NUM_20MHZ_RF_CHANNELS) { + hddLog(LOGW, FL("LTECoex unsafe ch list full")); + break; + } + } + } + + hddLog(CDF_TRACE_LEVEL_INFO, + FL("number of unsafe channels is %d "), + hdd_ctxt->unsafe_channel_count); + + if (cnss_set_wlan_unsafe_channel(hdd_ctxt->unsafe_channel_list, + hdd_ctxt->unsafe_channel_count)) { + hdd_err("Failed to set unsafe channel"); + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + cdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + + return; + } + + for (channel_loop = 0; + channel_loop < hdd_ctxt->unsafe_channel_count; channel_loop++) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("channel %d is not safe "), + hdd_ctxt->unsafe_channel_list[channel_loop]); + } + + /* + * If auto channel select is enabled + * preferred channel is in safe channel, + * re-start softap interface with safe channel. + * no overlap with preferred channel and safe channel + * do not re-start softap interface + * stay current operating channel. + */ + if (hdd_ctxt->unsafe_channel_count) { + hostapd_adapter = hdd_get_adapter(hdd_ctxt, WLAN_HDD_SOFTAP); + if (hostapd_adapter) { + if ((hostapd_adapter->sessionCtx.ap.sapConfig. + acs_cfg.acs_mode) && + (!hdd_find_prefd_safe_chnl(hdd_ctxt, + hostapd_adapter))) + return; + + hddLog(CDF_TRACE_LEVEL_INFO, + FL( + "Current operation channel %d, sessionCtx.ap.sapConfig.channel %d" + ), + hostapd_adapter->sessionCtx.ap. + operatingChannel, + hostapd_adapter->sessionCtx.ap.sapConfig. + channel); + for (channel_loop = 0; + channel_loop < hdd_ctxt->unsafe_channel_count; + channel_loop++) { + if (((hdd_ctxt-> + unsafe_channel_list[channel_loop] == + hostapd_adapter->sessionCtx.ap. + operatingChannel)) && + (hostapd_adapter->sessionCtx.ap. + sapConfig.acs_cfg.acs_mode + == true) && + !restart_sap_in_progress) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("Restarting SAP")); + wlan_hdd_send_svc_nlink_msg + (WLAN_SVC_LTE_COEX_IND, NULL, 0); + restart_sap_in_progress = 1; + /* + * current operating channel is un-safe + * channel, restart driver + */ + hdd_hostapd_stop(hostapd_adapter->dev); + break; + } + } + } + } + return; +} + +/** + * hdd_init_channel_avoidance() - Initialize channel avoidance + * @hdd_ctx: HDD global context + * + * Initialize the channel avoidance logic by retrieving the unsafe + * channel list from the CNSS platform driver and plumbing the data + * down to the lower layers. Then subscribe to subsequent channel + * avoidance events. + * + * Return: None + */ +static void hdd_init_channel_avoidance(hdd_context_t *hdd_ctx) +{ + uint16_t unsafe_channel_count; + int index; + + cnss_get_wlan_unsafe_channel(hdd_ctx->unsafe_channel_list, + &(hdd_ctx->unsafe_channel_count), + sizeof(uint16_t) * NUM_20MHZ_RF_CHANNELS); + + hddLog(CDF_TRACE_LEVEL_INFO, FL("num of unsafe channels is %d"), + hdd_ctx->unsafe_channel_count); + + unsafe_channel_count = CDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, + (uint16_t)NUM_20MHZ_RF_CHANNELS); + + for (index = 0; index < unsafe_channel_count; index++) { + hddLog(CDF_TRACE_LEVEL_INFO, FL("channel %d is not safe"), + hdd_ctx->unsafe_channel_list[index]); + + } + + /* Plug in avoid channel notification callback */ + sme_add_ch_avoid_callback(hdd_ctx->hHal, hdd_ch_avoid_cb); +} +#else +static void hdd_init_channel_avoidance(hdd_context_t *hdd_ctx) +{ +} +static void hdd_set_thermal_level_cb(hdd_context_t *hdd_ctx, u_int8_t level) +{ +} +#endif /* defined(FEATURE_WLAN_CH_AVOID) && defined(CONFIG_CNSS) */ + +/** + * wlan_hdd_disable_all_dual_mac_features() - Disable dual mac features + * @hdd_ctx: HDD context + * + * Disables all the dual mac features like DBS, Agile DFS etc. + * + * Return: CDF_STATUS_SUCCESS on success + */ +static CDF_STATUS wlan_hdd_disable_all_dual_mac_features(hdd_context_t *hdd_ctx) +{ + struct sir_dual_mac_config cfg; + CDF_STATUS status; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return CDF_STATUS_E_FAILURE; + } + + cfg.scan_config = 0; + cfg.fw_mode_config = 0; + cfg.set_dual_mac_cb = + (void *)cds_soc_set_dual_mac_cfg_cb; + + hdd_debug("Disabling all dual mac features..."); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != CDF_STATUS_SUCCESS) { + hdd_err("sme_soc_set_dual_mac_config failed %d", status); + return status; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wlan_startup() - HDD init function + * @dev: Pointer to the underlying device + * + * This is the driver startup code executed once a WLAN device has been detected + * + * Return: 0 for success, < 0 for failure + */ +int hdd_wlan_startup(struct device *dev, void *hif_sc) +{ + CDF_STATUS status; + hdd_adapter_t *adapter = NULL; +#ifdef WLAN_OPEN_P2P_INTERFACE + hdd_adapter_t *pP2adapter = NULL; +#endif + hdd_context_t *hdd_ctx = NULL; + v_CONTEXT_t p_cds_context = NULL; + int ret; + int i; + struct wiphy *wiphy; + unsigned long rc; + tSmeThermalParams thermalParam; + tSirTxPowerLimit *hddtxlimit; + uint8_t rtnl_lock_enable; + uint8_t reg_netdev_notifier_done = false; + hdd_adapter_t *dot11_adapter = NULL; + + ENTER(); + + if (WLAN_IS_EPPING_ENABLED(con_mode)) { + ret = epping_enable(dev); + EXIT(); + return ret; + } + + /* cfg80211: wiphy allocation */ + wiphy = wlan_hdd_cfg80211_wiphy_alloc(sizeof(hdd_context_t)); + + if (wiphy == NULL) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("cfg80211 init failed")); + return -EIO; + } + + hdd_ctx = wiphy_priv(wiphy); + + /* Initialize the adapter context to zeros. */ + cdf_mem_zero(hdd_ctx, sizeof(hdd_context_t)); + + hdd_ctx->wiphy = wiphy; + hdd_ctx->isLoadInProgress = true; + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + cds_set_wakelock_logging(false); + + cds_set_load_unload_in_progress(true); + + /* Get cds context here bcoz cds_open requires it */ + p_cds_context = cds_get_global_context(); + + if (p_cds_context == NULL) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed cds_get_global_context")); + goto err_free_hdd_context; + } + /* Save the Global CDS context in adapter context for future. */ + hdd_ctx->pcds_context = p_cds_context; + + /* Save the adapter context in global context for future. */ + ((cds_context_type *) (p_cds_context))->pHDDContext = (void *)hdd_ctx; + + hdd_ctx->parent_dev = dev; + + hdd_init_ll_stats_ctx(); + + init_completion(&hdd_ctx->mc_sus_event_var); + init_completion(&hdd_ctx->ready_to_suspend); + + spin_lock_init(&hdd_ctx->schedScan_lock); + + cdf_spinlock_init(&hdd_ctx->hdd_adapter_lock); + cdf_list_init(&hdd_ctx->hddAdapters, MAX_NUMBER_OF_ADAPTERS); + + wlan_hdd_cfg80211_extscan_init(hdd_ctx); + +#ifdef FEATURE_WLAN_TDLS + /* + * tdls_lock is initialized before an hdd_open_adapter ( which is + * invoked by other instances also) to protect the concurrent + * access for the Adapters by TDLS module. + */ + mutex_init(&hdd_ctx->tdls_lock); +#endif + + /* store target type and target version info in hdd ctx */ + hdd_ctx->target_type = ((struct ol_softc *)hif_sc)->target_type; + hdd_init_offloaded_packets_ctx(hdd_ctx); + /* Load all config first as TL config is needed during cds_open */ + hdd_ctx->config = + (struct hdd_config *) kmalloc(sizeof(struct hdd_config), GFP_KERNEL); + if (hdd_ctx->config == NULL) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed kmalloc struct hdd_config")); + goto err_config; + } + + cdf_mem_zero(hdd_ctx->config, sizeof(struct hdd_config)); + + /* Read and parse the qcom_cfg.ini file */ + status = hdd_parse_config_ini(hdd_ctx); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("error parsing %s"), + WLAN_INI_FILE); + goto err_config; + } + + hdd_ctx->current_intf_count = 0; + hdd_ctx->max_intf_count = CSR_ROAM_SESSION_MAX; + + /* + * INI has been read, initialise the configuredMcastBcastFilter with + * INI value as this will serve as the default value + */ + hdd_ctx->configuredMcastBcastFilter = + hdd_ctx->config->mcastBcastFilterSetting; + hddLog(CDF_TRACE_LEVEL_INFO, + FL("Setting configuredMcastBcastFilter: %d"), + hdd_ctx->config->mcastBcastFilterSetting); + + if (false == hdd_is_5g_supported(hdd_ctx)) { + /* 5Ghz is not supported. */ + if (1 != hdd_ctx->config->nBandCapability) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL( + "Setting hdd_ctx->config->nBandCapability = 1" + )); + hdd_ctx->config->nBandCapability = 1; + } + } + + /* + * cfg80211: Initialization ... + */ + if (0 < wlan_hdd_cfg80211_init(dev, wiphy, hdd_ctx->config)) { + hddLog(LOGE, + FL("wlan_hdd_cfg80211_init return failure")); + goto err_config; + } + + hdd_enable_fastpath(hdd_ctx->config, hif_sc); + /* + * Initialize struct for saving f/w log setting will be used + * after ssr + */ + hdd_ctx->fw_log_settings.enable = hdd_ctx->config->enablefwlog; + hdd_ctx->fw_log_settings.dl_type = 0; + hdd_ctx->fw_log_settings.dl_report = 0; + hdd_ctx->fw_log_settings.dl_loglevel = 0; + hdd_ctx->fw_log_settings.index = 0; + for (i = 0; i < MAX_MOD_LOGLEVEL; i++) { + hdd_ctx->fw_log_settings.dl_mod_loglevel[i] = 0; + } + /* Update CDF trace levels based upon the cfg.ini */ + hdd_cdf_trace_enable(CDF_MODULE_ID_WMI, + hdd_ctx->config->cdf_trace_enable_wdi); + hdd_cdf_trace_enable(CDF_MODULE_ID_HDD, + hdd_ctx->config->cdf_trace_enable_hdd); + hdd_cdf_trace_enable(CDF_MODULE_ID_SME, + hdd_ctx->config->cdf_trace_enable_sme); + hdd_cdf_trace_enable(CDF_MODULE_ID_PE, + hdd_ctx->config->cdf_trace_enable_pe); + hdd_cdf_trace_enable(CDF_MODULE_ID_WMA, + hdd_ctx->config->cdf_trace_enable_wma); + hdd_cdf_trace_enable(CDF_MODULE_ID_SYS, + hdd_ctx->config->cdf_trace_enable_sys); + hdd_cdf_trace_enable(CDF_MODULE_ID_CDF, + hdd_ctx->config->cdf_trace_enable_cdf); + hdd_cdf_trace_enable(CDF_MODULE_ID_SAP, + hdd_ctx->config->cdf_trace_enable_sap); + hdd_cdf_trace_enable(CDF_MODULE_ID_HDD_SOFTAP, + hdd_ctx->config->cdf_trace_enable_hdd_sap); + hdd_cdf_trace_enable(CDF_MODULE_ID_BMI, + hdd_ctx->config->cdf_trace_enable_bmi); + hdd_cfg_print(hdd_ctx); + + if (CDF_FTM_MODE == hdd_get_conparam()) + goto ftm_processing; + + hdd_ctx->isLogpInProgress = false; + cds_set_logp_in_progress(false); + + cds_set_connection_in_progress(hdd_ctx, false); + + status = cds_open(&p_cds_context, 0); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("cds_open failed")); + goto err_cds_open; + } + + wlan_hdd_update_wiphy(wiphy, hdd_ctx->config); + + hdd_ctx->hHal = cds_get_context(CDF_MODULE_ID_SME); + + if (NULL == hdd_ctx->hHal) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("HAL context is null")); + goto err_cds_close; + } + + status = cds_pre_enable(hdd_ctx->pcds_context); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("cds_pre_enable failed")); + goto err_cds_close; + } + + ol_txrx_register_pause_cb(wlan_hdd_txrx_pause_cb); + + status = wlan_hdd_regulatory_init(hdd_ctx); + + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to init channel list")); + goto err_cds_close; + } + + /* + * Set 802.11p config + * TODO-OCB: This has been temporarily added here to ensure this + * parameter is set in CSR when we init the channel list. This should + * be removed once the 5.9 GHz channels are added to the regulatory + * domain. + */ + hdd_set_dot11p_config(hdd_ctx); + + if (0 == enable_dfs_chan_scan || 1 == enable_dfs_chan_scan) { + hdd_ctx->config->enableDFSChnlScan = enable_dfs_chan_scan; + hddLog(CDF_TRACE_LEVEL_INFO, + FL("module enable_dfs_chan_scan set to %d"), + enable_dfs_chan_scan); + } + if (0 == enable_11d || 1 == enable_11d) { + hdd_ctx->config->Is11dSupportEnabled = enable_11d; + hddLog(CDF_TRACE_LEVEL_INFO, FL("module enable_11d set to %d"), + enable_11d); + } + + /* + * Note that the cds_pre_enable() sequence triggers the cfg download. + * The cfg download must occur before we update the SME config + * since the SME config operation must access the cfg database + */ + status = hdd_set_sme_config(hdd_ctx); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("Failed hdd_set_sme_config")); + goto err_wiphy_unregister; + } + + ret = wma_cli_set_command(0, WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS, + hdd_ctx->config->tx_chain_mask_1ss, + PDEV_CMD); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS failed %d", + __func__, ret); + } + + status = hdd_set_sme_chan_list(hdd_ctx); + if (status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to init channel list")); + goto err_wiphy_unregister; + } + + /* Apply the cfg.ini to cfg.dat */ + if (false == hdd_update_config_dat(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("config update failed")); + goto err_wiphy_unregister; + } + + if (CDF_STATUS_SUCCESS != hdd_update_mac_config(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_WARN, + FL("can't update mac config, using MAC from ini file")); + } + + { + CDF_STATUS cdf_ret_status; + /* + * Set the MAC Address Currently this is used by HAL to + * add self sta. Remove this once self sta is added as + * part of session open. + */ + cdf_ret_status = cfg_set_str(hdd_ctx->hHal, WNI_CFG_STA_ID, + (uint8_t *) &hdd_ctx->config-> + intfMacAddr[0], + sizeof(hdd_ctx->config-> + intfMacAddr[0])); + + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "Failed to set MAC Address. HALStatus is %08d [x%08x]" + ), + cdf_ret_status, cdf_ret_status); + goto err_wiphy_unregister; + } + } + + if (hdd_ipa_init(hdd_ctx) == CDF_STATUS_E_FAILURE) + goto err_wiphy_unregister; + + /* + * Start CDS which starts up the SME/MAC/HAL modules and everything + * else + */ + status = cds_enable(hdd_ctx->pcds_context); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("cds_enable failed")); + goto err_wiphy_unregister; + } + + hdd_init_channel_avoidance(hdd_ctx); + + status = hdd_post_cds_enable_config(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("hdd_post_cds_enable_config failed")); + goto err_cds_disable; + } +#ifdef QCA_PKT_PROTO_TRACE + cds_pkt_proto_trace_init(); +#endif /* QCA_PKT_PROTO_TRACE */ + +ftm_processing: + if (CDF_FTM_MODE == hdd_get_conparam()) { + if (CDF_STATUS_SUCCESS != wlan_hdd_ftm_open(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("wlan_hdd_ftm_open Failed")); + goto err_config; + } +#if defined(QCA_WIFI_FTM) + if (hdd_ftm_start(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("hdd_ftm_start Failed")); + goto err_free_ftm_open; + } +#endif + /* registration of wiphy dev with cfg80211 */ + if (0 > wlan_hdd_cfg80211_register(wiphy)) { + hddLog(LOGE, FL("wiphy register failed")); + goto err_free_ftm_open; + } + + cds_set_load_unload_in_progress(false); + hdd_ctx->isLoadInProgress = false; + hddLog(LOGE, FL("FTM driver loaded")); + complete(&wlan_start_comp); + return CDF_STATUS_SUCCESS; + } +#if defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) + rtnl_lock(); + rtnl_lock_enable = true; +#else + rtnl_lock_enable = false; +#endif + + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_STANDALONE) + /* Create only 802.11p interface */ + adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_OCB, "wlanocb%d", + wlan_hdd_get_intf_addr(hdd_ctx), + rtnl_lock_enable); + else + adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_INFRA_STATION, + "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), + rtnl_lock_enable); + +#ifdef WLAN_OPEN_P2P_INTERFACE + /* Open P2P device interface */ + if (adapter != NULL) { + if (hdd_ctx->config->isP2pDeviceAddrAdministrated && + !(hdd_ctx->config->intfMacAddr[0].bytes[0] & 0x02)) { + cdf_mem_copy(hdd_ctx->p2pDeviceAddress.bytes, + hdd_ctx->config->intfMacAddr[0].bytes, + sizeof(tSirMacAddr)); + + /* + * Generate the P2P Device Address. This consists of + * the device's primary MAC address with the locally + * administered bit set. + */ + hdd_ctx->p2pDeviceAddress.bytes[0] |= 0x02; + } else { + uint8_t *p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx); + if (p2p_dev_addr != NULL) { + cdf_mem_copy(&hdd_ctx->p2pDeviceAddress. + bytes[0], p2p_dev_addr, + CDF_MAC_ADDR_SIZE); + } else { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "Failed to allocate mac_address for p2p_device" + )); + goto err_close_adapter; + } + } + + pP2adapter = + hdd_open_adapter(hdd_ctx, WLAN_HDD_P2P_DEVICE, "p2p%d", + &hdd_ctx->p2pDeviceAddress.bytes[0], + rtnl_lock_enable); + + if (NULL == pP2adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "Failed to do hdd_open_adapter for P2P Device Interface" + )); + goto err_close_adapter; + } + } +#endif + + if (adapter == NULL) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("hdd_open_adapter failed")); + goto err_close_adapter; + } + + /* Open 802.11p Interface */ + if (adapter != NULL) { + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_CONCURRENT) { + dot11_adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_OCB, + "wlanocb%d", + wlan_hdd_get_intf_addr(hdd_ctx), + rtnl_lock_enable); + if (dot11_adapter == NULL) { + hddLog(LOGE, + FL("failed to open 802.11p Interface")); + goto err_close_adapter; + } + } + } + + /* + * target hw version/revision would only be retrieved after firmware + * donwload + */ + hif_get_hw_info(hif_sc, &hdd_ctx->target_hw_version, + &hdd_ctx->target_hw_revision, + &hdd_ctx->target_hw_name); + + /* Get the wlan hw/fw version */ + hdd_wlan_get_version(adapter, NULL, NULL); + + /* pass target_fw_version to HIF layer */ + hif_set_fw_info(hif_sc, hdd_ctx->target_fw_version); + + if (country_code) { + CDF_STATUS ret; + + INIT_COMPLETION(adapter->change_country_code); + + ret = sme_change_country_code(hdd_ctx->hHal, + wlan_hdd_change_country_code_callback, + country_code, adapter, + hdd_ctx->pcds_context, eSIR_TRUE, + eSIR_TRUE); + if (CDF_STATUS_SUCCESS == ret) { + rc = wait_for_completion_timeout( + &adapter->change_country_code, + msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY)); + if (!rc) { + hddLog(LOGE, + FL("SME while setting country code timed out")); + } + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL( + "SME Change Country code from module param fail ret=%d" + ), + ret); + ret = -EINVAL; + } + } + + sme_register11d_scan_done_callback(hdd_ctx->hHal, hdd_11d_scan_done); + +#ifdef FEATURE_OEM_DATA_SUPPORT + sme_register_oem_data_rsp_callback(hdd_ctx->hHal, + hdd_send_oem_data_rsp_msg); +#endif + + /* Open debugfs interface */ + if (CDF_STATUS_SUCCESS != hdd_debugfs_init(adapter)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("hdd_debugfs_init failed!")); + } + + /* FW capabilities received, Set the Dot11 mode */ + sme_setdef_dot11mode(hdd_ctx->hHal); +#if !defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) + /* register net device notifier for device change notification */ + ret = register_netdevice_notifier(&hdd_netdev_notifier); + + if (ret < 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("register_netdevice_notifier failed")); + goto err_free_power_on_lock; + } + reg_netdev_notifier_done = true; +#endif + /* Initialize the nlink service */ + if (nl_srv_init() != 0) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("nl_srv_init failed")); + goto err_reg_netdev; + } +#ifdef WLAN_KD_READY_NOTIFIER + hdd_ctx->kd_nl_init = 1; +#endif /* WLAN_KD_READY_NOTIFIER */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + /* Initialize the OEM service */ + if (oem_activate_service(hdd_ctx) != 0) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("oem_activate_service failed")); + goto err_nl_srv; + } +#endif + +#ifdef PTT_SOCK_SVC_ENABLE + /* Initialize the PTT service */ + if (ptt_sock_activate_svc() != 0) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("ptt_sock_activate_svc failed")); + goto err_nl_srv; + } +#endif + + /* Initialize the CNSS-DIAG service */ + if (cnss_diag_activate_service() < 0) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("cnss_diag_activate_service failed")); + goto err_nl_srv; + } +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + if (hdd_ctx->config->wlanLoggingEnable) { + if (wlan_logging_sock_activate_svc + (hdd_ctx->config->wlanLoggingFEToConsole, + hdd_ctx->config->wlanLoggingNumBuf)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("wlan_logging_sock_activate_svc failed")); + goto err_nl_srv; + } + } +#endif + if (cds_is_multicast_logging()) + wlan_logging_set_log_level(); + + if (CDF_SAP_MODE != hdd_get_conparam()) { + /* + * Action frame registered in one adapter which will + * applicable to all interfaces + */ + wlan_hdd_cfg80211_register_frames(adapter); + } + + mutex_init(&hdd_ctx->sap_lock); + + hdd_ctx->isLoadInProgress = false; + +#if defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) + if (rtnl_lock_enable == true) { + rtnl_lock_enable = false; + rtnl_unlock(); + } + ret = register_netdevice_notifier(&hdd_netdev_notifier); + if (ret < 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("register_netdevice_notifier failed")); + goto err_nl_srv; + } + reg_netdev_notifier_done = true; +#endif +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK + /* Initialize the wake lcok */ + cdf_wake_lock_init(&hdd_ctx->rx_wake_lock, "qcom_rx_wakelock"); +#endif + /* Initialize the wake lcok */ + cdf_wake_lock_init(&hdd_ctx->sap_wake_lock, "qcom_sap_wakelock"); + + hdd_hostapd_channel_wakelock_init(hdd_ctx); + + cds_set_load_unload_in_progress(false); + + hdd_set_idle_ps_config(hdd_ctx, true); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + if (hdd_ctx->config->WlanAutoShutdown != 0) + if (sme_set_auto_shutdown_cb + (hdd_ctx->hHal, wlan_hdd_auto_shutdown_cb) + != CDF_STATUS_SUCCESS) + hddLog(LOGE, + FL( + "Auto shutdown feature could not be enabled" + )); +#endif + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + status = cdf_mc_timer_init(&hdd_ctx->skip_acs_scan_timer, + CDF_TIMER_TYPE_SW, + hdd_skip_acs_scan_timer_handler, + (void *)hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) + hddLog(LOGE, FL("Failed to init ACS Skip timer")); +#endif + + hdd_wlan_green_ap_init(hdd_ctx); + wlan_hdd_nan_init(hdd_ctx); + status = cds_init_policy_mgr(hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Policy manager initialization failed"); + goto err_nl_srv; + } + + /* Thermal Mitigation */ + thermalParam.smeThermalMgmtEnabled = + hdd_ctx->config->thermalMitigationEnable; + thermalParam.smeThrottlePeriod = hdd_ctx->config->throttlePeriod; + + thermalParam.smeThermalLevels[0].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel0; + thermalParam.smeThermalLevels[0].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel0; + thermalParam.smeThermalLevels[1].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel1; + thermalParam.smeThermalLevels[1].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel1; + thermalParam.smeThermalLevels[2].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel2; + thermalParam.smeThermalLevels[2].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel2; + thermalParam.smeThermalLevels[3].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel3; + thermalParam.smeThermalLevels[3].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel3; + + if (0 != hdd_lro_init(hdd_ctx)) + hdd_err("Unable to initialize LRO in fw"); + + if (CDF_STATUS_SUCCESS != + sme_init_thermal_info(hdd_ctx->hHal, thermalParam)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Error while initializing thermal information")); + } + + /* Plug in set thermal level callback */ + sme_add_set_thermal_level_callback(hdd_ctx->hHal, + (sme_set_thermal_level_callback)hdd_set_thermal_level_cb); + + /* SAR power limit */ + hddtxlimit = cdf_mem_malloc(sizeof(tSirTxPowerLimit)); + if (!hddtxlimit) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation for TxPowerLimit failed!")); + goto err_nl_srv; + } + hddtxlimit->txPower2g = hdd_ctx->config->TxPower2g; + hddtxlimit->txPower5g = hdd_ctx->config->TxPower5g; + + if (CDF_STATUS_SUCCESS != sme_txpower_limit(hdd_ctx->hHal, hddtxlimit)) + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Error setting txlimit in sme")); + +#ifdef MSM_PLATFORM + spin_lock_init(&hdd_ctx->bus_bw_lock); + cdf_mc_timer_init(&hdd_ctx->bus_bw_timer, + CDF_TIMER_TYPE_SW, + hdd_bus_bw_compute_cbk, (void *)hdd_ctx); +#endif + +#ifdef WLAN_FEATURE_STATS_EXT + wlan_hdd_cfg80211_stats_ext_init(hdd_ctx); +#endif +#ifdef FEATURE_WLAN_EXTSCAN + sme_ext_scan_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_extscan_callback); +#endif /* FEATURE_WLAN_EXTSCAN */ + sme_set_rssi_threshold_breached_cb(hdd_ctx->hHal, + hdd_rssi_threshold_breached); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + wlan_hdd_cfg80211_link_layer_stats_init(hdd_ctx); +#endif + +#ifdef WLAN_FEATURE_LPSS + wlan_hdd_send_all_scan_intf_info(hdd_ctx); + wlan_hdd_send_version_pkg(hdd_ctx->target_fw_version, + hdd_ctx->target_hw_version, + hdd_ctx->target_hw_name); +#endif + + cdf_spinlock_init(&hdd_ctx->hdd_roc_req_q_lock); + cdf_list_init((&hdd_ctx->hdd_roc_req_q), MAX_ROC_REQ_QUEUE_ENTRY); + cdf_spinlock_init(&hdd_ctx->hdd_scan_req_q_lock); + cdf_list_init((&hdd_ctx->hdd_scan_req_q), CFG_MAX_SCAN_COUNT_MAX); +#ifdef CONFIG_CNSS + cnss_init_delayed_work(&hdd_ctx->roc_req_work, + wlan_hdd_roc_request_dequeue); +#else + INIT_DELAYED_WORK(&hdd_ctx->roc_req_work, wlan_hdd_roc_request_dequeue); +#endif + + /* + * Register IPv6 notifier to notify if any change in IP + * So that we can reconfigure the offload parameters + */ + hdd_wlan_register_ip6_notifier(hdd_ctx); + + /* + * Register IPv4 notifier to notify if any change in IP + * So that we can reconfigure the offload parameters + */ + hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed; + ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier); + if (ret) + hddLog(LOGE, FL("Failed to register IPv4 notifier")); + else + hddLog(LOGE, FL("Registered IPv4 notifier")); + + wlan_hdd_dcc_register_for_dcc_stats_event(hdd_ctx); + + if (hdd_ctx->config->dual_mac_feature_disable) { + status = wlan_hdd_disable_all_dual_mac_features(hdd_ctx); + if (status != CDF_STATUS_SUCCESS) { + hdd_err("Failed to disable dual mac features"); + goto err_nl_srv; + } + } + + hif_enable_power_gating(hif_sc); + + complete(&wlan_start_comp); + goto success; + +err_nl_srv: +#ifdef WLAN_KD_READY_NOTIFIER + cnss_diag_notify_wlan_close(); + ptt_sock_deactivate_svc(); +#endif /* WLAN_KD_READY_NOTIFIER */ + nl_srv_exit(); + + if (!CDF_IS_STATUS_SUCCESS + (cdf_mutex_destroy(&hdd_ctx->hdd_conc_list_lock))) { + hdd_err("Failed to destroy hdd_conc_list_lock"); + /* Proceed and complete the clean up */ + } +err_reg_netdev: + if (rtnl_lock_enable == true) { + rtnl_lock_enable = false; + rtnl_unlock(); + } + if (reg_netdev_notifier_done == true) { + unregister_netdevice_notifier(&hdd_netdev_notifier); + reg_netdev_notifier_done = false; + } +#if !defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) +err_free_power_on_lock: +#endif + hdd_debugfs_exit(hdd_ctx); + +err_close_adapter: +#if defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) + if (rtnl_lock_enable == true) { + rtnl_lock_enable = false; + rtnl_unlock(); + } +#endif + hdd_close_all_adapters(hdd_ctx); + +err_cds_disable: + cds_disable(p_cds_context); + +err_wiphy_unregister: + wiphy_unregister(wiphy); + +err_cds_close: + status = cds_sched_close(p_cds_context); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to close CDS Scheduler")); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(status)); + } + cds_close(p_cds_context); + +err_cds_open: + + if (CDF_FTM_MODE == hdd_get_conparam()) { +#if defined(QCA_WIFI_FTM) +err_free_ftm_open: + wlan_hdd_ftm_close(hdd_ctx); +#endif + } + +err_config: + kfree(hdd_ctx->config); + hdd_ctx->config = NULL; + +err_free_hdd_context: + /* wiphy_free() will free the HDD context so remove global reference */ + if (p_cds_context) + ((cds_context_type *) (p_cds_context))->pHDDContext = NULL; + + wiphy_free(wiphy); + /* kfree(wdev) ; */ + CDF_BUG(1); + + if (hdd_is_ssr_required()) { +#ifdef MSM_PLATFORM +#ifdef CONFIG_CNSS + /* + * WDI timeout had happened during load, so SSR is needed + * here + */ + subsystem_restart("wcnss"); +#endif +#endif + msleep(5000); + } + hdd_set_ssr_required(false); + + return -EIO; + +success: + EXIT(); + return 0; +} + +/* + * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at + * a time, and wait for the completion interrupt to start the next transfer. + * During this phase, the KRAIT is entering IDLE/StandAlone(SA) Power Save(PS). + * The delay incurred for resuming from IDLE/SA PS is huge during driver load. + * So prevent APPS IDLE/SA PS durint driver load for reducing interrupt latency. + */ + +#ifdef CONFIG_CNSS +static inline void hdd_request_pm_qos(int val) +{ + cnss_request_pm_qos(val); +} + +static inline void hdd_remove_pm_qos(void) +{ + cnss_remove_pm_qos(); +} +#else +static inline void hdd_request_pm_qos(int val) +{ +} + +static inline void hdd_remove_pm_qos(void) +{ +} +#endif + +/** + * hdd_driver_init() - Core Driver Init Function + * + * This is the driver entry point - called in different timeline depending + * on whether the driver is statically or dynamically linked + * + * Return: 0 for success, non zero for failure + */ +static int hdd_driver_init(void) +{ + CDF_STATUS status; + v_CONTEXT_t p_cds_context = NULL; + int ret_status = 0; + unsigned long rc; + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_init_svc(); +#endif + + ENTER(); + + cdf_wake_lock_init(&wlan_wake_lock, "wlan"); + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + /* + * The Krait is going to Idle/Stand Alone Power Save + * more aggressively which is resulting in the longer driver load time. + * The Fix is to not allow Krait to enter Idle Power Save during driver + * load. + */ + hdd_request_pm_qos(DISABLE_KRAIT_IDLE_PS_VAL); + cds_ssr_protect_init(); + + pr_info("%s: loading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR); + + do { + cdf_mc_timer_manager_init(); + cdf_mem_init(); + /* Allocate CDS global context */ + status = cds_alloc_global_context(&p_cds_context); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("Failed to preOpen CDS")); + ret_status = -1; + break; + } + + hdd_trace_init(); + +#ifndef MODULE + /* + * For statically linked driver, call hdd_set_conparam to update + * curr_con_mode + */ + hdd_set_conparam((uint32_t) con_mode); +#endif + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define HDD_WLAN_START_WAIT_TIME (3600 * 1000) +#else +#define HDD_WLAN_START_WAIT_TIME (CDS_WMA_TIMEOUT + 5000) +#endif + + init_completion(&wlan_start_comp); + ret_status = wlan_hdd_register_driver(); + if (!ret_status) { + rc = wait_for_completion_timeout( + &wlan_start_comp, + msecs_to_jiffies(HDD_WLAN_START_WAIT_TIME)); + if (!rc) { + hddLog(LOGP, + FL("timed-out waiting for wlan_hdd_register_driver")); + ret_status = -1; + } else + ret_status = 0; + } + + hdd_remove_pm_qos(); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + + if (ret_status) { + hddLog(LOGP, FL("WLAN Driver Initialization failed")); + wlan_hdd_unregister_driver(); + cds_free_global_context(&p_cds_context); + ret_status = -ENODEV; + break; + } else { + pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); + memdump_init(); + return 0; + } + + } while (0); + + if (0 != ret_status) { + cdf_mc_timer_exit(); + cdf_mem_exit(); + cdf_wake_lock_destroy(&wlan_wake_lock); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_deinit_svc(); +#endif + memdump_deinit(); + pr_err("%s: driver load failure\n", WLAN_MODULE_NAME); + } else { + pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); + } + + EXIT(); + + return ret_status; +} + +/** + * hdd_module_init() - Init Function + * + * This is the driver entry point (invoked when module is loaded using insmod) + * + * Return: 0 for success, non zero for failure + */ +#ifdef MODULE +static int __init hdd_module_init(void) +{ + return hdd_driver_init(); +} +#else /* #ifdef MODULE */ +static int __init hdd_module_init(void) +{ + /* Driver initialization is delayed to fwpath_changed_handler */ + return 0; +} +#endif /* #ifdef MODULE */ + +/** + * hdd_driver_exit() - Exit function + * + * This is the driver exit point (invoked when module is unloaded using rmmod + * or con_mode was changed by userspace) + * + * Return: None + */ +static void hdd_driver_exit(void) +{ + hdd_context_t *hdd_ctx = NULL; + int retry = 0; + + pr_info("%s: unloading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("module exit called before probe")); + } else { +#ifdef QCA_PKT_PROTO_TRACE + cds_pkt_proto_trace_close(); +#endif /* QCA_PKT_PROTO_TRACE */ + while (hdd_ctx->isLogpInProgress || + cds_is_logp_in_progress()) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL( + "SSR in Progress; block rmmod for 1 second!!!" + )); + msleep(1000); + + if (retry++ == HDD_MOD_EXIT_SSR_MAX_RETRIES) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL("SSR never completed, fatal error")); + CDF_BUG(0); + } + } + + rtnl_lock(); + hdd_ctx->isUnloadInProgress = true; + cds_set_load_unload_in_progress(true); + rtnl_unlock(); + } + + cds_wait_for_work_thread_completion(__func__); + memdump_deinit(); + + wlan_hdd_unregister_driver(); + return; +} + +/** + * hdd_module_exit() - Exit function + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: None + */ +static void __exit hdd_module_exit(void) +{ + hdd_driver_exit(); +} + +#ifdef MODULE +static int fwpath_changed_handler(const char *kmessage, struct kernel_param *kp) +{ + return param_set_copystring(kmessage, kp); +} + +#if !defined(QCA_WIFI_FTM) +static int con_mode_handler(const char *kmessage, struct kernel_param *kp) +{ + return param_set_int(kmessage, kp); +} +#endif +#else /* #ifdef MODULE */ +/** + * kickstart_driver() - driver entry point + * + * This is the driver entry point + * - delayed driver initialization when driver is statically linked + * - invoked when module parameter fwpath is modified from userspace to signal + * initializing the WLAN driver or when con_mode is modified from userspace + * to signal a switch in operating mode + * + * Return: 0 for success, non zero for failure + */ +static int kickstart_driver(void) +{ + int ret_status; + + if (!wlan_hdd_inited) { + ret_status = hdd_driver_init(); + wlan_hdd_inited = ret_status ? 0 : 1; + return ret_status; + } + + hdd_driver_exit(); + + msleep(200); + + ret_status = hdd_driver_init(); + wlan_hdd_inited = ret_status ? 0 : 1; + return ret_status; +} + +/** + * fwpath_changed_handler() - Handler Function + * + * Handle changes to the fwpath parameter + * + * Return: 0 for success, non zero for failure + */ +static int fwpath_changed_handler(const char *kmessage, struct kernel_param *kp) +{ + int ret; + + ret = param_set_copystring(kmessage, kp); + if (0 == ret) + ret = kickstart_driver(); + return ret; +} + +#if !defined(QCA_WIFI_FTM) +/** + * con_mode_handler() - handls module param con_mode change + * + * Handler function for module param con_mode when it is changed by userspace + * Dynamically linked - do nothing + * Statically linked - exit and init driver, as in rmmod and insmod + * + * Return - + */ +static int con_mode_handler(const char *kmessage, struct kernel_param *kp) +{ + int ret; + + ret = param_set_int(kmessage, kp); + if (0 == ret) + ret = kickstart_driver(); + return ret; +} +#endif +#endif /* #ifdef MODULE */ + +/** + * hdd_get_conparam() - driver exit point + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: tCDF_CON_MODE + */ +tCDF_CON_MODE hdd_get_conparam(void) +{ +#ifdef MODULE + return (tCDF_CON_MODE) con_mode; +#else + return (tCDF_CON_MODE) curr_con_mode; +#endif +} + +void hdd_set_conparam(uint32_t newParam) +{ + con_mode = newParam; +#ifndef MODULE + curr_con_mode = con_mode; +#endif +} + +/** + * hdd_softap_sta_deauth() - handle deauth req from HDD + * @adapter: Pointer to the HDD + * @enable: bool value + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +CDF_STATUS hdd_softap_sta_deauth(hdd_adapter_t *adapter, + struct tagCsrDelStaParams *pDelStaParams) +{ +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(adapter))->pcds_context; +#endif + CDF_STATUS cdf_status = CDF_STATUS_E_FAULT; + + ENTER(); + + hddLog(LOG1, FL("hdd_softap_sta_deauth:(%p, false)"), + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + + /* Ignore request to deauth bcmc station */ + if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) + return cdf_status; + +#ifdef WLAN_FEATURE_MBSSID + cdf_status = + wlansap_deauth_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDelStaParams); +#else + cdf_status = wlansap_deauth_sta(p_cds_context, pDelStaParams); +#endif + + EXIT(); + return cdf_status; +} + +/** + * hdd_softap_sta_disassoc() - take counter measure to handle deauth req from HDD + * @adapter: Pointer to the HDD + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +void hdd_softap_sta_disassoc(hdd_adapter_t *adapter, + uint8_t *pDestMacAddress) +{ +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(adapter))->pcds_context; +#endif + + ENTER(); + + hddLog(LOGE, FL("hdd_softap_sta_disassoc:(%p, false)"), + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + + /* Ignore request to disassoc bcmc station */ + if (pDestMacAddress[0] & 0x1) + return; + +#ifdef WLAN_FEATURE_MBSSID + wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDestMacAddress); +#else + wlansap_disassoc_sta(p_cds_context, pDestMacAddress); +#endif +} + +void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *adapter, + bool enable) +{ +#ifndef WLAN_FEATURE_MBSSID + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(adapter))->pcds_context; +#endif + + ENTER(); + + hddLog(LOGE, FL("hdd_softap_tkip_mic_fail_counter_measure:(%p, false)"), + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + +#ifdef WLAN_FEATURE_MBSSID + wlansap_set_counter_measure(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + (bool) enable); +#else + wlansap_set_counter_measure(p_cds_context, (bool) enable); +#endif +} + +/** + * hdd_issta_p2p_clientconnected() - check if sta or p2p client is connected + * @hdd_ctx: HDD Context + * + * API to find if there is any STA or P2P-Client is connected + * + * Return: true if connected; false otherwise + */ +CDF_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *hdd_ctx) +{ + return sme_is_sta_p2p_client_connected(hdd_ctx->hHal); +} + +#ifdef WLAN_FEATURE_LPSS +int wlan_hdd_gen_wlan_status_pack(struct wlan_status_data *data, + hdd_adapter_t *adapter, + hdd_station_ctx_t *pHddStaCtx, + uint8_t is_on, uint8_t is_connected) +{ + hdd_context_t *hdd_ctx = NULL; + uint8_t buflen = WLAN_SVC_COUNTRY_CODE_LEN; + + if (!data) { + hddLog(LOGE, FL("invalid data pointer")); + return -EINVAL; + } + if (!adapter) { + if (is_on) { + /* no active interface */ + data->lpss_support = 0; + data->is_on = is_on; + return 0; + } + hddLog(LOGE, FL("invalid adapter pointer")); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx->lpss_support && hdd_ctx->config->enablelpasssupport) + data->lpss_support = 1; + else + data->lpss_support = 0; + data->numChannels = WLAN_SVC_MAX_NUM_CHAN; + sme_get_cfg_valid_channels(hdd_ctx->hHal, data->channel_list, + &data->numChannels); + sme_get_country_code(hdd_ctx->hHal, data->country_code, &buflen); + data->is_on = is_on; + data->vdev_id = adapter->sessionId; + data->vdev_mode = adapter->device_mode; + if (pHddStaCtx) { + data->is_connected = is_connected; + data->rssi = adapter->rssi; + data->freq = + cds_chan_to_freq(pHddStaCtx->conn_info.operationChannel); + if (WLAN_SVC_MAX_SSID_LEN >= + pHddStaCtx->conn_info.SSID.SSID.length) { + data->ssid_len = pHddStaCtx->conn_info.SSID.SSID.length; + memcpy(data->ssid, + pHddStaCtx->conn_info.SSID.SSID.ssId, + pHddStaCtx->conn_info.SSID.SSID.length); + } + if (CDF_MAC_ADDR_SIZE >= + sizeof(pHddStaCtx->conn_info.bssId)) + memcpy(data->bssid, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + } + return 0; +} + +int wlan_hdd_gen_wlan_version_pack(struct wlan_version_data *data, + uint32_t fw_version, + uint32_t chip_id, const char *chip_name) +{ + if (!data) { + hddLog(LOGE, FL("invalid data pointer")); + return -EINVAL; + } + + data->chip_id = chip_id; + strlcpy(data->chip_name, chip_name, WLAN_SVC_MAX_STR_LEN); + if (strncmp(chip_name, "Unknown", 7)) + strlcpy(data->chip_from, "Qualcomm", WLAN_SVC_MAX_STR_LEN); + else + strlcpy(data->chip_from, "Unknown", WLAN_SVC_MAX_STR_LEN); + strlcpy(data->host_version, QWLAN_VERSIONSTR, WLAN_SVC_MAX_STR_LEN); + scnprintf(data->fw_version, WLAN_SVC_MAX_STR_LEN, "%d.%d.%d.%d", + (fw_version & 0xf0000000) >> 28, + (fw_version & 0xf000000) >> 24, + (fw_version & 0xf00000) >> 20, (fw_version & 0x7fff)); + return 0; +} +#endif + +#if defined(FEATURE_WLAN_LFR) +/** + * wlan_hdd_disable_roaming() - disable roaming on all STAs except the input one + * @adapter: HDD adapter pointer + * + * This function loop through each adapter and disable roaming on each STA + * device mode except the input adapter. + * + * Note: On the input adapter roaming is not enabled yet hence no need to + * disable. + * + * Return: None + */ +void wlan_hdd_disable_roaming(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_adapter_t *adapterIdx = NULL; + hdd_adapter_list_node_t *adapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + CDF_STATUS status; + + if (hdd_ctx->config->isFastRoamIniFeatureEnabled && + hdd_ctx->config->isRoamOffloadScanEnabled && + WLAN_HDD_INFRA_STATION == adapter->device_mode && + cds_is_sta_active_connection_exists()) { + hddLog(LOG1, FL("Connect received on STA sessionId(%d)"), + adapter->sessionId); + /* + * Loop through adapter and disable roaming for each STA device + * mode except the input adapter. + */ + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapterIdx = adapterNode->pAdapter; + + if (WLAN_HDD_INFRA_STATION == adapterIdx->device_mode + && adapter->sessionId != adapterIdx->sessionId) { + hddLog(LOG1, + FL("Disable Roaming on sessionId(%d)"), + adapterIdx->sessionId); + sme_stop_roaming(WLAN_HDD_GET_HAL_CTX + (adapterIdx), + adapterIdx->sessionId, 0); + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } +} + +/** + * wlan_hdd_enable_roaming() - enable roaming on all STAs except the input one + * @adapter: HDD adapter pointer + * + * This function loop through each adapter and enable roaming on each STA + * device mode except the input adapter. + * Note: On the input adapter no need to enable roaming because link got + * disconnected on this. + * + * Return: None + */ +void wlan_hdd_enable_roaming(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_adapter_t *adapterIdx = NULL; + hdd_adapter_list_node_t *adapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + CDF_STATUS status; + + if (hdd_ctx->config->isFastRoamIniFeatureEnabled && + hdd_ctx->config->isRoamOffloadScanEnabled && + WLAN_HDD_INFRA_STATION == adapter->device_mode && + cds_is_sta_active_connection_exists()) { + hddLog(LOG1, FL("Disconnect received on STA sessionId(%d)"), + adapter->sessionId); + /* + * Loop through adapter and enable roaming for each STA device + * mode except the input adapter. + */ + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapterIdx = adapterNode->pAdapter; + + if (WLAN_HDD_INFRA_STATION == adapterIdx->device_mode + && adapter->sessionId != adapterIdx->sessionId) { + hddLog(LOG1, + FL("Enabling Roaming on sessionId(%d)"), + adapterIdx->sessionId); + sme_start_roaming(WLAN_HDD_GET_HAL_CTX + (adapterIdx), + adapterIdx->sessionId, + REASON_CONNECT); + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } +} +#endif + +void wlan_hdd_send_svc_nlink_msg(int type, void *data, int len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + void *nl_data = NULL; + int flags = GFP_KERNEL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), flags); + + if (skb == NULL) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("alloc_skb failed")); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_SVC; + + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = type; + + switch (type) { + case WLAN_SVC_FW_CRASHED_IND: + case WLAN_SVC_LTE_COEX_IND: +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND: +#endif + ani_hdr->length = 0; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr))); + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr))); + break; + case WLAN_SVC_WLAN_STATUS_IND: + case WLAN_SVC_WLAN_VERSION_IND: + case WLAN_SVC_DFS_CAC_START_IND: + case WLAN_SVC_DFS_CAC_END_IND: + case WLAN_SVC_DFS_RADAR_DETECT_IND: + case WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND: + case WLAN_SVC_WLAN_TP_IND: + ani_hdr->length = len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + len)); + nl_data = (char *)ani_hdr + sizeof(tAniMsgHdr); + memcpy(nl_data, data, len); + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + len)); + break; + + default: + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("WLAN SVC: Attempt to send unknown nlink message %d"), + type); + kfree_skb(skb); + return; + } + + nl_srv_bcast(skb); + + return; +} + +#ifdef WLAN_FEATURE_LPSS +void wlan_hdd_send_status_pkg(hdd_adapter_t *adapter, + hdd_station_ctx_t *pHddStaCtx, + uint8_t is_on, uint8_t is_connected) +{ + int ret = 0; + struct wlan_status_data data; + + if (CDF_FTM_MODE == hdd_get_conparam()) + return; + + memset(&data, 0, sizeof(struct wlan_status_data)); + if (is_on) + ret = wlan_hdd_gen_wlan_status_pack(&data, adapter, pHddStaCtx, + is_on, is_connected); + if (!ret) + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_WLAN_STATUS_IND, + &data, + sizeof(struct wlan_status_data)); +} + +void wlan_hdd_send_version_pkg(uint32_t fw_version, + uint32_t chip_id, const char *chip_name) +{ + int ret = 0; + struct wlan_version_data data; +#ifdef CONFIG_CNSS + struct cnss_platform_cap cap; + + ret = cnss_get_platform_cap(&cap); + if (ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("platform capability info from CNSS not available")); + return; + } + + if (!(cap.cap_flag & CNSS_HAS_UART_ACCESS)) + return; +#endif + + if (CDF_FTM_MODE == hdd_get_conparam()) + return; + + memset(&data, 0, sizeof(struct wlan_version_data)); + ret = + wlan_hdd_gen_wlan_version_pack(&data, fw_version, chip_id, + chip_name); + if (!ret) + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_WLAN_VERSION_IND, + &data, + sizeof(struct wlan_version_data)); +} + +void wlan_hdd_send_all_scan_intf_info(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *pDataAdapter = NULL; + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + bool scan_intf_found = false; + CDF_STATUS status; + + if (!hdd_ctx) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("NULL pointer for hdd_ctx")); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + pDataAdapter = adapterNode->pAdapter; + if (pDataAdapter) { + if (pDataAdapter->device_mode == WLAN_HDD_INFRA_STATION + || pDataAdapter->device_mode == WLAN_HDD_P2P_CLIENT + || pDataAdapter->device_mode == + WLAN_HDD_P2P_DEVICE) { + scan_intf_found = true; + wlan_hdd_send_status_pkg(pDataAdapter, NULL, 1, + 0); + } + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + if (!scan_intf_found) + wlan_hdd_send_status_pkg(pDataAdapter, NULL, 1, 0); +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_cb(void) +{ + hddLog(LOGE, FL("Wlan Idle. Sending Shutdown event..")); + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND, NULL, 0); +} + +void wlan_hdd_auto_shutdown_enable(hdd_context_t *hdd_ctx, bool enable) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *adapter; + bool ap_connected = false, sta_connected = false; + tHalHandle hal_handle; + + hal_handle = hdd_ctx->hHal; + if (hal_handle == NULL) + return; + + if (hdd_ctx->config->WlanAutoShutdown == 0) + return; + + if (enable == false) { + if (sme_set_auto_shutdown_timer(hal_handle, 0) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, + FL("Failed to stop wlan auto shutdown timer")); + } + return; + } + + /* To enable shutdown timer check conncurrency */ + if (cds_concurrent_open_sessions_running()) { + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter + && adapter->device_mode == + WLAN_HDD_INFRA_STATION) { + if (WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == + eConnectionState_Associated) { + sta_connected = true; + break; + } + } + if (adapter + && adapter->device_mode == WLAN_HDD_SOFTAP) { + if (WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + bApActive == true) { + ap_connected = true; + break; + } + } + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } + + if (ap_connected == true || sta_connected == true) { + hddLog(LOG1, + FL("CC Session active. Shutdown timer not enabled")); + return; + } else { + if (sme_set_auto_shutdown_timer(hal_handle, + hdd_ctx->config-> + WlanAutoShutdown) + != CDF_STATUS_SUCCESS) + hddLog(LOGE, + FL("Failed to start wlan auto shutdown timer")); + else + hddLog(LOG1, + FL("Auto Shutdown timer for %d seconds enabled"), + hdd_ctx->config->WlanAutoShutdown); + + } +} +#endif + +hdd_adapter_t *hdd_get_con_sap_adapter(hdd_adapter_t *this_sap_adapter, + bool check_start_bss) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(this_sap_adapter); + hdd_adapter_t *adapter, *con_sap_adapter; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + + con_sap_adapter = NULL; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter && ((adapter->device_mode == WLAN_HDD_SOFTAP) || + (adapter->device_mode == WLAN_HDD_P2P_GO)) && + adapter != this_sap_adapter) { + if (check_start_bss) { + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) { + con_sap_adapter = adapter; + break; + } + } else { + con_sap_adapter = adapter; + break; + } + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return con_sap_adapter; +} + +#ifdef MSM_PLATFORM +void hdd_start_bus_bw_compute_timer(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&hdd_ctx->bus_bw_timer)) + return; + + cdf_mc_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); +} + +void hdd_stop_bus_bw_compute_timer(hdd_adapter_t *adapter) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + bool can_stop = true; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (CDF_TIMER_STATE_RUNNING != + cdf_mc_timer_get_current_state(&hdd_ctx->bus_bw_timer)) { + /* trying to stop timer, when not running is not good */ + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("bus band width compute timer is not running")); + return; + } + + if (cds_concurrent_open_sessions_running()) { + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && CDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter + && (adapter->device_mode == WLAN_HDD_INFRA_STATION + || adapter->device_mode == WLAN_HDD_P2P_CLIENT) + && WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == + eConnectionState_Associated) { + can_stop = false; + break; + } + if (adapter + && (adapter->device_mode == WLAN_HDD_SOFTAP + || adapter->device_mode == WLAN_HDD_P2P_GO) + && WLAN_HDD_GET_AP_CTX_PTR(adapter)->bApActive == + true) { + can_stop = false; + break; + } + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } + + if (can_stop == true) + cdf_mc_timer_stop(&hdd_ctx->bus_bw_timer); +} +#endif + +/** + * wlan_hdd_check_custom_con_channel_rules() - This function checks the sap's + * and sta's operating channel. + * @sta_adapter: Describe the first argument to foobar. + * @ap_adapter: Describe the second argument to foobar. + * @roam_profile: Roam profile of AP to which STA wants to connect. + * @concurrent_chnl_same: If both SAP and STA channels are same then + * set this flag to true else false. + * + * This function checks the sap's operating channel and sta's operating channel. + * if both are same then it will return false else it will restart the sap in + * sta's channel and return true. + * + * Return: CDF_STATUS_SUCCESS or CDF_STATUS_E_FAILURE. + */ +CDF_STATUS wlan_hdd_check_custom_con_channel_rules(hdd_adapter_t *sta_adapter, + hdd_adapter_t *ap_adapter, + tCsrRoamProfile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + uint8_t channel_id; + CDF_STATUS status; + device_mode_t device_mode = ap_adapter->device_mode; + *concurrent_chnl_same = true; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + status = + sme_get_ap_channel_from_scan_cache(WLAN_HDD_GET_HAL_CTX(sta_adapter), + roam_profile, + scan_cache, + &channel_id); + if ((CDF_STATUS_SUCCESS == status)) { + if ((WLAN_HDD_SOFTAP == device_mode) && + (channel_id < SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operatingChannel != channel_id) { + *concurrent_chnl_same = false; + hddLog(CDF_TRACE_LEVEL_INFO_MED, + FL("channels are different")); + } + } else if ((WLAN_HDD_P2P_GO == device_mode) && + (channel_id >= SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operatingChannel != channel_id) { + *concurrent_chnl_same = false; + hddLog(CDF_TRACE_LEVEL_INFO_MED, + FL("channels are different")); + } + } + } else { + /* + * Lets handle worst case scenario here, Scan cache lookup is + * failed so we have to stop the SAP to avoid any channel + * discrepancy between SAP's channel and STA's channel. + * Return the status as failure so caller function could know + * that scan look up is failed. + */ + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Finding AP from scan cache failed")); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_MBSSID +/** + * wlan_hdd_stop_sap() - This function stops bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the stopping of sap adapter. + * + * Return: None + */ +void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + CDF_STATUS cdf_status; + hdd_context_t *hdd_ctx; +#ifdef CFG80211_DEL_STA_V2 + struct station_del_parameters delStaParams; +#endif + + if (NULL == ap_adapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("ap_adapter is NULL here")); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("HDD context is not valid")); + return; + } + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { +#ifdef CFG80211_DEL_STA_V2 + delStaParams.mac = NULL; + delStaParams.subtype = SIR_MAC_MGMT_DEAUTH >> 4; + delStaParams.reason_code = eCsrForcedDeauthSta; + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, + ap_adapter->dev, + &delStaParams); +#else + wlan_hdd_cfg80211_del_station(ap_adapter->wdev.wiphy, + ap_adapter->dev, + NULL); +#endif + hdd_cleanup_actionframe(hdd_ctx, ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Now doing SAP STOPBSS")); + cdf_event_reset(&hostapd_state->cdf_stop_bss_event); + if (CDF_STATUS_SUCCESS == wlansap_stop_bss(hdd_ap_ctx-> + sapContext)) { + cdf_status = cdf_wait_single_event(&hostapd_state-> + cdf_stop_bss_event, + BSS_WAIT_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + mutex_unlock(&hdd_ctx->sap_lock); + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SAP Stop Failed")); + return; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_decr_session_set_pcl(hdd_ctx, + ap_adapter->device_mode, + ap_adapter->sessionId); + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP Stop Success")); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Can't stop ap because its not started")); + } + mutex_unlock(&hdd_ctx->sap_lock); + return; +} + +/** + * wlan_hdd_start_sap() - this function starts bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the starting of sap adapter. + * + * Return: None + */ +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + CDF_STATUS cdf_status; + hdd_context_t *hdd_ctx; + tsap_Config_t *sap_config; + + if (NULL == ap_adapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("ap_adapter is NULL here")); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + sap_config = &ap_adapter->sessionCtx.ap.sapConfig; + + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("HDD context is not valid")); + return; + } + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + goto end; + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + hddLog(LOGE, FL("SAP Not able to set AP IEs")); + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + goto end; + } + + if (wlansap_start_bss(hdd_ap_ctx->sapContext, hdd_hostapd_sap_event_cb, + &hdd_ap_ctx->sapConfig, + ap_adapter->dev) + != CDF_STATUS_SUCCESS) + goto end; + + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Waiting for SAP to start")); + cdf_status = cdf_wait_single_event(&hostapd_state->cdf_event, + BSS_WAIT_TIMEOUT); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("SAP Start failed")); + goto end; + } + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, FL("SAP Start Success")); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_incr_active_session(hdd_ctx, ap_adapter->device_mode, + ap_adapter->sessionId); + hostapd_state->bCommit = true; + +end: + mutex_unlock(&hdd_ctx->sap_lock); + return; +} +#endif + +/** + * hdd_wlan_get_wake_lock_ptr(): get HDD's wake lock pointer + * + * This function returns the wake lock pointer to the caller + * + * Return: cdf_wake_lock_t + */ +cdf_wake_lock_t *hdd_wlan_get_wake_lock_ptr(void) +{ + return &wlan_wake_lock; +} + +/** + * hdd_get_fw_version() - Get FW version + * @hdd_ctx: pointer to HDD context. + * @major_spid: FW version - major spid. + * @minor_spid: FW version - minor spid + * @ssid: FW version - ssid + * @crmid: FW version - crmid + * + * This function is called to get the firmware build version stored + * as part of the HDD context + * + * Return: None + */ +void hdd_get_fw_version(hdd_context_t *hdd_ctx, + uint32_t *major_spid, uint32_t *minor_spid, + uint32_t *siid, uint32_t *crmid) +{ + *major_spid = (hdd_ctx->target_fw_version & 0xf0000000) >> 28; + *minor_spid = (hdd_ctx->target_fw_version & 0xf000000) >> 24; + *siid = (hdd_ctx->target_fw_version & 0xf00000) >> 20; + *crmid = hdd_ctx->target_fw_version & 0x7fff; +} + +#ifdef QCA_CONFIG_SMP +/** + * wlan_hdd_get_cpu() - get cpu_index + * + * Return: cpu_index + */ +int wlan_hdd_get_cpu(void) +{ + int cpu_index = get_cpu(); + put_cpu(); + return cpu_index; +} +#endif + +/** + * hdd_get_fwpath() - get framework path + * + * This function is used to get the string written by + * userspace to start the wlan driver + * + * Return: string + */ +const char *hdd_get_fwpath(void) +{ + return fwpath.string; +} + + +/* Register the module init/exit functions */ +module_init(hdd_module_init); +module_exit(hdd_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Qualcomm Atheros, Inc."); +MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER"); + +#if defined(QCA_WIFI_FTM) +module_param(con_mode, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +#else +module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +#endif + +module_param_call(fwpath, fwpath_changed_handler, param_get_string, &fwpath, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param(enable_dfs_chan_scan, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(enable_11d, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(country_code, charp, S_IRUSR | S_IRGRP | S_IROTH); diff --git a/core/hdd/src/wlan_hdd_memdump.c b/core/hdd/src/wlan_hdd_memdump.c new file mode 100644 index 0000000000..d1ad781ed9 --- /dev/null +++ b/core/hdd/src/wlan_hdd_memdump.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC : wlan_hdd_memdump.c + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#include +#include +#include "wlan_hdd_memdump.h" +#include +#include +#include +#include /* Necessary because we use the proc fs */ +#include /* for copy_to_user */ + +/** + * hdd_fw_dump_context - hdd firmware memory dump context + * + * @request_id: userspace assigned firmware memory dump request ID + * @response_event: firmware memory dump request wait event + */ +struct hdd_fw_dump_context { + uint32_t request_id; + struct completion response_event; +}; +static struct hdd_fw_dump_context fw_dump_context; + +/** + * memdump_cleanup_timer_cb() - Timer callback function for memory dump cleanup. + * + * @data: Callback data (used to stored HDD context) + * + * Callback function registered for memory dump cleanup VOS timer. + * + * Return: none + */ + +static void memdump_cleanup_timer_cb(void *data) +{ + int status; + hdd_context_t *hdd_ctx = data; + cdf_dma_addr_t paddr; + cdf_dma_addr_t dma_ctx = 0; + cdf_device_t cdf_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return; + } + + if (!hdd_ctx->fw_dump_loc) { + hddLog(LOG1, FL("Memory dump already freed")); + return; + } + + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + if (!cdf_ctx) { + hddLog(LOGE, FL("CDF context is NULL")); + return; + } + + paddr = hdd_ctx->dump_loc_paddr; + mutex_lock(&hdd_ctx->memdump_lock); + cdf_os_mem_free_consistent(cdf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + mutex_unlock(&hdd_ctx->memdump_lock); + +} + +/** + * wlan_hdd_cfg80211_fw_mem_dump_cb() - Callback to receive FW memory dump + * @ctx: pointer to HDD context. + * @rsp: pointer to fw dump copy complete response + * + * This is a callback function used to indicate user space about the + * availability for firmware memory dump via vendor event. + * + * Return: None + */ +static void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, + struct fw_dump_rsp *dump_rsp) +{ + hdd_context_t *hdd_ctx = ctx; + struct hdd_fw_dump_context *context; + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return; + } + + spin_lock(&hdd_context_lock); + context = &fw_dump_context; + /* validate the response received */ + if (!dump_rsp->dump_complete || + context->request_id != dump_rsp->request_id) { + spin_unlock(&hdd_context_lock); + hddLog(LOGE, + FL("Error @ request_id: %d response_id: %d status: %d"), + context->request_id, dump_rsp->request_id, + dump_rsp->dump_complete); + return; + } else { + complete(&context->response_event); + } + spin_unlock(&hdd_context_lock); + + return; +} + +/** + * wlan_hdd_send_memdump_rsp - send memory dump response to user space + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 for success; non-zero for failure + */ +static int wlan_hdd_send_memdump_rsp(hdd_context_t *hdd_ctx) +{ + struct sk_buff *skb; + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + NLMSG_HDRLEN + NLA_HDRLEN + sizeof(uint32_t)); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE, + FW_MEM_DUMP_SIZE)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + hddLog(LOG1, FL("Memdump event sent successfully to user space")); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int status; + CDF_STATUS sme_status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct fw_dump_req fw_mem_dump_req; + struct fw_dump_seg_req *seg_req; + uint8_t loop; + cdf_dma_addr_t paddr; + cdf_dma_addr_t dma_ctx = 0; + cdf_device_t cdf_ctx; + unsigned long rc; + struct hdd_fw_dump_context *context; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return status; + } + + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + if (!cdf_ctx) { + hddLog(LOGE, FL("CDF context is NULL")); + return -EINVAL; + } + + if (hdd_ctx->memdump_in_progress) { + hddLog(LOGE, FL("Already a memdump req in progress.")); + return -EBUSY; + } + + /* + * Allocate memory for fw memory dump. Memory allocated should be + * contiguous. Physical address of the allocated memory is passed + * to the FW for copy + * + * Reuse the memory if available. + */ + mutex_lock(&hdd_ctx->memdump_lock); + if (!hdd_ctx->fw_dump_loc) { + hdd_ctx->fw_dump_loc = cdf_os_mem_alloc_consistent( + cdf_ctx, FW_MEM_DUMP_SIZE, &paddr, dma_ctx); + if (!hdd_ctx->fw_dump_loc) { + mutex_unlock(&hdd_ctx->memdump_lock); + hddLog(LOGE, FL("cdf_os_mem_alloc_consistent failed")); + return -ENOMEM; + } + hdd_ctx->dump_loc_paddr = paddr; + } + mutex_unlock(&hdd_ctx->memdump_lock); + + /* + * Currently request_id and num_seg is assumed to be default(1) + * It is assumed that firmware dump requested is for DRAM section + * only + */ + + fw_mem_dump_req.request_id = FW_MEM_DUMP_REQ_ID; + fw_mem_dump_req.num_seg = FW_MEM_DUMP_NUM_SEG; + + hddLog(LOG1, FL("request_id:%d num_seg:%d"), + fw_mem_dump_req.request_id, fw_mem_dump_req.num_seg); + seg_req = (struct fw_dump_seg_req *) fw_mem_dump_req.segment; + for (loop = 0; loop < fw_mem_dump_req.num_seg; loop++) { + seg_req->seg_id = 1; + seg_req->seg_start_addr_lo = FW_DRAM_LOCATION; + seg_req->seg_start_addr_hi = 0; + seg_req->seg_length = FW_MEM_DUMP_SIZE; + seg_req->dst_addr_lo = hdd_ctx->dump_loc_paddr; + seg_req->dst_addr_hi = 0; + hddLog(LOG1, FL("seg_number:%d"), loop); + hddLog(LOG1, + FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + seg_req->seg_id, seg_req->seg_start_addr_lo, + seg_req->seg_start_addr_hi); + hddLog(LOG1, + FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + seg_req->seg_length, seg_req->dst_addr_lo, + seg_req->dst_addr_hi); + seg_req++; + } + + /** + * Start the cleanup timer. + * Memory allocated for this request will be freed up + * once the timer expires. Memory dump request is expected to be + * completed by this time. + * + * User space will not be able to access the dump after this time. + * New request should be issued to get the dump again. + */ + cdf_mc_timer_start(&hdd_ctx->memdump_cleanup_timer, + MEMDUMP_COMPLETION_TIME_MS); + hdd_ctx->memdump_in_progress = true; + + spin_lock(&hdd_context_lock); + context = &fw_dump_context; + context->request_id = fw_mem_dump_req.request_id; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + + sme_status = sme_fw_mem_dump(hdd_ctx->hHal, &fw_mem_dump_req); + if (CDF_STATUS_SUCCESS != sme_status) { + hddLog(LOGE, FL("sme_fw_mem_dump Failed")); + mutex_lock(&hdd_ctx->memdump_lock); + cdf_os_mem_free_consistent(cdf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_ctx->memdump_in_progress = false; + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &hdd_ctx->memdump_cleanup_timer)) { + cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(MEMDUMP_COMPLETION_TIME_MS)); + if (!rc) { + hddLog(LOGE, FL("Target response timed out for request_id: %d"), + context->request_id); + return -ETIMEDOUT; + } + + status = wlan_hdd_send_memdump_rsp(hdd_ctx); + if (status) + hddLog(LOGE, + FL("Failed to send FW memory dump rsp to user space")); + + return status; +} + +/** + * wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define PROCFS_MEMDUMP_DIR "debug" +#define PROCFS_MEMDUMP_NAME "fwdump" +#define PROCFS_MEMDUMP_PERM 0444 + +static struct proc_dir_entry *proc_file, *proc_dir; + +/** memdump_get_file_data() - get data available in proc file + * + * @file - handle for the proc file. + * + * This function is used to retrieve the data passed while + * creating proc file entry. + * + * Return: void pointer to hdd_context + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) || defined(WITH_BACKPORTS) +static void *memdump_get_file_data(struct file *file) +{ + void *hdd_ctx; + + hdd_ctx = PDE_DATA(file_inode(file)); + return hdd_ctx; +} +#else +static void *memdump_get_file_data(struct file *file) +{ + void *hdd_ctx; + + hdd_ctx = PDE(file->f_path.dentry->d_inode)->data; + return hdd_ctx; +} +#endif + +/** + * memdump_read() - perform read operation in memory dump proc file + * + * @file - handle for the proc file. + * @buf - pointer to user space buffer. + * @count - number of bytes to be read. + * @pos - offset in the from buffer. + * + * This function performs read operation for the memory dump proc file. + * + * Return: number of bytes read on success, error code otherwise. + */ +static ssize_t memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + hdd_context_t *hdd_ctx; + cdf_dma_addr_t paddr; + cdf_dma_addr_t dma_ctx = 0; + cdf_device_t cdf_ctx; + + hdd_ctx = memdump_get_file_data(file); + + hddLog(LOG1, FL("Read req for size:%zu pos:%llu"), count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + if (!cdf_ctx) { + hddLog(LOGE, FL("CDF context is NULL")); + return -EINVAL; + } + + if (!hdd_ctx->memdump_in_progress) { + hddLog(LOGE, FL("Current mem dump request timed out/failed")); + return -EINVAL; + } + + if (*pos < 0) { + hddLog(LOGE, FL("Invalid start offset for memdump read")); + return -EINVAL; + } else if (*pos >= FW_MEM_DUMP_SIZE || !count) { + hddLog(LOGE, FL("No more data to copy")); + return 0; + } else if (count > FW_MEM_DUMP_SIZE - *pos) { + count = FW_MEM_DUMP_SIZE - *pos; + } + + if (!hdd_ctx->fw_dump_loc) { + hddLog(LOGE, FL("Invalid fw mem dump location")); + return -EINVAL; + } + + if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) { + hddLog(LOGE, FL("copy to user space failed")); + return -EFAULT; + } + + /* offset(pos) should be updated here based on the copy done*/ + *pos += count; + + /* Entire FW memory dump copy completed */ + if (*pos >= FW_MEM_DUMP_SIZE) { + paddr = hdd_ctx->dump_loc_paddr; + mutex_lock(&hdd_ctx->memdump_lock); + cdf_os_mem_free_consistent(cdf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &hdd_ctx->memdump_cleanup_timer)) { + cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + mutex_unlock(&hdd_ctx->memdump_lock); + } + + return count; +} + +/** + * struct memdump_fops - file operations for memory dump feature + * @read - read function for memory dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations memdump_fops = { + read: memdump_read +}; + +/** + * memdump_procfs_init() - Initialize procfs for memory dump + * + * This function create file under proc file system to be used later for + * processing firmware memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int memdump_procfs_init(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + proc_dir = proc_mkdir(PROCFS_MEMDUMP_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_MEMDUMP_NAME, + PROCFS_MEMDUMP_PERM, proc_dir, + &memdump_fops, hdd_ctx); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_NAME); + return -ENOMEM; + } + + pr_debug("/proc/%s/%s created\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + return 0; +} + +/** + * memdump_procfs_remove() - Remove file/dir under procfs for memory dump + * + * This function removes file/dir under proc file system that was + * processing firmware memory dump + * + * Return: None + */ +static void memdump_procfs_remove(void) +{ + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("/proc/%s/%s removed\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("/proc/%s removed\n", PROCFS_MEMDUMP_DIR); +} + +/** + * memdump_init() - Intialization function for memory dump feature + * + * This function creates proc file for memdump feature and registers + * HDD callback function with SME. + * + * Return - 0 on success, error otherwise + */ +int memdump_init(void) +{ + hdd_context_t *hdd_ctx; + int status = 0; + CDF_STATUS cb_status; + CDF_STATUS cdf_status; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Not initializing memdump in FTM mode")); + return -EINVAL; + } + + cb_status = sme_fw_mem_dump_register_cb(hdd_ctx->hHal, + wlan_hdd_cfg80211_fw_mem_dump_cb); + if (CDF_STATUS_SUCCESS != cb_status) { + hddLog(LOGE , FL("Failed to register the callback")); + return -EINVAL; + } + + status = memdump_procfs_init(); + if (status) { + hddLog(LOGE , FL("Failed to create proc file")); + return status; + } + + init_completion(&fw_dump_context.response_event); + + cdf_status = cdf_mc_timer_init(&hdd_ctx->memdump_cleanup_timer, + CDF_TIMER_TYPE_SW, memdump_cleanup_timer_cb, + (void *)hdd_ctx); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("Failed to init memdump cleanup timer")); + return -EINVAL; + } + + mutex_init(&hdd_ctx->memdump_lock); + + return 0; +} + +/** + * memdump_deinit() - De initialize memdump feature + * + * This function removes proc file created for memdump feature. + * + * Return: None + */ +void memdump_deinit(void) +{ + hdd_context_t *hdd_ctx; + cdf_dma_addr_t paddr; + cdf_dma_addr_t dma_ctx = 0; + cdf_device_t cdf_ctx; + CDF_STATUS cdf_status; + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return; + } + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Not deinitializing memdump in FTM mode")); + return; + } + + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + if (!cdf_ctx) { + hddLog(LOGE, FL("CDF context is NULL")); + return; + } + + memdump_procfs_remove(); + sme_fw_mem_dump_unregister_cb(hdd_ctx->hHal); + + mutex_lock(&hdd_ctx->memdump_lock); + if (hdd_ctx->fw_dump_loc) { + paddr = hdd_ctx->dump_loc_paddr; + cdf_os_mem_free_consistent(cdf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + } + mutex_unlock(&hdd_ctx->memdump_lock); + + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&hdd_ctx->memdump_cleanup_timer)) { + cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + + cdf_status = cdf_mc_timer_destroy(&hdd_ctx->memdump_cleanup_timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hddLog(LOGE, FL("Failed to deallocate timer")); +} diff --git a/core/hdd/src/wlan_hdd_nan.c b/core/hdd/src/wlan_hdd_nan.c new file mode 100644 index 0000000000..4fff12bd15 --- /dev/null +++ b/core/hdd/src/wlan_hdd_nan.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_nan.c + * + * WLAN Host Device Driver NAN API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "nan_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_nan.h" + +/** + * __wlan_hdd_cfg80211_nan_request() - cfg80211 NAN request handler + * @wiphy: driver's wiphy struct + * @wdev: wireless device to which the request is targeted + * @data: actual request data (netlink-encapsulated) + * @data_len: length of @data + * + * This is called when userspace needs to send a nan request to + * firmware. The wlan host driver simply de-encapsulates the + * request from the netlink payload and then forwards it to + * firmware via SME. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tNanRequestReq nan_req; + CDF_STATUS status; + int ret_val; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!hdd_ctx->config->enable_nan_support) { + hdd_err("NaN support is not enabled in INI"); + return -EPERM; + } + + nan_req.request_data_len = data_len; + nan_req.request_data = data; + + status = sme_nan_request(&nan_req); + if (CDF_STATUS_SUCCESS != status) { + ret_val = -EINVAL; + } + return ret_val; +} + +/** + * wlan_hdd_cfg80211_nan_request() - handle NAN request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to send a NAN request to + * firmware. This is an SSR-protected wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) + +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_nan_request(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_nan_callback() - cfg80211 NAN event handler + * @ctx: global HDD context + * @msg: NAN event message + * + * This is a callback function and it gets called when we need to report + * a nan event to userspace. The wlan host driver simply encapsulates the + * event into a netlink payload and then forwards it to userspace via a + * cfg80211 vendor event. + * + * Return: nothing + */ +static void wlan_hdd_cfg80211_nan_callback(void *ctx, tSirNanEvent *msg) +{ + hdd_context_t *hdd_ctx = ctx; + struct sk_buff *vendor_event; + int status; + + if (NULL == msg) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("msg received here is null")); + return; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("HDD context is not valid")); + return; + } + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + msg->event_data_len + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_event_alloc failed")); + return; + } + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NAN, + msg->event_data_len, msg->event_data)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR_NAN put fail")); + kfree_skb(vendor_event); + return; + } + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * wlan_hdd_nan_is_supported() - HDD NAN support query function + * + * This function is called to determine if NAN is supported by the + * driver and by the firmware. + * + * Return: true if NAN is supported by the driver and firmware + */ +bool wlan_hdd_nan_is_supported(void) +{ + return sme_is_feature_supported_by_fw(NAN); +} + +/** + * wlan_hdd_nan_init() - HDD NAN initialization function + * @hdd_ctx: Global HDD context + * + * This function is called to initialize the HDD NAN feature. Currently + * the only operation required is to register a callback with SME. + * + * Return: void + */ +void wlan_hdd_nan_init(hdd_context_t *hdd_ctx) +{ + sme_nan_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_nan_callback); +} diff --git a/core/hdd/src/wlan_hdd_napi.c b/core/hdd/src/wlan_hdd_napi.c new file mode 100644 index 0000000000..4bca8b9a22 --- /dev/null +++ b/core/hdd/src/wlan_hdd_napi.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_napi.c + * + * WLAN HDD NAPI interface implementation + */ +#include /* get_cpu */ + +#include "wlan_hdd_napi.h" +#include "cds_api.h" /* cds_get_context */ +#include "hif.h" /* hif_map_service...*/ +#include "wlan_hdd_main.h" /* hdd_err/warn... */ +#include "cdf_types.h" /* CDF_MODULE_ID_... */ +#include "ce_api.h" + +/* guaranteed to be initialized to zero/NULL by the standard */ +static struct qca_napi_data *hdd_napi_ctx; + +/** + * hdd_napi_get_all() - return the whole NAPI structure from HIF + * + * Gets to the data structure common to all NAPI instances. + * + * Return: + * NULL : probably NAPI not initialized yet. + * : the address of the whole NAPI structure + */ +struct qca_napi_data *hdd_napi_get_all(void) +{ + struct qca_napi_data *rp; + struct ol_softc *hif; + + NAPI_DEBUG("-->\n"); + + hif = cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif != NULL); + rp = hif_napi_get_all(hif); + + NAPI_DEBUG("<-- [addr=%p]\n", rp); + return rp; +} + +/** + * hdd_napi_get_map() - get a copy of napi pipe map + * + * Return: + * uint32_t : copy of pipe map + */ +static uint32_t hdd_napi_get_map(void) +{ + uint32_t map; + + NAPI_DEBUG("-->\n"); + /* cache once, use forever */ + if (hdd_napi_ctx == NULL) + hdd_napi_ctx = hdd_napi_get_all(); + map = hdd_napi_ctx->ce_map; + + NAPI_DEBUG("<--[map=0x%08x]\n", map); + return map; +} + +/** + * hdd_napi_create() - creates the NAPI structures for a given netdev + * + * Creates NAPI instances. This function is called + * unconditionally during initialization. It creates + * napi structures through the proper HTC/HIF calls. + * The structures are disabled on creation. + * + * Return: + * single-queue: <0: err, >0=id, 0 (should not happen) + * multi-queue: bitmap of created instances (0: none) + */ +int hdd_napi_create(void) +{ + struct ol_softc *hif_ctx; + uint8_t ul, dl; + int ul_polled, dl_polled; + int rc = 0; + + hif_ctx = cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif_ctx != NULL); + + NAPI_DEBUG("-->\n"); + + /* + * hif_service_to_pipe currently returns one pipe id per service. + * However for Adrestea, we will need to figure out how to map + * DATA service to multiple pipes. Either we will need to create + * family of services, or this function may return a bitmap (of + * at least #MAX_CEs bits) and then we will need to iterate on + * the bitmap for hif_napi_create() calls. + * For Rome, there is only one service, so there is a single call + * TODO: clarify for multi-queue/Adrestea + */ + if (CDF_STATUS_SUCCESS != + hif_map_service_to_pipe(hif_ctx, HTT_DATA_MSG_SVC, + &ul, &dl, &ul_polled, &dl_polled)) { + hdd_err("cannot map service to pipe"); + rc = -EINVAL; + } else { + rc = hif_napi_create(hif_ctx, dl, hdd_napi_poll, + QCA_NAPI_BUDGET, QCA_NAPI_DEF_SCALE); + if (rc < 0) + hdd_err("ERR(%d) creating NAPI on pipe %d", rc, dl); + else { + hdd_info("napi instance %d created on pipe %d", + rc, dl); + /* rc = (0x01 << rc); -- phase 2 */ + } + } + NAPI_DEBUG("<-- [rc=%d]\n", rc); + + return rc; +} + +/** + * hdd_napi_destroy() - destroys the NAPI structures for a given netdev + * @force: if set, will force-disable the instance before _del'ing + * + * Destroy NAPI instances. This function is called + * unconditionally during module removal. It destroy + * napi structures through the proper HTC/HIF calls. + * + * Return: + * number of NAPI instances destroyed + */ +int hdd_napi_destroy(int force) +{ + int rc = 0; + int i; + uint32_t hdd_napi_map = hdd_napi_get_map(); + + NAPI_DEBUG("--> (force=%d)\n", force); + if (hdd_napi_map) { + struct ol_softc *hif_ctx; + + hif_ctx = cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif_ctx != NULL); + + for (i = 0; i < (sizeof(uint32_t)*8); i++) + if (hdd_napi_map & (0x01 << i)) { + if (0 <= hif_napi_destroy(hif_ctx, + NAPI_PIPE2ID(i), + force)) { + rc++; + hdd_napi_map &= ~(0x01 << i); + } else + hdd_err("cannot destroy napi inst %d: (pipe:%d), f=%d\n", + i, NAPI_PIPE2ID(i), force); + } + } + + /* if all instances are removed, it is likely that hif_context has been + * removed as well, so the cached value of the napi context also needs + * to be removed + */ + if (force) + CDF_ASSERT(hdd_napi_map == 0); + if (0 == hdd_napi_map) + hdd_napi_ctx = NULL; + + NAPI_DEBUG("<-- [rc=%d]\n", rc); + return rc; +} + +/** + * hdd_napi_enabled() - checks if NAPI is enabled (for a given id) + * @id: the id of the NAPI to check (any= -1) + * + * Return: + * int: 0 = false (NOT enabled) + * !0 = true (enabbled) + */ +inline int hdd_napi_enabled(int id) +{ + struct ol_softc *hif; + + hif = cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif != NULL); + if (-1 == id) + return hif_napi_enabled(hif, id); + else + return hif_napi_enabled(hif, NAPI_ID2PIPE(id)); +} + +/** + * hdd_napi_event() - relay the event detected by HDD to HIF NAPI decision maker + * @event: event code + * @data : event-specific auxiliary data + * + * Return code does not indicate a change, but whether or not NAPI is + * enabled at the time of the return of the function. That is, if NAPI + * was disabled before the call, and the event does not cause NAPI to be + * enabled, a value of 0 will be returned indicating that it is (still) + * disabled. + * + * Return: + * < 0: error code + * = 0: NAPI state = disabled (after processing the event) + * = 1: NAPI state = enabled (after processing the event) + */ +int hdd_napi_event(enum qca_napi_event event, void *data) +{ + int rc; + struct ol_softc *hif; + + NAPI_DEBUG("-->(event=%d, aux=%p)\n", event, data); + + hif = cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif != NULL); + rc = hif_napi_event(hif, event, data); + + NAPI_DEBUG("<--[rc=%d]\n", rc); + return rc; +} + +/** + * hdd_napi_poll() - NAPI poll function + * @napi : pointer to NAPI struct + * @budget: the pre-declared budget + * + * Implementation of poll function. This function is called + * by kernel during softirq processing. + * + * NOTE FOR THE MAINTAINER: + * Make sure this is very close to the ce_tasklet code. + * + * Return: + * int: the amount of work done ( <= budget ) + */ +int hdd_napi_poll(struct napi_struct *napi, int budget) +{ + return hif_napi_poll(napi, budget); +} diff --git a/core/hdd/src/wlan_hdd_ocb.c b/core/hdd/src/wlan_hdd_ocb.c new file mode 100644 index 0000000000..a34959d2f2 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ocb.c @@ -0,0 +1,2112 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "cds_sched.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_trace.h" +#include "wlan_tgt_def_config.h" +#include "sch_api.h" +#include "wma_api.h" + +/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */ +#define AIFSN_MIN (2) +#define AIFSN_MAX (15) +#define CW_MIN (1) +#define CW_MAX (10) + +/* Maximum time(ms) to wait for OCB operations */ +#define WLAN_WAIT_TIME_OCB_CMD 1500 +#define HDD_OCB_MAGIC 0x489a154f + +/** + * struct hdd_ocb_ctxt - Context for OCB operations + * adapter: the ocb adapter + * completion_evt: the completion event + * status: status of the request + */ +struct hdd_ocb_ctxt { + uint32_t magic; + hdd_adapter_t *adapter; + struct completion completion_evt; + int status; +}; + +/** + * hdd_set_dot11p_config() - Set 802.11p config flag + * @hdd_ctx: HDD Context pointer + * + * TODO-OCB: This has been temporarily added to ensure this paramter + * is set in CSR when we init the channel list. This should be removed + * once the 5.9 GHz channels are added to the regulatory domain. + */ +void hdd_set_dot11p_config(hdd_context_t *hdd_ctx) +{ + sme_set_dot11p_config(hdd_ctx->hHal, + hdd_ctx->config->dot11p_mode != + WLAN_HDD_11P_DISABLED); +} + +/** + * dot11p_validate_qos_params() - Check if QoS parameters are valid + * @qos_params: Array of QoS parameters + * + * Return: 0 on success. error code on failure. + */ +static int dot11p_validate_qos_params(struct sir_qos_params qos_params[]) +{ + int i; + + for (i = 0; i < MAX_NUM_AC; i++) { + if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin) + && (!qos_params[i].cwmax)) + continue; + + /* Validate AIFSN */ + if ((qos_params[i].aifsn < AIFSN_MIN) + || (qos_params[i].aifsn > AIFSN_MAX)) { + hddLog(LOGE, FL("Invalid QoS parameter aifsn %d"), + qos_params[i].aifsn); + return -EINVAL; + } + + /* Validate CWMin */ + if ((qos_params[i].cwmin < CW_MIN) + || (qos_params[i].cwmin > CW_MAX)) { + hddLog(LOGE, FL("Invalid QoS parameter cwmin %d"), + qos_params[i].cwmin); + return -EINVAL; + } + + /* Validate CWMax */ + if ((qos_params[i].cwmax < CW_MIN) + || (qos_params[i].cwmax > CW_MAX)) { + hddLog(LOGE, FL("Invalid QoS parameter cwmax %d"), + qos_params[i].cwmax); + return -EINVAL; + } + } + + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) || \ + defined(FEATURE_STATICALLY_ADD_11P_CHANNELS) +/* + * If FEATURE_STATICALLY_ADD_11P_CHANNELS + * is defined, IEEE80211_CHAN_NO_10MHZ, + * and IEEE80211_CHAN_NO_20MHZ won't + * be defined. + */ +#define IEEE80211_CHAN_NO_20MHZ (1<<11) +#define IEEE80211_CHAN_NO_10MHZ (1<<12) +#endif + +#ifdef FEATURE_STATICALLY_ADD_11P_CHANNELS + +#define DOT11P_TX_PWR_MAX 30 +#define DOT11P_TX_ANTENNA_MAX 6 +#define NUM_DOT11P_CHANNELS 10 +/** + * struct chan_info - information for the channel + * @center_freq: center frequency + * @max_bandwidth: maximum bandwidth of the channel in MHz + */ +struct chan_info { + uint32_t center_freq; + uint32_t max_bandwidth; +}; + +struct chan_info valid_dot11p_channels[NUM_DOT11P_CHANNELS] = { + {5860, 10}, + {5870, 10}, + {5880, 10}, + {5890, 10}, + {5900, 10}, + {5910, 10}, + {5920, 10}, + {5875, 20}, + {5905, 20}, + {5852, 5} +}; + +/** + * dot11p_validate_channel_static_channels() - validate a DSRC channel + * @center_freq: the channel's center frequency + * @bandwidth: the channel's bandwidth + * @tx_power: transmit power + * @reg_power: (output) the max tx power from the regulatory domain + * @antenna_max: (output) the max antenna gain from the regulatory domain + * + * This function of the function checks the channel parameters against a + * hardcoded list of valid channels based on the FCC rules. + * + * Return: 0 if the channel is valid, error code otherwise. + */ +static int dot11p_validate_channel_static_channels(struct wiphy *wiphy, + uint32_t channel_freq, uint32_t bandwidth, uint32_t tx_power, + uint8_t *reg_power, uint8_t *antenna_max) +{ + int i; + + for (i = 0; i < NUM_DOT11P_CHANNELS; i++) { + if (channel_freq == valid_dot11p_channels[i].center_freq) { + if (reg_power) + *reg_power = DOT11P_TX_PWR_MAX; + if (antenna_max) + *antenna_max = DOT11P_TX_ANTENNA_MAX; + + if (bandwidth == 0) + bandwidth = + valid_dot11p_channels[i].max_bandwidth; + else if (bandwidth > + valid_dot11p_channels[i].max_bandwidth) + return -EINVAL; + + if (bandwidth != 5 && bandwidth != 10 && + bandwidth != 20) + return -EINVAL; + if (tx_power > DOT11P_TX_PWR_MAX) + return -EINVAL; + + return 0; + } + } + + return -EINVAL; +} +#else +/** + * dot11p_validate_channel_static_channels() - validate a DSRC channel + * @center_freq: the channel's center frequency + * @bandwidth: the channel's bandwidth + * @tx_power: transmit power + * @reg_power: (output) the max tx power from the regulatory domain + * @antenna_max: (output) the max antenna gain from the regulatory domain + * + * This function of the function checks the channel parameters against a + * hardcoded list of valid channels based on the FCC rules. + * + * Return: 0 if the channel is valid, error code otherwise. + */ +static int dot11p_validate_channel_static_channels(struct wiphy *wiphy, + uint32_t channel_freq, uint32_t bandwidth, uint32_t tx_power, + uint8_t *reg_power, uint8_t *antenna_max) +{ + return -EINVAL; +} +#endif /* FEATURE_STATICALLY_ADD_11P_CHANNELS */ + +/** + * dot11p_validate_channel() - validates a DSRC channel + * @center_freq: the channel's center frequency + * @bandwidth: the channel's bandwidth + * @tx_power: transmit power + * @reg_power: (output) the max tx power from the regulatory domain + * @antenna_max: (output) the max antenna gain from the regulatory domain + * + * Return: 0 if the channel is valid, error code otherwise. + */ +static int dot11p_validate_channel(struct wiphy *wiphy, + uint32_t channel_freq, uint32_t bandwidth, + uint32_t tx_power, uint8_t *reg_power, + uint8_t *antenna_max) +{ + int band_idx, channel_idx; + struct ieee80211_supported_band *current_band; + struct ieee80211_channel *current_channel; + + for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) { + current_band = wiphy->bands[band_idx]; + if (!current_band) + continue; + + for (channel_idx = 0; channel_idx < current_band->n_channels; + channel_idx++) { + current_channel = ¤t_band->channels[channel_idx]; + + if (channel_freq == current_channel->center_freq) { + if (current_channel->flags & + IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (reg_power) + *reg_power = + current_channel->max_reg_power; + if (antenna_max) + *antenna_max = + current_channel-> + max_antenna_gain; + + switch (bandwidth) { + case 0: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + bandwidth = 5; + else if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + bandwidth = 10; + else + bandwidth = 20; + break; + case 5: + break; + case 10: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + return -EINVAL; + break; + case 20: + if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (tx_power > current_channel->max_power) + return -EINVAL; + + return 0; + } + } + } + + return dot11p_validate_channel_static_channels(wiphy, channel_freq, + bandwidth, tx_power, reg_power, antenna_max); +} + +/** + * hdd_ocb_validate_config() - Validates the config data + * @config: configuration to be validated + * + * Return: 0 on success. + */ +static int hdd_ocb_validate_config(hdd_adapter_t *adapter, + struct sir_ocb_config *config) +{ + int i; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < config->channel_count; i++) { + if (dot11p_validate_channel(hdd_ctx->wiphy, + config->channels[i].chan_freq, + config->channels[i].bandwidth, + config->channels[i].max_pwr, + &config->channels[i].reg_pwr, + &config->channels[i].antenna_max)) { + hddLog(LOGE, FL("Invalid channel frequency %d"), + config->channels[i].chan_freq); + return -EINVAL; + } + if (dot11p_validate_qos_params(config->channels[i].qos_params)) + return -EINVAL; + } + + return 0; +} + +/** + * hdd_ocb_register_sta() - Register station with Transport Layer + * @adapter: Pointer to HDD Adapter + * + * This function should be invoked in the OCB Set Schedule callback + * to enable the data path in the TL by calling RegisterSTAClient + * + * Return: 0 on success. -1 on failure. + */ +static int hdd_ocb_register_sta(hdd_adapter_t *adapter) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type sta_desc = {0}; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint8_t peer_id; + + cdf_status = ol_txrx_register_ocb_peer(hdd_ctx->pcds_context, + adapter->macAddressCurrent.bytes, + &peer_id); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("Error registering OCB Self Peer!")); + return -EINVAL; + } + + hdd_ctx->sta_to_adapter[peer_id] = adapter; + + sta_desc.sta_id = peer_id; + sta_desc.is_qos_enabled = 1; + + cdf_status = ol_txrx_register_peer(hdd_rx_packet_cbk, + &sta_desc); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("Failed to register. Status= %d [0x%08X]"), + cdf_status, cdf_status); + return -EINVAL; + } + + if (pHddStaCtx->conn_info.staId[0] != 0 && + pHddStaCtx->conn_info.staId[0] != peer_id) { + hddLog(LOGE, FL("The ID for the OCB station has changed.")); + } + + pHddStaCtx->conn_info.staId[0] = peer_id; + cdf_copy_macaddr(&pHddStaCtx->conn_info.peerMacAddress[0], + &adapter->macAddressCurrent); + + return 0; +} + +/** + * hdd_ocb_config_new() - Creates a new OCB configuration + * @num_channels: the number of channels + * @num_schedule: the schedule size + * @ndl_chan_list_len: length in bytes of the NDL chan blob + * @ndl_active_state_list_len: length in bytes of the active state blob + * + * Return: A pointer to the OCB configuration struct, NULL on failure. + */ +static struct sir_ocb_config *hdd_ocb_config_new(int num_channels, + int num_schedule, + int ndl_chan_list_len, + int ndl_active_state_list_len) +{ + struct sir_ocb_config *ret = 0; + uint32_t len; + void *cursor; + + if (num_channels > CFG_TGT_NUM_OCB_CHANNELS || + num_schedule > CFG_TGT_NUM_OCB_SCHEDULES) + return NULL; + + len = sizeof(*ret) + + num_channels * sizeof(struct sir_ocb_config_channel) + + num_schedule * sizeof(struct sir_ocb_config_sched) + + ndl_chan_list_len + + ndl_active_state_list_len; + + cursor = cdf_mem_malloc(len); + if (!cursor) + goto fail; + + cdf_mem_zero(cursor, len); + ret = cursor; + cursor += sizeof(*ret); + + ret->channel_count = num_channels; + ret->channels = cursor; + cursor += num_channels * sizeof(*ret->channels); + + ret->schedule_size = num_schedule; + ret->schedule = cursor; + cursor += num_schedule * sizeof(*ret->schedule); + + ret->dcc_ndl_chan_list = cursor; + cursor += ndl_chan_list_len; + + ret->dcc_ndl_active_state_list = cursor; + cursor += ndl_active_state_list_len; + + return ret; + +fail: + cdf_mem_free(ret); + return NULL; +} + +/** + * hdd_ocb_set_config_callback() - OCB set config callback function + * @context_ptr: OCB call context + * @response_ptr: Pointer to response structure + * + * This function is registered as a callback with the lower layers + * and is used to respond with the status of a OCB set config command. + */ +static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_ocb_set_config_response *resp = response_ptr; + + if (!context) + return; + + if (resp && resp->status) + hddLog(LOGE, FL("Operation failed: %d"), resp->status); + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + hdd_adapter_t *adapter = context->adapter; + if (!resp) { + context->status = -EINVAL; + complete(&context->completion_evt); + spin_unlock(&hdd_context_lock); + return; + } + + context->adapter->ocb_set_config_resp = *resp; + spin_unlock(&hdd_context_lock); + if (!resp->status) { + /* + * OCB set config command successful. + * Open the TX data path + */ + if (!hdd_ocb_register_sta(adapter)) { + netif_carrier_on(adapter->dev); + netif_tx_start_all_queues( + adapter->dev); + } + } + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) + complete(&context->completion_evt); + spin_unlock(&hdd_context_lock); + } else { + spin_unlock(&hdd_context_lock); + } +} + +/** + * hdd_ocb_set_config_req() - Send an OCB set config request + * @adapter: a pointer to the adapter + * @config: a pointer to the OCB configuration + * + * Return: 0 on success. + */ +static int hdd_ocb_set_config_req(hdd_adapter_t *adapter, + struct sir_ocb_config *config) +{ + int rc; + CDF_STATUS cdf_status; + struct hdd_ocb_ctxt context = {0}; + + if (hdd_ocb_validate_config(adapter, config)) { + hddLog(LOGE, FL("The configuration is invalid")); + return -EINVAL; + } + + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + hddLog(LOG1, FL("Disabling queues")); + netif_tx_disable(adapter->dev); + netif_carrier_off(adapter->dev); + + /* Call the SME API to set the config */ + cdf_status = sme_ocb_set_config( + ((hdd_context_t *)adapter->pHddCtx)->hHal, &context, + hdd_ocb_set_config_callback, config); + if (cdf_status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error calling SME function.")); + /* Convert from ecdf_status to errno */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + rc = context.status; + goto end; + } + + if (adapter->ocb_set_config_resp.status) { + rc = -EINVAL; + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + if (rc) + hddLog(LOGE, FL("Operation failed: %d"), rc); + return rc; +} + +/** + * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED + * ioctl + * @dev: Pointer to net_device structure + * @iw_request_info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success + */ +static int __iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int rc = 0; + struct dot11p_channel_sched *sched; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct sir_ocb_config *config = NULL; + uint8_t *mac_addr; + int i, j; + struct sir_ocb_config_channel *curr_chan; + + if (wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter))) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + sched = (struct dot11p_channel_sched *)extra; + + /* Scheduled slots same as num channels for compatibility */ + config = hdd_ocb_config_new(sched->num_channels, sched->num_channels, + 0, 0); + if (config == NULL) { + hddLog(LOGE, FL("Failed to allocate memory!")); + return -ENOMEM; + } + + /* Identify the vdev interface */ + config->session_id = adapter->sessionId; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(adapter->pHddCtx, + adapter->ocb_mac_address[i]); + } + adapter->ocb_mac_addr_count = 0; + + config->channel_count = 0; + for (i = 0; i < sched->num_channels; i++) { + if (0 == sched->channels[i].channel_freq) + continue; + + curr_chan = &(config->channels[config->channel_count]); + + curr_chan->chan_freq = sched->channels[i].channel_freq; + /* + * tx_power is divided by 2 because ocb_channel.tx_power is + * in half dB increments and sir_ocb_config_channel.max_pwr + * is in 1 dB increments. + */ + curr_chan->max_pwr = sched->channels[i].tx_power / 2; + curr_chan->bandwidth = sched->channels[i].channel_bandwidth; + /* assume 10 as default if not provided */ + if (curr_chan->bandwidth == 0) + curr_chan->bandwidth = 10; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + if (i == 0) { + cdf_mem_copy(curr_chan->mac_address, + adapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + } else { + mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx); + if (mac_addr == NULL) { + hddLog(LOGE, FL("Cannot obtain mac address")); + rc = -EINVAL; + goto fail; + } + cdf_mem_copy(config->channels[ + config->channel_count].mac_address, + mac_addr, sizeof(tSirMacAddr)); + /* Save the mac address to release later */ + cdf_mem_copy(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count], + mac_addr, + sizeof(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count])); + adapter->ocb_mac_addr_count++; + } + + for (j = 0; j < MAX_NUM_AC; j++) { + curr_chan->qos_params[j].aifsn = + sched->channels[i].qos_params[j].aifsn; + curr_chan->qos_params[j].cwmin = + sched->channels[i].qos_params[j].cwmin; + curr_chan->qos_params[j].cwmax = + sched->channels[i].qos_params[j].cwmax; + } + + config->channel_count++; + } + + /* + * Scheduled slots same as num channels for compatibility with + * legacy use. + */ + for (i = 0; i < sched->num_channels; i++) { + config->schedule[i].chan_freq = sched->channels[i].channel_freq; + config->schedule[i].guard_interval = + sched->channels[i].start_guard_interval; + config->schedule[i].total_duration = + sched->channels[i].duration; + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) { + hddLog(LOGE, FL("Error while setting OCB config")); + goto fail; + } + + rc = 0; + +fail: + cdf_mem_free(config); + return rc; +} + +/** + * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule + * @dev: Pointer to net_device structure + * @iw_request_info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success. + */ +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = { + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = { + .type = NLA_BINARY + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = { + .type = NLA_BINARY + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[ + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, +}; + +/** + * struct wlan_hdd_ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (1/2 dBm) + * @min_pwr: minimum transmit power of the channel (1/2 dBm) + */ +struct wlan_hdd_ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + uint16_t flags; + uint8_t reserved[4]; + struct sir_qos_params qos_params[MAX_NUM_AC]; + uint32_t max_pwr; + uint32_t min_pwr; +}; + +static void wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel( + struct sir_ocb_config_channel *dest, + struct wlan_hdd_ocb_config_channel *src, + uint32_t channel_count) +{ + uint32_t i; + + cdf_mem_zero(dest, channel_count * sizeof(*dest)); + + for (i = 0; i < channel_count; i++) { + dest[i].chan_freq = src[i].chan_freq; + dest[i].bandwidth = src[i].bandwidth; + cdf_mem_copy(dest[i].qos_params, src[i].qos_params, + sizeof(dest[i].qos_params)); + /* + * max_pwr and min_pwr are divided by 2 because + * wlan_hdd_ocb_config_channel.max_pwr and min_pwr + * are in 1/2 dB increments and + * sir_ocb_config_channel.max_pwr and min_pwr are in + * 1 dB increments. + */ + dest[i].max_pwr = src[i].max_pwr / 2; + dest[i].min_pwr = (src[i].min_pwr + 1) / 2; + dest[i].flags = src[i].flags; + } +} + +/** + * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1]; + struct nlattr *channel_array; + struct nlattr *sched_array; + struct nlattr *ndl_chan_list; + uint32_t ndl_chan_list_len; + struct nlattr *ndl_active_state_list; + uint32_t ndl_active_state_list_len; + uint32_t flags = 0; + int i; + int channel_count, schedule_size; + struct sir_ocb_config *config; + int rc = -EINVAL; + uint8_t *mac_addr; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX, + data, + data_len, qca_wlan_vendor_ocb_set_config_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Get the number of channels in the schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) { + hddLog(LOGE, FL("CHANNEL_COUNT is not present")); + return -EINVAL; + } + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]); + + /* Get the size of the channel schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) { + hddLog(LOGE, FL("SCHEDULE_SIZE is not present")); + return -EINVAL; + } + schedule_size = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]); + + /* Get the ndl chan array and the ndl active state array. */ + ndl_chan_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]; + ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0); + + ndl_active_state_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]; + ndl_active_state_list_len = (ndl_active_state_list ? + nla_len(ndl_active_state_list) : 0); + + /* Get the flags */ + if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]) + flags = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]); + + config = hdd_ocb_config_new(channel_count, schedule_size, + ndl_chan_list_len, + ndl_active_state_list_len); + if (config == NULL) { + hddLog(LOGE, FL("Failed to allocate memory!")); + return -ENOMEM; + } + + config->channel_count = channel_count; + config->schedule_size = schedule_size; + config->flags = flags; + + /* Read the channel array */ + channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY]; + if (!channel_array) { + hddLog(LOGE, FL("No channel present")); + goto fail; + } + if (nla_len(channel_array) != channel_count * + sizeof(struct wlan_hdd_ocb_config_channel)) { + hddLog(LOGE, FL("CHANNEL_ARRAY is not the correct size")); + goto fail; + } + wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel( + config->channels, nla_data(channel_array), channel_count); + + /* Identify the vdev interface */ + config->session_id = adapter->sessionId; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(adapter->pHddCtx, + adapter->ocb_mac_address[i]); + } + adapter->ocb_mac_addr_count = 0; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + for (i = 0; i < config->channel_count; i++) { + if (i == 0) { + cdf_mem_copy(config->channels[i].mac_address, + adapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + } else { + mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx); + if (mac_addr == NULL) { + hddLog(LOGE, FL("Cannot obtain mac address")); + goto fail; + } + cdf_mem_copy(config->channels[i].mac_address, + mac_addr, sizeof(tSirMacAddr)); + /* Save the mac address to release later */ + cdf_mem_copy(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count], + config->channels[i].mac_address, + sizeof(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count])); + adapter->ocb_mac_addr_count++; + } + } + + /* Read the schedule array */ + sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY]; + if (!sched_array) { + hddLog(LOGE, FL("No channel present")); + goto fail; + } + if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) { + hddLog(LOGE, FL("SCHEDULE_ARRAY is not the correct size")); + goto fail; + } + cdf_mem_copy(config->schedule, nla_data(sched_array), + nla_len(sched_array)); + + /* Copy the NDL chan array */ + if (ndl_chan_list_len) { + config->dcc_ndl_chan_list_len = ndl_chan_list_len; + cdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list), + nla_len(ndl_chan_list)); + } + + /* Copy the NDL active state array */ + if (ndl_active_state_list_len) { + config->dcc_ndl_active_state_list_len = + ndl_active_state_list_len; + cdf_mem_copy(config->dcc_ndl_active_state_list, + nla_data(ndl_active_state_list), + nla_len(ndl_active_state_list)); + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) + hddLog(LOGE, FL("Error while setting OCB config: %d"), rc); + +fail: + cdf_mem_free(config); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1]; + struct nlattr *utc_attr; + struct nlattr *time_error_attr; + struct sir_ocb_utc *utc; + int rc = -EINVAL; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX, + data, + data_len, qca_wlan_vendor_ocb_set_utc_time_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Read the UTC time */ + utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE]; + if (!utc_attr) { + hddLog(LOGE, FL("UTC_TIME is not present")); + return -EINVAL; + } + if (nla_len(utc_attr) != SIZE_UTC_TIME) { + hddLog(LOGE, FL("UTC_TIME is not the correct size")); + return -EINVAL; + } + + /* Read the time error */ + time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR]; + if (!time_error_attr) { + hddLog(LOGE, FL("UTC_TIME is not present")); + return -EINVAL; + } + if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) { + hddLog(LOGE, FL("UTC_TIME is not the correct size")); + return -EINVAL; + } + + utc = cdf_mem_malloc(sizeof(*utc)); + if (!utc) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + utc->vdev_id = adapter->sessionId; + cdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME); + cdf_mem_copy(utc->time_error, nla_data(time_error_attr), + SIZE_UTC_TIME_ERROR); + + if (sme_ocb_set_utc_time(hdd_ctx->hHal, utc) != CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error while setting UTC time")); + rc = -EINVAL; + } else { + rc = 0; + } + + cdf_mem_free(utc); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpAniSirGlobal mac_ctx = PMAC_STRUCT(WLAN_HDD_GET_HAL_CTX(adapter)); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1]; + struct sir_ocb_timing_advert *timing_advert; + int rc = -EINVAL; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + timing_advert = cdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + cdf_mem_zero(timing_advert, sizeof(*timing_advert)); + timing_advert->vdev_id = adapter->sessionId; + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX, + data, + data_len, + qca_wlan_vendor_ocb_start_timing_advert_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) { + hddLog(LOGE, FL("CHANNEL_FREQ is not present")); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) { + hddLog(LOGE, FL("REPEAT_RATE is not present")); + goto fail; + } + timing_advert->repeat_rate = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]); + + timing_advert->template_length = + sch_gen_timing_advert_frame(mac_ctx, + *(tSirMacAddr *)&adapter->macAddressCurrent.bytes, + &timing_advert->template_value, + &timing_advert->timestamp_offset, + &timing_advert->time_value_offset); + if (timing_advert->template_length <= 0) { + hddLog(LOGE, FL("Error while generating the TA frame")); + goto fail; + } + + if (sme_ocb_start_timing_advert(hdd_ctx->hHal, timing_advert) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error while starting timing advert")); + rc = -EINVAL; + } else { + rc = 0; + } + +fail: + if (timing_advert->template_value) + cdf_mem_free(timing_advert->template_value); + cdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1]; + struct sir_ocb_timing_advert *timing_advert; + int rc = -EINVAL; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + timing_advert = cdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + cdf_mem_zero(timing_advert, sizeof(sizeof(*timing_advert))); + timing_advert->vdev_id = adapter->sessionId; + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX, + data, + data_len, + qca_wlan_vendor_ocb_stop_timing_advert_policy)) { + hddLog(LOGE, FL("Invalid ATTR")); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) { + hddLog(LOGE, FL("CHANNEL_FREQ is not present")); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]); + + if (sme_ocb_stop_timing_advert(hdd_ctx->hHal, timing_advert) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error while stopping timing advert")); + rc = -EINVAL; + } else { + rc = 0; + } + +fail: + cdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_ocb_get_tsf_timer_callback(void *context_ptr, + void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_ocb_get_tsf_timer_response *response = response_ptr; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + context->adapter->ocb_get_tsf_timer_resp = *response; + context->status = 0; + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct sk_buff *nl_resp = 0; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int rc = -EINVAL; + struct sir_ocb_get_tsf_timer request = {0}; + struct hdd_ocb_ctxt context = {0}; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + request.vdev_id = adapter->sessionId; + /* Call the SME function */ + rc = sme_ocb_get_tsf_timer(hdd_ctx->hHal, &context, + hdd_ocb_get_tsf_timer_callback, + &request); + if (rc) { + hddLog(LOGE, FL("Error calling SME function")); + /* Need to convert from ecdf_status to errno. */ + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hddLog(LOGE, FL("Operation timed out")); + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + hddLog(LOGE, FL("Operation failed: %d"), context.status); + rc = context.status; + goto end; + } + + /* Allocate the buffer for the response. */ + nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 2 * sizeof(uint32_t) + NLMSG_HDRLEN); + + if (!nl_resp) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + rc = -ENOMEM; + goto end; + } + + hddLog(LOGE, FL("Got TSF timer response, high=%d, low=%d"), + adapter->ocb_get_tsf_timer_resp.timer_high, + adapter->ocb_get_tsf_timer_resp.timer_low); + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + adapter->ocb_get_tsf_timer_resp.timer_high); + if (rc) + goto end; + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + adapter->ocb_get_tsf_timer_resp.timer_low); + if (rc) + goto end; + + /* Send the response. */ + rc = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_reply failed: %d"), rc); + goto end; + } + +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + if (nl_resp) + kfree_skb(nl_resp); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_dcc_get_stats_callback() - Callback to get stats command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_dcc_get_stats_response *response = response_ptr; + struct sir_dcc_get_stats_response *hdd_resp; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + /* + * If the response is hanging around from the previous + * request, delete it + */ + if (context->adapter->dcc_get_stats_resp) { + cdf_mem_free( + context->adapter->dcc_get_stats_resp); + } + context->adapter->dcc_get_stats_resp = + cdf_mem_malloc(sizeof( + *context->adapter->dcc_get_stats_resp) + + response->channel_stats_array_len); + if (context->adapter->dcc_get_stats_resp) { + hdd_resp = context->adapter->dcc_get_stats_resp; + *hdd_resp = *response; + hdd_resp->channel_stats_array = + (void *)hdd_resp + sizeof(*hdd_resp); + cdf_mem_copy(hdd_resp->channel_stats_array, + response->channel_stats_array, + response->channel_stats_array_len); + context->status = 0; + } else { + context->status = -ENOMEM; + } + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t channel_count = 0; + uint32_t request_array_len = 0; + void *request_array = 0; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1]; + struct sk_buff *nl_resp = 0; + int rc = -EINVAL; + struct sir_dcc_get_stats request = {0}; + struct hdd_ocb_ctxt context = {0}; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX, + data, + data_len, + qca_wlan_vendor_dcc_get_stats)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Validate all the parameters are present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) { + hddLog(LOGE, FL("Parameters are not present.")); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]); + request_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + request_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + request.vdev_id = adapter->sessionId; + request.channel_count = channel_count; + request.request_array_len = request_array_len; + request.request_array = request_array; + + /* Call the SME function. */ + rc = sme_dcc_get_stats(hdd_ctx->hHal, &context, + hdd_dcc_get_stats_callback, + &request); + if (rc) { + hddLog(LOGE, FL("Error calling SME function")); + /* Need to convert from cdf_status to errno. */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hddLog(LOGE, FL("Operation failed: %d"), rc); + rc = -ETIMEDOUT; + goto end; + } + + if (context.status) { + hddLog(LOGE, FL("There was error: %d"), context.status); + rc = context.status; + goto end; + } + + if (!adapter->dcc_get_stats_resp) { + hddLog(LOGE, FL("The response was NULL")); + rc = -EINVAL; + goto end; + } + + /* Allocate the buffer for the response. */ + nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(uint32_t) + + adapter->dcc_get_stats_resp->channel_stats_array_len + + NLMSG_HDRLEN); + if (!nl_resp) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + rc = -ENOMEM; + goto end; + } + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + adapter->dcc_get_stats_resp->num_channels); + if (rc) + goto end; + rc = nla_put(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + adapter->dcc_get_stats_resp->channel_stats_array_len, + adapter->dcc_get_stats_resp->channel_stats_array); + if (rc) + goto end; + + /* Send the response. */ + rc = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hddLog(LOGE, FL("cfg80211_vendor_cmd_reply failed: %d"), rc); + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + cdf_mem_free(adapter->dcc_get_stats_resp); + adapter->dcc_get_stats_resp = NULL; + spin_unlock(&hdd_context_lock); + if (nl_resp) + kfree_skb(nl_resp); + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1]; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX, + data, + data_len, + qca_wlan_vendor_dcc_clear_stats)) { + hddLog(LOGE, FL("Invalid ATTR")); + return -EINVAL; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) { + hddLog(LOGE, FL("Parameters are not present.")); + return -EINVAL; + } + + /* Call the SME function */ + if (sme_dcc_clear_stats(hdd_ctx->hHal, adapter->sessionId, + nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Error calling SME function.")); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_dcc_update_ndl_callback() - Callback to update NDL command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_dcc_update_ndl_response *response = response_ptr; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + context->adapter->dcc_update_ndl_resp = *response; + context->status = 0; + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1]; + struct sir_dcc_update_ndl request; + uint32_t channel_count; + uint32_t ndl_channel_array_len; + void *ndl_channel_array; + uint32_t ndl_active_state_array_len; + void *ndl_active_state_array; + int rc = -EINVAL; + struct hdd_ocb_ctxt context = {0}; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + goto end; + } + + if (adapter->device_mode != WLAN_HDD_OCB) { + hddLog(LOGE, FL("Device not in OCB mode!")); + goto end; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hddLog(LOGE, FL("The device has not been started")); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX, + data, + data_len, + qca_wlan_vendor_dcc_update_ndl)) { + hddLog(LOGE, FL("Invalid ATTR")); + goto end; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) { + hddLog(LOGE, FL("Parameters are not present.")); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]); + ndl_channel_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_channel_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_active_state_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + ndl_active_state_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + /* Copy the parameters to the request structure. */ + request.vdev_id = adapter->sessionId; + request.channel_count = channel_count; + request.dcc_ndl_chan_list_len = ndl_channel_array_len; + request.dcc_ndl_chan_list = ndl_channel_array; + request.dcc_ndl_active_state_list_len = ndl_active_state_array_len; + request.dcc_ndl_active_state_list = ndl_active_state_array; + + /* Call the SME function */ + rc = sme_dcc_update_ndl(hdd_ctx->hHal, &context, + hdd_dcc_update_ndl_callback, + &request); + if (rc) { + hddLog(LOGE, FL("Error calling SME function.")); + /* Convert from cdf_status to errno */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hddLog(LOGE, FL("Operation timed out")); + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + hddLog(LOGE, FL("Operation failed: %d"), context.status); + rc = context.status; + goto end; + } + + if (adapter->dcc_update_ndl_resp.status) { + hddLog(LOGE, FL("Operation returned: %d"), + adapter->dcc_update_ndl_resp.status); + rc = -EINVAL; + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event + * @context_ptr: request context + * @response_ptr: response data + */ +static void wlan_hdd_dcc_stats_event_callback(void *context_ptr, + void *response_ptr) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context_ptr; + struct sir_dcc_get_stats_response *resp = response_ptr; + struct sk_buff *vendor_event; + + ENTER(); + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, sizeof(uint32_t) + resp->channel_stats_array_len + + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + resp->num_channels) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + resp->channel_stats_array_len, + resp->channel_stats_array)) { + hddLog(LOGE, FL("nla put failed")); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events + * @hdd_ctx: hdd context + */ +void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx) +{ + int rc; + + rc = sme_register_for_dcc_stats_event(hdd_ctx->hHal, hdd_ctx, + wlan_hdd_dcc_stats_event_callback); + if (rc) + hddLog(LOGE, FL("Register callback failed: %d"), rc); +} diff --git a/core/hdd/src/wlan_hdd_ocb.h b/core/hdd/src/wlan_hdd_ocb.h new file mode 100644 index 0000000000..0ca97bf607 --- /dev/null +++ b/core/hdd/src/wlan_hdd_ocb.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_OCB_H +#define __WLAN_HDD_OCB_H + +#include +#include "sir_api.h" + +#define WLAN_OCB_CHANNEL_MAX 5 + +/** + * struct ocb_qos_params - QoS Parameters for each AC + * @aifsn: Arbitration Inter-Frame Spacing + * @cwmin: Contention Window (Min) + * @cwmax: Contention Window (Max) + */ +struct ocb_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct ocb_channel - Parameters for each OCB channel + * @channel_freq: Channel Center Frequency (MHz) + * @duration: Channel Duration (ms) + * @start_guard_interval: Start Guard Interval (ms) + * @channel_bandwidth: Channel Bandwidth (MHz) + * @tx_power: Transmit Power (1/2 dBm) + * @tx_rate: Transmit Data Rate (mbit) + * @qos_params: Array of QoS Parameters + * @per_packet_rx_stats: Enable per packet RX statistics + */ +struct ocb_channel { + uint32_t channel_freq; + uint32_t duration; + uint32_t start_guard_interval; + uint32_t channel_bandwidth; + uint32_t tx_power; + uint32_t tx_rate; + struct ocb_qos_params qos_params[MAX_NUM_AC]; + uint32_t per_packet_rx_stats; +}; + +/** + * struct dot11p_channel_sched - OCB channel schedule + * @num_channels: Number of channels + * @channels: Array of channel parameters + * @off_channel_tx: Enable off channel TX + */ +struct dot11p_channel_sched { + uint32_t num_channels; + struct ocb_channel channels[WLAN_OCB_CHANNEL_MAX]; + uint32_t off_channel_tx; +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_config - vendor subcmd to set ocb config + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE: size of the schedule + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY: array of channels + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY: + * array of channels to be scheduled + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY: + * array of NDL channel information + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY: + * array of NDL active state configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS: + * flag to set the absolute expiry + */ +enum qca_wlan_vendor_attr_ocb_set_config { + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_utc_time - vendor subcmd to set UTC time + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE: + * the UTC time as an array of 10 bytes + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR: + * the time error as an array of 5 bytes + */ +enum qca_wlan_vendor_attr_ocb_set_utc_time { + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_start_timing_advert - vendor subcmd to start + sending timing advert + frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ: + * channel frequency on which to send the frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE: + * number of times the frame is sent in 5 seconds + */ +enum qca_wlan_vendor_attr_ocb_start_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_stop_timing_advert - vendor subcmd to stop + * timing advert + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ: + * the channel frequency on which to stop the timing advert + */ +enum qca_wlan_vendor_attr_ocb_stop_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_tsf_response - vendor subcmd to get TSF + * timer value + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH: + * higher 32 bits of the timer + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW: + * lower 32 bits of the timer + */ +enum qca_wlan_vendor_attr_ocb_get_tsf_resp { + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats - vendor subcmd to get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY + * array of the channel and information being requested + */ +enum qca_wlan_vendor_attr_dcc_get_stats { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats_resp - response event from get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY + * array of the information being requested + */ +enum qca_wlan_vendor_attr_dcc_get_stats_resp { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_clear_stats - vendor subcmd to clear DCC stats + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP: + * mask of the type of stats to be cleared + */ +enum qca_wlan_vendor_attr_dcc_clear_stats { + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_config - vendor subcmd to update dcc + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY: the array of NDL + * channel info + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY: the array of + * NDL active states + */ +enum qca_wlan_vendor_attr_dcc_update_ndl { + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST - 1, +}; + +void hdd_set_dot11p_config(hdd_context_t *hdd_ctx); + +void hdd_remove_ocb_tx_header(struct sk_buff *skb); + +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx); + +#endif /* __WLAN_HDD_OCB_H */ diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c new file mode 100644 index 0000000000..63ae62ef9a --- /dev/null +++ b/core/hdd/src/wlan_hdd_oemdata.c @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * DOC: wlan_hdd_oemdata.c + * + * Support for generic OEM Data Request handling + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "qwlan_version.h" +#include "cds_utils.h" +#include "wma.h" + +static struct hdd_context_s *p_hdd_ctx; + +/** + * hdd_oem_data_req_callback() - OEM Data request callback handler + * @hHal: MAC handle + * @pContext: User context. For this callback the net device was registered + * @oemDataReqID: The ID of the request + * @oemDataReqStatus: Status of the request + * + * This function reports the results of the request to user space + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_oem_data_req_callback(tHalHandle hHal, + void *pContext, + uint32_t oemDataReqID, + eOemDataReqStatus oemDataReqStatus) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct net_device *dev = (struct net_device *)pContext; + union iwreq_data wrqu; + char buffer[IW_CUSTOM_MAX + 1]; + + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buffer, '\0', sizeof(buffer)); + + if (oemDataReqStatus == eOEM_DATA_REQ_FAILURE) { + snprintf(buffer, IW_CUSTOM_MAX, "QCOM: OEM-DATA-REQ-FAILED"); + hddLog(LOGW, "%s: oem data req %d failed", __func__, + oemDataReqID); + } else if (oemDataReqStatus == eOEM_DATA_REQ_INVALID_MODE) { + snprintf(buffer, IW_CUSTOM_MAX, + "QCOM: OEM-DATA-REQ-INVALID-MODE"); + hddLog(LOGW, + "%s: oem data req %d failed because the driver is in invalid mode (IBSS|AP)", + __func__, oemDataReqID); + } else { + snprintf(buffer, IW_CUSTOM_MAX, "QCOM: OEM-DATA-REQ-SUCCESS"); + } + + wrqu.data.pointer = buffer; + wrqu.data.length = strlen(buffer); + + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buffer); + + return status; +} + +/** + * iw_get_oem_data_cap() - Get OEM Data Capabilities + * @dev: net device upon which the request was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl data payload + * + * This function gets the capability information for OEM Data Request + * and Response. + * + * Return: 0 for success, negative errno value on failure + */ +int iw_get_oem_data_cap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + CDF_STATUS status; + t_iw_oem_data_cap oemDataCap; + t_iw_oem_data_cap *pHddOemDataCap; + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *pHddContext; + struct hdd_config *pConfig; + uint32_t numChannels; + uint8_t chanList[OEM_CAP_MAX_NUM_CHANNELS]; + uint32_t i; + int ret; + + ENTER(); + + pHddContext = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddContext); + if (0 != ret) + return ret; + + pConfig = pHddContext->config; + if (!pConfig) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s:HDD configuration is null", __func__); + return -ENOENT; + } + + do { + cdf_mem_zero(&oemDataCap, sizeof(oemDataCap)); + strlcpy(oemDataCap.oem_target_signature, OEM_TARGET_SIGNATURE, + OEM_TARGET_SIGNATURE_LEN); + oemDataCap.oem_target_type = pHddContext->target_type; + oemDataCap.oem_fw_version = pHddContext->target_fw_version; + oemDataCap.driver_version.major = QWLAN_VERSION_MAJOR; + oemDataCap.driver_version.minor = QWLAN_VERSION_MINOR; + oemDataCap.driver_version.patch = QWLAN_VERSION_PATCH; + oemDataCap.driver_version.build = QWLAN_VERSION_BUILD; + oemDataCap.allowed_dwell_time_min = + pConfig->nNeighborScanMinChanTime; + oemDataCap.allowed_dwell_time_max = + pConfig->nNeighborScanMaxChanTime; + oemDataCap.curr_dwell_time_min = + sme_get_neighbor_scan_min_chan_time(pHddContext->hHal, + pAdapter->sessionId); + oemDataCap.curr_dwell_time_max = + sme_get_neighbor_scan_max_chan_time(pHddContext->hHal, + pAdapter->sessionId); + oemDataCap.supported_bands = pConfig->nBandCapability; + + /* request for max num of channels */ + numChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + status = sme_get_cfg_valid_channels(pHddContext->hHal, + &chanList[0], &numChannels); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s:failed to get valid channel list", + __func__); + return -ENOENT; + } else { + /* make sure num channels is not more than chan list array */ + if (numChannels > OEM_CAP_MAX_NUM_CHANNELS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s:Num of channels(%d) more than length(%d) of chanlist", + __func__, numChannels, + OEM_CAP_MAX_NUM_CHANNELS); + return -ENOMEM; + } + + oemDataCap.num_channels = numChannels; + for (i = 0; i < numChannels; i++) { + oemDataCap.channel_list[i] = chanList[i]; + } + } + + pHddOemDataCap = (t_iw_oem_data_cap *) (extra); + cdf_mem_copy(pHddOemDataCap, &oemDataCap, + sizeof(*pHddOemDataCap)); + } while (0); + + EXIT(); + return 0; +} + +/** + * send_oem_reg_rsp_nlink_msg() - send oem registration response + * + * This function sends oem message to registered application process + * + * Return: none + */ +static void send_oem_reg_rsp_nlink_msg(void) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + uint8_t *buf; + uint8_t *numInterfaces; + uint8_t *deviceMode; + uint8_t *vdevId; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + CDF_STATUS status = 0; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return; + } + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_APP_REG_RSP; + + /* Fill message body: + * First byte will be number of interfaces, followed by + * two bytes for each interfaces + * - one byte for device mode + * - one byte for vdev id + */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + numInterfaces = buf++; + *numInterfaces = 0; + + /* Iterate through each of the adapters and fill device mode and vdev id */ + status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode); + while ((CDF_STATUS_SUCCESS == status) && pAdapterNode) { + pAdapter = pAdapterNode->pAdapter; + if (pAdapter) { + deviceMode = buf++; + vdevId = buf++; + *deviceMode = pAdapter->device_mode; + *vdevId = pAdapter->sessionId; + (*numInterfaces)++; + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: numInterfaces: %d, deviceMode: %d, vdevId: %d", + __func__, *numInterfaces, *deviceMode, + *vdevId); + } + status = hdd_get_next_adapter(p_hdd_ctx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + aniHdr->length = + sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sending App Reg Response length (%d) to process pid (%d)", + __func__, aniHdr->length, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/** + * send_oem_err_rsp_nlink_msg() - send oem error response + * @app_pid: PID of oem application process + * @error_code: response error code + * + * This function sends error response to oem app + * + * Return: none + */ +static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + uint8_t *buf; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_ERROR; + aniHdr->length = sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length); + + /* message body will contain one byte of error code */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf = error_code; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length)); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sending oem error response to process pid (%d)", + __func__, app_pid); + + (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + + return; +} + +/** + * hdd_send_oem_data_rsp_msg() - send oem data response + * @length: length of the OEM Data Response message + * @oemDataRsp: the actual OEM Data Response message + * + * This function sends an OEM Data Response message to a registered + * application process over the netlink socket. + * + * Return: 0 for success, non zero for failure + */ +void hdd_send_oem_data_rsp_msg(int length, uint8_t *oemDataRsp) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + uint8_t *oemData; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return; + } + + if (length > OEM_DATA_RSP_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid length of Oem Data response", __func__); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE), + GFP_KERNEL); + if (skb == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_DATA_RSP; + + aniHdr->length = length; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + oemData = (uint8_t *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + cdf_mem_copy(oemData, oemDataRsp, length); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sending Oem Data Response of len (%d) to process pid (%d)", + __func__, length, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/** + * oem_process_data_req_msg() - process oem data request + * @oemDataLen: Length to OEM Data buffer + * @oemData: Pointer to OEM Data buffer + * + * This function sends oem message to SME + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS oem_process_data_req_msg(int oemDataLen, char *oemData) +{ + hdd_adapter_t *pAdapter = NULL; + tOemDataReqConfig oemDataReqConfig; + uint32_t oemDataReqID = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* for now, STA interface only */ + pAdapter = hdd_get_adapter(p_hdd_ctx, WLAN_HDD_INFRA_STATION); + if (!pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: No adapter for STA mode", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (!oemData) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: oemData is null", __func__); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_zero(&oemDataReqConfig, sizeof(tOemDataReqConfig)); + + cdf_mem_copy((&oemDataReqConfig)->oemDataReq, oemData, oemDataLen); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: calling sme_oem_data_req", __func__); + + status = sme_oem_data_req(p_hdd_ctx->hHal, + pAdapter->sessionId, + &oemDataReqConfig, + &oemDataReqID, + &hdd_oem_data_req_callback, pAdapter->dev); + return status; +} + +/** + * oem_process_channel_info_req_msg() - process oem channel_info request + * @numOfChannels: number of channels + * @chanList: list of channel information + * + * This function responds with channel info to oem process + * + * Return: 0 for success, non zero for failure + */ +static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tHddChannelInfo *pHddChanInfo; + tHddChannelInfo hddChanInfo; + uint8_t chanId; + uint32_t reg_info_1; + uint32_t reg_info_2; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int i; + uint8_t *buf; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: invalid dest pid", __func__); + return -EPERM; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) + + numOfChannels * sizeof(tHddChannelInfo)), + GFP_KERNEL); + if (skb == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return -ENOMEM; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP; + + aniHdr->length = + sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + /* First byte of message body will have num of channels */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf++ = numOfChannels; + + /* Next follows channel info struct for each channel id. + * If chan id is wrong or SME returns failure for a channel + * then fill in 0 in channel info for that particular channel + */ + for (i = 0; i < numOfChannels; i++) { + pHddChanInfo = (tHddChannelInfo *) ((char *)buf + + i * + sizeof(tHddChannelInfo)); + + chanId = chanList[i]; + status = sme_get_reg_info(p_hdd_ctx->hHal, chanId, + ®_info_1, ®_info_2); + if (CDF_STATUS_SUCCESS == status) { + /* copy into hdd chan info struct */ + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = cds_chan_to_freq(chanId); + hddChanInfo.band_center_freq1 = hddChanInfo.mhz; + hddChanInfo.band_center_freq2 = 0; + + hddChanInfo.info = 0; + if (CHANNEL_STATE_DFS == + cds_get_channel_state(chanId)) + WMI_SET_CHANNEL_FLAG(&hddChanInfo, + WMI_CHAN_FLAG_DFS); + hddChanInfo.reg_info_1 = reg_info_1; + hddChanInfo.reg_info_2 = reg_info_2; + } else { + /* channel info is not returned, fill in zeros in channel + * info struct + */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sme_get_reg_info failed for chan (%d), return info 0", + __func__, chanId); + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = 0; + hddChanInfo.band_center_freq1 = 0; + hddChanInfo.band_center_freq2 = 0; + hddChanInfo.info = 0; + hddChanInfo.reg_info_1 = 0; + hddChanInfo.reg_info_2 = 0; + } + cdf_mem_copy(pHddChanInfo, &hddChanInfo, + sizeof(tHddChannelInfo)); + } + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sending channel info resp for num channels (%d) to pid (%d)", + __func__, numOfChannels, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return 0; +} + +/** + * hdd_send_peer_status_ind_to_oem_app() - + * Function to send peer status to a registered application + * @peerMac: MAC address of peer + * @peerStatus: ePeerConnected or ePeerDisconnected + * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @sessionId: SME session id, i.e. vdev_id + * @chan_info: operating channel information + * + * Return: none + */ +void hdd_send_peer_status_ind_to_oem_app(struct cdf_mac_addr *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + tSirSmeChanInfo *chan_info) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tPeerStatusInfo *pPeerInfo; + + if (!p_hdd_ctx || !p_hdd_ctx->hHal) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Either HDD Ctx is null or Hal Ctx is null", + __func__); + return; + } + + /* check if oem app has registered and pid is valid */ + if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: OEM app is not registered(%d) or pid is invalid(%d)", + __func__, p_hdd_ctx->oem_app_registered, + p_hdd_ctx->oem_pid); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + + sizeof(tPeerStatusInfo)), + GFP_KERNEL); + if (skb == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: alloc_skb failed", __func__); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_PEER_STATUS_IND; + + aniHdr->length = sizeof(tPeerStatusInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + + cdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes, + sizeof(peerMac->bytes)); + pPeerInfo->peer_status = peerStatus; + pPeerInfo->vdev_id = sessionId; + pPeerInfo->peer_capability = peerTimingMeasCap; + pPeerInfo->reserved0 = 0; + + if (chan_info) { + pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = chan_info->mhz; + pPeerInfo->peer_chan_info.band_center_freq1 = + chan_info->band_center_freq1; + pPeerInfo->peer_chan_info.band_center_freq2 = + chan_info->band_center_freq2; + pPeerInfo->peer_chan_info.info = chan_info->info; + pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1; + pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2; + } else { + pPeerInfo->peer_chan_info.chan_id = 0; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = 0; + pPeerInfo->peer_chan_info.band_center_freq1 = 0; + pPeerInfo->peer_chan_info.band_center_freq2 = 0; + pPeerInfo->peer_chan_info.info = 0; + pPeerInfo->peer_chan_info.reg_info_1 = 0; + pPeerInfo->peer_chan_info.reg_info_2 = 0; + } + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: sending peer " MAC_ADDRESS_STR + " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)" + " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d)," + " info (0x%x), frequency (%d),reg info 1 (0x%x)," + " reg info 2 (0x%x)", __func__, + MAC_ADDR_ARRAY(peerMac->bytes), + peerStatus, peerTimingMeasCap, + sessionId, pPeerInfo->peer_chan_info.chan_id, + p_hdd_ctx->oem_pid, + pPeerInfo->peer_chan_info.band_center_freq1, + pPeerInfo->peer_chan_info.band_center_freq2, + pPeerInfo->peer_chan_info.info, + pPeerInfo->peer_chan_info.mhz, + pPeerInfo->peer_chan_info.reg_info_1, + pPeerInfo->peer_chan_info.reg_info_2); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/* + * Callback function invoked by Netlink service for all netlink + * messages (from user space) addressed to WLAN_NL_MSG_OEM + */ + +/** + * oem_msg_callback() - callback invoked by netlink service + * @skb: skb with netlink message + * + * This function gets invoked by netlink service when a message + * is received from user space addressed to WLAN_NL_MSG_OEM + * + * Return: zero on success + * On error, error number will be returned. + */ +static int oem_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + tAniMsgHdr *msg_hdr; + int ret; + char *sign_str = NULL; + nlh = (struct nlmsghdr *)skb->data; + + if (!nlh) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Netlink header null", __func__); + return -EPERM; + } + + ret = wlan_hdd_validate_context(p_hdd_ctx); + if (0 != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("HDD context is not valid")); + return ret; + } + + msg_hdr = NLMSG_DATA(nlh); + + if (!msg_hdr) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Message header null", __func__); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_NULL_MESSAGE_HEADER); + return -EPERM; + } + + if (nlh->nlmsg_len < + NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)", + __func__, nlh->nlmsg_len, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + switch (msg_hdr->type) { + case ANI_MSG_APP_REG_REQ: + /* Registration request is only allowed for Qualcomm Application */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received App Req Req from App process pid(%d), len(%d)", + __func__, nlh->nlmsg_pid, msg_hdr->length); + + sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && + (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Valid App Req Req from oem app process pid(%d)", + __func__, nlh->nlmsg_pid); + + p_hdd_ctx->oem_app_registered = true; + p_hdd_ctx->oem_pid = nlh->nlmsg_pid; + send_oem_reg_rsp_nlink_msg(); + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid signature in App Reg Request from pid(%d)", + __func__, nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_SIGNATURE); + return -EPERM; + } + break; + + case ANI_MSG_OEM_DATA_REQ: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received Oem Data Request length(%d) from pid: %d", + __func__, msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: OEM DataReq: app not registered(%d) or incorrect pid(%d)", + __func__, p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid length (%d) in Oem Data Request", + __func__, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_data_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + + sizeof(tAniMsgHdr))); + break; + + case ANI_MSG_CHANNEL_INFO_REQ: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received channel info request, num channel(%d) from pid: %d", + __func__, msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Chan InfoReq: app not registered(%d) or incorrect pid(%d)", + __func__, p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + /* message length contains list of channel ids */ + if ((!msg_hdr->length) || + (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid length (%d) in channel info request", + __func__, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_channel_info_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + + sizeof(tAniMsgHdr))); + break; + + default: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Received Invalid message type (%d), length (%d)", + __func__, msg_hdr->type, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_TYPE); + return -EPERM; + } + return 0; +} + +static int __oem_msg_callback(struct sk_buff *skb) +{ + int ret; + + cds_ssr_protect(__func__); + ret = oem_msg_callback(skb); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * oem_activate_service() - Activate oem message handler + * @hdd_ctx: pointer to global HDD context + * + * This function registers a handler to receive netlink message from + * an OEM application process. + * + * Return: zero on success + * On error, error number will be returned. + */ +int oem_activate_service(struct hdd_context_s *hdd_ctx) +{ + p_hdd_ctx = hdd_ctx; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback); +} + +#endif diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c new file mode 100644 index 0000000000..a6d5accaad --- /dev/null +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -0,0 +1,2626 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * @file wlan_hdd_p2p.c + * + * @brief WLAN Host Device Driver implementation for P2P commands interface + * + */ + +#include +#include +#include +#include "sme_api.h" +#include "sme_qos_api.h" +#include "wlan_hdd_p2p.h" +#include "sap_api.h" +#include "wlan_hdd_main.h" +#include "cdf_trace.h" +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_trace.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cds_sched.h" +#include "cds_concurrency.h" + +/* Ms to Micro Sec */ +#define MS_TO_MUS(x) ((x) * 1000) + +static uint8_t *hdd_get_action_string(uint16_t MsgType) +{ + switch (MsgType) { + CASE_RETURN_STRING(SIR_MAC_ACTION_SPECTRUM_MGMT); + CASE_RETURN_STRING(SIR_MAC_ACTION_QOS_MGMT); + CASE_RETURN_STRING(SIR_MAC_ACTION_DLP); + CASE_RETURN_STRING(SIR_MAC_ACTION_PUBLIC_USAGE); + CASE_RETURN_STRING(SIR_MAC_ACTION_RRM); + CASE_RETURN_STRING(SIR_MAC_ACTION_FAST_BSS_TRNST); + CASE_RETURN_STRING(SIR_MAC_ACTION_HT); + CASE_RETURN_STRING(SIR_MAC_ACTION_SA_QUERY); + CASE_RETURN_STRING(SIR_MAC_ACTION_PROT_DUAL_PUB); + CASE_RETURN_STRING(SIR_MAC_ACTION_WNM); + CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM); + CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS); + CASE_RETURN_STRING(SIR_MAC_ACITON_MESH); + CASE_RETURN_STRING(SIR_MAC_ACTION_MHF); + CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED); + CASE_RETURN_STRING(SIR_MAC_ACTION_WME); + CASE_RETURN_STRING(SIR_MAC_ACTION_VHT); + default: + return "UNKNOWN"; + } +} + +#ifdef WLAN_FEATURE_P2P_DEBUG +#define MAX_P2P_ACTION_FRAME_TYPE 9 +const char *p2p_action_frame_type[] = { "GO Negotiation Request", + "GO Negotiation Response", + "GO Negotiation Confirmation", + "P2P Invitation Request", + "P2P Invitation Response", + "Device Discoverability Request", + "Device Discoverability Response", + "Provision Discovery Request", + "Provision Discovery Response"}; + +/* We no need to protect this variable since + * there is no chance of race to condition + * and also not make any complicating the code + * just for debugging log + */ +tP2PConnectionStatus global_p2p_connection_status = P2P_NOT_ACTIVE; + +#endif +#define MAX_TDLS_ACTION_FRAME_TYPE 11 +const char *tdls_action_frame_type[] = { "TDLS Setup Request", + "TDLS Setup Response", + "TDLS Setup Confirm", + "TDLS Teardown", + "TDLS Peer Traffic Indication", + "TDLS Channel Switch Request", + "TDLS Channel Switch Response", + "TDLS Peer PSM Request", + "TDLS Peer PSM Response", + "TDLS Peer Traffic Response", + "TDLS Discovery Request"}; + +static bool wlan_hdd_is_type_p2p_action(const u8 *buf) +{ + const u8 *ouiPtr; + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET] != + WLAN_HDD_PUBLIC_ACTION_FRAME) { + return false; + } + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET] != + WLAN_HDD_VENDOR_SPECIFIC_ACTION) { + return false; + } + + ouiPtr = &buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET]; + + if (WPA_GET_BE24(ouiPtr) != WLAN_HDD_WFA_OUI) { + return false; + } + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET] != + WLAN_HDD_WFA_P2P_OUI_TYPE) { + return false; + } + + return true; +} + +static bool hdd_p2p_is_action_type_rsp(const u8 *buf) +{ + tActionFrmType actionFrmType; + + if (wlan_hdd_is_type_p2p_action(buf)) { + actionFrmType = + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET]; + if (actionFrmType != WLAN_HDD_INVITATION_REQ + && actionFrmType != WLAN_HDD_GO_NEG_REQ + && actionFrmType != WLAN_HDD_DEV_DIS_REQ + && actionFrmType != WLAN_HDD_PROV_DIS_REQ) + return true; + } + + return false; +} + +static +CDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx, + CDF_STATUS status, uint32_t scan_id) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pCtx; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return CDF_STATUS_E_FAILURE; + } + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + + if (pRemainChanCtx == NULL) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOGW, + "%s: No Rem on channel pending for which Rsp is received", + __func__); + return CDF_STATUS_SUCCESS; + } + + hddLog(LOG1, "Received remain on channel rsp"); + cdf_mc_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer); + cdf_mc_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer); + + cfgState->remain_on_chan_ctx = NULL; + /* + * Resetting the roc in progress early ensures that the subsequent + * roc requests are immediately processed without being queued + */ + pAdapter->is_roc_inprogress = false; + /* + * If the allow suspend is done later, the scheduled roc wil prevent + * the system from going into suspend and immediately this logic + * will allow the system to go to suspend breaking the exising logic. + * Basically, the system must not go into suspend while roc is in + * progress. + */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) { + if (cfgState->buf) { + hddLog(LOGP, + "%s: We need to receive yet an ack from one of tx packet", + __func__); + } + cfg80211_remain_on_channel_expired( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + pRemainChanCtx->dev-> + ieee80211_ptr, +#else + pRemainChanCtx->dev, +#endif + pRemainChanCtx-> + cookie, + &pRemainChanCtx->chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + pRemainChanCtx-> + chan_type, +#endif + GFP_KERNEL); + pAdapter->last_roc_ts = cdf_mc_timer_get_system_time(); + } + + /* Schedule any pending RoC: Any new roc request during this time + * would have got queued in 'wlan_hdd_request_remain_on_channel' + * since the queue is not empty. So, the roc at the head of the + * queue will only get the priority. Scheduling the work queue + * after sending any cancel remain on channel event will also + * ensure that the cancel roc is sent without any delays. + */ + schedule_delayed_work(&hdd_ctx->roc_req_work, 0); + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + uint8_t sessionId = pAdapter->sessionId; + if (REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request) { + sme_deregister_mgmt_frame(hHal, sessionId, + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), + NULL, 0); + } + } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode) + ) { + wlansap_de_register_mgmt_frame( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pAdapter), +#else + (WLAN_HDD_GET_CTX + (pAdapter))->pcds_context, +#endif + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << + 4), NULL, 0); + + } + + if (pRemainChanCtx->action_pkt_buff.frame_ptr != NULL + && pRemainChanCtx->action_pkt_buff.frame_length != 0) { + cdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr); + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + pRemainChanCtx->action_pkt_buff.frame_length = 0; + } + cdf_mem_free(pRemainChanCtx); + complete(&pAdapter->cancel_rem_on_chan_var); + if (CDF_STATUS_SUCCESS != status) + complete(&pAdapter->rem_on_chan_ready_event); + return CDF_STATUS_SUCCESS; +} + +void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + unsigned long rc; + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (cfgState->remain_on_chan_ctx != NULL) { + hddLog(LOGE, "Cancel Existing Remain on Channel"); + + if (CDF_TIMER_STATE_RUNNING == cdf_mc_timer_get_current_state( + &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer)) + cdf_mc_timer_stop(&cfgState->remain_on_chan_ctx-> + hdd_remain_on_chan_timer); + + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress == + true) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOGE, + "ROC timer cancellation in progress," + " wait for completion"); + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hddLog(LOGE, + "%s:wait on cancel_rem_on_chan_var timed out", + __func__); + } + return; + } + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + /* Wait till remain on channel ready indication before issuing cancel + * remain on channel request, otherwise if remain on channel not + * received and if the driver issues cancel remain on channel then lim + * will be in unknown state. + */ + rc = wait_for_completion_timeout(&pAdapter-> + rem_on_chan_ready_event, + msecs_to_jiffies + (WAIT_REM_CHAN_READY)); + if (!rc) { + hddLog(LOGE, + "%s: timeout waiting for remain on channel ready indication", + __func__); + } + + INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + + /* Issue abort remain on chan request to sme. + * The remain on channel callback will make sure the remain_on_chan + * expired event is sent. + */ + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + pRemainChanCtx->scan_id); + } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) + || (WLAN_HDD_P2P_GO == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR + (pAdapter), +#else + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, +#endif + pRemainChanCtx->scan_id); + } + + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + + if (!rc) { + hddLog(LOGE, + "%s: timeout waiting for cancel remain on channel ready" + " indication", __func__); + } + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + } else + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); +} + +int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter) +{ + int status = 0; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + if (WLAN_HDD_P2P_GO != pAdapter->device_mode) { + /* Cancel Existing Remain On Channel */ + /* If no action frame is pending */ + if (cfgState->remain_on_chan_ctx != NULL) { + /* Check whether Action Frame is pending or not */ + if (cfgState->buf == NULL) { + wlan_hdd_cancel_existing_remain_on_channel + (pAdapter); + } else { + hddLog(LOG1, + "Cannot Cancel Existing Remain on Channel"); + status = -EBUSY; + } + } + } + return status; +} + +/** + * wlan_hdd_cancel_pending_roc() - Cancel pending roc + * @adapter: HDD adapter + * + * Cancels any pending remain on channel request + * + * Return: None + */ +void wlan_hdd_cancel_pending_roc(hdd_adapter_t *adapter) +{ + hdd_remain_on_chan_ctx_t *roc_ctx; + unsigned long rc; + hdd_cfg80211_state_t *cfg_state = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: ROC completion is not received.!!!", + __func__); + + mutex_lock(&cfg_state->remain_on_chan_ctx_lock); + roc_ctx = cfg_state->remain_on_chan_ctx; + + if (roc_ctx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + hdd_debug("roc cancel already in progress"); + /* + * Since a cancel roc is already issued and is + * in progress, we need not send another + * cancel roc again. Instead we can just wait + * for cancel roc completion + */ + goto wait; + } + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + + if (adapter->device_mode == WLAN_HDD_P2P_GO) { + wlansap_cancel_remain_on_channel((WLAN_HDD_GET_CTX + (adapter))->pcds_context, + cfg_state->remain_on_chan_ctx->scan_id); + } else if (adapter->device_mode == WLAN_HDD_P2P_CLIENT + || adapter->device_mode == + WLAN_HDD_P2P_DEVICE) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX + (adapter), + adapter->sessionId, + cfg_state->remain_on_chan_ctx->scan_id); + } + +wait: + rc = wait_for_completion_timeout(&adapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Timeout occurred while waiting for RoC Cancellation", + __func__); + mutex_lock(&cfg_state->remain_on_chan_ctx_lock); + roc_ctx = cfg_state->remain_on_chan_ctx; + if (roc_ctx != NULL) { + cfg_state->remain_on_chan_ctx = NULL; + cdf_mc_timer_stop(&roc_ctx->hdd_remain_on_chan_timer); + cdf_mc_timer_destroy( + &roc_ctx->hdd_remain_on_chan_timer); + if (roc_ctx->action_pkt_buff.frame_ptr != NULL + && roc_ctx->action_pkt_buff.frame_length != 0) { + cdf_mem_free( + roc_ctx->action_pkt_buff.frame_ptr); + roc_ctx->action_pkt_buff.frame_ptr = NULL; + roc_ctx->action_pkt_buff.frame_length = 0; + } + cdf_mem_free(roc_ctx); + adapter->is_roc_inprogress = false; + } + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + } +} + +/* Clean up RoC context at hdd_stop_adapter*/ +void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter) +{ + uint8_t retry = 0; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + while (pAdapter->is_roc_inprogress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: ROC in progress for session %d!!!", + __func__, pAdapter->sessionId); + msleep(500); + if (retry++ > 3) { + wlan_hdd_cancel_pending_roc(pAdapter); + /* hold the lock before break from the loop */ + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + break; + } + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + } /* end of while */ + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + +} + +void wlan_hdd_remain_on_chan_timeout(void *data) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) data; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_cfg80211_state_t *cfgState; + + if (NULL == pAdapter) { + hddLog(LOGE, "%s: pAdapter is NULL !!!", __func__); + return; + } + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + + if (NULL == pRemainChanCtx) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOGE, "%s: No Remain on channel is pending", __func__); + return; + } + + if (true == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOGE, FL("Cancellation already in progress")); + return; + } + + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOG1, "%s: Cancel Remain on Channel on timeout", __func__); + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + pRemainChanCtx->scan_id); + } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + pRemainChanCtx->scan_id); + } + + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + +} + +static int wlan_hdd_execute_remain_on_channel(hdd_adapter_t *pAdapter, + hdd_remain_on_chan_ctx_t *pRemainChanCtx) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter_temp; + CDF_STATUS status; + bool isGoPresent = false; + unsigned int duration; + + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (pAdapter->is_roc_inprogress == true) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("remain on channel request is in execution")); + return -EBUSY; + } + + cfgState->remain_on_chan_ctx = pRemainChanCtx; + cfgState->current_freq = pRemainChanCtx->chan.center_freq; + pAdapter->is_roc_inprogress = true; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + /* Initialize Remain on chan timer */ + cdf_status = + cdf_mc_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer, + CDF_TIMER_TYPE_SW, + wlan_hdd_remain_on_chan_timeout, pAdapter); + if (cdf_status != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Not able to initialize remain_on_chan timer")); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + cfgState->remain_on_chan_ctx = NULL; + pAdapter->is_roc_inprogress = false; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + cdf_mem_free(pRemainChanCtx); + return -EINVAL; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter_temp = pAdapterNode->pAdapter; + if (pAdapter_temp->device_mode == WLAN_HDD_P2P_GO) { + isGoPresent = true; + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* Extending duration for proactive extension logic for RoC */ + duration = pRemainChanCtx->duration; + if (isGoPresent == true) + duration = P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT * duration; + else + duration = P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT * duration; + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + INIT_COMPLETION(pAdapter->rem_on_chan_ready_event); + + /* call sme API to start remain on channel. */ + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + uint8_t sessionId = pAdapter->sessionId; + /* call sme API to start remain on channel. */ + + if (CDF_STATUS_SUCCESS != sme_remain_on_channel( + WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, + pRemainChanCtx->chan.hw_value, duration, + wlan_hdd_remain_on_channel_callback, + pAdapter, + (pRemainChanCtx->rem_on_chan_request == + REMAIN_ON_CHANNEL_REQUEST) ? true : false, + &pRemainChanCtx->scan_id)) { + hddLog(LOGE, FL("sme_remain_on_channel failed")); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + cfgState->remain_on_chan_ctx = NULL; + pAdapter->is_roc_inprogress = false; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + cdf_mc_timer_destroy( + &pRemainChanCtx->hdd_remain_on_chan_timer); + cdf_mem_free(pRemainChanCtx); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + if (REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request) { + if (CDF_STATUS_SUCCESS != sme_register_mgmt_frame( + WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), + NULL, 0)) + hddLog(LOGE, + FL("sme_register_mgmt_frame failed")); + } + + } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode)) { + /* call sme API to start remain on channel. */ + if (CDF_STATUS_SUCCESS != wlansap_remain_on_channel( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), +#else + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, +#endif + pRemainChanCtx->chan.hw_value, + duration, wlan_hdd_remain_on_channel_callback, + pAdapter, &pRemainChanCtx->scan_id)) { + hddLog(LOGE, FL("wlansap_remain_on_channel failed")); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + cfgState->remain_on_chan_ctx = NULL; + pAdapter->is_roc_inprogress = false; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + cdf_mc_timer_destroy( + &pRemainChanCtx->hdd_remain_on_chan_timer); + cdf_mem_free(pRemainChanCtx); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + if (CDF_STATUS_SUCCESS != wlansap_register_mgmt_frame( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), +#else + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, +#endif + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("wlansap_register_mgmt_frame return fail")); + wlansap_cancel_remain_on_channel( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), +#else + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, +#endif + pRemainChanCtx->scan_id); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + } + return 0; +} + +/** + * wlan_hdd_roc_request_enqueue() - enqueue remain on channel request + * @adapter: Pointer to the adapter + * @remain_chan_ctx: Pointer to the remain on channel context + * + * Return: 0 on success, error number otherwise + */ +static int wlan_hdd_roc_request_enqueue(hdd_adapter_t *adapter, + hdd_remain_on_chan_ctx_t *remain_chan_ctx) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_roc_req_t *hdd_roc_req; + CDF_STATUS status; + + /* + * "Driver is busy" OR "there is already RoC request inside the queue" + * so enqueue this RoC Request and execute sequentially later. + */ + + hdd_roc_req = cdf_mem_malloc(sizeof(*hdd_roc_req)); + + if (NULL == hdd_roc_req) { + hddLog(LOGP, FL("malloc failed for roc req context")); + return -ENOMEM; + } + + hdd_roc_req->pAdapter = adapter; + hdd_roc_req->pRemainChanCtx = remain_chan_ctx; + + /* Enqueue this RoC request */ + cdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock); + status = cdf_list_insert_back(&hdd_ctx->hdd_roc_req_q, + &hdd_roc_req->node); + cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGP, FL("Not able to enqueue RoC Req context")); + cdf_mem_free(hdd_roc_req); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_indicate_roc_drop() - Indicate roc drop to userspace + * @adapter: HDD adapter + * @ctx: Remain on channel context + * + * Send remain on channel ready and cancel event for the queued + * roc that is being dropped. This will ensure that the userspace + * will send more roc requests. If this drop is not indicated to + * userspace, subsequent roc will not be sent to the driver since + * the userspace times out waiting for the remain on channel ready + * event. + * + * Return: None + */ +void wlan_hdd_indicate_roc_drop(hdd_adapter_t *adapter, + hdd_remain_on_chan_ctx_t *ctx) +{ + hdd_debug("indicate roc drop to userspace"); + cfg80211_ready_on_channel( + adapter->dev->ieee80211_ptr, + (uintptr_t)ctx, + &ctx->chan, + ctx->duration, GFP_KERNEL); + + cfg80211_remain_on_channel_expired( + ctx->dev->ieee80211_ptr, + ctx->cookie, + &ctx->chan, + GFP_KERNEL); +} + +/** + * wlan_hdd_roc_request_dequeue() - dequeue remain on channel request + * @work: Pointer to work queue struct + * + * Return: none + */ +void wlan_hdd_roc_request_dequeue(struct work_struct *work) +{ + CDF_STATUS status; + int ret = 0; + hdd_roc_req_t *hdd_roc_req; + hdd_context_t *hdd_ctx = + container_of(work, hdd_context_t, roc_req_work.work); + + hdd_debug("going to dequeue roc"); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + /* + * The queued roc requests is dequeued and processed one at a time. + * Callback 'wlan_hdd_remain_on_channel_callback' ensures + * that any pending roc in the queue will be scheduled + * on the current roc completion by scheduling the work queue. + */ + cdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock); + if (list_empty(&hdd_ctx->hdd_roc_req_q.anchor)) { + cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + hdd_debug("list is empty"); + return; + } + status = cdf_list_remove_front(&hdd_ctx->hdd_roc_req_q, + (cdf_list_node_t **) &hdd_roc_req); + cdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + if (CDF_STATUS_SUCCESS != status) { + hdd_debug("unable to remove roc element from list"); + return; + } + ret = wlan_hdd_execute_remain_on_channel( + hdd_roc_req->pAdapter, + hdd_roc_req->pRemainChanCtx); + if (ret == -EBUSY) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("dropping RoC request")); + wlan_hdd_indicate_roc_drop(hdd_roc_req->pAdapter, + hdd_roc_req->pRemainChanCtx); + cdf_mem_free(hdd_roc_req->pRemainChanCtx); + } + cdf_mem_free(hdd_roc_req); +} + +static int wlan_hdd_request_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type + channel_type, +#endif + unsigned int duration, + u64 *cookie, + rem_on_channel_request_type_t + request_type) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + bool isBusy = false; + uint32_t size = 0; + hdd_adapter_t *sta_adapter; + int ret; + int status = 0; + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + hddLog(LOG1, + "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d", + chan->hw_value, chan->center_freq, channel_type, duration); +#else + hddLog(LOG1, + "chan(hw_val)0x%x chan(centerfreq) %d, duration %d", + chan->hw_value, chan->center_freq, duration); +#endif + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + if (cds_is_connection_in_progress( + (hdd_context_t *) pAdapter->pHddCtx)) { + hddLog(LOGE, FL("Connection is in progress")); + isBusy = true; + } + pRemainChanCtx = cdf_mem_malloc(sizeof(hdd_remain_on_chan_ctx_t)); + if (NULL == pRemainChanCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: Not able to allocate memory for Channel context", + __func__); + return -ENOMEM; + } + + cdf_mem_zero(pRemainChanCtx, sizeof(*pRemainChanCtx)); + cdf_mem_copy(&pRemainChanCtx->chan, chan, + sizeof(struct ieee80211_channel)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + pRemainChanCtx->chan_type = channel_type; +#endif + pRemainChanCtx->duration = duration; + pRemainChanCtx->dev = dev; + *cookie = (uintptr_t) pRemainChanCtx; + pRemainChanCtx->cookie = *cookie; + pRemainChanCtx->rem_on_chan_request = request_type; + pRemainChanCtx->action_pkt_buff.freq = 0; + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + pRemainChanCtx->action_pkt_buff.frame_length = 0; + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = false; + if (REMAIN_ON_CHANNEL_REQUEST == request_type) { + sta_adapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION); + if ((NULL != sta_adapter)&& + hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter))) { + if (pAdapter->last_roc_ts !=0 && + ((cdf_mc_timer_get_system_time() - + pAdapter->last_roc_ts) < + pHddCtx->config->p2p_listen_defer_interval)) { + if (pRemainChanCtx->duration > HDD_P2P_MAX_ROC_DURATION) + pRemainChanCtx->duration = + HDD_P2P_MAX_ROC_DURATION; + + wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx); + schedule_delayed_work(&pHddCtx->roc_req_work, + msecs_to_jiffies( + pHddCtx->config->p2p_listen_defer_interval)); + hddLog(LOG1, "Defer interval is %hu, pAdapter %p", + pHddCtx->config->p2p_listen_defer_interval, + pAdapter); + return 0; + } + } + } + + cdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock); + cdf_list_size(&(pHddCtx->hdd_roc_req_q), &size); + cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + if ((isBusy == false) && (!size)) { + status = wlan_hdd_execute_remain_on_channel(pAdapter, + pRemainChanCtx); + if (status == -EBUSY) { + if (wlan_hdd_roc_request_enqueue(pAdapter, + pRemainChanCtx)) { + cdf_mem_free(pRemainChanCtx); + return -EAGAIN; + } + } + return 0; + } else { + if (wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx)) { + cdf_mem_free(pRemainChanCtx); + return -EAGAIN; + } + } + + /* + * If a connection is not in progress (isBusy), before scheduling + * the work queue it is necessary to check if a roc in in progress + * or not because: if an roc is in progress, the dequeued roc + * that will be processed will be dropped. To ensure that this new + * roc request is not dropped, it is suggested to check if an roc + * is in progress or not. The existing roc completion will provide + * the trigger to dequeue the next roc request. + */ + if (isBusy == false && pAdapter->is_roc_inprogress == false) { + hdd_debug("scheduling delayed work: no connection/roc active"); + schedule_delayed_work(&pHddCtx->roc_req_work, 0); + } + return 0; +} + +int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + struct ieee80211_channel *chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type + channel_type, +#endif + unsigned int duration, u64 *cookie) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct net_device *dev = wdev->netdev; +#endif + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_REMAIN_ON_CHANNEL, + pAdapter->sessionId, REMAIN_ON_CHANNEL_REQUEST)); + return wlan_hdd_request_remain_on_channel(wiphy, dev, chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + channel_type, +#endif + duration, cookie, + REMAIN_ON_CHANNEL_REQUEST); +} + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + struct ieee80211_channel *chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type, +#endif + unsigned int duration, u64 *cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_remain_on_channel(wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + wdev, +#else + dev, +#endif + chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + channel_type, +#endif + duration, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_remain_chan_ready_handler(hdd_adapter_t *pAdapter, + uint32_t scan_id) +{ + hdd_cfg80211_state_t *cfgState = NULL; + hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL; + CDF_STATUS status; + + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL")); + return; + } + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hddLog(LOG1, "Ready on chan ind %d", scan_id); + + pAdapter->start_roc_ts = cdf_mc_timer_get_system_time(); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx != NULL) { + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_REMAINCHANREADYHANDLER, + pAdapter->sessionId, + pRemainChanCtx->duration)); + /* start timer for actual duration */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &pRemainChanCtx->hdd_remain_on_chan_timer)) { + hddLog(LOGE, "Timer Started before ready event!!!"); + cdf_mc_timer_stop(&pRemainChanCtx-> + hdd_remain_on_chan_timer); + } + status = + cdf_mc_timer_start(&pRemainChanCtx-> + hdd_remain_on_chan_timer, + (pRemainChanCtx->duration + + COMPLETE_EVENT_PROPOGATE_TIME)); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, "%s: Remain on Channel timer start failed", + __func__); + } + + if (REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request) { + cfg80211_ready_on_channel( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + pAdapter->dev-> + ieee80211_ptr, +#else + pAdapter->dev, +#endif + (uintptr_t) + pRemainChanCtx, + &pRemainChanCtx->chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + pRemainChanCtx-> + chan_type, +#endif + pRemainChanCtx-> + duration, GFP_KERNEL); + } else if (OFF_CHANNEL_ACTION_TX == + pRemainChanCtx->rem_on_chan_request) { + complete(&pAdapter->offchannel_tx_event); + } + /* Check for cached action frame */ + if (pRemainChanCtx->action_pkt_buff.frame_length != 0) { + hddLog(LOGE, + "%s: Sent cached action frame to supplicant", + __func__); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, 0, + pRemainChanCtx->action_pkt_buff.frame_ptr, + pRemainChanCtx->action_pkt_buff.frame_length, + NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, 0, + pRemainChanCtx->action_pkt_buff.frame_ptr, + pRemainChanCtx->action_pkt_buff.frame_length, + NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, + 0, + pRemainChanCtx->action_pkt_buff. + frame_ptr, + pRemainChanCtx->action_pkt_buff. + frame_length, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(pAdapter->dev, + pRemainChanCtx->action_pkt_buff.freq, + 0, + pRemainChanCtx->action_pkt_buff. + frame_ptr, + pRemainChanCtx->action_pkt_buff. + frame_length, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(pAdapter->dev, + pRemainChanCtx->action_pkt_buff.freq, + pRemainChanCtx->action_pkt_buff. + frame_ptr, + pRemainChanCtx->action_pkt_buff. + frame_length, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ + + cdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr); + pRemainChanCtx->action_pkt_buff.frame_length = 0; + pRemainChanCtx->action_pkt_buff.freq = 0; + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + } + complete(&pAdapter->rem_on_chan_ready_event); + } else { + hddLog(LOGW, "%s: No Pending Remain on channel Request", + __func__); + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + return; +} + +int __wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + u64 cookie) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct net_device *dev = wdev->netdev; +#endif + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + unsigned long rc; + cdf_list_node_t *tmp, *q; + hdd_roc_req_t *curr_roc_req; + + hddLog(LOG1, "Cancel remain on channel"); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return status; + } + cdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock); + list_for_each_safe(tmp, q, &pHddCtx->hdd_roc_req_q.anchor) { + curr_roc_req = list_entry(tmp, hdd_roc_req_t, node); + if ((uintptr_t) curr_roc_req->pRemainChanCtx == cookie) { + status = cdf_list_remove_node(&pHddCtx->hdd_roc_req_q, + (cdf_list_node_t *) + curr_roc_req); + cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + if (status == CDF_STATUS_SUCCESS) { + cdf_mem_free(curr_roc_req->pRemainChanCtx); + cdf_mem_free(curr_roc_req); + } + return 0; + } + } + cdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + /* FIXME cancel currently running remain on chan. + * Need to check cookie and cancel accordingly + */ + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if ((cfgState->remain_on_chan_ctx == NULL) || + (cfgState->remain_on_chan_ctx->cookie != cookie)) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOGE, + "%s: No Remain on channel pending with specified cookie value", + __func__); + return -EINVAL; + } + + if (NULL != cfgState->remain_on_chan_ctx) { + cdf_mc_timer_stop(&cfgState->remain_on_chan_ctx-> + hdd_remain_on_chan_timer); + if (true == + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hddLog(LOG1, + FL("ROC timer cancellation in progress," + " wait for completion")); + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hddLog(LOGE, + "%s:wait on cancel_rem_on_chan_var timed out", + __func__); + } + return 0; + } else + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = + true; + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + /* wait until remain on channel ready event received + * for already issued remain on channel request */ + rc = wait_for_completion_timeout(&pAdapter->rem_on_chan_ready_event, + msecs_to_jiffies(WAIT_REM_CHAN_READY)); + if (!rc) { + hddLog(LOGE, + "%s: timeout waiting for remain on channel ready indication", + __func__); + + if (pHddCtx->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: LOGP in Progress. Ignore!!!", __func__); + return -EAGAIN; + } + } + INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + /* Issue abort remain on chan request to sme. + * The remain on channel callback will make sure the remain_on_chan + * expired event is sent. + */ + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + + uint8_t sessionId = pAdapter->sessionId; + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, + pRemainChanCtx->scan_id); + } else if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( +#ifdef WLAN_FEATURE_MBSSID + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), +#else + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, +#endif + pRemainChanCtx->scan_id); + + } else { + hddLog(LOGE, FL("Invalid device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EIO; + } + rc = wait_for_completion_timeout(&pAdapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hddLog(LOGE, + "%s:wait on cancel_rem_on_chan_var timed out ", + __func__); + } + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return 0; +} + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct wireless_dev *wdev, +#else + struct net_device *dev, +#endif + u64 cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + wdev, +#else + dev, +#endif + cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type, + bool channel_type_valid, +#endif + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) +int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#else +int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, u64 *cookie) +#endif /* LINUX_VERSION_CODE */ +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct net_device *dev = wdev->netdev; +#endif + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint16_t extendedWait = 0; + uint8_t type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]); + uint8_t subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]); + tActionFrmType actionFrmType; + bool noack = 0; + int status; + unsigned long rc; + hdd_adapter_t *goAdapter; + uint16_t current_freq; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ACTION, pAdapter->sessionId, + pAdapter->device_mode)); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return status; + } + + hddLog(LOG1, FL("Device_mode %s(%d) type: %d"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, type); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + wlan_hdd_is_type_p2p_action(&buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) { + actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "[P2P] unknown[%d] ---> OTA to " MAC_ADDRESS_STR, + actionFrmType, + MAC_ADDR_ARRAY(&buf + [WLAN_HDD_80211_FRM_DA_OFFSET])); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, "[P2P] %s ---> OTA to " + MAC_ADDRESS_STR, + p2p_action_frame_type[actionFrmType], + MAC_ADDR_ARRAY(&buf + [WLAN_HDD_80211_FRM_DA_OFFSET])); + if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ) + && (global_p2p_connection_status == P2P_NOT_ACTIVE)) { + global_p2p_connection_status = P2P_GO_NEG_PROCESS; + hddLog(LOGE, "[P2P State]Inactive state to " + "GO negotiation progress state"); + } else if ((actionFrmType == WLAN_HDD_GO_NEG_CNF) && + (global_p2p_connection_status == + P2P_GO_NEG_PROCESS)) { + global_p2p_connection_status = + P2P_GO_NEG_COMPLETED; + hddLog(LOGE, + "[P2P State]GO nego progress to GO nego" + " completed state"); + } + } + } +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + noack = dont_wait_for_ack; +#endif + + /* If the wait is coming as 0 with off channel set */ + /* then set the wait to 200 ms */ + if (offchan && !wait) { + wait = ACTION_FRAME_DEFAULT_WAIT; + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (cfgState->remain_on_chan_ctx) { + + uint32_t current_time = cdf_mc_timer_get_system_time(); + int remaining_roc_time = + ((int) cfgState->remain_on_chan_ctx->duration - + (current_time - pAdapter->start_roc_ts)); + + if (remaining_roc_time > ACTION_FRAME_DEFAULT_WAIT) + wait = remaining_roc_time; + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + } + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && + (type == SIR_MAC_MGMT_FRAME && + subType == SIR_MAC_MGMT_PROBE_RSP)) { + /* Drop Probe response received + * from supplicant in sta mode + */ + goto err_rem_channel; + } + + /* Call sme API to send out a action frame. */ + /* OR can we send it directly through data path?? */ + /* After tx completion send tx status back. */ + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode) + ) { + if (type == SIR_MAC_MGMT_FRAME) { + if (subType == SIR_MAC_MGMT_PROBE_RSP) { + /* Drop Probe response recieved from supplicant, as for GO and + SAP PE itself sends probe response + */ + goto err_rem_channel; + } else if ((subType == SIR_MAC_MGMT_DISASSOC) || + (subType == SIR_MAC_MGMT_DEAUTH)) { + /* During EAP failure or P2P Group Remove supplicant + * is sending del_station command to driver. From + * del_station function, Driver will send deauth frame to + * p2p client. No need to send disassoc frame from here. + * so Drop the frame here and send tx indication back to + * supplicant. + */ + uint8_t dstMac[ETH_ALEN] = { 0 }; + memcpy(&dstMac, + &buf[WLAN_HDD_80211_FRM_DA_OFFSET], + ETH_ALEN); + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Deauth/Disassoc received for STA:" + MAC_ADDRESS_STR, __func__, + MAC_ADDR_ARRAY(dstMac)); + goto err_rem_channel; + } + } + } + + if (NULL != cfgState->buf) { + if (!noack) { + hddLog(LOGE, + "(%s):Previous P2P Action frame packet pending", + __func__); + hdd_cleanup_actionframe(pAdapter->pHddCtx, pAdapter); + } else { + hddLog(LOGE, + "(%s):Pending Action frame packet return EBUSY", + __func__); + return -EBUSY; + } + } + + if (subType == SIR_MAC_MGMT_ACTION) { + hddLog(LOG1, "Action frame tx request : %s", + hdd_get_action_string(buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET])); + } + + goAdapter = hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO); + + /* If GO adapter exists and operating on same frequency */ + /* then we will not request remain on channel */ + if (goAdapter && (ieee80211_frequency_to_channel(chan->center_freq) + == goAdapter->sessionCtx.ap.operatingChannel)) { + /* if GO exist and is not off channel + * wait time should be zero + */ + wait = 0; + goto send_frame; + } + + if (offchan && wait) { + int status; + rem_on_channel_request_type_t req_type = OFF_CHANNEL_ACTION_TX; + /* In case of P2P Client mode if we are already */ + /* on the same channel then send the frame directly */ + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + hdd_p2p_is_action_type_rsp(&buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET]) + && cfgState->remain_on_chan_ctx + && cfgState->current_freq == chan->center_freq) { + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer)) { + cdf_mc_timer_stop(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer); + status = + cdf_mc_timer_start(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer, + wait); + if (status != CDF_STATUS_SUCCESS) { + hddLog(LOGE, + "%s: Remain on Channel timer start failed", + __func__); + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + goto send_frame; + } else { + if (pRemainChanCtx-> + hdd_remain_on_chan_cancel_in_progress == + true) { + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + hddLog(CDF_TRACE_LEVEL_INFO, + "action frame tx: waiting for completion of ROC "); + + rc = wait_for_completion_timeout + (&pAdapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hddLog(LOGE, + "%s:wait on cancel_rem_on_chan_var timed out", + __func__); + } + + } else + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + } + } else + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + if ((cfgState->remain_on_chan_ctx != NULL) && + (cfgState->current_freq == chan->center_freq) + ) { + hddLog(LOG1, "action frame: extending the wait time"); + extendedWait = (uint16_t) wait; + goto send_frame; + } + + INIT_COMPLETION(pAdapter->offchannel_tx_event); + + status = wlan_hdd_request_remain_on_channel(wiphy, dev, chan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + channel_type, +#endif + wait, cookie, + req_type); + if (0 != status) { + if ((-EBUSY == status) && + (cfgState->current_freq == chan->center_freq)) { + goto send_frame; + } + goto err_rem_channel; + } + /* This will extend timer in LIM when sending Any action frame + * It will cover remain on channel timer till next action frame + * in rx direction. + */ + extendedWait = (uint16_t) wait; + /* Wait for driver to be ready on the requested channel */ + rc = wait_for_completion_timeout(&pAdapter->offchannel_tx_event, + msecs_to_jiffies + (WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX)); + if (!rc) { + hddLog(LOGE, "wait on offchannel_tx_event timed out"); + goto err_rem_channel; + } + } else if (offchan) { + /* Check before sending action frame + whether we already remain on channel */ + if (NULL == cfgState->remain_on_chan_ctx) { + goto err_rem_channel; + } + } +send_frame: + + if (!noack) { + cfgState->buf = cdf_mem_malloc(len); /* buf; */ + if (cfgState->buf == NULL) + return -ENOMEM; + + cfgState->len = len; + + cdf_mem_copy(cfgState->buf, buf, len); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + + if (cfgState->remain_on_chan_ctx) { + cfgState->action_cookie = + cfgState->remain_on_chan_ctx->cookie; + *cookie = cfgState->action_cookie; + } else { + *cookie = (uintptr_t) cfgState->buf; + cfgState->action_cookie = *cookie; + } + + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + } + + /* + * Firmware needs channel information for action frames + * which are not sent on the current operating channel of VDEV + */ + if ((WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_GO == pAdapter->device_mode)) { + if (chan && (chan->center_freq != 0)) + current_freq = chan->center_freq; + else + current_freq = cfgState->current_freq; + } else { + current_freq = 0; + } + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + uint8_t sessionId = pAdapter->sessionId; + + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_PUBLIC_ACTION_FRAME)) { + actionFrmType = + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + hddLog(LOG1, "Tx Action Frame %u", actionFrmType); + if (actionFrmType == WLAN_HDD_PROV_DIS_REQ) { + cfgState->actionFrmState = + HDD_PD_REQ_ACK_PENDING; + hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING", + __func__); + } else if (actionFrmType == WLAN_HDD_GO_NEG_REQ) { + cfgState->actionFrmState = + HDD_GO_NEG_REQ_ACK_PENDING; + hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING", + __func__); + } + } + + if (CDF_STATUS_SUCCESS != + sme_send_action(WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, buf, len, extendedWait, noack, + current_freq)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_send_action returned fail", __func__); + goto err; + } + } else if (WLAN_HDD_SOFTAP == pAdapter->device_mode || + WLAN_HDD_P2P_GO == pAdapter->device_mode) { + if (CDF_STATUS_SUCCESS != +#ifdef WLAN_FEATURE_MBSSID + wlansap_send_action(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), +#else + wlansap_send_action((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, +#endif + buf, len, 0, current_freq)) { + hddLog(LOGE, + FL("wlansap_send_action returned fail")); + goto err; + } + } + + return 0; +err: + if (!noack) { + hdd_send_action_cnf(pAdapter, false); + } + return 0; +err_rem_channel: + *cookie = (uintptr_t) cfgState; + cfg80211_mgmt_tx_status( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + pAdapter->dev->ieee80211_ptr, +#else + pAdapter->dev, +#endif + *cookie, buf, len, false, GFP_KERNEL); + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + enum nl80211_channel_type channel_type, + bool channel_type_valid, +#endif + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, u64 *cookie) +#endif /* LINUX_VERSION_CODE */ +{ + int ret; + + cds_ssr_protect(__func__); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + ret = __wlan_hdd_mgmt_tx(wiphy, wdev, params->chan, params->offchan, + params->wait, params->buf, params->len, + params->no_cck, params->dont_wait_for_ack, + cookie); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + ret = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + channel_type, channel_type_valid, +#endif + wait, buf, len, no_cck, + dont_wait_for_ack, cookie); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + ret = __wlan_hdd_mgmt_tx(wiphy, dev, chan, offchan, + channel_type, channel_type_valid, wait, + buf, len, no_cck, dont_wait_for_ack, cookie); +#else + ret = __wlan_hdd_mgmt_tx(wiphy, dev, chan, offchan, + channel_type, channel_type_valid, wait, + buf, len, cookie); +#endif /* LINUX_VERSION_CODE */ + cds_ssr_unprotect(__func__); + + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + return wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, wdev, cookie); +} +#else +int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, u64 cookie) +{ + return wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, dev, cookie); +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} +#else +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, u64 cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, dev, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +void hdd_send_action_cnf(hdd_adapter_t *pAdapter, bool actionSendSuccess) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + cfgState->actionFrmState = HDD_IDLE; + + hddLog(LOG1, "Send Action cnf, actionSendSuccess %d", + actionSendSuccess); + + if (NULL == cfgState->buf) { + return; + } + + /* + * buf is the same pointer it passed us to send. Since we are sending + * it through control path, we use different buffers. + * In case of mac80211, they just push it to the skb and pass the same + * data while sending tx ack status. + * */ + cfg80211_mgmt_tx_status( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + pAdapter->dev->ieee80211_ptr, +#else + pAdapter->dev, +#endif + cfgState->action_cookie, + cfgState->buf, cfgState->len, + actionSendSuccess, GFP_KERNEL); + + cdf_mem_free(cfgState->buf); + cfgState->buf = NULL; + + complete(&pAdapter->tx_action_cnf_event); +} + +/** + * hdd_set_p2p_noa + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_NOA comand from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tP2pPsConfig NoA; + int count, duration, start_time; + char *param; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (param == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: strnchr failed to find delimeter", __func__); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &count, &start_time, &duration); + if (ret != 3) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: P2P_SET GO NoA: fail to read params, ret=%d", + __func__, ret); + return -EINVAL; + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: P2P_SET GO NoA: count=%d start_time=%d duration=%d", + __func__, count, start_time, duration); + duration = MS_TO_MUS(duration); + /* PS Selection + * Periodic NoA (2) + * Single NOA (4) + */ + NoA.opp_ps = 0; + NoA.ctWindow = 0; + if (count == 1) { + NoA.duration = 0; + NoA.single_noa_duration = duration; + NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA; + } else { + NoA.duration = duration; + NoA.single_noa_duration = 0; + NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA; + } + NoA.interval = MS_TO_MUS(100); + NoA.count = count; + NoA.sessionid = pAdapter->sessionId; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d " + "PsSelection %x", __func__, NoA.opp_ps, + NoA.ctWindow, NoA.duration, NoA.interval, + NoA.count, NoA.single_noa_duration, NoA.psSelection); + + sme_p2p_set_ps(hHal, &NoA); + return 0; +} + +/** + * hdd_set_p2p_opps + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_PS comand from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tP2pPsConfig NoA; + char *param; + int legacy_ps, opp_ps, ctwindow; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (param == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: strnchr failed to find delimiter", __func__); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow); + if (ret != 3) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: P2P_SET GO PS: fail to read params, ret=%d", + __func__, ret); + return -EINVAL; + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d", + __func__, legacy_ps, opp_ps, ctwindow); + + /* PS Selection + * Opportunistic Power Save (1) + */ + + /* From wpa_cli user need to use separate command to set ctWindow and Opps + * When user want to set ctWindow during that time other parameters + * values are coming from wpa_supplicant as -1. + * Example : User want to set ctWindow with 30 then wpa_cli command : + * P2P_SET ctwindow 30 + * Command Received at hdd_hostapd_ioctl is as below: + * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30) + */ + if (ctwindow != -1) { + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "Opportunistic Power Save is %s", + (true == pAdapter->ops) ? "Enable" : "Disable"); + + if (ctwindow != pAdapter->ctw) { + pAdapter->ctw = ctwindow; + + if (pAdapter->ops) { + NoA.opp_ps = pAdapter->ops; + NoA.ctWindow = pAdapter->ctw; + NoA.duration = 0; + NoA.single_noa_duration = 0; + NoA.interval = 0; + NoA.count = 0; + NoA.psSelection = + P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; + NoA.sessionid = pAdapter->sessionId; + + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d " + "PsSelection %x", __func__, + NoA.opp_ps, NoA.ctWindow, + NoA.duration, NoA.interval, NoA.count, + NoA.single_noa_duration, + NoA.psSelection); + + sme_p2p_set_ps(hHal, &NoA); + } + return 0; + } + } + + if (opp_ps != -1) { + pAdapter->ops = opp_ps; + + if ((opp_ps != -1) && (pAdapter->ctw)) { + NoA.opp_ps = opp_ps; + NoA.ctWindow = pAdapter->ctw; + NoA.duration = 0; + NoA.single_noa_duration = 0; + NoA.interval = 0; + NoA.count = 0; + NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; + NoA.sessionid = pAdapter->sessionId; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d " + "PsSelection %x", __func__, NoA.opp_ps, + NoA.ctWindow, NoA.duration, NoA.interval, + NoA.count, NoA.single_noa_duration, + NoA.psSelection); + + sme_p2p_set_ps(hHal, &NoA); + } + } + return 0; +} + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tP2pPsConfig NoA; + p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData; + + NoA.opp_ps = pappNoA->opp_ps; + NoA.ctWindow = pappNoA->ctWindow; + NoA.duration = pappNoA->duration; + NoA.interval = pappNoA->interval; + NoA.count = pappNoA->count; + NoA.single_noa_duration = pappNoA->single_noa_duration; + NoA.psSelection = pappNoA->psSelection; + NoA.sessionid = pAdapter->sessionId; + + sme_p2p_set_ps(hHal, &NoA); + return status; +} + +static uint8_t wlan_hdd_get_session_type(enum nl80211_iftype type) +{ + uint8_t sessionType; + + switch (type) { + case NL80211_IFTYPE_AP: + sessionType = WLAN_HDD_SOFTAP; + break; + case NL80211_IFTYPE_P2P_GO: + sessionType = WLAN_HDD_P2P_GO; + break; + case NL80211_IFTYPE_P2P_CLIENT: + sessionType = WLAN_HDD_P2P_CLIENT; + break; + case NL80211_IFTYPE_STATION: + sessionType = WLAN_HDD_INFRA_STATION; + break; + default: + sessionType = WLAN_HDD_INFRA_STATION; + break; + } + + return sessionType; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +#else +struct net_device *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +#endif +{ + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + hdd_adapter_t *pAdapter = NULL; + hdd_scaninfo_t *scan_info = NULL; + int ret; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return ERR_PTR(-EINVAL); + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return ERR_PTR(ret); + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type)); + /* + * Allow addition multiple interface for WLAN_HDD_P2P_CLIENT and + * WLAN_HDD_SOFTAP session type. + */ + if ((hdd_get_adapter(pHddCtx, wlan_hdd_get_session_type(type)) != NULL) +#ifdef WLAN_FEATURE_MBSSID + && WLAN_HDD_SOFTAP != wlan_hdd_get_session_type(type) +#endif + && WLAN_HDD_P2P_CLIENT != wlan_hdd_get_session_type(type) + && WLAN_HDD_INFRA_STATION != wlan_hdd_get_session_type(type)) { + hddLog(LOGE, + "%s: Interface type %d already exists. " + "Two interfaces of same type are not supported currently.", + __func__, type); + return ERR_PTR(-EINVAL); + } + + wlan_hdd_tdls_disable_offchan_and_teardown_links(pHddCtx); + + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION); + if (pAdapter != NULL) { + scan_info = &pAdapter->scan_info; + if (scan_info->mScanPending) { + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + hddLog(LOG1, + FL("Abort Scan while adding virtual interface")); + } + } + + pAdapter = NULL; + if (pHddCtx->config->isP2pDeviceAddrAdministrated && + ((NL80211_IFTYPE_P2P_GO == type) || + (NL80211_IFTYPE_P2P_CLIENT == type))) { + /* + * Generate the P2P Interface Address. this address must be + * different from the P2P Device Address. + */ + struct cdf_mac_addr p2pDeviceAddress = + pHddCtx->p2pDeviceAddress; + p2pDeviceAddress.bytes[4] ^= 0x80; + pAdapter = hdd_open_adapter(pHddCtx, + wlan_hdd_get_session_type(type), + name, p2pDeviceAddress.bytes, true); + } else { + pAdapter = + hdd_open_adapter(pHddCtx, wlan_hdd_get_session_type(type), + name, wlan_hdd_get_intf_addr(pHddCtx), + true); + } + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: hdd_open_adapter failed", + __func__); + return ERR_PTR(-ENOSPC); + } + EXIT(); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + return pAdapter->dev->ieee80211_ptr; +#else + return pAdapter->dev; +#endif +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; +} +#else +struct net_device *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct net_device *ndev; + + cds_ssr_protect(__func__); + ndev = __wlan_hdd_add_virtual_intf(wiphy, name, type, flags, params); + cds_ssr_unprotect(__func__); + return ndev; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +#else +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +#endif +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct net_device *dev = wdev->netdev; +#endif + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_DEL_VIRTUAL_INTF, + pVirtAdapter->sessionId, pVirtAdapter->device_mode)); + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pVirtAdapter->device_mode), + pVirtAdapter->device_mode); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return status; + } + + wlan_hdd_release_intf_addr(pHddCtx, + pVirtAdapter->macAddressCurrent.bytes); + + hdd_stop_adapter(pHddCtx, pVirtAdapter, true); + hdd_close_adapter(pHddCtx, pVirtAdapter, true); + EXIT(); + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +#else +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +#endif +{ + int ret; + + cds_ssr_protect(__func__); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + ret = __wlan_hdd_del_virtual_intf(wiphy, wdev); +#else + ret = __wlan_hdd_del_virtual_intf(wiphy, dev); +#endif + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, + uint32_t nFrameLength, + uint8_t *pbFrames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi) +{ + uint16_t freq; + uint16_t extend_time; + uint8_t type = 0; + uint8_t subType = 0; + tActionFrmType actionFrmType; + hdd_cfg80211_state_t *cfgState = NULL; + CDF_STATUS status; + hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL; + hdd_context_t *pHddCtx; + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d", + __func__, frameType, nFrameLength); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL")); + return; + } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 == nFrameLength) { + hddLog(LOGE, FL("Frame Length is Invalid ZERO")); + return; + } + + if (NULL == pbFrames) { + hddLog(LOGE, FL("pbFrames is NULL")); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]); + + /* Get pAdapter from Destination mac address of the frame */ + if ((type == SIR_MAC_MGMT_FRAME) && (subType != SIR_MAC_MGMT_PROBE_REQ)) { + pAdapter = + hdd_get_adapter_by_macaddr(WLAN_HDD_GET_CTX(pAdapter), + &pbFrames + [WLAN_HDD_80211_FRM_DA_OFFSET]); + if (NULL == pAdapter) { + /* + * Under assumtion that we don't receive any action + * frame with BCST as destination, + * we are dropping action frame + */ + hddLog(LOGP, + "pAdapter for action frame is NULL Macaddr = " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(&pbFrames + [WLAN_HDD_80211_FRM_DA_OFFSET])); + hddLog(LOGP, + FL("Frame Type = %d Frame Length = %d subType = %d"), + frameType, nFrameLength, subType); + return; + } + } + + if (NULL == pAdapter->dev) { + hddLog(LOGE, FL("pAdapter->dev is NULL")); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hddLog(LOGE, FL("pAdapter has invalid magic")); + return; + } + + /* Channel indicated may be wrong. TODO */ + /* Indicate an action frame. */ + if (rxChan <= MAX_NO_OF_2_4_CHANNELS) + freq = ieee80211_channel_to_frequency(rxChan, + IEEE80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(rxChan, + IEEE80211_BAND_5GHZ); + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + if ((type == SIR_MAC_MGMT_FRAME) && (subType == SIR_MAC_MGMT_ACTION)) { + if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_PUBLIC_ACTION_FRAME) { + /* Public action frame */ + if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] + == SIR_MAC_ACTION_VENDOR_SPECIFIC) && + cdf_mem_compare(&pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + + 2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE)) { + /* P2P action frames */ + u8 *macFrom = + &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET + 6]; + actionFrmType = + pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + hddLog(LOG1, "Rx Action Frame %u", + actionFrmType); +#ifdef WLAN_FEATURE_P2P_DEBUG + if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "[P2P] unknown[%d] <--- OTA" + " from " MAC_ADDRESS_STR, + actionFrmType, + MAC_ADDR_ARRAY(macFrom)); + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + "[P2P] %s <--- OTA" " from " + MAC_ADDRESS_STR, + p2p_action_frame_type + [actionFrmType], + MAC_ADDR_ARRAY(macFrom)); + if ((actionFrmType == + WLAN_HDD_PROV_DIS_REQ) + && (global_p2p_connection_status == + P2P_NOT_ACTIVE)) { + global_p2p_connection_status = + P2P_GO_NEG_PROCESS; + hddLog(LOGE, + "[P2P State]Inactive state to " + "GO negotiation progress state"); + } else + if ((actionFrmType == + WLAN_HDD_GO_NEG_CNF) + && (global_p2p_connection_status == + P2P_GO_NEG_PROCESS)) { + global_p2p_connection_status = + P2P_GO_NEG_COMPLETED; + hddLog(LOGE, + "[P2P State]GO negotiation progress to " + "GO negotiation completed state"); + } else + if ((actionFrmType == + WLAN_HDD_INVITATION_REQ) + && (global_p2p_connection_status == + P2P_NOT_ACTIVE)) { + global_p2p_connection_status = + P2P_GO_NEG_COMPLETED; + hddLog(LOGE, + "[P2P State]Inactive state to GO negotiation" + " completed state Autonomous GO formation"); + } + } +#endif + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx != NULL) { + if (actionFrmType == WLAN_HDD_GO_NEG_REQ + || actionFrmType == + WLAN_HDD_GO_NEG_RESP + || actionFrmType == + WLAN_HDD_INVITATION_REQ + || actionFrmType == + WLAN_HDD_DEV_DIS_REQ + || actionFrmType == + WLAN_HDD_PROV_DIS_REQ) { + hddLog(LOG1, + "Extend RoC timer on reception of Action Frame"); + + if ((actionFrmType == + WLAN_HDD_GO_NEG_REQ) + || (actionFrmType == + WLAN_HDD_GO_NEG_RESP)) + extend_time = + 2 * + ACTION_FRAME_DEFAULT_WAIT; + else + extend_time = + ACTION_FRAME_DEFAULT_WAIT; + + if (completion_done + (&pAdapter-> + rem_on_chan_ready_event)) { + if (CDF_TIMER_STATE_RUNNING == cdf_mc_timer_get_current_state(&pRemainChanCtx->hdd_remain_on_chan_timer)) { + cdf_mc_timer_stop + (&pRemainChanCtx-> + hdd_remain_on_chan_timer); + status = + cdf_mc_timer_start + (&pRemainChanCtx-> + hdd_remain_on_chan_timer, + extend_time); + if (status != + CDF_STATUS_SUCCESS) { + hddLog + (LOGE, + "%s: Remain on Channel timer start failed", + __func__); + } + } else { + hddLog(LOG1, + "%s: Rcvd action frame after timer expired", + __func__); + } + } else { + /* Buffer Packet */ + if (pRemainChanCtx-> + action_pkt_buff. + frame_length == 0) { + pRemainChanCtx-> + action_pkt_buff. + frame_length + = + nFrameLength; + pRemainChanCtx-> + action_pkt_buff. + freq = freq; + pRemainChanCtx-> + action_pkt_buff. + frame_ptr = + cdf_mem_malloc + (nFrameLength); + cdf_mem_copy + (pRemainChanCtx-> + action_pkt_buff. + frame_ptr, + pbFrames, + nFrameLength); + hddLog(LOGE, + "%s:" + "Action Pkt Cached successfully !!!", + __func__); + } else { + hddLog(LOGE, + "%s:" + "Frames are pending. dropping frame !!!", + __func__); + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + return; + } + } + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + + if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) + && (cfgState->actionFrmState == + HDD_PD_REQ_ACK_PENDING)) + || ((actionFrmType == WLAN_HDD_GO_NEG_RESP) + && (cfgState->actionFrmState == + HDD_GO_NEG_REQ_ACK_PENDING))) { + hddLog(LOG1, + "%s: ACK_PENDING and But received RESP for Action frame ", + __func__); + hdd_send_action_cnf(pAdapter, true); + } + } +#ifdef FEATURE_WLAN_TDLS + else if (pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] == + WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP) { + u8 *mac = + &pbFrames[WLAN_HDD_80211_FRM_DA_OFFSET + 6]; + + hddLog(LOG1, + "[TDLS] TDLS Discovery Response," + MAC_ADDRESS_STR " RSSI[%d] <--- OTA", + MAC_ADDR_ARRAY(mac), rxRssi); + + wlan_hdd_tdls_set_rssi(pAdapter, mac, rxRssi); + wlan_hdd_tdls_recv_discovery_resp(pAdapter, + mac); + } +#endif + } + + if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_TDLS_ACTION_FRAME) { + actionFrmType = + pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1]; + if (actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE) { + hddLog(LOG1, + "[TDLS] unknown[%d] <--- OTA", + actionFrmType); + } else { + hddLog(LOG1, + "[TDLS] %s <--- OTA", + tdls_action_frame_type[actionFrmType]); + } + } + + if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_QOS_ACTION_FRAME) + && (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] == + WLAN_HDD_QOS_MAP_CONFIGURE)) { + sme_update_dsc_pto_up_mapping(pHddCtx->hHal, + pAdapter->hddWmmDscpToUpMap, + pAdapter->sessionId); + } + } + /* Indicate Frame Over Normal Interface */ + hddLog(LOG1, FL("Indicate Frame over NL80211 Interface")); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0, pbFrames, + nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0, pbFrames, + nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED, + GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, 0, + pbFrames, nFrameLength, GFP_ATOMIC); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) + cfg80211_rx_mgmt(pAdapter->dev, freq, 0, + pbFrames, nFrameLength, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(pAdapter->dev, freq, + pbFrames, nFrameLength, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +} + diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c new file mode 100644 index 0000000000..d7662e8171 --- /dev/null +++ b/core/hdd/src/wlan_hdd_power.c @@ -0,0 +1,2346 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_power.c + * + * WLAN power management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include "cdf_types.h" +#include "sme_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "cfg_api.h" + +#include +#include +#include +#include +#include + +#include +#include "hif.h" +#include "sme_power_save_api.h" + +/* Preprocessor definitions and constants */ +#define HDD_SSR_BRING_UP_TIME 15000 + +/* Type declarations */ + +/** + * enum hdd_power_mode - Power Mode enumerations + * @DRIVER_POWER_MODE_AUTO: Driver can place device into power save + * @DRIVER_POWER_MODE_ACTIVE: Driver should operate at full power + */ +enum hdd_power_mode { + DRIVER_POWER_MODE_AUTO = 0, + DRIVER_POWER_MODE_ACTIVE = 1, +}; + +/* Function and variables declarations */ + +extern struct notifier_block hdd_netdev_notifier; + +static struct timer_list ssr_timer; +static bool ssr_timer_started; +/** + * hdd_conf_gtk_offload() - Configure GTK offload + * @pAdapter: pointer to the adapter + * @fenable: flag set to enable (1) or disable (0) GTK offload + * + * Central function to enable or disable GTK offload. + * + * Return: nothing + */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD +static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable) +{ + CDF_STATUS ret; + tSirGtkOffloadParams hddGtkOffloadReqParams; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (fenable) { + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (GTK_OFFLOAD_ENABLE == + pHddStaCtx->gtkOffloadReqParams.ulFlags)) { + cdf_mem_copy(&hddGtkOffloadReqParams, + &pHddStaCtx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + + ret = sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + &hddGtkOffloadReqParams, + pAdapter->sessionId); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: sme_set_gtk_offload failed, returned %d", + __func__, ret); + return; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: sme_set_gtk_offload successfull", + __func__); + } + + } else { + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (0 == + memcmp(&pHddStaCtx->gtkOffloadReqParams.bssId, + &pHddStaCtx->conn_info.bssId, CDF_MAC_ADDR_SIZE)) + && (GTK_OFFLOAD_ENABLE == + pHddStaCtx->gtkOffloadReqParams.ulFlags)) { + + /* Host driver has previously offloaded GTK rekey */ + ret = sme_get_gtk_offload + (WLAN_HDD_GET_HAL_CTX(pAdapter), + wlan_hdd_cfg80211_update_replay_counter_callback, + pAdapter, pAdapter->sessionId); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: sme_get_gtk_offload failed, returned %d", + __func__, ret); + return; + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: sme_get_gtk_offload successful", + __func__); + + /* Sending GTK offload dissable */ + memcpy(&hddGtkOffloadReqParams, + &pHddStaCtx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + hddGtkOffloadReqParams.ulFlags = + GTK_OFFLOAD_DISABLE; + ret = + sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX + (pAdapter), + &hddGtkOffloadReqParams, + pAdapter->sessionId); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: failed to dissable GTK offload, returned %d", + __func__, ret); + return; + } + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: successfully dissabled GTK offload request to HAL", + __func__); + } + } + } + return; +} +#else /* WLAN_FEATURE_GTK_OFFLOAD */ +static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable) +{ +} +#endif /*WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef WLAN_NS_OFFLOAD +/** + * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * This is a callback function that is registered with the kernel via + * register_inet6addr_notifier() which allows the driver to be + * notified when there is an IPv6 address change. + * + * Return: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; + struct net_device *ndev = ifa->idev->dev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + int status; + + if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hddLog(LOGE, FL("Adapter context is invalid %p"), pAdapter); + return -EINVAL; + } + + if ((pAdapter->dev == ndev) && + (pAdapter->device_mode == WLAN_HDD_INFRA_STATION || + pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return NOTIFY_DONE; + } + + schedule_work(&pAdapter->ipv6NotifierWorkQueue); + } + + return NOTIFY_DONE; +} + +/** + * wlan_hdd_ipv6_changed() - IPv6 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv6 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv6_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_conf_ns_offload() - Configure NS offload + * @pAdapter: pointer to the adapter + * @fenable: flag to enable or disable + * 0 - disable + * 1 - enable + * + * Return: nothing + */ +static void hdd_conf_ns_offload(hdd_adapter_t *pAdapter, bool fenable) +{ + struct inet6_dev *in6_dev; + struct inet6_ifaddr *ifp; + struct list_head *p; + uint8_t + selfIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [SIR_MAC_IPV6_ADDR_LEN] = { {0,} }; + bool selfIPv6AddrValid[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] = { 0 }; + tSirHostOffloadReq offLoadRequest; + hdd_context_t *pHddCtx; + + int i = 0; + CDF_STATUS returnStatus; + uint32_t count = 0, scope; + + ENTER(); + hddLog(LOG1, FL(" fenable = %d"), fenable); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* In SAP/P2PGo mode, ARP/NS offload feature capability + * is controlled by one bit. + */ + + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode || + WLAN_HDD_P2P_GO == pAdapter->device_mode) && + !pHddCtx->ap_arpns_support) { + hddLog(LOG1, + FL("NS Offload is not supported in SAP/P2PGO mode")); + return; + } + + if (fenable) { + in6_dev = __in6_dev_get(pAdapter->dev); + if (NULL != in6_dev) { + /* read_lock_bh(&in6_dev->lock); */ + list_for_each(p, &in6_dev->addr_list) { + if (count >= + SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { + hdd_err("Reached max supported NS Offload addresses"); + break; + } + ifp = + list_entry(p, struct inet6_ifaddr, if_list); + scope = ipv6_addr_src_scope(&ifp->addr); + + switch (scope) { + case IPV6_ADDR_SCOPE_GLOBAL: + case IPV6_ADDR_SCOPE_LINKLOCAL: + cdf_mem_copy(&selfIPv6Addr[count], + &ifp->addr.s6_addr, + sizeof(ifp->addr.s6_addr)); + selfIPv6AddrValid[count] = + SIR_IPV6_ADDR_VALID; + hdd_info("Index %d scope = %s Address : %pI6", + count, + (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? + "LINK LOCAL" : "GLOBAL", + selfIPv6Addr[count]); + count += 1; + break; + default: + hdd_err("The Scope %d is not supported", + scope); + } + } + /* read_unlock_bh(&in6_dev->lock); */ + cdf_mem_zero(&offLoadRequest, sizeof(offLoadRequest)); + for (i = 0; i < count; i++) { + /* Filling up the request structure + * Filling the selfIPv6Addr with solicited address + * A Solicited-Node multicast address is created by + * taking the last 24 bits of a unicast or anycast + * address and appending them to the prefix + * + * FF02:0000:0000:0000:0000:0001:FFXX:XXXX + * + * here XX is the unicast/anycast bits + */ + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][0] = 0xFF; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][1] = 0x02; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][11] = 0x01; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][12] = 0xFF; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][13] = + selfIPv6Addr[i][13]; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][14] = + selfIPv6Addr[i][14]; + offLoadRequest.nsOffloadInfo.selfIPv6Addr[i][15] = + selfIPv6Addr[i][15]; + offLoadRequest.nsOffloadInfo.slotIdx = i; + cdf_mem_copy(&offLoadRequest.nsOffloadInfo.targetIPv6Addr[i], + &selfIPv6Addr[i][0], SIR_MAC_IPV6_ADDR_LEN); + + offLoadRequest.nsOffloadInfo.targetIPv6AddrValid[i] = + SIR_IPV6_ADDR_VALID; + + hdd_info("configuredMcastBcastFilter: %d", + pHddCtx->configuredMcastBcastFilter); + + if ((true == pHddCtx->sus_res_mcastbcast_filter_valid) + && ((HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST == + pHddCtx->sus_res_mcastbcast_filter) || + (HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST == + pHddCtx->sus_res_mcastbcast_filter))) { + hdd_info("Set offLoadRequest with SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE"); + offLoadRequest.enableOrDisable = + SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE; + } + + cdf_mem_copy(&offLoadRequest.params.hostIpv6Addr, + &offLoadRequest.nsOffloadInfo.targetIPv6Addr[i], + SIR_MAC_IPV6_ADDR_LEN); + + hdd_info("Setting NSOffload with solicitedIp: %pI6, targetIp: %pI6, Index %d", + &offLoadRequest.nsOffloadInfo.selfIPv6Addr[i], + &offLoadRequest.nsOffloadInfo.targetIPv6Addr[i], i); + } + offLoadRequest.offloadType = SIR_IPV6_NS_OFFLOAD; + offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE; + cdf_mem_copy(&offLoadRequest.nsOffloadInfo.selfMacAddr, + &pAdapter->macAddressCurrent.bytes, SIR_MAC_ADDR_LEN); + /* set number of ns offload address count */ + offLoadRequest.num_ns_offload_count = count; + /* Configure the Firmware with this */ + returnStatus = sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offLoadRequest); + if (CDF_STATUS_SUCCESS != returnStatus) { + hdd_err("Failed to enable HostOffload feature with status: %d", + returnStatus); + } + } else { + hdd_err("IPv6 dev does not exist. Failed to request NSOffload"); + return; + } + } else { + /* Disable NSOffload */ + cdf_mem_zero((void *)&offLoadRequest, sizeof(tSirHostOffloadReq)); + offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE; + offLoadRequest.offloadType = SIR_IPV6_NS_OFFLOAD; + + if (CDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offLoadRequest)) + hdd_err("Failed to disable NS Offload"); + } + EXIT(); + return; +} + +/** + * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function + * @work: registered work item + * + * This function performs the work initially trigged by a callback + * from the IPv6 netdev notifier. Since this means there has been a + * change in IPv6 state for the interface, the NS offload is + * reconfigured. + * + * Return: None + */ +void __hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + hdd_adapter_t *pAdapter = + container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue); + hdd_context_t *pHddCtx; + int status; + + hddLog(LOG1, FL("Reconfiguring NS Offload")); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return; + } + + if (!pHddCtx->config->active_mode_offload) { + hdd_err("Active mode offload is disabled"); + return; + } + + if (false == pHddCtx->sus_res_mcastbcast_filter_valid) { + pHddCtx->sus_res_mcastbcast_filter = + pHddCtx->configuredMcastBcastFilter; + pHddCtx->sus_res_mcastbcast_filter_valid = true; + } + + if ((eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) + if (pHddCtx->config->fhostNSOffload) + hdd_conf_ns_offload(pAdapter, true); +} + +/** + * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv6_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_conf_hostoffload() - Central function to configure the supported offloads + * @pAdapter: pointer to the adapter + * @fenable: flag set to enable (1) or disable (0) + * + * Central function to configure the supported offloads either + * enable or disable them. + * + * Return: nothing + */ +void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable) +{ + hdd_context_t *pHddCtx; + + hdd_info("Configuring offloads with flag: %d", fenable); + + /* Get the HDD context. */ + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (((WLAN_HDD_INFRA_STATION != pAdapter->device_mode) && + (WLAN_HDD_P2P_CLIENT != pAdapter->device_mode))) { + hdd_err("Offloads not supported in mode %d", + pAdapter->device_mode); + return; + } + + if (eConnectionState_Associated != + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) { + hdd_err("Offloads not supported in state %d", + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.connState); + return; + } + + hdd_conf_gtk_offload(pAdapter, fenable); + + /* Configure ARP/NS offload during cfg80211 suspend/resume only + * if active mode offload is disabled + */ + if (!pHddCtx->config->active_mode_offload) { + hdd_conf_arp_offload(pAdapter, fenable); + if (pHddCtx->config->fhostNSOffload) + hdd_conf_ns_offload(pAdapter, fenable); + } + return; +} +#endif + +/** + * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function + * @work: registered work item + * + * This function performs the work initially trigged by a callback + * from the IPv4 netdev notifier. Since this means there has been a + * change in IPv4 state for the interface, the ARP offload is + * reconfigured. + * + * Return: None + */ +void __hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + hdd_adapter_t *pAdapter = + container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue); + hdd_context_t *pHddCtx; + int status; + + hdd_info("Configuring ARP Offload"); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return; + } + + if (!pHddCtx->config->active_mode_offload) { + hdd_err("Active mode offload is disabled"); + return; + } + + if (false == pHddCtx->sus_res_mcastbcast_filter_valid) { + pHddCtx->sus_res_mcastbcast_filter = + pHddCtx->configuredMcastBcastFilter; + pHddCtx->sus_res_mcastbcast_filter_valid = true; + } + + if ((eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) + hdd_conf_arp_offload(pAdapter, true); +} + +/** + * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv4_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +/** + * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * This is a callback function that is registered with the kernel via + * register_inetaddr_notifier() which allows the driver to be + * notified when there is an IPv4 address change. + * + * Return: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)arg; + struct in_ifaddr **ifap = NULL; + struct in_device *in_dev; + + struct net_device *ndev = ifa->ifa_dev->dev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + int status; + + if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hddLog(LOGE, FL("Adapter context is invalid %p"), pAdapter); + return -EINVAL; + } + + if ((pAdapter && pAdapter->dev == ndev) && + (pAdapter->device_mode == WLAN_HDD_INFRA_STATION || + pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) { + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return NOTIFY_DONE; + } + + if (!pHddCtx->config->fhostArpOffload) { + hddLog(LOG1, + FL("Offload not enabled ARPOffload=%d"), + pHddCtx->config->fhostArpOffload); + return NOTIFY_DONE; + } + + in_dev = __in_dev_get_rtnl(pAdapter->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(pAdapter->dev->name, + ifa->ifa_label)) { + break; /* found */ + } + } + } + if (ifa && ifa->ifa_local) { + schedule_work(&pAdapter->ipv4NotifierWorkQueue); + } + } + + return NOTIFY_DONE; +} + +/** + * wlan_hdd_ipv4_changed() - IPv4 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv4 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv4_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_conf_arp_offload() - Configure ARP offload + * @pAdapter: Adapter context for which ARP offload is to be configured + * @fenable: true : enable ARP offload false : disable arp offload + * + * Return: + * CDF_STATUS_SUCCESS - on successful operation, + * CDF_STATUS_E_FAILURE - on failure of operation + */ +CDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable) +{ + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + int i = 0; + tSirHostOffloadReq offLoadRequest; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + hdd_info("fenable = %d", fenable); + + /* In SAP/P2P Go mode, ARP/NS Offload feature capability + * is controlled by one bit. + */ + if ((WLAN_HDD_SOFTAP == pAdapter->device_mode || + WLAN_HDD_P2P_GO == pAdapter->device_mode) && + !pHddCtx->ap_arpns_support) { + hddLog(LOG1, + FL("ARP Offload is not supported in SAP/P2PGO mode")); + return CDF_STATUS_SUCCESS; + } + + if (fenable) { + in_dev = __in_dev_get_rtnl(pAdapter->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(pAdapter->dev->name, + ifa->ifa_label)) { + break; /* found */ + } + } + } + if (ifa && ifa->ifa_local) { + offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; + offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE; + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Enabled", __func__); + + if (((HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST == + pHddCtx->sus_res_mcastbcast_filter) || + (HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST + == pHddCtx->sus_res_mcastbcast_filter)) + && (true == + pHddCtx->sus_res_mcastbcast_filter_valid)) { + offLoadRequest.enableOrDisable = + SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; + hddLog(CDF_TRACE_LEVEL_INFO, + "offload: inside arp offload conditional check"); + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "offload: arp filter programmed = %d", + offLoadRequest.enableOrDisable); + + /* converting u32 to IPV4 address */ + for (i = 0; i < 4; i++) { + offLoadRequest.params.hostIpv4Addr[i] = + (ifa->ifa_local >> (i * 8)) & 0xFF; + } + hddLog(CDF_TRACE_LEVEL_INFO, + " Enable SME HostOffload: %d.%d.%d.%d", + offLoadRequest.params.hostIpv4Addr[0], + offLoadRequest.params.hostIpv4Addr[1], + offLoadRequest.params.hostIpv4Addr[2], + offLoadRequest.params.hostIpv4Addr[3]); + + if (CDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &offLoadRequest)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failed to enable HostOffload feature", + __func__); + return CDF_STATUS_E_FAILURE; + } + } else { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("IP Address is not assigned")); + } + + return CDF_STATUS_SUCCESS; + } else { + cdf_mem_zero((void *)&offLoadRequest, + sizeof(tSirHostOffloadReq)); + offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE; + offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; + + if (CDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offLoadRequest)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failure to disable host " "offload feature", + __func__); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; + } +} + +/** + * hdd_mcbc_filter_modification() - MCBC Filter Modifier + * @pHddCtx: Global Hdd Context + * @pMcBcFilter: Multicast/Broadcast filter to be modified + * + * This function is called before setting mcbc filters + * to modify filter value considering different offloads + * + * Return: None. + */ +static void hdd_mcbc_filter_modification(hdd_context_t *pHddCtx, + uint8_t *pMcBcFilter) +{ + if (NULL == pHddCtx) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("NULL HDD context passed")); + return; + } + + *pMcBcFilter = pHddCtx->configuredMcastBcastFilter; + if (pHddCtx->config->fhostArpOffload) { + /* ARP offload is enabled, do not block bcast packets at RXP + * Will be using Bitmasking to reset the filter. As we have + * disable Broadcast filtering, Anding with the negation + * of Broadcast BIT + */ + *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST); + } +#ifdef WLAN_NS_OFFLOAD + if (pHddCtx->config->fhostNSOffload) { + /* NS offload is enabled, do not block mcast packets at RXP + * Will be using Bitmasking to reset the filter. As we have + * disable Multicast filtering, Anding with the negation + * of Multicast BIT + */ + *pMcBcFilter &= ~(HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST); + } +#endif + + pHddCtx->configuredMcastBcastFilter = *pMcBcFilter; +} + +/** + * hdd_conf_mcastbcast_filter() - Configure multicast/broadcast filter + * @pHddCtx: Global HDD context + * @setfilter: true if filter is being set, false if filter is being cleared + * + * Return: None. + */ +void hdd_conf_mcastbcast_filter(hdd_context_t *pHddCtx, bool setfilter) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + tpSirWlanSetRxpFilters wlanRxpFilterParam = + cdf_mem_malloc(sizeof(tSirWlanSetRxpFilters)); + if (NULL == wlanRxpFilterParam) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: cdf_mem_alloc failed ", __func__); + return; + } + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Configuring Mcast/Bcast Filter Setting. setfilter %d", + __func__, setfilter); + if (true == setfilter) { + hdd_mcbc_filter_modification(pHddCtx, + &wlanRxpFilterParam-> + configuredMcstBcstFilterSetting); + } else { + /*Use the current configured value to clear */ + wlanRxpFilterParam->configuredMcstBcstFilterSetting = + pHddCtx->configuredMcastBcastFilter; + } + + wlanRxpFilterParam->setMcstBcstFilter = setfilter; + cdf_ret_status = + sme_configure_rxp_filter(pHddCtx->hHal, wlanRxpFilterParam); + + if (setfilter && (CDF_STATUS_SUCCESS == cdf_ret_status)) + pHddCtx->hdd_mcastbcast_filter_set = true; + + hddLog(LOG1, + FL("%s to post set/reset filter to lower mac with status %d configuredMcstBcstFilterSetting = %d setMcstBcstFilter = %d"), + (CDF_STATUS_SUCCESS != cdf_ret_status) ? "Failed" : "Success", + cdf_ret_status, + wlanRxpFilterParam->configuredMcstBcstFilterSetting, + wlanRxpFilterParam->setMcstBcstFilter); + + if (CDF_STATUS_SUCCESS != cdf_ret_status) + cdf_mem_free(wlanRxpFilterParam); +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * wlan_hdd_set_mc_addr_list() - set MC address list in FW + * @pAdapter: adapter whose MC list is being set + * @set: flag which indicates if addresses are being set or cleared + */ +void wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set) +{ + uint8_t i; + tpSirRcvFltMcAddrList pMulticastAddrs = NULL; + tHalHandle hHal = NULL; + hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx; + + if (NULL == pHddCtx) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD CTX is NULL")); + return; + } + + hHal = pHddCtx->hHal; + + if (NULL == hHal) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HAL Handle is NULL")); + return; + } + + /* Check if INI is enabled or not, other wise just return + */ + if (!pHddCtx->config->fEnableMCAddrList) { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("gMCAddrListEnable is not enabled in INI")); + return; + } + pMulticastAddrs = cdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (NULL == pMulticastAddrs) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Could not allocate Memory")); + return; + } + cdf_mem_zero(pMulticastAddrs, sizeof(tSirRcvFltMcAddrList)); + pMulticastAddrs->action = set; + + if (set) { + /* Following pre-conditions should be satisfied before we + * configure the MC address list. + */ + if (((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) + || (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) + && pAdapter->mc_addr_list.mc_cnt + && (eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.connState)) { + pMulticastAddrs->ulMulticastAddrCnt = + pAdapter->mc_addr_list.mc_cnt; + for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; + i++) { + memcpy(pMulticastAddrs->multicastAddr[i], + pAdapter->mc_addr_list.addr[i], + sizeof(pAdapter->mc_addr_list. + addr[i])); + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: %s multicast filter: addr =" + MAC_ADDRESS_STR, __func__, + set ? "setting" : "clearing", + MAC_ADDR_ARRAY(pMulticastAddrs-> + multicastAddr[i])); + } + /* Set multicast filter */ + sme_8023_multicast_list(hHal, pAdapter->sessionId, + pMulticastAddrs); + } + } else { + /* Need to clear only if it was previously configured */ + if (pAdapter->mc_addr_list.isFilterApplied) { + pMulticastAddrs->ulMulticastAddrCnt = + pAdapter->mc_addr_list.mc_cnt; + for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; + i++) { + memcpy(pMulticastAddrs->multicastAddr[i], + pAdapter->mc_addr_list.addr[i], + sizeof(pAdapter->mc_addr_list. + addr[i])); + } + sme_8023_multicast_list(hHal, pAdapter->sessionId, + pMulticastAddrs); + } + + } + /* MAddrCnt is MulticastAddrCnt */ + hddLog(CDF_TRACE_LEVEL_INFO, + "smeSessionId:%d; set:%d; MCAdddrCnt :%d", + pAdapter->sessionId, set, + pMulticastAddrs->ulMulticastAddrCnt); + + pAdapter->mc_addr_list.isFilterApplied = set ? true : false; + cdf_mem_free(pMulticastAddrs); + return; +} +#endif + +/** + * hdd_conf_suspend_ind() - Send Suspend notification + * @pHddCtx: HDD Global context + * @pAdapter: adapter being suspended + * @callback: callback function to be called upon completion + * @callbackContext: callback context to be passed back to callback function + * + * Return: None. + */ +static void hdd_conf_suspend_ind(hdd_context_t *pHddCtx, + hdd_adapter_t *pAdapter, + void (*callback)(void *callbackContext, + bool suspended), + void *callbackContext) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + tpSirWlanSuspendParam wlanSuspendParam = + cdf_mem_malloc(sizeof(tSirWlanSuspendParam)); + + if (false == pHddCtx->sus_res_mcastbcast_filter_valid) { + pHddCtx->sus_res_mcastbcast_filter = + pHddCtx->configuredMcastBcastFilter; + pHddCtx->sus_res_mcastbcast_filter_valid = true; + hddLog(CDF_TRACE_LEVEL_INFO, "offload: hdd_conf_suspend_ind"); + hddLog(CDF_TRACE_LEVEL_INFO, + "configuredMCastBcastFilter saved = %d", + pHddCtx->configuredMcastBcastFilter); + + } + + if (NULL == wlanSuspendParam) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: cdf_mem_alloc failed ", __func__); + return; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: send wlan suspend indication", __func__); + + /* Configure supported OffLoads */ + hdd_conf_hostoffload(pAdapter, true); + wlanSuspendParam->configuredMcstBcstFilterSetting = + pHddCtx->configuredMcastBcastFilter; + + /* Enable MC address filtering during cfg80211 suspend if active mode + * mode offload is disabled in INI + */ + if (!pHddCtx->config->active_mode_offload) { + hdd_info("enable mc address filtering"); + wlan_hdd_set_mc_addr_list(pAdapter, true); + } + + if ((eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) || + (eConnectionState_IbssConnected == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) + wlanSuspendParam->connectedState = true; + else + wlanSuspendParam->connectedState = false; + + wlanSuspendParam->sessionId = pAdapter->sessionId; + cdf_ret_status = + sme_configure_suspend_ind(pHddCtx->hHal, wlanSuspendParam, + callback, callbackContext); + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + pHddCtx->hdd_mcastbcast_filter_set = true; + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("sme_configure_suspend_ind returned failure %d"), + cdf_ret_status); + + cdf_mem_free(wlanSuspendParam); + } +} + +/** + * hdd_conf_suspend_ind() - Send Resume notification + * @pAdapter: adapter being resumed + * + * Return: None. + */ +static void hdd_conf_resume_ind(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + cdf_ret_status = sme_configure_resume_req(pHddCtx->hHal, NULL); + + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: sme_configure_resume_req return failure %d", + __func__, cdf_ret_status); + + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: send wlan resume indication", __func__); + /* Disable supported OffLoads */ + hdd_conf_hostoffload(pAdapter, false); + pHddCtx->hdd_mcastbcast_filter_set = false; + + if (true == pHddCtx->sus_res_mcastbcast_filter_valid) { + pHddCtx->configuredMcastBcastFilter = + pHddCtx->sus_res_mcastbcast_filter; + pHddCtx->sus_res_mcastbcast_filter_valid = false; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "offload: in hdd_conf_resume_ind, restoring configuredMcastBcastFilter"); + hddLog(CDF_TRACE_LEVEL_INFO, "configuredMcastBcastFilter = %d", + pHddCtx->configuredMcastBcastFilter); + + /* Disable MC address filtering during cfg80211 suspend if active mode + * mode offload is disabled in INI + */ + if (!pHddCtx->config->active_mode_offload) { + hdd_info("disable mc address filtering"); + wlan_hdd_set_mc_addr_list(pAdapter, false); + } +} + +/** + * hdd_suspend_wlan() - Driver suspend function + * @callback: Callback function to invoke when driver is ready to suspend + * @callbackContext: Context to pass back to @callback function + * + * Return: None. + */ +static void +hdd_suspend_wlan(void (*callback)(void *callbackContext, bool suspended), + void *callbackContext) +{ + hdd_context_t *pHddCtx; + + CDF_STATUS status; + hdd_adapter_t *pAdapter = NULL; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: WLAN being suspended by OS", + __func__); + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD context is Null", + __func__); + return; + } + + if (pHddCtx->isLogpInProgress) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Ignore suspend wlan, LOGP in progress!", __func__); + return; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + /* stop all TX queues before suspend */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE, + WLAN_CONTROL_PATH); + + /* Send suspend notification down to firmware. + * + * N.B.: Keep this suspend indication at the end + * (before processing next adaptor). This indication + * is considered as trigger point to start WOW (if wow + * is enabled). + */ + hdd_conf_suspend_ind(pHddCtx, pAdapter, callback, + callbackContext); + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + pHddCtx->hdd_wlan_suspended = true; + + return; +} + +/** + * hdd_resume_wlan() - Driver resume function + * + * Return: None. + */ +static void hdd_resume_wlan(void) +{ + hdd_context_t *pHddCtx; + hdd_adapter_t *pAdapter = NULL; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: WLAN being resumed by OS", + __func__); + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD context is Null", + __func__); + return; + } + + if (pHddCtx->isLogpInProgress) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Ignore resume wlan, LOGP in progress!", __func__); + return; + } + + pHddCtx->hdd_wlan_suspended = false; + + /*loop through all adapters. Concurrency */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + /* wake the tx queues */ + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + hdd_conf_resume_ind(pAdapter); + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + hdd_ipa_resume(pHddCtx); + + return; +} + +/** + * DOC: SSR Timer + * + * When SSR is initiated, an SSR timer is started. Under normal + * circumstances SSR should complete amd the timer should be deleted + * before it fires. If the SSR timer does fire, it indicates SSR has + * taken too long, and our only recourse is to invoke the CDF_BUG() + * API which can allow a crashdump to be captured. + */ + +/** + * hdd_ssr_timer_init() - Initialize SSR Timer + * + * Return: None. + */ +static void hdd_ssr_timer_init(void) +{ + init_timer(&ssr_timer); +} + +/** + * hdd_ssr_timer_del() - Delete SSR Timer + * + * Return: None. + */ +static void hdd_ssr_timer_del(void) +{ + del_timer(&ssr_timer); + ssr_timer_started = false; +} + +/** + * hdd_ssr_timer_cb() - SSR Timer callback function + * @data: opaque data registered with timer infrastructure + * + * Return: None. + */ +static void hdd_ssr_timer_cb(unsigned long data) +{ + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD SSR timer expired!", __func__); + CDF_BUG(0); +} + +/** + * hdd_ssr_timer_start() - Start SSR Timer + * @msec: Timer timeout value in milliseconds + * + * Return: None. + */ +static void hdd_ssr_timer_start(int msec) +{ + if (ssr_timer_started) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: Trying to start SSR timer when " "it's running!", + __func__); + } + ssr_timer.expires = jiffies + msecs_to_jiffies(msec); + ssr_timer.function = hdd_ssr_timer_cb; + add_timer(&ssr_timer); + ssr_timer_started = true; +} + +/** + * hdd_wlan_shutdown() - HDD SSR shutdown function + * + * This function is called by the HIF to shutdown the driver during SSR. + * + * Return: CDF_STATUS_SUCCESS if the driver was shut down, + * or an error status otherwise + */ +CDF_STATUS hdd_wlan_shutdown(void) +{ + CDF_STATUS cdf_status; + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx; + p_cds_sched_context cds_sched_context = NULL; + + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: WLAN driver shutting down!", + __func__); + +#ifdef WLAN_FEATURE_LPSS + wlan_hdd_send_status_pkg(NULL, NULL, 0, 0); +#endif + + /* If SSR never completes, then do kernel panic. */ + hdd_ssr_timer_init(); + hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME); + + /* Get the global CDS context. */ + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Global CDS context is Null", + __func__); + return CDF_STATUS_E_FAILURE; + } + + /* Get the HDD context. */ + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD context is Null", + __func__); + return CDF_STATUS_E_FAILURE; + } + + pHddCtx->isLogpInProgress = true; + cds_set_logp_in_progress(true); + + cds_clear_concurrent_session_count(); + + hdd_reset_all_adapters(pHddCtx); + + hdd_ipa_uc_ssr_deinit(); + + cds_sched_context = get_cds_sched_ctxt(); + + /* Wakeup all driver threads */ + if (true == pHddCtx->isMcThreadSuspended) { + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; + } +#ifdef QCA_CONFIG_SMP + if (true == pHddCtx->is_ol_rx_thread_suspended) { + complete(&cds_sched_context->ol_resume_rx_event); + pHddCtx->is_ol_rx_thread_suspended = false; + } +#endif + + /* Stop all the threads; we do not want any messages to be a processed, + * any more and the best way to ensure that is to terminate the threads + * gracefully. + */ + /* Wait for MC to exit */ + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Shutting down MC thread", __func__); + set_bit(MC_SHUTDOWN_EVENT_MASK, &cds_sched_context->mcEventFlag); + set_bit(MC_POST_EVENT_MASK, &cds_sched_context->mcEventFlag); + wake_up_interruptible(&cds_sched_context->mcWaitQueue); + wait_for_completion(&cds_sched_context->McShutdown); + +#ifdef QCA_CONFIG_SMP + /* Wait for OL RX to exit */ + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Shutting down OL RX thread", + __func__); + unregister_hotcpu_notifier(cds_sched_context->cpu_hot_plug_notifier); + set_bit(RX_SHUTDOWN_EVENT_MASK, &cds_sched_context->ol_rx_event_flag); + set_bit(RX_POST_EVENT_MASK, &cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue); + wait_for_completion(&cds_sched_context->ol_rx_shutdown); + cds_sched_context->ol_rx_thread = NULL; + cds_drop_rxpkt_by_staid(cds_sched_context, WLAN_MAX_STA_COUNT); + cds_free_ol_rx_pkt_freeq(cds_sched_context); +#endif + + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Doing WMA STOP", __func__); + cdf_status = wma_stop(p_cds_context, HAL_STOP_TYPE_RF_KILL); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop WMA", __func__); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + wma_setneedshutdown(p_cds_context); + } + + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Doing SME STOP", __func__); + /* Stop SME - Cannot invoke cds_disable as cds_disable relies + * on threads being running to process the SYS Stop + */ + cdf_status = sme_stop(pHddCtx->hHal, HAL_STOP_TYPE_SYS_RESET); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop sme %d", __func__, cdf_status); + CDF_ASSERT(0); + } + + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Doing MAC STOP", __func__); + /* Stop MAC (PE and HAL) */ + cdf_status = mac_stop(pHddCtx->hHal, HAL_STOP_TYPE_SYS_RESET); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop mac %d", __func__, cdf_status); + CDF_ASSERT(0); + } + + hif_disable_isr(((cds_context_type *) p_cds_context)->pHIFContext); + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Flush Queues", __func__); + /* Clean up message queues of TX, RX and MC thread */ + cds_sched_flush_mc_mqs(cds_sched_context); + + /* Deinit all the TX, RX and MC queues */ + cds_sched_deinit_mqs(cds_sched_context); + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: Doing CDS Shutdown", __func__); + /* shutdown CDS */ + cds_shutdown(p_cds_context); + + /*mac context has already been released in mac_close call + so setting it to NULL in hdd context */ + pHddCtx->hHal = (tHalHandle) NULL; + + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: WLAN driver shutdown complete", + __func__); + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wlan_re_init() - HDD SSR re-init function + * + * This function is called by the HIF to re-initialize the driver after SSR. + * + * Return: CDF_STATUS_SUCCESS if the driver was re-initialized, + * or an error status otherwise + */ +CDF_STATUS hdd_wlan_re_init(void *hif_sc) +{ + CDF_STATUS cdf_status; + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx = NULL; + CDF_STATUS cdf_ret_status; + hdd_adapter_t *pAdapter; + int i; + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + + /* Get the CDS context */ + p_cds_context = cds_get_global_context(); + if (p_cds_context == NULL) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: Failed cds_get_global_context", __func__); + goto err_re_init; + } + + /* Get the HDD context */ + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (!pHddCtx) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HDD context is Null", + __func__); + goto err_re_init; + } + + if (!hif_sc) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: hif_sc is NULL", __func__); + goto err_re_init; + } + + ((cds_context_type *) p_cds_context)->pHIFContext = hif_sc; + + /* The driver should always be initialized in STA mode after SSR */ + hdd_set_conparam(0); + + /* Re-open CDS, it is a re-open b'se control transport was never closed. */ + cdf_status = cds_open(&p_cds_context, 0); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_open failed", __func__); + goto err_re_init; + } + + /* Save the hal context in Adapter */ + pHddCtx->hHal = cds_get_context(CDF_MODULE_ID_SME); + if (NULL == pHddCtx->hHal) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: HAL context is null", + __func__); + goto err_cds_close; + } + + /* Set the SME configuration parameters. */ + cdf_status = hdd_set_sme_config(pHddCtx); + if (CDF_STATUS_SUCCESS != cdf_status) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: Failed hdd_set_sme_config", + __func__); + goto err_cds_close; + } + + cdf_status = cds_pre_enable(pHddCtx->pcds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_pre_enable failed", + __func__); + goto err_cds_close; + } + + ol_txrx_register_pause_cb(wlan_hdd_txrx_pause_cb); + + cdf_status = hdd_set_sme_chan_list(pHddCtx); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: Failed to init channel list", __func__); + goto err_cds_close; + } + + /* Apply the cfg.ini to cfg.dat */ + if (false == hdd_update_config_dat(pHddCtx)) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: config update failed", + __func__); + goto err_cds_close; + } + + /* Set the MAC Address, currently this is used by HAL to add self sta. + * Remove this once self sta is added as part of session open. */ + cdf_ret_status = cfg_set_str(pHddCtx->hHal, WNI_CFG_STA_ID, + (uint8_t *) &pHddCtx->config-> + intfMacAddr[0], + sizeof(pHddCtx->config->intfMacAddr[0])); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Failed to set MAC Address. " + "HALStatus is %08d [x%08x]", __func__, cdf_ret_status, + cdf_ret_status); + goto err_cds_close; + } + + /* Start CDS which starts up the SME/MAC/HAL modules and everything else + Note: Firmware image will be read and downloaded inside cds_enable API */ + cdf_status = cds_enable(p_cds_context); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_enable failed", __func__); + goto err_cds_close; + } + + cdf_status = hdd_post_cds_enable_config(pHddCtx); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: hdd_post_cds_enable_config failed", __func__); + goto err_cds_disable; + } + + /* Try to get an adapter from mode ID */ + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION); + if (!pAdapter) { + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_SOFTAP); + if (!pAdapter) { + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_IBSS); + if (!pAdapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: Failed to get Adapter!", __func__); + } + } + } + + if (hdd_ipa_uc_ssr_reinit()) + hddLog(LOGE, "%s: HDD IPA UC reinit failed", __func__); + + /* Get WLAN Host/FW/HW version */ + if (pAdapter) + hdd_wlan_get_version(pAdapter, NULL, NULL); + + /* Pass FW version to HIF layer */ + hif_set_fw_info(hif_sc, pHddCtx->target_fw_version); + + /* Restart all adapters */ + hdd_start_all_adapters(pHddCtx); + + /* Reconfigure FW logs after SSR */ + if (pAdapter) { + if (pHddCtx->fw_log_settings.enable != 0) { + wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_ENABLE, + pHddCtx->fw_log_settings.enable, + DBG_CMD); + } else { + wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_DISABLE, + pHddCtx->fw_log_settings.enable, + DBG_CMD); + } + + if (pHddCtx->fw_log_settings.dl_report != 0) { + wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_REPORT_ENABLE, + pHddCtx->fw_log_settings. + dl_report, DBG_CMD); + + wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_TYPE, + pHddCtx->fw_log_settings. + dl_type, DBG_CMD); + + wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + pHddCtx->fw_log_settings. + dl_loglevel, DBG_CMD); + + for (i = 0; i < MAX_MOD_LOGLEVEL; i++) { + if (pHddCtx->fw_log_settings. + dl_mod_loglevel[i] != 0) { + wma_cli_set_command( + pAdapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + pHddCtx->fw_log_settings. + dl_mod_loglevel[i], + DBG_CMD); + } + } + } + } + + pHddCtx->hdd_mcastbcast_filter_set = false; + pHddCtx->btCoexModeSet = false; + hdd_ssr_timer_del(); + + wlan_hdd_send_svc_nlink_msg(WLAN_SVC_FW_CRASHED_IND, NULL, 0); + + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + + sme_ext_scan_register_callback(pHddCtx->hHal, + wlan_hdd_cfg80211_extscan_callback); + sme_set_rssi_threshold_breached_cb(pHddCtx->hHal, hdd_rssi_threshold_breached); + +#ifdef WLAN_FEATURE_LPSS + wlan_hdd_send_all_scan_intf_info(pHddCtx); + wlan_hdd_send_version_pkg(pHddCtx->target_fw_version, + pHddCtx->target_hw_version, + pHddCtx->target_hw_name); +#endif + + hif_enable_power_gating(hif_sc); + hddLog(LOGE, + "%s: WLAN host driver reinitiation completed!", __func__); + goto success; + +err_cds_disable: + cds_disable(p_cds_context); + +err_cds_close: + cds_close(p_cds_context); + cds_sched_close(p_cds_context); + if (pHddCtx) { + /* Unregister the Net Device Notifier */ + unregister_netdevice_notifier(&hdd_netdev_notifier); +#ifdef WLAN_KD_READY_NOTIFIER + cnss_diag_notify_wlan_close(); + ptt_sock_deactivate_svc(); +#endif /* WLAN_KD_READY_NOTIFIER */ + nl_srv_exit(); + + /* Free up dynamically allocated members inside HDD Adapter */ + kfree(pHddCtx->config); + pHddCtx->config = NULL; + + wiphy_unregister(pHddCtx->wiphy); + wiphy_free(pHddCtx->wiphy); + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_destroy( + &pHddCtx->hdd_conc_list_lock))) { + hdd_err("Failed to destroy hdd_conc_list_lock"); + /* Proceed and complete the clean up */ + } + } + +err_re_init: + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + CDF_BUG(0); + return -EPERM; + +success: + pHddCtx->isLogpInProgress = false; + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_set_powersave() - Set powersave mode + * @adapter: adapter upon which the request was received + * @mode: desired powersave mode + * + * Return: 0 on success, non-zero on any error + */ +static int +wlan_hdd_set_powersave(hdd_adapter_t *adapter, enum hdd_power_mode mode) +{ + tHalHandle hal; + hdd_context_t *hdd_ctx; + + if (NULL == adapter) { + hddLog(CDF_TRACE_LEVEL_FATAL, FL("Adapter NULL")); + return -ENODEV; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err(FL("hdd context is NULL")); + return -EINVAL; + } + + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, FL("power mode=%d"), mode); + hal = WLAN_HDD_GET_HAL_CTX(adapter); + + + if (DRIVER_POWER_MODE_ACTIVE == mode) { + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Wlan driver Entering Full Power")); + + /* + * Enter Full power command received from GUI + * this means we are disconnected + */ + sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE); + } else if (DRIVER_POWER_MODE_AUTO == mode) { + if ((WLAN_HDD_INFRA_STATION == adapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == adapter->device_mode)) { + hddLog(LOG1, FL("Disabling Auto Power save timer")); + sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX + (adapter), + adapter->sessionId); + } + if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) { + hddLog(LOG1, FL("Wlan driver Entering Power save")); + + /* + * Enter Power Save command received from GUI + * this means DHCP is completed + */ + sme_ps_enable_disable(hal, adapter->sessionId, + SME_PS_ENABLE); + } else { + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + FL("Power Save is not enabled in the cfg")); + } + } + return 0; +} + +/** + * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_adapter_t *pAdapter; + hdd_adapter_list_node_t *pAdapterNode, *pNext; + CDF_STATUS status = CDF_STATUS_SUCCESS; + int result; + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + result = wlan_hdd_validate_context(pHddCtx); + if (0 != result) { + hddLog(LOGE, FL("HDD context is not valid")); + return result; + } +#ifdef CONFIG_CNSS + cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_MEDIUM); +#endif + + /* Resume MC thread */ + if (pHddCtx->isMcThreadSuspended) { + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; + } +#ifdef QCA_CONFIG_SMP + /* Resume tlshim Rx thread */ + if (pHddCtx->is_ol_rx_thread_suspended) { + complete(&cds_sched_context->ol_resume_rx_event); + pHddCtx->is_ol_rx_thread_suspended = false; + } +#endif + hdd_resume_wlan(); + + spin_lock(&pHddCtx->schedScan_lock); + pHddCtx->isWiphySuspended = false; + if (true != pHddCtx->isSchedScanUpdatePending) { + spin_unlock(&pHddCtx->schedScan_lock); + hddLog(LOG1, FL("Return resume is not due to PNO indication")); + return 0; + } + /* Reset flag to avoid updatating cfg80211 data old results again */ + pHddCtx->isSchedScanUpdatePending = false; + spin_unlock(&pHddCtx->schedScan_lock); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + if ((NULL != pAdapter) && + (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)) { + if (0 != + wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, + pAdapter, 0)) { + hddLog(LOGW, FL("NO SCAN result")); + } else { + /* Acquire wakelock to handle the case where + * APP's tries to suspend immediately after + * updating the scan results. Whis results in + * app's is in suspended state and not able to + * process the connect request to AP + */ + hdd_prevent_suspend_timeout(2000, + WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN); + cfg80211_sched_scan_results(pHddCtx->wiphy); + } + + hddLog(LOG1, + FL("cfg80211 scan result database updated")); + + return result; + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + hddLog(LOG1, FL("Failed to find Adapter")); + return result; +} + +/** + * wlan_hdd_cfg80211_ready_to_suspend() - set cfg80211 ready to suspend event + * @callbackContext: Pointer to callback context + * @suspended: Suspend flag + * + * Return: none + */ +static void wlan_hdd_cfg80211_ready_to_suspend(void *callbackContext, + bool suspended) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) callbackContext; + pHddCtx->suspended = suspended; + complete(&pHddCtx->ready_to_suspend); +} + +/** + * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_resume_wlan(wiphy); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ +#ifdef QCA_CONFIG_SMP +#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */ +#endif + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter; + hdd_scaninfo_t *pScanInfo; + CDF_STATUS status; + int rc; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + rc = wlan_hdd_validate_context(pHddCtx); + if (0 != rc) { + hddLog(LOGE, FL("HDD context is not valid")); + return rc; + } + + /* If RADAR detection is in progress (HDD), prevent suspend. The flag + * "dfs_cac_block_tx" is set to true when RADAR is found and stay true + * until CAC is done for a SoftAP which is in started state. + */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + if (WLAN_HDD_SOFTAP == pAdapter->device_mode) { + if (BSS_START == + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState && + true == + WLAN_HDD_GET_AP_CTX_PTR(pAdapter)-> + dfs_cac_block_tx) { + hddLog(LOG1, + FL("RADAR detection in progress, do not allow suspend")); + return -EAGAIN; + } else if (!pHddCtx->config->enableSapSuspend) { + /* return -EOPNOTSUPP if SAP does not support + * suspend + */ + hddLog(LOGE, + FL("SAP does not support suspend!!")); + return -EOPNOTSUPP; + } + } else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) { + if (!pHddCtx->config->enableSapSuspend) { + /* return -EOPNOTSUPP if GO does not support + * suspend + */ + hddLog(LOGE, + FL("GO does not support suspend!!")); + return -EOPNOTSUPP; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* Stop ongoing scan on each interface */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + pScanInfo = &pAdapter->scan_info; + + if (sme_sta_in_middle_of_roaming + (pHddCtx->hHal, pAdapter->sessionId)) { + hddLog(LOG1, + FL("Roaming in progress, do not allow suspend")); + return -EAGAIN; + } + + if (pHddCtx->config->is_ps_enabled) { + if (sme_is_auto_ps_timer_running(pHddCtx->hHal, + pAdapter->sessionId)) { + hddLog(LOGE, + FL("Auto Power save timer is running; Do not allow suspend")); + return -EAGAIN; + } else { + sme_ps_enable_disable(pHddCtx->hHal, + pAdapter->sessionId, + SME_PS_ENABLE); + hddLog(LOG1, + FL("Auto PS timer is not running; allow suspend and enter into power save")); + } + } + + if (pScanInfo->mScanPending) { + INIT_COMPLETION(pScanInfo->abortscan_event_var); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + + status = + wait_for_completion_timeout(&pScanInfo-> + abortscan_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN)); + if (!status) { + hddLog(LOGE, + FL("Timeout occurred while waiting for abort scan")); + return -ETIME; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* + * Suspend IPA early before proceeding to suspend other entities like + * firmware to avoid any race conditions. + */ + if (hdd_ipa_suspend(pHddCtx)) { + hddLog(LOG1, FL("IPA not ready to suspend!")); + return -EAGAIN; + } + + /* Wait for the target to be ready for suspend */ + INIT_COMPLETION(pHddCtx->ready_to_suspend); + + hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx); + + rc = wait_for_completion_timeout(&pHddCtx->ready_to_suspend, + msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_SUSPEND)); + if (!rc) { + hddLog(LOGE, FL("Failed to get ready to suspend")); + goto resume_tx; + } + + if (!pHddCtx->suspended) { + hddLog(LOGE, FL("Faied as suspend_status is wrong:%d"), + pHddCtx->suspended); + goto resume_tx; + } + + /* Suspend MC thread */ + set_bit(MC_SUSPEND_EVENT_MASK, &cds_sched_context->mcEventFlag); + wake_up_interruptible(&cds_sched_context->mcWaitQueue); + + /* Wait for suspend confirmation from MC thread */ + rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND)); + if (!rc) { + clear_bit(MC_SUSPEND_EVENT_MASK, + &cds_sched_context->mcEventFlag); + hddLog(LOGE, FL("Failed to stop mc thread")); + goto resume_tx; + } + + pHddCtx->isMcThreadSuspended = true; + +#ifdef QCA_CONFIG_SMP + /* Suspend tlshim rx thread */ + set_bit(RX_SUSPEND_EVENT_MASK, &cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue); + rc = wait_for_completion_timeout(&cds_sched_context-> + ol_suspend_rx_event, + msecs_to_jiffies + (RX_TLSHIM_SUSPEND_TIMEOUT)); + if (!rc) { + clear_bit(RX_SUSPEND_EVENT_MASK, + &cds_sched_context->ol_rx_event_flag); + hddLog(LOGE, FL("Failed to stop tl_shim rx thread")); + goto resume_all; + } + pHddCtx->is_ol_rx_thread_suspended = true; +#endif + + pHddCtx->isWiphySuspended = true; + +#ifdef CONFIG_CNSS + cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_NONE); +#endif + + EXIT(); + return 0; + +#ifdef QCA_CONFIG_SMP +resume_all: + + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; +#endif + +resume_tx: + + hdd_resume_wlan(); + return -ETIME; + +} + +/** + * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mode: Driver mode + * @timeout: Timeout value + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool mode, + int timeout) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + CDF_STATUS cdf_status; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT, + pAdapter->sessionId, timeout)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + if ((DRIVER_POWER_MODE_AUTO == !mode) && + (true == pHddCtx->hdd_wlan_suspended) && + (pHddCtx->config->fhostArpOffload) && + (eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) { + + hddLog(LOG1, + FL("offload: in cfg80211_set_power_mgmt, calling arp offload")); + cdf_status = hdd_conf_arp_offload(pAdapter, true); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOG1, + FL("Failed to enable ARPOFFLOAD Feature %d"), + cdf_status); + } + } + + status = wlan_hdd_set_powersave(pAdapter, !mode); + + if (!mode) { + hddLog(LOGE, FL("DHCP start indicated through power save")); + sme_dhcp_start_ind(pHddCtx->hHal, pAdapter->device_mode, + pAdapter->macAddressCurrent.bytes, + pAdapter->sessionId); + } else { + hddLog(LOGW, FL("DHCP stop indicated through power save")); + sme_dhcp_stop_ind(pHddCtx->hHal, pAdapter->device_mode, + pAdapter->macAddressCurrent.bytes, + pAdapter->sessionId); + } + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mode: Driver mode + * @timeout: Timeout value + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool mode, + int timeout) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, mode, timeout); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @dbm: TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + struct wireless_dev *wdev, +#endif + enum nl80211_tx_power_setting type, + int dbm) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + tHalHandle hHal = NULL; + tSirMacAddr bssid = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirMacAddr selfMac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_TXPOWER, + NO_SESSION, type)); + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + hHal = pHddCtx->hHal; + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) { + hddLog(LOGE, FL("sme_cfg_set_int failed for tx power %hu"), + dbm); + return -EIO; + } + + hddLog(LOG2, FL("Set tx power level %d dbm"), dbm); + + switch (type) { + /* Automatically determine transmit power */ + case NL80211_TX_POWER_AUTOMATIC: + /* Fall through */ + case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */ + if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, FL("Setting maximum tx power failed")); + return -EIO; + } + break; + + case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */ + hddLog(LOGE, FL("NL80211_TX_POWER_FIXED not supported")); + return -EOPNOTSUPP; + break; + + default: + hddLog(LOGE, FL("Invalid power setting type %d"), type); + return -EIO; + } + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @dbm: TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + struct wireless_dev *wdev, +#endif + enum nl80211_tx_power_setting type, + int dbm) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_txpower(wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + wdev, +#endif + type, dbm); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_get_txpower() - get TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @dbm: Pointer to TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) + struct wireless_dev *wdev, +#endif + int *dbm) +{ + + hdd_adapter_t *pAdapter; + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + int status; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + *dbm = 0; + return status; + } + + pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION); + if (NULL == pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL")); + return -ENOENT; + } + + wlan_hdd_get_class_astats(pAdapter); + *dbm = pAdapter->hdd_stats.ClassA_stat.max_pwr; + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function + * @wiphy: Pointer to wiphy structure. + * @wdev: Pointer to wireless_dev structure. + * @dbm: dbm + * + * This is the cfg80211 get txpower handler function which invokes + * the internal function @__wlan_hdd_cfg80211_get_txpower with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) || defined(WITH_BACKPORTS) + struct wireless_dev *wdev, +#endif + int *dbm) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_txpower(wiphy, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) || defined(WITH_BACKPORTS) + wdev, +#endif + dbm); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c new file mode 100644 index 0000000000..2804c59f2f --- /dev/null +++ b/core/hdd/src/wlan_hdd_scan.c @@ -0,0 +1,2429 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_scan.c + * + * WLAN Host Device Driver scan implementation + */ + +#include +#include + +#include "wlan_hdd_includes.h" +#include "cds_api.h" +#include "cds_api.h" +#include "ani_global.h" +#include "dot11f.h" +#include "cds_sched.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_scan.h" +#include "cds_concurrency.h" +#include "wma_api.h" + +#define MAX_RATES 12 +#define HDD_WAKE_LOCK_SCAN_DURATION (5 * 1000) /* in msec */ + +#define SCAN_DONE_EVENT_BUF_SIZE 4096 +#define RATE_MASK 0x7f + +/** + * typedef tSSIDBcastType - SSID broadcast type + * @eBCAST_UNKNOWN: Broadcast unknown + * @eBCAST_NORMAL: Broadcast normal + * @eBCAST_HIDDEN: Broadcast hidden + */ +typedef enum eSSIDBcastType { + eBCAST_UNKNOWN = 0, + eBCAST_NORMAL = 1, + eBCAST_HIDDEN = 2, +} tSSIDBcastType; + + +/** + * typedef hdd_scan_info_t - HDD scan info + * @dev: Pointer to net device + * @info: Pointer to request info + * @start: Start pointer + * @end: End pointer + */ +typedef struct hdd_scan_info { + struct net_device *dev; + struct iw_request_info *info; + char *start; + char *end; +} hdd_scan_info_t, *hdd_scan_info_tp; + +/** + * hdd_translate_abg_rate_to_mbps_rate() - translate abg rate to Mbps rate + * @pFcRate: Rate pointer + * + * Return: Mbps rate in integer + */ +static int32_t hdd_translate_abg_rate_to_mbps_rate(uint8_t *pFcRate) +{ + /* Slightly more sophisticated processing has to take place here. + * Basic rates are rounded DOWN. HT rates are rounded UP + */ + return ((((int32_t) *pFcRate) & 0x007f) * 1000000) / 2; +} + +/** + * hdd_add_iw_stream_event() - add iw stream event + * @cmd: Command + * @length: Length + * @data: Pointer to data + * @pscanInfo: Pointer to scan info + * @last_event: Pointer to pointer to last event + * @current_event: Pointer to pointer to current event + * + * Return: 0 for success, non zero for failure + */ +static int hdd_add_iw_stream_event(int cmd, int length, char *data, + hdd_scan_info_t *pscanInfo, + char **last_event, + char **current_event) +{ + struct iw_event event; + + *last_event = *current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + event.cmd = cmd; + event.u.data.flags = 1; + event.u.data.length = length; + *current_event = + iwe_stream_add_point(pscanInfo->info, *current_event, + pscanInfo->end, &event, data); + + if (*last_event == *current_event) { + /* no space to add event */ + hddLog(LOGE, "%s: no space left to add event", __func__); + return -E2BIG; /* Error code, may be E2BIG */ + } + + return 0; +} + +/** + * hdd_get_wparsn_ies() - get wpa RSN IEs + * @ieFields: Pointer to the Bss Descriptor IEs + * @ie_length: IE Length + * @last_event: Points to last event + * @current_event: Points to current event + * + * This function extract the WPA/RSN IE from the Bss descriptor IEs fields + * + * Return: 0 for success, non zero for failure + */ +static int hdd_get_wparsn_ies(uint8_t *ieFields, uint16_t ie_length, + char **last_event, char **current_event, + hdd_scan_info_t *pscanInfo) +{ + uint8_t eid, elen, *element; + uint16_t tie_length = 0; + + ENTER(); + + element = ieFields; + tie_length = ie_length; + + while (tie_length > 2 && element != NULL) { + eid = element[0]; + elen = element[1]; + + /* If element length is greater than total remaining ie length, + * break the loop + */ + if ((elen + 2) > tie_length) + break; + + switch (eid) { + case DOT11F_EID_WPA: + case DOT11F_EID_RSN: +#ifdef FEATURE_WLAN_WAPI + case DOT11F_EID_WAPI: +#endif + if (hdd_add_iw_stream_event + (IWEVGENIE, elen + 2, (char *)element, pscanInfo, + last_event, current_event) < 0) + return -E2BIG; + break; + + default: + break; + } + + /* Next element */ + tie_length -= (2 + elen); + element += 2 + elen; + } + + return 0; +} + +/** + * hdd_indicate_scan_result() - indicate scan results + * @scanInfo: Pointer to the scan info structure. + * @descriptor: Pointer to the Bss Descriptor. + * + * This function returns the scan results to the wpa_supplicant + * + * @Return: 0 for success, non zero for failure + */ +#define MAX_CUSTOM_LEN 64 +static int hdd_indicate_scan_result(hdd_scan_info_t *scanInfo, + tCsrScanResultInfo *scan_result) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tSirBssDescription *descriptor = &scan_result->BssDescriptor; + struct iw_event event; + char *current_event = scanInfo->start; + char *end = scanInfo->end; + char *last_event; + char *current_pad; + uint16_t ie_length = 0; + uint16_t capabilityInfo; + char *modestr; + int error; + char custom[MAX_CUSTOM_LEN]; + char *p; + + hddLog(LOG1, "hdd_indicate_scan_result " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(descriptor->bssId)); + + error = 0; + last_event = current_event; + cdf_mem_zero(&event, sizeof(event)); + + /* BSSID */ + event.cmd = SIOCGIWAP; + event.u.ap_addr.sa_family = ARPHRD_ETHER; + cdf_mem_copy(event.u.ap_addr.sa_data, descriptor->bssId, + sizeof(descriptor->bssId)); + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_ADDR_LEN); + + if (last_event == current_event) { + /* no space to add event */ + /* Error code may be E2BIG */ + hddLog(LOGE, "hdd_indicate_scan_result: no space for SIOCGIWAP "); + return -E2BIG; + } + + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + /* Protocol Name */ + event.cmd = SIOCGIWNAME; + + switch (descriptor->nwType) { + case eSIR_11A_NW_TYPE: + modestr = "a"; + break; + case eSIR_11B_NW_TYPE: + modestr = "b"; + break; + case eSIR_11G_NW_TYPE: + modestr = "g"; + break; + case eSIR_11N_NW_TYPE: + modestr = "n"; + break; + default: + hddLog(LOGW, "%s: Unknown network type [%d]", + __func__, descriptor->nwType); + modestr = "?"; + break; + } + snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr); + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_CHAR_LEN); + + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWNAME"); + /* Error code, may be E2BIG */ + return -E2BIG; + } + + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + /*Freq */ + event.cmd = SIOCGIWFREQ; + + event.u.freq.m = descriptor->channelId; + event.u.freq.e = 0; + event.u.freq.i = 0; + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_FREQ_LEN); + + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWFREQ"); + return -E2BIG; + } + + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + /* BSS Mode */ + event.cmd = SIOCGIWMODE; + + capabilityInfo = descriptor->capabilityInfo; + + if (SIR_MAC_GET_ESS(capabilityInfo)) { + event.u.mode = IW_MODE_MASTER; + } else if (SIR_MAC_GET_IBSS(capabilityInfo)) { + event.u.mode = IW_MODE_ADHOC; + } else { + /* neither ESS or IBSS */ + event.u.mode = IW_MODE_AUTO; + } + + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_UINT_LEN); + + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWMODE"); + return -E2BIG; + } + /* To extract SSID */ + ie_length = GET_IE_LEN_IN_BSS(descriptor->length); + + if (ie_length > 0) { + /* dot11BeaconIEs is a large struct, so we make it static to + avoid stack overflow. This API is only invoked via ioctl, + so it is serialized by the kernel rtnl_lock and hence does + not need to be reentrant */ + static tDot11fBeaconIEs dot11BeaconIEs; + tDot11fIESSID *pDot11SSID; + tDot11fIESuppRates *pDot11SuppRates; + tDot11fIEExtSuppRates *pDot11ExtSuppRates; + tDot11fIEHTCaps *pDot11IEHTCaps; + int numBasicRates = 0; + int maxNumRates = 0; + + pDot11IEHTCaps = NULL; + + dot11f_unpack_beacon_i_es((tpAniSirGlobal) + hHal, (uint8_t *) descriptor->ieFields, + ie_length, &dot11BeaconIEs); + + pDot11SSID = &dot11BeaconIEs.SSID; + + if (pDot11SSID->present) { + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + event.cmd = SIOCGIWESSID; + event.u.data.flags = 1; + event.u.data.length = scan_result->ssId.length; + current_event = + iwe_stream_add_point(scanInfo->info, current_event, + end, &event, + (char *)scan_result->ssId. + ssId); + + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWESSID"); + return -E2BIG; + } + } + + if (hdd_get_wparsn_ies + ((uint8_t *) descriptor->ieFields, ie_length, &last_event, + ¤t_event, scanInfo) < 0) { + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWESSID"); + return -E2BIG; + } + + last_event = current_event; + current_pad = current_event + IW_EV_LCP_LEN; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + /*Rates */ + event.cmd = SIOCGIWRATE; + + pDot11SuppRates = &dot11BeaconIEs.SuppRates; + + if (pDot11SuppRates->present) { + int i; + + numBasicRates = pDot11SuppRates->num_rates; + for (i = 0; i < pDot11SuppRates->num_rates; i++) { + if (0 != (pDot11SuppRates->rates[i] & 0x7F)) { + event.u.bitrate.value = + hdd_translate_abg_rate_to_mbps_rate + (&pDot11SuppRates->rates[i]); + + current_pad = + iwe_stream_add_value(scanInfo->info, + current_event, + current_pad, + end, &event, + IW_EV_PARAM_LEN); + } + } + + } + + pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates; + + if (pDot11ExtSuppRates->present) { + int i, no_of_rates; + maxNumRates = + numBasicRates + pDot11ExtSuppRates->num_rates; + + /* Check to make sure the total number of rates + * doesn't exceed IW_MAX_BITRATES + */ + + maxNumRates = CDF_MIN(maxNumRates, IW_MAX_BITRATES); + + if ((maxNumRates - numBasicRates) > MAX_RATES) { + no_of_rates = MAX_RATES; + hddLog(LOGW, + "Accessing array out of bound that array is pDot11ExtSuppRates->rates "); + } else { + no_of_rates = maxNumRates - numBasicRates; + } + for (i = 0; i < no_of_rates; i++) { + if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F)) { + event.u.bitrate.value = + hdd_translate_abg_rate_to_mbps_rate + (&pDot11ExtSuppRates->rates[i]); + + current_pad = + iwe_stream_add_value(scanInfo->info, + current_event, + current_pad, + end, &event, + IW_EV_PARAM_LEN); + } + } + } + + if ((current_pad - current_event) >= IW_EV_LCP_LEN) { + current_event = current_pad; + } else { + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWRATE"); + return -E2BIG; + } + } + + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + event.cmd = SIOCGIWENCODE; + + if (SIR_MAC_GET_PRIVACY(capabilityInfo)) { + event.u.data.flags = + IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + event.u.data.flags = IW_ENCODE_DISABLED; + } + event.u.data.length = 0; + + current_event = + iwe_stream_add_point(scanInfo->info, current_event, end, + &event, (char *)pDot11SSID->ssid); + if (last_event == current_event) { + hddLog(LOGE, + "hdd_indicate_scan_result: no space for SIOCGIWENCODE"); + return -E2BIG; + } + } + + last_event = current_event; + cdf_mem_zero(&event, sizeof(struct iw_event)); + + /* RSSI */ + event.cmd = IWEVQUAL; + event.u.qual.qual = descriptor->rssi; + event.u.qual.noise = descriptor->sinr; + event.u.qual.level = CDF_MIN((descriptor->rssi + descriptor->sinr), 0); + + event.u.qual.updated = IW_QUAL_ALL_UPDATED; + + current_event = iwe_stream_add_event(scanInfo->info, current_event, + end, &event, IW_EV_QUAL_LEN); + + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, "hdd_indicate_scan_result: no space for IWEVQUAL"); + return -E2BIG; + } + + /* AGE */ + event.cmd = IWEVCUSTOM; + p = custom; + p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %lu", + cdf_mc_timer_get_system_ticks() - + descriptor->nReceivedTime); + event.u.data.length = p - custom; + current_event = iwe_stream_add_point(scanInfo->info, current_event, end, + &event, custom); + if (last_event == current_event) { /* no space to add event */ + hddLog(LOGE, + "hdd_indicate_scan_result: no space for IWEVCUSTOM (age)"); + return -E2BIG; + } + + scanInfo->start = current_event; + + return 0; +} + + +/** + * wlan_hdd_scan_request_enqueue() - enqueue Scan Request + * @adapter: Pointer to the adapter + * @scan_req: Pointer to the scan request + * + * Enqueue scan request in the global HDD scan list.This list + * stores the active scan request information. + * + * Return: 0 on success, error number otherwise + */ +static int wlan_hdd_scan_request_enqueue(hdd_adapter_t *adapter, + struct cfg80211_scan_request *scan_req, + uint8_t source, uint32_t scan_id, + uint32_t timestamp) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_scan_req *hdd_scan_req; + CDF_STATUS status; + + ENTER(); + hdd_scan_req = cdf_mem_malloc(sizeof(*hdd_scan_req)); + if (NULL == hdd_scan_req) { + hddLog(LOGP, FL("malloc failed for Scan req")); + return -ENOMEM; + } + + hdd_scan_req->adapter = adapter; + hdd_scan_req->scan_request = scan_req; + hdd_scan_req->source = source; + hdd_scan_req->scan_id = scan_id; + hdd_scan_req->timestamp = timestamp; + + cdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + status = cdf_list_insert_back(&hdd_ctx->hdd_scan_req_q, + &hdd_scan_req->node); + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + + if (CDF_STATUS_SUCCESS != status) { + hdd_err("Failed to enqueue Scan Req"); + cdf_mem_free(hdd_scan_req); + return -EINVAL; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_scan_request_dequeue() - dequeue scan request + * @hdd_ctx: Global HDD context + * @scan_id: scan id + * @req: scan request + * @source : returns source of the scan request + * @timestamp: scan request timestamp + * + * Return: CDF_STATUS + */ +CDF_STATUS wlan_hdd_scan_request_dequeue(hdd_context_t *hdd_ctx, + uint32_t scan_id, struct cfg80211_scan_request **req, uint8_t *source, + uint32_t *timestamp) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + struct hdd_scan_req *hdd_scan_req; + cdf_list_node_t *pNode = NULL, *ppNode = NULL; + + hdd_info("Dequeue Scan id: %d", scan_id); + + if ((source == NULL) && (timestamp == NULL) && (req == NULL)) + return CDF_STATUS_E_NULL_VALUE; + + cdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + + if (list_empty(&hdd_ctx->hdd_scan_req_q.anchor)) { + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return CDF_STATUS_E_FAILURE; + } + + if (CDF_STATUS_SUCCESS != + cdf_list_peek_front(&hdd_ctx->hdd_scan_req_q, &ppNode)) { + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove Scan Req from queue"); + return CDF_STATUS_E_FAILURE; + } + + do { + pNode = ppNode; + hdd_scan_req = (struct hdd_scan_req *)pNode; + if (hdd_scan_req->scan_id == scan_id) { + status = cdf_list_remove_node(&hdd_ctx->hdd_scan_req_q, + pNode); + if (status == CDF_STATUS_SUCCESS) { + *req = hdd_scan_req->scan_request; + *source = hdd_scan_req->source; + *timestamp = hdd_scan_req->timestamp; + cdf_mem_free(hdd_scan_req); + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_info("removed Scan id: %d, req = %p", + scan_id, req); + return CDF_STATUS_SUCCESS; + } else { + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove node scan id %d", + scan_id); + return status; + } + } + } while (CDF_STATUS_SUCCESS == + cdf_list_peek_next(&hdd_ctx->hdd_scan_req_q, pNode, &ppNode)); + + cdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to find scan id %d", scan_id); + return status; +} + +/** + * hdd_scan_request_callback() - scan complete callback from SME + * @halHandle: Pointer to the Hal Handle + * @pContext: Pointer to the data context + * @sessionId: Session identifier + * @scanId: Scan ID + * @status: CSR Status + * + * The sme module calls this callback function once it finish the scan request + * and this function notifies the scan complete event to the wpa_supplicant. + * + * Return: 0 for success, non zero for failure + */ + +static CDF_STATUS +hdd_scan_request_callback(tHalHandle halHandle, void *pContext, + uint8_t sessionId, uint32_t scanId, + eCsrScanStatus status) +{ + struct net_device *dev = (struct net_device *)pContext; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + union iwreq_data wrqu; + int we_event; + char *msg; + uint8_t source; + struct cfg80211_scan_request *req; + uint32_t timestamp; + uint32_t size = 0; + + ENTER(); + hddLog(LOGW, + "%s called with halHandle = %p, pContext = %p, scanID = %d," + " returned status = %d", __func__, halHandle, pContext, + (int)scanId, (int)status); + + /* if there is a scan request pending when the wlan driver is unloaded + * we may be invoked as SME flushes its pending queue. If that is the + * case, the underlying net_device may have already been destroyed, so + * do some quick sanity before proceeding + */ + if (pAdapter->dev != dev) { + hddLog(LOGW, "%s: device mismatch %p vs %p", + __func__, pAdapter->dev, dev); + return CDF_STATUS_SUCCESS; + } + + wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source, + ×tamp); + + if (req != NULL) + hdd_err("Got unexpected request struct for Scan id %d", + scanId); + + cdf_spin_lock(&hddctx->hdd_scan_req_q_lock); + cdf_list_size(&(hddctx->hdd_scan_req_q), &size); + if (!size) + /* Scan is no longer pending */ + pAdapter->scan_info.mScanPending = false; + cdf_spin_unlock(&hddctx->hdd_scan_req_q_lock); + + /* notify any applications that may be interested */ + memset(&wrqu, '\0', sizeof(wrqu)); + we_event = SIOCGIWSCAN; + msg = NULL; + wireless_send_event(dev, we_event, &wrqu, msg); + + EXIT(); + return CDF_STATUS_SUCCESS; +} + +/** + * __iw_set_scan() - set scan request + * @dev: Pointer to the net device + * @info: Pointer to the iw_request_info + * @wrqu: Pointer to the iwreq_data + * @extra: Pointer to the data + * + * This function process the scan request from the wpa_supplicant + * and set the scan request to the SME + * + * Return: 0 for success, non zero for failure + */ + +static int __iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrScanRequest scanRequest; + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct iw_scan_req *scanReq = (struct iw_scan_req *)extra; + hdd_adapter_t *con_sap_adapter; + uint16_t con_dfs_ch; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: enter !!!", + __func__); + + /* Block All Scan during DFS operation and send null scan result */ + con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true); + if (con_sap_adapter) { + con_dfs_ch = con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (CDS_IS_DFS_CH(con_dfs_ch)) { + hddLog(LOGW, FL("##In DFS Master mode. Scan aborted")); + return -EOPNOTSUPP; + } + } + + cdf_mem_zero(&scanRequest, sizeof(scanRequest)); + + if (NULL != wrqu->data.pointer) { + /* set scanType, active or passive */ + if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) || + (eSIR_ACTIVE_SCAN == hdd_ctx->ioctl_scan_mode)) { + scanRequest.scanType = eSIR_ACTIVE_SCAN; + } else { + scanRequest.scanType = eSIR_PASSIVE_SCAN; + } + + /* set bssid using sockaddr from iw_scan_req */ + cdf_mem_copy(scanRequest.bssid.bytes, + &scanReq->bssid.sa_data, + CDF_MAC_ADDR_SIZE); + + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + + if (scanReq->essid_len) { + scanRequest.SSIDs.numOfSSIDs = 1; + scanRequest.SSIDs.SSIDList = + (tCsrSSIDInfo *) + cdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (scanRequest.SSIDs.SSIDList) { + scanRequest.SSIDs.SSIDList->SSID. + length = scanReq->essid_len; + cdf_mem_copy(scanRequest.SSIDs. + SSIDList->SSID.ssId, + scanReq->essid, + scanReq->essid_len); + } else { + scanRequest.SSIDs.numOfSSIDs = 0; + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate memory", + __func__); + CDF_ASSERT(0); + } + } + } + + /* set min and max channel time */ + scanRequest.minChnTime = scanReq->min_channel_time; + scanRequest.maxChnTime = scanReq->max_channel_time; + + } else { + if (hdd_ctx->ioctl_scan_mode == eSIR_ACTIVE_SCAN) { + /* set the scan type to active */ + scanRequest.scanType = eSIR_ACTIVE_SCAN; + } else { + scanRequest.scanType = eSIR_PASSIVE_SCAN; + } + + cdf_set_macaddr_broadcast(&scanRequest.bssid); + + /* set min and max channel time to zero */ + scanRequest.minChnTime = 0; + scanRequest.maxChnTime = 0; + } + + /* set BSSType to default type */ + scanRequest.BSSType = eCSR_BSS_TYPE_ANY; + + /*Scan all the channels */ + scanRequest.ChannelInfo.numOfChannels = 0; + + scanRequest.ChannelInfo.ChannelList = NULL; + + /* set requestType to full scan */ + scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + + /* if previous genIE is not NULL, update ScanIE */ + if (0 != pwextBuf->genIE.length) { + memset(&pAdapter->scan_info.scanAddIE, 0, + sizeof(pAdapter->scan_info.scanAddIE)); + memcpy(pAdapter->scan_info.scanAddIE.addIEdata, + pwextBuf->genIE.addIEdata, pwextBuf->genIE.length); + pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length; + + pwextBuf->roamProfile.pAddIEScan = + pAdapter->scan_info.scanAddIE.addIEdata; + pwextBuf->roamProfile.nAddIEScanLength = + pAdapter->scan_info.scanAddIE.length; + + /* clear previous genIE after use it */ + memset(&pwextBuf->genIE, 0, sizeof(pwextBuf->genIE)); + } + + /* push addIEScan in scanRequset if exist */ + if (pAdapter->scan_info.scanAddIE.addIEdata && + pAdapter->scan_info.scanAddIE.length) { + scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length; + scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata; + } + scanRequest.timestamp = cdf_mc_timer_get_system_ticks(); + status = sme_scan_request((WLAN_HDD_GET_CTX(pAdapter))->hHal, + pAdapter->sessionId, &scanRequest, + &hdd_scan_request_callback, dev); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:sme_scan_request fail %d!!!", __func__, status); + goto error; + } + + wlan_hdd_scan_request_enqueue(pAdapter, NULL, NL_SCAN, + scanRequest.scan_id, + scanRequest.timestamp); + + pAdapter->scan_info.mScanPending = true; +error: + if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len)) + cdf_mem_free(scanRequest.SSIDs.SSIDList); + EXIT(); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: exit !!!", + __func__); + return status; +} + +/** + * iw_set_scan() - SSR wrapper for __iw_set_scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 on success, error number otherwise + */ +int iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_scan(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_scan() - get scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * This function returns the scan results to the wpa_supplicant + * + * Return: 0 for success, non zero for failure + */ + +static int __iw_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tCsrScanResultInfo *pScanResult; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_scan_info_t scanInfo; + tScanResultHandle pResult; + int i = 0; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: enter buffer length %d!!!", __func__, + (wrqu->data.length) ? wrqu->data.length : IW_SCAN_MAX_DATA); + + if (true == pAdapter->scan_info.mScanPending) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:mScanPending is true !!!", __func__); + return -EAGAIN; + } + + scanInfo.dev = dev; + scanInfo.start = extra; + scanInfo.info = info; + + if (0 == wrqu->data.length) { + scanInfo.end = extra + IW_SCAN_MAX_DATA; + } else { + scanInfo.end = extra + wrqu->data.length; + } + + status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult); + + if (NULL == pResult) { + /* no scan results */ + hddLog(LOG1, "iw_get_scan: NULL Scan Result "); + return 0; + } + + pScanResult = sme_scan_result_get_first(hHal, pResult); + + while (pScanResult) { + status = hdd_indicate_scan_result(&scanInfo, pScanResult); + if (0 != status) { + break; + } + i++; + pScanResult = sme_scan_result_get_next(hHal, pResult); + } + + sme_scan_result_purge(hHal, pResult); + + EXIT(); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: exit total %d BSS reported !!!", __func__, i); + return status; +} + +/** + * iw_get_scan() - SSR wrapper function for __iw_get_scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 on success, error number otherwise + */ +int iw_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_scan(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_abort_mac_scan() - aborts ongoing mac scan + * @pHddCtx: Pointer to hdd context + * @sessionId: session id + * @reason: abort reason + * + * Abort any MAC scan if in progress + * + * Return: none + */ +void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId, + eCsrAbortReason reason) +{ + sme_abort_mac_scan(pHddCtx->hHal, sessionId, reason); +} + +/** + * hdd_vendor_scan_callback() - Scan completed callback event + * @hddctx: HDD context + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function sends scan completed callback event to NL. + * + * Return: none + */ +static void hdd_vendor_scan_callback(hdd_adapter_t *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb; + struct nlattr *attr; + int i; + uint8_t scan_status; + uint64_t cookie; + + ENTER(); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter magic"); + return; + } + skb = cfg80211_vendor_event_alloc(hddctx->wiphy, NULL, + SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("skb alloc failed"); + return; + } + + if (0 != hdd_vendor_put_ifindex(skb, adapter->dev->ifindex)) + goto nla_put_failure; + + cookie = (uintptr_t)req; + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) { + if (nla_put(skb, i, req->ssids[i].ssid_len, req->ssids[i].ssid)) + goto nla_put_failure; + } + nla_nest_end(skb, attr); + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) { + if (nla_put_u32(skb, i, req->channels[i]->center_freq)) + goto nla_put_failure; + } + nla_nest_end(skb, attr); + + if (req->ie && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len, + req->ie)) + goto nla_put_failure; + + if (req->flags && + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags)) + goto nla_put_failure; + + if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) + goto nla_put_failure; + + scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED : + VENDOR_SCAN_STATUS_NEW_RESULTS; + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * hdd_cfg80211_scan_done_callback() - scan done callback function called after + * scan is finished + * @halHandle: Pointer to handle + * @pContext: Pointer to context + * @sessionId: Session Id + * @scanId: Scan Id + * @status: Scan status + * + * Return: CDF status + */ +static CDF_STATUS hdd_cfg80211_scan_done_callback(tHalHandle halHandle, + void *pContext, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + struct net_device *dev = (struct net_device *)pContext; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info; + struct cfg80211_scan_request *req = NULL; + bool aborted = false; + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + int ret = 0; + uint8_t source; + uint32_t scan_time; + uint32_t size = 0; + + hddLog(CDF_TRACE_LEVEL_INFO, + "%s called with hal = %p, pContext = %p, ID = %d, status = %d", + __func__, halHandle, pContext, (int)scanId, (int)status); + + pScanInfo->mScanPendingCounter = 0; + + if (pScanInfo->mScanPending != true) { + CDF_ASSERT(pScanInfo->mScanPending); + goto allow_suspend; + } + + if (CDF_STATUS_SUCCESS != + wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source, + &scan_time)) { + hdd_err("Dequeue of scan request failed ID: %d", scanId); + goto allow_suspend; + } + + ret = wlan_hdd_cfg80211_update_bss((WLAN_HDD_GET_CTX(pAdapter))->wiphy, + pAdapter, scan_time); + if (0 > ret) + hddLog(CDF_TRACE_LEVEL_INFO, "%s: NO SCAN result", __func__); + + /* + * cfg80211_scan_done informing NL80211 about completion + * of scanning + */ + if (status == eCSR_SCAN_ABORT || status == eCSR_SCAN_FAILURE) { + aborted = true; + } + + cdf_spin_lock(&hddctx->hdd_scan_req_q_lock); + cdf_list_size(&(hddctx->hdd_scan_req_q), &size); + if (!size) { + /* Scan is no longer pending */ + pScanInfo->mScanPending = false; + complete(&pScanInfo->abortscan_event_var); + } + cdf_spin_unlock(&hddctx->hdd_scan_req_q_lock); + /* + * Scan can be triggred from NL or vendor scan + * - If scan is triggered from NL then cfg80211 scan done should be + * called to updated scan completion to NL. + * - If scan is triggred through vendor command then + * scan done event will be posted + */ + if (NL_SCAN == source) + cfg80211_scan_done(req, aborted); + else + hdd_vendor_scan_callback(pAdapter, req, aborted); + +allow_suspend: + if (!size) { + /* release the wake lock at the end of the scan */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN); + + /* Acquire wakelock to handle the case where APP's tries + * to suspend immediatly after the driver gets connect + * request(i.e after scan) from supplicant, this result in + * app's is suspending and not ableto process the connect + * request to AP + */ + hdd_prevent_suspend_timeout(1000, + WIFI_POWER_EVENT_WAKELOCK_SCAN); + } + +#ifdef FEATURE_WLAN_TDLS + wlan_hdd_tdls_scan_done_callback(pAdapter); +#endif + + EXIT(); + return 0; +} + + +/** + * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler + * @work: Pointer to work + * + * Return: none + */ +static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) +{ + hdd_adapter_t *adapter = container_of(work, + hdd_adapter_t, scan_block_work); + struct cfg80211_scan_request *request = adapter->request; + + request->n_ssids = 0; + request->n_channels = 0; + + hddLog(LOGE, + FL("##In DFS Master mode. Scan aborted. Null result sent")); + cfg80211_scan_done(request, true); + adapter->request = NULL; +} + +/** + * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @request: Pointer to scan request + * @source: scan request source(NL/Vendor scan) + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to recieve scan results + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request, + uint8_t source) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct net_device *dev = request->wdev->netdev; +#endif + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + struct hdd_config *cfg_param = NULL; + tCsrScanRequest scan_req; + uint8_t *channelList = NULL, i; + int status; + hdd_scaninfo_t *pScanInfo = NULL; + uint8_t *pP2pIe = NULL; + hdd_adapter_t *con_sap_adapter; + uint16_t con_dfs_ch; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SCAN, + pAdapter->sessionId, request->n_channels)); + + hddLog(LOG1, FL("Device_mode %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + cfg_param = pHddCtx->config; + pScanInfo = &pAdapter->scan_info; + + /* Block All Scan during DFS operation and send null scan result */ + con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true); + if (con_sap_adapter) { + con_dfs_ch = con_sap_adapter->sessionCtx.ap.sapConfig.channel; + if (con_dfs_ch == AUTO_CHANNEL_SELECT) + con_dfs_ch = + con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (CDS_IS_DFS_CH(con_dfs_ch)) { + /* Provide empty scan result during DFS operation since + * scanning not supported during DFS. Reason is + * following case: + * DFS is supported only in SCC for MBSSID Mode. + * We shall not return EBUSY or ENOTSUPP as when Primary + * AP is operating in DFS channel and secondary AP is + * started. Though we force SCC in driver, the hostapd + * issues obss scan before starting secAP. This results + * in MCC in DFS mode. Thus we return null scan result. + * If we return scan failure hostapd fails secondary AP + * startup. + */ + pAdapter->request = request; + +#ifdef CONFIG_CNSS + cnss_init_work(&pAdapter->scan_block_work, + wlan_hdd_cfg80211_scan_block_cb); +#else + INIT_WORK(&pAdapter->scan_block_work, + wlan_hdd_cfg80211_scan_block_cb); +#endif + schedule_work(&pAdapter->scan_block_work); + return 0; + } + } + if (!wma_is_hw_dbs_capable()) { + if (true == pScanInfo->mScanPending) { + if (MAX_PENDING_LOG > + pScanInfo->mScanPendingCounter++) { + hddLog(LOGE, FL("mScanPending is true")); + } + return -EBUSY; + } + + /* Don't Allow Scan and return busy if Remain On + * Channel and action frame is pending + * Otherwise Cancel Remain On Channel and allow Scan + * If no action frame pending + */ + if (0 != wlan_hdd_check_remain_on_channel(pAdapter)) { + hddLog(LOGE, FL("Remain On Channel Pending")); + return -EBUSY; + } + } +#ifdef FEATURE_WLAN_TDLS + /* if tdls disagree scan right now, return immediately. + * tdls will schedule the scan when scan is allowed. + * (return SUCCESS) + * or will reject the scan if any TDLS is in progress. + * (return -EBUSY) + */ + status = wlan_hdd_tdls_scan_callback(pAdapter, wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + dev, +#endif + request); + if (status <= 0) { + if (!status) + hddLog(LOGE, + FL("TDLS in progress.scan rejected %d"), + status); + else + hddLog(LOGE, FL("TDLS teardown is ongoing %d"), + status); + return status; + } +#endif + + /* Check if scan is allowed at this point of time */ + if (cds_is_connection_in_progress(pHddCtx)) { + hddLog(LOGE, FL("Scan not allowed")); + return -EBUSY; + } + + cdf_mem_zero(&scan_req, sizeof(scan_req)); + + hddLog(LOG1, "scan request for ssid = %d", request->n_ssids); + scan_req.timestamp = cdf_mc_timer_get_system_ticks(); + + /* Even though supplicant doesn't provide any SSIDs, n_ssids is + * set to 1. Because of this, driver is assuming that this is not + * wildcard scan and so is not aging out the scan results. + */ + if ((request->ssids) && (request->n_ssids == 1) && + ('\0' == request->ssids->ssid[0])) { + request->n_ssids = 0; + } + + if ((request->ssids) && (0 < request->n_ssids)) { + tCsrSSIDInfo *SsidInfo; + int j; + scan_req.SSIDs.numOfSSIDs = request->n_ssids; + /* Allocate num_ssid tCsrSSIDInfo structure */ + SsidInfo = scan_req.SSIDs.SSIDList = + cdf_mem_malloc(request->n_ssids * sizeof(tCsrSSIDInfo)); + + if (NULL == scan_req.SSIDs.SSIDList) { + hddLog(LOGE, FL("memory alloc failed SSIDInfo buffer")); + return -ENOMEM; + } + + /* copy all the ssid's and their length */ + for (j = 0; j < request->n_ssids; j++, SsidInfo++) { + /* get the ssid length */ + SsidInfo->SSID.length = request->ssids[j].ssid_len; + cdf_mem_copy(SsidInfo->SSID.ssId, + &request->ssids[j].ssid[0], + SsidInfo->SSID.length); + SsidInfo->SSID.ssId[SsidInfo->SSID.length] = '\0'; + hddLog(LOG1, FL("SSID number %d: %s"), j, + SsidInfo->SSID.ssId); + } + /* set the scan type to active */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + } else if (WLAN_HDD_P2P_GO == pAdapter->device_mode) { + /* set the scan type to active */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + } else { + /* + * Set the scan type to passive if there is no ssid list + * provided else set default type configured in the driver. + */ + if (!request->ssids) + scan_req.scanType = eSIR_PASSIVE_SCAN; + else + scan_req.scanType = pHddCtx->ioctl_scan_mode; + } + scan_req.minChnTime = cfg_param->nActiveMinChnTime; + scan_req.maxChnTime = cfg_param->nActiveMaxChnTime; + + /* set BSSType to default type */ + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + + if (MAX_CHANNEL < request->n_channels) { + hddLog(LOGW, FL("No of Scan Channels exceeded limit: %d"), + request->n_channels); + request->n_channels = MAX_CHANNEL; + } + + hddLog(LOG1, FL("No of Scan Channels: %d"), request->n_channels); + + if (request->n_channels) { + char chList[(request->n_channels * 5) + 1]; + int len; + channelList = cdf_mem_malloc(request->n_channels); + if (NULL == channelList) { + hddLog(LOGE, + FL("channelList malloc failed channelList")); + status = -ENOMEM; + goto free_mem; + } + for (i = 0, len = 0; i < request->n_channels; i++) { + channelList[i] = request->channels[i]->hw_value; + len += snprintf(chList + len, 5, "%d ", channelList[i]); + } + + hddLog(LOG1, FL("Channel-List: %s"), chList); + + } + scan_req.ChannelInfo.numOfChannels = request->n_channels; + scan_req.ChannelInfo.ChannelList = channelList; + + /* set requestType to full scan */ + scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + + /* Flush the scan results(only p2p beacons) for STA scan and P2P + * search (Flush on both full scan and social scan but not on single + * channel scan).P2P search happens on 3 social channels (1, 6, 11) + */ + + /* Supplicant does single channel scan after 8-way handshake + * and in that case driver shoudnt flush scan results. If + * driver flushes the scan results here and unfortunately if + * the AP doesnt respond to our probe req then association + * fails which is not desired + */ + + if (request->n_channels != WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN) { + hddLog(CDF_TRACE_LEVEL_DEBUG, "Flushing P2P Results"); + sme_scan_flush_p2p_result(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId); + } + + if (request->ie_len) { + /* save this for future association (join requires this) */ + memset(&pScanInfo->scanAddIE, 0, sizeof(pScanInfo->scanAddIE)); + memcpy(pScanInfo->scanAddIE.addIEdata, request->ie, + request->ie_len); + pScanInfo->scanAddIE.length = request->ie_len; + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode) + ) { + pwextBuf->roamProfile.pAddIEScan = + pScanInfo->scanAddIE.addIEdata; + pwextBuf->roamProfile.nAddIEScanLength = + pScanInfo->scanAddIE.length; + } + + scan_req.uIEFieldLen = pScanInfo->scanAddIE.length; + scan_req.pIEField = pScanInfo->scanAddIE.addIEdata; + + pP2pIe = wlan_hdd_get_p2p_ie_ptr((uint8_t *) request->ie, + request->ie_len); + if (pP2pIe != NULL) { +#ifdef WLAN_FEATURE_P2P_DEBUG + if (((global_p2p_connection_status == P2P_GO_NEG_COMPLETED) + || (global_p2p_connection_status == + P2P_GO_NEG_PROCESS)) + && (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTING_STATE_1; + hddLog(LOGE, + FL("[P2P State] Changing state from Go nego completed to Connection is started")); + hddLog(LOGE, + FL("[P2P]P2P Scanning is started for 8way Handshake")); + } else + if ((global_p2p_connection_status == + P2P_CLIENT_DISCONNECTED_STATE) + && (WLAN_HDD_P2P_CLIENT == + pAdapter->device_mode)) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTING_STATE_2; + hddLog(LOGE, + FL("[P2P State] Changing state from Disconnected state to Connection is started")); + hddLog(LOGE, + FL("[P2P]P2P Scanning is started for 4way Handshake")); + } +#endif + + /* no_cck will be set during p2p find to disable 11b rates */ + if (request->no_cck) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: This is a P2P Search", __func__); + scan_req.p2pSearch = 1; + + if (request->n_channels == + WLAN_HDD_P2P_SOCIAL_CHANNELS) { + /* set requestType to P2P Discovery */ + scan_req.requestType = + eCSR_SCAN_P2P_DISCOVERY; + } + + /* + * Skip Dfs Channel in case of P2P Search if it is set in + * ini file + */ + if (cfg_param->skipDfsChnlInP2pSearch) { + scan_req.skipDfsChnlInP2pSearch = 1; + } else { + scan_req.skipDfsChnlInP2pSearch = 0; + } + + } + } + } + + /* acquire the wakelock to avoid the apps suspend during the scan. To + * address the following issues. + * 1) Disconnected scenario: we are not allowing the suspend as WLAN is not in + * BMPS/IMPS this result in android trying to suspend aggressively and backing off + * for long time, this result in apps running at full power for long time. + * 2) Connected scenario: If we allow the suspend during the scan, RIVA will + * be stuck in full power because of resume BMPS + */ + hdd_prevent_suspend_timeout(HDD_WAKE_LOCK_SCAN_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SCAN); + + hddLog(LOG2, + FL("requestType %d, scanType %d, minChnTime %d, maxChnTime %d,p2pSearch %d, skipDfsChnlIn P2pSearch %d"), + scan_req.requestType, scan_req.scanType, + scan_req.minChnTime, scan_req.maxChnTime, + scan_req.p2pSearch, scan_req.skipDfsChnlInP2pSearch); + + status = sme_scan_request(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &scan_req, + &hdd_cfg80211_scan_done_callback, dev); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("sme_scan_request returned error %d"), status); + if (CDF_STATUS_E_RESOURCES == status) { + hddLog(LOGE, + FL("HO is in progress.So defer the scan by informing busy")); + status = -EBUSY; + } else { + status = -EIO; + } + + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN); + goto free_mem; + } + wlan_hdd_scan_request_enqueue(pAdapter, request, source, + scan_req.scan_id, scan_req.timestamp); + pAdapter->scan_info.mScanPending = true; + +free_mem: + if (scan_req.SSIDs.SSIDList) + cdf_mem_free(scan_req.SSIDs.SSIDList); + + if (channelList) + cdf_mem_free(channelList); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @request: Pointer to scan request + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to recieve scan results + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_scan(wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + dev, +#endif + request, NL_SCAN); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * wlan_hdd_get_rates() -API to get the rates from scan request + * @wiphy: Pointer to wiphy + * @band: Band + * @rates: array of rates + * @rate_count: number of rates + * + * Return: o for failure, rate bitmap for success + */ +static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy, + enum ieee80211_band band, + const u8 *rates, unsigned int rate_count) +{ + uint32_t j, count, rate_bitmap = 0; + uint32_t rate; + bool found; + + for (count = 0; count < rate_count; count++) { + rate = ((rates[count]) & RATE_MASK) * 5; + found = false; + for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) { + if (wiphy->bands[band]->bitrates[j].bitrate == rate) { + found = true; + rate_bitmap |= (1 << j); + break; + } + } + if (!found) + return 0; + } + return rate_bitmap; +} + +/** + * wlan_hdd_send_scan_start_event() -API to send the scan start event + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @cookie: scan identifier + * + * Return: return 0 on success and negative error code on failure + */ +static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy, + struct wireless_dev *wdev, uint64_t cookie) +{ + struct sk_buff *skb; + int ret; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) + + NLA_HDRLEN + NLMSG_HDRLEN); + if (!skb) { + hddLog(LOGE, FL(" reply skb alloc failed")); + return -ENOMEM; + } + + if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) { + hddLog(LOGE, FL("nla put fail")); + kfree_skb(skb); + return -EINVAL; + } + + ret = cfg80211_vendor_cmd_reply(skb); + + /* Send a scan started event to supplicant */ + skb = cfg80211_vendor_event_alloc(wiphy, wdev, + sizeof(u64) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, GFP_KERNEL); + if (!skb) { + hddLog(LOGE, FL("skb alloc failed")); + return -ENOMEM; + } + + ret = hdd_vendor_put_ifindex(skb, wdev->netdev->ifindex); + if (ret) { + kfree_skb(skb); + return -EINVAL; + } + + if (nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, cookie)) { + kfree_skb(skb); + return -EINVAL; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + + return ret; +} +/** + * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * API to process venor scan request. + * + * Return: return 0 on success and negative error code on failure + */ +static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + struct cfg80211_scan_request *request = NULL; + struct nlattr *attr; + enum ieee80211_band band; + uint8_t n_channels = 0, n_ssid = 0, ie_len = 0; + uint32_t tmp, count, j; + unsigned int len; + struct ieee80211_channel *chan; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data, + data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp) + n_channels++; + } else { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (MAX_CHANNEL < n_channels) { + hdd_err("Exceed max number of channels: %d", n_channels); + return -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp) + n_ssid++; + + if (MAX_SCAN_SSID < n_ssid) { + hdd_err("Exceed max number of SSID: %d", n_ssid); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) + ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]); + else + ie_len = 0; + + len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) + + (sizeof(*request->channels) * n_channels) + ie_len; + + request = cdf_mem_malloc(len); + if (!request) + goto error; + if (n_ssid) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssid; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssid); + else + request->ie = (void *)(request->channels + n_channels); + } + + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], + tmp) { + chan = __ieee80211_get_channel(wiphy, + nla_get_u32(attr)); + if (!chan) + goto error; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } else { + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; + j++) { + chan = &wiphy->bands[band]->channels[j]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } + } + + if (!count) + goto error; + + request->n_channels = count; + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], + tmp) { + request->ssids[count].ssid_len = nla_len(attr); + memcpy(request->ssids[count].ssid, nla_data(attr), + nla_len(attr)); + count++; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) { + request->ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]); + memcpy((void *)request->ie, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]), + request->ie_len); + } + + for (count = 0; count < IEEE80211_NUM_BANDS; count++) + if (wiphy->bands[count]) + request->rates[count] = + (1 << wiphy->bands[count]->n_bitrates) - 1; + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES], + tmp) { + band = nla_type(attr); + if (!wiphy->bands[band]) + continue; + request->rates[band] = wlan_hdd_get_rates(wiphy, + band, nla_data(attr), + nla_len(attr)); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) { + request->flags = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]); + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + hddLog(LOGE, FL("LOW PRIORITY SCAN not supported")); + goto error; + } + } + request->no_cck = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]); + request->wdev = wdev; + request->wiphy = wiphy; + request->scan_start = jiffies; + + if (0 != __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN)) + goto error; + + ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request); + + return ret; +error: + hdd_err("Scan Request Failed"); + cdf_mem_free(request); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from userspace to request scan. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +/** + * wlan_hdd_scan_abort() - abort ongoing scan + * @pAdapter: Pointer to interface adapter + * + * Return: 0 for success, non zero for failure + */ +#ifdef FEATURE_WLAN_SCAN_PNO +int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_scaninfo_t *pScanInfo = NULL; + unsigned long rc; + + pScanInfo = &pAdapter->scan_info; + + if (pScanInfo->mScanPending) { + INIT_COMPLETION(pScanInfo->abortscan_event_var); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + eCSR_SCAN_ABORT_DEFAULT); + + rc = wait_for_completion_timeout( + &pScanInfo->abortscan_event_var, + msecs_to_jiffies(5000)); + if (!rc) { + hddLog(LOGE, + FL("Timeout occurred while waiting for abort scan")); + return -ETIME; + } + } + return 0; +} + +/** + * hdd_sched_scan_callback - scheduled scan callback + * @callbackContext: Callback context + * @pPrefNetworkFoundInd: Preferred network found indication + * + * This is a callback function that is registerd with SME that is + * invoked when a preferred network is discovered by firmware. + * + * Return: none + */ +static void +hdd_sched_scan_callback(void *callbackContext, + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd) +{ + int ret; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + hdd_context_t *pHddCtx; + + ENTER(); + + if (NULL == pAdapter) { + hddLog(LOGE, FL("HDD adapter is Null")); + return; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (NULL == pHddCtx) { + hddLog(LOGE, FL("HDD context is Null!!!")); + return; + } + + spin_lock(&pHddCtx->schedScan_lock); + if (true == pHddCtx->isWiphySuspended) { + pHddCtx->isSchedScanUpdatePending = true; + spin_unlock(&pHddCtx->schedScan_lock); + hddLog(LOG1, + FL("Update cfg80211 scan database after it resume")); + return; + } + spin_unlock(&pHddCtx->schedScan_lock); + + ret = wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, pAdapter, 0); + + if (0 > ret) + hddLog(LOG1, FL("NO SCAN result")); + + cfg80211_sched_scan_results(pHddCtx->wiphy); + hddLog(LOG1, + FL("cfg80211 scan result database updated")); +} + +/** + * wlan_hdd_is_pno_allowed() - Check if PNO is allowed + * @adapter: HDD Device Adapter + * + * The PNO Start request is coming from upper layers. + * It is to be allowed only for Infra STA device type + * and the link should be in a disconnected state. + * + * Return: Success if PNO is allowed, Failure otherwise. + */ +static CDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter) +{ + hddLog(LOG1, + FL("dev_mode=%d, conn_state=%d, session ID=%d"), + adapter->device_mode, + adapter->sessionCtx.station.conn_info.connState, + adapter->sessionId); + if ((adapter->device_mode == WLAN_HDD_INFRA_STATION) && + (eConnectionState_NotConnected == + adapter->sessionCtx.station.conn_info.connState)) + return CDF_STATUS_SUCCESS; + else + return CDF_STATUS_E_FAILURE; + +} + +/** + * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct + cfg80211_sched_scan_request + *request) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpSirPNOScanReq pPnoRequest = NULL; + hdd_context_t *pHddCtx; + tHalHandle hHal; + uint32_t i, indx, num_ch, tempInterval, j; + u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + u8 channels_allowed[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint32_t num_channels_allowed = WNI_CFG_VALID_CHANNEL_LIST_LEN; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int ret = 0; + hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info; + struct hdd_config *config = NULL; + uint32_t num_ignore_dfs_ch = 0; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + config = pHddCtx->config; + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) { + hddLog(LOGE, FL("HAL context is Null!!!")); + return -EINVAL; + } + + if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) && + (eConnectionState_Connecting == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) { + hddLog(LOGE, + FL("%p(%d) Connection in progress: sched_scan_start denied (EBUSY)"), + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), + pAdapter->sessionId); + return -EBUSY; + } + + /* + * The current umac is unable to handle the SCAN_PREEMPT and SCAN_DEQUEUED + * so its necessary to terminate the existing scan which is already issued + * otherwise the host won't enter into the suspend state due to the reason + * that the wlan wakelock which was held in the wlan_hdd_cfg80211_scan + * function. + */ + sme_scan_flush_result(hHal); + if (true == pScanInfo->mScanPending) { + ret = wlan_hdd_scan_abort(pAdapter); + if (ret < 0) { + hddLog(LOGE, + FL("aborting the existing scan is unsuccessful")); + return -EBUSY; + } + } + + if (CDF_STATUS_E_FAILURE == wlan_hdd_is_pno_allowed(pAdapter)) { + hddLog(LOGE, FL("pno is not allowed")); + return -ENOTSUPP; + } + + pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == pPnoRequest) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + memset(pPnoRequest, 0, sizeof(tSirPNOScanReq)); + pPnoRequest->enable = 1; /*Enable PNO */ + pPnoRequest->ucNetworksCount = request->n_match_sets; + + if ((!pPnoRequest->ucNetworksCount) || + (pPnoRequest->ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) { + hddLog(LOGE, FL("Network input is not correct %d"), + pPnoRequest->ucNetworksCount); + ret = -EINVAL; + goto error; + } + + if (SIR_PNO_MAX_NETW_CHANNELS_EX < request->n_channels) { + hddLog(LOGE, FL("Incorrect number of channels %d"), + request->n_channels); + ret = -EINVAL; + goto error; + } + + /* Framework provides one set of channels(all) + * common for all saved profile */ + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + channels_allowed, &num_channels_allowed)) { + hddLog(LOGE, + FL("failed to get valid channel list")); + ret = -EINVAL; + goto error; + } + /* Checking each channel against allowed channel list */ + num_ch = 0; + if (request->n_channels) { + char chList[(request->n_channels * 5) + 1]; + int len; + for (i = 0, len = 0; i < request->n_channels; i++) { + for (indx = 0; indx < num_channels_allowed; indx++) { + if (request->channels[i]->hw_value == + channels_allowed[indx]) { + + if ((!config->enable_dfs_pno_chnl_scan) + && (CHANNEL_STATE_DFS == + cds_get_channel_state( + channels_allowed[indx]))) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s : Dropping DFS channel : %d", + __func__, + channels_allowed[indx]); + num_ignore_dfs_ch++; + break; + } + + valid_ch[num_ch++] = + request->channels[i]->hw_value; + len += + snprintf(chList + len, 5, "%d ", + request->channels[i]-> + hw_value); + break; + } + } + } + hddLog(LOG1, FL("Channel-List: %s "), chList); + + /* If all channels are DFS and dropped, + * then ignore the PNO request + */ + if (num_ignore_dfs_ch == request->n_channels) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s : All requested channels are DFS channels", + __func__); + ret = -EINVAL; + goto error; + } + + } + /* Filling per profile params */ + for (i = 0; i < pPnoRequest->ucNetworksCount; i++) { + pPnoRequest->aNetworks[i].ssId.length = + request->match_sets[i].ssid.ssid_len; + + if ((0 == pPnoRequest->aNetworks[i].ssId.length) || + (pPnoRequest->aNetworks[i].ssId.length > 32)) { + hddLog(LOGE, + FL(" SSID Len %d is not correct for network %d"), + pPnoRequest->aNetworks[i].ssId.length, i); + ret = -EINVAL; + goto error; + } + + memcpy(pPnoRequest->aNetworks[i].ssId.ssId, + request->match_sets[i].ssid.ssid, + request->match_sets[i].ssid.ssid_len); + pPnoRequest->aNetworks[i].authentication = 0; /*eAUTH_TYPE_ANY */ + pPnoRequest->aNetworks[i].encryption = 0; /*eED_ANY */ + pPnoRequest->aNetworks[i].bcastNetwType = 0; /*eBCAST_UNKNOWN */ + + /*Copying list of valid channel into request */ + memcpy(pPnoRequest->aNetworks[i].aChannels, valid_ch, num_ch); + pPnoRequest->aNetworks[i].ucChannelCount = num_ch; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + pPnoRequest->aNetworks[i].rssiThreshold = + request->match_sets[i].rssi_thold; +#else + pPnoRequest->aNetworks[i].rssiThreshold = 0; /* Default value */ +#endif + } + + for (i = 0; i < request->n_ssids; i++) { + j = 0; + while (j < pPnoRequest->ucNetworksCount) { + if ((pPnoRequest->aNetworks[j].ssId.length == + request->ssids[i].ssid_len) && + (0 == memcmp(pPnoRequest->aNetworks[j].ssId.ssId, + request->ssids[i].ssid, + pPnoRequest->aNetworks[j].ssId. + length))) { + pPnoRequest->aNetworks[j].bcastNetwType = + eBCAST_HIDDEN; + break; + } + j++; + } + } + hddLog(LOG1, FL("Number of hidden networks being Configured = %d"), + request->n_ssids); + + hddLog(LOG1, FL("request->ie_len = %zu"), request->ie_len); + if ((0 < request->ie_len) && (NULL != request->ie)) { + pPnoRequest->us24GProbeTemplateLen = request->ie_len; + memcpy(&pPnoRequest->p24GProbeTemplate, request->ie, + pPnoRequest->us24GProbeTemplateLen); + + pPnoRequest->us5GProbeTemplateLen = request->ie_len; + memcpy(&pPnoRequest->p5GProbeTemplate, request->ie, + pPnoRequest->us5GProbeTemplateLen); + } + + /* Driver gets only one time interval which is hardcoded in + * supplicant for 10000ms. Taking power consumption into account 6 timers + * will be used, Timervalue is increased exponentially i.e 10,20,40, + * 80,160,320 secs. And number of scan cycle for each timer + * is configurable through INI param gPNOScanTimerRepeatValue. + * If it is set to 0 only one timer will be used and PNO scan cycle + * will be repeated after each interval specified by supplicant + * till PNO is disabled. + */ + if (0 == pHddCtx->config->configPNOScanTimerRepeatValue) + pPnoRequest->scanTimers.ucScanTimersCount = + HDD_PNO_SCAN_TIMERS_SET_ONE; + else + pPnoRequest->scanTimers.ucScanTimersCount = + HDD_PNO_SCAN_TIMERS_SET_MULTIPLE; + + tempInterval = (request->interval) / 1000; + hddLog(LOG1, + FL("Base scan interval = %d PNOScanTimerRepeatValue = %d"), + tempInterval, pHddCtx->config->configPNOScanTimerRepeatValue); + for (i = 0; i < pPnoRequest->scanTimers.ucScanTimersCount; i++) { + pPnoRequest->scanTimers.aTimerValues[i].uTimerRepeat = + pHddCtx->config->configPNOScanTimerRepeatValue; + pPnoRequest->scanTimers.aTimerValues[i].uTimerValue = + tempInterval; + tempInterval *= 2; + } + /* Repeat last timer until pno disabled. */ + pPnoRequest->scanTimers.aTimerValues[i - 1].uTimerRepeat = 0; + + pPnoRequest->modePNO = SIR_PNO_MODE_IMMEDIATE; + + hddLog(LOG1, + FL("SessionId %d, enable %d, modePNO %d, ucScanTimersCount %d"), + pAdapter->sessionId, pPnoRequest->enable, + pPnoRequest->modePNO, + pPnoRequest->scanTimers.ucScanTimersCount); + + status = sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(pAdapter), + pPnoRequest, + pAdapter->sessionId, + hdd_sched_scan_callback, + pAdapter); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("Failed to enable PNO")); + ret = -EINVAL; + goto error; + } + + hddLog(LOG1, FL("PNO scanRequest offloaded")); + +error: + cdf_mem_free(pPnoRequest); + return ret; +} + +/** + * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno) + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + tHalHandle hHal; + tpSirPNOScanReq pPnoRequest = NULL; + int ret = 0; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (NULL == pHddCtx) { + hddLog(LOGE, FL("HDD context is Null")); + return -ENODEV; + } + + /* The return 0 is intentional when isLogpInProgress and + * isLoadUnloadInProgress. We did observe a crash due to a return of + * failure in sched_scan_stop , especially for a case where the unload + * of the happens at the same time. The function __cfg80211_stop_sched_scan + * was clearing rdev->sched_scan_req only when the sched_scan_stop returns + * success. If it returns a failure , then its next invocation due to the + * clean up of the second interface will have the dev pointer corresponding + * to the first one leading to a crash. + */ + if (pHddCtx->isLogpInProgress) { + hddLog(LOGE, FL("LOGP in Progress. Ignore!!!")); + return ret; + } + + if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) { + hddLog(LOGE, FL("Unloading/Loading in Progress. Ignore!!!")); + return ret; + } + + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) { + hddLog(LOGE, FL(" HAL context is Null!!!")); + return -EINVAL; + } + + pPnoRequest = (tpSirPNOScanReq) cdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == pPnoRequest) { + hddLog(LOGE, FL("cdf_mem_malloc failed")); + return -ENOMEM; + } + + memset(pPnoRequest, 0, sizeof(tSirPNOScanReq)); + pPnoRequest->enable = 0; /* Disable PNO */ + pPnoRequest->ucNetworksCount = 0; + + status = sme_set_preferred_network_list(hHal, pPnoRequest, + pAdapter->sessionId, + NULL, pAdapter); + if (CDF_STATUS_SUCCESS != status) { + hddLog(LOGE, FL("Failed to disabled PNO")); + ret = -EINVAL; + } + + hddLog(LOG1, FL("PNO scan disabled")); + + cdf_mem_free(pPnoRequest); + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno) + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_stop(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /*FEATURE_WLAN_SCAN_PNO */ + +/** + * hdd_vendor_put_ifindex() -send interface index + * @skb: buffer pointer + * @ifindex: interface index + * + * Send the IF index to differentiate the events on each interface + * Return: 0 for success, non zero for failure + */ +int hdd_vendor_put_ifindex(struct sk_buff *skb, int ifindex) +{ + struct nlattr *attr; + + nla_nest_cancel(skb, ((void **)skb->cb)[2]); + if (nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifindex)) + return -EINVAL; + + attr = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA); + ((void **)skb->cb)[2] = attr; + + return 0; +} diff --git a/core/hdd/src/wlan_hdd_scan.h b/core/hdd/src/wlan_hdd_scan.h new file mode 100644 index 0000000000..06ef03b378 --- /dev/null +++ b/core/hdd/src/wlan_hdd_scan.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_scan.h + * + * WLAN Host Device Driver scan related implementation + * + */ + +#if !defined(WLAN_HDD_SCAN_H) +#define WLAN_HDD_SCAN_H + +#include "wlan_hdd_main.h" + +#define MAX_PENDING_LOG 5 + +/* + * enum scan_source - scan request source + * + * @NL_SCAN: Scan initiated from NL + * @VENDOR_SCAN: Scan intiated from vendor command +*/ +enum scan_source { + NL_SCAN, + VENDOR_SCAN, +}; + +int iw_get_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request); + +#ifdef FEATURE_WLAN_SCAN_PNO +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request); + +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev); +#endif /* End of FEATURE_WLAN_SCAN_PNO */ + +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len); + +int hdd_vendor_put_ifindex(struct sk_buff *skb, int ifindex); +#endif /* end #if !defined(WLAN_HDD_SCAN_H) */ + diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c new file mode 100644 index 0000000000..6626ca211f --- /dev/null +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IPA_OFFLOAD +#include +#endif + +/* Preprocessor definitions and constants */ +#undef QCA_HDD_SAP_DUMP_SK_BUFF + +/* Type declarations */ + +/* Function definitions and documenation */ +#ifdef QCA_HDD_SAP_DUMP_SK_BUFF +/** + * hdd_softap_dump_sk_buff() - Dump an skb + * @skb: skb to dump + * + * Return: None + */ +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: head = %p ", __func__, skb->head); + /* CDF_TRACE( CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data); */ + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: tail = %p ", __func__, skb->tail); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: end = %p ", __func__, skb->end); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: len = %d ", __func__, skb->len); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: data_len = %d ", __func__, skb->data_len); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: mac_len = %d", __func__, skb->mac_len); + + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", skb->data[0], + skb->data[1], skb->data[2], skb->data[3], skb->data[4], + skb->data[5], skb->data[6], skb->data[7]); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", skb->data[8], + skb->data[9], skb->data[10], skb->data[11], skb->data[12], + skb->data[13], skb->data[14], skb->data[15]); +} +#else +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_softap_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * TX Q resume timer handler for SAP and P2P GO interface. If Blocked + * OS Q is not resumed during timeout period, to prevent permanent + * stall, resume OS Q forcefully for SAP and P2P GO interface. + * + * Return: None + */ +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: INV ARG", __func__); + /* INVALID ARG */ + return; + } + + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + return; +} + +/** + * hdd_softap_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: INV ARG", __func__); + /* INVALID ARG */ + return; + } + + /* Resume TX */ + if (true == tx_resume) { + if (CDF_TIMER_STATE_STOPPED != + cdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + cdf_mc_timer_stop(&pAdapter->tx_flow_control_timer); + } + + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + else if (false == tx_resume) { /* Pause TX */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + if (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + CDF_STATUS status; + status = + cdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + if (!CDF_IS_STATUS_SUCCESS(status)) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to start tx_flow_control_timer", + __func__); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + } +#endif + + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * hdd_softap_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Transport Layer. + * + * Return: Always returns NETDEV_TX_OK + */ +int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + sme_ac_enum_type ac = SME_AC_BE; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev); + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct cdf_mac_addr *pDestMacAddress; + uint8_t STAId; + uint8_t proto_type = 0; +#ifdef QCA_PKT_PROTO_TRACE + hdd_context_t *hddCtxt = (hdd_context_t *) pAdapter->pHddCtx; +#endif /* QCA_PKT_PROTO_TRACE */ + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; + /* Prevent this function from being called during SSR since TL + * context may not be reinitialized at this time which may + * lead to a crash. + */ + if (pHddCtx->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: LOGP in Progress. Ignore!!!", __func__); + goto drop_pkt; + } + + /* + * If the device is operating on a DFS Channel + * then check if SAP is in CAC WAIT state and + * drop the packets. In CAC WAIT state device + * is expected not to transmit any frames. + * SAP starts Tx only after the BSS START is + * done. + */ + if (pHddApCtx->dfs_cac_block_tx) { + goto drop_pkt; + } + + pDestMacAddress = (struct cdf_mac_addr *) skb->data; + + if (cdf_is_macaddr_broadcast(pDestMacAddress) || + cdf_is_macaddr_group(pDestMacAddress)) { + /* The BC/MC station ID is assigned during BSS + * starting phase. SAP will return the station ID + * used for BC/MC traffic. + */ + STAId = pHddApCtx->uBCStaId; + } else { + if (CDF_STATUS_SUCCESS != + hdd_softap_get_sta_id(pAdapter, + pDestMacAddress, &STAId)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_WARN, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } + + if (STAId == HDD_WLAN_INVALID_STA_ID) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_WARN, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } else if (false == pAdapter->aStaInfo[STAId].isUsed) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_WARN, + "%s: STA %d is unregistered", __func__, + STAId); + goto drop_pkt; + } + + if ((ol_txrx_peer_state_conn != + pAdapter->aStaInfo[STAId].tlSTAState) + && (ol_txrx_peer_state_auth != + pAdapter->aStaInfo[STAId].tlSTAState)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_WARN, + "%s: Station not connected yet", __func__); + goto drop_pkt; + } else if (ol_txrx_peer_state_conn == + pAdapter->aStaInfo[STAId].tlSTAState) { + if (ntohs(skb->protocol) != HDD_ETHERTYPE_802_1_X) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_WARN, + "%s: NON-EAPOL packet in non-Authenticated state", + __func__); + goto drop_pkt; + } + } + } + + hdd_get_tx_resource(pAdapter, STAId, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac]; + +#if defined (IPA_OFFLOAD) + if (!(NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID)) { +#endif + /* Check if the buffer has enough header room */ + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) + goto drop_pkt; + + if (skb_headroom(skb) < dev->hard_header_len) { + struct sk_buff *tmp; + tmp = skb; + skb = skb_realloc_headroom(tmp, dev->hard_header_len); + dev_kfree_skb(tmp); + if (!skb) + goto drop_pkt; + } +#if defined (IPA_OFFLOAD) + } +#endif + + wlan_hdd_log_eapol(skb, + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); + +#ifdef QCA_PKT_PROTO_TRACE + if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + /* Proto Trace enabled */ + proto_type = cds_pkt_get_proto_type(skb, + hddCtxt->config-> + gEnableDebugLog, 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("HA:T:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("HA:T:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + pAdapter->stats.tx_bytes += skb->len; + ++pAdapter->stats.tx_packets; + + /* Zero out skb's context buffer for the driver to use */ + cdf_mem_set(skb->cb, sizeof(skb->cb), 0); + NBUF_SET_PACKET_TRACK(skb, NBUF_TX_PKT_DATA_TRACK); + NBUF_UPDATE_TX_PKT_COUNT(skb, NBUF_TX_PKT_HDD); + + cdf_dp_trace_set_track(skb); + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_PTR_RECORD, + (uint8_t *)skb->data, sizeof(skb->data))); + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD, + (uint8_t *)skb->data, cdf_nbuf_len(skb))); + if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE) + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD, + (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE], + (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE))); + + if (ol_tx_send_data_frame(STAId, skb, + proto_type) != NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_WARN, + "%s: Failed to send packet to txrx for staid:%d", + __func__, STAId); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + goto drop_pkt; + } + dev->trans_start = jiffies; + + return NETDEV_TX_OK; + +drop_pkt: + + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)skb->data, cdf_nbuf_len(skb))); + if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE) + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE], + (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE))); + + ++pAdapter->stats.tx_dropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; + kfree_skb(skb); + + return NETDEV_TX_OK; +} + +/** + * __hdd_softap_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * + * This function is registered as a netdev ndo_tx_timeout method, and + * is invoked by the kernel if the driver takes too long to transmit a + * frame. + * + * Return: None + */ +static void __hdd_softap_tx_timeout(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + + DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, + NULL, 0)); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Transmission timeout occurred", __func__); + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: LOGP in Progress. Ignore!!!", __func__); + return; + } +} + +/** + * hdd_softap_tx_timeout() - SSR wrapper for __hdd_softap_tx_timeout + * @dev: pointer to net_device + * + * Return: none + */ +void hdd_softap_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_softap_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +/** + * @hdd_softap_init_tx_rx() - Initialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + uint8_t STAId = 0; + + cdf_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats)); + + spin_lock_init(&pAdapter->staInfo_lock); + + for (STAId = 0; STAId < WLAN_MAX_STA_COUNT; STAId++) { + cdf_mem_zero(&pAdapter->aStaInfo[STAId], + sizeof(hdd_station_info_t)); + } + + return status; +} + +/** + * @hdd_softap_deinit_tx_rx() - Deinitialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + return status; +} + +/** + * hdd_softap_init_tx_rx_sta() - Initialize tx/rx for a softap station + * @pAdapter: pointer to adapter context + * @STAId: Station ID to initialize + * @pmacAddrSTA: pointer to the MAC address of the station + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId, + struct cdf_mac_addr *pmacAddrSTA) +{ + spin_lock_bh(&pAdapter->staInfo_lock); + if (pAdapter->aStaInfo[STAId].isUsed) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Reinit station %d", __func__, STAId); + spin_unlock_bh(&pAdapter->staInfo_lock); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_zero(&pAdapter->aStaInfo[STAId], sizeof(hdd_station_info_t)); + + pAdapter->aStaInfo[STAId].isUsed = true; + pAdapter->aStaInfo[STAId].isDeauthInProgress = false; + cdf_copy_macaddr(&pAdapter->aStaInfo[STAId].macAddrSTA, pmacAddrSTA); + + spin_unlock_bh(&pAdapter->staInfo_lock); + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_deinit_tx_rx_sta() - Deinitialize tx/rx for a softap station + * @pAdapter: pointer to adapter context + * @STAId: Station ID to deinitialize + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_hostapd_state_t *pHostapdState; + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + spin_lock_bh(&pAdapter->staInfo_lock); + + if (false == pAdapter->aStaInfo[STAId].isUsed) { + spin_unlock_bh(&pAdapter->staInfo_lock); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Deinit station not inited %d", __func__, STAId); + return CDF_STATUS_E_FAILURE; + } + + pAdapter->aStaInfo[STAId].isUsed = false; + pAdapter->aStaInfo[STAId].isDeauthInProgress = false; + + spin_unlock_bh(&pAdapter->staInfo_lock); + return status; +} + +/** + * hdd_softap_rx_packet_cbk() - Receive packet handler + * @cds_context: pointer to CDS context + * @rxBuf: pointer to rx cdf_nbuf + * @staId: Station Id + * + * Receive callback registered with TL. TL will call this to notify + * the HDD when one or more packets were received for a registered + * STA. + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_softap_rx_packet_cbk(void *cds_context, + cdf_nbuf_t rxBuf, uint8_t staId) +{ + hdd_adapter_t *pAdapter = NULL; + int rxstat; + unsigned int cpu_index; + struct sk_buff *skb = NULL; + hdd_context_t *pHddCtx = NULL; +#ifdef QCA_PKT_PROTO_TRACE + uint8_t proto_type; +#endif /* QCA_PKT_PROTO_TRACE */ + + /* Sanity check on inputs */ + if ((NULL == cds_context) || (NULL == rxBuf)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return CDF_STATUS_E_FAILURE; + } + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL == pHddCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return CDF_STATUS_E_FAILURE; + } + + pAdapter = pHddCtx->sta_to_adapter[staId]; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hddLog(LOGE, + FL("invalid adapter %p or adapter has invalid magic"), + pAdapter); + return CDF_STATUS_E_FAILURE; + } + + /* walk the chain until all are processed */ + skb = (struct sk_buff *)rxBuf; + + hdd_softap_dump_sk_buff(skb); + + skb->dev = pAdapter->dev; + + if (skb->dev == NULL) { + + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: ERROR!!Invalid netdevice", __func__); + return CDF_STATUS_E_FAILURE; + } + cpu_index = wlan_hdd_get_cpu(); + ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += skb->len; + + wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); + +#ifdef QCA_PKT_PROTO_TRACE + if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + proto_type = cds_pkt_get_proto_type(skb, + pHddCtx->config-> + gEnableDebugLog, 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("HA:R:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("HA:R:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + + skb->protocol = eth_type_trans(skb, skb->dev); +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK + cdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock, + HDD_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); +#endif + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + cdf_net_buf_debug_release_skb(rxBuf); + + if (hdd_napi_enabled(HDD_NAPI_ANY)) + rxstat = netif_receive_skb(skb); + else + rxstat = netif_rx_ni(skb); + if (NET_RX_SUCCESS == rxstat) { + ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + } else { + ++pAdapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + } + + pAdapter->dev->last_rx = jiffies; + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) + * @pAdapter: pointer to adapter context + * @staId: Station ID to deregister + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + hdd_context_t *pHddCtx; + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: pAdapter is NULL", __func__); + return CDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid pAdapter magic", __func__); + return CDF_STATUS_E_INVAL; + } + + pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + /* Clear station in TL and then update HDD data + * structures. This helps to block RX frames from other + * station to this station. + */ + cdf_status = ol_txrx_clear_peer(staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "ol_txrx_clear_peer() failed to for staID %d. " + "Status= %d [0x%08X]", staId, cdf_status, cdf_status); + } + + if (pAdapter->aStaInfo[staId].isUsed) { + spin_lock_bh(&pAdapter->staInfo_lock); + cdf_mem_zero(&pAdapter->aStaInfo[staId], + sizeof(hdd_station_info_t)); + spin_unlock_bh(&pAdapter->staInfo_lock); + } + pHddCtx->sta_to_adapter[staId] = NULL; + + return cdf_status; +} + +/** + * hdd_softap_register_sta() - Register a SoftAP STA + * @pAdapter: pointer to adapter context + * @fAuthRequired: is additional authentication required? + * @fPrivacyBit: should 802.11 privacy bit be set? + * @staId: station ID assigned to this station + * @ucastSig: unicast security signature + * @bcastSig: broadcast security signature + * @pPeerMacAddress: station MAC address + * @fWmmEnabled: is WMM enabled for this STA? + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter, + bool fAuthRequired, + bool fPrivacyBit, + uint8_t staId, + uint8_t ucastSig, + uint8_t bcastSig, + struct cdf_mac_addr *pPeerMacAddress, + bool fWmmEnabled) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + + /* + * Clean up old entry if it is not cleaned up properly + */ + if (pAdapter->aStaInfo[staId].isUsed) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "clean up old entry for STA %d", staId); + hdd_softap_deregister_sta(pAdapter, staId); + } + /* Get the Station ID from the one saved during the assocation. */ + + staDesc.sta_id = staId; + + /*Save the pAdapter Pointer for this staId */ + pHddCtx->sta_to_adapter[staId] = pAdapter; + + cdf_status = + hdd_softap_init_tx_rx_sta(pAdapter, staId, + pPeerMacAddress); + + staDesc.is_qos_enabled = fWmmEnabled; + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "HDD SOFTAP register TL QoS_enabled=%d", + staDesc.is_qos_enabled); + + + cdf_status = + ol_txrx_register_peer(hdd_softap_rx_packet_cbk, + &staDesc); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "SOFTAP ol_txrx_register_peer() failed to register. Status= %d [0x%08X]", + cdf_status, cdf_status); + return cdf_status; + } + + /* if ( WPA ), tell TL to go to 'connected' and after keys come to the + * driver then go to 'authenticated'. For all other authentication + * types (those that do not require upper layer authentication) we can + * put TL directly into 'authenticated' state + */ + + pAdapter->aStaInfo[staId].ucSTAId = staId; + pAdapter->aStaInfo[staId].isQosEnabled = fWmmEnabled; + + if (!fAuthRequired) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "open/shared auth StaId= %d. Changing TL state to AUTHENTICATED at Join time", + pAdapter->aStaInfo[staId].ucSTAId); + + /* Connections that do not need Upper layer auth, + * transition TL directly to 'Authenticated' state. + */ + cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id, + ol_txrx_peer_state_auth, false); + + pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_auth; + pAdapter->sessionCtx.ap.uIsAuthenticated = true; + } else { + + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + pAdapter->aStaInfo[staId].ucSTAId); + + cdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id, + ol_txrx_peer_state_conn, false); + pAdapter->aStaInfo[staId].tlSTAState = ol_txrx_peer_state_conn; + + pAdapter->sessionCtx.ap.uIsAuthenticated = false; + + } + + /* Enable Tx queue */ + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + return cdf_status; +} + +/** + * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA + * @pAdapter: pointer to adapter context + * @fPrivacyBit: should 802.11 privacy bit be set? + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter, + bool fPrivacyBit) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct cdf_mac_addr broadcastMacAddr = + CDF_MAC_ADDR_BROADCAST_INITIALIZER; + hdd_ap_ctx_t *pHddApCtx; + + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + + pHddCtx->sta_to_adapter[WLAN_RX_BCMC_STA_ID] = pAdapter; +#ifdef WLAN_FEATURE_MBSSID + pHddCtx->sta_to_adapter[pHddApCtx->uBCStaId] = pAdapter; +#else + pHddCtx->sta_to_adapter[WLAN_RX_SAP_SELF_STA_ID] = pAdapter; +#endif + cdf_status = + hdd_softap_register_sta(pAdapter, false, fPrivacyBit, + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))-> + uBCStaId, 0, 1, &broadcastMacAddr, 0); + + return cdf_status; +} + +/** + * hdd_softap_deregister_bc_sta() - Deregister the SoftAP broadcast STA + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter) +{ + return hdd_softap_deregister_sta(pAdapter, + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))-> + uBCStaId); +} + +/** + * hdd_softap_stop_bss() - Stop the BSS + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pAdapter) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + uint8_t staId = 0; + hdd_context_t *pHddCtx; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* bss deregister is not allowed during wlan driver loading or + * unloading + */ + if ((pHddCtx->isLoadInProgress) || (pHddCtx->isUnloadInProgress)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s:Loading_unloading in Progress. Ignore!!!", + __func__); + return CDF_STATUS_E_PERM; + } + + cdf_status = hdd_softap_deregister_bc_sta(pAdapter); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to deregister BC sta Id %d", __func__, + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->uBCStaId); + } + + for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) { + /* This excludes BC sta as it is already deregistered */ + if (pAdapter->aStaInfo[staId].isUsed) { + cdf_status = hdd_softap_deregister_sta(pAdapter, staId); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to deregister sta Id %d", + __func__, staId); + } + } + } + return cdf_status; +} + +/** + * hdd_softap_change_sta_state() - Change the state of a SoftAP station + * @pAdapter: pointer to adapter context + * @pDestMacAddress: MAC address of the station + * @state: new state of the station + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter, + struct cdf_mac_addr *pDestMacAddress, + enum ol_txrx_peer_state state) +{ + uint8_t ucSTAId = WLAN_MAX_STA_COUNT; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "%s: enter", __func__); + + if (CDF_STATUS_SUCCESS != + hdd_softap_get_sta_id(pAdapter, + pDestMacAddress, &ucSTAId)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to find right station", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (false == + cdf_is_macaddr_equal(&pAdapter->aStaInfo[ucSTAId].macAddrSTA, + pDestMacAddress)) { + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Station MAC address does not matching", + __func__); + return CDF_STATUS_E_FAILURE; + } + + cdf_status = + hdd_change_peer_state(pAdapter, ucSTAId, state, false); + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "%s: change station to state %d succeed", __func__, state); + + if (CDF_STATUS_SUCCESS == cdf_status) { + pAdapter->aStaInfo[ucSTAId].tlSTAState = + ol_txrx_peer_state_auth; + } + + CDF_TRACE(CDF_MODULE_ID_HDD_SAP_DATA, CDF_TRACE_LEVEL_INFO, + "%s exit", __func__); + + return cdf_status; +} + +/* + * hdd_softap_get_sta_id() - Find station ID from MAC address + * @pAdapter: pointer to adapter context + * @pDestMacAddress: MAC address of the destination + * @staId: Station ID associated with the MAC address + * + * Return: CDF_STATUS_SUCCESS if a match was found, in which case + * staId is populated, CDF_STATUS_E_FAILURE if a match is + * not found + */ +CDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter, + struct cdf_mac_addr *pMacAddress, + uint8_t *staId) +{ + uint8_t i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (cdf_mem_compare + (&pAdapter->aStaInfo[i].macAddrSTA, pMacAddress, + CDF_MAC_ADDR_SIZE) && pAdapter->aStaInfo[i].isUsed) { + *staId = i; + return CDF_STATUS_SUCCESS; + } + } + + return CDF_STATUS_E_FAILURE; +} diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c new file mode 100644 index 0000000000..a08f133213 --- /dev/null +++ b/core/hdd/src/wlan_hdd_stats.c @@ -0,0 +1,2511 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_stats.c + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#include "wlan_hdd_stats.h" +#include "sme_api.h" +#include "cds_sched.h" +#include "wlan_hdd_trace.h" + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * struct hdd_ll_stats_context - hdd link layer stats context + * + * @request_id: userspace-assigned link layer stats request id + * @request_bitmap: userspace-assigned link layer stats request bitmap + * @response_event: LL stats request wait event + */ +struct hdd_ll_stats_context { + uint32_t request_id; + uint32_t request_bitmap; + struct completion response_event; + spinlock_t context_lock; +}; + +static struct hdd_ll_stats_context ll_stats_context; + +#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +/* 11B, 11G Rate table include Basic rate and Extended rate + * The IDX field is the rate index + * The HI field is the rate when RSSI is strong or being ignored + * (in this case we report actual rate) + * The MID field is the rate when RSSI is moderate + * (in this case we cap 11b rates at 5.5 and 11g rates at 24) + * The LO field is the rate when RSSI is low + * (in this case we don't report rates, actual current rate used) + */ +static const struct { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +} supported_data_rate[] = { +/* IDX HI HM LM LO (RSSI-based index */ + { + 2, { + 10, 10, 10, 0 + } + }, { + 4, { + 20, 20, 10, 0 + } + }, { + 11, { + 55, 20, 10, 0 + } + }, { + 12, { + 60, 55, 20, 0 + } + }, { + 18, { + 90, 55, 20, 0 + } + }, { + 22, { + 110, 55, 20, 0 + } + }, { + 24, { + 120, 90, 60, 0 + } + }, { + 36, { + 180, 120, 60, 0 + } + }, { + 44, { + 220, 180, 60, 0 + } + }, { + 48, { + 240, 180, 90, 0 + } + }, { + 66, { + 330, 180, 90, 0 + } + }, { + 72, { + 360, 240, 90, 0 + } + }, { + 96, { + 480, 240, 120, 0 + } + }, { + 108, { + 540, 240, 120, 0 + } + } +}; +/* MCS Based rate table HT MCS parameters with Nss = 1 */ +static struct index_data_rate_type supported_mcs_rate_nss1[] = { +/* MCS L20 L40 S20 S40 */ + {0, {65, 135, 72, 150} }, + {1, {130, 270, 144, 300} }, + {2, {195, 405, 217, 450} }, + {3, {260, 540, 289, 600} }, + {4, {390, 810, 433, 900} }, + {5, {520, 1080, 578, 1200} }, + {6, {585, 1215, 650, 1350} }, + {7, {650, 1350, 722, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static struct index_data_rate_type supported_mcs_rate_nss2[] = { +/* MCS L20 L40 S20 S40 */ + {0, {130, 270, 144, 300} }, + {1, {260, 540, 289, 600} }, + {2, {390, 810, 433, 900} }, + {3, {520, 1080, 578, 1200} }, + {4, {780, 1620, 867, 1800} }, + {5, {1040, 2160, 1156, 2400} }, + {6, {1170, 2430, 1300, 2700} }, + {7, {1300, 2700, 1444, 3000} } +}; + +#ifdef WLAN_FEATURE_11AC +/* MCS Based VHT rate table MCS parameters with Nss = 1*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {293, 325}, {135, 150}, {65, 72} }, + {1, {585, 650}, {270, 300}, {130, 144} }, + {2, {878, 975}, {405, 450}, {195, 217} }, + {3, {1170, 1300}, {540, 600}, {260, 289} }, + {4, {1755, 1950}, {810, 900}, {390, 433} }, + {5, {2340, 2600}, {1080, 1200}, {520, 578} }, + {6, {2633, 2925}, {1215, 1350}, {585, 650} }, + {7, {2925, 3250}, {1350, 1500}, {650, 722} }, + {8, {3510, 3900}, {1620, 1800}, {780, 867} }, + {9, {3900, 4333}, {1800, 2000}, {780, 867} } +}; + +/*MCS parameters with Nss = 2*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {585, 650}, {270, 300}, {130, 144} }, + {1, {1170, 1300}, {540, 600}, {260, 289} }, + {2, {1755, 1950}, {810, 900}, {390, 433} }, + {3, {2340, 2600}, {1080, 1200}, {520, 578} }, + {4, {3510, 3900}, {1620, 1800}, {780, 867} }, + {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, + {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, + {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, + {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, + {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } +}; +#endif /* End of WLAN_FEATURE_11AC */ + +/*array index ponints to MCS and array value points respective rssi*/ +static int rssi_mcs_tbl[][10] = { +/*MCS 0 1 2 3 4 5 6 7 8 9*/ + {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */ + {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */ + {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */ +}; + + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * put_wifi_rate_stat() - put wifi rate stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_rate_stat(tpSirWifiRateStat stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE, + stats->rate.preamble) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS, + stats->rate.nss) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW, + stats->rate.bw) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX, + stats->rate.rateMcsIdx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE, + stats->rate.bitrate) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU, + stats->txMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + stats->rxMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + stats->mpduLost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT, + stats->retriesShort) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + stats->retriesLong)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + } + + return true; +} + +/** + * put_wifi_peer_info() - put wifi peer info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_peer_info(tpSirWifiPeerInfo stats, + struct sk_buff *vendor_event) +{ + u32 i = 0; + tpSirWifiRateStat pRateStats; + + if (nla_put_u32 + (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + stats->type) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + CDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + stats->capabilities) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + stats->numRate)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + goto error; + } + + if (stats->numRate) { + struct nlattr *rateInfo; + struct nlattr *rates; + + rateInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO); + if (rateInfo == NULL) + goto error; + + for (i = 0; i < stats->numRate; i++) { + pRateStats = (tpSirWifiRateStat) ((uint8_t *) + stats->rateStats + + (i * + sizeof + (tSirWifiRateStat))); + rates = nla_nest_start(vendor_event, i); + if (rates == NULL) + goto error; + + if (false == + put_wifi_rate_stat(pRateStats, vendor_event)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + } + nla_nest_end(vendor_event, rates); + } + nla_nest_end(vendor_event, rateInfo); + } + + return true; +error: + return false; +} + +/** + * put_wifi_wmm_ac_stat() - put wifi wmm ac stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC, + stats->ac) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU, + stats->txMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU, + stats->rxMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST, + stats->txMcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST, + stats->rxMcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU, + stats->rxAmpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU, + stats->txAmpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST, + stats->mpduLost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT, + stats->retriesShort) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG, + stats->retriesLong) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN, + stats->contentionTimeMin) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX, + stats->contentionTimeMax) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG, + stats->contentionTimeAvg) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, + stats->contentionNumSamples)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + } + + return true; +} + +/** + * put_wifi_interface_info() - put wifi interface info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE, + stats->mode) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR, + CDF_MAC_ADDR_SIZE, stats->macAddr.bytes) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE, + stats->state) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING, + stats->roaming) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES, + stats->capabilities) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID, + strlen(stats->ssid), stats->ssid) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID, + CDF_MAC_ADDR_SIZE, stats->bssid.bytes) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR, + WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + } + + return true; +} + +/** + * put_wifi_iface_stats() - put wifi interface stats + * @pWifiIfaceStat: Pointer to interface stats context + * @num_peer: Number of peers + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, + u32 num_peers, struct sk_buff *vendor_event) +{ + int i = 0; + struct nlattr *wmmInfo; + struct nlattr *wmmStats; + u64 average_tsf_offset; + + if (false == put_wifi_interface_info(&pWifiIfaceStat->info, + vendor_event)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + + } + + average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high; + average_tsf_offset = (average_tsf_offset << 32) | + pWifiIfaceStat->avg_bcn_spread_offset_low ; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + num_peers) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX, + pWifiIfaceStat->beaconRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX, + pWifiIfaceStat->mgmtRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX, + pWifiIfaceStat->mgmtActionRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX, + pWifiIfaceStat->mgmtActionTx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT, + pWifiIfaceStat->rssiMgmt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA, + pWifiIfaceStat->rssiData) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK, + pWifiIfaceStat->rssiAck) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + pWifiIfaceStat->is_leaky_ap) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + pWifiIfaceStat->avg_rx_frms_leaked) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + pWifiIfaceStat->rx_leak_window) || + nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + average_tsf_offset)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + return false; + } + + wmmInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO); + if (wmmInfo == NULL) + return false; + + for (i = 0; i < WIFI_AC_MAX; i++) { + wmmStats = nla_nest_start(vendor_event, i); + if (wmmStats == NULL) + return false; + + if (false == + put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i], + vendor_event)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("put_wifi_wmm_ac_stat Fail")); + return false; + } + + nla_nest_end(vendor_event, wmmStats); + } + nla_nest_end(vendor_event, wmmInfo); + return true; +} + +/** + * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode + * @deviceMode: Device mode + * + * Return: interface mode + */ +static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode) +{ + switch (deviceMode) { + case WLAN_HDD_INFRA_STATION: + return WIFI_INTERFACE_STA; + case WLAN_HDD_SOFTAP: + return WIFI_INTERFACE_SOFTAP; + case WLAN_HDD_P2P_CLIENT: + return WIFI_INTERFACE_P2P_CLIENT; + case WLAN_HDD_P2P_GO: + return WIFI_INTERFACE_P2P_GO; + case WLAN_HDD_IBSS: + return WIFI_INTERFACE_IBSS; + default: + /* Return Interface Mode as STA for all the unsupported modes */ + return WIFI_INTERFACE_STA; + } +} + +/** + * hdd_get_interface_info() - get interface info + * @pAdapter: Pointer to device adapter + * @pInfo: Pointer to interface info + * + * Return: bool + */ +static bool hdd_get_interface_info(hdd_adapter_t *pAdapter, + tpSirWifiInterfaceInfo pInfo) +{ + uint8_t *staMac = NULL; + hdd_station_ctx_t *pHddStaCtx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode); + + cdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent); + + if (((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || + (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || + (WLAN_HDD_P2P_DEVICE == pAdapter->device_mode))) { + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState) { + pInfo->state = WIFI_DISCONNECTED; + } + if (eConnectionState_Connecting == + pHddStaCtx->conn_info.connState) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Session ID %d, Connection is in progress", + __func__, pAdapter->sessionId); + pInfo->state = WIFI_ASSOCIATING; + } + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (false == pHddStaCtx->conn_info.uIsAuthenticated)) { + staMac = + (uint8_t *) &(pAdapter->macAddressCurrent. + bytes[0]); + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: client " MAC_ADDRESS_STR + " is in the middle of WPS/EAPOL exchange.", + __func__, MAC_ADDR_ARRAY(staMac)); + pInfo->state = WIFI_AUTHENTICATING; + } + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + pInfo->state = WIFI_ASSOCIATED; + cdf_copy_macaddr(&pInfo->bssid, + &pHddStaCtx->conn_info.bssId); + cdf_mem_copy(pInfo->ssid, + pHddStaCtx->conn_info.SSID.SSID.ssId, + pHddStaCtx->conn_info.SSID.SSID.length); + /* + * NULL Terminate the string + */ + pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0; + } + } + + cdf_mem_copy(pInfo->countryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + cdf_mem_copy(pInfo->apCountryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + return true; +} + +/** + * hdd_link_layer_process_peer_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @more_data: More data + * @pData: Pointer to stats data + * + * Receiving Link Layer Peer statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, + u32 more_data, + tpSirWifiPeerStat pData) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tpSirWifiRateStat pWifiRateStat; + tpSirWifiPeerStat pWifiPeerStat; + tpSirWifiPeerInfo pWifiPeerInfo; + struct sk_buff *vendor_event; + int status, i, j; + struct nlattr *peers; + int numRate; + + pWifiPeerStat = pData; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_PEER_ALL : numPeers %u, more data = %u", + pWifiPeerStat->numPeers, more_data); + + for (i = 0; i < pWifiPeerStat->numPeers; i++) { + pWifiPeerInfo = (tpSirWifiPeerInfo) + ((uint8_t *) pWifiPeerStat->peerInfo + + (i * sizeof(tSirWifiPeerInfo))); + + if (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) + pWifiPeerInfo->type = WIFI_PEER_AP; + + if (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) + pWifiPeerInfo->type = WIFI_PEER_P2P_GO; + + hddLog(CDF_TRACE_LEVEL_INFO, + " %d) LL_STATS Channel Stats " + " Peer Type %u " + " peerMacAddress %pM " + " capabilities 0x%x " + " numRate %u ", + i, + pWifiPeerInfo->type, + pWifiPeerInfo->peerMacAddress.bytes, + pWifiPeerInfo->capabilities, pWifiPeerInfo->numRate); + { + for (j = 0; j < pWifiPeerInfo->numRate; j++) { + pWifiRateStat = (tpSirWifiRateStat) + ((uint8_t *) pWifiPeerInfo->rateStats + + (j * sizeof(tSirWifiRateStat))); + + hddLog(CDF_TRACE_LEVEL_INFO, + " peer Rate Stats " + " preamble %u " + " nss %u " + " bw %u " + " rateMcsIdx %u " + " reserved %u " + " bitrate %u " + " txMpdu %u " + " rxMpdu %u " + " mpduLost %u " + " retries %u " + " retriesShort %u " + " retriesLong %u", + pWifiRateStat->rate.preamble, + pWifiRateStat->rate.nss, + pWifiRateStat->rate.bw, + pWifiRateStat->rate.rateMcsIdx, + pWifiRateStat->rate.reserved, + pWifiRateStat->rate.bitrate, + pWifiRateStat->txMpdu, + pWifiRateStat->rxMpdu, + pWifiRateStat->mpduLost, + pWifiRateStat->retries, + pWifiRateStat->retriesShort, + pWifiRateStat->retriesLong); + } + } + } + + /* + * Allocate a size of 4096 for the peer stats comprising + * each of size = sizeof (tSirWifiPeerInfo) + numRate * + * sizeof (tSirWifiRateStat).Each field is put with an + * NL attribute.The size of 4096 is considered assuming + * that number of rates shall not exceed beyond 50 with + * the sizeof (tSirWifiRateStat) being 32. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hddLog(LOGE, + FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + pWifiPeerStat->numPeers)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: QCA_WLAN_VENDOR_ATTR put fail", __func__); + + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat->peerInfo); + + if (pWifiPeerStat->numPeers) { + struct nlattr *peerInfo; + peerInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO); + if (peerInfo == NULL) { + hddLog(LOGE, FL("nla_nest_start failed")); + kfree_skb(vendor_event); + return; + } + + for (i = 1; i <= pWifiPeerStat->numPeers; i++) { + peers = nla_nest_start(vendor_event, i); + if (peers == NULL) { + hddLog(LOGE, FL("nla_nest_start failed")); + kfree_skb(vendor_event); + return; + } + + numRate = pWifiPeerInfo->numRate; + + if (false == + put_wifi_peer_info(pWifiPeerInfo, vendor_event)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("put_wifi_peer_info fail")); + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat-> + peerInfo + + (i * + sizeof + (tSirWifiPeerInfo)) + + + (numRate * + sizeof + (tSirWifiRateStat))); + nla_nest_end(vendor_event, peers); + } + nla_nest_end(vendor_event, peerInfo); + } + cfg80211_vendor_cmd_reply(vendor_event); + return; +} + +/** + * hdd_link_layer_process_iface_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @pData: Pointer to stats data + * @num_peers: Number of peers + * + * Receiving Link Layer Interface statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter, + tpSirWifiIfaceStat pData, + u32 num_peers) +{ + tpSirWifiIfaceStat pWifiIfaceStat; + struct sk_buff *vendor_event; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + int i; + + pWifiIfaceStat = pData; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + + /* + * Allocate a size of 4096 for the interface stats comprising + * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered + * assuming that all these fit with in the limit.Please take + * a call on the limit based on the data requirements on + * interface statistics. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return; + } + + hddLog(CDF_TRACE_LEVEL_INFO, "WMI_LINK_STATS_IFACE Data"); + + if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("hdd_get_interface_info get fail")); + kfree_skb(vendor_event); + return; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + " Num peers %u " + "LL_STATS_IFACE: " + " Mode %u " + " MAC %pM " + " State %u " + " Roaming %u " + " capabilities 0x%x " + " SSID %s " + " BSSID %pM", + num_peers, + pWifiIfaceStat->info.mode, + pWifiIfaceStat->info.macAddr.bytes, + pWifiIfaceStat->info.state, + pWifiIfaceStat->info.roaming, + pWifiIfaceStat->info.capabilities, + pWifiIfaceStat->info.ssid, pWifiIfaceStat->info.bssid.bytes); + + hddLog(CDF_TRACE_LEVEL_INFO, + " AP country str: %c%c%c", + pWifiIfaceStat->info.apCountryStr[0], + pWifiIfaceStat->info.apCountryStr[1], + pWifiIfaceStat->info.apCountryStr[2]); + + hddLog(CDF_TRACE_LEVEL_INFO, + " Country Str Association: %c%c%c", + pWifiIfaceStat->info.countryStr[0], + pWifiIfaceStat->info.countryStr[1], + pWifiIfaceStat->info.countryStr[2]); + + hddLog(CDF_TRACE_LEVEL_INFO, + " beaconRx %u " + " mgmtRx %u " + " mgmtActionRx %u " + " mgmtActionTx %u " + " rssiMgmt %u " + " rssiData %u " + " rssiAck %u " + " avg_bcn_spread_offset_high %u" + " avg_bcn_spread_offset_low %u" + " is leaky_ap %u" + " avg_rx_frms_leaked %u" + " rx_leak_window %u", + pWifiIfaceStat->beaconRx, + pWifiIfaceStat->mgmtRx, + pWifiIfaceStat->mgmtActionRx, + pWifiIfaceStat->mgmtActionTx, + pWifiIfaceStat->rssiMgmt, + pWifiIfaceStat->rssiData, + pWifiIfaceStat->rssiAck, + pWifiIfaceStat->avg_bcn_spread_offset_high, + pWifiIfaceStat->avg_bcn_spread_offset_low, + pWifiIfaceStat->is_leaky_ap, + pWifiIfaceStat->avg_rx_frms_leaked, + pWifiIfaceStat->rx_leak_window); + + for (i = 0; i < WIFI_AC_MAX; i++) { + hddLog(CDF_TRACE_LEVEL_INFO, + " %d) LL_STATS IFACE: " + " ac: %u txMpdu: %u " + " rxMpdu: %u txMcast: %u " + " rxMcast: %u rxAmpdu: %u " + " txAmpdu: %u mpduLost: %u " + " retries: %u retriesShort: %u " + " retriesLong: %u contentionTimeMin: %u " + " contentionTimeMax: %u contentionTimeAvg: %u " + " contentionNumSamples: %u", + i, + pWifiIfaceStat->AccessclassStats[i].ac, + pWifiIfaceStat->AccessclassStats[i].txMpdu, + pWifiIfaceStat->AccessclassStats[i].rxMpdu, + pWifiIfaceStat->AccessclassStats[i].txMcast, + pWifiIfaceStat->AccessclassStats[i].rxMcast, + pWifiIfaceStat->AccessclassStats[i].rxAmpdu, + pWifiIfaceStat->AccessclassStats[i].txAmpdu, + pWifiIfaceStat->AccessclassStats[i].mpduLost, + pWifiIfaceStat->AccessclassStats[i].retries, + pWifiIfaceStat->AccessclassStats[i].retriesShort, + pWifiIfaceStat->AccessclassStats[i].retriesLong, + pWifiIfaceStat->AccessclassStats[i].contentionTimeMin, + pWifiIfaceStat->AccessclassStats[i].contentionTimeMax, + pWifiIfaceStat->AccessclassStats[i].contentionTimeAvg, + pWifiIfaceStat->AccessclassStats[i]. + contentionNumSamples); + } + + if (false == + put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("put_wifi_iface_stats fail")); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_cmd_reply(vendor_event); + return; +} + +/** + * hdd_link_layer_process_radio_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @more_data: More data + * @pData: Pointer to stats data + * @num_radios: Number of radios + * + * Receiving Link Layer Radio statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, + u32 more_data, + tpSirWifiRadioStat pData, + u32 num_radio) +{ + int status, i; + tpSirWifiRadioStat pWifiRadioStat; + tpSirWifiChannelStats pWifiChannelStats; + struct sk_buff *vendor_event; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + pWifiRadioStat = pData; + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_RADIO" + " number of radios = %u" + " radio is %d onTime is %u" + " txTime is %u rxTime is %u" + " onTimeScan is %u onTimeNbd is %u" + " onTimeGscan is %u onTimeRoamScan is %u" + " onTimePnoScan is %u onTimeHs20 is %u" + " numChannels is %u", + num_radio, + pWifiRadioStat->radio, + pWifiRadioStat->onTime, + pWifiRadioStat->txTime, + pWifiRadioStat->rxTime, + pWifiRadioStat->onTimeScan, + pWifiRadioStat->onTimeNbd, + pWifiRadioStat->onTimeGscan, + pWifiRadioStat->onTimeRoamScan, + pWifiRadioStat->onTimePnoScan, + pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels); + + /* + * Allocate a size of 4096 for the Radio stats comprising + * sizeof (tSirWifiRadioStat) + numChannels * sizeof + * (tSirWifiChannelStats).Each channel data is put with an + * NL attribute.The size of 4096 is considered assuming that + * number of channels shall not exceed beyond 60 with the + * sizeof (tSirWifiChannelStats) being 24 bytes. + */ + + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hddLog(LOGE, + FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + num_radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + pWifiRadioStat->radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, + pWifiRadioStat->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + pWifiRadioStat->txTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + pWifiRadioStat->rxTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + pWifiRadioStat->onTimeScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + pWifiRadioStat->onTimeNbd) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + pWifiRadioStat->onTimeGscan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + pWifiRadioStat->onTimeRoamScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + pWifiRadioStat->onTimePnoScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + pWifiRadioStat->onTimeHs20) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, + pWifiRadioStat->numChannels)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("QCA_WLAN_VENDOR_ATTR put fail")); + + kfree_skb(vendor_event); + return; + } + + if (pWifiRadioStat->numChannels) { + struct nlattr *chList; + struct nlattr *chInfo; + + chList = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO); + if (chList == NULL) { + hddLog(LOGE, FL("nla_nest_start failed")); + kfree_skb(vendor_event); + return; + } + + for (i = 0; i < pWifiRadioStat->numChannels; i++) { + pWifiChannelStats = (tpSirWifiChannelStats) ((uint8_t *) + pWifiRadioStat-> + channels + + (i * + sizeof + (tSirWifiChannelStats))); + + hddLog(CDF_TRACE_LEVEL_INFO, + " %d) Channel Info" + " width is %u " + " CenterFreq %u " + " CenterFreq0 %u " + " CenterFreq1 %u " + " onTime %u " + " ccaBusyTime %u", + i, + pWifiChannelStats->channel.width, + pWifiChannelStats->channel.centerFreq, + pWifiChannelStats->channel.centerFreq0, + pWifiChannelStats->channel.centerFreq1, + pWifiChannelStats->onTime, + pWifiChannelStats->ccaBusyTime); + + chInfo = nla_nest_start(vendor_event, i); + if (chInfo == NULL) { + hddLog(LOGE, FL("nla_nest_start failed")); + kfree_skb(vendor_event); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH, + pWifiChannelStats->channel.width) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + pWifiChannelStats->channel.centerFreq) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + pWifiChannelStats->channel. + centerFreq0) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + pWifiChannelStats->channel. + centerFreq1) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + pWifiChannelStats->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + pWifiChannelStats->ccaBusyTime)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("nla_put failed")); + kfree_skb(vendor_event); + return; + } + nla_nest_end(vendor_event, chInfo); + } + nla_nest_end(vendor_event, chList); + } + cfg80211_vendor_cmd_reply(vendor_event); + return; +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called + * @ctx: Pointer to hdd context + * @indType: Indication type + * @pRsp: Pointer to response + * + * After receiving Link Layer indications from FW.This callback converts the + * firmware data to the NL data and send the same to the kernel/upper layers. + * + * Return: None + */ +static void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, + int indType, void *pRsp) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct hdd_ll_stats_context *context; + hdd_adapter_t *pAdapter = NULL; + tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp; + int status; + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return; + } + + pAdapter = hdd_get_adapter_by_vdev(pHddCtx, + linkLayerStatsResults->ifaceId); + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: vdev_id %d does not exist with host", + __func__, linkLayerStatsResults->ifaceId); + return; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Link Layer Indication indType: %d", __func__, indType); + + switch (indType) { + case SIR_HAL_LL_STATS_RESULTS_RSP: + { + hddLog(CDF_TRACE_LEVEL_INFO, + FL("RESPONSE SIR_HAL_LL_STATS_RESULTS_RSP")); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE paramID = 0x%x", + linkLayerStatsResults->paramId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE ifaceId = %u", + linkLayerStatsResults->ifaceId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE respId = %u", + linkLayerStatsResults->rspId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE more data = %u", + linkLayerStatsResults->moreResultToFollow); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE num radio = %u", + linkLayerStatsResults->num_radio); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS RESULTS RESPONSE result = %p", + linkLayerStatsResults->results); + + context = &ll_stats_context; + spin_lock(&context->context_lock); + /* validate response received from target */ + if ((context->request_id != linkLayerStatsResults->rspId) || + !(context->request_bitmap & linkLayerStatsResults->paramId)) { + spin_unlock(&context->context_lock); + hddLog(LOGE, + FL("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x"), + context->request_id, linkLayerStatsResults->rspId, + context->request_bitmap, linkLayerStatsResults->paramId); + return; + } + spin_unlock(&context->context_lock); + + if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_RADIO) { + hdd_link_layer_process_radio_stats(pAdapter, + linkLayerStatsResults->moreResultToFollow, + (tpSirWifiRadioStat)linkLayerStatsResults->results, + linkLayerStatsResults->num_radio); + + spin_lock(&context->context_lock); + if (!linkLayerStatsResults->moreResultToFollow) + context->request_bitmap &= ~(WMI_LINK_STATS_RADIO); + spin_unlock(&context->context_lock); + + } else if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_IFACE) { + hdd_link_layer_process_iface_stats(pAdapter, + (tpSirWifiIfaceStat)linkLayerStatsResults->results, + linkLayerStatsResults->num_peers); + + spin_lock(&context->context_lock); + context->request_bitmap &= ~(WMI_LINK_STATS_IFACE); + spin_unlock(&context->context_lock); + + } else if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_ALL_PEER) { + hdd_link_layer_process_peer_stats(pAdapter, + linkLayerStatsResults->moreResultToFollow, + (tpSirWifiPeerStat)linkLayerStatsResults->results); + + spin_lock(&context->context_lock); + if (!linkLayerStatsResults->moreResultToFollow) + context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + spin_unlock(&context->context_lock); + + } else { + hddLog(LOGE, + FL("INVALID LL_STATS_NOTIFY RESPONSE")); + } + + spin_lock(&context->context_lock); + /* complete response event if all requests are completed */ + if (0 == context->request_bitmap) + complete(&context->response_event); + spin_unlock(&context->context_lock); + + break; + } + default: + hddLog(CDF_TRACE_LEVEL_ERROR, "invalid event type %d", indType); + break; + } + + return; +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_init() - initialize link layer stats + * @pHddCtx: Pointer to hdd context + * + * Return: None + */ +void wlan_hdd_cfg80211_link_layer_stats_init(hdd_context_t *pHddCtx) +{ + sme_set_link_layer_stats_ind_cb(pHddCtx->hHal, + wlan_hdd_cfg80211_link_layer_stats_callback); +} + +const struct +nla_policy + qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1]; + tSirLLStatsSetReq LinkLayerStatsSetReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_set_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("maximum attribute not present")); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("MPDU size Not present")); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Stats Gathering Not Present")); + return -EINVAL; + } + + /* Shall take the request Id if the Upper layers pass. 1 For now. */ + LinkLayerStatsSetReq.reqId = 1; + + LinkLayerStatsSetReq.mpduSizeThreshold = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]); + + LinkLayerStatsSetReq.aggressiveStatisticsGathering = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]); + + LinkLayerStatsSetReq.staId = pAdapter->sessionId; + + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_SET reqId = %d", LinkLayerStatsSetReq.reqId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_SET staId = %d", LinkLayerStatsSetReq.staId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_SET mpduSizeThreshold = %d", + LinkLayerStatsSetReq.mpduSizeThreshold); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_SET aggressive Statistics Gathering = %d", + LinkLayerStatsSetReq.aggressiveStatisticsGathering); + + if (CDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal, + &LinkLayerStatsSetReq)) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s:" + "sme_ll_stats_set_req Failed", __func__); + return -EINVAL; + } + + pAdapter->isLinkLayerStatsSet = 1; + + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +const struct +nla_policy + qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = { + /* Unsigned 32bit value provided by the caller issuing the GET stats + * command. When reporting + * the stats results, the driver uses the same value to indicate + * which GET request the results + * correspond to. + */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32}, + + /* Unsigned 32bit value . bit mask to identify what statistics are + requested for retrieval */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32} +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + unsigned long rc; + struct hdd_ll_stats_context *context; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1]; + tSirLLStatsGetReq LinkLayerStatsGetReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (!pAdapter->isLinkLayerStatsSet) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: isLinkLayerStatsSet : %d", + __func__, pAdapter->isLinkLayerStatsSet); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_get_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("max attribute not present")); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Request Id Not present")); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Req Mask Not present")); + return -EINVAL; + } + + LinkLayerStatsGetReq.reqId = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]); + LinkLayerStatsGetReq.paramIdMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]); + + LinkLayerStatsGetReq.staId = pAdapter->sessionId; + + hddLog(LOG1, + FL("LL_STATS_GET reqId = %d"), LinkLayerStatsGetReq.reqId); + hddLog(LOG1, + FL("LL_STATS_GET staId = %d"), LinkLayerStatsGetReq.staId); + hddLog(LOG1, + FL("LL_STATS_GET paramIdMask = %d"), + LinkLayerStatsGetReq.paramIdMask); + + context = &ll_stats_context; + spin_lock(&context->context_lock); + context->request_id = LinkLayerStatsGetReq.reqId; + context->request_bitmap = LinkLayerStatsGetReq.paramIdMask; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + if (CDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal, + &LinkLayerStatsGetReq)) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s:" + "sme_ll_stats_get_req Failed", __func__); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS)); + if (!rc) { + hddLog(LOGE, + FL("Target response timed out request id %d request bitmap 0x%x"), + context->request_id, context->request_bitmap); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +const struct +nla_policy + qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1]; + tSirLLStatsClearReq LinkLayerStatsClearReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + u32 statsClearReqMask; + u8 stopReq; + int status; + struct sk_buff *temp_skbuff; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + + if (!pAdapter->isLinkLayerStatsSet) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "%s: isLinkLayerStatsSet : %d", + __func__, pAdapter->isLinkLayerStatsSet); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_clr_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("STATS_CLR_MAX is not present")); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] || + !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Error in LL_STATS CLR CONFIG PARA")); + return -EINVAL; + } + + statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]); + + stopReq = LinkLayerStatsClearReq.stopReq = + nla_get_u8(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]); + + /* + * Shall take the request Id if the Upper layers pass. 1 For now. + */ + LinkLayerStatsClearReq.reqId = 1; + + LinkLayerStatsClearReq.staId = pAdapter->sessionId; + + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_CLEAR reqId = %d", LinkLayerStatsClearReq.reqId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_CLEAR staId = %d", LinkLayerStatsClearReq.staId); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_CLEAR statsClearReqMask = 0x%X", + LinkLayerStatsClearReq.statsClearReqMask); + hddLog(CDF_TRACE_LEVEL_INFO, + "LL_STATS_CLEAR stopReq = %d", LinkLayerStatsClearReq.stopReq); + + if (CDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal, + &LinkLayerStatsClearReq)) { + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 2 * + sizeof(u32) + + 2 * + NLMSG_HDRLEN); + if (temp_skbuff != NULL) { + if (nla_put_u32(temp_skbuff, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK, + statsClearReqMask) || + nla_put_u32(temp_skbuff, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, + stopReq)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("LL_STATS_CLR put fail")); + kfree_skb(temp_skbuff); + return -EINVAL; + } + + /* If the ask is to stop the stats collection as part of clear + * (stopReq = 1) , ensure that no further requests of get + * go to the firmware by having isLinkLayerStatsSet set to 0. + * However it the stopReq as part of the clear request is 0 , + * the request to get the statistics are honoured as in this + * case the firmware is just asked to clear the statistics. + */ + if (stopReq == 1) + pAdapter->isLinkLayerStatsSet = 0; + + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + return -ENOMEM; + } + + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tStatsExtRequestReq stats_ext_req; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret_val; + CDF_STATUS status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + stats_ext_req.request_data_len = data_len; + stats_ext_req.request_data = (void *)data; + + status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req); + + if (CDF_STATUS_SUCCESS != status) + ret_val = -EINVAL; + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback + * @ctx: Pointer to HDD context + * @msg: Message received + * + * Return: nothing + */ +static void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, + tStatsExtEvent *msg) +{ + + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *vendor_event; + int status; + int ret_val; + tStatsExtEvent *data = msg; + hdd_adapter_t *pAdapter = NULL; + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return; + } + + pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id); + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: vdev_id %d does not exist with host", + __func__, data->vdev_id); + return; + } + + vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + data->event_data_len + + sizeof(uint32_t) + + NLMSG_HDRLEN + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: cfg80211_vendor_event_alloc failed", __func__); + return; + } + + ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX, + pAdapter->dev->ifindex); + if (ret_val) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: QCA_WLAN_VENDOR_ATTR_IFINDEX put fail", + __func__); + kfree_skb(vendor_event); + + return; + } + + ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT, + data->event_data_len, data->event_data); + + if (ret_val) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail", + __func__); + kfree_skb(vendor_event); + + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + +} + +/** + * wlan_hdd_cfg80211_stats_ext_init() - ext stats init + * @ctx: Pointer to HDD context + * + * Return: nothing + */ +void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx) +{ + sme_stats_ext_register_callback(pHddCtx->hHal, + wlan_hdd_cfg80211_stats_ext_callback); +} +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +/** + * __wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_info *sinfo) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length; + uint8_t rate_flags; + + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + struct hdd_config *pCfg = pHddCtx->config; + + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX; + uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX; + uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET]; + uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET; + uint16_t maxRate = 0; + uint16_t myRate; + uint16_t currentRate = 0; + uint8_t maxSpeedMCS = 0; + uint8_t maxMCSIdx = 0; + uint8_t rateFlag = 1; + uint8_t i, j, rssidx; + uint8_t nss = 1; + int status, mode = 0, maxHtIdx; + struct index_vht_data_rate_type *supported_vht_mcs_rate; + struct index_data_rate_type *supported_mcs_rate; + +#ifdef WLAN_FEATURE_11AC + uint32_t vht_mcs_map; + enum eDataRate11ACMaxMcs vhtMaxMcs; +#endif /* WLAN_FEATURE_11AC */ + + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) || + (0 == ssidlen)) { + hddLog(LOG1, FL("Not associated or Invalid ssidlen, %d"), + ssidlen); + /*To keep GUI happy */ + return 0; + } + + if (true == pHddStaCtx->hdd_ReassocScenario) { + hddLog(LOG1, + FL("Roaming is in progress, cannot continue with this request")); + return 0; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + wlan_hdd_get_rssi(pAdapter, &sinfo->signal); + sinfo->filled |= STATION_INFO_SIGNAL; + +#ifdef WLAN_FEATURE_LPSS + if (!pAdapter->rssi_send) { + pAdapter->rssi_send = true; + wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 1); + } +#endif + + wlan_hdd_get_station_stats(pAdapter); + rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags; + + /* convert to the UI units of 100kbps */ + myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5; + if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt; + + if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) { + /* Get current rate flags if report actual */ + rate_flags = + pAdapter->hdd_stats.ClassA_stat. + promiscuous_rx_frag_cnt; + } + + if (pAdapter->hdd_stats.ClassA_stat.mcs_index == + INVALID_MCS_IDX) { + rate_flags = eHAL_TX_RATE_LEGACY; + pAdapter->hdd_stats.ClassA_stat.mcs_index = 0; + } + } +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d\n", + sinfo->signal, pCfg->reportMaxLinkSpeed, myRate, + (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid, + (int)pCfg->linkSpeedRssiLow, (int)rate_flags, + (int)pAdapter->hdd_stats.ClassA_stat.mcs_index); +#endif /* LINKSPEED_DEBUG_ENABLED */ + + if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) { + /* we do not want to necessarily report the current speed */ + if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) { + /* report the max possible speed */ + rssidx = 0; + } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED == + pCfg->reportMaxLinkSpeed) { + /* report the max possible speed with RSSI scaling */ + if (sinfo->signal >= pCfg->linkSpeedRssiHigh) { + /* report the max possible speed */ + rssidx = 0; + } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) { + /* report middle speed */ + rssidx = 1; + } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) { + /* report middle speed */ + rssidx = 2; + } else { + /* report actual speed */ + rssidx = 3; + } + } else { + /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */ + hddLog(LOGE, + FL("Invalid value for reportMaxLinkSpeed: %u"), + pCfg->reportMaxLinkSpeed); + rssidx = 0; + } + + maxRate = 0; + + /* Get Basic Rate Set */ + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_OPERATIONAL_RATE_SET, + OperationalRates, + &ORLeng)) { + hddLog(LOGE, FL("cfg get returned failure")); + /*To keep GUI happy */ + return 0; + } + + for (i = 0; i < ORLeng; i++) { + for (j = 0; + j < ARRAY_SIZE(supported_data_rate); j++) { + /* Validate Rate Set */ + if (supported_data_rate[j].beacon_rate_index == + (OperationalRates[i] & 0x7F)) { + currentRate = + supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + maxRate = + (currentRate > maxRate) ? currentRate : maxRate; + } + + /* Get Extended Rate Set */ + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedRates, &ERLeng)) { + hddLog(LOGE, FL("cfg get returned failure")); + /*To keep GUI happy */ + return 0; + } + + for (i = 0; i < ERLeng; i++) { + for (j = 0; + j < ARRAY_SIZE(supported_data_rate); j++) { + if (supported_data_rate[j].beacon_rate_index == + (ExtendedRates[i] & 0x7F)) { + currentRate = + supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + maxRate = + (currentRate > maxRate) ? currentRate : maxRate; + } + /* Get MCS Rate Set -- + Only if we are connected in non legacy mode and not reporting + actual speed */ + if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) { + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_CURRENT_MCS_SET, MCSRates, + &MCSLeng)) { + hddLog(LOGE, FL("cfg get returned failure")); + /*To keep GUI happy */ + return 0; + } + rateFlag = 0; +#ifdef WLAN_FEATURE_11AC + supported_vht_mcs_rate = + (struct index_vht_data_rate_type *) + ((nss == + 1) ? &supported_vht_mcs_rate_nss1 : + &supported_vht_mcs_rate_nss2); + + if (rate_flags & eHAL_TX_RATE_VHT80) + mode = 2; + else if ((rate_flags & eHAL_TX_RATE_VHT40) || + (rate_flags & eHAL_TX_RATE_HT40)) + mode = 1; + else + mode = 0; + + /* VHT80 rate has seperate rate table */ + if (rate_flags & + (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | + eHAL_TX_RATE_VHT80)) { + sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_VHT_TX_MCS_MAP, + &vht_mcs_map); + vhtMaxMcs = (enum eDataRate11ACMaxMcs) + (vht_mcs_map & DATA_RATE_11AC_MCS_MASK); + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 1; + if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs) + maxMCSIdx = 7; + else if (DATA_RATE_11AC_MAX_MCS_8 == + vhtMaxMcs) + maxMCSIdx = 8; + else if (DATA_RATE_11AC_MAX_MCS_9 == + vhtMaxMcs) { + /* VHT20 is supporting 0~8 */ + if (rate_flags & eHAL_TX_RATE_VHT20) + maxMCSIdx = 8; + else + maxMCSIdx = 9; + } + + if (rssidx != 0) { + for (i = 0; i <= maxMCSIdx; i++) { + if (sinfo->signal <= + rssi_mcs_tbl[mode][i]) { + maxMCSIdx = i; + break; + } + } + } + + if (rate_flags & eHAL_TX_RATE_VHT80) { + currentRate = + supported_vht_mcs_rate[pAdapter-> + hdd_stats.ClassA_stat.mcs_index]. + supported_VHT80_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT80_rate[rateFlag]; + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + currentRate = + supported_vht_mcs_rate[pAdapter-> + hdd_stats.ClassA_stat.mcs_index]. + supported_VHT40_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT40_rate[rateFlag]; + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + currentRate = + supported_vht_mcs_rate[pAdapter-> + hdd_stats.ClassA_stat.mcs_index]. + supported_VHT20_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT20_rate[rateFlag]; + } + + maxSpeedMCS = 1; + if (currentRate > maxRate) + maxRate = currentRate; + + } else +#endif /* WLAN_FEATURE_11AC */ + { + if (rate_flags & eHAL_TX_RATE_HT40) + rateFlag |= 1; + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 2; + + supported_mcs_rate = + (struct index_data_rate_type *) + ((nss == + 1) ? &supported_mcs_rate_nss1 : + &supported_mcs_rate_nss2); + + maxHtIdx = MAX_HT_MCS_IDX; + if (rssidx != 0) { + for (i = 0; i < MAX_HT_MCS_IDX; i++) { + if (sinfo->signal <= + rssi_mcs_tbl[mode][i]) { + maxHtIdx = i + 1; + break; + } + } + } + + for (i = 0; i < MCSLeng; i++) { + for (j = 0; j < maxHtIdx; j++) { + if (supported_mcs_rate[j]. + beacon_rate_index == + MCSRates[i]) { + currentRate = + supported_mcs_rate[j]. + supported_rate + [rateFlag]; + break; + } + } + + if ((j < MAX_HT_MCS_IDX) + && (currentRate > maxRate)) { + maxRate = currentRate; + maxSpeedMCS = 1; + maxMCSIdx = + supported_mcs_rate[j]. + beacon_rate_index; + } + } + } + } + + else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + maxRate = myRate; + maxSpeedMCS = 1; + maxMCSIdx = pAdapter->hdd_stats.ClassA_stat.mcs_index; + } + /* report a value at least as big as current rate */ + if ((maxRate < myRate) || (0 == maxRate)) { + maxRate = myRate; + if (rate_flags & eHAL_TX_RATE_LEGACY) { + maxSpeedMCS = 0; + } else { + maxSpeedMCS = 1; + maxMCSIdx = + pAdapter->hdd_stats.ClassA_stat.mcs_index; + } + } + + if (rate_flags & eHAL_TX_RATE_LEGACY) { + sinfo->txrate.legacy = maxRate; +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting legacy rate %d\n", + sinfo->txrate.legacy); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } else { + sinfo->txrate.mcs = maxMCSIdx; +#ifdef WLAN_FEATURE_11AC + sinfo->txrate.nss = nss; + if (rate_flags & eHAL_TX_RATE_VHT80) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + sinfo->txrate.flags |= + RATE_INFO_FLAGS_80_MHZ_WIDTH; + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + } else + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; +#endif /* WLAN_FEATURE_11AC */ + if (rate_flags & + (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & eHAL_TX_RATE_HT40) { + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; + } + } + if (rate_flags & eHAL_TX_RATE_SGI) { + if (! + (sinfo->txrate. + flags & RATE_INFO_FLAGS_VHT_MCS)) + sinfo->txrate.flags |= + RATE_INFO_FLAGS_MCS; + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting MCS rate %d flags %x\n", + sinfo->txrate.mcs, sinfo->txrate.flags); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } + } else { + /* report current rate instead of max rate */ + + if (rate_flags & eHAL_TX_RATE_LEGACY) { + /* provide to the UI in units of 100kbps */ + sinfo->txrate.legacy = myRate; +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting actual legacy rate %d\n", + sinfo->txrate.legacy); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } else { + /* must be MCS */ + sinfo->txrate.mcs = + pAdapter->hdd_stats.ClassA_stat.mcs_index; +#ifdef WLAN_FEATURE_11AC + sinfo->txrate.nss = nss; + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & eHAL_TX_RATE_VHT80) { + sinfo->txrate.flags |= + RATE_INFO_FLAGS_80_MHZ_WIDTH; + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; + } +#endif /* WLAN_FEATURE_11AC */ + if (rate_flags & + (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & eHAL_TX_RATE_HT40) { + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; + } + } + if (rate_flags & eHAL_TX_RATE_SGI) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting actual MCS rate %d flags %x\n", + sinfo->txrate.mcs, sinfo->txrate.flags); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } + } + sinfo->filled |= STATION_INFO_TX_BITRATE; + + sinfo->tx_bytes = pAdapter->stats.tx_bytes; + sinfo->filled |= STATION_INFO_TX_BYTES; + + sinfo->tx_packets = + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3]; + + sinfo->tx_retries = + pAdapter->hdd_stats.summary_stat.retry_cnt[0] + + pAdapter->hdd_stats.summary_stat.retry_cnt[1] + + pAdapter->hdd_stats.summary_stat.retry_cnt[2] + + pAdapter->hdd_stats.summary_stat.retry_cnt[3]; + + sinfo->tx_failed = + pAdapter->hdd_stats.summary_stat.fail_cnt[0] + + pAdapter->hdd_stats.summary_stat.fail_cnt[1] + + pAdapter->hdd_stats.summary_stat.fail_cnt[2] + + pAdapter->hdd_stats.summary_stat.fail_cnt[3]; + + sinfo->filled |= + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_RETRIES | STATION_INFO_TX_FAILED; + + sinfo->rx_bytes = pAdapter->stats.rx_bytes; + sinfo->filled |= STATION_INFO_RX_BYTES; + + sinfo->rx_packets = pAdapter->stats.rx_packets; + sinfo->filled |= STATION_INFO_RX_PACKETS; + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_STA, + pAdapter->sessionId, maxRate)); + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo) +#else +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_info *sinfo) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_stats() - Function to retrieve interface statistics + * @dev: pointer to network device + * + * This function is the ndo_get_stats method for all netdevs + * registered with the kernel + * + * Return: pointer to net_device_stats structure + */ +struct net_device_stats *hdd_get_stats(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + return &adapter->stats; +} +/** + * __wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + tHalHandle halHandle; + uint32_t channel = 0, freq = 0; /* Initialization Required */ + int8_t snr, rssi; + int status, i, j, filled = 0; + + ENTER(); + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return status; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (0 == pHddCtx->config->fEnableSNRMonitoring || + 0 != pAdapter->survey_idx || + eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + /* The survey dump ops when implemented completely is expected + * to return a survey of all channels and the ops is called by + * the kernel with incremental values of the argument 'idx' + * till it returns -ENONET. But we can only support the survey + * for the operating channel for now. survey_idx is used to + * track that the ops is called only once and then return + * -ENONET for the next iteration + */ + pAdapter->survey_idx = 0; + return -ENONET; + } + + if (!pHddStaCtx->hdd_ReassocScenario) { + hdd_err("Roaming in progress, hence return"); + return -ENONET; + } + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + wlan_hdd_get_snr(pAdapter, &snr); + wlan_hdd_get_rssi(pAdapter, &rssi); + + sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId); + hdd_wlan_get_freq(channel, &freq); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + if (NULL == wiphy->bands[i]) { + hddLog(LOG1, FL("wiphy->bands[i] is NULL, i = %d"), i); + continue; + } + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + if (band->channels[j].center_freq == (uint16_t) freq) { + survey->channel = &band->channels[j]; + /* The Rx BDs contain SNR values in dB for the + * received frames while the supplicant expects + * noise. So we calculate and return the value + * of noise (dBm) + * SNR (dB) = RSSI (dBm) - NOISE (dBm) + */ + survey->noise = rssi - snr; + survey->filled = SURVEY_INFO_NOISE_DBM; + filled = 1; + } + } + } + + if (filled) + pAdapter->survey_idx = 1; + else { + pAdapter->survey_idx = 0; + return -ENONET; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey); + cds_ssr_unprotect(__func__); + + return ret; +} +/** + * hdd_init_ll_stats_ctx() - initialize link layer stats context + * + * Return: none + */ +inline void hdd_init_ll_stats_ctx(void) +{ + spin_lock_init(&ll_stats_context.context_lock); + init_completion(&ll_stats_context.response_event); + ll_stats_context.request_bitmap = 0; + + return; +} diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h new file mode 100644 index 0000000000..ae5e84d0a2 --- /dev/null +++ b/core/hdd/src/wlan_hdd_stats.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_stats.h + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#if !defined(WLAN_HDD_STATS_H) +#define WLAN_HDD_STATS_H + +#include "wlan_hdd_main.h" + +#define INVALID_MCS_IDX 255 +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 + +#ifdef WLAN_FEATURE_11AC +#define DATA_RATE_11AC_MCS_MASK 0x03 + +/* LL stats get request time out value */ +#define WLAN_WAIT_TIME_LL_STATS 5000 + +/** + * struct index_vht_data_rate_type - vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_VHT80_rate: VHT80 rate + * @supported_VHT40_rate: VHT40 rate + * @supported_VHT20_rate: VHT20 rate + */ +struct index_vht_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_VHT80_rate[2]; + uint16_t supported_VHT40_rate[2]; + uint16_t supported_VHT20_rate[2]; +}; + +/** + * enum - eDataRate11ACMaxMcs + * @DATA_RATE_11AC_MAX_MCS_7: MCS7 rate + * @DATA_RATE_11AC_MAX_MCS_8: MCS8 rate + * @DATA_RATE_11AC_MAX_MCS_9: MCS9 rate + * @DATA_RATE_11AC_MAX_MCS_NA:i Not applicable + */ +enum eDataRate11ACMaxMcs{ + DATA_RATE_11AC_MAX_MCS_7, + DATA_RATE_11AC_MAX_MCS_8, + DATA_RATE_11AC_MAX_MCS_9, + DATA_RATE_11AC_MAX_MCS_NA +}; +#endif /* End of WLAN_FEATURE_11AC */ + +/** + * struct index_data_rate_type - non vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_rate: Supported rate table + */ +struct index_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +}; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +/* + * Used to allocate the size of 4096 for the link layer stats. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements on link layer + * statistics. + */ +#define LL_STATS_EVENT_BUF_SIZE 4096 + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void hdd_init_ll_stats_ctx(void); +#else +static inline void hdd_init_ll_stats_ctx(void) +{ + return; +} + +#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo); +#else +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_info *sinfo); +#endif + +struct net_device_stats *hdd_get_stats(struct net_device *dev); + +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey); +#endif /* end #if !defined(WLAN_HDD_STATS_H) */ + diff --git a/core/hdd/src/wlan_hdd_tdls.c b/core/hdd/src/wlan_hdd_tdls.c new file mode 100644 index 0000000000..459724608f --- /dev/null +++ b/core/hdd/src/wlan_hdd_tdls.c @@ -0,0 +1,4705 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_tdls.c + * + * WLAN Host Device Driver implementation for TDLS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_cfg80211.h" +#include "cds_sched.h" +#include "wma_types.h" + +static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t * + pHddTdlsCtx); +static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx); +int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac); +static void wlan_hdd_tdls_pre_setup(struct work_struct *work); + +/** + * wlan_hdd_tdls_hash_key() - calculate tdls hash key given mac address + * @mac: mac address + * + * Return: hash key + */ +static u8 wlan_hdd_tdls_hash_key(const u8 *mac) +{ + int i; + u8 key = 0; + + for (i = 0; i < 6; i++) + key ^= mac[i]; + + return key; +} + +/** + * wlan_hdd_tdls_disable_offchan_and_teardown_links - Disable offchannel + * and teardown TDLS links + * @hddCtx : pointer to hdd context + * + * Return: None + */ +void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) +{ + u16 connected_tdls_peers = 0; + u8 staidx; + hddTdlsPeer_t *curr_peer = NULL; + hdd_adapter_t *adapter = NULL; + + if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) { + hddLog(LOG1, FL("TDLS mode is disabled OR not enabled in FW")); + return ; + } + + adapter = hdd_get_adapter(hddctx, WLAN_HDD_INFRA_STATION); + + if (adapter == NULL) { + hddLog(LOGE, FL("Station Adapter Not Found")); + return; + } + + connected_tdls_peers = wlan_hdd_tdls_connected_peers(adapter); + + if (!connected_tdls_peers) + return ; + + /* TDLS is not supported in case of concurrency. + * Disable TDLS Offchannel in FW to avoid more + * than two concurrent channels and generate TDLS + * teardown indication to supplicant. + * Below function Finds the first connected peer and + * disables TDLS offchannel for that peer. + * FW enables TDLS offchannel only when there is + * one TDLS peer. When there are more than one TDLS peer, + * there will not be TDLS offchannel in FW. + * So to avoid sending multiple request to FW, for now, + * just invoke offchannel mode functions only once + */ + hdd_set_tdls_offchannel(hddctx, hddctx->config->fTDLSPrefOffChanNum); + hdd_set_tdls_secoffchanneloffset(hddctx, + TDLS_SEC_OFFCHAN_OFFSET_40PLUS); + hdd_set_tdls_offchannelmode(adapter, DISABLE_CHANSWITCH); + + for (staidx = 0; staidx < hddctx->max_num_tdls_sta; + staidx++) { + if (!hddctx->tdlsConnInfo[staidx].staId) + continue; + + curr_peer = wlan_hdd_tdls_find_all_peer(hddctx, + hddctx->tdlsConnInfo[staidx].peerMac.bytes); + + if (!curr_peer) + continue; + + hddLog(LOG1, FL("indicate TDLS teardown (staId %d)"), + curr_peer->staId); + + wlan_hdd_tdls_indicate_teardown( + curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + } +} + +/** + * hdd_tdls_notify_mode_change - Notify mode change + * @adapter: pointer to hdd adapter + * @hddCtx : pointer to hdd context + * + * Return: None + */ +void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter, hdd_context_t *hddctx) +{ + if (adapter->device_mode != WLAN_HDD_INFRA_STATION) + wlan_hdd_tdls_disable_offchan_and_teardown_links(hddctx); +} + + +/** + * wlan_hdd_tdls_pre_setup_init_work() - schedule work for tdls pre-setup + * @pHddTdlsCtx: HDD TDLS context + * @curr_candidate: current candidate peer + * + * Return: None + */ +void wlan_hdd_tdls_pre_setup_init_work(tdlsCtx_t *pHddTdlsCtx, + hddTdlsPeer_t *curr_candidate) +{ + if (!pHddTdlsCtx || !curr_candidate) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: either pHddTdlsCtx or curr_candidate is null", + __func__); + return; + } + + if (TDLS_CTX_MAGIC != pHddTdlsCtx->magic) { + /* When TDLS discovery attempt for a peer reaches to max configured + * threshold then tdls support for that peer would be disabled and + * in that case, ignore discovery trigger from FW for that peer. + */ + if (eTDLS_CAP_NOT_SUPPORTED == curr_candidate->tdls_support) { + hddLog(LOGW, + "%s: tdls_support is marked disabled for peer: " + MAC_ADDRESS_STR + ", ignore pre_setup_init_work", __func__, + MAC_ADDR_ARRAY(curr_candidate->peerMac)); + return; + } + + pHddTdlsCtx->curr_candidate = curr_candidate; + pHddTdlsCtx->magic = TDLS_CTX_MAGIC; + + schedule_work(&pHddTdlsCtx->implicit_setup); + } +} + +/** + * wlan_hdd_tdls_pre_setup_init_work() - get value of discovery counter sent + * @pHddCtx: HDD context + * + * Return: the value of the transmitted TDLS discovery counter + */ +static uint32_t wlan_hdd_tdls_discovery_sent_cnt(hdd_context_t *pHddCtx) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + CDF_STATUS status = 0; + uint32_t count = 0; + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + count = count + pHddTdlsCtx->discovery_sent_cnt; + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + return count; +} + +/** + * wlan_hdd_tdls_check_power_save_prohibited() - set/clear proper TDLS power + * save probihited bit + * @pAdapter: HDD adapter handle + * + * Ensure TDLS power save probihited bit is set/cleared properly + * + * Return: None + */ +static void wlan_hdd_tdls_check_power_save_prohibited(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if ((NULL == pHddTdlsCtx) || (NULL == pHddCtx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx or pHddTdlsCtx points to NULL")); + return; + } + + if ((0 == pHddCtx->connected_peer_count) && + (0 == wlan_hdd_tdls_discovery_sent_cnt(pHddCtx))) { + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX + (pHddTdlsCtx->pAdapter), + pAdapter->sessionId, 0); + return; + } + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX + (pHddTdlsCtx->pAdapter), + pAdapter->sessionId, 1); + return; +} + +/** + * wlan_hdd_tdls_free_scan_request() - free tdls scan request + * @tdls_scan_ctx: tdls scan context + * + * Return: None + */ +static void wlan_hdd_tdls_free_scan_request(tdls_scan_context_t *tdls_scan_ctx) +{ + if (NULL == tdls_scan_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("tdls_scan_ctx is NULL")); + return; + } + + tdls_scan_ctx->attempt = 0; + tdls_scan_ctx->reject = 0; + tdls_scan_ctx->magic = 0; + tdls_scan_ctx->scan_request = NULL; + return; +} + +/** + * wlan_hdd_tdls_discovery_timeout_peer_cb() - tdls discovery timeout callback + * @userData: tdls context + * + * Return: None + */ +static void wlan_hdd_tdls_discovery_timeout_peer_cb(void *userData) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + + pHddTdlsCtx = (tdlsCtx_t *) userData; + + if ((NULL == pHddTdlsCtx) || (NULL == pHddTdlsCtx->pAdapter)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx or pAdapter points to NULL")); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pHddTdlsCtx->pAdapter->magic) { + hddLog(LOGE, FL("pAdapter has invalid magic")); + return; + } + + pHddCtx = WLAN_HDD_GET_CTX(pHddTdlsCtx->pAdapter); + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + if (NULL == pHddCtx) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + if (eTDLS_LINK_DISCOVERING == tmp->link_status) { + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + " to idle state", __func__, + MAC_ADDR_ARRAY(tmp->peerMac)); + wlan_hdd_tdls_set_peer_link_status(tmp, + eTDLS_LINK_IDLE, + eTDLS_LINK_NOT_SUPPORTED); + mutex_lock(&pHddCtx->tdls_lock); + } + } + } + + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + mutex_unlock(&pHddCtx->tdls_lock); + + return; +} + +/** + * wlan_hdd_tdls_free_list() - free TDLS peer list + * @pHddTdlsCtx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_free_list(tdlsCtx_t *pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + if (NULL == pHddTdlsCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx is NULL")); + return; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + list_del(pos); + cdf_mem_free(tmp); + tmp = NULL; + } + } +} + +/** + * wlan_hdd_tdls_schedule_scan() - schedule scan for tdls + * @work: work_struct used to find tdls scan context + * + * Return: None + */ +static void wlan_hdd_tdls_schedule_scan(struct work_struct *work) +{ + tdls_scan_context_t *scan_ctx = + container_of(work, tdls_scan_context_t, tdls_scan_work.work); + + if (NULL == scan_ctx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("scan_ctx is NULL")); + return; + } + + if (unlikely(TDLS_CTX_MAGIC != scan_ctx->magic)) + return; + + scan_ctx->attempt++; + + wlan_hdd_cfg80211_scan(scan_ctx->wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + scan_ctx->dev, +#endif + scan_ctx->scan_request); +} + +/** + * dump_tdls_state_param_setting() - print tdls state & parameters to send to fw + * @info: tdls setting to be sent to fw + * + * Return: void + */ +static void dump_tdls_state_param_setting(tdlsInfo_t *info) +{ + if (!info) + return; + + hddLog(LOG1, + FL( + "Setting tdls state and param in fw: vdev_id: %d, tdls_state: %d, notification_interval_ms: %d, tx_discovery_threshold: %d, tx_teardown_threshold: %d, rssi_teardown_threshold: %d, rssi_delta: %d, tdls_options: 0x%x, peer_traffic_ind_window: %d, peer_traffic_response_timeout: %d, puapsd_mask: 0x%x, puapsd_inactivity_time: %d, puapsd_rx_frame_threshold: %d" + ), + info->vdev_id, + info->tdls_state, + info->notification_interval_ms, + info->tx_discovery_threshold, + info->tx_teardown_threshold, + info->rssi_teardown_threshold, + info->rssi_delta, + info->tdls_options, + info->peer_traffic_ind_window, + info->peer_traffic_response_timeout, + info->puapsd_mask, + info->puapsd_inactivity_time, + info->puapsd_rx_frame_threshold); +} + + +/** + * wlan_hdd_tdls_monitor_timers_stop() - stop all monitoring timers + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + cdf_mc_timer_stop(&hdd_tdls_ctx->peerDiscoveryTimeoutTimer); +} + +/** + * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +static void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + wlan_hdd_tdls_monitor_timers_stop(hdd_tdls_ctx); +} + +/** + * wlan_hdd_tdls_del_non_forced_peers() - delete non forced tdls peers + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +static void wlan_hdd_tdls_del_non_forced_peers(tdlsCtx_t *hdd_tdls_ctx) +{ + struct list_head *head, *pos, *q; + hddTdlsPeer_t *peer = NULL; + int i; + + /* remove entries from peer list only if peer is not forced */ + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each_safe(pos, q, head) { + peer = list_entry(pos, hddTdlsPeer_t, node); + if (false == peer->isForcedPeer) { + list_del(pos); + cdf_mem_free(peer); + } else { + peer->link_status = eTDLS_LINK_IDLE; + peer->reason = eTDLS_LINK_UNSPECIFIED; + peer->staId = 0; + peer->discovery_attempt = 0; + } + } + } +} + +/** + * wlan_hdd_tdls_init() - tdls initializaiton + * @pAdapter: hdd adapter + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx; + int i; + uint8_t staIdx; + tdlsInfo_t *tInfo; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (NULL == pHddCtx) + return -EINVAL; + + mutex_lock(&pHddCtx->tdls_lock); + + if (false == pHddCtx->config->fEnableTDLSSupport) { + pHddCtx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED; + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOGE, + FL("TDLS not enabled (%d) or FW doesn't support"), + pHddCtx->config->fEnableTDLSSupport); + return 0; + } + /* TDLS is supported only in STA / P2P Client modes, + * hence the check for TDLS support in a specific Device mode. + * Do not return a failure rather do not continue further + * with the initialization as tdls_init would be called + * during the open adapter for a p2p interface at which point + * the device mode would be a P2P_DEVICE. The point here is to + * continue initialization for STA / P2P Client modes. + * TDLS exit also check for the device mode for clean up hence + * there is no issue even if success is returned. + */ + if (0 == WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter)) { + mutex_unlock(&pHddCtx->tdls_lock); + return 0; + } + /* Check for the valid pHddTdlsCtx. If valid do not further + * allocate the memory, rather continue with the initialization. + * If tdls_initialization would get reinvoked without tdls_exit + * getting invoked (SSR) there is no point to further proceed + * with the memory allocations. + */ + if (NULL == pAdapter->sessionCtx.station.pHddTdlsCtx) { + pHddTdlsCtx = cdf_mem_malloc(sizeof(tdlsCtx_t)); + + if (NULL == pHddTdlsCtx) { + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOGE, FL("malloc failed!")); + return -ENOMEM; + } + /* initialize TDLS pAdater context */ + cdf_mem_zero(pHddTdlsCtx, sizeof(tdlsCtx_t)); + + cdf_mc_timer_init(&pHddTdlsCtx->peerDiscoveryTimeoutTimer, + CDF_TIMER_TYPE_SW, + wlan_hdd_tdls_discovery_timeout_peer_cb, + pHddTdlsCtx); + + pAdapter->sessionCtx.station.pHddTdlsCtx = pHddTdlsCtx; + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) + INIT_LIST_HEAD(&pHddTdlsCtx->peer_list[i]); + } else { + pHddTdlsCtx = pAdapter->sessionCtx.station.pHddTdlsCtx; + + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); + + wlan_hdd_tdls_del_non_forced_peers(pHddTdlsCtx); + + pHddCtx->connected_peer_count = 0; + } + + /* initialize TDLS global context */ + pHddCtx->connected_peer_count = 0; + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, 0); + + pHddCtx->tdls_scan_ctxt.magic = 0; + pHddCtx->tdls_scan_ctxt.attempt = 0; + pHddCtx->tdls_scan_ctxt.reject = 0; + pHddCtx->tdls_scan_ctxt.scan_request = NULL; + + if (pHddCtx->config->fEnableTDLSSleepSta || + pHddCtx->config->fEnableTDLSBufferSta || + pHddCtx->config->fEnableTDLSOffChannel) + pHddCtx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN; + else + pHddCtx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA; + + hddLog(LOG1, FL("max_num_tdls_sta: %d"), pHddCtx->max_num_tdls_sta); + + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; staIdx++) { + pHddCtx->tdlsConnInfo[staIdx].staId = 0; + pHddCtx->tdlsConnInfo[staIdx].sessionId = 255; + cdf_mem_zero(&pHddCtx->tdlsConnInfo[staIdx].peerMac, + CDF_MAC_ADDR_SIZE); + } + + pHddTdlsCtx->pAdapter = pAdapter; + + pHddTdlsCtx->curr_candidate = NULL; + pHddTdlsCtx->magic = 0; + + /* remember configuration even if it is not used right now. it could be used later */ + pHddTdlsCtx->threshold_config.tx_period_t = + pHddCtx->config->fTDLSTxStatsPeriod; + pHddTdlsCtx->threshold_config.tx_packet_n = + pHddCtx->config->fTDLSTxPacketThreshold; + pHddTdlsCtx->threshold_config.discovery_tries_n = + pHddCtx->config->fTDLSMaxDiscoveryAttempt; + pHddTdlsCtx->threshold_config.idle_packet_n = + pHddCtx->config->fTDLSIdlePacketThreshold; + pHddTdlsCtx->threshold_config.rssi_trigger_threshold = + pHddCtx->config->fTDLSRSSITriggerThreshold; + pHddTdlsCtx->threshold_config.rssi_teardown_threshold = + pHddCtx->config->fTDLSRSSITeardownThreshold; + pHddTdlsCtx->threshold_config.rssi_delta = + pHddCtx->config->fTDLSRSSIDelta; + + if (false == pHddCtx->config->fEnableTDLSImplicitTrigger) { + pHddCtx->tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY; + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s TDLS Implicit trigger not enabled!", __func__); + } else { + pHddCtx->tdls_mode = eTDLS_SUPPORT_ENABLED; + } + +#ifdef CONFIG_CNSS + cnss_init_work(&pHddTdlsCtx->implicit_setup, wlan_hdd_tdls_pre_setup); +#else + INIT_WORK(&pHddTdlsCtx->implicit_setup, wlan_hdd_tdls_pre_setup); +#endif + +#ifdef CONFIG_CNSS + cnss_init_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, + wlan_hdd_tdls_schedule_scan); +#else + INIT_DELAYED_WORK(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, + wlan_hdd_tdls_schedule_scan); +#endif + + /* + * Release tdls lock before calling in SME api + * which would try to acquire sme lock. + */ + mutex_unlock(&pHddCtx->tdls_lock); + tInfo = cdf_mem_malloc(sizeof(tdlsInfo_t)); + if (NULL == tInfo) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("cdf_mem_alloc failed for tInfo")); + cdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + cdf_mem_free(pHddTdlsCtx); + return -ENOMEM; + } + + tInfo->vdev_id = pAdapter->sessionId; + tInfo->tdls_state = pHddCtx->tdls_mode; + tInfo->notification_interval_ms = + pHddTdlsCtx->threshold_config.tx_period_t; + tInfo->tx_discovery_threshold = + pHddTdlsCtx->threshold_config.tx_packet_n; + tInfo->tx_teardown_threshold = + pHddTdlsCtx->threshold_config.idle_packet_n; + tInfo->rssi_teardown_threshold = + pHddTdlsCtx->threshold_config.rssi_teardown_threshold; + tInfo->rssi_delta = pHddTdlsCtx->threshold_config.rssi_delta; + tInfo->tdls_options = 0; + if (pHddCtx->config->fEnableTDLSOffChannel) + tInfo->tdls_options |= ENA_TDLS_OFFCHAN; + if (pHddCtx->config->fEnableTDLSBufferSta) + tInfo->tdls_options |= ENA_TDLS_BUFFER_STA; + if (pHddCtx->config->fEnableTDLSSleepSta) + tInfo->tdls_options |= ENA_TDLS_SLEEP_STA; + tInfo->peer_traffic_ind_window = pHddCtx->config->fTDLSPuapsdPTIWindow; + tInfo->peer_traffic_response_timeout = + pHddCtx->config->fTDLSPuapsdPTRTimeout; + tInfo->puapsd_mask = pHddCtx->config->fTDLSUapsdMask; + tInfo->puapsd_inactivity_time = + pHddCtx->config->fTDLSPuapsdInactivityTimer; + tInfo->puapsd_rx_frame_threshold = + pHddCtx->config->fTDLSRxFrameThreshold; + + dump_tdls_state_param_setting(tInfo); + + cdf_ret_status = sme_update_fw_tdls_state(pHddCtx->hHal, tInfo, true); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + cdf_mem_free(tInfo); + cdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + cdf_mem_free(pHddTdlsCtx); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_tdls_exit() - TDLS de-initialization + * @pAdapter: HDD adapter + * + * Return: None + */ +void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + tdlsInfo_t *tInfo; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is NULL")); + return; + } + + if (!test_bit(TDLS_INIT_DONE, &pAdapter->event_flags)) { + hddLog(LOGE, FL("TDLS init was not done, exit")); + return; + } + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + /* TDLS context can be null and might have been freed up during + * cleanup for STA adapter + */ + hddLog(LOG2, + FL("pHddTdlsCtx is NULL, adapter device mode: %s(%d)"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + goto done; + } + + cds_flush_work(&pHddTdlsCtx->implicit_setup); + cds_flush_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work); + + mutex_lock(&pHddCtx->tdls_lock); + + /* must stop timer here before freeing peer list, because peerIdleTimer is + part of peer list structure. */ + wlan_hdd_tdls_timers_destroy(pHddTdlsCtx); + wlan_hdd_tdls_free_list(pHddTdlsCtx); + + mutex_unlock(&pHddCtx->tdls_lock); + + wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt); + + /* No need to post message during driver unlaod because MC thread is + already shutdown */ + if (!pHddCtx->isUnloadInProgress) { + tInfo = cdf_mem_malloc(sizeof(tdlsInfo_t)); + if (NULL != tInfo) { + tInfo->vdev_id = pAdapter->sessionId; + tInfo->tdls_state = eTDLS_SUPPORT_DISABLED; + tInfo->notification_interval_ms = + pHddTdlsCtx->threshold_config.tx_period_t; + tInfo->tx_discovery_threshold = + pHddTdlsCtx->threshold_config.tx_packet_n; + tInfo->tx_teardown_threshold = + pHddTdlsCtx->threshold_config.idle_packet_n; + tInfo->rssi_teardown_threshold = + pHddTdlsCtx->threshold_config. + rssi_teardown_threshold; + tInfo->rssi_delta = + pHddTdlsCtx->threshold_config.rssi_delta; + tInfo->tdls_options = 0; + if (pHddCtx->config->fEnableTDLSOffChannel) + tInfo->tdls_options |= ENA_TDLS_OFFCHAN; + if (pHddCtx->config->fEnableTDLSBufferSta) + tInfo->tdls_options |= ENA_TDLS_BUFFER_STA; + if (pHddCtx->config->fEnableTDLSSleepSta) + tInfo->tdls_options |= ENA_TDLS_SLEEP_STA; + tInfo->peer_traffic_ind_window = + pHddCtx->config->fTDLSPuapsdPTIWindow; + tInfo->peer_traffic_response_timeout = + pHddCtx->config->fTDLSPuapsdPTRTimeout; + tInfo->puapsd_mask = pHddCtx->config->fTDLSUapsdMask; + tInfo->puapsd_inactivity_time = + pHddCtx->config->fTDLSPuapsdInactivityTimer; + tInfo->puapsd_rx_frame_threshold = + pHddCtx->config->fTDLSRxFrameThreshold; + + dump_tdls_state_param_setting(tInfo); + + cdf_ret_status = + sme_update_fw_tdls_state(pHddCtx->hHal, tInfo, false); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + cdf_mem_free(tInfo); + } + } else { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: cdf_mem_alloc failed for tInfo", __func__); + } + } + + pHddTdlsCtx->magic = 0; + pHddTdlsCtx->pAdapter = NULL; + + cdf_mem_free(pHddTdlsCtx); + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + pHddTdlsCtx = NULL; + +done: + clear_bit(TDLS_INIT_DONE, &pAdapter->event_flags); +} + +/** + * wlan_hdd_tdls_monitor_timers_destroy() - destroy all tdls monitoring timers + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_monitor_timers_destroy(tdlsCtx_t *pHddTdlsCtx) +{ + cdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + cdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); +} + +/** + * wlan_hdd_tdls_timers_destroy() - Destroy all the tdls timers running + * @pHddTdlsCtx: TDLS Context + * + * Return: Void + */ +static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx) +{ + wlan_hdd_tdls_monitor_timers_destroy(pHddTdlsCtx); +} + +/** + * wlan_hdd_tdls_get_peer() - find or add an peer given mac address + * @pAdapter: HDD adapter + * @mac: MAC address used to find or create peer + * + * Search peer given an MAC address and create one if not found. + * + * Return: Pointer to peer if mac address exist or peer creation + * succeeds; NULL if peer creation fails + */ +hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) +{ + struct list_head *head; + hddTdlsPeer_t *peer; + u8 key; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return NULL; + } + + /* if already there, just update */ + peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + if (peer != NULL) { + return peer; + } + + /* not found, allocate and add the list */ + peer = cdf_mem_malloc(sizeof(hddTdlsPeer_t)); + if (NULL == peer) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s peer malloc failed!", + __func__); + return NULL; + } + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + + if (NULL == pHddTdlsCtx) { + cdf_mem_free(peer); + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOG1, FL("pHddTdlsCtx is NULL")); + return NULL; + } + + key = wlan_hdd_tdls_hash_key(mac); + head = &pHddTdlsCtx->peer_list[key]; + + cdf_mem_zero(peer, sizeof(hddTdlsPeer_t)); + cdf_mem_copy(peer->peerMac, mac, sizeof(peer->peerMac)); + peer->pHddTdlsCtx = pHddTdlsCtx; + peer->pref_off_chan_num = pHddCtx->config->fTDLSPrefOffChanNum; + + list_add_tail(&peer->node, head); + mutex_unlock(&pHddCtx->tdls_lock); + + return peer; +} + +/** + * wlan_hdd_tdls_set_cap() - set TDLS capability type + * @pAdapter: HDD adapter + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, + tTDLSCapType cap) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->tdls_support = cap; + + return 0; +} + +/** + * wlan_hdd_tdls_set_peer_link_status() - set TDLS peer link status + * @curr_peer: peer + * @status: status + * @reason: reason + * + * Return: Void + */ +void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, + tTDLSLinkStatus status, + tTDLSLinkReason reason) +{ + int32_t state = 0; + int32_t res = 0; + hdd_context_t *pHddCtx; + if (curr_peer == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + return; + } + + if (curr_peer->pHddTdlsCtx == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("curr_peer->pHddTdlsCtx is NULL")); + return; + } + pHddCtx = WLAN_HDD_GET_CTX(curr_peer->pHddTdlsCtx->pAdapter); + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + hddLog(CDF_TRACE_LEVEL_WARN, + "tdls set peer " MAC_ADDRESS_STR " link status to %u", + MAC_ADDR_ARRAY(curr_peer->peerMac), status); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer->link_status = status; + + /* If TDLS link status is already passed the discovery state + * then clear discovery attempt count + */ + if (status >= eTDLS_LINK_DISCOVERED) { + curr_peer->discovery_attempt = 0; + } + + mutex_unlock(&pHddCtx->tdls_lock); + if (curr_peer->isForcedPeer && curr_peer->state_change_notification) { + curr_peer->reason = reason; + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res); + (*curr_peer->state_change_notification)(curr_peer->peerMac, + state, + res, + curr_peer-> + pHddTdlsCtx->pAdapter); + } + return; +} + +/** + * wlan_hdd_tdls_set_link_status() - set TDLS peer link status + * @pAdapter: HDD adapter + * @mac: mac address of TDLS peer + * @linkStatus: status + * @reason: reason + * + * Return: Void + */ +void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tTDLSLinkStatus linkStatus, + tTDLSLinkReason reason) +{ + int32_t state = 0; + int32_t res = 0; + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + if (curr_peer == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer->link_status = linkStatus; + + /* If TDLS link status is already passed the discovery state + * then clear discovery attempt count + */ + if (linkStatus >= eTDLS_LINK_DISCOVERED) { + curr_peer->discovery_attempt = 0; + } + mutex_unlock(&pHddCtx->tdls_lock); + if (curr_peer->isForcedPeer && curr_peer->state_change_notification) { + curr_peer->reason = reason; + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res); + (curr_peer->state_change_notification)(mac, + state, + res, + curr_peer->pHddTdlsCtx-> + pAdapter); + } + + return; +} + +/** + * wlan_hdd_tdls_recv_discovery_resp() - handling of tdls discovery response + * @pAdapter: HDD adapter + * @mac: mac address of peer from which the response was received + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, + const uint8_t *mac) +{ + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx; + + if (NULL == pHddTdlsCtx) { + hddLog(LOGE, FL("pHddTdlsCtx is NULL")); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pHddTdlsCtx->pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + hddLog(LOGE, FL("pHddCtx is not valid")); + return -EINVAL; + } + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (NULL == curr_peer) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + if (pHddTdlsCtx->discovery_sent_cnt) + pHddTdlsCtx->discovery_sent_cnt--; + + mutex_lock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + mutex_unlock(&pHddCtx->tdls_lock); + if (0 == pHddTdlsCtx->discovery_sent_cnt) { + cdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + } + + hddLog(LOG1, + "Discovery(%u) Response from " MAC_ADDRESS_STR + " link_status %d", pHddTdlsCtx->discovery_sent_cnt, + MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->link_status); + + if (eTDLS_LINK_DISCOVERING == curr_peer->link_status) { + /* Since we are here, it means Throughput threshold is alredy met. Make sure RSSI + threshold is also met before setting up TDLS link */ + if ((int32_t) curr_peer->rssi > + (int32_t) pHddTdlsCtx->threshold_config. + rssi_trigger_threshold) { + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERED, + eTDLS_LINK_SUCCESS); + hddLog(LOG1, + "Rssi Threshold met: " MAC_ADDRESS_STR + " rssi = %d threshold= %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->rssi, + pHddTdlsCtx->threshold_config. + rssi_trigger_threshold); + cfg80211_tdls_oper_request(pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_SETUP, false, + GFP_KERNEL); + } else { + hddLog(LOG1, + "Rssi Threshold not met: " MAC_ADDRESS_STR + " rssi = %d threshold = %d ", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->rssi, + pHddTdlsCtx->threshold_config. + rssi_trigger_threshold); + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + + /* if RSSI threshold is not met then allow further discovery + * attempts by decrementing count for the last attempt + */ + if (curr_peer->discovery_attempt) + curr_peer->discovery_attempt--; + } + } + + curr_peer->tdls_support = eTDLS_CAP_SUPPORTED; + return 0; +} + +/** + * wlan_hdd_tdls_set_peer_caps() - set TDLS peer capability + * @pAdapter: HDD adapter + * @mac: MAC address of the TDLS peer + * @StaParams: CSR Station Parameter + * @isBufSta: is peer buffer station + * @isOffChannelSupported: Is off channel supported + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrStaParams *StaParams, + bool isBufSta, bool isOffChannelSupported) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->uapsdQueues = StaParams->uapsd_queues; + curr_peer->maxSp = StaParams->max_sp; + curr_peer->isBufSta = isBufSta; + curr_peer->isOffChannelSupported = isOffChannelSupported; + + cdf_mem_copy(curr_peer->supported_channels, + StaParams->supported_channels, + StaParams->supported_channels_len); + + curr_peer->supported_channels_len = StaParams->supported_channels_len; + + cdf_mem_copy(curr_peer->supported_oper_classes, + StaParams->supported_oper_classes, + StaParams->supported_oper_classes_len); + + curr_peer->supported_oper_classes_len = + StaParams->supported_oper_classes_len; + return 0; +} + +/** + * wlan_hdd_tdls_get_link_establish_params() - get TDLS link establish + * parameter + * @pAdapter: HDD adapter + * @mac: mac address + * @tdlsLinkEstablishParams: output parameter to store the result + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, + const u8 *mac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + tdlsLinkEstablishParams->isResponder = curr_peer->is_responder; + tdlsLinkEstablishParams->uapsdQueues = curr_peer->uapsdQueues; + tdlsLinkEstablishParams->maxSp = curr_peer->maxSp; + tdlsLinkEstablishParams->isBufSta = curr_peer->isBufSta; + tdlsLinkEstablishParams->isOffChannelSupported = + curr_peer->isOffChannelSupported; + + cdf_mem_copy(tdlsLinkEstablishParams->supportedChannels, + curr_peer->supported_channels, + curr_peer->supported_channels_len); + + tdlsLinkEstablishParams->supportedChannelsLen = + curr_peer->supported_channels_len; + + cdf_mem_copy(tdlsLinkEstablishParams->supportedOperClasses, + curr_peer->supported_oper_classes, + curr_peer->supported_oper_classes_len); + + tdlsLinkEstablishParams->supportedOperClassesLen = + curr_peer->supported_oper_classes_len; + return 0; +} + +/** + * wlan_hdd_tdls_set_rssi() - Set TDLS RSSI on peer given by mac + * @pAdapter: HDD adapter + * @mac: MAC address of Peer + * @rxRssi: rssi value + * + * Set RSSI on TDSL peer + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, const uint8_t *mac, + int8_t rxRssi) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->rssi = rxRssi; + + return 0; +} + +/** + * wlan_hdd_tdls_set_responder() - Set/clear TDLS peer's responder role + * @pAdapter: HDD adapter + * @mac: MAC address of Peer + * @responder: flag that indicates if the TDLS peer should be responder or not + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t responder) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->is_responder = responder; + + return 0; +} + +/** + * wlan_hdd_tdls_set_signature() - Set TDLS peer's signature + * @pAdapter: HDD adapter + * @mac: MAC address of TDLS Peer + * @uSignature: signature value + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t uSignature) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->signature = uSignature; + + return 0; +} + +/** + * wlan_hdd_tdls_extract_da() - Extract destination address from socket buffer + * @skb: socket buffer + * @mac: output mac address buffer to store the destination address + * + * Return: Void + */ +void wlan_hdd_tdls_extract_da(struct sk_buff *skb, uint8_t *mac) +{ + memcpy(mac, skb->data, 6); +} + +/** + * wlan_hdd_tdls_extract_sa() - Extract source address from socket buffer + * @skb: socket buffer + * @mac: output mac address buffer to store the source address + * + * Return: Void + */ +void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, uint8_t *mac) +{ + memcpy(mac, skb->data + 6, 6); +} + +/** + * wlan_hdd_tdls_increment_pkt_count() - update statistics counter on tdls peer + * @pAdapter: HDD adapter + * @mac: MAC address of the TDLS peer + * @tx: If 1, increment tx packet counter, if 0, increment rx packet counter + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter, + const uint8_t *mac, uint8_t tx) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (eTDLS_SUPPORT_ENABLED != pHddCtx->tdls_mode) + return -EINVAL; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOG1, FL("curr_peer is NULL")); + return -EINVAL; + } + + if (tx) + curr_peer->tx_pkt++; + else + curr_peer->rx_pkt++; + + return 0; +} + +/** + * wlan_hdd_tdls_check_config() - validate tdls configuration parameters + * @config: tdls configuration parameter structure + * + * Return: 0 if all parameters are valid; -EINVAL otherwise + */ +static int wlan_hdd_tdls_check_config(tdls_config_params_t *config) +{ + if (config->tdls > 2) { + hddLog(LOGE, + FL("Invalid 1st argument %d. <0...2>"), + config->tdls); + return -EINVAL; + } + if (config->tx_period_t < CFG_TDLS_TX_STATS_PERIOD_MIN || + config->tx_period_t > CFG_TDLS_TX_STATS_PERIOD_MAX) { + hddLog(LOGE, + FL("Invalid 2nd argument %d. <%d...%ld>"), + config->tx_period_t, CFG_TDLS_TX_STATS_PERIOD_MIN, + CFG_TDLS_TX_STATS_PERIOD_MAX); + return -EINVAL; + } + if (config->tx_packet_n < CFG_TDLS_TX_PACKET_THRESHOLD_MIN || + config->tx_packet_n > CFG_TDLS_TX_PACKET_THRESHOLD_MAX) { + hddLog(LOGE, + FL("Invalid 3rd argument %d. <%d...%ld>"), + config->tx_packet_n, CFG_TDLS_TX_PACKET_THRESHOLD_MIN, + CFG_TDLS_TX_PACKET_THRESHOLD_MAX); + return -EINVAL; + } + if (config->discovery_tries_n < CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN || + config->discovery_tries_n > CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX) { + hddLog(LOGE, + FL("Invalid 5th argument %d. <%d...%d>"), + config->discovery_tries_n, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX); + return -EINVAL; + } + if (config->idle_packet_n < CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN || + config->idle_packet_n > CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX) { + hddLog(LOGE, + FL("Invalid 7th argument %d. <%d...%d>"), + config->idle_packet_n, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX); + return -EINVAL; + } + if (config->rssi_trigger_threshold < CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN + || config->rssi_trigger_threshold > + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX) { + hddLog(LOGE, + FL("Invalid 9th argument %d. <%d...%d>"), + config->rssi_trigger_threshold, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX); + return -EINVAL; + } + if (config->rssi_teardown_threshold < + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN + || config->rssi_teardown_threshold > + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX) { + hddLog(LOGE, + FL("Invalid 10th argument %d. <%d...%d>"), + config->rssi_teardown_threshold, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX); + return -EINVAL; + } + return 0; +} + +/** + * wlan_tdd_tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers + * @pHddTdlsCtx: TDLS context + * + * Caller has to take the TDLS lock before calling this function + * + * Return: Void + */ +static void wlan_tdd_tdls_reset_tx_rx(tdlsCtx_t *pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + tmp->tx_pkt = 0; + tmp->rx_pkt = 0; + } + } + + return; +} + +/** + * wlan_hdd_tdls_implicit_disable() - disable implicit tdls triggering + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_implicit_disable(tdlsCtx_t *pHddTdlsCtx) +{ + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); +} + +/** + * wlan_hdd_tdls_implicit_enable() - enable implicit tdls triggering + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx) +{ + wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_tdd_tdls_reset_tx_rx(pHddTdlsCtx); + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + +} + +/** + * wlan_hdd_tdls_set_mode() - set TDLS mode + * @pHddCtx: HDD context + * @tdls_mode: TDLS mode + * @bUpdateLast: Switch on if to set pHddCtx->tdls_mode_last to tdls_mode. + * If 1, set pHddCtx->tdls_mode_last to tdls_mode, otherwise + * set pHddCtx->tdls_mode_last to pHddCtx->tdls_mode + * + * Return: Void + */ +void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, + eTDLSSupportMode tdls_mode, bool bUpdateLast) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + CDF_STATUS status; + hdd_adapter_t *pAdapter; + tdlsCtx_t *pHddTdlsCtx; + + hddLog(LOG1, "%s mode %d", __func__, (int)tdls_mode); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + if (pHddCtx->tdls_mode == tdls_mode) { + mutex_unlock(&pHddCtx->tdls_lock); + hddLog(LOG1, FL("already in mode %d"), (int)tdls_mode); + return; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + if (eTDLS_SUPPORT_ENABLED == tdls_mode) + wlan_hdd_tdls_implicit_enable(pHddTdlsCtx); + else if ((eTDLS_SUPPORT_DISABLED == tdls_mode) || + (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == + tdls_mode)) + wlan_hdd_tdls_implicit_disable(pHddTdlsCtx); + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + if (bUpdateLast) { + pHddCtx->tdls_mode_last = tdls_mode; + } else { + pHddCtx->tdls_mode_last = pHddCtx->tdls_mode; + } + pHddCtx->tdls_mode = tdls_mode; + + mutex_unlock(&pHddCtx->tdls_lock); +} + +/** + * wlan_hdd_tdls_set_params() - set TDLS parameters + * @dev: net device + * @config: TDLS configuration parameters + * + * Return: 0 if success or negative errno otherwise + */ +int wlan_hdd_tdls_set_params(struct net_device *dev, + tdls_config_params_t *config) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + eTDLSSupportMode req_tdls_mode; + tdlsInfo_t *tdlsParams; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (NULL == pHddTdlsCtx) { + hddLog(LOGE, FL("TDLS not enabled!")); + return -EINVAL; + } + + if (wlan_hdd_tdls_check_config(config) != 0) { + return -EINVAL; + } + + /* config->tdls is mapped to 0->1, 1->2, 2->3 */ + req_tdls_mode = config->tdls + 1; + if (pHddCtx->tdls_mode == req_tdls_mode) { + hddLog(LOGE, FL("Already in mode %d"), config->tdls); + return -EINVAL; + } + + /* copy the configuration only when given tdls mode is implicit trigger enable */ + if (eTDLS_SUPPORT_ENABLED == req_tdls_mode) { + memcpy(&pHddTdlsCtx->threshold_config, config, + sizeof(tdls_config_params_t)); + } + + hddLog(LOGE, + FL("iw set tdls params: %d %d %d %d %d %d %d"), + config->tdls, + config->tx_period_t, + config->tx_packet_n, + config->discovery_tries_n, + config->idle_packet_n, + config->rssi_trigger_threshold, + config->rssi_teardown_threshold); + + wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, true); + + tdlsParams = cdf_mem_malloc(sizeof(tdlsInfo_t)); + if (NULL == tdlsParams) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: cdf_mem_alloc failed for tdlsParams", __func__); + return -ENOMEM; + } + + tdlsParams->vdev_id = pAdapter->sessionId; + tdlsParams->tdls_state = config->tdls; + tdlsParams->notification_interval_ms = config->tx_period_t; + tdlsParams->tx_discovery_threshold = config->tx_packet_n; + tdlsParams->tx_teardown_threshold = config->idle_packet_n; + tdlsParams->rssi_teardown_threshold = config->rssi_teardown_threshold; + tdlsParams->rssi_delta = config->rssi_delta; + tdlsParams->tdls_options = 0; + if (pHddCtx->config->fEnableTDLSOffChannel) + tdlsParams->tdls_options |= ENA_TDLS_OFFCHAN; + if (pHddCtx->config->fEnableTDLSBufferSta) + tdlsParams->tdls_options |= ENA_TDLS_BUFFER_STA; + if (pHddCtx->config->fEnableTDLSSleepSta) + tdlsParams->tdls_options |= ENA_TDLS_SLEEP_STA; + tdlsParams->peer_traffic_ind_window = + pHddCtx->config->fTDLSPuapsdPTIWindow; + tdlsParams->peer_traffic_response_timeout = + pHddCtx->config->fTDLSPuapsdPTRTimeout; + tdlsParams->puapsd_mask = pHddCtx->config->fTDLSUapsdMask; + tdlsParams->puapsd_inactivity_time = + pHddCtx->config->fTDLSPuapsdInactivityTimer; + tdlsParams->puapsd_rx_frame_threshold = + pHddCtx->config->fTDLSRxFrameThreshold; + + hddLog(LOG1, + "%s: Setting tdls state and param in fw: " + "vdev_id: %d, " + "tdls_state: %d, " + "notification_interval_ms: %d, " + "tx_discovery_threshold: %d, " + "tx_teardown_threshold: %d, " + "rssi_teardown_threshold: %d, " + "rssi_delta: %d, " + "tdls_options: 0x%x, " + "peer_traffic_ind_window: %d, " + "peer_traffic_response_timeout: %d, " + "puapsd_mask: 0x%x, " + "puapsd_inactivity_time: %d, " + "puapsd_rx_frame_threshold: %d ", + __func__, + tdlsParams->vdev_id, + tdlsParams->tdls_state, + tdlsParams->notification_interval_ms, + tdlsParams->tx_discovery_threshold, + tdlsParams->tx_teardown_threshold, + tdlsParams->rssi_teardown_threshold, + tdlsParams->rssi_delta, + tdlsParams->tdls_options, + tdlsParams->peer_traffic_ind_window, + tdlsParams->peer_traffic_response_timeout, + tdlsParams->puapsd_mask, + tdlsParams->puapsd_inactivity_time, + tdlsParams->puapsd_rx_frame_threshold); + + cdf_ret_status = sme_update_fw_tdls_state(pHddCtx->hHal, tdlsParams, true); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + cdf_mem_free(tdlsParams); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_update_tdls_info - update tdls status info + * @adapter: ptr to device adapter. + * @tdls_prohibited: indicates whether tdls is prohibited. + * @tdls_chan_swit_prohibited: indicates whether tdls channel switch + * is prohibited. + * + * Normally an AP does not influence TDLS connection between STAs + * associated to it. But AP may set bits for TDLS Prohibited or + * TDLS Channel Switch Prohibited in Extended Capability IE in + * Assoc/Re-assoc response to STA. So after STA is connected to + * an AP, call this function to update TDLS status as per those + * bits set in Ext Cap IE in received Assoc/Re-assoc response + * from AP. + * + * Return: None. + */ +void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited, + bool tdls_chan_swit_prohibited) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tdlsCtx_t *hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + tdlsInfo_t *tdls_param; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (!hdd_tdls_ctx) { + /* may be TDLS is not applicable for this adapter */ + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD TDLS context is null")); + return; + } + + /* If TDLS support is disabled then no need to update target */ + if (false == hdd_ctx->config->fEnableTDLSSupport) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("TDLS not enabled")); + return; + } + + /* If AP indicated TDLS Prohibited then disable tdls mode */ + mutex_lock(&hdd_ctx->tdls_lock); + if (tdls_prohibited) { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED; + } else { + if (false == hdd_ctx->config->fEnableTDLSImplicitTrigger) { + hdd_ctx->tdls_mode = + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY; + } else { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED; + } + } + mutex_unlock(&hdd_ctx->tdls_lock); + + tdls_param = cdf_mem_malloc(sizeof(*tdls_param)); + if (!tdls_param) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("memory allocation failed for tdlsParams")); + return; + } + + tdls_param->vdev_id = adapter->sessionId; + tdls_param->tdls_state = hdd_ctx->tdls_mode; + tdls_param->notification_interval_ms = + hdd_tdls_ctx->threshold_config.tx_period_t; + tdls_param->tx_discovery_threshold = + hdd_tdls_ctx->threshold_config.tx_packet_n; + tdls_param->tx_teardown_threshold = + hdd_tdls_ctx->threshold_config.idle_packet_n; + tdls_param->rssi_teardown_threshold = + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold; + tdls_param->rssi_delta = hdd_tdls_ctx->threshold_config.rssi_delta; + + tdls_param->tdls_options = 0; + + /* Do not enable TDLS offchannel, if AP prohibited TDLS channel switch */ + if ((hdd_ctx->config->fEnableTDLSOffChannel) && + (!tdls_chan_swit_prohibited)) { + tdls_param->tdls_options |= ENA_TDLS_OFFCHAN; + } + + if (hdd_ctx->config->fEnableTDLSBufferSta) + tdls_param->tdls_options |= ENA_TDLS_BUFFER_STA; + + if (hdd_ctx->config->fEnableTDLSSleepSta) + tdls_param->tdls_options |= ENA_TDLS_SLEEP_STA; + + tdls_param->peer_traffic_ind_window = + hdd_ctx->config->fTDLSPuapsdPTIWindow; + tdls_param->peer_traffic_response_timeout = + hdd_ctx->config->fTDLSPuapsdPTRTimeout; + tdls_param->puapsd_mask = + hdd_ctx->config->fTDLSUapsdMask; + tdls_param->puapsd_inactivity_time = + hdd_ctx->config->fTDLSPuapsdInactivityTimer; + tdls_param->puapsd_rx_frame_threshold = + hdd_ctx->config->fTDLSRxFrameThreshold; + + hddLog(CDF_TRACE_LEVEL_DEBUG, + FL("Setting tdls state and param in fw: " + "vdev_id: %d, " + "tdls_state: %d, " + "notification_interval_ms: %d, " + "tx_discovery_threshold: %d, " + "tx_teardown_threshold: %d, " + "rssi_teardown_threshold: %d, " + "rssi_delta: %d, " + "tdls_options: 0x%x, " + "peer_traffic_ind_window: %d, " + "peer_traffic_response_timeout: %d, " + "puapsd_mask: 0x%x, " + "puapsd_inactivity_time: %d, " + "puapsd_rx_frame_threshold: %d "), + tdls_param->vdev_id, + tdls_param->tdls_state, + tdls_param->notification_interval_ms, + tdls_param->tx_discovery_threshold, + tdls_param->tx_teardown_threshold, + tdls_param->rssi_teardown_threshold, + tdls_param->rssi_delta, + tdls_param->tdls_options, + tdls_param->peer_traffic_ind_window, + tdls_param->peer_traffic_response_timeout, + tdls_param->puapsd_mask, + tdls_param->puapsd_inactivity_time, + tdls_param->puapsd_rx_frame_threshold); + + cdf_ret_status = sme_update_fw_tdls_state(hdd_ctx->hHal, + tdls_param, + true); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + cdf_mem_free(tdls_param); + return; + } + return; +} + +/** + * wlan_hdd_tdls_set_sta_id() - set station ID on a tdls peer + * @pAdapter: HDD adapter + * @mac: MAC address of a tdls peer + * @staId: station ID + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t staId) +{ + hddTdlsPeer_t *curr_peer; + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + curr_peer->staId = staId; + + return 0; +} + +/** + * wlan_hdd_tdls_set_extctrl_param() - set external control parameter on a peer + * @pAdapter: HDD adapter + * @mac: MAC address of the peer + * @chan: Channel + * @max_latency: Maximum latency + * @op_class: Operation class + * @min_bandwidth: Minimal bandwidth + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_set_extctrl_param(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint32_t chan, uint32_t max_latency, + uint32_t op_class, uint32_t min_bandwidth) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) + return -EINVAL; + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, false); + if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); + return -EINVAL; + } + curr_peer->op_class_for_pref_off_chan = (uint8_t) op_class; + curr_peer->pref_off_chan_num = (uint8_t) chan; + + if (curr_peer->op_class_for_pref_off_chan) + curr_peer->op_class_for_pref_off_chan_is_set = 1; + else + curr_peer->op_class_for_pref_off_chan_is_set = 0; + + mutex_unlock(&pHddCtx->tdls_lock); + return 0; +} + +/** + * wlan_hdd_tdls_set_force_peer() - set/clear isForcedPeer flag on a peer + * @pAdapter: HDD adapter + * @mac: MAC address of the tdls peer + * @forcePeer: value used to set isForcedPeer flag on the peer + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, const uint8_t *mac, + bool forcePeer) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (!pHddCtx) + return -EINVAL; + + mutex_lock(&pHddCtx->tdls_lock); + + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, false); + if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); + return -EINVAL; + } + + curr_peer->isForcedPeer = forcePeer; + mutex_unlock(&pHddCtx->tdls_lock); + return 0; +} + +/** + * wlan_hdd_tdls_find_peer() - find TDLS peer given its MAC address + * @pAdapter: HDD adapter + * @mac: MAC address of peer + * @mutexLock: Option to indicate if mutex locking is required for searching + * + * Return: If peerMac is found, then it returns pointer to hddTdlsPeer_t; + * otherwise, it returns NULL + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac, bool mutexLock) +{ + uint8_t key; + struct list_head *pos; + struct list_head *head; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return NULL; + } + + if (mutexLock) { + mutex_lock(&pHddCtx->tdls_lock); + } + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + if (mutexLock) + mutex_unlock(&pHddCtx->tdls_lock); + return NULL; + } + + key = wlan_hdd_tdls_hash_key(mac); + + head = &pHddTdlsCtx->peer_list[key]; + + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (!memcmp(mac, curr_peer->peerMac, 6)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "findTdlsPeer: found staId %d", + curr_peer->staId); + if (mutexLock) + mutex_unlock(&pHddCtx->tdls_lock); + return curr_peer; + } + } + if (mutexLock) + mutex_unlock(&pHddCtx->tdls_lock); + return NULL; +} + +/** + * wlan_hdd_tdls_find_all_peer() - find all peers matching the input MAC + * @pHddCtx: HDD context + * @mac: MAC address + * + * Return: TDLS peer if a matching is detected; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, + const u8 *mac) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + hddTdlsPeer_t *curr_peer = NULL; + CDF_STATUS status = 0; + + mutex_lock(&pHddCtx->tdls_lock); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, mac, false); + if (curr_peer) { + mutex_unlock(&pHddCtx->tdls_lock); + return curr_peer; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + mutex_unlock(&pHddCtx->tdls_lock); + return curr_peer; +} + +/** + * wlan_hdd_tdls_reset_peer() - reset TDLS peer identified by MAC address + * @pAdapter: HDD adapter + * @mac: MAC address of the peer + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac) +{ + hdd_context_t *pHddCtx; + hddTdlsPeer_t *curr_peer; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hddLog(LOGE, FL("curr_peer is NULL")); + return -EINVAL; + } + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + curr_peer->staId = 0; + + return 0; +} + +/** + * wlan_hdd_tdls_peer_reset_discovery_processed() - reset discovery status + * @pHddTdlsCtx: TDLS context + * + * This function resets discovery processing bit for all TDLS peers + * + * Caller has to take the lock before calling this function + * + * Return: 0 + */ +static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t * + pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + pHddTdlsCtx->discovery_peer_cnt = 0; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + tmp->discovery_processed = 0; + } + } + + return 0; +} + +/** + * wlan_hdd_tdls_connected_peers() - Find the number of connected TDLS peers + * @pAdapter: HDD adapter + * + * Return: The number of connected TDLS peers or 0 if error is detected + */ +uint16_t wlan_hdd_tdls_connected_peers(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return 0; + } + + return pHddCtx->connected_peer_count; +} + +/** + * wlan_hdd_tdls_get_all_peers() - dump all TDLS peer info into output string + * @pAdapter: HDD adapter + * @buf: output string buffer to hold the peer info + * @buflen: the size of output string buffer + * + * Return: The size (in bytes) of the valid peer info in the output buffer + */ +int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, int buflen) +{ + int i; + int len, init_len; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return 0; + } + + init_len = buflen; + len = scnprintf(buf, buflen, "\n%-18s%-3s%-4s%-3s%-5s\n", + "MAC", "Id", "cap", "up", "RSSI"); + buf += len; + buflen -= len; + /* 1234567890123456789012345678901234567 */ + len = scnprintf(buf, buflen, "---------------------------------\n"); + buf += len; + buflen -= len; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + len = scnprintf(buf, buflen, "TDLS not enabled\n"); + return len; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + + if (buflen < 32 + 1) + break; + len = scnprintf(buf, buflen, + MAC_ADDRESS_STR "%3d%4s%3s%5d\n", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->staId, + (curr_peer->tdls_support == + eTDLS_CAP_SUPPORTED) ? "Y" : "N", + TDLS_IS_CONNECTED(curr_peer) ? "Y" : + "N", curr_peer->rssi); + buf += len; + buflen -= len; + } + } + mutex_unlock(&pHddCtx->tdls_lock); + return init_len - buflen; +} + +/** + * wlan_hdd_tdls_connection_callback() - callback after tdls connection + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if ((NULL == pHddCtx) || (NULL == pHddTdlsCtx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx or pHddTdlsCtx points to NULL")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + hddLog(LOG1, + FL("update %d"), + pHddTdlsCtx->threshold_config.tx_period_t); + + if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) { + wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx-> + pAdapter); + + } + mutex_unlock(&pHddCtx->tdls_lock); + +} + +/** + * wlan_hdd_tdls_disconnection_callback() - callback after tdls disconnection + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if ((NULL == pHddCtx) || (NULL == pHddTdlsCtx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx or pHddTdlsCtx points to NULL")); + return; + } + + hddLog(LOG1, "%s", __func__); + + mutex_lock(&pHddCtx->tdls_lock); + + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx is NULL")); + return; + } + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + wlan_hdd_tdls_monitor_timers_stop(pHddTdlsCtx); + wlan_hdd_tdls_free_list(pHddTdlsCtx); + + pHddTdlsCtx->curr_candidate = NULL; + + mutex_unlock(&pHddCtx->tdls_lock); +} + +/** + * wlan_hdd_tdls_mgmt_completion_callback() - callback for TDLS management + * TX completion + * @pAdapter: HDD adapter + * @statusCode: management TX completion status + * + * Return: Void + */ +void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter, + uint32_t statusCode) +{ + pAdapter->mgmtTxCompletionStatus = statusCode; + hddLog(LOG1, + "%s: Mgmt TX Completion %d", __func__, statusCode); + complete(&pAdapter->tdls_mgmt_comp); +} + +/** + * wlan_hdd_tdls_increment_peer_count() - increment connected TDLS peer counter + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_increment_peer_count(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + pHddCtx->connected_peer_count++; + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + hddLog(LOG1, "%s: %d", + __func__, pHddCtx->connected_peer_count); + + mutex_unlock(&pHddCtx->tdls_lock); +} + +/** + * wlan_hdd_tdls_decrement_peer_count() - decrement connected TDLS peer counter + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + if (pHddCtx->connected_peer_count) + pHddCtx->connected_peer_count--; + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + hddLog(LOG1, "%s: %d", + __func__, pHddCtx->connected_peer_count); + + mutex_unlock(&pHddCtx->tdls_lock); + +} + + +/** + * wlan_hdd_tdls_find_progress_peer() - find peer if TDLS is ongoing + * @pAdapter: HDD adapter + * @mac: If NULL check for all the peer list, otherwise, skip this mac when + * skip_self is true + * @skip_self: If true, skip this mac. otherwise, check all the peer list. if + * mac is NULL, this argument is ignored, and check for all the peer + * list. + * + * Return: Pointer to hddTdlsPeer_t if TDLS is ongoing. Otherwise return NULL. + */ +static hddTdlsPeer_t *wlan_hdd_tdls_find_progress_peer(hdd_adapter_t *pAdapter, + const u8 *mac, + u8 skip_self) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *curr_peer; + struct list_head *pos; + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);; + + if (NULL == pHddTdlsCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx is NULL")); + return NULL; + } + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (skip_self && mac + && !memcmp(mac, curr_peer->peerMac, 6)) { + continue; + } else { + if (eTDLS_LINK_CONNECTING == + curr_peer->link_status) { + hddLog(LOG1, + "%s:" MAC_ADDRESS_STR + " eTDLS_LINK_CONNECTING", + __func__, + MAC_ADDR_ARRAY(curr_peer-> + peerMac)); + return curr_peer; + } + } + } + } + return NULL; +} + +/** + * wlan_hdd_tdls_is_progress() - find the peer with ongoing TDLS progress + * @pHddCtx: HDD context + * @mac: mac address of the peer + * @skip_self: if 1, skip checking self. If 0, search includes self + * + * Return: TDLS peer if found; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, + const uint8_t *mac, uint8_t skip_self) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + hddTdlsPeer_t *curr_peer = NULL; + CDF_STATUS status = 0; + + mutex_lock(&pHddCtx->tdls_lock); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + curr_peer = + wlan_hdd_tdls_find_progress_peer(pAdapter, mac, + skip_self); + if (curr_peer) { + mutex_unlock(&pHddCtx->tdls_lock); + return curr_peer; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + mutex_unlock(&pHddCtx->tdls_lock); + return NULL; +} + +/** + * __wlan_hdd_tdls_pre_setup() - TDLS Pre implicit setup + * @work: work_struct used to find the TDLS context + * + * Return: Void + */ +static void __wlan_hdd_tdls_pre_setup(struct work_struct *work) +{ + tdlsCtx_t *pHddTdlsCtx = container_of(work, tdlsCtx_t, implicit_setup); + hdd_context_t *pHddCtx; + hddTdlsPeer_t *curr_peer; + hddTdlsPeer_t *temp_peer; + int status; + tSirMacAddr peer_mac; + + if (NULL == pHddTdlsCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx is NULL")); + return; + } + + if (unlikely(TDLS_CTX_MAGIC != pHddTdlsCtx->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: tdls magic number mis-match %u", + __func__, pHddTdlsCtx->magic); + return; + } + + pHddCtx = WLAN_HDD_GET_CTX(pHddTdlsCtx->pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + curr_peer = pHddTdlsCtx->curr_candidate; + + if (NULL == curr_peer) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + goto done; + } + + cdf_mem_copy(&peer_mac, curr_peer->peerMac, sizeof(peer_mac)); + + mutex_unlock(&pHddCtx->tdls_lock); + + temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0); + + if (NULL != temp_peer) { + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR " ongoing. pre_setup ignored", + __func__, MAC_ADDR_ARRAY(temp_peer->peerMac)); + goto done; + } + + if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support) + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_SUCCESS); + + mutex_lock(&pHddCtx->tdls_lock); + + /* Ignore discovery attempt if External Control is enabled, that + * is, peer is forced. In that case, continue discovery attempt + * regardless attempt count + */ + if (false == curr_peer->isForcedPeer) { + if (curr_peer->discovery_attempt >= + pHddTdlsCtx->threshold_config.discovery_tries_n) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: discovery attempt (%d) reached max (%d) for peer " + MAC_ADDRESS_STR + ", ignore discovery trigger from fw", + __func__, curr_peer->discovery_attempt, + pHddTdlsCtx->threshold_config. + discovery_tries_n, + MAC_ADDR_ARRAY(curr_peer->peerMac)); + curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED; + goto done; + } + } + + mutex_unlock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_SUCCESS); + + status = + wlan_hdd_cfg80211_send_tdls_discover_req(pHddTdlsCtx->pAdapter-> + wdev.wiphy, + pHddTdlsCtx->pAdapter->dev, + peer_mac); + + mutex_lock(&pHddCtx->tdls_lock); + + if (NULL == pHddTdlsCtx->curr_candidate) { + hddLog(LOGE, + "%s: current candidate Not valid any more", __func__); + goto done; + } + + curr_peer = pHddTdlsCtx->curr_candidate; + + if (0 != status) { + hddLog(LOGE, + "%s: " MAC_ADDRESS_STR " discovery could not sent", + __func__, MAC_ADDR_ARRAY(curr_peer->peerMac)); + if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support) { + mutex_unlock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + mutex_lock(&pHddCtx->tdls_lock); + } + goto done; + } + + pHddTdlsCtx->discovery_sent_cnt++; + + curr_peer->discovery_attempt++; + + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + hddLog(LOG1, + "%s: discovery count %u timeout %u msec", __func__, + pHddTdlsCtx->discovery_sent_cnt, + pHddTdlsCtx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); + + wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter, + &pHddTdlsCtx->peerDiscoveryTimeoutTimer, + pHddTdlsCtx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); + +done: + pHddTdlsCtx->curr_candidate = NULL; + pHddTdlsCtx->magic = 0; + mutex_unlock(&pHddCtx->tdls_lock); + return; +} + +/** + * wlan_hdd_tdls_pre_setup() - TDLS Pre implicit setup + * @work: work_struct used to find the TDLS context + * + * Return: Void + */ +void wlan_hdd_tdls_pre_setup(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __wlan_hdd_tdls_pre_setup(work); + cds_ssr_unprotect(__func__); +} + +/** + * wlan_hdd_tdls_copy_scan_context() - Copy TDLS scan context + * @pHddCtx: HDD context + * @wiphy: wiphy pointer + * @dev: net device + * request: source scan context + * + * Copy the source scan context into the HDD context's TDLS scan context + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request) +{ + tdls_scan_context_t *scan_ctx; + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + hddLog(LOGE, FL("pHddCtx is not valid")); + return -EINVAL; + } + + scan_ctx = &pHddCtx->tdls_scan_ctxt; + + scan_ctx->wiphy = wiphy; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + scan_ctx->dev = dev; +#endif + + scan_ctx->scan_request = request; + return 0; +} + +/** + * wlan_hdd_tdls_scan_init_work() - schedule tdls scan work + * @pHddCtx: HDD context + * @wiphy: wiphy pointer + * @dev: net device + * @request: scan request + * @delay: delay value to pass to the work scheduling + * + * Return: Void + */ +static void wlan_hdd_tdls_scan_init_work(hdd_context_t *pHddCtx, + struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request, + unsigned long delay) +{ + if (TDLS_CTX_MAGIC != pHddCtx->tdls_scan_ctxt.magic) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, dev, request); +#else + wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, request); +#endif + pHddCtx->tdls_scan_ctxt.attempt = 0; + pHddCtx->tdls_scan_ctxt.magic = TDLS_CTX_MAGIC; + } + schedule_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, delay); +} + +/** + * wlan_hdd_tdls_scan_callback() - callback for TDLS scan operation + * @pAdapter: HDD adapter + * @wiphy: wiphy + * @dev: net device + * @request: scan request + * + * Return: negative = caller should stop and return error code immediately + * 0 = caller should stop and return success immediately + * 1 = caller can continue to scan + */ +int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + struct net_device *dev, +#endif + struct cfg80211_scan_request *request) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + u16 connectedTdlsPeers; + hddTdlsPeer_t *curr_peer; + unsigned long delay; + int ret; + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + /* if tdls is not enabled, then continue scan */ + if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) + return 1; + + curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0); + if (NULL != curr_peer) { + if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) { + pHddCtx->tdls_scan_ctxt.reject = 0; + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + ". scan rejected %d. force it to idle", + __func__, MAC_ADDR_ARRAY(curr_peer->peerMac), + pHddCtx->tdls_scan_ctxt.reject); + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + return 1; + } + hddLog(LOGW, + "%s: tdls in progress. scan rejected %d", + __func__, pHddCtx->tdls_scan_ctxt.reject); + return -EBUSY; + } + + /* tdls teardown is ongoing */ + if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) { + connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (connectedTdlsPeers + && (pHddCtx->tdls_scan_ctxt.attempt < + TDLS_MAX_SCAN_SCHEDULE)) { + delay = + (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION * + connectedTdlsPeers); + hddLog(LOG1, + "%s: tdls disabled, but still connected_peers %d attempt %d. schedule scan %lu msec", + __func__, connectedTdlsPeers, + pHddCtx->tdls_scan_ctxt.attempt, delay); + + wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + dev, +#endif + request, + msecs_to_jiffies(delay)); + /* scan should not continue */ + return 0; + } + /* no connected peer or max retry reached, scan continue */ + hddLog(LOG1, + "%s: tdls disabled. connected_peers %d attempt %d. scan allowed", + __func__, connectedTdlsPeers, + pHddCtx->tdls_scan_ctxt.attempt); + return 1; + } + /* while tdls is up, first time scan */ + else if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) { + /* disable implicit trigger logic & tdls operatoin */ + wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, false); + /* indicate the teardown all connected to peer */ + connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (connectedTdlsPeers) { + uint8_t staIdx; + uint8_t num = 0; + uint8_t i; + bool allPeersBufStas = 1; + hddTdlsPeer_t *curr_peer; + hddTdlsPeer_t *connectedPeerList[HDD_MAX_NUM_TDLS_STA]; + + /* If TDLSScan is enabled then allow scan and + * maintain tdls link regardless if peer is buffer + * sta capable or not and if device is sleep sta + * capable or not. If peer is not buffer sta + * capable, then Tx would stop when device + * initiates scan and there will be loss of Rx + * packets since peer would not know when device + * moves away from the tdls channel. + */ + if (1 == pHddCtx->config->enable_tdls_scan) { + hddLog(LOG1, FL( + "TDLSScan enabled, keep tdls link and allow scan, connectedTdlsPeers: %d"), + connectedTdlsPeers); + return 1; + } + + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if (pHddCtx->tdlsConnInfo[staIdx].staId) { + curr_peer = + wlan_hdd_tdls_find_all_peer(pHddCtx, + pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes); + if (curr_peer) { + connectedPeerList[num++] = + curr_peer; + if (!(curr_peer->isBufSta)) + allPeersBufStas = 0; + } + } + } + + if ((TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN == + connectedTdlsPeers) && + (pHddCtx->config->fEnableTDLSSleepSta) && + (allPeersBufStas)) { + /* All connected peers bufStas and we can be sleepSta + * so allow scan + */ + hddLog(LOG1, + "%s: All peers (num %d) bufSTAs, we can be sleep sta, so allow scan, tdls mode changed to %d", + __func__, connectedTdlsPeers, + pHddCtx->tdls_mode); + return 1; + } else { + for (i = 0; i < num; i++) { + hddLog(LOG1, + "%s: indicate TDLS teadown (staId %d)", + __func__, + connectedPeerList[i]->staId); + + wlan_hdd_tdls_indicate_teardown + (connectedPeerList[i]->pHddTdlsCtx-> + pAdapter, connectedPeerList[i], + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + } + } + /* schedule scan */ + delay = + (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION * + connectedTdlsPeers); + + hddLog(LOG1, + "%s: tdls enabled (mode %d), connected_peers %d. schedule scan %lu msec", + __func__, pHddCtx->tdls_mode, + wlan_hdd_tdls_connected_peers(pAdapter), delay); + + wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) + dev, +#endif + request, + msecs_to_jiffies(delay)); + /* scan should not continue */ + return 0; + } + /* no connected peer, scan continue */ + hddLog(LOG1, + "%s: tdls_mode %d, and no tdls connection. scan allowed", + __func__, pHddCtx->tdls_mode); + } + return 1; +} + +/** + * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("pHddCtx is not valid")); + return; + } + + /* free allocated memory at scan time */ + wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt); + + /* if tdls was enabled before scan, re-enable tdls mode */ + if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode_last || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode_last) { + hddLog(LOG1, + ("%s: revert tdls mode %d"), __func__, + pHddCtx->tdls_mode_last); + + wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, false); + } +} + +/** + * wlan_hdd_tdls_timer_restart() - restart TDLS timer + * @pAdapter: HDD adapter + * @timer: timer to restart + * @expirationTime: new expiration time to set for the timer + * + * Return: Void + */ +void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter, + cdf_mc_timer_t *timer, + uint32_t expirationTime) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Check whether driver load unload is in progress */ + if (cds_is_load_unload_in_progress()) { + hddLog(LOGE, FL("Driver load/unload is in progress.")); + return; + } + + if (hdd_conn_is_connected(pHddStaCtx)) { + cdf_mc_timer_stop(timer); + cdf_mc_timer_start(timer, expirationTime); + } +} + +/** + * wlan_hdd_tdls_indicate_teardown() - indicate tdls teardown + * @pAdapter: HDD adapter + * @curr_peer: peer tdls teardown happened + * @reason: teardown reason + * + * Return: Void + */ +void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, + hddTdlsPeer_t *curr_peer, uint16_t reason) +{ + if (NULL == pAdapter || NULL == curr_peer) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("parameters passed are invalid")); + return; + } + + if (eTDLS_LINK_CONNECTED != curr_peer->link_status) + return; + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_TEARING, + eTDLS_LINK_UNSPECIFIED); + cfg80211_tdls_oper_request(pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_TEARDOWN, reason, GFP_KERNEL); +} + +/** + * wlan_hdd_set_callback() - set state change callback on current TDLS peer + * @curr_peer: current TDLS peer + * @callback: state change callback + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, + cfg80211_exttdls_callback callback) +{ + hdd_context_t *pHddCtx; + hdd_adapter_t *pAdapter; + if (!curr_peer) + return -EINVAL; + pAdapter = curr_peer->pHddTdlsCtx->pAdapter; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if ((NULL == pHddCtx)) + return -EINVAL; + mutex_lock(&pHddCtx->tdls_lock); + curr_peer->state_change_notification = callback; + mutex_unlock(&pHddCtx->tdls_lock); + return 0; +} + +/** + * wlan_hdd_tdls_get_wifi_hal_state() - get tdls wifi hal state on current peer + * @curr_peer: current TDLS peer + * @state: output parameter to store the tdls wifi hal state + * @reason: output parameter to store the reason of the current peer + * + * Return: Void + */ +void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, + int32_t *state, int32_t *reason) +{ + *reason = curr_peer->reason; + switch (curr_peer->link_status) { + case eTDLS_LINK_IDLE: + case eTDLS_LINK_DISCOVERED: + *state = QCA_WIFI_HAL_TDLS_ENABLED; + break; + case eTDLS_LINK_DISCOVERING: + case eTDLS_LINK_CONNECTING: + *state = QCA_WIFI_HAL_TDLS_ENABLED; + break; + case eTDLS_LINK_CONNECTED: + *state = QCA_WIFI_HAL_TDLS_ESTABLISHED; + break; + case eTDLS_LINK_TEARING: + *state = QCA_WIFI_HAL_TDLS_DROPPED; + break; + } +} + +/** + * wlan_hdd_tdls_get_status() - get tdls status on current tdls peer + * @pAdapter: HDD adapter + * @mac: MAC address of current TDLS peer + * @state: output parameter to store the tdls wifi hal state + * @reason: output parameter to store the reason of the current peer + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, int32_t *state, + int32_t *reason) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + if (curr_peer == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + *state = QCA_WIFI_HAL_TDLS_DISABLED; + *reason = eTDLS_LINK_UNSPECIFIED; + } else { + if (pHddCtx->config->fTDLSExternalControl && + (false == curr_peer->isForcedPeer)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("curr_peer is not Forced")); + *state = QCA_WIFI_HAL_TDLS_DISABLED; + *reason = eTDLS_LINK_UNSPECIFIED; + } else { + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, + state, reason); + } + } + + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, state, reason); + return 0; +} + +#ifdef FEATURE_WLAN_TDLS +static const struct nla_policy + wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = {.type = NLA_UNSPEC}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type = + NLA_S32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = {.type = NLA_UNSPEC}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_state_change_policy[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR] = {.type = NLA_UNSPEC}, + [QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_U32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_get_status_policy +[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR] = {.type = NLA_UNSPEC}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_exttdls_get_status() - handle get status cfg80211 command + * @wiphy: wiphy + * @wdev: wireless dev + * @data: netlink buffer with the mac address of the peer to get the status for + * @data_len: length of data in bytes + */ +static int +__wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint8_t peer[ETH_ALEN] = { 0 }; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1]; + CDF_STATUS ret; + uint32_t state; + int32_t reason; + uint32_t global_operating_class = 0; + uint32_t channel = 0; + struct sk_buff *skb = NULL; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + return -EINVAL; + } + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX, + data, data_len, wlan_hdd_tdls_config_get_status_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid attribute")); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr mac addr failed")); + return -EINVAL; + } + memcpy(peer, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]), + sizeof(peer)); + hddLog(CDF_TRACE_LEVEL_INFO, FL(MAC_ADDRESS_STR), MAC_ADDR_ARRAY(peer)); + ret = wlan_hdd_tdls_get_status(pAdapter, peer, &state, &reason); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("get status Failed")); + return -EINVAL; + } + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 4 * sizeof(int32_t) + + NLMSG_HDRLEN); + if (!skb) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -EINVAL; + } + hddLog(CDF_TRACE_LEVEL_INFO, FL("Reason %d Status %d class %d channel %d peer " MAC_ADDRESS_STR), + reason, state, global_operating_class, channel, + MAC_ADDR_ARRAY(peer)); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE, + state) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON, + reason) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS, + global_operating_class) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL, + channel)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } + return cfg80211_vendor_cmd_reply(skb); +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_exttdls_get_status() - get ext tdls status + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_get_status(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_callback() - notify cfg80211 state change + * @mac: MAC address of the peer with state change + * @state: New state + * @reason: Reason to enter new state + * @ctx: HDD adapter + * + * Return: 0 for success; negative errno otherwise + */ +static int wlan_hdd_cfg80211_exttdls_callback(const uint8_t *mac, + uint32_t state, + int32_t reason, void *ctx) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) ctx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct sk_buff *skb = NULL; + uint32_t global_operating_class = 0; + uint32_t channel = 0; + if (wlan_hdd_validate_context(pHddCtx)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid ")); + return -EINVAL; + } + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTTDLS_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX, + GFP_KERNEL); + if (!skb) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("cfg80211_vendor_event_alloc failed")); + return -EINVAL; + } + hddLog(CDF_TRACE_LEVEL_INFO, FL("Reason: %d Status: %d Class: %d Channel: %d tdls peer " MAC_ADDRESS_STR), + reason, state, global_operating_class, channel, + MAC_ADDR_ARRAY(mac)); + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR, + CDF_MAC_ADDR_SIZE, mac) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE, + state) || + nla_put_s32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON, + reason) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL, + channel) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS, + global_operating_class)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail")); + goto nla_put_failure; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_exttdls_enable() - enable an externally controllable + * TDLS peer and set parameters + * wiphy: wiphy + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address and configuration parameters + * @data_len: size of data in bytes + * + * This function sets channel, operation class, maximum latency and minimal + * bandwidth parameters on a TDLS peer that's externally controllable. + * + * Return: 0 for success; negative errno otherwise + */ +static int +__wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint8_t peer[ETH_ALEN] = { 0 }; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + 1]; + CDF_STATUS status; + tdls_req_params_t pReqMsg = { 0 }; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + if (pHddCtx->config->fTDLSExternalControl == false) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("TDLS External Control is not enabled")); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX, + data, data_len, wlan_hdd_tdls_config_enable_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr mac addr failed")); + return -EINVAL; + } + memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]), + sizeof(peer)); + hddLog(CDF_TRACE_LEVEL_INFO, FL(MAC_ADDRESS_STR), MAC_ADDR_ARRAY(peer)); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr channel failed")); + return -EINVAL; + } + pReqMsg.channel = + nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]); + hddLog(CDF_TRACE_LEVEL_INFO, FL("Channel Num (%d)"), pReqMsg.channel); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("attr operating class failed")); + return -EINVAL; + } + pReqMsg.global_operating_class = + nla_get_s32(tb + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]); + hddLog(CDF_TRACE_LEVEL_INFO, FL("Operating class (%d)"), + pReqMsg.global_operating_class); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr latency failed")); + return -EINVAL; + } + pReqMsg.max_latency_ms = + nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]); + hddLog(CDF_TRACE_LEVEL_INFO, FL("Latency (%d)"), + pReqMsg.max_latency_ms); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr bandwidth failed")); + return -EINVAL; + } + pReqMsg.min_bandwidth_kbps = + nla_get_s32(tb + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]); + hddLog(CDF_TRACE_LEVEL_INFO, FL("Bandwidth (%d)"), + pReqMsg.min_bandwidth_kbps); + return wlan_hdd_tdls_extctrl_config_peer( + pAdapter, + peer, + wlan_hdd_cfg80211_exttdls_callback, + pReqMsg.channel, + pReqMsg.max_latency_ms, + pReqMsg. + global_operating_class, + pReqMsg.min_bandwidth_kbps); +} + +/** + * wlan_hdd_cfg80211_exttdls_enable() - enable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_enable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_exttdls_disable() - disable an externally controllable + * TDLS peer + * wiphy: wiphy + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address + * @data_len: size of data in bytes + * + * This function disables an externally controllable TDLS peer + * + * Return: 0 for success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + u8 peer[ETH_ALEN] = {0}; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + 1]; + CDF_STATUS status; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return -EINVAL; + } + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX, + data, data_len, wlan_hdd_tdls_config_disable_policy)) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid ATTR")); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("attr mac addr failed")); + return -EINVAL; + } + memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]), + sizeof(peer)); + hddLog(CDF_TRACE_LEVEL_INFO, FL(MAC_ADDRESS_STR), MAC_ADDR_ARRAY(peer)); + return wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer); +} + +/** + * wlan_hdd_cfg80211_exttdls_disable() - disable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_disable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tdls_add_station() - add or change a TDLS peer station + * @wiphy: wiphy + * @dev: net device + * @mac: MAC address of the TDLS peer + * @update: if non-0, modify the peer with StaParams; if 0, add new peer + * @StaParams: station parameters for the TDLS to change + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_add_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + bool update, tCsrStaParams *StaParams) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + CDF_STATUS status; + hddTdlsPeer_t *pTdlsPeer; + uint16_t numCurrTdlsPeers; + unsigned long rc; + long ret; + + ENTER(); + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return ret; + } + + if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) || + (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode)) { + hddLog(LOG1, + "%s: TDLS mode is disabled OR not enabled in FW." + MAC_ADDRESS_STR " Request declined.", + __func__, MAC_ADDR_ARRAY(mac)); + return -ENOTSUPP; + } + + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac); + + if (NULL == pTdlsPeer) { + hddLog(LOGE, + "%s: " MAC_ADDRESS_STR + " (update %d) not exist. return invalid", __func__, + MAC_ADDR_ARRAY(mac), update); + return -EINVAL; + } + + /* in add station, we accept existing valid staId if there is */ + if ((0 == update) && + ((pTdlsPeer->link_status >= eTDLS_LINK_CONNECTING) || + (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + " link_status %d. staId %d. add station ignored.", + __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, + pTdlsPeer->staId); + return 0; + } + /* in change station, we accept only when staId is valid */ + if ((1 == update) && + ((pTdlsPeer->link_status > eTDLS_LINK_CONNECTING) || + (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { + hddLog(LOGE, + "%s: " MAC_ADDRESS_STR + " link status %d. staId %d. change station %s.", + __func__, MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, + pTdlsPeer->staId, + (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? "ignored" : + "declined"); + return (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? 0 : -EPERM; + } + + /* when others are on-going, we want to change link_status to idle */ + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true)) { + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + " TDLS setup is ongoing. Request declined.", + __func__, MAC_ADDR_ARRAY(mac)); + goto error; + } + + /* first to check if we reached to maximum supported TDLS peer. + TODO: for now, return -EPERM looks working fine, + but need to check if any other errno fit into this category. */ + numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected. Request declined." + " Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(mac), numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + goto error; + } else { + hddTdlsPeer_t *pTdlsPeer; + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac, true); + if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " already connected. Request declined.", + __func__, MAC_ADDR_ARRAY(mac)); + return -EPERM; + } + } + if (0 == update) + wlan_hdd_tdls_set_link_status(pAdapter, + mac, + eTDLS_LINK_CONNECTING, + eTDLS_LINK_SUCCESS); + + /* debug code */ + if (NULL != StaParams) { + hddLog(LOG1, + "%s: TDLS Peer Parameters.", __func__); + if (StaParams->htcap_present) { + hddLog(LOG1, + "ht_capa->cap_info: %0x", + StaParams->HTCap.capInfo); + hddLog(LOG1, + "ht_capa->extended_capabilities: %0x", + StaParams->HTCap.extendedHtCapInfo); + } + hddLog(LOG1, + "params->capability: %0x", StaParams->capability); + hddLog(LOG1, + "params->ext_capab_len: %0x", + StaParams->extn_capability[0]); + if (StaParams->vhtcap_present) { + hddLog(LOG1, + "rxMcsMap %x rxHighest %x txMcsMap %x txHighest %x", + StaParams->VHTCap.suppMcs.rxMcsMap, + StaParams->VHTCap.suppMcs.rxHighest, + StaParams->VHTCap.suppMcs.txMcsMap, + StaParams->VHTCap.suppMcs.txHighest); + } + { + int i = 0; + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "Supported rates:"); + for (i = 0; i < sizeof(StaParams->supported_rates); i++) + hddLog(LOG1, "[%d]: %x ", i, + StaParams->supported_rates[i]); + } + } /* end debug code */ + else if ((1 == update) && (NULL == StaParams)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s : update is true, but staParams is NULL. Error!", + __func__); + return -EPERM; + } + + INIT_COMPLETION(pAdapter->tdls_add_station_comp); + + if (!update) { + status = sme_add_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, mac); + } else { + status = sme_change_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, mac, + StaParams); + } + + rc = wait_for_completion_timeout(&pAdapter->tdls_add_station_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_ADD_STA)); + + if (!rc) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: timeout waiting for tdls add station indication", + __func__); + return -EPERM; + } + + if (CDF_STATUS_SUCCESS != pAdapter->tdlsAddStaStatus) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Add Station is unsuccessful", __func__); + return -EPERM; + } + + return 0; + +error: + wlan_hdd_tdls_set_link_status(pAdapter, + mac, + eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED); + return -EPERM; + +} + +#if TDLS_MGMT_VERSION2 +/** + * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, u8 *peer, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else +/** + * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#else +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len) +#endif +#endif +{ + + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + u8 peerMac[CDF_MAC_ADDR_SIZE]; + CDF_STATUS status; + int max_sta_failed = 0; + int responder; + unsigned long rc; + uint16_t numCurrTdlsPeers; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) +#if !(TDLS_MGMT_VERSION2) + u32 peer_capability; + peer_capability = 0; +#endif +#endif + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_MGMT, + pAdapter->sessionId, action_code)); + + if (0 != wlan_hdd_validate_context(pHddCtx)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return -EINVAL; + } + + if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) { + hddLog(LOG1, + "%s: TDLS mode is disabled OR not enabled in FW." + MAC_ADDRESS_STR " action %d declined.", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -ENOTSUPP; + } + + /* If any concurrency is detected */ + if (((1 << CDF_STA_MODE) != pHddCtx->concurrency_mode) || + (pHddCtx->no_of_active_sessions[CDF_STA_MODE] > 1)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Multiple STA OR Concurrency detected. Ignore TDLS MGMT frame. action_code=%d, concurrency_mode: 0x%x, active_sessions: %d", + __func__, + action_code, + pHddCtx->concurrency_mode, + pHddCtx->no_of_active_sessions[CDF_STA_MODE]); + return -EPERM; + } + /* other than teardown frame, mgmt frames are not sent if disabled */ + if (SIR_MAC_TDLS_TEARDOWN != action_code) { + /* if tdls_mode is disabled to respond to peer's request */ + if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) { + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + " TDLS mode is disabled. action %d declined.", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -ENOTSUPP; + } + } + + if (WLAN_IS_TDLS_SETUP_ACTION(action_code)) { + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer, true)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS setup is ongoing. action %d declined.", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -EPERM; + } + } + + if (SIR_MAC_TDLS_SETUP_REQ == action_code || + SIR_MAC_TDLS_SETUP_RSP == action_code) { + numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) { + /* supplicant still sends tdls_mgmt(SETUP_REQ) even after + we return error code at 'add_station()'. Hence we have this + check again in addtion to add_station(). + Anyway, there is no hard to double-check. */ + if (SIR_MAC_TDLS_SETUP_REQ == action_code) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(peer), + action_code, numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + return -EINVAL; + } else { + /* maximum reached. tweak to send error code to peer and return + error code to supplicant */ + status_code = eSIR_MAC_UNSPEC_FAILURE_STATUS; + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(peer), + status_code, numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + max_sta_failed = -EPERM; + /* fall through to send setup resp with failure status + code */ + } + } else { + hddTdlsPeer_t *pTdlsPeer; + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer, true); + if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s:" MAC_ADDRESS_STR + " already connected. action %d declined.", + __func__, MAC_ADDR_ARRAY(peer), + action_code); + return -EPERM; + } + } + } + cdf_mem_copy(peerMac, peer, 6); + + hddLog(LOG1, + "%s: " MAC_ADDRESS_STR + " action %d, dialog_token %d status %d, len = %zu", + "tdls_mgmt", MAC_ADDR_ARRAY(peer), action_code, dialog_token, + status_code, len); + + /*Except teardown responder will not be used so just make 0 */ + responder = 0; + if (SIR_MAC_TDLS_TEARDOWN == action_code) { + + hddTdlsPeer_t *pTdlsPeer; + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peerMac, true); + + if (pTdlsPeer && TDLS_IS_CONNECTED(pTdlsPeer)) + responder = pTdlsPeer->is_responder; + else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " peer doesn't exist or not connected %d dialog_token %d status %d, len = %zu", + __func__, MAC_ADDR_ARRAY(peer), + (NULL == + pTdlsPeer) ? -1 : pTdlsPeer->link_status, + dialog_token, status_code, len); + return -EPERM; + } + } + + /* For explicit trigger of DIS_REQ come out of BMPS for + successfully receiving DIS_RSP from peer. */ + if ((SIR_MAC_TDLS_SETUP_RSP == action_code) || + (SIR_MAC_TDLS_DIS_RSP == action_code) || + (SIR_MAC_TDLS_DIS_REQ == action_code)) { + /* Fw will take care if PS offload is enabled. */ + if (SIR_MAC_TDLS_DIS_REQ != action_code) + wlan_hdd_tdls_set_cap(pAdapter, peerMac, + eTDLS_CAP_SUPPORTED); + } + + /* make sure doesn't call send_mgmt() while it is pending */ + if (TDLS_CTX_MAGIC == pAdapter->mgmtTxCompletionStatus) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " action %d couldn't sent, as one is pending. return EBUSY", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -EBUSY; + } + + pAdapter->mgmtTxCompletionStatus = TDLS_CTX_MAGIC; + INIT_COMPLETION(pAdapter->tdls_mgmt_comp); + + status = sme_send_tdls_mgmt_frame(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, peerMac, + action_code, dialog_token, status_code, + peer_capability, (uint8_t *) buf, len, + !responder); + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_send_tdls_mgmt_frame failed!", __func__); + pAdapter->mgmtTxCompletionStatus = false; + return -EINVAL; + } + + rc = wait_for_completion_timeout(&pAdapter->tdls_mgmt_comp, + msecs_to_jiffies(WAIT_TIME_TDLS_MGMT)); + + if ((0 == rc) || (true != pAdapter->mgmtTxCompletionStatus)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Mgmt Tx Completion timed out TxCompletion %u", + __func__, pAdapter->mgmtTxCompletionStatus); + + if (pHddCtx->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: LOGP in Progress. Ignore!!!", __func__); + return -EAGAIN; + } + + if (pHddCtx->isUnloadInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Unloading/Loading in Progress. Ignore!!!", + __func__); + return -EAGAIN; + } + + pAdapter->mgmtTxCompletionStatus = false; + return -EINVAL; + } + + if (max_sta_failed) { + return max_sta_failed; + } + + if (SIR_MAC_TDLS_SETUP_RSP == action_code) { + return wlan_hdd_tdls_set_responder(pAdapter, peerMac, false); + } else if (SIR_MAC_TDLS_SETUP_CNF == action_code) { + return wlan_hdd_tdls_set_responder(pAdapter, peerMac, true); + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_tdls_mgmt() - cfg80211 tdls mgmt handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device structure. + * @peer: peer address + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @buf: buffer + * @len: Length of @buf + * + * This is the cfg80211 tdls mgmt handler function which invokes + * the internal function @__wlan_hdd_cfg80211_tdls_mgmt with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#if TDLS_MGMT_VERSION2 +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else /* TDLS_MGMT_VERSION2 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, const u8 *buf, + size_t len) +#endif +#endif +{ + int ret; + + cds_ssr_protect(__func__); +#if TDLS_MGMT_VERSION2 + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else /* TDLS_MGMT_VERSION2 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); +#endif +#endif + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tdls_extctrl_config_peer() - configure an externally controllable + * TDLS peer + * @pAdapter: HDD adapter + * @peer: MAC address of the TDLS peer + * @callback: Callback to set on the peer + * @chan: Channel + * @max_latency: Maximum latency + * @op_class: Operation class + * @min_bandwidth: Minimal bandwidth + * + * Return: 0 on success; negative otherwise + */ +int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + u32 chan, + u32 max_latency, + u32 op_class, u32 min_bandwidth) +{ + hddTdlsPeer_t *pTdlsPeer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s : NL80211_TDLS_SETUP for " MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(peer)); + if ((false == pHddCtx->config->fTDLSExternalControl) || + (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s TDLS External control or Implicit Trigger not enabled ", + __func__); + return -ENOTSUPP; + } + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer); + if (pTdlsPeer == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: peer " MAC_ADDRESS_STR " does not exist", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, true)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s TDLS Add Force Peer Failed", __func__); + return -EINVAL; + } + if (0 != wlan_hdd_tdls_set_extctrl_param(pAdapter, peer, + chan, max_latency, + op_class, min_bandwidth)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s TDLS Set Peer's External Ctrl Parameter Failed", + __func__); + return -EINVAL; + } + if (0 != wlan_hdd_set_callback(pTdlsPeer, callback)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s TDLS set callback Failed", __func__); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_tdls_extctrl_deconfig_peer() - de-configure an externally + * controllable TDLS peer + * @pAdapter: HDD adapter + * @peer: MAC address of the tdls peer + * + * Return: 0 if success; negative errno otherwisw + */ +int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer) +{ + hddTdlsPeer_t *pTdlsPeer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s : NL80211_TDLS_TEARDOWN for " MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(peer)); + if ((false == pHddCtx->config->fTDLSExternalControl) || + (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s TDLS External control or Implicit Trigger not enabled ", + __func__); + return -ENOTSUPP; + } + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer, true); + if (NULL == pTdlsPeer) { + hddLog(CDF_TRACE_LEVEL_INFO, "%s: " MAC_ADDRESS_STR + "peer matching MAC_ADDRESS_STR not found", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } else { + wlan_hdd_tdls_indicate_teardown(pAdapter, pTdlsPeer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + } + if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, false)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s Failed", __func__); + return -EINVAL; + } + if (0 != wlan_hdd_set_callback(pTdlsPeer, NULL)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s TDLS set callback Failed", __func__); + return -EINVAL; + } + return 0; +} + +/** + * __wlan_hdd_cfg80211_tdls_oper() - helper function to handle cfg80211 operation + * on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + int status; + tSmeTdlsPeerStateParams smeTdlsPeerStateParams; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + hddTdlsPeer_t *pTdlsPeer; + + if (CDF_FTM_MODE == hdd_get_conparam()) { + hddLog(LOGE, FL("Command not allowed in FTM mode")); + return -EINVAL; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_OPER, + pAdapter->sessionId, oper)); + if (NULL == peer) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid arguments", __func__); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is not valid", __func__); + return status; + } + + /* QCA 2.0 Discrete ANDs feature capability in HDD config with that + * received from target, so HDD config gives combined intersected result + */ + if (false == pHddCtx->config->fEnableTDLSSupport) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "TDLS Disabled in INI OR not enabled in FW. " + "Cannot process TDLS commands"); + return -ENOTSUPP; + } + + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + { + CDF_STATUS status; + unsigned long rc; + tCsrTdlsLinkEstablishParams tdlsLinkEstablishParams; + + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer, true); + + if (NULL == pTdlsPeer) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " not found, ignore NL80211_TDLS_ENABLE_LINK", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: NL80211_TDLS_ENABLE_LINK for peer " + MAC_ADDRESS_STR " link_status: %d", + __func__, MAC_ADDR_ARRAY(peer), + pTdlsPeer->link_status); + + if (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: invalid sta index %u for " + MAC_ADDRESS_STR + " TDLS_ENABLE_LINK failed", __func__, + pTdlsPeer->staId, + MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + + if (eTDLS_LINK_CONNECTED != pTdlsPeer->link_status) { + if (IS_ADVANCE_TDLS_ENABLE) { + + if (0 != + wlan_hdd_tdls_get_link_establish_params + (pAdapter, peer, + &tdlsLinkEstablishParams)) { + return -EINVAL; + } + INIT_COMPLETION(pAdapter-> + tdls_link_establish_req_comp); + + sme_send_tdls_link_establish_params + (WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, peer, + &tdlsLinkEstablishParams); + /* Send TDLS peer UAPSD capabilities to the firmware and + * register with the TL on after the response for this operation + * is received . + */ + rc = wait_for_completion_timeout + (&pAdapter-> + tdls_link_establish_req_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_LINK_ESTABLISH_REQ)); + if (!rc) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Link Establish Request timed out", + __func__); + return -EINVAL; + } + } + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, + eTDLS_LINK_CONNECTED, + eTDLS_LINK_SUCCESS); + /* start TDLS client registration with TL */ + status = + hdd_roam_register_tdlssta(pAdapter, peer, + pTdlsPeer->staId, + pTdlsPeer-> + signature); + if (CDF_STATUS_SUCCESS == status) { + uint8_t i; + + cdf_mem_zero(&smeTdlsPeerStateParams, + sizeof + (tSmeTdlsPeerStateParams)); + + smeTdlsPeerStateParams.vdevId = + pAdapter->sessionId; + cdf_mem_copy(&smeTdlsPeerStateParams. + peerMacAddr, + &pTdlsPeer->peerMac, + sizeof(tSirMacAddr)); + smeTdlsPeerStateParams.peerState = + eSME_TDLS_PEER_STATE_CONNECTED; + smeTdlsPeerStateParams.peerCap. + isPeerResponder = + pTdlsPeer->is_responder; + smeTdlsPeerStateParams.peerCap. + peerUapsdQueue = + pTdlsPeer->uapsdQueues; + smeTdlsPeerStateParams.peerCap. + peerMaxSp = pTdlsPeer->maxSp; + smeTdlsPeerStateParams.peerCap. + peerBuffStaSupport = + pTdlsPeer->isBufSta; + smeTdlsPeerStateParams.peerCap. + peerOffChanSupport = + pTdlsPeer->isOffChannelSupported; + smeTdlsPeerStateParams.peerCap. + peerCurrOperClass = 0; + smeTdlsPeerStateParams.peerCap. + selfCurrOperClass = 0; + smeTdlsPeerStateParams.peerCap. + peerChanLen = + pTdlsPeer->supported_channels_len; + smeTdlsPeerStateParams.peerCap. + prefOffChanNum = + pTdlsPeer->pref_off_chan_num; + smeTdlsPeerStateParams.peerCap. + prefOffChanBandwidth = + pHddCtx->config-> + fTDLSPrefOffChanBandwidth; + if (pTdlsPeer-> + op_class_for_pref_off_chan_is_set) { + smeTdlsPeerStateParams.peerCap. + opClassForPrefOffChanIsSet = + pTdlsPeer-> + op_class_for_pref_off_chan_is_set; + smeTdlsPeerStateParams.peerCap. + opClassForPrefOffChan = + pTdlsPeer-> + op_class_for_pref_off_chan; + } + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: Peer " MAC_ADDRESS_STR + "vdevId: %d, peerState: %d, isPeerResponder: %d, uapsdQueues: 0x%x, maxSp: 0x%x, peerBuffStaSupport: %d, peerOffChanSupport: %d, peerCurrOperClass: %d, selfCurrOperClass: %d, peerChanLen: %d, peerOperClassLen: %d, prefOffChanNum: %d, prefOffChanBandwidth: %d, op_class_for_pref_off_chan_is_set: %d, op_class_for_pref_off_chan: %d", + __func__, + MAC_ADDR_ARRAY(peer), + smeTdlsPeerStateParams.vdevId, + smeTdlsPeerStateParams. + peerState, + smeTdlsPeerStateParams. + peerCap.isPeerResponder, + smeTdlsPeerStateParams. + peerCap.peerUapsdQueue, + smeTdlsPeerStateParams. + peerCap.peerMaxSp, + smeTdlsPeerStateParams. + peerCap.peerBuffStaSupport, + smeTdlsPeerStateParams. + peerCap.peerOffChanSupport, + smeTdlsPeerStateParams. + peerCap.peerCurrOperClass, + smeTdlsPeerStateParams. + peerCap.selfCurrOperClass, + smeTdlsPeerStateParams. + peerCap.peerChanLen, + smeTdlsPeerStateParams. + peerCap.peerOperClassLen, + smeTdlsPeerStateParams. + peerCap.prefOffChanNum, + smeTdlsPeerStateParams. + peerCap.prefOffChanBandwidth, + pTdlsPeer-> + op_class_for_pref_off_chan_is_set, + pTdlsPeer-> + op_class_for_pref_off_chan); + + for (i = 0; + i < + pTdlsPeer->supported_channels_len; + i++) { + smeTdlsPeerStateParams.peerCap. + peerChan[i] = + pTdlsPeer-> + supported_channels[i]; + } + smeTdlsPeerStateParams.peerCap. + peerOperClassLen = + pTdlsPeer-> + supported_oper_classes_len; + for (i = 0; + i < + pTdlsPeer-> + supported_oper_classes_len; i++) { + smeTdlsPeerStateParams.peerCap. + peerOperClass[i] = + pTdlsPeer-> + supported_oper_classes[i]; + } + + cdf_ret_status = + sme_update_tdls_peer_state(pHddCtx-> + hHal, + &smeTdlsPeerStateParams); + if (CDF_STATUS_SUCCESS != + cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: sme_update_tdls_peer_state failed for " + MAC_ADDRESS_STR, + __func__, + MAC_ADDR_ARRAY(peer)); + return -EPERM; + } + wlan_hdd_tdls_increment_peer_count + (pAdapter); + } + + /* Update TL about the UAPSD masks , to route the packets to firmware */ + if ((true == + pHddCtx->config->fEnableTDLSBufferSta) + || pHddCtx->config->fTDLSUapsdMask) { + int ac; + uint8_t ucAc[4] = { SME_AC_VO, + SME_AC_VI, + SME_AC_BK, + SME_AC_BE}; + uint8_t tlTid[4] = { 7, 5, 2, 3 }; + for (ac = 0; ac < 4; ac++) { + status = sme_enable_uapsd_for_ac( + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + pTdlsPeer->staId, ucAc[ac], + tlTid[ac], tlTid[ac], 0, 0, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + } + } + } + + } + break; + case NL80211_TDLS_DISABLE_LINK: + { + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer, true); + + if (NULL == pTdlsPeer) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " not found, ignore NL80211_TDLS_DISABLE_LINK", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: NL80211_TDLS_DISABLE_LINK for peer " + MAC_ADDRESS_STR " link_status: %d", + __func__, MAC_ADDR_ARRAY(peer), + pTdlsPeer->link_status); + + if (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) { + unsigned long rc; + + INIT_COMPLETION(pAdapter-> + tdls_del_station_comp); + + sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + peer); + + rc = wait_for_completion_timeout(&pAdapter-> + tdls_del_station_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_DEL_STA)); + if (!rc) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Del station timed out", + __func__); + return -EPERM; + } + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, + eTDLS_LINK_IDLE, + (pTdlsPeer->link_status == + eTDLS_LINK_TEARING) ? + eTDLS_LINK_UNSPECIFIED : + eTDLS_LINK_DROPPED_BY_REMOTE); + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: TDLS Peer Station doesn't exist.", + __func__); + } + } + break; + case NL80211_TDLS_TEARDOWN: + { + status = + wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer); + + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Error in TDLS Teardown", + __func__); + return status; + } + } + break; + case NL80211_TDLS_SETUP: + { + status = wlan_hdd_tdls_extctrl_config_peer(pAdapter, + peer, NULL, + pHddCtx->config->fTDLSPrefOffChanNum, 0, 0, 0); + if (0 != status) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Error in TDLS Setup", __func__); + return status; + } + } + break; + case NL80211_TDLS_DISCOVERY_REQ: + /* We don't support in-driver setup/teardown/discovery */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "%s: We don't support in-driver setup/teardown/discovery", + __func__); + return -ENOTSUPP; + default: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: unsupported event", __func__); + return -ENOTSUPP; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_tdls_oper() - handle cfg80211 operation on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_tdls_oper(wiphy, dev, peer, oper); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_send_tdls_discover_req() - send out TDLS discovery for + * a TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the peer + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer) +{ + hddLog(CDF_TRACE_LEVEL_INFO, + "tdls send discover req: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer)); +#if TDLS_MGMT_VERSION2 + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, 0, + NULL, 0); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#else + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + NULL, 0); +#endif +#endif +} + +#endif /* End of FEATURE_WLAN_TDLS */ + +/** + * wlan_hdd_tdls_find_first_connected_peer() - find the 1st connected tdls peer + * @adapter: Pointer to the HDD adapter + * + * This function searchs for the 1st connected TDLS peer + * + * Return: The first connected TDLS peer if found; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer = NULL; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + hddLog(LOGE, FL("hdd_ctx is not valid")); + return NULL; + } + mutex_lock(&hdd_ctx->tdls_lock); + hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + if (NULL == hdd_tdls_ctx) { + mutex_unlock(&hdd_ctx->tdls_lock); + return NULL; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (curr_peer && (curr_peer->link_status == + eTDLS_LINK_CONNECTED)) { + mutex_unlock(&hdd_ctx->tdls_lock); + hddLog(LOG1, + FL(MAC_ADDRESS_STR + " eTDLS_LINK_CONNECTED" + ), + MAC_ADDR_ARRAY(curr_peer->peerMac)); + return curr_peer; + } + } + } + mutex_unlock(&hdd_ctx->tdls_lock); + return NULL; +} + +/** + * hdd_set_tdls_offchannel() - set tdls off-channel number + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel number + * + * This function sets tdls off-channel number + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel) +{ + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + if (offchannel < CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN || + offchannel > CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) { + hddLog(LOGE, FL("Invalid tdls off channel %u"), + offchannel); + return -EINVAL; + } + } else { + hddLog(LOGE, + FL("Either TDLS or TDLS Off-channel is not enabled")); + return -ENOTSUPP; + } + hddLog(LOG1, + FL("change tdls off channel from %d to %d"), + hdd_ctx->tdls_off_channel, offchannel); + hdd_ctx->tdls_off_channel = offchannel; + return 0; +} + +/** + * hdd_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel offset + * + * This function sets 2nd tdls off-channel offset + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset) +{ + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + hdd_ctx->tdls_channel_offset = 0; + + switch (offchanoffset) { + case TDLS_SEC_OFFCHAN_OFFSET_0: + hdd_ctx->tdls_channel_offset = (1 << BW_20_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_40PLUS: + case TDLS_SEC_OFFCHAN_OFFSET_40MINUS: + hdd_ctx->tdls_channel_offset = (1 << BW_40_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_80: + hdd_ctx->tdls_channel_offset = (1 << BW_80_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_160: + hdd_ctx->tdls_channel_offset = (1 << BW_160_OFFSET_BIT); + break; + default: + hddLog(LOGE, + FL( + "Invalid tdls secondary off channel offset %d" + ), + offchanoffset); + return -EINVAL; + } /* end switch */ + } else { + hddLog(LOGE, + FL("Either TDLS or TDLS Off-channel is not enabled")); + return -ENOTSUPP; + } + hddLog(LOG1, + FL("change tdls secondary off channel offset to 0x%x"), + hdd_ctx->tdls_channel_offset); + return 0; +} + +/** + * hdd_set_tdls_offchannelmode() - set tdls off-channel mode + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel mode + * + * This function sets tdls off-channel mode + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode) +{ + hddTdlsPeer_t *conn_peer = NULL; + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sme_tdls_chan_switch_params chan_switch_params; + + if (offchanmode < ENABLE_CHANSWITCH || + offchanmode > DISABLE_CHANSWITCH) { + hddLog(LOGE, + FL("Invalid tdls off channel mode %d"), + offchanmode); + return -EINVAL; + } + if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState) { + hddLog(LOGE, + FL( + "tdls off channel mode req in not associated state %d" + ), + offchanmode); + return -EPERM; + } + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + conn_peer = wlan_hdd_tdls_find_first_connected_peer(adapter); + if (NULL == conn_peer) { + hddLog(LOGP, + FL("No TDLS Connected Peer")); + return -EPERM; + } + } else { + hddLog(LOGP, + FL("TDLS Connection not supported")); + return -ENOTSUPP; + } + hddLog(LOG1, + FL("TDLS Channel Switch in swmode=%d"), + offchanmode); + + switch (offchanmode) { + case ENABLE_CHANSWITCH: + case DISABLE_CHANSWITCH: + hddLog(LOG1, + FL( + "change tdls off channel mode %d tdls_off_channel %d offchanoffset %d" + ), + offchanmode, hdd_ctx->tdls_off_channel, + hdd_ctx->tdls_channel_offset); + if (hdd_ctx->tdls_off_channel && hdd_ctx->tdls_channel_offset) { + chan_switch_params.vdev_id = adapter->sessionId; + chan_switch_params.tdls_off_channel = + hdd_ctx->tdls_off_channel; + chan_switch_params.tdls_off_ch_bw_offset = + hdd_ctx->tdls_channel_offset; + chan_switch_params.tdls_off_ch_mode = offchanmode; + chan_switch_params.is_responder = + conn_peer->is_responder; + cdf_mem_copy(&chan_switch_params.peer_mac_addr, + &conn_peer->peerMac, + sizeof(tSirMacAddr)); + hddLog(LOG1, + FL("Peer " MAC_ADDRESS_STR + " vdevId: %d, off channel: %d, offset: %d, mode: %d, is_responder: %d" + ), + MAC_ADDR_ARRAY(chan_switch_params. + peer_mac_addr), + chan_switch_params.vdev_id, + chan_switch_params.tdls_off_channel, + chan_switch_params.tdls_off_ch_bw_offset, + chan_switch_params.tdls_off_ch_mode, + chan_switch_params.is_responder); + + sme_send_tdls_chan_switch_req( + WLAN_HDD_GET_HAL_CTX(adapter), + &chan_switch_params); + } else { + hddLog(LOGE, + FL( + "TDLS off-channel parameters are not set yet!!!" + )); + return -EINVAL; + } + break; + default: + hddLog(LOGE, + FL( + "Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d" + ), + offchanmode, hdd_ctx->tdls_off_channel, + hdd_ctx->tdls_channel_offset); + break; + } /* end switch */ + return 0; +} + +/** + * hdd_set_tdls_scan_type - set scan during active tdls session + * @hdd_ctx: ptr to hdd context. + * @val: scan type value: 0 or 1. + * + * Set scan type during tdls session. If set to 1, that means driver + * shall maintain tdls link and allow scan regardless if tdls peer is + * buffer sta capable or not and/or if device is sleep sta capable or + * not. If tdls peer is not buffer sta capable then during scan there + * will be loss of Rx packets and Tx would stop when device moves away + * from tdls channel. If set to 0, then driver shall teardown tdls link + * before initiating scan if peer is not buffer sta capable and device + * is not sleep sta capable. By default, scan type is set to 0. + * + * Return: success (0) or failure (errno value) + */ +int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val) +{ + if ((val != 0) && (val != 1)) { + hddLog(LOGE, FL("Incorrect value of tdls scan type: %d"), + val); + return -EINVAL; + } else { + hdd_ctx->config->enable_tdls_scan = val; + return 0; + } +} diff --git a/core/hdd/src/wlan_hdd_trace.c b/core/hdd/src/wlan_hdd_trace.c new file mode 100644 index 0000000000..ff25fb2bb4 --- /dev/null +++ b/core/hdd/src/wlan_hdd_trace.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef HDD_TRACE_RECORD + +/** + * DOC: wlan_hdd_trace.c + * + * WLAN Host Device Driver trace implementation + * + */ + +#include "cdf_trace.h" +#include "cdf_types.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_main.h" + +/** + * hdd_trace_dump() - Dump an HDD-specific trace record + * @mac: (unused) global MAC handle + * @record: trace record that was previously recorded + * @index: index of the trace record + * + * Return: none + */ +static void +hdd_trace_dump(void *mac, tp_cdf_trace_record record, uint16_t index) +{ + hddLog(LOGE, "%04d %012llu S%d %-14s %-30s(0x%x) ", + index, record->time, record->session, + "HDD Event:", hdd_trace_event_string(record->code), + record->data); +} + +/** + * hdd_trace_init() - HDD trace subsystem initialization + * + * Registers HDD with the debug trace subsystem + * + * Return: none + */ +void hdd_trace_init(void) +{ + cdf_trace_register(CDF_MODULE_ID_HDD, hdd_trace_dump); +} + +#endif /* ifdef HDD_TRACE_RECORD */ diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c new file mode 100644 index 0000000000..3ea2d855ed --- /dev/null +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -0,0 +1,1065 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_tx_rx.c + * + * Linux HDD Tx/RX APIs + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "sap_api.h" +#include "wlan_hdd_wmm.h" + +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif +#include + +#include "wlan_hdd_ocb.h" + +#include "wlan_hdd_lro.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#define HDD_EAPOL_ETHER_TYPE (0x888E) +#define HDD_EAPOL_ETHER_TYPE_OFFSET (12) +#define HDD_EAPOL_PACKET_TYPE_OFFSET (15) +#define HDD_EAPOL_KEY_INFO_OFFSET (19) +#define HDD_EAPOL_DEST_MAC_OFFSET (0) +#define HDD_EAPOL_SRC_MAC_OFFSET (6) +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +const uint8_t hdd_wmm_ac_to_highest_up[] = { + SME_QOS_WMM_UP_RESV, + SME_QOS_WMM_UP_EE, + SME_QOS_WMM_UP_VI, + SME_QOS_WMM_UP_NC +}; + +/* Mapping Linux AC interpretation to SME AC. */ +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VI, + SME_AC_BE, + SME_AC_BK, +}; + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * If Blocked OS Q is not resumed during timeout period, to prevent + * permanent stall, resume OS Q forcefully. + * + * Return: None + */ +void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + /* INVALID ARG */ + return; + } + + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + return; +} + +/** + * hdd_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + hdd_station_ctx_t *hdd_sta_ctx = NULL; + + if (!pAdapter) { + /* INVALID ARG */ + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Resume TX */ + if (true == tx_resume) { + if (CDF_TIMER_STATE_STOPPED != + cdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + cdf_mc_timer_stop(&pAdapter->tx_flow_control_timer); + } + if (cdf_unlikely(hdd_sta_ctx->hdd_ReassocScenario)) { + hddLog(LOGW, + FL("flow control, tx queues un-pause avoided as we are in REASSOCIATING state")); + return; + } + hddLog(LOG1, FL("Enabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + else if (false == tx_resume) { /* Pause TX */ + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + if (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + CDF_STATUS status; + status = + cdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + if (!CDF_IS_STATUS_SUCCESS(status)) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: Failed to start tx_flow_control_timer", + __func__); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + pAdapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++; + pAdapter->hdd_stats.hddTxRxStats.is_txflow_paused = true; + } +#endif + + return; +} + +/** + * hdd_register_tx_flow_control() - Register TX Flow control + * @adapter: adapter handle + * @timer_callback: timer callback + * @flow_control_fp: txrx flow control + * + * Return: none + */ +void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + cdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flow_control_fp) +{ + if (adapter->tx_flow_timer_initialized == false) { + cdf_mc_timer_init(&adapter->tx_flow_control_timer, + CDF_TIMER_TYPE_SW, + timer_callback, + adapter); + adapter->tx_flow_timer_initialized = true; + } + ol_txrx_register_tx_flow_control(adapter->sessionId, + flow_control_fp, + adapter); + +} + +/** + * hdd_deregister_tx_flow_control() - Deregister TX Flow control + * @adapter: adapter handle + * + * Return: none + */ +void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter) +{ + ol_txrx_deregister_tx_flow_control_cb(adapter->sessionId); + if (adapter->tx_flow_timer_initialized == true) { + cdf_mc_timer_stop(&adapter->tx_flow_control_timer); + cdf_mc_timer_destroy(&adapter->tx_flow_control_timer); + adapter->tx_flow_timer_initialized = false; + } +} + +/** + * hdd_get_tx_resource() - check tx resources and take action + * @adapter: adapter handle + * @STAId: station id + * @timer_value: timer value + * + * Return: none + */ +void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value) +{ + if (false == + ol_txrx_get_tx_resource(STAId, + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset)) { + hdd_info("Disabling queues lwm %d hwm offset %d", + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + if ((adapter->tx_flow_timer_initialized == true) && + (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer))) { + cdf_mc_timer_start(&adapter->tx_flow_control_timer, + timer_value); + adapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + adapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++; + adapter->hdd_stats.hddTxRxStats.is_txflow_paused = true; + } + } +} + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * wlan_hdd_is_eapol() - Function to check if frame is EAPOL or not + * @skb: skb data + * + * This function checks if the frame is an EAPOL frame or not + * + * Return: true (1) if packet is EAPOL + * + */ +static bool wlan_hdd_is_eapol(struct sk_buff *skb) +{ + uint16_t ether_type; + + if (!skb) { + hdd_err(FL("skb is NULL")); + return false; + } + + ether_type = (uint16_t)(*(uint16_t *) + (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET)); + + if (ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_802_1_X)) + return true; + + return false; +} + +/** + * wlan_hdd_is_eapol_or_wai() - Check if frame is EAPOL or WAPI + * @skb: skb data + * + * This function checks if the frame is EAPOL or WAPI. + * single routine call will check for both types, thus avoiding + * data path performance penalty. + * + * Return: true (1) if packet is EAPOL or WAPI + * + */ +static bool wlan_hdd_is_eapol_or_wai(struct sk_buff *skb) +{ + uint16_t ether_type; + + if (!skb) { + hdd_err(FL("skb is NULL")); + return false; + } + + ether_type = (uint16_t)(*(uint16_t *) + (skb->data + HDD_ETHERTYPE_802_1_X_FRAME_OFFSET)); + + if (ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_802_1_X) || + ether_type == CDF_SWAP_U16(HDD_ETHERTYPE_WAI)) + return true; + + /* No error msg handled since this will happen often */ + return false; +} + +/** + * hdd_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Transport Layer. + * + * Return: Always returns NETDEV_TX_OK + */ +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + CDF_STATUS status; + sme_ac_enum_type ac; + sme_QosWmmUpType up; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool granted; + uint8_t STAId = WLAN_MAX_STA_COUNT; + hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; + uint8_t proto_type = 0; +#ifdef QCA_PKT_PROTO_TRACE + hdd_context_t *hddCtxt = WLAN_HDD_GET_CTX(pAdapter); +#endif /* QCA_PKT_PROTO_TRACE */ + +#ifdef QCA_WIFI_FTM + if (hdd_get_conparam() == CDF_FTM_MODE) { + kfree_skb(skb); + return NETDEV_TX_OK; + } +#endif + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; + + if (WLAN_HDD_IBSS == pAdapter->device_mode) { + struct cdf_mac_addr *pDestMacAddress = + (struct cdf_mac_addr *) skb->data; + + if (CDF_STATUS_SUCCESS != + hdd_ibss_get_sta_id(&pAdapter->sessionCtx.station, + pDestMacAddress, &STAId)) + STAId = HDD_WLAN_INVALID_STA_ID; + + if ((STAId == HDD_WLAN_INVALID_STA_ID) && + (cdf_is_macaddr_broadcast(pDestMacAddress) || + cdf_is_macaddr_group(pDestMacAddress))) { + STAId = IBSS_BROADCAST_STAID; + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, + CDF_TRACE_LEVEL_INFO_LOW, "%s: BC/MC packet", + __func__); + } else if (STAId == HDD_WLAN_INVALID_STA_ID) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_WARN, + "%s: Received Unicast frame with invalid staID", + __func__); + ++pAdapter->stats.tx_dropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; + kfree_skb(skb); + return NETDEV_TX_OK; + } + } else { + STAId = pHddStaCtx->conn_info.staId[0]; + } + + + hdd_get_tx_resource(pAdapter, STAId, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + + if (!(NBUF_OWNER_ID(skb) == IPA_NBUF_OWNER_ID)) { + /* Check if the buffer has enough header room */ + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) + goto drop_pkt; + + if (skb_headroom(skb) < dev->hard_header_len) { + struct sk_buff *tmp; + tmp = skb; + skb = skb_realloc_headroom(tmp, dev->hard_header_len); + dev_kfree_skb(tmp); + if (!skb) + goto drop_pkt; + } + } + + /* user priority from IP header, which is already extracted and set from + * select_queue call back function + */ + up = skb->priority; + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac]; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_FATAL, + "%s: Classified as ac %d up %d", __func__, ac, up); +#endif /* HDD_WMM_DEBUG */ + + if (HDD_PSB_CHANGED == pAdapter->psbChanged) { + /* Function which will determine acquire admittance for a + * WMM AC is required or not based on psb configuration done + * in the framework + */ + hdd_wmm_acquire_access_required(pAdapter, ac); + } + /* + * Make sure we already have access to this access category + * or it is EAPOL or WAPI frame during initial authentication which + * can have artifically boosted higher qos priority. + */ + + if (((pAdapter->psbChanged & (1 << ac)) && + likely(pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed)) || + ((pHddStaCtx->conn_info.uIsAuthenticated == false) && + wlan_hdd_is_eapol_or_wai(skb))) { + granted = true; + } else { + status = hdd_wmm_acquire_access(pAdapter, ac, &granted); + pAdapter->psbChanged |= (1 << ac); + } + + if (!granted) { + bool isDefaultAc = false; + /* ADDTS request for this AC is sent, for now + * send this packet through next avaiable lower + * Access category until ADDTS negotiation completes. + */ + while (!likely + (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed)) { + switch (ac) { + case SME_AC_VO: + ac = SME_AC_VI; + up = SME_QOS_WMM_UP_VI; + break; + case SME_AC_VI: + ac = SME_AC_BE; + up = SME_QOS_WMM_UP_BE; + break; + case SME_AC_BE: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + break; + default: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + isDefaultAc = true; + break; + } + if (isDefaultAc) + break; + } + skb->priority = up; + skb->queue_mapping = hdd_linux_up_to_ac_map[up]; + } + + wlan_hdd_log_eapol(skb, + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); + +#ifdef QCA_PKT_PROTO_TRACE + if ((hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (hddCtxt->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + proto_type = cds_pkt_get_proto_type(skb, + hddCtxt->config-> + gEnableDebugLog, 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("ST:T:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("ST:T:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + + pAdapter->stats.tx_bytes += skb->len; + ++pAdapter->stats.tx_packets; + + /* Zero out skb's context buffer for the driver to use */ + cdf_mem_set(skb->cb, sizeof(skb->cb), 0); + NBUF_SET_PACKET_TRACK(skb, NBUF_TX_PKT_DATA_TRACK); + NBUF_UPDATE_TX_PKT_COUNT(skb, NBUF_TX_PKT_HDD); + + cdf_dp_trace_set_track(skb); + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_PTR_RECORD, + (uint8_t *)skb->data, sizeof(skb->data))); + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD, + (uint8_t *)skb->data, cdf_nbuf_len(skb))); + if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE) + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_HDD_PACKET_RECORD, + (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE], + (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE))); + + if (ol_tx_send_data_frame(STAId, (cdf_nbuf_t) skb, + proto_type) != NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_WARN, + "%s: Failed to send packet to txrx for staid:%d", + __func__, STAId); + goto drop_pkt; + } + dev->trans_start = jiffies; + + return NETDEV_TX_OK; + +drop_pkt: + + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)skb->data, cdf_nbuf_len(skb))); + if (cdf_nbuf_len(skb) > CDF_DP_TRACE_RECORD_SIZE) + DPTRACE(cdf_dp_trace(skb, CDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)&skb->data[CDF_DP_TRACE_RECORD_SIZE], + (cdf_nbuf_len(skb)-CDF_DP_TRACE_RECORD_SIZE))); + + ++pAdapter->stats.tx_dropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + kfree_skb(skb); + return NETDEV_TX_OK; +} + +/** + * hdd_ibss_get_sta_id() - Get the StationID using the Peer Mac address + * @pHddStaCtx: pointer to HDD Station Context + * @pMacAddress: pointer to Peer Mac address + * @staID: pointer to returned Station Index + * + * Return: CDF_STATUS_SUCCESS/CDF_STATUS_E_FAILURE + */ + +CDF_STATUS hdd_ibss_get_sta_id(hdd_station_ctx_t *pHddStaCtx, + struct cdf_mac_addr *pMacAddress, uint8_t *staId) +{ + uint8_t idx; + + for (idx = 0; idx < MAX_IBSS_PEERS; idx++) { + if (cdf_mem_compare(&pHddStaCtx->conn_info.peerMacAddress[idx], + pMacAddress, CDF_MAC_ADDR_SIZE)) { + *staId = pHddStaCtx->conn_info.staId[idx]; + return CDF_STATUS_SUCCESS; + } + } + + return CDF_STATUS_E_FAILURE; +} + +/** + * __hdd_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * + * This function is registered as a netdev ndo_tx_timeout method, and + * is invoked by the kernel if the driver takes too long to transmit a + * frame. + * + * Return: None + */ +static void __hdd_tx_timeout(struct net_device *dev) +{ + struct netdev_queue *txq; + int i = 0; + + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Transmission timeout occurred jiffies %lu trans_start %lu", + __func__, jiffies, dev->trans_start); + DPTRACE(cdf_dp_trace(NULL, CDF_DP_TRACE_HDD_TX_TIMEOUT, + NULL, 0)); + + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO, + "Queue%d status: %d txq->trans_start %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO, + "carrier state: %d", netif_carrier_ok(dev)); +} + +/** + * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR + * @dev: pointer to net_device structure + * + * Function called by OS if there is any timeout during transmission. + * Since HDD simply enqueues packet and returns control to OS right away, + * this would never be invoked + * + * Return: none + */ +void hdd_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +/** + * @hdd_init_tx_rx() - Initialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR, + FL("pAdapter is NULL")); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR, + FL("pAdapter is NULL")); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * hdd_rx_packet_cbk() - Receive packet handler + * @cds_context: pointer to CDS context + * @rxBuf: pointer to rx cdf_nbuf + * @staId: Station Id + * + * Receive callback registered with TL. TL will call this to notify + * the HDD when one or more packets were received for a registered + * STA. + * + * Return: CDF_STATUS_E_FAILURE if any errors encountered, + * CDF_STATUS_SUCCESS otherwise + */ +CDF_STATUS hdd_rx_packet_cbk(void *cds_context, cdf_nbuf_t rxBuf, uint8_t staId) +{ + hdd_adapter_t *pAdapter = NULL; + hdd_context_t *pHddCtx = NULL; + int rxstat; + struct sk_buff *skb = NULL; +#ifdef QCA_PKT_PROTO_TRACE + uint8_t proto_type; +#endif /* QCA_PKT_PROTO_TRACE */ + hdd_station_ctx_t *pHddStaCtx = NULL; + unsigned int cpu_index; + + /* Sanity check on inputs */ + if ((NULL == cds_context) || (NULL == rxBuf)) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return CDF_STATUS_E_FAILURE; + } + + pHddCtx = cds_get_context(CDF_MODULE_ID_HDD); + if (NULL == pHddCtx) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return CDF_STATUS_E_FAILURE; + } + + pAdapter = pHddCtx->sta_to_adapter[staId]; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hddLog(LOGE, + FL("invalid adapter %p or adapter has invalid magic"), + pAdapter); + return CDF_STATUS_E_FAILURE; + } + cpu_index = wlan_hdd_get_cpu(); + + skb = (struct sk_buff *)rxBuf; + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_FATAL, + "Magic cookie(%x) for adapter sanity verification is invalid", + pAdapter->magic); + return CDF_STATUS_E_FAILURE; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if ((pHddStaCtx->conn_info.proxyARPService) && + cfg80211_is_gratuitous_arp_unsolicited_na(skb)) { + ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index]; + CDF_TRACE(CDF_MODULE_ID_HDD_DATA, CDF_TRACE_LEVEL_INFO, + "%s: Dropping HS 2.0 Gratuitous ARP or Unsolicited NA", + __func__); + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + cdf_nbuf_free(skb); + return CDF_STATUS_SUCCESS; + } + + wlan_hdd_log_eapol(skb, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); + +#ifdef QCA_PKT_PROTO_TRACE + if ((pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (pHddCtx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + proto_type = cds_pkt_get_proto_type(skb, + pHddCtx->config-> + gEnableDebugLog, 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("ST:R:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("ST:R:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + + skb->dev = pAdapter->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += skb->len; +#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK + cdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock, + HDD_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); +#endif + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + cdf_net_buf_debug_release_skb(rxBuf); + + if (HDD_LRO_NO_RX == + hdd_lro_rx(pHddCtx, pAdapter, skb)) { + if (hdd_napi_enabled(HDD_NAPI_ANY)) + rxstat = netif_receive_skb(skb); + else + rxstat = netif_rx_ni(skb); + + if (NET_RX_SUCCESS == rxstat) + ++pAdapter->hdd_stats.hddTxRxStats. + rxDelivered[cpu_index]; + else + ++pAdapter->hdd_stats.hddTxRxStats. + rxRefused[cpu_index]; + + } else { + ++pAdapter->hdd_stats.hddTxRxStats. + rxDelivered[cpu_index]; + } + + pAdapter->dev->last_rx = jiffies; + + return CDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +/** + * wlan_hdd_get_eapol_params() - Function to extract EAPOL params + * @skb: sbb data + * @eapol_params: Pointer to hold the parsed EAPOL params + * @event_type: Event type to indicate Tx/Rx + * + * This function parses the input skb data and return the EAPOL parameters if + * the packet is an eapol packet. + * + * Return: -EINVAL if the packet is not an EAPOL packet and 0 on success + * + */ +static int wlan_hdd_get_eapol_params(struct sk_buff *skb, + struct host_event_wlan_eapol *eapol_params, + uint8_t event_type) +{ + bool ret; + uint8_t packet_type; + + ret = wlan_hdd_is_eapol(skb); + + if (!ret) + return -EINVAL; + + packet_type = (uint8_t)(*(uint8_t *) + (skb->data + HDD_EAPOL_PACKET_TYPE_OFFSET)); + + eapol_params->eapol_packet_type = packet_type; + eapol_params->eapol_key_info = (uint16_t)(*(uint16_t *) + (skb->data + HDD_EAPOL_KEY_INFO_OFFSET)); + eapol_params->event_sub_type = event_type; + eapol_params->eapol_rate = 0;/* As of now, zero */ + + cdf_mem_copy(eapol_params->dest_addr, + (skb->data + HDD_EAPOL_DEST_MAC_OFFSET), + sizeof(eapol_params->dest_addr)); + cdf_mem_copy(eapol_params->src_addr, + (skb->data + HDD_EAPOL_SRC_MAC_OFFSET), + sizeof(eapol_params->src_addr)); + return 0; +} + +/** + * wlan_hdd_event_eapol_log() - Function to log EAPOL events + * @eapol_params: Structure containing EAPOL params + * + * This function logs the parsed EAPOL params + * + * Return: None + * + */ +static void wlan_hdd_event_eapol_log(struct host_event_wlan_eapol eapol_params) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol); + + wlan_diag_event.event_sub_type = eapol_params.event_sub_type; + wlan_diag_event.eapol_packet_type = eapol_params.eapol_packet_type; + wlan_diag_event.eapol_key_info = eapol_params.eapol_key_info; + wlan_diag_event.eapol_rate = eapol_params.eapol_rate; + cdf_mem_copy(wlan_diag_event.dest_addr, + eapol_params.dest_addr, + sizeof(wlan_diag_event.dest_addr)); + cdf_mem_copy(wlan_diag_event.src_addr, + eapol_params.src_addr, + sizeof(wlan_diag_event.src_addr)); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL); +} + +/** + * wlan_hdd_log_eapol() - Logs the EAPOL parameters of a packet + * @skb: skb data + * @event_type: One of enum wifi_connectivity_events to indicate Tx/Rx + * + * This function parses the input skb data to get the EAPOL params and log + * them to user space, if the packet is EAPOL + * + * Return: None + * + */ +void wlan_hdd_log_eapol(struct sk_buff *skb, + uint8_t event_type) +{ + int ret; + struct host_event_wlan_eapol eapol_params; + + ret = wlan_hdd_get_eapol_params(skb, &eapol_params, event_type); + if (!ret) + wlan_hdd_event_eapol_log(eapol_params); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * hdd_reason_type_to_string() - return string conversion of reason type + * @reason: reason type + * + * This utility function helps log string conversion of reason type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_reason_type_to_string(enum netif_reason_type reason) +{ + switch (reason) { + CASE_RETURN_STRING(WLAN_CONTROL_PATH); + CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL); + CASE_RETURN_STRING(WLAN_FW_PAUSE); + CASE_RETURN_STRING(WLAN_TX_ABORT); + CASE_RETURN_STRING(WLAN_VDEV_STOP); + CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED); + CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION); + default: + return "Unknown"; + } +} + +/** + * hdd_action_type_to_string() - return string conversion of action type + * @action: action type + * + * This utility function helps log string conversion of action_type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_action_type_to_string(enum netif_action_type action) +{ + + switch (action) { + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE); + CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE_N_CARRIER); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF); + default: + return "Unknown"; + } +} + +/** + * wlan_hdd_update_queue_oper_stats - update queue operation statistics + * @adapter: adapter handle + * @action: action type + * @reason: reason type + */ +static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + switch (action) { + case WLAN_STOP_ALL_NETIF_QUEUE: + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + case WLAN_NETIF_TX_DISABLE: + case WLAN_NETIF_TX_DISABLE_N_CARRIER: + adapter->queue_oper_stats[reason].pause_count++; + break; + case WLAN_START_ALL_NETIF_QUEUE: + case WLAN_WAKE_ALL_NETIF_QUEUE: + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + adapter->queue_oper_stats[reason].unpause_count++; + break; + default: + break; + } + + return; +} + +/** + * wlan_hdd_netif_queue_control() - Use for netif_queue related actions + * @adapter: adapter handle + * @action: action type + * @reason: reason type + * + * This is single function which is used for netif_queue related + * actions like start/stop of network queues and on/off carrier + * option. + * + * Return: None + */ +void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) || + (!adapter->dev)) { + hdd_err("adapter is invalid"); + return; + } + + switch (action) { + + case WLAN_NETIF_CARRIER_ON: + netif_carrier_on(adapter->dev); + break; + + case WLAN_NETIF_CARRIER_OFF: + netif_carrier_off(adapter->dev); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) + netif_tx_stop_all_queues(adapter->dev); + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) + netif_tx_start_all_queues(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_WAKE_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) + netif_tx_wake_all_queues(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) + netif_tx_stop_all_queues(adapter->dev); + adapter->pause_map |= (1 << reason); + netif_carrier_off(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + netif_carrier_on(adapter->dev); + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) + netif_tx_start_all_queues(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_TX_DISABLE: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) + netif_tx_disable(adapter->dev); + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_TX_DISABLE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) + netif_tx_disable(adapter->dev); + adapter->pause_map |= (1 << reason); + netif_carrier_off(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + default: + hdd_err("unsupported action %d", action); + } + + spin_lock_bh(&adapter->pause_map_lock); + if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED)) + wlan_hdd_process_peer_unauthorised_pause(adapter); + spin_unlock_bh(&adapter->pause_map_lock); + + + wlan_hdd_update_queue_oper_stats(adapter, action, reason); + + adapter->queue_oper_history[adapter->history_index].time = + cdf_system_ticks(); + adapter->queue_oper_history[adapter->history_index].netif_action = + action; + adapter->queue_oper_history[adapter->history_index].netif_reason = + reason; + adapter->queue_oper_history[adapter->history_index].pause_map = + adapter->pause_map; + if (++adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY) + adapter->history_index = 0; + + return; +} + diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c new file mode 100644 index 0000000000..91076fe511 --- /dev/null +++ b/core/hdd/src/wlan_hdd_wext.c @@ -0,0 +1,10708 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_wext.c + * + * Linux Wireless Extensions Implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sir_params.h" +#include "csr_api.h" +#include "csr_inside_api.h" +#if defined WLAN_FEATURE_VOWIFI +#include "sme_rrm_internal.h" +#endif +#include +#include "dot11f.h" +#include +#include +#include +#include "utils_api.h" +#include "wlan_hdd_p2p.h" +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif + +#include "cds_ieee80211_common.h" +#include "ol_if_athvar.h" +#include "dbglog_host.h" +#include "wma.h" + +#include "wlan_hdd_power.h" +#include "qwlan_version.h" +#include "wlan_hdd_host_offload.h" + +#include +#include + +#include "wlan_hdd_misc.h" + +#include "qc_sap_ioctl.h" +#include "sme_api.h" +#include "wma_types.h" +#include "cdf_trace.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_scan.h" +#include "sme_power_save_api.h" +#include "cds_concurrency.h" +#include "wlan_hdd_conc_ut.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_napi.h" + +#ifdef QCA_PKT_PROTO_TRACE +#include "cds_packet.h" +#endif /* QCA_PKT_PROTO_TRACE */ + +#define HDD_FINISH_ULA_TIME_OUT 800 +#define HDD_SET_MCBC_FILTERS_TO_FW 1 +#define HDD_DELETE_MCBC_FILTERS_FROM_FW 0 + +extern int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, eCsrBand eBand); +static int ioctl_debug; +module_param(ioctl_debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +/* To Validate Channel against the Frequency and Vice-Versa */ +static const hdd_freq_chan_map_t freq_chan_map[] = { + {2412, 1}, {2417, 2}, {2422, 3}, {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14}, {4920, 240}, {4940, 244}, {4960, 248}, + {4980, 252}, {5040, 208}, {5060, 212}, {5080, 216}, {5180, 36}, + {5200, 40}, {5220, 44}, {5240, 48}, {5260, 52}, {5280, 56}, + {5300, 60}, {5320, 64}, {5500, 100}, {5520, 104}, {5540, 108}, + {5560, 112}, {5580, 116}, {5600, 120}, {5620, 124}, {5640, 128}, + {5660, 132}, {5680, 136}, {5700, 140}, {5720, 144}, {5745, 149}, + {5765, 153}, {5785, 157}, {5805, 161}, {5825, 165}, {5852, 170}, + {5855, 171}, {5860, 172}, {5865, 173}, {5870, 174}, {5875, 175}, + {5880, 176}, {5885, 177}, {5890, 178}, {5895, 179}, {5900, 180}, + {5905, 181}, {5910, 182}, {5915, 183}, {5920, 184} }; + +#define FREQ_CHAN_MAP_TABLE_SIZE \ + (sizeof(freq_chan_map) / sizeof(freq_chan_map[0])) + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_NONE (SIOCIWFIRSTPRIV + 0) +#define WE_SET_11D_STATE 1 +#define WE_WOWL 2 +#define WE_SET_POWER 3 +#define WE_SET_MAX_ASSOC 4 +#define WE_SET_SCAN_DISABLE 5 +#define WE_SET_DATA_INACTIVITY_TO 6 +#define WE_SET_MAX_TX_POWER 7 +#define WE_SET_HIGHER_DTIM_TRANSITION 8 +#define WE_SET_TM_LEVEL 9 +#define WE_SET_PHYMODE 10 +#define WE_SET_NSS 11 +#define WE_SET_LDPC 12 +#define WE_SET_TX_STBC 13 +#define WE_SET_RX_STBC 14 +#define WE_SET_SHORT_GI 15 +#define WE_SET_RTSCTS 16 +#define WE_SET_CHWIDTH 17 +#define WE_SET_ANI_EN_DIS 18 +#define WE_SET_ANI_POLL_PERIOD 19 +#define WE_SET_ANI_LISTEN_PERIOD 20 +#define WE_SET_ANI_OFDM_LEVEL 21 +#define WE_SET_ANI_CCK_LEVEL 22 +#define WE_SET_DYNAMIC_BW 23 +#define WE_SET_TX_CHAINMASK 24 +#define WE_SET_RX_CHAINMASK 25 +#define WE_SET_11N_RATE 26 +#define WE_SET_AMPDU 27 +#define WE_SET_AMSDU 28 +#define WE_SET_TXPOW_2G 29 +#define WE_SET_TXPOW_5G 30 +/* Private ioctl for firmware debug log */ +#define WE_DBGLOG_LOG_LEVEL 31 +#define WE_DBGLOG_VAP_ENABLE 32 +#define WE_DBGLOG_VAP_DISABLE 33 +#define WE_DBGLOG_MODULE_ENABLE 34 +#define WE_DBGLOG_MODULE_DISABLE 35 +#define WE_DBGLOG_MOD_LOG_LEVEL 36 +#define WE_DBGLOG_TYPE 37 +#define WE_SET_TXRX_FWSTATS 38 +#define WE_SET_VHT_RATE 39 +#define WE_DBGLOG_REPORT_ENABLE 40 +#define WE_TXRX_FWSTATS_RESET 41 +#define WE_SET_MAX_TX_POWER_2_4 42 +#define WE_SET_MAX_TX_POWER_5_0 43 +#define WE_SET_POWER_GATING 44 +/* Private ioctl for packet powe save */ +#define WE_PPS_PAID_MATCH 45 +#define WE_PPS_GID_MATCH 46 +#define WE_PPS_EARLY_TIM_CLEAR 47 +#define WE_PPS_EARLY_DTIM_CLEAR 48 +#define WE_PPS_EOF_PAD_DELIM 49 +#define WE_PPS_MACADDR_MISMATCH 50 +#define WE_PPS_DELIM_CRC_FAIL 51 +#define WE_PPS_GID_NSTS_ZERO 52 +#define WE_PPS_RSSI_CHECK 53 +#define WE_SET_SAP_AUTO_CHANNEL_SELECTION 54 +#define WE_SET_HTSMPS 55 +/* Private ioctl for QPower */ +#define WE_SET_QPOWER_MAX_PSPOLL_COUNT 56 +#define WE_SET_QPOWER_MAX_TX_BEFORE_WAKE 57 +#define WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 58 +#define WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 59 + +#define WE_SET_BURST_ENABLE 60 +#define WE_SET_BURST_DUR 61 +/* GTX Commands */ +#define WE_SET_GTX_HT_MCS 62 +#define WE_SET_GTX_VHT_MCS 63 +#define WE_SET_GTX_USRCFG 64 +#define WE_SET_GTX_THRE 65 +#define WE_SET_GTX_MARGIN 66 +#define WE_SET_GTX_STEP 67 +#define WE_SET_GTX_MINTPC 68 +#define WE_SET_GTX_BWMASK 69 +/* Private ioctl to configure MCC home channels time quota and latency */ +#define WE_MCC_CONFIG_LATENCY 70 +#define WE_MCC_CONFIG_QUOTA 71 +/* Private IOCTL for debug connection issues */ +#define WE_SET_DEBUG_LOG 72 +#ifdef WE_SET_TX_POWER +#undef WE_SET_TX_POWER +#endif +#define WE_SET_TX_POWER 74 +/* Private ioctl for earlyrx power save feature */ +#define WE_SET_EARLY_RX_ADJUST_ENABLE 75 +#define WE_SET_EARLY_RX_TGT_BMISS_NUM 76 +#define WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE 77 +#define WE_SET_EARLY_RX_SLOP_STEP 78 +#define WE_SET_EARLY_RX_INIT_SLOP 79 +#define WE_SET_EARLY_RX_ADJUST_PAUSE 80 +#define WE_SET_MC_RATE 81 +#define WE_SET_EARLY_RX_DRIFT_SAMPLE 82 +/* Private ioctl for packet power save */ +#define WE_PPS_5G_EBT 83 +#define WE_SET_CTS_CBW 84 +#define WE_DUMP_STATS 85 +#define WE_CLEAR_STATS 86 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1) +#define WE_GET_11D_STATE 1 +#define WE_IBSS_STATUS 2 +#define WE_SET_SAP_CHANNELS 3 +#define WE_GET_WLAN_DBG 4 +#define WE_GET_MAX_ASSOC 6 +/* 7 is unused */ +#define WE_GET_SAP_AUTO_CHANNEL_SELECTION 8 +#define WE_GET_CONCURRENCY_MODE 9 +#define WE_GET_NSS 11 +#define WE_GET_LDPC 12 +#define WE_GET_TX_STBC 13 +#define WE_GET_RX_STBC 14 +#define WE_GET_SHORT_GI 15 +#define WE_GET_RTSCTS 16 +#define WE_GET_CHWIDTH 17 +#define WE_GET_ANI_EN_DIS 18 +#define WE_GET_ANI_POLL_PERIOD 19 +#define WE_GET_ANI_LISTEN_PERIOD 20 +#define WE_GET_ANI_OFDM_LEVEL 21 +#define WE_GET_ANI_CCK_LEVEL 22 +#define WE_GET_DYNAMIC_BW 23 +#define WE_GET_TX_CHAINMASK 24 +#define WE_GET_RX_CHAINMASK 25 +#define WE_GET_11N_RATE 26 +#define WE_GET_AMPDU 27 +#define WE_GET_AMSDU 28 +#define WE_GET_TXPOW_2G 29 +#define WE_GET_TXPOW_5G 30 +#define WE_GET_POWER_GATING 31 +#define WE_GET_PPS_PAID_MATCH 32 +#define WE_GET_PPS_GID_MATCH 33 +#define WE_GET_PPS_EARLY_TIM_CLEAR 34 +#define WE_GET_PPS_EARLY_DTIM_CLEAR 35 +#define WE_GET_PPS_EOF_PAD_DELIM 36 +#define WE_GET_PPS_MACADDR_MISMATCH 37 +#define WE_GET_PPS_DELIM_CRC_FAIL 38 +#define WE_GET_PPS_GID_NSTS_ZERO 39 +#define WE_GET_PPS_RSSI_CHECK 40 +/* Private ioctl for QPower */ +#define WE_GET_QPOWER_MAX_PSPOLL_COUNT 41 +#define WE_GET_QPOWER_MAX_TX_BEFORE_WAKE 42 +#define WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 43 +#define WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 44 +#define WE_GET_BURST_ENABLE 45 +#define WE_GET_BURST_DUR 46 +/* GTX Commands */ +#define WE_GET_GTX_HT_MCS 47 +#define WE_GET_GTX_VHT_MCS 48 +#define WE_GET_GTX_USRCFG 49 +#define WE_GET_GTX_THRE 50 +#define WE_GET_GTX_MARGIN 51 +#define WE_GET_GTX_STEP 52 +#define WE_GET_GTX_MINTPC 53 +#define WE_GET_GTX_BWMASK 54 +#define WE_GET_TEMPERATURE 56 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2) + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_CHAR_GET_NONE (SIOCIWFIRSTPRIV + 3) +#define WE_WOWL_ADD_PTRN 1 +#define WE_WOWL_DEL_PTRN 2 +#if defined WLAN_FEATURE_VOWIFI +#define WE_NEIGHBOR_REPORT_REQUEST 3 +#endif +#define WE_SET_AP_WPS_IE 4 /* This is called in station mode to set probe rsp ie. */ +#define WE_SET_CONFIG 5 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 4) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define WE_SET_SAP_CHANNELS 3 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 5) +#define WE_WLAN_VERSION 1 +#define WE_GET_STATS 2 +#define WE_GET_CFG 3 +#define WE_GET_WMM_STATUS 4 +#define WE_GET_CHANNEL_LIST 5 +#ifdef WLAN_FEATURE_11AC +#define WE_GET_RSSI 6 +#endif +#ifdef FEATURE_WLAN_TDLS +#define WE_GET_TDLS_PEERS 8 +#endif +#ifdef WLAN_FEATURE_11W +#define WE_GET_11W_INFO 9 +#endif +#define WE_GET_STATES 10 + +#define WE_GET_PHYMODE 12 +#ifdef FEATURE_OEM_DATA_SUPPORT +#define WE_GET_OEM_DATA_CAP 13 +#endif +#define WE_GET_SNR 14 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6) +#define WE_SET_REASSOC_TRIGGER 8 + +#define WE_DUMP_AGC_START 11 +#define WE_DUMP_AGC 12 +#define WE_DUMP_CHANINFO_START 13 +#define WE_DUMP_CHANINFO 14 +#define WE_DUMP_WATCHDOG 15 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define WE_DUMP_PCIE_LOG 16 +#endif +#define WE_GET_RECOVERY_STAT 17 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7) + +#define WE_P2P_NOA_CMD 2 + +/* subcommands 3 and 4 are unused */ + +#ifdef FEATURE_WLAN_TDLS +#define WE_TDLS_CONFIG_PARAMS 5 +#endif + +#define WE_UNIT_TEST_CMD 7 + +#define WE_MTRACE_DUMP_CMD 8 +#define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD 9 + + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WE_LED_FLASHING_PARAM 10 +#endif + +#define WE_POLICY_MANAGER_CLIST_CMD 11 +#define WE_POLICY_MANAGER_DLIST_CMD 12 +#define WE_POLICY_MANAGER_DBS_CMD 13 +#define WE_POLICY_MANAGER_PCL_CMD 14 +#define WE_POLICY_MANAGER_CINFO_CMD 15 +#define WE_POLICY_MANAGER_ULIST_CMD 16 +#define WE_POLICY_MANAGER_QUERY_ACTION_CMD 17 +#define WE_POLICY_MANAGER_QUERY_ALLOW_CMD 18 +#define WE_POLICY_MANAGER_SCENARIO_CMD 19 +#define WE_POLICY_SET_HW_MODE_CMD 20 + +#define WE_SET_DUAL_MAC_SCAN_CONFIG 21 +#define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22 + +#ifdef FEATURE_WLAN_TDLS +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 11 +#else +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 9 +#endif + +/* Private ioctls (with no sub-ioctls) */ +/* note that they must be odd so that they have "get" semantics */ +#define WLAN_PRIV_ADD_TSPEC (SIOCIWFIRSTPRIV + 9) +#define WLAN_PRIV_DEL_TSPEC (SIOCIWFIRSTPRIV + 11) +#define WLAN_PRIV_GET_TSPEC (SIOCIWFIRSTPRIV + 13) + +/* (SIOCIWFIRSTPRIV + 8) is currently unused */ +/* (SIOCIWFIRSTPRIV + 10) is currently unused */ +/* (SIOCIWFIRSTPRIV + 12) is currently unused */ +/* (SIOCIWFIRSTPRIV + 14) is currently unused */ +/* (SIOCIWFIRSTPRIV + 15) is currently unused */ +/* (SIOCIWFIRSTPRIV + 16) is currently unused */ +/* (SIOCIWFIRSTPRIV + 17) is currently unused */ +/* (SIOCIWFIRSTPRIV + 19) is currently unused */ + +#ifdef WLAN_FEATURE_VOWIFI_11R +#define WLAN_PRIV_SET_FTIES (SIOCIWFIRSTPRIV + 20) +#endif + +/* Private ioctl for setting the host offload feature */ +#define WLAN_PRIV_SET_HOST_OFFLOAD (SIOCIWFIRSTPRIV + 18) + +/* Private ioctl to get the statistics */ +#define WLAN_GET_WLAN_STATISTICS (SIOCIWFIRSTPRIV + 21) + +/* Private ioctl to set the Keep Alive Params */ +#define WLAN_SET_KEEPALIVE_PARAMS (SIOCIWFIRSTPRIV + 22) + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/* Private ioctl to set the packet filtering params */ +#define WLAN_SET_PACKET_FILTER_PARAMS (SIOCIWFIRSTPRIV + 23) +#endif + + +#ifdef FEATURE_WLAN_SCAN_PNO +/* Private ioctl to get the statistics */ +#define WLAN_SET_PNO (SIOCIWFIRSTPRIV + 24) +#endif + +#define WLAN_SET_BAND_CONFIG (SIOCIWFIRSTPRIV + 25) + +/* (SIOCIWFIRSTPRIV + 26) is currently unused */ +/* (SIOCIWFIRSTPRIV + 27) is currently unused */ + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#define WE_SET_SMPS_PARAM 1 +#ifdef DEBUG +#define WE_SET_FW_CRASH_INJECT 2 +#endif +#define WE_DUMP_DP_TRACE_LEVEL 3 +#define DUMP_DP_TRACE 0 + +/* (SIOCIWFIRSTPRIV + 29) is currently unused */ + +/* 802.11p IOCTL */ +#define WLAN_SET_DOT11P_CHANNEL_SCHED (SIOCIWFIRSTPRIV + 30) + +#define WLAN_GET_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#define WLAN_STATS_INVALID 0 +#define WLAN_STATS_RETRY_CNT 1 +#define WLAN_STATS_MUL_RETRY_CNT 2 +#define WLAN_STATS_TX_FRM_CNT 3 +#define WLAN_STATS_RX_FRM_CNT 4 +#define WLAN_STATS_FRM_DUP_CNT 5 +#define WLAN_STATS_FAIL_CNT 6 +#define WLAN_STATS_RTS_FAIL_CNT 7 +#define WLAN_STATS_ACK_FAIL_CNT 8 +#define WLAN_STATS_RTS_SUC_CNT 9 +#define WLAN_STATS_RX_DISCARD_CNT 10 +#define WLAN_STATS_RX_ERROR_CNT 11 +#define WLAN_STATS_TX_BYTE_CNT 12 + +#define WLAN_STATS_RX_BYTE_CNT 13 +#define WLAN_STATS_RX_RATE 14 +#define WLAN_STATS_TX_RATE 15 + +#define WLAN_STATS_RX_UC_BYTE_CNT 16 +#define WLAN_STATS_RX_MC_BYTE_CNT 17 +#define WLAN_STATS_RX_BC_BYTE_CNT 18 +#define WLAN_STATS_TX_UC_BYTE_CNT 19 +#define WLAN_STATS_TX_MC_BYTE_CNT 20 +#define WLAN_STATS_TX_BC_BYTE_CNT 21 + +#define FILL_TLV(__p, __type, __size, __val, __tlen) do { \ + if ((__tlen + __size + 2) < WE_MAX_STR_LEN) { \ + *__p++ = __type; \ + *__p++ = __size; \ + memcpy(__p, __val, __size); \ + __p += __size; \ + __tlen += __size + 2; \ + } else { \ + hddLog(CDF_TRACE_LEVEL_ERROR, "FILL_TLV Failed!!!"); \ + } \ + } while (0) + +#define VERSION_VALUE_MAX_LEN 32 + +#define TX_PER_TRACKING_DEFAULT_RATIO 5 +#define TX_PER_TRACKING_MAX_RATIO 10 +#define TX_PER_TRACKING_DEFAULT_WATERMARK 5 + +#define WLAN_ADAPTER 0 +#define P2P_ADAPTER 1 + +/** + * mem_alloc_copy_from_user_helper - copy from user helper + * @wrqu_data: wireless extensions request data + * @len: length of @wrqu_data + * + * Helper function to allocate buffer and copy user data. + * + * Return: On success return a pointer to a kernel buffer containing a + * copy of the userspace data (with an additional NUL character + * appended for safety). On failure return %NULL. + */ +void *mem_alloc_copy_from_user_helper(const __user void *wrqu_data, size_t len) +{ + u8 *ptr = NULL; + + /* in order to protect the code, an extra byte is post + * appended to the buffer and the null termination is added. + * However, when allocating (len+1) byte of memory, we need to + * make sure that there is no uint overflow when doing + * addition. In theory check len < UINT_MAX protects the uint + * overflow. For wlan private ioctl, the buffer size is much + * less than UINT_MAX, as a good guess, now, it is assumed + * that the private command buffer size is no greater than 4K + * (4096 bytes). So we use 4096 as the upper boundary for now. + */ + if (len > MAX_USER_COMMAND_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Invalid length"); + return NULL; + } + + ptr = kmalloc(len + 1, GFP_KERNEL); + if (NULL == ptr) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "unable to allocate memory"); + return NULL; + } + + if (copy_from_user(ptr, wrqu_data, len)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: failed to copy data to user buffer", __func__); + kfree(ptr); + return NULL; + } + ptr[len] = '\0'; + return ptr; +} + +/** + * hdd_priv_get_data() - Get pointer to ioctl private data + * @p_priv_data: pointer to iw_point struct to be filled + * @wrqu: Pointer to IOCTL Data received from userspace + * + * Helper function to get compatible struct iw_point passed to ioctl + * + * Return - 0 if p_priv_data successfully filled, error otherwise + */ +int hdd_priv_get_data(struct iw_point *p_priv_data, union iwreq_data *wrqu) +{ + if ((NULL == p_priv_data) || (NULL == wrqu)) { + return -EINVAL; + } +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + struct compat_iw_point *p_compat_priv_data; + + /* Compat task: + * typecast to compat structure and copy the members. + */ + p_compat_priv_data = (struct compat_iw_point *)&wrqu->data; + + p_priv_data->pointer = compat_ptr(p_compat_priv_data->pointer); + p_priv_data->length = p_compat_priv_data->length; + p_priv_data->flags = p_compat_priv_data->flags; + } else { +#endif /* #ifdef CONFIG_COMPAT */ + + /* Non compat task: directly copy the structure. */ + memcpy(p_priv_data, &wrqu->data, sizeof(struct iw_point)); + +#ifdef CONFIG_COMPAT + } +#endif /* #ifdef CONFIG_COMPAT */ + + return 0; +} + + +/** + * hdd_wlan_get_stats() - Get txrx stats in SAP mode + * @pAdapter: Pointer to the hdd adapter. + * @length: Size of the data copied + * @buffer: Pointer to char buffer. + * @buf_len: Length of the char buffer. + * + * This function called when the "iwpriv wlan0 get_stats" command is given. + * It used to collect the txrx stats when the device is configured in SAP mode. + * + * Return - none + */ +void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length, + char *buffer, uint16_t buf_len) +{ + hdd_tx_rx_stats_t *pStats = &pAdapter->hdd_stats.hddTxRxStats; + uint32_t len = 0; + uint32_t total_rx_pkt = 0, total_rx_dropped = 0; + uint32_t total_rx_delv = 0, total_rx_refused = 0; + int i = 0; + + for (; i < NUM_CPUS; i++) { + total_rx_pkt += pStats->rxPackets[i]; + total_rx_dropped += pStats->rxDropped[i]; + total_rx_delv += pStats->rxDelivered[i]; + total_rx_refused += pStats->rxRefused[i]; + } + + len = scnprintf(buffer, buf_len, + "\nTransmit" + "\ncalled %u, dropped %u," + "\n dropped BK %u, BE %u, VI %u, VO %u" + "\n classified BK %u, BE %u, VI %u, VO %u" + "\ncompleted %u," + "\n\nReceive Total" + "\n packets %u, dropped %u, delivered %u, refused %u" + "\n", + pStats->txXmitCalled, + pStats->txXmitDropped, + + pStats->txXmitDroppedAC[SME_AC_BK], + pStats->txXmitDroppedAC[SME_AC_BE], + pStats->txXmitDroppedAC[SME_AC_VI], + pStats->txXmitDroppedAC[SME_AC_VO], + + pStats->txXmitClassifiedAC[SME_AC_BK], + pStats->txXmitClassifiedAC[SME_AC_BE], + pStats->txXmitClassifiedAC[SME_AC_VI], + pStats->txXmitClassifiedAC[SME_AC_VO], + + pStats->txCompleted, + total_rx_pkt, total_rx_dropped, total_rx_delv, total_rx_refused + ); + + for (i = 0; i < NUM_CPUS; i++) { + len += scnprintf(buffer + len, buf_len - len, + "\nReceive CPU: %d" + "\n packets %u, dropped %u, delivered %u, refused %u", + i, pStats->rxPackets[i], pStats->rxDropped[i], + pStats->rxDelivered[i], pStats->rxRefused[i]); + } + + len += scnprintf(buffer + len, buf_len - len, + "\n\nTX_FLOW" + "\nCurrent status: %s" + "\ntx-flow timer start count %u" + "\npause count %u, unpause count %u", + (pStats->is_txflow_paused == true ? "PAUSED" : "UNPAUSED"), + pStats->txflow_timer_cnt, + pStats->txflow_pause_cnt, + pStats->txflow_unpause_cnt); + + len += ol_txrx_stats(pAdapter->sessionId, + &buffer[len], (buf_len - len)); + + len += hdd_napi_stats(buffer + len, buf_len - len, + NULL, hdd_napi_get_all()); + + *length = len + 1; +} + +/** + * hdd_wlan_dump_stats() - display dump Stats + * @adapter: adapter handle + * @value: value from user + * + * Return: none + */ +void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + switch (value) { + + case WLAN_TXRX_HIST_STATS: + wlan_hdd_display_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_display_netif_queue_history(hdd_ctx); + break; + default: + ol_txrx_display_stats(value); + break; + } +} + +/** + * hdd_wlan_get_version() - Get driver version information + * @pAdapter: Pointer to the adapter. + * @wrqu: Pointer to IOCTL REQUEST Data. + * @extra: Pointer to destination buffer + * + * This function is used to get Wlan Driver, Firmware, & Hardware + * Version information. If @wrqu and @extra are specified, then the + * version string is returned. Otherwise it is simply printed to the + * kernel log. + * + * Return: none + */ +void hdd_wlan_get_version(hdd_adapter_t *pAdapter, union iwreq_data *wrqu, + char *extra) +{ + tSirVersionString wcnss_SW_version; + const char *pSWversion; + const char *pHWversion; + uint32_t MSPId = 0, mSPId = 0, SIId = 0, CRMId = 0; + + hdd_context_t *pHddContext; + + pHddContext = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddContext) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s:Invalid context, HDD context is null", __func__); + goto error; + } + + snprintf(wcnss_SW_version, sizeof(tSirVersionString), "%08x", + pHddContext->target_fw_version); + + pSWversion = wcnss_SW_version; + MSPId = (pHddContext->target_fw_version & 0xf0000000) >> 28; + mSPId = (pHddContext->target_fw_version & 0xf000000) >> 24; + SIId = (pHddContext->target_fw_version & 0xf00000) >> 20; + CRMId = pHddContext->target_fw_version & 0x7fff; + + pHWversion = pHddContext->target_hw_name; + + if (wrqu && extra) { + wrqu->data.length = + scnprintf(extra, WE_MAX_STR_LEN, + "Host SW:%s, FW:%d.%d.%d.%d, HW:%s", + QWLAN_VERSIONSTR, + MSPId, mSPId, SIId, CRMId, pHWversion); + } else { + pr_info("Host SW:%s, FW:%d.%d.%d.%d, HW:%s\n", + QWLAN_VERSIONSTR, + MSPId, mSPId, SIId, CRMId, pHWversion); + } +error: + return; +} + +/** + * hdd_wlan_get_rts_threshold() - Get RTS threshold + * @pAdapter: adapter upon which the request was received + * @wrqu: pointer to the ioctl request + * + * This function retrieves the current RTS threshold value and stores + * it in the ioctl request structure + * + * Return: 0 if valid data was returned, non-zero on error + */ +int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, union iwreq_data *wrqu) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t threshold = 0; + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER(); + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL", __func__); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (CDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_RTS_THRESHOLD, &threshold)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL + ("failed to get ini parameter, WNI_CFG_RTS_THRESHOLD")); + return -EIO; + } + wrqu->rts.value = threshold; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("Rts-Threshold=%d!!"), wrqu->rts.value); + + EXIT(); + + return 0; +} + +/** + * hdd_wlan_get_frag_threshold() - Get fragmentation threshold + * @pAdapter: adapter upon which the request was received + * @wrqu: pointer to the ioctl request + * + * This function retrieves the current fragmentation threshold value + * and stores it in the ioctl request structure + * + * Return: 0 if valid data was returned, non-zero on error + */ +int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t threshold = 0, status = 0; + hdd_context_t *hdd_ctx; + + ENTER(); + + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Adapter is NULL", __func__); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (sme_cfg_get_int(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, &threshold) + != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL + ("failed to get ini parameter, WNI_CFG_FRAGMENTATION_THRESHOLD")); + return -EIO; + } + wrqu->frag.value = threshold; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("Frag-Threshold=%d!!"), wrqu->frag.value); + + EXIT(); + + return 0; +} + +/** + * hdd_wlan_get_freq() - Convert channel to frequency + * @channel: channel to be converted + * @pfreq: where to store the frequency + * + * Return: 1 on success, otherwise a negative errno + */ +int hdd_wlan_get_freq(uint32_t channel, uint32_t *pfreq) +{ + int i; + if (channel > 0) { + for (i = 0; i < FREQ_CHAN_MAP_TABLE_SIZE; i++) { + if (channel == freq_chan_map[i].chan) { + *pfreq = freq_chan_map[i].freq; + return 1; + } + } + } + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("Invalid channel no=%d!!"), channel); + return -EINVAL; +} + +/** + * hdd_is_auth_type_rsn() - RSN authentication type check + * @authType: authentication type to be checked + * + * Return: true if @authType is an RSN authentication type, + * false if it is not + */ +static bool hdd_is_auth_type_rsn(eCsrAuthType authType) +{ + bool rsnType = false; + /* is the authType supported? */ + switch (authType) { + case eCSR_AUTH_TYPE_NONE: /* never used */ + rsnType = false; + break; + /* MAC layer authentication types */ + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + rsnType = false; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + rsnType = false; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + rsnType = false; + break; + + /* Upper layer authentication types */ + case eCSR_AUTH_TYPE_WPA: + rsnType = true; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + rsnType = true; + break; + case eCSR_AUTH_TYPE_WPA_NONE: + rsnType = true; + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN: +#endif + case eCSR_AUTH_TYPE_RSN: + rsnType = true; + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN_PSK: +#endif + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + rsnType = true; + break; + /* case eCSR_AUTH_TYPE_FAILED: */ + case eCSR_AUTH_TYPE_UNKNOWN: + rsnType = false; + break; + default: + hddLog(LOGE, FL("unknown authType %d, treat as open"), + authType); + rsnType = false; + break; + } + hddLog(LOG1, FL("called with authType: %d, returned: %d"), + authType, rsnType); + return rsnType; +} + +/** + * hdd_get_rssi_cb() - "Get RSSI" callback function + * @rssi: Current RSSI of the station + * @staId: ID of the station + * @pContext: opaque context originally passed to SME. HDD always passes + * a &struct statsContext + * + * Return: None + */ +static void hdd_get_rssi_cb(int8_t rssi, uint32_t staId, void *pContext) +{ + struct statsContext *pStatsContext; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: rssi [%d] STA [%d] pContext [%p]\n", + __func__, (int)rssi, (int)staId, pContext); + } + + if (NULL == pContext) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, pContext [%p]", __func__, pContext); + return; + } + + pStatsContext = pContext; + pAdapter = pStatsContext->pAdapter; + + /* there is a race condition that exists between this callback + * function and the caller since the caller could time out + * either before or while this code is executing. we use a + * spinlock to serialize these actions + */ + spin_lock(&hdd_context_lock); + + if ((NULL == pAdapter) || + (RSSI_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the rssi */ + pAdapter->rssi = rssi; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * hdd_get_snr_cb() - "Get SNR" callback function + * @snr: Current SNR of the station + * @staId: ID of the station + * @pContext: opaque context originally passed to SME. HDD always passes + * a &struct statsContext + * + * Return: None + */ +static void hdd_get_snr_cb(int8_t snr, uint32_t staId, void *pContext) +{ + struct statsContext *pStatsContext; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: snr [%d] STA [%d] pContext [%p]\n", + __func__, (int)snr, (int)staId, pContext); + } + + if (NULL == pContext) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, pContext [%p]", __func__, pContext); + return; + } + + pStatsContext = pContext; + pAdapter = pStatsContext->pAdapter; + + /* there is a race condition that exists between this callback + * function and the caller since the caller could time out + * either before or while this code is executing. we use a + * spinlock to serialize these actions + */ + spin_lock(&hdd_context_lock); + + if ((NULL == pAdapter) || (SNR_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the snr */ + pAdapter->snr = snr; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_rssi() - Get the current RSSI + * @pAdapter: adapter upon which the measurement is requested + * @rssi_value: pointer to where the RSSI should be returned + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value) +{ + struct statsContext context; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + CDF_STATUS hstatus; + unsigned long rc; + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter", __func__); + return CDF_STATUS_E_FAULT; + } + if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + /* return a cached value */ + *rssi_value = pAdapter->rssi; + return CDF_STATUS_SUCCESS; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_err("Not associated!, return last connected AP rssi!"); + *rssi_value = pAdapter->rssi; + return CDF_STATUS_SUCCESS; + } + + if (pHddStaCtx->hdd_ReassocScenario) { + hdd_info("Roaming in progress, return cached RSSI"); + *rssi_value = pAdapter->rssi; + return CDF_STATUS_SUCCESS; + } + + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = RSSI_CONTEXT_MAGIC; + + hstatus = sme_get_rssi(pHddCtx->hHal, hdd_get_rssi_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, pAdapter->rssi, + &context, pHddCtx->pcds_context); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Unable to retrieve RSSI", + __func__); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context.completion, + msecs_to_jiffies + (WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving RSSI")); + /* we'll now returned a cached value below */ + } + } + + /* either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. if + * we never sent a request or if we sent a request and got a + * response, we want to clear the magic out of paranoia. if + * we timed out there is a race condition such that the + * callback function could be executing at the same time we + * are. of primary concern is if the callback function had + * already verified the "magic" but had not yet set the + * completion variable when a timeout occurred. we serialize + * these activities by invalidating the magic while holding a + * shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + *rssi_value = pAdapter->rssi; + + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_get_snr() - Get the current SNR + * @pAdapter: adapter upon which the measurement is requested + * @snr: pointer to where the SNR should be returned + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error + */ +CDF_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, int8_t *snr) +{ + struct statsContext context; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + CDF_STATUS hstatus; + unsigned long rc; + int valid; + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Invalid context, pAdapter", __func__); + return CDF_STATUS_E_FAULT; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + valid = wlan_hdd_validate_context(pHddCtx); + if (0 != valid) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid")); + return CDF_STATUS_E_FAULT; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = SNR_CONTEXT_MAGIC; + + hstatus = sme_get_snr(pHddCtx->hHal, hdd_get_snr_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, &context); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Unable to retrieve RSSI", + __func__); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context.completion, + msecs_to_jiffies + (WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving SNR")); + /* we'll now returned a cached value below */ + } + } + + /* either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. if + * we never sent a request or if we sent a request and got a + * response, we want to clear the magic out of paranoia. if + * we timed out there is a race condition such that the + * callback function could be executing at the same time we + * are. of primary concern is if the callback function had + * already verified the "magic" but had not yet set the + * completion variable when a timeout occurred. we serialize + * these activities by invalidating the magic while holding a + * shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + *snr = pAdapter->snr; + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_get_link_speed_cb() - Get link speed callback function + * @pLinkSpeed: pointer to the link speed record + * @pContext: pointer to the user context passed to SME + * + * This function is passed as the callback function to + * sme_get_link_speed() by wlan_hdd_get_linkspeed_for_peermac(). By + * agreement a &struct linkspeedContext is passed as @pContext. If + * the context is valid, then the contents of @pLinkSpeed are copied + * into the adapter record referenced by @pContext where they can be + * subsequently retrieved. If the context is invalid, then this + * function does nothing since it is assumed the caller has already + * timed-out and destroyed the context. + * + * Return: None. + */ +static void +hdd_get_link_speed_cb(tSirLinkSpeedInfo *pLinkSpeed, void *pContext) +{ + struct linkspeedContext *pLinkSpeedContext; + hdd_adapter_t *pAdapter; + + if ((NULL == pLinkSpeed) || (NULL == pContext)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, pLinkSpeed [%p] pContext [%p]", + __func__, pLinkSpeed, pContext); + return; + } + spin_lock(&hdd_context_lock); + pLinkSpeedContext = pContext; + pAdapter = pLinkSpeedContext->pAdapter; + + /* there is a race condition that exists between this callback + * function and the caller since the caller could time out either + * before or while this code is executing. we use a spinlock to + * serialize these actions + */ + + if ((NULL == pAdapter) || + (LINK_CONTEXT_MAGIC != pLinkSpeedContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, pLinkSpeedContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pLinkSpeedContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pLinkSpeedContext->magic = 0; + + /* copy over the stats. do so as a struct copy */ + pAdapter->ls_stats = *pLinkSpeed; + + /* notify the caller */ + complete(&pLinkSpeedContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer + * @pAdapter: adapter upon which the peer is active + * @macAddress: MAC address of the peer + * + * This function will send a query to SME for the linkspeed of the + * given peer, and then wait for the callback to be invoked. + * + * Return: CDF_STATUS_SUCCESS if linkspeed data is available, + * otherwise a CDF_STATUS_E_* error. + */ +CDF_STATUS wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, + tSirMacAddr macAddress) { + CDF_STATUS status; + unsigned long rc; + struct linkspeedContext context; + tSirLinkSpeedInfo *linkspeed_req; + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__); + return CDF_STATUS_E_FAULT; + } + linkspeed_req = cdf_mem_malloc(sizeof(*linkspeed_req)); + if (NULL == linkspeed_req) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s Request Buffer Alloc Fail", __func__); + return CDF_STATUS_E_NOMEM; + } + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = LINK_CONTEXT_MAGIC; + + cdf_mem_copy(linkspeed_req->peer_macaddr, macAddress, + sizeof(tSirMacAddr)); + status = sme_get_link_speed(WLAN_HDD_GET_HAL_CTX(pAdapter), + linkspeed_req, + &context, hdd_get_link_speed_cb); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve statistics for link speed", + __func__); + cdf_mem_free(linkspeed_req); + } else { + rc = wait_for_completion_timeout + (&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME timed out while retrieving link speed", + __func__); + } + } + + /* either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. if + * we never sent a request or if we sent a request and got a + * response, we want to clear the magic out of paranoia. if + * we timed out there is a race condition such that the + * callback function could be executing at the same time we + * are. of primary concern is if the callback function had + * already verified the "magic" but had not yet set the + * completion variable when a timeout occurred. we serialize + * these activities by invalidating the magic while holding a + * shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + return CDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_get_link_speed() - get link speed + * @pAdapter: pointer to the adapter + * @link_speed: pointer to link speed + * + * This function fetches per bssid link speed. + * + * Return: if associated, link speed shall be returned. + * if not associated, link speed of 0 is returned. + * On error, error number will be returned. + */ +int wlan_hdd_get_link_speed(hdd_adapter_t *sta_adapter, uint32_t *link_speed) +{ + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(sta_adapter); + hdd_station_ctx_t *hdd_stactx = + WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter); + int ret; + + ret = wlan_hdd_validate_context(hddctx); + + if (0 != ret) { + hddLog(LOGE, FL("HDD context is not valid")); + return ret; + } + + if (eConnectionState_Associated != hdd_stactx->conn_info.connState) { + /* we are not connected so we don't have a classAstats */ + *link_speed = 0; + } else { + CDF_STATUS status; + tSirMacAddr bssid; + + cdf_mem_copy(bssid, hdd_stactx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + + status = wlan_hdd_get_linkspeed_for_peermac(sta_adapter, bssid); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("Unable to retrieve SME linkspeed")); + return -EINVAL; + } + *link_speed = sta_adapter->ls_stats.estLinkSpeed; + /* linkspeed in units of 500 kbps */ + *link_speed = (*link_speed) / 500; + } + return 0; +} + +/** + * hdd_statistics_cb() - "Get statistics" callback function + * @pStats: statistics payload + * @pContext: opaque context originally passed to SME. HDD always passes + * a pointer to an adapter + * + * Return: None + */ +void hdd_statistics_cb(void *pStats, void *pContext) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pContext; + hdd_stats_t *pStatsCache = NULL; + hdd_wext_state_t *pWextState; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + tCsrSummaryStatsInfo *pSummaryStats = NULL; + tCsrGlobalClassAStatsInfo *pClassAStats = NULL; + tCsrGlobalClassBStatsInfo *pClassBStats = NULL; + tCsrGlobalClassCStatsInfo *pClassCStats = NULL; + tCsrGlobalClassDStatsInfo *pClassDStats = NULL; + tCsrPerStaStatsInfo *pPerStaStats = NULL; + + if (pAdapter != NULL) + pStatsCache = &pAdapter->hdd_stats; + + pSummaryStats = (tCsrSummaryStatsInfo *) pStats; + pClassAStats = (tCsrGlobalClassAStatsInfo *) (pSummaryStats + 1); + pClassBStats = (tCsrGlobalClassBStatsInfo *) (pClassAStats + 1); + pClassCStats = (tCsrGlobalClassCStatsInfo *) (pClassBStats + 1); + pClassDStats = (tCsrGlobalClassDStatsInfo *) (pClassCStats + 1); + pPerStaStats = (tCsrPerStaStatsInfo *) (pClassDStats + 1); + + if (pStatsCache != NULL) { + /* copy the stats into the cache we keep in the + * adapter instance structure + */ + cdf_mem_copy(&pStatsCache->summary_stat, pSummaryStats, + sizeof(pStatsCache->summary_stat)); + cdf_mem_copy(&pStatsCache->ClassA_stat, pClassAStats, + sizeof(pStatsCache->ClassA_stat)); + cdf_mem_copy(&pStatsCache->ClassB_stat, pClassBStats, + sizeof(pStatsCache->ClassB_stat)); + cdf_mem_copy(&pStatsCache->ClassC_stat, pClassCStats, + sizeof(pStatsCache->ClassC_stat)); + cdf_mem_copy(&pStatsCache->ClassD_stat, pClassDStats, + sizeof(pStatsCache->ClassD_stat)); + cdf_mem_copy(&pStatsCache->perStaStats, pPerStaStats, + sizeof(pStatsCache->perStaStats)); + } + + if (pAdapter) { + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + cdf_status = cdf_event_set(&pWextState->hdd_cdf_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(LOGE, FL("cdf_event_set failed")); + return; + } + } +} + +/** + * hdd_clear_roam_profile_ie() - Clear Roam Profile IEs + * @pAdapter: adapter who's IEs are to be cleared + * + * Return: None + */ +void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter) +{ + int i = 0; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + /* clear WPA/RSN/WSC IE information in the profile */ + pWextState->roamProfile.nWPAReqIELength = 0; + pWextState->roamProfile.pWPAReqIE = (uint8_t *) NULL; + pWextState->roamProfile.nRSNReqIELength = 0; + pWextState->roamProfile.pRSNReqIE = (uint8_t *) NULL; + +#ifdef FEATURE_WLAN_WAPI + pWextState->roamProfile.nWAPIReqIELength = 0; + pWextState->roamProfile.pWAPIReqIE = (uint8_t *) NULL; +#endif + + pWextState->roamProfile.bWPSAssociation = false; + pWextState->roamProfile.bOSENAssociation = false; + pWextState->roamProfile.pAddIEScan = (uint8_t *) NULL; + pWextState->roamProfile.nAddIEScanLength = 0; + pWextState->roamProfile.pAddIEAssoc = (uint8_t *) NULL; + pWextState->roamProfile.nAddIEAssocLength = 0; + + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + + pWextState->roamProfile.AuthType.numEntries = 1; + pWextState->roamProfile.AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + +#ifdef WLAN_FEATURE_11W + pWextState->roamProfile.MFPEnabled = false; + pWextState->roamProfile.MFPRequired = 0; + pWextState->roamProfile.MFPCapable = 0; +#endif + + pWextState->authKeyMgmt = 0; + + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (pWextState->roamProfile.Keys.KeyMaterial[i]) { + pWextState->roamProfile.Keys.KeyLength[i] = 0; + } + } +#ifdef FEATURE_WLAN_WAPI + pAdapter->wapi_info.wapiAuthMode = WAPI_AUTH_MODE_OPEN; + pAdapter->wapi_info.nWapiMode = 0; +#endif + + cdf_zero_macaddr(&pWextState->req_bssId); + +} + +/** + * wlan_hdd_get_vendor_oui_ie_ptr() - Find a vendor OUI + * @oui: The OUI that is being searched for + * @oui_size: The length of @oui + * @ie: The set of IEs within which we're trying to find @oui + * @ie_len: The length of @ie + * + * This function will scan the IEs contained within @ie looking for @oui. + * + * Return: Pointer to @oui embedded within @ie if it is present, NULL + * if @oui is not present within @ie. + */ +uint8_t *wlan_hdd_get_vendor_oui_ie_ptr(uint8_t *oui, uint8_t oui_size, + uint8_t *ie, int ie_len) +{ + int left = ie_len; + uint8_t *ptr = ie; + uint8_t elem_id, elem_len; + uint8_t eid = 0xDD; + + if (NULL == ie || 0 == ie_len) + return NULL; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hddLog(CDF_TRACE_LEVEL_FATAL, + FL + ("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + eid, elem_len, left); + return NULL; + } + if (elem_id == eid) { + if (memcmp(&ptr[2], oui, oui_size) == 0) + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} + +/** + * __iw_set_commit() - SIOCSIWCOMMIT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_commit(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hddLog(LOG1, "In %s", __func__); + /* Do nothing for now */ + return 0; +} + +/** + * iw_set_commit() - SSR wrapper function for __iw_set_commit + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +int iw_set_commit(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_commit(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_name() - SIOCGIWNAME ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_name(struct net_device *dev, + struct iw_request_info *info, char *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + strlcpy(wrqu, "Qcom:802.11n", IFNAMSIZ); + EXIT(); + return 0; +} + +/** + * __iw_get_name() - SSR wrapper for __iw_get_name + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_name(struct net_device *dev, + struct iw_request_info *info, + char *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_name(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_mode() - ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tCsrRoamProfile *pRoamProfile; + eCsrRoamBssType LastBSSType; + eMib_dot11DesiredBssType connectedBssType; + struct hdd_config *pConfig; + struct wireless_dev *wdev; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + wdev = dev->ieee80211_ptr; + pRoamProfile = &pWextState->roamProfile; + LastBSSType = pRoamProfile->BSSType; + + hddLog(LOG1, "%s Old Bss type = %d", __func__, LastBSSType); + + switch (wrqu->mode) { + case IW_MODE_ADHOC: + hddLog(LOG1, "%s Setting AP Mode as IW_MODE_ADHOC", __func__); + pRoamProfile->BSSType = eCSR_BSS_TYPE_START_IBSS; + /* Set the phymode correctly for IBSS. */ + pConfig = (WLAN_HDD_GET_CTX(pAdapter))->config; + pWextState->roamProfile.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + pAdapter->device_mode = WLAN_HDD_IBSS; + wdev->iftype = NL80211_IFTYPE_ADHOC; + break; + case IW_MODE_INFRA: + hddLog(LOG1, "%s Setting AP Mode as IW_MODE_INFRA", __func__); + pRoamProfile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + wdev->iftype = NL80211_IFTYPE_STATION; + break; + case IW_MODE_AUTO: + hddLog(LOG1, "%s Setting AP Mode as IW_MODE_AUTO", __func__); + pRoamProfile->BSSType = eCSR_BSS_TYPE_ANY; + break; + default: + hddLog(LOGE, "%s Unknown AP Mode value %d ", __func__, + wrqu->mode); + return -EOPNOTSUPP; + } + + if (LastBSSType != pRoamProfile->BSSType) { + /* the BSS mode changed. We need to issue disconnect + * if connected or in IBSS disconnect state + */ + if (hdd_conn_get_connected_bss_type + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), &connectedBssType) + || (eCSR_BSS_TYPE_START_IBSS == LastBSSType)) { + CDF_STATUS cdf_status; + /* need to issue a disconnect to CSR. */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + cdf_status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + if (CDF_STATUS_SUCCESS == cdf_status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hddLog(CDF_TRACE_LEVEL_ERROR, + FL + ("failed wait on disconnect_comp_var")); + } + } + } + + EXIT(); + return 0; +} + +/** + * iw_set_mode() - SSR wrapper for __iw_set_mode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_mode() - SIOCGIWMODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int +__iw_get_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + switch (pWextState->roamProfile.BSSType) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + hddLog(LOG1, FL("returns IW_MODE_INFRA")); + wrqu->mode = IW_MODE_INFRA; + break; + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + hddLog(LOG1, FL("returns IW_MODE_ADHOC")); + wrqu->mode = IW_MODE_ADHOC; + break; + case eCSR_BSS_TYPE_ANY: + default: + hddLog(LOG1, FL("returns IW_MODE_AUTO")); + wrqu->mode = IW_MODE_AUTO; + break; + } + + EXIT(); + return 0; +} + +/** + * iw_get_mode() - SSR wrapper for __iw_get_mode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_freq() - SIOCSIWFREQ ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t numChans = 0; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t indx = 0; + int ret; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + + hddLog(LOG1, "setCHANNEL ioctl"); + + /* Link is up then return cant set channel */ + if (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState || + eConnectionState_Associated == pHddStaCtx->conn_info.connState) { + hddLog(LOGE, "IBSS Associated"); + return -EOPNOTSUPP; + } + + /* Settings by Frequency as input */ + if ((wrqu->freq.e == 1) && (wrqu->freq.m >= (uint32_t) 2.412e8) && + (wrqu->freq.m <= (uint32_t) 5.825e8)) { + uint32_t freq = wrqu->freq.m / 100000; + + while ((indx < FREQ_CHAN_MAP_TABLE_SIZE) + && (freq != freq_chan_map[indx].freq)) + indx++; + if (indx >= FREQ_CHAN_MAP_TABLE_SIZE) { + return -EINVAL; + } + wrqu->freq.e = 0; + wrqu->freq.m = freq_chan_map[indx].chan; + + } + + if (wrqu->freq.e == 0) { + if ((wrqu->freq.m < WNI_CFG_CURRENT_CHANNEL_STAMIN) || + (wrqu->freq.m > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + hddLog(LOG1, + "%s: Channel [%d] is outside valid range from %d to %d", + __func__, wrqu->freq.m, + WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, FL + ("failed to get ini parameter, WNI_CFG_VALID_CHANNEL_LIST")); + return -EIO; + } + + for (indx = 0; indx < numChans; indx++) { + if (wrqu->freq.m == validChan[indx]) { + break; + } + } + } else { + + return -EINVAL; + } + + if (indx >= numChans) { + return -EINVAL; + } + + /* Set the Operational Channel */ + numChans = pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = wrqu->freq.m; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + + hddLog(LOG1, "pRoamProfile->operationChannel = %d", wrqu->freq.m); + + EXIT(); + + return ret; +} + +/** + * iw_set_freq() - SSR wrapper for __iw_set_freq() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_freq(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_freq() - SIOCGIWFREQ ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + uint32_t status = false, channel = 0, freq = 0; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal; + hdd_wext_state_t *pWextState; + tCsrRoamProfile *pRoamProfile; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + + if (pHddStaCtx->conn_info.connState == eConnectionState_Associated) { + if (sme_get_operation_channel(hHal, &channel, pAdapter->sessionId) + != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("failed to get operating channel %u"), + pAdapter->sessionId); + return -EIO; + } else { + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) + * in struct iw_freq iwlist & iwconfig + * command shows frequency into proper + * format (2.412 GHz instead of 246.2 + * MHz) + */ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + } else { + /* Set Exponent parameter as 6 (MHZ) in struct iw_freq + * iwlist & iwconfig command shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz) + */ + fwrq->m = 0; + fwrq->e = MHZ; + } + return 0; +} + +/** + * iw_get_freq() - SSR wrapper for __iw_get_freq() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @fwrq: pointer to frequency data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_freq(dev, info, fwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_tx_power() - SIOCGIWTXPOW ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + wrqu->txpower.value = 0; + return 0; + } + wlan_hdd_get_class_astats(pAdapter); + wrqu->txpower.value = pAdapter->hdd_stats.ClassA_stat.max_pwr; + + return 0; +} + +/** + * iw_get_tx_power() - SSR wrapper for __iw_get_tx_power() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_tx_power() - SIOCSIWTXPOW ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + wrqu->txpower.value) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_CURRENT_TX_POWER_LEVEL")); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_set_tx_power() - SSR wrapper for __iw_set_tx_power() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_bitrate() - SIOCGIWRATE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:LOGP in Progress. Ignore!!!", __func__); + return status; + } + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + wrqu->bitrate.value = 0; + } else { + status = + sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + hdd_statistics_cb, 0, + false, + pHddStaCtx->conn_info.staId[0], + pAdapter, pAdapter->sessionId); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve statistics", __func__); + return status; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + cdf_status = + cdf_wait_single_event(&pWextState->hdd_cdf_event, + WLAN_WAIT_TIME_STATS); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME timeout while retrieving statistics", + __func__); + return CDF_STATUS_E_FAILURE; + } + + wrqu->bitrate.value = + pAdapter->hdd_stats.ClassA_stat.tx_rate * 500 * 1000; + } + + EXIT(); + + return cdf_status; +} + +/** + * iw_get_bitrate() - SSR wrapper for __iw_get_bitrate() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_bitrate(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_bitrate() - SIOCSIWRATE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint8_t supp_rates[WNI_CFG_SUPPORTED_RATES_11A_LEN]; + uint32_t a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + uint32_t b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + uint32_t i, rate; + uint32_t valid_rate = false, active_phy_mode = 0; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + return -ENXIO; + } + + rate = wrqu->bitrate.value; + + if (rate == -1) { + rate = WNI_CFG_FIXED_RATE_AUTO; + valid_rate = true; + } else if (sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_DOT11_MODE, + &active_phy_mode) == CDF_STATUS_SUCCESS) { + if (active_phy_mode == WNI_CFG_DOT11_MODE_11A + || active_phy_mode == WNI_CFG_DOT11_MODE_11G + || active_phy_mode == WNI_CFG_DOT11_MODE_11B) { + if ((sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_SUPPORTED_RATES_11A, supp_rates, + &a_len) == CDF_STATUS_SUCCESS) + && + (sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_SUPPORTED_RATES_11B, supp_rates, + &b_len) == CDF_STATUS_SUCCESS)) { + for (i = 0; i < (b_len + a_len); ++i) { + /* supported rates returned is double + * the actual rate so we divide it by 2 + */ + if ((supp_rates[i] & 0x7F) / 2 == + rate) { + valid_rate = true; + rate = i + + WNI_CFG_FIXED_RATE_1MBPS; + break; + } + } + } + } + } + if (valid_rate != true) { + return -EINVAL; + } + if (sme_cfg_set_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_FIXED_RATE, rate) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_FIXED_RATE")); + return -EIO; + } + return 0; +} + +/** + * iw_set_bitrate() - SSR wrapper for __iw_set_bitrate() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_bitrate(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_genie() - SIOCSIWGENIE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + uint8_t *genie = NULL; + uint8_t *base_genie = NULL; + uint16_t remLen; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + hdd_clear_roam_profile_ie(pAdapter); + EXIT(); + return 0; + } + + base_genie = mem_alloc_copy_from_user_helper(wrqu->data.pointer, + wrqu->data.length); + if (NULL == base_genie) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + genie = base_genie; + + remLen = wrqu->data.length; + + hddLog(LOG1, "iw_set_genie ioctl IE[0x%X], LEN[%d]", genie[0], + genie[1]); + + /* clear any previous genIE before this call */ + memset(&pWextState->genIE, 0, sizeof(pWextState->genIE)); + + while (remLen >= 2) { + uint16_t eLen = 0; + uint8_t elementId; + elementId = *genie++; + eLen = *genie++; + remLen -= 2; + + hddLog(CDF_TRACE_LEVEL_INFO, "%s: IE[0x%X], LEN[%d]", + __func__, elementId, eLen); + + switch (elementId) { + case IE_EID_VENDOR: + if ((IE_LEN_SIZE + IE_EID_SIZE + IE_VENDOR_OUI_SIZE) > eLen) { /* should have at least OUI */ + kfree(base_genie); + return -EINVAL; + } + + if (0 == memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) { + uint16_t curGenIELen = pWextState->genIE.length; + hddLog(CDF_TRACE_LEVEL_INFO, + "%s Set WPS OUI(%02x %02x %02x %02x) IE(len %d)", + __func__, genie[0], genie[1], genie[2], + genie[3], eLen + 2); + + if (SIR_MAC_MAX_IE_LENGTH < + (pWextState->genIE.length + eLen)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "Cannot accommodate genIE. " + "Need bigger buffer space"); + CDF_ASSERT(0); + kfree(base_genie); + return -ENOMEM; + } + /* save to Additional IE ; it should be accumulated to handle WPS IE + other IE */ + memcpy(pWextState->genIE.addIEdata + + curGenIELen, genie - 2, eLen + 2); + pWextState->genIE.length += eLen + 2; + } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s Set WPA IE (len %d)", __func__, + eLen + 2); + memset(pWextState->WPARSNIE, 0, + MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pWPAReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nWPAReqIELength = + eLen + 2; + } else { /* any vendorId except WPA IE should be accumulated to genIE */ + + uint16_t curGenIELen = pWextState->genIE.length; + hddLog(CDF_TRACE_LEVEL_INFO, + "%s Set OUI(%02x %02x %02x %02x) IE(len %d)", + __func__, genie[0], genie[1], genie[2], + genie[3], eLen + 2); + + if (SIR_MAC_MAX_IE_LENGTH < + (pWextState->genIE.length + eLen)) { + hddLog(CDF_TRACE_LEVEL_FATAL, + "Cannot accommodate genIE. " + "Need bigger buffer space"); + CDF_ASSERT(0); + kfree(base_genie); + return -ENOMEM; + } + /* save to Additional IE ; it should be accumulated to handle WPS IE + other IE */ + memcpy(pWextState->genIE.addIEdata + + curGenIELen, genie - 2, eLen + 2); + pWextState->genIE.length += eLen + 2; + } + break; + case DOT11F_EID_RSN: + hddLog(LOG1, "%s Set RSN IE (len %d)", __func__, + eLen + 2); + memset(pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, (eLen + 2)); + pWextState->roamProfile.pRSNReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nRSNReqIELength = eLen + 2; + break; + + default: + hddLog(LOGE, "%s Set UNKNOWN IE %X", __func__, + elementId); + kfree(base_genie); + return 0; + } + genie += eLen; + remLen -= eLen; + } + EXIT(); + kfree(base_genie); + return 0; +} + +/** + * iw_set_genie() - SSR wrapper for __iw_set_genie() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_genie() - SIOCGIWGENIE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + CDF_STATUS status; + uint32_t length = DOT11F_IE_RSN_MAX_LEN; + uint8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hddLog(LOG1, "getGEN_IE ioctl"); + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (pHddStaCtx->conn_info.connState == eConnectionState_NotConnected) { + return -ENXIO; + } + + /* Return something ONLY if we are associated with an RSN or + * WPA network + */ + if (!hdd_is_auth_type_rsn(pWextState->roamProfile.negotiatedAuthType)) { + return -ENXIO; + } + + /* Actually retrieve the RSN IE from CSR. (We previously sent + * it down in the CSR Roam Profile.) + */ + status = csr_roam_get_wpa_rsn_req_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &length, genIeBytes); + length = CDF_MIN((uint16_t) length, DOT11F_IE_RSN_MAX_LEN); + if (wrqu->data.length < length) { + hddLog(LOG1, "%s: failed to copy data to user buffer", + __func__); + return -EFAULT; + } + cdf_mem_copy(extra, (void *)genIeBytes, length); + wrqu->data.length = length; + + hddLog(LOG1, "%s: RSN IE of %d bytes returned", __func__, + wrqu->data.length); + + EXIT(); + + return 0; +} + +/** + * iw_get_genie() - SSR wrapper for __iw_get_genie() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_encode() - SIOCGIWENCODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + int keyId; + eCsrAuthType authType = eCSR_AUTH_TYPE_NONE; + int i; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = pRoamProfile->Keys.defaultIndex; + + if (keyId < 0 || keyId >= MAX_WEP_KEYS) { + hddLog(LOG1, "%s: Invalid keyId : %d", __func__, keyId); + return -EINVAL; + } + + if (pRoamProfile->Keys.KeyLength[keyId] > 0) { + dwrq->flags |= IW_ENCODE_ENABLED; + dwrq->length = pRoamProfile->Keys.KeyLength[keyId]; + cdf_mem_copy(extra, &(pRoamProfile->Keys.KeyMaterial[keyId][0]), + pRoamProfile->Keys.KeyLength[keyId]); + + dwrq->flags |= (keyId + 1); + + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + for (i = 0; i < MAX_WEP_KEYS; i++) { + if (pRoamProfile->Keys.KeyMaterial[i] == NULL) { + continue; + } else { + break; + } + } + + if (MAX_WEP_KEYS == i) { + dwrq->flags |= IW_ENCODE_NOKEY; + } + + authType = + ((hdd_station_ctx_t *) WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.authType; + + if (eCSR_AUTH_TYPE_OPEN_SYSTEM == authType) { + dwrq->flags |= IW_ENCODE_OPEN; + } else { + dwrq->flags |= IW_ENCODE_RESTRICTED; + } + EXIT(); + return 0; +} + +/** + * iw_get_encode() - SSR wrapper for __iw_get_encode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @dwrq: pointer to encoding information + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_encode(dev, info, dwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_rts_threshold() - SIOCGIWRTS ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t status = 0; + + status = hdd_wlan_get_rts_threshold(pAdapter, wrqu); + + return status; +} + +/** + * __iw_set_rts_threshold() - SIOCSIWRTS ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->rts.value < WNI_CFG_RTS_THRESHOLD_STAMIN + || wrqu->rts.value > WNI_CFG_RTS_THRESHOLD_STAMAX) { + return -EINVAL; + } + + if (sme_cfg_set_int(hHal, WNI_CFG_RTS_THRESHOLD, wrqu->rts.value) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_RTS_THRESHOLD")); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_get_rts_threshold() - SSR wrapper for __iw_get_rts_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_rts_threshold() - SSR wrapper for __iw_set_rts_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_frag_threshold() - SIOCGIWFRAG ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t status = 0; + + status = hdd_wlan_get_frag_threshold(pAdapter, wrqu); + + return status; +} + +/** + * iw_get_frag_threshold() - SSR wrapper for __iw_get_frag_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_frag_threshold() - SIOCSIWFRAG ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->frag.value < WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN + || wrqu->frag.value > WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX) { + return -EINVAL; + } + + if (sme_cfg_set_int + (hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, wrqu->frag.value) + != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_FRAGMENTATION_THRESHOLD")); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_set_frag_threshold() - SSR wrapper for __iw_set_frag_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_power_mode() - SIOCGIWPOWER ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return -EOPNOTSUPP; +} + +/** + * iw_get_power_mode() - SSR wrapper function for __iw_get_power_mode + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +int iw_get_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_power_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_power_mode() - SIOCSIWPOWER ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return -EOPNOTSUPP; +} + +/** + * iw_set_power_mode() - SSR wrapper function for __iw_set_power_mode + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +int iw_set_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_power_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_range() - SIOCGIWRANGE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_range(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + struct iw_range *range = (struct iw_range *)extra; + + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + uint32_t num_channels = sizeof(channels); + uint8_t supp_rates[WNI_CFG_SUPPORTED_RATES_11A_LEN]; + uint32_t a_len; + uint32_t b_len; + uint32_t active_phy_mode = 0; + uint8_t index = 0, i; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + wrqu->data.length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + + /*Get the phy mode */ + if (sme_cfg_get_int(hHal, + WNI_CFG_DOT11_MODE, + &active_phy_mode) == CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "active_phy_mode = %d", active_phy_mode); + + if (active_phy_mode == WNI_CFG_DOT11_MODE_11A + || active_phy_mode == WNI_CFG_DOT11_MODE_11G) { + /*Get the supported rates for 11G band */ + a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + if (sme_cfg_get_str(hHal, + WNI_CFG_SUPPORTED_RATES_11A, + supp_rates, + &a_len) == CDF_STATUS_SUCCESS) { + if (a_len > WNI_CFG_SUPPORTED_RATES_11A_LEN) { + a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + } + for (i = 0; i < a_len; i++) { + range->bitrate[i] = + ((supp_rates[i] & 0x7F) / 2) * + 1000000; + } + range->num_bitrates = a_len; + } else { + return -EIO; + } + } else if (active_phy_mode == WNI_CFG_DOT11_MODE_11B) { + /*Get the supported rates for 11B band */ + b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + if (sme_cfg_get_str(hHal, + WNI_CFG_SUPPORTED_RATES_11B, + supp_rates, + &b_len) == CDF_STATUS_SUCCESS) { + if (b_len > WNI_CFG_SUPPORTED_RATES_11B_LEN) { + b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + } + for (i = 0; i < b_len; i++) { + range->bitrate[i] = + ((supp_rates[i] & 0x7F) / 2) * + 1000000; + } + range->num_bitrates = b_len; + } else { + return -EIO; + } + } + } + + range->max_rts = WNI_CFG_RTS_THRESHOLD_STAMAX; + range->min_frag = WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN; + range->max_frag = WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = MAX_WEP_KEYS; + + /* we support through Wireless Extensions 22 */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 22; + + /*Supported Channels and Frequencies */ + if (sme_cfg_get_str + ((hHal), WNI_CFG_VALID_CHANNEL_LIST, channels, + &num_channels) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL + ("failed to get ini parameter, WNI_CFG_VALID_CHANNEL_LIST")); + return -EIO; + } + if (num_channels > IW_MAX_FREQUENCIES) { + num_channels = IW_MAX_FREQUENCIES; + } + + range->num_channels = num_channels; + range->num_frequency = num_channels; + + for (index = 0; index < num_channels; index++) { + uint32_t frq_indx = 0; + + range->freq[index].i = channels[index]; + while (frq_indx < FREQ_CHAN_MAP_TABLE_SIZE) { + if (channels[index] == freq_chan_map[frq_indx].chan) { + range->freq[index].m = + freq_chan_map[frq_indx].freq * 100000; + range->freq[index].e = 1; + break; + } + frq_indx++; + } + } + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + /*Encryption capability */ + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + /* Txpower capability */ + range->txpower_capa = IW_TXPOW_MWATT; + + /*Scanning capability */ +#if WIRELESS_EXT >= 22 + range->scan_capa = + IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | IW_SCAN_CAPA_CHANNEL; +#endif + + EXIT(); + return 0; +} + +/** + * iw_get_range() - SSR wrapper for __iw_get_range() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_range(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_range(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_class_a_statistics_cb() - Get Class A stats callback function + * @pStats: pointer to Class A stats + * @pContext: user context originally registered with SME + * + * Return: None + */ +static void hdd_get_class_a_statistics_cb(void *pStats, void *pContext) +{ + struct statsContext *pStatsContext; + tCsrGlobalClassAStatsInfo *pClassAStats; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: pStats [%p] pContext [%p]\n", + __func__, pStats, pContext); + } + + if ((NULL == pStats) || (NULL == pContext)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, pStats [%p] pContext [%p]", + __func__, pStats, pContext); + return; + } + + pClassAStats = pStats; + pStatsContext = pContext; + pAdapter = pStatsContext->pAdapter; + + /* there is a race condition that exists between this callback + * function and the caller since the caller could time out + * either before or while this code is executing. we use a + * spinlock to serialize these actions + */ + spin_lock(&hdd_context_lock); + + if ((NULL == pAdapter) || + (STATS_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the stats. do so as a struct copy */ + pAdapter->hdd_stats.ClassA_stat = *pClassAStats; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_class_astats() - Get Class A statistics + * @pAdapter: adapter for which statistics are desired + * + * Return: CDF_STATUS_SUCCESS if adapter's Class A statistics were updated + */ +CDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + CDF_STATUS hstatus; + unsigned long rc; + struct statsContext context; + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__); + return CDF_STATUS_E_FAULT; + } + if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!", __func__); + return CDF_STATUS_SUCCESS; + } + + /* we are connected so prepare our callback context */ + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = STATS_CONTEXT_MAGIC; + /* query only for Class A statistics (which include link speed) */ + hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, SME_GLOBAL_CLASSA_STATS, + hdd_get_class_a_statistics_cb, + 0, /* not periodic */ + false, /* non-cached results */ + pHddStaCtx->conn_info.staId[0], + &context, pAdapter->sessionId); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve Class A statistics", __func__); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving Class A statistics")); + } + } + + /* either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. if + * we never sent a request or if we sent a request and got a + * response, we want to clear the magic out of paranoia. if + * we timed out there is a race condition such that the + * callback function could be executing at the same time we + * are. of primary concern is if the callback function had + * already verified the "magic" but had not yet set the + * completion variable when a timeout occurred. we serialize + * these activities by invalidating the magic while holding a + * shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + /* either callback updated pAdapter stats or it has cached data */ + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_get_station_statistics_cb() - Get stats callback function + * @pStats: pointer to Class A stats + * @pContext: user context originally registered with SME + * + * Return: None + */ +static void hdd_get_station_statistics_cb(void *pStats, void *pContext) +{ + struct statsContext *pStatsContext; + tCsrSummaryStatsInfo *pSummaryStats; + tCsrGlobalClassAStatsInfo *pClassAStats; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: pStats [%p] pContext [%p]\n", + __func__, pStats, pContext); + } + + if ((NULL == pStats) || (NULL == pContext)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Bad param, pStats [%p] pContext [%p]", + __func__, pStats, pContext); + return; + } + + /* there is a race condition that exists between this callback + * function and the caller since the caller could time out + * either before or while this code is executing. we use a + * spinlock to serialize these actions + */ + spin_lock(&hdd_context_lock); + + pSummaryStats = (tCsrSummaryStatsInfo *) pStats; + pClassAStats = (tCsrGlobalClassAStatsInfo *) (pSummaryStats + 1); + pStatsContext = pContext; + pAdapter = pStatsContext->pAdapter; + if ((NULL == pAdapter) || + (STATS_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter [%p] magic [%08x]", + __func__, pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the stats. do so as a struct copy */ + pAdapter->hdd_stats.summary_stat = *pSummaryStats; + pAdapter->hdd_stats.ClassA_stat = *pClassAStats; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_station_stats() - Get station statistics + * @pAdapter: adapter for which statistics are desired + * + * Return: CDF_STATUS_SUCCESS if adapter's statistics were updated + */ +CDF_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + CDF_STATUS hstatus; + unsigned long rc; + struct statsContext context; + + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__); + return CDF_STATUS_SUCCESS; + } + + /* we are connected so prepare our callback context */ + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = STATS_CONTEXT_MAGIC; + + /* query only for Summary & Class A statistics */ + hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS, + hdd_get_station_statistics_cb, + 0, /* not periodic */ + false, /* non-cached results */ + pHddStaCtx->conn_info.staId[0], + &context, pAdapter->sessionId); + if (CDF_STATUS_SUCCESS != hstatus) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve statistics", __func__); + /* we'll return with cached values */ + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving statistics")); + } + } + + /* either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. if + * we never sent a request or if we sent a request and got a + * response, we want to clear the magic out of paranoia. if + * we timed out there is a race condition such that the + * callback function could be executing at the same time we + * are. of primary concern is if the callback function had + * already verified the "magic" but had not yet set the + * completion variable when a timeout occurred. we serialize + * these activities by invalidating the magic while holding a + * shared spinlock which will cause us to block if the + * callback is currently executing + */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + /* either callback updated pAdapter stats or it has cached data */ + return CDF_STATUS_SUCCESS; +} + +/** + * iw_get_linkspeed() - Get current link speed ioctl + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: extra ioctl buffer + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + char *pLinkSpeed = (char *)extra; + int len = sizeof(uint32_t) + 1; + uint32_t link_speed = 0; + hdd_context_t *hdd_ctx; + int rc, valid; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + valid = wlan_hdd_validate_context(hdd_ctx); + if (0 != valid) + return valid; + + rc = wlan_hdd_get_link_speed(pAdapter, &link_speed); + if (0 != rc) { + return rc; + } + + wrqu->data.length = len; + /* return the linkspeed as a string */ + rc = snprintf(pLinkSpeed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Unable to encode link speed")); + return -EIO; + } + + /* a value is being successfully returned */ + return 0; +} + +static int iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_change_country_code_callback() - Change country code callback + * @context: opaque context originally passed to SME. All functions + * which use this callback pass the adapter upon which the country + * code change is active + * + * This function is registered as the callback function when + * sme_change_country_code() is invoked. Callers of + * sme_change_country_code() subsequently wait for the adapter's + * @change_country_code completion variable, so all this function + * needs to do is set that completion variable so that execution can + * continue. + * + * Return: none + */ +void wlan_hdd_change_country_code_callback(void *context) +{ + + hdd_adapter_t *adapter = context; + + if (adapter && (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) + complete(&adapter->change_country_code); + + return; +} + +/** + * __iw_set_nick() - SIOCSIWNICKN ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return 0; +} + +/** + * iw_set_nick() - SSR wrapper for __iw_set_nick + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_nick(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_nick() - SIOCGIWNICKN ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return 0; +} + +/** + * iw_get_nick() - SSR wrapper for __iw_get_nick + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_nick(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_encode() - SIOCSIWENCODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_encode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + struct iw_point *encoderq = &(wrqu->encoding); + uint32_t keyId; + uint8_t key_length; + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + bool fKeyPresent = 0; + int i; + CDF_STATUS status = CDF_STATUS_SUCCESS; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = encoderq->flags & IW_ENCODE_INDEX; + + if (keyId) { + if (keyId > MAX_WEP_KEYS) { + return -EINVAL; + } + + fKeyPresent = 1; + keyId--; + } else { + fKeyPresent = 0; + } + + if (wrqu->data.flags & IW_ENCODE_DISABLED) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "****iwconfig wlan0 key off*****"); + if (!fKeyPresent) { + + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + + if (pWextState->roamProfile.Keys.KeyMaterial[i]) + pWextState->roamProfile.Keys. + KeyLength[i] = 0; + } + } + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pHddStaCtx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + pHddStaCtx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if (CDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hddLog(CDF_TRACE_LEVEL_ERROR, + FL + ("failed wait on disconnect_comp_var")); + } + } + + return status; + + } + + if (wrqu->data.flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { + hddLog(CDF_TRACE_LEVEL_INFO, "iwconfig wlan0 key on"); + + pHddStaCtx->conn_info.authType = + (encoderq-> + flags & IW_ENCODE_RESTRICTED) ? eCSR_AUTH_TYPE_SHARED_KEY : + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + } + + if (wrqu->data.length > 0) { + hddLog(CDF_TRACE_LEVEL_INFO, "%s : wrqu->data.length : %d", + __func__, wrqu->data.length); + + key_length = wrqu->data.length; + + /* IW_ENCODING_TOKEN_MAX is the value that is set for wrqu->data.length by iwconfig.c when 'iwconfig wlan0 key on' is issued. */ + + if (5 == key_length) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Call with WEP40,key_len=%d", __func__, + key_length); + + if ((IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + encryptionType = eCSR_ENCRYPT_TYPE_WEP40; + } else { + encryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + } else if (13 == key_length) { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s:Call with WEP104,key_len:%d", __func__, + key_length); + + if ((IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + encryptionType = eCSR_ENCRYPT_TYPE_WEP104; + } else { + encryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } else { + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Invalid WEP key length :%d", __func__, + key_length); + return -EINVAL; + } + + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pHddStaCtx->conn_info.mcEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + encryptionType; + + if ((eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState) + && + ((eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType) + || (eCSR_AUTH_TYPE_SHARED_KEY == + pHddStaCtx->conn_info.authType))) { + + cdf_mem_copy(&pWextState->roamProfile.Keys. + KeyMaterial[keyId][0], extra, key_length); + + pWextState->roamProfile.Keys.KeyLength[keyId] = + (uint8_t) key_length; + pWextState->roamProfile.Keys.defaultIndex = + (uint8_t) keyId; + + return status; + } + } + + return 0; +} + +/** + * iw_set_encode() - SSR wrapper for __iw_set_encode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_encode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_encode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_encodeext() - SIOCGIWENCODEEXT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + int keyId; + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + eCsrAuthType authType = eCSR_AUTH_TYPE_NONE; + int i, ret; + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = pRoamProfile->Keys.defaultIndex; + + if (keyId < 0 || keyId >= MAX_WEP_KEYS) { + hddLog(LOG1, "%s: Invalid keyId : %d", __func__, keyId); + return -EINVAL; + } + + if (pRoamProfile->Keys.KeyLength[keyId] > 0) { + dwrq->flags |= IW_ENCODE_ENABLED; + dwrq->length = pRoamProfile->Keys.KeyLength[keyId]; + cdf_mem_copy(extra, &(pRoamProfile->Keys.KeyMaterial[keyId][0]), + pRoamProfile->Keys.KeyLength[keyId]); + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + for (i = 0; i < MAX_WEP_KEYS; i++) { + if (pRoamProfile->Keys.KeyMaterial[i] == NULL) { + continue; + } else { + break; + } + } + + if (MAX_WEP_KEYS == i) { + dwrq->flags |= IW_ENCODE_NOKEY; + } else { + dwrq->flags |= IW_ENCODE_ENABLED; + } + + encryptionType = pRoamProfile->EncryptionType.encryptionType[0]; + + if (eCSR_ENCRYPT_TYPE_NONE == encryptionType) { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + authType = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.authType; + + if (IW_AUTH_ALG_OPEN_SYSTEM == authType) { + dwrq->flags |= IW_ENCODE_OPEN; + } else { + dwrq->flags |= IW_ENCODE_RESTRICTED; + } + EXIT(); + return 0; + +} + +/** + * iw_get_encodeext() - SSR wrapper for __iw_get_encodeext() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @dwrq: pointer to encoding information + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_encodeext(dev, info, dwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_encodeext() - SIOCSIWENCODEEXT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + int ret; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int key_index; + struct iw_point *encoding = &wrqu->encoding; + tCsrRoamSetKey setKey; + uint32_t roamId = 0xFF; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + key_index = encoding->flags & IW_ENCODE_INDEX; + + if (key_index > 0) { + + /*Convert from 1-based to 0-based keying */ + key_index--; + } + if (!ext->key_len) { + + /*Set the encrytion type to NONE */ + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + return ret; + } + + if (eConnectionState_NotConnected == pHddStaCtx->conn_info.connState && + (IW_ENCODE_ALG_WEP == ext->alg)) { + if (IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) { + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("Invalid Configuration:%s"), __func__); + return -EINVAL; + } else { + /*Static wep, update the roam profile with the keys */ + if (ext->key + && (ext->key_len <= + eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES) + && key_index < CSR_MAX_NUM_KEY) { + cdf_mem_copy(&pRoamProfile->Keys. + KeyMaterial[key_index][0], + ext->key, ext->key_len); + pRoamProfile->Keys.KeyLength[key_index] = + (uint8_t) ext->key_len; + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + pRoamProfile->Keys.defaultIndex = + (uint8_t) key_index; + + } + } + return ret; + } + + cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + + setKey.keyId = key_index; + setKey.keyLength = ext->key_len; + + if (ext->key_len <= CSR_MAX_KEY_LEN) { + cdf_mem_copy(&setKey.Key[0], ext->key, ext->key_len); + } + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /*Key direction for group is RX only */ + setKey.keyDirection = eSIR_RX_ONLY; + cdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + + setKey.keyDirection = eSIR_TX_RX; + cdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + CDF_MAC_ADDR_SIZE); + } + + /*For supplicant pae role is zero */ + setKey.paeRole = 0; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case IW_ENCODE_ALG_WEP: + setKey.encType = + (ext->key_len == + 5) ? eCSR_ENCRYPT_TYPE_WEP40 : eCSR_ENCRYPT_TYPE_WEP104; + break; + + case IW_ENCODE_ALG_TKIP: + { + uint8_t *pKey = &setKey.Key[0]; + + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + cdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /* Supplicant sends the 32bytes key in this order + * |--------------|----------|----------| + * | Tk1 | TX MIC | RX MIC | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + * + * + * Sme expects the 32 bytes key to be in the below order + * |--------------|----------|----------| + * | Tk1 | RX MIC | TX MIC | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + */ + + /* Copy the Temporal Key 1 (TK1) */ + cdf_mem_copy(pKey, ext->key, 16); + + /* Copy the rx mic first */ + cdf_mem_copy(&pKey[16], &ext->key[24], 8); + + /* Copy the tx mic */ + cdf_mem_copy(&pKey[24], &ext->key[16], 8); + + } + break; + + case IW_ENCODE_ALG_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + +#ifdef FEATURE_WLAN_ESE +#define IW_ENCODE_ALG_KRK 6 + case IW_ENCODE_ALG_KRK: + setKey.encType = eCSR_ENCRYPT_TYPE_KRK; + break; +#endif /* FEATURE_WLAN_ESE */ + + default: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("%s:cipher_alg:%d key_len[%d] *pEncryptionType :%d"), + __func__, (int)ext->alg, (int)ext->key_len, setKey.encType); + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* The supplicant may attempt to set the PTK once + * pre-authentication is done. Save the key in the UMAC and + * include it in the ADD BSS request + */ + cdf_ret_status = sme_ft_update_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey); + if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_INFO_MED, + "%s: Update PreAuth Key success", __func__); + return 0; + } else if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_FAILED) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Update PreAuth Key failed", __func__); + return -EINVAL; + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + + cdf_ret_status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &setKey, &roamId); + + if (cdf_ret_status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "[%4d] sme_roam_set_key returned ERROR status= %d", + __LINE__, cdf_ret_status); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } + + return cdf_ret_status; +} + +/** + * iw_set_encodeext() - SSR wrapper for __iw_set_encodeext() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_encodeext(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_retry() - SIOCSIWRETRY ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->retry.value < WNI_CFG_LONG_RETRY_LIMIT_STAMIN || + wrqu->retry.value > WNI_CFG_LONG_RETRY_LIMIT_STAMAX) { + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("Invalid Retry-Limit=%d!!"), wrqu->retry.value); + + return -EINVAL; + } + + if (wrqu->retry.flags & IW_RETRY_LIMIT) { + + if ((wrqu->retry.flags & IW_RETRY_LONG)) { + if (sme_cfg_set_int (hHal, WNI_CFG_LONG_RETRY_LIMIT, + wrqu->retry.value) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_LONG_RETRY_LIMIT")); + return -EIO; + } + } else if ((wrqu->retry.flags & IW_RETRY_SHORT)) { + if (sme_cfg_set_int (hHal, WNI_CFG_SHORT_RETRY_LIMIT, + wrqu->retry.value) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_LONG_RETRY_LIMIT")); + return -EIO; + } + } + } else { + return -EOPNOTSUPP; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("Set Retry-Limit=%d!!"), wrqu->retry.value); + + EXIT(); + + return 0; + +} + +/** + * iw_set_retry() - SSR wrapper for __iw_set_retry() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_retry(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_retry() - SIOCGIWRETRY ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t retry = 0; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if ((wrqu->retry.flags & IW_RETRY_LONG)) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + + if (sme_cfg_get_int(hHal, WNI_CFG_LONG_RETRY_LIMIT, &retry) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL + ("failed to get ini parameter, WNI_CFG_LONG_RETRY_LIMIT")); + return -EIO; + } + + wrqu->retry.value = retry; + } else if ((wrqu->retry.flags & IW_RETRY_SHORT)) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + + if (sme_cfg_get_int(hHal, WNI_CFG_SHORT_RETRY_LIMIT, &retry) != + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL + ("failed to get ini parameter, WNI_CFG_LONG_RETRY_LIMIT")); + return -EIO; + } + + wrqu->retry.value = retry; + } else { + return -EOPNOTSUPP; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, ("Retry-Limit=%d!!"), + retry); + + EXIT(); + + return 0; +} + +/** + * iw_get_retry() - SSR wrapper for __iw_get_retry() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_retry(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_mlme() - SIOCSIWMLME ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* reason_code is unused. By default it is set to + * eCSR_DISCONNECT_REASON_UNSPECIFIED + */ + switch (mlme->cmd) { + case IW_MLME_DISASSOC: + case IW_MLME_DEAUTH: + + if (pHddStaCtx->conn_info.connState == + eConnectionState_Associated) { + eCsrRoamDisconnectReason reason = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + + if (mlme->reason_code == HDD_REASON_MICHAEL_MIC_FAILURE) + reason = eCSR_DISCONNECT_REASON_MIC_ERROR; + + INIT_COMPLETION(pAdapter->disconnect_comp_var); + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, reason); + + if (CDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hddLog(CDF_TRACE_LEVEL_ERROR, + FL + ("failed wait on disconnect_comp_var")); + } else + hddLog(LOGE, + "%s %d Command Disassociate/Deauthenticate : csr_roam_disconnect failure returned %d", + __func__, (int)mlme->cmd, (int)status); + + /* Resetting authKeyMgmt */ + (WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter))->authKeyMgmt = + 0; + + hddLog(LOG1, FL("Disabling queues")); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_CONTROL_PATH); + + } else { + hddLog(LOGE, + "%s %d Command Disassociate/Deauthenticate called but station is not in associated state", + __func__, (int)mlme->cmd); + } + break; + default: + hddLog(LOGE, + "%s %d Command should be Disassociate/Deauthenticate", + __func__, (int)mlme->cmd); + return -EINVAL; + } /* end of switch */ + + EXIT(); + + return status; + +} + +/** + * iw_set_mlme() - SSR wrapper for __iw_set_mlme() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_mlme(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_update_phymode() - handle change in PHY mode + * @net: device upon which PHY mode change was received + * @hal: umac handle for the driver + * @new_phymode: new PHY mode for the device + * @phddctx: pointer to the HDD context + * + * This function is called when the device is set to a new PHY mode. + * It takes a holistic look at the desired PHY mode along with the + * configured capabilities of the driver and the reported capabilities + * of the hardware in order to correctly configure all PHY-related + * parameters. + * + * Return: 0 on success, negative errno value on error + */ +int wlan_hdd_update_phymode(struct net_device *net, tHalHandle hal, + int new_phymode, hdd_context_t *phddctx) +{ +#ifdef QCA_HT_2040_COEX + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(net); + CDF_STATUS halStatus = CDF_STATUS_E_FAILURE; +#endif + bool band_24 = false, band_5g = false; + bool ch_bond24 = false, ch_bond5g = false; + tSmeConfigParams smeconfig; + uint32_t chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; +#ifdef WLAN_FEATURE_11AC + uint32_t vhtchanwidth; +#endif + eCsrPhyMode phymode = -EIO, old_phymode; + eHddDot11Mode hdd_dot11mode = phddctx->config->dot11Mode; + eCsrBand curr_band = eCSR_BAND_ALL; + + old_phymode = sme_get_phy_mode(hal); + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode24GHz)) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode5GHz)) + ch_bond5g = true; + + if (phddctx->config->nBandCapability == eCSR_BAND_ALL) { + band_24 = band_5g = true; + } else if (phddctx->config->nBandCapability == eCSR_BAND_24) { + band_24 = true; + } else if (phddctx->config->nBandCapability == eCSR_BAND_5G) { + band_5g = true; + } + + vhtchanwidth = phddctx->config->vhtChannelWidth; + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, ("ch_bond24=%d " + "ch_bond5g=%d band_24=%d band_5g=%d VHT_ch_width=%u"), + ch_bond24, ch_bond5g, band_24, band_5g, vhtchanwidth); + + switch (new_phymode) { + case IEEE80211_MODE_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if (hdd_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_ALL; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11A: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11a); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11a; + hdd_dot11mode = eHDD_DOT11_MODE_11a; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11B: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11b); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11b; + hdd_dot11mode = eHDD_DOT11_MODE_11b; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11G: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11g); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11g; + hdd_dot11mode = eHDD_DOT11_MODE_11g; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + /* UMAC doesnt have option to set MODE_11NA/MODE_11NG as phymode + * so setting phymode as eCSR_DOT11_MODE_11n and updating the band + * and channel bonding in configuration to reflect MODE_11NA/MODE_11NG + */ + case IEEE80211_MODE_11NA_HT20: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NA_HT40: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT20: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT40: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; +#ifdef WLAN_FEATURE_11AC + case IEEE80211_MODE_11AC_VHT20: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11ac); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11ac; + hdd_dot11mode = eHDD_DOT11_MODE_11ac; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; +#endif + case IEEE80211_MODE_2G_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_5G_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11AGN: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_ALL; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + default: + return -EIO; + } + +#ifdef WLAN_FEATURE_11AC + switch (new_phymode) { + case IEEE80211_MODE_11AC_VHT20: + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_20MHZ; + break; + case IEEE80211_MODE_11AC_VHT40: + vhtchanwidth = eHT_CHANNEL_WIDTH_40MHZ; + break; + case IEEE80211_MODE_11AC_VHT80: + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + break; + default: + vhtchanwidth = phddctx->config->vhtChannelWidth; + break; + } +#endif + + if (phymode != -EIO) { + sme_get_config_param(hal, &smeconfig); + smeconfig.csrConfig.phyMode = phymode; +#ifdef QCA_HT_2040_COEX + if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + smeconfig.csrConfig.obssEnabled = false; + halStatus = sme_set_ht2040_mode(hal, + pAdapter->sessionId, + eHT_CHAN_HT20, false); + if (halStatus == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Failed to disable OBSS")); + return -EIO; + } + } else if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) { + smeconfig.csrConfig.obssEnabled = true; + halStatus = sme_set_ht2040_mode(hal, + pAdapter->sessionId, + eHT_CHAN_HT20, true); + if (halStatus == CDF_STATUS_E_FAILURE) { + hddLog(LOGE, FL("Failed to enable OBSS")); + return -EIO; + } + } +#endif + smeconfig.csrConfig.eBand = curr_band; + smeconfig.csrConfig.bandCapability = curr_band; + if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.Is11hSupportEnabled = 0; + else + smeconfig.csrConfig.Is11hSupportEnabled = + phddctx->config->Is11hSupportEnabled; + if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.channelBondingMode24GHz = chwidth; + else if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.channelBondingMode5GHz = chwidth; + else { + smeconfig.csrConfig.channelBondingMode24GHz = chwidth; + smeconfig.csrConfig.channelBondingMode5GHz = chwidth; + } +#ifdef WLAN_FEATURE_11AC + smeconfig.csrConfig.nVhtChannelWidth = vhtchanwidth; +#endif + sme_update_config(hal, &smeconfig); + + phddctx->config->dot11Mode = hdd_dot11mode; + phddctx->config->nBandCapability = curr_band; + phddctx->config->nChannelBondingMode24GHz = + smeconfig.csrConfig.channelBondingMode24GHz; + phddctx->config->nChannelBondingMode5GHz = + smeconfig.csrConfig.channelBondingMode5GHz; + phddctx->config->vhtChannelWidth = vhtchanwidth; + if (hdd_update_config_dat(phddctx) == false) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: could not update config_dat", __func__); + return -EIO; + } + if (phddctx->config->nChannelBondingMode5GHz) + phddctx->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.cap + |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + phddctx->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap.cap + &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "New_Phymode= %d ch_bonding=%d band=%d VHT_ch_width=%u", + phymode, chwidth, curr_band, vhtchanwidth); + } + + return 0; +} + +/** + * hdd_get_temperature_cb() - "Get Temperature" callback function + * @temperature: measured temperature + * @pContext: callback context + * + * This function is passed to sme_get_temperature() as the callback + * function to be invoked when the temperature measurement is + * available. + * + * Return: None + */ +static void hdd_get_temperature_cb(int temperature, void *pContext) +{ + struct statsContext *pTempContext; + hdd_adapter_t *pAdapter; + ENTER(); + if (NULL == pContext) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("pContext is NULL")); + return; + } + pTempContext = pContext; + pAdapter = pTempContext->pAdapter; + spin_lock(&hdd_context_lock); + if ((NULL == pAdapter) || (TEMP_CONTEXT_MAGIC != pTempContext->magic)) { + spin_unlock(&hdd_context_lock); + hddLog(CDF_TRACE_LEVEL_WARN, + FL("Invalid context, pAdapter [%p] magic [%08x]"), + pAdapter, pTempContext->magic); + return; + } + if (temperature != 0) { + pAdapter->temperature = temperature; + } + complete(&pTempContext->completion); + spin_unlock(&hdd_context_lock); + EXIT(); +} + +/** + * wlan_hdd_get_temperature() - get current device temperature + * @pAdapter: device upon which the request was made + * @temperature: pointer to where the temperature is to be returned + * + * Return: 0 if a temperature value (either current or cached) was + * returned, otherwise a negative errno is returned. + * + */ +int wlan_hdd_get_temperature(hdd_adapter_t *pAdapter, int *temperature) +{ + CDF_STATUS status; + struct statsContext tempContext; + unsigned long rc; + + ENTER(); + if (NULL == pAdapter) { + hddLog(CDF_TRACE_LEVEL_ERROR, FL("pAdapter is NULL")); + return -EPERM; + } + init_completion(&tempContext.completion); + tempContext.pAdapter = pAdapter; + tempContext.magic = TEMP_CONTEXT_MAGIC; + status = sme_get_temperature(WLAN_HDD_GET_HAL_CTX(pAdapter), + &tempContext, hdd_get_temperature_cb); + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL("Unable to retrieve temperature")); + } else { + rc = wait_for_completion_timeout(&tempContext.completion, + msecs_to_jiffies + (WLAN_WAIT_TIME_STATS)); + if (!rc) { + hddLog(CDF_TRACE_LEVEL_ERROR, + FL + ("SME timed out while retrieving temperature")); + } + } + spin_lock(&hdd_context_lock); + tempContext.magic = 0; + spin_unlock(&hdd_context_lock); + *temperature = pAdapter->temperature; + EXIT(); + return 0; +} + +/** + * iw_setint_getnone() - Generic "set integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + tSmeConfigParams smeConfig; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + int ret; + int enable_pbm, enable_mp; + + INIT_COMPLETION(pWextState->completion_var); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_SET_11D_STATE: + { + if ((ENABLE_11D == set_value) + || (DISABLE_11D == set_value)) { + + memset(&smeConfig, 0x00, sizeof(smeConfig)); + sme_get_config_param(hHal, &smeConfig); + smeConfig.csrConfig.Is11dSupportEnabled = + (bool) set_value; + + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + ("11D state=%d!!"), + smeConfig.csrConfig. + Is11dSupportEnabled); + + sme_update_config(hHal, &smeConfig); + } else { + return -EINVAL; + } + break; + } + + case WE_WOWL: + { + switch (set_value) { + case 0x00: + hdd_exit_wowl(pAdapter); + break; + case 0x01: + case 0x02: + case 0x03: + enable_mp = (set_value & 0x01) ? 1 : 0; + enable_pbm = (set_value & 0x02) ? 1 : 0; + hddLog(LOGE, + "magic packet ? = %s pattern byte matching ? = %s", + (enable_mp ? "YES" : "NO"), + (enable_pbm ? "YES" : "NO")); + hdd_enter_wowl(pAdapter, enable_mp, enable_pbm); + break; + default: + hddLog(LOGE, "Invalid arg %d in WE_WOWL IOCTL", + set_value); + ret = -EINVAL; + break; + } + + break; + } + case WE_SET_POWER: + { + switch (set_value) { + case 1: + /* Enable PowerSave */ + sme_ps_enable_disable(hHal, pAdapter->sessionId, + SME_PS_ENABLE); + break; + case 2: + /* Disable PowerSave */ + sme_ps_enable_disable(hHal, pAdapter->sessionId, + SME_PS_DISABLE); + break; + case 3: /* Enable UASPD */ + sme_ps_uapsd_enable(hHal, pAdapter->sessionId); + break; + case 4: /* Disable UASPD */ + sme_ps_uapsd_disable(hHal, pAdapter->sessionId); + break; + default: + hddLog(LOGE, + "Invalid arg %d in WE_SET_POWER IOCTL", + set_value); + ret = -EINVAL; + break; + } + break; + } + + case WE_SET_MAX_ASSOC: + { + if ((WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) || + (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value)) { + ret = -EINVAL; + } else if (sme_cfg_set_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + set_value) + != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, FL + ("failed to set ini parameter, WNI_CFG_ASSOC_STA_LIMIT")); + ret = -EIO; + } + break; + } + + case WE_SET_SAP_AUTO_CHANNEL_SELECTION: + if (set_value == 0 || set_value == 1) + (WLAN_HDD_GET_CTX(pAdapter))->config->force_sap_acs = + set_value; + else + ret = -EINVAL; + break; + + case WE_SET_DATA_INACTIVITY_TO: + { + if ((set_value < CFG_DATA_INACTIVITY_TIMEOUT_MIN) || + (set_value > CFG_DATA_INACTIVITY_TIMEOUT_MAX) || + (sme_cfg_set_int((WLAN_HDD_GET_CTX(pAdapter))->hHal, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + set_value) == CDF_STATUS_E_FAILURE)) { + hddLog(LOGE, "Failure: Could not pass on " + "WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT configuration info " + "to CCM"); + ret = -EINVAL; + } + break; + } + case WE_SET_MC_RATE: + { + ret = wlan_hdd_set_mc_rate(pAdapter, set_value); + break; + } + case WE_SET_TX_POWER: + { + tSirMacAddr bssid; + + cdf_mem_copy(bssid, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + if (sme_set_tx_power + (hHal, pAdapter->sessionId, bssid, + pAdapter->device_mode, + set_value) != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Setting tx power failed", __func__); + return -EIO; + } + break; + } + case WE_SET_MAX_TX_POWER: + { + tSirMacAddr bssid; + tSirMacAddr selfMac; + + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Setting maximum tx power %d dBm", __func__, + set_value); + cdf_mem_copy(bssid, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(selfMac, pHddStaCtx->conn_info.bssId.bytes, + CDF_MAC_ADDR_SIZE); + + if (sme_set_max_tx_power(hHal, bssid, selfMac, set_value) + != CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Setting maximum tx power failed", + __func__); + return -EIO; + } + + break; + } + case WE_SET_MAX_TX_POWER_2_4: + { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Setting maximum tx power %d dBm for 2.4 GHz band", + __func__, set_value); + if (sme_set_max_tx_power_per_band(eCSR_BAND_24, set_value) != + CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Setting maximum tx power failed for 2.4 GHz band", + __func__); + return -EIO; + } + + break; + } + case WE_SET_MAX_TX_POWER_5_0: + { + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Setting maximum tx power %d dBm for 5.0 GHz band", + __func__, set_value); + if (sme_set_max_tx_power_per_band(eCSR_BAND_5G, set_value) != + CDF_STATUS_SUCCESS) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Setting maximum tx power failed for 5.0 GHz band", + __func__); + return -EIO; + } + + break; + } + case WE_SET_HIGHER_DTIM_TRANSITION: + { + if (!((set_value == false) || (set_value == true))) { + hddLog(LOGE, "Dynamic DTIM Incorrect data:%d", + set_value); + ret = -EINVAL; + } else { + if (pAdapter->higherDtimTransition != set_value) { + pAdapter->higherDtimTransition = + set_value; + hddLog(LOG1, + "%s: higherDtimTransition set to :%d", + __func__, + pAdapter->higherDtimTransition); + } + } + + break; + } + + case WE_SET_TM_LEVEL: + { + hddLog(CDF_TRACE_LEVEL_INFO, + "Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(hHal, set_value); + break; + } + + case WE_SET_PHYMODE: + { + hdd_context_t *phddctx = WLAN_HDD_GET_CTX(pAdapter); + + ret = + wlan_hdd_update_phymode(dev, hHal, set_value, + phddctx); + break; + } + + case WE_SET_NSS: + { + hddLog(LOG1, "Set NSS = %d", set_value); + if ((set_value > 2) || (set_value <= 0)) { + hddLog(LOGE, "NSS greater than 2 not supported"); + ret = -EINVAL; + } else { + if (CDF_STATUS_SUCCESS != + hdd_update_nss(WLAN_HDD_GET_CTX(pAdapter), + set_value)) + ret = -EINVAL; + } + break; + } + + case WE_SET_GTX_HT_MCS: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_HT_MCS %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_VHT_MCS: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_VHT_MCS %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_USRCFG: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_USR_CFG %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_THRE: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_THRE %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MARGIN: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_MARGIN %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_STEP: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_STEP %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MINTPC: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_MINTPC %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_BWMASK: + { + hddLog(LOG1, "WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + set_value, GTX_CMD); + break; + } + + case WE_SET_LDPC: + { + uint32_t value; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + + hddLog(LOG1, "LDPC val %d", set_value); + /* get the HT capability info */ + ret = sme_cfg_get_int(hHal, WNI_CFG_HT_CAP_INFO, &value); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: could not get HT capability info", + __func__); + return -EIO; + } + + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value; + if ((set_value + && (uHTCapabilityInfo.htCapInfo.advCodingCap)) + || (!set_value)) { + ret = + sme_update_ht_config(hHal, + pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING, + set_value); + } + + if (ret) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Failed to set LDPC value"); + + break; + } + + case WE_SET_TX_STBC: + { + uint32_t value; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + + hddLog(LOG1, "TX_STBC val %d", set_value); + /* get the HT capability info */ + ret = sme_cfg_get_int(hHal, WNI_CFG_HT_CAP_INFO, &value); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "%s: could not get HT capability info", + __func__); + return -EIO; + } + + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value; + if ((set_value && (uHTCapabilityInfo.htCapInfo.txSTBC)) + || (!set_value)) { + ret = + sme_update_ht_config(hHal, + pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_TX_STBC, + set_value); + } + + if (ret) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Failed to set TX STBC value"); + + break; + } + + case WE_SET_RX_STBC: + { + uint32_t value; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + + hddLog(LOG1, "WMI_VDEV_PARAM_RX_STBC val %d", + set_value); + /* get the HT capability info */ + ret = sme_cfg_get_int(hHal, WNI_CFG_HT_CAP_INFO, &value); + if (CDF_STATUS_SUCCESS != ret) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: could not get HT capability info", + __func__); + return -EIO; + } + + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value; + if ((set_value && (uHTCapabilityInfo.htCapInfo.rxSTBC)) + || (!set_value)) { + ret = + sme_update_ht_config(hHal, + pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_RX_STBC, + (!set_value) ? set_value + : uHTCapabilityInfo. + htCapInfo.rxSTBC); + } + + if (ret) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Failed to set RX STBC value"); + break; + } + + case WE_SET_SHORT_GI: + { + hddLog(LOG1, "WMI_VDEV_PARAM_SGI val %d", set_value); + ret = sme_update_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + set_value); + if (ret) + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Failed to set ShortGI value"); + break; + } + + case WE_SET_RTSCTS: + { + uint32_t value; + + hddLog(LOG1, "WMI_VDEV_PARAM_ENABLE_RTSCTS val 0x%x", + set_value); + + if ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_RTSCTS_ENABLE) + value = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + RTSThreshold; + else if (((set_value & HDD_RTSCTS_EN_MASK) == 0) + || ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_CTS_ENABLE)) + value = WNI_CFG_RTS_THRESHOLD_STAMAX; + else + return -EIO; + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + set_value, VDEV_CMD); + if (!ret) { + if (sme_cfg_set_int + (hHal, WNI_CFG_RTS_THRESHOLD, value) != + CDF_STATUS_SUCCESS) { + hddLog(LOGE, "FAILED TO SET RTSCTS"); + return -EIO; + } + } + + break; + } + + case WE_SET_CHWIDTH: + { + bool chwidth = false; + hdd_context_t *phddctx = WLAN_HDD_GET_CTX(pAdapter); + /*updating channel bonding only on 5Ghz */ + hddLog(LOG1, "WMI_VDEV_PARAM_CHWIDTH val %d", + set_value); + if (set_value > eHT_CHANNEL_WIDTH_80MHZ) { + hddLog(LOGE, + "Invalid channel width 0->20 1->40 2->80"); + return -EINVAL; + } + + if ((WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + csr_convert_cb_ini_value_to_phy_cb_state(phddctx->config-> + nChannelBondingMode5GHz))) + chwidth = true; + + memset(&smeConfig, 0x00, sizeof(smeConfig)); + sme_get_config_param(hHal, &smeConfig); + switch (set_value) { + case eHT_CHANNEL_WIDTH_20MHZ: + smeConfig.csrConfig.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + case eHT_CHANNEL_WIDTH_40MHZ: + if (chwidth) + smeConfig.csrConfig. + channelBondingMode5GHz = + phddctx->config-> + nChannelBondingMode5GHz; + else + return -EINVAL; + + break; +#ifdef WLAN_FEATURE_11AC + case eHT_CHANNEL_WIDTH_80MHZ: + if (chwidth) + smeConfig.csrConfig. + channelBondingMode5GHz = + phddctx->config-> + nChannelBondingMode5GHz; + else + return -EINVAL; + + break; +#endif + + default: + return -EINVAL; + } + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_CHWIDTH, + set_value, VDEV_CMD); + if (!ret) + sme_update_config(hHal, &smeConfig); + + break; + } + + case WE_SET_ANI_EN_DIS: + { + hddLog(LOG1, "WMI_PDEV_PARAM_ANI_ENABLE val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_ENABLE, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_POLL_PERIOD: + { + hddLog(LOG1, "WMI_PDEV_PARAM_ANI_POLL_PERIOD val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_LISTEN_PERIOD: + { + hddLog(LOG1, "WMI_PDEV_PARAM_ANI_LISTEN_PERIOD val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_OFDM_LEVEL: + { + hddLog(LOG1, "WMI_PDEV_PARAM_ANI_OFDM_LEVEL val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_CCK_LEVEL: + { + hddLog(LOG1, "WMI_PDEV_PARAM_ANI_CCK_LEVEL val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_DYNAMIC_BW: + { + hddLog(LOG1, "WMI_PDEV_PARAM_DYNAMIC_BW val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_DYNAMIC_BW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_CTS_CBW: + { + hddLog(LOG1, "WE_SET_CTS_CBW val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_CTS_CBW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + hddLog(LOG1, "WMI_VDEV_PARAM_FIXED_RATE val %d", + set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else { + nss = 0; + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x10) { + preamble = + WMI_RATE_PREAMBLE_CCK; + if (rix != 0x3) + /* Enable Short + * preamble always for + * CCK except 1mbps + */ + rix |= 0x4; + } else { + preamble = + WMI_RATE_PREAMBLE_OFDM; + } + } + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX_11AC(set_value); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(set_value) - 1; + + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_AMPDU: + { + hddLog(LOG1, "SET AMPDU val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case WE_SET_AMSDU: + { + hddLog(LOG1, "SET AMSDU val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + break; + } + + case WE_SET_BURST_ENABLE: + { + hddLog(LOG1, "SET Burst enable val %d", set_value); + if ((set_value == 0) || (set_value == 1)) { + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + set_value, PDEV_CMD); + } else + ret = -EINVAL; + break; + } + case WE_SET_BURST_DUR: + { + hddLog(LOG1, "SET Burst duration val %d", set_value); + if ((set_value > 0) && (set_value <= 8192)) + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_DUR, + set_value, PDEV_CMD); + else + ret = -EINVAL; + break; + } + + case WE_SET_TX_CHAINMASK: + { + hddLog(LOG1, "WMI_PDEV_PARAM_TX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case WE_SET_RX_CHAINMASK: + { + hddLog(LOG1, "WMI_PDEV_PARAM_RX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case WE_SET_TXPOW_2G: + { + hddLog(LOG1, "WMI_PDEV_PARAM_TXPOWER_LIMIT2G val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + set_value, PDEV_CMD); + break; + } + + case WE_SET_TXPOW_5G: + { + hddLog(LOG1, "WMI_PDEV_PARAM_TXPOWER_LIMIT5G val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + set_value, PDEV_CMD); + break; + } + + case WE_SET_POWER_GATING: + { + hddLog(LOG1, "WMI_PDEV_PARAM_POWER_GATING_SLEEP val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_POWER_GATING_SLEEP, + (set_value) ? true : false, PDEV_CMD); + break; + } + + /* Firmware debug log */ + case WE_DBGLOG_LOG_LEVEL: + { + hddLog(LOG1, "WE_DBGLOG_LOG_LEVEL val %d", set_value); + hdd_ctx->fw_log_settings.dl_loglevel = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_ENABLE: + { + hddLog(LOG1, "WE_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_DISABLE: + { + hddLog(LOG1, "WE_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_ENABLE: + { + hddLog(LOG1, "WE_DBGLOG_MODULE_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_DISABLE: + { + hddLog(LOG1, "WE_DBGLOG_MODULE_DISABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_MOD_LOG_LEVEL: + { + hddLog(LOG1, "WE_DBGLOG_MOD_LOG_LEVEL val %d", + set_value); + + if (hdd_ctx->fw_log_settings.index >= MAX_MOD_LOGLEVEL) + hdd_ctx->fw_log_settings.index = 0; + + hdd_ctx->fw_log_settings. + dl_mod_loglevel[hdd_ctx->fw_log_settings.index] = + set_value; + hdd_ctx->fw_log_settings.index++; + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_TYPE: + { + hddLog(LOG1, "WE_DBGLOG_TYPE val %d", set_value); + hdd_ctx->fw_log_settings.dl_type = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_REPORT_ENABLE: + { + hddLog(LOG1, "WE_DBGLOG_REPORT_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.dl_report = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_SET_TXRX_FWSTATS: + { + hddLog(LOG1, "WE_SET_TXRX_FWSTATS val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_TXRX_FWSTATS_RESET: + { + hddLog(LOG1, "WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_DUMP_STATS: + { + hddLog(LOG1, "WE_DUMP_STATS val %d", set_value); + hdd_wlan_dump_stats(pAdapter, set_value); + break; + } + + case WE_CLEAR_STATS: + { + hddLog(LOG1, "WE_CLEAR_STATS val %d", set_value); + switch (set_value) { + case WLAN_HDD_STATS: + memset(&pAdapter->stats, 0, sizeof(pAdapter->stats)); + memset(&pAdapter->hdd_stats, 0, + sizeof(pAdapter->hdd_stats)); + break; + case WLAN_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(hdd_ctx); + break; + default: + ol_txrx_clear_stats(set_value); + } + break; + } + + case WE_PPS_PAID_MATCH: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + + hddLog(LOG1, "WMI_VDEV_PPS_PAID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_PAID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_MATCH: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_GID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_TIM_CLEAR: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, " WMI_VDEV_PPS_EARLY_TIM_CLEAR val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_DTIM_CLEAR: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_EARLY_DTIM_CLEAR val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EOF_PAD_DELIM: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_EOF_PAD_DELIM val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EOF_PAD_DELIM, + set_value, PPS_CMD); + break; + } + + case WE_PPS_MACADDR_MISMATCH: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_MACADDR_MISMATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_MACADDR_MISMATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_DELIM_CRC_FAIL: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_DELIM_CRC_FAIL val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_NSTS_ZERO: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_GID_NSTS_ZERO val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_NSTS_ZERO, + set_value, PPS_CMD); + break; + } + + case WE_PPS_RSSI_CHECK: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return EINVAL; + hddLog(LOG1, "WMI_VDEV_PPS_RSSI_CHECK val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_RSSI_CHECK, + set_value, PPS_CMD); + break; + } + + case WE_PPS_5G_EBT: + { + if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION) + return -EINVAL; + + hddLog(LOG1, "WMI_VDEV_PPS_5G_EBT val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_5G_EBT, + set_value, PPS_CMD); + break; + } + + case WE_SET_HTSMPS: + { + hddLog(LOG1, "WE_SET_HTSMPS val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_SMPS_FORCE_MODE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_SET_QPOWER_MAX_PSPOLL_COUNT: + { + hddLog(LOG1, "WE_SET_QPOWER_MAX_PSPOLL_COUNT val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hddLog(LOG1, "WE_SET_QPOWER_MAX_TX_BEFORE_WAKE val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hddLog(LOG1, + "WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hddLog(LOG1, + "WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + set_value, QPOWER_CMD); + break; + } + + case WE_MCC_CONFIG_LATENCY: + { + cds_set_mcc_latency(pAdapter, set_value); + break; + } + + case WE_MCC_CONFIG_QUOTA: + { + hddLog(LOG1, "iwpriv cmd to set MCC quota with val %dms", + set_value); + ret = cds_set_mcc_p2p_quota(pAdapter, set_value); + break; + } + case WE_SET_DEBUG_LOG: + { + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); +#ifdef QCA_PKT_PROTO_TRACE + /* Trace buffer dump only */ + if (CDS_PKT_TRAC_DUMP_CMD == set_value) { + cds_pkt_trace_buf_dump(); + break; + } +#endif /* QCA_PKT_PROTO_TRACE */ + hdd_ctx->config->gEnableDebugLog = set_value; + sme_update_connect_debug(hdd_ctx->hHal, set_value); + break; + } + case WE_SET_EARLY_RX_ADJUST_ENABLE: + { + hddLog(LOG1, "SET early_rx enable val %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_TGT_BMISS_NUM: + { + hddLog(LOG1, "SET early_rx bmiss val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE: + { + hddLog(LOG1, "SET early_rx bmiss sample cycle %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_SLOP_STEP: + { + hddLog(LOG1, "SET early_rx bmiss slop step val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_INIT_SLOP: + { + hddLog(LOG1, "SET early_rx init slop step val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_ADJUST_PAUSE: + { + hddLog(LOG1, "SET early_rx adjust pause %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_DRIFT_SAMPLE: + { + hddLog(LOG1, "SET early_rx drift sample %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_SCAN_DISABLE: + { + hddLog(LOG1, "SET SCAN DISABLE %d", set_value); + sme_set_scan_disable(WLAN_HDD_GET_HAL_CTX(pAdapter), set_value); + break; + } + default: + { + hddLog(LOGE, "%s: Invalid sub command %d", __func__, + sub_cmd); + ret = -EINVAL; + break; + } + } + return ret; +} + +static int iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setint_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setchar_getnone() - Generic "set string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + CDF_STATUS vstatus; + int sub_cmd; + int ret; + char *pBuffer = NULL; + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); +#ifdef WLAN_FEATURE_VOWIFI + struct hdd_config *pConfig = hdd_ctx->config; +#endif /* WLAN_FEATURE_VOWIFI */ + struct iw_point s_priv_data; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + return -EINVAL; + } + + /* make sure all params are correctly passed to function */ + if ((NULL == s_priv_data.pointer) || (0 == s_priv_data.length)) { + return -EINVAL; + } + + sub_cmd = s_priv_data.flags; + + /* ODD number is used for set, copy data using copy_from_user */ + pBuffer = mem_alloc_copy_from_user_helper(s_priv_data.pointer, + s_priv_data.length); + if (NULL == pBuffer) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received length %d", __func__, s_priv_data.length); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Received data %s", __func__, pBuffer); + + switch (sub_cmd) { + case WE_WOWL_ADD_PTRN: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "ADD_PTRN"); + hdd_add_wowl_ptrn(pAdapter, pBuffer); + break; + case WE_WOWL_DEL_PTRN: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "DEL_PTRN"); + hdd_del_wowl_ptrn(pAdapter, pBuffer); + break; +#if defined WLAN_FEATURE_VOWIFI + case WE_NEIGHBOR_REPORT_REQUEST: + { + tRrmNeighborReq neighborReq; + tRrmNeighborRspCallbackInfo callbackInfo; + + if (pConfig->fRrmEnable) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "Neighbor Request"); + neighborReq.no_ssid = + (s_priv_data.length - 1) ? false : true; + if (!neighborReq.no_ssid) { + neighborReq.ssid.length = + (s_priv_data.length - 1) > + 32 ? 32 : (s_priv_data.length - 1); + cdf_mem_copy(neighborReq.ssid.ssId, + pBuffer, + neighborReq.ssid.length); + } + + callbackInfo.neighborRspCallback = NULL; + callbackInfo.neighborRspCallbackContext = NULL; + callbackInfo.timeout = 5000; /* 5 seconds */ + sme_neighbor_report_request(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &neighborReq, + &callbackInfo); + } else { + hddLog(LOGE, + "%s: Ignoring neighbor request as RRM is not enabled", + __func__); + ret = -EINVAL; + } + } + break; +#endif + case WE_SET_AP_WPS_IE: + hddLog(LOGE, "Received WE_SET_AP_WPS_IE"); + sme_update_p2p_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), pBuffer, + s_priv_data.length); + break; + case WE_SET_CONFIG: + vstatus = hdd_execute_global_config_command(hdd_ctx, pBuffer); + if (CDF_STATUS_SUCCESS != vstatus) { + ret = -EINVAL; + } + break; + default: + { + hddLog(LOGE, "%s: Invalid sub command %d", __func__, + sub_cmd); + ret = -EINVAL; + break; + } + } + kfree(pBuffer); + return ret; +} + +static int iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setchar_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setnone_getint() - Generic "get integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int *value = (int *)extra; + int ret; + tSmeConfigParams smeConfig; + hdd_context_t *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (value[0]) { + case WE_GET_11D_STATE: + { + sme_get_config_param(hHal, &smeConfig); + + *value = smeConfig.csrConfig.Is11dSupportEnabled; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("11D state=%d!!"), *value); + + break; + } + + case WE_IBSS_STATUS: + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "****Return IBSS Status*****"); + break; + + case WE_GET_WLAN_DBG: + { + cdf_trace_display(); + *value = 0; + break; + } + case WE_GET_MAX_ASSOC: + { + if (sme_cfg_get_int + (hHal, WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *) value) != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_WARN, FL + ("failed to get ini parameter, WNI_CFG_ASSOC_STA_LIMIT")); + ret = -EIO; + } + break; + } + case WE_GET_SAP_AUTO_CHANNEL_SELECTION: + *value = (WLAN_HDD_GET_CTX( + pAdapter))->config->force_sap_acs; + break; + + case WE_GET_CONCURRENCY_MODE: + { + *value = cds_get_concurrency_mode(); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + ("concurrency mode=%d"), *value); + break; + } + + case WE_GET_NSS: + { + sme_get_config_param(hHal, &smeConfig); + *value = (smeConfig.csrConfig.enable2x2 == 0) ? 1 : 2; + hddLog(LOG1, "GET_NSS: Current NSS:%d", *value); + break; + } + + case WE_GET_GTX_HT_MCS: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_HT_MCS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + GTX_CMD); + break; + } + + case WE_GET_GTX_VHT_MCS: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_VHT_MCS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + GTX_CMD); + break; + } + + case WE_GET_GTX_USRCFG: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_USR_CFG"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + GTX_CMD); + break; + } + + case WE_GET_GTX_THRE: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_THRE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + GTX_CMD); + break; + } + + case WE_GET_GTX_MARGIN: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_MARGIN"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + GTX_CMD); + break; + } + + case WE_GET_GTX_STEP: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_STEP"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + GTX_CMD); + break; + } + + case WE_GET_GTX_MINTPC: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_MINTPC"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + GTX_CMD); + break; + } + + case WE_GET_GTX_BWMASK: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_GTX_BW_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + GTX_CMD); + break; + } + + case WE_GET_LDPC: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_LDPC"); + *value = sme_get_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING); + break; + } + + case WE_GET_TX_STBC: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_TX_STBC"); + *value = sme_get_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_TX_STBC); + break; + } + + case WE_GET_RX_STBC: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_RX_STBC"); + *value = sme_get_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_RX_STBC); + break; + } + + case WE_GET_SHORT_GI: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_SGI"); + *value = sme_get_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ); + break; + } + + case WE_GET_RTSCTS: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_ENABLE_RTSCTS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + VDEV_CMD); + break; + } + + case WE_GET_CHWIDTH: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_CHWIDTH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_CHWIDTH, + VDEV_CMD); + break; + } + + case WE_GET_ANI_EN_DIS: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_ENABLE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_ENABLE, + PDEV_CMD); + break; + } + + case WE_GET_ANI_POLL_PERIOD: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_POLL_PERIOD"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + PDEV_CMD); + break; + } + + case WE_GET_ANI_LISTEN_PERIOD: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_LISTEN_PERIOD"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + PDEV_CMD); + break; + } + + case WE_GET_ANI_OFDM_LEVEL: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_OFDM_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + PDEV_CMD); + break; + } + + case WE_GET_ANI_CCK_LEVEL: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_CCK_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + PDEV_CMD); + break; + } + + case WE_GET_DYNAMIC_BW: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_ANI_CCK_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_DYNAMIC_BW, + PDEV_CMD); + break; + } + + case WE_GET_11N_RATE: + { + hddLog(LOG1, "GET WMI_VDEV_PARAM_FIXED_RATE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + VDEV_CMD); + break; + } + + case WE_GET_AMPDU: + { + hddLog(LOG1, "GET AMPDU"); + *value = wma_cli_get_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + GEN_CMD); + break; + } + + case WE_GET_AMSDU: + { + hddLog(LOG1, "GET AMSDU"); + *value = wma_cli_get_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + GEN_CMD); + break; + } + + case WE_GET_BURST_ENABLE: + { + hddLog(LOG1, "GET Burst enable value"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + PDEV_CMD); + break; + } + case WE_GET_BURST_DUR: + { + hddLog(LOG1, "GET Burst Duration value"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_DUR, + PDEV_CMD); + break; + } + + case WE_GET_TX_CHAINMASK: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_TX_CHAIN_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case WE_GET_RX_CHAINMASK: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_RX_CHAIN_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case WE_GET_TXPOW_2G: + { + uint32_t txpow2g = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hddLog(LOG1, "GET WMI_PDEV_PARAM_TXPOWER_LIMIT2G"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + PDEV_CMD); + if (CDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow2g)) { + return -EIO; + } + hddLog(LOG1, "2G tx_power %d", txpow2g); + break; + } + + case WE_GET_TXPOW_5G: + { + uint32_t txpow5g = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hddLog(LOG1, "GET WMI_PDEV_PARAM_TXPOWER_LIMIT5G"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + PDEV_CMD); + if (CDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow5g)) { + return -EIO; + } + hddLog(LOG1, "5G tx_power %d", txpow5g); + break; + } + + case WE_GET_POWER_GATING: + { + hddLog(LOG1, "GET WMI_PDEV_PARAM_POWER_GATING_SLEEP"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_POWER_GATING_SLEEP, + PDEV_CMD); + break; + } + + case WE_GET_PPS_PAID_MATCH: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_PAID_MATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_PAID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_MATCH: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_GID_MATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_TIM_CLEAR: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_EARLY_TIM_CLEAR"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_DTIM_CLEAR: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_EARLY_DTIM_CLEAR"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EOF_PAD_DELIM: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_EOF_PAD_DELIM"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EOF_PAD_DELIM, + PPS_CMD); + break; + } + + case WE_GET_PPS_MACADDR_MISMATCH: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_MACADDR_MISMATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_MACADDR_MISMATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_DELIM_CRC_FAIL: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_DELIM_CRC_FAIL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_NSTS_ZERO: + { + hddLog(LOG1, "GET WMI_VDEV_PPS_GID_NSTS_ZERO"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_NSTS_ZERO, + PPS_CMD); + break; + } + + case WE_GET_PPS_RSSI_CHECK: + { + + hddLog(LOG1, "GET WMI_VDEV_PPS_RSSI_CHECK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_RSSI_CHECK, + PPS_CMD); + break; + } + + case WE_GET_QPOWER_MAX_PSPOLL_COUNT: + { + hddLog(LOG1, "WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hddLog(LOG1, "WE_GET_QPOWER_MAX_TX_BEFORE_WAKE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hddLog(LOG1, "WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hddLog(LOG1, "WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + QPOWER_CMD); + break; + } + + case WE_GET_TEMPERATURE: + { + hddLog(CDF_TRACE_LEVEL_INFO, "WE_GET_TEMPERATURE"); + ret = wlan_hdd_get_temperature(pAdapter, value); + break; + } + default: + { + hddLog(LOGE, "Invalid IOCTL get_value command %d", + value[0]); + break; + } + } + + return ret; +} + +static int iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_three_ints_getnone() - Generic "set 3 params" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + + case WE_SET_WLAN_DBG: + cdf_trace_set_value(value[1], value[2], value[3]); + break; + case WE_SET_DP_TRACE: + cdf_dp_trace_set_value(value[1], value[2], value[3]); + break; + + /* value[3] the acs band is not required as start and end channels are + * enough but this cmd is maintained under set three ints for historic + * reasons. + */ + case WE_SET_SAP_CHANNELS: + if (wlan_hdd_validate_operation_channel(pAdapter, value[1]) != + CDF_STATUS_SUCCESS || + wlan_hdd_validate_operation_channel(pAdapter, + value[2]) != CDF_STATUS_SUCCESS) { + ret = -EINVAL; + } else { + hdd_ctx->config->force_sap_acs_st_ch = value[1]; + hdd_ctx->config->force_sap_acs_end_ch = value[2]; + } + break; + case WE_SET_DUAL_MAC_SCAN_CONFIG: + hdd_debug("Ioctl to set dual mac scan config"); + if (hdd_ctx->config->dual_mac_feature_disable) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d %d", value[1], value[2], value[3]); + cds_set_dual_mac_scan_config(hdd_ctx, + value[1], value[2], + value[3]); + break; + default: + hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd); + break; + + } + return ret; +} + +int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_three_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_connection_state_string() - Get connection state string + * @connection_state: enum to be converted to a string + * + * Return: the string equivalent of @connection_state + */ +static const char * +hdd_connection_state_string(eConnectionState connection_state) +{ + switch (connection_state) { + CASE_RETURN_STRING(eConnectionState_NotConnected); + CASE_RETURN_STRING(eConnectionState_Connecting); + CASE_RETURN_STRING(eConnectionState_Associated); + CASE_RETURN_STRING(eConnectionState_IbssDisconnected); + CASE_RETURN_STRING(eConnectionState_IbssConnected); + CASE_RETURN_STRING(eConnectionState_Disconnecting); + default: + return "UNKNOWN"; + } +} + +/** + * iw_get_char_setnone() - Generic "get string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int sub_cmd = wrqu->data.flags; + hdd_context_t *hdd_ctx; + int ret; +#ifdef WLAN_FEATURE_11W + hdd_wext_state_t *pWextState; +#endif + +#ifdef WLAN_FEATURE_11W + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); +#endif + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_WLAN_VERSION: + { + hdd_wlan_get_version(pAdapter, wrqu, extra); + break; + } + + case WE_GET_STATS: + { + hdd_wlan_get_stats(pAdapter, &(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + } + + /* The case prints the current state of the HDD, SME, CSR, PE, + * TL it can be extended for WDI Global State as well. And + * currently it only checks P2P_CLIENT adapter. P2P_DEVICE + * and P2P_GO have not been added as of now. + */ + case WE_GET_STATES: + { + int buf = 0, len = 0; + int adapter_num = 0; + int count = 0, check = 1; + + tHalHandle hHal = NULL; + tpAniSirGlobal pMac = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_adapter_t *useAdapter = NULL; + + /* Print wlan0 or p2p0 states based on the adapter_num + * by using the correct adapter + */ + while (adapter_num < 2) { + if (WLAN_ADAPTER == adapter_num) { + useAdapter = pAdapter; + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n wlan0 States:-"); + len += buf; + } else if (P2P_ADAPTER == adapter_num) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n p2p0 States:-"); + len += buf; + + if (!pHddCtx) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n pHddCtx is NULL"); + len += buf; + break; + } + + /* Printing p2p0 states only in the + * case when the device is configured + * as a p2p_client + */ + useAdapter = + hdd_get_adapter(pHddCtx, + WLAN_HDD_P2P_CLIENT); + if (!useAdapter) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Device not configured as P2P_CLIENT."); + len += buf; + break; + } + } + + hHal = WLAN_HDD_GET_HAL_CTX(useAdapter); + if (!hHal) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n pMac is NULL"); + len += buf; + break; + } + pMac = PMAC_STRUCT(hHal); + if (!pMac) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n pMac is NULL"); + len += buf; + break; + } + pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(useAdapter); + + + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n HDD Conn State - %s " + "\n \n SME State:" + "\n Neighbour Roam State - %s" + "\n CSR State - %s" + "\n CSR Substate - %s", + hdd_connection_state_string + (pHddStaCtx->conn_info.connState), + mac_trace_get_neighbour_roam_state + (sme_get_neighbor_roam_state + (hHal, useAdapter->sessionId)), + mac_trace_getcsr_roam_state + (sme_get_current_roam_state + (hHal, useAdapter->sessionId)), + mac_trace_getcsr_roam_sub_state + (sme_get_current_roam_sub_state + (hHal, useAdapter->sessionId)) + ); + len += buf; + adapter_num++; + } + + if (pMac) { + /* Printing Lim State starting with global lim states */ + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n \n LIM STATES:-" + "\n Global Sme State - %s " + "\n Global mlm State - %s " "\n", + mac_trace_get_lim_sme_state + (sme_get_lim_sme_state(hHal)), + mac_trace_get_lim_mlm_state + (sme_get_lim_sme_state(hHal)) + ); + len += buf; + + /* Printing the PE Sme and Mlm states for valid lim sessions */ + while (check < 3 && count < 255) { + if (sme_is_lim_session_valid(hHal, count)) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Lim Valid Session %d:-" + "\n PE Sme State - %s " + "\n PE Mlm State - %s " + "\n", check, + mac_trace_get_lim_sme_state + (sme_get_lim_sme_session_state + (hHal, count)), + mac_trace_get_lim_mlm_state + (sme_get_lim_mlm_session_state + (hHal, count)) + ); + + len += buf; + check++; + } + count++; + } + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_CFG: + { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Printing CLD global INI Config", + __func__); + hdd_cfg_get_global_config(WLAN_HDD_GET_CTX(pAdapter), + extra, + QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + break; + } +#ifdef WLAN_FEATURE_11AC + case WE_GET_RSSI: + { + int8_t s7Rssi = 0; + wlan_hdd_get_rssi(pAdapter, &s7Rssi); + snprintf(extra, WE_MAX_STR_LEN, "rssi=%d", s7Rssi); + wrqu->data.length = strlen(extra) + 1; + break; + } +#endif + + case WE_GET_WMM_STATUS: + { + snprintf(extra, WE_MAX_STR_LEN, + "\nDir: 0=up, 1=down, 3=both\n" + "|------------------------|\n" + "|AC | ACM |Admitted| Dir |\n" + "|------------------------|\n" + "|VO | %d | %3s | %d |\n" + "|VI | %d | %3s | %d |\n" + "|BE | %d | %3s | %d |\n" + "|BK | %d | %3s | %d |\n" + "|------------------------|\n", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK].wmmAcTspecInfo. + ts_info.direction); + + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_CHANNEL_LIST: + { + CDF_STATUS status; + uint8_t i, len; + char *buf; + uint8_t ubuf[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t ubuf_len = WNI_CFG_COUNTRY_CODE_LEN; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + tChannelListInfo channel_list; + + memset(&channel_list, 0, sizeof(channel_list)); + status = + iw_softap_get_channel_list(dev, info, wrqu, + (char *)&channel_list); + if (!CDF_IS_STATUS_SUCCESS(status)) { + hddLog(LOGE, FL("GetChannelList Failed!!!")); + return -EINVAL; + } + buf = extra; + /* + * Maximum channels = WNI_CFG_VALID_CHANNEL_LIST_LEN. + * Maximum buffer needed = 5 * number of channels. + * Check ifsufficient buffer is available and then + * proceed to fill the buffer. + */ + if (WE_MAX_STR_LEN < + (5 * WNI_CFG_VALID_CHANNEL_LIST_LEN)) { + hddLog(LOGE, + FL("Insufficient Buffer to populate channel list")); + return -EINVAL; + } + len = scnprintf(buf, WE_MAX_STR_LEN, "%u ", + channel_list.num_channels); + if (CDF_STATUS_SUCCESS == sme_get_country_code(hdd_ctx->hHal, + ubuf, &ubuf_len)) { + /* Printing Country code in getChannelList */ + for (i = 0; i < (ubuf_len - 1); i++) + len += scnprintf(buf + len, + WE_MAX_STR_LEN - len, + "%c", ubuf[i]); + } + for (i = 0; i < channel_list.num_channels; i++) { + len += + scnprintf(buf + len, WE_MAX_STR_LEN - len, + " %u", channel_list.channels[i]); + } + wrqu->data.length = strlen(extra) + 1; + + break; + } +#ifdef FEATURE_WLAN_TDLS + case WE_GET_TDLS_PEERS: + { + wrqu->data.length = + wlan_hdd_tdls_get_all_peers(pAdapter, extra, + WE_MAX_STR_LEN) + 1; + break; + } +#endif +#ifdef WLAN_FEATURE_11W + case WE_GET_11W_INFO: + { + hddLog(LOGE, "WE_GET_11W_ENABLED = %d", + pWextState->roamProfile.MFPEnabled); + + snprintf(extra, WE_MAX_STR_LEN, + "\n BSSID %02X:%02X:%02X:%02X:%02X:%02X, Is PMF Assoc? %d" + "\n Number of Unprotected Disassocs %d" + "\n Number of Unprotected Deauths %d", + pWextState->roamProfile.BSSIDs.bssid->bytes[0], + pWextState->roamProfile.BSSIDs.bssid->bytes[1], + pWextState->roamProfile.BSSIDs.bssid->bytes[2], + pWextState->roamProfile.BSSIDs.bssid->bytes[3], + pWextState->roamProfile.BSSIDs.bssid->bytes[4], + pWextState->roamProfile.BSSIDs.bssid->bytes[5], + pWextState->roamProfile.MFPEnabled, + pAdapter->hdd_stats.hddPmfStats. + numUnprotDisassocRx, + pAdapter->hdd_stats.hddPmfStats. + numUnprotDeauthRx); + + wrqu->data.length = strlen(extra) + 1; + break; + } +#endif + case WE_GET_PHYMODE: + { + bool ch_bond24 = false, ch_bond5g = false; + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + eCsrPhyMode phymode; + eCsrBand currBand; + tSmeConfigParams smeconfig; + + sme_get_config_param(hal, &smeconfig); + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + smeconfig.csrConfig.channelBondingMode24GHz) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + smeconfig.csrConfig.channelBondingMode5GHz) + ch_bond5g = true; + + phymode = sme_get_phy_mode(hal); + if ((CDF_STATUS_SUCCESS != + sme_get_freq_band(hal, &currBand))) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_INFO, + "%s: Failed to get current band config", + __func__); + return -EIO; + } + + switch (phymode) { + case eCSR_DOT11_MODE_AUTO: + snprintf(extra, WE_MAX_STR_LEN, "AUTO MODE"); + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + if (currBand == eCSR_BAND_24) { + if (ch_bond24) + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT20"); + } else if (currBand == eCSR_BAND_5G) { + if (ch_bond5g) + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT20"); + } else { + snprintf(extra, WE_MAX_STR_LEN, "11N"); + } + break; + case eCSR_DOT11_MODE_abg: + snprintf(extra, WE_MAX_STR_LEN, "11ABG"); + break; + case eCSR_DOT11_MODE_11a: + snprintf(extra, WE_MAX_STR_LEN, "11A"); + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11B"); + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11G"); + break; +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT20"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT40"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT80"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT160"); + break; +#endif + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + +#ifdef FEATURE_OEM_DATA_SUPPORT + case WE_GET_OEM_DATA_CAP: + { + return iw_get_oem_data_cap(dev, info, wrqu, extra); + } +#endif /* FEATURE_OEM_DATA_SUPPORT */ + case WE_GET_SNR: + { + int8_t s7snr = 0; + int status = 0; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, + "%s: getSNR: HDD context is not valid", + __func__); + return status; + } + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (0 == pHddCtx->config->fEnableSNRMonitoring || + eConnectionState_Associated != + pHddStaCtx->conn_info.connState) { + hddLog(LOGE, + "%s: getSNR failed: Enable SNR Monitoring-%d," + " ConnectionState-%d", __func__, + pHddCtx->config->fEnableSNRMonitoring, + pHddStaCtx->conn_info.connState); + return -ENONET; + } + wlan_hdd_get_snr(pAdapter, &s7snr); + snprintf(extra, WE_MAX_STR_LEN, "snr=%d", s7snr); + wrqu->data.length = strlen(extra) + 1; + break; + } + default: + { + hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, + sub_cmd); + break; + } + } + + return 0; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setnone_getnone() - Generic "action" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + int sub_cmd; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifdef CONFIG_COMPAT + /* this ioctl is a special case where a sub-ioctl is used and both + * the number of get and set args is 0. in this specific case the + * logic in iwpriv places the sub_cmd in the data.flags portion of + * the iwreq. unfortunately the location of this field will be + * different between 32-bit and 64-bit userspace, and the standard + * compat support in the kernel does not handle this case. so we + * need to explicitly handle it here. + */ + if (is_compat_task()) { + struct compat_iw_point *compat_iw_point = + (struct compat_iw_point *)&wrqu->data; + sub_cmd = compat_iw_point->flags; + } else { + sub_cmd = wrqu->data.flags; + } +#else + sub_cmd = wrqu->data.flags; +#endif + + switch (sub_cmd) { + case WE_GET_RECOVERY_STAT: + { + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + sme_get_recovery_stats(hal); + break; + } + + case WE_SET_REASSOC_TRIGGER: + { + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t roamId = 0; + tCsrRoamModifyProfileFields modProfileFields; + hdd_station_ctx_t *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Reassoc to same AP, only supported for Open Security*/ + if ((hdd_sta_ctx->conn_info.ucEncryptionType || + hdd_sta_ctx->conn_info.mcEncryptionType)) { + hddLog(LOGE, + FL("Reassoc to same AP, only supported for Open Security")); + return -ENOTSUPP; + } + + sme_get_modify_profile_fields(hHal, pAdapter->sessionId, + &modProfileFields); + sme_roam_reassoc(hHal, pAdapter->sessionId, + NULL, modProfileFields, &roamId, 1); + return 0; + } + + case WE_DUMP_AGC_START: + { + hddLog(LOG1, "WE_DUMP_AGC_START"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_AGC_START, + 0, GEN_CMD); + break; + } + case WE_DUMP_AGC: + { + hddLog(LOG1, "WE_DUMP_AGC"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_AGC, + 0, GEN_CMD); + break; + } + + case WE_DUMP_CHANINFO_START: + { + hddLog(LOG1, "WE_DUMP_CHANINFO_START"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_CHANINFO_START, + 0, GEN_CMD); + break; + } + case WE_DUMP_CHANINFO: + { + hddLog(LOG1, "WE_DUMP_CHANINFO_START"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_CHANINFO, + 0, GEN_CMD); + break; + } + case WE_DUMP_WATCHDOG: + { + hddLog(LOG1, "WE_DUMP_WATCHDOG"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_WATCHDOG, + 0, GEN_CMD); + break; + } +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + case WE_DUMP_PCIE_LOG: + { + hddLog(LOGE, "WE_DUMP_PCIE_LOG"); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_PARAM_DUMP_PCIE_ACCESS_LOG, + 0, GEN_CMD); + break; + } +#endif + default: + { + hddLog(LOGE, "%s: unknown ioctl %d", __func__, sub_cmd); + break; + } + } + + return ret; +} + +static int iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is an SSR-protected generic handler for private ioctls which + * take multiple arguments. Note that this implementation is also + * somewhat unique in that it is shared by both STA-mode and SAP-mode + * interfaces. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int sub_cmd; + int *apps_args = (int *) extra; + hdd_context_t *hdd_ctx; + int ret, num_args; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (extra == NULL) { + hddLog(LOGE, FL("NULL extra buffer pointer")); + return -EINVAL; + } + + sub_cmd = wrqu->data.flags; + num_args = wrqu->data.length; + + hddLog(LOG1, FL("Received length %d"), wrqu->data.length); + + switch (sub_cmd) { + + case WE_P2P_NOA_CMD: + { + p2p_app_setP2pPs_t p2pNoA; + + p2pNoA.opp_ps = apps_args[0]; + p2pNoA.ctWindow = apps_args[1]; + p2pNoA.duration = apps_args[2]; + p2pNoA.interval = apps_args[3]; + p2pNoA.count = apps_args[4]; + p2pNoA.single_noa_duration = apps_args[5]; + p2pNoA.psSelection = apps_args[6]; + + hddLog(LOG1, + "%s: P2P_NOA_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d PsSelection %x", + __func__, apps_args[0], apps_args[1], + apps_args[2], apps_args[3], apps_args[4], + apps_args[5], apps_args[6]); + + hdd_set_p2p_ps(dev, &p2pNoA); + + } + break; + + case WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD: + { + hddLog(LOG1, "%s: SELECTIVE_MODULE_LOG %d arg1 %d arg2", + __func__, apps_args[0], apps_args[1]); + cdf_trace_enable(apps_args[0], apps_args[1]); + } + break; + + case WE_MTRACE_DUMP_CMD: + { + hddLog(LOG1, + "%s: MTRACE_DUMP code %d session %d count %d " + "bitmask_of_module %d ", __func__, apps_args[0], + apps_args[1], apps_args[2], apps_args[3]); + cdf_trace_dump_all((void *)hHal, apps_args[0], + apps_args[1], apps_args[2], + apps_args[3]); + + } + break; + + case WE_POLICY_MANAGER_CLIST_CMD: + { + hddLog(LOGE, + FL(" is called\n")); + cds_incr_connection_count_utfw(hdd_ctx, apps_args[0], + apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], + apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DLIST_CMD: + { + hddLog(LOGE, + FL(" is called\n")); + cds_decr_connection_count_utfw(hdd_ctx, apps_args[0], + apps_args[1]); + } + break; + + case WE_POLICY_MANAGER_ULIST_CMD: + { + hddLog(LOGE, + FL(" is called\n")); + cds_update_connection_info_utfw(hdd_ctx, apps_args[0], + apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], + apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DBS_CMD: + { + hddLog(LOGE, + FL(" is called\n")); + if (apps_args[0] == 0) + wma_set_dbs_capability_ut(0); + else + wma_set_dbs_capability_ut(1); + + if (apps_args[1] >= CDS_THROUGHPUT && + apps_args[1] <= CDS_LATENCY) { + pr_info("setting system pref to [%d]\n", apps_args[1]); + hdd_ctx->config->conc_system_pref = apps_args[1]; + } + } + break; + + case WE_POLICY_MANAGER_PCL_CMD: + { + uint8_t pcl[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0, i = 0; + + hddLog(LOGE, + FL(" is called\n")); + + cds_get_pcl(hdd_ctx, apps_args[0], + pcl, &pcl_len); + pr_info("PCL list for role[%d] is {", apps_args[0]); + for (i = 0 ; i < pcl_len; i++) + pr_info(" %d, ", pcl[i]); + pr_info("}--------->\n"); + } + break; + + case WE_POLICY_MANAGER_CINFO_CMD: + { + struct cds_conc_connection_info *conn_info; + uint32_t i = 0, len = 0; + + hddLog(LOGE, + FL(" is called\n")); + conn_info = cds_get_conn_info(hdd_ctx, &len); + pr_info("+-----------------------------+\n"); + for (i = 0; i < len; i++) { + pr_info("|table_index[%d]\t\t|\n", i); + pr_info("|\t|vdev_id - %d\t\t|\n", conn_info->vdev_id); + pr_info("|\t|tx_spatial_stream - %d\t|\n", + conn_info->tx_spatial_stream); + pr_info("|\t|rx_spatial_stream - %d\t|\n", + conn_info->rx_spatial_stream); + pr_info("|\t|chain_mask - %d\t\t|\n", + conn_info->chain_mask); + pr_info("|\t|chan - %d\t\t|\n", conn_info->chan); + pr_info("|\t|mode - %d\t\t|\n", conn_info->mode); + pr_info("|\t|mac - %d\t\t|\n", conn_info->mac); + pr_info("|\t|in_use - %d\t\t|\n", conn_info->in_use); + pr_info("+-----------------------------+\n"); + conn_info++; + } + } + break; + + case WE_POLICY_SET_HW_MODE_CMD: + { + if (apps_args[0] == 0) { + hddLog(LOGE, + FL("set hw mode for single mac\n")); + cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE); + } else if (apps_args[0] == 1) { + hddLog(LOGE, + FL("set hw mode for dual mac\n")); + cds_soc_set_hw_mode(hdd_ctx, HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE); + } + } + break; + + case WE_POLICY_MANAGER_QUERY_ACTION_CMD: + { + enum cds_conc_next_action action; + hddLog(LOGE, + FL(" is called\n")); + action = cds_current_connections_update(hdd_ctx, + apps_args[0]); + pr_info("next action is %d {HDD_NOP = 0, HDD_DBS, HDD_DBS_DOWNGRADE, HDD_MCC, HDD_MCC_UPGRADE}", action); + } + break; + case WE_POLICY_MANAGER_QUERY_ALLOW_CMD: + { + bool allow; + hddLog(LOGE, + FL(" is called\n")); + allow = cds_allow_concurrency(hdd_ctx, + apps_args[0], apps_args[1], apps_args[2]); + pr_info("allow %d {0 = don't allow, 1 = allow}", allow); + } + break; + + case WE_POLICY_MANAGER_SCENARIO_CMD: + { + clean_report(hdd_ctx); + if (apps_args[0] == 1) { + wlan_hdd_one_connection_scenario(hdd_ctx); + } else if (apps_args[0] == 2) { + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, CDS_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, CDS_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, CDS_ONE_ONE); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, CDS_ONE_ONE); + } else if (apps_args[0] == 3) { + /* MCC on same band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 11, CDS_TWO_TWO, 0); + /* MCC on diff band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 36, CDS_TWO_TWO, 0); + /* MCC on diff band with 1x1 diff mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, CDS_ONE_ONE, 0); + /* MCC on diff band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, CDS_ONE_ONE, 1); + /* SCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, CDS_TWO_TWO, 0); + /* SCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, CDS_ONE_ONE, 1); + /* MCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, CDS_TWO_TWO, 0); + /* MCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, CDS_ONE_ONE, 1); + } + print_report(hdd_ctx); + } + break; + +#ifdef FEATURE_WLAN_TDLS + case WE_TDLS_CONFIG_PARAMS: + { + tdls_config_params_t tdlsParams; + + tdlsParams.tdls = apps_args[0]; + tdlsParams.tx_period_t = apps_args[1]; + tdlsParams.tx_packet_n = apps_args[2]; + /* ignore args[3] as discovery_period is not used anymore */ + tdlsParams.discovery_tries_n = apps_args[4]; + /* ignore args[5] as idle_timeout is not used anymore */ + tdlsParams.idle_packet_n = apps_args[6]; + /* ignore args[7] as rssi_hysteresis is not used anymore */ + tdlsParams.rssi_trigger_threshold = apps_args[8]; + tdlsParams.rssi_teardown_threshold = apps_args[9]; + tdlsParams.rssi_delta = apps_args[10]; + + wlan_hdd_tdls_set_params(dev, &tdlsParams); + } + break; +#endif + case WE_UNIT_TEST_CMD: + { + t_wma_unit_test_cmd *unitTestArgs; + cds_msg_t msg = { 0 }; + int i, j; + if ((apps_args[0] < WLAN_MODULE_ID_MIN) || + (apps_args[0] >= WLAN_MODULE_ID_MAX)) { + hddLog(LOGE, FL("Invalid MODULE ID %d"), + apps_args[0]); + return -EINVAL; + } + if (apps_args[1] > (WMA_MAX_NUM_ARGS)) { + hddLog(LOGE, FL("Too Many args %d"), + apps_args[1]); + return -EINVAL; + } + unitTestArgs = cdf_mem_malloc(sizeof(*unitTestArgs)); + if (NULL == unitTestArgs) { + hddLog(LOGE, + FL("cdf_mem_alloc failed for unitTestArgs")); + return -ENOMEM; + } + unitTestArgs->vdev_id = (int)pAdapter->sessionId; + unitTestArgs->module_id = apps_args[0]; + unitTestArgs->num_args = apps_args[1]; + for (i = 0, j = 2; i < unitTestArgs->num_args; i++, j++) { + unitTestArgs->args[i] = apps_args[j]; + } + msg.type = SIR_HAL_UNIT_TEST_CMD; + msg.reserved = 0; + msg.bodyptr = unitTestArgs; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + cdf_mem_free(unitTestArgs); + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + FL + ("Not able to post UNIT_TEST_CMD message to WMA")); + return -EINVAL; + } + } + break; +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WE_LED_FLASHING_PARAM: + { + int i; + if (num_args != 4) { + hddLog(LOGE, + FL("gpio_control: 4 parameters are required")); + return -EINVAL; + } + for (i = 0; i < num_args; i++) { + if (apps_args[i] >= 0x7fffffff) { + hddLog(LOGE, + FL("gpio_control: parameter should be less than 0x7fffffff")); + return -EINVAL; + } + } + sme_set_led_flashing(WLAN_HDD_GET_HAL_CTX(pAdapter), + 0, apps_args[0], apps_args[1]); + sme_set_led_flashing(WLAN_HDD_GET_HAL_CTX(pAdapter), + 1, apps_args[2], apps_args[3]); + } + break; +#endif + default: + { + hddLog(LOGE, FL("Invalid IOCTL command %d"), sub_cmd); + } + break; + } + + return 0; +} + +/** + * iw_hdd_set_var_ints_getnone() - set var ints getnone callback + * @dev: pointer to net_device structure + * @info: pointer to iw_request_info structure + * @wrqu: pointer to iwreq_data + * @extra; extra + * + * Return: 0 on success, error number otherwise + * + */ +static int iw_hdd_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + union iwreq_data u_priv_wrqu; + int apps_args[MAX_VAR_ARGS] = {0}; + int ret, num_args; + + /* Helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&u_priv_wrqu.data, wrqu)) + return -EINVAL; + + if (NULL == u_priv_wrqu.data.pointer) { + hddLog(LOGE, FL("NULL data pointer")); + return -EINVAL; + } + + num_args = u_priv_wrqu.data.length; + if (num_args > MAX_VAR_ARGS) + num_args = MAX_VAR_ARGS; + + if (copy_from_user(apps_args, u_priv_wrqu.data.pointer, + (sizeof(int)) * num_args)) { + hddLog(LOGE, FL("failed to copy data from user buffer")); + return -EFAULT; + } + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, &u_priv_wrqu, + (char *)&apps_args); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is a generic handler for private ioctls which take multiple + * arguments. Note that this implementation is also somewhat unique + * in that it is shared by both STA-mode and SAP-mode interfaces. + * + * Return: 0 on success, non-zero on error + */ +int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * iw_add_tspec - Add TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_add_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + int params[HDD_WLAN_WMM_PARAM_COUNT]; + sme_QosWmmTspecInfo tSpec; + uint32_t handle; + struct iw_point s_priv_data; + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently priviledged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + + /* we must be associated in order to add a tspec */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* since we are defined to be a "get" ioctl, and since the number */ + /* of params exceeds the number of params that wireless extensions */ + /* will pass down in the iwreq_data, we must copy the "set" params. */ + /* We must handle the compat for iwreq_data in 32U/64K environment. */ + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* make sure all params are correctly passed to function */ + if ((NULL == s_priv_data.pointer) || + (HDD_WLAN_WMM_PARAM_COUNT != s_priv_data.length)) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* from user space ourselves */ + if (copy_from_user(¶ms, s_priv_data.pointer, sizeof(params))) { + /* hmmm, can't get them */ + return -EIO; + } + /* clear the tspec */ + memset(&tSpec, 0, sizeof(tSpec)); + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* validate the TID */ + if (params[HDD_WLAN_WMM_PARAM_TID] > 7) { + /* out of range */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tSpec.ts_info.tid = params[HDD_WLAN_WMM_PARAM_TID]; + + /* validate the direction */ + switch (params[HDD_WLAN_WMM_PARAM_DIRECTION]) { + case HDD_WLAN_WMM_DIRECTION_UPSTREAM: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_UPLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_DOWNSTREAM: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_DOWNLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_BOTH; + break; + + default: + /* unknown */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + tSpec.ts_info.psb = params[HDD_WLAN_WMM_PARAM_APSD]; + + /* validate the user priority */ + if (params[HDD_WLAN_WMM_PARAM_USER_PRIORITY] >= SME_QOS_WMM_UP_MAX) { + /* out of range */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tSpec.ts_info.up = params[HDD_WLAN_WMM_PARAM_USER_PRIORITY]; + if (0 > tSpec.ts_info.up || SME_QOS_WMM_UP_MAX < tSpec.ts_info.up) { + hddLog(CDF_TRACE_LEVEL_ERROR, "***ts_info.up out of bounds***"); + return 0; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH, + "%s:TS_INFO PSB %d UP %d !!!", __func__, + tSpec.ts_info.psb, tSpec.ts_info.up); + + tSpec.nominal_msdu_size = params[HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE]; + tSpec.maximum_msdu_size = params[HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE]; + tSpec.min_data_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE]; + tSpec.mean_data_rate = params[HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE]; + tSpec.peak_data_rate = params[HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE]; + tSpec.max_burst_size = params[HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE]; + tSpec.min_phy_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE]; + tSpec.surplus_bw_allowance = + params[HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE]; + tSpec.min_service_interval = + params[HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL]; + tSpec.max_service_interval = + params[HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL]; + tSpec.suspension_interval = + params[HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL]; + tSpec.inactivity_interval = + params[HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL]; + + tSpec.ts_info.burst_size_defn = + params[HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN]; + + /* validate the ts info ack policy */ + switch (params[HDD_WLAN_WMM_PARAM_ACK_POLICY]) { + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + tSpec.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + tSpec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_addts(pAdapter, handle, &tSpec); + return 0; +} + +static int iw_add_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_add_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_del_tspec - Delete TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_del_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently priviledged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_delts(pAdapter, handle); + return 0; +} + +static int iw_del_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_del_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_get_tspec - Get TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_checkts(pAdapter, handle); + return 0; +} + +static int iw_get_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/** + * iw_set_fties - Set FT IEs private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Each time the supplicant has the auth_request or reassoc request + * IEs ready they are pushed to the driver. The driver will in turn + * use it to send out the auth req and reassoc req for 11r FT Assoc. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_fties(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + hddLog(LOGE, FL("called with 0 length IEs")); + return -EINVAL; + } + if (wrqu->data.pointer == NULL) { + hddLog(LOGE, FL("called with NULL IE")); + return -EINVAL; + } + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(LOGE, + FL("Called with Ie of length = %d when not associated"), + wrqu->data.length); + hddLog(LOGE, FL("Should be Re-assoc Req IEs")); + } +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + hddLog(LOG1, FL("%s called with Ie of length = %d"), __func__, + wrqu->data.length); +#endif + + /* Pass the received FT IEs to SME */ + sme_set_ft_ies(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, + extra, wrqu->data.length); + + return 0; +} + +static int iw_set_fties(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_fties(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * iw_set_host_offload - Set host offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpHostOffloadRequest pRequest = (tpHostOffloadRequest) extra; + tSirHostOffloadReq offloadRequest; + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + "%s:LOGP dev is not in CONNECTED state, ignore!!!", + __func__); + return -EINVAL; + } + + /* Debug display of request components. */ + switch (pRequest->offloadType) { + case WLAN_IPV4_ARP_REPLY_OFFLOAD: + hddLog(CDF_TRACE_LEVEL_WARN, + "%s: Host offload request: ARP reply", __func__); + switch (pRequest->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hddLog(CDF_TRACE_LEVEL_WARN, " disable"); + break; + case WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE: + hddLog(CDF_TRACE_LEVEL_WARN, " BC Filtering enable"); + case WLAN_OFFLOAD_ENABLE: + hddLog(CDF_TRACE_LEVEL_WARN, " ARP offload enable"); + hddLog(CDF_TRACE_LEVEL_WARN, + " IP address: %d.%d.%d.%d", + pRequest->params.hostIpv4Addr[0], + pRequest->params.hostIpv4Addr[1], + pRequest->params.hostIpv4Addr[2], + pRequest->params.hostIpv4Addr[3]); + } + break; + + case WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD: + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Host offload request: neighbor discovery", + __func__); + switch (pRequest->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, " disable"); + break; + case WLAN_OFFLOAD_ENABLE: + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, " enable"); + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + " IP address: %x:%x:%x:%x:%x:%x:%x:%x", + *(uint16_t *) (pRequest->params.hostIpv6Addr), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 2), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 4), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 6), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 8), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 10), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 12), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 14)); + } + } + + /* Execute offload request. The reason that we can copy the + * request information from the ioctl structure to the SME + * structure is that they are laid out exactly the same. + * Otherwise, each piece of information would have to be + * copied individually. + */ + memcpy(&offloadRequest, pRequest, wrqu->data.length); + if (CDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offloadRequest)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failure to execute host offload request", __func__); + return -EINVAL; + } + + return 0; +} + +static int iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_host_offload(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_keepalive_params - Set keepalive params ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpKeepAliveRequest pRequest = (tpKeepAliveRequest) extra; + tSirKeepAliveReq keepaliveRequest; + hdd_context_t *hdd_ctx; + int ret; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (pRequest->timePeriod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + hddLog(LOGE, FL("Value of timePeriod %d exceed Max limit %d"), + pRequest->timePeriod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return -EINVAL; + } + + /* Debug display of request components. */ + hddLog(CDF_TRACE_LEVEL_INFO, + "%s: Set Keep Alive Request : TimePeriod %d size %zu", + __func__, pRequest->timePeriod, sizeof(tKeepAliveRequest)); + + switch (pRequest->packetType) { + case WLAN_KEEP_ALIVE_NULL_PKT: + hddLog(CDF_TRACE_LEVEL_WARN, "%s: Keep Alive Request: Tx NULL", + __func__); + break; + + case WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP: + hddLog(CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Keep Alive Request: Tx UnSolicited ARP RSP", + __func__); + + hddLog(CDF_TRACE_LEVEL_WARN, " Host IP address: %d.%d.%d.%d", + pRequest->hostIpv4Addr[0], pRequest->hostIpv4Addr[1], + pRequest->hostIpv4Addr[2], pRequest->hostIpv4Addr[3]); + + hddLog(CDF_TRACE_LEVEL_WARN, " Dest IP address: %d.%d.%d.%d", + pRequest->destIpv4Addr[0], pRequest->destIpv4Addr[1], + pRequest->destIpv4Addr[2], pRequest->destIpv4Addr[3]); + + hddLog(CDF_TRACE_LEVEL_WARN, + " Dest MAC address: %d:%d:%d:%d:%d:%d", + pRequest->destMacAddr[0], pRequest->destMacAddr[1], + pRequest->destMacAddr[2], pRequest->destMacAddr[3], + pRequest->destMacAddr[4], pRequest->destMacAddr[5]); + break; + } + + /* Execute keep alive request. The reason that we can copy the + * request information from the ioctl structure to the SME + * structure is that they are laid out exactly the same. + * Otherwise, each piece of information would have to be + * copied individually. + */ + memcpy(&keepaliveRequest, pRequest, wrqu->data.length); + + hddLog(CDF_TRACE_LEVEL_ERROR, "set Keep: TP before SME %d", + keepaliveRequest.timePeriod); + + if (CDF_STATUS_SUCCESS != + sme_set_keep_alive(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &keepaliveRequest)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Failure to execute Keep Alive", __func__); + return -EINVAL; + } + + return 0; +} + +static int iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_keepalive_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @sessionId: Target session for the request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_set_filter(hdd_context_t *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t sessionId) +{ + tSirRcvPktFilterCfgType packetFilterSetReq = {0}; + tSirRcvFltPktClearParam packetFilterClrReq = {0}; + int i = 0; + + if (hdd_ctx->config->disablePacketFilter) { + hdd_err("packet filtering disabled in ini returning"); + return 0; + } + + /* Debug display of request components. */ + hdd_info("Packet Filter Request : FA %d params %d", + request->filter_action, request->num_params); + + switch (request->filter_action) { + case HDD_RCV_FILTER_SET: + hdd_info("Set Packet Filter Request for Id: %d", + request->filter_id); + + packetFilterSetReq.filterId = request->filter_id; + if (request->num_params >= HDD_MAX_CMP_PER_PACKET_FILTER) { + hdd_err("Number of Params exceed Max limit %d", + request->num_params); + return -EINVAL; + } + packetFilterSetReq.numFieldParams = request->num_params; + packetFilterSetReq.coalesceTime = 0; + packetFilterSetReq.filterType = HDD_RCV_FILTER_SET; + for (i = 0; i < request->num_params; i++) { + packetFilterSetReq.paramsData[i].protocolLayer = + request->params_data[i].protocol_layer; + packetFilterSetReq.paramsData[i].cmpFlag = + request->params_data[i].compare_flag; + packetFilterSetReq.paramsData[i].dataOffset = + request->params_data[i].data_offset; + packetFilterSetReq.paramsData[i].dataLength = + request->params_data[i].data_length; + packetFilterSetReq.paramsData[i].reserved = 0; + + if (request->params_data[i].data_length > + SIR_MAX_FILTER_TEST_DATA_LEN) { + hdd_err("Error invalid data length %d", + request->params_data[i].data_length); + return -EINVAL; + } + + hdd_info("Proto %d Comp Flag %d Filter Type %d", + request->params_data[i].protocol_layer, + request->params_data[i].compare_flag, + packetFilterSetReq.filterType); + + hdd_info("Data Offset %d Data Len %d", + request->params_data[i].data_offset, + request->params_data[i].data_length); + + memcpy(&packetFilterSetReq.paramsData[i].compareData, + request->params_data[i].compare_data, + request->params_data[i].data_length); + memcpy(&packetFilterSetReq.paramsData[i].dataMask, + request->params_data[i].data_mask, + request->params_data[i].data_length); + + hdd_info("CData %d CData %d CData %d CData %d CData %d CData %d", + request->params_data[i].compare_data[0], + request->params_data[i].compare_data[1], + request->params_data[i].compare_data[2], + request->params_data[i].compare_data[3], + request->params_data[i].compare_data[4], + request->params_data[i].compare_data[5]); + + hdd_info("MData %d MData %d MData %d MData %d MData %d MData %d", + request->params_data[i].data_mask[0], + request->params_data[i].data_mask[1], + request->params_data[i].data_mask[2], + request->params_data[i].data_mask[3], + request->params_data[i].data_mask[4], + request->params_data[i].data_mask[5]); + } + + if (CDF_STATUS_SUCCESS != + sme_receive_filter_set_filter(hdd_ctx->hHal, + &packetFilterSetReq, + sessionId)) { + hdd_err("Failure to execute Set Filter"); + return -EINVAL; + } + + break; + + case HDD_RCV_FILTER_CLEAR: + + hdd_info("Clear Packet Filter Request for Id: %d", + request->filter_id); + packetFilterClrReq.filterId = request->filter_id; + if (CDF_STATUS_SUCCESS != + sme_receive_filter_clear_filter(hdd_ctx->hHal, + &packetFilterClrReq, + sessionId)) { + hdd_err("Failure to execute Clear Filter"); + return -EINVAL; + } + break; + + default: + hdd_err("Packet Filter Request: Invalid %d", + request->filter_action); + return -EINVAL; + } + return 0; +} + +/** + * __iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + hdd_context_t *hdd_ctx; + struct iw_point priv_data; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct pkt_filter_cfg *request = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (hdd_priv_get_data(&priv_data, wrqu)) { + hdd_err("failed to get priv data"); + return -EINVAL; + } + + if ((NULL == priv_data.pointer) || (0 == priv_data.length)) { + hdd_err("invalid priv data %p or invalid priv data length %d", + priv_data.pointer, priv_data.length); + return -EINVAL; + } + + /* copy data using copy_from_user */ + request = mem_alloc_copy_from_user_helper(priv_data.pointer, + priv_data.length); + if (NULL == request) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + ret = wlan_hdd_set_filter(hdd_ctx, request, adapter->sessionId); + + kfree(request); + + return ret; +} + +/** + * iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_packet_filter_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + + +static int __iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + CDF_STATUS status = CDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + char *p = extra; + int tlen = 0; + tCsrSummaryStatsInfo *pStats = &(pAdapter->hdd_stats.summary_stat); + tCsrGlobalClassAStatsInfo *aStats = &(pAdapter->hdd_stats.ClassA_stat); + tCsrGlobalClassDStatsInfo *dStats = &(pAdapter->hdd_stats.ClassD_stat); + int ret; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (eConnectionState_Associated != + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) { + + wrqu->txpower.value = 0; + } else { + status = sme_get_statistics(hdd_ctx->hHal, eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + hdd_statistics_cb, 0, false, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + pAdapter, pAdapter->sessionId); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve SME statistics", + __func__); + return -EINVAL; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + cdf_status = + cdf_wait_single_event(&pWextState->hdd_cdf_event, + WLAN_WAIT_TIME_STATS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s: SME timeout while retrieving statistics", + __func__); + /*Remove the SME statistics list by passing NULL in callback argument */ + status = sme_get_statistics(hdd_ctx->hHal, eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + NULL, 0, false, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info. + staId[0], pAdapter, + pAdapter->sessionId); + + return -EINVAL; + } + FILL_TLV(p, (uint8_t) WLAN_STATS_RETRY_CNT, + (uint8_t) sizeof(pStats->retry_cnt), + (char *)&(pStats->retry_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_MUL_RETRY_CNT, + (uint8_t) sizeof(pStats->multiple_retry_cnt), + (char *)&(pStats->multiple_retry_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_FRM_CNT, + (uint8_t) sizeof(pStats->tx_frm_cnt), + (char *)&(pStats->tx_frm_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_FRM_CNT, + (uint8_t) sizeof(pStats->rx_frm_cnt), + (char *)&(pStats->rx_frm_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_FRM_DUP_CNT, + (uint8_t) sizeof(pStats->frm_dup_cnt), + (char *)&(pStats->frm_dup_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_FAIL_CNT, + (uint8_t) sizeof(pStats->fail_cnt), + (char *)&(pStats->fail_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RTS_FAIL_CNT, + (uint8_t) sizeof(pStats->rts_fail_cnt), + (char *)&(pStats->rts_fail_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_ACK_FAIL_CNT, + (uint8_t) sizeof(pStats->ack_fail_cnt), + (char *)&(pStats->ack_fail_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RTS_SUC_CNT, + (uint8_t) sizeof(pStats->rts_succ_cnt), + (char *)&(pStats->rts_succ_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_DISCARD_CNT, + (uint8_t) sizeof(pStats->rx_discard_cnt), + (char *)&(pStats->rx_discard_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_ERROR_CNT, + (uint8_t) sizeof(pStats->rx_error_cnt), + (char *)&(pStats->rx_error_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_uc_byte_cnt[0]), + (char *)&(dStats->tx_uc_byte_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_byte_cnt), + (char *)&(dStats->rx_byte_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_RATE, + (uint8_t) sizeof(dStats->rx_rate), + (char *)&(dStats->rx_rate), tlen); + + /* Transmit rate, in units of 500 kbit/sec */ + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_RATE, + (uint8_t) sizeof(aStats->tx_rate), + (char *)&(aStats->tx_rate), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_UC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_uc_byte_cnt[0]), + (char *)&(dStats->rx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_MC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_mc_byte_cnt), + (char *)&(dStats->rx_mc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_BC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_bc_byte_cnt), + (char *)&(dStats->rx_bc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_UC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_uc_byte_cnt[0]), + (char *)&(dStats->tx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_MC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_mc_byte_cnt), + (char *)&(dStats->tx_mc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_BC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_bc_byte_cnt), + (char *)&(dStats->tx_bc_byte_cnt), tlen); + + wrqu->data.length = tlen; + + } + + EXIT(); + + return 0; +} + +static int iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_statistics(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_SCAN_PNO + +/*Max Len for PNO notification*/ +#define MAX_PNO_NOTIFY_LEN 100 +void found_pref_network_cb(void *callbackContext, + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + union iwreq_data wrqu; + char buf[MAX_PNO_NOTIFY_LEN + 1]; + + hddLog(CDF_TRACE_LEVEL_WARN, + "A preferred network was found: %s with rssi: -%d", + pPrefNetworkFoundInd->ssId.ssId, pPrefNetworkFoundInd->rssi); + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, MAX_PNO_NOTIFY_LEN, + "QCOM: Found preferred network: %s with RSSI of -%u", + pPrefNetworkFoundInd->ssId.ssId, + (unsigned int)pPrefNetworkFoundInd->rssi); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* send the event */ + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); + +} + +/** + * __iw_set_pno() - Preferred Network Offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This function parses a Preferred Network Offload command + * Input is string based and expected to be of the form: + * + * + * when enabling: + * + * for each network: + * + * + * + * for each timer: + * + * + * + * e.g: + * 1 2 4 test 0 0 3 1 6 11 2 40 5 test2 4 4 6 1 2 3 4 5 6 1 0 2 5 2 300 0 1 + * + * this translates into: + * ----------------------------- + * enable PNO + * 2 networks + * Network 1: + * test - with authentication type 0 and encryption type 0, + * search on 3 channels: 1 6 and 11, + * SSID bcast type is unknown (directed probe will be sent if + * AP not found) and must meet -40dBm RSSI + * Network 2: + * test2 - with authentication type 4 and encryption type 4, + * search on 6 channels 1, 2, 3, 4, 5 and 6 + * bcast type is non-bcast (directed probe will be sent) + * and must not meet any RSSI threshold + * 2 scan timers: + * scan every 5 seconds 2 times + * then scan every 300 seconds until stopped + * enable on suspend + */ +static int __iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + int offset; + char *ptr; + uint8_t i, j, params, mode; + + /* request is a large struct, so we make it static to avoid + * stack overflow. This API is only invoked via ioctl, so it + * is serialized by the kernel rtnl_lock and hence does not + * need to be reentrant + */ + static tSirPNOScanReq request; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_notice("PNO data len %d data %s", wrqu->data.length, extra); + + request.enable = 0; + request.ucNetworksCount = 0; + + ptr = extra; + + if (1 != sscanf(ptr, "%hhu%n", &(request.enable), &offset)) { + hdd_err("PNO enable input is not valid %s", ptr); + return -EINVAL; + } + + if (0 == request.enable) { + /* Disable PNO, ignore any other params */ + memset(&request, 0, sizeof(request)); + sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(adapter), + &request, adapter->sessionId, + found_pref_network_cb, adapter); + return 0; + } + + ptr += offset; + + if (1 != + sscanf(ptr, "%hhu %n", &(request.ucNetworksCount), &offset)) { + hdd_err("PNO count input not valid %s", ptr); + return -EINVAL; + + } + + hdd_info("PNO enable %d networks count %d offset %d", + request.enable, request.ucNetworksCount, offset); + + if ((0 == request.ucNetworksCount) || + (request.ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) { + hdd_err("Network count %d invalid", + request.ucNetworksCount); + return -EINVAL; + } + + ptr += offset; + + for (i = 0; i < request.ucNetworksCount; i++) { + + request.aNetworks[i].ssId.length = 0; + + params = sscanf(ptr, "%hhu %n", + &(request.aNetworks[i].ssId.length), + &offset); + + if (1 != params) { + hdd_err("PNO ssid length input is not valid %s", ptr); + return -EINVAL; + } + + if ((0 == request.aNetworks[i].ssId.length) || + (request.aNetworks[i].ssId.length > 32)) { + hdd_err("SSID Len %d is not correct for network %d", + request.aNetworks[i].ssId.length, i); + return -EINVAL; + } + + /* Advance to SSID */ + ptr += offset; + + memcpy(request.aNetworks[i].ssId.ssId, ptr, + request.aNetworks[i].ssId.length); + ptr += request.aNetworks[i].ssId.length; + + params = sscanf(ptr, "%u %u %hhu %n", + &(request.aNetworks[i].authentication), + &(request.aNetworks[i].encryption), + &(request.aNetworks[i].ucChannelCount), + &offset); + + if (3 != params) { + hdd_warn("Incorrect cmd %s", ptr); + return -EINVAL; + } + + hdd_notice("PNO len %d ssid %.*s auth %d encry %d channel count %d offset %d", + request.aNetworks[i].ssId.length, + request.aNetworks[i].ssId.length, + request.aNetworks[i].ssId.ssId, + request.aNetworks[i].authentication, + request.aNetworks[i].encryption, + request.aNetworks[i].ucChannelCount, offset); + + /* Advance to channel list */ + ptr += offset; + + if (SIR_PNO_MAX_NETW_CHANNELS < + request.aNetworks[i].ucChannelCount) { + hdd_warn("Incorrect number of channels"); + return -EINVAL; + } + + if (0 != request.aNetworks[i].ucChannelCount) { + for (j = 0; j < request.aNetworks[i].ucChannelCount; + j++) { + if (1 != + sscanf(ptr, "%hhu %n", + &(request.aNetworks[i]. + aChannels[j]), &offset)) { + hdd_err("PNO network channel input is not valid %s", + ptr); + return -EINVAL; + } + /* Advance to next channel number */ + ptr += offset; + } + } + + if (1 != sscanf(ptr, "%u %n", + &(request.aNetworks[i].bcastNetwType), + &offset)) { + hdd_err("PNO broadcast network type input is not valid %s", + ptr); + return -EINVAL; + } + + hdd_notice("PNO bcastNetwType %d offset %d", + request.aNetworks[i].bcastNetwType, offset); + + /* Advance to rssi Threshold */ + ptr += offset; + if (1 != sscanf(ptr, "%d %n", + &(request.aNetworks[i].rssiThreshold), + &offset)) { + hdd_err("PNO rssi threshold input is not valid %s", + ptr); + return -EINVAL; + } + hdd_notice("PNO rssi %d offset %d", + request.aNetworks[i].rssiThreshold, offset); + /* Advance to next network */ + ptr += offset; + } /* For ucNetworkCount */ + + params = sscanf(ptr, "%hhu %n", + &(request.scanTimers.ucScanTimersCount), &offset); + + /* Read the scan timers */ + if ((1 == params) && (request.scanTimers.ucScanTimersCount > 0)) { + ptr += offset; + + hdd_notice("Scan timer count %d offset %d", + request.scanTimers.ucScanTimersCount, offset); + + if (SIR_PNO_MAX_SCAN_TIMERS < + request.scanTimers.ucScanTimersCount) { + hdd_err("Incorrect cmd - too many scan timers"); + return -EINVAL; + } + + for (i = 0; i < request.scanTimers.ucScanTimersCount; i++) { + params = sscanf(ptr, "%u %u %n", + &(request.scanTimers. + aTimerValues[i].uTimerValue), + &(request.scanTimers. + aTimerValues[i].uTimerRepeat), + &offset); + + if (2 != params) { + hdd_err("Incorrect cmd - diff params then expected %d", + params); + return -EINVAL; + } + + hdd_notice("PNO Timer value %d Timer repeat %d offset %d", + request.scanTimers.aTimerValues[i]. + uTimerValue, + request.scanTimers.aTimerValues[i]. + uTimerRepeat, offset); + + ptr += offset; + } + + } else { + hdd_notice("No scan timers provided param count %d scan timers %d", + params, request.scanTimers.ucScanTimersCount); + + /* Scan timers defaults to 5 minutes */ + request.scanTimers.ucScanTimersCount = 1; + request.scanTimers.aTimerValues[0].uTimerValue = 60; + request.scanTimers.aTimerValues[0].uTimerRepeat = 0; + } + + params = sscanf(ptr, "%hhu %n", &(mode), &offset); + + request.modePNO = mode; + /* for LA we just expose suspend option */ + if ((1 != params) || (mode >= SIR_PNO_MODE_MAX)) { + request.modePNO = SIR_PNO_MODE_ON_SUSPEND; + } + + sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(adapter), + &request, + adapter->sessionId, + found_pref_network_cb, adapter); + + return 0; +} + +static int iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_pno(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/* Common function to SetBand */ +int hdd_set_band(struct net_device *dev, u8 ui_band) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + eCsrBand band; + + CDF_STATUS status; + hdd_context_t *pHddCtx; + hdd_adapter_list_node_t *pAdapterNode, *pNext; + eCsrBand currBand = eCSR_BAND_MAX; + eCsrBand connectedBand; + + pAdapterNode = NULL; + pNext = NULL; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + switch (ui_band) { + case WLAN_HDD_UI_BAND_AUTO: + band = eCSR_BAND_ALL; + break; + case WLAN_HDD_UI_BAND_5_GHZ: + band = eCSR_BAND_5G; + break; + case WLAN_HDD_UI_BAND_2_4_GHZ: + band = eCSR_BAND_24; + break; + default: + band = eCSR_BAND_MAX; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: change band to %u", __func__, band); + + if (band == eCSR_BAND_MAX) { + /* Received change band request with invalid band value */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid band value %u", __func__, ui_band); + return -EINVAL; + } + + if ((band == eCSR_BAND_24 && pHddCtx->config->nBandCapability == 2) || + (band == eCSR_BAND_5G && pHddCtx->config->nBandCapability == 1)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: band value %u violate INI settings %u", __func__, + band, pHddCtx->config->nBandCapability); + return -EIO; + } + + if (band == eCSR_BAND_ALL) { + hddLog(LOG1, + FL("Auto band received. Setting band same as ini value %d"), + pHddCtx->config->nBandCapability); + band = pHddCtx->config->nBandCapability; + } + + if (CDF_STATUS_SUCCESS != sme_get_freq_band(hHal, &currBand)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Failed to get current band config", __func__); + return -EIO; + } + + if (currBand != band) { + /* Change band request received. + * Abort pending scan requests, flush the existing scan results, + * and change the band capability + */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Current band value = %u, new setting %u ", + __func__, currBand, band); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && CDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE); + connectedBand = + hdd_conn_get_connected_band + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)); + + /* Handling is done only for STA and P2P */ + if (band != eCSR_BAND_ALL && + ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) + || (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) + && + (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) + && (connectedBand != band)) { + CDF_STATUS status = CDF_STATUS_SUCCESS; + long lrc; + + /* STA already connected on current band, So issue disconnect + * first, then change the band*/ + + hddLog(LOG1, + FL("STA (Device mode %s(%d)) connected in band %u, Changing band to %u, Issuing Disconnect"), + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, currBand, band); + INIT_COMPLETION(pAdapter->disconnect_comp_var); + + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if (CDF_STATUS_SUCCESS != status) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s csr_roam_disconnect failure, returned %d", + __func__, (int)status); + return -EINVAL; + } + + lrc = + wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + + if (lrc == 0) { + hddLog(CDF_TRACE_LEVEL_ERROR, + "%s:Timeout while waiting for csr_roam_disconnect", + __func__); + return -ETIMEDOUT; + } + } + + sme_scan_flush_result(hHal); + + status = + hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + if (CDF_STATUS_SUCCESS != + sme_set_freq_band(hHal, pAdapter->sessionId, band)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL, + FL("Failed to set the band value to %u"), + band); + return -EINVAL; + } + wlan_hdd_cfg80211_update_band(pHddCtx->wiphy, (eCsrBand) band); + } + return 0; +} + +int hdd_set_band_helper(struct net_device *dev, const char *command) +{ + uint8_t band; + int ret; + + /* Convert the band value from ascii to integer */ + command += WLAN_HDD_UI_SET_BAND_VALUE_OFFSET; + ret = kstrtou8(command, 10, &band); + if (ret < 0) { + hddLog(LOGE, FL("kstrtou8 failed")); + return -EINVAL; + } + + return hdd_set_band(dev, band); +} + +static int __iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int *value = (int *)extra; + + ENTER(); + + return hdd_set_band(dev, value[0]); +} + +static int iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_band_config(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_SET_SMPS_PARAM: + hddLog(LOG1, "WE_SET_SMPS_PARAM val %d %d", value[1], value[2]); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_SMPS_PARAM_CMDID, + value[1] << WMA_SMPS_PARAM_VALUE_S + | value[2], + VDEV_CMD); + break; +#ifdef DEBUG + case WE_SET_FW_CRASH_INJECT: + hddLog(LOGE, "WE_SET_FW_CRASH_INJECT: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(pAdapter->sessionId, + GEN_PARAM_CRASH_INJECT, + value[1], value[2], GEN_CMD); + break; +#endif + case WE_SET_DUAL_MAC_FW_MODE_CONFIG: + hdd_debug("Ioctl to set dual fw mode config"); + if (hdd_ctx->config->dual_mac_feature_disable) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d", value[1], value[2]); + cds_set_dual_mac_fw_mode_config(hdd_ctx, + value[1], value[2]); + break; + case WE_DUMP_DP_TRACE_LEVEL: + hdd_info("WE_DUMP_DP_TRACE_LEVEL: %d %d", + value[1], value[2]); + if (value[1] == DUMP_DP_TRACE) + cdf_dp_trace_dump_all(value[2]); + break; + default: + hddLog(LOGE, "%s: Invalid IOCTL command %d", __func__, sub_cmd); + break; + } + + return ret; +} + +static int iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Define the Wireless Extensions to the Linux Network Device structure */ +/* A number of these routines are NULL (meaning they are not implemented.) */ + +static const iw_handler we_handler[] = { + (iw_handler) iw_set_commit, /* SIOCSIWCOMMIT */ + (iw_handler) iw_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iw_set_freq, /* SIOCSIWFREQ */ + (iw_handler) iw_get_freq, /* SIOCGIWFREQ */ + (iw_handler) iw_set_mode, /* SIOCSIWMODE */ + (iw_handler) iw_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) iw_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iw_set_ap_address, /* SIOCSIWAP */ + (iw_handler) iw_get_ap_address, /* SIOCGIWAP */ + (iw_handler) iw_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) iw_set_scan, /* SIOCSIWSCAN */ + (iw_handler) iw_get_scan, /* SIOCGIWSCAN */ + (iw_handler) iw_set_essid, /* SIOCSIWESSID */ + (iw_handler) iw_get_essid, /* SIOCGIWESSID */ + (iw_handler) iw_set_nick, /* SIOCSIWNICKN */ + (iw_handler) iw_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_bitrate, /* SIOCSIWRATE */ + (iw_handler) iw_get_bitrate, /* SIOCGIWRATE */ + (iw_handler) iw_set_rts_threshold, /* SIOCSIWRTS */ + (iw_handler) iw_get_rts_threshold, /* SIOCGIWRTS */ + (iw_handler) iw_set_frag_threshold, /* SIOCSIWFRAG */ + (iw_handler) iw_get_frag_threshold, /* SIOCGIWFRAG */ + (iw_handler) iw_set_tx_power, /* SIOCSIWTXPOW */ + (iw_handler) iw_get_tx_power, /* SIOCGIWTXPOW */ + (iw_handler) iw_set_retry, /* SIOCSIWRETRY */ + (iw_handler) iw_get_retry, /* SIOCGIWRETRY */ + (iw_handler) iw_set_encode, /* SIOCSIWENCODE */ + (iw_handler) iw_get_encode, /* SIOCGIWENCODE */ + (iw_handler) iw_set_power_mode, /* SIOCSIWPOWER */ + (iw_handler) iw_get_power_mode, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_genie, /* SIOCSIWGENIE */ + (iw_handler) iw_get_genie, /* SIOCGIWGENIE */ + (iw_handler) iw_set_auth, /* SIOCSIWAUTH */ + (iw_handler) iw_get_auth, /* SIOCGIWAUTH */ + (iw_handler) iw_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) iw_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ +}; + +static const iw_handler we_private[] = { + + [WLAN_PRIV_SET_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_setint_getnone, /* set priv ioctl */ + [WLAN_PRIV_SET_NONE_GET_INT - SIOCIWFIRSTPRIV] = iw_setnone_getint, /* get priv ioctl */ + [WLAN_PRIV_SET_CHAR_GET_NONE - SIOCIWFIRSTPRIV] = iw_setchar_getnone, /* get priv ioctl */ + [WLAN_PRIV_SET_THREE_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [WLAN_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = iw_get_char_setnone, + [WLAN_PRIV_SET_NONE_GET_NONE - SIOCIWFIRSTPRIV] = iw_setnone_getnone, /* action priv ioctl */ + [WLAN_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_hdd_set_var_ints_getnone, + [WLAN_PRIV_ADD_TSPEC - SIOCIWFIRSTPRIV] = iw_add_tspec, + [WLAN_PRIV_DEL_TSPEC - SIOCIWFIRSTPRIV] = iw_del_tspec, + [WLAN_PRIV_GET_TSPEC - SIOCIWFIRSTPRIV] = iw_get_tspec, +#ifdef WLAN_FEATURE_VOWIFI_11R + [WLAN_PRIV_SET_FTIES - SIOCIWFIRSTPRIV] = iw_set_fties, +#endif + [WLAN_PRIV_SET_HOST_OFFLOAD - SIOCIWFIRSTPRIV] = iw_set_host_offload, + [WLAN_GET_WLAN_STATISTICS - SIOCIWFIRSTPRIV] = iw_get_statistics, + [WLAN_SET_KEEPALIVE_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_keepalive_params, +#ifdef WLAN_FEATURE_PACKET_FILTERING + [WLAN_SET_PACKET_FILTER_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_packet_filter_params, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + [WLAN_SET_PNO - SIOCIWFIRSTPRIV] = iw_set_pno, +#endif + [WLAN_SET_BAND_CONFIG - SIOCIWFIRSTPRIV] = iw_set_band_config, + [WLAN_GET_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_linkspeed, + [WLAN_PRIV_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_two_ints_getnone, + [WLAN_SET_DOT11P_CHANNEL_SCHED - SIOCIWFIRSTPRIV] = + iw_set_dot11p_channel_sched, +}; + +/*Maximum command length can be only 15 */ +static const struct iw_priv_args we_private_args[] = { + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_11D_STATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11Dstate"}, + + {WE_WOWL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "wowl"}, + + {WE_SET_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setPower"}, + + {WE_SET_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxAssoc"}, + + {WE_SET_SAP_AUTO_CHANNEL_SELECTION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setAutoChannel" }, + + {WE_SET_SCAN_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "scan_disable"}, + + {WE_SET_DATA_INACTIVITY_TO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "inactivityTO"}, + + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxTxPower"}, + + {WE_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxPower"}, + + {WE_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMcRate"}, + + {WE_SET_MAX_TX_POWER_2_4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower2G"}, + + {WE_SET_MAX_TX_POWER_5_0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower5G"}, + + /* SAP has TxMax whereas STA has MaxTx, adding TxMax for STA + * as well to keep same syntax as in SAP. Now onwards, STA + * will support both */ + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower"}, + + /* set Higher DTIM Transition (DTIM1 to DTIM3) + * 1 = enable and 0 = disable */ + { + WE_SET_HIGHER_DTIM_TRANSITION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setHDtimTransn" + }, + + {WE_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTmLevel"}, + + {WE_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setphymode"}, + + {WE_SET_NSS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "nss"}, + + {WE_SET_LDPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ldpc"}, + + {WE_SET_TX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "tx_stbc"}, + + {WE_SET_RX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rx_stbc"}, + + {WE_SET_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "shortgi"}, + + {WE_SET_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "enablertscts"}, + + {WE_SET_CHWIDTH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "chwidth"}, + + {WE_SET_ANI_EN_DIS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anienable"}, + + {WE_SET_ANI_POLL_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniplen"}, + + {WE_SET_ANI_LISTEN_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anilislen"}, + + {WE_SET_ANI_OFDM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniofdmlvl"}, + + {WE_SET_ANI_CCK_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniccklvl"}, + + {WE_SET_DYNAMIC_BW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cwmenable"}, + + {WE_SET_CTS_CBW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cts_cbw" }, + + {WE_SET_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxHTMcs"}, + + {WE_SET_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxVHTMcs"}, + + {WE_SET_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxUsrCfg"}, + + {WE_SET_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxThre"}, + + {WE_SET_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMargin"}, + + {WE_SET_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxStep"}, + + {WE_SET_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMinTpc"}, + + {WE_SET_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxBWMask"}, + + {WE_SET_TX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txchainmask"}, + + {WE_SET_RX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rxchainmask"}, + + {WE_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11NRates"}, + + {WE_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11ACRates"}, + + {WE_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ampdu"}, + + {WE_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "amsdu"}, + + {WE_SET_BURST_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "burst_enable"}, + + {WE_SET_BURST_DUR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "burst_dur"}, + + {WE_SET_TXPOW_2G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow2g"}, + + {WE_SET_TXPOW_5G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow5g"}, + + {WE_SET_POWER_GATING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "pwrgating"}, + + /* Sub-cmds DBGLOG specific commands */ + {WE_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_loglevel"}, + + {WE_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapon"}, + + {WE_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapoff"}, + + {WE_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modon"}, + + {WE_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modoff"}, + + {WE_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_mod_loglevel"}, + + {WE_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_type"}, + {WE_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_report"}, + + {WE_SET_TXRX_FWSTATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_stats"}, + + {WE_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_st_rst"}, + + {WE_PPS_PAID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "paid_match"}, + + {WE_PPS_GID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gid_match"}, + + {WE_PPS_EARLY_TIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "tim_clear"}, + + {WE_PPS_EARLY_DTIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dtim_clear"}, + + {WE_PPS_EOF_PAD_DELIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "eof_delim"}, + + {WE_PPS_MACADDR_MISMATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "mac_match"}, + + {WE_PPS_DELIM_CRC_FAIL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "delim_fail"}, + + {WE_PPS_GID_NSTS_ZERO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "nsts_zero"}, + + {WE_PPS_RSSI_CHECK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "rssi_chk"}, + + {WE_PPS_5G_EBT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "5g_ebt"}, + + {WE_SET_HTSMPS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "htsmps"}, + + {WE_SET_QPOWER_MAX_PSPOLL_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qpspollcnt"}, + + {WE_SET_QPOWER_MAX_TX_BEFORE_WAKE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qtxwake"}, + + {WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qwakeintv"}, + + {WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qnodatapoll"}, + + /* handlers for MCC time quota and latency sub ioctls */ + {WE_MCC_CONFIG_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccLatency"}, + + {WE_MCC_CONFIG_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccQuota"}, + + {WE_SET_DEBUG_LOG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDbgLvl"}, + + /* handlers for early_rx power save */ + {WE_SET_EARLY_RX_ADJUST_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_enable"}, + + {WE_SET_EARLY_RX_TGT_BMISS_NUM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_val"}, + + {WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_smpl"}, + + {WE_SET_EARLY_RX_SLOP_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_slop_step"}, + + {WE_SET_EARLY_RX_INIT_SLOP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_init_slop"}, + + {WE_SET_EARLY_RX_ADJUST_PAUSE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_adj_pause"}, + + {WE_SET_EARLY_RX_DRIFT_SAMPLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_dri_sample"}, + + {WE_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats"}, + + {WE_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats"}, + + {WLAN_PRIV_SET_NONE_GET_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + + /* handlers for sub-ioctl */ + {WE_GET_11D_STATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get11Dstate"}, + + {WE_IBSS_STATUS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getAdhocStatus"}, + + {WE_GET_WLAN_DBG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getwlandbg"}, + + {WE_GET_MAX_ASSOC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getMaxAssoc"}, + + {WE_GET_SAP_AUTO_CHANNEL_SELECTION, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getAutoChannel" }, + + {WE_GET_CONCURRENCY_MODE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getconcurrency"}, + + {WE_GET_NSS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss"}, + + {WE_GET_LDPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ldpc"}, + + {WE_GET_TX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tx_stbc"}, + + {WE_GET_RX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rx_stbc"}, + + {WE_GET_SHORT_GI, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_shortgi"}, + + {WE_GET_RTSCTS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rtscts"}, + + {WE_GET_CHWIDTH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_chwidth"}, + + {WE_GET_ANI_EN_DIS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anienable"}, + + {WE_GET_ANI_POLL_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniplen"}, + + {WE_GET_ANI_LISTEN_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anilislen"}, + + {WE_GET_ANI_OFDM_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniofdmlvl"}, + + {WE_GET_ANI_CCK_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniccklvl"}, + + {WE_GET_DYNAMIC_BW, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_cwmenable"}, + + {WE_GET_GTX_HT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs"}, + + {WE_GET_GTX_VHT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs"}, + + {WE_GET_GTX_USRCFG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg"}, + + {WE_GET_GTX_THRE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre"}, + + {WE_GET_GTX_MARGIN, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin"}, + + {WE_GET_GTX_STEP, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep"}, + + {WE_GET_GTX_MINTPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc"}, + + {WE_GET_GTX_BWMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask"}, + + {WE_GET_TX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask"}, + + {WE_GET_RX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask"}, + + {WE_GET_11N_RATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_11nrate"}, + + {WE_GET_AMPDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ampdu"}, + + {WE_GET_AMSDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_amsdu"}, + + {WE_GET_BURST_ENABLE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_burst_en"}, + + {WE_GET_BURST_DUR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_burst_dur"}, + + {WE_GET_TXPOW_2G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow2g"}, + + {WE_GET_TXPOW_5G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow5g"}, + + {WE_GET_POWER_GATING, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_pwrgating"}, + + {WE_GET_PPS_PAID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_paid_match"}, + + {WE_GET_PPS_GID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gid_match"}, + + {WE_GET_PPS_EARLY_TIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tim_clear"}, + + {WE_GET_PPS_EARLY_DTIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_dtim_clear"}, + + {WE_GET_PPS_EOF_PAD_DELIM, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_eof_delim"}, + + {WE_GET_PPS_MACADDR_MISMATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_mac_match"}, + + {WE_GET_PPS_DELIM_CRC_FAIL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_delim_fail"}, + + {WE_GET_PPS_GID_NSTS_ZERO, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nsts_zero"}, + + {WE_GET_PPS_RSSI_CHECK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rssi_chk"}, + + {WE_GET_QPOWER_MAX_PSPOLL_COUNT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qpspollcnt"}, + + {WE_GET_QPOWER_MAX_TX_BEFORE_WAKE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qtxwake"}, + + {WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qwakeintv"}, + + {WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qnodatapoll"}, + + {WE_GET_TEMPERATURE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_temp"}, + /* handlers for main ioctl */ + {WLAN_PRIV_SET_CHAR_GET_NONE, + IW_PRIV_TYPE_CHAR | 512, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_WOWL_ADD_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlAddPtrn"}, + + {WE_WOWL_DEL_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlDelPtrn"}, + +#if defined WLAN_FEATURE_VOWIFI + /* handlers for sub-ioctl */ + {WE_NEIGHBOR_REPORT_REQUEST, + IW_PRIV_TYPE_CHAR | 512, + 0, + "neighbor"}, +#endif + {WE_SET_AP_WPS_IE, + IW_PRIV_TYPE_CHAR | 512, + 0, + "set_ap_wps_ie"}, + + {WE_SET_CONFIG, + IW_PRIV_TYPE_CHAR | 512, + 0, + "setConfig"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "setwlandbg"}, + + /* handlers for sub-ioctl */ + {WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_dp_trace"}, + + {WE_SET_SAP_CHANNELS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "setsapchannels"}, + + {WE_SET_DUAL_MAC_SCAN_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_scan_cfg"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_CHAR_SET_NONE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + ""}, + + /* handlers for sub-ioctl */ + {WE_WLAN_VERSION, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "version"}, + {WE_GET_STATS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getStats"}, + {WE_GET_STATES, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getHostStates"}, + {WE_GET_CFG, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getConfig"}, +#ifdef WLAN_FEATURE_11AC + {WE_GET_RSSI, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getRSSI"}, +#endif + {WE_GET_WMM_STATUS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getWmmStatus"}, + { + WE_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getChannelList" + }, +#ifdef FEATURE_WLAN_TDLS + { + WE_GET_TDLS_PEERS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getTdlsPeers" + }, +#endif +#ifdef WLAN_FEATURE_11W + { + WE_GET_11W_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getPMFInfo" + }, +#endif + + {WE_GET_PHYMODE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getphymode"}, +#ifdef FEATURE_OEM_DATA_SUPPORT + {WE_GET_OEM_DATA_CAP, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getOemDataCap"}, +#endif /* FEATURE_OEM_DATA_SUPPORT */ + {WE_GET_SNR, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getSNR"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_NONE, + 0, + 0, + ""}, + + {WE_GET_RECOVERY_STAT, + 0, + 0, + "getRecoverStat"}, + { + WE_SET_REASSOC_TRIGGER, + 0, + 0, + "reassoc" + }, + {WE_DUMP_AGC_START, + 0, + 0, + "dump_agc_start"}, + + {WE_DUMP_AGC, + 0, + 0, + "dump_agc"}, + + {WE_DUMP_CHANINFO_START, + 0, + 0, + "dump_chninfo_en"}, + + {WE_DUMP_CHANINFO, + 0, + 0, + "dump_chninfo"}, + + {WE_DUMP_WATCHDOG, + 0, + 0, + "dump_watchdog"}, +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + {WE_DUMP_PCIE_LOG, + 0, + 0, + "dump_pcie_log"}, +#endif + /* handlers for main ioctl */ + {WLAN_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setdumplog"}, + + {WE_MTRACE_DUMP_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "dumplog"}, +#ifdef MPC_UT_FRAMEWORK + {WE_POLICY_MANAGER_CLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_clist"}, + + {WE_POLICY_MANAGER_DLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dlist"}, + + {WE_POLICY_MANAGER_DBS_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dbs"}, + + {WE_POLICY_MANAGER_PCL_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_pcl"}, + + {WE_POLICY_MANAGER_CINFO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_cinfo"}, + + {WE_POLICY_MANAGER_ULIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_ulist"}, + + {WE_POLICY_MANAGER_QUERY_ACTION_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_action"}, + + {WE_POLICY_MANAGER_QUERY_ALLOW_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_allow"}, + + {WE_POLICY_MANAGER_SCENARIO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_run_scenario"}, + + {WE_POLICY_SET_HW_MODE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_set_hw_mode"}, +#endif +#ifdef FEATURE_WLAN_TDLS + /* handlers for sub ioctl */ + { + WE_TDLS_CONFIG_PARAMS, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setTdlsConfig" + }, +#endif + { + WE_UNIT_TEST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setUnitTestCmd" + }, + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + {WE_LED_FLASHING_PARAM, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "gpio_control"}, +#endif + /* handlers for main ioctl */ + {WLAN_PRIV_ADD_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | HDD_WLAN_WMM_PARAM_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "addTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_DEL_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "delTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getTspec"}, + + /* handlers for main ioctl - host offload */ + { + WLAN_PRIV_SET_HOST_OFFLOAD, + IW_PRIV_TYPE_BYTE | sizeof(tHostOffloadRequest), + 0, + "setHostOffload" + } + , + + { + WLAN_GET_WLAN_STATISTICS, + 0, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + "getWlanStats" + } + , + + { + WLAN_SET_KEEPALIVE_PARAMS, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + 0, + "setKeepAlive" + } + , +#ifdef WLAN_FEATURE_PACKET_FILTERING + { + WLAN_SET_PACKET_FILTER_PARAMS, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | + sizeof(struct pkt_filter_cfg), + 0, + "setPktFilter" + } + , +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + { + WLAN_SET_PNO, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + 0, + "setpno" + } + , +#endif + { + WLAN_SET_BAND_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "SETBAND" + } + , + { + WLAN_GET_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" + } + , + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, + ""} + , + {WE_SET_SMPS_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_smps_param"} + , + {WLAN_SET_DOT11P_CHANNEL_SCHED, + IW_PRIV_TYPE_BYTE | sizeof(struct dot11p_channel_sched), + 0, "set_dot11p" } + , +#ifdef DEBUG + {WE_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject"} + , +#endif + {WE_SET_DUAL_MAC_FW_MODE_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_fw_mode_cfg"} + , + {WE_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace"} + , +}; + +const struct iw_handler_def we_handler_def = { + .num_standard = CDF_ARRAY_SIZE(we_handler), + .num_private = CDF_ARRAY_SIZE(we_private), + .num_private_args = CDF_ARRAY_SIZE(we_private_args), + + .standard = (iw_handler *) we_handler, + .private = (iw_handler *) we_private, + .private_args = we_private_args, + .get_wireless_stats = NULL, +}; + +int hdd_set_wext(hdd_adapter_t *pAdapter) +{ + hdd_wext_state_t *pwextBuf; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + /* Now configure the roaming profile links. To SSID and bssid. */ + pwextBuf->roamProfile.SSIDs.numOfSSIDs = 0; + pwextBuf->roamProfile.SSIDs.SSIDList = &pHddStaCtx->conn_info.SSID; + + pwextBuf->roamProfile.BSSIDs.numOfBSSIDs = 0; + pwextBuf->roamProfile.BSSIDs.bssid = &pHddStaCtx->conn_info.bssId; + + /*Set the numOfChannels to zero to scan all the channels */ + pwextBuf->roamProfile.ChannelInfo.numOfChannels = 0; + pwextBuf->roamProfile.ChannelInfo.ChannelList = NULL; + + /* Default is no encryption */ + pwextBuf->roamProfile.EncryptionType.numEntries = 1; + pwextBuf->roamProfile.EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pwextBuf->roamProfile.mcEncryptionType.numEntries = 1; + pwextBuf->roamProfile.mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pwextBuf->roamProfile.BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + + /* Default is no authentication */ + pwextBuf->roamProfile.AuthType.numEntries = 1; + pwextBuf->roamProfile.AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + pwextBuf->roamProfile.phyMode = eCSR_DOT11_MODE_AUTO; + pwextBuf->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + + /*Set the default scan mode */ + pAdapter->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + + hdd_clear_roam_profile_ie(pAdapter); + + return CDF_STATUS_SUCCESS; + +} + +int hdd_register_wext(struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + CDF_STATUS status; + + ENTER(); + + /* Zero the memory. This zeros the profile structure. */ + memset(pwextBuf, 0, sizeof(hdd_wext_state_t)); + + init_completion(&(WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter))-> + completion_var); + + status = hdd_set_wext(pAdapter); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("ERROR: hdd_set_wext failed!!")); + return CDF_STATUS_E_FAILURE; + } + + if (!CDF_IS_STATUS_SUCCESS(cdf_event_init(&pwextBuf->hdd_cdf_event))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("ERROR: HDD cdf event init failed!!")); + return CDF_STATUS_E_FAILURE; + } + + if (!CDF_IS_STATUS_SUCCESS(cdf_event_init(&pwextBuf->scanevent))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + ("ERROR: HDD scan event init failed!!")); + return CDF_STATUS_E_FAILURE; + } + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&we_handler_def; + + EXIT(); + return 0; +} + +int hdd_unregister_wext(struct net_device *dev) +{ + hddLog(LOG1, FL("dev(%p)"), dev); + + if (dev != NULL) { + rtnl_lock(); + dev->wireless_handlers = NULL; + rtnl_unlock(); + } + + return 0; +} diff --git a/core/hdd/src/wlan_hdd_wmm.c b/core/hdd/src/wlan_hdd_wmm.c new file mode 100644 index 0000000000..cdc1863ff4 --- /dev/null +++ b/core/hdd/src/wlan_hdd_wmm.c @@ -0,0 +1,2590 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* change logging behavior based upon debug flag */ +#ifdef HDD_WMM_DEBUG +#define WMM_TRACE_LEVEL_FATAL CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_ERROR CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_WARN CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_INFO CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_INFO_HIGH CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_INFO_LOW CDF_TRACE_LEVEL_FATAL +#else +#define WMM_TRACE_LEVEL_FATAL CDF_TRACE_LEVEL_FATAL +#define WMM_TRACE_LEVEL_ERROR CDF_TRACE_LEVEL_ERROR +#define WMM_TRACE_LEVEL_WARN CDF_TRACE_LEVEL_WARN +#define WMM_TRACE_LEVEL_INFO CDF_TRACE_LEVEL_INFO +#define WMM_TRACE_LEVEL_INFO_HIGH CDF_TRACE_LEVEL_INFO_HIGH +#define WMM_TRACE_LEVEL_INFO_LOW CDF_TRACE_LEVEL_INFO_LOW +#endif + +#define WLAN_HDD_MAX_DSCP 0x3f + +/* DHCP Port number */ +#define DHCP_SOURCE_PORT 0x4400 +#define DHCP_DESTINATION_PORT 0x4300 + +#define HDD_WMM_UP_TO_AC_MAP_SIZE 8 + +const uint8_t hdd_wmm_up_to_ac_map[] = { + SME_AC_BE, + SME_AC_BK, + SME_AC_BK, + SME_AC_BE, + SME_AC_VI, + SME_AC_VI, + SME_AC_VO, + SME_AC_VO +}; + +/** + * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to + * operate on different traffic. + */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +enum hdd_wmm_linuxac { + HDD_LINUX_AC_VO = 0, + HDD_LINUX_AC_VI = 1, + HDD_LINUX_AC_BE = 2, + HDD_LINUX_AC_BK = 3, + HDD_LINUX_AC_HI_PRIO = 4, +}; + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter) +{ + /* Enable HI_PRIO queue */ + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); + +} +#else +enum hdd_wmm_linuxac { + HDD_LINUX_AC_VO = 0, + HDD_LINUX_AC_VI = 1, + HDD_LINUX_AC_BE = 2, + HDD_LINUX_AC_BK = 3 +}; + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter) +{ + return; +} +#endif + +/* Linux based UP -> AC Mapping */ +const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = { + HDD_LINUX_AC_BE, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BE, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VO, + HDD_LINUX_AC_VO +}; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_enable_tl_uapsd() - function which decides whether and + * how to update UAPSD parameters in TL + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_enable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + CDF_STATUS status; + uint32_t service_interval; + uint32_t suspension_interval; + sme_QosWmmDirType direction; + bool psb; + + /* The TSPEC must be valid */ + if (pAc->wmmAcTspecValid == false) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Invoked with invalid TSPEC", __func__); + return; + } + /* determine the service interval */ + if (pAc->wmmAcTspecInfo.min_service_interval) { + service_interval = pAc->wmmAcTspecInfo.min_service_interval; + } else if (pAc->wmmAcTspecInfo.max_service_interval) { + service_interval = pAc->wmmAcTspecInfo.max_service_interval; + } else { + /* no service interval is present in the TSPEC */ + /* this is OK, there just won't be U-APSD */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: No service interval supplied", __func__); + service_interval = 0; + } + + /* determine the suspension interval & direction */ + suspension_interval = pAc->wmmAcTspecInfo.suspension_interval; + direction = pAc->wmmAcTspecInfo.ts_info.direction; + psb = pAc->wmmAcTspecInfo.ts_info.psb; + + /* if we have previously enabled U-APSD, have any params changed? */ + if ((pAc->wmmAcUapsdInfoValid) && + (pAc->wmmAcUapsdServiceInterval == service_interval) && + (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) && + (pAc->wmmAcUapsdDirection == direction) && + (pAc->wmmAcIsUapsdEnabled == psb)) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: No change in U-APSD parameters", __func__); + return; + } + /* everything is in place to notify TL */ + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.staId[0], acType, + pAc->wmmAcTspecInfo.ts_info.tid, + pAc->wmmAcTspecInfo.ts_info.up, + service_interval, suspension_interval, + direction, psb, pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Failed to enable U-APSD for AC=%d", + __func__, acType); + return; + } + /* stash away the parameters that were used */ + pAc->wmmAcUapsdInfoValid = true; + pAc->wmmAcUapsdServiceInterval = service_interval; + pAc->wmmAcUapsdSuspensionInterval = suspension_interval; + pAc->wmmAcUapsdDirection = direction; + pAc->wmmAcIsUapsdEnabled = psb; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Enabled UAPSD in TL srv_int=%d " + "susp_int=%d dir=%d AC=%d", + __func__, + service_interval, suspension_interval, direction, acType); + +} + +/** + * hdd_wmm_disable_tl_uapsd() - function which decides whether + * to disable UAPSD parameters in TL + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_disable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + CDF_STATUS status; + uint32_t service_interval; + uint32_t suspension_interval; + uint8_t uapsd_mask; + uint8_t active_tspec = INVALID_TSPEC; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + struct hdd_config *cfg = hdd_ctx->config; + + /* have we previously enabled UAPSD? */ + if (pAc->wmmAcUapsdInfoValid == true) { + uapsd_mask = cfg->UapsdMask; + /* Finding uapsd_mask as per AC */ + uapsd_mask = uapsd_mask & (1 << (SME_AC_VO - acType)); + + sme_qos_tspec_active( + (tpAniSirGlobal)WLAN_HDD_GET_HAL_CTX(pAdapter), acType, + pAdapter->sessionId, &active_tspec); + + /* Call sme_enable_uapsd_for_ac only when static uapsd mask + * is present and no active tspecs. + */ + + if (uapsd_mask && !active_tspec) { + switch (acType) { + case SME_AC_VO: + service_interval = cfg->InfraUapsdVoSrvIntv; + suspension_interval = cfg->InfraUapsdVoSuspIntv; + break; + case SME_AC_VI: + service_interval = cfg->InfraUapsdViSrvIntv; + suspension_interval = cfg->InfraUapsdViSuspIntv; + break; + case SME_AC_BE: + service_interval = cfg->InfraUapsdBeSrvIntv; + suspension_interval = cfg->InfraUapsdBeSuspIntv; + break; + case SME_AC_BK: + service_interval = cfg->InfraUapsdBkSrvIntv; + suspension_interval = cfg->InfraUapsdBkSuspIntv; + break; + default: + return; + } + + /* restore the UAPSD intervals configuration */ + status = sme_enable_uapsd_for_ac(hdd_ctx->pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + acType, + pAc->wmmAcTspecInfo.ts_info.tid, + pAc->wmmAcTspecInfo.ts_info.up, + service_interval, + suspension_interval, + pAc->wmmAcTspecInfo.ts_info.direction, + pAc->wmmAcTspecInfo.ts_info.psb, + pAdapter->sessionId, + cfg->DelayedTriggerFrmInt); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to set U-APSD for AC=%d", + acType); + } else { + /* TL no longer has valid UAPSD info */ + pAc->wmmAcUapsdInfoValid = false; + hdd_err("Disabled UAPSD in TL for AC=%d", + acType); + } + } + } +} + +#endif + +/** + * hdd_wmm_free_context() - function which frees a QoS context + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_free_context(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered, context %p", __func__, pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + /* must have been freed in another thread */ + return; + } + /* get pointer to the adapter context */ + pAdapter = pQosContext->pAdapter; + + /* take the wmmLock since we're manipulating the context list */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + + /* make sure nobody thinks this is a valid context */ + pQosContext->magic = 0; + + /* unlink the context */ + list_del(&pQosContext->node); + + /* done manipulating the list */ + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + /* reclaim memory */ + kfree(pQosContext); + +} + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_notify_app() - function which notifies an application + * of changes in state of it flow + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +#define MAX_NOTIFY_LEN 50 +static void hdd_wmm_notify_app(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter; + union iwreq_data wrqu; + char buf[MAX_NOTIFY_LEN + 1]; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered, context %p", __func__, pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Invalid QoS Context", __func__); + return; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]", + (unsigned int)pQosContext->handle, + (unsigned int)pQosContext->lastStatus); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* get pointer to the adapter */ + pAdapter = pQosContext->pAdapter; + + /* send the event */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Sending [%s]", __func__, buf); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function + * + * @user_data: opaque user data registered with the timer. In the + * case of this timer, the associated wmm QoS context is registered. + * + * This timer handler function is called for every inactivity interval + * per AC. This function gets the current transmitted packets on the + * given AC, and checks if there was any TX activity from the previous + * interval. If there was no traffic then it would delete the TS that + * was negotiated on that AC. + * + * Return: None + */ +static void hdd_wmm_inactivity_timer_cb(void *user_data) +{ + hdd_wmm_qos_context_t *pQosContext = user_data; + hdd_adapter_t *pAdapter; + hdd_wmm_ac_status_t *pAc; + hdd_wlan_wmm_status_e status; + CDF_STATUS cdf_status; + uint32_t currentTrafficCnt = 0; + sme_ac_enum_type acType = pQosContext->acType; + + pAdapter = pQosContext->pAdapter; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + /* Get the Tx stats for this AC. */ + currentTrafficCnt = + pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext-> + acType]; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL( + "WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d" + ), + acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt); + if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) { + /* there is no traffic activity, delete the TSPEC for this AC */ + status = hdd_wmm_delts(pAdapter, pQosContext->handle); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + FL( + "Deleted TS on AC %d, due to inactivity with status = %d!!!" + ), + acType, status); + } else { + pAc->wmmPrevTrafficCnt = currentTrafficCnt; + if (pAc->wmmInactivityTimer.state == CDF_TIMER_STATE_STOPPED) { + /* Restart the timer */ + cdf_status = + cdf_mc_timer_start(&pAc->wmmInactivityTimer, + pAc->wmmInactivityTime); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + FL( + "Restarting inactivity timer failed on AC %d" + ), + acType); + } + } else { + CDF_ASSERT(cdf_mc_timer_get_current_state + (&pAc->wmmInactivityTimer) == + CDF_TIMER_STATE_STOPPED); + } + } + + return; +} + +/** + * hdd_wmm_enable_inactivity_timer() - + * function to enable the traffic inactivity timer for the given AC + * + * @pQosContext: [in] pointer to pQosContext + * @inactivityTime: [in] value of the inactivity interval in millisecs + * + * When a QoS-Tspec is successfully setup, if the inactivity interval + * time specified in the AddTS parameters is non-zero, this function + * is invoked to start a traffic inactivity timer for the given AC. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +hdd_wmm_enable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext, + uint32_t inactivityTime) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc; + + pAdapter = pQosContext->pAdapter; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + cdf_status = cdf_mc_timer_init(&pAc->wmmInactivityTimer, + CDF_TIMER_TYPE_SW, + hdd_wmm_inactivity_timer_cb, + pQosContext); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Initializing inactivity timer failed on AC %d"), + acType); + return cdf_status; + } + /* Start the inactivity timer */ + cdf_status = cdf_mc_timer_start(&pAc->wmmInactivityTimer, + inactivityTime); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + FL("Starting inactivity timer failed on AC %d"), + acType); + cdf_status = cdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hdd_err("Failed to destroy inactivity timer"); + } + return cdf_status; + } + pAc->wmmInactivityTime = inactivityTime; + /* Initialize the current tx traffic count on this AC */ + pAc->wmmPrevTrafficCnt = + pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext-> + acType]; + pQosContext->is_inactivity_timer_running = true; + return cdf_status; +} + +/** + * hdd_wmm_disable_inactivity_timer() - + * function to disable the traffic inactivity timer for the given AC. + * + * @pQosContext: [in] pointer to pQosContext + * + * This function is invoked to disable the traffic inactivity timer + * for the given AC. This is normally done when the TS is deleted. + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS +hdd_wmm_disable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + /* Clear the timer and the counter */ + pAc->wmmInactivityTime = 0; + pAc->wmmPrevTrafficCnt = 0; + + if (pQosContext->is_inactivity_timer_running == true) { + pQosContext->is_inactivity_timer_running = false; + cdf_status = cdf_mc_timer_stop(&pAc->wmmInactivityTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + hdd_err("Failed to stop inactivity timer"); + return cdf_status; + } + cdf_status = cdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + hdd_err("Failed to destroy inactivity timer:Timer started"); + } + + return cdf_status; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_wmm_sme_callback() - callback for QoS notifications + * + * @hHal: [in] the HAL handle + * @hddCtx : [in] the HDD specified handle + * @pCurrentQosInfo : [in] the TSPEC params + * @smeStatus : [in] the QoS related SME status + * @qosFlowId: [in] the unique identifier of the flow + * + * This callback is registered by HDD with SME for receiving QoS + * notifications. Even though this function has a static scope it + * gets called externally through some function pointer magic (so + * there is a need for rigorous parameter checking). + * + * Return: CDF_STATUS enumeration + */ +static CDF_STATUS hdd_wmm_sme_callback(tHalHandle hHal, + void *hddCtx, + sme_QosWmmTspecInfo *pCurrentQosInfo, + sme_QosStatusType smeStatus, + uint32_t qosFlowId) +{ + hdd_wmm_qos_context_t *pQosContext = hddCtx; + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wmm_ac_status_t *pAc; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered, context %p", __func__, pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Invalid QoS Context", __func__); + return CDF_STATUS_E_FAILURE; + } + + pAdapter = pQosContext->pAdapter; + acType = pQosContext->acType; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: status %d flowid %d info %p", + __func__, smeStatus, qosFlowId, pCurrentQosInfo); + + switch (smeStatus) { + + case SME_QOS_STATUS_SETUP_SUCCESS_IND: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Setup is complete", __func__); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + +#ifdef FEATURE_WLAN_ESE + /* Check if the inactivity interval is specified */ + if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Inactivity timer value = %d for AC=%d", + __func__, + pCurrentQosInfo->inactivity_interval, acType); + hdd_wmm_enable_inactivity_timer(pQosContext, + pCurrentQosInfo-> + inactivity_interval); + } +#endif /* FEATURE_WLAN_ESE */ + + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Setup is complete (U-APSD set previously)", + __func__); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Setup failed", __func__); + /* QoS setup failed */ + + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = false; + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED; + + hdd_wmm_notify_app(pQosContext); + } + + /* Setting up QoS Failed, QoS context can be released. + * SME is releasing this flow information and if HDD + * doesn't release this context, next time if + * application uses the same handle to set-up QoS, HDD + * (as it has QoS context for this handle) will issue + * Modify QoS request to SME but SME will reject as now + * it has no information for this flow. + */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Setup Invalid Params, notify TL", __func__); + /* QoS setup failed */ + pAc->wmmAcAccessAllowed = false; + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* we note the failure, but we also mark + * access as allowed so that the packets will + * flow. Note that the MAC will "do the right + * thing" + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = true; + + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Setup failed, not a QoS AP", __func__); + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Setup pending", __func__); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_SETUP_MODIFIED_IND: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Setup modified", __func__); + if (pCurrentQosInfo) { + /* update the TSPEC */ + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + CDF_TRACE(CDF_MODULE_ID_HDD, + WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFIED; + hdd_wmm_notify_app(pQosContext); + } + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* this was triggered by implicit QoS so we + * know packets are pending + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now */ + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Setup successful but U-APSD failed", __func__); + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* QoS setup was successful but setting U=APSD + * failed. Since the OTA part of the request + * was successful, we don't mark this as a + * failure. the packets will flow. Note that + * the MAC will "do the right thing" */ + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessFailed = false; + pAc->wmmAcAccessPending = false; + + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Release is complete", __func__); + + if (pCurrentQosInfo) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: flows still active", __func__); + + /* there is still at least one flow active for + * this AC so update the AC state + */ + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: last flow", __func__); + + /* this is the last flow active for this AC so + * update the AC state + */ + pAc->wmmAcTspecValid = false; + + /* DELTS is successful, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Release failure", __func__); + + /* we don't need to update our state or TL since + * nothing has changed + */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_RELEASE_QOS_LOST_IND: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: QOS Lost indication received", __func__); + + /* current TSPEC is no longer valid */ + pAc->wmmAcTspecValid = false; + /* AP has sent DELTS, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + /* we no longer have implicit access granted */ + pAc->wmmAcAccessGranted = false; + pAc->wmmAcAccessFailed = false; + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Explicit Qos, notifying user space", + __func__); + + /* this was triggered by an application */ + pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST; + hdd_wmm_notify_app(pQosContext); + } + + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Release pending", __func__); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Release Invalid Params", __func__); + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Modification is complete, notify TL", __func__); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + /* the flow modification failed so we'll leave in + * place whatever existed beforehand + */ + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: modification pending", __func__); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* the flow modification was successful but no QoS + * changes required + */ + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + /* invalid params -- notify the application */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now. when APSD is established we'll have work to do */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Modify successful but U-APSD failed", __func__); + + /* QoS modification was successful but setting U=APSD + * failed. This will always be an explicit QoS + * instance, so all we can do is notify the + * application and let it clean up. + */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_HANDING_OFF: + /* no roaming so we won't see this */ + break; + + case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND: + /* need to tell TL to stop trigger frame generation */ + hdd_wmm_disable_tl_uapsd(pQosContext); + break; + + case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND: + /* need to tell TL to start sending trigger frames again */ + hdd_wmm_enable_tl_uapsd(pQosContext); + break; + + default: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: unexpected SME Status=%d", __func__, smeStatus); + CDF_ASSERT(0); + } + + /* if Tspec only allows downstream traffic then access is not + * allowed + */ + if (pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + pAc->wmmAcAccessAllowed = false; + } + /* if we have valid Tpsec or if ACM bit is not set, allow access */ + if ((pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) { + pAc->wmmAcAccessAllowed = true; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: complete, access for TL AC %d is%sallowed", + __func__, acType, pAc->wmmAcAccessAllowed ? " " : " not "); + + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @pAdapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr) +{ + if (NULL == pAdapter) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: pAdapter is NULL", __func__); + return -EINVAL; + } + if (NULL == ptr) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: ptr is NULL", __func__); + return -EINVAL; + } + /* convert ASCII to integer */ + pAdapter->configuredPsb = ptr[9] - '0'; + pAdapter->psbChanged = HDD_PSB_CHANGED; + + return 0; +} + +/** + * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup + * QoS for any AC requiring it. + * @work: [in] pointer to work structure. + * + * Return: none + */ +static void __hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + hdd_wmm_qos_context_t *pQosContext = + container_of(work, hdd_wmm_qos_context_t, wmmAcSetupImplicitQos); + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wmm_ac_status_t *pAc; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + sme_QosWmmTspecInfo qosInfo; + hdd_context_t *hdd_ctx; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered, context %p", __func__, pQosContext); + + if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Invalid QoS Context", __func__); + return; + } + + pAdapter = pQosContext->pAdapter; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + hddLog(LOGE, FL("HDD context is not valid")); + return; + } + + acType = pQosContext->acType; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: pAdapter %p acType %d", __func__, pAdapter, acType); + + if (!pAc->wmmAcAccessNeeded) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: AC %d doesn't need service", __func__, acType); + pQosContext->magic = 0; + kfree(pQosContext); + return; + } + + pAc->wmmAcAccessPending = true; + pAc->wmmAcAccessNeeded = false; + + memset(&qosInfo, 0, sizeof(qosInfo)); + + qosInfo.ts_info.psb = pAdapter->configuredPsb; + + switch (acType) { + case SME_AC_VO: + qosInfo.ts_info.up = SME_QOS_WMM_UP_VO; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVo; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcVo; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVo; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVo; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVo; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSuspIntv; + break; + case SME_AC_VI: + qosInfo.ts_info.up = SME_QOS_WMM_UP_VI; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVi; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcVi; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVi; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVi; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVi; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSuspIntv; + break; + default: + case SME_AC_BE: + qosInfo.ts_info.up = SME_QOS_WMM_UP_BE; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBe; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcBe; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBe; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBe; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBe; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSuspIntv; + break; + case SME_AC_BK: + qosInfo.ts_info.up = SME_QOS_WMM_UP_BK; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBk; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcBk; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBk; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBk; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBk; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSuspIntv; + break; + } +#ifdef FEATURE_WLAN_ESE + qosInfo.inactivity_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraInactivityInterval; +#endif + qosInfo.ts_info.burst_size_defn = + (WLAN_HDD_GET_CTX(pAdapter))->config->burstSizeDefinition; + + switch ((WLAN_HDD_GET_CTX(pAdapter))->config->tsInfoAckPolicy) { + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + + if (qosInfo.ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + if (!sme_qos_is_ts_info_ack_policy_valid + ((tpAniSirGlobal) WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo, + pAdapter->sessionId)) { + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + } + + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList); + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &qosInfo, + hdd_wmm_sme_callback, + pQosContext, + qosInfo.ts_info.up, + &pQosContext->qosFlowId); + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: sme_qos_setup_req returned %d flowid %d", + __func__, smeStatus, pQosContext->qosFlowId); + + /* need to check the return values and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* setup is pending, so no more work to do now. all + * further work will be done in hdd_wmm_sme_callback() + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Setup is pending, no further work", __func__); + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encountered an internal error. in either case SME + * won't ever reference this context so free the + * record + */ + hdd_wmm_free_context(pQosContext); + + /* fall through and start packets flowing */ + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* no ACM in effect, no need to setup U-APSD */ + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + /* no ACM in effect, U-APSD is desired but was already setup */ + + /* for these cases everything is already setup so we + * can signal TL that it has work to do + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Setup is complete, notify TL", __func__); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + break; + + default: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: unexpected SME Status=%d", __func__, smeStatus); + CDF_ASSERT(0); + } +#endif + +} + +/** + * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos + * @work: pointer to work_struct + * + * Return: none + */ +static void hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_wmm_do_implicit_qos(work); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_wmm_init() - initialize the WMM DSCP configuation + * @pAdapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter) +{ + sme_QosWmmUpType *hddWmmDscpToUpMap = pAdapter->hddWmmDscpToUpMap; + uint8_t dscp; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + + /* DSCP to User Priority Lookup Table + * By default use the 3 Precedence bits of DSCP as the User Priority + */ + for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) { + hddWmmDscpToUpMap[dscp] = dscp >> 3; + } + + /* Special case for Expedited Forwarding (DSCP 46) */ + hddWmmDscpToUpMap[46] = SME_QOS_WMM_UP_VO; + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @pAdapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuation and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter) +{ + hdd_wmm_ac_status_t *pAcStatus; + sme_ac_enum_type acType; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + + pAdapter->hddWmmStatus.wmmQap = false; + INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList); + mutex_init(&pAdapter->hddWmmStatus.wmmLock); + + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = false; + } + /* Invalid value(0xff) to indicate psb not configured through + * framework initially. + */ + pAdapter->configuredPsb = HDD_PSB_CFG_INVALID; + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @pAdapter: [in] pointer to Adapter context + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter) +{ + hdd_wmm_ac_status_t *pAcStatus; + sme_ac_enum_type acType; + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = false; + } + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_close() - WMM close function + * @pAdapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter) +{ + hdd_wmm_qos_context_t *pQosContext; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + + /* free any context records that we still have linked */ + while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList)) { + pQosContext = + list_first_entry(&pAdapter->hddWmmStatus.wmmContextList, + hdd_wmm_qos_context_t, node); +#ifdef FEATURE_WLAN_ESE + hdd_wmm_disable_inactivity_timer(pQosContext); +#endif + if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT + && pQosContext->magic == HDD_WMM_CTX_MAGIC) + cds_flush_work(&pQosContext->wmmAcSetupImplicitQos); + + hdd_wmm_free_context(pQosContext); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_classify_pkt() - Function which will classify an OS packet + * into a WMM AC based on either 802.1Q or DSCP + * + * @pAdapter: [in] adapter upon which the packet is being transmitted + * @skb: [in] the actual OS packet (sk_buff) being transmitted + * @pAcType: [out] WMM AC type of the OS packet + * @pUserPri: [out] User Priority of the OS packet + * + * Return: None + */ +static +void hdd_wmm_classify_pkt(hdd_adapter_t *pAdapter, + struct sk_buff *skb, + sme_ac_enum_type *pAcType, + sme_QosWmmUpType *pUserPri, + bool *is_eapol) +{ + unsigned char *pPkt; + union generic_ethhdr *pHdr; + struct iphdr *pIpHdr; + unsigned char tos; + unsigned char dscp; + sme_QosWmmUpType userPri; + sme_ac_enum_type acType; + + /* this code is executed for every packet therefore + * all debug code is kept conditional + */ + +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); +#endif /* HDD_WMM_DEBUG */ + + pPkt = skb->data; + pHdr = (union generic_ethhdr *)pPkt; + +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: proto/length is 0x%04x", __func__, pHdr->eth_II.h_proto); +#endif /* HDD_WMM_DEBUG */ + + if (HDD_WMM_CLASSIFICATION_DSCP == + (WLAN_HDD_GET_CTX(pAdapter))->config->PktClassificationBasis) { + if (pHdr->eth_II.h_proto == htons(ETH_P_IP)) { + /* case 1: Ethernet II IP packet */ + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_II)]; + tos = pIpHdr->tos; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Ethernet II IP Packet, tos is %d", + __func__, tos); +#endif /* HDD_WMM_DEBUG */ + + } else if ((ntohs(pHdr->eth_II.h_proto) < WLAN_MIN_PROTO) && + (pHdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) && + (pHdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) && + (pHdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) && + (pHdr->eth_8023.h_proto == htons(ETH_P_IP))) { + /* case 2: 802.3 LLC/SNAP IP packet */ + pIpHdr = (struct iphdr *)&pPkt[sizeof(pHdr->eth_8023)]; + tos = pIpHdr->tos; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: 802.3 LLC/SNAP IP Packet, tos is %d", + __func__, tos); +#endif /* HDD_WMM_DEBUG */ + } else if (pHdr->eth_II.h_proto == htons(ETH_P_8021Q)) { + /* VLAN tagged */ + + if (pHdr->eth_IIv.h_vlan_encapsulated_proto == + htons(ETH_P_IP)) { + /* case 3: Ethernet II vlan-tagged IP packet */ + pIpHdr = + (struct iphdr *) + &pPkt[sizeof(pHdr->eth_IIv)]; + tos = pIpHdr->tos; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, + WMM_TRACE_LEVEL_INFO_LOW, + "%s: Ethernet II VLAN tagged IP Packet, tos is %d", + __func__, tos); +#endif /* HDD_WMM_DEBUG */ + } else + if ((ntohs(pHdr->eth_IIv.h_vlan_encapsulated_proto) + < WLAN_MIN_PROTO) + && (pHdr->eth_8023v.h_snap.dsap == + WLAN_SNAP_DSAP) + && (pHdr->eth_8023v.h_snap.ssap == + WLAN_SNAP_SSAP) + && (pHdr->eth_8023v.h_snap.ctrl == + WLAN_SNAP_CTRL) + && (pHdr->eth_8023v.h_proto == + htons(ETH_P_IP))) { + /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */ + pIpHdr = + (struct iphdr *) + &pPkt[sizeof(pHdr->eth_8023v)]; + tos = pIpHdr->tos; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, + WMM_TRACE_LEVEL_INFO_LOW, + "%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d", + __func__, tos); +#endif /* HDD_WMM_DEBUG */ + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, + WMM_TRACE_LEVEL_WARN, + "%s: VLAN tagged Unhandled Protocol, using default tos", + __func__); +#endif /* HDD_WMM_DEBUG */ + tos = 0; + } + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN, + "%s: Unhandled Protocol, using default tos", + __func__); +#endif /* HDD_WMM_DEBUG */ + /* Give the highest priority to 802.1x packet */ + if (pHdr->eth_II.h_proto == + htons(HDD_ETHERTYPE_802_1_X)) { + tos = 0xC0; + *is_eapol = true; + } else + tos = 0; + } + + dscp = (tos >> 2) & 0x3f; + userPri = pAdapter->hddWmmDscpToUpMap[dscp]; + +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: tos is %d, dscp is %d, up is %d", + __func__, tos, dscp, userPri); +#endif /* HDD_WMM_DEBUG */ + + } else if (HDD_WMM_CLASSIFICATION_802_1Q == + (WLAN_HDD_GET_CTX(pAdapter))->config-> + PktClassificationBasis) { + if (pHdr->eth_IIv.h_vlan_proto == htons(ETH_P_8021Q)) { + /* VLAN tagged */ + userPri = (ntohs(pHdr->eth_IIv.h_vlan_TCI) >> 13) & 0x7; +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Tagged frame, UP is %d", + __func__, userPri); +#endif /* HDD_WMM_DEBUG */ + } else { + /* not VLAN tagged, use default */ +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN, + "%s: Untagged frame, using default UP", + __func__); +#endif /* HDD_WMM_DEBUG */ + /* Give the highest priority to 802.1x packet */ + if (pHdr->eth_II.h_proto == + htons(HDD_ETHERTYPE_802_1_X)) { + userPri = SME_QOS_WMM_UP_VO; + *is_eapol = true; + } else + userPri = SME_QOS_WMM_UP_BE; + } + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Unknown classification scheme, using default UP", + __func__); +#endif /* HDD_WMM_DEBUG */ + userPri = SME_QOS_WMM_UP_BE; + } + + acType = hdd_wmm_up_to_ac_map[userPri]; + +#ifdef HDD_WMM_DEBUG + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: UP is %d, AC is %d", __func__, userPri, acType); +#endif /* HDD_WMM_DEBUG */ + + *pUserPri = userPri; + *pAcType = acType; + + return; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * hdd_get_queue_index() - get queue index + * @up: user priority + * @is_eapol: is_eapol flag + * + * Return: queue_index + */ +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) +{ + if (cdf_unlikely(is_eapol == true)) + return HDD_LINUX_AC_HI_PRIO; + else + return hdd_linux_up_to_ac_map[up]; +} +#else +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) +{ + return hdd_linux_up_to_ac_map[up]; +} +#endif + + +/** + * hdd_hostapd_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif + +) +{ + sme_ac_enum_type ac; + sme_QosWmmUpType up = SME_QOS_WMM_UP_BE; + uint16_t queueIndex; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + bool is_eapol = false; + + if (HDD_WMM_USER_MODE_NO_QOS != pHddCtx->config->WmmMode) { + /* Get the user priority from IP header & corresponding AC */ + hdd_wmm_classify_pkt(pAdapter, skb, &ac, &up, &is_eapol); + } + + skb->priority = up; + queueIndex = hdd_get_queue_index(skb->priority, is_eapol); + + return queueIndex; +} + +/** + * hdd_wmm_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + sme_ac_enum_type ac; + sme_QosWmmUpType up = SME_QOS_WMM_UP_BE; + uint16_t queueIndex; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool is_eapol = false; + + /* if we don't want QoS or the AP doesn't support Qos */ + /* All traffic will get equal opportuniy to transmit data frames. */ + if (hdd_wmm_is_active(pAdapter)) { + /* Get the user priority from IP header & corresponding AC */ + hdd_wmm_classify_pkt(pAdapter, skb, &ac, &up, &is_eapol); + } + + skb->priority = up; + queueIndex = hdd_get_queue_index(skb->priority, is_eapol); + return queueIndex; +} + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @pAdapter: [in] pointer to adapter structure + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType) +{ + /* Each bit in the LSB nibble indicates 1 AC. + * Clearing the particular bit in LSB nibble to indicate + * access required + */ + switch (acType) { + case SME_AC_BK: + /* clear first bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK; + break; + case SME_AC_BE: + /* clear second bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK; + break; + case SME_AC_VI: + /* clear third bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK; + break; + case SME_AC_VO: + /* clear fourth bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK; + break; + default: + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Invalid AC Type", __func__); + break; + } +} + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @pAdapter: [in] pointer to adapter context + * @acType: [in] WMM AC type of OS packet + * @pGranted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType, bool *pGranted) +{ + hdd_wmm_qos_context_t *pQosContext; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered for AC %d", __func__, acType); + + if (!hdd_wmm_is_active(pAdapter) || + !(WLAN_HDD_GET_CTX(pAdapter))->config->bImplicitQosEnabled || + !pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessRequired) { + /* either we don't want QoS or the AP doesn't support + * QoS or we don't want to do implicit QoS + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: QoS not configured on both ends ", __func__); + + *pGranted = + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed; + + return CDF_STATUS_SUCCESS; + } + /* do we already have an implicit QoS request pending for this AC? */ + if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) || + (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending)) { + /* request already pending so we need to wait for that + * response + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Implicit QoS for TL AC %d already scheduled", + __func__, acType); + + *pGranted = false; + return CDF_STATUS_SUCCESS; + } + /* did we already fail to establish implicit QoS for this AC? + * (if so, access should have been granted when the failure + * was handled) + */ + if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed) { + /* request previously failed + * allow access, but we'll be downgraded + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Implicit QoS for TL AC %d previously failed", + __func__, acType); + + if (!pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessRequired) { + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed = true; + *pGranted = true; + } else { + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed = false; + *pGranted = false; + } + + return CDF_STATUS_SUCCESS; + } + /* we need to establish implicit QoS */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p", + __func__, acType, pAdapter); + + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = true; + + pQosContext = kmalloc(sizeof(*pQosContext), GFP_ATOMIC); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do but + * let data flow + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Unable to allocate context", __func__); + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = + true; + *pGranted = true; + return CDF_STATUS_SUCCESS; + } + + pQosContext->acType = acType; + pQosContext->pAdapter = pAdapter; + pQosContext->qosFlowId = 0; + pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + pQosContext->is_inactivity_timer_running = false; + +#ifdef CONFIG_CNSS + cnss_init_work(&pQosContext->wmmAcSetupImplicitQos, + hdd_wmm_do_implicit_qos); +#else + INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos); +#endif + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Scheduling work for AC %d, context %p", + __func__, acType, pQosContext); + + schedule_work(&pQosContext->wmmAcSetupImplicitQos); + + /* caller will need to wait until the work takes place and + * TSPEC negotiation completes + */ + *pGranted = false; + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @pAdapter: [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType) +{ + uint8_t uapsdMask; + CDF_STATUS status; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* when we associate we need to notify TL if it needs to + * enable UAPSD for any access categories + */ + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + + if (pRoamInfo->fReassocReq) { + /* when we reassociate we should continue to use + * whatever parameters were previously established. + * if we are reassociating due to a U-APSD change for + * a particular Access Category, then the change will + * be communicated to HDD via the QoS callback + * associated with the given flow, and U-APSD + * parameters will be updated there + */ + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Reassoc so no work, Exiting", __func__); + + return CDF_STATUS_SUCCESS; + } + /* get the negotiated UAPSD Mask */ + uapsdMask = + pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: U-APSD mask is 0x%02x", __func__, (int)uapsdMask); + + if (uapsdMask & HDD_AC_VO) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_VO, 7, 7, + pHddCtx->config->InfraUapsdVoSrvIntv, + pHddCtx->config->InfraUapsdVoSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_VI) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_VI, 5, 5, + pHddCtx->config->InfraUapsdViSrvIntv, + pHddCtx->config->InfraUapsdViSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BK) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_BK, 2, 2, + pHddCtx->config->InfraUapsdBkSrvIntv, + pHddCtx->config->InfraUapsdBkSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BE) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_BE, 3, 3, + pHddCtx->config->InfraUapsdBeSrvIntv, + pHddCtx->config->InfraUapsdBeSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(status)); + } + + status = sme_update_dsc_pto_up_mapping(pHddCtx->hHal, + pAdapter->hddWmmDscpToUpMap, + pAdapter->sessionId); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + hdd_wmm_init(pAdapter); + } + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Exiting", __func__); + + return CDF_STATUS_SUCCESS; +} + +static const uint8_t acm_mask_bit[WLAN_MAX_AC] = { + 0x4, /* SME_AC_BK */ + 0x8, /* SME_AC_BE */ + 0x2, /* SME_AC_VI */ + 0x1 /* SME_AC_VO */ +}; + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @pAdapter : [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType : [in] type of BSS + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType) +{ + int ac; + bool qap; + bool qosConnection; + uint8_t acmMask; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered", __func__); + + if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) && + pRoamInfo && pRoamInfo->u.pConnectedProfile) { + qap = pRoamInfo->u.pConnectedProfile->qap; + qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection; + acmMask = pRoamInfo->u.pConnectedProfile->acm_mask; + } else { + qap = true; + qosConnection = true; + acmMask = 0x0; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: qap is %d, qosConnection is %d, acmMask is 0x%x", + __func__, qap, qosConnection, acmMask); + + pAdapter->hddWmmStatus.wmmQap = qap; + pAdapter->hddWmmStatus.wmmQosConnection = qosConnection; + + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: ac %d on", __func__, ac); + + /* admission is required */ + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessRequired = true; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = false; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessGranted = false; + /* after reassoc if we have valid tspec, allow access */ + if (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcTspecValid + && (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: ac %d off", __func__, ac); + /* admission is not required so access is allowed */ + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessRequired = false; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + + } + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Exiting", __func__); + + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @pAdapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter, + uint8_t *pUapsdMask) +{ + uint8_t uapsdMask; + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) { + /* no QOS then no UAPSD */ + uapsdMask = 0; + } else { + /* start with the default mask */ + uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask; + + /* disable UAPSD for any ACs with a 0 Service Interval */ + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdVoSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VO; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdViSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VI; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdBkSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BK; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdBeSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BE; + } + } + + /* return calculated mask */ + *pUapsdMask = uapsdMask; + return CDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @pAdapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(hdd_adapter_t *pAdapter) +{ + if ((!pAdapter->hddWmmStatus.wmmQosConnection) || + (!pAdapter->hddWmmStatus.wmmQap)) { + return false; + } else { + return true; + } +} + +/** + * hdd_wmm_addts() - Function which will add a traffic spec at the + * request of an application + * + * @pAdapter : [in] pointer to adapter context + * @handle : [in] handle to uniquely identify a TS + * @pTspec : [in] pointer to the traffic spec + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter, + uint32_t handle, + sme_QosWmmTspecInfo *pTspec) +{ + hdd_wmm_qos_context_t *pQosContext; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + bool found = false; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered with handle 0x%x", __func__, handle); + + /* see if a context already exists with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + if (found) { + /* record with that handle already exists */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Record already exists with handle 0x%x", + __func__, handle); + + /* Application is trying to modify some of the Tspec + * params. Allow it + */ + smeStatus = sme_qos_modify_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pTspec, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + break; + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + break; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + break; + default: + /* we didn't get back one of the + * SME_QOS_STATUS_MODIFY_* status codes + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: unexpected SME Status=%d", __func__, + smeStatus); + CDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + } + + /* we were successful, save the status */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; + } + + pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: Unable to allocate QoS context", __func__); + return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE; + } + /* we assume the tspec has already been validated by the caller */ + + pQosContext->handle = handle; + if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE) + pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up]; + else { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: ts_info.up (%d) larger than max value (%d), use default acType (%d)", + __func__, pTspec->ts_info.up, + HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]); + pQosContext->acType = hdd_wmm_up_to_ac_map[0]; + } + pQosContext->pAdapter = pAdapter; + pQosContext->qosFlowId = 0; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: Setting up QoS, context %p", __func__, pQosContext); + + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList); + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + pTspec, + hdd_wmm_sme_callback, + pQosContext, + pTspec->ts_info.up, + &pQosContext->qosFlowId); + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO, + "%s: sme_qos_setup_req returned %d flowid %d", + __func__, smeStatus, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encounterd an internal error + */ + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + default: + /* we didn't get back one of the + * SME_QOS_STATUS_SETUP_* status codes + */ + hdd_wmm_free_context(pQosContext); + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: unexpected SME Status=%d", __func__, smeStatus); + CDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + } +#endif + + /* we were successful, save the status */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; +} + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle) +{ + hdd_wmm_qos_context_t *pQosContext; + bool found = false; + sme_ac_enum_type acType = 0; + uint32_t qosFlowId = 0; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered with handle 0x%x", __func__, handle); + + /* locate the context with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + acType = pQosContext->acType; + qosFlowId = pQosContext->qosFlowId; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + if (false == found) { + /* we didn't find the handle */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: handle 0x%x not found", __func__, handle); + return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: found handle 0x%x, flow %d, AC %d, context %p", + __func__, handle, qosFlowId, acType, pQosContext); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = + sme_qos_release_req(WLAN_HDD_GET_HAL_CTX(pAdapter), qosFlowId); + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: SME flow %d released, SME status %d", + __func__, qosFlowId, smeStatus); + + switch (smeStatus) { + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + /* this flow is the only one on that AC, so go ahead + * and update our TSPEC state for the AC + */ + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid = + false; + + /* need to tell TL to stop trigger timer, etc */ + hdd_wmm_disable_tl_uapsd(pQosContext); + +#ifdef FEATURE_WLAN_ESE + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); +#endif + /* we are done with this context */ + hdd_wmm_free_context(pQosContext); + + /* SME must not fire any more callbacks for this flow + * since the context is no longer valid + */ + + return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + /* do nothing as we will get a response from SME */ + status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING; + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + + default: + /* we didn't get back one of the + * SME_QOS_STATUS_RELEASE_* status codes + */ + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR, + "%s: unexpected SME Status=%d", __func__, smeStatus); + CDF_ASSERT(0); + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + } + +#endif + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; +} + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, uint32_t handle) +{ + hdd_wmm_qos_context_t *pQosContext; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST; + + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: Entered with handle 0x%x", __func__, handle); + + /* locate the context with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW, + "%s: found handle 0x%x, context %p", + __func__, handle, pQosContext); + + status = pQosContext->lastStatus; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + return status; +} diff --git a/core/hdd/src/wlan_hdd_wowl.c b/core/hdd/src/wlan_hdd_wowl.c new file mode 100644 index 0000000000..1c2ff5789a --- /dev/null +++ b/core/hdd/src/wlan_hdd_wowl.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file wlan_hdd_wowl.c + * + * @brief wake up on WLAN API file + */ + +/* Include Files */ + +#include +#include + +/* Preprocessor Definitions and Constants */ +#define WOWL_INTER_PTRN_TOKENIZER ';' +#define WOWL_INTRA_PTRN_TOKENIZER ':' + +/* Type Declarations */ + +static char *g_hdd_wowl_ptrns[WOWL_MAX_PTRNS_ALLOWED]; +static bool g_hdd_wowl_ptrns_debugfs[WOWL_MAX_PTRNS_ALLOWED] = { 0 }; + +static uint8_t g_hdd_wowl_ptrns_count; + +static inline int find_ptrn_len(const char *ptrn) +{ + int len = 0; + while (*ptrn != '\0' && *ptrn != WOWL_INTER_PTRN_TOKENIZER) { + len++; + ptrn++; + } + return len; +} + +static void hdd_wowl_callback(void *pContext, CDF_STATUS cdf_ret_status) +{ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Return code = (%d)", __func__, cdf_ret_status); +} + +#ifdef WLAN_WAKEUP_EVENTS +static void hdd_wowl_wake_indication_callback(void *pContext, + tpSirWakeReasonInd wake_reason_ind) +{ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: Wake Reason %d", + __func__, wake_reason_ind->ulReason); + hdd_exit_wowl((hdd_adapter_t *) pContext); +} +#endif + +/** + * dump_hdd_wowl_ptrn() - log wow patterns + * @ptrn: pointer to wow pattern + * + * Return: none + */ +static void dump_hdd_wowl_ptrn(struct wow_add_pattern *ptrn) +{ + int i; + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Patetrn Id = 0x%x", __func__, ptrn->pattern_id); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: Pattern Byte Offset = 0x%x", __func__, + ptrn->pattern_byte_offset); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: pattern_size = 0x%x", __func__, ptrn->pattern_size); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: pattern_mask_size = 0x%x", __func__, + ptrn->pattern_mask_size); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: Pattern: ", + __func__); + for (i = 0; i < ptrn->pattern_size; i++) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, " %02X", + ptrn->pattern[i]); + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%s: pattern_mask: ", + __func__); + for (i = 0; i < ptrn->pattern_mask_size; i++) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, "%02X", + ptrn->pattern_mask[i]); +} + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn) +{ + struct wow_add_pattern localPattern; + int i, first_empty_slot, len, offset; + CDF_STATUS cdf_ret_status; + const char *temp; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t sessionId = pAdapter->sessionId; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + + len = find_ptrn_len(ptrn); + + /* There has to have at least 1 byte for each field (pattern + * size, mask size, pattern, mask) e.g. PP:QQ:RR:SS ==> 11 + * chars + */ + while (len >= 11) { + /* Detect duplicate pattern */ + for (i = 0; i < pHddCtx->config->maxWoWFilters; i++) { + if (g_hdd_wowl_ptrns[i] == NULL) + continue; + + if (!memcmp(ptrn, g_hdd_wowl_ptrns[i], len)) { + /* Pattern Already configured, skip to + * next pattern + */ + CDF_TRACE(CDF_MODULE_ID_HDD, + CDF_TRACE_LEVEL_ERROR, + "Trying to add duplicate WoWL pattern. Skip it!"); + ptrn += len; + goto next_ptrn; + } + } + + first_empty_slot = -1; + + /* Find an empty slot to store the pattern */ + for (i = 0; i < pHddCtx->config->maxWoWFilters; i++) { + if (g_hdd_wowl_ptrns[i] == NULL) { + first_empty_slot = i; + break; + } + } + + /* Maximum number of patterns have been configured already */ + if (first_empty_slot == -1) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Cannot add anymore patterns. No free slot!", + __func__); + return false; + } + /* Validate the pattern */ + if (ptrn[2] != WOWL_INTRA_PTRN_TOKENIZER || + ptrn[5] != WOWL_INTRA_PTRN_TOKENIZER) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed pattern string. Skip!", + __func__); + ptrn += len; + goto next_ptrn; + } + /* Extract the pattern size */ + localPattern.pattern_size = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + + /* Extract the pattern mask size */ + localPattern.pattern_mask_size = + (hex_to_bin(ptrn[3]) * 0x10) + + hex_to_bin(ptrn[4]); + + if (localPattern.pattern_size > SIR_WOWL_BCAST_PATTERN_MAX_SIZE + || localPattern.pattern_mask_size > + WOWL_PTRN_MASK_MAX_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid length specified. Skip!", + __func__); + ptrn += len; + goto next_ptrn; + } + /* compute the offset of tokenizer after the pattern */ + offset = 5 + 2 * localPattern.pattern_size + 1; + if ((offset >= len) || + (ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed pattern string..skip!", + __func__); + ptrn += len; + goto next_ptrn; + } + /* compute the end of pattern sring */ + offset = offset + 2 * localPattern.pattern_mask_size; + if (offset + 1 != len) { + /* offset begins with 0 */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed pattern string...skip!", + __func__); + ptrn += len; + goto next_ptrn; + } + + temp = ptrn; + + /* Now advance to where pattern begins */ + ptrn += 6; + + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.pattern[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* Skip over the ':' seperator after the pattern */ + ptrn++; + + /* Extract the pattern Mask */ + for (i = 0; i < localPattern.pattern_mask_size; i++) { + localPattern.pattern_mask[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* All is good. Store the pattern locally */ + g_hdd_wowl_ptrns[first_empty_slot] = + kmalloc(len + 1, GFP_KERNEL); + if (g_hdd_wowl_ptrns[first_empty_slot] == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: kmalloc failure", __func__); + return false; + } + + memcpy(g_hdd_wowl_ptrns[first_empty_slot], temp, len); + g_hdd_wowl_ptrns[first_empty_slot][len] = '\0'; + localPattern.pattern_id = first_empty_slot; + localPattern.pattern_byte_offset = 0; + localPattern.session_id = sessionId; + + /* Register the pattern downstream */ + cdf_ret_status = + sme_wow_add_pattern(hHal, &localPattern, + sessionId); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + /* Add failed, so invalidate the local storage */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "sme_wowl_add_bcast_pattern failed with error code (%d)", + cdf_ret_status); + kfree(g_hdd_wowl_ptrns[first_empty_slot]); + g_hdd_wowl_ptrns[first_empty_slot] = NULL; + } + + dump_hdd_wowl_ptrn(&localPattern); + +next_ptrn: + if (*ptrn == WOWL_INTER_PTRN_TOKENIZER) { + /* move past the tokenizer */ + ptrn += 1; + len = find_ptrn_len(ptrn); + continue; + } else + break; + } + + return true; +} + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn) +{ + struct wow_delete_pattern delPattern; + unsigned char id; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + bool patternFound = false; + CDF_STATUS cdf_ret_status; + uint8_t sessionId = pAdapter->sessionId; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + + /* Detect pattern */ + for (id = 0; + id < pHddCtx->config->maxWoWFilters + && g_hdd_wowl_ptrns[id] != NULL; id++) { + if (!strcmp(ptrn, g_hdd_wowl_ptrns[id])) { + patternFound = true; + break; + } + } + + /* If pattern present, remove it from downstream */ + if (patternFound) { + delPattern.pattern_id = id; + delPattern.session_id = sessionId; + cdf_ret_status = + sme_wow_delete_pattern(hHal, &delPattern, + sessionId); + if (CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + /* Remove from local storage as well */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Deleted pattern with id %d [%s]", id, + g_hdd_wowl_ptrns[id]); + + kfree(g_hdd_wowl_ptrns[id]); + g_hdd_wowl_ptrns[id] = NULL; + return true; + } + } + return false; +} + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask) +{ + struct wow_add_pattern localPattern; + CDF_STATUS cdf_ret_status; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t session_id = pAdapter->sessionId; + uint16_t pattern_len, mask_len, i; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern index %d is out of range (0 ~ %d).", + __func__, pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed WoW pattern!", __func__); + + return false; + } else + pattern_len >>= 1; + + if (!pattern_len || pattern_len > WOWL_PTRN_MAX_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern length %d is out of range (1 ~ %d).", + __func__, pattern_len, WOWL_PTRN_MAX_SIZE); + + return false; + } + + localPattern.pattern_id = pattern_idx; + localPattern.pattern_byte_offset = pattern_offset; + localPattern.pattern_size = pattern_len; + localPattern.session_id = session_id; + + if (localPattern.pattern_size > SIR_WOWL_BCAST_PATTERN_MAX_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern size (%d) greater than max (%d)", + __func__, localPattern.pattern_size, + SIR_WOWL_BCAST_PATTERN_MAX_SIZE); + return false; + } + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.pattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Get pattern mask size by pattern length */ + localPattern.pattern_mask_size = pattern_len >> 3; + if (pattern_len % 8) + localPattern.pattern_mask_size += 1; + + mask_len = strlen(pattern_mask); + if ((mask_len % 2) + || (localPattern.pattern_mask_size != (mask_len >> 1))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: Malformed WoW pattern mask!", __func__); + + return false; + } + if (localPattern.pattern_mask_size > WOWL_PTRN_MASK_MAX_SIZE) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern mask size (%d) greater than max (%d)", + __func__, localPattern.pattern_mask_size, + WOWL_PTRN_MASK_MAX_SIZE); + return false; + } + /* Extract the pattern mask */ + for (i = 0; i < localPattern.pattern_mask_size; i++) { + localPattern.pattern_mask[i] = + (hex_to_bin(pattern_mask[0]) << 4) + + hex_to_bin(pattern_mask[1]); + + /* Skip to next byte */ + pattern_mask += 2; + } + + /* Register the pattern downstream */ + cdf_ret_status = + sme_wow_add_pattern(hHal, &localPattern, session_id); + + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_wowl_add_bcast_pattern failed with error code (%d).", + __func__, cdf_ret_status); + + return false; + } + + /* All is good. */ + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 1; + g_hdd_wowl_ptrns_count++; + } + + dump_hdd_wowl_ptrn(&localPattern); + + return true; +} + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx) +{ + struct wow_delete_pattern delPattern; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + CDF_STATUS cdf_ret_status; + uint8_t sessionId = pAdapter->sessionId; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern index %d is not in the range (0 ~ %d).", + __func__, pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: WoW pattern %d is not in the table.", + __func__, pattern_idx); + + return false; + } + + delPattern.pattern_id = pattern_idx; + delPattern.session_id = sessionId; + cdf_ret_status = sme_wow_delete_pattern(hHal, &delPattern, + sessionId); + + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s: sme_wowl_del_bcast_pattern failed with error code (%d).", + __func__, cdf_ret_status); + + return false; + } + + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 0; + g_hdd_wowl_ptrns_count--; + + return true; +} + +/** + * hdd_enter_wowl() - Function which will enable WoWL. At least one + * of MP and PBM must be enabled + * @pAdapter: pointer to the adapter + * @enable_mp: Whether to enable magic packet WoWL mode + * @enable_pbm: Whether to enable pattern byte matching WoWL mode + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_enter_wowl(hdd_adapter_t *pAdapter, bool enable_mp, bool enable_pbm) +{ + tSirSmeWowlEnterParams wowParams; + CDF_STATUS cdf_ret_status; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + + cdf_mem_zero(&wowParams, sizeof(tSirSmeWowlEnterParams)); + + wowParams.ucPatternFilteringEnable = enable_pbm; + wowParams.ucMagicPktEnable = enable_mp; + wowParams.sessionId = pAdapter->sessionId; + if (enable_mp) { + cdf_copy_macaddr((struct cdf_mac_addr *) &(wowParams.magicPtrn), + &(pAdapter->macAddressCurrent)); + } +#ifdef WLAN_WAKEUP_EVENTS + wowParams.ucWoWEAPIDRequestEnable = true; + wowParams.ucWoWEAPOL4WayEnable = true; + wowParams.ucWowNetScanOffloadMatch = true; + wowParams.ucWowGTKRekeyError = true; + wowParams.ucWoWBSSConnLoss = true; +#endif /* WLAN_WAKEUP_EVENTS */ + + /* Request to put Libra into WoWL */ + cdf_ret_status = sme_enter_wowl(hHal, hdd_wowl_callback, pAdapter, +#ifdef WLAN_WAKEUP_EVENTS + hdd_wowl_wake_indication_callback, + pAdapter, +#endif /* WLAN_WAKEUP_EVENTS */ + &wowParams, pAdapter->sessionId); + + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + if (CDF_STATUS_PMC_PENDING != cdf_ret_status) { + /* We failed to enter WoWL */ + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "sme_enter_wowl failed with error code (%d)", + cdf_ret_status); + return false; + } + } + return true; +} + +/** + * hdd_exit_wowl() - Function which will disable WoWL + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_exit_wowl(hdd_adapter_t *pAdapter) +{ + tSirSmeWowlExitParams wowParams; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + CDF_STATUS cdf_ret_status; + + wowParams.sessionId = pAdapter->sessionId; + + cdf_ret_status = sme_exit_wowl(hHal, &wowParams); + if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "sme_exit_wowl failed with error code (%d)", + cdf_ret_status); + return false; + } + + return true; +} + +/** + * hdd_init_wowl() - Init function which will initialize the WoWL module + * and perform any required initial configuration + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_init_wowl(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = NULL; + pHddCtx = pAdapter->pHddCtx; + + memset(g_hdd_wowl_ptrns, 0, sizeof(g_hdd_wowl_ptrns)); + g_hdd_wowl_ptrns_count = 0; + + /* Add any statically configured patterns */ + hdd_add_wowl_ptrn(pAdapter, pHddCtx->config->wowlPattern); + + return true; +} diff --git a/core/hif/inc/hif.h b/core/hif/inc/hif.h new file mode 100644 index 0000000000..0c9a41318a --- /dev/null +++ b/core/hif/inc/hif.h @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HIF_H_ +#define _HIF_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Header files */ +#include "athdefs.h" +#include "a_types.h" +#include "osapi_linux.h" +#include "cdf_status.h" +#include "cdf_nbuf.h" +#include "ol_if_athvar.h" +#include +#ifdef HIF_PCI +#include +#endif /* HIF_PCI */ + +#define ENABLE_MBOX_DUMMY_SPACE_FEATURE 1 + +typedef struct htc_callbacks HTC_CALLBACKS; +typedef void __iomem *A_target_id_t; + +#define HIF_TYPE_AR6002 2 +#define HIF_TYPE_AR6003 3 +#define HIF_TYPE_AR6004 5 +#define HIF_TYPE_AR9888 6 +#define HIF_TYPE_AR6320 7 +#define HIF_TYPE_AR6320V2 8 +/* For attaching Peregrine 2.0 board host_reg_tbl only */ +#define HIF_TYPE_AR9888V2 8 +#define HIF_TYPE_QCA6180 9 +#define HIF_TYPE_ADRASTEA 10 + +#define TARGET_TYPE_UNKNOWN 0 +#define TARGET_TYPE_AR6001 1 +#define TARGET_TYPE_AR6002 2 +#define TARGET_TYPE_AR6003 3 +#define TARGET_TYPE_AR6004 5 +#define TARGET_TYPE_AR6006 6 +#define TARGET_TYPE_AR9888 7 +#define TARGET_TYPE_AR6320 8 +#define TARGET_TYPE_AR900B 9 +/* For attach Peregrine 2.0 board target_reg_tbl only */ +#define TARGET_TYPE_AR9888V2 10 +/* For attach Rome1.0 target_reg_tbl only*/ +#define TARGET_TYPE_AR6320V1 11 +/* For Rome2.0/2.1 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V2 12 +/* For Rome3.0 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V3 13 +/* For Tufello1.0 target_reg_tbl ID*/ +#define TARGET_TYPE_QCA9377V1 14 +/* For QCA6180 target */ +#define TARGET_TYPE_QCA6180 15 +/* For Adrastea target */ +#define TARGET_TYPE_ADRASTEA 16 + +struct CE_state; +#define CE_COUNT_MAX 8 + +/* These numbers are selected so that the product is close to current + higher limit of packets HIF services at one shot (1000) */ +#define QCA_NAPI_BUDGET 64 +#define QCA_NAPI_DEF_SCALE 16 +/* NOTE: This is to adapt non-NAPI solution to use + the same "budget" as NAPI. Will be removed + `once decision about NAPI is made */ +#define HIF_NAPI_MAX_RECEIVES (QCA_NAPI_BUDGET * QCA_NAPI_DEF_SCALE) + +/* NOTE: "napi->scale" can be changed, + but this does not change the number of buckets */ +#define QCA_NAPI_NUM_BUCKETS (QCA_NAPI_BUDGET / QCA_NAPI_DEF_SCALE) +struct qca_napi_stat { + uint32_t napi_schedules; + uint32_t napi_polls; + uint32_t napi_completes; + uint32_t napi_workdone; + uint32_t napi_budget_uses[QCA_NAPI_NUM_BUCKETS]; +}; + +/** + * per NAPI instance data structure + * This data structure holds stuff per NAPI instance. + * Note that, in the current implementation, though scale is + * an instance variable, it is set to the same value for all + * instances. + */ +struct qca_napi_info { + struct napi_struct napi; /* one NAPI Instance per CE in phase I */ + uint8_t scale; /* currently same on all instances */ + uint8_t id; + struct qca_napi_stat stats[NR_CPUS]; +}; + +/** + * NAPI data-sructure common to all NAPI instances. + * + * A variable of this type will be stored in hif module context. + */ + +struct qca_napi_data { + /* NOTE: make sure the mutex is inited only at the very beginning + once for the lifetime of the driver. For now, granularity of one + is OK, but we might want to have a better granularity later */ + struct mutex mutex; + uint32_t state; + uint32_t ce_map; /* bitmap of created/registered NAPI + instances, indexed by pipe_id, + not used by clients (clients use an + id returned by create) */ + struct net_device netdev; /* dummy net_dev */ + struct qca_napi_info napis[CE_COUNT_MAX]; +}; + +struct ol_softc { + void __iomem *mem; /* IO mapped memory base address */ + cdf_dma_addr_t mem_pa; + uint32_t soc_version; + /* + * handle for code that uses the osdep.h version of OS + * abstraction primitives + */ + struct _NIC_DEV aps_osdev; + enum ath_hal_bus_type bus_type; + uint32_t lcr_val; + bool pkt_log_init; + bool request_irq_done; + /* + * handle for code that uses cdf version of OS + * abstraction primitives + */ + cdf_device_t cdf_dev; + + struct ol_version version; + + /* Packet statistics */ + struct ol_ath_stats pkt_stats; + + /* A_TARGET_TYPE_* */ + uint32_t target_type; + uint32_t target_fw_version; + uint32_t target_version; + uint32_t target_revision; + uint8_t crm_version_string[64]; + uint8_t wlan_version_string[64]; + ol_target_status target_status; + bool is_sim; + /* calibration data is stored in flash */ + uint8_t *cal_in_flash; + /* virtual address for the calibration data on the flash */ + void *cal_mem; + /* status of target init */ + WLAN_INIT_STATUS wlan_init_status; + + /* BMI info */ + /* OS-dependent private info for BMI */ + void *bmi_ol_priv; + bool bmi_done; + bool bmi_ua_done; + uint8_t *bmi_cmd_buff; + dma_addr_t bmi_cmd_da; + OS_DMA_MEM_CONTEXT(bmicmd_dmacontext) + + uint8_t *bmi_rsp_buff; + dma_addr_t bmi_rsp_da; + /* length of last response */ + uint32_t last_rxlen; + OS_DMA_MEM_CONTEXT(bmirsp_dmacontext) + + void *msi_magic; + dma_addr_t msi_magic_da; + OS_DMA_MEM_CONTEXT(msi_dmacontext) + + /* Handles for Lower Layers : filled in at init time */ + hif_handle_t hif_hdl; +#ifdef HIF_PCI + struct hif_pci_softc *hif_sc; +#endif + +#ifdef WLAN_FEATURE_FASTPATH + int fastpath_mode_on; /* Duplicating this for data path efficiency */ +#endif /* WLAN_FEATURE_FASTPATH */ + + /* HTC handles */ + void *htc_handle; + + bool fEnableBeaconEarlyTermination; + uint8_t bcnEarlyTermWakeInterval; + + /* UTF event information */ + struct { + uint8_t *data; + uint32_t length; + cdf_size_t offset; + uint8_t currentSeq; + uint8_t expectedSeq; + } utf_event_info; + + struct ol_wow_info *scn_wowInfo; + /* enable uart/serial prints from target */ + bool enableuartprint; + /* enable fwlog */ + bool enablefwlog; + + HAL_REG_CAPABILITIES hal_reg_capabilities; + struct ol_regdmn *ol_regdmn_handle; + uint8_t bcn_mode; + uint8_t arp_override; + /* + * Includes host side stack level stats + + * radio level athstats + */ + struct wlan_dbg_stats ath_stats; + /* noise_floor */ + int16_t chan_nf; + uint32_t min_tx_power; + uint32_t max_tx_power; + uint32_t txpowlimit2G; + uint32_t txpowlimit5G; + uint32_t txpower_scale; + uint32_t chan_tx_pwr; + uint32_t vdev_count; + uint32_t max_bcn_ie_size; + cdf_spinlock_t scn_lock; + uint8_t vow_extstats; + /* if dcs enabled or not */ + uint8_t scn_dcs; + wdi_event_subscribe scn_rx_peer_invalid_subscriber; + uint8_t proxy_sta; + uint8_t bcn_enabled; + /* Dynamic Tx Chainmask Selection enabled/disabled */ + uint8_t dtcs; + /* true if vht ies are set on target */ + uint32_t set_ht_vht_ies:1; + /*CWM enable/disable state */ + bool scn_cwmenable; + uint8_t max_no_of_peers; +#ifdef CONFIG_CNSS + struct cnss_fw_files fw_files; +#endif +#if defined(CONFIG_CNSS) + void *ramdump_base; + unsigned long ramdump_address; + unsigned long ramdump_size; +#endif + bool enable_self_recovery; +#ifdef WLAN_FEATURE_LPSS + bool enablelpasssupport; +#endif + bool enable_ramdump_collection; + struct targetdef_s *targetdef; + struct ce_reg_def *target_ce_def; + struct hostdef_s *hostdef; + struct host_shadow_regs_s *host_shadow_regs; + bool athdiag_procfs_inited; + /* + * Guard changes to Target HW state and to software + * structures that track hardware state. + */ + cdf_spinlock_t target_lock; + unsigned int ce_count; /* Number of Copy Engines supported */ + bool force_break; /* Flag to indicate whether to + * break out the DPC context */ + unsigned int receive_count; /* count Num Of Receive Buffers + * handled for one interrupt + * DPC routine */ + struct CE_state *ce_id_to_state[CE_COUNT_MAX]; /* CE id to CE_state */ +#ifdef FEATURE_NAPI + struct qca_napi_data napi_data; +#endif /* FEATURE_NAPI */ + int htc_endpoint; + bool recovery; + bool hif_init_done; + int linkstate_vote; + atomic_t link_suspended; + atomic_t wow_done; + atomic_t tasklet_from_intr; + atomic_t active_tasklet_cnt; + bool notice_send; +#ifdef HIF_PCI + cdf_spinlock_t irq_lock; + uint32_t ce_irq_summary; +#endif +}; + +typedef enum { + HIF_DEVICE_POWER_UP, /* HIF layer should power up interface + * and/or module */ + HIF_DEVICE_POWER_DOWN, /* HIF layer should initiate bus-specific + * measures to minimize power */ + HIF_DEVICE_POWER_CUT /* HIF layer should initiate bus-specific + * AND/OR platform-specific measures + * to completely power-off the module and + * associated hardware (i.e. cut power + * supplies) */ +} HIF_DEVICE_POWER_CHANGE_TYPE; + +/** + * enum hif_enable_type: what triggered the enabling of hif + * + * @HIF_ENABLE_TYPE_PROBE: probe triggered enable + * @HIF_ENABLE_TYPE_REINIT: reinit triggered enable + */ +enum hif_enable_type { + HIF_ENABLE_TYPE_PROBE, + HIF_ENABLE_TYPE_REINIT, + HIF_ENABLE_TYPE_MAX +}; + +/** + * enum hif_disable_type: what triggered the disabling of hif + * + * @HIF_DISABLE_TYPE_PROBE_ERROR: probe error triggered disable + * @HIF_DISABLE_TYPE_REINIT_ERROR: reinit error triggered + * disable + * @HIF_DISABLE_TYPE_REMOVE: remove triggered disable + * @HIF_DISABLE_TYPE_SHUTDOWN: shutdown triggered disable + */ +enum hif_disable_type { + HIF_DISABLE_TYPE_PROBE_ERROR, + HIF_DISABLE_TYPE_REINIT_ERROR, + HIF_DISABLE_TYPE_REMOVE, + HIF_DISABLE_TYPE_SHUTDOWN, + HIF_DISABLE_TYPE_MAX +}; + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +typedef struct _HID_ACCESS_LOG { + uint32_t seqnum; + bool is_write; + void *addr; + uint32_t value; +} HIF_ACCESS_LOG; +#endif + +#define HIF_MAX_DEVICES 1 + +struct htc_callbacks { + void *context; /* context to pass to the dsrhandler + * note : rwCompletionHandler is provided + * the context passed to hif_read_write */ + int (*rwCompletionHandler)(void *rwContext, int status); + int (*dsrHandler)(void *context); +}; + +typedef struct osdrv_callbacks { + void *context; /* context to pass for all callbacks + * except deviceRemovedHandler + * the deviceRemovedHandler is only + * called if the device is claimed */ + int (*deviceInsertedHandler)(void *context, void *hif_handle); + int (*deviceRemovedHandler)(void *claimedContext, + void *hif_handle); + int (*deviceSuspendHandler)(void *context); + int (*deviceResumeHandler)(void *context); + int (*deviceWakeupHandler)(void *context); + int (*devicePowerChangeHandler)(void *context, + HIF_DEVICE_POWER_CHANGE_TYPE + config); +} OSDRV_CALLBACKS; + +/* + * This API is used to perform any global initialization of the HIF layer + * and to set OS driver callbacks (i.e. insertion/removal) to the HIF layer + * + */ +int hif_init(OSDRV_CALLBACKS *callbacks); + +/* + * This API claims the HIF device and provides a context for handling removal. + * The device removal callback is only called when the OSDRV layer claims + * a device. The claimed context must be non-NULL */ +void hif_claim_device(struct ol_softc *scn, void *claimedContext); +/* release the claimed device */ +void hif_release_device(struct ol_softc *scn); + +/* This API detaches the HTC layer from the HIF device */ +void hif_detach_htc(struct ol_softc *scn); + +/****************************************************************/ +/* BMI and Diag window abstraction */ +/****************************************************************/ + +#define HIF_BMI_EXCHANGE_NO_TIMEOUT ((uint32_t)(0)) + +#define DIAG_TRANSFER_LIMIT 2048U /* maximum number of bytes that can be + * handled atomically by + * DiagRead/DiagWrite */ + +/* + * API to handle HIF-specific BMI message exchanges, this API is synchronous + * and only allowed to be called from a context that can block (sleep) */ +CDF_STATUS hif_exchange_bmi_msg(struct ol_softc *scn, + uint8_t *pSendMessage, + uint32_t Length, + uint8_t *pResponseMessage, + uint32_t *pResponseLength, uint32_t TimeoutMS); + +/* + * APIs to handle HIF specific diagnostic read accesses. These APIs are + * synchronous and only allowed to be called from a context that + * can block (sleep). They are not high performance APIs. + * + * hif_diag_read_access reads a 4 Byte aligned/length value from a + * Target register or memory word. + * + * hif_diag_read_mem reads an arbitrary length of arbitrarily aligned memory. + */ +CDF_STATUS hif_diag_read_access(struct ol_softc *scn, uint32_t address, + uint32_t *data); +CDF_STATUS hif_diag_read_mem(struct ol_softc *scn, uint32_t address, + uint8_t *data, int nbytes); +void hif_dump_target_memory(struct ol_softc *scn, void *ramdump_base, + uint32_t address, uint32_t size); +/* + * APIs to handle HIF specific diagnostic write accesses. These APIs are + * synchronous and only allowed to be called from a context that + * can block (sleep). + * They are not high performance APIs. + * + * hif_diag_write_access writes a 4 Byte aligned/length value to a + * Target register or memory word. + * + * hif_diag_write_mem writes an arbitrary length of arbitrarily aligned memory. + */ +CDF_STATUS hif_diag_write_access(struct ol_softc *scn, uint32_t address, + uint32_t data); +CDF_STATUS hif_diag_write_mem(struct ol_softc *scn, uint32_t address, + uint8_t *data, int nbytes); + +/* + * Set the FASTPATH_mode_on flag in sc, for use by data path + */ +#ifdef WLAN_FEATURE_FASTPATH +void hif_enable_fastpath(struct ol_softc *hif_dev); +#endif + +#if defined(HIF_PCI) && !defined(A_SIMOS_DEVHOST) +/* + * This API allows the Host to access Target registers of a given + * A_target_id_t directly and relatively efficiently over PCIe. + * This allows the Host to avoid extra overhead associated with + * sending a message to firmware and waiting for a response message + * from firmware, as is done on other interconnects. + * + * Yet there is some complexity with direct accesses because the + * Target's power state is not known a priori. The Host must issue + * special PCIe reads/writes in order to explicitly wake the Target + * and to verify that it is awake and will remain awake. + * + * NB: Host endianness conversion is left for the caller to handle. + * These interfaces handle access; not interpretation. + * + * Usage: + * During initialization, use A_TARGET_ID to obtain an 'target ID' + * for use with these interfaces. + * + * Use A_TARGET_READ and A_TARGET_WRITE to access Target space. + * These calls must be bracketed by A_TARGET_ACCESS_BEGIN and + * A_TARGET_ACCESS_END. A single BEGIN/END pair is adequate for + * multiple READ/WRITE operations. + * + * Use A_TARGET_ACCESS_BEGIN to put the Target in a state in + * which it is legal for the Host to directly access it. This + * may involve waking the Target from a low power state, which + * may take up to 2Ms! + * + * Use A_TARGET_ACCESS_END to tell the Target that as far as + * this code path is concerned, it no longer needs to remain + * directly accessible. BEGIN/END is under a reference counter; + * multiple code paths may issue BEGIN/END on a single targid. + * + * For added efficiency, the Host may use A_TARGET_ACCESS_LIKELY. + * The LIKELY interface works just like A_TARGET_ACCESS_BEGIN, + * except that it may return before the Target is actually + * available. It's a vague indication that some Target accesses + * are expected "soon". When the LIKELY API is used, + * A_TARGET_ACCESS_BEGIN must be used before any access. + * + * There are several uses for the LIKELY/UNLIKELY API: + * -If there is some potential time before Target accesses + * and we want to get a head start on waking the Target + * (e.g. to overlap Target wake with Host-side malloc) + * -High-level code knows that it will call low-level + * functions that will use BEGIN/END, and we don't want + * to allow the Target to sleep until the entire sequence + * has completed. + * + * A_TARGET_ACCESS_OK verifies that the Target can be + * accessed. In general, this should not be needed, but it + * may be useful for debugging or for special uses. + * + * Note that there must be a matching END for each BEGIN + * AND there must be a matching UNLIKELY for each LIKELY! + * + * NB: This API is designed to allow some flexibility in tradeoffs + * between Target power utilization and Host efficiency and + * system performance. + */ + +/* + * Enable/disable CDC max performance workaround + * For max-performace set this to 0 + * To allow SoC to enter sleep set this to 1 + */ +#define CONFIG_DISABLE_CDC_MAX_PERF_WAR 0 +#endif + +#ifdef IPA_OFFLOAD +/* + * IPA micro controller data path offload feature enabled, + * HIF should release copy engine related resource information to IPA UC + * IPA UC will access hardware resource with released information + */ +void hif_ipa_get_ce_resource(struct ol_softc *scn, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr); +#else +static inline void hif_ipa_get_ce_resource(struct ol_softc *scn, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr) +{ + return; +} +#endif /* IPA_OFFLOAD */ + + +void hif_read_phy_mem_base(struct ol_softc *scn, + cdf_dma_addr_t *bar_value); + +/** + * @brief List of callbacks - filled in by HTC. + */ +struct hif_msg_callbacks { + void *Context; + /**< context meaningful to HTC */ + CDF_STATUS (*txCompletionHandler)(void *Context, cdf_nbuf_t wbuf, + uint32_t transferID, + uint32_t toeplitz_hash_result); + CDF_STATUS (*rxCompletionHandler)(void *Context, cdf_nbuf_t wbuf, + uint8_t pipeID); + void (*txResourceAvailHandler)(void *context, uint8_t pipe); + void (*fwEventHandler)(void *context, CDF_STATUS status); +}; + +#define HIF_DATA_ATTR_SET_TX_CLASSIFY(attr, v) \ + (attr |= (v & 0x01) << 5) +#define HIF_DATA_ATTR_SET_ENCAPSULATION_TYPE(attr, v) \ + (attr |= (v & 0x03) << 6) +#define HIF_DATA_ATTR_SET_ADDR_X_SEARCH_DISABLE(attr, v) \ + (attr |= (v & 0x01) << 13) +#define HIF_DATA_ATTR_SET_ADDR_Y_SEARCH_DISABLE(attr, v) \ + (attr |= (v & 0x01) << 14) +#define HIF_DATA_ATTR_SET_TOEPLITZ_HASH_ENABLE(attr, v) \ + (attr |= (v & 0x01) << 15) +#define HIF_DATA_ATTR_SET_PACKET_OR_RESULT_OFFSET(attr, v) \ + (attr |= (v & 0x0FFF) << 16) +#define HIF_DATA_ATTR_SET_ENABLE_11H(attr, v) \ + (attr |= (v & 0x01) << 30) + +#ifdef HIF_PCI +typedef struct pci_device_id hif_bus_id; +#else +typedef struct device hif_bus_id; +#endif + +void hif_post_init(struct ol_softc *scn, void *hHTC, + struct hif_msg_callbacks *callbacks); +CDF_STATUS hif_start(struct ol_softc *scn); +void hif_stop(struct ol_softc *scn); +void hif_flush_surprise_remove(struct ol_softc *scn); +void hif_dump(struct ol_softc *scn, uint8_t CmdId, bool start); +CDF_STATUS hif_send_head(struct ol_softc *scn, uint8_t PipeID, + uint32_t transferID, uint32_t nbytes, + cdf_nbuf_t wbuf, uint32_t data_attr); +void hif_send_complete_check(struct ol_softc *scn, uint8_t PipeID, + int force); +void hif_cancel_deferred_target_sleep(struct ol_softc *scn); +void hif_get_default_pipe(struct ol_softc *scn, uint8_t *ULPipe, + uint8_t *DLPipe); +int hif_map_service_to_pipe(struct ol_softc *scn, uint16_t ServiceId, + uint8_t *ULPipe, uint8_t *DLPipe, + int *ul_is_polled, int *dl_is_polled); +uint16_t hif_get_free_queue_number(struct ol_softc *scn, uint8_t PipeID); +void *hif_get_targetdef(struct ol_softc *scn); +void hi_fsuspendwow(struct ol_softc *scn); +uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset); +void hif_set_target_sleep(struct ol_softc *scn, bool sleep_ok, + bool wait_for_it); +int hif_check_fw_reg(struct ol_softc *scn); +int hif_check_soc_status(struct ol_softc *scn); +void dump_ce_debug_register(struct ol_softc *scn); +void hif_get_hw_info(void *scn, u32 *version, u32 *revision, + const char **target_name); +void hif_set_fw_info(void *scn, u32 target_fw_version); +void hif_disable_isr(void *scn); +void hif_reset_soc(void *scn); +void hif_disable_aspm(void); +void hif_save_htc_htt_config_endpoint(int htc_endpoint); +CDF_STATUS hif_open(void); +void hif_close(void *hif_ctx); +CDF_STATUS hif_enable(void *hif_ctx, struct device *dev, void *bdev, + const hif_bus_id *bid, enum ath_hal_bus_type bus_type, + enum hif_enable_type type); +void hif_disable(void *hif_ctx, enum hif_disable_type type); +void hif_enable_power_gating(void *hif_ctx); +int hif_bus_resume(void); +int hif_bus_suspend(void); +void hif_vote_link_down(void); +void hif_vote_link_up(void); +bool hif_can_suspend_link(void); +int dump_ce_register(struct ol_softc *scn); +int ol_copy_ramdump(struct ol_softc *scn); +void hif_pktlogmod_exit(void *hif_ctx); +void hif_crash_shutdown(void *hif_ctx); +#ifdef __cplusplus +} +#endif +#endif /* _HIF_H_ */ diff --git a/core/hif/inc/hif_napi.h b/core/hif/inc/hif_napi.h new file mode 100644 index 0000000000..c6f817f314 --- /dev/null +++ b/core/hif/inc/hif_napi.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_NAPI_H__ +#define __HIF_NAPI_H__ + +/** + * DOC: hif_napi.h + * + * Interface to HIF implemented functions of NAPI. + * These are used by hdd_napi. + */ + + +/* CLD headers */ +#include /* struct ol_softc; */ + +/** + * common stuff + * The declarations until #ifdef FEATURE_NAPI below + * are valid whether or not FEATURE_NAPI has been + * defined. + */ + +/* the following triggers napi_enable/disable as required */ +enum qca_napi_event { + NAPI_EVT_INVALID, + NAPI_EVT_INI_FILE, + NAPI_EVT_CMD_STATE /* ioctl enable/disable commands */ +}; + +/** + * Macros to map ids -returned by ...create()- to pipes and vice versa + */ +#define NAPI_ID2PIPE(i) ((i)-1) +#define NAPI_PIPE2ID(p) ((p)+1) + + +#ifdef FEATURE_NAPI + +/** + * NAPI HIF API + * + * the declarations below only apply to the case + * where FEATURE_NAPI is defined + */ + +int hif_napi_create(struct ol_softc *hif, + uint8_t pipe_id, + int (*poll)(struct napi_struct *, int), + int budget, + int scale); +int hif_napi_destroy(struct ol_softc *hif, + uint8_t id, + int force); + +struct qca_napi_data *hif_napi_get_all(struct ol_softc *hif); + +int hif_napi_event(struct ol_softc *hif, + enum qca_napi_event event, + void *data); + +/* called from the ISR within hif, so, ce is known */ +int hif_napi_enabled(struct ol_softc *hif, int ce); + +/* called from hdd (napi_poll), using napi id as a selector */ +void hif_napi_enable_irq(struct ol_softc *hif, int id); + +/* called by ce_tasklet.c::ce_irq_handler */ +int hif_napi_schedule(struct ol_softc *scn, int ce_id); + +/* called by hdd_napi, which is called by kernel */ +int hif_napi_poll(struct napi_struct *napi, int budget); + +#ifdef FEATURE_NAPI_DEBUG +#define NAPI_DEBUG(fmt, ...) \ + cdf_print("wlan: NAPI: %s:%d "fmt, __func__, __LINE__, ##__VA_ARGS__); +#else +#define NAPI_DEBUG(fmt, ...) /* NO-OP */ +#endif /* FEATURE NAPI_DEBUG */ + +#else /* ! defined(FEATURE_NAPI) */ + +/** + * Stub API + * + * The declarations in this section are valid only + * when FEATURE_NAPI has *not* been defined. + */ + +#define NAPI_DEBUG(fmt, ...) /* NO-OP */ + +static inline int hif_napi_create(struct ol_softc *hif, + uint8_t pipe_id, + int (*poll)(struct napi_struct *, int), + int budget, + int scale) +{ return -EPERM; } + +static inline int hif_napi_destroy(struct ol_softc *hif, + uint8_t id, + int force) +{ return -EPERM; } + +static inline struct qca_napi_data *hif_napi_get_all(struct ol_softc *hif) +{ return NULL; } + +static inline int hif_napi_event(struct ol_softc *hif, + enum qca_napi_event event, + void *data) +{ return -EPERM; } + +/* called from the ISR within hif, so, ce is known */ +static inline int hif_napi_enabled(struct ol_softc *hif, int ce) +{ return 0; } + +/* called from hdd (napi_poll), using napi id as a selector */ +static inline void hif_napi_enable_irq(struct ol_softc *hif, int id) +{ return; } + +static inline int hif_napi_schedule(struct ol_softc *hif, int ce_id) +{ return 0; } + +static inline int hif_napi_poll(struct napi_struct *napi, int budget) +{ return -EPERM; } + +#endif /* FEATURE_NAPI */ + +#endif /* __HIF_NAPI_H__ */ diff --git a/core/hif/inc/regtable.h b/core/hif/inc/regtable.h new file mode 100644 index 0000000000..2aae9e8d89 --- /dev/null +++ b/core/hif/inc/regtable.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _REGTABLE_H_ +#define _REGTABLE_H_ + +#include "regtable_pcie.h" +#include "regtable_ce.h" +#endif diff --git a/core/hif/inc/regtable_ce.h b/core/hif/inc/regtable_ce.h new file mode 100644 index 0000000000..e5f5a9f10c --- /dev/null +++ b/core/hif/inc/regtable_ce.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _REGTABLE_CE_H_ +#define _REGTABLE_CE_H_ + +/* + * @d_DST_WR_INDEX_ADDRESS: Destination ring write index + * + * @d_SRC_WATERMARK_ADDRESS: Source ring watermark + * + * @d_SRC_WATERMARK_LOW_MASK: Bits indicating low watermark from Source ring + * watermark + * + * @d_SRC_WATERMARK_HIGH_MASK: Bits indicating high watermark from Source ring + * watermark + * + * @d_DST_WATERMARK_LOW_MASK: Bits indicating low watermark from Destination + * ring watermark + * + * @d_DST_WATERMARK_HIGH_MASK: Bits indicating high watermark from Destination + * ring watermark + * + * @d_CURRENT_SRRI_ADDRESS: Current source ring read index.The Start Offset + * will be reflected after a CE transfer is completed. + * + * @d_CURRENT_DRRI_ADDRESS: Current Destination ring read index. The Start + * Offset will be reflected after a CE transfer + * is completed. + * + * @d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK: Source ring high watermark + * Interrupt Status + * + * @d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK: Source ring low watermark + * Interrupt Status + * + * @d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK: Destination ring high watermark + * Interrupt Status + * + * @d_HOST_IS_DST_RING_LOW_WATERMARK_MASK: Source ring low watermark + * Interrupt Status + * + * @d_HOST_IS_ADDRESS: Host Interrupt Status Register + * + * @d_MISC_IS_ADDRESS: Miscellaneous Interrupt Status Register + * + * @d_HOST_IS_COPY_COMPLETE_MASK: Bits indicating Copy complete interrupt + * status from the Host Interrupt Status + * register + * + * @d_CE_WRAPPER_BASE_ADDRESS: Copy Engine Wrapper Base Address + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS: CE Wrapper summary for interrupts + * to host + * + * @d_CE_WRAPPER_INDEX_BASE_LOW: The LSB Base address to which source and + * destination read indices are written + * + * @d_CE_WRAPPER_INDEX_BASE_HIGH: The MSB Base address to which source and + * destination read indices are written + * + * @d_HOST_IE_ADDRESS: Host Line Interrupt Enable Register + * + * @d_HOST_IE_COPY_COMPLETE_MASK: Bits indicating Copy complete interrupt + * enable from the IE register + * + * @d_SR_BA_ADDRESS: LSB of Source Ring Base Address + * + * @d_SR_BA_ADDRESS_HIGH: MSB of Source Ring Base Address + * + * @d_SR_SIZE_ADDRESS: Source Ring size - number of entries and Start Offset + * + * @d_CE_CTRL1_ADDRESS: CE Control register + * + * @d_CE_CTRL1_DMAX_LENGTH_MASK: Destination buffer Max Length used for error + * check + * + * @d_DR_BA_ADDRESS: Destination Ring Base Address Low + * + * @d_DR_BA_ADDRESS_HIGH: Destination Ring Base Address High + * + * @d_DR_SIZE_ADDRESS: Destination Ring size - number of entries Start Offset + * + * @d_CE_CMD_REGISTER: Implements commands to all CE Halt Flush + * + * @d_CE_MSI_ADDRESS: CE MSI LOW Address register + * + * @d_CE_MSI_ADDRESS_HIGH: CE MSI High Address register + * + * @d_CE_MSI_DATA: CE MSI Data Register + * + * @d_CE_MSI_ENABLE_BIT: Bit in CTRL1 register indication the MSI enable + * + * @d_MISC_IE_ADDRESS: Miscellaneous Interrupt Enable Register + * + * @d_MISC_IS_AXI_ERR_MASK: Bit in Misc IS indicating AXI Timeout Interrupt + * status + * + * @d_MISC_IS_DST_ADDR_ERR_MASK: Bit in Misc IS indicating Destination Address + * Error + * + * @d_MISC_IS_SRC_LEN_ERR_MASK: Bit in Misc IS indicating Source Zero Length + * Error Interrupt status + * + * @d_MISC_IS_DST_MAX_LEN_VIO_MASK: Bit in Misc IS indicating Destination Max + * Length Violated Interrupt status + * + * @d_MISC_IS_DST_RING_OVERFLOW_MASK: Bit in Misc IS indicating Destination + * Ring Overflow Interrupt status + * + * @d_MISC_IS_SRC_RING_OVERFLOW_MASK: Bit in Misc IS indicating Source Ring + * Overflow Interrupt status + * + * @d_SRC_WATERMARK_LOW_LSB: Source Ring Low Watermark LSB + * + * @d_SRC_WATERMARK_HIGH_LSB: Source Ring Low Watermark MSB + * + * @d_DST_WATERMARK_LOW_LSB: Destination Ring Low Watermark LSB + * + * @d_DST_WATERMARK_HIGH_LSB: Destination Ring High Watermark LSB + * + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK: Bits in + * d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDR + * indicating Copy engine + * miscellaneous interrupt summary + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB:Bits in + * d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDR + * indicating Host interrupts summary + * + * @d_CE_CTRL1_DMAX_LENGTH_LSB: LSB of Destination buffer Max Length used for + * error check + * + * @d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK: Bits indicating Source ring Byte Swap + * enable. Treats source ring memory + * organisation as big-endian + * + * @d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK: Bits indicating Destination ring + * byte swap enable. Treats destination + * ring memory organisation as big-endian + * + * @d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB: LSB of Source ring Byte Swap enable + * + * @d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB: LSB of Destination ring Byte Swap enable + * + * @d_CE_WRAPPER_DEBUG_OFFSET: Offset of CE OBS BUS Select register + * + * @d_CE_WRAPPER_DEBUG_SEL_MSB: MSB of Control register selecting inputs for + * trace/debug + * + * @d_CE_WRAPPER_DEBUG_SEL_LSB: LSB of Control register selecting inputs for + * trace/debug + * + * @d_CE_WRAPPER_DEBUG_SEL_MASK: Bits indicating Control register selecting + * inputs for trace/debug + * + * @d_CE_DEBUG_OFFSET: Offset of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_MSB: MSB of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_LSB: LSB of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_MASK: Bits indicating Copy Engine FSM Debug Status + * +*/ + +struct ce_reg_def { + /* copy_engine.c */ + uint32_t d_DST_WR_INDEX_ADDRESS; + uint32_t d_SRC_WATERMARK_ADDRESS; + uint32_t d_SRC_WATERMARK_LOW_MASK; + uint32_t d_SRC_WATERMARK_HIGH_MASK; + uint32_t d_DST_WATERMARK_LOW_MASK; + uint32_t d_DST_WATERMARK_HIGH_MASK; + uint32_t d_CURRENT_SRRI_ADDRESS; + uint32_t d_CURRENT_DRRI_ADDRESS; + uint32_t d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_ADDRESS; + uint32_t d_MISC_IS_ADDRESS; + uint32_t d_HOST_IS_COPY_COMPLETE_MASK; + uint32_t d_CE_WRAPPER_BASE_ADDRESS; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS; + uint32_t d_CE_WRAPPER_INDEX_BASE_LOW; + uint32_t d_CE_WRAPPER_INDEX_BASE_HIGH; + uint32_t d_HOST_IE_ADDRESS; + uint32_t d_HOST_IE_COPY_COMPLETE_MASK; + uint32_t d_SR_BA_ADDRESS; + uint32_t d_SR_BA_ADDRESS_HIGH; + uint32_t d_SR_SIZE_ADDRESS; + uint32_t d_CE_CTRL1_ADDRESS; + uint32_t d_CE_CTRL1_DMAX_LENGTH_MASK; + uint32_t d_DR_BA_ADDRESS; + uint32_t d_DR_BA_ADDRESS_HIGH; + uint32_t d_DR_SIZE_ADDRESS; + uint32_t d_CE_CMD_REGISTER; + uint32_t d_CE_MSI_ADDRESS; + uint32_t d_CE_MSI_ADDRESS_HIGH; + uint32_t d_CE_MSI_DATA; + uint32_t d_CE_MSI_ENABLE_BIT; + uint32_t d_MISC_IE_ADDRESS; + uint32_t d_MISC_IS_AXI_ERR_MASK; + uint32_t d_MISC_IS_DST_ADDR_ERR_MASK; + uint32_t d_MISC_IS_SRC_LEN_ERR_MASK; + uint32_t d_MISC_IS_DST_MAX_LEN_VIO_MASK; + uint32_t d_MISC_IS_DST_RING_OVERFLOW_MASK; + uint32_t d_MISC_IS_SRC_RING_OVERFLOW_MASK; + uint32_t d_SRC_WATERMARK_LOW_LSB; + uint32_t d_SRC_WATERMARK_HIGH_LSB; + uint32_t d_DST_WATERMARK_LOW_LSB; + uint32_t d_DST_WATERMARK_HIGH_LSB; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB; + uint32_t d_CE_CTRL1_DMAX_LENGTH_LSB; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_WRAPPER_DEBUG_OFFSET; + uint32_t d_CE_WRAPPER_DEBUG_SEL_MSB; + uint32_t d_CE_WRAPPER_DEBUG_SEL_LSB; + uint32_t d_CE_WRAPPER_DEBUG_SEL_MASK; + uint32_t d_CE_DEBUG_OFFSET; + uint32_t d_CE_DEBUG_SEL_MSB; + uint32_t d_CE_DEBUG_SEL_LSB; + uint32_t d_CE_DEBUG_SEL_MASK; + uint32_t d_CE0_BASE_ADDRESS; + uint32_t d_CE1_BASE_ADDRESS; + uint32_t d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES; + uint32_t d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS; +}; +#endif /* _REGTABLE_CE_H_ */ diff --git a/core/hif/inc/regtable_pcie.h b/core/hif/inc/regtable_pcie.h new file mode 100644 index 0000000000..1ae7b181ab --- /dev/null +++ b/core/hif/inc/regtable_pcie.h @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _REGTABLE_PCIE_H_ +#define _REGTABLE_PCIE_H_ + +#define MISSING 0 + +struct targetdef_s { + uint32_t d_RTC_SOC_BASE_ADDRESS; + uint32_t d_RTC_WMAC_BASE_ADDRESS; + uint32_t d_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_LSB; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_MASK; + uint32_t d_CLOCK_CONTROL_OFFSET; + uint32_t d_CLOCK_CONTROL_SI0_CLK_MASK; + uint32_t d_RESET_CONTROL_OFFSET; + uint32_t d_RESET_CONTROL_MBOX_RST_MASK; + uint32_t d_RESET_CONTROL_SI0_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_OFFSET; + uint32_t d_WLAN_RESET_CONTROL_COLD_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_WARM_RST_MASK; + uint32_t d_GPIO_BASE_ADDRESS; + uint32_t d_GPIO_PIN0_OFFSET; + uint32_t d_GPIO_PIN1_OFFSET; + uint32_t d_GPIO_PIN0_CONFIG_MASK; + uint32_t d_GPIO_PIN1_CONFIG_MASK; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_LSB; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_MASK; + uint32_t d_SI_CONFIG_I2C_LSB; + uint32_t d_SI_CONFIG_I2C_MASK; + uint32_t d_SI_CONFIG_POS_SAMPLE_LSB; + uint32_t d_SI_CONFIG_POS_SAMPLE_MASK; + uint32_t d_SI_CONFIG_INACTIVE_CLK_LSB; + uint32_t d_SI_CONFIG_INACTIVE_CLK_MASK; + uint32_t d_SI_CONFIG_INACTIVE_DATA_LSB; + uint32_t d_SI_CONFIG_INACTIVE_DATA_MASK; + uint32_t d_SI_CONFIG_DIVIDER_LSB; + uint32_t d_SI_CONFIG_DIVIDER_MASK; + uint32_t d_SI_BASE_ADDRESS; + uint32_t d_SI_CONFIG_OFFSET; + uint32_t d_SI_TX_DATA0_OFFSET; + uint32_t d_SI_TX_DATA1_OFFSET; + uint32_t d_SI_RX_DATA0_OFFSET; + uint32_t d_SI_RX_DATA1_OFFSET; + uint32_t d_SI_CS_OFFSET; + uint32_t d_SI_CS_DONE_ERR_MASK; + uint32_t d_SI_CS_DONE_INT_MASK; + uint32_t d_SI_CS_START_LSB; + uint32_t d_SI_CS_START_MASK; + uint32_t d_SI_CS_RX_CNT_LSB; + uint32_t d_SI_CS_RX_CNT_MASK; + uint32_t d_SI_CS_TX_CNT_LSB; + uint32_t d_SI_CS_TX_CNT_MASK; + uint32_t d_BOARD_DATA_SZ; + uint32_t d_BOARD_EXT_DATA_SZ; + uint32_t d_MBOX_BASE_ADDRESS; + uint32_t d_LOCAL_SCRATCH_OFFSET; + uint32_t d_CPU_CLOCK_OFFSET; + uint32_t d_LPO_CAL_OFFSET; + uint32_t d_GPIO_PIN10_OFFSET; + uint32_t d_GPIO_PIN11_OFFSET; + uint32_t d_GPIO_PIN12_OFFSET; + uint32_t d_GPIO_PIN13_OFFSET; + uint32_t d_CLOCK_GPIO_OFFSET; + uint32_t d_CPU_CLOCK_STANDARD_LSB; + uint32_t d_CPU_CLOCK_STANDARD_MASK; + uint32_t d_LPO_CAL_ENABLE_LSB; + uint32_t d_LPO_CAL_ENABLE_MASK; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK; + uint32_t d_ANALOG_INTF_BASE_ADDRESS; + uint32_t d_WLAN_MAC_BASE_ADDRESS; + uint32_t d_FW_INDICATOR_ADDRESS; + uint32_t d_DRAM_BASE_ADDRESS; + uint32_t d_SOC_CORE_BASE_ADDRESS; + uint32_t d_CORE_CTRL_ADDRESS; + uint32_t d_CE_COUNT; + uint32_t d_MSI_NUM_REQUEST; + uint32_t d_MSI_ASSIGN_FW; + uint32_t d_MSI_ASSIGN_CE_INITIAL; + uint32_t d_PCIE_INTR_ENABLE_ADDRESS; + uint32_t d_PCIE_INTR_CLR_ADDRESS; + uint32_t d_PCIE_INTR_FIRMWARE_MASK; + uint32_t d_PCIE_INTR_CE_MASK_ALL; + uint32_t d_CORE_CTRL_CPU_INTR_MASK; + uint32_t d_SR_WR_INDEX_ADDRESS; + uint32_t d_DST_WATERMARK_ADDRESS; + + /* htt_rx.c */ + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_MASK; + uint32_t d_RX_MPDU_START_2_TID_LSB; + uint32_t d_RX_MPDU_START_2_TID_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_MASK; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_LSB; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_LSB; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_MASK; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_LSB; + uint32_t d_RX_ATTENTION_0_FRAGMENT_MASK; + uint32_t d_RX_ATTENTION_0_FRAGMENT_LSB; + uint32_t d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_MASK; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_LSB; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_MASK; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_LSB; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_MASK; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_LSB; + uint32_t d_RX_ATTENTION_0_MORE_DATA_MASK; + uint32_t d_RX_ATTENTION_0_MSDU_DONE_MASK; + uint32_t d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK; + /* end */ + + /* PLL start */ + uint32_t d_EFUSE_OFFSET; + uint32_t d_EFUSE_XTAL_SEL_MSB; + uint32_t d_EFUSE_XTAL_SEL_LSB; + uint32_t d_EFUSE_XTAL_SEL_MASK; + uint32_t d_BB_PLL_CONFIG_OFFSET; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_LSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MASK; + uint32_t d_BB_PLL_CONFIG_FRAC_MSB; + uint32_t d_BB_PLL_CONFIG_FRAC_LSB; + uint32_t d_BB_PLL_CONFIG_FRAC_MASK; + uint32_t d_WLAN_PLL_SETTLE_TIME_MSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_LSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_MASK; + uint32_t d_WLAN_PLL_SETTLE_OFFSET; + uint32_t d_WLAN_PLL_SETTLE_SW_MASK; + uint32_t d_WLAN_PLL_SETTLE_RSTMASK; + uint32_t d_WLAN_PLL_SETTLE_RESET; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_LSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_LSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_RESET; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_LSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MASK; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_RESET; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_DIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_DIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_OFFSET; + uint32_t d_WLAN_PLL_CONTROL_SW_MASK; + uint32_t d_WLAN_PLL_CONTROL_RSTMASK; + uint32_t d_WLAN_PLL_CONTROL_RESET; + uint32_t d_SOC_CORE_CLK_CTRL_OFFSET; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_LSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_LSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_RESET; + uint32_t d_RTC_SYNC_STATUS_OFFSET; + uint32_t d_SOC_CPU_CLOCK_OFFSET; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_LSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MASK; + /* PLL end */ + + uint32_t d_SOC_POWER_REG_OFFSET; + uint32_t d_PCIE_INTR_CAUSE_ADDRESS; + uint32_t d_SOC_RESET_CONTROL_ADDRESS; + uint32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK; + uint32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB; + uint32_t d_SOC_RESET_CONTROL_CE_RST_MASK; + uint32_t d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + uint32_t d_CPU_INTR_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + + /* chip id start */ + uint32_t d_SOC_CHIP_ID_ADDRESS; + uint32_t d_SOC_CHIP_ID_VERSION_MASK; + uint32_t d_SOC_CHIP_ID_VERSION_LSB; + uint32_t d_SOC_CHIP_ID_REVISION_MASK; + uint32_t d_SOC_CHIP_ID_REVISION_LSB; + /* chip id end */ + + uint32_t d_A_SOC_CORE_SCRATCH_0_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_1_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_2_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_3_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_4_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_5_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_6_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_7_ADDRESS; + uint32_t d_A_SOC_CORE_SPARE_0_REGISTER; + uint32_t d_PCIE_INTR_FIRMWARE_ROUTE_MASK; + uint32_t d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1; + uint32_t d_A_SOC_CORE_SPARE_1_REGISTER; + uint32_t d_A_SOC_CORE_PCIE_INTR_CLR_GRP1; + uint32_t d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_0; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_1; + uint32_t d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_2; + uint32_t d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK; + + uint32_t d_WLAN_DEBUG_INPUT_SEL_OFFSET; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_LSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MASK; + uint32_t d_WLAN_DEBUG_CONTROL_OFFSET; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_LSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MASK; + uint32_t d_WLAN_DEBUG_OUT_OFFSET; + uint32_t d_WLAN_DEBUG_OUT_DATA_MSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_LSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_MASK; + uint32_t d_AMBA_DEBUG_BUS_OFFSET; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK; + uint32_t d_AMBA_DEBUG_BUS_SEL_MSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_LSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_MASK; + +#ifdef QCA_WIFI_3_0_ADRASTEA + uint32_t d_Q6_ENABLE_REGISTER_0; + uint32_t d_Q6_ENABLE_REGISTER_1; + uint32_t d_Q6_CAUSE_REGISTER_0; + uint32_t d_Q6_CAUSE_REGISTER_1; + uint32_t d_Q6_CLEAR_REGISTER_0; + uint32_t d_Q6_CLEAR_REGISTER_1; +#endif +}; + +#define A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK) +#define A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1) +#define A_SOC_CORE_SPARE_1_REGISTER \ + (scn->targetdef->d_A_SOC_CORE_SPARE_1_REGISTER) +#define A_SOC_CORE_PCIE_INTR_CLR_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_CLR_GRP1) +#define A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1) +#define A_SOC_PCIE_PCIE_SCRATCH_0 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_0) +#define A_SOC_PCIE_PCIE_SCRATCH_1 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_1) +#define A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA \ + (scn->targetdef->d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA) +#define A_SOC_PCIE_PCIE_SCRATCH_2 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_2) +/* end Q6 iHelium emu registers */ + +#define PCIE_INTR_FIRMWARE_ROUTE_MASK \ + (scn->targetdef->d_PCIE_INTR_FIRMWARE_ROUTE_MASK) +#define A_SOC_CORE_SPARE_0_REGISTER \ + (scn->targetdef->d_A_SOC_CORE_SPARE_0_REGISTER) +#define A_SOC_CORE_SCRATCH_0_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_0_ADDRESS) +#define A_SOC_CORE_SCRATCH_1_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_1_ADDRESS) +#define A_SOC_CORE_SCRATCH_2_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_2_ADDRESS) +#define A_SOC_CORE_SCRATCH_3_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_3_ADDRESS) +#define A_SOC_CORE_SCRATCH_4_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_4_ADDRESS) +#define A_SOC_CORE_SCRATCH_5_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_5_ADDRESS) +#define A_SOC_CORE_SCRATCH_6_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_6_ADDRESS) +#define A_SOC_CORE_SCRATCH_7_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_7_ADDRESS) +#define RTC_SOC_BASE_ADDRESS (scn->targetdef->d_RTC_SOC_BASE_ADDRESS) +#define RTC_WMAC_BASE_ADDRESS (scn->targetdef->d_RTC_WMAC_BASE_ADDRESS) +#define SYSTEM_SLEEP_OFFSET (scn->targetdef->d_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_OFFSET \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_LSB) +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define CLOCK_CONTROL_OFFSET (scn->targetdef->d_CLOCK_CONTROL_OFFSET) +#define CLOCK_CONTROL_SI0_CLK_MASK \ + (scn->targetdef->d_CLOCK_CONTROL_SI0_CLK_MASK) +#define RESET_CONTROL_OFFSET (scn->targetdef->d_RESET_CONTROL_OFFSET) +#define RESET_CONTROL_MBOX_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_MBOX_RST_MASK) +#define RESET_CONTROL_SI0_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_SI0_RST_MASK) +#define WLAN_RESET_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_RESET_CONTROL_OFFSET) +#define WLAN_RESET_CONTROL_COLD_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_COLD_RST_MASK) +#define WLAN_RESET_CONTROL_WARM_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_WARM_RST_MASK) +#define GPIO_BASE_ADDRESS (scn->targetdef->d_GPIO_BASE_ADDRESS) +#define GPIO_PIN0_OFFSET (scn->targetdef->d_GPIO_PIN0_OFFSET) +#define GPIO_PIN1_OFFSET (scn->targetdef->d_GPIO_PIN1_OFFSET) +#define GPIO_PIN0_CONFIG_MASK (scn->targetdef->d_GPIO_PIN0_CONFIG_MASK) +#define GPIO_PIN1_CONFIG_MASK (scn->targetdef->d_GPIO_PIN1_CONFIG_MASK) +#define A_SOC_CORE_SCRATCH_0 (scn->targetdef->d_A_SOC_CORE_SCRATCH_0) +#define SI_CONFIG_BIDIR_OD_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_LSB) +#define SI_CONFIG_BIDIR_OD_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_LSB (scn->targetdef->d_SI_CONFIG_I2C_LSB) +#define SI_CONFIG_I2C_MASK \ + (scn->targetdef->d_SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_LSB \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_LSB) +#define SI_CONFIG_POS_SAMPLE_MASK \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_LSB) +#define SI_CONFIG_INACTIVE_CLK_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_LSB) +#define SI_CONFIG_INACTIVE_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_LSB (scn->targetdef->d_SI_CONFIG_DIVIDER_LSB) +#define SI_CONFIG_DIVIDER_MASK (scn->targetdef->d_SI_CONFIG_DIVIDER_MASK) +#define SI_BASE_ADDRESS (scn->targetdef->d_SI_BASE_ADDRESS) +#define SI_CONFIG_OFFSET (scn->targetdef->d_SI_CONFIG_OFFSET) +#define SI_TX_DATA0_OFFSET (scn->targetdef->d_SI_TX_DATA0_OFFSET) +#define SI_TX_DATA1_OFFSET (scn->targetdef->d_SI_TX_DATA1_OFFSET) +#define SI_RX_DATA0_OFFSET (scn->targetdef->d_SI_RX_DATA0_OFFSET) +#define SI_RX_DATA1_OFFSET (scn->targetdef->d_SI_RX_DATA1_OFFSET) +#define SI_CS_OFFSET (scn->targetdef->d_SI_CS_OFFSET) +#define SI_CS_DONE_ERR_MASK (scn->targetdef->d_SI_CS_DONE_ERR_MASK) +#define SI_CS_DONE_INT_MASK (scn->targetdef->d_SI_CS_DONE_INT_MASK) +#define SI_CS_START_LSB (scn->targetdef->d_SI_CS_START_LSB) +#define SI_CS_START_MASK (scn->targetdef->d_SI_CS_START_MASK) +#define SI_CS_RX_CNT_LSB (scn->targetdef->d_SI_CS_RX_CNT_LSB) +#define SI_CS_RX_CNT_MASK (scn->targetdef->d_SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_LSB (scn->targetdef->d_SI_CS_TX_CNT_LSB) +#define SI_CS_TX_CNT_MASK (scn->targetdef->d_SI_CS_TX_CNT_MASK) +#define EEPROM_SZ (scn->targetdef->d_BOARD_DATA_SZ) +#define EEPROM_EXT_SZ (scn->targetdef->d_BOARD_EXT_DATA_SZ) +#define MBOX_BASE_ADDRESS (scn->targetdef->d_MBOX_BASE_ADDRESS) +#define LOCAL_SCRATCH_OFFSET (scn->targetdef->d_LOCAL_SCRATCH_OFFSET) +#define CPU_CLOCK_OFFSET (scn->targetdef->d_CPU_CLOCK_OFFSET) +#define LPO_CAL_OFFSET (scn->targetdef->d_LPO_CAL_OFFSET) +#define GPIO_PIN10_OFFSET (scn->targetdef->d_GPIO_PIN10_OFFSET) +#define GPIO_PIN11_OFFSET (scn->targetdef->d_GPIO_PIN11_OFFSET) +#define GPIO_PIN12_OFFSET (scn->targetdef->d_GPIO_PIN12_OFFSET) +#define GPIO_PIN13_OFFSET (scn->targetdef->d_GPIO_PIN13_OFFSET) +#define CLOCK_GPIO_OFFSET (scn->targetdef->d_CLOCK_GPIO_OFFSET) +#define CPU_CLOCK_STANDARD_LSB (scn->targetdef->d_CPU_CLOCK_STANDARD_LSB) +#define CPU_CLOCK_STANDARD_MASK (scn->targetdef->d_CPU_CLOCK_STANDARD_MASK) +#define LPO_CAL_ENABLE_LSB (scn->targetdef->d_LPO_CAL_ENABLE_LSB) +#define LPO_CAL_ENABLE_MASK (scn->targetdef->d_LPO_CAL_ENABLE_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB) +#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +#define ANALOG_INTF_BASE_ADDRESS (scn->targetdef->d_ANALOG_INTF_BASE_ADDRESS) +#define WLAN_MAC_BASE_ADDRESS (scn->targetdef->d_WLAN_MAC_BASE_ADDRESS) +#define FW_INDICATOR_ADDRESS (scn->targetdef->d_FW_INDICATOR_ADDRESS) +#define DRAM_BASE_ADDRESS (scn->targetdef->d_DRAM_BASE_ADDRESS) +#define SOC_CORE_BASE_ADDRESS (scn->targetdef->d_SOC_CORE_BASE_ADDRESS) +#define CORE_CTRL_ADDRESS (scn->targetdef->d_CORE_CTRL_ADDRESS) +#define CE_COUNT (scn->targetdef->d_CE_COUNT) +#define PCIE_INTR_ENABLE_ADDRESS (scn->targetdef->d_PCIE_INTR_ENABLE_ADDRESS) +#define PCIE_INTR_CLR_ADDRESS (scn->targetdef->d_PCIE_INTR_CLR_ADDRESS) +#define PCIE_INTR_FIRMWARE_MASK (scn->targetdef->d_PCIE_INTR_FIRMWARE_MASK) +#define PCIE_INTR_CE_MASK_ALL (scn->targetdef->d_PCIE_INTR_CE_MASK_ALL) +#define CORE_CTRL_CPU_INTR_MASK (scn->targetdef->d_CORE_CTRL_CPU_INTR_MASK) +#define PCIE_INTR_CAUSE_ADDRESS (scn->targetdef->d_PCIE_INTR_CAUSE_ADDRESS) +#define SOC_RESET_CONTROL_ADDRESS (scn->targetdef->d_SOC_RESET_CONTROL_ADDRESS) +#define HOST_GROUP0_MASK (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL | \ + A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK) +#define SOC_RESET_CONTROL_CE_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CE_RST_MASK) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +#define CPU_INTR_ADDRESS (scn->targetdef->d_CPU_INTR_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ADDRESS \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_GET(x) \ + (((x) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) >> \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_SET(x) \ + (((x) << SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) & \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +/* hif_pci.c */ +#define CHIP_ID_ADDRESS (scn->targetdef->d_SOC_CHIP_ID_ADDRESS) +#define SOC_CHIP_ID_REVISION_MASK (scn->targetdef->d_SOC_CHIP_ID_REVISION_MASK) +#define SOC_CHIP_ID_REVISION_LSB (scn->targetdef->d_SOC_CHIP_ID_REVISION_LSB) +#define SOC_CHIP_ID_VERSION_MASK (scn->targetdef->d_SOC_CHIP_ID_VERSION_MASK) +#define SOC_CHIP_ID_VERSION_LSB (scn->targetdef->d_SOC_CHIP_ID_VERSION_LSB) +#define CHIP_ID_REVISION_GET(x) \ + (((x) & SOC_CHIP_ID_REVISION_MASK) >> SOC_CHIP_ID_REVISION_LSB) +#define CHIP_ID_VERSION_GET(x) \ + (((x) & SOC_CHIP_ID_VERSION_MASK) >> SOC_CHIP_ID_VERSION_LSB) +/* hif_pci.c end */ + +/* misc */ +#define SR_WR_INDEX_ADDRESS (scn->targetdef->d_SR_WR_INDEX_ADDRESS) +#define DST_WATERMARK_ADDRESS (scn->targetdef->d_DST_WATERMARK_ADDRESS) +#define SOC_POWER_REG_OFFSET (scn->targetdef->d_SOC_POWER_REG_OFFSET) +/* end */ + +/* htt_rx.c */ +#define RX_MSDU_END_4_FIRST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_MASK) +#define RX_MSDU_END_4_FIRST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_LSB) +#define RX_MPDU_START_0_RETRY_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_LSB) +#define RX_MPDU_START_0_RETRY_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_MASK) +#define RX_MPDU_START_0_SEQ_NUM_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_MASK) +#define RX_MPDU_START_0_SEQ_NUM_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_LSB) +#define RX_MPDU_START_2_PN_47_32_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_LSB) +#define RX_MPDU_START_2_PN_47_32_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_MASK) +#define RX_MPDU_START_2_TID_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_LSB) +#define RX_MPDU_START_2_TID_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_LSB) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB) +#define RX_MSDU_END_4_LAST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_MASK) +#define RX_MSDU_END_4_LAST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_LSB) +#define RX_ATTENTION_0_MCAST_BCAST_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_MASK) +#define RX_ATTENTION_0_MCAST_BCAST_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_LSB) +#define RX_ATTENTION_0_FRAGMENT_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_MASK) +#define RX_ATTENTION_0_FRAGMENT_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_LSB) +#define RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB) +#define RX_MSDU_START_0_MSDU_LENGTH_MASK \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_MASK) +#define RX_MSDU_START_0_MSDU_LENGTH_LSB \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_LSB) +#define RX_MSDU_START_2_DECAP_FORMAT_OFFSET \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET) +#define RX_MSDU_START_2_DECAP_FORMAT_MASK \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_MASK) +#define RX_MSDU_START_2_DECAP_FORMAT_LSB \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_LSB) +#define RX_MPDU_START_0_ENCRYPTED_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_MASK) +#define RX_MPDU_START_0_ENCRYPTED_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_LSB) +#define RX_ATTENTION_0_MORE_DATA_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MORE_DATA_MASK) +#define RX_ATTENTION_0_MSDU_DONE_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MSDU_DONE_MASK) +#define RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) +/* end */ + +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_OFFSET (scn->targetdef->d_EFUSE_OFFSET) +#define EFUSE_XTAL_SEL_MSB (scn->targetdef->d_EFUSE_XTAL_SEL_MSB) +#define EFUSE_XTAL_SEL_LSB (scn->targetdef->d_EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_MASK (scn->targetdef->d_EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OFFSET (scn->targetdef->d_BB_PLL_CONFIG_OFFSET) +#define BB_PLL_CONFIG_OUTDIV_MSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MSB) +#define BB_PLL_CONFIG_OUTDIV_LSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_MASK (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_MSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MSB) +#define BB_PLL_CONFIG_FRAC_LSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_MASK (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_MSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MSB) +#define WLAN_PLL_SETTLE_TIME_LSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_SETTLE_OFFSET (scn->targetdef->d_WLAN_PLL_SETTLE_OFFSET) +#define WLAN_PLL_SETTLE_SW_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_SW_MASK) +#define WLAN_PLL_SETTLE_RSTMASK (scn->targetdef->d_WLAN_PLL_SETTLE_RSTMASK) +#define WLAN_PLL_SETTLE_RESET (scn->targetdef->d_WLAN_PLL_SETTLE_RESET) +#define WLAN_PLL_CONTROL_NOPWD_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MSB) +#define WLAN_PLL_CONTROL_NOPWD_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MSB) +#define WLAN_PLL_CONTROL_BYPASS_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_BYPASS_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_RESET) +#define WLAN_PLL_CONTROL_CLK_SEL_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MSB) +#define WLAN_PLL_CONTROL_CLK_SEL_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_RESET) +#define WLAN_PLL_CONTROL_REFDIV_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MSB) +#define WLAN_PLL_CONTROL_REFDIV_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_REFDIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_RESET) +#define WLAN_PLL_CONTROL_DIV_MSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MSB) +#define WLAN_PLL_CONTROL_DIV_LSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MASK) +#define WLAN_PLL_CONTROL_DIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_RESET) +#define WLAN_PLL_CONTROL_OFFSET (scn->targetdef->d_WLAN_PLL_CONTROL_OFFSET) +#define WLAN_PLL_CONTROL_SW_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_SW_MASK) +#define WLAN_PLL_CONTROL_RSTMASK (scn->targetdef->d_WLAN_PLL_CONTROL_RSTMASK) +#define WLAN_PLL_CONTROL_RESET (scn->targetdef->d_WLAN_PLL_CONTROL_RESET) +#define SOC_CORE_CLK_CTRL_OFFSET (scn->targetdef->d_SOC_CORE_CLK_CTRL_OFFSET) +#define SOC_CORE_CLK_CTRL_DIV_MSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MSB) +#define SOC_CORE_CLK_CTRL_DIV_LSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_MASK \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_MSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_LSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_MASK \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_RESET \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_RESET) +#define RTC_SYNC_STATUS_OFFSET (scn->targetdef->d_RTC_SYNC_STATUS_OFFSET) +#define SOC_CPU_CLOCK_OFFSET (scn->targetdef->d_SOC_CPU_CLOCK_OFFSET) +#define SOC_CPU_CLOCK_STANDARD_MSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MSB) +#define SOC_CPU_CLOCK_STANDARD_LSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_MASK \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +/* SET macros */ +#define WLAN_SYSTEM_SLEEP_DISABLE_SET(x) \ + (((x) << WLAN_SYSTEM_SLEEP_DISABLE_LSB) & \ + WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define SI_CONFIG_BIDIR_OD_DATA_SET(x) \ + (((x) << SI_CONFIG_BIDIR_OD_DATA_LSB) & SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_SET(x) (((x) << SI_CONFIG_I2C_LSB) & SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_SET(x) \ + (((x) << SI_CONFIG_POS_SAMPLE_LSB) & SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_CLK_LSB) & SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_DATA_LSB) & SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_SET(x) \ + (((x) << SI_CONFIG_DIVIDER_LSB) & SI_CONFIG_DIVIDER_MASK) +#define SI_CS_START_SET(x) (((x) << SI_CS_START_LSB) & SI_CS_START_MASK) +#define SI_CS_RX_CNT_SET(x) (((x) << SI_CS_RX_CNT_LSB) & SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_SET(x) (((x) << SI_CS_TX_CNT_LSB) & SI_CS_TX_CNT_MASK) +#define LPO_CAL_ENABLE_SET(x) \ + (((x) << LPO_CAL_ENABLE_LSB) & LPO_CAL_ENABLE_MASK) +#define CPU_CLOCK_STANDARD_SET(x) \ + (((x) << CPU_CLOCK_STANDARD_LSB) & CPU_CLOCK_STANDARD_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_SET(x) \ + (((x) << CLOCK_GPIO_BT_CLK_OUT_EN_LSB) & CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_XTAL_SEL_GET(x) \ + (((x) & EFUSE_XTAL_SEL_MASK) >> EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_SET(x) \ + (((x) << EFUSE_XTAL_SEL_LSB) & EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OUTDIV_GET(x) \ + (((x) & BB_PLL_CONFIG_OUTDIV_MASK) >> BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_SET(x) \ + (((x) << BB_PLL_CONFIG_OUTDIV_LSB) & BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_GET(x) \ + (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) \ + (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_GET(x) \ + (((x) & WLAN_PLL_SETTLE_TIME_MASK) >> WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_SET(x) \ + (((x) << WLAN_PLL_SETTLE_TIME_LSB) & WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_CONTROL_NOPWD_GET(x) \ + (((x) & WLAN_PLL_CONTROL_NOPWD_MASK) >> WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_SET(x) \ + (((x) << WLAN_PLL_CONTROL_NOPWD_LSB) & WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_GET(x) \ + (((x) & WLAN_PLL_CONTROL_BYPASS_MASK) >> WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_SET(x) \ + (((x) << WLAN_PLL_CONTROL_BYPASS_LSB) & WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_GET(x) \ + (((x) & WLAN_PLL_CONTROL_CLK_SEL_MASK) >> WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_SET(x) \ + (((x) << WLAN_PLL_CONTROL_CLK_SEL_LSB) & WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_REFDIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_REFDIV_MASK) >> WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_REFDIV_LSB) & WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_DIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_DIV_MASK) >> WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_DIV_LSB) & WLAN_PLL_CONTROL_DIV_MASK) +#define SOC_CORE_CLK_CTRL_DIV_GET(x) \ + (((x) & SOC_CORE_CLK_CTRL_DIV_MASK) >> SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) \ + (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_GET(x) \ + (((x) & RTC_SYNC_STATUS_PLL_CHANGING_MASK) >> \ + RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_SET(x) \ + (((x) << RTC_SYNC_STATUS_PLL_CHANGING_LSB) & \ + RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define SOC_CPU_CLOCK_STANDARD_GET(x) \ + (((x) & SOC_CPU_CLOCK_STANDARD_MASK) >> SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) \ + (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define Q6_ENABLE_REGISTER_0 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_0) +#define Q6_ENABLE_REGISTER_1 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_1) +#define Q6_CAUSE_REGISTER_0 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_0) +#define Q6_CAUSE_REGISTER_1 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_1) +#define Q6_CLEAR_REGISTER_0 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_0) +#define Q6_CLEAR_REGISTER_1 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_1) +#endif + +struct hostdef_s { + A_UINT32 d_INT_STATUS_ENABLE_ERROR_LSB; + A_UINT32 d_INT_STATUS_ENABLE_ERROR_MASK; + A_UINT32 d_INT_STATUS_ENABLE_CPU_LSB; + A_UINT32 d_INT_STATUS_ENABLE_CPU_MASK; + A_UINT32 d_INT_STATUS_ENABLE_COUNTER_LSB; + A_UINT32 d_INT_STATUS_ENABLE_COUNTER_MASK; + A_UINT32 d_INT_STATUS_ENABLE_MBOX_DATA_LSB; + A_UINT32 d_INT_STATUS_ENABLE_MBOX_DATA_MASK; + A_UINT32 d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB; + A_UINT32 d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK; + A_UINT32 d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB; + A_UINT32 d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + A_UINT32 d_COUNTER_INT_STATUS_ENABLE_BIT_LSB; + A_UINT32 d_COUNTER_INT_STATUS_ENABLE_BIT_MASK; + A_UINT32 d_INT_STATUS_ENABLE_ADDRESS; + A_UINT32 d_CPU_INT_STATUS_ENABLE_BIT_LSB; + A_UINT32 d_CPU_INT_STATUS_ENABLE_BIT_MASK; + A_UINT32 d_HOST_INT_STATUS_ADDRESS; + A_UINT32 d_CPU_INT_STATUS_ADDRESS; + A_UINT32 d_ERROR_INT_STATUS_ADDRESS; + A_UINT32 d_ERROR_INT_STATUS_WAKEUP_MASK; + A_UINT32 d_ERROR_INT_STATUS_WAKEUP_LSB; + A_UINT32 d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK; + A_UINT32 d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB; + A_UINT32 d_ERROR_INT_STATUS_TX_OVERFLOW_MASK; + A_UINT32 d_ERROR_INT_STATUS_TX_OVERFLOW_LSB; + A_UINT32 d_COUNT_DEC_ADDRESS; + A_UINT32 d_HOST_INT_STATUS_CPU_MASK; + A_UINT32 d_HOST_INT_STATUS_CPU_LSB; + A_UINT32 d_HOST_INT_STATUS_ERROR_MASK; + A_UINT32 d_HOST_INT_STATUS_ERROR_LSB; + A_UINT32 d_HOST_INT_STATUS_COUNTER_MASK; + A_UINT32 d_HOST_INT_STATUS_COUNTER_LSB; + A_UINT32 d_RX_LOOKAHEAD_VALID_ADDRESS; + A_UINT32 d_WINDOW_DATA_ADDRESS; + A_UINT32 d_WINDOW_READ_ADDR_ADDRESS; + A_UINT32 d_WINDOW_WRITE_ADDR_ADDRESS; + A_UINT32 d_SOC_GLOBAL_RESET_ADDRESS; + A_UINT32 d_RTC_STATE_ADDRESS; + A_UINT32 d_RTC_STATE_COLD_RESET_MASK; + A_UINT32 d_PCIE_LOCAL_BASE_ADDRESS; + A_UINT32 d_PCIE_SOC_WAKE_RESET; + A_UINT32 d_PCIE_SOC_WAKE_ADDRESS; + A_UINT32 d_PCIE_SOC_WAKE_V_MASK; + A_UINT32 d_RTC_STATE_V_MASK; + A_UINT32 d_RTC_STATE_V_LSB; + A_UINT32 d_FW_IND_EVENT_PENDING; + A_UINT32 d_FW_IND_INITIALIZED; + A_UINT32 d_FW_IND_HELPER; + A_UINT32 d_RTC_STATE_V_ON; +#if defined(SDIO_3_0) + A_UINT32 d_HOST_INT_STATUS_MBOX_DATA_MASK; + A_UINT32 d_HOST_INT_STATUS_MBOX_DATA_LSB; +#endif + A_UINT32 d_PCIE_SOC_RDY_STATUS_ADDRESS; + A_UINT32 d_PCIE_SOC_RDY_STATUS_BAR_MASK; + A_UINT32 d_SOC_PCIE_BASE_ADDRESS; + A_UINT32 d_MSI_MAGIC_ADR_ADDRESS; + A_UINT32 d_MSI_MAGIC_ADDRESS; + uint32_t d_HOST_CE_COUNT; + uint32_t d_ENABLE_MSI; + uint32_t d_MUX_ID_MASK; + uint32_t d_TRANSACTION_ID_MASK; + uint32_t d_DESC_DATA_FLAG_MASK; + uint32_t d_A_SOC_PCIE_PCIE_BAR0_START; +}; +#define A_SOC_PCIE_PCIE_BAR0_START (scn->hostdef->d_A_SOC_PCIE_PCIE_BAR0_START) +#define DESC_DATA_FLAG_MASK (scn->hostdef->d_DESC_DATA_FLAG_MASK) +#define MUX_ID_MASK (scn->hostdef->d_MUX_ID_MASK) +#define TRANSACTION_ID_MASK (scn->hostdef->d_TRANSACTION_ID_MASK) +#define HOST_CE_COUNT (scn->hostdef->d_HOST_CE_COUNT) +#define ENABLE_MSI (scn->hostdef->d_ENABLE_MSI) +#define INT_STATUS_ENABLE_ERROR_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_LSB (scn->hostdef->d_INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_MASK (scn->hostdef->d_INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define INT_STATUS_ENABLE_ADDRESS \ + (scn->hostdef->d_INT_STATUS_ENABLE_ADDRESS) +#define CPU_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_MASK) +#define HOST_INT_STATUS_ADDRESS (scn->hostdef->d_HOST_INT_STATUS_ADDRESS) +#define CPU_INT_STATUS_ADDRESS (scn->hostdef->d_CPU_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_ADDRESS (scn->hostdef->d_ERROR_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_WAKEUP_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_WAKEUP_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define COUNT_DEC_ADDRESS (scn->hostdef->d_COUNT_DEC_ADDRESS) +#define HOST_INT_STATUS_CPU_MASK (scn->hostdef->d_HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_CPU_LSB (scn->hostdef->d_HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_MASK (scn->hostdef->d_HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_ERROR_LSB (scn->hostdef->d_HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_COUNTER_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_LSB) +#define RX_LOOKAHEAD_VALID_ADDRESS (scn->hostdef->d_RX_LOOKAHEAD_VALID_ADDRESS) +#define WINDOW_DATA_ADDRESS (scn->hostdef->d_WINDOW_DATA_ADDRESS) +#define WINDOW_READ_ADDR_ADDRESS (scn->hostdef->d_WINDOW_READ_ADDR_ADDRESS) +#define WINDOW_WRITE_ADDR_ADDRESS (scn->hostdef->d_WINDOW_WRITE_ADDR_ADDRESS) +#define SOC_GLOBAL_RESET_ADDRESS (scn->hostdef->d_SOC_GLOBAL_RESET_ADDRESS) +#define RTC_STATE_ADDRESS (scn->hostdef->d_RTC_STATE_ADDRESS) +#define RTC_STATE_COLD_RESET_MASK (scn->hostdef->d_RTC_STATE_COLD_RESET_MASK) +#define PCIE_LOCAL_BASE_ADDRESS (scn->hostdef->d_PCIE_LOCAL_BASE_ADDRESS) +#define PCIE_SOC_WAKE_RESET (scn->hostdef->d_PCIE_SOC_WAKE_RESET) +#define PCIE_SOC_WAKE_ADDRESS (scn->hostdef->d_PCIE_SOC_WAKE_ADDRESS) +#define PCIE_SOC_WAKE_V_MASK (scn->hostdef->d_PCIE_SOC_WAKE_V_MASK) +#define RTC_STATE_V_MASK (scn->hostdef->d_RTC_STATE_V_MASK) +#define RTC_STATE_V_LSB (scn->hostdef->d_RTC_STATE_V_LSB) +#define FW_IND_EVENT_PENDING (scn->hostdef->d_FW_IND_EVENT_PENDING) +#define FW_IND_INITIALIZED (scn->hostdef->d_FW_IND_INITIALIZED) +#define FW_IND_HELPER (scn->hostdef->d_FW_IND_HELPER) +#define RTC_STATE_V_ON (scn->hostdef->d_RTC_STATE_V_ON) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_MASK) +#define HOST_INT_STATUS_MBOX_DATA_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#if !defined(SOC_PCIE_BASE_ADDRESS) +#define SOC_PCIE_BASE_ADDRESS 0 +#endif + +#if !defined(PCIE_SOC_RDY_STATUS_ADDRESS) +#define PCIE_SOC_RDY_STATUS_ADDRESS 0 +#define PCIE_SOC_RDY_STATUS_BAR_MASK 0 +#endif + +#if !defined(MSI_MAGIC_ADR_ADDRESS) +#define MSI_MAGIC_ADR_ADDRESS 0 +#define MSI_MAGIC_ADDRESS 0 +#endif + +/* SET/GET macros */ +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> \ + ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB) +#define RTC_STATE_V_GET(x) \ + (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#define INVALID_REG_LOC_DUMMY_DATA 0xAA + +#define AR6320_CORE_CLK_DIV_ADDR 0x403fa8 +#define AR6320_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320_CPU_SPEED_ADDR 0x403fa4 +#define AR6320V2_CORE_CLK_DIV_ADDR 0x403fd8 +#define AR6320V2_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320V2_CPU_SPEED_ADDR 0x403fd4 +#define AR6320V3_CORE_CLK_DIV_ADDR 0x404028 +#define AR6320V3_CPU_PLL_INIT_DONE_ADDR 0x404020 +#define AR6320V3_CPU_SPEED_ADDR 0x404024 + +typedef enum { + SOC_REFCLK_UNKNOWN = -1, /* Unsupported ref clock -- use PLL Bypass */ + SOC_REFCLK_48_MHZ = 0, + SOC_REFCLK_19_2_MHZ = 1, + SOC_REFCLK_24_MHZ = 2, + SOC_REFCLK_26_MHZ = 3, + SOC_REFCLK_37_4_MHZ = 4, + SOC_REFCLK_38_4_MHZ = 5, + SOC_REFCLK_40_MHZ = 6, + SOC_REFCLK_52_MHZ = 7, +} A_refclk_speed_t; + +#define A_REFCLK_UNKNOWN SOC_REFCLK_UNKNOWN +#define A_REFCLK_48_MHZ SOC_REFCLK_48_MHZ +#define A_REFCLK_19_2_MHZ SOC_REFCLK_19_2_MHZ +#define A_REFCLK_24_MHZ SOC_REFCLK_24_MHZ +#define A_REFCLK_26_MHZ SOC_REFCLK_26_MHZ +#define A_REFCLK_37_4_MHZ SOC_REFCLK_37_4_MHZ +#define A_REFCLK_38_4_MHZ SOC_REFCLK_38_4_MHZ +#define A_REFCLK_40_MHZ SOC_REFCLK_40_MHZ +#define A_REFCLK_52_MHZ SOC_REFCLK_52_MHZ + +#define TARGET_CPU_FREQ 176000000 + +struct wlan_pll_s { + uint32_t refdiv; + uint32_t div; + uint32_t rnfrac; + uint32_t outdiv; +}; + +struct cmnos_clock_s { + A_refclk_speed_t refclk_speed; + uint32_t refclk_hz; + uint32_t pll_settling_time; /* 50us */ + struct wlan_pll_s wlan_pll; +}; + +typedef struct TGT_REG_SECTION { + uint32_t start_addr; + uint32_t end_addr; +} tgt_reg_section; + +typedef struct TGT_REG_TABLE { + tgt_reg_section *section; + uint32_t section_size; +} tgt_reg_table; + +struct ol_softc; +void target_register_tbl_attach(struct ol_softc *scn, u32 target_type); +void hif_register_tbl_attach(struct ol_softc *scn, u32 hif_type); + +struct host_shadow_regs_s { + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_0; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_1; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_2; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_3; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_4; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_5; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_6; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_7; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_8; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_9; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_10; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_11; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_12; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_13; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_14; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_15; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_16; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_17; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_18; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_19; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_20; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_21; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_22; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_23; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_0; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_1; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_2; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_3; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_4; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_5; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_6; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_7; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_8; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_9; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_10; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_11; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_12; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_13; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_14; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_15; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_16; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_17; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_18; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_19; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_20; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_21; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_22; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_23; +}; + +#endif /* _REGTABLE_PCIE_H_ */ diff --git a/core/hif/src/adrastea_reg_def.h b/core/hif/src/adrastea_reg_def.h new file mode 100644 index 0000000000..743d22ef5c --- /dev/null +++ b/core/hif/src/adrastea_reg_def.h @@ -0,0 +1,2352 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef ADRASTEA_REG_DEF_H +#define ADRASTEA_REG_DEF_H + +/* + * Start auto-generated headers from register parser + * + * DO NOT CHANGE MANUALLY +*/ + + +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW (0x00241000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2 (0x00030028) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW (0x00244000) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___M 0x000003FF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE (0x00032060) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6 (0x00030038) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH (0x00032064) +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___M 0x0003FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___M 0x00FFF000 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4 (0x00030030) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX (0x00240040) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS (0x00240038) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR (0x002F1008) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20 (0x00030070) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12 (0x00032030) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___S 18 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB (0x00032070) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13 (0x00032034) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3 (0x0003002C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID (0x000300E0) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22 (0x00032058) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___M 0x00000020 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14 (0x00030058) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___M 0x0000007F +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___S 19 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1 (0x00032004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14 (0x00032038) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23 (0x0003205C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE (0x00240034) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY (0x0024D000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15 (0x0003005C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE (0x0024002C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___M 0x01FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___S 24 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0 (0x00032000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR (0x00030014) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20 (0x00032050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___M 0x00008000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___M 0x00020000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW (0x0024B000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET (0x002F1004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2 (0x00032008) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___POR 0x00 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___M 0x00000060 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___S 6 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___M 0x0FFC0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW (0x00245000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22 (0x00030078) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___POR 0x00000005 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___POR 0x1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK (0x0024004C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17 (0x00030064) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW (0x0024000C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW (0x0024A000) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___M 0x00000003 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___M 0x00000040 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS (0x00030008) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___M 0x00010000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___M 0x000FF800 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19 (0x0003204C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5 (0x00030034) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___M 0x00FFF000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___M 0x000FF800 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___M 0x00010000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5 (0x00032014) +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS (0x0003000C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___S 16 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9 (0x00032024) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___M 0x00004000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___M 0x00020000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___M 0x00000008 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___POR 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18 (0x00032048) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___M 0x00001000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK (0x00240050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW (0x00243000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY (0x00030080) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW (0x00248000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16 (0x00032040) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___M 0x0000000F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY (0x0024C000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___M 0x00000800 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___S 18 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS (0x00032078) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12 (0x00030050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___M 0x00000007 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___S 14 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___M 0x00040000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7 (0x0003003C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET (0x002F0084) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8 (0x00030040) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS (0x00240030) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15 (0x0003203C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH (0x00240004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___POR 0x0080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW (0x00240000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13 (0x00030054) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___S 15 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH (0x00240010) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4 (0x00032010) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___S 7 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW (0x00246000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23 (0x0003007C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___M 0x00000040 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___POR 0x00 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___POR 0x1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1 (0x00240018) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19 (0x0003006C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX (0x0024003C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___M 0x0000000F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___M 0x0000000F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___M 0x0FFFDDFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7 (0x0003201C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___M 0x0000000C +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___S 7 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___RWC QCSR_REG_WO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16 (0x00030060) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS (0x00030144) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17 (0x00032044) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___M 0x000003FF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___M 0x00020000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___M 0x00000007 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW (0x00242000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE (0x00030010) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8 (0x00032020) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___M 0x00000FFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___M 0x00080000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0 (0x00030020) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___M 0x00FFF000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___M 0x01000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11 (0x0003004C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB (0x0003206C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE (0x00240014) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___M 0x00000007 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11 (0x0003202C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI (0x00240048) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW (0x00249000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___M 0x00010000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL (0x00030000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI (0x00240044) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___M 0x000003FF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD (0x00240020) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___S 12 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES (0x002F1000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9 (0x00030044) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6 (0x00032018) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21 (0x00032054) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW (0x00247000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18 (0x00030068) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE (0x00240008) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1 (0x00030024) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2 (0x0024001C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21 (0x00030074) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB (0x00032074) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10 (0x00030048) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB (0x00032068) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY (0x00030004) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10 (0x00032028) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3 (0x0003200C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___S 0 + + +/* End auto-generated headers from register parser */ + +#define MISSING 0 +#define MISSING_FOR_ADRASTEA MISSING +#define ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS 0 +#define ADRASTEA_WIFI_RTC_REG_BASE_ADDRESS 0x45000 +#define ADRASTEA_RTC_SOC_REG_BASE_ADDRESS 0x113000 +#define ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS 0x85000 +#define ADRASTEA_SI_REG_BASE_ADDRESS 0x84000 +#define ADRASTEA_SOC_CORE_REG_BASE_ADDRESS 0x113000 +#define ADRASTEA_CE_WRAPPER_REG_CSR_BASE_ADDRESS 0xC000 +#define ADRASTEA_MAC_WIFICMN_REG_BASE_ADDRESS MISSING + +/* Base Addresses */ +#define ADRASTEA_RTC_SOC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_RTC_WMAC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define ADRASTEA_BT_COEX_BASE_ADDRESS 0x00002000 +#define ADRASTEA_SOC_PCIE_BASE_ADDRESS 0x00130000 +#define ADRASTEA_SOC_CORE_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_UART_BASE_ADDRESS 0x00111000 +#define ADRASTEA_WLAN_SI_BASE_ADDRESS 0x00010000 +#define ADRASTEA_WLAN_GPIO_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_MAC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_EFUSE_BASE_ADDRESS 0x00024000 +#define ADRASTEA_FPGA_REG_BASE_ADDRESS 0x00039000 +#define ADRASTEA_WLAN_UART2_BASE_ADDRESS 0x00054c00 + +#define ADRASTEA_CE_WRAPPER_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY +#define ADRASTEA_CE0_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW +#define ADRASTEA_CE1_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW +#define ADRASTEA_CE2_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW +#define ADRASTEA_CE3_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW +#define ADRASTEA_CE4_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW +#define ADRASTEA_CE5_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW +#define ADRASTEA_CE6_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW +#define ADRASTEA_CE7_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW +#define ADRASTEA_CE8_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW +#define ADRASTEA_CE9_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW +#define ADRASTEA_CE10_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW +#define ADRASTEA_CE11_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW + +#define ADRASTEA_A_SOC_PCIE_SOC_PCIE_REG MISSING +#define ADRASTEA_DBI_BASE_ADDRESS MISSING +#define ADRASTEA_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS MISSING +#define ADRASTEA_WIFICMN_BASE_ADDRESS MISSING +#define ADRASTEA_BOARD_DATA_SZ MISSING +#define ADRASTEA_BOARD_EXT_DATA_SZ MISSING +#define ADRASTEA_A_SOC_PCIE_PCIE_BAR0_START MISSING +#define ADRASTEA_A_SOC_CORE_SCRATCH_0_ADDRESS MISSING +#define ADRASTEA_A_SOC_CORE_SPARE_0_REGISTER MISSING +#define ADRASTEA_PCIE_INTR_FIRMWARE_ROUTE_MASK MISSING +#define ADRASTEA_SCRATCH_3_ADDRESS MISSING +#define ADRASTEA_TARG_DRAM_START 0x00400000 +#define ADRASTEA_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define ADRASTEA_SOC_RESET_CONTROL_OFFSET \ + (0x00000000 + _RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CLOCK_CONTROL_OFFSET \ + (0x00000028 + _RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define ADRASTEA_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define ADRASTEA_WLAN_GPIO_PIN0_ADDRESS \ + (0x50 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN1_ADDRESS \ + (0x54 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define ADRASTEA_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define ADRASTEA_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define ADRASTEA_SOC_LPO_CAL_OFFSET \ + (0xe0 + _RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN10_ADDRESS \ + (0x78 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN11_ADDRESS \ + (0x7c + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN12_ADDRESS \ + (0x80 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN13_ADDRESS \ + (0x84 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define ADRASTEA_SOC_LPO_CAL_ENABLE_LSB 20 +#define ADRASTEA_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define ADRASTEA_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000002 +#define ADRASTEA_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000001 +#define ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define ADRASTEA_SI_CONFIG_I2C_LSB 16 +#define ADRASTEA_SI_CONFIG_I2C_MASK 0x00010000 +#define ADRASTEA_SI_CONFIG_POS_SAMPLE_LSB 7 +#define ADRASTEA_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define ADRASTEA_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define ADRASTEA_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define ADRASTEA_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define ADRASTEA_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define ADRASTEA_SI_CONFIG_DIVIDER_LSB 0 +#define ADRASTEA_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define ADRASTEA_SI_CONFIG_OFFSET (0x00000000 + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_TX_DATA0_OFFSET (0x00000008 + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_TX_DATA1_OFFSET (0x0000000c + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_RX_DATA0_OFFSET (0x00000010 + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_RX_DATA1_OFFSET (0x00000014 + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_CS_OFFSET (0x00000004 + _SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_CS_DONE_ERR_MASK 0x00000400 +#define ADRASTEA_SI_CS_DONE_INT_MASK 0x00000200 +#define ADRASTEA_SI_CS_START_LSB 8 +#define ADRASTEA_SI_CS_START_MASK 0x00000100 +#define ADRASTEA_SI_CS_RX_CNT_LSB 4 +#define ADRASTEA_SI_CS_RX_CNT_MASK 0x000000f0 +#define ADRASTEA_SI_CS_TX_CNT_LSB 0 +#define ADRASTEA_SI_CS_TX_CNT_MASK 0x0000000f +#define ADRASTEA_CE_COUNT 12 +#define ADRASTEA_SR_WR_INDEX_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX \ + - ADRASTEA_CE0_BASE_ADDRESS) +#define ADRASTEA_DST_WATERMARK_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK \ + - ADRASTEA_CE0_BASE_ADDRESS) +#define ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define ADRASTEA_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define ADRASTEA_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define ADRASTEA_RX_MPDU_START_2_PN_47_32_LSB 0 +#define ADRASTEA_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define ADRASTEA_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define ADRASTEA_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define ADRASTEA_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define ADRASTEA_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define ADRASTEA_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff + +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define ADRASTEA_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define ADRASTEA_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define ADRASTEA_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define ADRASTEA_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define ADRASTEA_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 + +#define ADRASTEA_DST_WR_INDEX_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SRC_WATERMARK_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define ADRASTEA_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define ADRASTEA_DST_WATERMARK_LOW_MASK 0xffff0000 +#define ADRASTEA_DST_WATERMARK_HIGH_MASK 0x0000ffff + +#define ADRASTEA_CURRENT_SRRI_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CURRENT_DRRI_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define ADRASTEA_HOST_IS_SRC_RING_LOW_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___M + +#define ADRASTEA_HOST_IS_DST_RING_HIGH_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___M + +#define ADRASTEA_HOST_IS_DST_RING_LOW_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___M + +#define ADRASTEA_HOST_IS_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IS_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IS_COPY_COMPLETE_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___M + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define ADRASTEA_CE_WRAPPER_INDEX_BASE_LOW 0x0004 +#define ADRASTEA_CE_WRAPPER_INDEX_BASE_HIGH 0x0008 + +#define ADRASTEA_HOST_IE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IE_COPY_COMPLETE_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___M + +#define ADRASTEA_SR_BA_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SR_BA_ADDRESS_HIGH_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SR_SIZE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CTRL1_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1 \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CTRL1_DMAX_LENGTH_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___M + +#define ADRASTEA_DR_BA_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_DR_BA_ADDRESS_HIGH_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_DR_SIZE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CMD_REGISTER_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IE_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IS_AXI_ERR_MASK 0x00000100 + +#define ADRASTEA_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 + +#define ADRASTEA_MISC_IS_AXI_TIMEOUT_ERR \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___M + +#define ADRASTEA_MISC_IS_SRC_LEN_ERR_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___M + +#define ADRASTEA_MISC_IS_DST_MAX_LEN_VIO_MASK\ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___M + +#define ADRASTEA_MISC_IS_DST_RING_OVERFLOW_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___M + +#define ADRASTEA_MISC_IS_SRC_RING_OVERFLOW_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___M + +#define ADRASTEA_SRC_WATERMARK_LOW_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___S + +#define ADRASTEA_SRC_WATERMARK_HIGH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_DST_WATERMARK_LOW_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_DST_WATERMARK_HIGH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___M + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___S + +#define ADRASTEA_CE_CTRL1_DMAX_LENGTH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___S + +#define ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___M + +#define ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___M + +#define ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___S + +#define ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___S + +#define ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x0000004 +#define ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define ADRASTEA_SOC_GLOBAL_RESET_ADDRESS \ + (0x0008 + ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS) +#define ADRASTEA_RTC_STATE_ADDRESS \ + (0x0000 + ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS) +#define ADRASTEA_RTC_STATE_COLD_RESET_MASK 0x400 + +#define ADRASTEA_PCIE_SOC_WAKE_RESET 0x00000000 +#define ADRASTEA_PCIE_SOC_WAKE_ADDRESS (ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE) +#define ADRASTEA_PCIE_SOC_WAKE_V_MASK 0x00000001 + +#define ADRASTEA_RTC_STATE_V_MASK 0x00000007 +#define ADRASTEA_RTC_STATE_V_LSB 0 +#define ADRASTEA_RTC_STATE_V_ON 5 +#define ADRASTEA_PCIE_LOCAL_BASE_ADDRESS 0x0 +#define ADRASTEA_FW_IND_EVENT_PENDING 1 +#define ADRASTEA_FW_IND_INITIALIZED 2 +#define ADRASTEA_FW_IND_HELPER 4 + +#define ADRASTEA_PCIE_INTR_FIRMWARE_MASK 0x00000000 +#define ADRASTEA_PCIE_INTR_CE0_MASK 0x00000100 +#define ADRASTEA_PCIE_INTR_CE_MASK_ALL 0x00001ffe + +#define ADRASTEA_CPU_INTR_ADDRESS 0xffffffff +#define ADRASTEA_SOC_LF_TIMER_CONTROL0_ADDRESS 0xffffffff +#define ADRASTEA_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0xffffffff +#define ADRASTEA_SOC_RESET_CONTROL_ADDRESS \ + (0x00000000 + _RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_RESET_CONTROL_CE_RST_MASK 0x0100 +#define ADRASTEA_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define ADRASTEA_CORE_CTRL_ADDRESS (0x0000 + _SOC_CORE_REG_BASE_ADDRESS) +#define ADRASTEA_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define ADRASTEA_LOCAL_SCRATCH_OFFSET 0x00000018 +#define ADRASTEA_CLOCK_GPIO_OFFSET 0xffffffff +#define ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define ADRASTEA_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define ADRASTEA_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define ADRASTEA_SOC_CHIP_ID_VERSION_LSB 18 +#define ADRASTEA_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define ADRASTEA_SOC_CHIP_ID_REVISION_LSB 8 +#define ADRASTEA_SOC_POWER_REG_OFFSET 0x0000010c + +/* Copy Engine Debug */ +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define ADRASTEA_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define ADRASTEA_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_MSB 19 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_LSB 0 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define ADRASTEA_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_MSB 4 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_LSB 0 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define ADRASTEA_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_MSB 4 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_MASK 0x0000001f +#define ADRASTEA_CE_DEBUG_OFFSET 0x0054 +#define ADRASTEA_CE_DEBUG_SEL_MSB 5 +#define ADRASTEA_CE_DEBUG_SEL_LSB 0 +#define ADRASTEA_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define ADRASTEA_EFUSE_OFFSET 0x0000032c +#define ADRASTEA_EFUSE_XTAL_SEL_MSB 10 +#define ADRASTEA_EFUSE_XTAL_SEL_LSB 8 +#define ADRASTEA_EFUSE_XTAL_SEL_MASK 0x00000700 +#define ADRASTEA_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_MSB 17 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_LSB 0 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_MSB 10 +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_LSB 0 +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define ADRASTEA_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define ADRASTEA_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define ADRASTEA_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define ADRASTEA_WLAN_PLL_SETTLE_RESET 0x00000400 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_MSB 9 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_LSB 0 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define ADRASTEA_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define ADRASTEA_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define ADRASTEA_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define ADRASTEA_WLAN_PLL_CONTROL_RESET 0x00010011 +#define ADRASTEA_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define ADRASTEA_RTC_SYNC_STATUS_OFFSET 0x0244 +#define ADRASTEA_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define ADRASTEA_PCIE_INTR_CE_MASK(n) (ADRASTEA_PCIE_INTR_CE0_MASK << (n)) +#define ADRASTEA_DRAM_BASE_ADDRESS ADRASTEA_TARG_DRAM_START +#define ADRASTEA_FW_INDICATOR_ADDRESS \ + (ADRASTEA_WIFICMN_BASE_ADDRESS + ADRASTEA_SCRATCH_3_ADDRESS) +#define ADRASTEA_SYSTEM_SLEEP_OFFSET ADRASTEA_SOC_SYSTEM_SLEEP_OFFSET +#define ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET (0x002c + _WIFI_RTC_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_RESET_CONTROL_OFFSET (0x0000 + _WIFI_RTC_REG_BASE_ADDRESS) +#define ADRASTEA_CLOCK_CONTROL_OFFSET ADRASTEA_SOC_CLOCK_CONTROL_OFFSET +#define ADRASTEA_CLOCK_CONTROL_SI0_CLK_MASK \ + ADRASTEA_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define ADRASTEA_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define ADRASTEA_RESET_CONTROL_SI0_RST_MASK \ + ADRASTEA_SOC_RESET_CONTROL_SI0_RST_MASK +#define ADRASTEA_GPIO_BASE_ADDRESS ADRASTEA_WLAN_GPIO_BASE_ADDRESS +#define ADRASTEA_GPIO_PIN0_OFFSET ADRASTEA_WLAN_GPIO_PIN0_ADDRESS +#define ADRASTEA_GPIO_PIN1_OFFSET ADRASTEA_WLAN_GPIO_PIN1_ADDRESS +#define ADRASTEA_GPIO_PIN0_CONFIG_MASK ADRASTEA_WLAN_GPIO_PIN0_CONFIG_MASK +#define ADRASTEA_GPIO_PIN1_CONFIG_MASK ADRASTEA_WLAN_GPIO_PIN1_CONFIG_MASK +#define ADRASTEA_SI_BASE_ADDRESS 0x00000000 +#define ADRASTEA_CPU_CLOCK_OFFSET (0x20 + _RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_LPO_CAL_OFFSET ADRASTEA_SOC_LPO_CAL_OFFSET +#define ADRASTEA_GPIO_PIN10_OFFSET ADRASTEA_WLAN_GPIO_PIN10_ADDRESS +#define ADRASTEA_GPIO_PIN11_OFFSET ADRASTEA_WLAN_GPIO_PIN11_ADDRESS +#define ADRASTEA_GPIO_PIN12_OFFSET ADRASTEA_WLAN_GPIO_PIN12_ADDRESS +#define ADRASTEA_GPIO_PIN13_OFFSET ADRASTEA_WLAN_GPIO_PIN13_ADDRESS +#define ADRASTEA_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_CPU_CLOCK_STANDARD_MASK 0x1 +#define ADRASTEA_LPO_CAL_ENABLE_LSB ADRASTEA_SOC_LPO_CAL_ENABLE_LSB +#define ADRASTEA_LPO_CAL_ENABLE_MASK ADRASTEA_SOC_LPO_CAL_ENABLE_MASK +#define ADRASTEA_ANALOG_INTF_BASE_ADDRESS ADRASTEA_WLAN_ANALOG_INTF_BASE_ADDRESS +#define ADRASTEA_MBOX_BASE_ADDRESS 0x00008000 +#define ADRASTEA_INT_STATUS_ENABLE_ERROR_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_ERROR_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_CPU_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_CPU_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_ADDRESS MISSING +#define ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_CPU_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_ERROR_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define ADRASTEA_COUNT_DEC_ADDRESS MISSING +#define ADRASTEA_HOST_INT_STATUS_CPU_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_CPU_LSB MISSING +#define ADRASTEA_HOST_INT_STATUS_ERROR_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_ERROR_LSB MISSING +#define ADRASTEA_HOST_INT_STATUS_COUNTER_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_COUNTER_LSB MISSING +#define ADRASTEA_RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define ADRASTEA_WINDOW_DATA_ADDRESS MISSING +#define ADRASTEA_WINDOW_READ_ADDR_ADDRESS MISSING +#define ADRASTEA_WINDOW_WRITE_ADDR_ADDRESS MISSING + +/* Shadow Registers - Start */ +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_0 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_1 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_2 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_3 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_4 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_5 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_6 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_7 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_8 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_9 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_10 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_11 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_12 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_13 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_14 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_15 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_16 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_17 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_18 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_19 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_20 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_21 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_22 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_23 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23 + +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_0 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_1 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_2 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_3 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_4 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_5 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_6 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_7 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_8 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_9 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_10 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_11 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_12 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_13 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_14 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_15 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_16 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_17 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_18 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_19 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_20 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_21 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_22 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_23 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23 + +/* Q6 iHelium emulation registers */ +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 0x00113018 +#define ADRASTEA_A_SOC_CORE_SPARE_1_REGISTER 0x00113184 +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_CLR_GRP1 0x00113020 +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 0x00113010 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_0 0x00130040 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_1 0x00130044 + +#define ADRASTEA_HOST_ENABLE_REGISTER 0x00188000 +#define ADRASTEA_Q6_ENABLE_REGISTER_0 0x00188004 +#define ADRASTEA_Q6_ENABLE_REGISTER_1 0x00188008 +#define ADRASTEA_HOST_CAUSE_REGISTER 0x0018800c +#define ADRASTEA_Q6_CAUSE_REGISTER_0 0x00188010 +#define ADRASTEA_Q6_CAUSE_REGISTER_1 0x00188014 +#define ADRASTEA_HOST_CLEAR_REGISTER 0x00188018 +#define ADRASTEA_Q6_CLEAR_REGISTER_0 0x0018801c +#define ADRASTEA_Q6_CLEAR_REGISTER_1 0x00188020 + +#define ADRASTEA_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA 0x08 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_2 0x0013005C +#ifdef QCA_WIFI_3_0_IHELIUM +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK 0xff +#else +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK 0x0 +#endif /* QCA_WIFI_3_0_IHELIUM */ +/* end: Q6 iHelium emulation registers */ + +struct targetdef_s adrastea_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = ADRASTEA_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = ADRASTEA_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = ADRASTEA_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = ADRASTEA_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = ADRASTEA_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = ADRASTEA_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = ADRASTEA_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = ADRASTEA_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + ADRASTEA_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + ADRASTEA_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = ADRASTEA_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = ADRASTEA_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = ADRASTEA_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = ADRASTEA_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = ADRASTEA_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = ADRASTEA_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = ADRASTEA_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = ADRASTEA_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = ADRASTEA_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = ADRASTEA_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = ADRASTEA_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = ADRASTEA_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = ADRASTEA_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = ADRASTEA_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = ADRASTEA_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = ADRASTEA_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = ADRASTEA_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = ADRASTEA_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = ADRASTEA_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = ADRASTEA_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = ADRASTEA_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = ADRASTEA_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = ADRASTEA_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = ADRASTEA_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = ADRASTEA_SI_CS_START_LSB, + .d_SI_CS_START_MASK = ADRASTEA_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = ADRASTEA_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = ADRASTEA_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = ADRASTEA_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = ADRASTEA_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = ADRASTEA_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = ADRASTEA_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = ADRASTEA_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = ADRASTEA_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = ADRASTEA_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = ADRASTEA_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = ADRASTEA_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = ADRASTEA_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = ADRASTEA_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = ADRASTEA_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = ADRASTEA_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = ADRASTEA_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = ADRASTEA_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = ADRASTEA_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = ADRASTEA_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = ADRASTEA_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = ADRASTEA_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = ADRASTEA_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = ADRASTEA_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = ADRASTEA_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = ADRASTEA_CORE_CTRL_ADDRESS, + .d_CE_COUNT = ADRASTEA_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = ADRASTEA_HOST_ENABLE_REGISTER, + .d_PCIE_INTR_CLR_ADDRESS = ADRASTEA_HOST_CLEAR_REGISTER, + .d_PCIE_INTR_FIRMWARE_MASK = ADRASTEA_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = ADRASTEA_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = ADRASTEA_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = ADRASTEA_SR_WR_INDEX_OFFSET, + .d_DST_WATERMARK_ADDRESS = ADRASTEA_DST_WATERMARK_OFFSET, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = ADRASTEA_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = ADRASTEA_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = ADRASTEA_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + ADRASTEA_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = ADRASTEA_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = ADRASTEA_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = ADRASTEA_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = ADRASTEA_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + ADRASTEA_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + ADRASTEA_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + ADRASTEA_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + ADRASTEA_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + ADRASTEA_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + ADRASTEA_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + + /* PLL start */ + .d_EFUSE_OFFSET = ADRASTEA_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = ADRASTEA_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = ADRASTEA_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = ADRASTEA_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = ADRASTEA_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = ADRASTEA_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = ADRASTEA_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = ADRASTEA_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = ADRASTEA_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = ADRASTEA_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = ADRASTEA_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = ADRASTEA_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = ADRASTEA_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = ADRASTEA_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = ADRASTEA_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = ADRASTEA_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = ADRASTEA_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = ADRASTEA_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + ADRASTEA_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + ADRASTEA_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = ADRASTEA_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = ADRASTEA_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = ADRASTEA_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = ADRASTEA_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = ADRASTEA_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = ADRASTEA_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = ADRASTEA_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = ADRASTEA_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = ADRASTEA_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = ADRASTEA_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = ADRASTEA_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = ADRASTEA_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = ADRASTEA_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = ADRASTEA_HOST_CAUSE_REGISTER, + .d_SOC_RESET_CONTROL_ADDRESS = ADRASTEA_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + ADRASTEA_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + ADRASTEA_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = ADRASTEA_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + ADRASTEA_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + ADRASTEA_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = ADRASTEA_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = ADRASTEA_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = ADRASTEA_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = ADRASTEA_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = ADRASTEA_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ + .d_A_SOC_CORE_SCRATCH_0_ADDRESS = ADRASTEA_A_SOC_CORE_SCRATCH_0_ADDRESS, + .d_A_SOC_CORE_SPARE_0_REGISTER = ADRASTEA_A_SOC_CORE_SPARE_0_REGISTER, + .d_PCIE_INTR_FIRMWARE_ROUTE_MASK = + ADRASTEA_PCIE_INTR_FIRMWARE_ROUTE_MASK, + .d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1, + .d_A_SOC_CORE_SPARE_1_REGISTER = + ADRASTEA_A_SOC_CORE_SPARE_1_REGISTER, + .d_A_SOC_CORE_PCIE_INTR_CLR_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_CLR_GRP1, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1, + .d_A_SOC_PCIE_PCIE_SCRATCH_0 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_0, + .d_A_SOC_PCIE_PCIE_SCRATCH_1 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_1, + .d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA = + ADRASTEA_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA, + .d_A_SOC_PCIE_PCIE_SCRATCH_2 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_2, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK = + ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK, + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = ADRASTEA_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = ADRASTEA_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = ADRASTEA_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = ADRASTEA_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = ADRASTEA_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = ADRASTEA_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = ADRASTEA_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = ADRASTEA_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = ADRASTEA_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = ADRASTEA_AMBA_DEBUG_BUS_SEL_MASK, + +#ifdef QCA_WIFI_3_0_ADRASTEA + .d_Q6_ENABLE_REGISTER_0 = ADRASTEA_Q6_ENABLE_REGISTER_0, + .d_Q6_ENABLE_REGISTER_1 = ADRASTEA_Q6_ENABLE_REGISTER_1, + .d_Q6_CAUSE_REGISTER_0 = ADRASTEA_Q6_CAUSE_REGISTER_0, + .d_Q6_CAUSE_REGISTER_1 = ADRASTEA_Q6_CAUSE_REGISTER_1, + .d_Q6_CLEAR_REGISTER_0 = ADRASTEA_Q6_CLEAR_REGISTER_0, + .d_Q6_CLEAR_REGISTER_1 = ADRASTEA_Q6_CLEAR_REGISTER_1, +#endif +}; + +struct hostdef_s adrastea_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = ADRASTEA_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = ADRASTEA_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = ADRASTEA_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = ADRASTEA_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + ADRASTEA_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + ADRASTEA_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = ADRASTEA_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = ADRASTEA_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = ADRASTEA_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = ADRASTEA_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = ADRASTEA_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = ADRASTEA_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = ADRASTEA_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = ADRASTEA_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = ADRASTEA_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = ADRASTEA_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = ADRASTEA_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = ADRASTEA_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = ADRASTEA_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = ADRASTEA_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = ADRASTEA_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = ADRASTEA_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = ADRASTEA_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = ADRASTEA_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = ADRASTEA_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = ADRASTEA_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = ADRASTEA_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = ADRASTEA_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = ADRASTEA_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = ADRASTEA_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = ADRASTEA_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = ADRASTEA_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = ADRASTEA_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = ADRASTEA_FW_IND_INITIALIZED, + .d_FW_IND_HELPER = ADRASTEA_FW_IND_HELPER, + .d_RTC_STATE_V_ON = ADRASTEA_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + ADRASTEA_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + ADRASTEA_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, + .d_MUX_ID_MASK = 0xf000, + .d_TRANSACTION_ID_MASK = 0x0fff, + .d_DESC_DATA_FLAG_MASK = 0x1FFFE3E0, + .d_A_SOC_PCIE_PCIE_BAR0_START = ADRASTEA_A_SOC_PCIE_PCIE_BAR0_START, +}; + + +struct ce_reg_def adrastea_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = ADRASTEA_DST_WR_INDEX_OFFSET, + .d_SRC_WATERMARK_ADDRESS = ADRASTEA_SRC_WATERMARK_OFFSET, + .d_SRC_WATERMARK_LOW_MASK = ADRASTEA_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = ADRASTEA_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = ADRASTEA_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = ADRASTEA_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = ADRASTEA_CURRENT_SRRI_OFFSET, + .d_CURRENT_DRRI_ADDRESS = ADRASTEA_CURRENT_DRRI_OFFSET, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + ADRASTEA_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + ADRASTEA_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + ADRASTEA_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + ADRASTEA_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = ADRASTEA_HOST_IS_OFFSET, + .d_MISC_IS_ADDRESS = ADRASTEA_MISC_IS_OFFSET, + .d_HOST_IS_COPY_COMPLETE_MASK = ADRASTEA_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = ADRASTEA_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_CE_WRAPPER_INDEX_BASE_LOW = ADRASTEA_CE_WRAPPER_INDEX_BASE_LOW, + .d_CE_WRAPPER_INDEX_BASE_HIGH = ADRASTEA_CE_WRAPPER_INDEX_BASE_HIGH, + .d_HOST_IE_ADDRESS = ADRASTEA_HOST_IE_OFFSET, + .d_HOST_IE_COPY_COMPLETE_MASK = ADRASTEA_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = ADRASTEA_SR_BA_OFFSET, + .d_SR_SIZE_ADDRESS = ADRASTEA_SR_SIZE_OFFSET, + .d_CE_CTRL1_ADDRESS = ADRASTEA_CE_CTRL1_OFFSET, + .d_CE_CTRL1_DMAX_LENGTH_MASK = ADRASTEA_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = ADRASTEA_DR_BA_OFFSET, + .d_DR_SIZE_ADDRESS = ADRASTEA_DR_SIZE_OFFSET, + .d_CE_CMD_REGISTER = ADRASTEA_CE_CMD_REGISTER_OFFSET, + .d_CE_MSI_ADDRESS = MISSING_FOR_ADRASTEA, + .d_CE_MSI_ADDRESS_HIGH = MISSING_FOR_ADRASTEA, + .d_CE_MSI_DATA = MISSING_FOR_ADRASTEA, + .d_CE_MSI_ENABLE_BIT = MISSING_FOR_ADRASTEA, + .d_MISC_IE_ADDRESS = ADRASTEA_MISC_IE_OFFSET, + .d_MISC_IS_AXI_ERR_MASK = ADRASTEA_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = ADRASTEA_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = ADRASTEA_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = ADRASTEA_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + ADRASTEA_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + ADRASTEA_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = ADRASTEA_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = ADRASTEA_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = ADRASTEA_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = ADRASTEA_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = ADRASTEA_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = ADRASTEA_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = ADRASTEA_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = ADRASTEA_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = ADRASTEA_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = ADRASTEA_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = ADRASTEA_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = ADRASTEA_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = ADRASTEA_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = ADRASTEA_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = ADRASTEA_CE1_BASE_ADDRESS, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES = + MISSING_FOR_ADRASTEA, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS = + MISSING_FOR_ADRASTEA, +}; + + +struct host_shadow_regs_s adrastea_host_shadow_regs = { + .d_A_LOCAL_SHADOW_REG_VALUE_0 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_0, + .d_A_LOCAL_SHADOW_REG_VALUE_1 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_1, + .d_A_LOCAL_SHADOW_REG_VALUE_2 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_2, + .d_A_LOCAL_SHADOW_REG_VALUE_3 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_3, + .d_A_LOCAL_SHADOW_REG_VALUE_4 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_4, + .d_A_LOCAL_SHADOW_REG_VALUE_5 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_5, + .d_A_LOCAL_SHADOW_REG_VALUE_6 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_6, + .d_A_LOCAL_SHADOW_REG_VALUE_7 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_7, + .d_A_LOCAL_SHADOW_REG_VALUE_8 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_8, + .d_A_LOCAL_SHADOW_REG_VALUE_9 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_9, + .d_A_LOCAL_SHADOW_REG_VALUE_10 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_10, + .d_A_LOCAL_SHADOW_REG_VALUE_11 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_11, + .d_A_LOCAL_SHADOW_REG_VALUE_12 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_12, + .d_A_LOCAL_SHADOW_REG_VALUE_13 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_13, + .d_A_LOCAL_SHADOW_REG_VALUE_14 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_14, + .d_A_LOCAL_SHADOW_REG_VALUE_15 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_15, + .d_A_LOCAL_SHADOW_REG_VALUE_16 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_16, + .d_A_LOCAL_SHADOW_REG_VALUE_17 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_17, + .d_A_LOCAL_SHADOW_REG_VALUE_18 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_18, + .d_A_LOCAL_SHADOW_REG_VALUE_19 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_19, + .d_A_LOCAL_SHADOW_REG_VALUE_20 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_20, + .d_A_LOCAL_SHADOW_REG_VALUE_21 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_21, + .d_A_LOCAL_SHADOW_REG_VALUE_22 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_22, + .d_A_LOCAL_SHADOW_REG_VALUE_23 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_23, + .d_A_LOCAL_SHADOW_REG_ADDRESS_0 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_0, + .d_A_LOCAL_SHADOW_REG_ADDRESS_1 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_1, + .d_A_LOCAL_SHADOW_REG_ADDRESS_2 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_2, + .d_A_LOCAL_SHADOW_REG_ADDRESS_3 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_3, + .d_A_LOCAL_SHADOW_REG_ADDRESS_4 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_4, + .d_A_LOCAL_SHADOW_REG_ADDRESS_5 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_5, + .d_A_LOCAL_SHADOW_REG_ADDRESS_6 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_6, + .d_A_LOCAL_SHADOW_REG_ADDRESS_7 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_7, + .d_A_LOCAL_SHADOW_REG_ADDRESS_8 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_8, + .d_A_LOCAL_SHADOW_REG_ADDRESS_9 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_9, + .d_A_LOCAL_SHADOW_REG_ADDRESS_10 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_10, + .d_A_LOCAL_SHADOW_REG_ADDRESS_11 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_11, + .d_A_LOCAL_SHADOW_REG_ADDRESS_12 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_12, + .d_A_LOCAL_SHADOW_REG_ADDRESS_13 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_13, + .d_A_LOCAL_SHADOW_REG_ADDRESS_14 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_14, + .d_A_LOCAL_SHADOW_REG_ADDRESS_15 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_15, + .d_A_LOCAL_SHADOW_REG_ADDRESS_16 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_16, + .d_A_LOCAL_SHADOW_REG_ADDRESS_17 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_17, + .d_A_LOCAL_SHADOW_REG_ADDRESS_18 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_18, + .d_A_LOCAL_SHADOW_REG_ADDRESS_19 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_19, + .d_A_LOCAL_SHADOW_REG_ADDRESS_20 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_20, + .d_A_LOCAL_SHADOW_REG_ADDRESS_21 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_21, + .d_A_LOCAL_SHADOW_REG_ADDRESS_22 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_22, + .d_A_LOCAL_SHADOW_REG_ADDRESS_23 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_23 +}; + +#endif /* ADRASTEA_REG_DEF_H */ diff --git a/core/hif/src/ar6320def.h b/core/hif/src/ar6320def.h new file mode 100644 index 0000000000..eacce5d628 --- /dev/null +++ b/core/hif/src/ar6320def.h @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320DEF_H_ +#define _AR6320DEF_H_ + +/* Base Addresses */ +#define AR6320_RTC_SOC_BASE_ADDRESS 0x00000000 +#define AR6320_RTC_WMAC_BASE_ADDRESS 0x00001000 +#define AR6320_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define AR6320_BT_COEX_BASE_ADDRESS 0x00002000 +#define AR6320_SOC_PCIE_BASE_ADDRESS 0x00038000 +#define AR6320_SOC_CORE_BASE_ADDRESS 0x0003a000 +#define AR6320_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR6320_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR6320_WLAN_GPIO_BASE_ADDRESS 0x00005000 +#define AR6320_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00006000 +#define AR6320_WLAN_MAC_BASE_ADDRESS 0x00010000 +#define AR6320_EFUSE_BASE_ADDRESS 0x00024000 +#define AR6320_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR6320_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define AR6320_CE_WRAPPER_BASE_ADDRESS 0x00034000 +#define AR6320_CE0_BASE_ADDRESS 0x00034400 +#define AR6320_CE1_BASE_ADDRESS 0x00034800 +#define AR6320_CE2_BASE_ADDRESS 0x00034c00 +#define AR6320_CE3_BASE_ADDRESS 0x00035000 +#define AR6320_CE4_BASE_ADDRESS 0x00035400 +#define AR6320_CE5_BASE_ADDRESS 0x00035800 +#define AR6320_CE6_BASE_ADDRESS 0x00035c00 +#define AR6320_CE7_BASE_ADDRESS 0x00036000 +#define AR6320_DBI_BASE_ADDRESS 0x0003c000 +#define AR6320_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x00007800 + +#define AR6320_SCRATCH_3_ADDRESS 0x0028 +#define AR6320_TARG_DRAM_START 0x00400000 +#define AR6320_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define AR6320_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR6320_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR6320_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR6320_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000000 +#define AR6320_WLAN_GPIO_PIN0_ADDRESS 0x00000068 +#define AR6320_WLAN_GPIO_PIN1_ADDRESS 0x0000006c +#define AR6320_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR6320_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR6320_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR6320_WLAN_GPIO_PIN10_ADDRESS 0x00000090 +#define AR6320_WLAN_GPIO_PIN11_ADDRESS 0x00000094 +#define AR6320_WLAN_GPIO_PIN12_ADDRESS 0x00000098 +#define AR6320_WLAN_GPIO_PIN13_ADDRESS 0x0000009c +#define AR6320_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR6320_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR6320_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define AR6320_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR6320_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR6320_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR6320_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR6320_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR6320_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR6320_SI_CONFIG_I2C_LSB 16 +#define AR6320_SI_CONFIG_I2C_MASK 0x00010000 +#define AR6320_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR6320_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR6320_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR6320_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR6320_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR6320_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR6320_SI_CONFIG_DIVIDER_LSB 0 +#define AR6320_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR6320_SI_CONFIG_OFFSET 0x00000000 +#define AR6320_SI_TX_DATA0_OFFSET 0x00000008 +#define AR6320_SI_TX_DATA1_OFFSET 0x0000000c +#define AR6320_SI_RX_DATA0_OFFSET 0x00000010 +#define AR6320_SI_RX_DATA1_OFFSET 0x00000014 +#define AR6320_SI_CS_OFFSET 0x00000004 +#define AR6320_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR6320_SI_CS_DONE_INT_MASK 0x00000200 +#define AR6320_SI_CS_START_LSB 8 +#define AR6320_SI_CS_START_MASK 0x00000100 +#define AR6320_SI_CS_RX_CNT_LSB 4 +#define AR6320_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR6320_SI_CS_TX_CNT_LSB 0 +#define AR6320_SI_CS_TX_CNT_MASK 0x0000000f +#define AR6320_CE_COUNT 8 +#define AR6320_SR_WR_INDEX_ADDRESS 0x003c +#define AR6320_DST_WATERMARK_ADDRESS 0x0050 +#define AR6320_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR6320_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR6320_RX_MPDU_START_0_RETRY_LSB 14 +#define AR6320_RX_MPDU_START_0_RETRY_MASK 0x00004000 +#define AR6320_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR6320_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR6320_RX_MPDU_START_2_TID_LSB 28 +#define AR6320_RX_MPDU_START_2_TID_MASK 0xf0000000 +#define AR6320_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR6320_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR6320_RX_MSDU_END_1_KEY_ID_OCT_MASK 0x000000ff +#define AR6320_RX_MSDU_END_1_KEY_ID_OCT_LSB 0 +#define AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR6320_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR6320_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR6320_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR6320_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR6320_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR6320_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR6320_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR6320_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR6320_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR6320_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR6320_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR6320_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR6320_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR6320_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR6320_DST_WR_INDEX_ADDRESS 0x0040 +#define AR6320_SRC_WATERMARK_ADDRESS 0x004c +#define AR6320_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320_CURRENT_SRRI_ADDRESS 0x0044 +#define AR6320_CURRENT_DRRI_ADDRESS 0x0048 +#define AR6320_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR6320_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR6320_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR6320_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR6320_HOST_IS_ADDRESS 0x0030 +#define AR6320_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR6320_HOST_IE_ADDRESS 0x002c +#define AR6320_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR6320_SR_BA_ADDRESS 0x0000 +#define AR6320_SR_SIZE_ADDRESS 0x0004 +#define AR6320_CE_CTRL1_ADDRESS 0x0010 +#define AR6320_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR6320_DR_BA_ADDRESS 0x0008 +#define AR6320_DR_SIZE_ADDRESS 0x000c +#define AR6320_MISC_IE_ADDRESS 0x0034 +#define AR6320_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR6320_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR6320_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR6320_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR6320_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR6320_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR6320_SRC_WATERMARK_LOW_LSB 16 +#define AR6320_SRC_WATERMARK_HIGH_LSB 0 +#define AR6320_DST_WATERMARK_LOW_LSB 16 +#define AR6320_DST_WATERMARK_HIGH_LSB 0 +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR6320_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000020 +#define AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 5 +#define AR6320_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR6320_RTC_STATE_ADDRESS 0x0000 +#define AR6320_RTC_STATE_COLD_RESET_MASK 0x00002000 +#define AR6320_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR6320_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR6320_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR6320_RTC_STATE_V_MASK 0x00000007 +#define AR6320_RTC_STATE_V_LSB 0 +#define AR6320_RTC_STATE_V_ON 3 +#define AR6320_MUX_ID_MASK 0x0000 +#define AR6320_TRANSACTION_ID_MASK 0x3fff +#define AR6320_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR6320_FW_IND_EVENT_PENDING 1 +#define AR6320_FW_IND_INITIALIZED 2 +#define AR6320_FW_IND_HELPER 4 +#define AR6320_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR6320_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR6320_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR6320_PCIE_INTR_CE0_MASK 0x00000800 +#define AR6320_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR6320_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR6320_CPU_INTR_ADDRESS 0x0010 +#define AR6320_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR6320_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR6320_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR6320_SOC_RESET_CONTROL_CE_RST_MASK 0x00000001 +#define AR6320_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR6320_CORE_CTRL_ADDRESS 0x0000 +#define AR6320_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR6320_LOCAL_SCRATCH_OFFSET 0x000000c0 +#define AR6320_CLOCK_GPIO_OFFSET 0xffffffff +#define AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define AR6320_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define AR6320_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define AR6320_SOC_CHIP_ID_VERSION_LSB 18 +#define AR6320_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define AR6320_SOC_CHIP_ID_REVISION_LSB 8 +#define AR6320_SOC_POWER_REG_OFFSET 0x0000010c + +/* Copy Engine Debug */ +#define AR6320_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define AR6320_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define AR6320_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define AR6320_WLAN_DEBUG_OUT_DATA_MSB 19 +#define AR6320_WLAN_DEBUG_OUT_DATA_LSB 0 +#define AR6320_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define AR6320_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define AR6320_AMBA_DEBUG_BUS_SEL_MSB 4 +#define AR6320_AMBA_DEBUG_BUS_SEL_LSB 0 +#define AR6320_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define AR6320_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define AR6320_CE_WRAPPER_DEBUG_SEL_MSB 5 +#define AR6320_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define AR6320_CE_WRAPPER_DEBUG_SEL_MASK 0x0000003f +#define AR6320_CE_DEBUG_OFFSET 0x0054 +#define AR6320_CE_DEBUG_SEL_MSB 5 +#define AR6320_CE_DEBUG_SEL_LSB 0 +#define AR6320_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define AR6320_EFUSE_OFFSET 0x0000032c +#define AR6320_EFUSE_XTAL_SEL_MSB 10 +#define AR6320_EFUSE_XTAL_SEL_LSB 8 +#define AR6320_EFUSE_XTAL_SEL_MASK 0x00000700 +#define AR6320_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define AR6320_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define AR6320_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define AR6320_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define AR6320_BB_PLL_CONFIG_FRAC_MSB 17 +#define AR6320_BB_PLL_CONFIG_FRAC_LSB 0 +#define AR6320_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define AR6320_WLAN_PLL_SETTLE_TIME_MSB 10 +#define AR6320_WLAN_PLL_SETTLE_TIME_LSB 0 +#define AR6320_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define AR6320_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define AR6320_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define AR6320_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define AR6320_WLAN_PLL_SETTLE_RESET 0x00000400 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define AR6320_WLAN_PLL_CONTROL_DIV_MSB 9 +#define AR6320_WLAN_PLL_CONTROL_DIV_LSB 0 +#define AR6320_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define AR6320_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define AR6320_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define AR6320_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define AR6320_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define AR6320_WLAN_PLL_CONTROL_RESET 0x00010011 +#define AR6320_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define AR6320_RTC_SYNC_STATUS_OFFSET 0x0244 +#define AR6320_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define AR6320_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define AR6320_PCIE_INTR_CE_MASK(n) \ + (AR6320_PCIE_INTR_CE0_MASK << (n)) +#define AR6320_DRAM_BASE_ADDRESS AR6320_TARG_DRAM_START +#define AR6320_FW_INDICATOR_ADDRESS \ + (AR6320_SOC_CORE_BASE_ADDRESS + AR6320_SCRATCH_3_ADDRESS) +#define AR6320_SYSTEM_SLEEP_OFFSET AR6320_SOC_SYSTEM_SLEEP_OFFSET +#define AR6320_WLAN_SYSTEM_SLEEP_OFFSET 0x002c +#define AR6320_WLAN_RESET_CONTROL_OFFSET AR6320_SOC_RESET_CONTROL_OFFSET +#define AR6320_CLOCK_CONTROL_OFFSET AR6320_SOC_CLOCK_CONTROL_OFFSET +#define AR6320_CLOCK_CONTROL_SI0_CLK_MASK AR6320_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR6320_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define AR6320_RESET_CONTROL_SI0_RST_MASK AR6320_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR6320_GPIO_BASE_ADDRESS AR6320_WLAN_GPIO_BASE_ADDRESS +#define AR6320_GPIO_PIN0_OFFSET AR6320_WLAN_GPIO_PIN0_ADDRESS +#define AR6320_GPIO_PIN1_OFFSET AR6320_WLAN_GPIO_PIN1_ADDRESS +#define AR6320_GPIO_PIN0_CONFIG_MASK AR6320_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR6320_GPIO_PIN1_CONFIG_MASK AR6320_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR6320_SI_BASE_ADDRESS 0x00050000 +#define AR6320_CPU_CLOCK_OFFSET AR6320_SOC_CPU_CLOCK_OFFSET +#define AR6320_LPO_CAL_OFFSET AR6320_SOC_LPO_CAL_OFFSET +#define AR6320_GPIO_PIN10_OFFSET AR6320_WLAN_GPIO_PIN10_ADDRESS +#define AR6320_GPIO_PIN11_OFFSET AR6320_WLAN_GPIO_PIN11_ADDRESS +#define AR6320_GPIO_PIN12_OFFSET AR6320_WLAN_GPIO_PIN12_ADDRESS +#define AR6320_GPIO_PIN13_OFFSET AR6320_WLAN_GPIO_PIN13_ADDRESS +#define AR6320_CPU_CLOCK_STANDARD_LSB AR6320_SOC_CPU_CLOCK_STANDARD_LSB +#define AR6320_CPU_CLOCK_STANDARD_MASK AR6320_SOC_CPU_CLOCK_STANDARD_MASK +#define AR6320_LPO_CAL_ENABLE_LSB AR6320_SOC_LPO_CAL_ENABLE_LSB +#define AR6320_LPO_CAL_ENABLE_MASK AR6320_SOC_LPO_CAL_ENABLE_MASK +#define AR6320_ANALOG_INTF_BASE_ADDRESS AR6320_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR6320_MBOX_BASE_ADDRESS 0x00008000 +#define AR6320_INT_STATUS_ENABLE_ERROR_LSB 7 +#define AR6320_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define AR6320_INT_STATUS_ENABLE_CPU_LSB 6 +#define AR6320_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define AR6320_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define AR6320_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define AR6320_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define AR6320_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 17 +#define AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 16 +#define AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00010000 +#define AR6320_COUNTER_INT_STATUS_ENABLE_BIT_LSB 24 +#define AR6320_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0xff000000 +#define AR6320_INT_STATUS_ENABLE_ADDRESS 0x0828 +#define AR6320_CPU_INT_STATUS_ENABLE_BIT_LSB 8 +#define AR6320_CPU_INT_STATUS_ENABLE_BIT_MASK 0x0000ff00 +#define AR6320_HOST_INT_STATUS_ADDRESS 0x0800 +#define AR6320_CPU_INT_STATUS_ADDRESS 0x0801 +#define AR6320_ERROR_INT_STATUS_ADDRESS 0x0802 +#define AR6320_ERROR_INT_STATUS_WAKEUP_MASK 0x00040000 +#define AR6320_ERROR_INT_STATUS_WAKEUP_LSB 18 +#define AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 17 +#define AR6320_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00010000 +#define AR6320_ERROR_INT_STATUS_TX_OVERFLOW_LSB 16 +#define AR6320_COUNT_DEC_ADDRESS 0x0840 +#define AR6320_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define AR6320_HOST_INT_STATUS_CPU_LSB 6 +#define AR6320_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define AR6320_HOST_INT_STATUS_ERROR_LSB 7 +#define AR6320_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define AR6320_HOST_INT_STATUS_COUNTER_LSB 4 +#define AR6320_RX_LOOKAHEAD_VALID_ADDRESS 0x0805 +#define AR6320_WINDOW_DATA_ADDRESS 0x0874 +#define AR6320_WINDOW_READ_ADDR_ADDRESS 0x087c +#define AR6320_WINDOW_WRITE_ADDR_ADDRESS 0x0878 + +struct targetdef_s ar6320_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR6320_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR6320_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR6320_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR6320_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR6320_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR6320_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR6320_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR6320_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR6320_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR6320_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR6320_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR6320_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR6320_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR6320_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR6320_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR6320_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR6320_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR6320_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR6320_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR6320_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = AR6320_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR6320_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR6320_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR6320_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR6320_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR6320_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR6320_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR6320_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = AR6320_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR6320_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR6320_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR6320_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR6320_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR6320_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR6320_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR6320_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR6320_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR6320_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR6320_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR6320_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR6320_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR6320_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR6320_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR6320_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR6320_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR6320_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR6320_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR6320_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR6320_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR6320_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR6320_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR6320_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR6320_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR6320_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR6320_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR6320_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR6320_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR6320_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR6320_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR6320_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR6320_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR6320_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR6320_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR6320_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR6320_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR6320_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR6320_CORE_CTRL_ADDRESS, + .d_CE_COUNT = AR6320_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR6320_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR6320_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR6320_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR6320_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = AR6320_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR6320_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR6320_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR6320_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = AR6320_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_RETRY_LSB = AR6320_RX_MPDU_START_0_RETRY_LSB, + .d_RX_MPDU_START_0_RETRY_MASK = AR6320_RX_MPDU_START_0_RETRY_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = AR6320_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR6320_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = AR6320_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR6320_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MPDU_START_2_TID_LSB = AR6320_RX_MPDU_START_2_TID_LSB, + .d_RX_MPDU_START_2_TID_MASK = AR6320_RX_MPDU_START_2_TID_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_MASK = + AR6320_RX_MSDU_END_1_KEY_ID_OCT_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_LSB = AR6320_RX_MSDU_END_1_KEY_ID_OCT_LSB, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = AR6320_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR6320_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR6320_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR6320_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = AR6320_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR6320_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR6320_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR6320_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR6320_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR6320_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR6320_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR6320_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR6320_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR6320_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + /* PLL start */ + .d_EFUSE_OFFSET = AR6320_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = AR6320_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = AR6320_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = AR6320_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = AR6320_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = AR6320_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = AR6320_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = AR6320_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = AR6320_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = AR6320_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = AR6320_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = AR6320_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = AR6320_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = AR6320_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = AR6320_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = AR6320_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = AR6320_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = AR6320_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = AR6320_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = AR6320_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = AR6320_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = AR6320_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = AR6320_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = AR6320_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + AR6320_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = AR6320_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = AR6320_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + AR6320_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + AR6320_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = AR6320_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = AR6320_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = AR6320_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + AR6320_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = AR6320_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = AR6320_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = AR6320_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = AR6320_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = AR6320_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = AR6320_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = AR6320_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = AR6320_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = AR6320_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = AR6320_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = AR6320_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = AR6320_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = AR6320_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = AR6320_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = AR6320_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = AR6320_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = AR6320_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = AR6320_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = AR6320_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR6320_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR6320_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR6320_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR6320_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR6320_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR6320_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = AR6320_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = AR6320_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = AR6320_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = AR6320_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = AR6320_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ + + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = AR6320_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = AR6320_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = AR6320_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = AR6320_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = AR6320_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = AR6320_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = AR6320_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = AR6320_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = AR6320_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = AR6320_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = AR6320_AMBA_DEBUG_BUS_SEL_MASK, + +}; + +struct hostdef_s ar6320_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR6320_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = AR6320_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR6320_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR6320_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR6320_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR6320_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR6320_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR6320_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR6320_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR6320_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR6320_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR6320_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR6320_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR6320_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR6320_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR6320_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = AR6320_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR6320_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR6320_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR6320_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR6320_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR6320_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR6320_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR6320_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR6320_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = AR6320_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR6320_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR6320_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR6320_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR6320_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR6320_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR6320_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR6320_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR6320_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = AR6320_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR6320_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR6320_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR6320_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = AR6320_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR6320_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR6320_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR6320_FW_IND_INITIALIZED, + .d_FW_IND_HELPER = AR6320_FW_IND_HELPER, + .d_RTC_STATE_V_ON = AR6320_RTC_STATE_V_ON, + .d_MUX_ID_MASK = AR6320_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR6320_TRANSACTION_ID_MASK, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR6320_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR6320_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +}; + + +struct ce_reg_def ar6320_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR6320_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR6320_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR6320_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR6320_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR6320_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR6320_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR6320_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR6320_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR6320_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR6320_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR6320_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR6320_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR6320_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR6320_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR6320_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR6320_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR6320_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR6320_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR6320_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR6320_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR6320_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR6320_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR6320_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR6320_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR6320_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR6320_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR6320_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = AR6320_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR6320_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR6320_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR6320_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR6320_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR6320_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR6320_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR6320_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = AR6320_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = AR6320_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = AR6320_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = AR6320_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = AR6320_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = AR6320_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = AR6320_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = AR6320_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = AR6320_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR6320_CE1_BASE_ADDRESS, + +}; + +#endif diff --git a/core/hif/src/ar6320v2def.h b/core/hif/src/ar6320v2def.h new file mode 100644 index 0000000000..1b3b92598f --- /dev/null +++ b/core/hif/src/ar6320v2def.h @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320V2DEF_H_ +#define _AR6320V2DEF_H_ + +/* Base Addresses */ +#define AR6320V2_RTC_SOC_BASE_ADDRESS 0x00000800 +#define AR6320V2_RTC_WMAC_BASE_ADDRESS 0x00001000 +#define AR6320V2_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define AR6320V2_BT_COEX_BASE_ADDRESS 0x00002000 +#define AR6320V2_SOC_PCIE_BASE_ADDRESS 0x00038000 +#define AR6320V2_SOC_CORE_BASE_ADDRESS 0x0003a000 +#define AR6320V2_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR6320V2_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR6320V2_WLAN_GPIO_BASE_ADDRESS 0x00005000 +#define AR6320V2_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00006000 +#define AR6320V2_WLAN_MAC_BASE_ADDRESS 0x00010000 +#define AR6320V2_EFUSE_BASE_ADDRESS 0x00024000 +#define AR6320V2_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR6320V2_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define AR6320V2_CE_WRAPPER_BASE_ADDRESS 0x00034000 +#define AR6320V2_CE0_BASE_ADDRESS 0x00034400 +#define AR6320V2_CE1_BASE_ADDRESS 0x00034800 +#define AR6320V2_CE2_BASE_ADDRESS 0x00034c00 +#define AR6320V2_CE3_BASE_ADDRESS 0x00035000 +#define AR6320V2_CE4_BASE_ADDRESS 0x00035400 +#define AR6320V2_CE5_BASE_ADDRESS 0x00035800 +#define AR6320V2_CE6_BASE_ADDRESS 0x00035c00 +#define AR6320V2_CE7_BASE_ADDRESS 0x00036000 +#define AR6320V2_DBI_BASE_ADDRESS 0x0003c000 +#define AR6320V2_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x00007800 + +#define AR6320V2_SCRATCH_3_ADDRESS 0x0028 +#define AR6320V2_TARG_DRAM_START 0x00400000 +#define AR6320V2_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define AR6320V2_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR6320V2_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR6320V2_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR6320V2_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000000 +#define AR6320V2_WLAN_GPIO_PIN0_ADDRESS 0x00000068 +#define AR6320V2_WLAN_GPIO_PIN1_ADDRESS 0x0000006c +#define AR6320V2_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR6320V2_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR6320V2_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320V2_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR6320V2_WLAN_GPIO_PIN10_ADDRESS 0x00000090 +#define AR6320V2_WLAN_GPIO_PIN11_ADDRESS 0x00000094 +#define AR6320V2_WLAN_GPIO_PIN12_ADDRESS 0x00000098 +#define AR6320V2_WLAN_GPIO_PIN13_ADDRESS 0x0000009c +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR6320V2_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR6320V2_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR6320V2_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR6320V2_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR6320V2_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR6320V2_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR6320V2_SI_CONFIG_I2C_LSB 16 +#define AR6320V2_SI_CONFIG_I2C_MASK 0x00010000 +#define AR6320V2_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR6320V2_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR6320V2_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR6320V2_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR6320V2_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR6320V2_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR6320V2_SI_CONFIG_DIVIDER_LSB 0 +#define AR6320V2_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR6320V2_SI_CONFIG_OFFSET 0x00000000 +#define AR6320V2_SI_TX_DATA0_OFFSET 0x00000008 +#define AR6320V2_SI_TX_DATA1_OFFSET 0x0000000c +#define AR6320V2_SI_RX_DATA0_OFFSET 0x00000010 +#define AR6320V2_SI_RX_DATA1_OFFSET 0x00000014 +#define AR6320V2_SI_CS_OFFSET 0x00000004 +#define AR6320V2_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR6320V2_SI_CS_DONE_INT_MASK 0x00000200 +#define AR6320V2_SI_CS_START_LSB 8 +#define AR6320V2_SI_CS_START_MASK 0x00000100 +#define AR6320V2_SI_CS_RX_CNT_LSB 4 +#define AR6320V2_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR6320V2_SI_CS_TX_CNT_LSB 0 +#define AR6320V2_SI_CS_TX_CNT_MASK 0x0000000f +#define AR6320V2_CE_COUNT 8 +#define AR6320V2_SR_WR_INDEX_ADDRESS 0x003c +#define AR6320V2_DST_WATERMARK_ADDRESS 0x0050 +#define AR6320V2_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR6320V2_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR6320V2_RX_MPDU_START_0_RETRY_LSB 14 +#define AR6320V2_RX_MPDU_START_0_RETRY_MASK 0x00004000 +#define AR6320V2_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR6320V2_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR6320V2_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR6320V2_RX_MPDU_START_2_TID_LSB 28 +#define AR6320V2_RX_MPDU_START_2_TID_MASK 0xf0000000 +#define AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR6320V2_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR6320V2_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR6320V2_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR6320V2_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR6320V2_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR6320V2_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR6320V2_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff + +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR6320V2_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR6320V2_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR6320V2_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR6320V2_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR6320V2_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR6320V2_DST_WR_INDEX_ADDRESS 0x0040 +#define AR6320V2_SRC_WATERMARK_ADDRESS 0x004c +#define AR6320V2_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320V2_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320V2_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320V2_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320V2_CURRENT_SRRI_ADDRESS 0x0044 +#define AR6320V2_CURRENT_DRRI_ADDRESS 0x0048 +#define AR6320V2_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR6320V2_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR6320V2_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR6320V2_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR6320V2_HOST_IS_ADDRESS 0x0030 +#define AR6320V2_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR6320V2_HOST_IE_ADDRESS 0x002c +#define AR6320V2_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR6320V2_SR_BA_ADDRESS 0x0000 +#define AR6320V2_SR_SIZE_ADDRESS 0x0004 +#define AR6320V2_CE_CTRL1_ADDRESS 0x0010 +#define AR6320V2_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR6320V2_DR_BA_ADDRESS 0x0008 +#define AR6320V2_DR_SIZE_ADDRESS 0x000c +#define AR6320V2_MISC_IE_ADDRESS 0x0034 +#define AR6320V2_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR6320V2_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR6320V2_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR6320V2_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR6320V2_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR6320V2_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR6320V2_SRC_WATERMARK_LOW_LSB 16 +#define AR6320V2_SRC_WATERMARK_HIGH_LSB 0 +#define AR6320V2_DST_WATERMARK_LOW_LSB 16 +#define AR6320V2_DST_WATERMARK_HIGH_LSB 0 +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR6320V2_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000020 +#define AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 5 +#define AR6320V2_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR6320V2_RTC_STATE_ADDRESS 0x0000 +#define AR6320V2_RTC_STATE_COLD_RESET_MASK 0x00002000 +#define AR6320V2_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR6320V2_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR6320V2_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR6320V2_RTC_STATE_V_MASK 0x00000007 +#define AR6320V2_RTC_STATE_V_LSB 0 +#define AR6320V2_RTC_STATE_V_ON 3 +#define AR6320V2_MUX_ID_MASK 0x0000 +#define AR6320V2_TRANSACTION_ID_MASK 0x3fff +#define AR6320V2_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR6320V2_FW_IND_EVENT_PENDING 1 +#define AR6320V2_FW_IND_INITIALIZED 2 +#define AR6320V2_FW_IND_HELPER 4 +#define AR6320V2_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR6320V2_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR6320V2_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR6320V2_PCIE_INTR_CE0_MASK 0x00000800 +#define AR6320V2_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR6320V2_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR6320V2_CPU_INTR_ADDRESS 0x0010 +#define AR6320V2_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR6320V2_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR6320V2_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR6320V2_SOC_RESET_CONTROL_CE_RST_MASK 0x00000001 +#define AR6320V2_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR6320V2_CORE_CTRL_ADDRESS 0x0000 +#define AR6320V2_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR6320V2_LOCAL_SCRATCH_OFFSET 0x000000c0 +#define AR6320V2_CLOCK_GPIO_OFFSET 0xffffffff +#define AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define AR6320V2_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define AR6320V2_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define AR6320V2_SOC_CHIP_ID_VERSION_LSB 18 +#define AR6320V2_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define AR6320V2_SOC_CHIP_ID_REVISION_LSB 8 +#define AR6320V2_SOC_POWER_REG_OFFSET 0x0000010c + +/* Copy Engine Debug */ +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define AR6320V2_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define AR6320V2_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_MSB 19 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_LSB 0 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define AR6320V2_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_MSB 4 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_LSB 0 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define AR6320V2_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_MSB 5 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_MASK 0x0000003f +#define AR6320V2_CE_DEBUG_OFFSET 0x0054 +#define AR6320V2_CE_DEBUG_SEL_MSB 5 +#define AR6320V2_CE_DEBUG_SEL_LSB 0 +#define AR6320V2_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define AR6320V2_EFUSE_OFFSET 0x0000032c +#define AR6320V2_EFUSE_XTAL_SEL_MSB 10 +#define AR6320V2_EFUSE_XTAL_SEL_LSB 8 +#define AR6320V2_EFUSE_XTAL_SEL_MASK 0x00000700 +#define AR6320V2_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define AR6320V2_BB_PLL_CONFIG_FRAC_MSB 17 +#define AR6320V2_BB_PLL_CONFIG_FRAC_LSB 0 +#define AR6320V2_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define AR6320V2_WLAN_PLL_SETTLE_TIME_MSB 10 +#define AR6320V2_WLAN_PLL_SETTLE_TIME_LSB 0 +#define AR6320V2_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define AR6320V2_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define AR6320V2_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define AR6320V2_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define AR6320V2_WLAN_PLL_SETTLE_RESET 0x00000400 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_MSB 9 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_LSB 0 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define AR6320V2_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define AR6320V2_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define AR6320V2_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define AR6320V2_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define AR6320V2_WLAN_PLL_CONTROL_RESET 0x00010011 +#define AR6320V2_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define AR6320V2_RTC_SYNC_STATUS_OFFSET 0x0244 +#define AR6320V2_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define AR6320V2_PCIE_INTR_CE_MASK(n) \ + (AR6320V2_PCIE_INTR_CE0_MASK << (n)) +#define AR6320V2_DRAM_BASE_ADDRESS AR6320V2_TARG_DRAM_START +#define AR6320V2_FW_INDICATOR_ADDRESS \ + (AR6320V2_SOC_CORE_BASE_ADDRESS + AR6320V2_SCRATCH_3_ADDRESS) +#define AR6320V2_SYSTEM_SLEEP_OFFSET AR6320V2_SOC_SYSTEM_SLEEP_OFFSET +#define AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET 0x002c +#define AR6320V2_WLAN_RESET_CONTROL_OFFSET AR6320V2_SOC_RESET_CONTROL_OFFSET +#define AR6320V2_CLOCK_CONTROL_OFFSET AR6320V2_SOC_CLOCK_CONTROL_OFFSET +#define AR6320V2_CLOCK_CONTROL_SI0_CLK_MASK \ + AR6320V2_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR6320V2_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define AR6320V2_RESET_CONTROL_SI0_RST_MASK \ + AR6320V2_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR6320V2_GPIO_BASE_ADDRESS AR6320V2_WLAN_GPIO_BASE_ADDRESS +#define AR6320V2_GPIO_PIN0_OFFSET AR6320V2_WLAN_GPIO_PIN0_ADDRESS +#define AR6320V2_GPIO_PIN1_OFFSET AR6320V2_WLAN_GPIO_PIN1_ADDRESS +#define AR6320V2_GPIO_PIN0_CONFIG_MASK AR6320V2_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR6320V2_GPIO_PIN1_CONFIG_MASK AR6320V2_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR6320V2_SI_BASE_ADDRESS 0x00050000 +#define AR6320V2_CPU_CLOCK_OFFSET AR6320V2_SOC_CPU_CLOCK_OFFSET +#define AR6320V2_LPO_CAL_OFFSET AR6320V2_SOC_LPO_CAL_OFFSET +#define AR6320V2_GPIO_PIN10_OFFSET AR6320V2_WLAN_GPIO_PIN10_ADDRESS +#define AR6320V2_GPIO_PIN11_OFFSET AR6320V2_WLAN_GPIO_PIN11_ADDRESS +#define AR6320V2_GPIO_PIN12_OFFSET AR6320V2_WLAN_GPIO_PIN12_ADDRESS +#define AR6320V2_GPIO_PIN13_OFFSET AR6320V2_WLAN_GPIO_PIN13_ADDRESS +#define AR6320V2_CPU_CLOCK_STANDARD_LSB AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB +#define AR6320V2_CPU_CLOCK_STANDARD_MASK AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK +#define AR6320V2_LPO_CAL_ENABLE_LSB AR6320V2_SOC_LPO_CAL_ENABLE_LSB +#define AR6320V2_LPO_CAL_ENABLE_MASK AR6320V2_SOC_LPO_CAL_ENABLE_MASK +#define AR6320V2_ANALOG_INTF_BASE_ADDRESS \ + AR6320V2_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR6320V2_MBOX_BASE_ADDRESS 0x00008000 +#define AR6320V2_INT_STATUS_ENABLE_ERROR_LSB 7 +#define AR6320V2_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define AR6320V2_INT_STATUS_ENABLE_CPU_LSB 6 +#define AR6320V2_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define AR6320V2_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define AR6320V2_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 17 +#define AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 16 +#define AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00010000 +#define AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_LSB 24 +#define AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0xff000000 +#define AR6320V2_INT_STATUS_ENABLE_ADDRESS 0x0828 +#define AR6320V2_CPU_INT_STATUS_ENABLE_BIT_LSB 8 +#define AR6320V2_CPU_INT_STATUS_ENABLE_BIT_MASK 0x0000ff00 +#define AR6320V2_HOST_INT_STATUS_ADDRESS 0x0800 +#define AR6320V2_CPU_INT_STATUS_ADDRESS 0x0801 +#define AR6320V2_ERROR_INT_STATUS_ADDRESS 0x0802 +#define AR6320V2_ERROR_INT_STATUS_WAKEUP_MASK 0x00040000 +#define AR6320V2_ERROR_INT_STATUS_WAKEUP_LSB 18 +#define AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 17 +#define AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00010000 +#define AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_LSB 16 +#define AR6320V2_COUNT_DEC_ADDRESS 0x0840 +#define AR6320V2_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define AR6320V2_HOST_INT_STATUS_CPU_LSB 6 +#define AR6320V2_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define AR6320V2_HOST_INT_STATUS_ERROR_LSB 7 +#define AR6320V2_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define AR6320V2_HOST_INT_STATUS_COUNTER_LSB 4 +#define AR6320V2_RX_LOOKAHEAD_VALID_ADDRESS 0x0805 +#define AR6320V2_WINDOW_DATA_ADDRESS 0x0874 +#define AR6320V2_WINDOW_READ_ADDR_ADDRESS 0x087c +#define AR6320V2_WINDOW_WRITE_ADDR_ADDRESS 0x0878 + +struct targetdef_s ar6320v2_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR6320V2_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR6320V2_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR6320V2_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR6320V2_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR6320V2_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR6320V2_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR6320V2_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR6320V2_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR6320V2_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR6320V2_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR6320V2_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR6320V2_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR6320V2_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR6320V2_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR6320V2_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR6320V2_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = + AR6320V2_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR6320V2_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR6320V2_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR6320V2_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR6320V2_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR6320V2_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR6320V2_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR6320V2_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = + AR6320V2_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR6320V2_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR6320V2_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR6320V2_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR6320V2_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR6320V2_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR6320V2_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR6320V2_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR6320V2_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR6320V2_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR6320V2_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR6320V2_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR6320V2_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR6320V2_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR6320V2_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR6320V2_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR6320V2_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR6320V2_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR6320_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR6320_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR6320V2_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR6320V2_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR6320V2_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR6320V2_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR6320V2_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR6320V2_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR6320V2_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR6320V2_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR6320V2_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR6320V2_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR6320V2_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR6320V2_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR6320V2_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = + AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR6320V2_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR6320V2_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR6320V2_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR6320V2_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR6320V2_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR6320V2_CORE_CTRL_ADDRESS, + .d_CE_COUNT = AR6320V2_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR6320V2_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR6320V2_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR6320V2_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR6320V2_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = AR6320V2_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR6320V2_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR6320V2_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR6320V2_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = + AR6320V2_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_RETRY_MASK = + AR6320V2_RX_MPDU_START_0_RETRY_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = + AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = + AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR6320V2_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = + AR6320V2_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR6320V2_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MPDU_START_2_TID_LSB = + AR6320V2_RX_MPDU_START_2_TID_LSB, + .d_RX_MPDU_START_2_TID_MASK = + AR6320V2_RX_MPDU_START_2_TID_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = + AR6320V2_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR6320V2_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR6320V2_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR6320V2_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = + AR6320V2_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR6320V2_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR6320V2_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR6320V2_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR6320V2_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR6320V2_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR6320V2_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR6320V2_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + /* PLL start */ + .d_EFUSE_OFFSET = AR6320V2_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = AR6320V2_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = AR6320V2_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = AR6320V2_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = AR6320V2_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = AR6320V2_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = AR6320V2_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = AR6320V2_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = AR6320V2_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = AR6320V2_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = AR6320V2_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = AR6320V2_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = AR6320V2_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = AR6320V2_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = AR6320V2_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = AR6320V2_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = AR6320V2_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = AR6320V2_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = AR6320V2_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = AR6320V2_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = AR6320V2_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = AR6320V2_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = AR6320V2_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = + AR6320V2_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + AR6320V2_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = AR6320V2_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = AR6320V2_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = + AR6320V2_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + AR6320V2_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = AR6320V2_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = AR6320V2_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = AR6320V2_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = AR6320V2_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = AR6320V2_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = AR6320V2_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = AR6320V2_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = AR6320V2_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = AR6320V2_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = AR6320V2_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = AR6320V2_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = AR6320V2_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = AR6320V2_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = AR6320V2_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = AR6320V2_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = AR6320V2_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = AR6320V2_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR6320V2_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR6320V2_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR6320V2_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR6320V2_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR6320V2_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR6320V2_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = AR6320V2_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = AR6320V2_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = AR6320V2_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = AR6320V2_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = AR6320V2_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ + + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = AR6320V2_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = AR6320V2_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = AR6320V2_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = AR6320V2_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = AR6320V2_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = AR6320V2_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = AR6320V2_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = AR6320V2_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = AR6320V2_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = AR6320V2_AMBA_DEBUG_BUS_SEL_MASK, +}; + +struct hostdef_s ar6320v2_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR6320V2_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = + AR6320V2_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR6320V2_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR6320V2_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR6320V2_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR6320V2_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR6320V2_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR6320V2_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR6320V2_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR6320V2_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR6320V2_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR6320V2_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = + AR6320V2_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR6320V2_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR6320V2_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR6320V2_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR6320V2_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR6320V2_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR6320V2_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = + AR6320V2_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR6320V2_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR6320V2_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR6320V2_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR6320V2_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR6320V2_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR6320V2_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR6320V2_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR6320V2_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = AR6320V2_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR6320V2_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR6320V2_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR6320V2_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = AR6320V2_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR6320V2_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR6320V2_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR6320V2_FW_IND_INITIALIZED, + .d_FW_IND_HELPER = AR6320V2_FW_IND_HELPER, + .d_RTC_STATE_V_ON = AR6320V2_RTC_STATE_V_ON, + .d_MUX_ID_MASK = AR6320V2_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR6320V2_TRANSACTION_ID_MASK, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR6320V2_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR6320V2_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +}; + +struct ce_reg_def ar6320v2_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR6320V2_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR6320V2_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR6320V2_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR6320V2_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR6320V2_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR6320V2_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR6320V2_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR6320V2_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR6320V2_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR6320V2_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR6320V2_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR6320V2_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR6320V2_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR6320V2_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR6320V2_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR6320V2_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR6320V2_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR6320V2_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR6320V2_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR6320V2_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR6320V2_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR6320V2_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR6320V2_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR6320V2_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR6320V2_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR6320V2_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR6320V2_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = + AR6320V2_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR6320V2_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR6320V2_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR6320V2_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR6320V2_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR6320V2_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR6320V2_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR6320V2_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = AR6320V2_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = AR6320V2_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = AR6320V2_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = AR6320V2_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = AR6320V2_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = AR6320V2_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = AR6320V2_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = AR6320V2_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = AR6320V2_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR6320V2_CE1_BASE_ADDRESS, + +}; + +#endif diff --git a/core/hif/src/ar9888def.h b/core/hif/src/ar9888def.h new file mode 100644 index 0000000000..fd9987b6f8 --- /dev/null +++ b/core/hif/src/ar9888def.h @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR9888DEF_H_ +#define AR9888__AR9888DEF_H_ + +/* Base Addresses */ +#define AR9888_RTC_SOC_BASE_ADDRESS 0x00004000 +#define AR9888_RTC_WMAC_BASE_ADDRESS 0x00005000 +#define AR9888_MAC_COEX_BASE_ADDRESS 0x00006000 +#define AR9888_BT_COEX_BASE_ADDRESS 0x00007000 +#define AR9888_SOC_PCIE_BASE_ADDRESS 0x00008000 +#define AR9888_SOC_CORE_BASE_ADDRESS 0x00009000 +#define AR9888_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR9888_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR9888_WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 +#define AR9888_WLAN_MAC_BASE_ADDRESS 0x00020000 +#define AR9888_EFUSE_BASE_ADDRESS 0x00030000 +#define AR9888_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR9888_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define AR9888_CE_WRAPPER_BASE_ADDRESS 0x00057000 +#define AR9888_CE0_BASE_ADDRESS 0x00057400 +#define AR9888_CE1_BASE_ADDRESS 0x00057800 +#define AR9888_CE2_BASE_ADDRESS 0x00057c00 +#define AR9888_CE3_BASE_ADDRESS 0x00058000 +#define AR9888_CE4_BASE_ADDRESS 0x00058400 +#define AR9888_CE5_BASE_ADDRESS 0x00058800 +#define AR9888_CE6_BASE_ADDRESS 0x00058c00 +#define AR9888_CE7_BASE_ADDRESS 0x00059000 +#define AR9888_DBI_BASE_ADDRESS 0x00060000 +#define AR9888_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 + +#define AR9888_SCRATCH_3_ADDRESS 0x0030 +#define AR9888_TARG_DRAM_START 0x00400000 +#define AR9888_SOC_SYSTEM_SLEEP_OFFSET 0x000000c4 +#define AR9888_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR9888_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR9888_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR9888_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define AR9888_WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define AR9888_WLAN_GPIO_PIN0_ADDRESS 0x00000028 +#define AR9888_WLAN_GPIO_PIN1_ADDRESS 0x0000002c +#define AR9888_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR9888_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR9888_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR9888_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR9888_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR9888_WLAN_GPIO_PIN10_ADDRESS 0x00000050 +#define AR9888_WLAN_GPIO_PIN11_ADDRESS 0x00000054 +#define AR9888_WLAN_GPIO_PIN12_ADDRESS 0x00000058 +#define AR9888_WLAN_GPIO_PIN13_ADDRESS 0x0000005c +#define AR9888_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR9888_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR9888_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR9888_SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 + +#define AR9888_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR9888_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR9888_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR9888_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR9888_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR9888_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR9888_SI_CONFIG_I2C_LSB 16 +#define AR9888_SI_CONFIG_I2C_MASK 0x00010000 +#define AR9888_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR9888_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR9888_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR9888_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR9888_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR9888_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR9888_SI_CONFIG_DIVIDER_LSB 0 +#define AR9888_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR9888_SI_CONFIG_OFFSET 0x00000000 +#define AR9888_SI_TX_DATA0_OFFSET 0x00000008 +#define AR9888_SI_TX_DATA1_OFFSET 0x0000000c +#define AR9888_SI_RX_DATA0_OFFSET 0x00000010 +#define AR9888_SI_RX_DATA1_OFFSET 0x00000014 +#define AR9888_SI_CS_OFFSET 0x00000004 +#define AR9888_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR9888_SI_CS_DONE_INT_MASK 0x00000200 +#define AR9888_SI_CS_START_LSB 8 +#define AR9888_SI_CS_START_MASK 0x00000100 +#define AR9888_SI_CS_RX_CNT_LSB 4 +#define AR9888_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR9888_SI_CS_TX_CNT_LSB 0 +#define AR9888_SI_CS_TX_CNT_MASK 0x0000000f +#define AR9888_CE_COUNT 8 +#define AR9888_SR_WR_INDEX_ADDRESS 0x003c +#define AR9888_DST_WATERMARK_ADDRESS 0x0050 +#define AR9888_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR9888_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR9888_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR9888_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR9888_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR9888_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR9888_RX_MSDU_END_1_KEY_ID_OCT_MASK 0x000000ff +#define AR9888_RX_MSDU_END_1_KEY_ID_OCT_LSB 0 +#define AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR9888_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR9888_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR9888_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR9888_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR9888_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR9888_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR9888_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR9888_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR9888_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR9888_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR9888_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR9888_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR9888_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR9888_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR9888_DST_WR_INDEX_ADDRESS 0x0040 +#define AR9888_SRC_WATERMARK_ADDRESS 0x004c +#define AR9888_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR9888_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR9888_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR9888_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR9888_CURRENT_SRRI_ADDRESS 0x0044 +#define AR9888_CURRENT_DRRI_ADDRESS 0x0048 +#define AR9888_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR9888_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR9888_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR9888_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR9888_HOST_IS_ADDRESS 0x0030 +#define AR9888_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR9888_HOST_IE_ADDRESS 0x002c +#define AR9888_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR9888_SR_BA_ADDRESS 0x0000 +#define AR9888_SR_SIZE_ADDRESS 0x0004 +#define AR9888_CE_CTRL1_ADDRESS 0x0010 +#define AR9888_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR9888_DR_BA_ADDRESS 0x0008 +#define AR9888_DR_SIZE_ADDRESS 0x000c +#define AR9888_MISC_IE_ADDRESS 0x0034 +#define AR9888_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR9888_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR9888_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR9888_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR9888_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR9888_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR9888_SRC_WATERMARK_LOW_LSB 16 +#define AR9888_SRC_WATERMARK_HIGH_LSB 0 +#define AR9888_DST_WATERMARK_LOW_LSB 16 +#define AR9888_DST_WATERMARK_HIGH_LSB 0 +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR9888_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000004 +#define AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define AR9888_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR9888_RTC_STATE_ADDRESS 0x0000 +#define AR9888_RTC_STATE_COLD_RESET_MASK 0x00000400 +#define AR9888_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR9888_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR9888_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR9888_RTC_STATE_V_MASK 0x00000007 +#define AR9888_RTC_STATE_V_LSB 0 +#define AR9888_RTC_STATE_V_ON 3 +#define AR9888_MUX_ID_MASK 0x0000 +#define AR9888_TRANSACTION_ID_MASK 0x3fff +#define AR9888_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR9888_FW_IND_EVENT_PENDING 1 +#define AR9888_FW_IND_INITIALIZED 2 +#define AR9888_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR9888_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR9888_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR9888_PCIE_INTR_CE0_MASK 0x00000800 +#define AR9888_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR9888_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR9888_CPU_INTR_ADDRESS 0x0010 +#define AR9888_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR9888_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR9888_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR9888_SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define AR9888_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR9888_CORE_CTRL_ADDRESS 0x0000 +#define AR9888_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR9888_LOCAL_SCRATCH_OFFSET 0x18 +#define AR9888_CLOCK_GPIO_OFFSET 0xffffffff +#define AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 + +#define AR9888_PCIE_INTR_CE_MASK(n) (AR9888_PCIE_INTR_CE0_MASK << (n)) +#define AR9888_FW_EVENT_PENDING_ADDRESS \ + (AR9888_SOC_CORE_BASE_ADDRESS + AR9888_SCRATCH_3_ADDRESS) +#define AR9888_DRAM_BASE_ADDRESS AR9888_TARG_DRAM_START +#define AR9888_FW_INDICATOR_ADDRESS \ + (AR9888_SOC_CORE_BASE_ADDRESS + AR9888_SCRATCH_3_ADDRESS) +#define AR9888_SYSTEM_SLEEP_OFFSET AR9888_SOC_SYSTEM_SLEEP_OFFSET +#define AR9888_WLAN_SYSTEM_SLEEP_OFFSET AR9888_SOC_SYSTEM_SLEEP_OFFSET +#define AR9888_WLAN_RESET_CONTROL_OFFSET AR9888_SOC_RESET_CONTROL_OFFSET +#define AR9888_CLOCK_CONTROL_OFFSET AR9888_SOC_CLOCK_CONTROL_OFFSET +#define AR9888_CLOCK_CONTROL_SI0_CLK_MASK AR9888_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR9888_RESET_CONTROL_MBOX_RST_MASK MISSING +#define AR9888_RESET_CONTROL_SI0_RST_MASK AR9888_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR9888_GPIO_BASE_ADDRESS AR9888_WLAN_GPIO_BASE_ADDRESS +#define AR9888_GPIO_PIN0_OFFSET AR9888_WLAN_GPIO_PIN0_ADDRESS +#define AR9888_GPIO_PIN1_OFFSET AR9888_WLAN_GPIO_PIN1_ADDRESS +#define AR9888_GPIO_PIN0_CONFIG_MASK AR9888_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR9888_GPIO_PIN1_CONFIG_MASK AR9888_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR9888_SI_BASE_ADDRESS AR9888_WLAN_SI_BASE_ADDRESS +#define AR9888_SCRATCH_BASE_ADDRESS AR9888_SOC_CORE_BASE_ADDRESS +#define AR9888_CPU_CLOCK_OFFSET AR9888_SOC_CPU_CLOCK_OFFSET +#define AR9888_LPO_CAL_OFFSET AR9888_SOC_LPO_CAL_OFFSET +#define AR9888_GPIO_PIN10_OFFSET AR9888_WLAN_GPIO_PIN10_ADDRESS +#define AR9888_GPIO_PIN11_OFFSET AR9888_WLAN_GPIO_PIN11_ADDRESS +#define AR9888_GPIO_PIN12_OFFSET AR9888_WLAN_GPIO_PIN12_ADDRESS +#define AR9888_GPIO_PIN13_OFFSET AR9888_WLAN_GPIO_PIN13_ADDRESS +#define AR9888_CPU_CLOCK_STANDARD_LSB AR9888_SOC_CPU_CLOCK_STANDARD_LSB +#define AR9888_CPU_CLOCK_STANDARD_MASK AR9888_SOC_CPU_CLOCK_STANDARD_MASK +#define AR9888_LPO_CAL_ENABLE_LSB AR9888_SOC_LPO_CAL_ENABLE_LSB +#define AR9888_LPO_CAL_ENABLE_MASK AR9888_SOC_LPO_CAL_ENABLE_MASK +#define AR9888_ANALOG_INTF_BASE_ADDRESS AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR9888_MBOX_BASE_ADDRESS MISSING +#define AR9888_INT_STATUS_ENABLE_ERROR_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_ERROR_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_CPU_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_CPU_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define AR9888_COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define AR9888_COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_ADDRESS MISSING +#define AR9888_CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define AR9888_CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define AR9888_HOST_INT_STATUS_ADDRESS MISSING +#define AR9888_CPU_INT_STATUS_ADDRESS MISSING +#define AR9888_ERROR_INT_STATUS_ADDRESS MISSING +#define AR9888_ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define AR9888_ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define AR9888_ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define AR9888_ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define AR9888_COUNT_DEC_ADDRESS MISSING +#define AR9888_HOST_INT_STATUS_CPU_MASK MISSING +#define AR9888_HOST_INT_STATUS_CPU_LSB MISSING +#define AR9888_HOST_INT_STATUS_ERROR_MASK MISSING +#define AR9888_HOST_INT_STATUS_ERROR_LSB MISSING +#define AR9888_HOST_INT_STATUS_COUNTER_MASK MISSING +#define AR9888_HOST_INT_STATUS_COUNTER_LSB MISSING +#define AR9888_RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define AR9888_WINDOW_DATA_ADDRESS MISSING +#define AR9888_WINDOW_READ_ADDR_ADDRESS MISSING +#define AR9888_WINDOW_WRITE_ADDR_ADDRESS MISSING + +struct targetdef_s ar9888_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR9888_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR9888_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR9888_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR9888_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR9888_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR9888_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR9888_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR9888_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR9888_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR9888_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR9888_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR9888_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR9888_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR9888_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR9888_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR9888_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR9888_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR9888_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR9888_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR9888_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = AR9888_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR9888_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR9888_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR9888_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR9888_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR9888_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR9888_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR9888_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = AR9888_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR9888_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR9888_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR9888_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR9888_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR9888_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR9888_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR9888_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR9888_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR9888_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR9888_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR9888_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR9888_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR9888_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR9888_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR9888_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR9888_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR9888_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR9888_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR9888_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR9888_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR9888_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR9888_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR9888_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR9888_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR9888_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR9888_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR9888_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR9888_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR9888_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR9888_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR9888_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR9888_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR9888_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR9888_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR9888_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR9888_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR9888_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR9888_CORE_CTRL_ADDRESS, + .d_CE_COUNT = AR9888_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR9888_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR9888_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR9888_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR9888_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = AR9888_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR9888_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR9888_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR9888_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = AR9888_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = AR9888_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR9888_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = AR9888_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR9888_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_1_KEY_ID_OCT_MASK = + AR9888_RX_MSDU_END_1_KEY_ID_OCT_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_LSB = AR9888_RX_MSDU_END_1_KEY_ID_OCT_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = AR9888_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR9888_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR9888_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR9888_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = AR9888_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR9888_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR9888_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR9888_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR9888_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR9888_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR9888_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR9888_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR9888_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR9888_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + + .d_PCIE_INTR_CAUSE_ADDRESS = AR9888_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR9888_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR9888_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR9888_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR9888_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR9888_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR9888_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, +}; + +struct hostdef_s ar9888_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR9888_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = AR9888_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR9888_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR9888_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR9888_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR9888_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR9888_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR9888_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR9888_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR9888_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR9888_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR9888_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR9888_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR9888_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR9888_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR9888_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = AR9888_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR9888_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR9888_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR9888_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR9888_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR9888_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR9888_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR9888_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR9888_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = AR9888_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR9888_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR9888_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR9888_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR9888_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR9888_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR9888_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR9888_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR9888_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = AR9888_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR9888_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR9888_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR9888_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = AR9888_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR9888_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR9888_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR9888_FW_IND_INITIALIZED, + .d_RTC_STATE_V_ON = AR9888_RTC_STATE_V_ON, + .d_MUX_ID_MASK = AR9888_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR9888_TRANSACTION_ID_MASK, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR9888_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR9888_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +}; + + +struct ce_reg_def ar9888_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR9888_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR9888_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR9888_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR9888_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR9888_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR9888_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR9888_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR9888_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR9888_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR9888_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR9888_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR9888_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR9888_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR9888_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR9888_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR9888_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR9888_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR9888_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR9888_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR9888_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR9888_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR9888_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR9888_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR9888_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR9888_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR9888_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR9888_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = AR9888_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR9888_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR9888_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR9888_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR9888_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR9888_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR9888_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR9888_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE0_BASE_ADDRESS = AR9888_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR9888_CE1_BASE_ADDRESS, + +}; +#endif diff --git a/core/hif/src/ath_procfs.c b/core/hif/src/ath_procfs.c new file mode 100644 index 0000000000..48b3021e14 --- /dev/null +++ b/core/hif/src/ath_procfs.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT) +#include /* Specifically, a module */ +#include /* We're doing kernel work */ +#include /* We're doing kernel work */ +#include /* Necessary because we use the proc fs */ +#include /* for copy_from_user */ +#include "ol_if_athvar.h" +#include "hif.h" +#if defined(HIF_PCI) +#include "if_pci.h" +#elif defined(HIF_USB) +#include "if_usb.h" +#elif defined(HIF_SDIO) +#include "if_ath_sdio.h" +#endif +#include "cds_api.h" +#include "hif_debug.h" + +#define PROCFS_NAME "athdiagpfs" +#define PROCFS_DIR "cld" + +/** + * This structure hold information about the /proc file + * + */ +static struct proc_dir_entry *proc_file, *proc_dir; + +static void *get_hif_hdl_from_file(struct file *file) +{ + struct ol_softc *scn; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + scn = (struct ol_softc *)PDE_DATA(file_inode(file)); +#else + scn = (struct ol_softc *)( + PDE(file->f_path.dentry->d_inode)->data); +#endif + return (void *)scn; +} + +static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + hif_handle_t hif_hdl; + int rv; + uint8_t *read_buffer = NULL; + + read_buffer = cdf_mem_malloc(count); + if (NULL == read_buffer) { + HIF_ERROR("%s: cdf_mem_alloc failed", __func__); + return -ENOMEM; + } + + hif_hdl = get_hif_hdl_from_file(file); + HIF_DBG("rd buff 0x%p cnt %zu offset 0x%x buf 0x%p", + read_buffer, count, (int)*pos, buf); + + if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) { + /* reading a word? */ + rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos), + (uint32_t *)read_buffer); + } else { + rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos), + (uint8_t *)read_buffer, count); + } + + if (copy_to_user(buf, read_buffer, count)) { + cdf_mem_free(read_buffer); + HIF_ERROR("%s: copy_to_user error in /proc/%s", + __func__, PROCFS_NAME); + return -EFAULT; + } else + cdf_mem_free(read_buffer); + + if (rv == 0) { + return count; + } else { + return -EIO; + } +} + +static ssize_t ath_procfs_diag_write(struct file *file, + const char __user *buf, + size_t count, loff_t *pos) +{ + hif_handle_t hif_hdl; + int rv; + uint8_t *write_buffer = NULL; + + write_buffer = cdf_mem_malloc(count); + if (NULL == write_buffer) { + HIF_ERROR("%s: cdf_mem_alloc failed", __func__); + return -ENOMEM; + } + if (copy_from_user(write_buffer, buf, count)) { + cdf_mem_free(write_buffer); + HIF_ERROR("%s: copy_to_user error in /proc/%s", + __func__, PROCFS_NAME); + return -EFAULT; + } + + hif_hdl = get_hif_hdl_from_file(file); + HIF_DBG("wr buff 0x%p buf 0x%p cnt %zu offset 0x%x value 0x%x", + write_buffer, buf, count, + (int)*pos, *((uint32_t *) write_buffer)); + + if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) { + /* reading a word? */ + uint32_t value = *((uint32_t *)write_buffer); + rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value); + } else { + rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos), + (uint8_t *)write_buffer, count); + } + + cdf_mem_free(write_buffer); + if (rv == 0) { + return count; + } else { + return -EIO; + } +} + +static const struct file_operations athdiag_fops = { + .read = ath_procfs_diag_read, + .write = ath_procfs_diag_write, +}; + +/** + *This function is called when the module is loaded + * + */ +int athdiag_procfs_init(void *scn) +{ + proc_dir = proc_mkdir(PROCFS_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_DIR, NULL); + HIF_ERROR("%s: Error: Could not initialize /proc/%s", + __func__, PROCFS_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_NAME, + S_IRUSR | S_IWUSR, proc_dir, + &athdiag_fops, (void *)scn); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_NAME, proc_dir); + HIF_ERROR("%s: Could not initialize /proc/%s", + __func__, PROCFS_NAME); + return -ENOMEM; + } + + HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME); + return 0; /* everything is ok */ +} + +/** + *This function is called when the module is unloaded + * + */ +void athdiag_procfs_remove(void) +{ + remove_proc_entry(PROCFS_NAME, proc_dir); + HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME); + remove_proc_entry(PROCFS_DIR, NULL); + HIF_DBG("/proc/%s removed", PROCFS_DIR); +} +#else +int athdiag_procfs_init(void *scn) +{ + return 0; +} +void athdiag_procfs_remove(void) {} +#endif diff --git a/core/hif/src/ce/ce_api.h b/core/hif/src/ce/ce_api.h new file mode 100644 index 0000000000..8bde74dba5 --- /dev/null +++ b/core/hif/src/ce/ce_api.h @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __COPY_ENGINE_API_H__ +#define __COPY_ENGINE_API_H__ + +#include "ce_main.h" +/* TBDXXX: Use int return values for consistency with Target */ + +/* TBDXXX: Perhaps merge Host/Target-->common */ + +/* + * Copy Engine support: low-level Target-side Copy Engine API. + * This is a hardware access layer used by code that understands + * how to use copy engines. + */ + +/* + * A "struct CE_handle *" serves as an opaque pointer-sized + * handle to a specific copy engine. + */ +struct CE_handle; + +/* + * "Send Completion" callback type for Send Completion Notification. + * + * If a Send Completion callback is registered and one or more sends + * have completed, the callback is invoked. + * + * per_ce_send_context is a context supplied by the calling layer + * (via ce_send_cb_register). It is associated with a copy engine. + * + * per_transfer_send_context is context supplied by the calling layer + * (via the "send" call). It may be different for each invocation + * of send. + * + * The buffer parameter is the first byte sent of the first buffer + * sent (if more than one buffer). + * + * nbytes is the number of bytes of that buffer that were sent. + * + * transfer_id matches the value used when the buffer or + * buf_list was sent. + * + * Implementation note: Pops 1 completed send buffer from Source ring + */ +typedef void (*ce_send_cb)(struct CE_handle *copyeng, + void *per_ce_send_context, + void *per_transfer_send_context, + cdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int sw_index, + unsigned int hw_index, + uint32_t toeplitz_hash_result); + +/* + * "Buffer Received" callback type for Buffer Received Notification. + * + * Implementation note: Pops 1 completed recv buffer from Dest ring + */ +typedef void (*CE_recv_cb)(struct CE_handle *copyeng, + void *per_CE_recv_context, + void *per_transfer_recv_context, + cdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags); + +/* + * Copy Engine Watermark callback type. + * + * Allows upper layers to be notified when watermarks are reached: + * space is available and/or running short in a source ring + * buffers are exhausted and/or abundant in a destination ring + * + * The flags parameter indicates which condition triggered this + * callback. See CE_WM_FLAG_*. + * + * Watermark APIs are provided to allow upper layers "batch" + * descriptor processing and to allow upper layers to + * throttle/unthrottle. + */ +typedef void (*CE_watermark_cb)(struct CE_handle *copyeng, + void *per_CE_wm_context, unsigned int flags); + +#define CE_WM_FLAG_SEND_HIGH 1 +#define CE_WM_FLAG_SEND_LOW 2 +#define CE_WM_FLAG_RECV_HIGH 4 +#define CE_WM_FLAG_RECV_LOW 8 + +/* A list of buffers to be gathered and sent */ +struct ce_sendlist; + +/* Copy Engine settable attributes */ +struct CE_attr; + +/*==================Send=====================================================*/ + +/* ce_send flags */ +/* disable ring's byte swap, even if the default policy is to swap */ +#define CE_SEND_FLAG_SWAP_DISABLE 1 + +/* + * Queue a source buffer to be sent to an anonymous destination buffer. + * copyeng - which copy engine to use + * buffer - address of buffer + * nbytes - number of bytes to send + * transfer_id - arbitrary ID; reflected to destination + * flags - CE_SEND_FLAG_* values + * Returns 0 on success; otherwise an error status. + * + * Note: If no flags are specified, use CE's default data swap mode. + * + * Implementation note: pushes 1 buffer to Source ring + */ +int ce_send(struct CE_handle *copyeng, + void *per_transfer_send_context, + cdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags, + unsigned int user_flags); + +#ifdef WLAN_FEATURE_FASTPATH +int ce_send_fast(struct CE_handle *copyeng, cdf_nbuf_t *msdus, + unsigned int num_msdus, unsigned int transfer_id); + +#endif +void ce_pkt_dl_len_set(void *hif_sc, unsigned int pkt_download_len); + +/* + * Register a Send Callback function. + * This function is called as soon as the contents of a Send + * have reached the destination, unless disable_interrupts is + * requested. In this case, the callback is invoked when the + * send status is polled, shortly after the send completes. + */ +void ce_send_cb_register(struct CE_handle *copyeng, + ce_send_cb fn_ptr, + void *per_ce_send_context, int disable_interrupts); + +/* + * Return the size of a SendList. This allows the caller to allocate + * a SendList while the SendList structure remains opaque. + */ +unsigned int ce_sendlist_sizeof(void); + +/* Initialize a sendlist */ +void ce_sendlist_init(struct ce_sendlist *sendlist); + +/* Append a simple buffer (address/length) to a sendlist. */ +int ce_sendlist_buf_add(struct ce_sendlist *sendlist, + cdf_dma_addr_t buffer, + unsigned int nbytes, + uint32_t flags, /* OR-ed with internal flags */ + uint32_t user_flags); + +/* + * Queue a "sendlist" of buffers to be sent using gather to a single + * anonymous destination buffer + * copyeng - which copy engine to use + * sendlist - list of simple buffers to send using gather + * transfer_id - arbitrary ID; reflected to destination + * Returns 0 on success; otherwise an error status. + * + * Implemenation note: Pushes multiple buffers with Gather to Source ring. + */ +int ce_sendlist_send(struct CE_handle *copyeng, + void *per_transfer_send_context, + struct ce_sendlist *sendlist, + unsigned int transfer_id); + +/*==================Recv=====================================================*/ + +/* + * Make a buffer available to receive. The buffer must be at least of a + * minimal size appropriate for this copy engine (src_sz_max attribute). + * copyeng - which copy engine to use + * per_transfer_recv_context - context passed back to caller's recv_cb + * buffer - address of buffer in CE space + * Returns 0 on success; otherwise an error status. + * + * Implemenation note: Pushes a buffer to Dest ring. + */ +int ce_recv_buf_enqueue(struct CE_handle *copyeng, + void *per_transfer_recv_context, + cdf_dma_addr_t buffer); + +/* + * Register a Receive Callback function. + * This function is called as soon as data is received + * from the source. + */ +void ce_recv_cb_register(struct CE_handle *copyeng, + CE_recv_cb fn_ptr, + void *per_CE_recv_context, + int disable_interrupts); + +/*==================CE Watermark=============================================*/ + +/* + * Register a Watermark Callback function. + * This function is called as soon as a watermark level + * is crossed. A Watermark Callback function is free to + * handle received data "en masse"; but then some coordination + * is required with a registered Receive Callback function. + * [Suggestion: Either handle Receives in a Receive Callback + * or en masse in a Watermark Callback; but not both.] + */ +void ce_watermark_cb_register(struct CE_handle *copyeng, + CE_watermark_cb fn_ptr, + void *per_CE_wm_context); + +/* + * Set low/high watermarks for the send/source side of a copy engine. + * + * Typically, the destination side CPU manages watermarks for + * the receive side and the source side CPU manages watermarks + * for the send side. + * + * A low watermark of 0 is never hit (so the watermark function + * will never be called for a Low Watermark condition). + * + * A high watermark equal to nentries is never hit (so the + * watermark function will never be called for a High Watermark + * condition). + */ +void ce_send_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries); + +/* Set low/high watermarks for the receive/destination side of copy engine. */ +void ce_recv_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries); + +/* + * Return the number of entries that can be queued + * to a ring at an instant in time. + * + * For source ring, does not imply that destination-side + * buffers are available; merely indicates descriptor space + * in the source ring. + * + * For destination ring, does not imply that previously + * received buffers have been processed; merely indicates + * descriptor space in destination ring. + * + * Mainly for use with CE Watermark callback. + */ +unsigned int ce_send_entries_avail(struct CE_handle *copyeng); +unsigned int ce_recv_entries_avail(struct CE_handle *copyeng); + +/* + * Return the number of entries in the ring that are ready + * to be processed by software. + * + * For source ring, the number of descriptors that have + * been completed and can now be overwritten with new send + * descriptors. + * + * For destination ring, the number of descriptors that + * are available to be processed (newly received buffers). + */ +unsigned int ce_send_entries_done(struct CE_handle *copyeng); +unsigned int ce_recv_entries_done(struct CE_handle *copyeng); + +/* recv flags */ +/* Data is byte-swapped */ +#define CE_RECV_FLAG_SWAPPED 1 + +void ce_enable_msi(struct ol_softc *scn, + unsigned int CE_id, + uint32_t msi_addr_lo, + uint32_t msi_addr_hi, + uint32_t msi_data); +/* + * Supply data for the next completed unprocessed receive descriptor. + * + * For use + * with CE Watermark callback, + * in a recv_cb function when processing buf_lists + * in a recv_cb function in order to mitigate recv_cb's. + * + * Implemenation note: Pops buffer from Dest ring. + */ +int ce_completed_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp); + +/* + * Supply data for the next completed unprocessed send descriptor. + * + * For use + * with CE Watermark callback + * in a send_cb function in order to mitigate send_cb's. + * + * Implementation note: Pops 1 completed send buffer from Source ring + */ +int ce_completed_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + uint32_t *toeplitz_hash_result); + +/*==================CE Engine Initialization=================================*/ + +/* Initialize an instance of a CE */ +struct CE_handle *ce_init(struct ol_softc *scn, + unsigned int CE_id, struct CE_attr *attr); + +/*==================CE Engine Shutdown=======================================*/ +/* + * Support clean shutdown by allowing the caller to revoke + * receive buffers. Target DMA must be stopped before using + * this API. + */ +CDF_STATUS +ce_revoke_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp); + +/* + * Support clean shutdown by allowing the caller to cancel + * pending sends. Target DMA must be stopped before using + * this API. + */ +CDF_STATUS +ce_cancel_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + uint32_t *toeplitz_hash_result); + +void ce_fini(struct CE_handle *copyeng); + +/*==================CE Interrupt Handlers====================================*/ +void ce_per_engine_service_any(int irq, struct ol_softc *scn); +int ce_per_engine_service(struct ol_softc *scn, unsigned int CE_id); +void ce_per_engine_servicereap(struct ol_softc *scn, unsigned int CE_id); + +/*===================CE cmpl interrupt Enable/Disable =======================*/ +void ce_disable_any_copy_compl_intr(struct ol_softc *scn); +void ce_enable_any_copy_compl_intr(struct ol_softc *scn); +void ce_disable_any_copy_compl_intr_nolock(struct ol_softc *scn); +void ce_enable_any_copy_compl_intr_nolock(struct ol_softc *scn); + +/* API to check if any of the copy engine pipes has + * pending frames for prcoessing + */ +bool ce_get_rx_pending(struct ol_softc *scn); + +/* CE_attr.flags values */ +#define CE_ATTR_NO_SNOOP 0x01 /* Use NonSnooping PCIe accesses? */ +#define CE_ATTR_BYTE_SWAP_DATA 0x02 /* Byte swap data words */ +#define CE_ATTR_SWIZZLE_DESCRIPTORS 0x04 /* Swizzle descriptors? */ +#define CE_ATTR_DISABLE_INTR 0x08 /* no interrupt on copy completion */ +#define CE_ATTR_ENABLE_POLL 0x10 /* poll for residue descriptors */ + +/* Attributes of an instance of a Copy Engine */ +struct CE_attr { + unsigned int flags; /* CE_ATTR_* values */ + unsigned int priority; /* TBD */ + unsigned int src_nentries; /* #entries in source ring - + * Must be a power of 2 */ + unsigned int src_sz_max; /* Max source send size for this CE. + * This is also the minimum size of + * a destination buffer. */ + unsigned int dest_nentries; /* #entries in destination ring - + * Must be a power of 2 */ + void *reserved; /* Future use */ +}; + +/* + * When using sendlist_send to transfer multiple buffer fragments, the + * transfer context of each fragment, except last one, will be filled + * with CE_SENDLIST_ITEM_CTXT. CE_completed_send will return success for + * each fragment done with send and the transfer context would be + * CE_SENDLIST_ITEM_CTXT. Upper layer could use this to identify the + * status of a send completion. + */ +#define CE_SENDLIST_ITEM_CTXT ((void *)0xcecebeef) + +/* + * This is an opaque type that is at least large enough to hold + * a sendlist. A sendlist can only be accessed through CE APIs, + * but this allows a sendlist to be allocated on the run-time + * stack. TBDXXX: un-opaque would be simpler... + */ +struct ce_sendlist { + unsigned int word[62]; +}; + +#define ATH_ISR_NOSCHED 0x0000 /* Do not schedule bottom half/DPC */ +#define ATH_ISR_SCHED 0x0001 /* Schedule the bottom half for execution */ +#define ATH_ISR_NOTMINE 0x0002 /* for shared IRQ's */ + +#ifdef IPA_OFFLOAD +/* + * Copy engine should release resource to micro controller + * Micro controller needs + - Copy engine source descriptor base address + - Copy engine source descriptor size + - PCI BAR address to access copy engine regiser + */ +void ce_ipa_get_resource(struct CE_handle *ce, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr); +#else +static inline void ce_ipa_get_resource(struct CE_handle *ce, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +static inline void ce_pkt_error_count_incr( + struct HIF_CE_state *_hif_state, + enum ol_ath_hif_pkt_ecodes _hif_ecode) +{ + if (_hif_ecode == HIF_PIPE_NO_RESOURCE) + (_hif_state->scn->pkt_stats.hif_pipe_no_resrc_count) + += 1; +} + +int hif_completion_thread(struct HIF_CE_state *hif_state); +bool ce_check_rx_pending(struct ol_softc *scn, int ce_id); +#if defined(FEATURE_LRO) +void ce_lro_flush_cb_register(struct ol_softc *scn, + void (handler)(void *), void *data); +#endif +#endif /* __COPY_ENGINE_API_H__ */ diff --git a/core/hif/src/ce/ce_assignment.h b/core/hif/src/ce/ce_assignment.h new file mode 100644 index 0000000000..b493d55502 --- /dev/null +++ b/core/hif/src/ce/ce_assignment.h @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Implementation of the Host-side Host InterFace (HIF) API + * for a Host/Target interconnect using Copy Engines over PCIe. + */ + +#ifndef __HIF_PCI_INTERNAL_H__ +#define __HIF_PCI_INTERNAL_H__ + +#define HIF_PCI_DEBUG ATH_DEBUG_MAKE_MODULE_MASK(0) +#define HIF_PCI_IPA_UC_ASSIGNED_CE 5 + +#if defined(DEBUG) +static ATH_DEBUG_MASK_DESCRIPTION g_hif_debug_description[] = { + {HIF_PCI_DEBUG, "hif_pci"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, "hif", "PCIe Host Interface", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO, + ATH_DEBUG_DESCRIPTION_COUNT + (g_hif_debug_description), + g_hif_debug_description); +#endif + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +spinlock_t pcie_access_log_lock; +unsigned int pcie_access_log_seqnum = 0; +HIF_ACCESS_LOG pcie_access_log[PCIE_ACCESS_LOG_NUM]; +static void hif_target_dump_access_log(void); +#endif + +/* + * Host software's Copy Engine configuration. + * This table is derived from the CE_PCI TABLE, above. + */ +#ifdef BIG_ENDIAN_HOST +#define CE_ATTR_FLAGS CE_ATTR_BYTE_SWAP_DATA +#else +#define CE_ATTR_FLAGS 0 +#endif + +/* Maximum number of Copy Engine's supported */ +#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048 + +#define DIAG_CE_ID 7 +#define EPPING_CE_FLAGS_POLL \ + (CE_ATTR_DISABLE_INTR|CE_ATTR_ENABLE_POLL|CE_ATTR_FLAGS) +#ifdef QCA_WIFI_3_0 +static struct CE_attr host_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host HTT + HTC control */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target->host WMI */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,}, + /* host->target WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,}, + /* host->target HTT */ + { /* CE4 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,}, + /* ipa_uc->target HTC control */ + { /* CE5 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + 1024, 512, 0, NULL,}, + /* Target autonomous HIF_memcpy */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; + +static struct CE_pipe_config target_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host HTT */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host WMI + HTC control */ + { /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target HTT */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* NB: 50% of src nentries, since tx has 2 frags */ + /* ipa_uc->target */ + { /* CE5 */ 5, PIPEDIR_OUT, 1024, 64, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* Reserved for target autonomous HIF_memcpy */ + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; + +static struct CE_attr host_ce_config_wlan_epping_poll[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; + +static struct CE_attr host_ce_config_wlan_epping_irq[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; +/* + * EP-ping firmware's CE configuration + */ +static struct CE_pipe_config target_ce_config_wlan_epping[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 16, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE1 */ 1, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE2 */ 2, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* EP-ping heartbeat */ + { /* CE5 */ 5, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* unused */ + { /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; +#else +static struct CE_attr host_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host HTT + HTC control */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target->host WMI */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,}, + /* host->target WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,}, + /* host->target HTT */ + { /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,}, + /* ipa_uc->target HTC control */ + { /* CE5 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + 1024, 512, 0, NULL,}, + /* Target autonomous HIF_memcpy */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, + 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; + +static struct CE_pipe_config target_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0,}, + /* target->host HTT + HTC control */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host WMI */ + { /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target HTT */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,}, + /* NB: 50% of src nentries, since tx has 2 frags */ + /* ipa_uc->target HTC control */ + { /* CE5 */ 5, PIPEDIR_OUT, 1024, 64, CE_ATTR_FLAGS, 0,}, + /* Reserved for target autonomous HIF_memcpy */ + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; + +static struct CE_attr host_ce_config_wlan_epping_poll[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; +static struct CE_attr host_ce_config_wlan_epping_irq[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; +/* + * EP-ping firmware's CE configuration + */ +static struct CE_pipe_config target_ce_config_wlan_epping[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 16, 256, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE1 */ 1, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE2 */ 2, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* EP-ping heartbeat */ + { /* CE5 */ 5, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* unused */ + { /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; +#endif + +static struct CE_attr *host_ce_config = host_ce_config_wlan; +static struct CE_pipe_config *target_ce_config = target_ce_config_wlan; +static int target_ce_config_sz = sizeof(target_ce_config_wlan); +#endif /* __HIF_PCI_INTERNAL_H__ */ diff --git a/core/hif/src/ce/ce_bmi.c b/core/hif/src/ce/ce_bmi.c new file mode 100644 index 0000000000..b2d541d2d2 --- /dev/null +++ b/core/hif/src/ce/ce_bmi.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "a_types.h" +#include "athdefs.h" +#include "osapi_linux.h" +#include "targcfg.h" +#include "cdf_lock.h" +#include "cdf_status.h" +#include /* cdf_atomic_read */ +#include +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#include "ce_api.h" +#include "cdf_trace.h" +#include "cds_api.h" +#ifdef CONFIG_CNSS +#include +#else +#include "cnss_stub.h" +#endif +#include +#include "epping_main.h" +#include "hif_debug.h" + +/* Track a BMI transaction that is in progress */ +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +enum { + BMI_REQ_SEND_DONE = BIT(0), /* the bmi tx completion */ + BMI_RESP_RECV_DONE = BIT(1), /* the bmi respond is received */ +}; + +struct BMI_transaction { + struct HIF_CE_state *hif_state; + cdf_semaphore_t bmi_transaction_sem; + uint8_t *bmi_request_host; /* Req BMI msg in Host addr space */ + cdf_dma_addr_t bmi_request_CE; /* Req BMI msg in CE addr space */ + uint32_t bmi_request_length; /* Length of BMI request */ + uint8_t *bmi_response_host; /* Rsp BMI msg in Host addr space */ + cdf_dma_addr_t bmi_response_CE; /* Rsp BMI msg in CE addr space */ + unsigned int bmi_response_length; /* Length of received response */ + unsigned int bmi_timeout_ms; + uint32_t bmi_transaction_flags; /* flags for the transcation */ +}; + +/* + * send/recv completion functions for BMI. + * NB: The "net_buf" parameter is actually just a + * straight buffer, not an sk_buff. + */ +void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int sw_index, + unsigned int hw_index, uint32_t toeplitz_hash_result) +{ + struct BMI_transaction *transaction = + (struct BMI_transaction *)transfer_context; + struct ol_softc *scn = transaction->hif_state->scn; + +#ifdef BMI_RSP_POLLING + /* + * Fix EV118783, Release a semaphore after sending + * no matter whether a response is been expecting now. + */ + cdf_semaphore_release(scn->cdf_dev, + &transaction->bmi_transaction_sem); +#else + /* + * If a response is anticipated, we'll complete the + * transaction if the response has been received. + * If no response is anticipated, complete the + * transaction now. + */ + transaction->bmi_transaction_flags |= BMI_REQ_SEND_DONE; + + /* resp is't needed or has already been received, + * never assume resp comes later then this */ + if (!transaction->bmi_response_CE || + (transaction->bmi_transaction_flags & BMI_RESP_RECV_DONE)) { + cdf_semaphore_release(scn->cdf_dev, + &transaction->bmi_transaction_sem); + } +#endif +} + +#ifndef BMI_RSP_POLLING +void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int flags) +{ + struct BMI_transaction *transaction = + (struct BMI_transaction *)transfer_context; + struct ol_softc *scn = transaction->hif_state->scn; + + transaction->bmi_response_length = nbytes; + transaction->bmi_transaction_flags |= BMI_RESP_RECV_DONE; + + /* when both send/recv are done, the sem can be released */ + if (transaction->bmi_transaction_flags & BMI_REQ_SEND_DONE) { + cdf_semaphore_release(scn->cdf_dev, + &transaction->bmi_transaction_sem); + } +} +#endif + +CDF_STATUS hif_exchange_bmi_msg(struct ol_softc *scn, + uint8_t *bmi_request, + uint32_t request_length, + uint8_t *bmi_response, + uint32_t *bmi_response_lengthp, uint32_t TimeoutMS) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + struct HIF_CE_pipe_info *send_pipe_info = + &(hif_state->pipe_info[BMI_CE_NUM_TO_TARG]); + struct CE_handle *ce_send_hdl = send_pipe_info->ce_hdl; + cdf_dma_addr_t CE_request, CE_response = 0; + struct BMI_transaction *transaction = NULL; + int status = CDF_STATUS_SUCCESS; + struct HIF_CE_pipe_info *recv_pipe_info = + &(hif_state->pipe_info[BMI_CE_NUM_TO_HOST]); + struct CE_handle *ce_recv = recv_pipe_info->ce_hdl; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + unsigned int user_flags = 0; +#ifdef BMI_RSP_POLLING + cdf_dma_addr_t buf; + unsigned int completed_nbytes, id, flags; + int i; +#endif + + transaction = + (struct BMI_transaction *)cdf_mem_malloc(sizeof(*transaction)); + if (unlikely(!transaction)) { + HIF_ERROR("%s: no memory", __func__); + return CDF_STATUS_E_NOMEM; + } + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + A_TARGET_ACCESS_LIKELY(scn); + + /* Initialize bmi_transaction_sem to block */ + cdf_semaphore_init(&transaction->bmi_transaction_sem); + cdf_semaphore_acquire(scn->cdf_dev, &transaction->bmi_transaction_sem); + + transaction->hif_state = hif_state; + transaction->bmi_request_host = bmi_request; + transaction->bmi_request_length = request_length; + transaction->bmi_response_length = 0; + transaction->bmi_timeout_ms = TimeoutMS; + transaction->bmi_transaction_flags = 0; + + /* + * CE_request = dma_map_single(dev, + * (void *)bmi_request, request_length, DMA_TO_DEVICE); + */ + CE_request = scn->bmi_cmd_da; + transaction->bmi_request_CE = CE_request; + + if (bmi_response) { + + /* + * CE_response = dma_map_single(dev, bmi_response, + * BMI_DATASZ_MAX, DMA_FROM_DEVICE); + */ + CE_response = scn->bmi_rsp_da; + transaction->bmi_response_host = bmi_response; + transaction->bmi_response_CE = CE_response; + /* dma_cache_sync(dev, bmi_response, + BMI_DATASZ_MAX, DMA_FROM_DEVICE); */ + cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, + CE_response, + BMI_DATASZ_MAX, + DMA_FROM_DEVICE); + ce_recv_buf_enqueue(ce_recv, transaction, + transaction->bmi_response_CE); + /* NB: see HIF_BMI_recv_done */ + } else { + transaction->bmi_response_host = NULL; + transaction->bmi_response_CE = 0; + } + + /* dma_cache_sync(dev, bmi_request, request_length, DMA_TO_DEVICE); */ + cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_request, + request_length, DMA_TO_DEVICE); + + status = + ce_send(ce_send_hdl, transaction, + CE_request, request_length, + transaction_id, 0, user_flags); + ASSERT(status == CDF_STATUS_SUCCESS); + /* NB: see hif_bmi_send_done */ + + /* TBDXXX: handle timeout */ + + /* Wait for BMI request/response transaction to complete */ + /* Always just wait for BMI request here if + * BMI_RSP_POLLING is defined */ + while (cdf_semaphore_acquire + (scn->cdf_dev, &transaction->bmi_transaction_sem)) { + /*need some break out condition(time out?) */ + } + + if (bmi_response) { +#ifdef BMI_RSP_POLLING + /* Fix EV118783, do not wait a semaphore for the BMI response + * since the relative interruption may be lost. + * poll the BMI response instead. + */ + i = 0; + while (ce_completed_recv_next( + ce_recv, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != CDF_STATUS_SUCCESS) { + if (i++ > BMI_RSP_TO_MILLISEC) { + HIF_ERROR("%s:error, can't get bmi response\n", + __func__); + status = CDF_STATUS_E_BUSY; + break; + } + OS_DELAY(1000); + } + + if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp) + *bmi_response_lengthp = completed_nbytes; +#else + if ((status == CDF_STATUS_SUCCESS) && bmi_response_lengthp) { + *bmi_response_lengthp = + transaction->bmi_response_length; + } +#endif + + } + + /* dma_unmap_single(dev, transaction->bmi_request_CE, + request_length, DMA_TO_DEVICE); */ + /* bus_unmap_single(scn->sc_osdev, + transaction->bmi_request_CE, + request_length, BUS_DMA_TODEVICE); */ + + if (status != CDF_STATUS_SUCCESS) { + cdf_dma_addr_t unused_buffer; + unsigned int unused_nbytes; + unsigned int unused_id; + unsigned int toeplitz_hash_result; + + ce_cancel_send_next(ce_send_hdl, + NULL, NULL, &unused_buffer, + &unused_nbytes, &unused_id, + &toeplitz_hash_result); + } + + A_TARGET_ACCESS_UNLIKELY(scn); + cdf_mem_free(transaction); + return status; +} diff --git a/core/hif/src/ce/ce_bmi.h b/core/hif/src/ce/ce_bmi.h new file mode 100644 index 0000000000..c09b211b6e --- /dev/null +++ b/core/hif/src/ce/ce_bmi.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_BMI_H__ +#define __CE_BMI_H__ + +#include /* cdf_atomic_read */ +#include "cdf_lock.h" +#include "ce_api.h" +#include "cepci.h" + +void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int flags); +void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int sw_index, + unsigned int hw_index, uint32_t toeplitz_hash_result); +#endif /* __CE_BMI_H__ */ diff --git a/core/hif/src/ce/ce_diag.c b/core/hif/src/ce/ce_diag.c new file mode 100644 index 0000000000..c078f218b0 --- /dev/null +++ b/core/hif/src/ce/ce_diag.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "a_types.h" +#include "athdefs.h" +#include "osapi_linux.h" +#include "targcfg.h" +#include "cdf_lock.h" +#include "cdf_status.h" +#include /* cdf_atomic_read */ +#include +#include +#include "hif_io32.h" +#include +#include +#include "regtable.h" +#include +#include "hif_main.h" +#include "ce_api.h" +#include "cdf_trace.h" +#include "cds_api.h" +#ifdef CONFIG_CNSS +#include +#endif +#include +#include "hif_debug.h" +#include "epping_main.h" + +void hif_dump_target_memory(struct ol_softc *scn, void *ramdump_base, + uint32_t address, uint32_t size) +{ + uint32_t loc = address; + uint32_t val = 0; + uint32_t j = 0; + u8 *temp = ramdump_base; + + A_TARGET_ACCESS_BEGIN(scn); + while (j < size) { + val = hif_read32_mb(scn->mem + loc + j); + cdf_mem_copy(temp, &val, 4); + j += 4; + temp += 4; + } + A_TARGET_ACCESS_END(scn); +} +/* + * TBDXXX: Should be a function call specific to each Target-type. + * This convoluted macro converts from Target CPU Virtual Address + * Space to CE Address Space. As part of this process, we + * conservatively fetch the current PCIE_BAR. MOST of the time, + * this should match the upper bits of PCI space for this device; + * but that's not guaranteed. + */ +#ifdef QCA_WIFI_3_0 +#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \ + (scn->mem_pa + addr) +#else +#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \ + (((hif_read32_mb((pci_addr) + \ + (SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \ + | 0x100000 | ((addr) & 0xfffff)) +#endif +/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ +#define DIAG_ACCESS_CE_TIMEOUT_MS 10 + +/* + * Diagnostic read/write access is provided for startup/config/debug usage. + * Caller must guarantee proper alignment, when applicable, and single user + * at any moment. + */ + +CDF_STATUS +hif_diag_read_mem(struct ol_softc *scn, uint32_t address, uint8_t *data, + int nbytes) +{ + struct HIF_CE_state *hif_state; + CDF_STATUS status = CDF_STATUS_SUCCESS; + cdf_dma_addr_t buf; + unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int id; + unsigned int flags; + struct CE_handle *ce_diag; + cdf_dma_addr_t CE_data; /* Host buffer address in CE space */ + cdf_dma_addr_t CE_data_base = 0; + void *data_buf = NULL; + int i; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + cdf_dma_addr_t ce_phy_addr = address; + unsigned int toeplitz_hash_result; + unsigned int user_flags = 0; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + + /* This code cannot handle reads to non-memory space. Redirect to the + * register read fn but preserve the multi word read capability of + * this fn + */ + if (address < DRAM_BASE_ADDRESS) { + + if ((address & 0x3) || ((uintptr_t) data & 0x3)) + return CDF_STATUS_E_INVAL; + + while ((nbytes >= 4) && + (CDF_STATUS_SUCCESS == (status = + hif_diag_read_access(scn, address, + (uint32_t *)data)))) { + + nbytes -= sizeof(uint32_t); + address += sizeof(uint32_t); + data += sizeof(uint32_t); + + } + + return status; + } + ce_diag = hif_state->ce_diag; + + A_TARGET_ACCESS_LIKELY(scn); + + /* + * Allocate a temporary bounce buffer to hold caller's data + * to be DMA'ed from Target. This guarantees + * 1) 4-byte alignment + * 2) Buffer in DMA-able space + */ + orig_nbytes = nbytes; + data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev, + orig_nbytes, &CE_data_base, 0); + if (!data_buf) { + status = CDF_STATUS_E_NOMEM; + goto done; + } + cdf_mem_set(data_buf, orig_nbytes, 0); + cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base, + orig_nbytes, DMA_FROM_DEVICE); + + remaining_bytes = orig_nbytes; + CE_data = CE_data_base; + while (remaining_bytes) { + nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT); + { + status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data); + if (status != CDF_STATUS_SUCCESS) + goto done; + } + + { /* Request CE to send from Target(!) + * address to Host buffer */ + /* + * The address supplied by the caller is in the + * Target CPU virtual address space. + * + * In order to use this address with the diagnostic CE, + * convert it from + * Target CPU virtual address space + * to + * CE address space + */ + A_TARGET_ACCESS_BEGIN_RET(scn); + ce_phy_addr = + TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address); + A_TARGET_ACCESS_END_RET(scn); + + status = + ce_send(ce_diag, NULL, ce_phy_addr, nbytes, + transaction_id, 0, user_flags); + if (status != CDF_STATUS_SUCCESS) + goto done; + } + + i = 0; + while (ce_completed_send_next(ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, NULL, NULL, + &toeplitz_hash_result) != CDF_STATUS_SUCCESS) { + cdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = CDF_STATUS_E_BUSY; + goto done; + } + } + if (nbytes != completed_nbytes) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + if (buf != ce_phy_addr) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + i = 0; + while (ce_completed_recv_next + (ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != CDF_STATUS_SUCCESS) { + cdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = CDF_STATUS_E_BUSY; + goto done; + } + } + if (nbytes != completed_nbytes) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + if (buf != CE_data) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + remaining_bytes -= nbytes; + address += nbytes; + CE_data += nbytes; + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + if (status == CDF_STATUS_SUCCESS) + cdf_mem_copy(data, data_buf, orig_nbytes); + else + HIF_ERROR("%s failure (0x%x)", __func__, address); + + if (data_buf) + cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes, + data_buf, CE_data_base, 0); + + return status; +} + +/* Read 4-byte aligned data from Target memory or register */ +CDF_STATUS hif_diag_read_access(struct ol_softc *scn, + uint32_t address, uint32_t *data) +{ + struct HIF_CE_state *hif_state; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + if (address >= DRAM_BASE_ADDRESS) { + /* Assume range doesn't cross this boundary */ + return hif_diag_read_mem(scn, address, (uint8_t *) data, + sizeof(uint32_t)); + } else { + A_TARGET_ACCESS_BEGIN_RET(scn); + *data = A_TARGET_READ(scn, address); + A_TARGET_ACCESS_END_RET(scn); + + return CDF_STATUS_SUCCESS; + } +} + +CDF_STATUS hif_diag_write_mem(struct ol_softc *scn, + uint32_t address, uint8_t *data, int nbytes) +{ + struct HIF_CE_state *hif_state; + CDF_STATUS status = CDF_STATUS_SUCCESS; + cdf_dma_addr_t buf; + unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int id; + unsigned int flags; + struct CE_handle *ce_diag; + void *data_buf = NULL; + cdf_dma_addr_t CE_data; /* Host buffer address in CE space */ + cdf_dma_addr_t CE_data_base = 0; + int i; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + cdf_dma_addr_t ce_phy_addr = address; + unsigned int toeplitz_hash_result; + unsigned int user_flags = 0; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + ce_diag = hif_state->ce_diag; + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + + A_TARGET_ACCESS_LIKELY(scn); + + /* + * Allocate a temporary bounce buffer to hold caller's data + * to be DMA'ed to Target. This guarantees + * 1) 4-byte alignment + * 2) Buffer in DMA-able space + */ + orig_nbytes = nbytes; + data_buf = cdf_os_mem_alloc_consistent(scn->cdf_dev, + orig_nbytes, &CE_data_base, 0); + if (!data_buf) { + status = A_NO_MEMORY; + goto done; + } + + /* Copy caller's data to allocated DMA buf */ + cdf_mem_copy(data_buf, data, orig_nbytes); + cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data_base, + orig_nbytes, DMA_TO_DEVICE); + + /* + * The address supplied by the caller is in the + * Target CPU virtual address space. + * + * In order to use this address with the diagnostic CE, + * convert it from + * Target CPU virtual address space + * to + * CE address space + */ + A_TARGET_ACCESS_BEGIN_RET(scn); + ce_phy_addr = TARG_CPU_SPACE_TO_CE_SPACE(scn->mem, address); + A_TARGET_ACCESS_END_RET(scn); + + remaining_bytes = orig_nbytes; + CE_data = CE_data_base; + while (remaining_bytes) { + nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT); + + { /* Set up to receive directly into Target(!) address */ + status = ce_recv_buf_enqueue(ce_diag, + NULL, ce_phy_addr); + if (status != CDF_STATUS_SUCCESS) + goto done; + } + + { + /* + * Request CE to send caller-supplied data that + * was copied to bounce buffer to Target(!) address. + */ + status = + ce_send(ce_diag, NULL, + (cdf_dma_addr_t) CE_data, nbytes, + transaction_id, 0, user_flags); + if (status != CDF_STATUS_SUCCESS) + goto done; + } + + i = 0; + while (ce_completed_send_next(ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + NULL, NULL, &toeplitz_hash_result) != + CDF_STATUS_SUCCESS) { + cdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = CDF_STATUS_E_BUSY; + goto done; + } + } + + if (nbytes != completed_nbytes) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + if (buf != CE_data) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + i = 0; + while (ce_completed_recv_next + (ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != CDF_STATUS_SUCCESS) { + cdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = CDF_STATUS_E_BUSY; + goto done; + } + } + + if (nbytes != completed_nbytes) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + if (buf != ce_phy_addr) { + status = CDF_STATUS_E_FAILURE; + goto done; + } + + remaining_bytes -= nbytes; + address += nbytes; + CE_data += nbytes; + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + if (data_buf) { + cdf_os_mem_free_consistent(scn->cdf_dev, orig_nbytes, + data_buf, CE_data_base, 0); + } + + if (status != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s failure (0x%llu)", __func__, + (uint64_t)ce_phy_addr); + } + + return status; +} + +/* Write 4B data to Target memory or register */ +CDF_STATUS +hif_diag_write_access(struct ol_softc *scn, uint32_t address, uint32_t data) +{ + struct HIF_CE_state *hif_state; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + if (address >= DRAM_BASE_ADDRESS) { + /* Assume range doesn't cross this boundary */ + uint32_t data_buf = data; + + return hif_diag_write_mem(scn, address, + (uint8_t *) &data_buf, + sizeof(uint32_t)); + } else { + A_TARGET_ACCESS_BEGIN_RET(scn); + A_TARGET_WRITE(scn, address, data); + A_TARGET_ACCESS_END_RET(scn); + + return CDF_STATUS_SUCCESS; + } +} diff --git a/core/hif/src/ce/ce_internal.h b/core/hif/src/ce/ce_internal.h new file mode 100644 index 0000000000..b3fa707370 --- /dev/null +++ b/core/hif/src/ce/ce_internal.h @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef __COPY_ENGINE_INTERNAL_H__ +#define __COPY_ENGINE_INTERNAL_H__ + +#include /* A_TARGET_WRITE */ + +/* Copy Engine operational state */ +enum CE_op_state { + CE_UNUSED, + CE_PAUSED, + CE_RUNNING, +}; + +enum ol_ath_hif_ce_ecodes { + CE_RING_DELTA_FAIL = 0 +}; + +struct CE_src_desc; + +/* Copy Engine Ring internal state */ +struct CE_ring_state { + + /* Number of entries in this ring; must be power of 2 */ + unsigned int nentries; + unsigned int nentries_mask; + + /* + * For dest ring, this is the next index to be processed + * by software after it was/is received into. + * + * For src ring, this is the last descriptor that was sent + * and completion processed by software. + * + * Regardless of src or dest ring, this is an invariant + * (modulo ring size): + * write index >= read index >= sw_index + */ + unsigned int sw_index; + unsigned int write_index; /* cached copy */ + /* + * For src ring, this is the next index not yet processed by HW. + * This is a cached copy of the real HW index (read index), used + * for avoiding reading the HW index register more often than + * necessary. + * This extends the invariant: + * write index >= read index >= hw_index >= sw_index + * + * For dest ring, this is currently unused. + */ + unsigned int hw_index; /* cached copy */ + + /* Start of DMA-coherent area reserved for descriptors */ + void *base_addr_owner_space_unaligned; /* Host address space */ + cdf_dma_addr_t base_addr_CE_space_unaligned; /* CE address space */ + + /* + * Actual start of descriptors. + * Aligned to descriptor-size boundary. + * Points into reserved DMA-coherent area, above. + */ + void *base_addr_owner_space; /* Host address space */ + cdf_dma_addr_t base_addr_CE_space; /* CE address space */ + /* + * Start of shadow copy of descriptors, within regular memory. + * Aligned to descriptor-size boundary. + */ + char *shadow_base_unaligned; + struct CE_src_desc *shadow_base; + + unsigned int low_water_mark_nentries; + unsigned int high_water_mark_nentries; + void **per_transfer_context; + OS_DMA_MEM_CONTEXT(ce_dmacontext) /* OS Specific DMA context */ +}; + +/* Copy Engine internal state */ +struct CE_state { + struct ol_softc *scn; + unsigned int id; + unsigned int attr_flags; /* CE_ATTR_* */ + uint32_t ctrl_addr; /* relative to BAR */ + enum CE_op_state state; + +#ifdef WLAN_FEATURE_FASTPATH + u_int32_t download_len; /* pkt download length for source ring */ +#endif /* WLAN_FEATURE_FASTPATH */ + + ce_send_cb send_cb; + void *send_context; + + CE_recv_cb recv_cb; + void *recv_context; + + /* misc_cbs - are any callbacks besides send and recv enabled? */ + uint8_t misc_cbs; + + CE_watermark_cb watermark_cb; + void *wm_context; + + /*Record the state of the copy compl interrupt */ + int disable_copy_compl_intr; + + unsigned int src_sz_max; + struct CE_ring_state *src_ring; + struct CE_ring_state *dest_ring; + atomic_t rx_pending; + + /* epping */ + bool timer_inited; + cdf_softirq_timer_t poll_timer; + void (*lro_flush_cb)(void *); + void *lro_data; +}; + +/* Descriptor rings must be aligned to this boundary */ +#define CE_DESC_RING_ALIGN 8 + +#ifdef QCA_WIFI_3_0 +#define HIF_CE_DESC_ADDR_TO_DMA(desc) \ + (cdf_dma_addr_t)(((uint64_t)(desc)->buffer_addr + \ + ((uint64_t)((desc)->buffer_addr_hi & 0x1F) << 32))) +#else +#define HIF_CE_DESC_ADDR_TO_DMA(desc) \ + (cdf_dma_addr_t)((desc)->buffer_addr) +#endif + +#ifdef QCA_WIFI_3_0 +struct CE_src_desc { + uint32_t buffer_addr:32; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t gather:1, + enable_11h:1, + meta_data_low:2, /* fw_metadata_low */ + packet_result_offset:12, + toeplitz_hash_enable:1, + addr_y_search_disable:1, + addr_x_search_disable:1, + misc_int_disable:1, + target_int_disable:1, + host_int_disable:1, + dest_byte_swap:1, + byte_swap:1, + type:2, + tx_classify:1, + buffer_addr_hi:5; + uint32_t meta_data:16, /* fw_metadata_high */ + nbytes:16; /* length in register map */ +#else + uint32_t buffer_addr_hi:5, + tx_classify:1, + type:2, + byte_swap:1, /* src_byte_swap */ + dest_byte_swap:1, + host_int_disable:1, + target_int_disable:1, + misc_int_disable:1, + addr_x_search_disable:1, + addr_y_search_disable:1, + toeplitz_hash_enable:1, + packet_result_offset:12, + meta_data_low:2, /* fw_metadata_low */ + enable_11h:1, + gather:1; + uint32_t nbytes:16, /* length in register map */ + meta_data:16; /* fw_metadata_high */ +#endif + uint32_t toeplitz_hash_result:32; +}; + +struct CE_dest_desc { + uint32_t buffer_addr:32; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t gather:1, + enable_11h:1, + meta_data_low:2, /* fw_metadata_low */ + packet_result_offset:12, + toeplitz_hash_enable:1, + addr_y_search_disable:1, + addr_x_search_disable:1, + misc_int_disable:1, + target_int_disable:1, + host_int_disable:1, + byte_swap:1, + src_byte_swap:1, + type:2, + tx_classify:1, + buffer_addr_hi:5; + uint32_t meta_data:16, /* fw_metadata_high */ + nbytes:16; /* length in register map */ +#else + uint32_t buffer_addr_hi:5, + tx_classify:1, + type:2, + src_byte_swap:1, + byte_swap:1, /* dest_byte_swap */ + host_int_disable:1, + target_int_disable:1, + misc_int_disable:1, + addr_x_search_disable:1, + addr_y_search_disable:1, + toeplitz_hash_enable:1, + packet_result_offset:12, + meta_data_low:2, /* fw_metadata_low */ + enable_11h:1, + gather:1; + uint32_t nbytes:16, /* length in register map */ + meta_data:16; /* fw_metadata_high */ +#endif + uint32_t toeplitz_hash_result:32; +}; +#else +struct CE_src_desc { + uint32_t buffer_addr; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t meta_data:14, + byte_swap:1, + gather:1, + nbytes:16; +#else + + uint32_t nbytes:16, + gather:1, + byte_swap:1, + meta_data:14; +#endif +}; + +struct CE_dest_desc { + uint32_t buffer_addr; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t meta_data:14, + byte_swap:1, + gather:1, + nbytes:16; +#else + uint32_t nbytes:16, + gather:1, + byte_swap:1, + meta_data:14; +#endif +}; +#endif /* QCA_WIFI_3_0 */ + +#define CE_SENDLIST_ITEMS_MAX 12 + +enum ce_sendlist_type_e { + CE_SIMPLE_BUFFER_TYPE, + /* TBDXXX: CE_RX_DESC_LIST, */ +}; + +/* + * There's a public "ce_sendlist" and a private "ce_sendlist_s". + * The former is an opaque structure with sufficient space + * to hold the latter. The latter is the actual structure + * definition and it is only used internally. The opaque version + * of the structure allows callers to allocate an instance on the + * run-time stack without knowing any of the details of the + * structure layout. + */ +struct ce_sendlist_s { + unsigned int num_items; + struct ce_sendlist_item { + enum ce_sendlist_type_e send_type; + dma_addr_t data; /* e.g. buffer or desc list */ + union { + unsigned int nbytes; /* simple buffer */ + unsigned int ndesc; /* Rx descriptor list */ + } u; + /* flags: externally-specified flags; + * OR-ed with internal flags */ + uint32_t flags; + uint32_t user_flags; + } item[CE_SENDLIST_ITEMS_MAX]; +}; + +#ifdef WLAN_FEATURE_FASTPATH +void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl); +#endif + +/* which ring of a CE? */ +#define CE_RING_SRC 0 +#define CE_RING_DEST 1 + +#define CDC_WAR_MAGIC_STR 0xceef0000 +#define CDC_WAR_DATA_CE 4 + +/* Additional internal-only ce_send flags */ +#define CE_SEND_FLAG_GATHER 0x00010000 /* Use Gather */ +#endif /* __COPY_ENGINE_INTERNAL_H__ */ diff --git a/core/hif/src/ce/ce_main.c b/core/hif/src/ce/ce_main.c new file mode 100644 index 0000000000..8cf00f13e9 --- /dev/null +++ b/core/hif/src/ce/ce_main.c @@ -0,0 +1,2593 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#include +#include "a_types.h" +#include "athdefs.h" +#include "osapi_linux.h" +#include "targcfg.h" +#include "cdf_lock.h" +#include "cdf_status.h" +#include /* cdf_atomic_read */ +#include +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#ifdef HIF_PCI +#include "ce_bmi.h" +#endif +#include "ce_api.h" +#include "cdf_trace.h" +#include "cds_api.h" +#ifdef CONFIG_CNSS +#include +#endif +#include +#include "epping_main.h" +#include "hif_debug.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "ce_assignment.h" +#include "ce_tasklet.h" +#ifdef HIF_PCI +#include "icnss_stub.h" +#else +#include +#endif +#include "qwlan_version.h" + +#define CE_POLL_TIMEOUT 10 /* ms */ + +/* Forward references */ +static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info); + +/* + * Fix EV118783, poll to check whether a BMI response comes + * other than waiting for the interruption which may be lost. + */ +/* #define BMI_RSP_POLLING */ +#define BMI_RSP_TO_MILLISEC 1000 + + +static int hif_post_recv_buffers(struct ol_softc *scn); + +static void ce_poll_timeout(void *arg) +{ + struct CE_state *CE_state = (struct CE_state *)arg; + if (CE_state->timer_inited) { + ce_per_engine_service(CE_state->scn, CE_state->id); + cdf_softirq_timer_mod(&CE_state->poll_timer, CE_POLL_TIMEOUT); + } +} + +static unsigned int roundup_pwr2(unsigned int n) +{ + int i; + unsigned int test_pwr2; + + if (!(n & (n - 1))) + return n; /* already a power of 2 */ + + test_pwr2 = 4; + for (i = 0; i < 29; i++) { + if (test_pwr2 > n) + return test_pwr2; + test_pwr2 = test_pwr2 << 1; + } + + CDF_ASSERT(0); /* n too large */ + return 0; +} + +/* + * Initialize a Copy Engine based on caller-supplied attributes. + * This may be called once to initialize both source and destination + * rings or it may be called twice for separate source and destination + * initialization. It may be that only one side or the other is + * initialized by software/firmware. + */ +struct CE_handle *ce_init(struct ol_softc *scn, + unsigned int CE_id, struct CE_attr *attr) +{ + struct CE_state *CE_state; + uint32_t ctrl_addr; + unsigned int nentries; + cdf_dma_addr_t base_addr; + bool malloc_CE_state = false; + bool malloc_src_ring = false; + + CDF_ASSERT(CE_id < scn->ce_count); + ctrl_addr = CE_BASE_ADDRESS(CE_id); + cdf_spin_lock(&scn->target_lock); + CE_state = scn->ce_id_to_state[CE_id]; + + if (!CE_state) { + cdf_spin_unlock(&scn->target_lock); + CE_state = + (struct CE_state *)cdf_mem_malloc(sizeof(*CE_state)); + if (!CE_state) { + HIF_ERROR("%s: CE_state has no mem", __func__); + return NULL; + } else + malloc_CE_state = true; + cdf_mem_zero(CE_state, sizeof(*CE_state)); + cdf_spin_lock(&scn->target_lock); + if (!scn->ce_id_to_state[CE_id]) { /* re-check under lock */ + scn->ce_id_to_state[CE_id] = CE_state; + + CE_state->id = CE_id; + CE_state->ctrl_addr = ctrl_addr; + CE_state->state = CE_RUNNING; + CE_state->attr_flags = attr->flags; + } else { + /* + * We released target_lock in order to allocate + * CE state, but someone else beat us to it. + * Continue, using that CE_state + * (and free the one we allocated). + */ + cdf_mem_free(CE_state); + malloc_CE_state = false; + CE_state = scn->ce_id_to_state[CE_id]; + } + } + CE_state->scn = scn; + cdf_spin_unlock(&scn->target_lock); + + cdf_atomic_init(&CE_state->rx_pending); + if (attr == NULL) { + /* Already initialized; caller wants the handle */ + return (struct CE_handle *)CE_state; + } + +#ifdef ADRASTEA_SHADOW_REGISTERS + HIF_ERROR("%s: Using Shadow Registers instead of CE Registers\n", + __func__); +#endif + + if (CE_state->src_sz_max) + CDF_ASSERT(CE_state->src_sz_max == attr->src_sz_max); + else + CE_state->src_sz_max = attr->src_sz_max; + + /* source ring setup */ + nentries = attr->src_nentries; + if (nentries) { + struct CE_ring_state *src_ring; + unsigned CE_nbytes; + char *ptr; + uint64_t dma_addr; + nentries = roundup_pwr2(nentries); + if (CE_state->src_ring) { + CDF_ASSERT(CE_state->src_ring->nentries == nentries); + } else { + CE_nbytes = sizeof(struct CE_ring_state) + + (nentries * sizeof(void *)); + ptr = cdf_mem_malloc(CE_nbytes); + if (!ptr) { + /* cannot allocate src ring. If the + * CE_state is allocated locally free + * CE_State and return error. + */ + HIF_ERROR("%s: src ring has no mem", __func__); + if (malloc_CE_state) { + /* allocated CE_state locally */ + cdf_spin_lock(&scn->target_lock); + scn->ce_id_to_state[CE_id] = NULL; + cdf_spin_unlock(&scn->target_lock); + cdf_mem_free(CE_state); + malloc_CE_state = false; + } + return NULL; + } else { + /* we can allocate src ring. + * Mark that the src ring is + * allocated locally + */ + malloc_src_ring = true; + } + cdf_mem_zero(ptr, CE_nbytes); + + src_ring = CE_state->src_ring = + (struct CE_ring_state *)ptr; + ptr += sizeof(struct CE_ring_state); + src_ring->nentries = nentries; + src_ring->nentries_mask = nentries - 1; + A_TARGET_ACCESS_BEGIN_RET_PTR(scn); + src_ring->hw_index = + CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr); + src_ring->sw_index = src_ring->hw_index; + src_ring->write_index = + CE_SRC_RING_WRITE_IDX_GET(scn, ctrl_addr); + A_TARGET_ACCESS_END_RET_PTR(scn); + src_ring->low_water_mark_nentries = 0; + src_ring->high_water_mark_nentries = nentries; + src_ring->per_transfer_context = (void **)ptr; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported + */ + src_ring->base_addr_owner_space_unaligned = + cdf_os_mem_alloc_consistent(scn->cdf_dev, + (nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN), + &base_addr, 0); + if (src_ring->base_addr_owner_space_unaligned + == NULL) { + HIF_ERROR("%s: src ring has no DMA mem", + __func__); + goto error_no_dma_mem; + } + src_ring->base_addr_CE_space_unaligned = base_addr; + + if (src_ring-> + base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN + - 1)) { + src_ring->base_addr_CE_space = + (src_ring->base_addr_CE_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1); + + src_ring->base_addr_owner_space = + (void + *)(((size_t) src_ring-> + base_addr_owner_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1)); + } else { + src_ring->base_addr_CE_space = + src_ring->base_addr_CE_space_unaligned; + src_ring->base_addr_owner_space = + src_ring-> + base_addr_owner_space_unaligned; + } + /* + * Also allocate a shadow src ring in + * regular mem to use for faster access. + */ + src_ring->shadow_base_unaligned = + cdf_mem_malloc(nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN); + if (src_ring->shadow_base_unaligned == NULL) { + HIF_ERROR("%s: src ring no shadow_base mem", + __func__); + goto error_no_dma_mem; + } + src_ring->shadow_base = (struct CE_src_desc *) + (((size_t) src_ring->shadow_base_unaligned + + CE_DESC_RING_ALIGN - 1) & + ~(CE_DESC_RING_ALIGN - 1)); + + A_TARGET_ACCESS_BEGIN_RET_PTR(scn); + dma_addr = src_ring->base_addr_CE_space; + CE_SRC_RING_BASE_ADDR_SET(scn, ctrl_addr, + (uint32_t)(dma_addr & 0xFFFFFFFF)); +#ifdef WLAN_ENABLE_QCA6180 + { + uint32_t tmp; + tmp = CE_SRC_RING_BASE_ADDR_HIGH_GET( + scn, ctrl_addr); + tmp &= ~0x1F; + dma_addr = ((dma_addr >> 32) & 0x1F)|tmp; + CE_SRC_RING_BASE_ADDR_HIGH_SET(scn, + ctrl_addr, (uint32_t)dma_addr); + } +#endif + CE_SRC_RING_SZ_SET(scn, ctrl_addr, nentries); + CE_SRC_RING_DMAX_SET(scn, ctrl_addr, attr->src_sz_max); +#ifdef BIG_ENDIAN_HOST + /* Enable source ring byte swap for big endian host */ + CE_SRC_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1); +#endif + CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, 0); + CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, nentries); + A_TARGET_ACCESS_END_RET_PTR(scn); + } + } + + /* destination ring setup */ + nentries = attr->dest_nentries; + if (nentries) { + struct CE_ring_state *dest_ring; + unsigned CE_nbytes; + char *ptr; + uint64_t dma_addr; + + nentries = roundup_pwr2(nentries); + if (CE_state->dest_ring) { + CDF_ASSERT(CE_state->dest_ring->nentries == nentries); + } else { + CE_nbytes = sizeof(struct CE_ring_state) + + (nentries * sizeof(void *)); + ptr = cdf_mem_malloc(CE_nbytes); + if (!ptr) { + /* cannot allocate dst ring. If the CE_state + * or src ring is allocated locally free + * CE_State and src ring and return error. + */ + HIF_ERROR("%s: dest ring has no mem", + __func__); + if (malloc_src_ring) { + cdf_mem_free(CE_state->src_ring); + CE_state->src_ring = NULL; + malloc_src_ring = false; + } + if (malloc_CE_state) { + /* allocated CE_state locally */ + cdf_spin_lock(&scn->target_lock); + scn->ce_id_to_state[CE_id] = NULL; + cdf_spin_unlock(&scn->target_lock); + cdf_mem_free(CE_state); + malloc_CE_state = false; + } + return NULL; + } + cdf_mem_zero(ptr, CE_nbytes); + + dest_ring = CE_state->dest_ring = + (struct CE_ring_state *)ptr; + ptr += sizeof(struct CE_ring_state); + dest_ring->nentries = nentries; + dest_ring->nentries_mask = nentries - 1; + A_TARGET_ACCESS_BEGIN_RET_PTR(scn); + dest_ring->sw_index = + CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr); + dest_ring->write_index = + CE_DEST_RING_WRITE_IDX_GET(scn, ctrl_addr); + A_TARGET_ACCESS_END_RET_PTR(scn); + dest_ring->low_water_mark_nentries = 0; + dest_ring->high_water_mark_nentries = nentries; + dest_ring->per_transfer_context = (void **)ptr; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported */ + dest_ring->base_addr_owner_space_unaligned = + cdf_os_mem_alloc_consistent(scn->cdf_dev, + (nentries * + sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN), + &base_addr, 0); + if (dest_ring->base_addr_owner_space_unaligned + == NULL) { + HIF_ERROR("%s: dest ring has no DMA mem", + __func__); + goto error_no_dma_mem; + } + dest_ring->base_addr_CE_space_unaligned = base_addr; + + /* Correctly initialize memory to 0 to + * prevent garbage data crashing system + * when download firmware + */ + cdf_mem_zero(dest_ring->base_addr_owner_space_unaligned, + nentries * sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN); + + if (dest_ring-> + base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN - + 1)) { + + dest_ring->base_addr_CE_space = + (dest_ring-> + base_addr_CE_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1); + + dest_ring->base_addr_owner_space = + (void + *)(((size_t) dest_ring-> + base_addr_owner_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1)); + } else { + dest_ring->base_addr_CE_space = + dest_ring->base_addr_CE_space_unaligned; + dest_ring->base_addr_owner_space = + dest_ring-> + base_addr_owner_space_unaligned; + } + + A_TARGET_ACCESS_BEGIN_RET_PTR(scn); + dma_addr = dest_ring->base_addr_CE_space; + CE_DEST_RING_BASE_ADDR_SET(scn, ctrl_addr, + (uint32_t)(dma_addr & 0xFFFFFFFF)); +#ifdef WLAN_ENABLE_QCA6180 + { + uint32_t tmp; + tmp = CE_DEST_RING_BASE_ADDR_HIGH_GET(scn, + ctrl_addr); + tmp &= ~0x1F; + dma_addr = ((dma_addr >> 32) & 0x1F)|tmp; + CE_DEST_RING_BASE_ADDR_HIGH_SET(scn, + ctrl_addr, (uint32_t)dma_addr); + } +#endif + CE_DEST_RING_SZ_SET(scn, ctrl_addr, nentries); +#ifdef BIG_ENDIAN_HOST + /* Enable Dest ring byte swap for big endian host */ + CE_DEST_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1); +#endif + CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr, 0); + CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr, nentries); + A_TARGET_ACCESS_END_RET_PTR(scn); + + /* epping */ + /* poll timer */ + if ((CE_state->attr_flags & CE_ATTR_ENABLE_POLL)) { + cdf_softirq_timer_init(scn->cdf_dev, + &CE_state->poll_timer, + ce_poll_timeout, + CE_state, + CDF_TIMER_TYPE_SW); + CE_state->timer_inited = true; + cdf_softirq_timer_mod(&CE_state->poll_timer, + CE_POLL_TIMEOUT); + } + } + } + + /* Enable CE error interrupts */ + A_TARGET_ACCESS_BEGIN_RET_PTR(scn); + CE_ERROR_INTR_ENABLE(scn, ctrl_addr); + A_TARGET_ACCESS_END_RET_PTR(scn); + + return (struct CE_handle *)CE_state; + +error_no_dma_mem: + ce_fini((struct CE_handle *)CE_state); + return NULL; +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ce_h2t_tx_ce_cleanup() Place holder function for H2T CE cleanup. + * No processing is required inside this function. + * @ce_hdl: Cope engine handle + * Using an assert, this function makes sure that, + * the TX CE has been processed completely. + * Return: none + */ +void +ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl) +{ + struct CE_state *ce_state = (struct CE_state *)ce_hdl; + struct CE_ring_state *src_ring = ce_state->src_ring; + struct ol_softc *sc = ce_state->scn; + uint32_t sw_index, write_index; + + if (sc->fastpath_mode_on && (ce_state->id == CE_HTT_H2T_MSG)) { + HIF_INFO("%s %d Fastpath mode ON, Cleaning up HTT Tx CE\n", + __func__, __LINE__); + cdf_spin_lock_bh(&sc->target_lock); + sw_index = src_ring->sw_index; + write_index = src_ring->sw_index; + cdf_spin_unlock_bh(&sc->target_lock); + + /* At this point Tx CE should be clean */ + cdf_assert_always(sw_index == write_index); + } +} +#else +void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl) +{ +} +#endif /* WLAN_FEATURE_FASTPATH */ + +void ce_fini(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int CE_id = CE_state->id; + struct ol_softc *scn = CE_state->scn; + + CE_state->state = CE_UNUSED; + scn->ce_id_to_state[CE_id] = NULL; + if (CE_state->src_ring) { + /* Cleanup the HTT Tx ring */ + ce_h2t_tx_ce_cleanup(copyeng); + + if (CE_state->src_ring->shadow_base_unaligned) + cdf_mem_free(CE_state->src_ring->shadow_base_unaligned); + if (CE_state->src_ring->base_addr_owner_space_unaligned) + cdf_os_mem_free_consistent(scn->cdf_dev, + (CE_state->src_ring->nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN), + CE_state->src_ring-> + base_addr_owner_space_unaligned, + CE_state->src_ring-> + base_addr_CE_space, 0); + cdf_mem_free(CE_state->src_ring); + } + if (CE_state->dest_ring) { + if (CE_state->dest_ring->base_addr_owner_space_unaligned) + cdf_os_mem_free_consistent(scn->cdf_dev, + (CE_state->dest_ring->nentries * + sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN), + CE_state->dest_ring-> + base_addr_owner_space_unaligned, + CE_state->dest_ring-> + base_addr_CE_space, 0); + cdf_mem_free(CE_state->dest_ring); + + /* epping */ + if (CE_state->timer_inited) { + CE_state->timer_inited = false; + cdf_softirq_timer_free(&CE_state->poll_timer); + } + } + cdf_mem_free(CE_state); +} + +void hif_detach_htc(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + cdf_mem_zero(&hif_state->msg_callbacks_pending, + sizeof(hif_state->msg_callbacks_pending)); + cdf_mem_zero(&hif_state->msg_callbacks_current, + sizeof(hif_state->msg_callbacks_current)); +} + +/* Send the first nbytes bytes of the buffer */ +CDF_STATUS +hif_send_head(struct ol_softc *scn, + uint8_t pipe, unsigned int transfer_id, unsigned int nbytes, + cdf_nbuf_t nbuf, unsigned int data_attr) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]); + struct CE_handle *ce_hdl = pipe_info->ce_hdl; + int bytes = nbytes, nfrags = 0; + struct ce_sendlist sendlist; + int status, i = 0; + unsigned int mux_id = 0; + + CDF_ASSERT(nbytes <= cdf_nbuf_len(nbuf)); + + transfer_id = + (mux_id & MUX_ID_MASK) | + (transfer_id & TRANSACTION_ID_MASK); + data_attr &= DESC_DATA_FLAG_MASK; + /* + * The common case involves sending multiple fragments within a + * single download (the tx descriptor and the tx frame header). + * So, optimize for the case of multiple fragments by not even + * checking whether it's necessary to use a sendlist. + * The overhead of using a sendlist for a single buffer download + * is not a big deal, since it happens rarely (for WMI messages). + */ + ce_sendlist_init(&sendlist); + do { + uint32_t frag_paddr; + int frag_bytes; + + frag_paddr = cdf_nbuf_get_frag_paddr_lo(nbuf, nfrags); + frag_bytes = cdf_nbuf_get_frag_len(nbuf, nfrags); + /* + * Clear the packet offset for all but the first CE desc. + */ + if (i++ > 0) + data_attr &= ~CDF_CE_TX_PKT_OFFSET_BIT_M; + + status = ce_sendlist_buf_add(&sendlist, frag_paddr, + frag_bytes > + bytes ? bytes : frag_bytes, + cdf_nbuf_get_frag_is_wordstream + (nbuf, + nfrags) ? 0 : + CE_SEND_FLAG_SWAP_DISABLE, + data_attr); + if (status != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: error, frag_num %d larger than limit", + __func__, nfrags); + return status; + } + bytes -= frag_bytes; + nfrags++; + } while (bytes > 0); + + /* Make sure we have resources to handle this request */ + cdf_spin_lock_bh(&pipe_info->completion_freeq_lock); + if (pipe_info->num_sends_allowed < nfrags) { + cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + ce_pkt_error_count_incr(hif_state, HIF_PIPE_NO_RESOURCE); + return CDF_STATUS_E_RESOURCES; + } + pipe_info->num_sends_allowed -= nfrags; + cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + + if (cdf_unlikely(ce_hdl == NULL)) { + HIF_ERROR("%s: error CE handle is null", __func__); + return A_ERROR; + } + + NBUF_UPDATE_TX_PKT_COUNT(nbuf, NBUF_TX_PKT_HIF); + DPTRACE(cdf_dp_trace(nbuf, CDF_DP_TRACE_HIF_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(nbuf)), + sizeof(cdf_nbuf_data(nbuf)))); + status = ce_sendlist_send(ce_hdl, nbuf, &sendlist, transfer_id); + CDF_ASSERT(status == CDF_STATUS_SUCCESS); + + return status; +} + +void hif_send_complete_check(struct ol_softc *scn, uint8_t pipe, int force) +{ + if (!force) { + int resources; + /* + * Decide whether to actually poll for completions, or just + * wait for a later chance. If there seem to be plenty of + * resources left, then just wait, since checking involves + * reading a CE register, which is a relatively expensive + * operation. + */ + resources = hif_get_free_queue_number(scn, pipe); + /* + * If at least 50% of the total resources are still available, + * don't bother checking again yet. + */ + if (resources > (host_ce_config[pipe].src_nentries >> 1)) { + return; + } + } +#ifdef ATH_11AC_TXCOMPACT + ce_per_engine_servicereap(scn, pipe); +#else + ce_per_engine_service(scn, pipe); +#endif +} + +uint16_t hif_get_free_queue_number(struct ol_softc *scn, uint8_t pipe) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]); + uint16_t rv; + + cdf_spin_lock_bh(&pipe_info->completion_freeq_lock); + rv = pipe_info->num_sends_allowed; + cdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + return rv; +} + +/* Called by lower (CE) layer when a send to Target completes. */ +void +hif_pci_ce_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t CE_data, + unsigned int nbytes, unsigned int transfer_id, + unsigned int sw_index, unsigned int hw_index, + unsigned int toeplitz_hash_result) +{ + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)ce_context; + struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state; + struct HIF_CE_completion_state *compl_state; + struct HIF_CE_completion_state *compl_queue_head, *compl_queue_tail; + unsigned int sw_idx = sw_index, hw_idx = hw_index; + + compl_queue_head = compl_queue_tail = NULL; + do { + /* + * For the send completion of an item in sendlist, just increment + * num_sends_allowed. The upper layer callback will be triggered + * when last fragment is done with send. + */ + if (transfer_context == CE_SENDLIST_ITEM_CTXT) { + cdf_spin_lock(&pipe_info->completion_freeq_lock); + pipe_info->num_sends_allowed++; + cdf_spin_unlock(&pipe_info->completion_freeq_lock); + continue; + } + + cdf_spin_lock(&pipe_info->completion_freeq_lock); + compl_state = pipe_info->completion_freeq_head; + if (!compl_state) { + cdf_spin_unlock(&pipe_info->completion_freeq_lock); + HIF_ERROR("%s: ce_id:%d num_allowed:%d pipe_info:%p", + __func__, pipe_info->pipe_num, + pipe_info->num_sends_allowed, + pipe_info); + ASSERT(0); + break; + } + pipe_info->completion_freeq_head = compl_state->next; + cdf_spin_unlock(&pipe_info->completion_freeq_lock); + + compl_state->next = NULL; + compl_state->send_or_recv = HIF_CE_COMPLETE_SEND; + compl_state->copyeng = copyeng; + compl_state->ce_context = ce_context; + compl_state->transfer_context = transfer_context; + compl_state->data = CE_data; + compl_state->nbytes = nbytes; + compl_state->transfer_id = transfer_id; + compl_state->flags = 0; + compl_state->toeplitz_hash_result = toeplitz_hash_result; + + /* Enqueue at end of local queue */ + if (compl_queue_tail) { + compl_queue_tail->next = compl_state; + } else { + compl_queue_head = compl_state; + } + compl_queue_tail = compl_state; + } while (ce_completed_send_next(copyeng, + &ce_context, &transfer_context, + &CE_data, &nbytes, &transfer_id, + &sw_idx, &hw_idx, + &toeplitz_hash_result) == CDF_STATUS_SUCCESS); + + if (compl_queue_head == NULL) { + /* + * If only some of the items within a sendlist have completed, + * don't invoke completion processing until the entire sendlist + * has been sent. + */ + return; + } + + cdf_spin_lock(&hif_state->completion_pendingq_lock); + + /* Enqueue the local completion queue on the + * per-device completion queue */ + if (hif_state->completion_pendingq_head) { + hif_state->completion_pendingq_tail->next = compl_queue_head; + hif_state->completion_pendingq_tail = compl_queue_tail; + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + } else { + hif_state->completion_pendingq_head = compl_queue_head; + hif_state->completion_pendingq_tail = compl_queue_tail; + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + + /* Alert the send completion service thread */ + hif_completion_thread(hif_state); + } +} + +/* Called by lower (CE) layer when data is received from the Target. */ +void +hif_pci_ce_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, cdf_dma_addr_t CE_data, + unsigned int nbytes, unsigned int transfer_id, + unsigned int flags) +{ + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)ce_context; + struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state; + struct ol_softc *scn = hif_state->scn; + struct HIF_CE_completion_state *compl_state; + struct HIF_CE_completion_state *compl_queue_head, *compl_queue_tail; + + compl_queue_head = compl_queue_tail = NULL; + do { + cdf_spin_lock(&pipe_info->completion_freeq_lock); + compl_state = pipe_info->completion_freeq_head; + ASSERT(compl_state != NULL); + pipe_info->completion_freeq_head = compl_state->next; + cdf_spin_unlock(&pipe_info->completion_freeq_lock); + + compl_state->next = NULL; + compl_state->send_or_recv = HIF_CE_COMPLETE_RECV; + compl_state->copyeng = copyeng; + compl_state->ce_context = ce_context; + compl_state->transfer_context = transfer_context; + compl_state->data = CE_data; + compl_state->nbytes = nbytes; + compl_state->transfer_id = transfer_id; + compl_state->flags = flags; + + /* Enqueue at end of local queue */ + if (compl_queue_tail) { + compl_queue_tail->next = compl_state; + } else { + compl_queue_head = compl_state; + } + compl_queue_tail = compl_state; + + cdf_nbuf_unmap_single(scn->cdf_dev, + (cdf_nbuf_t) transfer_context, + CDF_DMA_FROM_DEVICE); + + /* + * EV #112693 - [Peregrine][ES1][WB342][Win8x86][Performance] + * BSoD_0x133 occurred in VHT80 UDP_DL + * Break out DPC by force if number of loops in + * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES to avoid + * spending too long time in DPC for each interrupt handling. + * Schedule another DPC to avoid data loss if we had taken + * force-break action before apply to Windows OS only + * currently, Linux/MAC os can expand to their platform + * if necessary + */ + + /* Set up force_break flag if num of receices reaches + * MAX_NUM_OF_RECEIVES */ + scn->receive_count++; + if (cdf_unlikely(hif_max_num_receives_reached( + scn->receive_count))) { + scn->force_break = 1; + break; + } + } while (ce_completed_recv_next(copyeng, &ce_context, &transfer_context, + &CE_data, &nbytes, &transfer_id, + &flags) == CDF_STATUS_SUCCESS); + + cdf_spin_lock(&hif_state->completion_pendingq_lock); + + /* Enqueue the local completion queue on the + * per-device completion queue */ + if (hif_state->completion_pendingq_head) { + hif_state->completion_pendingq_tail->next = compl_queue_head; + hif_state->completion_pendingq_tail = compl_queue_tail; + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + } else { + hif_state->completion_pendingq_head = compl_queue_head; + hif_state->completion_pendingq_tail = compl_queue_tail; + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + + /* Alert the recv completion service thread */ + hif_completion_thread(hif_state); + } +} + +/* TBDXXX: Set CE High Watermark; invoke txResourceAvailHandler in response */ + +void +hif_post_init(struct ol_softc *scn, void *unused, + struct hif_msg_callbacks *callbacks) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + spin_lock_init(&pcie_access_log_lock); +#endif + /* Save callbacks for later installation */ + cdf_mem_copy(&hif_state->msg_callbacks_pending, callbacks, + sizeof(hif_state->msg_callbacks_pending)); + +} + +static void hif_pci_free_complete_state(struct HIF_CE_pipe_info *pipe_info) +{ + struct HIF_CE_completion_state_list *tmp_list; + + while (pipe_info->completion_space_list) { + tmp_list = pipe_info->completion_space_list; + pipe_info->completion_space_list = tmp_list->next; + cdf_mem_free(tmp_list); + } +} + +static int hif_alloc_complete_state_list( + struct HIF_CE_pipe_info *pipe_info, + int completions_needed) +{ + struct HIF_CE_completion_state *compl_state; + struct HIF_CE_completion_state_list *tmp_list; + int i; + int idx; + int num_list; + int allocated_node; + int num_in_batch; + size_t len; + + allocated_node = 0; + num_list = (completions_needed + HIF_CE_COMPLETE_STATE_NUM -1); + num_list /= HIF_CE_COMPLETE_STATE_NUM; + for (idx = 0; idx < num_list; idx++) { + if (completions_needed - allocated_node >= + HIF_CE_COMPLETE_STATE_NUM) + num_in_batch = HIF_CE_COMPLETE_STATE_NUM; + else + num_in_batch = completions_needed - allocated_node; + if (num_in_batch <= 0) + break; + len = num_in_batch * sizeof(struct HIF_CE_completion_state) + + sizeof(struct HIF_CE_completion_state_list); + /* Allocate structures to track pending send/recv completions */ + tmp_list = + (struct HIF_CE_completion_state_list *) + cdf_mem_malloc(len); + if (!tmp_list) { + HIF_ERROR("%s: compl_state has no mem", __func__); + hif_pci_free_complete_state(pipe_info); + return -1; + } + cdf_mem_zero(tmp_list, len); + compl_state = (struct HIF_CE_completion_state *) + ((uint8_t *)tmp_list + + sizeof(struct HIF_CE_completion_state_list)); + for (i = 0; i < num_in_batch; i++) { + compl_state->send_or_recv = HIF_CE_COMPLETE_FREE; + compl_state->next = NULL; + if (pipe_info->completion_freeq_head) + pipe_info->completion_freeq_tail->next = + compl_state; + else + pipe_info->completion_freeq_head = + compl_state; + pipe_info->completion_freeq_tail = compl_state; + compl_state++; + allocated_node++; + } + if (pipe_info->completion_space_list == NULL) { + pipe_info->completion_space_list = tmp_list; + tmp_list->next = NULL; + } else { + tmp_list->next = + pipe_info->completion_space_list; + pipe_info->completion_space_list = tmp_list; + } + } + cdf_spinlock_init(&pipe_info->completion_freeq_lock); + return 0; +} +int hif_completion_thread_startup(struct HIF_CE_state *hif_state) +{ + struct CE_handle *ce_diag = hif_state->ce_diag; + int pipe_num; + struct ol_softc *scn = hif_state->scn; + + /* daemonize("hif_compl_thread"); */ + + cdf_spinlock_init(&hif_state->completion_pendingq_lock); + hif_state->completion_pendingq_head = + hif_state->completion_pendingq_tail = NULL; + + if (scn->ce_count == 0) { + HIF_ERROR("%s: Invalid ce_count\n", __func__); + return -EINVAL; + } + A_TARGET_ACCESS_LIKELY(scn); + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct CE_attr attr; + struct HIF_CE_pipe_info *pipe_info; + int completions_needed; + + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl == ce_diag) { + continue; /* Handle Diagnostic CE specially */ + } + attr = host_ce_config[pipe_num]; + completions_needed = 0; + if (attr.src_nentries) { + /* pipe used to send to target */ + HIF_INFO_MED("%s: pipe_num:%d pipe_info:0x%p", + __func__, pipe_num, pipe_info); + ce_send_cb_register(pipe_info->ce_hdl, + hif_pci_ce_send_done, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + completions_needed += attr.src_nentries; + pipe_info->num_sends_allowed = attr.src_nentries - 1; + } + if (attr.dest_nentries) { + /* pipe used to receive from target */ + ce_recv_cb_register(pipe_info->ce_hdl, + hif_pci_ce_recv_data, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + completions_needed += attr.dest_nentries; + } + + pipe_info->completion_freeq_head = + pipe_info->completion_freeq_tail = NULL; + if (completions_needed > 0) { + int ret; + + ret = hif_alloc_complete_state_list(pipe_info, + completions_needed); + if (ret != 0) { + HIF_ERROR("%s: ce_id = %d, no mem", + __func__, pipe_info->pipe_num); + return ret; + } + } + } + A_TARGET_ACCESS_UNLIKELY(scn); + return 0; +} + +void hif_completion_thread_shutdown(struct HIF_CE_state *hif_state) +{ + struct HIF_CE_completion_state *compl_state; + struct HIF_CE_pipe_info *pipe_info; + struct ol_softc *scn = hif_state->scn; + int pipe_num; + + /* + * Drop pending completions. These have already been + * reported by the CE layer to us but we have not yet + * passed them upstack. + */ + while ((compl_state = hif_state->completion_pendingq_head) != NULL) { + cdf_nbuf_t netbuf; + + netbuf = (cdf_nbuf_t) compl_state->transfer_context; + cdf_nbuf_free(netbuf); + + hif_state->completion_pendingq_head = compl_state->next; + + /* + * NB: Don't bother to place compl_state on pipe's free queue, + * because we'll free underlying memory for the free queues + * in a moment anyway. + */ + } + + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + pipe_info = &hif_state->pipe_info[pipe_num]; + hif_pci_free_complete_state(pipe_info); + cdf_spinlock_destroy(&pipe_info->completion_freeq_lock); + } + + /* hif_state->compl_thread = NULL; */ + /* complete_and_exit(&hif_state->compl_thread_done, 0); */ +} + +/* + * This thread provides a context in which send/recv completions + * are handled. + * + * Note: HIF installs callback functions with the CE layer. + * Those functions are called directly (e.g. in interrupt context). + * Upper layers (e.g. HTC) have installed callbacks with HIF which + * expect to be called in a thread context. This is where that + * conversion occurs. + * + * TBDXXX: Currently we use just one thread for all pipes. + * This might be sufficient or we might need multiple threads. + */ +int +/* hif_completion_thread(void *hif_dev) */ +hif_completion_thread(struct HIF_CE_state *hif_state) +{ + struct hif_msg_callbacks *msg_callbacks = + &hif_state->msg_callbacks_current; + struct HIF_CE_completion_state *compl_state; + + /* Allow only one instance of the thread to execute at a time to + * prevent out of order processing of messages - this is bad for higher + * layer code + */ + if (!cdf_atomic_dec_and_test(&hif_state->hif_thread_idle)) { + /* We were not the lucky one */ + cdf_atomic_inc(&hif_state->hif_thread_idle); + return 0; + } + + if (!msg_callbacks->fwEventHandler + || !msg_callbacks->txCompletionHandler + || !msg_callbacks->rxCompletionHandler) { + return 0; + } + while (atomic_read(&hif_state->fw_event_pending) > 0) { + /* + * Clear pending state before handling, in case there's + * another while we process the first. + */ + atomic_set(&hif_state->fw_event_pending, 0); + msg_callbacks->fwEventHandler(msg_callbacks->Context, + CDF_STATUS_E_FAILURE); + } + + if (hif_state->scn->target_status == OL_TRGET_STATUS_RESET) + return 0; + + for (;; ) { + struct HIF_CE_pipe_info *pipe_info; + int send_done = 0; + + cdf_spin_lock(&hif_state->completion_pendingq_lock); + + if (!hif_state->completion_pendingq_head) { + /* We are atomically sure that + * there is no pending work */ + cdf_atomic_inc(&hif_state->hif_thread_idle); + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + break; /* All pending completions are handled */ + } + + /* Dequeue the first unprocessed but completed transfer */ + compl_state = hif_state->completion_pendingq_head; + hif_state->completion_pendingq_head = compl_state->next; + cdf_spin_unlock(&hif_state->completion_pendingq_lock); + + pipe_info = (struct HIF_CE_pipe_info *)compl_state->ce_context; + if (compl_state->send_or_recv == HIF_CE_COMPLETE_SEND) { + msg_callbacks->txCompletionHandler(msg_callbacks-> + Context, + compl_state-> + transfer_context, + compl_state-> + transfer_id, + compl_state->toeplitz_hash_result); + send_done = 1; + } else { + /* compl_state->send_or_recv == HIF_CE_COMPLETE_RECV */ + cdf_nbuf_t netbuf; + unsigned int nbytes; + + atomic_inc(&pipe_info->recv_bufs_needed); + hif_post_recv_buffers(hif_state->scn); + + netbuf = (cdf_nbuf_t) compl_state->transfer_context; + nbytes = compl_state->nbytes; + /* + * To see the following debug output, + * enable the HIF_PCI_DEBUG flag in + * the debug module declaration in this source file + */ + HIF_DBG("%s: netbuf=%p, nbytes=%d", + __func__, netbuf, nbytes); + if (nbytes <= pipe_info->buf_sz) { + cdf_nbuf_set_pktlen(netbuf, nbytes); + msg_callbacks-> + rxCompletionHandler(msg_callbacks->Context, + netbuf, + pipe_info->pipe_num); + } else { + HIF_ERROR( + "%s: Invalid Rx msg buf:%p nbytes:%d", + __func__, netbuf, nbytes); + cdf_nbuf_free(netbuf); + } + } + + /* Recycle completion state back to the pipe it came from. */ + compl_state->next = NULL; + compl_state->send_or_recv = HIF_CE_COMPLETE_FREE; + cdf_spin_lock(&pipe_info->completion_freeq_lock); + if (pipe_info->completion_freeq_head) { + pipe_info->completion_freeq_tail->next = compl_state; + } else { + pipe_info->completion_freeq_head = compl_state; + } + pipe_info->completion_freeq_tail = compl_state; + pipe_info->num_sends_allowed += send_done; + cdf_spin_unlock(&pipe_info->completion_freeq_lock); + } + + return 0; +} + +/* + * Install pending msg callbacks. + * + * TBDXXX: This hack is needed because upper layers install msg callbacks + * for use with HTC before BMI is done; yet this HIF implementation + * needs to continue to use BMI msg callbacks. Really, upper layers + * should not register HTC callbacks until AFTER BMI phase. + */ +static void hif_msg_callbacks_install(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + cdf_mem_copy(&hif_state->msg_callbacks_current, + &hif_state->msg_callbacks_pending, + sizeof(hif_state->msg_callbacks_pending)); +} + +void hif_claim_device(struct ol_softc *scn, void *claimedContext) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + hif_state->claimedContext = claimedContext; +} + +void hif_release_device(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + hif_state->claimedContext = NULL; +} + +void +hif_get_default_pipe(struct ol_softc *scn, uint8_t *ULPipe, uint8_t *DLPipe) +{ + int ul_is_polled, dl_is_polled; + + (void)hif_map_service_to_pipe(scn, HTC_CTRL_RSVD_SVC, + ULPipe, DLPipe, &ul_is_polled, &dl_is_polled); +} + +/* TBDXXX - temporary mapping while we have too few CE's */ +int +hif_map_service_to_pipe(struct ol_softc *scn, uint16_t ServiceId, + uint8_t *ULPipe, uint8_t *DLPipe, int *ul_is_polled, + int *dl_is_polled) +{ + int status = CDF_STATUS_SUCCESS; + + *dl_is_polled = 0; /* polling for received messages not supported */ + switch (ServiceId) { + case HTT_DATA_MSG_SVC: + /* + * Host->target HTT gets its own pipe, so it can be polled + * while other pipes are interrupt driven. + */ + *ULPipe = 4; + /* + * Use the same target->host pipe for HTC ctrl, + * HTC raw streams, and HTT. + */ + *DLPipe = 1; + break; + + case HTC_CTRL_RSVD_SVC: + *ULPipe = 0; + *DLPipe = 2; + break; + + case HTC_RAW_STREAMS_SVC: + /* + * Note: HTC_RAW_STREAMS_SVC is currently unused, and + * HTC_CTRL_RSVD_SVC could share the same pipe as the + * WMI services. So, if another CE is needed, change + * this to *ULPipe = 3, which frees up CE 0. + */ + /**ULPipe = 3; */ + *ULPipe = 0; + *DLPipe = 2; + break; + + case WMI_DATA_BK_SVC: + /* + * To avoid some confusions, better to introduce new EP-ping + * service instead of using existed services. Until the main + * framework support this, keep this design. + */ + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + *ULPipe = 4; + *DLPipe = 1; + break; + } + case WMI_DATA_BE_SVC: + case WMI_DATA_VI_SVC: + case WMI_DATA_VO_SVC: + + case WMI_CONTROL_SVC: + *ULPipe = 3; + *DLPipe = 2; + break; + + case WDI_IPA_TX_SVC: + *ULPipe = 5; + break; + + /* pipe 5 unused */ + /* pipe 6 reserved */ + /* pipe 7 reserved */ + + default: + status = CDF_STATUS_E_INVAL; + break; + } + *ul_is_polled = + (host_ce_config[*ULPipe].flags & CE_ATTR_DISABLE_INTR) != 0; + + return status; +} + +/** + * hif_dump_pipe_debug_count() - Log error count + * @scn: ol_softc pointer. + * + * Output the pipe error counts of each pipe to log file + * + * Return: N/A + */ +void hif_dump_pipe_debug_count(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state; + int pipe_num; + + if (scn == NULL) { + HIF_ERROR("%s scn is NULL", __func__); + return; + } + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + if (hif_state == NULL) { + HIF_ERROR("%s hif_state is NULL", __func__); + return; + } + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + + if (pipe_info->nbuf_alloc_err_count > 0 || + pipe_info->nbuf_dma_err_count > 0 || + pipe_info->nbuf_ce_enqueue_err_count) + HIF_ERROR( + "%s: pipe_id = %d, recv_bufs_needed = %d, nbuf_alloc_err_count = %u, nbuf_dma_err_count = %u, nbuf_ce_enqueue_err_count = %u", + __func__, pipe_info->pipe_num, + atomic_read(&pipe_info->recv_bufs_needed), + pipe_info->nbuf_alloc_err_count, + pipe_info->nbuf_dma_err_count, + pipe_info->nbuf_ce_enqueue_err_count); + } +} + +static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct CE_handle *ce_hdl; + cdf_size_t buf_sz; + struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state; + struct ol_softc *scn = hif_state->scn; + CDF_STATUS ret; + uint32_t bufs_posted = 0; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return 0; + } + + ce_hdl = pipe_info->ce_hdl; + + cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + while (atomic_read(&pipe_info->recv_bufs_needed) > 0) { + cdf_dma_addr_t CE_data; /* CE space buffer address */ + cdf_nbuf_t nbuf; + int status; + + atomic_dec(&pipe_info->recv_bufs_needed); + cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + + nbuf = cdf_nbuf_alloc(scn->cdf_dev, buf_sz, 0, 4, false); + if (!nbuf) { + cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + pipe_info->nbuf_alloc_err_count++; + cdf_spin_unlock_bh( + &pipe_info->recv_bufs_needed_lock); + HIF_ERROR( + "%s buf alloc error [%d] needed %d, nbuf_alloc_err_count = %u", + __func__, pipe_info->pipe_num, + atomic_read(&pipe_info->recv_bufs_needed), + pipe_info->nbuf_alloc_err_count); + atomic_inc(&pipe_info->recv_bufs_needed); + return 1; + } + + /* + * cdf_nbuf_peek_header(nbuf, &data, &unused); + * CE_data = dma_map_single(dev, data, buf_sz, ); + * DMA_FROM_DEVICE); + */ + ret = + cdf_nbuf_map_single(scn->cdf_dev, nbuf, + CDF_DMA_FROM_DEVICE); + + if (unlikely(ret != CDF_STATUS_SUCCESS)) { + cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + pipe_info->nbuf_dma_err_count++; + cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + HIF_ERROR( + "%s buf alloc error [%d] needed %d, nbuf_dma_err_count = %u", + __func__, pipe_info->pipe_num, + atomic_read(&pipe_info->recv_bufs_needed), + pipe_info->nbuf_dma_err_count); + cdf_nbuf_free(nbuf); + atomic_inc(&pipe_info->recv_bufs_needed); + return 1; + } + + CE_data = cdf_nbuf_get_frag_paddr_lo(nbuf, 0); + + cdf_os_mem_dma_sync_single_for_device(scn->cdf_dev, CE_data, + buf_sz, DMA_FROM_DEVICE); + status = ce_recv_buf_enqueue(ce_hdl, (void *)nbuf, CE_data); + CDF_ASSERT(status == CDF_STATUS_SUCCESS); + if (status != EOK) { + cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + pipe_info->nbuf_ce_enqueue_err_count++; + cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + HIF_ERROR( + "%s buf alloc error [%d] needed %d, nbuf_alloc_err_count = %u", + __func__, pipe_info->pipe_num, + atomic_read(&pipe_info->recv_bufs_needed), + pipe_info->nbuf_ce_enqueue_err_count); + atomic_inc(&pipe_info->recv_bufs_needed); + cdf_nbuf_free(nbuf); + return 1; + } + + cdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + bufs_posted++; + } + pipe_info->nbuf_alloc_err_count = + (pipe_info->nbuf_alloc_err_count > bufs_posted)? + pipe_info->nbuf_alloc_err_count - bufs_posted : 0; + pipe_info->nbuf_dma_err_count = + (pipe_info->nbuf_dma_err_count > bufs_posted)? + pipe_info->nbuf_dma_err_count - bufs_posted : 0; + pipe_info->nbuf_ce_enqueue_err_count = + (pipe_info->nbuf_ce_enqueue_err_count > bufs_posted)? + pipe_info->nbuf_ce_enqueue_err_count - bufs_posted : 0; + + cdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + + return 0; +} + +/* + * Try to post all desired receive buffers for all pipes. + * Returns 0 if all desired buffers are posted, + * non-zero if were were unable to completely + * replenish receive buffers. + */ +static int hif_post_recv_buffers(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + int pipe_num, rv = 0; + + A_TARGET_ACCESS_LIKELY(scn); + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + if (hif_post_recv_buffers_for_pipe(pipe_info)) { + rv = 1; + goto done; + } + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + return rv; +} + +CDF_STATUS hif_start(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + + if (hif_completion_thread_startup(hif_state)) + return CDF_STATUS_E_FAILURE; + + hif_msg_callbacks_install(scn); + + /* Post buffers once to start things off. */ + (void)hif_post_recv_buffers(scn); + + hif_state->started = true; + + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hif_enable_fastpath() Update that we have enabled fastpath mode + * @hif_device: HIF context + * + * For use in data path + * + * Retrun: void + */ +void +hif_enable_fastpath(struct ol_softc *hif_device) +{ + HIF_INFO("Enabling fastpath mode\n"); + hif_device->fastpath_mode_on = 1; +} +#endif /* WLAN_FEATURE_FASTPATH */ + +void hif_recv_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct ol_softc *scn; + struct CE_handle *ce_hdl; + uint32_t buf_sz; + struct HIF_CE_state *hif_state; + cdf_nbuf_t netbuf; + cdf_dma_addr_t CE_data; + void *per_CE_context; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return; + } + + hif_state = pipe_info->HIF_CE_state; + if (!hif_state->started) { + return; + } + + scn = hif_state->scn; + ce_hdl = pipe_info->ce_hdl; + + if (scn->cdf_dev == NULL) { + return; + } + while (ce_revoke_recv_next + (ce_hdl, &per_CE_context, (void **)&netbuf, + &CE_data) == CDF_STATUS_SUCCESS) { + cdf_nbuf_unmap_single(scn->cdf_dev, netbuf, + CDF_DMA_FROM_DEVICE); + cdf_nbuf_free(netbuf); + } +} + +void hif_send_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct CE_handle *ce_hdl; + struct HIF_CE_state *hif_state; + cdf_nbuf_t netbuf; + void *per_CE_context; + cdf_dma_addr_t CE_data; + unsigned int nbytes; + unsigned int id; + uint32_t buf_sz; + uint32_t toeplitz_hash_result; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return; + } + + hif_state = pipe_info->HIF_CE_state; + if (!hif_state->started) { + return; + } + + ce_hdl = pipe_info->ce_hdl; + + while (ce_cancel_send_next + (ce_hdl, &per_CE_context, + (void **)&netbuf, &CE_data, &nbytes, + &id, &toeplitz_hash_result) == CDF_STATUS_SUCCESS) { + if (netbuf != CE_SENDLIST_ITEM_CTXT) { + /* + * Packets enqueued by htt_h2t_ver_req_msg() and + * htt_h2t_rx_ring_cfg_msg_ll() have already been + * freed in htt_htc_misc_pkt_pool_free() in + * wlantl_close(), so do not free them here again + * by checking whether it's the EndPoint + * which they are queued in. + */ + if (id == hif_state->scn->htc_endpoint) + return; + /* Indicate the completion to higer + * layer to free the buffer */ + hif_state->msg_callbacks_current. + txCompletionHandler(hif_state-> + msg_callbacks_current.Context, + netbuf, id, toeplitz_hash_result); + } + } +} + +/* + * Cleanup residual buffers for device shutdown: + * buffers that were enqueued for receive + * buffers that were to be sent + * Note: Buffers that had completed but which were + * not yet processed are on a completion queue. They + * are handled when the completion thread shuts down. + */ +void hif_buffer_cleanup(struct HIF_CE_state *hif_state) +{ + int pipe_num; + + for (pipe_num = 0; pipe_num < hif_state->scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + hif_recv_buffer_cleanup_on_pipe(pipe_info); + hif_send_buffer_cleanup_on_pipe(pipe_info); + } +} + +void hif_flush_surprise_remove(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + hif_buffer_cleanup(hif_state); +} + +void hif_stop(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + int pipe_num; + + scn->hif_init_done = false; + if (hif_state->started) { + /* sync shutdown */ + hif_completion_thread_shutdown(hif_state); + hif_completion_thread(hif_state); + } else { + hif_completion_thread_shutdown(hif_state); + } + + /* + * At this point, asynchronous threads are stopped, + * The Target should not DMA nor interrupt, Host code may + * not initiate anything more. So we just need to clean + * up Host-side state. + */ + + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + + hif_buffer_cleanup(hif_state); + + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl) { + ce_fini(pipe_info->ce_hdl); + pipe_info->ce_hdl = NULL; + pipe_info->buf_sz = 0; + } + } + + if (hif_state->sleep_timer_init) { + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + cdf_softirq_timer_free(&hif_state->sleep_timer); + hif_state->sleep_timer_init = false; + } + + hif_state->started = false; +} + +#define ADRASTEA_SRC_WR_INDEX_OFFSET 0x3C +#define ADRASTEA_DST_WR_INDEX_OFFSET 0x40 + + +static struct shadow_reg_cfg target_shadow_reg_cfg_map[] = { + { 0, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 3, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 4, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 5, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 7, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 1, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 2, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 7, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 8, ADRASTEA_DST_WR_INDEX_OFFSET}, +}; + + + +/* CE_PCI TABLE */ +/* + * NOTE: the table below is out of date, though still a useful reference. + * Refer to target_service_to_ce_map and hif_map_service_to_pipe for the actual + * mapping of HTC services to HIF pipes. + */ +/* + * This authoritative table defines Copy Engine configuration and the mapping + * of services/endpoints to CEs. A subset of this information is passed to + * the Target during startup as a prerequisite to entering BMI phase. + * See: + * target_service_to_ce_map - Target-side mapping + * hif_map_service_to_pipe - Host-side mapping + * target_ce_config - Target-side configuration + * host_ce_config - Host-side configuration + ============================================================================ + Purpose | Service / Endpoint | CE | Dire | Xfer | Xfer + | | | ctio | Size | Frequency + | | | n | | + ============================================================================ + tx | HTT_DATA (downlink) | CE 0 | h->t | medium - | very frequent + descriptor | | | | O(100B) | and regular + download | | | | | + ---------------------------------------------------------------------------- + rx | HTT_DATA (uplink) | CE 1 | t->h | small - | frequent and + indication | | | | O(10B) | regular + upload | | | | | + ---------------------------------------------------------------------------- + MSDU | DATA_BK (uplink) | CE 2 | t->h | large - | rare + upload | | | | O(1000B) | (frequent + e.g. noise | | | | | during IP1.0 + packets | | | | | testing) + ---------------------------------------------------------------------------- + MSDU | DATA_BK (downlink) | CE 3 | h->t | large - | very rare + download | | | | O(1000B) | (frequent + e.g. | | | | | during IP1.0 + misdirecte | | | | | testing) + d EAPOL | | | | | + packets | | | | | + ---------------------------------------------------------------------------- + n/a | DATA_BE, DATA_VI | CE 2 | t->h | | never(?) + | DATA_VO (uplink) | | | | + ---------------------------------------------------------------------------- + n/a | DATA_BE, DATA_VI | CE 3 | h->t | | never(?) + | DATA_VO (downlink) | | | | + ---------------------------------------------------------------------------- + WMI events | WMI_CONTROL (uplink) | CE 4 | t->h | medium - | infrequent + | | | | O(100B) | + ---------------------------------------------------------------------------- + WMI | WMI_CONTROL | CE 5 | h->t | medium - | infrequent + messages | (downlink) | | | O(100B) | + | | | | | + ---------------------------------------------------------------------------- + n/a | HTC_CTRL_RSVD, | CE 1 | t->h | | never(?) + | HTC_RAW_STREAMS | | | | + | (uplink) | | | | + ---------------------------------------------------------------------------- + n/a | HTC_CTRL_RSVD, | CE 0 | h->t | | never(?) + | HTC_RAW_STREAMS | | | | + | (downlink) | | | | + ---------------------------------------------------------------------------- + diag | none (raw CE) | CE 7 | t<>h | 4 | Diag Window + | | | | | infrequent + ============================================================================ + */ + +/* + * Map from service/endpoint to Copy Engine. + * This table is derived from the CE_PCI TABLE, above. + * It is passed to the Target at startup for use by firmware. + */ +static struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + WMI_DATA_VO_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VO_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, /* could be moved to 3 (share with WMI) */ + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTT_DATA_MSG_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 4, + }, + { + HTT_DATA_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + WDI_IPA_TX_SVC, + PIPEDIR_OUT, /* in = DL = target -> host */ + 5, + }, + /* (Additions here) */ + + { /* Must be last */ + 0, + 0, + 0, + }, +}; + +static struct service_to_pipe *target_service_to_ce_map = + target_service_to_ce_map_wlan; +static int target_service_to_ce_map_sz = sizeof(target_service_to_ce_map_wlan); + +static struct shadow_reg_cfg *target_shadow_reg_cfg = target_shadow_reg_cfg_map; +static int shadow_cfg_sz = sizeof(target_shadow_reg_cfg_map); + +static struct service_to_pipe target_service_to_ce_map_wlan_epping[] = { + {WMI_DATA_VO_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_VO_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_DATA_BK_SVC, PIPEDIR_OUT, 4,}, /* out = UL = host -> target */ + {WMI_DATA_BK_SVC, PIPEDIR_IN, 1,}, /* in = DL = target -> host */ + {WMI_DATA_BE_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_BE_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_DATA_VI_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_VI_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_CONTROL_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_CONTROL_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTC_CTRL_RSVD_SVC, PIPEDIR_OUT, 0,}, /* out = UL = host -> target */ + {HTC_CTRL_RSVD_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTC_RAW_STREAMS_SVC, PIPEDIR_OUT, 0,}, /* out = UL = host -> target */ + {HTC_RAW_STREAMS_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTT_DATA_MSG_SVC, PIPEDIR_OUT, 4,}, /* out = UL = host -> target */ + {HTT_DATA_MSG_SVC, PIPEDIR_IN, 1,}, /* in = DL = target -> host */ + {0, 0, 0,}, /* Must be last */ +}; + +#ifdef HIF_PCI +/* + * Send an interrupt to the device to wake up the Target CPU + * so it has an opportunity to notice any changed state. + */ +void hif_wake_target_cpu(struct ol_softc *scn) +{ + CDF_STATUS rv; + uint32_t core_ctrl; + + rv = hif_diag_read_access(scn, + SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS, + &core_ctrl); + CDF_ASSERT(rv == CDF_STATUS_SUCCESS); + /* A_INUM_FIRMWARE interrupt to Target CPU */ + core_ctrl |= CORE_CTRL_CPU_INTR_MASK; + + rv = hif_diag_write_access(scn, + SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS, + core_ctrl); + CDF_ASSERT(rv == CDF_STATUS_SUCCESS); +} +#endif + +static void hif_sleep_entry(void *arg) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)arg; + struct ol_softc *scn = hif_state->scn; + uint32_t idle_ms; + if (scn->recovery) + return; + + cdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + if (hif_state->verified_awake == false) { + idle_ms = cdf_system_ticks_to_msecs(cdf_system_ticks() + - hif_state->sleep_ticks); + if (idle_ms >= HIF_MIN_SLEEP_INACTIVITY_TIME_MS) { + if (!cdf_atomic_read(&scn->link_suspended)) { + soc_wake_reset(scn); + hif_state->fake_sleep = false; + } + } else { + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + cdf_softirq_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + } else { + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + cdf_softirq_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + cdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); +} +#define HIF_HIA_MAX_POLL_LOOP 1000000 +#define HIF_HIA_POLLING_DELAY_MS 10 + +#ifndef HIF_PCI +int hif_set_hia(struct ol_softc *scn) +{ + return 0; +} +#else +int hif_set_hia(struct ol_softc *scn) +{ + CDF_STATUS rv; + uint32_t interconnect_targ_addr = 0; + uint32_t pcie_state_targ_addr = 0; + uint32_t pipe_cfg_targ_addr = 0; + uint32_t svc_to_pipe_map = 0; + uint32_t pcie_config_flags = 0; + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr = 0; +#ifdef QCA_WIFI_3_0 + uint32_t host_interest_area = 0; + uint8_t i; +#else + uint32_t ealloc_value = 0; + uint32_t ealloc_targ_addr = 0; + uint8_t banks_switched = 1; + uint32_t chip_id; +#endif + uint32_t pipe_cfg_addr; + + HIF_TRACE("%s: E", __func__); + + if (IHELIUM_BU || ADRASTEA_BU) + return CDF_STATUS_SUCCESS; + +#ifdef QCA_WIFI_3_0 + i = 0; + while (i < HIF_HIA_MAX_POLL_LOOP) { + host_interest_area = hif_read32_mb(scn->mem + + A_SOC_CORE_SCRATCH_0_ADDRESS); + if ((host_interest_area & 0x01) == 0) { + cdf_mdelay(HIF_HIA_POLLING_DELAY_MS); + host_interest_area = 0; + i++; + if (i > HIF_HIA_MAX_POLL_LOOP && (i % 1000 == 0)) { + HIF_ERROR("%s: poll timeout(%d)", __func__, i); + } + } else { + host_interest_area &= (~0x01); + hif_write32_mb(scn->mem + 0x113014, 0); + break; + } + } + + if (i >= HIF_HIA_MAX_POLL_LOOP) { + HIF_ERROR("%s: hia polling timeout", __func__); + return -EIO; + } + + if (host_interest_area == 0) { + HIF_ERROR("%s: host_interest_area = 0", __func__); + return -EIO; + } + + interconnect_targ_addr = host_interest_area + + offsetof(struct host_interest_area_t, + hi_interconnect_state); + + flag2_targ_addr = host_interest_area + + offsetof(struct host_interest_area_t, hi_option_flag2); + +#else + interconnect_targ_addr = hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_interconnect_state)); + ealloc_targ_addr = hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_early_alloc)); + flag2_targ_addr = hif_hia_item_address(scn->target_type, + offsetof(struct host_interest_s, hi_option_flag2)); +#endif + /* Supply Target-side CE configuration */ + rv = hif_diag_read_access(scn, interconnect_targ_addr, + &pcie_state_targ_addr); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: interconnect_targ_addr = 0x%0x, ret = %d", + __func__, interconnect_targ_addr, rv); + goto done; + } + if (pcie_state_targ_addr == 0) { + rv = CDF_STATUS_E_FAILURE; + HIF_ERROR("%s: pcie state addr is 0", __func__); + goto done; + } + pipe_cfg_addr = pcie_state_targ_addr + + offsetof(struct pcie_state_s, + pipe_cfg_addr); + rv = hif_diag_read_access(scn, + pipe_cfg_addr, + &pipe_cfg_targ_addr); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: pipe_cfg_addr = 0x%0x, ret = %d", + __func__, pipe_cfg_addr, rv); + goto done; + } + if (pipe_cfg_targ_addr == 0) { + rv = CDF_STATUS_E_FAILURE; + HIF_ERROR("%s: pipe cfg addr is 0", __func__); + goto done; + } + + rv = hif_diag_write_mem(scn, pipe_cfg_targ_addr, + (uint8_t *) target_ce_config, + target_ce_config_sz); + + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write pipe cfg (%d)", __func__, rv); + goto done; + } + + rv = hif_diag_read_access(scn, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + svc_to_pipe_map), + &svc_to_pipe_map); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get svc/pipe map (%d)", __func__, rv); + goto done; + } + if (svc_to_pipe_map == 0) { + rv = CDF_STATUS_E_FAILURE; + HIF_ERROR("%s: svc_to_pipe map is 0", __func__); + goto done; + } + + rv = hif_diag_write_mem(scn, + svc_to_pipe_map, + (uint8_t *) target_service_to_ce_map, + target_service_to_ce_map_sz); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write svc/pipe map (%d)", __func__, rv); + goto done; + } + + rv = hif_diag_read_access(scn, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + config_flags), + &pcie_config_flags); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get pcie config_flags (%d)", __func__, rv); + goto done; + } +#if (CONFIG_PCIE_ENABLE_L1_CLOCK_GATE) + pcie_config_flags |= PCIE_CONFIG_FLAG_ENABLE_L1; +#else + pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1; +#endif /* CONFIG_PCIE_ENABLE_L1_CLOCK_GATE */ + pcie_config_flags |= PCIE_CONFIG_FLAG_CLK_SWITCH_WAIT; +#if (CONFIG_PCIE_ENABLE_AXI_CLK_GATE) + pcie_config_flags |= PCIE_CONFIG_FLAG_AXI_CLK_GATE; +#endif + rv = hif_diag_write_mem(scn, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + config_flags), + (uint8_t *) &pcie_config_flags, + sizeof(pcie_config_flags)); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write pcie config_flags (%d)", __func__, rv); + goto done; + } + +#ifndef QCA_WIFI_3_0 + /* configure early allocation */ + ealloc_targ_addr = hif_hia_item_address(scn->target_type, + offsetof( + struct host_interest_s, + hi_early_alloc)); + + rv = hif_diag_read_access(scn, ealloc_targ_addr, + &ealloc_value); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get early alloc val (%d)", __func__, rv); + goto done; + } + + /* 1 bank is switched to IRAM, except ROME 1.0 */ + ealloc_value |= + ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & + HI_EARLY_ALLOC_MAGIC_MASK); + + rv = hif_diag_read_access(scn, + CHIP_ID_ADDRESS | + RTC_SOC_BASE_ADDRESS, &chip_id); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get chip id val (%d)", __func__, rv); + goto done; + } + if (CHIP_ID_VERSION_GET(chip_id) == 0xD) { + scn->target_revision = + CHIP_ID_REVISION_GET(chip_id); + switch (CHIP_ID_REVISION_GET(chip_id)) { + case 0x2: /* ROME 1.3 */ + /* 2 banks are switched to IRAM */ + banks_switched = 2; + break; + case 0x4: /* ROME 2.1 */ + case 0x5: /* ROME 2.2 */ + banks_switched = 6; + break; + case 0x8: /* ROME 3.0 */ + case 0x9: /* ROME 3.1 */ + case 0xA: /* ROME 3.2 */ + banks_switched = 9; + break; + case 0x0: /* ROME 1.0 */ + case 0x1: /* ROME 1.1 */ + default: + /* 3 banks are switched to IRAM */ + banks_switched = 3; + break; + } + } + + ealloc_value |= + ((banks_switched << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) + & HI_EARLY_ALLOC_IRAM_BANKS_MASK); + + rv = hif_diag_write_access(scn, + ealloc_targ_addr, + ealloc_value); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: set early alloc val (%d)", __func__, rv); + goto done; + } +#endif + + /* Tell Target to proceed with initialization */ + flag2_targ_addr = hif_hia_item_address(scn->target_type, + offsetof( + struct host_interest_s, + hi_option_flag2)); + + rv = hif_diag_read_access(scn, flag2_targ_addr, + &flag2_value); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get option val (%d)", __func__, rv); + goto done; + } + + flag2_value |= HI_OPTION_EARLY_CFG_DONE; + rv = hif_diag_write_access(scn, flag2_targ_addr, + flag2_value); + if (rv != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: set option val (%d)", __func__, rv); + goto done; + } + + hif_wake_target_cpu(scn); + +done: + + return rv; +} +#endif + +/** + * hif_wlan_enable(): call the platform driver to enable wlan + * + * This function passes the con_mode and CE configuration to + * platform driver to enable wlan. + * + * Return: void + */ +static int hif_wlan_enable(void) +{ + struct icnss_wlan_enable_cfg cfg; + enum icnss_driver_mode mode; + uint32_t con_mode = cds_get_conparam(); + + cfg.num_ce_tgt_cfg = target_ce_config_sz / + sizeof(struct CE_pipe_config); + cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)target_ce_config; + cfg.num_ce_svc_pipe_cfg = target_service_to_ce_map_sz / + sizeof(struct service_to_pipe); + cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)target_service_to_ce_map; + cfg.num_shadow_reg_cfg = shadow_cfg_sz / sizeof(struct shadow_reg_cfg); + cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) target_shadow_reg_cfg; + + switch (con_mode) { + case CDF_FTM_MODE: + mode = ICNSS_FTM; + break; + case CDF_EPPING_MODE: + mode = ICNSS_EPPING; + break; + default: + mode = ICNSS_MISSION; + break; + } + return icnss_wlan_enable(&cfg, mode, QWLAN_VERSIONSTR); +} + +#if ((!defined(QCA_WIFI_3_0_IHELIUM) && !defined(QCA_WIFI_3_0_ADRASTEA)) || defined(CONFIG_ICNSS)) +static inline void cnss_pcie_notify_q6(void) +{ + return; +} +#endif + +/* + * Called from PCI layer whenever a new PCI device is probed. + * Initializes per-device HIF state and notifies the main + * driver that a new HIF device is present. + */ +int hif_config_ce(hif_handle_t hif_hdl) +{ + struct HIF_CE_state *hif_state; + struct HIF_CE_pipe_info *pipe_info; + int pipe_num; +#ifdef ADRASTEA_SHADOW_REGISTERS + int i; +#endif + CDF_STATUS rv = CDF_STATUS_SUCCESS; + int ret; + struct ol_softc *scn = hif_hdl; + struct icnss_soc_info soc_info; + + /* if epping is enabled we need to use the epping configuration. */ + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + if (WLAN_IS_EPPING_IRQ(cds_get_conparam())) + host_ce_config = host_ce_config_wlan_epping_irq; + else + host_ce_config = host_ce_config_wlan_epping_poll; + target_ce_config = target_ce_config_wlan_epping; + target_ce_config_sz = sizeof(target_ce_config_wlan_epping); + target_service_to_ce_map = + target_service_to_ce_map_wlan_epping; + target_service_to_ce_map_sz = + sizeof(target_service_to_ce_map_wlan_epping); + } + + ret = hif_wlan_enable(); + + if (ret) { + HIF_ERROR("%s: hif_wlan_enable error = %d", __func__, ret); + return CDF_STATUS_NOT_INITIALIZED; + } + if (IHELIUM_BU) { + cnss_pcie_notify_q6(); + HIF_TRACE("%s: cnss_pcie_notify_q6 done, notice_send= %d", + __func__, scn->notice_send); + } + + scn->notice_send = true; + + cdf_mem_zero(&soc_info, sizeof(soc_info)); + ret = icnss_get_soc_info(&soc_info); + if (ret < 0) { + HIF_ERROR("%s: icnss_get_soc_info error = %d", __func__, ret); + return CDF_STATUS_NOT_INITIALIZED; + } + + hif_state = (struct HIF_CE_state *)cdf_mem_malloc(sizeof(*hif_state)); + if (!hif_state) { + return -ENOMEM; + } + cdf_mem_zero(hif_state, sizeof(*hif_state)); + + hif_state->scn = scn; + scn->hif_hdl = hif_state; + scn->mem = soc_info.v_addr; + scn->mem_pa = soc_info.p_addr; + scn->soc_version = soc_info.version; + + cdf_spinlock_init(&hif_state->keep_awake_lock); + + cdf_atomic_init(&hif_state->hif_thread_idle); + cdf_atomic_inc(&hif_state->hif_thread_idle); + + hif_state->keep_awake_count = 0; + + hif_state->fake_sleep = false; + hif_state->sleep_ticks = 0; + cdf_softirq_timer_init(NULL, &hif_state->sleep_timer, + hif_sleep_entry, (void *)hif_state, + CDF_TIMER_TYPE_WAKE_APPS); + hif_state->sleep_timer_init = true; + hif_state->fw_indicator_address = FW_INDICATOR_ADDRESS; +#ifdef HIF_PCI +#if CONFIG_ATH_PCIE_MAX_PERF || CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD + /* Force AWAKE forever/till the driver is loaded */ + if (hif_target_sleep_state_adjust(scn, false, true) < 0) + return -EACCES; +#endif +#endif + + /* During CE initializtion */ + scn->ce_count = HOST_CE_COUNT; + A_TARGET_ACCESS_LIKELY(scn); + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct CE_attr *attr; + + pipe_info = &hif_state->pipe_info[pipe_num]; + pipe_info->pipe_num = pipe_num; + pipe_info->HIF_CE_state = hif_state; + attr = &host_ce_config[pipe_num]; + pipe_info->ce_hdl = ce_init(scn, pipe_num, attr); + CDF_ASSERT(pipe_info->ce_hdl != NULL); + if (pipe_info->ce_hdl == NULL) { + rv = CDF_STATUS_E_FAILURE; + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + + if (pipe_num == DIAG_CE_ID) { + /* Reserve the ultimate CE for + * Diagnostic Window support */ + hif_state->ce_diag = + hif_state->pipe_info[scn->ce_count - 1].ce_hdl; + continue; + } + + pipe_info->buf_sz = (cdf_size_t) (attr->src_sz_max); + cdf_spinlock_init(&pipe_info->recv_bufs_needed_lock); + if (attr->dest_nentries > 0) { + atomic_set(&pipe_info->recv_bufs_needed, + init_buffer_count(attr->dest_nentries - 1)); + } else { + atomic_set(&pipe_info->recv_bufs_needed, 0); + } + ce_tasklet_init(hif_state, (1 << pipe_num)); + ce_register_irq(hif_state, (1 << pipe_num)); + scn->request_irq_done = true; + } + + if (athdiag_procfs_init(scn) != 0) { + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + scn->athdiag_procfs_inited = true; + + /* + * Initially, establish CE completion handlers for use with BMI. + * These are overwritten with generic handlers after we exit BMI phase. + */ + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_TARG]; +#ifdef HIF_PCI + ce_send_cb_register( + pipe_info->ce_hdl, hif_bmi_send_done, pipe_info, 0); +#ifndef BMI_RSP_POLLING + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_HOST]; + ce_recv_cb_register( + pipe_info->ce_hdl, hif_bmi_recv_data, pipe_info, 0); +#endif +#endif + HIF_INFO_MED("%s: ce_init done", __func__); + + rv = hif_set_hia(scn); + + HIF_INFO_MED("%s: hif_set_hia done", __func__); + + A_TARGET_ACCESS_UNLIKELY(scn); + + if (rv != CDF_STATUS_SUCCESS) + goto err; + else + init_tasklet_workers(); + + HIF_TRACE("%s: X, ret = %d\n", __func__, rv); + +#ifdef ADRASTEA_SHADOW_REGISTERS + HIF_ERROR("Using Shadow Registers instead of CE Registers\n"); + for (i = 0; i < NUM_SHADOW_REGISTERS; i++) { + HIF_ERROR("%s Shadow Register%d is mapped to address %x\n", + __func__, i, + (A_TARGET_READ(scn, (SHADOW_ADDRESS(i))) << 2)); + } +#endif + + + return rv != CDF_STATUS_SUCCESS; + +err: + /* Failure, so clean up */ + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl) { + ce_unregister_irq(hif_state, (1 << pipe_num)); + scn->request_irq_done = false; + ce_fini(pipe_info->ce_hdl); + pipe_info->ce_hdl = NULL; + pipe_info->buf_sz = 0; + } + } + if (hif_state->sleep_timer_init) { + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + cdf_softirq_timer_free(&hif_state->sleep_timer); + hif_state->sleep_timer_init = false; + } + if (scn->hif_hdl) { + scn->hif_hdl = NULL; + cdf_mem_free(hif_state); + } + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + HIF_TRACE("%s: X, ret = %d\n", __func__, rv); + return CDF_STATUS_SUCCESS != CDF_STATUS_E_FAILURE; +} + + + + + + +#ifdef IPA_OFFLOAD +void hif_ipa_get_ce_resource(struct ol_softc *scn, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + struct HIF_CE_pipe_info *pipe_info = + &(hif_state->pipe_info[HIF_PCI_IPA_UC_ASSIGNED_CE]); + struct CE_handle *ce_hdl = pipe_info->ce_hdl; + + ce_ipa_get_resource(ce_hdl, ce_sr_base_paddr, ce_sr_ring_size, + ce_reg_paddr); + return; +} +#endif /* IPA_OFFLOAD */ + + +#ifdef ADRASTEA_SHADOW_REGISTERS + +/* + Current shadow register config + + ----------------------------------------------------------- + Shadow Register | CE | src/dst write index + ----------------------------------------------------------- + 0 | 0 | src + 1 No Config - Doesn't point to anything + 2 No Config - Doesn't point to anything + 3 | 3 | src + 4 | 4 | src + 5 | 5 | src + 6 No Config - Doesn't point to anything + 7 | 7 | src + 8 No Config - Doesn't point to anything + 9 No Config - Doesn't point to anything + 10 No Config - Doesn't point to anything + 11 No Config - Doesn't point to anything + ----------------------------------------------------------- + 12 No Config - Doesn't point to anything + 13 | 1 | dst + 14 | 2 | dst + 15 No Config - Doesn't point to anything + 16 No Config - Doesn't point to anything + 17 No Config - Doesn't point to anything + 18 No Config - Doesn't point to anything + 19 | 7 | dst + 20 | 8 | dst + 21 No Config - Doesn't point to anything + 22 No Config - Doesn't point to anything + 23 No Config - Doesn't point to anything + ----------------------------------------------------------- + + + ToDo - Move shadow register config to following in the future + This helps free up a block of shadow registers towards the end. + Can be used for other purposes + + ----------------------------------------------------------- + Shadow Register | CE | src/dst write index + ----------------------------------------------------------- + 0 | 0 | src + 1 | 3 | src + 2 | 4 | src + 3 | 5 | src + 4 | 7 | src + ----------------------------------------------------------- + 5 | 1 | dst + 6 | 2 | dst + 7 | 7 | dst + 8 | 8 | dst + ----------------------------------------------------------- + 9 No Config - Doesn't point to anything + 12 No Config - Doesn't point to anything + 13 No Config - Doesn't point to anything + 14 No Config - Doesn't point to anything + 15 No Config - Doesn't point to anything + 16 No Config - Doesn't point to anything + 17 No Config - Doesn't point to anything + 18 No Config - Doesn't point to anything + 19 No Config - Doesn't point to anything + 20 No Config - Doesn't point to anything + 21 No Config - Doesn't point to anything + 22 No Config - Doesn't point to anything + 23 No Config - Doesn't point to anything + ----------------------------------------------------------- +*/ + +u32 shadow_sr_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr) +{ + u32 addr = 0; + + switch (COPY_ENGINE_ID(ctrl_addr)) { + case 0: + addr = SHADOW_VALUE0; + break; + case 3: + addr = SHADOW_VALUE3; + break; + case 4: + addr = SHADOW_VALUE4; + break; + case 5: + addr = SHADOW_VALUE5; + break; + case 7: + addr = SHADOW_VALUE7; + break; + default: + printk("invalid CE ctrl_addr\n"); + CDF_ASSERT(0); + + } + return addr; + +} + +u32 shadow_dst_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr) +{ + u32 addr = 0; + + switch (COPY_ENGINE_ID(ctrl_addr)) { + case 1: + addr = SHADOW_VALUE13; + break; + case 2: + addr = SHADOW_VALUE14; + break; + case 7: + addr = SHADOW_VALUE19; + break; + case 8: + addr = SHADOW_VALUE20; + break; + default: + printk("invalid CE ctrl_addr\n"); + CDF_ASSERT(0); + } + + return addr; + +} +#endif + +void ce_lro_flush_cb_register(struct ol_softc *scn, + void (handler)(void *), void *data) +{ + struct CE_state *ce_state = scn->ce_id_to_state[CE_HTT_T2H_MSG]; + ce_state->lro_flush_cb = handler; + ce_state->lro_data = data; +} diff --git a/core/hif/src/ce/ce_main.h b/core/hif/src/ce/ce_main.h new file mode 100644 index 0000000000..570fd41fd7 --- /dev/null +++ b/core/hif/src/ce/ce_main.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_H__ +#define __CE_H__ + +#include "cdf_atomic.h" +#include "cdf_lock.h" +#include "hif.h" + +#define CE_HTT_T2H_MSG 1 +#define CE_HTT_H2T_MSG 4 + +/** + * enum ce_id_type + * + * @ce_id_type: Copy engine ID + */ +enum ce_id_type { + CE_ID_0, + CE_ID_1, + CE_ID_2, + CE_ID_3, + CE_ID_4, + CE_ID_5, + CE_ID_6, + CE_ID_7, + CE_ID_8, + CE_ID_9, + CE_ID_10, + CE_ID_11, + CE_ID_MAX +}; +struct HIF_CE_completion_state { + struct HIF_CE_completion_state *next; + int send_or_recv; + struct CE_handle *copyeng; + void *ce_context; + void *transfer_context; + cdf_dma_addr_t data; + unsigned int nbytes; + unsigned int transfer_id; + unsigned int flags; + uint32_t toeplitz_hash_result; +}; + +/* compl_state.send_or_recv */ +#define HIF_CE_COMPLETE_FREE 0 +#define HIF_CE_COMPLETE_SEND 1 +#define HIF_CE_COMPLETE_RECV 2 + +enum ol_ath_hif_pkt_ecodes { + HIF_PIPE_NO_RESOURCE = 0 +}; + +struct HIF_CE_state; +#define HIF_CE_COMPLETE_STATE_NUM 18 /* 56 * 18 + 4/8 = 1012/1016 bytes */ +struct HIF_CE_completion_state_list { + struct HIF_CE_completion_state_list *next; +}; + +/* Per-pipe state. */ +struct HIF_CE_pipe_info { + /* Handle of underlying Copy Engine */ + struct CE_handle *ce_hdl; + + /* Our pipe number; facilitiates use of pipe_info ptrs. */ + uint8_t pipe_num; + + /* Convenience back pointer to HIF_CE_state. */ + struct HIF_CE_state *HIF_CE_state; + + /* Instantaneous number of receive buffers that should be posted */ + atomic_t recv_bufs_needed; + cdf_size_t buf_sz; + cdf_spinlock_t recv_bufs_needed_lock; + + cdf_spinlock_t completion_freeq_lock; + /* Limit the number of outstanding send requests. */ + int num_sends_allowed; + struct HIF_CE_completion_state_list *completion_space_list; + struct HIF_CE_completion_state *completion_freeq_head; + struct HIF_CE_completion_state *completion_freeq_tail; + /* adding three counts for debugging ring buffer errors */ + uint32_t nbuf_alloc_err_count; + uint32_t nbuf_dma_err_count; + uint32_t nbuf_ce_enqueue_err_count; +}; + +/** + * struct ce_tasklet_entry + * + * @intr_tq: intr_tq + * @ce_id: ce_id + * @inited: inited + * @hif_ce_state: hif_ce_state + * @from_irq: from_irq + */ +struct ce_tasklet_entry { + struct tasklet_struct intr_tq; + enum ce_id_type ce_id; + bool inited; + void *hif_ce_state; + bool from_irq; +}; + +struct HIF_CE_state { + struct ol_softc *scn; + bool started; + struct ce_tasklet_entry tasklets[CE_COUNT_MAX]; + cdf_spinlock_t keep_awake_lock; + unsigned int keep_awake_count; + bool verified_awake; + bool fake_sleep; + cdf_softirq_timer_t sleep_timer; + bool sleep_timer_init; + unsigned long sleep_ticks; + cdf_spinlock_t completion_pendingq_lock; + /* Queue of send/recv completions that need to be processed */ + struct HIF_CE_completion_state *completion_pendingq_head; + struct HIF_CE_completion_state *completion_pendingq_tail; + atomic_t fw_event_pending; + cdf_atomic_t hif_thread_idle; + + /* wait_queue_head_t service_waitq; */ + /* struct task_struct *compl_thread; */ + /* struct completion compl_thread_done; */ + + /* Per-pipe state. */ + struct HIF_CE_pipe_info pipe_info[CE_COUNT_MAX]; + /* to be activated after BMI_DONE */ + struct hif_msg_callbacks msg_callbacks_pending; + /* current msg callbacks in use */ + struct hif_msg_callbacks msg_callbacks_current; + + void *claimedContext; + + /* Target address used to signal a pending firmware event */ + uint32_t fw_indicator_address; + + /* Copy Engine used for Diagnostic Accesses */ + struct CE_handle *ce_diag; +}; +#endif /* __CE_H__ */ diff --git a/core/hif/src/ce/ce_reg.h b/core/hif/src/ce/ce_reg.h new file mode 100644 index 0000000000..cb7439421d --- /dev/null +++ b/core/hif/src/ce/ce_reg.h @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_REG_H__ +#define __CE_REG_H__ + +#define DST_WR_INDEX_ADDRESS (scn->target_ce_def->d_DST_WR_INDEX_ADDRESS) +#define SRC_WATERMARK_ADDRESS (scn->target_ce_def->d_SRC_WATERMARK_ADDRESS) +#define SRC_WATERMARK_LOW_MASK (scn->target_ce_def->d_SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_MASK (scn->target_ce_def->d_SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_MASK (scn->target_ce_def->d_DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_MASK (scn->target_ce_def->d_DST_WATERMARK_HIGH_MASK) +#define CURRENT_SRRI_ADDRESS (scn->target_ce_def->d_CURRENT_SRRI_ADDRESS) +#define CURRENT_DRRI_ADDRESS (scn->target_ce_def->d_CURRENT_DRRI_ADDRESS) + +#define SHADOW_VALUE0 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_0) +#define SHADOW_VALUE1 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_1) +#define SHADOW_VALUE2 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_2) +#define SHADOW_VALUE3 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_3) +#define SHADOW_VALUE4 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_4) +#define SHADOW_VALUE5 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_5) +#define SHADOW_VALUE6 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_6) +#define SHADOW_VALUE7 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_7) +#define SHADOW_VALUE8 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_8) +#define SHADOW_VALUE9 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_9) +#define SHADOW_VALUE10 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_10) +#define SHADOW_VALUE11 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_11) +#define SHADOW_VALUE12 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_12) +#define SHADOW_VALUE13 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_13) +#define SHADOW_VALUE14 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_14) +#define SHADOW_VALUE15 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_15) +#define SHADOW_VALUE16 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_16) +#define SHADOW_VALUE17 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_17) +#define SHADOW_VALUE18 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_18) +#define SHADOW_VALUE19 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_19) +#define SHADOW_VALUE20 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_20) +#define SHADOW_VALUE21 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_21) +#define SHADOW_VALUE22 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_22) +#define SHADOW_VALUE23 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_23) +#define SHADOW_ADDRESS0 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_0) +#define SHADOW_ADDRESS1 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_1) +#define SHADOW_ADDRESS2 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_2) +#define SHADOW_ADDRESS3 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_3) +#define SHADOW_ADDRESS4 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_4) +#define SHADOW_ADDRESS5 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_5) +#define SHADOW_ADDRESS6 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_6) +#define SHADOW_ADDRESS7 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_7) +#define SHADOW_ADDRESS8 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_8) +#define SHADOW_ADDRESS9 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_9) +#define SHADOW_ADDRESS10 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_10) +#define SHADOW_ADDRESS11 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_11) +#define SHADOW_ADDRESS12 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_12) +#define SHADOW_ADDRESS13 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_13) +#define SHADOW_ADDRESS14 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_14) +#define SHADOW_ADDRESS15 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_15) +#define SHADOW_ADDRESS16 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_16) +#define SHADOW_ADDRESS17 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_17) +#define SHADOW_ADDRESS18 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_18) +#define SHADOW_ADDRESS19 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_19) +#define SHADOW_ADDRESS20 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_20) +#define SHADOW_ADDRESS21 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_21) +#define SHADOW_ADDRESS22 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_22) +#define SHADOW_ADDRESS23 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_23) + +#define SHADOW_ADDRESS(i) (SHADOW_ADDRESS0 + i*(SHADOW_ADDRESS1-SHADOW_ADDRESS0)) + +#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK) +#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_DST_RING_LOW_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_DST_RING_LOW_WATERMARK_MASK) +#define MISC_IS_ADDRESS (scn->target_ce_def->d_MISC_IS_ADDRESS) +#define HOST_IS_COPY_COMPLETE_MASK \ + (scn->target_ce_def->d_HOST_IS_COPY_COMPLETE_MASK) +#define CE_WRAPPER_BASE_ADDRESS (scn->target_ce_def->d_CE_WRAPPER_BASE_ADDRESS) +#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS) +#define CE_WRAPPER_INDEX_BASE_LOW \ + (scn->target_ce_def->d_CE_WRAPPER_INDEX_BASE_LOW) +#define CE_WRAPPER_INDEX_BASE_HIGH \ + (scn->target_ce_def->d_CE_WRAPPER_INDEX_BASE_HIGH) +#define HOST_IE_COPY_COMPLETE_MASK \ + (scn->target_ce_def->d_HOST_IE_COPY_COMPLETE_MASK) +#define SR_BA_ADDRESS (scn->target_ce_def->d_SR_BA_ADDRESS) +#define SR_BA_ADDRESS_HIGH (scn->target_ce_def->d_SR_BA_ADDRESS_HIGH) +#define SR_SIZE_ADDRESS (scn->target_ce_def->d_SR_SIZE_ADDRESS) +#define CE_CTRL1_ADDRESS (scn->target_ce_def->d_CE_CTRL1_ADDRESS) +#define CE_CTRL1_DMAX_LENGTH_MASK \ + (scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_MASK) +#define DR_BA_ADDRESS (scn->target_ce_def->d_DR_BA_ADDRESS) +#define DR_BA_ADDRESS_HIGH (scn->target_ce_def->d_DR_BA_ADDRESS_HIGH) +#define DR_SIZE_ADDRESS (scn->target_ce_def->d_DR_SIZE_ADDRESS) +#define CE_CMD_REGISTER (scn->target_ce_def->d_CE_CMD_REGISTER) +#define CE_MSI_ADDRESS (scn->target_ce_def->d_CE_MSI_ADDRESS) +#define CE_MSI_ADDRESS_HIGH (scn->target_ce_def->d_CE_MSI_ADDRESS_HIGH) +#define CE_MSI_DATA (scn->target_ce_def->d_CE_MSI_DATA) +#define CE_MSI_ENABLE_BIT (scn->target_ce_def->d_CE_MSI_ENABLE_BIT) +#define MISC_IE_ADDRESS (scn->target_ce_def->d_MISC_IE_ADDRESS) +#define MISC_IS_AXI_ERR_MASK (scn->target_ce_def->d_MISC_IS_AXI_ERR_MASK) +#define MISC_IS_DST_ADDR_ERR_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_ADDR_ERR_MASK) +#define MISC_IS_SRC_LEN_ERR_MASK \ + (scn->target_ce_def->d_MISC_IS_SRC_LEN_ERR_MASK) +#define MISC_IS_DST_MAX_LEN_VIO_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_MAX_LEN_VIO_MASK) +#define MISC_IS_DST_RING_OVERFLOW_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_RING_OVERFLOW_MASK) +#define MISC_IS_SRC_RING_OVERFLOW_MASK \ + (scn->target_ce_def->d_MISC_IS_SRC_RING_OVERFLOW_MASK) +#define SRC_WATERMARK_LOW_LSB (scn->target_ce_def->d_SRC_WATERMARK_LOW_LSB) +#define SRC_WATERMARK_HIGH_LSB (scn->target_ce_def->d_SRC_WATERMARK_HIGH_LSB) +#define DST_WATERMARK_LOW_LSB (scn->target_ce_def->d_DST_WATERMARK_LOW_LSB) +#define DST_WATERMARK_HIGH_LSB (scn->target_ce_def->d_DST_WATERMARK_HIGH_LSB) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_LSB (scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_LSB) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK \ + (scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK \ + (scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \ + (scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \ + (scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) +#define WLAN_DEBUG_INPUT_SEL_OFFSET \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_OFFSET) +#define WLAN_DEBUG_INPUT_SEL_SRC_MSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_LSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_MASK \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_OFFSET (scn->targetdef->d_WLAN_DEBUG_CONTROL_OFFSET) +#define WLAN_DEBUG_CONTROL_ENABLE_MSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MSB) +#define WLAN_DEBUG_CONTROL_ENABLE_LSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_MASK \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_OFFSET (scn->targetdef->d_WLAN_DEBUG_OUT_OFFSET) +#define WLAN_DEBUG_OUT_DATA_MSB (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MSB) +#define WLAN_DEBUG_OUT_DATA_LSB (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_MASK (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_OFFSET (scn->targetdef->d_AMBA_DEBUG_BUS_OFFSET) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_MSB (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MSB) +#define AMBA_DEBUG_BUS_SEL_LSB (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_MASK (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_OFFSET (scn->target_ce_def->d_CE_WRAPPER_DEBUG_OFFSET) +#define CE_WRAPPER_DEBUG_SEL_MSB (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MSB) +#define CE_WRAPPER_DEBUG_SEL_LSB (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_MASK (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_OFFSET (scn->target_ce_def->d_CE_DEBUG_OFFSET) +#define CE_DEBUG_SEL_MSB (scn->target_ce_def->d_CE_DEBUG_SEL_MSB) +#define CE_DEBUG_SEL_LSB (scn->target_ce_def->d_CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_MASK (scn->target_ce_def->d_CE_DEBUG_SEL_MASK) +#define HOST_IE_ADDRESS (scn->target_ce_def->d_HOST_IE_ADDRESS) +#define HOST_IS_ADDRESS (scn->target_ce_def->d_HOST_IS_ADDRESS) + +#define SRC_WATERMARK_LOW_SET(x) \ + (((x) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_SET(x) \ + (((x) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_SET(x) \ + (((x) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_SET(x) \ + (((x) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \ + (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_SET(x) \ + (((x) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define WLAN_DEBUG_INPUT_SEL_SRC_GET(x) \ + (((x) & WLAN_DEBUG_INPUT_SEL_SRC_MASK) >> \ + WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_SET(x) \ + (((x) << WLAN_DEBUG_INPUT_SEL_SRC_LSB) & \ + WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_ENABLE_GET(x) \ + (((x) & WLAN_DEBUG_CONTROL_ENABLE_MASK) >> \ + WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_SET(x) \ + (((x) << WLAN_DEBUG_CONTROL_ENABLE_LSB) & \ + WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_DATA_GET(x) \ + (((x) & WLAN_DEBUG_OUT_DATA_MASK) >> WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_SET(x) \ + (((x) << WLAN_DEBUG_OUT_DATA_LSB) & WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_GET(x) \ + (((x) & AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) >> \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) & \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_GET(x) \ + (((x) & AMBA_DEBUG_BUS_SEL_MASK) >> AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_SEL_LSB) & AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_SEL_GET(x) \ + (((x) & CE_WRAPPER_DEBUG_SEL_MASK) >> CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_SET(x) \ + (((x) << CE_WRAPPER_DEBUG_SEL_LSB) & CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_SEL_GET(x) (((x) & CE_DEBUG_SEL_MASK) >> CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_SET(x) (((x) << CE_DEBUG_SEL_LSB) & CE_DEBUG_SEL_MASK) + +#define CE_SRC_RING_READ_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS) + +#define CE_SRC_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS, (addr)) + +#define CE_SRC_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH, (addr)) + +#define CE_SRC_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH) + +#define CE_SRC_RING_SZ_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_SIZE_ADDRESS, (n)) + +#define CE_SRC_RING_DMAX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \ + (A_TARGET_READ(scn, (CE_ctrl_addr) + \ + CE_CTRL1_ADDRESS) & ~CE_CTRL1_DMAX_LENGTH_MASK) | \ + CE_CTRL1_DMAX_LENGTH_SET(n)) + +#define CE_CMD_REGISTER_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CMD_REGISTER) + +#define CE_CMD_REGISTER_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CMD_REGISTER, n) + +#define CE_MSI_ADDR_LOW_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS, (addr)) + +#define CE_MSI_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS_HIGH, (addr)) + +#define CE_MSI_DATA_SET(scn, CE_ctrl_addr, data) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_DATA, (data)) + +#define CE_CTRL_REGISTER1_SET(scn, CE_ctrl_addr, val) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, val) + +#define CE_CTRL_REGISTER1_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS) + +#define CE_SRC_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \ + (A_TARGET_READ((targid), \ + (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \ + & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)) + +#define CE_DEST_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr)+CE_CTRL1_ADDRESS, \ + (A_TARGET_READ((targid), \ + (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \ + & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)) + +#define CE_DEST_RING_READ_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS) + +#define CE_DEST_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS, (addr)) + +#define CE_DEST_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH, (addr)) + +#define CE_DEST_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH) + +#define CE_DEST_RING_SZ_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_SIZE_ADDRESS, (n)) + +#define CE_SRC_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \ + & ~SRC_WATERMARK_HIGH_MASK) | \ + SRC_WATERMARK_HIGH_SET(n)) + +#define CE_SRC_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \ + & ~SRC_WATERMARK_LOW_MASK) | \ + SRC_WATERMARK_LOW_SET(n)) + +#define CE_DEST_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \ + & ~DST_WATERMARK_HIGH_MASK) | \ + DST_WATERMARK_HIGH_SET(n)) + +#define CE_DEST_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \ + & ~DST_WATERMARK_LOW_MASK) | \ + DST_WATERMARK_LOW_SET(n)) + +#define CE_COPY_COMPLETE_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) | \ + HOST_IE_COPY_COMPLETE_MASK) + +#define CE_COPY_COMPLETE_INTR_DISABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) \ + & ~HOST_IE_COPY_COMPLETE_MASK) + +#define CE_BASE_ADDRESS(CE_id) \ + CE0_BASE_ADDRESS + ((CE1_BASE_ADDRESS - \ + CE0_BASE_ADDRESS)*(CE_id)) + +#define CE_WATERMARK_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) | \ + CE_WATERMARK_MASK) + +#define CE_WATERMARK_INTR_DISABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) \ + & ~CE_WATERMARK_MASK) + +#define CE_ERROR_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + MISC_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + MISC_IE_ADDRESS) | CE_ERROR_MASK) + +#define CE_MISC_INT_STATUS_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + MISC_IS_ADDRESS) + +#define CE_ENGINE_INT_STATUS_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS) + +#define CE_ENGINE_INT_STATUS_CLEAR(scn, CE_ctrl_addr, mask) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS, (mask)) + +#define CE_WRAPPER_INDEX_BASE_LOW_SET(scn, n) \ + A_TARGET_WRITE(scn, \ + CE_WRAPPER_INDEX_BASE_LOW + CE_WRAPPER_BASE_ADDRESS, n) + +#define CE_WRAPPER_INDEX_BASE_HIGH_SET(scn, n) \ + A_TARGET_WRITE(scn, \ + CE_WRAPPER_INDEX_BASE_HIGH + CE_WRAPPER_BASE_ADDRESS, n) + +#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \ + HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \ + HOST_IS_DST_RING_LOW_WATERMARK_MASK | \ + HOST_IS_DST_RING_HIGH_WATERMARK_MASK) + +#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \ + MISC_IS_DST_ADDR_ERR_MASK | \ + MISC_IS_SRC_LEN_ERR_MASK | \ + MISC_IS_DST_MAX_LEN_VIO_MASK | \ + MISC_IS_DST_RING_OVERFLOW_MASK | \ + MISC_IS_SRC_RING_OVERFLOW_MASK) + +#define CE_SRC_RING_TO_DESC(baddr, idx) \ + (&(((struct CE_src_desc *)baddr)[idx])) +#define CE_DEST_RING_TO_DESC(baddr, idx) \ + (&(((struct CE_dest_desc *)baddr)[idx])) + +/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */ +#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \ + (((int)(toidx)-(int)(fromidx)) & (nentries_mask)) + +#define CE_RING_IDX_INCR(nentries_mask, idx) \ + (((idx) + 1) & (nentries_mask)) + +#define CE_RING_IDX_ADD(nentries_mask, idx, num) \ + (((idx) + (num)) & (nentries_mask)) + +#define CE_INTERRUPT_SUMMARY(scn) \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \ + A_TARGET_READ(scn, CE_WRAPPER_BASE_ADDRESS + \ + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)) + +/*Macro to increment CE packet errors*/ +#define OL_ATH_CE_PKT_ERROR_COUNT_INCR(_scn, _ce_ecode) \ + do { if (_ce_ecode == CE_RING_DELTA_FAIL) \ + (_scn->pkt_stats.ce_ring_delta_fail_count) \ + += 1; } while (0) + +/* Given a Copy Engine's ID, determine the interrupt number for that + * copy engine's interrupts. + */ +#define CE_ID_TO_INUM(id) (A_INUM_CE0_COPY_COMP_BASE + (id)) +#define CE_INUM_TO_ID(inum) ((inum) - A_INUM_CE0_COPY_COMP_BASE) +#define CE0_BASE_ADDRESS (scn->target_ce_def->d_CE0_BASE_ADDRESS) +#define CE1_BASE_ADDRESS (scn->target_ce_def->d_CE1_BASE_ADDRESS) + +#ifdef ADRASTEA_SHADOW_REGISTERS + +#define NUM_SHADOW_REGISTERS 24 + +#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) ((COPY_ENGINE_BASE_ADDRESS \ + - CE0_BASE_ADDRESS)/(CE1_BASE_ADDRESS - CE0_BASE_ADDRESS)) + +u32 shadow_sr_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr); +u32 shadow_dst_wr_ind_addr(struct ol_softc *scn, u32 ctrl_addr); +#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, shadow_sr_wr_ind_addr(scn, CE_ctrl_addr), n) + +#define CE_SRC_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, shadow_sr_wr_ind_addr(scn, CE_ctrl_addr)) + +#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, shadow_dst_wr_ind_addr(scn, CE_ctrl_addr), n) + +#define CE_DEST_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, shadow_dst_wr_ind_addr(scn, CE_ctrl_addr)) + +#else + +#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS, (n)) + +#define CE_SRC_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS) + +#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS, (n)) + +#define CE_DEST_RING_WRITE_IDX_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS) + +#endif + +#endif /* __CE_REG_H__ */ diff --git a/core/hif/src/ce/ce_service.c b/core/hif/src/ce/ce_service.c new file mode 100644 index 0000000000..d27ca6b1a8 --- /dev/null +++ b/core/hif/src/ce/ce_service.c @@ -0,0 +1,1678 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "a_types.h" +#include +#include "osapi_linux.h" +#include "hif.h" +#include "hif_io32.h" +#include "ce_api.h" +#include "ce_main.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "cdf_lock.h" +#include "regtable.h" +#include +#include "epping_main.h" +#include "hif_main.h" +#include "hif_debug.h" + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 +#define CE_IPA_RING_INIT(ce_desc) \ + do { \ + ce_desc->gather = 0; \ + ce_desc->enable_11h = 0; \ + ce_desc->meta_data_low = 0; \ + ce_desc->packet_result_offset = 64; \ + ce_desc->toeplitz_hash_enable = 0; \ + ce_desc->addr_y_search_disable = 0; \ + ce_desc->addr_x_search_disable = 0; \ + ce_desc->misc_int_disable = 0; \ + ce_desc->target_int_disable = 0; \ + ce_desc->host_int_disable = 0; \ + ce_desc->dest_byte_swap = 0; \ + ce_desc->byte_swap = 0; \ + ce_desc->type = 2; \ + ce_desc->tx_classify = 1; \ + ce_desc->buffer_addr_hi = 0; \ + ce_desc->meta_data = 0; \ + ce_desc->nbytes = 128; \ + } while (0) +#else +#define CE_IPA_RING_INIT(ce_desc) \ + do { \ + ce_desc->byte_swap = 0; \ + ce_desc->nbytes = 60; \ + ce_desc->gather = 0; \ + } while (0) +#endif /* QCA_WIFI_3_0 */ +#endif /* IPA_OFFLOAD */ + +static int war1_allow_sleep; +/* io32 write workaround */ +static int hif_ce_war1; + +/* + * Support for Copy Engine hardware, which is mainly used for + * communication between Host and Target over a PCIe interconnect. + */ + +/* + * A single CopyEngine (CE) comprises two "rings": + * a source ring + * a destination ring + * + * Each ring consists of a number of descriptors which specify + * an address, length, and meta-data. + * + * Typically, one side of the PCIe interconnect (Host or Target) + * controls one ring and the other side controls the other ring. + * The source side chooses when to initiate a transfer and it + * chooses what to send (buffer address, length). The destination + * side keeps a supply of "anonymous receive buffers" available and + * it handles incoming data as it arrives (when the destination + * recieves an interrupt). + * + * The sender may send a simple buffer (address/length) or it may + * send a small list of buffers. When a small list is sent, hardware + * "gathers" these and they end up in a single destination buffer + * with a single interrupt. + * + * There are several "contexts" managed by this layer -- more, it + * may seem -- than should be needed. These are provided mainly for + * maximum flexibility and especially to facilitate a simpler HIF + * implementation. There are per-CopyEngine recv, send, and watermark + * contexts. These are supplied by the caller when a recv, send, + * or watermark handler is established and they are echoed back to + * the caller when the respective callbacks are invoked. There is + * also a per-transfer context supplied by the caller when a buffer + * (or sendlist) is sent and when a buffer is enqueued for recv. + * These per-transfer contexts are echoed back to the caller when + * the buffer is sent/received. + * Target TX harsh result toeplitz_hash_result + */ + +/* + * Guts of ce_send, used by both ce_send and ce_sendlist_send. + * The caller takes responsibility for any needed locking. + */ +int +ce_completed_send_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, unsigned int *hw_idx, + uint32_t *toeplitz_hash_result); + +void war_ce_src_ring_write_idx_set(struct ol_softc *scn, + u32 ctrl_addr, unsigned int write_index) +{ + if (hif_ce_war1) { + void __iomem *indicator_addr; + + indicator_addr = scn->mem + ctrl_addr + DST_WATERMARK_ADDRESS; + + if (!war1_allow_sleep + && ctrl_addr == CE_BASE_ADDRESS(CDC_WAR_DATA_CE)) { + hif_write32_mb(indicator_addr, + (CDC_WAR_MAGIC_STR | write_index)); + } else { + unsigned long irq_flags; + local_irq_save(irq_flags); + hif_write32_mb(indicator_addr, 1); + + /* + * PCIE write waits for ACK in IPQ8K, there is no + * need to read back value. + */ + (void)hif_read32_mb(indicator_addr); + (void)hif_read32_mb(indicator_addr); /* conservative */ + + CE_SRC_RING_WRITE_IDX_SET(scn, + ctrl_addr, write_index); + + hif_write32_mb(indicator_addr, 0); + local_irq_restore(irq_flags); + } + } else + CE_SRC_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index); +} + +int +ce_send_nolock(struct CE_handle *copyeng, + void *per_transfer_context, + cdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t transfer_id, + uint32_t flags, + uint32_t user_flags) +{ + int status; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index = src_ring->sw_index; + unsigned int write_index = src_ring->write_index; + uint64_t dma_addr = buffer; + struct ol_softc *scn = CE_state->scn; + + A_TARGET_ACCESS_BEGIN_RET(scn); + if (unlikely(CE_RING_DELTA(nentries_mask, + write_index, sw_index - 1) <= 0)) { + OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL); + status = CDF_STATUS_E_FAILURE; + A_TARGET_ACCESS_END_RET(scn); + return status; + } + { + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, write_index); + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, write_index); + + /* Update low 32 bits source descriptor address */ + shadow_src_desc->buffer_addr = + (uint32_t)(dma_addr & 0xFFFFFFFF); +#ifdef QCA_WIFI_3_0 + shadow_src_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); + user_flags |= shadow_src_desc->buffer_addr_hi; + memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags, + sizeof(uint32_t)); +#endif + shadow_src_desc->meta_data = transfer_id; + + /* + * Set the swap bit if: + * typical sends on this CE are swapped (host is big-endian) + * and this send doesn't disable the swapping + * (data is not bytestream) + */ + shadow_src_desc->byte_swap = + (((CE_state->attr_flags & CE_ATTR_BYTE_SWAP_DATA) + != 0) & ((flags & CE_SEND_FLAG_SWAP_DISABLE) == 0)); + shadow_src_desc->gather = ((flags & CE_SEND_FLAG_GATHER) != 0); + shadow_src_desc->nbytes = nbytes; + + *src_desc = *shadow_src_desc; + + src_ring->per_transfer_context[write_index] = + per_transfer_context; + + /* Update Source Ring Write Index */ + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + /* WORKAROUND */ + if (!shadow_src_desc->gather) { + war_ce_src_ring_write_idx_set(scn, ctrl_addr, + write_index); + } + + src_ring->write_index = write_index; + status = CDF_STATUS_SUCCESS; + } + A_TARGET_ACCESS_END_RET(scn); + + return status; +} + +int +ce_send(struct CE_handle *copyeng, + void *per_transfer_context, + cdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t transfer_id, + uint32_t flags, + uint32_t user_flag) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + cdf_spin_lock_bh(&CE_state->scn->target_lock); + status = ce_send_nolock(copyeng, per_transfer_context, buffer, nbytes, + transfer_id, flags, user_flag); + cdf_spin_unlock_bh(&CE_state->scn->target_lock); + + return status; +} + +unsigned int ce_sendlist_sizeof(void) +{ + return sizeof(struct ce_sendlist); +} + +void ce_sendlist_init(struct ce_sendlist *sendlist) +{ + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + sl->num_items = 0; +} + +int +ce_sendlist_buf_add(struct ce_sendlist *sendlist, + cdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t flags, + uint32_t user_flags) +{ + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + unsigned int num_items = sl->num_items; + struct ce_sendlist_item *item; + + if (num_items >= CE_SENDLIST_ITEMS_MAX) { + CDF_ASSERT(num_items < CE_SENDLIST_ITEMS_MAX); + return CDF_STATUS_E_RESOURCES; + } + + item = &sl->item[num_items]; + item->send_type = CE_SIMPLE_BUFFER_TYPE; + item->data = buffer; + item->u.nbytes = nbytes; + item->flags = flags; + item->user_flags = user_flags; + sl->num_items = num_items + 1; + return CDF_STATUS_SUCCESS; +} + +int +ce_sendlist_send(struct CE_handle *copyeng, + void *per_transfer_context, + struct ce_sendlist *sendlist, unsigned int transfer_id) +{ + int status = -ENOMEM; + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int num_items = sl->num_items; + unsigned int sw_index; + unsigned int write_index; + + CDF_ASSERT((num_items > 0) && (num_items < src_ring->nentries)); + + cdf_spin_lock_bh(&CE_state->scn->target_lock); + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) >= + num_items) { + struct ce_sendlist_item *item; + int i; + + /* handle all but the last item uniformly */ + for (i = 0; i < num_items - 1; i++) { + item = &sl->item[i]; + /* TBDXXX: Support extensible sendlist_types? */ + CDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE); + status = ce_send_nolock(copyeng, CE_SENDLIST_ITEM_CTXT, + (cdf_dma_addr_t) item->data, + item->u.nbytes, transfer_id, + item->flags | CE_SEND_FLAG_GATHER, + item->user_flags); + CDF_ASSERT(status == CDF_STATUS_SUCCESS); + } + /* provide valid context pointer for final item */ + item = &sl->item[i]; + /* TBDXXX: Support extensible sendlist_types? */ + CDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE); + status = ce_send_nolock(copyeng, per_transfer_context, + (cdf_dma_addr_t) item->data, + item->u.nbytes, + transfer_id, item->flags, + item->user_flags); + CDF_ASSERT(status == CDF_STATUS_SUCCESS); + NBUF_UPDATE_TX_PKT_COUNT((cdf_nbuf_t)per_transfer_context, + NBUF_TX_PKT_CE); + DPTRACE(cdf_dp_trace((cdf_nbuf_t)per_transfer_context, + CDF_DP_TRACE_CE_PACKET_PTR_RECORD, + (uint8_t *)(((cdf_nbuf_t)per_transfer_context)->data), + sizeof(((cdf_nbuf_t)per_transfer_context)->data))); + } else { + /* + * Probably not worth the additional complexity to support + * partial sends with continuation or notification. We expect + * to use large rings and small sendlists. If we can't handle + * the entire request at once, punt it back to the caller. + */ + } + cdf_spin_unlock_bh(&CE_state->scn->target_lock); + + return status; +} + +#ifdef WLAN_FEATURE_FASTPATH +#ifdef QCA_WIFI_3_0 +static inline void +ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc, + uint64_t dma_addr, + uint32_t user_flags) +{ + shadow_src_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); + user_flags |= shadow_src_desc->buffer_addr_hi; + memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags, + sizeof(uint32_t)); +} +#else +static inline void +ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc, + uint64_t dma_addr, + uint32_t user_flags) +{ +} +#endif + +/** + * ce_send_fast() CE layer Tx buffer posting function + * @copyeng: copy engine handle + * @msdus: iarray of msdu to be sent + * @num_msdus: number of msdus in an array + * @transfer_id: transfer_id + * + * Assumption : Called with an array of MSDU's + * Function: + * For each msdu in the array + * 1. Check no. of available entries + * 2. Create src ring entries (allocated in consistent memory + * 3. Write index to h/w + * + * Return: No. of packets that could be sent + */ + +int ce_send_fast(struct CE_handle *copyeng, cdf_nbuf_t *msdus, + unsigned int num_msdus, unsigned int transfer_id) +{ + struct CE_state *ce_state = (struct CE_state *)copyeng; + struct ol_softc *scn = ce_state->scn; + struct CE_ring_state *src_ring = ce_state->src_ring; + u_int32_t ctrl_addr = ce_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int write_index; + unsigned int sw_index; + unsigned int frag_len; + cdf_nbuf_t msdu; + int i; + uint64_t dma_addr; + uint32_t user_flags = 0; + + /* + * This lock could be more fine-grained, one per CE, + * TODO : Add this lock now. + * That is the next step of optimization. + */ + cdf_spin_lock_bh(&scn->target_lock); + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + /* 2 msdus per packet */ + for (i = 0; i < num_msdus; i++) { + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, write_index); + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, write_index); + + msdu = msdus[i]; + + /* + * First fill out the ring descriptor for the HTC HTT frame + * header. These are uncached writes. Should we use a local + * structure instead? + */ + /* HTT/HTC header can be passed as a argument */ + dma_addr = cdf_nbuf_get_frag_paddr_lo(msdu, 0); + shadow_src_desc->buffer_addr = (uint32_t)(dma_addr & + 0xFFFFFFFF); + user_flags = cdf_nbuf_data_attr_get(msdu) & DESC_DATA_FLAG_MASK; + ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags); + + shadow_src_desc->meta_data = transfer_id; + shadow_src_desc->nbytes = cdf_nbuf_get_frag_len(msdu, 0); + + /* + * HTC HTT header is a word stream, so byte swap if CE byte + * swap enabled + */ + shadow_src_desc->byte_swap = ((ce_state->attr_flags & + CE_ATTR_BYTE_SWAP_DATA) != 0); + /* For the first one, it still does not need to write */ + shadow_src_desc->gather = 1; + *src_desc = *shadow_src_desc; + + /* By default we could initialize the transfer context to this + * value + */ + src_ring->per_transfer_context[write_index] = + CE_SENDLIST_ITEM_CTXT; + + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + src_desc = CE_SRC_RING_TO_DESC(src_ring_base, write_index); + shadow_src_desc = CE_SRC_RING_TO_DESC(shadow_base, write_index); + /* + * Now fill out the ring descriptor for the actual data + * packet + */ + dma_addr = cdf_nbuf_get_frag_paddr_lo(msdu, 1); + shadow_src_desc->buffer_addr = (uint32_t)(dma_addr & + 0xFFFFFFFF); + /* + * Clear packet offset for all but the first CE desc. + */ + user_flags &= ~CDF_CE_TX_PKT_OFFSET_BIT_M; + ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags); + shadow_src_desc->meta_data = transfer_id; + + /* get actual packet length */ + frag_len = cdf_nbuf_get_frag_len(msdu, 1); + shadow_src_desc->nbytes = frag_len > ce_state->download_len ? + ce_state->download_len : frag_len; + + /* Data packet is a byte stream, so disable byte swap */ + shadow_src_desc->byte_swap = 0; + /* For the last one, gather is not set */ + shadow_src_desc->gather = 0; + *src_desc = *shadow_src_desc; + src_ring->per_transfer_context[write_index] = msdu; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + } + + /* Write the final index to h/w one-shot */ + if (i) { + src_ring->write_index = write_index; + /* Don't call WAR_XXX from here + * Just call XXX instead, that has the reqd. intel + */ + war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index); + } + + cdf_spin_unlock_bh(&scn->target_lock); + + /* + * If all packets in the array are transmitted, + * i = num_msdus + * Temporarily add an ASSERT + */ + ASSERT(i == num_msdus); + return i; +} +#endif /* WLAN_FEATURE_FASTPATH */ + +int +ce_recv_buf_enqueue(struct CE_handle *copyeng, + void *per_recv_context, cdf_dma_addr_t buffer) +{ + int status; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int write_index; + unsigned int sw_index; + int val = 0; + uint64_t dma_addr = buffer; + struct ol_softc *scn = CE_state->scn; + + cdf_spin_lock_bh(&scn->target_lock); + write_index = dest_ring->write_index; + sw_index = dest_ring->sw_index; + + A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val); + if (val == -1) { + cdf_spin_unlock_bh(&scn->target_lock); + return val; + } + + if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) { + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring-> + base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, write_index); + + /* Update low 32 bit destination descriptor */ + dest_desc->buffer_addr = (uint32_t)(dma_addr & 0xFFFFFFFF); +#ifdef QCA_WIFI_3_0 + dest_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); +#endif + dest_desc->nbytes = 0; + + dest_ring->per_transfer_context[write_index] = + per_recv_context; + + /* Update Destination Ring Write Index */ + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + CE_DEST_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index); + dest_ring->write_index = write_index; + status = CDF_STATUS_SUCCESS; + } else { + status = CDF_STATUS_E_FAILURE; + } + A_TARGET_ACCESS_END_RET_EXT(scn, val); + if (val == -1) { + cdf_spin_unlock_bh(&scn->target_lock); + return val; + } + + cdf_spin_unlock_bh(&scn->target_lock); + + return status; +} + +void +ce_send_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct ol_softc *scn = CE_state->scn; + + cdf_spin_lock(&scn->target_lock); + CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, low_alert_nentries); + CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, high_alert_nentries); + cdf_spin_unlock(&scn->target_lock); +} + +void +ce_recv_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct ol_softc *scn = CE_state->scn; + + cdf_spin_lock(&scn->target_lock); + CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr, + low_alert_nentries); + CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr, + high_alert_nentries); + cdf_spin_unlock(&scn->target_lock); +} + +unsigned int ce_send_entries_avail(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index; + unsigned int write_index; + + cdf_spin_lock(&CE_state->scn->target_lock); + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + cdf_spin_unlock(&CE_state->scn->target_lock); + + return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +} + +unsigned int ce_recv_entries_avail(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index; + unsigned int write_index; + + cdf_spin_lock(&CE_state->scn->target_lock); + sw_index = dest_ring->sw_index; + write_index = dest_ring->write_index; + cdf_spin_unlock(&CE_state->scn->target_lock); + + return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +} + +/* + * Guts of ce_send_entries_done. + * The caller takes responsibility for any necessary locking. + */ +unsigned int +ce_send_entries_done_nolock(struct ol_softc *scn, + struct CE_state *CE_state) +{ + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index; + unsigned int read_index; + + sw_index = src_ring->sw_index; + read_index = CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr); + + return CE_RING_DELTA(nentries_mask, sw_index, read_index); +} + +unsigned int ce_send_entries_done(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int nentries; + + cdf_spin_lock(&CE_state->scn->target_lock); + nentries = ce_send_entries_done_nolock(CE_state->scn, CE_state); + cdf_spin_unlock(&CE_state->scn->target_lock); + + return nentries; +} + +/* + * Guts of ce_recv_entries_done. + * The caller takes responsibility for any necessary locking. + */ +unsigned int +ce_recv_entries_done_nolock(struct ol_softc *scn, + struct CE_state *CE_state) +{ + struct CE_ring_state *dest_ring = CE_state->dest_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index; + unsigned int read_index; + + sw_index = dest_ring->sw_index; + read_index = CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr); + + return CE_RING_DELTA(nentries_mask, sw_index, read_index); +} + +unsigned int ce_recv_entries_done(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int nentries; + + cdf_spin_lock(&CE_state->scn->target_lock); + nentries = ce_recv_entries_done_nolock(CE_state->scn, CE_state); + cdf_spin_unlock(&CE_state->scn->target_lock); + + return nentries; +} + +/* Debug support */ +void *ce_debug_cmplrn_context; /* completed recv next context */ +void *ce_debug_cnclsn_context; /* cancel send next context */ +void *ce_debug_rvkrn_context; /* revoke receive next context */ +void *ce_debug_cmplsn_context; /* completed send next context */ + +/* + * Guts of ce_completed_recv_next. + * The caller takes responsibility for any necessary locking. + */ +int +ce_completed_recv_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp) +{ + int status; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index = dest_ring->sw_index; + + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring->base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, sw_index); + int nbytes; + struct CE_dest_desc dest_desc_info; + /* + * By copying the dest_desc_info element to local memory, we could + * avoid extra memory read from non-cachable memory. + */ + dest_desc_info = *dest_desc; + nbytes = dest_desc_info.nbytes; + if (nbytes == 0) { + /* + * This closes a relatively unusual race where the Host + * sees the updated DRRI before the update to the + * corresponding descriptor has completed. We treat this + * as a descriptor that is not yet done. + */ + status = CDF_STATUS_E_FAILURE; + goto done; + } + + dest_desc->nbytes = 0; + + /* Return data from completed destination descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(&dest_desc_info); + *nbytesp = nbytes; + *transfer_idp = dest_desc_info.meta_data; + *flagsp = (dest_desc_info.byte_swap) ? CE_RECV_FLAG_SWAPPED : 0; + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->recv_context; + } + + ce_debug_cmplrn_context = dest_ring->per_transfer_context[sw_index]; + if (per_transfer_contextp) { + *per_transfer_contextp = ce_debug_cmplrn_context; + } + dest_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + status = CDF_STATUS_SUCCESS; + +done: + return status; +} + +int +ce_completed_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, unsigned int *flagsp) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + cdf_spin_lock_bh(&CE_state->scn->target_lock); + status = + ce_completed_recv_next_nolock(CE_state, per_CE_contextp, + per_transfer_contextp, bufferp, + nbytesp, transfer_idp, flagsp); + cdf_spin_unlock_bh(&CE_state->scn->target_lock); + + return status; +} + +/* NB: Modeled after ce_completed_recv_next_nolock */ +CDF_STATUS +ce_revoke_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, cdf_dma_addr_t *bufferp) +{ + struct CE_state *CE_state; + struct CE_ring_state *dest_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + CDF_STATUS status; + struct ol_softc *scn; + + CE_state = (struct CE_state *)copyeng; + dest_ring = CE_state->dest_ring; + if (!dest_ring) { + return CDF_STATUS_E_FAILURE; + } + + scn = CE_state->scn; + cdf_spin_lock(&scn->target_lock); + nentries_mask = dest_ring->nentries_mask; + sw_index = dest_ring->sw_index; + write_index = dest_ring->write_index; + if (write_index != sw_index) { + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring-> + base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, sw_index); + + /* Return data from completed destination descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(dest_desc); + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->recv_context; + } + + ce_debug_rvkrn_context = + dest_ring->per_transfer_context[sw_index]; + if (per_transfer_contextp) { + *per_transfer_contextp = ce_debug_rvkrn_context; + } + dest_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + status = CDF_STATUS_SUCCESS; + } else { + status = CDF_STATUS_E_FAILURE; + } + cdf_spin_unlock(&scn->target_lock); + + return status; +} + +/* + * Guts of ce_completed_send_next. + * The caller takes responsibility for any necessary locking. + */ +int +ce_completed_send_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + uint32_t *toeplitz_hash_result) +{ + int status = CDF_STATUS_E_FAILURE; + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index = src_ring->sw_index; + unsigned int read_index; + struct ol_softc *scn = CE_state->scn; + + if (src_ring->hw_index == sw_index) { + /* + * The SW completion index has caught up with the cached + * version of the HW completion index. + * Update the cached HW completion index to see whether + * the SW has really caught up to the HW, or if the cached + * value of the HW index has become stale. + */ + A_TARGET_ACCESS_BEGIN_RET(scn); + src_ring->hw_index = + CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr); + A_TARGET_ACCESS_END_RET(scn); + } + read_index = src_ring->hw_index; + + if (sw_idx) + *sw_idx = sw_index; + + if (hw_idx) + *hw_idx = read_index; + + if ((read_index != sw_index) && (read_index != 0xffffffff)) { + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, sw_index); +#ifdef QCA_WIFI_3_0 + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, sw_index); +#endif + /* Return data from completed source descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(shadow_src_desc); + *nbytesp = shadow_src_desc->nbytes; + *transfer_idp = shadow_src_desc->meta_data; +#ifdef QCA_WIFI_3_0 + *toeplitz_hash_result = src_desc->toeplitz_hash_result; +#else + *toeplitz_hash_result = 0; +#endif + if (per_CE_contextp) { + *per_CE_contextp = CE_state->send_context; + } + + ce_debug_cmplsn_context = + src_ring->per_transfer_context[sw_index]; + if (per_transfer_contextp) { + *per_transfer_contextp = ce_debug_cmplsn_context; + } + src_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + src_ring->sw_index = sw_index; + status = CDF_STATUS_SUCCESS; + } + + return status; +} + +/* NB: Modeled after ce_completed_send_next */ +CDF_STATUS +ce_cancel_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + uint32_t *toeplitz_hash_result) +{ + struct CE_state *CE_state; + struct CE_ring_state *src_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + CDF_STATUS status; + struct ol_softc *scn; + + CE_state = (struct CE_state *)copyeng; + src_ring = CE_state->src_ring; + if (!src_ring) { + return CDF_STATUS_E_FAILURE; + } + + scn = CE_state->scn; + cdf_spin_lock(&CE_state->scn->target_lock); + nentries_mask = src_ring->nentries_mask; + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (write_index != sw_index) { + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, sw_index); + + /* Return data from completed source descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(src_desc); + *nbytesp = src_desc->nbytes; + *transfer_idp = src_desc->meta_data; +#ifdef QCA_WIFI_3_0 + *toeplitz_hash_result = src_desc->toeplitz_hash_result; +#else + *toeplitz_hash_result = 0; +#endif + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->send_context; + } + + ce_debug_cnclsn_context = + src_ring->per_transfer_context[sw_index]; + if (per_transfer_contextp) { + *per_transfer_contextp = ce_debug_cnclsn_context; + } + src_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + src_ring->sw_index = sw_index; + status = CDF_STATUS_SUCCESS; + } else { + status = CDF_STATUS_E_FAILURE; + } + cdf_spin_unlock(&CE_state->scn->target_lock); + + return status; +} + +/* Shift bits to convert IS_*_RING_*_WATERMARK_MASK to CE_WM_FLAG_*_* */ +#define CE_WM_SHFT 1 + +int +ce_completed_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + cdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + unsigned int *toeplitz_hash_result) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + cdf_spin_lock_bh(&CE_state->scn->target_lock); + status = + ce_completed_send_next_nolock(CE_state, per_CE_contextp, + per_transfer_contextp, bufferp, + nbytesp, transfer_idp, sw_idx, + hw_idx, toeplitz_hash_result); + cdf_spin_unlock_bh(&CE_state->scn->target_lock); + + return status; +} + +#ifdef ATH_11AC_TXCOMPACT +/* CE engine descriptor reap + * Similar to ce_per_engine_service , Only difference is ce_per_engine_service + * does recieve and reaping of completed descriptor , + * This function only handles reaping of Tx complete descriptor. + * The Function is called from threshold reap poll routine + * hif_send_complete_check so should not countain recieve functionality + * within it . + */ + +void ce_per_engine_servicereap(struct ol_softc *scn, unsigned int CE_id) +{ + void *CE_context; + void *transfer_context; + cdf_dma_addr_t buf; + unsigned int nbytes; + unsigned int id; + unsigned int sw_idx, hw_idx; + uint32_t toeplitz_hash_result; + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + + A_TARGET_ACCESS_BEGIN(scn); + + /* Since this function is called from both user context and + * tasklet context the spinlock has to lock the bottom halves. + * This fix assumes that ATH_11AC_TXCOMPACT flag is always + * enabled in TX polling mode. If this is not the case, more + * bottom halve spin lock changes are needed. Due to data path + * performance concern, after internal discussion we've decided + * to make minimum change, i.e., only address the issue occured + * in this function. The possible negative effect of this minimum + * change is that, in the future, if some other function will also + * be opened to let the user context to use, those cases need to be + * addressed by change spin_lock to spin_lock_bh also. + */ + + cdf_spin_lock_bh(&scn->target_lock); + + if (CE_state->send_cb) { + { + /* Pop completed send buffers and call the + * registered send callback for each + */ + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, + &nbytes, &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == + CDF_STATUS_SUCCESS) { + if (CE_id != CE_HTT_H2T_MSG) { + cdf_spin_unlock_bh(&scn->target_lock); + CE_state-> + send_cb((struct CE_handle *) + CE_state, CE_context, + transfer_context, buf, + nbytes, id, sw_idx, hw_idx, + toeplitz_hash_result); + cdf_spin_lock_bh(&scn->target_lock); + } else { + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *) + CE_context; + + cdf_spin_lock_bh(&pipe_info-> + completion_freeq_lock); + pipe_info->num_sends_allowed++; + cdf_spin_unlock_bh(&pipe_info-> + completion_freeq_lock); + } + } + } + } + + cdf_spin_unlock_bh(&scn->target_lock); + A_TARGET_ACCESS_END(scn); +} + +#endif /*ATH_11AC_TXCOMPACT */ + +/* + * Number of times to check for any pending tx/rx completion on + * a copy engine, this count should be big enough. Once we hit + * this threashold we'll not check for any Tx/Rx comlpetion in same + * interrupt handling. Note that this threashold is only used for + * Rx interrupt processing, this can be used tor Tx as well if we + * suspect any infinite loop in checking for pending Tx completion. + */ +#define CE_TXRX_COMP_CHECK_THRESHOLD 20 + +/* + * Guts of interrupt handler for per-engine interrupts on a particular CE. + * + * Invokes registered callbacks for recv_complete, + * send_complete, and watermarks. + * + * Returns: number of messages processed + */ + +int ce_per_engine_service(struct ol_softc *scn, unsigned int CE_id) +{ + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + void *CE_context; + void *transfer_context; + cdf_dma_addr_t buf; + unsigned int nbytes; + unsigned int id; + unsigned int flags; + uint32_t CE_int_status; + unsigned int more_comp_cnt = 0; + unsigned int more_snd_comp_cnt = 0; + unsigned int sw_idx, hw_idx; + uint32_t toeplitz_hash_result; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) { + HIF_ERROR("[premature rc=0]\n"); + return 0; /* no work done */ + } + + cdf_spin_lock(&scn->target_lock); + + /* Clear force_break flag and re-initialize receive_count to 0 */ + + /* NAPI: scn variables- thread/multi-processing safety? */ + scn->receive_count = 0; + scn->force_break = 0; +more_completions: + if (CE_state->recv_cb) { + + /* Pop completed recv buffers and call + * the registered recv callback for each + */ + while (ce_completed_recv_next_nolock + (CE_state, &CE_context, &transfer_context, + &buf, &nbytes, &id, &flags) == + CDF_STATUS_SUCCESS) { + cdf_spin_unlock(&scn->target_lock); + CE_state->recv_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, buf, + nbytes, id, flags); + + /* + * EV #112693 - + * [Peregrine][ES1][WB342][Win8x86][Performance] + * BSoD_0x133 occurred in VHT80 UDP_DL + * Break out DPC by force if number of loops in + * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES + * to avoid spending too long time in + * DPC for each interrupt handling. Schedule another + * DPC to avoid data loss if we had taken + * force-break action before apply to Windows OS + * only currently, Linux/MAC os can expand to their + * platform if necessary + */ + + /* Break the receive processes by + * force if force_break set up + */ + if (cdf_unlikely(scn->force_break)) { + cdf_atomic_set(&CE_state->rx_pending, 1); + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + HOST_IS_COPY_COMPLETE_MASK); + if (Q_TARGET_ACCESS_END(scn) < 0) + HIF_ERROR("<--[premature rc=%d]\n", + scn->receive_count); + return scn->receive_count; + } + cdf_spin_lock(&scn->target_lock); + } + } + + /* + * Attention: We may experience potential infinite loop for below + * While Loop during Sending Stress test. + * Resolve the same way as Receive Case (Refer to EV #112693) + */ + + if (CE_state->send_cb) { + /* Pop completed send buffers and call + * the registered send callback for each + */ + +#ifdef ATH_11AC_TXCOMPACT + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, &nbytes, + &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == CDF_STATUS_SUCCESS) { + + if (CE_id != CE_HTT_H2T_MSG || + WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + cdf_spin_unlock(&scn->target_lock); + CE_state->send_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, + buf, nbytes, id, sw_idx, + hw_idx, toeplitz_hash_result); + cdf_spin_lock(&scn->target_lock); + } else { + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)CE_context; + + cdf_spin_lock(&pipe_info-> + completion_freeq_lock); + pipe_info->num_sends_allowed++; + cdf_spin_unlock(&pipe_info-> + completion_freeq_lock); + } + } +#else /*ATH_11AC_TXCOMPACT */ + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, &nbytes, + &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == CDF_STATUS_SUCCESS) { + cdf_spin_unlock(&scn->target_lock); + CE_state->send_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, buf, + nbytes, id, sw_idx, hw_idx, + toeplitz_hash_result); + cdf_spin_lock(&scn->target_lock); + } +#endif /*ATH_11AC_TXCOMPACT */ + } + +more_watermarks: + if (CE_state->misc_cbs) { + CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr); + if (CE_int_status & CE_WATERMARK_MASK) { + if (CE_state->watermark_cb) { + + cdf_spin_unlock(&scn->target_lock); + /* Convert HW IS bits to software flags */ + flags = + (CE_int_status & CE_WATERMARK_MASK) >> + CE_WM_SHFT; + + CE_state-> + watermark_cb((struct CE_handle *)CE_state, + CE_state->wm_context, flags); + cdf_spin_lock(&scn->target_lock); + } + } + } + + /* + * Clear the misc interrupts (watermark) that were handled above, + * and that will be checked again below. + * Clear and check for copy-complete interrupts again, just in case + * more copy completions happened while the misc interrupts were being + * handled. + */ + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + CE_WATERMARK_MASK | + HOST_IS_COPY_COMPLETE_MASK); + + /* + * Now that per-engine interrupts are cleared, verify that + * no recv interrupts arrive while processing send interrupts, + * and no recv or send interrupts happened while processing + * misc interrupts.Go back and check again.Keep checking until + * we find no more events to process. + */ + if (CE_state->recv_cb && ce_recv_entries_done_nolock(scn, CE_state)) { + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam()) || + more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { + goto more_completions; + } else { + HIF_ERROR( + "%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x", + __func__, CE_state->dest_ring->nentries_mask, + CE_state->dest_ring->sw_index, + CE_DEST_RING_READ_IDX_GET(scn, + CE_state->ctrl_addr)); + } + } + + if (CE_state->send_cb && ce_send_entries_done_nolock(scn, CE_state)) { + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam()) || + more_snd_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { + goto more_completions; + } else { + HIF_ERROR( + "%s:Potential infinite loop detected during send completion nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x", + __func__, CE_state->src_ring->nentries_mask, + CE_state->src_ring->sw_index, + CE_SRC_RING_READ_IDX_GET(scn, + CE_state->ctrl_addr)); + } + } + + if (CE_state->misc_cbs) { + CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr); + if (CE_int_status & CE_WATERMARK_MASK) { + if (CE_state->watermark_cb) { + goto more_watermarks; + } + } + } + + cdf_spin_unlock(&scn->target_lock); + cdf_atomic_set(&CE_state->rx_pending, 0); + + if (Q_TARGET_ACCESS_END(scn) < 0) + HIF_ERROR("<--[premature rc=%d]\n", scn->receive_count); + return scn->receive_count; +} + +/* + * Handler for per-engine interrupts on ALL active CEs. + * This is used in cases where the system is sharing a + * single interrput for all CEs + */ + +void ce_per_engine_service_any(int irq, struct ol_softc *scn) +{ + int CE_id; + uint32_t intr_summary; + + A_TARGET_ACCESS_BEGIN(scn); + if (!cdf_atomic_read(&scn->tasklet_from_intr)) { + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + if (cdf_atomic_read(&CE_state->rx_pending)) { + cdf_atomic_set(&CE_state->rx_pending, 0); + ce_per_engine_service(scn, CE_id); + } + } + + A_TARGET_ACCESS_END(scn); + return; + } + + intr_summary = CE_INTERRUPT_SUMMARY(scn); + + for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) { + if (intr_summary & (1 << CE_id)) { + intr_summary &= ~(1 << CE_id); + } else { + continue; /* no intr pending on this CE */ + } + + ce_per_engine_service(scn, CE_id); + } + + A_TARGET_ACCESS_END(scn); +} + +/* + * Adjust interrupts for the copy complete handler. + * If it's needed for either send or recv, then unmask + * this interrupt; otherwise, mask it. + * + * Called with target_lock held. + */ +static void +ce_per_engine_handler_adjust(struct CE_state *CE_state, + int disable_copy_compl_intr) +{ + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct ol_softc *scn = CE_state->scn; + + CE_state->disable_copy_compl_intr = disable_copy_compl_intr; + A_TARGET_ACCESS_BEGIN(scn); + if ((!disable_copy_compl_intr) && + (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr); + } else { + CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr); + } else { + CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr); + } + A_TARGET_ACCESS_END(scn); + +} + +/*Iterate the CE_state list and disable the compl interrupt + * if it has been registered already. + */ +void ce_disable_any_copy_compl_intr_nolock(struct ol_softc *scn) +{ + int CE_id; + + A_TARGET_ACCESS_BEGIN(scn); + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + + /* if the interrupt is currently enabled, disable it */ + if (!CE_state->disable_copy_compl_intr + && (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr); + } + } + A_TARGET_ACCESS_END(scn); +} + +void ce_enable_any_copy_compl_intr_nolock(struct ol_softc *scn) +{ + int CE_id; + + A_TARGET_ACCESS_BEGIN(scn); + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + + /* + * If the CE is supposed to have copy complete interrupts + * enabled (i.e. there a callback registered, and the + * "disable" flag is not set), then re-enable the interrupt. + */ + if (!CE_state->disable_copy_compl_intr + && (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr); + } + } + A_TARGET_ACCESS_END(scn); +} + +void ce_disable_any_copy_compl_intr(struct ol_softc *scn) +{ + cdf_spin_lock(&scn->target_lock); + ce_disable_any_copy_compl_intr_nolock(scn); + cdf_spin_unlock(&scn->target_lock); +} + +/*Re-enable the copy compl interrupt if it has not been disabled before.*/ +void ce_enable_any_copy_compl_intr(struct ol_softc *scn) +{ + cdf_spin_lock(&scn->target_lock); + ce_enable_any_copy_compl_intr_nolock(scn); + cdf_spin_unlock(&scn->target_lock); +} + +void +ce_send_cb_register(struct CE_handle *copyeng, + ce_send_cb fn_ptr, + void *ce_send_context, int disable_interrupts) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + cdf_spin_lock(&CE_state->scn->target_lock); + CE_state->send_cb = fn_ptr; + CE_state->send_context = ce_send_context; + ce_per_engine_handler_adjust(CE_state, disable_interrupts); + cdf_spin_unlock(&CE_state->scn->target_lock); +} + +void +ce_recv_cb_register(struct CE_handle *copyeng, + CE_recv_cb fn_ptr, + void *CE_recv_context, int disable_interrupts) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + cdf_spin_lock(&CE_state->scn->target_lock); + CE_state->recv_cb = fn_ptr; + CE_state->recv_context = CE_recv_context; + ce_per_engine_handler_adjust(CE_state, disable_interrupts); + cdf_spin_unlock(&CE_state->scn->target_lock); +} + +void +ce_watermark_cb_register(struct CE_handle *copyeng, + CE_watermark_cb fn_ptr, void *CE_wm_context) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + cdf_spin_lock(&CE_state->scn->target_lock); + CE_state->watermark_cb = fn_ptr; + CE_state->wm_context = CE_wm_context; + ce_per_engine_handler_adjust(CE_state, 0); + if (fn_ptr) { + CE_state->misc_cbs = 1; + } + cdf_spin_unlock(&CE_state->scn->target_lock); +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ce_pkt_dl_len_set() set the HTT packet download length + * @hif_sc: HIF context + * @pkt_download_len: download length + * + * Return: None + */ +void ce_pkt_dl_len_set(void *hif_sc, u_int32_t pkt_download_len) +{ + struct ol_softc *sc = (struct ol_softc *)(hif_sc); + struct CE_state *ce_state = sc->ce_id_to_state[CE_HTT_H2T_MSG]; + + cdf_assert_always(ce_state); + + cdf_spin_lock_bh(&sc->target_lock); + ce_state->download_len = pkt_download_len; + cdf_spin_unlock_bh(&sc->target_lock); + + cdf_print("%s CE %d Pkt download length %d\n", __func__, + ce_state->id, ce_state->download_len); +} +#else +void ce_pkt_dl_len_set(void *hif_sc, u_int32_t pkt_download_len) +{ +} +#endif /* WLAN_FEATURE_FASTPATH */ + +bool ce_get_rx_pending(struct ol_softc *scn) +{ + int CE_id; + + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + if (cdf_atomic_read(&CE_state->rx_pending)) + return true; + } + + return false; +} + +/** + * ce_check_rx_pending() - ce_check_rx_pending + * @scn: ol_softc + * @ce_id: ce_id + * + * Return: bool + */ +bool ce_check_rx_pending(struct ol_softc *scn, int ce_id) +{ + struct CE_state *CE_state = scn->ce_id_to_state[ce_id]; + if (cdf_atomic_read(&CE_state->rx_pending)) + return true; + else + return false; +} +void ce_enable_msi(struct ol_softc *scn, unsigned int CE_id, + uint32_t msi_addr_lo, uint32_t msi_addr_hi, + uint32_t msi_data) +{ +#ifdef WLAN_ENABLE_QCA6180 + struct CE_state *CE_state; + A_target_id_t targid; + u_int32_t ctrl_addr; + uint32_t tmp; + + adf_os_spin_lock(&scn->target_lock); + CE_state = scn->ce_id_to_state[CE_id]; + if (!CE_state) { + HIF_ERROR("%s: error - CE_state = NULL", __func__); + adf_os_spin_unlock(&scn->target_lock); + return; + } + targid = TARGID(sc); + ctrl_addr = CE_state->ctrl_addr; + CE_MSI_ADDR_LOW_SET(scn, ctrl_addr, msi_addr_lo); + CE_MSI_ADDR_HIGH_SET(scn, ctrl_addr, msi_addr_hi); + CE_MSI_DATA_SET(scn, ctrl_addr, msi_data); + tmp = CE_CTRL_REGISTER1_GET(scn, ctrl_addr); + tmp |= (1 << CE_MSI_ENABLE_BIT); + CE_CTRL_REGISTER1_SET(scn, ctrl_addr, tmp); + adf_os_spin_unlock(&scn->target_lock); +#endif +} + +#ifdef IPA_OFFLOAD +/* + * Copy engine should release resource to micro controller + * Micro controller needs + - Copy engine source descriptor base address + - Copy engine source descriptor size + - PCI BAR address to access copy engine regiser + */ +void ce_ipa_get_resource(struct CE_handle *ce, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr) +{ + struct CE_state *CE_state = (struct CE_state *)ce; + uint32_t ring_loop; + struct CE_src_desc *ce_desc; + cdf_dma_addr_t phy_mem_base; + struct ol_softc *scn = CE_state->scn; + + if (CE_RUNNING != CE_state->state) { + *ce_sr_base_paddr = 0; + *ce_sr_ring_size = 0; + return; + } + + /* Update default value for descriptor */ + for (ring_loop = 0; ring_loop < CE_state->src_ring->nentries; + ring_loop++) { + ce_desc = (struct CE_src_desc *) + ((char *)CE_state->src_ring->base_addr_owner_space + + ring_loop * (sizeof(struct CE_src_desc))); + CE_IPA_RING_INIT(ce_desc); + } + + /* Get BAR address */ + hif_read_phy_mem_base(CE_state->scn, &phy_mem_base); + + *ce_sr_base_paddr = (uint32_t) CE_state->src_ring->base_addr_CE_space; + *ce_sr_ring_size = (uint32_t) CE_state->src_ring->nentries; + *ce_reg_paddr = phy_mem_base + CE_BASE_ADDRESS(CE_state->id) + + SR_WR_INDEX_ADDRESS; + return; +} +#endif /* IPA_OFFLOAD */ + diff --git a/core/hif/src/ce/ce_tasklet.c b/core/hif/src/ce/ce_tasklet.c new file mode 100644 index 0000000000..6bb550e3c8 --- /dev/null +++ b/core/hif/src/ce/ce_tasklet.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include "a_types.h" +#include "athdefs.h" +#include "cdf_lock.h" +#include "cdf_types.h" +#include "cdf_status.h" +#include "cds_api.h" +#include "regtable.h" +#include "hif.h" +#include "hif_io32.h" +#include "ce_main.h" +#include "ce_api.h" +#include "ce_reg.h" +#include "ce_internal.h" +#ifdef CONFIG_CNSS +#include +#ifdef HIF_PCI +#include "icnss_stub.h" +#else +#include +#endif /* HIF_PCI */ +#endif +#include "hif_debug.h" +#include "hif_napi.h" + + +/** + * ce_irq_status() - read CE IRQ status + * @scn: struct ol_softc + * @ce_id: ce_id + * @host_status: host_status + * + * Return: IRQ status + */ +static inline void ce_irq_status(struct ol_softc *scn, + int ce_id, uint32_t *host_status) +{ + uint32_t offset = HOST_IS_ADDRESS + CE_BASE_ADDRESS(ce_id); + + *host_status = hif_read32_mb(scn->mem + offset); +} + +/** + * reschedule_ce_tasklet_work_handler() - reschedule work + * @ce_id: ce_id + * + * Return: N/A + */ +static void reschedule_ce_tasklet_work_handler(int ce_id) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct HIF_CE_state *hif_ce_state; + + if (NULL == scn) { + HIF_ERROR("%s: tasklet scn is null", __func__); + return; + } + hif_ce_state = (struct HIF_CE_state *)scn->hif_hdl; + + if (scn->hif_init_done == false) { + HIF_ERROR("%s: wlan driver is unloaded", __func__); + return; + } + tasklet_schedule(&hif_ce_state->tasklets[ce_id].intr_tq); + return; +} + +/** + * struct tasklet_work + * + * @id: ce_id + * @work: work + */ +struct tasklet_work { + enum ce_id_type id; + struct work_struct work; +}; + +static struct tasklet_work tasklet_workers[CE_ID_MAX]; +static bool work_initialized; + +/** + * work_handler() - work_handler + * @work: struct work_struct + * + * Return: N/A + */ +static void work_handler(struct work_struct *work) +{ + struct tasklet_work *tmp; + + tmp = container_of(work, struct tasklet_work, work); + reschedule_ce_tasklet_work_handler(tmp->id); +} + +/** + * init_tasklet_work() - init_tasklet_work + * @work: struct work_struct + * @work_handler: work_handler + * + * Return: N/A + */ +#ifdef CONFIG_CNSS +static void init_tasklet_work(struct work_struct *work, + work_func_t work_handler) +{ + cnss_init_work(work, work_handler); +} +#else +static void init_tasklet_work(struct work_struct *work, + work_func_t work_handler) +{ + INIT_WORK(work, work_handler); +} +#endif + +/** + * init_tasklet_workers() - init_tasklet_workers + * + * Return: N/A + */ +void init_tasklet_workers(void) +{ + uint32_t id; + + for (id = 0; id < CE_ID_MAX; id++) { + tasklet_workers[id].id = id; + init_tasklet_work(&tasklet_workers[id].work, work_handler); + } + work_initialized = true; +} + +#ifdef CONFIG_SLUB_DEBUG_ON +/** + * ce_schedule_tasklet() - schedule ce tasklet + * @tasklet_entry: struct ce_tasklet_entry + * + * Return: N/A + */ +static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry) +{ + if (work_initialized && (tasklet_entry->ce_id <= CE_ID_MAX)) + schedule_work(&tasklet_workers[tasklet_entry->ce_id].work); + else + HIF_ERROR("%s: work_initialized = %d, ce_id = %d", + __func__, work_initialized, tasklet_entry->ce_id); +} +#else +/** + * ce_schedule_tasklet() - schedule ce tasklet + * @tasklet_entry: struct ce_tasklet_entry + * + * Return: N/A + */ +static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry) +{ + tasklet_schedule(&tasklet_entry->intr_tq); +} +#endif + +/** + * ce_tasklet() - ce_tasklet + * @data: data + * + * Return: N/A + */ +static void ce_tasklet(unsigned long data) +{ + struct ce_tasklet_entry *tasklet_entry = + (struct ce_tasklet_entry *)data; + struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state; + struct ol_softc *scn = hif_ce_state->scn; + struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id]; + + if (tasklet_entry->from_irq) + tasklet_entry->from_irq = false; + + if (cdf_atomic_read(&scn->link_suspended)) { + HIF_ERROR("%s: ce %d tasklet fired after link suspend.", + __func__, tasklet_entry->ce_id); + CDF_BUG(0); + } + + ce_per_engine_service(scn, tasklet_entry->ce_id); + + if (tasklet_entry->ce_id == CE_HTT_T2H_MSG && + CE_state->lro_flush_cb != NULL) { + CE_state->lro_flush_cb(CE_state->lro_data); + } + + if (ce_check_rx_pending(scn, tasklet_entry->ce_id)) { + /* + * There are frames pending, schedule tasklet to process them. + * Enable the interrupt only when there is no pending frames in + * any of the Copy Engine pipes. + */ + ce_schedule_tasklet(tasklet_entry); + return; + } + + if (scn->target_status != OL_TRGET_STATUS_RESET) + ce_irq_enable(scn, tasklet_entry->ce_id); + + cdf_atomic_dec(&scn->active_tasklet_cnt); +} +/** + * ce_tasklet_init() - ce_tasklet_init + * @hif_ce_state: hif_ce_state + * @mask: mask + * + * Return: N/A + */ +void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int i; + + for (i = 0; i < CE_COUNT_MAX; i++) { + if (mask & (1 << i)) { + hif_ce_state->tasklets[i].ce_id = i; + hif_ce_state->tasklets[i].inited = true; + hif_ce_state->tasklets[i].hif_ce_state = hif_ce_state; + tasklet_init(&hif_ce_state->tasklets[i].intr_tq, + ce_tasklet, + (unsigned long)&hif_ce_state->tasklets[i]); + } + } +} +/** + * ce_tasklet_kill() - ce_tasklet_kill + * @hif_ce_state: hif_ce_state + * + * Return: N/A + */ +void ce_tasklet_kill(struct HIF_CE_state *hif_ce_state) +{ + int i; + struct ol_softc *scn = hif_ce_state->scn; + + for (i = 0; i < CE_COUNT_MAX; i++) + if (hif_ce_state->tasklets[i].inited) { + tasklet_kill(&hif_ce_state->tasklets[i].intr_tq); + hif_ce_state->tasklets[i].inited = false; + } + cdf_atomic_set(&scn->active_tasklet_cnt, 0); +} +/** + * ce_irq_handler() - ce_irq_handler + * @ce_id: ce_id + * @context: context + * + * Return: N/A + */ +static irqreturn_t ce_irq_handler(int irq, void *context) +{ + struct ce_tasklet_entry *tasklet_entry = context; + struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state; + struct ol_softc *scn = hif_ce_state->scn; + int ce_id = icnss_get_ce_id(irq); + uint32_t host_status; + + + if (tasklet_entry->ce_id != ce_id) { + HIF_ERROR("%s: ce_id (expect %d, received %d) does not match", + __func__, tasklet_entry->ce_id, ce_id); + return IRQ_NONE; + } + +#ifndef HIF_PCI + disable_irq_nosync(irq); +#endif + ce_irq_disable(scn, ce_id); + ce_irq_status(scn, ce_id, &host_status); + cdf_atomic_inc(&scn->active_tasklet_cnt); + if (hif_napi_enabled(scn, ce_id)) + hif_napi_schedule(scn, ce_id); + else { + tasklet_entry->from_irq = true; + tasklet_schedule(&tasklet_entry->intr_tq); + } + return IRQ_HANDLED; +} + +/** + * const char *ce_name + * + * @ce_name: ce_name + */ +const char *ce_name[ICNSS_MAX_IRQ_REGISTRATIONS] = { + "WLAN_CE_0", + "WLAN_CE_1", + "WLAN_CE_2", + "WLAN_CE_3", + "WLAN_CE_4", + "WLAN_CE_5", + "WLAN_CE_6", + "WLAN_CE_7", + "WLAN_CE_8", + "WLAN_CE_9", + "WLAN_CE_10", + "WLAN_CE_11", +}; +/** + * ce_unregister_irq() - ce_unregister_irq + * @hif_ce_state: hif_ce_state copy engine device handle + * @mask: which coppy engines to unregister for. + * + * Unregisters copy engine irqs matching mask. If a 1 is set at bit x, + * unregister for copy engine x. + * + * Return: CDF_STATUS + */ +CDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int id; + int ret; + + if (hif_ce_state == NULL) { + HIF_WARN("%s: hif_ce_state = NULL", __func__); + return CDF_STATUS_SUCCESS; + } + for (id = 0; id < CE_COUNT_MAX; id++) { + if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) { + ret = icnss_ce_free_irq(id, + &hif_ce_state->tasklets[id]); + if (ret < 0) + HIF_ERROR( + "%s: icnss_unregister_irq error - ce_id = %d, ret = %d", + __func__, id, ret); + } + } + return CDF_STATUS_SUCCESS; +} +/** + * ce_register_irq() - ce_register_irq + * @hif_ce_state: hif_ce_state + * @mask: which coppy engines to unregister for. + * + * Registers copy engine irqs matching mask. If a 1 is set at bit x, + * Register for copy engine x. + * + * Return: CDF_STATUS + */ +CDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int id; + int ret; + unsigned long irqflags = IRQF_TRIGGER_RISING; + uint32_t done_mask = 0; + + for (id = 0; id < CE_COUNT_MAX; id++) { + if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) { + ret = icnss_ce_request_irq(id, ce_irq_handler, + irqflags, ce_name[id], + &hif_ce_state->tasklets[id]); + if (ret) { + HIF_ERROR( + "%s: cannot register CE %d irq handler, ret = %d", + __func__, id, ret); + ce_unregister_irq(hif_ce_state, done_mask); + return CDF_STATUS_E_FAULT; + } else { + done_mask |= 1 << id; + } + } + } + +#ifndef HIF_PCI + /* move to hif_configure_irq */ + ce_enable_irq_in_group_reg(hif_ce_state->scn, done_mask); +#endif + + return CDF_STATUS_SUCCESS; +} diff --git a/core/hif/src/ce/ce_tasklet.h b/core/hif/src/ce/ce_tasklet.h new file mode 100644 index 0000000000..c4147709c8 --- /dev/null +++ b/core/hif/src/ce/ce_tasklet.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_TASKLET_H__ +#define __CE_TASKLET_H__ +void init_tasklet_workers(void); +void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask); +void ce_tasklet_kill(struct HIF_CE_state *hif_ce_state); +CDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); +CDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); +#endif /* __CE_TASKLET_H__ */ diff --git a/core/hif/src/hif_debug.h b/core/hif/src/hif_debug.h new file mode 100644 index 0000000000..4ab7d1f8e0 --- /dev/null +++ b/core/hif/src/hif_debug.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +#ifndef __HIF_DEBUG_H__ +#define __HIF_DEBUG_H__ +#include "cdf_trace.h" + +#define HIF_ERROR(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_ERROR, ## args) +#define HIF_WARN(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_WARN, ## args) +#define HIF_INFO(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_INFO, ## args) +#define HIF_INFO_HI(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_INFO_HIGH, ## args) +#define HIF_INFO_MED(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_INFO_MED, ## args) +#define HIF_INFO_LO(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_INFO_LOW, ## args) +#define HIF_TRACE(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_ERROR, ## args) +#define HIF_DBG(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_DEBUG, ## args) +#endif /* __HIF_DEBUG_H__ */ diff --git a/core/hif/src/hif_hw_version.h b/core/hif/src/hif_hw_version.h new file mode 100644 index 0000000000..d5d76dc059 --- /dev/null +++ b/core/hif/src/hif_hw_version.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +#ifndef HIF_HW_VERSION_H +#define HIF_HW_VERSION_H + +#define AR6320_REV1_VERSION 0x5000000 +#define AR6320_REV1_1_VERSION 0x5000001 +#define AR6320_REV1_3_VERSION 0x5000003 +#define AR6320_REV2_1_VERSION 0x5010000 +#define AR6320_REV3_VERSION 0x5020000 +#define AR6320_REV3_2_VERSION 0x5030000 + +struct qwlan_hw { + u32 id; + u32 subid; + const char *name; +}; + +static const struct qwlan_hw qwlan_hw_list[] = { + { + .id = AR6320_REV1_VERSION, + .subid = 0, + .name = "QCA6174_REV1", + }, + { + .id = AR6320_REV1_1_VERSION, + .subid = 0x1, + .name = "QCA6174_REV1_1", + }, + { + .id = AR6320_REV1_3_VERSION, + .subid = 0x2, + .name = "QCA6174_REV1_3", + }, + { + .id = AR6320_REV2_1_VERSION, + .subid = 0x4, + .name = "QCA6174_REV2_1", + }, + { + .id = AR6320_REV2_1_VERSION, + .subid = 0x5, + .name = "QCA6174_REV2_2", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x6, + .name = "QCA6174_REV2.3", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x8, + .name = "QCA6174_REV3", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x9, + .name = "QCA6174_REV3_1", + }, + { + .id = AR6320_REV3_2_VERSION, + .subid = 0xA, + .name = "AR6320_REV3_2_VERSION", + } +}; + +#endif /* HIF_HW_VERSION_H */ diff --git a/core/hif/src/hif_io32.h b/core/hif/src/hif_io32.h new file mode 100644 index 0000000000..d711ff719f --- /dev/null +++ b/core/hif/src/hif_io32.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_IO32_H__ +#define __HIF_IO32_H__ + +#include +#include "ol_if_athvar.h" +#include "hif.h" +#ifdef HIF_PCI +#include "hif_io32_pci.h" +#else +#include "hif_io32_snoc.h" +#endif /* HIF_PCI */ +#endif /* __HIF_IO32_H__ */ diff --git a/core/hif/src/hif_main.c b/core/hif/src/hif_main.c new file mode 100644 index 0000000000..bbfde23c23 --- /dev/null +++ b/core/hif/src/hif_main.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "a_types.h" +#include "athdefs.h" +#include "osapi_linux.h" +#include "targcfg.h" +#include "cdf_lock.h" +#include "cdf_status.h" +#include /* cdf_atomic_read */ +#include +#include +#include "hif_io32.h" +#include +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#include "hif_hw_version.h" +#include "ce_api.h" +#include "ce_tasklet.h" +#include "cdf_trace.h" +#include "cdf_status.h" +#include "cds_api.h" +#ifdef CONFIG_CNSS +#include +#endif +#include +#include "epping_main.h" +#include "hif_debug.h" +#include "mp_dev.h" +#ifdef HIF_PCI +#include "icnss_stub.h" +#else +#include +#endif + +#ifndef REMOVE_PKT_LOG +#include "pktlog_ac.h" +#endif + +#define AGC_DUMP 1 +#define CHANINFO_DUMP 2 +#define BB_WATCHDOG_DUMP 3 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_ACCESS_DUMP 4 +#endif + +void hif_dump(struct ol_softc *scn, uint8_t cmd_id, bool start) +{ + switch (cmd_id) { + case AGC_DUMP: + if (start) + priv_start_agc(scn); + else + priv_dump_agc(scn); + break; + + case CHANINFO_DUMP: + if (start) + priv_start_cap_chaninfo(scn); + else + priv_dump_chaninfo(scn); + break; + + case BB_WATCHDOG_DUMP: + priv_dump_bbwatchdog(scn); + break; + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + case PCIE_ACCESS_DUMP: + hif_target_dump_access_log(); + break; +#endif + default: + HIF_ERROR("%s: Invalid htc dump command", __func__); + break; + } +} + +/** + * hif_shut_down_device() - hif_shut_down_device + * + * SThis fucntion shuts down the device + * + * @scn: ol_softc + * + * Return: void + */ +void hif_shut_down_device(struct ol_softc *scn) +{ + if (scn && scn->hif_hdl) { + struct HIF_CE_state *hif_state = + (struct HIF_CE_state *)scn->hif_hdl; + + hif_stop(scn); + cdf_mem_free(hif_state); + scn->hif_hdl = NULL; + } + +} + + + +/** + * hif_cancel_deferred_target_sleep() - cancel deferred target sleep + * + * This function cancels the defered target sleep + * + * @scn: ol_softc + * + * Return: void + */ +void hif_cancel_deferred_target_sleep(struct ol_softc *scn) +{ + hif_pci_cancel_deferred_target_sleep(scn); +} + +/** + * hif_get_target_id(): hif_get_target_id + * + * Return the virtual memory base address to the caller + * + * @scn: ol_softc + * + * Return: A_target_id_t + */ +A_target_id_t hif_get_target_id(struct ol_softc *scn) +{ + return scn->mem; +} + +/** + * hif_set_target_sleep(): hif_set_target_sleep + * @scn: scn + * @sleep_ok: sleep_ok + * @wait_for_it: wait + * + * Return: void + */ +void hif_set_target_sleep(struct ol_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + hif_target_sleep_state_adjust(scn, + sleep_ok, wait_for_it); +} + +/** + * hif_target_forced_awake(): hif_target_forced_awake + * @scn: scn + * + * Return: bool + */ +bool hif_target_forced_awake(struct ol_softc *scn) +{ + A_target_id_t addr = scn->mem; + bool awake; + bool forced_awake; + + awake = hif_targ_is_awake(scn, addr); + + forced_awake = + !!(hif_read32_mb + (addr + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS) & PCIE_SOC_WAKE_V_MASK); + + return awake && forced_awake; +} + +/** + * hif_fw_interrupt_handler(): FW interrupt handler + * + * This function is the FW interrupt handlder + * + * @irq: irq number + * @arg: the user pointer + * + * Return: bool + */ +#ifndef QCA_WIFI_3_0 +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg) +{ + struct ol_softc *scn = arg; + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + uint32_t fw_indicator_address, fw_indicator; + + A_TARGET_ACCESS_BEGIN_RET(scn); + + fw_indicator_address = hif_state->fw_indicator_address; + /* For sudden unplug this will return ~0 */ + fw_indicator = A_TARGET_READ(scn, fw_indicator_address); + + if ((fw_indicator != ~0) && (fw_indicator & FW_IND_EVENT_PENDING)) { + /* ACK: clear Target-side pending event */ + A_TARGET_WRITE(scn, fw_indicator_address, + fw_indicator & ~FW_IND_EVENT_PENDING); + A_TARGET_ACCESS_END_RET(scn); + + if (hif_state->started) { + /* Alert the Host-side service thread */ + atomic_set(&hif_state->fw_event_pending, 1); + hif_completion_thread(hif_state); + } else { + /* + * Probable Target failure before we're prepared + * to handle it. Generally unexpected. + */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Early firmware event indicated\n", + __func__)); + } + } else { + A_TARGET_ACCESS_END_RET(scn); + } + + return ATH_ISR_SCHED; +} +#else +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg) +{ + return ATH_ISR_SCHED; +} +#endif /* #ifdef QCA_WIFI_3_0 */ + +/** + * hif_get_targetdef(): hif_get_targetdef + * @scn: scn + * + * Return: void * + */ +void *hif_get_targetdef(struct ol_softc *scn) +{ + return scn->targetdef; +} + +/** + * hif_vote_link_down(): unvote for link up + * + * Call hif_vote_link_down to release a previous request made using + * hif_vote_link_up. A hif_vote_link_down call should only be made + * after a corresponding hif_vote_link_up, otherwise you could be + * negating a vote from another source. When no votes are present + * hif will not guarantee the linkstate after hif_bus_suspend. + * + * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread + * and initialization deinitialization sequencences. + * + * Return: n/a + */ +void hif_vote_link_down(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + CDF_BUG(scn); + + scn->linkstate_vote--; + if (scn->linkstate_vote == 0) + hif_bus_prevent_linkdown(false); +} + +/** + * hif_vote_link_up(): vote to prevent bus from suspending + * + * Makes hif guarantee that fw can message the host normally + * durring suspend. + * + * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread + * and initialization deinitialization sequencences. + * + * Return: n/a + */ +void hif_vote_link_up(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + CDF_BUG(scn); + + scn->linkstate_vote++; + if (scn->linkstate_vote == 1) + hif_bus_prevent_linkdown(true); +} + +/** + * hif_can_suspend_link(): query if hif is permitted to suspend the link + * + * Hif will ensure that the link won't be suspended if the upperlayers + * don't want it to. + * + * SYNCHRONIZATION: MC thread is stopped before bus suspend thus + * we don't need extra locking to ensure votes dont change while + * we are in the process of suspending or resuming. + * + * Return: false if hif will guarantee link up durring suspend. + */ +bool hif_can_suspend_link(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + CDF_BUG(scn); + + return scn->linkstate_vote == 0; +} + +/** + * hif_hia_item_address(): hif_hia_item_address + * @target_type: target_type + * @item_offset: item_offset + * + * Return: n/a + */ +uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset) +{ + switch (target_type) { + case TARGET_TYPE_AR6002: + return AR6002_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6003: + return AR6003_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6004: + return AR6004_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6006: + return AR6006_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR9888: + return AR9888_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6320: + case TARGET_TYPE_AR6320V2: + return AR6320_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_QCA6180: + return QCA6180_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_ADRASTEA: + /* ADRASTEA doesn't have a host interest address */ + ASSERT(0); + return 0; + default: + ASSERT(0); + return 0; + } +} + +/** + * hif_max_num_receives_reached() - check max receive is reached + * @count: unsigned int. + * + * Output check status as bool + * + * Return: bool + */ +bool hif_max_num_receives_reached(unsigned int count) +{ + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) + return count > 120; + else + return count > MAX_NUM_OF_RECEIVES; +} + +/** + * init_buffer_count() - initial buffer count + * @maxSize: cdf_size_t + * + * routine to modify the initial buffer count to be allocated on an os + * platform basis. Platform owner will need to modify this as needed + * + * Return: cdf_size_t + */ +cdf_size_t init_buffer_count(cdf_size_t maxSize) +{ + return maxSize; +} + +/** + * hif_init_cdf_ctx(): hif_init_cdf_ctx + * @hif_ctx: hif_ctx + * + * Return: int + */ +int hif_init_cdf_ctx(void *hif_ctx) +{ + cdf_device_t cdf_ctx; + struct ol_softc *scn = (struct ol_softc *)hif_ctx; + + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + if (!cdf_ctx) { + HIF_ERROR("%s: CDF is NULL", __func__); + return -ENOMEM; + } + + cdf_ctx->drv = &scn->aps_osdev; + cdf_ctx->drv_hdl = scn->aps_osdev.bdev; + cdf_ctx->dev = scn->aps_osdev.device; + scn->cdf_dev = cdf_ctx; + return 0; +} + +/** + * hif_deinit_cdf_ctx(): hif_deinit_cdf_ctx + * @hif_ctx: hif_ctx + * + * Return: void + */ +void hif_deinit_cdf_ctx(void *hif_ctx) +{ + struct ol_softc *scn = (struct ol_softc *)hif_ctx; + + if (scn == NULL || !scn->cdf_dev) + return; + scn->cdf_dev = NULL; +} + +/** + * hif_save_htc_htt_config_endpoint(): + * hif_save_htc_htt_config_endpoint + * @htc_endpoint: htc_endpoint + * + * Return: void + */ +void hif_save_htc_htt_config_endpoint(int htc_endpoint) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + + if (!scn) { + HIF_ERROR("%s: error: scn or scn->hif_sc is NULL!", + __func__); + return; + } + + scn->htc_endpoint = htc_endpoint; +} + +/** + * hif_get_hw_name(): get a human readable name for the hardware + * + * Return: human readible name for the underlying wifi hardware. + */ +const char *hif_get_hw_name(struct ol_softc *scn) +{ + int i; + for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) { + if (scn->target_version == qwlan_hw_list[i].id && + scn->target_revision == qwlan_hw_list[i].subid) { + return qwlan_hw_list[i].name; + } + } + + return "Unknown Device"; +} + +/** + * hif_get_hw_info(): hif_get_hw_info + * @scn: scn + * @version: version + * @revision: revision + * + * Return: n/a + */ +void hif_get_hw_info(void *scn, u32 *version, u32 *revision, + const char **target_name) +{ + *version = ((struct ol_softc *)scn)->target_version; + *revision = ((struct ol_softc *)scn)->target_revision; + *target_name = hif_get_hw_name((struct ol_softc *)scn); +} + +/** + * hif_set_fw_info(): set the target_fw_version + * @scn: scn + * @target_fw_version: target_fw_version + * + * Return: n/a + */ +void hif_set_fw_info(void *scn, uint32_t target_fw_version) +{ + ((struct ol_softc *)scn)->target_fw_version = target_fw_version; +} + +/** + * hif_open(): hif_open + * + * Return: scn + */ +CDF_STATUS hif_open(void) +{ + struct ol_softc *scn; + v_CONTEXT_t cds_context; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + cds_context = cds_get_global_context(); + status = cds_alloc_context(cds_context, CDF_MODULE_ID_HIF, + (void **)&scn, sizeof(*scn)); + if (status != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: cannot alloc ol_sc", __func__); + return status; + } + + cdf_mem_zero(scn, sizeof(*scn)); + scn->enableuartprint = 0; + scn->enablefwlog = 0; + scn->max_no_of_peers = 1; + scn->pkt_log_init = false; + cdf_atomic_init(&scn->wow_done); + cdf_atomic_init(&scn->active_tasklet_cnt); + cdf_atomic_init(&scn->link_suspended); + cdf_atomic_init(&scn->tasklet_from_intr); + init_waitqueue_head(&scn->aps_osdev.event_queue); + cdf_spinlock_init(&scn->target_lock); + scn->linkstate_vote = 0; + return status; +} + +/** + * hif_close(): hif_close + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +void hif_close(void *hif_ctx) +{ + struct ol_softc *scn = hif_ctx; + + if (scn == NULL) { + HIF_ERROR("%s: ol_softc is NULL", __func__); + return; + } + + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + + if (scn->hif_hdl) { + cdf_mem_free(scn->hif_hdl); + scn->hif_hdl = NULL; + } + hif_bus_close(scn); + cds_free_context(cds_get_global_context(), + CDF_MODULE_ID_HIF, hif_ctx); +} + +/** + * hif_enable(): hif_enable + * @hif_ctx: hif_ctx + * @dev: dev + * @bdev: bus dev + * @bid: bus ID + * @bus_type: bus type + * @type: enable type + * + * Return: CDF_STATUS + */ +CDF_STATUS hif_enable(void *hif_ctx, struct device *dev, + void *bdev, const hif_bus_id *bid, + enum ath_hal_bus_type bus_type, + enum hif_enable_type type) +{ + CDF_STATUS status; + struct ol_softc *scn = hif_ctx; + + if (scn == NULL) { + HIF_ERROR("%s: hif_ctx = NULL", __func__); + return CDF_STATUS_E_NULL_VALUE; + } + + status = hif_bus_open(scn, bus_type); + if (status != CDF_STATUS_SUCCESS) { + HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d", + __func__, status, bus_type); + return status; + } + + status = hif_enable_bus(scn, dev, bdev, bid, type); + if (status != CDF_STATUS_SUCCESS) { + hif_bus_close(scn); + HIF_ERROR("%s: hif_enable_bus error = %d", + __func__, status); + return status; + } + + if (ADRASTEA_BU) + hif_vote_link_up(); + + if (hif_config_ce(scn)) { + HIF_ERROR("%s: Target probe failed.", __func__); + hif_disable_bus(scn->aps_osdev.bdev); + hif_bus_close(scn); + status = CDF_STATUS_E_FAILURE; + return status; + } + /* + * Flag to avoid potential unallocated memory access from MSI + * interrupt handler which could get scheduled as soon as MSI + * is enabled, i.e to take care of the race due to the order + * in where MSI is enabled before the memory, that will be + * in interrupt handlers, is allocated. + */ + +#ifdef HIF_PCI + status = hif_configure_irq(scn->hif_sc); + if (status < 0) { + HIF_ERROR("%s: ERROR - configure_IRQ_and_CE failed, status = %d", + __func__, status); + return CDF_STATUS_E_FAILURE; + } +#endif + + scn->hif_init_done = true; + + HIF_TRACE("%s: X OK", __func__); + + return CDF_STATUS_SUCCESS; +} + +/** + * hif_pktlogmod_exit(): hif_pktlogmod_exit + * @scn: scn + * + * Return: n/a + */ +#ifndef REMOVE_PKT_LOG +void hif_pktlogmod_exit(void *hif_ctx) +{ + struct ol_softc *scn = hif_ctx; + + if (scn && cds_get_conparam() != CDF_FTM_MODE && + !WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && scn->pkt_log_init) { + pktlogmod_exit(scn); + scn->pkt_log_init = false; + } +} +#else +void hif_pktlogmod_exit(void *hif_ctx) +{ +} +#endif + +#if ((!defined(QCA_WIFI_3_0_IHELIUM) && !defined(QCA_WIFI_3_0_ADRASTEA)) || defined(CONFIG_ICNSS)) +static inline void cnss_pcie_notify_q6(void) +{ + return; +} +#endif + +/** + * hif_wlan_disable(): call the platform driver to disable wlan + * + * This function passes the con_mode to platform driver to disable + * wlan. + * + * Return: void + */ +void hif_wlan_disable(void) +{ + enum icnss_driver_mode mode; + uint32_t con_mode = cds_get_conparam(); + + switch (con_mode) { + case CDF_FTM_MODE: + mode = ICNSS_FTM; + break; + case CDF_EPPING_MODE: + mode = ICNSS_EPPING; + break; + default: + mode = ICNSS_MISSION; + break; + } + + icnss_wlan_disable(mode); +} + +void hif_disable(void *hif_ctx, enum hif_disable_type type) +{ + struct ol_softc *scn = hif_ctx; + + if (!scn) + return; + + hif_nointrs(scn); + if (scn->hif_init_done == false) + hif_shut_down_device(scn); + else + hif_stop(scn); + + if (ADRASTEA_BU) + hif_vote_link_down(); + + if (scn->aps_osdev.bdev) + hif_disable_bus(scn->aps_osdev.bdev); + + if (IHELIUM_BU) { + cnss_pcie_notify_q6(); + HIF_TRACE("%s: cnss_pcie_notify_q6 done, notice_send= %d", + __func__, scn->notice_send); + } + + hif_wlan_disable(); + + scn->notice_send = false; + + HIF_INFO("%s: X", __func__); +} + + +/** + * hif_crash_shutdown_dump_ce_register(): + * hif_crash_shutdown_dump_ce_register + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +#if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \ +&& defined(HIF_PCI) && defined(DEBUG) + +static void hif_crash_shutdown_dump_ce_register(void *hif_ctx) +{ + struct ol_softc *scn = hif_ctx; + + if (hif_check_soc_status(scn) + || dump_ce_register(scn)) { + return; + } + + dump_ce_debug_register(scn); +} + +/** + * hif_crash_shutdown(): hif_crash_shutdown + * + * This function is called by the platform driver to dump CE registers + * + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +void hif_crash_shutdown(void *hif_ctx) +{ + struct ol_softc *scn = hif_ctx; + struct HIF_CE_state *hif_state; + + if (!scn) + return; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + if (!hif_state) + return; + + + if (OL_TRGET_STATUS_RESET == scn->target_status) { + HIF_INFO_MED("%s: Target is already asserted, ignore!", + __func__); + return; + } + + if (cds_is_load_unload_in_progress()) { + HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__); + return; + } + + cdf_spin_lock_irqsave(&scn->target_lock); + + hif_crash_shutdown_dump_ce_register(hif_ctx); + + if (ol_copy_ramdump(scn)) + goto out; + + HIF_INFO_MED("%s: RAM dump collecting completed!", __func__); + +out: + cdf_spin_unlock_irqrestore(&scn->target_lock); + return; +} +#else +void hif_crash_shutdown(void *hif_ctx) +{ + HIF_INFO_MED("%s: Collecting target RAM dump disabled", + __func__); + return; +} +#endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */ + +#ifdef QCA_WIFI_3_0 +/** + * hif_check_fw_reg(): hif_check_fw_reg + * @scn: scn + * @state: + * + * Return: int + */ +int hif_check_fw_reg(struct ol_softc *scn) +{ + return 0; +} +#endif + +#ifdef IPA_OFFLOAD +/** + * hif_read_phy_mem_base(): hif_read_phy_mem_base + * @scn: scn + * @phy_mem_base: physical mem base + * + * Return: n/a + */ +void hif_read_phy_mem_base(struct ol_softc *scn, cdf_dma_addr_t *phy_mem_base) +{ + *phy_mem_base = scn->mem_pa; +} +#endif /* IPA_OFFLOAD */ + +/** + * hif_get_device_type(): hif_get_device_type + * @device_id: device_id + * @revision_id: revision_id + * @hif_type: returned hif_type + * @target_type: returned target_type + * + * Return: int + */ +int hif_get_device_type(uint32_t device_id, + uint32_t revision_id, + uint32_t *hif_type, uint32_t *target_type) +{ + int ret = 0; + + switch (device_id) { +#ifdef QCA_WIFI_3_0_ADRASTEA + case ADRASTEA_DEVICE_ID: + case ADRASTEA_DEVICE_ID_P2_E12: + + *hif_type = HIF_TYPE_ADRASTEA; + *target_type = TARGET_TYPE_ADRASTEA; + break; +#else + case QCA6180_DEVICE_ID: + *hif_type = HIF_TYPE_QCA6180; + *target_type = TARGET_TYPE_QCA6180; + break; +#endif + + case AR9888_DEVICE_ID: + *hif_type = HIF_TYPE_AR9888; + *target_type = TARGET_TYPE_AR9888; + break; + + case AR6320_DEVICE_ID: + switch (revision_id) { + case AR6320_FW_1_1: + case AR6320_FW_1_3: + *hif_type = HIF_TYPE_AR6320; + *target_type = TARGET_TYPE_AR6320; + break; + + case AR6320_FW_2_0: + case AR6320_FW_3_0: + case AR6320_FW_3_2: + *hif_type = HIF_TYPE_AR6320V2; + *target_type = TARGET_TYPE_AR6320V2; + break; + + default: + HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x", + __func__, device_id, revision_id); + ret = -ENODEV; + goto end; + } + break; + + default: + HIF_ERROR("%s: Unsupported device ID!", __func__); + ret = -ENODEV; + break; + } +end: + return ret; +} diff --git a/core/hif/src/hif_main.h b/core/hif/src/hif_main.h new file mode 100644 index 0000000000..5a9c81ca1a --- /dev/null +++ b/core/hif/src/hif_main.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * NB: Inappropriate references to "HTC" are used in this (and other) + * HIF implementations. HTC is typically the calling layer, but it + * theoretically could be some alternative. + */ + +/* + * This holds all state needed to process a pending send/recv interrupt. + * The information is saved here as soon as the interrupt occurs (thus + * allowing the underlying CE to re-use the ring descriptor). The + * information here is eventually processed by a completion processing + * thread. + */ + +#ifndef __HIF_MAIN_H__ +#define __HIF_MAIN_H__ + +#include /* cdf_atomic_read */ +#include "cdf_lock.h" +#include "cepci.h" +#include "hif.h" + +#define HIF_MIN_SLEEP_INACTIVITY_TIME_MS 50 +#define HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS 60 + +/* + * This macro implementation is exposed for efficiency only. + * The implementation may change and callers should + * consider the targid to be a completely opaque handle. + */ +#define TARGID_TO_PCI_ADDR(targid) (*((A_target_id_t *)(targid))) + +A_target_id_t hif_get_target_id(struct ol_softc *scn); +bool hif_target_forced_awake(struct ol_softc *scn); + +#ifdef QCA_WIFI_3_0 +#define DISABLE_L1SS_STATES 1 +#endif +#ifdef CONFIG_SLUB_DEBUG_ON +#define MAX_NUM_OF_RECEIVES 100 /* Maximum number of Rx buf to process before* + * break out in SLUB debug builds */ +#elif defined(FEATURE_NAPI) +#define MAX_NUM_OF_RECEIVES HIF_NAPI_MAX_RECEIVES +#else /* no SLUBS, no NAPI */ +/* Maximum number of Rx buf to process before break out */ +#define MAX_NUM_OF_RECEIVES 1000 +#endif /* SLUB_DEBUG_ON / FEATURE_NAPI */ + +#ifdef QCA_WIFI_3_0_IHELIUM +#define IHELIUM_BU 1 +#else +#define IHELIUM_BU 0 +#endif + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define ADRASTEA_BU 1 +#else +#define ADRASTEA_BU 0 +#endif + +#ifdef QCA_WIFI_3_0 +#define HAS_FW_INDICATOR 0 +#else +#define HAS_FW_INDICATOR 1 +#endif + + +#define AR9888_DEVICE_ID (0x003c) +#define AR6320_DEVICE_ID (0x003e) +#define AR6320_FW_1_1 (0x11) +#define AR6320_FW_1_3 (0x13) +#define AR6320_FW_2_0 (0x20) +#define AR6320_FW_3_0 (0x30) +#define AR6320_FW_3_2 (0x32) +#define ADRASTEA_DEVICE_ID (0xabcd) +#define ADRASTEA_DEVICE_ID_P2_E12 (0x7021) +#if (defined(QVIT) || defined (QCA_WIFI_3_0_IHELIUM)) +#define QCA6180_DEVICE_ID (0xabcd) +#else +#define QCA6180_DEVICE_ID (0x041) +#endif + +A_target_id_t hif_get_target_id(struct ol_softc *scn); +void hif_dump_pipe_debug_count(struct ol_softc *scn); + +bool hif_max_num_receives_reached(unsigned int count); +int hif_config_ce(hif_handle_t hif_hdl); +int athdiag_procfs_init(void *scn); +void athdiag_procfs_remove(void); +/* routine to modify the initial buffer count to be allocated on an os + * platform basis. Platform owner will need to modify this as needed + */ +cdf_size_t init_buffer_count(cdf_size_t maxSize); + +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg); +int hif_get_target_type(struct ol_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, uint32_t *hif_type, + uint32_t *target_type); +int hif_get_device_type(uint32_t device_id, + uint32_t revision_id, + uint32_t *hif_type, uint32_t *target_type); +/*These functions are exposed to HDD*/ +int hif_init_cdf_ctx(void *ol_sc); +void hif_deinit_cdf_ctx(void *ol_sc); +bool hif_targ_is_awake(struct ol_softc *scn, void *__iomem *mem); +void hif_nointrs(struct ol_softc *scn); +void hif_bus_close(struct ol_softc *ol_sc); +CDF_STATUS hif_bus_open(struct ol_softc *ol_sc, + enum ath_hal_bus_type bus_type); +CDF_STATUS hif_enable_bus(struct ol_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, enum hif_enable_type type); +void hif_disable_bus(void *bdev); +void hif_bus_prevent_linkdown(bool flag); + +#endif /* __HIF_MAIN_H__ */ diff --git a/core/hif/src/hif_napi.c b/core/hif/src/hif_napi.c new file mode 100644 index 0000000000..f33fb8747b --- /dev/null +++ b/core/hif/src/hif_napi.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: hif_napi.c + * + * HIF NAPI interface implementation + */ + +#include /* memset */ + +#include +#include +#include +#include +#include + +enum napi_decision_vector { + HIF_NAPI_NOEVENT = 0, + HIF_NAPI_INITED = 1, + HIF_NAPI_CONF_UP = 2 +}; +#define ENABLE_NAPI_MASK (HIF_NAPI_INITED | HIF_NAPI_CONF_UP) + +/** + * hif_napi_create() - creates the NAPI structures for a given CE + * @hif : pointer to hif context + * @pipe_id: the CE id on which the instance will be created + * @poll : poll function to be used for this NAPI instance + * @budget : budget to be registered with the NAPI instance + * @scale : scale factor on the weight (to scaler budget to 1000) + * + * Description: + * Creates NAPI instances. This function is called + * unconditionally during initialization. It creates + * napi structures through the proper HTC/HIF calls. + * The structures are disabled on creation. + * Note that for each NAPI instance a separate dummy netdev is used + * + * Return: + * < 0: error + * = 0: + * > 0: id of the created object (for multi-NAPI, number of objects created) + */ +int hif_napi_create(struct ol_softc *hif, + uint8_t pipe_id, + int (*poll)(struct napi_struct *, int), + int budget, + int scale) +{ + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + NAPI_DEBUG("-->(pipe=%d, budget=%d, scale=%d)\n", + pipe_id, budget, scale); + NAPI_DEBUG("hif->napi_data.state = 0x%08x\n", + hif->napi_data.state); + NAPI_DEBUG("hif->napi_data.ce_map = 0x%08x\n", + hif->napi_data.ce_map); + + napid = &(hif->napi_data); + if (0 == (napid->state & HIF_NAPI_INITED)) { + memset(napid, 0, sizeof(struct qca_napi_data)); + mutex_init(&(napid->mutex)); + + init_dummy_netdev(&(napid->netdev)); + + napid->state |= HIF_NAPI_INITED; + HIF_INFO("%s: NAPI structures initialized\n", __func__); + + NAPI_DEBUG("NAPI structures initialized\n"); + } + napii = &(napid->napis[pipe_id]); + memset(napii, 0, sizeof(struct qca_napi_info)); + napii->scale = scale; + napii->id = NAPI_PIPE2ID(pipe_id); + + NAPI_DEBUG("adding napi=%p to netdev=%p (poll=%p, bdgt=%d)\n", + &(napii->napi), &(napid->netdev), poll, budget); + netif_napi_add(&(napid->netdev), &(napii->napi), poll, budget); + + NAPI_DEBUG("after napi_add\n"); + NAPI_DEBUG("napi=0x%p, netdev=0x%p\n", + &(napii->napi), &(napid->netdev)); + NAPI_DEBUG("napi.dev_list.prev=0x%p, next=0x%p\n", + napii->napi.dev_list.prev, napii->napi.dev_list.next); + NAPI_DEBUG("dev.napi_list.prev=0x%p, next=0x%p\n", + napid->netdev.napi_list.prev, napid->netdev.napi_list.next); + + /* It is OK to change the state variable below without protection + as there should be no-one around yet */ + napid->ce_map |= (0x01 << pipe_id); + HIF_INFO("%s: NAPI id %d created for pipe %d\n", __func__, + napii->id, pipe_id); + + NAPI_DEBUG("NAPI id %d created for pipe %d\n", napii->id, pipe_id); + NAPI_DEBUG("<--napi_id=%d]\n", napii->id); + return napii->id; +} + +/** + * + * hif_napi_destroy() - destroys the NAPI structures for a given instance + * @hif : pointer to hif context + * @ce_id : the CE id whose napi instance will be destroyed + * @force : if set, will destroy even if entry is active (de-activates) + * + * Description: + * Destroy a given NAPI instance. This function is called + * unconditionally during cleanup. + * Refuses to destroy an entry of it is still enabled (unless force=1) + * Marks the whole napi_data invalid if all instances are destroyed. + * + * Return: + * -EINVAL: specific entry has not been created + * -EPERM : specific entry is still active + * 0 < : error + * 0 = : success + */ +int hif_napi_destroy(struct ol_softc *hif, + uint8_t id, + int force) +{ + uint8_t ce = NAPI_ID2PIPE(id); + int rc = 0; + + NAPI_DEBUG("-->(id=%d, force=%d)\n", id, force); + + if (0 == (hif->napi_data.state & HIF_NAPI_INITED)) { + HIF_ERROR("%s: NAPI not initialized or entry %d not created\n", + __func__, id); + rc = -EINVAL; + } else if (0 == (hif->napi_data.ce_map & (0x01 << ce))) { + HIF_ERROR("%s: NAPI instance %d (pipe %d) not created\n", + __func__, id, ce); + rc = -EINVAL; + } else { + struct qca_napi_data *napid; + struct qca_napi_info *napii; + napid = &(hif->napi_data); + napii = &(napid->napis[ce]); + + if (hif->napi_data.state == HIF_NAPI_CONF_UP) { + if (force) { + napi_disable(&(napii->napi)); + HIF_INFO("%s: NAPI entry %d force disabled\n", + __func__, id); + NAPI_DEBUG("NAPI %d force disabled\n", id); + } else { + HIF_ERROR("%s: Cannot destroy active NAPI %d\n", + __func__, id); + rc = -EPERM; + } + } + if (0 == rc) { + NAPI_DEBUG("before napi_del\n"); + NAPI_DEBUG("napi.dlist.prv=0x%p, next=0x%p\n", + napii->napi.dev_list.prev, + napii->napi.dev_list.next); + NAPI_DEBUG("dev.napi_l.prv=0x%p, next=0x%p\n", + napid->netdev.napi_list.prev, + napid->netdev.napi_list.next); + + netif_napi_del(&(napii->napi)); + + napid->ce_map &= ~(0x01 << ce); + napii->scale = 0; + HIF_INFO("%s: NAPI %d destroyed\n", __func__, id); + + /* if there are no active instances and + if they are all destroyed, + set the whole structure to uninitialized state */ + if (napid->ce_map == 0) { + /* hif->napi_data.state = 0; */ + memset(napid, + 0, sizeof(struct qca_napi_data)); + HIF_INFO("%s: no NAPI instances. Zapped.\n", + __func__); + } + } + } + + return rc; +} + +/** + * + * hif_napi_get_all() - returns the address of the whole HIF NAPI structure + * @hif: pointer to hif context + * + * Description: + * Returns the address of the whole structure + * + * Return: + * : address of the whole HIF NAPI structure + */ +inline struct qca_napi_data *hif_napi_get_all(struct ol_softc *hif) +{ + return &(hif->napi_data); +} + +/** + * + * hif_napi_event() - Decision-maker to enable/disable NAPI. + * @hif : pointer to hif context + * @evnt: event that has been detected + * @data: more data regarding the event + * + * Description: + * This function decides whether or not NAPI should be enabled. + * NAPI will be enabled, if all the following is satisfied. + * 1- has been enabled administratively: + * the .ini file has the enabled setting and it has not been disabled + * by an vendor command override later + * + * Return: + * < 0: some error + * = 0: NAPI is now disabled + * = 1: NAPI is now enabled + */ +int hif_napi_event(struct ol_softc *hif, enum qca_napi_event event, void *data) +{ + int rc; + uint32_t prev_state; + int i; + struct napi_struct *napi; + + NAPI_DEBUG("-->(event=%d, aux=%p)\n", event, data); + + mutex_lock(&(hif->napi_data.mutex)); + prev_state = hif->napi_data.state; + switch (event) { + case NAPI_EVT_INI_FILE: + case NAPI_EVT_CMD_STATE: { + int on = (data != ((void *)0)); + HIF_INFO("%s: received evnt: CONF %s; v = %d (state=0x%0x)\n", + __func__, + (event == NAPI_EVT_INI_FILE)?".ini file":"cmd", + on, prev_state); + if (on) + if (prev_state & HIF_NAPI_CONF_UP) { + HIF_INFO("%s: duplicate NAPI conf ON msg\n", + __func__); + } else { + HIF_INFO("%s: setting configuration to ON\n", + __func__); + hif->napi_data.state |= HIF_NAPI_CONF_UP; + } + else /* off request */ + if (prev_state & HIF_NAPI_CONF_UP) { + HIF_INFO("%s: setting configuration to OFF\n", + __func__); + hif->napi_data.state &= ~HIF_NAPI_CONF_UP; + } else { + HIF_INFO("%s: duplicate NAPI conf OFF msg\n", + __func__); + } + break; + } + /* case NAPI_INIT_FILE/CMD_STATE */ + default: { + HIF_ERROR("%s: unknown event: %d (data=0x%0lx)\n", + __func__, event, (unsigned long) data); + break; + } /* default */ + }; /* switch */ + + + mutex_unlock(&(hif->napi_data.mutex)); + + if (prev_state != hif->napi_data.state) { + if (hif->napi_data.state == ENABLE_NAPI_MASK) { + rc = 1; + for (i = 0; i < CE_COUNT_MAX; i++) + if ((hif->napi_data.ce_map & (0x01 << i))) { + napi = &(hif->napi_data.napis[i].napi); + NAPI_DEBUG("enabling NAPI %d\n", i); + napi_enable(napi); + } + } else { + rc = 0; + for (i = 0; i < CE_COUNT_MAX; i++) + if (hif->napi_data.ce_map & (0x01 << i)) { + napi = &(hif->napi_data.napis[i].napi); + NAPI_DEBUG("disabling NAPI %d\n", i); + napi_disable(napi); + } + } + } else { + HIF_INFO("%s: no change in hif napi state (still %d)\n", + __func__, prev_state); + rc = (hif->napi_data.state == ENABLE_NAPI_MASK); + } + + NAPI_DEBUG("<--[rc=%d]\n", rc); + return rc; +} + +/** + * hif_napi_enabled() - checks whether NAPI is enabled for given ce or not + * @hif: hif context + * @ce : CE instance (or -1, to check if any CEs are enabled) + * + * Return: bool + */ +inline int hif_napi_enabled(struct ol_softc *hif, int ce) +{ + int rc; + if (-1 == ce) + rc = ((hif->napi_data.state == ENABLE_NAPI_MASK)); + else + rc = ((hif->napi_data.state == ENABLE_NAPI_MASK) && + (hif->napi_data.ce_map & (0x01 << ce))); + return rc; +}; + +/** + * hif_napi_enable_irq() - enables bus interrupts after napi_complete + * + * @hif: hif context + * @id : id of NAPI instance calling this (used to determine the CE) + * + * Return: void + */ +inline void hif_napi_enable_irq(struct ol_softc *hif, int id) +{ + ce_irq_enable(hif, NAPI_ID2PIPE(id)); + return; +} + + +/** + * hif_napi_schedule() - schedules napi, updates stats + * @scn: hif context + * @ce_id: index of napi instance + * + * Return: void + */ +int hif_napi_schedule(struct ol_softc *scn, int ce_id) +{ + int cpu = smp_processor_id(); + + scn->napi_data.napis[ce_id].stats[cpu].napi_schedules++; + NAPI_DEBUG("scheduling napi %d (ce:%d)\n", + scn->napi_data.napis[ce_id].id, ce_id); + napi_schedule(&(scn->napi_data.napis[ce_id].napi)); + + return true; +} + +/** + * hif_napi_poll() - NAPI poll routine + * @napi : pointer to NAPI struct as kernel holds it + * @budget: + * + * This is the body of the poll function. + * The poll function is called by kernel. So, there is a wrapper + * function in HDD, which in turn calls this function. + * Two main reasons why the whole thing is not implemented in HDD: + * a) references to things like ce_service that HDD is not aware of + * b) proximity to the implementation of ce_tasklet, which the body + * of this function should be very close to. + * + * NOTE TO THE MAINTAINER: + * Consider this function and ce_tasklet very tightly coupled pairs. + * Any changes to ce_tasklet or this function may likely need to be + * reflected in the counterpart. + * + * Returns: + * int: the amount of work done in this poll ( <= budget) + */ +int hif_napi_poll(struct napi_struct *napi, int budget) +{ + int rc, normalized, bucket; + int cpu = smp_processor_id(); + struct ol_softc *hif; + struct qca_napi_info *napi_info; + + NAPI_DEBUG("%s -->(.., budget=%d)\n", budget); + + napi_info = (struct qca_napi_info *) + container_of(napi, struct qca_napi_info, napi); + napi_info->stats[cpu].napi_polls++; + + hif = (struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF); + CDF_ASSERT(hif != NULL); + rc = ce_per_engine_service(hif, NAPI_ID2PIPE(napi_info->id)); + HIF_INFO_HI("%s: ce_per_engine_service reports %d msgs processed", + __func__, rc); + napi_info->stats[cpu].napi_workdone += rc; + normalized = (rc / napi_info->scale); + /* do not return 0, if there was some work done, + even if it is below the scale */ + if (rc) + normalized++; + bucket = (normalized / QCA_NAPI_DEF_SCALE); + napi_info->stats[cpu].napi_budget_uses[bucket]++; + + /* if ce_per engine reports 0, then we should make sure + poll is terminated */ + if (0 == rc) + NAPI_DEBUG("%s:%d: nothing processed by CE. Completing NAPI\n", + __func__, __LINE__); + + if (rc <= HIF_NAPI_MAX_RECEIVES) { + napi_info->stats[cpu].napi_completes++; + /* enable interrupts */ + napi_complete(napi); + hif_napi_enable_irq(hif, napi_info->id); + + /* support suspend/resume */ + cdf_atomic_dec(&(hif->active_tasklet_cnt)); + + NAPI_DEBUG("%s:%d: napi_complete + enabling the interrupts\n", + __func__, __LINE__); + } + + NAPI_DEBUG("%s <--[normalized=%d]\n", _func__, normalized); + return normalized; +} diff --git a/core/hif/src/icnss_stub/icnss_stub.c b/core/hif/src/icnss_stub/icnss_stub.c new file mode 100644 index 0000000000..956b456940 --- /dev/null +++ b/core/hif/src/icnss_stub/icnss_stub.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef HIF_PCI + +#include "icnss_stub.h" +#include "hif_io32.h" +#include +#include "regtable.h" +#include "hif_debug.h" +#include "cds_api.h" +#include "cdf_status.h" +#include "qwlan_version.h" +#include + +static int icnss_get_irq_num(int ce_id); + +/** + * struct icnss_stub_entry + * + * @irq_handler: irq_handler + * @data: data + * @name: name + * @ce_id: ce_id + */ +struct icnss_stub_entry { + irqreturn_t (*irq_handler)(int, void *); + void *data; + const char *name; + int ce_id; +}; + +/** + * struct icnss_stub_context + * + * @stub: icnss_stub_entry + * @regged_irq: regged_irq + */ +struct icnss_stub_context { + struct icnss_stub_entry stub[ICNSS_MAX_IRQ_REGISTRATIONS]; + uint32_t regged_irq; +}; + +static struct icnss_stub_context cnss_stub; + +#ifndef QCA_WIFI_3_0_ADRASTEA +/** + * icnss_wlan_enable() - icnss_wlan_enable + * @config: ce configuration information + * @mode: driver_mode + * @host_version: version string to send to the fw + * + * Return: int + */ +int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, + enum icnss_driver_mode mode, const char *host_version) +{ + return 0; +} + +/** + * icnss_wlan_disable() - icnss_wlan_disable + * @mode: driver_mode + * + * Return: int + */ +int icnss_wlan_disable(enum icnss_driver_mode mode) +{ + return 0; +} + +#else + +/** + * icnss_wlan_enable(): call the platform driver to enable wlan + * @config: ce configuration information + * @mode: driver_mode + * @host_version: version string to send to the fw + * + * This function passes the con_mode and CE configuration to + * platform driver to enable wlan. + * cnss_wlan_enable has been hacked to do a qmi handshake with fw. + * this is not needed for rome. + * + * Return: 0 on success, error number otherwise. + */ +int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, + enum icnss_driver_mode mode, const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *) + config->ce_svc_cfg; + + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + + switch (mode) { + case ICNSS_FTM: + cnss_mode = CNSS_FTM; + break; + case ICNSS_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_wlan_enable(&cfg, cnss_mode, host_version); +} + +/** + * icnss_wlan_disable(): call the platform driver to disable wlan + * + * This function passes the con_mode to platform driver to disable wlan. + * cnss_wlan_disable has been hacked to do a qmi handshake with fw. + * this is not needed for rome. + * + * Return: void + */ +int icnss_wlan_disable(enum icnss_driver_mode con_mode) +{ + enum cnss_driver_mode mode; + + switch (con_mode) { + case ICNSS_FTM: + mode = CNSS_FTM; + break; + case ICNSS_EPPING: + mode = CNSS_EPPING; + break; + default: + mode = CNSS_MISSION; + break; + } + + cnss_wlan_disable(mode); + return 0; +} +#endif + +/** + * icnss_ce_request_irq() - register an irq handler + * @ce_id: ce_id + * @handler: handler + * @flags: flags to pass to the kernel api + * @name: name + * @context: context to pass to the irq handler + * + * Return: integer status + */ +int icnss_ce_request_irq(int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, + void *context) +{ + if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) { + HIF_ERROR("%s: invalid ce_id = %d", __func__, ce_id); + return -EINVAL; + } + + cnss_stub.stub[ce_id].irq_handler = handler; + cnss_stub.stub[ce_id].ce_id = ce_id; + cnss_stub.stub[ce_id].data = context; + cnss_stub.stub[ce_id].name = name; + cnss_stub.regged_irq |= (1 << ce_id); + return 0; +} + +/** + * icnss_ce_free_irq() - icnss_unregister_irq + * @ce_id: the ce_id that the irq belongs to + * @context: context with witch the irq was requested. + * Return: integer status + */ +int icnss_ce_free_irq(int ce_id, void *context) +{ + if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) { + HIF_ERROR("%s: invalid ce_id = %d", __func__, ce_id); + return -EINVAL; + } + + if (cnss_stub.stub[ce_id].data != context) { + HIF_ERROR("%s: context match failure for ce_id %d", + __func__, ce_id); + return -EINVAL; + } + + if (cnss_stub.regged_irq & (1 << ce_id)) { + cnss_stub.stub[ce_id].irq_handler = NULL; + cnss_stub.stub[ce_id].ce_id = 0; + cnss_stub.stub[ce_id].data = 0; + cnss_stub.stub[ce_id].name = NULL; + cnss_stub.regged_irq &= ~(1 << ce_id); + } + return 0; +} + +/** + * icnss_dispatch_one_ce_irq() - icnss_dispatch_one_ce_irq + * @ce_id: ce_id + * + * Return: irqreturn_t + */ +static irqreturn_t icnss_dispatch_one_ce_irq(int ce_id) +{ + irqreturn_t ret = IRQ_NONE; + + if (cnss_stub.stub[ce_id].irq_handler) + ret = cnss_stub.stub[ce_id].irq_handler( + icnss_get_irq_num(ce_id), + (void *)cnss_stub.stub[ce_id].data); + else + HIF_ERROR( + "%sd: error - ce_id = %d, no IRQ handler", + __func__, ce_id); + + return ret; +} + +/** + * icnss_dispatch_ce_irq() - icnss_dispatch_ce_irq + * @scn: scn + * + * Return: N/A + */ +void icnss_dispatch_ce_irq(struct ol_softc *scn) +{ + uint32_t intr_summary; + int id; + irqreturn_t ret; + + if (scn->hif_init_done != true) + return; + + A_TARGET_ACCESS_BEGIN(scn); + intr_summary = CE_INTERRUPT_SUMMARY(scn); + + if (intr_summary == 0) { + if ((scn->target_status != OL_TRGET_STATUS_RESET) && + (!cdf_atomic_read(&scn->link_suspended))) { + + hif_write32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + + hif_read32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + } + A_TARGET_ACCESS_END(scn); + return; + } else { + A_TARGET_ACCESS_END(scn); + } + + scn->ce_irq_summary = intr_summary; + for (id = 0; intr_summary && (id < scn->ce_count); id++) { + if (intr_summary & (1 << id)) { + intr_summary &= ~(1 << id); + ret = icnss_dispatch_one_ce_irq(id); + } + } +} + +/** + * icnss_get_soc_info() - get soc info + * + * This function query the soc information from the platform + * driver + * + * @info: struct icnss_soc_info + * + * Return: 0 for success + */ +int icnss_get_soc_info(struct icnss_soc_info *info) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + + if (!scn) { + HIF_ERROR("%s: SCN = NULL", __func__); + return -EINVAL; + } + info->v_addr = scn->mem; + info->p_addr = scn->mem_pa; + info->version = 0; + return 0; +} + + +/* icnss_get_irq_num() - generate a number to represent an irq number +*/ +static int icnss_get_irq_num(int ce_id) +{ + if (ce_id <= ICNSS_MAX_IRQ_REGISTRATIONS && ce_id >= 0) + return ce_id + 100; + + pr_err("icnss: No irq registered for CE id %d\n", ce_id); + return -EINVAL; +} + +int icnss_get_ce_id(int irq) +{ + int ce_id = irq - 100; + if (ce_id <= ICNSS_MAX_IRQ_REGISTRATIONS && ce_id >= 0) + return ce_id; + + pr_err("icnss: No matching CE id for irq %d\n", irq); + return -EINVAL; +} +#endif /* HIF_PCI */ diff --git a/core/hif/src/icnss_stub/icnss_stub.h b/core/hif/src/icnss_stub/icnss_stub.h new file mode 100644 index 0000000000..bce229a2db --- /dev/null +++ b/core/hif/src/icnss_stub/icnss_stub.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef HIF_PCI +#ifndef _ICNSS_WLAN_H_ +#define _ICNSS_WLAN_H_ + +#include +#include +#include + +#define ICNSS_MAX_IRQ_REGISTRATIONS 12 + +/** + * struct ce_tgt_pipe_cfg + * + * @pipenum: pipe_num + * @pipedir: pipe_dir + * @nentries: nentries + * @nbytes_max: nbytes_max + * @flags: flags + * @reserved: reserved + */ +struct ce_tgt_pipe_cfg { + uint32_t pipe_num; + uint32_t pipe_dir; + uint32_t nentries; + uint32_t nbytes_max; + uint32_t flags; + uint32_t reserved; +}; + +/** + * struct ce_svc_pipe_cfg + * + * @service_id: service_id + * @pipedir: pipedir + * @pipenum: pipenum + */ +struct ce_svc_pipe_cfg { + uint32_t service_id; + uint32_t pipedir; + uint32_t pipenum; +}; + +/** + * struct icnss_shadow_reg_cfg + * + * @ce_id: Copy engine id + * @reg_offset: Register offset + */ +struct icnss_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; +/** + * struct icnss_wlan_enable_cfg + * + * @num_ce_tgt_cfg: num_ce_tgt_cfg + * @ce_tgt_cfg: ce_tgt_cfg + * @num_ce_svc_pipe_cfg: num_ce_svc_pipe_cfg + * @ce_svc_cfg: ce_svc_cfg + */ +struct icnss_wlan_enable_cfg { + uint32_t num_ce_tgt_cfg; + struct ce_tgt_pipe_cfg *ce_tgt_cfg; + uint32_t num_ce_svc_pipe_cfg; + struct ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct icnss_shadow_reg_cfg *shadow_reg_cfg; +}; + +/** + * enum driver_mode + * + * @driver_mode: driver_mode + */ +enum icnss_driver_mode { + ICNSS_MISSION, + ICNSS_FTM, + ICNSS_EPPING, +}; + +/** + * struct icnss_soc_info + * + * @v_addr: virtual address + * @p_addr: physical address + * @ver: version + */ +struct icnss_soc_info { + void __iomem *v_addr; + phys_addr_t p_addr; + uint32_t version; +}; + +int icnss_wlan_enable(struct icnss_wlan_enable_cfg *config, + enum icnss_driver_mode mode, const char *host_version); +int icnss_wlan_disable(enum icnss_driver_mode mode); +int icnss_ce_request_irq(int ce_id, + irqreturn_t (*handler)(int ce_id, void *arg), + unsigned long flags, const char *name, void *context); +int icnss_ce_free_irq(int irq, void *context); +void icnss_enable_irq(unsigned int ce_id); +void icnss_disable_irq(unsigned int ce_id); +int icnss_get_soc_info(struct icnss_soc_info *info); +int icnss_get_ce_id(int irq); +#endif /* _ICNSS_WLAN_H_ */ +#endif /* HIF_PCI */ + diff --git a/core/hif/src/mp_dev.c b/core/hif/src/mp_dev.c new file mode 100644 index 0000000000..276e60ae1a --- /dev/null +++ b/core/hif/src/mp_dev.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "hif_io32.h" +#include "hif_debug.h" + +/*chaninfo*/ +#define CHANINFOMEM_S2_READ_MASK 0x00000008 +#define CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK 0x00000001 +#define CHANINFO_CTRL_CHANINFOMEM_BW_MASK 0x00000030 +#define MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK 0x00000007 + +/*agc*/ +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK 0x00040000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK 0x00080000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK 0x00100000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK 0x00200000 +#define AGC_HISTORY_DUMP_MASK (\ + GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK \ + ) + +#define BB_chaninfo_ctrl 0x1a370 +#define BB_multichain_enable 0x1a2a0 +#define BB_chn_tables_intf_addr 0x19894 +#define BB_chn1_tables_intf_addr 0x1a894 +#define BB_chn_tables_intf_data 0x19898 +#define BB_chn1_tables_intf_data 0x1a898 +#define BB_gains_min_offsets 0x19e08 +#define BB_chaninfo_tab_b0 0x03200 +#define BB_chaninfo_tab_b1 0x03300 +#define BB_watchdog_status 0x1a7c0 +#define BB_watchdog_ctrl_1 0x1a7c4 +#define BB_watchdog_ctrl_2 0x1a7c8 +#define BB_watchdog_status_B 0x1a7e0 + +struct priv_ctrl_ctx { + uint32_t chaninfo_ctrl_orig; + uint32_t gain_min_offsets_orig; + uint32_t anyreg_start; + uint32_t anyreg_len; +}; + +static struct priv_ctrl_ctx g_priv_dump_ctx; + +static INLINE void set_target_reg_bits(void __iomem *mem, uint32_t reg, + uint32_t bitmask, uint32_t val) +{ + uint32_t value = hif_read32_mb(mem + (reg)); + uint32_t shift = 0; + value &= ~(bitmask); + while (!((bitmask >> shift) & 0x01)) + shift++; + + value |= (((val) << shift) & (bitmask)); + hif_write32_mb(mem + (reg), value); +} + +static INLINE uint32_t get_target_reg_bits(void __iomem *mem, + uint32_t reg, uint32_t bitmask) +{ + uint32_t value = hif_read32_mb(mem + (reg)); + uint32_t shift = 0; + while (!((bitmask >> shift) & 0x01)) + shift++; + + return (value >> shift) & bitmask; +} + +void priv_start_cap_chaninfo(struct ol_softc *scn) +{ + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK, 1); +} + +void priv_start_agc(struct ol_softc *scn) +{ + g_priv_dump_ctx.gain_min_offsets_orig = + hif_read32_mb(scn->mem + BB_gains_min_offsets); + set_target_reg_bits(scn->mem, BB_gains_min_offsets, + AGC_HISTORY_DUMP_MASK, + 0x0f); +} + +void priv_stop_agc(struct ol_softc *scn) +{ + set_target_reg_bits(scn->mem, BB_gains_min_offsets, + AGC_HISTORY_DUMP_MASK, + 0); +} + +void priv_dump_chaninfo(struct ol_softc *scn) +{ + uint32_t bw, val; + uint32_t len, i, tmp; + uint32_t chain_mask; + uint32_t chain0, chain1; + + chain_mask = + get_target_reg_bits(scn->mem, BB_multichain_enable, + MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK); + chain0 = chain_mask & 1; + chain1 = chain_mask & 2; + + HIF_TRACE("%s: E", __func__); + bw = get_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFO_CTRL_CHANINFOMEM_BW_MASK); + + if (bw == 0) + len = 53; + else if (bw == 1) + len = 57; + else if (bw == 2) + len = 59 * 2 - 1; + else + len = 60 * 2 + 61 * 2; + + /* + * each tone is 16 bit valid, write to 32bit buffer each. + * bw==0(legacy20): 53 tones. + * bw==1(ht/vht20): 57 tones. + * bw==2(ht/vht40): 59+58 tones. + * bw==3(vht80): 60*2+61*2 tones. + */ + + if (chain0) { + hif_write32_mb(scn->mem + BB_chn_tables_intf_addr, + 0x80003200); + } + if (chain1) { + hif_write32_mb(scn->mem + BB_chn1_tables_intf_addr, + 0x80003200); + } + + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFOMEM_S2_READ_MASK, 0); + + if (chain0) { + if (bw < 2) { + len = (bw == 0) ? 53 : 57; + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data) & + 0x0000ffff; + cdf_print("0x%x\t", val); + if (i % 4 == 0) + cdf_print("\n"); + } + } else { + len = (bw == 2) ? 59 : 60; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data); + cdf_print("0x%x\t", ((tmp >> 16) & 0x0000ffff)); + cdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + cdf_print("\n"); + } + if (bw > 2) { + /* bw == 3 for vht80 */ + hif_write32_mb(scn->mem + + BB_chn_tables_intf_addr, + 0x80003300); + len = 61; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data); + cdf_print("0x%x\t", + ((tmp >> 16) & 0x0000ffff)); + cdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + cdf_print("\n"); + } + } + } + } + if (chain1) { + if (bw < 2) { + len = (bw == 0) ? 53 : 57; + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data) & + 0x0000ffff; + cdf_print("0x%x\t", val); + if (i % 4 == 0) + cdf_print("\n"); + } + } else { + len = (bw == 2) ? 59 : 60; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data); + cdf_print("0x%x\n", (tmp >> 16) & 0x0000ffff); + cdf_print("0x%x\n", tmp & 0x0000ffff); + if (i % 2 == 0) + cdf_print("\n"); + } + if (bw > 2) { + /* bw == 3 for vht80 */ + hif_write32_mb(scn->mem + + BB_chn1_tables_intf_addr, + 0x80003300); + len = 61; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data); + cdf_print("0x%x\t", + ((tmp >> 16) & 0x0000ffff)); + cdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + cdf_print("\n"); + } + } + } + } + HIF_TRACE("%s: X", __func__); +} + +void priv_dump_agc(struct ol_softc *scn) +{ + int i, len = 30; /* check this value for Rome and Peregrine */ + uint32_t chain0, chain1, chain_mask, val; + + chain_mask = + get_target_reg_bits(scn->mem, BB_multichain_enable, + MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK); + chain0 = chain_mask & 1; + chain1 = chain_mask & 2; + + len = len << 1; /* each agc item is 64bit, total*2 */ + priv_stop_agc(scn); + + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFOMEM_S2_READ_MASK, 0); + + HIF_TRACE("%s: AGC history buffer dump: E", __func__); + if (chain0) { + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + BB_chaninfo_tab_b0 + + i * 4); + cdf_print("0x%x\t", val); + if (i % 4 == 0) + cdf_print("\n"); + } + } + if (chain1) { + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + BB_chaninfo_tab_b1 + + i * 4); + cdf_print("0x%x\t", val); + if (i % 4 == 0) + cdf_print("\n"); + } + } + HIF_TRACE("%s: AGC history buffer dump X", __func__); + /* restore original value */ + hif_write32_mb(scn->mem + BB_gains_min_offsets, + g_priv_dump_ctx.gain_min_offsets_orig); + return; +} + +void priv_dump_bbwatchdog(struct ol_softc *scn) +{ + uint32_t val; + + HIF_TRACE("%s: BB watchdog dump E", __func__); + val = hif_read32_mb(scn->mem + BB_watchdog_status); + cdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_ctrl_1); + cdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_ctrl_2); + cdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_status_B); + cdf_print("0x%x", val); + HIF_TRACE("%s: BB watchdog dump X", __func__); +} diff --git a/core/hif/src/mp_dev.h b/core/hif/src/mp_dev.h new file mode 100644 index 0000000000..cb7e3d06ec --- /dev/null +++ b/core/hif/src/mp_dev.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __MP_DEV_H__ +#define __MP_DEV_H__ +void priv_start_agc(struct ol_softc *scn); +void priv_dump_agc(struct ol_softc *scn); +void priv_start_cap_chaninfo(struct ol_softc *scn); +void priv_dump_chaninfo(struct ol_softc *scn); +void priv_dump_bbwatchdog(struct ol_softc *scn); +void hif_shut_down_device(struct ol_softc *scn); +#endif /* __MP_DEV_H__ */ diff --git a/core/hif/src/pcie/cnss_stub.h b/core/hif/src/pcie/cnss_stub.h new file mode 100644 index 0000000000..64ab19e535 --- /dev/null +++ b/core/hif/src/pcie/cnss_stub.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CNSS_STUB_H__ +#define __CNSS_STUB_H__ + +#ifndef CONFIG_CNSS +inline void cnss_wlan_pci_link_down(void) {} + +inline int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable) +{ + return 0; +} + +#endif +#endif /* __CNSS_STUB_H__ */ diff --git a/core/hif/src/pcie/hif_io32_pci.h b/core/hif/src/pcie/hif_io32_pci.h new file mode 100644 index 0000000000..3ffa30da03 --- /dev/null +++ b/core/hif/src/pcie/hif_io32_pci.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_IO32_PCI_H__ +#define __HIF_IO32_PCI_H__ + +#ifdef HIF_PCI + +#include "hif.h" +#include "regtable.h" +#include "ce_reg.h" +#include "cdf_atomic.h" +#include "if_pci.h" +/* + * For maximum performance and no power management, set this to 1. + * For power management at the cost of performance, set this to 0. + */ +#define CONFIG_ATH_PCIE_MAX_PERF 0 + +/* + * For keeping the target awake till the driver is + * loaded, set this to 1 + */ +#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD 1 + +/* + * When CONFIG_ATH_PCIE_MAX_PERF is 0: + * To use LIKELY hints, set this to 1 (slightly better performance, more power) + * To ignore "LIKELY" hints, set this to 0 (slightly worse performance, + * less power) + */ +#if defined(CONFIG_ATH_PCIE_MAX_PERF) +#define CONFIG_ATH_PCIE_ACCESS_LIKELY 0 +#else +#define CONFIG_ATH_PCIE_ACCESS_LIKELY 1 +#endif + +/* + * PCI-E L1 ASPPM sub-states + * To enable clock gating in L1 state, set this to 1. + * (less power, slightly more wakeup latency) + * To disable clock gating in L1 state, set this to 0. (slighly more power) + */ +#define CONFIG_PCIE_ENABLE_L1_CLOCK_GATE 1 + +/* + * PCIE_ACCESS_LOG_NUM specifies the number of + * read/write records to store + */ +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_ACCESS_LOG_NUM 500 +#endif + +/* 64-bit MSI support */ +#define CONFIG_PCIE_64BIT_MSI 0 + +/* BAR0 ready checking for AR6320v2 */ +#define PCIE_BAR0_READY_CHECKING 0 + +/* AXI gating when L1, L2 to reduce power consumption */ +#define CONFIG_PCIE_ENABLE_AXI_CLK_GATE 0 + +#define hif_read32_mb(addr) ioread32((void __iomem *)addr) +#define hif_write32_mb(addr, value) \ + iowrite32((u32)(value), (void __iomem *)(addr)) + +extern int hif_target_sleep_state_adjust(struct ol_softc *scn, + bool sleep_ok, + bool wait_for_it); + +#if CONFIG_ATH_PCIE_MAX_PERF +#define A_TARGET_ACCESS_BEGIN(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_END(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_OK(scn) 1 + +#define A_TARGET_ACCESS_LIKELY(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_UNLIKELY(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_READ(scn, offset) \ + hif_read32_mb(scn->mem + (offset)) + +void war_pci_write32(char *addr, u32 offset, u32 value); +#define A_TARGET_WRITE(scn, offset, value) \ + war_pci_write32(scn->mem, (offset), (value)) + +#define A_TARGET_ACCESS_BEGIN_RET(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_BEGIN_RET_PTR(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_END_RET(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_END_RET_EXT(scn, val) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#define A_TARGET_ACCESS_END_RET_PTR(scn) \ + do {struct ol_softc *unused = scn; \ + unused = unused; } while (0) + +#else /* CONFIG_ATH_PCIE_MAX_PERF */ + +void war_pci_write32(char *addr, u32 offset, u32 value); + +#define A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_BEGIN(scn) < 0) \ + val = -1; \ +} while (0) + +#define A_TARGET_ACCESS_BEGIN_RET(scn) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_BEGIN(scn) < 0) \ + return ATH_ISR_NOSCHED; \ +} while (0) + +#define A_TARGET_ACCESS_BEGIN_RET_PTR(scn) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_BEGIN(scn) < 0) \ + return NULL; \ +} while (0) + +#define A_TARGET_ACCESS_BEGIN(scn) \ +do { \ + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) \ + return; \ +} while (0) + +#define Q_TARGET_ACCESS_BEGIN(scn) \ + hif_target_sleep_state_adjust(scn, false, true) + +#define A_TARGET_ACCESS_END_RET(scn) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_END(scn) < 0) \ + return ATH_ISR_NOSCHED; \ +} while (0) + +#define A_TARGET_ACCESS_END_RET_EXT(scn, val) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_END(scn) < 0) \ + val = -1; \ +} while (0) + +#define A_TARGET_ACCESS_END_RET_PTR(scn) \ +do { \ + if (!WLAN_IS_EPPING_ENABLED(cds_get_conparam()) && \ + Q_TARGET_ACCESS_END(scn) < 0) \ + return NULL; \ +} while (0) +#define A_TARGET_ACCESS_END(scn) \ +do { \ + if (Q_TARGET_ACCESS_END(scn) < 0) \ + return; \ +} while (0) + +#define Q_TARGET_ACCESS_END(scn) \ + hif_target_sleep_state_adjust(scn, true, false) + +#define A_TARGET_ACCESS_OK(scn) hif_target_forced_awake(scn) + +#if CONFIG_ATH_PCIE_ACCESS_LIKELY +#define A_TARGET_ACCESS_LIKELY(scn) \ + hif_target_sleep_state_adjust(scn, false, false) +#define A_TARGET_ACCESS_UNLIKELY(scn) \ + hif_target_sleep_state_adjust(scn, true, false) +#else /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ +#define A_TARGET_ACCESS_LIKELY(scn) \ + do { \ + unsigned long unused = (unsigned long)(scn); \ + unused = unused; \ + } while (0) + +#define A_TARGET_ACCESS_UNLIKELY(scn) \ + do { \ + unsigned long unused = (unsigned long)(scn); \ + unused = unused; \ + } while (0) +#endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +extern uint32_t hif_target_read_checked(struct ol_softc *scn, + uint32_t offset); +extern void hif_target_write_checked(struct ol_softc *scn, uint32_t offset, + uint32_t value); +#define A_TARGET_READ(scn, offset) \ + hif_target_read_checked(scn, (offset)) +#define A_TARGET_WRITE(scn, offset, value) \ + hif_target_write_checked(scn, (offset), (value)) +#else /* CONFIG_ATH_PCIE_ACCESS_DEBUG */ +#define A_TARGET_READ(scn, offset) \ + hif_read32_mb(scn->mem + (offset)) +#define A_TARGET_WRITE(scn, offset, value) \ + war_pci_write32(scn->mem, (offset), (value)) +#endif +#endif /* CONFIG_ATH_PCIE_MAX_PERF */ + +/** + * ce_irq_enable() - ce_irq_enable + * @scn: ol_softc + * @ce_id: ce_id + * + * Return: void + */ +static inline void ce_irq_enable(struct ol_softc *scn, int ce_id) +{ + uint32_t tmp = 1 << ce_id; + struct hif_pci_softc *sc = scn->hif_sc; + + cdf_spin_lock_irqsave(&scn->irq_lock); + scn->ce_irq_summary &= ~tmp; + if (scn->ce_irq_summary == 0) { + /* Enable Legacy PCI line interrupts */ + if (LEGACY_INTERRUPTS(sc) && + (scn->target_status != OL_TRGET_STATUS_RESET) && + (!cdf_atomic_read(&scn->link_suspended))) { + + hif_write32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + + hif_read32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + } + } + if (scn->hif_init_done == true) + A_TARGET_ACCESS_END(scn); + cdf_spin_unlock_irqrestore(&scn->irq_lock); +} +/** + * ce_irq_disable() - ce_irq_disable + * @scn: ol_softc + * @ce_id: ce_id + * + * Return: void + */ +static inline void ce_irq_disable(struct ol_softc *scn, int ce_id) +{ + /* For Rome only need to wake up target */ + A_TARGET_ACCESS_BEGIN(scn); +} +/** + * soc_wake_reset() - soc_wake_reset + * @scn: ol_softc + * + * Return: void + */ +static inline void soc_wake_reset(struct ol_softc *scn) +{ + hif_write32_mb(scn->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); +} +#endif /* HIF_PCI */ +#endif /* __HIF_IO32_PCI_H__ */ diff --git a/core/hif/src/pcie/if_pci.c b/core/hif/src/pcie/if_pci.c new file mode 100644 index 0000000000..6efb418ee8 --- /dev/null +++ b/core/hif/src/pcie/if_pci.c @@ -0,0 +1,2239 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#ifdef CONFIG_PCI_MSM +#include +#endif +#include "hif_io32.h" +#include "if_pci.h" +#include "hif.h" +#include "hif_main.h" +#include "ce_api.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "bmi_msg.h" /* TARGET_TYPE_ */ +#include "regtable.h" +#include "ol_fw.h" +#include +#include "cds_api.h" +#include "cdf_status.h" +#include "cds_sched.h" +#include "wma_api.h" +#include "cdf_atomic.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_main.h" +#ifdef CONFIG_CNSS +#include +#else +#include "cnss_stub.h" +#endif +#include "epping_main.h" +#include "mp_dev.h" +#include "hif_debug.h" + +#ifndef REMOVE_PKT_LOG +#include "ol_txrx_types.h" +#include "pktlog_ac_api.h" +#include "pktlog_ac.h" +#endif +#include "if_pci_internal.h" +#include "icnss_stub.h" +#include "ce_tasklet.h" + +/* Maximum ms timeout for host to wake up target */ +#define PCIE_WAKE_TIMEOUT 1000 +#define RAMDUMP_EVENT_TIMEOUT 2500 + +unsigned int msienable = 0; +module_param(msienable, int, 0644); + +int hif_pci_war1 = 0; +static DEFINE_SPINLOCK(pciwar_lock); + +#ifndef REMOVE_PKT_LOG +struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs = NULL; +#endif + +/* Setting SOC_GLOBAL_RESET during driver unload causes intermittent + * PCIe data bus error + * As workaround for this issue - changing the reset sequence to + * use TargetCPU warm reset * instead of SOC_GLOBAL_RESET + */ +#define CPU_WARM_RESET_WAR +/* + * Top-level interrupt handler for all PCI interrupts from a Target. + * When a block of MSI interrupts is allocated, this top-level handler + * is not used; instead, we directly call the correct sub-handler. + */ +struct ce_irq_reg_table { + uint32_t irq_enable; + uint32_t irq_status; +}; + +#if !defined(QCA_WIFI_3_0_IHELIUM) && !defined(QCA_WIFI_3_0_ADRASTEA) +static inline void cnss_intr_notify_q6(void) +{ +} +#endif + +#if !defined(QCA_WIFI_3_0_IHELIUM) && !defined(QCA_WIFI_3_0_ADRASTEA) +static inline void *cnss_get_target_smem(void) +{ + return NULL; +} +#endif + +void hif_pci_route_target_interrupt(struct hif_pci_softc *sc) +{ + uint32_t target_cause0, target_cause1, target_cause2; + uint32_t *target_smem; + struct ol_softc *scn = sc->ol_sc; + + target_smem = (uint32_t *)cnss_get_target_smem(); + if (!target_smem) + return; + + /* disable interrupts */ + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_0_ADDRESS, 0); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_1_ADDRESS, 0); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_2_ADDRESS, 0); + /* read cause */ + target_cause0 = hif_read32_mb(sc->mem + + A_SOC_CORE_SCRATCH_3_ADDRESS); + target_cause1 = hif_read32_mb(sc->mem + + A_SOC_CORE_SCRATCH_4_ADDRESS); + target_cause2 = hif_read32_mb(sc->mem + + A_SOC_CORE_SCRATCH_5_ADDRESS); + /* clear cause registers */ + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_3_ADDRESS, 0xffffffff); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_4_ADDRESS, 0xffffffff); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_5_ADDRESS, 0xffffffff); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_3_ADDRESS, 0); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_4_ADDRESS, 0); + hif_write32_mb(sc->mem + + A_SOC_CORE_SCRATCH_5_ADDRESS, 0); + /* copy cause value to Q6 */ + *target_smem = target_cause0; + *(target_smem + 1) = target_cause1; + *(target_smem + 2) = target_cause2; + if (scn->notice_send) + cnss_intr_notify_q6(); +} + +#ifndef QCA_WIFI_3_0_ADRASTEA +static inline void hif_pci_route_adrastea_interrupt(struct hif_pci_softc *sc) +{ + return; +} +#else +void hif_pci_route_adrastea_interrupt(struct hif_pci_softc *sc) +{ + struct ol_softc *scn = sc->ol_sc; + unsigned int target_enable0, target_enable1; + unsigned int target_cause0, target_cause1; + + target_enable0 = hif_read32_mb(sc->mem + Q6_ENABLE_REGISTER_0); + target_enable1 = hif_read32_mb(sc->mem + Q6_ENABLE_REGISTER_1); + target_cause0 = hif_read32_mb(sc->mem + Q6_CAUSE_REGISTER_0); + target_cause1 = hif_read32_mb(sc->mem + Q6_CAUSE_REGISTER_1); + + if ((target_enable0 & target_cause0) || + (target_enable1 & target_cause1)) { + hif_write32_mb(sc->mem + Q6_ENABLE_REGISTER_0, 0); + hif_write32_mb(sc->mem + Q6_ENABLE_REGISTER_1, 0); + + if (scn->notice_send) + cnss_intr_notify_q6(); + } +} +#endif + +static irqreturn_t hif_pci_interrupt_handler(int irq, void *arg) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)arg; + struct ol_softc *scn = sc->ol_sc; + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + volatile int tmp; + uint16_t val; + uint32_t bar0; + uint32_t fw_indicator_address, fw_indicator; + bool ssr_irq = false; + unsigned int host_cause, host_enable; + + if (LEGACY_INTERRUPTS(sc)) { + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return IRQ_HANDLED; + + if (ADRASTEA_BU) { + host_enable = hif_read32_mb(sc->mem + + PCIE_INTR_ENABLE_ADDRESS); + host_cause = hif_read32_mb(sc->mem + + PCIE_INTR_CAUSE_ADDRESS); + if (!(host_enable & host_cause)) { + hif_pci_route_adrastea_interrupt(sc); + return IRQ_HANDLED; + } + } + + /* Clear Legacy PCI line interrupts + * IMPORTANT: INTR_CLR regiser has to be set + * after INTR_ENABLE is set to 0, + * otherwise interrupt can not be really cleared */ + hif_write32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), 0); + if (IHELIUM_BU) { + if (!hif_read32_mb(sc->mem + PCIE_INTR_CAUSE_ADDRESS)) { + hif_pci_route_target_interrupt(sc); + + hif_write32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + + return IRQ_HANDLED; + } + } + + hif_write32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_CLR_ADDRESS), + ADRASTEA_BU ? + (host_enable & host_cause) : + HOST_GROUP0_MASK); + + if (ADRASTEA_BU) + hif_write32_mb(sc->mem + 0x2f100c , (host_cause >> 1)); + + /* IMPORTANT: this extra read transaction is required to + * flush the posted write buffer */ + if (!ADRASTEA_BU) { + tmp = + hif_read32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + + if (tmp == 0xdeadbeef) { + HIF_ERROR("BUG(%s): SoC returns 0xdeadbeef!!", + __func__); + + pci_read_config_word(sc->pdev, PCI_VENDOR_ID, &val); + HIF_ERROR("%s: PCI Vendor ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &val); + HIF_ERROR("%s: PCI Device ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, PCI_COMMAND, &val); + HIF_ERROR("%s: PCI Command = 0x%04x", __func__, + val); + + pci_read_config_word(sc->pdev, PCI_STATUS, &val); + HIF_ERROR("%s: PCI Status = 0x%04x", __func__, + val); + + pci_read_config_dword(sc->pdev, PCI_BASE_ADDRESS_0, + &bar0); + HIF_ERROR("%s: PCI BAR0 = 0x%08x", __func__, + bar0); + + HIF_ERROR("%s: RTC_STATE_ADDRESS = 0x%08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS)); + HIF_ERROR("%s: PCIE_SOC_WAKE_ADDRESS = 0x%08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + HIF_ERROR("%s: 0x80008 = 0x%08x, 0x8000c = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80008), + hif_read32_mb(sc->mem + 0x8000c)); + HIF_ERROR("%s: 0x80010 = 0x%08x, 0x80014 = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80010), + hif_read32_mb(sc->mem + 0x80014)); + HIF_ERROR("%s: 0x80018 = 0x%08x, 0x8001c = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80018), + hif_read32_mb(sc->mem + 0x8001c)); + CDF_BUG(0); + } + + PCI_CLR_CAUSE0_REGISTER(sc); + } + + if (HAS_FW_INDICATOR) { + fw_indicator_address = hif_state->fw_indicator_address; + fw_indicator = A_TARGET_READ(scn, fw_indicator_address); + if ((fw_indicator != ~0) && + (fw_indicator & FW_IND_EVENT_PENDING)) + ssr_irq = true; + } + + if (Q_TARGET_ACCESS_END(scn) < 0) + return IRQ_HANDLED; + } + /* TBDXXX: Add support for WMAC */ + + if (ssr_irq) { + sc->irq_event = irq; + cdf_atomic_set(&scn->tasklet_from_intr, 1); + + cdf_atomic_inc(&scn->active_tasklet_cnt); + tasklet_schedule(&sc->intr_tq); + } else { + icnss_dispatch_ce_irq(scn); + } + + return IRQ_HANDLED; +} + +static irqreturn_t hif_pci_msi_fw_handler(int irq, void *arg) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)arg; + + (irqreturn_t) hif_fw_interrupt_handler(sc->irq_event, sc->ol_sc); + + return IRQ_HANDLED; +} + +bool hif_targ_is_awake(struct ol_softc *scn, void *__iomem *mem) +{ + HIF_PCI_TARG_IS_AWAKE(scn, mem); +} + +bool hif_pci_targ_is_present(struct ol_softc *scn, void *__iomem *mem) +{ + return 1; /* FIX THIS */ +} + +/** + * hif_pci_cancel_deferred_target_sleep() - cancels the defered target sleep + * @scn: ol_softc + * + * Return: void + */ +#if CONFIG_ATH_PCIE_MAX_PERF == 0 +void hif_pci_cancel_deferred_target_sleep(struct ol_softc *scn) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)scn->hif_hdl; + A_target_id_t pci_addr = scn->mem; + + cdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + /* + * If the deferred sleep timer is running cancel it + * and put the soc into sleep. + */ + if (hif_state->fake_sleep == true) { + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + if (hif_state->verified_awake == false) { + hif_write32_mb(pci_addr + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); + } + hif_state->fake_sleep = false; + } + cdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); +} +#else +inline void hif_pci_cancel_deferred_target_sleep(struct ol_softc *scn) +{ + return; +} +#endif + +#define A_PCIE_LOCAL_REG_READ(mem, addr) \ + hif_read32_mb((char *)(mem) + \ + PCIE_LOCAL_BASE_ADDRESS + (uint32_t)(addr)) + +#define A_PCIE_LOCAL_REG_WRITE(mem, addr, val) \ + hif_write32_mb(((char *)(mem) + \ + PCIE_LOCAL_BASE_ADDRESS + (uint32_t)(addr)), (val)) + +#define ATH_PCI_RESET_WAIT_MAX 10 /* Ms */ +static void hif_pci_device_reset(struct hif_pci_softc *sc) +{ + void __iomem *mem = sc->mem; + int i; + uint32_t val; + struct ol_softc *scn = sc->ol_sc; + + if (!scn->hostdef) + return; + + /* NB: Don't check resetok here. This form of reset + * is integral to correct operation. */ + + if (!SOC_GLOBAL_RESET_ADDRESS) { + return; + } + + if (!mem) { + return; + } + + HIF_ERROR("%s: Reset Device", __func__); + + /* + * NB: If we try to write SOC_GLOBAL_RESET_ADDRESS without first + * writing WAKE_V, the Target may scribble over Host memory! + */ + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (hif_targ_is_awake(scn, mem)) + break; + + cdf_mdelay(1); + } + + /* Put Target, including PCIe, into RESET. */ + val = A_PCIE_LOCAL_REG_READ(mem, SOC_GLOBAL_RESET_ADDRESS); + val |= 1; + A_PCIE_LOCAL_REG_WRITE(mem, SOC_GLOBAL_RESET_ADDRESS, val); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (A_PCIE_LOCAL_REG_READ(mem, RTC_STATE_ADDRESS) & + RTC_STATE_COLD_RESET_MASK) + break; + + cdf_mdelay(1); + } + + /* Pull Target, including PCIe, out of RESET. */ + val &= ~1; + A_PCIE_LOCAL_REG_WRITE(mem, SOC_GLOBAL_RESET_ADDRESS, val); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (! + (A_PCIE_LOCAL_REG_READ(mem, RTC_STATE_ADDRESS) & + RTC_STATE_COLD_RESET_MASK)) + break; + + cdf_mdelay(1); + } + + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); +} + +/* CPU warm reset function + * Steps: + * 1. Disable all pending interrupts - so no pending interrupts on WARM reset + * 2. Clear the FW_INDICATOR_ADDRESS -so Traget CPU intializes FW + * correctly on WARM reset + * 3. Clear TARGET CPU LF timer interrupt + * 4. Reset all CEs to clear any pending CE tarnsactions + * 5. Warm reset CPU + */ +void hif_pci_device_warm_reset(struct hif_pci_softc *sc) +{ + void __iomem *mem = sc->mem; + int i; + uint32_t val; + uint32_t fw_indicator; + struct ol_softc *scn = sc->ol_sc; + + /* NB: Don't check resetok here. This form of reset is + * integral to correct operation. */ + + if (!mem) { + return; + } + + HIF_INFO_MED("%s: Target Warm Reset", __func__); + + /* + * NB: If we try to write SOC_GLOBAL_RESET_ADDRESS without first + * writing WAKE_V, the Target may scribble over Host memory! + */ + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (hif_targ_is_awake(scn, mem)) + break; + cdf_mdelay(1); + } + + /* + * Disable Pending interrupts + */ + val = + hif_read32_mb(mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_CAUSE_ADDRESS)); + HIF_INFO_MED("%s: Host Intr Cause reg 0x%x : value : 0x%x", __func__, + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_CAUSE_ADDRESS), val); + /* Target CPU Intr Cause */ + val = hif_read32_mb(mem + (SOC_CORE_BASE_ADDRESS | CPU_INTR_ADDRESS)); + HIF_INFO_MED("%s: Target CPU Intr Cause 0x%x", __func__, val); + + val = + hif_read32_mb(mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + hif_write32_mb((mem + + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS)), 0); + hif_write32_mb((mem + (SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS)), + HOST_GROUP0_MASK); + + cdf_mdelay(100); + + /* Clear FW_INDICATOR_ADDRESS */ + if (HAS_FW_INDICATOR) { + fw_indicator = hif_read32_mb(mem + FW_INDICATOR_ADDRESS); + hif_write32_mb(mem + FW_INDICATOR_ADDRESS, 0); + } + + /* Clear Target LF Timer interrupts */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS)); + HIF_INFO_MED("%s: addr 0x%x : 0x%x", __func__, + (RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS), val); + val &= ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + hif_write32_mb(mem + + (RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS), + val); + + /* Reset CE */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + val |= SOC_RESET_CONTROL_CE_RST_MASK; + hif_write32_mb((mem + + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS)), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + cdf_mdelay(10); + + /* CE unreset */ + val &= ~SOC_RESET_CONTROL_CE_RST_MASK; + hif_write32_mb(mem + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + cdf_mdelay(10); + + /* Read Target CPU Intr Cause */ + val = hif_read32_mb(mem + (SOC_CORE_BASE_ADDRESS | CPU_INTR_ADDRESS)); + HIF_INFO_MED("%s: Target CPU Intr Cause after CE reset 0x%x", + __func__, val); + + /* CPU warm RESET */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + val |= SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + hif_write32_mb(mem + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + HIF_INFO_MED("%s: RESET_CONTROL after cpu warm reset 0x%x", + __func__, val); + + cdf_mdelay(100); + HIF_INFO_MED("%s: Target Warm reset complete", __func__); + +} + +#ifndef QCA_WIFI_3_0 +int hif_check_fw_reg(struct ol_softc *scn) +{ + struct hif_pci_softc *sc = scn->hif_sc; + void __iomem *mem = sc->mem; + uint32_t val; + + A_TARGET_ACCESS_BEGIN_RET(scn); + val = hif_read32_mb(mem + FW_INDICATOR_ADDRESS); + A_TARGET_ACCESS_END_RET(scn); + + HIF_INFO_MED("%s: FW_INDICATOR register is 0x%x", __func__, val); + + if (val & FW_IND_HELPER) + return 0; + + return 1; +} +#endif + +int hif_check_soc_status(struct ol_softc *scn) +{ + uint16_t device_id; + uint32_t val; + uint16_t timeout_count = 0; + struct hif_pci_softc *sc = scn->hif_sc; + + /* Check device ID from PCIe configuration space for link status */ + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &device_id); + if (device_id != sc->devid) { + HIF_ERROR("%s: device ID does match (read 0x%x, expect 0x%x)", + __func__, device_id, sc->devid); + return -EACCES; + } + + /* Check PCIe local register for bar/memory access */ + val = hif_read32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS); + HIF_INFO_MED("%s: RTC_STATE_ADDRESS is %08x", __func__, val); + + /* Try to wake up taget if it sleeps */ + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + HIF_INFO_MED("%s: PCIE_SOC_WAKE_ADDRESS is %08x", __func__, + hif_read32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + + /* Check if taget can be woken up */ + while (!hif_targ_is_awake(scn, sc->mem)) { + if (timeout_count >= PCIE_WAKE_TIMEOUT) { + HIF_ERROR("%s: wake up timeout, %08x, %08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS), + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + return -EACCES; + } + + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + + cdf_mdelay(100); + timeout_count += 100; + } + + /* Check Power register for SoC internal bus issues */ + val = + hif_read32_mb(sc->mem + RTC_SOC_BASE_ADDRESS + + SOC_POWER_REG_OFFSET); + HIF_INFO_MED("%s: Power register is %08x", __func__, val); + + return 0; +} + +void dump_ce_debug_register(struct ol_softc *scn) +{ + struct hif_pci_softc *sc = scn->hif_sc; + void __iomem *mem = sc->mem; + uint32_t val, i, j; + uint32_t wrapper_idx[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint32_t ce_base; + + A_TARGET_ACCESS_BEGIN(scn); + + /* DEBUG_INPUT_SEL_SRC = 0x6 */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_INPUT_SEL_OFFSET); + val &= ~WLAN_DEBUG_INPUT_SEL_SRC_MASK; + val |= WLAN_DEBUG_INPUT_SEL_SRC_SET(0x6); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + WLAN_DEBUG_INPUT_SEL_OFFSET, + val); + + /* DEBUG_CONTROL_ENABLE = 0x1 */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET); + val &= ~WLAN_DEBUG_CONTROL_ENABLE_MASK; + val |= WLAN_DEBUG_CONTROL_ENABLE_SET(0x1); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET, val); + + HIF_INFO_MED("%s: Debug: inputsel: %x dbgctrl: %x", __func__, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_INPUT_SEL_OFFSET), + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET)); + + HIF_INFO_MED("%s: Debug CE", __func__); + /* Loop CE debug output */ + /* AMBA_DEBUG_BUS_SEL = 0xc */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_SEL_MASK; + val |= AMBA_DEBUG_BUS_SEL_SET(0xc); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, val); + + for (i = 0; i < sizeof(wrapper_idx) / sizeof(uint32_t); i++) { + /* For (i=1,2,3,4,8,9) write CE_WRAPPER_DEBUG_SEL = i */ + val = hif_read32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET); + val &= ~CE_WRAPPER_DEBUG_SEL_MASK; + val |= CE_WRAPPER_DEBUG_SEL_SET(wrapper_idx[i]); + hif_write32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET, val); + + HIF_INFO_MED("%s: ce wrapper: %d amdbg: %x cewdbg: %x", + __func__, wrapper_idx[i], + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + AMBA_DEBUG_BUS_OFFSET), + hif_read32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET)); + + if (wrapper_idx[i] <= 7) { + for (j = 0; j <= 5; j++) { + ce_base = CE_BASE_ADDRESS(wrapper_idx[i]); + /* For (j=0~5) write CE_DEBUG_SEL = j */ + val = + hif_read32_mb(mem + ce_base + + CE_DEBUG_OFFSET); + val &= ~CE_DEBUG_SEL_MASK; + val |= CE_DEBUG_SEL_SET(j); + hif_write32_mb(mem + ce_base + CE_DEBUG_OFFSET, + val); + + /* read (@gpio_athr_wlan_reg) + * WLAN_DEBUG_OUT_DATA */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: module%d: cedbg: %x out: %x", + __func__, j, + hif_read32_mb(mem + ce_base + + CE_DEBUG_OFFSET), val); + } + } else { + /* read (@gpio_athr_wlan_reg) WLAN_DEBUG_OUT_DATA */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: out: %x", __func__, val); + } + } + + HIF_INFO_MED("%s: Debug PCIe:", __func__); + /* Loop PCIe debug output */ + /* Write AMBA_DEBUG_BUS_SEL = 0x1c */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_SEL_MASK; + val |= AMBA_DEBUG_BUS_SEL_SET(0x1c); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, val); + + for (i = 0; i <= 8; i++) { + /* For (i=1~8) write AMBA_DEBUG_BUS_PCIE_DEBUG_SEL = i */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK; + val |= AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(i); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, + val); + + /* read (@gpio_athr_wlan_reg) WLAN_DEBUG_OUT_DATA */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: amdbg: %x out: %x %x", __func__, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET), val, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET)); + } + + A_TARGET_ACCESS_END(scn); +} + +/* + * Handler for a per-engine interrupt on a PARTICULAR CE. + * This is used in cases where each CE has a private + * MSI interrupt. + */ +static irqreturn_t ce_per_engine_handler(int irq, void *arg) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)arg; + int CE_id = irq - MSI_ASSIGN_CE_INITIAL; + + /* + * NOTE: We are able to derive CE_id from irq because we + * use a one-to-one mapping for CE's 0..5. + * CE's 6 & 7 do not use interrupts at all. + * + * This mapping must be kept in sync with the mapping + * used by firmware. + */ + + ce_per_engine_service(sc->ol_sc, CE_id); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_SLUB_DEBUG_ON + +/* worker thread to schedule wlan_tasklet in SLUB debug build */ +static void reschedule_tasklet_work_handler(struct work_struct *recovery) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct hif_pci_softc *sc; + + if (NULL == scn) { + HIF_ERROR("%s: tasklet scn is null", __func__); + return; + } + + sc = scn->hif_sc; + + if (scn->hif_init_done == false) { + HIF_ERROR("%s: wlan driver is unloaded", __func__); + return; + } + + tasklet_schedule(&sc->intr_tq); + return; +} + +static DECLARE_WORK(reschedule_tasklet_work, reschedule_tasklet_work_handler); + +#endif + +static void wlan_tasklet(unsigned long data) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)data; + struct ol_softc *scn = sc->ol_sc; + + if (scn->hif_init_done == false) + goto end; + + if (cdf_atomic_read(&scn->link_suspended)) + goto end; + + if (!IHELIUM_BU && !ADRASTEA_BU) { + (irqreturn_t) hif_fw_interrupt_handler(sc->irq_event, scn); + if (sc->ol_sc->target_status == OL_TRGET_STATUS_RESET) + goto end; + } + +end: + cdf_atomic_set(&scn->tasklet_from_intr, 0); + cdf_atomic_dec(&scn->active_tasklet_cnt); +} + +#define ATH_PCI_PROBE_RETRY_MAX 3 +/** + * hif_bus_open(): hif_bus_open + * @scn: scn + * @bus_type: bus type + * + * Return: n/a + */ +CDF_STATUS hif_bus_open(struct ol_softc *ol_sc, enum ath_hal_bus_type bus_type) +{ + struct hif_pci_softc *sc; + + sc = cdf_mem_malloc(sizeof(*sc)); + if (!sc) { + HIF_ERROR("%s: no mem", __func__); + return CDF_STATUS_E_NOMEM; + } + ol_sc->hif_sc = (void *)sc; + sc->ol_sc = ol_sc; + ol_sc->bus_type = bus_type; + + return CDF_STATUS_SUCCESS; +} + +/** + * hif_bus_close(): hif_bus_close + * + * Return: n/a + */ +void hif_bus_close(struct ol_softc *ol_sc) +{ + struct hif_pci_softc *sc; + + if (ol_sc == NULL) { + HIF_ERROR("%s: ol_softc is NULL", __func__); + return; + } + sc = ol_sc->hif_sc; + if (sc == NULL) + return; + cdf_mem_free(sc); + ol_sc->hif_sc = NULL; +} + +#define BAR_NUM 0 + +int hif_enable_pci(struct hif_pci_softc *sc, + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + int ret = 0; + uint16_t device_id; + struct ol_softc *ol_sc = sc->ol_sc; + + pci_read_config_word(pdev,PCI_DEVICE_ID,&device_id); + if(device_id != id->device) { + HIF_ERROR( + "%s: dev id mismatch, config id = 0x%x, probing id = 0x%x", + __func__, device_id, id->device); + /* pci link is down, so returing with error code */ + return -EIO; + } + + /* FIXME: temp. commenting out assign_resource + * call for dev_attach to work on 2.6.38 kernel + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) && \ + !defined(__LINUX_ARM_ARCH__) + if (pci_assign_resource(pdev, BAR_NUM)) { + HIF_ERROR("%s: pci_assign_resource error", __func__); + return -EIO; + } +#endif + + if (pci_enable_device(pdev)) { + HIF_ERROR("%s: pci_enable_device error", + __func__); + return -EIO; + } + + /* Request MMIO resources */ + ret = pci_request_region(pdev, BAR_NUM, "ath"); + if (ret) { + HIF_ERROR("%s: PCI MMIO reservation error", __func__); + ret = -EIO; + goto err_region; + } +#ifdef CONFIG_ARM_LPAE + /* if CONFIG_ARM_LPAE is enabled, we have to set 64 bits mask + * for 32 bits device also. */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + HIF_ERROR("%s: Cannot enable 64-bit pci DMA", __func__); + goto err_dma; + } + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + HIF_ERROR("%s: Cannot enable 64-bit DMA", __func__); + goto err_dma; + } +#else + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + HIF_ERROR("%s: Cannot enable 32-bit pci DMA", __func__); + goto err_dma; + } + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + HIF_ERROR("%s: Cannot enable 32-bit consistent DMA!", + __func__); + goto err_dma; + } +#endif + + PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, 0x188); + + /* Set bus master bit in PCI_COMMAND to enable DMA */ + pci_set_master(pdev); + + /* Arrange for access to Target SoC registers. */ + mem = pci_iomap(pdev, BAR_NUM, 0); + if (!mem) { + HIF_ERROR("%s: PCI iomap error", __func__); + ret = -EIO; + goto err_iomap; + } + sc->mem = mem; + sc->pdev = pdev; + sc->dev = &pdev->dev; + ol_sc->aps_osdev.bdev = pdev; + ol_sc->aps_osdev.device = &pdev->dev; + ol_sc->aps_osdev.bc.bc_handle = (void *)mem; + ol_sc->aps_osdev.bc.bc_bustype = HAL_BUS_TYPE_PCI; + sc->devid = id->device; + sc->cacheline_sz = dma_get_cache_alignment(); + /* Get RAM dump memory address and size */ + GET_VIRT_RAMDUMP_MEM(ol_sc); + ol_sc->mem = mem; + sc->pci_enabled = true; + return ret; + +err_iomap: + pci_clear_master(pdev); +err_dma: + pci_release_region(pdev, BAR_NUM); +err_region: + pci_disable_device(pdev); + return ret; +} + +void hif_disable_pci(struct hif_pci_softc *sc) +{ + struct ol_softc *ol_sc; + + if (!sc) + return; + + ol_sc = sc->ol_sc; + if (ol_sc == NULL) { + HIF_ERROR("%s: ol_sc = NULL", __func__); + return; + } + pci_set_drvdata(sc->pdev, NULL); + hif_pci_device_reset(sc); + pci_iounmap(sc->pdev, sc->mem); + sc->mem = NULL; + ol_sc->mem = NULL; + pci_clear_master(sc->pdev); + pci_release_region(sc->pdev, BAR_NUM); + pci_disable_device(sc->pdev); +} + +int hif_pci_probe_tgt_wakeup(struct hif_pci_softc *sc) +{ + int ret = 0; + int targ_awake_limit = 500; +#ifndef QCA_WIFI_3_0 + uint32_t fw_indicator; +#endif + struct ol_softc *scn = sc->ol_sc; + /* + * Verify that the Target was started cleanly.* + * The case where this is most likely is with an AUX-powered + * Target and a Host in WoW mode. If the Host crashes, + * loses power, or is restarted (without unloading the driver) + * then the Target is left (aux) powered and running. On a + * subsequent driver load, the Target is in an unexpected state. + * We try to catch that here in order to reset the Target and + * retry the probe. + */ + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + while (!hif_targ_is_awake(scn, sc->mem)) { + if (0 == targ_awake_limit) { + HIF_ERROR("%s: target awake timeout", __func__); + ret = -EAGAIN; + goto end; + } + cdf_mdelay(1); + targ_awake_limit--; + } + +#if PCIE_BAR0_READY_CHECKING + { + int wait_limit = 200; + /* Synchronization point: wait the BAR0 is configured */ + while (wait_limit-- && + !(hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_RDY_STATUS_ADDRESS) \ + & PCIE_SOC_RDY_STATUS_BAR_MASK)) { + cdf_mdelay(10); + } + if (wait_limit < 0) { + /* AR6320v1 doesn't support checking of BAR0 configuration, + takes one sec to wait BAR0 ready */ + HIF_INFO_MED("%s: AR6320v1 waits two sec for BAR0", + __func__); + } + } +#endif + +#ifndef QCA_WIFI_3_0 + fw_indicator = hif_read32_mb(sc->mem + FW_INDICATOR_ADDRESS); + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); + + if (fw_indicator & FW_IND_INITIALIZED) { + HIF_ERROR("%s: Target is in an unknown state. EAGAIN", + __func__); + ret = -EAGAIN; + goto end; + } +#endif + +end: + return ret; +} + +static void wlan_tasklet_msi(unsigned long data) +{ + struct hif_tasklet_entry *entry = (struct hif_tasklet_entry *)data; + struct hif_pci_softc *sc = (struct hif_pci_softc *) entry->hif_handler; + struct ol_softc *scn = sc->ol_sc; + + if (sc->ol_sc->hif_init_done == false) + goto irq_handled; + + if (cdf_atomic_read(&sc->ol_sc->link_suspended)) + goto irq_handled; + + cdf_atomic_inc(&scn->active_tasklet_cnt); + + if (entry->id == HIF_MAX_TASKLET_NUM) { + /* the last tasklet is for fw IRQ */ + (irqreturn_t)hif_fw_interrupt_handler(sc->irq_event, sc->ol_sc); + if (sc->ol_sc->target_status == OL_TRGET_STATUS_RESET) + goto irq_handled; + } else if (entry->id < sc->ol_sc->ce_count) { + ce_per_engine_service(sc->ol_sc, entry->id); + } else { + HIF_ERROR("%s: ERROR - invalid CE_id = %d", + __func__, entry->id); + } + return; + +irq_handled: + cdf_atomic_dec(&scn->active_tasklet_cnt); + +} + +int hif_configure_msi(struct hif_pci_softc *sc) +{ + int ret = 0; + int num_msi_desired; + int rv = -1; + struct ol_softc *scn = sc->ol_sc; + + HIF_TRACE("%s: E", __func__); + + num_msi_desired = MSI_NUM_REQUEST; /* Multiple MSI */ + if (num_msi_desired < 1) { + HIF_ERROR("%s: MSI is not configured", __func__); + return -EINVAL; + } + + if (num_msi_desired > 1) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + rv = pci_enable_msi_range(sc->pdev, num_msi_desired, + num_msi_desired); +#else + rv = pci_enable_msi_block(sc->pdev, num_msi_desired); +#endif + } + HIF_TRACE("%s: num_msi_desired = %d, available_msi = %d", + __func__, num_msi_desired, rv); + + if (rv == 0 || rv >= HIF_MAX_TASKLET_NUM) { + int i; + + sc->num_msi_intrs = HIF_MAX_TASKLET_NUM; + sc->tasklet_entries[HIF_MAX_TASKLET_NUM -1].hif_handler = + (void *)sc; + sc->tasklet_entries[HIF_MAX_TASKLET_NUM -1].id = + HIF_MAX_TASKLET_NUM; + tasklet_init(&sc->intr_tq, wlan_tasklet_msi, + (unsigned long)&sc->tasklet_entries[ + HIF_MAX_TASKLET_NUM -1]); + ret = request_irq(sc->pdev->irq + MSI_ASSIGN_FW, + hif_pci_msi_fw_handler, + IRQF_SHARED, "wlan_pci", sc); + if(ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + for (i = 0; i <= scn->ce_count; i++) { + sc->tasklet_entries[i].hif_handler = (void *)sc; + sc->tasklet_entries[i].id = i; + tasklet_init(&sc->intr_tq, wlan_tasklet_msi, + (unsigned long)&sc->tasklet_entries[i]); + ret = request_irq((sc->pdev->irq + + i + MSI_ASSIGN_CE_INITIAL), + ce_per_engine_handler, IRQF_SHARED, + "wlan_pci", sc); + if(ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + } else if (rv > 0) { + HIF_TRACE("%s: use single msi", __func__); + + if ((ret = pci_enable_msi(sc->pdev)) < 0) { + HIF_ERROR("%s: single MSI allocation failed", + __func__); + /* Try for legacy PCI line interrupts */ + sc->num_msi_intrs = 0; + } else { + sc->num_msi_intrs = 1; + tasklet_init(&sc->intr_tq, + wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, + IRQF_SHARED, "wlan_pci", sc); + if(ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + } else { + sc->num_msi_intrs = 0; + ret = -EIO; + HIF_ERROR("%s: do not support MSI, rv = %d", __func__, rv); + } + if ((ret = pci_enable_msi(sc->pdev)) < 0) { + HIF_ERROR("%s: single MSI interrupt allocation failed", + __func__); + /* Try for legacy PCI line interrupts */ + sc->num_msi_intrs = 0; + } else { + sc->num_msi_intrs = 1; + tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, IRQF_SHARED, + "wlan_pci", sc); + if(ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + + if (ret == 0) { + hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + hif_write32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); + } + HIF_TRACE("%s: X, ret = %d", __func__, ret); + + return ret; + +err_intr: +if (sc->num_msi_intrs >= 1) + pci_disable_msi(sc->pdev); + return ret; +} + +static int hif_pci_configure_legacy_irq(struct hif_pci_softc *sc) +{ + int ret = 0; + struct ol_softc *scn = sc->ol_sc; + + HIF_TRACE("%s: E", __func__); + + /* do notn support MSI or MSI IRQ failed */ + tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, IRQF_SHARED, + "wlan_pci", sc); + if(ret) { + HIF_ERROR("%s: request_irq failed, ret = %d", __func__, ret); + goto end; + } + /* Use Legacy PCI Interrupts */ + hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); +end: + CDF_TRACE(CDF_MODULE_ID_HIF, CDF_TRACE_LEVEL_ERROR, + "%s: X, ret = %d", __func__, ret); + return ret; +} + +/** + * hif_nointrs(): disable IRQ + * + * This function stops interrupt(s) + * + * @scn: struct ol_softc + * + * Return: none + */ +void hif_nointrs(struct ol_softc *scn) +{ + int i; + struct hif_pci_softc *sc = scn->hif_sc; + + if (scn->request_irq_done == false) + return; + if (sc->num_msi_intrs > 0) { + /* MSI interrupt(s) */ + for (i = 0; i < sc->num_msi_intrs; i++) { + free_irq(sc->pdev->irq + i, sc); + } + sc->num_msi_intrs = 0; + } else { + /* Legacy PCI line interrupt */ + free_irq(sc->pdev->irq, sc); + } + ce_unregister_irq(scn->hif_hdl, 0xfff); + scn->request_irq_done = false; +} + +/** + * hif_disable_bus(): hif_disable_bus + * + * This function disables the bus + * + * @bdev: bus dev + * + * Return: none + */ +void hif_disable_bus(void *bdev) +{ + struct pci_dev *pdev = bdev; + struct hif_pci_softc *sc = pci_get_drvdata(pdev); + struct ol_softc *scn; + void __iomem *mem; + + /* Attach did not succeed, all resources have been + * freed in error handler + */ + if (!sc) + return; + + scn = sc->ol_sc; + + if (ADRASTEA_BU) { + hif_write32_mb(sc->mem + PCIE_INTR_ENABLE_ADDRESS, 0); + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, + HOST_GROUP0_MASK); + } + + mem = (void __iomem *)sc->mem; + if (mem) { + pci_disable_msi(pdev); + hif_dump_pipe_debug_count(scn); + hif_deinit_cdf_ctx(scn); + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + pci_set_drvdata(pdev, NULL); + pci_iounmap(pdev, mem); + scn->mem = NULL; + pci_release_region(pdev, BAR_NUM); + pci_clear_master(pdev); + pci_disable_device(pdev); + } + HIF_INFO("%s: X", __func__); +} + +#define OL_ATH_PCI_PM_CONTROL 0x44 + +#ifdef CONFIG_CNSS +/** + * hif_bus_prevent_linkdown(): allow or permit linkdown + * @flag: true prevents linkdown, false allows + * + * Calls into the platform driver to vote against taking down the + * pcie link. + * + * Return: n/a + */ +void hif_bus_prevent_linkdown(bool flag) +{ + HIF_ERROR("wlan: %s pcie power collapse", + (flag ? "disable" : "enable")); + cnss_wlan_pm_control(flag); +} +#endif + +/** + * hif_drain_tasklets(): wait untill no tasklet is pending + * @scn: hif context + * + * Let running tasklets clear pending trafic. + * + * Return: 0 if no bottom half is in progress when it returns. + * -EFAULT if it times out. + */ +static inline int hif_drain_tasklets(struct ol_softc *scn) +{ + uint32_t ce_drain_wait_cnt = 0; + + while (cdf_atomic_read(&scn->active_tasklet_cnt)) { + if (++ce_drain_wait_cnt > HIF_CE_DRAIN_WAIT_CNT) { + HIF_ERROR("%s: CE still not done with access", + __func__); + + return -EFAULT; + } + HIF_INFO("%s: Waiting for CE to finish access", __func__); + msleep(10); + } + return 0; +} + +/** + * hif_bus_suspend_link_up() - suspend the bus + * + * Configures the pci irq line as a wakeup source. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_suspend_link_up(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct pci_dev *pdev; + int status; + + if (!scn) + return -EFAULT; + + pdev = scn->aps_osdev.bdev; + + status = hif_drain_tasklets(scn); + if (status != 0) + return status; + + if (unlikely(enable_irq_wake(pdev->irq))) { + HIF_ERROR("%s: Fail to enable wake IRQ!", __func__); + return -EINVAL; + } + + return 0; +} + +/** + * hif_bus_resume_link_up() - hif bus resume API + * + * This function disables the wakeup source. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_resume_link_up(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct pci_dev *pdev; + + if (!scn) + return -EFAULT; + + pdev = scn->aps_osdev.bdev; + if (!pdev) { + HIF_ERROR("%s: pci_dev is null", __func__); + return -EFAULT; + } + + if (unlikely(disable_irq_wake(pdev->irq))) { + HIF_ERROR("%s: Fail to disable wake IRQ!", __func__); + return -EFAULT; + } + + return 0; +} + +/** + * hif_bus_suspend_link_down() - suspend the bus + * + * Suspends the hif layer taking care of draining recieve queues and + * shutting down copy engines if needed. Ensures opy engine interrupts + * are disabled when it returns. Prevents register access after it + * returns. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_suspend_link_down(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct pci_dev *pdev; + struct HIF_CE_state *hif_state; + int status = 0; + + if (!scn) + return -EFAULT; + + pdev = scn->aps_osdev.bdev; + + hif_state = (struct HIF_CE_state *)scn->hif_hdl; + if (!hif_state) { + HIF_ERROR("%s: hif_state is null", __func__); + return -EFAULT; + } + + disable_irq(pdev->irq); + + status = hif_drain_tasklets(scn); + if (status != 0) { + enable_irq(pdev->irq); + return status; + } + + /* Stop the HIF Sleep Timer */ + hif_cancel_deferred_target_sleep(scn); + + cdf_atomic_set(&scn->link_suspended, 1); + + return 0; +} + +/** + * hif_bus_resume_link_down() - hif bus resume API + * + * This function resumes the bus reenabling interupts. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_resume_link_down(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct pci_dev *pdev; + + if (!scn) + return -EFAULT; + + pdev = scn->aps_osdev.bdev; + if (!pdev) { + HIF_ERROR("%s: pci_dev is null", __func__); + return -EFAULT; + } + + cdf_atomic_set(&scn->link_suspended, 0); + + enable_irq(pdev->irq); + + return 0; +} + +/** + * hif_bus_suspend(): prepare hif for suspend + * chose suspend type based on link suspend voting. + * + * Return: linux status + */ +int hif_bus_suspend(void) +{ + if (hif_can_suspend_link()) + return hif_bus_suspend_link_down(); + else + return hif_bus_suspend_link_up(); +} + +/** + * hif_bus_suspend(): prepare hif for suspend + * chose suspend type based on link suspend voting. + * + * Return: linux status + */ +int hif_bus_resume(void) +{ + if (hif_can_suspend_link()) + return hif_bus_resume_link_down(); + else + return hif_bus_resume_link_up(); +} + +void hif_disable_isr(void *ol_sc) +{ + struct ol_softc *scn = (struct ol_softc *)ol_sc; + struct hif_pci_softc *sc = scn->hif_sc; + + hif_nointrs(ol_sc); +#if CONFIG_PCIE_64BIT_MSI + OS_FREE_CONSISTENT(&scn->aps_osdev, 4, + scn->msi_magic, scn->msi_magic_dma, + OS_GET_DMA_MEM_CONTEXT(scn, MSI_dmacontext)); + scn->msi_magic = NULL; + scn->msi_magic_dma = 0; +#endif + /* Cancel the pending tasklet */ + ce_tasklet_kill(scn->hif_hdl); + tasklet_kill(&sc->intr_tq); + cdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +/* Function to reset SoC */ +void hif_reset_soc(void *ol_sc) +{ + struct ol_softc *scn = (struct ol_softc *)ol_sc; + struct hif_pci_softc *sc = scn->hif_sc; + +#if defined(CPU_WARM_RESET_WAR) + /* Currently CPU warm reset sequence is tested only for AR9888_REV2 + * Need to enable for AR9888_REV1 once CPU warm reset sequence is + * verified for AR9888_REV1 + */ + if (scn->target_version == AR9888_REV2_VERSION) { + hif_pci_device_warm_reset(sc); + } else { + hif_pci_device_reset(sc); + } +#else + hif_pci_device_reset(sc); +#endif +} + +void hif_disable_aspm(void) +{ + struct ol_softc *scn = cds_get_context(CDF_MODULE_ID_HIF); + struct hif_pci_softc *sc; + + if (NULL == scn) { + HIF_ERROR("%s: Could not disable ASPM scn is null", + __func__); + return; + } + + sc = scn->hif_sc; + + /* Disable ASPM when pkt log is enabled */ + pci_read_config_dword(sc->pdev, 0x80, &scn->lcr_val); + pci_write_config_dword(sc->pdev, 0x80, (scn->lcr_val & 0xffffff00)); +} + +/** + * hif_enable_power_gating(): enable HW power gating + * + * This function enables HW gating + * + * Return: none + */ +void hif_enable_power_gating(void *hif_ctx) +{ + struct ol_softc *scn = hif_ctx; + struct hif_pci_softc *sc; + + if (NULL == scn) { + HIF_ERROR("%s: Could not disable ASPM scn is null", + __func__); + return; + } + sc = scn->hif_sc; + + /* Re-enable ASPM after firmware/OTP download is complete */ + pci_write_config_dword(sc->pdev, 0x80, scn->lcr_val); + if (scn->pkt_log_init == false) { + PKT_LOG_MOD_INIT(scn); + scn->pkt_log_init = true; + } +} + +#ifdef CONFIG_PCI_MSM +static inline void hif_msm_pcie_debug_info(struct hif_pci_softc *sc) +{ + msm_pcie_debug_info(sc->pdev, 13, 1, 0, 0, 0); + msm_pcie_debug_info(sc->pdev, 13, 2, 0, 0, 0); +} +#else +static inline void hif_msm_pcie_debug_info(struct hif_pci_softc *sc) {}; +#endif + +/* + * For now, we use simple on-demand sleep/wake. + * Some possible improvements: + * -Use the Host-destined A_INUM_PCIE_AWAKE interrupt rather than spin/delay + * (or perhaps spin/delay for a short while, then convert to sleep/interrupt) + * Careful, though, these functions may be used by + * interrupt handlers ("atomic") + * -Don't use host_reg_table for this code; instead use values directly + * -Use a separate timer to track activity and allow Target to sleep only + * if it hasn't done anything for a while; may even want to delay some + * processing for a short while in order to "batch" (e.g.) transmit + * requests with completion processing into "windows of up time". Costs + * some performance, but improves power utilization. + * -On some platforms, it might be possible to eliminate explicit + * sleep/wakeup. Instead, take a chance that each access works OK. If not, + * recover from the failure by forcing the Target awake. + * -Change keep_awake_count to an atomic_t in order to avoid spin lock + * overhead in some cases. Perhaps this makes more sense when + * CONFIG_ATH_PCIE_ACCESS_LIKELY is used and less sense when LIKELY is + * disabled. + * -It is possible to compile this code out and simply force the Target + * to remain awake. That would yield optimal performance at the cost of + * increased power. See CONFIG_ATH_PCIE_MAX_PERF. + * + * Note: parameter wait_for_it has meaning only when waking (when sleep_ok==0). + */ +/** + * hif_target_sleep_state_adjust() - on-demand sleep/wake + * @scn: ol_softc pointer. + * @sleep_ok: bool + * @wait_for_it: bool + * + * Output the pipe error counts of each pipe to log file + * + * Return: int + */ +#if ((CONFIG_ATH_PCIE_MAX_PERF == 0) && CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD) +int +hif_target_sleep_state_adjust(struct ol_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + struct HIF_CE_state *hif_state = scn->hif_hdl; + A_target_id_t pci_addr = scn->mem; + static int max_delay; + struct hif_pci_softc *sc = scn->hif_sc; + static int debug; + + if (scn->recovery) + return -EACCES; + + if (cdf_atomic_read(&scn->link_suspended)) { + HIF_ERROR("%s:invalid access, PCIe link is down", __func__); + debug = true; + CDF_ASSERT(0); + return -EACCES; + } + + if (debug) { + wait_for_it = true; + HIF_ERROR("%s: doing debug for invalid access, PCIe link is suspended", + __func__); + CDF_ASSERT(0); + } + + if (sleep_ok) { + cdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + hif_state->keep_awake_count--; + if (hif_state->keep_awake_count == 0) { + /* Allow sleep */ + hif_state->verified_awake = false; + hif_state->sleep_ticks = cdf_system_ticks(); + } + if (hif_state->fake_sleep == false) { + /* Set the Fake Sleep */ + hif_state->fake_sleep = true; + + /* Start the Sleep Timer */ + cdf_softirq_timer_cancel(&hif_state->sleep_timer); + cdf_softirq_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + cdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); + } else { + cdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + + if (hif_state->fake_sleep) { + hif_state->verified_awake = true; + } else { + if (hif_state->keep_awake_count == 0) { + /* Force AWAKE */ + hif_write32_mb(pci_addr + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + } + } + hif_state->keep_awake_count++; + cdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); + + if (wait_for_it && !hif_state->verified_awake) { +#define PCIE_SLEEP_ADJUST_TIMEOUT 8000 /* 8Ms */ + int tot_delay = 0; + int curr_delay = 5; + + for (;; ) { + if (hif_targ_is_awake(scn, pci_addr)) { + hif_state->verified_awake = true; + break; + } else + if (!hif_pci_targ_is_present + (scn, pci_addr)) { + break; + } + if (tot_delay > PCIE_SLEEP_ADJUST_TIMEOUT) { + uint16_t val; + uint32_t bar; + + HIF_ERROR("%s: keep_awake_count = %d", + __func__, + hif_state->keep_awake_count); + + pci_read_config_word(sc->pdev, + PCI_VENDOR_ID, + &val); + HIF_ERROR("%s: PCI Vendor ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, + PCI_DEVICE_ID, + &val); + HIF_ERROR("%s: PCI Device ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, + PCI_COMMAND, &val); + HIF_ERROR("%s: PCI Command = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, + PCI_STATUS, &val); + HIF_ERROR("%s: PCI Status = 0x%04x", + __func__, val); + + pci_read_config_dword(sc->pdev, + PCI_BASE_ADDRESS_0, &bar); + HIF_ERROR("%s: PCI BAR 0 = 0x%08x", + __func__, bar); + + HIF_ERROR("%s: SOC_WAKE_ADDR 0%08x", + __func__, + hif_read32_mb(pci_addr + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + HIF_ERROR("%s: RTC_STATE_ADDR 0x%08x", + __func__, + hif_read32_mb(pci_addr + + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS)); + + HIF_ERROR("%s:error, wakeup target", + __func__); + hif_msm_pcie_debug_info(sc); + if (!sc->ol_sc->enable_self_recovery) + CDF_BUG(0); + scn->recovery = true; + cds_set_logp_in_progress(true); + cnss_wlan_pci_link_down(); + return -EACCES; + } + + OS_DELAY(curr_delay); + tot_delay += curr_delay; + + if (curr_delay < 50) + curr_delay += 5; + } + + /* + * NB: If Target has to come out of Deep Sleep, + * this may take a few Msecs. Typically, though + * this delay should be <30us. + */ + if (tot_delay > max_delay) + max_delay = tot_delay; + } + } + + if (debug && hif_state->verified_awake) { + debug = 0; + HIF_ERROR("%s: INTR_ENABLE_REG = 0x%08x, INTR_CAUSE_REG = 0x%08x, CPU_INTR_REG = 0x%08x, INTR_CLR_REG = 0x%08x, CE_INTERRUPT_SUMMARY_REG = 0x%08x", + __func__, + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CLR_ADDRESS), + hif_read32_mb(sc->mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + } + + return 0; +} +#else +inline int +hif_target_sleep_state_adjust(struct ol_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + return 0; +} +#endif + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +uint32_t hif_target_read_checked(struct ol_softc *scn, uint32_t offset) +{ + uint32_t value; + void *addr; + + if (!A_TARGET_ACCESS_OK(scn)) + hi_fdebug(); + + addr = scn->mem + offset; + value = A_PCI_READ32(addr); + + { + unsigned long irq_flags; + int idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + pcie_access_log[idx].seqnum = pcie_access_log_seqnum; + pcie_access_log[idx].is_write = false; + pcie_access_log[idx].addr = addr; + pcie_access_log[idx].value = value; + pcie_access_log_seqnum++; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); + } + + return value; +} + +void +hif_target_write_checked(struct ol_softc *scn, uint32_t offset, uint32_t value) +{ + void *addr; + + if (!A_TARGET_ACCESS_OK(scn)) + hi_fdebug(); + + addr = scn->mem + (offset); + hif_write32_mb(addr, value); + + { + unsigned long irq_flags; + int idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + pcie_access_log[idx].seqnum = pcie_access_log_seqnum; + pcie_access_log[idx].is_write = true; + pcie_access_log[idx].addr = addr; + pcie_access_log[idx].value = value; + pcie_access_log_seqnum++; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); + } +} + +/** + * hi_fdebug() - not needed in PCI + * + * + * Return: n/a + */ +void hi_fdebug(void) +{ + /* BUG_ON(1); */ +} + +/** + * hif_target_dump_access_log() - dump access log + * + * dump access log + * + * Return: n/a + */ +void hif_target_dump_access_log(void) +{ + int idx, len, start_idx, cur_idx; + unsigned long irq_flags; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + if (pcie_access_log_seqnum > PCIE_ACCESS_LOG_NUM) { + len = PCIE_ACCESS_LOG_NUM; + start_idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + } else { + len = pcie_access_log_seqnum; + start_idx = 0; + } + + for (idx = 0; idx < len; idx++) { + cur_idx = (start_idx + idx) % PCIE_ACCESS_LOG_NUM; + HIF_ERROR("%s: idx:%d sn:%u wr:%d addr:%p val:%u.", + __func__, idx, + pcie_access_log[cur_idx].seqnum, + pcie_access_log[cur_idx].is_write, + pcie_access_log[cur_idx].addr, + pcie_access_log[cur_idx].value); + } + + pcie_access_log_seqnum = 0; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); +} +#endif + +/** + * war_pci_write32() - PCIe io32 write workaround + * @addr: addr + * @offset: offset + * @value: value + * + * iowrite32 + * + * Return: int + */ +void war_pci_write32(char *addr, uint32_t offset, uint32_t value) +{ + if (hif_pci_war1) { + unsigned long irq_flags; + + spin_lock_irqsave(&pciwar_lock, irq_flags); + + (void)ioread32((void __iomem *)(addr + offset + 4)); + (void)ioread32((void __iomem *)(addr + offset + 4)); + (void)ioread32((void __iomem *)(addr + offset + 4)); + iowrite32((uint32_t) (value), (void __iomem *)(addr + offset)); + + spin_unlock_irqrestore(&pciwar_lock, irq_flags); + } else { + iowrite32((uint32_t) (value), (void __iomem *)(addr + offset)); + } +} + +/** + * hif_configure_irq(): configure interrupt + * + * This function configures interrupt(s) + * + * @sc: PCIe control struct + * @hif_hdl: struct HIF_CE_state + * + * Return: 0 - for success + */ +int hif_configure_irq(struct hif_pci_softc *sc) +{ + int ret = 0; + struct ol_softc *scn = sc->ol_sc; + + HIF_TRACE("%s: E", __func__); + + if (ENABLE_MSI) { + ret = hif_configure_msi(sc); + if (ret == 0) + goto end; + } + /* MSI failed. Try legacy irq */ + ret = hif_pci_configure_legacy_irq(sc); + if (ret < 0) { + HIF_ERROR("%s: hif_pci_configure_legacy_irq error = %d", + __func__, ret); + return ret; + } +end: + scn->request_irq_done = true; + return 0; +} + +/** + * hif_target_sync() : ensure the target is ready + * @scn: hif controll structure + * + * Informs fw that we plan to use legacy interupts so that + * it can begin booting. Ensures that the fw finishes booting + * before continuing. Should be called before trying to write + * to the targets other registers for the first time. + * + * Return: none + */ +void hif_target_sync(struct ol_softc *scn) +{ + hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK); + + hif_write32_mb(scn->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + while (!hif_targ_is_awake(scn, scn->mem)) + ; + + if (HAS_FW_INDICATOR) { + int wait_limit = 500; + int fw_ind = 0; + HIF_TRACE("%s: Loop checking FW signal", __func__); + while (1) { + fw_ind = hif_read32_mb(scn->hif_sc->mem + + FW_INDICATOR_ADDRESS); + if (fw_ind & FW_IND_INITIALIZED) + break; + if (wait_limit-- < 0) + break; + hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK); + + cdf_mdelay(10); + } + if (wait_limit < 0) + HIF_TRACE("%s: FW signal timed out", + __func__); + else + HIF_TRACE("%s: Got FW signal, retries = %x", + __func__, 500-wait_limit); + } + hif_write32_mb(scn->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); +} + +/** + * hif_enable_bus(): enable bus + * + * This function enables the bus + * + * @ol_sc: soft_sc struct + * @dev: device pointer + * @bdev: bus dev pointer + * bid: bus id pointer + * type: enum hif_enable_type such as HIF_ENABLE_TYPE_PROBE + * Return: CDF_STATUS + */ +CDF_STATUS hif_enable_bus(struct ol_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret = 0; + uint32_t hif_type, target_type; + struct hif_pci_softc *sc; + uint16_t revision_id; + uint32_t lcr_val; + int probe_again = 0; + struct pci_dev *pdev = bdev; + const struct pci_device_id *id = bid; + + HIF_TRACE("%s: con_mode = 0x%x, device_id = 0x%x", + __func__, cds_get_conparam(), id->device); + + ol_sc = cds_get_context(CDF_MODULE_ID_HIF); + if (!ol_sc) { + HIF_ERROR("%s: hif_ctx is NULL", __func__); + return CDF_STATUS_E_NOMEM; + } + sc = ol_sc->hif_sc; + ol_sc->aps_osdev.bdev = pdev; + + sc->pdev = pdev; + sc->dev = &pdev->dev; + ol_sc->aps_osdev.bdev = pdev; + ol_sc->aps_osdev.device = &pdev->dev; + ol_sc->aps_osdev.bc.bc_handle = (void *)ol_sc->mem; + ol_sc->aps_osdev.bc.bc_bustype = type; + sc->devid = id->device; + sc->cacheline_sz = dma_get_cache_alignment(); +again: + ret = hif_enable_pci(sc, pdev, id); + if (ret < 0) { + HIF_ERROR("%s: ERROR - hif_enable_pci error = %d", + __func__, ret); + goto err_enable_pci; + } + HIF_TRACE("%s: hif_enable_pci done", __func__); + + /* Temporary FIX: disable ASPM on peregrine. + * Will be removed after the OTP is programmed + */ + pci_read_config_dword(pdev, 0x80, &lcr_val); + pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00)); + + device_disable_async_suspend(&pdev->dev); + pci_read_config_word(pdev, 0x08, &revision_id); + + ret = hif_get_device_type(id->device, revision_id, + &hif_type, &target_type); + if (ret < 0) { + HIF_ERROR("%s: invalid device id/revision_id", __func__); + goto err_tgtstate; + } + HIF_TRACE("%s: hif_type = 0x%x, target_type = 0x%x", + __func__, hif_type, target_type); + + hif_register_tbl_attach(sc->ol_sc, hif_type); + target_register_tbl_attach(sc->ol_sc, target_type); + + ret = hif_pci_probe_tgt_wakeup(sc); + if (ret < 0) { + HIF_ERROR("%s: ERROR - hif_pci_prob_wakeup error = %d", + __func__, ret); + if (ret == -EAGAIN) + probe_again++; + goto err_tgtstate; + } + HIF_TRACE("%s: hif_pci_probe_tgt_wakeup done", __func__); + + ol_sc->target_type = target_type; + sc->soc_pcie_bar0 = pci_resource_start(pdev, BAR_NUM); + if (!sc->soc_pcie_bar0) { + HIF_ERROR("%s: ERROR - cannot get CE BAR0", __func__); + ret = -EIO; + goto err_tgtstate; + } + ol_sc->mem_pa = sc->soc_pcie_bar0; + + BUG_ON(pci_get_drvdata(sc->pdev) != NULL); + pci_set_drvdata(sc->pdev, sc); + + ret = hif_init_cdf_ctx(ol_sc); + if (ret != 0) { + HIF_ERROR("%s: cannot init CDF", __func__); + goto err_tgtstate; + } + + hif_target_sync(ol_sc); + return 0; + +err_tgtstate: + hif_deinit_cdf_ctx(ol_sc); + hif_disable_pci(sc); + sc->pci_enabled = false; + HIF_ERROR("%s: error, hif_disable_pci done", __func__); + return CDF_STATUS_E_ABORTED; + +err_enable_pci: + if (probe_again && (probe_again <= ATH_PCI_PROBE_RETRY_MAX)) { + int delay_time; + + HIF_INFO("%s: pci reprobe", __func__); + /* 10, 40, 90, 100, 100, ... */ + delay_time = max(100, 10 * (probe_again * probe_again)); + cdf_mdelay(delay_time); + goto again; + } + return ret; +} + +/** + * hif_get_target_type(): Get the target type + * + * This function is used to query the target type. + * + * @ol_sc: ol_softc struct pointer + * @dev: device pointer + * @bdev: bus dev pointer + * @bid: bus id pointer + * @hif_type: HIF type such as HIF_TYPE_QCA6180 + * @target_type: target type such as TARGET_TYPE_QCA6180 + * + * Return: 0 for success + */ +int hif_get_target_type(struct ol_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, uint32_t *hif_type, + uint32_t *target_type) +{ + uint16_t revision_id; + struct pci_dev *pdev = bdev; + const struct pci_device_id *id = bid; + + pci_read_config_word(pdev, 0x08, &revision_id); + return hif_get_device_type(id->device, revision_id, + hif_type, target_type); +} diff --git a/core/hif/src/pcie/if_pci.h b/core/hif/src/pcie/if_pci.h new file mode 100644 index 0000000000..b2f5bd6c20 --- /dev/null +++ b/core/hif/src/pcie/if_pci.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __ATH_PCI_H__ +#define __ATH_PCI_H__ + +#include +#include +#include + +#define ATH_DBG_DEFAULT 0 +#include +#include +#include +#include "osapi_linux.h" +#include "hif.h" +#include "cepci.h" + +struct CE_state; +struct ol_softc; + +/* An address (e.g. of a buffer) in Copy Engine space. */ + +#define HIF_MAX_TASKLET_NUM 11 +struct hif_tasklet_entry { + uint8_t id; /* 0 - 9: maps to CE, 10: fw */ + void *hif_handler; /* struct hif_pci_softc */ +}; +struct hif_pci_softc { + void __iomem *mem; /* PCI address. */ + /* For efficiency, should be first in struct */ + + struct device *dev; + struct pci_dev *pdev; + struct ol_softc *ol_sc; + int num_msi_intrs; /* number of MSI interrupts granted */ + /* 0 --> using legacy PCI line interrupts */ + struct tasklet_struct intr_tq; /* tasklet */ + + + int irq; + int irq_event; + int cacheline_sz; + u16 devid; + cdf_dma_addr_t soc_pcie_bar0; + struct hif_tasklet_entry tasklet_entries[HIF_MAX_TASKLET_NUM]; + bool pci_enabled; +}; + +bool hif_pci_targ_is_present(struct ol_softc *scn, void *__iomem *mem); +void icnss_dispatch_ce_irq(struct ol_softc *scn); +int hif_configure_irq(struct hif_pci_softc *sc); +void hif_pci_cancel_deferred_target_sleep(struct ol_softc *scn); + +/* + * A firmware interrupt to the Host is indicated by the + * low bit of SCRATCH_3_ADDRESS being set. + */ +#define FW_EVENT_PENDING_REG_ADDRESS SCRATCH_3_ADDRESS + +/* + * Typically, MSI Interrupts are used with PCIe. To force use of legacy + * "ABCD" PCI line interrupts rather than MSI, define + * FORCE_LEGACY_PCI_INTERRUPTS. + * Even when NOT forced, the driver may attempt to use legacy PCI interrupts + * MSI allocation fails + */ +#define LEGACY_INTERRUPTS(sc) ((sc)->num_msi_intrs == 0) + +/* + * There may be some pending tx frames during platform suspend. + * Suspend operation should be delayed until those tx frames are + * transfered from the host to target. This macro specifies how + * long suspend thread has to sleep before checking pending tx + * frame count. + */ +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 /* ms */ + +#define HIF_CE_DRAIN_WAIT_DELAY 10 /* ms */ +/* + * Wait time (in unit of OL_ATH_TX_DRAIN_WAIT_DELAY) for pending + * tx frame completion before suspend. Refer: hif_pci_suspend() + */ +#ifndef QCA_WIFI_3_0_EMU +#define OL_ATH_TX_DRAIN_WAIT_CNT 10 +#else +#define OL_ATH_TX_DRAIN_WAIT_CNT 60 +#endif + +#define HIF_CE_DRAIN_WAIT_CNT 20 +#endif /* __ATH_PCI_H__ */ diff --git a/core/hif/src/pcie/if_pci_internal.h b/core/hif/src/pcie/if_pci_internal.h new file mode 100644 index 0000000000..e5f28d2b27 --- /dev/null +++ b/core/hif/src/pcie/if_pci_internal.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __IF_PCI_INTERNAL_H__ +#define __IF_PCI_INTERNAL_H__ +#ifdef CONFIG_CNSS +#define HIF_REGISTER_DRIVER(wlan_drv_id) \ + cnss_wlan_register_driver(wlan_drv_id) +#define HIF_UNREGISTER_DRIVER(wlan_drv_id) \ + cnss_wlan_unregister_driver(wlan_drv_id) +#else +#define HIF_REGISTER_DRIVER(wlan_drv_id) \ + pci_register_driver(wlan_drv_id) +#define HIF_UNREGISTER_DRIVER(wlan_drv_id) \ + pci_unregister_driver(wlan_drv_id) +#endif + +#ifdef DISABLE_L1SS_STATES +#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr) \ +{ \ + uint32_t lcr_val; \ + pci_read_config_dword(pdev, addr, &lcr_val); \ + pci_write_config_dword(pdev, addr, (lcr_val & ~0x0000000f)); \ +} +#else +#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr) +#endif + +#if defined(CONFIG_CNSS) && !defined(QCA_WIFI_3_0) +#define GET_VIRT_RAMDUMP_MEM(ol_sc) \ +{ \ + ol_sc->ramdump_base = cnss_get_virt_ramdump_mem(&ol_sc->ramdump_size); \ + if (ol_sc->ramdump_base == NULL || !ol_sc->ramdump_size) \ + HIF_ERROR("%s: Failed to get RAM dump memory addr or size!", \ + __func__); \ +} +#else +#define GET_VIRT_RAMDUMP_MEM(ol_sc) +#endif + +#ifdef QCA_WIFI_3_0 +#define PCI_CLR_CAUSE0_REGISTER(sc) \ +{ \ + uint32_t tmp_cause0; \ + tmp_cause0 = hif_read32_mb(sc->mem + PCIE_INTR_CAUSE_ADDRESS); \ + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, \ + PCIE_INTR_FIRMWARE_MASK | tmp_cause0); \ + hif_read32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS); \ + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, 0); \ + hif_read32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS); \ +} + +#define HIF_PCI_TARG_IS_AWAKE(scn, mem) \ +{ \ + return 1; \ +} +#else +#define PCI_CLR_CAUSE0_REGISTER(sc) + +#define HIF_PCI_TARG_IS_AWAKE(scn, mem) \ +{ \ + uint32_t val; \ + if (scn->recovery) \ + return false; \ + val = hif_read32_mb(mem + PCIE_LOCAL_BASE_ADDRESS \ + + RTC_STATE_ADDRESS); \ + return RTC_STATE_V_GET(val) == RTC_STATE_V_ON; \ +} +#endif + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) +#define PKT_LOG_MOD_INIT(ol_sc) \ +{ \ + ol_txrx_pdev_handle pdev_txrx_handle; \ + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); \ + if (cds_get_conparam() != CDF_FTM_MODE && \ + !WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { \ + ol_pl_sethandle(&pdev_txrx_handle->pl_dev, ol_sc); \ + if (pktlogmod_init(ol_sc)) \ + HIF_ERROR("%s: pktlogmod_init failed", __func__); \ + } \ +} +#else +#define PKT_LOG_MOD_INIT(ol_sc) +#endif +#endif /* __IF_PCI_INTERNAL_H__ */ diff --git a/core/hif/src/qca6180def.h b/core/hif/src/qca6180def.h new file mode 100644 index 0000000000..cdfc2a3256 --- /dev/null +++ b/core/hif/src/qca6180def.h @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _QCA6180DEF_H_ +#define _QCA6180DEF_H_ + +#define MISSING 0 +#define _PCIE_LOCAL_REG_BASE_ADDRESS 0x1E8000 +#define _WIFI_RTC_REG_BASE_ADDRESS 0x45000 +#define _RTC_SOC_REG_BASE_ADDRESS 0x113000 +#define _GPIO_ATHR_WLAN_REG_BASE_ADDRESS 0x85000 +#define _SI_REG_BASE_ADDRESS 0x84000 +#define _SOC_CORE_REG_BASE_ADDRESS 0x113000 +#define _CE_REG_CSR_BASE_ADDRESS 0x240000 +#define _CE0_CE_REG_CSR_BASE_ADDRESS 0 +#define _CE_WRAPPER_REG_CSR_BASE_ADDRESS 0xC000 +#define _MAC_WIFICMN_REG_BASE_ADDRESS MISSING + +/* Base Addresses */ +#define QCA6180_RTC_SOC_BASE_ADDRESS 0x00000000 +#define QCA6180_RTC_WMAC_BASE_ADDRESS 0x00000000 +#define QCA6180_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define QCA6180_BT_COEX_BASE_ADDRESS 0x00002000 +#define QCA6180_SOC_PCIE_BASE_ADDRESS 0x00130000 +#define QCA6180_SOC_CORE_BASE_ADDRESS 0x00000000 +#define QCA6180_WLAN_UART_BASE_ADDRESS 0x00111000 +#define QCA6180_WLAN_SI_BASE_ADDRESS 0x00010000 +#define QCA6180_WLAN_GPIO_BASE_ADDRESS 0x00000000 +#define QCA6180_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00000000 +#define QCA6180_WLAN_MAC_BASE_ADDRESS 0x00000000 +#define QCA6180_EFUSE_BASE_ADDRESS 0x00024000 +#define QCA6180_FPGA_REG_BASE_ADDRESS 0x00039000 +#define QCA6180_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define QCA6180_CE_WRAPPER_BASE_ADDRESS 0x24C000 +#define QCA6180_CE0_BASE_ADDRESS 0x240000 +#define QCA6180_CE1_BASE_ADDRESS 0x241000 +#define QCA6180_CE2_BASE_ADDRESS 0x242000 +#define QCA6180_CE3_BASE_ADDRESS 0x243000 +#define QCA6180_CE4_BASE_ADDRESS 0x244000 +#define QCA6180_CE5_BASE_ADDRESS 0x245000 +#define QCA6180_CE6_BASE_ADDRESS 0x246000 +#define QCA6180_CE7_BASE_ADDRESS 0x247000 +#define QCA6180_CE8_BASE_ADDRESS 0x248000 +#define QCA6180_CE9_BASE_ADDRESS 0x249000 +#define QCA6180_CE10_BASE_ADDRESS 0x24A000 +#define QCA6180_CE11_BASE_ADDRESS 0x24B000 +#define QCA6180_A_SOC_PCIE_SOC_PCIE_REG 0x130000 +#define QCA6180_DBI_BASE_ADDRESS 0x0003c000 +#define QCA6180_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x00007800 +#define QCA6180_WIFICMN_BASE_ADDRESS 0x00000000 +#define QCA6180_BOARD_DATA_SZ MISSING +#define QCA6180_BOARD_EXT_DATA_SZ MISSING +#define QCA6180_A_SOC_PCIE_PCIE_BAR0_START \ + (0x030 + QCA6180_A_SOC_PCIE_SOC_PCIE_REG) +#define QCA6180_A_SOC_CORE_SCRATCH_0_ADDRESS 0x00114000 +#define QCA6180_A_SOC_CORE_SCRATCH_1_ADDRESS 0x00114004 +#define QCA6180_A_SOC_CORE_SCRATCH_2_ADDRESS 0x00114008 +#define QCA6180_A_SOC_CORE_SCRATCH_3_ADDRESS 0x0011400c +#define QCA6180_A_SOC_CORE_SCRATCH_4_ADDRESS 0x00114010 +#define QCA6180_A_SOC_CORE_SCRATCH_5_ADDRESS 0x00114014 +#define QCA6180_A_SOC_CORE_SCRATCH_6_ADDRESS 0x00114018 +#define QCA6180_A_SOC_CORE_SCRATCH_7_ADDRESS 0x0011401c +#define QCA6180_A_SOC_CORE_SPARE_0_REGISTER 0x00113180 +#define QCA6180_PCIE_INTR_FIRMWARE_ROUTE_MASK 0xff +#define QCA6180_SCRATCH_3_ADDRESS 0x00113020 +#define QCA6180_TARG_DRAM_START 0x00400000 +#define QCA6180_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define QCA6180_SOC_RESET_CONTROL_OFFSET \ + (0x00000000 + _RTC_SOC_REG_BASE_ADDRESS) +#define QCA6180_SOC_CLOCK_CONTROL_OFFSET \ + (0x00000028 + _RTC_SOC_REG_BASE_ADDRESS) +#define QCA6180_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define QCA6180_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define QCA6180_WLAN_GPIO_PIN0_ADDRESS \ + (0x50 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN1_ADDRESS \ + (0x54 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define QCA6180_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define QCA6180_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define QCA6180_SOC_LPO_CAL_OFFSET \ + (0xe0 + _RTC_SOC_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN10_ADDRESS \ + (0x78 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN11_ADDRESS \ + (0x7c + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN12_ADDRESS \ + (0x80 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_WLAN_GPIO_PIN13_ADDRESS \ + (0x84 + _GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define QCA6180_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define QCA6180_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define QCA6180_SOC_LPO_CAL_ENABLE_LSB 20 +#define QCA6180_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define QCA6180_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define QCA6180_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define QCA6180_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000002 +#define QCA6180_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000001 +#define QCA6180_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define QCA6180_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define QCA6180_SI_CONFIG_I2C_LSB 16 +#define QCA6180_SI_CONFIG_I2C_MASK 0x00010000 +#define QCA6180_SI_CONFIG_POS_SAMPLE_LSB 7 +#define QCA6180_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define QCA6180_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define QCA6180_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define QCA6180_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define QCA6180_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define QCA6180_SI_CONFIG_DIVIDER_LSB 0 +#define QCA6180_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define QCA6180_SI_CONFIG_OFFSET (0x00000000 + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_TX_DATA0_OFFSET (0x00000008 + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_TX_DATA1_OFFSET (0x0000000c + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_RX_DATA0_OFFSET (0x00000010 + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_RX_DATA1_OFFSET (0x00000014 + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_CS_OFFSET (0x00000004 + _SI_REG_BASE_ADDRESS) +#define QCA6180_SI_CS_DONE_ERR_MASK 0x00000400 +#define QCA6180_SI_CS_DONE_INT_MASK 0x00000200 +#define QCA6180_SI_CS_START_LSB 8 +#define QCA6180_SI_CS_START_MASK 0x00000100 +#define QCA6180_SI_CS_RX_CNT_LSB 4 +#define QCA6180_SI_CS_RX_CNT_MASK 0x000000f0 +#define QCA6180_SI_CS_TX_CNT_LSB 0 +#define QCA6180_SI_CS_TX_CNT_MASK 0x0000000f +#define QCA6180_CE_COUNT 8 +#define QCA6180_SR_WR_INDEX_ADDRESS (0x003C + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_DST_WATERMARK_ADDRESS (0x0050 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define QCA6180_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define QCA6180_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define QCA6180_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define QCA6180_RX_MPDU_START_2_PN_47_32_LSB 0 +#define QCA6180_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define QCA6180_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define QCA6180_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define QCA6180_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define QCA6180_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define QCA6180_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define QCA6180_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define QCA6180_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define QCA6180_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define QCA6180_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define QCA6180_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define QCA6180_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define QCA6180_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define QCA6180_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff + +#define QCA6180_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define QCA6180_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define QCA6180_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define QCA6180_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define QCA6180_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define QCA6180_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define QCA6180_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define QCA6180_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define QCA6180_DST_WR_INDEX_ADDRESS (0x0040 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_SRC_WATERMARK_ADDRESS (0x004c + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define QCA6180_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define QCA6180_DST_WATERMARK_LOW_MASK 0xffff0000 +#define QCA6180_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define QCA6180_CURRENT_SRRI_ADDRESS (0x0044 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CURRENT_DRRI_ADDRESS (0x0048 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define QCA6180_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define QCA6180_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define QCA6180_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define QCA6180_HOST_IS_ADDRESS (0x0030 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_MISC_IS_ADDRESS (0x0038 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define QCA6180_CE_WRAPPER_INDEX_BASE_LOW 0x0004 +#define QCA6180_CE_WRAPPER_INDEX_BASE_HIGH 0x0008 +#define QCA6180_HOST_IE_ADDRESS (0x002C + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define QCA6180_SR_BA_ADDRESS (0x0000 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_SR_BA_ADDRESS_HIGH (0x0004 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_SR_SIZE_ADDRESS (0x0008 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_CTRL1_ADDRESS (0x0018 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define QCA6180_DR_BA_ADDRESS (0x000C + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_DR_BA_ADDRESS_HIGH (0x000C + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_DR_SIZE_ADDRESS (0x0014 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_CMD_REGISTER (0x0020 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_MSI_ADDRESS (0x0058 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_MSI_ADDRESS_HIGH (0x005C + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_MSI_DATA (0x0060 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_CE_MSI_ENABLE_BIT 16 +#define QCA6180_MISC_IE_ADDRESS (0x0034 + _CE0_CE_REG_CSR_BASE_ADDRESS) +#define QCA6180_MISC_IS_AXI_ERR_MASK 0x00000100 +#define QCA6180_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define QCA6180_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define QCA6180_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define QCA6180_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define QCA6180_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define QCA6180_WRAPPER_INTERRUPT_SUMMARY_ADDR 0x0024D000 +#define QCA6180_SRC_WATERMARK_LOW_LSB 16 +#define QCA6180_SRC_WATERMARK_HIGH_LSB 0 +#define QCA6180_DST_WATERMARK_LOW_LSB 16 +#define QCA6180_DST_WATERMARK_HIGH_LSB 0 +#define QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0xfff000 +#define QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 12 +#define QCA6180_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define QCA6180_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define QCA6180_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00040000 +#define QCA6180_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 17 +#define QCA6180_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 18 +#define QCA6180_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x0000004 +#define QCA6180_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define QCA6180_SOC_GLOBAL_RESET_ADDRESS \ + (0x0008 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_RTC_STATE_ADDRESS \ + (0x0000 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_RTC_STATE_COLD_RESET_MASK 0x400 + +#define QCA6180_PCIE_SOC_WAKE_RESET 0x00000000 +#define QCA6180_PCIE_SOC_WAKE_ADDRESS (0x0004 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_PCIE_SOC_WAKE_V_MASK 0x00000001 + +#define QCA6180_RTC_STATE_V_MASK 0x00000007 +#define QCA6180_RTC_STATE_V_LSB 0 +#define QCA6180_RTC_STATE_V_ON 5 +#define QCA6180_PCIE_LOCAL_BASE_ADDRESS 0x0 +#define QCA6180_FW_IND_EVENT_PENDING 1 +#define QCA6180_FW_IND_INITIALIZED 2 +#define QCA6180_FW_IND_HELPER 4 + +#define QCA6180_PCIE_INTR_ENABLE_ADDRESS (0x000c + _SOC_CORE_REG_BASE_ADDRESS) +#define QCA6180_PCIE_INTR_CLR_ADDRESS (0x001c + _SOC_CORE_REG_BASE_ADDRESS) +#define QCA6180_PCIE_INTR_FIRMWARE_MASK 0x00100000 +#define QCA6180_PCIE_INTR_CE0_MASK 0x00000100 +#define QCA6180_PCIE_INTR_CE_MASK_ALL 0x0000ff00 +#define QCA6180_PCIE_INTR_CAUSE_ADDRESS (0x0014 + _SOC_CORE_REG_BASE_ADDRESS) + +#define QCA6180_CPU_INTR_ADDRESS 0xffffffff +#define QCA6180_SOC_LF_TIMER_CONTROL0_ADDRESS 0xffffffff +#define QCA6180_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0xffffffff +#define QCA6180_SOC_RESET_CONTROL_ADDRESS \ + (0x00000000 + _RTC_SOC_REG_BASE_ADDRESS) +#define QCA6180_SOC_RESET_CONTROL_CE_RST_MASK 0x0100 +#define QCA6180_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define QCA6180_CORE_CTRL_ADDRESS (0x0000 + _SOC_CORE_REG_BASE_ADDRESS) +#define QCA6180_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define QCA6180_LOCAL_SCRATCH_OFFSET 0x00000018 +#define QCA6180_CLOCK_GPIO_OFFSET 0xffffffff +#define QCA6180_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define QCA6180_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define QCA6180_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define QCA6180_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define QCA6180_SOC_CHIP_ID_VERSION_LSB 18 +#define QCA6180_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define QCA6180_SOC_CHIP_ID_REVISION_LSB 8 +#define QCA6180_SOC_POWER_REG_OFFSET 0x0000010c + +/* Copy Engine Debug */ +#define QCA6180_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define QCA6180_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define QCA6180_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define QCA6180_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define QCA6180_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define QCA6180_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define QCA6180_WLAN_DEBUG_OUT_DATA_MSB 19 +#define QCA6180_WLAN_DEBUG_OUT_DATA_LSB 0 +#define QCA6180_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define QCA6180_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define QCA6180_AMBA_DEBUG_BUS_SEL_MSB 4 +#define QCA6180_AMBA_DEBUG_BUS_SEL_LSB 0 +#define QCA6180_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define QCA6180_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define QCA6180_CE_WRAPPER_DEBUG_SEL_MSB 4 +#define QCA6180_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define QCA6180_CE_WRAPPER_DEBUG_SEL_MASK 0x0000001f +#define QCA6180_CE_DEBUG_OFFSET 0x0054 +#define QCA6180_CE_DEBUG_SEL_MSB 5 +#define QCA6180_CE_DEBUG_SEL_LSB 0 +#define QCA6180_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define QCA6180_EFUSE_OFFSET 0x0000032c +#define QCA6180_EFUSE_XTAL_SEL_MSB 10 +#define QCA6180_EFUSE_XTAL_SEL_LSB 8 +#define QCA6180_EFUSE_XTAL_SEL_MASK 0x00000700 +#define QCA6180_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define QCA6180_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define QCA6180_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define QCA6180_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define QCA6180_BB_PLL_CONFIG_FRAC_MSB 17 +#define QCA6180_BB_PLL_CONFIG_FRAC_LSB 0 +#define QCA6180_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define QCA6180_WLAN_PLL_SETTLE_TIME_MSB 10 +#define QCA6180_WLAN_PLL_SETTLE_TIME_LSB 0 +#define QCA6180_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define QCA6180_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define QCA6180_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define QCA6180_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define QCA6180_WLAN_PLL_SETTLE_RESET 0x00000400 +#define QCA6180_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define QCA6180_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define QCA6180_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define QCA6180_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define QCA6180_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define QCA6180_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define QCA6180_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define QCA6180_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define QCA6180_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define QCA6180_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define QCA6180_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define QCA6180_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define QCA6180_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define QCA6180_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define QCA6180_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define QCA6180_WLAN_PLL_CONTROL_DIV_MSB 9 +#define QCA6180_WLAN_PLL_CONTROL_DIV_LSB 0 +#define QCA6180_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define QCA6180_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define QCA6180_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define QCA6180_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define QCA6180_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define QCA6180_WLAN_PLL_CONTROL_RESET 0x00010011 +#define QCA6180_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define QCA6180_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define QCA6180_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define QCA6180_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define QCA6180_RTC_SYNC_STATUS_OFFSET 0x0244 +#define QCA6180_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define QCA6180_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define QCA6180_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define QCA6180_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define QCA6180_PCIE_INTR_CE_MASK(n) (QCA6180_PCIE_INTR_CE0_MASK << (n)) +#define QCA6180_DRAM_BASE_ADDRESS QCA6180_TARG_DRAM_START +#define QCA6180_FW_INDICATOR_ADDRESS \ + (QCA6180_WIFICMN_BASE_ADDRESS + QCA6180_SCRATCH_3_ADDRESS) +#define QCA6180_SYSTEM_SLEEP_OFFSET QCA6180_SOC_SYSTEM_SLEEP_OFFSET +#define QCA6180_WLAN_SYSTEM_SLEEP_OFFSET (0x002c + _WIFI_RTC_REG_BASE_ADDRESS) +#define QCA6180_WLAN_RESET_CONTROL_OFFSET (0x0000 + _WIFI_RTC_REG_BASE_ADDRESS) +#define QCA6180_CLOCK_CONTROL_OFFSET QCA6180_SOC_CLOCK_CONTROL_OFFSET +#define QCA6180_CLOCK_CONTROL_SI0_CLK_MASK \ + QCA6180_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define QCA6180_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define QCA6180_RESET_CONTROL_SI0_RST_MASK \ + QCA6180_SOC_RESET_CONTROL_SI0_RST_MASK +#define QCA6180_GPIO_BASE_ADDRESS QCA6180_WLAN_GPIO_BASE_ADDRESS +#define QCA6180_GPIO_PIN0_OFFSET QCA6180_WLAN_GPIO_PIN0_ADDRESS +#define QCA6180_GPIO_PIN1_OFFSET QCA6180_WLAN_GPIO_PIN1_ADDRESS +#define QCA6180_GPIO_PIN0_CONFIG_MASK QCA6180_WLAN_GPIO_PIN0_CONFIG_MASK +#define QCA6180_GPIO_PIN1_CONFIG_MASK QCA6180_WLAN_GPIO_PIN1_CONFIG_MASK +#define QCA6180_SI_BASE_ADDRESS 0x00000000 +#define QCA6180_CPU_CLOCK_OFFSET (0x20 + _RTC_SOC_REG_BASE_ADDRESS) +#define QCA6180_LPO_CAL_OFFSET QCA6180_SOC_LPO_CAL_OFFSET +#define QCA6180_GPIO_PIN10_OFFSET QCA6180_WLAN_GPIO_PIN10_ADDRESS +#define QCA6180_GPIO_PIN11_OFFSET QCA6180_WLAN_GPIO_PIN11_ADDRESS +#define QCA6180_GPIO_PIN12_OFFSET QCA6180_WLAN_GPIO_PIN12_ADDRESS +#define QCA6180_GPIO_PIN13_OFFSET QCA6180_WLAN_GPIO_PIN13_ADDRESS +#define QCA6180_CPU_CLOCK_STANDARD_LSB 0 +#define QCA6180_CPU_CLOCK_STANDARD_MASK 0x1 +#define QCA6180_LPO_CAL_ENABLE_LSB QCA6180_SOC_LPO_CAL_ENABLE_LSB +#define QCA6180_LPO_CAL_ENABLE_MASK QCA6180_SOC_LPO_CAL_ENABLE_MASK +#define QCA6180_ANALOG_INTF_BASE_ADDRESS QCA6180_WLAN_ANALOG_INTF_BASE_ADDRESS +#define QCA6180_MBOX_BASE_ADDRESS 0x00008000 +#define QCA6180_INT_STATUS_ENABLE_ERROR_LSB MISSING +#define QCA6180_INT_STATUS_ENABLE_ERROR_MASK MISSING +#define QCA6180_INT_STATUS_ENABLE_CPU_LSB MISSING +#define QCA6180_INT_STATUS_ENABLE_CPU_MASK MISSING +#define QCA6180_INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define QCA6180_INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define QCA6180_INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define QCA6180_INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define QCA6180_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define QCA6180_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define QCA6180_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define QCA6180_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define QCA6180_COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define QCA6180_COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define QCA6180_INT_STATUS_ENABLE_ADDRESS MISSING +#define QCA6180_CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define QCA6180_CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define QCA6180_HOST_INT_STATUS_ADDRESS MISSING +#define QCA6180_CPU_INT_STATUS_ADDRESS MISSING +#define QCA6180_ERROR_INT_STATUS_ADDRESS MISSING +#define QCA6180_ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define QCA6180_ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define QCA6180_ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define QCA6180_ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define QCA6180_ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define QCA6180_ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define QCA6180_COUNT_DEC_ADDRESS MISSING +#define QCA6180_HOST_INT_STATUS_CPU_MASK MISSING +#define QCA6180_HOST_INT_STATUS_CPU_LSB MISSING +#define QCA6180_HOST_INT_STATUS_ERROR_MASK MISSING +#define QCA6180_HOST_INT_STATUS_ERROR_LSB MISSING +#define QCA6180_HOST_INT_STATUS_COUNTER_MASK MISSING +#define QCA6180_HOST_INT_STATUS_COUNTER_LSB MISSING +#define QCA6180_RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define QCA6180_WINDOW_DATA_ADDRESS MISSING +#define QCA6180_WINDOW_READ_ADDR_ADDRESS MISSING +#define QCA6180_WINDOW_WRITE_ADDR_ADDRESS MISSING +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_0 \ + (0x0024 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_1 \ + (0x0028 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_2 \ + (0x002C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_3 \ + (0x0030 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_4 \ + (0x0034 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_5 \ + (0x0038 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_6 \ + (0x003C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_7 \ + (0x0040 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_8 \ + (0x0044 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_9 \ + (0x0048 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_10 \ + (0x004C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_11 \ + (0x0050 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_12 \ + (0x0054 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_13 \ + (0x0058 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_14 \ + (0x005C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_15 \ + (0x0060 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_16 \ + (0x0064 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_17 \ + (0x0068 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_18 \ + (0x006C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_19 \ + (0x0070 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_20 \ + (0x0074 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_21 \ + (0x0078 + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_22 \ + (0x007C + _PCIE_LOCAL_REG_BASE_ADDRESS) +#define QCA6180_A_LOCAL_SHADOW_REG_VALUE_23 \ + (0x0080 + _PCIE_LOCAL_REG_BASE_ADDRESS) + + +/* Q6 iHelium emulation registers */ +#define QCA6180_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 0x00113018 +#define QCA6180_A_SOC_CORE_SPARE_1_REGISTER 0x00113184 +#define QCA6180_A_SOC_CORE_PCIE_INTR_CLR_GRP1 0x00113020 +#define QCA6180_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 0x00113010 +#define QCA6180_A_SOC_PCIE_PCIE_SCRATCH_0 0x00130040 +#define QCA6180_A_SOC_PCIE_PCIE_SCRATCH_1 0x00130044 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE0_TARGET_IE 0x00240024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE0_TARGET_IS 0x00240028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE1_TARGET_IE 0x00241024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE1_TARGET_IS 0x00241028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE2_TARGET_IE 0x00242024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE2_TARGET_IS 0x00242028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE3_TARGET_IE 0x00243024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE3_TARGET_IS 0x00243028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE4_TARGET_IE 0x00244024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE4_TARGET_IS 0x00244028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE5_TARGET_IE 0x00245024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE5_TARGET_IS 0x00245028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE6_TARGET_IE 0x00246024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE6_TARGET_IS 0x00246028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE7_TARGET_IE 0x00247024 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE7_TARGET_IS 0x00247028 +#define QCA6180_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA 0x08 +#define QCA6180_A_SOC_PCIE_PCIE_SCRATCH_2 0x0013005C +#define QCA6180_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK 0x0 +/* end: Q6 iHelium emulation registers */ + +struct targetdef_s qca6180_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = QCA6180_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = QCA6180_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = QCA6180_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = QCA6180_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + QCA6180_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + QCA6180_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = QCA6180_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = QCA6180_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = QCA6180_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = QCA6180_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = QCA6180_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = QCA6180_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + QCA6180_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + QCA6180_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = QCA6180_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = QCA6180_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = QCA6180_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = QCA6180_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = QCA6180_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = QCA6180_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = QCA6180_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = QCA6180_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = QCA6180_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = QCA6180_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = QCA6180_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = QCA6180_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = QCA6180_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = QCA6180_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = QCA6180_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = QCA6180_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = QCA6180_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = QCA6180_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = QCA6180_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = QCA6180_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = QCA6180_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = QCA6180_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = QCA6180_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = QCA6180_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = QCA6180_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = QCA6180_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = QCA6180_SI_CS_START_LSB, + .d_SI_CS_START_MASK = QCA6180_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = QCA6180_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = QCA6180_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = QCA6180_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = QCA6180_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = QCA6180_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = QCA6180_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = QCA6180_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = QCA6180_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = QCA6180_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = QCA6180_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = QCA6180_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = QCA6180_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = QCA6180_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = QCA6180_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = QCA6180_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = QCA6180_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = QCA6180_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = QCA6180_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = QCA6180_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = QCA6180_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + QCA6180_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = QCA6180_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = QCA6180_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = QCA6180_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = QCA6180_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = QCA6180_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = QCA6180_CORE_CTRL_ADDRESS, + .d_CE_COUNT = QCA6180_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = QCA6180_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = QCA6180_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = QCA6180_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = QCA6180_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = QCA6180_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = QCA6180_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = QCA6180_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + QCA6180_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = QCA6180_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = QCA6180_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = QCA6180_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = QCA6180_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + QCA6180_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + QCA6180_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + QCA6180_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = QCA6180_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = QCA6180_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + QCA6180_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + QCA6180_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = QCA6180_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = QCA6180_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + QCA6180_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + QCA6180_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + QCA6180_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + QCA6180_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + QCA6180_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + QCA6180_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + QCA6180_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + QCA6180_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + QCA6180_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + QCA6180_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + QCA6180_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + QCA6180_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + QCA6180_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + + /* PLL start */ + .d_EFUSE_OFFSET = QCA6180_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = QCA6180_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = QCA6180_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = QCA6180_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = QCA6180_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = QCA6180_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = QCA6180_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = QCA6180_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = QCA6180_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = QCA6180_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = QCA6180_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = QCA6180_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = QCA6180_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = QCA6180_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = QCA6180_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = QCA6180_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = QCA6180_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = QCA6180_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = QCA6180_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = QCA6180_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = QCA6180_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = QCA6180_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = QCA6180_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = QCA6180_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + QCA6180_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = QCA6180_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = QCA6180_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + QCA6180_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + QCA6180_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = QCA6180_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = QCA6180_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = QCA6180_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + QCA6180_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = QCA6180_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = QCA6180_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = QCA6180_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = QCA6180_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = QCA6180_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = QCA6180_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = QCA6180_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = QCA6180_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = QCA6180_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = QCA6180_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = QCA6180_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = QCA6180_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + QCA6180_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = QCA6180_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = QCA6180_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = QCA6180_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = QCA6180_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = QCA6180_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = QCA6180_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = QCA6180_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = QCA6180_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + QCA6180_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + QCA6180_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + QCA6180_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + QCA6180_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = QCA6180_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + QCA6180_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + QCA6180_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = QCA6180_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = QCA6180_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = QCA6180_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = QCA6180_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = QCA6180_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ + .d_A_SOC_CORE_SCRATCH_0_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_0_ADDRESS, + .d_A_SOC_CORE_SCRATCH_1_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_1_ADDRESS, + .d_A_SOC_CORE_SCRATCH_2_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_2_ADDRESS, + .d_A_SOC_CORE_SCRATCH_3_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_3_ADDRESS, + .d_A_SOC_CORE_SCRATCH_4_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_4_ADDRESS, + .d_A_SOC_CORE_SCRATCH_5_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_5_ADDRESS, + .d_A_SOC_CORE_SCRATCH_6_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_6_ADDRESS, + .d_A_SOC_CORE_SCRATCH_7_ADDRESS = QCA6180_A_SOC_CORE_SCRATCH_7_ADDRESS, + .d_A_SOC_CORE_SPARE_0_REGISTER = QCA6180_A_SOC_CORE_SPARE_0_REGISTER, + .d_PCIE_INTR_FIRMWARE_ROUTE_MASK = + QCA6180_PCIE_INTR_FIRMWARE_ROUTE_MASK, + .d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 = + QCA6180_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1, + .d_A_SOC_CORE_SPARE_1_REGISTER = + QCA6180_A_SOC_CORE_SPARE_1_REGISTER, + .d_A_SOC_CORE_PCIE_INTR_CLR_GRP1 = + QCA6180_A_SOC_CORE_PCIE_INTR_CLR_GRP1, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 = + QCA6180_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1, + .d_A_SOC_PCIE_PCIE_SCRATCH_0 = + QCA6180_A_SOC_PCIE_PCIE_SCRATCH_0, + .d_A_SOC_PCIE_PCIE_SCRATCH_1 = + QCA6180_A_SOC_PCIE_PCIE_SCRATCH_1, + .d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA = + QCA6180_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA, + .d_A_SOC_PCIE_PCIE_SCRATCH_2 = QCA6180_A_SOC_PCIE_PCIE_SCRATCH_2, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK = + QCA6180_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK, + + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = QCA6180_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + QCA6180_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = QCA6180_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + QCA6180_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + QCA6180_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + QCA6180_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = QCA6180_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = QCA6180_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = QCA6180_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = QCA6180_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = QCA6180_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + QCA6180_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = QCA6180_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = QCA6180_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = QCA6180_AMBA_DEBUG_BUS_SEL_MASK, +}; + +struct hostdef_s qca6180_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = QCA6180_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = QCA6180_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = QCA6180_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = QCA6180_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + QCA6180_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + QCA6180_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + QCA6180_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + QCA6180_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + QCA6180_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + QCA6180_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + QCA6180_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + QCA6180_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + QCA6180_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + QCA6180_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = QCA6180_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + QCA6180_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + QCA6180_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = QCA6180_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = QCA6180_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = QCA6180_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = QCA6180_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = QCA6180_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + QCA6180_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + QCA6180_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + QCA6180_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + QCA6180_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = QCA6180_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = QCA6180_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = QCA6180_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = QCA6180_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = QCA6180_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = QCA6180_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = QCA6180_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = QCA6180_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = QCA6180_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = QCA6180_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = QCA6180_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = QCA6180_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = QCA6180_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = QCA6180_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = QCA6180_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = QCA6180_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = QCA6180_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = QCA6180_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = QCA6180_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = QCA6180_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = QCA6180_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = QCA6180_FW_IND_INITIALIZED, + .d_FW_IND_HELPER = QCA6180_FW_IND_HELPER, + .d_RTC_STATE_V_ON = QCA6180_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + QCA6180_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + QCA6180_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, + .d_MUX_ID_MASK = 0xf000, + .d_TRANSACTION_ID_MASK = 0x0fff, + .d_DESC_DATA_FLAG_MASK = 0x1FFFE3E0, + .d_A_SOC_PCIE_PCIE_BAR0_START = QCA6180_A_SOC_PCIE_PCIE_BAR0_START, +}; + + +struct ce_reg_def qca6180_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = QCA6180_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = QCA6180_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = QCA6180_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = QCA6180_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = QCA6180_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = QCA6180_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = QCA6180_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = QCA6180_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + QCA6180_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + QCA6180_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + QCA6180_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + QCA6180_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = QCA6180_HOST_IS_ADDRESS, + .d_MISC_IS_ADDRESS = QCA6180_MISC_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = QCA6180_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = QCA6180_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_CE_WRAPPER_INDEX_BASE_LOW = QCA6180_CE_WRAPPER_INDEX_BASE_LOW, + .d_CE_WRAPPER_INDEX_BASE_HIGH = QCA6180_CE_WRAPPER_INDEX_BASE_HIGH, + .d_HOST_IE_ADDRESS = QCA6180_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = QCA6180_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = QCA6180_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = QCA6180_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = QCA6180_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = QCA6180_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = QCA6180_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = QCA6180_DR_SIZE_ADDRESS, + .d_CE_CMD_REGISTER = QCA6180_CE_CMD_REGISTER, + .d_CE_MSI_ADDRESS = QCA6180_CE_MSI_ADDRESS, + .d_CE_MSI_ADDRESS_HIGH = QCA6180_CE_MSI_ADDRESS_HIGH, + .d_CE_MSI_DATA = QCA6180_CE_MSI_DATA, + .d_CE_MSI_ENABLE_BIT = QCA6180_CE_MSI_ENABLE_BIT, + .d_MISC_IE_ADDRESS = QCA6180_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = QCA6180_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = QCA6180_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = QCA6180_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = QCA6180_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + QCA6180_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + QCA6180_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = QCA6180_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = QCA6180_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = QCA6180_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = QCA6180_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + QCA6180_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = QCA6180_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + QCA6180_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + QCA6180_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + QCA6180_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + QCA6180_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = QCA6180_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = QCA6180_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = QCA6180_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = QCA6180_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = QCA6180_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = QCA6180_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = QCA6180_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = QCA6180_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = QCA6180_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = QCA6180_CE1_BASE_ADDRESS, +}; + + +struct host_shadow_regs_s qca6180_host_shadow_regs = { + .d_A_LOCAL_SHADOW_REG_VALUE_0 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_0, + .d_A_LOCAL_SHADOW_REG_VALUE_1 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_1, + .d_A_LOCAL_SHADOW_REG_VALUE_2 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_2, + .d_A_LOCAL_SHADOW_REG_VALUE_3 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_3, + .d_A_LOCAL_SHADOW_REG_VALUE_4 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_4, + .d_A_LOCAL_SHADOW_REG_VALUE_5 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_5, + .d_A_LOCAL_SHADOW_REG_VALUE_6 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_6, + .d_A_LOCAL_SHADOW_REG_VALUE_7 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_7, + .d_A_LOCAL_SHADOW_REG_VALUE_8 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_8, + .d_A_LOCAL_SHADOW_REG_VALUE_9 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_9, + .d_A_LOCAL_SHADOW_REG_VALUE_10 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_10, + .d_A_LOCAL_SHADOW_REG_VALUE_11 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_11, + .d_A_LOCAL_SHADOW_REG_VALUE_12 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_12, + .d_A_LOCAL_SHADOW_REG_VALUE_13 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_13, + .d_A_LOCAL_SHADOW_REG_VALUE_14 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_14, + .d_A_LOCAL_SHADOW_REG_VALUE_15 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_15, + .d_A_LOCAL_SHADOW_REG_VALUE_16 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_16, + .d_A_LOCAL_SHADOW_REG_VALUE_17 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_17, + .d_A_LOCAL_SHADOW_REG_VALUE_18 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_18, + .d_A_LOCAL_SHADOW_REG_VALUE_19 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_19, + .d_A_LOCAL_SHADOW_REG_VALUE_20 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_20, + .d_A_LOCAL_SHADOW_REG_VALUE_21 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_21, + .d_A_LOCAL_SHADOW_REG_VALUE_22 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_22, + .d_A_LOCAL_SHADOW_REG_VALUE_23 = + QCA6180_A_LOCAL_SHADOW_REG_VALUE_23, + +}; + +#endif /* _QCA6180DEF_H_ */ diff --git a/core/hif/src/regtable.c b/core/hif/src/regtable.c new file mode 100644 index 0000000000..90d8f8ef91 --- /dev/null +++ b/core/hif/src/regtable.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "bmi_msg.h" +#include "targaddrs.h" +#include "cepci.h" +#include "regtable.h" +#include "ar9888def.h" +#include "ar6320def.h" +#include "ar6320v2def.h" +#include "qca6180def.h" +#include "ol_if_athvar.h" +#include "hif.h" +#include "adrastea_reg_def.h" + +void target_register_tbl_attach(struct ol_softc *scn, u32 target_type) +{ + switch (target_type) { + case TARGET_TYPE_AR9888: + scn->targetdef = &ar9888_targetdef; + scn->target_ce_def = &ar9888_ce_targetdef; + break; + case TARGET_TYPE_AR6320: + scn->targetdef = &ar6320_targetdef; + scn->target_ce_def = &ar6320_ce_targetdef; + break; + case TARGET_TYPE_AR6320V2: + scn->targetdef = &ar6320v2_targetdef; + scn->target_ce_def = &ar6320v2_ce_targetdef; + break; + case TARGET_TYPE_QCA6180: + scn->targetdef = &qca6180_targetdef; + scn->target_ce_def = &qca6180_ce_targetdef; + break; + case TARGET_TYPE_ADRASTEA: + scn->targetdef = &adrastea_targetdef; + scn->target_ce_def = &adrastea_ce_targetdef; + break; + default: + break; + } +} + +void hif_register_tbl_attach(struct ol_softc *scn, u32 hif_type) +{ + switch (hif_type) { + case HIF_TYPE_AR9888: + scn->hostdef = &ar9888_hostdef; + break; + case HIF_TYPE_AR6320: + scn->hostdef = &ar6320_hostdef; + break; + case HIF_TYPE_AR6320V2: + scn->hostdef = &ar6320v2_hostdef; + break; + case HIF_TYPE_QCA6180: + scn->hostdef = &qca6180_hostdef; + scn->host_shadow_regs = &qca6180_host_shadow_regs; + break; + case HIF_TYPE_ADRASTEA: + scn->hostdef = &adrastea_hostdef; + scn->host_shadow_regs = &adrastea_host_shadow_regs; + break; + default: + break; + } +} diff --git a/core/hif/src/snoc/hif_io32_snoc.h b/core/hif/src/snoc/hif_io32_snoc.h new file mode 100644 index 0000000000..8507c4b98d --- /dev/null +++ b/core/hif/src/snoc/hif_io32_snoc.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: hif_io32_snoc.h + * + * snoc specific implementations and configurations + */ + +#ifndef __HIF_IO32_SNOC_H__ +#define __HIF_IO32_SNOC_H__ + +#ifdef HIF_PCI +#error snoc and pci cannot be supported in parrallel at this time +#endif + +#include "hif.h" +#include "regtable.h" +#include "ce_reg.h" +#include "cdf_atomic.h" +#include +#include "hif_main.h" +#include "hif_debug.h" + +/** + * Following features are not supported for snoc bus + * Force 0 and consider moving corresponding code into + * pci specific files + */ +#define CONFIG_ATH_PCIE_MAX_PERF 0 +#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD 0 +#define CONFIG_ATH_PCIE_ACCESS_LIKELY 0 +#define CONFIG_PCIE_ENABLE_L1_CLOCK_GATE 0 + +#define A_TARGET_ACCESS_LIKELY(scn) +#define A_TARGET_ACCESS_UNLIKELY(scn) +#define A_TARGET_ACCESS_BEGIN_RET_PTR(scn) +#define A_TARGET_ACCESS_END_RET_PTR(scn) +#define A_TARGET_ACCESS_BEGIN(scn) +#define A_TARGET_ACCESS_END(scn) +#define A_TARGET_ACCESS_BEGIN_RET(scn) +#define A_TARGET_ACCESS_END_RET(scn) +#define A_TARGET_ACCESS_BEGIN_RET_EXT(scn, val) +#define A_TARGET_ACCESS_END_RET_EXT(scn, val) + +#define Q_TARGET_ACCESS_BEGIN(scn) 0 +#define Q_TARGET_ACCESS_END(scn) 0 + +static inline void hif_pci_cancel_deferred_target_sleep(struct ol_softc *scn) +{ + return; +} + +static inline void hif_target_sleep_state_adjust(struct ol_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + return; +} + +/** + * soc_wake_reset() - soc_wake_reset + * @scn: ol_softc + * + * Return: void + */ +static inline void soc_wake_reset(struct ol_softc *scn) +{ +} + +/** + * hif_write32_mb - SNOC write 32 + * @addr: physical address + * @value: value + * + * Return: N/A + */ +static inline void hif_write32_mb(void __iomem *addr, uint32_t value) +{ + wmb(); /* write memory barrier */ + writel_relaxed((value), (addr)); + wmb(); /* write memory barrier */ +} + +/** + * hif_read32_mb - SNOC read 32 + * @addr: physical address + * + * Return: N/A + */ +static inline uint32_t hif_read32_mb(void __iomem *addr) +{ + uint32_t tmp; + rmb(); /* read memory barrier */ + tmp = readl_relaxed(addr); + rmb(); /* read memory barrier */ + return tmp; +} + +#define A_TARGET_READ(scn, offset) \ + hif_read32_mb(scn->mem + (offset)) +#define A_TARGET_WRITE(scn, offset, value) \ + hif_write32_mb((scn->mem + offset), (value)) + +#define ADRASTEA_CE_INTR_ENABLES 0x002F00A8 +#define ADRASTEA_CE_INTR_ENABLES_SET "COMING IN REGISTER SET36" +#define ADRASTEA_CE_INTR_ENABLES_CLEAR "COMING IN REGISTER SET36" + +#define ADRASTEA_CE_INTR_STATUS 0x002F00AC + +static inline void ce_enable_irq_in_individual_register(struct ol_softc *scn, + int ce_id) +{ + uint32_t offset; + offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + hif_write32_mb(scn->mem + offset, 1); + hif_read32_mb(scn->mem + offset); +} + +static inline void ce_disable_irq_in_individual_register(struct ol_softc *scn, + int ce_id) +{ + uint32_t offset; + offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + hif_write32_mb(scn->mem + offset, 0); + hif_read32_mb(scn->mem + offset); +} + +static inline void ce_read_irq_group_status(struct ol_softc *scn) +{ + uint32_t group_status = 0; + group_status = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_STATUS); +} + +static inline void ce_clear_irq_group_status(struct ol_softc *scn, int mask) +{ + uint32_t group_status = 0; + group_status = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_STATUS); + + hif_write32_mb(scn->mem + + ADRASTEA_CE_INTR_STATUS, mask); + + group_status = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_STATUS); +} + +/* this will need to be changed when we move to reg set 36 + * because we will have set & clear registers provided + */ +static inline void ce_enable_irq_in_group_reg(struct ol_softc *scn, + int mask) +{ + int new_mask = 0; + new_mask = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES); + + new_mask |= mask; + + hif_write32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES, new_mask); + mask = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES); +} + +/* this will need to be changed when we move to reg set 36 + * because we will have set & clear registers provided + */ +static inline void ce_disable_irq_in_group_reg(struct ol_softc *scn, + int mask) +{ + int new_mask = 0; + new_mask = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES); + + new_mask &= ~mask; + + hif_write32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES, new_mask); + mask = hif_read32_mb(scn->mem + + ADRASTEA_CE_INTR_ENABLES); +} + +/** + * ce_irq_enable() - enable copy engine IRQ + * @scn: struct ol_softc + * @ce_id: ce_id + * + * Return: N/A + */ +static inline void ce_irq_enable(struct ol_softc *scn, + int ce_id) +{ + icnss_enable_irq(ce_id); + ce_enable_irq_in_individual_register(scn, ce_id); + ce_enable_irq_in_group_reg(scn, 1<hif_hdl); + cdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +/** + * dump_ce_debug_register(): dump CE debug registers + * + * This function dumps CE debug registers + * + * @scn: struct ol_softc + * + * Return: void + */ +void dump_ce_debug_register(struct ol_softc *scn) +{ + return; +} + +/** + * hif_bus_suspend() - suspend the bus + * + * This function suspends the bus, but snoc doesn't need to suspend. + * Therefore do nothing. + * + * Return: 0 for success and non-zero for failure + */ +int hif_bus_suspend(void) +{ + return 0; +} + +/** + * hif_bus_resume() - hif resume API + * + * This function resumes the bus. but snoc doesn't need to resume. + * Therefore do nothing. + * + * Return: 0 for success and non-zero for failure + */ +int hif_bus_resume(void) +{ + return 0; +} + +/** + * hif_enable_power_gating(): enable HW power gating + * + * Return: n/a + */ +void hif_enable_power_gating(void *hif_ctx) +{ +} + +/** + * hif_disable_aspm(): hif_disable_aspm + * + * Return: n/a + */ +void hif_disable_aspm(void) +{ +} + +/** + * hif_bus_close(): hif_bus_close + * + * Return: n/a + */ +void hif_bus_close(struct ol_softc *scn) +{ +} + +/** + * hif_bus_open(): hif_bus_open + * @scn: scn + * @bus_type: bus type + * + * Return: n/a + */ +CDF_STATUS hif_bus_open(struct ol_softc *scn, enum ath_hal_bus_type bus_type) +{ + return CDF_STATUS_SUCCESS; +} + +/** + * hif_get_target_type(): Get the target type + * + * This function is used to query the target type. + * + * @ol_sc: ol_softc struct pointer + * @dev: device pointer + * @bdev: bus dev pointer + * @bid: bus id pointer + * @hif_type: HIF type such as HIF_TYPE_QCA6180 + * @target_type: target type such as TARGET_TYPE_QCA6180 + * + * Return: 0 for success + */ +int hif_get_target_type(struct ol_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, uint32_t *hif_type, + uint32_t *target_type) +{ + /* TODO: need to use CNSS's HW version. Hard code for now */ +#ifdef QCA_WIFI_3_0_ADRASTEA + *hif_type = HIF_TYPE_ADRASTEA; + *target_type = TARGET_TYPE_ADRASTEA; +#else + *hif_type = 0; + *target_type = 0; +#endif + return 0; +} + +/** + * hif_enable_bus(): hif_enable_bus + * @dev: dev + * @bdev: bus dev + * @bid: bus id + * @type: bus type + * + * Return: CDF_STATUS + */ +CDF_STATUS hif_enable_bus(struct ol_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret; + int hif_type; + int target_type; + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) { + HIF_ERROR("%s: failed to set dma mask error = %d", + __func__, ret); + return ret; + } + + if (!ol_sc) { + HIF_ERROR("%s: hif_ctx is NULL", __func__); + return CDF_STATUS_E_NOMEM; + } + + ol_sc->aps_osdev.device = dev; + ol_sc->aps_osdev.bc.bc_handle = (void *)ol_sc->mem; + ol_sc->aps_osdev.bc.bc_bustype = type; + + ret = hif_get_target_type(ol_sc, dev, bdev, bid, + &hif_type, &target_type); + if (ret < 0) { + HIF_ERROR("%s: invalid device id/revision_id", __func__); + return CDF_STATUS_E_FAILURE; + } + + hif_register_tbl_attach(ol_sc, hif_type); + target_register_tbl_attach(ol_sc, target_type); + + HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x", + __func__, hif_type, target_type); + + ret = hif_init_cdf_ctx(ol_sc); + if (ret != 0) { + HIF_ERROR("%s: cannot init CDF", __func__); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * hif_disable_bus(): hif_disable_bus + * + * This function disables the bus + * + * @bdev: bus dev + * + * Return: none + */ +void hif_disable_bus(void *bdev) +{ +} + +/** + * hif_nointrs(): disable IRQ + * + * This function stops interrupt(s) + * + * @scn: struct ol_softc + * + * Return: none + */ +void hif_nointrs(struct ol_softc *scn) +{ + if (scn->request_irq_done) { + ce_unregister_irq(scn->hif_hdl, 0xfff); + scn->request_irq_done = false; + } +} diff --git a/core/htc/dl_list.h b/core/htc/dl_list.h new file mode 100644 index 0000000000..1b5d72f780 --- /dev/null +++ b/core/htc/dl_list.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ============================================================================== */ +/* Double-link list definitions (adapted from Atheros SDIO stack) */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ + +#ifndef __DL_LIST_H___ +#define __DL_LIST_H___ + +#define A_CONTAINING_STRUCT(address, struct_type, field_name) \ + ((struct_type *)((char *)(address) - (char *)(&((struct_type *)0)->field_name))) + +/* list functions */ +/* pointers for the list */ +typedef struct _DL_LIST { + struct _DL_LIST *pPrev; + struct _DL_LIST *pNext; +} DL_LIST, *PDL_LIST; +/* + * DL_LIST_INIT , initialize doubly linked list + */ +#define DL_LIST_INIT(pList) \ + {(pList)->pPrev = pList; (pList)->pNext = pList; } + +/* faster macro to init list and add a single item */ +#define DL_LIST_INIT_AND_ADD(pList,pItem) \ + { (pList)->pPrev = (pItem); \ + (pList)->pNext = (pItem); \ + (pItem)->pNext = (pList); \ + (pItem)->pPrev = (pList); \ + } + +#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList))) +#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext +#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev +/* + * ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member + * NOT: do not use this function if the items in the list are deleted inside the + * iteration loop + */ +#define ITERATE_OVER_LIST(pStart, pTemp) \ + for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext) + +static __inline bool dl_list_is_entry_in_list(const DL_LIST *pList, + const DL_LIST *pEntry) +{ + const DL_LIST *pTmp; + + if (pList == pEntry) + return true; + + ITERATE_OVER_LIST(pList, pTmp) { + if (pTmp == pEntry) { + return true; + } + } + + return false; +} + +/* safe iterate macro that allows the item to be removed from the list + * the iteration continues to the next item in the list + */ +#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \ + { \ + PDL_LIST pTemp; \ + pTemp = (pStart)->pNext; \ + while (pTemp != (pStart)) { \ + (pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \ + pTemp = pTemp->pNext; \ + +#define ITERATE_IS_VALID(pStart) dl_list_is_entry_in_list(pStart, pTemp) +#define ITERATE_RESET(pStart) pTemp=(pStart)->pNext + +#define ITERATE_END }} + +/* + * dl_list_insert_tail - insert pAdd to the end of the list + */ +static __inline PDL_LIST dl_list_insert_tail(PDL_LIST pList, PDL_LIST pAdd) +{ + /* insert at tail */ + pAdd->pPrev = pList->pPrev; + pAdd->pNext = pList; + if (pList->pPrev) { + pList->pPrev->pNext = pAdd; + } + pList->pPrev = pAdd; + return pAdd; +} + +/* + * dl_list_insert_head - insert pAdd into the head of the list + */ +static __inline PDL_LIST dl_list_insert_head(PDL_LIST pList, PDL_LIST pAdd) +{ + /* insert at head */ + pAdd->pPrev = pList; + pAdd->pNext = pList->pNext; + pList->pNext->pPrev = pAdd; + pList->pNext = pAdd; + return pAdd; +} + +#define DL_ListAdd(pList,pItem) dl_list_insert_head((pList),(pItem)) +/* + * dl_list_remove - remove pDel from list + */ +static __inline PDL_LIST dl_list_remove(PDL_LIST pDel) +{ + if (pDel->pNext != NULL) { + pDel->pNext->pPrev = pDel->pPrev; + } + if (pDel->pPrev != NULL) { + pDel->pPrev->pNext = pDel->pNext; + } + + /* point back to itself just to be safe, incase remove is called again */ + pDel->pNext = pDel; + pDel->pPrev = pDel; + return pDel; +} + +/* + * dl_list_remove_item_from_head - get a list item from the head + */ +static __inline PDL_LIST dl_list_remove_item_from_head(PDL_LIST pList) +{ + PDL_LIST pItem = NULL; + if (pList->pNext != pList) { + pItem = pList->pNext; + /* remove the first item from head */ + dl_list_remove(pItem); + } + return pItem; +} + +static __inline PDL_LIST dl_list_remove_item_from_tail(PDL_LIST pList) +{ + PDL_LIST pItem = NULL; + if (pList->pPrev != pList) { + pItem = pList->pPrev; + /* remove the item from tail */ + dl_list_remove(pItem); + } + return pItem; +} + +/* transfer src list items to the tail of the destination list */ +static __inline void dl_list_transfer_items_to_tail(PDL_LIST pDest, PDL_LIST pSrc) +{ + /* only concatenate if src is not empty */ + if (!DL_LIST_IS_EMPTY(pSrc)) { + /* cut out circular list in src and re-attach to end of dest */ + pSrc->pPrev->pNext = pDest; + pSrc->pNext->pPrev = pDest->pPrev; + pDest->pPrev->pNext = pSrc->pNext; + pDest->pPrev = pSrc->pPrev; + /* terminate src list, it is now empty */ + pSrc->pPrev = pSrc; + pSrc->pNext = pSrc; + } +} + +/* transfer src list items to the head of the destination list */ +static __inline void dl_list_transfer_items_to_head(PDL_LIST pDest, PDL_LIST pSrc) +{ + /* only concatenate if src is not empty */ + if (!DL_LIST_IS_EMPTY(pSrc)) { + /* cut out circular list in src and re-attach to start of dest */ + pSrc->pNext->pPrev = pDest; + pDest->pNext->pPrev = pSrc->pPrev; + pSrc->pPrev->pNext = pDest->pNext; + pDest->pNext = pSrc->pNext; + /* terminate src list, it is now empty */ + pSrc->pPrev = pSrc; + pSrc->pNext = pSrc; + } +} + +#endif /* __DL_LIST_H___ */ diff --git a/core/htc/htc.c b/core/htc/htc.c new file mode 100644 index 0000000000..bbabee1f25 --- /dev/null +++ b/core/htc/htc.c @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ol_if_athvar.h" +#include "htc_debug.h" +#include "htc_internal.h" +#include /* cdf_nbuf_t */ +#include /* cdf_print */ +#include +#include +#include "epping_main.h" +#include "hif_io32.h" + +#ifdef DEBUG +static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = { + {ATH_DEBUG_SEND, "Send"}, + {ATH_DEBUG_RECV, "Recv"}, + {ATH_DEBUG_SYNC, "Sync"}, + {ATH_DEBUG_DUMP, "Dump Data (RX or TX)"}, + {ATH_DEBUG_SETUP, "Setup"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc, + "htc", + "Host Target Communications", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | + ATH_DEBUG_SETUP, + ATH_DEBUG_DESCRIPTION_COUNT + (g_htc_debug_description), + g_htc_debug_description); + +#endif + +extern unsigned int htc_credit_flow; + +static void reset_endpoint_states(HTC_TARGET *target); + +static void destroy_htc_tx_ctrl_packet(HTC_PACKET *pPacket) +{ + cdf_nbuf_t netbuf; + netbuf = (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("free ctrl netbuf :0x%p \n", netbuf)); + if (netbuf != NULL) { + cdf_nbuf_free(netbuf); + } + + cdf_mem_free(pPacket); +} + +static HTC_PACKET *build_htc_tx_ctrl_packet(cdf_device_t osdev) +{ + HTC_PACKET *pPacket = NULL; + cdf_nbuf_t netbuf; + + do { + pPacket = (HTC_PACKET *) cdf_mem_malloc(sizeof(HTC_PACKET)); + if (NULL == pPacket) { + break; + } + A_MEMZERO(pPacket, sizeof(HTC_PACKET)); + netbuf = + cdf_nbuf_alloc(osdev, HTC_CONTROL_BUFFER_SIZE, 20, 4, true); + if (NULL == netbuf) { + cdf_mem_free(pPacket); + pPacket = NULL; + cdf_print("%s: nbuf alloc failed\n", __func__); + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("alloc ctrl netbuf :0x%p \n", netbuf)); + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); + } while (false); + + return pPacket; +} + +void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + +#ifdef TODO_FIXME + LOCK_HTC(target); + HTC_PACKET_ENQUEUE(&target->ControlBufferTXFreeList, pPacket); + UNLOCK_HTC(target); + /* TODO_FIXME netbufs cannot be RESET! */ +#else + destroy_htc_tx_ctrl_packet(pPacket); +#endif + +} + +HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target) +{ +#ifdef TODO_FIXME + HTC_PACKET *pPacket; + + LOCK_HTC(target); + pPacket = htc_packet_dequeue(&target->ControlBufferTXFreeList); + UNLOCK_HTC(target); + + return pPacket; +#else + return build_htc_tx_ctrl_packet(target->osdev); +#endif +} + +/* Set the target failure handling callback */ +void htc_set_target_failure_callback(HTC_HANDLE HTCHandle, + HTC_TARGET_FAILURE Callback) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + target->HTCInitInfo.TargetFailure = Callback; +} + +void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + hif_dump(target->hif_dev, CmdId, start); +} + +/* cleanup the HTC instance */ +static void htc_cleanup(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + /* cdf_nbuf_t netbuf; */ + + if (target->hif_dev != NULL) { + hif_detach_htc(target->hif_dev); + target->hif_dev = NULL; + } + + while (true) { + pPacket = allocate_htc_packet_container(target); + if (NULL == pPacket) { + break; + } + cdf_mem_free(pPacket); + } + + pPacket = target->pBundleFreeList; + while (pPacket) { + HTC_PACKET *pPacketTmp = (HTC_PACKET *) pPacket->ListLink.pNext; + cdf_mem_free(pPacket); + pPacket = pPacketTmp; + } +#ifdef TODO_FIXME + while (true) { + pPacket = htc_alloc_control_tx_packet(target); + if (NULL == pPacket) { + break; + } + netbuf = (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + if (netbuf != NULL) { + cdf_nbuf_free(netbuf); + } + + cdf_mem_free(pPacket); + } +#endif + + cdf_spinlock_destroy(&target->HTCLock); + cdf_spinlock_destroy(&target->HTCRxLock); + cdf_spinlock_destroy(&target->HTCTxLock); + cdf_spinlock_destroy(&target->HTCCreditLock); + + /* free our instance */ + cdf_mem_free(target); +} + +/* registered target arrival callback from the HIF layer */ +HTC_HANDLE htc_create(void *ol_sc, HTC_INIT_INFO *pInfo, cdf_device_t osdev) +{ + struct hif_msg_callbacks htcCallbacks; + HTC_ENDPOINT *pEndpoint = NULL; + HTC_TARGET *target = NULL; + int i; + + if (ol_sc == NULL) { + HTC_ERROR("%s: ol_sc = NULL", __func__); + return NULL; + } + HTC_TRACE("+htc_create .. HIF :%p", ol_sc); + + A_REGISTER_MODULE_DEBUG_INFO(htc); + + target = (HTC_TARGET *) cdf_mem_malloc(sizeof(HTC_TARGET)); + if (target == NULL) { + HTC_ERROR("%s: Unable to allocate memory", __func__); + return NULL; + } + + A_MEMZERO(target, sizeof(HTC_TARGET)); + + cdf_spinlock_init(&target->HTCLock); + cdf_spinlock_init(&target->HTCRxLock); + cdf_spinlock_init(&target->HTCTxLock); + cdf_spinlock_init(&target->HTCCreditLock); + + do { + A_MEMCPY(&target->HTCInitInfo, pInfo, sizeof(HTC_INIT_INFO)); + target->host_handle = pInfo->pContext; + target->osdev = osdev; + + reset_endpoint_states(target); + + INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); + + for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { + HTC_PACKET *pPacket = + (HTC_PACKET *) cdf_mem_malloc(sizeof(HTC_PACKET)); + if (pPacket != NULL) { + A_MEMZERO(pPacket, sizeof(HTC_PACKET)); + free_htc_packet_container(target, pPacket); + } + } + +#ifdef TODO_FIXME + for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) { + pPacket = build_htc_tx_ctrl_packet(); + if (NULL == pPacket) { + break; + } + htc_free_control_tx_packet(target, pPacket); + } +#endif + + /* setup HIF layer callbacks */ + cdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks)); + htcCallbacks.Context = target; + htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; + htcCallbacks.txCompletionHandler = htc_tx_completion_handler; + htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler; + htcCallbacks.fwEventHandler = htc_fw_event_handler; + target->hif_dev = ol_sc; + + /* Get HIF default pipe for HTC message exchange */ + pEndpoint = &target->EndPoint[ENDPOINT_0]; + + hif_post_init(target->hif_dev, target, &htcCallbacks); + hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID, + &pEndpoint->DL_PipeID); + + } while (false); + + htc_recv_init(target); + + HTC_TRACE("-htc_create: (0x%p)", target); + + return (HTC_HANDLE) target; +} + +void htc_destroy(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+htc_destroy .. Destroying :0x%p\n", target)); + if (target) + htc_cleanup(target); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n")); +} + +/* get the low level HIF device for the caller , the caller may wish to do low level + * HIF requests */ +void *htc_get_hif_device(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + return target->hif_dev; +} + +void htc_control_tx_complete(void *Context, HTC_PACKET *pPacket) +{ + HTC_TARGET *target = (HTC_TARGET *) Context; + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+-htc_control_tx_complete 0x%p (l:%d) \n", pPacket, + pPacket->ActualLength)); + htc_free_control_tx_packet(target, pPacket); +} + +/* TODO, this is just a temporary max packet size */ +#define MAX_MESSAGE_SIZE 1536 + +/** + * htc_setup_target_buffer_assignments() - setup target buffer assignments + * @target: HTC Target Pointer + * + * Return: A_STATUS + */ +A_STATUS htc_setup_target_buffer_assignments(HTC_TARGET *target) +{ + HTC_SERVICE_TX_CREDIT_ALLOCATION *pEntry; + A_STATUS status; + int credits; + int creditsPerMaxMsg; + + creditsPerMaxMsg = MAX_MESSAGE_SIZE / target->TargetCreditSize; + if (MAX_MESSAGE_SIZE % target->TargetCreditSize) { + creditsPerMaxMsg++; + } + + /* TODO, this should be configured by the caller! */ + + credits = target->TotalTransmitCredits; + pEntry = &target->ServiceTxAllocTable[0]; + + /* + * Allocate all credists/HTC buffers to WMI. + * no buffers are used/required for data. data always + * remains on host. + */ + status = A_OK; + pEntry++; + pEntry->ServiceID = WMI_CONTROL_SVC; + pEntry->CreditAllocation = credits; + + if (WLAN_IS_EPPING_ENABLED(cds_get_conparam())) { + /* endpoint ping is a testing tool directly on top of HTC in + * both target and host sides. + * In target side, the endppint ping fw has no wlan stack and the + * FW mboxping app directly sits on HTC and it simply drops + * or loops back TX packets. For rx perf, FW mboxping app + * generates packets and passes packets to HTC to send to host. + * There is no WMI mesage exchanges between host and target + * in endpoint ping case. + * In host side, the endpoint ping driver is a Ethernet driver + * and it directly sits on HTC. Only HIF, HTC, CDF, ADF are + * used by the endpoint ping driver. There is no wifi stack + * at all in host side also. For tx perf use case, + * the user space mboxping app sends the raw packets to endpoint + * ping driver and it directly forwards to HTC for transmission + * to stress the bus. For the rx perf, HTC passes the received + * packets to endpoint ping driver and it is passed to the user + * space through the Ethernet interface. + * For credit allocation, in SDIO bus case, only BE service is + * used for tx/rx perf testing so that all credits are given + * to BE service. In PCIe and USB bus case, endpoint ping uses both + * BE and BK services to stress the bus so that the total credits + * are equally distributed to BE and BK services. + */ + pEntry->ServiceID = WMI_DATA_BE_SVC; + pEntry->CreditAllocation = (credits >> 1); + + pEntry++; + pEntry->ServiceID = WMI_DATA_BK_SVC; + pEntry->CreditAllocation = (credits >> 1); + } + + if (A_SUCCESS(status)) { + int i; + for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { + if (target->ServiceTxAllocTable[i].ServiceID != 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC Service Index : %d TX : 0x%2.2X : alloc:%d \n", + i, + target->ServiceTxAllocTable[i]. + ServiceID, + target->ServiceTxAllocTable[i]. + CreditAllocation)); + } + } + } + + return status; +} + +A_UINT8 htc_get_credit_allocation(HTC_TARGET *target, A_UINT16 ServiceID) +{ + A_UINT8 allocation = 0; + int i; + + for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { + if (target->ServiceTxAllocTable[i].ServiceID == ServiceID) { + allocation = + target->ServiceTxAllocTable[i].CreditAllocation; + } + } + + if (0 == allocation) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC Service TX : 0x%2.2X : allocation is zero! \n", + ServiceID)); + } + + return allocation; +} + +A_STATUS htc_wait_target(HTC_HANDLE HTCHandle) +{ + A_STATUS status = A_OK; + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_READY_EX_MSG *pReadyMsg; + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP resp; + HTC_READY_MSG *rdy_msg; + A_UINT16 htc_rdy_msg_id; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("htc_wait_target - Enter (target:0x%p) \n", HTCHandle)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("+HWT\n")); + + do { + + status = hif_start(target->hif_dev); + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("hif_start failed\n")); + break; + } + + status = htc_wait_recv_ctrl_message(target); + + if (A_FAILED(status)) { + break; + } + + if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid HTC Ready Msg Len:%d! \n", + target->CtrlResponseLength)); + status = A_ECOMM; + break; + } + + pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer; + + rdy_msg = &pReadyMsg->Version2_0_Info; + htc_rdy_msg_id = + HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID); + if (htc_rdy_msg_id != HTC_MSG_READY_ID) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid HTC Ready Msg : 0x%X ! \n", + htc_rdy_msg_id)); + status = A_ECOMM; + break; + } + + target->TotalTransmitCredits = + HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITCOUNT); + target->TargetCreditSize = + (int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE); + target->MaxMsgsPerHTCBundle = + (A_UINT8) pReadyMsg->MaxMsgsPerHTCBundle; + /* for old fw this value is set to 0. But the minimum value should be 1, + * i.e., no bundling */ + if (target->MaxMsgsPerHTCBundle < 1) + target->MaxMsgsPerHTCBundle = 1; + + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("Target Ready! : transmit resources : %d size:%d, MaxMsgsPerHTCBundle = %d\n", + target->TotalTransmitCredits, + target->TargetCreditSize, + target->MaxMsgsPerHTCBundle)); + + if ((0 == target->TotalTransmitCredits) + || (0 == target->TargetCreditSize)) { + status = A_ECOMM; + break; + } + /* done processing */ + target->CtrlResponseProcessing = false; + + htc_setup_target_buffer_assignments(target); + + /* setup our pseudo HTC control endpoint connection */ + A_MEMZERO(&connect, sizeof(connect)); + A_MEMZERO(&resp, sizeof(resp)); + connect.EpCallbacks.pContext = target; + connect.EpCallbacks.EpTxComplete = htc_control_tx_complete; + connect.EpCallbacks.EpRecv = htc_control_rx_complete; + connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS; + connect.ServiceID = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = htc_connect_service((HTC_HANDLE) target, + &connect, &resp); + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n", status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-HWT\n")); + return status; +} + +/* start HTC, this is called after all services are connected */ +static A_STATUS htc_config_target_hif_pipe(HTC_TARGET *target) +{ + + return A_OK; +} + +static void reset_endpoint_states(HTC_TARGET *target) +{ + HTC_ENDPOINT *pEndpoint; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + pEndpoint->ServiceID = 0; + pEndpoint->MaxMsgLength = 0; + pEndpoint->MaxTxQueueDepth = 0; + pEndpoint->Id = i; + INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); + INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue); + INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue); + pEndpoint->target = target; + /* pEndpoint->TxCreditFlowEnabled = (A_BOOL)htc_credit_flow; */ + pEndpoint->TxCreditFlowEnabled = (A_BOOL) 1; + cdf_atomic_init(&pEndpoint->TxProcessCount); + } +} + +A_STATUS htc_start(HTC_HANDLE HTCHandle) +{ + cdf_nbuf_t netbuf; + A_STATUS status = A_OK; + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_SETUP_COMPLETE_EX_MSG *pSetupComp; + HTC_PACKET *pSendPacket; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n")); + + do { + + htc_config_target_hif_pipe(target); + + /* allocate a buffer to send */ + pSendPacket = htc_alloc_control_tx_packet(target); + if (NULL == pSendPacket) { + AR_DEBUG_ASSERT(false); + cdf_print("%s: allocControlTxPacket failed\n", + __func__); + status = A_NO_MEMORY; + break; + } + + netbuf = + (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); + /* assemble setup complete message */ + cdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); + pSetupComp = + (HTC_SETUP_COMPLETE_EX_MSG *) cdf_nbuf_data(netbuf); + A_MEMZERO(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); + + HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG, + MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID); + + if (!htc_credit_flow) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC will not use TX credit flow control\n")); + pSetupComp->SetupFlags |= + HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC using TX credit flow control\n")); + } + +#ifdef HIF_SDIO +#if ENABLE_BUNDLE_RX + if (HTC_ENABLE_BUNDLE(target)) + pSetupComp->SetupFlags |= + HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; +#endif /* ENABLE_BUNDLE_RX */ +#endif /* HIF_SDIO */ + + SET_HTC_PACKET_INFO_TX(pSendPacket, + NULL, + (A_UINT8 *) pSetupComp, + sizeof(HTC_SETUP_COMPLETE_EX_MSG), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); + if (A_FAILED(status)) { + break; + } + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n")); + return status; +} + +/*flush all queued buffers for surpriseremove case*/ +void htc_flush_surprise_remove(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + int i; + HTC_ENDPOINT *pEndpoint; +#ifdef RX_SG_SUPPORT + cdf_nbuf_t netbuf; + cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove \n")); + + /* cleanup endpoints */ + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + htc_flush_rx_hold_queue(target, pEndpoint); + htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); + } + + hif_flush_surprise_remove(target->hif_dev); + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) { + cdf_nbuf_free(netbuf); + } + RESET_RX_SG_CONFIG(target); + UNLOCK_HTC_RX(target); +#endif + + reset_endpoint_states(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove \n")); +} + +/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ +void htc_stop(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + int i; + HTC_ENDPOINT *pEndpoint; +#ifdef RX_SG_SUPPORT + cdf_nbuf_t netbuf; + cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop \n")); + + /* cleanup endpoints */ + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + htc_flush_rx_hold_queue(target, pEndpoint); + htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); + if (pEndpoint->ul_is_polled) { + cdf_softirq_timer_cancel(&pEndpoint->ul_poll_timer); + cdf_softirq_timer_free(&pEndpoint->ul_poll_timer); + } + } + + /* Note: htc_flush_endpoint_tx for all endpoints should be called before + * hif_stop - otherwise htc_tx_completion_handler called from + * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer, + * might queue the packet again to HIF Layer - which could cause tx + * buffer leak + */ + + hif_stop(target->hif_dev); + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + while ((netbuf = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) { + cdf_nbuf_free(netbuf); + } + RESET_RX_SG_CONFIG(target); + UNLOCK_HTC_RX(target); +#endif + + reset_endpoint_states(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop \n")); +} + +void htc_dump_credit_states(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + int i; + + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + if (0 == pEndpoint->ServiceID) { + continue; + } + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("--- EP : %d ServiceID: 0x%X --------------\n", + pEndpoint->Id, pEndpoint->ServiceID)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCredits : %d \n", + pEndpoint->TxCredits)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCreditSize : %d \n", + pEndpoint->TxCreditSize)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCreditsPerMaxMsg : %d \n", + pEndpoint->TxCreditsPerMaxMsg)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxQueueDepth : %d \n", + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("----------------------------------------------------\n")); + } +} + +A_BOOL htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, + HTC_ENDPOINT_STAT_ACTION Action, + HTC_ENDPOINT_STATS *pStats) +{ +#ifdef HTC_EP_STAT_PROFILING + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + A_BOOL clearStats = false; + A_BOOL sample = false; + + switch (Action) { + case HTC_EP_STAT_SAMPLE: + sample = true; + break; + case HTC_EP_STAT_SAMPLE_AND_CLEAR: + sample = true; + clearStats = true; + break; + case HTC_EP_STAT_CLEAR: + clearStats = true; + break; + default: + break; + } + + A_ASSERT(Endpoint < ENDPOINT_MAX); + + /* lock out TX and RX while we sample and/or clear */ + LOCK_HTC_TX(target); + LOCK_HTC_RX(target); + + if (sample) { + A_ASSERT(pStats != NULL); + /* return the stats to the caller */ + A_MEMCPY(pStats, &target->EndPoint[Endpoint].EndPointStats, + sizeof(HTC_ENDPOINT_STATS)); + } + + if (clearStats) { + /* reset stats */ + A_MEMZERO(&target->EndPoint[Endpoint].EndPointStats, + sizeof(HTC_ENDPOINT_STATS)); + } + + UNLOCK_HTC_RX(target); + UNLOCK_HTC_TX(target); + + return true; +#else + return false; +#endif +} + +void *htc_get_targetdef(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + return hif_get_targetdef(target->hif_dev); +} + +/** + * htc_set_target_to_sleep() - set target to sleep + * @context: ol_softc context + * + * Return: none + */ +void htc_set_target_to_sleep(void *context) +{ + struct ol_softc *scn = (struct ol_softc *)context; + + hif_set_target_sleep(scn, true, false); +} + +/** + * htc_cancel_deferred_target_sleep() - cancel deferred target sleep + * @context: ol_softc context + * + * Return: none + */ +void htc_cancel_deferred_target_sleep(void *context) +{ + struct ol_softc *scn = (struct ol_softc *)context; + hif_cancel_deferred_target_sleep(scn); +} + +#ifdef IPA_OFFLOAD +void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (target->hif_dev != NULL) { + hif_ipa_get_ce_resource(target->hif_dev, + ce_sr_base_paddr, + ce_sr_ring_size, ce_reg_paddr); + } +} +#endif /* IPA_OFFLOAD */ diff --git a/core/htc/htc_api.h b/core/htc/htc_api.h new file mode 100644 index 0000000000..937d326ba7 --- /dev/null +++ b/core/htc/htc_api.h @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTC_API_H_ +#define _HTC_API_H_ + +#include +#include "osapi_linux.h" +#include "htc_packet.h" +#include +#include +#include /* cdf_device_t */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* TODO.. for BMI */ +#define ENDPOINT1 0 +/* TODO -remove me, but we have to fix BMI first */ +#define HTC_MAILBOX_NUM_MAX 4 + +/* this is the amount of header room required by users of HTC */ +#define HTC_HEADER_LEN HTC_HDR_LENGTH + +typedef void *HTC_HANDLE; + +typedef A_UINT16 HTC_SERVICE_ID; + +typedef void (*HTC_TARGET_FAILURE)(void *Instance, CDF_STATUS Status); + +typedef struct _HTC_INIT_INFO { + void *pContext; /* context for target notifications */ + void (*TargetFailure)(void *Instance, CDF_STATUS Status); + void (*TargetSendSuspendComplete)(void *ctx); +} HTC_INIT_INFO; + +/* Struct for HTC layer packet stats*/ +struct ol_ath_htc_stats { + int htc_get_pkt_q_fail_count; + int htc_pkt_q_empty_count; + int htc_send_q_empty_count; +}; + +/* per service connection send completion */ +typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *, HTC_PACKET *); +/* per service connection callback when a plurality of packets have been sent + * The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback) + * to hold a list of completed send packets. + * If the handler cannot fully traverse the packet queue before returning, it should + * transfer the items of the queue into the caller's private queue using: + * HTC_PACKET_ENQUEUE() */ +typedef void (*HTC_EP_SEND_PKT_COMP_MULTIPLE)(void *, + HTC_PACKET_QUEUE *); +/* per service connection pkt received */ +typedef void (*HTC_EP_RECV_PKT)(void *, HTC_PACKET *); +/* per service connection callback when a plurality of packets are received + * The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback) + * to hold a list of recv packets. + * If the handler cannot fully traverse the packet queue before returning, it should + * transfer the items of the queue into the caller's private queue using: + * HTC_PACKET_ENQUEUE() */ +typedef void (*HTC_EP_RECV_PKT_MULTIPLE)(void *, HTC_PACKET_QUEUE *); + +/* Optional per service connection receive buffer re-fill callback, + * On some OSes (like Linux) packets are allocated from a global pool and indicated up + * to the network stack. The driver never gets the packets back from the OS. For these OSes + * a refill callback can be used to allocate and re-queue buffers into HTC. + * + * On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and + * the driver can re-queue these buffers into HTC. In this regard a refill callback is + * unnecessary */ +typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint); + +/* Optional per service connection receive buffer allocation callback. + * On some systems packet buffers are an extremely limited resource. Rather than + * queue largest-possible-sized buffers to HTC, some systems would rather + * allocate a specific size as the packet is received. The trade off is + * slightly more processing (callback invoked for each RX packet) + * for the benefit of committing fewer buffer resources into HTC. + * + * The callback is provided the length of the pending packet to fetch. This includes the + * HTC header length plus the length of payload. The callback can return a pointer to + * the allocated HTC packet for immediate use. + * + * Alternatively a variant of this handler can be used to allocate large receive packets as needed. + * For example an application can use the refill mechanism for normal packets and the recv-alloc mechanism to + * handle the case where a large packet buffer is required. This can significantly reduce the + * amount of "committed" memory used to receive packets. + * + * */ +typedef HTC_PACKET *(*HTC_EP_RECV_ALLOC)(void *, + HTC_ENDPOINT_ID Endpoint, + int Length); + +typedef enum _HTC_SEND_FULL_ACTION { + HTC_SEND_FULL_KEEP = 0, /* packet that overflowed should be kept in the queue */ + HTC_SEND_FULL_DROP = 1, /* packet that overflowed should be dropped */ +} HTC_SEND_FULL_ACTION; + +/* Optional per service connection callback when a send queue is full. This can occur if the + * host continues queueing up TX packets faster than credits can arrive + * To prevent the host (on some Oses like Linux) from continuously queueing packets + * and consuming resources, this callback is provided so that that the host + * can disable TX in the subsystem (i.e. network stack). + * This callback is invoked for each packet that "overflows" the HTC queue. The callback can + * determine whether the new packet that overflowed the queue can be kept (HTC_SEND_FULL_KEEP) or + * dropped (HTC_SEND_FULL_DROP). If a packet is dropped, the EpTxComplete handler will be called + * and the packet's status field will be set to A_NO_RESOURCE. + * Other OSes require a "per-packet" indication for each completed TX packet, this + * closed loop mechanism will prevent the network stack from overunning the NIC + * The packet to keep or drop is passed for inspection to the registered handler the handler + * must ONLY inspect the packet, it may not free or reclaim the packet. */ +typedef HTC_SEND_FULL_ACTION (*HTC_EP_SEND_QUEUE_FULL)(void *, + HTC_PACKET * + pPacket); + +typedef struct _HTC_EP_CALLBACKS { + void *pContext; /* context for each callback */ + HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */ + HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */ + HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */ + HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */ + HTC_EP_RECV_ALLOC EpRecvAlloc; /* OPTIONAL recv allocation callback */ + HTC_EP_RECV_ALLOC EpRecvAllocThresh; /* OPTIONAL recv allocation callback based on a threshold */ + HTC_EP_SEND_PKT_COMP_MULTIPLE EpTxCompleteMultiple; /* OPTIONAL completion handler for multiple complete + indications (EpTxComplete must be NULL) */ + HTC_EP_RECV_PKT_MULTIPLE EpRecvPktMultiple; /* OPTIONAL completion handler for multiple + recv packet indications (EpRecv must be NULL) */ + int RecvAllocThreshold; /* if EpRecvAllocThresh is non-NULL, HTC will compare the + threshold value to the current recv packet length and invoke + the EpRecvAllocThresh callback to acquire a packet buffer */ + int RecvRefillWaterMark; /* if a EpRecvRefill handler is provided, this value + can be used to set a trigger refill callback + when the recv queue drops below this value + if set to 0, the refill is only called when packets + are empty */ +} HTC_EP_CALLBACKS; + +/* service connection information */ +typedef struct _HTC_SERVICE_CONNECT_REQ { + HTC_SERVICE_ID ServiceID; /* service ID to connect to */ + A_UINT16 ConnectionFlags; /* connection flags, see htc protocol definition */ + A_UINT8 *pMetaData; /* ptr to optional service-specific meta-data */ + A_UINT8 MetaDataLength; /* optional meta data length */ + HTC_EP_CALLBACKS EpCallbacks; /* endpoint callbacks */ + int MaxSendQueueDepth; /* maximum depth of any send queue */ + A_UINT32 LocalConnectionFlags; /* HTC flags for the host-side (local) connection */ + unsigned int MaxSendMsgSize; /* override max message size in send direction */ +} HTC_SERVICE_CONNECT_REQ; + +#define HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING (1 << 0) /* enable send bundle padding for this endpoint */ + +/* service connection response information */ +typedef struct _HTC_SERVICE_CONNECT_RESP { + A_UINT8 *pMetaData; /* caller supplied buffer to optional meta-data */ + A_UINT8 BufferLength; /* length of caller supplied buffer */ + A_UINT8 ActualLength; /* actual length of meta data */ + HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */ + unsigned int MaxMsgLength; /* max length of all messages over this endpoint */ + A_UINT8 ConnectRespCode; /* connect response code from target */ +} HTC_SERVICE_CONNECT_RESP; + +/* endpoint distribution structure */ +typedef struct _HTC_ENDPOINT_CREDIT_DIST { + struct _HTC_ENDPOINT_CREDIT_DIST *pNext; + struct _HTC_ENDPOINT_CREDIT_DIST *pPrev; + HTC_SERVICE_ID ServiceID; /* Service ID (set by HTC) */ + HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */ + A_UINT32 DistFlags; /* distribution flags, distribution function can + set default activity using SET_EP_ACTIVE() macro */ + int TxCreditsNorm; /* credits for normal operation, anything above this + indicates the endpoint is over-subscribed, this field + is only relevant to the credit distribution function */ + int TxCreditsMin; /* floor for credit distribution, this field is + only relevant to the credit distribution function */ + int TxCreditsAssigned; /* number of credits assigned to this EP, this field + is only relevant to the credit dist function */ + int TxCredits; /* current credits available, this field is used by + HTC to determine whether a message can be sent or + must be queued */ + int TxCreditsToDist; /* pending credits to distribute on this endpoint, this + is set by HTC when credit reports arrive. + The credit distribution functions sets this to zero + when it distributes the credits */ + int TxCreditsSeek; /* this is the number of credits that the current pending TX + packet needs to transmit. This is set by HTC when + and endpoint needs credits in order to transmit */ + int TxCreditSize; /* size in bytes of each credit (set by HTC) */ + int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */ + void *pHTCReserved; /* reserved for HTC use */ + int TxQueueDepth; /* current depth of TX queue , i.e. messages waiting for credits + This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE + or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint + that has non-zero credits to recover + */ +} HTC_ENDPOINT_CREDIT_DIST; + +#define HTC_EP_ACTIVE ((A_UINT32) (1u << 31)) + +/* macro to check if an endpoint has gone active, useful for credit + * distributions */ +#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE) +#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE + +/* credit distibution code that is passed into the distrbution function, + * there are mandatory and optional codes that must be handled */ +typedef enum _HTC_CREDIT_DIST_REASON { + HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed + send operations (MANDATORY) resulting in credit reports */ + HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */ + HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */ + HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by + the distribution function */ +} HTC_CREDIT_DIST_REASON; + +typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context, + HTC_ENDPOINT_CREDIT_DIST * + pEPList, + HTC_CREDIT_DIST_REASON + Reason); + +typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context, + HTC_ENDPOINT_CREDIT_DIST * + pEPList, int TotalCredits); + +/* endpoint statistics action */ +typedef enum _HTC_ENDPOINT_STAT_ACTION { + HTC_EP_STAT_SAMPLE = 0, /* only read statistics */ + HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */ + HTC_EP_STAT_CLEAR /* clear only */ +} HTC_ENDPOINT_STAT_ACTION; + +/* endpoint statistics */ +typedef struct _HTC_ENDPOINT_STATS { + A_UINT32 TxPosted; /* number of TX packets posted to the endpoint */ + A_UINT32 TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on + this endpoint */ + A_UINT32 TxIssued; /* running count of total TX packets issued */ + A_UINT32 TxPacketsBundled; /* running count of TX packets that were issued in bundles */ + A_UINT32 TxBundles; /* running count of TX bundles that were issued */ + A_UINT32 TxDropped; /* tx packets that were dropped */ + A_UINT32 TxCreditRpts; /* running count of total credit reports received for this endpoint */ + A_UINT32 TxCreditRptsFromRx; /* credit reports received from this endpoint's RX packets */ + A_UINT32 TxCreditRptsFromOther; /* credit reports received from RX packets of other endpoints */ + A_UINT32 TxCreditRptsFromEp0; /* credit reports received from endpoint 0 RX packets */ + A_UINT32 TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */ + A_UINT32 TxCreditsFromOther; /* count of credits received via another endpoint */ + A_UINT32 TxCreditsFromEp0; /* count of credits received via another endpoint */ + A_UINT32 TxCreditsConsummed; /* count of consummed credits */ + A_UINT32 TxCreditsReturned; /* count of credits returned */ + A_UINT32 RxReceived; /* count of RX packets received */ + A_UINT32 RxLookAheads; /* count of lookahead records + found in messages received on this endpoint */ + A_UINT32 RxPacketsBundled; /* count of recv packets received in a bundle */ + A_UINT32 RxBundleLookAheads; /* count of number of bundled lookaheads */ + A_UINT32 RxBundleIndFromHdr; /* count of the number of bundle indications from the HTC header */ + A_UINT32 RxAllocThreshHit; /* count of the number of times the recv allocation threshhold was hit */ + A_UINT32 RxAllocThreshBytes; /* total number of bytes */ +} HTC_ENDPOINT_STATS; + +/* ------ Function Prototypes ------ */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Create an instance of HTC over the underlying HIF device + @function name: htc_create + @input: HifDevice - hif device handle, + pInfo - initialization information + @output: + @return: HTC_HANDLE on success, NULL on failure + @notes: + @example: + @see also: htc_destroy + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +HTC_HANDLE htc_create(void *HifDevice, + HTC_INIT_INFO *pInfo, cdf_device_t osdev); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get the underlying HIF device handle + @function name: htc_get_hif_device + @input: HTCHandle - handle passed into the AddInstance callback + @output: + @return: opaque HIF device handle usable in HIF API calls. + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void *htc_get_hif_device(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Set credit distribution parameters + @function name: htc_set_credit_distribution + @input: HTCHandle - HTC handle + pCreditDistCont - caller supplied context to pass into distribution functions + CreditDistFunc - Distribution function callback + CreditDistInit - Credit Distribution initialization callback + ServicePriorityOrder - Array containing list of service IDs, lowest index is highest + priority + ListLength - number of elements in ServicePriorityOrder + @output: + @return: + @notes: The user can set a custom credit distribution function to handle special requirements + for each endpoint. A default credit distribution routine can be used by setting + CreditInitFunc to NULL. The default credit distribution is only provided for simple + "fair" credit distribution without regard to any prioritization. + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_set_credit_distribution(HTC_HANDLE HTCHandle, + void *pCreditDistContext, + HTC_CREDIT_DIST_CALLBACK CreditDistFunc, + HTC_CREDIT_INIT_CALLBACK CreditInitFunc, + HTC_SERVICE_ID ServicePriorityOrder[], + int ListLength); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Wait for the target to indicate the HTC layer is ready + @function name: htc_wait_target + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This API blocks until the target responds with an HTC ready message. + The caller should not connect services until the target has indicated it is + ready. + @example: + @see also: htc_connect_service + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_wait_target(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Start target service communications + @function name: htc_start + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This API indicates to the target that the service connection phase is complete + and the target can freely start all connected services. This API should only be + called AFTER all service connections have been made. TCStart will issue a + SETUP_COMPLETE message to the target to indicate that all service connections + have been made and the target can start communicating over the endpoints. + @example: + @see also: htc_connect_service + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_start(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Add receive packet to HTC + @function name: htc_add_receive_pkt + @input: HTCHandle - HTC handle + pPacket - HTC receive packet to add + @output: + @return: A_OK on success + @notes: user must supply HTC packets for capturing incomming HTC frames. The caller + must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL() + macro. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Connect to an HTC service + @function name: htc_connect_service + @input: HTCHandle - HTC handle + pReq - connection details + @output: pResp - connection response + @return: + @notes: Service connections must be performed before htc_start. User provides callback handlers + for various endpoint events. + @example: + @see also: htc_start + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_connect_service(HTC_HANDLE HTCHandle, + HTC_SERVICE_CONNECT_REQ *pReq, + HTC_SERVICE_CONNECT_RESP *pResp); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: HTC register log dump + @function name: htc_dump + @input: HTCHandle - HTC handle + CmdId - Log command + start - start/print logs + @output: + @return: + @notes: Register logs will be started/printed. + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Send an HTC packet + @function name: htc_send_pkt + @input: HTCHandle - HTC handle + pPacket - packet to send + @output: + @return: A_OK + @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro. + This interface is fully asynchronous. On error, HTC SendPkt will + call the registered Endpoint callback to cleanup the packet. + @example: + @see also: htc_flush_endpoint + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Send an HTC packet containing a tx descriptor and data + @function name: htc_send_data_pkt + @input: HTCHandle - HTC handle + pPacket - packet to send + @output: + @return: A_OK + @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro. + Caller must provide headroom in an initial fragment added to the + network buffer to store a HTC_FRAME_HDR. + This interface is fully asynchronous. On error, htc_send_data_pkt will + call the registered Endpoint EpDataTxComplete callback to cleanup + the packet. + @example: + @see also: htc_send_pkt + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#ifdef ATH_11AC_TXCOMPACT +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, cdf_nbuf_t netbuf, + int Epid, int ActualLength); +#else /*ATH_11AC_TXCOMPACT */ +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, + A_UINT8 more_data); +#endif /*ATH_11AC_TXCOMPACT */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Flush HTC when target is removed surprisely service communications + @function name: htc_flush_surprise_remove + @input: HTCHandle - HTC handle + @output: + @return: + @notes: All receive and pending TX packets will + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_flush_surprise_remove(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Stop HTC service communications + @function name: htc_stop + @input: HTCHandle - HTC handle + @output: + @return: + @notes: HTC communications is halted. All receive and pending TX packets will + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_stop(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Destory HTC service + @function name: htc_destroy + @input: HTCHandle + @output: + @return: + @notes: This cleans up all resources allocated by htc_create(). + @example: + @see also: htc_create + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_destroy(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Flush pending TX packets + @function name: htc_flush_endpoint + @input: HTCHandle - HTC handle + Endpoint - Endpoint to flush + Tag - flush tag + @output: + @return: + @notes: The Tag parameter is used to selectively flush packets with matching tags. + The value of 0 forces all packets to be flush regardless of tag. + @example: + @see also: htc_send_pkt + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, + HTC_TX_TAG Tag); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Dump credit distribution state + @function name: htc_dump_credit_states + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This dumps all credit distribution information to the debugger + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_dump_credit_states(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Indicate a traffic activity change on an endpoint + @function name: htc_indicate_activity_change + @input: HTCHandle - HTC handle + Endpoint - endpoint in which activity has changed + Active - true if active, false if it has become inactive + @output: + @return: + @notes: This triggers the registered credit distribution function to + re-adjust credits for active/inactive endpoints. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_indicate_activity_change(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, A_BOOL Active); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get endpoint statistics + @function name: htc_get_endpoint_statistics + @input: HTCHandle - HTC handle + Endpoint - Endpoint identifier + Action - action to take with statistics + @output: + pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR) + + @return: true if statistics profiling is enabled, otherwise false. + + @notes: Statistics is a compile-time option and this function may return false + if HTC is not compiled with profiling. + + The caller can specify the statistic "action" to take when sampling + the statistics. This includes: + + HTC_EP_STAT_SAMPLE: The pStats structure is filled with the current values. + HTC_EP_STAT_SAMPLE_AND_CLEAR: The structure is filled and the current statistics + are cleared. + HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL value for + pStats + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_BOOL htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, + HTC_ENDPOINT_STAT_ACTION Action, + HTC_ENDPOINT_STATS *pStats); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Unblock HTC message reception + @function name: htc_unblock_recv + @input: HTCHandle - HTC handle + @output: + @return: + @notes: + HTC will block the receiver if the EpRecvAlloc callback fails to provide a packet. + The caller can use this API to indicate to HTC when resources (buffers) are available + such that the receiver can be unblocked and HTC may re-attempt fetching the pending message. + + This API is not required if the user uses the EpRecvRefill callback or uses the HTCAddReceivePacket() + API to recycle or provide receive packets to HTC. + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_unblock_recv(HTC_HANDLE HTCHandle); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: send a series of HTC packets + @function name: htc_send_pkts_multiple + @input: HTCHandle - HTC handle + pPktQueue - local queue holding packets to send + @output: + @return: A_OK + @notes: Caller must initialize each packet using SET_HTC_PACKET_INFO_TX() macro. + The queue must only contain packets directed at the same endpoint. + Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the TX packets in FIFO order. + This API will remove the packets from the pkt queue and place them into the HTC Tx Queue + and bundle messages where possible. + The caller may allocate the pkt queue on the stack to hold the packets. + This interface is fully asynchronous. On error, htc_send_pkts will + call the registered Endpoint callback to cleanup the packet. + @example: + @see also: htc_flush_endpoint + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Add multiple receive packets to HTC + @function name: htc_add_receive_pkt_multiple + @input: HTCHandle - HTC handle + pPktQueue - HTC receive packet queue holding packets to add + @output: + @return: A_OK on success + @notes: user must supply HTC packets for capturing incomming HTC frames. The caller + must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL() + macro. The queue must only contain recv packets for the same endpoint. + Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the recv packet. + This API will remove the packets from the pkt queue and place them into internal + recv packet list. + The caller may allocate the pkt queue on the stack to hold the packets. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Check if an endpoint is marked active + @function name: htc_is_endpoint_active + @input: HTCHandle - HTC handle + Endpoint - endpoint to check for active state + @output: + @return: returns true if Endpoint is Active + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_BOOL htc_is_endpoint_active(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get the number of recv buffers currently queued into an HTC endpoint + @function name: htc_get_num_recv_buffers + @input: HTCHandle - HTC handle + Endpoint - endpoint to check + @output: + @return: returns number of buffers in queue + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Set the target failure handling callback in HTC layer + @function name: htc_set_target_failure_callback + @input: HTCHandle - HTC handle + Callback - target failure handling callback + @output: + @return: + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_set_target_failure_callback(HTC_HANDLE HTCHandle, + HTC_TARGET_FAILURE Callback); + +/* internally used functions for testing... */ +void htc_enable_recv(HTC_HANDLE HTCHandle); +void htc_disable_recv(HTC_HANDLE HTCHandle); +A_STATUS HTCWaitForPendingRecv(HTC_HANDLE HTCHandle, + A_UINT32 TimeoutInMs, + A_BOOL *pbIsRecvPending); + +/* function to fetch stats from htc layer*/ +struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE + HTCHandle); + +#ifdef HIF_USB +#define HTCReturnReceivePkt(target,p,osbuf) \ + A_NETBUF_FREE(osbuf); \ + if(p->Status == A_CLONE) { \ + cdf_mem_free(p); \ + } +#else +#define HTCReturnReceivePkt(target,p,osbuf) htc_add_receive_pkt(target,p) +#endif + +#ifdef WLAN_FEATURE_FASTPATH +#define HTC_TX_DESC_FILL(_htc_tx_desc, _download_len, _ep_id, _seq_no) \ +do { \ + HTC_WRITE32((_htc_tx_desc), \ + SM((_download_len), HTC_FRAME_HDR_PAYLOADLEN) | \ + SM((_ep_id), HTC_FRAME_HDR_ENDPOINTID)); \ + \ + HTC_WRITE32((A_UINT32 *)(_htc_tx_desc) + 1, \ + SM((_seq_no), HTC_FRAME_HDR_CONTROLBYTES1));\ +} while (0) +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef __cplusplus +} +#endif +void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credit); +void htc_dump_counter_info(HTC_HANDLE HTCHandle); +void *htc_get_targetdef(HTC_HANDLE htc_handle); +void htc_set_target_to_sleep(void *context); +void htc_cancel_deferred_target_sleep(void *context); + +/* Disable ASPM : Disable PCIe low power */ +void htc_disable_aspm(void); + +#ifdef IPA_OFFLOAD +void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle, + uint32_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + cdf_dma_addr_t *ce_reg_paddr); +#else +#define htc_ipa_get_ce_resource(htc_handle, \ + ce_sr_base_paddr, \ + ce_sr_ring_size, \ + ce_reg_paddr) /* NO-OP */ +#endif /* IPA_OFFLOAD */ +#endif /* _HTC_API_H_ */ diff --git a/core/htc/htc_debug.h b/core/htc/htc_debug.h new file mode 100644 index 0000000000..fe0c8496f8 --- /dev/null +++ b/core/htc/htc_debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HTC_DEBUG_H_ +#define HTC_DEBUG_H_ + +#define ATH_MODULE_NAME htc +#include "a_debug.h" +#include "cdf_trace.h" + +/* ------- Debug related stuff ------- */ + +#define ATH_DEBUG_SEND ATH_DEBUG_MAKE_MODULE_MASK(0) +#define ATH_DEBUG_RECV ATH_DEBUG_MAKE_MODULE_MASK(1) +#define ATH_DEBUG_SYNC ATH_DEBUG_MAKE_MODULE_MASK(2) +#define ATH_DEBUG_DUMP ATH_DEBUG_MAKE_MODULE_MASK(3) +#define ATH_DEBUG_SETUP ATH_DEBUG_MAKE_MODULE_MASK(4) +#define HTC_ERROR(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_ERROR, ## args) +#define HTC_WARN(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_WARN, ## args) +#define HTC_INFO(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_INFO, ## args) +#define HTC_TRACE(args ...) \ + CDF_TRACE(CDF_MODULE_ID_HTC, CDF_TRACE_LEVEL_DEBUG, ## args) +#endif /*HTC_DEBUG_H_ */ diff --git a/core/htc/htc_internal.h b/core/htc/htc_internal.h new file mode 100644 index 0000000000..2e48b790d4 --- /dev/null +++ b/core/htc/htc_internal.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTC_INTERNAL_H_ +#define _HTC_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include "a_types.h" +#include "osapi_linux.h" +#include +#include +#include +#include +#include +#include "hif.h" +#include +#include "htc_api.h" +#include "htc_packet.h" + +/* HTC operational parameters */ +#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ +#define HTC_TARGET_DEBUG_INTR_MASK 0x01 +#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 +#define HTC_MIN_MSG_PER_BUNDLE 2 +#if defined(HIF_USB) +#define HTC_MAX_MSG_PER_BUNDLE 9 +#else +#define HTC_MAX_MSG_PER_BUNDLE 16 +#endif +/* + * HTC_MAX_TX_BUNDLE_SEND_LIMIT - + * This value is in units of tx frame fragments. + * It needs to be at least as large as the maximum number of tx frames in a + * HTC download bundle times the average number of fragments in each such frame + * (In certain operating systems, such as Linux, we expect to only have + * a single fragment per frame anyway.) + */ +#define HTC_MAX_TX_BUNDLE_SEND_LIMIT 255 + +#define HTC_PACKET_CONTAINER_ALLOCATION 32 +#define NUM_CONTROL_TX_BUFFERS 2 +#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH) +#define HTC_CONTROL_BUFFER_ALIGN 32 +#define HTC_TARGET_RESPONSE_POLL_MS 10 +#if !defined(A_SIMOS_DEVHOST) +#define HTC_TARGET_MAX_RESPONSE_POLL 200 /* actual HW */ +#else +#define HTC_TARGET_MAX_RESPONSE_POLL 600 /* host + target simulation */ +#endif + +#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL + +#define HTC_CREDIT_HISTORY_MAX 1024 + +typedef enum { + HTC_REQUEST_CREDIT, + HTC_PROCESS_CREDIT_REPORT, + HTC_SUSPEND_ACK, + HTC_SUSPEND_NACK, +} htc_credit_exchange_type; + +typedef struct { + htc_credit_exchange_type type; + uint64_t time; + uint32_t tx_credit; + uint32_t htc_tx_queue_depth; +} HTC_CREDIT_HISTORY; + +typedef struct _HTC_ENDPOINT { + HTC_ENDPOINT_ID Id; + HTC_SERVICE_ID ServiceID; /* service ID this endpoint is bound to + non-zero value means this endpoint is in use */ + HTC_EP_CALLBACKS EpCallBacks; /* callbacks associated with this endpoint */ + HTC_PACKET_QUEUE TxQueue; /* HTC frame buffer TX queue */ + int MaxTxQueueDepth; /* max depth of the TX queue before we need to + call driver's full handler */ + int MaxMsgLength; /* max length of endpoint message */ + uint8_t UL_PipeID; + uint8_t DL_PipeID; + int ul_is_polled; /* Need to call HIF to get tx completion callbacks? */ + cdf_softirq_timer_t ul_poll_timer; + int ul_poll_timer_active; + int ul_outstanding_cnt; + int dl_is_polled; /* Need to call HIF to fetch rx? (Not currently supported.) */ +#if 0 /* not currently supported */ + cdf_softirq_timer_t dl_poll_timer; +#endif + + HTC_PACKET_QUEUE TxLookupQueue; /* lookup queue to match netbufs to htc packets */ + HTC_PACKET_QUEUE RxBufferHoldQueue; /* temporary hold queue for back compatibility */ + A_UINT8 SeqNo; /* TX seq no (helpful) for debugging */ + cdf_atomic_t TxProcessCount; /* serialization */ + struct _HTC_TARGET *target; + int TxCredits; /* TX credits available on this endpoint */ + int TxCreditSize; /* size in bytes of each credit (set by HTC) */ + int TxCreditsPerMaxMsg; /* credits required per max message (precalculated) */ +#ifdef HTC_EP_STAT_PROFILING + HTC_ENDPOINT_STATS EndPointStats; /* endpoint statistics */ +#endif + A_BOOL TxCreditFlowEnabled; +} HTC_ENDPOINT; + +#ifdef HTC_EP_STAT_PROFILING +#define INC_HTC_EP_STAT(p,stat,count) (p)->EndPointStats.stat += (count); +#else +#define INC_HTC_EP_STAT(p,stat,count) +#endif + +typedef struct { + A_UINT16 ServiceID; + A_UINT8 CreditAllocation; +} HTC_SERVICE_TX_CREDIT_ALLOCATION; + +#define HTC_MAX_SERVICE_ALLOC_ENTRIES 8 + +/* Error codes for HTC layer packet stats*/ +enum ol_ath_htc_pkt_ecodes { + GET_HTC_PKT_Q_FAIL = 0, /* error- get packet at head of HTC_PACKET_Q */ + HTC_PKT_Q_EMPTY, + HTC_SEND_Q_EMPTY +}; +/* our HTC target state */ +typedef struct _HTC_TARGET { + struct ol_softc *hif_dev; + HTC_ENDPOINT EndPoint[ENDPOINT_MAX]; + cdf_spinlock_t HTCLock; + cdf_spinlock_t HTCRxLock; + cdf_spinlock_t HTCTxLock; + cdf_spinlock_t HTCCreditLock; + A_UINT32 HTCStateFlags; + void *host_handle; + HTC_INIT_INFO HTCInitInfo; + HTC_PACKET *pHTCPacketStructPool; /* pool of HTC packets */ + HTC_PACKET_QUEUE ControlBufferTXFreeList; + A_UINT8 CtrlResponseBuffer[HTC_MAX_CONTROL_MESSAGE_LENGTH]; + int CtrlResponseLength; + cdf_semaphore_t CtrlResponseValid; + A_BOOL CtrlResponseProcessing; + int TotalTransmitCredits; + HTC_SERVICE_TX_CREDIT_ALLOCATION + ServiceTxAllocTable[HTC_MAX_SERVICE_ALLOC_ENTRIES]; + int TargetCreditSize; +#ifdef RX_SG_SUPPORT + cdf_nbuf_queue_t RxSgQueue; + A_BOOL IsRxSgInprogress; + A_UINT32 CurRxSgTotalLen; /* current total length */ + A_UINT32 ExpRxSgTotalLen; /* expected total length */ +#endif + cdf_device_t osdev; + struct ol_ath_htc_stats htc_pkt_stats; + HTC_PACKET *pBundleFreeList; + A_UINT32 ce_send_cnt; + A_UINT32 TX_comp_cnt; + A_UINT8 MaxMsgsPerHTCBundle; +} HTC_TARGET; + +#define HTC_ENABLE_BUNDLE(target) (target->MaxMsgsPerHTCBundle > 1) +#ifdef RX_SG_SUPPORT +#define RESET_RX_SG_CONFIG(_target) \ + _target->ExpRxSgTotalLen = 0; \ + _target->CurRxSgTotalLen = 0; \ + _target->IsRxSgInprogress = false; +#endif + +#define HTC_STATE_STOPPING (1 << 0) +#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING) +#define LOCK_HTC(t) cdf_spin_lock_bh(&(t)->HTCLock); +#define UNLOCK_HTC(t) cdf_spin_unlock_bh(&(t)->HTCLock); +#define LOCK_HTC_RX(t) cdf_spin_lock_bh(&(t)->HTCRxLock); +#define UNLOCK_HTC_RX(t) cdf_spin_unlock_bh(&(t)->HTCRxLock); +#define LOCK_HTC_TX(t) cdf_spin_lock_bh(&(t)->HTCTxLock); +#define UNLOCK_HTC_TX(t) cdf_spin_unlock_bh(&(t)->HTCTxLock); +#define LOCK_HTC_CREDIT(t) cdf_spin_lock_bh(&(t)->HTCCreditLock); +#define UNLOCK_HTC_CREDIT(t) cdf_spin_unlock_bh(&(t)->HTCCreditLock); + +#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd)) + +#define IS_TX_CREDIT_FLOW_ENABLED(ep) ((ep)->TxCreditFlowEnabled) + +#define HTC_POLL_CLEANUP_PERIOD_MS 10 /* milliseconds */ + +/* Macro to Increment the HTC_PACKET_ERRORS for Tx.*/ +#define OL_ATH_HTC_PKT_ERROR_COUNT_INCR(_target,_ecode) \ + do { \ + if(_ecode==GET_HTC_PKT_Q_FAIL) (_target->htc_pkt_stats.htc_get_pkt_q_fail_count)+=1; \ + if(_ecode==HTC_PKT_Q_EMPTY) (_target->htc_pkt_stats.htc_pkt_q_empty_count)+=1; \ + if(_ecode==HTC_SEND_Q_EMPTY) (_target->htc_pkt_stats.htc_send_q_empty_count)+=1; \ + } while(0); +/* internal HTC functions */ + +CDF_STATUS htc_rx_completion_handler(void *Context, cdf_nbuf_t netbuf, + uint8_t pipeID); +CDF_STATUS htc_tx_completion_handler(void *Context, cdf_nbuf_t netbuf, + unsigned int transferID, uint32_t toeplitz_hash_result); + +HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target); +void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket); + +HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target); +void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket); +void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint); +void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_TX_TAG Tag); +void htc_recv_init(HTC_TARGET *target); +A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target); +void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket); +HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target); +A_UINT8 htc_get_credit_allocation(HTC_TARGET *target, A_UINT16 ServiceID); +void htc_tx_resource_avail_handler(void *context, A_UINT8 pipeID); +void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket); +void htc_process_credit_rpt(HTC_TARGET *target, + HTC_CREDIT_REPORT *pRpt, + int NumEntries, HTC_ENDPOINT_ID FromEndpoint); +void htc_fw_event_handler(void *context, CDF_STATUS status); +void htc_send_complete_check_cleanup(void *context); + +void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit, + uint32_t htc_tx_queue_depth); + +static inline void htc_send_complete_poll_timer_stop(HTC_ENDPOINT * + pEndpoint) { + LOCK_HTC_TX(pEndpoint->target); + if (pEndpoint->ul_poll_timer_active) { + /* cdf_softirq_timer_cancel(&pEndpoint->ul_poll_timer); */ + pEndpoint->ul_poll_timer_active = 0; + } + UNLOCK_HTC_TX(pEndpoint->target); +} + +static inline void htc_send_complete_poll_timer_start(HTC_ENDPOINT * + pEndpoint) { + LOCK_HTC_TX(pEndpoint->target); + if (pEndpoint->ul_outstanding_cnt + && !pEndpoint->ul_poll_timer_active) { + /* + cdf_softirq_timer_start( + &pEndpoint->ul_poll_timer, HTC_POLL_CLEANUP_PERIOD_MS); + */ + pEndpoint->ul_poll_timer_active = 1; + } + UNLOCK_HTC_TX(pEndpoint->target); +} + +static inline void +htc_send_complete_check(HTC_ENDPOINT *pEndpoint, int force) { + /* + * Stop the polling-cleanup timer that will result in a later call to + * this function. It may get started again below, if there are still + * outsending sends. + */ + htc_send_complete_poll_timer_stop(pEndpoint); + /* + * Check whether HIF has any prior sends that have finished, + * have not had the post-processing done. + */ + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, force); + /* + * If there are still outstanding sends after polling, start a timer + * to check again a little later. + */ + htc_send_complete_poll_timer_start(pEndpoint); +} + +#ifdef __cplusplus +} +#endif + +#ifndef DEBUG_BUNDLE +#define DEBUG_BUNDLE 0 +#endif + +#ifdef HIF_SDIO +#ifndef ENABLE_BUNDLE_TX +#define ENABLE_BUNDLE_TX 1 +#endif + +#ifndef ENABLE_BUNDLE_RX +#define ENABLE_BUNDLE_RX 1 +#endif +#endif /* HIF_SDIO */ +#endif /* !_HTC_HOST_INTERNAL_H_ */ diff --git a/core/htc/htc_packet.h b/core/htc/htc_packet.h new file mode 100644 index 0000000000..c30d511443 --- /dev/null +++ b/core/htc/htc_packet.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HTC_PACKET_H_ +#define HTC_PACKET_H_ + +#include +#include /* A_UINT16, etc. */ +#include "dl_list.h" + +/* ------ Endpoint IDS ------ */ +typedef enum { + ENDPOINT_UNUSED = -1, + ENDPOINT_0 = 0, + ENDPOINT_1 = 1, + ENDPOINT_2 = 2, + ENDPOINT_3, + ENDPOINT_4, + ENDPOINT_5, + ENDPOINT_6, + ENDPOINT_7, + ENDPOINT_8, + ENDPOINT_MAX, +} HTC_ENDPOINT_ID; + +struct _HTC_PACKET; + +typedef void (*HTC_PACKET_COMPLETION)(void *, struct _HTC_PACKET *); + +typedef A_UINT16 HTC_TX_TAG; + +typedef struct _HTC_TX_PACKET_INFO { + HTC_TX_TAG Tag; /* tag used to selective flush packets */ + int CreditsUsed; /* number of credits used for this TX packet (HTC internal) */ + A_UINT8 SendFlags; /* send flags (HTC internal) */ + int SeqNo; /* internal seq no for debugging (HTC internal) */ + A_UINT32 Flags; /* internal use */ +} HTC_TX_PACKET_INFO; + +#define HTC_TX_PACKET_TAG_ALL 0 /* a tag of zero is reserved and used to flush ALL packets */ +#define HTC_TX_PACKET_TAG_INTERNAL 1 /* internal tags start here */ +#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) /* user-defined tags start here */ +#define HTC_TX_PACKET_TAG_BUNDLED HTC_TX_PACKET_TAG_USER_DEFINED + 1 /* indicate this is bundled TX packet */ + +#define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0) + +typedef struct _HTC_RX_PACKET_INFO { + A_UINT32 ExpectedHdr; /* HTC internal use */ + A_UINT32 HTCRxFlags; /* HTC internal use */ + A_UINT32 IndicationFlags; /* indication flags set on each RX packet indication */ +} HTC_RX_PACKET_INFO; + +#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) /* more packets on this endpoint are being fetched */ + +/* wrapper around endpoint-specific packets */ +typedef struct _HTC_PACKET { + DL_LIST ListLink; /* double link */ + void *pPktContext; /* caller's per packet specific context */ + + A_UINT8 *pBufferStart; /* the true buffer start , the caller can + store the real buffer start here. In + receive callbacks, the HTC layer sets pBuffer + to the start of the payload past the header. This + field allows the caller to reset pBuffer when it + recycles receive packets back to HTC */ + /* + * Pointer to the start of the buffer. In the transmit + * direction this points to the start of the payload. In the + * receive direction, however, the buffer when queued up + * points to the start of the HTC header but when returned + * to the caller points to the start of the payload + */ + A_UINT8 *pBuffer; /* payload start (RX/TX) */ + A_UINT32 BufferLength; /* length of buffer */ + A_UINT32 ActualLength; /* actual length of payload */ + HTC_ENDPOINT_ID Endpoint; /* endpoint that this packet was sent/recv'd from */ + A_STATUS Status; /* completion status */ + union { + HTC_TX_PACKET_INFO AsTx; /* Tx Packet specific info */ + HTC_RX_PACKET_INFO AsRx; /* Rx Packet specific info */ + } PktInfo; + + /* the following fields are for internal HTC use */ + A_UINT32 netbufOrigHeadRoom; + HTC_PACKET_COMPLETION Completion; /* completion */ + void *pContext; /* HTC private completion context */ + void *pNetBufContext; /* optimization for network-oriented data, the HTC packet + can pass the network buffer corresponding to the HTC packet + lower layers may optimized the transfer knowing this is + a network buffer */ +} HTC_PACKET; + +#define COMPLETE_HTC_PACKET(p,status) \ + { \ + (p)->Status = (status); \ + (p)->Completion((p)->pContext,(p)); \ + } + +#define INIT_HTC_PACKET_INFO(p,b,len) \ + { \ + (p)->pBufferStart = (b); \ + (p)->BufferLength = (len); \ + } + +/* macro to set an initial RX packet for refilling HTC */ +#define SET_HTC_PACKET_INFO_RX_REFILL(p,c,b,len,ep) \ + { \ + (p)->pPktContext = (c); \ + (p)->pBuffer = (b); \ + (p)->pBufferStart = (b); \ + (p)->BufferLength = (len); \ + (p)->Endpoint = (ep); \ + } + +/* fast macro to recycle an RX packet that will be re-queued to HTC */ +#define HTC_PACKET_RESET_RX(p) \ + { (p)->pBuffer = (p)->pBufferStart; (p)->ActualLength = 0; } + +/* macro to set packet parameters for TX */ +#define SET_HTC_PACKET_INFO_TX(p,c,b,len,ep,tag) \ + { \ + (p)->pPktContext = (c); \ + (p)->pBuffer = (b); \ + (p)->ActualLength = (len); \ + (p)->Endpoint = (ep); \ + (p)->PktInfo.AsTx.Tag = (tag); \ + (p)->PktInfo.AsTx.Flags = 0; \ + } + +#define SET_HTC_PACKET_NET_BUF_CONTEXT(p,nb) \ + (p)->pNetBufContext = (nb) + +#define GET_HTC_PACKET_NET_BUF_CONTEXT(p) (p)->pNetBufContext + +/* HTC Packet Queueing Macros */ +typedef struct _HTC_PACKET_QUEUE { + DL_LIST QueueHead; + int Depth; +} HTC_PACKET_QUEUE; + +/* initialize queue */ +#define INIT_HTC_PACKET_QUEUE(pQ) \ + { \ + DL_LIST_INIT(& (pQ)->QueueHead); \ + (pQ)->Depth = 0; \ + } + +/* enqueue HTC packet to the tail of the queue */ +#define HTC_PACKET_ENQUEUE(pQ,p) \ + { dl_list_insert_tail(& (pQ)->QueueHead,& (p)->ListLink); \ + (pQ)->Depth ++; \ + } + +/* enqueue HTC packet to the tail of the queue */ +#define HTC_PACKET_ENQUEUE_TO_HEAD(pQ,p) \ + { dl_list_insert_head(& (pQ)->QueueHead,& (p)->ListLink); \ + (pQ)->Depth ++; \ + } +/* test if a queue is empty */ +#define HTC_QUEUE_EMPTY(pQ) ((pQ)->Depth == 0) +/* get packet at head without removing it */ +static INLINE HTC_PACKET *htc_get_pkt_at_head(HTC_PACKET_QUEUE *queue) +{ + if (queue->Depth == 0) { + return NULL; + } + return + A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(&queue->QueueHead)), + HTC_PACKET, ListLink); +} + +/* remove a packet from a queue, where-ever it is in the queue */ +#define HTC_PACKET_REMOVE(pQ,p) \ + { \ + dl_list_remove(& (p)->ListLink); \ + (pQ)->Depth --; \ + } + +/* dequeue an HTC packet from the head of the queue */ +static INLINE HTC_PACKET *htc_packet_dequeue(HTC_PACKET_QUEUE *queue) +{ + DL_LIST *pItem = dl_list_remove_item_from_head(&queue->QueueHead); + if (pItem != NULL) { + queue->Depth--; + return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink); + } + return NULL; +} + +/* dequeue an HTC packet from the tail of the queue */ +static INLINE HTC_PACKET *htc_packet_dequeue_tail(HTC_PACKET_QUEUE *queue) +{ + DL_LIST *pItem = dl_list_remove_item_from_tail(&queue->QueueHead); + if (pItem != NULL) { + queue->Depth--; + return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink); + } + return NULL; +} + +#define HTC_PACKET_QUEUE_DEPTH(pQ) (pQ)->Depth + +#define HTC_GET_ENDPOINT_FROM_PKT(p) (p)->Endpoint +#define HTC_GET_TAG_FROM_PKT(p) (p)->PktInfo.AsTx.Tag + +/* transfer the packets from one queue to the tail of another queue */ +#define HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(pQDest,pQSrc) \ + { \ + dl_list_transfer_items_to_tail(&(pQDest)->QueueHead,&(pQSrc)->QueueHead); \ + (pQDest)->Depth += (pQSrc)->Depth; \ + (pQSrc)->Depth = 0; \ + } + +/* + * Transfer the packets from one queue to the head of another queue. + * This xfer_to_head(q1,q2) is basically equivalent to xfer_to_tail(q2,q1), + * but it updates the queue descriptor object for the initial queue to refer + * to the concatenated queue. + */ +#define HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(pQDest, pQSrc) \ + { \ + dl_list_transfer_items_to_head(&(pQDest)->QueueHead,&(pQSrc)->QueueHead); \ + (pQDest)->Depth += (pQSrc)->Depth; \ + (pQSrc)->Depth = 0; \ + } + +/* fast version to init and add a single packet to a queue */ +#define INIT_HTC_PACKET_QUEUE_AND_ADD(pQ,pP) \ + { \ + DL_LIST_INIT_AND_ADD(&(pQ)->QueueHead,&(pP)->ListLink) \ + (pQ)->Depth = 1; \ + } + +#define HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQ, pPTemp) \ + ITERATE_OVER_LIST_ALLOW_REMOVE(&(pQ)->QueueHead,(pPTemp), HTC_PACKET, ListLink) + +#define HTC_PACKET_QUEUE_ITERATE_IS_VALID(pQ) ITERATE_IS_VALID(&(pQ)->QueueHead) +#define HTC_PACKET_QUEUE_ITERATE_RESET(pQ) ITERATE_RESET(&(pQ)->QueueHead) + +#define HTC_PACKET_QUEUE_ITERATE_END ITERATE_END + +#endif /*HTC_PACKET_H_ */ diff --git a/core/htc/htc_recv.c b/core/htc/htc_recv.c new file mode 100644 index 0000000000..dd8719e264 --- /dev/null +++ b/core/htc/htc_recv.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include "cds_api.h" +#include /* cdf_nbuf_t */ +#include +#include "epping_main.h" + +#ifdef DEBUG +void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription) +{ + A_CHAR stream[60]; + A_CHAR byteOffsetStr[10]; + A_UINT32 i; + A_UINT16 offset, count, byteOffset; + + A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, + pDescription); + + count = 0; + offset = 0; + byteOffset = 0; + for (i = 0; i < length; i++) { + A_SNPRINTF(stream + offset, (sizeof(stream) - offset), + "%02X ", buffer[i]); + count++; + offset += 3; + + if (count == 16) { + count = 0; + offset = 0; + A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", + byteOffset); + A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); + A_MEMZERO(stream, 60); + byteOffset += 16; + } + } + + if (offset != 0) { + A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", + byteOffset); + A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); + } + + A_PRINTF("<------------------------------------------------->\n"); +} +#else +void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription) +{ +} +#endif + +static A_STATUS htc_process_trailer(HTC_TARGET *target, + A_UINT8 *pBuffer, + int Length, HTC_ENDPOINT_ID FromEndpoint); + +static void do_recv_completion(HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueueToIndicate) +{ + + do { + + if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { + /* nothing to indicate */ + break; + } + + if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + (" HTC calling ep %d, recv multiple callback (%d pkts) \n", + pEndpoint->Id, + HTC_PACKET_QUEUE_DEPTH + (pQueueToIndicate))); + /* a recv multiple handler is being used, pass the queue to the handler */ + pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint-> + EpCallBacks. + pContext, + pQueueToIndicate); + INIT_HTC_PACKET_QUEUE(pQueueToIndicate); + } else { + HTC_PACKET *pPacket; + /* using legacy EpRecv */ + while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { + pPacket = htc_packet_dequeue(pQueueToIndicate); + if (pEndpoint->EpCallBacks.EpRecv == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC ep %d has NULL recv callback on packet %p\n", + pEndpoint->Id, + pPacket)); + continue; + } + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("HTC calling ep %d recv callback on packet %p\n", + pEndpoint->Id, pPacket)); + pEndpoint->EpCallBacks.EpRecv(pEndpoint-> + EpCallBacks. + pContext, + pPacket); + } + } + + } while (false); + +} + +static void recv_packet_completion(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE container; + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + /* do completion */ + do_recv_completion(pEndpoint, &container); +} + +void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket) +{ + /* TODO, can't really receive HTC control messages yet.... */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid call to htc_control_rx_complete\n")); +} + +void htc_unblock_recv(HTC_HANDLE HTCHandle) +{ + /* TODO find the Need in new model */ +} + +void htc_enable_recv(HTC_HANDLE HTCHandle) +{ + + /* TODO find the Need in new model */ +} + +void htc_disable_recv(HTC_HANDLE HTCHandle) +{ + + /* TODO find the Need in new model */ +} + +int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint]; + return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue); +} + +HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + + LOCK_HTC_RX(target); + + if (NULL == target->pHTCPacketStructPool) { + UNLOCK_HTC_RX(target); + return NULL; + } + + pPacket = target->pHTCPacketStructPool; + target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext; + + UNLOCK_HTC_RX(target); + + pPacket->ListLink.pNext = NULL; + return pPacket; +} + +void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + LOCK_HTC_RX(target); + + if (NULL == target->pHTCPacketStructPool) { + target->pHTCPacketStructPool = pPacket; + pPacket->ListLink.pNext = NULL; + } else { + pPacket->ListLink.pNext = + (DL_LIST *) target->pHTCPacketStructPool; + target->pHTCPacketStructPool = pPacket; + } + + UNLOCK_HTC_RX(target); +} + +#ifdef RX_SG_SUPPORT +cdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target) +{ + cdf_nbuf_t skb; + uint8_t *anbdata; + uint8_t *anbdata_new; + uint32_t anblen; + cdf_nbuf_t new_skb = NULL; + uint32_t sg_queue_len; + cdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; + + sg_queue_len = cdf_nbuf_queue_len(rx_sg_queue); + + if (sg_queue_len <= 1) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("rx_sg_to_single_netbuf: invalid sg queue len %u\n")); + goto _failed; + } + + new_skb = cdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false); + if (new_skb == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n", + target->ExpRxSgTotalLen)); + goto _failed; + } + + cdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); + + skb = cdf_nbuf_queue_remove(rx_sg_queue); + do { + cdf_nbuf_peek_header(skb, &anbdata, &anblen); + cdf_mem_copy(anbdata_new, anbdata, cdf_nbuf_len(skb)); + cdf_nbuf_put_tail(new_skb, cdf_nbuf_len(skb)); + anbdata_new += cdf_nbuf_len(skb); + cdf_nbuf_free(skb); + skb = cdf_nbuf_queue_remove(rx_sg_queue); + } while (skb != NULL); + + RESET_RX_SG_CONFIG(target); + return new_skb; + +_failed: + + while ((skb = cdf_nbuf_queue_remove(rx_sg_queue)) != NULL) { + cdf_nbuf_free(skb); + } + + RESET_RX_SG_CONFIG(target); + return NULL; +} +#endif + +CDF_STATUS htc_rx_completion_handler(void *Context, cdf_nbuf_t netbuf, + uint8_t pipeID) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + HTC_FRAME_HDR *HtcHdr; + HTC_TARGET *target = (HTC_TARGET *) Context; + uint8_t *netdata; + uint32_t netlen; + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; + A_UINT16 payloadLen; + uint32_t trailerlen = 0; + A_UINT8 htc_ep_id; + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + if (target->IsRxSgInprogress) { + target->CurRxSgTotalLen += cdf_nbuf_len(netbuf); + cdf_nbuf_queue_add(&target->RxSgQueue, netbuf); + if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { + netbuf = rx_sg_to_single_netbuf(target); + if (netbuf == NULL) { + UNLOCK_HTC_RX(target); + goto _out; + } + } else { + netbuf = NULL; + UNLOCK_HTC_RX(target); + goto _out; + } + } + UNLOCK_HTC_RX(target); +#endif + + netdata = cdf_nbuf_data(netbuf); + netlen = cdf_nbuf_len(netbuf); + + HtcHdr = (HTC_FRAME_HDR *) netdata; + + do { + + htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); + + if (htc_ep_id >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx: invalid EndpointID=%d\n", + htc_ep_id)); + debug_dump_bytes((A_UINT8 *) HtcHdr, + sizeof(HTC_FRAME_HDR), "BAD HTC Header"); + status = CDF_STATUS_E_FAILURE; + CDF_BUG(0); + break; + } + + pEndpoint = &target->EndPoint[htc_ep_id]; + + /* + * If this endpoint that received a message from the target has + * a to-target HIF pipe whose send completions are polled rather + * than interrupt-driven, this is a good point to ask HIF to check + * whether it has any completed sends to handle. + */ + if (pEndpoint->ul_is_polled) { + htc_send_complete_check(pEndpoint, 1); + } + + payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); + + if (netlen < (payloadLen + HTC_HDR_LENGTH)) { +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + target->IsRxSgInprogress = true; + cdf_nbuf_queue_init(&target->RxSgQueue); + cdf_nbuf_queue_add(&target->RxSgQueue, netbuf); + target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); + target->CurRxSgTotalLen += netlen; + UNLOCK_HTC_RX(target); + netbuf = NULL; + break; +#else + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx: insufficient length, got:%d expected =%zu\n", + netlen, payloadLen + HTC_HDR_LENGTH)); + debug_dump_bytes((A_UINT8 *) HtcHdr, + sizeof(HTC_FRAME_HDR), + "BAD RX packet length"); + status = CDF_STATUS_E_FAILURE; + CDF_BUG(0); + break; +#endif + } +#ifdef HTC_EP_STAT_PROFILING + LOCK_HTC_RX(target); + INC_HTC_EP_STAT(pEndpoint, RxReceived, 1); + UNLOCK_HTC_RX(target); +#endif + + /* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */ + { + A_UINT8 temp; + A_STATUS temp_status; + /* get flags to check for trailer */ + temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); + if (temp & HTC_FLAGS_RECV_TRAILER) { + /* extract the trailer length */ + temp = + HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, + CONTROLBYTES0); + if ((temp < sizeof(HTC_RECORD_HDR)) + || (temp > payloadLen)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n", + payloadLen, temp)); + status = CDF_STATUS_E_INVAL; + break; + } + + trailerlen = temp; + /* process trailer data that follows HDR + application payload */ + temp_status = htc_process_trailer(target, + ((A_UINT8 *) HtcHdr + + HTC_HDR_LENGTH + + payloadLen - temp), + temp, htc_ep_id); + if (A_FAILED(temp_status)) { + status = CDF_STATUS_E_FAILURE; + break; + } + + } + } + + if (((int)payloadLen - (int)trailerlen) <= 0) { + /* zero length packet with trailer data, just drop these */ + break; + } + + if (htc_ep_id == ENDPOINT_0) { + A_UINT16 message_id; + HTC_UNKNOWN_MSG *htc_msg; + int wow_nack = 0; + + /* remove HTC header */ + cdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); + netdata = cdf_nbuf_data(netbuf); + netlen = cdf_nbuf_len(netbuf); + + htc_msg = (HTC_UNKNOWN_MSG *) netdata; + message_id = + HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID); + + switch (message_id) { + default: + /* handle HTC control message */ + if (target->CtrlResponseProcessing) { + /* this is a fatal error, target should not be sending unsolicited messages + * on the endpoint 0 */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx Ctrl still processing\n")); + status = CDF_STATUS_E_FAILURE; + break; + } + + LOCK_HTC_RX(target); + target->CtrlResponseLength = + min((int)netlen, + HTC_MAX_CONTROL_MESSAGE_LENGTH); + A_MEMCPY(target->CtrlResponseBuffer, netdata, + target->CtrlResponseLength); + UNLOCK_HTC_RX(target); + + cdf_semaphore_release(target->osdev, + &target-> + CtrlResponseValid); + break; + case HTC_MSG_SEND_SUSPEND_COMPLETE: + wow_nack = 0; + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_SUSPEND_ACK, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH( + &pEndpoint->TxQueue)); + UNLOCK_HTC_CREDIT(target); + target->HTCInitInfo. + TargetSendSuspendComplete((void *) + &wow_nack); + break; + case HTC_MSG_NACK_SUSPEND: + wow_nack = 1; + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_SUSPEND_ACK, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH( + &pEndpoint->TxQueue)); + UNLOCK_HTC_CREDIT(target); + + target->HTCInitInfo. + TargetSendSuspendComplete((void *) + &wow_nack); + break; + } + + cdf_nbuf_free(netbuf); + netbuf = NULL; + break; + } + + /* the current message based HIF architecture allocates net bufs for recv packets + * since this layer bridges that HIF to upper layers , which expects HTC packets, + * we form the packets here + * TODO_FIXME */ + pPacket = allocate_htc_packet_container(target); + if (NULL == pPacket) { + status = CDF_STATUS_E_RESOURCES; + break; + } + pPacket->Status = CDF_STATUS_SUCCESS; + pPacket->Endpoint = htc_ep_id; + pPacket->pPktContext = netbuf; + pPacket->pBuffer = cdf_nbuf_data(netbuf) + HTC_HDR_LENGTH; + pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; + + cdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN); + cdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength); + + recv_packet_completion(target, pEndpoint, pPacket); + /* recover the packet container */ + free_htc_packet_container(target, pPacket); + netbuf = NULL; + + } while (false); + +#ifdef RX_SG_SUPPORT +_out: +#endif + + if (netbuf != NULL) { + cdf_nbuf_free(netbuf); + } + + return status; + +} + +A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pFirstPacket; + A_STATUS status = A_OK; + HTC_PACKET *pPacket; + + pFirstPacket = htc_get_pkt_at_head(pPktQueue); + + if (NULL == pFirstPacket) { + A_ASSERT(false); + return A_EINVAL; + } + + AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX); + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n", + pFirstPacket->Endpoint, + HTC_PACKET_QUEUE_DEPTH(pPktQueue), + pFirstPacket->BufferLength)); + + pEndpoint = &target->EndPoint[pFirstPacket->Endpoint]; + + LOCK_HTC_RX(target); + + do { + + if (HTC_STOPPING(target)) { + status = A_ERROR; + break; + } + + /* store receive packets */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue, + pPktQueue); + + } while (false); + + UNLOCK_HTC_RX(target); + + if (A_FAILED(status)) { + /* walk through queue and mark each one canceled */ + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + pPacket->Status = A_ECANCELED; + } + HTC_PACKET_QUEUE_ITERATE_END; + + do_recv_completion(pEndpoint, pPktQueue); + } + + return status; +} + +A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE queue; + INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket); + return htc_add_receive_pkt_multiple(HTCHandle, &queue); +} + +void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) +{ + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE container; + + LOCK_HTC_RX(target); + + while (1) { + pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue); + if (NULL == pPacket) { + break; + } + UNLOCK_HTC_RX(target); + pPacket->Status = A_ECANCELED; + pPacket->ActualLength = 0; + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + (" Flushing RX packet:%p, length:%d, ep:%d \n", + pPacket, pPacket->BufferLength, + pPacket->Endpoint)); + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + /* give the packet back */ + do_recv_completion(pEndpoint, &container); + LOCK_HTC_RX(target); + } + + UNLOCK_HTC_RX(target); +} + +void htc_recv_init(HTC_TARGET *target) +{ + /* Initialize CtrlResponseValid to block */ + cdf_semaphore_init(&target->CtrlResponseValid); + cdf_semaphore_acquire(target->osdev, &target->CtrlResponseValid); +} + +/* polling routine to wait for a control packet to be received */ +A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target) +{ +/* int count = HTC_TARGET_MAX_RESPONSE_POLL; */ + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n")); + + /* Wait for BMI request/response transaction to complete */ + while (cdf_semaphore_acquire(target->osdev, &target->CtrlResponseValid)) { + } + + LOCK_HTC_RX(target); + /* caller will clear this flag */ + target->CtrlResponseProcessing = true; + + UNLOCK_HTC_RX(target); + +#if 0 + while (count > 0) { + + LOCK_HTC_RX(target); + + if (target->CtrlResponseValid) { + target->CtrlResponseValid = false; + /* caller will clear this flag */ + target->CtrlResponseProcessing = true; + UNLOCK_HTC_RX(target); + break; + } + + UNLOCK_HTC_RX(target); + + count--; + A_MSLEEP(HTC_TARGET_RESPONSE_POLL_MS); + } + + if (count <= 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("-HTCWaitCtrlMessageRecv: Timeout!\n")); + return A_ECOMM; + } +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n")); + return A_OK; +} + +static A_STATUS htc_process_trailer(HTC_TARGET *target, + A_UINT8 *pBuffer, + int Length, HTC_ENDPOINT_ID FromEndpoint) +{ + HTC_RECORD_HDR *pRecord; + A_UINT8 htc_rec_id; + A_UINT8 htc_rec_len; + A_UINT8 *pRecordBuf; + A_UINT8 *pOrigBuffer; + int origLength; + A_STATUS status; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+htc_process_trailer (length:%d) \n", Length)); + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { + AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer"); + } + + pOrigBuffer = pBuffer; + origLength = Length; + status = A_OK; + + while (Length > 0) { + + if (Length < sizeof(HTC_RECORD_HDR)) { + status = A_EPROTO; + break; + } + /* these are byte aligned structs */ + pRecord = (HTC_RECORD_HDR *) pBuffer; + Length -= sizeof(HTC_RECORD_HDR); + pBuffer += sizeof(HTC_RECORD_HDR); + + htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH); + htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID); + + if (htc_rec_len > Length) { + /* no room left in buffer for record */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" invalid record length: %d (id:%d) buffer has: %d bytes left \n", + htc_rec_len, htc_rec_id, Length)); + status = A_EPROTO; + break; + } + /* start of record follows the header */ + pRecordBuf = pBuffer; + + switch (htc_rec_id) { + case HTC_RECORD_CREDITS: + AR_DEBUG_ASSERT(htc_rec_len >= + sizeof(HTC_CREDIT_REPORT)); + htc_process_credit_rpt(target, + (HTC_CREDIT_REPORT *) pRecordBuf, + htc_rec_len / + (sizeof(HTC_CREDIT_REPORT)), + FromEndpoint); + break; + +#ifdef HIF_SDIO + case HTC_RECORD_LOOKAHEAD: + /* Process in HIF layer */ + break; + + case HTC_RECORD_LOOKAHEAD_BUNDLE: + /* Process in HIF layer */ + break; +#endif /* HIF_SDIO */ + + default: + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" HTC unhandled record: id:%d length:%d \n", + htc_rec_id, htc_rec_len)); + break; + } + + if (A_FAILED(status)) { + break; + } + + /* advance buffer past this record for next time around */ + pBuffer += htc_rec_len; + Length -= htc_rec_len; + } + + if (A_FAILED(status)) { + debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer"); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer \n")); + return status; + +} diff --git a/core/htc/htc_send.c b/core/htc/htc_send.c new file mode 100644 index 0000000000..e011538de1 --- /dev/null +++ b/core/htc/htc_send.c @@ -0,0 +1,1850 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include /* cdf_nbuf_t */ +#include /* cdf_mem_malloc */ +#include +#include "epping_main.h" + +/* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */ +/* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */ +#define DATA_EP_SIZE 4 +/* #endif */ +#define HTC_DATA_RESOURCE_THRS 256 +#define HTC_DATA_MINDESC_PERPACKET 2 + +typedef enum _HTC_SEND_QUEUE_RESULT { + HTC_SEND_QUEUE_OK = 0, /* packet was queued */ + HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */ +} HTC_SEND_QUEUE_RESULT; + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if DEBUG_CREDIT +/* bit mask to enable debug certain endpoint */ +static unsigned ep_debug_mask = + (1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2); +#endif + +/* HTC Control Path Credit History */ +A_UINT32 g_htc_credit_history_idx = 0; +HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX]; + +/** + * htc_credit_record() - records tx que state & credit transactions + * @type: type of echange can be HTC_REQUEST_CREDIT + * or HTC_PROCESS_CREDIT_REPORT + * @tx_credits: current number of tx_credits + * @htc_tx_queue_depth: current hct tx queue depth + * + * This function records the credits and pending commands whenever a command is + * sent or credits are returned. Call this after the credits have been updated + * according to the transaction. Call this before dequeing commands. + * + * Consider making this function accept an HTC_ENDPOINT and find the current + * credits and queue depth itself. + * + * Consider moving the LOCK_HTC_CREDIT(target); logic into this function as well. + */ +void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit, + uint32_t htc_tx_queue_depth) { + if (HTC_CREDIT_HISTORY_MAX <= g_htc_credit_history_idx) + g_htc_credit_history_idx = 0; + + htc_credit_history_buffer[g_htc_credit_history_idx].type = type; + htc_credit_history_buffer[g_htc_credit_history_idx].time = + cdf_get_log_timestamp(); + htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit = + tx_credit; + htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth = + htc_tx_queue_depth; + g_htc_credit_history_idx++; + +#ifdef QCA_WIFI_3_0_EMU + if (type == HTC_REQUEST_CREDIT) + printk("\nrequest_credits-> current_credit %d, pending commands %d\n", + tx_credit, htc_tx_queue_depth); + + else if (type == HTC_PROCESS_CREDIT_REPORT) + printk("\ncredit_report<- current_credit %d, pending commands %d\n", + tx_credit, htc_tx_queue_depth); +#endif +} + +void htc_dump_counter_info(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n", + __func__, target->ce_send_cnt, target->TX_comp_cnt)); +} + +void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credits) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + int i; + + if (!credits || !target) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__)); + return; + } + + *credits = 0; + LOCK_HTC_TX(target); + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + if (pEndpoint->ServiceID == WMI_CONTROL_SVC) { + *credits = pEndpoint->TxCredits; + break; + } + } + UNLOCK_HTC_TX(target); +} + +static INLINE void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) { + cdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + cdf_nbuf_unmap(target->osdev, netbuf, CDF_DMA_TO_DEVICE); + cdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR)); + pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF; + } + +} + +static void do_send_completion(HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueueToIndicate) +{ + do { + + if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { + /* nothing to indicate */ + break; + } + + if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" HTC calling ep %d, send complete multiple callback (%d pkts) \n", + pEndpoint->Id, + HTC_PACKET_QUEUE_DEPTH + (pQueueToIndicate))); + /* a multiple send complete handler is being used, pass the queue to the handler */ + pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint-> + EpCallBacks. + pContext, + pQueueToIndicate); + /* all packets are now owned by the callback, reset queue to be safe */ + INIT_HTC_PACKET_QUEUE(pQueueToIndicate); + } else { + HTC_PACKET *pPacket; + /* using legacy EpTxComplete */ + do { + pPacket = htc_packet_dequeue(pQueueToIndicate); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" HTC calling ep %d send complete callback on packet %p \n", + pEndpoint->Id, pPacket)); + pEndpoint->EpCallBacks.EpTxComplete(pEndpoint-> + EpCallBacks. + pContext, + pPacket); + } while (!HTC_QUEUE_EMPTY(pQueueToIndicate)); + } + + } while (false); + +} + +static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + HTC_ENDPOINT *pEndpoint = &target->EndPoint[pPacket->Endpoint]; + HTC_PACKET_QUEUE container; + + restore_tx_packet(target, pPacket); + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + + /* do completion */ + do_send_completion(pEndpoint, &container); +} + +void htc_send_complete_check_cleanup(void *context) +{ + HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context; + htc_send_complete_check(pEndpoint, 1); +} + +HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE *pQueueSave; + cdf_nbuf_t netbuf; + LOCK_HTC_TX(target); + if (NULL == target->pBundleFreeList) { + UNLOCK_HTC_TX(target); + netbuf = cdf_nbuf_alloc(NULL, + target->MaxMsgsPerHTCBundle * + target->TargetCreditSize, 0, 4, false); + AR_DEBUG_ASSERT(netbuf); + if (!netbuf) { + return NULL; + } + pPacket = cdf_mem_malloc(sizeof(HTC_PACKET)); + AR_DEBUG_ASSERT(pPacket); + if (!pPacket) { + cdf_nbuf_free(netbuf); + return NULL; + } + pQueueSave = cdf_mem_malloc(sizeof(HTC_PACKET_QUEUE)); + AR_DEBUG_ASSERT(pQueueSave); + if (!pQueueSave) { + cdf_nbuf_free(netbuf); + cdf_mem_free(pPacket); + return NULL; + } + INIT_HTC_PACKET_QUEUE(pQueueSave); + pPacket->pContext = pQueueSave; + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); + pPacket->pBuffer = cdf_nbuf_data(netbuf); + pPacket->BufferLength = cdf_nbuf_len(netbuf); + + /* store the original head room so that we can restore this when we "free" the packet */ + /* free packet puts the packet back on the free list */ + pPacket->netbufOrigHeadRoom = cdf_nbuf_headroom(netbuf); + return pPacket; + } + /* already done malloc - restore from free list */ + pPacket = target->pBundleFreeList; + AR_DEBUG_ASSERT(pPacket); + if (!pPacket) { + UNLOCK_HTC_TX(target); + return NULL; + } + target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext; + UNLOCK_HTC_TX(target); + pPacket->ListLink.pNext = NULL; + + return pPacket; +} + +void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + A_UINT32 curentHeadRoom; + cdf_nbuf_t netbuf; + HTC_PACKET_QUEUE *pQueueSave; + + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + if (!netbuf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("\n%s: Invalid netbuf in HTC " + "Packet\n", __func__)); + return; + } + /* HIF adds data to the headroom section of the nbuf, restore the original */ + /* size. If this is not done, headroom keeps shrinking with every HIF send */ + /* and eventually HIF ends up doing another malloc big enough to store the */ + /* data + its header */ + + curentHeadRoom = cdf_nbuf_headroom(netbuf); + cdf_nbuf_pull_head(netbuf, + pPacket->netbufOrigHeadRoom - curentHeadRoom); + cdf_nbuf_trim_tail(netbuf, cdf_nbuf_len(netbuf)); + + /* restore the pBuffer pointer. HIF changes this */ + pPacket->pBuffer = cdf_nbuf_data(netbuf); + pPacket->BufferLength = cdf_nbuf_len(netbuf); + + /* restore queue */ + pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext; + AR_DEBUG_ASSERT(pQueueSave); + + INIT_HTC_PACKET_QUEUE(pQueueSave); + + LOCK_HTC_TX(target); + if (target->pBundleFreeList == NULL) { + target->pBundleFreeList = pPacket; + pPacket->ListLink.pNext = NULL; + } else { + pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList; + target->pBundleFreeList = pPacket; + } + UNLOCK_HTC_TX(target); +} + +#if defined(HIF_USB) || defined(HIF_SDIO) +#ifdef ENABLE_BUNDLE_TX +static A_STATUS htc_send_bundled_netbuf(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + unsigned char *pBundleBuffer, + HTC_PACKET *pPacketTx) +{ + cdf_size_t data_len; + A_STATUS status; + cdf_nbuf_t bundleBuf; + uint32_t data_attr = 0; + + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + data_len = pBundleBuffer - cdf_nbuf_data(bundleBuf); + cdf_nbuf_put_tail(bundleBuf, data_len); + SET_HTC_PACKET_INFO_TX(pPacketTx, + target, + pBundleBuffer, + data_len, + pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED); + LOCK_HTC_TX(target); + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx); + UNLOCK_HTC_TX(target); +#if DEBUG_BUNDLE + cdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + data_len, data_len / pEndpoint->TxCreditSize); +#endif + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, data_len, bundleBuf, data_attr); + if (status != A_OK) { + cdf_print("%s:hif_send_head failed(len=%d).\n", __FUNCTION__, + data_len); + } + return status; +} + +static void htc_issue_packets_bundle(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pPktQueue) +{ + int i, frag_count, nbytes; + cdf_nbuf_t netbuf, bundleBuf; + unsigned char *pBundleBuffer = NULL; + HTC_PACKET *pPacket = NULL, *pPacketTx = NULL; + HTC_FRAME_HDR *pHtcHdr; + int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining = + 0; + HTC_PACKET_QUEUE *pQueueSave = NULL; + + bundlesSpaceRemaining = + target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize; + pPacketTx = allocate_htc_bundle_packet(target); + if (!pPacketTx) { + /* good time to panic */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("allocate_htc_bundle_packet failed \n")); + AR_DEBUG_ASSERT(false); + return; + } + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + pBundleBuffer = cdf_nbuf_data(bundleBuf); + pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; + while (1) { + pPacket = htc_packet_dequeue(pPktQueue); + if (pPacket == NULL) { + break; + } + creditPad = 0; + transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; + creditRemainder = transferLength % pEndpoint->TxCreditSize; + if (creditRemainder != 0) { + if (transferLength < pEndpoint->TxCreditSize) { + creditPad = + pEndpoint->TxCreditSize - transferLength; + } else { + creditPad = creditRemainder; + } + transferLength += creditPad; + } + + if (bundlesSpaceRemaining < transferLength) { + /* send out previous buffer */ + htc_send_bundled_netbuf(target, pEndpoint, pBundleBuffer, + pPacketTx); + if (HTC_PACKET_QUEUE_DEPTH(pPktQueue) < + HTC_MIN_MSG_PER_BUNDLE) { + return; + } + bundlesSpaceRemaining = + target->MaxMsgsPerHTCBundle * + pEndpoint->TxCreditSize; + pPacketTx = allocate_htc_bundle_packet(target); + if (!pPacketTx) { + /* good time to panic */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("allocate_htc_bundle_packet failed \n")); + AR_DEBUG_ASSERT(false); + return; + } + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + pBundleBuffer = cdf_nbuf_data(bundleBuf); + pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; + } + + bundlesSpaceRemaining -= transferLength; + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + pHtcHdr = (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, 0); + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->PktInfo. + AsTx. + SendFlags | + HTC_FLAGS_SEND_BUNDLE, + HTC_FRAME_HDR_FLAGS) + | SM(pPacket->Endpoint, HTC_FRAME_HDR_ENDPOINTID)); + HTC_WRITE32((A_UINT32 *) pHtcHdr + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad, + HTC_FRAME_HDR_RESERVED)); + pHtcHdr->reserved = creditPad; + frag_count = cdf_nbuf_get_num_frags(netbuf); + nbytes = pPacket->ActualLength + HTC_HDR_LENGTH; + for (i = 0; i < frag_count && nbytes > 0; i++) { + int frag_len = cdf_nbuf_get_frag_len(netbuf, i); + unsigned char *frag_addr = + cdf_nbuf_get_frag_vaddr(netbuf, i); + if (frag_len > nbytes) { + frag_len = nbytes; + } + A_MEMCPY(pBundleBuffer, frag_addr, frag_len); + nbytes -= frag_len; + pBundleBuffer += frag_len; + } + HTC_PACKET_ENQUEUE(pQueueSave, pPacket); + pBundleBuffer += creditPad; + } + if (pBundleBuffer != cdf_nbuf_data(bundleBuf)) { + /* send out remaining buffer */ + htc_send_bundled_netbuf(target, pEndpoint, pBundleBuffer, + pPacketTx); + } else { + free_htc_bundle_packet(target, pPacketTx); + } +} +#endif /* ENABLE_BUNDLE_TX */ +#endif + +static A_STATUS htc_issue_packets(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pPktQueue) +{ + A_STATUS status = A_OK; + cdf_nbuf_t netbuf; + HTC_PACKET *pPacket = NULL; + uint16_t payloadLen; + HTC_FRAME_HDR *pHtcHdr; + uint32_t data_attr = 0; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_issue_packets: Queue: %p, Pkts %d \n", pPktQueue, + HTC_PACKET_QUEUE_DEPTH(pPktQueue))); + while (true) { +#if defined(HIF_USB) || defined(HIF_SDIO) +#ifdef ENABLE_BUNDLE_TX + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint) && + HTC_ENABLE_BUNDLE(target) && + HTC_PACKET_QUEUE_DEPTH(pPktQueue) >= + HTC_MIN_MSG_PER_BUNDLE) { + htc_issue_packets_bundle(target, pEndpoint, pPktQueue); + } +#endif +#endif + /* if not bundling or there was a packet that could not be placed in a bundle, + * and send it by normal way + */ + pPacket = htc_packet_dequeue(pPktQueue); + if (NULL == pPacket) { + /* local queue is fully drained */ + break; + } + + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + /* Non-credit enabled endpoints have been mapped and setup by now, + * so no need to revisit the HTC headers + */ + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + + payloadLen = pPacket->ActualLength; + /* setup HTC frame header */ + + pHtcHdr = + (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, + 0); + AR_DEBUG_ASSERT(pHtcHdr); + + HTC_WRITE32(pHtcHdr, + SM(payloadLen, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket-> + PktInfo. + AsTx. + SendFlags, + HTC_FRAME_HDR_FLAGS) + | SM(pPacket->Endpoint, + HTC_FRAME_HDR_ENDPOINTID)); + HTC_WRITE32(((A_UINT32 *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + /* + * Now that the HTC frame header has been added, the netbuf can be + * mapped. This only applies to non-data frames, since data frames + * were already mapped as they entered into the driver. + * Check the "FIXUP_NETBUF" flag to see whether this is a data netbuf + * that is already mapped, or a non-data netbuf that needs to be + * mapped. + */ + if (pPacket->PktInfo.AsTx. + Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) { + cdf_nbuf_map(target->osdev, + GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket), CDF_DMA_TO_DEVICE); + } + } + LOCK_HTC_TX(target); + /* store in look up queue to match completions */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); + INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); + pEndpoint->ul_outstanding_cnt++; + UNLOCK_HTC_TX(target); + + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, pEndpoint->Id, + HTC_HDR_LENGTH + pPacket->ActualLength, + netbuf, data_attr); +#if DEBUG_BUNDLE + cdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + HTC_HDR_LENGTH + pPacket->ActualLength); +#endif + + target->ce_send_cnt++; + + if (cdf_unlikely(A_FAILED(status))) { + if (status != A_NO_RESOURCE) { + /* TODO : if more than 1 endpoint maps to the same PipeID it is possible + * to run out of resources in the HIF layer. Don't emit the error */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("hif_send Failed status:%d \n", + status)); + } + LOCK_HTC_TX(target); + target->ce_send_cnt--; + pEndpoint->ul_outstanding_cnt--; + HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); + /* reclaim credits */ +#if defined(HIF_USB) + if (pEndpoint->Id >= ENDPOINT_2 + && pEndpoint->Id <= ENDPOINT_5) + target->avail_tx_credits += + pPacket->PktInfo.AsTx.CreditsUsed; + else + pEndpoint->TxCredits += + pPacket->PktInfo.AsTx.CreditsUsed; +#else + pEndpoint->TxCredits += + pPacket->PktInfo.AsTx.CreditsUsed; +#endif + /* put it back into the callers queue */ + HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); + UNLOCK_HTC_TX(target); + break; + } + + } + if (cdf_unlikely(A_FAILED(status))) { +#if defined(HIF_USB) + if (pEndpoint->Id >= ENDPOINT_2 && pEndpoint->Id <= ENDPOINT_5) + target->avail_tx_credits += + pPacket->PktInfo.AsTx.CreditsUsed; + else + pEndpoint->TxCredits += + pPacket->PktInfo.AsTx.CreditsUsed; +#endif + while (!HTC_QUEUE_EMPTY(pPktQueue)) { + if (status != A_NO_RESOURCE) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("htc_issue_packets, failed pkt:0x%p status:%d \n", + pPacket, status)); + } + pPacket = htc_packet_dequeue(pPktQueue); + if (pPacket) { + pPacket->Status = status; + send_packet_completion(target, pPacket); + } + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets \n")); + + return status; +} + +/* get HTC send packets from the TX queue on an endpoint, based on available credits */ +void get_htc_send_packets_credit_based(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueue) +{ + int creditsRequired; + int remainder; + A_UINT8 sendFlags; + HTC_PACKET *pPacket; + unsigned int transferLength; + + /****** NOTE : the TX lock is held when this function is called *****************/ + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+get_htc_send_packets_credit_based \n")); + + /* loop until we can grab as many packets out of the queue as we can */ + while (true) { + + sendFlags = 0; + /* get packet at head, but don't remove it */ + pPacket = htc_get_pkt_at_head(&pEndpoint->TxQueue); + if (pPacket == NULL) { + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Got head packet:%p , Queue Depth: %d\n", + pPacket, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); + + transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; + + if (transferLength <= pEndpoint->TxCreditSize) { + creditsRequired = 1; + } else { + /* figure out how many credits this message requires */ + creditsRequired = + transferLength / pEndpoint->TxCreditSize; + remainder = transferLength % pEndpoint->TxCreditSize; + + if (remainder) { + creditsRequired++; + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Credits Required:%d Got:%d\n", + creditsRequired, pEndpoint->TxCredits)); + + if (pEndpoint->Id == ENDPOINT_0) { + /* endpoint 0 is special, it always has a credit and does not require credit based + * flow control */ + creditsRequired = 0; +#if defined(HIF_USB) + } else if (pEndpoint->Id >= ENDPOINT_2 + && pEndpoint->Id <= ENDPOINT_5) { + if (target->avail_tx_credits < creditsRequired) + break; + + target->avail_tx_credits -= creditsRequired; + + if (target->avail_tx_credits < 9) { + /* tell the target we need credits ASAP! */ + sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + INC_HTC_EP_STAT(pEndpoint, + TxCreditLowIndications, 1); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Host Needs Credits \n")); + } +#endif + } else { + + if (pEndpoint->TxCredits < creditsRequired) { +#if DEBUG_CREDIT + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" EP%d, No Credit now. %d < %d\n", + pEndpoint->Id, + pEndpoint->TxCredits, + creditsRequired)); +#endif + break; + } + + pEndpoint->TxCredits -= creditsRequired; + INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, + creditsRequired); + + /* check if we need credits back from the target */ + if (pEndpoint->TxCredits <= + pEndpoint->TxCreditsPerMaxMsg) { + /* tell the target we need credits ASAP! */ + sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + + if (pEndpoint->ServiceID == WMI_CONTROL_SVC) { + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_REQUEST_CREDIT, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH + (&pEndpoint-> + TxQueue)); + UNLOCK_HTC_CREDIT(target); + } + + INC_HTC_EP_STAT(pEndpoint, + TxCreditLowIndications, 1); +#if DEBUG_CREDIT + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" EP%d Needs Credits\n", + pEndpoint->Id)); +#endif + } + } + + /* now we can fully dequeue */ + pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); + if (pPacket) { + /* save the number of credits this packet consumed */ + pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; + /* save send flags */ + pPacket->PktInfo.AsTx.SendFlags = sendFlags; + + /* queue this packet into the caller's queue */ + HTC_PACKET_ENQUEUE(pQueue, pPacket); + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets_credit_based \n")); + +} + +void get_htc_send_packets(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueue, int Resources) +{ + + HTC_PACKET *pPacket; + + /****** NOTE : the TX lock is held when this function is called *****************/ + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+get_htc_send_packets %d resources\n", Resources)); + + /* loop until we can grab as many packets out of the queue as we can */ + while (Resources > 0) { + int num_frags; + + pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); + if (pPacket == NULL) { + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Got packet:%p , New Queue Depth: %d\n", + pPacket, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); + /* For non-credit path the sequence number is already embedded + * in the constructed HTC header + */ +#if 0 + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; +#endif + pPacket->PktInfo.AsTx.SendFlags = 0; + pPacket->PktInfo.AsTx.CreditsUsed = 0; + /* queue this packet into the caller's queue */ + HTC_PACKET_ENQUEUE(pQueue, pPacket); + + /* + * FIX THIS: + * For now, avoid calling cdf_nbuf_get_num_frags before calling + * cdf_nbuf_map, because the MacOS version of cdf_nbuf_t doesn't + * support cdf_nbuf_get_num_frags until after cdf_nbuf_map has + * been done. + * Assume that the non-data netbufs, i.e. the WMI message netbufs, + * consist of a single fragment. + */ + num_frags = + (pPacket->PktInfo.AsTx. + Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 + /* WMI messages are in a single-fragment network buffer */ : + cdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket)); + Resources -= num_frags; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets \n")); + +} + +static HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pCallersSendQueue) +{ + HTC_PACKET_QUEUE sendQueue; /* temp queue to hold packets at various stages */ + HTC_PACKET *pPacket; + int tx_resources; + int overflow; + HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%p Depth:%d)\n", + pCallersSendQueue, + (pCallersSendQueue == + NULL) ? 0 : + HTC_PACKET_QUEUE_DEPTH + (pCallersSendQueue))); + + /* init the local send queue */ + INIT_HTC_PACKET_QUEUE(&sendQueue); + + do { + + if (NULL == pCallersSendQueue) { + /* caller didn't provide a queue, just wants us to check queues and send */ + break; + } + + if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { + /* empty queue */ + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, + HTC_PKT_Q_EMPTY); + result = HTC_SEND_QUEUE_DROP; + break; + } + + if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= + pEndpoint->MaxTxQueueDepth) { + /* we've already overflowed */ + overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); + } else { + /* figure out how much we will overflow by */ + overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); + overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); + /* figure out how much we will overflow the TX queue by */ + overflow -= pEndpoint->MaxTxQueueDepth; + } + + /* if overflow is negative or zero, we are okay */ + if (overflow > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n", + pEndpoint->Id, overflow, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> + TxQueue), + pEndpoint->MaxTxQueueDepth)); + } + if ((overflow <= 0) + || (pEndpoint->EpCallBacks.EpSendFull == NULL)) { + /* all packets will fit or caller did not provide send full indication handler + * -- just move all of them to the local sendQueue object */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, + pCallersSendQueue); + } else { + int i; + int goodPkts = + HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - + overflow; + + A_ASSERT(goodPkts >= 0); + /* we have overflowed, and a callback is provided */ + /* dequeue all non-overflow packets into the sendqueue */ + for (i = 0; i < goodPkts; i++) { + /* pop off caller's queue */ + pPacket = htc_packet_dequeue(pCallersSendQueue); + A_ASSERT(pPacket != NULL); + /* insert into local queue */ + HTC_PACKET_ENQUEUE(&sendQueue, pPacket); + } + + /* the caller's queue has all the packets that won't fit */ + /* walk through the caller's queue and indicate each one to the send full handler */ + ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue-> + QueueHead, pPacket, + HTC_PACKET, ListLink) { + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Indicating overflowed TX packet: %p \n", + pPacket)); + /* + * Remove headroom reserved for HTC_FRAME_HDR before giving + * the packet back to the user via the EpSendFull callback. + */ + restore_tx_packet(target, pPacket); + + if (pEndpoint->EpCallBacks. + EpSendFull(pEndpoint->EpCallBacks.pContext, + pPacket) == HTC_SEND_FULL_DROP) { + /* callback wants the packet dropped */ + INC_HTC_EP_STAT(pEndpoint, TxDropped, + 1); + /* leave this one in the caller's queue for cleanup */ + } else { + /* callback wants to keep this packet, remove from caller's queue */ + HTC_PACKET_REMOVE(pCallersSendQueue, + pPacket); + /* put it in the send queue */ + /* add HTC_FRAME_HDR space reservation again */ + cdf_nbuf_push_head + (GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket), sizeof(HTC_FRAME_HDR)); + + HTC_PACKET_ENQUEUE(&sendQueue, pPacket); + } + + } + ITERATE_END; + + if (HTC_QUEUE_EMPTY(&sendQueue)) { + /* no packets made it in, caller will cleanup */ + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, + HTC_SEND_Q_EMPTY); + result = HTC_SEND_QUEUE_DROP; + break; + } + } + + } while (false); + + if (result != HTC_SEND_QUEUE_OK) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: \n")); + return result; + } + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } else { + tx_resources = 0; + } + + LOCK_HTC_TX(target); + + if (!HTC_QUEUE_EMPTY(&sendQueue)) { + /* transfer packets to tail */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue, + &sendQueue); + A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); + INIT_HTC_PACKET_QUEUE(&sendQueue); + } + + /* increment tx processing count on entry */ + cdf_atomic_inc(&pEndpoint->TxProcessCount); + if (cdf_atomic_read(&pEndpoint->TxProcessCount) > 1) { + /* another thread or task is draining the TX queues on this endpoint + * that thread will reset the tx processing count when the queue is drained */ + cdf_atomic_dec(&pEndpoint->TxProcessCount); + UNLOCK_HTC_TX(target); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy) \n")); + return HTC_SEND_QUEUE_OK; + } + + /***** beyond this point only 1 thread may enter ******/ + + /* now drain the endpoint TX queue for transmission as long as we have enough + * transmit resources */ + while (true) { + + if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) { + break; + } + + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { +#if DEBUG_CREDIT + int cred = pEndpoint->TxCredits; +#endif + /* credit based mechanism provides flow control based on target transmit resource availability, we + * assume that the HIF layer will always have bus resources greater than target transmit resources */ + get_htc_send_packets_credit_based(target, pEndpoint, + &sendQueue); +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + if (cred - pEndpoint->TxCredits > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Decrease EP%d %d - %d = %d credits.\n", + pEndpoint->Id, cred, + cred - + pEndpoint->TxCredits, + pEndpoint->TxCredits)); + } + } +#endif + } else { + /* get all the packets for this endpoint that we can for this pass */ + get_htc_send_packets(target, pEndpoint, &sendQueue, + tx_resources); + } + + if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { + /* didn't get any packets due to a lack of resources or TX queue was drained */ + break; + } + + UNLOCK_HTC_TX(target); + + /* send what we can */ + htc_issue_packets(target, pEndpoint, &sendQueue); + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } + + LOCK_HTC_TX(target); + + } + + UNLOCK_HTC_TX(target); + /* done with this endpoint, we can clear the count */ + cdf_atomic_init(&pEndpoint->TxProcessCount); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: \n")); + + return HTC_SEND_QUEUE_OK; +} + +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED +static A_UINT16 htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID id) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_ENDPOINT_ID eid; + HTC_PACKET_QUEUE *pTxQueue; + A_UINT16 resources; + A_UINT16 acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 }; + + if (id < ENDPOINT_2 || id > ENDPOINT_5) { + return 1; + } + + for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) { + pEndpoint = &target->EndPoint[eid]; + pTxQueue = &pEndpoint->TxQueue; + + if (HTC_QUEUE_EMPTY(pTxQueue)) { + acQueueStatus[eid - 2] = 1; + } + } + + switch (id) { + case ENDPOINT_2: /* BE */ + return (acQueueStatus[0] && acQueueStatus[2] + && acQueueStatus[3]); + case ENDPOINT_3: /* BK */ + return (acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2] + && acQueueStatus[3]); + case ENDPOINT_4: /* VI */ + return (acQueueStatus[2] && acQueueStatus[3]); + case ENDPOINT_5: /* VO */ + return (acQueueStatus[3]); + default: + return 0; + } + +} + +static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target, + HTC_PACKET_QUEUE *pPktQueue, + HTC_ENDPOINT_ID eid) +{ + HTC_ENDPOINT *pEndpoint; + HTC_PACKET_QUEUE *pTxQueue; + HTC_PACKET *pPacket; + int goodPkts; + + pEndpoint = &target->EndPoint[eid]; + pTxQueue = &pEndpoint->TxQueue; + + LOCK_HTC_TX(target); + + goodPkts = + pEndpoint->MaxTxQueueDepth - + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); + + if (goodPkts > 0) { + while (!HTC_QUEUE_EMPTY(pPktQueue)) { + pPacket = htc_packet_dequeue(pPktQueue); + HTC_PACKET_ENQUEUE(pTxQueue, pPacket); + goodPkts--; + + if (goodPkts <= 0) { + break; + } + } + } + + if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) { + ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket, + HTC_PACKET, ListLink) { + + if (pEndpoint->EpCallBacks. + EpSendFull(pEndpoint->EpCallBacks.pContext, + pPacket) == HTC_SEND_FULL_DROP) { + INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); + } else { + HTC_PACKET_REMOVE(pPktQueue, pPacket); + HTC_PACKET_ENQUEUE(pTxQueue, pPacket); + } + } + ITERATE_END; + } + + UNLOCK_HTC_TX(target); + + return A_OK; +} + +#endif + +A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; + cdf_nbuf_t netbuf; + HTC_FRAME_HDR *pHtcHdr; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_send_pkts_multiple: Queue: %p, Pkts %d \n", + pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue))); + + /* get packet at head to figure out which endpoint these packets will go into */ + pPacket = htc_get_pkt_at_head(pPktQueue); + if (NULL == pPacket) { + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n")); + return A_EINVAL; + } + + AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); + pEndpoint = &target->EndPoint[pPacket->Endpoint]; + + if (!pEndpoint->ServiceID) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s ServiceID is invalid\n", + __func__)); + return A_EINVAL; + } + +#ifdef HTC_EP_STAT_PROFILING + LOCK_HTC_TX(target); + INC_HTC_EP_STAT(pEndpoint, TxPosted, HTC_PACKET_QUEUE_DEPTH(pPktQueue)); + UNLOCK_HTC_TX(target); +#endif + + /* provide room in each packet's netbuf for the HTC frame header */ + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + + cdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); + /* setup HTC frame header */ + pHtcHdr = (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->Endpoint, + HTC_FRAME_HDR_ENDPOINTID)); + + LOCK_HTC_TX(target); + + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; + + HTC_WRITE32(((A_UINT32 *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + UNLOCK_HTC_TX(target); + /* + * Now that the HTC frame header has been added, the netbuf can be + * mapped. This only applies to non-data frames, since data frames + * were already mapped as they entered into the driver. + */ + cdf_nbuf_map(target->osdev, + GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), + CDF_DMA_TO_DEVICE); + + pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF; + } + HTC_PACKET_QUEUE_ITERATE_END; + +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED + if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) { + htc_send_pkts_sched_queue(HTCHandle, pPktQueue, pEndpoint->Id); + } else { + htc_try_send(target, pEndpoint, pPktQueue); + } +#else + htc_try_send(target, pEndpoint, pPktQueue); +#endif + + /* do completion on any packets that couldn't get in */ + if (!HTC_QUEUE_EMPTY(pPktQueue)) { + + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + /* remove the headroom reserved for HTC_FRAME_HDR */ + restore_tx_packet(target, pPacket); + + if (HTC_STOPPING(target)) { + pPacket->Status = A_ECANCELED; + } else { + pPacket->Status = A_NO_RESOURCE; + } + } + HTC_PACKET_QUEUE_ITERATE_END; + + do_send_completion(pEndpoint, pPktQueue); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n")); + + return A_OK; +} + +/* HTC API - htc_send_pkt */ +A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE queue; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+-htc_send_pkt: Enter endPointId: %d, buffer: %p, length: %d \n", + pPacket->Endpoint, pPacket->pBuffer, + pPacket->ActualLength)); + INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket); + return htc_send_pkts_multiple(HTCHandle, &queue); +} + +#ifdef ATH_11AC_TXCOMPACT + +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, cdf_nbuf_t netbuf, int Epid, + int ActualLength) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_FRAME_HDR *pHtcHdr; + A_STATUS status = A_OK; + int tx_resources; + uint32_t data_attr = 0; + + pEndpoint = &target->EndPoint[Epid]; + + tx_resources = + hif_get_free_queue_number(target->hif_dev, pEndpoint->UL_PipeID); + + if (tx_resources < HTC_DATA_RESOURCE_THRS) { + if (pEndpoint->ul_is_polled) { + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, 1); + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } + if (tx_resources < HTC_DATA_MINDESC_PERPACKET) { + return A_ERROR; + } + } + + pHtcHdr = (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + + data_attr = cdf_nbuf_data_attr_get(netbuf); + + HTC_WRITE32(pHtcHdr, SM(ActualLength, HTC_FRAME_HDR_PAYLOADLEN) | + SM(Epid, HTC_FRAME_HDR_ENDPOINTID)); + /* + * If the HIF pipe for the data endpoint is polled rather than + * interrupt-driven, this is a good point to check whether any + * data previously sent through the HIF pipe have finished being + * sent. + * Since this may result in callbacks to htc_tx_completion_handler, + * which can take the HTC tx lock, make the hif_send_complete_check + * call before acquiring the HTC tx lock. + * Call hif_send_complete_check directly, rather than calling + * htc_send_complete_check, and call the PollTimerStart separately + * after calling hif_send_head, so the timer will be started to + * check for completion of the new outstanding download (in the + * unexpected event that other polling calls don't catch it). + */ + + LOCK_HTC_TX(target); + + HTC_WRITE32(((A_UINT32 *) pHtcHdr) + 1, + SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1)); + + pEndpoint->SeqNo++; + + NBUF_UPDATE_TX_PKT_COUNT(netbuf, NBUF_TX_PKT_HTC); + DPTRACE(cdf_dp_trace(netbuf, CDF_DP_TRACE_HTC_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(netbuf)), + sizeof(cdf_nbuf_data(netbuf)))); + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, ActualLength, netbuf, data_attr); + + UNLOCK_HTC_TX(target); + return status; +} +#else /*ATH_11AC_TXCOMPACT */ + +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, + A_UINT8 more_data) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_FRAME_HDR *pHtcHdr; + HTC_PACKET_QUEUE sendQueue; + cdf_nbuf_t netbuf; + int tx_resources; + A_STATUS status = A_OK; + uint32_t data_attr = 0; + + if (pPacket) { + AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); + pEndpoint = &target->EndPoint[pPacket->Endpoint]; + + /* add HTC_FRAME_HDR in the initial fragment */ + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + pHtcHdr = (HTC_FRAME_HDR *) cdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->PktInfo. + AsTx.SendFlags, + HTC_FRAME_HDR_FLAGS) + | SM(pPacket->Endpoint, HTC_FRAME_HDR_ENDPOINTID)); + /* + * If the HIF pipe for the data endpoint is polled rather than + * interrupt-driven, this is a good point to check whether any + * data previously sent through the HIF pipe have finished being + * sent. + * Since this may result in callbacks to htc_tx_completion_handler, + * which can take the HTC tx lock, make the hif_send_complete_check + * call before acquiring the HTC tx lock. + * Call hif_send_complete_check directly, rather than calling + * htc_send_complete_check, and call the PollTimerStart separately + * after calling hif_send_head, so the timer will be started to + * check for completion of the new outstanding download (in the + * unexpected event that other polling calls don't catch it). + */ + if (pEndpoint->ul_is_polled) { + htc_send_complete_poll_timer_stop(pEndpoint); + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, 0); + } + + LOCK_HTC_TX(target); + + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; + + HTC_WRITE32(((A_UINT32 *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + /* append new packet to pEndpoint->TxQueue */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket); +#ifdef ENABLE_BUNDLE_TX + if (HTC_ENABLE_BUNDLE(target) && (more_data)) { + UNLOCK_HTC_TX(target); + return A_OK; + } +#endif + } else { + LOCK_HTC_TX(target); + pEndpoint = &target->EndPoint[1]; + } + + /* increment tx processing count on entry */ + cdf_atomic_inc(&pEndpoint->TxProcessCount); + if (cdf_atomic_read(&pEndpoint->TxProcessCount) > 1) { + /* + * Another thread or task is draining the TX queues on this endpoint. + * That thread will reset the tx processing count when the queue is + * drained. + */ + cdf_atomic_dec(&pEndpoint->TxProcessCount); + UNLOCK_HTC_TX(target); + return A_OK; + } + + /***** beyond this point only 1 thread may enter ******/ + + INIT_HTC_PACKET_QUEUE(&sendQueue); + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { +#if DEBUG_CREDIT + int cred = pEndpoint->TxCredits; +#endif + get_htc_send_packets_credit_based(target, pEndpoint, &sendQueue); +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + if (cred - pEndpoint->TxCredits > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Decrease EP%d %d - %d = %d credits.\n", + pEndpoint->Id, cred, + cred - pEndpoint->TxCredits, + pEndpoint->TxCredits)); + } + } +#endif + UNLOCK_HTC_TX(target); + } +#ifdef ENABLE_BUNDLE_TX + else if (HTC_ENABLE_BUNDLE(target)) { + /* Dequeue max packets from endpoint tx queue */ + get_htc_send_packets(target, pEndpoint, &sendQueue, + HTC_MAX_TX_BUNDLE_SEND_LIMIT); + UNLOCK_HTC_TX(target); + } +#endif + else { + /* + * Now drain the endpoint TX queue for transmission as long as we have + * enough transmit resources + */ + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + get_htc_send_packets(target, pEndpoint, &sendQueue, tx_resources); + UNLOCK_HTC_TX(target); + } + NBUF_UPDATE_TX_PKT_COUNT(netbuf, NBUF_TX_PKT_HTC); + DPTRACE(cdf_dp_trace(netbuf, CDF_DP_TRACE_HTC_PACKET_PTR_RECORD, + (uint8_t *)(cdf_nbuf_data(netbuf)), + sizeof(cdf_nbuf_data(netbuf)))); + + /* send what we can */ + while (true) { +#if defined(HIF_USB) || defined(HIF_SDIO) +#ifdef ENABLE_BUNDLE_TX + if (HTC_ENABLE_BUNDLE(target) && + HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= + HTC_MIN_MSG_PER_BUNDLE) { + htc_issue_packets_bundle(target, pEndpoint, &sendQueue); + } +#endif +#endif + pPacket = htc_packet_dequeue(&sendQueue); + if (pPacket == NULL) { + break; + } + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + + LOCK_HTC_TX(target); + /* store in look up queue to match completions */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); + INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); + pEndpoint->ul_outstanding_cnt++; + UNLOCK_HTC_TX(target); + + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, + HTC_HDR_LENGTH + pPacket->ActualLength, + netbuf, data_attr); +#if DEBUG_BUNDLE + cdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + HTC_HDR_LENGTH + pPacket->ActualLength); +#endif + + if (cdf_unlikely(A_FAILED(status))) { + LOCK_HTC_TX(target); + pEndpoint->ul_outstanding_cnt--; + /* remove this packet from the tx completion queue */ + HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); + + /* + * Don't bother reclaiming credits - HTC flow control + * is not applicable to tx data. + * In LL systems, there is no download flow control, + * since there's virtually no download delay. + * In HL systems, the txrx SW explicitly performs the + * tx flow control. + */ + /* pEndpoint->TxCredits += pPacket->PktInfo.AsTx.CreditsUsed; */ + + /* put this frame back at the front of the sendQueue */ + HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket); + + /* put the sendQueue back at the front of pEndpoint->TxQueue */ + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, + &sendQueue); + UNLOCK_HTC_TX(target); + break; /* still need to reset TxProcessCount */ + } + } + /* done with this endpoint, we can clear the count */ + cdf_atomic_init(&pEndpoint->TxProcessCount); + + if (pEndpoint->ul_is_polled) { + /* + * Start a cleanup timer to poll for download completion. + * The download completion should be noticed promptly from + * other polling calls, but the timer provides a safety net + * in case other polling calls don't occur as expected. + */ + htc_send_complete_poll_timer_start(pEndpoint); + } + + return status; +} +#endif /*ATH_11AC_TXCOMPACT */ + +/* + * In the adapted HIF layer, cdf_nbuf_t are passed between HIF and HTC, since upper layers expects + * HTC_PACKET containers we use the completed netbuf and lookup its corresponding HTC packet buffer + * from a lookup list. + * This is extra overhead that can be fixed by re-aligning HIF interfaces with HTC. + * + */ +static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + cdf_nbuf_t netbuf) +{ + HTC_PACKET *pPacket = NULL; + HTC_PACKET *pFoundPacket = NULL; + HTC_PACKET_QUEUE lookupQueue; + + INIT_HTC_PACKET_QUEUE(&lookupQueue); + LOCK_HTC_TX(target); + + /* mark that HIF has indicated the send complete for another packet */ + pEndpoint->ul_outstanding_cnt--; + + /* Dequeue first packet directly because of in-order completion */ + pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue); + if (cdf_unlikely(!pPacket)) { + UNLOCK_HTC_TX(target); + return NULL; + } + if (netbuf == (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { + UNLOCK_HTC_TX(target); + return pPacket; + } else { + HTC_PACKET_ENQUEUE(&lookupQueue, pPacket); + } + + /* + * Move TX lookup queue to temp queue because most of packets that are not index 0 + * are not top 10 packets. + */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue, + &pEndpoint->TxLookupQueue); + UNLOCK_HTC_TX(target); + + ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket, + HTC_PACKET, ListLink) { + + if (NULL == pPacket) { + pFoundPacket = pPacket; + break; + } + /* check for removal */ + if (netbuf == + (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { + /* found it */ + HTC_PACKET_REMOVE(&lookupQueue, pPacket); + pFoundPacket = pPacket; + break; + } + + } + ITERATE_END; + + LOCK_HTC_TX(target); + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue, + &lookupQueue); + UNLOCK_HTC_TX(target); + + return pFoundPacket; +} + +CDF_STATUS htc_tx_completion_handler(void *Context, + cdf_nbuf_t netbuf, unsigned int EpID, + uint32_t toeplitz_hash_result) +{ + HTC_TARGET *target = (HTC_TARGET *) Context; + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED + HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = + { ENDPOINT_5, ENDPOINT_4, ENDPOINT_2, ENDPOINT_3 }; + int epidIdx; + A_UINT16 resourcesThresh[DATA_EP_SIZE]; /* urb resources */ + A_UINT16 resources; + A_UINT16 resourcesMax; +#endif + + pEndpoint = &target->EndPoint[EpID]; + target->TX_comp_cnt++; + + do { + pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf); + if (NULL == pPacket) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC TX lookup failed!\n")); + /* may have already been flushed and freed */ + netbuf = NULL; + break; + } + if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) { + HTC_PACKET *pPacketTemp; + HTC_PACKET_QUEUE *pQueueSave = + (HTC_PACKET_QUEUE *) pPacket->pContext; + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave, + pPacketTemp) { + pPacket->Status = A_OK; + send_packet_completion(target, pPacketTemp); + } + HTC_PACKET_QUEUE_ITERATE_END; + free_htc_bundle_packet(target, pPacket); + return CDF_STATUS_SUCCESS; + } + /* will be giving this buffer back to upper layers */ + netbuf = NULL; + pPacket->Status = CDF_STATUS_SUCCESS; + send_packet_completion(target, pPacket); + + } while (false); + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + /* note: when using TX credit flow, the re-checking of queues happens + * when credits flow back from the target. + * in the non-TX credit case, we recheck after the packet completes */ + htc_try_send(target, pEndpoint, NULL); + } + + return CDF_STATUS_SUCCESS; +} + +/* callback when TX resources become available */ +void htc_tx_resource_avail_handler(void *context, A_UINT8 pipeID) +{ + int i; + HTC_TARGET *target = (HTC_TARGET *) context; + HTC_ENDPOINT *pEndpoint = NULL; + + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->EndPoint[i]; + if (pEndpoint->ServiceID != 0) { + if (pEndpoint->UL_PipeID == pipeID) { + break; + } + } + } + + if (i >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid pipe indicated for TX resource avail : %d!\n", + pipeID)); + return; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("HIF indicated more resources for pipe:%d \n", + pipeID)); + + htc_try_send(target, pEndpoint, NULL); +} + +/* flush endpoint TX queue */ +void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_TX_TAG Tag) +{ + HTC_PACKET *pPacket; + + LOCK_HTC_TX(target); + while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); + + if (pPacket) { + /* let the sender know the packet was not delivered */ + pPacket->Status = A_ECANCELED; + send_packet_completion(target, pPacket); + } + } + UNLOCK_HTC_TX(target); +} + +/* HTC API to flush an endpoint's TX queue*/ +void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, + HTC_TX_TAG Tag) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint = &target->EndPoint[Endpoint]; + + if (pEndpoint->ServiceID == 0) { + AR_DEBUG_ASSERT(false); + /* not in use.. */ + return; + } + + htc_flush_endpoint_tx(target, pEndpoint, Tag); +} + +/* HTC API to indicate activity to the credit distribution function */ +void htc_indicate_activity_change(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, A_BOOL Active) +{ + /* TODO */ +} + +A_BOOL htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) +{ + return true; +} + +/* process credit reports and call distribution function */ +void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, + int NumEntries, HTC_ENDPOINT_ID FromEndpoint) +{ + int i; + HTC_ENDPOINT *pEndpoint; + int totalCredits = 0; + A_UINT8 rpt_credits, rpt_ep_id; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_process_credit_rpt, Credit Report Entries:%d \n", + NumEntries)); + + /* lock out TX while we update credits */ + LOCK_HTC_TX(target); + + for (i = 0; i < NumEntries; i++, pRpt++) { + + rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID); + + if (rpt_ep_id >= ENDPOINT_MAX) { + AR_DEBUG_ASSERT(false); + break; + } + + rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS); + + pEndpoint = &target->EndPoint[rpt_ep_id]; +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Increase EP%d %d + %d = %d credits\n", + rpt_ep_id, pEndpoint->TxCredits, + rpt_credits, + pEndpoint->TxCredits + rpt_credits)); + } +#endif + +#ifdef HTC_EP_STAT_PROFILING + + INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1); + INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits); + + if (FromEndpoint == rpt_ep_id) { + /* this credit report arrived on the same endpoint indicating it arrived in an RX + * packet */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1); + } else if (FromEndpoint == ENDPOINT_0) { + /* this credit arrived on endpoint 0 as a NULL message */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1); + } else { + /* arrived on another endpoint */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1); + } + +#endif +#if defined(HIF_USB) + if (pEndpoint->Id >= ENDPOINT_2 && pEndpoint->Id <= ENDPOINT_5) { + HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = + { ENDPOINT_5, ENDPOINT_4, ENDPOINT_2, ENDPOINT_3 }; + int epid_idx; + + target->avail_tx_credits += rpt_credits; + + for (epid_idx = 0; epid_idx < DATA_EP_SIZE; epid_idx++) { + pEndpoint = &target->EndPoint[eid[epid_idx]]; + if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + break; + } + + } + UNLOCK_HTC_TX(target); + htc_try_send(target, pEndpoint, NULL); + LOCK_HTC_TX(target); + } else { + pEndpoint->TxCredits += rpt_credits; + + if (pEndpoint->TxCredits + && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + UNLOCK_HTC_TX(target); + htc_try_send(target, pEndpoint, NULL); + LOCK_HTC_TX(target); + } + } +#else + pEndpoint->TxCredits += rpt_credits; + + if (pEndpoint->ServiceID == WMI_CONTROL_SVC) { + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_PROCESS_CREDIT_REPORT, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> + TxQueue)); + UNLOCK_HTC_CREDIT(target); + } + + if (pEndpoint->TxCredits + && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + UNLOCK_HTC_TX(target); +#ifdef ATH_11AC_TXCOMPACT + htc_try_send(target, pEndpoint, NULL); +#else + if (pEndpoint->ServiceID == HTT_DATA_MSG_SVC) { + htc_send_data_pkt(target, NULL, 0); + } else { + htc_try_send(target, pEndpoint, NULL); + } +#endif + LOCK_HTC_TX(target); + } +#endif + totalCredits += rpt_credits; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Report indicated %d credits to distribute \n", + totalCredits)); + + UNLOCK_HTC_TX(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt \n")); +} + +/* function to fetch stats from htc layer*/ +struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + return (&(target->htc_pkt_stats)); +} diff --git a/core/htc/htc_services.c b/core/htc/htc_services.c new file mode 100644 index 0000000000..40067f7336 --- /dev/null +++ b/core/htc/htc_services.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include /* cdf_nbuf_t */ +#include "hif.h" + +/* use credit flow control over HTC */ +unsigned int htc_credit_flow = 1; +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +A_STATUS htc_connect_service(HTC_HANDLE HTCHandle, + HTC_SERVICE_CONNECT_REQ *pConnectReq, + HTC_SERVICE_CONNECT_RESP *pConnectResp) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + A_STATUS status = A_OK; + HTC_PACKET *pSendPacket = NULL; + HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg; + HTC_CONNECT_SERVICE_MSG *pConnectMsg; + HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX; + HTC_ENDPOINT *pEndpoint; + unsigned int maxMsgSize = 0; + cdf_nbuf_t netbuf; + A_UINT8 txAlloc; + int length; + A_BOOL disableCreditFlowCtrl = false; + A_UINT16 conn_flags; + A_UINT16 rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size; + A_UINT8 rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+htc_connect_service, target:%p SvcID:0x%X \n", target, + pConnectReq->ServiceID)); + + do { + + AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0); + + if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) { + /* special case for pseudo control service */ + assignedEndpoint = ENDPOINT_0; + maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH; + txAlloc = 0; + + } else { + + txAlloc = + htc_get_credit_allocation(target, + pConnectReq->ServiceID); + if (!txAlloc) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("Service %d does not allocate target credits!\n", + pConnectReq->ServiceID)); + } + + /* allocate a packet to send to the target */ + pSendPacket = htc_alloc_control_tx_packet(target); + + if (NULL == pSendPacket) { + AR_DEBUG_ASSERT(false); + status = A_NO_MEMORY; + break; + } + + netbuf = + (cdf_nbuf_t) + GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); + length = + sizeof(HTC_CONNECT_SERVICE_MSG) + + pConnectReq->MetaDataLength; + + /* assemble connect service message */ + cdf_nbuf_put_tail(netbuf, length); + pConnectMsg = + (HTC_CONNECT_SERVICE_MSG *) cdf_nbuf_data(netbuf); + + if (NULL == pConnectMsg) { + AR_DEBUG_ASSERT(0); + status = A_EFAULT; + break; + } + + A_MEMZERO(pConnectMsg, sizeof(HTC_CONNECT_SERVICE_MSG)); + + conn_flags = + (pConnectReq-> + ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) | + HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + SERVICE_ID, pConnectReq->ServiceID); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + CONNECTIONFLAGS, conn_flags); + + if (pConnectReq-> + ConnectionFlags & + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) { + disableCreditFlowCtrl = true; + } +#if defined(HIF_USB) + if (!htc_credit_flow) { + disableCreditFlowCtrl = true; + } +#else + /* Only enable credit for WMI service */ + if (!htc_credit_flow + && pConnectReq->ServiceID != WMI_CONTROL_SVC) { + disableCreditFlowCtrl = true; + } +#endif + /* check caller if it wants to transfer meta data */ + if ((pConnectReq->pMetaData != NULL) && + (pConnectReq->MetaDataLength <= + HTC_SERVICE_META_DATA_MAX_LENGTH)) { + /* copy meta data into message buffer (after header ) */ + A_MEMCPY((A_UINT8 *) pConnectMsg + + sizeof(HTC_CONNECT_SERVICE_MSG), + pConnectReq->pMetaData, + pConnectReq->MetaDataLength); + + HTC_SET_FIELD(pConnectMsg, + HTC_CONNECT_SERVICE_MSG, + SERVICEMETALENGTH, + pConnectReq->MetaDataLength); + } + + SET_HTC_PACKET_INFO_TX(pSendPacket, + NULL, + (A_UINT8 *) pConnectMsg, + length, + ENDPOINT_0, + HTC_SERVICE_TX_PACKET_TAG); + + status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); + /* we don't own it anymore */ + pSendPacket = NULL; + if (A_FAILED(status)) { + break; + } + + /* wait for response */ + status = htc_wait_recv_ctrl_message(target); + if (A_FAILED(status)) { + break; + } + /* we controlled the buffer creation so it has to be properly aligned */ + pResponseMsg = + (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target-> + CtrlResponseBuffer; + + rsp_msg_id = HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + MESSAGEID); + rsp_msg_serv_id = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + SERVICEID); + rsp_msg_status = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + STATUS); + rsp_msg_end_id = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + ENDPOINTID); + rsp_msg_max_msg_size = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + MAXMSGSIZE); + rsp_msg_serv_meta_len = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + SERVICEMETALENGTH); + + if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) + || (target->CtrlResponseLength < + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) { + /* this message is not valid */ + AR_DEBUG_ASSERT(false); + status = A_EPROTO; + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n", + rsp_msg_serv_id, rsp_msg_status, + rsp_msg_end_id)); + + pConnectResp->ConnectRespCode = rsp_msg_status; + + /* check response status */ + if (rsp_msg_status != HTC_SERVICE_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Target failed service 0x%X connect request (status:%d)\n", + rsp_msg_serv_id, + rsp_msg_status)); + status = A_EPROTO; +#ifdef QCA_TX_HTT2_SUPPORT + /* Keep work and not to block the control message. */ + target->CtrlResponseProcessing = false; +#endif /* QCA_TX_HTT2_SUPPORT */ + break; + } + + assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id; + maxMsgSize = rsp_msg_max_msg_size; + + if ((pConnectResp->pMetaData != NULL) && + (rsp_msg_serv_meta_len > 0) && + (rsp_msg_serv_meta_len <= + HTC_SERVICE_META_DATA_MAX_LENGTH)) { + /* caller supplied a buffer and the target responded with data */ + int copyLength = + min((int)pConnectResp->BufferLength, + (int)rsp_msg_serv_meta_len); + /* copy the meta data */ + A_MEMCPY(pConnectResp->pMetaData, + ((A_UINT8 *) pResponseMsg) + + sizeof + (HTC_CONNECT_SERVICE_RESPONSE_MSG), + copyLength); + pConnectResp->ActualLength = copyLength; + } + /* done processing response buffer */ + target->CtrlResponseProcessing = false; + } + + /* the rest of these are parameter checks so set the error status */ + status = A_EPROTO; + + if (assignedEndpoint >= ENDPOINT_MAX) { + AR_DEBUG_ASSERT(false); + break; + } + + if (0 == maxMsgSize) { + AR_DEBUG_ASSERT(false); + break; + } + + pEndpoint = &target->EndPoint[assignedEndpoint]; + pEndpoint->Id = assignedEndpoint; + if (pEndpoint->ServiceID != 0) { + /* endpoint already in use! */ + AR_DEBUG_ASSERT(false); + break; + } + + /* return assigned endpoint to caller */ + pConnectResp->Endpoint = assignedEndpoint; + pConnectResp->MaxMsgLength = maxMsgSize; + + /* setup the endpoint */ + pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */ + pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth; + pEndpoint->MaxMsgLength = maxMsgSize; + pEndpoint->TxCredits = txAlloc; + pEndpoint->TxCreditSize = target->TargetCreditSize; + pEndpoint->TxCreditsPerMaxMsg = + maxMsgSize / target->TargetCreditSize; + if (maxMsgSize % target->TargetCreditSize) { + pEndpoint->TxCreditsPerMaxMsg++; + } +#if DEBUG_CREDIT + cdf_print(" Endpoint%d initial credit:%d, size:%d.\n", + pEndpoint->Id, pEndpoint->TxCredits, + pEndpoint->TxCreditSize); +#endif + + /* copy all the callbacks */ + pEndpoint->EpCallBacks = pConnectReq->EpCallbacks; + + status = hif_map_service_to_pipe(target->hif_dev, + pEndpoint->ServiceID, + &pEndpoint->UL_PipeID, + &pEndpoint->DL_PipeID, + &pEndpoint->ul_is_polled, + &pEndpoint->dl_is_polled); + if (A_FAILED(status)) { + break; + } + + cdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */ + + if (pEndpoint->ul_is_polled) { + cdf_softirq_timer_init(target->osdev, + &pEndpoint->ul_poll_timer, + htc_send_complete_check_cleanup, + pEndpoint, + CDF_TIMER_TYPE_SW); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SETUP, + ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n", + pEndpoint->ServiceID, pEndpoint->UL_PipeID, + pEndpoint->DL_PipeID, pEndpoint->Id)); + + if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) { + pEndpoint->TxCreditFlowEnabled = false; + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n", + pEndpoint->ServiceID, + assignedEndpoint)); + } + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service \n")); + + return status; +} + +void htc_set_credit_distribution(HTC_HANDLE HTCHandle, + void *pCreditDistContext, + HTC_CREDIT_DIST_CALLBACK CreditDistFunc, + HTC_CREDIT_INIT_CALLBACK CreditInitFunc, + HTC_SERVICE_ID ServicePriorityOrder[], + int ListLength) +{ + /* NOT Supported, this transport does not use a credit based flow control mechanism */ + +} + +void htc_fw_event_handler(void *context, CDF_STATUS status) +{ + HTC_TARGET *target = (HTC_TARGET *) context; + HTC_INIT_INFO *initInfo = &target->HTCInitInfo; + + /* check if target failure handler exists and pass error code to it. */ + if (target->HTCInitInfo.TargetFailure != NULL) { + initInfo->TargetFailure(initInfo->pContext, status); + } +} + +/* Disable ASPM : disable PCIe low power */ +void htc_disable_aspm(void) +{ + hif_disable_aspm(); +} diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h new file mode 100644 index 0000000000..f3bee2ad08 --- /dev/null +++ b/core/mac/inc/ani_global.h @@ -0,0 +1,1064 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ANIGLOBAL_H +#define _ANIGLOBAL_H + +/* Take care to avoid redefinition of this type, if it is */ +/* already defined in "halWmmApi.h" */ +#if !defined(_HALMAC_WMM_API_H) +typedef struct sAniSirGlobal *tpAniSirGlobal; +#endif + +#include "cdf_types.h" +#include "sir_common.h" +#include "ani_system_defs.h" +#include "sys_def.h" +#include "dph_global.h" +#include "lim_global.h" +#include "sch_global.h" +#include "sys_global.h" +#include "cfg_global.h" +#include "utils_global.h" +#include "sir_api.h" + +#include "csr_api.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "sme_ft_api.h" +#endif +#include "csr_support.h" +#include "sme_internal.h" +#include "sap_api.h" +#include "csr_internal.h" + +#ifdef FEATURE_OEM_DATA_SUPPORT +#include "oem_data_internal.h" +#endif + +#if defined WLAN_FEATURE_VOWIFI +#include "sme_rrm_internal.h" +#include "rrm_global.h" +#endif +#include "p2p_api.h" + +#if defined WLAN_FEATURE_VOWIFI_11R +#include +#endif + +/* Check if this definition can actually move here from halInternal.h even for Volans. In that case */ +/* this featurization can be removed. */ +#define PMAC_STRUCT(_hHal) ((tpAniSirGlobal)_hHal) + +#define ANI_DRIVER_TYPE(pMac) (((tpAniSirGlobal)(pMac))->gDriverType) + +#define IS_MIRACAST_SESSION_PRESENT(pMac) (((tpAniSirGlobal)(pMac))->fMiracastSessionPresent ? 1 : 0) +/* ------------------------------------------------------------------- */ +/* Bss Qos Caps bit map definition */ +#define LIM_BSS_CAPS_OFFSET_HCF 0 +#define LIM_BSS_CAPS_OFFSET_WME 1 +#define LIM_BSS_CAPS_OFFSET_WSM 2 + +#define LIM_BSS_CAPS_HCF (1 << LIM_BSS_CAPS_OFFSET_HCF) +#define LIM_BSS_CAPS_WME (1 << LIM_BSS_CAPS_OFFSET_WME) +#define LIM_BSS_CAPS_WSM (1 << LIM_BSS_CAPS_OFFSET_WSM) + +/* cap should be one of HCF/WME/WSM */ +#define LIM_BSS_CAPS_GET(cap, val) (((val) & (LIM_BSS_CAPS_ ## cap)) >> LIM_BSS_CAPS_OFFSET_ ## cap) +#define LIM_BSS_CAPS_SET(cap, val) ((val) |= (LIM_BSS_CAPS_ ## cap)) +#define LIM_BSS_CAPS_CLR(cap, val) ((val) &= (~(LIM_BSS_CAPS_ ## cap))) + +/* 40 beacons per heart beat interval is the default + 1 to count the rest */ +#define MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL 41 + +/* max number of legacy bssid we can store during scan on one channel */ +#define MAX_NUM_LEGACY_BSSID_PER_CHANNEL 10 + +#define P2P_WILDCARD_SSID "DIRECT-" /* TODO Put it in proper place; */ +#define P2P_WILDCARD_SSID_LEN 7 + +#ifdef WLAN_FEATURE_CONCURRENT_P2P +#define MAX_NO_OF_P2P_SESSIONS 5 +#endif /* WLAN_FEATURE_CONCURRENT_P2P */ + +#define SPACE_ASCII_VALUE 32 + +#define WLAN_HOST_SEQ_NUM_MIN 2048 +#define WLAN_HOST_SEQ_NUM_MAX 4095 +#define LOW_SEQ_NUM_MASK 0x000F +#define HIGH_SEQ_NUM_MASK 0x0FF0 +#define HIGH_SEQ_NUM_OFFSET 4 + +/* vendor element ID */ +#define IE_EID_VENDOR (221) /* 0xDD */ +#define IE_LEN_SIZE (1) +#define IE_EID_SIZE (1) +/* Minimum size of vendor IE = 3 bytes of oui_data + 1 byte of data */ +#define IE_VENDOR_OUI_SIZE (4) + +/** + * enum log_event_type - Type of event initiating bug report + * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event + * @WLAN_LOG_TYPE_FATAL: Fatal event + * + * Enum indicating the type of event that is initiating the bug report + */ +enum log_event_type { + WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_TYPE_FATAL, +}; + +/** + * enum log_event_indicator - Module triggering bug report + * @WLAN_LOG_INDICATOR_UNUSED: Unused + * @WLAN_LOG_INDICATOR_FRAMEWORK: Framework triggers bug report + * @WLAN_LOG_INDICATOR_HOST_DRIVER: Host driver triggers bug report + * @WLAN_LOG_INDICATOR_FIRMWARE: FW initiates bug report + * + * Enum indicating the module that triggered the bug report + */ +enum log_event_indicator { + WLAN_LOG_INDICATOR_UNUSED, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_INDICATOR_FIRMWARE, +}; + +/** + * enum log_event_host_reason_code - Reason code for bug report + * @WLAN_LOG_REASON_CODE_UNUSED: Unused + * @WLAN_LOG_REASON_COMMAND_UNSUCCESSFUL: Command response status from FW + * is error + * @WLAN_LOG_REASON_ROAM_FAIL: Driver initiated roam has failed + * @WLAN_LOG_REASON_THREAD_STUCK: Monitor Health of host threads and report + * fatal event if some thread is stuck + * @WLAN_LOG_REASON_DATA_STALL: Unable to send/receive data due to low resource + * scenario for a prolonged period + * @WLAN_LOG_REASON_SME_COMMAND_STUCK: SME command is stuck in SME active queue + * @WLAN_LOG_REASON_ZERO_SCAN_RESULTS: Full scan resulted in zero scan results + * @WLAN_LOG_REASON_QUEUE_FULL: Defer queue becomes full for a prolonged period + * @WLAN_LOG_REASON_POWER_COLLAPSE_FAIL: Unable to allow apps power collapse + * for a prolonged period + * @WLAN_LOG_REASON_SSR_FAIL: Unable to gracefully complete SSR + * @WLAN_LOG_REASON_DISCONNECT_FAIL: Disconnect from Supplicant is not + * successful + * @WLAN_LOG_REASON_CLEAN_UP_FAIL: Clean up of TDLS or Pre-Auth Sessions + * not successful + * @WLAN_LOG_REASON_MALLOC_FAIL: Memory allocation Fails + * @WLAN_LOG_REASON_VOS_MSG_UNDER_RUN: VOS Core runs out of message wrapper + * @WLAN_LOG_REASON_MSG_POST_FAIL: Unable to post msg + * + * This enum contains the different reason codes for bug report + */ +enum log_event_host_reason_code { + WLAN_LOG_REASON_CODE_UNUSED, + WLAN_LOG_REASON_COMMAND_UNSUCCESSFUL, + WLAN_LOG_REASON_ROAM_FAIL, + WLAN_LOG_REASON_THREAD_STUCK, + WLAN_LOG_REASON_DATA_STALL, + WLAN_LOG_REASON_SME_COMMAND_STUCK, + WLAN_LOG_REASON_ZERO_SCAN_RESULTS, + WLAN_LOG_REASON_QUEUE_FULL, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + WLAN_LOG_REASON_SSR_FAIL, + WLAN_LOG_REASON_DISCONNECT_FAIL, + WLAN_LOG_REASON_CLEAN_UP_FAIL, + WLAN_LOG_REASON_MALLOC_FAIL, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + WLAN_LOG_REASON_MSG_POST_FAIL, +}; + +/** + * enum userspace_log_level - Log level at userspace + * @LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection + * @LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log level, + * with minimal user impact. this is the default value + * @LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily + * trying to reproduce a problem, wifi performances and power can be impacted + * but device should not otherwise be significantly impacted + * @LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to + * actively debug a problem + * + * Various log levels defined in the userspace for logging applications + */ +enum userspace_log_level { + LOG_LEVEL_NO_COLLECTION, + LOG_LEVEL_NORMAL_COLLECT, + LOG_LEVEL_ISSUE_REPRO, + LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_driver_log_level - Log level defined in the driver for logging + * @WLAN_LOG_LEVEL_OFF: No logging + * @WLAN_LOG_LEVEL_NORMAL: Default logging + * @WLAN_LOG_LEVEL_REPRO: Normal debug level + * @WLAN_LOG_LEVEL_ACTIVE: Active debug level + * + * Log levels defined for logging by the wifi driver + */ +enum wifi_driver_log_level { + WLAN_LOG_LEVEL_OFF, + WLAN_LOG_LEVEL_NORMAL, + WLAN_LOG_LEVEL_REPRO, + WLAN_LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_logging_ring_id - Ring id of logging entities + * @RING_ID_WAKELOCK: Power events ring id + * @RING_ID_CONNECTIVITY: Connectivity event ring id + * @RING_ID_PER_PACKET_STATS: Per packet statistic ring id + * @RIND_ID_DRIVER_DEBUG: Driver debug messages ring id + * @RING_ID_FIRMWARE_DEBUG: Firmware debug messages ring id + * + * This enum has the ring id values of logging rings + */ +enum wifi_logging_ring_id { + RING_ID_WAKELOCK, + RING_ID_CONNECTIVITY, + RING_ID_PER_PACKET_STATS, + RIND_ID_DRIVER_DEBUG, + RING_ID_FIRMWARE_DEBUG, +}; + +/* ------------------------------------------------------------------- */ +/* Change channel generic scheme */ +typedef void (*CHANGE_CHANNEL_CALLBACK)(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, + tpPESession psessionEntry); + +/* / LIM global definitions */ +typedef struct sAniSirLimIbss { + void *pHdr; + void *pBeacon; +} tAniSirLimIbss; + +typedef struct sDialogueToken { + /* bytes 0-3 */ + uint16_t assocId; + uint8_t token; + uint8_t rsvd1; + /* Bytes 4-7 */ + uint16_t tid; + uint8_t rsvd2[2]; + + struct sDialogueToken *next; +} tDialogueToken, *tpDialogueToken; + +typedef struct sLimTimers { + /* TIMERS IN LIM ARE NOT SUPPOSED TO BE ZEROED OUT DURING RESET. */ + /* DURING lim_initialize DONOT ZERO THEM OUT. */ + +/* STA SPECIFIC TIMERS */ + + TX_TIMER gLimPreAuthClnupTimer; + + /* Association related timers */ + TX_TIMER gLimAssocFailureTimer; + TX_TIMER gLimReassocFailureTimer; + + /* / Wait for Probe after Heartbeat failure timer on STA */ + TX_TIMER gLimProbeAfterHBTimer; + + /* Authentication related timers */ + TX_TIMER gLimAuthFailureTimer; + + /* Join Failure timeout on STA */ + TX_TIMER gLimJoinFailureTimer; + + TX_TIMER gLimPeriodicProbeReqTimer; + + /* CNF_WAIT timer */ + TX_TIMER *gpLimCnfWaitTimer; + + /* Send Disassociate frame threshold parameters */ + TX_TIMER gLimSendDisassocFrameThresholdTimer; + + TX_TIMER gLimAddtsRspTimer; /* max wait for a response */ + + /* Update OLBC Cache Timer */ + TX_TIMER gLimUpdateOlbcCacheTimer; + + TX_TIMER gLimChannelSwitchTimer; + /* This TIMER is started on the STA, as indicated by the */ + /* AP in its Quiet BSS IE, for the specified interval */ + TX_TIMER gLimQuietTimer; + /* This TIMER is started on the AP, prior to the AP going */ + /* into LEARN mode */ + /* This TIMER is started on the STA, for the specified */ + /* quiet duration */ + TX_TIMER gLimQuietBssTimer; + +#ifdef WLAN_FEATURE_VOWIFI_11R + TX_TIMER gLimFTPreAuthRspTimer; +#endif + +#ifdef FEATURE_WLAN_ESE + TX_TIMER gLimEseTsmTimer; +#endif + TX_TIMER gLimRemainOnChannelTimer; + + TX_TIMER gLimPeriodicJoinProbeReqTimer; + TX_TIMER gLimDisassocAckTimer; + TX_TIMER gLimDeauthAckTimer; + /* This timer is started when single shot NOA insert msg is sent to FW for scan in P2P GO mode */ + TX_TIMER gLimP2pSingleShotNoaInsertTimer; + /* This timer is used to convert active channel to + * passive channel when there is no beacon + * for a period of time on a particular DFS channel + */ + TX_TIMER gLimActiveToPassiveChannelTimer; + +/* ********************TIMER SECTION ENDS************************************************** */ +/* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */ +/* **************************************************************************************** */ + +} tLimTimers; + +typedef struct { + void *pMlmDisassocReq; + void *pMlmDeauthReq; +} tLimDisassocDeauthCnfReq; + +typedef struct sAniSirLim { + /* //////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// */ + + tLimTimers limTimers; + /* / Flag to track if LIM timers are created or not */ + uint32_t gLimTimersCreated; + + /* //////////////////////////////////// TIMER RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////// SCAN/LEARN RELATED START /////////////////////////////////////////// */ + /** + * This flag when set, will use scan mode instead of + * Learn mode on BP/AP. By default this flag is set + * to true until HIF getting stuck in 0x800 state is + * debugged. + */ + uint32_t gLimUseScanModeForLearnMode; + + /** + * This is useful for modules other than LIM + * to see if system is in scan/learn mode or not + */ + uint32_t gLimSystemInScanLearnMode; + + /* Scan related globals on STA */ + uint8_t gLimReturnAfterFirstMatch; + uint8_t gLim24Band11dScanDone; + uint8_t gLim50Band11dScanDone; + uint8_t gLimReturnUniqueResults; + + /* / Place holder for current channel ID */ + /* / being scanned */ + uint32_t gLimCurrentScanChannelId; + + /* Hold onto SCAN criteria */ + /* The below is used in P2P GO case when we need to defer processing SME Req + * to LIM and insert NOA first and process SME req once SNOA is started + */ + uint16_t gDeferMsgTypeForNOA; + uint32_t *gpDefdSmeMsgForNOA; + + tLimMlmScanReq *gpLimMlmScanReq; + + + /* Used to store the list of legacy bss sta detected during scan on one channel */ + uint16_t gLimRestoreCBNumScanInterval; + uint16_t gLimRestoreCBCount; + tSirMacAddr gLimLegacyBssidList[MAX_NUM_LEGACY_BSSID_PER_CHANNEL]; + + /* abort scan is used to abort an on-going scan */ + uint8_t abortScan; + tLimScanChnInfo scanChnInfo; + + /* //////////////////////////////////// SCAN/LEARN RELATED START /////////////////////////////////////////// */ + tSirMacAddr gSelfMacAddr; /* added for BT-AMP Support */ + + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + /* Place holder for StartBssReq message */ + /* received by SME state machine */ + + uint8_t gLimCurrentBssUapsd; + + /* This is used for testing sta legacy bss detect feature */ + uint8_t gLimForceNoPropIE; + + /* */ + /* Store the BSS Index returned by HAL during */ + /* WMA_ADD_BSS_RSP here. */ + /* */ + + /* For now: */ + /* This will be used during WMA_SET_BSSKEY_REQ in */ + /* order to set the GTK */ + /* Later: */ + /* There could be other interfaces needing this info */ + /* */ + + /* */ + /* Due to the asynchronous nature of the interface */ + /* between PE <-> HAL, some transient information */ + /* like this needs to be cached. */ + /* This is cached upon receipt of eWNI_SME_SETCONTEXT_REQ. */ + /* This is released while posting LIM_MLM_SETKEYS_CNF */ + /* */ + void *gpLimMlmSetKeysReq; + + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// IBSS RELATED START /////////////////////////////////////////// */ + /* This indicates whether this STA coalesced and adapter to peer's capabilities or not. */ + uint8_t gLimIbssCoalescingHappened; + + /* / Definition for storing IBSS peers BSS description */ + tLimIbssPeerNode *gLimIbssPeerList; + uint32_t gLimNumIbssPeers; + uint32_t ibss_retry_cnt; + + /* ibss info - params for which ibss to join while coalescing */ + tAniSirLimIbss ibssInfo; + + /* //////////////////////////////////////// IBSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATS/COUNTER RELATED START /////////////////////////////////////////// */ + + uint16_t maxStation; + uint16_t maxBssId; + + uint32_t gLimNumBeaconsRcvd; + uint32_t gLimNumBeaconsIgnored; + + uint32_t gLimNumDeferredMsgs; + + /* / Variable to keep track of number of currently associated STAs */ + uint16_t gLimNumOfAniSTAs; /* count of ANI peers */ + uint16_t gLimAssocStaLimit; + + /* Heart-Beat interval value */ + uint32_t gLimHeartBeatCount; + tSirMacAddr gLimHeartBeatApMac[2]; + uint8_t gLimHeartBeatApMacIndex; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + uint16_t + gLimHeartBeatBeaconStats[MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL]; + +#ifdef WLAN_DEBUG + /* Debug counters */ + uint32_t numTot, numBbt, numProtErr, numLearn, numLearnIgnore; + uint32_t numSme, numMAC[4][16]; + + /* Debug counter to track number of Assoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumAssocReqDropInvldState; + /* counters to track rejection of Assoc Req due to Admission Control */ + uint32_t gLimNumAssocReqDropACRejectTS; + uint32_t gLimNumAssocReqDropACRejectSta; + /* Debug counter to track number of Reassoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumReassocReqDropInvldState; + /* Debug counter to track number of Hash Miss event that */ + /* will not cause a sending of de-auth/de-associate frame */ + uint32_t gLimNumHashMissIgnored; + + /* Debug counter to track number of Beacon frames */ + /* received in unexpected state */ + uint32_t gLimUnexpBcnCnt; + + /* Debug counter to track number of Beacon frames */ + /* received in wt-join-state that do have SSID mismatch */ + uint32_t gLimBcnSSIDMismatchCnt; + + /* Debug counter to track number of Link establishments on STA/BP */ + uint32_t gLimNumLinkEsts; + + /* Debug counter to track number of Rx cleanup */ + uint32_t gLimNumRxCleanup; + + /* Debug counter to track different parse problem */ + uint32_t gLim11bStaAssocRejectCount; + +#endif + + /* Time stamp of the last beacon received from the BSS to which STA is connected. */ + uint64_t gLastBeaconTimeStamp; + /* RX Beacon count for the current BSS to which STA is connected. */ + uint32_t gCurrentBssBeaconCnt; + uint8_t gLastBeaconDtimCount; + uint8_t gLastBeaconDtimPeriod; + + /* //////////////////////////////////////// STATS/COUNTER RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATES RELATED START /////////////////////////////////////////// */ + /* Counts Heartbeat failures */ + uint8_t gLimHBfailureCntInLinkEstState; + uint8_t gLimProbeFailureAfterHBfailedCnt; + uint8_t gLimHBfailureCntInOtherStates; + + /** + * This variable indicates whether LIM module need to + * send response to host. Used to identify whether a request + * is generated internally within LIM module or by host + */ + uint8_t gLimRspReqd; + + /* / Previous SME State */ + tLimSmeStates gLimPrevSmeState; + + /* / MLM State visible across all Sirius modules */ + tLimMlmStates gLimMlmState; + + /* / Previous MLM State */ + tLimMlmStates gLimPrevMlmState; + + /* LIM to HAL SCAN Management Message Interface states */ + tLimLimHalScanState gLimHalScanState; +/* WLAN_SUSPEND_LINK Related */ + SUSPEND_RESUME_LINK_CALLBACK gpLimSuspendCallback; + uint32_t *gpLimSuspendData; + SUSPEND_RESUME_LINK_CALLBACK gpLimResumeCallback; + uint32_t *gpLimResumeData; +/* end WLAN_SUSPEND_LINK Related */ + /* Can be set to invalid channel. If it is invalid, HAL */ + /* should move to previous valid channel or stay in the */ + /* current channel. CB state goes along with channel to resume to */ + uint16_t gResumeChannel; + ePhyChanBondState gResumePhyCbState; + + /* Change channel generic scheme */ + CHANGE_CHANNEL_CALLBACK gpchangeChannelCallback; + uint32_t *gpchangeChannelData; + + /* / SME State visible across all Sirius modules */ + tLimSmeStates gLimSmeState; + /* / This indicates whether we're an AP, STA in BSS/IBSS */ + tLimSystemRole gLimSystemRole; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOverlap11gParams; + + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + /* */ + /* ---------------- DPH ----------------------- */ + /* these used to live in DPH but are now moved here (where they belong) */ + uint32_t gLimPhyMode; + uint32_t propRateAdjustPeriod; + uint32_t scanStartTime; /* used to measure scan time */ + + uint8_t gLimMyMacAddr[6]; + uint8_t ackPolicy; + + uint8_t gLimQosEnabled:1; /* 11E */ + uint8_t gLimWmeEnabled:1; /* WME */ + uint8_t gLimWsmEnabled:1; /* WSM */ + uint8_t gLimHcfEnabled:1; + uint8_t gLim11dEnabled:1; + uint8_t gLimProbeRespDisableFlag:1; /* control over probe response */ + /* ---------------- DPH ----------------------- */ + + /* //////////////////////////////////////// STATES RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// MISC RELATED START /////////////////////////////////////////// */ + + /* Deferred Queue Parameters */ + tLimDeferredMsgQParams gLimDeferredMsgQ; + + /* addts request if any - only one can be outstanding at any time */ + tSirAddtsReq gLimAddtsReq; + uint8_t gLimAddtsSent; + uint8_t gLimAddtsRspTimerCount; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + uint8_t gLimProtectionControl; + /* This flag will remain to be set except while LIM is waiting for specific response messages */ + /* from HAL. e.g when LIM issues ADD_STA req it will clear this flag and when it will receive */ + /* the response the flag will be set. */ + uint8_t gLimProcessDefdMsgs; + + /* UAPSD flag used on AP */ + uint8_t gUapsdEnable; + + /* Used on STA, this is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. If a + * particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + */ + uint8_t gUapsdPerAcBitmask; + + /* Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That partiular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* dialogue token List head/tail for Action frames request sent. */ + tpDialogueToken pDialogueTokenHead; + tpDialogueToken pDialogueTokenTail; + + tLimTspecInfo tspecInfo[LIM_NUM_TSPEC_MAX]; + + /* admission control policy information */ + tLimAdmitPolicyInfo admitPolicyInfo; + cdf_mutex_t lkPeGlobalLock; + uint8_t disableLDPCWithTxbfAP; +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimTDLSBufStaEnabled; + uint8_t gLimTDLSUapsdMask; + uint8_t gLimTDLSOffChannelEnabled; + uint8_t gLimTDLSWmmMode; +#endif + /* //////////////////////////////////////// MISC RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// ASSOC RELATED START /////////////////////////////////////////// */ + /* Place holder for JoinReq message */ + /* received by SME state machine */ + /* tpSirSmeJoinReq gpLimJoinReq; */ + + /* Place holder for ReassocReq message */ + /* received by SME state machine */ + /* tpSirSmeReassocReq gpLimReassocReq; sep23 review */ + + /* Current Authentication type used at STA */ + /* tAniAuthType gLimCurrentAuthType; */ + + /* Place holder for current authentication request */ + /* being handled */ + tLimMlmAuthReq *gpLimMlmAuthReq; + + /* Reason code to determine the channel change context while sending */ + /* WMA_CHNL_SWITCH_REQ message to HAL */ + uint32_t channelChangeReasonCode; + + /* / MAC level Pre-authentication related globals */ + tSirMacChanNum gLimPreAuthChannelNumber; + tAniAuthType gLimPreAuthType; + tSirMacAddr gLimPreAuthPeerAddr; + uint32_t gLimNumPreAuthContexts; + tLimPreAuthTable gLimPreAuthTimerTable; + + /* Placed holder to deauth reason */ + uint16_t gLimDeauthReasonCode; + + /* Place holder for Pre-authentication node list */ + struct tLimPreAuthNode *pLimPreAuthList; + + /* Send Disassociate frame threshold parameters */ + uint16_t gLimDisassocFrameThreshold; + uint16_t gLimDisassocFrameCredit; + + /* Assoc or ReAssoc Response Data/Frame */ + void *gLimAssocResponseData; + + /* One cache for each overlap and associated case. */ + tCacheParams protStaOverlapCache[LIM_PROT_STA_OVERLAP_CACHE_SIZE]; + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + /* //////////////////////////////////////// ASSOC RELATED END /////////////////////////////////////////// */ + + /* ////////////////////////////// HT RELATED ////////////////////////////////////////// */ + /* */ + /* The following global LIM variables maintain/manage */ + /* the runtime configurations related to 802.11n */ + + /* 802.11n Station detected HT capability in Beacon Frame */ + uint8_t htCapabilityPresentInBeacon; + + /* 802.11 HT capability: Enabled or Disabled */ + uint8_t htCapability; + + uint8_t gHTGreenfield; + + uint8_t gHTShortGI40Mhz; + uint8_t gHTShortGI20Mhz; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t gHTMaxAmsduLength; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t gHTDsssCckRate40MHzSupport; + + /* PSMP Support: Enabled 1 or Disabled 0 */ + uint8_t gHTPSMPSupport; + + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t gHTLsigTXOPProtection; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState gHTMIMOPSState; + + /* Scan In Power Save */ + uint8_t gScanInPowersave; + + /* */ + /* A-MPDU Density */ + /* 000 - No restriction */ + /* 001 - 1/8 usec */ + /* 010 - 1/4 usec */ + /* 011 - 1/2 usec */ + /* 100 - 1 usec */ + /* 101 - 2 usec */ + /* 110 - 4 usec */ + /* 111 - 8 usec */ + /* */ + uint8_t gHTAMpduDensity; + + bool gMaxAmsduSizeEnabled; + /* Maximum Tx/Rx A-MPDU factor */ + uint8_t gHTMaxRxAMpduFactor; + + /* */ + /* Scheduled PSMP related - Service Interval Granularity */ + /* 000 - 5 ms */ + /* 001 - 10 ms */ + /* 010 - 15 ms */ + /* 011 - 20 ms */ + /* 100 - 25 ms */ + /* 101 - 30 ms */ + /* 110 - 35 ms */ + /* 111 - 40 ms */ + /* */ + uint8_t gHTServiceIntervalGranularity; + + /* Indicates whether an AP wants to associate PSMP enabled Stations */ + uint8_t gHTControlledAccessOnly; + + /* RIFS Mode. Set if no APSD legacy devices associated */ + uint8_t gHTRifsMode; + /* OBss Mode . set when we have Non HT STA is associated or with in overlap bss */ + uint8_t gHTObssMode; + + /* Identifies the current Operating Mode */ + tSirMacHTOperatingMode gHTOperMode; + + /* Indicates if PCO is activated in the BSS */ + uint8_t gHTPCOActive; + + /* */ + /* If PCO is active, indicates which PCO phase to use */ + /* 0 - switch to 20 MHz phase */ + /* 1 - switch to 40 MHz phase */ + /* */ + uint8_t gHTPCOPhase; + + /* */ + /* Used only in beacons. For PR, this is set to 0 */ + /* 0 - Primary beacon */ + /* 1 - Secondary beacon */ + /* */ + uint8_t gHTSecondaryBeacon; + + /* */ + /* Dual CTS Protection */ + /* 0 - Use RTS/CTS */ + /* 1 - Dual CTS Protection is used */ + /* */ + uint8_t gHTDualCTSProtection; + + /* */ + /* Identifies a single STBC MCS that shall ne used for */ + /* STBC control frames and STBC beacons */ + /* */ + uint8_t gHTSTBCBasicMCS; + + uint8_t gHTNonGFDevicesPresent; + + /* ////////////////////////////// HT RELATED ////////////////////////////////////////// */ + +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimAddStaTdls; + uint8_t gLimTdlsLinkMode; + /* ////////////////////////////// TDLS RELATED ////////////////////////////////////////// */ +#endif + + /* wsc info required to form the wsc IE */ + tLimWscIeInfo wscIeInfo; + tpPESession gpSession; /* Pointer to session table */ + /* + * sessionID and transactionID from SME is stored here for those messages, for which + * there is no session context in PE, e.g. Scan related messages. + **/ + uint8_t gSmeSessionId; + uint16_t gTransactionId; + +#ifdef FEATURE_OEM_DATA_SUPPORT + tLimMlmOemDataReq *gpLimMlmOemDataReq; + tLimMlmOemDataRsp *gpLimMlmOemDataRsp; +#endif + + tSirRemainOnChnReq *gpLimRemainOnChanReq; /* hold remain on chan request in this buf */ + cdf_mutex_t lim_frame_register_lock; + cdf_list_t gLimMgmtFrameRegistratinQueue; + uint32_t mgmtFrameSessionId; + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + tpPESession pSessionEntry; + uint8_t reAssocRetryAttempt; +#endif + tLimDisassocDeauthCnfReq limDisassocDeauthCnfReq; + uint8_t deferredMsgCnt; + tSirDFSChannelList dfschannelList; + uint8_t deauthMsgCnt; + uint8_t gLimIbssStaLimit; + + /* Number of channel switch IEs sent so far */ + uint8_t gLimDfsChanSwTxCount; + uint8_t gLimDfsTargetChanNum; + uint8_t probeCounter; + uint8_t maxProbe; + CDF_STATUS(*add_bssdescr_callback) + (tpAniSirGlobal pMac, tpSirBssDescription buf, + uint32_t scan_id, uint32_t flags); + uint8_t retry_packet_cnt; + uint8_t scan_disabled; +} tAniSirLim, *tpAniSirLim; + +struct mgmt_frm_reg_info { + cdf_list_node_t node; /* MUST be first element */ + uint16_t frameType; + uint16_t matchLen; + uint16_t sessionId; + uint8_t matchData[1]; +}; + +#if defined WLAN_FEATURE_VOWIFI +typedef struct sRrmContext { + tRrmSMEContext rrmSmeContext; + tRrmPEContext rrmPEContext; +} tRrmContext, *tpRrmContext; +#endif + +/** + * enum tDriverType - Indicate the driver type to the mac, and based on this + * do appropriate initialization. + * + * @eDRIVER_TYPE_PRODUCTION: + * @eDRIVER_TYPE_MFG: + * + */ +typedef enum { + eDRIVER_TYPE_PRODUCTION = 0, + eDRIVER_TYPE_MFG = 1, +} tDriverType; + +/** ------------------------------------------------------------------------- * + + \typedef tMacOpenParameters + + \brief Parameters needed for Enumeration of all status codes returned by the higher level + interface functions. + + -------------------------------------------------------------------------- */ + +typedef struct sMacOpenParameters { + uint16_t maxStation; + uint16_t maxBssId; + uint32_t frameTransRequired; + uint8_t powersaveOffloadEnabled; + /* Powersave Parameters */ + uint8_t staMaxLIModDtim; + uint8_t staModDtim; + uint8_t staDynamicDtim; + tDriverType driverType; + uint8_t maxWoWFilters; + uint8_t wowEnable; +/* Here olIniInfo is used to store ini + * status of arp offload, ns offload + * and others. Currently 1st bit is used + * for arp off load and 2nd bit for ns + * offload currently, rest bits are unused + */ + uint8_t olIniInfo; + bool ssdp; + /* + * DFS Phyerror Filtering offload status from ini + * 0 indicates offload disabled + * 1 indicates offload enabled + */ + uint8_t dfsPhyerrFilterOffload; +/* pass intra-bss-fwd info to txrx module */ + uint8_t apDisableIntraBssFwd; + + /* max offload peer */ + uint8_t apMaxOffloadPeers; + + /* max offload reorder buffs */ + uint8_t apMaxOffloadReorderBuffs; + +#ifdef FEATURE_WLAN_RA_FILTERING + uint16_t RArateLimitInterval; + bool IsRArateLimitEnabled; +#endif + /* is RX re-ordering offloaded to the fw */ + uint8_t reorderOffload; + + /* dfs radar pri multiplier */ + int32_t dfsRadarPriMultiplier; + + /* IPA Micro controller data path offload enable flag */ + uint8_t ucOffloadEnabled; + /* IPA Micro controller data path offload TX buffer count */ + uint32_t ucTxBufCount; + /* IPA Micro controller data path offload TX buffer size */ + uint32_t ucTxBufSize; + /* IPA Micro controller data path offload RX indication ring count */ + uint32_t ucRxIndRingCount; + /* IPA Micro controller data path offload TX partition base */ + uint32_t ucTxPartitionBase; + bool enable_rxthread; + bool ip_tcp_udp_checksum_offload; + + /* CE based classification enabled */ + bool ce_classify_enabled; + + /* Maximum number of parallel scans */ + uint8_t max_scan; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + /* Threshold to stop queue in percentage */ + uint32_t tx_flow_stop_queue_th; + /* Start queue offset in percentage */ + uint32_t tx_flow_start_queue_offset; +#endif +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + bool tx_chain_mask_cck; + uint16_t self_gen_frm_pwr; +} tMacOpenParameters; + +typedef struct sHalMacStartParameters { + /* parametes for the Firmware */ + tDriverType driverType; + +} tHalMacStartParameters; + +/* ------------------------------------------------------------------- */ +/* / MAC Sirius parameter structure */ +typedef struct sAniSirGlobal { + tDriverType gDriverType; + + tAniSirCfg cfg; + tAniSirLim lim; + tAniSirSch sch; + tAniSirSys sys; + tAniSirUtils utils; + + /* PAL/HDD handle */ + tHddHandle hHdd; + + + tSmeStruct sme; + tSapStruct sap; + tCsrScanStruct scan; + tCsrRoamStruct roam; + +#ifdef FEATURE_OEM_DATA_SUPPORT + tOemDataStruct oemData; +#endif +#if defined WLAN_FEATURE_VOWIFI + tRrmContext rrm; +#endif +#ifdef WLAN_FEATURE_CONCURRENT_P2P + tp2pContext p2pContext[MAX_NO_OF_P2P_SESSIONS]; +#else + tp2pContext p2pContext; +#endif + +#ifdef FEATURE_WLAN_TDLS + bool is_tdls_power_save_prohibited; +#endif + + uint8_t isCoalesingInIBSSAllowed; + + bool imps_enabled; + + /* PNO offload */ + bool pnoOffload; + + csr_readyToSuspendCallback readyToSuspendCallback; + void *readyToSuspendContext; + uint8_t lteCoexAntShare; + uint8_t beacon_offload; + uint32_t fEnableDebugLog; + uint16_t mgmtSeqNum; + bool enable5gEBT; + /* Miracast session 0-Disabled, 1-Source, 2-sink */ + uint8_t fMiracastSessionPresent; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + csr_readyToExtWoWCallback readyToExtWoWCallback; + void *readyToExtWoWContext; +#endif + uint32_t f_sta_miracast_mcc_rest_time_val; + uint8_t f_prefer_non_dfs_on_radar; + hdd_ftm_msg_processor ftm_msg_processor_callback; + bool policy_manager_enabled; + uint32_t fine_time_meas_cap; + + /* 802.11p enable */ + bool enable_dot11p; + + uint32_t dual_mac_feature_disable; + + bool first_scan_done; +} tAniSirGlobal; + +typedef enum { + eHIDDEN_SSID_NOT_IN_USE, + eHIDDEN_SSID_ZERO_LEN, + eHIDDEN_SSID_ZERO_CONTENTS +} tHiddenssId; + +#ifdef FEATURE_WLAN_TDLS + +#define RFC1042_HDR_LENGTH (6) +#define GET_BE16(x) ((uint16_t) (((x)[0] << 8) | (x)[1])) +#define ETH_TYPE_89_0d (0x890d) +#define ETH_TYPE_LEN (2) +#define PAYLOAD_TYPE_TDLS_SIZE (1) +#define PAYLOAD_TYPE_TDLS (2) + +#endif + +#endif /* _ANIGLOBAL_H */ diff --git a/core/mac/inc/ani_system_defs.h b/core/mac/inc/ani_system_defs.h new file mode 100644 index 0000000000..578d0b8339 --- /dev/null +++ b/core/mac/inc/ani_system_defs.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file ani_system_defs.h contains definitions used by + * various ANI entities + * Author: Chandra Modumudi + * Date: 09/18/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __ANI_SYSTEM_DEFS_H +#define __ANI_SYSTEM_DEFS_H + +#include "sir_types.h" +#include "sir_mac_prot_def.h" + +#define ANI_OUI 0x000AF5 + +/* / Max WDS info length. */ +#define ANI_WDS_INFO_MAX_LENGTH 64 + +/* This is to force compiler to use the maximum of an int for enum */ +#define SIR_MAX_ENUM_SIZE 0x7FFFFFFF + +/* Max key size including the WAPI and TKIP */ +#define WLAN_MAX_KEY_RSC_LEN 16 +#define WLAN_WAPI_KEY_RSC_LEN 16 + +#ifndef false +#undef false +#define false 0 +#endif +#ifndef true +#undef true +#define true 1 +#endif + +typedef enum eAniBool { + eSIR_FALSE, + eSIR_TRUE, + eSIR_DONOT_USE_BOOL = SIR_MAX_ENUM_SIZE +} tAniBool; + +/* / Authentication type enum used with peer */ +typedef enum eAniAuthType { + eSIR_OPEN_SYSTEM, + eSIR_SHARED_KEY, +#if defined WLAN_FEATURE_VOWIFI_11R + eSIR_FT_AUTH, +#endif +#if defined FEATURE_WLAN_ESE + eSIR_LEAP_AUTH = 0x80, +#endif + eSIR_AUTO_SWITCH, + eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE +} tAniAuthType; + +/* / Encryption type enum used with peer */ +typedef enum eAniEdType { + eSIR_ED_NONE, + eSIR_ED_WEP40, + eSIR_ED_WEP104, + eSIR_ED_TKIP, + eSIR_ED_CCMP, +#if defined(FEATURE_WLAN_WAPI) + eSIR_ED_WPI, +#endif + /*DPU HW treats encryption mode 4 plus RMF bit set in TX BD as BIP. + Thus while setting BIP encryption mode in corresponding DPU Desc + eSIR_ED_AES_128_CMAC should be set to eSIR_ED_CCMP */ + eSIR_ED_AES_128_CMAC, + eSIR_ED_NOT_IMPLEMENTED = SIR_MAX_ENUM_SIZE +} tAniEdType; + +typedef enum eAniWepType { + eSIR_WEP_STATIC, + eSIR_WEP_DYNAMIC, +} tAniWepType; + +/* / Enum to specify whether key is used */ +/* / for TX only, RX only or both */ +typedef enum eAniKeyDirection { + eSIR_TX_ONLY, + eSIR_RX_ONLY, + eSIR_TX_RX, + eSIR_TX_DEFAULT, + eSIR_DONOT_USE_KEY_DIRECTION = SIR_MAX_ENUM_SIZE +} tAniKeyDirection; + +typedef struct sAniSSID { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH]; +} tAniSSID, *tpAniSSID; + +typedef struct sAniApName { + uint8_t length; + uint8_t name[SIR_MAC_MAX_SSID_LENGTH]; +} tAniApName, *tpAniApName; + +/* / RSN IE information */ +typedef struct sSirRSNie { + uint16_t length; + uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirRSNie, *tpSirRSNie; + +typedef struct sSirWAPIie { + uint16_t length; + uint8_t wapiIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirWAPIie, *tpSirWAPIie; +/* / Additional IE information : */ +/* / This can include WSC IE, P2P IE, and/or FTIE from upper layer. */ +/* / MAC layer transparently convey these IE info between peer STA and upper layer, */ +/* / but never requires to parse it. */ +typedef struct sSirAddie { + uint16_t length; + uint8_t addIEdata[SIR_MAC_MAX_ADD_IE_LENGTH + 2]; +} tSirAddie, *tpSirAddie; + +#ifdef FEATURE_WLAN_ESE + +/* The CCKM IE needs to be in the */ +/* Join and Reassoc Req. */ +typedef struct sSirCCKMie { + uint16_t length; + uint8_t cckmIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirCCKMie, *tpSirCCKMie; + +#endif + +/* / Definition for Encryption Keys */ +typedef struct sSirKeys { + uint8_t keyId; + uint8_t unicast; /* 0 for multicast */ + tAniKeyDirection keyDirection; + uint8_t keyRsc[WLAN_MAX_KEY_RSC_LEN]; /* Usage is unknown */ + uint8_t paeRole; /* =1 for authenticator, */ + /* =0 for supplicant */ + uint16_t keyLength; + uint8_t key[SIR_MAC_MAX_KEY_LENGTH]; +} tSirKeys, *tpSirKeys; + +/* / Definition for Keying material */ +typedef struct sSirKeyMaterial { + uint16_t length; /* This is the length of all */ + /* data that follows */ + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[1]; +} tSirKeyMaterial, *tpSirKeyMaterial; + +#define SIR_CIPHER_SEQ_CTR_SIZE 6 +/* / Definition for MIC failure indication */ +typedef struct sSirMicFailureInfo { + tSirMacAddr srcMacAddr; /* address used to compute MIC */ + tSirMacAddr taMacAddr; /* transmitter address */ + tSirMacAddr dstMacAddr; + tAniBool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + tSirMacAddr rxMacAddr; /* receive address */ + +} tSirMicFailureInfo, *tpSirMicFailureInfo; + +typedef struct sTrafStrmMetrics { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + uint8_t RoamingCount; + uint16_t RoamingDly; +} cdf_packed tTrafStrmMetrics, *tpTrafStrmMetrics; + +typedef struct sBcnReportFields { + uint8_t ChanNum; + uint8_t Spare; + uint16_t MeasDuration; + uint8_t PhyType; + uint8_t RecvSigPower; + tSirMacAddr Bssid; + uint32_t ParentTsf; + uint32_t TargetTsf[2]; + uint16_t BcnInterval; + uint16_t CapabilityInfo; +} cdf_packed tBcnReportFields, *tpBcnReportFields; + +#endif /* __ANI_SYSTEM_DEFS_H */ diff --git a/core/mac/inc/mac_init_api.h b/core/mac/inc/mac_init_api.h new file mode 100644 index 0000000000..195f9e83db --- /dev/null +++ b/core/mac/inc/mac_init_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * mac_init_api.c - Header file for mac level init functions + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +#ifndef __MAC_INIT_API_H +#define __MAC_INIT_API_H + +#include "ani_global.h" +#include "sir_types.h" + +tSirRetStatus mac_start(tHalHandle hHal, void *pHalMacStartParams); +tSirRetStatus mac_stop(tHalHandle hHal, tHalStopType stopType); +tSirRetStatus mac_open(tHalHandle *pHalHandle, tHddHandle hHdd, + tMacOpenParameters *pMacOpenParms); +tSirRetStatus mac_close(tHalHandle hHal); + +#endif /* __MAC_INIT_API_H */ diff --git a/core/mac/inc/mac_trace.h b/core/mac/inc/mac_trace.h new file mode 100644 index 0000000000..dbe01b1f3f --- /dev/null +++ b/core/mac/inc/mac_trace.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + * \file mac_trace.h + + * \brief definition for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __MAC_TRACE_H +#define __MAC_TRACE_H + +#include "ani_global.h" + +#ifdef TRACE_RECORD + +#define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) +#define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) + +#define eLOG_NODROP_MISSED_BEACON_SCENARIO 0 +#define eLOG_PROC_DEAUTH_FRAME_SCENARIO 1 + +void mac_trace(tpAniSirGlobal pMac, uint8_t code, uint16_t session, + uint32_t data); +void mac_trace_new(tpAniSirGlobal pMac, uint8_t module, uint8_t code, + uint16_t session, uint32_t data); +uint8_t *mac_trace_get_cfg_msg_string(uint16_t cfgMsg); +uint8_t *mac_trace_get_lim_msg_string(uint16_t limMsg); +uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); +uint8_t *mac_trace_get_sme_msg_string(uint16_t smeMsg); +uint8_t *mac_trace_get_info_log_string(uint16_t infoLog); +CDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe); +CDF_STATUS pe_release_global_lock(tAniSirLim *psPe); + +uint8_t *mac_trace_get_neighbour_roam_state(uint16_t neighbourRoamState); +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roamState); +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roamSubState); +uint8_t *mac_trace_get_lim_sme_state(uint16_t limState); +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlmState); +uint8_t *mac_trace_get_tl_state(uint16_t tlState); + +#endif + +#endif diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h new file mode 100644 index 0000000000..1fa77d28e8 --- /dev/null +++ b/core/mac/inc/qwlan_version.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef QWLAN_VERSION_H +#define QWLAN_VERSION_H +/*=========================================================================== + + FILE: + qwlan_version.h + + BRIEF DESCRIPTION: + WLAN Host Version file. + Build number automaticly updated by build scripts. + + ===========================================================================*/ + +#define QWLAN_VERSION_MAJOR 5 +#define QWLAN_VERSION_MINOR 0 +#define QWLAN_VERSION_PATCH 0 +#define QWLAN_VERSION_EXTRA "" +#define QWLAN_VERSION_BUILD 139 + +#define QWLAN_VERSIONSTR "5.0.0.139" + +#endif /* QWLAN_VERSION_H */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h new file mode 100644 index 0000000000..4be197e1b6 --- /dev/null +++ b/core/mac/inc/sir_api.h @@ -0,0 +1,5350 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sir_api.h contains definitions exported by + * Sirius software. + * Author: Chandra Modumudi + * Date: 04/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIR_API_H +#define __SIR_API_H + +#include "sir_types.h" +#include "sir_mac_prot_def.h" +#include "ani_system_defs.h" +#include "sir_params.h" + +#define OFFSET_OF(structType, fldName) (&((structType *)0)->fldName) + +/* / Max supported channel list */ +#define SIR_MAX_SUPPORTED_CHANNEL_LIST 96 + +#define SIR_MDIE_ELEMENT_ID 54 +#define SIR_MDIE_SIZE 3 + +/* Increase dwell time for P2P search in ms */ +#define P2P_SEARCH_DWELL_TIME_INCREASE 20 +#define P2P_SOCIAL_CHANNELS 3 + +/* Max number of channels are 165, but to access 165th element of array, + *array of 166 is required. + */ +#define SIR_MAX_24G_5G_CHANNEL_RANGE 166 +#define SIR_BCN_REPORT_MAX_BSS_DESC 4 + +#define SIR_NUM_11B_RATES 4 /* 1,2,5.5,11 */ +#define SIR_NUM_11A_RATES 8 /* 6,9,12,18,24,36,48,54 */ + +#define SIR_PM_SLEEP_MODE 0 +#define SIR_PM_ACTIVE_MODE 1 + +/* hidden SSID options */ +#define SIR_SCAN_NO_HIDDEN_SSID 0 +#define SIR_SCAN_HIDDEN_SSID_PE_DECISION 1 + +#define SIR_MAC_ADDR_LEN 6 +#define SIR_IPV4_ADDR_LEN 4 + +typedef uint8_t tSirIpv4Addr[SIR_IPV4_ADDR_LEN]; + +#define SIR_VERSION_STRING_LEN 64 +typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; + +/* Periodic Tx pattern offload feature */ +#define PERIODIC_TX_PTRN_MAX_SIZE 1536 +#define MAXNUM_PERIODIC_TX_PTRNS 6 +#define WIFI_SCANNING_MAC_OUI_LENGTH 3 + +#ifdef FEATURE_WLAN_EXTSCAN + +#define WLAN_EXTSCAN_MAX_CHANNELS 36 +#define WLAN_EXTSCAN_MAX_BUCKETS 16 +#define WLAN_EXTSCAN_MAX_HOTLIST_APS 128 +#define WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 +#define WLAN_EXTSCAN_MAX_HOTLIST_SSIDS 8 + +/* This should not be greater than MAX_NUMBER_OF_CONC_CONNECTIONS */ +#define MAX_VDEV_SUPPORTED 4 + +typedef enum { + eSIR_EXTSCAN_INVALID, + eSIR_EXTSCAN_START_RSP, + eSIR_EXTSCAN_STOP_RSP, + eSIR_EXTSCAN_CACHED_RESULTS_RSP, + eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP, + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP, + + eSIR_EXTSCAN_GET_CAPABILITIES_IND, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + eSIR_EPNO_NETWORK_FOUND_IND, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP, + eSIR_EXTSCAN_HOTLIST_SSID_MATCH_IND, + + /* Keep this last */ + eSIR_EXTSCAN_CALLBACK_TYPE_MAX, +} tSirExtScanCallbackType; + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#define SIR_KRK_KEY_LEN 16 +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_BTK_KEY_LEN 32 +#define SIR_KCK_KEY_LEN 16 +#define SIR_KEK_KEY_LEN 16 +#define SIR_REPLAY_CTR_LEN 8 + +#define SIR_UAPSD_BITOFFSET_ACVO 0 +#define SIR_UAPSD_BITOFFSET_ACVI 1 +#define SIR_UAPSD_BITOFFSET_ACBK 2 +#define SIR_UAPSD_BITOFFSET_ACBE 3 + +#define SIR_UAPSD_FLAG_ACVO (1 << SIR_UAPSD_BITOFFSET_ACVO) +#define SIR_UAPSD_FLAG_ACVI (1 << SIR_UAPSD_BITOFFSET_ACVI) +#define SIR_UAPSD_FLAG_ACBK (1 << SIR_UAPSD_BITOFFSET_ACBK) +#define SIR_UAPSD_FLAG_ACBE (1 << SIR_UAPSD_BITOFFSET_ACBE) +#define SIR_UAPSD_GET(ac, mask) (((mask) & (SIR_UAPSD_FLAG_ ## ac)) >> SIR_UAPSD_BITOFFSET_ ## ac) +#endif + +/** + * Module ID definitions. + */ +enum { + SIR_BOOT_MODULE_ID = 1, + SIR_HAL_MODULE_ID = 0x10, + SIR_CFG_MODULE_ID = 0x12, + SIR_LIM_MODULE_ID, + SIR_ARQ_MODULE_ID, + SIR_SCH_MODULE_ID, + SIR_PMM_MODULE_ID, + SIR_MNT_MODULE_ID, + SIR_DBG_MODULE_ID, + SIR_DPH_MODULE_ID, + SIR_SYS_MODULE_ID, + SIR_SMS_MODULE_ID, +}; + +#define SIR_WMA_MODULE_ID SIR_HAL_MODULE_ID + +/** + * First and last module definition for logging utility + * + * NOTE: The following definitions need to be updated if + * the above list is changed. + */ +#define SIR_FIRST_MODULE_ID SIR_HAL_MODULE_ID +#define SIR_LAST_MODULE_ID SIR_SMS_MODULE_ID + +/* Type declarations used by Firmware and Host software */ + +/* Scan type enum used in scan request */ +typedef enum eSirScanType { + eSIR_PASSIVE_SCAN, + eSIR_ACTIVE_SCAN, + eSIR_BEACON_TABLE, +} tSirScanType; + +/* / Result codes Firmware return to Host SW */ +typedef enum eSirResultCodes { + eSIR_SME_SUCCESS, + eSIR_LOGP_EXCEPTION, + eSIR_SME_INVALID_PARAMETERS = 500, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + eSIR_SME_RESOURCES_UNAVAILABLE, + /* Unable to find a BssDescription */ + eSIR_SME_SCAN_FAILED, + /* matching requested scan criteria */ + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED, + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE, + eSIR_SME_REFUSED, + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA, + eSIR_SME_JOIN_TIMEOUT_RESULT_CODE, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED, + eSIR_SME_AUTH_REFUSED, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + eSIR_SME_NO_KEY_MAPPING_KEY_FOR_PEER, + eSIR_SME_ASSOC_REFUSED, + eSIR_SME_REASSOC_REFUSED, + /* Recvd Deauth while join/pre-auth */ + eSIR_SME_DEAUTH_WHILE_JOIN, + eSIR_SME_STA_NOT_AUTHENTICATED, + eSIR_SME_STA_NOT_ASSOCIATED, + eSIR_SME_ALREADY_JOINED_A_BSS, + /* Given in SME_SCAN_RSP msg */ + eSIR_SME_MORE_SCAN_RESULTS_FOLLOW, + /* that more SME_SCAN_RSP */ + /* messages are following. */ + /* SME_SCAN_RSP message with */ + /* eSIR_SME_SUCCESS status */ + /* code is the last one. */ + /* Sent in SME_JOIN/REASSOC_RSP */ + eSIR_SME_INVALID_ASSOC_RSP_RXED, + /* messages upon receiving */ + /* invalid Re/Assoc Rsp frame. */ + /* STOP BSS triggered by MIC failures: MAC software to + * disassoc all stations + */ + eSIR_SME_MIC_COUNTER_MEASURES, + /* with MIC_FAILURE reason code and perform the stop bss operation */ + /* didn't get rsp from peer within timeout interval */ + eSIR_SME_ADDTS_RSP_TIMEOUT, + /* didn't get success rsp from HAL */ + eSIR_SME_ADDTS_RSP_FAILED, + /* failed to send ch switch act frm */ + eSIR_SME_CHANNEL_SWITCH_FAIL, + eSIR_SME_INVALID_STATE, + /* SIR_HAL_SIR_HAL_INIT_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_INIT_FAILED, + /* SIR_HAL_END_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_END_FAILED, + /* SIR_HAL_FINISH_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_FINISH_FAILED, + /* Failed to send a message to HAL */ + eSIR_SME_HAL_SEND_MESSAGE_FAIL, + /* Failed to stop the bss */ + eSIR_SME_STOP_BSS_FAILURE, + eSIR_SME_WOWL_ENTER_REQ_FAILED, + eSIR_SME_WOWL_EXIT_REQ_FAILED, +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + eSIR_SME_FT_REASSOC_FAILURE, +#endif + eSIR_SME_SEND_ACTION_FAIL, + eSIR_SME_DEAUTH_STATUS, + eSIR_PNO_SCAN_SUCCESS, + eSIR_DONOT_USE_RESULT_CODE = SIR_MAX_ENUM_SIZE +} tSirResultCodes; + +/* each station added has a rate mode which specifies the sta attributes */ +typedef enum eStaRateMode { + eSTA_TAURUS = 0, + eSTA_TITAN, + eSTA_POLARIS, + eSTA_11b, + eSTA_11bg, + eSTA_11a, + eSTA_11n, +#ifdef WLAN_FEATURE_11AC + eSTA_11ac, +#endif + eSTA_INVALID_RATE_MODE +} tStaRateMode, *tpStaRateMode; + +/* + * although in tSirSupportedRates each IE is 16bit but PE only passes IEs in 8 + * bits with MSB=1 for basic rates. change the mask for bit0-7 only so HAL gets + * correct basic rates for setting response rates. + */ +#define IERATE_BASICRATE_MASK 0x80 +#define IERATE_RATE_MASK 0x7f +#define IERATE_IS_BASICRATE(x) ((x) & IERATE_BASICRATE_MASK) + +typedef struct sSirSupportedRates { + /* + * For Self STA Entry: this represents Self Mode. + * For Peer Stations, this represents the mode of the peer. + * On Station: + * --this mode is updated when PE adds the Self Entry. + * -- OR when PE sends 'ADD_BSS' message and station context in BSS is + * used to indicate the mode of the AP. + * ON AP: + * -- this mode is updated when PE sends 'ADD_BSS' and Sta entry for + * that BSS is used to indicate the self mode of the AP. + * -- OR when a station is associated, PE sends 'ADD_STA' message with + * this mode updated. + */ + + tStaRateMode opRateMode; + /* + * 11b, 11a and aniLegacyRates are IE rates which gives rate in unit + * of 500Kbps + */ + uint16_t llbRates[SIR_NUM_11B_RATES]; + uint16_t llaRates[SIR_NUM_11A_RATES]; + /* + * 0-76 bits used, remaining reserved + * bits 0-15 and 32 should be set. + */ + uint8_t supportedMCSSet[SIR_MAC_MAX_SUPPORTED_MCS_SET]; + + /* + * RX Highest Supported Data Rate defines the highest data + * rate that the STA is able to receive, in unites of 1Mbps. + * This value is derived from "Supported MCS Set field" inside + * the HT capability element. + */ + uint16_t rxHighestDataRate; + +#ifdef WLAN_FEATURE_11AC + /*Indicates the Maximum MCS that can be received for each number + of spacial streams */ + uint16_t vhtRxMCSMap; + /*Indicate the highest VHT data rate that the STA is able to receive */ + uint16_t vhtRxHighestDataRate; + /*Indicates the Maximum MCS that can be transmitted for each number + of spacial streams */ + uint16_t vhtTxMCSMap; + /*Indicate the highest VHT data rate that the STA is able to transmit */ + uint16_t vhtTxHighestDataRate; +#endif +} tSirSupportedRates, *tpSirSupportedRates; + +typedef enum eSirRFBand { + SIR_BAND_UNKNOWN, + SIR_BAND_2_4_GHZ, + SIR_BAND_5_GHZ, +} tSirRFBand; + +typedef struct sSirRemainOnChnReq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirMacAddr selfMacAddr; + uint8_t chnNum; + uint8_t phyMode; + uint32_t duration; + uint8_t isProbeRequestAllowed; + uint32_t scan_id; + uint8_t probeRspIe[1]; +} tSirRemainOnChnReq, *tpSirRemainOnChnReq; + +/** + * struct sir_roc_rsp - Structure to store the remain on channel response + * @message_type: Message Type + * @length: Message Length + * @session_id: SME session Id + * @scan_id : scan identifier + * @status: result status + */ +struct sir_roc_rsp { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint32_t scan_id; + tSirResultCodes status; +}; + +typedef struct sSirRegisterMgmtFrame { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + bool registerFrame; + uint16_t frameType; + uint16_t matchLen; + uint8_t matchData[1]; +} tSirRegisterMgmtFrame, *tpSirRegisterMgmtFrame; + +/* / Generic type for sending a response message */ +/* / with result code to host software */ +typedef struct sSirSmeRsp { + uint16_t messageType; /* eWNI_SME_*_RSP */ + uint16_t length; + uint8_t sessionId; /* To support BT-AMP */ + uint16_t transactionId; /* To support BT-AMP */ + tSirResultCodes statusCode; +} tSirSmeRsp, *tpSirSmeRsp; + +/* / Definition for indicating all modules ready on STA */ +typedef struct sSirSmeReadyReq { + uint16_t messageType; /* eWNI_SME_SYS_READY_IND */ + uint16_t length; + uint16_t transactionId; + void *add_bssdescr_cb; +} tSirSmeReadyReq, *tpSirSmeReadyReq; + +/** + * struct sir_hw_mode - Format of set HW mode + * @hw_mode_index: Index of HW mode to be set + * @set_hw_mode_cb: HDD set HW mode callback + */ +struct sir_hw_mode { + uint32_t hw_mode_index; + void *set_hw_mode_cb; +}; + +/** + * struct s_sir_set_hw_mode - Set HW mode request + * @messageType: Message type + * @length: Length of the message + * @set_hw: Params containing the HW mode index and callback + */ +struct s_sir_set_hw_mode { + uint16_t messageType; + uint16_t length; + struct sir_hw_mode set_hw; +}; + +/** + * struct sir_dual_mac_config - Dual MAC configuration + * @scan_config: Scan configuration + * @fw_mode_config: FW mode configuration + * @set_dual_mac_cb: Callback function to be executed on response to the command + */ +struct sir_dual_mac_config { + uint32_t scan_config; + uint32_t fw_mode_config; + void *set_dual_mac_cb; +}; + +/** + * struct sir_set_dual_mac_cfg - Set Dual mac config request + * @message_type: Message type + * @length: Length of the message + * @set_dual_mac: Params containing the dual mac config and callback + */ +struct sir_set_dual_mac_cfg { + uint16_t message_type; + uint16_t length; + struct sir_dual_mac_config set_dual_mac; +}; + +/* / BSS type enum used in while scanning/joining etc */ +typedef enum eSirBssType { + eSIR_INFRASTRUCTURE_MODE, + eSIR_INFRA_AP_MODE, /* Added for softAP support */ + eSIR_IBSS_MODE, + eSIR_BTAMP_STA_MODE, /* Added for BT-AMP support */ + eSIR_BTAMP_AP_MODE, /* Added for BT-AMP support */ + eSIR_AUTO_MODE, + eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE +} tSirBssType; + +/* / Power Capability info used in 11H */ +typedef struct sSirMacPowerCapInfo { + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapInfo, *tpSirMacPowerCapInfo; + +/* / Supported Channel info used in 11H */ +typedef struct sSirSupChnl { + uint8_t numChnl; + uint8_t channelList[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +} tSirSupChnl, *tpSirSupChnl; + +typedef enum eSirNwType { + eSIR_11A_NW_TYPE, + eSIR_11B_NW_TYPE, + eSIR_11G_NW_TYPE, + eSIR_11N_NW_TYPE, +#ifdef WLAN_FEATURE_11AC + eSIR_11AC_NW_TYPE, +#endif + eSIR_DONOT_USE_NW_TYPE = SIR_MAX_ENUM_SIZE +} tSirNwType; + +/* / Definition for new iBss peer info */ +typedef struct sSirNewIbssPeerInfo { + tSirMacAddr peerAddr; + uint16_t aid; +} tSirNewIbssPeerInfo, *tpSirNewIbssPeerInfo; + +/* HT configuration values */ +typedef struct sSirHtConfig { + /* Enable/Disable receiving LDPC coded packets */ + uint32_t ht_rx_ldpc:1; + /* Enable/Disable TX STBC */ + uint32_t ht_tx_stbc:1; + /* Enable/Disable RX STBC */ + uint32_t ht_rx_stbc:2; + /* Enable/Disable SGI */ + uint32_t ht_sgi:1; + uint32_t unused:27; +} cdf_packed tSirHTConfig, *tpSirHTConfig; + +typedef struct sSirAddIeParams { + uint16_t probeRespDataLen; + uint8_t *probeRespData_buff; + uint16_t assocRespDataLen; + uint8_t *assocRespData_buff; + uint16_t probeRespBCNDataLen; + uint8_t *probeRespBCNData_buff; +} tSirAddIeParams, *tpSirAddIeParams; + +/* / Definition for kick starting BSS */ +/* / ---> MAC */ +/** + * Usage of ssId, numSSID & ssIdList: + * --------------------------------- + * 1. ssId.length of zero indicates that Broadcast/Suppress SSID + * feature is enabled. + * 2. If ssId.length is zero, MAC SW will advertise NULL SSID + * and interpret the SSID list from numSSID & ssIdList. + * 3. If ssId.length is non-zero, MAC SW will advertise the SSID + * specified in the ssId field and it is expected that + * application will set numSSID to one (only one SSID present + * in the list) and SSID in the list is same as ssId field. + * 4. Application will always set numSSID >= 1. + */ +/* ***** NOTE: Please make sure all codes are updated if inserting field into + * this structure..********** */ +typedef struct sSirSmeStartBssReq { + uint16_t messageType; /* eWNI_SME_START_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP Support */ + uint16_t transactionId; /* Added for BT-AMP Support */ + tSirMacAddr bssId; /* Added for BT-AMP Support */ + tSirMacAddr selfMacAddr; /* Added for BT-AMP Support */ + uint16_t beaconInterval; /* Added for BT-AMP Support */ + uint8_t dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + tSirBssType bssType; + tSirMacSSid ssId; + uint8_t channelId; + ePhyChanBondState cbMode; + uint8_t vht_channel_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + uint8_t sec_ch_offset; + + uint8_t privacy; + uint8_t apUapsdEnable; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + uint16_t ht_capab; + tAniAuthType authType; + uint32_t dtimPeriod; + uint8_t wps_state; + uint8_t isCoalesingInIBSSAllowed; /* Coalesing on/off knob */ + tCDF_CON_MODE bssPersona; + + uint8_t txLdpcIniFeatureEnabled; + + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* Beacon and Probe */ + /* Response frames */ + tSirNwType nwType; /* Indicates 11a/b/g */ + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirHTConfig htConfig; + +#ifdef WLAN_FEATURE_11W + bool pmfCapable; + bool pmfRequired; +#endif + + tSirAddIeParams addIeParams; + + bool obssEnabled; + uint8_t sap_dot11mc; + +} tSirSmeStartBssReq, *tpSirSmeStartBssReq; + +#define GET_IE_LEN_IN_BSS(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription,\ + ieFields))) + +#define WSCIE_PROBE_RSP_LEN (317 + 2) + +typedef struct sSirBssDescription { + /* offset of the ieFields from bssId. */ + uint16_t length; + tSirMacAddr bssId; + v_TIME_t scanSysTimeMsec; + uint32_t timeStamp[2]; + uint16_t beaconInterval; + uint16_t capabilityInfo; + tSirNwType nwType; /* Indicates 11a/b/g */ + uint8_t reserved_padding0; + int8_t rssi; + int8_t sinr; + /* channelId what peer sent in beacon/probersp. */ + uint8_t channelId; + /* channelId on which we are parked at. */ + /* used only in scan case. */ + uint8_t channelIdSelf; + uint8_t sSirBssDescriptionRsvd[3]; + /* base on a tick count. It is a time stamp, not a relative time. */ + uint32_t nReceivedTime; +#if defined WLAN_FEATURE_VOWIFI + uint32_t parentTSF; + uint32_t startTSF[2]; +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + uint8_t mdiePresent; + /* MDIE for 11r, picked from the beacons */ + uint8_t mdie[SIR_MDIE_SIZE]; +#endif +#ifdef FEATURE_WLAN_ESE + uint16_t QBSSLoad_present; + uint16_t QBSSLoad_avail; + /* To achieve 8-byte alignment with ESE enabled */ + uint32_t reservedPadding5; +#endif + /* Please keep the structure 4 bytes aligned above the ieFields */ + + /* whether it is from a probe rsp */ + uint8_t fProbeRsp; + uint8_t reservedPadding1; + uint8_t reservedPadding2; + uint8_t reservedPadding3; + uint32_t WscIeLen; + uint8_t WscIeProbeRsp[WSCIE_PROBE_RSP_LEN]; + uint8_t reservedPadding4; + uint32_t tsf_delta; + + uint32_t ieFields[1]; +} tSirBssDescription, *tpSirBssDescription; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct sSirSmeHTProfile { + uint8_t dot11mode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; +#ifdef WLAN_FEATURE_11AC + uint8_t vhtCapability; + uint8_t vhtTxChannelWidthSet; + uint8_t apCenterChan; + uint8_t apChanWidth; +#endif +} tSirSmeHTProfile; +#endif +/* / Definition for response message to previously */ +/* / issued start BSS request */ +/* / MAC ---> */ +typedef struct sSirSmeStartBssRsp { + uint16_t messageType; /* eWNI_SME_START_BSS_RSP */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; /* transaction ID for cmd */ + tSirResultCodes statusCode; + tSirBssType bssType; /* Add new type for WDS mode */ + uint16_t beaconInterval; /* Beacon Interval for both type */ + uint32_t staId; /* Staion ID for Self */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + tSirBssDescription bssDescription; /* Peer BSS description */ +} tSirSmeStartBssRsp, *tpSirSmeStartBssRsp; + +typedef struct sSirChannelList { + uint8_t numChannels; + uint8_t channelNumber[SIR_ESE_MAX_MEAS_IE_REQS]; +} tSirChannelList, *tpSirChannelList; + +typedef struct sSirDFSChannelList { + uint32_t timeStamp[SIR_MAX_24G_5G_CHANNEL_RANGE]; + +} tSirDFSChannelList, *tpSirDFSChannelList; + +#ifdef FEATURE_WLAN_ESE +typedef struct sTspecInfo { + uint8_t valid; + tSirMacTspecIE tspec; +} tTspecInfo; + +#define SIR_ESE_MAX_TSPEC_IES 4 +typedef struct sESETspecTspecInfo { + uint8_t numTspecs; + tTspecInfo tspec[SIR_ESE_MAX_TSPEC_IES]; +} tESETspecInfo; +#endif + +/* / Two Background Scan mode */ +typedef enum eSirBackgroundScanMode { + eSIR_ROAMING_SCAN = 2, +} tSirBackgroundScanMode; + +/* / Two types of traffic check */ +typedef enum eSirLinkTrafficCheck { + eSIR_DONT_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 0, + eSIR_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 1, + eSIR_CHECK_ROAMING_SCAN = 2, +} tSirLinkTrafficCheck; + +#define SIR_BG_SCAN_RETURN_CACHED_RESULTS 0x0 +#define SIR_BG_SCAN_PURGE_RESUTLS 0x80 +#define SIR_BG_SCAN_RETURN_FRESH_RESULTS 0x01 +#define SIR_SCAN_MAX_NUM_SSID 0x0A +#define SIR_BG_SCAN_RETURN_LFR_CACHED_RESULTS 0x02 +#define SIR_BG_SCAN_PURGE_LFR_RESULTS 0x40 + +/* / Definition for scan request */ +typedef struct sSirSmeScanReq { + uint16_t messageType; /* eWNI_SME_SCAN_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + tSirMacAddr selfMacAddr; /* Added For BT-AMP Support */ + tSirBssType bssType; + uint8_t dot11mode; + tSirScanType scanType; + uint32_t scan_id; + /** + * minChannelTime. Not used if scanType is passive. + * 0x0 - Dont Use min channel timer. Only max channel timeout will used. + * 11k measurements set this to 0 to user only single duration for scan. + * - Timeout value used for min channel timeout. + */ + uint32_t minChannelTime; + /** + * maxChannelTime. + * 0x0 - Invalid. In case of active scan. + * In case of passive scan, MAX( maxChannelTime, + * WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME) is used. + */ + uint32_t maxChannelTime; + /** + * returnAfterFirstMatch can take following values: + * 0x00 - Return SCAN_RSP message after complete channel scan + * 0x01 - Return SCAN_RSP message after collecting BSS description + * that matches scan criteria. + * 0xC0 - Return after collecting first 11d IE from 2.4 GHz & + * 5 GHz band channels + * 0x80 - Return after collecting first 11d IE from 5 GHz band + * channels + * 0x40 - Return after collecting first 11d IE from 2.4 GHz + * band channels + * + * Values of 0xC0, 0x80 & 0x40 are to be used by + * Roaming/application when 11d is enabled. + */ + /* in units of milliseconds, ignored when not connected */ + uint32_t restTime; + uint8_t returnAfterFirstMatch; + + /** + * returnUniqueResults can take following values: + * 0 - Collect & report all received BSS descriptions from same BSS. + * 1 - Collect & report unique BSS description from same BSS. + */ + uint8_t returnUniqueResults; + + /** + * returnFreshResults can take following values: + * 0x00 - Return background scan results. + * 0x80 - Return & purge background scan results + * 0x01 - Trigger fresh scan instead of returning background scan + * results. + * 0x81 - Trigger fresh scan instead of returning background scan + * results and purge background scan results. + */ + uint8_t returnFreshResults; + + /* backgroundScanMode can take following values: + * 0x0 - agressive scan + * 0x1 - normal scan where HAL will check for link traffic + * prior to proceeding with the scan + */ + tSirBackgroundScanMode backgroundScanMode; + + uint8_t hiddenSsid; + + /* Number of SSIDs to scan */ + uint8_t numSsid; + + /* channelList has to be the last member of this structure. Check + * tSirChannelList for the reason. This MUST be the last field of the + * structure + */ + + bool p2pSearch; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + + /* channelList MUST be the last field of this structure */ + tSirChannelList channelList; + /*----------------------------- + tSirSmeScanReq.... + ----------------------------- + uIEFiledLen + ----------------------------- + uIEFiledOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEFiled + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tSirSmeScanReq, *tpSirSmeScanReq; + +typedef struct sSirSmeScanAbortReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint32_t scan_id; +} tSirSmeScanAbortReq, *tpSirSmeScanAbortReq; + +typedef struct sSirSmeScanChanReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint16_t transcationId; +} tSirSmeGetScanChanReq, *tpSirSmeGetScanChanReq; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 280 +#endif +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +typedef struct sSirOemDataReq { + uint16_t messageType; /* eWNI_SME_OEM_DATA_REQ */ + uint16_t messageLen; + tSirMacAddr selfMacAddr; + uint8_t oemDataReq[OEM_DATA_REQ_SIZE]; +} tSirOemDataReq, *tpSirOemDataReq; + +typedef struct sSirOemDataRsp { + uint16_t messageType; + uint16_t length; + uint8_t oemDataRsp[OEM_DATA_RSP_SIZE]; +} tSirOemDataRsp, *tpSirOemDataRsp; + +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/* / Definition for response message to previously issued scan request */ +typedef struct sSirSmeScanRsp { + uint16_t messageType; /* eWNI_SME_SCAN_RSP */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + uint16_t transcationId; + uint32_t scan_id; +} tSirSmeScanRsp, *tpSirSmeScanRsp; + +/* / Definition for join request */ +/* / ---> MAC */ +/* / WARNING! If you add a field in JOIN REQ. */ +/* / Make sure to add it in REASSOC REQ */ +/* / The Serdes function is the same and its */ +/* / shared with REASSOC. So if we add a field */ +/* here and dont add it in REASSOC REQ. It will BREAK!!! REASSOC. */ +typedef struct sSirSmeJoinReq { + uint16_t messageType; /* eWNI_SME_JOIN_REQ */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; + tSirMacSSid ssId; + tSirMacAddr selfMacAddr; /* self Mac address */ + tSirBssType bsstype; /* add new type for BT-AMP STA and AP Modules */ + uint8_t dot11mode; /* to support BT-AMP */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + tCDF_CON_MODE staPersona; /* Persona */ + ePhyChanBondState cbMode; /* Pass CB mode value in Join. */ + + /*This contains the UAPSD Flag for all 4 AC + * B0: AC_VO UAPSD FLAG + * B1: AC_VI UAPSD FLAG + * B2: AC_BK UAPSD FLAG + * B3: AC_BE UASPD FLAG + */ + uint8_t uapsdPerAcBitmask; + + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* (Re) Association Request */ +#ifdef FEATURE_WLAN_ESE + /* CCMK IE to be included as handler for join and reassoc is */ + tSirCCKMie cckmIE; + /* the same. The join will never carry cckm, but will be set to */ + /* 0. */ +#endif + + tSirAddie addIEScan; /* Additional IE to be sent in */ + /* (unicast) Probe Request at the time of join */ + + tSirAddie addIEAssoc; /* Additional IE to be sent in */ + /* (Re) Association Request */ + + tAniEdType UCEncryptionType; + + tAniEdType MCEncryptionType; + +#ifdef WLAN_FEATURE_11W + tAniEdType MgmtEncryptionType; +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + tAniBool is11Rconnection; +#endif +#ifdef FEATURE_WLAN_ESE + tAniBool isESEFeatureIniEnabled; + tAniBool isESEconnection; + tESETspecInfo eseTspecInfo; +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + tAniBool isFastTransitionEnabled; +#endif +#ifdef FEATURE_WLAN_LFR + tAniBool isFastRoamIniFeatureEnabled; +#endif + + uint8_t txLdpcIniFeatureEnabled; + tSirHTConfig htConfig; +#ifdef WLAN_FEATURE_11AC + uint8_t txBFIniFeatureEnabled; + uint8_t txBFCsnValue; + uint8_t txMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; +#endif + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + + uint8_t isAmsduSupportInAMPDU; + tAniBool isWMEenabled; + tAniBool isQosEnabled; + tAniBool isOSENConnection; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + tSirBssDescription bssDescription; + +} tSirSmeJoinReq, *tpSirSmeJoinReq; + +/* / Definition for reponse message to previously issued join request */ +/* / MAC ---> */ +typedef struct sSirSmeJoinRsp { + uint16_t messageType; /* eWNI_SME_JOIN_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tAniAuthType authType; + uint32_t vht_channel_width; + /* It holds reasonCode when join fails due to deauth/disassoc frame. + * Otherwise it holds status code. + */ + uint16_t protStatusCode; + uint16_t aid; + uint32_t beaconLength; + uint32_t assocReqLength; + uint32_t assocRspLength; +#ifdef WLAN_FEATURE_VOWIFI_11R + uint32_t parsedRicRspLen; +#endif +#ifdef FEATURE_WLAN_ESE + uint32_t tspecIeLen; +#endif + uint32_t staId; /* Station ID for peer */ + + /* The DPU signatures will be sent eventually to TL to help it determine + * the association to which a packet belongs to + * Unicast DPU signature + */ + uint8_t ucastSig; + + /*Broadcast DPU signature */ + uint8_t bcastSig; + + /*Timing measurement capability */ + uint8_t timingMeasCap; + +#ifdef FEATURE_WLAN_TDLS + /* TDLS prohibited and TDLS channel switch prohibited are set as + * per ExtCap IE in received assoc/re-assoc response from AP + */ + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + uint8_t frames[1]; +} tSirSmeJoinRsp, *tpSirSmeJoinRsp; + +/* / probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbereq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirMacAddr peerMacAddr; + uint16_t devicePasswdId; +} tSirSmeProbeReq, *tpSirSmeProbeReq; + +typedef struct sSirSmeChanInfo { + uint8_t chan_id; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; +} tSirSmeChanInfo, *tpSirSmeChanInfo; +/* / Definition for Association indication from peer */ +/* / MAC ---> */ +typedef struct sSirSmeAssocInd { + uint16_t messageType; /* eWNI_SME_ASSOC_IND */ + uint16_t length; + uint8_t sessionId; + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr bssId; /* Self BSSID */ + uint16_t staId; /* Station ID for peer */ + uint8_t uniSig; /* DPU signature for unicast packets */ + uint8_t bcastSig; /* DPU signature for broadcast packets */ + tAniAuthType authType; + tAniSSID ssId; /* SSID used by STA to associate */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + /* Additional IE received from peer, which possibly include + * WSC IE and/or P2P IE + */ + tSirAddie addIE; + + /* powerCap & supportedChannels are present only when */ + /* spectrumMgtIndicator flag is set */ + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + tAniBool wmmEnabledSta; /* if present - STA is WMM enabled */ + tAniBool reassocReq; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + + /* Timing measurement capability */ + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; +} tSirSmeAssocInd, *tpSirSmeAssocInd; + +/* / Definition for Association confirm */ +/* / ---> MAC */ +typedef struct sSirSmeAssocCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + tSirResultCodes statusCode; + tSirMacAddr bssId; /* Self BSSID */ + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr alternateBssId; + uint8_t alternateChannelId; +} tSirSmeAssocCnf, *tpSirSmeAssocCnf; + +/* / Enum definition for Wireless medium status change codes */ +typedef enum eSirSmeStatusChangeCode { + eSIR_SME_DEAUTH_FROM_PEER, + eSIR_SME_DISASSOC_FROM_PEER, + eSIR_SME_LOST_LINK_WITH_PEER, + eSIR_SME_CHANNEL_SWITCH, + eSIR_SME_JOINED_NEW_BSS, + eSIR_SME_LEAVING_BSS, + eSIR_SME_IBSS_ACTIVE, + eSIR_SME_IBSS_INACTIVE, + eSIR_SME_IBSS_PEER_DEPARTED, + eSIR_SME_RADAR_DETECTED, + eSIR_SME_IBSS_NEW_PEER, + eSIR_SME_AP_CAPS_CHANGED, +} tSirSmeStatusChangeCode; + +typedef struct sSirSmeNewBssInfo { + tSirMacAddr bssId; + uint8_t channelNumber; + uint8_t reserved; + tSirMacSSid ssId; +} tSirSmeNewBssInfo, *tpSirSmeNewBssInfo; + +typedef struct sSirSmeApNewCaps { + uint16_t capabilityInfo; + tSirMacAddr bssId; + uint8_t channelId; + uint8_t reserved[3]; + tSirMacSSid ssId; +} tSirSmeApNewCaps, *tpSirSmeApNewCaps; + +/** + * Table below indicates what information is passed for each of + * the Wireless Media status change notifications: + * + * Status Change code Status change info + * ---------------------------------------------------------------------- + * eSIR_SME_DEAUTH_FROM_PEER Reason code received in DEAUTH frame + * eSIR_SME_DISASSOC_FROM_PEER Reason code received in DISASSOC frame + * eSIR_SME_LOST_LINK_WITH_PEER None + * eSIR_SME_CHANNEL_SWITCH New channel number + * eSIR_SME_JOINED_NEW_BSS BSSID, SSID and channel number + * eSIR_SME_LEAVING_BSS None + * eSIR_SME_IBSS_ACTIVE Indicates that another STA joined + * IBSS apart from this STA that + * started IBSS + * eSIR_SME_IBSS_INACTIVE Indicates that only this STA is left + * in IBSS + * eSIR_SME_RADAR_DETECTED Indicates that radar is detected + * eSIR_SME_IBSS_NEW_PEER Indicates that a new peer is detected + * eSIR_SME_AP_CAPS_CHANGED Indicates that capabilities of the AP + * that STA is currently associated with + * have changed. + */ + +/* / Definition for Wireless medium status change notification */ +typedef struct sSirSmeWmStatusChangeNtf { + uint16_t messageType; /* eWNI_SME_WM_STATUS_CHANGE_NTF */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirSmeStatusChangeCode statusChangeCode; + tSirMacAddr bssId; /* Self BSSID */ + union { + uint16_t deAuthReasonCode; /* eSIR_SME_DEAUTH_FROM_PEER */ + /* eSIR_SME_DISASSOC_FROM_PEER */ + uint16_t disassocReasonCode; + /* none for eSIR_SME_LOST_LINK_WITH_PEER */ + uint8_t newChannelId; /* eSIR_SME_CHANNEL_SWITCH */ + tSirSmeNewBssInfo newBssInfo; /* eSIR_SME_JOINED_NEW_BSS */ + /* none for eSIR_SME_LEAVING_BSS */ + /* none for eSIR_SME_IBSS_ACTIVE */ + /* none for eSIR_SME_IBSS_INACTIVE */ + /* eSIR_SME_IBSS_NEW_PEER */ + tSirNewIbssPeerInfo newIbssPeerInfo; + tSirSmeApNewCaps apNewCaps; /* eSIR_SME_AP_CAPS_CHANGED */ + } statusChangeInfo; +} tSirSmeWmStatusChangeNtf, *tpSirSmeWmStatusChangeNtf; + +/* Definition for Disassociation request */ +typedef struct sSirSmeDisassocReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; /* Peer BSSID */ + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + /* This flag tells LIM whether to send the disassoc OTA or not */ + /* This will be set in while handing off from one AP to other */ + uint8_t doNotSendOverTheAir; +} cdf_packed tSirSmeDisassocReq, *tpSirSmeDisassocReq; + +/* / Definition for Tkip countermeasures request */ +typedef struct sSirSmeTkipCntrMeasReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; /* Peer BSSID */ + bool bEnable; /* Start/stop countermeasures */ +} cdf_packed tSirSmeTkipCntrMeasReq, *tpSirSmeTkipCntrMeasReq; + +typedef struct sAni64BitCounters { + uint32_t Hi; + uint32_t Lo; +} tAni64BitCounters, *tpAni64BitCounters; + +typedef struct sAniSecurityStat { + tAni64BitCounters txBlks; + tAni64BitCounters rxBlks; + tAni64BitCounters formatErrorCnt; + tAni64BitCounters decryptErr; + tAni64BitCounters protExclCnt; + tAni64BitCounters unDecryptableCnt; + tAni64BitCounters decryptOkCnt; + +} tAniSecurityStat, *tpAniSecurityStat; + +typedef struct sAniTxRxStats { + tAni64BitCounters txFrames; + tAni64BitCounters rxFrames; + tAni64BitCounters nRcvBytes; + tAni64BitCounters nXmitBytes; + +} tAniTxRxStats, *tpAniTxRxStats; + +typedef struct sAniSecStats { + tAniSecurityStat aes; + tAni64BitCounters aesReplays; + tAniSecurityStat tkip; + tAni64BitCounters tkipReplays; + tAni64BitCounters tkipMicError; + + tAniSecurityStat wep; +#if defined(FEATURE_WLAN_WAPI) && !defined(LIBRA_WAPI_SUPPORT) + tAniSecurityStat wpi; + tAni64BitCounters wpiReplays; + tAni64BitCounters wpiMicError; +#endif +} tAniSecStats, *tpAniSecStats; + +#define SIR_MAX_RX_CHAINS 3 + +typedef struct sAniStaStatStruct { + /* following statistic elements till expandPktRxCntLo are not filled + * with valid data. These are kept as it is, since WSM is using this + * structure. These elements can be removed whenever WSM is updated. + * Phystats is used to hold phystats from BD. + */ + uint32_t sentAesBlksUcastHi; + uint32_t sentAesBlksUcastLo; + uint32_t recvAesBlksUcastHi; + uint32_t recvAesBlksUcastLo; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; + uint32_t singleRetryPkts; + uint32_t failedTxPkts; + uint32_t ackTimeouts; + uint32_t multiRetryPkts; + uint32_t fragTxCntsHi; + uint32_t fragTxCntsLo; + uint32_t transmittedPktsHi; + uint32_t transmittedPktsLo; + uint32_t phyStatHi; /* These are used to fill in the phystats. */ + uint32_t phyStatLo; /* This is only for private use. */ + + uint32_t uplinkRssi; + uint32_t uplinkSinr; + uint32_t uplinkRate; + uint32_t downlinkRssi; + uint32_t downlinkSinr; + uint32_t downlinkRate; + uint32_t nRcvBytes; + uint32_t nXmitBytes; + + /* + * Following elements are valid and filled in correctly. They have + * valid values. + */ + + /* Unicast frames and bytes. */ + tAniTxRxStats ucStats; + + /* Broadcast frames and bytes. */ + tAniTxRxStats bcStats; + + /* Multicast frames and bytes. */ + tAniTxRxStats mcStats; + + uint32_t currentTxRate; + uint32_t currentRxRate; /* Rate in 100Kbps */ + + uint32_t maxTxRate; + uint32_t maxRxRate; + + int8_t rssi[SIR_MAX_RX_CHAINS]; + + tAniSecStats securityStats; + + uint8_t currentRxRateIdx; /* This the softmac rate Index. */ + uint8_t currentTxRateIdx; + +} tAniStaStatStruct, *tpAniStaStatStruct; + +typedef enum sPacketType { + ePACKET_TYPE_UNKNOWN, + ePACKET_TYPE_11A, + ePACKET_TYPE_11G, + ePACKET_TYPE_11B, + ePACKET_TYPE_11N +} tPacketType, *tpPacketType; + +/* / Definition for Disassociation response */ +typedef struct sSirSmeDisassocRsp { + uint16_t messageType; /* eWNI_SME_DISASSOC_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tSirMacAddr peerMacAddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; +} cdf_packed tSirSmeDisassocRsp, *tpSirSmeDisassocRsp; + +/* / Definition for Disassociation indication from peer */ +typedef struct sSirSmeDisassocInd { + uint16_t messageType; /* eWNI_SME_DISASSOC_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ + uint16_t transactionId; /* Transaction Identifier with PE */ + tSirResultCodes statusCode; + tSirMacAddr bssId; + tSirMacAddr peerMacAddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; + uint32_t reasonCode; +} tSirSmeDisassocInd, *tpSirSmeDisassocInd; + +/* / Definition for Disassociation confirm */ +/* / MAC ---> */ +typedef struct sSirSmeDisassocCnf { + uint16_t messageType; /* eWNI_SME_DISASSOC_CNF */ + uint16_t length; + tSirResultCodes statusCode; + tSirMacAddr bssId; + tSirMacAddr peerMacAddr; +} tSirSmeDisassocCnf, *tpSirSmeDisassocCnf, + tSirSmeDeauthCnf, *tpSirSmeDeauthCnf; + +/* / Definition for Deauthetication request */ +typedef struct sSirSmeDeauthReq { + uint16_t messageType; /* eWNI_SME_DEAUTH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; /* AP BSSID */ + tSirMacAddr peerMacAddr; + uint16_t reasonCode; +} tSirSmeDeauthReq, *tpSirSmeDeauthReq; + +/* / Definition for Deauthetication response */ +typedef struct sSirSmeDeauthRsp { + uint16_t messageType; /* eWNI_SME_DEAUTH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tSirMacAddr peerMacAddr; +} tSirSmeDeauthRsp, *tpSirSmeDeauthRsp; + +/* / Definition for Deauthetication indication from peer */ +typedef struct sSirSmeDeauthInd { + uint16_t messageType; /* eWNI_SME_DEAUTH_IND */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP */ + uint16_t transactionId; /* Added for BT-AMP */ + tSirResultCodes statusCode; + tSirMacAddr bssId; /* AP BSSID */ + tSirMacAddr peerMacAddr; + + uint16_t staId; + uint32_t reasonCode; +} tSirSmeDeauthInd, *tpSirSmeDeauthInd; + +/* / Definition for stop BSS request message */ +typedef struct sSirSmeStopBssReq { + uint16_t messageType; /* eWNI_SME_STOP_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* tranSaction ID for cmd */ + tSirResultCodes reasonCode; + tSirMacAddr bssId; /* Self BSSID */ +} tSirSmeStopBssReq, *tpSirSmeStopBssReq; + +/* / Definition for stop BSS response message */ +typedef struct sSirSmeStopBssRsp { + uint16_t messageType; /* eWNI_SME_STOP_BSS_RSP */ + uint16_t length; + tSirResultCodes statusCode; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ +} tSirSmeStopBssRsp, *tpSirSmeStopBssRsp; + +/* / Definition for Channel Switch indication for station */ +/* / MAC ---> */ +typedef struct sSirSmeSwitchChannelInd { + uint16_t messageType; /* eWNI_SME_SWITCH_CHL_IND */ + uint16_t length; + uint8_t sessionId; + uint16_t newChannelId; + tSirMacAddr bssId; /* BSSID */ +} tSirSmeSwitchChannelInd, *tpSirSmeSwitchChannelInd; + +/* / Definition for Neighbor BSS indication */ +/* / MAC ---> */ +/* / MAC reports this each time a new I/BSS is detected */ +typedef struct sSirSmeNeighborBssInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_BSS_IND */ + uint16_t length; + uint8_t sessionId; + tSirBssDescription bssDescription[1]; +} tSirSmeNeighborBssInd, *tpSirSmeNeighborBssInd; + +/* / Definition for MIC failure indication */ +/* / MAC ---> */ +/* / MAC reports this each time a MIC failure occures on Rx TKIP packet */ +typedef struct sSirSmeMicFailureInd { + uint16_t messageType; /* eWNI_SME_MIC_FAILURE_IND */ + uint16_t length; + uint8_t sessionId; + tSirMacAddr bssId; /* BSSID */ + tSirMicFailureInfo info; +} tSirSmeMicFailureInd, *tpSirSmeMicFailureInd; + +typedef struct sSirSmeMissedBeaconInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bssIdx; +} tSirSmeMissedBeaconInd, *tpSirSmeMissedBeaconInd; + +/* / Definition for Set Context request */ +/* / ---> MAC */ +typedef struct sSirSmeSetContextReq { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr peerMacAddr; + tSirMacAddr bssId; /* BSSID */ + tSirKeyMaterial keyMaterial; +} tSirSmeSetContextReq, *tpSirSmeSetContextReq; + +/* / Definition for Set Context response */ +/* / MAC ---> */ +typedef struct sSirSmeSetContextRsp { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tSirMacAddr peerMacAddr; +} tSirSmeSetContextRsp, *tpSirSmeSetContextRsp; + +/* / Statistic definitions */ +/* ============================================================= */ +/* Per STA statistic structure; This same struct will be used for Aggregate */ +/* STA stats as well. */ + +/* Clear radio stats and clear per sta stats */ +typedef enum { + eANI_CLEAR_ALL_STATS, /* Clears all stats */ + eANI_CLEAR_RX_STATS, /* Clears RX stats of the radio interface */ + eANI_CLEAR_TX_STATS, /* Clears TX stats of the radio interface */ + eANI_CLEAR_RADIO_STATS, /* Clears all the radio stats */ + eANI_CLEAR_PER_STA_STATS, /* Clears Per STA stats */ + eANI_CLEAR_AGGR_PER_STA_STATS, /* Clears aggregate stats */ + + /* Used to distinguish between per sta to security stats. */ + /* Used only by AP, FW just returns the same param as it received. */ + eANI_LINK_STATS, /* Get Per STA stats */ + eANI_SECURITY_STATS, /* Get Per STA security stats */ + + eANI_CLEAR_STAT_TYPES_END +} tAniStatSubTypes; + +typedef struct sAniTxCtrs { + /* add the rate counters here */ + uint32_t tx1Mbps; + uint32_t tx2Mbps; + uint32_t tx5_5Mbps; + uint32_t tx6Mbps; + uint32_t tx9Mbps; + uint32_t tx11Mbps; + uint32_t tx12Mbps; + uint32_t tx18Mbps; + uint32_t tx24Mbps; + uint32_t tx36Mbps; + uint32_t tx48Mbps; + uint32_t tx54Mbps; + uint32_t tx72Mbps; + uint32_t tx96Mbps; + uint32_t tx108Mbps; + + /* tx path radio counts */ + uint32_t txFragHi; + uint32_t txFragLo; + uint32_t txFrameHi; + uint32_t txFrameLo; + uint32_t txMulticastFrameHi; + uint32_t txMulticastFrameLo; + uint32_t txFailedHi; + uint32_t txFailedLo; + uint32_t multipleRetryHi; + uint32_t multipleRetryLo; + uint32_t singleRetryHi; + uint32_t singleRetryLo; + uint32_t ackFailureHi; + uint32_t ackFailureLo; + uint32_t xmitBeacons; +} tAniTxCtrs, *tpAniTxCtrs; + +typedef struct sAniRxCtrs { + /* receive frame rate counters */ + uint32_t rx1Mbps; + uint32_t rx2Mbps; + uint32_t rx5_5Mbps; + uint32_t rx6Mbps; + uint32_t rx9Mbps; + uint32_t rx11Mbps; + uint32_t rx12Mbps; + uint32_t rx18Mbps; + uint32_t rx24Mbps; + uint32_t rx36Mbps; + uint32_t rx48Mbps; + uint32_t rx54Mbps; + uint32_t rx72Mbps; + uint32_t rx96Mbps; + uint32_t rx108Mbps; + + /* receive size counters; 'Lte' = Less than or equal to */ + uint32_t rxLte64; + uint32_t rxLte128Gt64; + uint32_t rxLte256Gt128; + uint32_t rxLte512Gt256; + uint32_t rxLte1kGt512; + uint32_t rxLte1518Gt1k; + uint32_t rxLte2kGt1518; + uint32_t rxLte4kGt2k; + + /* rx radio stats */ + uint32_t rxFrag; + uint32_t rxFrame; + uint32_t fcsError; + uint32_t rxMulticast; + uint32_t duplicate; + uint32_t rtsSuccess; + uint32_t rtsFailed; + uint32_t wepUndecryptables; + uint32_t drops; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; +} tAniRxCtrs, *tpAniRxCtrs; + +/* Get Radio Stats request structure */ +/* This structure shall be used for both Radio stats and Aggregate stats */ +/* A valid request must contain entire structure with/without valid fields. */ +/* Based on the request type, the valid fields will be checked. */ +typedef struct sAniGetStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + tSirMacAddr bssId; /* BSSID */ + /* only used for clear stats and per sta stats clear */ + tAniStatSubTypes stat; /* Clears the stats of the described types. */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* values */ + tSirMacAddr macAddr; +} tAniGetStatsReq, *tpAniGetStatsReq; + +/* *************************************************************** */ + +/*******************PE Statistics*************************/ + +/* + * tpAniGetPEStatsReq is tied to + * for SME ==> PE eWNI_SME_GET_STATISTICS_REQ msgId and + * for PE ==> HAL SIR_HAL_GET_STATISTICS_REQ msgId + */ +typedef struct sAniGetPEStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + uint8_t sessionId; +} tAniGetPEStatsReq, *tpAniGetPEStatsReq; + +/* + * tpAniGetPEStatsRsp is tied to + * for PE ==> SME eWNI_SME_GET_STATISTICS_RSP msgId and + * for HAL ==> PE SIR_HAL_GET_STATISTICS_RSP msgId + */ +typedef struct sAniGetPEStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* message type is same as the request type */ + /* length of the entire request, includes the pStatsBuf length too */ + uint16_t msgLen; + uint8_t sessionId; + uint32_t rc; /* success/failure */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + /* void *pStatsBuf; */ + /* + * The Stats buffer starts here and can be an aggregate of more than one + * statistics structure depending on statsMask. The void pointer + * "pStatsBuf" is commented out intentionally and the src code that uses + * this structure should take that into account. + */ +} tAniGetPEStatsRsp, *tpAniGetPEStatsRsp; + +typedef struct sAniGetRssiReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t staId; + int8_t lastRSSI; /* in case of error, return last RSSI */ + void *rssiCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ + +} tAniGetRssiReq, *tpAniGetRssiReq; + +typedef struct sAniGetSnrReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t staId; + void *snrCallback; + void *pDevContext; /* device context */ + int8_t snr; +} tAniGetSnrReq, *tpAniGetSnrReq; + +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD) +typedef struct sSirTsmIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirTsmIE, *tpSirTsmIE; +typedef struct sSirSmeTsmIEInd { + tSirTsmIE tsmIe; + uint8_t sessionId; +} tSirSmeTsmIEInd, *tpSirSmeTsmIEInd; +typedef struct sAniTrafStrmMetrics { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + uint8_t RoamingCount; + uint16_t RoamingDly; +} tAniTrafStrmMetrics, *tpAniTrafStrmMetrics; +typedef struct sAniGetTsmStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t staId; + uint8_t tid; /* traffic id */ + tSirMacAddr bssId; + void *tsmStatsCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ +} tAniGetTsmStatsReq, *tpAniGetTsmStatsReq; +typedef struct sAniGetTsmStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* + * message type is same as + * the request type + */ + uint16_t msgLen; /* + * length of the entire request, + * includes the pStatsBuf length too + */ + uint8_t sessionId; + uint32_t rc; /* success/failure */ + uint32_t staId; /* + * Per STA stats request must + * contain valid + */ + tAniTrafStrmMetrics tsmMetrics; + void *tsmStatsReq; /* tsm stats request backup */ +} tAniGetTsmStatsRsp, *tpAniGetTsmStatsRsp; + +typedef struct sSirEseBcnReportBssInfo { + tBcnReportFields bcnReportFields; + uint8_t ieLen; + uint8_t *pBuf; +} tSirEseBcnReportBssInfo, *tpSirEseBcnReportBssInfo; + +typedef struct sSirEseBcnReportRsp { + uint16_t measurementToken; + uint8_t flag; /* Flag to report measurement done and more data */ + uint8_t numBss; + tSirEseBcnReportBssInfo bcnRepBssInfo[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirEseBcnReportRsp, *tpSirEseBcnReportRsp; + +#endif /* FEATURE_WLAN_ESE || FEATURE_WLAN_ESE_UPLOAD */ + +/* Change country code request MSG structure */ +typedef struct sAniChangeCountryCodeReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; /* 3 char country code */ + tAniBool countryFromUserSpace; + tAniBool sendRegHint; /* true if we want to send hint to NL80211 */ + void *changeCCCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ + +} tAniChangeCountryCodeReq, *tpAniChangeCountryCodeReq; + +/** + * struct ani_scan_req - Scan request + * @msg_type: Message type + * @msg_len: Message Length + * @session_id: SME session Id + * @scan_param: scan request parameter + * @callback: call back function for scan result + * @ctx: Global context + * + * Scan request message structure + */ +struct ani_scan_req { + /* message type is same as the request type */ + uint16_t msg_type; + /* length of the entire request */ + uint16_t msg_len; + uint16_t session_id; + void *scan_param; + void *callback; + void *ctx; +}; + +/** + * struct ani_roc_req - Remain on channel request + * @msg_type: Message type + * @msg_len: Message Length + * @session_id: SME session Id + * @channel: channel number + * @callback: call back function for scan result + * @duration: Roc duration + * @is_p2pprobe_allowed : flag for p2p probe request + * @ctx: Global context + * @scan_id: Scan Identifier + * + * Remain on channel request message structure + */ +struct ani_roc_req { + /* message type is same as the request type */ + uint16_t msg_type; + /* length of the entire request */ + uint16_t msg_len; + uint16_t session_id; + uint8_t channel; + uint32_t duration; + uint8_t is_p2pprobe_allowed; + void *callback; + void *ctx; + uint32_t scan_id; +}; + +/* generic country code change request MSG structure */ +typedef struct sAniGenericChangeCountryCodeReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; /* 3 char country code */ + uint16_t domain_index; +} tAniGenericChangeCountryCodeReq, *tpAniGenericChangeCountryCodeReq; + +typedef struct sAniDHCPStopInd { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t device_mode; /* Mode of the device(ex:STA, AP) */ + tSirMacAddr adapterMacAddr; /* MAC address of the adapter */ + tSirMacAddr peerMacAddr; /* MAC address of the connected peer */ + +} tAniDHCPInd, *tpAniDHCPInd; + +typedef enum eTxRateInfo { + eHAL_TX_RATE_LEGACY = 0x1, /* Legacy rates */ + eHAL_TX_RATE_HT20 = 0x2, /* HT20 rates */ + eHAL_TX_RATE_HT40 = 0x4, /* HT40 rates */ + eHAL_TX_RATE_SGI = 0x8, /* Rate with Short guard interval */ + eHAL_TX_RATE_LGI = 0x10, /* Rate with Long guard interval */ + eHAL_TX_RATE_VHT20 = 0x20, /* VHT 20 rates */ + eHAL_TX_RATE_VHT40 = 0x40, /* VHT 40 rates */ + eHAL_TX_RATE_VHT80 = 0x80 /* VHT 80 rates */ +} tTxrateinfoflags; + +/**********************PE Statistics end*************************/ + +typedef struct sSirP2PNoaStart { + uint32_t status; + uint32_t bssIdx; +} tSirP2PNoaStart, *tpSirP2PNoaStart; + +typedef struct sSirTdlsInd { + uint16_t status; + uint16_t assocId; + uint16_t staIdx; + uint16_t reasonCode; +} tSirTdlsInd, *tpSirTdlsInd; + +typedef struct sSirP2PNoaAttr { +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t index:8; + uint32_t oppPsFlag:1; + uint32_t ctWin:7; + uint32_t rsvd1:16; +#else + uint32_t rsvd1:16; + uint32_t ctWin:7; + uint32_t oppPsFlag:1; + uint32_t index:8; +#endif + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa1IntervalCnt:8; + uint32_t rsvd2:24; +#else + uint32_t rsvd2:24; + uint32_t uNoa1IntervalCnt:8; +#endif + uint32_t uNoa1Duration; + uint32_t uNoa1Interval; + uint32_t uNoa1StartTime; + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa2IntervalCnt:8; + uint32_t rsvd3:24; +#else + uint32_t rsvd3:24; + uint32_t uNoa2IntervalCnt:8; +#endif + uint32_t uNoa2Duration; + uint32_t uNoa2Interval; + uint32_t uNoa2StartTime; +} tSirP2PNoaAttr, *tpSirP2PNoaAttr; + +typedef struct sSirTclasInfo { + tSirMacTclasIE tclas; + uint8_t version; /* applies only for classifier type ip */ + union { + tSirMacTclasParamEthernet eth; + tSirMacTclasParamIPv4 ipv4; + tSirMacTclasParamIPv6 ipv6; + tSirMacTclasParam8021dq t8021dq; + } cdf_packed tclasParams; +} cdf_packed tSirTclasInfo; + +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD) +#define TSRS_11AG_RATE_6MBPS 0xC +#define TSRS_11B_RATE_5_5MBPS 0xB +typedef struct sSirMacESETSRSIE { + uint8_t tsid; + uint8_t rates[8]; +} tSirMacESETSRSIE; +typedef struct sSirMacESETSMIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirMacESETSMIE; +typedef struct sTSMStats { + uint8_t tid; + tSirMacAddr bssId; + tTrafStrmMetrics tsmMetrics; +} tTSMStats, *tpTSMStats; +typedef struct sEseTSMContext { + uint8_t tid; + tSirMacESETSMIE tsmInfo; + tTrafStrmMetrics tsmMetrics; +} tEseTSMContext, *tpEseTSMContext; +typedef struct sEsePEContext { + tEseTSMContext tsm; +} tEsePEContext, *tpEsePEContext; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +typedef struct sSirAddtsReqInfo { + uint8_t dialogToken; + tSirMacTspecIE tspec; + + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; +#if defined(FEATURE_WLAN_ESE) + tSirMacESETSRSIE tsrsIE; + uint8_t tsrsPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; +} tSirAddtsReqInfo, *tpSirAddtsReqInfo; + +typedef struct sSirAddtsRspInfo { + uint8_t dialogToken; + tSirMacStatusCodes status; + tSirMacTsDelayIE delay; + + tSirMacTspecIE tspec; + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + tSirMacScheduleIE schedule; +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD) + tSirMacESETSMIE tsmIE; + uint8_t tsmPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; + uint8_t schedulePresent:1; +} tSirAddtsRspInfo, *tpSirAddtsRspInfo; + +typedef struct sSirDeltsReqInfo { + tSirMacTSInfo tsinfo; + tSirMacTspecIE tspec; + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; +} tSirDeltsReqInfo, *tpSirDeltsReqInfo; + +/* / Add a tspec as defined */ +typedef struct sSirAddtsReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + tSirMacAddr bssId; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAddtsReqInfo req; +} tSirAddtsReq, *tpSirAddtsReq; + +typedef struct sSirAddtsRsp { + uint16_t messageType; /* eWNI_SME_ADDTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint16_t transactionId; /* sme transaction Id - for BT-AMP Support */ + uint32_t rc; /* return code */ + tSirAddtsRspInfo rsp; +} tSirAddtsRsp, *tpSirAddtsRsp; + +typedef struct sSirDeltsReq { + uint16_t messageType; /* eWNI_SME_DELTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + tSirMacAddr bssId; /* BSSID */ + uint16_t aid; /* use 0 if macAddr is being specified */ + tSirMacAddr macAddr; /* only on AP to specify the STA */ + uint8_t rspReqd; + tSirDeltsReqInfo req; +} tSirDeltsReq, *tpSirDeltsReq; + +typedef struct sSirDeltsRsp { + uint16_t messageType; /* eWNI_SME_DELTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint16_t transactionId; /* sme transaction Id - for BT-AMP Support */ + uint32_t rc; + uint16_t aid; /* use 0 if macAddr is being specified */ + tSirMacAddr macAddr; /* only on AP to specify the STA */ + tSirDeltsReqInfo rsp; +} tSirDeltsRsp, *tpSirDeltsRsp; + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +typedef struct sSirPlmReq { + uint16_t diag_token; /* Dialog token */ + uint16_t meas_token; /* measurement token */ + uint16_t numBursts; /* total number of bursts */ + uint16_t burstInt; /* burst interval in seconds */ + uint16_t measDuration; /* in TU's,STA goes off-ch */ + /* no of times the STA should cycle through PLM ch list */ + uint8_t burstLen; + tPowerdBm desiredTxPwr; /* desired tx power */ + tSirMacAddr macAddr; /* MC dest addr */ + /* no of channels */ + uint8_t plmNumCh; + /* channel numbers */ + uint8_t plmChList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t sessionId; + bool enable; +} tSirPlmReq, *tpSirPlmReq; +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + +#define SIR_QOS_NUM_AC_MAX 4 + +typedef struct sSirAggrQosReqInfo { + uint16_t tspecIdx; + tSirAddtsReqInfo aggrAddTsInfo[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosReqInfo, *tpSirAggrQosReqInfo; + +typedef struct sSirAggrQosReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + tSirMacAddr bssId; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAggrQosReqInfo aggrInfo; +} tSirAggrQosReq, *tpSirAggrQosReq; + +typedef struct sSirAggrQosRspInfo { + uint16_t tspecIdx; + tSirAddtsRspInfo aggrRsp[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosRspInfo, *tpSirAggrQosRspInfo; + +typedef struct sSirAggrQosRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirAggrQosRspInfo aggrInfo; +} tSirAggrQosRsp, *tpSirAggrQosRsp; + +#endif /*WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE */ + +typedef struct sSirQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[21][2]; + uint8_t dscp_range[8][2]; +} tSirQosMapSet, *tpSirQosMapSet; + +typedef struct sSmeIbssPeerInd { + uint16_t mesgType; + uint16_t mesgLen; + uint8_t sessionId; + + tSirMacAddr peerAddr; + uint16_t staId; + + /* + * The DPU signatures will be sent eventually to TL to help it determine + * the association to which a packet belongs to + */ + /* Unicast DPU signature */ + uint8_t ucastSig; + + /*Broadcast DPU signature */ + uint8_t bcastSig; + + /* Beacon will be appended for new Peer indication. */ +} tSmeIbssPeerInd, *tpSmeIbssPeerInd; + +typedef struct sSirIbssPeerInactivityInd { + uint8_t bssIdx; + uint8_t staIdx; + tSirMacAddr peerAddr; +} tSirIbssPeerInactivityInd, *tpSirIbssPeerInactivityInd; + +typedef struct sLimScanChn { + uint16_t numTimeScan; /* how many time this channel is scan */ + uint8_t channelId; +} tLimScanChn; + +typedef struct sSmeGetScanChnRsp { + /* Message Type */ + uint16_t mesgType; + /* Message Length */ + uint16_t mesgLen; + uint8_t sessionId; + uint8_t numChn; + tLimScanChn scanChn[1]; +} tSmeGetScanChnRsp, *tpSmeGetScanChnRsp; + +typedef struct sLimScanChnInfo { + uint8_t numChnInfo; /* number of channels in scanChn */ + tLimScanChn scanChn[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +} tLimScanChnInfo; + +typedef struct sSirSmeGetAssocSTAsReq { + uint16_t messageType; /* eWNI_SME_GET_ASSOC_STAS_REQ */ + uint16_t length; + tSirMacAddr bssId; /* BSSID */ + uint16_t modId; + void *pUsrContext; + void *pSapEventCallback; + /* Pointer to allocated mem passed in wlansap_get_assoc_stations API */ + void *pAssocStasArray; +} tSirSmeGetAssocSTAsReq, *tpSirSmeGetAssocSTAsReq; + +typedef struct sSmeMaxAssocInd { + uint16_t mesgType; /* eWNI_SME_MAX_ASSOC_EXCEEDED */ + uint16_t mesgLen; + uint8_t sessionId; + /* the new peer that got rejected max assoc limit reached */ + tSirMacAddr peerMac; +} tSmeMaxAssocInd, *tpSmeMaxAssocInd; + +typedef struct sSmeCsaOffloadInd { + uint16_t mesgType; /* eWNI_SME_CSA_OFFLOAD_EVENT */ + uint16_t mesgLen; + tSirMacAddr bssId; /* BSSID */ +} tSmeCsaOffloadInd, *tpSmeCsaOffloadInd; + +/* WOW related structures */ +#define SIR_WOWL_BCAST_PATTERN_MAX_SIZE 146 + +/** + * struct wow_add_pattern - wow pattern add structure + * @pattern_id: pattern id + * @pattern_byte_offset: pattern byte offset from beginning of the 802.11 + * packet to start of the wake-up pattern + * @pattern_size: pattern size + * @pattern: pattern byte stream + * @pattern_mask_size: pattern mask size + * @pattern_mask: pattern mask + * @session_id: session id + */ +struct wow_add_pattern { + uint8_t pattern_id; + uint8_t pattern_byte_offset; + uint8_t pattern_size; + uint8_t pattern[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + uint8_t pattern_mask_size; + uint8_t pattern_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + uint8_t session_id; +}; + +/** + * struct wow_delete_patern - wow pattern delete structure + * @pattern_id: pattern id of wake up pattern to be deleted + * @session_id: session id + */ +struct wow_delete_pattern { + uint8_t pattern_id; + uint8_t session_id; +}; + +/* SME->PE: Enter WOWLAN parameters */ +typedef struct sSirSmeWowlEnterParams { + uint8_t sessionId; + + /* Enables/disables magic packet filtering */ + uint8_t ucMagicPktEnable; + + /* Magic pattern */ + tSirMacAddr magicPtrn; + + /* Enables/disables packet pattern filtering */ + uint8_t ucPatternFilteringEnable; + +#ifdef WLAN_WAKEUP_EVENTS + /* + * This configuration directs the WoW packet filtering to look at EAP-ID + * requests embedded in EAPOL frames and use this as a wake source. + */ + uint8_t ucWoWEAPIDRequestEnable; + + /* + * This configuration directs the WoW packet filtering to look for + * EAPOL-4WAY requests and use this as a wake source. + */ + uint8_t ucWoWEAPOL4WayEnable; + + /* + * This configuration allows a host wakeup on an network scan + * offload match. + */ + uint8_t ucWowNetScanOffloadMatch; + + /* This configuration allows a host wakeup on any GTK rekeying error. + */ + uint8_t ucWowGTKRekeyError; + + /* This configuration allows a host wakeup on BSS connection loss. + */ + uint8_t ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + tSirMacAddr bssId; +} tSirSmeWowlEnterParams, *tpSirSmeWowlEnterParams; + +/* PE<->HAL: Enter WOWLAN parameters */ +typedef struct sSirHalWowlEnterParams { + uint8_t sessionId; + + /* Enables/disables magic packet filtering */ + uint8_t ucMagicPktEnable; + + /* Magic pattern */ + tSirMacAddr magicPtrn; + + /* Enables/disables packet pattern filtering in firmware. + Enabling this flag enables broadcast pattern matching + in Firmware. If unicast pattern matching is also desired, + ucUcastPatternFilteringEnable flag must be set tot true + as well + */ + uint8_t ucPatternFilteringEnable; + + /* Enables/disables unicast packet pattern filtering. + This flag specifies whether we want to do pattern match + on unicast packets as well and not just broadcast packets. + This flag has no effect if the ucPatternFilteringEnable + (main controlling flag) is set to false + */ + uint8_t ucUcastPatternFilteringEnable; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Channel Switch Action Frame. + */ + uint8_t ucWowChnlSwitchRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Deauthentication Frame. + */ + uint8_t ucWowDeauthRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Disassociation Frame. + */ + uint8_t ucWowDisassocRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it has missed + * consecutive beacons. This is a hardware register + * configuration (NOT a firmware configuration). + */ + uint8_t ucWowMaxMissedBeacons; + + /* This configuration is valid only when magicPktEnable=1. + * This is a timeout value in units of microsec. It requests + * hardware to unconditionally wake up after it has stayed + * in WoWLAN mode for some time. Set 0 to disable this feature. + */ + uint8_t ucWowMaxSleepUsec; + +#ifdef WLAN_WAKEUP_EVENTS + /* This config directs the WoW pkt filtering to look for EAP-ID + * requests embedded in EAPOL frames and use this as a wake source. + */ + uint8_t ucWoWEAPIDRequestEnable; + + /* This config directs the WoW pkt filtering to look for EAPOL-4WAY + * requests and use this as a wake source. + */ + uint8_t ucWoWEAPOL4WayEnable; + + /* This config allows a host wakeup on an network scan offload match. + */ + uint8_t ucWowNetScanOffloadMatch; + + /* This configuration allows a host wakeup on any GTK rekeying error. + */ + uint8_t ucWowGTKRekeyError; + + /* This configuration allows a host wakeup on BSS connection loss. + */ + uint8_t ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + /* Status code to be filled by HAL when it sends + * SIR_HAL_WOWL_ENTER_RSP to PE. + */ + CDF_STATUS status; + + /*BSSID to find the current session + */ + uint8_t bssIdx; +} tSirHalWowlEnterParams, *tpSirHalWowlEnterParams; + +/* SME->PE: Exit WOWLAN parameters */ +typedef struct sSirSmeWowlExitParams { + uint8_t sessionId; + +} tSirSmeWowlExitParams, *tpSirSmeWowlExitParams; + +/* PE<->HAL: Exit WOWLAN parameters */ +typedef struct sSirHalWowlExitParams { + uint8_t sessionId; + + /* Status code to be filled by HAL when it sends + * SIR_HAL_WOWL_EXIT_RSP to PE. + */ + CDF_STATUS status; + + /*BSSIDX to find the current session + */ + uint8_t bssIdx; +} tSirHalWowlExitParams, *tpSirHalWowlExitParams; + +#define SIR_MAX_NAME_SIZE 64 +#define SIR_MAX_TEXT_SIZE 32 + +typedef struct sSirName { + uint8_t num_name; + uint8_t name[SIR_MAX_NAME_SIZE]; +} tSirName; + +typedef struct sSirText { + uint8_t num_text; + uint8_t text[SIR_MAX_TEXT_SIZE]; +} tSirText; + +#define SIR_WPS_PROBRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_PROBRSP_STATE_PRESENT 0x00000002 +#define SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT 0x00000040 +#define SIR_WPS_PROBRSP_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_PROBRSP_MANUFACTURE_PRESENT 0x00000100 +#define SIR_WPS_PROBRSP_MODELNAME_PRESENT 0x00000200 +#define SIR_WPS_PROBRSP_MODELNUMBER_PRESENT 0x00000400 +#define SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT 0x00000800 +#define SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT 0x00001000 +#define SIR_WPS_PROBRSP_DEVICENAME_PRESENT 0x00002000 +#define SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT 0x00004000 +#define SIR_WPS_PROBRSP_RF_BANDS_PRESENT 0x00008000 + +typedef struct sSirWPSProbeRspIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t ResponseType; /* Response type */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + tSirName Manufacture; + tSirText ModelName; + tSirText ModelNumber; + tSirText SerialNumber; + /* Device Category ID: 1Computer, 2Input Device, ... */ + uint32_t PrimaryDeviceCategory; + /* Vendor specific OUI for Device Sub Category */ + uint8_t PrimaryDeviceOUI[4]; + /* + Device Sub Category ID: 1-PC, 2-Server if Device Category ID + * is computer + */ + uint32_t DeviceSubCategory; + tSirText DeviceName; + uint16_t ConfigMethod; /* Configuaration method */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSProbeRspIE; + +#define SIR_WPS_BEACON_VER_PRESENT 0x00000001 +#define SIR_WPS_BEACON_STATE_PRESENT 0x00000002 +#define SIR_WPS_BEACON_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_BEACON_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_BEACON_RF_BANDS_PRESENT 0x00000100 +#define SIR_WPS_UUID_LEN 16 + +typedef struct sSirWPSBeaconIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t UUID_E[SIR_WPS_UUID_LEN]; /* Unique identifier of the AP. */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSBeaconIE; + +#define SIR_WPS_ASSOCRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_ASSOCRSP_RESPONSETYPE_PRESENT 0x00000002 + +typedef struct sSirWPSAssocRspIE { + uint32_t FieldPresent; + uint32_t Version; + uint8_t ResposeType; +} tSirWPSAssocRspIE; + +typedef struct sSirAPWPSIEs { + tSirWPSProbeRspIE SirWPSProbeRspIE; /*WPS Set Probe Respose IE */ + tSirWPSBeaconIE SirWPSBeaconIE; /*WPS Set Beacon IE */ + tSirWPSAssocRspIE SirWPSAssocRspIE; /*WPS Set Assoc Response IE */ +} tSirAPWPSIEs, *tpSiriAPWPSIEs; + +typedef struct sSirUpdateAPWPSIEsReq { + uint16_t messageType; /* eWNI_SME_UPDATE_APWPSIE_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirAPWPSIEs APWPSIEs; +} tSirUpdateAPWPSIEsReq, *tpSirUpdateAPWPSIEsReq; + +typedef struct sSirUpdateParams { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint8_t ssidHidden; /* Hide SSID */ +} tSirUpdateParams, *tpSirUpdateParams; + +/* Beacon Interval */ +typedef struct sSirChangeBIParams { + uint16_t messageType; + uint16_t length; + uint16_t beaconInterval; /* Beacon Interval */ + tSirMacAddr bssId; + uint8_t sessionId; /* Session ID */ +} tSirChangeBIParams, *tpSirChangeBIParams; + +#ifdef QCA_HT_2040_COEX +typedef struct sSirSetHT2040Mode { + uint16_t messageType; + uint16_t length; + uint8_t cbMode; + bool obssEnabled; + tSirMacAddr bssId; + uint8_t sessionId; /* Session ID */ +} tSirSetHT2040Mode, *tpSirSetHT2040Mode; +#endif + +#define SIR_WPS_PBC_WALK_TIME 120 /* 120 Second */ + +typedef struct sSirWPSPBCSession { + struct sSirWPSPBCSession *next; + tSirMacAddr addr; + uint8_t uuid_e[SIR_WPS_UUID_LEN]; + uint32_t timestamp; +} tSirWPSPBCSession; + +typedef struct sSirSmeGetWPSPBCSessionsReq { + uint16_t messageType; /* eWNI_SME_GET_WPSPBC_SESSION_REQ */ + uint16_t length; + void *pUsrContext; + void *pSapEventCallback; + tSirMacAddr bssId; /* BSSID */ + /* MAC Address of STA in WPS Session to be removed */ + tSirMacAddr pRemoveMac; +} tSirSmeGetWPSPBCSessionsReq, *tpSirSmeGetWPSPBCSessionsReq; + +typedef struct sSirWPSPBCProbeReq { + tSirMacAddr peerMacAddr; + uint16_t probeReqIELen; + uint8_t probeReqIE[512]; +} tSirWPSPBCProbeReq, *tpSirWPSPBCProbeReq; + +/* probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbeReqInd { + uint16_t messageType; /* eWNI_SME_WPS_PBC_PROBE_REQ_IND */ + uint16_t length; + uint8_t sessionId; + tSirMacAddr bssId; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSirSmeProbeReqInd, *tpSirSmeProbeReqInd; + +typedef struct sSirUpdateAPWPARSNIEsReq { + uint16_t messageType; /* eWNI_SME_SET_APWPARSNIEs_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + tSirMacAddr bssId; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirRSNie APWPARSNIEs; +} tSirUpdateAPWPARSNIEsReq, *tpSirUpdateAPWPARSNIEsReq; + +#define SIR_ROAM_MAX_CHANNELS 80 +#define SIR_ROAM_SCAN_MAX_PB_REQ_SIZE 450 +/* Occupied channel list remains static */ +#define CHANNEL_LIST_STATIC 1 +/* Occupied channel list can be learnt after init */ +#define CHANNEL_LIST_DYNAMIC_INIT 2 +/* Occupied channel list can be learnt after flush */ +#define CHANNEL_LIST_DYNAMIC_FLUSH 3 +/* Occupied channel list can be learnt after update */ +#define CHANNEL_LIST_DYNAMIC_UPDATE 4 +#define SIR_ROAM_SCAN_24G_DEFAULT_CH 1 +#define SIR_ROAM_SCAN_5G_DEFAULT_CH 36 +#define SIR_ROAM_SCAN_RESERVED_BYTES 61 + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_ROAM_SCAN_PSK_SIZE 32 +#define SIR_ROAM_R0KH_ID_MAX_LEN 48 +#endif +/* SME -> HAL - This is the host offload request. */ +#define SIR_IPV4_ARP_REPLY_OFFLOAD 0 +#define SIR_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 +#define SIR_IPV6_NS_OFFLOAD 2 +#define SIR_OFFLOAD_DISABLE 0 +#define SIR_OFFLOAD_ENABLE 1 +#define SIR_OFFLOAD_BCAST_FILTER_ENABLE 0x2 +#define SIR_OFFLOAD_MCAST_FILTER_ENABLE 0x4 +#define SIR_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE (SIR_OFFLOAD_ENABLE|SIR_OFFLOAD_BCAST_FILTER_ENABLE) +#define SIR_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE (SIR_OFFLOAD_ENABLE|SIR_OFFLOAD_MCAST_FILTER_ENABLE) + +#ifdef WLAN_NS_OFFLOAD +typedef struct sSirNsOffloadReq { + uint8_t srcIPv6Addr[16]; + uint8_t selfIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + uint8_t targetIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + tSirMacAddr selfMacAddr; + uint8_t srcIPv6AddrValid; + uint8_t targetIPv6AddrValid[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t slotIdx; +} tSirNsOffloadReq, *tpSirNsOffloadReq; +#endif /* WLAN_NS_OFFLOAD */ + +typedef struct sSirHostOffloadReq { + uint8_t offloadType; + uint8_t enableOrDisable; + uint32_t num_ns_offload_count; + union { + uint8_t hostIpv4Addr[4]; + uint8_t hostIpv6Addr[16]; + } params; +#ifdef WLAN_NS_OFFLOAD + tSirNsOffloadReq nsOffloadInfo; +#endif /* WLAN_NS_OFFLOAD */ + tSirMacAddr bssId; +} tSirHostOffloadReq, *tpSirHostOffloadReq; + +/* Packet Types. */ +#define SIR_KEEP_ALIVE_NULL_PKT 1 +#define SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 + +/* Keep Alive request. */ +typedef struct sSirKeepAliveReq { + uint8_t packetType; + uint32_t timePeriod; + tSirIpv4Addr hostIpv4Addr; + tSirIpv4Addr destIpv4Addr; + tSirMacAddr destMacAddr; + tSirMacAddr bssId; + uint8_t sessionId; +} tSirKeepAliveReq, *tpSirKeepAliveReq; + +typedef struct sSirSmeMgmtFrameInd { + uint16_t mesgType; + uint16_t mesgLen; + uint32_t rxChan; + uint8_t sessionId; + uint8_t frameType; + int8_t rxRssi; + uint8_t frameBuf[1]; /* variable */ +} tSirSmeMgmtFrameInd, *tpSirSmeMgmtFrameInd; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirSmeUnprotMgmtFrameInd { + uint8_t sessionId; + uint8_t frameType; + uint8_t frameLen; + uint8_t frameBuf[1]; /* variable */ +} tSirSmeUnprotMgmtFrameInd, *tpSirSmeUnprotMgmtFrameInd; +#endif + +#define SIR_IS_FULL_POWER_REASON_DISCONNECTED(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_LINK_DISCONNECTED_BY_OTHER == (eReason))) +#define SIR_IS_FULL_POWER_NEEDED_BY_HDD(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_FULL_PWR_NEEDED_BY_HDD == (eReason))) + +/* P2P Power Save Related */ +typedef struct sSirNoAParam { + uint8_t ctWindow:7; + uint8_t OppPS:1; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t singleNoADuration; + uint8_t psSelection; +} tSirNoAParam, *tpSirNoAParam; + +typedef struct sSirWlanSuspendParam { + uint8_t configuredMcstBcstFilterSetting; + uint8_t sessionId; + uint8_t connectedState; +} tSirWlanSuspendParam, *tpSirWlanSuspendParam; + +typedef struct sSirWlanResumeParam { + uint8_t configuredMcstBcstFilterSetting; +} tSirWlanResumeParam, *tpSirWlanResumeParam; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + +typedef enum ext_wow_type { + EXT_WOW_TYPE_APP_TYPE1, /* wow type: only enable wakeup for app type1 */ + EXT_WOW_TYPE_APP_TYPE2, /* wow type: only enable wakeup for app type2 */ + EXT_WOW_TYPE_APP_TYPE1_2, /* wow type: enable wakeup for app type1&2 */ +} EXT_WOW_TYPE; + +typedef struct { + uint8_t vdev_id; + EXT_WOW_TYPE type; + uint32_t wakeup_pin_num; +} tSirExtWoWParams, *tpSirExtWoWParams; + +typedef struct { + uint8_t vdev_id; + tSirMacAddr wakee_mac_addr; + uint8_t identification_id[8]; + uint8_t password[16]; + uint32_t id_length; + uint32_t pass_length; +} tSirAppType1Params, *tpSirAppType1Params; + +typedef struct { + uint8_t vdev_id; + + uint8_t rc4_key[16]; + uint32_t rc4_key_len; + + /** ip header parameter */ + uint32_t ip_id; /* NC id */ + uint32_t ip_device_ip; /* NC IP address */ + uint32_t ip_server_ip; /* Push server IP address */ + + /** tcp header parameter */ + uint16_t tcp_src_port; /* NC TCP port */ + uint16_t tcp_dst_port; /* Push server TCP port */ + uint32_t tcp_seq; + uint32_t tcp_ack_seq; + + uint32_t keepalive_init; /* Initial ping interval */ + uint32_t keepalive_min; /* Minimum ping interval */ + uint32_t keepalive_max; /* Maximum ping interval */ + uint32_t keepalive_inc; /* Increment of ping interval */ + + tSirMacAddr gateway_mac; + uint32_t tcp_tx_timeout_val; + uint32_t tcp_rx_timeout_val; +} tSirAppType2Params, *tpSirAppType2Params; +#endif + +typedef struct sSirWlanSetRxpFilters { + uint8_t configuredMcstBcstFilterSetting; + uint8_t setMcstBcstFilter; +} tSirWlanSetRxpFilters, *tpSirWlanSetRxpFilters; + + +#define ANI_MAX_IBSS_ROUTE_TABLE_ENTRY 100 + +typedef struct sAniDestIpNextHopMacPair { + uint8_t destIpv4Addr[CDF_IPV4_ADDR_SIZE]; + uint8_t nextHopMacAddr[CDF_MAC_ADDR_SIZE]; +} tAniDestIpNextHopMacPair; + +typedef struct sAniIbssRouteTable { + uint8_t sessionId; + uint16_t numEntries; + tAniDestIpNextHopMacPair destIpNextHopPair[1]; +} tAniIbssRouteTable; + +#ifdef FEATURE_WLAN_SCAN_PNO +/* */ +/* PNO Messages */ +/* */ + + +/* Set PNO */ +#define SIR_PNO_MAX_NETW_CHANNELS 26 +#define SIR_PNO_MAX_NETW_CHANNELS_EX 60 +#define SIR_PNO_MAX_SUPP_NETWORKS 16 +#define SIR_PNO_MAX_SCAN_TIMERS 10 + +/* + * size based of dot11 declaration without extra IEs as we will not carry those + * for PNO + */ +#define SIR_PNO_MAX_PB_REQ_SIZE 450 + +#define SIR_PNO_24G_DEFAULT_CH 1 +#define SIR_PNO_5G_DEFAULT_CH 36 + +typedef enum { + SIR_PNO_MODE_IMMEDIATE, + SIR_PNO_MODE_ON_SUSPEND, + SIR_PNO_MODE_ON_RESUME, + SIR_PNO_MODE_MAX +} eSirPNOMode; + +typedef struct { + tSirMacSSid ssId; + uint32_t authentication; + uint32_t encryption; + uint32_t bcastNetwType; + uint8_t ucChannelCount; + uint8_t aChannels[SIR_PNO_MAX_NETW_CHANNELS_EX]; + int32_t rssiThreshold; +} tSirNetworkType; + +typedef struct { + uint32_t uTimerValue; + uint32_t uTimerRepeat; +} tSirScanTimer; + +typedef struct { + uint8_t ucScanTimersCount; + tSirScanTimer aTimerValues[SIR_PNO_MAX_SCAN_TIMERS]; +} tSirScanTimersType; + +typedef struct sSirPNOScanReq { + uint8_t enable; + eSirPNOMode modePNO; + uint8_t ucNetworksCount; + tSirNetworkType aNetworks[SIR_PNO_MAX_SUPP_NETWORKS]; + tSirScanTimersType scanTimers; + uint8_t sessionId; + + uint16_t us24GProbeTemplateLen; + uint8_t p24GProbeTemplate[SIR_PNO_MAX_PB_REQ_SIZE]; + uint16_t us5GProbeTemplateLen; + uint8_t p5GProbeTemplate[SIR_PNO_MAX_PB_REQ_SIZE]; +} tSirPNOScanReq, *tpSirPNOScanReq; + +/* Preferred Network Found Indication */ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + /* Network that was found with the highest RSSI */ + tSirMacSSid ssId; + /* Indicates the RSSI */ + uint8_t rssi; + /* Length of the beacon or probe response + * corresponding to the candidate found by PNO */ + uint32_t frameLength; + uint8_t sessionId; + /* Index to memory location where the contents of + * beacon or probe response frame will be copied */ + uint8_t data[1]; +} tSirPrefNetworkFoundInd, *tpSirPrefNetworkFoundInd; +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct { + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved:4; +} tSirAcUapsd, *tpSirAcUapsd; +#endif + +typedef struct { + tSirMacSSid ssId; + uint8_t currAPbssid[CDF_MAC_ADDR_SIZE]; + uint32_t authentication; + uint8_t encryption; + uint8_t mcencryption; + uint8_t ChannelCount; + uint8_t ChannelCache[SIR_ROAM_MAX_CHANNELS]; +#ifdef WLAN_FEATURE_11W + bool mfp_enabled; +#endif + +} tSirRoamNetworkType; + +typedef struct SirMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tSirMobilityDomainInfo; + +typedef enum { + SIR_ROAMING_DFS_CHANNEL_DISABLED = 0, + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL = 1, + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE = 2 +} eSirDFSRoamScanMode; +#define MAX_SSID_ALLOWED_LIST 4 +#define MAX_BSSID_AVOID_LIST 16 +#define MAX_BSSID_FAVORED 16 +/** + * struct roam_ext_params - Structure holding roaming parameters + * @num_bssid_avoid_list: The number of BSSID's that we should + * avoid connecting to. It is like a + * blacklist of BSSID's. + * @num_ssid_allowed_list: The number of SSID profiles that are + * in the Whitelist. When roaming, we + * consider the BSSID's with this SSID + * also for roaming apart from the connected one's + * @num_bssid_favored: Number of BSSID's which have a preference over + * others + * @ssid_allowed_list: Whitelist SSID's + * @bssid_avoid_list: Blacklist SSID's + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * @raise_rssi_thresh_5g: The RSSI threshold below which the + * raise_factor_5g (boost factor) should be + * applied. + * @drop_rssi_thresh_5g: The RSSI threshold beyond which the + * drop_factor_5g (penalty factor) should be + * applied + * @raise_rssi_type_5g: Algorithm to apply the boost factor + * @raise_factor_5g: Boost factor + * @drop_rssi_type_5g: Algorithm to apply the penalty factor + * @drop_factor_5g: Penalty factor + * @max_raise_rssi_5g: Maximum amount of Boost that can added + * @max_drop_rssi_5g: Maximum amount of penalty that can be subtracted + * @good_rssi_threshold: The Lookup UP threshold beyond which roaming + * scan should be performed. + * @rssi_diff: RSSI difference for the AP to be better over the + * current AP to avoid ping pong effects + * @good_rssi_roam: Lazy Roam + * @is_5g_pref_enabled: 5GHz BSSID preference feature enable/disable. + * + * This structure holds all the key parameters related to + * initial connection and also roaming connections. + * */ +struct roam_ext_params { + uint8_t num_bssid_avoid_list; + uint8_t num_ssid_allowed_list; + uint8_t num_bssid_favored; + tSirMacSSid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; + tSirMacAddr bssid_avoid_list[MAX_BSSID_AVOID_LIST]; + tSirMacAddr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; + int raise_rssi_thresh_5g; + int drop_rssi_thresh_5g; + uint8_t raise_rssi_type_5g; + uint8_t raise_factor_5g; + uint8_t drop_rssi_type_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + int max_drop_rssi_5g; + int alert_rssi_threshold; + int rssi_diff; + int good_rssi_roam; + bool is_5g_pref_enabled; +}; + +typedef struct sSirRoamOffloadScanReq { + bool RoamScanOffloadEnabled; + bool MAWCEnabled; + int8_t LookupThreshold; + uint8_t delay_before_vdev_stop; + uint8_t OpportunisticScanThresholdDiff; + uint8_t RoamRescanRssiDiff; + uint8_t RoamRssiDiff; + uint8_t ChannelCacheType; + uint8_t Command; + uint8_t reason; + uint16_t NeighborScanTimerPeriod; + uint16_t NeighborRoamScanRefreshPeriod; + uint16_t NeighborScanChannelMinTime; + uint16_t NeighborScanChannelMaxTime; + uint16_t EmptyRefreshScanPeriod; + uint8_t ValidChannelCount; + uint8_t ValidChannelList[SIR_ROAM_MAX_CHANNELS]; + bool IsESEAssoc; + uint16_t us24GProbeTemplateLen; + uint8_t p24GProbeTemplate[SIR_ROAM_SCAN_MAX_PB_REQ_SIZE]; + uint16_t us5GProbeTemplateLen; + uint8_t p5GProbeTemplate[SIR_ROAM_SCAN_MAX_PB_REQ_SIZE]; + uint8_t ReservedBytes[SIR_ROAM_SCAN_RESERVED_BYTES]; + /*ReservedBytes is to add any further params in future + without changing the interface params on Host + and firmware.The firmware right now checks + if the size of this structure matches and then + proceeds with the processing of the command. + So, in future, if there is any need to add + more params, pick the memory from reserved + bytes and keep deducting the reserved bytes + by the amount of bytes picked. */ + uint8_t nProbes; + uint16_t HomeAwayTime; + tSirRoamNetworkType ConnectedNetwork; + tSirMobilityDomainInfo MDID; + uint8_t sessionId; + uint8_t RoamBmissFirstBcnt; + uint8_t RoamBmissFinalBcnt; + uint8_t RoamBeaconRssiWeight; + eSirDFSRoamScanMode allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t RoamOffloadEnabled; + uint8_t PSK_PMK[SIR_ROAM_SCAN_PSK_SIZE]; + uint32_t pmk_len; + uint8_t Prefer5GHz; + uint8_t RoamRssiCatGap; + uint8_t Select5GHzMargin; + uint8_t KRK[SIR_KRK_KEY_LEN]; + uint8_t BTK[SIR_BTK_KEY_LEN]; + uint32_t ReassocFailureTimeout; + tSirAcUapsd AcUapsd; + uint8_t R0KH_ID[SIR_ROAM_R0KH_ID_MAX_LEN]; + uint32_t R0KH_ID_Length; + uint8_t RoamKeyMgmtOffloadEnabled; +#endif + struct roam_ext_params roam_params; + uint8_t middle_of_roaming; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + uint32_t hi_rssi_scan_delay; + int32_t hi_rssi_scan_rssi_ub; +} tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; + +typedef struct sSirRoamOffloadScanRsp { + uint8_t sessionId; + uint32_t reason; +} tSirRoamOffloadScanRsp, *tpSirRoamOffloadScanRsp; + + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/*--------------------------------------------------------------------------- + Packet Filtering Parameters + ---------------------------------------------------------------------------*/ +#define SIR_IPV4_ADDR_LEN 4 +#define SIR_MAC_ADDR_LEN 6 +#define SIR_MAX_FILTER_TEST_DATA_LEN 8 +#define SIR_MAX_NUM_MULTICAST_ADDRESS 240 +#define SIR_MAX_NUM_FILTERS 20 +#define SIR_MAX_NUM_TESTS_PER_FILTER 10 + +/* */ +/* Receive Filter Parameters */ +/* */ +typedef enum { + SIR_RCV_FILTER_TYPE_INVALID, + SIR_RCV_FILTER_TYPE_FILTER_PKT, + SIR_RCV_FILTER_TYPE_BUFFER_PKT, + SIR_RCV_FILTER_TYPE_MAX_ENUM_SIZE +} eSirReceivePacketFilterType; + +typedef enum { + SIR_FILTER_HDR_TYPE_INVALID, + SIR_FILTER_HDR_TYPE_MAC, + SIR_FILTER_HDR_TYPE_ARP, + SIR_FILTER_HDR_TYPE_IPV4, + SIR_FILTER_HDR_TYPE_IPV6, + SIR_FILTER_HDR_TYPE_UDP, + SIR_FILTER_HDR_TYPE_MAX +} eSirRcvPktFltProtocolType; + +typedef enum { + SIR_FILTER_CMP_TYPE_INVALID, + SIR_FILTER_CMP_TYPE_EQUAL, + SIR_FILTER_CMP_TYPE_MASK_EQUAL, + SIR_FILTER_CMP_TYPE_NOT_EQUAL, + SIR_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + SIR_FILTER_CMP_TYPE_MAX +} eSirRcvPktFltCmpFlagType; + +typedef struct sSirRcvPktFilterFieldParams { + eSirRcvPktFltProtocolType protocolLayer; + eSirRcvPktFltCmpFlagType cmpFlag; + /* Length of the data to compare */ + uint16_t dataLength; + /* from start of the respective frame header */ + uint8_t dataOffset; + /* Reserved field */ + uint8_t reserved; + /* Data to compare */ + uint8_t compareData[SIR_MAX_FILTER_TEST_DATA_LEN]; + /* Mask to be applied on the received packet data before compare */ + uint8_t dataMask[SIR_MAX_FILTER_TEST_DATA_LEN]; +} tSirRcvPktFilterFieldParams, *tpSirRcvPktFilterFieldParams; + +typedef struct sSirRcvPktFilterCfg { + uint8_t filterId; + eSirReceivePacketFilterType filterType; + uint32_t numFieldParams; + uint32_t coalesceTime; + tSirMacAddr selfMacAddr; + tSirMacAddr bssId; /* Bssid of the connected AP */ + tSirRcvPktFilterFieldParams paramsData[SIR_MAX_NUM_TESTS_PER_FILTER]; +} tSirRcvPktFilterCfgType, *tpSirRcvPktFilterCfgType; + +/* */ +/* Filter Packet Match Count Parameters */ +/* */ +typedef struct sSirRcvFltPktMatchCnt { + uint8_t filterId; + uint32_t matchCnt; +} tSirRcvFltPktMatchCnt, tpSirRcvFltPktMatchCnt; + +typedef struct sSirRcvFltPktMatchRsp { + uint16_t mesgType; + uint16_t mesgLen; + + /* Success or Failure */ + uint32_t status; + tSirRcvFltPktMatchCnt filterMatchCnt[SIR_MAX_NUM_FILTERS]; + tSirMacAddr bssId; +} tSirRcvFltPktMatchRsp, *tpSirRcvFltPktMatchRsp; + +/* */ +/* Receive Filter Clear Parameters */ +/* */ +typedef struct sSirRcvFltPktClearParam { + uint32_t status; /* only valid for response message */ + uint8_t filterId; + tSirMacAddr selfMacAddr; + tSirMacAddr bssId; +} tSirRcvFltPktClearParam, *tpSirRcvFltPktClearParam; + +/* */ +/* Multicast Address List Parameters */ +/* */ +typedef struct sSirRcvFltMcAddrList { + uint32_t ulMulticastAddrCnt; + tSirMacAddr multicastAddr[SIR_MAX_NUM_MULTICAST_ADDRESS]; + tSirMacAddr selfMacAddr; + tSirMacAddr bssId; + uint8_t action; +} tSirRcvFltMcAddrList, *tpSirRcvFltMcAddrList; +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* */ +/* Generic version information */ +/* */ +typedef struct { + uint8_t revision; + uint8_t version; + uint8_t minor; + uint8_t major; +} tSirVersionType; + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/*--------------------------------------------------------------------------- +* WMA_GTK_OFFLOAD_REQ +*--------------------------------------------------------------------------*/ +typedef struct { + uint32_t ulFlags; /* optional flags */ + uint8_t aKCK[16]; /* Key confirmation key */ + uint8_t aKEK[16]; /* key encryption key */ + uint64_t ullKeyReplayCounter; /* replay counter */ + tSirMacAddr bssId; +} tSirGtkOffloadParams, *tpSirGtkOffloadParams; + +/** + * struct sir_wifi_start_log - Structure to store the params sent to start/ + * stop logging + * @name: Attribute which indicates the type of logging like per packet + * statistics, connectivity etc. + * @verbose_level: Verbose level which can be 0,1,2,3 + * @flag: Flag field for future use + */ +struct sir_wifi_start_log { + uint32_t ring_id; + uint32_t verbose_level; + uint32_t flag; +}; + +/** + * enum hw_mode_ss_config - Possible spatial stream configuration + * @SS_0x0: Unused Tx and Rx of MAC + * @SS_1x1: 1 Tx SS and 1 Rx SS + * @SS_2x2: 2 Tx SS and 2 Rx SS + * @SS_3x3: 3 Tx SS and 3 Rx SS + * @SS_4x4: 4 Tx SS and 4 Rx SS + * + * Note: Right now only 1x1 and 2x2 are being supported. Other modes should + * be added when supported. Asymmetric configuration like 1x2, 2x1 are also + * not supported now. But, they are still valid. Right now, Tx/Rx SS support is + * 4 bits long. So, we can go upto 15x15 + */ +enum hw_mode_ss_config { + HW_MODE_SS_0x0, + HW_MODE_SS_1x1, + HW_MODE_SS_2x2, + HW_MODE_SS_3x3, + HW_MODE_SS_4x4, +}; + +/** + * enum hw_mode_bandwidth - bandwidth of wifi channel. + * + * @HW_MODE_5_MHZ: 5 Mhz bandwidth + * @HW_MODE_10_MHZ: 10 Mhz bandwidth + * @HW_MODE_20_MHZ: 20 Mhz bandwidth + * @HW_MODE_40_MHZ: 40 Mhz bandwidth + * @HW_MODE_80_MHZ: 80 Mhz bandwidth + * @HW_MODE_80_PLUS_80_MHZ: 80 Mhz plus 80 Mhz bandwidth + * @HW_MODE_160_MHZ: 160 Mhz bandwidth + * @HW_MODE_MAX_BANDWIDTH: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum hw_mode_bandwidth { + HW_MODE_BW_NONE, + HW_MODE_5_MHZ, + HW_MODE_10_MHZ, + HW_MODE_20_MHZ, + HW_MODE_40_MHZ, + HW_MODE_80_MHZ, + HW_MODE_80_PLUS_80_MHZ, + HW_MODE_160_MHZ, + HW_MODE_MAX_BANDWIDTH +}; + +/** + * enum hw_mode_dbs_capab - DBS HW mode capability + * @HW_MODE_DBS_NONE: Non DBS capable + * @HW_MODE_DBS: DFS capable + */ +enum hw_mode_dbs_capab { + HW_MODE_DBS_NONE, + HW_MODE_DBS, +}; + +/** + * enum hw_mode_agile_dfs_capab - Agile DFS HW mode capability + * @HW_MODE_AGILE_DFS_NONE: Non Agile DFS capable + * @HW_MODE_AGILE_DFS: Agile DFS capable + */ +enum hw_mode_agile_dfs_capab { + HW_MODE_AGILE_DFS_NONE, + HW_MODE_AGILE_DFS, +}; + +/** + * enum set_hw_mode_status - Status of set HW mode command + * @SET_HW_MODE_STATUS_OK: command successful + * @SET_HW_MODE_STATUS_EINVAL: Requested invalid hw_mode + * @SET_HW_MODE_STATUS_ECANCELED: HW mode change cancelled + * @SET_HW_MODE_STATUS_ENOTSUP: HW mode not supported + * @SET_HW_MODE_STATUS_EHARDWARE: HW mode change prevented by hardware + * @SET_HW_MODE_STATUS_EPENDING: HW mode change is pending + * @SET_HW_MODE_STATUS_ECOEX: HW mode change conflict with Coex + */ +enum set_hw_mode_status { + SET_HW_MODE_STATUS_OK, + SET_HW_MODE_STATUS_EINVAL, + SET_HW_MODE_STATUS_ECANCELED, + SET_HW_MODE_STATUS_ENOTSUP, + SET_HW_MODE_STATUS_EHARDWARE, + SET_HW_MODE_STATUS_EPENDING, + SET_HW_MODE_STATUS_ECOEX, +}; + +/** + * struct sir_pcl_list - Format of PCL + * @pcl_list: List of preferred channels + * @pcl_len: Number of channels in the PCL + */ +struct sir_pcl_list { + uint8_t pcl_list[128]; + uint32_t pcl_len; +}; + +/** + * struct sir_hw_mode_params - HW mode params + * @mac0_tx_ss: MAC0 Tx spatial stream + * @mac0_rx_ss: MAC0 Rx spatial stream + * @mac1_tx_ss: MAC1 Tx spatial stream + * @mac1_rx_ss: MAC1 Rx spatial stream + * @mac0_bw: MAC0 bandwidth + * @mac1_bw: MAC1 bandwidth + * @dbs_cap: DBS capabality + * @agile_dfs_cap: Agile DFS capabality + */ +struct sir_hw_mode_params { + uint8_t mac0_tx_ss; + uint8_t mac0_rx_ss; + uint8_t mac1_tx_ss; + uint8_t mac1_rx_ss; + uint8_t mac0_bw; + uint8_t mac1_bw; + uint8_t dbs_cap; + uint8_t agile_dfs_cap; +}; + +/** + * struct sir_vdev_mac_map - vdev id-mac id map + * @vdev_id: VDEV id + * @mac_id: MAC id + */ +struct sir_vdev_mac_map { + uint32_t vdev_id; + uint32_t mac_id; +}; + +/** + * struct sir_set_hw_mode_resp - HW mode response + * @status: Status + * @cfgd_hw_mode_index: Configured HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + */ +struct sir_set_hw_mode_resp { + uint32_t status; + uint32_t cfgd_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct sir_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; +}; + +/** + * struct sir_hw_mode_trans_ind - HW mode transition indication + * @old_hw_mode_index: Index of old HW mode + * @new_hw_mode_index: Index of new HW mode + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + */ +struct sir_hw_mode_trans_ind { + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct sir_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; +}; + +/** + * struct sir_dual_mac_config_resp - Dual MAC config response + * @status: Status of setting the dual mac configuration + */ +struct sir_dual_mac_config_resp { + uint32_t status; +}; + +/*--------------------------------------------------------------------------- +* WMA_GTK_OFFLOAD_GETINFO_REQ +*--------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + + uint32_t ulStatus; /* success or failure */ + uint64_t ullKeyReplayCounter; /* current replay counter value */ + uint32_t ulTotalRekeyCount; /* total rekey attempts */ + uint32_t ulGTKRekeyCount; /* successful GTK rekeys */ + uint32_t ulIGTKRekeyCount; /* successful iGTK rekeys */ + tSirMacAddr bssId; +} tSirGtkOffloadGetInfoRspParams, *tpSirGtkOffloadGetInfoRspParams; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef WLAN_WAKEUP_EVENTS +/*--------------------------------------------------------------------------- + tSirWakeReasonInd + ---------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + uint32_t ulReason; /* see tWakeReasonType */ + uint32_t ulReasonArg; /* argument specific to the reason type */ + /* length of optional data stored in this message, in case + * HAL truncates the data (i.e. data packets) this length + * will be less than the actual length + */ + uint32_t ulStoredDataLen; + uint32_t ulActualDataLen; /* actual length of data */ + /* variable length start of data (length == storedDataLen) + * see specific wake type + */ + uint8_t aDataStart[1]; +} tSirWakeReasonInd, *tpSirWakeReasonInd; +#endif /* WLAN_WAKEUP_EVENTS */ + +/*--------------------------------------------------------------------------- + sAniSetTmLevelReq + ---------------------------------------------------------------------------*/ +typedef struct sAniSetTmLevelReq { + uint16_t tmMode; + uint16_t newTmLevel; +} tAniSetTmLevelReq, *tpAniSetTmLevelReq; + +#ifdef FEATURE_WLAN_TDLS +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsSendMgmtReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t reqType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + /* For multi-session, for PE to locate peSession ID */ + tSirMacAddr bssid; + tSirMacAddr peerMac; + /* Variable lenght. Dont add any field after this. */ + uint8_t addIe[1]; +} tSirTdlsSendMgmtReq, *tpSirSmeTdlsSendMgmtReq; + +typedef enum TdlsAddOper { + TDLS_OPER_NONE, + TDLS_OPER_ADD, + TDLS_OPER_UPDATE +} eTdlsAddOper; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsAddStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + tSirMacAddr bssid; + eTdlsAddOper tdlsAddOper; + tSirMacAddr peerMac; + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_length; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap htCap; + uint8_t vhtcap_present; + tSirVHTCap vhtCap; + uint8_t uapsd_queues; + uint8_t max_sp; +} tSirTdlsAddStaReq, *tpSirSmeTdlsAddStaReq; + +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsAddStaRsp { + uint16_t messageType; + uint16_t length; + tSirResultCodes statusCode; + tSirMacAddr peerMac; + uint8_t sessionId; /* Session ID */ + uint16_t staId; + uint16_t staType; + uint8_t ucastSig; + uint8_t bcastSig; + eTdlsAddOper tdlsAddOper; +} tSirTdlsAddStaRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t uapsdQueues; /* Peer's uapsd Queues Information */ + uint8_t maxSp; /* Peer's Supported Maximum Service Period */ + uint8_t isBufSta; /* Does Peer Support as Buffer Station. */ + /* Does Peer Support as TDLS Off Channel. */ + uint8_t isOffChannelSupported; + uint8_t isResponder; /* Is Peer a responder. */ + /* For multi-session, for PE to locate peSession ID */ + tSirMacAddr bssid; + tSirMacAddr peerMac; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[SIR_MAC_MAX_SUPP_OPER_CLASSES]; +} tSirTdlsLinkEstablishReq, *tpSirTdlsLinkEstablishReq; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tSirMacAddr peerMac; +} tSirTdlsLinkEstablishReqRsp, *tpSirTdlsLinkEstablishReqRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsDelStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + tSirMacAddr bssid; + tSirMacAddr peerMac; +} tSirTdlsDelStaReq, *tpSirSmeTdlsDelStaReq; +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsDelStaRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes statusCode; + tSirMacAddr peerMac; + uint16_t staId; +} tSirTdlsDelStaRsp, *tpSirTdlsDelStaRsp; +/* TDLS Delete Indication struct PE-->SME */ +typedef struct sSirTdlsDelStaInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirMacAddr peerMac; + uint16_t staId; + uint16_t reasonCode; +} tSirTdlsDelStaInd, *tpSirTdlsDelStaInd; +typedef struct sSirTdlsDelAllPeerInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ +} tSirTdlsDelAllPeerInd, *tpSirTdlsDelAllPeerInd; +#ifdef FEATURE_WLAN_TDLS_DISAPPEAR_AP +typedef struct sSirTdlsDisappearAPInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t staId; + tSirMacAddr staAddr; +} tSirTdlsDisappearAPInd, *tpSirTdlsDisappearAPInd; +#endif +typedef struct sSirMgmtTxCompletionInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint32_t txCompleteStatus; +} tSirMgmtTxCompletionInd, *tpSirMgmtTxCompletionInd; + +typedef struct sSirTdlsEventnotify { + uint8_t sessionId; + tSirMacAddr peerMac; + uint16_t messageType; + uint32_t peer_reason; +} tSirTdlsEventnotify; +#endif /* FEATURE_WLAN_TDLS */ + +typedef struct sSirActiveModeSetBcnFilterReq { + uint16_t messageType; + uint16_t length; + uint8_t seesionId; +} tSirSetActiveModeSetBncFilterReq, *tpSirSetActiveModeSetBncFilterReq; + +/* Reset AP Caps Changed */ +typedef struct sSirResetAPCapsChange { + uint16_t messageType; + uint16_t length; + tSirMacAddr bssId; +} tSirResetAPCapsChange, *tpSirResetAPCapsChange; + +/* / Definition for Candidate found indication from FW */ +typedef struct sSirSmeCandidateFoundInd { + uint16_t messageType; /* eWNI_SME_CANDIDATE_FOUND_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ +} tSirSmeCandidateFoundInd, *tpSirSmeCandidateFoundInd; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirWlanExcludeUnencryptParam { + bool excludeUnencrypt; + tSirMacAddr bssId; +} tSirWlanExcludeUnencryptParam, *tpSirWlanExcludeUnencryptParam; +#endif + +typedef enum { + P2P_SCAN_TYPE_SEARCH = 1, /* P2P Search */ + P2P_SCAN_TYPE_LISTEN /* P2P Listen */ +} tSirP2pScanType; + +typedef struct sAniHandoffReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t bssid[CDF_MAC_ADDR_SIZE]; + uint8_t channel; + uint8_t handoff_src; +} tAniHandoffReq, *tpAniHandoffReq; + +typedef struct sSirScanOffloadReq { + uint8_t sessionId; + tSirMacAddr bssId; + uint8_t numSsid; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + uint8_t hiddenSsid; + tSirMacAddr selfMacAddr; + tSirBssType bssType; + uint8_t dot11mode; + tSirScanType scanType; + uint32_t minChannelTime; + uint32_t maxChannelTime; + uint32_t scan_id; + /* in units of milliseconds, ignored when not connected */ + uint32_t restTime; + tSirP2pScanType p2pScanType; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + tSirChannelList channelList; + /*----------------------------- + sSirScanOffloadReq.... + ----------------------------- + uIEFieldLen + ----------------------------- + uIEFieldOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEField + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tSirScanOffloadReq, *tpSirScanOffloadReq; + +typedef enum sSirScanEventType { + SCAN_EVENT_STARTED = 0x1, /* Scan command accepted by FW */ + SCAN_EVENT_COMPLETED = 0x2, /* Scan has been completed by FW */ + SCAN_EVENT_BSS_CHANNEL = 0x4, /* FW is going to move to HOME ch */ + SCAN_EVENT_FOREIGN_CHANNEL = 0x8, /* FW going to move to FORIEGN ch */ + SCAN_EVENT_DEQUEUED = 0x10, /* scan request got dequeued */ + SCAN_EVENT_PREEMPTED = 0x20, /* preempted by high priority scan */ + SCAN_EVENT_START_FAILED = 0x40, /* scan start failed */ + SCAN_EVENT_RESTARTED = 0x80, /*scan restarted */ + SCAN_EVENT_MAX = 0x8000 +} tSirScanEventType; + +typedef struct sSirScanOffloadEvent { + tSirScanEventType event; + tSirResultCodes reasonCode; + uint32_t chanFreq; + uint32_t requestor; + uint32_t scanId; + tSirP2pScanType p2pScanType; + uint8_t sessionId; +} tSirScanOffloadEvent, *tpSirScanOffloadEvent; + +/** + * struct sSirUpdateChanParam - channel parameters + * @chanId: ID of the channel + * @pwr: power level + * @dfsSet: is dfs supported or not + * @half_rate: is the channel operating at 10MHz + * @quarter_rate: is the channel operating at 5MHz + */ +typedef struct sSirUpdateChanParam { + uint8_t chanId; + uint8_t pwr; + bool dfsSet; + bool half_rate; + bool quarter_rate; +} tSirUpdateChanParam, *tpSirUpdateChanParam; + +typedef struct sSirUpdateChan { + uint8_t numChan; + tSirUpdateChanParam chanParam[1]; +} tSirUpdateChanList, *tpSirUpdateChanList; + +typedef enum eSirAddonPsReq { + eSIR_ADDON_NOTHING, + eSIR_ADDON_ENABLE_UAPSD, + eSIR_ADDON_DISABLE_UAPSD +} tSirAddonPsReq; + +/* Powersave Offload data */ +typedef struct sSirPsReqData { + /* BSSID */ + tSirMacAddr bssId; + + /* Additional Info */ + tSirAddonPsReq addOnReq; +} tSirPsReqData, *tpSirPsReqData; + +#ifdef FEATURE_WLAN_LPHB +#define SIR_LPHB_FILTER_LEN 64 + +typedef enum { + LPHB_SET_EN_PARAMS_INDID, + LPHB_SET_TCP_PARAMS_INDID, + LPHB_SET_TCP_PKT_FILTER_INDID, + LPHB_SET_UDP_PARAMS_INDID, + LPHB_SET_UDP_PKT_FILTER_INDID, + LPHB_SET_NETWORK_INFO_INDID, +} LPHBIndType; + +typedef struct sSirLPHBEnableStruct { + uint8_t enable; + uint8_t item; + uint8_t session; +} tSirLPHBEnableStruct; + +typedef struct sSirLPHBTcpParamStruct { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t timeout; + uint8_t session; + tSirMacAddr gateway_mac; + uint16_t timePeriodSec; /* in seconds */ + uint32_t tcpSn; +} tSirLPHBTcpParamStruct; + +typedef struct sSirLPHBTcpFilterStruct { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[SIR_LPHB_FILTER_LEN]; +} tSirLPHBTcpFilterStruct; + +typedef struct sSirLPHBUdpParamStruct { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t interval; + uint16_t timeout; + uint8_t session; + tSirMacAddr gateway_mac; +} tSirLPHBUdpParamStruct; + +typedef struct sSirLPHBUdpFilterStruct { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[SIR_LPHB_FILTER_LEN]; +} tSirLPHBUdpFilterStruct; + +typedef struct sSirLPHBReq { + uint16_t cmd; + uint16_t dummy; + union { + tSirLPHBEnableStruct lphbEnableReq; + tSirLPHBTcpParamStruct lphbTcpParamReq; + tSirLPHBTcpFilterStruct lphbTcpFilterReq; + tSirLPHBUdpParamStruct lphbUdpParamReq; + tSirLPHBUdpFilterStruct lphbUdpFilterReq; + } params; +} tSirLPHBReq; + +typedef struct sSirLPHBInd { + uint8_t sessionIdx; + uint8_t protocolType; /*TCP or UDP */ + uint8_t eventReason; +} tSirLPHBInd; +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID +typedef struct sSirChAvoidUpdateReq { + uint32_t reserved_param; +} tSirChAvoidUpdateReq; +#endif /* FEATURE_WLAN_CH_AVOID */ + +typedef struct sSirLinkSpeedInfo { + /* MAC Address for the peer */ + tSirMacAddr peer_macaddr; + uint32_t estLinkSpeed; /* Linkspeed from firmware */ +} tSirLinkSpeedInfo, *tpSirLinkSpeedInfo; + +typedef struct sSirAddPeriodicTxPtrn { + /* MAC Address for the adapter */ + tSirMacAddr macAddress; + uint8_t ucPtrnId; /* Pattern ID */ + uint16_t ucPtrnSize; /* Pattern size */ + uint32_t usPtrnIntervalMs; /* In msec */ + uint8_t ucPattern[PERIODIC_TX_PTRN_MAX_SIZE]; /* Pattern buffer */ +} tSirAddPeriodicTxPtrn, *tpSirAddPeriodicTxPtrn; + +typedef struct sSirDelPeriodicTxPtrn { + /* MAC Address for the adapter */ + tSirMacAddr macAddress; + /* Bitmap of pattern IDs that need to be deleted */ + uint32_t ucPatternIdBitmap; + uint8_t ucPtrnId; /* Pattern ID */ +} tSirDelPeriodicTxPtrn, *tpSirDelPeriodicTxPtrn; + +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool suspended; +} tSirReadyToSuspendInd, *tpSirReadyToSuspendInd; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool status; +} tSirReadyToExtWoWInd, *tpSirReadyToExtWoWInd; +#endif +typedef struct sSirRateUpdateInd { + uint8_t nss; /* 0: 1x1, 1: 2x2 */ + tSirMacAddr bssid; + tCDF_CON_MODE dev_mode; + int32_t bcastDataRate; /* bcast rate unit Mbpsx10, -1:not used */ + /* + * 0 implies RA, positive value implies fixed rate, -1 implies ignore + * this param. + */ + int32_t ucastDataRate; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags ucastDataRateTxFlag; + + /* + * 0 implies MCAST RA, positive value implies fixed rate, + * -1 implies ignore this param + */ + int32_t reliableMcastDataRate; /* unit Mbpsx10 */ + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags reliableMcastDataRateTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 2.4 GHz, unit Mbpsx10, + * 0 implies ignore + */ + uint32_t mcastDataRate24GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags mcastDataRate24GHzTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 5 GHz, + * unit Mbpsx10, 0 implies ignore + */ + uint32_t mcastDataRate5GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags mcastDataRate5GHzTxFlag; + +} tSirRateUpdateInd, *tpSirRateUpdateInd; + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +#define SIR_CH_AVOID_MAX_RANGE 4 + +typedef struct sSirChAvoidFreqType { + uint32_t start_freq; + uint32_t end_freq; +} tSirChAvoidFreqType; + +typedef struct sSirChAvoidIndType { + uint32_t avoid_range_count; + tSirChAvoidFreqType avoid_freq_range[SIR_CH_AVOID_MAX_RANGE]; +} tSirChAvoidIndType; +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#define SIR_DFS_MAX_20M_SUB_CH 8 + +typedef struct sSirSmeDfsChannelList { + uint32_t nchannels; + /* Ch num including bonded channels on which the RADAR is present */ + uint8_t channels[SIR_DFS_MAX_20M_SUB_CH]; +} tSirSmeDfsChannelList, *tpSirSmeDfsChannelList; + +typedef struct sSirSmeDfsEventInd { + uint32_t sessionId; + tSirSmeDfsChannelList chan_list; + uint32_t dfs_radar_status; + int use_nol; +} tSirSmeDfsEventInd, *tpSirSmeDfsEventInd; + +typedef struct sSirChanChangeRequest { + uint16_t messageType; + uint16_t messageLen; + uint8_t targetChannel; + uint8_t cbMode; + uint8_t channel_width; + uint8_t center_freq_seg_0; + uint8_t center_freq_seg_1; + uint8_t bssid[CDF_MAC_ADDR_SIZE]; + uint32_t dot11mode; + tSirMacRateSet operational_rateset; + tSirMacRateSet extended_rateset; +} tSirChanChangeRequest, *tpSirChanChangeRequest; + +typedef struct sSirChanChangeResponse { + uint8_t sessionId; + uint8_t newChannelNumber; + uint8_t channelChangeStatus; + ePhyChanBondState secondaryChannelOffset; +} tSirChanChangeResponse, *tpSirChanChangeResponse; + +typedef struct sSirStartBeaconIndication { + uint16_t messageType; + uint16_t messageLen; + uint8_t beaconStartStatus; + uint8_t bssid[CDF_MAC_ADDR_SIZE]; +} tSirStartBeaconIndication, *tpSirStartBeaconIndication; + +/* additional IE type */ +typedef enum tUpdateIEsType { + eUPDATE_IE_NONE, + eUPDATE_IE_PROBE_BCN, + eUPDATE_IE_PROBE_RESP, + eUPDATE_IE_ASSOC_RESP, + + /* Add type above this line */ + /* this is used to reset all buffer */ + eUPDATE_IE_ALL, + eUPDATE_IE_MAX +} eUpdateIEsType; + +/* Modify particular IE in addition IE for prob resp Bcn */ +typedef struct sSirModifyIE { + tSirMacAddr bssid; + uint16_t smeSessionId; + bool notify; + uint8_t ieID; + uint8_t ieIDLen; /*ie length as per spec */ + uint16_t ieBufferlength; + uint8_t *pIEBuffer; + +} tSirModifyIE, *tpSirModifyIE; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirModifyIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirModifyIE modifyIE; + eUpdateIEsType updateType; +} tSirModifyIEsInd, *tpSirModifyIEsInd; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIE { + tSirMacAddr bssid; + uint16_t smeSessionId; + bool append; + bool notify; + uint16_t ieBufferlength; + uint8_t *pAdditionIEBuffer; +} tSirUpdateIE, *tpSirUpdateIE; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirUpdateIE updateIE; + eUpdateIEsType updateType; +} tSirUpdateIEsInd, *tpSirUpdateIEsInd; + +/* Message format for requesting channel switch announcement to lower layers */ +typedef struct sSirDfsCsaIeRequest { + uint16_t msgType; + uint16_t msgLen; + uint8_t targetChannel; + uint8_t csaIeRequired; + uint8_t bssid[CDF_MAC_ADDR_SIZE]; + uint8_t ch_bandwidth; +} tSirDfsCsaIeRequest, *tpSirDfsCsaIeRequest; + +/* Indication from lower layer indicating the completion of first beacon send + * after the beacon template update + */ +typedef struct sSirFirstBeaconTxCompleteInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bssIdx; +} tSirFirstBeaconTxCompleteInd, *tpSirFirstBeaconTxCompleteInd; + +typedef struct sSirSmeCSAIeTxCompleteRsp { + uint8_t sessionId; + uint8_t chanSwIeTxStatus; +} tSirSmeCSAIeTxCompleteRsp, *tpSirSmeCSAIeTxCompleteRsp; + +/* Thermal Mitigation*/ + +typedef struct { + uint16_t minTempThreshold; + uint16_t maxTempThreshold; +} t_thermal_level_info, *tp_thermal_level_info; + +typedef enum { + WLAN_WMA_THERMAL_LEVEL_0, + WLAN_WMA_THERMAL_LEVEL_1, + WLAN_WMA_THERMAL_LEVEL_2, + WLAN_WMA_THERMAL_LEVEL_3, + WLAN_WMA_MAX_THERMAL_LEVELS +} t_thermal_level; + +typedef struct { + /* Array of thermal levels */ + t_thermal_level_info thermalLevels[WLAN_WMA_MAX_THERMAL_LEVELS]; + uint8_t thermalCurrLevel; + uint8_t thermalMgmtEnabled; + uint32_t throttlePeriod; +} t_thermal_mgmt, *tp_thermal_mgmt; + +typedef struct sSirTxPowerLimit { + /* Thermal limits for 2g and 5g */ + uint32_t txPower2g; + uint32_t txPower5g; +} tSirTxPowerLimit; + +/* notify MODEM power state to FW */ +typedef struct { + uint32_t param; +} tSirModemPowerStateInd, *tpSirModemPowerStateInd; + +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tSirStatsExtEvent, *tpSirStatsExtEvent; +#endif + +#ifdef WLAN_FEATURE_NAN +typedef struct { + uint32_t event_data_len; + uint8_t event_data[]; +} tSirNanEvent, *tpSirNanEvent; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct sSirSmeRoamOffloadSynchInd { + uint16_t messageType; /*eWNI_SME_ROAM_OFFLOAD_SYNCH_IND */ + uint16_t length; + uint16_t beaconProbeRespOffset; + uint16_t beaconProbeRespLength; + uint16_t reassocRespOffset; + uint16_t reassocRespLength; + uint8_t isBeacon; + uint8_t roamedVdevId; + tSirMacAddr bssId; + int8_t txMgmtPower; + uint32_t authStatus; + uint8_t rssi; + uint8_t roamReason; + uint32_t chan_freq; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + tpSirBssDescription bss_desc_ptr; +} roam_offload_synch_ind; + +typedef struct sSirSmeRoamOffloadSynchCnf { + uint8_t sessionId; +} tSirSmeRoamOffloadSynchCnf, *tpSirSmeRoamOffloadSynchCnf; + +typedef struct sSirSmeHOFailureInd { + uint8_t sessionId; +} tSirSmeHOFailureInd, *tpSirSmeHOFailureInd; + +struct roam_offload_synch_fail { + uint8_t session_id; +}; + +#endif + +#ifdef FEATURE_WLAN_EXTSCAN + +/** + * typedef enum wifi_scan_flags - wifi scan flags + * @WIFI_SCAN_FLAG_INTERRUPTED: Indicates that scan results are not complete + * because probes were not sent on some channels + */ +typedef enum { + WIFI_SCAN_FLAG_INTERRUPTED = 1, +} wifi_scan_flags; + +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_A_DFS_ONLY = 4, /* 5 GHz DFS only */ + /* 5 is reserved */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ + + /* Keep it last */ + WIFI_BAND_MAX +} tWifiBand; + +/* wifi scan related events */ +typedef enum { + WIFI_SCAN_BUFFER_FULL, + WIFI_SCAN_COMPLETE, +} tWifiScanEventType; + +/** + * enum extscan_configuration_flags - extscan config flags + * @EXTSCAN_LP_EXTENDED_BATCHING: extended batching + */ +enum extscan_configuration_flags { + EXTSCAN_LP_EXTENDED_BATCHING = 0x00000001, +}; + +typedef struct { + struct cdf_mac_addr bssid; + + /* Low threshold */ + int32_t low; + + /* High threshold */ + int32_t high; +} tSirAPThresholdParam, *tpSirAPThresholdParam; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirGetExtScanCapabilitiesReqParams, *tpSirGetExtScanCapabilitiesReqParams; + +/** + * struct ext_scan_capabilities_response - extscan capabilities response data + * @requestId: request identifier + * @status: status + * @max_scan_cache_size: total space allocated for scan (in bytes) + * @max_scan_buckets: maximum number of channel buckets + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI + * @ax_scan_reporting_threshold: max possible report_threshold + * @max_hotlist_bssids: maximum number of entries for hotlist APs + * @max_significant_wifi_change_aps: maximum number of entries for + * significant wifi change APs + * @max_bssid_history_entries: number of BSSID/RSSI entries that device can hold + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs + * @max_number_epno_networks: max number of epno entries + * @max_number_epno_networks_by_ssid: max number of epno entries + * if ssid is specified, that is, epno entries for + * which an exact match is required, + * or entries corresponding to hidden ssids + * @max_number_of_white_listed_ssid: max number of white listed SSIDs + */ +struct ext_scan_capabilities_response { + uint32_t requestId; + uint32_t status; + + uint32_t max_scan_cache_size; + uint32_t max_scan_buckets; + uint32_t max_ap_cache_per_scan; + uint32_t max_rssi_sample_size; + uint32_t max_scan_reporting_threshold; + + uint32_t max_hotlist_bssids; + uint32_t max_significant_wifi_change_aps; + + uint32_t max_bssid_history_entries; + uint32_t max_hotlist_ssids; + uint32_t max_number_epno_networks; + uint32_t max_number_epno_networks_by_ssid; + uint32_t max_number_of_white_listed_ssid; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + /* + * 1 - return cached results and flush it + * 0 - return cached results and do not flush + */ + bool flush; +} tSirExtScanGetCachedResultsReqParams, *tpSirExtScanGetCachedResultsReqParams; + +typedef struct { + uint32_t requestId; + uint32_t status; +} tSirExtScanGetCachedResultsRspParams, *tpSirExtScanGetCachedResultsRspParams; + +typedef struct { + /* Time of discovery */ + uint64_t ts; + + /* Null terminated SSID */ + uint8_t ssid[SIR_MAC_MAX_SSID_LENGTH + 1]; + + struct cdf_mac_addr bssid; + + /* Frequency in MHz */ + uint32_t channel; + + /* RSSI in dBm */ + int32_t rssi; + + /* RTT in nanoseconds */ + uint32_t rtt; + + /* Standard deviation in rtt */ + uint32_t rtt_sd; + + /* Period advertised in the beacon */ + uint16_t beaconPeriod; + + /* Capabilities advertised in the beacon */ + uint16_t capability; + + uint16_t ieLength; + + uint8_t ieData[]; +} tSirWifiScanResult, *tpSirWifiScanResult; + +/** + * struct extscan_hotlist_match - extscan hotlist match + * @requestId: request identifier + * @numOfAps: number of bssids retrieved by the scan + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: wifi scan result + */ +struct extscan_hotlist_match { + uint32_t requestId; + bool moreData; + bool ap_found; + uint32_t numOfAps; + tSirWifiScanResult ap[]; +}; + +/** + * struct extscan_cached_scan_result - extscan cached scan result + * @scan_id: a unique identifier for the scan unit + * @flags: a bitmask with additional information about scan + * @num_results: number of bssids retrieved by the scan + * @ap: wifi scan bssid results info + */ +struct extscan_cached_scan_result { + uint32_t scan_id; + uint32_t flags; + uint32_t num_results; + tSirWifiScanResult *ap; +}; + +/** + * struct tSirWifiScanResultEvent - wifi scan result event + * @requestId: request identifier + * @ap_found: flag to indicate ap found or not + * true: AP was found + * false: AP was lost + * @numOfAps: number of aps + * @moreData: more data + * @ap: bssid information + * + */ +typedef struct { + uint32_t requestId; + bool ap_found; + uint32_t numOfAps; + bool moreData; + tSirWifiScanResult ap[]; +} tSirWifiScanResultEvent, *tpSirWifiScanResultEvent; + +/** + * struct extscan_cached_scan_results - extscan cached scan results + * @request_id: request identifier + * @more_data: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_scan_ids: number of scan ids + * @result: wifi scan result + */ +struct extscan_cached_scan_results { + uint32_t request_id; + bool more_data; + uint32_t num_scan_ids; + struct extscan_cached_scan_result *result; +}; + + +/** + * struct tSirWifiFullScanResultEvent - extscan full scan event + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: bssid info + * + * Reported when each probe response is received, if reportEvents + * enabled in tSirWifiScanCmdReqParams + */ +typedef struct { + uint32_t requestId; + bool moreData; + tSirWifiScanResult ap; +} tSirWifiFullScanResultEvent, *tpSirWifiFullScanResultEvent; + +/** + * struct pno_match_found - epno match found + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_results: number of bssids, driver sends this event to upper layer + * for every beacon, hence %num_results is always set to 1. + * @ap: bssid info + * + * Reported when each beacon probe response is received with + * epno match found tag. + */ +struct pno_match_found { + uint32_t request_id; + bool more_data; + uint32_t num_results; + tSirWifiScanResult ap[]; +}; + +typedef struct { + /* Frequency in MHz */ + uint32_t channel; + + uint32_t dwellTimeMs; + + /* 0 => active + 1 => passive scan; ignored for DFS */ + bool passive; + + uint8_t chnlClass; +} tSirWifiScanChannelSpec, *tpSirWifiScanChannelSpec; + +/** + * struct tSirWifiScanBucketSpec - wifi scan bucket spec + * @bucket: bucket identifier + * @band: wifi band + * @period: Desired period, in millisecond; if this is too + * low, the firmware should choose to generate results as fast as + * it can instead of failing the command byte + * for exponential backoff bucket this is the min_period + * @reportEvents: 0 => normal reporting (reporting rssi history + * only, when rssi history buffer is % full) + * 1 => same as 0 + report a scan completion event after scanning + * this bucket + * 2 => same as 1 + forward scan results + * (beacons/probe responses + IEs) in real time to HAL + * @max_period: if max_period is non zero or different than period, + * then this bucket is an exponential backoff bucket and + * the scan period will grow exponentially as per formula: + * actual_period(N) = period ^ (N/(step_count+1)) to a + * maximum period of max_period + * @exponent: for exponential back off bucket: multiplier: + * new_period = old_period * exponent + * @step_count: for exponential back off bucket, number of scans performed + * at a given period and until the exponent is applied + * @numChannels: channels to scan; these may include DFS channels + * Note that a given channel may appear in multiple buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @channels: Channel list + */ +typedef struct { + uint8_t bucket; + tWifiBand band; + uint32_t period; + uint32_t reportEvents; + uint32_t max_period; + uint32_t exponent; + uint32_t step_count; + uint32_t numChannels; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + tSirWifiScanChannelSpec channels[WLAN_EXTSCAN_MAX_CHANNELS]; +} tSirWifiScanBucketSpec, *tpSirWifiScanBucketSpec; + +/** + * struct tSirWifiScanCmdReqParams - wifi scan command request params + * @basePeriod: base timer period + * @maxAPperScan: max ap per scan + * @report_threshold_percent: report threshold + * in %, when buffer is this much full, wake up host + * @report_threshold_num_scans: report threshold number of scans + * in number of scans, wake up host after these many scans + * @requestId: request id + * @sessionId: session id + * @numBuckets: number of buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @configuration_flags: configuration flags + * @buckets: buckets array + */ +typedef struct { + uint32_t basePeriod; + uint32_t maxAPperScan; + + uint32_t report_threshold_percent; + uint32_t report_threshold_num_scans; + + uint32_t requestId; + uint8_t sessionId; + uint32_t numBuckets; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + uint32_t configuration_flags; + tSirWifiScanBucketSpec buckets[WLAN_EXTSCAN_MAX_BUCKETS]; +} tSirWifiScanCmdReqParams, *tpSirWifiScanCmdReqParams; + +/** + * struct sir_extscan_generic_response - + * Generic ExtScan Response structure + * @request_id: ID of the request + * @status: operation status returned by firmware + */ +struct sir_extscan_generic_response { + uint32_t request_id; + uint32_t status; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanStopReqParams, *tpSirExtScanStopReqParams; + +/** + * struct tSirExtScanSetBssidHotListReqParams - set hotlist request + * @requestId: request identifier + * @sessionId: session identifier + * @lost_ap_sample_size: number of samples to confirm AP loss + * @numAp: Number of hotlist APs + * @ap: hotlist APs + */ +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + uint32_t lost_ap_sample_size; + uint32_t numAp; + tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_HOTLIST_APS]; +} tSirExtScanSetBssidHotListReqParams, *tpSirExtScanSetBssidHotListReqParams; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanResetBssidHotlistReqParams, +*tpSirExtScanResetBssidHotlistReqParams; + +/** + * struct sir_ssid_hotlist_param - param for SSID Hotlist + * @ssid: SSID which is being hotlisted + * @band: Band in which the given SSID should be scanned + * @rssi_low: Low bound on RSSI + * @rssi_high: High bound on RSSI + */ +struct sir_ssid_hotlist_param { + tSirMacSSid ssid; + uint8_t band; + int32_t rssi_low; + int32_t rssi_high; +}; + +/** + * struct sir_set_ssid_hotlist_request - set SSID hotlist request struct + * @request_id: ID of the request + * @session_id: ID of the session + * @lost_ssid_sample_size: Number of consecutive scans in which the SSID + * must not be seen in order to consider the SSID "lost" + * @ssid_count: Number of valid entries in the @ssids array + * @ssids: Array that defines the SSIDs that are in the hotlist + */ +struct sir_set_ssid_hotlist_request { + uint32_t request_id; + uint8_t session_id; + uint32_t lost_ssid_sample_size; + uint32_t ssid_count; + struct sir_ssid_hotlist_param ssids[WLAN_EXTSCAN_MAX_HOTLIST_SSIDS]; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + /* Number of samples for averaging RSSI */ + uint32_t rssiSampleSize; + + /* Number of missed samples to confirm AP loss */ + uint32_t lostApSampleSize; + + /* Number of APs breaching threshold required for firmware + * to generate event + */ + uint32_t minBreaching; + + uint32_t numAp; + tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS]; +} tSirExtScanSetSigChangeReqParams, *tpSirExtScanSetSigChangeReqParams; + +typedef struct { + struct cdf_mac_addr bssid; + uint32_t channel; + uint32_t numOfRssi; + + /* Rssi history in db */ + int32_t rssi[]; +} tSirWifiSignificantChange, *tpSirWifiSignificantChange; + +typedef struct { + uint32_t requestId; + + bool moreData; + uint32_t numResults; + tSirWifiSignificantChange ap[]; +} tSirWifiSignificantChangeEvent, *tpSirWifiSignificantChangeEvent; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanResetSignificantChangeReqParams, +*tpSirExtScanResetSignificantChangeReqParams; + +typedef struct { + uint32_t requestId; + uint32_t numResultsAvailable; +} tSirExtScanResultsAvailableIndParams, *tpSirExtScanResultsAvailableIndParams; + +typedef struct { + uint32_t requestId; + uint32_t status; + uint8_t scanEventType; +} tSirExtScanOnScanEventIndParams, *tpSirExtScanOnScanEventIndParams; + +/** + * struct wifi_epno_network - enhanced pno network block + * @ssid: ssid + * @rssi_threshold: threshold for considering this SSID as found, required + * granularity for this threshold is 4dBm to 8dBm + * @flags: WIFI_PNO_FLAG_XXX + * @auth_bit_field: auth bit field for matching WPA IE + */ +struct wifi_epno_network { + tSirMacSSid ssid; + int8_t rssi_threshold; + uint8_t flags; + uint8_t auth_bit_field; +}; + +/** + * struct wifi_epno_params - enhanced pno network params + * @num_networks: number of ssids + * @networks: PNO networks + */ +struct wifi_epno_params { + uint32_t request_id; + uint32_t session_id; + uint32_t num_networks; + struct wifi_epno_network networks[]; +}; + +#define SIR_PASSPOINT_REALM_LEN 256 +#define SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define SIR_PASSPOINT_PLMN_LEN 3 +/** + * struct wifi_passpoint_network - passpoint network block + * @id: identifier of this network block + * @realm: null terminated UTF8 encoded realm, 0 if unspecified + * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified + * @plmn: mcc/mnc combination as per rules, 0s if unspecified + */ +struct wifi_passpoint_network { + uint32_t id; + uint8_t realm[SIR_PASSPOINT_REALM_LEN]; + int64_t roaming_consortium_ids[SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM]; + uint8_t plmn[SIR_PASSPOINT_PLMN_LEN]; +}; + +/** + * struct wifi_passpoint_req - passpoint request + * @request_id: request identifier + * @num_networks: number of networks + * @networks: passpoint networks + */ +struct wifi_passpoint_req { + uint32_t request_id; + uint32_t session_id; + uint32_t num_networks; + struct wifi_passpoint_network networks[]; +}; + +/** + * struct wifi_passpoint_match - wifi passpoint network match + * @id: network block identifier for the matched network + * @anqp_len: length of ANQP blob + * @ap: scan result, with channel and beacon information + * @anqp: ANQP data, in the information_element format + */ +struct wifi_passpoint_match { + uint32_t request_id; + uint32_t id; + uint32_t anqp_len; + tSirWifiScanResult ap; + uint8_t anqp[]; +}; +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +typedef struct { + uint32_t timer_val; +} tSirAutoShutdownCmdParams; + +typedef struct { + uint32_t shutdown_reason; +} tSirAutoShutdownEvtParams; +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t mpduSizeThreshold; + uint32_t aggressiveStatisticsGathering; +} tSirLLStatsSetReq, *tpSirLLStatsSetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t paramIdMask; +} tSirLLStatsGetReq, *tpSirLLStatsGetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t statsClearReqMask; + uint8_t stopReq; +} tSirLLStatsClearReq, *tpSirLLStatsClearReq; + +typedef struct { + uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH]; +} tSirScanMacOui, *tpSirScanMacOui; + +enum { + SIR_AP_RX_DATA_OFFLOAD = 0x00, + SIR_STA_RX_DATA_OFFLOAD = 0x01, +}; + +struct sir_ipa_offload_enable_disable { + uint32_t offload_type; + uint32_t vdev_id; + uint32_t enable; +}; + +/*--------------------------------------------------------------------------- + WLAN_HAL_LL_NOTIFY_STATS + ---------------------------------------------------------------------------*/ + +/******************************LINK LAYER Statistics**********************/ + +typedef int tSirWifiRadio; +typedef int tSirWifiChannel; +typedef int tSirwifiTxRate; + +/* channel operating width */ +typedef enum { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, +} tSirWifiChannelWidth; + +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} tSirWifiConnectionState; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1, +} tSirWifiRoamState; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6, +} tSirWifiInterfaceMode; + +/* set for QOS association */ +#define WIFI_CAPABILITY_QOS 0x00000001 +/* set for protected assoc (802.11 beacon frame control protected bit set) */ +#define WIFI_CAPABILITY_PROTECTED 0x00000002 +/* set if 802.11 Extended Capabilities element interworking bit is set */ +#define WIFI_CAPABILITY_INTERWORKING 0x00000004 +/* set for HS20 association */ +#define WIFI_CAPABILITY_HS20 0x00000008 +/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ +#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 +/* set is 802.11 Country Element is present */ +#define WIFI_CAPABILITY_COUNTRY 0x00000020 + +typedef struct { + /* tSirWifiInterfaceMode */ + /* interface mode */ + uint8_t mode; + /* interface mac address (self) */ + struct cdf_mac_addr macAddr; + /* tSirWifiConnectionState */ + /* connection state (valid for STA, CLI only) */ + uint8_t state; + /* tSirWifiRoamState */ + /* roaming state */ + uint32_t roaming; + /* WIFI_CAPABILITY_XXX (self) */ + uint32_t capabilities; + /* null terminated SSID */ + uint8_t ssid[33]; + /* bssid */ + struct cdf_mac_addr bssid; + /* country string advertised by AP */ + uint8_t apCountryStr[WNI_CFG_COUNTRY_CODE_LEN]; + /* country string for this association */ + uint8_t countryStr[WNI_CFG_COUNTRY_CODE_LEN]; +} tSirWifiInterfaceInfo, *tpSirWifiInterfaceInfo; + +/* channel information */ +typedef struct { + /* channel width (20, 40, 80, 80+80, 160) */ + tSirWifiChannelWidth width; + /* primary 20 MHz channel */ + tSirWifiChannel centerFreq; + /* center frequency (MHz) first segment */ + tSirWifiChannel centerFreq0; + /* center frequency (MHz) second segment */ + tSirWifiChannel centerFreq1; +} tSirWifiChannelInfo, *tpSirWifiChannelInfo; + +/* wifi rate info */ +typedef struct { + /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + uint32_t preamble:3; + /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + uint32_t nss:2; + /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + uint32_t bw:3; + /* OFDM/CCK rate code would be as per ieee std in units of 0.5mbps */ + /* HT/VHT it would be mcs index */ + uint32_t rateMcsIdx:8; + /* reserved */ + uint32_t reserved:16; + /* units of 100 Kbps */ + uint32_t bitrate; +} tSirWifiRate, *tpSirWifiRate; + +/* channel statistics */ +typedef struct { + /* channel */ + tSirWifiChannelInfo channel; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the CCA register is busy (32 bits number accruing over time) */ + uint32_t ccaBusyTime; +} tSirWifiChannelStats, *tpSirWifiChannelStats; + +/* radio statistics */ +typedef struct { + /* wifi radio (if multiple radio supported) */ + tSirWifiRadio radio; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the radio is transmitting + * (32 bits number accruing over time) + */ + uint32_t txTime; + /* msecs the radio is in active receive + *(32 bits number accruing over time) + */ + uint32_t rxTime; + /* msecs the radio is awake due to all scan + * (32 bits number accruing over time) + */ + uint32_t onTimeScan; + /* msecs the radio is awake due to NAN + * (32 bits number accruing over time) + */ + uint32_t onTimeNbd; + /* msecs the radio is awake due to Gscan + * (32 bits number accruing over time) + */ + uint32_t onTimeGscan; + /* msecs the radio is awake due to roam?scan + * (32 bits number accruing over time) + */ + uint32_t onTimeRoamScan; + /* msecs the radio is awake due to PNO scan + * (32 bits number accruing over time) + */ + uint32_t onTimePnoScan; + /* msecs the radio is awake due to HS2.0 scans and GAS exchange + * (32 bits number accruing over time) + */ + uint32_t onTimeHs20; + /* number of channels */ + uint32_t numChannels; + /* channel statistics tSirWifiChannelStats */ + tSirWifiChannelStats channels[0]; +} tSirWifiRadioStat, *tpSirWifiRadioStat; + +/* per rate statistics */ +typedef struct { + /* rate information */ + tSirWifiRate rate; + /* number of successfully transmitted data pkts (ACK rcvd) */ + uint32_t txMpdu; + /* number of received data pkts */ + uint32_t rxMpdu; + /* number of data packet losses (no ACK) */ + uint32_t mpduLost; + /* total number of data pkt retries * */ + uint32_t retries; + /* number of short data pkt retries */ + uint32_t retriesShort; + /* number of long data pkt retries */ + uint32_t retriesLong; +} tSirWifiRateStat, *tpSirWifiRateStat; + +/* access categories */ +typedef enum { + WIFI_AC_VO = 0, + WIFI_AC_VI = 1, + WIFI_AC_BE = 2, + WIFI_AC_BK = 3, + WIFI_AC_MAX = 4, +} tSirWifiTrafficAc; + +/* wifi peer type */ +typedef enum { + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID, +} tSirWifiPeerType; + +/* per peer statistics */ +typedef struct { + /* peer type (AP, TDLS, GO etc.) */ + tSirWifiPeerType type; + /* mac address */ + struct cdf_mac_addr peerMacAddress; + /* peer WIFI_CAPABILITY_XXX */ + uint32_t capabilities; + /* number of rates */ + uint32_t numRate; + /* per rate statistics, number of entries = num_rate */ + tSirWifiRateStat rateStats[0]; +} tSirWifiPeerInfo, *tpSirWifiPeerInfo; + +/* per access category statistics */ +typedef struct { + /* tSirWifiTrafficAc */ + /* access category (VI, VO, BE, BK) */ + uint32_t ac; + /* number of successfully transmitted unicast data pkts (ACK rcvd) */ + uint32_t txMpdu; + /* number of received unicast mpdus */ + uint32_t rxMpdu; + /* number of succesfully transmitted multicast data packets */ + /* STA case: implies ACK received from AP for the unicast */ + /* packet in which mcast pkt was sent */ + uint32_t txMcast; + /* number of received multicast data packets */ + uint32_t rxMcast; + /* number of received unicast a-mpdus */ + uint32_t rxAmpdu; + /* number of transmitted unicast a-mpdus */ + uint32_t txAmpdu; + /* number of data pkt losses (no ACK) */ + uint32_t mpduLost; + /* total number of data pkt retries */ + uint32_t retries; + /* number of short data pkt retries */ + uint32_t retriesShort; + /* number of long data pkt retries */ + uint32_t retriesLong; + /* data pkt min contention time (usecs) */ + uint32_t contentionTimeMin; + /* data pkt max contention time (usecs) */ + uint32_t contentionTimeMax; + /* data pkt avg contention time (usecs) */ + uint32_t contentionTimeAvg; + /* num of data pkts used for contention statistics */ + uint32_t contentionNumSamples; +} tSirWifiWmmAcStat, *tpSirWifiWmmAcStat; + +/* Interface statistics - corresponding to 2nd most + * LSB in wifi statistics bitmap for getting statistics + */ +typedef struct { + /* current state of the interface */ + tSirWifiInterfaceInfo info; + /* access point beacon received count from connected AP */ + uint32_t beaconRx; + /* access point mgmt frames received count from */ + /* connected AP (including Beacon) */ + uint32_t mgmtRx; + /* action frames received count */ + uint32_t mgmtActionRx; + /* action frames transmit count */ + uint32_t mgmtActionTx; + /* access Point Beacon and Management frames RSSI (averaged) */ + uint32_t rssiMgmt; + /* access Point Data Frames RSSI (averaged) from connected AP */ + uint32_t rssiData; + /* access Point ACK RSSI (averaged) from connected AP */ + uint32_t rssiAck; + /* number of peers */ + uint32_t num_peers; + /* + * Indicates how many peer_stats events will be sent depending on the + * num_peers. + */ + uint32_t num_peer_events; + /* number of ac */ + uint32_t num_ac; + /* Roaming Stat */ + uint32_t roam_state; + /* + * Average Beacon spread offset is the averaged time delay between TBTT + * and beacon TSF. Upper 32 bits of averaged 64 bit beacon spread offset + */ + uint32_t avg_bcn_spread_offset_high; + /* Lower 32 bits of averaged 64 bit beacon spread offset */ + uint32_t avg_bcn_spread_offset_low; + /* + * Takes value of 1 if AP leaks packets after sending an ACK for PM=1 + * otherwise 0 + */ + uint32_t is_leaky_ap; + /* + * Average number of frames received from AP after receiving the ACK + * for a frame with PM = 1 + */ + uint32_t avg_rx_frms_leaked; + /* + * Rx leak watch window currently in force to minimize data loss + * because of leaky AP. Rx leak window is the + * time driver waits before shutting down the radio or switching + * the channel and after receiving an ACK for + * a data frame with PM bit set. + */ + uint32_t rx_leak_window; + /* per ac data packet statistics */ + tSirWifiWmmAcStat AccessclassStats[WIFI_AC_MAX]; +} tSirWifiIfaceStat, *tpSirWifiIfaceStat; + +/* Peer statistics - corresponding to 3rd most LSB in + * wifi statistics bitmap for getting statistics + */ +typedef struct { + /* number of peers */ + uint32_t numPeers; + /* per peer statistics */ + tSirWifiPeerInfo peerInfo[0]; +} tSirWifiPeerStat, *tpSirWifiPeerStat; + +/* wifi statistics bitmap for getting statistics */ +#define WMI_LINK_STATS_RADIO 0x00000001 +#define WMI_LINK_STATS_IFACE 0x00000002 +#define WMI_LINK_STATS_ALL_PEER 0x00000004 +#define WMI_LINK_STATS_PER_PEER 0x00000008 + +/* wifi statistics bitmap for clearing statistics */ +/* all radio statistics */ +#define WIFI_STATS_RADIO 0x00000001 +/* cca_busy_time (within radio statistics) */ +#define WIFI_STATS_RADIO_CCA 0x00000002 +/* all channel statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_CHANNELS 0x00000004 +/* all scan statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_SCAN 0x00000008 +/* all interface statistics */ +#define WIFI_STATS_IFACE 0x00000010 +/* all tx rate statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_TXRATE 0x00000020 +/* all ac statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_AC 0x00000040 +/* all contention (min, max, avg) statistics (within ac statistics) */ +#define WIFI_STATS_IFACE_CONTENTION 0x00000080 + +typedef struct { + uint32_t paramId; + uint8_t ifaceId; + uint32_t rspId; + uint32_t moreResultToFollow; + union { + uint32_t num_peers; + uint32_t num_radio; + }; + + uint32_t peer_event_number; + /* Variable length field - Do not add anything after this */ + uint8_t results[0]; +} tSirLLStatsResults, *tpSirLLStatsResults; + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +typedef struct sAniGetLinkStatus { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t linkStatus; + uint8_t sessionId; +} tAniGetLinkStatus, *tpAniGetLinkStatus; + +#ifdef DHCP_SERVER_OFFLOAD +typedef struct { + uint32_t vdev_id; + uint32_t dhcpSrvOffloadEnabled; + uint32_t dhcpClientNum; + uint32_t dhcpSrvIP; +} tSirDhcpSrvOffloadInfo, *tpSirDhcpSrvOffloadInfo; +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +typedef struct { + uint32_t reqId; + /* pattern identifier. 0: disconnected 1: connected */ + uint32_t pattern_id; + uint32_t led_x0; /* led flashing parameter0 */ + uint32_t led_x1; /* led flashing parameter1 */ +} tSirLedFlashingReq, *tpSirLedFlashingReq; +#endif +/* find the size of given member within a structure */ +#ifndef member_size +#define member_size(type, member) (sizeof(((type *)0)->member)) +#endif + +#define RTT_INVALID 0x00 +#define RTT_TIMING_MEAS_CAPABILITY 0x01 +#define RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY 0x02 +#define RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY 0x03 + +/** + * enum fine_time_meas_mask - bit mask to identify device's + * fine timing measurement capability + * @FINE_TIME_MEAS_STA_INITIATOR - STA role, Initiator capability is supported + * @FINE_TIME_MEAS_STA_RESPONDER - STA role, Responder capability is supported + * @FINE_TIME_MEAS_P2PCLI_INITIATOR - P2P-CLI supports initiator capability + * @FINE_TIME_MEAS_P2PCLI_RESPONDER - P2P-CLI supports responder capability + * @FINE_TIME_MEAS_P2PGO_INITIATOR - P2P-GO supports initiator capability + * @FINE_TIME_MEAS_P2PGO_RESPONDER - P2P-GO supports responder capability + * @FINE_TIME_MEAS_SAP_INITIATOR - SAP role, Initiator capability is supported + * @FINE_TIME_MEAS_SAP_RESPONDER - SAP role, Responder capability is supported + */ +enum fine_time_meas_mask { + FINE_TIME_MEAS_STA_INITIATOR = (1 << (0)), + FINE_TIME_MEAS_STA_RESPONDER = (1 << (1)), + FINE_TIME_MEAS_P2PCLI_INITIATOR = (1 << (2)), + FINE_TIME_MEAS_P2PCLI_RESPONDER = (1 << (3)), + FINE_TIME_MEAS_P2PGO_INITIATOR = (1 << (4)), + FINE_TIME_MEAS_P2PGO_RESPONDER = (1 << (5)), + FINE_TIME_MEAS_SAP_INITIATOR = (1 << (6)), + FINE_TIME_MEAS_SAP_RESPONDER = (1 << (7)), +}; + +/* number of neighbor reports that we can handle in Neighbor Report Response */ +#define MAX_SUPPORTED_NEIGHBOR_RPT 15 + +/** + * struct sir_stats_avg_factor + * @vdev_id: session id + * @stats_avg_factor: average factor + */ +struct sir_stats_avg_factor { + uint8_t vdev_id; + uint16_t stats_avg_factor; +}; + +/** + * struct sir_guard_time_request + * @vdev_id: session id + * @guard_time: guard time + */ +struct sir_guard_time_request { + uint8_t vdev_id; + uint32_t guard_time; +}; + +/* Max number of rates allowed in Supported Rates IE */ +#define MAX_NUM_SUPPORTED_RATES (8) + +/* + * struct rssi_monitor_req - rssi monitoring + * @request_id: request id + * @session_id: session id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +struct rssi_monitor_req { + uint32_t request_id; + uint32_t session_id; + int8_t min_rssi; + int8_t max_rssi; + bool control; +}; + +/** + * struct rssi_breach_event - rssi breached event structure + * @request_id: request id + * @session_id: session id + * @curr_rssi: current rssi + * @curr_bssid: current bssid + */ +struct rssi_breach_event { + uint32_t request_id; + uint32_t session_id; + int8_t curr_rssi; + struct cdf_mac_addr curr_bssid; +}; + +#define MAX_NUM_FW_SEGMENTS 4 + +/** + * struct fw_dump_seg_req - individual segment details + * @seg_id - segment id. + * @seg_start_addr_lo - lower address of the segment. + * @seg_start_addr_hi - higher address of the segment. + * @seg_length - length of the segment. + * @dst_addr_lo - lower address of the destination buffer. + * @dst_addr_hi - higher address of the destination buffer. + * + * This structure carries the information to firmware about the + * individual segments. This structure is part of firmware memory + * dump request. + */ +struct fw_dump_seg_req { + uint8_t seg_id; + uint32_t seg_start_addr_lo; + uint32_t seg_start_addr_hi; + uint32_t seg_length; + uint32_t dst_addr_lo; + uint32_t dst_addr_hi; +}; + +/** + * struct fw_dump_req - firmware memory dump request details. + * @request_id - request id. + * @num_seg - requested number of segments. + * @fw_dump_seg_req - individual segment information. + * + * This structure carries information about the firmware + * memory dump request. + */ +struct fw_dump_req { + uint32_t request_id; + uint32_t num_seg; + struct fw_dump_seg_req segment[MAX_NUM_FW_SEGMENTS]; +}; + +/** + * struct fw_dump_rsp - firmware dump response details. + * @request_id - request id. + * @dump_complete - copy completion status. + * + * This structure is used to store the firmware dump copy complete + * response from the firmware. + */ +struct fw_dump_rsp { + uint32_t request_id; + uint32_t dump_complete; +}; + +/** + * struct vdev_ie_info - IE info + * @vdev_id - vdev for which the IE is being sent + * @ie_id - ID of the IE + * @length - length of the IE data + * @data - IE data + * + * This structure is used to store the IE information. + */ +struct vdev_ie_info { + uint32_t vdev_id; + uint32_t ie_id; + uint32_t length; + uint8_t *data; +}; + +/** + * struct send_extcap_ie - used to pass send_extcap_ie msg from SME to PE + * @type - MSG type + * @length - length of the message + * @seesion_id - session_id for which the message is intended for + * + * This structure is used to pass send_extcap_ie msg from SME to PE + */ +struct send_extcap_ie { + uint16_t msg_type; /* eWNI_SME_SET_IE_REQ */ + uint16_t length; + uint8_t session_id; +}; + +typedef void (*hw_mode_cb)(uint32_t status, uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map); +typedef void (*hw_mode_transition_cb)(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map); +typedef void (*dual_mac_cb)(uint32_t status, uint32_t scan_config, + uint32_t fw_mode_config); + +/** + * struct sir_nss_update_request + * @msgType: nss update msg type + * @msgLen: length of the msg + * @new_nss: new spatial stream value + * @vdev_id: session id + */ +struct sir_nss_update_request { + uint16_t msgType; + uint16_t msgLen; + uint8_t new_nss; + uint32_t vdev_id; +}; + +/** + * struct sir_beacon_tx_complete_rsp + * + * @session_id: session for which beacon update happened + * @tx_status: status of the beacon tx from FW + */ +struct sir_beacon_tx_complete_rsp { + uint8_t session_id; + uint8_t tx_status; +}; + +typedef void (*nss_update_cb)(void *context, uint8_t tx_status, uint8_t vdev_id, + uint8_t next_action); + +/** + * OCB structures + */ + +#define NUM_AC (4) +#define OCB_CHANNEL_MAX (5) + +struct sir_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct sir_ocb_set_config_response + * @status: response status + */ +struct sir_ocb_set_config_response { + uint8_t status; +}; + +/** Callback for the dcc_stats_event */ +typedef void (*dcc_stats_event_callback_t)(void *hdd_ctx, uint32_t vdev_id, + uint32_t num_channels, uint32_t stats_per_channel_array_len, + const void *stats_per_channel_array); + +/** + * struct sir_ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (dBm) + * @min_pwr: minimum transmit power of the channel (dBm) + * @reg_pwr: maximum transmit power specified by the regulatory domain (dBm) + * @antenna_max: maximum antenna gain specified by the regulatory domain (dB) + */ +struct sir_ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + tSirMacAddr mac_address; + struct sir_qos_params qos_params[MAX_NUM_AC]; + uint32_t max_pwr; + uint32_t min_pwr; + uint8_t reg_pwr; + uint8_t antenna_max; + uint16_t flags; +}; + +/** + * OCB_CHANNEL_FLAG_NO_RX_HDR - Don't add the RX stats header to packets + * received on this channel. + */ +#define OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR (1 << 0) + +/** + * struct sir_ocb_config_sched + * @chan_freq: frequency of the channel + * @total_duration: duration of the schedule + * @guard_interval: guard interval on the start of the schedule + */ +struct sir_ocb_config_sched { + uint32_t chan_freq; + uint32_t total_duration; + uint32_t guard_interval; +}; + +/** + * struct sir_ocb_config + * @session_id: session id + * @channel_count: number of channels + * @schedule_size: size of the channel schedule + * @flags: reserved + * @channels: array of OCB channels + * @schedule: array of OCB schedule elements + * @dcc_ndl_chan_list_len: size of the ndl_chan array + * @dcc_ndl_chan_list: array of dcc channel info + * @dcc_ndl_active_state_list_len: size of the active state array + * @dcc_ndl_active_state_list: array of active states + * @adapter: the OCB adapter + * @dcc_stats_callback: callback for the response event + */ +struct sir_ocb_config { + uint8_t session_id; + uint32_t channel_count; + uint32_t schedule_size; + uint32_t flags; + struct sir_ocb_config_channel *channels; + struct sir_ocb_config_sched *schedule; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/* The size of the utc time in bytes. */ +#define SIZE_UTC_TIME (10) +/* The size of the utc time error in bytes. */ +#define SIZE_UTC_TIME_ERROR (5) + +/** + * struct sir_ocb_utc + * @vdev_id: session id + * @utc_time: number of nanoseconds from Jan 1st 1958 + * @time_error: the error in the UTC time. All 1's for unknown + */ +struct sir_ocb_utc { + uint32_t vdev_id; + uint8_t utc_time[SIZE_UTC_TIME]; + uint8_t time_error[SIZE_UTC_TIME_ERROR]; +}; + +/** + * struct sir_ocb_timing_advert + * @vdev_id: session id + * @chan_freq: frequency on which to advertise + * @repeat_rate: the number of times it will send TA in 5 seconds + * @timestamp_offset: offset of the timestamp field in the TA frame + * @time_value_offset: offset of the time_value field in the TA frame + * @template_length: size in bytes of the TA frame + * @template_value: the TA frame + */ +struct sir_ocb_timing_advert { + uint32_t vdev_id; + uint32_t chan_freq; + uint32_t repeat_rate; + uint32_t timestamp_offset; + uint32_t time_value_offset; + uint32_t template_length; + uint8_t *template_value; +}; + +/** + * struct sir_ocb_get_tsf_timer_response + * @vdev_id: session id + * @timer_high: higher 32-bits of the timer + * @timer_low: lower 32-bits of the timer + */ +struct sir_ocb_get_tsf_timer_response { + uint32_t vdev_id; + uint32_t timer_high; + uint32_t timer_low; +}; + +/** + * struct sir_ocb_get_tsf_timer + * @vdev_id: session id + */ +struct sir_ocb_get_tsf_timer { + uint32_t vdev_id; +}; + +/** + * struct sir_dcc_get_stats_response + * @vdev_id: session id + * @num_channels: number of dcc channels + * @channel_stats_array_len: size in bytes of the stats array + * @channel_stats_array: the stats array + */ +struct sir_dcc_get_stats_response { + uint32_t vdev_id; + uint32_t num_channels; + uint32_t channel_stats_array_len; + void *channel_stats_array; +}; + +/** + * struct sir_dcc_get_stats + * @vdev_id: session id + * @channel_count: number of dcc channels + * @request_array_len: size in bytes of the request array + * @request_array: the request array + */ +struct sir_dcc_get_stats { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t request_array_len; + void *request_array; +}; + +/** + * struct sir_dcc_clear_stats + * @vdev_id: session id + * @dcc_stats_bitmap: bitmap of clear option + */ +struct sir_dcc_clear_stats { + uint32_t vdev_id; + uint32_t dcc_stats_bitmap; +}; + +/** + * struct sir_dcc_update_ndl_response + * @vdev_id: session id + * @status: response status + */ +struct sir_dcc_update_ndl_response { + uint32_t vdev_id; + uint32_t status; +}; + +/** + * struct sir_dcc_update_ndl + * @vdev_id: session id + * @channel_count: number of channels to be updated + * @dcc_ndl_chan_list_len: size in bytes of the ndl_chan array + * @dcc_ndl_chan_list: the ndl_chan array + * @dcc_ndl_active_state_list_len: size in bytes of the active_state array + * @dcc_ndl_active_state_list: the active state array + */ +struct sir_dcc_update_ndl { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/** + * enum powersave_qpower_mode: QPOWER modes + * @QPOWER_DISABLED: Qpower is disabled + * @QPOWER_ENABLED: Qpower is enabled + * @QPOWER_DUTY_CYCLING: Qpower is enabled with duty cycling + */ +enum powersave_qpower_mode { + QPOWER_DISABLED = 0, + QPOWER_ENABLED = 1, + QPOWER_DUTY_CYCLING = 2 +}; + +/** + * enum powersave_qpower_mode: powersave_mode + * @PS_NOT_SUPPORTED: Power save is not supported + * @PS_LEGACY_NODEEPSLEEP: Legacy power save enabled and deep sleep disabled + * @PS_QPOWER_NODEEPSLEEP: QPOWER enabled and deep sleep disabled + * @PS_LEGACY_DEEPSLEEP: Legacy power save enabled and deep sleep enabled + * @PS_QPOWER_DEEPSLEEP: QPOWER enabled and deep sleep enabled + * @PS_DUTY_CYCLING_QPOWER: QPOWER enabled in duty cycling mode + */ +enum powersave_mode { + PS_NOT_SUPPORTED = 0, + PS_LEGACY_NODEEPSLEEP = 1, + PS_QPOWER_NODEEPSLEEP = 2, + PS_LEGACY_DEEPSLEEP = 3, + PS_QPOWER_DEEPSLEEP = 4, + PS_DUTY_CYCLING_QPOWER = 5 +}; + +#endif /* __SIR_API_H */ diff --git a/core/mac/inc/sir_mac_prop_exts.h b/core/mac/inc/sir_mac_prop_exts.h new file mode 100644 index 0000000000..dd24a87904 --- /dev/null +++ b/core/mac/inc/sir_mac_prop_exts.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_mac_prop_exts.h contains the MAC protocol + * extensions to support ANI feature set. + * Author: Chandra Modumudi + * Date: 11/27/02 + */ +#ifndef __MAC_PROP_EXTS_H +#define __MAC_PROP_EXTS_H + +#include "sir_types.h" +#include "sir_api.h" +#include "ani_system_defs.h" + +/* / EID (Element ID) definitions */ + +#define PROP_CAPABILITY_GET(bitname, value) \ + (((value) >> SIR_MAC_PROP_CAPABILITY_ ## bitname) & 1) + +#define IS_DOT11_MODE_HT(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11N) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11N_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#ifdef WLAN_FEATURE_11AC +#define IS_DOT11_MODE_VHT(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) +#endif + +#define IS_DOT11_MODE_11B(dot11Mode) \ + ((dot11Mode == WNI_CFG_DOT11_MODE_11B) ? true:false) + +#define IS_BSS_VHT_CAPABLE(vhtCaps) \ + ((vhtCaps).present && \ + ((vhtCaps).rxMCSMap != 0xFFFF) && \ + ((vhtCaps).txMCSMap != 0xFFFF)) + +#define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 +#define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 + +/* / Proprietary IE definition */ +typedef struct sSirMacPropIE { + uint8_t elementID; /* SIR_MAC_ANI_PROP_IE_EID */ + uint8_t length; + uint8_t oui[3]; /* ANI_OUI for Airgo products */ + uint8_t info[1]; +} tSirMacPropIE, *tpSirMacPropIE; + +typedef struct sSirMacPropRateSet { + uint8_t numPropRates; + uint8_t propRate[8]; +} tSirMacPropRateSet, *tpSirMacPropRateSet; + +#define SIR_PROP_VERSION_STR_MAX 20 +typedef struct sSirMacPropVersion { + uint32_t chip_rev; /* board, chipset info */ + uint8_t card_type; /* Type of Card */ + /* build version string */ + uint8_t build_version[SIR_PROP_VERSION_STR_MAX]; +} tSirMacPropVersion, *tpSirMacPropVersion; + +/* Default value for gLimRestoreCBNumScanInterval */ +#define LIM_RESTORE_CB_NUM_SCAN_INTERVAL_DEFAULT 2 + +/* generic proprietary IE structure definition */ +typedef struct sSirPropIEStruct { + uint8_t propRatesPresent:1; + uint8_t apNamePresent:1; + uint8_t loadBalanceInfoPresent:1; + uint8_t versionPresent:1; + uint8_t edcaParamPresent:1; + uint8_t capabilityPresent:1; + uint8_t propChannelSwitchPresent:1; + uint8_t triggerStaScanPresent:1; + uint8_t rsvd:8; + + tSirMacPropRateSet propRates; + tAniApName apName; /* used in beacon/probe only */ + uint16_t capability; /* capability bit map */ + tSirMacPropVersion version; + tSirMacEdcaParamSetIE edca; + uint8_t triggerStaScanEnable; + +} tSirPropIEStruct, *tpSirPropIEStruct; + +#endif /* __MAC_PROP_EXTS_H */ diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h new file mode 100644 index 0000000000..ccc2dcefbf --- /dev/null +++ b/core/mac/inc/sir_mac_prot_def.h @@ -0,0 +1,2192 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +/* + * This file sir_mac_prot_def.h contains the MAC/PHY protocol + * definitions used across various projects. + */ + +#ifndef __MAC_PROT_DEFS_H +#define __MAC_PROT_DEFS_H + +#include + +#include "cds_api.h" +#include "sir_types.h" +#include "wni_cfg.h" + +/* /Capability information related */ +#define CAPABILITY_INFO_DELAYED_BA_BIT 14 +#define CAPABILITY_INFO_IMMEDIATE_BA_BIT 15 + +/* / 11h MAC defaults */ +#define SIR_11A_CHANNEL_BEGIN 34 +#define SIR_11A_CHANNEL_END 165 +#define SIR_11B_CHANNEL_BEGIN 1 +#define SIR_11B_CHANNEL_END 14 +#define SIR_11A_FREQUENCY_OFFSET 4 +#define SIR_11B_FREQUENCY_OFFSET 1 +#define SIR_11P_CHANNEL_BEGIN 170 +#define SIR_11P_CHANNEL_END 184 + +/* / Current version of 802.11 */ +#define SIR_MAC_PROTOCOL_VERSION 0 + +/* Frame Type definitions */ + +#define SIR_MAC_MGMT_FRAME 0x0 +#define SIR_MAC_CTRL_FRAME 0x1 +#define SIR_MAC_DATA_FRAME 0x2 + +#define SIR_MAC_FRAME_TYPE_START 0x0 +#define SIR_MAC_FRAME_TYPE_END 0x3 + +/* Control frame subtype definitions */ + +#define SIR_MAC_CTRL_RR 4 +#define SIR_MAC_CTRL_BAR 8 +#define SIR_MAC_CTRL_BA 9 +#define SIR_MAC_CTRL_PS_POLL 10 +#define SIR_MAC_CTRL_RTS 11 +#define SIR_MAC_CTRL_CTS 12 +#define SIR_MAC_CTRL_ACK 13 +#define SIR_MAC_CTRL_CF_END 14 +#define SIR_MAC_CTRL_CF_END_ACK 15 + +#define SIR_MAC_MAX_DURATION_MICRO_SECONDS 32767 + +/* Data frame subtype definitions */ +#define SIR_MAC_DATA_DATA 0 +#define SIR_MAC_DATA_DATA_ACK 1 +#define SIR_MAC_DATA_DATA_POLL 2 +#define SIR_MAC_DATA_DATA_ACK_POLL 3 +#define SIR_MAC_DATA_NULL 4 +#define SIR_MAC_DATA_NULL_ACK 5 +#define SIR_MAC_DATA_NULL_POLL 6 +#define SIR_MAC_DATA_NULL_ACK_POLL 7 +#define SIR_MAC_DATA_QOS_DATA 8 +#define SIR_MAC_DATA_QOS_DATA_ACK 9 +#define SIR_MAC_DATA_QOS_DATA_POLL 10 +#define SIR_MAC_DATA_QOS_DATA_ACK_POLL 11 +#define SIR_MAC_DATA_QOS_NULL 12 +#define SIR_MAC_DATA_QOS_NULL_ACK 13 +#define SIR_MAC_DATA_QOS_NULL_POLL 14 +#define SIR_MAC_DATA_QOS_NULL_ACK_POLL 15 + +#define SIR_MAC_FRAME_SUBTYPE_START 0 +#define SIR_MAC_FRAME_SUBTYPE_END 16 + +#define SIR_MAC_DATA_QOS_MASK 8 +#define SIR_MAC_DATA_NULL_MASK 4 +#define SIR_MAC_DATA_POLL_MASK 2 +#define SIR_MAC_DATA_ACK_MASK 1 + +/* Management frame subtype definitions */ + +#define SIR_MAC_MGMT_ASSOC_REQ 0x0 +#define SIR_MAC_MGMT_ASSOC_RSP 0x1 +#define SIR_MAC_MGMT_REASSOC_REQ 0x2 +#define SIR_MAC_MGMT_REASSOC_RSP 0x3 +#define SIR_MAC_MGMT_PROBE_REQ 0x4 +#define SIR_MAC_MGMT_PROBE_RSP 0x5 +#define SIR_MAC_MGMT_TIME_ADVERT 0x6 +#define SIR_MAC_MGMT_BEACON 0x8 +#define SIR_MAC_MGMT_ATIM 0x9 +#define SIR_MAC_MGMT_DISASSOC 0xA +#define SIR_MAC_MGMT_AUTH 0xB +#define SIR_MAC_MGMT_DEAUTH 0xC +#define SIR_MAC_MGMT_ACTION 0xD +#define SIR_MAC_MGMT_RESERVED15 0xF + +/* Action frame categories */ + +#define SIR_MAC_ACTION_SPECTRUM_MGMT 0 +#define SIR_MAC_ACTION_QOS_MGMT 1 +#define SIR_MAC_ACTION_DLP 2 +#define SIR_MAC_ACTION_PUBLIC_USAGE 4 +#define SIR_MAC_ACTION_RRM 5 +#define SIR_MAC_ACTION_FAST_BSS_TRNST 6 +#define SIR_MAC_ACTION_HT 7 +#define SIR_MAC_ACTION_SA_QUERY 8 +#define SIR_MAC_ACTION_PROT_DUAL_PUB 9 +#define SIR_MAC_ACTION_WNM 10 +#define SIR_MAC_ACTION_UNPROT_WNM 11 +#define SIR_MAC_ACTION_TDLS 12 +#define SIR_MAC_ACITON_MESH 13 +#define SIR_MAC_ACTION_MHF 14 +#define SIR_MAC_SELF_PROTECTED 15 +#define SIR_MAC_ACTION_WME 17 +#define SIR_MAC_ACTION_VHT 21 + +/* QoS management action codes */ + +#define SIR_MAC_QOS_ADD_TS_REQ 0 +#define SIR_MAC_QOS_ADD_TS_RSP 1 +#define SIR_MAC_QOS_DEL_TS_REQ 2 +#define SIR_MAC_QOS_SCHEDULE 3 +#define SIR_MAC_QOS_MAP_CONFIGURE 4 +/* and these are proprietary */ +#define SIR_MAC_QOS_DEF_BA_REQ 4 +#define SIR_MAC_QOS_DEF_BA_RSP 5 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_ACTION_MEASURE_REQUEST_ID 0 +#define SIR_MAC_ACTION_MEASURE_REPORT_ID 1 +#define SIR_MAC_ACTION_TPC_REQUEST_ID 2 +#define SIR_MAC_ACTION_TPC_REPORT_ID 3 +#endif /* ANI_SUPPORT_11H */ +#define SIR_MAC_ACTION_CHANNEL_SWITCH_ID 4 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_BASIC_MEASUREMENT_TYPE 0 +#define SIR_MAC_CCA_MEASUREMENT_TYPE 1 +#define SIR_MAC_RPI_MEASUREMENT_TYPE 2 +#endif /* ANI_SUPPORT_11H */ + +/* RRM related. */ +/* Refer IEEE Std 802.11k-2008, Section 7.3.2.21, table 7.29 */ +#if defined WLAN_FEATURE_VOWIFI + +#define SIR_MAC_RRM_CHANNEL_LOAD_TYPE 3 +#define SIR_MAC_RRM_NOISE_HISTOGRAM_BEACON 4 +#define SIR_MAC_RRM_BEACON_TYPE 5 +#define SIR_MAC_RRM_FRAME_TYPE 6 +#define SIR_MAC_RRM_STA_STATISTICS_TYPE 7 +#define SIR_MAC_RRM_LCI_TYPE 8 +#define SIR_MAC_RRM_TSM_TYPE 9 +#define SIR_MAC_RRM_LOCATION_CIVIC_TYPE 11 +#define SIR_MAC_RRM_FINE_TIME_MEAS_TYPE 16 + +/* RRM action codes */ +#define SIR_MAC_RRM_RADIO_MEASURE_REQ 0 +#define SIR_MAC_RRM_RADIO_MEASURE_RPT 1 +#define SIR_MAC_RRM_LINK_MEASUREMENT_REQ 2 +#define SIR_MAC_RRM_LINK_MEASUREMENT_RPT 3 +#define SIR_MAC_RRM_NEIGHBOR_REQ 4 +#define SIR_MAC_RRM_NEIGHBOR_RPT 5 + +#endif + +/* VHT Action Field */ +#ifdef WLAN_FEATURE_11AC +#define SIR_MAC_VHT_GID_NOTIFICATION 1 +#define SIR_MAC_VHT_OPMODE_NOTIFICATION 2 +#endif + +#define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ +/* HT Action Field Codes */ +#define SIR_MAC_SM_POWER_SAVE 1 + +/* DLP action frame types */ +#define SIR_MAC_DLP_REQ 0 +#define SIR_MAC_DLP_RSP 1 +#define SIR_MAC_DLP_TEARDOWN 2 + +/* block acknowledgement action frame types */ +#define SIR_MAC_ACTION_VENDOR_SPECIFIC 9 +#define SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY 0x7F +#define SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP 2 + +/* Public Action for 20/40 BSS Coexistence */ +#define SIR_MAC_ACTION_2040_BSS_COEXISTENCE 0 + +#ifdef WLAN_FEATURE_11W +/* 11w SA query request/response action frame category code */ +#define SIR_MAC_SA_QUERY_REQ 0 +#define SIR_MAC_SA_QUERY_RSP 1 +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_MAC_TDLS_SETUP_REQ 0 +#define SIR_MAC_TDLS_SETUP_RSP 1 +#define SIR_MAC_TDLS_SETUP_CNF 2 +#define SIR_MAC_TDLS_TEARDOWN 3 +#define SIR_MAC_TDLS_PEER_TRAFFIC_IND 4 +#define SIR_MAC_TDLS_CH_SWITCH_REQ 5 +#define SIR_MAC_TDLS_CH_SWITCH_RSP 6 +#define SIR_MAC_TDLS_PEER_TRAFFIC_RSP 9 +#define SIR_MAC_TDLS_DIS_REQ 10 +#define SIR_MAC_TDLS_DIS_RSP 14 +#endif + +/* WNM Action field values; IEEE Std 802.11-2012, 8.5.14.1, Table 8-250 */ +#define SIR_MAC_WNM_BSS_TM_QUERY 6 +#define SIR_MAC_WNM_BSS_TM_REQUEST 7 +#define SIR_MAC_WNM_BSS_TM_RESPONSE 8 +#define SIR_MAC_WNM_NOTIF_REQUEST 26 +#define SIR_MAC_WNM_NOTIF_RESPONSE 27 + +#define SIR_MAC_MAX_RANDOM_LENGTH 2306 + +/* ----------------------------------------------------------------------------- */ +/* EID (Element ID) definitions */ +/* and their min/max lengths */ +/* ----------------------------------------------------------------------------- */ + +#define SIR_MAC_SSID_EID 0 +#define SIR_MAC_SSID_EID_MIN 0 +#define SIR_MAC_SSID_EID_MAX 32 +#define SIR_MAC_RATESET_EID 1 +#define SIR_MAC_RATESET_EID_MIN 1 +#define SIR_MAC_RATESET_EID_MAX 12 +#define SIR_MAC_FH_PARAM_SET_EID 2 +#define SIR_MAC_FH_PARAM_SET_EID_MIN 5 +#define SIR_MAC_FH_PARAM_SET_EID_MAX 5 +#define SIR_MAC_DS_PARAM_SET_EID 3 +#define SIR_MAC_DS_PARAM_SET_EID_MIN 1 +#define SIR_MAC_DS_PARAM_SET_EID_MAX 1 +#define SIR_MAC_CF_PARAM_SET_EID 4 +#define SIR_MAC_CF_PARAM_SET_EID_MIN 6 +#define SIR_MAC_CF_PARAM_SET_EID_MAX 6 +#define SIR_MAC_TIM_EID 5 +#define SIR_MAC_TIM_EID_MIN 3 +#define SIR_MAC_TIM_EID_MAX 254 +#define SIR_MAC_IBSS_PARAM_SET_EID 6 +#define SIR_MAC_IBSS_PARAM_SET_EID_MIN 2 +#define SIR_MAC_IBSS_PARAM_SET_EID_MAX 2 +#define SIR_MAC_COUNTRY_EID 7 +#define SIR_MAC_COUNTRY_EID_MIN 6 +#define SIR_MAC_COUNTRY_EID_MAX 254 +#define SIR_MAC_FH_PARAMS_EID 8 +#define SIR_MAC_FH_PARAMS_EID_MIN 4 +#define SIR_MAC_FH_PARAMS_EID_MAX 4 +#define SIR_MAC_FH_PATTERN_EID 9 +#define SIR_MAC_FH_PATTERN_EID_MIN 4 +#define SIR_MAC_FH_PATTERN_EID_MAX 254 +#define SIR_MAC_REQUEST_EID 10 +#define SIR_MAC_REQUEST_EID_MIN 1 +#define SIR_MAC_REQUEST_EID_MAX 255 +#define SIR_MAC_QBSS_LOAD_EID 11 +#define SIR_MAC_QBSS_LOAD_EID_MIN 5 +#define SIR_MAC_QBSS_LOAD_EID_MAX 5 +#define SIR_MAC_EDCA_PARAM_SET_EID 12 /* EDCA parameter set */ +#define SIR_MAC_EDCA_PARAM_SET_EID_MIN 18 +#define SIR_MAC_EDCA_PARAM_SET_EID_MAX 20 /* TBD temp - change backto 18 */ +#define SIR_MAC_TSPEC_EID 13 +#define SIR_MAC_TSPEC_EID_MIN 55 +#define SIR_MAC_TSPEC_EID_MAX 55 +#define SIR_MAC_TCLAS_EID 14 +#define SIR_MAC_TCLAS_EID_MIN 4 +#define SIR_MAC_TCLAS_EID_MAX 255 +#define SIR_MAC_QOS_SCHEDULE_EID 15 +#define SIR_MAC_QOS_SCHEDULE_EID_MIN 14 +#define SIR_MAC_QOS_SCHEDULE_EID_MAX 14 +#define SIR_MAC_CHALLENGE_TEXT_EID 16 +#define SIR_MAC_CHALLENGE_TEXT_EID_MIN 1 +#define SIR_MAC_CHALLENGE_TEXT_EID_MAX 253 +/* reserved 17-31 */ +#define SIR_MAC_PWR_CONSTRAINT_EID 32 +#define SIR_MAC_PWR_CONSTRAINT_EID_MIN 1 +#define SIR_MAC_PWR_CONSTRAINT_EID_MAX 1 +#define SIR_MAC_PWR_CAPABILITY_EID 33 +#define SIR_MAC_PWR_CAPABILITY_EID_MIN 2 +#define SIR_MAC_PWR_CAPABILITY_EID_MAX 2 +#define SIR_MAC_TPC_REQ_EID 34 +#define SIR_MAC_TPC_REQ_EID_MIN 0 +#define SIR_MAC_TPC_REQ_EID_MAX 255 +/* SIR_MAC_EXTENDED_CAP_EID 35 */ +#define SIR_MAC_TPC_RPT_EID 35 +#define SIR_MAC_TPC_RPT_EID_MIN 2 +#define SIR_MAC_TPC_RPT_EID_MAX 2 +#define SIR_MAC_SPRTD_CHNLS_EID 36 +#define SIR_MAC_SPRTD_CHNLS_EID_MIN 2 +#define SIR_MAC_SPRTD_CHNLS_EID_MAX 254 +#define SIR_MAC_CHNL_SWITCH_ANN_EID 37 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MIN 3 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MAX 3 +#define SIR_MAC_MEAS_REQ_EID 38 +#define SIR_MAC_MEAS_REQ_EID_MIN 3 +#define SIR_MAC_MEAS_REQ_EID_MAX 255 +#define SIR_MAC_MEAS_RPT_EID 39 +#define SIR_MAC_MEAS_RPT_EID_MIN 3 +#define SIR_MAC_MEAS_RPT_EID_MAX 255 +#define SIR_MAC_QUIET_EID 40 +#define SIR_MAC_QUIET_EID_MIN 6 +#define SIR_MAC_QUIET_EID_MAX 6 +#define SIR_MAC_IBSS_DFS_EID 41 +#define SIR_MAC_IBSS_DFS_EID_MIN 7 +#define SIR_MAC_IBSS_DFS_EID_MAX 255 +#define SIR_MAC_ERP_INFO_EID 42 +#define SIR_MAC_ERP_INFO_EID_MIN 0 +#define SIR_MAC_ERP_INFO_EID_MAX 255 +#define SIR_MAC_TS_DELAY_EID 43 +#define SIR_MAC_TS_DELAY_EID_MIN 4 +#define SIR_MAC_TS_DELAY_EID_MAX 4 +#define SIR_MAC_TCLAS_PROC_EID 44 +#define SIR_MAC_TCLAS_PROC_EID_MIN 1 +#define SIR_MAC_TCLAS_PROC_EID_MAX 1 +#define SIR_MAC_QOS_CAPABILITY_EID 46 +#define SIR_MAC_QOS_CAPABILITY_EID_MIN 1 +#define SIR_MAC_QOS_CAPABILITY_EID_MAX 1 +#define SIR_MAC_RSN_EID 48 +#define SIR_MAC_RSN_EID_MIN 4 +#define SIR_MAC_RSN_EID_MAX 254 + +/* using reserved EID for Qos Action IE for now, */ +/* need to check 11e spec for the actual EID */ +#define SIR_MAC_QOS_ACTION_EID 49 +#define SIR_MAC_QOS_ACTION_EID_MIN 4 +#define SIR_MAC_QOS_ACTION_EID_MAX 255 +#define SIR_MAC_EXTENDED_RATE_EID 50 +#define SIR_MAC_EXTENDED_RATE_EID_MIN 0 +#define SIR_MAC_EXTENDED_RATE_EID_MAX 255 +/* reserved 51-69 */ +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID 70 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MIN 5 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX 5 +/* reserved 71-220 */ +#define SIR_MAC_WPA_EID 221 +#define SIR_MAC_WPA_EID_MIN 0 +#define SIR_MAC_WPA_EID_MAX 255 + +#define SIR_MAC_EID_VENDOR 221 + +#define SIR_MAC_WAPI_EID 68 +/* reserved 222-254 */ +#define SIR_MAC_HT_CAPABILITIES_EID 45 +#define SIR_MAC_HT_CAPABILITIES_EID_MIN 0 +#define SIR_MAC_HT_CAPABILITIES_EID_MAX 255 +#define SIR_MAC_HT_INFO_EID 61 +#define SIR_MAC_HT_INFO_EID_MIN 0 +#define SIR_MAC_HT_INFO_EID_MAX 255 + +#ifdef WLAN_FEATURE_11AC +#define SIR_MAC_VHT_CAPABILITIES_EID 191 +#define SIR_MAC_VHT_OPERATION_EID 192 +#define SIR_MAC_VHT_EXT_BSS_LOAD_EID 193 +#define SIR_MAC_VHT_OPMODE_EID 199 +#endif +#define SIR_MAC_MAX_SUPPORTED_MCS_SET 16 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_MAC_QCOM_VENDOR_EID 200 +#define SIR_MAC_QCOM_VENDOR_OUI "\x00\xA0\xC6" +#define SIR_MAC_QCOM_VENDOR_SIZE 3 +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/* / Workaround IE to change beacon length when it is 4*n+1 */ +#define SIR_MAC_ANI_WORKAROUND_EID 255 +#define SIR_MAC_ANI_WORKAROUND_EID_MIN 0 +#define SIR_MAC_ANI_WORKAROUND_EID_MAX 255 + +#define SIR_MAC_MAX_ADD_IE_LENGTH 500 + +/* / Maximum length of each IE */ +#define SIR_MAC_MAX_IE_LENGTH 255 + +/* / Maximum length of each IE */ +#define SIR_MAC_RSN_IE_MAX_LENGTH 255 +#define SIR_MAC_WPA_IE_MAX_LENGTH 255 +/* / Minimum length of each IE */ +#define SIR_MAC_RSN_IE_MIN_LENGTH 2 +#define SIR_MAC_WPA_IE_MIN_LENGTH 6 + +#ifdef FEATURE_WLAN_ESE +#define ESE_VERSION_4 4 +#define ESE_VERSION_SUPPORTED ESE_VERSION_4 + +/* When station sends Radio Management Cap. */ +/* State should be normal=1 */ +/* Mbssid Mask should be 0 */ +#define RM_STATE_NORMAL 1 +#endif + +#define SIR_MAC_OUI_VERSION_1 1 + +/* OUI and type definition for WPA IE in network byte order */ +#define SIR_MAC_WPA_OUI 0x01F25000 +#define SIR_MAC_WME_OUI 0x02F25000 +#define SIR_MAC_WSM_OUI SIR_MAC_WME_OUI +#define SIR_MAC_WSC_OUI "\x00\x50\xf2\x04" +#define SIR_MAC_WSC_OUI_SIZE 4 +#define SIR_MAC_P2P_OUI "\x50\x6f\x9a\x09" +#define SIR_MAC_P2P_OUI_SIZE 4 +#define SIR_P2P_NOA_ATTR 12 +#define SIR_MAX_NOA_ATTR_LEN 31 +#define SIR_MAX_NOA_DESCR 2 +#define SIR_P2P_IE_HEADER_LEN 6 + +#define SIR_MAC_CISCO_OUI "\x00\x40\x96" +#define SIR_MAC_CISCO_OUI_SIZE 3 + +/* min size of wme oui header: oui(3) + type + subtype + version */ +#define SIR_MAC_OUI_WME_HDR_MIN 6 + +/* OUI subtype and their lengths */ +#define SIR_MAC_OUI_SUBTYPE_WME_INFO 0 +#define SIR_MAC_OUI_WME_INFO_MIN 7 +#define SIR_MAC_OUI_WME_INFO_MAX 7 + +#define SIR_MAC_OUI_SUBTYPE_WME_PARAM 1 +#define SIR_MAC_OUI_WME_PARAM_MIN 24 +#define SIR_MAC_OUI_WME_PARAM_MAX 24 + +#define SIR_MAC_OUI_SUBTYPE_WME_TSPEC 2 +#define SIR_MAC_OUI_WME_TSPEC_MIN 61 +#define SIR_MAC_OUI_WME_TSPEC_MAX 61 + +#define SIR_MAC_OUI_SUBTYPE_WSM_TSPEC 2 /* same as WME TSPEC */ +#define SIR_MAC_OUI_WSM_TSPEC_MIN 61 +#define SIR_MAC_OUI_WSM_TSPEC_MAX 61 + +/* reserved subtypes 3-4 */ +/* WSM capability */ +#define SIR_MAC_OUI_SUBTYPE_WSM_CAPABLE 5 +#define SIR_MAC_OUI_WSM_CAPABLE_MIN 7 +#define SIR_MAC_OUI_WSM_CAPABLE_MAX 7 +/* WSM classifier */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLAS 6 +#define SIR_MAC_OUI_WSM_TCLAS_MIN 10 +#define SIR_MAC_OUI_WSM_TCLAS_MAX 255 +/* classifier processing element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLASPROC 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MIN 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MAX 7 +/* tspec delay element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TSDELAY 8 +#define SIR_MAC_OUI_WSM_TSDELAY_MIN 10 +#define SIR_MAC_OUI_WSM_TSDELAY_MAX 10 +/* schedule element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_SCHEDULE 9 +#define SIR_MAC_OUI_WSM_SCHEDULE_MIN 20 +#define SIR_MAC_OUI_WSM_SCHEDULE_MAX 20 + +#ifdef WLAN_NS_OFFLOAD +#define SIR_MAC_NS_OFFLOAD_SIZE 1 /* support only one IPv6 offload */ +/* Number of target IP V6 addresses for NS offload */ +#define SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA 16 +#define SIR_MAC_IPV6_ADDR_LEN 16 +#define SIR_IPV6_ADDR_VALID 1 +#endif /* WLAN_NS_OFFLOAD */ +#define SIR_MAC_ARP_OFFLOAD_SIZE 1 + +/* total length of an Info element including T/L fields */ +#define EID_LEN(eid) (2 + (eid)) + +/* support for radar Detect, Channel Switch */ +#define CHANNEL_SWITCH_MAX_FRAME_SIZE 256 + +/* Length of Channel Switch related message */ +#define SIR_SME_CHANNEL_SWITCH_SIZE \ + (sizeof(uint8_t) + 2 * sizeof(uint16_t) + sizeof(uint32_t) +\ + sizeof(ePhyChanBondState)) +#define SIR_CHANNEL_SWITCH_IE_SIZE EID_LEN(SIR_MAC_CHNL_SWITCH_ANN_EID_MIN) + +/* Measurement Request/Report messages */ +#define SIR_MEAS_REQ_FIELD_SIZE 11 +#define SIR_MEAS_REQ_IE_SIZE (5 + SIR_MEAS_REQ_FIELD_SIZE) +#define SIR_MEAS_REQ_ACTION_FRAME_SIZE (3 + SIR_MEAS_REQ_IE_SIZE) +#define SIR_MEAS_MAX_FRAME_SIZE 256 +#define SIR_MEAS_REPORT_MIN_FRAME_SIZE (3 + EID_LEN(SIR_MAC_MEAS_RPT_EID_MIN)) + +#define SIR_MAC_SET_MEAS_REQ_ENABLE(x) (((uint8_t) x) | 2) +#define SIR_MAC_SET_MEAS_REQ_REQUEST(x) (((uint8_t) x) | 4) +#define SIR_MAC_SET_MEAS_REQ_REPORT(x) (((uint8_t) x) | 8) + +#define SIR_MAC_SET_MEAS_REPORT_LATE(x) (((uint8_t) x) | 1) +#define SIR_MAC_SET_MEAS_REPORT_INCAPABLE(x) (((uint8_t) x) | 2) +#define SIR_MAC_SET_MEAS_REPORT_REFUSE(x) (((uint8_t) x) | 4) + +/* Length of TPC Request Action Frame */ +#define SIR_TPC_REQ_ACTION_FRAME_SIZE (3 + EID_LEN(SIR_MAC_TPC_REQ_EID_MIN)) +#define SIR_TPC_REPORT_ACTION_FRAME_SIZE (3 + EID_LEN(SIR_MAC_TPC_RPT_EID_MIN)) +#define SIR_TPC_MAX_FRAME_SIZE 256 +/* ----------------------------------------------------------------------------- */ + +/* OFFSET definitions for fixed fields in Management frames */ + +/* Beacon/Probe Response offsets */ +#define SIR_MAC_TS_OFFSET 0 +#define SIR_MAC_BEACON_INT_OFFSET 8 /* Beacon Interval offset */ +#define SIR_MAC_B_PR_CAPAB_OFFSET 10 +#define SIR_MAC_B_PR_SSID_OFFSET 12 + +/* Association/Reassociation offsets */ +#define SIR_MAC_ASSOC_CAPAB_OFFSET 0 +#define SIR_MAC_LISTEN_INT_OFFSET 2 /* Listen Interval offset */ +#define SIR_MAC_ASSOC_SSID_OFFSET 4 +#define SIR_MAC_CURRENT_AP_OFFSET 4 +#define SIR_MAC_REASSOC_SSID_OFFSET 10 +#define SIR_MAC_ASSOC_STATUS_CODE_OFFSET 2 +#define SIR_MAC_ASSOC_AID_OFFSET 4 +#define SIR_MAC_ASSOC_RSP_RATE_OFFSET 6 + +/* Disassociation/Deauthentication offsets */ +#define SIR_MAC_REASON_CODE_OFFSET 0 + +/* Probe Request offset */ +#define SIR_MAC_PROBE_REQ_SSID_OFFSET 0 + +/* Authentication offsets */ +#define SIR_MAC_AUTH_ALGO_OFFSET 0 +#define SIR_MAC_AUTH_XACT_SEQNUM_OFFSET 2 +#define SIR_MAC_AUTH_STATUS_CODE_OFFSET 4 +#define SIR_MAC_AUTH_CHALLENGE_OFFSET 6 + +/* / Transaction sequence number definitions (used in Authentication frames) */ +#define SIR_MAC_AUTH_FRAME_1 1 +#define SIR_MAC_AUTH_FRAME_2 2 +#define SIR_MAC_AUTH_FRAME_3 3 +#define SIR_MAC_AUTH_FRAME_4 4 + +/* / Protocol defined MAX definitions */ +#define SIR_MAC_MAX_SSID_LENGTH 32 +#define SIR_MAC_MAX_NUMBER_OF_RATES 12 +#define SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS 4 +#define SIR_MAC_KEY_LENGTH 13 /* WEP Maximum key length size */ +#define SIR_MAC_AUTH_CHALLENGE_LENGTH 128 +#define SIR_MAC_WEP_IV_LENGTH 4 +#define SIR_MAC_WEP_ICV_LENGTH 4 + +/* / MAX key length when ULA is used */ +#define SIR_MAC_MAX_KEY_LENGTH 32 + +/* / Macro definitions for get/set on FC fields */ +#define SIR_MAC_GET_PROT_VERSION(x) ((((uint16_t) x) & 0x0300) >> 8) +#define SIR_MAC_GET_FRAME_TYPE(x) ((((uint16_t) x) & 0x0C00) >> 8) +#define SIR_MAC_GET_FRAME_SUB_TYPE(x) ((((uint16_t) x) & 0xF000) >> 12) +#define SIR_MAC_GET_WEP_BIT_IN_FC(x) (((uint16_t) x) & 0x0040) +#define SIR_MAC_SET_PROT_VERSION(x) ((uint16_t) x) +#define SIR_MAC_SET_FRAME_TYPE(x) (((uint16_t) x) << 2) +#define SIR_MAC_SET_FRAME_SUB_TYPE(x) (((uint16_t) x) << 4) +#define SIR_MAC_SET_WEP_BIT_IN_FC(x) (((uint16_t) x) << 14) + +/* / Macro definitions for get/set on capabilityInfo bits */ +#define SIR_MAC_GET_ESS(x) (((uint16_t) x) & 0x0001) +#define SIR_MAC_GET_IBSS(x) ((((uint16_t) x) & 0x0002) >> 1) +#define SIR_MAC_GET_CF_POLLABLE(x) ((((uint16_t) x) & 0x0004) >> 2) +#define SIR_MAC_GET_CF_POLL_REQ(x) ((((uint16_t) x) & 0x0008) >> 3) +#define SIR_MAC_GET_PRIVACY(x) ((((uint16_t) x) & 0x0010) >> 4) +#define SIR_MAC_GET_SHORT_PREAMBLE(x) ((((uint16_t) x) & 0x0020) >> 5) +#define SIR_MAC_GET_SPECTRUM_MGMT(x) ((((uint16_t) x) & 0x0100) >> 8) +#define SIR_MAC_GET_QOS(x) ((((uint16_t) x) & 0x0200) >> 9) +#define SIR_MAC_GET_SHORT_SLOT_TIME(x) ((((uint16_t) x) & 0x0400) >> 10) +#define SIR_MAC_GET_APSD(x) ((((uint16_t) x) & 0x0800) >> 11) +#if defined WLAN_FEATURE_VOWIFI +#define SIR_MAC_GET_RRM(x) ((((uint16_t) x) & 0x1000) >> 12) +#endif +#define SIR_MAC_GET_BLOCK_ACK(x) ((((uint16_t) x) & 0xc000) >> CAPABILITY_INFO_DELAYED_BA_BIT) +#define SIR_MAC_SET_ESS(x) (((uint16_t) x) | 0x0001) +#define SIR_MAC_SET_IBSS(x) (((uint16_t) x) | 0x0002) +#define SIR_MAC_SET_CF_POLLABLE(x) (((uint16_t) x) | 0x0004) +#define SIR_MAC_SET_CF_POLL_REQ(x) (((uint16_t) x) | 0x0008) +#define SIR_MAC_SET_PRIVACY(x) (((uint16_t) x) | 0x0010) +#define SIR_MAC_SET_SHORT_PREAMBLE(x) (((uint16_t) x) | 0x0020) +#define SIR_MAC_SET_SPECTRUM_MGMT(x) (((uint16_t) x) | 0x0100) +#define SIR_MAC_SET_QOS(x) (((uint16_t) x) | 0x0200) +#define SIR_MAC_SET_SHORT_SLOT_TIME(x) (((uint16_t) x) | 0x0400) +#define SIR_MAC_SET_APSD(x) (((uint16_t) x) | 0x0800) +#if defined WLAN_FEATURE_VOWIFI +#define SIR_MAC_SET_RRM(x) (((uint16_t) x) | 0x1000) +#endif +#define SIR_MAC_SET_GROUP_ACK(x) (((uint16_t) x) | 0x4000) + +#ifdef WLAN_FEATURE_11AC +#define SIR_MAC_GET_VHT_MAX_AMPDU_EXPO(x) ((((uint32_t) x) & 0x03800000) >> 23) +#endif + +/* bitname must be one of the above, eg ESS, CF_POLLABLE, etc. */ +#define SIR_MAC_CLEAR_CAPABILITY(u16value, bitname) \ + ((u16value) &= (~(SIR_MAC_SET_ ## bitname(0)))) + +#define IS_WES_MODE_ENABLED(x) \ + ((x)->roam.configParam.isWESModeEnabled) + +#define BA_RECIPIENT 1 +#define BA_INITIATOR 2 +#define BA_BOTH_DIRECTIONS 3 + +/* / Status Code (present in Management response frames) enum */ + +typedef enum eSirMacStatusCodes { + eSIR_MAC_SUCCESS_STATUS = 0, /* Reserved */ + eSIR_MAC_UNSPEC_FAILURE_STATUS = 1, /* Unspecified reason */ + /* 802.11 reserved 2-9 */ + /* + WMM status codes(standard 1.1 table 9) + Table 9 ADDTS Response Status Codes + Value Operation + 0 Admission accepted + 1 Invalid parameters + 2 Reserved + 3 Refused + 4-255 Reserved + */ + eSIR_MAC_WME_INVALID_PARAMS_STATUS = 1, /* ?? */ + eSIR_MAC_WME_REFUSED_STATUS = 3, /* ?? */ + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS = 10, /* Cannot support all requested capabilities in the Capability Information field */ + eSIR_MAC_INABLITY_TO_CONFIRM_ASSOC_STATUS = 11, /* Reassociation denied due to inability to confirm that association exists */ + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS = 12, /* Association denied due to reason outside the scope of this standard */ + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS = 13, /* Responding station does not support the specified authentication algorithm */ + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS = 14, /* Received an Authentication frame with authentication transaction sequence number */ + /* out of expected sequence */ + eSIR_MAC_CHALLENGE_FAILURE_STATUS = 15, /* Authentication rejected because of challenge failure */ + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS = 16, /* Authentication rejected due to timeout waiting for next frame in sequence */ + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS = 17, /* Association denied because AP is unable to handle additional associated stations */ + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS = 18, /* Association denied due to requesting station not supporting all of the data rates in the */ + /* BSSBasicRateSet parameter */ + eSIR_MAC_SHORT_PREAMBLE_NOT_SUPPORTED_STATUS = 19, /* Association denied due to requesting station not supporting the short preamble */ + /* option */ + eSIR_MAC_PBCC_NOT_SUPPORTED_STATUS = 20, /* Association denied due to requesting station not supporting the PBCC modulation */ + /* option */ + eSIR_MAC_CHANNEL_AGILITY_NOT_SUPPORTED_STATUS = 21, /* Association denied due to requesting station not supporting the Channel Agility */ + /* option */ + eSIR_MAC_SPECTRUM_MGMT_REQD_STATUS = 22, /* Association request rejected because Spectrum Management capability is required */ + eSIR_MAC_PWR_CAPABILITY_BAD_STATUS = 23, /* Association request rejected because the information in the Power Capability */ + /* element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_STATUS = 24, /* Association request rejected because the information in the Supported Channels */ + /* element is unacceptable */ + eSIR_MAC_SHORT_SLOT_NOT_SUPORTED_STATUS = 25, /* Association denied due to requesting station not supporting the Short Slot Time */ + /* option */ + eSIR_MAC_DSSS_OFDM_NOT_SUPPORTED_STATUS = 26, /* Association denied due to requesting station not supporting the DSSS-OFDM option */ + /* reserved 27-29 */ + eSIR_MAC_TRY_AGAIN_LATER = 30, /* Association request rejected temporarily, try again later */ + /* reserved 31 */ + eSIR_MAC_QOS_UNSPECIFIED_FAILURE_STATUS = 32, /* Unspecified, QoS-related failure */ + eSIR_MAC_QAP_NO_BANDWIDTH_STATUS = 33, /* Association denied because QoS AP has insufficient bandwidth to handle another */ + /* QoS STA */ + eSIR_MAC_XS_FRAME_LOSS_STATUS = 34, /* Association denied due to excessive frame loss rates and/or poor conditions on cur- */ + /* rent operating channel */ + eSIR_MAC_STA_QOS_NOT_SUPPORTED_STATUS = 35, /* Association (with QoS BSS) denied because the requesting STA does not support the */ + /* QoS facility */ + eSIR_MAC_STA_BLK_ACK_NOT_SUPPORTED_STATUS = 36, /* Reserved */ + eSIR_MAC_REQ_DECLINED_STATUS = 37, /* The request has been declined */ + eSIR_MAC_INVALID_PARAM_STATUS = 38, /* The request has not been successful as one or more parameters have invalid values */ + eSIR_MAC_TS_NOT_HONOURED_STATUS = 39, /* The TS has not been created because the request cannot be honored; however, a suggested */ + /* TSPEC is provided so that the initiating STA may attempt to set another TS */ + /* with the suggested changes to the TSPEC */ + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS = 40, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_INVALID_GROUP_CIPHER_STATUS = 41, /* Invalid group cipher */ + eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS = 42, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_STATUS = 43, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS = 44, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS = 45, /* Invalid RSN information element capabilities */ + eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS = 46, /* Cipher suite rejected because of security policy */ + eSIR_MAC_TS_NOT_CREATED_STATUS = 47, /* The TS has not been created; however, the HC may be capable of creating a TS, in */ + /* response to a request, after the time indicated in the TS Delay element */ + eSIR_MAC_DL_NOT_ALLOWED_STATUS = 48, /* Direct link is not allowed in the BSS by policy */ + eSIR_MAC_DEST_STA_NOT_KNOWN_STATUS = 49, /* The Destination STA is not present within this BSS */ + eSIR_MAC_DEST_STA_NOT_QSTA_STATUS = 50, /* The Destination STA is not a QoS STA */ + eSIR_MAC_INVALID_LISTEN_INTERVAL_STATUS = 51, /* Association denied because the ListenInterval is too large */ + + eSIR_MAC_DSSS_CCK_RATE_MUST_SUPPORT_STATUS = 52, /* FIXME: */ + eSIR_MAC_DSSS_CCK_RATE_NOT_SUPPORT_STATUS = 53, + eSIR_MAC_PSMP_CONTROLLED_ACCESS_ONLY_STATUS = 54, +#ifdef FEATURE_WLAN_ESE + eSIR_MAC_ESE_UNSPECIFIED_QOS_FAILURE_STATUS = 200, /* ESE-Unspecified, QoS related failure in (Re)Assoc response frames */ + eSIR_MAC_ESE_TSPEC_REQ_REFUSED_STATUS = 201, /* ESE-TSPEC request refused due to AP's policy configuration in AddTs Rsp, (Re)Assoc Rsp. */ + eSIR_MAC_ESE_ASSOC_DENIED_INSUFF_BW_STATUS = 202, /* ESE-Assoc denied due to insufficient bandwidth to handle new TS in (Re)Assoc Rsp. */ + eSIR_MAC_ESE_INVALID_PARAMETERS_STATUS = 203, /* ESE-Invalid parameters. (Re)Assoc request had one or more TSPEC parameters with */ + /* invalid values. */ +#endif + +} tSirMacStatusCodes; + +/** + * Reason Code (present in Deauthentication/Disassociation + * Management frames) enum + */ +typedef enum eSirMacReasonCodes { + eSIR_MAC_UNSPEC_FAILURE_REASON = 1, /* Unspecified reason */ + eSIR_MAC_PREV_AUTH_NOT_VALID_REASON = 2, /* Previous authentication no longer valid */ + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON = 3, /* Deauthenticated because sending station is leaving (or has left) IBSS or ESS */ + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON = 4, /* Disassociated due to inactivity */ + eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON = 5, /* Disassociated because AP is unable to handle all currently associated stations */ + eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON = 6, /* Class 2 frame received from nonauthenticated station */ + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON = 7, /* Class 3 frame received from nonassociated station */ + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON = 8, /* Disassociated because sending station is leaving (or has left) BSS */ + eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON = 9, /* Station requesting (re)association is not authenticated with responding station */ + eSIR_MAC_PWR_CAPABILITY_BAD_REASON = 10, /* Disassociated because the information in the Power Capability element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_REASON = 11, /* Disassociated because the information in the Supported Channels element is unacceptable */ + /* reserved 12 */ + eSIR_MAC_INVALID_IE_REASON = 13, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_MIC_FAILURE_REASON = 14, /* Message integrity code (MIC) failure */ + eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON = 15, /* 4-Way Handshake timeout */ + eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON = 16, /* Group Key Handshake timeout */ + eSIR_MAC_RSN_IE_MISMATCH_REASON = 17, /* Information element in 4-Way Handshake different from (Re)Association Request/Probe */ + /* Response/Beacon frame */ + eSIR_MAC_INVALID_MC_CIPHER_REASON = 18, /* Invalid group cipher */ + eSIR_MAC_INVALID_UC_CIPHER_REASON = 19, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_REASON = 20, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON = 21, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON = 22, /* Invalid RSN information element capabilities */ + eSIR_MAC_1X_AUTH_FAILURE_REASON = 23, /* IEEE 802.1X authentication failed */ + eSIR_MAC_CIPHER_SUITE_REJECTED_REASON = 24, /* Cipher suite rejected because of the security policy */ +#ifdef FEATURE_WLAN_TDLS + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE = 25, /* TDLS direct link teardown due to TDLS peer STA unreachable via the TDLS direct link */ + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON = 26, /* TDLS direct link teardown for unspecified reason */ +#endif + /* reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION = 31, /* Robust management frames policy violation */ +#endif + eSIR_MAC_QOS_UNSPECIFIED_REASON = 32, /* Disassociated for unspecified, QoS-related reason */ + eSIR_MAC_QAP_NO_BANDWIDTH_REASON = 33, /* Disassociated because QoS AP lacks sufficient bandwidth for this QoS STA */ + eSIR_MAC_XS_UNACKED_FRAMES_REASON = 34, /* Disassociated because excessive number of frames need to be acknowledged, but are not */ + /* acknowledged due to AP transmissions and/or poor channel conditions */ + eSIR_MAC_BAD_TXOP_USE_REASON = 35, /* Disassociated because STA is transmitting outside the limits of its TXOPs */ + eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON = 36, /* Requested from peer STA as the STA is leaving the BSS (or resetting) */ + eSIR_MAC_PEER_REJECT_MECHANISIM_REASON = 37, /* Requested from peer STA as it does not want to use the mechanism */ + eSIR_MAC_MECHANISM_NOT_SETUP_REASON = 38, /* Requested from peer STA as the STA received frames using the mechanism for which a */ + /* setup is required */ + eSIR_MAC_PEER_TIMEDOUT_REASON = 39, /* Requested from peer STA due to timeout */ + eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON = 45, /* Peer STA does not support the requested cipher suite */ + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON = 46, /* FT reason */ + /* reserved 47 - 65535. */ + eSIR_BEACON_MISSED = 65534, /* We invented this to tell beacon missed case */ +} tSirMacReasonCodes; + +/* BA Initiator v/s Recipient */ +typedef enum eBADirection { + eBA_RECIPIENT, + eBA_INITIATOR +} tBADirection; + +/* A-MPDU/BA Enable/Disable in Tx/Rx direction */ +typedef enum eBAEnable { + eBA_DISABLE, + eBA_ENABLE +} tBAEnable; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicy { + eBA_UNCOMPRESSED, + eBA_COMPRESSED +} tBAPolicy; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicyType { + eBA_POLICY_DELAYED, + eBA_POLICY_IMMEDIATE +} tBAPolicyType; + +/* / Frame control field format (2 bytes) */ +typedef struct sSirMacFrameCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t subType:4; + uint8_t type:2; + uint8_t protVer:2; + + uint8_t order:1; + uint8_t wep:1; + uint8_t moreData:1; + uint8_t powerMgmt:1; + uint8_t retry:1; + uint8_t moreFrag:1; + uint8_t fromDS:1; + uint8_t toDS:1; + +#else + + uint8_t protVer:2; + uint8_t type:2; + uint8_t subType:4; + + uint8_t toDS:1; + uint8_t fromDS:1; + uint8_t moreFrag:1; + uint8_t retry:1; + uint8_t powerMgmt:1; + uint8_t moreData:1; + uint8_t wep:1; + uint8_t order:1; + +#endif + +} cdf_packed tSirMacFrameCtl, *tpSirMacFrameCtl; + +/* / Sequence control field */ +typedef struct sSirMacSeqCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t seqNumLo:4; + uint8_t fragNum:4; + + uint8_t seqNumHi:8; + +#else + + uint8_t fragNum:4; + uint8_t seqNumLo:4; + uint8_t seqNumHi:8; + +#endif +} cdf_packed tSirMacSeqCtl, *tpSirMacSeqCtl; + +/* / QoS control field */ +typedef struct sSirMacQosCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t rsvd:1; + uint8_t ackPolicy:2; + uint8_t esop_txopUnit:1; + uint8_t tid:4; + + uint8_t txop:8; + +#else + + uint8_t tid:4; + uint8_t esop_txopUnit:1; + uint8_t ackPolicy:2; + uint8_t rsvd:1; + + uint8_t txop:8; + +#endif +} cdf_packed tSirMacQosCtl, *tpSirMacQosCtl; + +/* / Length (in bytes) of MAC header in 3 address format */ +#define SIR_MAC_HDR_LEN_3A 24 + +typedef uint8_t tSirMacAddr[ETH_ALEN]; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDot3Hdr { + tSirMacAddr da; + tSirMacAddr sa; + uint16_t length; +} cdf_packed tSirMacDot3Hdr, *tpSirMacDot3Hdr; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDataHdr3a { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr addr1; + tSirMacAddr addr2; + tSirMacAddr addr3; + tSirMacSeqCtl seqControl; + tSirMacQosCtl qosControl; +} cdf_packed tSirMacDataHdr3a, *tpSirMacDataHdr3a; + +/* / Management header format */ +typedef struct sSirMacMgmtHdr { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr da; + tSirMacAddr sa; + tSirMacAddr bssId; + tSirMacSeqCtl seqControl; +} cdf_packed tSirMacMgmtHdr, *tpSirMacMgmtHdr; + +/* / ERP information field */ +typedef struct sSirMacErpInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:5; + uint8_t barkerPreambleMode:1; + uint8_t useProtection:1; + uint8_t nonErpPresent:1; +#else + uint8_t nonErpPresent:1; + uint8_t useProtection:1; + uint8_t barkerPreambleMode:1; + uint8_t reserved:5; +#endif +} cdf_packed tSirMacErpInfo, *tpSirMacErpInfo; + +/* / Capability information field */ +typedef struct sSirMacCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t immediateBA:1; + uint16_t delayedBA:1; + uint16_t dsssOfdm:1; + uint16_t rrm:1; + uint16_t apsd:1; + uint16_t shortSlotTime:1; + uint16_t qos:1; + uint16_t spectrumMgt:1; + uint16_t channelAgility:1; + uint16_t pbcc:1; + uint16_t shortPreamble:1; + uint16_t privacy:1; + uint16_t cfPollReq:1; + uint16_t cfPollable:1; + uint16_t ibss:1; + uint16_t ess:1; +#else + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t pbcc:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +#endif +} cdf_packed tSirMacCapabilityInfo, *tpSirMacCapabilityInfo; + +typedef struct sSirMacCfParamSet { + uint8_t cfpCount; + uint8_t cfpPeriod; + uint16_t cfpMaxDuration; + uint16_t cfpDurRemaining; +} cdf_packed tSirMacCfParamSet; + +typedef struct sSirMacTim { + uint8_t dtimCount; + uint8_t dtimPeriod; + uint8_t bitmapControl; + uint8_t bitmapLength; + uint8_t bitmap[251]; +} cdf_packed tSirMacTim; + +/* 12 Bytes long because this structure can be used to represent rate */ +/* and extended rate set IEs */ +/* The parser assume this to be at least 12 */ +typedef struct sSirMacRateSet { + uint8_t numRates; + uint8_t rate[SIR_MAC_RATESET_EID_MAX]; +} cdf_packed tSirMacRateSet; + +typedef struct sSirMacSSid { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH]; +} cdf_packed tSirMacSSid; + +typedef struct sSirMacWpaInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} cdf_packed tSirMacWpaInfo, *tpSirMacWpaInfo, +tSirMacRsnInfo, *tpSirMacRsnInfo; +typedef struct sSirMacWapiInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} cdf_packed tSirMacWapiInfo, *tpSirMacWapiInfo, +tSirMacWapiInfo, *tpSirMacWapiInfo; + +typedef struct sSirMacFHParamSet { + uint16_t dwellTime; + uint8_t hopSet; + uint8_t hopPattern; + uint8_t hopIndex; +} tSirMacFHParamSet, *tpSirMacFHParamSet; + +typedef struct sSirMacIBSSParams { + uint16_t atim; +} tSirMacIBSSParams, *tpSirMacIBSSParams; + +typedef struct sSirMacRRMEnabledCap { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:6; + uint8_t AntennaInformation:1; + uint8_t BSSAvailAdmission:1; + uint8_t BssAvgAccessDelay:1; + uint8_t RSNIMeasurement:1; + uint8_t RCPIMeasurement:1; + uint8_t NeighborTSFOffset:1; + uint8_t MeasurementPilotEnabled:1; + uint8_t MeasurementPilot:3; + uint8_t nonOperatinChanMax:3; + uint8_t operatingChanMax:3; + uint8_t RRMMIBEnabled:1; + uint8_t APChanReport:1; + uint8_t triggeredTCM:1; + uint8_t TCMCapability:1; + uint8_t LCIAzimuth:1; + uint8_t LCIMeasurement:1; + uint8_t statistics:1; + uint8_t NoiseHistogram:1; + uint8_t ChannelLoad:1; + uint8_t FrameMeasurement:1; + uint8_t BeaconRepCond:1; + uint8_t BeaconTable:1; + uint8_t BeaconActive:1; + uint8_t BeaconPassive:1; + uint8_t repeated:1; + uint8_t parallel:1; + uint8_t NeighborRpt:1; + uint8_t LinkMeasurement:1; + uint8_t present; +#else + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t reserved:6; +#endif +} tSirMacRRMEnabledCap, *tpSirMacRRMEnabledCap; + +/* ---------------- + * EDCA Profiles + * --------------- + */ + +#define EDCA_AC_BE 0 +#define EDCA_AC_BK 1 +#define EDCA_AC_VI 2 +#define EDCA_AC_VO 3 +#define AC_MGMT_LO 4 +#define AC_MGMT_HI 5 +#define MAX_NUM_AC 4 + +/* access categories */ +#define SIR_MAC_EDCAACI_BESTEFFORT (EDCA_AC_BE) +#define SIR_MAC_EDCAACI_BACKGROUND (EDCA_AC_BK) +#define SIR_MAC_EDCAACI_VIDEO (EDCA_AC_VI) +#define SIR_MAC_EDCAACI_VOICE (EDCA_AC_VO) + +/* access category record */ +typedef struct sSirMacAciAifsn { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:1; + uint8_t aci:2; + uint8_t acm:1; + uint8_t aifsn:4; +#else + uint8_t aifsn:4; + uint8_t acm:1; + uint8_t aci:2; + uint8_t rsvd:1; +#endif +} cdf_packed tSirMacAciAifsn; + +/* contention window size */ +typedef struct sSirMacCW { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t max:4; + uint8_t min:4; +#else + uint8_t min:4; + uint8_t max:4; +#endif +} cdf_packed tSirMacCW; + +typedef struct sSirMacEdcaParamRecord { + tSirMacAciAifsn aci; + tSirMacCW cw; + uint16_t txoplimit; +} cdf_packed tSirMacEdcaParamRecord; + +typedef struct sSirMacQosInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t uapsd:1; + uint8_t txopreq:1; + uint8_t qreq:1; + uint8_t qack:1; + uint8_t count:4; +#else + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t uapsd:1; +#endif +} cdf_packed tSirMacQosInfo; + +typedef struct sSirMacQosInfoStation { +#ifdef ANI_LITTLE_BIT_ENDIAN + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t maxSpLen:2; + uint8_t moreDataAck:1; +#else + uint8_t moreDataAck:1; + uint8_t maxSpLen:2; + uint8_t qack:1; + uint8_t acbe_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acvo_uapsd:1; +#endif +} cdf_packed tSirMacQosInfoStation, *tpSirMacQosInfoStation; + +typedef struct sSirMacEdcaParamSetIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; + uint8_t rsvd; + tSirMacEdcaParamRecord acbe; /* best effort */ + tSirMacEdcaParamRecord acbk; /* background */ + tSirMacEdcaParamRecord acvi; /* video */ + tSirMacEdcaParamRecord acvo; /* voice */ +} cdf_packed tSirMacEdcaParamSetIE; + +typedef struct sSirMacQoSParams { + uint8_t count; + uint16_t limit; + uint8_t CWmin[8]; + uint8_t AIFS[8]; +} cdf_packed tSirMacQoSParams; + +/* ts info direction field can take any of these values */ +#define SIR_MAC_DIRECTION_UPLINK 0 +#define SIR_MAC_DIRECTION_DNLINK 1 +#define SIR_MAC_DIRECTION_DIRECT 2 +#define SIR_MAC_DIRECTION_BIDIR 3 + +/* access policy */ +/* reserved 0 */ +#define SIR_MAC_ACCESSPOLICY_EDCA 1 +#define SIR_MAC_ACCESSPOLICY_HCCA 2 +#define SIR_MAC_ACCESSPOLICY_BOTH 3 + +typedef struct sSirMacTSInfoTfc { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t burstSizeDefn:1; + uint8_t reserved:7; +#else + uint8_t reserved:7; + uint8_t burstSizeDefn:1; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t ackPolicy:2; + uint16_t userPrio:3; + uint16_t psb:1; + uint16_t aggregation:1; + uint16_t accessPolicy:2; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t trafficType:1; +#else + uint16_t trafficType:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t accessPolicy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t userPrio:3; + uint16_t ackPolicy:2; +#endif +} cdf_packed tSirMacTSInfoTfc; + +typedef struct sSirMacTSInfoSch { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:7; + uint8_t schedule:1; +#else + uint8_t schedule:1; + uint8_t rsvd:7; +#endif +} cdf_packed tSirMacTSInfoSch; + +typedef struct sSirMacTSInfo { + tSirMacTSInfoTfc traffic; + tSirMacTSInfoSch schedule; +} cdf_packed tSirMacTSInfo; + +typedef struct sSirMacTspecIE { + uint8_t type; + uint8_t length; + tSirMacTSInfo tsinfo; + uint16_t nomMsduSz; + uint16_t maxMsduSz; + uint32_t minSvcInterval; + uint32_t maxSvcInterval; + uint32_t inactInterval; + uint32_t suspendInterval; + uint32_t svcStartTime; + uint32_t minDataRate; + uint32_t meanDataRate; + uint32_t peakDataRate; + uint32_t maxBurstSz; + uint32_t delayBound; + uint32_t minPhyRate; + uint16_t surplusBw; + uint16_t mediumTime; +} cdf_packed tSirMacTspecIE; + +/* frame classifier types */ +#define SIR_MAC_TCLASTYPE_ETHERNET 0 +#define SIR_MAC_TCLASTYPE_TCPUDPIP 1 +#define SIR_MAC_TCLASTYPE_8021DQ 2 +/* reserved 3-255 */ + +typedef struct sSirMacTclasParamEthernet { + tSirMacAddr srcAddr; + tSirMacAddr dstAddr; + uint16_t type; +} cdf_packed tSirMacTclasParamEthernet; + +typedef struct sSirMacTclasParamIPv4 { + uint8_t version; + uint8_t srcIpAddr[4]; + uint8_t dstIpAddr[4]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t dscp; + uint8_t protocol; + uint8_t rsvd; +} cdf_packed tSirMacTclasParamIPv4; + +#define SIR_MAC_TCLAS_IPV4 4 +#define SIR_MAC_TCLAS_IPV6 6 + +typedef struct sSirMacTclasParamIPv6 { + uint8_t version; + uint8_t srcIpAddr[16]; + uint8_t dstIpAddr[16]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t flowLabel[3]; +} cdf_packed tSirMacTclasParamIPv6; + +typedef struct sSirMacTclasParam8021dq { + uint16_t tag; +} cdf_packed tSirMacTclasParam8021dq; + +typedef struct sSirMacTclasIE { + uint8_t type; + uint8_t length; + uint8_t userPrio; + uint8_t classifierType; + uint8_t classifierMask; +} cdf_packed tSirMacTclasIE; + +typedef struct sSirMacTsDelayIE { + uint8_t type; + uint8_t length; + uint32_t delay; +} cdf_packed tSirMacTsDelayIE; + +typedef struct sSirMacScheduleInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t rsvd:9; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t aggregation:1; +#else + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t rsvd:9; +#endif +} cdf_packed tSirMacScheduleInfo; + +typedef struct sSirMacScheduleIE { + uint8_t type; + uint8_t length; + tSirMacScheduleInfo info; + uint32_t svcStartTime; + uint32_t svcInterval; + uint16_t maxSvcDuration; + uint16_t specInterval; +} cdf_packed tSirMacScheduleIE; + +typedef struct sSirMacQosCapabilityIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; +} cdf_packed tSirMacQosCapabilityIE; + +typedef struct sSirMacQosCapabilityStaIE { + uint8_t type; + uint8_t length; + tSirMacQosInfoStation qosInfo; +} cdf_packed tSirMacQosCapabilityStaIE; + +typedef uint32_t tSirMacTimeStamp[2]; + +typedef uint16_t tSirMacBeaconInterval; + +typedef uint16_t tSirMacListenInterval; + +typedef uint8_t tSirMacChanNum; + +/* IE definitions */ +typedef struct sSirMacSSidIE { + uint8_t type; + tSirMacSSid ssId; +} cdf_packed tSirMacSSidIE; + +typedef struct sSirMacRateSetIE { + uint8_t type; + tSirMacRateSet supportedRateSet; +} cdf_packed tSirMacRateSetIE; + +typedef struct sSirMacDsParamSetIE { + uint8_t type; + uint8_t length; + tSirMacChanNum channelNumber; +} cdf_packed tSirMacDsParamSetIE; + +typedef struct sSirMacCfParamSetIE { + uint8_t type; + uint8_t length; + tSirMacCfParamSet cfParams; +} cdf_packed tSirMacCfParamSetIE; + +typedef struct sSirMacChanInfo { + tSirMacChanNum firstChanNum; + uint8_t numChannels; + int8_t maxTxPower; +} cdf_packed tSirMacChanInfo; + +typedef struct sSirMacNonErpPresentIE { + uint8_t type; + uint8_t length; + uint8_t erp; +} cdf_packed tSirMacNonErpPresentIE; + +typedef struct sSirMacPowerCapabilityIE { + uint8_t type; + uint8_t length; + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapabilityIE; + +typedef struct sSirMacSupportedChannelIE { + uint8_t type; + uint8_t length; + uint8_t supportedChannels[96]; +} tSirMacSupportedChannelIE; + +typedef struct sSirMacMeasReqField { + uint8_t channelNumber; + uint8_t measStartTime[8]; + uint16_t measDuration; +} tSirMacMeasReqField, *tpSirMacMeasReqField; + +typedef struct sSirMacMeasReqIE { + uint8_t type; + uint8_t length; + uint8_t measToken; + uint8_t measReqMode; + uint8_t measType; + tSirMacMeasReqField measReqField; +} tSirMacMeasReqIE, *tpSirMacMeasReqIE; + +#define SIR_MAC_MAX_SUPP_RATES 32 + +#define SIR_MAC_MAX_SUPP_CHANNELS 100 +#define SIR_MAC_MAX_SUPP_OPER_CLASSES 32 +#define SIR_MAC_MAX_EXTN_CAP 8 + +/* VHT Capabilities Info */ +typedef struct sSirMacVHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved1:2; + uint32_t txAntPattern:1; + uint32_t rxAntPattern:1; + uint32_t vhtLinkAdaptCap:2; + uint32_t maxAMPDULenExp:3; + uint32_t htcVHTCap:1; + uint32_t vhtTXOPPS:1; + uint32_t muBeamformeeCap:1; + uint32_t muBeamformerCap:1; + uint32_t numSoundingDim:3; + uint32_t csnofBeamformerAntSup:3; + uint32_t suBeamformeeCap:1; + uint32_t suBeamFormerCap:1; + uint32_t rxSTBC:3; + uint32_t txSTBC:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t shortGI80MHz:1; + uint32_t ldpcCodingCap:1; + uint32_t supportedChannelWidthSet:2; + uint32_t maxMPDULen:2; +#else + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t reserved1:2; +#endif +} cdf_packed tSirMacVHTCapabilityInfo; + +typedef struct sSirMacVHTTxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t txSupDataRate:13; +#else + uint16_t txSupDataRate:13; + uint16_t reserved:3; +#endif +} cdf_packed tSirMacVHTTxSupDataRateInfo; + +typedef struct sSirMacVHTRxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t rxSupDataRate:13; +#else + uint16_t rxSupDataRate:13; + uint16_t reserved:3; +#endif +} cdf_packed tSirMacVHTRxSupDataRateInfo; + +/** + * struct sSirVhtMcsInfo - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +typedef struct sSirVhtMcsInfo { + uint16_t rxMcsMap; + uint16_t rxHighest; + uint16_t txMcsMap; + uint16_t txHighest; +} tSirVhtMcsInfo; + +/** + * struct sSirVHtCap - VHT capabilities + * + * This structure is the "VHT capabilities element" as + * described in 802.11ac D3.0 8.4.2.160 + * @vht_cap_info: VHT capability info + * @supp_mcs: VHT MCS supported rates + */ +typedef struct sSirVHtCap { + uint32_t vhtCapInfo; + tSirVhtMcsInfo suppMcs; +} tSirVHTCap; + +/** + * struct sSirHtCap - HT capabilities + * + * This structure refers to "HT capabilities element" as + * described in 802.11n draft section 7.3.2.52 + */ + +typedef struct sSirHtCap { + uint16_t capInfo; + uint8_t ampduParamsInfo; + uint8_t suppMcsSet[16]; + uint16_t extendedHtCapInfo; + uint32_t txBFCapInfo; + uint8_t antennaSelectionInfo; +} tSirHTCap; + +/* HT Cap and HT IE Size defines */ +#define HT_CAPABILITY_IE_SIZE 28 +#define HT_INFO_IE_SIZE 24 + +/* */ +/* Determines the current operating mode of the 802.11n STA */ +/* */ + +typedef enum eSirMacHTOperatingMode { + eSIR_HT_OP_MODE_PURE, /* No Protection */ + eSIR_HT_OP_MODE_OVERLAP_LEGACY, /* Overlap Legacy device present, protection is optional */ + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT, /* No legacy device, but 20 MHz HT present */ + eSIR_HT_OP_MODE_MIXED /* Protetion is required */ +} tSirMacHTOperatingMode; + +/* Spatial Multiplexing(SM) Power Save mode */ +typedef enum eSirMacHTMIMOPowerSaveState { + eSIR_HT_MIMO_PS_STATIC = 0, /* Static SM Power Save mode */ + eSIR_HT_MIMO_PS_DYNAMIC = 1, /* Dynamic SM Power Save mode */ + eSIR_HT_MIMO_PS_NA = 2, /* reserved */ + eSIR_HT_MIMO_PS_NO_LIMIT = 3 /* SM Power Save disabled */ +} tSirMacHTMIMOPowerSaveState; + +typedef enum eSirMacHTChannelWidth { + eHT_CHANNEL_WIDTH_20MHZ = 0, + eHT_CHANNEL_WIDTH_40MHZ = 1, + eHT_CHANNEL_WIDTH_80MHZ = 2, + eHT_CHANNEL_WIDTH_160MHZ = 3, + eHT_CHANNEL_WIDTH_80P80MHZ = 4, + eHT_MAX_CHANNEL_WIDTH +} tSirMacHTChannelWidth; + +typedef enum eSirMacHTChannelType { + eHT_CHAN_NO_HT = 0, + eHT_CHAN_HT20 = 1, + eHT_CHAN_HT40MINUS = 2, + eHT_CHAN_HT40PLUS = 3 +} tSirMacHTChannelType; + +/* Packet struct for HT capability */ +typedef struct sHtCaps { + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + +} cdf_packed tHtCaps; + +/* During 11h channel switch, the AP can indicate if the + * STA needs to stop the transmission or continue until the + * channel-switch. + * eSIR_CHANSW_MODE_NORMAL - STA can continue transmission + * eSIR_CHANSW_MODE_SILENT - STA should stop transmission + */ +typedef enum eSirMacChanSwMode { + eSIR_CHANSW_MODE_NORMAL = 0, + eSIR_CHANSW_MODE_SILENT = 1 +} tSirMacChanSwitchMode; + +typedef struct _BarControl { + +#ifndef ANI_BIG_BYTE_ENDIAN + + uint16_t barAckPolicy:1; + uint16_t multiTID:1; + uint16_t bitMap:1; + uint16_t rsvd:9; + uint16_t numTID:4; + +#else + uint16_t numTID:4; + uint16_t rsvd:9; + uint16_t bitMap:1; + uint16_t multiTID:1; + uint16_t barAckPolicy:1; + +#endif + +} cdf_packed barCtrlType; + +typedef struct _BARFrmStruct { + tSirMacFrameCtl fc; + uint16_t duration; + tSirMacAddr rxAddr; + tSirMacAddr txAddr; + barCtrlType barControl; + tSirMacSeqCtl ssnCtrl; +} cdf_packed BARFrmType; + +/* Supported MCS set */ +#define SIZE_OF_SUPPORTED_MCS_SET 16 +#define SIZE_OF_BASIC_MCS_SET 16 +#define VALID_MCS_SIZE 77 /* 0-76 */ +#define MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET 10 +#define VALID_MAX_MCS_INDEX 8 + +/* */ +/* The following enums will be used to get the "current" HT Capabilities of */ +/* the local STA in a generic fashion. In other words, the following enums */ +/* identify the HT capabilities that can be queried or set. */ +/* */ +typedef enum eHTCapability { + eHT_LSIG_TXOP_PROTECTION, + eHT_STBC_CONTROL_FRAME, + eHT_PSMP, + eHT_DSSS_CCK_MODE_40MHZ, + eHT_MAX_AMSDU_LENGTH, + eHT_RX_STBC, + eHT_TX_STBC, + eHT_SHORT_GI_40MHZ, + eHT_SHORT_GI_20MHZ, + eHT_GREENFIELD, + eHT_MIMO_POWER_SAVE, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + eHT_ADVANCED_CODING, + eHT_MAX_RX_AMPDU_FACTOR, + eHT_MPDU_DENSITY, + eHT_PCO, + eHT_TRANSITION_TIME, + eHT_MCS_FEEDBACK, + eHT_TX_BEAMFORMING, + eHT_ANTENNA_SELECTION, + /* The following come under Additional HT Capabilities */ + eHT_SI_GRANULARITY, + eHT_CONTROLLED_ACCESS, + eHT_RIFS_MODE, + eHT_RECOMMENDED_TX_WIDTH_SET, + eHT_EXTENSION_CHANNEL_OFFSET, + eHT_OP_MODE, + eHT_BASIC_STBC_MCS, + eHT_DUAL_CTS_PROTECTION, + eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT, + eHT_PCO_ACTIVE, + eHT_PCO_PHASE +} tHTCapability; + +/* HT Capabilities Info */ +typedef struct sSirMacHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t lsigTXOPProtection:1; /* Dynamic state */ + uint16_t stbcControlFrame:1; /* Static via CFG */ + uint16_t psmp:1; /* Static via CFG */ + uint16_t dsssCckMode40MHz:1; /* Static via CFG */ + uint16_t maximalAMSDUsize:1; /* Static via CFG */ + uint16_t delayedBA:1; /* Static via CFG */ + uint16_t rxSTBC:2; /* Static via CFG */ + uint16_t txSTBC:1; /* Static via CFG */ + uint16_t shortGI40MHz:1; /* Static via CFG */ + uint16_t shortGI20MHz:1; /* Static via CFG */ + uint16_t greenField:1; /* Static via CFG */ + uint16_t mimoPowerSave:2; /* Dynamic state */ + uint16_t supportedChannelWidthSet:1; /* Static via CFG */ + uint16_t advCodingCap:1; /* Static via CFG */ +#else + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; +#endif +} cdf_packed tSirMacHTCapabilityInfo; + +/* HT Parameters Info */ +typedef struct sSirMacHTParametersInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:3; + uint8_t mpduDensity:3; /* Dynamic state */ + uint8_t maxRxAMPDUFactor:2; /* Dynamic state */ +#else + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved:3; +#endif +} cdf_packed tSirMacHTParametersInfo; + +/* Extended HT Capabilities Info */ +typedef struct sSirMacExtendedHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved2:6; + uint16_t mcsFeedback:2; /* Static via CFG */ + uint16_t reserved1:5; + uint16_t transitionTime:2; /* Static via CFG */ + uint16_t pco:1; /* Static via CFG */ +#else + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved1:5; + uint16_t mcsFeedback:2; + uint16_t reserved2:6; +#endif +} cdf_packed tSirMacExtendedHTCapabilityInfo; + +/* IEEE 802.11n/D7.0 - 7.3.2.57.4 */ +/* Part of the "supported MCS set field" */ +typedef struct sSirMacRxHighestSupportRate { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:6; + uint16_t rate:10; +#else + uint16_t rate:10; + uint16_t reserved:6; +#endif +} cdf_packed tSirMacRxHighestSupportRate, *tpSirMacRxHighestSupportRate; + +/* Transmit Beam Forming Capabilities Info */ +typedef struct sSirMacTxBFCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved:7; + uint32_t compressedSteeringMatrixBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t csiNumBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t explicitCompressedSteeringMatrixFeedback:3; + /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitBFCSIFeedback:3; /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrix:1; /* Static via CFG */ + uint32_t explicitCSITxBF:1; /* Static via CFG */ + uint32_t calibration:2; /* Static via CFG */ + uint32_t implicitTxBF:1; /* Static via CFG */ + uint32_t txZLF:1; /* Static via CFG */ + uint32_t rxZLF:1; /* Static via CFG */ + uint32_t txStaggeredSounding:1; /* Static via CFG */ + uint32_t rxStaggeredSounding:1; /* Static via CFG */ + uint32_t txBF:1; /* Static via CFG */ +#else + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved:7; +#endif +} cdf_packed tSirMacTxBFCapabilityInfo; + +/* Antenna Selection Capability Info */ +typedef struct sSirMacASCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved2:1; + uint8_t txSoundingPPDUs:1; /* Static via CFG */ + uint8_t rxAS:1; /* Static via CFG */ + uint8_t antennaIndicesFeedback:1; /* Static via CFG */ + uint8_t explicitCSIFeedback:1; /* Static via CFG */ + uint8_t antennaIndicesFeedbackTx:1; /* Static via CFG */ + uint8_t explicitCSIFeedbackTx:1; /* Static via CFG */ + uint8_t antennaSelection:1; /* Static via CFG */ +#else + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved2:1; +#endif +} cdf_packed tSirMacASCapabilityInfo; + +/* Additional HT IE Field1 */ +typedef struct sSirMacHTInfoField1 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t serviceIntervalGranularity:3; /* Dynamic state */ + uint8_t controlledAccessOnly:1; /* Static via CFG */ + uint8_t rifsMode:1; /* Dynamic state */ + uint8_t recommendedTxWidthSet:1; /* Dynamic state */ + uint8_t secondaryChannelOffset:2; /* Dynamic state */ +#else + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; +#endif +} cdf_packed tSirMacHTInfoField1; + +/* Additional HT IE Field2 */ +typedef struct sSirMacHTInfoField2 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:11; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t transmitBurstLimit:1; + uint16_t nonGFDevicesPresent:1; + uint16_t opMode:2; /* Dynamic state */ +#else + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t reserved:11; +#endif +} cdf_packed tSirMacHTInfoField2; + +/* Additional HT IE Field3 */ +typedef struct sSirMacHTInfoField3 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:4; + uint16_t pcoPhase:1; /* Dynamic state */ + uint16_t pcoActive:1; /* Dynamic state */ + uint16_t lsigTXOPProtectionFullSupport:1; /* Dynamic state */ + uint16_t secondaryBeacon:1; /* Dynamic state */ + uint16_t dualCTSProtection:1; /* Dynamic state */ + uint16_t basicSTBCMCS:7; /* Dynamic state */ +#else + uint16_t basicSTBCMCS:7; + uint16_t dualCTSProtection:1; + uint16_t secondaryBeacon:1; + uint16_t lsigTXOPProtectionFullSupport:1; + uint16_t pcoActive:1; + uint16_t pcoPhase:1; + uint16_t reserved:4; +#endif +} cdf_packed tSirMacHTInfoField3; + +typedef struct sSirMacProbeReqFrame { + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} cdf_packed tSirMacProbeReqFrame, *tpSirMacProbeReqFrame; + +typedef struct sSirMacProbeRspFrame { + tSirMacTimeStamp ts; + tSirMacBeaconInterval beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; + tSirMacNonErpPresentIE nonErpPresent; + tSirMacDsParamSetIE dsParamsIE; + tSirMacCfParamSetIE cfParamsIE; +} cdf_packed tSirMacProbeRspFrame, *tpSirMacProbeRspFrame; + +typedef struct sSirMacAuthFrameBody { + uint16_t authAlgoNumber; + uint16_t authTransactionSeqNumber; + uint16_t authStatusCode; + uint8_t type; /* = SIR_MAC_CHALLENGE_TEXT_EID */ + uint8_t length; /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */ + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; +} cdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody; + +typedef struct sSirMacAuthenticationFrame { + tSirMacAuthFrameBody authFrameBody; +} cdf_packed tSirMacAuthFrame, *tpSirMacAuthFrame; + +typedef struct sSirMacAssocReqFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} cdf_packed tSirMacAssocReqFrame, *tpSirMacAssocReqFrame; + +typedef struct sSirMacAssocRspFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t statusCode; + uint16_t aid; + tSirMacRateSetIE supportedRates; + tSirMacRateSetIE extendedRateSetIE; +} cdf_packed tSirMacAssocRspFrame, *tpSirMacAssocRspFrame; + +typedef struct sSirMacDisassocFrame { + uint16_t reasonCode; +} cdf_packed tSirMacDisassocFrame, *tpSirMacDisassocFrame; + +typedef struct sDSirMacDeauthFrame { + uint16_t reasonCode; +} cdf_packed tSirMacDeauthFrame, *tpSirMacDeauthFrame; + +/* / Common header for all action frames */ +typedef struct sSirMacActionFrameHdr { + uint8_t category; + uint8_t actionID; +} cdf_packed tSirMacActionFrameHdr, *tpSirMacActionFrameHdr; + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +typedef struct sSirMacVendorSpecificFrameHdr { + uint8_t category; + uint8_t Oui[4]; +} cdf_packed tSirMacVendorSpecificFrameHdr, +*tpSirMacVendorSpecificFrameHdr; +#endif + +typedef struct sSirMacVendorSpecificPublicActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} cdf_packed tSirMacVendorSpecificPublicActionFrameHdr, +*tpSirMacVendorSpecificPublicActionFrameHdr; + +typedef struct sSirMacP2PActionFrameHdr { + uint8_t category; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} cdf_packed tSirMacP2PActionFrameHdr, *tpSirMacP2PActionFrameHdr; + +typedef struct sSirMacMeasActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t dialogToken; +} tSirMacMeasActionFrameHdr, *tpSirMacMeasActionFrameHdr; + +#ifdef ANI_SUPPORT_11H +typedef struct sSirMacTpcReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + uint8_t type; + uint8_t length; +} tSirMacTpcReqActionFrame, *tpSirMacTpcReqActionFrame; +typedef struct sSirMacMeasReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + tSirMacMeasReqIE measReqIE; +} tSirMacMeasReqActionFrame, *tpSirMacMeasReqActionFrame; +#endif + +#if defined WLAN_FEATURE_VOWIFI + +typedef struct sSirMacNeighborReportReq { + uint8_t dialogToken; + uint8_t ssid_present; + tSirMacSSid ssid; +} tSirMacNeighborReportReq, *tpSirMacNeighborReportReq; + +typedef struct sSirMacLinkReport { + uint8_t dialogToken; + uint8_t txPower; + uint8_t rxAntenna; + uint8_t txAntenna; + uint8_t rcpi; + uint8_t rsni; +} tSirMacLinkReport, *tpSirMacLinkReport; + +#define BEACON_REPORT_MAX_IES 224 /* Refer IEEE 802.11k-2008, Table 7-31d */ +typedef struct sSirMacBeaconReport { + uint8_t regClass; + uint8_t channel; + uint8_t measStartTime[8]; + uint8_t measDuration; + uint8_t phyType; + uint8_t bcnProbeRsp; + uint8_t rsni; + uint8_t rcpi; + tSirMacAddr bssid; + uint8_t antennaId; + uint32_t parentTSF; + uint8_t numIes; + uint8_t Ies[BEACON_REPORT_MAX_IES]; + +} tSirMacBeaconReport, *tpSirMacBeaconReport; + +#define RADIO_REPORTS_MAX_IN_A_FRAME 4 +typedef struct sSirMacRadioMeasureReport { + uint8_t token; + uint8_t refused; + uint8_t incapable; + uint8_t type; + union { + tSirMacBeaconReport beaconReport; + } report; + +} tSirMacRadioMeasureReport, *tpSirMacRadioMeasureReport; + +#endif + +/* QOS action frame definitions */ + +/* max number of possible tclas elements in any frame */ +#define SIR_MAC_TCLASIE_MAXNUM 2 + +/* 11b rate encoding in MAC format */ + +#define SIR_MAC_RATE_1 0x02 +#define SIR_MAC_RATE_2 0x04 +#define SIR_MAC_RATE_5_5 0x0B +#define SIR_MAC_RATE_11 0x16 + +/* 11a/g rate encoding in MAC format */ + +#define SIR_MAC_RATE_6 0x0C +#define SIR_MAC_RATE_9 0x12 +#define SIR_MAC_RATE_12 0x18 +#define SIR_MAC_RATE_18 0x24 +#define SIR_MAC_RATE_24 0x30 +#define SIR_MAC_RATE_36 0x48 +#define SIR_MAC_RATE_48 0x60 +#define SIR_MAC_RATE_54 0x6C + +/* ANI legacy supported rates */ +#define SIR_MAC_RATE_72 0x01 +#define SIR_MAC_RATE_96 0x03 +#define SIR_MAC_RATE_108 0x05 + +/* ANI enhanced rates */ +#define SIR_MAC_RATE_42 1000 +#define SIR_MAC_RATE_84 1001 +#define SIR_MAC_RATE_126 1002 +#define SIR_MAC_RATE_144 1003 +#define SIR_MAC_RATE_168 1004 +#define SIR_MAC_RATE_192 1005 +#define SIR_MAC_RATE_216 1006 +#define SIR_MAC_RATE_240 1007 + +#define SIR_MAC_RATE_1_BITMAP (1<<0) +#define SIR_MAC_RATE_2_BITMAP (1<<1) +#define SIR_MAC_RATE_5_5_BITMAP (1<<2) +#define SIR_MAC_RATE_11_BITMAP (1<<3) +#define SIR_MAC_RATE_6_BITMAP (1<<4) +#define SIR_MAC_RATE_9_BITMAP (1<<5) +#define SIR_MAC_RATE_12_BITMAP (1<<6) +#define SIR_MAC_RATE_18_BITMAP (1<<7) +#define SIR_MAC_RATE_24_BITMAP (1<<8) +#define SIR_MAC_RATE_36_BITMAP (1<<9) +#define SIR_MAC_RATE_48_BITMAP (1<<10) +#define SIR_MAC_RATE_54_BITMAP (1<<11) + +#define sirIsArate(x) ((((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define sirIsBrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11)) + +#define sirIsGrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11) || \ + (((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define SIR_MAC_MIN_IE_LEN 2 /* Minimum IE length for IE validation */ + +#define SIR_MAC_TI_TYPE_REASSOC_DEADLINE 1 +#define SIR_MAC_TI_TYPE_KEY_LIFETIME 2 +#define SIR_MAC_TI_TYPE_ASSOC_COMEBACK 3 + +#define SIR_MAC_VHT_CAP_MAX_MPDU_LEN 0 +#define SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET 2 +#define SIR_MAC_VHT_CAP_LDPC_CODING_CAP 4 +#define SIR_MAC_VHT_CAP_SHORTGI_80MHZ 5 +#define SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ 6 +#define SIR_MAC_VHT_CAP_TXSTBC 7 +#define SIR_MAC_VHT_CAP_RXSTBC 8 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP 11 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP 12 +#define SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP 13 +#define SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM 16 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP 19 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP 20 +#define SIR_MAC_VHT_CAP_TXOPPS 21 +#define SIR_MAC_VHT_CAP_HTC_CAP 22 +#define SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO 23 +#define SIR_MAC_VHT_CAP_LINK_ADAPT_CAP 26 +#define SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN 28 +#define SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN 29 +#define SIR_MAC_VHT_CAP_RESERVED2 30 + +#define SIR_MAC_HT_CAP_ADVCODING_S 0 +#define SIR_MAC_HT_CAP_CHWIDTH40_S 1 +#define SIR_MAC_HT_CAP_SMPOWERSAVE_DYNAMIC_S 2 +#define SIR_MAC_HT_CAP_SM_RESERVED_S 3 +#define SIR_MAC_HT_CAP_GREENFIELD_S 4 +#define SIR_MAC_HT_CAP_SHORTGI20MHZ_S 5 +#define SIR_MAC_HT_CAP_SHORTGI40MHZ_S 6 +#define SIR_MAC_HT_CAP_TXSTBC_S 7 +#define SIR_MAC_HT_CAP_RXSTBC_S 8 +#define SIR_MAC_HT_CAP_DELAYEDBLKACK_S 10 +#define SIR_MAC_HT_CAP_MAXAMSDUSIZE_S 11 +#define SIR_MAC_HT_CAP_DSSSCCK40_S 12 +#define SIR_MAC_HT_CAP_PSMP_S 13 +#define SIR_MAC_HT_CAP_INTOLERANT40_S 14 +#define SIR_MAC_HT_CAP_LSIGTXOPPROT_S 15 + +#define SIR_MAC_TXSTBC 1 +#define SIR_MAC_RXSTBC 1 + +#endif /* __MAC_PROT_DEFS_H */ diff --git a/core/mac/inc/sir_types.h b/core/mac/inc/sir_types.h new file mode 100644 index 0000000000..84032abae6 --- /dev/null +++ b/core/mac/inc/sir_types.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_types.h contains the common types + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + */ + +#ifndef __SIR_TYPES_H +#define __SIR_TYPES_H + +#include "cdf_types.h" + + +/** ------------------------------------------------------------------------ * + + \typedef tHalHandle + + \brief Handle to the HAL. The HAL handle is returned by the HAL after it + is opened (by calling halOpen). + + ------------------------------------------------------------------------- */ +typedef void *tHalHandle; + +/** ------------------------------------------------------------------------ * + + \typedef tHddHandle + + \brief Handle to the HDD. The HDD handle is given to the HAL from + the HDD on halOpen. The HDD handle is an input to all HDD/PAL function + calls and represents an opaque handle to the HDD instance that is tied + to the HAL instance, opened through halOpen. + + The HDD must be able to derive it's internal instance structure pointer + through this handle. hint hint... + + ------------------------------------------------------------------------- */ +typedef void *tHddHandle; + +/* ********************************************** * +* * +* SIRIUS ERROR Codes / Return Codes * +* * +* ********************************************** */ + +/* / Return status type */ +typedef enum eSirRetStatus { + eSIR_SUCCESS, + eSIR_FAILURE, + + /* / System Errors */ + eSIR_SYS_ERROR_BASE = 0x100, + eSIR_SYS_TX_THREAD_CREATE_FAILED, + eSIR_SYS_TX_THREAD_RESUME_FAILED, + eSIR_SYS_TX_MSG_Q_CREATE_FAILED, + eSIR_SYS_TX_Q_SEND_FAILED, + eSIR_SYS_TX_Q_RECV_FAILED, + eSIR_SYS_TX_TIMER_ACTIVATE_FAILED, + eSIR_SYS_TX_TIMER_CHANGE_FAILED, + eSIR_SYS_TX_TIMER_CREATE_FAILED, + eSIR_MEM_ALLOC_FAILED, + eSIR_PCI_ERROR, + + /* Driver Return Codes */ + eSIR_HAL_ERROR_BASE = 0x1000, + eSIR_HAL_STAID_INVALID, /* 1 */ + eSIR_HAL_TCDESC_INVALID, /* 2 */ + eSIR_HAL_TX_WQ_NOT_VALID, /* 3 */ + eSIR_HAL_PREV_BMU_CMD_INCOMPLETE, /* 4 */ + eSIR_HAL_EEPROM_CRC_FAILED, /* 5 */ + eSIR_HAL_PCI_REVID_INVALID, /* 6 */ + eSIR_HAL_STA_TC_ID_INVALID, /* 7 */ + eSIR_HAL_TXWQ_EMPTY, /* 8 */ + eSIR_HAL_ROUT_TBL_TYPE_STYPE_INVALID, /* 9 */ + eSIR_HAL_TFP_ENABLE_FAILED, /* a */ + eSIR_HAL_TFP_ABORT_CMD_FAILED, /* b */ + eSIR_HAL_TFP_TEMPL_BCNLEN_INVALID, /* c */ + eSIR_HAL_TFP_TEMPL_SCHLEN_INVALID, /* d */ + eSIR_HAL_TFP_TEMPL_CFENDLEN_INVALID, /* e */ + eSIR_HAL_TFP_TEMPL_RRLEN_INVALID, /* f */ + eSIR_HAL_TFP_TEMPL_PSPOLLLEN_INVALID, /* 10 */ + eSIR_HAL_TFP_TEMPL_CTSLEN_INVALID, /* 11 */ + eSIR_HAL_TFP_TEMPL_CFPOLLLEN_INVALID, /* 12 */ + eSIR_HAL_TFP_TEMPL_BACKLEN_INVALID, /* 13 */ + eSIR_HAL_INPUT_INVALID, /* 14 */ + eSIR_HAL_GET_PDU_FAILED, /* 15 */ + eSIR_HAL_ADD_STA_ACK_POLICY_INVALID, /* 16 */ + eSIR_HAL_STA_EXISTS, /* 17 */ + eSIR_HAL_STA_DOES_NOT_EXIST, /* 18 */ + eSIR_HAL_MASTER_WQ_ID_INVALID, /* 19 */ + eSIR_HAL_WQ_NOT_EMPTY, /* 1a */ + eSIR_HAL_WQ_EMPTY, /* 1b */ + eSIR_HAL_PDUCNT_AND_NEXTPTR_MISMATCH, /* 1c */ + eSIR_HAL_ERR_NUM_BYTES_TO_BE_SET_TOO_BIG, /* 1d */ + eSIR_HAL_GET_PKT_LENGTH_INVALID, /* 1e */ + eSIR_HAL_AS_CNT_INVALID, /* 1f */ + eSIR_HAL_RFP_AGE_CMD_SEQFAIL, /* 20 */ + eSIR_HAL_RFP_AGE_CMD_AGE_CMD_TCFAIL, /* 21 */ + eSIR_HAL_RFP_AGE_CMD_PASS, /* 22 */ + eSIR_HAL_RFP_AGE_CMD_TIMEDOUT, /* 23 */ + eSIR_HAL_RHP_HASH_CMD_TIMEOUT, /* 24 */ + eSIR_HAL_RHP_ROUTING_TBL_SET_FAILED, /* 25 */ + eSIR_HAL_RHP_ROUTING_TBL_GET_FAILED, /* 26 */ + + eSIR_HAL_CAL_STATUS_CHK_FAILED, + + eSIR_HAL_SYS_ARM_DBG_MODE_SET_FAILED, + eSIR_HAL_TFP_BCN_SENT, + eSIR_HAL_TFP_BCN_NOT_SENT, + eSIR_HAL_TFP_BKOF_ID_INVALID, + eSIR_HAL_TFP_CFB_ENABLE_INPUT_INVALID, + eSIR_HAL_TFP_EDCF_TXOP_INVALID, + eSIR_HAL_TFP_TEMPL_LEN_INVALID, + eSIR_HAL_KEY_ID_INVALID, + eSIR_HAL_KEY_LEN_INVALID, + eSIR_HAL_CHID_INVALID, + eSIR_HAL_HIF_BURST_READ_FAILED, + eSIR_HAL_HIF_BURST_WRITE_FAILED, + eSIR_HAL_HIF_BURST_LEN_REQ_INVALID, + eSIR_HAL_HIF_TX_NO_FRAG_DESC, + + eSIR_HAL_INVALID_PRODUCT_ID, /* 44 */ + + eSIR_HAL_INVALID_CAPABILITY, /* 48 */ + eSIR_HAL_CB_NOT_ENABLED, /* 49 */ + eSIR_HAL_MAC_RATE_INVALID, /* 4a */ + eSIR_HAL_RHP_HANG, /* 4b */ + eSIR_HAL_UNSUPPORTED, /* 4c */ + eSIR_HAL_TSPEC_INVALID, /* 4d */ + + /* NIM Return Codes */ + eSIR_NIM_ERROR_BASE = 0x2000, + eSIR_NIM_ERR_INVALID_EVENT, + + /* MMH Return Codes */ + eSIR_NIM_MMH_ERROR_BASE = 0x2100, + eSIR_NIM_MMH_ERR_INV_EVENT, + eSIR_NIM_MMH_ERR_MSG_LEN, + eSIR_NIM_MMH_ERR_IN_Q_TYPE, + + /* MNT Return Codes */ + eSIR_NIM_MNT_ERROR_BASE = 0x2140, + + /* WDT Errors */ + eSIR_NIM_WDT_ERROR_BASE = 0x2180, + + /* LIM Return Codes */ + eSIR_LIM_ERROR_BASE = 0x2200, + eSIR_LIM_IGNORE_BEACON, + eSIR_LIM_INVALID_STA, + eSIR_LIM_MAX_STA_REACHED_ERROR, + + /* SCH Return Codes */ + eSIR_SCH_ERROR_BASE = 0x2300, + + /* PMM Return Codes */ + eSIR_PMM_ERROR_BASE = 0x2400, + eSIR_PMM_INVALID_MODE, + eSIR_PMM_INVALID_STATE, + eSIR_PMM_INVALID_ROLE, + eSIR_PMM_STA_NOT_ASSOCIATED, + eSIR_PMM_HEART_BEAT_TMOUT, + eSIR_PMM_NTH_BEACON_DELIVERY, + + /* ARQ Return Codes */ + eSIR_ARQ_ERROR_BASE = 0x2500, + + /* CFG Return Codes */ + eSIR_CFG_ERROR_BASE = 2600, + eSIR_CFG_INVALID_ID, + eSIR_CFG_INVALID_LEN, + + /* parser Return Codes */ + eSIR_PRS_ERROR_BASE = 0x2700, + eSIR_IGNORE_IE, + + /* Put all your return codes above this line */ + eSIR_ERROR_LAST +} tSirRetStatus; + +#define IS_SIR_STATUS_SUCCESS(status) (eSIR_SUCCESS == status) +typedef enum { + HAL_STOP_TYPE_SYS_RESET, + HAL_STOP_TYPE_SYS_DEEP_SLEEP, + HAL_STOP_TYPE_RF_KILL, +} tHalStopType; + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define HAL_NUM_ASSOC_STA 32 +#define HAL_NUM_STA 41 +#define HAL_NUM_HW_STA 16 +#define HAL_NUM_GPSTA 4 + +/* is the STA a HW STA (excluding GP STAs) */ +#define IS_HWSTA_IDX(__x) \ + ((__x) < (HAL_NUM_HW_STA-HAL_NUM_GPSTA)) + +#else +/*In prima 12 HW stations are supported including BCAST STA(staId 0) + and SELF STA(staId 1) so total ASSOC stations which can connect to Prima + SoftAP = 12 - 1(Self STa) - 1(Bcast Sta) = 10 Stations. */ +#define HAL_NUM_STA 12 +#define HAL_NUM_ASSOC_STA 10 +#define HAL_NUM_HW_STA 12 +#endif + +#define STACFG_MAX_TC 8 + +#endif /* __SIR_TYPES_H */ diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h new file mode 100644 index 0000000000..9c279eada3 --- /dev/null +++ b/core/mac/inc/wni_api.h @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file wni_api.h contains message definitions exported by + * Sirius software modules. + * NOTE: See projects/sirius/include/sir_api.h for structure + * definitions of the host/FW messages. + * + * Author: Chandra Modumudi + * Date: 04/11/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __WNI_API_H +#define __WNI_API_H + +/* / Start of Sirius/Host message types */ +#define WNI_HOST_MSG_START 0x1500 + +enum eWniMsgTypes { + /* / CFG message types */ + eWNI_CFG_MSG_TYPES_BEGIN = WNI_HOST_MSG_START, + eWNI_CFG_MSG_TYPES_END = eWNI_CFG_MSG_TYPES_BEGIN + 0xFF, + + /* / SME message types */ + eWNI_SME_MSG_TYPES_BEGIN = eWNI_CFG_MSG_TYPES_END, + eWNI_SME_SYS_READY_IND, + eWNI_SME_SCAN_REQ, + eWNI_SME_SCAN_ABORT_IND, + eWNI_SME_SCAN_RSP, +#ifdef FEATURE_OEM_DATA_SUPPORT + eWNI_SME_OEM_DATA_REQ, + eWNI_SME_OEM_DATA_RSP, +#endif + eWNI_SME_JOIN_REQ, + eWNI_SME_JOIN_RSP, + eWNI_SME_SETCONTEXT_REQ, + eWNI_SME_SETCONTEXT_RSP, + eWNI_SME_REASSOC_REQ, + eWNI_SME_REASSOC_RSP, + eWNI_SME_DISASSOC_REQ, + eWNI_SME_DISASSOC_RSP, + eWNI_SME_DISASSOC_IND, + eWNI_SME_DISASSOC_CNF, + eWNI_SME_DEAUTH_REQ, + eWNI_SME_DEAUTH_RSP, + eWNI_SME_DEAUTH_IND, + eWNI_SME_WM_STATUS_CHANGE_NTF, + eWNI_SME_IBSS_NEW_PEER_IND, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + eWNI_SME_START_BSS_REQ, + eWNI_SME_START_BSS_RSP, + eWNI_SME_ASSOC_IND, + eWNI_SME_ASSOC_CNF, + eWNI_SME_SWITCH_CHL_IND, + eWNI_SME_STOP_BSS_REQ, + eWNI_SME_STOP_BSS_RSP, + eWNI_SME_NEIGHBOR_BSS_IND, + eWNI_SME_DEAUTH_CNF, + eWNI_SME_MIC_FAILURE_IND, + eWNI_SME_ADDTS_REQ, + eWNI_SME_ADDTS_RSP, + eWNI_SME_DELTS_REQ, + eWNI_SME_DELTS_RSP, + eWNI_SME_DELTS_IND, + eWNI_SME_GET_STATISTICS_REQ, + eWNI_SME_GET_STATISTICS_RSP, + eWNI_SME_GET_RSSI_REQ, + eWNI_SME_GET_ASSOC_STAS_REQ, + eWNI_SME_TKIP_CNTR_MEAS_REQ, + eWNI_SME_UPDATE_APWPSIE_REQ, + eWNI_SME_GET_WPSPBC_SESSION_REQ, + eWNI_SME_WPS_PBC_PROBE_REQ_IND, + eWNI_SME_SET_APWPARSNIEs_REQ, + eWNI_SME_UPPER_LAYER_ASSOC_CNF, + eWNI_SME_HIDE_SSID_REQ, + eWNI_SME_CHNG_MCC_BEACON_INTERVAL, + eWNI_SME_REMAIN_ON_CHANNEL_REQ, + eWNI_SME_REMAIN_ON_CHN_RSP, + eWNI_SME_MGMT_FRM_IND, + eWNI_SME_REMAIN_ON_CHN_RDY_IND, + eWNI_SME_SEND_ACTION_FRAME_IND, + eWNI_SME_ACTION_FRAME_SEND_CNF, + eWNI_SME_ABORT_REMAIN_ON_CHAN_IND, + eWNI_SME_UPDATE_NOA, + eWNI_SME_CLEAR_DFS_CHANNEL_LIST, + eWNI_SME_GET_SNR_REQ, + /* General Power Save Messages */ + eWNI_PMC_MSG_TYPES_BEGIN, + + /* WOWL Messages */ + eWNI_PMC_SMPS_STATE_IND, + +#if defined WLAN_FEATURE_VOWIFI + eWNI_SME_RRM_MSG_TYPE_BEGIN, + + eWNI_SME_NEIGHBOR_REPORT_REQ_IND, + eWNI_SME_NEIGHBOR_REPORT_IND, + eWNI_SME_BEACON_REPORT_REQ_IND, + eWNI_SME_BEACON_REPORT_RESP_XMIT_IND, + +#endif + eWNI_SME_ADD_STA_SELF_RSP, + eWNI_SME_DEL_STA_SELF_RSP, + +#if defined WLAN_FEATURE_VOWIFI_11R + eWNI_SME_FT_PRE_AUTH_REQ, + eWNI_SME_FT_PRE_AUTH_RSP, + eWNI_SME_FT_UPDATE_KEY, + eWNI_SME_FT_AGGR_QOS_REQ, + eWNI_SME_FT_AGGR_QOS_RSP, +#endif + +#if defined FEATURE_WLAN_ESE + eWNI_SME_ESE_ADJACENT_AP_REPORT, +#endif + + eWNI_SME_REGISTER_MGMT_FRAME_REQ, +#ifdef FEATURE_WLAN_SCAN_PNO + eWNI_SME_PREF_NETWORK_FOUND_IND, +#endif /* FEATURE_WLAN_SCAN_PNO */ + + eWNI_SME_CHANGE_COUNTRY_CODE, + eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE, + eWNI_SME_MAX_ASSOC_EXCEEDED, +#ifdef FEATURE_WLAN_TDLS + eWNI_SME_TDLS_SEND_MGMT_REQ, + eWNI_SME_TDLS_SEND_MGMT_RSP, + eWNI_SME_TDLS_ADD_STA_REQ, + eWNI_SME_TDLS_ADD_STA_RSP, + eWNI_SME_TDLS_DEL_STA_REQ, + eWNI_SME_TDLS_DEL_STA_RSP, + eWNI_SME_TDLS_DEL_STA_IND, + eWNI_SME_TDLS_DEL_ALL_PEER_IND, + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND, + eWNI_SME_TDLS_LINK_ESTABLISH_REQ, + eWNI_SME_TDLS_LINK_ESTABLISH_RSP, + eWNI_SME_TDLS_SHOULD_DISCOVER, + eWNI_SME_TDLS_SHOULD_TEARDOWN, + eWNI_SME_TDLS_PEER_DISCONNECTED, +#endif + /* NOTE: If you are planning to add more mesages, please make sure that */ + /* SIR_LIM_ITC_MSG_TYPES_BEGIN is moved appropriately. It is set as */ + /* SIR_LIM_MSG_TYPES_BEGIN+0xB0 = 12B0 (which means max of 176 messages and */ + /* eWNI_SME_TDLS_DEL_STA_RSP = 175. */ + /* Should fix above issue to enable TDLS_INTERNAL */ + eWNI_SME_SET_BCN_FILTER_REQ, + eWNI_SME_RESET_AP_CAPS_CHANGED, +#ifdef WLAN_FEATURE_11W + eWNI_SME_UNPROT_MGMT_FRM_IND, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + eWNI_SME_CANDIDATE_FOUND_IND, /*ROAM candidate indication from FW */ + eWNI_SME_HANDOFF_REQ, /*upper layer requested handoff to driver in STA mode */ + eWNI_SME_ROAM_SCAN_OFFLOAD_RSP, /*Fwd the LFR scan offload rsp from FW to SME */ +#ifdef FEATURE_WLAN_LPHB + eWNI_SME_LPHB_IND, +#endif /* FEATURE_WLAN_LPHB */ + + eWNI_SME_GET_TSM_STATS_REQ, + eWNI_SME_GET_TSM_STATS_RSP, + eWNI_SME_TSM_IE_IND, + + eWNI_SME_READY_TO_SUSPEND_IND, +#ifdef FEATURE_WLAN_CH_AVOID + eWNI_SME_CH_AVOID_IND, +#endif /* FEATURE_WLAN_CH_AVOID */ + /* DFS EVENTS */ + eWNI_SME_DFS_RADAR_FOUND, /* RADAR found indication from DFS */ + eWNI_SME_CHANNEL_CHANGE_REQ, /* Channel Change Request from SAP */ + eWNI_SME_CHANNEL_CHANGE_RSP, /* Channel Change Response from WMA */ + eWNI_SME_START_BEACON_REQ, /* Start Beacon Transmission. */ + eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ, /* Transmit CSA IE in beacons */ + eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND, /* To indicate completion of CSA IE */ + /* update in beacons/probe rsp */ + eWNI_SME_STATS_EXT_EVENT, + eWNI_SME_LINK_SPEED_IND, /* Indicate linkspeed response from WMA */ + eWNI_SME_CSA_OFFLOAD_EVENT, + eWNI_SME_UPDATE_ADDITIONAL_IES, /* indicates Additional IE from hdd to PE */ + eWNI_SME_MODIFY_ADDITIONAL_IES, /* To indicate IE modify from hdd to PE */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + eWNI_SME_AUTO_SHUTDOWN_IND, +#endif +#ifdef QCA_HT_2040_COEX + eWNI_SME_SET_HT_2040_MODE, +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + eWNI_SME_ROAM_OFFLOAD_SYNCH_IND, /* Roam Synch Indication from WMA to SME */ + eWNI_SME_HO_FAIL_IND, /* Hand Off Failure Ind from WMA to SME */ +#endif +#ifdef WLAN_FEATURE_NAN + eWNI_SME_NAN_EVENT, +#endif + eWNI_SME_LINK_STATUS_IND, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + eWNI_SME_READY_TO_EXTWOW_IND, +#endif + eWNI_SME_MSG_GET_TEMPERATURE_IND, + eWNI_SME_SNR_IND, +#ifdef FEATURE_WLAN_EXTSCAN + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND, + eWNI_SME_EPNO_NETWORK_FOUND_IND, +#endif + eWNI_SME_FW_DUMP_IND, + eWNI_SME_SET_HW_MODE_REQ, + eWNI_SME_SET_HW_MODE_RESP, + eWNI_SME_HW_MODE_TRANS_IND, + eWNI_SME_NSS_UPDATE_REQ, + eWNI_SME_NSS_UPDATE_RSP, + eWNI_SME_SCAN_CMD, + eWNI_SME_OCB_SET_CONFIG_RSP, + eWNI_SME_OCB_GET_TSF_TIMER_RSP, + eWNI_SME_DCC_GET_STATS_RSP, + eWNI_SME_DCC_UPDATE_NDL_RSP, + eWNI_SME_DCC_STATS_EVENT, + eWNI_SME_SET_DUAL_MAC_CFG_REQ, + eWNI_SME_SET_DUAL_MAC_CFG_RESP, + eWNI_SME_ROC_CMD, + eWNI_SME_SET_THERMAL_LEVEL_IND, + eWNI_SME_SET_IE_REQ, + eWNI_SME_MSG_TYPES_END +}; + +typedef enum { + eWNI_TDLS_TEARDOWN_REASON_TX, + eWNI_TDLS_TEARDOWN_REASON_RSSI, + eWNI_TDLS_TEARDOWN_REASON_SCAN, + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + eWNI_TDLS_TEARDOWN_REASON_BAD_PTR, + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE, +} eWniTdlsTeardownReason; + +#define WNI_CFG_MSG_TYPES_BEGIN 0x1200 + +/*---------------------------------------------------------------------*/ +/* CFG Module Definitions */ +/*---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------*/ +/* CFG message definitions */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_MSG_HDR_MASK 0xffff0000 +#define WNI_CFG_MSG_LEN_MASK 0x0000ffff +#define WNI_CFG_MB_HDR_LEN 4 +#define WNI_CFG_MAX_PARAM_NUM 32 + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_PARAM_UPDATE_IND (WNI_CFG_MSG_TYPES_BEGIN | 0x00) +#define WNI_CFG_DNLD_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x01) +#define WNI_CFG_DNLD_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x02) +#define WNI_CFG_GET_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x03) +#define WNI_CFG_SET_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x04) +#define WNI_CFG_GET_ATTRIB_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x05) +#define WNI_CFG_ADD_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x06) +#define WNI_CFG_DEL_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x07) + +#define ANI_CFG_GET_RADIO_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define ANI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define ANI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define ANI_CFG_CLEAR_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message paramter indices */ + +/* The followings are word indices starting from the message body */ + +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ + +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Parameter update indication */ +#define WNI_CFG_PARAM_UPDATE_IND_PID 0 + +#define WNI_CFG_PARAM_UPDATE_IND_NUM 1 +#define WNI_CFG_PARAM_UPDATE_IND_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_PARAM_UPDATE_IND_NUM << 2)) + +/* Configuration download request */ +#define WNI_CFG_DNLD_REQ_NUM 0 +#define WNI_CFG_DNLD_REQ_LEN WNI_CFG_MB_HDR_LEN + +/* Configuration download confirm */ +#define WNI_CFG_DNLD_CNF_RES 0 + +#define WNI_CFG_DNLD_CNF_NUM 1 +#define WNI_CFG_DNLD_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_CNF_NUM << 2)) +/* Get response */ +#define WNI_CFG_GET_RSP_RES 0 +#define WNI_CFG_GET_RSP_PID 1 +#define WNI_CFG_GET_RSP_PLEN 2 + +#define WNI_CFG_GET_RSP_NUM 3 +#define WNI_CFG_GET_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_RSP_NUM << 2)) +/* Set confirm */ +#define WNI_CFG_SET_CNF_RES 0 +#define WNI_CFG_SET_CNF_PID 1 + +#define WNI_CFG_SET_CNF_NUM 2 +#define WNI_CFG_SET_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_SET_CNF_NUM << 2)) +/* Get attribute response */ +#define WNI_CFG_GET_ATTRIB_RSP_RES 0 +#define WNI_CFG_GET_ATTRIB_RSP_PID 1 +#define WNI_CFG_GET_ATTRIB_RSP_TYPE 2 +#define WNI_CFG_GET_ATTRIB_RSP_PLEN 3 +#define WNI_CFG_GET_ATTRIB_RSP_RW 4 + +#define WNI_CFG_GET_ATTRIB_RSP_NUM 5 +#define WNI_CFG_GET_ATTRIB_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_ATTRIB_RSP_NUM << 2)) + +/* Add group address confirm */ +#define WNI_CFG_ADD_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_ADD_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_ADD_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_ADD_GRP_ADDR_CNF_NUM << 2)) + +/* Delete group address confirm */ +#define WNI_CFG_DEL_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_DEL_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_DEL_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DEL_GRP_ADDR_CNF_NUM << 2)) + +#define IS_CFG_MSG(msg) ((msg & 0xff00) == WNI_CFG_MSG_TYPES_BEGIN) + +/* Clear stats types. */ +#define ANI_CLEAR_ALL_STATS 0 +#define ANI_CLEAR_RX_STATS 1 +#define ANI_CLEAR_TX_STATS 2 +#define ANI_CLEAR_PER_STA_STATS 3 +#define ANI_CLEAR_AGGR_PER_STA_STATS 4 +#define ANI_CLEAR_STAT_TYPES_END 5 + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_DNLD_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x80) +#define WNI_CFG_GET_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x81) +#define WNI_CFG_SET_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x82) +#define WNI_CFG_SET_REQ_NO_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x83) /* No RSP for this set */ + +/* Shall be removed after stats integration */ + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message paramter indices */ +/* */ +/* The followings are word indices starting from the message body */ +/* */ +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ +/* */ +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Download response */ +#define WNI_CFG_DNLD_RSP_BIN_LEN 0 + +#define WNI_CFG_DNLD_RSP_NUM 1 +#define WNI_CFG_DNLD_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_RSP_NUM << 2)) + +/* Set parameter request */ +#define WNI_CFG_SET_REQ_PID 0 +#define WNI_CFG_SET_REQ_PLEN 1 + +/*---------------------------------------------------------------------*/ +/* CFG return values */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_SUCCESS 1 +#define WNI_CFG_NOT_READY 2 +#define WNI_CFG_INVALID_PID 3 +#define WNI_CFG_INVALID_LEN 4 +#define WNI_CFG_RO_PARAM 5 +#define WNI_CFG_WO_PARAM 6 +#define WNI_CFG_INVALID_STAID 7 +#define WNI_CFG_OTHER_ERROR 8 +#define WNI_CFG_NEED_RESTART 9 +#define WNI_CFG_NEED_RELOAD 10 + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* Shall be removed after integration of stats. */ +/* Get statistic response */ +#define WNI_CFG_GET_STAT_RSP_RES 0 +#define WNI_CFG_GET_STAT_RSP_PARAMID 1 +#define WNI_CFG_GET_STAT_RSP_VALUE 2 + +#define WNI_CFG_GET_STAT_RSP_NUM 3 +#define WNI_CFG_GET_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_RSP_NUM << 2)) +/* Get per station statistic response */ +#define WNI_CFG_GET_PER_STA_STAT_RSP_RES 0 +#define WNI_CFG_GET_PER_STA_STAT_RSP_STAID 1 +#define WNI_CFG_GET_PER_STA_STAT_RSP_FIRST_PARAM 2 + +/* Per STA statistic structure */ +typedef struct sAniCfgPerStaStatStruct { + unsigned long sentAesBlksUcastHi; + unsigned long sentAesBlksUcastLo; + + unsigned long recvAesBlksUcastHi; + unsigned long recvAesBlksUcastLo; + + unsigned long aesFormatErrorUcastCnts; + + unsigned long aesReplaysUcast; + + unsigned long aesDecryptErrUcast; + + unsigned long singleRetryPkts; + + unsigned long failedTxPkts; + + unsigned long ackTimeouts; + + unsigned long multiRetryPkts; + + unsigned long fragTxCntsHi; + unsigned long fragTxCntsLo; + + unsigned long transmittedPktsHi; + unsigned long transmittedPktsLo; + + unsigned long phyStatHi; + unsigned long phyStatLo; +} tCfgPerStaStatStruct, *tpAniCfgPerStaStatStruct; + +#define WNI_CFG_GET_PER_STA_STAT_RSP_NUM 23 +#define WNI_CFG_GET_PER_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_RSP_NUM << 2)) + +/* Shall be removed after integrating stats. */ +#define WNI_CFG_GET_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define WNI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define WNI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define WNI_CFG_GET_TX_RATE_CTR_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +#define WNI_CFG_GET_AGG_STA_STAT_RSP_NUM 21 +#define WNI_CFG_GET_AGG_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_AGG_STA_STAT_RSP_NUM << 2)) +#define WNI_CFG_GET_AGG_STA_STAT_RSP_RES 0 + +/* Get TX rate based stats */ +#define WNI_CFG_GET_TX_RATE_CTR_RSP_RES 0 + +typedef struct sAniCfgTxRateCtrs { +/* add the rate counters here */ + unsigned long TxFrames_1Mbps; + unsigned long TxFrames_2Mbps; + unsigned long TxFrames_5_5Mbps; + unsigned long TxFrames_6Mbps; + unsigned long TxFrames_9Mbps; + unsigned long TxFrames_11Mbps; + unsigned long TxFrames_12Mbps; + unsigned long TxFrames_18Mbps; + unsigned long TxFrames_24Mbps; + unsigned long TxFrames_36Mbps; + unsigned long TxFrames_48Mbps; + unsigned long TxFrames_54Mbps; + unsigned long TxFrames_72Mbps; + unsigned long TxFrames_96Mbps; + unsigned long TxFrames_108Mbps; + +} tAniCfgTxRateCtrs, *tpAniCfgTxRateCtrs; + +#define WNI_CFG_GET_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x86) +#define WNI_CFG_GET_PER_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x87) +#define WNI_CFG_GET_AGG_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x88) +#define WNI_CFG_GET_TX_RATE_CTR_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x89) + +/* Get statistic request */ +#define WNI_CFG_GET_STAT_REQ_PARAMID 0 + +#define WNI_CFG_GET_STAT_REQ_NUM 1 +#define WNI_CFG_GET_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_REQ_NUM << 2)) + +/* Get per station statistic request */ +#define WNI_CFG_GET_PER_STA_STAT_REQ_STAID 0 + +#define WNI_CFG_GET_PER_STA_STAT_REQ_NUM 1 +#define WNI_CFG_GET_PER_STA_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_REQ_NUM << 2)) + +#define DYNAMIC_CFG_TYPE_SELECTED_REGISTRAR (0) +#define DYNAMIC_CFG_TYPE_WPS_STATE (1) + +#endif /* __WNI_API_H */ diff --git a/core/mac/inc/wni_cfg.h b/core/mac/inc/wni_cfg.h new file mode 100644 index 0000000000..76583d0d3a --- /dev/null +++ b/core/mac/inc/wni_cfg.h @@ -0,0 +1,1572 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WNICFG_H +#define __WNICFG_H + +/* + * Configuration Parameter ID for STA + */ + +enum { + WNI_CFG_STA_ID, + WNI_CFG_CF_POLLABLE, + WNI_CFG_CFP_PERIOD, + WNI_CFG_CFP_MAX_DURATION, + WNI_CFG_SSID, + WNI_CFG_BEACON_INTERVAL, + WNI_CFG_DTIM_PERIOD, + WNI_CFG_WEP_KEY_LENGTH, + WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEYID, + WNI_CFG_EXCLUDE_UNENCRYPTED, + WNI_CFG_RTS_THRESHOLD, + WNI_CFG_SHORT_RETRY_LIMIT, + WNI_CFG_LONG_RETRY_LIMIT, + WNI_CFG_FRAGMENTATION_THRESHOLD, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_JOIN_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS, + WNI_CFG_PS_ENABLE_BCN_FILTER, + WNI_CFG_PS_ENABLE_HEART_BEAT, + WNI_CFG_PS_ENABLE_RSSI_MONITOR, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + WNI_CFG_RF_SETTLING_TIME_CLK, + WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_PHY_MODE, + WNI_CFG_DOT11_MODE, + WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + WNI_CFG_LISTEN_INTERVAL, + WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_CURRENT_CHANNEL, + WNI_CFG_DEFAULT_RATE_INDEX_5GHZ, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + WNI_CFG_RATE_ADAPTATION_TYPE, + WNI_CFG_FIXED_RATE, + WNI_CFG_FIXED_RATE_MULTICAST_24GHZ, + WNI_CFG_FIXED_RATE_MULTICAST_5GHZ, + WNI_CFG_RETRYRATE_POLICY, + WNI_CFG_RETRYRATE_SECONDARY, + WNI_CFG_RETRYRATE_TERTIARY, + WNI_CFG_APSD_ENABLED, + WNI_CFG_SHARED_KEY_AUTH_ENABLE, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + WNI_CFG_AUTHENTICATION_TYPE, + WNI_CFG_CF_POLL_REQUEST, + WNI_CFG_PRIVACY_ENABLED, + WNI_CFG_SHORT_PREAMBLE, + WNI_CFG_SHORT_SLOT_TIME, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + WNI_CFG_QOS_ENABLED, + WNI_CFG_HCF_ENABLED, + WNI_CFG_RSN_ENABLED, + WNI_CFG_MAX_NUM_PRE_AUTH, + WNI_CFG_PREAUTH_CLNUP_TIMEOUT, + WNI_CFG_RELEASE_AID_TIMEOUT, + WNI_CFG_HEART_BEAT_THRESHOLD, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + WNI_CFG_MANUFACTURER_OUI, + WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_11D_ENABLED, + WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_NETWORK_DENSITY, + WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM, + WNI_CFG_CURRENT_TX_ANTENNA, + WNI_CFG_CURRENT_RX_ANTENNA, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + WNI_CFG_NEW_BSS_FOUND_IND, + WNI_CFG_PROPRIETARY_RATES_ENABLED, + WNI_CFG_AP_NODE_NAME, + WNI_CFG_COUNTRY_CODE, + WNI_CFG_11H_ENABLED, + WNI_CFG_WT_CNF_TIMEOUT, + WNI_CFG_PROXIMITY, + WNI_CFG_LOG_LEVEL, + WNI_CFG_OLBC_DETECT_TIMEOUT, + WNI_CFG_PROTECTION_ENABLED, + WNI_CFG_11G_PROTECTION_ALWAYS, + WNI_CFG_FORCE_POLICY_PROTECTION, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + WNI_CFG_11G_ONLY_POLICY, + WNI_CFG_PACKET_CLASSIFICATION, + WNI_CFG_WME_ENABLED, + WNI_CFG_ADDTS_RSP_TIMEOUT, + WNI_CFG_MAX_SP_LENGTH, + WNI_CFG_KEEP_ALIVE_STA_LIMIT_THRESHOLD, + WNI_CFG_SEND_SINGLE_SSID_ALWAYS, + WNI_CFG_WSM_ENABLED, + WNI_CFG_EDCA_PROFILE, + WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_RDET_FLAG, + WNI_CFG_RADAR_CHANNEL_LIST, + WNI_CFG_LOCAL_POWER_CONSTRAINT, + WNI_CFG_ADMIT_POLICY, + WNI_CFG_ADMIT_BWFACTOR, + WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE, + WNI_CFG_CHANNEL_BONDING_MODE, + WNI_CFG_CB_SECONDARY_CHANNEL_STATE, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + WNI_CFG_DYNAMIC_THRESHOLD_ONE, + WNI_CFG_DYNAMIC_THRESHOLD_TWO, + WNI_CFG_TRIG_STA_BK_SCAN, + WNI_CFG_DYNAMIC_PROFILE_SWITCHING, + WNI_CFG_SCAN_CONTROL_LIST, + WNI_CFG_MIMO_ENABLED, + WNI_CFG_BLOCK_ACK_ENABLED, + WNI_CFG_HT_RX_STBC, + WNI_CFG_HT_CAP_INFO, + WNI_CFG_HT_AMPDU_PARAMS, + WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_EXT_HT_CAP_INFO, + WNI_CFG_TX_BF_CAP, + WNI_CFG_AS_CAP, + WNI_CFG_HT_INFO_FIELD1, + WNI_CFG_HT_INFO_FIELD2, + WNI_CFG_HT_INFO_FIELD3, + WNI_CFG_BASIC_MCS_SET, + WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_GREENFIELD_CAPABILITY, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + WNI_CFG_VHT_LDPC_CODING_CAP, + WNI_CFG_VHT_SHORT_GI_80MHZ, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + WNI_CFG_VHT_TXSTBC, + WNI_CFG_VHT_RXSTBC, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + WNI_CFG_VHT_TXOP_PS, + WNI_CFG_VHT_HTC_VHTC_CAP, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + WNI_CFG_VHT_LINK_ADAPTATION_CAP, + WNI_CFG_VHT_RX_ANT_PATTERN, + WNI_CFG_VHT_TX_ANT_PATTERN, + WNI_CFG_VHT_RX_MCS_MAP, + WNI_CFG_VHT_TX_MCS_MAP, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2, + WNI_CFG_VHT_BASIC_MCS_SET, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + WNI_CFG_VHT_SS_UNDER_UTIL, + WNI_CFG_VHT_40MHZ_UTILIZATION, + WNI_CFG_VHT_80MHZ_UTILIZATION, + WNI_CFG_VHT_160MHZ_UTILIZATION, + WNI_CFG_MAX_AMSDU_LENGTH, + WNI_CFG_MPDU_DENSITY, + WNI_CFG_MAX_RX_AMPDU_FACTOR, + WNI_CFG_SHORT_GI_20MHZ, + WNI_CFG_SHORT_GI_40MHZ, + WNI_CFG_RIFS_ENABLED, + WNI_CFG_MAX_PS_POLL, + WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE, + WNI_CFG_RSSI_FILTER_PERIOD, + WNI_CFG_MIN_RSSI_THRESHOLD, + WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE, + WNI_CFG_SCAN_IN_POWERSAVE, + WNI_CFG_IGNORE_DTIM, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + WNI_CFG_WOWLAN_DEAUTH_ENABLE, + WNI_CFG_WOWLAN_DISASSOC_ENABLE, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + WNI_CFG_BG_SCAN_CHANNEL_LIST, + WNI_CFG_MAX_MEDIUM_TIME, + WNI_CFG_MAX_MPDUS_IN_AMPDU, + WNI_CFG_IBSS_AUTO_BSSID, + WNI_CFG_PROBE_REQ_ADDNIE_FLAG, + WNI_CFG_PROBE_REQ_ADDNIE_DATA, + WNI_CFG_PROBE_RSP_ADDNIE_FLAG, + WNI_CFG_PROBE_RSP_ADDNIE_DATA1, + WNI_CFG_PROBE_RSP_ADDNIE_DATA2, + WNI_CFG_PROBE_RSP_ADDNIE_DATA3, + WNI_CFG_ASSOC_RSP_ADDNIE_FLAG, + WNI_CFG_ASSOC_RSP_ADDNIE_DATA, + WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG, + WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, + WNI_CFG_WPS_ENABLE, + WNI_CFG_WPS_STATE, + WNI_CFG_WPS_PROBE_REQ_FLAG, + WNI_CFG_WPS_VERSION, + WNI_CFG_WPS_REQUEST_TYPE, + WNI_CFG_WPS_CFG_METHOD, + WNI_CFG_WPS_UUID, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + WNI_CFG_WPS_PIMARY_DEVICE_OUI, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + WNI_CFG_WPS_ASSOCIATION_STATE, + WNI_CFG_WPS_CONFIGURATION_ERROR, + WNI_CFG_WPS_DEVICE_PASSWORD_ID, + WNI_CFG_WPS_ASSOC_METHOD, + WNI_CFG_LOW_GAIN_OVERRIDE, + WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE, + WNI_CFG_RPE_POLLING_THRESHOLD, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG, + WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS, + WNI_CFG_SINGLE_TID_RC, + WNI_CFG_RRM_ENABLED, + WNI_CFG_RRM_OPERATING_CHAN_MAX, + WNI_CFG_RRM_NON_OPERATING_CHAN_MAX, + WNI_CFG_TX_PWR_CTRL_ENABLE, + WNI_CFG_MCAST_BCAST_FILTER_SETTING, + WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK, + WNI_CFG_DYNAMIC_PS_POLL_VALUE, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + WNI_CFG_TELE_BCN_WAKEUP_EN, + WNI_CFG_TELE_BCN_TRANS_LI, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + WNI_CFG_TELE_BCN_MAX_LI, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + WNI_CFG_ASSOC_STA_LIMIT, + WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL, + WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL, + WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + WNI_CFG_ENABLE_CLOSE_LOOP, + WNI_CFG_ENABLE_LTE_COEX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + WNI_CFG_ENABLE_MC_ADDR_LIST, + WNI_CFG_ENABLE_UC_FILTER, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + WNI_CFG_TDLS_BUF_STA_ENABLED, + WNI_CFG_TDLS_PUAPSD_INACT_TIME, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + WNI_CFG_FLEX_CONNECT_POWER_FACTOR, + WNI_CFG_ANTENNA_DIVESITY, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + WNI_CFG_CURRENT_RSSI, + WNI_CFG_RTT3_ENABLE, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + WNI_CFG_DFS_MASTER_ENABLED, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + WNI_CFG_TDLS_WMM_MODE_ENABLED +}; +/* + * String parameter lengths + */ + +#define WNI_CFG_STA_ID_LEN 6 +#define WNI_CFG_SSID_LEN 32 +#define WNI_CFG_WEP_DEFAULT_KEY_1_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_2_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_3_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_4_LEN 13 +#define WNI_CFG_SUPPORTED_RATES_11B_LEN 4 +#define WNI_CFG_SUPPORTED_RATES_11A_LEN 8 +#define WNI_CFG_OPERATIONAL_RATE_SET_LEN 12 +#define WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN 8 +#define WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET_LEN 4 +#define WNI_CFG_VALID_CHANNEL_LIST_LEN 100 +#define WNI_CFG_MANUFACTURER_OUI_LEN 3 +#define WNI_CFG_MANUFACTURER_NAME_LEN 64 +#define WNI_CFG_MODEL_NUMBER_LEN 32 +#define WNI_CFG_MODEL_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN 32 +#define WNI_CFG_MAX_TX_POWER_2_4_LEN 128 +#define WNI_CFG_MAX_TX_POWER_5_LEN 128 +#define WNI_CFG_AP_NODE_NAME_LEN 32 +#define WNI_CFG_COUNTRY_CODE_LEN 3 +#define WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBK_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LEN 20 +#define WNI_CFG_RADAR_CHANNEL_LIST_LEN 20 +#define WNI_CFG_SCAN_CONTROL_LIST_LEN 128 +#define WNI_CFG_SUPPORTED_MCS_SET_LEN 16 +#define WNI_CFG_BASIC_MCS_SET_LEN 16 +#define WNI_CFG_CURRENT_MCS_SET_LEN 16 +#define WNI_CFG_BG_SCAN_CHANNEL_LIST_LEN 100 +#define WNI_CFG_PROBE_REQ_ADDNIE_DATA_LEN 255 +#define WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN 255 +#define WNI_CFG_PROBE_RSP_ADDNIE_DATA2_LEN 255 +#define WNI_CFG_PROBE_RSP_ADDNIE_DATA3_LEN 255 +#define WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN 255 +#define WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA_LEN 255 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN 255 +#define WNI_CFG_WPS_UUID_LEN 16 + +/* + * Integer parameter min/max/default values + */ + +#define WNI_CFG_CFP_PERIOD_STAMIN 0 +#define WNI_CFG_CFP_PERIOD_STAMAX 255 +#define WNI_CFG_CFP_PERIOD_STADEF 1 + +#define WNI_CFG_CFP_MAX_DURATION_STAMIN 0 +#define WNI_CFG_CFP_MAX_DURATION_STAMAX 65535 +#define WNI_CFG_CFP_MAX_DURATION_STADEF 30000 + +#define WNI_CFG_BEACON_INTERVAL_STAMIN 0 +#define WNI_CFG_BEACON_INTERVAL_STAMAX 65535 +#define WNI_CFG_BEACON_INTERVAL_STADEF 100 + +#define WNI_CFG_DTIM_PERIOD_STAMIN 0 +#define WNI_CFG_DTIM_PERIOD_STAMAX 65535 +#define WNI_CFG_DTIM_PERIOD_STADEF 1 + +#define WNI_CFG_WEP_KEY_LENGTH_STAMIN 5 +#define WNI_CFG_WEP_KEY_LENGTH_STAMAX 13 +#define WNI_CFG_WEP_KEY_LENGTH_STADEF 5 + +#define WNI_CFG_WEP_KEY_LENGTH_5 5 +#define WNI_CFG_WEP_KEY_LENGTH_13 13 + +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMIN 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMAX 3 +#define WNI_CFG_WEP_DEFAULT_KEYID_STADEF 0 + +#define WNI_CFG_WEP_DEFAULT_KEYID_0 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_1 1 +#define WNI_CFG_WEP_DEFAULT_KEYID_2 2 +#define WNI_CFG_WEP_DEFAULT_KEYID_3 3 + +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMIN 0 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMAX 1 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STADEF 0 + +#define WNI_CFG_RTS_THRESHOLD_STAMIN 0 +#define WNI_CFG_RTS_THRESHOLD_STAMAX 1048576 +#define WNI_CFG_RTS_THRESHOLD_STADEF 2347 + +#define WNI_CFG_SHORT_RETRY_LIMIT_STAMIN 0 +#define WNI_CFG_SHORT_RETRY_LIMIT_STAMAX 255 +#define WNI_CFG_SHORT_RETRY_LIMIT_STADEF 6 + +#define WNI_CFG_LONG_RETRY_LIMIT_STAMIN 0 +#define WNI_CFG_LONG_RETRY_LIMIT_STAMAX 255 +#define WNI_CFG_LONG_RETRY_LIMIT_STADEF 6 + +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN 256 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX 8000 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF 8000 + +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF 20 + +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF 40 + +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF 60 + +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF 110 + +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF 3000 + +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF 2000 + +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STAMIN 0 +#define WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STAMAX 65535 +#define WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STADEF 1000 + +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMIN 0 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMAX 1 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STADEF 1 + +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMIN 0 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMAX 1 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STADEF 1 + +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMIN 0 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMAX 1 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STADEF 0 + +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN 1 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX 255 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF 20 + +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMIN 0 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMAX 60000 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STADEF 1500 + +#define WNI_CFG_PHY_MODE_STAMIN 0 +#define WNI_CFG_PHY_MODE_STAMAX 3 +#define WNI_CFG_PHY_MODE_STADEF 0 + +#define WNI_CFG_PHY_MODE_11A 0 +#define WNI_CFG_PHY_MODE_11B 1 +#define WNI_CFG_PHY_MODE_11G 2 +#define WNI_CFG_PHY_MODE_NONE 3 + +#define WNI_CFG_DOT11_MODE_STAMIN 0 +#define WNI_CFG_DOT11_MODE_STAMAX 11 +#define WNI_CFG_DOT11_MODE_STADEF 0 + +#define WNI_CFG_DOT11_MODE_ALL 0 +#define WNI_CFG_DOT11_MODE_11A 1 +#define WNI_CFG_DOT11_MODE_11B 2 +#define WNI_CFG_DOT11_MODE_11G 3 +#define WNI_CFG_DOT11_MODE_11N 4 +#define WNI_CFG_DOT11_MODE_11G_ONLY 5 +#define WNI_CFG_DOT11_MODE_11N_ONLY 6 +#define WNI_CFG_DOT11_MODE_11AC 7 +#define WNI_CFG_DOT11_MODE_11AC_ONLY 8 + +#define WNI_CFG_LISTEN_INTERVAL_STAMIN 0 +#define WNI_CFG_LISTEN_INTERVAL_STAMAX 65535 +#define WNI_CFG_LISTEN_INTERVAL_STADEF 1 + +#define WNI_CFG_CURRENT_CHANNEL_STAMIN 0 +#define WNI_CFG_CURRENT_CHANNEL_STAMAX 165 +#define WNI_CFG_CURRENT_CHANNEL_STADEF 1 + +#define WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STAMIN 0 +#define WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STAMAX 11 +#define WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STADEF 5 + +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMIN 0 +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMAX 31 +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STADEF 1 + +#define WNI_CFG_RATE_ADAPTATION_TYPE_STAMIN 0 +#define WNI_CFG_RATE_ADAPTATION_TYPE_STAMAX 2 +#define WNI_CFG_RATE_ADAPTATION_TYPE_STADEF 1 + +#define WNI_CFG_RATE_ADAPTATION_TYPE_FIXED 0 +#define WNI_CFG_RATE_ADAPTATION_TYPE_AUTO 1 +#define WNI_CFG_RATE_ADAPTATION_TYPE_SNR_BASED 2 + +#define WNI_CFG_FIXED_RATE_STAMIN 0 +#define WNI_CFG_FIXED_RATE_STAMAX 44 +#define WNI_CFG_FIXED_RATE_STADEF 0 + +#define WNI_CFG_FIXED_RATE_AUTO 0 +#define WNI_CFG_FIXED_RATE_1MBPS 1 +#define WNI_CFG_FIXED_RATE_2MBPS 2 +#define WNI_CFG_FIXED_RATE_5_5MBPS 3 +#define WNI_CFG_FIXED_RATE_11MBPS 4 +#define WNI_CFG_FIXED_RATE_6MBPS 5 +#define WNI_CFG_FIXED_RATE_9MBPS 6 +#define WNI_CFG_FIXED_RATE_12MBPS 7 +#define WNI_CFG_FIXED_RATE_18MBPS 8 +#define WNI_CFG_FIXED_RATE_24MBPS 9 +#define WNI_CFG_FIXED_RATE_36MBPS 10 +#define WNI_CFG_FIXED_RATE_48MBPS 11 +#define WNI_CFG_FIXED_RATE_54MBPS 12 +#define WNI_CFG_FIXED_RATE_6_5MBPS_MCS0_20MHZ_SIMO 13 +#define WNI_CFG_FIXED_RATE_13MBPS_MCS1_20MHZ_SIMO 14 +#define WNI_CFG_FIXED_RATE_19_5MBPS_MCS2_20MHZ_SIMO 15 +#define WNI_CFG_FIXED_RATE_26MBPS_MCS3_20MHZ_SIMO 16 +#define WNI_CFG_FIXED_RATE_39MBPS_MCS4_20MHZ_SIMO 17 +#define WNI_CFG_FIXED_RATE_52MBPS_MCS5_20MHZ_SIMO 18 +#define WNI_CFG_FIXED_RATE_58_5MBPS_MCS6_20MHZ_SIMO 19 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS7_20MHZ_SIMO 20 +#define WNI_CFG_FIXED_RATE_7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#define WNI_CFG_FIXED_RATE_14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#define WNI_CFG_FIXED_RATE_21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#define WNI_CFG_FIXED_RATE_28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#define WNI_CFG_FIXED_RATE_43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#define WNI_CFG_FIXED_RATE_57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#define WNI_CFG_FIXED_RATE_72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 +#define WNI_CFG_FIXED_RATE_0_25MBPS_SLR_20MHZ_SIMO 29 +#define WNI_CFG_FIXED_RATE_0_5MBPS_SLR_20MHZ_SIMO 30 +#define WNI_CFG_FIXED_RATE_68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#define WNI_CFG_FIXED_RATE_54MBPS_MCS3_40MHZ_SIMO 32 +#define WNI_CFG_FIXED_RATE_81MBPS_MCS4_40MHZ_SIMO 33 +#define WNI_CFG_FIXED_RATE_108MBPS_MCS5_40MHZ_SIMO 34 +#define WNI_CFG_FIXED_RATE_121_5MBPS_MCS6_40MHZ_SIMO 35 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS7_40MHZ_SIMO 36 +#define WNI_CFG_FIXED_RATE_15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#define WNI_CFG_FIXED_RATE_30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#define WNI_CFG_FIXED_RATE_45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#define WNI_CFG_FIXED_RATE_60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#define WNI_CFG_FIXED_RATE_90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#define WNI_CFG_FIXED_RATE_120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#define WNI_CFG_FIXED_RATE_150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +#define WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STAMIN 0 +#define WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STAMAX 31 +#define WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STADEF 1 + +#define WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STAMIN 0 +#define WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STAMAX 31 +#define WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STADEF 5 + +#define WNI_CFG_RETRYRATE_POLICY_STAMIN 0 +#define WNI_CFG_RETRYRATE_POLICY_STAMAX 255 +#define WNI_CFG_RETRYRATE_POLICY_STADEF 4 + +#define WNI_CFG_RETRYRATE_POLICY_MIN_SUPPORTED 0 +#define WNI_CFG_RETRYRATE_POLICY_PRIMARY 1 +#define WNI_CFG_RETRYRATE_POLICY_RESERVED 2 +#define WNI_CFG_RETRYRATE_POLICY_CLOSEST 3 +#define WNI_CFG_RETRYRATE_POLICY_AUTOSELECT 4 +#define WNI_CFG_RETRYRATE_POLICY_MAX 5 + +#define WNI_CFG_RETRYRATE_SECONDARY_STAMIN 0 +#define WNI_CFG_RETRYRATE_SECONDARY_STAMAX 255 +#define WNI_CFG_RETRYRATE_SECONDARY_STADEF 0 + +#define WNI_CFG_RETRYRATE_TERTIARY_STAMIN 0 +#define WNI_CFG_RETRYRATE_TERTIARY_STAMAX 255 +#define WNI_CFG_RETRYRATE_TERTIARY_STADEF 0 + +#define WNI_CFG_APSD_ENABLED_STAMIN 0 +#define WNI_CFG_APSD_ENABLED_STAMAX 1 +#define WNI_CFG_APSD_ENABLED_STADEF 0 + +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_AUTHENTICATION_TYPE_STAMIN 0 +#define WNI_CFG_AUTHENTICATION_TYPE_STAMAX 65535 +#define WNI_CFG_AUTHENTICATION_TYPE_STADEF 0 + +#define WNI_CFG_PRIVACY_ENABLED_STAMIN 0 +#define WNI_CFG_PRIVACY_ENABLED_STAMAX 1 +#define WNI_CFG_PRIVACY_ENABLED_STADEF 0 + +#define WNI_CFG_SHORT_PREAMBLE_STAMIN 0 +#define WNI_CFG_SHORT_PREAMBLE_STAMAX 1 +#define WNI_CFG_SHORT_PREAMBLE_STADEF 1 + +#define WNI_CFG_SHORT_SLOT_TIME_STAMIN 0 +#define WNI_CFG_SHORT_SLOT_TIME_STAMAX 1 +#define WNI_CFG_SHORT_SLOT_TIME_STADEF 1 + +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN 0 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX 1 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF 0 + +#define WNI_CFG_QOS_ENABLED_STAMIN 0 +#define WNI_CFG_QOS_ENABLED_STAMAX 1 +#define WNI_CFG_QOS_ENABLED_STADEF 0 + +#define WNI_CFG_HCF_ENABLED_STAMIN 0 +#define WNI_CFG_HCF_ENABLED_STAMAX 1 +#define WNI_CFG_HCF_ENABLED_STADEF 0 + +#define WNI_CFG_RSN_ENABLED_STAMIN 0 +#define WNI_CFG_RSN_ENABLED_STAMAX 1 +#define WNI_CFG_RSN_ENABLED_STADEF 0 + +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMIN 0 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMAX 180000 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STADEF 5000 + +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN 0 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX 256 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STADEF 64 + +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN 0 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX 65535 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STADEF 40 + +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN 10 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX 10000 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF 40 + +#define WNI_CFG_11D_ENABLED_STAMIN 0 +#define WNI_CFG_11D_ENABLED_STAMAX 1 +#define WNI_CFG_11D_ENABLED_STADEF 1 + +#define WNI_CFG_NETWORK_DENSITY_STAMIN 0 +#define WNI_CFG_NETWORK_DENSITY_STAMAX 3 +#define WNI_CFG_NETWORK_DENSITY_STADEF 3 + +#define WNI_CFG_NETWORK_DENSITY_LOW 0 +#define WNI_CFG_NETWORK_DENSITY_MEDIUM 1 +#define WNI_CFG_NETWORK_DENSITY_HIGH 2 +#define WNI_CFG_NETWORK_DENSITY_ADAPTIVE 3 + +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STAMIN 1 +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STAMAX 2 +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STADEF 2 + +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CARRIER 1 +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CORRELATION 2 + +#define WNI_CFG_CURRENT_TX_ANTENNA_STAMIN 1 +#define WNI_CFG_CURRENT_TX_ANTENNA_STAMAX 1 +#define WNI_CFG_CURRENT_TX_ANTENNA_STADEF 1 + +#define WNI_CFG_CURRENT_RX_ANTENNA_STAMIN 1 +#define WNI_CFG_CURRENT_RX_ANTENNA_STAMAX 2 +#define WNI_CFG_CURRENT_RX_ANTENNA_STADEF 2 + +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN 0 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX 128 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF 27 + + + +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMIN 0 +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMAX 1 +#define WNI_CFG_NEW_BSS_FOUND_IND_STADEF 0 + + +#define WNI_CFG_PROPRIETARY_RATES_ENABLED_STAMIN 0 +#define WNI_CFG_PROPRIETARY_RATES_ENABLED_STAMAX 1 +#define WNI_CFG_PROPRIETARY_RATES_ENABLED_STADEF 0 + +#define WNI_CFG_11H_ENABLED_STAMIN 0 +#define WNI_CFG_11H_ENABLED_STAMAX 1 +#define WNI_CFG_11H_ENABLED_STADEF 1 + +#define WNI_CFG_WT_CNF_TIMEOUT_STAMIN 10 +#define WNI_CFG_WT_CNF_TIMEOUT_STAMAX 3000 +#define WNI_CFG_WT_CNF_TIMEOUT_STADEF 1000 + +#define WNI_CFG_PROXIMITY_STAMIN 0 +#define WNI_CFG_PROXIMITY_STAMAX 1 +#define WNI_CFG_PROXIMITY_STADEF 0 + +#define WNI_CFG_PROXIMITY_OFF 0 +#define WNI_CFG_PROXIMITY_ON 1 + +#define WNI_CFG_LOG_LEVEL_STAMIN 0 +#define WNI_CFG_LOG_LEVEL_STAMAX 7 +#define WNI_CFG_LOG_LEVEL_STADEF 4 + +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN 1000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX 30000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF 10000 + +#define WNI_CFG_PROTECTION_ENABLED_STAMIN 0 +#define WNI_CFG_PROTECTION_ENABLED_STAMAX 65535 +#define WNI_CFG_PROTECTION_ENABLED_STADEF 65535 + +#define WNI_CFG_PROTECTION_ENABLED_FROM_llA 0 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llB 1 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llG 2 +#define WNI_CFG_PROTECTION_ENABLED_HT_20 3 +#define WNI_CFG_PROTECTION_ENABLED_NON_GF 4 +#define WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP 5 +#define WNI_CFG_PROTECTION_ENABLED_RIFS 6 +#define WNI_CFG_PROTECTION_ENABLED_OBSS 7 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llA 8 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llB 9 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llG 10 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_HT20 11 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_NON_GF 12 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_LSIG_TXOP 13 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_RIFS 14 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_OBSS 15 + +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN 0 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX 1 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STADEF 0 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX 5 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STADEF 5 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_CTS 1 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS 2 +#define WNI_CFG_FORCE_POLICY_PROTECTION_DUAL_CTS 3 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS_ALWAYS 4 +#define WNI_CFG_FORCE_POLICY_PROTECTION_AUTO 5 + +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF 0 + +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF 1 + +#define WNI_CFG_11G_ONLY_POLICY_STAMIN 0 +#define WNI_CFG_11G_ONLY_POLICY_STAMAX 1 +#define WNI_CFG_11G_ONLY_POLICY_STADEF 0 + +#define WNI_CFG_PACKET_CLASSIFICATION_STAMIN 0 +#define WNI_CFG_PACKET_CLASSIFICATION_STAMAX 3 +#define WNI_CFG_PACKET_CLASSIFICATION_STADEF 0 + +#define WNI_CFG_PACKET_CLASSIFICATION_DISABLED 0 +#define WNI_CFG_PACKET_CLASSIFICATION_DSCP 1 +#define WNI_CFG_PACKET_CLASSIFICATION_8021P 2 +#define WNI_CFG_PACKET_CLASSIFICATION_ALL 3 + +#define WNI_CFG_WME_ENABLED_STAMIN 0 +#define WNI_CFG_WME_ENABLED_STAMAX 1 +#define WNI_CFG_WME_ENABLED_STADEF 1 + +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_MAX_SP_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_SP_LENGTH_STAMAX 3 +#define WNI_CFG_MAX_SP_LENGTH_STADEF 0 + +#define WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STAMIN 0 +#define WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STAMAX 1 +#define WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STADEF 0 + +#define WNI_CFG_WSM_ENABLED_STAMIN 0 +#define WNI_CFG_WSM_ENABLED_STAMAX 1 +#define WNI_CFG_WSM_ENABLED_STADEF 0 + +#define WNI_CFG_EDCA_PROFILE_STAMIN 0 +#define WNI_CFG_EDCA_PROFILE_STAMAX 255 +#define WNI_CFG_EDCA_PROFILE_STADEF 1 + +#define WNI_CFG_EDCA_PROFILE_ANI 0 +#define WNI_CFG_EDCA_PROFILE_WMM 1 +#define WNI_CFG_EDCA_PROFILE_TIT_DEMO 2 +#define WNI_CFG_EDCA_PROFILE_MAX 3 +#define WNI_CFG_EDCA_PROFILE_ACM_IDX 0 +#define WNI_CFG_EDCA_PROFILE_AIFSN_IDX 1 +#define WNI_CFG_EDCA_PROFILE_CWMINA_IDX 2 +#define WNI_CFG_EDCA_PROFILE_CWMAXA_IDX 4 +#define WNI_CFG_EDCA_PROFILE_TXOPA_IDX 6 +#define WNI_CFG_EDCA_PROFILE_CWMINB_IDX 7 +#define WNI_CFG_EDCA_PROFILE_CWMAXB_IDX 9 +#define WNI_CFG_EDCA_PROFILE_TXOPB_IDX 11 +#define WNI_CFG_EDCA_PROFILE_CWMING_IDX 12 +#define WNI_CFG_EDCA_PROFILE_CWMAXG_IDX 14 +#define WNI_CFG_EDCA_PROFILE_TXOPG_IDX 16 + +#define WNI_CFG_RDET_FLAG_STAMIN 0 +#define WNI_CFG_RDET_FLAG_STAMAX 1 +#define WNI_CFG_RDET_FLAG_STADEF 0 + +#define WNI_CFG_RDET_FLAG_ENABLE 1 +#define WNI_CFG_RDET_FLAG_DISABLE 0 + +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN 0 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX 255 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF 0 + +#define WNI_CFG_ADMIT_POLICY_STAMIN 0 +#define WNI_CFG_ADMIT_POLICY_STAMAX 2 +#define WNI_CFG_ADMIT_POLICY_STADEF 0 + +#define WNI_CFG_ADMIT_POLICY_ADMIT_ALL 0 +#define WNI_CFG_ADMIT_POLICY_REJECT_ALL 1 +#define WNI_CFG_ADMIT_POLICY_BW_FACTOR 2 + +#define WNI_CFG_ADMIT_BWFACTOR_STAMIN 0 +#define WNI_CFG_ADMIT_BWFACTOR_STAMAX 100 +#define WNI_CFG_ADMIT_BWFACTOR_STADEF 20 + +#define WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STAMIN 0 +#define WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STAMAX 256 +#define WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STADEF 60 + +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMIN 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMAX 10 +#define WNI_CFG_CHANNEL_BONDING_MODE_STADEF 0 + +#define WNI_CFG_CHANNEL_BONDING_MODE_DISABLE 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_ENABLE 1 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_BSS 2 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_ALL 3 +#define WNI_CFG_CHANNEL_BONDING_MODE_INTELLIGENT 4 + +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STAMIN 0 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STAMAX 10 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STADEF 0 + +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_NONE 0 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_LOWER 1 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_HIGHER 2 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_LOW_40MHZ_CENTERED 3 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_CENTERED_40MHZ_CENTERED 4 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_HIGH_40MHZ_CENTERED 5 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_LOW_40MHZ_LOW 6 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_HIGH_40MHZ_LOW 7 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_LOW_40MHZ_HIGH 8 +#define WNI_CFG_CB_SECONDARY_CHANNEL_STATE_11AC_20MHZ_HIGH_40MHZ_HIGH 9 + +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STADEF 2 + +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STADEF 4 + +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STADEF 6 + +#define WNI_CFG_TRIG_STA_BK_SCAN_STAMIN 0 +#define WNI_CFG_TRIG_STA_BK_SCAN_STAMAX 1 +#define WNI_CFG_TRIG_STA_BK_SCAN_STADEF 0 + +#define WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STAMIN 0 +#define WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STAMAX 255 +#define WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STADEF 255 + +#define WNI_CFG_DYNAMIC_PROFILE_SWITCHING_UNUSED 255 + +#define WNI_CFG_MIMO_ENABLED_STAMIN 0 +#define WNI_CFG_MIMO_ENABLED_STAMAX 1 +#define WNI_CFG_MIMO_ENABLED_STADEF 1 + +#define WNI_CFG_MIMO_ENABLED_ENABLE 1 +#define WNI_CFG_MIMO_ENABLED_DISABLE 0 + +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMIN 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMAX 3 +#define WNI_CFG_BLOCK_ACK_ENABLED_STADEF 0 + +#define WNI_CFG_BLOCK_ACK_ENABLED_DELAYED 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE 1 + +#define WNI_CFG_HT_RX_STBC_STAMIN 0 +#define WNI_CFG_HT_RX_STBC_STAMAX 3 +#define WNI_CFG_HT_RX_STBC_STADEF 1 + +#define WNI_CFG_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_HT_CAP_INFO_STADEF 364 + +#define WNI_CFG_HT_CAP_INFO_ADVANCE_CODING 0 +#define WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET 1 +#define WNI_CFG_HT_CAP_INFO_SM_POWER_SAVE 2 +#define WNI_CFG_HT_CAP_INFO_GREEN_FIELD 4 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ 5 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ 6 +#define WNI_CFG_HT_CAP_INFO_TX_STBC 7 +#define WNI_CFG_HT_CAP_INFO_RX_STBC 8 +#define WNI_CFG_HT_CAP_INFO_DELAYED_BA 10 +#define WNI_CFG_HT_CAP_INFO_MAX_AMSDU_SIZE 11 +#define WNI_CFG_HT_CAP_INFO_DSSS_CCK_MODE_40MHZ 12 +#define WNI_CFG_HT_CAP_INFO_PSMP 13 +#define WNI_CFG_HT_CAP_INFO_STBC_CONTROL_FRAME 14 +#define WNI_CFG_HT_CAP_INFO_LSIG_TXOP_PROTECTION 15 + +#define WNI_CFG_HT_AMPDU_PARAMS_STAMIN 0 +#define WNI_CFG_HT_AMPDU_PARAMS_STAMAX 255 +#define WNI_CFG_HT_AMPDU_PARAMS_STADEF 0 + +#define WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR 0 +#define WNI_CFG_HT_AMPDU_PARAMS_MPDU_DENSITY 2 +#define WNI_CFG_HT_AMPDU_PARAMS_RESERVED 5 + +#define WNI_CFG_EXT_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_EXT_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_EXT_HT_CAP_INFO_STADEF 1024 + +#define WNI_CFG_EXT_HT_CAP_INFO_PCO 0 +#define WNI_CFG_EXT_HT_CAP_INFO_TRANSITION_TIME 1 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED1 3 +#define WNI_CFG_EXT_HT_CAP_INFO_MCS_FEEDBACK 8 +#define WNI_CFG_EXT_HT_CAP_INFO_HTC_SUPPORT 10 +#define WNI_CFG_EXT_HT_CAP_INFO_RD_RESPONDER 11 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED2 12 + +#define WNI_CFG_TX_BF_CAP_STAMIN 0 +#define WNI_CFG_TX_BF_CAP_STAMAX 4294967295 +#define WNI_CFG_TX_BF_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_STAMIN 0 +#define WNI_CFG_AS_CAP_STAMAX 255 +#define WNI_CFG_AS_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_ANTENNA_SELECTION 0 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK_TX 1 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK_TX 2 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK 3 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK 4 +#define WNI_CFG_AS_CAP_RX_AS 5 +#define WNI_CFG_AS_CAP_TX_SOUNDING_PPDUS 6 +#define WNI_CFG_AS_CAP_RESERVED 7 + +#define WNI_CFG_HT_INFO_FIELD1_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD1_STAMAX 255 +#define WNI_CFG_HT_INFO_FIELD1_STADEF 15 + +#define WNI_CFG_HT_INFO_FIELD1_SECONDARY_CHANNEL_OFFSET 0 +#define WNI_CFG_HT_INFO_FIELD1_RECOMMENDED_CHANNEL_WIDTH 2 +#define WNI_CFG_HT_INFO_FIELD1_RIFS_MODE 3 +#define WNI_CFG_HT_INFO_FIELD1_PSMP_ACCESS_ONLY 4 +#define WNI_CFG_HT_INFO_FIELD1_SERVICE_INTERVAL_GRANULARITY 5 + +#define WNI_CFG_HT_INFO_FIELD2_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD2_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD2_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD2_OP_MODE 0 +#define WNI_CFG_HT_INFO_FIELD2_NON_GF_DEVICES_PRESENT 2 +#define WNI_CFG_HT_INFO_FIELD2_RESERVED 3 + +#define WNI_CFG_HT_INFO_FIELD3_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD3_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD3_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD3_BASIC_STBC_MCS 0 +#define WNI_CFG_HT_INFO_FIELD3_DUAL_STBC_PROTECTION 7 +#define WNI_CFG_HT_INFO_FIELD3_SECONDARY_BEACON 8 +#define WNI_CFG_HT_INFO_FIELD3_LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#define WNI_CFG_HT_INFO_FIELD3_PCO_ACTIVE 10 +#define WNI_CFG_HT_INFO_FIELD3_PCO_PHASE 11 +#define WNI_CFG_HT_INFO_FIELD3_RESERVED 12 + +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMIN 0 +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMAX 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_STADEF 0 + +#define WNI_CFG_GREENFIELD_CAPABILITY_ENABLE 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_DISABLE 0 + +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN 0 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX 2 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF 0 + +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN 0 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX 2 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF 2 + +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN 0 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX 1 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STADEF 0 + +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF 1 + +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF 1 + +#define WNI_CFG_VHT_TXSTBC_STAMIN 0 +#define WNI_CFG_VHT_TXSTBC_STAMAX 1 +#define WNI_CFG_VHT_TXSTBC_STADEF 0 + +#define WNI_CFG_VHT_RXSTBC_STAMIN 0 +#define WNI_CFG_VHT_RXSTBC_STAMAX 1 +#define WNI_CFG_VHT_RXSTBC_STADEF 1 + +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF 0 + +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN 0 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX 4 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF 0 + +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN 0 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX 3 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF 0 + +#define WNI_CFG_VHT_TXOP_PS_STAMIN 0 +#define WNI_CFG_VHT_TXOP_PS_STAMAX 1 +#define WNI_CFG_VHT_TXOP_PS_STADEF 0 + +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN 0 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX 1 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STADEF 0 + +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN 0 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX 7 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF 3 + +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN 0 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX 3 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF 0 + +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_RX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_RX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_RX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_TX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_TX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_TX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STAMIN 0 +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STAMAX 256 +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STADEF 0 + +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STAMIN 0 +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STAMAX 0 +#define WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STADEF 0 + +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMIN 0 +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMAX 65535 +#define WNI_CFG_VHT_BASIC_MCS_SET_STADEF 65534 + +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN 0 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX 4 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF 0 + +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STADEF 0 + +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMAX 1 +#define WNI_CFG_MAX_AMSDU_LENGTH_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_SHORT_3839_BYTES 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_LONG_7935__BYTES 1 + +#define WNI_CFG_MPDU_DENSITY_STAMIN 0 +#define WNI_CFG_MPDU_DENSITY_STAMAX 7 +#define WNI_CFG_MPDU_DENSITY_STADEF 0 + +#define WNI_CFG_NUM_BUFF_ADVERT_STAMIN 0 +#define WNI_CFG_NUM_BUFF_ADVERT_STAMAX 128 +#define WNI_CFG_NUM_BUFF_ADVERT_STADEF 64 + +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN 0 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX 3 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF 3 + +#define WNI_CFG_SHORT_GI_20MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_20MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_20MHZ_STADEF 1 + +#define WNI_CFG_SHORT_GI_20MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_20MHZ_DISABLE 0 + +#define WNI_CFG_SHORT_GI_40MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_40MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_40MHZ_STADEF 0 + +#define WNI_CFG_SHORT_GI_40MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_40MHZ_DISABLE 0 + +#define WNI_CFG_RIFS_ENABLED_STAMIN 0 +#define WNI_CFG_RIFS_ENABLED_STAMAX 1 +#define WNI_CFG_RIFS_ENABLED_STADEF 1 + +#define WNI_CFG_RIFS_ENABLED_ENABLE 1 +#define WNI_CFG_RIFS_ENABLED_DISABLE 0 + +#define WNI_CFG_MAX_PS_POLL_STAMIN 0 +#define WNI_CFG_MAX_PS_POLL_STAMAX 255 +#define WNI_CFG_MAX_PS_POLL_STADEF 0 + +#define WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMIN 1 +#define WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMAX 20 +#define WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STADEF 20 + +#define WNI_CFG_RSSI_FILTER_PERIOD_STAMIN 0 +#define WNI_CFG_RSSI_FILTER_PERIOD_STAMAX 255 +#define WNI_CFG_RSSI_FILTER_PERIOD_STADEF 5 + +#define WNI_CFG_MIN_RSSI_THRESHOLD_STAMIN 0 +#define WNI_CFG_MIN_RSSI_THRESHOLD_STAMAX 10 +#define WNI_CFG_MIN_RSSI_THRESHOLD_STADEF 10 + +#define WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STAMIN 0 +#define WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STAMAX 1 +#define WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STADEF 0 + +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMIN 0 +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMAX 1 +#define WNI_CFG_SCAN_IN_POWERSAVE_STADEF 1 + +#define WNI_CFG_IGNORE_DTIM_STAMIN 0 +#define WNI_CFG_IGNORE_DTIM_STAMAX 1 +#define WNI_CFG_IGNORE_DTIM_STADEF 0 + +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF 40 + +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF 65535 + +#define WNI_CFG_MAX_MEDIUM_TIME_STAMIN 0 +#define WNI_CFG_MAX_MEDIUM_TIME_STAMAX 65535 +#define WNI_CFG_MAX_MEDIUM_TIME_STADEF 2048 + +#define WNI_CFG_MAX_MPDUS_IN_AMPDU_STAMIN 0 +#define WNI_CFG_MAX_MPDUS_IN_AMPDU_STAMAX 65535 +#define WNI_CFG_MAX_MPDUS_IN_AMPDU_STADEF 64 + +#define WNI_CFG_IBSS_AUTO_BSSID_STAMIN 0 +#define WNI_CFG_IBSS_AUTO_BSSID_STAMAX 1 +#define WNI_CFG_IBSS_AUTO_BSSID_STADEF 1 + +#define WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STAMIN 0 +#define WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STAMAX 1 +#define WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STADEF 0 + +#define WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STAMIN 0 +#define WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STAMAX 1 +#define WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STADEF 0 + +#define WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STAMIN 0 +#define WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STAMAX 1 +#define WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STADEF 0 + +#define WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STAMIN 0 +#define WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STAMAX 1 +#define WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STADEF 0 + +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMIN 0 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMAX 1 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STADEF 0 + +#define WNI_CFG_WPS_ENABLE_STAMIN 0 +#define WNI_CFG_WPS_ENABLE_STAMAX 255 +#define WNI_CFG_WPS_ENABLE_STADEF 0 + +#define WNI_CFG_WPS_ENABLE_AP 1 +#define WNI_CFG_WPS_ENABLE_STA 2 + +#define WNI_CFG_WPS_STATE_STAMIN 0 +#define WNI_CFG_WPS_STATE_STAMAX 255 +#define WNI_CFG_WPS_STATE_STADEF 1 + +#define WNI_CFG_WPS_PROBE_REQ_FLAG_STAMIN 0 +#define WNI_CFG_WPS_PROBE_REQ_FLAG_STAMAX 1 +#define WNI_CFG_WPS_PROBE_REQ_FLAG_STADEF 0 + +#define WNI_CFG_WPS_VERSION_STAMIN 0 +#define WNI_CFG_WPS_VERSION_STAMAX 255 +#define WNI_CFG_WPS_VERSION_STADEF 16 + +#define WNI_CFG_WPS_REQUEST_TYPE_STAMIN 0 +#define WNI_CFG_WPS_REQUEST_TYPE_STAMAX 255 +#define WNI_CFG_WPS_REQUEST_TYPE_STADEF 0 + +#define WNI_CFG_WPS_CFG_METHOD_STAMIN 0 +#define WNI_CFG_WPS_CFG_METHOD_STAMAX 4294967295 +#define WNI_CFG_WPS_CFG_METHOD_STADEF 8 + +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN 0 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMAX 4294967295 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF 5304836 + +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_ASSOCIATION_STATE_STAMIN 0 +#define WNI_CFG_WPS_ASSOCIATION_STATE_STAMAX 65535 +#define WNI_CFG_WPS_ASSOCIATION_STATE_STADEF 0 + +#define WNI_CFG_WPS_CONFIGURATION_ERROR_STAMIN 0 +#define WNI_CFG_WPS_CONFIGURATION_ERROR_STAMAX 65535 +#define WNI_CFG_WPS_CONFIGURATION_ERROR_STADEF 0 + +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMAX 4294967295 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF 0 + +#define WNI_CFG_WPS_ASSOC_METHOD_STAMIN 0 +#define WNI_CFG_WPS_ASSOC_METHOD_STAMAX 65535 +#define WNI_CFG_WPS_ASSOC_METHOD_STADEF 0 + +#define WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN 0 +#define WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX 1 +#define WNI_CFG_LOW_GAIN_OVERRIDE_STADEF 0 + +#define WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STAMIN 0 +#define WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STAMAX 128 +#define WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STADEF 128 + +#define WNI_CFG_RPE_POLLING_THRESHOLD_STAMIN 0 +#define WNI_CFG_RPE_POLLING_THRESHOLD_STAMAX 65535 +#define WNI_CFG_RPE_POLLING_THRESHOLD_STADEF 10 + +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STAMIN 0 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STAMAX 65535 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STADEF 30 + +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STAMIN 0 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STAMAX 65535 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STADEF 30 + +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STAMIN 0 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STAMAX 65535 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STADEF 30 + +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STAMIN 0 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STAMAX 65535 +#define WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STADEF 30 + +#define WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STAMIN 0 +#define WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STAMAX 2 +#define WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STADEF 1 + +#define WNI_CFG_SINGLE_TID_RC_STAMIN 0 +#define WNI_CFG_SINGLE_TID_RC_STAMAX 1 +#define WNI_CFG_SINGLE_TID_RC_STADEF 1 + +#define WNI_CFG_RRM_ENABLED_STAMIN 0 +#define WNI_CFG_RRM_ENABLED_STAMAX 1 +#define WNI_CFG_RRM_ENABLED_STADEF 0 + +#define WNI_CFG_RRM_OPERATING_CHAN_MAX_STAMIN 0 +#define WNI_CFG_RRM_OPERATING_CHAN_MAX_STAMAX 8 +#define WNI_CFG_RRM_OPERATING_CHAN_MAX_STADEF 0 + +#define WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STAMIN 0 +#define WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STAMAX 8 +#define WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STADEF 0 + +#define WNI_CFG_TX_PWR_CTRL_ENABLE_STAMIN 0 +#define WNI_CFG_TX_PWR_CTRL_ENABLE_STAMAX 1 +#define WNI_CFG_TX_PWR_CTRL_ENABLE_STADEF 1 + +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMIN 0 +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMAX 3 +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STADEF 0 + +#define WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STAMIN 0 +#define WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STAMAX 255 +#define WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STADEF 0 + +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMIN 0 +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMAX 255 +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STADEF 0 + +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN 0 +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX 80 +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF 0 + +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN 0 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX 1 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF 0 + +#define WNI_CFG_TELE_BCN_TRANS_LI_STAMIN 0 +#define WNI_CFG_TELE_BCN_TRANS_LI_STAMAX 7 +#define WNI_CFG_TELE_BCN_TRANS_LI_STADEF 3 + +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMIN 5 +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMAX 255 +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STADEF 10 + +#define WNI_CFG_TELE_BCN_MAX_LI_STAMIN 0 +#define WNI_CFG_TELE_BCN_MAX_LI_STAMAX 7 +#define WNI_CFG_TELE_BCN_MAX_LI_STADEF 5 + +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMIN 5 +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMAX 255 +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STADEF 15 + +#define WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STAMIN 0 +#define WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STAMAX 255 +#define WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STADEF 7 + +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN 0 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX 1000 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF 0 + +#define WNI_CFG_ASSOC_STA_LIMIT_STAMIN 1 +#define WNI_CFG_ASSOC_STA_LIMIT_STAMAX 32 +#define WNI_CFG_ASSOC_STA_LIMIT_STADEF 10 + +#define WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STAMIN 1 +#define WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STAMAX 252 +#define WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STADEF 1 + +#define WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STAMIN 1 +#define WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STAMAX 252 +#define WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STADEF 11 + +#define WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STAMIN 0 +#define WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STAMAX 5 +#define WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STADEF 0 + +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN 0 +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX 65535 +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF 5 + +#define WNI_CFG_ENABLE_CLOSE_LOOP_STAMIN 0 +#define WNI_CFG_ENABLE_CLOSE_LOOP_STAMAX 1 +#define WNI_CFG_ENABLE_CLOSE_LOOP_STADEF 0 + +#define WNI_CFG_ENABLE_LTE_COEX_STAMIN 0 +#define WNI_CFG_ENABLE_LTE_COEX_STAMAX 1 +#define WNI_CFG_ENABLE_LTE_COEX_STADEF 0 + +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN 0 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX 1 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF 0 + +#define WNI_CFG_ENABLE_UC_FILTER_STAMIN 0 +#define WNI_CFG_ENABLE_UC_FILTER_STAMAX 1 +#define WNI_CFG_ENABLE_UC_FILTER_STADEF 0 + +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN 0 +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX 1 +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF 0 + +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN 0 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX 1 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF 0 + +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN 0 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX 1 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF 0 + +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX 255 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF 3 + +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN 0 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX 15 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF 0 + +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF 0 + +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN 0 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX 10 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF 0 + +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN 10 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX 20 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF 10 + +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN 0 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX 20 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF 5 + +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN 10 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX 2000 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF 200 + +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN 0 +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX 1 +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF 1 + +#define WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STAMIN 0 +#define WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STAMAX 9 +#define WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STADEF 0 + +#define WNI_CFG_ANTENNA_DIVESITY_STAMIN 0 +#define WNI_CFG_ANTENNA_DIVESITY_STAMAX 3 +#define WNI_CFG_ANTENNA_DIVESITY_STADEF 0 + +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN 3 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX 50 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF 10 + +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN 100 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX 1000 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF 300 + +#define WNI_CFG_CURRENT_RSSI_STAMIN 0 +#define WNI_CFG_CURRENT_RSSI_STAMAX 127 +#define WNI_CFG_CURRENT_RSSI_STADEF 0 + +#define WNI_CFG_RTT3_ENABLE_STAMIN 0 +#define WNI_CFG_RTT3_ENABLE_STAMAX 1 +#define WNI_CFG_RTT3_ENABLE_STADEF 1 + +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN 0 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX 1 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF 0 + +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF 0 + +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN 0 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX 100 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF 0 + +#define WNI_CFG_DFS_MASTER_ENABLED_STAMIN 0 +#define WNI_CFG_DFS_MASTER_ENABLED_STAMAX 1 +#define WNI_CFG_DFS_MASTER_ENABLED_STADEF 0 + +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN 0 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX 1 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF 0 + +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF 0 + +#define CFG_PARAM_MAX_NUM 289 +#define CFG_STA_IBUF_MAX_SIZE 237 +#define CFG_STA_SBUF_MAX_SIZE 3199 + +#define CFG_STA_MAGIC_DWORD 0xbeefbeef + +#endif diff --git a/core/mac/src/cfg/cfgUtil/cfg.txt b/core/mac/src/cfg/cfgUtil/cfg.txt new file mode 100644 index 0000000000..85071b9687 --- /dev/null +++ b/core/mac/src/cfg/cfgUtil/cfg.txt @@ -0,0 +1,4474 @@ +* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. +* +* Previously licensed under the ISC license by Qualcomm Atheros, Inc. +* +* +* 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. + +* This file was originally distributed by Qualcomm Atheros, Inc. +* under proprietary terms before Copyright ownership was assigned +* to the Linux Foundation. + +* +* This is the data definition file for the CFG module. +* Author: Kevin Nguyen +* Date: 03/18/02 +* History:- +* 03/18/02 Created. +* 08/10/05 ww: add maoe channels to have a complete channel listing: (see WNI_CFG_VALID_CHANNEL_LIST) +* 08/10/05 ww: WNI_CFG_SCAN_CONTROL_LIST has a new contents +* -------------------------------------------------------------------- + +********************************************************************** +* +* This file contains the descriptions of all configuration parameters +* for both STA and AP. +* +* OUTPUT: +* ------- +* The output files are: +* wniCfgSta.h - C header file for STA mode only +* wniCfgAp.h - C header file for both STA and AP +* wniCfgSta.bin - Control and default values for STA system +* wniCfgAp.bin - Control and default values for AP system +* +* PARAMETER DESCRIPTION: +* ---------------------- +* For each parameter, the description must be on separate lines and +* exactly as specified below. [] are comments and should not be included. +* +* [Common info] parameter_name type maxLen semIndx +* [STA flags] valid RW P/NP RESTART/RELOAD +* [STA_NTF] notification_mask +* [STA values] min max value [for integer] +* length byte1 byte2 ... [for string] +* [AP flags] valid RW/RO/WO P/NP RESTART/RELOAD +* [AP_NTF] notification_mask +* [AP values] min max value [for integer] +* length byte1 byte2 ... [for string] +* +* parameter_name: +* This will be used as the base name for C macro definition. +* Therefore, C syntax rule must be observed. +* +* type: +* Specifies parameter type +* S - variable-length string +* I - integer +* +* maxLen: +* Specifies maximum parameter length in bytes. +* +* semIndx: +* Specifies semaphore index to use for locking this parameter. +* More than one parameters (those belonging to the same group) +* can share the same semaphore index. +* +* valid: +* Specifies if this parameter will be valid in current mode. +* V - Valid +* NV - Not valid +* +* RW: +* Specifies Read/Write mode. +* RO - Read only +* RW - Read/Write +* WO - Write only +* XX - Not accessible from host +* +* P: +* Specifies persistent memory option +* P - Save to persistent memory +* NP - No save +* +* RELOAD: +* Specifies whether setting this requires reloading the MAC module +* This attribute can be changed only when SME is in OFFLINE or SUSPEND(OFFLINE) state +* +* RESTART: +* Specifies whether setting this requires (re)assoc at STA and restart at AP +* This attribute can be changed only when SME is in OFFLINE, SUSPEND(OFFLINE), +* IDLE or SUSPEND(IDLE) states +* +* STA_notification: +* Lists modules to be notified in STA mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* AP_notification: +* Lists module to be notified in AP mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* STA/AP integer values: +* min: +* Specifies minimum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* max: +* Specifies maximum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* default: +* Specifies default value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* STA/AP string values: +* len: +* The actual length of the string +* +* bytei: +* byte i of the string where i varies from 1 to len +* +* TABLE GENERATION: +* ----------------- +* Table can be generated using keywords '#TABLE' and '#END' as below: +* +* #TABLE table_name number_of_row +* WNI_CFG_xxxx +* ....... +* ....... +* #END +* +* The CFG utility will generate the following output: +* WNI_CFG_table_xxx_ID xxx +* WNI_CFG_table_xxx_ROW number_of_rows +* WNI_CFG_table_xxx_COL number_of_columns +* +* These will be followed by the parameter definition for each entry in +* the table. Table is organized in column-major order. +* +* #ENTRY_VALUES 1 +* 0 4 1 +* 0 0 0 +* #ENTRY_VALUES 2 +* 0 4 2 +* 0 0 0 +* #ENTRY_VALUES 3 +* 0 4 3 +* 0 0 0 +* #ENTRY_VALUES 4 +* 0 4 4 +* 0 0 0 +* +* +* ENUMERATION +* ----------- +* Enumerations can be define using keyword '#ENUM' +* +* #ENUM xxx val +* +* The cfg utility will generate the following output in the header file +* #define paramname_xxx val +* + + +* +* Station ID (changing requires restart) +* + +WNI_CFG_STA_ID S 6 1 +V RW NP RELOAD +HAL +6 0x22 0x22 0x44 0x44 0x33 0x33 +V RW NP RELOAD +HAL +6 0x22 0x22 0x11 0x11 0x33 0x33 + +* +* CF Pollable +* + +WNI_CFG_CF_POLLABLE I 4 1 +NV RO NP RESTART +NONE +0 0 0 +V RO NP RESTART +NONE +0 1 0 + +* +* CFP Period +* + +WNI_CFG_CFP_PERIOD I 4 1 +V RO NP +NONE +0 255 1 +V RW NP +SCH +0 255 1 + +* +* CFP Max Duration +* + +WNI_CFG_CFP_MAX_DURATION I 4 1 +V RO NP +NONE +0 65535 30000 +V RW NP +HAL +0 65535 30000 + +* +* SSID (changing requires restart) +* + +WNI_CFG_SSID S 32 1 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 + +* +* Beacon Period +* Can't be changed on STA in infrastructure, ignore notification at SCH +* + +WNI_CFG_BEACON_INTERVAL I 4 2 +V RW NP +SCH +0 65535 100 +V RW NP +SCH +0 65535 100 + +* +* DTIM Period +* + +WNI_CFG_DTIM_PERIOD I 4 2 +V RO NP +NONE +0 65535 1 +V RW NP +SCH +0 65535 1 + + +* +* WEP Key Length (5 or 13 bytes) +* + +WNI_CFG_WEP_KEY_LENGTH I 4 5 +V RW NP RESTART +NONE +5 13 5 +V RW NP RESTART +NONE +5 13 5 + +#ENUM 5 5 +#ENUM 13 13 + +* +* Default Key Table +* + +#TABLE WNI_CFG_WEP_DEFAULT_KEY_TABLE 4 + +WNI_CFG_WEP_DEFAULT_KEY S 13 4 +V WO NP RESTART +NONE +0 +V WO NP RESTART +NONE +0 + +#END + +* +* WEP Default Key id +* + +WNI_CFG_WEP_DEFAULT_KEYID I 4 5 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +#ENUM 0 0 +#ENUM 1 1 +#ENUM 2 2 +#ENUM 3 3 + +* +* Exclude unencrypted frames (WEP) +* + +WNI_CFG_EXCLUDE_UNENCRYPTED I 4 5 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* RTS Threshold +* + +WNI_CFG_RTS_THRESHOLD I 4 6 +V RW NP +HAL +0 1048576 2347 +V RW NP +HAL +0 1048576 2347 + +* +* Short Retry Limit +* + +WNI_CFG_SHORT_RETRY_LIMIT I 4 6 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + +* +* Long Retry Limit +* + +WNI_CFG_LONG_RETRY_LIMIT I 4 6 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + + +* +* Fragmentation Threshold +* + +WNI_CFG_FRAGMENTATION_THRESHOLD I 4 6 +V RW NP +HAL +256 8000 8000 +V RW NP +HAL +256 8000 8000 + + +* +* Minimum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 20 +V RW NP +NONE +0 65535 20 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 40 +V RW NP +NONE +0 65535 40 +* +* Minimum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 60 +V RW NP +NONE +0 65535 60 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 110 +V RW NP +NONE +0 65535 110 + +* +* Join Failure Timeout (TU) +* + +WNI_CFG_JOIN_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 3000 +V RW NP +NONE +0 65535 3000 + +* +* Authenticate Failure Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Authenticate Response Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_RSP_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Assocation Failure Timeout (TU) +* + +WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT I 4 8 +V RW NP +LIM +0 65535 2000 +V RW NP +LIM +0 65535 3000 + +* +* Reassociation Failure Timeout (TU) +* + +WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 3000 + + +* +* RA periodicity Timeout (TU) +* + +WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS I 4 7 +V RW NP +HAL +0 65535 1000 +NV RW NP +NONE +0 0 0 + +* +* Beacon Filter Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_BCN_FILTER I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* Heart Beat Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_HEART_BEAT I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* RSSI Monitor Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_RSSI_MONITOR I 4 7 +V RW NP +HAL +0 1 0 +NV RW NP +NONE +0 1 0 + + +* +* PS Data InActivity Timeout (TU) +* + +WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT I 4 7 +V RW NP +HAL +1 255 20 +NV RW NP +NONE +1 255 20 + + +* +* RF Settling Time Clk (In US) +* + +WNI_CFG_RF_SETTLING_TIME_CLK I 4 7 +V RW NP +HAL +0 60000 1500 +NV RW NP +NONE +0 60000 1500 + +* +* Supported Rate Set for 11b +* + +WNI_CFG_SUPPORTED_RATES_11B S 4 2 +V RO NP +NONE +4 2 4 11 22 +V RO NP +NONE +4 2 4 11 22 + +* +* Supported Rate Set for 11a +* + +WNI_CFG_SUPPORTED_RATES_11A S 8 7 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 + + +* +* PHY Mode +* + +WNI_CFG_PHY_MODE I 4 9 +V RW NP RESTART +NONE +0 3 0 +V RW NP RESTART +NONE +0 3 0 + +#ENUM 11A 0 +#ENUM 11B 1 +#ENUM 11G 2 +#ENUM NONE 3 + + +* +*The Dot11 mode can change dynamically on STA +* +WNI_CFG_DOT11_MODE I 4 9 +V RW NP RESTART +LIM +0 11 0 +V RW NP RESTART +LIM +0 11 0 + +#ENUM ALL 0 +#ENUM 11A 1 +#ENUM 11B 2 +#ENUM 11G 3 +#ENUM 11N 4 +#ENUM 11G_ONLY 5 +#ENUM 11N_ONLY 6 +#ENUM 11AC 7 +#ENUM 11AC_ONLY 8 + + + + + + +* +* Operational Rate Set (goes in beacon, probe rsp and assoc req) +* + +WNI_CFG_OPERATIONAL_RATE_SET S 12 2 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +4 0x82 0x84 11 22 +* 8 0x8c 18 24 36 48 72 96 108 + +* +* Extended Operational Rate Set (goes in beacon, assoc req) +* required for 11g +* + +WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET S 8 7 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +0 + +* +* Proprietary Operational Rate Set +* + +WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET S 4 7 +V RW NP RESTART +NONE +4 1 3 5 7 +V RW NP RESTART +NONE +4 1 3 5 7 + +* +* BSSID +* In IBSS, this can be changed for coalescing, should SME go into IDLE state? +* + +* +* Listen Interval +* + +WNI_CFG_LISTEN_INTERVAL I 4 7 +V RW NP RESTART +NONE +0 65535 1 +V RO NP +NONE +0 65535 1 + +* +* Valid Channel List +* + +WNI_CFG_VALID_CHANNEL_LIST S 100 8 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + +* +* Current Channel +* + +WNI_CFG_CURRENT_CHANNEL I 4 9 +V RO NP +NONE +0 165 1 +V RO NP +NONE +0 165 1 + + +* +* For 11a or pure 11g, use 6Mbps(rateindex 11) +* as the default beaconRateIndex and +* nonBeaconRateIndex. +* +WNI_CFG_DEFAULT_RATE_INDEX_5GHZ I 4 9 +V RW NP +NONE +0 11 5 +V RW NP +NONE +0 11 5 + +* +* For 11b/g, use 1Mbps +* as the default beaconRateIndex and +* nonBeaconRateIndex. +* +WNI_CFG_DEFAULT_RATE_INDEX_24GHZ I 4 9 +V RW NP +NONE +0 31 1 +V RW NP +NONE +0 31 1 + + +* ********************************************************* +* +* Rate adaptation type +* + +WNI_CFG_RATE_ADAPTATION_TYPE I 4 0 +V RW NP +SCH +0 2 1 +V RW NP +SCH +0 2 1 + +#ENUM FIXED 0 +#ENUM AUTO 1 +#ENUM SNR_BASED 2 + +* +* Rate adaptation fixed rate +* Used to determine the rate for all peer stations +* +* + +WNI_CFG_FIXED_RATE I 4 0 +V RW NP +HAL +0 44 0 +V RW NP +HAL +0 44 0 + +#ENUM AUTO 0 + +#ENUM 1MBPS 1 +#ENUM 2MBPS 2 +#ENUM 5_5MBPS 3 +#ENUM 11MBPS 4 + +#ENUM 6MBPS 5 +#ENUM 9MBPS 6 +#ENUM 12MBPS 7 +#ENUM 18MBPS 8 +#ENUM 24MBPS 9 +#ENUM 36MBPS 10 +#ENUM 48MBPS 11 +#ENUM 54MBPS 12 + +#ENUM 6_5MBPS_MCS0_20MHZ_SIMO 13 +#ENUM 13MBPS_MCS1_20MHZ_SIMO 14 +#ENUM 19_5MBPS_MCS2_20MHZ_SIMO 15 +#ENUM 26MBPS_MCS3_20MHZ_SIMO 16 +#ENUM 39MBPS_MCS4_20MHZ_SIMO 17 +#ENUM 52MBPS_MCS5_20MHZ_SIMO 18 +#ENUM 58_5MBPS_MCS6_20MHZ_SIMO 19 +#ENUM 65MBPS_MCS7_20MHZ_SIMO 20 + +#ENUM 7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#ENUM 14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#ENUM 21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#ENUM 28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#ENUM 43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#ENUM 57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#ENUM 65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#ENUM 72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 + +#ENUM 0_25MBPS_SLR_20MHZ_SIMO 29 +#ENUM 0_5MBPS_SLR_20MHZ_SIMO 30 + +#ENUM 68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#ENUM 54MBPS_MCS3_40MHZ_SIMO 32 +#ENUM 81MBPS_MCS4_40MHZ_SIMO 33 +#ENUM 108MBPS_MCS5_40MHZ_SIMO 34 +#ENUM 121_5MBPS_MCS6_40MHZ_SIMO 35 +#ENUM 135MBPS_MCS7_40MHZ_SIMO 36 +#ENUM 15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#ENUM 30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#ENUM 45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#ENUM 60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#ENUM 90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#ENUM 120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#ENUM 135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#ENUM 150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 2.4GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 1M + +WNI_CFG_FIXED_RATE_MULTICAST_24GHZ I 4 8 +V RW NP +HAL +0 31 1 +V RW NP +HAL +0 31 1 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 5 GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 6M + +WNI_CFG_FIXED_RATE_MULTICAST_5GHZ I 4 8 +V RW NP +HAL +0 31 5 +V RW NP +HAL +0 31 5 + +* +* retry rate selection policy +* 0 => use the minimum supported rate +* 1 => use the same rate as the chosen primary rate +* 2 => use the rate specified in RETRYRATE_SECONDARY +* 3 => use the rate closest to the primary +* 4 => autoselect the retry rate based on RA algorithm +* + +WNI_CFG_RETRYRATE_POLICY I 4 0 +V RW NP +HAL +0 255 4 +V RW NP +HAL +0 255 4 + +#ENUM MIN_SUPPORTED 0 +#ENUM PRIMARY 1 +#ENUM RESERVED 2 +#ENUM CLOSEST 3 +#ENUM AUTOSELECT 4 +#ENUM MAX 5 + +* +* the following two CFG's are +* used only if the retryrate policy == 2 +* These should be set to one of the values used +* for configuring fixed rates (see enumerated rates) +* + +WNI_CFG_RETRYRATE_SECONDARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +WNI_CFG_RETRYRATE_TERTIARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +* ********************************************************* +* +* Automatic Power Save Delivery capability +* + +WNI_CFG_APSD_ENABLED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Shared key authentication supported +* + +WNI_CFG_SHARED_KEY_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Open system authentication supported +* + +WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Authentication Type (change requires restart) +* + +WNI_CFG_AUTHENTICATION_TYPE I 4 8 +V RW NP RESTART +NONE +0 65535 0 +V RW NP RESTART +NONE +0 65535 0 + +* +* CF Poll Request (change requires restart) +* + +WNI_CFG_CF_POLL_REQUEST I 4 8 +NV RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Privacy Enabled (change requires restart) +* + +WNI_CFG_PRIVACY_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Short Preamble (change requires restart) +* + +WNI_CFG_SHORT_PREAMBLE I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Short Slot time +* This is the operational state of the BSS + +WNI_CFG_SHORT_SLOT_TIME I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 0 + + +* +* ACCEPT Short Slot Association only +* +* 1: If AP supports shortSlot, then AP will accept +* association only from stations that supports +* supports short slot +* 0: AP supports shortSlot, but AP will accept association +* from stations regardless of whether station supports +* short slot or long slot +* +WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* QOS Enabled (change requires restart) +* + +WNI_CFG_QOS_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* HCF Enabled (change requires restart) +* + +WNI_CFG_HCF_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* RSN (11i/WPA) Enabled +* + +WNI_CFG_RSN_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Background scanning periodicity (kilo usec) +* + +WNI_CFG_BACKGROUND_SCAN_PERIOD I 4 8 +V RW NP +LIM +0 180000 5000 +V RW NP +LIM +0 18000 5000 + +* +* Max number of Preauthentication +* + +WNI_CFG_MAX_NUM_PRE_AUTH I 4 8 +V RW NP RESTART +NONE +0 256 64 +V RW NP RESTART +NONE +0 256 64 + +* +* Preauthentication Cleanup Timeout (kilo usec) +* + +WNI_CFG_PREAUTH_CLNUP_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 120000 30000 + +* +* Release AID Timeout +* + +WNI_CFG_RELEASE_AID_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 100000 1000 +* +* Heartbeat Threshold +* + +WNI_CFG_HEART_BEAT_THRESHOLD I 4 8 +V RW NP +LIM +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Probe response wait time out after heartbeat failure +* + +WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT I 4 8 +V RW NP +NONE +10 10000 40 +V RW NP +NONE +10 10000 40 + +* +* Manufacturer OUI (from eeprom) +* + +WNI_CFG_MANUFACTURER_OUI S 3 8 +V RO NP +NONE +3 0x0 0xa 0xf5 +V RO NP +NONE +3 0x0 0xa 0xf5 + +* +* Manufacture Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_NAME S 65 8 +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D + +* +* Model Number (from eeprom) +* + +WNI_CFG_MODEL_NUMBER S 33 8 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 + + + +* +* Model Name (from eeprom) +* WFR4031 +* + +WNI_CFG_MODEL_NAME S 33 8 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 + + + + +* +* Manufacture Product Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_NAME S 33 8 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 + + +* +* Manufacture Product Version (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_VERSION S 33 8 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 + +* +* Multi Domain Capability (11d) Enable +* + +WNI_CFG_11D_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 0 + +* +* per channel Max power transmit (in dBm) +* this parameter correspond to the MAX_COUNTRY_EID +* table of (Channel Number/num channel/max tx power) +* +* There is one table for 5GHz channels and one table for 2.4GHz channels +* + +WNI_CFG_MAX_TX_POWER_2_4 S 128 8 +V RW NP +NONE +3 1 14 20 +V RW NP +NONE +3 1 14 20 + +WNI_CFG_MAX_TX_POWER_5 S 128 8 +V RW NP +NONE +3 36 126 20 +V RW NP +NONE +3 36 126 20 + +* +* Cell size configurations. These are canned configurations for a specified +* cell size. +* +WNI_CFG_NETWORK_DENSITY I 4 9 +V RW NP +HAL +0 3 3 +V RW NP +HAL +0 3 0 + +#ENUM LOW 0 +#ENUM MEDIUM 1 +#ENUM HIGH 2 +#ENUM ADAPTIVE 3 + + +* +* Adaptive Threshold Algorithm +* +WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 2 2 + +#ENUM CARRIER 1 +#ENUM CORRELATION 2 + + + +* +* Current TX Antenna +* + +WNI_CFG_CURRENT_TX_ANTENNA I 4 9 +V RW NP +HAL +1 1 1 +V RW NP +HAL +1 2 2 + +* +* Current RX Antenna +* + +WNI_CFG_CURRENT_RX_ANTENNA I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 3 3 + +* +* Current TX Power Level +* + +WNI_CFG_CURRENT_TX_POWER_LEVEL I 4 9 +V RW NP +NONE +0 128 27 +V RW NP +NONE +0 128 27 + + +* + + + + +* Parameter to indicate or not new BSS found +* + +WNI_CFG_NEW_BSS_FOUND_IND I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + + +* +* Qualcomm Prop Rates are disabled by default +* +WNI_CFG_PROPRIETARY_RATES_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* AP node Name +* + +WNI_CFG_AP_NODE_NAME S 32 8 +NV RO NP +NONE +0 +V RW NP RESTART +NONE +0 + +* +* Country code (from EEPROM) +* + +WNI_CFG_COUNTRY_CODE S 3 8 +V RW NP +NONE +0 +V RW NP +NONE +3 0x11 0x22 0x33 + +* +* Spectrum Management (11h) enable/disable +* + +WNI_CFG_11H_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Wait for CNF Timeout. CNF include (RE)ASSOC, DISASSOC, AUTH, DEAUTH, +* DUMMY packet +* + +WNI_CFG_WT_CNF_TIMEOUT I 4 12 +V RW NP +NONE +10 3000 1000 +V RW NP +NONE +10 3000 1000 + +* +* Proximity, set it for very short distances +* Proxmity setting is applied via halPhySetNwDensity() +* +* close proximity off = densityOn is true. network density config applies. +* close proximity on = densityOn is false. Don't care about network density config. +* + +WNI_CFG_PROXIMITY I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM OFF 0 +#ENUM ON 1 + +* +* Default LOG level +* + +WNI_CFG_LOG_LEVEL I 4 12 +V RW NP +NONE +0 7 4 +V RW NP +NONE +0 7 4 + +* +* OLBC detection timeout +* + +WNI_CFG_OLBC_DETECT_TIMEOUT I 4 12 +V RW NP +NONE +1000 30000 10000 +V RW NP +NONE +1000 30000 10000 + +********************************** +* Protection Enable +* +*LOWER byte for associated stations +*UPPER byte for overlapping stations. +*11g ==> protection from 11g +*11b ==> protection from 11b +*each byte will have the following info +*bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 +*reserved reserved RIFS Lsig n-GF ht20 11g 11b +********************************** +WNI_CFG_PROTECTION_ENABLED I 4 9 +V RW NP RESTART +LIM +0 0xffff 0xffff +V RW NP RESTART +LIM +0 0xffff 0xffff + +#ENUM FROM_llA 0 +#ENUM FROM_llB 1 +#ENUM FROM_llG 2 +#ENUM HT_20 3 +#ENUM NON_GF 4 +#ENUM LSIG_TXOP 5 +#ENUM RIFS 6 +#ENUM OBSS 7 +#ENUM OLBC_FROM_llA 8 +#ENUM OLBC_FROM_llB 9 +#ENUM OLBC_FROM_llG 10 +#ENUM OLBC_HT20 11 +#ENUM OLBC_NON_GF 12 +#ENUM OLBC_LSIG_TXOP 13 +#ENUM OLBC_RIFS 14 +#ENUM OLBC_OBSS 15 + + +* **************************************** +* +* 11G Protection Enable Always +* Valid only if protection is enabled +* forces uses of protection regardless of legacy stations +* + +WNI_CFG_11G_PROTECTION_ALWAYS I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +********************************************* +* Force protection +* 0 : disable protection +* 1 : CTS +* 2 : RTS by threshold (threshold nonzero) +* 3 : dual CTS (not supported right now) +* 4 : RTS (threshold 0) +* 5 : auto + +WNI_CFG_FORCE_POLICY_PROTECTION I 4 9 +V RW NP RESTART +HAL +0 5 5 +V RW NP RESTART +HAL +0 5 5 + +#ENUM DISABLE 0 +#ENUM CTS 1 +#ENUM RTS 2 +#ENUM DUAL_CTS 3 +#ENUM RTS_ALWAYS 4 +#ENUM AUTO 5 + + + + + + +******************************************** +* 11G Short Preamble Enable +* + +WNI_CFG_11G_SHORT_PREAMBLE_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* 11G Short Slot Time Enable (change requires restart) +* This is the admin state of short slot support. + +WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Calibration periodicity (minutes) +* + +WNI_CFG_CAL_PERIOD I 4 12 +V RW NP +HAL +2 10 5 +V RW NP +HAL +2 10 5 + +* +* Statistics collection periodicity (seconds) +* + +WNI_CFG_STATS_PERIOD I 4 12 +V RW NP +HAL +1 10 10 +V RW NP +HAL +1 10 10 + +* +* Calibration on/off control +* + +WNI_CFG_CAL_CONTROL I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM CAL_ON 0 +#ENUM CAL_OFF 1 + + +* +* Parameter to allow 11g only STAs while operating in 11g mode +* + +WNI_CFG_11G_ONLY_POLICY I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Packet Classification +* This flag is a bitmask used to indicate which +* frame classifier to be enabled: +* b0: DSCP +* b1: 802.1P +* + +WNI_CFG_PACKET_CLASSIFICATION I 4 12 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +#ENUM DISABLED 0 +#ENUM DSCP 1 +#ENUM 8021P 2 +#ENUM ALL 3 + +* +* WME Enabled (change requires restart) +* + +WNI_CFG_WME_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* ADDTS response timeout (in ms) +* + +WNI_CFG_ADDTS_RSP_TIMEOUT I 4 8 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + + + * Max SP Length indicates the max number of + * total buffered MSDUs and MMPDUs the WMM AP + * may deliver to WMM STA during any service period + * triggered by WMM STA. + * 1) If AP sends WMM IE with the UAPSD bit 0, max_sp_length=0 + * 2) If WMM STA's all 4 UAPSD flag are set to 0, max_sp_length=0 + * 3) If AP sends WMM IE with UAPSD=1, and at least one of stations + * UAPSD flag is set to 1, then max_sp_length can be set to: + * [b5:b6]=0x00: WMM AP may deliver all buffered frames + * [b5:b6]=0x10: WMM AP may deliver max 2 buffered frames + * [b5:b6]=0x01: WMM AP may deliver max 4 buffered frames + * [b5:b6]=0x11: WMM AP may deliver max 6 buffered frames + +WNI_CFG_MAX_SP_LENGTH I 4 8 +V RW NP +NONE +0 3 0 +V RW NP +NONE +0 3 0 + + +* +* KEEP ALIVE STA Limit Threshold , used in AP to delete the STA +* from Station Table which didn't respond to Probe Response Messages +* + +WNI_CFG_KEEP_ALIVE_STA_LIMIT_THRESHOLD I 4 8 +NV RW NP +NONE +0 32 0 +V RW NP +NONE +0 32 0 + +* +* Parameter that specifies whether to send SSID +* in Probe Response when SSID is suppressed +* + +WNI_CFG_SEND_SINGLE_SSID_ALWAYS I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* WSM Enabled (change requires restart) +* Takes effect only if WME is also enabled +* + +WNI_CFG_WSM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* **************************************** +* + + + +* Background Channel List +* Contains pairs of {channelNumber, scanType} +* where scanType = 0 indicates active scan and +* = 1 indicates passive scan +* +* +*WNI_CFG_BACKGROUND_SCAN_LIST S 128 8 +*V RW NP RESTART +*LIM +*60 36 0 40 0 44 0 48 0 52 0 56 0 60 0 64 0 1 0 6 0 11 0 34 0 38 0 42 0 46 0 2 0 3 0 4 0 5 0 7 0 8 0 9 0 10 0 12 0 13 0 14 0 149 0 153 0 157 0 161 0 +*V RW NP RESTART +*LIM +*60 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 34 0 36 0 38 0 40 0 42 0 44 0 46 0 48 0 52 0 56 0 60 0 64 0 149 0 153 0 157 0 161 0 +* + +* **************************************** +* EDCA paramters are contained in profiles - each profile contains +* the parameters [ACM, AIFSN, CWmin, CWmax, TxOp] for four +* access categories (i.e., four sets). Two such sets of four parameters +* make a single profile: One set is used locally by the AP, the other set +* is broadcast for use by stations. +* +* Cwmin and Cwmax are two bytes each, MSB first. So Cwmin of [3 255] is +* equivalent to 0x3ff, i.e. 3*256+255=1023 +* +* The profile to use is selected based on the valus of the profile select param +* See ENUMs below for definitions of profile values +* + +WNI_CFG_EDCA_PROFILE I 4 8 +V RW NP +SCH +0 255 1 +V RW NP +SCH +0 255 1 + +#ENUM ANI 0 +#ENUM WMM 1 +#ENUM TIT_DEMO 2 +#ENUM MAX 3 + +#ENUM ACM_IDX 0 +#ENUM AIFSN_IDX 1 +#ENUM CWMINA_IDX 2 +#ENUM CWMAXA_IDX 4 +#ENUM TXOPA_IDX 6 +#ENUM CWMINB_IDX 7 +#ENUM CWMAXB_IDX 9 +#ENUM TXOPB_IDX 11 +#ENUM CWMING_IDX 12 +#ENUM CWMAXG_IDX 14 +#ENUM TXOPG_IDX 16 + + +* **************************************** +* Profile 0 (Airgo) parameters - AC_BK Local +* ACM, AIFSN, [CWminH, CWminL, CWmaxH, CWmaxL, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + +* +* Profile 0 (Airgo) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + + +* **************************************** +* Profile 1 (WME) parameters - AC_BK Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + + +* +* Profile 1 (WME) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 31 3 255 0 0 15 0 63 0 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 15 0 63 0 0 15 0 63 0 + +* +* Profile 1 (WME) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Profile 1 (WME) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Radar detector flag enable/disable +* + +WNI_CFG_RDET_FLAG I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +WNI_CFG_RADAR_CHANNEL_LIST S 20 8 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 + +* +* Local Power Constraint (dBm) +* + +WNI_CFG_LOCAL_POWER_CONSTRAINT I 4 12 +V RW NP RESTART +NONE +0 255 0 +V RW NP RESTART +NONE +0 255 0 + +* ********************************************************* +* +* Admission Control Policy +* used for admitting tspec's when either edca or hcca are in use +* + +WNI_CFG_ADMIT_POLICY I 4 8 +V RW NP RESTART +NONE +0 2 0 +V RW NP +SCH +0 2 0 + +#ENUM ADMIT_ALL 0 +#ENUM REJECT_ALL 1 +#ENUM BW_FACTOR 2 + +* +* Oversubscription factor for admission control +* valid only when admit policy is set to BW_FACTOR +* units are in terms of 1/10th of available bandwidth +* + +WNI_CFG_ADMIT_BWFACTOR I 4 8 +V RW NP RESTART +NONE +0 100 20 +V RW NP +SCH +0 100 20 + +* ********************************************************* +* +* Number of "consecutive" Background Scan Failure needed +* before LIM is forced to perform 1 aggressive background scan +* +WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE I 4 8 +V RW NP RESTART +NONE +0 256 60 +V RW NP RESTART +NONE +0 256 60 + + +************************************* +* Feature: Channel Bonding +************************************* +* +* Global flag to enable/disable Channel Bonding +* 0 - Disable: Force disable channel bonding for all TC-ids +* 1 - Enable: Force enable channel bonding for all TC-ids +* 2 - no legacy bss: Enable channel bonding if no legacy BSS are present +* 3 - no legacy all: Enable channel bonding if no legacy BSS or devices are present +* 4 - intelligent: Enable channel bonding depending on load level on secondary channel +* +WNI_CFG_CHANNEL_BONDING_MODE I 4 12 +V RW NP RESTART +LIM +0 10 0 +V RW NP RESTART +LIM +0 10 0 + +#ENUM DISABLE 0 +#ENUM ENABLE 1 +#ENUM IF_NO_LEGACY_BSS 2 +#ENUM IF_NO_LEGACY_ALL 3 +#ENUM INTELLIGENT 4 + + +* +* When the channel is 40MHz wide, this CFG indicates +* if the secondary channel is located above (at +* a higher frequency), or located below (at a +* lower frequency). +* +* 0 - There is no secondary channel. The channel is 20Mhz +* 1 - LOWER: Secondary channel 40MHZ is located below the primary channel +* 2 - CENTERED:Secondary channel and primary located at centered +* 3 - HIGHER: Secondary channel 40 MHZ is located above the primary channel +* 4 - 80MHZ_LOW_CENTERED : 20/40MHZ offset LOW 40/80MHZ offset CENTERED +* 5 - 80MHZ_CENTERED_CENTERED : 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED +* 6 - 80MHZ_HIGH_CENTERED : 20/40MHZ offset HIGH 40/80MHZ offset CENTERED +* 7 - 80MHZ_LOW_LOW: 20/40MHZ offset LOW 40/80MHZ offset LOW +* 8 - 80MHZ_HIGH_LOW: 20/40MHZ offset HIGH 40/80MHZ offset LOW +* 9 - 80MHZ_LOW_HIGH: 20/40MHZ offset LOW 40/80MHZ offset HIGH +* 10 - 80MHZ_HIGH_HIGH: 20/40MHZ offset HIGH 40/80MHZ offset HIGH +* +WNI_CFG_CB_SECONDARY_CHANNEL_STATE I 4 12 +V RW NP +NONE +0 10 0 +V RW NP +NONE +0 10 0 + +#ENUM NONE 0 +#ENUM LOWER 1 +#ENUM HIGHER 2 +#ENUM 11AC_20MHZ_LOW_40MHZ_CENTERED 3 +#ENUM 11AC_20MHZ_CENTERED_40MHZ_CENTERED 4 +#ENUM 11AC_20MHZ_HIGH_40MHZ_CENTERED 5 +#ENUM 11AC_20MHZ_LOW_40MHZ_LOW 6 +#ENUM 11AC_20MHZ_HIGH_40MHZ_LOW 7 +#ENUM 11AC_20MHZ_LOW_40MHZ_HIGH 8 +#ENUM 11AC_20MHZ_HIGH_40MHZ_HIGH 9 + +************************************* +* Feature: Dynamic Retry Rates +************************************* +* +* When the short/long retry count reach the +* adaptive_retry_threshold(0), then the retry0 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_ZERO I 4 12 +V RW NP +HAL +0 255 2 +V RW NP +HAL +0 255 2 + +* +* When the short/long retry count reach the +* adaptive_retry_threshold(1), then the retry1 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_ONE I 4 12 +V RW NP +HAL +0 255 4 +V RW NP +HAL +0 255 4 + +* +* When the short/long retry count reach the +* adaptive_retry_threshold(2), then the retry2 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_TWO I 4 12 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + + +* +* Trigger Station Background Scan Flag +* +WNI_CFG_TRIG_STA_BK_SCAN I 4 12 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 1 + +* ********************************************************* +* control of dynamic EDCA parameter profile switching +* +* OOB, we would like to support WMM standard edca profile +* However, when Airgo STA's join the BSS, we would like +* to switch the profile to Airgo high-performance edca parameters +* +* This cfg supports that behaviour. It is used only if 11e qos +* has been enabled and is ignored otherwise. +* +* When set to any value (other than unused), it determines the +* edca profile to switch to when an Airgo STA joins the BSS. +* +* By default, we choose to switch to Airgo profile. +* +* NOTE: This parameter applies only to an AP +* + +WNI_CFG_DYNAMIC_PROFILE_SWITCHING I 4 8 +V RW NP RESTART +NONE +0 255 255 +V RW NP RESTART +NONE +0 255 1 + +#ENUM UNUSED 255 + +* ********************************************************* +* +* Scan control list +* Contains pairs of {channelNumber, activeScanAllowedFlag} +* where scanType = 1 indicates active scan is allowed, and +* = 0 indicates passive scan is used +* If a channel is not on this list, active scan is NOT allowed. So it is +* sufficient to inlude only those channels where active scan is allowed +* on this list. +* +* The list determines only whether active scan is allowed or not; it does not +* determine which type of scan is actually performed. +* + +WNI_CFG_SCAN_CONTROL_LIST S 128 8 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 + + +* **************************************** +* +* MIMO rates enabled (for rate adaptation, to start) +* + +WNI_CFG_MIMO_ENABLED I 4 9 +V RW NP RELOAD +NONE +0 1 1 +V RW NP RELOAD +NIM +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + + +* +* BLOCK ACK Enabled (change requires restart) +* change default to ON +* bit 0 ==> delayed BA +* bit 1 ==> immediate BA +WNI_CFG_BLOCK_ACK_ENABLED I 4 8 +V RW NP RESTART +LIM +0 3 0 +V RW NP RESTART +LIM +0 3 0 + +#ENUM DELAYED 0 +#ENUM IMMEDIATE 1 + + +* +*BA Activity check global timer +* +WNI_CFG_BA_ACTIVITY_CHECK_TIMEOUT I 4 7 +V RW NP +HAL +0 65535 1000 +V RW NP +HAL +0 65535 1000 + + +* +* Rx STBC support +* +WNI_CFG_HT_RX_STBC I 4 7 +V RW NP RESTART +LIM +0 3 1 +V RW NP RESTART +LIM +0 3 1 + + +* +* 1. HT capabilities Info: 2 bytes size +* +* Supported channel Width is set to 1 (40 Mhz) +* SM Power Save is disabled. +* GreenField support is enabled. +* Short GI for 20 and 40Mhz is enabled. +* Max AMSDU Size is set to 0(3839 Octets) +* DSSS-CCK Mode is enabled. +* LSIG TXOP Protection is disabled +* Rest of the features are not supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0001 0010 0000 +* +WNI_CFG_HT_CAP_INFO I 4 10 +V RW NP RESTART +LIM +0 0xffff 0x016c +V RW NP RESTART +LIM +0 0xffff 0x106e + +#ENUM ADVANCE_CODING 0 +#ENUM SUPPORTED_CHAN_WIDTH_SET 1 +#ENUM SM_POWER_SAVE 2 +#ENUM GREEN_FIELD 4 +#ENUM SHORT_GI_20MHZ 5 +#ENUM SHORT_GI_40MHZ 6 +#ENUM TX_STBC 7 +#ENUM RX_STBC 8 +#ENUM DELAYED_BA 10 +#ENUM MAX_AMSDU_SIZE 11 +#ENUM DSSS_CCK_MODE_40MHZ 12 +#ENUM PSMP 13 +#ENUM STBC_CONTROL_FRAME 14 +#ENUM LSIG_TXOP_PROTECTION 15 + +* +* 2. HT Parameters Info: 1 byte size +* +* Max AMPDU Rx Factor is defined using bit #0 and #1 +* MPDU Density is defined using bit #2 thru #4. +* The default values are, +* 7654 3210 +* 0000 0010 --> 2 for RX AMPDU Factor, 0 for MPDU density +* +WNI_CFG_HT_AMPDU_PARAMS I 4 7 +V RW NP RESTART +LIM +0 0xff 0x00 +V RW NP RESTART +LIM +0 0xff 0x02 + +#ENUM MAX_RX_AMPDU_FACTOR 0 +#ENUM MPDU_DENSITY 2 +#ENUM RESERVED 5 + +* +* 3. Supported MCS Set: 16 bytes size +* +* MCS #0-15 and #32 is supported. +* +WNI_CFG_SUPPORTED_MCS_SET S 16 7 +V RW P RESTART +LIM +16 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 255 255 0 0 1 0 0 0 0 0 0 0 0 0 0 0 + +* +* 4. Extended HT Capabilities Info: 2 bytes size +* +* Only HTC Support is enabled, rest all features are not +* supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0100 0000 0000 +* +WNI_CFG_EXT_HT_CAP_INFO I 4 10 +V RW P RESTART +LIM +0 0xffff 0x0400 +V RW P RESTART +LIM +0 0xffff 0x0400 + +#ENUM PCO 0 +#ENUM TRANSITION_TIME 1 +#ENUM RESERVED1 3 +#ENUM MCS_FEEDBACK 8 +#ENUM HTC_SUPPORT 10 +#ENUM RD_RESPONDER 11 +#ENUM RESERVED2 12 + + +* +* 5. Transmit Beam Forming Capabiliries Info: 4 bytes size +* +WNI_CFG_TX_BF_CAP I 4 7 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 + +* +* 6. Antenna Selection Capabilities: 1 byte size +* +WNI_CFG_AS_CAP I 4 7 +V RW P RESTART +LIM +0 0xff 0x00 +V RW P RESTART +LIM +0 0xff 0x00 + +#ENUM ANTENNA_SELECTION 0 +#ENUM EXPLICIT_CSI_FEEDBACK_TX 1 +#ENUM ANTENNA_INDICES_FEEDBACK_TX 2 +#ENUM EXPLICIT_CSI_FEEDBACK 3 +#ENUM ANTENNA_INDICES_FEEDBACK 4 +#ENUM RX_AS 5 +#ENUM TX_SOUNDING_PPDUS 6 +#ENUM RESERVED 7 + +************************************************** +* Beacon HT (High Through) Info IE +*************************************************** +* +* 3. HT Info Field1: 1 byte size. +* +* Secondary Channel Offset is set to 3 (Down) by default and will +* be updated dynamically by DFS algorithm. +* Channel Width is set to 1 (40 Mhz) +* RIFS Mode is enabled +* Rest of the features are not supported at this moment. +* +* 7654 3210 +* 0000 1111 +* +WNI_CFG_HT_INFO_FIELD1 I 4 10 +V RW NP RESTART +LIM +0 0xff 0x0f +V RW NP RESTART +LIM +0 0xff 0x0f + +#ENUM SECONDARY_CHANNEL_OFFSET 0 +#ENUM RECOMMENDED_CHANNEL_WIDTH 2 +#ENUM RIFS_MODE 3 +#ENUM PSMP_ACCESS_ONLY 4 +#ENUM SERVICE_INTERVAL_GRANULARITY 5 + +* +* 4. HT Info Field2: 2 bytes +* +* Operation mode is set to 0(Pure, GF) to begin with and +* will be updated dynamically. +* 'NonGF Devices present is also set to zero and +* will be updated dynamically. +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +WNI_CFG_HT_INFO_FIELD2 I 4 10 +V RW P +LIM +0 0xffff 0x00 +V RW P +LIM +0 0xffff 0x00 + +#ENUM OP_MODE 0 +#ENUM NON_GF_DEVICES_PRESENT 2 +#ENUM RESERVED 3 + +* +* 5. HT Info Field3: 2 bytes +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +* LSIG TXOP Full Protection will be zero to begin with and +* updated dynamically. +* Everything else is not supported at this moment. +* +WNI_CFG_HT_INFO_FIELD3 I 4 10 +V RW P +LIM +0 0xffff 0x0000 +V RW P +LIM +0 0xffff 0x0000 + +#ENUM BASIC_STBC_MCS 0 +#ENUM DUAL_STBC_PROTECTION 7 +#ENUM SECONDARY_BEACON 8 +#ENUM LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#ENUM PCO_ACTIVE 10 +#ENUM PCO_PHASE 11 +#ENUM RESERVED 12 + +* +* 6. Basic MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_BASIC_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +* +* 7. Current supported MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_CURRENT_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + +* +* Greenfield Capability +* By default Greenfield is enabled +* +WNI_CFG_GREENFIELD_CAPABILITY I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Maximum AMPDU Length +* By default set to zero for 3895 octets +* +WNI_CFG_VHT_MAX_MPDU_LENGTH I 4 19 +V RW NP +LIM +0 2 0 +V RW NP +LIM +0 2 0 + +* +* Supported Channel Width Set +* By default set to zero for +* STAs does not support either 160 or 80+80MHz +* +WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* LDPC Coding Capability +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_LDPC_CODING_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Short GI for 80MHz +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_SHORT_GI_80MHZ I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Short GI for 160MHz and 80+80MHz +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Transmission of 2x1 STBC +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_TXSTBC I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Reception of PPDUs using STBC +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_RXSTBC I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Support for Operating as SU Beamformer +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Operating as SU Beamformee +* Riva does not support, But Pronto supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Compressed Steering Number of Beamformer Antennas Supported +* Riva does not support,Pronto supports, default set to 0 +* +WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Number of Sounding Dimensions indicates Number +* of antennas used by the beamformer when sending beamformed transmissions +* Riva/Pronto does not support beamformer, default set to 0 +* +WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* MU Beamformer Capable +* Riva/Pronto does not support, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* MU Beamformee Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* VHT TXOP PS +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_TXOP_PS I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* +HTC-VHT Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_HTC_VHTC_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Maximum AMPDU Length exponent range 0-7 +* 2^(13+Max AMPDU Length)-1, default set to 0 +* +WNI_CFG_VHT_AMPDU_LEN_EXPONENT I 4 19 +V RW NP +LIM +0 7 3 +V RW NP +LIM +0 7 3 + +* +* VHT Link Adaptation Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_LINK_ADAPTATION_CAP I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* VHT Rx Antenna Pattern Consistency +* +WNI_CFG_VHT_RX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* VHT Tx Antenna Pattern Consistency +* +WNI_CFG_VHT_TX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* RxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be received for each +* number of spacial streams. Riva supports MCS 0-9 +* +WNI_CFG_VHT_RX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* TxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be transmitted for each +* number of spacial streams. +* +WNI_CFG_VHT_TX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* Rx Highest supported data rate. +* +WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Tx Highest supported data rate. +* +WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Channel center freq Seg1 +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1 I 4 19 +V RW NP +LIM +0 256 0 +V RW NP +LIM +0 256 0 + +* +* Channel center freq Seg2 for 80+80 Mhz +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2 I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Basic MCS Set +* +WNI_CFG_VHT_BASIC_MCS_SET I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* MU-MIMO Capable STA Count +* +WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Spatial Stream Under-Utilization +* +WNI_CFG_VHT_SS_UNDER_UTIL I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Forty MHZ Utilization +* +WNI_CFG_VHT_40MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Eighty MHz Utilization +* +WNI_CFG_VHT_80MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Hundred Sixty MHz Utilization +* +WNI_CFG_VHT_160MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Maximum AMSDU length +* User can set it to either 3839 or 7935 bytes. +* +WNI_CFG_MAX_AMSDU_LENGTH I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM SHORT_3839_BYTES 0 +#ENUM LONG_7935__BYTES 1 + + +* +* Minimum MPDU Start Spacing +* Determines the minimum time between the start of adjacent MPDUs within an AMPDU. +* Set to 0 for no restriction +* Set to 1 for 1/4 s +* Set to 2 for 1/2 s +* Set to 3 for 1 s +* Set to 4 for 2 s +* Set to 5 for 4 s +* Set to 6 for 8 s +* Set to 7 for 16 s +* default is set to 0 +WNI_CFG_MPDU_DENSITY I 4 7 +V RW NP RESTART +LIM +0 7 0 +V RW NP RESTART +LIM +0 7 0 + +* +* NUM BUFFERS ADVERTISED +* Defines number of buffers advertised in ADDBA +* +WNI_CFG_NUM_BUFF_ADVERT I 4 7 +V RW NP +LIM +0 128 64 +V RW NP +LIM +0 128 64 + +* +* Maximum Rx AMPDU Factor +* Indicates the maximum length of A-MPDU +* that the STA can receive. +* The Maximum Rx A-MPDU defined by this field is equal to (2 ^ (13 + MAX RX AMPDU FActor))-1 octets. +* Maximum Rx A-MPDU Factor is an integer in the range 0 to 3. +* default is set to 2 for 32K max RX side. +* +WNI_CFG_MAX_RX_AMPDU_FACTOR I 4 7 +V RW NP RESTART +LIM +0 3 3 +V RW NP RESTART +LIM +0 3 3 + + +* +* Short GI support for the reception of 20Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_20MHZ I 4 7 +V RW NP RESTART +LIM +0 1 1 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* Short GI support for the reception of 40Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_40MHZ I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* RIFS support on TX Side +* on RX side it is always supported, it is mandatory +* +WNI_CFG_RIFS_ENABLED I 4 7 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* ********************************************************* +* +* Power Save Configuration +* +WNI_CFG_MAX_PS_POLL I 4 5 +V RW NP +LIM +0 255 0 +NV RW NP +LIM +0 255 0 + + +WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE I 4 5 +V RW NP +LIM +1 20 20 +NV RW NP +LIM +1 20 20 + + +* +* Period for which Firmware will collect the +* RSSI stats. Its in units of beacon interval. +* Rssi Filter period should always be >= +* the num_beacon_per_rssi_average. +* +WNI_CFG_RSSI_FILTER_PERIOD I 4 5 +V RW NP +LIM +0 255 5 +NV RW NP +LIM +0 255 5 + + +WNI_CFG_MIN_RSSI_THRESHOLD I 4 5 +V RW NP +LIM +0 10 10 +NV RW NP +LIM +0 10 10 + + +WNI_CFG_NTH_BEACON_FILTER I 4 5 +V RW NP +LIM +0 255 10 +NV RW NP +LIM +0 255 10 + + +WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE I 4 5 +V RW NP +LIM +0 1 0 +NV RW NP +LIM +0 1 0 + + +WNI_CFG_SCAN_IN_POWERSAVE I 4 5 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + + +* +* Ignore DTIM support - If disabled(value=0), HAL will +* try to align the Listen Interval to the DTIM +* period and the following rules will be applied: +* 1) If LI=DTIM, then set LI=DTIM +* 2) If LIDTIM, then set LI=DTIM +* +WNI_CFG_IGNORE_DTIM I 4 5 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* ********************************************************* +* +* WoWLAN Configuration The following configurations +* are valid only when magicPktEnable = 1. +* +WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DEAUTH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DISASSOC_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_MAX_MISSED_BEACON I 4 5 +V RW NP +NONE +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Timeout value in units of us. It requests +* hardware to unconditionally wake up after +* it has stayed in WoWLAN mode for some time. +* +WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD I 4 5 +V RW NP +NONE +0 65535 65535 +NV RW NP +NONE +0 65535 65535 + + +* +* BA timeout in TUs, set to 1 minute = approx 58593 TUs +* 16 bit wide +* +WNI_CFG_BA_TIMEOUT I 4 7 +V RW NP RESTART +HAL +0 0xffff 0 +V RW NP +HAL +0 0xffff 0 + + +* +* This threshold is registered with a traffic monitoring interface (probably HAL), +* on a per-STA, per-TID basis. Once this threshold has been reached, +* HAL will indicate to PE that the threshold has been reached for that TID. +* PE is then free to negotiate a BA session for that peer +* defaults to 128 +* 16 bit wide +* +WNI_CFG_BA_THRESHOLD_HIGH I 4 7 +V RW NP RESTART +HAL +0 0xffff 0x80 +V RW NP +HAL +0 0xffff 0x80 + + +* +* MAX BA Buffers to be allocated. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_BUFFERS I 4 7 +V RW NP RESTART +HAL +0 2560 2560 +V RW NP +HAL +0 2560 2560 + + +* +* MAX BA Sessions. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_SESSIONS I 4 7 +V RW NP RESTART +HAL +0 64 40 +V RW NP +HAL +0 64 40 + + +* +* BA setup based on Traffic +* +WNI_CFG_BA_AUTO_SETUP I 4 7 +V RW NP RESTART +HAL +0 1 1 +V RW NP RESTART +HAL +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Decline an ADDBA Request +* +WNI_CFG_ADDBA_REQ_DECLINE I 4 7 +V RW NP RESTART +LIM +0 0xff 0 +V RW NP RESTART +LIM +0 0xff 0 + +* +* Valid Channel List +* + +WNI_CFG_BG_SCAN_CHANNEL_LIST S 100 8 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + + +* +* AMPDU default TX medium Time (in us) +* +WNI_CFG_MAX_MEDIUM_TIME I 4 8 +V RW NP +HAL +0 65535 2048 +V RW NP +HAL +0 65535 2048 + + +* +* Maximum number of MPDUs in single A-MPDU. +* +WNI_CFG_MAX_MPDUS_IN_AMPDU I 4 8 +V RW NP +HAL +0 65535 64 +V RW NP +HAL +0 65535 64 + + +* +* Auto BSSID - When set, BSSID is generated automatically in IBSS, else BSSID in cfg will be used. +* + +WNI_CFG_IBSS_AUTO_BSSID I 4 0 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* Include Additional IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA1 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA2 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA3 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional P2P IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional P2P IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + + +* +* Include Additional IEs in probe response/beacon. +* +WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG I 4 0 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + + +* +* Include Additional IEs in probe response/beacon. +* +WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA S 255 0 +V RW NP +LIM +0 0 +V RW NP +LIM +0 0 + + +* +* wpsApEnable and wpsStaEnable is specified in here +* wpsApEnable is bit #0 and wpsStaEnable is bit #1 +* +WNI_CFG_WPS_ENABLE I 4 7 +V RW NP +LIM +0 0xff 0 +V RW NP +LIM +0 0xff 0 + +#ENUM AP 1 +#ENUM STA 2 + +WNI_CFG_WPS_STATE I 4 7 +V RW NP +LIM +0 0xff 1 +V RW NP +LIM +0 0xff 1 + +* +* TRUE => include this information in Probe Requests, FALSE => omit it +* + +WNI_CFG_WPS_PROBE_REQ_FLAG I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Wi-Fi Protected Setup Version +* +* This one-byte field is broken into a four-bit major +* part using the top MSBs and four-bit minor part +* using the LSBs. As an example, version 3.2 would be 0x32. +* + +WNI_CFG_WPS_VERSION I 4 7 +V RW NP +LIM +0 0xff 0x10 +V RW NP +LIM +0 0xff 0x10 + +* +* Wi-Fi Protected Setup Request type +* 0x00: Enrollee, Info only +* 0x01: Enrollee, open 802.1X +* 0x02: Registrar +* 0x03: WLAN Manager Registrar + +WNI_CFG_WPS_REQUEST_TYPE I 4 7 +V RW NP +LIM +0 0xff 0x00 +V RW NP +LIM +0 0xff 0x03 + +* Configuration Method(s) +* +* The Config Methods Data component lists the configuration methods +* the Enrollee or Registrar supports. The list is a bitwise OR of +* values from the table below. In addition to Config Methods, APs and +* STAs that support the UPnP Management Interface must support the +* Permitted Config Methods attribute, which is used to control the +* Config Methods that are enabled on that AP. +* +* Value Hardware Interface +* 0x0001 USBA (Flash Drive) +* 0x0002 Ethernet +* 0x0004 Label +* 0x0008 Display +* 0x0010 External NFC Token +* 0x0020 Integrated NFC Token +* 0x0040 NFC Interface +* 0x0080 PushButton +* 0x0100 Keypad +* +* The bottom 16 bits contain the configuration method(s) when acting +* as an Enrollee, and the top 16 when acting as a Registrar. +* +* QNE-TODO: Merge this with the inappropriately named +* 'WNI_CFG_WSC_AP_CFG_METHOD'-- this one can serve both puposes. +* + +WNI_CFG_WPS_CFG_METHOD I 4 7 +V RW NP +LIM +0 0xFFFFFFFF 0x00000008 +V RW NP +LIM +0 0xFFFFFFFF 0x018c018e + +* UUID +* The universally unique identifier (UUID) element is a unique +* GUID generated by the Enrollee or Registrar. It uniquely identifies +* an operational device and should survive reboots and resets. The +* UUID is provided in binary format. If the device also supports UPnP, +* then the UUID corresponds to the UPnP UUID. +* +* QNE-TODO: Re-name their cfg from 'WNI_CFG_UUID' + +WNI_CFG_WPS_UUID S 16 8 +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf + +************************************************************************ +* The following cfgs contains the primary type of the device. Its format +* follows: +* +* 0 1 2 3 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | Attribute ID | Length | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | Category ID | OUI (1-2) | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | OUI (3-4) | Sub Category ID | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* +* Vendor-specific sub-categories are designated by setting the OUI to the +* value associated with that vendor. Note that a four-byte subdivided OUI +* is used. For the predefined values, the Wi-Fi Alliance OUI of 00 50 F2 04 +* is used. The predefined values for Category ID and Sub Category ID are +* provided in the next table. There is no way to indicate a vendor-specific +* main device category. The OUI applies only to the interpretation of the +* Sub Category. If a vendor does not use sub categories for their OUI, the +* three-byte OUI occupies the first three bytes of the OUI field and the +* fourth byte is set to zero. +* +* Category ID Value Sub Category ID Value +* Computer 1 PC 1 +* Server 2 +* Media Center 3 +* Input Device 2 +* Printers, Scanners, Printer 1 +* Faxes and Copiers 3 Scanner 2 +* Camera 4 Digital Still Camera 1 +* Storage 5 NAS 1 +* Network AP 1 +* Infrastructure 6 Router 2 +* Switch 3 +* Displays 7 Television 1 +* Electronic Picture Frame 2 +* Projector 3 +* Multimedia Devices 8 DAR 1 +* PVR 2 +* MCX 3 +* Gaming Devices 9 Xbox 1 +* Xbox360 2 +* Playstation 3 +* Telephone 10 Windows Mobile 1 +* +************************************************************************ + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_CATEGORY' +WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 6 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_OUI' +WNI_CFG_WPS_PIMARY_DEVICE_OUI I 4 7 +V RW NP +LIM +0 0xffffffff 0x0050f204 +V RW NP +LIM +0 0xffffffff 0x0050f204 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_SUB_CATEGORY' +WNI_CFG_WPS_DEVICE_SUB_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 1 + +* Association State +* + +* The Association State component shows the configuration and previous +* association state of the wireless station when sending a Discovery +* request. +* +* Association State Description +* 0 Not Associated +* 1 Connection Success +* 2 Configuration Failure +* 3 Association Failure +* 4 IP Failure + +WNI_CFG_WPS_ASSOCIATION_STATE I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* Configuration Error +* +* The Configuration Error component shows the result of the device +* attempting to configure itself and to associate with the WLAN. +* +* Configuration Error Description +* 0 No Error +* 1 OOB Interface Read Error +* 2 Decryption CRC Failure +* 3 2.4 channel not supported +* 4 5.0 channel not supported +* 5 Signal too weak +* 6 Network auth failure +* 7 Network association failure +* 8 No DHCP response +* 9 Failed DHCP config +* 10 IP address conflict +* 11 Couldnt connect to Registrar +* 12 Multiple PBC sessions detected +* 13 Rogue activity suspected +* 14 Device busy +* 15 Setup locked +* 16 Message Timeout +* 17 Registration Session Timeout +* 18 Device Password Auth Failure +* +* The Device busy error is returned if the sending device is unable to +* respond to the request due to some internal conflict or resource +* contention issue. For example, if a device is only capable of +* performing a single instance of the Registration Protocol at a time, +* it may return this error in response to attempts to start another +* instance in the middle of an active session. + +WNI_CFG_WPS_CONFIGURATION_ERROR I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* Device Password ID +* + +* This attribute is used to identify a device password. There are six +* predefined values and ten reserved values. If the Device Password ID is +* Default, the Enrollee should use its PIN password (from the label or +* display). This password may correspond to the label, display, or a +* user-defined password that has been configured to replace the original +* device password. +* +* User-specified indicates that the user has overridden the password with a +* manually selected value. Machine-specified indicates that the original +* PIN password has been overridden by a strong, machinegenerated device +* password value. The Rekey value indicates that the device's 256-bit +* rekeying password will be used. The PushButton value indicates that the +* PIN is the all-zero value reserved for the PushButton Configuration +* method. +* +* The Registrar-specified value indicates a PIN that has been obtained from +* the Registrar (via a display or other out-of-band method). This value may +* be further augmented with the optional 'Identity' attribute in M1. This +* augmentation is useful when multiple predefined UserID/PIN pairs have been +* established by a Registrar such as an authenticator used for Hotspot +* access. If the Device Password ID in M1 is not one of the predefined or +* reserved values, it corresponds to a password given to the Registrar as an +* OOB Device Password. +* +* Value Description +* 0x0000 Default (PIN) +* 0x0001 User-specified +* 0x0002 Machine-specified +* 0x0003 Rekey +* 0x0004 PushButton +* 0x0005 Registrar-specified +* 0x0006 - 0x000F Reserved' +* + +WNI_CFG_WPS_DEVICE_PASSWORD_ID I 4 7 +V RW NP +LIM +0 0xffffffff 0 +V RW NP +LIM +0 0xffffffff 0 + +* +* WPS Association +* +* Wi-Fi Protected Setup requires a prospective enrollee to associate to +* an AP in the network in which the STA would like to enroll. Once +* associated, the enrollment takes place over an EAPOL conversation +* (there's actually a new EAP method: EAP-WSC). The STA would +* presumably send an EAPOL-Start over his new link, to which the AP +* would respond with an EAP Identity Request. When the STA sends back +* "WSC-Enrollee-1" as his EAP Identity, the AP knows that he's got a WPS +* supplicant on his hands, and proceeds to talk EAP-WSC. +* +* Toward the end of the specification's development, a problem came up. +* Microsoft's EAP supplicant on XP SP1 & SP2 will send an EAPOL-Start, +* no matter what. Even if the AP is beaconing WPA-PSK, say, the MS +* supplicant will send an EAPOL-Start. If it receives an EAP Identity +* Request in return, it decides that the AP is really using 802.1x +* authentication, and proceeds on that assumption. +* +* Now, imagine an AP that is configured for WPA-PSK, and is WPS-capable. +* It receives an association request from some STA, and then sees an +* EAPOL-Start from the newly joined STA. It naturally sends back an EAP +* Identity Request to see if the new STA wants to talk EAP-WSC. On +* Windows XP SP1 & SP2, the supplicant will take that to mean that this +* AP is using 802.1x authentication, and will never let the user provide +* the PSK. Consequently, WZC will never be able to associate with this +* AP. +* +* Naturally, Microsoft's solution was to have the world change to +* accommodate them. After a lot of back & forth, the WFA decided on the +* following change to the WPS spec: when associating for purposes of WPS +* enrollment, "A client that intends to use the EAP-WSC method with a +* WSC enabled AP may include a WSC IE in its 802.11 (re)association +* request. If a WSC IE is present in the (re)association request, the AP +* shall engage in EAP-WSC with the station and must not attempt other +* security handshake. If the client does not include a WSC IE in its +* 802.11 (re)association request, it must send its 802.11 Authentication +* frame with Authentication set to open and an 802.11 Association +* Request frame without an RSN IE or SSN IE, regardless of the network +* type that is hosted by the AP. On successful association, the client +* will then send an EAPOL-Start to the AP and wait for +* EAP-Request/Identity. When the client receives an EAP Request/ +* Identity, it will respond with EAP-Response/Identity and the +* appropriate WSC string to indicate if it is an Enrollee or Registrar. +* ' +* +* This configuration variable contains a bitvector: +* +* 0x0001 Incldue the WPS Information Element in Assoc Request frames +* 0x0002 Elide the the WPA and RSN Information Elements from the +* Assoc Request frame +* + +WNI_CFG_WPS_ASSOC_METHOD I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* +* Low gain override +* + +WNI_CFG_LOW_GAIN_OVERRIDE I 4 9 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* Listen Mode Enable/Disable +* + +WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE I 4 7 +V RW NP +HAL +0 128 128 +V RW NP +HAL +0 128 128 + +* +* On chip reodering polling threshold +* + +WNI_CFG_RPE_POLLING_THRESHOLD I 4 2 +V RW NP +HAL +0 65535 10 +V RW NP +HAL +0 65535 10 + +* +* On chip reodering aging threshold for AC0 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC1 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC2 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC3 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* Number of On-Chip reorder sessions +* + +WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS I 4 2 +V RW NP +HAL +0 2 1 +V RW NP +HAL +0 2 1 + + +* +* Single RC for all TID +* + +WNI_CFG_SINGLE_TID_RC I 4 7 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* RRM Enabled +* + +WNI_CFG_RRM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* RRM measurement max duration. Section 11.10.3 802.11k-2008. +* Max Duration represented as maxDuration inTUs = 2^(*WNI_CFG_RRM_IN_CHAN_MAX - 4) * bcnIntvl +* Operating channel max measurement duration. +* + +WNI_CFG_RRM_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* Non-Operating channel max measurement duration. +* + +WNI_CFG_RRM_NON_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* TX power control feature +* + +WNI_CFG_TX_PWR_CTRL_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* MCAST BCAST filter Setting +* 0: No filter, 1: Block Mcast, 2: Block Bcast, 3: Block Mcast and Bcast +* + +WNI_CFG_MCAST_BCAST_FILTER_SETTING I 4 7 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +* +* BTC DHCP No of Bt slots to block +* +WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK I 4 7 +V RW NP +HAL +0 0xFF 0 +V RW NP +HAL +0 0xFF 0 + +* +* Config parameter to Enable/Disable Dynamic PS-Poll mechanism +* 0: Disable, x: FW will send x number of NULL frames before switching to PS-Poll mexhanism +* +WNI_CFG_DYNAMIC_PS_POLL_VALUE I 4 7 +V RW NP +HAL +0 0xFF 0 +V RW NP +HAL +0 0xFF 0 + +* +* PS Data InActivity Timeout (TU) +* + +WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT I 4 7 +V RW NP +HAL +0 80 0 +NV RW NP +NONE +0 80 0 + +* +* Config parameter to Enable/Disable Telescopic Bcn Wakeups +* 0: Disable, 1: Enable +* + +WNI_CFG_TELE_BCN_WAKEUP_EN I 4 7 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + + +* +* Config parameter for Transient LI +* 0: Disable, x: Transient LI +* + +WNI_CFG_TELE_BCN_TRANS_LI I 4 7 +V RW NP +HAL +0 7 3 +V RW NP +HAL +0 7 3 + +* +* Config parameter for Idle bcns for Transient LI +* x: Num Idle bcns before switch to trans LI +* + +WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS I 4 7 +V RW NP +HAL +5 255 10 +V RW NP +HAL +5 255 10 + +* +* Config parameter for Max LI +* 0: Disable, x: Max LI +* + +WNI_CFG_TELE_BCN_MAX_LI I 4 7 +V RW NP +HAL +0 7 5 +V RW NP +HAL +0 7 5 + +* +* Config parameter for Idle bcns for max LI +* x: Num Idle bcns before switch to max LI +* + +WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS I 4 7 +V RW NP +HAL +5 255 15 +V RW NP +HAL +5 255 15 + +* +* BTC DHCP No of Bt sub interval during DHCP +* +WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS I 4 7 +V RW NP +HAL +0 0xFF 7 +V RW NP +HAL +0 0xFF 7 + +* +* Infra STA mode Keep alive period (in secs) for +* sending keep alive (Qos)Null frames to the AP. +* 0 = disabled. Recommended values is 30 secs +* +WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD I 4 7 +V RW NP +HAL +0 1000 0 +V RW NP +HAL +0 1000 0 + +* Limit on number of associated stations +* (applies to peer stations in IBSS, SoftAP, BT-AMP AP, & P2P-GO modes) +* + +WNI_CFG_ASSOC_STA_LIMIT I 4 8 +V RW NP +LIM +1 32 10 +V RW NP +LIM +1 32 10 + +* +* SAP channel select start channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 1 +V RW NP +NONE +1 0xFC 1 + +* +* SAP channel select end channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 11 +V RW NP +NONE +1 0xFC 11 + +* +* SAP channel select operating band +* 0- 2.4GHZ / 1- Low 5GHZ /2-MID /3-HIGH/4-Japan4.9GHZ +* +WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND I 4 7 +V RW NP +NONE +0 0x5 0 +V RW NP +NONE +0 0x5 0 + +* +* Softap data available poll period (in milliseconds) for +* queueing (Qos)Null frames to the station if there +* is no data available and PS-Poll/Trigger frame is pending. +* 0 = disabled. Recommended values is 5ms +* +WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD I 4 8 +V RW NP +NONE +0 65535 5 +V RW NP +NONE +0 65535 5 + +* +* Close loop power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_CLOSE_LOOP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* LTE Coexistence will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_LTE_COEX I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Keep Alive Timeout (TU) +* +WNI_CFG_AP_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* GO Keep Alive Timeout (TU) +* +WNI_CFG_GO_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* MC Addr List power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MC_ADDR_LIST I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* UC Filter will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_UC_FILTER I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* Low Power Image Transition will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_LPWR_IMG_TRANSITION I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* MCC Adaptive Scheduler will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*Disable LDPC in STA mode when AP is TXBF capable +* +* +* +WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Link Monitor Timeout (TU) +* +WNI_CFG_AP_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +1 255 3 +V RW NP +HAL +1 255 3 + +* +*TDLS Station's UAPSD MASK Configuration +* +* +* +WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK I 4 7 +V RW NP +LIM +0 15 0 +V RW NP +LIM +0 15 0 +* +*TDLS Stations Buffer STA Capability +* +* +* +WNI_CFG_TDLS_BUF_STA_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 +*TDLS Stations PUAPSD Inactivity Timer +* +* +* +WNI_CFG_TDLS_PUAPSD_INACT_TIME I 4 7 +V RW NP +LIM +0 10 0 +V RW NP +LIM +0 10 0 +*TDLS Stations PUAPSD RX Frame Threshold +* +* +* +WNI_CFG_TDLS_RX_FRAME_THRESHOLD I 4 7 +V RW NP +LIM +10 20 10 +V RW NP +LIM +10 20 10 + +* +* PMF SA Query Maximum Retries +* + +WNI_CFG_PMF_SA_QUERY_MAX_RETRIES I 4 1 +V RW NP RESTART +NONE +0 20 5 +V RW NP RESTART +NONE +0 20 5 + +* +* PMF SA Query Retry Interval (in TUs) +* + +WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL I 4 1 +V RW NP RESTART +NONE +10 2000 200 +V RW NP RESTART +NONE +10 2000 200 + + +* +*MCC ENABLE/DISABLE ADAPTIVE RX Drain feature +* +* +* +WNI_CFG_ENABLE_ADAPT_RX_DRAIN I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +HAL +0 1 1 + +* +* FlexConnect Power Factor +* Default is set to 0 (disable) +* +* +WNI_CFG_FLEX_CONNECT_POWER_FACTOR I 4 0 +V RW NP +NONE +0 9 0 +V RW NP +NONE +0 9 0 + +* +* Antenna Diversity +* +* 0 = disabled +* 1 = Ant 1 +* 2 = Ant 2 +* 3 = Adaptive +* +WNI_CFG_ANTENNA_DIVESITY I 4 7 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +* GO Link Monitor Timeout (TU) +* +WNI_CFG_GO_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +3 50 10 +V RW NP +HAL +3 50 10 +* +* + +* RMC action period frequency (milli seconds) +* +WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY I 4 7 +V RW NP +HAL +100 1000 300 +V RW NP +HAL +100 1000 300 +* +* + +* Current RSSI value (of connected AP) +* +WNI_CFG_CURRENT_RSSI I 4 7 +V RW NP +NONE +0 127 0 +V RW NP +NONE +0 127 0 + +* RTT3 Bit Value +* +WNI_CFG_RTT3_ENABLE I 1 1 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* Debug p2p remain on channel +* +WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* TDLS Off Channel Implementation +* +WNI_CFG_TDLS_OFF_CHANNEL_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +WNI_CFG_IBSS_ATIM_WIN_SIZE I 4 7 +V RW NP +NONE +0 100 0 +V RW NP +NONE +0 100 0 + +* +* DFS Master capability (11h) enable/disable +* + +WNI_CFG_DFS_MASTER_ENABLED I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +WNI_CFG_VHT_ENABLE_TXBF_20MHZ I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*TDLS WMM Mode +* +* +WNI_CFG_TDLS_WMM_MODE_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 diff --git a/core/mac/src/cfg/cfgUtil/dot11f.frms b/core/mac/src/cfg/cfgUtil/dot11f.frms new file mode 100644 index 0000000000..04165e7907 --- /dev/null +++ b/core/mac/src/cfg/cfgUtil/dot11f.frms @@ -0,0 +1,3611 @@ +/* + * Copyright (c) 2006-2007, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file dot11f.frms + * + * \brief Primary 'frames' file for the MAC parser + * + * + * This file defines several 802.11 frames (along with their associated + * constituents) in a little language called "frames". When run through the + * 'framesc' program, it will generate C code for working with these frames: + * C structs representing the 802.11 frame together with functions for + * packing & unpacking them. + * + * For more information on the "frames" language, run 'framesc --help'... + * + * + */ + + +// Tell framesc what types to use for... +%8-bit-type uint8_t // 8, +%16-bit-type uint16_t // 16, +%32-bit-type uint32_t // & 32-bit unsigned integral types. These can also + // be specified on the command line. + +// Define some mnemonic constants; these are just for our use with the frames +// files we're compiling. IOW, they won't result in any C code being +// emitted. + +const EID_SSID = 0; +const EID_SUPP_RATES = 1; +const EID_FH_PARAM_SET = 2; +const EID_DS_PARAM_SET = 3; +const EID_CF_PARAM_SET = 4; +const EID_TIM = 5; +const EID_IBSS_PARAM_SET = 6; +const EID_COUNTRY = 7; +const EID_FH_PATTERN = 8; +const EID_FH_PATT_TABLE = 9; +const EID_REQUEST = 10; +const EID_QBSS_LOAD = 11; +const EID_EDCA_PARAM_SET = 12; +const EID_TSPEC = 13; +const EID_TCLAS = 14; +const EID_SCHEDULE = 15; +const EID_CHALLENGE_TEXT = 16; +const EID_POWER_CONSTRAINTS = 32; +const EID_POWER_CAPABILITY = 33; +const EID_TPC_REQUEST = 34; +const EID_TPC_REPORT = 35; +const EID_SUPPORTED_CHANNELS = 36; +const EID_CHANNEL_SWITCH_ANN = 37; +const EID_MEAS_REQUEST = 38; +const EID_MEAS_REPORT = 39; +const EID_QUIET = 40; +const EID_ERP_INFO = 42; +const EID_TS_DELAY = 43; +const EID_TCLASS_PROC = 44; +const EID_HT_CAPABILITIES = 45; +const EID_QOS_CAPABILITY = 46; +const EID_RSN = 48; +const EID_EXT_SUPP_RATES = 50; +const EID_AP_CHAN_REPORT = 51; +const EID_NEIGHBOR_REPORT = 52; +const EID_RCPI = 53; +const EID_FT_MOBILITY_DOMAIN = 54; +const EID_FT_INFO = 55; +const EID_TIMEOUT_INTERVAL = 56; +const EID_FT_RIC_DATA = 57; +const EID_SUPPORTED_OPER_CLASSES = 59; +const EID_EXT_CHAN_SWITCH = 60; +const EID_HT_INFO = 61; +const EID_SEC_CHAN_OFFSET = 62; +const EID_RSNI = 65; +const EID_RRM_MEAS_PILOT_TX_INFO = 66; +const EID_WAPI = 68; +const EID_TIME_ADVERTISEMENT = 69; +const EID_RRM_ENABLED_CAPS = 70; +const EID_MULTIPLE_BSSID = 71; +const EID_20_40_BSS_COEXISTENCE = 72; +const EID_20_40_BSS_INTOLERANT_REPORT= 73; +const EID_OBSS_SCAN_PARAMETERS = 74; +const EID_FT_RIC_DESCRIPTOR = 75; +const EID_LINK_IDENTIFIER = 101; +const EID_PTI_CONTROL = 105; +const EID_PU_BUFFER_STATUS = 106; +const EID_QOS_MAP_SET = 110; +const EID_ESE_SPECIFIC = 150; +const EID_ESE_CCKM_SPECIFIC = 156; +const EID_VHT_CAPABILITIES = 191; +const EID_VHT_OPERATION_ELEMENT = 192; +const EID_VHT_EXT_BSS_LOAD = 193; +const EID_AID = 197; +const EID_EXT_CAP = 127; +const EID_OPERATING_MODE = 199; +const EID_WIDER_BW_CHANNEL_SWITCH_ANN= 194; +const EID_CHANNEL_SWITCH_WRAPPER = 196; +const EID_VENDOR_SPECIFIC = 221; + +const SIR_MAC_PROP_EXT_RATES_TYPE = 0; +const SIR_MAC_PROP_AP_NAME_TYPE = 1; +const SIR_MAC_PROP_HCF_TYPE = 2; +const SIR_MAC_PROP_WDS_TYPE = 3; +const SIR_MAC_PROP_BP_IND_TYPE = 4; +const SIR_MAC_PROP_NEIGHBOR_BSS_TYPE = 5; +const SIR_MAC_PROP_LOAD_INFO_TYPE = 6; +const SIR_MAC_PROP_ASSOC_TYPE = 7; +const SIR_MAC_PROP_LOAD_BALANCE_TYPE = 8; +const SIR_MAC_PROP_LL_ATTR_TYPE = 9; +const SIR_MAC_PROP_CAPABILITY = 10; +const SIR_MAC_PROP_VERSION = 11; +const SIR_MAC_PROP_EDCAPARAMS = 12; +const SIR_MAC_PROP_CHANNEL_SWITCH = 15; +const SIR_MAC_PROP_QUIET_BSS = 16; +const SIR_MAC_PROP_TRIG_STA_BK_SCAN = 17; + +const ANI_WDS_INFO_MAX_LENGTH = 64; +const SIR_MAC_MAX_NUMBER_OF_RATES = 12; +const HT_MAX_SUPPORTED_MCS_SET = 16; +const MAX_SUPPORTED_NEIGHBOR_RPT = 15; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Protected Setup TLV Identifiers // +// WSC Version 2.0.0 Table 28 // +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Simple Configuration TLV Identifiers // +// WFA Vendor Extension Subelements // +///////////////////////////////////////////////////////////////////////////// +const TLV_VERSION2 = 0; +const TLV_AUTHORIZED_MAC = 1; +const TLV_NETWORK_KEY_SHAREABLE = 2; +const TLV_REQUEST_TO_ENROLL = 3; +const TLV_SETTINGS_DELAY_TIME = 4; + +const TLV_VERSION = 0x104A; +const TLV_WI_FI_SIMPLE_CONFIG_STATE = 0x1044; +const TLV_AP_SETUP_LOCKED = 0x1057; +const TLV_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053; +const TLV_DEVICE_PASSWORD_ID = 0x1012; +const TLV_UUID_E = 0x1047; +const TLV_UUID_R = 0x1048; +const TLV_RF_BANDS = 0x103C; +const TLV_REQUEST_TYPE = 0x103A; +const TLV_RESPONSE_TYPE = 0x103B; +const TLV_CONFIG_METHODS = 0x1008; +const TLV_PRIMARY_DEVICE_TYPE = 0x1054; +const TLV_ASSOCIATION_STATE = 0x1002; +const TLV_CONFIGURATION_ERROR = 0x1009; +const TLV_MANUFACTURER = 0x1021; +const TLV_MODEL_NAME = 0x1023; +const TLV_MODEL_NUMBER = 0x1024; +const TLV_SERIAL_NUMBER = 0x1042; +const TLV_DEVICE_NAME = 0x1011; +const TLV_SELECTED_REGISTRAR = 0x1041; +const TLV_VENDOR_EXTENSION = 0x1049; +const TLV_REQUESTED_DEVICE_TYPE = 0x106A; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Direct/P2P TLV Identifiers // +///////////////////////////////////////////////////////////////////////////// +const TLV_P2P_STATUS = 0; +const TLV_MINOR_REASON_CODE = 1; +const TLV_P2P_CAPABILITY = 2; +const TLV_P2P_DEVICE_ID = 3; +const TLV_P2P_GROUP_OWNER_INTENT = 4; +const TLV_CONFIGURATION_TIMEOUT = 5; +const TLV_LISTEN_CHANNEL = 6; +const TLV_P2P_GROUP_BSSID = 7; +const TLV_EXTENDED_LISTEN_TIMING = 8; +const TLV_INTENDED_P2P_INTERFACE_ADDRESS = 9; +const TLV_P2P_MANAGEABILITY = 10; +const TLV_CHANNEL_LIST = 11; +const TLV_NOTICE_OF_ABSENCE = 12; +const TLV_P2P_DEVICE_INFO = 13; +const TLV_P2P_GROUP_INFO = 14; +const TLV_P2P_GROUP_ID = 15; +const TLV_P2P_INTERFACE = 16; +const TLV_OPERATING_CHANNEL = 17; +const TLV_INVITATION_FLAGS = 18; +const TLV_P2P_VENDOR_SPECIFIC = 221; + +///////////////////////////////////////////////////////////////////////////// +// Fixed Fields + +FF AuthAlgo (2) // C.f. Sec. 7.3.1.1 +{ + algo, 2; +} + +FF AuthSeqNo (2) // 7.3.1.2 +{ + no, 2; +} + +FF BeaconInterval (2) // 7.3.1.3 +{ + interval, 2; +} + +FF Capabilities (2) // 7.3.1.4 +{ + { + ess: 1; + ibss: 1; + cfPollable: 1; + cfPollReq: 1; + privacy: 1; + shortPreamble: 1; + pbcc: 1; + channelAgility: 1; + spectrumMgt: 1; + qos: 1; + shortSlotTime: 1; + apsd: 1; + rrm: 1; + dsssOfdm: 1; + delayedBA: 1; + immediateBA: 1; + } +} + +FF CurrentAPAddress(6) // 7.3.1.5 +{ + mac[6]; +} + +FF ListenInterval (2) // 7.3.1.6 +{ + interval, 2; +} + +FF Reason (2) // 7.3.1.7 +{ + code, 2; +} + +FF AID (2) // 7.3.1.8 +{ + associd, 2; +} + +FF Status (2) // 7.3.1.9 +{ + status, 2; +} + +FF TimeStamp (8) // 7.3.1.10 +{ + timestamp, 8; +} + +FF Category (1) // 7.3.1.11 +{ + category, 1; +} + +FF Action (1) // 7.3.1.11 +{ + action, 1; +} + +FF TransactionId (2) // 7.3.1.11 +{ + transId[2]; +} + +FF DialogToken (1) // 7.3.1.12 +{ + token, 1; +} + +FF StatusCode (1) // WMM Spec 2.2.10 +{ + statusCode, 1; +} + +FF OperatingMode (1) +{ + { + //Operating Mode field + chanWidth: 2; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +FF SMPowerModeSet (1) //7.3.1.25 +{ + { + PowerSave_En: 1; + Mode: 1; + reserved: 6; + } +} + +FF TSInfo (3) // 7.3.2.30 +{ + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + schedule: 1; + unused: 15; + } +} + +FF NumOfRepetitions (2) +{ + repetitions, 2; +} + +FF TxPower (1) +{ + txPower, 1; +} + +FF MaxTxPower (1) +{ + maxTxPower, 1; +} +FF TPCEleID (1) +{ + TPCId, 1; +} +FF TPCEleLen (1) +{ + TPCLen, 1; +} +FF LinkMargin (1) +{ + linkMargin, 1; +} +FF RxAntennaId (1) +{ + antennaId, 1; +} +FF TxAntennaId (1) +{ + antennaId, 1; +} +FF RCPI (1) +{ + rcpi, 1; +} +FF RSNI (1) +{ + rsni, 1; +} + +FF VhtMembershipStatusArray(8) // 8.4.1.51 +{ + membershipStatusArray[8]; +} + +FF VhtUserPositionArray(16) // 8.4.1.52 +{ + userPositionArray[16]; +} + + +///////////////////////////////////////////////////////////////////////////// +// TLVs // +///////////////////////////////////////////////////////////////////////////// + +/** + * \brief Version + * + * WPS 1.0h + * Version specifies the Easy Setup version. The one-byte field is broken + * into a four-bit major part using the top MSBs and four-bit minor part + * using the LSBs. As an example, version 3.2 would be 0x32. + * + * WSC 2.0.0 + * Deprecated Version mechanism. This attribute is always set to value 0x10 + * (version 1.0) for backwards compatibility. Version 1.0h of the specification + * did not fully describe the version negotiation mechanism and version 2.0 + * introduced a new subelement (Version2) for indicating the version number + * to avoid potential interoperability issues with deployed 1.0h-based devices. + * + */ + +TLV Version( TLV_VERSION ) ( 2 : 2 ) MSB +{ + { + minor: 4; + major: 4; + } +} + +/// Wi-Fi Protected Setup State +TLV WPSState( TLV_WI_FI_SIMPLE_CONFIG_STATE ) ( 2 : 2 ) MSB +{ + state, 1; +} + +/** + * \brief AP Setup Locked + * + * + * This variable indicates that the AP has entered a state in which it will + * refuse to allow an external Registrar to attempt to run the Registration + * Protocol using the AP?s PIN (with the AP acting as Enrollee). The AP + * should enter this state if it believes a brute force attack is underway + * against the AP?s PIN. + * + * When the AP is in this state, it MUST continue to allow other Enrollees to + * connect and run the Registration Protocol with any external Registrars or + * the AP's built-in Registrar (if any). It is only the use of the AP' PIN + * for adding external Registrars that is disabled in this state. + * + * The AP Setup Locked state can be reset to FALSE through an authenticated + * call to SetAPSettings. APs may provide other implementation-specific + * methods of resetting the AP Setup Locked state as well. + * + * + */ + +TLV APSetupLocked( TLV_AP_SETUP_LOCKED ) ( 2 : 2 ) MSB +{ + fLocked, 1; +} + +/** + * \brief Selected Registrar Config Methods + * + * + * This attribute has the same values that Config Methods have. It is used in + * Probe Response messages to convey the Config Methods of the selected + * Registrar. + * + * + */ + +TLV SelectedRegistrarConfigMethods ( TLV_SELECTED_REGISTRAR_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief UUID-E + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Enrollee. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_E ( TLV_UUID_E ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief UUID-R + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Registrar. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_R ( TLV_UUID_R ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief RF Bands + * + * + \code + + 0x01 2.4GHz + 0x02 5.0GHz + + \endcode + * + * + */ + +TLV RFBands ( TLV_RF_BANDS ) ( 2 : 2 ) MSB +{ + bands, 1; +} + + +/** + * \brief Selected Registrar + * + * + * This field indicates that a Registrar has been selected by a user and that + * an Enrollee should proceed with setting up an 802.1X uncontrolled data + * port with the Registrar. + * + * + */ + +TLV SelectedRegistrar ( TLV_SELECTED_REGISTRAR ) ( 2 : 2 ) MSB +{ + selected, 1; +} + +/** + * \brief Config Methods + * + * + * The Config Methods Data component lists the configuration methods the + * Enrollee or Registrar supports. The list is a bitwise OR of values from + * the table below. In addition to Config Methods, APs and STAs that support + * the UPnP Management Interface must support the Permitted Config Methods + * attribute, which is used to control the Config Methods that are enabled on + * that AP. + * + \code + + Value Hardware Interface + 0x0001 USBA (Flash Drive) + 0x0002 Ethernet + 0x0004 Label + 0x0008 Display + 0x0010 External NFC Token + 0x0020 Integrated NFC Token + 0x0040 NFC Interface + 0x0080 PushButton + 0x0100 Keypad + + \endcode + * + * + */ + +TLV ConfigMethods ( TLV_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief Association State + * + * + * The Association State component shows the configuration and previous + * association state of the wireless station when sending a Discovery + * request. + * + \code + + Association State Description + 0 Not Associated + 1 Connection Success + 2 Configuration Failure + 3 Association Failure + 4 IP Failure + + \endcode + * + * + */ + +TLV AssociationState ( TLV_ASSOCIATION_STATE ) ( 2 : 2 ) MSB +{ + state, 2; +} + +/** + * \brief Configuration Error + * + * + * The Configuration Error component shows the result of the device + * attempting to configure itself and to associate with the WLAN. + * + \code + + Configuration Error Description + 0 No Error + 1 OOB Interface Read Error + 2 Decryption CRC Failure + 3 2.4 channel not supported + 4 5.0 channel not supported + 5 Signal too weak + 6 Network auth failure + 7 Network association failure + 8 No DHCP response + 9 Failed DHCP config + 10 IP address conflict + 11 Couldn't connect to Registrar + 12 Multiple PBC sessions detected + 13 Rogue activity suspected + 14 Device busy + 15 Setup locked + 16 Message Timeout + 17 Registration Session Timeout + 18 Device Password Auth Failure + + \endcode + * + * The Device busy error is returned if the sending device is unable to + * respond to the request due to some internal conflict or resource + * contention issue. For example, if a device is only capable of performing a + * single instance of the Registration Protocol at a time, it may return this + * error in response to attempts to start another instance in the middle of + * an active session. + * + * + */ + +TLV ConfigurationError ( TLV_CONFIGURATION_ERROR ) ( 2 : 2 ) MSB +{ + error, 2; +} + +TLV Manufacturer ( TLV_MANUFACTURER ) ( 2 : 2 ) MSB +{ + name[ 0..64 ]; +} + +TLV ModelName ( TLV_MODEL_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV ModelNumber ( TLV_MODEL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV SerialNumber ( TLV_SERIAL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV DeviceName ( TLV_DEVICE_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +/** + * \brief Device Password ID + * + * + * This attribute is used to identify a device password. There are six + * predefined values and ten reserved values. If the Device Password ID is + * Default, the Enrollee should use its PIN password (from the label or + * display). This password may correspond to the label, display, or a + * user-defined password that has been configured to replace the original + * device password. + * + * User-specified indicates that the user has overridden the password with a + * manually selected value. Machine-specified indicates that the original + * PIN password has been overridden by a strong, machinegenerated device + * password value. The Rekey value indicates that the device's 256-bit + * rekeying password will be used. The PushButton value indicates that the + * PIN is the all-zero value reserved for the PushButton Configuration + * method. + * + * The Registrar-specified value indicates a PIN that has been obtained from + * the Registrar (via a display or other out-of-band method). This value may + * be further augmented with the optional 'Identity' attribute in M1. This + * augmentation is useful when multiple predefined UserID/PIN pairs have been + * established by a Registrar such as an authenticator used for Hotspot + * access. If the Device Password ID in M1 is not one of the predefined or + * reserved values, it corresponds to a password given to the Registrar as an + * OOB Device Password. + * + \code + + Value Description + + 0x0000 Default (PIN) + 0x0001 User-specified + 0x0002 Machine-specified + 0x0003 Rekey + 0x0004 PushButton + 0x0005 Registrar-specified + 0x0006 - 0x000F Reserved + + \endcode + * + * + */ + +TLV DevicePasswordID ( TLV_DEVICE_PASSWORD_ID ) ( 2 : 2 ) MSB +{ + id, 2; +} + + +/** + * \brief Primary Device Type + * + * + * This attribute contains the primary type of the device. Its format + * follows: + * + \code + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute ID | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Category ID | OUI (1-2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OUI (3-4) | Sub Category ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + \endcode + * + * Vendor-specific sub-categories are designated by setting the OUI to the + * value associated with that vendor. Note that a four-byte subdivided OUI + * is used. For the predefined values, the Wi-Fi Alliance OUI of 00 50 F2 04 + * is used. The predefined values for Category ID and Sub Category ID are + * provided in the next table. There is no way to indicate a vendor-specific + * main device category. The OUI applies only to the interpretation of the + * Sub Category. If a vendor does not use sub categories for their OUI, the + * three-byte OUI occupies the first three bytes of the OUI field and the + * fourth byte is set to zero. + * + * + \code + + Category ID Value Sub Category ID Value + Computer 1 PC 1 + Server 2 + Media Center 3 + Input Device 2 + Printers, Scanners, Printer 1 + Faxes and Copiers 3 Scanner 2 + Camera 4 Digital Still Camera 1 + Storage 5 NAS 1 + Network AP 1 + Infrastructure 6 Router 2 + Switch 3 + Displays 7 Television 1 + Electronic Picture Frame 2 + Projector 3 + Multimedia Devices 8 DAR 1 + PVR 2 + MCX 3 + Gaming Devices 9 Xbox 1 + Xbox360 2 + Playstation 3 + Telephone 10 Windows Mobile 1 + + \endcode + * + * + */ + +TLV PrimaryDeviceType ( TLV_PRIMARY_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + + +/** + * \brief Request Type + * + * + * The Request Type component specifies the mode in which the device will + * operate in for this setup exchange. If the device is an Enrollee, it may + * send only discovery messages or it may also request that the Registrar + * proceed with opening a data connection. This protocol allows Enrollees to + * more efficiently discover devices on the network. + + * If the device indicates that it intends to engage setup either as a + * Registrar or an Enrollee, the Access Point continues to indicate that it + * will operate as an AP in the response. The Request Type attribute is + * carried throughout the 802.1X data channel setup process in the Wi-Fi + * Protected Setup IE. There are two sub-types of Registrars: WLAN Manager + * Registrar indicates that this Registrar intends to manage the AP or STA + * settings using UPnP. It will derive a UPnP AP or STA Management key. The + * ordinary Registrar type indicates that this Registrar does not intend to + * subsequently manage the Enrollee's settings. APs must not derive AP + * Management Keys for an ordinary Registrar. If a Registrar does not intend + * to be a WLAN Manager Registrar, it should set the Request Type to + * Registrar. Doing so avoids needlessly consuming resources on the AP. + + \code + + Request Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 WLAN Manager Registrar + + \endcode + * + * + */ + +TLV RequestType ( TLV_REQUEST_TYPE ) ( 2 : 2 ) MSB +{ + reqType, 1; +} + +/** + * \brief Response Type + * + * + * The Response Type component specifies the operational mode of the + * device for this setup exchange. The Response Type IE is carried + * throughout the 802.1X data channel setup process. + + \code + + Response Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 AP + +\endcode + * + * + */ + +TLV ResponseType ( TLV_RESPONSE_TYPE ) ( 2 : 2 ) MSB +{ + resType, 1; +} + + +/////////////////////////////////////////////////////////////////////////// +// WiFi Direct/P2P TLVs // +/////////////////////////////////////////////////////////////////////////// + +/** + * \brief P2P Status Attribute + */ + +TLV P2PStatus ( TLV_P2P_STATUS ) ( 1 : 2 ) LSB +{ + status, 1; +} + + +/** + * \brief Minor Reason Code Attribute + */ + +TLV MinorReasonCode ( TLV_MINOR_REASON_CODE ) ( 1 : 2 ) LSB +{ + minorReasonCode, 1; +} + + +/** + * \brief P2P Capability Attribute + */ + +TLV P2PCapability ( TLV_P2P_CAPABILITY ) ( 1 : 2 ) LSB +{ + deviceCapability, 1; + groupCapability, 1; +} + + +/** + * \brief P2P Device Id Attribute + */ + +TLV P2PDeviceId ( TLV_P2P_DEVICE_ID ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + +/** + * \brief Listen Channel Attribute + */ + +TLV ListenChannel ( TLV_LISTEN_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + +/** + * \brief Extended Listen Attribute + */ + +TLV ExtendedListenTiming ( TLV_EXTENDED_LISTEN_TIMING ) ( 1 : 2 ) LSB +{ + availibilityPeriod, 2; + availibilityInterval, 2; +} + + +/** + * \brief P2P Manageability Attribute + */ + +TLV P2PManageability ( TLV_P2P_MANAGEABILITY ) ( 1 : 2 ) LSB +{ + manageability, 1; +} + + +/** + * \brief Notice of Absence + */ + +TLV NoticeOfAbsence ( TLV_NOTICE_OF_ABSENCE ) ( 1 : 2 ) LSB +{ + index, 1; + CTSWindowOppPS, 1; + NoADesc[0..36]; +} + +/** + * \brief P2P Device Info Attribute + */ + +TLV P2PDeviceInfo ( TLV_P2P_DEVICE_INFO ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; + configMethod, 2 , FLIPBYTEORDER; + primaryDeviceType[8]; + MANDATORYTLV DeviceName; +} + + +/** + * \brief P2P Group Info Attribute + */ + +TLV P2PGroupInfo ( TLV_P2P_GROUP_INFO ) ( 1 : 2 ) LSB +{ + P2PClientInfoDesc[0..1024]; +} + + +/** + * \brief P2P Interface Attribute + */ + +TLV P2PInterface ( TLV_P2P_INTERFACE ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + + +/** + * \brief Operating Channel Attribute + */ + +TLV OperatingChannel ( TLV_OPERATING_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + + +/** + * \brief Vendor Extension + * + * This variable permits vendor extensions in the Wi-Fi Simple + * Configuration TLV framework. The Vendor Extension figure + * illustrates the implementation of vendor extensions. Vendor + * ID is the SMI network management private enterprise code + * + * +-----------+----------------------+ + * | Vendor ID | Vendor Data | + * +-----------+----------------------+ + * |<--- 3 --->|<----- 1 - 1021 ----->| + * + */ + +TLV VendorExtension ( TLV_VENDOR_EXTENSION ) ( 2 : 2 ) MSB +{ + /* + * vendorId is the SMI network management private enterprise code. + * WFA Vendor ID 0x00372A + * + */ + vendorId[ 3 ]; + + /** + * \breif Version2 + * + * The Version2 field specifies the version Wi-Fi Simple + * Configuration implemented by the device sending this attribute. + * The one-byte field is broken into a four-bit major part using + * the top MSBs and four-bit minor part using the LSBs. As an example, + * version 3.2 would be 0x32. This subelement was added in the + * specification version 2.0 and if the subelement is not included + * in a message, the transmitter of the message is assumed to + * use version 1.0. + * + */ + OPTIONALTLV TLV Version2 ( TLV_VERSION2 ) ( 1 : 1 ) MSB + { + { + minor: 4; + major: 4; + } + } + /** + * \brief AuthorizedMACs + * + * This subelement contains a list of Enrollee MAC addresses (each + * being six bytes in length) that have been registered to start WSC. + * The AP includes this field in Beacon and Probe Response frames so + * Enrollees can tell if they have been registered to start WSC. There + * may be multiple Enrollees active on the network, but not all of them have + * been registered to start WSC. This element allows an Enrollee to detect + * if they should start WSC with the AP. The AuthorizedMACs field augments + * the use of the Selected Registrar. + * + */ + OPTIONALTLV TLV AuthorizedMACs ( TLV_AUTHORIZED_MAC ) ( 1 : 1 ) MSB + { + mac[6]; + } + + /** + * \brief Request to Enroll + * + * This optional subelement in the WSC IE in Probe Request or M1 indicates + * the desire to enroll in the network by setting its value to TRUE. If the + * Registrar gets this subelement it can use this as a trigger that a device + * wants to enroll (maybe an indication can be shown to the user). The device + * must set it to FALSE after the registration protocol completion. + * + */ + OPTIONALTLV TLV RequestToEnroll( TLV_REQUEST_TO_ENROLL ) ( 1 : 1 ) MSB + { + req, 1; + } +} + +/** + * \brief Requested Device Type + * + * This attribute contains the requested device type of a Wi-Fi + * Direct device. + * + * This attribute allows a device to specify the Primary Device Type + * or the Secondary Device Type of other devices it is interested in. + * Only a device that receives a Probe Request containing a WSC IE with + * this attribute and with a Primary Device Type or Secondary Device Type + * that matches the Requested Device Type will respond with a Probe Response. + * + * Its format and contents is identical to the 'Primary Device Type'. + * + * Both the Category ID and Sub Category ID can be used as a filter. If only + * looking for devices with a certain Category ID, the OUI and Sub Category ID + * fields will have to be set to zero. + * + */ +TLV RequestDeviceType ( TLV_REQUESTED_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + +///////////////////////////////////////////////////////////////////////////// +// Information Elements + +IE SSID (EID_SSID) // C.f. Sec. 7.3.2.1 +{ + ssid[0..32]; +} + +IE SuppRates (EID_SUPP_RATES) // 7.3.2.2 +{ + rates[0..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE FHParamSet (EID_FH_PARAM_SET) // 7.3.2.3 +{ + dwell_time, 2; + hop_set, 1; + hop_pattern, 1; + hop_index, 1; +} + +IE DSParams (EID_DS_PARAM_SET) // 7.3.2.4 +{ + curr_channel, 1; +} + +IE CFParams (EID_CF_PARAM_SET) // 7.3.2.5 +{ + cfp_count, 1; + cfp_period, 1; + cfp_maxduration, 2; + cfp_durremaining, 2; +} + +IE TIM (EID_TIM) // 7.3.2.6 +{ + dtim_count, 1; + dtim_period, 1; + bmpctl, 1; + vbmp[1..251]; +} + +IE IBSSParams (EID_IBSS_PARAM_SET) // 7.3.2.7 +{ + atim, 2; +} + +IE ChallengeText (EID_CHALLENGE_TEXT) // 7.3.2.8 +{ + text[1..253]; +} + +IE RequestedInfo (EID_REQUEST) // 7.3.2.12 +{ + requested_eids[0..255]; +} + +IE Country (EID_COUNTRY) // 7.3.2.9 +{ + country[3]; + OPTIONAL triplets[3][0..84]; +} + +IE FHParams (EID_FH_PATTERN) // 7.3.2.10 +{ + radix, 1; + nchannels, 1; +} + +IE FHPattTable (EID_FH_PATT_TABLE) // 7.3.2.11 +{ + flag, 1; + nsets, 1; + modulus, 1; + offset, 1; + randtable[0..251]; +} + +IE ERPInfo (EID_ERP_INFO) // 7.3.2.13 +{ + { + non_erp_present : 1; + use_prot: 1; + barker_preamble: 1; + unused: 5; + } +} + +IE ExtSuppRates (EID_EXT_SUPP_RATES) // 7.3.2.14 +{ + rates[1..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE PowerConstraints (EID_POWER_CONSTRAINTS) // 7.3.2.15 +{ + localPowerConstraints, 1; +} + +IE PowerCaps (EID_POWER_CAPABILITY) // 7.3.2.16 +{ + minTxPower, 1; + maxTxPower, 1; +} + +IE TPCRequest (EID_TPC_REQUEST) // 7.3.2.17 +{ } + +IE TPCReport (EID_TPC_REPORT) // 7.3.2.18 +{ + tx_power, 1; + link_margin, 1; +} + +IE SuppChannels (EID_SUPPORTED_CHANNELS) // 7.2.3.19 +{ + bands[2][1..48]; +} + +IE SuppOperatingClasses (EID_SUPPORTED_OPER_CLASSES) +{ + classes[1..32]; +} + +IE ChanSwitchAnn (EID_CHANNEL_SWITCH_ANN) // 7.3.2.20 +{ + switchMode, 1; + newChannel, 1; + switchCount, 1; +} + +IE ext_chan_switch_ann (EID_EXT_CHAN_SWITCH) // 8.4.2.55 +{ + switch_mode, 1; + new_reg_class, 1; + new_channel, 1; + switch_count, 1; +} + +IE sec_chan_offset_ele (EID_SEC_CHAN_OFFSET) // 7.3.2.20a +{ + secondaryChannelOffset, 1; +} + +IE Quiet (EID_QUIET) // 7.3.2.23 +{ + count, 1; + period, 1; + duration, 2; + offset, 2; +} + +IE RSN (EID_RSN) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // The next four octets will be the Group Cipher Suite + gp_cipher_suite[4]; + // The IE *may* stop here; if there's any more, we should see two more + // octets giving the number of Pairwise Cipher Suites + OPTIONAL pwise_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + pwise_cipher_suites[4][0..4] COUNTIS pwise_cipher_suite_count; + // Optional count of AKM suite selectors + OPTIONAL akm_suite_count, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suites[4][0..4] COUNTIS akm_suite_count; + OPTIONAL RSN_Cap[2]; + // Finally, the IE may contain zero or more PMKIDs: + OPTIONAL pmkid_count, 2; + pmkid[16][0..4] COUNTIS pmkid_count; + OPTIONAL gp_mgmt_cipher_suite[4]; +} + +IE RSNOpaque (EID_RSN) // 7.3.2.25 +{ + data[ 6..253 ]; +} + +IE WAPI (EID_WAPI) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // count of AKM suite selectors + akm_suite_count, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suites[4][0..4] COUNTIS akm_suite_count; + // we should see two more + // octets giving the number of Unicast Cipher Suites + unicast_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + unicast_cipher_suites[4][0..4] COUNTIS unicast_cipher_suite_count; + // The next four octets will be the Multicast Cipher Suite + multicast_cipher_suite[4]; + // WAPI capabilities + { + preauth: 1; + reserved: 15; + } + // Finally, the IE may contain zero or more BKIDs: + OPTIONAL bkid_count, 2; + bkid[16][0..4] COUNTIS bkid_count; +} + +IE WAPIOpaque (EID_WAPI) // 7.3.2.25 +{ + data[ 6..253 ]; +} + +IE QBSSLoad (EID_QBSS_LOAD) // 7.3.2.28 +{ + stacount, 2; + chautil, 1; + avail, 2; +} + +IE EDCAParamSet (EID_EDCA_PARAM_SET) // 7.3.2.29 +{ + qos, 1; // ToDo: This is a bitfield whose format + // depends on whether this is from an AP + // or a STA, information which I'm not + // sure we have at parse time... + reserved, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE TSPEC (EID_TSPEC) // 7.3.2.30 +{ + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + schedule: 1; + unused: 7; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE TSPEC. + +IE TCLAS (EID_TCLAS) // 7.3.2.31 +{ + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; +} // End IE TCLASS + +const EID_RRM_BEACON_REPORTING = 1; +const EID_RRM_BCN_REPORTING_DETAIL = 2; + +IE BeaconReporting (EID_RRM_BEACON_REPORTING) +{ + reportingCondition, 1; + threshold, 1; +} + +IE BcnReportingDetail (EID_RRM_BCN_REPORTING_DETAIL) +{ + reportingDetail, 1; +} + +IE APChannelReport (EID_AP_CHAN_REPORT) +{ + regulatoryClass, 1; + channelList[0..50]; +} + +IE MeasurementRequest (EID_MEAS_REQUEST) // 7.3.2.21 +{ + measurement_token, 1; + + // Measurement Request Mode + { + parallel: 1; + enable: 1; + request: 1; + report: 1; + durationMandatory: 1; + unused: 3; + } + + measurement_type, 1; + UNION measurement_request (DISCRIMINATOR measurement_type) + { + Basic (measurement_type IS 0) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + CCA (measurement_type IS 1) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + RPIHistogram (measurement_type IS 2) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + Beacon (measurement_type IS 5) + { + regClass, 1; + channel, 1; + randomization, 2; + meas_duration, 2; + meas_mode, 1; + BSSID[6]; + OPTIE SSID; + OPTIE BeaconReporting; + OPTIE BcnReportingDetail; + OPTIE RequestedInfo; + OPTIE APChannelReport[0..2]; + //OPTIONAL vendor_specific[1..239]; + } + + }; +} + +const EID_BCN_REPORT_FRAME_BODY = 1; +IE BeaconReportFrmBody (EID_BCN_REPORT_FRAME_BODY) +{ + reportedFields[0..224]; +} + +IE MeasurementReport (EID_MEAS_REPORT) // 7.3.2.22 +{ + token, 1; + // Measurement Report Mode + { + late: 1; + incapable: 1; + refused: 1; + unused: 5; + } + type, 1; + OPTIONAL UNION report (DISCRIMINATOR type) + { + Basic (type IS 0) // 7.3.2.22.1 + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // Map + { + bss: 1; + ofdm_preamble: 1; + unid_signal: 1; + rader: 1; + unmeasured: 1; + unused: 3; + } + } + CCA (type IS 1) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + cca_busy_fraction, 1; + } + RPIHistogram (type IS 2) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + rpi0_density, 1; + rpi1_density, 1; + rpi2_density, 1; + rpi3_density, 1; + rpi4_density, 1; + rpi5_density, 1; + rpi6_density, 1; + rpi7_density, 1; + } + Beacon (type IS 5) + { + regClass, 1; + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // reported_frame_info, + { + condensed_PHY: 7; + reported_frame_type: 1; + } + RCPI, 1; + RSNI, 1; + BSSID[6]; + antenna_id, 1; + parent_TSF, 4; + OPTIE BeaconReportFrmBody; + //IE vendor_specific + } + }; +} + +IE TSDelay (EID_TS_DELAY) // 7.3.2.32 +{ + delay, 4; +} + +IE TCLASSPROC (EID_TCLASS_PROC) // 7.3.2.33 +{ + processing, 1; +} + +IE Schedule (EID_SCHEDULE) // 7.3.2.34 +{ + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE QOSCapsAp (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + count: 4; + qack: 1; + qreq: 1; + txopreq: 1; + reserved: 1; + } +} + +IE QOSCapsStation (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + qack: 1; + max_sp_length: 2; + more_data_ack: 1; + } +} + +IE LinkIdentifier (EID_LINK_IDENTIFIER) // 7.3.2.62 +{ + bssid[6]; + InitStaAddr[6]; + RespStaAddr[6]; +} + +IE WPA (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + // This IE's first two octets should be interpreted as a version number; + // we only support version 1. + version, 2 MUSTBE 1; + // A four-octet Multicast Cipher may or may not appear next (hence the + // OPTIONAL keyword) + OPTIONAL multicast_cipher[4]; + // Optional Unicast Cipher count + OPTIONAL unicast_cipher_count, 2; + // Next comes an array of four-octet Cipher Suite selectors; the COUNTIS + // clause indicates that the actual number of selectors seen is in the + // member 'unicast_cipher_count'. + unicast_ciphers[4][0..4] COUNTIS unicast_cipher_count; + // (Optional) Authentication suites: + OPTIONAL auth_suite_count, 2; + auth_suites[4][0..4] COUNTIS auth_suite_count; + // This field is declared optional as per bugs 15234, 14755, & 14991. + OPTIONAL caps, 2; +} + +IE WPAOpaque (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + data[ 2..249 ]; +} + +IE WMMInfoStation (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM Station + version, 1; + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + reserved1: 1; + max_sp_length: 2; + reserved2: 1; + } +} + +IE WMMInfoAp (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM AP + version, 1; + { + param_set_count: 4; + reserved: 3; + uapsd: 1; + } +} + + +IE WMMParams (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x01) +{ + version, 1 MUSTBE 1; + qosInfo, 1; // ToDo: This is actually a + // bitfield, but it's format + // varies depending on whether + // the sender is a STA or AP... + reserved2, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE WMMTSPEC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xf2, 0x02, 0x02) +{ + version, 1 MUSTBE 1; + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + tsinfo_rsvd: 7; + burst_size_defn: 1; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE WMMTSpec. + +IE WMMCaps (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x05) +{ + version, 1 MUSTBE 1; + { + reserved: 4; + qack: 1; + queue_request: 1; + txop_request: 1; + more_ack: 1; + } +} + +IE WMMTCLAS (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x06) +{ + version, 1 MUSTBE 1; + + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; + +} + +IE WMMTCLASPROC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x07) +{ + version, 1 MUSTBE 1; + processing, 1; +} + +IE WMMTSDelay (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x08) +{ + version, 1 MUSTBE 1; + delay, 4; +} + +IE WMMSchedule (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x09) +{ + version, 1 MUSTBE 1; + + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE ESERadMgmtCap (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x01) +{ + + mgmt_state, 1; + + { + mbssid_mask: 3; + reserved: 5; + } + +} + +IE Vendor1IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x10, 0x18) +{ +} + +IE Vendor3IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x16, 0x32) +{ +} + +IE QComVendorIE (EID_VENDOR_SPECIFIC) OUI (0x00, 0xA0, 0xC6) +{ + type, 1; + channel, 1; +} + +IE ESETrafStrmMet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x07) +{ + tsid, 1; + state, 1; + msmt_interval, 2; +} + +IE ESETrafStrmRateSet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x08) +{ + tsid, 1; + tsrates[0..8]; +} + +IE ESEVersion (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x03) +{ + version, 1; +} + +IE ESETxmitPower (EID_ESE_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + power_limit, 1; + reserved, 1; +} + +IE ESECckmOpaque (EID_ESE_CCKM_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + data[ 6..20 ]; +} + +IE RRMEnabledCap (EID_RRM_ENABLED_CAPS) +{ + //Capability bitmap + { + LinkMeasurement: 1; + NeighborRpt: 1; + parallel: 1; + repeated: 1; + BeaconPassive: 1; + BeaconActive: 1; + BeaconTable: 1; + BeaconRepCond: 1; + } + { + FrameMeasurement: 1; + ChannelLoad: 1; + NoiseHistogram: 1; + statistics: 1; + LCIMeasurement: 1; + LCIAzimuth: 1; + TCMCapability: 1; + triggeredTCM: 1; + } + { + APChanReport: 1; + RRMMIBEnabled: 1; + operatingChanMax: 3; + nonOperatinChanMax: 3; + } + { + MeasurementPilot: 3; + MeasurementPilotEnabled: 1; + NeighborTSFOffset: 1; + RCPIMeasurement: 1; + RSNIMeasurement: 1; + BssAvgAccessDelay: 1; + } + { + BSSAvailAdmission: 1; + AntennaInformation: 1; + fine_time_meas_rpt: 1; + lci_capability: 1; + reserved: 4; + } +} + +IE MeasurementPilot (EID_RRM_MEAS_PILOT_TX_INFO) +{ + measurementPilot, 1; + vendorSpecific[0..255]; //Should be an IE. But currently only one level of nesting allowed. Can ignore for now. +} + +IE MultiBssid (EID_MULTIPLE_BSSID) +{ + maxBSSIDIndicator, 1; + vendorSpecific[0..255]; +} + +IE OBSSScanParameters (EID_OBSS_SCAN_PARAMETERS) +{ + obssScanPassiveDwell, 2; + obssScanActiveDwell, 2; + bssChannelWidthTriggerScanInterval, 2; + obssScanPassiveTotalPerChannel, 2; + obssScanActiveTotalPerChannel, 2; + bssWidthChannelTransitionDelayFactor, 2; + obssScanActivityThreshold, 2; +} + +IE ht2040_bss_coexistence (EID_20_40_BSS_COEXISTENCE) +{ + // 20/40 BSS Coexistence Information + { + info_request: 1; + forty_mhz_intolerant: 1; + twenty_mhz_bsswidth_req: 1; + obss_scan_exemption_req: 1; + obss_scan_exemption_grant: 1; + unused: 3; + } +} + +IE ht2040_bss_intolerant_report (EID_20_40_BSS_INTOLERANT_REPORT) +{ + operating_class, 1; + channel_list[0..50]; +} + +const EID_RRM_NBR_RPT_TSF = 1; +const EID_RRM_NBR_CD_COUNTRY = 2; +const EID_RRM_NBR_MSMT_PILOT_TX_INFO = 66; + +IE NeighborReport (EID_NEIGHBOR_REPORT) +{ + bssid[6]; + //Bssid Info + { + APReachability: 2; + Security: 1; + KeyScope: 1; + //Capabilities + SpecMgmtCap: 1; + QosCap: 1; + apsd: 1; + rrm: 1; + } + //Capabilities contd. + { + DelayedBA: 1; + ImmBA: 1; + //Capabilities end. + MobilityDomain: 1; + reserved: 5; + } + + reserved1, 2; //part of BSSID Info. + + regulatoryClass, 1; + channel, 1; + PhyType, 1; + OPTIE IE TSFInfo (EID_RRM_NBR_RPT_TSF) + { + TsfOffset, 2; + BeaconIntvl, 2; + } + OPTIE IE CondensedCountryStr (EID_RRM_NBR_CD_COUNTRY) + { + countryStr[2]; + } + OPTIE IE MeasurementPilot; // (EID_RRM_NBR_MSMT_PILOT_TX_INFO) +// { +// measurementPilot, 1; +// vendorSpecific[0..255]; //Should be an IE. But currently only one level of nesting allowed. Can ignore for now. +// } + OPTIE IE RRMEnabledCap; + OPTIE IE MultiBssid; + //Ignoring vendor specific. +} + +IE RCPIIE (EID_RCPI) +{ + rcpi, 1; +} + +IE RSNIIE (EID_RSNI) +{ + rsni, 1; +} + +IE WFATPC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x08, 0x00) +{ + txPower, 1; + linkMargin, 1; +} + +IE MobilityDomain (EID_FT_MOBILITY_DOMAIN) +{ + MDID, 2; + //FT Capability and policy + { + overDSCap: 1; + resourceReqCap: 1; + reserved: 6; + } +} +const SUB_EID_FT_R1KH_ID = 1; +const SUB_EID_FT_GTK = 2; +const SUB_EID_FT_R0KH_ID = 3; +const SUB_EID_FT_IGTK = 4; +IE FTInfo (EID_FT_INFO) +{ + // MicControl, 2; + { + reserved: 8; + IECount: 8; + } + MIC[16]; + Anonce[32]; + Snonce[32]; + + OPTIE IE R1KH_ID (SUB_EID_FT_R1KH_ID) + { + PMK_R1_ID[6]; + } + + OPTIE IE GTK (SUB_EID_FT_GTK) + { + //Key Info + { + keyId: 2; + reserved: 14; + } + keyLength, 1; + RSC[8]; + key[5..32]; + } + + OPTIE IE R0KH_ID (SUB_EID_FT_R0KH_ID) + { + PMK_R0_ID[1..48]; + } + + OPTIE IE IGTK (SUB_EID_FT_IGTK) + { + //Key Info + keyID[2]; + IPN[6]; + keyLength, 1; + key[24]; + } +} + +IE TimeoutInterval (EID_TIMEOUT_INTERVAL) +{ + timeoutType, 1; + timeoutValue, 4; +} + +//TODO: need to define this properly. +IE RICData (EID_FT_RIC_DATA) +{ + Identifier, 1; + resourceDescCount, 1; + statusCode, 2; +} + +IE RICDescriptor (EID_FT_RIC_DESCRIPTOR) +{ + resourceType, 1; + variableData[0..255]; //Block ack param set...TODO: +} + +IE WscIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x00, 0x50, 0xF2, 0x04 ) +{ + data[ 2..249 ]; +} + +IE P2PIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x09 ) +{ + data[ 2..249 ]; +} + +IE WFDIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x0A ) +{ + data[ 2..249 ]; +} + +IE PTIControl (EID_PTI_CONTROL) // 7.3.2.65 +{ + tid, 1; + sequence_control, 2; +} + +IE PUBufferStatus (EID_PU_BUFFER_STATUS) // 7.3.2.66 +{ + { + ac_bk_traffic_aval: 1; + ac_be_traffic_aval: 1; + ac_vi_traffic_aval: 1; + ac_vo_traffic_aval: 1; + reserved: 4; + } +} + + + +IE VHTCaps (EID_VHT_CAPABILITIES) +{ + //VHT Capability Info + { + maxMPDULen: 2; + supportedChannelWidthSet: 2; + ldpcCodingCap: 1; + shortGI80MHz: 1; + shortGI160and80plus80MHz: 1; + txSTBC: 1; + rxSTBC: 3; + suBeamFormerCap: 1; + suBeamformeeCap: 1; + csnofBeamformerAntSup: 3; + numSoundingDim: 3; + muBeamformerCap: 1; + muBeamformeeCap: 1; + vhtTXOPPS: 1; + htcVHTCap: 1; + maxAMPDULenExp: 3; + vhtLinkAdaptCap: 2; + rxAntPattern: 1; + txAntPattern: 1; + reserved1: 2; + } + rxMCSMap, 2; + { + rxHighSupDataRate: 13; + reserved2: 3; + } + txMCSMap, 2; + { + txSupDataRate: 13; + reserved3: 3; + } +} + +IE VHTOperation (EID_VHT_OPERATION_ELEMENT) +{ + chanWidth, 1; + chanCenterFreqSeg1, 1; + chanCenterFreqSeg2, 1; + basicMCSSet, 2; +} + +IE VHTExtBssLoad (EID_VHT_EXT_BSS_LOAD) +{ + muMIMOCapStaCount, 1; + ssUnderUtil, 1; + FortyMHzUtil, 1; + EightyMHzUtil, 1; + OneSixtyMHzUtil, 1; +} + +IE AID (EID_AID) +{ + assocId, 2; +} + +IE WiderBWChanSwitchAnn (EID_WIDER_BW_CHANNEL_SWITCH_ANN) +{ + newChanWidth, 1; + newCenterChanFreq0, 1; + newCenterChanFreq1, 1; +} + +IE ChannelSwitchWrapper (EID_CHANNEL_SWITCH_WRAPPER) +{ + OPTIE IE WiderBWChanSwitchAnn; +} +IE ExtCap (EID_EXT_CAP) +{ + bytes[8..9]; +} + +IE HTCaps (EID_HT_CAPABILITIES) +{ + // HT Capability Info + { + advCodingCap: 1; + supportedChannelWidthSet: 1; + mimoPowerSave: 2; + greenField: 1; + shortGI20MHz: 1; + shortGI40MHz: 1; + txSTBC: 1; + rxSTBC: 2; + delayedBA: 1; + maximalAMSDUsize: 1; + dsssCckMode40MHz: 1; + psmp: 1; + stbcControlFrame: 1; + lsigTXOPProtection: 1; + } + // HT Parameters Info; + { + maxRxAMPDUFactor: 2; + mpduDensity: 3; + reserved1: 3; + } + + supportedMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + // Extended HT Capability Info + { + pco: 1; + transitionTime: 2; + reserved2: 5; + mcsFeedback: 2; + reserved3: 6; + } + // TXBF Capability Info + { + txBF: 1; + rxStaggeredSounding: 1; + txStaggeredSounding: 1; + rxZLF: 1; + txZLF: 1; + implicitTxBF: 1; + calibration: 2; + explicitCSITxBF: 1; + explicitUncompressedSteeringMatrix: 1; + explicitBFCSIFeedback: 3; + explicitUncompressedSteeringMatrixFeedback: 3; + explicitCompressedSteeringMatrixFeedback: 3; + csiNumBFAntennae: 2; + uncompressedSteeringMatrixBFAntennae: 2; + compressedSteeringMatrixBFAntennae: 2; + reserved4: 7; + } + // AS Capability Info + { + antennaSelection: 1; + explicitCSIFeedbackTx: 1; + antennaIndicesFeedbackTx: 1; + explicitCSIFeedback: 1; + antennaIndicesFeedback: 1; + rxAS: 1; + txSoundingPPDUs: 1; + reserved5: 1; + } + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTCaps. + +IE HTInfo (EID_HT_INFO) +{ + primaryChannel, 1; + + // ahtInfoField1 + { + secondaryChannelOffset: 2; + recommendedTxWidthSet: 1; + rifsMode: 1; + controlledAccessOnly: 1; + serviceIntervalGranularity: 3; + } + + // ahtInfoField2 + + + // ahtInfoField2 + { + opMode: 2; + nonGFDevicesPresent: 1; + transmitBurstLimit: 1; + obssNonHTStaPresent:1; + reserved: 11; + } + + + // ahtInfoField3 + { + basicSTBCMCS: 7; + dualCTSProtection: 1; + secondaryBeacon: 1; + lsigTXOPProtectionFullSupport: 1; + pcoActive: 1; + pcoPhase: 1; + reserved2: 4; + } + + basicMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTInfo. + + +IE OperatingMode (EID_OPERATING_MODE) +{ + { //Operating Mode field + chanWidth: 2; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +IE QosMapSet (EID_QOS_MAP_SET) +{ + dscp_exceptions[0..60]; +} + +CONTAINERIE RICDataDesc +{ + MANDIE RICData; + OPTIE RICDescriptor; + OPTIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE TSDelay; + OPTIE Schedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE WMMTSDelay; + OPTIE WMMSchedule; +} + +IE TimeAdvertisement (EID_TIME_ADVERTISEMENT) // 8.4.2.63 +{ + timing_capabilities, 1; + time_value[10]; + time_error[5]; +} + +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE WSC ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // Must be 0x10 + OPTIONALTLV WPSState; + OPTIONALTLV APSetupLocked; + OPTIONALTLV SelectedRegistrarConfigMethods; + OPTIONALTLV UUID_E; + OPTIONALTLV UUID_R; + OPTIONALTLV RFBands; + OPTIONALTLV SelectedRegistrar; + OPTIONALTLV ConfigMethods; + OPTIONALTLV AssociationState; + OPTIONALTLV ConfigurationError; + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV DeviceName; + OPTIONALTLV DevicePasswordID; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV RequestType; + OPTIONALTLV ResponseType; + OPTIONALTLV VendorExtension; + OPTIONALTLV RequestDeviceType; +} + +MULTIIE WscBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV UUID_E; // The AP's UUID is provided + // only when the AP is a + // dual-band AP in push + // button mode and + // indicating push button + // mode on both radios + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // End Multi-IE WscBeacon. + +MULTIIE WscAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocReq. + + +MULTIIE WscAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocRes. + +MULTIIE WscReassocRes ( 221 ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscReassocRes + +MULTIIE WscProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + MANDATORYTLV ConfigMethods; // Configuration methods the + // Enrollee or Registrar + // supports + MANDATORYTLV UUID_E; // unique GUID generated by + // the Enrollee. + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV RFBands; // Specific RF bands used + // for this message + MANDATORYTLV AssociationState; // Configuration and previous + // association state + MANDATORYTLV ConfigurationError; + MANDATORYTLV DevicePasswordID; + + // WSC 2.0 + OPTIONALTLV Manufacturer; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelNumber; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV DeviceName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV VendorExtension; // Version2 and RequestToEntroll + + OPTIONALTLV RequestDeviceType; // When a device receives a Probe + // Request containing this type, + // It will only reponse if Primary + // or Secondary Device Type matches. + +} // End Multi-IE WscProbeReq. + +MULTIIE WscProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + MANDATORYTLV ResponseType; + MANDATORYTLV UUID_E; // unique identifier of AP + MANDATORYTLV Manufacturer; + MANDATORYTLV ModelName; + MANDATORYTLV ModelNumber; + MANDATORYTLV SerialNumber; + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV DeviceName; // User-friendly description + // of device + MANDATORYTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. + +// This MULTIIE combines the fields from the WSC IEs as they appear in +// Beacons *and* in Probe Responses, with the difference that they're all +// optional. In our device drivers, we combine Probe Responses and Beacons +// into one list, and parse their IEs later (c.f. frame BeaconIEs). Because +// the WSC IE differs in those two frames, we'd often see warning messages +// about either unexpected fields showing up (if we thought we were parsing a +// Beacon, and we in fact had data from a Probe Response) or mandatory fields +// missing (if we thought we were parsing a Probe Response, and in fact had +// data from a Beacon). + +// I created this MULTIIE to stuff into the BeaconIEs frames to avoid this. +// It's intended to be used on unpack only, and to do so in a very forgiving +// way. + +MULTIIE WscBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + OPTIONALTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + OPTIONALTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV ResponseType; + OPTIONALTLV UUID_E; // unique identifier of AP + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV DeviceName; // User-friendly description + // of device + OPTIONALTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE P2PBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + MANDATORYTLV P2PDeviceId; // Contains P2P Device + // Address + OPTIONALTLV NoticeOfAbsence; // Indicates Notice of + // Absence schedule and + // CT Window + +} // End P2PBeacon + + +MULTIIE P2PAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + OPTIONALTLV ExtendedListenTiming; + MANDATORYTLV P2PDeviceInfo; + +} // End P2PAssocReq + + +MULTIIE P2PAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PStatus; + OPTIONALTLV ExtendedListenTiming; + +} // End P2PAssocRes + + +MULTIIE P2PProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + MANDATORYTLV ListenChannel; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV OperatingChannel; +} // End P2PProbeReq + + +MULTIIE P2PProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + MANDATORYTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PProbeRes + + +MULTIIE P2PBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + OPTIONALTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + OPTIONALTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PBeaconProbeRes + + +MULTIIE P2PDeAuth ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + + +MULTIIE P2PDisAssoc ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + +IE vendor2_ie (EID_VENDOR_SPECIFIC) OUI (0x00, 0x90, 0x4c) +{ + type, 1; + sub_type, 1; + OPTIE IE VHTCaps; + OPTIE IE VHTOperation; +} + +///////////////////////////////////////////////////////////////////////////// +// Frames + +FRAME Beacon // C.f. Sec. 7.2.3.1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeacon; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor2_ie; + OPTIE Vendor3IE; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; +} // End frame Beacon. + +// Ok, here's the story on Beacon1 & Beacon2. We presumably beacon a lot +// more than we change configuration. So it makes sense to keep the beacon +// we plan to send next in serialized format. We do this in struct schMisc. +// Whenever our config changes in a way that would affect our beacons, we +// just update our internal datastructures & re-generate the serialized +// beacon. + +// The problem is that there are *some* fields that need to be updated at +// send time, specifically the CF Param Set & the TIM. So, what we do is +// this: whenever our config changes, call schSetFixedBeaconFields. There, +// we serialize the following Beacon fields into gSchBeaconFrameBegin (after +// the power template & MAC header): TimeStamp, BeaconInterval, Capabilities, +// SSID, SuppRates, DSParams, & IBSSParams. It sets gSchBeaconOffsetBegin to +// the length of this buffer (incl. power template & MAC header). + +// Next, it serializes the following fields into gSchBeaconFrameEnd: Country, +// EDCAParamSet, PowerConstraints, TPCReport, ChannelSwitchAnn, Quiet, +// ERPInfo, HTCaps, HTInfo, ExtSuppRates, WPA, RSN, WMMInfo, +// WMMParams, WMMCaps. +// The length of *this* buffer is kept in gSchBeaconOffsetEnd. + +// Then, in 'schBeaconInterruptHandler', we write CFParams & TIM at the end +// of gSchBeaconFrameBegin, keeping track of the (new) size of this buffer in +// the local 'beaconSize'. + +// After that, we call 'specialBeaconProcessing'. Note that this may +// actually call schSetFixedBeaconFields repeatedly! The comments say they +// try to avoid this, but... + +// Finally, we call writeBeaconToTFP, where the first thing we do is copy the +// gSchBeaconFrameEnd buffer after the end of gSchBeaconFrameBegin. + +FRAME Beacon1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE DSParams; + OPTIE IBSSParams; +} + +FRAME Beacon2 +{ + OPTIE Country; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE EDCAParamSet; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WscBeacon; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor2_ie; + OPTIE Vendor3IE; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; +} + +// This frame is just Beacon with its Fixed Fields stripped out. It's handy +// for use with struct 'tSirBssDescription', which has members corresponding +// to some fixed fields, but keeps its IEs in un-parsed format. + +// Note that it also includes the IE 'WscBeaconProbeRes'. + +FRAME BeaconIEs +{ + + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeaconProbeRes; + OPTIE P2PBeaconProbeRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor2_ie; + OPTIE Vendor3IE; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; +} // End frame BeaconIEs. + +FRAME Disassociation // 7.3.3.3 +{ + FF Reason; + OPTIE P2PDisAssoc; +} + +FRAME AssocRequest // 7.2.3.4 +{ + FF Capabilities; + FF ListenInterval; + MANDIE SSID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE RSNOpaque; + OPTIE QOSCapsStation; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPAOpaque; + OPTIE HTCaps; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE QosMapSet; + OPTIE vendor2_ie; +} // End frame AssocRequest. + +FRAME AssocResponse // 7.2.3.5 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE WscAssocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE vendor2_ie; +} // End frame AssocResponse. + +FRAME ReAssocRequest // 7.2.3.6 +{ + FF Capabilities; + FF ListenInterval; + FF CurrentAPAddress; + MANDIE SSID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE RSNOpaque; + OPTIE QOSCapsStation; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPAOpaque; + OPTIE HTCaps; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE ESECckmOpaque; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE QosMapSet; + OPTIE vendor2_ie; +} // End frame ReAssocRequest. + +FRAME ReAssocResponse // 7.2.3.7 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE WscReassocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE vendor2_ie; +} // End frame ReAssocResponse. + +FRAME ProbeRequest // 7.2.3.8 +{ + MANDIE SSID; + MANDIE SuppRates; + OPTIE RequestedInfo; + OPTIE ExtSuppRates; + OPTIE DSParams; + OPTIE HTCaps; + OPTIE WscProbeReq; + OPTIE WFATPC; + OPTIE P2PProbeReq; + OPTIE VHTCaps; + OPTIE ExtCap; +} // End frame ProbeRequest. + +FRAME ProbeResponse // 7.2.3.9 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE RRMEnabledCap; + OPTIE APChannelReport; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscProbeRes; + OPTIE P2PProbeRes; + + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor2_ie; + OPTIE Vendor3IE; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; +} // End frame ProbeResponse. + +FRAME Authentication // 7.2.3.10 +{ + FF AuthAlgo; + FF AuthSeqNo; + FF Status; + OPTIE ChallengeText; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICDataDesc[2]; +} // End frame Auth. + +FRAME DeAuth // 7.2.3.11 +{ + FF Reason; + OPTIE P2PDeAuth; +} + +FRAME AddTSRequest // 7.4.2.1 +{ + + FF Category; + FF Action; + FF DialogToken; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmRateSet; + +} // End frame AddTSRequest. + +FRAME WMMAddTSRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; + OPTIE ESETrafStrmRateSet; +} // End Frame WMMAddTSRequest + +FRAME AddTSResponse // 7.4.2.2 +{ + + FF Category; + FF Action; + FF DialogToken; + FF Status; + MANDIE TSDelay; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE Schedule; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + OPTIE WMMTSDelay; + OPTIE WMMSchedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmMet; + +} // End frame AddTSResponse. + +FRAME WMMAddTSResponse +{ + + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + OPTIE WMMTSPEC; + OPTIE ESETrafStrmMet; + +} // End frame WMMAddTSResponse. + +FRAME DelTS // 7.4.2.3 +{ + FF Category; + FF Action; + FF TSInfo; + FF Reason; +} + +FRAME WMMDelTS +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; +} + +FRAME TPCRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCRequest; +} + +FRAME TPCReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCReport; +} + +FRAME ChannelSwitch +{ + FF Category; + FF Action; + MANDIE ChanSwitchAnn; + OPTIE sec_chan_offset_ele; + OPTIE WiderBWChanSwitchAnn; +} + +FRAME MeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementRequest[1..4]; +} + +FRAME MeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementReport; +} + +FRAME SMPowerSave +{ + FF Category; + FF Action; + FF SMPowerModeSet; +} + +FRAME RadioMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF NumOfRepetitions; + //Measurement Request IE. + MANDIE MeasurementRequest[1..2]; +} + +FRAME RadioMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + //Measurement Report elements. + MANDIE MeasurementReport[1..4]; +} + +FRAME LinkMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF TxPower; + FF MaxTxPower; + //Optional Sub Ies +} + +FRAME LinkMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + FF TPCEleID; + FF TPCEleLen; + FF TxPower; + FF LinkMargin; + FF RxAntennaId; + FF TxAntennaId; + FF RCPI; + FF RSNI; + //Optional Vendor specific IEs ... ignoring +} + +FRAME NeighborReportRequest +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE SSID; + //Optional vendor specific IE...ignoring. +} + +FRAME NeighborReportResponse +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE NeighborReport[1..MAX_SUPPORTED_NEIGHBOR_RPT]; +} + +FRAME OperatingMode +{ + FF Category; + FF Action; + //Operating Mode field + FF OperatingMode; +} + +FRAME TDLSDisReq +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME TDLSDisRsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE SuppOperatingClasses; + OPTIE RSN; + OPTIE ExtCap; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE VHTCaps; +} + +FRAME TDLSSetupReq +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; +} + +FRAME TDLSSetupRsp +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + FF Capabilities ; + OPTIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + OPTIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; + OPTIE OperatingMode; +} + +FRAME TDLSSetupCnf +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + OPTIE RSN; + OPTIE EDCAParamSet; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE HTInfo; + OPTIE LinkIdentifier; + OPTIE WMMParams; + OPTIE VHTOperation; + OPTIE OperatingMode; +} +FRAME TDLSTeardown +{ + FF Category; + FF Action; + FF Reason; + OPTIE FTInfo; + MANDIE LinkIdentifier; +} + +FRAME TDLSPeerTrafficInd +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; + OPTIE PTIControl; + MANDIE PUBufferStatus; +} + +FRAME TDLSPeerTrafficRsp +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME SaQueryReq +{ + FF Category; + FF Action; + FF TransactionId; +} + +FRAME SaQueryRsp +{ + FF Category; + FF Action; + FF TransactionId; +} + +FRAME QosMapConfigure +{ + FF Category; + FF Action; + MANDIE QosMapSet; +} + +FRAME VHTGidManagementActionFrame +{ + FF Category; + FF Action; + FF VhtMembershipStatusArray; + FF VhtUserPositionArray; +} + +FRAME ht2040_bss_coexistence_mgmt_action_frame +{ + FF Category; + FF Action; + MANDIE ht2040_bss_coexistence; + MANDIE ht2040_bss_intolerant_report; +} + +FRAME TimingAdvertisementFrame // 8.3.3.15 +{ + FF TimeStamp; + FF Capabilities; + OPTIE Country; + OPTIE PowerConstraints; + OPTIE TimeAdvertisement; + OPTIE ExtCap; + OPTIE Vendor1IE; + OPTIE Vendor3IE; +} + +// Local Variables: +// mode: c++ +// fill-column: 77 +// comment-column: 42 +// indent-tabs-mode: nil +// show-trailing-whitespace: t +// End: + +// parser.frms ends here. diff --git a/core/mac/src/cfg/cfg_api.c b/core/mac/src/cfg/cfg_api.c new file mode 100644 index 0000000000..3a0d689e29 --- /dev/null +++ b/core/mac/src/cfg/cfg_api.c @@ -0,0 +1,948 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file contains the source code for CFG API functions. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "cfg_priv.h" +#include "cfg_debug.h" +#include "wma_types.h" +#include "cfg_api.h" + +/* --------------------------------------------------------------------- */ +/* Static Variables */ +/* ---------------------------------------------------------------------- */ +static tCfgCtl __g_cfg_entry[CFG_PARAM_MAX_NUM]; +static uint32_t __g_cfg_i_buf_min[CFG_STA_IBUF_MAX_SIZE]; +static uint32_t __g_cfg_i_buf_max[CFG_STA_IBUF_MAX_SIZE]; +static uint32_t __g_cfg_i_buf[CFG_STA_IBUF_MAX_SIZE]; +static uint8_t __g_cfg_s_buf[CFG_STA_SBUF_MAX_SIZE]; +static uint8_t __g_s_buffer[CFG_MAX_STR_LEN]; +static uint32_t __g_param_list[WNI_CFG_MAX_PARAM_NUM + + WNI_CFG_GET_PER_STA_STAT_RSP_NUM]; + +static void notify(tpAniSirGlobal, uint16_t, uint32_t); + +typedef enum { + eRF_BAND_UNKNOWN = 0, + eRF_BAND_2_4_GHZ = 1, + eRF_BAND_5_GHZ = 2 +} eRfBandMode; + +extern cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING]; +extern cgstatic cfg_static[CFG_PARAM_MAX_NUM] ; + +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RESTART); +} + +void cfg_get_strindex(tpAniSirGlobal pMac, uint16_t cfgId) +{ + uint16_t i = 0; + + for (i = 0; i < CFG_MAX_STATIC_STRING; i++) { + if (cfgId == cfg_static_string[i].cfgId) + break; + } + if (i == CFG_MAX_STATIC_STRING) { + PELOGE(cfg_log(pMac, LOGE, FL("Entry not found for cfg id :%d"), cfgId);) + cfg_static[cfgId].pStrData = NULL; + return; + } + cfg_static[cfgId].pStrData = &cfg_static_string[i]; +} +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RELOAD); +} + +/* --------------------------------------------------------------------- */ +tSirRetStatus cfg_init(tpAniSirGlobal pMac) +{ + uint16_t i = 0; + pMac->cfg.gCfgIBufMin = __g_cfg_i_buf_min; + pMac->cfg.gCfgIBufMax = __g_cfg_i_buf_max; + pMac->cfg.gCfgIBuf = __g_cfg_i_buf; + pMac->cfg.gCfgSBuf = __g_cfg_s_buf; + pMac->cfg.gSBuffer = __g_s_buffer; + pMac->cfg.gCfgEntry = __g_cfg_entry; + pMac->cfg.gParamList = __g_param_list; + + for (i = 0; i < CFG_PARAM_MAX_NUM; i++) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + cfg_get_strindex(pMac, i); + } else { + cfg_static[i].pStrData = NULL; + } + } + return (eSIR_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ +void cfg_de_init(tpAniSirGlobal pMac) +{ + pMac->cfg.gCfgIBufMin = NULL; + pMac->cfg.gCfgIBufMax = NULL; + pMac->cfg.gCfgIBuf = NULL; + pMac->cfg.gCfgSBuf = NULL; + pMac->cfg.gSBuffer = NULL; + pMac->cfg.gCfgEntry = NULL; + pMac->cfg.gParamList = NULL; +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_check_valid() + * + * FUNCTION: + * This function is called to check if a parameter is valid + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ +tSirRetStatus cfg_check_valid(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *index) +{ + uint32_t control; + + if (cfgId >= CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log(pMac, LOG3, FL("Invalid cfg id %d"), cfgId);) + return eSIR_CFG_INVALID_ID; + } + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return eSIR_CFG_INVALID_ID; + } + + control = pMac->cfg.gCfgEntry[cfgId].control; + + /* Check if parameter is valid */ + if ((control & CFG_CTL_VALID) == 0) { + PELOGE(cfg_log(pMac, LOGE, FL("Not valid cfg id %d"), cfgId);) + return eSIR_CFG_INVALID_ID; + } + + *index = control & CFG_BUF_INDX_MASK; + + if (*index >= CFG_STA_SBUF_MAX_SIZE) { + PELOGE(cfg_log(pMac, LOGE, FL("cfg index out of bounds %d"), + *index);) + return eSIR_CFG_INVALID_ID; + } + + return eSIR_SUCCESS; + +} /*** end cfg_check_valid() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_int() + * + * FUNCTION: + * This function is called to update an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Range checking is performed by the calling function. In case this + * function call is being triggered by a request from host, then host + * is responsible for performing range checking before sending the + * request. + * + * - Host RW permission checking should already be done prior to calling + * this function by the message processing function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param value: 32-bit unsigned value + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ + +tSirRetStatus cfg_set_int(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t value) +{ + uint32_t index; + uint32_t control; + uint32_t mask; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + if ((pMac->cfg.gCfgIBufMin[index] > value) || + (pMac->cfg.gCfgIBufMax[index] < value)) { + PELOGE(cfg_log (pMac, LOGE, FL( + "Value %d out of range [%d,%d] cfg id %d"), value, + pMac->cfg.gCfgIBufMin[index], + pMac->cfg.gCfgIBufMax[index], cfgId);) + return eSIR_CFG_INVALID_ID; + } else { + /* Write integer value */ + pMac->cfg.gCfgIBuf[index] = value; + + control = pMac->cfg.gCfgEntry[cfgId].control; + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; + if ((mask & CFG_CTL_NTF_HW) != 0) + PELOGE(cfg_log(pMac, LOGE, FL( + "CFG notify HW not supported!!!"));) + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) + notify(pMac, cfgId, mask); + } + return status; +} /*** end cfg_set_int ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_int() + * + * FUNCTION: + * This function is called to read an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pVal: address where parameter value will be written + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ + +tSirRetStatus wlan_cfg_get_int(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pValue) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + /* Get integer value */ + *pValue = pMac->cfg.gCfgIBuf[index]; + + return eSIR_SUCCESS; +} /*** end wlan_cfg_get_int() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * This function invokes the cfg_set_str_notify function passing the notify + * bool value set to true. This basically means that HAL needs to be + * notified. This is true in the case of non-integrated SOC's or Libra/Volans. + * In the case of Prima the cfg_set_str_notify is invoked with the bool value + * set to false. + * + * ASSUMPTIONS: + * - always notify has to be called + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus cfg_set_str(tpAniSirGlobal pMac, uint16_t cfgId, uint8_t *pStr, + uint32_t length) +{ + return cfg_set_str_notify(pMac, cfgId, pStr, length, true); +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str_notify() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - No length checking will be performed. Should be done by calling + * module. + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * @param notifyMod. notify respective Module + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus cfg_set_str_notify(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pStr, uint32_t length, + int notifyMod) +{ + uint8_t *pDst, *pDstEnd; + uint32_t index, paramLen, mask; + uint32_t control; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + pDst = &pMac->cfg.gCfgSBuf[index]; + paramLen = *pDst++; + control = pMac->cfg.gCfgEntry[cfgId].control; + if (length > paramLen) { + PELOGE(cfg_log(pMac, LOGE, FL( + "Invalid length %d (>%d) cfg id %d"), + length, paramLen, cfgId);) + return eSIR_CFG_INVALID_LEN; + } else { + *pDst++ = (uint8_t) length; + pDstEnd = pDst + length; + while (pDst < pDstEnd) { + *pDst++ = *pStr++; + } + if (notifyMod) { + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; + if ((mask & CFG_CTL_NTF_HW) != 0) { + PELOGE(cfg_log(pMac, LOGE, FL( + "CFG notify HW not supported!"));) + } + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) { + notify(pMac, cfgId, mask); + } + } + } + return eSIR_SUCCESS; +} /*** end cfg_set_str_notify() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str() + * + * FUNCTION: + * This function is called to get a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pBuf: address of string buffer + * @param pLen: address of max buffer length + * actual length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus wlan_cfg_get_str(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pBuf, uint32_t *pLength) +{ + uint8_t *pSrc, *pSrcEnd; + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + /* Get string */ + pSrc = &pMac->cfg.gCfgSBuf[index]; + pSrc++; /* skip over max length */ + if (*pLength < *pSrc) { + PELOGE(cfg_log(pMac, LOGE, FL( + "Invalid length %d (<%d) cfg id %d"), + *pLength, *pSrc, cfgId);) + return eSIR_CFG_INVALID_LEN; + } else { + *pLength = *pSrc++; /* save parameter length */ + pSrcEnd = pSrc + *pLength; + while (pSrc < pSrcEnd) + *pBuf++ = *pSrc++; + } + return eSIR_SUCCESS; +} /*** end wlan_cfg_get_str() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_max_len() + * + * FUNCTION: + * This function is called to get a string maximum length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: maximum length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * + */ + +tSirRetStatus wlan_cfg_get_str_max_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index]; + + return status; +} /*** end wlan_cfg_get_str_max_len() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_len() + * + * FUNCTION: + * This function is called to get a string length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: current length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * + */ + +tSirRetStatus wlan_cfg_get_str_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index + 1]; + + return status; + +} /*** end wlan_cfg_get_str_len() ***/ + +/*------------------------------------------------------------- + \fn cfg_get_dot11d_transmit_power + \brief This function returns the regulatory max transmit power + \param pMac + \return tPowerdBm - Power + \-------------------------------------------------------------*/ +static tPowerdBm +cfg_get_dot11d_transmit_power(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t cfgLength, uint8_t channel) +{ + uint8_t *pCountryInfo = NULL; + uint8_t count = 0; + tPowerdBm maxTxPwr = WMA_MAX_TXPOWER_INVALID; + + /* At least one element is present */ + if (cfgLength < sizeof(tSirMacChanInfo)) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Invalid CFGLENGTH %d while getting 11d txpower"), + cfgLength); + ) + goto error; + } + + pCountryInfo = cdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) { + cfg_log(pMac, LOGP, FL(" failed to allocate memory")); + goto error; + } + /* The CSR will always update this CFG. The contents will be from country IE if regulatory domain + * is enabled on AP else will contain EEPROM contents + */ + if (wlan_cfg_get_str(pMac, cfgId, pCountryInfo, &cfgLength) != + eSIR_SUCCESS) { + cdf_mem_free(pCountryInfo); + pCountryInfo = NULL; + + cfg_log(pMac, LOGP, + FL + ("Failed to retrieve 11d configuration parameters while retrieving 11d tuples")); + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + uint8_t firstChannel, maxChannels; + + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + cdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +/**---------------------------------------------------------------------- + \fn cfg_get_regulatory_max_transmit_power + + \brief Gets regulatory tx power on the current channel. + + \param pMac + \param channel + \param rfBand + -----------------------------------------------------------------------*/ +tPowerdBm cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + tPowerdBm maxTxPwr; + eRfBandMode rfBand = eRF_BAND_UNKNOWN; + + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + rfBand = eRF_BAND_5_GHZ; + else + rfBand = eRF_BAND_2_4_GHZ; + + /* Get the max transmit power for current channel for the current regulatory domain */ + switch (rfBand) { + case eRF_BAND_2_4_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + PELOG2(cfg_log + (pMac, LOG2, + FL + ("HAL: Reading CFG for 2.4 GHz channels to get regulatory max tx power")); + ) + break; + + case eRF_BAND_5_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + PELOG2(cfg_log + (pMac, LOG2, + FL + ("HAL: Reading CFG for 5.0 GHz channels to get regulatory max tx power")); + ) + break; + + case eRF_BAND_UNKNOWN: + default: + PELOG2(cfg_log + (pMac, LOG2, + FL("HAL: Invalid current working band for the device")); + ) + return WMA_MAX_TXPOWER_INVALID; /* Its return, not break. */ + } + + maxTxPwr = cfg_get_dot11d_transmit_power(pMac, cfgId, cfgLength, channel); + + return (maxTxPwr); +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_get_capability_info + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +tSirRetStatus cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession sessionEntry) +{ + uint32_t val = 0; + tpSirMacCapabilityInfo pCapInfo; + + *pCap = 0; + pCapInfo = (tpSirMacCapabilityInfo) pCap; + + if (LIM_IS_IBSS_ROLE(sessionEntry)) + pCapInfo->ibss = 1; /* IBSS bit */ + else if (LIM_IS_AP_ROLE(sessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(sessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(sessionEntry) || + LIM_IS_STA_ROLE(sessionEntry)) + pCapInfo->ess = 1; /* ESS bit */ + else if (LIM_IS_P2P_DEVICE_ROLE(sessionEntry)) { + pCapInfo->ess = 0; + pCapInfo->ibss = 0; + } else + cfg_log(pMac, LOGP, + FL("can't get capability, role is UNKNOWN!!")); + + if (LIM_IS_AP_ROLE(sessionEntry)) { + val = sessionEntry->privacy; + } else { + /* PRIVACY bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_PRIVACY_ENABLED failed")); + return eSIR_FAILURE; + } + } + if (val) + pCapInfo->privacy = 1; + + /* Short preamble bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_SHORT_PREAMBLE failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->shortPreamble = 1; + + /* PBCC bit */ + pCapInfo->pbcc = 0; + + /* Channel agility bit */ + pCapInfo->channelAgility = 0; + /* If STA/AP operating in 11B mode, don't set rest of the capability info bits. */ + if (sessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11B) + return eSIR_SUCCESS; + + /* Short slot time bit */ + if (LIM_IS_AP_ROLE(sessionEntry)) { + pCapInfo->shortSlotTime = sessionEntry->shortSlotTimeSupported; + } else { + if (wlan_cfg_get_int + (pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val) + != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL + ("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed")); + return eSIR_FAILURE; + } + /* When in STA mode, we need to check if short slot is enabled as well as check if the current operating + * mode is short slot time and then decide whether to enable short slot or not. It is safe to check both + * cfg values to determine short slot value in this funcn since this funcn is always used after assoc when + * these cfg values are already set based on peer's capability. Even in case of IBSS, its value is set to + * correct value either in delBSS as part of deleting the previous IBSS or in start BSS as part of coalescing + */ + if (val) { + pCapInfo->shortSlotTime = + sessionEntry->shortSlotTimeSupported; + } + } + + /* Spectrum Management bit */ + if (!LIM_IS_IBSS_ROLE(sessionEntry) && sessionEntry->lim11hEnable) { + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_11H_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->spectrumMgt = 1; + } + /* QoS bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_QOS_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->qos = 1; + + /* APSD bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_APSD_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->apsd = 1; + +#if defined WLAN_FEATURE_VOWIFI + if (LIM_IS_STA_ROLE(sessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_RRM_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_RRM_ENABLED failed")); + return eSIR_FAILURE; + } +#if defined WLAN_VOWIFI_DEBUG + PELOGE(cfg_log(pMac, LOGE, "RRM = %d", val);) +#endif + if (val) + pCapInfo->rrm = 1; + } +#endif + /* DSSS-OFDM */ + /* FIXME : no config defined yet. */ + + /* Block ack bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_BLOCK_ACK_ENABLED failed")); + return eSIR_FAILURE; + } + pCapInfo->delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + pCapInfo->immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * cfg_set_capability_info + * + * FUNCTION: + * This function is called on BP based on the capabilities + * received in SME_JOIN/REASSOC_REQ message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: 1. ESS/IBSS capabilities are based on system role. + * 2. Since PBCC, Channel agility and Extended capabilities + * are not supported, they're not set at CFG + * + * @param pMac Pointer to global MAC structure + * @param caps 16-bit Capability Info field + * @return None + */ + +void cfg_set_capability_info(tpAniSirGlobal pMac, uint16_t caps) +{ +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_cleanup() + * + * FUNCTION: + * CFG cleanup function. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * This function must be called during system shutdown. + * + * @param None + * + * @return None. + * + */ + +void cfg_cleanup(tpAniSirGlobal pMac) +{ + /* Set status to not-ready */ + pMac->cfg.gCfgStatus = CFG_INCOMPLETE; + +} /*** end CfgCleanup() ***/ + +/* --------------------------------------------------------------------- */ +/** + * notify() + * + * FUNCTION: + * This function is called to notify other modules of parameter update. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: configuration parameter ID + * @param mask: notification mask + * + * @return None. + * + */ + +static void notify(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t ntfMask) +{ + + tSirMsgQ mmhMsg; + + mmhMsg.type = SIR_CFG_PARAM_UPDATE_IND; + mmhMsg.bodyval = (uint32_t) cfgId; + mmhMsg.bodyptr = NULL; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + + if ((ntfMask & CFG_CTL_NTF_SCH) != 0) + sch_post_message(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_LIM) != 0) + lim_post_msg_api(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_HAL) != 0) + wma_post_ctrl_msg(pMac, &mmhMsg); + + /* notify ARQ */ + +} /*** end notify() ***/ + +/** + * cfg_get_vendor_ie_ptr_from_oui() - returns IE pointer in IE buffer given its + * OUI and OUI size + * @mac_ctx: mac context. + * @oui: OUI string. + * @oui_size: length of OUI string + * One can provide multiple line descriptions + * for arguments. + * @ie: ie buffer + * @ie_len: length of ie buffer + * + * This function parses the IE buffer and finds the given OUI and returns its + * pointer + * + * Return: pointer of given OUI IE else NULL + */ +uint8_t *cfg_get_vendor_ie_ptr_from_oui(tpAniSirGlobal mac_ctx, + uint8_t *oui, + uint8_t oui_size, + uint8_t *ie, + uint16_t ie_len) +{ + int32_t left = ie_len; + uint8_t *ptr = ie; + uint8_t elem_id, elem_len; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + cfg_log(mac_ctx, LOGE, + FL("Invalid IEs eid = %d elem_len=%d left=%d"), + elem_id, elem_len, left); + return NULL; + } + if (SIR_MAC_EID_VENDOR == elem_id) { + if (memcmp(&ptr[2], oui, oui_size) == 0) + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} +/* --------------------------------------------------------------------- */ diff --git a/core/mac/src/cfg/cfg_debug.c b/core/mac/src/cfg/cfg_debug.c new file mode 100644 index 0000000000..7d09c91763 --- /dev/null +++ b/core/mac/src/cfg/cfg_debug.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file cfg_debug.c + + \brief implementation for log Debug related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#include "cfg_debug.h" + +void cfg_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_CFG_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_CFG_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} diff --git a/core/mac/src/cfg/cfg_debug.h b/core/mac/src/cfg/cfg_debug.h new file mode 100644 index 0000000000..424152e6e9 --- /dev/null +++ b/core/mac/src/cfg/cfg_debug.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ + +#ifndef __CFG_DEBUG_H__ +#define __CFG_DEBUG_H__ + +#include "sir_debug.h" +#include "utils_api.h" +#include "lim_trace.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) cfg_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif diff --git a/core/mac/src/cfg/cfg_def.h b/core/mac/src/cfg/cfg_def.h new file mode 100644 index 0000000000..6239538ebc --- /dev/null +++ b/core/mac/src/cfg/cfg_def.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGDEF_H +#define __CFGDEF_H + +/* + * CFG Control Flag definitions + */ +#define CFG_CTL_VALID 0x00010000 +#define CFG_CTL_RE 0x00020000 +#define CFG_CTL_WE 0x00040000 +#define CFG_CTL_INT 0x00080000 +#define CFG_CTL_SAVE 0x00100000 +#define CFG_CTL_RESTART 0x00200000 +#define CFG_CTL_RELOAD 0x00400000 +#define CFG_CTL_NTF_PHY 0x00800000 +#define CFG_CTL_NTF_MAC 0x01000000 +#define CFG_CTL_NTF_LOG 0x02000000 +#define CFG_CTL_NTF_HAL 0x04000000 +#define CFG_CTL_NTF_DPH 0x08000000 +#define CFG_CTL_NTF_ARQ 0x10000000 +#define CFG_CTL_NTF_SCH 0x20000000 +#define CFG_CTL_NTF_LIM 0x40000000 +#define CFG_CTL_NTF_HDD 0x80000000 +#define CFG_CTL_NTF_MASK 0xFFE00000 + +#define CFG_CTL_NTF_TFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RHP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_SP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_HW (CFG_CTL_NTF_MAC | CFG_CTL_NTF_PHY) + +#define CFG_BUF_INDX_MASK 0x00000fff + +#endif /* __CFGDEF_H */ diff --git a/core/mac/src/cfg/cfg_param_name.c b/core/mac/src/cfg/cfg_param_name.c new file mode 100644 index 0000000000..00be55d649 --- /dev/null +++ b/core/mac/src/cfg/cfg_param_name.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * DO NOT EDIT - This file is generated automatically + */ + +/* + * IMPORTANT: This file is for system that supports STA mode ONLY. + */ +#include "cfg_priv.h" + +unsigned char *g_cfg_param_name[] = { + (unsigned char *)"STA_ID", + (unsigned char *)"CF_POLLABLE", + (unsigned char *)"CFP_PERIOD", + (unsigned char *)"CFP_MAX_DURATION", + (unsigned char *)"SSID", + (unsigned char *)"BEACON_INTERVAL", + (unsigned char *)"DTIM_PERIOD", + (unsigned char *)"WEP_KEY_LENGTH", + (unsigned char *)"WEP_DEFAULT_KEY_1", + (unsigned char *)"WEP_DEFAULT_KEY_2", + (unsigned char *)"WEP_DEFAULT_KEY_3", + (unsigned char *)"WEP_DEFAULT_KEY_4", + (unsigned char *)"WEP_DEFAULT_KEYID", + (unsigned char *)"EXCLUDE_UNENCRYPTED", + (unsigned char *)"RTS_THRESHOLD", + (unsigned char *)"SHORT_RETRY_LIMIT", + (unsigned char *)"LONG_RETRY_LIMIT", + (unsigned char *)"FRAGMENTATION_THRESHOLD", + (unsigned char *)"ACTIVE_MINIMUM_CHANNEL_TIME", + (unsigned char *)"ACTIVE_MAXIMUM_CHANNEL_TIME", + (unsigned char *)"PASSIVE_MINIMUM_CHANNEL_TIME", + (unsigned char *)"PASSIVE_MAXIMUM_CHANNEL_TIME", + (unsigned char *)"JOIN_FAILURE_TIMEOUT", + (unsigned char *)"AUTHENTICATE_FAILURE_TIMEOUT", + (unsigned char *)"AUTHENTICATE_RSP_TIMEOUT", + (unsigned char *)"ASSOCIATION_FAILURE_TIMEOUT", + (unsigned char *)"REASSOCIATION_FAILURE_TIMEOUT", + (unsigned char *)"RA_PERIODICITY_TIMEOUT_IN_PS", + (unsigned char *)"PS_ENABLE_BCN_FILTER", + (unsigned char *)"PS_ENABLE_HEART_BEAT", + (unsigned char *)"PS_ENABLE_RSSI_MONITOR", + (unsigned char *)"PS_DATA_INACTIVITY_TIMEOUT", + (unsigned char *)"RF_SETTLING_TIME_CLK", + (unsigned char *)"SUPPORTED_RATES_11B", + (unsigned char *)"SUPPORTED_RATES_11A", + (unsigned char *)"PHY_MODE", + (unsigned char *)"DOT11_MODE", + (unsigned char *)"OPERATIONAL_RATE_SET", + (unsigned char *)"EXTENDED_OPERATIONAL_RATE_SET", + (unsigned char *)"PROPRIETARY_OPERATIONAL_RATE_SET", + (unsigned char *)"LISTEN_INTERVAL", + (unsigned char *)"VALID_CHANNEL_LIST", + (unsigned char *)"CURRENT_CHANNEL", + (unsigned char *)"DEFAULT_RATE_INDEX_5GHZ", + (unsigned char *)"DEFAULT_RATE_INDEX_24GHZ", + (unsigned char *)"RATE_ADAPTATION_TYPE", + (unsigned char *)"FIXED_RATE", + (unsigned char *)"FIXED_RATE_MULTICAST_24GHZ", + (unsigned char *)"FIXED_RATE_MULTICAST_5GHZ", + (unsigned char *)"RETRYRATE_POLICY", + (unsigned char *)"RETRYRATE_SECONDARY", + (unsigned char *)"RETRYRATE_TERTIARY", + (unsigned char *)"APSD_ENABLED", + (unsigned char *)"SHARED_KEY_AUTH_ENABLE", + (unsigned char *)"OPEN_SYSTEM_AUTH_ENABLE", + (unsigned char *)"AUTHENTICATION_TYPE", + (unsigned char *)"CF_POLL_REQUEST", + (unsigned char *)"PRIVACY_ENABLED", + (unsigned char *)"SHORT_PREAMBLE", + (unsigned char *)"SHORT_SLOT_TIME", + (unsigned char *)"ACCEPT_SHORT_SLOT_ASSOC_ONLY", + (unsigned char *)"QOS_ENABLED", + (unsigned char *)"HCF_ENABLED", + (unsigned char *)"RSN_ENABLED", + (unsigned char *)"BACKGROUND_SCAN_PERIOD", + (unsigned char *)"MAX_NUM_PRE_AUTH", + (unsigned char *)"PREAUTH_CLNUP_TIMEOUT", + (unsigned char *)"RELEASE_AID_TIMEOUT", + (unsigned char *)"HEART_BEAT_THRESHOLD", + (unsigned char *)"PROBE_AFTER_HB_FAIL_TIMEOUT", + (unsigned char *)"MANUFACTURER_OUI", + (unsigned char *)"MANUFACTURER_NAME", + (unsigned char *)"MODEL_NUMBER", + (unsigned char *)"MODEL_NAME", + (unsigned char *)"MANUFACTURER_PRODUCT_NAME", + (unsigned char *)"MANUFACTURER_PRODUCT_VERSION", + (unsigned char *)"11D_ENABLED", + (unsigned char *)"MAX_TX_POWER_2_4", + (unsigned char *)"MAX_TX_POWER_5", + (unsigned char *)"NETWORK_DENSITY", + (unsigned char *)"ADAPTIVE_THRESHOLD_ALGORITHM", + (unsigned char *)"CURRENT_TX_ANTENNA", + (unsigned char *)"CURRENT_RX_ANTENNA", + (unsigned char *)"CURRENT_TX_POWER_LEVEL", + (unsigned char *)"NEW_BSS_FOUND_IND", + (unsigned char *)"PROPRIETARY_RATES_ENABLED", + (unsigned char *)"AP_NODE_NAME", + (unsigned char *)"COUNTRY_CODE", + (unsigned char *)"11H_ENABLED", + (unsigned char *)"WT_CNF_TIMEOUT", + (unsigned char *)"KEEPALIVE_TIMEOUT", + (unsigned char *)"PROXIMITY", + (unsigned char *)"LOG_LEVEL", + (unsigned char *)"OLBC_DETECT_TIMEOUT", + (unsigned char *)"PROTECTION_ENABLED", + (unsigned char *)"11G_PROTECTION_ALWAYS", + (unsigned char *)"FORCE_POLICY_PROTECTION", + (unsigned char *)"11G_SHORT_PREAMBLE_ENABLED", + (unsigned char *)"11G_SHORT_SLOT_TIME_ENABLED", + (unsigned char *)"11G_ONLY_POLICY", + (unsigned char *)"PACKET_CLASSIFICATION", + (unsigned char *)"WME_ENABLED", + (unsigned char *)"ADDTS_RSP_TIMEOUT", + (unsigned char *)"MAX_SP_LENGTH", + (unsigned char *)"KEEP_ALIVE_STA_LIMIT_THRESHOLD", + (unsigned char *)"SEND_SINGLE_SSID_ALWAYS", + (unsigned char *)"WSM_ENABLED", + (unsigned char *)"EDCA_PROFILE", + (unsigned char *)"EDCA_ANI_ACBK_LOCAL", + (unsigned char *)"EDCA_ANI_ACBE_LOCAL", + (unsigned char *)"EDCA_ANI_ACVI_LOCAL", + (unsigned char *)"EDCA_ANI_ACVO_LOCAL", + (unsigned char *)"EDCA_ANI_ACBK", + (unsigned char *)"EDCA_ANI_ACBE", + (unsigned char *)"EDCA_ANI_ACVI", + (unsigned char *)"EDCA_ANI_ACVO", + (unsigned char *)"EDCA_WME_ACBK_LOCAL", + (unsigned char *)"EDCA_WME_ACBE_LOCAL", + (unsigned char *)"EDCA_WME_ACVI_LOCAL", + (unsigned char *)"EDCA_WME_ACVO_LOCAL", + (unsigned char *)"EDCA_WME_ACBK", + (unsigned char *)"EDCA_WME_ACBE", + (unsigned char *)"EDCA_WME_ACVI", + (unsigned char *)"EDCA_WME_ACVO", + (unsigned char *)"RDET_FLAG", + (unsigned char *)"RADAR_CHANNEL_LIST", + (unsigned char *)"LOCAL_POWER_CONSTRAINT", + (unsigned char *)"ADMIT_POLICY", + (unsigned char *)"ADMIT_BWFACTOR", + (unsigned char *)"MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE", + (unsigned char *)"CHANNEL_BONDING_MODE", + (unsigned char *)"CB_SECONDARY_CHANNEL_STATE", + (unsigned char *)"DYNAMIC_THRESHOLD_ZERO", + (unsigned char *)"DYNAMIC_THRESHOLD_ONE", + (unsigned char *)"DYNAMIC_THRESHOLD_TWO", + (unsigned char *)"TRIG_STA_BK_SCAN", + (unsigned char *)"DYNAMIC_PROFILE_SWITCHING", + (unsigned char *)"SCAN_CONTROL_LIST", + (unsigned char *)"MIMO_ENABLED", + (unsigned char *)"BLOCK_ACK_ENABLED", + (unsigned char *)"HT_RX_STBC", + (unsigned char *)"HT_CAP_INFO", + (unsigned char *)"HT_AMPDU_PARAMS", + (unsigned char *)"SUPPORTED_MCS_SET", + (unsigned char *)"EXT_HT_CAP_INFO", + (unsigned char *)"TX_BF_CAP", + (unsigned char *)"AS_CAP", + (unsigned char *)"HT_INFO_FIELD1", + (unsigned char *)"HT_INFO_FIELD2", + (unsigned char *)"HT_INFO_FIELD3", + (unsigned char *)"BASIC_MCS_SET", + (unsigned char *)"CURRENT_MCS_SET", + (unsigned char *)"GREENFIELD_CAPABILITY", + (unsigned char *)"VHT_MAX_MPDU_LENGTH", + (unsigned char *)"VHT_SUPPORTED_CHAN_WIDTH_SET", + (unsigned char *)"VHT_LDPC_CODING_CAP", + (unsigned char *)"VHT_SHORT_GI_80MHZ", + (unsigned char *)"VHT_SHORT_GI_160_AND_80_PLUS_80MHZ", + (unsigned char *)"VHT_TXSTBC", + (unsigned char *)"VHT_RXSTBC", + (unsigned char *)"VHT_SU_BEAMFORMER_CAP", + (unsigned char *)"VHT_SU_BEAMFORMEE_CAP", + (unsigned char *)"VHT_CSN_BEAMFORMEE_ANT_SUPPORTED", + (unsigned char *)"VHT_NUM_SOUNDING_DIMENSIONS", + (unsigned char *)"VHT_MU_BEAMFORMER_CAP", + (unsigned char *)"VHT_MU_BEAMFORMEE_CAP", + (unsigned char *)"VHT_TXOP_PS", + (unsigned char *)"VHT_HTC_VHTC_CAP", + (unsigned char *)"VHT_AMPDU_LEN_EXPONENT", + (unsigned char *)"VHT_LINK_ADAPTATION_CAP", + (unsigned char *)"VHT_RX_ANT_PATTERN", + (unsigned char *)"VHT_TX_ANT_PATTERN", + (unsigned char *)"VHT_RX_MCS_MAP", + (unsigned char *)"VHT_TX_MCS_MAP", + (unsigned char *)"VHT_RX_HIGHEST_SUPPORTED_DATA_RATE", + (unsigned char *)"VHT_TX_HIGHEST_SUPPORTED_DATA_RATE", + (unsigned char *)"VHT_CHANNEL_CENTER_FREQ_SEGMENT1", + (unsigned char *)"VHT_CHANNEL_CENTER_FREQ_SEGMENT2", + (unsigned char *)"VHT_BASIC_MCS_SET", + (unsigned char *)"VHT_MU_MIMO_CAP_STA_COUNT", + (unsigned char *)"VHT_SS_UNDER_UTIL", + (unsigned char *)"VHT_40MHZ_UTILIZATION", + (unsigned char *)"VHT_80MHZ_UTILIZATION", + (unsigned char *)"VHT_160MHZ_UTILIZATION", + (unsigned char *)"MAX_AMSDU_LENGTH", + (unsigned char *)"MPDU_DENSITY", + (unsigned char *)"NUM_BUFF_ADVERT", + (unsigned char *)"MAX_RX_AMPDU_FACTOR", + (unsigned char *)"SHORT_GI_20MHZ", + (unsigned char *)"SHORT_GI_40MHZ", + (unsigned char *)"RIFS_ENABLED", + (unsigned char *)"MAX_PS_POLL", + (unsigned char *)"NUM_BEACON_PER_RSSI_AVERAGE", + (unsigned char *)"RSSI_FILTER_PERIOD", + (unsigned char *)"MIN_RSSI_THRESHOLD", + (unsigned char *)"NTH_BEACON_FILTER", + (unsigned char *)"BROADCAST_FRAME_FILTER_ENABLE", + (unsigned char *)"SCAN_IN_POWERSAVE", + (unsigned char *)"IGNORE_DTIM", + (unsigned char *)"WOWLAN_UCAST_PATTERN_FILTER_ENABLE", + (unsigned char *)"WOWLAN_CHANNEL_SWITCH_ENABLE", + (unsigned char *)"WOWLAN_DEAUTH_ENABLE", + (unsigned char *)"WOWLAN_DISASSOC_ENABLE", + (unsigned char *)"WOWLAN_MAX_MISSED_BEACON", + (unsigned char *)"WOWLAN_MAX_SLEEP_PERIOD", + (unsigned char *)"BA_THRESHOLD_HIGH", + (unsigned char *)"BG_SCAN_CHANNEL_LIST", + (unsigned char *)"MAX_MEDIUM_TIME", + (unsigned char *)"MAX_MPDUS_IN_AMPDU", + (unsigned char *)"IBSS_AUTO_BSSID", + (unsigned char *)"PROBE_REQ_ADDNIE_FLAG", + (unsigned char *)"PROBE_REQ_ADDNIE_DATA", + (unsigned char *)"PROBE_RSP_ADDNIE_FLAG", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA1", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA2", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA3", + (unsigned char *)"ASSOC_RSP_ADDNIE_FLAG", + (unsigned char *)"ASSOC_RSP_ADDNIE_DATA", + (unsigned char *)"PROBE_REQ_ADDNP2PIE_FLAG", + (unsigned char *)"PROBE_REQ_ADDNP2PIE_DATA", + (unsigned char *)"PROBE_RSP_BCN_ADDNIE_FLAG", + (unsigned char *)"PROBE_RSP_BCN_ADDNIE_DATA", + (unsigned char *)"WPS_ENABLE", + (unsigned char *)"WPS_STATE", + (unsigned char *)"WPS_PROBE_REQ_FLAG", + (unsigned char *)"WPS_VERSION", + (unsigned char *)"WPS_REQUEST_TYPE", + (unsigned char *)"WPS_CFG_METHOD", + (unsigned char *)"WPS_UUID", + (unsigned char *)"WPS_PRIMARY_DEVICE_CATEGORY", + (unsigned char *)"WPS_PIMARY_DEVICE_OUI", + (unsigned char *)"WPS_DEVICE_SUB_CATEGORY", + (unsigned char *)"WPS_ASSOCIATION_STATE", + (unsigned char *)"WPS_CONFIGURATION_ERROR", + (unsigned char *)"WPS_DEVICE_PASSWORD_ID", + (unsigned char *)"WPS_ASSOC_METHOD", + (unsigned char *)"LOW_GAIN_OVERRIDE", + (unsigned char *)"ENABLE_PHY_AGC_LISTEN_MODE", + (unsigned char *)"RPE_POLLING_THRESHOLD", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC0_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC1_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC2_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC3_REG", + (unsigned char *)"NO_OF_ONCHIP_REORDER_SESSIONS", + (unsigned char *)"SINGLE_TID_RC", + (unsigned char *)"RRM_ENABLED", + (unsigned char *)"RRM_OPERATING_CHAN_MAX", + (unsigned char *)"RRM_NON_OPERATING_CHAN_MAX", + (unsigned char *)"TX_PWR_CTRL_ENABLE", + (unsigned char *)"MCAST_BCAST_FILTER_SETTING", + (unsigned char *)"BTC_DHCP_BT_SLOTS_TO_BLOCK", + (unsigned char *)"DYNAMIC_PS_POLL_VALUE", + (unsigned char *)"PS_NULLDATA_AP_RESP_TIMEOUT", + (unsigned char *)"TELE_BCN_WAKEUP_EN", + (unsigned char *)"TELE_BCN_TRANS_LI", + (unsigned char *)"TELE_BCN_TRANS_LI_IDLE_BCNS", + (unsigned char *)"TELE_BCN_MAX_LI", + (unsigned char *)"TELE_BCN_MAX_LI_IDLE_BCNS", + (unsigned char *)"BTC_A2DP_DHCP_BT_SUB_INTERVALS", + (unsigned char *)"INFRA_STA_KEEP_ALIVE_PERIOD", + (unsigned char *)"ASSOC_STA_LIMIT", + (unsigned char *)"SAP_CHANNEL_SELECT_START_CHANNEL", + (unsigned char *)"SAP_CHANNEL_SELECT_END_CHANNEL", + (unsigned char *)"SAP_CHANNEL_SELECT_OPERATING_BAND", + (unsigned char *)"AP_DATA_AVAIL_POLL_PERIOD", + (unsigned char *)"ENABLE_CLOSE_LOOP", + (unsigned char *)"ENABLE_LTE_COEX", + (unsigned char *)"AP_KEEP_ALIVE_TIMEOUT", + (unsigned char *)"GO_KEEP_ALIVE_TIMEOUT", + (unsigned char *)"ENABLE_MC_ADDR_LIST", + (unsigned char *)"ENABLE_UC_FILTER", + (unsigned char *)"ENABLE_LPWR_IMG_TRANSITION", + (unsigned char *)"ENABLE_MCC_ADAPTIVE_SCHED", + (unsigned char *)"DISABLE_LDPC_WITH_TXBF_AP", + (unsigned char *)"AP_LINK_MONITOR_TIMEOUT", + (unsigned char *)"TDLS_QOS_WMM_UAPSD_MASK", + (unsigned char *)"TDLS_BUF_STA_ENABLED", + (unsigned char *)"TDLS_PUAPSD_INACT_TIME", + (unsigned char *)"TDLS_RX_FRAME_THRESHOLD", + (unsigned char *)"PMF_SA_QUERY_MAX_RETRIES", + (unsigned char *)"PMF_SA_QUERY_RETRY_INTERVAL", + (unsigned char *)"ENABLE_ADAPT_RX_DRAIN", + (unsigned char *)"FLEX_CONNECT_POWER_FACTOR", + (unsigned char *)"ANTENNA_DIVESITY", + (unsigned char *)"GO_LINK_MONITOR_TIMEOUT", + (unsigned char *)"RMC_ACTION_PERIOD_FREQUENCY", + (unsigned char *)"CURRENT_RSSI", + (unsigned char *)"RTT3_ENABLE", + (unsigned char *)"DEBUG_P2P_REMAIN_ON_CHANNEL", + (unsigned char *)"TDLS_OFF_CHANNEL_ENABLED", + (unsigned char *)"IBSS_ATIM_WIN_SIZE", + (unsigned char *)"DFS_MASTER_ENABLED", + (unsigned char *)"VHT_ENABLE_TXBF_20MHZ", + (unsigned char *)"TDLS_WMM_MODE_ENABLED", +}; diff --git a/core/mac/src/cfg/cfg_priv.h b/core/mac/src/cfg/cfg_priv.h new file mode 100644 index 0000000000..78769f59c2 --- /dev/null +++ b/core/mac/src/cfg/cfg_priv.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGPRIV_H +#define __CFGPRIV_H + +#include +#include +#include +#include +#include +#include +#include +#include "cfg_def.h" + +#include + +/*--------------------------------------------------------------------*/ +/* CFG miscellaneous definition */ +/*--------------------------------------------------------------------*/ + +/* Function index bit mask */ +#define CFG_FUNC_INDX_MASK 0x7f +#define CFG_GET_FUNC_INDX(val) (val & CFG_FUNC_INDX_MASK) + +/* Macro to convert return code to debug string index */ +#define CFG_GET_DBG_INDX(val) (val - eCFG_SUCCESS - 1) + +/*--------------------------------------------------------------------*/ +/* Binary header structure */ +/*--------------------------------------------------------------------*/ +typedef struct sCfgBinHdr { + uint32_t hdrInfo; + uint32_t controlSize; + uint32_t iBufSize; + uint32_t sBufSize; +} tCfgBinHdr, *tpCfgBinHdr; + +/*--------------------------------------------------------------------*/ +/* Polaris HW counter access structure */ +/*--------------------------------------------------------------------*/ + +#define CFG_STAT_CNT_LO_MASK 0x0000ffff +#define CFG_STAT_CNT_HI_MASK 0xffff0000 +#define CFG_STAT_CNT_HI_INCR 0x00010000 + +/*--------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*--------------------------------------------------------------------*/ + +extern void cfg_send_host_msg(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *, uint32_t, uint32_t *); + +#endif /* __CFGPRIV_H */ diff --git a/core/mac/src/cfg/cfg_proc_msg.c b/core/mac/src/cfg/cfg_proc_msg.c new file mode 100644 index 0000000000..0a477d0b80 --- /dev/null +++ b/core/mac/src/cfg/cfg_proc_msg.c @@ -0,0 +1,2607 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains CFG functions for processing host messages. + */ +#include "cds_api.h" +#include "ani_global.h" +#include "cfg_priv.h" +#include "cfg_debug.h" +#include "wma_types.h" + +cgstatic cfg_static[CFG_PARAM_MAX_NUM] = { + {WNI_CFG_STA_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RELOAD | + CFG_CTL_NTF_HAL, + 0, 255, 1}, + {WNI_CFG_CF_POLLABLE, + CFG_CTL_RE | CFG_CTL_INT | CFG_CTL_RESTART, + 0, 255, 1}, + {WNI_CFG_CFP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_PERIOD_STAMIN, + WNI_CFG_CFP_PERIOD_STAMAX, + WNI_CFG_CFP_PERIOD_STADEF}, + {WNI_CFG_CFP_MAX_DURATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_MAX_DURATION_STAMIN, + WNI_CFG_CFP_MAX_DURATION_STAMAX, + WNI_CFG_CFP_MAX_DURATION_STADEF}, + {WNI_CFG_SSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 255, 6}, + {WNI_CFG_BEACON_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_BEACON_INTERVAL_STAMIN, + WNI_CFG_BEACON_INTERVAL_STAMAX, + WNI_CFG_BEACON_INTERVAL_STADEF}, + {WNI_CFG_DTIM_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_DTIM_PERIOD_STAMIN, + WNI_CFG_DTIM_PERIOD_STAMAX, + WNI_CFG_DTIM_PERIOD_STADEF}, + {WNI_CFG_WEP_KEY_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_WEP_KEY_LENGTH_STAMIN, + WNI_CFG_WEP_KEY_LENGTH_STAMAX, + WNI_CFG_WEP_KEY_LENGTH_STADEF}, + {WNI_CFG_WEP_DEFAULT_KEY_1, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 0}, + {WNI_CFG_WEP_DEFAULT_KEY_2, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 1, 1, 1}, + {WNI_CFG_WEP_DEFAULT_KEY_3, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 5, 5}, + {WNI_CFG_WEP_DEFAULT_KEY_4, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 0}, + {WNI_CFG_WEP_DEFAULT_KEYID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WEP_DEFAULT_KEYID_STAMIN, + WNI_CFG_WEP_DEFAULT_KEYID_STAMAX, + WNI_CFG_WEP_DEFAULT_KEYID_STADEF}, + {WNI_CFG_EXCLUDE_UNENCRYPTED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_EXCLUDE_UNENCRYPTED_STAMIN, + WNI_CFG_EXCLUDE_UNENCRYPTED_STAMAX, + WNI_CFG_EXCLUDE_UNENCRYPTED_STADEF}, + {WNI_CFG_RTS_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RTS_THRESHOLD_STAMIN, + WNI_CFG_RTS_THRESHOLD_STAMAX, + WNI_CFG_RTS_THRESHOLD_STADEF}, + {WNI_CFG_SHORT_RETRY_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_SHORT_RETRY_LIMIT_STAMIN, + WNI_CFG_SHORT_RETRY_LIMIT_STAMAX, + WNI_CFG_SHORT_RETRY_LIMIT_STADEF}, + {WNI_CFG_LONG_RETRY_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_LONG_RETRY_LIMIT_STAMIN, + WNI_CFG_LONG_RETRY_LIMIT_STAMAX, + WNI_CFG_LONG_RETRY_LIMIT_STADEF}, + {WNI_CFG_FRAGMENTATION_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX, + WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF}, + {WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_JOIN_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF}, + {WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STAMIN, + WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STAMAX, + WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS_STADEF}, + {WNI_CFG_PS_ENABLE_BCN_FILTER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_BCN_FILTER_STAMIN, + WNI_CFG_PS_ENABLE_BCN_FILTER_STAMAX, + WNI_CFG_PS_ENABLE_BCN_FILTER_STADEF}, + {WNI_CFG_PS_ENABLE_HEART_BEAT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_HEART_BEAT_STAMIN, + WNI_CFG_PS_ENABLE_HEART_BEAT_STAMAX, + WNI_CFG_PS_ENABLE_HEART_BEAT_STADEF}, + {WNI_CFG_PS_ENABLE_RSSI_MONITOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMIN, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMAX, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STADEF}, + {WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF}, + {WNI_CFG_RF_SETTLING_TIME_CLK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RF_SETTLING_TIME_CLK_STAMIN, + WNI_CFG_RF_SETTLING_TIME_CLK_STAMAX, + WNI_CFG_RF_SETTLING_TIME_CLK_STADEF}, + {WNI_CFG_SUPPORTED_RATES_11B, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 3, 1}, + {WNI_CFG_SUPPORTED_RATES_11A, CFG_CTL_VALID | CFG_CTL_RE, + 0, 255, 15}, + {WNI_CFG_PHY_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PHY_MODE_STAMIN, + WNI_CFG_PHY_MODE_STAMAX, + WNI_CFG_PHY_MODE_STADEF}, + {WNI_CFG_DOT11_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_DOT11_MODE_STAMIN, + WNI_CFG_DOT11_MODE_STAMAX, + WNI_CFG_DOT11_MODE_STADEF}, + {WNI_CFG_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 1}, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 65534}, + {WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_LISTEN_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LISTEN_INTERVAL_STAMIN, + WNI_CFG_LISTEN_INTERVAL_STAMAX, + WNI_CFG_LISTEN_INTERVAL_STADEF}, + {WNI_CFG_VALID_CHANNEL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + 0, 1, 1}, + {WNI_CFG_CURRENT_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX, + WNI_CFG_CURRENT_CHANNEL_STADEF}, + {WNI_CFG_DEFAULT_RATE_INDEX_5GHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STAMIN, + WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STAMAX, + WNI_CFG_DEFAULT_RATE_INDEX_5GHZ_STADEF}, + {WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMIN, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMAX, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STADEF}, + {WNI_CFG_RATE_ADAPTATION_TYPE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_RATE_ADAPTATION_TYPE_STAMIN, + WNI_CFG_RATE_ADAPTATION_TYPE_STAMAX, + WNI_CFG_RATE_ADAPTATION_TYPE_STADEF}, + {WNI_CFG_FIXED_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FIXED_RATE_STAMIN, + WNI_CFG_FIXED_RATE_STAMAX, + WNI_CFG_FIXED_RATE_STADEF}, + {WNI_CFG_FIXED_RATE_MULTICAST_24GHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STAMIN, + WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STAMAX, + WNI_CFG_FIXED_RATE_MULTICAST_24GHZ_STADEF}, + {WNI_CFG_FIXED_RATE_MULTICAST_5GHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STAMIN, + WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STAMAX, + WNI_CFG_FIXED_RATE_MULTICAST_5GHZ_STADEF}, + {WNI_CFG_RETRYRATE_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RETRYRATE_POLICY_STAMIN, + WNI_CFG_RETRYRATE_POLICY_STAMAX, + WNI_CFG_RETRYRATE_POLICY_STADEF}, + {WNI_CFG_RETRYRATE_SECONDARY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RETRYRATE_SECONDARY_STAMIN, + WNI_CFG_RETRYRATE_SECONDARY_STAMAX, + WNI_CFG_RETRYRATE_SECONDARY_STADEF}, + {WNI_CFG_RETRYRATE_TERTIARY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RETRYRATE_TERTIARY_STAMIN, + WNI_CFG_RETRYRATE_TERTIARY_STAMAX, + WNI_CFG_RETRYRATE_TERTIARY_STADEF}, + {WNI_CFG_APSD_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_APSD_ENABLED_STAMIN, + WNI_CFG_APSD_ENABLED_STAMAX, + WNI_CFG_APSD_ENABLED_STADEF}, + {WNI_CFG_SHARED_KEY_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF}, + {WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF}, + {WNI_CFG_AUTHENTICATION_TYPE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_AUTHENTICATION_TYPE_STAMIN, + WNI_CFG_AUTHENTICATION_TYPE_STAMAX, + WNI_CFG_AUTHENTICATION_TYPE_STADEF}, + {WNI_CFG_CF_POLL_REQUEST, + CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_RESTART, + 0, 255, 1}, + {WNI_CFG_PRIVACY_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PRIVACY_ENABLED_STAMIN, + WNI_CFG_PRIVACY_ENABLED_STAMAX, + WNI_CFG_PRIVACY_ENABLED_STADEF}, + {WNI_CFG_SHORT_PREAMBLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_SHORT_PREAMBLE_STAMIN, + WNI_CFG_SHORT_PREAMBLE_STAMAX, + WNI_CFG_SHORT_PREAMBLE_STADEF}, + {WNI_CFG_SHORT_SLOT_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SHORT_SLOT_TIME_STAMIN, + WNI_CFG_SHORT_SLOT_TIME_STAMAX, + WNI_CFG_SHORT_SLOT_TIME_STADEF}, + {WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF}, + {WNI_CFG_QOS_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_QOS_ENABLED_STAMIN, + WNI_CFG_QOS_ENABLED_STAMAX, + WNI_CFG_QOS_ENABLED_STADEF}, + {WNI_CFG_HCF_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_HCF_ENABLED_STAMIN, + WNI_CFG_HCF_ENABLED_STAMAX, + WNI_CFG_HCF_ENABLED_STADEF}, + {WNI_CFG_RSN_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_RSN_ENABLED_STAMIN, + WNI_CFG_RSN_ENABLED_STAMAX, + WNI_CFG_RSN_ENABLED_STADEF}, + {WNI_CFG_MAX_NUM_PRE_AUTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX, + WNI_CFG_MAX_NUM_PRE_AUTH_STADEF}, + {WNI_CFG_PREAUTH_CLNUP_TIMEOUT, + CFG_CTL_INT, + 0, 255, 1}, + {WNI_CFG_RELEASE_AID_TIMEOUT, + CFG_CTL_INT, + 0, 255, 1}, + {WNI_CFG_HEART_BEAT_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX, + WNI_CFG_HEART_BEAT_THRESHOLD_STADEF}, + {WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | + CFG_CTL_INT, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF}, + {WNI_CFG_MANUFACTURER_OUI, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NUMBER, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_11D_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11D_ENABLED_STAMIN, + WNI_CFG_11D_ENABLED_STAMAX, + WNI_CFG_11D_ENABLED_STADEF}, + {WNI_CFG_MAX_TX_POWER_2_4, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_MAX_TX_POWER_5, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_NETWORK_DENSITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_NETWORK_DENSITY_STAMIN, + WNI_CFG_NETWORK_DENSITY_STAMAX, + WNI_CFG_NETWORK_DENSITY_STADEF}, + {WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STAMIN, + WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STAMAX, + WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_STADEF}, + {WNI_CFG_CURRENT_TX_ANTENNA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_CURRENT_TX_ANTENNA_STAMIN, + WNI_CFG_CURRENT_TX_ANTENNA_STAMAX, + WNI_CFG_CURRENT_TX_ANTENNA_STADEF}, + {WNI_CFG_CURRENT_RX_ANTENNA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_CURRENT_RX_ANTENNA_STAMIN, + WNI_CFG_CURRENT_RX_ANTENNA_STAMAX, + WNI_CFG_CURRENT_RX_ANTENNA_STADEF}, + {WNI_CFG_CURRENT_TX_POWER_LEVEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF}, + {WNI_CFG_NEW_BSS_FOUND_IND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_NEW_BSS_FOUND_IND_STAMIN, + WNI_CFG_NEW_BSS_FOUND_IND_STAMAX, + WNI_CFG_NEW_BSS_FOUND_IND_STADEF}, + {WNI_CFG_PROPRIETARY_RATES_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PROPRIETARY_RATES_ENABLED_STAMIN, + WNI_CFG_PROPRIETARY_RATES_ENABLED_STAMAX, + WNI_CFG_PROPRIETARY_RATES_ENABLED_STADEF}, + {WNI_CFG_AP_NODE_NAME, + CFG_CTL_RE, + 0, 255, 1}, + {WNI_CFG_COUNTRY_CODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_11H_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11H_ENABLED_STAMIN, + WNI_CFG_11H_ENABLED_STAMAX, + WNI_CFG_11H_ENABLED_STADEF}, + {WNI_CFG_WT_CNF_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WT_CNF_TIMEOUT_STAMIN, + WNI_CFG_WT_CNF_TIMEOUT_STAMAX, + WNI_CFG_WT_CNF_TIMEOUT_STADEF}, + {WNI_CFG_PROXIMITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PROXIMITY_STAMIN, + WNI_CFG_PROXIMITY_STAMAX, + WNI_CFG_PROXIMITY_STADEF}, + {WNI_CFG_LOG_LEVEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_LOG_LEVEL_STAMIN, + WNI_CFG_LOG_LEVEL_STAMAX, + WNI_CFG_LOG_LEVEL_STADEF}, + {WNI_CFG_OLBC_DETECT_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX, + WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF}, + {WNI_CFG_PROTECTION_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_PROTECTION_ENABLED_STAMIN, + WNI_CFG_PROTECTION_ENABLED_STAMAX, + WNI_CFG_PROTECTION_ENABLED_STADEF}, + {WNI_CFG_11G_PROTECTION_ALWAYS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX, + WNI_CFG_11G_PROTECTION_ALWAYS_STADEF}, + {WNI_CFG_FORCE_POLICY_PROTECTION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_HAL, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX, + WNI_CFG_FORCE_POLICY_PROTECTION_STADEF}, + {WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF}, + {WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF}, + {WNI_CFG_11G_ONLY_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_11G_ONLY_POLICY_STAMIN, + WNI_CFG_11G_ONLY_POLICY_STAMAX, + WNI_CFG_11G_ONLY_POLICY_STADEF}, + {WNI_CFG_PACKET_CLASSIFICATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PACKET_CLASSIFICATION_STAMIN, + WNI_CFG_PACKET_CLASSIFICATION_STAMAX, + WNI_CFG_PACKET_CLASSIFICATION_STADEF}, + {WNI_CFG_WME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_WME_ENABLED_STAMIN, + WNI_CFG_WME_ENABLED_STAMAX, + WNI_CFG_WME_ENABLED_STADEF}, + {WNI_CFG_ADDTS_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX, + WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF}, + {WNI_CFG_MAX_SP_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_MAX_SP_LENGTH_STAMIN, + WNI_CFG_MAX_SP_LENGTH_STAMAX, + WNI_CFG_MAX_SP_LENGTH_STADEF}, + {WNI_CFG_KEEP_ALIVE_STA_LIMIT_THRESHOLD, + CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + 0, 255, 1}, + {WNI_CFG_SEND_SINGLE_SSID_ALWAYS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STAMIN, + WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STAMAX, + WNI_CFG_SEND_SINGLE_SSID_ALWAYS_STADEF}, + {WNI_CFG_WSM_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WSM_ENABLED_STAMIN, + WNI_CFG_WSM_ENABLED_STAMAX, + WNI_CFG_WSM_ENABLED_STADEF}, + {WNI_CFG_EDCA_PROFILE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_EDCA_PROFILE_STAMIN, + WNI_CFG_EDCA_PROFILE_STAMAX, + WNI_CFG_EDCA_PROFILE_STADEF}, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_RDET_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RDET_FLAG_STAMIN, + WNI_CFG_RDET_FLAG_STAMAX, + WNI_CFG_RDET_FLAG_STADEF}, + {WNI_CFG_RADAR_CHANNEL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_LOCAL_POWER_CONSTRAINT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF}, + {WNI_CFG_ADMIT_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_POLICY_STAMIN, + WNI_CFG_ADMIT_POLICY_STAMAX, + WNI_CFG_ADMIT_POLICY_STADEF}, + {WNI_CFG_ADMIT_BWFACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_BWFACTOR_STAMIN, + WNI_CFG_ADMIT_BWFACTOR_STAMAX, + WNI_CFG_ADMIT_BWFACTOR_STADEF}, + {WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STAMIN, + WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STAMAX, + WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE_STADEF}, + {WNI_CFG_CHANNEL_BONDING_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_CHANNEL_BONDING_MODE_STAMIN, + WNI_CFG_CHANNEL_BONDING_MODE_STAMAX, + WNI_CFG_CHANNEL_BONDING_MODE_STADEF}, + {WNI_CFG_CB_SECONDARY_CHANNEL_STATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STAMIN, + WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STAMAX, + WNI_CFG_CB_SECONDARY_CHANNEL_STATE_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_ONE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_TWO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STADEF}, + {WNI_CFG_TRIG_STA_BK_SCAN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TRIG_STA_BK_SCAN_STAMIN, + WNI_CFG_TRIG_STA_BK_SCAN_STAMAX, + WNI_CFG_TRIG_STA_BK_SCAN_STADEF}, + {WNI_CFG_DYNAMIC_PROFILE_SWITCHING, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STAMIN, + WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STAMAX, + WNI_CFG_DYNAMIC_PROFILE_SWITCHING_STADEF}, + {WNI_CFG_SCAN_CONTROL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_MIMO_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RELOAD, + WNI_CFG_MIMO_ENABLED_STAMIN, + WNI_CFG_MIMO_ENABLED_STAMAX, + WNI_CFG_MIMO_ENABLED_STADEF}, + {WNI_CFG_BLOCK_ACK_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_BLOCK_ACK_ENABLED_STAMIN, + WNI_CFG_BLOCK_ACK_ENABLED_STAMAX, + WNI_CFG_BLOCK_ACK_ENABLED_STADEF}, + {WNI_CFG_HT_RX_STBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_RX_STBC_STAMIN, + WNI_CFG_HT_RX_STBC_STAMAX, + WNI_CFG_HT_RX_STBC_STADEF}, + {WNI_CFG_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_CAP_INFO_STAMIN, + WNI_CFG_HT_CAP_INFO_STAMAX, + WNI_CFG_HT_CAP_INFO_STADEF}, + {WNI_CFG_HT_AMPDU_PARAMS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_AMPDU_PARAMS_STAMIN, + WNI_CFG_HT_AMPDU_PARAMS_STAMAX, + WNI_CFG_HT_AMPDU_PARAMS_STADEF}, + {WNI_CFG_SUPPORTED_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_EXT_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_EXT_HT_CAP_INFO_STAMIN, + WNI_CFG_EXT_HT_CAP_INFO_STAMAX, + WNI_CFG_EXT_HT_CAP_INFO_STADEF}, + {WNI_CFG_TX_BF_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_TX_BF_CAP_STAMIN, + 4294967295u, + WNI_CFG_TX_BF_CAP_STADEF}, + {WNI_CFG_AS_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_AS_CAP_STAMIN, + WNI_CFG_AS_CAP_STAMAX, + WNI_CFG_AS_CAP_STADEF}, + {WNI_CFG_HT_INFO_FIELD1, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD1_STAMIN, + WNI_CFG_HT_INFO_FIELD1_STAMAX, + WNI_CFG_HT_INFO_FIELD1_STADEF}, + {WNI_CFG_HT_INFO_FIELD2, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD2_STAMIN, + WNI_CFG_HT_INFO_FIELD2_STAMAX, + WNI_CFG_HT_INFO_FIELD2_STADEF}, + {WNI_CFG_HT_INFO_FIELD3, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD3_STAMIN, + WNI_CFG_HT_INFO_FIELD3_STAMAX, + WNI_CFG_HT_INFO_FIELD3_STADEF}, + {WNI_CFG_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_CURRENT_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_GREENFIELD_CAPABILITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_GREENFIELD_CAPABILITY_STAMIN, + WNI_CFG_GREENFIELD_CAPABILITY_STAMAX, + WNI_CFG_GREENFIELD_CAPABILITY_STADEF}, + {WNI_CFG_VHT_MAX_MPDU_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF}, + {WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF}, + {WNI_CFG_VHT_LDPC_CODING_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX, + WNI_CFG_VHT_LDPC_CODING_CAP_STADEF}, + {WNI_CFG_VHT_SHORT_GI_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF}, + {WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF}, + {WNI_CFG_VHT_TXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXSTBC_STAMIN, + WNI_CFG_VHT_TXSTBC_STAMAX, + WNI_CFG_VHT_TXSTBC_STADEF}, + {WNI_CFG_VHT_RXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RXSTBC_STAMIN, + WNI_CFG_VHT_RXSTBC_STAMAX, + WNI_CFG_VHT_RXSTBC_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF}, + {WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_TXOP_PS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXOP_PS_STAMIN, + WNI_CFG_VHT_TXOP_PS_STAMAX, + WNI_CFG_VHT_TXOP_PS_STADEF}, + {WNI_CFG_VHT_HTC_VHTC_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX, + WNI_CFG_VHT_HTC_VHTC_CAP_STADEF}, + {WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF}, + {WNI_CFG_VHT_LINK_ADAPTATION_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF}, + {WNI_CFG_VHT_RX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_RX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_TX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_TX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_RX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_MCS_MAP_STAMIN, + WNI_CFG_VHT_RX_MCS_MAP_STAMAX, + WNI_CFG_VHT_RX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_TX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_MCS_MAP_STAMIN, + WNI_CFG_VHT_TX_MCS_MAP_STAMAX, + WNI_CFG_VHT_TX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STAMIN, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STAMAX, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1_STADEF}, + {WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STAMIN, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STAMAX, + WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2_STADEF}, + {WNI_CFG_VHT_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_BASIC_MCS_SET_STAMIN, + WNI_CFG_VHT_BASIC_MCS_SET_STAMAX, + WNI_CFG_VHT_BASIC_MCS_SET_STADEF}, + {WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF}, + {WNI_CFG_VHT_SS_UNDER_UTIL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX, + WNI_CFG_VHT_SS_UNDER_UTIL_STADEF}, + {WNI_CFG_VHT_40MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_80MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_160MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF, + WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF}, + {WNI_CFG_MAX_AMSDU_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MAX_AMSDU_LENGTH_STAMIN, + WNI_CFG_MAX_AMSDU_LENGTH_STAMAX, + WNI_CFG_MAX_AMSDU_LENGTH_STADEF}, + {WNI_CFG_MPDU_DENSITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MPDU_DENSITY_STAMIN, + WNI_CFG_MPDU_DENSITY_STAMAX, + WNI_CFG_MPDU_DENSITY_STADEF}, + {WNI_CFG_MAX_RX_AMPDU_FACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX}, + {WNI_CFG_SHORT_GI_20MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_SHORT_GI_20MHZ_STAMIN, + WNI_CFG_SHORT_GI_20MHZ_STAMAX, + WNI_CFG_SHORT_GI_20MHZ_STADEF}, + {WNI_CFG_SHORT_GI_40MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_SHORT_GI_40MHZ_STAMIN, + WNI_CFG_SHORT_GI_40MHZ_STAMAX, + WNI_CFG_SHORT_GI_40MHZ_STADEF}, + {WNI_CFG_RIFS_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_RIFS_ENABLED_STAMIN, + WNI_CFG_RIFS_ENABLED_STAMAX, + WNI_CFG_RIFS_ENABLED_STADEF}, + {WNI_CFG_MAX_PS_POLL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_MAX_PS_POLL_STAMIN, + WNI_CFG_MAX_PS_POLL_STAMAX, + WNI_CFG_MAX_PS_POLL_STADEF}, + {WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMIN, + WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMAX, + WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STADEF}, + {WNI_CFG_RSSI_FILTER_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_RSSI_FILTER_PERIOD_STAMIN, + WNI_CFG_RSSI_FILTER_PERIOD_STAMAX, + WNI_CFG_RSSI_FILTER_PERIOD_STADEF}, + {WNI_CFG_MIN_RSSI_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_MIN_RSSI_THRESHOLD_STAMIN, + WNI_CFG_MIN_RSSI_THRESHOLD_STAMAX, + WNI_CFG_MIN_RSSI_THRESHOLD_STADEF}, + {WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STAMIN, + WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STAMAX, + WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE_STADEF}, + {WNI_CFG_SCAN_IN_POWERSAVE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_SCAN_IN_POWERSAVE_STAMIN, + WNI_CFG_SCAN_IN_POWERSAVE_STAMAX, + WNI_CFG_SCAN_IN_POWERSAVE_STADEF}, + {WNI_CFG_IGNORE_DTIM, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IGNORE_DTIM_STAMIN, + WNI_CFG_IGNORE_DTIM_STAMAX, + WNI_CFG_IGNORE_DTIM_STADEF}, + {WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DEAUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DISASSOC_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF}, + {WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF}, + {WNI_CFG_BG_SCAN_CHANNEL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_MAX_MEDIUM_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_MAX_MEDIUM_TIME_STAMIN, + WNI_CFG_MAX_MEDIUM_TIME_STAMAX, + WNI_CFG_MAX_MEDIUM_TIME_STADEF}, + {WNI_CFG_MAX_MPDUS_IN_AMPDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_MAX_MPDUS_IN_AMPDU_STAMIN, + WNI_CFG_MAX_MPDUS_IN_AMPDU_STAMAX, + WNI_CFG_MAX_MPDUS_IN_AMPDU_STADEF}, + {WNI_CFG_IBSS_AUTO_BSSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_AUTO_BSSID_STAMIN, + WNI_CFG_IBSS_AUTO_BSSID_STAMAX, + WNI_CFG_IBSS_AUTO_BSSID_STADEF}, + {WNI_CFG_PROBE_REQ_ADDNIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STAMIN, + WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STAMAX, + WNI_CFG_PROBE_REQ_ADDNIE_FLAG_STADEF}, + {WNI_CFG_PROBE_REQ_ADDNIE_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_PROBE_RSP_ADDNIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STAMIN, + WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STAMAX, + WNI_CFG_PROBE_RSP_ADDNIE_FLAG_STADEF}, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA1, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA2, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA3, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_ASSOC_RSP_ADDNIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STAMIN, + WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STAMAX, + WNI_CFG_ASSOC_RSP_ADDNIE_FLAG_STADEF}, + {WNI_CFG_ASSOC_RSP_ADDNIE_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STAMIN, + WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STAMAX, + WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG_STADEF}, + {WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMIN, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMAX, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STADEF}, + {WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_WPS_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_ENABLE_STAMIN, + WNI_CFG_WPS_ENABLE_STAMAX, + WNI_CFG_WPS_ENABLE_STADEF}, + {WNI_CFG_WPS_STATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_STATE_STAMIN, + WNI_CFG_WPS_STATE_STAMAX, + WNI_CFG_WPS_STATE_STADEF}, + {WNI_CFG_WPS_PROBE_REQ_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PROBE_REQ_FLAG_STAMIN, + WNI_CFG_WPS_PROBE_REQ_FLAG_STAMAX, + WNI_CFG_WPS_PROBE_REQ_FLAG_STADEF}, + {WNI_CFG_WPS_VERSION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_VERSION_STAMIN, + WNI_CFG_WPS_VERSION_STAMAX, + WNI_CFG_WPS_VERSION_STADEF}, + {WNI_CFG_WPS_REQUEST_TYPE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_REQUEST_TYPE_STAMIN, + WNI_CFG_WPS_REQUEST_TYPE_STAMAX, + WNI_CFG_WPS_REQUEST_TYPE_STADEF}, + {WNI_CFG_WPS_CFG_METHOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_CFG_METHOD_STAMIN, + 4294967295u, + WNI_CFG_WPS_CFG_METHOD_STADEF}, + {WNI_CFG_WPS_UUID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF}, + {WNI_CFG_WPS_PIMARY_DEVICE_OUI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN, + 4294967295u, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF}, + {WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF}, + {WNI_CFG_WPS_ASSOCIATION_STATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_ASSOCIATION_STATE_STAMIN, + WNI_CFG_WPS_ASSOCIATION_STATE_STAMAX, + WNI_CFG_WPS_ASSOCIATION_STATE_STADEF}, + {WNI_CFG_WPS_CONFIGURATION_ERROR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_CONFIGURATION_ERROR_STAMIN, + WNI_CFG_WPS_CONFIGURATION_ERROR_STAMAX, + WNI_CFG_WPS_CONFIGURATION_ERROR_STADEF}, + {WNI_CFG_WPS_DEVICE_PASSWORD_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN, + 4294967295u, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF}, + {WNI_CFG_WPS_ASSOC_METHOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_ASSOC_METHOD_STAMIN, + WNI_CFG_WPS_ASSOC_METHOD_STAMAX, + WNI_CFG_WPS_ASSOC_METHOD_STADEF}, + {WNI_CFG_LOW_GAIN_OVERRIDE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN, + WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX, + WNI_CFG_LOW_GAIN_OVERRIDE_STADEF}, + {WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STAMIN, + WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STAMAX, + WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE_STADEF}, + {WNI_CFG_RPE_POLLING_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RPE_POLLING_THRESHOLD_STAMIN, + WNI_CFG_RPE_POLLING_THRESHOLD_STAMAX, + WNI_CFG_RPE_POLLING_THRESHOLD_STADEF}, + {WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STAMIN, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STAMAX, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG_STADEF}, + {WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STAMIN, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STAMAX, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG_STADEF}, + {WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STAMIN, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STAMAX, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG_STADEF}, + {WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STAMIN, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STAMAX, + WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG_STADEF}, + {WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STAMIN, + WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STAMAX, + WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS_STADEF}, + {WNI_CFG_SINGLE_TID_RC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SINGLE_TID_RC_STAMIN, + WNI_CFG_SINGLE_TID_RC_STAMAX, + WNI_CFG_SINGLE_TID_RC_STADEF}, + {WNI_CFG_RRM_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RRM_ENABLED_STAMIN, + WNI_CFG_RRM_ENABLED_STAMAX, + WNI_CFG_RRM_ENABLED_STADEF}, + {WNI_CFG_RRM_OPERATING_CHAN_MAX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RRM_OPERATING_CHAN_MAX_STAMIN, + WNI_CFG_RRM_OPERATING_CHAN_MAX_STAMAX, + WNI_CFG_RRM_OPERATING_CHAN_MAX_STADEF}, + {WNI_CFG_RRM_NON_OPERATING_CHAN_MAX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STAMIN, + WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STAMAX, + WNI_CFG_RRM_NON_OPERATING_CHAN_MAX_STADEF}, + {WNI_CFG_TX_PWR_CTRL_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TX_PWR_CTRL_ENABLE_STAMIN, + WNI_CFG_TX_PWR_CTRL_ENABLE_STAMAX, + WNI_CFG_TX_PWR_CTRL_ENABLE_STADEF}, + {WNI_CFG_MCAST_BCAST_FILTER_SETTING, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMIN, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMAX, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STADEF}, + {WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STAMIN, + WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STAMAX, + WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK_STADEF}, + {WNI_CFG_DYNAMIC_PS_POLL_VALUE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMIN, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMAX, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STADEF}, + {WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF}, + {WNI_CFG_TELE_BCN_WAKEUP_EN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX, + WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF}, + {WNI_CFG_TELE_BCN_TRANS_LI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_TRANS_LI_STAMIN, + WNI_CFG_TELE_BCN_TRANS_LI_STAMAX, + WNI_CFG_TELE_BCN_TRANS_LI_STADEF}, + {WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMIN, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMAX, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STADEF}, + {WNI_CFG_TELE_BCN_MAX_LI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_MAX_LI_STAMIN, + WNI_CFG_TELE_BCN_MAX_LI_STAMAX, + WNI_CFG_TELE_BCN_MAX_LI_STADEF}, + {WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMIN, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMAX, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STADEF}, + {WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STAMIN, + WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STAMAX, + WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS_STADEF}, + {WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF}, + {WNI_CFG_ASSOC_STA_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOC_STA_LIMIT_STAMIN, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX, + WNI_CFG_ASSOC_STA_LIMIT_STADEF}, + {WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STAMIN, + WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STAMAX, + WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL_STADEF}, + {WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STAMIN, + WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STAMAX, + WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL_STADEF}, + {WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STAMIN, + WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STAMAX, + WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND_STADEF}, + {WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF}, + {WNI_CFG_ENABLE_CLOSE_LOOP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_CLOSE_LOOP_STAMIN, + WNI_CFG_ENABLE_CLOSE_LOOP_STAMAX, + WNI_CFG_ENABLE_CLOSE_LOOP_STADEF}, + {WNI_CFG_ENABLE_LTE_COEX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_LTE_COEX_STAMIN, + WNI_CFG_ENABLE_LTE_COEX_STAMAX, + WNI_CFG_ENABLE_LTE_COEX_STADEF}, + {WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_ENABLE_MC_ADDR_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX, + WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF}, + {WNI_CFG_ENABLE_UC_FILTER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_UC_FILTER_STAMIN, + WNI_CFG_ENABLE_UC_FILTER_STAMAX, + WNI_CFG_ENABLE_UC_FILTER_STADEF}, + {WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF}, + {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF}, + {WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF}, + {WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF}, + {WNI_CFG_TDLS_BUF_STA_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX, + WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF}, + {WNI_CFG_TDLS_PUAPSD_INACT_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF}, + {WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF}, + {WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF}, + {WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF}, + {WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF}, + {WNI_CFG_FLEX_CONNECT_POWER_FACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STAMIN, + WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STAMAX, + WNI_CFG_FLEX_CONNECT_POWER_FACTOR_STADEF}, + {WNI_CFG_ANTENNA_DIVESITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ANTENNA_DIVESITY_STAMIN, + WNI_CFG_ANTENNA_DIVESITY_STAMAX, + WNI_CFG_ANTENNA_DIVESITY_STADEF}, + {WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF}, + {WNI_CFG_CURRENT_RSSI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_RSSI_STAMIN, + WNI_CFG_CURRENT_RSSI_STAMAX, + WNI_CFG_CURRENT_RSSI_STADEF}, + {WNI_CFG_RTT3_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RTT3_ENABLE_STAMIN, + WNI_CFG_RTT3_ENABLE_STAMAX, + WNI_CFG_RTT3_ENABLE_STADEF}, + {WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF}, + {WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF}, + {WNI_CFG_IBSS_ATIM_WIN_SIZE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF}, + {WNI_CFG_DFS_MASTER_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DFS_MASTER_ENABLED_STAMIN, + WNI_CFG_DFS_MASTER_ENABLED_STAMAX, + WNI_CFG_DFS_MASTER_ENABLED_STADEF}, + {WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF}, + {WNI_CFG_TDLS_WMM_MODE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF} +}; + + +cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING] = { + + {WNI_CFG_STA_ID, + WNI_CFG_STA_ID_LEN, + 6, + {0x22, 0x22, 0x44, 0x44, 0x33, 0x33} }, + {WNI_CFG_SSID, + WNI_CFG_SSID_LEN, + 10, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 0} }, + {WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_1_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_2_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_3_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEY_4_LEN, + 0, + {0} }, + {WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11B_LEN, + 4, + {2, 4, 11, 22} }, + {WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_SUPPORTED_RATES_11A_LEN, + 8, + {12, 18, 24, 36, 48, 72, 96, 108} }, + {WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET_LEN, + 4, + {1, 3, 5, 7} }, + {WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_VALID_CHANNEL_LIST_LEN, + 55, + {36, 40, 44, 48, 52, 56, 60, 64, 1, 6, 11, 34, 38, 42, 46, 2, 3, 4, + 5, 7, 8, 9, 10, 12, 13, 14, 100, 104, 108, 112, 116, 120, 124, 128, + 132, 136, 140, 149, 151, 153, 155, 157, 159, 161, 50, 54, 58, 62, 240, + 242, 244, 246, 248, 250, 252} }, + + {WNI_CFG_MANUFACTURER_OUI, + WNI_CFG_MANUFACTURER_OUI_LEN, + 3, + {0x0, 0xa, 0xf5} }, + {WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MANUFACTURER_NAME_LEN, + 8, + {0x51, 0x75, 0x61, 0x6c, 0x63, 0x6f, 0x6d, 0x6d} }, + {WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NUMBER_LEN, + 6, + {0x4d, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MODEL_NAME, + WNI_CFG_MODEL_NAME_LEN, + 7, + {0x57, 0x46, 0x52, 0x34, 0x30, 0x33, 0x31} }, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN, + 6, + {0x31, 0x31, 0x6e, 0x2d, 0x41, 0x50} }, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN, + 6, + {0x53, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_2_4_LEN, + 3, + {0x1, 0xe, 0x14} }, + {WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_MAX_TX_POWER_5_LEN, + 3, + {0x24, 0x7e, 0x14} }, + {WNI_CFG_AP_NODE_NAME, + WNI_CFG_AP_NODE_NAME_LEN, + 0, + {0} }, + {WNI_CFG_COUNTRY_CODE, + WNI_CFG_COUNTRY_CODE_LEN, + 0, + {0} }, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, 0xbc, 0x0, + 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, + 0x3, 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACBE_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVI_LEN, + 17, {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, + 0xbc, 0x0, 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_ANI_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN, + 17, {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN, + 17, {0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x0, 0x3f, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACBE_LEN, + 17, + {0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVI_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_EDCA_WME_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_RADAR_CHANNEL_LIST, + WNI_CFG_RADAR_CHANNEL_LIST_LEN, + 15, + {0x34, 0x38, 0x3c, 0x40, 0x64, 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c, 0x80, + 0x84, 0x88, 0x8c} }, + {WNI_CFG_SCAN_CONTROL_LIST, + WNI_CFG_SCAN_CONTROL_LIST_LEN, + 114, + {0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x4, 0x1, 0x5, 0x1, 0x6, 0x1, 0x7, 0x1, + 0x8, 0x1, 0x9, 0x1, 0xa, 0x1, 0xb, 0x1, 0xc, 0x1, 0xd, 0x1, 0xe, 0x1, + 0x22, 0x1, 0x24, 0x1, 0x26, 0x1, 0x28, 0x1, 0x2a, 0x1, 0x2c, 0x1, 0x2e, + 0x1, 0x30, 0x1, 0x32, 0x1, 0x34, 0x0, 0x36, 0x0, 0x38, 0x0, 0x3a, 0x0, + 0x3c, 0x0, 0x3e, 0x0, 0x40, 0x0, 0x64, 0x0, 0x68, 0x0, 0x6c, 0x0, 0x70, + 0x0, 0x74, 0x0, 0x78, 0x0, 0x7c, 0x0, 0x80, 0x0, 0x84, 0x0, 0x88, 0x0, + 0x8c, 0x0, 0x90, 0x0, 0x95, 0x1, 0x97, 0x1, 0x99, 0x1, 0x9b, 0x1, 0x9d, + 0x1, 0x9f, 0x1, 0xa1, 0x1, 0xa5, 0x1, 0xf0, 0x1, 0xf2, 0x1, 0xf4, 0x1, + 0xf6, 0x1, 0xf8, 0x1, 0xfa, 0x1, 0xfc, 0x1} }, + {WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_SUPPORTED_MCS_SET_LEN, + 16, + {0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_BASIC_MCS_SET, + WNI_CFG_BASIC_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_CURRENT_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_BG_SCAN_CHANNEL_LIST, + WNI_CFG_BG_SCAN_CHANNEL_LIST_LEN, + 55, + {0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c, 0x40, 0x1, 0x6, 0xb, 0x22, + 0x26, 0x2a, 0x2e, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8, 0x9, 0xa, 0xc, 0xd, + 0xe, 0x64, 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c, 0x80, 0x84, 0x88, 0x8c, + 0x95, 0x97, 0x99, 0x9b, 0x9d, 0x9f, 0xa1, 0x32, 0x36, 0x3a, 0x3e, 0xf0, + 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc} }, + {WNI_CFG_PROBE_REQ_ADDNIE_DATA, + WNI_CFG_PROBE_REQ_ADDNIE_DATA_LEN, + 0, + {0} }, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA1, + WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN, + 0, + {0} }, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA2, + WNI_CFG_PROBE_RSP_ADDNIE_DATA2_LEN, + 0, + {0} }, + {WNI_CFG_PROBE_RSP_ADDNIE_DATA3, + WNI_CFG_PROBE_RSP_ADDNIE_DATA3_LEN, + 0, + {0} }, + {WNI_CFG_ASSOC_RSP_ADDNIE_DATA, + WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN, + 0, + {0} }, + {WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA, + WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA_LEN, + 0, + {0} }, + {WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN, + 0, + {0} }, + {WNI_CFG_WPS_UUID, + WNI_CFG_WPS_UUID_LEN, + 6, + {0xa, 0xb, 0xc, 0xd, 0xe, 0xf} } +}; + +/*--------------------------------------------------------------------*/ +/* Static function prototypes */ +/*--------------------------------------------------------------------*/ +static void proc_dnld_rsp(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_get_req(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_set_req(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_set_req_no_rsp(tpAniSirGlobal, uint16_t, uint32_t *); + +static uint8_t check_param(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *); +static void get_str_value(uint8_t *, uint8_t *, uint32_t); + +/*--------------------------------------------------------------------*/ +/* Module global variables */ +/*--------------------------------------------------------------------*/ + +/* CFG function table */ +void (*g_cfg_func[])(tpAniSirGlobal, uint16_t, uint32_t *) = { + proc_dnld_rsp, proc_get_req, proc_set_req, proc_set_req_no_rsp +}; + +/**--------------------------------------------------------------------- + * cfg_process_mb_msg() + * + ***FUNCTION: + * CFG mailbox message processing function. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * None. + * + ***NOTE: + * + * @param pMsg Message pointer + * + * @return None. + * + */ +void cfg_process_mb_msg(tpAniSirGlobal pMac, tSirMbMsg *pMsg) +{ + uint16_t index; + uint16_t len; + uint32_t *pParam; + + /* Use type[7:0] as index to function table */ + index = CFG_GET_FUNC_INDX(pMsg->type); + + if (index >= CDF_ARRAY_SIZE(g_cfg_func)) { + cdf_mem_free(pMsg); + return; + } + len = pMsg->msgLen - WNI_CFG_MB_HDR_LEN; + pParam = ((uint32_t *) pMsg) + 1; + + /* Call processing function */ + g_cfg_func[index] (pMac, len, pParam); + + /* Free up buffer */ + cdf_mem_free(pMsg); + +} /*** end cfg_process_mb_msg() ***/ + +/**--------------------------------------------------------------------- + * proc_dnld_rsp() + * + * FUNCTION: + * This function processes CFG_DNLD_RSP message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_dnld_rsp(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + int32_t i; + + uint32_t expLen, retVal, bufStart, bufEnd; + uint32_t *pSrc, *pDst, *pDstEnd; + uint32_t strSize, j; + uint8_t pStr[CFG_MAX_STR_LEN]; + tpCfgBinHdr pHdr; + uint32_t logLevel; + tSirMsgQ mmhMsg; + + /* First Dword must contain the AP or STA magic dword */ + PELOGW(cfg_log(pMac, LOGW, FL("CFG size %d bytes MAGIC dword is 0x%x"), + length, sir_read_u32_n((uint8_t *) pParam)); + ) + /* if the string is not correct, return failure */ + if (*pParam == CFG_STA_MAGIC_DWORD) { + } + + else { + PELOGE(cfg_log + (pMac, LOGE, FL("Invalid magic dword 0x%x"), + sir_read_u32_n((uint8_t *) pParam)); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + pParam++; + length -= 4; + + /* Verify message length */ + { + pMac->cfg.gCfgMaxIBufSize = CFG_STA_IBUF_MAX_SIZE; + pMac->cfg.gCfgMaxSBufSize = CFG_STA_SBUF_MAX_SIZE; + } + + /* Parse the Cfg header */ + pHdr = (tpCfgBinHdr) pParam; + pParam += (sizeof(tCfgBinHdr) >> 2); + PELOGW(cfg_log + (pMac, LOGW, + FL("CFG hdr totParams %d intParams %d strBufSize %d/%d"), + pHdr->controlSize, pHdr->iBufSize, pHdr->sBufSize, + pMac->cfg.gCfgMaxSBufSize); + ) + + expLen = + ((CFG_PARAM_MAX_NUM + 3 * pMac->cfg.gCfgMaxIBufSize) << 2) + + pHdr->sBufSize + sizeof(tCfgBinHdr); + + if (length != expLen) { + PELOGE(cfg_log + (pMac, LOGE, + FL(" DNLD_RSP invalid length %d (exp %d)"), length, + expLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->controlSize != CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log + (pMac, LOGE, FL(" Total parameter count mismatch")); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->iBufSize != pMac->cfg.gCfgMaxIBufSize) { + PELOGE(cfg_log + (pMac, LOGE, + FL(" Integer parameter count mismatch")); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + /* Copy control array */ + pDst = (uint32_t *) pMac->cfg.gCfgEntry; + pDstEnd = pDst + CFG_PARAM_MAX_NUM; + pSrc = pParam; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + /* Copy default values */ + pDst = pMac->cfg.gCfgIBuf; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy min values */ + pDst = pMac->cfg.gCfgIBufMin; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy max values */ + pDst = pMac->cfg.gCfgIBufMax; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + for (i = 0; i < pMac->cfg.gCfgMaxIBufSize; i++) + if (pMac->cfg.gCfgIBuf[i] < pMac->cfg.gCfgIBufMin[i] || + pMac->cfg.gCfgIBuf[i] > pMac->cfg.gCfgIBufMax[i]) { + PELOGE(cfg_log + (pMac, LOGE, + FL("cfg id %d Invalid def value %d " + "min %d max %d"), i, pMac->cfg.gCfgIBuf[i], + pMac->cfg.gCfgIBufMin[i], + pMac->cfg.gCfgIBufMax[i]); + ) + } + /* Calculate max string buffer lengths for all string parameters */ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = + (uint8_t) (bufEnd - bufStart - 2); + + PELOG1(cfg_log + (pMac, LOG1, FL("id %d max %d bufStart %d bufEnd %d"), i, + pMac->cfg.gCfgSBuf[bufStart], bufStart, bufEnd); + ) + + bufEnd = bufStart; + } + + /* Initialize string defaults */ + strSize = pHdr->sBufSize; + while (strSize) { + uint32_t paramId, paramLen, paramLenCeil4; + + if (strSize < 4) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error parsing str defaults, rem %d bytes"), + strSize); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + paramId = *pSrc >> 16; + paramLen = *pSrc & 0xff; + pSrc++; + strSize -= 4; + + paramLenCeil4 = ((paramLen + 3) >> 2); + if (strSize < paramLenCeil4 << 2) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error parsing str defaults, rem %d bytes"), + strSize); + ) + PELOGE(cfg_log + (pMac, LOGE, FL("param id %d len %d bytes"), + paramId, paramLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + for (j = 0; j < paramLenCeil4; j++) { + pStr[4 * j] = (uint8_t) (*pSrc >> 24) & 0xff; + pStr[4 * j + 1] = (uint8_t) (*pSrc >> 16) & 0xff; + pStr[4 * j + 2] = (uint8_t) (*pSrc >> 8) & 0xff; + pStr[4 * j + 3] = (uint8_t) (*pSrc) & 0xff; + + pSrc++; + strSize -= 4; + } + + PELOG1(cfg_log + (pMac, LOG1, FL("set str id %d len %d"), paramId, + paramLen); + ) + + if (cfg_set_str(pMac, (uint16_t) paramId, pStr, paramLen) != + eSIR_SUCCESS) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error setting str default param %d len %d"), + paramId, paramLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + } + + /* Set the default log level based on config */ + wlan_cfg_get_int(pMac, WNI_CFG_LOG_LEVEL, &logLevel); + for (i = 0; i < LOG_ENTRY_NUM; i++) + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + logLevel; + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + PELOG1(cfg_log(pMac, LOG1, " Completed successfully");) + +end : + + if (retVal != WNI_CFG_SUCCESS) + pMac->cfg.gCfgStatus = CFG_FAILURE; + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + cfg_send_host_msg(pMac, WNI_CFG_DNLD_CNF, WNI_CFG_DNLD_CNF_LEN, + WNI_CFG_DNLD_CNF_NUM, pMac->cfg.gParamList, 0, 0); + + /* notify WMA that the config has downloaded */ + mmhMsg.type = SIR_CFG_DOWNLOAD_COMPLETE_IND; + mmhMsg.bodyptr = NULL; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + if (wma_post_ctrl_msg(pMac, &mmhMsg) != eSIR_SUCCESS) { + PELOGE(cfg_log(pMac, LOGE, FL("WMAPostMsgApi failed!"));) + } + +} /*** end procDnldRsp() ***/ + +/**--------------------------------------------------------------------- + * proc_get_req() + * + * FUNCTION: + * This function processes CFG_GET_REQ message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * For every parameter ID specified on the list, CFG will send a separate + * CFG_GET_RSP back to host. + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_get_req(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + uint16_t cfgId, i; + uint32_t value, valueLen, result; + uint32_t *pValue; + + PELOG1(cfg_log(pMac, LOG1, FL("Rcvd cfg get request %d bytes"), length);) + for (i = 0; i < length / 4; i++) + PELOG2(cfg_log(pMac, LOG2, FL("[%2d] 0x%08x"), i, pParam[i]);) + + if (!pMac->cfg.gCfgStatus) { + cfgId = (uint16_t) sir_read_u32_n((uint8_t *) pParam); + PELOGE(cfg_log(pMac, LOGE, FL("CFG not ready, param %d"), cfgId);) + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = + WNI_CFG_NOT_READY; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = 0; + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN, WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, 0, 0); + } else { + /* Process all parameter ID's on the list */ + while (length >= sizeof(uint32_t)) { + cfgId = (uint16_t) *pParam++; + pValue = 0; + valueLen = 0; + + PELOG1(cfg_log + (pMac, LOG1, FL("Cfg get param %d"), cfgId); + ) + /* Check for valid parameter ID, etc... */ + if (check_param + (pMac, cfgId, CFG_CTL_RE, WNI_CFG_WO_PARAM, + &result)) { + if ((pMac->cfg.gCfgEntry[cfgId]. + control & CFG_CTL_INT) != 0) { + /* Get integer parameter */ + result = + (wlan_cfg_get_int(pMac, cfgId, &value) + == + eSIR_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = &value; + valueLen = sizeof(uint32_t); + } else { + /* Get string parameter */ + valueLen = sizeof(pMac->cfg.gSBuffer); + result = + (wlan_cfg_get_str + (pMac, cfgId, pMac->cfg.gSBuffer, + &valueLen) + == eSIR_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = + (uint32_t *) pMac->cfg.gSBuffer; + } + } else { + PELOGE(cfg_log + (pMac, LOGE, + FL("Check param failed, param %d"), + cfgId); + ) + result = WNI_CFG_INVALID_LEN; + } + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = result; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = valueLen; + + /* We need to round up buffer length to word-increment */ + valueLen = (((valueLen + 3) >> 2) << 2); + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN + valueLen, + WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, valueLen, pValue); + + /* Decrement length */ + length -= sizeof(uint32_t); + } + } + +} /*** end procGetReq() ***/ + +/**--------------------------------------------------------------------- + * proc_set_req_internal() + * + * FUNCTION: + * This function processes CFG_SET_REQ message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * - The message content is coded in TLV format. + * - For string parameter, the length field is byte accurate. However, + * the next TLV set will begin on the next word boundary. + * + * NOTE: + * - For every parameter ID specified on the list, CFG will send a separate + * CFG_SET_RSP back to host. + * + * @param length: message length + * @param pParam: parameter list pointer + * @param fRsp: whether to send response to host. true means sending. + * @return None + * + */ +static void +proc_set_req_internal(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam, + bool fRsp) +{ + uint16_t cfgId, valueLen, valueLenRoundedUp4; + uint32_t value, result; + + PELOG1(cfg_log(pMac, LOGl, FL("Rcvd cfg set request %d bytes"), length);) + + if (!pMac->cfg.gCfgStatus) { + cfgId = (uint16_t) sir_read_u32_n((uint8_t *) pParam); + PELOG1(cfg_log(pMac, LOGW, FL("CFG not ready, param %d"), cfgId);) + pMac->cfg.gParamList[WNI_CFG_SET_CNF_RES] = + WNI_CFG_NOT_READY; + pMac->cfg.gParamList[WNI_CFG_SET_CNF_PID] = cfgId; + if (fRsp) { + cfg_send_host_msg(pMac, WNI_CFG_SET_CNF, + WNI_CFG_SET_CNF_LEN, WNI_CFG_SET_CNF_NUM, + pMac->cfg.gParamList, 0, 0); + } + } else { + /* Process all TLVs in buffer */ + while (length >= (sizeof(uint32_t) * 2)) { + cfgId = (uint16_t) *pParam++; + valueLen = (uint16_t) *pParam++; + length -= (sizeof(uint32_t) * 2); + /* value length rounded up to a 4 byte multiple */ + valueLenRoundedUp4 = (((valueLen + 3) >> 2) << 2); + + /* Check for valid request before proceeding */ + if (check_param + (pMac, cfgId, CFG_CTL_WE, WNI_CFG_RO_PARAM, + &result)) { + PELOG1(cfg_log + (pMac, LOGW, + (char *)g_cfg_param_name[cfgId]); + ) + /* Process integer parameter */ + if ((pMac->cfg.gCfgEntry[cfgId]. + control & CFG_CTL_INT) != 0) { + /* Set VALUE */ + if (valueLen != sizeof(uint32_t)) { + PELOGE(cfg_log + (pMac, LOGE, + FL + ("Invalid value length %d in set param %d (tot %d)"), + valueLen, cfgId, + length); + ) + result = + WNI_CFG_INVALID_LEN; + } else { + value = *pParam; + PELOG1(cfg_log + (pMac, LOGW, + FL + ("Cfg set int %d len %d(%d) val %d"), + cfgId, valueLen, + valueLenRoundedUp4, + value); + ) + result = + (cfg_set_int + (pMac, cfgId, + value) == + eSIR_SUCCESS ? + WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + if (result == WNI_CFG_SUCCESS) { + if (cfg_need_restart + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RESTART; + } else + if (cfg_need_reload + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RELOAD; + } + } + } + } + /* Process string parameter */ + else { + if (valueLenRoundedUp4 > length) { + PELOGE(cfg_log + (pMac, LOGE, + FL + ("Invalid string length %d" + "in set param %d (tot %d)"), + valueLen, cfgId, + length); + ) + result = + WNI_CFG_INVALID_LEN; + } else { + get_str_value((uint8_t *) pParam, + pMac->cfg.gSBuffer, + valueLen); + PELOG1(cfg_log + (pMac, LOGW, + FL + ("Cfg set str %d len %d(%d) bytes"), + cfgId, valueLen, + valueLenRoundedUp4); + ) + result = + (cfg_set_str + (pMac, cfgId, + pMac->cfg.gSBuffer, + valueLen) == + eSIR_SUCCESS ? + WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + if (result == WNI_CFG_SUCCESS) { + if (cfg_need_restart + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RESTART; + } else + if (cfg_need_reload + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RELOAD; + } + } + } + } + } else { + PELOGE(cfg_log + (pMac, LOGE, + FL("Check param failed, param %d"), + cfgId); + ) + result = WNI_CFG_INVALID_LEN; + } + + /* Send confirm message to host */ + pMac->cfg.gParamList[WNI_CFG_SET_CNF_RES] = result; + pMac->cfg.gParamList[WNI_CFG_SET_CNF_PID] = cfgId; + if (fRsp) { + cfg_send_host_msg(pMac, WNI_CFG_SET_CNF, + WNI_CFG_SET_CNF_LEN, + WNI_CFG_SET_CNF_NUM, + pMac->cfg.gParamList, 0, 0); + } else { + PELOGW(cfg_log + (pMac, LOG2, " CFGID %d no rsp", cfgId); + ) + } + + if (valueLenRoundedUp4 > length) + length = 0; + else { + length -= valueLenRoundedUp4; + pParam += (valueLenRoundedUp4 >> 2); + } + } + } +} + +static void proc_set_req(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + proc_set_req_internal(pMac, length, pParam, true); +} + +static void +proc_set_req_no_rsp(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + proc_set_req_internal(pMac, length, pParam, false); +} + +/**--------------------------------------------------------------------- + * check_param() + * + * FUNCTION: + * This function is called to perform various check on a parameter. + * + * LOGIC: + * - If cfgId is out of bound or parameter is not valid, result + * WNI_CFG_INVALID_PID is returned at address specified in pResult. + * + * - If specified 'flag' is not set in the parameter control entry, + * 'failedResult' is returned at address specified in pResult. + * + * ASSUMPTIONS: + * Since this function is used internally, 'pResult' is always valid. + * + * NOTE: + * + * @param None + * + * @return true: Parameter is valid and matches checked condition \n + * @return false: Parameter either is not valid or does not match + * checked condition. + * + */ +static uint8_t +check_param(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t flag, + uint32_t failedResult, uint32_t *pResult) +{ + /* Check if parameter ID is out of bound */ + if (cfgId >= CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log(pMac, LOGE, FL("Invalid param id %d"), cfgId);) + * pResult = WNI_CFG_INVALID_PID; + } else { + /* Check if parameter is valid */ + if ((pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_VALID) == 0) { + PELOGE(cfg_log + (pMac, LOGE, FL("Param id %d not valid"), cfgId); + ) + * pResult = WNI_CFG_INVALID_PID; + } else { + /* Check control field against flag */ + if ((pMac->cfg.gCfgEntry[cfgId].control & flag) == 0) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Param id %d wrong permissions %x"), + cfgId, + pMac->cfg.gCfgEntry[cfgId].control); + ) + * pResult = failedResult; + } else + return true; + } + } + return false; + +} /*** cfgParamCheck() ***/ + +/**--------------------------------------------------------------------- + * get_str_value() + * + * FUNCTION: + * This function copies a string value from the specified buffer. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBuf: input data buffer + * @param pValue: address where data is returned + * @param length: number of bytes to copy + * + * @return None + * + */ +static void get_str_value(uint8_t *pBuf, uint8_t *pValue, uint32_t length) +{ + uint8_t *pEnd; + + pEnd = pValue + length; + while (pValue < pEnd) + *pValue++ = *pBuf++; +} /*** end get_str_value() ***/ + +/**--------------------------------------------------------------------- + * process_cfg_download_req() + * + * FUNCTION: This function does the Cfg Download and is invoked + * only in the case of Prima or the Integrated SOC + * solutions. Not applicable to Volans or Libra + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac: Pointer to Mac Structure + * + * @return None + * + */ + +void +process_cfg_download_req(tpAniSirGlobal pMac) +{ + int32_t i; + uint32_t index; + uint8_t *pDstTest, *pSrcTest; + uint8_t len; + cfgstatic_string *pStrCfg; + uint32_t bufStart, bufEnd; + uint32_t logLevel, retVal; + uint32_t iCount = 0; + uint32_t sCount = 0; + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + if ((cfg_static[i].control & CFG_CTL_VALID) != 0) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + pStrCfg = (cfgstatic_string *)cfg_static[i]. + pStrData; + if (pStrCfg == NULL) { + PELOGE(cfg_log(pMac, LOGE, + FL("pStrCfg is NULL for CfigID : %d"), + i);) + continue; + } + index = sCount & CFG_BUF_INDX_MASK; + sCount += pStrCfg->maxLen + 1 + 1; + } else { + index = iCount & CFG_BUF_INDX_MASK; + iCount++; + } + } else { + index = 0; + } + pMac->cfg.gCfgEntry[i].control = cfg_static[i].control | index; + } + + /*Fill the SBUF wih maxLength*/ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = (uint8_t)(bufEnd - bufStart - 2); + + PELOG1(cfgLog(pMac, LOG1, FL("id %d max %d bufStart %d bufEnd %d"), + i, pMac->cfg.gCfgSBuf[bufStart], + bufStart, bufEnd);) + bufEnd = bufStart; + } + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + index = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) { + pMac->cfg.gCfgIBufMin[index] = cfg_static[i].cfgIMin; + pMac->cfg.gCfgIBufMax[index] = cfg_static[i].cfgIMax; + pMac->cfg.gCfgIBuf[index] = cfg_static[i].cfgIVal; + } else { + uint8_t maxSavedLen; + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + if (index >= CFG_STA_SBUF_MAX_SIZE) + continue; + + pDstTest = &pMac->cfg.gCfgSBuf[index]; + pStrCfg = (cfgstatic_string *)cfg_static[i].pStrData; + pSrcTest = pStrCfg->data; + if ((pDstTest == NULL) || (pStrCfg == NULL) || + (pSrcTest == NULL)) + continue; + maxSavedLen = *pDstTest; + len = pStrCfg->length; + if (len > maxSavedLen) + continue; + *pDstTest++ = pStrCfg->maxLen; + *pDstTest++ = len; + while (len) { + *pDstTest++ = *pSrcTest++; + len--; + } + } + } + + /* Set the default log level based on config */ + wlan_cfg_get_int(pMac, WNI_CFG_LOG_LEVEL, &logLevel); + for (i = 0; i < LOG_ENTRY_NUM; i++) + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + logLevel; + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + PELOG1(cfg_log(pMac, LOG1, " Completed successfully");) + + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + +} /*** end ProcessDownloadReq() ***/ diff --git a/core/mac/src/cfg/cfg_send_msg.c b/core/mac/src/cfg/cfg_send_msg.c new file mode 100644 index 0000000000..ebad7c739f --- /dev/null +++ b/core/mac/src/cfg/cfg_send_msg.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the source code for composing and sending messages + * to host. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ +#include "cds_api.h" +#include "cfg_priv.h" +#include "lim_trace.h" +#include "cfg_debug.h" + +/*--------------------------------------------------------------------*/ +/* ATTENTION: The functions contained in this module are to be used */ +/* by CFG module ONLY. */ +/*--------------------------------------------------------------------*/ + +/**--------------------------------------------------------------------- + * cfg_send_host_msg() + * + * FUNCTION: + * Send CNF/RSP to host. + * + * LOGIC: + * Please see Configuration & Statistic Collection Micro-Architecture + * specification for details. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msgType: message type + * @param msgLen: message length + * @param paramNum: number of parameters + * @param pParamList: pointer to parameter list + * @param dataLen: data length + * @param pData: pointer to additional data + * + * @return None. + * + */ +void +cfg_send_host_msg(tpAniSirGlobal pMac, uint16_t msgType, uint32_t msgLen, + uint32_t paramNum, uint32_t *pParamList, uint32_t dataLen, + uint32_t *pData) +{ + uint32_t *pMsg, *pEnd; + tSirMsgQ mmhMsg; + + /* sanity */ + if ((paramNum > 0) && (NULL == pParamList)) { + PELOGE(cfg_log(pMac, LOGE, + FL + ("pParamList NULL when paramNum greater than 0!")); + ) + return; + } + if ((dataLen > 0) && (NULL == pData)) { + PELOGE(cfg_log(pMac, LOGE, + FL("pData NULL when dataLen greater than 0!")); + ) + return; + } + /* Allocate message buffer */ + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) { + PELOGE(cfg_log(pMac, LOGE, FL("Memory allocation failure!"));) + return; + } + /* Fill in message details */ + mmhMsg.type = msgType; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + ((tSirMbMsg *) pMsg)->type = msgType; + ((tSirMbMsg *) pMsg)->msgLen = (uint16_t) msgLen; + + switch (msgType) { + case WNI_CFG_GET_RSP: + case WNI_CFG_PARAM_UPDATE_IND: + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_SET_CNF: + /* Fill in parameters */ + pMsg++; + if (NULL != pParamList) { + pEnd = pMsg + paramNum; + while (pMsg < pEnd) { + *pMsg++ = *pParamList++; + } + } + /* Copy data if there is any */ + if (NULL != pData) { + pEnd = pMsg + (dataLen >> 2); + while (pMsg < pEnd) { + *pMsg++ = *pData++; + } + } + break; + + default: + PELOGE(cfg_log(pMac, LOGE, FL("Unknown msg %d!"), (int)msgType);) + cdf_mem_free(pMsg); + return; + } + + /* Ship it */ + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + sys_process_mmh_msg(pMac, &mmhMsg); + +} /*** end cfg_send_host_msg() ***/ diff --git a/core/mac/src/dph/dph_hash_table.c b/core/mac/src/dph/dph_hash_table.c new file mode 100644 index 0000000000..e1bbe39f63 --- /dev/null +++ b/core/mac/src/dph/dph_hash_table.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file dph_hash_table.cc implements the member functions of + * DPH hash table class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "cfg_api.h" +#include "sch_api.h" +#include "dph_global.h" +#include "lim_debug.h" + +#include "wma_if.h" + +/* --------------------------------------------------------------------- */ +/** + * dphHashTableClass() + * + * FUNCTION: + * Constructor function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable) +{ + uint16_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pHashTable[i] = 0; + } + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pDphNodeArray[i].valid = 0; + pDphHashTable->pDphNodeArray[i].added = 0; + pDphHashTable->pDphNodeArray[i].assocId = i; + } + +} + +/* --------------------------------------------------------------------- */ +/** + * hash_function + * + * FUNCTION: + * Hashing function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @return None + */ + +uint16_t hash_function(tpAniSirGlobal pMac, uint8_t staAddr[], uint16_t numSta) +{ + int i; + uint16_t sum = 0; + + for (i = 0; i < 6; i++) + sum += staAddr[i]; + + return (sum % numSta); +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_hash_entry + * + * FUNCTION: + * Look up an entry in hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param pStaId pointer to the Station ID assigned to the station + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_lookup_hash_entry(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pAssocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr = NULL; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + for (ptr = pDphHashTable->pHashTable[index]; ptr; ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) { + *pAssocId = ptr->assocId; + break; + } + } + return ptr; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_get_hash_entry + * + * FUNCTION: + * Get a pointer to the hash node + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staId Station ID + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_get_hash_entry(tpAniSirGlobal pMac, uint16_t peerIdx, + dphHashTableClass *pDphHashTable) +{ + if (peerIdx < pDphHashTable->size) { + if (pDphHashTable->pDphNodeArray[peerIdx].added) + return &pDphHashTable->pDphNodeArray[peerIdx]; + else + return NULL; + } else + return NULL; + +} + +static inline tpDphHashNode get_node(tpAniSirGlobal pMac, uint8_t assocId, + dphHashTableClass *pDphHashTable) +{ + return &pDphHashTable->pDphNodeArray[assocId]; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_assoc_id + * + * FUNCTION: + * This function looks up assocID given the station Id. It traverses the complete table to do this. + * Need to find an efficient way to do this. + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac pointer to global Mac structure. + * @param staIdx station ID + * @param *assocId pointer to associd to be returned by this function. + * @return pointer to the dph node. + */ +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable) +{ + uint8_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + if ((pDphHashTable->pDphNodeArray[i].added) && + (pDphHashTable->pDphNodeArray[i].staIndex == staIdx)) { + *assocId = i; + break; + } + + } + if (i == pDphHashTable->size) + return NULL; + return &pDphHashTable->pDphNodeArray[i]; + +} + +/** ------------------------------------------------------------- + \fn dph_init_sta_state + \brief Initialize STA state. this function saves the staId from the current entry in the DPH table with given assocId + \ if validStaIdx flag is set. Otherwise it sets the staId to invalid. + \param tpAniSirGlobal pMac + \param tSirMacAddr staAddr + \param uint16_t assocId + \param uint8_t validStaIdx - true ==> the staId in the DPH entry with given assocId is valid and restore it back. + \ false ==> set the staId to invalid. + \return tpDphHashNode - DPH hash node if found. + -------------------------------------------------------------*/ + +tpDphHashNode dph_init_sta_state(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable) +{ + uint32_t val; + + tpDphHashNode pStaDs; + uint16_t staIdx = STA_INVALID_IDX; + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid Assoc Id %d"), assocId);) + return NULL; + } + + pStaDs = get_node(pMac, (uint8_t) assocId, pDphHashTable); + staIdx = pStaDs->staIndex; + + PELOG1(lim_log + (pMac, LOG1, FL("Assoc Id %d, Addr %08X"), assocId, pStaDs); + ) + /* Clear the STA node except for the next pointer (last 4 bytes) */ + cdf_mem_set((uint8_t *) pStaDs, + sizeof(tDphHashNode) - sizeof(tpDphHashNode), 0); + + /* Initialize the assocId */ + pStaDs->assocId = assocId; + if (true == validStaIdx) + pStaDs->staIndex = staIdx; + else + pStaDs->staIndex = STA_INVALID_IDX; + + /* Initialize STA mac address */ + cdf_mem_copy(pStaDs->staAddr, staAddr, sizeof(tSirMacAddr)); + + /* Initialize fragmentation threshold */ + if (wlan_cfg_get_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve fragmentation threshold")); + else + pStaDs->fragSize = (uint16_t) val; + + pStaDs->added = 1; + pStaDs->encPolicy = ENC_POLICY_NULL; + pStaDs->is_disassoc_deauth_in_progress = 0; +#ifdef WLAN_FEATURE_11W + pStaDs->last_assoc_received_time = 0; +#endif + pStaDs->valid = 1; + return pStaDs; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_add_hash_entry + * + * FUNCTION: + * Add entry to hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return Pointer to STA hash entry + */ + +tpDphHashNode dph_add_hash_entry(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, node; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + PELOG1(lim_log(pMac, LOG1, FL("assocId %d index %d STA addr"), + assocId, index); dph_print_mac_addr(pMac, staAddr, LOG1); + ) + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA id %d"), assocId);) + return NULL; + } + + if (pDphHashTable->pDphNodeArray[assocId].added) { + PELOGE(lim_log(pMac, LOGE, FL("already added STA %d"), assocId);) + return NULL; + } + + for (ptr = pDphHashTable->pHashTable[index]; ptr; ptr = ptr->next) { + if (ptr == ptr->next) { + PELOGE(lim_log(pMac, LOGE, FL("Infinite Loop"));) + return NULL; + } + + if (dph_compare_mac_addr(staAddr, ptr->staAddr) + || ptr->assocId == assocId) + break; + } + + if (ptr) { + /* Duplicate entry */ + lim_log(pMac, LOGE, FL("assocId %d hashIndex %d entry exists"), + assocId, index); + return NULL; + } else { + if (dph_init_sta_state + (pMac, staAddr, assocId, false, pDphHashTable) == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("could not Init STAid=%d"), + assocId); + ) + return NULL; + } + /* Add the node to the link list */ + pDphHashTable->pDphNodeArray[assocId].next = + pDphHashTable->pHashTable[index]; + pDphHashTable->pHashTable[index] = + &pDphHashTable->pDphNodeArray[assocId]; + + node = pDphHashTable->pHashTable[index]; + return node; + } +} + +/* --------------------------------------------------------------------- */ +/** + * dph_delete_hash_entry + * + * FUNCTION: + * Delete entry from hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return eSIR_SUCCESS if successful,\n + * eSIR_FAILURE otherwise + */ + +tSirRetStatus dph_delete_hash_entry(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, prev; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + PELOG1(lim_log(pMac, LOG1, FL("assocId %d index %d STA addr"), + assocId, index); dph_print_mac_addr(pMac, staAddr, LOG1); + ) + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA id %d"), assocId);) + return eSIR_FAILURE; + } + + if (pDphHashTable->pDphNodeArray[assocId].added == 0) { + PELOGE(lim_log(pMac, LOGE, FL("STA %d never added"), assocId);) + return eSIR_FAILURE; + } + + for (prev = 0, ptr = pDphHashTable->pHashTable[index]; + ptr; prev = ptr, ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) + break; + if (prev == ptr) { + PELOGE(lim_log(pMac, LOGE, FL("Infinite Loop"));) + return eSIR_FAILURE; + } + } + + if (ptr) { + /* / Delete the entry after invalidating it */ + ptr->valid = 0; + memset(ptr->staAddr, 0, sizeof(ptr->staAddr)); + if (prev == 0) + pDphHashTable->pHashTable[index] = ptr->next; + else + prev->next = ptr->next; + ptr->added = 0; + ptr->is_disassoc_deauth_in_progress = 0; +#ifdef WLAN_FEATURE_11W + ptr->last_assoc_received_time = 0; +#endif + ptr->next = 0; + } else { + /* / Entry not present */ + PELOGE(lim_log(pMac, LOGE, FL("Entry not present STA addr")); + dph_print_mac_addr(pMac, staAddr, LOGE); + ) + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_print_mac_addr + * + * FUNCTION: + * Print a MAC address + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param addr MAC address + * @return None + */ + +void dph_print_mac_addr(tpAniSirGlobal pMac, uint8_t addr[], uint32_t level) +{ + lim_log(pMac, (uint16_t) level, FL("MAC ADDR = %d:%d:%d:%d:%d:%d"), + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); +} + +/* --------------------------------------------------------------------- */ + + diff --git a/core/mac/src/dph/dph_hash_table.h b/core/mac/src/dph/dph_hash_table.h new file mode 100644 index 0000000000..1a55f586a8 --- /dev/null +++ b/core/mac/src/dph/dph_hash_table.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file dph_hash_table.h contains the definition of the scheduler class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __DPH_HASH_TABLE_H__ +#define __DPH_HASH_TABLE_H__ + +#include "ani_global.h" +/* Compare MAC addresses, return true if same */ +static inline uint8_t dph_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +} + +/* Hash table class */ +typedef struct { + + /* The hash table itself */ + tpDphHashNode *pHashTable; + + /* The state array */ + tDphHashNode *pDphNodeArray; + uint16_t size; +} dphHashTableClass; + +/* The hash table object */ +extern dphHashTableClass dphHashTable; + +/* Print MAC addresse */ +extern void dph_print_mac_addr(struct sAniSirGlobal *pMac, uint8_t addr[], + uint32_t); + +tpDphHashNode dph_lookup_hash_entry(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pStaId, + dphHashTableClass *pDphHashTable); +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable); + +/* Get a pointer to the hash node */ +extern tpDphHashNode dph_get_hash_entry(tpAniSirGlobal pMac, uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Add an entry to the hash table */ +extern tpDphHashNode dph_add_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Delete an entry from the hash table */ +extern tSirRetStatus dph_delete_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, uint16_t staId, + dphHashTableClass *pDphHashTable); + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable); +/* Initialize STA state */ +extern tpDphHashNode dph_init_sta_state(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable); + +#endif diff --git a/core/mac/src/include/cfg_api.h b/core/mac/src/include/cfg_api.h new file mode 100644 index 0000000000..e165d5a362 --- /dev/null +++ b/core/mac/src/include/cfg_api.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011-2012,2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGAPI_H +#define __CFGAPI_H + +#include +#include +#include +#include +#include + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* CFG status */ +typedef enum eCfgStatusTypes { + CFG_INCOMPLETE, + CFG_SUCCESS, + CFG_FAILURE +} tCfgStatusTypes; + +/* WEP key mapping table row structure */ +typedef struct { + uint8_t keyMappingAddr[CDF_MAC_ADDR_SIZE]; + uint32_t wepOn; + uint8_t key[SIR_MAC_KEY_LENGTH]; + uint32_t status; +} tCfgWepKeyEntry; + +/*---------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*---------------------------------------------------------------------*/ + +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId); +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId); + +/* / Process host message */ +void cfg_process_mb_msg(tpAniSirGlobal, tSirMbMsg *); + +/* / Set integer parameter value */ +tSirRetStatus cfg_set_int(tpAniSirGlobal, uint16_t, uint32_t); + +/* / Check if the parameter is valid */ +tSirRetStatus cfg_check_valid(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get integer parameter value */ +tSirRetStatus wlan_cfg_get_int(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Set string parameter value */ +tSirRetStatus cfg_set_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t); + +tSirRetStatus cfg_set_str_notify(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t, + int); + +/* Cfg Download function for Prima or Integrated solutions. */ +void process_cfg_download_req(tpAniSirGlobal); + +/* / Get string parameter value */ +tSirRetStatus wlan_cfg_get_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t *); + +/* / Get string parameter maximum length */ +tSirRetStatus wlan_cfg_get_str_max_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get string parameter maximum length */ +tSirRetStatus wlan_cfg_get_str_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get the regulatory tx power on given channel */ +tPowerdBm cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, + uint8_t channel); + +/* / Dump CFG data to memory */ +void cfgDump(uint32_t *); + +/* / Save parameters with P flag set */ +void cfgSave(void); + +/* / Get capability info */ +extern tSirRetStatus cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession psessionEntry); + +/* / Set capability info */ +extern void cfg_set_capability_info(tpAniSirGlobal, uint16_t); + +/* / Cleanup CFG module */ +void cfg_cleanup(tpAniSirGlobal pMac); + +extern uint8_t *g_cfg_param_name[]; + +uint8_t *cfg_get_vendor_ie_ptr_from_oui(tpAniSirGlobal mac_ctx, + uint8_t *oui, + uint8_t oui_size, + uint8_t *ie, + uint16_t ie_len); + +#endif /* __CFGAPI_H */ diff --git a/core/mac/src/include/cfg_global.h b/core/mac/src/include/cfg_global.h new file mode 100644 index 0000000000..8678f27daf --- /dev/null +++ b/core/mac/src/include/cfg_global.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/09/03 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGGLOBAL_H +#define __CFGGLOBAL_H + +#include "sir_common.h" +#include "sir_types.h" +#include "wni_cfg.h" + +#define CFG_MAX_NUM_STA SIR_MAX_NUM_STA_IN_IBSS + +#define CFG_MAX_STATIC_STRING 70 +/* as the number of channels grows, 128 is not big enough */ +#define CFG_MAX_STR_LEN 256 + +/*--------------------------------------------------------------------*/ +/* Configuration Control Structure */ +/*--------------------------------------------------------------------*/ +typedef struct { + uint32_t control; +} tCfgCtl; + + +typedef struct sAniSirCfgStaticString { + uint16_t cfgId; + uint8_t maxLen; + uint8_t length; + uint8_t data[255]; +} cfgstatic_string; + +typedef struct sAniSirCfgStatic { + uint16_t cfgId; + uint32_t control; + uint32_t cfgIMin; + uint32_t cfgIMax; + uint32_t cfgIVal; + void *pStrData; +} cgstatic; + +typedef struct sAniSirCfg { + /* CFG module status */ + uint8_t gCfgStatus; + + tCfgCtl *gCfgEntry; + uint32_t *gCfgIBufMin; + uint32_t *gCfgIBufMax; + uint32_t *gCfgIBuf; + uint8_t *gCfgSBuf; + + uint16_t gCfgMaxIBufSize; + uint16_t gCfgMaxSBufSize; + + /* Static buffer for string parameter (must be word-aligned) */ + uint8_t *gSBuffer; + + /* Message param list buffer (enough for largest possible response) */ + uint32_t *gParamList; +} tAniSirCfg, *tpAniSirCfg; + +#endif diff --git a/core/mac/src/include/dot11f.h b/core/mac/src/include/dot11f.h new file mode 100644 index 0000000000..0258abdf8f --- /dev/null +++ b/core/mac/src/include/dot11f.h @@ -0,0 +1,8920 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef DOT11F_H +#define DOT11F_H +/* + * \file dot11f.h + * + * \brief Structures, function prototypes & definitions + * for working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Wed Oct 14 10:14:42 2015 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + * Instead, please update the input files & re-run + * 'framesc' For more information on 'framesc' & the + * frames language, run 'framesc --help'. + * + */ + +typedef uint32_t tDOT11F_U64[2]; + +#if defined (_MSC_VER) +#pragma warning (disable:4214) /* nonstandard extension used */ +#endif /* Microsoft C/C++ bit field types other than int */ + +/* + * Frames Return Codes: + * + * Success is indicated by a return value of zero. Failure is indicated + * by the presence of the high bit. Warnings encountered in the course + * of a successful parse are indicated by various bits in the lower 31 + * being turned on. + * + * For instance, a return value of 0x0000000a would indicate that the + * parse succeeded, but that a mandatory IE wasn't present, and some IE + * was found to be corrupt. + * + * + */ + +#define DOT11F_PARSE_SUCCESS (0x00000000) +#define DOT11F_UNKNOWN_IES (0x00000001) +#define DOT11F_MANDATORY_IE_MISSING (0x00000002) +#define DOT11F_INCOMPLETE_IE (0x00000004) +#define DOT11F_SKIPPED_BAD_IE (0x00000008) +#define DOT11F_LAST_IE_TOO_LONG (0x00000010) +#define DOT11F_DUPLICATE_IE (0x00000020) +#define DOT11F_BAD_FIXED_VALUE (0x00000040) +#define DOT11F_INCOMPLETE_TLV (0x00000080) +#define DOT11F_INVALID_TLV_LENGTH (0x00000100) +#define DOT11F_SKIPPED_BAD_TLV (0x00000200) +#define DOT11F_UNKNOWN_TLVS (0x00000400) +#define DOT11F_LAST_TLV_TOO_LONG (0x00000800) +#define DOT11F_INTERNAL_ERROR (0x10000001) +#define DOT11F_MISSING_FIXED_FIELD (0x10000002) +#define DOT11F_BAD_INPUT_BUFFER (0x10000003) +#define DOT11F_BAD_OUTPUT_BUFFER (0x10000004) +#define DOT11F_BUFFER_OVERFLOW (0x10000005) +#define DOT11F_MANDATORY_TLV_MISSING (0x00001000) +#define DOT11F_FAILED(code) ((code) & 0x10000000) +#define DOT11F_WARNED(code) (((0 == (code)) & 0x10000000) && code) +#define DOT11F_SUCCEEDED(code) ((code) == 0) + +/********************************************************************* + * Fixed Fields * + ********************************************************************/ + +typedef struct sDot11fFfAID { + uint16_t associd; +} tDot11fFfAID; + +#define DOT11F_FF_AID_LEN (2) + +void dot11f_unpack_ff_AID(tpAniSirGlobal, uint8_t *, tDot11fFfAID *); + +void dot11f_pack_ff_aid(tpAniSirGlobal, tDot11fFfAID *, uint8_t *); + +typedef struct sDot11fFfAction { + uint8_t action; +} tDot11fFfAction; + +#define DOT11F_FF_ACTION_LEN (1) + +void dot11f_unpack_ff_action(tpAniSirGlobal, uint8_t *, tDot11fFfAction *); + +void dot11f_pack_ff_action(tpAniSirGlobal, tDot11fFfAction *, uint8_t *); + +typedef struct sDot11fFfAuthAlgo { + uint16_t algo; +} tDot11fFfAuthAlgo; + +#define DOT11F_FF_AUTHALGO_LEN (2) + +void dot11f_unpack_ff_AuthAlgo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthAlgo *); + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal, tDot11fFfAuthAlgo *, uint8_t *); + +typedef struct sDot11fFfAuthSeqNo { + uint16_t no; +} tDot11fFfAuthSeqNo; + +#define DOT11F_FF_AUTHSEQNO_LEN (2) + +void dot11f_unpack_ff_AuthSeqNo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthSeqNo *); + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal, tDot11fFfAuthSeqNo *, + uint8_t *); + +typedef struct sDot11fFfBeaconInterval { + uint16_t interval; +} tDot11fFfBeaconInterval; + +#define DOT11F_FF_BEACONINTERVAL_LEN (2) + +void dot11f_unpack_ff_BeaconInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfBeaconInterval *); + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal, tDot11fFfBeaconInterval *, + uint8_t *); + +typedef struct sDot11fFfCapabilities { + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t pbcc:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +} tDot11fFfCapabilities; + +#define DOT11F_FF_CAPABILITIES_LEN (2) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal, uint8_t *, + tDot11fFfCapabilities *); + +void dot11f_pack_ff_capabilities(tpAniSirGlobal, tDot11fFfCapabilities *, + uint8_t *); + +#define CAPABILITIES_ESS_OFFSET 0 +#define CAPABILITIES_ESS_WIDTH 1 +#define CAPABILITIES_IBSS_OFFSET 1 +#define CAPABILITIES_IBSS_WIDTH 1 +#define CAPABILITIES_CFPOLLABLE_OFFSET 2 +#define CAPABILITIES_CFPOLLABLE_WIDTH 1 +#define CAPABILITIES_CFPOLLREQ_OFFSET 3 +#define CAPABILITIES_CFPOLLREQ_WIDTH 1 +#define CAPABILITIES_PRIVACY_OFFSET 4 +#define CAPABILITIES_PRIVACY_WIDTH 1 +#define CAPABILITIES_SHORTPREAMBLE_OFFSET 5 +#define CAPABILITIES_SHORTPREAMBLE_WIDTH 1 +#define CAPABILITIES_PBCC_OFFSET 6 +#define CAPABILITIES_PBCC_WIDTH 1 +#define CAPABILITIES_CHANNELAGILITY_OFFSET 7 +#define CAPABILITIES_CHANNELAGILITY_WIDTH 1 +#define CAPABILITIES_SPECTRUMMGT_OFFSET 8 +#define CAPABILITIES_SPECTRUMMGT_WIDTH 1 +#define CAPABILITIES_QOS_OFFSET 9 +#define CAPABILITIES_QOS_WIDTH 1 +#define CAPABILITIES_SHORTSLOTTIME_OFFSET 10 +#define CAPABILITIES_SHORTSLOTTIME_WIDTH 1 +#define CAPABILITIES_APSD_OFFSET 11 +#define CAPABILITIES_APSD_WIDTH 1 +#define CAPABILITIES_RRM_OFFSET 12 +#define CAPABILITIES_RRM_WIDTH 1 +#define CAPABILITIES_DSSSOFDM_OFFSET 13 +#define CAPABILITIES_DSSSOFDM_WIDTH 1 +#define CAPABILITIES_DELAYEDBA_OFFSET 14 +#define CAPABILITIES_DELAYEDBA_WIDTH 1 +#define CAPABILITIES_IMMEDIATEBA_OFFSET 15 +#define CAPABILITIES_IMMEDIATEBA_WIDTH 1 + +typedef struct sDot11fFfCategory { + uint8_t category; +} tDot11fFfCategory; + +#define DOT11F_FF_CATEGORY_LEN (1) + +void dot11f_unpack_ff_category(tpAniSirGlobal, uint8_t *, + tDot11fFfCategory *); + +void dot11f_pack_ff_category(tpAniSirGlobal, tDot11fFfCategory *, uint8_t *); + +typedef struct sDot11fFfCurrentAPAddress { + uint8_t mac[6]; +} tDot11fFfCurrentAPAddress; + +#define DOT11F_FF_CURRENTAPADDRESS_LEN (6) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal, uint8_t *, + tDot11fFfCurrentAPAddress *); + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal, + tDot11fFfCurrentAPAddress *, + uint8_t *); + + +typedef struct sDot11fFfDialogToken { + uint8_t token; +} tDot11fFfDialogToken; + +#define DOT11F_FF_DIALOGTOKEN_LEN (1) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal, uint8_t *, + tDot11fFfDialogToken *); + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal, tDot11fFfDialogToken *, + uint8_t *); + +typedef struct sDot11fFfLinkMargin { + uint8_t linkMargin; +} tDot11fFfLinkMargin; + +#define DOT11F_FF_LINKMARGIN_LEN (1) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal, uint8_t *, + tDot11fFfLinkMargin *); + +void dot11f_pack_ff_link_margin(tpAniSirGlobal, tDot11fFfLinkMargin *, + uint8_t *); + +typedef struct sDot11fFfListenInterval { + uint16_t interval; +} tDot11fFfListenInterval; + +#define DOT11F_FF_LISTENINTERVAL_LEN (2) + +void dot11f_unpack_ff_ListenInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfListenInterval *); + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal, tDot11fFfListenInterval *, + uint8_t *); + +typedef struct sDot11fFfMaxTxPower { + uint8_t maxTxPower; +} tDot11fFfMaxTxPower; + +#define DOT11F_FF_MAXTXPOWER_LEN (1) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfMaxTxPower *); + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal, tDot11fFfMaxTxPower *, + uint8_t *); + +typedef struct sDot11fFfNumOfRepetitions { + uint16_t repetitions; +} tDot11fFfNumOfRepetitions; + +#define DOT11F_FF_NUMOFREPETITIONS_LEN (2) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal, uint8_t *, + tDot11fFfNumOfRepetitions *); + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal, + tDot11fFfNumOfRepetitions *, + uint8_t *); + + +typedef struct sDot11fFfOperatingMode { + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fFfOperatingMode; + +#define DOT11F_FF_OPERATINGMODE_LEN (1) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal, uint8_t *, + tDot11fFfOperatingMode *); + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal, tDot11fFfOperatingMode *, + uint8_t *); + +#define OPERATINGMODE_CHANWIDTH_OFFSET 0 +#define OPERATINGMODE_CHANWIDTH_WIDTH 2 +#define OPERATINGMODE_RESERVED_OFFSET 2 +#define OPERATINGMODE_RESERVED_WIDTH 2 +#define OPERATINGMODE_RXNSS_OFFSET 4 +#define OPERATINGMODE_RXNSS_WIDTH 3 +#define OPERATINGMODE_RXNSSTYPE_OFFSET 7 +#define OPERATINGMODE_RXNSSTYPE_WIDTH 1 + +typedef struct sDot11fFfRCPI { + uint8_t rcpi; +} tDot11fFfRCPI; + +#define DOT11F_FF_RCPI_LEN (1) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal, uint8_t *, tDot11fFfRCPI *); + +void dot11f_pack_ff_rcpi(tpAniSirGlobal, tDot11fFfRCPI *, uint8_t *); + +typedef struct sDot11fFfRSNI { + uint8_t rsni; +} tDot11fFfRSNI; + +#define DOT11F_FF_RSNI_LEN (1) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal, uint8_t *, tDot11fFfRSNI *); + +void dot11f_pack_ff_rsni(tpAniSirGlobal, tDot11fFfRSNI *, uint8_t *); + +typedef struct sDot11fFfReason { + uint16_t code; +} tDot11fFfReason; + +#define DOT11F_FF_REASON_LEN (2) + +void dot11f_unpack_ff_Reason(tpAniSirGlobal, uint8_t *, tDot11fFfReason *); + +void dot11f_pack_ff_reason(tpAniSirGlobal, tDot11fFfReason *, uint8_t *); + +typedef struct sDot11fFfRxAntennaId { + uint8_t antennaId; +} tDot11fFfRxAntennaId; + +#define DOT11F_FF_RXANTENNAID_LEN (1) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfRxAntennaId *); + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal, tDot11fFfRxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfSMPowerModeSet { + uint8_t PowerSave_En:1; + uint8_t Mode:1; + uint8_t reserved:6; +} tDot11fFfSMPowerModeSet; + +#define DOT11F_FF_SMPOWERMODESET_LEN (1) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal, uint8_t *, + tDot11fFfSMPowerModeSet *); + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal, tDot11fFfSMPowerModeSet *, + uint8_t *); + +#define SMPOWERMODESET_POWERSAVE_EN_OFFSET 0 +#define SMPOWERMODESET_POWERSAVE_EN_WIDTH 1 +#define SMPOWERMODESET_MODE_OFFSET 1 +#define SMPOWERMODESET_MODE_WIDTH 1 +#define SMPOWERMODESET_RESERVED_OFFSET 2 +#define SMPOWERMODESET_RESERVED_WIDTH 6 + +typedef struct sDot11fFfStatus { + uint16_t status; +} tDot11fFfStatus; + +#define DOT11F_FF_STATUS_LEN (2) + +void dot11f_unpack_ff_Status(tpAniSirGlobal, uint8_t *, tDot11fFfStatus *); + +void dot11f_pack_ff_status(tpAniSirGlobal, tDot11fFfStatus *, uint8_t *); + +typedef struct sDot11fFfStatusCode { + uint8_t statusCode; +} tDot11fFfStatusCode; + +#define DOT11F_FF_STATUSCODE_LEN (1) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal, uint8_t *, + tDot11fFfStatusCode *); + +void dot11f_pack_ff_status_code(tpAniSirGlobal, tDot11fFfStatusCode *, + uint8_t *); + +typedef struct sDot11fFfTPCEleID { + uint8_t TPCId; +} tDot11fFfTPCEleID; + +#define DOT11F_FF_TPCELEID_LEN (1) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleID *); + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal, tDot11fFfTPCEleID *, uint8_t *); + +typedef struct sDot11fFfTPCEleLen { + uint8_t TPCLen; +} tDot11fFfTPCEleLen; + +#define DOT11F_FF_TPCELELEN_LEN (1) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleLen *); + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal, tDot11fFfTPCEleLen *, + uint8_t *); + +typedef struct sDot11fFfTSInfo { + uint32_t traffic_type:1; + uint32_t tsid:4; + uint32_t direction:2; + uint32_t access_policy:2; + uint32_t aggregation:1; + uint32_t psb:1; + uint32_t user_priority:3; + uint32_t tsinfo_ack_pol:2; + uint32_t schedule:1; + uint32_t unused:15; +} tDot11fFfTSInfo; + +#define DOT11F_FF_TSINFO_LEN (3) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal, uint8_t *, tDot11fFfTSInfo *); + +void dot11f_pack_ff_ts_info(tpAniSirGlobal, tDot11fFfTSInfo *, uint8_t *); + +#define TSINFO_TRAFFIC_TYPE_OFFSET 0 +#define TSINFO_TRAFFIC_TYPE_WIDTH 1 +#define TSINFO_TSID_OFFSET 1 +#define TSINFO_TSID_WIDTH 4 +#define TSINFO_DIRECTION_OFFSET 5 +#define TSINFO_DIRECTION_WIDTH 2 +#define TSINFO_ACCESS_POLICY_OFFSET 7 +#define TSINFO_ACCESS_POLICY_WIDTH 2 +#define TSINFO_AGGREGATION_OFFSET 9 +#define TSINFO_AGGREGATION_WIDTH 1 +#define TSINFO_PSB_OFFSET 10 +#define TSINFO_PSB_WIDTH 1 +#define TSINFO_USER_PRIORITY_OFFSET 11 +#define TSINFO_USER_PRIORITY_WIDTH 3 +#define TSINFO_TSINFO_ACK_POL_OFFSET 14 +#define TSINFO_TSINFO_ACK_POL_WIDTH 2 +#define TSINFO_SCHEDULE_OFFSET 16 +#define TSINFO_SCHEDULE_WIDTH 1 +#define TSINFO_UNUSED_OFFSET 17 +#define TSINFO_UNUSED_WIDTH 15 + +typedef struct sDot11fFfTimeStamp { + tDOT11F_U64 timestamp; +} tDot11fFfTimeStamp; + +#define DOT11F_FF_TIMESTAMP_LEN (8) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal, uint8_t *, + tDot11fFfTimeStamp *); + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal, tDot11fFfTimeStamp *, + uint8_t *); + +typedef struct sDot11fFfTransactionId { + uint8_t transId[2]; +} tDot11fFfTransactionId; + +#define DOT11F_FF_TRANSACTIONID_LEN (2) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTransactionId *); + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal, tDot11fFfTransactionId *, + uint8_t *); + +typedef struct sDot11fFfTxAntennaId { + uint8_t antennaId; +} tDot11fFfTxAntennaId; + +#define DOT11F_FF_TXANTENNAID_LEN (1) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTxAntennaId *); + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal, tDot11fFfTxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfTxPower { + uint8_t txPower; +} tDot11fFfTxPower; + +#define DOT11F_FF_TXPOWER_LEN (1) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfTxPower *); + +void dot11f_pack_ff_tx_power(tpAniSirGlobal, tDot11fFfTxPower *, uint8_t *); + +typedef struct sDot11fFfVhtMembershipStatusArray { + uint8_t membershipStatusArray[8]; +} tDot11fFfVhtMembershipStatusArray; + +#define DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN (8) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtMembershipStatusArray *); + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal, + tDot11fFfVhtMembershipStatusArray *, + uint8_t *); + + +typedef struct sDot11fFfVhtUserPositionArray { + uint8_t userPositionArray[16]; +} tDot11fFfVhtUserPositionArray; + +#define DOT11F_FF_VHTUSERPOSITIONARRAY_LEN (16) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtUserPositionArray *); + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal, + tDot11fFfVhtUserPositionArray *, + uint8_t *); + + +/********************************************************************* + * TLVs * + ********************************************************************/ + + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVAuthorizedMACs { + uint8_t present; + uint8_t mac[6]; +} tDot11fTLVAuthorizedMACs; + +#define DOT11F_TLV_AUTHORIZEDMACS (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_AUTHORIZEDMACS_MIN_LEN (6) + +#define DOT11F_TLV_AUTHORIZEDMACS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_authorized_ma_cs( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAuthorizedMACs*); + +uint32_t dot11f_pack_tlv_authorized_ma_cs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AuthorizedMACs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVRequestToEnroll { + uint8_t present; + uint8_t req; +} tDot11fTLVRequestToEnroll; + +#define DOT11F_TLV_REQUESTTOENROLL (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTOENROLL_MIN_LEN (1) + +#define DOT11F_TLV_REQUESTTOENROLL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestToEnroll( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestToEnroll*); + +uint32_t dot11f_pack_tlv_request_to_enroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestToEnroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVVersion2 { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion2; + +#define DOT11F_TLV_VERSION2 (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION2_MIN_LEN (1) + +#define DOT11F_TLV_VERSION2_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version2( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion2*); + +uint32_t dot11f_pack_tlv_version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4183 (0x1057) */ +typedef struct sDot11fTLVAPSetupLocked { + uint8_t present; + uint8_t fLocked; +} tDot11fTLVAPSetupLocked; + +#define DOT11F_TLV_APSETUPLOCKED (4183) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_APSETUPLOCKED_MIN_LEN (3) + +#define DOT11F_TLV_APSETUPLOCKED_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_APSetupLocked( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAPSetupLocked*); + +uint32_t dot11f_pack_tlv_ap_setup_locked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_APSetupLocked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4098 (0x1002) */ +typedef struct sDot11fTLVAssociationState { + uint8_t present; + uint16_t state; +} tDot11fTLVAssociationState; + +#define DOT11F_TLV_ASSOCIATIONSTATE (4098) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ASSOCIATIONSTATE_MIN_LEN (4) + +#define DOT11F_TLV_ASSOCIATIONSTATE_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_AssociationState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAssociationState*); + +uint32_t dot11f_pack_tlv_association_state( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AssociationState( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4104 (0x1008) */ +typedef struct sDot11fTLVConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVConfigMethods; + +#define DOT11F_TLV_CONFIGMETHODS (4104) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigMethods*); + +uint32_t dot11f_pack_tlv_config_methods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigMethods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4105 (0x1009) */ +typedef struct sDot11fTLVConfigurationError { + uint8_t present; + uint16_t error; +} tDot11fTLVConfigurationError; + +#define DOT11F_TLV_CONFIGURATIONERROR (4105) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGURATIONERROR_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGURATIONERROR_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigurationError( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigurationError*); + +uint32_t dot11f_pack_tlv_configuration_error( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigurationError( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4113 (0x1011) */ +typedef struct sDot11fTLVDeviceName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVDeviceName; + +#define DOT11F_TLV_DEVICENAME (4113) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICENAME_MIN_LEN (2) + +#define DOT11F_TLV_DEVICENAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_device_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDeviceName*); + +uint32_t dot11f_pack_tlv_device_name( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DeviceName( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4114 (0x1012) */ +typedef struct sDot11fTLVDevicePasswordID { + uint8_t present; + uint16_t id; +} tDot11fTLVDevicePasswordID; + +#define DOT11F_TLV_DEVICEPASSWORDID (4114) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICEPASSWORDID_MIN_LEN (4) + +#define DOT11F_TLV_DEVICEPASSWORDID_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_DevicePasswordID( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDevicePasswordID*); + +uint32_t dot11f_pack_tlv_device_password_id( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DevicePasswordID( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 8 (0x0008) */ +typedef struct sDot11fTLVExtendedListenTiming { + uint8_t present; + uint16_t availibilityPeriod; + uint16_t availibilityInterval; +} tDot11fTLVExtendedListenTiming; + +#define DOT11F_TLV_EXTENDEDLISTENTIMING (8) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MIN_LEN (5) + +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_extended_listen_timing( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVExtendedListenTiming*); + +uint32_t dot11f_pack_tlv_extended_listen_timing( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ExtendedListenTiming( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 6 (0x0006) */ +typedef struct sDot11fTLVListenChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVListenChannel; + +#define DOT11F_TLV_LISTENCHANNEL (6) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_LISTENCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_LISTENCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_listen_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVListenChannel*); + +uint32_t dot11f_pack_tlv_listen_channel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ListenChannel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4129 (0x1021) */ +typedef struct sDot11fTLVManufacturer { + uint8_t present; + uint8_t num_name; + uint8_t name[64]; +} tDot11fTLVManufacturer; + +#define DOT11F_TLV_MANUFACTURER (4129) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MANUFACTURER_MIN_LEN (2) + +#define DOT11F_TLV_MANUFACTURER_MAX_LEN (66) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_manufacturer( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVManufacturer*); + +uint32_t dot11f_pack_tlv_manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVMinorReasonCode { + uint8_t present; + uint8_t minorReasonCode; +} tDot11fTLVMinorReasonCode; + +#define DOT11F_TLV_MINORREASONCODE (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MINORREASONCODE_MIN_LEN (2) + +#define DOT11F_TLV_MINORREASONCODE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_MinorReasonCode( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVMinorReasonCode*); + +uint32_t dot11f_pack_tlv_minor_reason_code( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_MinorReasonCode( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4131 (0x1023) */ +typedef struct sDot11fTLVModelName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelName; + +#define DOT11F_TLV_MODELNAME (4131) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNAME_MIN_LEN (2) + +#define DOT11F_TLV_MODELNAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelName*); + +uint32_t dot11f_pack_tlv_model_name( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelName( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4132 (0x1024) */ +typedef struct sDot11fTLVModelNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelNumber; + +#define DOT11F_TLV_MODELNUMBER (4132) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_MODELNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelNumber*); + +uint32_t dot11f_pack_tlv_model_number( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelNumber( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 12 (0x000c) */ +typedef struct sDot11fTLVNoticeOfAbsence { + uint8_t present; + uint8_t index; + uint8_t CTSWindowOppPS; + uint8_t num_NoADesc; + uint8_t NoADesc[36]; +} tDot11fTLVNoticeOfAbsence; + +#define DOT11F_TLV_NOTICEOFABSENCE (12) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_NOTICEOFABSENCE_MIN_LEN (3) + +#define DOT11F_TLV_NOTICEOFABSENCE_MAX_LEN (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_notice_of_absence( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVNoticeOfAbsence*); + +uint32_t dot11f_pack_tlv_notice_of_absence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_NoticeOfAbsence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 17 (0x0011) */ +typedef struct sDot11fTLVOperatingChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVOperatingChannel; + +#define DOT11F_TLV_OPERATINGCHANNEL (17) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_OPERATINGCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_OPERATINGCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_operating_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVOperatingChannel*); + +uint32_t dot11f_pack_tlv_operating_channel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_OperatingChannel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 2 (0x0002) */ +typedef struct sDot11fTLVP2PCapability { + uint8_t present; + uint8_t deviceCapability; + uint8_t groupCapability; +} tDot11fTLVP2PCapability; + +#define DOT11F_TLV_P2PCAPABILITY (2) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PCAPABILITY_MIN_LEN (3) + +#define DOT11F_TLV_P2PCAPABILITY_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_capability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PCapability*); + +uint32_t dot11f_pack_tlv_p2_p_capability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PCapability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVP2PDeviceId { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PDeviceId; + +#define DOT11F_TLV_P2PDEVICEID (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEID_MIN_LEN (7) + +#define DOT11F_TLV_P2PDEVICEID_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_id( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceId*); + +uint32_t dot11f_pack_tlv_p2_p_device_id( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceId( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 13 (0x000d) */ +typedef struct sDot11fTLVP2PDeviceInfo { + uint8_t present; + uint8_t P2PDeviceAddress[6]; + uint16_t configMethod; + uint8_t primaryDeviceType[8]; + tDot11fTLVDeviceName DeviceName; +} tDot11fTLVP2PDeviceInfo; + +#define DOT11F_TLV_P2PDEVICEINFO (13) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEINFO_MIN_LEN (17) + +#define DOT11F_TLV_P2PDEVICEINFO_MAX_LEN (53) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceInfo*); + +uint32_t dot11f_pack_tlv_p2_p_device_info( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceInfo( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 14 (0x000e) */ +typedef struct sDot11fTLVP2PGroupInfo { + uint8_t present; + uint8_t num_P2PClientInfoDesc; + uint8_t P2PClientInfoDesc[1024]; +} tDot11fTLVP2PGroupInfo; + +#define DOT11F_TLV_P2PGROUPINFO (14) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PGROUPINFO_MIN_LEN (1) + +#define DOT11F_TLV_P2PGROUPINFO_MAX_LEN (1025) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_group_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PGroupInfo*); + +uint32_t dot11f_pack_tlv_p2_p_group_info( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PGroupInfo( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVP2PStatus { + uint8_t present; + uint8_t status; +} tDot11fTLVP2PStatus; + +#define DOT11F_TLV_P2PSTATUS (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PSTATUS_MIN_LEN (2) + +#define DOT11F_TLV_P2PSTATUS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PStatus( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PStatus*); + +uint32_t dot11f_pack_tlv_p2_p_status( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PStatus( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4180 (0x1054) */ +typedef struct sDot11fTLVPrimaryDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVPrimaryDeviceType; + +#define DOT11F_TLV_PRIMARYDEVICETYPE (4180) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_PRIMARYDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_PRIMARYDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_primary_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVPrimaryDeviceType*); + +uint32_t dot11f_pack_tlv_primary_device_type( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_PrimaryDeviceType( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4156 (0x103c) */ +typedef struct sDot11fTLVRFBands { + uint8_t present; + uint8_t bands; +} tDot11fTLVRFBands; + +#define DOT11F_TLV_RFBANDS (4156) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RFBANDS_MIN_LEN (3) + +#define DOT11F_TLV_RFBANDS_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RFBands( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRFBands*); + +uint32_t dot11f_pack_tlv_rf_bands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RFBands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4202 (0x106a) */ +typedef struct sDot11fTLVRequestDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVRequestDeviceType; + +#define DOT11F_TLV_REQUESTDEVICETYPE (4202) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_REQUESTDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_request_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestDeviceType*); + +uint32_t dot11f_pack_tlv_request_device_type( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestDeviceType( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4154 (0x103a) */ +typedef struct sDot11fTLVRequestType { + uint8_t present; + uint8_t reqType; +} tDot11fTLVRequestType; + +#define DOT11F_TLV_REQUESTTYPE (4154) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTYPE_MIN_LEN (3) + +#define DOT11F_TLV_REQUESTTYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestType*); + +uint32_t dot11f_pack_tlv_request_type( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestType( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4155 (0x103b) */ +typedef struct sDot11fTLVResponseType { + uint8_t present; + uint8_t resType; +} tDot11fTLVResponseType; + +#define DOT11F_TLV_RESPONSETYPE (4155) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RESPONSETYPE_MIN_LEN (3) + +#define DOT11F_TLV_RESPONSETYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ResponseType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVResponseType*); + +uint32_t dot11f_pack_tlv_response_type( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ResponseType( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4161 (0x1041) */ +typedef struct sDot11fTLVSelectedRegistrar { + uint8_t present; + uint8_t selected; +} tDot11fTLVSelectedRegistrar; + +#define DOT11F_TLV_SELECTEDREGISTRAR (4161) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRAR_MIN_LEN (3) + +#define DOT11F_TLV_SELECTEDREGISTRAR_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrar( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrar*); + +uint32_t dot11f_pack_tlv_selected_registrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4179 (0x1053) */ +typedef struct sDot11fTLVSelectedRegistrarConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVSelectedRegistrarConfigMethods; + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS (4179) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrarConfigMethods*); + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4162 (0x1042) */ +typedef struct sDot11fTLVSerialNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVSerialNumber; + +#define DOT11F_TLV_SERIALNUMBER (4162) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SERIALNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_SERIALNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_serial_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSerialNumber*); + +uint32_t dot11f_pack_tlv_serial_number( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SerialNumber( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4167 (0x1047) */ +typedef struct sDot11fTLVUUID_E { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_E; + +#define DOT11F_TLV_UUID_E (4167) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_E_MIN_LEN (18) + +#define DOT11F_TLV_UUID_E_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_e( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_E*); + +uint32_t dot11f_pack_tlv_uuid_e( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_E( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4168 (0x1048) */ +typedef struct sDot11fTLVUUID_R { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_R; + +#define DOT11F_TLV_UUID_R (4168) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_R_MIN_LEN (18) + +#define DOT11F_TLV_UUID_R_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_r( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_R*); + +uint32_t dot11f_pack_tlv_uuid_r( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_R( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4169 (0x1049) */ +typedef struct sDot11fTLVVendorExtension { + uint8_t present; + uint8_t vendorId[3]; + tDot11fTLVVersion2 Version2; + tDot11fTLVAuthorizedMACs AuthorizedMACs; + tDot11fTLVRequestToEnroll RequestToEnroll; +} tDot11fTLVVendorExtension; + +#define DOT11F_TLV_VENDOREXTENSION (4169) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VENDOREXTENSION_MIN_LEN (5) + +#define DOT11F_TLV_VENDOREXTENSION_MAX_LEN (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_vendor_extension( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVendorExtension*); + +uint32_t dot11f_pack_tlv_vendor_extension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_VendorExtension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4170 (0x104a) */ +typedef struct sDot11fTLVVersion { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion; + +#define DOT11F_TLV_VERSION (4170) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION_MIN_LEN (3) + +#define DOT11F_TLV_VERSION_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion*); + +uint32_t dot11f_pack_tlv_version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4164 (0x1044) */ +typedef struct sDot11fTLVWPSState { + uint8_t present; + uint8_t state; +} tDot11fTLVWPSState; + +#define DOT11F_TLV_WPSSTATE (4164) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_WPSSTATE_MIN_LEN (3) + +#define DOT11F_TLV_WPSSTATE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_WPSState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVWPSState*); + +uint32_t dot11f_pack_tlv_wps_state( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_WPSState( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 16 (0x0010) */ +typedef struct sDot11fTLVP2PInterface { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PInterface; + +#define DOT11F_TLV_P2PINTERFACE (16) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PINTERFACE_MIN_LEN (7) + +#define DOT11F_TLV_P2PINTERFACE_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_interface( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PInterface*); + +uint32_t dot11f_pack_tlv_p2_p_interface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PInterface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 10 (0x000a) */ +typedef struct sDot11fTLVP2PManageability { + uint8_t present; + uint8_t manageability; +} tDot11fTLVP2PManageability; + +#define DOT11F_TLV_P2PMANAGEABILITY (10) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PMANAGEABILITY_MIN_LEN (2) + +#define DOT11F_TLV_P2PMANAGEABILITY_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PManageability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PManageability*); + +uint32_t dot11f_pack_tlv_p2_p_manageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PManageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/********************************************************************* + * Information Elements * + ********************************************************************/ + + +/* EID 2 (0x02) */ +typedef struct sDot11fIECondensedCountryStr { + uint8_t present; + uint8_t countryStr[2]; +} tDot11fIECondensedCountryStr; + +#define DOT11F_EID_CONDENSEDCOUNTRYSTR (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MIN_LEN (2) + +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_condensed_country_str( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECondensedCountryStr*); + +uint32_t dot11f_pack_ie_condensed_country_str( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CondensedCountryStr( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEGTK { + uint8_t present; + uint16_t keyId:2; + uint16_t reserved:14; + uint8_t keyLength; + uint8_t RSC[8]; + uint8_t num_key; + uint8_t key[32]; +} tDot11fIEGTK; + +#define DOT11F_EID_GTK (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_GTK_MIN_LEN (16) + +#define DOT11F_IE_GTK_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_gtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEGTK*); + +uint32_t dot11f_pack_ie_gtk( + tpAniSirGlobal, + tDot11fIEGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_GTK( + tpAniSirGlobal, + tDot11fIEGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIEIGTK { + uint8_t present; + uint8_t keyID[2]; + uint8_t IPN[6]; + uint8_t keyLength; + uint8_t key[24]; +} tDot11fIEIGTK; + +#define DOT11F_EID_IGTK (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IGTK_MIN_LEN (33) + +#define DOT11F_IE_IGTK_MAX_LEN (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_igtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIGTK*); + +uint32_t dot11f_pack_ie_igtk( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IGTK( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIER0KH_ID { + uint8_t present; + uint8_t num_PMK_R0_ID; + uint8_t PMK_R0_ID[48]; +} tDot11fIER0KH_ID; + +#define DOT11F_EID_R0KH_ID (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R0KH_ID_MIN_LEN (1) + +#define DOT11F_IE_R0KH_ID_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_r0_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER0KH_ID*); + +uint32_t dot11f_pack_ie_r0_kh_id( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R0KH_ID( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIER1KH_ID { + uint8_t present; + uint8_t PMK_R1_ID[6]; +} tDot11fIER1KH_ID; + +#define DOT11F_EID_R1KH_ID (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R1KH_ID_MIN_LEN (6) + +#define DOT11F_IE_R1KH_ID_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_r1_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER1KH_ID*); + +uint32_t dot11f_pack_ie_r1_kh_id( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R1KH_ID( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIETSFInfo { + uint8_t present; + uint16_t TsfOffset; + uint16_t BeaconIntvl; +} tDot11fIETSFInfo; + +#define DOT11F_EID_TSFINFO (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSFINFO_MIN_LEN (4) + +#define DOT11F_IE_TSFINFO_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tsf_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSFInfo*); + +uint32_t dot11f_pack_ie_tsf_info( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSFInfo( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 51 (0x33) */ +typedef struct sDot11fIEAPChannelReport { + uint8_t present; + uint8_t regulatoryClass; + uint8_t num_channelList; + uint8_t channelList[50]; +} tDot11fIEAPChannelReport; + +#define DOT11F_EID_APCHANNELREPORT (51) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_APCHANNELREPORT_MIN_LEN (1) + +#define DOT11F_IE_APCHANNELREPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ap_channel_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAPChannelReport*); + +uint32_t dot11f_pack_ie_ap_channel_report( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_APChannelReport( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEBcnReportingDetail { + uint8_t present; + uint8_t reportingDetail; +} tDot11fIEBcnReportingDetail; + +#define DOT11F_EID_BCNREPORTINGDETAIL (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BCNREPORTINGDETAIL_MIN_LEN (1) + +#define DOT11F_IE_BCNREPORTINGDETAIL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_bcn_reporting_detail( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBcnReportingDetail*); + +uint32_t dot11f_pack_ie_bcn_reporting_detail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BcnReportingDetail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEBeaconReportFrmBody { + uint8_t present; + uint8_t num_reportedFields; + uint8_t reportedFields[224]; +} tDot11fIEBeaconReportFrmBody; + +#define DOT11F_EID_BEACONREPORTFRMBODY (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTFRMBODY_MIN_LEN (0) + +#define DOT11F_IE_BEACONREPORTFRMBODY_MAX_LEN (224) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_beacon_report_frm_body( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReportFrmBody*); + +uint32_t dot11f_pack_ie_beacon_report_frm_body( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReportFrmBody( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEBeaconReporting { + uint8_t present; + uint8_t reportingCondition; + uint8_t threshold; +} tDot11fIEBeaconReporting; + +#define DOT11F_EID_BEACONREPORTING (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTING_MIN_LEN (2) + +#define DOT11F_IE_BEACONREPORTING_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_beacon_reporting( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReporting*); + +uint32_t dot11f_pack_ie_beacon_reporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 66 (0x42) */ +typedef struct sDot11fIEMeasurementPilot { + uint8_t present; + uint8_t measurementPilot; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMeasurementPilot; + +#define DOT11F_EID_MEASUREMENTPILOT (66) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTPILOT_MIN_LEN (1) + +#define DOT11F_IE_MEASUREMENTPILOT_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_pilot( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementPilot*); + +uint32_t dot11f_pack_ie_measurement_pilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MeasurementPilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 71 (0x47) */ +typedef struct sDot11fIEMultiBssid { + uint8_t present; + uint8_t maxBSSIDIndicator; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMultiBssid; + +#define DOT11F_EID_MULTIBSSID (71) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MULTIBSSID_MIN_LEN (1) + +#define DOT11F_IE_MULTIBSSID_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_multi_bssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMultiBssid*); + +uint32_t dot11f_pack_ie_multi_bssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MultiBssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICData { + uint8_t present; + uint8_t Identifier; + uint8_t resourceDescCount; + uint16_t statusCode; +} tDot11fIERICData; + +#define DOT11F_EID_RICDATA (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATA_MIN_LEN (4) + +#define DOT11F_IE_RICDATA_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_data( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICData*); + +uint32_t dot11f_pack_ie_ric_data( + tpAniSirGlobal, + tDot11fIERICData *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICData( + tpAniSirGlobal, + tDot11fIERICData *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 75 (0x4b) */ +typedef struct sDot11fIERICDescriptor { + uint8_t present; + uint8_t resourceType; + uint8_t num_variableData; + uint8_t variableData[255]; +} tDot11fIERICDescriptor; + +#define DOT11F_EID_RICDESCRIPTOR (75) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDESCRIPTOR_MIN_LEN (1) + +#define DOT11F_IE_RICDESCRIPTOR_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_descriptor( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDescriptor*); + +uint32_t dot11f_pack_ie_ric_descriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICDescriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 70 (0x46) */ +typedef struct sDot11fIERRMEnabledCap { + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tDot11fIERRMEnabledCap; + +#define DOT11F_EID_RRMENABLEDCAP (70) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RRMENABLEDCAP_MIN_LEN (5) + +#define DOT11F_IE_RRMENABLEDCAP_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rrm_enabled_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERRMEnabledCap*); + +uint32_t dot11f_pack_ie_rrm_enabled_cap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RRMEnabledCap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 10 (0x0a) */ +typedef struct sDot11fIERequestedInfo { + uint8_t present; + uint8_t num_requested_eids; + uint8_t requested_eids[255]; +} tDot11fIERequestedInfo; + +#define DOT11F_EID_REQUESTEDINFO (10) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REQUESTEDINFO_MIN_LEN (0) + +#define DOT11F_IE_REQUESTEDINFO_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_requested_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERequestedInfo*); + +uint32_t dot11f_pack_ie_requested_info( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RequestedInfo( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 0 (0x00) */ +typedef struct sDot11fIESSID { + uint8_t present; + uint8_t num_ssid; + uint8_t ssid[32]; +} tDot11fIESSID; + +#define DOT11F_EID_SSID (0) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SSID_MIN_LEN (0) + +#define DOT11F_IE_SSID_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESSID*); + +uint32_t dot11f_pack_ie_ssid( + tpAniSirGlobal, + tDot11fIESSID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SSID( + tpAniSirGlobal, + tDot11fIESSID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 15 (0x0f) */ +typedef struct sDot11fIESchedule { + uint8_t present; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIESchedule; + +#define DOT11F_EID_SCHEDULE (15) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SCHEDULE_MIN_LEN (14) + +#define DOT11F_IE_SCHEDULE_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESchedule*); + +uint32_t dot11f_pack_ie_schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 14 (0x0e) */ +typedef struct sDot11fIETCLAS { + uint8_t present; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIETCLAS; + +#define DOT11F_EID_TCLAS (14) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLAS_MIN_LEN (5) + +#define DOT11F_IE_TCLAS_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLAS*); + +uint32_t dot11f_pack_ie_tclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 44 (0x2c) */ +typedef struct sDot11fIETCLASSPROC { + uint8_t present; + uint8_t processing; +} tDot11fIETCLASSPROC; + +#define DOT11F_EID_TCLASSPROC (44) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLASSPROC_MIN_LEN (1) + +#define DOT11F_IE_TCLASSPROC_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tclasSPROC( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLASSPROC*); + +uint32_t dot11f_pack_ie_tclassproc( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclasSPROC( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 43 (0x2b) */ +typedef struct sDot11fIETSDelay { + uint8_t present; + uint32_t delay; +} tDot11fIETSDelay; + +#define DOT11F_EID_TSDELAY (43) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSDELAY_MIN_LEN (4) + +#define DOT11F_IE_TSDELAY_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSDelay*); + +uint32_t dot11f_pack_ie_ts_delay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSDelay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 13 (0x0d) */ +typedef struct sDot11fIETSPEC { + uint8_t present; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t schedule:1; + uint8_t unused:7; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIETSPEC; + +#define DOT11F_EID_TSPEC (13) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSPEC_MIN_LEN (55) + +#define DOT11F_IE_TSPEC_MAX_LEN (55) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSPEC*); + +uint32_t dot11f_pack_ie_tspec( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSPEC( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 191 (0xbf) */ +typedef struct sDot11fIEVHTCaps { + uint8_t present; + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t reserved1:2; + uint16_t rxMCSMap; + uint16_t rxHighSupDataRate:13; + uint16_t reserved2:3; + uint16_t txMCSMap; + uint16_t txSupDataRate:13; + uint16_t reserved3:3; +} tDot11fIEVHTCaps; + +#define DOT11F_EID_VHTCAPS (191) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTCAPS_MIN_LEN (12) + +#define DOT11F_IE_VHTCAPS_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTCaps*); + +uint32_t dot11f_pack_ie_vht_caps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTCaps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 192 (0xc0) */ +typedef struct sDot11fIEVHTOperation { + uint8_t present; + uint8_t chanWidth; + uint8_t chanCenterFreqSeg1; + uint8_t chanCenterFreqSeg2; + uint16_t basicMCSSet; +} tDot11fIEVHTOperation; + +#define DOT11F_EID_VHTOPERATION (192) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTOPERATION_MIN_LEN (5) + +#define DOT11F_IE_VHTOPERATION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_operation( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTOperation*); + +uint32_t dot11f_pack_ie_vht_operation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTOperation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x09} */ +typedef struct sDot11fIEWMMSchedule { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIEWMMSchedule; + +#define DOT11F_EID_WMMSCHEDULE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMSCHEDULE_MIN_LEN (20) + +#define DOT11F_IE_WMMSCHEDULE_MAX_LEN (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMSchedule*); + +uint32_t dot11f_pack_ie_wmm_schedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMSchedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x06} */ +typedef struct sDot11fIEWMMTCLAS { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIEWMMTCLAS; + +#define DOT11F_EID_WMMTCLAS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLAS_MIN_LEN (11) + +#define DOT11F_IE_WMMTCLAS_MAX_LEN (49) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLAS*); + +uint32_t dot11f_pack_ie_wmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x07} */ +typedef struct sDot11fIEWMMTCLASPROC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t processing; +} tDot11fIEWMMTCLASPROC; + +#define DOT11F_EID_WMMTCLASPROC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLASPROC_MIN_LEN (7) + +#define DOT11F_IE_WMMTCLASPROC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtclasproc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLASPROC*); + +uint32_t dot11f_pack_ie_wmmtclasproc( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclasPROC( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x08} */ +typedef struct sDot11fIEWMMTSDelay { + uint8_t present; + uint8_t version /* Must be 1! */; + uint32_t delay; +} tDot11fIEWMMTSDelay; + +#define DOT11F_EID_WMMTSDELAY (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSDELAY_MIN_LEN (10) + +#define DOT11F_IE_WMMTSDELAY_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSDelay*); + +uint32_t dot11f_pack_ie_wmmts_delay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSDelay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x02} */ +typedef struct sDot11fIEWMMTSPEC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t tsinfo_rsvd:7; + uint8_t burst_size_defn:1; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIEWMMTSPEC; + +#define DOT11F_EID_WMMTSPEC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSPEC_MIN_LEN (61) + +#define DOT11F_IE_WMMTSPEC_MAX_LEN (61) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSPEC*); + +uint32_t dot11f_pack_ie_wmmtspec( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSPEC( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 194 (0xc2) */ +typedef struct sDot11fIEWiderBWChanSwitchAnn { + uint8_t present; + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tDot11fIEWiderBWChanSwitchAnn; + +#define DOT11F_EID_WIDERBWCHANSWITCHANN (194) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWiderBWChanSwitchAnn*); + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WiderBWChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 197 (0xc5) */ +typedef struct sDot11fIEAID { + uint8_t present; + uint16_t assocId; +} tDot11fIEAID; + +#define DOT11F_EID_AID (197) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_AID_MIN_LEN (2) + +#define DOT11F_IE_AID_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_aid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAID*); + +uint32_t dot11f_pack_ie_aid( + tpAniSirGlobal, + tDot11fIEAID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_AID( + tpAniSirGlobal, + tDot11fIEAID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIECFParams { + uint8_t present; + uint8_t cfp_count; + uint8_t cfp_period; + uint16_t cfp_maxduration; + uint16_t cfp_durremaining; +} tDot11fIECFParams; + +#define DOT11F_EID_CFPARAMS (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CFPARAMS_MIN_LEN (6) + +#define DOT11F_IE_CFPARAMS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_cf_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECFParams*); + +uint32_t dot11f_pack_ie_cf_params( + tpAniSirGlobal, + tDot11fIECFParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CFParams( + tpAniSirGlobal, + tDot11fIECFParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 16 (0x10) */ +typedef struct sDot11fIEChallengeText { + uint8_t present; + uint8_t num_text; + uint8_t text[253]; +} tDot11fIEChallengeText; + +#define DOT11F_EID_CHALLENGETEXT (16) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHALLENGETEXT_MIN_LEN (1) + +#define DOT11F_IE_CHALLENGETEXT_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_challenge_text( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChallengeText*); + +uint32_t dot11f_pack_ie_challenge_text( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChallengeText( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 37 (0x25) */ +typedef struct sDot11fIEChanSwitchAnn { + uint8_t present; + uint8_t switchMode; + uint8_t newChannel; + uint8_t switchCount; +} tDot11fIEChanSwitchAnn; + +#define DOT11F_EID_CHANSWITCHANN (37) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_CHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChanSwitchAnn*); + +uint32_t dot11f_pack_ie_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 196 (0xc4) */ +typedef struct sDot11fIEChannelSwitchWrapper { + uint8_t present; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +} tDot11fIEChannelSwitchWrapper; + +#define DOT11F_EID_CHANNELSWITCHWRAPPER (196) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MIN_LEN (0) + +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_channel_switch_wrapper( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChannelSwitchWrapper*); + +uint32_t dot11f_pack_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 7 (0x07) */ +typedef struct sDot11fIECountry { + uint8_t present; + uint8_t country[3]; + uint8_t num_triplets; + uint8_t triplets[84][3]; +} tDot11fIECountry; + +#define DOT11F_EID_COUNTRY (7) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_COUNTRY_MIN_LEN (3) + +#define DOT11F_IE_COUNTRY_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_country( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECountry*); + +uint32_t dot11f_pack_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIEDSParams { + uint8_t present; + uint8_t curr_channel; +} tDot11fIEDSParams; + +#define DOT11F_EID_DSPARAMS (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_DSPARAMS_MIN_LEN (1) + +#define DOT11F_IE_DSPARAMS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_DSParams( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEDSParams*); + +uint32_t dot11f_pack_ie_ds_params( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_DSParams( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 12 (0x0c) */ +typedef struct sDot11fIEEDCAParamSet { + uint8_t present; + uint8_t qos; + uint8_t reserved; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEEDCAParamSet; + +#define DOT11F_EID_EDCAPARAMSET (12) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EDCAPARAMSET_MIN_LEN (18) + +#define DOT11F_IE_EDCAPARAMSET_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_edca_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEEDCAParamSet*); + +uint32_t dot11f_pack_ie_edca_param_set( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_EDCAParamSet( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 42 (0x2a) */ +typedef struct sDot11fIEERPInfo { + uint8_t present; + uint8_t non_erp_present:1; + uint8_t use_prot:1; + uint8_t barker_preamble:1; + uint8_t unused:5; +} tDot11fIEERPInfo; + +#define DOT11F_EID_ERPINFO (42) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ERPINFO_MIN_LEN (1) + +#define DOT11F_IE_ERPINFO_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_erp_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEERPInfo*); + +uint32_t dot11f_pack_ie_erp_info( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ERPInfo( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 156 (0x9c) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESECckmOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[20]; +} tDot11fIEESECckmOpaque; + +#define DOT11F_EID_ESECCKMOPAQUE (156) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESECCKMOPAQUE_MIN_LEN (10) + +#define DOT11F_IE_ESECCKMOPAQUE_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_cckm_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESECckmOpaque*); + +uint32_t dot11f_pack_ie_ese_cckm_opaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESECckmOpaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x01} */ +typedef struct sDot11fIEESERadMgmtCap { + uint8_t present; + uint8_t mgmt_state; + uint8_t mbssid_mask:3; + uint8_t reserved:5; +} tDot11fIEESERadMgmtCap; + +#define DOT11F_EID_ESERADMGMTCAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESERADMGMTCAP_MIN_LEN (6) + +#define DOT11F_IE_ESERADMGMTCAP_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESERadMgmtCap*); + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESERadMgmtCap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x07} */ +typedef struct sDot11fIEESETrafStrmMet { + uint8_t present; + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tDot11fIEESETrafStrmMet; + +#define DOT11F_EID_ESETRAFSTRMMET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMMET_MIN_LEN (8) + +#define DOT11F_IE_ESETRAFSTRMMET_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_traf_strm_met( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmMet*); + +uint32_t dot11f_pack_ie_ese_traf_strm_met( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmMet( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x08} */ +typedef struct sDot11fIEESETrafStrmRateSet { + uint8_t present; + uint8_t tsid; + uint8_t num_tsrates; + uint8_t tsrates[8]; +} tDot11fIEESETrafStrmRateSet; + +#define DOT11F_EID_ESETRAFSTRMRATESET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMRATESET_MIN_LEN (5) + +#define DOT11F_IE_ESETRAFSTRMRATESET_MAX_LEN (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmRateSet*); + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmRateSet( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 150 (0x96) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESETxmitPower { + uint8_t present; + uint8_t power_limit; + uint8_t reserved; +} tDot11fIEESETxmitPower; + +#define DOT11F_EID_ESETXMITPOWER (150) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETXMITPOWER_MIN_LEN (6) + +#define DOT11F_IE_ESETXMITPOWER_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_txmit_power( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETxmitPower*); + +uint32_t dot11f_pack_ie_ese_txmit_power( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETxmitPower( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x03} */ +typedef struct sDot11fIEESEVersion { + uint8_t present; + uint8_t version; +} tDot11fIEESEVersion; + +#define DOT11F_EID_ESEVERSION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESEVERSION_MIN_LEN (5) + +#define DOT11F_IE_ESEVERSION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_version( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESEVersion*); + +uint32_t dot11f_pack_ie_ese_version( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESEVersion( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 127 (0x7f) */ +typedef struct sDot11fIEExtCap { + uint8_t present; + uint8_t num_bytes; + uint8_t bytes[9]; +} tDot11fIEExtCap; + +#define DOT11F_EID_EXTCAP (127) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTCAP_MIN_LEN (8) + +#define DOT11F_IE_EXTCAP_MAX_LEN (9) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtCap*); + +uint32_t dot11f_pack_ie_ext_cap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtCap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 50 (0x32) */ +typedef struct sDot11fIEExtSuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIEExtSuppRates; + +#define DOT11F_EID_EXTSUPPRATES (50) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTSUPPRATES_MIN_LEN (1) + +#define DOT11F_IE_EXTSUPPRATES_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtSuppRates*); + +uint32_t dot11f_pack_ie_ext_supp_rates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtSuppRates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEFHParamSet { + uint8_t present; + uint16_t dwell_time; + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} tDot11fIEFHParamSet; + +#define DOT11F_EID_FHPARAMSET (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMSET_MIN_LEN (5) + +#define DOT11F_IE_FHPARAMSET_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParamSet*); + +uint32_t dot11f_pack_ie_fh_param_set( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParamSet( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 8 (0x08) */ +typedef struct sDot11fIEFHParams { + uint8_t present; + uint8_t radix; + uint8_t nchannels; +} tDot11fIEFHParams; + +#define DOT11F_EID_FHPARAMS (8) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMS_MIN_LEN (2) + +#define DOT11F_IE_FHPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParams*); + +uint32_t dot11f_pack_ie_fh_params( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParams( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 9 (0x09) */ +typedef struct sDot11fIEFHPattTable { + uint8_t present; + uint8_t flag; + uint8_t nsets; + uint8_t modulus; + uint8_t offset; + uint8_t num_randtable; + uint8_t randtable[251]; +} tDot11fIEFHPattTable; + +#define DOT11F_EID_FHPATTTABLE (9) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPATTTABLE_MIN_LEN (4) + +#define DOT11F_IE_FHPATTTABLE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_patt_table( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHPattTable*); + +uint32_t dot11f_pack_ie_fh_patt_table( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHPattTable( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 55 (0x37) */ +typedef struct sDot11fIEFTInfo { + uint8_t present; + uint16_t reserved:8; + uint16_t IECount:8; + uint8_t MIC[16]; + uint8_t Anonce[32]; + uint8_t Snonce[32]; + tDot11fIER1KH_ID R1KH_ID; + tDot11fIEGTK GTK; + tDot11fIER0KH_ID R0KH_ID; + tDot11fIEIGTK IGTK; +} tDot11fIEFTInfo; + +#define DOT11F_EID_FTINFO (55) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FTINFO_MIN_LEN (82) + +#define DOT11F_IE_FTINFO_MAX_LEN (220) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ft_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFTInfo*); + +uint32_t dot11f_pack_ie_ft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 45 (0x2d) */ +typedef struct sDot11fIEHTCaps { + uint8_t present; + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTCaps; + +#define DOT11F_EID_HTCAPS (45) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTCAPS_MIN_LEN (26) + +#define DOT11F_IE_HTCAPS_MAX_LEN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTCaps*); + +uint32_t dot11f_pack_ie_ht_caps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTCaps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 61 (0x3d) */ +typedef struct sDot11fIEHTInfo { + uint8_t present; + uint8_t primaryChannel; + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; + uint16_t reserved:11; + uint16_t basicSTBCMCS:7; + uint16_t dualCTSProtection:1; + uint16_t secondaryBeacon:1; + uint16_t lsigTXOPProtectionFullSupport:1; + uint16_t pcoActive:1; + uint16_t pcoPhase:1; + uint16_t reserved2:4; + uint8_t basicMCSSet[16]; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTInfo; + +#define DOT11F_EID_HTINFO (61) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTINFO_MIN_LEN (22) + +#define DOT11F_IE_HTINFO_MAX_LEN (54) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTInfo*); + +uint32_t dot11f_pack_ie_ht_info( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTInfo( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 6 (0x06) */ +typedef struct sDot11fIEIBSSParams { + uint8_t present; + uint16_t atim; +} tDot11fIEIBSSParams; + +#define DOT11F_EID_IBSSPARAMS (6) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IBSSPARAMS_MIN_LEN (2) + +#define DOT11F_IE_IBSSPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ibss_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIBSSParams*); + +uint32_t dot11f_pack_ie_ibss_params( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IBSSParams( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 101 (0x65) */ +typedef struct sDot11fIELinkIdentifier { + uint8_t present; + uint8_t bssid[6]; + uint8_t InitStaAddr[6]; + uint8_t RespStaAddr[6]; +} tDot11fIELinkIdentifier; + +#define DOT11F_EID_LINKIDENTIFIER (101) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_LINKIDENTIFIER_MIN_LEN (18) + +#define DOT11F_IE_LINKIDENTIFIER_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_link_identifier( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIELinkIdentifier*); + +uint32_t dot11f_pack_ie_link_identifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_LinkIdentifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 39 (0x27) */ +typedef struct sDot11fIEMeasurementReport { + uint8_t present; + uint8_t token; + uint8_t late:1; + uint8_t incapable:1; + uint8_t refused:1; + uint8_t unused:5; + uint8_t type; + union { + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t bss:1; + uint8_t ofdm_preamble:1; + uint8_t unid_signal:1; + uint8_t rader:1; + uint8_t unmeasured:1; + uint8_t unused:3; + } Basic; /* type = 0 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t cca_busy_fraction; + } CCA; /* type = 1 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t rpi0_density; + uint8_t rpi1_density; + uint8_t rpi2_density; + uint8_t rpi3_density; + uint8_t rpi4_density; + uint8_t rpi5_density; + uint8_t rpi6_density; + uint8_t rpi7_density; + } RPIHistogram; /* type = 2 */ + struct { + uint8_t regClass; + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t condensed_PHY:7; + uint8_t reported_frame_type:1; + uint8_t RCPI; + uint8_t RSNI; + uint8_t BSSID[6]; + uint8_t antenna_id; + uint32_t parent_TSF; + tDot11fIEBeaconReportFrmBody BeaconReportFrmBody; + } Beacon; /* type = 5 */ + } report; +} tDot11fIEMeasurementReport; + +#define DOT11F_EID_MEASUREMENTREPORT (39) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREPORT_MIN_LEN (3) + +#define DOT11F_IE_MEASUREMENTREPORT_MAX_LEN (29) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementReport*); + +uint32_t dot11f_pack_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 38 (0x26) */ +typedef struct sDot11fIEMeasurementRequest { + uint8_t present; + uint8_t measurement_token; + uint8_t parallel:1; + uint8_t enable:1; + uint8_t request:1; + uint8_t report:1; + uint8_t durationMandatory:1; + uint8_t unused:3; + uint8_t measurement_type; + union { + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } Basic; /* measurement_type = 0 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } CCA; /* measurement_type = 1 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } RPIHistogram; /* measurement_type = 2 */ + struct { + uint8_t regClass; + uint8_t channel; + uint16_t randomization; + uint16_t meas_duration; + uint8_t meas_mode; + uint8_t BSSID[6]; + tDot11fIESSID SSID; + tDot11fIEBeaconReporting BeaconReporting; + tDot11fIEBcnReportingDetail BcnReportingDetail; + tDot11fIERequestedInfo RequestedInfo; + uint16_t num_APChannelReport; + tDot11fIEAPChannelReport APChannelReport[2]; + } Beacon; /* measurement_type = 5 */ + } measurement_request; +} tDot11fIEMeasurementRequest; + +#define DOT11F_EID_MEASUREMENTREQUEST (38) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN (14) + +#define DOT11F_IE_MEASUREMENTREQUEST_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementRequest*); + +uint32_t dot11f_pack_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 54 (0x36) */ +typedef struct sDot11fIEMobilityDomain { + uint8_t present; + uint16_t MDID; + uint8_t overDSCap:1; + uint8_t resourceReqCap:1; + uint8_t reserved:6; +} tDot11fIEMobilityDomain; + +#define DOT11F_EID_MOBILITYDOMAIN (54) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MOBILITYDOMAIN_MIN_LEN (3) + +#define DOT11F_IE_MOBILITYDOMAIN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_mobility_domain( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMobilityDomain*); + +uint32_t dot11f_pack_ie_mobility_domain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MobilityDomain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 52 (0x34) */ +typedef struct sDot11fIENeighborReport { + uint8_t present; + uint8_t bssid[6]; + uint8_t APReachability:2; + uint8_t Security:1; + uint8_t KeyScope:1; + uint8_t SpecMgmtCap:1; + uint8_t QosCap:1; + uint8_t apsd:1; + uint8_t rrm:1; + uint8_t DelayedBA:1; + uint8_t ImmBA:1; + uint8_t MobilityDomain:1; + uint8_t reserved:5; + uint16_t reserved1; + uint8_t regulatoryClass; + uint8_t channel; + uint8_t PhyType; + tDot11fIETSFInfo TSFInfo; + tDot11fIECondensedCountryStr CondensedCountryStr; + tDot11fIEMeasurementPilot MeasurementPilot; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMultiBssid MultiBssid; +} tDot11fIENeighborReport; + +#define DOT11F_EID_NEIGHBORREPORT (52) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NEIGHBORREPORT_MIN_LEN (13) + +#define DOT11F_IE_NEIGHBORREPORT_MAX_LEN (546) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_neighbor_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIENeighborReport*); + +uint32_t dot11f_pack_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 74 (0x4a) */ +typedef struct sDot11fIEOBSSScanParameters { + uint8_t present; + uint16_t obssScanPassiveDwell; + uint16_t obssScanActiveDwell; + uint16_t bssChannelWidthTriggerScanInterval; + uint16_t obssScanPassiveTotalPerChannel; + uint16_t obssScanActiveTotalPerChannel; + uint16_t bssWidthChannelTransitionDelayFactor; + uint16_t obssScanActivityThreshold; +} tDot11fIEOBSSScanParameters; + +#define DOT11F_EID_OBSSSCANPARAMETERS (74) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OBSSSCANPARAMETERS_MIN_LEN (14) + +#define DOT11F_IE_OBSSSCANPARAMETERS_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_obss_scan_parameters( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOBSSScanParameters*); + +uint32_t dot11f_pack_ie_obss_scan_parameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OBSSScanParameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 199 (0xc7) */ +typedef struct sDot11fIEOperatingMode { + uint8_t present; + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fIEOperatingMode; + +#define DOT11F_EID_OPERATINGMODE (199) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OPERATINGMODE_MIN_LEN (1) + +#define DOT11F_IE_OPERATINGMODE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_operating_mode( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOperatingMode*); + +uint32_t dot11f_pack_ie_operating_mode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OperatingMode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; +} tDot11fIEP2PAssocReq; + +#define DOT11F_EID_P2PASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCREQ_MAX_LEN (71) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocReq*); + +uint32_t dot11f_pack_ie_p2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocRes { + uint8_t present; + tDot11fTLVP2PStatus P2PStatus; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; +} tDot11fIEP2PAssocRes; + +#define DOT11F_EID_P2PASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCRES_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocRes*); + +uint32_t dot11f_pack_ie_p2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeacon { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; +} tDot11fIEP2PBeacon; + +#define DOT11F_EID_P2PBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACON_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACON_MAX_LEN (59) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeacon*); + +uint32_t dot11f_pack_ie_p2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeaconProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PBeaconProbeRes; + +#define DOT11F_EID_P2PBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACONPROBERES_MAX_LEN (1148) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeaconProbeRes*); + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDeAuth { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDeAuth; + +#define DOT11F_EID_P2PDEAUTH (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDEAUTH_MIN_LEN (4) + +#define DOT11F_IE_P2PDEAUTH_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_de_auth( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDeAuth*); + +uint32_t dot11f_pack_ie_p2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDisAssoc { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDisAssoc; + +#define DOT11F_EID_P2PDISASSOC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDISASSOC_MIN_LEN (4) + +#define DOT11F_IE_P2PDISASSOC_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDisAssoc*); + +uint32_t dot11f_pack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} */ +typedef struct sDot11fIEP2PIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEP2PIEOpaque; + +#define DOT11F_EID_P2PIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_P2PIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_pie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PIEOpaque*); + +uint32_t dot11f_pack_ie_p2_pie_opaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_P2PIEOpaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVListenChannel ListenChannel; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVOperatingChannel OperatingChannel; +} tDot11fIEP2PProbeReq; + +#define DOT11F_EID_P2PPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBEREQ_MAX_LEN (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeReq*); + +uint32_t dot11f_pack_ie_p2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PProbeRes; + +#define DOT11F_EID_P2PPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBERES_MAX_LEN (1139) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeRes*); + +uint32_t dot11f_pack_ie_p2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 105 (0x69) */ +typedef struct sDot11fIEPTIControl { + uint8_t present; + uint8_t tid; + uint16_t sequence_control; +} tDot11fIEPTIControl; + +#define DOT11F_EID_PTICONTROL (105) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PTICONTROL_MIN_LEN (3) + +#define DOT11F_IE_PTICONTROL_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_pti_control( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPTIControl*); + +uint32_t dot11f_pack_ie_pti_control( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PTIControl( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 106 (0x6a) */ +typedef struct sDot11fIEPUBufferStatus { + uint8_t present; + uint8_t ac_bk_traffic_aval:1; + uint8_t ac_be_traffic_aval:1; + uint8_t ac_vi_traffic_aval:1; + uint8_t ac_vo_traffic_aval:1; + uint8_t reserved:4; +} tDot11fIEPUBufferStatus; + +#define DOT11F_EID_PUBUFFERSTATUS (106) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PUBUFFERSTATUS_MIN_LEN (1) + +#define DOT11F_IE_PUBUFFERSTATUS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_pu_buffer_status( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPUBufferStatus*); + +uint32_t dot11f_pack_ie_pu_buffer_status( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PUBufferStatus( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 33 (0x21) */ +typedef struct sDot11fIEPowerCaps { + uint8_t present; + uint8_t minTxPower; + uint8_t maxTxPower; +} tDot11fIEPowerCaps; + +#define DOT11F_EID_POWERCAPS (33) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCAPS_MIN_LEN (2) + +#define DOT11F_IE_POWERCAPS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_power_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerCaps*); + +uint32_t dot11f_pack_ie_power_caps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerCaps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 32 (0x20) */ +typedef struct sDot11fIEPowerConstraints { + uint8_t present; + uint8_t localPowerConstraints; +} tDot11fIEPowerConstraints; + +#define DOT11F_EID_POWERCONSTRAINTS (32) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCONSTRAINTS_MIN_LEN (1) + +#define DOT11F_IE_POWERCONSTRAINTS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_power_constraints( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerConstraints*); + +uint32_t dot11f_pack_ie_power_constraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerConstraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 11 (0x0b) */ +typedef struct sDot11fIEQBSSLoad { + uint8_t present; + uint16_t stacount; + uint8_t chautil; + uint16_t avail; +} tDot11fIEQBSSLoad; + +#define DOT11F_EID_QBSSLOAD (11) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_QBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qbss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQBSSLoad*); + +uint32_t dot11f_pack_ie_qbss_load( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QBSSLoad( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0xa0, 0xc6} */ +typedef struct sDot11fIEQComVendorIE { + uint8_t present; + uint8_t type; + uint8_t channel; +} tDot11fIEQComVendorIE; + +#define DOT11F_EID_QCOMVENDORIE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QCOMVENDORIE_MIN_LEN (5) + +#define DOT11F_IE_QCOMVENDORIE_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_QComVendorIE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQComVendorIE*); + +uint32_t dot11f_pack_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsAp { + uint8_t present; + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t reserved:1; +} tDot11fIEQOSCapsAp; + +#define DOT11F_EID_QOSCAPSAP (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSAP_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_caps_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsAp*); + +uint32_t dot11f_pack_ie_qos_caps_ap( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsAp( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsStation { + uint8_t present; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t max_sp_length:2; + uint8_t more_data_ack:1; +} tDot11fIEQOSCapsStation; + +#define DOT11F_EID_QOSCAPSSTATION (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSSTATION_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSSTATION_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_caps_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsStation*); + +uint32_t dot11f_pack_ie_qos_caps_station( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsStation( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 110 (0x6e) */ +typedef struct sDot11fIEQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[60]; +} tDot11fIEQosMapSet; + +#define DOT11F_EID_QOSMAPSET (110) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSMAPSET_MIN_LEN (0) + +#define DOT11F_IE_QOSMAPSET_MAX_LEN (60) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_map_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQosMapSet*); + +uint32_t dot11f_pack_ie_qos_map_set( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QosMapSet( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 40 (0x28) */ +typedef struct sDot11fIEQuiet { + uint8_t present; + uint8_t count; + uint8_t period; + uint16_t duration; + uint16_t offset; +} tDot11fIEQuiet; + +#define DOT11F_EID_QUIET (40) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QUIET_MIN_LEN (6) + +#define DOT11F_IE_QUIET_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_quiet( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQuiet*); + +uint32_t dot11f_pack_ie_quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 53 (0x35) */ +typedef struct sDot11fIERCPIIE { + uint8_t present; + uint8_t rcpi; +} tDot11fIERCPIIE; + +#define DOT11F_EID_RCPIIE (53) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RCPIIE_MIN_LEN (1) + +#define DOT11F_IE_RCPIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rcpiie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERCPIIE*); + +uint32_t dot11f_pack_ie_rcpiie( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RCPIIE( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICDataDesc { + uint8_t present; + tDot11fIERICData RICData; + tDot11fIERICDescriptor RICDescriptor; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIETSDelay TSDelay; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; +} tDot11fIERICDataDesc; + +#define DOT11F_EID_RICDATADESC (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATADESC_MIN_LEN (0) + +#define DOT11F_IE_RICDATADESC_MAX_LEN (548) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_data_desc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDataDesc*); + +uint32_t dot11f_pack_ie_ric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSN { + uint8_t present; + uint16_t version /* Must be 1! */; + uint8_t gp_cipher_suite[4]; + uint16_t pwise_cipher_suite_count; + uint8_t pwise_cipher_suites[4][4]; + uint16_t akm_suite_count; + uint8_t akm_suites[4][4]; + uint8_t RSN_Cap[2]; + uint16_t pmkid_count; + uint8_t pmkid[4][16]; + uint8_t gp_mgmt_cipher_suite[4]; +} tDot11fIERSN; + +#define DOT11F_EID_RSN (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSN_MIN_LEN (6) + +#define DOT11F_IE_RSN_MAX_LEN (114) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsn( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSN*); + +uint32_t dot11f_pack_ie_rsn( + tpAniSirGlobal, + tDot11fIERSN *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersn( + tpAniSirGlobal, + tDot11fIERSN *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 65 (0x41) */ +typedef struct sDot11fIERSNIIE { + uint8_t present; + uint8_t rsni; +} tDot11fIERSNIIE; + +#define DOT11F_EID_RSNIIE (65) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNIIE_MIN_LEN (1) + +#define DOT11F_IE_RSNIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsniie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNIIE*); + +uint32_t dot11f_pack_ie_rsniie( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnIIE( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSNOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIERSNOpaque; + +#define DOT11F_EID_RSNOPAQUE (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_RSNOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsn_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNOpaque*); + +uint32_t dot11f_pack_ie_rsn_opaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnOpaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 36 (0x24) */ +typedef struct sDot11fIESuppChannels { + uint8_t present; + uint8_t num_bands; + uint8_t bands[48][2]; +} tDot11fIESuppChannels; + +#define DOT11F_EID_SUPPCHANNELS (36) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPCHANNELS_MIN_LEN (2) + +#define DOT11F_IE_SUPPCHANNELS_MAX_LEN (96) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_channels( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppChannels*); + +uint32_t dot11f_pack_ie_supp_channels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppChannels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 59 (0x3b) */ +typedef struct sDot11fIESuppOperatingClasses { + uint8_t present; + uint8_t num_classes; + uint8_t classes[32]; +} tDot11fIESuppOperatingClasses; + +#define DOT11F_EID_SUPPOPERATINGCLASSES (59) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPOPERATINGCLASSES_MIN_LEN (1) + +#define DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_operating_classes( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppOperatingClasses*); + +uint32_t dot11f_pack_ie_supp_operating_classes( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppOperatingClasses( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIESuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIESuppRates; + +#define DOT11F_EID_SUPPRATES (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPRATES_MIN_LEN (0) + +#define DOT11F_IE_SUPPRATES_MAX_LEN (12) + +#define DOT11F_IS_BG_RATE(_x) (((_x) == 02) || \ + ((_x) == 04) || \ + ((_x) == 11) || \ + ((_x) == 22) || \ + ((_x) == 12) || \ + ((_x) == 18) || \ + ((_x) == 24) || \ + ((_x) == 36) || \ + ((_x) == 48) || \ + ((_x) == 72) || \ + ((_x) == 96) || \ + ((_x) == 108)) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppRates*); + +uint32_t dot11f_pack_ie_supp_rates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppRates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 5 (0x05) */ +typedef struct sDot11fIETIM { + uint8_t present; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t bmpctl; + uint8_t num_vbmp; + uint8_t vbmp[251]; +} tDot11fIETIM; + +#define DOT11F_EID_TIM (5) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIM_MIN_LEN (4) + +#define DOT11F_IE_TIM_MAX_LEN (254) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tim( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETIM*); + +uint32_t dot11f_pack_ie_tim( + tpAniSirGlobal, + tDot11fIETIM *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TIM( + tpAniSirGlobal, + tDot11fIETIM *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 35 (0x23) */ +typedef struct sDot11fIETPCReport { + uint8_t present; + uint8_t tx_power; + uint8_t link_margin; +} tDot11fIETPCReport; + +#define DOT11F_EID_TPCREPORT (35) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREPORT_MIN_LEN (2) + +#define DOT11F_IE_TPCREPORT_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tpc_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCReport*); + +uint32_t dot11f_pack_ie_tpc_report( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCReport( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 34 (0x22) */ +typedef struct sDot11fIETPCRequest { + uint8_t present; +} tDot11fIETPCRequest; + +#define DOT11F_EID_TPCREQUEST (34) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREQUEST_MIN_LEN (0) + +#define DOT11F_IE_TPCREQUEST_MAX_LEN (0) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tpc_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCRequest*); + +uint32_t dot11f_pack_ie_tpc_request( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCRequest( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 69 (0x45) */ +typedef struct sDot11fIETimeAdvertisement { + uint8_t present; + uint8_t timing_capabilities; + uint8_t time_value[10]; + uint8_t time_error[5]; +} tDot11fIETimeAdvertisement; + +#define DOT11F_EID_TIMEADVERTISEMENT (69) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEADVERTISEMENT_MIN_LEN (16) + +#define DOT11F_IE_TIMEADVERTISEMENT_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_time_advertisement( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeAdvertisement*); + +uint32_t dot11f_pack_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 56 (0x38) */ +typedef struct sDot11fIETimeoutInterval { + uint8_t present; + uint8_t timeoutType; + uint32_t timeoutValue; +} tDot11fIETimeoutInterval; + +#define DOT11F_EID_TIMEOUTINTERVAL (56) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEOUTINTERVAL_MIN_LEN (5) + +#define DOT11F_IE_TIMEOUTINTERVAL_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_timeout_interval( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeoutInterval*); + +uint32_t dot11f_pack_ie_timeout_interval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TimeoutInterval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 193 (0xc1) */ +typedef struct sDot11fIEVHTExtBssLoad { + uint8_t present; + uint8_t muMIMOCapStaCount; + uint8_t ssUnderUtil; + uint8_t FortyMHzUtil; + uint8_t EightyMHzUtil; + uint8_t OneSixtyMHzUtil; +} tDot11fIEVHTExtBssLoad; + +#define DOT11F_EID_VHTEXTBSSLOAD (193) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTEXTBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_VHTEXTBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_ext_bss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTExtBssLoad*); + +uint32_t dot11f_pack_ie_vht_ext_bss_load( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTExtBssLoad( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x10, 0x18} */ +typedef struct sDot11fIEVendor1IE { + uint8_t present; +} tDot11fIEVendor1IE; + +#define DOT11F_EID_VENDOR1IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR1IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR1IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor1_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor1IE*); + +uint32_t dot11f_pack_ie_vendor1_ie( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor1IE( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x16, 0x32} */ +typedef struct sDot11fIEVendor3IE { + uint8_t present; +} tDot11fIEVendor3IE; + +#define DOT11F_EID_VENDOR3IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR3IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR3IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor3_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor3IE*); + +uint32_t dot11f_pack_ie_vendor3_ie( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor3IE( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPI { + uint8_t present; + uint16_t version /* Must be 1! */; + uint16_t akm_suite_count; + uint8_t akm_suites[4][4]; + uint16_t unicast_cipher_suite_count; + uint8_t unicast_cipher_suites[4][4]; + uint8_t multicast_cipher_suite[4]; + uint16_t preauth:1; + uint16_t reserved:15; + uint16_t bkid_count; + uint8_t bkid[4][16]; +} tDot11fIEWAPI; + +#define DOT11F_EID_WAPI (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPI_MIN_LEN (12) + +#define DOT11F_IE_WAPI_MAX_LEN (110) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wapi( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPI*); + +uint32_t dot11f_pack_ie_wapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPIOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIEWAPIOpaque; + +#define DOT11F_EID_WAPIOPAQUE (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPIOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WAPIOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wapi_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPIOpaque*); + +uint32_t dot11f_pack_ie_wapi_opaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapiOpaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x08, 0x00} */ +typedef struct sDot11fIEWFATPC { + uint8_t present; + uint8_t txPower; + uint8_t linkMargin; +} tDot11fIEWFATPC; + +#define DOT11F_EID_WFATPC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFATPC_MIN_LEN (7) + +#define DOT11F_IE_WFATPC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wfatpc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFATPC*); + +uint32_t dot11f_pack_ie_wfatpc( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFATPC( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x0a} */ +typedef struct sDot11fIEWFDIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWFDIEOpaque; + +#define DOT11F_EID_WFDIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFDIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WFDIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wfdie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFDIEOpaque*); + +uint32_t dot11f_pack_ie_wfdie_opaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFDIEOpaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x05} */ +typedef struct sDot11fIEWMMCaps { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t reserved:4; + uint8_t qack:1; + uint8_t queue_request:1; + uint8_t txop_request:1; + uint8_t more_ack:1; +} tDot11fIEWMMCaps; + +#define DOT11F_EID_WMMCAPS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMCAPS_MIN_LEN (7) + +#define DOT11F_IE_WMMCAPS_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMCaps*); + +uint32_t dot11f_pack_ie_wmm_caps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMCaps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoAp { + uint8_t present; + uint8_t version; + uint8_t param_set_count:4; + uint8_t reserved:3; + uint8_t uapsd:1; +} tDot11fIEWMMInfoAp; + +#define DOT11F_EID_WMMINFOAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOAP_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOAP_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_info_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoAp*); + +uint32_t dot11f_pack_ie_wmm_info_ap( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoAp( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoStation { + uint8_t present; + uint8_t version; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved1:1; + uint8_t max_sp_length:2; + uint8_t reserved2:1; +} tDot11fIEWMMInfoStation; + +#define DOT11F_EID_WMMINFOSTATION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOSTATION_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOSTATION_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_info_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoStation*); + +uint32_t dot11f_pack_ie_wmm_info_station( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoStation( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x01} */ +typedef struct sDot11fIEWMMParams { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t qosInfo; + uint8_t reserved2; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEWMMParams; + +#define DOT11F_EID_WMMPARAMS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMPARAMS_MIN_LEN (24) + +#define DOT11F_IE_WMMPARAMS_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMParams*); + +uint32_t dot11f_pack_ie_wmm_params( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMParams( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPA { + uint8_t present; + uint16_t version /* Must be 1! */; + /* field added to fix the bug in dot11fPackIEWPA */ + uint8_t multicast_cipher_present; + uint8_t multicast_cipher[4]; + uint16_t unicast_cipher_count; + uint8_t unicast_ciphers[4][4]; + uint16_t auth_suite_count; + uint8_t auth_suites[4][4]; + uint16_t caps; +} tDot11fIEWPA; + +#define DOT11F_EID_WPA (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPA_MIN_LEN (6) + +#define DOT11F_IE_WPA_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wpa( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPA*); + +uint32_t dot11f_pack_ie_wpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPAOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWPAOpaque; + +#define DOT11F_EID_WPAOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPAOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WPAOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wpa_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPAOpaque*); + +uint32_t dot11f_pack_ie_wpa_opaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpaOpaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWSC { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVUUID_R UUID_R; + tDot11fTLVRFBands RFBands; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRequestType RequestType; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWSC; + +#define DOT11F_EID_WSC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSC_MIN_LEN (4) + +#define DOT11F_IE_WSC_MAX_LEN (366) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWSC*); + +uint32_t dot11f_pack_ie_wsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocReq; + +#define DOT11F_EID_WSCASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCREQ_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocReq*); + +uint32_t dot11f_pack_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocRes; + +#define DOT11F_EID_WSCASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocRes*); + +uint32_t dot11f_pack_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeacon { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeacon; + +#define DOT11F_EID_WSCBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACON_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACON_MAX_LEN (82) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeacon*); + +uint32_t dot11f_pack_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeaconProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeaconProbeRes; + +#define DOT11F_EID_WSCBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACONPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeaconProbeRes*); + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} */ +typedef struct sDot11fIEWscIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWscIEOpaque; + +#define DOT11F_EID_WSCIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WSCIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_ie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscIEOpaque*); + +uint32_t dot11f_pack_ie_wsc_ie_opaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WscIEOpaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRFBands RFBands; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWscProbeReq; + +#define DOT11F_EID_WSCPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBEREQ_MAX_LEN (284) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeReq*); + +uint32_t dot11f_pack_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscProbeRes; + +#define DOT11F_EID_WSCPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeRes*); + +uint32_t dot11f_pack_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscReassocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscReassocRes; + +#define DOT11F_EID_WSCREASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCREASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCREASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_reassoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscReassocRes*); + +uint32_t dot11f_pack_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 60 (0x3c) */ +typedef struct sDot11fIEext_chan_switch_ann { + uint8_t present; + uint8_t switch_mode; + uint8_t new_reg_class; + uint8_t new_channel; + uint8_t switch_count; +} tDot11fIEext_chan_switch_ann; + +#define DOT11F_EID_EXT_CHAN_SWITCH_ANN (60) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MIN_LEN (4) + +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEext_chan_switch_ann*); + +uint32_t dot11f_pack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 72 (0x48) */ +typedef struct sDot11fIEht2040_bss_coexistence { + uint8_t present; + uint8_t info_request:1; + uint8_t forty_mhz_intolerant:1; + uint8_t twenty_mhz_bsswidth_req:1; + uint8_t obss_scan_exemption_req:1; + uint8_t obss_scan_exemption_grant:1; + uint8_t unused:3; +} tDot11fIEht2040_bss_coexistence; + +#define DOT11F_EID_HT2040_BSS_COEXISTENCE (72) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_coexistence*); + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 73 (0x49) */ +typedef struct sDot11fIEht2040_bss_intolerant_report { + uint8_t present; + uint8_t operating_class; + uint8_t num_channel_list; + uint8_t channel_list[50]; +} tDot11fIEht2040_bss_intolerant_report; + +#define DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT (73) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_intolerant_report*); + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 62 (0x3e) */ +typedef struct sDot11fIEsec_chan_offset_ele { + uint8_t present; + uint8_t secondaryChannelOffset; +} tDot11fIEsec_chan_offset_ele; + +#define DOT11F_EID_SEC_CHAN_OFFSET_ELE (62) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MIN_LEN (1) + +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEsec_chan_offset_ele*); + +uint32_t dot11f_pack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x90, 0x4c} */ +typedef struct sDot11fIEvendor2_ie { + uint8_t present; + uint8_t type; + uint8_t sub_type; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; +} tDot11fIEvendor2_ie; + +#define DOT11F_EID_VENDOR2_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR2_IE_MIN_LEN (5) + +#define DOT11F_IE_VENDOR2_IE_MAX_LEN (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor2_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEvendor2_ie*); + +uint32_t dot11f_pack_ie_vendor2_ie( + tpAniSirGlobal, + tDot11fIEvendor2_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_vendor2_ie( + tpAniSirGlobal, + tDot11fIEvendor2_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/************************************************************************ + * Frames + **********************************************************************/ + +typedef struct sDot11fAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fAddTSRequest; + +#define DOT11F_ADDTSREQUEST (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest * pFrm); +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; + tDot11fIETSDelay TSDelay; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fAddTSResponse; + +#define DOT11F_ADDTSRESPONSE (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse * pFrm); +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor2_ie vendor2_ie; +} tDot11fAssocRequest; + +#define DOT11F_ASSOCREQUEST (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest * pFrm); +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEWscAssocRes WscAssocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor2_ie vendor2_ie; +} tDot11fAssocResponse; + +#define DOT11F_ASSOCRESPONSE (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse * pFrm); +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAuthentication{ + tDot11fFfAuthAlgo AuthAlgo; + tDot11fFfAuthSeqNo AuthSeqNo; + tDot11fFfStatus Status; + tDot11fIEChallengeText ChallengeText; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; +} tDot11fAuthentication; + +#define DOT11F_AUTHENTICATION (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication * pFrm); +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor2_ie vendor2_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; +} tDot11fBeacon; + +#define DOT11F_BEACON (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon * pFrm); +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon1{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEDSParams DSParams; + tDot11fIEIBSSParams IBSSParams; +} tDot11fBeacon1; + +#define DOT11F_BEACON1 (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 * pFrm); +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon2{ + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor2_ie vendor2_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; +} tDot11fBeacon2; + +#define DOT11F_BEACON2 (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 * pFrm); +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeaconIEs{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeaconProbeRes WscBeaconProbeRes; + tDot11fIEP2PBeaconProbeRes P2PBeaconProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor2_ie vendor2_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; +} tDot11fBeaconIEs; + +#define DOT11F_BEACONIES (9) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs * pFrm); +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fChannelSwitch{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +} tDot11fChannelSwitch; + +#define DOT11F_CHANNELSWITCH (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch * pFrm); +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDeAuth{ + tDot11fFfReason Reason; + tDot11fIEP2PDeAuth P2PDeAuth; +} tDot11fDeAuth; + +#define DOT11F_DEAUTH (11) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth * pFrm); +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTSInfo TSInfo; + tDot11fFfReason Reason; +} tDot11fDelTS; + +#define DOT11F_DELTS (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS * pFrm); +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDisassociation{ + tDot11fFfReason Reason; + tDot11fIEP2PDisAssoc P2PDisAssoc; +} tDot11fDisassociation; + +#define DOT11F_DISASSOCIATION (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation * pFrm); +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTPCEleID TPCEleID; + tDot11fFfTPCEleLen TPCEleLen; + tDot11fFfTxPower TxPower; + tDot11fFfLinkMargin LinkMargin; + tDot11fFfRxAntennaId RxAntennaId; + tDot11fFfTxAntennaId TxAntennaId; + tDot11fFfRCPI RCPI; + tDot11fFfRSNI RSNI; +} tDot11fLinkMeasurementReport; + +#define DOT11F_LINKMEASUREMENTREPORT (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport * pFrm); +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTxPower TxPower; + tDot11fFfMaxTxPower MaxTxPower; +} tDot11fLinkMeasurementRequest; + +#define DOT11F_LINKMEASUREMENTREQUEST (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest * pFrm); +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIEMeasurementReport MeasurementReport; +} tDot11fMeasurementReport; + +#define DOT11F_MEASUREMENTREPORT (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport * pFrm); +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[4]; +} tDot11fMeasurementRequest; + +#define DOT11F_MEASUREMENTREQUEST (17) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest * pFrm); +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIESSID SSID; +} tDot11fNeighborReportRequest; + +#define DOT11F_NEIGHBORREPORTREQUEST (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest * pFrm); +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_NeighborReport; + tDot11fIENeighborReport NeighborReport[15]; +} tDot11fNeighborReportResponse; + +#define DOT11F_NEIGHBORREPORTRESPONSE (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse * pFrm); +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fOperatingMode{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfOperatingMode OperatingMode; +} tDot11fOperatingMode; + +#define DOT11F_OPERATINGMODE (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode * pFrm); +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeRequest{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIERequestedInfo RequestedInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEDSParams DSParams; + tDot11fIEHTCaps HTCaps; + tDot11fIEWscProbeReq WscProbeReq; + tDot11fIEWFATPC WFATPC; + tDot11fIEP2PProbeReq P2PProbeReq; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; +} tDot11fProbeRequest; + +#define DOT11F_PROBEREQUEST (21) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest * pFrm); +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeResponse{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscProbeRes WscProbeRes; + tDot11fIEP2PProbeRes P2PProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor2_ie vendor2_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; +} tDot11fProbeResponse; + +#define DOT11F_PROBERESPONSE (22) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse * pFrm); +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fQosMapConfigure{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEQosMapSet QosMapSet; +} tDot11fQosMapConfigure; + +#define DOT11F_QOSMAPCONFIGURE (23) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure * pFrm); +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementReport; + tDot11fIEMeasurementReport MeasurementReport[4]; +} tDot11fRadioMeasurementReport; + +#define DOT11F_RADIOMEASUREMENTREPORT (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport * pFrm); +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfNumOfRepetitions NumOfRepetitions; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[2]; +} tDot11fRadioMeasurementRequest; + +#define DOT11F_RADIOMEASUREMENTREQUEST (25) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest * pFrm); +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fFfCurrentAPAddress CurrentAPAddress; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESECckmOpaque ESECckmOpaque; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor2_ie vendor2_ie; +} tDot11fReAssocRequest; + +#define DOT11F_REASSOCREQUEST (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest * pFrm); +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEWscReassocRes WscReassocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor2_ie vendor2_ie; +} tDot11fReAssocResponse; + +#define DOT11F_REASSOCRESPONSE (27) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse * pFrm); +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSMPowerSave{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfSMPowerModeSet SMPowerModeSet; +} tDot11fSMPowerSave; + +#define DOT11F_SMPOWERSAVE (28) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave * pFrm); +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; +} tDot11fSaQueryReq; + +#define DOT11F_SAQUERYREQ (29) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq * pFrm); +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; +} tDot11fSaQueryRsp; + +#define DOT11F_SAQUERYRSP (30) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp * pFrm); +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSDisReq; + +#define DOT11F_TDLSDISREQ (31) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq * pFrm); +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEVHTCaps VHTCaps; +} tDot11fTDLSDisRsp; + +#define DOT11F_TDLSDISRSP (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp * pFrm); +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficInd{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEPTIControl PTIControl; + tDot11fIEPUBufferStatus PUBufferStatus; +} tDot11fTDLSPeerTrafficInd; + +#define DOT11F_TDLSPEERTRAFFICIND (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd * pFrm); +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSPeerTrafficRsp; + +#define DOT11F_TDLSPEERTRAFFICRSP (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp * pFrm); +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupCnf{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fIERSN RSN; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTInfo HTInfo; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMParams WMMParams; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEOperatingMode OperatingMode; +} tDot11fTDLSSetupCnf; + +#define DOT11F_TDLSSETUPCNF (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf * pFrm); +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; +} tDot11fTDLSSetupReq; + +#define DOT11F_TDLSSETUPREQ (36) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq * pFrm); +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; +} tDot11fTDLSSetupRsp; + +#define DOT11F_TDLSSETUPRSP (37) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp * pFrm); +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSTeardown{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfReason Reason; + tDot11fIEFTInfo FTInfo; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSTeardown; + +#define DOT11F_TDLSTEARDOWN (38) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown * pFrm); +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCReport TPCReport; +} tDot11fTPCReport; + +#define DOT11F_TPCREPORT (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport * pFrm); +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCRequest TPCRequest; +} tDot11fTPCRequest; + +#define DOT11F_TPCREQUEST (40) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest * pFrm); +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTimingAdvertisementFrame{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfCapabilities Capabilities; + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIETimeAdvertisement TimeAdvertisement; + tDot11fIEExtCap ExtCap; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEVendor3IE Vendor3IE; +} tDot11fTimingAdvertisementFrame; + +#define DOT11F_TIMINGADVERTISEMENTFRAME (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame * pFrm); +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fVHTGidManagementActionFrame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfVhtMembershipStatusArray VhtMembershipStatusArray; + tDot11fFfVhtUserPositionArray VhtUserPositionArray; +} tDot11fVHTGidManagementActionFrame; + +#define DOT11F_VHTGIDMANAGEMENTACTIONFRAME (42) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame * pFrm); +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fWMMAddTSRequest; + +#define DOT11F_WMMADDTSREQUEST (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest * pFrm); +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fWMMAddTSResponse; + +#define DOT11F_WMMADDTSRESPONSE (44) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse * pFrm); +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; +} tDot11fWMMDelTS; + +#define DOT11F_WMMDELTS (45) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS * pFrm); +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fht2040_bss_coexistence_mgmt_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIEht2040_bss_intolerant_report ht2040_bss_intolerant_report; +} tDot11fht2040_bss_coexistence_mgmt_action_frame; + +#define DOT11F_HT2040_BSS_COEXISTENCE_MGMT_ACTION_FRAME (46) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame * pFrm); +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +#endif /* DOT11F_H */ diff --git a/core/mac/src/include/dph_global.h b/core/mac/src/include/dph_global.h new file mode 100644 index 0000000000..ae590db666 --- /dev/null +++ b/core/mac/src/include/dph_global.h @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + + * + + * Author: Sandesh Goel + + * Date: 02/25/02 + + * History:- + + * Date Modified by Modification Information + + * -------------------------------------------------------------------- + + * + + */ + +#ifndef __DPH_GLOBAL_H__ +#define __DPH_GLOBAL_H__ + +#include "lim_global.h" +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_api.h" + +/* Following determines whether statistics are maintained or not */ +#define DPH_STATS + +/* STAID for Management frames */ +#define DPH_USE_MGMT_STAID -1 + +/* Keep Alive frames */ +#define DPH_NON_KEEPALIVE_FRAME 0 +#define DPH_KEEPALIVE_FRAME 1 + +/* DPH Hash Index for BSS(STA's Peer) on station. */ +#define DPH_STA_HASH_INDEX_PEER 1 + +#ifdef WLAN_FEATURE_11W +/* DPH PMF SA Query state for station */ +#define DPH_SA_QUERY_NOT_IN_PROGRESS 1 +#define DPH_SA_QUERY_IN_PROGRESS 2 +#define DPH_SA_QUERY_TIMED_OUT 3 +#endif + +typedef struct sDphRateBasedCtr { + uint32_t hi; + uint32_t lo; +} tDphRateBasedCtr; + +typedef struct sDphPhyRates { + uint8_t dataRateX2; + uint8_t ackRateX2; + uint8_t rtsRateX2; +} tDphPhyRates; + +typedef struct sDphIFSValues { + uint8_t sifs; + uint8_t pifs; + uint8_t difs; + uint8_t preamble; +} tDphIFSValues; + +typedef struct sDphQosParams { + uint8_t addtsPresent; + tSirAddtsReqInfo addts; + tSirMacQosCapabilityStaIE capability; +} tDphQosParams; + +/* Queue attribute structure */ +typedef struct sDphQueueAttr { + uint16_t valid:1; + uint16_t seqNum:12; + uint16_t ackPolicy:2; + uint16_t rsvd:1; +} tDphQueueAttr, *tpDphQueueAttr; + +/* STA state node */ +typedef struct sDphHashNode { + /* + * BYTE 0 + * HASH ENTRY FIELDS NOT NEEDED IN HAL. + * This STA valid or not + */ + uint8_t valid:1; + uint8_t encPolicy:3; + uint8_t defaultKey:1; + uint8_t defaultKeyId:2; + uint8_t qosMode:1; + /* BYTE 1 */ + uint8_t erpEnabled:1; + /* This has been added to the dph hash table */ + uint8_t added:1; + uint8_t linkTestOn:1; + uint8_t shortPreambleEnabled:1; + uint8_t shortSlotTimeEnabled:1; + uint8_t stopTx:1; + /* set if both ap and sta are wme capable */ + uint8_t wmeEnabled:1; + /* set if both ap and sta are 11e capable */ + uint8_t lleEnabled:1; + /* BYTE 2 */ + /* set if both ap and sta are wsm capable */ + uint8_t wsmEnabled:1; + /* station gave version info */ + uint8_t versionPresent:1; + /* allow bursting regardless of qosMode */ + uint8_t burstEnableForce:1; + uint8_t staAuthenticated:1; + uint8_t fAniCount:1; + uint8_t rmfEnabled:1; + /* Fragmentation size */ + uint16_t fragSize; + /* LIM state */ + tLimMlmStaContext mlmStaContext; + /* Number of Tim to wait if the STA doesn't respond / fetch data */ + uint8_t timWaitCount; + /* Number of Successful MPDU's being sent */ + uint32_t curTxMpduCnt; + /* number of consecutive TIMs sent without response */ + uint8_t numTimSent; + /* qos parameter info */ + tDphQosParams qos; + /* station version info - valid only if versionPresent is set */ + tSirMacPropVersion version; +#ifdef PLM_WDS + uint8_t wdsIndex; + uint8_t wdsPeerBeaconSeen; +#endif + /* Taurus capabilities */ + uint16_t baPolicyFlag; /* BA Policy for each TID. */ + /* + * All the legacy and airgo supported rates. + */ + tSirSupportedRates supportedRates; + uint8_t htGreenfield:1; + uint8_t htShortGI40Mhz:1; + uint8_t htShortGI20Mhz:1; + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport:1; + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t htLsigTXOPProtection:1; + /* + * A-MPDU Density + * 000 - No restriction + * 001 - 1/8 usec + * 010 - 1/4 usec + * 011 - 1/2 usec + * 100 - 1 usec + * 101 - 2 usec + * 110 - 4 usec + * 111 - 8 usec + */ + uint8_t htAMpduDensity:3; + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + /* */ + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor:3; + /* + * Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use 40 Mhz channel + */ + uint8_t htSupportedChannelWidthSet:1; + uint8_t htSecondaryChannelOffset:2; + uint8_t rsvd1:2; + /* DPH HASH ENTRY FIELDS NEEDED IN HAL ONLY */ + uint8_t dpuSig:4; /* DPU signiture */ + uint8_t staSig:4; /* STA signature */ + uint8_t staType; + uint16_t bssId; /* BSSID */ + uint16_t assocId; /* Association ID */ + /* This is the real sta index generated by HAL */ + uint16_t staIndex; + uint8_t staAddr[6]; + /* + * The DPU signatures will be sent eventually to TL to help + * it determine the association to which a packet belongs to + */ + /*Unicast DPU signature */ + uint8_t ucUcastSig; + /*Broadcast DPU signature */ + uint8_t ucBcastSig; + + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtSupportedRxNss; + uint8_t vhtBeamFormerCapable; + uint8_t vht_su_bfee_capable; +#ifdef WLAN_FEATURE_11W + uint8_t pmfSaQueryState; + uint8_t pmfSaQueryRetryCount; + uint16_t pmfSaQueryCurrentTransId; + uint16_t pmfSaQueryStartTransId; + TX_TIMER pmfSaQueryTimer; + v_TIME_t last_unprot_deauth_disassoc; + uint8_t proct_deauh_disassoc_cnt; + v_TIME_t last_assoc_received_time; +#endif + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; +#ifdef FEATURE_WLAN_TDLS + uint16_t ht_caps; + uint32_t vht_caps; +#endif + uint8_t timingMeasCap; + /* key installed for this STA or not in the firmware */ + uint8_t is_key_installed; + uint8_t is_disassoc_deauth_in_progress; + /* + * When a station with already an existing dph entry tries to + * associate again, the old dph entry will be zeroed out except + * for the next pointer. The next pointer must be defined at the + * end of the structure. + */ + struct sDphHashNode *next; +} tDphHashNode, *tpDphHashNode; + +#include "dph_hash_table.h" + +/* ------------------------------------------------------------------- */ +typedef struct sAniSirDph { + /* The hash table object */ + dphHashTableClass dphHashTable; +} tAniSirDph, *tpAniSirDph; + +#endif diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h new file mode 100644 index 0000000000..afbfd5e339 --- /dev/null +++ b/core/mac/src/include/parser_api.h @@ -0,0 +1,965 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file parser_api.h contains the definitions used + * for parsing received 802.11 frames + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __PARSE_H__ +#define __PARSE_H__ + +#include +#include "sir_mac_prop_exts.h" +#include "dot11f.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" + +#define COUNTRY_STRING_LENGTH (3) +#define COUNTRY_INFO_MAX_CHANNEL (84) +#define MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE (COUNTRY_STRING_LENGTH * \ + COUNTRY_INFO_MAX_CHANNEL) +#define HIGHEST_24GHZ_CHANNEL_NUM (14) + +#define IS_24G_CH(__chNum) ((__chNum > 0) && (__chNum < 15)) +#define IS_5G_CH(__chNum) ((__chNum >= 36) && (__chNum <= 165)) +#define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3) +#define DISABLE_NSS2_MCS 0xC + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define QCOM_VENDOR_IE_MCC_AVOID_CH 0x01 + +struct sAvoidChannelIE { + /* following must be 0xDD (221) */ + uint8_t tag_number; + uint8_t length; + /* following must be 00-A0-C6 */ + uint8_t oui[3]; + /* following must be 0x01 */ + uint8_t type; + uint8_t channel; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +typedef struct sSirCountryInformation { + uint8_t countryString[COUNTRY_STRING_LENGTH]; + uint8_t numIntervals; /* number of channel intervals */ + struct channelPowerLim { + uint8_t channelNumber; + uint8_t numChannel; + uint8_t maxTransmitPower; + } channelTransmitPower[COUNTRY_INFO_MAX_CHANNEL]; +} tSirCountryInformation, *tpSirCountryInformation; + +/* Structure common to Beacons & Probe Responses */ +typedef struct sSirProbeRespBeacon { + tSirMacTimeStamp timeStamp; + uint16_t beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacChanNum channelNumber; + tSirMacCfParamSet cfParamSet; + tSirMacTim tim; + tSirMacEdcaParamSetIE edcaParams; + tSirMacQosCapabilityIE qosCapability; + + tSirCountryInformation countryInfoParam; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + + tSirMacErpInfo erpIEInfo; + + tSirPropIEStruct propIEinfo; + tDot11fIEPowerConstraints localPowerConstraint; + tDot11fIETPCReport tpcReport; + tDot11fIEChanSwitchAnn channelSwitchIE; + tDot11fIEsec_chan_offset_ele sec_chan_offset; + tDot11fIEext_chan_switch_ann ext_chan_switch; + tSirMacAddr bssid; + tDot11fIEQuiet quietIE; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEP2PProbeRes P2PProbeRes; +#ifdef WLAN_FEATURE_VOWIFI_11R + uint8_t mdie[SIR_MDIE_SIZE]; +#endif +#ifdef FEATURE_WLAN_ESE + tDot11fIEESETxmitPower eseTxPwr; + tDot11fIEQBSSLoad QBSSLoad; +#endif + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t cfPresent; + uint8_t dsParamsPresent; + uint8_t timPresent; + + uint8_t edcaPresent; + uint8_t qosCapabilityPresent; + uint8_t wmeEdcaPresent; + uint8_t wmeInfoPresent; + uint8_t wsmCapablePresent; + + uint8_t countryInfoPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t erpPresent; + uint8_t channelSwitchPresent; + uint8_t sec_chan_offset_present; + uint8_t ext_chan_switch_present; + uint8_t quietIEPresent; + uint8_t tpcReportPresent; + uint8_t powerConstraintPresent; + +#ifdef WLAN_FEATURE_VOWIFI_11R + uint8_t mdiePresent; +#endif + +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEOperatingMode OperatingMode; + uint8_t WiderBWChanSwitchAnnPresent; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +#endif + uint8_t Vendor1IEPresent; + tDot11fIEvendor2_ie vendor2_ie; + uint8_t Vendor3IEPresent; + tDot11fIEIBSSParams IBSSParams; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tDot11fIEQComVendorIE AvoidChannelIE; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_ver_ie_present; +#endif +} tSirProbeRespBeacon, *tpSirProbeRespBeacon; + +/* probe Request structure */ +typedef struct sSirProbeReq { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tDot11fIEWscProbeReq probeReqWscIeInfo; + tDot11fIEHTCaps HTCaps; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t wscIePresent; + uint8_t p2pIePresent; +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps VHTCaps; +#endif + +} tSirProbeReq, *tpSirProbeReq; + +/* / Association Request structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocReq { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacAddr currentApAddr; /* only in reassoc frames */ + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + + tSirAddtsReqInfo addtsReq; + tSirMacQosCapabilityStaIE qosCapability; + + tSirMacWapiInfo wapi; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + tSirAddie addIE; + + tSirPropIEStruct propIEinfo; + tSirMacPowerCapabilityIE powerCapability; + tSirMacSupportedChannelIE supportedChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + /* / This is set if the frame is a reassoc request: */ + uint8_t reassocRequest; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t wmeInfoPresent; + uint8_t qosCapabilityPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; + + uint8_t wapiPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t addIEPresent; + + uint8_t powerCapabilityPresent; + uint8_t supportedChannelsPresent; + /* keeping copy of association request received, this is + required for indicating the frame to upper layers */ + uint32_t assocReqFrameLength; + uint8_t *assocReqFrame; +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode operMode; +#endif + tDot11fIEExtCap ExtCap; +} tSirAssocReq, *tpSirAssocReq; + +/* / Association Response structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocRsp { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t aid; + uint16_t statusCode; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirPropIEStruct propIEinfo; + tSirMacEdcaParamSetIE edca; + tSirAddtsRspInfo addtsRsp; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; +#if defined WLAN_FEATURE_VOWIFI_11R + tDot11fIEFTInfo FTInfo; + uint8_t mdie[SIR_MDIE_SIZE]; + uint8_t num_RICData; + tDot11fIERICDataDesc RICData[2]; +#endif + +#ifdef FEATURE_WLAN_ESE + uint8_t num_tspecs; + tDot11fIEWMMTSPEC TSPECInfo[SIR_ESE_MAX_TSPEC_IES]; + tSirMacESETSMIE tsmIE; +#endif + + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t edcaPresent; + uint8_t wmeEdcaPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; +#if defined WLAN_FEATURE_VOWIFI_11R + uint8_t ftinfoPresent; + uint8_t mdiePresent; + uint8_t ricPresent; +#endif +#ifdef FEATURE_WLAN_ESE + uint8_t tspecPresent; + uint8_t tsmPresent; +#endif +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; +#endif + tDot11fIEExtCap ExtCap; + tSirQosMapSet QosMapSet; +#ifdef WLAN_FEATURE_11W + tDot11fIETimeoutInterval TimeoutInterval; +#endif + tDot11fIEvendor2_ie vendor2_ie; +} tSirAssocRsp, *tpSirAssocRsp; + +#if defined(FEATURE_WLAN_ESE_UPLOAD) +/* Structure to hold ESE Beacon report mandatory IEs */ +typedef struct sSirEseBcnReportMandatoryIe { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacFHParamSet fhParamSet; + tSirMacDsParamSetIE dsParamSet; + tSirMacCfParamSet cfParamSet; + tSirMacIBSSParams ibssParamSet; + tSirMacTim tim; + tSirMacRRMEnabledCap rmEnabledCapabilities; + + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t fhParamPresent; + uint8_t dsParamsPresent; + uint8_t cfPresent; + uint8_t ibssParamPresent; + uint8_t timPresent; + uint8_t rrmPresent; +} tSirEseBcnReportMandatoryIe, *tpSirEseBcnReportMandatoryIe; +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + +/** + * struct s_ext_cap - holds bitfields of extended capability IE + * + * s_ext_cap holds bitfields of extended capability IE. In dot11f files + * extended capability IE information is stored as an array of bytes. + * This structure is used to encode/decode the byte array present in + * dot11f IE structure. + */ + +struct s_ext_cap { + uint8_t bss_coexist_mgmt_support:1; + uint8_t reserved1:1; + uint8_t ext_chan_switch:1; + uint8_t reserved2:1; + uint8_t psmp_cap:1; + uint8_t reserved3:1; + uint8_t spsmp_cap:1; + uint8_t event:1; + uint8_t diagnostics:1; + uint8_t multi_diagnostics:1; + uint8_t loc_tracking:1; + uint8_t fms:1; + uint8_t proxy_arp_service:1; + uint8_t co_loc_intf_reporting:1; + uint8_t civic_loc:1; + uint8_t geospatial_loc:1; + uint8_t tfs:1; + uint8_t wnm_sleep_mode:1; + uint8_t tim_broadcast:1; + uint8_t bss_transition:1; + uint8_t qos_traffic_cap:1; + uint8_t ac_sta_cnt:1; + uint8_t multi_bssid:1; + uint8_t timing_meas:1; + uint8_t chan_usage:1; + uint8_t ssid_list:1; + uint8_t dms:1; + uint8_t utctsf_offset:1; + uint8_t tdls_peer_uapsd_buffer_sta:1; + uint8_t tdls_peer_psm_supp:1; + uint8_t tdls_channel_switching:1; + uint8_t interworking_service:1; + uint8_t qos_map:1; + uint8_t ebr:1; + uint8_t sspn_interface:1; + uint8_t reserved4:1; + uint8_t msg_cf_cap:1; + uint8_t tdls_support:1; + uint8_t tdls_prohibited:1; + uint8_t tdls_chan_swit_prohibited:1; + uint8_t reject_unadmitted_traffic:1; + uint8_t service_interval_granularity:3; + uint8_t identifier_loc:1; + uint8_t uapsd_coexistence:1; + uint8_t wnm_notification:1; + uint8_t qa_bcapbility:1; + uint8_t utf8_ssid:1; + uint8_t qmf_activated:1; + uint8_t qm_frecon_act:1; + uint8_t robust_av_streaming:1; + uint8_t advanced_gcr:1; + uint8_t mesh_gcr:1; + uint8_t scs:1; + uint8_t q_load_report:1; + uint8_t alternate_edca:1; + uint8_t unprot_txo_pneg:1; + uint8_t prot_txo_pneg:1; + uint8_t reserved6:1; + uint8_t prot_q_load_report:1; + uint8_t tdls_wider_bw:1; + uint8_t oper_mode_notification:1; + uint8_t max_num_of_msdu_bit1:1; + uint8_t max_num_of_msdu_bit2:1; + uint8_t chan_sch_mgmt:1; + uint8_t geo_db_inband_en_signal:1; + uint8_t nw_chan_control:1; + uint8_t white_space_map:1; + uint8_t chan_avail_query:1; + uint8_t fine_time_meas_responder:1; + uint8_t fine_time_meas_initiator:1; +}; + +uint8_t sirIsPropCapabilityEnabled(struct sAniSirGlobal *pMac, uint32_t bitnum); + +void dot11f_log(tpAniSirGlobal pMac, int nSev, const char *lpszFormat, ...); + +#define CFG_GET_INT(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_INT_NO_STATUS(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return; \ + } \ +} while (0) + +#define CFG_GET_STR(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_STR_NO_STATUS(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return; \ + } \ +} while (0) + +void swap_bit_field16(uint16_t in, uint16_t *out); + +/* Currently implemented as "shims" between callers & the new framesc- */ +/* generated code: */ + +tSirRetStatus +sir_convert_probe_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirProbeReq probe); + +tSirRetStatus +sir_convert_probe_frame2_struct(struct sAniSirGlobal *pMac, uint8_t *frame, + uint32_t len, tpSirProbeRespBeacon probe); + +tSirRetStatus +sir_convert_assoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +tSirRetStatus +sir_convert_assoc_resp_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocRsp assoc); + +tSirRetStatus +sir_convert_reassoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +tSirRetStatus +sir_parse_beacon_ie(struct sAniSirGlobal *pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t payloadLength); + +#if defined(FEATURE_WLAN_ESE_UPLOAD) +tSirRetStatus +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + uint8_t *pPayload, const uint32_t payloadLength, + uint8_t **outIeBuf, uint32_t *pOutIeLen); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + +tSirRetStatus +sir_convert_beacon_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *pBeaconFrame, + tpSirProbeRespBeacon pBeaconStruct); + +tSirRetStatus +sir_convert_auth_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirMacAuthFrameBody auth); + +tSirRetStatus +sir_convert_addts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsReqInfo *addTs); + +tSirRetStatus +sir_convert_addts_rsp2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsRspInfo *addts); + +tSirRetStatus +sir_convert_delts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirDeltsReqInfo *delTs); +tSirRetStatus +sir_convert_qos_map_configure_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, uint32_t nFrame, + tSirQosMapSet *pQosMapSet); + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +sir_convert_tpc_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacTpcReqActionFrame, uint32_t); + +tSirRetStatus +sir_convert_meas_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacMeasReqActionFrame, uint32_t); +#endif + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled, we'll clear the QOS + * bit in pDot11f + * + * + */ + +tSirRetStatus +populate_dot11f_capabilities(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * \param pSta Pointer to a tDphHashNode representing a peer + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled on our peer, we'll + * clear the QOS bit in pDot11f + * + * + */ + +struct sDphHashNode; + +tSirRetStatus +populate_dot11f_capabilities2(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + struct sDphHashNode *pSta, + tpPESession psessionEntry); + +/* / Populate a tDot11fIEChanSwitchAnn */ +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry); + +void +populate_dot_11_f_ext_chann_switch_ann(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry); + +/* / Populate a tDot11fIEChannelSwitchWrapper */ +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11fIECountry */ +tSirRetStatus +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry); + +/* Populated a populate_dot11f_ds_params */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal pMac, + tDot11fIEDSParams *pDot11f, uint8_t channel); + +/* / Populated a tDot11fIEEDCAParamSet */ +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry); + +#if defined WLAN_FEATURE_VOWIFI +tSirRetStatus +populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport); +#endif + +/** + * \brief Populate a tDot11fIEExtSuppRates + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param nChannelNum Channel on which the enclosing frame will be going out + * + * \param pDot11f Address of a tDot11fIEExtSuppRates struct to be filled in. + * + * + * This method is a NOP if the channel is greater than 14. + * + * + */ + +tSirRetStatus +populate_dot11f_ext_supp_rates1(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f); + +tSirRetStatus +populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f); + +tSirRetStatus +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry); + +void populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry); + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is CCA */ +tSirRetStatus +populate_dot11f_measurement_report1(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is RPI Hist */ +tSirRetStatus +populate_dot11f_measurement_report2(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); +#endif /* ANI_SUPPORT_11H */ + +/* / Populate a tDot11fIEPowerCaps */ +void +populate_dot11f_power_caps(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry); + +/* / Populate a tDot11fIEPowerConstraints */ +tSirRetStatus +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f); + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, + tDot11fIEQOSCapsStation *pDot11f); + +tSirRetStatus +populate_dot11f_rsn(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f); + +tSirRetStatus +populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSNOpaque *pDot11f); + +#if defined(FEATURE_WLAN_WAPI) + +tSirRetStatus +populate_dot11f_wapi(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f); + +tSirRetStatus populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f); + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +/* / Populate a tDot11fIESSID given a tSirMacSSid */ +void +populate_dot11f_ssid(tpAniSirGlobal pMac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f); + +/* / Populate a tDot11fIESSID from CFG */ +tSirRetStatus populate_dot11f_ssid2(tpAniSirGlobal pMac, + tDot11fIESSID *pDot11f); + +/** + * \brief Populate a tDot11fIESchedule + * + * \sa populate_dot11f_wmm_schedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIESchedule to be filled in + * + * + */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f); + +void +populate_dot11f_supp_channels(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fIESuppRates + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param nChannelNum Channel the enclosing frame will be going out on; see + * below + * + * \param pDot11f Address of a tDot11fIESuppRates struct to be filled in. + * + * + * If nChannelNum is greater than 13, the supported rates will be + * WNI_CFG_SUPPORTED_RATES_11B. If it is less than or equal to 13, the + * supported rates will be WNI_CFG_SUPPORTED_RATES_11A. If nChannelNum is + * set to the sentinel value POPULATE_DOT11F_RATES_OPERATIONAL, the struct + * will be populated with WNI_CFG_OPERATIONAL_RATE_SET. + * + * + */ + +#define POPULATE_DOT11F_RATES_OPERATIONAL (0xff) + +tSirRetStatus +populate_dot11f_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession); + +tSirRetStatus +populate_dot11f_rates_tdls(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates); + +tSirRetStatus populate_dot11f_tpc_report(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11FfTSInfo */ +void populate_dot11f_ts_info(tSirMacTSInfo *pInfo, tDot11fFfTSInfo *pDot11f); + +void populate_dot11f_wmm(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry); + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps); + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version IE */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion); +/* Fill the Radio Management Capability */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap); +/* Fill the CCKM IE */ +tSirRetStatus populate_dot11f_ese_cckm_opaque(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f); + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length); +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry); +#endif + +void populate_dot11f_wmm_info_ap(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry); + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo); + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry); + +/** + * \brief Populate a tDot11fIEWMMSchedule + * + * \sa PopulatedDot11fSchedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIEWMMSchedule to be filled in + * + * + */ + +void +populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f); + +tSirRetStatus +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f); + +tSirRetStatus +populate_dot11f_wpa_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPAOpaque *pDot11f); + +void populate_dot11f_tspec(tSirMacTspecIE *pOld, tDot11fIETSPEC *pDot11f); + +void populate_dot11f_wmmtspec(tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pDot11f); + +tSirRetStatus +populate_dot11f_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f); + +tSirRetStatus +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f); + +tSirRetStatus populate_dot11f_wsc(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus de_populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus populate_dot11f_probe_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry); +tSirRetStatus populate_dot11f_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry); +tSirRetStatus populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry); + +tSirRetStatus populate_dot11f_wsc_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus +populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus +de_populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus populate_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +tSirRetStatus populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +tSirRetStatus populate_dot11f_wscInAssocRes(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f); + +#if defined WLAN_FEATURE_VOWIFI +tSirRetStatus populate_dot11f_wfatpc(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin); + +tSirRetStatus populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry); +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R +void populate_mdie(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain * pDot11f, uint8_t mdie[]); +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f); +#endif + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates); + +int find_ie_location(tpAniSirGlobal pMac, tpSirRSNie pRsnIe, uint8_t EID); + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +populate_dot11f_vht_caps(tpAniSirGlobal pMac, tpPESession psessionEntry, + tDot11fIEVHTCaps *pDot11f); + +tSirRetStatus +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f); + +tSirRetStatus +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f); + +tSirRetStatus +populate_dot11f_ext_cap(tpAniSirGlobal pMac, bool isVHTEnabled, + tDot11fIEExtCap *pDot11f, tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry); +#endif + +void populate_dot11f_timeout_interval(tpAniSirGlobal pMac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* Populate a tDot11fIEQComVendorIE */ +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession session_entry); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +tSirRetStatus populate_dot11f_timing_advert_frame(tpAniSirGlobal pMac, + tDot11fTimingAdvertisementFrame *frame); + +#endif /* __PARSE_H__ */ diff --git a/core/mac/src/include/sir_common.h b/core/mac/src/include/sir_common.h new file mode 100644 index 0000000000..f6997725d5 --- /dev/null +++ b/core/mac/src/include/sir_common.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_common.h contains the common definitions used by all + * Firmware modules. + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRCOMMON_H +#define __SIRCOMMON_H + +#include "sir_api.h" +#include "sir_params.h" +#include "sys_wrapper.h" + +/* ********************************************* * +* * +* SIRIUS SYSTEM EXTERNAL GLOBALS * +* * +* ********************************************* */ + +/* All the following are resource definitions */ + +#endif /* __SIRCOMMON_H */ diff --git a/core/mac/src/include/sir_debug.h b/core/mac/src/include/sir_debug.h new file mode 100644 index 0000000000..674855d056 --- /dev/null +++ b/core/mac/src/include/sir_debug.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Author: Sandesh Goel + * Date: 02/25/02 + */ + +#ifndef __POL_DEBUG_H__ +#define __POL_DEBUG_H__ + +#define LOGOFF 0 +#define LOGP 1 +#define LOGE 2 +#define LOGW 3 +#define LOG1 4 +#define LOG2 5 +#define LOG3 6 +#define LOG4 7 + +#ifdef WLAN_MDM_CODE_REDUCTION_OPT +#ifdef PE_DEBUG_LOGE +#define PELOGE(p) { p } +#else +#define PELOGE(p) { } +#endif + +#ifdef PE_DEBUG_LOGW +#define PELOGW(p) { p } +#else +#define PELOGW(p) { } +#endif + +#define PELOG1(p) { } +#define PELOG2(p) { } +#define PELOG3(p) { } +#define PELOG4(p) { } + +#else /* WLAN_MDM_CODE_REDUCTION_OPT */ + +#ifdef PE_DEBUG_LOGE +#define PELOGE(p) { p } +#else +#define PELOGE(p) { } +#endif + +#ifdef PE_DEBUG_LOGW +#define PELOGW(p) { p } +#else +#define PELOGW(p) { } +#endif + +#ifdef PE_DEBUG_LOG1 +#define PELOG1(p) { p } +#else +#define PELOG1(p) { } +#endif + +#ifdef PE_DEBUG_LOG2 +#define PELOG2(p) { p } +#else +#define PELOG2(p) { } +#endif + +#ifdef PE_DEBUG_LOG3 +#define PELOG3(p) { p } +#else +#define PELOG3(p) { } +#endif + +#ifdef PE_DEBUG_LOG4 +#define PELOG4(p) { p } +#else +#define PELOG4(p) { } +#endif + +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + +#define FL(x) "%s: %d: " \ + x, __func__, __LINE__ + +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" + +#endif diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h new file mode 100644 index 0000000000..78513a3ac8 --- /dev/null +++ b/core/mac/src/include/sir_params.h @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sir_params.h contains the common parameter definitions, which + * are not dependent on threadX API. These can be used by all Firmware + * modules. + * + * Author: Sandesh Goel + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRPARAMS_H +#define __SIRPARAMS_H + +#include "sir_types.h" + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 + + +/* Firmware wide constants */ + +#define SIR_MAX_PACKET_SIZE 512 +#define SIR_MAX_NUM_CHANNELS 64 +#define SIR_MAX_NUM_STA_IN_IBSS 16 +#define SIR_ESE_MAX_MEAS_IE_REQS 8 + +typedef enum { + PHY_SINGLE_CHANNEL_CENTERED = 0, /* 20MHz IF bandwidth centered on IF carrier */ + PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1, /* 40MHz IF bandwidth with lower 20MHz supporting the primary channel */ + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3, /* 40MHz IF bandwidth with higher 20MHz supporting the primary channel */ +#ifdef WLAN_FEATURE_11AC + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4, /* 20/40MHZ offset LOW 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5, /* 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6, /* 20/40MHZ offset HIGH 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7, /* 20/40MHZ offset LOW 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8, /* 20/40MHZ offset HIGH 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9, /* 20/40MHZ offset LOW 40/80MHZ offset HIGH */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10, /* 20/40MHZ offset-HIGH 40/80MHZ offset HIGH */ +#endif + PHY_CHANNEL_BONDING_STATE_MAX = 11 +} ePhyChanBondState; + +#define MAX_BONDED_CHANNELS 4 + +typedef enum { + MCC = 0, + P2P = 1, + DOT11AC = 2, + SLM_SESSIONIZATION = 3, + DOT11AC_OPMODE = 4, + SAP32STA = 5, + TDLS = 6, + P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7, + WLANACTIVE_OFFLOAD = 8, +#ifdef FEATURE_WLAN_EXTSCAN + EXTENDED_SCAN = 9, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + PNO = 10, +#endif +#ifdef WLAN_FEATURE_NAN + NAN = 11, +#endif + RTT = 12, + WOW = 22, + WLAN_ROAM_SCAN_OFFLOAD = 23, + IBSS_HEARTBEAT_OFFLOAD = 26, + WLAN_PERIODIC_TX_PTRN = 28, +#ifdef FEATURE_WLAN_TDLS + ADVANCE_TDLS = 29, + TDLS_OFF_CHANNEL = 30, +#endif + + /* MAX_FEATURE_SUPPORTED = 128 */ +} placeHolderInCapBitmap; + +typedef enum eSriLinkState { + eSIR_LINK_IDLE_STATE = 0, + eSIR_LINK_PREASSOC_STATE = 1, + eSIR_LINK_POSTASSOC_STATE = 2, + eSIR_LINK_AP_STATE = 3, + eSIR_LINK_IBSS_STATE = 4, + /* BT-AMP Case */ + eSIR_LINK_BTAMP_PREASSOC_STATE = 5, + eSIR_LINK_BTAMP_POSTASSOC_STATE = 6, + eSIR_LINK_BTAMP_AP_STATE = 7, + eSIR_LINK_BTAMP_STA_STATE = 8, + + /* Reserved for HAL internal use */ + eSIR_LINK_LEARN_STATE = 9, + eSIR_LINK_SCAN_STATE = 10, + eSIR_LINK_FINISH_SCAN_STATE = 11, + eSIR_LINK_INIT_CAL_STATE = 12, + eSIR_LINK_FINISH_CAL_STATE = 13, + eSIR_LINK_LISTEN_STATE = 14, + eSIR_LINK_SEND_ACTION_STATE = 15, + eSIR_LINK_DOWN_STATE = 16, +} tSirLinkState; + +/* / Message queue structure used across Sirius project. */ +/* / NOTE: this structure should be multiples of a word size (4bytes) */ +/* / as this is used in tx_queue where it expects to be multiples of 4 bytes. */ +typedef struct sSirMsgQ { + uint16_t type; + /* + * This field can be used as sequence number/dialog token for matching + * requests and responses. + */ + uint16_t reserved; + /** + * Based on the type either a bodyptr pointer into + * memory or bodyval as a 32 bit data is used. + * bodyptr: is always a freeable pointer, one should always + * make sure that bodyptr is always freeable. + * + * Messages should use either bodyptr or bodyval; not both !!!. + */ + void *bodyptr; + uint32_t bodyval; + + /* + * Some messages provide a callback function. The function signature + * must be agreed upon between the two entities exchanging the message + */ + void *callback; + +} tSirMsgQ, *tpSirMsgQ; + +/* / Mailbox Message Structure Define */ +typedef struct sSirMbMsg { + uint16_t type; + + /** + * This length includes 4 bytes of header, that is, + * 2 bytes type + 2 bytes msgLen + n*4 bytes of data. + * This field is byte length. + */ + uint16_t msgLen; + + /** + * This is the first data word in the mailbox message. + * It is followed by n words of data. + * NOTE: data[1] is not a place holder to store data + * instead to dereference the message body. + */ + uint32_t data[1]; +} tSirMbMsg, *tpSirMbMsg; + +/* / Mailbox Message Structure for P2P */ +typedef struct sSirMbMsgP2p { + uint16_t type; + + /** + * This length includes 4 bytes of header, that is, + * 2 bytes type + 2 bytes msgLen + n*4 bytes of data. + * This field is byte length. + */ + uint16_t msgLen; + + uint8_t sessionId; + uint8_t noack; + uint16_t wait; + uint16_t channel_freq; + uint32_t scan_id; + + /** + * This is the first data word in the mailbox message. + * It is followed by n words of data. + * NOTE: data[1] is not a place holder to store data + * instead to dereference the message body. + */ + uint32_t data[1]; +} tSirMbMsgP2p, *tpSirMbMsgP2p; + +/* ******************************************* * +* * +* SIRIUS MESSAGE TYPES * +* * +* ******************************************* */ + +/* + * The following message types have bounds defined for each module for + * inter thread/module communications. + * Each module will get 256 message types in total. + * Note that message type definitions for mailbox messages for + * communication with Host are in wni_api.h file. + * + * Any addition/deletion to this message list should also be + * reflected in the halUtil_getMsgString() routine. + */ + +/* HAL message types */ +#define SIR_HAL_MSG_TYPES_BEGIN (SIR_HAL_MODULE_ID << 8) +#define SIR_HAL_ITC_MSG_TYPES_BEGIN (SIR_HAL_MSG_TYPES_BEGIN+0x20) +#define SIR_HAL_RADAR_DETECTED_IND SIR_HAL_ITC_MSG_TYPES_BEGIN + +/* + * New Taurus related messages + */ +#define SIR_HAL_ADD_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_HAL_ADD_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 2) +#define SIR_HAL_DELETE_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 3) +#define SIR_HAL_DELETE_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 4) +#define SIR_HAL_ADD_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 5) +#define SIR_HAL_ADD_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 6) +#define SIR_HAL_DELETE_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 7) +#define SIR_HAL_DELETE_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 8) +#define SIR_HAL_INIT_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 9) +#define SIR_HAL_INIT_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 10) +#define SIR_HAL_START_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 11) +#define SIR_HAL_START_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 12) +#define SIR_HAL_END_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 13) +#define SIR_HAL_END_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 14) +#define SIR_HAL_FINISH_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 15) +#define SIR_HAL_FINISH_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 16) +#define SIR_HAL_SEND_BEACON_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 17) + +#define SIR_HAL_SET_BSSKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 18) +#define SIR_HAL_SET_BSSKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 19) +#define SIR_HAL_SET_STAKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 20) +#define SIR_HAL_SET_STAKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 21) +#define SIR_HAL_UPDATE_EDCA_PROFILE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 22) + +#define SIR_HAL_UPDATE_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 23) +#define SIR_HAL_UPDATE_CF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 24) +#define SIR_HAL_CHNL_SWITCH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 25) +#define SIR_HAL_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 26) +#define SIR_HAL_DEL_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 27) + +#define SIR_HAL_MISSED_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 34) + +#define SIR_HAL_SWITCH_CHANNEL_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 35) +#define SIR_HAL_PWR_SAVE_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 36) + +#define SIR_HAL_REGISTER_PE_CALLBACK (SIR_HAL_ITC_MSG_TYPES_BEGIN + 37) + +#define SIR_HAL_IBSS_STA_ADD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 43) +#define SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 44) +#define SIR_HAL_SET_LINK_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 45) + +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 46) to + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 57) are unused + */ + +#define SIR_HAL_SET_STA_BCASTKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 58) +#define SIR_HAL_SET_STA_BCASTKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 59) +#define SIR_HAL_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 60) +#define SIR_HAL_DPU_MIC_ERROR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 61) +#define SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 63) +#define SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 64) +#define SIR_HAL_TIMER_ADC_RSSI_STATS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 65) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 66) is unused */ +#define SIR_HAL_SET_MIMOPS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 67) +#define SIR_HAL_SET_MIMOPS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 68) +#define SIR_HAL_SYS_READY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 69) +#define SIR_HAL_SET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 70) +#define SIR_HAL_SET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 71) +#define SIR_HAL_GET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 72) +#define SIR_HAL_GET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 73) +#define SIR_HAL_GET_NOISE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 74) + +/* Messages to support transmit_halt and transmit_resume */ +#define SIR_HAL_TRANSMISSION_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 75) + +#define SIR_HAL_LOW_RSSI_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 80) +#define SIR_HAL_BEACON_FILTER_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 81) +/* / PE <-> HAL WOWL messages */ +#define SIR_HAL_WOW_ADD_PTRN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 82) +#define SIR_HAL_WOW_DEL_PTRN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 83) +#define SIR_HAL_WOWL_ENTER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 84) +#define SIR_HAL_WOWL_ENTER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 85) +#define SIR_HAL_WOWL_EXIT_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 86) +#define SIR_HAL_WOWL_EXIT_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 87) +/* / PE <-> HAL statistics messages */ +#define SIR_HAL_GET_STATISTICS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 88) +#define SIR_HAL_GET_STATISTICS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 89) +#define SIR_HAL_SET_KEY_DONE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 90) + +/* / PE <-> HAL BTC messages */ +#define SIR_HAL_BTC_SET_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 91) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 92) is unused */ +#define SIR_HAL_HANDLE_FW_MBOX_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 93) +#define SIR_HAL_SEND_PROBE_RSP_TMPL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 94) + +/* PE <-> HAL addr2 mismatch message */ +#define SIR_LIM_ADDR2_MISS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 95) +#ifdef FEATURE_OEM_DATA_SUPPORT +/* PE <-> HAL OEM_DATA RELATED MESSAGES */ +#define SIR_HAL_START_OEM_DATA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 96) +#define SIR_HAL_START_OEM_DATA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 97) +#endif + +#define SIR_HAL_SET_MAX_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 98) +#define SIR_HAL_SET_MAX_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 99) + +/* / PE <-> HAL Host Offload message */ +#define SIR_HAL_SET_HOST_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 100) + +#define SIR_HAL_ADD_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 101) +#define SIR_HAL_ADD_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 102) +#define SIR_HAL_DEL_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 103) +#define SIR_HAL_DEL_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 104) + +#define SIR_HAL_CFG_RXP_FILTER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 106) + +#ifdef WLAN_FEATURE_VOWIFI_11R +#define SIR_HAL_AGGR_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 107) +#define SIR_HAL_AGGR_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 108) +#define SIR_HAL_AGGR_QOS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 109) +#define SIR_HAL_AGGR_QOS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 110) +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/* P2P <-> HAL P2P msg */ +#define SIR_HAL_SET_P2P_GO_NOA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 111) +#define SIR_HAL_P2P_NOA_ATTR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 112) +#define SIR_HAL_P2P_NOA_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 113) + +#define SIR_HAL_SET_LINK_STATE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 114) + +#define SIR_HAL_WLAN_SUSPEND_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 115) +#define SIR_HAL_WLAN_RESUME_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 116) + +/* / PE <-> HAL Keep Alive message */ +#define SIR_HAL_SET_KEEP_ALIVE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 117) + +#ifdef WLAN_NS_OFFLOAD +#define SIR_HAL_SET_NS_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 118) +#endif /* WLAN_NS_OFFLOAD */ + +#ifdef FEATURE_WLAN_SCAN_PNO +#define SIR_HAL_SET_PNO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 119) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 120) is unused */ +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 122) is unused */ + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define SIR_HAL_8023_MULTICAST_LIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 123) +#define SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 124) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 125) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 126) +#define SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 127) +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 128) is unused */ + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define SIR_HAL_GTK_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 129) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 130) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 131) +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef FEATURE_WLAN_ESE +#define SIR_HAL_TSM_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 132) +#define SIR_HAL_TSM_STATS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 133) +#endif + +#define SIR_HAL_SET_TM_LEVEL_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 134) + +#ifdef WLAN_FEATURE_11AC +#define SIR_HAL_UPDATE_OP_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 135) +#endif + +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH (SIR_HAL_ITC_MSG_TYPES_BEGIN + 136) +#define SIR_HAL_TDLS_LINK_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 137) +#endif +#define SIR_HAL_ROAM_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 138) + +#define SIR_HAL_TRAFFIC_STATS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 141) + +#ifdef WLAN_FEATURE_11W +#define SIR_HAL_EXCLUDE_UNENCRYPTED_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 142) +#endif +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 143) +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 144) +#define SIR_HAL_TDLS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 145) +#endif + +#define SIR_HAL_STOP_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 146) +#define SIR_HAL_RX_SCAN_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 147) +#define SIR_HAL_DHCP_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 148) +#define SIR_HAL_DHCP_STOP_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 149) +#define SIR_HAL_IBSS_PEER_INACTIVITY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 150) + +#define SIR_HAL_LPHB_CONF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 151) + +#define SIR_HAL_ADD_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 152) +#define SIR_HAL_DEL_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 153) + +/* Messages between 156 to 157 are not used */ +#define SIR_HAL_SOC_DUAL_MAC_CFG_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 154) +#define SIR_HAL_SOC_DUAL_MAC_CFG_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 155) + +#define SIR_HAL_RATE_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 159) + +#define SIR_HAL_FLUSH_LOG_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 160) + +#define SIR_HAL_SOC_SET_PCL_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 161) + +/* 162 unused */ + +#define SIR_HAL_CLI_SET_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 163) +#ifndef REMOVE_PKT_LOG +#define SIR_HAL_PKTLOG_ENABLE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 164) +#endif +#ifdef FEATURE_WLAN_SCAN_PNO +#define SIR_HAL_SME_SCAN_CACHE_UPDATED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 165) +#endif +#define SIR_HAL_START_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 166) +#define SIR_HAL_UPDATE_CHAN_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 167) +#define SIR_CSA_OFFLOAD_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 169) + +#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 170) + +#ifdef WLAN_FEATURE_11AC +#define SIR_HAL_UPDATE_MEMBERSHIP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 172) +#define SIR_HAL_UPDATE_USERPOS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 173) +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_UPDATE_FW_TDLS_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 174) +#define SIR_HAL_UPDATE_TDLS_PEER_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 175) +#define SIR_HAL_TDLS_SHOULD_DISCOVER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 176) +#define SIR_HAL_TDLS_SHOULD_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 177) +#define SIR_HAL_TDLS_PEER_DISCONNECTED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 178) +#endif + +/* Handling of beacon tx indication from FW */ +#define SIR_HAL_BEACON_TX_SUCCESS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 179) +#define SIR_HAL_DFS_RADAR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 180) + +#define SIR_HAL_INIT_THERMAL_INFO_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 185) +#define SIR_HAL_SET_THERMAL_LEVEL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 186) + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +#define SIR_HAL_SET_PLM_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 187) +#endif + +#define SIR_HAL_SET_TX_POWER_LIMIT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 188) +#define SIR_HAL_SET_SAP_INTRABSS_DIS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 189) + +#define SIR_HAL_MODEM_POWER_STATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 190) + +#define SIR_HAL_DISASSOC_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 191) +#define SIR_HAL_DEAUTH_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 192) + +#ifdef WLAN_FEATURE_11AC +#define SIR_HAL_UPDATE_RX_NSS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 193) +#endif + +#ifdef WLAN_FEATURE_STATS_EXT +#define SIR_HAL_STATS_EXT_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 194) +#define SIR_HAL_STATS_EXT_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 195) +#endif /* WLAN_FEATURE_STATS_EXT */ + +#define SIR_HAL_HIDE_SSID_VDEV_RESTART (SIR_HAL_ITC_MSG_TYPES_BEGIN + 196) + +#define SIR_HAL_GET_LINK_SPEED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 197) + +#ifdef FEATURE_WLAN_EXTSCAN +#define SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 198) +#define SIR_HAL_EXTSCAN_START_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 199) +#define SIR_HAL_EXTSCAN_STOP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 200) +#define SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 201) +#define SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 202) +#define SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 203) +#define SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 204) +#define SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 205) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define SIR_HAL_CH_AVOID_UPDATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 206) +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define SIR_HAL_LL_STATS_CLEAR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207) +#define SIR_HAL_LL_STATS_SET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208) +#define SIR_HAL_LL_STATS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209) +#define SIR_HAL_LL_STATS_RESULTS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210) +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) +#endif +#ifdef WLAN_FEATURE_NAN +#define SIR_HAL_NAN_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212) +#endif /* WLAN_FEATURE_NAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213) +#endif + +#define SIR_HAL_SET_BASE_MACADDR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 214) + +#define SIR_HAL_UNIT_TEST_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 215) + +#define SIR_HAL_LINK_STATUS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 216) + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define SIR_HAL_CONFIG_EXT_WOW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 217) +#define SIR_HAL_CONFIG_APP_TYPE1_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218) +#define SIR_HAL_CONFIG_APP_TYPE2_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219) +#endif + +#define SIR_HAL_GET_TEMPERATURE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220) +#define SIR_HAL_SET_SCAN_MAC_OUI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221) +#ifdef DHCP_SERVER_OFFLOAD +#define SIR_HAL_SET_DHCP_SERVER_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 222) +#endif /* DHCP_SERVER_OFFLOAD */ +#define SIR_HAL_LED_FLASHING_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 223) +#define SIR_HAL_PROCESS_FW_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 224) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 225) +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 226) +#define SIR_HAL_ROAM_INVOKE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 227) +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_TDLS_SET_OFFCHAN_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 228) +#endif + +#define SIR_HAL_SET_MAS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229) +#define SIR_HAL_SET_MIRACAST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 230) +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_HAL_UPDATE_Q2Q_IE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 231) +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define SIR_HAL_CONFIG_STATS_FACTOR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 232) +#define SIR_HAL_CONFIG_GUARD_TIME (SIR_HAL_ITC_MSG_TYPES_BEGIN + 233) +#define SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 234) + +#define SIR_HAL_ENTER_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 235) +#define SIR_HAL_EXIT_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 236) +#define SIR_HAL_ENABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 237) +#define SIR_HAL_DISABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 238) + +#define SIR_HAL_SET_EPNO_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 313) +#define SIR_HAL_SET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 316) +#define SIR_HAL_RESET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 317) +#define SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 318) + +#define SIR_HAL_OCB_SET_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 319) +#define SIR_HAL_OCB_SET_UTC_TIME_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 320) +#define SIR_HAL_OCB_START_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 321) +#define SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 322) +#define SIR_HAL_OCB_GET_TSF_TIMER_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 323) +#define SIR_HAL_DCC_GET_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 324) +#define SIR_HAL_DCC_CLEAR_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 325) +#define SIR_HAL_DCC_UPDATE_NDL_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 326) + +#define SIR_HAL_FW_MEM_DUMP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 327) +#define SIR_HAL_START_STOP_LOGGING (SIR_HAL_ITC_MSG_TYPES_BEGIN + 328) +#define SIR_HAL_SOC_SET_HW_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 329) +#define SIR_HAL_SOC_SET_HW_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 330) +#define SIR_HAL_SOC_HW_MODE_TRANS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 331) + +#define SIR_HAL_SET_RSSI_MONITOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 333) +#define SIR_HAL_SET_IE_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 334) + +#define SIR_HAL_LRO_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 335) + +#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) + +/* CFG message types */ +#define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) +#define SIR_CFG_ITC_MSG_TYPES_BEGIN (SIR_CFG_MSG_TYPES_BEGIN+0xB0) +#define SIR_CFG_PARAM_UPDATE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN) +#define SIR_CFG_DOWNLOAD_COMPLETE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_CFG_MSG_TYPES_END (SIR_CFG_MSG_TYPES_BEGIN+0xFF) + +/* LIM message types */ +#define SIR_LIM_MSG_TYPES_BEGIN (SIR_LIM_MODULE_ID << 8) +#define SIR_LIM_ITC_MSG_TYPES_BEGIN (SIR_LIM_MSG_TYPES_BEGIN+0xB0) + +/* Messages to/from HAL */ +/* Removed as part of moving HAL down to FW */ + +/* Message from ISR upon TFP retry interrupt */ +#define SIR_LIM_RETRY_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 3) +/* Message from BB Transport */ +#define SIR_BB_XPORT_MGMT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 4) +/* UNUSED SIR_LIM_ITC_MSG_TYPES_BEGIN + 6 */ +/* Message from ISR upon SP's Invalid session key interrupt */ +#define SIR_LIM_INV_KEY_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 7) +/* Message from ISR upon SP's Invalid key ID interrupt */ +#define SIR_LIM_KEY_ID_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 8) +/* Message from ISR upon SP's Replay threshold reached interrupt */ +#define SIR_LIM_REPLAY_THRES_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 9) +/* Message from HDD after the TD dummy packet is cleaned up */ +#define SIR_LIM_TD_DUMMY_CALLBACK_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xA) +/* Message from SCH when the STA is ready to be deleted */ +#define SIR_LIM_SCH_CLEAN_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xB) +/* Message from ISR upon Radar Detection */ +#define SIR_LIM_RADAR_DETECT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xC) + +/* /////////////////////////////////// */ +/* message id Available */ +/* ////////////////////////////////// */ + +/* Message from Hal to send out a DEL-TS indication */ +#define SIR_LIM_DEL_TS_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xE) +/* Indication from HAL to delete Station context */ +#define SIR_LIM_DELETE_STA_CONTEXT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x11) +/* Indication from HAL to delete BA */ +#define SIR_LIM_UPDATE_BEACON (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x13) + +/* LIM Timeout messages */ +#define SIR_LIM_TIMEOUT_MSG_START ((SIR_LIM_MODULE_ID << 8) + 0xD0) +#define SIR_LIM_JOIN_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 2) +#define SIR_LIM_AUTH_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 3) +#define SIR_LIM_AUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 4) +#define SIR_LIM_ASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 5) +#define SIR_LIM_REASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 6) +#define SIR_LIM_HEART_BEAT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 7) +/* currently unused SIR_LIM_TIMEOUT_MSG_START + 0x8 */ +/* Link Monitoring Messages */ +#define SIR_LIM_PROBE_HB_FAILURE_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xB) +#define SIR_LIM_ADDTS_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xC) +#define SIR_LIM_LINK_TEST_DURATION_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x13) +#define SIR_LIM_HASH_MISS_THRES_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x16) +#define SIR_LIM_CNF_WAIT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x17) +/* currently unused (SIR_LIM_TIMEOUT_MSG_START + 0x18) */ +#define SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x19) +#define SIR_LIM_CHANNEL_SWITCH_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1A) +#define SIR_LIM_QUIET_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1B) +#define SIR_LIM_QUIET_BSS_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1C) + +#define SIR_LIM_WPS_OVERLAP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1D) +#ifdef WLAN_FEATURE_VOWIFI_11R +#define SIR_LIM_FT_PREAUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1E) +#endif +#define SIR_LIM_REMAIN_CHN_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1F) +#define SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x20) + +#define SIR_LIM_BEACON_GEN_IND (SIR_LIM_TIMEOUT_MSG_START + 0x23) +#define SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x24) +#ifdef FEATURE_WLAN_ESE +#define SIR_LIM_ESE_TSM_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x25) +#endif + +#define SIR_LIM_DISASSOC_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x26) +#define SIR_LIM_DEAUTH_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x27) +#define SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT \ + (SIR_LIM_TIMEOUT_MSG_START + 0x28) + +#define SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE \ + (SIR_LIM_TIMEOUT_MSG_START + 0x2C) + +#define SIR_LIM_MSG_TYPES_END (SIR_LIM_MSG_TYPES_BEGIN+0xFF) + +/* SCH message types */ +#define SIR_SCH_MSG_TYPES_BEGIN (SIR_SCH_MODULE_ID << 8) +#define SIR_SCH_CHANNEL_SWITCH_REQUEST (SIR_SCH_MSG_TYPES_BEGIN) +#define SIR_SCH_START_SCAN_REQ (SIR_SCH_MSG_TYPES_BEGIN + 1) +#define SIR_SCH_START_SCAN_RSP (SIR_SCH_MSG_TYPES_BEGIN + 2) +#define SIR_SCH_END_SCAN_NTF (SIR_SCH_MSG_TYPES_BEGIN + 3) +#define SIR_SCH_MSG_TYPES_END (SIR_SCH_MSG_TYPES_BEGIN+0xFF) + +/* PMM message types */ +#define SIR_PMM_MSG_TYPES_BEGIN (SIR_PMM_MODULE_ID << 8) +#define SIR_PMM_CHANGE_PM_MODE (SIR_PMM_MSG_TYPES_BEGIN) +#define SIR_PMM_MSG_TYPES_END (SIR_PMM_MSG_TYPES_BEGIN+0xFF) + +/* MNT message types */ +#define SIR_MNT_MSG_TYPES_BEGIN (SIR_MNT_MODULE_ID << 8) +#define SIR_MNT_RELEASE_BD (SIR_MNT_MSG_TYPES_BEGIN + 0) +#define SIR_MNT_MSG_TYPES_END (SIR_MNT_MSG_TYPES_BEGIN + 0xFF) + +/* PTT message types */ +#define SIR_PTT_MSG_TYPES_BEGIN 0x3000 +#define SIR_PTT_MSG_TYPES_END 0x3300 + +/* ****************************************** * +* * +* EVENT TYPE Defintions * +* * +* ****************************************** */ + +/* MMH Events that are used in other modules to post events to MMH */ +#define SIR_HSTEMUL_TXMB_DONE_EVT 0x00000100 +#define SIR_HSTEMUL_RXMB_READY_EVT 0x00000200 +#define SIR_HSTEMUL_MSGQ_NE_EVT 0x00000400 + +#define SIR_TST_XMIT_MSG_QS_EMPTY_EVT 0x00000080 + +/* added for OBSS */ + +/* Param Change Bitmap sent to HAL */ +#define PARAM_BCN_INTERVAL_CHANGED (1 << 0) +#define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) +#define PARAM_SHORT_SLOT_TIME_CHANGED (1 << 2) +#define PARAM_llACOEXIST_CHANGED (1 << 3) +#define PARAM_llBCOEXIST_CHANGED (1 << 4) +#define PARAM_llGCOEXIST_CHANGED (1 << 5) +#define PARAM_HT20MHZCOEXIST_CHANGED (1<<6) +#define PARAM_NON_GF_DEVICES_PRESENT_CHANGED (1<<7) +#define PARAM_RIFS_MODE_CHANGED (1<<8) +#define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED (1<<9) +#define PARAM_OBSS_MODE_CHANGED (1<<10) +#define PARAM_BEACON_UPDATE_MASK (PARAM_BCN_INTERVAL_CHANGED | \ + PARAM_SHORT_PREAMBLE_CHANGED | \ + PARAM_SHORT_SLOT_TIME_CHANGED | \ + PARAM_llACOEXIST_CHANGED | \ + PARAM_llBCOEXIST_CHANGED | \ + PARAM_llGCOEXIST_CHANGED | \ + PARAM_HT20MHZCOEXIST_CHANGED | \ + PARAM_NON_GF_DEVICES_PRESENT_CHANGED | \ + PARAM_RIFS_MODE_CHANGED | \ + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED | \ + PARAM_OBSS_MODE_CHANGED) + +#endif diff --git a/core/mac/src/include/sys_global.h b/core/mac/src/include/sys_global.h new file mode 100644 index 0000000000..2f76ddf5e6 --- /dev/null +++ b/core/mac/src/include/sys_global.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __SYS_GLOBAL_H__ +#define __SYS_GLOBAL_H__ + +typedef struct sAniSirSys { + + uint32_t gSysFrameCount[4][16]; + uint32_t gSysBbtReceived; + uint32_t gSysBbtPostedToLim; + uint32_t gSysBbtPostedToSch; + uint32_t gSysBbtPostedToPmm; + uint32_t gSysBbtPostedToHal; + uint32_t gSysBbtDropped; + uint32_t gSysBbtNonLearnFrameInv; + uint32_t gSysBbtLearnFrameInv; + uint32_t gSysBbtCrcFail; + uint32_t gSysBbtDuplicates; + uint32_t gSysReleaseCount; + uint32_t probeError, probeBadSsid, probeIgnore, probeRespond; + + uint32_t gSysEnableLearnMode; + uint32_t gSysEnableScanMode; + uint32_t gSysEnableLinkMonitorMode; +} tAniSirSys, *tpAniSirSys; + +#endif diff --git a/core/mac/src/include/utils_api.h b/core/mac/src/include/utils_api.h new file mode 100644 index 0000000000..6a344befe9 --- /dev/null +++ b/core/mac/src/include/utils_api.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __UTILSAPI_H +#define __UTILSAPI_H + +#include +#include +#include "ani_global.h" +#include "utils_global.h" +#include "sys_wrapper.h" + +/* / System role definition on a per BSS */ +typedef enum eBssSystemRole { + eSYSTEM_UNKNOWN_ROLE, + eSYSTEM_AP_ROLE, + eSYSTEM_STA_IN_IBSS_ROLE, + eSYSTEM_STA_ROLE, + eSYSTEM_BTAMP_STA_ROLE, + eSYSTEM_BTAMP_AP_ROLE, + + eSYSTEM_LAST_ROLE, + eSYSTEM_MULTI_BSS_ROLE = eSYSTEM_LAST_ROLE +} tBssSystemRole; + +#define LOG_INDEX_FOR_MODULE(modId) ((modId) - LOG_FIRST_MODULE_ID) +#define GET_MIN_VALUE(__val1, __val2) ((__val1 < __val2) ? __val1 : __val2) + +/* The caller must check loglevel. This API assumes loglevel is good */ +extern void log_debug(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, va_list marker); + +extern void log_dbg(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, ...); + +extern uint32_t gPktAllocCnt, gPktFreeCnt; + +extern CDF_TRACE_LEVEL get_vos_debug_level(uint32_t debugLevel); + +/* / Log initialization */ +extern tSirRetStatus log_init(tpAniSirGlobal); + +extern void log_deinit(tpAniSirGlobal); + +extern tSirRetStatus cfg_init(tpAniSirGlobal); +extern void cfg_de_init(tpAniSirGlobal); + +void sir_dump_buf(tpAniSirGlobal pMac, uint8_t modId, uint32_t level, + uint8_t *buf, uint32_t size); + +/** + * sir_swap_u16() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16(uint16_t val) +{ + return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8); +} /*** end sir_swap_u16() ***/ + +/** + * sir_swap_u16if_needed() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16if_needed(uint16_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u16(val); +#else + return val; +#endif +} /*** end sir_swap_u16if_needed() ***/ + +/** + * sir_swap_u32() + * + * FUNCTION: + * This function is called to swap four U8s of an uint32_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32(uint32_t val) +{ + return (val << 24) | + (val >> 24) | + ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8); +} /*** end sir_swap_u32() ***/ + +/** + * sir_swap_u32if_needed() + * + * FUNCTION: + * This function is called to swap U8s of an uint32_t value depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32if_needed(uint32_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u32(val); +#else + return val; +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_u32_buf + * + * FUNCTION: + * It swaps N dwords into the same buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of uint32_t array + * @return void + * + */ + +static inline void sir_swap_u32_buf(uint32_t *ptr, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + ptr[i] = sir_swap_u32(ptr[i]); +} + +/** + * sir_swap_u32_buf_if_needed() + * + * FUNCTION: + * This function is called to swap U8s of U32s in the buffer depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBuf Buffer that will get swapped + * @param nWords Number DWORDS will be swapped + * @return void + */ + +static inline void sir_swap_u32_buf_if_needed(uint32_t *pBuf, uint32_t nWords) +{ +#ifdef ANI_LITTLE_BYTE_ENDIAN + sir_swap_u32_buf(pBuf, nWords); +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_bd_if_needed + * + * FUNCTION: + * Byte swap all the dwords in the BD, except the PHY/MAC headers + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBd BD that will get swapped + * @return void + */ + +static inline void sir_swap_bd_if_needed(uint32_t *pBd) +{ + sir_swap_u32_buf_if_needed(pBd, 6); + sir_swap_u32_buf_if_needed(pBd + 18, 14); +} + +/** + * sir_store_u16_n + * + * FUNCTION: + * It stores a 16 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16_n(uint8_t *ptr, uint16_t val) +{ + *ptr++ = (val >> 8) & 0xff; + *ptr = val & 0xff; +} + +/** + * sir_store_u32_n + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32_n(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) (val >> 24) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr = (uint8_t) (val) & 0xff; +} + +/** + * sir_store_u16 + * + * FUNCTION: + * It stores a 16 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16(uint8_t *ptr, uint16_t val) +{ + *ptr++ = val & 0xff; + *ptr = (val >> 8) & 0xff; +} + +/** + * sir_store_u32 + * + * FUNCTION: + * It stores a 32 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) val & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr = (uint8_t) (val >> 24) & 0xff; +} + +/** + * sir_store_u32BufN + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first. It performs the above operation + * on entire buffer and writes to the dst buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * Assumes that the pSrc buffer is of all uint32_t data type fields. + * + * NOTE: + * Must be used if all the fields in the buffer must be of uint32_t types. + * + * @param pDst address of destination byte array + * @param pSrc address of the source DWORD array + * @param length number of DWORDs + * @return None + */ + +static inline void +sir_store_buf_n(uint8_t *pDst, uint32_t *pSrc, uint32_t length) +{ + while (length) { + sir_store_u32_n(pDst, *pSrc); + pDst += 4; + pSrc++; + length--; + } +} + +/** + * sir_read_u16_n + * + * FUNCTION: + * It reads a 16 bit number from the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 16 bit value + */ + +static inline uint16_t sir_read_u16_n(uint8_t *ptr) +{ + return ((*ptr) << 8) | (*(ptr + 1)); +} + +/** + * sir_swap_u32_buf + * + * FUNCTION: + * It swaps N dwords into the same buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of uint32_t array + * @return void + * + */ + +static inline void +sir_swap_n_store(uint32_t *src, uint32_t *dst, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + dst[i] = sir_swap_u32(src[i]); +} + +/** + * sir_read_u32_n + * + * FUNCTION: + * It reads a 32 bit number from the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32_n(uint8_t *ptr) +{ + return (*(ptr) << 24) | + (*(ptr + 1) << 16) | (*(ptr + 2) << 8) | (*(ptr + 3)); +} + +/** + * sir_read_u16 + * + * FUNCTION: + * It reads a 16 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 16 bit value + */ + +static inline uint16_t sir_read_u16(uint8_t *ptr) +{ + return (*ptr) | (*(ptr + 1) << 8); +} + +/** + * sir_read_u32 + * + * FUNCTION: + * It reads a 32 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32(uint8_t *ptr) +{ + return (*(ptr)) | + (*(ptr + 1) << 8) | (*(ptr + 2) << 16) | (*(ptr + 3) << 24); +} + +/* / Copy a MAC address from 'from' to 'to' */ +static inline void sir_copy_mac_addr(uint8_t to[], uint8_t from[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) to | (uint32_t) from)); + if (align == 0) { + *((uint16_t *) &(to[4])) = *((uint16_t *) &(from[4])); + *((uint32_t *) to) = *((uint32_t *) from); + } else if (align == 2) { + *((uint16_t *) &to[4]) = *((uint16_t *) &from[4]); + *((uint16_t *) &to[2]) = *((uint16_t *) &from[2]); + *((uint16_t *) &to[0]) = *((uint16_t *) &from[0]); + } else { + to[5] = from[5]; + to[4] = from[4]; + to[3] = from[3]; + to[2] = from[2]; + to[1] = from[1]; + to[0] = from[0]; + } +#else + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to[4] = from[4]; + to[5] = from[5]; +#endif +} + +static inline uint8_t sir_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) addr1 | (uint32_t) addr2)); + + if (align == 0) { + return (*((uint16_t *) &(addr1[4])) == + *((uint16_t *) &(addr2[4]))) + && (*((uint32_t *) addr1) == *((uint32_t *) addr2)); + } else if (align == 2) { + return (*((uint16_t *) &addr1[4]) == + *((uint16_t *) &addr2[4])) + && (*((uint16_t *) &addr1[2]) == + *((uint16_t *) &addr2[2])) + && (*((uint16_t *) &addr1[0]) == + *((uint16_t *) &addr2[0])); + } else { + return (addr1[5] == addr2[5]) && + (addr1[4] == addr2[4]) && + (addr1[3] == addr2[3]) && + (addr1[2] == addr2[2]) && + (addr1[1] == addr2[1]) && (addr1[0] == addr2[0]); + } +#else + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +#endif +} + +/* + * converts uint16_t CW value to 4 bit value to be inserted in IE + */ +static inline uint8_t convert_cw(uint16_t cw) +{ + uint8_t val = 0; + while (cw > 0) { + val++; + cw >>= 1; + } + if (val > 15) + return 0xF; + return val; +} + +/* The user priority to AC mapping is such: + * UP(1, 2) ---> AC_BK(1) + * UP(0, 3) ---> AC_BE(0) + * UP(4, 5) ---> AC_VI(2) + * UP(6, 7) ---> AC_VO(3) + */ +#define WLAN_UP_TO_AC_MAP 0x33220110 +#define upToAc(up) ((WLAN_UP_TO_AC_MAP >> ((up) << 2)) & 0x03) + +/* ------------------------------------------------------------------- */ + +/* / Parse the next IE in a message */ +extern tSirRetStatus sirParseNextIE(tpAniSirGlobal, uint8_t *pPayload, + uint16_t payloadLength, int16_t lastType, + uint8_t *pType, uint8_t *pLength); + +/* / Check if the given channel is 11b channel */ +#define SIR_IS_CHANNEL_11B(chId) (chId <= 14) + +/** + * hal_round_s32 + * + * FUNCTION: + * Performs integer rounding like returns 12346 for 123456 or -12346 for -123456 + * Note that a decimal place is lost. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param int32_t input + * @return rounded number + */ +static inline int32_t hal_round_s32(int32_t p) +{ + int32_t k, i, j; + + i = p / 10; + j = p % 10; + if (p > 0) + k = i + (j > 4 ? 1 : 0); + else if (p < 0) + k = i + (j < -5 ? -1 : 0); + else + k = p; + + return k; +} + +/* New functions for endianess conversion */ +#ifdef ANI_LITTLE_BYTE_ENDIAN +#define ani_cpu_to_be16(x) sir_swap_u16((x)) +#define ani_cpu_to_le16(x) (x) +#define ani_cpu_to_be32(x) sir_swap_u32((x)) +#define ani_cpu_to_le32(x) (x) +#else /* ANI_LITTLE_BYTE_ENDIAN */ +#define ani_cpu_to_be16(x) (x) +#define ani_cpu_to_le16(x) sir_swap_u16((x)) +#define ani_cpu_to_be32(x) (x) +#define ani_cpu_to_le32(x) sir_swap_u32((x)) +#endif /* ANI_LITTLE_BYTE_ENDIAN */ + +#define ani_le16_to_cpu(x) ani_cpu_to_le16(x) +#define ani_le32_to_cpu(x) ani_cpu_to_le32(x) +#define ani_be16_to_cpu(x) ani_cpu_to_be16(x) +#define ani_be32_to_cpu(x) ani_cpu_to_be32(x) + +void convertto_big_endian(void *ptr, uint16_t size); +void create_scan_cts_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tSirMacAddr selfMac); +void create_scan_data_null_frame(tpAniSirGlobal pMac, + tSirMacMgmtHdr *macMgmtHdr, uint8_t pwrMgmt, tSirMacAddr bssid, + tSirMacAddr selfMacAddr); +void create_init_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role); +void create_finish_scan_raw_frame(tpAniSirGlobal pMac, + tSirMacMgmtHdr *macMgmtHdr, tBssSystemRole role); + +#endif /* __UTILSAPI_H */ diff --git a/core/mac/src/include/utils_global.h b/core/mac/src/include/utils_global.h new file mode 100644 index 0000000000..db2f8547dc --- /dev/null +++ b/core/mac/src/include/utils_global.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __UTILS_GLOBAL_H__ +#define __UTILS_GLOBAL_H__ + +#include "sir_params.h" + +/* + * Current debug and event log level + */ +#define LOG_FIRST_MODULE_ID SIR_FIRST_MODULE_ID +#define LOG_LAST_MODULE_ID SIR_LAST_MODULE_ID +#define LOG_ENTRY_NUM (LOG_LAST_MODULE_ID - LOG_FIRST_MODULE_ID + 1) + +typedef struct sAniSirUtils { + uint32_t gLogEvtLevel[LOG_ENTRY_NUM]; + uint32_t gLogDbgLevel[LOG_ENTRY_NUM]; + +} tAniSirUtils, *tpAniSirUtils; + +#endif diff --git a/core/mac/src/pe/include/lim_admit_control.h b/core/mac/src/pe/include/lim_admit_control.h new file mode 100644 index 0000000000..90eae86ee5 --- /dev/null +++ b/core/mac/src/pe/include/lim_admit_control.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Dinesh Upadhyay + * Date: 10/24/06 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_ADMIT_CONTROL_H__ +#define __LIM_ADMIT_CONTROL_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +tSirRetStatus +lim_tspec_find_by_assoc_id(tpAniSirGlobal, uint16_t, tSirMacTspecIE *, + tpLimTspecInfo, tpLimTspecInfo *); + +/* Add TSPEC in lim local table */ +tSirRetStatus lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo); + +/* admit control interface */ +extern tSirRetStatus lim_admit_control_add_ts(tpAniSirGlobal pMac, + uint8_t *pAddr, tSirAddtsReqInfo *addts, + tSirMacQosCapabilityStaIE *qos, + uint16_t assocId, uint8_t alloc, + tSirMacScheduleIE *pSch, + /* index to the lim tspec table. */ + uint8_t *pTspecIdx, + tpPESession psessionEntry); + +static inline tSirRetStatus +lim_admit_control_add_sta(tpAniSirGlobal pMac, uint8_t *staAddr, uint8_t alloc) +{ + return eSIR_SUCCESS; +} + +extern tSirRetStatus +lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId); + +extern tSirRetStatus +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *tsinfo, + uint8_t *tsStatus, uint8_t *tspecIdx); + +extern tSirRetStatus lim_update_admit_policy(tpAniSirGlobal pMac); + +tSirRetStatus lim_admit_control_init(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_ESE +tSirRetStatus lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval); +#else +tSirRetStatus lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId); +#endif + +tSirRetStatus lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, + uint8_t sessionId, uint8_t *bssId); +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg); + +#endif diff --git a/core/mac/src/pe/include/lim_api.h b/core/mac/src/pe/include/lim_api.h new file mode 100644 index 0000000000..99e2fc7376 --- /dev/null +++ b/core/mac/src/pe/include/lim_api.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_api.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_API_H +#define __LIM_API_H +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "sch_global.h" +#include "utils_api.h" +#include "lim_global.h" +#include "wma_if.h" +#include "wma_types.h" + +/* Macro to count heartbeat */ +#define limResetHBPktCount(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB = 0) + +/* Useful macros for fetching various states in pMac->lim */ +/* gLimSystemRole */ +#define GET_LIM_SYSTEM_ROLE(psessionEntry) (psessionEntry->limSystemRole) +#define LIM_IS_AP_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_AP_ROLE) +#define LIM_IS_STA_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_ROLE) +#define LIM_IS_IBSS_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_IN_IBSS_ROLE) +#define LIM_IS_UNKNOWN_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_UNKNOWN_ROLE) +#define LIM_IS_BT_AMP_AP_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_BT_AMP_AP_ROLE) +#define LIM_IS_BT_AMP_STA_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_BT_AMP_STA_ROLE) +#define LIM_IS_P2P_DEVICE_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_ROLE) +#define LIM_IS_P2P_DEVICE_GO(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_GO) +/* gLimSmeState */ +#define GET_LIM_SME_STATE(pMac) (pMac->lim.gLimSmeState) +#define SET_LIM_SME_STATE(pMac, state) (pMac->lim.gLimSmeState = state) +/* gLimMlmState */ +#define GET_LIM_MLM_STATE(pMac) (pMac->lim.gLimMlmState) +#define SET_LIM_MLM_STATE(pMac, state) (pMac->lim.gLimMlmState = state) +/*tpdphHashNode mlmStaContext*/ +#define GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs) (pStaDs->mlmStaContext.mlmState) +#define SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, state) (pStaDs->mlmStaContext.mlmState = state) +/* gLimQuietState */ +#define GET_LIM_QUIET_STATE(pMac) (pMac->lim.gLimSpecMgmt.quietState) +#define SET_LIM_QUIET_STATE(pMac, state) (pMac->lim.gLimSpecMgmt.quietState = state) +#define LIM_IS_CONNECTION_ACTIVE(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB) +/*pMac->lim.gLimProcessDefdMsgs*/ +#define GET_LIM_PROCESS_DEFD_MESGS(pMac) (pMac->lim.gLimProcessDefdMsgs) +#define SET_LIM_PROCESS_DEFD_MESGS(pMac, val) (pMac->lim.gLimProcessDefdMsgs = val) +/* LIM exported function templates */ +#define LIM_IS_RADAR_DETECTED(pMac) (pMac->lim.gLimSpecMgmt.fRadarDetCurOperChan) +#define LIM_SET_RADAR_DETECTED(pMac, val) (pMac->lim.gLimSpecMgmt.fRadarDetCurOperChan = val) +#define LIM_MIN_BCN_PR_LENGTH 12 +#define LIM_BCN_PR_CAPABILITY_OFFSET 10 +typedef enum eMgmtFrmDropReason { + eMGMT_DROP_NO_DROP, + eMGMT_DROP_NOT_LAST_IBSS_BCN, + eMGMT_DROP_INFRA_BCN_IN_IBSS, + eMGMT_DROP_SCAN_MODE_FRAME, + eMGMT_DROP_NON_SCAN_MODE_FRAME, + eMGMT_DROP_INVALID_SIZE, + eMGMT_DROP_SPURIOUS_FRAME, +} tMgmtFrmDropReason; + +/** + * Function to initialize LIM state machines. + * This called upon LIM thread creation. + */ +extern tSirRetStatus lim_initialize(tpAniSirGlobal); +tSirRetStatus pe_open(tpAniSirGlobal pMac, tMacOpenParameters *pMacOpenParam); +tSirRetStatus pe_close(tpAniSirGlobal pMac); +void pe_register_tl_handle(tpAniSirGlobal pMac); +tSirRetStatus lim_start(tpAniSirGlobal pMac); +tSirRetStatus pe_start(tpAniSirGlobal pMac); +void pe_stop(tpAniSirGlobal pMac); +tSirRetStatus pe_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg); +tSirRetStatus peProcessMsg(tpAniSirGlobal pMac, tSirMsgQ *limMsg); +/** + * Function to cleanup LIM state. + * This called upon reset/persona change etc + */ +extern void lim_cleanup(tpAniSirGlobal); +/* / Function to post messages to LIM thread */ +extern uint32_t lim_post_msg_api(tpAniSirGlobal, tSirMsgQ *); +/** + * Function to process messages posted to LIM thread + * and dispatch to various sub modules within LIM module. + */ +extern void lim_message_processor(tpAniSirGlobal, tpSirMsgQ); +extern void lim_process_messages(tpAniSirGlobal, tpSirMsgQ); /* DT test alt deferred 2 */ +/** + * Function to check the LIM state if system is in Scan/Learn state. + */ +extern uint8_t lim_is_system_in_scan_state(tpAniSirGlobal); +/** + * Function to handle IBSS coalescing. + * Beacon Processing module to call this. + */ +extern tSirRetStatus lim_handle_ibss_coalescing(tpAniSirGlobal, + tpSchBeaconStruct, + uint8_t *, tpPESession); +/* / Function used by other Sirius modules to read global SME state */ +static inline tLimSmeStates lim_get_sme_state(tpAniSirGlobal pMac) +{ + return pMac->lim.gLimSmeState; +} + +extern void lim_received_hb_handler(tpAniSirGlobal, uint8_t, tpPESession); +extern void limCheckAndQuietBSS(tpAniSirGlobal); +/* / Function that triggers STA context deletion */ +extern void lim_trigger_sta_deletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +#ifdef FEATURE_WLAN_TDLS +/* Function that sends TDLS Del Sta indication to SME */ +extern void lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, + uint16_t reasonCode); +#endif + +/* / Function that checks for change in AP's capabilties on STA */ +extern void lim_detect_change_in_ap_capabilities(tpAniSirGlobal, + tpSirProbeRespBeacon, tpPESession); +tSirRetStatus lim_update_short_slot(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession); + +void lim_ps_offload_handle_missed_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEntry); +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType); +bool lim_is_deauth_diassoc_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info); +#ifdef WLAN_FEATURE_11W +bool lim_is_assoc_req_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info); +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void lim_roam_offload_synch_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +#endif +#define limGetQosMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limQosEnabled) +#define limGetWmeMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWmeEnabled) +#define limGetWsmMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWsmEnabled) +#define limGet11dMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->lim11dEnabled) +#define limGetAckPolicy(pMac, pVal) (*(pVal) = pMac->lim.ackPolicy) +/* ----------------------------------------------------------------------- */ +static inline void lim_get_phy_mode(tpAniSirGlobal pMac, uint32_t *phyMode, + tpPESession psessionEntry) +{ + *phyMode = + psessionEntry ? psessionEntry->gLimPhyMode : pMac->lim.gLimPhyMode; +} + +/* ----------------------------------------------------------------------- */ +static inline void lim_get_rf_band_new(tpAniSirGlobal pMac, tSirRFBand *band, + tpPESession psessionEntry) +{ + *band = psessionEntry ? psessionEntry->limRFBand : SIR_BAND_UNKNOWN; +} + +/*-------------------------------------------------------------------------- + + \brief pe_process_messages() - Message Processor for PE + + Voss calls this function to dispatch the message to PE + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ +tSirRetStatus pe_process_messages(tpAniSirGlobal pMac, tSirMsgQ *pMsg); +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param tpAniSirGlobal pMac + \param tSirMsgQ pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +/*-------------------------------------------------------------------------- + + \brief lim_remain_on_chn_rsp() - API for sending remain on channel response. + + LIM calls this api to send the remain on channel response to SME. + + \param pMac - Pointer to Global MAC structure + \param status - status of the response + \param data - pointer to msg + + \return void + + --------------------------------------------------------------------------*/ +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, CDF_STATUS status, uint32_t *data); + +/*-------------------------------------------------------------------------- + + \brief lim_process_abort_scan_ind() - function for sending abort scan indication. + + LIM calls this function for sending abort scan indication. + + \param pMac - Pointer to Global MAC structure + + \return void + + --------------------------------------------------------------------------*/ +void lim_process_abort_scan_ind(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id); + +void __lim_process_sme_assoc_cnf_new(tpAniSirGlobal, uint32_t, uint32_t *); + +/************************************************************/ +#endif /* __LIM_API_H */ diff --git a/core/mac/src/pe/include/lim_ft.h b/core/mac/src/pe/include/lim_ft.h new file mode 100644 index 0000000000..a0be848165 --- /dev/null +++ b/core/mac/src/pe/include/lim_ft.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if defined WLAN_FEATURE_VOWIFI_11R +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFT_H__ +#define __LIMFT_H__ + +#include +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, tpPESession psessionEntry); +int lim_process_ft_pre_auth_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +void limPerformPostFTPreAuth(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +void limFTResumeLinkCb(tpAniSirGlobal pMac, CDF_STATUS status, uint32_t *data); +void lim_post_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry); +void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_len, + tpPESession psessionEntry); +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry); +void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal pMac); + +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +tSirRetStatus lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac); +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, + tpPESession psessionEntry); +tSirRetStatus lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, + uint8_t updateEntry, + tpPESession pftSessionEntry, + tpSirBssDescription bssDescription); +#endif /* __LIMFT_H__ */ + +#endif /* WLAN_FEATURE_VOWIFI_11R */ diff --git a/core/mac/src/pe/include/lim_ft_defs.h b/core/mac/src/pe/include/lim_ft_defs.h new file mode 100644 index 0000000000..da4f11f7a2 --- /dev/null +++ b/core/mac/src/pe/include/lim_ft_defs.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if defined WLAN_FEATURE_VOWIFI_11R +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFTDEFS_H__ +#define __LIMFTDEFS_H__ + +#include +#include "wma_if.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define SIR_MDIE_SIZE 3 /* MD ID(2 bytes), Capability(1 byte) */ +#define MAX_FTIE_SIZE 384 /* Max size limited to 384, on acct. of IW custom events */ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- + FT Pre Auth Req SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthReq { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_REQ */ + uint16_t length; + /* + * Track if response is processed for this request + * We expect only one response per request. + */ + bool bPreAuthRspProcessed; + uint8_t preAuthchannelNum; + /* BSSID currently associated to suspend the link */ + tSirMacAddr currbssId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + tpSirBssDescription pbssDescription; +} tSirFTPreAuthReq, *tpSirFTPreAuthReq; + +/*------------------------------------------------------------------------- + FT Pre Auth Rsp PE<->SME + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthRsp { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_RSP */ + uint16_t length; + uint8_t smeSessionId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + tSirRetStatus status; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + uint16_t ric_ies_length; + uint8_t ric_ies[MAX_FTIE_SIZE]; +} tSirFTPreAuthRsp, *tpSirFTPreAuthRsp; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTUpdateKeyInfo { + uint16_t messageType; + uint16_t length; + uint32_t smeSessionId; + tSirMacAddr bssId; + tSirKeyMaterial keyMaterial; +} tSirFTUpdateKeyInfo, *tpSirFTUpdateKeyInfo; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthKeyInfo { + uint8_t extSetStaKeyParamValid; /* Ext Bss Config Msg if set */ + /* SetStaKeyParams for ext bss msg */ + tLimMlmSetKeysReq extSetStaKeyParam; +} tSirFTPreAuthKeyInfo, *tpSirFTPreAuthKeyInfo; + +/*------------------------------------------------------------------------- + Global FT Information + ------------------------------------------------------------------------*/ +typedef struct sFTPEContext { + tpSirFTPreAuthReq pFTPreAuthReq; /* Saved FT Pre Auth Req */ + tSirRetStatus ftPreAuthStatus; + uint16_t saved_auth_rsp_length; + uint8_t saved_auth_rsp[MAX_FTIE_SIZE]; + tSirFTPreAuthKeyInfo PreAuthKeyInfo; + /* Items created for the new FT, session */ + void *pAddBssReq; /* Save add bss req */ + void *pAddStaReq; /*Save add sta req */ + uint32_t peSessionId; + uint32_t smeSessionId; + + /* This flag is required to indicate on which session the preauth + * has taken place, since the auth reponse for preauth will come + * for a new BSSID for which there is no session yet. This flag + * will be used to extract the session from the session preauth + * has been initiated + */ + bool ftPreAuthSession; +} tftPEContext, *tpftPEContext; + +#endif /* __LIMFTDEFS_H__ */ + +#endif /* WLAN_FEATURE_VOWIFI_11R */ diff --git a/core/mac/src/pe/include/lim_global.h b/core/mac/src/pe/include/lim_global.h new file mode 100644 index 0000000000..5ddb01c632 --- /dev/null +++ b/core/mac/src/pe/include/lim_global.h @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_global.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_GLOBAL_H +#define __LIM_GLOBAL_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "wni_cfg.h" +#include "csr_api.h" +#include "sap_api.h" +#include "dot11f.h" +#include "wma_if.h" + +/* / Maximum number of scan hash table entries */ +#define LIM_MAX_NUM_OF_SCAN_RESULTS 256 + +/* Sending Disassociate frames threshold */ +#define LIM_SEND_DISASSOC_FRAME_THRESHOLD 2 +#define LIM_HASH_MISS_TIMER_MS 10000 + +/* Deferred Message Queue Length */ +#define MAX_DEFERRED_QUEUE_LEN 80 + +/* Maximum number of PS - TIM's to be sent with out wakeup from STA */ +#define LIM_TIM_WAIT_COUNT_FACTOR 5 + +/* + * Use this count if (LIM_TIM_WAIT_FACTOR * ListenInterval) + * is less than LIM_MIN_TIM_WAIT_CNT + */ +#define LIM_MIN_TIM_WAIT_COUNT 50 + +#define GET_TIM_WAIT_COUNT(LIntrvl) \ + ((LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) > LIM_MIN_TIM_WAIT_COUNT ? \ + (LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) : LIM_MIN_TIM_WAIT_COUNT) + +#define IS_5G_BAND(__rfBand) ((__rfBand & 0x3) == 0x2) +#define IS_24G_BAND(__rfBand) ((__rfBand & 0x3) == 0x1) + +#define LIM_MAX_CSA_IE_UPDATES (5) + +/* enums exported by LIM are as follows */ + +/*System role definition */ +typedef enum eLimSystemRole { + eLIM_UNKNOWN_ROLE, + eLIM_AP_ROLE, + eLIM_STA_IN_IBSS_ROLE, + eLIM_STA_ROLE, + eLIM_BT_AMP_STA_ROLE, + eLIM_BT_AMP_AP_ROLE, + eLIM_P2P_DEVICE_ROLE, + eLIM_P2P_DEVICE_GO, + eLIM_P2P_DEVICE_CLIENT +} tLimSystemRole; + +/* + * SME state definition accessible across all Sirius modules. + * AP only states are LIM_SME_CHANNEL_SCAN_STATE & + * LIM_SME_NORMAL_CHANNEL_SCAN_STATE. + * Note that these states may also be present in STA + * side too when DFS support is present for a STA in IBSS mode. + */ +typedef enum eLimSmeStates { + eLIM_SME_OFFLINE_STATE, + eLIM_SME_IDLE_STATE, + eLIM_SME_SUSPEND_STATE, + eLIM_SME_WT_SCAN_STATE, + eLIM_SME_WT_JOIN_STATE, + eLIM_SME_WT_AUTH_STATE, + eLIM_SME_WT_ASSOC_STATE, + eLIM_SME_WT_REASSOC_STATE, + eLIM_SME_WT_REASSOC_LINK_FAIL_STATE, + eLIM_SME_JOIN_FAILURE_STATE, + eLIM_SME_ASSOCIATED_STATE, + eLIM_SME_REASSOCIATED_STATE, + eLIM_SME_LINK_EST_STATE, + eLIM_SME_LINK_EST_WT_SCAN_STATE, + eLIM_SME_WT_PRE_AUTH_STATE, + eLIM_SME_WT_DISASSOC_STATE, + eLIM_SME_WT_DEAUTH_STATE, + eLIM_SME_WT_START_BSS_STATE, + eLIM_SME_WT_STOP_BSS_STATE, + eLIM_SME_NORMAL_STATE, + eLIM_SME_CHANNEL_SCAN_STATE, + eLIM_SME_NORMAL_CHANNEL_SCAN_STATE +} tLimSmeStates; + +/* + * MLM state definition. + * While these states are present on AP too when it is + * STA mode, per-STA MLM state exclusive to AP is: + * eLIM_MLM_WT_AUTH_FRAME3. + */ +typedef enum eLimMlmStates { + eLIM_MLM_OFFLINE_STATE, + eLIM_MLM_IDLE_STATE, + eLIM_MLM_WT_PROBE_RESP_STATE, + eLIM_MLM_PASSIVE_SCAN_STATE, + eLIM_MLM_WT_JOIN_BEACON_STATE, + eLIM_MLM_JOINED_STATE, + eLIM_MLM_BSS_STARTED_STATE, + eLIM_MLM_WT_AUTH_FRAME2_STATE, + eLIM_MLM_WT_AUTH_FRAME3_STATE, + eLIM_MLM_WT_AUTH_FRAME4_STATE, + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE, + eLIM_MLM_AUTHENTICATED_STATE, + eLIM_MLM_WT_ASSOC_RSP_STATE, + eLIM_MLM_WT_REASSOC_RSP_STATE, + eLIM_MLM_ASSOCIATED_STATE, + eLIM_MLM_REASSOCIATED_STATE, + eLIM_MLM_LINK_ESTABLISHED_STATE, + eLIM_MLM_WT_ASSOC_CNF_STATE, + eLIM_MLM_LEARN_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_STATE, + eLIM_MLM_WT_DEL_BSS_RSP_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE, + eLIM_MLM_WT_ADD_STA_RSP_STATE, + eLIM_MLM_WT_DEL_STA_RSP_STATE, + /* + * MLM goes to this state when LIM initiates DELETE_STA + * as processing of Assoc req because the entry already exists. + * LIM comes out of this state when DELETE_STA response from + * HAL is received. LIM needs to maintain this state so that ADD_STA + * can be issued while processing DELETE_STA response from HAL. + */ + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE, + eLIM_MLM_WT_SET_BSS_KEY_STATE, + eLIM_MLM_WT_SET_STA_KEY_STATE, + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE, + eLIM_MLM_WT_SET_MIMOPS_STATE, +#if defined WLAN_FEATURE_VOWIFI_11R + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE, +#endif + eLIM_MLM_P2P_LISTEN_STATE, +} tLimMlmStates; + +/* 11h channel quiet states */ + +/* + * This enum indicates in which state the device is in + * when it receives quiet element in beacon or probe-response. + * The default quiet state of the device is always INIT + * eLIM_QUIET_BEGIN - When Quiet period is started + * eLIM_QUIET_CHANGED - When Quiet period is updated + * eLIM_QUIET_RUNNING - Between two successive Quiet updates + * eLIM_QUIET_END - When quiet period ends + */ +typedef enum eLimQuietStates { + eLIM_QUIET_INIT, + eLIM_QUIET_BEGIN, + eLIM_QUIET_CHANGED, + eLIM_QUIET_RUNNING, + eLIM_QUIET_END +} tLimQuietStates; + +/* 11h channel switch states */ + +/* + * This enum indicates in which state the channel-swith + * is presently operating. + * eLIM_11H_CHANSW_INIT - Default state + * eLIM_11H_CHANSW_RUNNING - When channel switch is running + * eLIM_11H_CHANSW_END - After channel switch is complete + */ +typedef enum eLimDot11hChanSwStates { + eLIM_11H_CHANSW_INIT, + eLIM_11H_CHANSW_RUNNING, + eLIM_11H_CHANSW_END +} tLimDot11hChanSwStates; + + +/* WLAN_SUSPEND_LINK Related */ +typedef void (*SUSPEND_RESUME_LINK_CALLBACK)(tpAniSirGlobal pMac, + CDF_STATUS status, + uint32_t *data); + +/* LIM to HAL SCAN Management Message Interface states */ +typedef enum eLimHalScanState { + eLIM_HAL_IDLE_SCAN_STATE, + eLIM_HAL_INIT_SCAN_WAIT_STATE, + eLIM_HAL_START_SCAN_WAIT_STATE, + eLIM_HAL_END_SCAN_WAIT_STATE, + eLIM_HAL_FINISH_SCAN_WAIT_STATE, + eLIM_HAL_INIT_LEARN_WAIT_STATE, + eLIM_HAL_START_LEARN_WAIT_STATE, + eLIM_HAL_END_LEARN_WAIT_STATE, + eLIM_HAL_FINISH_LEARN_WAIT_STATE, + eLIM_HAL_SCANNING_STATE, +/* WLAN_SUSPEND_LINK Related */ + eLIM_HAL_SUSPEND_LINK_WAIT_STATE, + eLIM_HAL_SUSPEND_LINK_STATE, + eLIM_HAL_RESUME_LINK_WAIT_STATE, +/* end WLAN_SUSPEND_LINK Related */ +} tLimLimHalScanState; + +/* MLM Req/Cnf structure definitions */ +typedef struct sLimMlmAuthReq { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + uint32_t authFailureTimeout; + uint8_t sessionId; +} tLimMlmAuthReq, *tpLimMlmAuthReq; + +typedef struct sLimMlmJoinReq { + uint32_t joinFailureTimeout; + tSirMacRateSet operationalRateSet; + uint8_t sessionId; + tSirBssDescription bssDescription; +} tLimMlmJoinReq, *tpLimMlmJoinReq; + +typedef struct sLimMlmScanReq { + tSirBssType bssType; + tSirMacAddr bssId; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + tSirScanType scanType; + uint32_t minChannelTime; + uint32_t maxChannelTime; + uint32_t dot11mode; + /* Number of SSIDs to scan(send Probe request) */ + uint8_t numSsid; + + bool p2pSearch; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + + uint8_t sessionId; + /* channelList MUST be the last field of this structure */ + tSirChannelList channelList; + /*----------------------------- + tLimMlmScanReq.... + ----------------------------- + uIEFiledLen + ----------------------------- + uIEFiledOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEFiled + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tLimMlmScanReq, *tpLimMlmScanReq; + +typedef struct tLimScanResultNode tLimScanResultNode; +struct tLimScanResultNode { + tLimScanResultNode *next; + tSirBssDescription bssDescription; +}; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 280 +#endif +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +/* OEM Data related structure definitions */ +typedef struct sLimMlmOemDataReq { + tSirMacAddr selfMacAddr; + uint8_t oemDataReq[OEM_DATA_REQ_SIZE]; +} tLimMlmOemDataReq, *tpLimMlmOemDataReq; + +typedef struct sLimMlmOemDataRsp { + uint8_t oemDataRsp[OEM_DATA_RSP_SIZE]; +} tLimMlmOemDataRsp, *tpLimMlmOemDataRsp; +#endif + +/* Pre-authentication structure definition */ +typedef struct tLimPreAuthNode { + struct tLimPreAuthNode *next; + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tLimMlmStates mlmState; + uint8_t authNodeIdx; + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; + uint8_t fTimerStarted:1; + uint8_t fSeen:1; + uint8_t fFree:1; + uint8_t rsvd:5; + TX_TIMER timer; + uint16_t seq_num; + v_TIME_t timestamp; +} tLimPreAuthNode, *tpLimPreAuthNode; + +/* Pre-authentication table definition */ +typedef struct tLimPreAuthTable { + uint32_t numEntry; + tpLimPreAuthNode pTable; +} tLimPreAuthTable, *tpLimPreAuthTable; + +/* / Per STA context structure definition */ +typedef struct sLimMlmStaContext { + tLimMlmStates mlmState; + tAniAuthType authType; + uint16_t listenInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacPropRateSet propRateSet; + tSirMacReasonCodes disassocReason; + uint16_t cleanupTrigger; + + tSirResultCodes resultCode; + uint16_t protStatusCode; + + uint8_t subType:1; /* Indicates ASSOC (0) or REASSOC (1) */ + uint8_t updateContext:1; + uint8_t schClean:1; + /* 802.11n HT Capability in Station: Enabled 1 or DIsabled 0 */ + uint8_t htCapability:1; +#ifdef WLAN_FEATURE_11AC + uint8_t vhtCapability:1; +#endif +} tLimMlmStaContext, *tpLimMlmStaContext; + +/* Structure definition to hold deferred messages queue parameters */ +typedef struct sLimDeferredMsgQParams { + tSirMsgQ deferredQueue[MAX_DEFERRED_QUEUE_LEN]; + uint16_t size; + uint16_t read; + uint16_t write; +} tLimDeferredMsgQParams, *tpLimDeferredMsgQParams; + +typedef struct sCfgProtection { + uint32_t overlapFromlla:1; + uint32_t overlapFromllb:1; + uint32_t overlapFromllg:1; + uint32_t overlapHt20:1; + uint32_t overlapNonGf:1; + uint32_t overlapLsigTxop:1; + uint32_t overlapRifs:1; + uint32_t overlapOBSS:1; /* added for obss */ + uint32_t fromlla:1; + uint32_t fromllb:1; + uint32_t fromllg:1; + uint32_t ht20:1; + uint32_t nonGf:1; + uint32_t lsigTxop:1; + uint32_t rifs:1; + uint32_t obss:1; /* added for Obss */ +} tCfgProtection, *tpCfgProtection; + +typedef enum eLimProtStaCacheType { + eLIM_PROT_STA_CACHE_TYPE_INVALID, + eLIM_PROT_STA_CACHE_TYPE_llB, + eLIM_PROT_STA_CACHE_TYPE_llG, + eLIM_PROT_STA_CACHE_TYPE_HT20 +} tLimProtStaCacheType; + +typedef struct sCacheParams { + uint8_t active; + tSirMacAddr addr; + tLimProtStaCacheType protStaCacheType; + +} tCacheParams, *tpCacheParams; + +#define LIM_PROT_STA_OVERLAP_CACHE_SIZE HAL_NUM_ASSOC_STA +#define LIM_PROT_STA_CACHE_SIZE HAL_NUM_ASSOC_STA + +typedef struct sLimProtStaParams { + uint8_t numSta; + uint8_t protectionEnabled; +} tLimProtStaParams, *tpLimProtStaParams; + +typedef struct sLimNoShortParams { + uint8_t numNonShortPreambleSta; + tCacheParams staNoShortCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortParams, *tpLimNoShortParams; + +typedef struct sLimNoShortSlotParams { + uint8_t numNonShortSlotSta; + tCacheParams staNoShortSlotCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortSlotParams, *tpLimNoShortSlotParams; + +typedef struct tLimIbssPeerNode tLimIbssPeerNode; +struct tLimIbssPeerNode { + tLimIbssPeerNode *next; + tSirMacAddr peerMacAddr; + uint8_t extendedRatesPresent:1; + uint8_t edcaPresent:1; + uint8_t wmeEdcaPresent:1; + uint8_t wmeInfoPresent:1; + uint8_t htCapable:1; + uint8_t vhtCapable:1; + uint8_t rsvd:2; + uint8_t htSecondaryChannelOffset; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + uint8_t supportedMCSSet[SIZE_OF_SUPPORTED_MCS_SET]; + tSirMacEdcaParamSetIE edcaParams; + uint8_t erpIePresent; + + /* HT Capabilities of IBSS Peer */ + uint8_t htGreenfield; + uint8_t htShortGI40Mhz; + uint8_t htShortGI20Mhz; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + + /* */ + /* A-MPDU Density */ + /* 000 - No restriction */ + /* 001 - 1/8 usec */ + /* 010 - 1/4 usec */ + /* 011 - 1/2 usec */ + /* 100 - 1 usec */ + /* 101 - 2 usec */ + /* 110 - 4 usec */ + /* 111 - 8 usec */ + /* */ + uint8_t htAMpduDensity; + + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + + /* */ + /* Recommended Tx Width Set */ + /* 0 - use 20 MHz channel (control channel) */ + /* 1 - use 40 Mhz channel */ + /* */ + uint8_t htSupportedChannelWidthSet; + + uint8_t htLdpcCapable; + + uint8_t beaconHBCount; + uint8_t heartbeatFailure; + + uint8_t *beacon; /* Hold beacon to be sent to HDD/CSR */ + uint16_t beaconLen; + +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps VHTCaps; + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtBeamFormerCapable; +#endif + /* + * Peer Atim Info + */ + uint8_t atimIePresent; + uint32_t peerAtimWindowLength; +}; + +/* Enums used for channel switching. */ +typedef enum eLimChannelSwitchState { + eLIM_CHANNEL_SWITCH_IDLE, + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY, + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY +} tLimChannelSwitchState; + +/* Channel Switch Info */ +typedef struct sLimChannelSwitchInfo { + tLimChannelSwitchState state; + uint8_t primaryChannel; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + phy_ch_width ch_width; + int8_t switchCount; + uint32_t switchTimeoutValue; + uint8_t switchMode; +} tLimChannelSwitchInfo, *tpLimChannelSwitchInfo; + +#ifdef WLAN_FEATURE_11AC +typedef struct sLimOperatingModeInfo { + uint8_t present; + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tLimOperatingModeInfo, *tpLimOperatingModeInfo; +#endif + +typedef struct sLimWiderBWChannelSwitch { + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tLimWiderBWChannelSwitchInfo, *tpLimWiderBWChannelSwitchInfo; + +/* Enums used when stopping the Tx. */ +typedef enum eLimQuietTxMode { + /* Stop/resume transmission of all stations,Uses the global flag */ + eLIM_TX_ALL = 0, + /* + * Stops/resumes the transmission of specific stations identified + * by staId. + */ + eLIM_TX_STA, + /* Stops/resumes the transmission of all the packets in BSS */ + eLIM_TX_BSS, + /* + * Stops/resumes the transmission of all packets except beacons in BSS + * This is used when radar is detected in the current operating channel. + * Beacon has to be sent to notify the stations associated about the + * scheduled channel switch + */ + eLIM_TX_BSS_BUT_BEACON +} tLimQuietTxMode; + +typedef enum eLimControlTx { + eLIM_RESUME_TX = 0, + eLIM_STOP_TX +} tLimControlTx; + +/* -------------------------------------------------------------------- */ + +typedef struct sLimTspecInfo { + /* 0==free, else used */ + uint8_t inuse; + /* index in list */ + uint8_t idx; + tSirMacAddr staAddr; + uint16_t assocId; + tSirMacTspecIE tspec; + /* number of Tclas elements */ + uint8_t numTclas; + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + /* tclassProc is valid only if this is set to 1. */ + uint8_t tclasProcPresent:1; +} cdf_packed tLimTspecInfo, *tpLimTspecInfo; + +typedef struct sLimAdmitPolicyInfo { + /* admit control policy type */ + uint8_t type; + /* oversubscription factor : 0 means nothing is allowed */ + uint8_t bw_factor; + /* valid only when 'type' is set BW_FACTOR */ +} tLimAdmitPolicyInfo, *tpLimAdmitPolicyInfo; + +typedef enum eLimWscEnrollState { + eLIM_WSC_ENROLL_NOOP, + eLIM_WSC_ENROLL_BEGIN, + eLIM_WSC_ENROLL_IN_PROGRESS, + eLIM_WSC_ENROLL_END +} tLimWscEnrollState; + +#define WSC_PASSWD_ID_PUSH_BUTTON (0x0004) + +typedef struct sLimWscIeInfo { + bool apSetupLocked; + bool selectedRegistrar; + uint16_t selectedRegistrarConfigMethods; + tLimWscEnrollState wscEnrollmentState; + tLimWscEnrollState probeRespWscEnrollmentState; + uint8_t reqType; + uint8_t respType; +} tLimWscIeInfo, *tpLimWscIeInfo; + +/* maximum number of tspec's supported */ +#define LIM_NUM_TSPEC_MAX 15 + +/* structure to hold all 11h specific data */ +typedef struct sLimSpecMgmtInfo { + tLimQuietStates quietState; + uint32_t quietCount; + /* This is in units of system TICKS */ + uint32_t quietDuration; + /* This is in units of TU, for over the air transmission */ + uint32_t quietDuration_TU; + /* After this timeout, actual quiet starts */ + uint32_t quietTimeoutValue; + /* Used on AP, if quiet is enabled during learning */ + bool fQuietEnabled; + tLimDot11hChanSwStates dot11hChanSwState; + /* Radar detected in cur oper chan on AP */ + bool fRadarDetCurOperChan; + /* Whether radar interrupt has been configured */ + bool fRadarIntrConfigured; +} tLimSpecMgmtInfo, *tpLimSpecMgmtInfo; + +#ifdef FEATURE_WLAN_TDLS +/* + * Peer info needed for TDLS setup.. + */ +typedef struct tLimTDLSPeerSta { + struct tLimTDLSPeerSta *next; + uint8_t dialog; + tSirMacAddr peerMac; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacQosCapabilityStaIE qosCaps; + tSirMacEdcaParamSetIE edcaParams; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t tdls_bIsResponder; + /* HT Capabilties */ + tDot11fIEHTCaps tdlsPeerHTCaps; + tDot11fIEExtCap tdlsPeerExtCaps; + uint8_t tdls_flags; + uint8_t tdls_link_state; + uint8_t tdls_prev_link_state; + uint8_t tdls_sessionId; + uint8_t ExtRatesPresent; + TX_TIMER gLimTdlsLinkSetupRspTimeoutTimer; + TX_TIMER gLimTdlsLinkSetupCnfTimeoutTimer; +} tLimTdlsLinkSetupPeer, *tpLimTdlsLinkSetupPeer; + +typedef struct tLimTdlsLinkSetupInfo { + tLimTdlsLinkSetupPeer *tdlsLinkSetupList; + uint8_t num_tdls_peers; + uint8_t tdls_flags; + uint8_t tdls_state; + uint8_t tdls_prev_state; +} tLimTdlsLinkSetupInfo, *tpLimTdlsLinkSetupInfo; + +typedef enum tdlsLinkMode { + TDLS_LINK_MODE_BG, + TDLS_LINK_MODE_N, + TDLS_LINK_MODE_AC, + TDLS_LINK_MODE_NONE +} eLimTdlsLinkMode; +#endif /* FEATURE_WLAN_TDLS */ + +#endif diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h new file mode 100644 index 0000000000..f027fa01a6 --- /dev/null +++ b/core/mac/src/pe/include/lim_session.h @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__LIM_SESSION_H) +#define __LIM_SESSION_H + +/**========================================================================= + + \file lim_session.h + + \brief prototype for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/* Powersave Offload Implementation */ +typedef enum ePowersaveState { + PMM_FULL_POWER, + PMM_POWER_SAVE +} tPowersaveState; + +/* Master Structure: This will be part of PE Session Entry */ +typedef struct sPowersaveoffloadInfo { + tPowersaveState psstate; + uint8_t bcnmiss; +} tPowersaveoffloadInfo, tpPowersaveoffloadInfo; + +#ifdef WLAN_FEATURE_11W +typedef struct tagComebackTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionID; + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimSmeStates limMlmState; /* MLM State */ +} tComebackTimerInfo; +#endif /* WLAN_FEATURE_11W */ +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define NUM_WEP_KEYS 4 + +/* Maximum allowable size of a beacon frame */ +#define SCH_MAX_BEACON_SIZE 512 + +#define SCH_MAX_PROBE_RESP_SIZE 512 +#define SCH_PROTECTION_RESET_TIME 4000 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct { + tSirMacBeaconInterval beaconInterval; + uint8_t fShortPreamble; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fRIFSMode; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t gHTObssMode; +} tBeaconParams, *tpBeaconParams; + +typedef struct sPESession /* Added to Support BT-AMP */ +{ + /* To check session table is in use or free */ + uint8_t available; + uint16_t peSessionId; + uint8_t smeSessionId; + uint16_t transactionId; + + /* In AP role: BSSID and selfMacAddr will be the same. */ + /* In STA role: they will be different */ + tSirMacAddr bssId; + tSirMacAddr selfMacAddr; + tSirMacSSid ssId; + uint8_t bssIdx; + uint8_t valid; + tLimMlmStates limMlmState; /* MLM State */ + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimSmeStates limSmeState; /* SME State */ + tLimSmeStates limPrevSmeState; /* Previous SME State */ + tLimSystemRole limSystemRole; + tSirBssType bssType; + uint8_t operMode; /* AP - 0; STA - 1 ; */ + tSirNwType nwType; + tpSirSmeStartBssReq pLimStartBssReq; /* handle to smestart bss req */ + tpSirSmeJoinReq pLimJoinReq; /* handle to sme join req */ + tpSirSmeJoinReq pLimReAssocReq; /* handle to sme reassoc req */ + tpLimMlmJoinReq pLimMlmJoinReq; /* handle to MLM join Req */ +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + void *pLimMlmReassocRetryReq; /* keep reasoc req for retry */ +#endif + void *pLimMlmReassocReq; /* handle to MLM reassoc Req */ + uint16_t channelChangeReasonCode; + uint8_t dot11mode; + uint8_t htCapability; + /* Supported Channel Width Set: 0-20MHz 1 - 40MHz */ + uint8_t htSupportedChannelWidthSet; + /* Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use channel width enabled under Supported Channel Width Set + */ + uint8_t htRecommendedTxWidthSet; + /* Identifies the 40 MHz extension channel */ + ePhyChanBondState htSecondaryChannelOffset; + tSirRFBand limRFBand; + uint8_t limIbssActive; /* TO SUPPORT CONCURRENCY */ + + /* These global varibales moved to session Table to support BT-AMP : Oct 9th review */ + tAniAuthType limCurrentAuthType; + uint16_t limCurrentBssCaps; + uint8_t limCurrentBssQosCaps; + uint16_t limCurrentBssPropCap; + uint8_t limSentCapsChangeNtf; + uint16_t limAID; + + /* Parameters For Reassociation */ + tSirMacAddr limReAssocbssId; + tSirMacChanNum limReassocChannelId; + /* CB paramaters required/duplicated for Reassoc since re-assoc mantains its own params in lim */ + uint8_t reAssocHtSupportedChannelWidthSet; + uint8_t reAssocHtRecommendedTxWidthSet; + ePhyChanBondState reAssocHtSecondaryChannelOffset; + tSirMacSSid limReassocSSID; + uint16_t limReassocBssCaps; + uint8_t limReassocBssQosCaps; + uint16_t limReassocBssPropCap; + + /* Assoc or ReAssoc Response Data/Frame */ + void *limAssocResponseData; + + /** BSS Table parameters **/ + + /* + * staId: Start BSS: this is the Sta Id for the BSS. + * Join: this is the selfStaId + * In both cases above, the peer STA ID wll be stored in dph hash table. + */ + uint16_t staId; + uint16_t statypeForBss; /* to know session is for PEER or SELF */ + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + tSirMacRateSet rateSet; + tSirMacRateSet extRateSet; + tSirMacHTOperatingMode htOperMode; + uint8_t currentOperChannel; + uint8_t currentReqChannel; + uint8_t LimRxedBeaconCntDuringHB; + + /* Time stamp of the last beacon received from the BSS to which STA is connected. */ + uint64_t lastBeaconTimeStamp; + /* RX Beacon count for the current BSS to which STA is connected. */ + uint32_t currentBssBeaconCnt; + uint8_t lastBeaconDtimCount; + uint8_t lastBeaconDtimPeriod; + + uint32_t bcnLen; + uint8_t *beacon; /* Used to store last beacon / probe response before assoc. */ + + uint32_t assocReqLen; + uint8_t *assocReq; /* Used to store association request frame sent out while associating. */ + + uint32_t assocRspLen; + uint8_t *assocRsp; /* Used to store association response received while associating */ + tAniSirDph dph; + void **parsedAssocReq; /* Used to store parsed assoc req from various requesting station */ +#ifdef WLAN_FEATURE_VOWIFI_11R + uint32_t RICDataLen; /* Used to store the Ric data received in the assoc response */ + uint8_t *ricData; +#endif +#ifdef FEATURE_WLAN_ESE + uint32_t tspecLen; /* Used to store the TSPEC IEs received in the assoc response */ + uint8_t *tspecIes; +#endif + uint32_t encryptType; + + bool bTkipCntrMeasActive; /* Used to keep record of TKIP counter measures start/stop */ + + uint8_t gLimProtectionControl; /* used for 11n protection */ + + uint8_t gHTNonGFDevicesPresent; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + /* Number of legacy STAs associated */ + tLimProtStaParams gLim11bParams; + + /* Number of 11A STAs associated */ + tLimProtStaParams gLim11aParams; + + /* Number of non-ht non-legacy STAs associated */ + tLimProtStaParams gLim11gParams; + + /* Number of nonGf STA associated */ + tLimProtStaParams gLimNonGfParams; + + /* Number of HT 20 STAs associated */ + tLimProtStaParams gLimHt20Params; + + /* Number of Lsig Txop not supported STAs associated */ + tLimProtStaParams gLimLsigTxopParams; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOlbcParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOverlap11gParams; + + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + /* cache for each overlap */ + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + uint8_t privacy; + tAniAuthType authType; + tSirKeyMaterial WEPKeyMaterial[NUM_WEP_KEYS]; + + tDot11fIERSN gStartBssRSNIe; + tDot11fIEWPA gStartBssWPAIe; + tSirAPWPSIEs APWPSIEs; + uint8_t apUapsdEnable; + tSirWPSPBCSession *pAPWPSPBCSession; + uint32_t DefProbeRspIeBitmap[8]; + uint32_t proxyProbeRspEn; + tDot11fProbeResponse probeRespFrame; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + uint8_t wps_state; + + uint8_t limQosEnabled:1; /* 11E */ + uint8_t limWmeEnabled:1; /* WME */ + uint8_t limWsmEnabled:1; /* WSM */ + uint8_t limHcfEnabled:1; + uint8_t lim11dEnabled:1; +#ifdef WLAN_FEATURE_11W + uint8_t limRmfEnabled:1; /* 11W */ +#endif + uint32_t lim11hEnable; + + tPowerdBm maxTxPower; /* MIN (Regulatory and local power constraint) */ + tCDF_CON_MODE pePersona; +#if defined WLAN_FEATURE_VOWIFI + tPowerdBm txMgmtPower; +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + tAniBool is11Rconnection; +#endif + +#ifdef FEATURE_WLAN_ESE + tAniBool isESEconnection; + tEsePEContext eseContext; +#endif +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + tAniBool isFastTransitionEnabled; +#endif +#ifdef FEATURE_WLAN_LFR + tAniBool isFastRoamIniFeatureEnabled; +#endif + tSirNoAParam p2pNoA; + tSirP2PNoaAttr p2pGoPsUpdate; + uint32_t defaultAuthFailureTimeout; + tSirP2PNoaStart p2pGoPsNoaStartInd; + + /* EDCA QoS parameters + * gLimEdcaParams - These EDCA parameters are used locally on AP or STA. + * If STA, then these are values taken from the Assoc Rsp when associating, + * or Beacons/Probe Response after association. If AP, then these are + * values originally set locally on AP. + * + * gLimEdcaParamsBC - These EDCA parameters are use by AP to broadcast + * to other STATIONs in the BSS. + * + * gLimEdcaParamsActive: These EDCA parameters are what's actively being + * used on station. Specific AC values may be downgraded depending on + * admission control for that particular AC. + */ + tSirMacEdcaParamRecord gLimEdcaParams[MAX_NUM_AC]; /* used locally */ + tSirMacEdcaParamRecord gLimEdcaParamsBC[MAX_NUM_AC]; /* used for broadcast */ + tSirMacEdcaParamRecord gLimEdcaParamsActive[MAX_NUM_AC]; + + uint8_t gLimEdcaParamSetCount; + + tBeaconParams beaconParams; + uint8_t vhtCapability; + uint8_t vhtTxChannelWidthSet; + tLimOperatingModeInfo gLimOperatingMode; + uint8_t vhtCapabilityPresentInBeacon; + uint8_t ch_center_freq_seg0; + phy_ch_width ch_width; + uint8_t ch_center_freq_seg1; + uint8_t txBFIniFeatureEnabled; + uint8_t txMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enable_su_tx_bformer; + tLimWiderBWChannelSwitchInfo gLimWiderBWChannelSwitch; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsvalue; + uint8_t spectrumMgtEnabled; + /* *********************11H related**************************** */ + tLimSpecMgmtInfo gLimSpecMgmt; + /* CB Primary/Secondary Channel Switch Info */ + tLimChannelSwitchInfo gLimChannelSwitch; + /* *********************End 11H related**************************** */ + + /*Flag to Track Status/Indicate HBFailure on this session */ + bool LimHBFailureStatus; + uint32_t gLimPhyMode; + uint8_t amsduSupportedInBA; + uint8_t txLdpcIniFeatureEnabled; + /** + * Following is the place holder for free peer index pool. + * A non-zero value indicates that peer index is available + * for assignment. + */ + uint8_t *gpLimPeerIdxpool; + uint8_t freePeerIdxHead; + uint8_t freePeerIdxTail; + uint16_t gLimNumOfCurrentSTAs; +#ifdef FEATURE_WLAN_TDLS + uint32_t peerAIDBitmap[2]; + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; +#endif + bool fWaitForProbeRsp; + bool fIgnoreCapsChange; + bool fDeauthReceived; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + int8_t rssi; +#endif + uint8_t isAmsduSupportInAMPDU; + uint8_t isCoalesingInIBSSAllowed; + + tSirHTConfig htConfig; + + /* + * Place holder for StartBssReq message + * received by SME state machine + */ + uint8_t gLimCurrentBssUapsd; + + /* Used on STA, this is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. If a + * particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + */ + uint8_t gUapsdPerAcBitmask; + + /* Used on STA, this is a dynamic UPASD mask setting + * derived from AddTS Rsp and DelTS frame. If a + * particular AC bit is set, it means AC is trigger + * enabled. + */ + uint8_t gUapsdPerAcTriggerEnableMask; + + /* Used on STA, dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. If + * a particular AC bit is set, it means AC is + * delivery enabled. + */ + uint8_t gUapsdPerAcDeliveryEnableMask; + + /* Flag to skip CSA IE processing when CSA + * offload is enabled. + */ + uint8_t csaOffloadEnable; + + /* Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That partiular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* Power Save Off load Parameters */ + tPowersaveoffloadInfo pmmOffloadInfo; + /* SMPS mode */ + uint8_t smpsMode; + + uint8_t chainMask; + + /* Flag to indicate Chan Sw announcement is required */ + uint8_t dfsIncludeChanSwIe; + + /* Flag to indicate Chan Wrapper Element is required */ + uint8_t dfsIncludeChanWrapperIe; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + + bool isCiscoVendorAP; + + tSirAddIeParams addIeParams; + + uint8_t *pSchProbeRspTemplate; + /* Beginning portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameBegin; + /* Trailing portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameEnd; + /* Size of the beginning portion */ + uint16_t schBeaconOffsetBegin; + /* Size of the trailing portion */ + uint16_t schBeaconOffsetEnd; + bool isOSENConnection; + /* DSCP to UP mapping for HS 2.0 */ + tSirQosMapSet QosMapSet; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool bRoamSynchInProgress; +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R + /* Fast Transition (FT) */ + tftPEContext ftPEContext; +#endif + bool isNonRoamReassoc; +#ifdef WLAN_FEATURE_11W + cdf_mc_timer_t pmfComebackTimer; + tComebackTimerInfo pmfComebackTimerInfo; +#endif /* WLAN_FEATURE_11W */ + uint8_t is_key_installed; + /* timer for reseting protection fileds at regular intervals */ + cdf_mc_timer_t protection_fields_reset_timer; + void *mac_ctx; + /* + * variable to store state of various protection struct like + * gLimOlbcParams, gLimOverlap11gParams, gLimOverlapHt20Params etc + */ + uint16_t old_protection_state; + tSirMacAddr prev_ap_bssid; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* tells if Q2Q IE, from another MDM device in AP MCC mode was recvd */ + bool sap_advertise_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_version_ie_present; +#endif + uint8_t sap_dot11mc; + bool is_vendor_specific_vhtcaps; + uint8_t vendor_specific_vht_ie_type; + uint8_t vendor_specific_vht_ie_sub_type; + /* flag to indicate country code in beacon */ + uint8_t country_info_present; + uint8_t nss; +} tPESession, *tpPESession; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/** + * pe_create_session() - creates a new PE session given the BSSID + * + * @pMac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * @numSta: number of stations + * @bssType: bss type of new session to do conditional memory allocation. + * + * This function returns the session context and the session ID if the session + * corresponding to the passed BSSID is found in the PE session table. + * + * Return: ptr to the session context or NULL if session can not be created. + */ +tpPESession pe_create_session(tpAniSirGlobal pMac, + uint8_t *bssid, + uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType); + +/** + * pe_find_session_by_bssid() - looks up the PE session given the BSSID. + * + * @pMac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * + * This function returns the session context and the session ID if the session + * corresponding to the given BSSID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId); + +/** + * pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + * + * @pMac: pointer to global adapter context + * @bssIdx: bss index of the session + * + * This function returns the session context if the session + * corresponding to the given bssIdx is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx); + +/** + * pe_find_session_by_peer_sta() - looks up the PE session given the Peer + * Station Address. + * + * @pMac: pointer to global adapter context + * @sa: Peer STA Address of the session + * @sessionId: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given destination address is found in the PE session + * table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId); + +/** + * pe_find_session_by_session_id() - looks up the PE session given the session + * ID. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID for which session context needs to be looked up. + * + * This function returns the session context if the session corresponding to + * the given session ID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, + uint8_t sessionId); + +/** + * pe_find_session_by_bssid() - looks up the PE session given staid. + * + * @pMac: pointer to global adapter context + * @staid: StaId of the session + * @sessionId: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given StaId is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_sta_id(tpAniSirGlobal pMac, uint8_t staid, + uint8_t *sessionId); + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID to delete. + * + * Return: void + */ +void pe_delete_session(tpAniSirGlobal pMac, tpPESession psessionEntry); + + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_id); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx); +#endif /* #if !defined( __LIM_SESSION_H ) */ diff --git a/core/mac/src/pe/include/lim_trace.h b/core/mac/src/pe/include/lim_trace.h new file mode 100644 index 0000000000..494edc8703 --- /dev/null +++ b/core/mac/src/pe/include/lim_trace.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + * \file lim_trace.h + + * \brief definition for trace related APIs + + * \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __LIM_TRACE_H +#define __LIM_TRACE_H + +#include "lim_global.h" +#include "mac_trace.h" +#include "cdf_trace.h" +#ifdef LIM_TRACE_RECORD + +#define LIM_TRACE_GET_SSN(data) (((data) >> 16) & 0xff) +#define LIM_TRACE_GET_SUBTYPE(data) (data & 0xff) +#define LIM_TRACE_GET_DEFERRED(data) (data & 0x80000000) +#define LIM_TRACE_GET_DEFRD_OR_DROPPED(data) (data & 0xc0000000) + +#define LIM_MSG_PROCESSED 0 +#define LIM_MSG_DEFERRED 1 +#define LIM_MSG_DROPPED 2 + +#define LIM_TRACE_MAKE_RXMGMT(type, ssn) \ + ((ssn << 16) | (type)) +#define LIM_TRACE_MAKE_RXMSG(msg, action) \ + ((msg) | (action << 30)) + +enum { + TRACE_CODE_MLM_STATE, + TRACE_CODE_SME_STATE, + TRACE_CODE_TX_MGMT, + TRACE_CODE_RX_MGMT, + TRACE_CODE_RX_MGMT_TSF, + TRACE_CODE_TX_COMPLETE, + TRACE_CODE_TX_SME_MSG, + TRACE_CODE_RX_SME_MSG, + TRACE_CODE_TX_WMA_MSG, + TRACE_CODE_RX_WMA_MSG, + TRACE_CODE_TX_LIM_MSG, + TRACE_CODE_RX_LIM_MSG, + TRACE_CODE_TX_CFG_MSG, + TRACE_CODE_RX_CFG_MSG, + TRACE_CODE_RX_MGMT_DROP, + + TRACE_CODE_TIMER_ACTIVATE, + TRACE_CODE_TIMER_DEACTIVATE, + TRACE_CODE_INFO_LOG +}; + +void lim_trace_init(tpAniSirGlobal pMac); +void limTraceReset(tpAniSirGlobal pMac); +void limTraceUpdateMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +void lim_trace_dumpMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState); +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState); +void lim_trace_dump(tpAniSirGlobal pMac, tp_cdf_trace_record pRecord, + uint16_t recIndex); +void mac_trace_msg_tx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); +void mac_trace_msg_rx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); + +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +#endif /* endof LIM_TRACE_RECORD MACRO */ + +#endif diff --git a/core/mac/src/pe/include/rrm_api.h b/core/mac/src/pe/include/rrm_api.h new file mode 100644 index 0000000000..05466c0042 --- /dev/null +++ b/core/mac/src/pe/include/rrm_api.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file rrm_api.h + + \brief RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#ifndef __RRM_API_H__ +#define __RRM_API_H__ + +#define RRM_MIN_TX_PWR_CAP 13 +#define RRM_MAX_TX_PWR_CAP 19 + +#define RRM_BCN_RPT_NO_BSS_INFO 0 +#define RRM_BCN_RPT_MIN_RPT 1 + +uint8_t rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, tPowerdBm regMax, + tPowerdBm apTxPower); + +extern tSirRetStatus rrm_initialize(tpAniSirGlobal pMac); + +extern tSirRetStatus rrm_cleanup(tpAniSirGlobal pMac); + +extern tSirRetStatus rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest + *pLinkReq, + tpPESession + pSessionEntry); + +extern tSirRetStatus rrm_process_radio_measurement_request(tpAniSirGlobal pMac, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest + *pRRMReq, + tpPESession + pSessionEntry); + +extern tSirRetStatus rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse + *pNeighborRep, + tpPESession + pSessionEntry); + +extern void rrm_process_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg); + +extern tSirRetStatus rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, + tPowerdBm txPower, + tpPESession pSessionEntry); + +extern tPowerdBm rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +extern void rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, + tPowerdBm txPower, tpPESession pSessionEntry); + +extern tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +extern void rrm_update_config(tpAniSirGlobal pMac, tpPESession pSessionEntry); + +extern void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF); + +extern void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]); + +extern tSirRetStatus rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ); + +extern tSirRetStatus +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq); +extern tSirRetStatus +rrm_process_beacon_report_xmit(tpAniSirGlobal pMac, + tpSirBeaconReportXmitInd pBcnReport); +#endif diff --git a/core/mac/src/pe/include/rrm_global.h b/core/mac/src/pe/include/rrm_global.h new file mode 100644 index 0000000000..053848d1f0 --- /dev/null +++ b/core/mac/src/pe/include/rrm_global.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__RRMGLOBAL_H) +#define __RRMGLOBAL_H + +/**========================================================================= + + \file rrm_global.h + + \brief Definitions for SME APIs + + ========================================================================*/ + +typedef enum eRrmRetStatus { + eRRM_SUCCESS, + eRRM_INCAPABLE, + eRRM_REFUSED, + eRRM_FAILURE +} tRrmRetStatus; + +typedef enum eRrmMsgReqSource { + eRRM_MSG_SOURCE_LEGACY_ESE = 1, /* legacy ese */ + eRRM_MSG_SOURCE_11K = 2, /* 11k */ + eRRM_MSG_SOURCE_ESE_UPLOAD = 3, /* ese upload approach */ +} tRrmMsgReqSource; + +typedef struct sSirChannelInfo { + uint8_t regulatoryClass; + uint8_t channelNum; +} tSirChannelInfo, *tpSirChannelInfo; + +typedef struct sSirBeaconReportReqInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_REQ_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t measurementDuration[SIR_ESE_MAX_MEAS_IE_REQS]; /* ms */ + uint16_t randomizationInterval; /* ms */ + tSirChannelInfo channelInfo; + /* 0: wildcard */ + tSirMacAddr macaddrBssid; + /* 0:Passive, 1: Active, 2: table mode */ + uint8_t fMeasurementtype[SIR_ESE_MAX_MEAS_IE_REQS]; + tAniSSID ssId; /* May be wilcard. */ + uint16_t uDialogToken; + tSirChannelList channelList; /* From AP channel report. */ + tRrmMsgReqSource msgSource; +} tSirBeaconReportReqInd, *tpSirBeaconReportReqInd; + +typedef struct sSirBeaconReportXmitInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_RESP_XMIT_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t uDialogToken; + uint8_t fMeasureDone; + uint16_t duration; + uint8_t regClass; + uint8_t numBssDesc; + tpSirBssDescription pBssDescription[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirBeaconReportXmitInd, *tpSirBeaconReportXmitInd; + +typedef struct sSirNeighborReportReqInd { + /* eWNI_SME_NEIGHBOR_REPORT_REQ_IND */ + uint16_t messageType; + uint16_t length; + /* For the session. */ + tSirMacAddr bssId; + /* true - dont include SSID in the request. */ + uint16_t noSSID; + /* false include the SSID. It may be null (wildcard) */ + tSirMacSSid ucSSID; +} tSirNeighborReportReqInd, *tpSirNeighborReportReqInd; + +typedef struct sSirNeighborBssDescription { + uint16_t length; + tSirMacAddr bssId; + uint8_t regClass; + uint8_t channel; + uint8_t phyType; + union sSirNeighborBssidInfo { + struct _rrmInfo { + /* see IEEE 802.11k Table 7-43a */ + uint32_t fApPreauthReachable:2; + uint32_t fSameSecurityMode:1; + uint32_t fSameAuthenticator:1; + /* see IEEE 802.11k Table 7-95d */ + uint32_t fCapSpectrumMeasurement:1; + uint32_t fCapQos:1; + uint32_t fCapApsd:1; + uint32_t fCapRadioMeasurement:1; + uint32_t fCapDelayedBlockAck:1; + uint32_t fCapImmediateBlockAck:1; + uint32_t fMobilityDomain:1; + uint32_t reserved:21; + } rrmInfo; + struct _eseInfo { + uint32_t channelBand:8; + uint32_t minRecvSigPower:8; + uint32_t apTxPower:8; + uint32_t roamHysteresis:8; + uint32_t adaptScanThres:8; + + uint32_t transitionTime:8; + uint32_t tsfOffset:16; + + uint32_t beaconInterval:16; + uint32_t reserved:16; + } eseInfo; + } bssidInfo; + + /* Optional sub IEs....ignoring for now. */ +} tSirNeighborBssDescription, *tpSirNeighborBssDescripton; + +typedef struct sSirNeighborReportInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_REPORT_IND */ + uint16_t length; + uint8_t sessionId; + uint16_t numNeighborReports; + tSirMacAddr bssId; /* For the session. */ + tSirNeighborBssDescription sNeighborBssDescription[1]; +} tSirNeighborReportInd, *tpSirNeighborReportInd; + +typedef struct sRRMBeaconReportRequestedIes { + uint8_t num; + uint8_t *pElementIds; +} tRRMBeaconReportRequestedIes, *tpRRMBeaconReportRequestedIes; + +/* Reporting detail defines. */ +/* Reference - IEEE Std 802.11k-2008 section 7.3.2.21.6 Table 7-29h */ +#define BEACON_REPORTING_DETAIL_NO_FF_IE 0 +#define BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE 1 +#define BEACON_REPORTING_DETAIL_ALL_FF_IE 2 + +typedef struct sRRMReq { + uint8_t dialog_token; /* In action frame; */ + uint8_t token; /* Within individual request; */ + uint8_t type; + union { + struct { + uint8_t reportingDetail; + tRRMBeaconReportRequestedIes reqIes; + } Beacon; + } request; + uint8_t sendEmptyBcnRpt; +} tRRMReq, *tpRRMReq; + +typedef struct sRRMCaps { + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatingChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tRRMCaps, *tpRRMCaps; + +typedef struct sRrmPEContext { + uint8_t rrmEnable; + /* + * Used during scan/measurement to store the start TSF. + * this is not used directly in beacon reports. + */ + uint32_t startTSF[2]; + /* + * This value is stored into bssdescription and beacon report + * gets it from bss decsription. + */ + tRRMCaps rrmEnabledCaps; + tPowerdBm txMgmtPower; + /* Dialog token for the request initiated from station. */ + uint8_t DialogToken; + tpRRMReq pCurrentReq; +} tRrmPEContext, *tpRrmPEContext; + +/* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ +#define RCPI_LOW_RSSI_VALUE (-110) +#define RCPI_MAX_VALUE (220) +#define CALCULATE_RCPI(rssi) (((rssi) + 110) * 2) + +#endif /* #if defined __RRMGLOBAL_H */ diff --git a/core/mac/src/pe/include/sch_api.h b/core/mac/src/pe/include/sch_api.h new file mode 100644 index 0000000000..04db805e19 --- /dev/null +++ b/core/mac/src/pe/include/sch_api.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_API_H__ +#define __SCH_API_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +/* / Send start scan response message */ +extern void sch_send_start_scan_rsp(tpAniSirGlobal pMac); + +/* update only the broadcast qos params */ +extern void sch_qos_update_broadcast(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* fill in the default local edca parameter into gLimEdcaParams[] */ +extern void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionE); + +/* update only local qos params */ +extern void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry); + +/* update the edca profile parameters */ +extern void sch_edca_profile_update(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Set the fixed fields in a beacon frame */ +extern tSirRetStatus sch_set_fixed_beacon_fields(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Initialize globals */ +extern void sch_init_globals(tpAniSirGlobal pMac); + +/* / Initialize CF Poll template */ +extern void sch_initializeCfPollTemplate(tpAniSirGlobal pMac); + +/* / Initialize CF End template */ +extern void sch_initializeCfEndTemplate(tpAniSirGlobal pMac); + +/* / Process the scheduler messages */ +extern void sch_process_message(tpAniSirGlobal pMac, tpSirMsgQ pSchMsg); + +/* / The beacon Indication handler function */ +extern void sch_process_pre_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg); + +/* / Post a message to the scheduler message queue */ +extern tSirRetStatus sch_post_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg); + +extern void sch_beacon_process(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry); +extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, + tpPESession psessionEntry); + +void sch_generate_tim(tpAniSirGlobal, uint8_t **, uint16_t *, uint8_t); +#define SCH_RR_TIMEOUT (SCH_RR_TIMEOUT_MS / SYS_TICK_DUR_MS) + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry); + +tSirRetStatus sch_send_beacon_req(tpAniSirGlobal, uint8_t *, uint16_t, + tpPESession psessionEntry); + +tSirRetStatus lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal, + tDot11fBeacon1 *, + tpPESession + psessionEntry); +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal, tDot11fBeacon2 *, + uint32_t *, + tDot11fProbeResponse *); +void set_probe_rsp_ie_bitmap(uint32_t *, uint32_t); +uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal, tpPESession, uint32_t *); + +int sch_gen_timing_advert_frame(tpAniSirGlobal pMac, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset); + +#endif diff --git a/core/mac/src/pe/include/sch_global.h b/core/mac/src/pe/include/sch_global.h new file mode 100644 index 0000000000..baebe98f96 --- /dev/null +++ b/core/mac/src/pe/include/sch_global.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_GLOBAL_H__ +#define __SCH_GLOBAL_H__ + +#include "sir_mac_prop_exts.h" +#include "lim_global.h" + +#include "parser_api.h" + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define TIM_IE_SIZE 0xB +#else +#define TIM_IE_SIZE 0x7 +#endif + +/* ----------------------- Beacon processing ------------------------ */ + +/* / Beacon structure */ +#define tSchBeaconStruct tSirProbeRespBeacon +#define tpSchBeaconStruct struct sSirProbeRespBeacon * + +/* ------------------------------------------------------------------- */ + +/* ****************** MISC defs ********************************* */ + +struct schMisc { + uint16_t gSchBeaconInterval; + + /* / Current CFP count */ + uint8_t gSchCFPCount; + + /* / CFP Duration remaining */ + uint8_t gSchCFPDurRemaining; + + /* / CFP Maximum Duration */ + uint8_t gSchCFPMaxDuration; + + /* / Current DTIM count */ + uint8_t gSchDTIMCount; + + /* / Whether we have initiated a CFP or not */ + uint8_t gSchCFPInitiated; + + /* / Whether we have initiated a CFB or not */ + uint8_t gSchCFBInitiated; + + /* / CFP is enabled and AP is configured as HCF */ + uint8_t gSchCFPEnabled; + + /* / CFB is enabled and AP is configured as HCF */ + uint8_t gSchCFBEnabled; + + /* --------- STA ONLY state ----------- */ + + /* / Indicates whether RR timer is running or not */ + uint8_t rrTimer[8]; + + /* / Indicates the remaining RR timeout value if the RR timer is running */ + uint16_t rrTimeout[8]; + + /* / Number of RRs transmitted */ + uint16_t numRR[8]; + uint16_t numRRtimeouts[8]; + + /* / flag to indicate that beacon template has been updated */ + uint8_t fBeaconChanged; + + uint16_t p2pIeOffset; + +}; + +/* ****************** MISC defs ********************************* */ + +typedef struct schStaWaitList { + uint16_t staId; + uint16_t count; +} tStaWaitList, *tpStaWaitList; + +/* / Global SCH structure */ +typedef struct sAniSirSch { + /* / The scheduler object */ + struct schMisc schObject; + + /* schQoSClass unsolicited; */ + + /* / Whether HCF is enabled or not */ + uint8_t gSchHcfEnabled; + + /* / Whether scan is requested by LIM or not */ + uint8_t gSchScanRequested; + + /* / Whether scan request is received by SCH or not */ + uint8_t gSchScanReqRcvd; + + /* / Debug flag to disable beacon generation */ + uint32_t gSchGenBeacon; + +#define SCH_MAX_ARR 100 + uint32_t gSchBeaconsWritten; + uint32_t gSchBeaconsSent; + uint32_t gSchBBXportRcvCnt; + uint32_t gSchRRRcvCnt, qosNullCnt; + uint32_t gSchBcnRcvCnt; + uint32_t gSchUnknownRcvCnt; + + uint32_t gSchBcnParseErrorCnt; + uint32_t gSchBcnIgnored; + + uint32_t numPoll, numData, numCorrupt; + uint32_t numBogusInt, numTxAct0; + +#define SCH_MAX_NUM_SCH 21 + uint32_t lastBeaconLength; + uint16_t rrTimeout; + uint32_t pollPeriod; + uint32_t multipleSched; + uint32_t pollFeedbackHist[8]; + uint32_t dataFeedbackHist[8]; + uint32_t maxPollTimeouts; + uint32_t checkCfbFlagStuck; + + /* / Sta Wait list */ + tpStaWaitList pStaWaitList; + + /* / Pointer to next available entry in sta wait list */ + uint16_t staWaitListIn; + /* / Pointer to first waiting sta in sta wait list */ + uint16_t staWaitListOut; + /* / Total number of waiting STAs in sta wait list */ + uint16_t staWaitListCount; + /* / Total number of schedules to be waited */ + uint16_t staWaitListTotalWait; + + /* / Number of entries in DPH activity queue that were ignored */ + uint32_t ignoreDph; + +} tAniSirSch, *tpAniSirSch; + +#endif diff --git a/core/mac/src/pe/include/wmm_apsd.h b/core/mac/src/pe/include/wmm_apsd.h new file mode 100644 index 0000000000..9b5d5d4aff --- /dev/null +++ b/core/mac/src/pe/include/wmm_apsd.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WMMAPSD_H__ +#define __WMMAPSD_H__ + +#include "ani_global.h" + +/* UAPSD Flag for each AC (WMM spec 2.2.1) */ +#define LIM_UAPSD_BITOFFSET_ACVO 0 +#define LIM_UAPSD_BITOFFSET_ACVI 1 +#define LIM_UAPSD_BITOFFSET_ACBK 2 +#define LIM_UAPSD_BITOFFSET_ACBE 3 + +#define LIM_UAPSD_FLAG_ACVO (1 << LIM_UAPSD_BITOFFSET_ACVO) +#define LIM_UAPSD_FLAG_ACVI (1 << LIM_UAPSD_BITOFFSET_ACVI) +#define LIM_UAPSD_FLAG_ACBK (1 << LIM_UAPSD_BITOFFSET_ACBK) +#define LIM_UAPSD_FLAG_ACBE (1 << LIM_UAPSD_BITOFFSET_ACBE) + +#define LIM_UAPSD_GET(ac, mask) (((mask) & (LIM_UAPSD_FLAG_ ## ac)) >> LIM_UAPSD_BITOFFSET_ ## ac) + +/* Definition for setting/clearing Uapsd Mask */ +#define SET_UAPSD_MASK 1 +#define CLEAR_UAPSD_MASK 0 + +#endif /* __WMMAPSD_H__ */ diff --git a/core/mac/src/pe/lim/lim_admit_control.c b/core/mac/src/pe/lim/lim_admit_control.c new file mode 100644 index 0000000000..b217c402ee --- /dev/null +++ b/core/mac/src/pe/lim/lim_admit_control.c @@ -0,0 +1,1140 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains TSPEC and STA admit control related functions + * NOTE: applies only to AP builds + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "lim_debug.h" +#include "sys_def.h" +#include "lim_api.h" +#include "cfg_api.h" /* wlan_cfg_get_int() */ +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_types.h" + +#define ADMIT_CONTROL_LOGLEVEL LOG1 +#define ADMIT_CONTROL_POLICY_LOGLEVEL LOG1 + +/* total available bandwidth in bps in each phy mode + * these should be defined in hal or dph - replace these later + */ +#define LIM_TOTAL_BW_11A 54000000 +#define LIM_MIN_BW_11A 6000000 +#define LIM_TOTAL_BW_11B 11000000 +#define LIM_MIN_BW_11B 1000000 +#define LIM_TOTAL_BW_11G LIM_TOTAL_BW_11A +#define LIM_MIN_BW_11G LIM_MIN_BW_11B + +/* conversion factors */ +#define LIM_CONVERT_SIZE_BITS(numBytes) ((numBytes) * 8) +#define LIM_CONVERT_RATE_MBPS(rate) ((rate)/1000000) + +/* ------------------------------------------------------------------------------ */ +/* local protos */ + +static tSirRetStatus +lim_calculate_svc_int(tpAniSirGlobal, tSirMacTspecIE *, uint32_t *); +static tSirRetStatus +lim_validate_tspec_edca(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static tSirRetStatus +lim_validate_tspec(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static void +lim_compute_mean_bw_used(tpAniSirGlobal, uint32_t *, uint32_t, tpLimTspecInfo, + tpPESession); +static void lim_get_available_bw(tpAniSirGlobal, uint32_t *, uint32_t *, uint32_t, + uint32_t); +static tSirRetStatus lim_admit_policy_oversubscription(tpAniSirGlobal, + tSirMacTspecIE *, + tpLimAdmitPolicyInfo, + tpLimTspecInfo, + tpPESession); +static tSirRetStatus lim_tspec_find_by_sta_addr(tpAniSirGlobal, uint8_t *, + tSirMacTspecIE *, tpLimTspecInfo, + tpLimTspecInfo *); +static tSirRetStatus lim_validate_access_policy(tpAniSirGlobal, uint8_t, uint16_t, + tpPESession); + +/** ------------------------------------------------------------- + \fn lim_calculate_svc_int + \brief TSPEC validation and servcie interval determination + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \param uint32_t *pSvcInt + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_calculate_svc_int(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, uint32_t *pSvcInt) +{ + uint32_t msduSz, dataRate; + *pSvcInt = 0; + + /* if a service interval is already specified, we are done */ + if ((pTspec->minSvcInterval != 0) || (pTspec->maxSvcInterval != 0)) { + *pSvcInt = (pTspec->maxSvcInterval != 0) + ? pTspec->maxSvcInterval : pTspec->minSvcInterval; + return eSIR_SUCCESS; + } + + /* Masking off the fixed bits according to definition of MSDU size + * in IEEE 802.11-2007 spec (section 7.3.2.30). Nominal MSDU size + * is defined as: Bit[0:14]=Size, Bit[15]=Fixed + */ + if (pTspec->nomMsduSz != 0) + msduSz = (pTspec->nomMsduSz & 0x7fff); + else if (pTspec->maxMsduSz != 0) + msduSz = pTspec->maxMsduSz; + else { + PELOGE(lim_log(pMac, LOGE, FL("MsduSize not specified"));) + return eSIR_FAILURE; + } + + /* need to calculate a reasonable service interval + * this is simply the msduSz/meanDataRate + */ + if (pTspec->meanDataRate != 0) + dataRate = pTspec->meanDataRate; + else if (pTspec->peakDataRate != 0) + dataRate = pTspec->peakDataRate; + else if (pTspec->minDataRate != 0) + dataRate = pTspec->minDataRate; + else { + PELOGE(lim_log(pMac, LOGE, FL("DataRate not specified"));) + return eSIR_FAILURE; + } + + *pSvcInt = + LIM_CONVERT_SIZE_BITS(msduSz) / LIM_CONVERT_RATE_MBPS(dataRate); + return eSIR_FAILURE; +} + +/** + * lim_validate_tspec_edca() - Validate the parameters + * @mac_ctx: Global MAC context + * @tspec: Pointer to the TSPEC + * @session_entry: Session Entry + * + * validate the parameters in the edca tspec + * mandatory fields are derived from 11e Annex I (Table I.1) + * + * Return: Status + **/ +static tSirRetStatus +lim_validate_tspec_edca(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, tpPESession session_entry) +{ + uint32_t max_phy_rate, min_phy_rate; + uint32_t phy_mode; + tSirRetStatus retval = eSIR_SUCCESS; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_get_available_bw(mac_ctx, &max_phy_rate, &min_phy_rate, phy_mode, + 1 /* bandwidth mult factor */); + /* mandatory fields are derived from 11e Annex I (Table I.1) */ + if ((tspec->nomMsduSz == 0) || + (tspec->meanDataRate == 0) || + (tspec->surplusBw == 0) || + (tspec->minPhyRate == 0) || + (tspec->minPhyRate > max_phy_rate)) { + lim_log(mac_ctx, LOGW, + FL + ("Invalid EDCA Tspec: NomMsdu %d, meanDataRate %d, surplusBw %d, min_phy_rate %d"), + tspec->nomMsduSz, tspec->meanDataRate, + tspec->surplusBw, tspec->minPhyRate); + retval = eSIR_FAILURE; + } + + lim_log(mac_ctx, ADMIT_CONTROL_LOGLEVEL, + FL("return status %d"), retval); + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_validate_tspec + \brief validate the offered tspec + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_validate_tspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_SUCCESS; + switch (pTspec->tsinfo.traffic.accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + retval = lim_validate_tspec_edca(pMac, pTspec, psessionEntry); + if (retval != eSIR_SUCCESS) + PELOGW(lim_log(pMac, LOGW, FL("EDCA tspec invalid"));) + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + /* TBD: should we support hybrid tspec as well?? for now, just fall through */ + default: + lim_log(pMac, LOGW, FL("AccessType %d not supported"), + pTspec->tsinfo.traffic.accessPolicy); + retval = eSIR_FAILURE; + break; + } + return retval; +} + +/* ----------------------------------------------------------------------------- */ +/* Admit Control Policy */ + +/** ------------------------------------------------------------- + \fn lim_compute_mean_bw_used + \brief determime the used/allocated bandwidth + \param tpAniSirGlobal pMac + \param uint32_t *pBw + \param uint32_t phyMode + \param tpLimTspecInfo pTspecInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static void +lim_compute_mean_bw_used(tpAniSirGlobal pMac, + uint32_t *pBw, + uint32_t phyMode, + tpLimTspecInfo pTspecInfo, tpPESession psessionEntry) +{ + uint32_t ctspec; + *pBw = 0; + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (pTspecInfo->inuse) { + tpDphHashNode pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + /* maybe we should delete the tspec?? */ + lim_log(pMac, LOGE, + FL + ("Tspec %d (assocId %d): dphNode not found"), + ctspec, pTspecInfo->assocId); + continue; + } + *pBw += pTspecInfo->tspec.meanDataRate; + } + } +} + +/** ------------------------------------------------------------- + \fn lim_get_available_bw + \brief based on the phy mode and the bw_factor, determine the total bandwidth that + can be supported + \param tpAniSirGlobal pMac + \param uint32_t *pMaxBw + \param uint32_t *pMinBw + \param uint32_t phyMode + \param uint32_t bw_factor + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static void +lim_get_available_bw(tpAniSirGlobal pMac, + uint32_t *pMaxBw, + uint32_t *pMinBw, uint32_t phyMode, uint32_t bw_factor) +{ + switch (phyMode) { + case WNI_CFG_PHY_MODE_11B: + *pMaxBw = LIM_TOTAL_BW_11B; + *pMinBw = LIM_MIN_BW_11B; + break; + + case WNI_CFG_PHY_MODE_11A: + *pMaxBw = LIM_TOTAL_BW_11A; + *pMinBw = LIM_MIN_BW_11A; + break; + + case WNI_CFG_PHY_MODE_11G: + case WNI_CFG_PHY_MODE_NONE: + default: + *pMaxBw = LIM_TOTAL_BW_11G; + *pMinBw = LIM_MIN_BW_11G; + break; + } + *pMaxBw *= bw_factor; +} + +/** + * lim_admit_policy_oversubscription() - Admission control policy + * @mac_ctx: Global MAC Context + * @tspec: Pointer to the tspec + * @admit_policy: Admission policy + * @tspec_info: TSPEC information + * @session_entry: Session Entry + * + * simple admission control policy based on oversubscription + * if the total bandwidth of all admitted tspec's exceeds (factor * phy-bw) then + * reject the tspec, else admit it. The phy-bw is the peak available bw in the + * current phy mode. The 'factor' is the configured oversubscription factor. + * + * Return: Status + **/ +static tSirRetStatus +lim_admit_policy_oversubscription(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, + tpLimAdmitPolicyInfo admit_policy, + tpLimTspecInfo tspec_info, + tpPESession session_entry) +{ + uint32_t totalbw, minbw, usedbw; + uint32_t phy_mode; + + /* determine total bandwidth used so far */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_compute_mean_bw_used(mac_ctx, &usedbw, phy_mode, + tspec_info, session_entry); + + /* determine how much bw is available based on the current phy mode */ + lim_get_available_bw(mac_ctx, &totalbw, &minbw, phy_mode, + admit_policy->bw_factor); + + if (usedbw > totalbw) /* this can't possibly happen */ + return eSIR_FAILURE; + + if ((totalbw - usedbw) < tspec->meanDataRate) { + lim_log(mac_ctx, ADMIT_CONTROL_POLICY_LOGLEVEL, + FL + ("Total BW %d, Used %d, Tspec request %d not possible"), + totalbw, usedbw, tspec->meanDataRate); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_policy + \brief determine the current admit control policy and apply it for the offered tspec + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_admit_policy(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_FAILURE; + tpLimAdmitPolicyInfo pAdmitPolicy = &pMac->lim.admitPolicyInfo; + + switch (pAdmitPolicy->type) { + case WNI_CFG_ADMIT_POLICY_ADMIT_ALL: + retval = eSIR_SUCCESS; + break; + + case WNI_CFG_ADMIT_POLICY_BW_FACTOR: + retval = lim_admit_policy_oversubscription(pMac, pTspec, + &pMac->lim. + admitPolicyInfo, + &pMac->lim.tspecInfo[0], + psessionEntry); + if (retval != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("rejected by BWFactor policy")); + ) + break; + + case WNI_CFG_ADMIT_POLICY_REJECT_ALL: + retval = eSIR_FAILURE; + break; + + default: + retval = eSIR_SUCCESS; + lim_log(pMac, LOGE, + FL("Admit Policy %d unknown, admitting all traffic"), + pAdmitPolicy->type); + break; + } + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_delete + \brief delete the specified tspec + \param tpAniSirGlobal pMac + \param tpLimTspecInfo pInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- */ +/* delete the specified tspec */ +void lim_tspec_delete(tpAniSirGlobal pMac, tpLimTspecInfo pInfo) +{ + if (pInfo == NULL) + return; + /* pierre */ + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("tspec entry = %d"), + pInfo->idx); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("delete tspec %p"), pInfo); + pInfo->inuse = 0; + + return; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_sta_addr + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param \param uint8_t *pAddr + \param tSirMacTspecIE *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +/* find the specified tspec in the list */ +static tSirRetStatus +lim_tspec_find_by_sta_addr(tpAniSirGlobal pMac, + uint8_t *pAddr, + tSirMacTspecIE *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && + (cdf_mem_compare + (pAddr, pTspecList->staAddr, sizeof(pTspecList->staAddr))) + && + (cdf_mem_compare + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_assoc_id + \brief find tspec with matchin staid and Tspec + \param tpAniSirGlobal pMac + \param uint32_t staid + \param tSirMacTspecIE *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_tspec_find_by_assoc_id(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTspecIE *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Trying to find tspec entry for assocId = %d"), assocId); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("pTsInfo->traffic.direction = %d, pTsInfo->traffic.tsid = %d"), + pTspecIE->tsinfo.traffic.direction, + pTspecIE->tsinfo.traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && (assocId == pTspecList->assocId) + && + (cdf_mem_compare + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_find_tspec + \brief finding a TSPEC entry with assocId, tsinfo.direction and tsinfo.tsid + \param uint16_t assocId + \param tpAniSirGlobal pMac + \param tSirMacTSInfo *pTsInfo + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +tSirRetStatus +lim_find_tspec(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *pTsInfo, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Trying to find tspec entry for assocId = %d"), assocId); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("pTsInfo->traffic.direction = %d, pTsInfo->traffic.tsid = %d"), + pTsInfo->traffic.direction, pTsInfo->traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && (assocId == pTspecList->assocId) + && (pTsInfo->traffic.direction == + pTspecList->tspec.tsinfo.traffic.direction) + && (pTsInfo->traffic.tsid == + pTspecList->tspec.tsinfo.traffic.tsid)) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_add + \brief add or update the specified tspec to the tspec list + \param tpAniSirGlobal pMac + \param uint8_t *pAddr + \param uint16_t assocId + \param tSirMacTspecIE *pTspec + \param uint32_t interval + \param tpLimTspecInfo *ppInfo + + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +tSirRetStatus lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo) +{ + tpLimTspecInfo pTspecList = &pMac->lim.tspecInfo[0]; + *ppInfo = NULL; + + /* validate the assocId */ + if (assocId >= pMac->lim.maxStation) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid assocId 0x%x"), assocId);) + return eSIR_FAILURE; + } + /* decide whether to add/update */ + { + *ppInfo = NULL; + + if (eSIR_SUCCESS == + lim_find_tspec(pMac, assocId, &pTspec->tsinfo, pTspecList, + ppInfo)) { + /* update this entry. */ + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("updating TSPEC table entry = %d"), + (*ppInfo)->idx); + } else { + /* We didn't find one to update. So find a free slot in the + * LIM TSPEC list and add this new entry + */ + uint8_t ctspec = 0; + for (ctspec = 0, pTspecList = &pMac->lim.tspecInfo[0]; + ctspec < LIM_NUM_TSPEC_MAX; + ctspec++, pTspecList++) { + if (!pTspecList->inuse) { + lim_log(pMac, LOG1, + FL + ("Found free slot in TSPEC list. Add to TSPEC table entry %d"), + ctspec); + break; + } + } + + if (ctspec >= LIM_NUM_TSPEC_MAX) + return eSIR_FAILURE; + + /* Record the new index entry */ + pTspecList->idx = ctspec; + } + } + + /* update the tspec info */ + pTspecList->tspec = *pTspec; + pTspecList->assocId = assocId; + cdf_mem_copy(pTspecList->staAddr, pAddr, sizeof(pTspecList->staAddr)); + + /* for edca tspec's, we are all done */ + if (pTspec->tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + pTspecList->inuse = 1; + *ppInfo = pTspecList; + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("added entry for EDCA AccessPolicy")); + return eSIR_SUCCESS; + } + + /* + * for hcca tspec's, must set the parameterized bit in the queues + * the 'ts' bit in the queue data structure indicates that the queue is + * parameterized (hcca). When the schedule is written this bit is used + * in the tsid field (bit 3) and the other three bits (0-2) are simply + * filled in as the user priority (or qid). This applies only to uplink + * polls where the qos control field must contain the tsid specified in the + * tspec. + */ + pTspecList->inuse = 1; + *ppInfo = pTspecList; + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("added entry for HCCA AccessPolicy")); + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_validate_access_policy + \brief Validates Access policy + \param tpAniSirGlobal pMac + \param uint8_t accessPolicy + \param uint16_t assocId + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_validate_access_policy(tpAniSirGlobal pMac, + uint8_t accessPolicy, + uint16_t assocId, tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_FAILURE; + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if ((pSta == NULL) || (!pSta->valid)) { + PELOGE(lim_log(pMac, LOGE, FL("invalid station address passed"));) + return eSIR_FAILURE; + } + + switch (accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + if (pSta->wmeEnabled || pSta->lleEnabled) + retval = eSIR_SUCCESS; + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + default: + PELOGE(lim_log + (pMac, LOGE, FL("Invalid accessPolicy %d"), + accessPolicy); + ) + break; + } + + if (retval != eSIR_SUCCESS) + lim_log(pMac, LOGW, + FL + ("failed (accPol %d, staId %d, lle %d, wme %d, wsm %d)"), + accessPolicy, pSta->staIndex, pSta->lleEnabled, + pSta->wmeEnabled, pSta->wsmEnabled); + + return retval; +} + +/** + * lim_admit_control_add_ts() - Check if STA can be admitted + * @pMac: Global MAC context + * @pAddr: Address + * @pAddts: ADD TS + * @pQos: QOS fields + * @assocId: Association ID + * @alloc: Allocate bandwidth for this tspec + * @pSch: Schedule IE + * @pTspecIdx: TSPEC index + * @psessionEntry: PE Session Entry + * + * Determine if STA with the specified TSPEC can be admitted. If it can, + * a schedule element is provided + * + * Return: status + **/ +tSirRetStatus lim_admit_control_add_ts(tpAniSirGlobal pMac, uint8_t *pAddr, + tSirAddtsReqInfo *pAddts, tSirMacQosCapabilityStaIE *pQos, + uint16_t assocId, uint8_t alloc, tSirMacScheduleIE *pSch, + uint8_t *pTspecIdx, tpPESession psessionEntry) +{ + tpLimTspecInfo pTspecInfo; + tSirRetStatus retval; + uint32_t svcInterval; + (void)pQos; + + /* TBD: modify tspec as needed */ + /* EDCA: need to fill in the medium time and the minimum phy rate */ + /* to be consistent with the desired traffic parameters. */ + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("tsid %d, directn %d, start %d, intvl %d, accPolicy %d, up %d"), + pAddts->tspec.tsinfo.traffic.tsid, + pAddts->tspec.tsinfo.traffic.direction, + pAddts->tspec.svcStartTime, pAddts->tspec.minSvcInterval, + pAddts->tspec.tsinfo.traffic.accessPolicy, + pAddts->tspec.tsinfo.traffic.userPrio); + + /* check for duplicate tspec */ + retval = (alloc) + ? lim_tspec_find_by_assoc_id(pMac, assocId, &pAddts->tspec, + &pMac->lim.tspecInfo[0], &pTspecInfo) + : lim_tspec_find_by_sta_addr(pMac, pAddr, &pAddts->tspec, + &pMac->lim.tspecInfo[0], &pTspecInfo); + + if (retval == eSIR_SUCCESS) { + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("duplicate tspec (index %d)!"), pTspecInfo->idx); + return eSIR_FAILURE; + } + /* check that the tspec's are well formed and acceptable */ + if (lim_validate_tspec(pMac, &pAddts->tspec, psessionEntry) != + eSIR_SUCCESS) { + PELOGW(lim_log(pMac, LOGW, FL("tspec validation failed"));) + return eSIR_FAILURE; + } + /* determine a service interval for the tspec */ + if (lim_calculate_svc_int(pMac, &pAddts->tspec, &svcInterval) != + eSIR_SUCCESS) { + PELOGW(lim_log(pMac, LOGW, FL("SvcInt calculate failed"));) + return eSIR_FAILURE; + } + /* determine if the tspec can be admitted or not based on current policy */ + if (lim_admit_policy(pMac, &pAddts->tspec, psessionEntry) != eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, + FL("tspec rejected by admit control policy")); + ) + return eSIR_FAILURE; + } + /* fill in a schedule if requested */ + if (pSch != NULL) { + cdf_mem_set((uint8_t *) pSch, sizeof(*pSch), 0); + pSch->svcStartTime = pAddts->tspec.svcStartTime; + pSch->svcInterval = svcInterval; + pSch->maxSvcDuration = (uint16_t) pSch->svcInterval; /* use SP = SI */ + pSch->specInterval = 0x1000; /* fixed for now: TBD */ + + pSch->info.direction = pAddts->tspec.tsinfo.traffic.direction; + pSch->info.tsid = pAddts->tspec.tsinfo.traffic.tsid; + pSch->info.aggregation = 0; /* no support for aggregation for now: TBD */ + } + /* if no allocation is requested, done */ + if (!alloc) + return eSIR_SUCCESS; + + /* check that we are in the proper mode to deal with the tspec type */ + if (lim_validate_access_policy + (pMac, (uint8_t) pAddts->tspec.tsinfo.traffic.accessPolicy, assocId, + psessionEntry) != eSIR_SUCCESS) { + lim_log(pMac, LOGW, + FL("AccessPolicy %d is not valid in current mode"), + pAddts->tspec.tsinfo.traffic.accessPolicy); + return eSIR_FAILURE; + } + /* add tspec to list */ + if (lim_tspec_add + (pMac, pAddr, assocId, &pAddts->tspec, svcInterval, &pTspecInfo) + != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("no space in tspec list"));) + return eSIR_FAILURE; + } + /* passing lim tspec table index to the caller */ + *pTspecIdx = pTspecInfo->idx; + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_ts + \brief Delete the specified Tspec for the specified STA + \param tpAniSirGlobal pMac + \param uint16_t assocId + \param tSirMacTSInfo *pTsInfo + \param uint8_t *pTsStatus + \param uint8_t *ptspecIdx + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *pTsInfo, + uint8_t *pTsStatus, uint8_t *ptspecIdx) +{ + tpLimTspecInfo pTspecInfo = NULL; + + if (pTsStatus != NULL) + *pTsStatus = 0; + + if (lim_find_tspec + (pMac, assocId, pTsInfo, &pMac->lim.tspecInfo[0], + &pTspecInfo) == eSIR_SUCCESS) { + if (pTspecInfo != NULL) { + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Tspec entry %d found"), pTspecInfo->idx); + + *ptspecIdx = pTspecInfo->idx; + lim_tspec_delete(pMac, pTspecInfo); + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_sta + \brief Delete all TSPEC for the specified STA + \param tpAniSirGlobal pMac + \param uint16_t assocId + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId) +{ + tpLimTspecInfo pTspecInfo = &pMac->lim.tspecInfo[0]; + int ctspec; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (assocId == pTspecInfo->assocId) { + lim_tspec_delete(pMac, pTspecInfo); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Deleting TSPEC %d for assocId %d"), ctspec, + assocId); + } + } + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("assocId %d done"), assocId); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_init + \brief init tspec table + \param tpAniSirGlobal pMac + \return eSirRetStatus - status + -------------------------------------------------------------*/ +tSirRetStatus lim_admit_control_init(tpAniSirGlobal pMac) +{ + cdf_mem_set(pMac->lim.tspecInfo, + LIM_NUM_TSPEC_MAX * sizeof(tLimTspecInfo), 0); + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_update_admit_policy + \brief Set the admit control policy based on CFG parameters + \param tpAniSirGlobal pMac + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_update_admit_policy(tpAniSirGlobal pMac) +{ + uint32_t val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_POLICY, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("Unable to get CFG_ADMIT_POLICY")); + return eSIR_FAILURE; + } + pMac->lim.admitPolicyInfo.type = (uint8_t) val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_BWFACTOR, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("Unable to get CFG_ADMIT_BWFACTOR")); + return eSIR_FAILURE; + } + pMac->lim.admitPolicyInfo.bw_factor = (uint8_t) val; + + PELOG1(lim_log(pMac, LOG1, FL("LIM: AdmitPolicy %d, bw_factor %d"), + pMac->lim.admitPolicyInfo.type, + pMac->lim.admitPolicyInfo.bw_factor); + ) + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_add_ts + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirMacTspecIE tspecIE + \param tSirTclasInfo *tclasInfo + \param uint8_t tclasProc + \param uint16_t tsm_interval + \return eSirRetStatus - status + -------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_ESE +tSirRetStatus +lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval) +#else +tSirRetStatus +lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, tSirMacTspecIE tspecIE, uint8_t sessionId) +#endif +{ + tSirMsgQ msg; + tpAddTsParams pAddTsParam; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tpPESession psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Unable to get Session for session Id %d"), + sessionId); + return eSIR_FAILURE; + } +#endif + pAddTsParam = cdf_mem_malloc(sizeof(tAddTsParams)); + if (NULL == pAddTsParam) { + PELOGW(lim_log(pMac, LOGW, FL("AllocateMemory() failed"));) + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) pAddTsParam, sizeof(tAddTsParams), 0); + pAddTsParam->staIdx = staIdx; + pAddTsParam->tspecIdx = tspecIdx; + cdf_mem_copy(&pAddTsParam->tspec, &tspecIE, sizeof(tSirMacTspecIE)); + pAddTsParam->sessionId = sessionId; + pAddTsParam->sme_session_id = psessionEntry->smeSessionId; + +#ifdef FEATURE_WLAN_ESE + pAddTsParam->tsm_interval = tsm_interval; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) + pAddTsParam->setRICparams = 1; +#endif + + msg.type = WMA_ADD_TS_REQ; + msg.bodyptr = pAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_ADD_TS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + cdf_mem_free(pAddTsParam); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_del_ts + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirAddtsReqInfo addts + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, uint8_t sessionId, uint8_t *bssId) +{ + tSirMsgQ msg; + tpDelTsParams pDelTsParam; + tpPESession psessionEntry = NULL; + + pDelTsParam = cdf_mem_malloc(sizeof(tDelTsParams)); + if (NULL == pDelTsParam) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return eSIR_MEM_ALLOC_FAILED; + } + + msg.type = WMA_DEL_TS_REQ; + msg.bodyptr = pDelTsParam; + msg.bodyval = 0; + cdf_mem_set((uint8_t *) pDelTsParam, sizeof(tDelTsParams), 0); + + /* filling message parameters. */ + pDelTsParam->staIdx = staIdx; + pDelTsParam->tspecIdx = tspecIdx; + cdf_mem_copy(&pDelTsParam->bssId, bssId, sizeof(tSirMacAddr)); + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Session does Not exist with given sessionId :%d "), + sessionId); + ) + goto err; + } + pDelTsParam->sessionId = psessionEntry->smeSessionId; + pDelTsParam->userPrio = delts.wmeTspecPresent ? + delts.tspec.tsinfo.traffic.userPrio : + delts.tsinfo.traffic.userPrio; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) { + cdf_mem_copy(&pDelTsParam->delTsInfo, &delts, + sizeof(tSirDeltsReqInfo)); + pDelTsParam->setRICparams = 1; + } +#endif + + lim_log(pMac, LOGW, FL("calling wma_post_ctrl_msg()")); + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + goto err; + } + return eSIR_SUCCESS; + +err: + cdf_mem_free(pDelTsParam); + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_process_hal_add_ts_rsp + \brief This function process the WMA_ADD_TS_RSP from HAL. + \ If response is successful, then send back SME_ADDTS_RSP. + \ Otherwise, send DELTS action frame to peer and then + \ then send back SME_ADDTS_RSP. + \ + \param tpAniSirGlobal pMac + \param tpSirMsgQ limMsg + -------------------------------------------------------------*/ +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpAddTsParams pAddTsRspMsg = NULL; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + + /* Need to process all the deferred messages enqueued + * since sending the WMA_ADD_TS_REQ. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + if (NULL == limMsg->bodyptr) { + lim_log(pMac, LOGP, FL("Received WMA_ADD_TS_RSP with NULL ")); + goto end; + } + + pAddTsRspMsg = (tpAddTsParams) (limMsg->bodyptr); + + /* 090803: Use pe_find_session_by_session_id() to obtain the PE session context */ + /* from the sessionId in the Rsp Msg from HAL */ + psessionEntry = pe_find_session_by_session_id(pMac, pAddTsRspMsg->sessionId); + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("Session does Not exist with given sessionId :%d "), + pAddTsRspMsg->sessionId); + ) + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + pMac->lim.gLimAddtsReq.sessionId, + pMac->lim.gLimAddtsReq.transactionId); + goto end; + } + + if (pAddTsRspMsg->status == CDF_STATUS_SUCCESS) { + PELOG1(lim_log + (pMac, LOG1, + FL("Received successful ADDTS response from HAL ")); + ) + /* Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_SUCCESS, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + goto end; + } else { + PELOG1(lim_log + (pMac, LOG1, + FL("Received failure ADDTS response from HAL ")); + ) + /* Send DELTS action frame to AP */ + /* 090803: Get peer MAC addr from session */ + sir_copy_mac_addr(peerMacAddr, psessionEntry->bssId); + + /* 090803: Add the SME Session ID */ + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &pAddTsRspMsg->tspec.tsinfo, + &pAddTsRspMsg->tspec, psessionEntry); + + /* Delete TSPEC */ + /* 090803: Pull the hash table from the session */ + pSta = dph_lookup_assoc_id(pMac, pAddTsRspMsg->staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) + lim_admit_control_delete_ts(pMac, assocId, + &pAddTsRspMsg->tspec.tsinfo, + NULL, + (uint8_t *) &pAddTsRspMsg-> + tspecIdx); + + /* Send SME_ADDTS_RSP */ + /* 090803: Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + goto end; + } + +end: + if (pAddTsRspMsg != NULL) + cdf_mem_free(pAddTsRspMsg); + return; +} diff --git a/core/mac/src/pe/lim/lim_aid_mgmt.c b/core/mac/src/pe/lim/lim_aid_mgmt.c new file mode 100644 index 0000000000..253543d86b --- /dev/null +++ b/core/mac/src/pe/lim/lim_aid_mgmt.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_aid_mgmt.c contains the functions related to + * AID pool management like initialization, assignment etc. + * Author: Chandra Modumudi + * Date: 03/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sir_params.h" +#include "lim_utils.h" +#include "lim_timer_utils.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_session_utils.h" + +#define LIM_START_PEER_IDX 1 + +/** + * lim_init_peer_idxpool() + * + ***FUNCTION: + * This function is called while starting a BSS at AP + * to initialize AID pool. This may also be called while + * starting/joining an IBSS if 'Association' is allowed + * in IBSS. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_init_peer_idxpool(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint8_t i; + uint8_t maxAssocSta = pMac->lim.gLimAssocStaLimit; + + pSessionEntry->gpLimPeerIdxpool[0] = 0; + +#ifdef FEATURE_WLAN_TDLS + /* In station role, DPH_STA_HASH_INDEX_PEER (index 1) is reserved for peer */ + /* station index corresponding to AP. Avoid choosing that index and get index */ + /* starting from (DPH_STA_HASH_INDEX_PEER + 1) (index 2) for TDLS stations; */ + if (LIM_IS_STA_ROLE(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = DPH_STA_HASH_INDEX_PEER + 1; + } else +#endif +#ifdef QCA_IBSS_SUPPORT + if (LIM_IS_IBSS_ROLE(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + maxAssocSta = pMac->lim.gLimIbssStaLimit; + } else +#endif + { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + } + + for (i = pSessionEntry->freePeerIdxHead; i < maxAssocSta; i++) { + pSessionEntry->gpLimPeerIdxpool[i] = i + 1; + } + pSessionEntry->gpLimPeerIdxpool[i] = 0; + + pSessionEntry->freePeerIdxTail = i; + +} + +/** + * lim_assign_peer_idx() + * + ***FUNCTION: + * This function is called to get a peer station index. This index is + * used during Association/Reassociation + * frame handling to assign association ID (aid) to a STA. + * In case of TDLS, this is used to assign a index into the Dph hash entry. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return peerIdx - assigned peer Station IDx for STA + */ + +uint16_t lim_assign_peer_idx(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint16_t peerId; + + /* make sure we haven't exceeded the configurable limit on associations */ + /* This count is global to ensure that it doesnt exceed the hardware limits. */ + if (pe_get_current_stas_count(pMac) >= pMac->lim.gLimAssocStaLimit) { + /* too many associations already active */ + return 0; + } + + /* return head of free list */ + + if (pSessionEntry->freePeerIdxHead) { + peerId = pSessionEntry->freePeerIdxHead; + pSessionEntry->freePeerIdxHead = + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxHead]; + if (pSessionEntry->freePeerIdxHead == 0) + pSessionEntry->freePeerIdxTail = 0; + pSessionEntry->gLimNumOfCurrentSTAs++; + return peerId; + } + + return 0; /* no more free peer index */ +} + +/** + * lim_release_peer_idx() + * + ***FUNCTION: + * This function is called when a STA context is removed + * at AP (or at a STA in IBSS mode or TDLS) to return peer Index + * to free pool. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param peerIdx - peer station index that need to return to free pool + * + * @return None + */ + +void +lim_release_peer_idx(tpAniSirGlobal pMac, uint16_t peerIdx, + tpPESession pSessionEntry) +{ + pSessionEntry->gLimNumOfCurrentSTAs--; + + /* insert at tail of free list */ + if (pSessionEntry->freePeerIdxTail) { + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxTail] = + (uint8_t) peerIdx; + pSessionEntry->freePeerIdxTail = (uint8_t) peerIdx; + } else { + pSessionEntry->freePeerIdxTail = + pSessionEntry->freePeerIdxHead = (uint8_t) peerIdx; + } + pSessionEntry->gpLimPeerIdxpool[(uint8_t) peerIdx] = 0; +} diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c new file mode 100644 index 0000000000..1d0dc07bfc --- /dev/null +++ b/core/mac/src/pe/lim/lim_api.c @@ -0,0 +1,2202 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_api.cc contains the functions that are + * exported by LIM to other modules. + * + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_cfg.h" +#include "wni_api.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_global.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_admit_control.h" +#include "lim_send_sme_rsp_messages.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "wma_types.h" + +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#include +#include "cdf_types.h" +#include "cds_packet.h" +#include "cds_utils.h" +#include "sys_startup.h" + +static void __lim_init_scan_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimUseScanModeForLearnMode = 1; + + pMac->lim.gLimSystemInScanLearnMode = 0; + + /* Scan related globals on STA */ + pMac->lim.gLimReturnAfterFirstMatch = 0; + pMac->lim.gLim24Band11dScanDone = 0; + pMac->lim.gLim50Band11dScanDone = 0; + pMac->lim.gLimReturnUniqueResults = 0; + + pMac->lim.gLimCurrentScanChannelId = 0; + pMac->lim.gpLimMlmScanReq = NULL; + pMac->lim.gDeferMsgTypeForNOA = 0; + pMac->lim.gpDefdSmeMsgForNOA = NULL; + + pMac->lim.gLimRestoreCBNumScanInterval = + LIM_RESTORE_CB_NUM_SCAN_INTERVAL_DEFAULT; + pMac->lim.gLimRestoreCBCount = 0; + cdf_mem_set(pMac->lim.gLimLegacyBssidList, + sizeof(pMac->lim.gLimLegacyBssidList), 0); + + /* Fill in default values */ + + /* abort scan is used to abort an on-going scan */ + pMac->lim.abortScan = 0; + cdf_mem_set(&pMac->lim.scanChnInfo, sizeof(tLimScanChnInfo), 0); + cdf_mem_set(&pMac->lim.dfschannelList, sizeof(tSirDFSChannelList), 0); + +/* WLAN_SUSPEND_LINK Related */ + pMac->lim.gpLimSuspendCallback = NULL; + pMac->lim.gpLimResumeCallback = NULL; +/* end WLAN_SUSPEND_LINK Related */ +} + +static void __lim_init_bss_vars(tpAniSirGlobal pMac) +{ + cdf_mem_set((void *)pMac->lim.gpSession, + sizeof(*pMac->lim.gpSession) * pMac->lim.maxBssId, 0); + + /* This is for testing purposes only, be default should always be off */ + pMac->lim.gLimForceNoPropIE = 0; + pMac->lim.gpLimMlmSetKeysReq = NULL; +} + +static void __lim_init_stats_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimNumBeaconsRcvd = 0; + pMac->lim.gLimNumBeaconsIgnored = 0; + + pMac->lim.gLimNumDeferredMsgs = 0; + + /* / Variable to keep track of number of currently associated STAs */ + pMac->lim.gLimNumOfAniSTAs = 0; /* count of ANI peers */ + + /* Heart-Beat interval value */ + pMac->lim.gLimHeartBeatCount = 0; + + cdf_mem_zero(pMac->lim.gLimHeartBeatApMac[0], + sizeof(tSirMacAddr)); + cdf_mem_zero(pMac->lim.gLimHeartBeatApMac[1], + sizeof(tSirMacAddr)); + pMac->lim.gLimHeartBeatApMacIndex = 0; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + cdf_mem_set(pMac->lim.gLimHeartBeatBeaconStats, + sizeof(pMac->lim.gLimHeartBeatBeaconStats), 0); + +#ifdef WLAN_DEBUG + /* Debug counters */ + pMac->lim.numTot = 0; + pMac->lim.numBbt = 0; + pMac->lim.numProtErr = 0; + pMac->lim.numLearn = 0; + pMac->lim.numLearnIgnore = 0; + pMac->lim.numSme = 0; + cdf_mem_set(pMac->lim.numMAC, sizeof(pMac->lim.numMAC), 0); + pMac->lim.gLimNumAssocReqDropInvldState = 0; + pMac->lim.gLimNumAssocReqDropACRejectTS = 0; + pMac->lim.gLimNumAssocReqDropACRejectSta = 0; + pMac->lim.gLimNumReassocReqDropInvldState = 0; + pMac->lim.gLimNumHashMissIgnored = 0; + pMac->lim.gLimUnexpBcnCnt = 0; + pMac->lim.gLimBcnSSIDMismatchCnt = 0; + pMac->lim.gLimNumLinkEsts = 0; + pMac->lim.gLimNumRxCleanup = 0; + pMac->lim.gLim11bStaAssocRejectCount = 0; +#endif +} + +static void __lim_init_states(tpAniSirGlobal pMac) +{ + /* Counts Heartbeat failures */ + pMac->lim.gLimHBfailureCntInLinkEstState = 0; + pMac->lim.gLimProbeFailureAfterHBfailedCnt = 0; + pMac->lim.gLimHBfailureCntInOtherStates = 0; + pMac->lim.gLimRspReqd = 0; + pMac->lim.gLimPrevSmeState = eLIM_SME_OFFLINE_STATE; + + /* / MLM State visible across all Sirius modules */ + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, eLIM_MLM_IDLE_STATE)); + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + + /* / Previous MLM State */ + pMac->lim.gLimPrevMlmState = eLIM_MLM_OFFLINE_STATE; + + /* LIM to HAL SCAN Management Message Interface states */ + pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE; + + /** + * Initialize state to eLIM_SME_OFFLINE_STATE + */ + pMac->lim.gLimSmeState = eLIM_SME_OFFLINE_STATE; + + /** + * By default assume 'unknown' role. This will be updated + * when SME_START_BSS_REQ is received. + */ + + cdf_mem_set(&pMac->lim.gLimOverlap11gParams, sizeof(tLimProtStaParams), + 0); + cdf_mem_set(&pMac->lim.gLimOverlap11aParams, sizeof(tLimProtStaParams), + 0); + cdf_mem_set(&pMac->lim.gLimOverlapHt20Params, sizeof(tLimProtStaParams), + 0); + cdf_mem_set(&pMac->lim.gLimOverlapNonGfParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set(&pMac->lim.gLimNoShortParams, sizeof(tLimNoShortParams), 0); + cdf_mem_set(&pMac->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + + pMac->lim.gLimPhyMode = 0; + pMac->lim.scanStartTime = 0; /* used to measure scan time */ + + cdf_mem_set(pMac->lim.gLimMyMacAddr, sizeof(pMac->lim.gLimMyMacAddr), + 0); + pMac->lim.ackPolicy = 0; + + pMac->lim.gLimProbeRespDisableFlag = 0; /* control over probe resp */ +} + +static void __lim_init_vars(tpAniSirGlobal pMac) +{ + /* Place holder for Measurement Req/Rsp/Ind related info */ + + + /* Deferred Queue Paramters */ + cdf_mem_set(&pMac->lim.gLimDeferredMsgQ, sizeof(tSirAddtsReq), 0); + + /* addts request if any - only one can be outstanding at any time */ + cdf_mem_set(&pMac->lim.gLimAddtsReq, sizeof(tSirAddtsReq), 0); + pMac->lim.gLimAddtsSent = 0; + pMac->lim.gLimAddtsRspTimerCount = 0; + + /* protection related config cache */ + cdf_mem_set(&pMac->lim.cfgProtection, sizeof(tCfgProtection), 0); + pMac->lim.gLimProtectionControl = 0; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + /* WMM Related Flag */ + pMac->lim.gUapsdEnable = 0; + pMac->lim.gUapsdPerAcBitmask = 0; + + /* QoS-AC Downgrade: Initially, no AC is admitted */ + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] = 0; + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] = 0; + + /* dialogue token List head/tail for Action frames request sent. */ + pMac->lim.pDialogueTokenHead = NULL; + pMac->lim.pDialogueTokenTail = NULL; + + cdf_mem_set(&pMac->lim.tspecInfo, + sizeof(tLimTspecInfo) * LIM_NUM_TSPEC_MAX, 0); + + /* admission control policy information */ + cdf_mem_set(&pMac->lim.admitPolicyInfo, sizeof(tLimAdmitPolicyInfo), 0); + + pMac->lim.gLastBeaconDtimCount = 0; + pMac->lim.gLastBeaconDtimPeriod = 0; + + /* Scan in Power Save Flag */ + pMac->lim.gScanInPowersave = 0; + pMac->lim.probeCounter = 0; + pMac->lim.maxProbe = 0; +} + +static void __lim_init_assoc_vars(tpAniSirGlobal pMac) +{ + uint32_t val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get assoc sta limit failed")); + pMac->lim.gLimAssocStaLimit = val; + pMac->lim.gLimIbssStaLimit = val; + /* Place holder for current authentication request */ + /* being handled */ + pMac->lim.gpLimMlmAuthReq = NULL; + + /* / MAC level Pre-authentication related globals */ + pMac->lim.gLimPreAuthChannelNumber = 0; + pMac->lim.gLimPreAuthType = eSIR_OPEN_SYSTEM; + cdf_mem_set(&pMac->lim.gLimPreAuthPeerAddr, sizeof(tSirMacAddr), 0); + pMac->lim.gLimNumPreAuthContexts = 0; + cdf_mem_set(&pMac->lim.gLimPreAuthTimerTable, sizeof(tLimPreAuthTable), + 0); + + /* Placed holder to deauth reason */ + pMac->lim.gLimDeauthReasonCode = 0; + + /* Place holder for Pre-authentication node list */ + pMac->lim.pLimPreAuthList = NULL; + + /* Send Disassociate frame threshold parameters */ + pMac->lim.gLimDisassocFrameThreshold = + LIM_SEND_DISASSOC_FRAME_THRESHOLD; + pMac->lim.gLimDisassocFrameCredit = 0; + + /* One cache for each overlap and associated case. */ + cdf_mem_set(pMac->lim.protStaOverlapCache, + sizeof(tCacheParams) * LIM_PROT_STA_OVERLAP_CACHE_SIZE, 0); + cdf_mem_set(pMac->lim.protStaCache, + sizeof(tCacheParams) * LIM_PROT_STA_CACHE_SIZE, 0); + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + pMac->lim.pSessionEntry = NULL; + pMac->lim.reAssocRetryAttempt = 0; +#endif + +} + +static void __lim_init_ht_vars(tpAniSirGlobal pMac) +{ + pMac->lim.htCapabilityPresentInBeacon = 0; + pMac->lim.gHTGreenfield = 0; + pMac->lim.gHTShortGI40Mhz = 0; + pMac->lim.gHTShortGI20Mhz = 0; + pMac->lim.gHTMaxAmsduLength = 0; + pMac->lim.gHTDsssCckRate40MHzSupport = 0; + pMac->lim.gHTPSMPSupport = 0; + pMac->lim.gHTLsigTXOPProtection = 0; + pMac->lim.gHTMIMOPSState = eSIR_HT_MIMO_PS_STATIC; + pMac->lim.gHTAMpduDensity = 0; + + pMac->lim.gMaxAmsduSizeEnabled = false; + pMac->lim.gHTMaxRxAMpduFactor = 0; + pMac->lim.gHTServiceIntervalGranularity = 0; + pMac->lim.gHTControlledAccessOnly = 0; + pMac->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pMac->lim.gHTPCOActive = 0; + + pMac->lim.gHTPCOPhase = 0; + pMac->lim.gHTSecondaryBeacon = 0; + pMac->lim.gHTDualCTSProtection = 0; + pMac->lim.gHTSTBCBasicMCS = 0; +} + +static tSirRetStatus __lim_init_config(tpAniSirGlobal pMac) +{ + uint32_t val1, val2, val3; + uint16_t val16; + uint8_t val8; + tSirMacHTCapabilityInfo *pHTCapabilityInfo; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTParametersInfo *pAmpduParamInfo; + + /* Read all the CFGs here that were updated before pe_start is called */ + /* All these CFG READS/WRITES are only allowed in init, at start when there is no session + * and they will be used throughout when there is no session + */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("could not retrieve HT Cap CFG"));) + return eSIR_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve Channel Bonding CFG")); + ) + return eSIR_FAILURE; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* channel bonding mode could be set to anything from 0 to 4(Titan had these */ + /* modes But for Taurus we have only two modes: enable(>0) or disable(=0) */ + pHTCapabilityInfo->supportedChannelWidthSet = val2 ? + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE : + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, *(uint16_t *) pHTCapabilityInfo) + != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not update HT Cap Info CFG")); + ) + return eSIR_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &val1) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT INFO Field1 CFG")); + ) + return eSIR_FAILURE; + } + + val8 = (uint8_t) val1; + pHTInfoField1 = (tSirMacHTInfoField1 *) &val8; + pHTInfoField1->recommendedTxWidthSet = + (uint8_t) pHTCapabilityInfo->supportedChannelWidthSet; + if (cfg_set_int(pMac, WNI_CFG_HT_INFO_FIELD1, *(uint8_t *) pHTInfoField1) + != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("could not update HT Info Field"));) + return eSIR_FAILURE; + } + + /* WNI_CFG_HEART_BEAT_THRESHOLD */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("could not retrieve WNI_CFG_HEART_BEAT_THRESHOLD CFG")); + ) + return eSIR_FAILURE; + } + if (!val1) { + pMac->sys.gSysEnableLinkMonitorMode = 0; + } else { + /* No need to activate the timer during init time. */ + pMac->sys.gSysEnableLinkMonitorMode = 1; + } + + /* WNI_CFG_SHORT_GI_20MHZ */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("could not retrieve HT Cap CFG"));) + return eSIR_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_20MHZ, &val2) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not retrieve shortGI 20Mhz CFG")); + ) + return eSIR_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_40MHZ, &val3) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not retrieve shortGI 40Mhz CFG")); + ) + return eSIR_FAILURE; + } + + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->shortGI20MHz = (uint16_t) val2; + pHTCapabilityInfo->shortGI40MHz = (uint16_t) val3; + + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not update HT Cap Info CFG")); + ) + return eSIR_FAILURE; + } + + /* WNI_CFG_MAX_RX_AMPDU_FACTOR */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT AMPDU Param CFG")); + ) + return eSIR_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not retrieve AMPDU Factor CFG")); + ) + return eSIR_FAILURE; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("cfg get short preamble failed")); + return eSIR_FAILURE; + } + + /* WNI_CFG_SHORT_PREAMBLE - this one is not updated in + lim_handle_cf_gparam_update do we want to update this? */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val1) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get short preamble failed")); + return eSIR_FAILURE; + } + + /* WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA - not needed */ + + /* This was initially done after resume notification from HAL. Now, DAL is + started before PE so this can be done here */ + handle_ht_capabilityand_ht_info(pMac, NULL); + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + (uint32_t *) &pMac->lim.disableLDPCWithTxbfAP)) { + lim_log(pMac, LOGP, FL("cfg get disableLDPCWithTxbfAP failed")); + return eSIR_FAILURE; + } +#ifdef FEATURE_WLAN_TDLS + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_BUF_STA_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSBufStaEnabled)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSBufStaEnabled failed")); + return eSIR_FAILURE; + } + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + (uint32_t *) &pMac->lim.gLimTDLSUapsdMask)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSUapsdMask failed")); + return eSIR_FAILURE; + } + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSOffChannelEnabled)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSUapsdMask failed")); + return eSIR_FAILURE; + } + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_WMM_MODE_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSWmmMode)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSWmmMode failed")); + return eSIR_FAILURE; + } +#endif + return eSIR_SUCCESS; +} + +/* + lim_start + This function is to replace the __lim_process_sme_start_req since there is no + eWNI_SME_START_REQ post to PE. + */ +tSirRetStatus lim_start(tpAniSirGlobal pMac) +{ + tSirResultCodes retCode = eSIR_SUCCESS; + + PELOG1(lim_log(pMac, LOG1, FL(" enter"));) + + if (pMac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + pMac->lim.gLimSmeState = eLIM_SME_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, NO_SESSION, + pMac->lim.gLimSmeState)); + + /* By default do not return after first scan match */ + pMac->lim.gLimReturnAfterFirstMatch = 0; + + /* Initialize MLM state machine */ + lim_init_mlm(pMac); + + /* By default return unique scan results */ + pMac->lim.gLimReturnUniqueResults = true; + } else { + /** + * Should not have received eWNI_SME_START_REQ in states + * other than OFFLINE. Return response to host and + * log error + */ + lim_log(pMac, LOGE, FL("Invalid SME state %X"), + pMac->lim.gLimSmeState); + retCode = eSIR_FAILURE; + } + + return retCode; +} + +/** + * lim_initialize() + * + ***FUNCTION: + * This function is called from LIM thread entry function. + * LIM related global data structures are initialized in this function. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @return None + */ + +tSirRetStatus lim_initialize(tpAniSirGlobal pMac) +{ + tSirRetStatus status = eSIR_SUCCESS; + + __lim_init_assoc_vars(pMac); + __lim_init_vars(pMac); + __lim_init_states(pMac); + __lim_init_stats_vars(pMac); + __lim_init_bss_vars(pMac); + __lim_init_scan_vars(pMac); + __lim_init_ht_vars(pMac); + + status = lim_start(pMac); + if (eSIR_SUCCESS != status) { + return status; + } + /* Initializations for maintaining peers in IBSS */ + lim_ibss_init(pMac); + +#if defined WLAN_FEATURE_VOWIFI + rrm_initialize(pMac); +#endif + + cdf_mutex_init(&pMac->lim.lim_frame_register_lock); + cdf_list_init(&pMac->lim.gLimMgmtFrameRegistratinQueue, 0); + + /* Initialize the configurations needed by PE */ + if (eSIR_FAILURE == __lim_init_config(pMac)) { + /* We need to undo everything in lim_start */ + lim_cleanup_mlm(pMac); + return eSIR_FAILURE; + } + /* initialize the TSPEC admission control table. */ + /* Note that this was initially done after resume notification from HAL. */ + /* Now, DAL is started before PE so this can be done here */ + lim_admit_control_init(pMac); + lim_register_hal_ind_call_back(pMac); + + return status; + +} /*** end lim_initialize() ***/ + +/** + * lim_cleanup() + * + ***FUNCTION: + * This function is called upon reset or persona change + * to cleanup LIM state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_cleanup(tpAniSirGlobal pMac) +{ + void *p_cds_gctx; + CDF_STATUS retStatus; + + /*Before destroying the list making sure all the nodes have been deleted + *Which should be the normal case, but a memory leak has been reported + */ + + struct mgmt_frm_reg_info *pLimMgmtRegistration = NULL; + + if (CDF_FTM_MODE != cds_get_conparam()) { + cdf_mutex_acquire(&pMac->lim.lim_frame_register_lock); + while (cdf_list_remove_front( + &pMac->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t **) &pLimMgmtRegistration) == + CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Fixing leak! Deallocating pLimMgmtRegistration node")); + cdf_mem_free(pLimMgmtRegistration); + } + cdf_mutex_release(&pMac->lim.lim_frame_register_lock); + cdf_list_destroy(&pMac->lim.gLimMgmtFrameRegistratinQueue); + } + + lim_cleanup_mlm(pMac); + lim_cleanup_lmm(pMac); + + /* free up preAuth table */ + if (pMac->lim.gLimPreAuthTimerTable.pTable != NULL) { + cdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->lim.gLimPreAuthTimerTable.pTable = NULL; + pMac->lim.gLimPreAuthTimerTable.numEntry = 0; + } + + if (NULL != pMac->lim.pDialogueTokenHead) { + lim_delete_dialogue_token_list(pMac); + } + + if (NULL != pMac->lim.pDialogueTokenTail) { + cdf_mem_free(pMac->lim.pDialogueTokenTail); + pMac->lim.pDialogueTokenTail = NULL; + } + + if (pMac->lim.gpLimMlmSetKeysReq != NULL) { + cdf_mem_free(pMac->lim.gpLimMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + } + + if (pMac->lim.gpLimMlmAuthReq != NULL) { + cdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + } + + if (pMac->lim.gpDefdSmeMsgForNOA != NULL) { + cdf_mem_free(pMac->lim.gpDefdSmeMsgForNOA); + pMac->lim.gpDefdSmeMsgForNOA = NULL; + } + + if (pMac->lim.gpLimMlmScanReq != NULL) { + cdf_mem_free(pMac->lim.gpLimMlmScanReq); + pMac->lim.gpLimMlmScanReq = NULL; + } + /* Now, finally reset the deferred message queue pointers */ + lim_reset_deferred_msg_q(pMac); + + p_cds_gctx = cds_get_global_context(); + retStatus = wma_de_register_mgmt_frm_client(p_cds_gctx); + + if (retStatus != CDF_STATUS_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL + ("DeRegistering the PE Handle with wma has failed bailing out...")); + ) +#if defined WLAN_FEATURE_VOWIFI + rrm_cleanup(pMac); +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R + lim_ft_cleanup_all_ft_sessions(pMac); +#endif + +} /*** end lim_cleanup() ***/ + +/** ------------------------------------------------------------- + \fn pe_open + \brief will be called in Open sequence from mac_open + \param tpAniSirGlobal pMac + \param tHalOpenParameters *pHalOpenParam + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus pe_open(tpAniSirGlobal pMac, tMacOpenParameters *pMacOpenParam) +{ + tSirRetStatus status = eSIR_SUCCESS; + + if (eDRIVER_TYPE_MFG == pMacOpenParam->driverType) + return eSIR_SUCCESS; + + pMac->lim.maxBssId = pMacOpenParam->maxBssId; + pMac->lim.maxStation = pMacOpenParam->maxStation; + + if ((pMac->lim.maxBssId == 0) || (pMac->lim.maxStation == 0)) { + PELOGE(lim_log(pMac, LOGE, + FL("max number of Bssid or Stations cannot be zero!"));) + return eSIR_FAILURE; + } + + pMac->lim.limTimers.gpLimCnfWaitTimer = + cdf_mem_malloc(sizeof(TX_TIMER) * (pMac->lim.maxStation + 1)); + if (NULL == pMac->lim.limTimers.gpLimCnfWaitTimer) { + PELOGE(lim_log(pMac, LOGE, + FL("gpLimCnfWaitTimer memory allocate failed!"));) + return eSIR_MEM_ALLOC_FAILED; + } + + pMac->lim.gpSession = + cdf_mem_malloc(sizeof(tPESession) * pMac->lim.maxBssId); + if (NULL == pMac->lim.gpSession) { + lim_log(pMac, LOGE, + FL("gpSession memory allocate failed!")); + status = eSIR_MEM_ALLOC_FAILED; + goto pe_open_psession_fail; + } + + cdf_mem_set(pMac->lim.gpSession, + sizeof(tPESession) * pMac->lim.maxBssId, 0); + + pMac->lim.mgmtFrameSessionId = 0xff; + pMac->lim.deferredMsgCnt = 0; + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_init(&pMac->lim.lkPeGlobalLock))) { + PELOGE(lim_log(pMac, LOGE, FL("pe lock init failed!"));) + status = eSIR_FAILURE; + goto pe_open_lock_fail; + } + pMac->lim.deauthMsgCnt = 0; + pMac->lim.retry_packet_cnt = 0; + pMac->lim.ibss_retry_cnt = 0; + + /* + * pe_open is successful by now, so it is right time to initialize + * MTRACE for PE module. if LIM_TRACE_RECORD is not defined in build + * file then nothing will be logged for PE module. + */ +#ifdef LIM_TRACE_RECORD + MTRACE(lim_trace_init(pMac)); +#endif + return status; /* status here will be eSIR_SUCCESS */ + +pe_open_lock_fail: + cdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; +pe_open_psession_fail: + cdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + return status; +} + +/** ------------------------------------------------------------- + \fn pe_close + \brief will be called in close sequence from mac_close + \param tpAniSirGlobal pMac + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus pe_close(tpAniSirGlobal pMac) +{ + uint8_t i; + + if (ANI_DRIVER_TYPE(pMac) == eDRIVER_TYPE_MFG) + return eSIR_SUCCESS; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + pe_delete_session(pMac, &pMac->lim.gpSession[i]); + } + } + cdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + if (pMac->lim.gpLimMlmOemDataReq) { + cdf_mem_free(pMac->lim.gpLimMlmOemDataReq); + pMac->lim.gpLimMlmOemDataReq = NULL; + } + + cdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; + if (!CDF_IS_STATUS_SUCCESS + (cdf_mutex_destroy(&pMac->lim.lkPeGlobalLock))) { + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn pe_start + \brief will be called in start sequence from mac_start + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +tSirRetStatus pe_start(tpAniSirGlobal pMac) +{ + tSirRetStatus status = eSIR_SUCCESS; + + status = lim_initialize(pMac); + return status; +} + +/** ------------------------------------------------------------- + \fn pe_stop + \brief will be called in stop sequence from mac_stop + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +void pe_stop(tpAniSirGlobal pMac) +{ + lim_cleanup(pMac); + SET_LIM_MLM_STATE(pMac, eLIM_MLM_OFFLINE_STATE); + return; +} + +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param tpAniSirGlobal pMac + \param tSirMsgQ pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (pMsg != NULL) { + if (NULL != pMsg->bodyptr) { + if (SIR_BB_XPORT_MGMT_MSG == pMsg->type) { + cds_pkt_return_packet((cds_pkt_t *) pMsg-> + bodyptr); + } else { + cdf_mem_free((void *)pMsg->bodyptr); + } + } + pMsg->bodyptr = 0; + pMsg->bodyval = 0; + pMsg->type = 0; + } + return; +} + +/** + * lim_post_msg_api() + * + ***FUNCTION: + * This function is called from other thread while posting a + * message to LIM message Queue gSirLimMsgQ. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg - Pointer to the message structure + * @return None + */ + +uint32_t lim_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + return cds_mq_post_message(CDS_MQ_ID_PE, (cds_msg_t *) pMsg); + +} /*** end lim_post_msg_api() ***/ + +/*-------------------------------------------------------------------------- + + \brief pe_post_msg_api() - A wrapper function to post message to Voss msg queues + + This function can be called by legacy code to post message to cds queues OR + legacy code may keep on invoking 'lim_post_msg_api' to post the message to cds queue + for dispatching it later. + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ + +tSirRetStatus pe_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + return (tSirRetStatus) lim_post_msg_api(pMac, pMsg); +} + +/*-------------------------------------------------------------------------- + + \brief pe_process_messages() - Message Processor for PE + + Voss calls this function to dispatch the message to PE + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ + +tSirRetStatus pe_process_messages(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (ANI_DRIVER_TYPE(pMac) == eDRIVER_TYPE_MFG) { + return eSIR_SUCCESS; + } + /** + * If the Message to be handled is for CFG Module call the CFG Msg + * Handler and for all the other cases post it to LIM + */ + if (SIR_CFG_PARAM_UPDATE_IND != pMsg->type && IS_CFG_MSG(pMsg->type)) + cfg_process_mb_msg(pMac, (tSirMbMsg *) pMsg->bodyptr); + else + lim_message_processor(pMac, pMsg); + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------------- */ +/** + * pe_handle_mgmt_frame + * + * FUNCTION: + * Process the Management frames from TL + * + * LOGIC: + * + * ASSUMPTIONS: TL sends the packet along with the CDS GlobalContext + * + * NOTE: + * + * @param p_cds_gctx Global Vos Context + * @param cds_buff Packet + * @return None + */ + +CDF_STATUS pe_handle_mgmt_frame(void *p_cds_gctx, void *cds_buff) +{ + tpAniSirGlobal pMac; + tpSirMacMgmtHdr mHdr; + tSirMsgQ msg; + cds_pkt_t *pVosPkt; + CDF_STATUS cdf_status; + uint8_t *pRxPacketInfo; + + pVosPkt = (cds_pkt_t *) cds_buff; + if (NULL == pVosPkt) { + return CDF_STATUS_E_FAILURE; + } + + pMac = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == pMac) { + /* cannot log a failure without a valid pMac */ + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return CDF_STATUS_E_FAILURE; + } + + cdf_status = + wma_ds_peek_rx_packet_info(pVosPkt, (void *)&pRxPacketInfo, false); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return CDF_STATUS_E_FAILURE; + } + + /* + * The MPDU header is now present at a certain "offset" in + * the BD and is specified in the BD itself + */ + + mHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + if (mHdr->fc.type == SIR_MAC_MGMT_FRAME) { + lim_log(pMac, LOG1, FL + ("RxBd=%p mHdr=%p Type: %d Subtype: %d Sizes:FC%zu Mgmt%zu"), + pRxPacketInfo, mHdr, mHdr->fc.type, mHdr->fc.subType, + sizeof(tSirMacFrameCtl), sizeof(tSirMacMgmtHdr)); + + lim_log(pMac, LOG1, FL("mpdu_len:%d hdr_len:%d data_len:%d"), + WMA_GET_RX_MPDU_LEN(pRxPacketInfo), + WMA_GET_RX_MPDU_HEADER_LEN(pRxPacketInfo), + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)); + + MTRACE(mac_trace(pMac, TRACE_CODE_RX_MGMT, + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo), + LIM_TRACE_MAKE_RXMGMT(mHdr->fc.subType, + (uint16_t) (((uint16_t) + (mHdr->seqControl.seqNumHi << 4)) | + mHdr->seqControl.seqNumLo)));) + + if (WMA_GET_ROAMCANDIDATEIND(pRxPacketInfo)) + lim_log(pMac, LOG1, FL("roamCandidateInd %d"), + WMA_GET_ROAMCANDIDATEIND(pRxPacketInfo)); + + if (WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)) + lim_log(pMac, LOG1, FL("offloadScanLearn %d"), + WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)); + } + + /* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */ + msg.type = SIR_BB_XPORT_MGMT_MSG; + msg.bodyptr = cds_buff; + msg.bodyval = 0; + + if (eSIR_SUCCESS != sys_bbt_process_message_core(pMac, + &msg, + mHdr->fc.type, + mHdr->fc.subType)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + lim_log(pMac, LOGW, + FL + ("sys_bbt_process_message_core failed to process SIR_BB_XPORT_MGMT_MSG")); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * pe_register_wma_handle() - register management frame handler to WMA + * @pMac: mac global ctx + * + * Return: None + */ +void pe_register_wma_handle(tpAniSirGlobal pMac) +{ + void *p_cds_gctx; + CDF_STATUS retStatus; + + p_cds_gctx = cds_get_global_context(); + + retStatus = wma_register_mgmt_frm_client(p_cds_gctx, + pe_handle_mgmt_frame); + if (retStatus != CDF_STATUS_SUCCESS) + lim_log(pMac, LOGP, + FL("Registering the PE Handle with WMA has failed")); + +} + +/** + * lim_is_system_in_scan_state() + * + ***FUNCTION: + * This function is called by various MAC software modules to + * determine if System is in Scan/Learn state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return true - System is in Scan/Learn state + * false - System is NOT in Scan/Learn state + */ + +uint8_t lim_is_system_in_scan_state(tpAniSirGlobal pMac) +{ + switch (pMac->lim.gLimSmeState) { + case eLIM_SME_CHANNEL_SCAN_STATE: + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + case eLIM_SME_LINK_EST_WT_SCAN_STATE: + case eLIM_SME_WT_SCAN_STATE: + /* System is in Learn mode */ + return true; + + default: + /* System is NOT in Learn mode */ + return false; + } +} /*** end lim_is_system_in_scan_state() ***/ + +#ifdef WLAN_FEATURE_11W +/** + * lim_is_assoc_req_for_drop()- function to decides to drop assoc\reassoc + * frames. + * @mac: pointer to global mac structure + * @rx_pkt_info: rx packet meta information + * + * This function is called before enqueuing the frame to PE queue to + * drop flooded assoc/reassoc frames getting into PE Queue. + * + * Return: true for dropping the frame otherwise false + */ + +bool lim_is_assoc_req_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info) +{ + uint8_t session_id; + uint16_t aid; + tpPESession session_entry; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ds; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + session_entry = pe_find_session_by_bssid(mac, mac_hdr->bssId, + &session_id); + if (!session_entry) { + PELOG1(limLog(pMac, LOG1, + FL("session does not exist for given STA [%pM]"), + mac_hdr->sa);); + return false; + } + + sta_ds = dph_lookup_hash_entry(mac, mac_hdr->sa, &aid, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + PELOG1(limLog(pMac, LOG1, FL("pStaDs is NULL"));); + return false; + } + + if (!sta_ds->rmfEnabled) + return false; + + if (sta_ds->pmfSaQueryState == DPH_SA_QUERY_IN_PROGRESS) + return true; + + if (sta_ds->last_assoc_received_time && + ((cdf_mc_timer_get_system_ticks() - + sta_ds->last_assoc_received_time) < 1000)) + return true; + + sta_ds->last_assoc_received_time = cdf_mc_timer_get_system_ticks(); + return false; +} +#endif + +/** + * lim_is_deauth_diassoc_for_drop()- function to decides to drop deauth\diassoc + * frames. + * @mac: pointer to global mac structure + * @rx_pkt_info: rx packet meta information + * + * This function is called before enqueuing the frame to PE queue to + * drop flooded deauth/diassoc frames getting into PE Queue. + * + * Return: true for dropping the frame otherwise false + */ + +bool lim_is_deauth_diassoc_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info) +{ + uint8_t session_id; + uint16_t aid; + tpPESession session_entry; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ds; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + session_entry = pe_find_session_by_bssid(mac, mac_hdr->bssId, + &session_id); + if (!session_entry) { + PELOG1(limLog(mac, LOG1, + FL("session does not exist for given STA [%pM]"), + mac_hdr->sa);); + return true; + } + + sta_ds = dph_lookup_hash_entry(mac, mac_hdr->sa, &aid, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + PELOG1(limLog(mac, LOG1, FL("pStaDs is NULL"));); + return true; + } + +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) { + if ((WMA_GET_RX_DPU_FEEDBACK(rx_pkt_info) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + /* It may be possible that deauth/diassoc frames from a + * spoofy AP is received. So if all further + * deauth/diassoc frmaes are dropped, then it may + * result in lossing deauth/diassoc frames from genuine + * AP. So process all deauth/diassoc frames with + * a time difference of 1 sec. + */ + if ((cdf_mc_timer_get_system_ticks() - + sta_ds->last_unprot_deauth_disassoc) < 1000) + return true; + + sta_ds->last_unprot_deauth_disassoc = + cdf_mc_timer_get_system_ticks(); + } else { + /* PMF enabed, Management frames are protected */ + if (sta_ds->proct_deauh_disassoc_cnt) + return true; + else + sta_ds->proct_deauh_disassoc_cnt++; + } + } else +#endif + /* PMF disabled */ + { + if (sta_ds->is_disassoc_deauth_in_progress) + return true; + else + sta_ds->is_disassoc_deauth_in_progress++; + } + + return false; +} + +/** + *\brief lim_received_hb_handler() + * + * This function is called by sch_beacon_process() upon + * receiving a Beacon on STA. This also gets called upon + * receiving Probe Response after heat beat failure is + * detected. + * + * param pMac - global mac structure + * param channel - channel number indicated in Beacon, Probe Response + * return - none + */ + +void +lim_received_hb_handler(tpAniSirGlobal pMac, uint8_t channelId, + tpPESession psessionEntry) +{ + if ((channelId == 0) + || (channelId == psessionEntry->currentOperChannel)) + psessionEntry->LimRxedBeaconCntDuringHB++; + + psessionEntry->pmmOffloadInfo.bcnmiss = false; +} /*** lim_init_wds_info_params() ***/ + +/** ------------------------------------------------------------- + \fn lim_update_overlap_sta_param + \brief Updates overlap cache and param data structure + \param tpAniSirGlobal pMac + \param tSirMacAddr bssId + \param tpLimProtStaParams pStaParams + \return None + -------------------------------------------------------------*/ +void +lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams) +{ + int i; + if (!pStaParams->numSta) { + cdf_mem_copy(pMac->lim.protStaOverlapCache[0].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[0].active = true; + + pStaParams->numSta = 1; + + return; + } + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) { + if (pMac->lim.protStaOverlapCache[i].active) { + if (cdf_mem_compare + (pMac->lim.protStaOverlapCache[i].addr, bssId, + sizeof(tSirMacAddr))) { + return; + } + } else + break; + } + + if (i == LIM_PROT_STA_OVERLAP_CACHE_SIZE) { + PELOG1(lim_log(pMac, LOGW, FL("Overlap cache is full"));) + } else { + cdf_mem_copy(pMac->lim.protStaOverlapCache[i].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[i].active = true; + + pStaParams->numSta++; + } +} + +/** + * lim_ibss_enc_type_matched + * + ***FUNCTION: + * This function compares the encryption type of the peer with self + * while operating in IBSS mode and detects mismatch. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pBeacon - Parsed Beacon Frame structure + * @param pSession - Pointer to the PE session + * + * @return eSIR_TRUE if encryption type is matched; eSIR_FALSE otherwise + */ +static tAniBool lim_ibss_enc_type_matched(tpSchBeaconStruct pBeacon, + tpPESession pSession) +{ + if (!pBeacon || !pSession) + return eSIR_FALSE; + + /* Open case */ + if (pBeacon->capabilityInfo.privacy == 0 + && pSession->encryptType == eSIR_ED_NONE) + return eSIR_TRUE; + + /* WEP case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 0 + && pBeacon->rsnPresent == 0 + && (pSession->encryptType == eSIR_ED_WEP40 + || pSession->encryptType == eSIR_ED_WEP104)) + return eSIR_TRUE; + + /* WPA-None case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 1 + && pBeacon->rsnPresent == 0 + && ((pSession->encryptType == eSIR_ED_CCMP) || + (pSession->encryptType == eSIR_ED_TKIP))) + return eSIR_TRUE; + + return eSIR_FALSE; +} + +/** + * lim_handle_ibs_scoalescing() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pRxPacketInfo - Pointer to RX packet info structure + * + * @return Status whether to process or ignore received Beacon Frame + */ + +tSirRetStatus +lim_handle_ibss_coalescing(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo, tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tSirRetStatus retCode; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + /* Ignore the beacon when any of the conditions below is met: + 1. The beacon claims no IBSS network + 2. SSID in the beacon does not match SSID of self station + 3. Operational channel in the beacon does not match self station + 4. Encyption type in the beacon does not match with self station + */ + if ((!pBeacon->capabilityInfo.ibss) || + (lim_cmp_s_sid(pMac, &pBeacon->ssId, psessionEntry) != true) || + (psessionEntry->currentOperChannel != pBeacon->channelNumber)) + retCode = eSIR_LIM_IGNORE_BEACON; + else if (lim_ibss_enc_type_matched(pBeacon, psessionEntry) != eSIR_TRUE) { + PELOG3(lim_log(pMac, LOG3, + FL + ("peer privacy %d peer wpa %d peer rsn %d self encType %d"), + pBeacon->capabilityInfo.privacy, + pBeacon->wpaPresent, pBeacon->rsnPresent, + psessionEntry->encryptType); + ) + retCode = eSIR_LIM_IGNORE_BEACON; + } else { + uint32_t ieLen; + uint16_t tsfLater; + uint8_t *pIEs; + ieLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + tsfLater = WMA_GET_RX_TSF_LATER(pRxPacketInfo); + pIEs = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + PELOG3(lim_log + (pMac, LOG3, FL("BEFORE Coalescing tsfLater val :%d"), + tsfLater); + ) + retCode = + lim_ibss_coalesce(pMac, pHdr, pBeacon, pIEs, ieLen, tsfLater, + psessionEntry); + } + return retCode; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * lim_enc_type_matched() - matches security type of incoming beracon with + * current + * @mac_ctx Pointer to Global MAC structure + * @bcn Pointer to parsed Beacon structure + * @session PE session entry + * + * This function matches security type of incoming beracon with current + * + * @return true if matched, false otherwise + */ +static bool +lim_enc_type_matched(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + tpPESession session) +{ + if (!bcn || !session) + return false; + + lim_log(mac_ctx, LOG1, + FL("Beacon/Probe:: Privacy :%d WPA Present:%d RSN Present: %d"), + bcn->capabilityInfo.privacy, bcn->wpaPresent, bcn->rsnPresent); + lim_log(mac_ctx, LOG1, + FL("session:: Privacy :%d EncyptionType: %d"), + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps), + session->encryptType); + + /* + * This is handled by sending probe req due to IOT issues so + * return TRUE + */ + if ((bcn->capabilityInfo.privacy) != + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps)) { + lim_log(mac_ctx, LOGW, FL("Privacy bit miss match\n")); + return true; + } + + /* Open */ + if ((bcn->capabilityInfo.privacy == 0) && + (session->encryptType == eSIR_ED_NONE)) + return true; + + /* WEP */ + if ((bcn->capabilityInfo.privacy == 1) && + (bcn->wpaPresent == 0) && (bcn->rsnPresent == 0) && + ((session->encryptType == eSIR_ED_WEP40) || + (session->encryptType == eSIR_ED_WEP104) +#ifdef FEATURE_WLAN_WAPI + || (session->encryptType == eSIR_ED_WPI) +#endif + )) + return true; + + /* WPA OR RSN*/ + if ((bcn->capabilityInfo.privacy == 1) && + ((bcn->wpaPresent == 1) || (bcn->rsnPresent == 1)) && + ((session->encryptType == eSIR_ED_TKIP) || + (session->encryptType == eSIR_ED_CCMP) || + (session->encryptType == eSIR_ED_AES_128_CMAC))) + return true; + + return false; +} + +/** + * lim_detect_change_in_ap_capabilities() + * + ***FUNCTION: + * This function is called while SCH is processing + * received Beacon from AP on STA to detect any + * change in AP's capabilities. If there any change + * is detected, Roaming is informed of such change + * so that it can trigger reassociation. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * Notification is enabled for STA product only since + * it is not a requirement on BP side. + * + * @param pMac Pointer to Global MAC structure + * @param pBeacon Pointer to parsed Beacon structure + * @return None + */ + +void +lim_detect_change_in_ap_capabilities(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpPESession psessionEntry) +{ + uint8_t len; + tSirSmeApNewCaps apNewCaps; + uint8_t newChannel; + tSirRetStatus status = eSIR_SUCCESS; + bool security_caps_matched = true; + + apNewCaps.capabilityInfo = + lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + newChannel = (uint8_t) pBeacon->channelNumber; + + security_caps_matched = lim_enc_type_matched(pMac, pBeacon, + psessionEntry); + if ((false == psessionEntry->limSentCapsChangeNtf) && + (((!lim_is_null_ssid(&pBeacon->ssId)) && + (false == lim_cmp_s_sid(pMac, &pBeacon->ssId, psessionEntry))) || + ((SIR_MAC_GET_ESS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_ESS(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_PRIVACY(apNewCaps.capabilityInfo) != + SIR_MAC_GET_PRIVACY(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_SHORT_PREAMBLE(apNewCaps.capabilityInfo) != + SIR_MAC_GET_SHORT_PREAMBLE(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_QOS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_QOS(psessionEntry->limCurrentBssCaps)) || + ((newChannel != psessionEntry->currentOperChannel) && + (newChannel != 0)) || + (false == security_caps_matched) + ))) { + if (false == psessionEntry->fWaitForProbeRsp) { + /* If Beacon capabilities is not matching with the current capability, + * then send unicast probe request to AP and take decision after + * receiving probe response */ + if (true == psessionEntry->fIgnoreCapsChange) { + lim_log(pMac, LOGW, + FL + ("Ignoring the Capability change as it is false alarm")); + return; + } + psessionEntry->fWaitForProbeRsp = true; + lim_log(pMac, LOGW, + FL("AP capabilities are not matching," + "sending directed probe request.. ")); + status = + lim_send_probe_req_mgmt_frame(pMac, &psessionEntry->ssId, + psessionEntry->bssId, + psessionEntry-> + currentOperChannel, + psessionEntry->selfMacAddr, + psessionEntry->dot11mode, + 0, NULL); + + if (eSIR_SUCCESS != status) { + lim_log(pMac, LOGE, FL("send ProbeReq failed")); + psessionEntry->fWaitForProbeRsp = false; + } + return; + } + /** + * BSS capabilities have changed. + * Inform Roaming. + */ + len = sizeof(tSirMacCapabilityInfo) + sizeof(tSirMacAddr) + sizeof(uint8_t) + 3 * sizeof(uint8_t) + /* reserved fields */ + pBeacon->ssId.length + 1; + + cdf_mem_copy(apNewCaps.bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + if (newChannel != psessionEntry->currentOperChannel) { + PELOGE(lim_log + (pMac, LOGE, + FL("Channel Change from %d --> %d - " + "Ignoring beacon!"), + psessionEntry->currentOperChannel, newChannel); + ) + return; + } + + /** + * When Cisco 1262 Enterprise APs are configured with WPA2-PSK with + * AES+TKIP Pairwise ciphers and WEP-40 Group cipher, they do not set + * the privacy bit in Beacons (wpa/rsnie is still present in beacons), + * the privacy bit is set in Probe and association responses. + * Due to this anomaly, we detect a change in + * AP capabilities when we receive a beacon after association and + * disconnect from the AP. The following check makes sure that we can + * connect to such APs + */ + else if ((SIR_MAC_GET_PRIVACY(apNewCaps.capabilityInfo) == 0) && + (pBeacon->rsnPresent || pBeacon->wpaPresent)) { + PELOGE(lim_log + (pMac, LOGE, + FL("BSS Caps (Privacy) bit 0 in beacon," + " but WPA or RSN IE present, Ignore Beacon!")); + ) + return; + } else + apNewCaps.channelId = psessionEntry->currentOperChannel; + cdf_mem_copy((uint8_t *) &apNewCaps.ssId, + (uint8_t *) &pBeacon->ssId, + pBeacon->ssId.length + 1); + + psessionEntry->fIgnoreCapsChange = false; + psessionEntry->fWaitForProbeRsp = false; + psessionEntry->limSentCapsChangeNtf = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_AP_CAPS_CHANGED, + (uint32_t *) &apNewCaps, + len, psessionEntry->smeSessionId); + } else if (true == psessionEntry->fWaitForProbeRsp) { + /* Only for probe response frames and matching capabilities the control + * will come here. If beacon is with broadcast ssid then fWaitForProbeRsp + * will be false, the control will not come here*/ + + lim_log(pMac, LOG1, FL("capabilities in probe response are" + "matching with the current setting," + "Ignoring subsequent capability" + "mismatch")); + psessionEntry->fIgnoreCapsChange = true; + psessionEntry->fWaitForProbeRsp = false; + } + +} /*** lim_detect_change_in_ap_capabilities() ***/ + +/* --------------------------------------------------------------------- */ +/** + * lim_update_short_slot + * + * FUNCTION: + * Enable/Disable short slot + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short slot + * @return None + */ + +tSirRetStatus lim_update_short_slot(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + tSirSmeApNewCaps apNewCaps; + uint32_t nShortSlot; + uint32_t val = 0; + uint32_t phyMode; + + /* Check Admin mode first. If it is disabled just return */ + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed")); + return eSIR_FAILURE; + } + if (val == false) + return eSIR_SUCCESS; + + /* Check for 11a mode or 11b mode. In both cases return since slot time is constant and cannot/should not change in beacon */ + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + if ((phyMode == WNI_CFG_PHY_MODE_11A) + || (phyMode == WNI_CFG_PHY_MODE_11B)) + return eSIR_SUCCESS; + + apNewCaps.capabilityInfo = + lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + + /* Earlier implementation: determine the appropriate short slot mode based on AP advertised modes */ + /* when erp is present, apply short slot always unless, prot=on && shortSlot=off */ + /* if no erp present, use short slot based on current ap caps */ + + /* Issue with earlier implementation : Cisco 1231 BG has shortSlot = 0, erpIEPresent and useProtection = 0 (Case4); */ + + /* Resolution : always use the shortSlot setting the capability info to decide slot time. */ + /* The difference between the earlier implementation and the new one is only Case4. */ + /* + ERP IE Present | useProtection | shortSlot = QC STA Short Slot + Case1 1 1 1 1 //AP should not advertise this combination. + Case2 1 1 0 0 + Case3 1 0 1 1 + Case4 1 0 0 0 + Case5 0 1 1 1 + Case6 0 1 0 0 + Case7 0 0 1 1 + Case8 0 0 0 0 + */ + nShortSlot = SIR_MAC_GET_SHORT_SLOT_TIME(apNewCaps.capabilityInfo); + + if (nShortSlot != psessionEntry->shortSlotTimeSupported) { + /* Short slot time capability of AP has changed. Adopt to it. */ + PELOG1(lim_log + (pMac, LOG1, + FL("Shortslot capability of AP changed: %d"), + nShortSlot); + ) + ((tpSirMacCapabilityInfo) & psessionEntry-> + limCurrentBssCaps)->shortSlotTime = (uint16_t) nShortSlot; + psessionEntry->shortSlotTimeSupported = nShortSlot; + pBeaconParams->fShortSlotTime = (uint8_t) nShortSlot; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + } + return eSIR_SUCCESS; +} + + +void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t statusCode; + tSirMsgQ msg; + + /* Prepare and post message to LIM Message Queue */ + msg.type = (uint16_t) SIR_LIM_HEART_BEAT_TIMEOUT; + msg.bodyptr = psessionEntry; + msg.bodyval = 0; + lim_log(pMac, LOGE, FL("Heartbeat failure from Fw")); + + statusCode = lim_post_msg_api(pMac, &msg); + + if (statusCode != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("posting message %X to LIM failed, reason=%d"), + msg.type, statusCode); + } +} + +/** + * lim_ps_offload_handle_missed_beacon_ind(): handles missed beacon indication + * @pMac : global mac context + * @pMsg: message + * + * This function process the SIR_HAL_MISSED_BEACON_IND + * message from HAL, to do active AP probing. + * + * Return: void + */ +void lim_ps_offload_handle_missed_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + tpSirSmeMissedBeaconInd pSirMissedBeaconInd = + (tpSirSmeMissedBeaconInd) pMsg->bodyptr; + tpPESession psessionEntry = + pe_find_session_by_bss_idx(pMac, pSirMissedBeaconInd->bssIdx); + + if (!psessionEntry) { + lim_log(pMac, LOGE, + FL("session does not exist for given BSSId")); + return; + } + + /* Set Beacon Miss in Powersave Offload */ + psessionEntry->pmmOffloadInfo.bcnmiss = true; + PELOGE(lim_log(pMac, LOGE, + FL("Received Heart Beat Failure"));) + + /* Do AP probing immediately */ + lim_send_heart_beat_timeout_ind(pMac, psessionEntry); + return; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS lim_roam_fill_bss_descr(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_offload_synch_ind_ptr) +{ + uint32_t ie_len = 0; + tpSirProbeRespBeacon parsed_frm_ptr; + tpSirMacMgmtHdr mac_hdr; + uint8_t *bcn_proberesp_ptr; + tSirBssDescription *bss_desc_ptr = NULL; + + bcn_proberesp_ptr = (uint8_t *)roam_offload_synch_ind_ptr + + roam_offload_synch_ind_ptr->beaconProbeRespOffset; + mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr; + parsed_frm_ptr = + (tpSirProbeRespBeacon) cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == parsed_frm_ptr) { + lim_log(pMac, LOGE, "fail to allocate memory for frame"); + return CDF_STATUS_E_NOMEM; + } + + if (roam_offload_synch_ind_ptr->beaconProbeRespLength <= + SIR_MAC_HDR_LEN_3A) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, "%s: very" + "few bytes in synchInd beacon / probe resp frame! length=%d", + __func__, roam_offload_synch_ind_ptr->beaconProbeRespLength); + cdf_mem_free(parsed_frm_ptr); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + "LFR3: Beacon/Prb Rsp:"); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + bcn_proberesp_ptr, roam_offload_synch_ind_ptr->beaconProbeRespLength); + if (roam_offload_synch_ind_ptr->isBeacon) { + if (sir_parse_beacon_ie(pMac, parsed_frm_ptr, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A) != eSIR_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "Parse error Beacon, length=%d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + cdf_mem_free(parsed_frm_ptr); + return CDF_STATUS_E_FAILURE; + } + } else { + if (sir_convert_probe_frame2_struct(pMac, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A, parsed_frm_ptr) != eSIR_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "Parse error ProbeResponse, length=%d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + cdf_mem_free(parsed_frm_ptr); + return CDF_STATUS_E_FAILURE; + } + } + /* 24 byte MAC header and 12 byte to ssid IE */ + if (roam_offload_synch_ind_ptr->beaconProbeRespLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + ie_len = roam_offload_synch_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } + /* + * Memory allocated below is freed up in csrProcessRoamOffloadSynchInd + */ + roam_offload_synch_ind_ptr->bss_desc_ptr = + cdf_mem_malloc(sizeof (tSirBssDescription) + ie_len); + bss_desc_ptr = roam_offload_synch_ind_ptr->bss_desc_ptr; + if (NULL == bss_desc_ptr) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3:Failed to allocate memory"); + CDF_ASSERT(bss_desc_ptr != NULL); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(bss_desc_ptr, sizeof(tSirBssDescription)); + + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + bss_desc_ptr->length = (uint16_t) (offsetof(tSirBssDescription, + ieFields[0]) - + sizeof(bss_desc_ptr->length) + ie_len); + + if (parsed_frm_ptr->dsParamsPresent) { + bss_desc_ptr->channelId = parsed_frm_ptr->channelNumber; + } else if (parsed_frm_ptr->HTInfo.present) { + bss_desc_ptr->channelId = parsed_frm_ptr->HTInfo.primaryChannel; + } else { + /* + * If DS Params or HTIE is not present in the probe resp or + * beacon, then use the channel frequency provided by firmware + * to fill the channel in the BSS descriptor.*/ + bss_desc_ptr->channelId = + cds_freq_to_chan(roam_offload_synch_ind_ptr->chan_freq); + } + bss_desc_ptr->channelIdSelf = bss_desc_ptr->channelId; + + if ((bss_desc_ptr->channelId > 0) && (bss_desc_ptr->channelId < 15)) { + int i; + /* * + * 11b or 11g packet + * 11g if extended Rate IE is present or + * if there is an A rate in suppRate IE + * */ + for (i = 0; i < parsed_frm_ptr->supportedRates.numRates; i++) { + if (sirIsArate(parsed_frm_ptr->supportedRates.rate[i] & + 0x7f)) { + bss_desc_ptr->nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (parsed_frm_ptr->extendedRatesPresent) { + bss_desc_ptr->nwType = eSIR_11G_NW_TYPE; + } + } else { + /* 11a packet */ + bss_desc_ptr->nwType = eSIR_11A_NW_TYPE; + } + + bss_desc_ptr->sinr = 0; + bss_desc_ptr->beaconInterval = parsed_frm_ptr->beaconInterval; + bss_desc_ptr->timeStamp[0] = parsed_frm_ptr->timeStamp[0]; + bss_desc_ptr->timeStamp[1] = parsed_frm_ptr->timeStamp[1]; + cdf_mem_copy(&bss_desc_ptr->capabilityInfo, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_CAPAB_OFFSET], 2); + cdf_mem_copy((uint8_t *) &bss_desc_ptr->bssId, + (uint8_t *) mac_hdr->bssId, + sizeof(tSirMacAddr)); + bss_desc_ptr->nReceivedTime = + (uint32_t)cdf_mc_timer_get_system_ticks(); + if (parsed_frm_ptr->mdiePresent) { + bss_desc_ptr->mdiePresent = parsed_frm_ptr->mdiePresent; + cdf_mem_copy((uint8_t *)bss_desc_ptr->mdie, + (uint8_t *)parsed_frm_ptr->mdie, + SIR_MDIE_SIZE); + } + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:%s:BssDescr Info:", __func__); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + bss_desc_ptr->bssId, sizeof(tSirMacAddr)); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "chan=%d, rssi=%d", bss_desc_ptr->channelId, + bss_desc_ptr->rssi); + if (ie_len) { + cdf_mem_copy(&bss_desc_ptr->ieFields, + bcn_proberesp_ptr + + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET), + ie_len); + } + cdf_mem_free(parsed_frm_ptr); + return CDF_STATUS_SUCCESS; +} + +/**----------------------------------------------------------------- + * brief lim_roam_offload_synch_ind() - Handles Roam Synch Indication + * param pMac - global mac structure + * return - none + *----------------------------------------------------------------- + **/ +void lim_roam_offload_synch_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + tpPESession session_ptr; + tpPESession ft_session_ptr; + uint8_t session_id; + tSirMsgQ mmh_msg; + tSirBssDescription *bss_desc_ptr = NULL; + roam_offload_synch_ind *roam_sync_ind_ptr = + (roam_offload_synch_ind *)pMsg->bodyptr; + + if (!roam_sync_ind_ptr) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3:%s:roam_sync_ind_ptr is NULL", __func__); + return; + } + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3: Received WMA_ROAM_OFFLOAD_SYNCH_IND"); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:%s:authStatus=%d, vdevId=%d", __func__, + roam_sync_ind_ptr->authStatus, + roam_sync_ind_ptr->roamedVdevId); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + roam_sync_ind_ptr->bssId, 6); + session_ptr = pe_find_session_by_bss_idx(pMac, + roam_sync_ind_ptr->roamedVdevId); + if (session_ptr == NULL) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "%s: LFR3:Unable to find session", __func__); + return; + } + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session_ptr)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "session is not in STA mode"); + return; + } + if (!CDF_IS_STATUS_SUCCESS(lim_roam_fill_bss_descr(pMac, + roam_sync_ind_ptr))) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3:%s:Failed to fill Bss Descr", __func__); + return; + } + bss_desc_ptr = roam_sync_ind_ptr->bss_desc_ptr; + ft_session_ptr = pe_create_session(pMac, bss_desc_ptr->bssId, + &session_id, pMac->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (ft_session_ptr == NULL) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3: Session Can't be created for new AP during Roam Synch"); + lim_print_mac_addr(pMac, bss_desc_ptr->bssId, LOGE); + return; + } + ft_session_ptr->peSessionId = session_id; + sir_copy_mac_addr(ft_session_ptr->selfMacAddr, session_ptr->selfMacAddr); + sir_copy_mac_addr(ft_session_ptr->limReAssocbssId, bss_desc_ptr->bssId); + ft_session_ptr->bssType = eSIR_INFRASTRUCTURE_MODE; + /** + * Set bRoamSynchInProgress here since this session is + *specific to roam synch indication. This flag will + *later be used to differentiate LFR3 with LFR2 in LIM + **/ + ft_session_ptr->bRoamSynchInProgress = true; + + if (ft_session_ptr->bssType == eSIR_INFRASTRUCTURE_MODE) { + ft_session_ptr->limSystemRole = eLIM_STA_ROLE; + } else { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "LFR3:Invalid bss type"); + return; + } + ft_session_ptr->limPrevSmeState = ft_session_ptr->limSmeState; + ft_session_ptr->limSmeState = eLIM_SME_WT_REASSOC_STATE; + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:%s:created session (%p) with id = %d", + __func__, ft_session_ptr, ft_session_ptr->peSessionId); + /* Update the ReAssoc BSSID of the current session */ + sir_copy_mac_addr(session_ptr->limReAssocbssId, bss_desc_ptr->bssId); + lim_print_mac_addr(pMac, session_ptr->limReAssocbssId, LOG2); + + /* Prepare the session right now with as much as possible */ + lim_fill_ft_session(pMac, bss_desc_ptr, ft_session_ptr, session_ptr); + lim_ft_prepare_add_bss_req(pMac, false, ft_session_ptr, bss_desc_ptr); + mmh_msg.type = + roam_sync_ind_ptr->messageType; + /* eWNI_SME_ROAM_OFFLOAD_SYNCH_IND */ + mmh_msg.bodyptr = roam_sync_ind_ptr; + mmh_msg.bodyval = 0; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:%s:sending eWNI_SME_ROAM_OFFLOAD_SYNCH_IND", __func__); + lim_sys_process_mmh_msg_api(pMac, &mmh_msg, ePROT); +} +#endif + +uint8_t lim_is_beacon_miss_scenario(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + uint8_t sessionId; + tpPESession psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, &sessionId); + + if (psessionEntry && psessionEntry->pmmOffloadInfo.bcnmiss) + return true; + return false; +} + +/** ----------------------------------------------------------------- + \brief lim_is_pkt_candidate_for_drop() - decides whether to drop the frame or not + + This function is called before enqueuing the frame to PE queue for further processing. + This prevents unnecessary frames getting into PE Queue and drops them right away. + Frames will be droped in the following scenarios: + + - In Scan State, drop the frames which are not marked as scan frames + - In non-Scan state, drop the frames which are marked as scan frames. + - Drop INFRA Beacons and Probe Responses in IBSS Mode + - Drop the Probe Request in IBSS mode, if STA did not send out the last beacon + + \param pMac - global mac structure + \return - none + \sa + ----------------------------------------------------------------- */ + +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType) +{ + uint32_t framelen; + uint8_t *pBody; + tSirMacCapabilityInfo capabilityInfo; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + + /* + * + * In scan mode, drop only Beacon/Probe Response which are NOT marked as scan-frames. + * In non-scan mode, drop only Beacon/Probe Response which are marked as scan frames. + * Allow other mgmt frames, they must be from our own AP, as we don't allow + * other than beacons or probe responses in scan state. + */ + if ((subType == SIR_MAC_MGMT_BEACON) || + (subType == SIR_MAC_MGMT_PROBE_RSP)) { + if (lim_is_beacon_miss_scenario(pMac, pRxPacketInfo)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_INFO_LOG, 0, + eLOG_NODROP_MISSED_BEACON_SCENARIO)); + return eMGMT_DROP_NO_DROP; + } + if (lim_is_system_in_scan_state(pMac)) { + return eMGMT_DROP_NO_DROP; + } else if (WMA_IS_RX_IN_SCAN(pRxPacketInfo)) { + return eMGMT_DROP_SCAN_MODE_FRAME; + } else { + /* Beacons and probe responses can come in any time + * because of parallel scans. Don't drop them. + */ + return eMGMT_DROP_NO_DROP; + } + } + + if ((subType == SIR_MAC_MGMT_DEAUTH || + subType == SIR_MAC_MGMT_DISASSOC) && + lim_is_deauth_diassoc_for_drop(pMac, pRxPacketInfo)) + return eMGMT_DROP_SPURIOUS_FRAME; + +#ifdef WLAN_FEATURE_11W + if ((subType == SIR_MAC_MGMT_ASSOC_REQ || + subType == SIR_MAC_MGMT_REASSOC_REQ) && + lim_is_assoc_req_for_drop(pMac, pRxPacketInfo)) + return eMGMT_DROP_SPURIOUS_FRAME; +#endif + + framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + /* Drop INFRA Beacons and Probe Responses in IBSS Mode */ + if ((subType == SIR_MAC_MGMT_BEACON) || + (subType == SIR_MAC_MGMT_PROBE_RSP)) { + /* drop the frame if length is less than 12 */ + if (framelen < LIM_MIN_BCN_PR_LENGTH) + return eMGMT_DROP_INVALID_SIZE; + + *((uint16_t *) &capabilityInfo) = + sir_read_u16(pBody + LIM_BCN_PR_CAPABILITY_OFFSET); + + /* Note sure if this is sufficient, basically this condition allows all probe responses and + * beacons from an infrastructure network + */ + if (!capabilityInfo.ibss) + return eMGMT_DROP_NO_DROP; + + /* This can be enhanced to even check the SSID before deciding to enque the frame. */ + if (capabilityInfo.ess) + return eMGMT_DROP_INFRA_BCN_IN_IBSS; + } else if ((subType == SIR_MAC_MGMT_PROBE_REQ) && + (!WMA_GET_RX_BEACON_SENT(pRxPacketInfo))) { + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, &sessionId); + if ((psessionEntry && !LIM_IS_IBSS_ROLE(psessionEntry)) || + (!psessionEntry)) + return eMGMT_DROP_NO_DROP; + + /* Drop the Probe Request in IBSS mode, if STA did not send out the last beacon */ + /* In IBSS, the node which sends out the beacon, is supposed to respond to ProbeReq */ + return eMGMT_DROP_NOT_LAST_IBSS_BCN; + } + + return eMGMT_DROP_NO_DROP; +} + +CDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + + if (psPe) { + if (CDF_IS_STATUS_SUCCESS + (cdf_mutex_acquire(&psPe->lkPeGlobalLock))) { + status = CDF_STATUS_SUCCESS; + } + } + return status; +} + +CDF_STATUS pe_release_global_lock(tAniSirLim *psPe) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + if (psPe) { + if (CDF_IS_STATUS_SUCCESS + (cdf_mutex_release(&psPe->lkPeGlobalLock))) { + status = CDF_STATUS_SUCCESS; + } + } + return status; +} + diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c new file mode 100644 index 0000000000..a1680d6bab --- /dev/null +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -0,0 +1,5132 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_assoc_utils.cc contains the utility functions + * LIM uses while processing (Re) Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "wni_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" + +#include "cdf_types.h" +#include "wma_types.h" +#include "lim_types.h" + +/* + * fill up the rate info properly based on what is actually supported by the peer + * TBD TBD TBD + */ +void +lim_fill_supported_rates_info(tpAniSirGlobal pMac, + tpDphHashNode pSta, + tpSirSupportedRates pRates, tpPESession psessionEntry) +{ + /* pSta will be NULL for self entry, so get the opRateMode based on the self mode. */ + /* For the peer entry get it from the peer Capabilities present in hash table */ + if (pSta == NULL) + pRates->opRateMode = + lim_get_sta_rate_mode((uint8_t) psessionEntry->dot11mode); + else + pRates->opRateMode = + lim_get_sta_peer_type(pMac, pSta, psessionEntry); + +} + +/** + * lim_cmp_s_sid() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether received SSid is same as SSID in use. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param *prxSSid - pointer to SSID structure + * + * @return status - true for SSID match else false. + */ + +uint8_t +lim_cmp_s_sid(tpAniSirGlobal pMac, tSirMacSSid *prxSSid, + tpPESession psessionEntry) +{ + + if (cdf_mem_compare + ((uint8_t *) prxSSid, (uint8_t *) &psessionEntry->ssId, + (uint8_t) (psessionEntry->ssId.length + 1))) + return true; + else + return false; + +} /****** end lim_cmp_s_sid() ******/ + +/** + * lim_compare_capabilities() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received capabilities + * match with local capabilities or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pAssocReq - Pointer to received Assoc Req frame + * @param pLocalCapabs - Pointer to local capabilities + * + * @return status - true for Capabilitity match else false. + */ + +uint8_t +lim_compare_capabilities(tpAniSirGlobal pMac, + tSirAssocReq *pAssocReq, + tSirMacCapabilityInfo *pLocalCapabs, + tpPESession psessionEntry) +{ + uint32_t val; + + if ((LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) && + (pAssocReq->capabilityInfo.ibss)) { + /* Requesting STA asserting IBSS capability. */ + lim_log(pMac, LOG1, + FL("Requesting STA asserting IBSS capability")); + return false; + } + /* Compare CF capabilities */ + if (pAssocReq->capabilityInfo.cfPollable || + pAssocReq->capabilityInfo.cfPollReq) { + /* AP does not support PCF functionality */ + lim_log(pMac, LOG1, + FL(" AP does not support PCF functionality")); + return false; + } + /* Compare short preamble capability */ + if (pAssocReq->capabilityInfo.shortPreamble && + (pAssocReq->capabilityInfo.shortPreamble != + pLocalCapabs->shortPreamble)) { + /* Allowing a STA requesting short preamble while */ + /* AP does not support it */ + } + + lim_log(pMac, LOG1, "QoS in AssocReq: %d, local capabs qos: %d", + pAssocReq->capabilityInfo.qos, pLocalCapabs->qos); + + /* Compare QoS capability */ + if (pAssocReq->capabilityInfo.qos && + (pAssocReq->capabilityInfo.qos != pLocalCapabs->qos)) { + /*Temporary hack for UPF to skip 11e capability check in order to interop with + CSR - proper fix needs to be put in place */ + lim_log(pMac, LOG1, + FL + ("Received unmatched QOS but cfg to suppress - continuing")); + } + + /* + * If AP supports shortSlot and if apple user has + * enforced association only from shortSlot station, + * then AP must reject any station that does not support + * shortSlot + */ + if ((LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) && + (pLocalCapabs->shortSlotTime == 1)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("error getting WNI_CFG_FORCE_SHORT_SLOT_ASSOC_ONLY ")); + return false; + } + if (val) { + if (pAssocReq->capabilityInfo.shortSlotTime != + pLocalCapabs->shortSlotTime) { + lim_log(pMac, LOGE, + FL + ("AP rejects association as station doesnt support shortslot time")); + return false; + } + return false; + } + } + + return true; +} /****** end lim_compare_capabilities() ******/ + +/** + * lim_check_rx_basic_rates() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received rates in + * Assoc/Reassoc request frames include all BSS basic rates + * or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param rxRateSet - pointer to SSID structure + * + * @return status - true if ALL BSS basic rates are present in the + * received rateset else false. + */ + +uint8_t +lim_check_rx_basic_rates(tpAniSirGlobal pMac, tSirMacRateSet rxRateSet, + tpPESession psessionEntry) +{ + tSirMacRateSet *pRateSet, basicRate; + uint8_t i, j, k, match; + + pRateSet = cdf_mem_malloc(sizeof(tSirMacRateSet)); + if (NULL == pRateSet) { + lim_log(pMac, LOGP, + FL("call to AllocateMemory failed for RATESET")); + + return false; + } + + /* Copy operational rate set from session Entry */ + cdf_mem_copy(pRateSet->rate, (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + + pRateSet->numRates = psessionEntry->rateSet.numRates; + + /* Extract BSS basic rateset from operational rateset */ + for (i = 0, j = 0; + ((i < pRateSet->numRates) && (i < SIR_MAC_RATESET_EID_MAX)); i++) { + if ((pRateSet->rate[i] & 0x80) == 0x80) { + /* msb is set, so this is a basic rate */ + basicRate.rate[j++] = pRateSet->rate[i]; + } + } + + /* + * For each BSS basic rate, find if it is present in the + * received rateset. + */ + for (k = 0; k < j; k++) { + match = 0; + for (i = 0; + ((i < rxRateSet.numRates) + && (i < SIR_MAC_RATESET_EID_MAX)); i++) { + if ((rxRateSet.rate[i] | 0x80) == basicRate.rate[k]) + match = 1; + } + + if (!match) { + /* Free up memory allocated for rateset */ + cdf_mem_free((uint8_t *) pRateSet); + + return false; + } + } + + /* Free up memory allocated for rateset */ + cdf_mem_free((uint8_t *) pRateSet); + + return true; +} /****** end lim_check_rx_basic_rates() ******/ + +/** + * lim_check_mcs_set() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received MCS rates in + * Assoc/Reassoc request frames includes all Basic MCS Rate Set or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param supportedMCSSet - pointer to Supported MCS Rate Set + * + * @return status - true if ALL MCS Basic Rate Set rates are present in the + * received rateset else false. + */ + +uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet) +{ + uint8_t basicMCSSet[SIZE_OF_BASIC_MCS_SET] = { 0 }; + uint32_t cfgLen = 0; + uint8_t i; + uint8_t validBytes; + uint8_t lastByteMCSMask = 0x1f; + + cfgLen = WNI_CFG_BASIC_MCS_SET_LEN; + if (wlan_cfg_get_str(pMac, WNI_CFG_BASIC_MCS_SET, + (uint8_t *) basicMCSSet, + (uint32_t *) &cfgLen) != eSIR_SUCCESS) { + /* / Could not get Basic MCS rateset from CFG. Log error. */ + lim_log(pMac, LOGP, FL("could not retrieve Basic MCS rateset")); + return false; + } + + validBytes = VALID_MCS_SIZE / 8; + + /* check if all the Basic MCS Bits are set in supported MCS bitmap */ + for (i = 0; i < validBytes; i++) { + if ((basicMCSSet[i] & supportedMCSSet[i]) != basicMCSSet[i]) { + /* Log is avaiable in calling function in file lim_process_assoc_req_frame.c */ + lim_log(pMac, LOGW, + FL + ("One of Basic MCS Set Rates is not supported by the Station.")); + return false; + } + } + + /* check the last 5 bits of the valid MCS bitmap */ + if (((basicMCSSet[i] & lastByteMCSMask) & + (supportedMCSSet[i] & lastByteMCSMask)) != + (basicMCSSet[i] & lastByteMCSMask)) { + lim_log(pMac, LOGW, + FL + ("One of Basic MCS Set Rates is not supported by the Station.")); + return false; + } + + return true; +} + +#define SECURITY_SUITE_TYPE_MASK 0xFF +#define SECURITY_SUITE_TYPE_WEP40 0x1 +#define SECURITY_SUITE_TYPE_TKIP 0x2 +#define SECURITY_SUITE_TYPE_CCMP 0x4 +#define SECURITY_SUITE_TYPE_WEP104 0x4 + +/** + * lim_check_rx_rsn_ie_match()- validate received rsn ie with supported cipher + * suites. + * @mac_ctx: pointer to global mac structure + * @rx_rsn_ie: received rsn IE + * @session_entry: pe session entry + * @sta_is_ht: peer station HT capability + * @pmf_connection: set to true if this is pmf connection + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: eSIR_SUCCESS if ALL BSS basic rates are present in the + * received rateset else failure status. + */ + +uint8_t +lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, tDot11fIERSN rx_rsn_ie, + tpPESession session_entry, uint8_t sta_is_ht, + bool *pmf_connection) +{ + tDot11fIERSN *rsn_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; +#ifdef WLAN_FEATURE_11W + bool we_are_pmf_capable; + bool we_require_pmf; + bool they_are_pmf_capable; + bool they_require_pmf; +#endif + + /* RSN IE should be received from PE */ + rsn_ie = &session_entry->gStartBssRSNIe; + + /* Check groupwise cipher suite */ + for (i = 0; i < sizeof(rx_rsn_ie.gp_cipher_suite); i++) + if (rsn_ie->gp_cipher_suite[i] != + rx_rsn_ie.gp_cipher_suite[i]) { + lim_log(mac_ctx, LOG3, + FL("Invalid groupwise cipher suite")); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_rsn_ie.pwise_cipher_suite_count; i++) { + for (j = 0; j < rsn_ie->pwise_cipher_suite_count; j++) { + if (cdf_mem_compare(&rx_rsn_ie.pwise_cipher_suites[i], + &rsn_ie->pwise_cipher_suites[j], + sizeof(rsn_ie->pwise_cipher_suites[j]))) { + match = 1; + break; + } + } + + if ((sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + && + ((rx_rsn_ie.pwise_cipher_suites[i][3] & + SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#else + && + ((rx_rsn_ie.pwise_cipher_suites[i][0] & + SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#endif + only_non_ht_cipher = 0; + + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + lim_log(mac_ctx, LOG1, FL("Invalid pairwise cipher suite")); + return eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS; + } + /* + * Check RSN capabilities + * Bit 0 of First Byte - PreAuthentication Capability + */ + if (((rx_rsn_ie.RSN_Cap[0] >> 0) & 0x1) == true) { + /* this is supported by AP only */ + lim_log(mac_ctx, LOG1, + FL("Invalid RSN information element capabilities")); + return eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS; + } + + *pmf_connection = false; + +#ifdef WLAN_FEATURE_11W + we_are_pmf_capable = session_entry->pLimStartBssReq->pmfCapable; + we_require_pmf = session_entry->pLimStartBssReq->pmfRequired; + they_are_pmf_capable = (rx_rsn_ie.RSN_Cap[0] >> 7) & 0x1; + they_require_pmf = (rx_rsn_ie.RSN_Cap[0] >> 6) & 0x1; + + if ((they_require_pmf && they_are_pmf_capable && !we_are_pmf_capable) || + (we_require_pmf && !they_are_pmf_capable)) { + lim_log(mac_ctx, LOG1, + FL("Association fail, robust management frames policy" + " violation they_require_pmf =%d" + " theyArePMFCapable %d weArePMFCapable %d" + " weRequirePMF %d theyArePMFCapable %d"), + they_require_pmf, they_are_pmf_capable, + we_are_pmf_capable, we_require_pmf, + they_are_pmf_capable); + return eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION; + } + + if (they_are_pmf_capable && we_are_pmf_capable) + *pmf_connection = true; + + lim_log(mac_ctx, LOG1, + FL("weAreCapable %d, weRequire %d, theyAreCapable %d," + " theyRequire %d, PMFconnection %d"), + we_are_pmf_capable, we_require_pmf, they_are_pmf_capable, + they_require_pmf, *pmf_connection); +#endif + + return eSIR_SUCCESS; +} + +/** + * lim_check_rx_wpa_ie_match() - to check supported cipher suites + * + * @mac: pointer to global mac structure + * @rx_wpaie: Received WPA IE in (Re)Assco req + * @session_entry: pointer to PE session + * @sta_is_ht: peer station is HT + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: Success if ALL BSS basic rates are present in the + * received rateset else failure status. + */ + +uint8_t +lim_check_rx_wpa_ie_match(tpAniSirGlobal mac, tDot11fIEWPA rx_wpaie, + tpPESession session_entry, uint8_t sta_is_ht) +{ + tDot11fIEWPA *wpa_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; + + /* WPA IE should be received from PE */ + wpa_ie = &session_entry->gStartBssWPAIe; + + /* Check groupwise cipher suite */ + for (i = 0; i < 4; i++) { + if (wpa_ie->multicast_cipher[i] != rx_wpaie.multicast_cipher[i]) { + lim_log(mac, LOG1, + FL("Invalid groupwise cipher suite")); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_wpaie.unicast_cipher_count; i++) { + for (j = 0; j < wpa_ie->unicast_cipher_count; j++) { + if (cdf_mem_compare(rx_wpaie.unicast_ciphers[i], + wpa_ie->unicast_ciphers[j], 4)) { + match = 1; + break; + } + } + + if ((sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + && + ((rx_wpaie. + unicast_ciphers[i][3] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#else + && + ((rx_wpaie. + unicast_ciphers[i][0] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#endif + { + only_non_ht_cipher = 0; + } + + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + lim_log(mac, LOG1, FL("Invalid pairwise cipher suite")); + return eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS; + } + + return eSIR_SUCCESS; +} + +/** + * lim_cleanup_rx_path() + * + ***FUNCTION: + * This function is called to cleanup STA state at SP & RFP. + * + ***LOGIC: + * To circumvent RFP's handling of dummy packet when it does not + * have an incomplete packet for the STA to be deleted, a packet + * with 'more framgents' bit set will be queued to RFP's WQ before + * queuing 'dummy packet'. + * A 'dummy' BD is pushed into RFP's WQ with type=00, subtype=1010 + * (Disassociation frame) and routing flags in BD set to eCPU's + * Low Priority WQ. + * RFP cleans up its local context for the STA id mentioned in the + * BD and then pushes BD to eCPU's low priority WQ. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pStaDs Pointer to the per STA data structure + * initialized by LIM and maintained at DPH + * + * @return None + */ + +tSirRetStatus +lim_cleanup_rx_path(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + + lim_log(pMac, LOG1, FL("Cleanup Rx Path for AID : %d" + "psessionEntry->limSmeState : %d, mlmState : %d"), + pStaDs->assocId, psessionEntry->limSmeState, + pStaDs->mlmStaContext.mlmState); + + psessionEntry->isCiscoVendorAP = false; + + if (pMac->lim.gLimAddtsSent) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_ADDTS_RSP_TIMER)); + tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer); + } + + if (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_ASSOC_CNF_STATE) { + lim_deactivate_and_change_per_sta_id_timer(pMac, eLIM_CNF_WAIT_TIMER, + pStaDs->assocId); + + if (!pStaDs->mlmStaContext.updateContext) { + /** + * There is no context at Polaris to delete. + * Release our assigned AID back to the free pool + */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + lim_release_peer_idx(pMac, pStaDs->assocId, + psessionEntry); + } + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + + return retCode; + } + } + /* delete all tspecs associated with this sta. */ + lim_admit_control_delete_sta(pMac, pStaDs->assocId); + + /** + * Make STA hash entry invalid at eCPU so that DPH + * does not process any more data packets and + * releases those BDs + */ + pStaDs->valid = 0; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Deactivating probe after heart beat timer */ + lim_deactivate_and_change_timer(pMac, eLIM_PROBE_AFTER_HB_TIMER); + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + pMac->lim.gLastBeaconDtimCount = 0; + pMac->lim.gLastBeaconDtimPeriod = 0; + +#ifdef FEATURE_WLAN_ESE +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); +#else + lim_deactivate_and_change_timer(pMac, eLIM_TSM_TIMER); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ +#endif + + } +#ifdef WLAN_DEBUG + /* increment a debug count */ + pMac->lim.gLimNumRxCleanup++; +#endif + + if (psessionEntry->limSmeState == eLIM_SME_JOIN_FAILURE_STATE) { + retCode = + lim_del_bss(pMac, pStaDs, psessionEntry->bssIdx, + psessionEntry); + } else + retCode = lim_del_sta(pMac, pStaDs, true, psessionEntry); + + return retCode; + +} /*** end lim_cleanup_rx_path() ***/ + +/** + * lim_send_del_sta_cnf() + * + ***FUNCTION: + * This function is called to send appropriate CNF message to SME + * + ***LOGIC: + * + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param tpAniSirGlobal pMac, + * @param tSirMacAddr staDsAddr, + * @param uint16_t staDsAssocId, + * @param tLimMlmStaContext mlmStaContext, + * @param tSirResultCodes statusCode + * + * @return None + */ + +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry) +{ + + tLimMlmDisassocCnf mlmDisassocCnf; + tLimMlmDeauthCnf mlmDeauthCnf; + tLimMlmPurgeStaInd mlmPurgeStaInd; + + lim_log(pMac, LOG1, FL("Sessionid: %d staDsAssocId: %d Trigger: %d" + "statusCode: %d staDsAddr: " MAC_ADDRESS_STR), + psessionEntry->peSessionId, staDsAssocId, + mlmStaContext.cleanupTrigger, statusCode, + MAC_ADDR_ARRAY(staDsAddr)); + + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + /* Set BSSID at CFG to null */ + tSirMacAddr nullAddr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + sir_copy_mac_addr(nullAddr, psessionEntry->bssId); + + /* Free up buffer allocated for JoinReq held by */ + /* MLM state machine */ + if (psessionEntry->pLimMlmJoinReq) { + cdf_mem_free(psessionEntry->pLimMlmJoinReq); + psessionEntry->pLimMlmJoinReq = NULL; + } + + psessionEntry->limAID = 0; + + } + + if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DISASSOC) || + (mlmStaContext.cleanupTrigger == eLIM_PROMISCUOUS_MODE_DISASSOC)) { + /** + * Host or LMM driven Disassociation. + * Issue Disassoc Confirm to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting DISASSOC_CNF to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + + cdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) staDsAddr, sizeof(tSirMacAddr)); + mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DEAUTH) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DEAUTH)) { + /** + * Host or LMM driven Deauthentication. + * Issue Deauth Confirm to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting DEAUTH_CNF to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + cdf_mem_copy((uint8_t *) &mlmDeauthCnf.peerMacAddr, + (uint8_t *) staDsAddr, sizeof(tSirMacAddr)); + mlmDeauthCnf.resultCode = statusCode; + mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; + /* PE session Id */ + mlmDeauthCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_CNF, + (uint32_t *) &mlmDeauthCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_PEER_ENTITY_DISASSOC) || + (mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DEAUTH)) { + /** + * Received Disassociation/Deauthentication from peer. + * Issue Purge Ind to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting PURGE_STA_IND to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + cdf_mem_copy((uint8_t *) &mlmPurgeStaInd.peerMacAddr, + (uint8_t *) staDsAddr, sizeof(tSirMacAddr)); + mlmPurgeStaInd.reasonCode = + (uint8_t) mlmStaContext.disassocReason; + mlmPurgeStaInd.aid = staDsAssocId; + mlmPurgeStaInd.purgeTrigger = mlmStaContext.cleanupTrigger; + mlmPurgeStaInd.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_PURGE_STA_IND, + (uint32_t *) &mlmPurgeStaInd); + } else if (mlmStaContext.cleanupTrigger == eLIM_JOIN_FAILURE) { + /* PE setup the peer entry in HW upfront, right after join is completed. */ + /* If there is a failure during rest of the assoc sequence, this context needs to be cleaned up. */ + uint8_t smesessionId; + uint16_t smetransactionId; + + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + psessionEntry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + /* if it is a reassoc failure to join new AP */ + if ((mlmStaContext.resultCode == + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE) + || (mlmStaContext.resultCode == eSIR_SME_FT_REASSOC_FAILURE) + || (mlmStaContext.resultCode == + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE)) { + lim_log(pMac, LOG1, + FL("Lim Posting eWNI_SME_REASSOC_RSP to SME" + "resultCode: %d, statusCode: %d," + "sessionId: %d"), + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + } else { + cdf_mem_free(psessionEntry->pLimJoinReq); + psessionEntry->pLimJoinReq = NULL; + + lim_log(pMac, LOG1, + FL("Lim Posting eWNI_SME_JOIN_RSP to SME." + "resultCode: %d,statusCode: %d," + "sessionId: %d"), + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + } + + } + + if (NULL != psessionEntry && !LIM_IS_AP_ROLE(psessionEntry)) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } +} + +/** + * lim_reject_association() - function to reject Re/Association Request + * + * @mac_ctx: pointer to global mac structure + * @peer_addr: mac address of the peer + * @sub_type: Indicates whether it is Association Request (=0) or + * Reassociation Request (=1) frame + * @add_pre_auth_context:Indicates whether pre-auth context + * to be added for this STA + * @auth_type: Indicates auth type to be added + * @sta_id: Indicates staId of the STA being rejected + * association + * @delete_sta: Indicates whether to delete STA context + * at Polaris + * @result_code: Indicates what reasonCode to be sent in + * Re/Assoc response to STA + * @session_entry: pointer to PE session + * + * This function is called whenever Re/Association Request need + * to be rejected due to failure in assigning an AID or failure + * in adding STA context at Polaris or reject by applications. + * Resources allocated if any are freedup and (Re) Association + * Response frame is sent to requesting STA. Pre-Auth context + * will be added for this STA if it does not exist already + * + * Return: none + */ + +void +lim_reject_association(tpAniSirGlobal mac_ctx, tSirMacAddr peer_addr, + uint8_t sub_type, uint8_t add_pre_auth_context, + tAniAuthType auth_type, uint16_t sta_id, + uint8_t delete_sta, tSirResultCodes result_code, + tpPESession session_entry) +{ + tpDphHashNode sta_ds; + + lim_log(mac_ctx, LOG1, + FL("Sessionid: %d auth_type: %d sub_type: %d add_pre_auth_context: %d sta_id: %d delete_sta: %d result_code : %d peer_addr: " MAC_ADDRESS_STR), + session_entry->peSessionId, auth_type, sub_type, + add_pre_auth_context, sta_id, delete_sta, result_code, + MAC_ADDR_ARRAY(peer_addr)); + + if (add_pre_auth_context) { + /* Create entry for this STA in pre-auth list */ + struct tLimPreAuthNode *auth_node; + + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + + if (auth_node) { + cdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + peer_addr, sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + auth_node->authType = (tAniAuthType) auth_type; + auth_node->timestamp = cdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + } + } + + if (delete_sta == false) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS, + 1, peer_addr, sub_type, 0, session_entry); + /* Log error */ + lim_log(mac_ctx, LOGW, + FL("received Re/Assoc req when max associated STAs reached from ")); + lim_print_mac_addr(mac_ctx, peer_addr, LOGW); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, peer_addr, + session_entry->smeSessionId); + return; + } + + sta_ds = dph_get_hash_entry(mac_ctx, sta_id, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGW, + FL("No STA context, yet rejecting Association")); + return; + } + + /* + * Polaris has state for this STA. + * Trigger cleanup. + */ + sta_ds->mlmStaContext.cleanupTrigger = eLIM_REASSOC_REJECT; + + /* Receive path cleanup */ + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry); + + /* + * Send Re/Association Response with + * status code to requesting STA. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, result_code, 0, peer_addr, + sub_type, 0, session_entry); + + if (session_entry->parsedAssocReq[sta_ds->assocId] != NULL) { + uint8_t *assoc_req_frame; + + assoc_req_frame = (uint8_t *)((tpSirAssocReq) (session_entry-> + parsedAssocReq[sta_ds->assocId]))->assocReqFrame; + /* + *Assoction confirmation is complete, + *free the copy of association request frame. + */ + if (assoc_req_frame) { + cdf_mem_free(assoc_req_frame); + assoc_req_frame = NULL; + } + + cdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +/** + * lim_decide_ap_protection_on_ht20_delete() - function to update protection + * parameters. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * protection related function while HT20 station is getting deleted. + * + * Return: none + */ +static void +lim_decide_ap_protection_on_ht20_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i = 0; + + lim_log(mac_ctx, LOG1, + FL("(%d) A HT 20 STA is disassociated. Addr is %pM"), + session_entry->gLimHt20Params.numSta, sta_ds->staAddr); + + if (session_entry->gLimHt20Params.numSta > 0) { + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!session_entry->protStaCache[i].active) + continue; + + if (cdf_mem_compare(session_entry->protStaCache[i].addr, + sta_ds->staAddr, sizeof(tSirMacAddr))) { + session_entry->gLimHt20Params.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + } + + if (session_entry->gLimHt20Params.numSta == 0) { + /* disable protection */ + lim_log(mac_ctx, LOG1, FL("No 11B STA exists, PESessionID %d"), + session_entry->peSessionId); + lim_enable_ht20_protection(mac_ctx, false, false, beacon_params, + session_entry); + } +} + +/** + * lim_decide_ap_protection_on_delete() - update SAP protection on station + * deletion. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about protection related settings when a station is getting deleted. + * + * Return: none + */ +void +lim_decide_ap_protection_on_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t phy_mode; + tHalBitVal erp_enabled = eHAL_CLEAR; + tSirRFBand rf_band = SIR_BAND_UNKNOWN; + uint32_t i; + + if (NULL == sta_ds) + return; + + lim_get_rf_band_new(mac_ctx, &rf_band, session_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + erp_enabled = sta_ds->erpEnabled; + + if ((SIR_BAND_5_GHZ == rf_band) && + (true == session_entry->htCapability) && + (session_entry->beaconParams.llaCoexist) && + (false == sta_ds->mlmStaContext.htCapability)) { + /* + * we are HT. if we are 11A, then protection is not required or + * we are HT and 11A station is leaving. + * protection consideration required. + * HT station leaving ==> this case is commonly handled + * between both the bands below. + */ + lim_log(mac_ctx, LOG1, + FL("(%d) A 11A STA is disassociated. Addr is %pM"), + session_entry->gLim11aParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + cdf_mem_compare( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11aParams.numSta == 0) { + /* disable protection */ + lim_update_11a_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* we are HT or 11G and 11B station is getting deleted */ + if ((SIR_BAND_2_4_GHZ == rf_band) && + (phy_mode == WNI_CFG_PHY_MODE_11G || + session_entry->htCapability) && + (erp_enabled == eHAL_CLEAR)) { + lim_log(mac_ctx, LOG1, + FL("(%d) A legacy STA is disassociated. Addr is %pM"), + session_entry->gLim11bParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + cdf_mem_compare( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->gLim11bParams.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + + if (session_entry->gLim11bParams.numSta == 0) { + /* disable protection */ + lim_enable11g_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * we are HT AP and non-11B station is leaving. + * 11g station is leaving + */ + if ((SIR_BAND_2_4_GHZ == rf_band) && + session_entry->htCapability && + !sta_ds->mlmStaContext.htCapability) { + lim_log(mac_ctx, LOG1, + FL("(%d) A 11g STA is disassociated. Addr is %pM"), + session_entry->gLim11bParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + cdf_mem_compare( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->gLim11gParams.numSta--; + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11gParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_protection_from11g(mac_ctx, false, false, + beacon_params, + session_entry); + } + } + + if (!((true == session_entry->htCapability) && + (true == sta_ds->mlmStaContext.htCapability))) + return; + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT non-GF leaving + */ + if (!sta_ds->htGreenfield) { + lim_log(mac_ctx, LOG1, + FL("(%d) A non-GF STA is disassociated. Addr is %pM"), + session_entry->gLimNonGfParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + cdf_mem_compare( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimNonGfParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_non_gf_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT 20Mhz station leaving + */ + if (session_entry->beaconParams.ht20Coexist && + (eHT_CHANNEL_WIDTH_20MHZ == + sta_ds->htSupportedChannelWidthSet)) { + lim_decide_ap_protection_on_ht20_delete(mac_ctx, sta_ds, + beacon_params, session_entry); + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * LSIG TXOP not supporting staiton leaving + */ + if ((false == session_entry->beaconParams. + fLsigTXOPProtectionFullSupport) && + (false == sta_ds->htLsigTXOPProtection)) { + lim_log(mac_ctx, LOG1, + FL("(%d) A HT LSIG not supporting STA is disassociated. Addr is %pM"), + session_entry->gLimLsigTxopParams.numSta, + sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + cdf_mem_compare( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimLsigTxopParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_lsig_txop_protection(mac_ctx, true, + false, beacon_params, session_entry); + } + } +} + +/** + * lim_decide_short_preamble() - update short preamble parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short preamble related change because of new station + * joining. + * + * Return: None + */ +void lim_decide_short_preamble(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i; + + if (sta_ds->shortPreambleEnabled == eHAL_CLEAR) { + lim_log(mac_ctx, LOG1, + FL("(%d) A non-short preamble STA is disassociated. Addr is %pM"), + session_entry->gLimNoShortParams.numNonShortPreambleSta, + sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortParams. + staNoShortCache[i].active && + cdf_mem_compare(session_entry-> + gLimNoShortParams. + staNoShortCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + session_entry->gLimNoShortParams. + numNonShortPreambleSta--; + session_entry->gLimNoShortParams. + staNoShortCache[i].active = false; + break; + } + } + + if (session_entry->gLimNoShortParams.numNonShortPreambleSta) + return; + + /* + * enable short preamble + * reset the cache + */ + cdf_mem_set((uint8_t *) &session_entry->gLimNoShortParams, + sizeof(tLimNoShortParams), 0); + if (lim_enable_short_preamble(mac_ctx, true, + beacon_params, session_entry) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Cannot enable short preamble")); + } + } +} + +/** + * lim_decide_short_slot() - update short slot time related parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short slot time related change because of station leaving + * the BSS. + * Return: None + */ +void +lim_decide_short_slot(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i, val, non_short_slot_sta_count; + + if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) + return; + + lim_log(mac_ctx, LOG1, + FL("(%d) A non-short slottime STA is disassociated. Addr is %pM"), + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, + sta_ds->staAddr); + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val); + + if (LIM_IS_AP_ROLE(session_entry)) { + non_short_slot_sta_count = + session_entry->gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + cdf_mem_compare(session_entry-> + gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + non_short_slot_sta_count--; + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (non_short_slot_sta_count == 0 && val) { + /* + * enable short slot time + * reset the cache + */ + cdf_mem_set((uint8_t *) &session_entry-> + gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + session_entry->gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } else { + non_short_slot_sta_count = + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + cdf_mem_compare( + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr))) { + non_short_slot_sta_count--; + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (val && !non_short_slot_sta_count) { + /* + * enable short slot time + * reset the cache + */ + cdf_mem_set( + (uint8_t *) &mac_ctx->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + /*in case of AP set SHORT_SLOT_TIME to enable*/ + if (LIM_IS_AP_ROLE(session_entry)) { + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + } + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } +} + +void +lim_post_reassoc_failure(tpAniSirGlobal pMac, + tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + /* Update PE session Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} /*** end lim_post_reassoc_failure() ***/ + +/** + * lim_restore_pre_reassoc_state() + * + ***FUNCTION: + * This function is called on STA role whenever Reasociation + * Response with a reject code is received from AP. + * + ***LOGIC: + * Reassociation failure timer is stopped, Old (or current) AP's + * context is restored both at Polaris & software + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param resultCode - Result code that specifies why Reassociation + * attemp failed + * + * @return None + */ + +void +lim_restore_pre_reassoc_state(tpAniSirGlobal pMac, + tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + lim_log(pMac, LOG1, + FL("sessionid: %d protStatusCode: %d resultCode: %d"), + psessionEntry->smeSessionId, protStatusCode, resultCode); + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + lim_set_channel(pMac, psessionEntry->currentOperChannel, + psessionEntry->ch_center_freq_seg0, + psessionEntry->ch_center_freq_seg1, + psessionEntry->ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId); + + /** @ToDo : Need to Integrate the STOP the DataTransfer to the AP from 11H code */ + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + /* Update PE session Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} /*** end lim_restore_pre_reassoc_state() ***/ + +/** + * lim_is_reassoc_in_progress() + * + ***FUNCTION: + * This function is called to see if STA is in wt-reassoc-rsp state. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return true When STA is waiting for Reassoc response from AP \n + * else false + */ + +bool lim_is_reassoc_in_progress(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry == NULL) { + return false; + } + if ((LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) && + ((psessionEntry->limSmeState == eLIM_SME_WT_REASSOC_STATE) || + (psessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_LINK_FAIL_STATE))) + return true; + + return false; +} /*** end lim_is_reassoc_in_progress() ***/ + +#ifdef WLAN_FEATURE_11AC +/** + * lim_populate_vht_mcs_set - function to populate vht mcs rate set + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rate set + * @peer_vht_caps: pointer to peer vht capabilities + * @session_entry: pe session entry + * + * Populates vht mcs rate set based on peer and self capabilities + * + * Return: eSIR_SUCCESS on success else eSIR_FAILURE + */ +tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + tDot11fIEVHTCaps *peer_vht_caps, + tpPESession session_entry) +{ + uint32_t val; + uint32_t self_sta_dot11mode = 0; + uint16_t mcs_map_mask = MCSMAPMASK1x1; + uint16_t mcs_map_mask2x2 = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + + if (!IS_DOT11_MODE_VHT(self_sta_dot11mode)) + return eSIR_SUCCESS; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_MCS_MAP, &val) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("could not retrieve VHT RX MCS MAP")); + goto error; + } + rates->vhtRxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_MCS_MAP, &val) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("could not retrieve VHT TX MCS MAP")); + goto error; + } + rates->vhtTxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("couldn't retrieve VHT RX Supported data rate MAP")); + goto error; + } + rates->vhtRxHighestDataRate = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("couldn't retrieve VHT RX Supported data rate MAP")); + goto error; + } + rates->vhtTxHighestDataRate = (uint16_t) val; + + if (peer_vht_caps == NULL) + return eSIR_SUCCESS; + + rates->vhtTxHighestDataRate = + CDF_MIN(rates->vhtTxHighestDataRate, + peer_vht_caps->txSupDataRate); + rates->vhtRxHighestDataRate = + CDF_MIN(rates->vhtRxHighestDataRate, + peer_vht_caps->rxHighSupDataRate); + + if (mac_ctx->roam.configParam.enable2x2) { + if (session_entry && mac_ctx->lteCoexAntShare && + IS_24G_CH(session_entry->currentOperChannel)) { + if (IS_2X2_CHAIN(session_entry->chainMask)) + mcs_map_mask2x2 = MCSMAPMASK2x2; + else + lim_log(mac_ctx, LOGE, FL("2x2 not enabled %d"), + session_entry->chainMask); + } else { + mcs_map_mask2x2 = MCSMAPMASK2x2; + } + } + + if ((peer_vht_caps->txMCSMap & mcs_map_mask) < + (rates->vhtRxMCSMap & mcs_map_mask)) { + rates->vhtRxMCSMap &= ~(mcs_map_mask); + rates->vhtRxMCSMap |= + (peer_vht_caps->txMCSMap & mcs_map_mask); + } + if ((peer_vht_caps->rxMCSMap & mcs_map_mask) < + (rates->vhtTxMCSMap & mcs_map_mask)) { + rates->vhtTxMCSMap &= ~(mcs_map_mask); + rates->vhtTxMCSMap |= + (peer_vht_caps->rxMCSMap & mcs_map_mask); + } + + if (mcs_map_mask2x2) { + + uint16_t peer_mcs_map, self_mcs_map; + + peer_mcs_map = + peer_vht_caps->txMCSMap & mcs_map_mask2x2; + self_mcs_map = + rates->vhtRxMCSMap & mcs_map_mask2x2; + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtRxMCSMap &= ~mcs_map_mask2x2; + rates->vhtRxMCSMap |= peer_mcs_map; + } + + peer_mcs_map = + (peer_vht_caps->rxMCSMap & mcs_map_mask2x2); + self_mcs_map = + (rates->vhtTxMCSMap & mcs_map_mask2x2); + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtTxMCSMap &= ~mcs_map_mask2x2; + rates->vhtTxMCSMap |= peer_mcs_map; + } + } + + lim_log(mac_ctx, LOG1, + FL("enable2x2 - %d vhtRxMCSMap - %x vhtTxMCSMap - %x\n"), + mac_ctx->roam.configParam.enable2x2, + rates->vhtRxMCSMap, rates->vhtTxMCSMap); + + return eSIR_SUCCESS; +error: + + return eSIR_FAILURE; +} +#endif + +/** + * lim_populate_own_rate_set() - comprises the basic and extended rates read + * from CFG + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rates + * @supported_mcs_set: pointer to supported mcs rates + * @basic_only: update only basic rates if set true + * @session_entry: pe session entry + * @vht_caps: pointer to vht capability + * + * This function is called by limProcessAssocRsp() or + * lim_add_staInIBSS() + * - It creates a combined rate set of 12 rates max which + * comprises the basic and extended rates read from CFG + * - It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * - It sets the erpEnabled bit of the STA descriptor + * ERP bit is set iff the dph PHY mode is 11G and there is at least + * an A rate in the supported or extended rate sets + * + * Return: eSIR_SUCCESS or eSIR_FAILURE. + */ +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +lim_populate_own_rate_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, uint8_t *supported_mcs_set, + uint8_t basic_only, tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +#else +tSirRetStatus +lim_populate_own_rate_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + uint8_t *supported_mcs_set, + uint8_t basic_only, tpPESession session_entry) +#endif +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode = 0; + uint32_t self_sta_dot11mode = 0; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + + + is_arate = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only + */ + if ((self_sta_dot11mode == WNI_CFG_DOT11_MODE_ALL) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11B)) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *) &temp_rate_set.rate, &val); + temp_rate_set.numRates = (uint8_t) val; + } else { + temp_rate_set.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_sta_dot11mode)) { + val = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *) &temp_rate_set2.rate, &val); + temp_rate_set2.numRates = (uint8_t) val; + } else { + temp_rate_set2.numRates = 0; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + /* we are in big trouble */ + lim_log(mac_ctx, LOGP, FL("more than 12 rates in CFG")); + /* panic */ + goto error; + } + /* copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /** + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in pSupportedRates + */ + + cdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + is_arate = 0; + + for (j = 0; (j < temp_rate_set.numRates) && + (j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < + val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + } + + if (sirIsArate(temp_rate_set.rate[min] & 0x7f)) + is_arate = 1; + + /* + * HAL needs to know whether the rate is basic rate or + * not, as it needs to update the response rate table + * accordingly. e.g. if one of the 11a rates is + * basic rate, then that rate can be used for sending + * control frames. + * HAL updates the response rate table whenever basic + * rate set is changed. + */ + if (basic_only && temp_rate_set.rate[min] & 0x80) { + if (is_arate) + rates->llaRates[a_rate_index++] = + temp_rate_set.rate[min]; + else + rates->llbRates[b_rate_index++] = + temp_rate_set.rate[min]; + } else { + if (is_arate) + rates->llaRates[a_rate_index++] = + temp_rate_set.rate[min]; + else + rates->llbRates[b_rate_index++] = + temp_rate_set.rate[min]; + } + temp_rate_set.rate[min] = 0xff; + } + + if (IS_DOT11_MODE_HT(self_sta_dot11mode)) { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + rates->supportedMCSSet, + &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGE, + FL("could not retrieve supportedMCSSet")); + goto error; + } + + /* + * if supported MCS Set of the peer is passed in, + * then do the intersection + * else use the MCS set from local CFG. + */ + + if (supported_mcs_set != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + rates->supportedMCSSet[i] &= + supported_mcs_set[i]; + } + + lim_log(mac_ctx, LOG2, FL("MCS Rate Set Bitmap: ")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + PELOG2(lim_log(mac_ctx, LOG2, FL("%x "), + rates->supportedMCSSet[i]);) + } +#ifdef WLAN_FEATURE_11AC + lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, session_entry); +#endif + + return eSIR_SUCCESS; +error: + return eSIR_FAILURE; +} + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, tDot11fIEVHTCaps *pVHTCaps) +#else +tSirRetStatus +lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, tpPESession psessionEntry) +#endif +{ + tSirMacRateSet tempRateSet; + tSirMacRateSet tempRateSet2; + uint32_t i, j, val, min, isArate; + isArate = 0; + + /* copy operational rate set from psessionEntry */ + if (psessionEntry->rateSet.numRates <= SIR_MAC_RATESET_EID_MAX) { + cdf_mem_copy((uint8_t *) tempRateSet.rate, + (uint8_t *) (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + tempRateSet.numRates = psessionEntry->rateSet.numRates; + } else { + lim_log(pMac, LOGE, + FL("more than SIR_MAC_RATESET_EID_MAX rates\n")); + goto error; + } + if ((psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11A) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N)) { + if (psessionEntry->extRateSet.numRates <= + SIR_MAC_RATESET_EID_MAX) { + cdf_mem_copy((uint8_t *) tempRateSet2.rate, + (uint8_t *) (psessionEntry->extRateSet. + rate), + psessionEntry->extRateSet.numRates); + tempRateSet2.numRates = + psessionEntry->extRateSet.numRates; + } else { + lim_log(pMac, LOGE, + FL + ("psessionEntry->extRateSet.numRates more than SIR_MAC_RATESET_EID_MAX rates\n")); + goto error; + } + } else + tempRateSet2.numRates = 0; + if ((tempRateSet.numRates + tempRateSet2.numRates) > + SIR_MAC_RATESET_EID_MAX) { + /* we are in big trouble */ + lim_log(pMac, LOGP, FL("more than 12 rates in CFG")); + goto error; + } + + /* copy all rates in tempRateSet, there are 12 rates max */ + for (i = 0; i < tempRateSet2.numRates; i++) + tempRateSet.rate[i + tempRateSet.numRates] = + tempRateSet2.rate[i]; + tempRateSet.numRates += tempRateSet2.numRates; + /** + * Sort rates in tempRateSet (they are likely to be already sorted) + * put the result in pSupportedRates + */ + { + uint8_t aRateIndex = 0; + uint8_t bRateIndex = 0; + cdf_mem_set((uint8_t *) pRates, sizeof(tSirSupportedRates), 0); + for (i = 0; i < tempRateSet.numRates; i++) { + min = 0; + val = 0xff; + isArate = 0; + for (j = 0; + (j < tempRateSet.numRates) + && (j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((uint32_t) (tempRateSet.rate[j] & 0x7f) < + val) { + val = tempRateSet.rate[j] & 0x7f; + min = j; + } + } + if (sirIsArate(tempRateSet.rate[min] & 0x7f)) + isArate = 1; + /* + * HAL needs to know whether the rate is basic rate or not, as it needs to + * update the response rate table accordingly. e.g. if one of the 11a rates is + * basic rate, then that rate can be used for sending control frames. + * HAL updates the response rate table whenever basic rate set is changed. + */ + if (basicOnly) { + if (tempRateSet.rate[min] & 0x80) { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + } else { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + tempRateSet.rate[min] = 0xff; + } + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + pRates->supportedMCSSet, + &val) != eSIR_SUCCESS) { + /* / Could not get rateset from CFG. Log error. */ + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve supportedMCSSet")); + ) + goto error; + } + /* if supported MCS Set of the peer is passed in, then do the intersection */ + /* else use the MCS set from local CFG. */ + if (pSupportedMCSSet != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pRates->supportedMCSSet[i] &= + pSupportedMCSSet[i]; + } + PELOG2(lim_log(pMac, LOG2, FL("MCS Rate Set Bitmap: "));) + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + PELOG2(lim_log + (pMac, LOG2, FL("%x "), + pRates->supportedMCSSet[i]); + ) + } +#ifdef WLAN_FEATURE_11AC + lim_populate_vht_mcs_set(pMac, pRates, pVHTCaps, psessionEntry); +#endif + return eSIR_SUCCESS; +error: + return eSIR_FAILURE; +} /*** lim_populate_peer_rate_set() ***/ + +/** + * lim_populate_matching_rate_set() -process the CFG rate sets and + * the rate sets received in the Assoc request on AP. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @oper_rate_set: pointer to operating rate set + * @ext_rate_set: pointer to extended rate set + * @supported_mcs_set: pointer to supported rate set + * @session_entry: pointer to pe session entry + * @vht_caps: pointer to vht capabilities + * + * This is called at the time of Association Request + * processing on AP and while adding peer's context + * in IBSS role to process the CFG rate sets and + * the rate sets received in the Assoc request on AP + * or Beacon/Probe Response from peer in IBSS. + * + * 1. It makes the intersection between our own rate Sat + * and extemcded rate set and the ones received in the + * association request. + * 2. It creates a combined rate set of 12 rates max which + * comprised the basic and extended rates + * 3. It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * + * The parser has already ensured unicity of the rates in the + * association request structure + * + * Return: eSIR_SUCCESS on success else eSIR_FAILURE + */ +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +lim_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, tpPESession session_entry, + tDot11fIEVHTCaps * vht_caps) +#else +tSirRetStatus +lim_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, tpPESession session_entry) +#endif +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + + is_arate = 0; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* copy operational rate set from session_entry */ + cdf_mem_copy((temp_rate_set.rate), (session_entry->rateSet.rate), + session_entry->rateSet.numRates); + temp_rate_set.numRates = (uint8_t) session_entry->rateSet.numRates; + + if (phy_mode == WNI_CFG_PHY_MODE_11G) { + cdf_mem_copy((temp_rate_set2.rate), + (session_entry->extRateSet.rate), + session_entry->extRateSet.numRates); + temp_rate_set2.numRates = + (uint8_t) session_entry->extRateSet.numRates; + } else { + temp_rate_set2.numRates = 0; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + lim_log(mac_ctx, LOGE, FL("more than 12 rates in CFG")); + goto error; + } + + /* + * Handling of the rate set IEs is the following: + * - keep only rates that we support and that the station supports + * - sort and the rates into the pSta->rate array + */ + + /* Copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /* + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in temp_rate_set2 + */ + temp_rate_set2.numRates = 0; + + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + + for (j = 0; j < temp_rate_set.numRates; j++) + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + + temp_rate_set2.rate[temp_rate_set2.numRates++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + /* + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 + */ + for (i = 0; (i < oper_rate_set->numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) + temp_rate_set.rate[i] = oper_rate_set->rate[i]; + + temp_rate_set.numRates = oper_rate_set->numRates; + + lim_log(mac_ctx, LOG2, + "Sum of SUPPORTED and EXTENDED Rate Set (%1d)", + temp_rate_set.numRates + ext_rate_set->numRates); + + if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) > 12) && + temp_rate_set.numRates < 12) { + int found = 0; + int tail = temp_rate_set.numRates; + + for (i = 0; (i < ext_rate_set->numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) { + found = 0; + for (j = 0; j < (uint32_t) tail; j++) { + if ((temp_rate_set.rate[j] & 0x7F) == + (ext_rate_set->rate[i] & 0x7F)) { + found = 1; + break; + } + } + + if (!found) { + temp_rate_set.rate[temp_rate_set.numRates++] = + ext_rate_set->rate[i]; + if (temp_rate_set.numRates >= 12) + break; + } + } + } else if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) <= 12)) { + for (j = 0; ((j < ext_rate_set->numRates) && + (j < SIR_MAC_RATESET_EID_MAX) && + ((i + j) < SIR_MAC_RATESET_EID_MAX)); j++) + temp_rate_set.rate[i + j] = ext_rate_set->rate[j]; + + temp_rate_set.numRates += ext_rate_set->numRates; + } else if (ext_rate_set->numRates) { + lim_log(mac_ctx, LOG2, + "Relying only on the SUPPORTED Rate Set IE..."); + } + + + rates = &sta_ds->supportedRates; + cdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + for (i = 0; (i < temp_rate_set2.numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) { + for (j = 0; (j < temp_rate_set.numRates && + j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + + if (sirIsArate(temp_rate_set2.rate[i] & 0x7f) && + a_rate_index < SIR_NUM_11A_RATES) { + is_arate = 1; + rates->llaRates[a_rate_index++] = + temp_rate_set2.rate[i]; + } else if ((b_rate_index < SIR_NUM_11B_RATES) && + !(sirIsArate(temp_rate_set2.rate[i] & 0x7f))) { + rates->llbRates[b_rate_index++] = + temp_rate_set2.rate[i]; + } + break; + } + } + + /* + * Now add the Polaris rates only when Proprietary rates are enabled. + * compute the matching MCS rate set, if peer is 11n capable and self + * mode is 11n + */ +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (sta_ds->mlmStaContext.htCapability)) +#endif + { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve supportedMCSet")); + goto error; + } + + for (i = 0; i < val; i++) + sta_ds->supportedRates.supportedMCSSet[i] = + mcs_set[i] & supported_mcs_set[i]; + + lim_log(mac_ctx, LOG2, + FL("lim_populate_matching_rate_set: MCS Rate Set Bitmap" + " from CFG and DPH : ")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + lim_log(mac_ctx, LOG2, FL("%x %x "), mcs_set[i], + sta_ds->supportedRates.supportedMCSSet[i]); + } + } +#ifdef WLAN_FEATURE_11AC + lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps, + session_entry); +#endif + /* + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && is_arate) + sta_ds->erpEnabled = eHAL_SET; + + return eSIR_SUCCESS; + +error: + + return eSIR_FAILURE; +} + +/** + * lim_populate_vht_caps() - populates vht capabilities based on input + * capabilities + * @input_caps: input capabilities based on which we format the vht + * capabilities + * + * function to populate the supported vht capabilities. + * + * Return: vht capabilities derived based on input parameters. + */ +static uint32_t lim_populate_vht_caps(tDot11fIEVHTCaps input_caps) +{ + uint32_t vht_caps; + + vht_caps = ((input_caps.maxMPDULen << SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (input_caps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (input_caps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (input_caps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (input_caps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (input_caps.txSTBC << SIR_MAC_VHT_CAP_TXSTBC) | + (input_caps.rxSTBC << SIR_MAC_VHT_CAP_RXSTBC) | + (input_caps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (input_caps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (input_caps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (input_caps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (input_caps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (input_caps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (input_caps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (input_caps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (input_caps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (input_caps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (input_caps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (input_caps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (input_caps.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + return vht_caps; +} +/** + * lim_add_sta()- called to add an STA context at hardware + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @update_entry: set to true for updating the entry + * @session_entry: pe session entry + * + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + * Return: eSIR_SUCCESS on success else eSirRetStatus failure codes + */ + +tSirRetStatus +lim_add_sta(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, uint8_t update_entry, tpPESession session_entry) +{ + tpAddStaParams add_sta_params = NULL; + tSirMsgQ msg_q; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMacAddr sta_mac, *sta_Addr; + uint8_t i, nw_type_11b = 0; + tpSirAssocReq assoc_req; + tLimIbssPeerNode *peer_node; /* for IBSS mode */ + uint8_t *p2p_ie = NULL; + + sir_copy_mac_addr(sta_mac, session_entry->selfMacAddr); + + lim_log(mac_ctx, LOG1, + FL("sessionid: %d update_entry = %d limsystemrole = %d "), + session_entry->smeSessionId, update_entry, + GET_LIM_SYSTEM_ROLE(session_entry)); + + add_sta_params = cdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == add_sta_params) { + lim_log(mac_ctx, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set((uint8_t *) add_sta_params, sizeof(tAddStaParams), 0); + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) + sta_Addr = &sta_ds->staAddr; +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) + sta_Addr = &sta_ds->staAddr; +#endif + else + sta_Addr = &sta_mac; + + lim_log(mac_ctx, LOG1, + FL(MAC_ADDRESS_STR ": Subtype(Assoc/Reassoc): %d"), + MAC_ADDR_ARRAY(*sta_Addr), sta_ds->mlmStaContext.subType); + + cdf_mem_copy((uint8_t *) add_sta_params->staMac, + (uint8_t *) *sta_Addr, sizeof(tSirMacAddr)); + cdf_mem_copy((uint8_t *) add_sta_params->bssId, + session_entry->bssId, sizeof(tSirMacAddr)); + cdf_mem_copy(&add_sta_params->capab_info, + &sta_ds->mlmStaContext.capabilityInfo, + sizeof(add_sta_params->capab_info)); + + lim_fill_supported_rates_info(mac_ctx, sta_ds, &sta_ds->supportedRates, + session_entry); + + /* Copy legacy rates */ + cdf_mem_copy((uint8_t *) &add_sta_params->supportedRates, + (uint8_t *) &sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + + add_sta_params->assocId = sta_ds->assocId; + + add_sta_params->wmmEnabled = sta_ds->qosMode; + add_sta_params->listenInterval = sta_ds->mlmStaContext.listenInterval; + add_sta_params->shortPreambleSupported = sta_ds->shortPreambleEnabled; + if (LIM_IS_AP_ROLE(session_entry) && + (sta_ds->mlmStaContext.subType == LIM_REASSOC)) { + /* + * TBD - need to remove this REASSOC check + * after fixinf rmmod issue + */ + add_sta_params->updateSta = sta_ds->mlmStaContext.updateContext; + } + sta_ds->valid = 0; + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + + lim_log(mac_ctx, LOG2, + FL(" Assoc ID: %d wmmEnabled = %d listenInterval = %d" + " shortPreambleSupported: %d "), add_sta_params->assocId, + add_sta_params->wmmEnabled, add_sta_params->listenInterval, + add_sta_params->shortPreambleSupported); + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef FEATURE_WLAN_TDLS + /* + * As there is corner case in-between add_sta and change_sta,if del_sta + * for other staIdx happened, firmware return wrong staIdx + * (recently removed staIdx). Until we get a confirmation from the + * firmware team it is now return correct staIdx for same sta_mac_addr + * for update case, we want to get around it by passing valid staIdx + * given by add_sta time. + */ + if ((STA_ENTRY_TDLS_PEER == sta_ds->staType) && (true == update_entry)) + add_sta_params->staIdx = sta_ds->staIndex; + else +#endif + add_sta_params->staIdx = STA_INVALID_IDX; + add_sta_params->staType = sta_ds->staType; + + add_sta_params->updateSta = update_entry; + + add_sta_params->status = CDF_STATUS_SUCCESS; + add_sta_params->respReqd = 1; + /* Update HT Capability */ + + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry) || + LIM_IS_IBSS_ROLE(session_entry)) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; +#ifdef WLAN_FEATURE_11AC + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability; +#endif + } +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; +#ifdef WLAN_FEATURE_11AC + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability; +#endif + } +#endif + else { + add_sta_params->htCapable = session_entry->htCapability; +#ifdef WLAN_FEATURE_11AC + add_sta_params->vhtCapable = session_entry->vhtCapability; +#endif + + } +#ifdef WLAN_FEATURE_11AC + lim_log(mac_ctx, LOG2, FL("vhtCapable: %d "), + add_sta_params->vhtCapable); +#endif + lim_log(mac_ctx, LOG2, FL(" StaIdx: %d updateSta = %d htcapable = %d "), + add_sta_params->staIdx, add_sta_params->updateSta, + add_sta_params->htCapable); + + add_sta_params->greenFieldCapable = sta_ds->htGreenfield; + add_sta_params->maxAmpduDensity = sta_ds->htAMpduDensity; + add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor; + add_sta_params->fDsssCckMode40Mhz = sta_ds->htDsssCckRate40MHzSupport; + add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz; + add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz; + add_sta_params->lsigTxopProtection = sta_ds->htLsigTXOPProtection; + add_sta_params->maxAmsduSize = sta_ds->htMaxAmsduLength; + add_sta_params->ch_width = sta_ds->htSupportedChannelWidthSet; + add_sta_params->mimoPS = sta_ds->htMIMOPSState; + + lim_log(mac_ctx, LOG2, + FL("greenFieldCapable: %d maxAmpduDensity = %d maxAmpduDensity = %d"), + add_sta_params->greenFieldCapable, + add_sta_params->maxAmpduDensity, add_sta_params->maxAmpduSize); + + lim_log(mac_ctx, LOG2, + FL("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d fShortGI40Mhz: %d"), + add_sta_params->fDsssCckMode40Mhz, + add_sta_params->fShortGI20Mhz, add_sta_params->fShortGI40Mhz); + + lim_log(mac_ctx, LOG2, + FL("lsigTxopProtection: %d maxAmsduSize: %d txChannelWidth: %d mimoPS: %d "), + add_sta_params->lsigTxopProtection, + add_sta_params->maxAmsduSize, add_sta_params->ch_width, + add_sta_params->mimoPS); + + if (add_sta_params->vhtCapable) { + if (sta_ds->vhtSupportedChannelWidthSet) + add_sta_params->ch_width = + sta_ds->vhtSupportedChannelWidthSet + 1; + + add_sta_params->vhtSupportedRxNss = sta_ds->vhtSupportedRxNss; + add_sta_params->vhtTxBFCapable = +#ifdef FEATURE_WLAN_TDLS + ((STA_ENTRY_PEER == sta_ds->staType) + || (STA_ENTRY_TDLS_PEER == sta_ds->staType)) ? + sta_ds->vhtBeamFormerCapable : + session_entry->txBFIniFeatureEnabled; +#else + (STA_ENTRY_PEER == sta_ds->staType) ? + sta_ds->vhtBeamFormerCapable : + session_entry->txBFIniFeatureEnabled; +#endif + add_sta_params->enable_su_tx_bformer = + sta_ds->vht_su_bfee_capable; + } + + lim_log(mac_ctx, LOGE, FL("TxChWidth %d vhtTxBFCap %d, su_bfer %d"), + add_sta_params->ch_width, add_sta_params->vhtTxBFCapable, + add_sta_params->enable_su_tx_bformer); +#ifdef FEATURE_WLAN_TDLS + if ((STA_ENTRY_PEER == sta_ds->staType) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType)) +#else + if (STA_ENTRY_PEER == sta_ds->staType) +#endif + { + /* + * peer STA get the LDPC capability from sta_ds, + * which populated from + * HT/VHT capability + */ + if (add_sta_params->vhtTxBFCapable + && mac_ctx->lim.disableLDPCWithTxbfAP) { + add_sta_params->htLdpcCapable = 0; + add_sta_params->vhtLdpcCapable = 0; + } else { + add_sta_params->htLdpcCapable = sta_ds->htLdpcCapable; + add_sta_params->vhtLdpcCapable = sta_ds->vhtLdpcCapable; + } + } else if (STA_ENTRY_SELF == sta_ds->staType) { + /* For Self STA get the LDPC capability from config.ini */ + add_sta_params->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + add_sta_params->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + } + + /* Update PE session ID */ + add_sta_params->sessionId = session_entry->peSessionId; + + /* Update SME session ID */ + add_sta_params->smesessionId = session_entry->smeSessionId; + + add_sta_params->maxTxPower = session_entry->maxTxPower; + + if (session_entry->parsedAssocReq != NULL) { + uint16_t aid = sta_ds->assocId; + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[aid]; + if (assoc_req && assoc_req->addIEPresent + && assoc_req->addIE.length) { + p2p_ie = limGetP2pIEPtr(mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + + add_sta_params->p2pCapableSta = (p2p_ie != NULL); + if (assoc_req && add_sta_params->htCapable) { + cdf_mem_copy(&add_sta_params->ht_caps, + ((uint8_t *) &assoc_req->HTCaps) + 1, + sizeof(add_sta_params->ht_caps)); + } + + if (assoc_req && add_sta_params->vhtCapable) + add_sta_params->vht_caps = + lim_populate_vht_caps(assoc_req->VHTCaps); + } else if (LIM_IS_IBSS_ROLE(session_entry)) { + + /* + * in IBSS mode, use peer node as the source of ht_caps + * and vht_caps + */ + peer_node = lim_ibss_peer_find(mac_ctx, *sta_Addr); + if (!peer_node) { + lim_log(mac_ctx, LOGP, + FL("Can't find IBSS peer node for ADD_STA")); + return eSIR_HAL_STA_DOES_NOT_EXIST; + } + + if (peer_node->atimIePresent) { + add_sta_params->atimIePresent = + peer_node->atimIePresent; + add_sta_params->peerAtimWindowLength = + peer_node->peerAtimWindowLength; + } + + add_sta_params->ht_caps = + (peer_node->htSupportedChannelWidthSet << + SIR_MAC_HT_CAP_CHWIDTH40_S) | + (peer_node->htGreenfield << + SIR_MAC_HT_CAP_GREENFIELD_S) | + (peer_node->htShortGI20Mhz << + SIR_MAC_HT_CAP_SHORTGI20MHZ_S) | + (peer_node->htShortGI40Mhz << + SIR_MAC_HT_CAP_SHORTGI40MHZ_S) | + (SIR_MAC_TXSTBC << + SIR_MAC_HT_CAP_TXSTBC_S) | + (SIR_MAC_RXSTBC << + SIR_MAC_HT_CAP_RXSTBC_S) | + (peer_node->htMaxAmsduLength << + SIR_MAC_HT_CAP_MAXAMSDUSIZE_S) | + (peer_node->htDsssCckRate40MHzSupport << + SIR_MAC_HT_CAP_DSSSCCK40_S); + + add_sta_params->vht_caps = + lim_populate_vht_caps(peer_node->VHTCaps); + } +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->ht_caps = sta_ds->ht_caps; + add_sta_params->vht_caps = sta_ds->vht_caps; + + lim_log(mac_ctx, LOG1, + FL("Sta type is TDLS_PEER, ht_caps: 0x%x, vht_caps: 0x%x"), + add_sta_params->ht_caps, + add_sta_params->vht_caps); + } +#endif + +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->wmeEnabled && + (LIM_IS_AP_ROLE(session_entry) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType))) +#else + if (sta_ds->wmeEnabled && LIM_IS_AP_ROLE(session_entry)) +#endif + { + add_sta_params->uAPSD = 0; + /* + * update UAPSD and send it to LIM to add STA + * bitmap MSB <- LSB MSB 4 bits are for + * trigger enabled AC setting and LSB 4 bits + * are for delivery enabled AC setting + * 7 6 5 4 3 2 1 0 + * BE BK VI VO BE BK VI VO + */ + add_sta_params->uAPSD |= + sta_ds->qos.capability.qosInfo.acvo_uapsd; + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acvi_uapsd << 1); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbk_uapsd << 2); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbe_uapsd << 3); + /* + * making delivery enabled and + * trigger enabled setting the same. + */ + add_sta_params->uAPSD |= add_sta_params->uAPSD << 4; + + add_sta_params->maxSPLen = + sta_ds->qos.capability.qosInfo.maxSpLen; + lim_log(mac_ctx, LOG1, FL("uAPSD = 0x%x, maxSpLen = %d"), + add_sta_params->uAPSD, add_sta_params->maxSPLen); + } +#ifdef WLAN_FEATURE_11W + add_sta_params->rmfEnabled = sta_ds->rmfEnabled; + lim_log(mac_ctx, LOG1, FL("PMF enabled %d"), + add_sta_params->rmfEnabled); +#endif + + lim_log(mac_ctx, LOG2, FL("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d"), + add_sta_params->htLdpcCapable, add_sta_params->vhtLdpcCapable, + add_sta_params->p2pCapableSta); + + /* + * we need to defer the message until we get the + * response back from HAL. + */ + if (add_sta_params->respReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); + + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (sirIsArate(sta_ds->supportedRates.llaRates[i] & 0x7F)) { + nw_type_11b = 0; + break; + } else { + nw_type_11b = 1; + } + } + if (nw_type_11b) + add_sta_params->nwType = eSIR_11B_NW_TYPE; + else + add_sta_params->nwType = session_entry->nwType; + + msg_q.type = WMA_ADD_STA_REQ; + + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("Sending WMA_ADD_STA_REQ for assocId %d"), + sta_ds->assocId); + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (eSIR_SUCCESS != ret_code) { + if (add_sta_params->respReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + lim_log(mac_ctx, LOGE, + FL("ADD_STA_REQ for aId %d failed (reason %X)"), + sta_ds->assocId, ret_code); + cdf_mem_free(add_sta_params); + } + + return ret_code; +} + +/** + * lim_del_sta() + * + ***FUNCTION: + * This function is called to delete an STA context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @param fRespReqd - flag to indicate whether the delete is synchronous (true) + * or not (false) + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_del_sta(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, bool fRespReqd, tpPESession psessionEntry) +{ + tpDeleteStaParams pDelStaParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + pDelStaParams = cdf_mem_malloc(sizeof(tDeleteStaParams)); + if (NULL == pDelStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) pDelStaParams, sizeof(tDeleteStaParams), 0); + + /* */ + /* DPH contains the STA index only for "peer" STA entries. */ + /* LIM global contains "self" STA index */ + /* Thus, */ + /* if( STA role ) */ + /* get STA index from LIM global */ + /* else */ + /* get STA index from DPH */ + /* */ + +#ifdef FEATURE_WLAN_TDLS + if ((LIM_IS_STA_ROLE(psessionEntry) && + (pStaDs->staType != STA_ENTRY_TDLS_PEER)) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) +#else + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) +#endif + pDelStaParams->staIdx = psessionEntry->staId; + + else + pDelStaParams->staIdx = pStaDs->staIndex; + + pDelStaParams->assocId = pStaDs->assocId; + pStaDs->valid = 0; + + if (!fRespReqd) + pDelStaParams->respReqd = 0; + else { + /* when lim_del_sta is called from processSmeAssocCnf then mlmState is already set properly. */ + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, + eLIM_MLM_WT_DEL_STA_RSP_STATE); + } + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + + psessionEntry->limMlmState = + eLIM_MLM_WT_DEL_STA_RSP_STATE; + + } + pDelStaParams->respReqd = 1; + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + } + + /* Update PE session ID */ + pDelStaParams->sessionId = psessionEntry->peSessionId; + pDelStaParams->smesessionId = psessionEntry->smeSessionId; + + pDelStaParams->staType = pStaDs->staType; + cdf_mem_copy((uint8_t *) pDelStaParams->staMac, + (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr)); + + pDelStaParams->status = CDF_STATUS_SUCCESS; + msgQ.type = WMA_DELETE_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelStaParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("Sessionid %d :Sending SIR_HAL_DELETE_STA_REQ " + "for STAID: %X and AssocID: %d MAC : " + MAC_ADDRESS_STR), pDelStaParams->sessionId, + pDelStaParams->staIdx, pDelStaParams->assocId, + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + if (fRespReqd) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOGE, + FL("Posting DELETE_STA_REQ to HAL failed, reason=%X"), + retCode); + cdf_mem_free(pDelStaParams); + } + + return retCode; +} + +#if defined WLAN_FEATURE_VOWIFI_11R +/** + * lim_add_ft_sta_self()- function to add STA once we have connected with a + * new AP + * @mac_ctx: pointer to global mac structure + * @assoc_id: association id for the station connection + * @session_entry: pe session entr + * + * This function is called to add a STA once we have connected with a new + * AP, that we have performed an FT to. + * + * The Add STA Response is created and now after the ADD Bss Is Successful + * we add the self sta. We update with the association id from the reassoc + * response from the AP. + * + * Return: eSIR_SUCCESS on success else eSirRetStatus failure codes + */ +tSirRetStatus lim_add_ft_sta_self(tpAniSirGlobal mac_ctx, uint16_t assoc_id, + tpPESession session_entry) +{ + tpAddStaParams add_sta_params = NULL; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + + add_sta_params = session_entry->ftPEContext.pAddStaReq; + add_sta_params->assocId = assoc_id; + add_sta_params->smesessionId = session_entry->smeSessionId; + + msg_q.type = WMA_ADD_STA_REQ; + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "Sending WMA_ADD_STA_REQ (aid %d)", + add_sta_params->assocId); +#endif + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + session_entry->limPrevMlmState = session_entry->limMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_WT_ADD_STA_RSP_STATE)); + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (eSIR_SUCCESS != ret_code) { + lim_log(mac_ctx, LOGE, + FL("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X"), + ret_code); + cdf_mem_free(add_sta_params); + } + + session_entry->ftPEContext.pAddStaReq = NULL; + return ret_code; +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/** + * lim_add_sta_self() + * + ***FUNCTION: + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_add_sta_self(tpAniSirGlobal pMac, uint16_t staIdx, uint8_t updateSta, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMacAddr staMac; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + uint32_t shortGi20MhzSupport; + uint32_t shortGi40MhzSupport; + uint32_t ampduLenExponent = 0; + /*This self Sta dot 11 mode comes from the cfg and the expectation here is + * that cfg carries the systemwide capability that device under + * consideration can support. This capability gets plumbed into the cfg + * cache at system initialization time via the .dat and .ini file override + * mechanisms and will not change. If it does change, it is the + * responsibility of SME to evict the selfSta and reissue a new AddStaSelf + * command.*/ + uint32_t selfStaDot11Mode = 0, selfTxWidth = 0; + uint32_t val; + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + lim_log(pMac, LOG1, FL("cfgDot11Mode %d"), (int)selfStaDot11Mode); + wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET, + &selfTxWidth); + lim_log(pMac, LOG1, FL("SGI 20 %d"), (int)selfTxWidth); + lim_log(pMac, LOG1, FL("Roam Channel Bonding Mode %d"), + (int)pMac->roam.configParam.uCfgDot11Mode); + + sir_copy_mac_addr(staMac, psessionEntry->selfMacAddr); + lim_log(pMac, LOG1, FL(MAC_ADDRESS_STR ": "), MAC_ADDR_ARRAY(staMac)); + pAddStaParams = cdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set((uint8_t *) pAddStaParams, sizeof(tAddStaParams), 0); + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + cdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) pAddStaParams->bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->assocId = psessionEntry->limAID; + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = CDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + + /* Update SME session ID */ + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* This will indicate HAL to "allocate" a new STA index */ + pAddStaParams->staIdx = staIdx; + pAddStaParams->updateSta = updateSta; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL( + "Couldn't get SHORT_PREAMBLE, set default")); + pAddStaParams->shortPreambleSupported = 1; + } else { + pAddStaParams->shortPreambleSupported = val; + } + +#ifdef WLAN_FEATURE_11AC + lim_populate_own_rate_set(pMac, &pAddStaParams->supportedRates, NULL, false, + psessionEntry, NULL); +#else + lim_populate_own_rate_set(pMac, &pAddStaParams->supportedRates, NULL, false, + psessionEntry); +#endif + if (IS_DOT11_MODE_HT(selfStaDot11Mode)) { + pAddStaParams->htCapable = true; +#ifdef DISABLE_GF_FOR_INTEROP + if ((psessionEntry->pLimJoinReq != NULL) + && (!psessionEntry->pLimJoinReq->bssDescription. + aniIndicator)) { + lim_log(pMac, LOGE, + FL + (" Turning off Greenfield, when adding self entry")); + pAddStaParams->greenFieldCapable = + WNI_CFG_GREENFIELD_CAPABILITY_DISABLE; + } else +#endif + { + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->ch_width = + pMac->roam.configParam.channelBondingMode5GHz; + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, + psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, + psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + /* + * We will read the gShortGI20Mhz from ini file, and if it is set + * to 1 then we will tell Peer that we support 40Mhz short GI + */ + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_20MHZ, + &shortGi20MhzSupport))) { + if (true == shortGi20MhzSupport) { + pAddStaParams->fShortGI20Mhz = + WNI_CFG_SHORT_GI_20MHZ_STAMAX; + } else { + pAddStaParams->fShortGI20Mhz = false; + } + } else { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve shortGI 20Mhz" + "CFG,setting value to default")); + ) + pAddStaParams->fShortGI20Mhz = + WNI_CFG_SHORT_GI_20MHZ_STADEF; + } + + /* + * We will read the gShortGI40Mhz from ini file, and if it is set + * to 1 then we will tell Peer that we support 40Mhz short GI + */ + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_40MHZ, + &shortGi40MhzSupport))) { + if (true == shortGi40MhzSupport) { + pAddStaParams->fShortGI40Mhz = + WNI_CFG_SHORT_GI_40MHZ_STAMAX; + } else { + pAddStaParams->fShortGI40Mhz = false; + } + } else { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve shortGI 40Mhz" + "CFG,setting value to default")); + ) + pAddStaParams->fShortGI40Mhz = + WNI_CFG_SHORT_GI_40MHZ_STADEF; + } + lim_log(pMac, LOG2, + FL(" greenFieldCapable: %d maxAmpduDensity = %d " + "maxAmpduSize = %d"), + pAddStaParams->greenFieldCapable, + pAddStaParams->maxAmpduDensity, + pAddStaParams->maxAmpduSize); + + lim_log(pMac, LOG2, + FL("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d " + "fShortGI40Mhz: %d lsigTxopProtection: %d"), + pAddStaParams->fDsssCckMode40Mhz, + pAddStaParams->fShortGI20Mhz, + pAddStaParams->fShortGI40Mhz, + pAddStaParams->lsigTxopProtection); + + lim_log(pMac, LOG2, + FL("maxAmsduSize: %d txChannelWidth: %d mimoPS: %d rifsMode %d"), + pAddStaParams->maxAmsduSize, + pAddStaParams->ch_width, + pAddStaParams->mimoPS, pAddStaParams->rifsMode); + } + } +#ifdef WLAN_FEATURE_11AC + pAddStaParams->vhtCapable = IS_DOT11_MODE_VHT(selfStaDot11Mode); + if (pAddStaParams->vhtCapable) { + pAddStaParams->ch_width = + psessionEntry->ch_width; + lim_log(pMac, LOG1, FL("VHT WIDTH SET %d"), + pAddStaParams->ch_width); + } + pAddStaParams->vhtTxBFCapable = psessionEntry->txBFIniFeatureEnabled; + pAddStaParams->enable_su_tx_bformer = + psessionEntry->enable_su_tx_bformer; + lim_log(pMac, LOG2, FL("vhtCapable: %d vhtTxBFCapable %d, su_bfer %d"), + pAddStaParams->vhtCapable, pAddStaParams->vhtTxBFCapable, + pAddStaParams->enable_su_tx_bformer); + + /* In 11ac mode, the hardware is capable of supporting 128K AMPDU size */ + if (IS_DOT11_MODE_VHT(selfStaDot11Mode)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &duLenExponent) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT")); + } + pAddStaParams->maxAmpduSize = (uint8_t) ampduLenExponent; + } + pAddStaParams->vhtTxMUBformeeCapable = psessionEntry->txMuBformee; + pAddStaParams->enableVhtpAid = psessionEntry->enableVhtpAid; +#endif + pAddStaParams->enableAmpduPs = psessionEntry->enableAmpduPs; + pAddStaParams->enableHtSmps = psessionEntry->enableHtSmps; + pAddStaParams->htSmpsconfig = psessionEntry->htSmpsvalue; + + /* For Self STA get the LDPC capability from session i.e config.ini */ + pAddStaParams->htLdpcCapable = + (psessionEntry->txLdpcIniFeatureEnabled & 0x01); + pAddStaParams->vhtLdpcCapable = + ((psessionEntry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + if (CDF_P2P_CLIENT_MODE == psessionEntry->pePersona) { + pAddStaParams->p2pCapableSta = 1; + } + + pAddStaParams->supportedRates.opRateMode = + lim_get_sta_rate_mode((uint8_t) selfStaDot11Mode); + + lim_log(pMac, LOG2, FL(" StaIdx: %d updateSta = %d htcapable = %d "), + pAddStaParams->staIdx, pAddStaParams->updateSta, + pAddStaParams->htCapable); + + lim_log(pMac, LOG2, FL("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d"), + pAddStaParams->htLdpcCapable, pAddStaParams->vhtLdpcCapable, + pAddStaParams->p2pCapableSta); + + if (psessionEntry->isNonRoamReassoc) { + pAddStaParams->nonRoamReassoc = 1; + psessionEntry->isNonRoamReassoc = 0; + } + lim_log(pMac, LOG2, FL("sessionid: %d Assoc ID: %d listenInterval = %d " + "shortPreambleSupported: %d"), + psessionEntry->smeSessionId, pAddStaParams->assocId, + pAddStaParams->listenInterval, + pAddStaParams->shortPreambleSupported); + + msgQ.type = WMA_ADD_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pAddStaParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL(MAC_ADDRESS_STR ":Sessionid %d : " + "Sending WMA_ADD_STA_REQ. (aid %d)"), + MAC_ADDR_ARRAY(pAddStaParams->staMac), + pAddStaParams->sessionId, pAddStaParams->assocId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, + FL("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X"), + retCode); + cdf_mem_free(pAddStaParams); + } + return retCode; +} + +/** + * limTeardownInfraBSS() + * + ***FUNCTION: + * This function is called by various LIM functions to teardown + * an established Infrastructure BSS + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_teardown_infra_bss(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + /** + * Send Broadcast Disassociate frame with + * 'leaving BSS' reason. + */ + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); +} /*** end lim_teardown_infra_bss() ***/ + +/** + * lim_handle_cnf_wait_timeout() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue to handle + * various confirmation failure cases. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to a sta descriptor + * @return None + */ + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId) +{ + tpDphHashNode pStaDs; + tpPESession psessionEntry = NULL; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + pStaDs = dph_get_hash_entry(pMac, staId, &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + PELOGW(lim_log + (pMac, LOGW, + FL("No STA context in SIR_LIM_CNF_WAIT_TIMEOUT.")); + ) + return; + } + + switch (pStaDs->mlmStaContext.mlmState) { + case eLIM_MLM_WT_ASSOC_CNF_STATE: + PELOGW(lim_log + (pMac, LOGW, + FL + ("Did not receive Assoc Cnf in eLIM_MLM_WT_ASSOC_CNF_STATE sta Assoc id %d"), + pStaDs->assocId); + ) + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGW); + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, + pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + } + break; + + default: + lim_log(pMac, LOGW, FL("Received CNF_WAIT_TIMEOUT in state %d"), + pStaDs->mlmStaContext.mlmState); + } +} + +/** + * lim_delete_dph_hash_entry()- function to delete dph hash entry + * @mac_ctx: pointer to global mac structure + * @sta_addr: peer station address + * @sta_id: id assigned to peer station + * @session_entry: pe session entry + * + * This function is called whenever we need to delete + * the dph hash entry + * + * Return: none + */ + +void +lim_delete_dph_hash_entry(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr, + uint16_t sta_id, tpPESession session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tUpdateBeaconParams beacon_params; + + cdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, eLIM_CNF_WAIT_TIMER, + sta_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("NULL session_entry")); + return; + } + + beacon_params.bssIdx = session_entry->bssIdx; + sta_ds = dph_lookup_hash_entry(mac_ctx, sta_addr, &aid, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("sta_ds is NULL")); + return; + } + + lim_log(mac_ctx, LOGW, FL("Deleting DPH Hash entry for STAID: %X"), + sta_id); + /* + * update the station count and perform associated actions + * do this before deleting the dph hash entry + */ + lim_util_count_sta_del(mac_ctx, sta_ds, session_entry); + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry)) { + if (LIM_IS_AP_ROLE(session_entry)) { + if (session_entry->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_ap_protection_on_delete(mac_ctx, + sta_ds, &beacon_params, session_entry); + } + + if (LIM_IS_IBSS_ROLE(session_entry)) + lim_ibss_decide_protection_on_delete(mac_ctx, sta_ds, + &beacon_params, session_entry); + + lim_decide_short_preamble(mac_ctx, sta_ds, &beacon_params, + session_entry); + lim_decide_short_slot(mac_ctx, sta_ds, &beacon_params, + session_entry); + + /* Send message to HAL about beacon parameter change. */ + lim_log(mac_ctx, LOGW, FL("param bitmap = %d "), + beacon_params.paramChangeBitmap); + if (beacon_params.paramChangeBitmap && + (false == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + sch_set_fixed_beacon_fields(mac_ctx, session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } +#ifdef WLAN_FEATURE_11W + tx_timer_delete(&sta_ds->pmfSaQueryTimer); +#endif + } + + if (dph_delete_hash_entry(mac_ctx, sta_addr, sta_id, + &session_entry->dph.dphHashTable) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("error deleting hash entry")); +} + +/** + * lim_check_and_announce_join_success()- function to check if the received + * Beacon/Probe Response is from the BSS that we're attempting to join. + * @mac: pointer to global mac structure + * @beacon_probe_rsp: pointer to reveived beacon/probe response frame + * @header: pointer to received management frame header + * @session_entry: pe session entry + * + * This function is called upon receiving Beacon/Probe Response + * frame in WT_JOIN_BEACON_STATE to check if the received + * Beacon/Probe Response is from the BSS that we're attempting + * to join. + * If the Beacon/Probe Response is indeed from the BSS we're + * attempting to join, join success is sent to SME. + * + * Return: none + */ + +void +lim_check_and_announce_join_success(tpAniSirGlobal mac_ctx, + tSirProbeRespBeacon *beacon_probe_rsp, tpSirMacMgmtHdr header, + tpPESession session_entry) +{ + tSirMacSSid current_ssid; + tLimMlmJoinCnf mlm_join_cnf; + uint32_t val = 0; + uint32_t *noa_duration_from_beacon = NULL; + uint32_t *noa2_duration_from_beacon = NULL; + uint32_t noa; + uint32_t total_num_noa_desc = 0; + + cdf_mem_copy(current_ssid.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + + current_ssid.length = (uint8_t) session_entry->ssId.length; + + /* + * Check for SSID only in probe response. Beacons may not carry + * SSID information in hidden SSID case + */ + if (((SIR_MAC_MGMT_FRAME == header->fc.type) && + (SIR_MAC_MGMT_PROBE_RSP == header->fc.subType)) && + current_ssid.length && + (!cdf_mem_compare((uint8_t *) &beacon_probe_rsp->ssId, + (uint8_t *) ¤t_ssid, + (uint8_t) (1 + current_ssid.length)))) { + /* + * Received SSID does not match with the one we've. + * Ignore received Beacon frame + */ + lim_log(mac_ctx, LOG1, + FL("SSID received in Beacon does not match")); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimBcnSSIDMismatchCnt++; +#endif + return; + } + + if (!(LIM_IS_BT_AMP_STA_ROLE(session_entry) || + LIM_IS_STA_ROLE(session_entry))) + return; + + lim_log(mac_ctx, LOG1, + FL("Received Beacon/PR with matching BSSID:%pM PESessionID %d"), + session_entry->bssId, session_entry->peSessionId); + + /* Deactivate Join Failure timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Deactivate Periodic Join timer */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + if (CDF_P2P_CLIENT_MODE == session_entry->pePersona && + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.present) { + + noa_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + 1); + + if (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.num_NoADesc) + total_num_noa_desc = + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence. + num_NoADesc / SIZE_OF_NOA_DESCRIPTOR; + + noa = *noa_duration_from_beacon; + + if (total_num_noa_desc > 1) { + noa2_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + + SIZE_OF_NOA_DESCRIPTOR + 1); + noa += *noa2_duration_from_beacon; + } + + /* + * If MAX Noa exceeds 3 secs we will consider only 3 secs to + * avoid arbitary values in noa duration field + */ + noa = noa > MAX_NOA_PERIOD_IN_MICROSECS ? + MAX_NOA_PERIOD_IN_MICROSECS : noa; + noa = noa / 1000; /* Convert to ms */ + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, &val) == + eSIR_SUCCESS) { + session_entry->defaultAuthFailureTimeout = val; + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + val + noa); + } + } else { + session_entry->defaultAuthFailureTimeout = 0; + } + + /* Update Beacon Interval at CFG database */ + + if (beacon_probe_rsp->HTCaps.present) + lim_update_sta_run_time_ht_capability(mac_ctx, + &beacon_probe_rsp->HTCaps); + if (beacon_probe_rsp->HTInfo.present) + lim_update_sta_run_time_ht_info(mac_ctx, + &beacon_probe_rsp->HTInfo, session_entry); + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + + /* + * update the capability info based on recently received beacon/probe + * response frame + */ + session_entry->limCurrentBssCaps = + lim_get_u16((uint8_t *)&beacon_probe_rsp->capabilityInfo); + + /* + * Announce join success by sending + * Join confirm to SME. + */ + mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; + mlm_join_cnf.protStatusCode = eSIR_MAC_SUCCESS_STATUS; + /* Update PE sessionId */ + mlm_join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + + if (beacon_probe_rsp->vendor2_ie.VHTCaps.present) { + session_entry->is_vendor_specific_vhtcaps = true; + session_entry->vendor_specific_vht_ie_type = + beacon_probe_rsp->vendor2_ie.type; + session_entry->vendor_specific_vht_ie_sub_type = + beacon_probe_rsp->vendor2_ie.sub_type; + lim_log(mac_ctx, LOG1, FL( + "VHT caps are present in vendor specific IE")); + } +} + +/** + * lim_extract_ap_capabilities() + * + ***FUNCTION: + * This function is called to extract all of the AP's capabilities + * from the IEs received from it in Beacon/Probe Response frames + * + ***LOGIC: + * This routine mimics the lim_extract_ap_capability() API. The difference here + * is that this API returns the entire tSirProbeRespBeacon info as is. It is + * left to the caller of this API to use this info as required + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pIE Pointer to starting IE in Beacon/Probe Response + * @param ieLen Length of all IEs combined + * @param beaconStruct A pointer to tSirProbeRespBeacon that needs to be + * populated + * @return status A status reporting eSIR_SUCCESS or eSIR_FAILURE + */ +tSirRetStatus lim_extract_ap_capabilities(tpAniSirGlobal pMac, + uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct) +{ + cdf_mem_set((uint8_t *) beaconStruct, sizeof(tSirProbeRespBeacon), 0); + + PELOG3(lim_log(pMac, LOG3, + FL + ("In lim_extract_ap_capabilities: The IE's being received are:")); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG3, pIE, ieLen); + ) + /* Parse the Beacon IE's, Don't try to parse if we dont have anything in IE */ + if (ieLen > 0) { + if (eSIR_SUCCESS != + sir_parse_beacon_ie(pMac, beaconStruct, pIE, + (uint32_t) ieLen)) { + lim_log(pMac, LOGE, + FL("APCapExtract: Beacon parsing error!")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; +} + +/** + * lim_del_bss() + * + ***FUNCTION: + * This function is called to delete BSS context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_del_bss(tpAniSirGlobal pMac, tpDphHashNode pStaDs, uint16_t bssIdx, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + pDelBssParams = cdf_mem_malloc(sizeof(tDeleteBssParams)); + if (NULL == pDelBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set((uint8_t *) pDelBssParams, sizeof(tDeleteBssParams), 0); + + pDelBssParams->sessionId = psessionEntry->peSessionId; /* update PE session Id */ + + /* DPH was storing the AssocID in staID field, */ + /* staID is actually assigned by HAL when AddSTA message is sent. */ + if (pStaDs != NULL) { + pDelBssParams->bssIdx = pStaDs->bssId; + pStaDs->valid = 0; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + } else + pDelBssParams->bssIdx = bssIdx; + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_BSS_RSP_STATE)); + + if ((psessionEntry->peSessionId == + pMac->lim.limTimers.gLimJoinFailureTimer.sessionId) + && (true == + tx_timer_running(&pMac->lim.limTimers.gLimJoinFailureTimer))) { + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + } + + pDelBssParams->status = CDF_STATUS_SUCCESS; + pDelBssParams->respReqd = 1; + cdf_mem_copy(pDelBssParams->bssid, psessionEntry->bssId, + sizeof(tSirMacAddr)); + pDelBssParams->smesessionId = psessionEntry->smeSessionId; + PELOGW(lim_log + (pMac, LOGW, + FL("Sessionid %d : Sending HAL_DELETE_BSS_REQ " + "for bss idx: %X BSSID:" MAC_ADDRESS_STR), + pDelBssParams->sessionId, pDelBssParams->bssIdx, + MAC_ADDR_ARRAY(psessionEntry->bssId)); + ) + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = WMA_DELETE_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelBssParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOGE, + FL("Posting DELETE_BSS_REQ to HAL failed, reason=%X"), + retCode); + cdf_mem_free(pDelBssParams); + } + + return retCode; +} + +/** + * lim_update_vhtcaps_assoc_resp : Update VHT caps in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_caps: VHT capabilities. + * @psessionEntry : session entry. + * + * Return : void + */ +void lim_update_vhtcaps_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTCaps *vht_caps, tpPESession psessionEntry) +{ + pAddBssParams->staContext.vht_caps = + ((vht_caps->maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (vht_caps->supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (vht_caps->ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (vht_caps->shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (vht_caps->shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (vht_caps->txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (vht_caps->rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (vht_caps->suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (vht_caps->suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (vht_caps->csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (vht_caps->numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (vht_caps->muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (vht_caps->muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (vht_caps->vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (vht_caps->htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (vht_caps->maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (vht_caps->vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (vht_caps->rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (vht_caps->txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (vht_caps->reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + + lim_log(mac_ctx, LOG1, + FL("Updating VHT caps in assoc Response")); +} + +/** + * lim_update_vht_oper_assoc_resp : Update VHT Operations in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_oper: VHT Operations to update. + * @psessionEntry : session entry. + * + * Return : void + */ +void lim_update_vht_oper_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTOperation *vht_oper, tpPESession psessionEntry) +{ + if (vht_oper->chanWidth && + psessionEntry->ch_width) { + pAddBssParams->ch_width = vht_oper->chanWidth + 1; + + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + lim_log(mac_ctx, LOG1, + FL("Updating VHT Operation in assoc Response")); +} + + +/** + * limSendAddBss() + * + ***FUNCTION: + * + ***LOGIC: + * 1) LIM receives eWNI_SME_JOIN_REQ + * 2) For a valid eWNI_SME_JOIN_REQ, LIM sends + * SIR_HAL_ADD_BSS_REQ to HAL + * + ***ASSUMPTIONS: + * JOIN REQ parameters are saved in pMac->lim.gLimMlmJoinReq + * ADD BSS parameters can be obtained from two sources: + * 1) pMac->lim.gLimMlmJoinReq + * 2) beaconStruct, passed as paramter + * So, if a reqd parameter is found in bssDescriptions + * then it is given preference over beaconStruct + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * pAssocRsp contains the structured assoc/reassoc Response got from AP + * beaconstruct Has the ProbeRsp/Beacon structured details + * bssDescription bssDescription passed to PE from the SME + * @return None + */ + +tSirRetStatus lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tpDphHashNode pStaDs = NULL; + uint8_t chanWidthSupp = 0; + uint32_t shortGi20MhzSupport; + uint32_t shortGi40MhzSupport; + uint32_t enableTxBF20MHz; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEVHTOperation *vht_oper = NULL; + tAddStaParams *sta_context; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = cdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } else + cdf_mem_set((uint8_t *) pAddBssParams, sizeof(tAddBssParams), + 0); + + cdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + /* Fill in tAddBssParams selfMacAddr */ + cdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + + lim_log(pMac, LOG1, + FL("sessionid: %d updateEntry = %d limsystemrole = %d "), + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + lim_log(pMac, LOG1, FL("BSSID: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddBssParams->bssId)); + + if (psessionEntry->bssType == eSIR_BTAMP_AP_MODE) { + pAddBssParams->bssType = eSIR_BTAMP_AP_MODE; + } else { + pAddBssParams->bssType = eSIR_INFRASTRUCTURE_MODE; + } + + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + /* Update PE session ID */ + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = pAssocRsp->supportedRates.numRates; + cdf_mem_copy(pAddBssParams->rateSet.rate, + pAssocRsp->supportedRates.rate, + pAssocRsp->supportedRates.numRates); + + if (IS_DOT11_MODE_11B(psessionEntry->dot11mode) && + bssDescription->nwType != eSIR_11B_NW_TYPE) { + pAddBssParams->nwType = eSIR_11B_NW_TYPE; + } else { + pAddBssParams->nwType = bssDescription->nwType; + } + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + lim_log(pMac, LOG2, FL(" BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d"), pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + lim_log(pMac, LOG2, + FL(" cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining:" + " %d numRates: %d "), pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + lim_log(pMac, LOG2, FL("nwType:%d shortSlotTimeSupported: %d" + "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d"), + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + lim_log(pMac, LOG2, FL("dot11_mode:%d"), pAddBssParams->dot11_mode); + + /* Use the advertised capabilities from the received beacon/PR */ + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pAssocRsp->HTCaps.present)) { + pAddBssParams->htCapable = pAssocRsp->HTCaps.present; + lim_log(pMac, LOG2, FL("htCapable: %d"), + pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pAssocRsp->HTInfo.opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pAssocRsp->HTInfo.dualCTSProtection; + chanWidthSupp = + lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + if ((pAssocRsp->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pAssocRsp->HTInfo.recommendedTxWidthSet; + if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pAssocRsp->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pAssocRsp->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = pAssocRsp->HTInfo.rifsMode; + + lim_log(pMac, LOGE, + FL("htOperMode: %d dualCTSProtection: %d txChannelWidth: %d center_freq_0: %d "), + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0); + + lim_log(pMac, LOG2, FL("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d"), + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + lim_log(pMac, LOGE, FL("currentOperChannel %d"), + pAddBssParams->currentOperChannel); + if (psessionEntry->vhtCapability && (pAssocRsp->VHTCaps.present)) { + pAddBssParams->vhtCapable = pAssocRsp->VHTCaps.present; + vht_caps = &pAssocRsp->VHTCaps; + vht_oper = &pAssocRsp->VHTOperation; + } else if (psessionEntry->vhtCapability && + pAssocRsp->vendor2_ie.VHTCaps.present){ + pAddBssParams->vhtCapable = + pAssocRsp->vendor2_ie.VHTCaps.present; + lim_log(pMac, LOG1, + FL("VHT Caps and Operation are present in vendor Specfic IE")); + vht_caps = &pAssocRsp->vendor2_ie.VHTCaps; + vht_oper = &pAssocRsp->vendor2_ie.VHTOperation; + } else { + pAddBssParams->vhtCapable = 0; + } + if (pAddBssParams->vhtCapable) { + if (vht_oper != NULL) + lim_update_vht_oper_assoc_resp(pMac, pAddBssParams, + vht_oper, psessionEntry); + if (vht_caps != NULL) + lim_update_vhtcaps_assoc_resp(pMac, pAddBssParams, + vht_caps, psessionEntry); + } + + lim_log(pMac, LOGE, FL("vhtCapable %d TxChannelWidth %d center_freq_0 %d center_freq_1 %d"), + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + * staType = PEER + */ + sta_context = &pAddBssParams->staContext; + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + cdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + /* Fill Assoc id from the dph table */ + pStaDs = dph_lookup_hash_entry(pMac, pAddBssParams->staContext.bssId, + &pAddBssParams->staContext.assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, FL( + "Couldn't get assoc id for " "MAC ADDR: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pAddBssParams->staContext.staMac)); + return eSIR_FAILURE; + } + + pAddBssParams->staContext.uAPSD = + psessionEntry->gUapsdPerAcBitmask; + + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + lim_log(pMac, LOG2, FL("StaContext: " MAC_ADDRESS_STR + " shortPreambleSupported: %d"), + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pAssocRsp->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pAssocRsp->HTCaps.lsigTXOPProtection; + lim_log(pMac, LOG2, FL( + "StaCtx: htCap %d GFcap %d lsigTxopProtn %d"), + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE( + pBeaconStruct->vendor2_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + pAddBssParams->staContext.vhtSupportedRxNss = + pStaDs->vhtSupportedRxNss; + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor2_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor2_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps are in vendor Specfic IE")); + } + + if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->txBFIniFeatureEnabled) + sta_context->vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->txMuBformee) + sta_context->vhtTxMUBformeeCapable = 1; + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->enable_su_tx_bformer) + sta_context->enable_su_tx_bformer = 1; + } + + if ((pAssocRsp->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = (uint8_t) + pAssocRsp->HTInfo.recommendedTxWidthSet; + if (pAssocRsp->VHTCaps.present) + vht_oper = &pAssocRsp->VHTOperation; + else if (pAssocRsp->vendor2_ie.VHTCaps.present) { + vht_oper = &pAssocRsp->vendor2_ie.VHTOperation; + lim_log(pMac, LOG1, FL( + "VHT Op IE is in vendor Specfic IE")); + } + if ((vht_oper != NULL) && + pAddBssParams->staContext.vhtCapable && + vht_oper->chanWidth) + pAddBssParams->staContext.ch_width = + vht_oper->chanWidth + 1; + + lim_log(pMac, LOGE, FL( + "StaCtx: vhtCap %d ChBW %d TxBF %d"), + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + sta_context->vhtTxBFCapable); + lim_log(pMac, LOGE, FL("StaContext su_tx_bfer %d"), + sta_context->enable_su_tx_bformer); + } else { + sta_context->ch_width = CH_WIDTH_20MHZ; + if ((IS_SIR_STATUS_SUCCESS( + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enableTxBF20MHz))) && + (false == enableTxBF20MHz)) + sta_context->vhtTxBFCapable = 0; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) + pAssocRsp->HTCaps.mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pAssocRsp->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pAssocRsp->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pAssocRsp->HTCaps.dsssCckMode40MHz; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from + * ini file. if they are set then we will use what ever + * Assoc response coming from AP supports. If these + * values are set as 0 in ini file then we will + * hardcode this values to 0. + */ + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_20MHZ, + &shortGi20MhzSupport))) { + if (true == shortGi20MhzSupport) { + pAddBssParams->staContext. + fShortGI20Mhz = + (uint8_t) pAssocRsp->HTCaps. + shortGI20MHz; + } else { + pAddBssParams->staContext. + fShortGI20Mhz = false; + } + } else { + lim_log(pMac, LOGE, FL( + "failed to get shortGI 20Mhz, set default")); + pAddBssParams->staContext.fShortGI20Mhz = + WNI_CFG_SHORT_GI_20MHZ_STADEF; + } + + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_40MHZ, + &shortGi40MhzSupport))) { + if (true == shortGi40MhzSupport) { + pAddBssParams->staContext. + fShortGI40Mhz = + (uint8_t) pAssocRsp->HTCaps. + shortGI40MHz; + } else { + pAddBssParams->staContext. + fShortGI40Mhz = false; + } + } else { + lim_log(pMac, LOGE, FL( + "failed to get shortGI 40Mhz, set default")); + pAddBssParams->staContext.fShortGI40Mhz = + WNI_CFG_SHORT_GI_40MHZ_STADEF; + } + + if (!pAddBssParams->staContext.vhtCapable) + /* Use max ampd factor advertised in + * HTCAP for non-vht connection */ + { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } else if (pAddBssParams->staContext.maxAmpduSize < + pAssocRsp->HTCaps.maxRxAMPDUFactor) { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } + if (pAddBssParams->staContext.vhtTxBFCapable + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pAssocRsp->HTCaps.advCodingCap; + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor2_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor2_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps is in vendor Specfic IE")); + } + if (vht_caps != NULL) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + } + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pAssocRsp->HTInfo.rifsMode; + + lim_log(pMac, LOGE, FL( + "StaCtx: ChBW %d mimoPS %d maxAmsduSize %d"), + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + lim_log(pMac, LOG2, FL( + "maxAmpduDens %d CckMode40Mhz %d SGI20Mhz %d"), + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + lim_log(pMac, LOG2, FL( + "SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d"), + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + pAddBssParams->staContext.smesessionId = + psessionEntry->smeSessionId; + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + if ((!pAddBssParams->staContext.wpa_rsn) + && (psessionEntry->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + cdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pAssocRsp->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + cdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pAssocRsp->HTCaps + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + + /* If WMM IE or 802.11E IE is present then enable WMM */ + if ((psessionEntry->limWmeEnabled && pAssocRsp->wmeEdcaPresent) || + (psessionEntry->limQosEnabled && pAssocRsp->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + lim_fill_supported_rates_info(pMac, pStaDs, + &pStaDs->supportedRates, + psessionEntry); + cdf_mem_copy((uint8_t *) &pAddBssParams->staContext. + supportedRates, + (uint8_t *) &pStaDs->supportedRates, + sizeof(tSirSupportedRates)); + } else + lim_log(pMac, LOGE, FL( + "could not Update the supported rates")); + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + +#if defined WLAN_FEATURE_VOWIFI + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + lim_log(pMac, LOG2, FL("maxTxPower: %d"), pAddBssParams->maxTxPower); +#endif + /* FIXME_GEN4 - Any other value that can be used for initialization? */ + pAddBssParams->status = CDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + /* update persona */ + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; + + if (CDF_P2P_CLIENT_MODE == psessionEntry->pePersona) + pAddBssParams->staContext.p2pCapableSta = 1; + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + +#if defined WLAN_FEATURE_VOWIFI_11R + pAddBssParams->extSetStaKeyParamValid = 0; + lim_log(pMac, LOG2, FL("extSetStaKeyParamValid: %d"), + pAddBssParams->extSetStaKeyParamValid); +#endif + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + /* Set a new state for MLME */ + if (eLIM_MLM_WT_ASSOC_RSP_STATE == psessionEntry->limMlmState) + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; + else + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + lim_log(pMac, LOG2, FL("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d"), + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + lim_log(pMac, LOG2, FL("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d"), + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + if (psessionEntry->isNonRoamReassoc) + pAddBssParams->nonRoamReassoc = 1; + pAddBssParams->nss = psessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pAddBssParams->nss); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("SessionId:%d Sending WMA_ADD_BSS_REQ"), + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + cdf_mem_free(pAddBssParams); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + goto returnFailure; + + } else + return retCode; + +returnFailure: + /* Clean-up will be done by the caller... */ + return retCode; +} + +tSirRetStatus lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tSchBeaconStruct *pBeaconStruct; + uint8_t chanWidthSupp = 0; + uint32_t shortGi20MhzSupport; + uint32_t shortGi40MhzSupport; + tDot11fIEVHTOperation *vht_oper = NULL; + tDot11fIEVHTCaps *vht_caps = NULL; + + tpSirBssDescription bssDescription = + &psessionEntry->pLimJoinReq->bssDescription; + + pBeaconStruct = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during ADD_BSS")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = cdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } + + cdf_mem_set((uint8_t *) pAddBssParams, sizeof(tAddBssParams), 0); + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + psessionEntry); + cdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + cdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + lim_log(pMac, LOG1, + FL("sessionid: %d updateEntry = %d limsystemrole = %d "), + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + lim_log(pMac, LOG1, FL("BSSID: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddBssParams->bssId)); + /* Incorrect BSS Type which caused UMA Descriptor to be overwritten on + * top of an already established Infra link. This lead to issues in + * concurrent data transfer. + */ + + pAddBssParams->bssType = psessionEntry->bssType; /* eSIR_INFRASTRUCTURE_MODE; */ + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + cdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + lim_log(pMac, LOG2, FL(" BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d"), pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + lim_log(pMac, LOG2, + FL(" cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining:" + " %d numRates: %d "), pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + lim_log(pMac, LOG2, FL("nwType:%d shortSlotTimeSupported: %d" + "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d"), + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + lim_log(pMac, LOG2, FL("htCapable: %d"), + pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = + lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + + lim_log(pMac, LOG2, + FL("htOperMode: %d dualCTSProtection: %d txChannelWidthSet: %d center_freq_seg0: %d "), + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->txChannelWidthSet, + pAddBssParams->ch_center_freq_seg0); + + lim_log(pMac, LOG2, FL("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d"), + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + lim_log(pMac, LOG2, FL("currentOperChannel %d"), + pAddBssParams->currentOperChannel); +#ifdef WLAN_FEATURE_11AC + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor2_ie.VHTCaps))) { + + pAddBssParams->vhtCapable = 1; + if (pBeaconStruct->VHTOperation.present) + vht_oper = &pBeaconStruct->VHTOperation; + else if (pBeaconStruct->vendor2_ie.VHTOperation.present) { + vht_oper = &pBeaconStruct->vendor2_ie.VHTOperation; + lim_log(pMac, LOG1, + FL("VHT Operation is present in vendor Specfic IE")); + } + + + if ((vht_oper != NULL) && + vht_oper->chanWidth && + chanWidthSupp) { + pAddBssParams->ch_width = + vht_oper->chanWidth + 1; + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + } else { + pAddBssParams->vhtCapable = 0; + } + lim_log(pMac, LOGE, FL("vhtCapable %d vhtTxChannelWidthSet %d center_freq_seg0 - %d, center_freq_seg1 - %d"), + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); +#endif + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + */ + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + cdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + lim_log(pMac, LOG2, FL( + "StaCtx: " MAC_ADDRESS_STR " shortPreamble: %d"), + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + lim_log(pMac, LOG2, FL("dot11_mode:%d"), + pAddBssParams->dot11_mode); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + lim_log(pMac, LOG2, FL( + "StaCtx: htCap %d GFCap %d lsigTxopProtn %d"), + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE( + pBeaconStruct->vendor2_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor2_ie.VHTCaps.present) + vht_caps = &pBeaconStruct->vendor2_ie.VHTCaps; + + if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->txBFIniFeatureEnabled) + pAddBssParams->staContext.vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->txMuBformee) + pAddBssParams->staContext.vhtTxMUBformeeCapable + = 1; + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->enable_su_tx_bformer) + pAddBssParams->staContext.enable_su_tx_bformer + = 1; + lim_log(pMac, LOG2, FL("StaContext: su_tx_bfer %d"), + pAddBssParams->staContext.enable_su_tx_bformer); + } + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if ((vht_oper != NULL) && + pAddBssParams->staContext.vhtCapable && + vht_oper->chanWidth) + pAddBssParams->staContext.ch_width = + vht_oper->chanWidth + 1; + lim_log(pMac, LOG2, FL( + "StaCtx: vhtCap %d ch_bw %d TxBF %d"), + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext. + vhtTxBFCapable); + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from ini file. + * if they are set then we will use what ever Beacon coming + * from AP supports. If these values are set as 0 in ini file + * then we will hardcode this values to 0. + */ + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_20MHZ, + &shortGi20MhzSupport))) { + if (true == shortGi20MhzSupport) + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pBeaconStruct->HTCaps.shortGI20MHz; + else + pAddBssParams->staContext.fShortGI20Mhz = + false; + } else { + lim_log(pMac, LOGE, FL( + "get shortGI 20Mhz failed, set default")); + pAddBssParams->staContext.fShortGI20Mhz = + WNI_CFG_SHORT_GI_20MHZ_STADEF; + } + + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int + (pMac, WNI_CFG_SHORT_GI_40MHZ, + &shortGi40MhzSupport))) { + if (true == shortGi40MhzSupport) { + pAddBssParams->staContext. + fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps. + shortGI40MHz; + } else { + pAddBssParams->staContext. + fShortGI40Mhz = false; + } + } else { + lim_log(pMac, LOGE, FL( + "get shortGI 40Mhz failed, set default")); + pAddBssParams->staContext.fShortGI40Mhz = + WNI_CFG_SHORT_GI_40MHZ_STADEF; + } + + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + if (pAddBssParams->staContext.vhtTxBFCapable + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pBeaconStruct->HTCaps. + advCodingCap; + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor2_ie.VHTCaps.present) { + vht_caps = + &pBeaconStruct->vendor2_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps are in vendor Specfic IE")); + } + if (vht_caps != NULL) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + } + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + lim_log(pMac, LOG2, + FL("StaContext ChannelWidth: %d mimoPS: %d maxAmsduSize: %d"), + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + lim_log(pMac, LOG2, FL( + "maxAmpduDensity %d Cck40Mhz %d SGI20Mhz %d"), + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + lim_log(pMac, LOG2, FL( + "SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d"), + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + /* + * If WMM IE or 802.11E IE is not present + * and AP is HT AP then enable WMM + */ + if ((psessionEntry->limWmeEnabled && (pBeaconStruct->wmeEdcaPresent || + pAddBssParams->staContext.htCapable)) || + (psessionEntry->limQosEnabled && + (pBeaconStruct->edcaPresent || + pAddBssParams->staContext.htCapable))) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ +#ifdef WLAN_FEATURE_11AC + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, psessionEntry, + &pBeaconStruct->VHTCaps); +#else + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, psessionEntry); +#endif + lim_fill_supported_rates_info(pMac, NULL, + &pAddBssParams->staContext. + supportedRates, psessionEntry); + + + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + +#if defined WLAN_FEATURE_VOWIFI + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + lim_log(pMac, LOG2, FL("maxTxPower: %d"), pAddBssParams->maxTxPower); +#endif + + pAddBssParams->status = CDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.smesessionId = psessionEntry->smeSessionId; + pAddBssParams->staContext.sessionId = psessionEntry->peSessionId; + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; /* update persona */ + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + +#if defined WLAN_FEATURE_VOWIFI_11R + pAddBssParams->extSetStaKeyParamValid = 0; + lim_log(pMac, LOG2, FL("extSetStaKeyParamValid: %d"), + pAddBssParams->extSetStaKeyParamValid); +#endif + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->nss = psessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pAddBssParams->nss); + + /* Set a new state for MLME */ + psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + lim_log(pMac, LOG2, FL("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d"), + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + lim_log(pMac, LOG2, FL("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d"), + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("SessionId:%d Sending WMA_ADD_BSS_REQ"), + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + cdf_mem_free(pAddBssParams); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + goto returnFailure; + + } else { + cdf_mem_free(pBeaconStruct); + return retCode; + } + +returnFailure: + /* Clean-up will be done by the caller... */ + cdf_mem_free(pBeaconStruct); + return retCode; +} + +/** + * lim_prepare_and_send_del_sta_cnf() - prepares and send del sta cnf + * + * @pMac: mac global context + * @pStaDs: sta dph node + * @statusCode: status code + * @psessionEntry: session context + * + * deletes DPH entry, changes the MLM mode for station, calls + * lim_send_del_sta_cnf + * + * Return: void + */ +void +lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, + tpPESession psessionEntry) +{ + uint16_t staDsAssocId = 0; + tSirMacAddr staDsAddr; + tLimMlmStaContext mlmStaContext; + + if (pStaDs == NULL) { + PELOGW(lim_log(pMac, LOGW, FL("pStaDs is NULL"));) + return; + } + staDsAssocId = pStaDs->assocId; + cdf_mem_copy((uint8_t *) staDsAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + + mlmStaContext = pStaDs->mlmStaContext; + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + } + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, + psessionEntry); + + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + } + lim_send_del_sta_cnf(pMac, staDsAddr, staDsAssocId, mlmStaContext, + statusCode, psessionEntry); +} + +/** ------------------------------------------------------------- + \fn lim_get_sta_rate_mode + \brief Gets the Station Rate Mode. + \param uint8_t dot11Mode + \return none + -------------------------------------------------------------*/ +tStaRateMode lim_get_sta_rate_mode(uint8_t dot11Mode) +{ + switch (dot11Mode) { + case WNI_CFG_DOT11_MODE_11A: + return eSTA_11a; + case WNI_CFG_DOT11_MODE_11B: + return eSTA_11b; + case WNI_CFG_DOT11_MODE_11G: + return eSTA_11bg; + case WNI_CFG_DOT11_MODE_11N: + return eSTA_11n; +#ifdef WLAN_FEATURE_11AC + case WNI_CFG_DOT11_MODE_11AC: + return eSTA_11ac; +#endif + case WNI_CFG_DOT11_MODE_ALL: + default: + return eSTA_11n; + + } +} + +/** ------------------------------------------------------------- + \fn lim_init_pre_auth_timer_table + \brief Initialize the Pre Auth Tanle and creates the timer for + each node for the timeout value got from cfg. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t cfgValue; + uint32_t authNodeIdx; + tpLimPreAuthNode pAuthNode = pPreAuthTimerTable->pTable; + + /* Get AUTH_RSP Timers value */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) { + /* + ** Could not get AUTH_RSP timeout value + ** from CFG. Log error. + **/ + lim_log(pMac, LOGP, + FL("could not retrieve AUTH_RSP timeout value")); + return; + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (authNodeIdx = 0; authNodeIdx < pPreAuthTimerTable->numEntry; + authNodeIdx++, pAuthNode++) { + if (tx_timer_create + (&pAuthNode->timer, "AUTH RESPONSE TIMEOUT", + lim_auth_response_timer_handler, authNodeIdx, cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + /* Cannot create timer. Log error. */ + lim_log(pMac, LOGP, + FL("Cannot create Auth Rsp timer of Index :%d."), + authNodeIdx); + return; + } + pAuthNode->authNodeIdx = (uint8_t) authNodeIdx; + pAuthNode->fFree = 1; + } + +} + +/** ------------------------------------------------------------- + \fn lim_acquire_free_pre_auth_node + \brief Retrives a free Pre Auth node from Pre Auth Table. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t i; + tLimPreAuthNode *pTempNode = pPreAuthTimerTable->pTable; + for (i = 0; i < pPreAuthTimerTable->numEntry; i++, pTempNode++) { + if (pTempNode->fFree == 1) { + pTempNode->fFree = 0; + return pTempNode; + } + } + + return NULL; +} + +/** ------------------------------------------------------------- + \fn lim_get_pre_auth_node_from_index + \brief Depending on the Index this retrives the pre auth node. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pAuthTable + \param uint32_t authNodeIdx + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx) +{ + if ((authNodeIdx >= pAuthTable->numEntry) + || (pAuthTable->pTable == NULL)) { + lim_log(pMac, LOGE, + FL("Invalid Auth Timer Index : %d NumEntry : %d"), + authNodeIdx, pAuthTable->numEntry); + return NULL; + } + + return pAuthTable->pTable + authNodeIdx; +} + +/* Util API to check if the channels supported by STA is within range */ +tSirRetStatus lim_is_dot11h_supported_channels_valid(tpAniSirGlobal pMac, + tSirAssocReq *assoc) +{ + /* + * Allow all the stations to join with us. + * 802.11h-2003 11.6.1 => An AP may use the supported channels list for associated STAs + * as an input into an algorithm used to select a new channel for the BSS. + * The specification of the algorithm is beyond the scope of this amendment. + */ + + return eSIR_SUCCESS; +} + +/* Util API to check if the txpower supported by STA is within range */ +tSirRetStatus lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession psessionEntry) +{ + tPowerdBm localMaxTxPower; + uint32_t localPwrConstraint; + + localMaxTxPower = + cfg_get_regulatory_max_transmit_power(pMac, + psessionEntry->currentOperChannel); + + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Local Power Constraint from cfg")); + return eSIR_FAILURE; + } + localMaxTxPower -= (tPowerdBm) localPwrConstraint; + + /** + * The min Tx Power of the associating station should not be greater than (regulatory + * max tx power - local power constraint configured on AP). + */ + if (assoc->powerCapability.minTxPower > localMaxTxPower) { + lim_log(pMac, LOGW, + FL("minTxPower (STA) = %d, localMaxTxPower (AP) = %d"), + assoc->powerCapability.minTxPower, localMaxTxPower); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_fill_rx_highest_supported_rate + \brief Fills in the Rx Highest Supported Data Rate field from + \ the 'supported MCS set' field in HT capability element. + \param tpAniSirGlobal pMac + \param tpSirSupportedRates pRates + \param uint8_t* pSupportedMCSSet + \return none + -------------------------------------------------------------*/ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet) +{ + tSirMacRxHighestSupportRate *pRxHighestRate; + uint8_t *pBuf; + uint16_t rate = 0; + + pBuf = pSupportedMCSSet + MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET; + rate = lim_get_u16(pBuf); + + pRxHighestRate = (tSirMacRxHighestSupportRate *) &rate; + *rxHighestRate = pRxHighestRate->rate; + + return; +} + +#ifdef WLAN_FEATURE_11W +/** ------------------------------------------------------------- + \fn lim_send_sme_unprotected_mgmt_frame_ind + \brief Forwards the unprotected management frame to SME. + \param tpAniSirGlobal pMac + \param frameType - 802.11 frame type + \param frame - frame buffer + \param sessionId - id for the current session + \param psessionEntry - PE session context + \return none + -------------------------------------------------------------*/ +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeUnprotMgmtFrameInd *pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeUnprotMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = cdf_mem_malloc(length); + if (NULL == pSirSmeMgmtFrame) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for tSirSmeUnprotectedMgmtFrameInd")); + return; + } + cdf_mem_set((void *)pSirSmeMgmtFrame, length, 0); + + pSirSmeMgmtFrame->sessionId = sessionId; + pSirSmeMgmtFrame->frameType = frameType; + + cdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); + pSirSmeMgmtFrame->frameLen = frameLen; + + mmhMsg.type = eWNI_SME_UNPROT_MGMT_FRM_IND; + mmhMsg.bodyptr = pSirSmeMgmtFrame; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** ------------------------------------------------------------- + \fn lim_send_sme_tsm_ie_ind + \brief Forwards the TSM IE information to SME. + \param tpAniSirGlobal pMac + \param psessionEntry - PE session context + \param tid - traffic id + \param state - tsm state (enabled/disabled) + \param measurementInterval - measurement interval + \return none + -------------------------------------------------------------*/ +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval) +{ + tSirMsgQ mmhMsg; + tpSirSmeTsmIEInd pSirSmeTsmIeInd = NULL; + + if (!pMac || !psessionEntry) + return; + + pSirSmeTsmIeInd = cdf_mem_malloc(sizeof(tSirSmeTsmIEInd)); + if (NULL == pSirSmeTsmIeInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for tSirSmeTsmIEInd")); + return; + } + cdf_mem_set((void *)pSirSmeTsmIeInd, sizeof(tSirSmeTsmIEInd), 0); + + pSirSmeTsmIeInd->sessionId = psessionEntry->smeSessionId; + pSirSmeTsmIeInd->tsmIe.tsid = tid; + pSirSmeTsmIeInd->tsmIe.state = state; + pSirSmeTsmIeInd->tsmIe.msmt_interval = measInterval; + + mmhMsg.type = eWNI_SME_TSM_IE_IND; + mmhMsg.bodyptr = pSirSmeTsmIeInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ diff --git a/core/mac/src/pe/lim/lim_assoc_utils.h b/core/mac/src/pe/lim/lim_assoc_utils.h new file mode 100644 index 0000000000..b9efbff3c8 --- /dev/null +++ b/core/mac/src/pe/lim/lim_assoc_utils.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_assoc_utils.h contains the utility definitions + * LIM uses while processing Re/Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ +#ifndef __LIM_ASSOC_UTILS_H +#define __LIM_ASSOC_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "lim_types.h" + +uint8_t lim_cmp_s_sid(tpAniSirGlobal, tSirMacSSid *, tpPESession); +uint8_t lim_compare_capabilities(tpAniSirGlobal, + tSirAssocReq *, + tSirMacCapabilityInfo *, tpPESession); +uint8_t lim_check_rx_basic_rates(tpAniSirGlobal, tSirMacRateSet, tpPESession); +uint8_t lim_check_rx_rsn_ie_match(tpAniSirGlobal, tDot11fIERSN, tpPESession, uint8_t, + bool *); +uint8_t lim_check_rx_wpa_ie_match(tpAniSirGlobal, tDot11fIEWPA, tpPESession, + uint8_t); +uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet); +void limPostDummyToTmRing(tpAniSirGlobal, tpDphHashNode); +void limPostPacketToTdRing(tpAniSirGlobal, tpDphHashNode, uint8_t); +tSirRetStatus lim_cleanup_rx_path(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_reject_association(tpAniSirGlobal, tSirMacAddr, uint8_t, + uint8_t, tAniAuthType, + uint16_t, uint8_t, tSirResultCodes, tpPESession); + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps); +#else +tSirRetStatus lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry); +#endif + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus lim_populate_own_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps); + +#else +tSirRetStatus lim_populate_own_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry); +#endif + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +lim_populate_matching_rate_set(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tSirMacRateSet *pOperRateSet, + tSirMacRateSet *pExtRateSet, + uint8_t *pSupportedMCSSet, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps); +#else +tSirRetStatus lim_populate_matching_rate_set(tpAniSirGlobal, + tpDphHashNode, + tSirMacRateSet *, + tSirMacRateSet *, + uint8_t *pSupportedMCSSet, + tpPESession); + +#endif + +#ifdef WLAN_FEATURE_11AC +#define MCSMAPMASK1x1 0x3 +#define MCSMAPMASK2x2 0xC +#endif + +tSirRetStatus lim_add_sta(tpAniSirGlobal, tpDphHashNode, uint8_t, tpPESession); +tSirRetStatus lim_del_bss(tpAniSirGlobal, tpDphHashNode, uint16_t, tpPESession); +tSirRetStatus lim_del_sta(tpAniSirGlobal, tpDphHashNode, bool, tpPESession); +#ifdef WLAN_FEATURE_VOWIFI_11R +tSirRetStatus lim_add_ft_sta_self(tpAniSirGlobal pMac, uint16_t assocId, + tpPESession psessionEntry); +#endif /* WLAN_FEATURE_VOWIFI_11R */ +tSirRetStatus lim_add_sta_self(tpAniSirGlobal, uint16_t, uint8_t, tpPESession); +tStaRateMode lim_get_sta_rate_mode(uint8_t dot11Mode); + +void lim_teardown_infra_bss(tpAniSirGlobal, tpPESession); +void lim_restore_pre_reassoc_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +void lim_post_reassoc_failure(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +bool lim_is_reassoc_in_progress(tpAniSirGlobal, tpPESession); +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, tSirMacAddr staDsAddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry); + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId); +void lim_delete_dph_hash_entry(tpAniSirGlobal, tSirMacAddr, uint16_t, tpPESession); +void lim_check_and_announce_join_success(tpAniSirGlobal, + tSirProbeRespBeacon *, + tpSirMacMgmtHdr, tpPESession); +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, + tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); + +void lim_update_assoc_sta_datas(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); +void lim_fill_supported_rates_info(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpSirSupportedRates pRates, + tpPESession psessionEntry); + +tSirRetStatus lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry); +tSirRetStatus lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry); + +void lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, tpPESession); +tSirRetStatus lim_extract_ap_capabilities(tpAniSirGlobal pMac, uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct); +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable); +tpLimPreAuthNode lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + tpLimPreAuthTable + pPreAuthTimerTable); +tpLimPreAuthNode lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx); + +/* Util API to check if the channels supported by STA is within range */ +tSirRetStatus lim_is_dot11h_supported_channels_valid(tpAniSirGlobal pMac, + tSirAssocReq *assoc); + +/* Util API to check if the txpower supported by STA is within range */ +tSirRetStatus lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession); + +/* API to re-add the same BSS during re-association */ +void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +/* API to fill in RX Highest Supported data Rate */ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet); +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry); +#endif +#ifdef WLAN_FEATURE_11W +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry); +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval); +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +#endif /* __LIM_ASSOC_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_debug.c b/core/mac/src/pe/lim/lim_debug.c new file mode 100644 index 0000000000..51620d78bf --- /dev/null +++ b/core/mac/src/pe/lim/lim_debug.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_debug.c + + \brief implementation for log Debug related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#include "lim_debug.h" + +void lim_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_LIM_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_LIM_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} diff --git a/core/mac/src/pe/lim/lim_debug.h b/core/mac/src/pe/lim/lim_debug.h new file mode 100644 index 0000000000..e0ab7f6251 --- /dev/null +++ b/core/mac/src/pe/lim/lim_debug.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_debug.h contains log function called by LIM module. + * + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_DEBUG_H__ +#define __LIM_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) lim_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +/* define this to show more message in the LIM during TDLS development */ +#define LIM_DEBUG_TDLS + +#ifdef LIM_DEBUG_TDLS +#define LIM_LOG_TDLS(x0) x0 +#else +#define LIM_LOG_TDLS(x0) +#endif + +#endif diff --git a/core/mac/src/pe/lim/lim_ft.c b/core/mac/src/pe/lim/lim_ft.c new file mode 100644 index 0000000000..c96327c12d --- /dev/null +++ b/core/mac/src/pe/lim/lim_ft.c @@ -0,0 +1,2027 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef WLAN_FEATURE_VOWIFI_11R +/**========================================================================= + + \brief implementation for PE 11r VoWiFi FT Protocol + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmm_apsd.h" + +extern void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp); + +/*-------------------------------------------------------------------------- + Initialize the FT variables. + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry) + cdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), + 0); +} + +/*-------------------------------------------------------------------------- + Cleanup FT variables. + ------------------------------------------------------------------------*/ +void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tpPESession pReAssocSessionEntry = NULL; + uint8_t sessionId = 0; + + if (!psessionEntry) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, "%s: psessionEntry is NULL", __func__); + ) +#endif + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq) { + pReAssocSessionEntry = + pe_find_session_by_bssid(pMac, + psessionEntry->ftPEContext. + pFTPreAuthReq->preAuthbssId, + &sessionId); + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOG1(lim_log(pMac, LOG1, FL("Freeing pFTPreAuthReq= %p"), + psessionEntry->ftPEContext.pFTPreAuthReq); + ) +#endif + if (psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + cdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + cdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + cdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + cdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + cdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), 0); + + /* Delete the session created while handling pre-auth response */ + if (pReAssocSessionEntry) { + /* If we have successful pre-auth response, then we would have + * created a session on which reassoc request will be sent + */ + if (pReAssocSessionEntry->valid && + pReAssocSessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) { + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_DEBUG, + FL("Deleting Preauth session(%d)"), + pReAssocSessionEntry->peSessionId); + pe_delete_session(pMac, pReAssocSessionEntry); + } + } +} + +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac) +{ + /* Wrapper function to cleanup all FT sessions */ + int i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid) { + /* The session is valid, may have FT data */ + lim_ft_cleanup(pMac, &pMac->lim.gpSession[i]); + } + } +} + +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (NULL == psessionEntry) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL"));) +#endif + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + + if (NULL != psessionEntry->ftPEContext.pFTPreAuthReq) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOG1(lim_log(pMac, LOG1, FL("Freeing pFTPreAuthReq= %p"), + psessionEntry->ftPEContext.pFTPreAuthReq); + ) +#endif + if (NULL != + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + cdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + cdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + cdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + cdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + cdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), 0); +} + +/*------------------------------------------------------------------ + * + * This is the handler after suspending the link. + * We suspend the link and then now proceed to switch channel. + * + *------------------------------------------------------------------*/ +void static +lim_ft_pre_auth_suspend_link_handler(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data) +{ + tpPESession psessionEntry = (tpPESession) data; + + /* The link is suspended of not */ + if (NULL == psessionEntry || + NULL == psessionEntry->ftPEContext.pFTPreAuthReq || + status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, + FL("preAuth error, status = %d"), status); + ) + lim_post_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0, + psessionEntry); + return; + } + + /* Suspended, now move to a different channel. + * Perform some sanity check before proceeding + */ + if (psessionEntry->ftPEContext.pFTPreAuthReq) { + lim_change_channel_with_callback(pMac, + psessionEntry->ftPEContext. + pFTPreAuthReq->preAuthchannelNum, + lim_perform_ft_pre_auth, NULL, + psessionEntry); + return; + } +} + +/* + * lim_process_ft_pre_auth_req() - process ft pre auth req + * + * @mac_ctx: global mac ctx + * @msg: pointer to message + * + * In this function, we process the FT Pre Auth Req: + * We receive Pre-Auth, suspend link, register a call back. In the call back, + * we will need to accept frames from the new bssid. Send out the auth req to + * new AP. Start timer and when the timer is done or if we receive the Auth + * response. We change channel. Resume link + * + * Return: value to indicate if buffer was consumed + */ +int lim_process_ft_pre_auth_req(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + int buf_consumed = false; + tpPESession session; + uint8_t session_id; + tpSirFTPreAuthReq ft_pre_auth_req = (tSirFTPreAuthReq *) msg->bodyptr; + + if (NULL == ft_pre_auth_req) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(mac_ctx, LOGE, FL("tSirFTPreAuthReq is NULL"));) +#endif + return buf_consumed; + } + + /* Get the current session entry */ + session = pe_find_session_by_bssid(mac_ctx, + ft_pre_auth_req->currbssId, + &session_id); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Unable to find session for the bssid" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(ft_pre_auth_req->currbssId)); + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(mac_ctx, eSIR_FAILURE, NULL, 0, + session); + /* + * return FALSE, since the Pre-Auth Req will be freed in + * limPostFTPreAuthRsp on failure + */ + return buf_consumed; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOGE, FL("session is not in STA mode")); +#endif + buf_consumed = true; + return buf_consumed; + } + + /* Can set it only after sending auth */ + session->ftPEContext.ftPreAuthStatus = eSIR_FAILURE; + session->ftPEContext.ftPreAuthSession = true; + + /* Indicate that this is the session on which preauth is being done */ + if (session->ftPEContext.pFTPreAuthReq) { + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + cdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + cdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + } + + /* We need information from the Pre-Auth Req. Lets save that */ + session->ftPEContext.pFTPreAuthReq = ft_pre_auth_req; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("PRE Auth ft_ies_length=%02x%02x%02x"), + session->ftPEContext.pFTPreAuthReq->ft_ies[0], + session->ftPEContext.pFTPreAuthReq->ft_ies[1], + session->ftPEContext.pFTPreAuthReq->ft_ies[2]); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + session, 0, 0); +#endif + + /* Dont need to suspend if APs are in same channel */ + if (session->currentOperChannel != + session->ftPEContext.pFTPreAuthReq->preAuthchannelNum) { + /* Need to suspend link only if the channels are different */ + lim_log(mac_ctx, LOG2, + FL("Performing pre-auth on diff channel(session %p)"), + session); + lim_ft_pre_auth_suspend_link_handler(mac_ctx, CDF_STATUS_SUCCESS, + (uint32_t *)session); + } else { + lim_log(mac_ctx, LOG2, + FL("Performing pre-auth on same channel (session %p)"), + session); + /* We are in the same channel. Perform pre-auth */ + lim_perform_ft_pre_auth(mac_ctx, CDF_STATUS_SUCCESS, NULL, + session); + } + + return buf_consumed; +} + +/*------------------------------------------------------------------ + * Send the Auth1 + * Receive back Auth2 + *------------------------------------------------------------------*/ +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + tSirMacAuthFrameBody authFrame; + + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL"));) + return; + } + + if (psessionEntry->is11Rconnection && + psessionEntry->ftPEContext.pFTPreAuthReq) { + /* Only 11r assoc has FT IEs */ + if (psessionEntry->ftPEContext.pFTPreAuthReq->ft_ies == NULL) { + PELOGE(lim_log(pMac, LOGE, + "%s: FTIEs for Auth Req Seq 1 is absent", + __func__); + ) + goto preauth_fail; + } + } + + if (status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, + "%s: Change channel not successful for FT pre-auth", + __func__); + ) + goto preauth_fail; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOG2(lim_log(pMac, LOG2, "Entered wait auth2 state for FT" + " (old session %p)", psessionEntry); + ) +#endif + if (psessionEntry->is11Rconnection) { + /* Now we are on the right channel and need to send out Auth1 and + * receive Auth2 + */ + authFrame.authAlgoNumber = eSIR_FT_AUTH; + } +#if defined FEATURE_WLAN_ESE || defined FEATURE_WLAN_LFR + else { + /* Will need to make isESEconnection a enum may be for further + * improvements to this to match this algorithm number + */ + authFrame.authAlgoNumber = eSIR_OPEN_SYSTEM; + } +#endif + authFrame.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + authFrame.authStatusCode = 0; + + /* Start timer here to come back to operating channel */ + pMac->lim.limTimers.gLimFTPreAuthRspTimer.sessionId = + psessionEntry->peSessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimFTPreAuthRspTimer)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(pMac, LOGE, FL("FT Auth Rsp Timer Start Failed"));) +#endif + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_FT_PREAUTH_RSP_TIMER)); + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOG1(lim_log(pMac, LOG1, FL("FT Auth Rsp Timer Started"));) +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + pMac->lim.pSessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + + lim_send_auth_mgmt_frame(pMac, &authFrame, + psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthbssId, LIM_NO_WEP_IN_FC, psessionEntry); + + return; + +preauth_fail: + lim_handle_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0, psessionEntry); + return; +} + +/*------------------------------------------------------------------ + * + * Create the new Add Bss Req to the new AP. + * This will be used when we are ready to FT to the new AP. + * The newly created ft Session entry is passed to this function + * + *------------------------------------------------------------------*/ +tSirRetStatus lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, + uint8_t updateEntry, + tpPESession pftSessionEntry, + tpSirBssDescription bssDescription) +{ + tpAddBssParams pAddBssParams = NULL; + tAddStaParams *sta_ctx; + uint8_t chanWidthSupp = 0; + tSchBeaconStruct *pBeaconStruct; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pftSessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return eSIR_FAILURE; + } + + pBeaconStruct = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory for creating ADD_BSS")); + return eSIR_MEM_ALLOC_FAILED; + } + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = cdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + cdf_mem_free(pBeaconStruct); + lim_log(pMac, LOGP, + FL("Unable to allocate memory for creating ADD_BSS")); + return (eSIR_MEM_ALLOC_FAILED); + } + + cdf_mem_set((uint8_t *) pAddBssParams, sizeof(tAddBssParams), 0); + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + pftSessionEntry); + + cdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + cdf_mem_copy(pAddBssParams->selfMacAddr, pftSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + pAddBssParams->bssType = pftSessionEntry->bssType; + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->reassocReq = true; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + cdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) pftSessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) pftSessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) pftSessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) pftSessionEntry->beaconParams.ht20Coexist; +#ifdef WLAN_FEATURE_11W + pAddBssParams->rmfEnabled = pftSessionEntry->limRmfEnabled; +#endif + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + cdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pBeaconStruct->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + cdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pBeaconStruct->HTCaps + + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + pftSessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + pftSessionEntry->htSecondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + sta_ctx = &pAddBssParams->staContext; + +#ifdef WLAN_FEATURE_11AC + if (pftSessionEntry->vhtCapability && + pftSessionEntry->vhtCapabilityPresentInBeacon) { + pAddBssParams->vhtCapable = pBeaconStruct->VHTCaps.present; + if (pBeaconStruct->VHTOperation.chanWidth && chanWidthSupp) { + pAddBssParams->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pAddBssParams->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } + pAddBssParams->staContext.vht_caps = + ((pBeaconStruct->VHTCaps.maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (pBeaconStruct->VHTCaps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (pBeaconStruct->VHTCaps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (pBeaconStruct->VHTCaps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (pBeaconStruct->VHTCaps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (pBeaconStruct->VHTCaps.txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (pBeaconStruct->VHTCaps.rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (pBeaconStruct->VHTCaps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (pBeaconStruct->VHTCaps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (pBeaconStruct->VHTCaps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (pBeaconStruct->VHTCaps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (pBeaconStruct->VHTCaps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (pBeaconStruct->VHTCaps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (pBeaconStruct->VHTCaps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (pBeaconStruct->VHTCaps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (pBeaconStruct->VHTCaps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (pBeaconStruct->VHTCaps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (pBeaconStruct->VHTCaps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + } else { + pAddBssParams->vhtCapable = 0; + } +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("SIR_HAL_ADD_BSS_REQ with channel = %d..."), + pAddBssParams->currentOperChannel); +#endif + + /* Populate the STA-related parameters here */ + /* Note that the STA here refers to the AP */ + { + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + cdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + pAddBssParams->staContext.encryptType = + pftSessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pAddBssParams->staContext.rmfEnabled = + pftSessionEntry->limRmfEnabled; +#endif + + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + if (pftSessionEntry->vhtCapability && + IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)) { + pAddBssParams->staContext.vhtCapable = 1; + if ((pBeaconStruct->VHTCaps.suBeamFormerCap || + pBeaconStruct->VHTCaps.muBeamformerCap) && + pftSessionEntry->txBFIniFeatureEnabled) + sta_ctx->vhtTxBFCapable + = 1; + if (pBeaconStruct->VHTCaps.suBeamformeeCap && + pftSessionEntry->enable_su_tx_bformer) + sta_ctx->enable_su_tx_bformer = 1; + } + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + sta_ctx->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pAddBssParams->staContext.vhtCapable && + pBeaconStruct->VHTOperation.chanWidth) + sta_ctx->ch_width = + pBeaconStruct->VHTOperation.chanWidth + + 1; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI20MHz; + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + } + + if ((pftSessionEntry->limWmeEnabled + && pBeaconStruct->wmeEdcaPresent) + || (pftSessionEntry->limQosEnabled + && pBeaconStruct->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + if ((!pAddBssParams->staContext.wpa_rsn) + && (pftSessionEntry->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + /* Update the rates */ +#ifdef WLAN_FEATURE_11AC + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, pftSessionEntry, + &pBeaconStruct->VHTCaps); +#else + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + beaconStruct.HTCaps.supportedMCSSet, + false, pftSessionEntry); +#endif + if (pftSessionEntry->htCapability) { + pAddBssParams->staContext.supportedRates.opRateMode = + eSTA_11n; + if (pftSessionEntry->vhtCapability) + pAddBssParams->staContext.supportedRates. + opRateMode = eSTA_11ac; + } else { + if (pftSessionEntry->limRFBand == SIR_BAND_5_GHZ) { + pAddBssParams->staContext.supportedRates. + opRateMode = eSTA_11a; + } else { + pAddBssParams->staContext.supportedRates. + opRateMode = eSTA_11bg; + } + } + } + +#if defined WLAN_FEATURE_VOWIFI + pAddBssParams->maxTxPower = pftSessionEntry->maxTxPower; +#endif + +#ifdef WLAN_FEATURE_11W + if (pftSessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->status = CDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.sessionId = pftSessionEntry->peSessionId; + pAddBssParams->staContext.smesessionId = pftSessionEntry->smeSessionId; + pAddBssParams->sessionId = pftSessionEntry->peSessionId; + + /* Set a new state for MLME */ + + pftSessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, pftSessionEntry->peSessionId, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE)); + pAddBssParams->halPersona = (uint8_t) pftSessionEntry->pePersona; + + pftSessionEntry->ftPEContext.pAddBssReq = pAddBssParams; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("Saving SIR_HAL_ADD_BSS_REQ for pre-auth ap...")); +#endif + + cdf_mem_free(pBeaconStruct); + return 0; +} + +/*------------------------------------------------------------------ + * + * Setup the new session for the pre-auth AP. + * Return the newly created session entry. + * + *------------------------------------------------------------------*/ +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, tpPESession psessionEntry) +{ + uint8_t currentBssUapsd; + tPowerdBm localPowerConstraint; + tPowerdBm regMax; + tSchBeaconStruct *pBeaconStruct; + uint32_t selfDot11Mode; + ePhyChanBondState cbEnabledMode; + + pBeaconStruct = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory for creating lim_fill_ft_session")); +#endif + return; + } + + /* Retrieve the session that has already been created and update the entry */ +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + lim_print_mac_addr(pMac, pbssDescription->bssId, LOG1); +#endif + pftSessionEntry->limWmeEnabled = psessionEntry->limWmeEnabled; + pftSessionEntry->limQosEnabled = psessionEntry->limQosEnabled; + pftSessionEntry->limWsmEnabled = psessionEntry->limWsmEnabled; + pftSessionEntry->lim11hEnable = psessionEntry->lim11hEnable; + pftSessionEntry->isOSENConnection = psessionEntry->isOSENConnection; + + /* Fields to be filled later */ + pftSessionEntry->pLimJoinReq = NULL; + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + pftSessionEntry->transactionId = 0; + + lim_extract_ap_capabilities(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + pBeaconStruct); + + pftSessionEntry->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + cdf_mem_copy(pftSessionEntry->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pftSessionEntry->extRateSet.numRates = + pBeaconStruct->extendedRates.numRates; + cdf_mem_copy(pftSessionEntry->extRateSet.rate, + pBeaconStruct->extendedRates.rate, + pftSessionEntry->extRateSet.numRates); + + pftSessionEntry->ssId.length = pBeaconStruct->ssId.length; + cdf_mem_copy(pftSessionEntry->ssId.ssId, pBeaconStruct->ssId.ssId, + pftSessionEntry->ssId.length); + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + lim_log(pMac, LOG1, FL("selfDot11Mode %d"), selfDot11Mode); + pftSessionEntry->dot11mode = selfDot11Mode; + pftSessionEntry->vhtCapability = + (IS_DOT11_MODE_VHT(pftSessionEntry->dot11mode) + && IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)); + pftSessionEntry->htCapability = + (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present); + + /* Copy The channel Id to the session Table */ + pftSessionEntry->limReassocChannelId = pbssDescription->channelId; + pftSessionEntry->currentOperChannel = pbssDescription->channelId; + + pftSessionEntry->limRFBand = lim_get_rf_band( + pftSessionEntry->currentOperChannel); + + if (pftSessionEntry->limRFBand == SIR_BAND_2_4_GHZ) { + cbEnabledMode = pMac->roam.configParam.channelBondingMode24GHz; + } else { + cbEnabledMode = pMac->roam.configParam.channelBondingMode5GHz; + } + pftSessionEntry->htSupportedChannelWidthSet = + (pBeaconStruct->HTInfo.present) ? + (cbEnabledMode && pBeaconStruct->HTInfo.recommendedTxWidthSet) : 0; + pftSessionEntry->htRecommendedTxWidthSet = + pftSessionEntry->htSupportedChannelWidthSet; + + +#ifdef WLAN_FEATURE_11AC + if (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) && + pBeaconStruct->VHTOperation.present && + pftSessionEntry->vhtCapability) { + pftSessionEntry->vhtCapabilityPresentInBeacon = 1; + } else { + pftSessionEntry->vhtCapabilityPresentInBeacon = 0; + } +#endif + if (pftSessionEntry->htRecommendedTxWidthSet) { + pftSessionEntry->ch_width = CH_WIDTH_40MHZ; + if (pftSessionEntry->vhtCapabilityPresentInBeacon && + pBeaconStruct->VHTOperation.chanWidth) { + pftSessionEntry->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pftSessionEntry->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pftSessionEntry->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } else { + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId - 2; + else + lim_log(pMac, LOGE, FL("Invalid sec ch offset")); + } + } else { + pftSessionEntry->ch_width = CH_WIDTH_20MHZ; + pftSessionEntry->ch_center_freq_seg0 = 0; + pftSessionEntry->ch_center_freq_seg1 = 0; + } + + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + sir_copy_mac_addr(pftSessionEntry->prev_ap_bssid, psessionEntry->bssId); +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + lim_print_mac_addr(pMac, pftSessionEntry->limReAssocbssId, LOG1); +#endif + + /* Store beaconInterval */ + pftSessionEntry->beaconParams.beaconInterval = + pbssDescription->beaconInterval; + pftSessionEntry->bssType = psessionEntry->bssType; + + pftSessionEntry->statypeForBss = STA_ENTRY_PEER; + pftSessionEntry->nwType = pbssDescription->nwType; + + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) { + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + } else if (pftSessionEntry->bssType == eSIR_BTAMP_AP_MODE) { + pftSessionEntry->limSystemRole = eLIM_BT_AMP_STA_ROLE; + } else { + /* Throw an error and return and make sure to delete the session. */ + lim_log(pMac, LOGE, FL("Invalid bss type")); + } + + pftSessionEntry->limCurrentBssCaps = pbssDescription->capabilityInfo; + pftSessionEntry->limReassocBssCaps = pbssDescription->capabilityInfo; + if (pMac->roam.configParam.shortSlotTime && + SIR_MAC_GET_SHORT_SLOT_TIME(pftSessionEntry->limReassocBssCaps)) { + pftSessionEntry->shortSlotTimeSupported = true; + } + + regMax = cfg_get_regulatory_max_transmit_power(pMac, + pftSessionEntry-> + currentOperChannel); + localPowerConstraint = regMax; + lim_extract_ap_capability(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + &pftSessionEntry->limCurrentBssQosCaps, + &pftSessionEntry->limCurrentBssPropCap, ¤tBssUapsd, + &localPowerConstraint, pftSessionEntry); + + pftSessionEntry->limReassocBssQosCaps = + pftSessionEntry->limCurrentBssQosCaps; + pftSessionEntry->limReassocBssPropCap = + pftSessionEntry->limCurrentBssPropCap; + +#ifdef WLAN_FEATURE_VOWIFI_11R + pftSessionEntry->is11Rconnection = psessionEntry->is11Rconnection; +#endif +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->isESEconnection = psessionEntry->isESEconnection; + pftSessionEntry->is_ese_version_ie_present = + pBeaconStruct->is_ese_ver_ie_present; +#endif +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + pftSessionEntry->isFastTransitionEnabled = + psessionEntry->isFastTransitionEnabled; +#endif + +#ifdef FEATURE_WLAN_LFR + pftSessionEntry->isFastRoamIniFeatureEnabled = + psessionEntry->isFastRoamIniFeatureEnabled; +#endif + +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->maxTxPower = + lim_get_max_tx_power(regMax, localPowerConstraint, + pMac->roam.configParam.nTxPowerCap); +#else + pftSessionEntry->maxTxPower = CDF_MIN(regMax, (localPowerConstraint)); +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, + FL + ("Reg max = %d, local power = %d, ini tx power = %d, max tx = %d"), + regMax, localPowerConstraint, pMac->roam.configParam.nTxPowerCap, + pftSessionEntry->maxTxPower); +#endif + + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, pftSessionEntry->peSessionId, + pftSessionEntry->limSmeState)); + + pftSessionEntry->encryptType = psessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pftSessionEntry->limRmfEnabled = psessionEntry->limRmfEnabled; +#endif + + cdf_mem_free(pBeaconStruct); +} + +/*------------------------------------------------------------------ + * + * Setup the session and the add bss req for the pre-auth AP. + * + *------------------------------------------------------------------*/ +tSirRetStatus lim_ft_setup_auth_session(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + + pftSessionEntry = + pe_find_session_by_bssid(pMac, psessionEntry->limReAssocbssId, + &sessionId); + if (pftSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Unable to find session for the following bssid")); + ) + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOGE); + return eSIR_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return eSIR_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq && + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + lim_fill_ft_session(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription, pftSessionEntry, + psessionEntry); + + lim_ft_prepare_add_bss_req(pMac, false, pftSessionEntry, + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + } + + return eSIR_SUCCESS; +} + +/*------------------------------------------------------------------ + * Resume Link Call Back + *------------------------------------------------------------------*/ +void lim_ft_process_pre_auth_result(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data) +{ + tpPESession psessionEntry = (tpPESession) data; + + if (NULL == psessionEntry || + NULL == psessionEntry->ftPEContext.pFTPreAuthReq) + return; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + + if (psessionEntry->ftPEContext.ftPreAuthStatus == eSIR_SUCCESS) { + psessionEntry->ftPEContext.ftPreAuthStatus = + lim_ft_setup_auth_session(pMac, psessionEntry); + } + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(pMac, psessionEntry->ftPEContext.ftPreAuthStatus, + psessionEntry->ftPEContext.saved_auth_rsp, + psessionEntry->ftPEContext.saved_auth_rsp_length, + psessionEntry); +} + +/*------------------------------------------------------------------ + * Resume Link Call Back + *------------------------------------------------------------------*/ +void lim_perform_post_ft_pre_auth_and_channel_change(tpAniSirGlobal pMac, + CDF_STATUS status, + uint32_t *data, + tpPESession psessionEntry) +{ + /* Set the resume channel to Any valid channel (invalid) + * This will instruct HAL to set it to any previous valid channel. + */ + pe_set_resume_channel(pMac, 0, 0); + lim_ft_process_pre_auth_result(pMac, CDF_STATUS_SUCCESS, + (uint32_t *) psessionEntry); +} + +/* + * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME. + * + * @mac_ctx: global mac ctx + * @status: status code to post in auth rsp + * @auth_rsp: pointer to auth rsp FT ie + * @auth_rsp_length: len of the IE field + * @session: pe session + * + * post pre auth response to SME. + * + * Return: void + */ +void lim_post_ft_pre_auth_rsp(tpAniSirGlobal mac_ctx, + tSirRetStatus status, + uint8_t *auth_rsp, + uint16_t auth_rsp_length, + tpPESession session) +{ + tpSirFTPreAuthRsp ft_pre_auth_rsp; + tSirMsgQ mmh_msg; + uint16_t rsp_len = sizeof(tSirFTPreAuthRsp); + + ft_pre_auth_rsp = (tpSirFTPreAuthRsp) cdf_mem_malloc(rsp_len); + if (NULL == ft_pre_auth_rsp) { + lim_log(mac_ctx, LOGE, "Failed to allocate memory"); + CDF_ASSERT(ft_pre_auth_rsp != NULL); + return; + } + cdf_mem_zero(ft_pre_auth_rsp, rsp_len); + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("Auth Rsp = %p"), ft_pre_auth_rsp); +#endif + if (session) { + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOGE, + FL("session is not in STA mode")); +#endif + cdf_mem_free(ft_pre_auth_rsp); + return; + } + ft_pre_auth_rsp->smeSessionId = session->smeSessionId; + /* The bssid of the AP we are sending Auth1 to. */ + if (session->ftPEContext.pFTPreAuthReq) + sir_copy_mac_addr(ft_pre_auth_rsp->preAuthbssId, + session->ftPEContext.pFTPreAuthReq->preAuthbssId); + } + + ft_pre_auth_rsp->messageType = eWNI_SME_FT_PRE_AUTH_RSP; + ft_pre_auth_rsp->length = (uint16_t) rsp_len; + ft_pre_auth_rsp->status = status; + + /* Attach the auth response now back to SME */ + ft_pre_auth_rsp->ft_ies_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + /* Only 11r assoc has FT IEs */ + cdf_mem_copy(ft_pre_auth_rsp->ft_ies, + auth_rsp, auth_rsp_length); + ft_pre_auth_rsp->ft_ies_length = auth_rsp_length; + } + + if (status != eSIR_SUCCESS) { + /* + * Ensure that on Pre-Auth failure the cached Pre-Auth Req and + * other allocated memory is freed up before returning. + */ + lim_log(mac_ctx, LOG1, "Pre-Auth Failed, Cleanup!"); + lim_ft_cleanup(mac_ctx, session); + } + + mmh_msg.type = ft_pre_auth_rsp->messageType; + mmh_msg.bodyptr = ft_pre_auth_rsp; + mmh_msg.bodyval = 0; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("Posted Auth Rsp to SME with status of 0x%x"), + status); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (status == eSIR_SUCCESS) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE, + session, status, 0); +#endif + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); +} + +/*------------------------------------------------------------------ + * + * Send the FT Pre Auth Response to SME whenever we have a status + * ready to be sent to SME + * + * SME will be the one to send it up to the supplicant to receive + * FTIEs which will be required for Reassoc Req. + * + *------------------------------------------------------------------*/ +void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + tpSirBssDescription pbssDescription = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + psessionEntry, (uint16_t) status, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + + /* Save the status of pre-auth */ + psessionEntry->ftPEContext.ftPreAuthStatus = status; + + /* Save the auth rsp, so we can send it to + * SME once we resume link + */ + psessionEntry->ftPEContext.saved_auth_rsp_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + cdf_mem_copy(psessionEntry->ftPEContext.saved_auth_rsp, + auth_rsp, auth_rsp_length); + psessionEntry->ftPEContext.saved_auth_rsp_length = + auth_rsp_length; + } + + if (!psessionEntry->ftPEContext.pFTPreAuthReq || + !psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + lim_log(pMac, LOGE, + FL("pFTPreAuthReq or pbssDescription is NULL")); + return; + } + + /* Create FT session for the re-association at this point */ + if (psessionEntry->ftPEContext.ftPreAuthStatus == eSIR_SUCCESS) { + pbssDescription = + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription; + lim_print_mac_addr(pMac, pbssDescription->bssId, LOG1); + if ((pftSessionEntry = + pe_create_session(pMac, pbssDescription->bssId, + &sessionId, pMac->lim.maxStation, + psessionEntry->bssType)) == NULL) { + lim_log(pMac, LOGE, FL( + "Session not created for pre-auth 11R AP")); + status = eSIR_FAILURE; + psessionEntry->ftPEContext.ftPreAuthStatus = status; + goto send_rsp; + } + pftSessionEntry->peSessionId = sessionId; + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + pftSessionEntry->bssType = psessionEntry->bssType; + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) { + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + } else if (pftSessionEntry->bssType == eSIR_BTAMP_AP_MODE) { + pftSessionEntry->limSystemRole = eLIM_BT_AMP_STA_ROLE; + } else { + lim_log(pMac, LOGE, FL("Invalid bss type")); + } + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + cdf_mem_copy(&(pftSessionEntry->htConfig), + &(psessionEntry->htConfig), + sizeof(psessionEntry->htConfig)); + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + PELOGE(lim_log + (pMac, LOG1, "%s:created session (%p) with id = %d", + __func__, pftSessionEntry, + pftSessionEntry->peSessionId); + ) + + /* Update the ReAssoc BSSID of the current session */ + sir_copy_mac_addr(psessionEntry->limReAssocbssId, + pbssDescription->bssId); + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOG1); + } +send_rsp: + if (psessionEntry->currentOperChannel != + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthchannelNum) { + /* Need to move to the original AP channel */ + lim_change_channel_with_callback(pMac, + psessionEntry->currentOperChannel, + lim_perform_post_ft_pre_auth_and_channel_change, + NULL, psessionEntry); + } else { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(pMac, LOG1, + "Pre auth on same channel as connected AP channel %d", + psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum); + ) +#endif + lim_ft_process_pre_auth_result(pMac, status, + (uint32_t *) psessionEntry); + } +} + +/*------------------------------------------------------------------ + * + * This function handles the 11R Reassoc Req from SME + * + *------------------------------------------------------------------*/ +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry) +{ + uint8_t smeSessionId = 0; + uint16_t transactionId = 0; + uint8_t chanNum = 0; + tLimMlmReassocReq *pMlmReassocReq; + uint16_t caps; + uint32_t val; + tSirMsgQ msgQ; + tSirRetStatus retCode; + uint32_t teleBcnEn = 0; + + chanNum = psessionEntry->currentOperChannel; + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smeSessionId, + &transactionId); + psessionEntry->smeSessionId = smeSessionId; + psessionEntry->transactionId = transactionId; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOCIATING, psessionEntry, 0, + 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + lim_log(pMac, LOGE, FL("pAddBssReq is NULL")); + return; + } + pMlmReassocReq = cdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pMlmReassocReq) { + lim_log(pMac, LOGE, + FL("call to AllocateMemory failed for mlmReassocReq")); + return; + } + + cdf_mem_copy(pMlmReassocReq->peerMacAddr, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(pMac, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &pMlmReassocReq->reassocFailureTimeout) + != eSIR_SUCCESS) { + /** + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ReassocFailureTimeout value")); + cdf_mem_free(pMlmReassocReq); + return; + } + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { + /** + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, FL("could not retrieve Capabilities value")); + cdf_mem_free(pMlmReassocReq); + return; + } + pMlmReassocReq->capabilityInfo = caps; + + /* Update PE sessionId */ + pMlmReassocReq->sessionId = psessionEntry->peSessionId; + + /* If telescopic beaconing is enabled, set listen interval + to WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_WAKEUP_EN, &teleBcnEn) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + cdf_mem_free(pMlmReassocReq); + return; + } + + if (teleBcnEn) { + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ListenInterval")); + cdf_mem_free(pMlmReassocReq); + return; + } + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &val) != + eSIR_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ListenInterval")); + cdf_mem_free(pMlmReassocReq); + return; + } + } + if (lim_set_link_state + (pMac, eSIR_LINK_PREASSOC_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, NULL) != eSIR_SUCCESS) { + cdf_mem_free(pMlmReassocReq); + return; + } + + pMlmReassocReq->listenInterval = (uint16_t) val; + psessionEntry->pLimMlmReassocReq = pMlmReassocReq; + + /* we need to defer the message until we get the response back from HAL */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = SIR_HAL_ADD_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = psessionEntry->ftPEContext.pAddBssReq; + msgQ.bodyval = 0; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("Sending SIR_HAL_ADD_BSS_REQ...")); +#endif + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + } + + psessionEntry->ftPEContext.pAddBssReq = NULL; + return; +} + +/* + * lim_process_ft_preauth_rsp_timeout() - process ft preauth rsp timeout + * + * @mac_ctx: global mac ctx + * + * This function is called if preauth response is not received from the AP + * within this timeout while FT in progress + * + * Return: void + */ +void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + + /* + * We have failed pre auth. We need to resume link and get back on + * home channel + */ + lim_log(mac_ctx, LOGE, FL("FT Pre-Auth Time Out!!!!")); + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOGE, FL("session is not in STA mode")); +#endif + return; + } + + /* Reset the flag to indicate preauth request session */ + session->ftPEContext.ftPreAuthSession = false; + + if (NULL == session->ftPEContext.pFTPreAuthReq) { + lim_log(mac_ctx, LOGE, + FL("pFTPreAuthReq is NULL. Auth Rsp might already be posted to SME and ftcleanup done! sessionId:%d"), + mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer.sessionId); + return; + } + + /* + * To handle the race condition where we recieve preauth rsp after + * timer has expired. + */ + if (true == + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + lim_log(mac_ctx, LOGE, + FL("Auth rsp already posted to SME (session %p)"), + session); + return; + } else { + /* + * Here we are sending preauth rsp with failure state + * and which is forwarded to SME. Now, if we receive an preauth + * resp from AP with success it would create a FT pesession, but + * will be dropped in SME leaving behind the pesession. Mark + * Preauth rsp processed so that any rsp from AP is dropped in + * lim_process_auth_frame_no_session. + */ + lim_log(mac_ctx, LOG1, + FL("Auth rsp not yet posted to SME (session %p)"), + session); + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = true; + } + + /* + * Attempted at Pre-Auth and failed. If we are off channel. We need + * to get back to home channel + */ + lim_handle_ft_pre_auth_rsp(mac_ctx, eSIR_FAILURE, NULL, 0, session); +} + +/*------------------------------------------------------------------ + * + * This function is called to process the update key request from SME + * + *------------------------------------------------------------------*/ +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tAddBssParams *pAddBssParams; + tSirFTUpdateKeyInfo *pKeyInfo; + uint32_t val = 0; + tpPESession psessionEntry; + uint8_t sessionId; + + /* Sanity Check */ + if (pMac == NULL || pMsgBuf == NULL) { + return false; + } + + pKeyInfo = (tSirFTUpdateKeyInfo *) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, pKeyInfo->bssId, &sessionId); + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, + "%s: Unable to find session for the following bssid", + __func__); + ) + lim_print_mac_addr(pMac, pKeyInfo->bssId, LOGE); + return false; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return false; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + /* AddBss Req is NULL, save the keys to configure them later. */ + tpLimMlmSetKeysReq pMlmSetKeysReq = + &psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParam; + + cdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); + cdf_mem_copy(pMlmSetKeysReq->peerMacAddr, pKeyInfo->bssId, + sizeof(tSirMacAddr)); + pMlmSetKeysReq->sessionId = psessionEntry->peSessionId; + pMlmSetKeysReq->smesessionId = psessionEntry->smeSessionId; + pMlmSetKeysReq->edType = pKeyInfo->keyMaterial.edType; + pMlmSetKeysReq->numKeys = pKeyInfo->keyMaterial.numKeys; + cdf_mem_copy((uint8_t *) &pMlmSetKeysReq->key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = true; + + lim_log(pMac, LOGE, FL("pAddBssReq is NULL")); + + if (psessionEntry->ftPEContext.pAddStaReq == NULL) { + lim_log(pMac, LOGE, FL("pAddStaReq is NULL")); + lim_send_set_sta_key_req(pMac, pMlmSetKeysReq, 0, 0, + psessionEntry, false); + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = false; + } + } else { + pAddBssParams = psessionEntry->ftPEContext.pAddBssReq; + + /* Store the key information in the ADD BSS parameters */ + pAddBssParams->extSetStaKeyParamValid = 1; + pAddBssParams->extSetStaKeyParam.encType = + pKeyInfo->keyMaterial.edType; + cdf_mem_copy((uint8_t *) &pAddBssParams->extSetStaKeyParam.key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, + FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pAddBssParams->extSetStaKeyParam.singleTidRc = val; + PELOG1(lim_log(pMac, LOG1, FL("Key valid %d"), + pAddBssParams->extSetStaKeyParamValid, + pAddBssParams->extSetStaKeyParam.key[0]. + keyLength); + ) + + pAddBssParams->extSetStaKeyParam.staIdx = 0; + + PELOG1(lim_log(pMac, LOG1, + FL("BSSID = " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pKeyInfo->bssId)); + ) + + sir_copy_mac_addr(pAddBssParams->extSetStaKeyParam.peerMacAddr, + pKeyInfo->bssId); + + pAddBssParams->extSetStaKeyParam.sendRsp = false; + + if (pAddBssParams->extSetStaKeyParam.key[0].keyLength == 16) { + PELOG1(lim_log(pMac, LOG1, + FL + ("BSS key = %02X-%02X-%02X-%02X-%02X-%02X-%02X- " + "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X"), + pAddBssParams->extSetStaKeyParam.key[0]. + key[0], + pAddBssParams->extSetStaKeyParam.key[0]. + key[1], + pAddBssParams->extSetStaKeyParam.key[0]. + key[2], + pAddBssParams->extSetStaKeyParam.key[0]. + key[3], + pAddBssParams->extSetStaKeyParam.key[0]. + key[4], + pAddBssParams->extSetStaKeyParam.key[0]. + key[5], + pAddBssParams->extSetStaKeyParam.key[0]. + key[6], + pAddBssParams->extSetStaKeyParam.key[0]. + key[7], + pAddBssParams->extSetStaKeyParam.key[0]. + key[8], + pAddBssParams->extSetStaKeyParam.key[0]. + key[9], + pAddBssParams->extSetStaKeyParam.key[0]. + key[10], + pAddBssParams->extSetStaKeyParam.key[0]. + key[11], + pAddBssParams->extSetStaKeyParam.key[0]. + key[12], + pAddBssParams->extSetStaKeyParam.key[0]. + key[13], + pAddBssParams->extSetStaKeyParam.key[0]. + key[14], + pAddBssParams->extSetStaKeyParam.key[0]. + key[15]); + ) + } + } + return true; +} + +void +lim_ft_send_aggr_qos_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, + tpAggrAddTsParams aggrQosRsp, uint8_t smesessionId) +{ + tpSirAggrQosRsp rsp; + int i = 0; + if (!rspReqd) { + return; + } + rsp = cdf_mem_malloc(sizeof(tSirAggrQosRsp)); + if (NULL == rsp) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for tSirAggrQosRsp")); + return; + } + cdf_mem_set((uint8_t *) rsp, sizeof(*rsp), 0); + rsp->messageType = eWNI_SME_FT_AGGR_QOS_RSP; + rsp->sessionId = smesessionId; + rsp->length = sizeof(*rsp); + rsp->aggrInfo.tspecIdx = aggrQosRsp->tspecIdx; + for (i = 0; i < SIR_QOS_NUM_AC_MAX; i++) { + if ((1 << i) & aggrQosRsp->tspecIdx) { + rsp->aggrInfo.aggrRsp[i].status = aggrQosRsp->status[i]; + rsp->aggrInfo.aggrRsp[i].tspec = aggrQosRsp->tspec[i]; + } + } + lim_send_sme_aggr_qos_rsp(pMac, rsp, smesessionId); + return; +} +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpAggrAddTsParams pAggrQosRspMsg = NULL; + tAddTsParams addTsParam = { 0 }; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + int i = 0; + PELOG1(lim_log(pMac, LOG1, FL(" Received AGGR_QOS_RSP from HAL"));) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pAggrQosRspMsg = (tpAggrAddTsParams) (limMsg->bodyptr); + if (NULL == pAggrQosRspMsg) { + PELOGE(lim_log(pMac, LOGE, FL("NULL pAggrQosRspMsg"));) + return; + } + psessionEntry = + pe_find_session_by_session_id(pMac, pAggrQosRspMsg->sessionId); + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, + FL("Cant find session entry for %s"), __func__); + ) + if (pAggrQosRspMsg != NULL) { + cdf_mem_free(pAggrQosRspMsg); + } + return; + } + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + return; + } + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if ((((1 << i) & pAggrQosRspMsg->tspecIdx)) && + (pAggrQosRspMsg->status[i] != CDF_STATUS_SUCCESS)) { + sir_copy_mac_addr(peerMacAddr, psessionEntry->bssId); + addTsParam.staIdx = pAggrQosRspMsg->staIdx; + addTsParam.sessionId = pAggrQosRspMsg->sessionId; + addTsParam.tspec = pAggrQosRspMsg->tspec[i]; + addTsParam.tspecIdx = pAggrQosRspMsg->tspecIdx; + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &addTsParam.tspec.tsinfo, + &addTsParam.tspec, + psessionEntry); + pSta = + dph_lookup_assoc_id(pMac, addTsParam.staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) { + lim_admit_control_delete_ts(pMac, assocId, + &addTsParam.tspec. + tsinfo, NULL, + (uint8_t *) & + addTsParam.tspecIdx); + } + } + } + lim_ft_send_aggr_qos_rsp(pMac, rspReqd, pAggrQosRspMsg, + psessionEntry->smeSessionId); + if (pAggrQosRspMsg != NULL) { + cdf_mem_free(pAggrQosRspMsg); + } + return; +} +tSirRetStatus lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + tSirAggrQosReq *aggrQosReq = (tSirAggrQosReq *) pMsgBuf; + tpAggrAddTsParams pAggrAddTsParam; + tpPESession psessionEntry = NULL; + tpLimTspecInfo tspecInfo; + uint8_t ac; + tpDphHashNode pSta; + uint16_t aid; + uint8_t sessionId; + int i; + + pAggrAddTsParam = cdf_mem_malloc(sizeof(tAggrAddTsParams)); + if (NULL == pAggrAddTsParam) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + return eSIR_MEM_ALLOC_FAILED; + } + + psessionEntry = + pe_find_session_by_bssid(pMac, aggrQosReq->bssId, &sessionId); + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("psession Entry Null for sessionId = %d"), + aggrQosReq->sessionId); + ) + cdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, FL("psessionEntry is not in STA mode")); + ) +#endif + cdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + pSta = dph_lookup_hash_entry(pMac, aggrQosReq->bssId, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Station context not found - ignoring AddTsRsp")); + ) + cdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + cdf_mem_set((uint8_t *) pAggrAddTsParam, sizeof(tAggrAddTsParams), 0); + pAggrAddTsParam->staIdx = psessionEntry->staId; + /* Fill in the sessionId specific to PE */ + pAggrAddTsParam->sessionId = sessionId; + pAggrAddTsParam->tspecIdx = aggrQosReq->aggrInfo.tspecIdx; + + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if (aggrQosReq->aggrInfo.tspecIdx & (1 << i)) { + tSirMacTspecIE *pTspec = + &aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + /* Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (pTspec->tsinfo.traffic.psb == 1) { + lim_set_tspec_uapsd_mask_per_session(pMac, + psessionEntry, + &pTspec-> + tsinfo, + SET_UAPSD_MASK); + } else { + lim_set_tspec_uapsd_mask_per_session(pMac, + psessionEntry, + &pTspec-> + tsinfo, + CLEAR_UAPSD_MASK); + } + /* + * ADDTS success, so AC is now admitted. + * We shall now use the default + * EDCA parameters as advertised by AP and + * send the updated EDCA params + * to HAL. + */ + ac = upToAc(pTspec->tsinfo.traffic.userPrio); + if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(pMac, + psessionEntry->gLimEdcaParams, + psessionEntry); + + lim_send_edca_params(pMac, + psessionEntry->gLimEdcaParamsActive, + pSta->bssId); + + if (eSIR_SUCCESS != + lim_tspec_add(pMac, pSta->staAddr, pSta->assocId, + pTspec, 0, &tspecInfo)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Adding entry in lim Tspec Table failed ")); + ) + pMac->lim.gLimAddtsSent = false; + cdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + pAggrAddTsParam->tspec[i] = + aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + } + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!pMac->roam.configParam.isRoamOffloadEnabled || + (pMac->roam.configParam.isRoamOffloadEnabled && + !psessionEntry->is11Rconnection)) +#endif + { + msg.type = WMA_AGGR_QOS_REQ; + msg.bodyptr = pAggrAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_AGGR_QOS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + PELOGW(lim_log + (pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + ) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + cdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + else { + /* Implies it is a LFR3.0 based 11r connection + * so donot send add ts request to fimware since it + * already has the RIC IEs */ + + /* Send the Aggr QoS response to SME */ + lim_ft_send_aggr_qos_rsp(pMac, true, pAggrAddTsParam, + psessionEntry->smeSessionId); + if (pAggrAddTsParam != NULL) { + cdf_mem_free(pAggrAddTsParam); + } + } +#endif + + return eSIR_SUCCESS; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R */ diff --git a/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c b/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c new file mode 100644 index 0000000000..c2c3dba535 --- /dev/null +++ b/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c @@ -0,0 +1,1833 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "sir_common.h" +#include "wni_cfg.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" /* sch_set_fixed_beacon_fields for IBSS coalesce */ +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_types.h" + +/** + * ibss_peer_find + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ + +static tLimIbssPeerNode *ibss_peer_find(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + tLimIbssPeerNode *pTempNode = pMac->lim.gLimIbssPeerList; + + while (pTempNode != NULL) { + if (cdf_mem_compare((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + pTempNode = pTempNode->next; + } + return pTempNode; +} /*** end ibss_peer_find() ***/ + +/** + * ibss_peer_add + * + ***FUNCTION: + * This is called on a STA in IBSS upon receiving Beacon/ + * Probe Response from a peer. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pPeerNode - Pointer to peer node to be added to the list. + * + * @return None + */ + +static tSirRetStatus +ibss_peer_add(tpAniSirGlobal pMac, tLimIbssPeerNode *pPeerNode) +{ +#ifdef ANI_SIR_IBSS_PEER_CACHING + uint32_t numIbssPeers = (2 * pMac->lim.maxStation); + + if (pMac->lim.gLimNumIbssPeers >= numIbssPeers) { + /** + * Reached max number of peers to be maintained. + * Delete last entry & add new entry at the beginning. + */ + tLimIbssPeerNode *pTemp, *pPrev; + pTemp = pPrev = pMac->lim.gLimIbssPeerList; + while (pTemp->next != NULL) { + pPrev = pTemp; + pTemp = pTemp->next; + } + if (pTemp->beacon) { + cdf_mem_free(pTemp->beacon); + } + + cdf_mem_free(pTemp); + pPrev->next = NULL; + } else +#endif + pMac->lim.gLimNumIbssPeers++; + + pPeerNode->next = pMac->lim.gLimIbssPeerList; + pMac->lim.gLimIbssPeerList = pPeerNode; + + return eSIR_SUCCESS; + +} /*** end limAddIbssPeerToList() ***/ + +/** + * ibss_peer_collect + * + ***FUNCTION: + * This is called to collect IBSS peer information + * from received Beacon/Probe Response frame from it. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_peer_collect(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + tpSirMacMgmtHdr pHdr, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + cdf_mem_copy(pPeer->peerMacAddr, pHdr->sa, sizeof(tSirMacAddr)); + + pPeer->capabilityInfo = pBeacon->capabilityInfo; + pPeer->extendedRatesPresent = pBeacon->extendedRatesPresent; + pPeer->edcaPresent = pBeacon->edcaPresent; + pPeer->wmeEdcaPresent = pBeacon->wmeEdcaPresent; + pPeer->wmeInfoPresent = pBeacon->wmeInfoPresent; + + if (pBeacon->IBSSParams.present) { + pPeer->atimIePresent = pBeacon->IBSSParams.present; + pPeer->peerAtimWindowLength = pBeacon->IBSSParams.atim; + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && + (pBeacon->HTCaps.present)) { + pPeer->htCapable = pBeacon->HTCaps.present; + cdf_mem_copy((uint8_t *) pPeer->supportedMCSSet, + (uint8_t *) pBeacon->HTCaps.supportedMCSSet, + sizeof(pPeer->supportedMCSSet)); + pPeer->htGreenfield = (uint8_t) pBeacon->HTCaps.greenField; + pPeer->htSupportedChannelWidthSet = + (uint8_t) pBeacon->HTCaps.supportedChannelWidthSet; + pPeer->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState) pBeacon->HTCaps.mimoPowerSave; + pPeer->htMaxAmsduLength = + (uint8_t) pBeacon->HTCaps.maximalAMSDUsize; + pPeer->htAMpduDensity = pBeacon->HTCaps.mpduDensity; + pPeer->htDsssCckRate40MHzSupport = + (uint8_t) pBeacon->HTCaps.dsssCckMode40MHz; + pPeer->htShortGI20Mhz = (uint8_t) pBeacon->HTCaps.shortGI20MHz; + pPeer->htShortGI40Mhz = (uint8_t) pBeacon->HTCaps.shortGI40MHz; + pPeer->htMaxRxAMpduFactor = pBeacon->HTCaps.maxRxAMPDUFactor; + pPeer->htSecondaryChannelOffset = + pBeacon->HTInfo.secondaryChannelOffset; + pPeer->htLdpcCapable = (uint8_t) pBeacon->HTCaps.advCodingCap; + } + + /* Collect peer VHT capabilities based on the received beacon from the peer */ +#ifdef WLAN_FEATURE_11AC + if (pBeacon->VHTCaps.present) { + pPeer->vhtSupportedChannelWidthSet = + pBeacon->VHTOperation.chanWidth; + pPeer->vhtCapable = pBeacon->VHTCaps.present; + + /* Collect VHT capabilities from beacon */ + cdf_mem_copy((uint8_t *) &pPeer->VHTCaps, + (uint8_t *) &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } +#endif + pPeer->erpIePresent = pBeacon->erpPresent; + + cdf_mem_copy((uint8_t *) &pPeer->supportedRates, + (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates + 1); + if (pPeer->extendedRatesPresent) + cdf_mem_copy((uint8_t *) &pPeer->extendedRates, + (uint8_t *) &pBeacon->extendedRates, + pBeacon->extendedRates.numRates + 1); + else + pPeer->extendedRates.numRates = 0; + + pPeer->next = NULL; +} /*** end ibss_peer_collect() ***/ + +/* handle change in peer qos/wme capabilities */ +static void +ibss_sta_caps_update(tpAniSirGlobal pMac, + tLimIbssPeerNode *pPeerNode, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + pPeerNode->beaconHBCount++; /* Update beacon count. */ + + /* if the peer node exists, update its qos capabilities */ + pStaDs = dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) + return; + + /* Update HT Capabilities */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.htCapability = pPeerNode->htCapable; + if (pPeerNode->htCapable) { + pStaDs->htGreenfield = pPeerNode->htGreenfield; + pStaDs->htSupportedChannelWidthSet = + pPeerNode->htSupportedChannelWidthSet; + pStaDs->htMIMOPSState = pPeerNode->htMIMOPSState; + pStaDs->htMaxAmsduLength = pPeerNode->htMaxAmsduLength; + pStaDs->htAMpduDensity = pPeerNode->htAMpduDensity; + pStaDs->htDsssCckRate40MHzSupport = + pPeerNode->htDsssCckRate40MHzSupport; + pStaDs->htShortGI20Mhz = pPeerNode->htShortGI20Mhz; + pStaDs->htShortGI40Mhz = pPeerNode->htShortGI40Mhz; + pStaDs->htMaxRxAMpduFactor = + pPeerNode->htMaxRxAMpduFactor; + /* In the future, may need to check for "delayedBA" */ + /* For now, it is IMMEDIATE BA only on ALL TID's */ + pStaDs->baPolicyFlag = 0xFF; + pStaDs->htLdpcCapable = pPeerNode->htLdpcCapable; + } + } +#ifdef WLAN_FEATURE_11AC + if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.vhtCapability = pPeerNode->vhtCapable; + if (pPeerNode->vhtCapable) { + pStaDs->vhtSupportedChannelWidthSet = + pPeerNode->vhtSupportedChannelWidthSet; + + /* If in 11AC mode and if session requires 11AC mode, consider peer's */ + /* max AMPDU length factor */ + pStaDs->htMaxRxAMpduFactor = + pPeerNode->VHTCaps.maxAMPDULenExp; + pStaDs->vhtLdpcCapable = + (uint8_t) pPeerNode->VHTCaps.ldpcCodingCap; + } + } +#endif + /* peer is 11e capable but is not 11e enabled yet */ + /* some STA's when joining Airgo IBSS, assert qos capability even when */ + /* they don't suport qos. however, they do not include the edca parameter */ + /* set. so let's check for edcaParam in addition to the qos capability */ + if (pPeerNode->capabilityInfo.qos && (psessionEntry->limQosEnabled) + && pPeerNode->edcaPresent) { + pStaDs->qosMode = 1; + pStaDs->wmeEnabled = 0; + if (!pStaDs->lleEnabled) { + pStaDs->lleEnabled = 1; + /* dphSetACM(pMac, pStaDs); */ + } + return; + } + /* peer is not 11e capable now but was 11e enabled earlier */ + else if (pStaDs->lleEnabled) { + pStaDs->qosMode = 0; + pStaDs->lleEnabled = 0; + } + /* peer is wme capable but is not wme enabled yet */ + if (pPeerNode->wmeInfoPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* When the peer device supports EDCA parameters, then we were not + considering. Added this code when we saw that one of the Peer Device + was advertising WMM param where we were not honouring that. CR# 210756 + */ + if (pPeerNode->wmeEdcaPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* peer is not wme capable now but was wme enabled earlier */ + else if (pStaDs->wmeEnabled) { + pStaDs->qosMode = 0; + pStaDs->wmeEnabled = 0; + } + +} + +static void +ibss_sta_rates_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ +#ifdef WLAN_FEATURE_11AC + lim_populate_matching_rate_set(pMac, pStaDs, &pPeer->supportedRates, + &pPeer->extendedRates, + pPeer->supportedMCSSet, psessionEntry, + &pPeer->VHTCaps); +#else + /* Populate supported rateset */ + lim_populate_matching_rate_set(pMac, pStaDs, &pPeer->supportedRates, + &pPeer->extendedRates, + pPeer->supportedMCSSet, psessionEntry); +#endif + + pStaDs->mlmStaContext.capabilityInfo = pPeer->capabilityInfo; +} /*** end ibss_sta_info_update() ***/ + +/** + * ibss_sta_info_update + * + ***FUNCTION: + * This is called to program both SW & Polaris context + * for peer in IBSS. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to DPH node + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_sta_info_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + pStaDs->staType = STA_ENTRY_PEER; + ibss_sta_caps_update(pMac, pPeer, psessionEntry); + ibss_sta_rates_update(pMac, pStaDs, pPeer, psessionEntry); +} /*** end ibss_sta_info_update() ***/ + +static void ibss_coalesce_free(tpAniSirGlobal pMac) +{ + if (pMac->lim.ibssInfo.pHdr != NULL) + cdf_mem_free(pMac->lim.ibssInfo.pHdr); + if (pMac->lim.ibssInfo.pBeacon != NULL) + cdf_mem_free(pMac->lim.ibssInfo.pBeacon); + + pMac->lim.ibssInfo.pHdr = NULL; + pMac->lim.ibssInfo.pBeacon = NULL; +} + +/* + * save the beacon params for use when adding the bss + */ +static void +ibss_coalesce_save(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, tpSchBeaconStruct pBeacon) +{ + /* get rid of any saved info */ + ibss_coalesce_free(pMac); + + pMac->lim.ibssInfo.pHdr = cdf_mem_malloc(sizeof(*pHdr)); + if (NULL == pMac->lim.ibssInfo.pHdr) { + PELOGE(lim_log(pMac, LOGE, FL("ibbs-save: Failed malloc pHdr"));) + return; + } + pMac->lim.ibssInfo.pBeacon = cdf_mem_malloc(sizeof(*pBeacon)); + if (NULL == pMac->lim.ibssInfo.pBeacon) { + PELOGE(lim_log + (pMac, LOGE, FL("ibbs-save: Failed malloc pBeacon")); + ) + ibss_coalesce_free(pMac); + return; + } + + cdf_mem_copy(pMac->lim.ibssInfo.pHdr, pHdr, sizeof(*pHdr)); + cdf_mem_copy(pMac->lim.ibssInfo.pBeacon, pBeacon, sizeof(*pBeacon)); +} + +/* + * tries to add a new entry to dph hash node + * if necessary, an existing entry is eliminated + */ +static tSirRetStatus +ibss_dph_entry_add(tpAniSirGlobal pMac, + tSirMacAddr peerAddr, + tpDphHashNode *ppSta, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + *ppSta = NULL; + + pStaDs = + dph_lookup_hash_entry(pMac, peerAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* Trying to add context for already existing STA in IBSS */ + PELOGE(lim_log(pMac, LOGE, FL("STA exists already "));) + lim_print_mac_addr(pMac, peerAddr, LOGE); + return eSIR_FAILURE; + } + + /** + * Assign an AID, delete context existing with that + * AID and then add an entry to hash table maintained + * by DPH module. + */ + peerIdx = lim_assign_peer_idx(pMac, psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, peerIdx, &psessionEntry->dph.dphHashTable); + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, peerIdx, + psessionEntry); + } + + pStaDs = + dph_add_hash_entry(pMac, peerAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + PELOGE(lim_log + (pMac, LOGE, + FL + ("could not add hash entry at DPH for peerIdx/aid=%d MACaddr:"), + peerIdx); + ) + lim_print_mac_addr(pMac, peerAddr, LOGE); + return eSIR_FAILURE; + } + + *ppSta = pStaDs; + return eSIR_SUCCESS; +} + +/* send a status change notification */ +static void +ibss_status_chg_notify(tpAniSirGlobal pMac, + tSirMacAddr peerAddr, + uint16_t staIndex, + uint8_t ucastSig, + uint8_t bcastSig, uint16_t status, uint8_t sessionId) +{ + + tLimIbssPeerNode *peerNode; + uint8_t *beacon = NULL; + uint16_t bcnLen = 0; + + peerNode = ibss_peer_find(pMac, peerAddr); + if (peerNode != NULL) { + if (peerNode->beacon == NULL) + peerNode->beaconLen = 0; + beacon = peerNode->beacon; + bcnLen = peerNode->beaconLen; + peerNode->beacon = NULL; + peerNode->beaconLen = 0; + } + + lim_send_sme_ibss_peer_ind(pMac, peerAddr, staIndex, ucastSig, bcastSig, + beacon, bcnLen, status, sessionId); + + if (beacon != NULL) { + cdf_mem_free(beacon); + } +} + +static void ibss_bss_add(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tLimMlmStartReq mlmStartReq; + uint32_t cfg; + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + uint8_t numExtRates = 0; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Unable to add BSS (no cached BSS info)")); + ) + return; + } + + cdf_mem_copy(psessionEntry->bssId, pHdr->bssId, sizeof(tSirMacAddr)); + + sir_copy_mac_addr(pHdr->bssId, psessionEntry->bssId); + + /* Copy beacon interval from sessionTable */ + cfg = psessionEntry->beaconParams.beaconInterval; + if (cfg != pBeacon->beaconInterval) + psessionEntry->beaconParams.beaconInterval = + pBeacon->beaconInterval; + + /* This function ibss_bss_add (and hence the below code) is only called during ibss coalescing. We need to + * adapt to peer's capability with respect to short slot time. Changes have been made to lim_apply_configuration() + * so that the IBSS doesnt blindly start with short slot = 1. If IBSS start is part of coalescing then it will adapt + * to peer's short slot using code below. + */ + /* If cfg is already set to current peer's capability then no need to set it again */ + if (psessionEntry->shortSlotTimeSupported != + pBeacon->capabilityInfo.shortSlotTime) { + psessionEntry->shortSlotTimeSupported = + pBeacon->capabilityInfo.shortSlotTime; + } + cdf_mem_copy((uint8_t *) &psessionEntry->pLimStartBssReq-> + operationalRateSet, (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates); + + /** + * WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET CFG needs to be reset, when + * there is no extended rate IE present in beacon. This is especially important when + * supportedRateSet IE contains all the extended rates as well and STA decides to coalesce. + * In this IBSS coalescing scenario LIM will tear down the BSS and Add a new one. So LIM needs to + * reset this CFG, just in case CSR originally had set this CFG when IBSS was started from the local profile. + * If IBSS was started by CSR from the BssDescription, then it would reset this CFG before StartBss is issued. + * The idea is that the count of OpRateSet and ExtendedOpRateSet rates should not be more than 12. + */ + + if (pBeacon->extendedRatesPresent) + numExtRates = pBeacon->extendedRates.numRates; + if (cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &pBeacon->extendedRates.rate, + numExtRates) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not update ExtendedOperRateset at CFG")); + return; + } + + /* + * Each IBSS node will advertise its own HT Capabilities instead of adapting to the Peer's capabilities + * If we don't do this then IBSS may not go back to full capabilities when the STA with lower capabilities + * leaves the IBSS. e.g. when non-CB STA joins an IBSS and then leaves, the IBSS will be stuck at non-CB mode + * even though all the nodes are capable of doing CB. + * so it is decided to leave the self HT capabilties intact. This may change if some issues are found in interop. + */ + cdf_mem_set((void *)&mlmStartReq, sizeof(mlmStartReq), 0); + + cdf_mem_copy(mlmStartReq.bssId, pHdr->bssId, sizeof(tSirMacAddr)); + mlmStartReq.rateSet.numRates = + psessionEntry->pLimStartBssReq->operationalRateSet.numRates; + cdf_mem_copy(&mlmStartReq.rateSet.rate[0], + &psessionEntry->pLimStartBssReq->operationalRateSet. + rate[0], mlmStartReq.rateSet.numRates); + mlmStartReq.bssType = eSIR_IBSS_MODE; + mlmStartReq.beaconPeriod = pBeacon->beaconInterval; + mlmStartReq.nwType = psessionEntry->pLimStartBssReq->nwType; /* psessionEntry->nwType is also OK???? */ + mlmStartReq.htCapable = psessionEntry->htCapability; + mlmStartReq.htOperMode = pMac->lim.gHTOperMode; + mlmStartReq.dualCTSProtection = pMac->lim.gHTDualCTSProtection; + mlmStartReq.txChannelWidthSet = psessionEntry->htRecommendedTxWidthSet; + + /* reading the channel num from session Table */ + mlmStartReq.channelNumber = psessionEntry->currentOperChannel; + + mlmStartReq.cbMode = psessionEntry->pLimStartBssReq->cbMode; + + /* Copy the SSID for RxP filtering based on SSID. */ + cdf_mem_copy((uint8_t *) &mlmStartReq.ssId, + (uint8_t *) &psessionEntry->pLimStartBssReq->ssId, + psessionEntry->pLimStartBssReq->ssId.length + 1); + + PELOG1(lim_log + (pMac, LOG1, FL("invoking ADD_BSS as part of coalescing!")); + ) + if (lim_mlm_add_bss(pMac, &mlmStartReq, psessionEntry) != + eSIR_SME_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("AddBss failure"));) + return; + } + /* Update fields in Beacon */ + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("*** Unable to set fixed Beacon fields ***")); + ) + return; + } + +} + +/* delete the current BSS */ +static void ibss_bss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirRetStatus status; + PELOGW(lim_log(pMac, LOGW, FL("Initiating IBSS Delete BSS"));) + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + lim_log(pMac, LOGW, + FL("Incorrect LIM MLM state for delBss (%d)"), + psessionEntry->limMlmState); + return; + } + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + if (status != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("delBss failed for bss %d"), + psessionEntry->bssIdx); + ) +} + +/** + * lim_ibss_init + * + ***FUNCTION: + * This function is called while starting an IBSS + * to initialize list used to maintain IBSS peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_ibss_init(tpAniSirGlobal pMac) +{ + pMac->lim.gLimIbssCoalescingHappened = 0; + pMac->lim.gLimIbssPeerList = NULL; + pMac->lim.gLimNumIbssPeers = 0; + + /* ibss info - params for which ibss to join while coalescing */ + cdf_mem_set(&pMac->lim.ibssInfo, sizeof(tAniSirLimIbss), 0); +} /*** end lim_ibss_init() ***/ + +/** + * lim_ibss_delete_all_peers + * + ***FUNCTION: + * This function is called to delete all peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_ibss_delete_all_peers(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tLimIbssPeerNode *pCurrNode, *pTempNode; + tpDphHashNode pStaDs; + uint16_t peerIdx; + + pCurrNode = pTempNode = pMac->lim.gLimIbssPeerList; + + while (pCurrNode != NULL) { + if (!pMac->lim.gLimNumIbssPeers) { + lim_log(pMac, LOGP, + FL + ("Number of peers in the list is zero and node present")); + return; + } + /* Delete the dph entry for the station + * Since it is called to remove all peers, just delete from dph, + * no need to do any beacon related params i.e., dont call lim_delete_dph_hash_entry + */ + pStaDs = + dph_lookup_hash_entry(pMac, pCurrNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs) { + + ibss_status_chg_notify(pMac, pCurrNode->peerMacAddr, + pStaDs->staIndex, + pStaDs->ucUcastSig, + pStaDs->ucBcastSig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + psessionEntry->smeSessionId); + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + dph_delete_hash_entry(pMac, pStaDs->staAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + } + + pTempNode = pCurrNode->next; + + /* TODO :Sessionize this code */ + /* Fix CR 227642: PeerList should point to the next node since the current node is being + * freed in the next line. In ibss_peerfind in ibss_status_chg_notify above, we use this + * peer list to find the next peer. So this list needs to be updated with the no of peers left + * after each iteration in this while loop since one by one peers are deleted (freed) in this + * loop causing the lim.gLimIbssPeerList to point to some freed memory. + */ + pMac->lim.gLimIbssPeerList = pTempNode; + + if (pCurrNode->beacon) { + cdf_mem_free(pCurrNode->beacon); + } + cdf_mem_free(pCurrNode); + if (pMac->lim.gLimNumIbssPeers > 0) /* be paranoid */ + pMac->lim.gLimNumIbssPeers--; + pCurrNode = pTempNode; + } + + if (pMac->lim.gLimNumIbssPeers) + lim_log(pMac, LOGP, + FL("Number of peers[%d] in the list is non-zero"), + pMac->lim.gLimNumIbssPeers); + + pMac->lim.gLimNumIbssPeers = 0; + pMac->lim.gLimIbssPeerList = NULL; + +} + +/** + * lim_ibss_delete() - This function is called while tearing down an IBSS + * + * @pMac: Pointer to Global MAC structure + * @psessionEntry: Pointer to session entry + * + * Return: none + */ + +void lim_ibss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + lim_ibss_delete_all_peers(pMac, psessionEntry); + ibss_coalesce_free(pMac); +} + +/** ------------------------------------------------------------- + \fn lim_ibss_set_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_set_protection(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!pMac->lim.cfgProtection.fromllb) { + PELOG1(lim_log + (pMac, LOG1, FL("protection from 11b is disabled")); + ) + return; + } + + if (enable) { + psessionEntry->gLim11bParams.protectionEnabled = true; + if (false == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + PELOGE(lim_log + (pMac, LOGE, FL("=> IBSS: Enable Protection ")); + ) + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } else if (true == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + psessionEntry->gLim11bParams.protectionEnabled = false; + PELOGE(lim_log(pMac, LOGE, FL("===> IBSS: Disable protection "));) + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = false; + pBeaconParams->paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; + } + return; +} + +/** ------------------------------------------------------------- + \fn lim_ibss_update_protection_params + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_update_protection_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tpPESession psessionEntry) +{ + uint32_t i; + + PELOG1(lim_log(pMac, LOG1, FL("A STA is associated:")); + lim_log(pMac, LOG1, FL("Addr : ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG1); + ) + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (pMac->lim.protStaCache[i].active) { + PELOG1(lim_log(pMac, LOG1, FL("Addr: "));) + PELOG1(lim_print_mac_addr + (pMac, pMac->lim.protStaCache[i].addr, LOG1); + ) + + if (cdf_mem_compare(pMac->lim.protStaCache[i].addr, + peerMacAddr, + sizeof(tSirMacAddr))) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("matching cache entry at %d already active."), + i); + ) + return; + } + } + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!pMac->lim.protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + PELOGE(lim_log(pMac, LOGE, FL("No space in ProtStaCache"));) + return; + } + + cdf_mem_copy(pMac->lim.protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + pMac->lim.protStaCache[i].protStaCacheType = protStaCacheType; + pMac->lim.protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + } +} + +/** ------------------------------------------------------------- + \fn lim_ibss_decide_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_decide_protection(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + + pBeaconParams->paramChangeBitmap = 0; + + if (NULL == pStaDs) { + PELOGE(lim_log(pMac, LOGE, FL("pStaDs is NULL"));) + return; + } + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (SIR_BAND_2_4_GHZ == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G or 11n. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) + || (psessionEntry->htCapability)) { + /* As we found in the past, it is possible that a 11n STA sends + * Beacon with HT IE but not ERP IE. So the absense of ERP IE + * in the Beacon is not enough to conclude that STA is 11b. + */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + PELOGE(lim_log + (pMac, LOGE, + FL("Enable protection from 11B")); + ) + lim_ibss_set_protection(pMac, true, + pBeaconParams, + psessionEntry); + } + } + } + lim_ibss_update_protection_params(pMac, pStaDs->staAddr, protStaCacheType, + psessionEntry); + return; +} + +/** + * lim_ibss_peer_find() + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + return ibss_peer_find(pMac, macAddr); +} + +/** + * lim_ibss_sta_add() + * + ***FUNCTION: + * This function is called to add an STA context in IBSS role + * whenever a data frame is received from/for a STA that failed + * hash lookup at DPH. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param peerAdddr MAC address of the peer being added + * @return retCode Indicates success or failure return code + * @return + */ + +tSirRetStatus +lim_ibss_sta_add(tpAniSirGlobal pMac, void *pBody, tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tpDphHashNode pStaDs; + tLimIbssPeerNode *pPeerNode; + tLimMlmStates prevState; + tSirMacAddr *pPeerAddr = (tSirMacAddr *) pBody; + tUpdateBeaconParams beaconParams; + + cdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + + if (pBody == 0) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid IBSS AddSta"));) + return eSIR_FAILURE; + } + + PELOGE(lim_log(pMac, LOGE, FL("Rx Add-Ibss-Sta for MAC:"));) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + + pPeerNode = ibss_peer_find(pMac, *pPeerAddr); + if (NULL != pPeerNode) { + retCode = + ibss_dph_entry_add(pMac, *pPeerAddr, &pStaDs, + psessionEntry); + if (eSIR_SUCCESS == retCode) { + prevState = pStaDs->mlmStaContext.mlmState; + pStaDs->erpEnabled = pPeerNode->erpIePresent; + + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + PELOGW(lim_log + (pMac, LOGW, + FL("initiating ADD STA for the IBSS peer.")); + ) + retCode = + lim_add_sta(pMac, pStaDs, false, psessionEntry); + if (retCode != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("ibss-sta-add failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + pStaDs->mlmStaContext.mlmState = prevState; + dph_delete_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, + &psessionEntry->dph. + dphHashTable); + } else { + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, + &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("---> Update Beacon Params ")); + ) + sch_set_fixed_beacon_fields(pMac, + psessionEntry); + beaconParams.bssIdx = + psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, + psessionEntry); + } + } + } else { + PELOGE(lim_log + (pMac, LOGE, FL("hashTblAdd failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + } + } else { + retCode = eSIR_FAILURE; + } + + return retCode; +} + +/* handle the response from HAL for an ADD STA request */ +tSirRetStatus +lim_ibss_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tpDphHashNode pStaDs; + uint16_t peerIdx; + tpAddStaParams pAddStaParams = (tpAddStaParams) msg; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pAddStaParams == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: ADD_STA_RSP with no body!")); + ) + return eSIR_FAILURE; + } + + pStaDs = + dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("IBSS: ADD_STA_RSP for unknown MAC addr ")); + ) + lim_print_mac_addr(pMac, pAddStaParams->staMac, LOGE); + cdf_mem_free(pAddStaParams); + return eSIR_FAILURE; + } + + if (pAddStaParams->status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: ADD_STA_RSP error (%x) "), + pAddStaParams->status); + ) + lim_print_mac_addr(pMac, pAddStaParams->staMac, LOGE); + cdf_mem_free(pAddStaParams); + return eSIR_FAILURE; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->ucUcastSig = pAddStaParams->ucUcastSig; + pStaDs->ucBcastSig = pAddStaParams->ucBcastSig; + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + + PELOGW(lim_log + (pMac, LOGW, FL("IBSS: sending IBSS_NEW_PEER msg to SME!")); + ) + + ibss_status_chg_notify(pMac, pAddStaParams->staMac, + pStaDs->staIndex, pStaDs->ucUcastSig, + pStaDs->ucBcastSig, + eWNI_SME_IBSS_NEW_PEER_IND, + psessionEntry->smeSessionId); + + cdf_mem_free(pAddStaParams); + + return eSIR_SUCCESS; +} + +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + + PELOGW(lim_log + (pMac, LOGW, FL("IBSS: DEL_BSS_RSP Rcvd during coalescing!")); + ) + + if (pDelBss == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("IBSS: DEL_BSS_RSP(coalesce) with no body!")); + ) + goto end; + } + + if (pDelBss->status != CDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, + FL("IBSS: DEL_BSS_RSP(coalesce) error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + goto end; + } + /* Delete peer entries. */ + lim_ibss_delete_all_peers(pMac, psessionEntry); + + /* add the new bss */ + ibss_bss_add(pMac, psessionEntry); + +end: + if (pDelBss != NULL) + cdf_mem_free(pDelBss); +} + +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry) +{ + uint8_t infoLen; + tSirSmeNewBssInfo newBssInfo; + + tpAddBssParams pAddBss = (tpAddBssParams) msg; + + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Unable to handle AddBssRspWhenCoalescing (no cached BSS info)")); + ) + goto end; + } + /* Inform Host of IBSS coalescing */ + infoLen = sizeof(tSirMacAddr) + sizeof(tSirMacChanNum) + + sizeof(uint8_t) + pBeacon->ssId.length + 1; + + cdf_mem_set((void *)&newBssInfo, sizeof(newBssInfo), 0); + cdf_mem_copy(newBssInfo.bssId, pHdr->bssId, sizeof(tSirMacAddr)); + newBssInfo.channelNumber = (tSirMacChanNum) pAddBss->currentOperChannel; + cdf_mem_copy((uint8_t *) &newBssInfo.ssId, + (uint8_t *) &pBeacon->ssId, pBeacon->ssId.length + 1); + + PELOGW(lim_log + (pMac, LOGW, FL("Sending JOINED_NEW_BSS notification to SME.")); + ) + + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_JOINED_NEW_BSS, + (uint32_t *) &newBssInfo, + infoLen, pSessionEntry->smeSessionId); + { + /* Configure beacon and send beacons to HAL */ + lim_send_beacon_ind(pMac, pSessionEntry); + } + +end: + ibss_coalesce_free(pMac); +} + +void lim_ibss_del_bss_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pDelBss == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: DEL_BSS_RSP with no body!")); + ) + rc = eSIR_SME_REFUSED; + goto end; + } + + psessionEntry = pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + goto end; + } + + /* + * If delBss was issued as part of IBSS Coalescing, gLimIbssCoalescingHappened flag will be true. + * BSS has to be added again in this scenario, so this case needs to be handled separately. + * If delBss was issued as a result of trigger from SME_STOP_BSS Request, then limSme state changes to + * 'IDLE' and gLimIbssCoalescingHappened flag will be false. In this case STOP BSS RSP has to be sent to SME. + */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + + lim_ibss_del_bss_rsp_when_coalescing(pMac, msg, psessionEntry); + return; + } + + if (pDelBss->status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: DEL_BSS_RSP error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + ) + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + if (lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("IBSS: DEL_BSS_RSP setLinkState failed")); + ) + rc = eSIR_SME_REFUSED; + goto end; + } + + lim_ibss_delete(pMac, psessionEntry); + + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + psessionEntry->limSystemRole = eLIM_STA_ROLE; + + /* Change the short slot operating mode to Default (which is 1 for now) so that when IBSS starts next time with Libra + * as originator, it picks up the default. This enables us to remove hard coding of short slot = 1 from lim_apply_configuration + */ + psessionEntry->shortSlotTimeSupported = WNI_CFG_SHORT_SLOT_TIME_STADEF; + +end: + if (pDelBss != NULL) + cdf_mem_free(pDelBss); + /* Delete PE session once BSS is deleted */ + if (NULL != psessionEntry) { + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } +} + +static void +__lim_ibss_search_and_delete_peer(tpAniSirGlobal pMac, + tpPESession psessionEntry, tSirMacAddr macAddr) +{ + tLimIbssPeerNode *pTempNode, *pPrevNode; + tLimIbssPeerNode *pTempNextNode = NULL; + tpDphHashNode pStaDs = NULL; + uint16_t peerIdx = 0; + uint16_t staIndex = 0; + uint8_t ucUcastSig; + uint8_t ucBcastSig; + + pPrevNode = pTempNode = pMac->lim.gLimIbssPeerList; + + lim_log(pMac, LOG1, FL(" PEER ADDR :" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(macAddr)); + + /** Compare Peer */ + while (NULL != pTempNode) { + pTempNextNode = pTempNode->next; + + /* Delete the STA with MAC address */ + if (cdf_mem_compare((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + pStaDs = dph_lookup_hash_entry(pMac, macAddr, + &peerIdx, + &psessionEntry->dph. + dphHashTable); + if (pStaDs) { + staIndex = pStaDs->staIndex; + ucUcastSig = pStaDs->ucUcastSig; + ucBcastSig = pStaDs->ucBcastSig; + + (void)lim_del_sta(pMac, pStaDs, + false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + peerIdx, psessionEntry); + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + + /* Send indication to upper layers */ + ibss_status_chg_notify(pMac, macAddr, staIndex, + ucUcastSig, ucBcastSig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + psessionEntry-> + smeSessionId); + if (pTempNode == pMac->lim.gLimIbssPeerList) { + pMac->lim.gLimIbssPeerList = + pTempNode->next; + pPrevNode = pMac->lim.gLimIbssPeerList; + } else + pPrevNode->next = pTempNode->next; + + cdf_mem_free(pTempNode); + pMac->lim.gLimNumIbssPeers--; + + pTempNode = pTempNextNode; + break; + } + } + pPrevNode = pTempNode; + pTempNode = pTempNextNode; + } + /* + * if it is the last peer walking out, we better + * we set IBSS state to inactive. + */ + if (0 == pMac->lim.gLimNumIbssPeers) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + "Last STA from IBSS walked out"); + psessionEntry->limIbssActive = false; + } +} + +/** + * lim_ibss_coalesce() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * + * @return Status whether to process or ignore received Beacon Frame + */ + +tSirRetStatus +lim_ibss_coalesce(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, + tpSchBeaconStruct pBeacon, + uint8_t *pIEs, + uint32_t ieLen, uint16_t fTsfLater, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tSirMacAddr currentBssId; + tLimIbssPeerNode *pPeerNode; + tpDphHashNode pStaDs; + tUpdateBeaconParams beaconParams; + + cdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + + sir_copy_mac_addr(currentBssId, psessionEntry->bssId); + + lim_log(pMac, LOG1, + FL("Current BSSID :" MAC_ADDRESS_STR " Received BSSID :" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(currentBssId), + MAC_ADDR_ARRAY(pHdr->bssId)); + + /* Check for IBSS Coalescing only if Beacon is from different BSS */ + if (!cdf_mem_compare(currentBssId, pHdr->bssId, sizeof(tSirMacAddr)) + && psessionEntry->isCoalesingInIBSSAllowed) { + /* + * If STA entry is already available in the LIM hash table, then it is + * possible that the peer may have left and rejoined within the heartbeat + * timeout. In the offloaded case with 32 peers, the HB timeout is whopping + * 128 seconds. In that case, the FW will not let any frames come in until + * atleast the last sequence number is received before the peer is left + * Hence, if the coalescing peer is already there in the peer list and if + * the BSSID matches then, invoke delSta() to cleanup the entries. We will + * let the peer coalesce when we receive next beacon from the peer + */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (NULL != pPeerNode) { + __lim_ibss_search_and_delete_peer(pMac, psessionEntry, + pHdr->sa); + PELOGW(lim_log + (pMac, LOGW, + FL + ("** Peer attempting to reconnect before HB timeout, deleted **")); + ) + return eSIR_LIM_IGNORE_BEACON; + } + + if (!fTsfLater) { /* No Coalescing happened. */ + PELOGW(lim_log(pMac, LOGW, FL("No Coalescing happened"));) + return eSIR_LIM_IGNORE_BEACON; + } + /* + * IBSS Coalescing happened. + * save the received beacon, and delete the current BSS. The rest of the + * processing will be done in the delBss response processing + */ + pMac->lim.gLimIbssCoalescingHappened = true; + PELOGW(lim_log(pMac, LOGW, FL("IBSS Coalescing happened"));) + ibss_coalesce_save(pMac, pHdr, pBeacon); + lim_log(pMac, LOGW, FL("Delete BSSID :" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(currentBssId)); + ibss_bss_delete(pMac, psessionEntry); + return eSIR_SUCCESS; + } else { + if (!cdf_mem_compare + (currentBssId, pHdr->bssId, sizeof(tSirMacAddr))) + return eSIR_LIM_IGNORE_BEACON; + } + + /* STA in IBSS mode and SSID matches with ours */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (pPeerNode == NULL) { + /* Peer not in the list - Collect BSS description & add to the list */ + uint32_t frameLen; + tSirRetStatus retCode; + + /* + * Limit the Max number of IBSS Peers allowed as the max + * number of STA's allowed + * pMac->lim.gLimNumIbssPeers will be increamented after exiting + * this function. so we will add additional 1 to compare against + * pMac->lim.gLimIbssStaLimit + */ + if ((pMac->lim.gLimNumIbssPeers + 1) >= + pMac->lim.gLimIbssStaLimit) { + /*Print every 100th time */ + if (pMac->lim.ibss_retry_cnt % 100 == 0) { + PELOGE(lim_log(pMac, LOG1, + FL("**** MAX STA LIMIT HAS REACHED ****"));) + } + pMac->lim.ibss_retry_cnt++; + return eSIR_LIM_MAX_STA_REACHED_ERROR; + } + PELOGW(lim_log + (pMac, LOGW, + FL("IBSS Peer node does not exist, adding it***")); + ) + frameLen = + sizeof(tLimIbssPeerNode) + ieLen - sizeof(uint32_t); + + pPeerNode = cdf_mem_malloc((uint16_t) frameLen); + if (NULL == pPeerNode) { + lim_log(pMac, LOGP, + FL + ("alloc fail (%d bytes) storing IBSS peer info"), + frameLen); + return eSIR_MEM_ALLOC_FAILED; + } + + pPeerNode->beacon = NULL; + pPeerNode->beaconLen = 0; + + ibss_peer_collect(pMac, pBeacon, pHdr, pPeerNode, + psessionEntry); + pPeerNode->beacon = cdf_mem_malloc(ieLen); + if (NULL == pPeerNode->beacon) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Unable to allocate memory to store beacon")); + ) + } else { + cdf_mem_copy(pPeerNode->beacon, pIEs, ieLen); + pPeerNode->beaconLen = (uint16_t) ieLen; + } + ibss_peer_add(pMac, pPeerNode); + + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* / DPH node already exists for the peer */ + PELOGW(lim_log + (pMac, LOGW, + FL("DPH Node present for just learned peer")); + ) + PELOG1(lim_print_mac_addr + (pMac, pPeerNode->peerMacAddr, LOG1); + ) + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + return eSIR_SUCCESS; + } + retCode = + lim_ibss_sta_add(pMac, pPeerNode->peerMacAddr, psessionEntry); + if (retCode != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("lim-ibss-sta-add failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, pPeerNode->peerMacAddr, LOGE); + return retCode; + } + /* Decide protection mode */ + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("beaconParams.paramChangeBitmap=1 ---> Update Beacon Params ")); + ) + sch_set_fixed_beacon_fields(pMac, psessionEntry); + beaconParams.bssIdx = psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } else + ibss_sta_caps_update(pMac, pPeerNode, psessionEntry); + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) + return eSIR_SUCCESS; + + /* Received Beacon from same IBSS we're */ + /* currently part of. Inform Roaming algorithm */ + /* if not already that IBSS is active. */ + if (psessionEntry->limIbssActive == false) { + limResetHBPktCount(psessionEntry); + PELOGW(lim_log + (pMac, LOGW, + FL + ("Partner joined our IBSS, Sending IBSS_ACTIVE Notification to SME")); + ) + psessionEntry->limIbssActive = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_IBSS_ACTIVE, NULL, 0, + psessionEntry->smeSessionId); + } + + return eSIR_SUCCESS; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * lim_ibss_heart_beat_handle() - handle IBSS hearbeat failure + * + * @mac_ctx: global mac context + * @session: PE session entry + * + * Hanlde IBSS hearbeat failure. + * + * Return: None. + */ +void lim_ibss_heart_beat_handle(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tLimIbssPeerNode *tempnode, *prevnode; + tLimIbssPeerNode *temp_next = NULL; + uint16_t peer_idx = 0; + tpDphHashNode stads = 0; + uint32_t threshold = 0; + uint16_t sta_idx = 0; + uint8_t ucast_sig = 0; + uint8_t bcast_sig = 0; + + /* + * MLM BSS is started and if PE in scanmode then MLM state will be + * waiting for probe resp. If Heart beat timeout triggers during this + * corner case then we need to reactivate HeartBeat timer. + */ + if (session->limMlmState != eLIM_MLM_BSS_STARTED_STATE) + return; + + /* If LinkMonitor is Disabled */ + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) + return; + + prevnode = tempnode = mac_ctx->lim.gLimIbssPeerList; + threshold = (mac_ctx->lim.gLimNumIbssPeers / 4) + 1; + + /* Monitor the HeartBeat with the Individual PEERS in the IBSS */ + while (tempnode != NULL) { + temp_next = tempnode->next; + if (tempnode->beaconHBCount) { + /* There was a beacon for this peer during heart beat */ + tempnode->beaconHBCount = 0; + tempnode->heartbeatFailure = 0; + prevnode = tempnode; + tempnode = temp_next; + continue; + } + + /* There wasnt any beacon received during heartbeat timer. */ + tempnode->heartbeatFailure++; + lim_log(mac_ctx, LOGE, FL("Heartbeat fail = %d thres = %d"), + tempnode->heartbeatFailure, mac_ctx->lim.gLimNumIbssPeers); + if (tempnode->heartbeatFailure >= threshold) { + /* Remove this entry from the list. */ + stads = dph_lookup_hash_entry(mac_ctx, + tempnode->peerMacAddr, &peer_idx, + &session->dph.dphHashTable); + if (stads) { + sta_idx = stads->staIndex; + ucast_sig = stads->ucUcastSig; + bcast_sig = stads->ucBcastSig; + + (void)lim_del_sta(mac_ctx, stads, false, + session); + lim_delete_dph_hash_entry(mac_ctx, + stads->staAddr, peer_idx, session); + lim_release_peer_idx(mac_ctx, peer_idx, + session); + /* Send indication. */ + ibss_status_chg_notify(mac_ctx, + tempnode->peerMacAddr, sta_idx, + ucast_sig, bcast_sig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + session->smeSessionId); + } + if (tempnode == mac_ctx->lim.gLimIbssPeerList) { + mac_ctx->lim.gLimIbssPeerList = tempnode->next; + prevnode = mac_ctx->lim.gLimIbssPeerList; + } else { + prevnode->next = tempnode->next; + } + + cdf_mem_free(tempnode); + mac_ctx->lim.gLimNumIbssPeers--; + + /* we deleted current node, so prevNode remains same. */ + tempnode = temp_next; + continue; + } + prevnode = tempnode; + tempnode = temp_next; + } + + /* + * General IBSS Activity Monitor, + * check if in IBSS Mode we are received any Beacons + */ + if (mac_ctx->lim.gLimNumIbssPeers) { + if (session->LimRxedBeaconCntDuringHB < + MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL) + mac_ctx->lim.gLimHeartBeatBeaconStats[ + session->LimRxedBeaconCntDuringHB]++; + else + mac_ctx->lim.gLimHeartBeatBeaconStats[0]++; + + /* Reset number of beacons received */ + limResetHBPktCount(session); + return; + } else { + lim_log(mac_ctx, LOGW, FL("Heartbeat Failure")); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + if (session->limIbssActive == true) { + /* + * We don't receive Beacon frames from any + * other STA in IBSS. Announce IBSS inactive + * to Roaming algorithm + */ + lim_log(mac_ctx, LOGW, FL("Alone in IBSS")); + session->limIbssActive = false; + + lim_send_sme_wm_status_change_ntf(mac_ctx, + eSIR_SME_IBSS_INACTIVE, NULL, 0, + session->smeSessionId); + } + } +} + +/** + * lim_ibss_decide_protection_on_delete() - decides protection related info. + * + * @mac_ctx: global mac context + * @stads: station hash node + * @bcn_param: beacon parameters + * @session: PE session entry + * + * Decides all the protection related information. + * + * Return: None + */ +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode stads, + tpUpdateBeaconParams bcn_param, + tpPESession session) +{ + uint32_t phymode; + tHalBitVal erpenabled = eHAL_CLEAR; + tSirRFBand rfband = SIR_BAND_UNKNOWN; + uint32_t i; + + if (NULL == stads) + return; + + lim_get_rf_band_new(mac_ctx, &rfband, session); + if (SIR_BAND_2_4_GHZ != rfband) + return; + + lim_get_phy_mode(mac_ctx, &phymode, session); + erpenabled = stads->erpEnabled; + /* we are HT or 11G and 11B station is getting deleted. */ + if (((phymode == WNI_CFG_PHY_MODE_11G) || + session->htCapability) && (erpenabled == eHAL_CLEAR)) { + lim_log(mac_ctx, LOGE, + FL("(%d) A legacy STA is disassociated. Addr is "), + session->gLim11bParams.numSta); + lim_print_mac_addr(mac_ctx, stads->staAddr, LOGE); + if (session->gLim11bParams.numSta == 0) { + lim_log(mac_ctx, LOGE, + FL("No 11B STA exists. Disable protection.")); + lim_ibss_set_protection(mac_ctx, false, + bcn_param, session); + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!mac_ctx->lim.protStaCache[i].active) + continue; + if (cdf_mem_compare(mac_ctx->lim.protStaCache[i].addr, + stads->staAddr, sizeof(tSirMacAddr))) { + session->gLim11bParams.numSta--; + mac_ctx->lim.protStaCache[i].active = false; + break; + } + } + + } +} + +/** ----------------------------------------------------------------- + \fn __lim_ibss_peer_inactivity_handler + \brief Internal function. Deletes FW indicated peer which is inactive + \ + \param tpAniSirGlobal pMac + \param tpPESession psessionEntry + \param tpSirIbssPeerInactivityInd peerInactivityInd + \return None + -----------------------------------------------------------------*/ +static void +__lim_ibss_peer_inactivity_handler(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSirIbssPeerInactivityInd peerInactivityInd) +{ + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + return; + } + + /* delete the peer for which heartbeat is observed */ + __lim_ibss_search_and_delete_peer(pMac, psessionEntry, + peerInactivityInd->peerAddr); + +} + +/** ------------------------------------------------------------- + \fn lim_process_ibss_peer_inactivity + \brief Peer inactivity message handler + \ + \param tpAniSirGlobal pMac + \param void* buf + \return None + -------------------------------------------------------------*/ +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf) +{ + /* + * --------------- HEARTBEAT OFFLOAD CASE ------------------ + * This message handler is executed when the firmware identifies + * inactivity from one or more peer devices. We will come here + * for every inactive peer device + */ + uint8_t i; + + tSirIbssPeerInactivityInd *peerInactivityInd = + (tSirIbssPeerInactivityInd *) buf; + + /* + * If IBSS is not started or heartbeat offload is not enabled + * we should not handle this request + */ + if (eLIM_STA_IN_IBSS_ROLE != pMac->lim.gLimSystemRole && + !IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE) { + return; + } + + /** If LinkMonitor is Disabled */ + if (!pMac->sys.gSysEnableLinkMonitorMode) { + return; + } + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid && + eSIR_IBSS_MODE == pMac->lim.gpSession[i].bssType) { + __lim_ibss_peer_inactivity_handler(pMac, + &pMac->lim.gpSession[i], + peerInactivityInd); + break; + } + } +} diff --git a/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h b/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h new file mode 100644 index 0000000000..0c97919c3d --- /dev/null +++ b/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ibss_peer_mgmt.h contains prototypes for + * the utility functions LIM uses to maintain peers in IBSS. + * Author: Chandra Modumudi + * Date: 03/12/04 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sir_common.h" +#include "lim_utils.h" + +#define IBSS_STATIONS_USED_DURING_INIT 4 /* (broadcast + self + p2p + softap) */ + +void lim_ibss_init(tpAniSirGlobal); +void lim_ibss_delete(tpAniSirGlobal, tpPESession psessionEntry); +tSirRetStatus lim_ibss_coalesce(tpAniSirGlobal, tpSirMacMgmtHdr, + tpSchBeaconStruct, uint8_t *, uint32_t, uint16_t, + tpPESession); +tSirRetStatus lim_ibss_sta_add(tpAniSirGlobal, void *, tpPESession); +tSirRetStatus lim_ibss_add_sta_rsp(tpAniSirGlobal, void *, tpPESession); +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr); +void lim_ibss_del_bss_rsp(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry); +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession pSessionEntry); +void lim_ibss_heart_beat_handle(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf); diff --git a/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/core/mac/src/pe/lim/lim_link_monitoring_algo.c new file mode 100644 index 0000000000..2ce55b062a --- /dev/null +++ b/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_link_monitoring_algo.cc contains the code for + * Link monitoring algorithm on AP and heart beat failure + * handling on STA. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_assoc_utils.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_ser_des_utils.h" + +/** + * lim_delete_sta_util - utility function for deleting station context + * + * @mac_ctx: global MAC context + * @msg: pointer to delte station context + * @session_entry: PE session entry + * + * utility function called to clear up station context. + * + * Return: None. + */ +static void lim_delete_sta_util(tpAniSirGlobal mac_ctx, tpDeleteStaContext msg, + tpPESession session_entry) +{ + tpDphHashNode stads; + + lim_log(mac_ctx, LOGE, + FL("Deleting station: staId = %d, reasonCode = %d"), + msg->staId, msg->reasonCode); + + if (LIM_IS_IBSS_ROLE(session_entry)) { + cdf_mem_free(msg); + return; + } + + stads = dph_lookup_assoc_id(mac_ctx, msg->staId, &msg->assocId, + &session_entry->dph.dphHashTable); + + if (!stads) { + lim_log(mac_ctx, LOGE, + FL("Invalid STA limSystemRole=%d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + cdf_mem_free(msg); + return; + } + + /* check and see if same staId. This is to avoid the scenario + * where we're trying to delete a staId we just added. + */ + if (stads->staIndex != msg->staId) { + lim_log(mac_ctx, LOGE, FL("staid mismatch: %d vs %d "), + stads->staIndex, msg->staId); + cdf_mem_free(msg); + return; + } + + if (LIM_IS_BT_AMP_AP_ROLE(session_entry) || + LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, + FL("Delete Station staId: %d, assocId: %d"), + msg->staId, msg->assocId); + /* + * Check if Deauth/Disassoc is triggered from Host. + * If mlmState is in some transient state then + * don't trigger STA deletion to avoid the race + * condition. + */ + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + lim_log(mac_ctx, LOGE, + FL("Inv Del STA staId:%d, assocId:%d"), + msg->staId, msg->assocId); + cdf_mem_free(msg); + return; + } else { + lim_trigger_sta_deletion(mac_ctx, stads, session_entry); + } + } else { +#ifdef FEATURE_WLAN_TDLS + if (LIM_IS_STA_ROLE(session_entry) && + STA_ENTRY_TDLS_PEER == stads->staType) { + /* + * TeardownLink with PEER reason code + * HAL_DEL_STA_REASON_CODE_KEEP_ALIVE means + * eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE + */ + lim_send_sme_tdls_del_sta_ind(mac_ctx, stads, + session_entry, + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + } else { +#endif + /* TearDownLink with AP */ + tLimMlmDeauthInd mlm_deauth_ind; + lim_log(mac_ctx, LOGW, + FL("Delete Station (staId: %d, assocId: %d) "), + msg->staId, msg->assocId); + + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + + /* + * Received SIR_LIM_DELETE_STA_CONTEXT_IND for STA that + * does not have context or in some transit state. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("Received SIR_LIM_DELETE_STA_CONTEXT_IND for " + "STA that either has no context or " + "in some transit state, Addr = " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(msg->bssId)); + cdf_mem_free(msg); + return; + } + + stads->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + stads->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + + /* Issue Deauth Indication to SME. */ + cdf_mem_copy((uint8_t *) &mlm_deauth_ind.peerMacAddr, + stads->staAddr, sizeof(tSirMacAddr)); + mlm_deauth_ind.reasonCode = + (uint8_t) stads->mlmStaContext.disassocReason; + mlm_deauth_ind.deauthTrigger = + stads->mlmStaContext.cleanupTrigger; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac_ctx, session_entry); +#endif + lim_post_sme_message(mac_ctx, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlm_deauth_ind); + + lim_send_sme_deauth_ind(mac_ctx, stads, session_entry); +#ifdef FEATURE_WLAN_TDLS + } +#endif + } +} + +/** + * lim_delete_sta_context() - delete sta context. + * + * @mac_ctx: global mac_ctx context + * @lim_msg: lim message. + * + * This function handles the message from HAL: WMA_DELETE_STA_CONTEXT_IND. + * This function validates that the given station id exist, and if so, + * deletes the station by calling lim_trigger_sta_deletion. + * + * Return: none + */ +void lim_delete_sta_context(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg) +{ + tpDeleteStaContext msg = (tpDeleteStaContext) lim_msg->bodyptr; + tpPESession session_entry; + uint8_t session_id; + + if (NULL == msg) { + lim_log(mac_ctx, LOGE, FL("Invalid body pointer in message")); + return; + } + session_entry = pe_find_session_by_bssid(mac_ctx, msg->bssId, + &session_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("session does not exist")); + cdf_mem_free(msg); + return; + } + + switch (msg->reasonCode) { + case HAL_DEL_STA_REASON_CODE_KEEP_ALIVE: + case HAL_DEL_STA_REASON_CODE_TIM_BASED: + lim_delete_sta_util(mac_ctx, msg, session_entry); + break; + + case HAL_DEL_STA_REASON_CODE_UNKNOWN_A2: + lim_log(mac_ctx, LOGE, FL("Deleting Unknown station ")); + lim_print_mac_addr(mac_ctx, msg->addr2, LOGE); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON, + msg->addr2, session_entry, false); + break; + + default: + lim_log(mac_ctx, LOGE, FL(" Unknown reason code ")); + break; + } + cdf_mem_free(msg); + return; +} + +/** + * lim_trigger_sta_deletion() + * + ***FUNCTION: + * This function is called to trigger STA context deletion + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param pStaDs - Pointer to internal STA Datastructure + * @return None + */ +void +lim_trigger_sta_deletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirSmeDeauthReq *pSmeDeauthReq; + uint8_t *pBuf; + uint8_t *pLen; + uint16_t msgLength = 0; + + if (!pStaDs) { + PELOGW(lim_log + (pMac, LOGW, FL("Skip STA deletion (invalid STA)")); + ) + return; + } + /** + * MAC based Authentication was used. Trigger + * Deauthentication frame to peer since it will + * take care of disassociation as well. + */ + + pSmeDeauthReq = cdf_mem_malloc(sizeof(tSirSmeDeauthReq)); + if (NULL == pSmeDeauthReq) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_DEAUTH_REQ ")); + return; + } + + pBuf = (uint8_t *) &pSmeDeauthReq->messageType; + + /* messageType */ + lim_copy_u16((uint8_t *) pBuf, eWNI_SME_DISASSOC_REQ); + pBuf += sizeof(uint16_t); + msgLength += sizeof(uint16_t); + + /* length */ + pLen = pBuf; + pBuf += sizeof(uint16_t); + msgLength += sizeof(uint16_t); + + /* sessionId */ + *pBuf = psessionEntry->smeSessionId; + pBuf++; + msgLength++; + + /* transactionId */ + lim_copy_u16((uint8_t *) pBuf, psessionEntry->transactionId); + pBuf += sizeof(uint16_t); + msgLength += sizeof(uint16_t); + + /* bssId */ + cdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + msgLength += sizeof(tSirMacAddr); + + /* peerMacAddr */ + cdf_mem_copy(pBuf, pStaDs->staAddr, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + msgLength += sizeof(tSirMacAddr); + + /* reasonCode */ + lim_copy_u16((uint8_t *) pBuf, (uint16_t) eLIM_LINK_MONITORING_DISASSOC); + pBuf += sizeof(uint16_t); + msgLength += sizeof(uint16_t); + + /* Do not send disassoc OTA */ + /* pBuf[0] = 1 means do not send the disassoc frame over the air */ + /* pBuf[0] = 0 means send the disassoc frame over the air */ + pBuf[0] = 0; + pBuf += sizeof(uint8_t); + msgLength += sizeof(uint8_t); + + /* Fill in length */ + lim_copy_u16((uint8_t *) pLen, msgLength); + + lim_post_sme_message(pMac, eWNI_SME_DISASSOC_REQ, + (uint32_t *) pSmeDeauthReq); + cdf_mem_free(pSmeDeauthReq); + +} /*** end lim_trigger_st_adeletion() ***/ + +/** + * lim_tear_down_link_with_ap() + * + ***FUNCTION: + * This function is called when heartbeat (beacon reception) + * fails on STA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void +lim_tear_down_link_with_ap(tpAniSirGlobal pMac, uint8_t sessionId, + tSirMacReasonCodes reasonCode) +{ + tpDphHashNode pStaDs = NULL; + + /* tear down the following sessionEntry */ + tpPESession psessionEntry; + + if ((psessionEntry = pe_find_session_by_session_id(pMac, sessionId)) == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + /** + * Heart beat failed for upto threshold value + * and AP did not respond for Probe request. + * Trigger link tear down. + */ + psessionEntry->pmmOffloadInfo.bcnmiss = false; + + lim_log(pMac, LOGW, + FL("No ProbeRsp from AP after HB failure. Tearing down link")); + + /* Announce loss of link to Roaming algorithm */ + /* and cleanup by sending SME_DISASSOC_REQ to SME */ + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs != NULL) { + tLimMlmDeauthInd mlmDeauthInd; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + + pStaDs->mlmStaContext.disassocReason = reasonCode; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from + * Tx inactivity timer by FWR. This will make sure that we + * will not process disassoc if deauth is in progress for + * the station and thus mlmStaContext.cleanupTrigger will + * not be overwritten. + */ + + pStaDs->mlmStaContext.mlmState = + eLIM_MLM_WT_DEL_STA_RSP_STATE; + + /* / Issue Deauth Indication to SME. */ + cdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + + /* + * if sendDeauthBeforeCon is enabled and reasoncode is + * Beacon Missed Store the MAC of AP in the flip flop + * buffer. This MAC will be used to send Deauth before + * connection, if we connect to same AP after HB failure. + */ + if (pMac->roam.configParam.sendDeauthBeforeCon && + eSIR_BEACON_MISSED == reasonCode) { + int apCount = pMac->lim.gLimHeartBeatApMacIndex; + + if (pMac->lim.gLimHeartBeatApMacIndex) + pMac->lim.gLimHeartBeatApMacIndex = 0; + else + pMac->lim.gLimHeartBeatApMacIndex = 1; + + lim_log(pMac, LOGE, FL("HB Failure on MAC " + MAC_ADDRESS_STR" Store it on Index %d"), + MAC_ADDR_ARRAY(pStaDs->staAddr),apCount); + + sir_copy_mac_addr(pMac->lim.gLimHeartBeatApMac[apCount], + pStaDs->staAddr); + } + + mlmDeauthInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = + pStaDs->mlmStaContext.cleanupTrigger; + + lim_post_sme_message(pMac, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + + lim_send_sme_deauth_ind(pMac, pStaDs, psessionEntry); + } +} /*** lim_tear_down_link_with_ap() ***/ + +/** + * lim_handle_heart_beat_failure() - handle hear beat failure in STA + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called when heartbeat (beacon reception) + * fails on STA + * + * Return: None + */ + +void lim_handle_heart_beat_failure(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t curr_chan; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_beacon_update_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_beacon_update_pkt_type, + LOG_WLAN_BEACON_UPDATE_C); + if (log_ptr) + log_ptr->bcn_rx_cnt = session->LimRxedBeaconCntDuringHB; + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Ensure HB Status for the session has been reseted */ + session->LimHBFailureStatus = false; + + if ((LIM_IS_STA_ROLE(session) || + LIM_IS_BT_AMP_STA_ROLE(session)) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + (session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && + (session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) + return; + + /* Beacon frame not received within heartbeat timeout. */ + lim_log(mac_ctx, LOGW, FL("Heartbeat Failure")); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + /* + * Check if connected on the DFS channel, if not connected on + * DFS channel then only send the probe request otherwise tear + * down the link + */ + curr_chan = session->currentOperChannel; + if (!lim_isconnected_on_dfs_channel(curr_chan)) { + /* Detected continuous Beacon Misses */ + session->LimHBFailureStatus = true; + + /*Reset the HB packet count before sending probe*/ + limResetHBPktCount(session); + /** + * Send Probe Request frame to AP to see if + * it is still around. Wait until certain + * timeout for Probe Response from AP. + */ + lim_log(mac_ctx, LOGW, + FL("HB missed from AP. Sending Probe Req")); + /* for searching AP, we don't include any more IE */ + lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId, + session->bssId, curr_chan, session->selfMacAddr, + session->dot11mode, 0, NULL); + } else { + lim_log(mac_ctx, LOGW, + FL("HB missed from AP on DFS chanel moving to passive")); + if (curr_chan < SIR_MAX_24G_5G_CHANNEL_RANGE) { + lim_covert_channel_scan_type(mac_ctx, curr_chan, + false); + mac_ctx->lim.dfschannelList.timeStamp[curr_chan] + = 0; + } + /* + * Connected on DFS channel so should not send the + * probe request tear down the link directly + */ + lim_tear_down_link_with_ap(mac_ctx, + session->peSessionId, + eSIR_BEACON_MISSED); + } + } else { + /** + * Heartbeat timer may have timed out + * while we're doing background scanning/learning + * or in states other than link-established state. + * Log error. + */ + lim_log(mac_ctx, LOG1, + FL("received heartbeat timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOG1, session->limMlmState); + mac_ctx->lim.gLimHBfailureCntInOtherStates++; + } +} diff --git a/core/mac/src/pe/lim/lim_p2p.c b/core/mac/src/pe/lim/lim_p2p.c new file mode 100644 index 0000000000..7f29157ddf --- /dev/null +++ b/core/mac/src/pe/lim/lim_p2p.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + L I M _ P 2 P . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN Protocol Engine for + P2P. + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + $Header$$DateTime$$Author$ + + when who what, where, why + ---------- --- -------------------------------------------------------- + 2011-05-02 djindal Corrected file indentation and changed remain on channel + handling for concurrency. + ===========================================================================*/ + +#include "lim_utils.h" +#include "lim_session_utils.h" +#include "wma_types.h" +#include "lim_types.h" + +#define PROBE_RSP_IE_OFFSET 36 +#define BSSID_OFFSET 16 +#define ADDR2_OFFSET 10 +#define ACTION_OFFSET 24 + +/* A DFS channel can be ACTIVE for max 9000 msec, from the last + received Beacon/Prpbe Resp. */ +#define MAX_TIME_TO_BE_ACTIVE_CHANNEL 9000 + +void lim_exit_remain_on_channel(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +extern tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMacAddr, + tpSetLinkStateCallback callback, + void *callbackArg); + +CDF_STATUS lim_p2p_action_cnf(tpAniSirGlobal pMac, uint32_t txCompleteSuccess); + +/*------------------------------------------------------------------ + * + * Below function is called if hdd requests a remain on channel. + * + *------------------------------------------------------------------*/ +static CDF_STATUS lim_send_hal_req_remain_on_chan_offload(tpAniSirGlobal pMac, + tSirRemainOnChnReq * + pRemOnChnReq) +{ + tSirScanOffloadReq *pScanOffloadReq; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + uint8_t bssid[CDF_MAC_ADDR_SIZE] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + pScanOffloadReq = cdf_mem_malloc(sizeof(tSirScanOffloadReq)); + if (NULL == pScanOffloadReq) { + lim_log(pMac, LOGE, + FL("Memory allocation failed for pScanOffloadReq")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pScanOffloadReq, sizeof(tSirScanOffloadReq)); + + msg.type = WMA_START_SCAN_OFFLOAD_REQ; + msg.bodyptr = pScanOffloadReq; + msg.bodyval = 0; + + cdf_mem_copy((uint8_t *) pScanOffloadReq->selfMacAddr, + (uint8_t *) pRemOnChnReq->selfMacAddr, + sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) pScanOffloadReq->bssId, + (uint8_t *) bssid, sizeof(tSirMacAddr)); + pScanOffloadReq->scanType = eSIR_PASSIVE_SCAN; + pScanOffloadReq->p2pScanType = P2P_SCAN_TYPE_LISTEN; + pScanOffloadReq->minChannelTime = pRemOnChnReq->duration; + pScanOffloadReq->maxChannelTime = pRemOnChnReq->duration; + pScanOffloadReq->sessionId = pRemOnChnReq->sessionId; + pScanOffloadReq->channelList.numChannels = 1; + pScanOffloadReq->channelList.channelNumber[0] = pRemOnChnReq->chnNum; + pScanOffloadReq->scan_id = pRemOnChnReq->scan_id; + + lim_log(pMac, LOG1, + FL("Req-rem-on-channel: duration %u, session %hu, chan %hu"), + pRemOnChnReq->duration, pRemOnChnReq->sessionId, + pRemOnChnReq->chnNum); + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure %u"), + rc); + cdf_mem_free(pScanOffloadReq); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/*------------------------------------------------------------------ + * + * Remain on channel req handler. Initiate the INIT_SCAN, CHN_CHANGE + * and SET_LINK Request from SME, chnNum and duration to remain on channel. + * + *------------------------------------------------------------------*/ +int lim_process_remain_on_chnl_req(tpAniSirGlobal pMac, uint32_t *pMsg) +{ + tSirRemainOnChnReq *msgbuff = (tSirRemainOnChnReq *) pMsg; + CDF_STATUS status; + + pMac->lim.gpLimRemainOnChanReq = msgbuff; + status = lim_send_hal_req_remain_on_chan_offload(pMac, msgbuff); + if (status != CDF_STATUS_SUCCESS) { + /* Post the meessage to Sme */ + lim_send_sme_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + status, msgbuff->sessionId, msgbuff->scan_id); + cdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + } + return false; +} + +/*------------------------------------------------------------------ + * + * lim Insert NOA timer timeout callback - when timer fires, deactivate it and send + * scan rsp to csr/hdd + * + *------------------------------------------------------------------*/ +void lim_process_insert_single_shot_noa_timeout(tpAniSirGlobal pMac) +{ + /* timeout means start NOA did not arrive; we need to deactivate and change the timer for + * future activations + */ + lim_deactivate_and_change_timer(pMac, eLIM_INSERT_SINGLESHOT_NOA_TIMER); + + /* Even if insert NOA timedout, go ahead and process/send stored SME request */ + lim_process_regd_defd_sme_req_after_noa_start(pMac); + + return; +} + +/*----------------------------------------------------------------- + * lim Insert Timer callback function to check active DFS channels + * and convert them to passive channels if there was no + * beacon/proberesp for MAX_TIME_TO_BE_ACTIVE_CHANNEL time + *------------------------------------------------------------------*/ +void lim_convert_active_channel_to_passive_channel(tpAniSirGlobal pMac) +{ + uint32_t currentTime; + uint32_t lastTime = 0; + uint32_t timeDiff; + uint8_t i; + currentTime = cdf_mc_timer_get_system_time(); + for (i = 1; i < SIR_MAX_24G_5G_CHANNEL_RANGE; i++) { + if ((pMac->lim.dfschannelList.timeStamp[i]) != 0) { + lastTime = pMac->lim.dfschannelList.timeStamp[i]; + if (currentTime >= lastTime) { + timeDiff = (currentTime - lastTime); + } else { + timeDiff = + (0xFFFFFFFF - lastTime) + currentTime; + } + + if (timeDiff >= MAX_TIME_TO_BE_ACTIVE_CHANNEL) { + lim_covert_channel_scan_type(pMac, i, false); + pMac->lim.dfschannelList.timeStamp[i] = 0; + } + } + } + /* lastTime is zero if there is no DFS active channels in the list. + * If this is non zero then we have active DFS channels so restart the timer. + */ + if (lastTime != 0) { + if (tx_timer_activate + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer) + != TX_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("Could not activate Active to Passive Channel timer")); + } + } + + return; + +} + +/** + * lim_process_remain_on_chn_timeout() - ROC timeout handler + * + * @mac_ctx: MAC context + * + * limchannelchange callback, on success channel change, set the + * link_state to LISTEN + * + * Return: NULL + */ +void lim_process_remain_on_chn_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + tSirMacAddr null_bssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + TX_TIMER *roc_timer; + + roc_timer = &mac_ctx->lim.limTimers.gLimRemainOnChannelTimer; + /* + * Timer might get extended while Sending Action Frame + * In that case don't process Channel Timeout + */ + if (tx_timer_running(roc_timer)) { + lim_log(mac_ctx, LOGE, + FL("already timer is running and not processing ")); + return; + } + + lim_deactivate_and_change_timer(mac_ctx, eLIM_REMAIN_CHN_TIMER); + if (NULL == mac_ctx->lim.gpLimRemainOnChanReq) { + lim_log(mac_ctx, LOGE, FL("No Remain on channel pending")); + return; + } + + /* get the previous valid LINK state */ + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, null_bssid, + mac_ctx->lim.gSelfMacAddr, NULL, NULL) != eSIR_SUCCESS) + { + lim_log(mac_ctx, LOGE, FL("Unable to change link state")); + return; + } + + if (mac_ctx->lim.gLimMlmState != eLIM_MLM_P2P_LISTEN_STATE) { + lim_remain_on_chn_rsp(mac_ctx, CDF_STATUS_SUCCESS, NULL); + } else { + session = pe_find_session_by_session_id(mac_ctx, + roc_timer->sessionId); + /* get the session */ + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist sessionID %d"), + roc_timer->sessionId); + goto error; + } + + lim_exit_remain_on_channel(mac_ctx, CDF_STATUS_SUCCESS, NULL, + session); + return; +error: + lim_remain_on_chn_rsp(mac_ctx, CDF_STATUS_E_FAILURE, NULL); + } + return; +} + +/*------------------------------------------------------------------ + * + * limchannelchange callback, on success channel change, set the link_state + * to LISTEN + * + *------------------------------------------------------------------*/ + +void lim_exit_remain_on_channel(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + + if (status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, "Remain on Channel Failed");) + goto error; + } + /* Set the resume channel to Any valid channel (invalid). */ + /* This will instruct HAL to set it to any previous valid channel. */ + pe_set_resume_channel(pMac, 0, 0); + lim_remain_on_chn_rsp(pMac, CDF_STATUS_SUCCESS, NULL); + return; +error: + lim_remain_on_chn_rsp(pMac, CDF_STATUS_E_FAILURE, NULL); + return; +} + +/*------------------------------------------------------------------ + * + * Send remain on channel respone: Success/ Failure + * + *------------------------------------------------------------------*/ +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, CDF_STATUS status, uint32_t *data) +{ + tpPESession psessionEntry; + uint8_t sessionId; + tSirRemainOnChnReq *MsgRemainonChannel = pMac->lim.gpLimRemainOnChanReq; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (NULL == MsgRemainonChannel) { + PELOGE(lim_log(pMac, LOGP, + "%s: No Pointer for Remain on Channel Req", + __func__); + ) + return; + } + /* Incase of the Remain on Channel Failure Case */ + /* Cleanup Everything */ + if (CDF_STATUS_E_FAILURE == status) { + /* Deactivate Remain on Channel Timer */ + lim_deactivate_and_change_timer(pMac, eLIM_REMAIN_CHN_TIMER); + + /* Set the Link State to Idle */ + /* get the previous valid LINK state */ + if (lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + pMac->lim.gSelfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, "Unable to change link state"); + } + + pMac->lim.gLimSystemInScanLearnMode = 0; + pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + } + + /* delete the session */ + if ((psessionEntry = pe_find_session_by_bssid(pMac, + MsgRemainonChannel-> + selfMacAddr, + &sessionId)) != NULL) { + if (LIM_IS_P2P_DEVICE_ROLE(psessionEntry)) { + pe_delete_session(pMac, psessionEntry); + } + } + + /* Post the meessage to Sme */ + lim_send_sme_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + status, + MsgRemainonChannel->sessionId, 0); + + cdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + + pMac->lim.gLimMlmState = pMac->lim.gLimPrevMlmState; + + /* If remain on channel timer expired and action frame is pending then + * indicaiton confirmation with status failure */ + if (pMac->lim.mgmtFrameSessionId != 0xff) { + lim_p2p_action_cnf(pMac, 0); + } + + return; +} + +/*------------------------------------------------------------------ + * + * Indicate the Mgmt Frame received to SME to HDD callback + * handle Probe_req/Action frame currently + * + *------------------------------------------------------------------*/ +void lim_send_sme_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, uint32_t rxChannel, + tpPESession psessionEntry, int8_t rxRssi) +{ + tSirMsgQ mmhMsg; + tpSirSmeMgmtFrameInd pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = cdf_mem_malloc(length); + if (NULL == pSirSmeMgmtFrame) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_LISTEN_RSP")); + return; + } + cdf_mem_set((void *)pSirSmeMgmtFrame, length, 0); + + pSirSmeMgmtFrame->mesgType = eWNI_SME_MGMT_FRM_IND; + pSirSmeMgmtFrame->mesgLen = length; + pSirSmeMgmtFrame->sessionId = sessionId; + pSirSmeMgmtFrame->frameType = frameType; + pSirSmeMgmtFrame->rxRssi = rxRssi; + pSirSmeMgmtFrame->rxChan = rxChannel; + + cdf_mem_zero(pSirSmeMgmtFrame->frameBuf, frameLen); + cdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); + + mmhMsg.type = eWNI_SME_MGMT_FRM_IND; + mmhMsg.bodyptr = pSirSmeMgmtFrame; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +CDF_STATUS lim_p2p_action_cnf(tpAniSirGlobal pMac, uint32_t txCompleteSuccess) +{ + if (pMac->lim.mgmtFrameSessionId != 0xff) { + /* The session entry might be invalid(0xff) action confirmation received after + * remain on channel timer expired */ + lim_send_sme_rsp(pMac, eWNI_SME_ACTION_FRAME_SEND_CNF, + (txCompleteSuccess ? eSIR_SME_SUCCESS : + eSIR_SME_SEND_ACTION_FAIL), + pMac->lim.mgmtFrameSessionId, 0); + pMac->lim.mgmtFrameSessionId = 0xff; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * lim_tx_action_frame() - Handles action frame transmission request + * @mac_ctx: Pointer to mac context + * @mb_msg: message sent from SME + * @msg_len: Message length + * @packet: network buffer for TX + * @frame: frame buffer + * + * This function processes the action frame transmission request and + * posts message to WMA. + * + * Return: NULL + */ +static void lim_tx_action_frame(tpAniSirGlobal mac_ctx, + tSirMbMsgP2p *mb_msg, uint32_t msg_len, void *packet, uint8_t *frame) +{ + uint8_t tx_flag = 0; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; + CDF_STATUS cdf_status; + uint8_t sme_session_id = 0; + uint16_t channel_freq; + + sme_session_id = mb_msg->sessionId; + channel_freq = mb_msg->channel_freq; + /* + * Use BD rate 2 for all P2P related frames. As these frames + * need to go at OFDM rates. And BD rate2 we configured at 6Mbps. + */ + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if ((SIR_MAC_MGMT_PROBE_RSP == fc->subType) || + (mb_msg->noack)) { + cdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) msg_len, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + frame, tx_flag, sme_session_id, + channel_freq); + + if (!mb_msg->noack) + lim_send_sme_rsp(mac_ctx, + eWNI_SME_ACTION_FRAME_SEND_CNF, + cdf_status, mb_msg->sessionId, 0); + mac_ctx->lim.mgmtFrameSessionId = 0xff; + } else { + mac_ctx->lim.mgmtFrameSessionId = mb_msg->sessionId; + cdf_status = + wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t) msg_len, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + frame, lim_p2p_action_cnf, tx_flag, + sme_session_id, false, + channel_freq); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGE, + FL("couldn't send action frame")); + lim_send_sme_rsp(mac_ctx, + eWNI_SME_ACTION_FRAME_SEND_CNF, + cdf_status, mb_msg->sessionId, 0); + mac_ctx->lim.mgmtFrameSessionId = 0xff; + } else { + mac_ctx->lim.mgmtFrameSessionId = mb_msg->sessionId; + lim_log(mac_ctx, LOG2, + FL("lim.actionFrameSessionId = %u"), + mac_ctx->lim.mgmtFrameSessionId); + } + } + + return; +} + +/** + * lim_send_p2p_action_frame() - Process action frame request + * @mac_ctx: Pointer to mac context + * @msg: message sent from SME + * + * This function processes the action frame request sent from the + * SME and generates the ACTION frame. + * + * Return: NULL + */ +void lim_send_p2p_action_frame(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tSirMbMsgP2p *mb_msg = (tSirMbMsgP2p *) msg->bodyptr; + uint32_t msg_len; + uint8_t *frame; + void *packet; + CDF_STATUS cdf_status; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; + uint8_t noa_len = 0; + uint8_t noa_stream[SIR_MAX_NOA_ATTR_LEN + (2 * SIR_P2P_IE_HEADER_LEN)]; + uint8_t orig_len = 0; + uint8_t session_id = 0; + uint8_t *p2p_ie = NULL; + tpPESession session_entry = NULL; + uint8_t *presence_noa_attr = NULL; + uint8_t *tmp_p2p_ie = NULL; + uint16_t remain_len = 0; + uint8_t sme_session_id = 0; +#ifdef WLAN_FEATURE_11W + tpSirMacMgmtHdr mac_hdr; + tpSirMacActionFrameHdr action_hdr; +#endif + + msg_len = mb_msg->msgLen - sizeof(tSirMbMsgP2p); + lim_log(mac_ctx, LOG1, FL("sending fc->type=%d fc->subType=%d"), + fc->type, fc->subType); + + if ((!mac_ctx->lim.gpLimRemainOnChanReq) && (0 != mb_msg->wait)) { + lim_log(mac_ctx, LOGE, + FL("RemainOnChannel is not running\n")); + lim_send_sme_rsp(mac_ctx, eWNI_SME_ACTION_FRAME_SEND_CNF, + CDF_STATUS_E_FAILURE, mb_msg->sessionId, 0); + return; + } + sme_session_id = mb_msg->sessionId; + + if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_PROBE_RSP == fc->subType)) { + /* get proper offset for Probe RSP */ + p2p_ie = limGetP2pIEPtr(mac_ctx, + (uint8_t *) mb_msg->data + + PROBE_RSP_IE_OFFSET, + msg_len - PROBE_RSP_IE_OFFSET); + while ((NULL != p2p_ie) + && (SIR_MAC_MAX_IE_LENGTH == p2p_ie[1])) { + remain_len = + msg_len - (p2p_ie - + (uint8_t *) mb_msg->data); + if (remain_len > 2) { + tmp_p2p_ie = limGetP2pIEPtr(mac_ctx, + p2p_ie + SIR_MAC_MAX_IE_LENGTH + 2, + remain_len); + } + if (tmp_p2p_ie) { + p2p_ie = tmp_p2p_ie; + tmp_p2p_ie = NULL; + } else { + break; + } + } /* end of while */ + } else if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_ACTION == fc->subType) && + (SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY == + *((uint8_t *) mb_msg->data + ACTION_OFFSET))) { + tpSirMacP2PActionFrameHdr action_hdr = + (tpSirMacP2PActionFrameHdr) ((uint8_t *) + mb_msg->data + ACTION_OFFSET); + if (cdf_mem_compare(action_hdr->Oui, SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE) && + (SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP == + action_hdr->OuiSubType)) { + + /* In case of Presence RSP response */ + p2p_ie = limGetP2pIEPtr(mac_ctx, + (uint8_t *)mb_msg->data + + ACTION_OFFSET + + sizeof(tSirMacP2PActionFrameHdr), + (msg_len - ACTION_OFFSET + - sizeof(tSirMacP2PActionFrameHdr))); + if (NULL != p2p_ie) { + /* extract the presence of NoA attribute inside + * P2P IE */ + presence_noa_attr = lim_get_ie_ptr_new(mac_ctx, + p2p_ie + SIR_P2P_IE_HEADER_LEN, + p2p_ie[1], SIR_P2P_NOA_ATTR, TWO_BYTE); + } + } + } + + if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_PROBE_RSP == fc->subType || + SIR_MAC_MGMT_ACTION == fc->subType) && p2p_ie != NULL) { + /* get NoA attribute stream P2P IE */ + noa_len = + lim_get_noa_attr_stream(mac_ctx, noa_stream, + session_entry); + /* need to append NoA attribute in P2P IE */ + if (noa_len > 0) { + orig_len = p2p_ie[1]; + /* if Presence Rsp has NoAttr */ + if (presence_noa_attr) { + uint16_t noa_len = + presence_noa_attr[1] | + (presence_noa_attr[2] << 8); + /*One byte for attribute, 2bytes for length */ + orig_len -= (noa_len + 1 + 2); + /* remove those bytes to copy */ + msg_len -= (noa_len + 1 + 2); + /* remove NoA from original Len */ + p2p_ie[1] = orig_len; + } + if ((p2p_ie[1] + (uint16_t) noa_len) > + SIR_MAC_MAX_IE_LENGTH) { + /* + * Form the new NoA Byte array in multiple + * P2P IEs + */ + noa_len = + lim_get_noa_attr_stream_in_mult_p2p_ies + (mac_ctx, noa_stream, noa_len, + ((p2p_ie[1] + (uint16_t)noa_len) + - SIR_MAC_MAX_IE_LENGTH)); + p2p_ie[1] = SIR_MAC_MAX_IE_LENGTH; + } else { + /* increment the length of P2P IE */ + p2p_ie[1] += noa_len; + } + msg_len += noa_len; + lim_log(mac_ctx, LOGE, + FL("noa_len=%d orig_len=%d p2p_ie=%p" + " msg_len=%d nBytesToCopy=%zu "), + noa_len, orig_len, p2p_ie, msg_len, + ((p2p_ie + orig_len + 2) - + (uint8_t *) mb_msg->data)); + } + } + + if ((SIR_MAC_MGMT_PROBE_RSP == fc->subType || + SIR_MAC_MGMT_ACTION == fc->subType)) + lim_set_ht_caps(mac_ctx, session_entry, + (uint8_t *) mb_msg->data + PROBE_RSP_IE_OFFSET, + msg_len - PROBE_RSP_IE_OFFSET); + + /* Ok-- try to allocate some memory: */ + cdf_status = cds_packet_alloc((uint16_t) msg_len, (void **)&frame, + (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to allocate %d bytes for a Probe Request."), + msg_len); + return; + } + /* Paranoia: */ + cdf_mem_set(frame, msg_len, 0); + + /* + * Add sequence number to action frames + * Frames are handed over in .11 format by supplicant already + */ + lim_populate_p2p_mac_header(mac_ctx, (uint8_t *) mb_msg->data); + + if ((noa_len > 0) + && (noa_len < (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN))) { + /* Add 2 bytes for length and Arribute field */ + uint32_t nBytesToCopy = ((p2p_ie + orig_len + 2) - + (uint8_t *) mb_msg->data); + cdf_mem_copy(frame, mb_msg->data, nBytesToCopy); + cdf_mem_copy((frame + nBytesToCopy), noa_stream, noa_len); + cdf_mem_copy((frame + nBytesToCopy + noa_len), + mb_msg->data + nBytesToCopy, + msg_len - nBytesToCopy - noa_len); + + } else { + cdf_mem_copy(frame, mb_msg->data, msg_len); + } + +#ifdef WLAN_FEATURE_11W + action_hdr = (tpSirMacActionFrameHdr) (frame + sizeof(tSirMacMgmtHdr)); + + /* + * Setting Protected bit for SA_QUERY Action Frame + * This has to be based on the current Connection with the + * station lim_set_protected_bit API will set the protected bit + * if PMF + */ + if ((SIR_MAC_MGMT_ACTION == fc->subType) && + (SIR_MAC_ACTION_SA_QUERY == action_hdr->category)) { + mac_hdr = (tpSirMacMgmtHdr) frame; + session_entry = pe_find_session_by_bssid(mac_ctx, + (uint8_t *) mb_msg->data + BSSID_OFFSET, + &session_id); + + /* + * Check for session corresponding to ADDR2 ss supplicant + * is filling ADDR2 with BSSID + */ + if (NULL == session_entry) { + session_entry = pe_find_session_by_bssid(mac_ctx, + (uint8_t *) mb_msg->data + ADDR2_OFFSET, + &session_id); + } + + if (NULL != session_entry) { + lim_set_protected_bit(mac_ctx, session_entry, + mac_hdr->da, mac_hdr); + } else { + lim_log(mac_ctx, LOGE, + FL("Dropping SA Query - PE Session not found")); + lim_send_sme_rsp(mac_ctx, + eWNI_SME_ACTION_FRAME_SEND_CNF, + CDF_STATUS_E_FAILURE, mb_msg->sessionId, 0); + cds_packet_free((void *)packet); + return; + } + + /* + * If wep bit is not set in MAC header then we are trying to + * send SA Query via non PMF connection. Drop the packet. + */ + if (0 == mac_hdr->fc.wep) { + lim_log(mac_ctx, LOGE, + FL("Dropping SA Query due to non PMF conne.")); + lim_send_sme_rsp(mac_ctx, + eWNI_SME_ACTION_FRAME_SEND_CNF, + CDF_STATUS_E_FAILURE, mb_msg->sessionId, 0); + cds_packet_free((void *)packet); + return; + } + } +#endif + lim_tx_action_frame(mac_ctx, mb_msg, msg_len, packet, frame); + return; +} + +void lim_abort_remain_on_chan(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id) +{ + lim_process_abort_scan_ind(pMac, sessionId, scan_id); +} + +/* Power Save Related Functions */ +tSirRetStatus __lim_process_sme_no_a_update(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpP2pPsConfig pNoA; + tpP2pPsParams pMsgNoA; + tSirMsgQ msg; + + pNoA = (tpP2pPsConfig) pMsgBuf; + + pMsgNoA = cdf_mem_malloc(sizeof(tP2pPsConfig)); + if (NULL == pMsgNoA) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during NoA Update")); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) pMsgNoA, sizeof(tP2pPsConfig), 0); + pMsgNoA->opp_ps = pNoA->opp_ps; + pMsgNoA->ctWindow = pNoA->ctWindow; + pMsgNoA->duration = pNoA->duration; + pMsgNoA->interval = pNoA->interval; + pMsgNoA->count = pNoA->count; + pMsgNoA->single_noa_duration = pNoA->single_noa_duration; + pMsgNoA->psSelection = pNoA->psSelection; + pMsgNoA->sessionId = pNoA->sessionid; + + msg.type = WMA_SET_P2P_GO_NOA_REQ; + msg.reserved = 0; + msg.bodyptr = pMsgNoA; + msg.bodyval = 0; + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGE, FL("halPostMsgApi failed")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} /*** end __limProcessSmeGoNegReq() ***/ diff --git a/core/mac/src/pe/lim/lim_process_action_frame.c b/core/mac/src/pe/lim/lim_process_action_frame.c new file mode 100644 index 0000000000..c77ae536ae --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_action_frame.c @@ -0,0 +1,2093 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_action_frame.cc contains the code + * for processing Action Frame. + * Author: Michael Lui + * Date: 05/23/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_admit_control.h" +#include "wmm_apsd.h" +#include "lim_send_messages.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif +#include "lim_session_utils.h" + +#include "wma_types.h" + + +#define BA_DEFAULT_TX_BUFFER_SIZE 64 + +/* Note: The test passes if the STAUT stops sending any frames, and no further + frames are transmitted on this channel by the station when the AP has sent + the last 6 beacons, with the channel switch information elements as seen + with the sniffer.*/ +#define SIR_CHANSW_TX_STOP_MAX_COUNT 6 +/**----------------------------------------------------------------- + \fn lim_stop_tx_and_switch_channel + \brief Stops the transmission if channel switch mode is silent and + starts the channel switch timer. + + \param pMac + \return NONE + -----------------------------------------------------------------*/ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("Session %d not active"), sessionId); + return; + } + + PELOG1(lim_log(pMac, LOG1, FL("Channel switch Mode == %d"), + psessionEntry->gLimChannelSwitch.switchMode); + ) + + if (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT + || psessionEntry->gLimChannelSwitch.switchCount <= + SIR_CHANSW_TX_STOP_MAX_COUNT) { + /* Freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_STOP_TX); + + } else { + /* Resume the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + } + + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId = sessionId; + /* change the channel immediatly only if + * the channel switch count is 0 + */ + if (psessionEntry->gLimChannelSwitch.switchCount == 0) { + lim_process_channel_switch_timeout(pMac); + return; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_activate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_activate failed")); + } + return; +} + +/**------------------------------------------------------------ + \fn lim_start_channel_switch + \brief Switches the channel if switch count == 0, otherwise + starts the timer for channel switch and stops BG scan + and heartbeat timer tempororily. + + \param pMac + \param psessionEntry + \return NONE + ------------------------------------------------------------*/ +tSirRetStatus lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + PELOG1(lim_log(pMac, LOG1, FL("Starting the channel switch"));) + + /*If channel switch is already running and it is on a different session, just return */ + /*This need to be removed for MCC */ + if ((lim_is_chan_switch_running(pMac) && + psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) || psessionEntry->csaOffloadEnable) { + lim_log(pMac, LOGW, FL("Ignoring channel switch on session %d"), + psessionEntry->peSessionId); + return eSIR_SUCCESS; + } + + /* Deactivate and change reconfigure the timeout value */ + /* lim_deactivate_and_change_timer(pMac, eLIM_CHANNEL_SWITCH_TIMER); */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed!")); + return eSIR_FAILURE; + } + + if (tx_timer_change(&pMac->lim.limTimers.gLimChannelSwitchTimer, + psessionEntry->gLimChannelSwitch.switchTimeoutValue, + 0) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_change failed ")); + return eSIR_FAILURE; + } + + /* Follow the channel switch, forget about the previous quiet. */ + /* If quiet is running, chance is there to resume tx on its timeout. */ + /* so stop timer for a safer side. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed")); + return eSIR_FAILURE; + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed")); + return eSIR_FAILURE; + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Prepare for 11h channel switch */ + lim_prepare_for11h_channel_switch(pMac, psessionEntry); + + /** Dont add any more statements here as we posted finish scan request + * to HAL, wait till we get the response + */ + return eSIR_SUCCESS; +} + +/** + * __lim_process_channel_switch_action_frame() - to process channel switch + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This routine will be called to process channel switch action frame + * + * Return: None + */ + +static void __lim_process_channel_switch_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fChannelSwitch *chnl_switch_frame; + uint16_t bcn_period; + uint32_t val, frame_len, status; + tLimChannelSwitchInfo *ch_switch_params; + struct sDot11fIEWiderBWChanSwitchAnn *wbw_chnlswitch_ie = NULL; + struct sLimWiderBWChannelSwitch *lim_wbw_chnlswitch_info = NULL; + struct sDot11fIEsec_chan_offset_ele *sec_chnl_offset = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + PELOG3(lim_log(mac_ctx, LOG3, + FL("Received Channel switch action frame"));) + if (!session->lim11hEnable) + return; + + chnl_switch_frame = cdf_mem_malloc(sizeof(*chnl_switch_frame)); + if (NULL == chnl_switch_frame) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + + /* Unpack channel switch frame */ + status = dot11f_unpack_channel_switch(mac_ctx, body_ptr, frame_len, + chnl_switch_frame); + + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to unpack and parse (0x%08x, %d bytes)"), + status, frame_len); + cdf_mem_free(chnl_switch_frame); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warning: unpack 11h-CHANSW Req(0x%08x, %d bytes)"), + status, frame_len); + } + + if (!(cdf_mem_compare((uint8_t *) &session->bssId, + (uint8_t *) &mac_hdr->sa, sizeof(tSirMacAddr)))) { + lim_log(mac_ctx, LOG1, + FL("Rcvd action frame not from our BSS, dropping...")); + cdf_mem_free(chnl_switch_frame); + return; + } + /* copy the beacon interval from session */ + val = session->beaconParams.beaconInterval; + ch_switch_params = &session->gLimChannelSwitch; + bcn_period = (uint16_t)val; + ch_switch_params->primaryChannel = + chnl_switch_frame->ChanSwitchAnn.newChannel; + ch_switch_params->switchCount = + chnl_switch_frame->ChanSwitchAnn.switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(bcn_period) * + session->gLimChannelSwitch.switchCount; + ch_switch_params->switchMode = + chnl_switch_frame->ChanSwitchAnn.switchMode; + + /* Only primary channel switch element is present */ + ch_switch_params->state = eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + if (chnl_switch_frame->WiderBWChanSwitchAnn.present + && session->vhtCapability) { + wbw_chnlswitch_ie = &chnl_switch_frame->WiderBWChanSwitchAnn; + session->gLimWiderBWChannelSwitch.newChanWidth = + wbw_chnlswitch_ie->newChanWidth; + session->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + wbw_chnlswitch_ie->newCenterChanFreq0; + session->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + wbw_chnlswitch_ie->newCenterChanFreq1; + } + lim_log(mac_ctx, LOG3, + FL("Rcv Chnl Swtch Frame: Timeout in %d ticks"), + session->gLimChannelSwitch.switchTimeoutValue); + if (session->htSupportedChannelWidthSet) { + sec_chnl_offset = &chnl_switch_frame->sec_chan_offset_ele; + if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + + } + if (session->vhtCapability && + chnl_switch_frame->WiderBWChanSwitchAnn.present) { + wbw_chnlswitch_ie = + &chnl_switch_frame->WiderBWChanSwitchAnn; + ch_switch_params->ch_width = + wbw_chnlswitch_ie->newChanWidth + 1; + lim_wbw_chnlswitch_info = + &session->gLimWiderBWChannelSwitch; + ch_switch_params->ch_center_freq_seg0 = + lim_wbw_chnlswitch_info->newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + lim_wbw_chnlswitch_info->newCenterChanFreq1; + + } + } + + if (CH_WIDTH_20MHZ == ch_switch_params->ch_width) { + session->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + } + + if (eSIR_SUCCESS != lim_start_channel_switch(mac_ctx, session)) + lim_log(mac_ctx, LOG1, + FL("Could not start channel switch")); + + cdf_mem_free(chnl_switch_frame); + return; +} + +#ifdef WLAN_FEATURE_11AC +/** + * __lim_process_operating_mode_action_frame() - To process op mode frames + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine is called to process operating mode action frames + * + * Return: None + */ +static void __lim_process_operating_mode_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fOperatingMode *operating_mode_frm; + uint32_t frame_len; + uint32_t status; + tpDphHashNode sta_ptr; + uint16_t aid; + uint8_t oper_mode; + uint8_t cb_mode; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG1, + FL("Received Operating Mode action frame")); + if (RF_CHAN_14 >= session->currentOperChannel) + cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; + else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* Do not update the channel bonding mode if channel bonding + * mode is disabled in INI. + */ + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) { + lim_log(mac_ctx, LOGW, FL("channel bonding disabled")); + return; + } + operating_mode_frm = cdf_mem_malloc(sizeof(*operating_mode_frm)); + if (NULL == operating_mode_frm) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + /* Unpack channel switch frame */ + status = dot11f_unpack_operating_mode(mac_ctx, body_ptr, frame_len, + operating_mode_frm); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to unpack and parse (0x%08x, %d bytes)"), + status, frame_len); + cdf_mem_free(operating_mode_frm); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warnings while unpacking (0x%08x, %d bytes):"), + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (sta_ptr->htSupportedChannelWidthSet) { + if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ < + sta_ptr->vhtSupportedChannelWidthSet) + oper_mode = eHT_CHANNEL_WIDTH_160MHZ; + else + oper_mode = sta_ptr->vhtSupportedChannelWidthSet + 1; + } else { + oper_mode = eHT_CHANNEL_WIDTH_20MHZ; + } + if (oper_mode != operating_mode_frm->OperatingMode.chanWidth) { + lim_log(mac_ctx, LOGE, + FL(" received Chanwidth %d, staIdx = %d"), + (operating_mode_frm->OperatingMode.chanWidth), + sta_ptr->staIndex); + + lim_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + mac_hdr->sa[0], mac_hdr->sa[1], mac_hdr->sa[2], + mac_hdr->sa[3], mac_hdr->sa[4], mac_hdr->sa[5]); + + if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_160MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_80MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + } + lim_check_vht_op_mode_change(mac_ctx, session, + operating_mode_frm->OperatingMode.chanWidth, + sta_ptr->staIndex, mac_hdr->sa); + } + + if (sta_ptr->vhtSupportedRxNss != + (operating_mode_frm->OperatingMode.rxNSS + 1)) { + sta_ptr->vhtSupportedRxNss = + operating_mode_frm->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session, sta_ptr->vhtSupportedRxNss, + sta_ptr->staIndex, mac_hdr->sa); + } + cdf_mem_free(operating_mode_frm); + return; +} + +/** + * __lim_process_gid_management_action_frame() - To process group-id mgmt frames + * @mac_ctx: Pointer to mac context + * @rx_pkt_info: Rx packet info + * @session: pointer to session + * + * This routine will be called to process group id management frames + * + * Return: none + */ +static void __lim_process_gid_management_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + + uint8_t *body_ptr; + uint16_t aid; + uint32_t frame_len, status, membership = 0, usr_position = 0; + uint32_t *mem_lower, *mem_upper, *mem_cur; + tpSirMacMgmtHdr mac_hdr; + tDot11fVHTGidManagementActionFrame *gid_mgmt_frame; + tpDphHashNode sta_ptr; + struct sDot11fFfVhtMembershipStatusArray *vht_member_status = NULL; + struct sDot11fFfVhtUserPositionArray *vht_user_position = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG3, FL("Received GID Management action frame")); + gid_mgmt_frame = cdf_mem_malloc(sizeof(*gid_mgmt_frame)); + if (NULL == gid_mgmt_frame) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + + /* Unpack Gid Mangement Action frame */ + status = dot11f_unpack_vht_gid_management_action_frame(mac_ctx, + body_ptr, frame_len, gid_mgmt_frame); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Fail to parse an Grp id frame (0x%08x, %d bytes):"), + status, frame_len); + cdf_mem_free(gid_mgmt_frame); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warnings while unpacking Grp id frm (0x%08x, %d bytes):"), + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + lim_log(mac_ctx, LOGE, + FL("received Gid Management Action Frame , staIdx = %d"), + sta_ptr->staIndex); + + lim_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + mac_hdr->sa[0], mac_hdr->sa[1], mac_hdr->sa[2], + mac_hdr->sa[3], mac_hdr->sa[4], mac_hdr->sa[5]); + vht_member_status = &gid_mgmt_frame->VhtMembershipStatusArray; + mem_lower = (uint32_t *) vht_member_status->membershipStatusArray; + mem_upper = (uint32_t *) &vht_member_status->membershipStatusArray[4]; + + if (*mem_lower && *mem_upper) { + lim_log(mac_ctx, LOGE, + FL("rcved frame with mult group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + if (*mem_lower) { + mem_cur = mem_lower; + } else if (*mem_upper) { + mem_cur = mem_upper; + membership += sizeof(uint32_t); + } else { + lim_log(mac_ctx, LOGE, + FL("rcved Gid frame with no group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + while (!(*mem_cur & 1)) { + *mem_cur >>= 1; + ++membership; + } + if (*mem_cur) { + lim_log(mac_ctx, LOGE, + FL("rcved frame with mult group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + + /*Just read the last two bits */ + vht_user_position = &gid_mgmt_frame->VhtUserPositionArray; + usr_position = vht_user_position->userPositionArray[membership] & 0x3; + lim_check_membership_user_position(mac_ctx, session, membership, + usr_position, sta_ptr->staIndex); +out: + cdf_mem_free(gid_mgmt_frame); + return; +} + +#endif + +static void +__lim_process_add_ts_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ +} + +/** + * __lim_process_add_ts_rsp() - To process add ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle add ts response frame + * + * Return: none + */ +static void __lim_process_add_ts_rsp(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tSirAddtsRspInfo addts; + tSirRetStatus retval; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint16_t aid; + uint32_t frameLen; + uint8_t *body_ptr; + tpLimTspecInfo tspec_info; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + uint8_t rsp_reqd = 1; + uint32_t cfg_len; + tSirMacAddr peer_macaddr; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frameLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOGW, "Recv AddTs Response"); + if (LIM_IS_AP_ROLE(session) || + LIM_IS_BT_AMP_AP_ROLE(session)) { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp recvd at AP: ignoring")); + return; + } + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (sta_ptr == NULL) { + lim_log(mac_ctx, LOGE, + FL("Station context not found - ignoring AddTsRsp")); + return; + } + + retval = sir_convert_addts_rsp2_struct(mac_ctx, body_ptr, + frameLen, &addts); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp parsing failed (error %d)"), retval); + return; + } + /* + * don't have to check for qos/wme capabilities since we wouldn't have + * this flag set otherwise + */ + if (!mac_ctx->lim.gLimAddtsSent) { + /* we never sent an addts request! */ + lim_log(mac_ctx, LOGW, + FL("rx AddTsRsp but no req was ever sent-ignoring")); + return; + } + + if (mac_ctx->lim.gLimAddtsReq.req.dialogToken != addts.dialogToken) { + lim_log(mac_ctx, LOGW, + FL("token mismatch (got %d, exp %d) - ignoring"), + addts.dialogToken, + mac_ctx->lim.gLimAddtsReq.req.dialogToken); + return; + } + + /* + * for successful addts reponse, try to add the classifier. + * if this fails for any reason, we should send a delts request to the + * ap for now, its ok not to send a delts since we are going to add + * support for multiple tclas soon and until then we won't send any + * addts requests with multiple tclas elements anyway. + * In case of addClassifier failure, we just let the addts timer run out + */ + if (((addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_HCCA) || + (addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) && + (addts.status == eSIR_MAC_SUCCESS_STATUS)) { + /* add the classifier - this should always succeed */ + if (addts.numTclas > 1) { + /* currently no support for multiple tclas elements */ + lim_log(mac_ctx, LOGE, + FL("Sta %d: Too many Tclas (%d), 1 supported"), + aid, addts.numTclas); + return; + } else if (addts.numTclas == 1) { + lim_log(mac_ctx, LOGW, + FL("Response from STA %d: tsid %d, UP %d, OK!"), + aid, addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio); + } + } + lim_log(mac_ctx, LOGW, FL("Recv AddTsRsp: tsid %d, UP %d, status %d "), + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + + /* deactivate the response timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ADDTS_RSP_TIMER); + + if (addts.status != eSIR_MAC_SUCCESS_STATUS) { + lim_log(mac_ctx, LOGW, + FL("Recv AddTsRsp: tsid %d, UP %d, status %d "), + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + lim_send_sme_addts_rsp(mac_ctx, true, addts.status, session, + addts.tspec, session->smeSessionId, + session->transactionId); + + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + + return; + } +#ifdef FEATURE_WLAN_ESE + if (addts.tsmPresent) { + lim_log(mac_ctx, LOGW, "TSM IE Present"); + session->eseContext.tsm.tid = + addts.tspec.tsinfo.traffic.userPrio; + cdf_mem_copy(&session->eseContext.tsm.tsmInfo, + &addts.tsmIE, sizeof(tSirMacESETSMIE)); +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_tsm_ie_ind(mac_ctx, session, addts.tsmIE.tsid, + addts.tsmIE.state, + addts.tsmIE.msmt_interval); +#else + limActivateTSMStatsTimer(mac_ctx, session); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + } +#endif + /* + * Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (addts.tspec.tsinfo.traffic.psb == 1) + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + SET_UAPSD_MASK); + else + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + CLEAR_UAPSD_MASK); + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + ac = upToAc(addts.tspec.tsinfo.traffic.userPrio); + if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId); + else + lim_log(mac_ctx, LOGE, FL("Self entry missing in Hash Table ")); + sir_copy_mac_addr(peer_macaddr, session->bssId); + /* if schedule is not present then add TSPEC with svcInterval as 0. */ + if (!addts.schedulePresent) + addts.schedule.svcInterval = 0; + if (eSIR_SUCCESS != + lim_tspec_add(mac_ctx, sta_ptr->staAddr, sta_ptr->assocId, + &addts.tspec, addts.schedule.svcInterval, &tspec_info)) { + lim_log(mac_ctx, LOGE, + FL("Adding entry in lim Tspec Table failed ")); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, rsp_reqd, + &addts.tspec.tsinfo, + &addts.tspec, session); + mac_ctx->lim.gLimAddtsSent = false; + return; + /* + * Error handling. send the response with error status. + * need to send DelTS to tear down the TSPEC status. + */ + } + if ((addts.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA) || + ((upToAc(addts.tspec.tsinfo.traffic.userPrio) < MAX_NUM_AC))) { +#ifdef FEATURE_WLAN_ESE + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, tspec_info->idx, + addts.tspec, session->peSessionId, + addts.tsmIE.msmt_interval); +#else + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, tspec_info->idx, + addts.tspec, session->peSessionId); +#endif + if (eSIR_SUCCESS != retval) { + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, + &addts.tspec.tsinfo, NULL, &tspec_info->idx); + + /* Send DELTS action frame to AP */ + cfg_len = sizeof(tSirMacAddr); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, + rsp_reqd, &addts.tspec.tsinfo, + &addts.tspec, session); + lim_send_sme_addts_rsp(mac_ctx, true, retval, + session, addts.tspec, + session->smeSessionId, + session->transactionId); + mac_ctx->lim.gLimAddtsSent = false; + return; + } + lim_log(mac_ctx, LOGW, + FL("AddTsRsp received successfully(UP %d, TSID %d)"), + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + } else { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp received successfully(UP %d, TSID %d)"), + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + lim_log(mac_ctx, LOGW, + FL("no ACM: Bypass sending WMA_ADD_TS_REQ to HAL ")); + /* + * Use the smesessionId and smetransactionId from the PE + * session context + */ + lim_send_sme_addts_rsp(mac_ctx, true, eSIR_SME_SUCCESS, + session, addts.tspec, session->smeSessionId, + session->transactionId); + } + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + return; +} + +/** + * __lim_process_del_ts_req() - To process del ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle del ts request frame + * + * Return: none + */ +static void __lim_process_del_ts_req(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tSirRetStatus retval; + tSirDeltsReqInfo delts; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint32_t frame_len; + uint16_t aid; + uint8_t *body_ptr; + uint8_t ts_status; + tSirMacTSInfo *tsinfo; + uint8_t tspec_idx; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (sta_ptr == NULL) { + lim_log(mac_ctx, LOGE, + FL("Station context not found - ignoring DelTs")); + return; + } + /* parse the delts request */ + retval = sir_convert_delts_req2_struct(mac_ctx, body_ptr, + frame_len, &delts); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("DelTs parsing failed (error %d)"), retval); + return; + } + + if (delts.wmeTspecPresent) { + if ((!session->limWmeEnabled) || (!sta_ptr->wmeEnabled)) { + lim_log(mac_ctx, LOGW, + FL("Ignore delts req: wme not enabled")); + return; + } + lim_log(mac_ctx, LOG2, FL("WME Delts received")); + } else if ((session->limQosEnabled) && sta_ptr->lleEnabled) { + lim_log(mac_ctx, LOG2, FL("11e QoS Delts received")); + } else if ((session->limWsmEnabled) && sta_ptr->wsmEnabled) { + lim_log(mac_ctx, LOG2, FL("WSM Delts received")); + } else { + lim_log(mac_ctx, LOGW, + FL("Ignoring delts request: qos not enabled/capable")); + return; + } + + tsinfo = delts.wmeTspecPresent ? &delts.tspec.tsinfo : &delts.tsinfo; + + /* if no Admit Control, ignore the request */ + if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA)) { + + if (upToAc(tsinfo->traffic.userPrio) >= MAX_NUM_AC) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d has no AC - ignoring req"), + tsinfo->traffic.userPrio); + return; + } + } + + if (!LIM_IS_AP_ROLE(session) && + !LIM_IS_BT_AMP_AP_ROLE(session)) + lim_send_sme_delts_ind(mac_ctx, &delts, aid, session); + + /* try to delete the TS */ + if (eSIR_SUCCESS != + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, tsinfo, + &ts_status, &tspec_idx)) { + lim_log(mac_ctx, LOGW, FL("Unable to Delete TS")); + return; + } else if (!((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH))){ + /* send message to HAL to delete TS */ + if (eSIR_SUCCESS != lim_send_hal_msg_del_ts(mac_ctx, + sta_ptr->staIndex, tspec_idx, + delts, session->peSessionId, + session->bssId)) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d failed ignoring request"), + tsinfo->traffic.userPrio); + return; + } + } + /* + * We successfully deleted the TSPEC. Update the dynamic UAPSD Mask. + * The AC for this TSPEC is no longer trigger enabled if this Tspec + * was set-up in uplink direction only. + * The AC for this TSPEC is no longer delivery enabled if this Tspec + * was set-up in downlink direction only. + * The AC for this TSPEC is no longer triiger enabled and delivery + * enabled if this Tspec was a bidirectional TSPEC. + */ + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + tsinfo, CLEAR_UAPSD_MASK); + /* + * We're deleting the TSPEC. + * The AC for this TSPEC is no longer admitted in uplink/downlink + * direction if this TSPEC was set-up in uplink/downlink direction only. + * The AC for this TSPEC is no longer admitted in both uplink and + * downlink directions if this TSPEC was a bi-directional TSPEC. + * If ACM is set for this AC and this AC is admitted only in downlink + * direction, PE needs to downgrade the EDCA parameter + * (for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(tsinfo->traffic.userPrio); + if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId); + else + lim_log(mac_ctx, LOGE, FL("Self entry missing in Hash Table ")); + + lim_log(mac_ctx, LOG1, FL("DeleteTS succeeded")); +#ifdef FEATURE_WLAN_ESE +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_tsm_ie_ind(mac_ctx, session, 0, 0, 0); +#else + lim_deactivate_and_change_timer(mac_ctx, eLIM_TSM_TIMER); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ +#endif +} + +/** + * __lim_process_qos_map_configure_frame() - to process QoS map configure frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine will called to process qos map configure frame + * + * Return: none + */ +static void __lim_process_qos_map_configure_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + tSirRetStatus retval; + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + retval = sir_convert_qos_map_configure_frame2_struct(mac_ctx, + body_ptr, frame_len, &session->QosMapSet); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("QosMapConfigure frame parsing fail(error %d)"), + retval); + return; + } + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(rx_pkt_info), session, 0); +} + +#ifdef ANI_SUPPORT_11H +static void +__lim_process_basic_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, + pMeasReqFrame, + peerMacAddr, psessionEntry) != eSIR_SUCCESS) + { + PELOGE(lim_log + (pMac, LOGE, FL("fail to send Basic Meas report ")); + ) + return; + } +} +static void +__lim_process_cca_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, + pMeasReqFrame, + peerMacAddr, psessionEntry) != eSIR_SUCCESS) + { + PELOGE(lim_log(pMac, LOGE, FL("fail to send CCA Meas report "));) + return; + } +} +static void +__lim_process_rpi_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, + pMeasReqFrame, + peerMacAddr, psessionEntry) != eSIR_SUCCESS) + { + PELOGE(lim_log(pMac, LOGE, FL("fail to send RPI Meas report "));) + return; + } +} +static void +__lim_process_measurement_request_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacMeasReqActionFrame pMeasReqFrame; + uint32_t frameLen; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pMeasReqFrame = cdf_mem_malloc(sizeof(tSirMacMeasReqActionFrame)); + if (NULL == pMeasReqFrame) { + lim_log(pMac, LOGE, + FL + ("limProcessMeasurementRequestFrame: AllocateMemory failed ")); + return; + } + + if (sir_convert_meas_req_frame2_struct(pMac, pBody, pMeasReqFrame, frameLen) + != eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, + FL("Rcv invalid Measurement Request Action Frame ")); + ) + return; + } + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + __lim_process_basic_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + __lim_process_cca_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + __lim_process_rpi_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + default: + PELOG1(lim_log(pMac, LOG1, FL("Unknown Measurement Type %d "), + pMeasReqFrame->measReqIE.measType); + ) + break; + } +} /*** end limProcessMeasurementRequestFrame ***/ +static void +__lim_process_tpc_request_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacTpcReqActionFrame pTpcReqFrame; + uint32_t frameLen; + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + PELOG1(lim_log + (pMac, LOG1, + FL("****LIM: Processing TPC Request from peer ****")); + ) + pTpcReqFrame = cdf_mem_malloc(sizeof(tSirMacTpcReqActionFrame)); + if (NULL == pTpcReqFrame) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory failed "));) + return; + } + if (sir_convert_tpc_req_frame2_struct(pMac, pBody, pTpcReqFrame, frameLen) != + eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, FL("Rcv invalid TPC Req Action Frame ")); + ) + return; + } + if (lim_send_tpc_report_frame(pMac, + pTpcReqFrame, + pHdr->sa, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("fail to send TPC Report Frame. ")); + ) + return; + } +} +#endif + +static void +__lim_process_sm_power_save_update(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + + tpSirMacMgmtHdr pHdr; + tDot11fSMPowerSave frmSMPower; + tSirMacHTMIMOPowerSaveState state; + tpDphHashNode pSta; + uint16_t aid; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pSta = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL + ("STA context not found - ignoring UpdateSM PSave Mode from ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_sm_power_save(pMac, pBody, frameLen, &frmSMPower); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Update SM Power (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a SMPower Save update (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + } + + lim_log(pMac, LOGW, + FL("Received SM Power save Mode update Frame with PS_Enable:%d" + "PS Mode: %d"), frmSMPower.SMPowerModeSet.PowerSave_En, + frmSMPower.SMPowerModeSet.Mode); + + /** Update in the DPH Table about the Update in the SM Power Save mode*/ + if (frmSMPower.SMPowerModeSet.PowerSave_En + && frmSMPower.SMPowerModeSet.Mode) + state = eSIR_HT_MIMO_PS_DYNAMIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_STATIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En == 0) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_NO_LIMIT; + else { + PELOGW(lim_log + (pMac, LOGW, + FL + ("Received SM Power save Mode update Frame with invalid mode")); + ) + return; + } + + if (state == pSta->htMIMOPSState) { + PELOGE(lim_log + (pMac, LOGE, + FL("The PEER is already set in the same mode")); + ) + return; + } + + /** Update in the HAL Station Table for the Update of the Protection Mode */ + pSta->htMIMOPSState = state; + lim_post_sm_state_update(pMac, pSta->staIndex, pSta->htMIMOPSState, + pSta->staAddr, psessionEntry->smeSessionId); +} + +#if defined WLAN_FEATURE_VOWIFI + +static void +__lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fRadioMeasurementRequest frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (psessionEntry == NULL) { + return; + } + + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *)pHdr, + frameLen + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pRxPacketInfo), psessionEntry, 0); + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_radio_measurement_request(pMac, pBody, frameLen, &frm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + } + /* Call rrm function to handle the request. */ + + rrm_process_radio_measurement_request(pMac, pHdr->sa, &frm, psessionEntry); +} + +static void +__lim_process_link_measurement_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fLinkMeasurementRequest frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (psessionEntry == NULL) { + return; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_link_measurement_request(pMac, pBody, frameLen, &frm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Link Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Link Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + } + /* Call rrm function to handle the request. */ + + rrm_process_link_measurement_request(pMac, pRxPacketInfo, &frm, + psessionEntry); + +} + +static void +__lim_process_neighbor_report(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fNeighborReportResponse *pFrm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pFrm = cdf_mem_malloc(sizeof(tDot11fNeighborReportResponse)); + if (NULL == pFrm) { + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory in __lim_process_neighbor_report")); + return; + } + + if (psessionEntry == NULL) { + cdf_mem_free(pFrm); + return; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_neighbor_report_response(pMac, pBody, frameLen, pFrm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Neighbor report response (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + cdf_mem_free(pFrm); + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Neighbor report response (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + } + /* Call rrm function to handle the request. */ + rrm_process_neighbor_report_response(pMac, pFrm, psessionEntry); + + cdf_mem_free(pFrm); +} + +#endif + +#ifdef WLAN_FEATURE_11W +/** + * limProcessSAQueryRequestActionFrame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query request Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * + * @return None + */ +static void __lim_process_sa_query_request_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + uint8_t transId[2]; + + /* Prima --- Below Macro not available in prima + pHdr = SIR_MAC_BD_TO_MPDUHEADER(pBd); + pBody = SIR_MAC_BD_TO_MPDUDATA(pBd); */ + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + /* If this is an unprotected SA Query Request, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + /*Extract 11w trsansId from SA query request action frame + In SA query response action frame we will send same transId + In SA query request action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + cdf_mem_copy(&transId[0], &pBody[2], 2); + + /* Send 11w SA query response action frame */ + if (lim_send_sa_query_response_frame(pMac, + transId, + pHdr->sa, + psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("fail to send SA query response action frame.")); + ) + return; + } +} + +/** + * __lim_process_sa_query_response_action_frame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query response Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * @return None + */ +static void __lim_process_sa_query_response_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + uint8_t *pBody; + tpDphHashNode pSta; + uint16_t aid; + uint16_t transId; + uint8_t retryNum; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + ("SA Query Response received...")); + + /* When a station, supplicant handles SA Query Response. + * Forward to SME to HDD to wpa_supplicant. + */ + if (LIM_IS_STA_ROLE(psessionEntry)) { + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *) pHdr, + frameLen + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pRxPacketInfo), + psessionEntry, 0); + return; + } + + /* If this is an unprotected SA Query Response, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + pSta = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pSta) + return; + + lim_log(pMac, LOG1, + FL("SA Query Response source addr - %0x:%0x:%0x:%0x:%0x:%0x"), + pHdr->sa[0], pHdr->sa[1], pHdr->sa[2], pHdr->sa[3], + pHdr->sa[4], pHdr->sa[5]); + lim_log(pMac, LOG1, + FL("SA Query state for station - %d"), pSta->pmfSaQueryState); + + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Extract 11w trsansId from SA query reponse action frame + In SA query response action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + cdf_mem_copy(&transId, &pBody[2], 2); + + /* If SA Query is in progress with the station and the station + responds then the association request that triggered the SA + query is from a rogue station, just go back to initial state. */ + for (retryNum = 0; retryNum <= pSta->pmfSaQueryRetryCount; retryNum++) + if (transId == pSta->pmfSaQueryStartTransId + retryNum) { + lim_log(pMac, LOG1, + FL + ("Found matching SA Query Request - transaction ID %d"), + transId); + tx_timer_deactivate(&pSta->pmfSaQueryTimer); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * lim_drop_unprotected_action_frame + * + ***FUNCTION: + * This function checks if an Action frame should be dropped since it is + * a Robust Managment Frame, it is unprotected, and it is received on a + * connection where PMF is enabled. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Global MAC structure + * @param psessionEntry - PE session entry + * @param pHdr - Frame header + * @param category - Action frame category + * @return true if frame should be dropped + */ + +static bool +lim_drop_unprotected_action_frame(tpAniSirGlobal pMac, tpPESession psessionEntry, + tpSirMacMgmtHdr pHdr, uint8_t category) +{ + uint16_t aid; + tpDphHashNode pStaDs; + bool rmfConnection = false; + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) + if (pStaDs->rmfEnabled) + rmfConnection = true; + } else if (psessionEntry->limRmfEnabled) + rmfConnection = true; + + if (rmfConnection && (pHdr->fc.wep == 0)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Dropping unprotected Action category %d frame " + "since RMF is enabled."), category); + ) + return true; + } else + return false; +} +#endif + +/** + * lim_process_action_frame() - to process action frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This function is called by limProcessMessageQueue() upon + * Action frame reception. + * + * Return: none + */ + +void lim_process_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + uint8_t *body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) body_ptr; +#ifdef WLAN_FEATURE_11W + tpSirMacMgmtHdr mac_hdr_11w = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#endif + tpSirMacMgmtHdr mac_hdr = NULL; + int8_t rssi; + uint32_t frame_len; + tpSirMacVendorSpecificFrameHdr vendor_specific; + uint8_t oui[] = { 0x00, 0x00, 0xf0 }; + tpSirMacVendorSpecificPublicActionFrameHdr pub_action; + uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x09 }; + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + switch (action_hdr->category) { + case SIR_MAC_ACTION_QOS_MGMT: +#ifdef WLAN_FEATURE_11W + if (lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + break; +#endif + if ((session->limQosEnabled) || + (action_hdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE)) { + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Qos action %d not handled"), + action_hdr->actionID); + break; + } + break; + } + break; + + case SIR_MAC_ACTION_SPECTRUM_MGMT: +#ifdef WLAN_FEATURE_11W + if (lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + break; +#endif + switch (action_hdr->actionID) { +#ifdef ANI_SUPPORT_11H + case SIR_MAC_ACTION_MEASURE_REQUEST_ID: + if (session->lim11hEnable) + __lim_process_measurement_request_frame(mac_ctx, + rx_pkt_info, + session); + break; + case SIR_MAC_ACTION_TPC_REQUEST_ID: + if ((LIM_IS_STA_ROLE(session) || + LIM_IS_AP_ROLE(session)) && + session->lim11hEnable) + __lim_process_tpc_request_frame(mac_ctx, + rx_pkt_info, session); + break; +#endif + case SIR_MAC_ACTION_CHANNEL_SWITCH_ID: + if (LIM_IS_STA_ROLE(session)) + __lim_process_channel_switch_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Spectrum mgmt action id %d not handled"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_WME: + if (!session->limWmeEnabled) { + lim_log(mac_ctx, LOGW, + FL("WME mode disabled - dropping frame %d"), + action_hdr->actionID); + break; + } + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, session); + break; + + default: + lim_log(mac_ctx, LOGE, + FL("WME action %d not handled"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_HT: + /** Type of HT Action to be performed*/ + switch (action_hdr->actionID) { + case SIR_MAC_SM_POWER_SAVE: + if (LIM_IS_AP_ROLE(session)) + __lim_process_sm_power_save_update(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Action ID %d not handled in HT category"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_WNM: +#ifdef WLAN_FEATURE_11W + if ((session->limRmfEnabled) && (mac_hdr_11w->fc.wep == 0)) { + lim_log(mac_ctx, LOGE, + FL("Dropping unprot action %d frm (PMF on)"), + action_hdr->category); + break; + } +#endif + lim_log(mac_ctx, LOG1, + FL("WNM Action category %d action %d."), + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_WNM_BSS_TM_QUERY: + case SIR_MAC_WNM_BSS_TM_REQUEST: + case SIR_MAC_WNM_BSS_TM_RESPONSE: + case SIR_MAC_WNM_NOTIF_REQUEST: + case SIR_MAC_WNM_NOTIF_RESPONSE: + rssi = WMA_GET_RX_RSSI_DB(rx_pkt_info); + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + /* Forward to the SME to HDD to wpa_supplicant */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, rssi); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Action ID %d not handled in WNM category"), + action_hdr->actionID); + break; + } + break; + +#if defined WLAN_FEATURE_VOWIFI + case SIR_MAC_ACTION_RRM: +#ifdef WLAN_FEATURE_11W + if (lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + break; +#endif + if (mac_ctx->rrm.rrmPEContext.rrmEnable) { + switch (action_hdr->actionID) { + case SIR_MAC_RRM_RADIO_MEASURE_REQ: + __lim_process_radio_measure_request(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_RRM_LINK_MEASUREMENT_REQ: + __lim_process_link_measurement_req(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_RRM_NEIGHBOR_RPT: + __lim_process_neighbor_report(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Action ID %d not handled in RRM"), + action_hdr->actionID); + break; + + } + } else { + /* Else we will just ignore the RRM messages. */ + lim_log(mac_ctx, LOGE, + FL("RRM frm ignored, it is disabled in cfg")); + } + break; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: + vendor_specific = (tpSirMacVendorSpecificFrameHdr) action_hdr; + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + /* Check if it is a vendor specific action frame. */ + if (LIM_IS_STA_ROLE(session) && + (true == cdf_mem_compare(session->selfMacAddr, + &mac_hdr->da[0], sizeof(tSirMacAddr))) + && IS_WES_MODE_ENABLED(mac_ctx) + && cdf_mem_compare(vendor_specific->Oui, oui, 3)) { + lim_log(mac_ctx, LOGW, + FL("Rcvd Vendor specific frame, OUI %x %x %x"), + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2]); + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, 0); + } else { + lim_log(mac_ctx, LOGE, + FL("Dropping the vendor specific action frame" + "beacause of (WES Mode not enabled " + "(WESMODE = %d) or OUI mismatch " + "(%02x %02x %02x) or not received with" + "SelfSta address) system role = %d"), + IS_WES_MODE_ENABLED(mac_ctx), + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2], + GET_LIM_SYSTEM_ROLE(session)); + } + break; +#endif /* WLAN_FEATURE_VOWIFI_11R || FEATURE_WLAN_ESE || + FEATURE_WLAN_LFR */ + case SIR_MAC_ACTION_PUBLIC_USAGE: + switch (action_hdr->actionID) { + case SIR_MAC_ACTION_VENDOR_SPECIFIC: + pub_action = + (tpSirMacVendorSpecificPublicActionFrameHdr) + action_hdr; + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + /* Check if it is a P2P public action frame. */ + if (cdf_mem_compare(pub_action->Oui, p2p_oui, 4)) { + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, 0); + } else { + lim_log(mac_ctx, LOGE, + FL("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"), + pub_action->Oui[0], pub_action->Oui[1], + pub_action->Oui[2], pub_action->Oui[3]); + } + break; + + case SIR_MAC_ACTION_2040_BSS_COEXISTENCE: + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, 0); + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_MAC_TDLS_DIS_RSP: + mac_hdr = NULL; + frame_len = 0; + rssi = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + rssi = WMA_GET_RX_RSSI_DB(rx_pkt_info); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + ("Public Action TDLS Discovery RSP ..")); + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, rssi); + break; +#endif + + default: + lim_log(mac_ctx, LOGE, + FL("Unhandled public action frame -- %x "), + action_hdr->actionID); + break; + } + break; + +#ifdef WLAN_FEATURE_11W + case SIR_MAC_ACTION_SA_QUERY: + lim_log(mac_ctx, LOG1, + FL("SA Query Action category %d action %d."), + action_hdr->category, action_hdr->actionID); + if (lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + break; + switch (action_hdr->actionID) { + case SIR_MAC_SA_QUERY_REQ: + /**11w SA query request action frame received**/ + /* Respond directly to the incoming request in LIM */ + __lim_process_sa_query_request_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_SA_QUERY_RSP: + /**11w SA query response action frame received**/ + /* Handle based on the current SA Query state */ + __lim_process_sa_query_response_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + break; + } + break; +#endif +#ifdef WLAN_FEATURE_11AC + case SIR_MAC_ACTION_VHT: + if (!session->vhtCapability) + break; + switch (action_hdr->actionID) { + case SIR_MAC_VHT_OPMODE_NOTIFICATION: + __lim_process_operating_mode_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case SIR_MAC_VHT_GID_NOTIFICATION: + /* Only if ini supports it */ + if (session->enableVhtGid) + __lim_process_gid_management_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + break; + } + break; +#endif + default: + lim_log(mac_ctx, LOGE, + FL("Action category %d not handled"), + action_hdr->category); + break; + } +} + +/** + * lim_process_action_frame_no_session + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Action frame reception and no session. + * Currently only public action frames can be received from + * a non-associated station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pBd - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd) +{ + uint8_t *pBody = WMA_GET_RX_MPDU_DATA(pBd); + tpSirMacVendorSpecificPublicActionFrameHdr pActionHdr = + (tpSirMacVendorSpecificPublicActionFrameHdr) pBody; + + lim_log(pMac, LOG1, "Received a Action frame -- no session"); + + switch (pActionHdr->category) { + case SIR_MAC_ACTION_PUBLIC_USAGE: + switch (pActionHdr->actionID) { + case SIR_MAC_ACTION_VENDOR_SPECIFIC: + { + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + uint8_t P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 }; + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + /* Check if it is a P2P public action frame. */ + if (cdf_mem_compare(pActionHdr->Oui, P2POui, 4)) { + /* Forward to the SME to HDD to wpa_supplicant */ + /* type is ACTION */ + lim_send_sme_mgmt_frame_ind(pMac, + pHdr->fc.subType, + (uint8_t *) pHdr, + frameLen + + sizeof + (tSirMacMgmtHdr), + 0, + WMA_GET_RX_CH + (pBd), NULL, 0); + } else { + lim_log(pMac, LOGE, + FL + ("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"), + pActionHdr->Oui[0], + pActionHdr->Oui[1], + pActionHdr->Oui[2], + pActionHdr->Oui[3]); + } + } + break; + default: + PELOGE(lim_log + (pMac, LOGE, + FL("Unhandled public action frame -- %x "), + pActionHdr->actionID); + ) + break; + } + break; + default: + PELOGE(lim_log + (pMac, LOG1, + FL("Unhandled action frame without session -- %x "), + pActionHdr->category); + ) + break; + + } +} diff --git a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c new file mode 100644 index 0000000000..1972461f03 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -0,0 +1,1921 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_assoc_req_frame.cc contains the code + * for processing Re/Association Request Frame. + * Author: Chandra Modumudi + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_admit_control.h" +#include "cds_packet.h" +#include "lim_session_utils.h" + +#include "cdf_types.h" +#include "cds_utils.h" + +/** + * lim_convert_supported_channels - Parses channel support IE + * + * @mac_ctx - A pointer to Global MAC structure + * @assoc_ind - A pointer to SME ASSOC/REASSOC IND + * @assoc_req - A pointer to ASSOC/REASSOC Request frame + * + * This function is called by lim_process_assoc_req_frame() to + * parse the channel support IE in the Assoc/Reassoc Request + * frame, and send relevant information in the SME_ASSOC_IND + * + * return None + */ +static void +lim_convert_supported_channels(tpAniSirGlobal mac_ctx, + tpLimMlmAssocInd assoc_ind, tSirAssocReq *assoc_req) +{ + uint16_t i, j, index = 0; + uint8_t first_chn_no; + uint8_t chn_count; + uint8_t next_chn_no; + uint8_t channel_offset = 0; + + if (assoc_req->supportedChannels.length >= + SIR_MAX_SUPPORTED_CHANNEL_LIST) { + lim_log(mac_ctx, LOG1, + FL("Number of supported channels:%d is more than MAX"), + assoc_req->supportedChannels.length); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + + for (i = 0; i < (assoc_req->supportedChannels.length); i++) { + /* Get First Channel Number */ + first_chn_no = + assoc_req->supportedChannels.supportedChannels[i]; + assoc_ind->supportedChannels.channelList[index] = + first_chn_no; + i++; + index++; + + /* Get Number of Channels in a Subband */ + chn_count = + assoc_req->supportedChannels.supportedChannels[i]; + PELOG2(lim_log(mac_ctx, LOG2, + FL("Rcv assoc_req: chnl=%d, numOfChnl=%d "), + first_chn_no, chn_count);) + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + PELOG2(lim_log(mac_ctx, LOGW, + FL("Channel count is more than max supported =%d "), + chn_count);) + assoc_ind->supportedChannels.numChnl = 0; + return; + } + if (chn_count <= 1) + continue; + next_chn_no = first_chn_no; + if (SIR_BAND_5_GHZ == lim_get_rf_band(first_chn_no)) + channel_offset = SIR_11A_FREQUENCY_OFFSET; + else if (SIR_BAND_2_4_GHZ == lim_get_rf_band(first_chn_no)) + channel_offset = SIR_11B_FREQUENCY_OFFSET; + else + continue; + + for (j = 1; j < chn_count; j++) { + next_chn_no += channel_offset; + assoc_ind->supportedChannels.channelList[index] + = next_chn_no; + index++; + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + PELOG2(lim_log(mac_ctx, LOGW, + FL("Channel count is more than supported =%d "), + chn_count);) + assoc_ind->supportedChannels.numChnl = 0; + return; + } + } + } + + assoc_ind->supportedChannels.numChnl = (uint8_t) index; + PELOG2(lim_log(mac_ctx, LOG2, + FL("Send AssocInd to WSM: minPwr %d, maxPwr %d, numChnl %d"), + assoc_ind->powerCap.minTxPower, + assoc_ind->powerCap.maxTxPower, + assoc_ind->supportedChannels.numChnl);) +} + +/**--------------------------------------------------------------- + \fn lim_check_sta_in_pe_entries + \brief This function is called by lim_process_assoc_req_frame() + \ to check if STA entry already exists in any of the + \ PE entries of the AP. If it exists, deauth will be + \ sent on that session and the STA deletion will + \ happen. After this, the ASSOC request will be + \ processed + \ + \param pMac - A pointer to Global MAC structure + \param pHdr - A pointer to the MAC header + \return None + ------------------------------------------------------------------*/ +void lim_check_sta_in_pe_entries(tpAniSirGlobal pMac, tpSirMacMgmtHdr pHdr) +{ + uint8_t i; + uint16_t assocId = 0; + tpDphHashNode pStaDs = NULL; + tpPESession psessionEntry = NULL; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((&pMac->lim.gpSession[i] != NULL) && + (pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].pePersona == CDF_SAP_MODE)) { + + psessionEntry = &pMac->lim.gpSession[i]; + pStaDs = dph_lookup_hash_entry(pMac, pHdr->sa, &assocId, + &psessionEntry->dph. + dphHashTable); + if (pStaDs +#ifdef WLAN_FEATURE_11W + && !pStaDs->rmfEnabled +#endif + ) { + lim_log(pMac, LOGE, + FL + ("Sending Deauth and Deleting existing STA entry: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(psessionEntry-> + selfMacAddr)); + lim_send_deauth_mgmt_frame(pMac, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) pHdr->sa, + psessionEntry, false); + lim_trigger_sta_deletion(pMac, pStaDs, + psessionEntry); + break; + } + } + } +} + +/**--------------------------------------------------------------- + \fn lim_process_assoc_req_frame + \brief This function is called by limProcessMessageQueue() + \ upon Re/Association Request frame reception in + \ BTAMP AP or Soft AP role. + \ + \param pMac + \param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs + \param subType - Indicates whether it is Association Request(=0) + \ or Reassociation Request(=1) frame + \return None + ------------------------------------------------------------------*/ +void +lim_process_assoc_req_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + uint8_t subType, tpPESession psessionEntry) +{ + uint8_t updateContext; + uint8_t *pBody; + uint16_t peerIdx, temp; + uint32_t val; + int32_t framelen; + tSirRetStatus status; + tpSirMacMgmtHdr pHdr; + struct tLimPreAuthNode *pStaPreAuthContext; + tAniAuthType authType; + tSirMacCapabilityInfo localCapabilities; + tpDphHashNode pStaDs = NULL; + tpSirAssocReq pAssocReq, pTempAssocReq; + tLimMlmStates mlmPrevState; + tDot11fIERSN Dot11fIERSN; + tDot11fIEWPA Dot11fIEWPA; + uint32_t phyMode; + tHalBitVal qosMode; + tHalBitVal wsmMode, wmeMode; + uint8_t *wpsIe = NULL; + uint8_t *ht_cap_ie = NULL; + tSirMacRateSet basicRates; + uint8_t i = 0, j = 0; + bool pmfConnection = false; +#ifdef WLAN_FEATURE_11W + tPmfSaQueryTimerId timerId; + uint32_t retryInterval; +#endif + uint16_t assoc_id = 0; + bool assoc_req_copied = false; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + limGetQosMode(psessionEntry, &qosMode); + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + lim_log(pMac, LOG1, + FL("Received %s Req Frame on sessionid: %d systemrole %d" + " limMlmState %d from: " MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + psessionEntry->peSessionId, GET_LIM_SYSTEM_ROLE(psessionEntry), + psessionEntry->limMlmState, MAC_ADDR_ARRAY(pHdr->sa)); + + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, + FL("received unexpected ASSOC REQ on sessionid: %d " + "sys subType=%d for role=%d from: " MAC_ADDRESS_STR), + psessionEntry->peSessionId, subType, + GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(pHdr->sa)); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG3, + WMA_GET_RX_MPDU_DATA(pRxPacketInfo), framelen); + return; + } + + /* + * If a STA is already present in DPH and it + * is initiating a Assoc re-transmit, do not + * process it. This can happen when first Assoc Req frame + * is received but ACK lost at STA side. The ACK for this + * dropped Assoc Req frame should be sent by HW. Host simply + * does not process it once the entry for the STA is already + * present in DPH. + */ + pStaDs = dph_lookup_hash_entry(pMac, pHdr->sa, &assoc_id, + &psessionEntry->dph.dphHashTable); + if ((NULL != pStaDs) && (pHdr->fc.retry > 0)) { + lim_log(pMac, LOGE, + FL("STA is initiating Assoc Req after ACK lost. Do not process" + " sessionid: %d sys subType=%d for role=%d from: " + MAC_ADDRESS_STR), psessionEntry->peSessionId, + subType, GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + + lim_check_sta_in_pe_entries(pMac, pHdr); + + /* Get pointer to Re/Association Request frame body */ + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Re/Assoc Req frame from a BC/MC address */ + /* Log error and ignore it */ + lim_log(pMac, LOGE, + FL("Received %s Req on sessionid: %d frame from a " + "BC/MC address" MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + psessionEntry->peSessionId, MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG2, (uint8_t *) pBody, framelen); + + if (cdf_mem_compare((uint8_t *) pHdr->sa, (uint8_t *) pHdr->da, + (uint8_t) (sizeof(tSirMacAddr)))) { + lim_log(pMac, LOGE, + FL("Rejected Assoc Req frame Since same mac as" + " SAP/GO")); + lim_send_assoc_rsp_mgmt_frame(pMac, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, pHdr->sa, subType, 0, + psessionEntry); + return; + } + /* If TKIP counter measures active send Assoc Rsp frame to station with eSIR_MAC_MIC_FAILURE_REASON */ + if (psessionEntry->bTkipCntrMeasActive && + LIM_IS_AP_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("TKIP counter measure is active")); + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_MIC_FAILURE_REASON, + 1, pHdr->sa, subType, + 0, psessionEntry); + return; + } + /* Allocate memory for the Assoc Request frame */ + pAssocReq = cdf_mem_malloc(sizeof(*pAssocReq)); + if (NULL == pAssocReq) { + lim_log(pMac, LOGP, FL("Allocate Memory failed in assoc_req")); + return; + } + cdf_mem_set((void *)pAssocReq, sizeof(*pAssocReq), 0); + + /* Parse Assoc Request frame */ + if (subType == LIM_ASSOC) + status = + sir_convert_assoc_req_frame2_struct(pMac, pBody, framelen, + pAssocReq); + else + status = + sir_convert_reassoc_req_frame2_struct(pMac, pBody, framelen, + pAssocReq); + + if (status != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Parse error AssocRequest, length=%d from " + MAC_ADDRESS_STR), framelen, MAC_ADDR_ARRAY(pHdr->sa)); + lim_send_assoc_rsp_mgmt_frame(pMac, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, pHdr->sa, subType, 0, + psessionEntry); + goto error; + } + + pAssocReq->assocReqFrame = cdf_mem_malloc(framelen); + if (NULL == pAssocReq->assocReqFrame) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory for the assoc req, " + "length=%d from "), framelen); + goto error; + } + + cdf_mem_copy((uint8_t *) pAssocReq->assocReqFrame, + (uint8_t *) pBody, framelen); + pAssocReq->assocReqFrameLength = framelen; + + if (cfg_get_capability_info(pMac, &temp, psessionEntry) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("could not retrieve Capabilities")); + goto error; + } + lim_copy_u16((uint8_t *) &localCapabilities, temp); + + if (lim_compare_capabilities(pMac, + pAssocReq, + &localCapabilities, psessionEntry) == false) + { + lim_log(pMac, LOGE, FL("local caps mismatch received caps")); + lim_log(pMac, LOGE, FL("Received %s Req with unsupported " + "capabilities from" MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + /** + * Capabilities of requesting STA does not match with + * local capabilities. Respond with 'unsupported capabilities' + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, + pHdr->sa, subType, 0, psessionEntry); + + goto error; + } + + updateContext = false; + + if (lim_cmp_s_sid(pMac, &pAssocReq->ssId, psessionEntry) == false) { + lim_log(pMac, LOGE, + FL("Received %s Req with unmatched ssid ( Received" + " SSID: %.*s current SSID: %.*s ) from " + MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + pAssocReq->ssId.length, pAssocReq->ssId.ssId, + psessionEntry->ssId.length, psessionEntry->ssId.ssId, + MAC_ADDR_ARRAY(pHdr->sa)); + + /** + * Received Re/Association Request with either + * Broadcast SSID OR with SSID that does not + * match with local one. + * Respond with unspecified status code. + */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, + pHdr->sa, subType, 0, psessionEntry); + + goto error; + } + + /*************************************************************** + ** Verify if the requested rates are available in supported rate + ** set or Extended rate set. Some APs are adding basic rates in + ** Extended rateset IE + ***************************************************************/ + basicRates.numRates = 0; + + for (i = 0; + i < pAssocReq->supportedRates.numRates + && (i < SIR_MAC_RATESET_EID_MAX); i++) { + basicRates.rate[i] = pAssocReq->supportedRates.rate[i]; + basicRates.numRates++; + } + + for (j = 0; + (j < pAssocReq->extendedRates.numRates) + && (i < SIR_MAC_RATESET_EID_MAX); i++, j++) { + basicRates.rate[i] = pAssocReq->extendedRates.rate[j]; + basicRates.numRates++; + } + if (lim_check_rx_basic_rates(pMac, basicRates, psessionEntry) == false) { + lim_log(pMac, LOGE, FL("Received %s Req with unsupported " + "rates from" MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + /** + * Requesting STA does not support ALL BSS basic + * rates. Respond with 'basic rates not supported' + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, + 1, + pHdr->sa, subType, 0, psessionEntry); + + goto error; + } + + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G_ONLY) && + (pAssocReq->HTCaps.present)) + { + lim_log(pMac, LOGE, + FL("SOFTAP was in 11G only mode, rejecting legacy " + "STA : " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, pHdr->sa, subType, 0, + psessionEntry); + goto error; + + } /* end if phyMode == 11G_only */ + + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N_ONLY) && + (!pAssocReq->HTCaps.present)) { + lim_log(pMac, LOGE, + FL("SOFTAP was in 11N only mode, rejecting legacy " + "STA : " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, pHdr->sa, subType, 0, + psessionEntry); + goto error; + } /* end if PhyMode == 11N_only */ + + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC_ONLY) && + (!pAssocReq->VHTCaps.present)) { + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, pHdr->sa, subType, 0, + psessionEntry); + lim_log(pMac, LOGE, FL("SOFTAP was in 11AC only mode, reject")); + goto error; + } /* end if PhyMode == 11AC_only */ + + /* Spectrum Management (11h) specific checks */ + if (localCapabilities.spectrumMgt) { + tSirRetStatus status = eSIR_SUCCESS; + + /* If station is 11h capable, then it SHOULD send all mandatory + * IEs in assoc request frame. Let us verify that + */ + if (pAssocReq->capabilityInfo.spectrumMgt) { + if (! + ((pAssocReq->powerCapabilityPresent) + && (pAssocReq->supportedChannelsPresent))) { + /* One or more required information elements are missing, log the peers error */ + if (!pAssocReq->powerCapabilityPresent) { + lim_log(pMac, LOG1, + FL + ("LIM Info: Missing Power capability " + "IE in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == + subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + } + if (!pAssocReq->supportedChannelsPresent) { + lim_log(pMac, LOGW, + FL + ("LIM Info: Missing Supported channel " + "IE in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == + subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + + } + } else { + /* Assoc request has mandatory fields */ + status = + lim_is_dot11h_power_capabilities_in_range(pMac, + pAssocReq, + psessionEntry); + if (eSIR_SUCCESS != status) { + lim_log(pMac, LOGW, + FL("LIM Info: MinTxPower(STA) > " + "MaxTxPower(AP) in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == + subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + + } + status = + lim_is_dot11h_supported_channels_valid(pMac, + pAssocReq); + if (eSIR_SUCCESS != status) { + lim_log(pMac, LOGW, + FL("LIM Info: wrong supported " + "channels (STA) in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == + subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + + } + /* IEs are valid, use them if needed */ + } + } /* if(assoc.capabilityInfo.spectrumMgt) */ + else { + /* As per the capabiities, the spectrum management is not enabled on the station + * The AP may allow the associations to happen even if spectrum management is not + * allowed, if the transmit power of station is below the regulatory maximum + */ + + /* TODO: presently, this is not handled. In the current implemetation, the AP would + * allow the station to associate even if it doesn't support spectrum management. + */ + } + } /* end of spectrum management related processing */ + + if ((pAssocReq->HTCaps.present) + && (lim_check_mcs_set(pMac, pAssocReq->HTCaps.supportedMCSSet) == + false)) { + lim_log(pMac, LOGE, + FL("received %s req with unsupported" + "MCS Rate Set from " MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + + /** + * Requesting STA does not support ALL BSS MCS basic Rate set rates. + * Spec does not define any status code for this scenario. + */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS, + 1, + pHdr->sa, subType, 0, psessionEntry); + + goto error; + } + + if (phyMode == WNI_CFG_PHY_MODE_11G) { + + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_ONLY_POLICY, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not retrieve 11g-only flag")); + goto error; + } + + if (!pAssocReq->extendedRatesPresent && val) { + /** + * Received Re/Association Request from + * 11b STA when 11g only policy option + * is set. + * Reject with unspecified status code. + */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, + 1, + pHdr->sa, + subType, 0, psessionEntry); + + lim_log(pMac, LOGE, + FL("Rejecting Re/Assoc req from 11b STA: ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + +#ifdef WLAN_DEBUG + pMac->lim.gLim11bStaAssocRejectCount++; +#endif + goto error; + } + } + + /* Check for 802.11n HT caps compatibility; are HT Capabilities */ + /* turned on in lim? */ + if (psessionEntry->htCapability) { + /* There are; are they turned on in the STA? */ + if (pAssocReq->HTCaps.present) { + /* The station *does* support 802.11n HT capability... */ + + lim_log(pMac, LOG1, FL("AdvCodingCap:%d ChaWidthSet:%d " + "PowerSave:%d greenField:%d " + "shortGI20:%d shortGI40:%d" + "txSTBC:%d rxSTBC:%d delayBA:%d" + "maxAMSDUsize:%d DSSS/CCK:%d " + "PSMP:%d stbcCntl:%d lsigTXProt:%d"), + pAssocReq->HTCaps.advCodingCap, + pAssocReq->HTCaps.supportedChannelWidthSet, + pAssocReq->HTCaps.mimoPowerSave, + pAssocReq->HTCaps.greenField, + pAssocReq->HTCaps.shortGI20MHz, + pAssocReq->HTCaps.shortGI40MHz, + pAssocReq->HTCaps.txSTBC, + pAssocReq->HTCaps.rxSTBC, + pAssocReq->HTCaps.delayedBA, + pAssocReq->HTCaps.maximalAMSDUsize, + pAssocReq->HTCaps.dsssCckMode40MHz, + pAssocReq->HTCaps.psmp, + pAssocReq->HTCaps.stbcControlFrame, + pAssocReq->HTCaps.lsigTXOPProtection); + + /* Make sure the STA's caps are compatible with our own: */ + /* 11.15.2 Support of DSSS/CCK in 40 MHz */ + /* the AP shall refuse association requests from an HT STA that has the DSSS/CCK */ + /* Mode in 40 MHz subfield set to 1; */ + } + } /* End if on HT caps turned on in lim. */ + + /* Clear the buffers so that frame parser knows that there isn't a previously decoded IE in these buffers */ + cdf_mem_set((uint8_t *) &Dot11fIERSN, sizeof(Dot11fIERSN), 0); + cdf_mem_set((uint8_t *) &Dot11fIEWPA, sizeof(Dot11fIEWPA), 0); + + /* if additional IE is present, check if it has WscIE */ + if (pAssocReq->addIEPresent && pAssocReq->addIE.length) + wpsIe = + limGetWscIEPtr(pMac, pAssocReq->addIE.addIEdata, + pAssocReq->addIE.length); + else { + lim_log(pMac, LOG1, FL("Assoc req addIEPresent = %d " + "addIE length = %d"), + pAssocReq->addIEPresent, pAssocReq->addIE.length); + } + /* when wpsIe is present, RSN/WPA IE is ignored */ + if (wpsIe == NULL) { + /** check whether as RSN IE is present */ + if (LIM_IS_AP_ROLE(psessionEntry) && + psessionEntry->pLimStartBssReq->privacy && + psessionEntry->pLimStartBssReq->rsnIE.length) { + lim_log(pMac, LOG1, + FL("RSN enabled auth, Re/Assoc req from STA: " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + if (pAssocReq->rsnPresent) { + if (pAssocReq->rsn.length) { + /* Unpack the RSN IE */ + dot11f_unpack_ie_rsn(pMac, + &pAssocReq->rsn. + info[0], + pAssocReq->rsn.length, + &Dot11fIERSN); + + /* Check RSN version is supported or not */ + if (SIR_MAC_OUI_VERSION_1 == + Dot11fIERSN.version) { + /* check the groupwise and pairwise cipher suites */ + if (eSIR_SUCCESS != + (status = + lim_check_rx_rsn_ie_match(pMac, + Dot11fIERSN, + psessionEntry, + pAssocReq-> + HTCaps. + present, + &pmfConnection))) + { + lim_log(pMac, LOGE, + FL("RSN Mismatch." + "Rejecting Re/Assoc req from " + "STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY + (pHdr->sa)); + + /* some IE is not properly sent */ + /* received Association req frame with RSN IE but length is 0 */ + lim_send_assoc_rsp_mgmt_frame + (pMac, status, 1, + pHdr->sa, subType, + 0, psessionEntry); + + goto error; + + } + } else { + lim_log(pMac, LOGE, + FL("RSN length not correct." + "Rejecting Re/Assoc req from " + "STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr-> + sa)); + + /* received Association req frame with RSN IE version wrong */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS, + 1, + pHdr-> + sa, + subType, + 0, + psessionEntry); + goto error; + + } + } else { + lim_log(pMac, LOGW, + FL + ("Rejecting Re/Assoc req from STA:" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + /* received Association req frame with RSN IE but length is 0 */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS, + 1, + pHdr->sa, + subType, 0, + psessionEntry); + + goto error; + + } + } /* end - if(pAssocReq->rsnPresent) */ + if ((!pAssocReq->rsnPresent) && pAssocReq->wpaPresent) { + /* Unpack the WPA IE */ + if (pAssocReq->wpa.length) { + dot11f_unpack_ie_wpa(pMac, &pAssocReq->wpa.info[4], /* OUI is not taken care */ + pAssocReq->wpa.length, + &Dot11fIEWPA); + /* check the groupwise and pairwise cipher suites */ + if (eSIR_SUCCESS != + (status = + lim_check_rx_wpa_ie_match(pMac, + Dot11fIEWPA, + psessionEntry, + pAssocReq-> + HTCaps. + present))) { + lim_log(pMac, LOGW, + FL("WPA IE mismatch" + "Rejecting Re/Assoc req from " + "STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr-> + sa)); + /* received Association req frame with WPA IE but mismatch */ + lim_send_assoc_rsp_mgmt_frame(pMac, + status, + 1, + pHdr-> + sa, + subType, + 0, + psessionEntry); + goto error; + + } + } else { + lim_log(pMac, LOGW, + FL("WPA len incorrect." + "Rejecting Re/Assoc req from" + "STA: "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + /* received Association req frame with invalid WPA IE */ + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS, + 1, + pHdr->sa, + subType, 0, + psessionEntry); + + goto error; + } /* end - if(pAssocReq->wpa.length) */ + } /* end - if(pAssocReq->wpaPresent) */ + } + /* end of if(psessionEntry->pLimStartBssReq->privacy + && psessionEntry->pLimStartBssReq->rsnIE->length) */ + } /* end of if( ! pAssocReq->wscInfo.present ) */ + else { + lim_log(pMac, LOG1, FL("Assoc req WSE IE is present")); + } + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &peerIdx, + &psessionEntry->dph.dphHashTable); + + /* / Extract pre-auth context for the STA, if any. */ + pStaPreAuthContext = lim_search_pre_auth_list(pMac, pHdr->sa); + + if (pStaDs == NULL) { + /* / Requesting STA is not currently associated */ + if (pe_get_current_stas_count(pMac) == + pMac->lim.gLimAssocStaLimit) { + /** + * Maximum number of STAs that AP can handle reached. + * Send Association response to peer MAC entity + */ + lim_log(pMac, LOGE, FL("Max Sta count reached : %d"), + pMac->lim.maxStation); + lim_reject_association(pMac, pHdr->sa, + subType, false, + (tAniAuthType) 0, 0, + false, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + goto error; + } + /* / Check if STA is pre-authenticated. */ + if ((pStaPreAuthContext == NULL) || + (pStaPreAuthContext && + (pStaPreAuthContext->mlmState != + eLIM_MLM_AUTHENTICATED_STATE))) { + /** + * STA is not pre-authenticated yet requesting + * Re/Association before Authentication. + * OR STA is in the process of getting authenticated + * and sent Re/Association request. + * Send Deauthentication frame with 'prior + * authentication required' reason code. + */ + lim_send_deauth_mgmt_frame(pMac, eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON, /* =9 */ + pHdr->sa, psessionEntry, false); + + lim_log(pMac, LOGE, + FL("received %s req on sessionid: %d from STA " + "that does not have pre-auth context" + MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + psessionEntry->peSessionId, + MAC_ADDR_ARRAY(pHdr->sa)); + goto error; + } + /* / Delete 'pre-auth' context of STA */ + authType = pStaPreAuthContext->authType; + lim_delete_pre_auth_node(pMac, pHdr->sa); + + /* All is well. Assign AID (after else part) */ + + } /* if (pStaDs == NULL) */ + else { + /* STA context does exist for this STA */ + + if (pStaDs->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) { + /** + * Requesting STA is in some 'transient' state? + * Ignore the Re/Assoc Req frame by incrementing + * debug counter & logging error. + */ + if (subType == LIM_ASSOC) { + +#ifdef WLAN_DEBUG + pMac->lim.gLimNumAssocReqDropInvldState++; +#endif + lim_log(pMac, LOGE, + FL("received Assoc req in state " + "%X from "), + pStaDs->mlmStaContext.mlmState); + } else { +#ifdef WLAN_DEBUG + pMac->lim.gLimNumReassocReqDropInvldState++; +#endif + lim_log(pMac, LOGE, + FL("received ReAssoc req in state %X" + " from "), + pStaDs->mlmStaContext.mlmState); + } + lim_print_mac_addr(pMac, pHdr->sa, LOG1); + lim_print_mlm_state(pMac, LOG1, + (tLimMlmStates) pStaDs->mlmStaContext. + mlmState); + + goto error; + } /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */ + + /* STA sent association Request frame while already in + * 'associated' state */ + +#ifdef WLAN_FEATURE_11W + lim_log(pMac, LOG1, + FL + ("Re/Assoc request from station that is already associated")); + lim_log(pMac, LOG1, FL("PMF enabled %d, SA Query state %d"), + pStaDs->rmfEnabled, pStaDs->pmfSaQueryState); + if (pStaDs->rmfEnabled) { + switch (pStaDs->pmfSaQueryState) { + + /* start SA Query procedure, respond to Association Request */ + /* with try again later */ + case DPH_SA_QUERY_NOT_IN_PROGRESS: + /* + * We should reset the retry counter before we start + * the SA query procedure, otherwise in next set of SA query + * procedure we will end up using the stale value. + */ + pStaDs->pmfSaQueryRetryCount = 0; + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_TRY_AGAIN_LATER, + 1, pHdr->sa, subType, + pStaDs, psessionEntry); + lim_send_sa_query_request_frame(pMac, + (uint8_t *) & + (pStaDs-> + pmfSaQueryCurrentTransId), + pHdr->sa, + psessionEntry); + pStaDs->pmfSaQueryStartTransId = + pStaDs->pmfSaQueryCurrentTransId; + pStaDs->pmfSaQueryCurrentTransId++; + + /* start timer for SA Query retry */ + if (tx_timer_activate(&pStaDs->pmfSaQueryTimer) + != TX_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("PMF SA Query timer activation failed!")); + goto error; + } + + pStaDs->pmfSaQueryState = + DPH_SA_QUERY_IN_PROGRESS; + goto error; + + /* SA Query procedure still going, respond to Association */ + /* Request with try again later */ + case DPH_SA_QUERY_IN_PROGRESS: + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_TRY_AGAIN_LATER, + 1, pHdr->sa, subType, + 0, psessionEntry); + goto error; + + /* SA Query procedure timed out, accept Association Request */ + /* normally */ + case DPH_SA_QUERY_TIMED_OUT: + pStaDs->pmfSaQueryState = + DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } + } +#endif + + /* no change in the capability so drop the frame */ + if ((true == + cdf_mem_compare(&pStaDs->mlmStaContext.capabilityInfo, + &pAssocReq->capabilityInfo, + sizeof(tSirMacCapabilityInfo))) + && (subType == LIM_ASSOC)) { + lim_log(pMac, LOGE, + FL(" Received Assoc req in state %X STAid=%d"), + pStaDs->mlmStaContext.mlmState, peerIdx); + goto error; + } else { + /** + * STA sent Re/association Request frame while already in + * 'associated' state. Update STA capabilities and + * send Association response frame with same AID + */ + lim_log(pMac, LOG1, + FL("Recved Assoc req from STA already connected" + " UpdateConext")); + pStaDs->mlmStaContext.capabilityInfo = + pAssocReq->capabilityInfo; + if (pStaPreAuthContext + && (pStaPreAuthContext->mlmState == + eLIM_MLM_AUTHENTICATED_STATE)) { + /* / STA has triggered pre-auth again */ + authType = pStaPreAuthContext->authType; + lim_delete_pre_auth_node(pMac, pHdr->sa); + } else + authType = pStaDs->mlmStaContext.authType; + + updateContext = true; + if (dph_init_sta_state + (pMac, pHdr->sa, peerIdx, true, + &psessionEntry->dph.dphHashTable) + == NULL) { + lim_log(pMac, LOGE, + FL("could not Init STAid=%d"), peerIdx); + goto error; + } + } + goto sendIndToSme; + } /* end if (lookup for STA in perStaDs fails) */ + + /* check if sta is allowed per QoS AC rules */ + limGetWmeMode(psessionEntry, &wmeMode); + if ((qosMode == eHAL_SET) || (wmeMode == eHAL_SET)) { + /* for a qsta, check if the requested Traffic spec */ + /* is admissible */ + /* for a non-qsta check if the sta can be admitted */ + if (pAssocReq->addtsPresent) { + uint8_t tspecIdx = 0; /* index in the sch tspec table. */ + if (lim_admit_control_add_ts + (pMac, pHdr->sa, &(pAssocReq->addtsReq), + &(pAssocReq->qosCapability), 0, false, NULL, + &tspecIdx, psessionEntry) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("AdmitControl: TSPEC rejected")); + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, + 1, pHdr->sa, subType, + 0, psessionEntry); +#ifdef WLAN_DEBUG + pMac->lim.gLimNumAssocReqDropACRejectTS++; +#endif + goto error; + } + } else if (lim_admit_control_add_sta(pMac, pHdr->sa, false) + != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("AdmitControl: Sta rejected")); + lim_send_assoc_rsp_mgmt_frame(pMac, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, + 1, + pHdr->sa, + subType, 0, psessionEntry); +#ifdef WLAN_DEBUG + pMac->lim.gLimNumAssocReqDropACRejectSta++; +#endif + goto error; + } + /* else all ok */ + lim_log(pMac, LOG1, FL("AdmitControl: Sta OK!")); + } + + /** + * STA is Associated ! + */ + lim_log(pMac, LOGE, + FL("Received %s Req successful from " MAC_ADDRESS_STR), + (LIM_ASSOC == subType) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(pHdr->sa)); + + /** + * AID for this association will be same as the peer Index used in DPH table. + * Assign unused/least recently used peer Index from perStaDs. + * NOTE: lim_assign_peer_idx() assigns AID values ranging + * between 1 - cfg_item(WNI_CFG_ASSOC_STA_LIMIT) + */ + + peerIdx = lim_assign_peer_idx(pMac, psessionEntry); + + if (!peerIdx) { + /* Could not assign AID */ + /* Reject association */ + lim_log(pMac, LOGE, + FL("PeerIdx not avaialble. Reject associaton")); + lim_reject_association(pMac, pHdr->sa, + subType, true, authType, + peerIdx, false, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + goto error; + } + + /** + * Add an entry to hash table maintained by DPH module + */ + + pStaDs = + dph_add_hash_entry(pMac, pHdr->sa, peerIdx, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + /* Could not add hash table entry at DPH */ + lim_log(pMac, LOGE, + FL("could not add hash entry at DPH for aid=%d, MacAddr:" + MAC_ADDRESS_STR), peerIdx, MAC_ADDR_ARRAY(pHdr->sa)); + + /* Release AID */ + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + + lim_reject_association(pMac, pHdr->sa, + subType, true, authType, peerIdx, false, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + goto error; + } + +sendIndToSme: + /* + * check here if the parsedAssocReq already + * pointing to the assoc_req and free it before + * assigning this new pAssocReq + */ + if (psessionEntry->parsedAssocReq != NULL) { + pTempAssocReq = psessionEntry->parsedAssocReq[pStaDs->assocId]; + if (pTempAssocReq != NULL) { + if (pTempAssocReq->assocReqFrame) { + cdf_mem_free(pTempAssocReq->assocReqFrame); + pTempAssocReq->assocReqFrame = NULL; + pTempAssocReq->assocReqFrameLength = 0; + } + cdf_mem_free(pTempAssocReq); + pTempAssocReq = NULL; + } + + psessionEntry->parsedAssocReq[pStaDs->assocId] = pAssocReq; + assoc_req_copied = true; + } + + pStaDs->mlmStaContext.htCapability = pAssocReq->HTCaps.present; +#ifdef WLAN_FEATURE_11AC + pStaDs->mlmStaContext.vhtCapability = pAssocReq->VHTCaps.present; +#endif + pStaDs->qos.addtsPresent = + (pAssocReq->addtsPresent == 0) ? false : true; + pStaDs->qos.addts = pAssocReq->addtsReq; + pStaDs->qos.capability = pAssocReq->qosCapability; + pStaDs->versionPresent = 0; + /* short slot and short preamble should be updated before doing limaddsta */ + pStaDs->shortPreambleEnabled = + (uint8_t) pAssocReq->capabilityInfo.shortPreamble; + pStaDs->shortSlotTimeEnabled = + (uint8_t) pAssocReq->capabilityInfo.shortSlotTime; + + pStaDs->valid = 0; + pStaDs->mlmStaContext.authType = authType; + pStaDs->staType = STA_ENTRY_PEER; + + /* TODO: If listen interval is more than certain limit, reject the association. */ + /* Need to check customer requirements and then implement. */ + pStaDs->mlmStaContext.listenInterval = pAssocReq->listenInterval; + pStaDs->mlmStaContext.capabilityInfo = pAssocReq->capabilityInfo; + + /* The following count will be used to knock-off the station if it doesn't + * come back to receive the buffered data. The AP will wait for numTimSent number + * of beacons after sending TIM information for the station, before assuming that + * the station is no more associated and disassociates it + */ + + /** timWaitCount is used by PMM for monitoring the STA's in PS for LINK*/ + pStaDs->timWaitCount = + (uint8_t) GET_TIM_WAIT_COUNT(pAssocReq->listenInterval); + + /** Initialise the Current successful MPDU's tranfered to this STA count as 0 */ + pStaDs->curTxMpduCnt = 0; + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && + pAssocReq->HTCaps.present && pAssocReq->wmeInfoPresent) { + pStaDs->htGreenfield = (uint8_t) pAssocReq->HTCaps.greenField; + pStaDs->htAMpduDensity = pAssocReq->HTCaps.mpduDensity; + pStaDs->htDsssCckRate40MHzSupport = + (uint8_t) pAssocReq->HTCaps.dsssCckMode40MHz; + pStaDs->htLsigTXOPProtection = + (uint8_t) pAssocReq->HTCaps.lsigTXOPProtection; + pStaDs->htMaxAmsduLength = + (uint8_t) pAssocReq->HTCaps.maximalAMSDUsize; + pStaDs->htMaxRxAMpduFactor = pAssocReq->HTCaps.maxRxAMPDUFactor; + pStaDs->htMIMOPSState = pAssocReq->HTCaps.mimoPowerSave; + + /* pAssocReq will be copied to psessionEntry->parsedAssocReq + * later + */ + ht_cap_ie = ((uint8_t *) &pAssocReq->HTCaps) + 1; + + /* check whether AP is enabled with shortGI */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_20MHZ, &val) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, + FL("could not retrieve shortGI 20Mhz CFG"));) + goto error; + } + if (val) { + pStaDs->htShortGI20Mhz = + (uint8_t)pAssocReq->HTCaps.shortGI20MHz; + } else { + /* Unset htShortGI20Mhz in ht_caps*/ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI20MHZ_S); + pStaDs->htShortGI20Mhz = 0; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_40MHZ, &val) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, + FL("could not retrieve shortGI 40Mhz CFG"));) + goto error; + } + if (val) { + pStaDs->htShortGI40Mhz = + (uint8_t)pAssocReq->HTCaps.shortGI40MHz; + } else { + /* Unset htShortGI40Mhz in ht_caps */ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI40MHZ_S); + pStaDs->htShortGI40Mhz = 0; + } + + pStaDs->htSupportedChannelWidthSet = + (uint8_t) pAssocReq->HTCaps.supportedChannelWidthSet; + /* + * peer just follows AP; so when we are softAP/GO, + * we just store our session entry's secondary channel offset + * here in peer INFRA STA. However, if peer's 40MHz channel + * width support is disabled then secondary channel will be zero + */ + pStaDs->htSecondaryChannelOffset = + (pStaDs->htSupportedChannelWidthSet) ? psessionEntry-> + htSecondaryChannelOffset : 0; +#ifdef WLAN_FEATURE_11AC + if (pAssocReq->operMode.present) { + pStaDs->vhtSupportedChannelWidthSet = + (uint8_t) ((pAssocReq->operMode.chanWidth == + eHT_CHANNEL_WIDTH_80MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ : + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ); + pStaDs->htSupportedChannelWidthSet = + (uint8_t) (pAssocReq->operMode. + chanWidth ? eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ); + } else if (pAssocReq->VHTCaps.present) { + /* Check if STA has enabled it's channel bonding mode. */ + /* If channel bonding mode is enabled, we decide based on SAP's current configuration. */ + /* else, we set it to VHT20. */ + pStaDs->vhtSupportedChannelWidthSet = + (uint8_t) ((pStaDs->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_20MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ : + psessionEntry->ch_width - 1); + pStaDs->htMaxRxAMpduFactor = + pAssocReq->VHTCaps.maxAMPDULenExp; + } + /* Lesser among the AP and STA bandwidth of operation. */ + pStaDs->htSupportedChannelWidthSet = + (pStaDs->htSupportedChannelWidthSet < + psessionEntry->htSupportedChannelWidthSet) ? + pStaDs->htSupportedChannelWidthSet : + psessionEntry->htSupportedChannelWidthSet; + +#endif + pStaDs->baPolicyFlag = 0xFF; + pStaDs->htLdpcCapable = + (uint8_t) pAssocReq->HTCaps.advCodingCap; + } + + if (pAssocReq->VHTCaps.present && pAssocReq->wmeInfoPresent) { + pStaDs->vhtLdpcCapable = + (uint8_t) pAssocReq->VHTCaps.ldpcCodingCap; + } + + if (!pAssocReq->wmeInfoPresent) { + pStaDs->mlmStaContext.htCapability = 0; + pStaDs->mlmStaContext.vhtCapability = 0; + } + if (pStaDs->mlmStaContext.vhtCapability) { + if (psessionEntry->txBFIniFeatureEnabled && + pAssocReq->VHTCaps.suBeamFormerCap) + pStaDs->vhtBeamFormerCapable = 1; + else + pStaDs->vhtBeamFormerCapable = 0; + if (psessionEntry->enable_su_tx_bformer && + pAssocReq->VHTCaps.suBeamformeeCap) + pStaDs->vht_su_bfee_capable = 1; + else + pStaDs->vht_su_bfee_capable = 0; + } +#ifdef WLAN_FEATURE_11AC + if (lim_populate_matching_rate_set(pMac, + pStaDs, + &(pAssocReq->supportedRates), + &(pAssocReq->extendedRates), + pAssocReq->HTCaps.supportedMCSSet, + psessionEntry, &pAssocReq->VHTCaps) + != eSIR_SUCCESS) +#else + + if (lim_populate_matching_rate_set(pMac, + pStaDs, + &(pAssocReq->supportedRates), + &(pAssocReq->extendedRates), + pAssocReq->HTCaps.supportedMCSSet, + psessionEntry) != eSIR_SUCCESS) +#endif + { + /* Could not update hash table entry at DPH with rateset */ + lim_log(pMac, LOGE, + FL + ("could not update hash entry at DPH for aid=%d, MacAddr: " + MAC_ADDRESS_STR), peerIdx, MAC_ADDR_ARRAY(pHdr->sa)); + + /* Release AID */ + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + + lim_reject_association(pMac, pHdr->sa, + subType, true, authType, peerIdx, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + if (psessionEntry->parsedAssocReq) + pAssocReq = + psessionEntry->parsedAssocReq[pStaDs->assocId]; + goto error; + } +#ifdef WLAN_FEATURE_11AC + if (pAssocReq->operMode.present) { + pStaDs->vhtSupportedRxNss = pAssocReq->operMode.rxNSS + 1; + } else { + pStaDs->vhtSupportedRxNss = + ((pStaDs->supportedRates.vhtRxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; + } +#endif + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + + pStaDs->qosMode = false; + pStaDs->lleEnabled = false; + if (pAssocReq->capabilityInfo.qos && (qosMode == eHAL_SET)) { + pStaDs->lleEnabled = true; + pStaDs->qosMode = true; + } + + pStaDs->wmeEnabled = false; + pStaDs->wsmEnabled = false; + limGetWmeMode(psessionEntry, &wmeMode); + if ((!pStaDs->lleEnabled) && pAssocReq->wmeInfoPresent + && (wmeMode == eHAL_SET)) { + pStaDs->wmeEnabled = true; + pStaDs->qosMode = true; + limGetWsmMode(psessionEntry, &wsmMode); + /* WMM_APSD - WMM_SA related processing should be separate; WMM_SA and WMM_APSD + can coexist */ + if (pAssocReq->WMMInfoStation.present) { + /* check whether AP supports or not */ + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->apUapsdEnable == 0) && + (pAssocReq->WMMInfoStation.acbe_uapsd || + pAssocReq->WMMInfoStation.acbk_uapsd || + pAssocReq->WMMInfoStation.acvo_uapsd || + pAssocReq->WMMInfoStation.acvi_uapsd)) { + + /** + * Received Re/Association Request from + * STA when UPASD is not supported. + */ + lim_log(pMac, LOGE, + FL("AP do not support UAPSD so reply " + "to STA accordingly")); + /* update UAPSD and send it to LIM to add STA */ + pStaDs->qos.capability.qosInfo.acbe_uapsd = 0; + pStaDs->qos.capability.qosInfo.acbk_uapsd = 0; + pStaDs->qos.capability.qosInfo.acvo_uapsd = 0; + pStaDs->qos.capability.qosInfo.acvi_uapsd = 0; + pStaDs->qos.capability.qosInfo.maxSpLen = 0; + + } else { + /* update UAPSD and send it to LIM to add STA */ + pStaDs->qos.capability.qosInfo.acbe_uapsd = + pAssocReq->WMMInfoStation.acbe_uapsd; + pStaDs->qos.capability.qosInfo.acbk_uapsd = + pAssocReq->WMMInfoStation.acbk_uapsd; + pStaDs->qos.capability.qosInfo.acvo_uapsd = + pAssocReq->WMMInfoStation.acvo_uapsd; + pStaDs->qos.capability.qosInfo.acvi_uapsd = + pAssocReq->WMMInfoStation.acvi_uapsd; + pStaDs->qos.capability.qosInfo.maxSpLen = + pAssocReq->WMMInfoStation.max_sp_length; + } + } + if (pAssocReq->wsmCapablePresent && (wsmMode == eHAL_SET)) + pStaDs->wsmEnabled = true; + + } + /* Re/Assoc Response frame to requesting STA */ + pStaDs->mlmStaContext.subType = subType; + +#ifdef WLAN_FEATURE_11W + pStaDs->rmfEnabled = (pmfConnection) ? 1 : 0; + pStaDs->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + timerId.fields.sessionId = psessionEntry->peSessionId; + timerId.fields.peerIdx = peerIdx; + if (wlan_cfg_get_int(pMac, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retryInterval) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("Could not retrieve PMF SA Query retry interval value")); + lim_reject_association(pMac, pHdr->sa, subType, true, authType, + peerIdx, false, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + goto error; + } + if (WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN > retryInterval) { + retryInterval = WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF; + } + if (tx_timer_create(&pStaDs->pmfSaQueryTimer, "PMF SA Query timer", + lim_pmf_sa_query_timer_handler, timerId.value, + SYS_MS_TO_TICKS((retryInterval * 1024) / 1000), + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGE, FL("could not create PMF SA Query timer")); + lim_reject_association(pMac, pHdr->sa, + subType, true, authType, + peerIdx, false, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + goto error; + } +#endif + + if (pAssocReq->ExtCap.present) { + lim_set_stads_rtt_cap(pStaDs, + (struct s_ext_cap *) pAssocReq->ExtCap.bytes, pMac); + } else { + pStaDs->timingMeasCap = 0; + PELOG1(lim_log(pMac, LOG1, FL("ExtCap not present"));) + } + + /* BTAMP: Storing the parsed assoc request in the psessionEntry array */ + if (psessionEntry->parsedAssocReq) + psessionEntry->parsedAssocReq[pStaDs->assocId] = pAssocReq; + assoc_req_copied = true; + + /* BTAMP: If STA context already exist (ie. updateContext = 1) + * for this STA, then we should delete the old one, and add + * the new STA. This is taken care of in the lim_del_sta() routine. + * + * Prior to BTAMP, we were setting this flag so that when + * PE receives SME_ASSOC_CNF, and if this flag is set, then + * PE shall delete the old station and then add. But now in + * BTAMP, we're directly adding station before waiting for + * SME_ASSOC_CNF, so we can do this now. + */ + if (!updateContext) { + pStaDs->mlmStaContext.updateContext = 0; + + /* BTAMP: Add STA context at HW - issue WMA_ADD_STA_REQ to HAL */ + if (lim_add_sta(pMac, pStaDs, false, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("could not Add STA with assocId=%d"), + pStaDs->assocId); + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, + pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + if (psessionEntry->parsedAssocReq) + pAssocReq = psessionEntry->parsedAssocReq[ + pStaDs->assocId]; + goto error; + } + } else { + pStaDs->mlmStaContext.updateContext = 1; + + mlmPrevState = pStaDs->mlmStaContext.mlmState; + + /* As per the HAL/FW needs the reassoc req need not be calling lim_del_sta */ + if (subType != LIM_REASSOC) { + /* we need to set the mlmState here in order differentiate in lim_del_sta. */ + pStaDs->mlmStaContext.mlmState = + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE; + if (lim_del_sta(pMac, pStaDs, true, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("could not DEL STA with assocId=%d staId %d"), + pStaDs->assocId, pStaDs->staIndex); + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext. + subType, true, + pStaDs->mlmStaContext. + authType, pStaDs->assocId, + true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + + /* Restoring the state back. */ + pStaDs->mlmStaContext.mlmState = mlmPrevState; + if (psessionEntry->parsedAssocReq) + pAssocReq = + psessionEntry->parsedAssocReq[ + pStaDs->assocId]; + goto error; + } + } else { + /* mlmState is changed in lim_add_sta context */ + /* use the same AID, already allocated */ + if (lim_add_sta(pMac, pStaDs, false, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Could not AddSta with assocId= %d" + "staId %d"), + pStaDs->assocId, pStaDs->staIndex); + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext. + subType, true, + pStaDs->mlmStaContext. + authType, pStaDs->assocId, + true, + (tSirResultCodes) + eSIR_MAC_WME_REFUSED_STATUS, + psessionEntry); + + /* Restoring the state back. */ + pStaDs->mlmStaContext.mlmState = mlmPrevState; + if (psessionEntry->parsedAssocReq) + pAssocReq = + psessionEntry->parsedAssocReq[ + pStaDs->assocId]; + goto error; + } + + } + + } + + /* AddSta is sucess here */ + if (LIM_IS_AP_ROLE(psessionEntry) && + IS_DOT11_MODE_HT(psessionEntry->dot11mode) && + pAssocReq->HTCaps.present && pAssocReq->wmeInfoPresent) { + /** Update in the HAL Station Table for the Update of the Protection Mode */ + lim_post_sm_state_update(pMac, pStaDs->staIndex, + pStaDs->htMIMOPSState, + pStaDs->staAddr, + psessionEntry->smeSessionId); + } + + return; + +error: + if (pAssocReq != NULL) { + if (pAssocReq->assocReqFrame) { + cdf_mem_free(pAssocReq->assocReqFrame); + pAssocReq->assocReqFrame = NULL; + pAssocReq->assocReqFrameLength = 0; + } + + cdf_mem_free(pAssocReq); + /* to avoid double free */ + if (assoc_req_copied && psessionEntry->parsedAssocReq) + psessionEntry->parsedAssocReq[pStaDs->assocId] = NULL; + } + + /* If it is not duplicate Assoc request then only make to Null */ + if ((pStaDs != NULL) && + (pStaDs->mlmStaContext.mlmState != eLIM_MLM_WT_ADD_STA_RSP_STATE)) { + if (psessionEntry->parsedAssocReq != NULL) { + pTempAssocReq = + psessionEntry->parsedAssocReq[pStaDs->assocId]; + if (pTempAssocReq != NULL) { + if (pTempAssocReq->assocReqFrame) { + cdf_mem_free(pTempAssocReq-> + assocReqFrame); + pTempAssocReq->assocReqFrame = NULL; + pTempAssocReq->assocReqFrameLength = 0; + } + cdf_mem_free(pTempAssocReq); + psessionEntry-> + parsedAssocReq[pStaDs->assocId] = NULL; + } + } + } + + return; + +} /*** end lim_process_assoc_req_frame() ***/ + +#ifdef FEATURE_WLAN_WAPI +/** + * lim_fill_assoc_ind_wapi_info()- Updates WAPI data in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @assoc_ind: Pointer to association indication + * @wpsie: WPS IE + * + * This function updates WAPI meta data in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_wapi_info(tpAniSirGlobal mac_ctx, + tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind, + uint8_t *wpsie) +{ + if (assoc_req->wapiPresent && (NULL == wpsie)) { + lim_log(mac_ctx, LOG2, + FL("Received WAPI IE length in Assoc Req is %d"), + assoc_req->wapi.length); + assoc_ind->wapiIE.wapiIEdata[0] = SIR_MAC_WAPI_EID; + assoc_ind->wapiIE.wapiIEdata[1] = assoc_req->wapi.length; + cdf_mem_copy(&assoc_ind->wapiIE.wapiIEdata[2], + assoc_req->wapi.info, assoc_req->wapi.length); + assoc_ind->wapiIE.length = + 2 + assoc_req->wapi.length; + } + return; +} +#endif + +/** + * lim_fill_assoc_ind_vht_info() - Updates VHT information in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @session_entry: PE session entry + * @assoc_ind: Pointer to association indication + * + * This function updates VHT information in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind) +{ + uint8_t chan; + + if (session_entry->limRFBand == SIR_BAND_2_4_GHZ) { + if (session_entry->vhtCapability + && assoc_req->VHTCaps.present) + assoc_ind->chan_info.info = MODE_11AC_VHT20; + else if (session_entry->htCapability + && assoc_req->HTCaps.present) + assoc_ind->chan_info.info = MODE_11NG_HT20; + else + assoc_ind->chan_info.info = MODE_11G; + } else { + if (session_entry->vhtCapability + && assoc_req->VHTCaps.present) { + if ((session_entry->ch_width > CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + chan = session_entry->ch_center_freq_seg0; + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(chan); + assoc_ind->chan_info.info = MODE_11AC_VHT80; + } else if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11AC_VHT40; + if (session_entry->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + assoc_ind->chan_info.band_center_freq1 + += 10; + else + assoc_ind->chan_info.band_center_freq1 + -= 10; + } else { + assoc_ind->chan_info.info = MODE_11AC_VHT20; + } + } else if (session_entry->htCapability + && assoc_req->HTCaps.present) { + if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11NA_HT40; + if (session_entry->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + assoc_ind->chan_info.band_center_freq1 + += 10; + else + assoc_ind->chan_info.band_center_freq1 + -= 10; + } else { + assoc_ind->chan_info.info = MODE_11NA_HT20; + } + } else { + assoc_ind->chan_info.info = MODE_11A; + } + } + return; +} + +/** + * lim_send_mlm_assoc_ind() - Sends assoc indication to SME + * @mac_ctx: Global Mac context + * @sta_ds: Station DPH hash entry + * @session_entry: PE session entry + * + * This function sends either LIM_MLM_ASSOC_IND + * or LIM_MLM_REASSOC_IND to SME. + * + * Return: None + */ +void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpPESession session_entry) +{ + tpLimMlmAssocInd assoc_ind = NULL; + tpSirAssocReq assoc_req; + uint16_t temp, rsn_len; + uint32_t phy_mode; + uint8_t sub_type; + uint8_t *wpsie = NULL; + uint32_t tmp; + + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[sta_ds->assocId]; + + /* Get the phy_mode */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* Determine if its Assoc or ReAssoc Request */ + if (assoc_req->reassocRequest == 1) + sub_type = LIM_REASSOC; + else + sub_type = LIM_ASSOC; + + lim_log(mac_ctx, LOG1, + FL("Sessionid %d ssid %s sub_type %d Associd %d staAddr " + MAC_ADDRESS_STR), session_entry->peSessionId, + assoc_req->ssId.ssId, sub_type, sta_ds->assocId, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + if (sub_type == LIM_ASSOC || sub_type == LIM_REASSOC) { + temp = sizeof(tLimMlmAssocInd); + + assoc_ind = cdf_mem_malloc(temp); + if (NULL == assoc_ind) { + lim_release_peer_idx(mac_ctx, sta_ds->assocId, + session_entry); + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for assoc_ind")); + return; + } + cdf_mem_set(assoc_ind, temp, 0); + cdf_mem_copy((uint8_t *) assoc_ind->peerMacAddr, + (uint8_t *) sta_ds->staAddr, sizeof(tSirMacAddr)); + assoc_ind->aid = sta_ds->assocId; + cdf_mem_copy((uint8_t *) &assoc_ind->ssId, + (uint8_t *) &(assoc_req->ssId), + assoc_req->ssId.length + 1); + assoc_ind->sessionId = session_entry->peSessionId; + assoc_ind->authType = sta_ds->mlmStaContext.authType; + assoc_ind->capabilityInfo = assoc_req->capabilityInfo; + + /* Fill in RSN IE information */ + assoc_ind->rsnIE.length = 0; + /* if WPS IE is present, ignore RSN IE */ + if (assoc_req->addIEPresent && assoc_req->addIE.length) { + wpsie = limGetWscIEPtr(mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + if (assoc_req->rsnPresent && (NULL == wpsie)) { + lim_log(mac_ctx, LOG2, FL("Assoc Req RSN IE len = %d"), + assoc_req->rsn.length); + assoc_ind->rsnIE.length = 2 + assoc_req->rsn.length; + assoc_ind->rsnIE.rsnIEdata[0] = SIR_MAC_RSN_EID; + assoc_ind->rsnIE.rsnIEdata[1] = + assoc_req->rsn.length; + cdf_mem_copy(&assoc_ind->rsnIE.rsnIEdata[2], + assoc_req->rsn.info, + assoc_req->rsn.length); + } + /* Fill in 802.11h related info */ + if (assoc_req->powerCapabilityPresent + && assoc_req->supportedChannelsPresent) { + assoc_ind->spectrumMgtIndicator = eSIR_TRUE; + assoc_ind->powerCap.minTxPower = + assoc_req->powerCapability.minTxPower; + assoc_ind->powerCap.maxTxPower = + assoc_req->powerCapability.maxTxPower; + lim_convert_supported_channels(mac_ctx, assoc_ind, + assoc_req); + } else { + assoc_ind->spectrumMgtIndicator = eSIR_FALSE; + } + + /* This check is to avoid extra Sec IEs present incase of WPS */ + if (assoc_req->wpaPresent && (NULL == wpsie)) { + rsn_len = assoc_ind->rsnIE.length; + if ((rsn_len + assoc_req->wpa.length) + >= SIR_MAC_MAX_IE_LENGTH) { + lim_log(mac_ctx, LOGE, + FL("rsnIEdata index out of bounds %d"), + rsn_len); + cdf_mem_free(assoc_ind); + return; + } + assoc_ind->rsnIE.rsnIEdata[rsn_len] = + SIR_MAC_WPA_EID; + assoc_ind->rsnIE.rsnIEdata[rsn_len + 1] + = assoc_req->wpa.length; + cdf_mem_copy( + &assoc_ind->rsnIE.rsnIEdata[rsn_len + 2], + assoc_req->wpa.info, assoc_req->wpa.length); + assoc_ind->rsnIE.length += 2 + assoc_req->wpa.length; + } +#ifdef FEATURE_WLAN_WAPI + lim_fill_assoc_ind_wapi_info(mac_ctx, assoc_req, assoc_ind, + wpsie); +#endif + + assoc_ind->addIE.length = 0; + if (assoc_req->addIEPresent) { + cdf_mem_copy(&assoc_ind->addIE.addIEdata, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + assoc_ind->addIE.length = assoc_req->addIE.length; + } + /* + * Add HT Capabilities into addIE for OBSS + * processing in hostapd + */ + if (assoc_req->HTCaps.present) { + rsn_len = assoc_ind->addIE.length; + if (assoc_ind->addIE.length + DOT11F_IE_HTCAPS_MIN_LEN + + 2 < SIR_MAC_MAX_IE_LENGTH) { + assoc_ind->addIE.addIEdata[rsn_len] = + SIR_MAC_HT_CAPABILITIES_EID; + assoc_ind->addIE.addIEdata[rsn_len + 1] = + DOT11F_IE_HTCAPS_MIN_LEN; + cdf_mem_copy( + &assoc_ind->addIE.addIEdata[rsn_len+2], + ((uint8_t *)&assoc_req->HTCaps) + 1, + DOT11F_IE_HTCAPS_MIN_LEN); + assoc_ind->addIE.length += + 2 + DOT11F_IE_HTCAPS_MIN_LEN; + } else { + lim_log(mac_ctx, LOGP, + FL("Fail:HT capabilities IE to addIE")); + } + } + + if (assoc_req->wmeInfoPresent) { + if (wlan_cfg_get_int (mac_ctx, + (uint16_t) WNI_CFG_WME_ENABLED, &tmp) + != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("wlan_cfg_get_int failed for id %d"), + WNI_CFG_WME_ENABLED); + + /* check whether AP is enabled with WMM */ + if (tmp) + assoc_ind->WmmStaInfoPresent = 1; + else + assoc_ind->WmmStaInfoPresent = 0; + /* + * Note: we are not rejecting association here + * because IOT will fail + */ + } + /* Required for indicating the frames to upper layer */ + assoc_ind->assocReqLength = assoc_req->assocReqFrameLength; + assoc_ind->assocReqPtr = assoc_req->assocReqFrame; + + assoc_ind->beaconPtr = session_entry->beacon; + assoc_ind->beaconLength = session_entry->bcnLen; + + assoc_ind->chan_info.chan_id = + session_entry->currentOperChannel; + assoc_ind->chan_info.mhz = + cds_chan_to_freq(session_entry->currentOperChannel); + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(session_entry->currentOperChannel); + assoc_ind->chan_info.band_center_freq2 = 0; + assoc_ind->chan_info.reg_info_1 = + (session_entry->maxTxPower << 16); + assoc_ind->chan_info.reg_info_2 = + (session_entry->maxTxPower << 8); + /* updates VHT information in assoc indication */ + lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req, + assoc_ind); + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND, + (uint32_t *) assoc_ind); + cdf_mem_free(assoc_ind); + } + return; +} diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c new file mode 100644 index 0000000000..e4c672be0e --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_assoc_rsp_frame.cc contains the code + * for processing Re/Association Response Frame. + * Author: Chandra Modumudi + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sch_api.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_send_messages.h" + + +extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, tpPESession psessionEntry); + +/** + * lim_update_stads_htcap() - Updates station Descriptor HT capability + * @mac_ctx: Pointer to Global MAC structure + * @sta_ds: Station Descriptor in DPH + * @assoc_rsp: Pointer to Association Response Structure + * + * This function is called to Update the HT capabilities in + * Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +static void lim_update_stads_htcap(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp) +{ + uint16_t highest_rxrate = 0; + tDot11fIEHTCaps *ht_caps; + + ht_caps = &assoc_rsp->HTCaps; + sta_ds->mlmStaContext.htCapability = assoc_rsp->HTCaps.present; + if (assoc_rsp->HTCaps.present) { + sta_ds->htGreenfield = + (uint8_t) ht_caps->greenField; + sta_ds->htSupportedChannelWidthSet = + (uint8_t) (ht_caps->supportedChannelWidthSet ? + assoc_rsp->HTInfo.recommendedTxWidthSet : + ht_caps->supportedChannelWidthSet); + sta_ds->htLsigTXOPProtection = + (uint8_t) ht_caps->lsigTXOPProtection; + sta_ds->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState)ht_caps->mimoPowerSave; + sta_ds->htMaxAmsduLength = + (uint8_t) ht_caps->maximalAMSDUsize; + sta_ds->htAMpduDensity = ht_caps->mpduDensity; + sta_ds->htDsssCckRate40MHzSupport = + (uint8_t) ht_caps->dsssCckMode40MHz; + sta_ds->htShortGI20Mhz = + (uint8_t) ht_caps->shortGI20MHz; + sta_ds->htShortGI40Mhz = + (uint8_t) ht_caps->shortGI40MHz; + sta_ds->htMaxRxAMpduFactor = + ht_caps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(mac_ctx, &highest_rxrate, + ht_caps->supportedMCSSet); + sta_ds->supportedRates.rxHighestDataRate = + highest_rxrate; + /* + * This is for AP as peer STA and we are INFRA STA + *.We will put APs offset in dph node which is peer STA + */ + sta_ds->htSecondaryChannelOffset = + (uint8_t) assoc_rsp->HTInfo.secondaryChannelOffset; + /* + * FIXME_AMPDU + * In the future, may need to check for + * "assoc.HTCaps.delayedBA" + * For now, it is IMMEDIATE BA only on ALL TID's + */ + sta_ds->baPolicyFlag = 0xFF; + } +} + +/** + * lim_update_assoc_sta_datas() - Updates station Descriptor + * mac_ctx: Pointer to Global MAC structure + * sta_ds: Station Descriptor in DPH + * assoc_rsp: Pointer to Association Response Structure + * session_entry : PE session Entry + * + * This function is called to Update the Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +void lim_update_assoc_sta_datas(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + uint32_t phy_mode; + bool qos_mode; + tDot11fIEVHTCaps *vht_caps = NULL; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + sta_ds->staType = STA_ENTRY_SELF; + limGetQosMode(session_entry, &qos_mode); + sta_ds->mlmStaContext.authType = session_entry->limCurrentAuthType; + + /* Add capabilities information, rates and AID */ + sta_ds->mlmStaContext.capabilityInfo = assoc_rsp->capabilityInfo; + sta_ds->shortPreambleEnabled = + (uint8_t) assoc_rsp->capabilityInfo.shortPreamble; + + /* Update HT Capabilites only when the self mode supports HT */ + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) + lim_update_stads_htcap(mac_ctx, sta_ds, assoc_rsp); + +#ifdef WLAN_FEATURE_11AC + if (assoc_rsp->VHTCaps.present) + vht_caps = &assoc_rsp->VHTCaps; + else if (assoc_rsp->vendor2_ie.VHTCaps.present) + vht_caps = &assoc_rsp->vendor2_ie.VHTCaps; + + if (IS_DOT11_MODE_VHT(session_entry->dot11mode)) { + if ((vht_caps != NULL) && vht_caps->present) { + sta_ds->mlmStaContext.vhtCapability = + vht_caps->present; + /* + * If 11ac is supported and if the peer is + * sending VHT capabilities, + * then htMaxRxAMpduFactor should be + * overloaded with VHT maxAMPDULenExp + */ + sta_ds->htMaxRxAMpduFactor = vht_caps->maxAMPDULenExp; + if (session_entry->htSupportedChannelWidthSet) { + if (assoc_rsp->VHTOperation.present) + sta_ds->vhtSupportedChannelWidthSet = + assoc_rsp->VHTOperation.chanWidth; + else + sta_ds->vhtSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } + } + if (lim_populate_peer_rate_set(mac_ctx, &sta_ds->supportedRates, + assoc_rsp->HTCaps.supportedMCSSet, + false, session_entry, + vht_caps) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not get rateset and extended rate set")); + return; + } +#else + if (lim_populate_peer_rate_set(mac_ctx, &sta_ds->supportedRates, + assoc_rsp->HTCaps.supportedMCSSet, + false, session_entry) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not get rateset and extended rate set")); + return; + } +#endif +#ifdef WLAN_FEATURE_11AC + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtRxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; +#endif + /* If one of the rates is 11g rates, set the ERP mode. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + sirIsArate(sta_ds->supportedRates.llaRates[0] & 0x7f)) + sta_ds->erpEnabled = eHAL_SET; + + /* Could not get prop rateset from CFG. Log error. */ + sta_ds->qosMode = 0; + sta_ds->lleEnabled = 0; + + /* update TSID to UP mapping */ + if (qos_mode) { + if (assoc_rsp->edcaPresent) { + tSirRetStatus status; + status = + sch_beacon_edca_process(mac_ctx, + &assoc_rsp->edca, session_entry); + lim_log(mac_ctx, LOG2, + "Edca set update based on AssocRsp: status %d", + status); + if (status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Edca error in AssocResp ")); + } else { + /* update default tidmap based on ACM */ + sta_ds->qosMode = 1; + sta_ds->lleEnabled = 1; + } + } + } + + sta_ds->wmeEnabled = 0; + sta_ds->wsmEnabled = 0; + if (session_entry->limWmeEnabled && assoc_rsp->wmeEdcaPresent) { + tSirRetStatus status; + status = sch_beacon_edca_process(mac_ctx, &assoc_rsp->edca, + session_entry); + lim_log(mac_ctx, LOGW, + "WME Edca set update based on AssocRsp: status %d", + status); + + if (status != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("WME Edca error in AssocResp - ignoring")); + + else { + /* update default tidmap based on HashACM */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } + } else { + /* + * We received assoc rsp from a legacy AP. + * So fill in the default local EDCA params. + * This is needed (refer to bug #14989) as we'll + * be passing the gLimEdcaParams to HAL in + * lim_process_sta_mlm_add_bss_rsp(). + */ + sch_set_default_edca_params(mac_ctx, session_entry); + } + + if (qos_mode && (!sta_ds->qosMode) && + sta_ds->mlmStaContext.htCapability) { + /* + * Enable QOS for all HT AP's even though WMM + * or 802.11E IE is not present + */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) + sta_ds->rmfEnabled = 1; +#endif +} + +/** + * @function : lim_update_re_assoc_globals + * + * @brief : This function is called to Update the Globals (LIM) during ReAssoc. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAssocRsp - Pointer to Association Response Structure + * + * @return None + */ + +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry) +{ + /* Update the current Bss Information */ + cdf_mem_copy(psessionEntry->bssId, + psessionEntry->limReAssocbssId, sizeof(tSirMacAddr)); + psessionEntry->currentOperChannel = psessionEntry->limReassocChannelId; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSupportedChannelWidthSet; + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->reAssocHtRecommendedTxWidthSet; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSecondaryChannelOffset; + psessionEntry->limCurrentBssCaps = psessionEntry->limReassocBssCaps; + psessionEntry->limCurrentBssQosCaps = + psessionEntry->limReassocBssQosCaps; + psessionEntry->limCurrentBssPropCap = + psessionEntry->limReassocBssPropCap; + + cdf_mem_copy((uint8_t *) &psessionEntry->ssId, + (uint8_t *) &psessionEntry->limReassocSSID, + psessionEntry->limReassocSSID.length + 1); + + /* Store assigned AID for TIM processing */ + psessionEntry->limAID = pAssocRsp->aid & 0x3FFF; + /** Set the State Back to ReAssoc Rsp*/ + psessionEntry->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + +} +#ifdef WLAN_FEATURE_VOWIFI_11R +/** + * lim_update_ric_data() - update session with ric data + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with RIC data. + * + * Return: None + */ +static void lim_update_ric_data(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->ricData != NULL) { + cdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + } + if (assoc_rsp->ricPresent) { + session_entry->RICDataLen = + assoc_rsp->num_RICData * sizeof(tDot11fIERICDataDesc); + session_entry->ricData = + cdf_mem_malloc(session_entry->RICDataLen); + if (NULL == session_entry->ricData) { + lim_log(mac_ctx, LOGE, + FL("Assoc res/RIC: Unable to allocate memory")); + session_entry->RICDataLen = 0; + } else { + cdf_mem_copy(session_entry->ricData, + &assoc_rsp->RICData[0], + session_entry->RICDataLen); + } + } else { + lim_log(mac_ctx, LOG1, + FL("Ric is not present,Set RICDataLen & RicData to 0")); + session_entry->RICDataLen = 0; + session_entry->ricData = NULL; + } + return; +} +#endif + +#ifdef FEATURE_WLAN_ESE + +/** + * lim_update_ese_tspec() - update session with Tspec info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with Tspec data. + * + * Return: None + */ +static void lim_update_ese_tspec(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->tspecIes != NULL) { + cdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + } + if (assoc_rsp->tspecPresent) { + session_entry->tspecLen = + assoc_rsp->num_tspecs * sizeof(tDot11fIEWMMTSPEC); + session_entry->tspecIes = + cdf_mem_malloc(session_entry->tspecLen); + if (NULL == session_entry->tspecIes) { + lim_log(mac_ctx, LOGE, + FL("Assoc Rsp/Tspec:Fail to allocate memory")); + session_entry->tspecLen = 0; + } else { + cdf_mem_copy(session_entry->tspecIes, + &assoc_rsp->TSPECInfo[0], + session_entry->tspecLen); + } + lim_log(mac_ctx, LOG1, FL(" Tspec EID present in assoc rsp ")); + } else { + session_entry->tspecLen = 0; + session_entry->tspecIes = NULL; + lim_log(mac_ctx, LOG1, + FL(" Tspec EID *NOT* present in assoc rsp ")); + } + return; +} + +/** + * lim_update_ese_tsm() - update session with TSM info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with TSM IE data and send + * eWNI_TSM_IE_IND to SME. + * + * Return: None + */ +static void lim_update_ese_tsm(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + uint8_t cnt = 0; + tpEseTSMContext tsm_ctx; + + lim_log(mac_ctx, LOG1, + FL("TSM IE Present in Reassoc Rsp")); + /* + * Start the TSM timer only if the TSPEC + * Ie is present in the reassoc rsp + */ + if (!assoc_rsp->tspecPresent) { + lim_log(mac_ctx, LOGE, + FL("TSM present but TSPEC IE not present")); + return; + } + tsm_ctx = &session_entry->eseContext.tsm; + /* Find the TSPEC IE with VO user priority */ + for (cnt = 0; cnt < assoc_rsp->num_tspecs; cnt++) { + if (upToAc(assoc_rsp->TSPECInfo[cnt].user_priority) == + EDCA_AC_VO) { + tsm_ctx->tid = + assoc_rsp->TSPECInfo[cnt].user_priority; + cdf_mem_copy(&tsm_ctx->tsmInfo, + &assoc_rsp->tsmIE, sizeof(tSirMacESETSMIE)); +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_tsm_ie_ind(mac_ctx, + session_entry, assoc_rsp->tsmIE.tsid, + assoc_rsp->tsmIE.state, + assoc_rsp->tsmIE.msmt_interval); +#else + limActivateTSMStatsTimer(mac_ctx, session_entry); +#endif + if (tsm_ctx->tsmInfo.state) + tsm_ctx->tsmMetrics.RoamingCount++; + break; + } + } +} +#endif + +/** + * lim_update_stads_ext_cap() - update sta ds with ext cap + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update STA DS with ext capablities. + * + * Return: None + */ +static void lim_update_stads_ext_cap(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp, + tpDphHashNode sta_ds) +{ + struct s_ext_cap *ext_cap; + if (!assoc_rsp->ExtCap.present) { + sta_ds->timingMeasCap = 0; +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = false; + session_entry->tdls_chan_swit_prohibited = false; +#endif + lim_log(mac_ctx, LOG1, FL("ExtCap not present")); + return; + } + + ext_cap = (struct s_ext_cap *)assoc_rsp->ExtCap.bytes; + lim_set_stads_rtt_cap(sta_ds, ext_cap, mac_ctx); +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = ext_cap->tdls_prohibited; + session_entry->tdls_chan_swit_prohibited = + ext_cap->tdls_chan_swit_prohibited; + lim_log(mac_ctx, LOG1, + FL("ExtCap: tdls_prohibited:%d, tdls_chan_swit_prohibited: %d"), + ext_cap->tdls_prohibited, + ext_cap->tdls_chan_swit_prohibited); +#endif +} + +/** + * lim_process_assoc_rsp_frame() - Processes assoc response + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info - A pointer to Rx packet info structure + * @sub_type - Indicates whether it is Association Response (=0) or + * Reassociation Response (=1) frame + * + * This function is called by limProcessMessageQueue() upon + * Re/Association Response frame reception. + * + * Return: None + */ + +void +lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, uint8_t subtype, tpPESession session_entry) +{ + uint8_t *body; + uint16_t caps, ie_len; + uint32_t frame_len; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr hdr = NULL; + tSirMacCapabilityInfo mac_capab; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + tLimMlmAssocCnf assoc_cnf; + tSchBeaconStruct *beacon; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t sme_sessionid = 0; +#endif + tCsrRoamSession *roam_session; + + /* Initialize status code to success. */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + else +#endif + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + sme_sessionid = session_entry->smeSessionId; +#endif + assoc_cnf.resultCode = eSIR_SME_SUCCESS; + /* Update PE session Id */ + assoc_cnf.sessionId = session_entry->peSessionId; + if (hdr == NULL) { + lim_log(mac_ctx, LOGE, + FL("LFR3: Reassoc response packet header is NULL")); + return; + } else if (hdr->sa == NULL) { + lim_log(mac_ctx, LOGE, + FL("LFR3: Reassoc resp packet source address is NULL")); + return; + } + + lim_log(mac_ctx, LOG1, + FL("received Re/Assoc(%d) resp on sessionid: %d systemrole: %d" + "and mlmstate: %d RSSI %d from " MAC_ADDRESS_STR), subtype, + session_entry->peSessionId, GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limMlmState, + (uint) abs((int8_t) WMA_GET_RX_RSSI_DB(rx_pkt_info)), + MAC_ADDR_ARRAY(hdr->sa)); + + beacon = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + /* + * Should not have received Re/Association + * Response frame on AP. Log error + */ + lim_log(mac_ctx, LOGE, + FL("Should not recieved Re/Assoc Response in role %d "), + GET_LIM_SYSTEM_ROLE(session_entry)); + cdf_mem_free(beacon); + return; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) { + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + frame_len = mac_ctx->roam.reassocRespLen - SIR_MAC_HDR_LEN_3A; + } else { +#endif + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +} +#endif + if (((subtype == LIM_ASSOC) && + (session_entry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE)) || + ((subtype == LIM_REASSOC) && + ((session_entry->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + && (session_entry->limMlmState != + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) +#endif + ))) { + /* Received unexpected Re/Association Response frame */ + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, + FL("Recieved Re/Assoc rsp in unexpected " + "state %d on session=%d"), + session_entry->limMlmState, session_entry->peSessionId); +#endif + if (!hdr->fc.retry) { + if (!(mac_ctx->lim.retry_packet_cnt & 0xf)) { + lim_log(mac_ctx, LOGE, + FL("recvd Re/Assoc rsp:not a retry frame")); + lim_print_mlm_state(mac_ctx, LOGE, + session_entry->limMlmState); + } else { + mac_ctx->lim.retry_packet_cnt++; + } + } + cdf_mem_free(beacon); + return; + } + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (subtype == LIM_ASSOC) { + if (!cdf_mem_compare + (hdr->sa, current_bssid, sizeof(tSirMacAddr))) { + /* + * Received Association Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Assoc Failure Timeout + */ + lim_log(mac_ctx, LOGW, + FL("received AssocRsp from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + cdf_mem_free(beacon); + return; + } + } else { + if (!cdf_mem_compare + (hdr->sa, session_entry->limReAssocbssId, + sizeof(tSirMacAddr))) { + /* + * Received Reassociation Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Reassoc Failure Timeout. + */ + lim_log(mac_ctx, LOGW, + FL("received ReassocRsp from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + cdf_mem_free(beacon); + return; + } + } + + assoc_rsp = cdf_mem_malloc(sizeof(*assoc_rsp)); + if (NULL == assoc_rsp) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed in AssocRsp")); + cdf_mem_free(beacon); + return; + } + /* Get pointer to Re/Association Response frame body */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) + body = mac_ctx->roam.pReassocResp + SIR_MAC_HDR_LEN_3A; + else +#endif + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + /* parse Re/Association Response frame. */ + if (sir_convert_assoc_resp_frame2_struct(mac_ctx, body, + frame_len, assoc_rsp) == eSIR_FAILURE) { + cdf_mem_free(assoc_rsp); + lim_log(mac_ctx, LOGE, + FL("Parse error Assoc resp subtype %d," "length=%d"), + frame_len, subtype); + cdf_mem_free(beacon); + return; + } + + if (!assoc_rsp->suppRatesPresent) { + lim_log(mac_ctx, LOGE, + FL("assoc response does not have supported rate set")); + cdf_mem_copy(&assoc_rsp->supportedRates, + &session_entry->rateSet, + sizeof(tSirMacRateSet)); + } + + assoc_cnf.protStatusCode = assoc_rsp->statusCode; + if (session_entry->assocRsp != NULL) { + lim_log(mac_ctx, LOGW, + FL("session_entry->assocRsp is not NULL freeing it " + "and setting NULL")); + cdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + } + + session_entry->assocRsp = cdf_mem_malloc(frame_len); + if (NULL == session_entry->assocRsp) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory for assoc res,len=%d"), + frame_len); + } else { + /* + * Store the Assoc response. This is sent + * to csr/hdd in join cnf response. + */ + cdf_mem_copy(session_entry->assocRsp, body, frame_len); + session_entry->assocRspLen = frame_len; + } + +#ifdef WLAN_FEATURE_VOWIFI_11R + lim_update_ric_data(mac_ctx, session_entry, assoc_rsp); +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_session = + &mac_ctx->roam.roamSession[sme_sessionid]; + if (assoc_rsp->FTInfo.R0KH_ID.present) { + roam_session->ftSmeContext.r0kh_id_len = + assoc_rsp->FTInfo.R0KH_ID.num_PMK_R0_ID; + cdf_mem_copy(roam_session->ftSmeContext.r0kh_id, + assoc_rsp->FTInfo.R0KH_ID.PMK_R0_ID, + roam_session->ftSmeContext.r0kh_id_len); + } else { + roam_session->ftSmeContext.r0kh_id_len = 0; + cdf_mem_zero(roam_session->ftSmeContext.r0kh_id, + SIR_ROAM_R0KH_ID_MAX_LEN); + } +#endif + +#ifdef FEATURE_WLAN_ESE + lim_update_ese_tspec(mac_ctx, session_entry, assoc_rsp); +#endif + + if (assoc_rsp->capabilityInfo.ibss) { + /* + * Received Re/Association Response from peer + * with IBSS capability set. + * Ignore the frame and wait until Re/assoc + * failure timeout. + */ + lim_log(mac_ctx, LOGE, + FL("received Re/AssocRsp frame with IBSS capability")); + cdf_mem_free(assoc_rsp); + cdf_mem_free(beacon); + return; + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) + != eSIR_SUCCESS) { + cdf_mem_free(assoc_rsp); + cdf_mem_free(beacon); + lim_log(mac_ctx, LOGP, FL("could not retrieve Capabilities ")); + return; + } + lim_copy_u16((uint8_t *) &mac_capab, caps); + + /* Stop Association failure timer */ + if (subtype == LIM_ASSOC) + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + else + { + /* Stop Reassociation failure timer */ +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + mac_ctx->lim.reAssocRetryAttempt = 0; + if ((NULL != mac_ctx->lim.pSessionEntry) + && (NULL != + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq)) { + cdf_mem_free( + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq); + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq = + NULL; + } +#endif + lim_deactivate_and_change_timer(mac_ctx, + eLIM_REASSOC_FAIL_TIMER); + } + + if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS +#ifdef WLAN_FEATURE_11W + && assoc_rsp->statusCode != eSIR_MAC_TRY_AGAIN_LATER +#endif + ) { + /* + *Re/Association response was received + * either with failure code. + */ + lim_log(mac_ctx, LOGE, + FL("received Re/AssocRsp frame failure code %d"), + assoc_rsp->statusCode); + /* + * Need to update 'association failure' error counter + * along with STATUS CODE + * Return Assoc confirm to SME with received failure code + */ + assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + goto assocReject; + } else if ((assoc_rsp->aid & 0x3FFF) > 2007) { + /* + * Re/Association response was received + * with invalid AID value + */ + lim_log(mac_ctx, LOGE, FL("received Re/AssocRsp frame with" + "invalid aid %X"), assoc_rsp->aid); + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + hdr->sa, session_entry, false); + goto assocReject; + } + /* + * Association Response received with success code + * Set the link state to POSTASSOC now that we have received + * assoc/reassoc response + * NOTE: for BTAMP case, it is being handled in + * lim_process_mlm_assoc_req + */ +#ifdef WLAN_FEATURE_11W + if (assoc_rsp->statusCode == eSIR_MAC_TRY_AGAIN_LATER) { + if (assoc_rsp->TimeoutInterval.present && + (assoc_rsp->TimeoutInterval.timeoutType == + SIR_MAC_TI_TYPE_ASSOC_COMEBACK)) { + uint16_t timeout_value = + assoc_rsp->TimeoutInterval.timeoutValue; + if (timeout_value < 10) { + /* + * if this value is less than 10 then our timer + * will fail to start and due to this we will + * never re-attempt. Better modify the timer + * value here. + */ + timeout_value = 10; + } + lim_log(mac_ctx, LOG1, + FL("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER " + " recvd.Starting timer to wait timeout=%d."), + timeout_value); + if (CDF_STATUS_SUCCESS != + cdf_mc_timer_start( + &session_entry->pmfComebackTimer, + timeout_value)) { + lim_log(mac_ctx, LOGE, + FL("Failed to start comeback timer.")); + } + } else { + lim_log(mac_ctx, LOGW, + FL("ASSOC resp with try again event recvd. " + "But try again time interval IE is wrong.")); + } + cdf_mem_free(beacon); + cdf_mem_free(assoc_rsp); + return; + } +#endif + if (!((session_entry->bssType == eSIR_BTAMP_STA_MODE) || + ((session_entry->bssType == eSIR_BTAMP_AP_MODE) && + LIM_IS_BT_AMP_STA_ROLE(session_entry)))) { + if (lim_set_link_state + (mac_ctx, eSIR_LINK_POSTASSOC_STATE, + session_entry->bssId, + session_entry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Set link state to POSTASSOC failed")); + cdf_mem_free(beacon); + cdf_mem_free(assoc_rsp); + return; + } + } + if (subtype == LIM_REASSOC) { + lim_log + (mac_ctx, LOG1, FL("Successfully Reassociated with BSS")); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + session_entry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif +#ifdef FEATURE_WLAN_ESE + if (assoc_rsp->tsmPresent) + lim_update_ese_tsm(mac_ctx, session_entry, assoc_rsp); +#endif + if (session_entry->pLimMlmJoinReq) { + cdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + + session_entry->limAssocResponseData = (void *)assoc_rsp; + /* + * Store the ReAssocRsp Frame in DphTable + * to be used during processing DelSta and + * DelBss to send AddBss again + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("could not get hash entry at DPH for")); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + assoc_cnf.resultCode = + eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, hdr->sa, + session_entry, false); + goto assocReject; + } +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("Sending self sta")); +#endif + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, + session_entry); + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, + session_entry); + /* Send the active EDCA parameters to HAL */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!session_entry->bRoamSynchInProgress) { +#endif + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + sta_ds->bssId); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } +#endif + lim_add_ft_sta_self(mac_ctx, (assoc_rsp->aid & 0x3FFF), + session_entry); + cdf_mem_free(beacon); + return; + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + /* + * If we're re-associating to the same BSS, + * we don't want to invoke delete STA, delete + * BSS, as that would remove the already + * established TSPEC. Just go ahead and re-add + * the BSS, STA with new capability information. + * However, if we're re-associating to a different + * BSS, then follow thru with del STA, del BSS, + * add BSS, add STA. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) + lim_handle_add_bss_in_re_assoc_context(mac_ctx, sta_ds, + session_entry); + else { + /* + * reset the uapsd mask settings since + * we're re-associating to new AP + */ + session_entry->gUapsdPerAcDeliveryEnableMask = 0; + session_entry->gUapsdPerAcTriggerEnableMask = 0; + + if (lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Could not cleanup the rx path")); + goto assocReject; + } + } + cdf_mem_free(beacon); + return; + } + lim_log(mac_ctx, LOG1, + FL("Successfully Associated with BSS " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); +#ifdef FEATURE_WLAN_ESE + if (session_entry->eseContext.tsm.tsmInfo.state) + session_entry->eseContext.tsm.tsmMetrics.RoamingCount = 0; +#endif + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + + /* STA entry was created during pre-assoc state. */ + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + /* Could not add hash table entry */ + lim_log(mac_ctx, LOGE, FL("could not get hash entry at DPH ")); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_SME_SUCCESS; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + cdf_mem_free(assoc_rsp); + cdf_mem_free(beacon); + return; + } + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, session_entry); + /* + * Extract the AP capabilities from the beacon that + * was received earlier + */ + ie_len = lim_get_ielen_from_bss_description( + &session_entry->pLimJoinReq->bssDescription); + lim_extract_ap_capabilities(mac_ctx, + (uint8_t *) session_entry->pLimJoinReq->bssDescription.ieFields, + ie_len, + beacon); + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac_ctx, beacon, + session_entry); + + if (beacon->erpPresent) { + if (beacon->erpIEInfo.barkerPreambleMode) + session_entry->beaconParams.fShortPreamble = false; + else + session_entry->beaconParams.fShortPreamble = true; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_CONNECTED, session_entry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + if (assoc_rsp->QosMapSet.present) + cdf_mem_copy(&session_entry->QosMapSet, + &assoc_rsp->QosMapSet, sizeof(tSirQosMapSet)); + else + cdf_mem_zero(&session_entry->QosMapSet, sizeof(tSirQosMapSet)); + + lim_update_stads_ext_cap(mac_ctx, session_entry, assoc_rsp, sta_ds); + /* Update the BSS Entry, this entry was added during preassoc. */ + if (eSIR_SUCCESS == lim_sta_send_add_bss(mac_ctx, assoc_rsp, + beacon, + &session_entry->pLimJoinReq->bssDescription, true, + session_entry)) { + cdf_mem_free(assoc_rsp); + cdf_mem_free(beacon); + return; + } else { + lim_log(mac_ctx, LOGE, FL("could not update the bss entry")); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + } + +assocReject: + if ((subtype == LIM_ASSOC) +#ifdef WLAN_FEATURE_VOWIFI_11R + || ((subtype == LIM_REASSOC) + && (session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE)) +#endif + ) { + lim_log(mac_ctx, LOGE, FL("Assoc Rejected by the peer. " + "mlmestate: %d sessionid %d Reason: %d MACADDR:" + MAC_ADDRESS_STR), + session_entry->limMlmState, + session_entry->peSessionId, + assoc_cnf.resultCode, MAC_ADDR_ARRAY(hdr->sa)); + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + if (session_entry->pLimMlmJoinReq) { + cdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (subtype == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + } +#ifdef WLAN_FEATURE_VOWIFI_11R + else { + assoc_cnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *)&assoc_cnf); + } +#endif + } else { + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_REFUSED, + assoc_cnf.protStatusCode, + session_entry); + } + + cdf_mem_free(beacon); + cdf_mem_free(assoc_rsp); + return; +} diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c new file mode 100644 index 0000000000..9871cff47c --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -0,0 +1,1929 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_auth_frame.cc contains the code + * for processing received Authentication Frame. + * Author: Chandra Modumudi + * Date: 03/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/12/2010 js To support Shared key authentication at AP side + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft.h" +#endif +#include "cds_utils.h" + +/** + * is_auth_valid + * + ***FUNCTION: + * This function is called by lim_process_auth_frame() upon Authentication + * frame reception. + * + ***LOGIC: + * This function is used to test validity of auth frame: + * - AUTH1 and AUTH3 must be received in AP mode + * - AUTH2 and AUTH4 must be received in STA mode + * - AUTH3 and AUTH4 must have challenge text IE, that is,'type' field has been set to + * SIR_MAC_CHALLENGE_TEXT_EID by parser + * - + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param *auth - Pointer to extracted auth frame body + * + * @return 0 or 1 (Valid) + */ + +static inline unsigned int is_auth_valid(tpAniSirGlobal pMac, + tpSirMacAuthFrameBody auth, + tpPESession sessionEntry) +{ + unsigned int valid = 1; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_1) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3)) && + (LIM_IS_STA_ROLE(sessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (LIM_IS_AP_ROLE(sessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (auth->type != SIR_MAC_CHALLENGE_TEXT_EID) && + (auth->authAlgoNumber != eSIR_SHARED_KEY)) + valid = 0; + + return valid; +} + +/** + * lim_process_auth_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon Authentication + * frame reception. + * + ***LOGIC: + * This function processes received Authentication frame and responds + * with either next Authentication frame in sequence to peer MAC entity + * or LIM_MLM_AUTH_IND on AP or LIM_MLM_AUTH_CNF on STA. + * + ***ASSUMPTIONS: + * + ***NOTE: + * 1. Authentication failures are reported to SME with same status code + * received from the peer MAC entity. + * 2. Authentication frame2/4 received with alogirthm number other than + * one requested in frame1/3 are logged with an error and auth confirm + * will be sent to SME only after auth failure timeout. + * 3. Inconsistency in the spec: + * On receiving Auth frame2, specs says that if WEP key mapping key + * or default key is NULL, Auth frame3 with a status code 15 (challenge + * failure to be returned to peer entity. However, section 7.2.3.10, + * table 14 says that status code field is 'reserved' for frame3 ! + * In the current implementation, Auth frame3 is returned with status + * code 15 overriding section 7.2.3.10. + * 4. If number pre-authentications reach configrable max limit, + * Authentication frame with 'unspecified failure' status code is + * returned to requesting entity. + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Rx packet info structure + * @return None + */ + +void +lim_process_auth_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody, keyId, cfgPrivacyOptImp, + defaultKey[SIR_MAC_KEY_LENGTH], + encrAuthFrame[LIM_ENCR_AUTH_BODY_LEN], plainBody[256]; + uint16_t frameLen; + uint32_t maxNumPreAuth, val; + tSirMacAuthFrameBody *pRxAuthFrameBody, rxAuthFrame, authFrame; + tpSirMacMgmtHdr pHdr; + struct tLimPreAuthNode *pAuthNode; + uint8_t decryptResult; + uint8_t *pChallenge; + uint32_t key_length = 8; + uint8_t challengeTextArray[SIR_MAC_AUTH_CHALLENGE_LENGTH]; + tpDphHashNode pStaDs = NULL; + uint16_t assocId = 0; + uint16_t curr_seq_num = 0; + + /* Get pointer to Authentication frame header and body */ + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (!frameLen) { + /* Log error */ + lim_log(pMac, LOGE, + FL("received Authentication frame with no body from ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGE); + + return; + } + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Auth frame from a BC/MC address */ + /* Log error and ignore it */ + lim_log(pMac, LOGE, FL ( + "received Auth frame from a BC/MC addr - ")); + PELOGE(lim_print_mac_addr(pMac, pHdr->sa, LOGE);) + + return; + } + curr_seq_num = (pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo); + + lim_log(pMac, LOG1, + FL("Sessionid: %d System role : %d limMlmState: %d :Auth " + "Frame Received: BSSID: " MAC_ADDRESS_STR " (RSSI %d)"), + psessionEntry->peSessionId, GET_LIM_SYSTEM_ROLE(psessionEntry), + psessionEntry->limMlmState, MAC_ADDR_ARRAY(pHdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_DB(pRxPacketInfo))); + + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + /* Restore default failure timeout */ + if (CDF_P2P_CLIENT_MODE == psessionEntry->pePersona + && psessionEntry->defaultAuthFailureTimeout) { + lim_log(pMac, LOG1, FL("Restore default failure timeout")); + cfg_set_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + psessionEntry->defaultAuthFailureTimeout); + } + /* / Determine if WEP bit is set in the FC or received MAC header */ + if (pHdr->fc.wep) { + /** + * WEP bit is set in FC of MAC header. + */ + + /* If TKIP counter measures enabled issue Deauth frame to station */ + if (psessionEntry->bTkipCntrMeasActive && + LIM_IS_AP_ROLE(psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Tkip counter measures Enabled, sending Deauth frame to")); + ) + lim_print_mac_addr(pMac, pHdr->sa, LOGE); + + lim_send_deauth_mgmt_frame(pMac, + eSIR_MAC_MIC_FAILURE_REASON, + pHdr->sa, psessionEntry, false); + return; + } + /* Extract key ID from IV (most 2 bits of 4th byte of IV) */ + + keyId = (*(pBody + 3)) >> 6; + + /** + * On STA in infrastructure BSS, Authentication frames received + * with WEP bit set in the FC must be rejected with challenge + * failure status code (wierd thing in the spec - this should have + * been rejected with unspecified failure or unexpected assertion + * of wep bit (this status code does not exist though) or + * Out-of-sequence-Authentication-Frame status code. + */ + + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame with wep bit set on role=%d " + MAC_ADDRESS_STR), + GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + + if (frameLen < LIM_ENCR_AUTH_BODY_LEN) { + /* Log error */ + lim_log(pMac, LOGE, + FL + ("Not enough size [%d] to decrypt received Auth frame"), + frameLen); + lim_print_mac_addr(pMac, pHdr->sa, LOGE); + + return; + } + if (LIM_IS_AP_ROLE(psessionEntry)) { + val = psessionEntry->privacy; + } else + /* Accept Authentication frame only if Privacy is implemented */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &val) != eSIR_SUCCESS) { + /** + * Could not get Privacy option + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL("could not retrieve Privacy option")); + } + + cfgPrivacyOptImp = (uint8_t) val; + if (cfgPrivacyOptImp) { + /** + * Privacy option is implemented. + * Check if the received frame is Authentication + * frame3 and there is a context for requesting STA. + * If not, reject with unspecified failure status code + */ + pAuthNode = lim_search_pre_auth_list(pMac, pHdr->sa); + + if (pAuthNode == NULL) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame from peer that has no preauth context with WEP bit set " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * No 'pre-auth' context exists for this STA that sent + * an Authentication frame with FC bit set. + * Send Auth frame4 with 'out of sequence' status code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } else { + /* / Change the auth-response timeout */ + lim_deactivate_and_change_per_sta_id_timer(pMac, + eLIM_AUTH_RSP_TIMER, + pAuthNode-> + authNodeIdx); + + /* / 'Pre-auth' status exists for STA */ + if ((pAuthNode->mlmState != + eLIM_MLM_WT_AUTH_FRAME3_STATE) && + (pAuthNode->mlmState != + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE)) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame from peer that is in state %d " + MAC_ADDRESS_STR), + pAuthNode->mlmState, + MAC_ADDR_ARRAY(pHdr->sa));) + /** + * Should not have received Authentication frame + * with WEP bit set in FC in other states. + * Reject by sending Authenticaton frame with + * out of sequence Auth frame status code. + */ + authFrame.authAlgoNumber = + eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + } + + val = SIR_MAC_KEY_LENGTH; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + tpSirKeys pKey; + pKey = + &psessionEntry-> + WEPKeyMaterial[keyId].key[0]; + cdf_mem_copy(defaultKey, pKey->key, + pKey->keyLength); + val = pKey->keyLength; + } else if (wlan_cfg_get_str(pMac, + (uint16_t) (WNI_CFG_WEP_DEFAULT_KEY_1 + + keyId), defaultKey, + &val) != eSIR_SUCCESS) { + /* / Could not get Default key from CFG. */ + /* Log error. */ + lim_log(pMac, LOGP, + FL + ("could not retrieve Default key")); + + /** + * Send Authentication frame + * with challenge failure status code + */ + + authFrame.authAlgoNumber = + eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + + return; + } + + key_length = val; + + decryptResult = lim_decrypt_auth_frame(pMac, defaultKey, + pBody, plainBody, key_length, + (uint16_t) (frameLen - + SIR_MAC_WEP_IV_LENGTH)); + if (decryptResult == LIM_DECRYPT_ICV_FAIL) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame from peer that failed decryption: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + /* / ICV failure */ + lim_delete_pre_auth_node(pMac, + pHdr->sa); + authFrame.authAlgoNumber = + eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + if ((sir_convert_auth_frame2_struct + (pMac, plainBody, frameLen - 8, + &rxAuthFrame) != eSIR_SUCCESS) || + (!is_auth_valid + (pMac, &rxAuthFrame, psessionEntry))) { + lim_log(pMac, LOGE, + FL + ("failed to convert Auth Frame to structure or Auth is not valid ")); + return; + } + } else { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame3 from peer that while privacy option is turned OFF " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + /** + * Privacy option is not implemented. + * So reject Authentication frame received with + * WEP bit set by sending Authentication frame + * with 'challenge failure' status code. This is + * another strange thing in the spec. Status code + * should have been 'unsupported algorithm' status code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, psessionEntry); + return; + } /* else if (wlan_cfg_get_int(CFG_PRIVACY_OPTION_IMPLEMENTED)) */ + } /* if (fc.wep) */ + else { + if ((sir_convert_auth_frame2_struct(pMac, pBody, + frameLen, + &rxAuthFrame) != eSIR_SUCCESS) + || (!is_auth_valid(pMac, &rxAuthFrame, psessionEntry))) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("failed to convert Auth Frame to structure or Auth is not valid ")); + ) + return; + } + } + + pRxAuthFrameBody = &rxAuthFrame; + + PELOGW(lim_log(pMac, LOGW, + FL + ("Received Auth frame with type=%d seqnum=%d, status=%d (%d)"), + (uint32_t) pRxAuthFrameBody->authAlgoNumber, + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber, + (uint32_t) pRxAuthFrameBody->authStatusCode, + (uint32_t) pMac->lim.gLimNumPreAuthContexts); + ) + + switch (pRxAuthFrameBody->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + /* AuthFrame 1 */ + + pStaDs = dph_lookup_hash_entry(pMac, pHdr->sa, + &assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs) { + tLimMlmDisassocReq *pMlmDisassocReq = NULL; + tLimMlmDeauthReq *pMlmDeauthReq = NULL; + tAniBool isConnected = eSIR_TRUE; + + pMlmDisassocReq = + pMac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (pMlmDisassocReq + && + (cdf_mem_compare + ((uint8_t *) pHdr->sa, + (uint8_t *) &pMlmDisassocReq->peerMacAddr, + sizeof(tSirMacAddr)))) { + PELOGE(lim_log + (pMac, LOGE, + FL("TODO:Ack for disassoc " + "frame is pending Issue delsta for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMlmDisassocReq-> + peerMacAddr)); + ) + lim_process_disassoc_ack_timeout(pMac); + isConnected = eSIR_FALSE; + } + pMlmDeauthReq = + pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (pMlmDeauthReq + && + (cdf_mem_compare + ((uint8_t *) pHdr->sa, + (uint8_t *) &pMlmDeauthReq->peerMacAddr, + sizeof(tSirMacAddr)))) { + PELOGE(lim_log + (pMac, LOGE, + FL("TODO:Ack for deauth frame " + "is pending Issue delsta for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMlmDeauthReq-> + peerMacAddr)); + ) + lim_process_deauth_ack_timeout(pMac); + isConnected = eSIR_FALSE; + } + + /* pStaDS != NULL and isConnected = 1 means the STA is already + * connected, But SAP received the Auth from that station. + * For non PMF connection send Deauth frame as STA will retry + * to connect back. + * + * For PMF connection the AP should not tear down or otherwise + * modify the state of the existing association until the + * SA-Query procedure determines that the original SA is + * invalid. + */ + if (isConnected +#ifdef WLAN_FEATURE_11W + && !pStaDs->rmfEnabled +#endif + ) { + lim_log(pMac, LOGE, + FL + ("STA is already connected but received auth frame" + "Send the Deauth and lim Delete Station Context" + "(staId: %d, assocId: %d) "), + pStaDs->staIndex, assocId); + lim_send_deauth_mgmt_frame(pMac, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) pHdr->sa, + psessionEntry, false); + lim_trigger_sta_deletion(pMac, pStaDs, + psessionEntry); + return; + } + } + /* / Check if there exists pre-auth context for this STA */ + pAuthNode = lim_search_pre_auth_list(pMac, pHdr->sa); + if (pAuthNode) { + /* / Pre-auth context exists for the STA */ + if (pHdr->fc.retry == 0 || + pAuthNode->seq_num != curr_seq_num) { + /** + * STA is initiating brand-new Authentication + * sequence after local Auth Response timeout. + * Or STA retrying to transmit First Auth frame due to packet drop OTA + * Delete Pre-auth node and fall through. + */ + if (pAuthNode->fTimerStarted) { + lim_deactivate_and_change_per_sta_id_timer + (pMac, eLIM_AUTH_RSP_TIMER, + pAuthNode->authNodeIdx); + } + PELOGE(lim_log + (pMac, LOGE, + FL + ("STA is initiating brand-new Authentication ...")); + ) + lim_delete_pre_auth_node(pMac, pHdr->sa); + /** + * SAP Mode:Disassociate the station and + * delete its entry if we have its entry + * already and received "auth" from the + * same station. + */ + + for (assocId = 0; assocId < psessionEntry->dph.dphHashTable.size; assocId++) /* Softap dphHashTable.size = 8 */ + { + pStaDs = + dph_get_hash_entry(pMac, assocId, + &psessionEntry->dph. + dphHashTable); + + if (NULL == pStaDs) + continue; + + if (pStaDs->valid) { + if (cdf_mem_compare + ((uint8_t *) &pStaDs-> + staAddr, + (uint8_t *) &(pHdr->sa), + (uint8_t) (sizeof + (tSirMacAddr)))) + break; + } + + pStaDs = NULL; + } + + if (NULL != pStaDs +#ifdef WLAN_FEATURE_11W + && !pStaDs->rmfEnabled +#endif + ) { + PELOGE(lim_log(pMac, LOGE, + FL + ("lim Delete Station Context (staId: %d, assocId: %d) "), + pStaDs->staIndex, + assocId); + ) + lim_send_deauth_mgmt_frame(pMac, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) + pAuthNode-> + peerMacAddr, + psessionEntry, + false); + lim_trigger_sta_deletion(pMac, pStaDs, + psessionEntry); + return; + } + } else { + /* + * This can happen when first authentication frame is received + * but ACK lost at STA side, in this case 2nd auth frame is already + * in transmission queue + * */ + PELOGE(lim_log + (pMac, LOGE, + FL + ("STA is initiating Authentication after ACK lost...")); + ) + return; + } + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &maxNumPreAuth) != + eSIR_SUCCESS) { + /** + * Could not get MaxNumPreAuth + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL("could not retrieve MaxNumPreAuth")); + } + if (pMac->lim.gLimNumPreAuthContexts == maxNumPreAuth && + !lim_delete_open_auth_pre_auth_node(pMac)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Max number of preauth context reached")); + ) + /** + * Maximum number of pre-auth contexts + * reached. Send Authentication frame + * with unspecified failure + */ + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody->authTransactionSeqNumber + 1; + authFrame.authStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, psessionEntry); + + return; + } + /* / No Pre-auth context exists for the STA. */ + if (lim_is_auth_algo_supported(pMac, (tAniAuthType) + pRxAuthFrameBody->authAlgoNumber, + psessionEntry)) { + switch (pRxAuthFrameBody->authAlgoNumber) { + case eSIR_OPEN_SYSTEM: + PELOGW(lim_log + (pMac, LOGW, + FL("=======> eSIR_OPEN_SYSTEM ...")); + ) + /* / Create entry for this STA in pre-auth list */ + pAuthNode = + lim_acquire_free_pre_auth_node(pMac, + &pMac->lim. + gLimPreAuthTimerTable); + if (pAuthNode == NULL) { + /* Log error */ + lim_log(pMac, LOGW, + FL + ("Max pre-auth nodes reached ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + + return; + } + + PELOG1(lim_log + (pMac, LOG1, + FL("Alloc new data: %x peer "), + pAuthNode); + lim_print_mac_addr(pMac, pHdr->sa, LOG1); + ) + + cdf_mem_copy((uint8_t *) pAuthNode-> + peerMacAddr, pHdr->sa, + sizeof(tSirMacAddr)); + + pAuthNode->mlmState = + eLIM_MLM_AUTHENTICATED_STATE; + pAuthNode->authType = (tAniAuthType) + pRxAuthFrameBody->authAlgoNumber; + pAuthNode->fSeen = 0; + pAuthNode->fTimerStarted = 0; + pAuthNode->seq_num = + ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)); + pAuthNode->timestamp = + cdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(pMac, pAuthNode); + + /** + * Send Authenticaton frame with Success + * status code. + */ + + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody->authTransactionSeqNumber + + 1; + authFrame.authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + lim_send_auth_mgmt_frame(pMac, &authFrame, pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + break; + + case eSIR_SHARED_KEY: + PELOGW(lim_log + (pMac, LOGW, + FL("=======> eSIR_SHARED_KEY ...")); + ) + if (LIM_IS_AP_ROLE(psessionEntry)) { + val = psessionEntry->privacy; + } else + if (wlan_cfg_get_int + (pMac, WNI_CFG_PRIVACY_ENABLED, + &val) != eSIR_SUCCESS) { + /** + * Could not get Privacy option + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve Privacy option")); + } + cfgPrivacyOptImp = (uint8_t) val; + if (!cfgPrivacyOptImp) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody-> + authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * Authenticator does not have WEP + * implemented. + * Reject by sending Authentication frame + * with Auth algorithm not supported status + * code. + */ + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody-> + authTransactionSeqNumber + 1; + authFrame.authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } else { + /* Create entry for this STA */ + /* in pre-auth list */ + pAuthNode = + lim_acquire_free_pre_auth_node(pMac, + &pMac-> + lim. + gLimPreAuthTimerTable); + if (pAuthNode == NULL) { + /* Log error */ + lim_log(pMac, LOGW, + FL + ("Max pre-auth nodes reached ")); + lim_print_mac_addr(pMac, pHdr->sa, + LOGW); + + return; + } + + cdf_mem_copy((uint8_t *) pAuthNode-> + peerMacAddr, pHdr->sa, + sizeof(tSirMacAddr)); + + pAuthNode->mlmState = + eLIM_MLM_WT_AUTH_FRAME3_STATE; + pAuthNode->authType = (tAniAuthType) + pRxAuthFrameBody->authAlgoNumber; + pAuthNode->fSeen = 0; + pAuthNode->fTimerStarted = 0; + pAuthNode->seq_num = + ((pHdr->seqControl.seqNumHi << + 4) | + (pHdr->seqControl.seqNumLo)); + pAuthNode->timestamp = + cdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(pMac, pAuthNode); + + PELOG1(lim_log + (pMac, LOG1, + FL + ("Alloc new data: %x id %d peer "), + pAuthNode, + pAuthNode->authNodeIdx); + ) + PELOG1(lim_print_mac_addr + (pMac, pHdr->sa, LOG1); + ) + /* / Create and activate Auth Response timer */ + if (tx_timer_change_context + (&pAuthNode->timer, + pAuthNode->authNodeIdx) != + TX_SUCCESS) { + /* / Could not start Auth response timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("Unable to chg context auth response timer for peer ")); + lim_print_mac_addr(pMac, pHdr->sa, + LOGP); + + /** + * Send Authenticaton frame with + * unspecified failure status code. + */ + + authFrame.authAlgoNumber = + pRxAuthFrameBody-> + authAlgoNumber; + authFrame. + authTransactionSeqNumber = + pRxAuthFrameBody-> + authTransactionSeqNumber + + 1; + authFrame.authStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, + &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + + lim_delete_pre_auth_node(pMac, + pHdr->sa); + return; + } + + lim_activate_auth_rsp_timer(pMac, + pAuthNode); + + pAuthNode->fTimerStarted = 1; + + /* get random bytes and use as */ + /* challenge text. If it fails we already have random stack bytes. */ + if (!CDF_IS_STATUS_SUCCESS + (cds_rand_get_bytes + (0, (uint8_t *) challengeTextArray, + SIR_MAC_AUTH_CHALLENGE_LENGTH))) { + lim_log(pMac, LOGE, + FL + ("Challenge text preparation failed in lim_process_auth_frame")); + } + + pChallenge = pAuthNode->challengeText; + + cdf_mem_copy(pChallenge, + (uint8_t *) + challengeTextArray, + sizeof + (challengeTextArray)); + + /** + * Sending Authenticaton frame with challenge. + */ + + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody-> + authTransactionSeqNumber + 1; + authFrame.authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + authFrame.type = + SIR_MAC_CHALLENGE_TEXT_EID; + authFrame.length = + SIR_MAC_AUTH_CHALLENGE_LENGTH; + cdf_mem_copy(authFrame.challengeText, + pAuthNode->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH); + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + } /* if (wlan_cfg_get_int(CFG_PRIVACY_OPTION_IMPLEMENTED)) */ + + break; + + default: + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * Responding party does not support the + * authentication algorithm requested by + * sending party. + * Reject by sending Authentication frame + * with auth algorithm not supported status code + */ + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody->authTransactionSeqNumber + + 1; + authFrame.authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } /* end switch(pRxAuthFrameBody->authAlgoNumber) */ + } /* if (lim_is_auth_algo_supported(pRxAuthFrameBody->authAlgoNumber)) */ + else { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * Responding party does not support the + * authentication algorithm requested by sending party. + * Reject Authentication with StatusCode=13. + */ + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody->authTransactionSeqNumber + 1; + authFrame.authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, psessionEntry); + return; + } /* end if (lim_is_auth_algo_supported(pRxAuthFrameBody->authAlgoNumber)) */ + break; + + case SIR_MAC_AUTH_FRAME_2: + /* AuthFrame 2 */ + + if (psessionEntry->limMlmState != eLIM_MLM_WT_AUTH_FRAME2_STATE) { +#ifdef WLAN_FEATURE_VOWIFI_11R + /** + * Check if a Reassociation is in progress and this is a + * Pre-Auth frame + */ + if ((LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) + && (psessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) + && (pRxAuthFrameBody->authStatusCode == + eSIR_MAC_SUCCESS_STATUS) + && (psessionEntry->ftPEContext.pFTPreAuthReq != + NULL) + && + (cdf_mem_compare + (psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthbssId, pHdr->sa, sizeof(tSirMacAddr)))) { + /* Update the FTIEs in the saved auth response */ + PELOGW(lim_log + (pMac, LOGW, + FL("received another PreAuth frame2" + " from peer " MAC_ADDRESS_STR + " in Smestate %d"), + MAC_ADDR_ARRAY(pHdr->sa), + psessionEntry->limSmeState); + ) + + psessionEntry->ftPEContext. + saved_auth_rsp_length = 0; + if ((pBody != NULL) + && (frameLen < MAX_FTIE_SIZE)) { + cdf_mem_copy(psessionEntry->ftPEContext. + saved_auth_rsp, pBody, + frameLen); + psessionEntry->ftPEContext. + saved_auth_rsp_length = frameLen; + } + } else +#endif + { + /** + * Received Authentication frame2 in an unexpected state. + * Log error and ignore the frame. + */ + + /* Log error */ + PELOG1(lim_log(pMac, LOG1, + FL + ("received Auth frame2 from peer in state %d, addr "), + psessionEntry->limMlmState); + ) + PELOG1(lim_print_mac_addr + (pMac, pHdr->sa, LOG1); + ) + } + + return; + + } + + if (!cdf_mem_compare((uint8_t *) pHdr->sa, + (uint8_t *) &pMac->lim.gpLimMlmAuthReq-> + peerMacAddr, sizeof(tSirMacAddr))) { + /** + * Received Authentication frame from an entity + * other than one request was initiated. + * Wait until Authentication Failure Timeout. + */ + + /* Log error */ + PELOGW(lim_log(pMac, LOGW, + FL + ("received Auth frame2 from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + + if (pRxAuthFrameBody->authStatusCode == + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS) { + /** + * Interoperability workaround: Linksys WAP4400N is returning + * wrong authType in OpenAuth response in case of + * SharedKey AP configuration. Pretend we don't see that, + * so upper layer can fallback to SharedKey authType, + * and successfully connect to the AP. + */ + if (pRxAuthFrameBody->authAlgoNumber != + pMac->lim.gpLimMlmAuthReq->authType) { + pRxAuthFrameBody->authAlgoNumber = + pMac->lim.gpLimMlmAuthReq->authType; + } + } + + if (pRxAuthFrameBody->authAlgoNumber != + pMac->lim.gpLimMlmAuthReq->authType) { + /** + * Received Authentication frame with an auth + * algorithm other than one requested. + * Wait until Authentication Failure Timeout. + */ + + /* Log error */ + PELOGW(lim_log(pMac, LOGW, + FL + ("received Auth frame2 for unexpected auth algo number %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + + if (pRxAuthFrameBody->authStatusCode == eSIR_MAC_SUCCESS_STATUS) { + if (pRxAuthFrameBody->authAlgoNumber == + eSIR_OPEN_SYSTEM) { + psessionEntry->limCurrentAuthType = + eSIR_OPEN_SYSTEM; + + pAuthNode = + lim_acquire_free_pre_auth_node(pMac, + &pMac->lim. + gLimPreAuthTimerTable); + + if (pAuthNode == NULL) { + /* Log error */ + lim_log(pMac, LOGW, + FL + ("Max pre-auth nodes reached ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + + return; + } + + PELOG1(lim_log + (pMac, LOG1, + FL("Alloc new data: %x peer "), + pAuthNode); + ) + PELOG1(lim_print_mac_addr + (pMac, pHdr->sa, LOG1); + ) + + cdf_mem_copy((uint8_t *) pAuthNode-> + peerMacAddr, + pMac->lim.gpLimMlmAuthReq-> + peerMacAddr, + sizeof(tSirMacAddr)); + pAuthNode->fTimerStarted = 0; + pAuthNode->authType = + pMac->lim.gpLimMlmAuthReq->authType; + pAuthNode->seq_num = + ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)); + pAuthNode->timestamp = + cdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(pMac, pAuthNode); + + lim_restore_from_auth_state(pMac, eSIR_SME_SUCCESS, + pRxAuthFrameBody-> + authStatusCode, + psessionEntry); + } /* if (pRxAuthFrameBody->authAlgoNumber == eSIR_OPEN_SYSTEM) */ + else { + /* Shared key authentication */ + + if (LIM_IS_AP_ROLE(psessionEntry)) { + val = psessionEntry->privacy; + } else + if (wlan_cfg_get_int + (pMac, WNI_CFG_PRIVACY_ENABLED, + &val) != eSIR_SUCCESS) { + /** + * Could not get Privacy option + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve Privacy option")); + } + cfgPrivacyOptImp = (uint8_t) val; + if (!cfgPrivacyOptImp) { + /** + * Requesting STA does not have WEP implemented. + * Reject with unsupported authentication algorithm + * Status code and wait until auth failure timeout + */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame from peer for unsupported auth algo %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody-> + authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + pRxAuthFrameBody-> + authTransactionSeqNumber + 1; + authFrame.authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } else { + + if (pRxAuthFrameBody->type != + SIR_MAC_CHALLENGE_TEXT_EID) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame with invalid challenge text IE")); + ) + + return; + } + + if (wlan_cfg_get_int + (pMac, + WNI_CFG_WEP_DEFAULT_KEYID, + &val) != eSIR_SUCCESS) { + /** + * Could not get Default keyId + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve Default keyId")); + } + keyId = (uint8_t) val; + + val = SIR_MAC_KEY_LENGTH; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + tpSirKeys pKey; + pKey = + &psessionEntry-> + WEPKeyMaterial + [keyId].key[0]; + cdf_mem_copy(defaultKey, + pKey->key, + pKey-> + keyLength); + } else + if (wlan_cfg_get_str + (pMac, + (uint16_t) + (WNI_CFG_WEP_DEFAULT_KEY_1 + + keyId), defaultKey, + &val) + != eSIR_SUCCESS) { + /* / Could not get Default key from CFG. */ + /* Log error. */ + lim_log(pMac, LOGP, + FL + ("could not retrieve Default key")); + + authFrame.authAlgoNumber = + pRxAuthFrameBody-> + authAlgoNumber; + authFrame. + authTransactionSeqNumber = + pRxAuthFrameBody-> + authTransactionSeqNumber + + 1; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame + (pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + + lim_restore_from_auth_state + (pMac, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + eSIR_MAC_UNSPEC_FAILURE_REASON, + psessionEntry); + + break; + } + key_length = val; + ((tpSirMacAuthFrameBody) + plainBody)->authAlgoNumber = + sir_swap_u16if_needed(pRxAuthFrameBody-> + authAlgoNumber); + ((tpSirMacAuthFrameBody) + plainBody)-> + authTransactionSeqNumber = + sir_swap_u16if_needed((uint16_t) + (pRxAuthFrameBody-> + authTransactionSeqNumber + 1)); + ((tpSirMacAuthFrameBody) + plainBody)->authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + ((tpSirMacAuthFrameBody) + plainBody)->type = + SIR_MAC_CHALLENGE_TEXT_EID; + ((tpSirMacAuthFrameBody) + plainBody)->length = + SIR_MAC_AUTH_CHALLENGE_LENGTH; + cdf_mem_copy((uint8_t*) ((tpSirMacAuthFrameBody) plainBody)->challengeText, + pRxAuthFrameBody->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH); + + lim_encrypt_auth_frame(pMac, keyId, + defaultKey, + plainBody, + encrAuthFrame, + key_length); + + psessionEntry->limMlmState = + eLIM_MLM_WT_AUTH_FRAME4_STATE; + MTRACE(mac_trace + (pMac, + TRACE_CODE_MLM_STATE, + psessionEntry-> + peSessionId, + psessionEntry-> + limMlmState)); + + lim_send_auth_mgmt_frame(pMac, + (tpSirMacAuthFrameBody) + encrAuthFrame, + pHdr->sa, + LIM_WEP_IN_FC, + psessionEntry); + + break; + } /* end if (!wlan_cfg_get_int(CFG_PRIVACY_OPTION_IMPLEMENTED)) */ + } /* end if (pRxAuthFrameBody->authAlgoNumber == eSIR_OPEN_SYSTEM) */ + } /* if (pRxAuthFrameBody->authStatusCode == eSIR_MAC_SUCCESS_STATUS) */ + else { + /** + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame from peer with failure code %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authStatusCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + lim_restore_from_auth_state(pMac, eSIR_SME_AUTH_REFUSED, + pRxAuthFrameBody-> + authStatusCode, + psessionEntry); + } /* end if (pRxAuthFrameBody->authStatusCode == eSIR_MAC_SUCCESS_STATUS) */ + + break; + + case SIR_MAC_AUTH_FRAME_3: + /* AuthFrame 3 */ + + if (pRxAuthFrameBody->authAlgoNumber != eSIR_SHARED_KEY) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame3 from peer with auth algo number %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * Received Authentication frame3 with algorithm other than + * Shared Key authentication type. Reject with Auth frame4 + * with 'out of sequence' status code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, psessionEntry); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + /** + * Check if wep bit was set in FC. If not set, + * reject with Authentication frame4 with + * 'challenge failure' status code. + */ + if (!pHdr->fc.wep) { + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame3 from peer with no WEP bit set " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + /* / WEP bit is not set in FC of Auth Frame3 */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + + pAuthNode = lim_search_pre_auth_list(pMac, pHdr->sa); + if (pAuthNode == NULL) { + /* Log error */ + PELOGE(lim_log(pMac, LOGW, + FL + ("received AuthFrame3 from peer that has no preauth context " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + /** + * No 'pre-auth' context exists for + * this STA that sent an Authentication + * frame3. + * Send Auth frame4 with 'out of sequence' + * status code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + + if (pAuthNode->mlmState == + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE) { + /* Log error */ + lim_log(pMac, LOGW, + FL + ("auth response timer timedout for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + + /** + * Received Auth Frame3 after Auth Response timeout. + * Reject by sending Auth Frame4 with + * Auth respone timeout Status Code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + + /* / Delete pre-auth context of STA */ + lim_delete_pre_auth_node(pMac, pHdr->sa); + + return; + } /* end switch (pAuthNode->mlmState) */ + + if (pRxAuthFrameBody->authStatusCode != + eSIR_MAC_SUCCESS_STATUS) { + /** + * Received Authenetication Frame 3 with status code + * other than success. Wait until Auth response timeout + * to delete STA context. + */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame3 from peer with status code %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authStatusCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + /** + * Check if received challenge text is same as one sent in + * Authentication frame3 + */ + + if (cdf_mem_compare(pRxAuthFrameBody->challengeText, + pAuthNode->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH)) { + /* / Challenge match. STA is autheticated ! */ + + /* / Delete Authentication response timer if running */ + lim_deactivate_and_change_per_sta_id_timer(pMac, + eLIM_AUTH_RSP_TIMER, + pAuthNode-> + authNodeIdx); + + pAuthNode->fTimerStarted = 0; + pAuthNode->mlmState = + eLIM_MLM_AUTHENTICATED_STATE; + + /** + * Send Authentication Frame4 with 'success' Status Code. + */ + authFrame.authAlgoNumber = eSIR_SHARED_KEY; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + break; + } else { + /* Log error */ + PELOGE(lim_log(pMac, LOGW, + FL("Challenge failure for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + /** + * Challenge Failure. + * Send Authentication frame4 with 'challenge failure' + * status code and wait until Auth response timeout to + * delete STA context. + */ + authFrame.authAlgoNumber = + pRxAuthFrameBody->authAlgoNumber; + authFrame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + authFrame.authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(pMac, &authFrame, + pHdr->sa, + LIM_NO_WEP_IN_FC, + psessionEntry); + return; + } + } /* if (pMac->lim.gLimSystemRole == eLIM_AP_ROLE || ... */ + + break; + + case SIR_MAC_AUTH_FRAME_4: + /* AuthFrame 4 */ + if (psessionEntry->limMlmState != eLIM_MLM_WT_AUTH_FRAME4_STATE) { + /** + * Received Authentication frame4 in an unexpected state. + * Log error and ignore the frame. + */ + + /* Log error */ + PELOG1(lim_log(pMac, LOG1, + FL + ("received unexpected Auth frame4 from peer in state %d, addr " + MAC_ADDRESS_STR), + psessionEntry->limMlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + if (pRxAuthFrameBody->authAlgoNumber != eSIR_SHARED_KEY) { + /** + * Received Authentication frame4 with algorithm other than + * Shared Key authentication type. + * Wait until Auth failure timeout to report authentication + * failure to SME. + */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame4 from peer with invalid auth algo %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody->authAlgoNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + if (!cdf_mem_compare((uint8_t *) pHdr->sa, + (uint8_t *) &pMac->lim.gpLimMlmAuthReq-> + peerMacAddr, sizeof(tSirMacAddr))) { + /** + * Received Authentication frame from an entity + * other than one to which request was initiated. + * Wait until Authentication Failure Timeout. + */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGW, + FL + ("received Auth frame4 from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + + if (pRxAuthFrameBody->authAlgoNumber != + pMac->lim.gpLimMlmAuthReq->authType) { + /** + * Received Authentication frame with an auth algorithm + * other than one requested. + * Wait until Authentication Failure Timeout. + */ + + PELOGE(lim_log(pMac, LOGE, + FL + ("received Authentication frame from peer with invalid auth seq number %d " + MAC_ADDRESS_STR), + pRxAuthFrameBody-> + authTransactionSeqNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + + if (pRxAuthFrameBody->authStatusCode == eSIR_MAC_SUCCESS_STATUS) { + /** + * Authentication Success ! + * Inform SME of same. + */ + psessionEntry->limCurrentAuthType = eSIR_SHARED_KEY; + + pAuthNode = + lim_acquire_free_pre_auth_node(pMac, + &pMac->lim. + gLimPreAuthTimerTable); + if (pAuthNode == NULL) { + /* Log error */ + lim_log(pMac, LOGW, + FL("Max pre-auth nodes reached ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + + return; + } + PELOG1(lim_log + (pMac, LOG1, FL("Alloc new data: %x peer "), + pAuthNode); + lim_print_mac_addr(pMac, pHdr->sa, LOG1); + ) + + cdf_mem_copy((uint8_t *) pAuthNode->peerMacAddr, + pMac->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + pAuthNode->fTimerStarted = 0; + pAuthNode->authType = + pMac->lim.gpLimMlmAuthReq->authType; + pAuthNode->seq_num = + ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)); + pAuthNode->timestamp = cdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(pMac, pAuthNode); + + lim_restore_from_auth_state(pMac, eSIR_SME_SUCCESS, + pRxAuthFrameBody-> + authStatusCode, psessionEntry); + + } /* if (pRxAuthFrameBody->authStatusCode == eSIR_MAC_SUCCESS_STATUS) */ + else { + /** + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + + /* Log error */ + PELOGE(lim_log + (pMac, LOGE, + FL("Authentication failure from peer " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + ) + + lim_restore_from_auth_state(pMac, eSIR_SME_AUTH_REFUSED, + pRxAuthFrameBody-> + authStatusCode, + psessionEntry); + } /* end if (pRxAuthFrameBody->Status == 0) */ + + break; + + default: + /* / Invalid Authentication Frame received. Ignore it. */ + + /* Log error */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Auth frame from peer with invalid auth seq " + "number %d " MAC_ADDRESS_STR), + pRxAuthFrameBody->authTransactionSeqNumber, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } /* end switch (pRxAuthFrameBody->authTransactionSeqNumber) */ +} /*** end lim_process_auth_frame() ***/ + +#ifdef WLAN_FEATURE_VOWIFI_11R + +/*---------------------------------------------------------------------- + * + * Pass the received Auth frame. This is possibly the pre-auth from the + * neighbor AP, in the same mobility domain. + * This will be used in case of 11r FT. + * + * !!!! This is going to be renoved for the next checkin. We will be creating + * the session before sending out the Auth. Thus when auth response + * is received we will have a session in progress. !!!!! + ***---------------------------------------------------------------------- + */ +tSirRetStatus lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd, + void *body) +{ + tpSirMacMgmtHdr pHdr; + tpPESession psessionEntry = NULL; + uint8_t *pBody; + uint16_t frameLen; + tSirMacAuthFrameBody rxAuthFrame; + tSirMacAuthFrameBody *pRxAuthFrameBody = NULL; + tSirRetStatus ret_status = eSIR_FAILURE; + int i; + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + pBody = WMA_GET_RX_MPDU_DATA(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + lim_log(pMac, LOG1, + FL("Auth Frame Received: BSSID " MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(pHdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_DB(pBd))); + + /* Auth frame has come on a new BSS, however, we need to find the session + * from where the auth-req was sent to the new AP + */ + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true && + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession == + true) { + /* Found the session */ + psessionEntry = &pMac->lim.gpSession[i]; + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession = + false; + } + } + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("Error: Unable to find session id while in pre-auth phase for FT")); + return eSIR_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq == NULL) { + lim_log(pMac, LOGE, FL("Error: No FT")); + /* No FT in progress. */ + return eSIR_FAILURE; + } + + if (frameLen == 0) { + lim_log(pMac, LOGE, FL("Error: Frame len = 0")); + return eSIR_FAILURE; + } +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_print_mac_addr(pMac, pHdr->bssId, LOG2); + lim_print_mac_addr(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + LOG2); + lim_log(pMac, LOG2, FL("seqControl 0x%X"), + ((pHdr->seqControl.seqNumHi << 8) | (pHdr->seqControl. + seqNumLo << 4) | (pHdr-> + seqControl. + fragNum))); +#endif + + /* Check that its the same bssId we have for preAuth */ + if (!cdf_mem_compare + (psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + pHdr->bssId, sizeof(tSirMacAddr))) { + lim_log(pMac, LOGE, FL("Error: Same bssid as preauth BSSID")); + /* In this case SME if indeed has triggered a */ + /* pre auth it will time out. */ + return eSIR_FAILURE; + } + + if (true == + psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + /* + * This is likely a duplicate for the same pre-auth request. + * PE/LIM already posted a response to SME. Hence, drop it. + * TBD: + * 1) How did we even receive multiple auth responses? + * 2) Do we need to delete pre-auth session? Suppose we + * previously received an auth resp with failure which + * would not have created the session and forwarded to SME. + * And, we subsequently received an auth resp with success + * which would have created the session. This will now be + * dropped without being forwarded to SME! However, it is + * very unlikely to receive auth responses from the same + * AP with different reason codes. + * NOTE: return eSIR_SUCCESS so that the packet is dropped + * as this was indeed a response from the BSSID we tried to + * pre-auth. + */ + PELOGE(lim_log(pMac, LOG1, "Auth rsp already posted to SME" + " (session %p, FT session %p)", psessionEntry, + psessionEntry); + ); + return eSIR_SUCCESS; + } else { + PELOGE(lim_log(pMac, LOGW, "Auth rsp not yet posted to SME" + " (session %p, FT session %p)", psessionEntry, + psessionEntry); + ); + psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = + true; + } + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("Pre-Auth response received from neighbor")); + lim_log(pMac, LOG1, FL("Pre-Auth done state")); +#endif + /* Stopping timer now, that we have our unicast from the AP */ + /* of our choice. */ + lim_deactivate_and_change_timer(pMac, eLIM_FT_PREAUTH_RSP_TIMER); + + /* Save off the auth resp. */ + if ((sir_convert_auth_frame2_struct(pMac, pBody, frameLen, &rxAuthFrame) != + eSIR_SUCCESS)) { + lim_log(pMac, LOGE, + FL("failed to convert Auth frame to struct")); + lim_handle_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0, + psessionEntry); + return eSIR_FAILURE; + } + pRxAuthFrameBody = &rxAuthFrame; + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(pMac, LOG1, + FL + ("Received Auth frame with type=%d seqnum=%d, status=%d (%d)"), + (uint32_t) pRxAuthFrameBody->authAlgoNumber, + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber, + (uint32_t) pRxAuthFrameBody->authStatusCode, + (uint32_t) pMac->lim.gLimNumPreAuthContexts); + ) +#endif + switch (pRxAuthFrameBody->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_2: + if (pRxAuthFrameBody->authStatusCode != eSIR_MAC_SUCCESS_STATUS) { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, "Auth status code received is %d", + (uint32_t) pRxAuthFrameBody->authStatusCode); + ); +#endif + if (eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS == + pRxAuthFrameBody->authStatusCode) + ret_status = eSIR_LIM_MAX_STA_REACHED_ERROR; + } else { + ret_status = eSIR_SUCCESS; + } + break; + + default: +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log + (pMac, LOGE, "Seq. no incorrect expected 2 received %d", + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber); + ) +#endif + break; + } + + /* Send the Auth response to SME */ + lim_handle_ft_pre_auth_rsp(pMac, ret_status, pBody, frameLen, psessionEntry); + + return ret_status; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R */ diff --git a/core/mac/src/pe/lim/lim_process_beacon_frame.c b/core/mac/src/pe/lim/lim_process_beacon_frame.c new file mode 100644 index 0000000000..3a72a69ba4 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_beacon_frame.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_beacon_frame.cc contains the code + * for processing Received Beacon Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" + +/** + * lim_process_beacon_frame() - to process beacon frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to RX packet info structure + * @session: A pointer to session + * + * This function is called by limProcessMessageQueue() upon Beacon + * frame reception. + * Note: + * 1. Beacons received in 'normal' state in IBSS are handled by + * Beacon Processing module. + * + * Return: none + */ + +void +lim_process_beacon_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + tSchBeaconStruct *bcn_ptr; + + mac_ctx->lim.gLimNumBeaconsRcvd++; + + /* + * here is it required to increment session specific heartBeat + * beacon counter + */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + lim_log(mac_ctx, LOG2, + FL("Received Beacon frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(rx_pkt_info)); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG2); + + /* Expect Beacon in any state as Scan is independent of LIM state */ + bcn_ptr = cdf_mem_malloc(sizeof(*bcn_ptr)); + if (NULL == bcn_ptr) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + /* Parse received Beacon */ + if (sir_convert_beacon_frame2_struct(mac_ctx, + rx_pkt_info, bcn_ptr) != + eSIR_SUCCESS) { + /* + * Received wrongly formatted/invalid Beacon. + * Ignore it and move on. + */ + lim_log(mac_ctx, LOGW, + FL("Received invalid Beacon in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + cdf_mem_free(bcn_ptr); + return; + } + /* + * during scanning, when any session is active, and + * beacon/Pr belongs to one of the session, fill up the + * following, TBD - HB couter + */ + if ((!session->lastBeaconDtimPeriod) && + (sir_compare_mac_addr(session->bssId, + bcn_ptr->bssid))) { + cdf_mem_copy((uint8_t *)&session->lastBeaconTimeStamp, + (uint8_t *) bcn_ptr->timeStamp, + sizeof(uint64_t)); + session->lastBeaconDtimCount = + bcn_ptr->tim.dtimCount; + session->lastBeaconDtimPeriod = + bcn_ptr->tim.dtimPeriod; + session->currentBssBeaconCnt++; + } + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_TSF, 0, bcn_ptr->timeStamp[0]);) + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, 0, + bcn_ptr->timeStamp[1]);) + lim_check_and_add_bss_description(mac_ctx, bcn_ptr, + rx_pkt_info, false, true); + + if ((mac_ctx->lim.gLimMlmState == + eLIM_MLM_WT_PROBE_RESP_STATE) || + (mac_ctx->lim.gLimMlmState == + eLIM_MLM_PASSIVE_SCAN_STATE)) { + lim_check_and_add_bss_description(mac_ctx, bcn_ptr, + rx_pkt_info, + ((mac_ctx->lim.gLimHalScanState == + eLIM_HAL_SCANNING_STATE) ? true : false), + false); + /* + * Calling dfsChannelList which will convert DFS channel + * to active channel for x secs if this channel is DFS + */ + lim_set_dfs_channel_list(mac_ctx, + bcn_ptr->channelNumber, + &mac_ctx->lim.dfschannelList); + } else if (session->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + if (session->beacon != NULL) { + cdf_mem_free(session->beacon); + session->beacon = NULL; + } + session->bcnLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + session->beacon = cdf_mem_malloc(session->bcnLen); + if (NULL == session->beacon) { + lim_log(mac_ctx, LOGE, + FL("fail to alloc mem to store bcn")); + } else { + /* + * Store the Beacon/ProbeRsp. This is sent to + * csr/hdd in join cnf response. + */ + cdf_mem_copy(session->beacon, + WMA_GET_RX_MPDU_DATA(rx_pkt_info), + session->bcnLen); + } + lim_check_and_announce_join_success(mac_ctx, bcn_ptr, + mac_hdr, session); + } + cdf_mem_free(bcn_ptr); + return; +} + +/**--------------------------------------------------------------- + \fn lim_process_beacon_frame_no_session + \brief This function is called by limProcessMessageQueue() + \ upon Beacon reception. + \ + \param pMac + \param *pRxPacketInfo - A pointer to Rx packet info structure + \return None + ------------------------------------------------------------------*/ +void +lim_process_beacon_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr; + tSchBeaconStruct *pBeacon; + + pMac->lim.gLimNumBeaconsRcvd++; + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + lim_log(pMac, LOG2, FL("Received Beacon frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(pRxPacketInfo)); + lim_print_mac_addr(pMac, pHdr->sa, LOG2); + + + /** + * No session has been established. Expect Beacon only when + * 1. STA is in Scan mode waiting for Beacon/Probe response or + * 2. STA/AP is in Learn mode + */ + if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE)) { + pBeacon = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeacon) { + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory in lim_process_beacon_frame_no_session")); + return; + } + + if (sir_convert_beacon_frame2_struct + (pMac, (uint8_t *) pRxPacketInfo, + pBeacon) != eSIR_SUCCESS) { + /* Received wrongly formatted/invalid Beacon. Ignore and move on. */ + lim_log(pMac, LOGW, + FL + ("Received invalid Beacon in global MLM state %X"), + pMac->lim.gLimMlmState); + lim_print_mlm_state(pMac, LOGW, pMac->lim.gLimMlmState); + cdf_mem_free(pBeacon); + return; + } + + if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE)) { + lim_check_and_add_bss_description(pMac, pBeacon, + pRxPacketInfo, true, + false); + /* Calling dfsChannelList which will convert DFS channel + * to Active channel for x secs if this channel is DFS channel */ + lim_set_dfs_channel_list(pMac, pBeacon->channelNumber, + &pMac->lim.dfschannelList); + } else if (pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE) { + } /* end of eLIM_MLM_LEARN_STATE) */ + cdf_mem_free(pBeacon); + } /* end of (eLIM_MLM_WT_PROBE_RESP_STATE) || (eLIM_MLM_PASSIVE_SCAN_STATE) */ + else { + lim_log(pMac, LOG1, FL("Rcvd Beacon in unexpected MLM state %d"), + pMac->lim.gLimMlmState); + lim_print_mlm_state(pMac, LOG1, pMac->lim.gLimMlmState); +#ifdef WLAN_DEBUG + pMac->lim.gLimUnexpBcnCnt++; +#endif + } + + return; +} /*** end lim_process_beacon_frame_no_session() ***/ diff --git a/core/mac/src/pe/lim/lim_process_cfg_updates.c b/core/mac/src/pe/lim/lim_process_cfg_updates.c new file mode 100644 index 0000000000..e1a645e1ac --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_cfg_updates.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_cfg_updates.cc contains the utility functions + * to handle various CFG parameter update events + * Author: Chandra Modumudi + * Date: 01/20/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" +#include "sch_api.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +static void lim_update_config(tpAniSirGlobal pMac, tpPESession psessionEntry); + +static void lim_set_default_key_id_and_keys(tpAniSirGlobal pMac) +{ +#ifdef FIXME_GEN6 + uint32_t val; + uint32_t dkCfgId; + PELOG1(lim_log(pMac, LOG1, FL("Setting default keys at SP"));) + if (wlan_cfg_get_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, + &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve defaultKeyId from CFG")); + } + dkCfgId = limGetCfgIdOfDefaultKeyid(val); +#endif + +} /*** end lim_set_default_key_id_and_keys() ***/ +/** ------------------------------------------------------------- + \fn lim_set_cfg_protection + \brief sets lim global cfg cache from the config. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry) +{ + uint32_t val = 0; + + if (pesessionEntry != NULL && LIM_IS_AP_ROLE(pesessionEntry)) { + if (pesessionEntry->gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + cdf_mem_set((void *)&pesessionEntry->cfgProtection, + sizeof(tCfgProtection), 0); + else { + lim_log(pMac, LOG1, + FL(" frm11a = %d, from11b = %d, frm11g = %d, " + "ht20 = %d, nongf = %d, lsigTxop = %d, " + "rifs = %d, obss = %d"), + pesessionEntry->cfgProtection.fromlla, + pesessionEntry->cfgProtection.fromllb, + pesessionEntry->cfgProtection.fromllg, + pesessionEntry->cfgProtection.ht20, + pesessionEntry->cfgProtection.nonGf, + pesessionEntry->cfgProtection.lsigTxop, + pesessionEntry->cfgProtection.rifs, + pesessionEntry->cfgProtection.obss); + } + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_FORCE_POLICY_PROTECTION, &val) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("reading WNI_CFG_FORCE_POLICY_PROTECTION cfg failed")); + return; + } else + pMac->lim.gLimProtectionControl = (uint8_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROTECTION_ENABLED, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("reading protection cfg failed")); + return; + } + + if (pMac->lim.gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + cdf_mem_set((void *)&pMac->lim.cfgProtection, + sizeof(tCfgProtection), 0); + else { + pMac->lim.cfgProtection.fromlla = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llA) & 1; + pMac->lim.cfgProtection.fromllb = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llB) & 1; + pMac->lim.cfgProtection.fromllg = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llG) & 1; + pMac->lim.cfgProtection.ht20 = + (val >> WNI_CFG_PROTECTION_ENABLED_HT_20) & 1; + pMac->lim.cfgProtection.nonGf = + (val >> WNI_CFG_PROTECTION_ENABLED_NON_GF) & 1; + pMac->lim.cfgProtection.lsigTxop = + (val >> WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP) & 1; + pMac->lim.cfgProtection.rifs = + (val >> WNI_CFG_PROTECTION_ENABLED_RIFS) & 1; + pMac->lim.cfgProtection.obss = + (val >> WNI_CFG_PROTECTION_ENABLED_OBSS) & 1; + + } + } +} + +/** + * lim_handle_param_update() + * + ***FUNCTION: + * This function is use to post a message whenever need indicate + * there is update of config parameter. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ +void lim_handle_param_update(tpAniSirGlobal pMac, eUpdateIEsType cfgId) +{ + tSirMsgQ msg = { 0 }; + uint32_t status; + + PELOG3(lim_log + (pMac, LOG3, FL("Handling CFG parameter id %X update"), cfgId); + ) + switch (cfgId) { + case eUPDATE_IE_PROBE_BCN: + { + msg.type = SIR_LIM_UPDATE_BEACON; + status = lim_post_msg_api(pMac, &msg); + + if (status != TX_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("Failed lim_post_msg_api %u"), status); + ) + break; + } + default: + break; + } +} + +/** + * lim_handle_cf_gparam_update() + * + ***FUNCTION: + * This function is called by lim_process_messages() to + * whenever SIR_CFG_PARAM_UPDATE_IND message is posted + * to LIM (due to a set operation on a CFG parameter). + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ + +void lim_handle_cf_gparam_update(tpAniSirGlobal pMac, uint32_t cfgId) +{ + uint32_t val1, val2; + uint16_t val16; + tSirMacHTCapabilityInfo *pHTCapabilityInfo; + tSirMacHTParametersInfo *pAmpduParamInfo; + + PELOG3(lim_log + (pMac, LOG3, FL("Handling CFG parameter id %X update"), cfgId); + ) + switch (cfgId) { + case WNI_CFG_WEP_DEFAULT_KEYID: + + /* !!LAC - when the default KeyID is changed, force all of the */ + /* keys and the keyID to be reprogrammed. this allows the */ + /* keys to change after the initial setting of the keys when the CFG was */ + /* applied at association time through CFG changes of the keys. */ + lim_set_default_key_id_and_keys(pMac); + + break; + + case WNI_CFG_EXCLUDE_UNENCRYPTED: + if (wlan_cfg_get_int(pMac, WNI_CFG_EXCLUDE_UNENCRYPTED, + &val1) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve excludeUnencr from CFG")); + } + lim_log(pMac, LOGE, + FL("Unsupported CFG: WNI_CFG_EXCLUDE_UNENCRYPTED")); + + break; + + case WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT: + if (pMac->lim.gLimMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) { + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, + eLIM_ASSOC_FAIL_TIMER); + } + + break; + + case WNI_CFG_PROTECTION_ENABLED: + lim_set_cfg_protection(pMac, NULL); + break; + case WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG: + { + tSirMsgQ msg = { 0 }; + uint32_t status; + + msg.type = SIR_LIM_UPDATE_BEACON; + + status = lim_post_msg_api(pMac, &msg); + + if (status != TX_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("Failed lim_post_msg_api %u"), status); + ) + break; + } + case WNI_CFG_GREENFIELD_CAPABILITY: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT Cap Info CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_GREENFIELD_CAPABILITY, &val2) + != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve GreenField CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->greenField = (uint16_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT Cap Info CFG")); + ) + break; + + case WNI_CFG_HT_RX_STBC: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve WNI_CFG_HT_CAP_INFO ")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_RX_STBC, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve WNI_CFG_HT_RX_STBC")); + ) + break; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->rxSTBC = (uint16_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT Cap Info CFG")); + ) + break; + + case WNI_CFG_MAX_AMSDU_LENGTH: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT Cap Info CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_AMSDU_LENGTH, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve Max AMSDU Length CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->maximalAMSDUsize = (uint16_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT Cap Info CFG")); + ) + break; + + case WNI_CFG_SHORT_GI_20MHZ: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT Cap CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_20MHZ, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve shortGI 20Mhz CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->shortGI20MHz = (uint16_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT Cap Info CFG")); + ) + break; + case WNI_CFG_SHORT_GI_40MHZ: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT Cap CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_GI_40MHZ, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve shortGI 40Mhz CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + pHTCapabilityInfo->shortGI40MHz = (uint16_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, + *(uint16_t *) pHTCapabilityInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT Cap Info CFG")); + ) + break; + case WNI_CFG_MPDU_DENSITY: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT AMPDU Param CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MPDU_DENSITY, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve MPDU Density CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->mpduDensity = (uint8_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT AMPDU Param CFG")); + ) + + break; + case WNI_CFG_MAX_RX_AMPDU_FACTOR: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT AMPDU Param CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve AMPDU Factor CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT AMPDU Param CFG")); + ) + break; + + case WNI_CFG_DOT11_MODE: + if (wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve Dot11 Mode CFG")); + ) + break; + } + break; + + case WNI_CFG_SCAN_IN_POWERSAVE: + if (wlan_cfg_get_int(pMac, WNI_CFG_SCAN_IN_POWERSAVE, &val1) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Unable to get WNI_CFG_SCAN_IN_POWERSAVE ")); + break; + } + pMac->lim.gScanInPowersave = (uint8_t) val1; + break; + + case WNI_CFG_ASSOC_STA_LIMIT: + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val1) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Unable to get WNI_CFG_ASSOC_STA_LIMIT")); + break; + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val1; + break; + default: + break; + } +} /*** end lim_handle_cf_gparam_update() ***/ + +/** + * lim_apply_configuration() + * + ***FUNCTION: + * This function is called to apply the configured parameters + * before joining or reassociating with a BSS or starting a BSS. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_apply_configuration(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val = 0, phyMode; + + PELOG2(lim_log(pMac, LOG2, FL("Applying config"));) + + psessionEntry->limSentCapsChangeNtf = false; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* Set default keyId and keys */ + lim_set_default_key_id_and_keys(pMac); + + lim_update_config(pMac, psessionEntry); + + lim_get_short_slot_from_phy_mode(pMac, psessionEntry, phyMode, + &psessionEntry->shortSlotTimeSupported); + + lim_set_cfg_protection(pMac, psessionEntry); + + /* Added for BT - AMP Support */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + /* This check is required to ensure the beacon generation is not done + as a part of join request for a BT-AMP station */ + + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + PELOG1(lim_log + (pMac, LOG1, + FL("Initializing BT-AMP beacon generation")); + ) + sch_set_beacon_interval(pMac, psessionEntry); + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_SCAN_IN_POWERSAVE, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not retrieve WNI_CFG_SCAN_IN_POWERSAVE")); + return; + } + + PELOG1(lim_log(pMac, LOG1, FL("pMac->lim.gScanInPowersave = %hu"), + pMac->lim.gScanInPowersave); + ) + pMac->lim.gScanInPowersave = (uint8_t) val; + +} /*** end lim_apply_configuration() ***/ + +/** + * lim_update_config + * + * FUNCTION: + * Update the local state from CFG database + * (This used to be dphUpdateConfig) + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +static void lim_update_config(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val; + + sir_copy_mac_addr(pMac->lim.gLimMyMacAddr, psessionEntry->selfMacAddr); + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get short preamble failed")); + psessionEntry->beaconParams.fShortPreamble = (val) ? 1 : 0; + + /* In STA case this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_WME_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get wme enabled failed")); + psessionEntry->limWmeEnabled = (val) ? 1 : 0; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WSM_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get wsm enabled failed")); + psessionEntry->limWsmEnabled = (val) ? 1 : 0; + + if ((!psessionEntry->limWmeEnabled) && (psessionEntry->limWsmEnabled)) { + PELOGE(lim_log(pMac, LOGE, FL("Can't enable WSM without WME"));) + psessionEntry->limWsmEnabled = 0; + } + /* In STA , this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get qos enabled failed")); + psessionEntry->limQosEnabled = (val) ? 1 : 0; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_HCF_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get hcf enabled failed")); + psessionEntry->limHcfEnabled = (val) ? 1 : 0; + + /* AP: WSM should enable HCF as well, for STA enable WSM only after */ + /* association response is received */ + if (psessionEntry->limWsmEnabled && LIM_IS_AP_ROLE(psessionEntry)) + psessionEntry->limHcfEnabled = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11D_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get 11d enabled failed")); + psessionEntry->lim11dEnabled = (val) ? 1 : 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get assoc sta limit failed")); + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val; + +#if defined WLAN_FEATURE_VOWIFI + rrm_update_config(pMac, psessionEntry); +#endif + PELOG1(lim_log(pMac, LOG1, FL("Updated Lim shadow state based on CFG"));) +} diff --git a/core/mac/src/pe/lim/lim_process_deauth_frame.c b/core/mac/src/pe/lim/lim_process_deauth_frame.c new file mode 100644 index 0000000000..e64058d283 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_deauth_frame.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_deauth_frame.cc contains the code + * for processing Deauthentication Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "lim_send_messages.h" + +/** + * lim_process_deauth_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Deauthentication frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void +lim_process_deauth_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tLimMlmAssocCnf mlmAssocCnf; + tLimMlmDeauthInd mlmDeauthInd; + tpDphHashNode pStaDs; + tpPESession pRoamSessionEntry = NULL; + uint8_t roamSessionId; +#ifdef WLAN_FEATURE_11W + uint32_t frameLen; +#endif + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + if (LIM_IS_STA_ROLE(psessionEntry) && + ((eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState) || + (eLIM_SME_WT_DEAUTH_STATE == psessionEntry->limSmeState))) { + /*Every 15th deauth frame will be logged in kmsg */ + if (!(pMac->lim.deauthMsgCnt & 0xF)) { + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in DEAUTH_WT_STATE" + "(already processing previously received DEAUTH frame).." + "Dropping this.. Deauth Failed %d"), + ++pMac->lim.deauthMsgCnt); + ) + } else { + pMac->lim.deauthMsgCnt++; + } + return; + } + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Deauth frame from a BC/MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Deauth frame from a BC/MC address")); + ) + + return; + } + + if (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(pHdr->da)) { + /* Received Deauth frame for a MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Deauth frame for a MC address")); + ) + + return; + } + if (!lim_validate_received_frame_a1_addr(pMac, + pHdr->da, psessionEntry)) { + lim_log(pMac, LOGE, + FL("rx frame doesn't have valid a1 address, drop it")); + return; + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received an unprotected deauth from AP")); + ) + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + /* Get reasonCode from Deauthentication frame body */ + reasonCode = sir_read_u16(pBody); + + PELOGE(lim_log(pMac, LOGE, + FL("Received Deauth frame for Addr: " MAC_ADDRESS_STR + " (mlm state = %s," + " sme state = %d systemrole = %d) with reason code %d [%s] from " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry), + reasonCode, lim_dot11_reason_str(reasonCode), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Ignore the Deauth received, while waiting for ack of " + "disassoc/deauth")); + ) + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + /* Valid reasonCode in received Deauthentication frame */ + break; + + default: + /* Invalid reasonCode in received Deauthentication frame */ + /* Log error and ignore the frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame with invalid reasonCode %d from " + MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + } else if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON: + case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON: + case eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON: + /* Valid reasonCode in received Deauth frame */ + break; + + default: + /* Invalid reasonCode in received Deauth frame */ + /* Log error and ignore the frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame with invalid reasonCode %d from " + MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + } else { + /* Received Deauth frame in either IBSS */ + /* or un-known role. Log and ignore it */ + lim_log(pMac, LOGE, + FL + ("received Deauth frame with reasonCode %d in role %d from " + MAC_ADDRESS_STR), reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(pHdr->sa)); + + return; + } + + /** If we are in the middle of ReAssoc, a few things could happen: + * - STA is reassociating to current AP, and receives deauth from: + * a) current AP + * b) other AP + * - STA is reassociating to a new AP, and receives deauth from: + * c) current AP + * d) reassoc AP + * e) other AP + * + * The logic is: + * 1) If rcv deauth from an AP other than the one we're trying to + * reassociate with, then drop the deauth frame (case b, c, e) + * 2) If rcv deauth from the "new" reassoc AP (case d), then restore + * context with previous AP and send SME_REASSOC_RSP failure. + * 3) If rcv deauth from the reassoc AP, which is also the same + * AP we're currently associated with (case a), then proceed + * with normal deauth processing. + */ + if (psessionEntry->limReAssocbssId != NULL) { + pRoamSessionEntry = + pe_find_session_by_bssid(pMac, psessionEntry->limReAssocbssId, + &roamSessionId); + } + if (lim_is_reassoc_in_progress(pMac, psessionEntry) + || lim_is_reassoc_in_progress(pMac, pRoamSessionEntry)) { + if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Rcv Deauth from unknown/different " + "AP while ReAssoc. Ignore " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + PELOGE(lim_log + (pMac, LOGE, + FL(" limReAssocbssId : " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(psessionEntry-> + limReAssocbssId)); + ) + return; + } + + /** Received deauth from the new AP to which we tried to ReAssociate. + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received DeAuth from the New AP to " + "which ReAssoc is sent " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + PELOGE(lim_log + (pMac, LOGE, + FL(" psessionEntry->bssId: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(psessionEntry->bssId)); + ) + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + return; + } + } + + /* If received DeAuth from AP other than the one we're trying to join with + * nor associated with, then ignore deauth and delete Pre-auth entry. + */ + if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!IS_CURRENT_BSSID(pMac, pHdr->bssId, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received DeAuth from an AP other " + "than we're trying to join. Ignore. " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + ) + if (lim_search_pre_auth_list(pMac, pHdr->sa)) { + PELOG1(lim_log + (pMac, LOG1, + FL("Preauth entry exist. " + "Deleting... ")); + ) + lim_delete_pre_auth_node(pMac, pHdr->sa); + } + return; + } + } + + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + + /* Check for pre-assoc states */ + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + switch (psessionEntry->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + /** + * AP sent Deauth frame while waiting + * for Auth frame2. Report Auth failure + * to SME. + */ + + /* Log error */ + PELOG1(lim_log(pMac, LOG1, + FL + ("received Deauth frame state %X with failure " + "code %d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + lim_restore_from_auth_state(pMac, + eSIR_SME_DEAUTH_WHILE_JOIN, + reasonCode, psessionEntry); + + return; + + case eLIM_MLM_AUTHENTICATED_STATE: + lim_log(pMac, LOG1, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + /* / Issue Deauth Indication to SME. */ + cdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pHdr->sa, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = reasonCode; + + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + return; + + case eLIM_MLM_WT_ASSOC_RSP_STATE: + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue ASSOC_CNF to SME. + */ + lim_log(pMac, LOG1, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); + + if (psessionEntry->pLimMlmJoinReq) { + cdf_mem_free(psessionEntry->pLimMlmJoinReq); + psessionEntry->pLimMlmJoinReq = NULL; + } + + mlmAssocCnf.resultCode = eSIR_SME_DEAUTH_WHILE_JOIN; + mlmAssocCnf.protStatusCode = reasonCode; + + /* PE session Id */ + mlmAssocCnf.sessionId = psessionEntry->peSessionId; + + psessionEntry->limMlmState = + psessionEntry->limPrevMlmState; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + /* Deactive Association response timeout */ + lim_deactivate_and_change_timer(pMac, + eLIM_ASSOC_FAIL_TIMER); + + lim_post_sme_message(pMac, + LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlmAssocCnf); + + return; + + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + psessionEntry->fDeauthReceived = true; + PELOGW(lim_log(pMac, LOGW, + FL + ("Received Deauth frame in state %X with Reason " + "Code %d from Peer" MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + + case eLIM_MLM_IDLE_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: +#ifdef FEATURE_WLAN_TDLS + if ((NULL != pStaDs) + && (STA_ENTRY_TDLS_PEER == pStaDs->staType)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("received Deauth frame in state %X with " + "reason code %d from Tdls peer" + MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + lim_send_sme_tdls_del_sta_ind(pMac, pStaDs, + psessionEntry, + reasonCode); + return; + } else { + + /* + * Delete all the TDLS peers only if Deauth + * is received from the AP + */ + if (IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + /** + * This could be Deauthentication frame from + * a BSS with which pre-authentication was + * performed. Delete Pre-auth entry if found. + */ + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); +#ifdef FEATURE_WLAN_TDLS + } +#endif + break; + + case eLIM_MLM_WT_REASSOC_RSP_STATE: + lim_log(pMac, LOGE, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + break; + + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in FT state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + break; + + default: + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + } + break; + + case eLIM_STA_IN_IBSS_ROLE: + break; + + case eLIM_AP_ROLE: + break; + + default: /* eLIM_AP_ROLE or eLIM_BT_AMP_AP_ROLE */ + + return; + } /* end switch (pMac->lim.gLimSystemRole) */ + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("pStaDs is NULL")); + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + /** + * Already in the process of deleting context for the peer + * and received Deauthentication frame. Log and Ignore. + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame from peer that is in state %X, addr " + MAC_ADDRESS_STR), pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + } + pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode; + pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DEAUTH; + + /* / Issue Deauth Indication to SME. */ + cdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = eLIM_PEER_ENTITY_DEAUTH; + + /* + * If we're in the middle of ReAssoc and received deauth from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. SME will post the disconnect to the + * supplicant and the latter would start a fresh assoc. + */ + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue REASSOC_CNF to SME. + */ + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); + + if (psessionEntry->limAssocResponseData) { + cdf_mem_free(psessionEntry->limAssocResponseData); + psessionEntry->limAssocResponseData = NULL; + } + + PELOGE(lim_log(pMac, LOGE, FL("Rcv Deauth from ReAssoc AP. " + "Issue REASSOC_CNF. ")); + ) + /* + * TODO: Instead of overloading eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE + * it would have been good to define/use a different failure type. + * Using eSIR_SME_FT_REASSOC_FAILURE does not seem to clean-up + * properly and we end up seeing "transmit queue timeout". + */ + lim_post_reassoc_failure(pMac, + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + return; + } + /* reset the deauthMsgCnt here since we are able to Process + * the deauth frame and sending up the indication as well */ + if (pMac->lim.deauthMsgCnt != 0) { + pMac->lim.deauthMsgCnt = 0; + } + if (LIM_IS_STA_ROLE(psessionEntry)) + wma_tx_abort(psessionEntry->smeSessionId); + + /* / Deauthentication from peer MAC entity */ + lim_post_sme_message(pMac, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + + /* send eWNI_SME_DEAUTH_IND to SME */ + lim_send_sme_deauth_ind(pMac, pStaDs, psessionEntry); + return; + +} /*** end lim_process_deauth_frame() ***/ diff --git a/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/core/mac/src/pe/lim/lim_process_disassoc_frame.c new file mode 100644 index 0000000000..33a1c089d2 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_disassoc_frame.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_disassoc_frame.cc contains the code + * for processing Disassocation Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" +#include "sch_api.h" + +/** + * lim_process_disassoc_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Disassociation frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * DPH drops packets for STA with 'valid' bit in pStaDs set to '0'. + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Rx packet info structure + * @return None + */ +void +lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tpDphHashNode pStaDs; + tLimMlmDisassocInd mlmDisassocInd; +#ifdef WLAN_FEATURE_11W + uint32_t frameLen; +#endif + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Disassoc frame from a BC/MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from a BC/MC address")); + ) + + return; + } + + if (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(pHdr->da)) { + /* Received Disassoc frame for a MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Disassoc frame for a MC address")); + ) + + return; + } + if (!lim_validate_received_frame_a1_addr(pMac, + pHdr->da, psessionEntry)) { + lim_log(pMac, LOGE, + FL("rx frame doesn't have valid a1 address, drop it")); + return; + } + + if (LIM_IS_STA_ROLE(psessionEntry) && + (eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState)) { + if (pHdr->fc.retry > 0) { + /* + * This can happen when first disassoc frame is received + * but ACK from this STA is lost, in this case 2nd + * disassoc frame is already in transmission queue + */ + lim_log(pMac, LOGE, + FL("AP is sending disassoc after ACK lost...")); + return; + } + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received an unprotected disassoc from AP")); + ) + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + /* Get reasonCode from Disassociation frame body */ + reasonCode = sir_read_u16(pBody); + + PELOG2(lim_log(pMac, LOGE, + FL("Received Disassoc frame for Addr: " MAC_ADDRESS_STR + "(mlm state=%s, sme state=%d)," + "with reason code %d [%s] from " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, reasonCode, + lim_dot11_reason_str(reasonCode), MAC_ADDR_ARRAY(pHdr->sa)); + ) + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + /** + * Disassociating STA is not associated. + * Log error. + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from STA that does not have context " + "reasonCode=%d, addr " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + PELOGE(lim_log(pMac, LOGE, + FL("Ignore the DisAssoc received, while waiting " + "for ack of disassoc/deauth")); + ) + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + /** If we are in the Wait for ReAssoc Rsp state */ + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + /** If we had received the DisAssoc from, + * a. the Current AP during ReAssociate to different AP in same ESS + * b. Unknown AP + * drop/ignore the DisAssoc received + */ + if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Ignore the DisAssoc received, while " + "Processing ReAssoc with different/unknown AP")); + ) + return; + } + /** If the Disassoc is received from the new AP to which we tried to ReAssociate + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGW(lim_log + (pMac, LOGW, + FL + ("received Disassoc from the New AP to which ReAssoc is sent ")); + ) + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + return; + } + } + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + case eSIR_MAC_MIC_FAILURE_REASON: + case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON: + case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON: + case eSIR_MAC_RSN_IE_MISMATCH_REASON: + case eSIR_MAC_1X_AUTH_FAILURE_REASON: + /* Valid reasonCode in received Disassociation frame */ + break; + + default: + /* Invalid reasonCode in received Disassociation frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame with invalid reasonCode " + "%d from " MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + break; + } + } else if ((LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) && + ((psessionEntry->limSmeState != eLIM_SME_WT_JOIN_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_AUTH_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_ASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_REASSOC_STATE))) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON: + case eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON: + case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON: + case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON: + case eSIR_MAC_MIC_FAILURE_REASON: + case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON: + case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON: + case eSIR_MAC_RSN_IE_MISMATCH_REASON: + case eSIR_MAC_1X_AUTH_FAILURE_REASON: + case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + /* Valid reasonCode in received Disassociation frame */ + break; + + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + /* Valid reasonCode in received Disassociation frame */ + /* as long as we're not about to channel switch */ + if (psessionEntry->gLimChannelSwitch.state != + eLIM_CHANNEL_SWITCH_IDLE) { + lim_log(pMac, LOGE, + FL + ("Ignoring disassoc frame due to upcoming " + "channel switch, from " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + break; + + default: + /* Invalid reasonCode in received Disassociation frame */ + /* Log error and ignore the frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame with invalid reasonCode " + "%d from " MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + } + } else { + /* Received Disassociation frame in either IBSS */ + /* or un-known role. Log and ignore it */ + lim_log(pMac, LOGE, + FL + ("received Disassoc frame with invalid reasonCode %d in role " + "%d in sme state %d from " MAC_ADDRESS_STR), reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), psessionEntry->limSmeState, + MAC_ADDR_ARRAY(pHdr->sa)); + + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + /** + * Already in the process of deleting context for the peer + * and received Disassociation frame. Log and Ignore. + */ + PELOGE(lim_log(pMac, LOGE, + FL("received Disassoc frame in state %d from " + MAC_ADDRESS_STR), + pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /** + * Requesting STA is in some 'transient' state? + * Log error. + */ + if (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_ASSOC_CNF_STATE) + pStaDs->mlmStaContext.updateContext = 1; + + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from peer that is in state %X, addr " + MAC_ADDRESS_STR), pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + } /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */ + + pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC; + pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode; + + /* Issue Disassoc Indication to SME. */ + cdf_mem_copy((uint8_t *) &mlmDisassocInd.peerMacAddr, + (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr)); + mlmDisassocInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDisassocInd.disassocTrigger = eLIM_PEER_ENTITY_DISASSOC; + + /* Update PE session Id */ + mlmDisassocInd.sessionId = psessionEntry->peSessionId; + + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + + /* If we're in the middle of ReAssoc and received disassoc from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. By design, SME will then issue "Disassoc" + * and cleanup will happen at that time. + */ + PELOGE(lim_log + (pMac, LOGE, + FL("received Disassoc from AP while waiting " + "for Reassoc Rsp")); + ) + + if (psessionEntry->limAssocResponseData) { + cdf_mem_free(psessionEntry->limAssocResponseData); + psessionEntry->limAssocResponseData = NULL; + } + + lim_restore_pre_reassoc_state(pMac, eSIR_SME_REASSOC_REFUSED, + reasonCode, psessionEntry); + return; + } + + lim_post_sme_message(pMac, LIM_MLM_DISASSOC_IND, + (uint32_t *) &mlmDisassocInd); + + /* send eWNI_SME_DISASSOC_IND to SME */ + lim_send_sme_disassoc_ind(pMac, pStaDs, psessionEntry); + + return; +} /*** end lim_process_disassoc_frame() ***/ diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c new file mode 100644 index 0000000000..25e7ed1a5c --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -0,0 +1,2098 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim ProcessMessageQueue.cc contains the code + * for processing LIM message Queue. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "wma_types.h" + +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_common.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" + +#include "lim_admit_control.h" +#include "lim_ibss_peer_mgmt.h" +#include "sch_api.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_send_messages.h" + +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R +#include "lim_ft.h" +#endif + +#include "cdf_types.h" +#include "cds_packet.h" +#include "cdf_memory.h" + +void lim_log_session_states(tpAniSirGlobal pMac); +static void lim_process_normal_hdd_msg(tpAniSirGlobal mac_ctx, + struct sSirMsgQ *msg, uint8_t rsp_reqd); + +/** + * lim_process_dual_mac_cfg_resp() - Process set dual mac config response + * @mac: Global MAC pointer + * @body: Set dual mac config response in sir_dual_mac_config_resp format + * + * Process the set dual mac config response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_dual_mac_cfg_resp(tpAniSirGlobal mac, void *body) +{ + struct sir_dual_mac_config_resp *resp, *param; + uint32_t len, fail_resp = 0; + tSirMsgQ msg; + + resp = (struct sir_dual_mac_config_resp *)body; + if (!resp) { + lim_log(mac, LOGE, FL("Set dual mac cfg param is NULL")); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME + */ + } + + len = sizeof(*param); + + param = cdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + return; + } + + if (fail_resp) { + lim_log(mac, LOGE, FL("Send fail status to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + } else { + param->status = resp->status; + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOG1, FL("Send eWNI_SME_SET_DUAL_MAC_CFG_RESP to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** + * lim_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_set_hw_mode_resp format + * + * Process the set HW mode response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_set_hw_mode_resp(tpAniSirGlobal mac, void *body) +{ + struct sir_set_hw_mode_resp *resp, *param; + uint32_t len, i, fail_resp = 0; + tSirMsgQ msg; + + resp = (struct sir_set_hw_mode_resp *)body; + if (!resp) { + lim_log(mac, LOGE, FL("Set HW mode param is NULL")); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME */ + } + + len = sizeof(*param); + + param = cdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + return; + } + + if (fail_resp) { + lim_log(mac, LOGE, FL("Send fail status to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + } else { + param->status = resp->status; + param->cfgd_hw_mode_index = resp->cfgd_hw_mode_index; + param->num_vdev_mac_entries = resp->num_vdev_mac_entries; + + for (i = 0; i < resp->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + resp->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + resp->vdev_mac_map[i].mac_id; + } + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOGE, FL("Send eWNI_SME_SET_HW_MODE_RESP to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** + * lim_process_hw_mode_trans_ind() - Process set HW mode transition indication + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_hw_mode_trans_ind format + * + * Process the set HW mode transition indication and post the message + * to SME to invoke the HDD callback + * command list + * + * Return: None + */ +static void lim_process_hw_mode_trans_ind(tpAniSirGlobal mac, void *body) +{ + struct sir_hw_mode_trans_ind *ind, *param; + uint32_t len, i; + tSirMsgQ msg; + + ind = (struct sir_hw_mode_trans_ind *)body; + if (!ind) { + lim_log(mac, LOGE, FL("Set HW mode trans ind param is NULL")); + return; + } + + len = sizeof(*param); + + param = cdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + return; + } + + param->old_hw_mode_index = ind->old_hw_mode_index; + param->new_hw_mode_index = ind->new_hw_mode_index; + param->num_vdev_mac_entries = ind->num_vdev_mac_entries; + + for (i = 0; i < ind->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + ind->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + ind->vdev_mac_map[i].mac_id; + } + + /* TODO: Update this HW mode info in any UMAC params, if needed */ + + msg.type = eWNI_SME_HW_MODE_TRANS_IND; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOGE, FL("Send eWNI_SME_HW_MODE_TRANS_IND to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** ------------------------------------------------------------- + \fn def_msg_decision + \brief The function decides whether to defer a message or not in limProcessMessage function + \param tpAniSirGlobal pMac + \param tSirMsgQ limMsg + \param tSirMacTspecIE *ppInfo + \return none + -------------------------------------------------------------*/ + +uint8_t static def_msg_decision(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + +/* this function should not changed */ + if (pMac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + /* Defer processsing this message */ + if (lim_defer_msg(pMac, limMsg) != TX_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(pMac); + lim_handle_defer_msg_error(pMac, limMsg); + } + return true; + } + /* When defer is requested then defer all the messages except HAL responses. */ + if ((!lim_is_system_in_scan_state(pMac)) + && (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) + && !pMac->lim.gLimSystemInScanLearnMode) { + if ((limMsg->type != WMA_ADD_BSS_RSP) + && (limMsg->type != WMA_DELETE_BSS_RSP) + && (limMsg->type != WMA_ADD_STA_RSP) + && (limMsg->type != WMA_DELETE_STA_RSP) + && (limMsg->type != WMA_SET_BSSKEY_RSP) + && (limMsg->type != WMA_SET_STAKEY_RSP) + && (limMsg->type != WMA_SET_STA_BCASTKEY_RSP) + && (limMsg->type != WMA_AGGR_QOS_RSP) + && (limMsg->type != WMA_SET_MIMOPS_RSP) + && (limMsg->type != WMA_SWITCH_CHANNEL_RSP) + && (limMsg->type != WMA_P2P_NOA_ATTR_IND) + && (limMsg->type != WMA_P2P_NOA_START_IND) && +#ifdef FEATURE_OEM_DATA_SUPPORT + (limMsg->type != WMA_START_OEM_DATA_RSP) && +#endif + (limMsg->type != WMA_ADD_TS_RSP)) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("Defer the current message %s , gLimProcessDefdMsgs is false and system is not in scan/learn mode"), + lim_msg_str(limMsg->type)); + ) + /* Defer processsing this message */ + if (lim_defer_msg(pMac, limMsg) != TX_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(pMac); + lim_handle_defer_msg_error(pMac, limMsg); + + } + return true; + } + } + return false; +} + +#ifdef FEATURE_WLAN_EXTSCAN +static void +__lim_pno_match_fwd_bcn_probepsp(tpAniSirGlobal pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, uint32_t ie_len, + uint32_t msg_type) +{ + struct pno_match_found *result; + uint8_t *body; + tSirMsgQ mmh_msg; + tpSirMacMgmtHdr hdr; + uint32_t num_results = 1, len, i; + + /* Upon receiving every matched beacon, bss info is forwarded to the + * the upper layer, hence num_results is set to 1 */ + len = sizeof(*result) + (num_results * sizeof(tSirWifiScanResult)) + + ie_len; + + result = cdf_mem_malloc(len); + if (NULL == result) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + cdf_mem_zero(result, sizeof(*result) + ie_len); + + /* Received frame does not have request id, hence set 0 */ + result->request_id = 0; + result->more_data = 0; + result->num_results = num_results; + + for (i = 0; i < result->num_results; i++) { + result->ap[i].ts = cdf_mc_timer_get_system_time(); + result->ap[i].beaconPeriod = frame->beaconInterval; + result->ap[i].capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap[i].channel = WMA_GET_RX_CH(rx_pkt_info); + result->ap[i].rssi = WMA_GET_RX_RSSI_DB(rx_pkt_info); + result->ap[i].rtt = 0; + result->ap[i].rtt_sd = 0; + result->ap[i].ieLength = ie_len; + cdf_mem_copy((uint8_t *) &result->ap[i].ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap[i].ssid[frame->ssId.length] = '\0'; + cdf_mem_copy((uint8_t *) &result->ap[i].bssid, + (uint8_t *) hdr->bssId, + sizeof(tSirMacAddr)); + /* Copy IE fields */ + cdf_mem_copy((uint8_t *) &result->ap[i].ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + } + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg, ePROT); +} + + +static void +__lim_ext_scan_forward_bcn_probe_rsp(tpAniSirGlobal pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, + uint32_t ie_len, + uint32_t msg_type) +{ + tpSirWifiFullScanResultEvent result; + uint8_t *body; + tSirMsgQ mmh_msg; + tpSirMacMgmtHdr hdr; + + result = cdf_mem_malloc(sizeof(*result) + ie_len); + if (NULL == result) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + cdf_mem_zero(result, sizeof(*result) + ie_len); + + /* Received frame does not have request id, hence set 0 */ + result->requestId = 0; + + result->moreData = 0; + result->ap.ts = cdf_mc_timer_get_system_time(); + result->ap.beaconPeriod = frame->beaconInterval; + result->ap.capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap.channel = WMA_GET_RX_CH(rx_pkt_info); + result->ap.rssi = WMA_GET_RX_RSSI_DB(rx_pkt_info); + result->ap.rtt = 0; + result->ap.rtt_sd = 0; + result->ap.ieLength = ie_len; + + cdf_mem_copy((uint8_t *) &result->ap.ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap.ssid[frame->ssId.length] = '\0'; + cdf_mem_copy((uint8_t *) &result->ap.bssid.bytes, + (uint8_t *) hdr->bssId, + CDF_MAC_ADDR_SIZE); + /* Copy IE fields */ + cdf_mem_copy((uint8_t *) &result->ap.ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg, ePROT); +} + +static void +__lim_process_ext_scan_beacon_probe_rsp(tpAniSirGlobal pmac, + uint8_t *rx_pkt_info, + uint8_t sub_type) +{ + tSirProbeRespBeacon *frame; + uint8_t *body; + uint32_t frm_len; + tSirRetStatus status; + + frm_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + if (frm_len <= SIR_MAC_B_PR_SSID_OFFSET) { + lim_log(pmac, LOGP, + FL("RX packet has invalid length %d"), frm_len); + return; + } + + frame = cdf_mem_malloc(sizeof(*frame)); + if (NULL == frame) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + + if (sub_type == SIR_MAC_MGMT_BEACON) { + lim_log(pmac, LOG2, FL("Beacon due to ExtScan/epno")); + status = sir_convert_beacon_frame2_struct(pmac, + (uint8_t *)rx_pkt_info, + frame); + } else if (sub_type == SIR_MAC_MGMT_PROBE_RSP) { + lim_log(pmac, LOG2, FL("Probe Rsp due to ExtScan/epno")); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + status = sir_convert_probe_frame2_struct(pmac, body, + frm_len, frame); + } else { + cdf_mem_free(frame); + return; + } + + if (status != eSIR_SUCCESS) { + lim_log(pmac, LOGE, FL("Frame parsing failed")); + cdf_mem_free(frame); + return; + } + + if (WMA_IS_EXTSCAN_SCAN_SRC(rx_pkt_info)) + __lim_ext_scan_forward_bcn_probe_rsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND); + + if (WMA_IS_EPNO_SCAN_SRC(rx_pkt_info)) + __lim_pno_match_fwd_bcn_probepsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EPNO_NETWORK_FOUND_IND); + + cdf_mem_free(frame); +} +#endif + +/* + * Beacon Handling Cases: + * during scanning, when no session is active: + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, but beacon/Pr does not belong to that session, psessionEntry will be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, and beacon/Pr belongs to one of the session, psessionEntry will not be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * Not scanning, no session: + * there should not be any beacon coming, if coming, should be dropped. + * Not Scanning, + */ +static void +__lim_handle_beacon(tpAniSirGlobal pMac, tpSirMsgQ pMsg, + tpPESession psessionEntry) +{ + /* checking for global SME state... */ + uint8_t *pRxPacketInfo; + lim_get_b_dfrom_rx_packet(pMac, pMsg->bodyptr, + (uint32_t * *) &pRxPacketInfo); + + /* This function should not be called if beacon is received in scan state. */ + /* So not doing any checks for the global state. */ + + if (psessionEntry == NULL) { + sch_beacon_process(pMac, pRxPacketInfo, NULL); + } else if ((psessionEntry->limSmeState == eLIM_SME_LINK_EST_STATE) || + (psessionEntry->limSmeState == eLIM_SME_NORMAL_STATE)) { + sch_beacon_process(pMac, pRxPacketInfo, psessionEntry); + } else + lim_process_beacon_frame(pMac, pRxPacketInfo, psessionEntry); + + return; +} + +/** + * lim_defer_msg() + * + ***FUNCTION: + * This function is called to defer the messages received + * during Learn mode + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg of type tSirMsgQ - Pointer to the message structure + * @return None + */ + +uint32_t lim_defer_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + uint32_t retCode = TX_SUCCESS; + + retCode = lim_write_deferred_msg_q(pMac, pMsg); + + if (retCode == TX_SUCCESS) { + MTRACE(mac_trace_msg_rx + (pMac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DEFERRED)); + ) + } else { + lim_log(pMac, LOGE, FL("Dropped lim message (0x%X)"), + pMsg->type); + MTRACE(mac_trace_msg_rx + (pMac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DROPPED)); + ) + } + + return retCode; +} /*** end lim_defer_msg() ***/ + +/** + * lim_handle_unknown_a2_index_frames() - This function handles Unknown Unicast + * (A2 Index) packets + * @mac_ctx: Pointer to the Global Mac Context. + * @rx_pkt_buffer: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This routine will handle public action frames. + * + * Return: None. + */ +static void lim_handle_unknown_a2_index_frames(tpAniSirGlobal mac_ctx, + void *rx_pkt_buffer, tpPESession session_entry) +{ +#ifdef FEATURE_WLAN_TDLS + tpSirMacDataHdr3a mac_hdr; +#endif + if (LIM_IS_P2P_DEVICE_ROLE(session_entry)) + lim_process_action_frame_no_session(mac_ctx, + (uint8_t *) rx_pkt_buffer); +#ifdef FEATURE_WLAN_TDLS + mac_hdr = WMA_GET_RX_MPDUHEADER3A(rx_pkt_buffer); + + if (lim_is_group_addr(mac_hdr->addr2)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Ignoring A2 Invalid Packet received for MC/BC:")); + lim_print_mac_addr(mac_ctx, mac_hdr->addr2, LOG2); + return; + } + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("type=0x%x, subtype=0x%x"), + mac_hdr->fc.type, mac_hdr->fc.subType); + /* Currently only following type and subtype are handled. + * If there are more combinations, then add switch-case + * statements. + */ + if (LIM_IS_STA_ROLE(session_entry) && + (mac_hdr->fc.type == SIR_MAC_MGMT_FRAME) && + (mac_hdr->fc.subType == SIR_MAC_MGMT_ACTION)) + lim_process_action_frame(mac_ctx, rx_pkt_buffer, session_entry); +#endif + return; +} + +/** + * lim_check_mgmt_registered_frames() - This function handles registered + * management frames. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @buff_desc: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This function is called to process to check if received frame match with + * any of the registered frame from HDD. If yes pass this frame to SME. + * + * Return: True or False for Match or Mismatch respectively. + */ +static bool +lim_check_mgmt_registered_frames(tpAniSirGlobal mac_ctx, uint8_t *buff_desc, + tpPESession session_entry) +{ + tSirMacFrameCtl fc; + tpSirMacMgmtHdr hdr; + uint8_t *body; + struct mgmt_frm_reg_info *mgmt_frame = NULL; + struct mgmt_frm_reg_info *next_frm = NULL; + uint16_t frm_type; + uint16_t frm_len; + uint8_t type, sub_type; + bool match = false; + CDF_STATUS cdf_status; + + hdr = WMA_GET_RX_MAC_HEADER(buff_desc); + fc = hdr->fc; + frm_type = (fc.type << 2) | (fc.subType << 4); + body = WMA_GET_RX_MPDU_DATA(buff_desc); + frm_len = WMA_GET_RX_PAYLOAD_LEN(buff_desc); + + cdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + cdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t **) &mgmt_frame); + cdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (mgmt_frame != NULL) { + type = (mgmt_frame->frameType >> 2) & 0x03; + sub_type = (mgmt_frame->frameType >> 4) & 0x0f; + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_HIGH, + FL + ("rcvd frm match for SIR_MAC_MGMT_RESERVED15")); + match = true; + break; + } + if (mgmt_frame->frameType == frm_type) { + if (mgmt_frame->matchLen <= 0) { + match = true; + break; + } + if (mgmt_frame->matchLen <= frm_len && + cdf_mem_compare(mgmt_frame->matchData, body, + mgmt_frame->matchLen)) { + /* found match! */ + match = true; + break; + } + } + + cdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + cdf_status = + cdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t *) mgmt_frame, + (cdf_list_node_t **) &next_frm); + cdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + mgmt_frame = next_frm; + next_frm = NULL; + } + + if (match) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("rcvd frame match with registered frame params")); + /* Indicate this to SME */ + lim_send_sme_mgmt_frame_ind(mac_ctx, hdr->fc.subType, + (uint8_t *) hdr, + WMA_GET_RX_PAYLOAD_LEN(buff_desc) + + sizeof(tSirMacMgmtHdr), mgmt_frame->sessionId, + WMA_GET_RX_CH(buff_desc), session_entry, 0); + + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) + /* These packets needs to be processed by PE/SME + * as well as HDD.If it returns true here, + * the packet is forwarded to HDD only. + */ + match = false; + } + + return match; +} + +/** + * lim_handle80211_frames() + * + ***FUNCTION: + * This function is called to process 802.11 frames + * received by LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg of type tSirMsgQ - Pointer to the message structure + * @return None + */ + +static void +lim_handle80211_frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, uint8_t *pDeferMsg) +{ + uint8_t *pRxPacketInfo = NULL; + tSirMacFrameCtl fc; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + tAniBool isFrmFt = false; + + *pDeferMsg = false; + lim_get_b_dfrom_rx_packet(pMac, limMsg->bodyptr, + (uint32_t * *) &pRxPacketInfo); + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + isFrmFt = WMA_GET_RX_FT_DONE(pRxPacketInfo); + fc = pHdr->fc; + +#ifdef WLAN_DUMP_MGMTFRAMES + lim_log(pMac, LOGE, + FL("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"), + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, pHdr, + WMA_GET_RX_MPDU_HEADER_LEN(pRxPacketInfo)); +#endif + if (pMac->fEnableDebugLog & 0x1) { + if ((fc.type == SIR_MAC_MGMT_FRAME) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) && + (fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON)) { + lim_log(pMac, LOGE, + FL("RX MGMT - Type %hu, SubType %hu, seq num[%d]"), + fc.type, + fc.subType, + ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + } + } +#ifdef FEATURE_WLAN_EXTSCAN + if (WMA_IS_EXTSCAN_SCAN_SRC(pRxPacketInfo) || + WMA_IS_EPNO_SCAN_SRC(pRxPacketInfo)) { + if (fc.subType == SIR_MAC_MGMT_BEACON || + fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + __lim_process_ext_scan_beacon_probe_rsp(pMac, + pRxPacketInfo, + fc.subType); + } else { + lim_log(pMac, LOGE, + FL("Wrong frameType %d, Subtype %d for %d"), + fc.type, fc.subType, + WMA_GET_SCAN_SRC(pRxPacketInfo)); + } + goto end; + } +#endif + if (WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)) { + if (fc.subType == SIR_MAC_MGMT_BEACON) { + lim_log(pMac, LOG2, FL("Learning scan beacon")); + __lim_handle_beacon(pMac, limMsg, NULL); + } else if (fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + lim_log(pMac, LOG2, FL("Learning scan probe rsp")); + lim_process_probe_rsp_frame_no_session(pMac, pRxPacketInfo); + } else { + lim_log(pMac, LOGE, + FL("Wrong frame Type %d, Subtype %d for LFR"), + fc.type, fc.subType); + } + goto end; + } + /* Added For BT-AMP Support */ + if ((psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, + &sessionId)) == NULL) { +#ifdef WLAN_FEATURE_VOWIFI_11R + if (fc.subType == SIR_MAC_MGMT_AUTH) { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, + FL + ("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"), + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + lim_print_mac_addr(pMac, pHdr->bssId, LOG1); +#endif + if (lim_process_auth_frame_no_session + (pMac, pRxPacketInfo, + limMsg->bodyptr) == eSIR_SUCCESS) { + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, + pRxPacketInfo, limMsg->bodyptr); + return; + } + } +#endif + if ((fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) + && (fc.subType != SIR_MAC_MGMT_ACTION) /* Public action frame can be received from non-associated stations. */ + ) { + + if ((psessionEntry = + pe_find_session_by_peer_sta(pMac, pHdr->sa, + &sessionId)) == NULL) { + lim_log(pMac, LOG1, + FL + ("session does not exist for given bssId")); + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, + pRxPacketInfo, limMsg->bodyptr); + return; + } else + lim_log(pMac, LOG1, + "SessionId:%d Session Exist for given Bssid", + psessionEntry->peSessionId); + } + /* For p2p resp frames search for valid session with DA as */ + /* BSSID will be SA and session will be present with DA only */ + if (fc.subType == SIR_MAC_MGMT_ACTION) { + psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->da, &sessionId); + } + } + + /* Check if frame is registered by HDD */ + if (lim_check_mgmt_registered_frames(pMac, pRxPacketInfo, psessionEntry)) { + lim_log(pMac, LOG1, FL("Received frame is passed to SME")); + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + limMsg->bodyptr); + return; + } + + if (fc.protVer != SIR_MAC_PROTOCOL_VERSION) { /* Received Frame with non-zero Protocol Version */ + lim_log(pMac, LOGE, + FL("Unexpected frame with protVersion %d received"), + fc.protVer); + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); +#ifdef WLAN_DEBUG + pMac->lim.numProtErr++; +#endif + return; + } + +/* Chance of crashing : to be done BT-AMP ........happens when broadcast probe req is received */ + +#ifdef WLAN_DEBUG + pMac->lim.numMAC[fc.type][fc.subType]++; +#endif + + switch (fc.type) { + case SIR_MAC_MGMT_FRAME: + { + /* Received Management frame */ + switch (fc.subType) { + case SIR_MAC_MGMT_ASSOC_REQ: + /* Make sure the role supports Association */ + if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_AP_ROLE(psessionEntry)) + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + else { + /* Unwanted messages - Log error */ + lim_log(pMac, LOGE, + FL + ("unexpected message received %X"), + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_ASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_REASSOC_REQ: + /* Make sure the role supports Reassociation */ + if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + } else { + /* Unwanted messages - Log error */ + lim_log(pMac, LOGE, + FL + ("unexpected message received %X"), + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_REASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_REQ: + lim_process_probe_req_frame_multiple_bss(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_RSP: + if (psessionEntry == NULL) + lim_process_probe_rsp_frame_no_session(pMac, + pRxPacketInfo); + else + lim_process_probe_rsp_frame(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_BEACON: + __lim_handle_beacon(pMac, limMsg, psessionEntry); + break; + + case SIR_MAC_MGMT_DISASSOC: + lim_process_disassoc_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_AUTH: + lim_process_auth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_DEAUTH: + lim_process_deauth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_ACTION: + if (psessionEntry == NULL) + lim_process_action_frame_no_session(pMac, + pRxPacketInfo); + else { + if (WMA_GET_RX_UNKNOWN_UCAST + (pRxPacketInfo)) + lim_handle_unknown_a2_index_frames + (pMac, pRxPacketInfo, + psessionEntry); + else + lim_process_action_frame(pMac, + pRxPacketInfo, + psessionEntry); + } + break; + default: + /* Received Management frame of 'reserved' subtype */ + break; + } /* switch (fc.subType) */ + + } + break; + case SIR_MAC_DATA_FRAME: + { + } + break; + default: + /* Received frame of type 'reserved' */ + break; + + } /* switch (fc.type) */ + +end: + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); + return; +} /*** end lim_handle80211_frames() ***/ + +/** + * lim_send_stop_scan_offload_req() + * + ***FUNCTION: + * This function will be called to abort the ongoing offloaded scan + * request. + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @return CDF_STATUS_SUCCESS or CDF_STATUS_E_FAILURE + */ +CDF_STATUS lim_send_stop_scan_offload_req(tpAniSirGlobal pMac, + uint8_t SessionId, uint32_t scan_id) +{ + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + tAbortScanParams *pAbortScanParams; + + pAbortScanParams = cdf_mem_malloc(sizeof(tAbortScanParams)); + if (NULL == pAbortScanParams) { + lim_log(pMac, LOGP, + FL("Memory allocation failed for AbortScanParams")); + return CDF_STATUS_E_NOMEM; + } + + pAbortScanParams->SessionId = SessionId; + pAbortScanParams->scan_id = scan_id; + msg.type = WMA_STOP_SCAN_OFFLOAD_REQ; + msg.bodyptr = pAbortScanParams; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure")); + cdf_mem_free(pAbortScanParams); + return CDF_STATUS_E_FAILURE; + } + + lim_log(pMac, LOG1, FL("Abort ongoing offload scan.")); + return CDF_STATUS_SUCCESS; + +} + +/** + * lim_process_abort_scan_ind() + * + ***FUNCTION: + * This function is called from HDD to abort the scan which is presently being run + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +void lim_process_abort_scan_ind(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint32_t scan_id) +{ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SCAN_ABORT_IND_EVENT, NULL, 0, 0); +#endif + + lim_log(mac_ctx, LOG2, FL("Processing AbortScan Ind scan_id %d"), + scan_id); + + /* send stop scan cmd to fw if scan offload is enabled. */ + lim_send_stop_scan_offload_req(mac_ctx, session_id, scan_id); + return; +} + +/** + * lim_message_processor() - Process messages from LIM. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received LIM message. + * + * Wrapper function for lim_process_messages when handling messages received by + * LIM.Could either defer messages or process them. + * + * Return: None. + */ +void lim_message_processor(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + if (eLIM_MLM_OFFLINE_STATE == mac_ctx->lim.gLimMlmState) { + pe_free_msg(mac_ctx, msg); + return; + } + + if (!def_msg_decision(mac_ctx, msg)) { + lim_process_messages(mac_ctx, msg); + /* process deferred message queue if allowed */ + if ((!(mac_ctx->lim.gLimAddtsSent)) && + (!(lim_is_system_in_scan_state(mac_ctx))) && + (true == GET_LIM_PROCESS_DEFD_MESGS(mac_ctx))) + lim_process_deferred_message_queue(mac_ctx); + } +} + +#ifdef FEATURE_OEM_DATA_SUPPORT + +void lim_oem_data_rsp_handle_resume_link_rsp(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *mlmOemDataRsp) +{ + if (status != CDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("OEM Data Rsp failed to get the response for resume link")); + } + + if (NULL != pMac->lim.gpLimMlmOemDataReq) { + cdf_mem_free(pMac->lim.gpLimMlmOemDataReq); + pMac->lim.gpLimMlmOemDataReq = NULL; + } + /* "Failure" status doesn't mean that Oem Data Rsp did not happen */ + /* and hence we need to respond to upper layers. Only Resume link is failed, but */ + /* we got the oem data response already. */ + /* Post the meessage to MLM */ + lim_post_sme_message(pMac, LIM_MLM_OEM_DATA_CNF, + (uint32_t *) (mlmOemDataRsp)); + + return; +} + +void lim_process_oem_data_rsp(tpAniSirGlobal pMac, uint32_t *body) +{ + tpLimMlmOemDataRsp mlmOemDataRsp = NULL; + + /* Process all the messages for the lim queue */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + mlmOemDataRsp = (tpLimMlmOemDataRsp) body; + + PELOG1(lim_log + (pMac, LOG1, FL("%s: sending oem data response msg to sme"), + __func__); + ) + lim_post_sme_message(pMac, LIM_MLM_OEM_DATA_CNF, + (uint32_t *) (mlmOemDataRsp)); + + return; +} + +#endif + +/** + * lim_process_messages() - Process messages from upper layers. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received message. + * + * Return: None. + */ +void lim_process_messages(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + uint8_t vdev_id = 0; + tUpdateBeaconParams beacon_params; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t i; + uint8_t p2p_go_exists = 0; + tpPESession session_entry = NULL; + uint8_t defer_msg = false; + tLinkStateParams *link_state_param; + uint16_t pkt_len = 0; + cds_pkt_t *body_ptr = NULL; + CDF_STATUS cdf_status; + tSirMsgQ new_msg; + tSirSmeScanAbortReq *req_msg = NULL; + uint8_t session_id; + uint32_t scan_id; + +#ifdef FEATURE_WLAN_TDLS + tSirTdlsInd *tdls_ind = NULL; + tpDphHashNode sta_ds = NULL; + tTdlsLinkEstablishParams *tdls_link_params = NULL; +#endif + tSirMbMsgP2p *p2p_msg = NULL; + if (ANI_DRIVER_TYPE(mac_ctx) == eDRIVER_TYPE_MFG) { + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Message pointer is Null")); + CDF_ASSERT(0); + return; + } +#ifdef WLAN_DEBUG + mac_ctx->lim.numTot++; +#endif + MTRACE(mac_trace_msg_rx(mac_ctx, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(msg->type, LIM_MSG_PROCESSED));) + + switch (msg->type) { + + case SIR_LIM_UPDATE_BEACON: + lim_update_beacon(mac_ctx); + break; + case SIR_CFG_PARAM_UPDATE_IND: + if (!lim_is_system_in_scan_state(mac_ctx)) { + lim_handle_cf_gparam_update(mac_ctx, msg->bodyval); + break; + } + /* System is in DFS (Learn) mode. + * Defer processsing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) + CDF_TRACE(CDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(mac_ctx); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + } + break; +#ifdef FEATURE_OEM_DATA_SUPPORT + case WMA_START_OEM_DATA_RSP: + lim_process_oem_data_rsp(mac_ctx, msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case WMA_SWITCH_CHANNEL_RSP: + lim_process_switch_channel_rsp(mac_ctx, msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef ANI_SIR_IBSS_PEER_CACHING + case WMA_IBSS_STA_ADD: + lim_ibss_sta_add(mac_ctx, msg->bodyptr); + break; +#endif + case SIR_BB_XPORT_MGMT_MSG: + /* These messages are from Peer MAC entity. */ +#ifdef WLAN_DEBUG + mac_ctx->lim.numBbt++; +#endif + /* The original msg which we were deferring have the + * bodyPointer point to 'BD' instead of 'cds pkt'. If we + * don't make a copy of msg, then overwrite the + * msg->bodyPointer and next time when we try to + * process the msg, we will try to use 'BD' as + * 'cds Pkt' which will cause a crash + */ + if (msg->bodyptr == NULL) { + lim_log(mac_ctx, LOGE, FL("Message bodyptr is Null")); + CDF_ASSERT(0); + break; + } + cdf_mem_copy((uint8_t *) &new_msg, + (uint8_t *) msg, sizeof(tSirMsgQ)); + body_ptr = (cds_pkt_t *) new_msg.bodyptr; + cds_pkt_get_packet_length(body_ptr, &pkt_len); + + cdf_status = wma_ds_peek_rx_packet_info(body_ptr, + (void **) &new_msg.bodyptr, false); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cds_pkt_return_packet(body_ptr); + break; + } + + if (WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)) + lim_log(mac_ctx, LOG1, FL("roamCandidateInd %d"), + WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)); + + if (WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)) + lim_log(mac_ctx, LOG1, FL("offloadScanLearn %d"), + WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)); + + lim_handle80211_frames(mac_ctx, &new_msg, &defer_msg); + + if (defer_msg == true) { + CDF_TRACE(CDF_MODULE_ID_PE, LOG1, + FL("Defer Msg type=%x"), msg->type); + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(mac_ctx); + cds_pkt_return_packet(body_ptr); + } + } else + /* PE is not deferring this 802.11 frame so we need to + * call cds_pkt_return. Asumption here is when Rx mgmt + * frame processing is done, cds packet could be + * freed here. + */ + cds_pkt_return_packet(body_ptr); + break; + case eWNI_SME_SCAN_REQ: + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + case eWNI_SME_DISASSOC_REQ: + case eWNI_SME_DEAUTH_REQ: +#ifdef FEATURE_OEM_DATA_SUPPORT + case eWNI_SME_OEM_DATA_REQ: +#endif +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + case eWNI_SME_TDLS_ADD_STA_REQ: + case eWNI_SME_TDLS_DEL_STA_REQ: + case eWNI_SME_TDLS_LINK_ESTABLISH_REQ: +#endif + case eWNI_SME_RESET_AP_CAPS_CHANGED: + case eWNI_SME_SET_HW_MODE_REQ: + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + /* These messages are from HDD. Need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, true); + break; + + case eWNI_SME_SCAN_ABORT_IND: + req_msg = msg->bodyptr; + if (req_msg) { + session_id = req_msg->sessionId; + scan_id = req_msg->scan_id; + lim_process_abort_scan_ind(mac_ctx, session_id, + scan_id); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case eWNI_SME_SYS_READY_IND: + case eWNI_SME_JOIN_REQ: + case eWNI_SME_REASSOC_REQ: + case eWNI_SME_START_BSS_REQ: + case eWNI_SME_STOP_BSS_REQ: + case eWNI_SME_SWITCH_CHL_IND: + case eWNI_SME_SETCONTEXT_REQ: + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + case eWNI_SME_ASSOC_CNF: + case eWNI_SME_ADDTS_REQ: + case eWNI_SME_DELTS_REQ: + case eWNI_SME_GET_ASSOC_STAS_REQ: + case eWNI_SME_TKIP_CNTR_MEAS_REQ: + case eWNI_SME_UPDATE_APWPSIE_REQ: + case eWNI_SME_HIDE_SSID_REQ: + case eWNI_SME_GET_WPSPBC_SESSION_REQ: + case eWNI_SME_SET_APWPARSNIEs_REQ: + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: +#if defined WLAN_FEATURE_VOWIFI + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: +#endif +#if defined FEATURE_WLAN_ESE + case eWNI_SME_ESE_ADJACENT_AP_REPORT: +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + case eWNI_SME_FT_UPDATE_KEY: + case eWNI_SME_FT_PRE_AUTH_REQ: + case eWNI_SME_FT_AGGR_QOS_REQ: +#endif + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + case eWNI_SME_UPDATE_NOA: + case eWNI_SME_CLEAR_DFS_CHANNEL_LIST: + case eWNI_SME_GET_STATISTICS_REQ: +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eWNI_SME_GET_TSM_STATS_REQ: +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + /* These messages are from HDD.No need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, false); + break; + + case eWNI_PMC_SMPS_STATE_IND: + if (msg->bodyptr) { + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case eWNI_SME_SEND_ACTION_FRAME_IND: + lim_send_p2p_action_frame(mac_ctx, msg); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_ABORT_REMAIN_ON_CHAN_IND: + p2p_msg = (tSirMbMsgP2p *) msg->bodyptr; + lim_abort_remain_on_chan(mac_ctx, p2p_msg->sessionId, + p2p_msg->scan_id); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_P2P_NOA_START_IND: + session_entry = &mac_ctx->lim.gpSession[0]; + lim_log(mac_ctx, LOG1, "LIM received NOA start %x", msg->type); + + /* Since insert NOA is done and NOA start msg received, + * we should deactivate the Insert NOA timer + */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_INSERT_SINGLESHOT_NOA_TIMER); + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session_entry = &mac_ctx->lim.gpSession[i]; + if ((session_entry != NULL) && (session_entry->valid) && + (session_entry->pePersona == CDF_P2P_GO_MODE)) { + /* Save P2P NOA start attribute for Go persona*/ + p2p_go_exists = 1; + cdf_mem_copy(&session_entry->p2pGoPsNoaStartInd, + msg->bodyptr, sizeof(tSirP2PNoaStart)); + cdf_status = + session_entry->p2pGoPsNoaStartInd.status; + if (cdf_status != CDF_STATUS_SUCCESS) + CDF_TRACE(CDF_MODULE_ID_PE, LOGW, + FL( + "GO NOA start status %d by FW"), + cdf_status); + break; + } + } + + if (p2p_go_exists == 0) + CDF_TRACE(CDF_MODULE_ID_PE, LOGW, + FL( + "GO is removed by the time NOA start recvd")); + + /* We received the NOA start indication. Now we can send down + * the SME request which requires off-channel operation */ + lim_process_regd_defd_sme_req_after_noa_start(mac_ctx); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_HAL_TDLS_IND: + tdls_ind = (tpSirTdlsInd) msg->bodyptr; + session_entry = pe_find_session_by_sta_id(mac_ctx, + tdls_ind->staIdx, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOG1, + FL("No session exist for given bssId")); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, tdls_ind->assocId, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOG1, + FL("No sta_ds exist for given staId")); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + lim_log(mac_ctx, LOGE, + FL("rcvd TDLS IND from FW with RC %d "), + tdls_ind->reasonCode); + lim_send_sme_tdls_del_sta_ind(mac_ctx, sta_ds, + session_entry, tdls_ind->reasonCode); + } + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case SIR_HAL_P2P_NOA_ATTR_IND: + session_entry = &mac_ctx->lim.gpSession[0]; + lim_log(mac_ctx, LOG1, FL("Received message Noa_ATTR %x"), + msg->type); + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session_entry = &mac_ctx->lim.gpSession[i]; + if ((session_entry != NULL) && (session_entry->valid) + && (session_entry->pePersona == + CDF_P2P_GO_MODE)) { /* Save P2P attr for Go */ + cdf_mem_copy( + &session_entry->p2pGoPsUpdate, + msg->bodyptr, + sizeof(tSirP2PNoaAttr)); + lim_log(mac_ctx, LOG2, + FL("bssId" + MAC_ADDRESS_STR + " ctWin=%d oppPsFlag=%d"), + MAC_ADDR_ARRAY( + session_entry->bssId), + session_entry->p2pGoPsUpdate.ctWin, + session_entry->p2pGoPsUpdate.oppPsFlag); + lim_log(mac_ctx, LOG2, + FL + (" uNoa1IntervalCnt=%d uNoa1Duration=%d uNoa1Interval=%d uNoa1StartTime=%d"), + session_entry->p2pGoPsUpdate.uNoa1IntervalCnt, + session_entry->p2pGoPsUpdate.uNoa1Duration, + session_entry->p2pGoPsUpdate.uNoa1Interval, + session_entry->p2pGoPsUpdate.uNoa1StartTime); + break; + } + } + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_MISSED_BEACON_IND: + lim_ps_offload_handle_missed_beacon_ind(mac_ctx, msg); + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMA_ROAM_OFFLOAD_SYNCH_IND: + lim_roam_offload_synch_ind(mac_ctx, msg); + /* bodyPtr is freed after handling + * eWNI_SME_ROAM_OFFLOAD_SYNCH_IND in sme_ProcessMsg */ + break; +#endif + case SIR_LIM_ADDTS_RSP_TIMEOUT: + lim_process_sme_req_messages(mac_ctx, msg); + break; +#ifdef FEATURE_WLAN_ESE + case SIR_LIM_ESE_TSM_TIMEOUT: +#ifndef FEATURE_WLAN_ESE_UPLOAD + limProcessTsmTimeoutHandler(mac_ctx, msg); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + break; + case WMA_TSM_STATS_RSP: +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_pe_ese_tsm_rsp(mac_ctx, + (tAniGetTsmStatsRsp *) msg->bodyptr); +#else + limProcessHalEseTsmRsp(mac_ctx, msg); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + break; +#endif + case WMA_ADD_TS_RSP: + lim_process_hal_add_ts_rsp(mac_ctx, msg); + break; + case SIR_LIM_DEL_TS_IND: + lim_process_del_ts_ind(mac_ctx, msg); + break; + case SIR_LIM_BEACON_GEN_IND: + if (mac_ctx->lim.gLimSystemRole != eLIM_AP_ROLE) + sch_process_pre_beacon_ind(mac_ctx, msg); + break; + case SIR_LIM_DELETE_STA_CONTEXT_IND: + lim_delete_sta_context(mac_ctx, msg); + break; + case SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT: + case SIR_LIM_JOIN_FAIL_TIMEOUT: + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + case SIR_LIM_AUTH_FAIL_TIMEOUT: + case SIR_LIM_AUTH_RSP_TIMEOUT: + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + case SIR_LIM_REASSOC_FAIL_TIMEOUT: +#ifdef WLAN_FEATURE_VOWIFI_11R + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: +#endif + case SIR_LIM_REMAIN_CHN_TIMEOUT: + case SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT: + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + case SIR_LIM_DEAUTH_ACK_TIMEOUT: + case SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + /* These timeout messages are handled by MLM sub module */ + lim_process_mlm_req_messages(mac_ctx, msg); + break; + case SIR_LIM_HEART_BEAT_TIMEOUT: + /** check if heart beat failed, even if one Beacon + * is rcvd within the Heart Beat interval continue + * normal processing + */ + if (NULL == msg->bodyptr) + lim_log(mac_ctx, LOGE, + FL("Can't Process HB TO - bodyptr is Null")); + else { + session_entry = (tpPESession) msg->bodyptr; + lim_log(mac_ctx, LOGE, + FL + ("SIR_LIM_HEART_BEAT_TIMEOUT, Session %d"), + ((tpPESession) msg->bodyptr)->peSessionId); + limResetHBPktCount(session_entry); + lim_handle_heart_beat_timeout_for_session(mac_ctx, + session_entry); + } + break; + case SIR_LIM_PROBE_HB_FAILURE_TIMEOUT: + lim_handle_heart_beat_failure_timeout(mac_ctx); + break; + case SIR_LIM_HASH_MISS_THRES_TIMEOUT: + mac_ctx->lim.gLimDisassocFrameCredit = 0; + break; + case SIR_LIM_CNF_WAIT_TIMEOUT: + /* Does not receive CNF or dummy packet */ + lim_handle_cnf_wait_timeout(mac_ctx, (uint16_t) msg->bodyval); + break; + case SIR_LIM_RETRY_INTERRUPT_MSG: + /* Message from ISR upon TFP's max retry limit interrupt */ + break; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid session key interrupt */ + break; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid key ID interrupt */ + break; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + /* Message from ISR upon SP's Replay threshold interrupt */ + break; + case SIR_LIM_CHANNEL_SWITCH_TIMEOUT: + lim_process_channel_switch_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_TIMEOUT: + lim_process_quiet_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_BSS_TIMEOUT: + lim_process_quiet_bss_timeout(mac_ctx); + break; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + lim_handle_update_olbc_cache(mac_ctx); + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_HAL_TDLS_SHOULD_DISCOVER: + case SIR_HAL_TDLS_SHOULD_TEARDOWN: + case SIR_HAL_TDLS_PEER_DISCONNECTED: + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + ("%s received tdls event: 0x%x"), __func__, msg->type); + lim_send_sme_tdls_event_notify(mac_ctx, msg->type, + (void *)msg->bodyptr); + break; +#endif + case WMA_ADD_BSS_RSP: + lim_process_mlm_add_bss_rsp(mac_ctx, msg); + break; + case WMA_ADD_STA_RSP: + lim_process_add_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_STA_RSP: + lim_process_mlm_del_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_BSS_RSP: + lim_handle_delete_bss_rsp(mac_ctx, msg); + break; + case WMA_CSA_OFFLOAD_EVENT: + lim_handle_csa_offload_msg(mac_ctx, msg); + break; + case WMA_SET_BSSKEY_RSP: + case WMA_SET_STA_BCASTKEY_RSP: + lim_process_mlm_set_bss_key_rsp(mac_ctx, msg); + break; + case WMA_SET_STAKEY_RSP: + lim_process_mlm_set_sta_key_rsp(mac_ctx, msg); + break; + case WMA_GET_STATISTICS_RSP: + lim_send_sme_pe_statistics_rsp(mac_ctx, msg->type, + (void *)msg->bodyptr); + break; + case WMA_SET_MIMOPS_RSP: + case WMA_SET_TX_POWER_RSP: + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_SET_MAX_TX_POWER_RSP: +#if defined WLAN_FEATURE_VOWIFI + rrm_set_max_tx_power_rsp(mac_ctx, msg); +#endif + if (msg->bodyptr != NULL) { + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case SIR_LIM_ADDR2_MISS_IND: + lim_log(mac_ctx, LOGE, + FL("Addr2 mismatch interrupt received %X"), msg->type); + /* message from HAL indicating addr2 mismatch interrupt occurred + * msg->bodyptr contains only pointer to 48-bit addr2 field + */ + cdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case WMA_AGGR_QOS_RSP: + lim_process_ft_aggr_qo_s_rsp(mac_ctx, msg); + break; +#endif + case WMA_SET_LINK_STATE_RSP: + link_state_param = (tLinkStateParams *) msg->bodyptr; +#if defined WLAN_FEATURE_VOWIFI_11R + session_entry = link_state_param->session; + if (link_state_param->ft +#if defined WLAN_FEATURE_ROAM_OFFLOAD + && !session_entry->bRoamSynchInProgress +#endif + ) + lim_send_reassoc_req_with_ft_ies_mgmt_frame(mac_ctx, + session_entry->pLimMlmReassocReq, + session_entry); +#endif + if (link_state_param->callback) + link_state_param->callback(mac_ctx, + link_state_param->callbackArg, + link_state_param->status); + cdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_BCN_FILTER_REQ: + session_id = (uint8_t) msg->bodyval; + session_entry = &mac_ctx->lim.gpSession[session_id]; + if ((session_entry != NULL) && + (lim_send_beacon_filter_info(mac_ctx, session_entry) != + eSIR_SUCCESS)) + lim_log(mac_ctx, LOGE, + FL("Failied to send Beacon Filter Info ")); + cdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; +#ifdef FEATURE_WLAN_TDLS + case WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP: + tdls_link_params = (tTdlsLinkEstablishParams *) msg->bodyptr; + session_entry = pe_find_session_by_sta_id(mac_ctx, + tdls_link_params->staIdx, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session %u does not exist"), session_id); + /* Still send the eWNI_SME_TDLS_LINK_ESTABLISH_RSP + * message to SME with session id as zero and status + * as FAILURE so, that message queued in SME queue + * can be freed to prevent the SME cmd buffer leak + */ + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, 0, + NULL, NULL, eSIR_FAILURE); + } else { + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + session_entry->smeSessionId, NULL, NULL, + tdls_link_params->status); + } + cdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; +#endif + case WMA_RX_SCAN_EVENT: + lim_process_rx_scan_event(mac_ctx, msg->bodyptr); + break; + case WMA_IBSS_PEER_INACTIVITY_IND: + lim_process_ibss_peer_inactivity(mac_ctx, msg->bodyptr); + cdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case WMA_DFS_RADAR_IND: + lim_send_sme_dfs_event_notify(mac_ctx, msg->type, + (void *)msg->bodyptr); + /* msg->bodyptr will be freed up by SME/CSR */ + break; + case WMA_DFS_BEACON_TX_SUCCESS_IND: + lim_process_beacon_tx_success_ind(mac_ctx, msg->type, + (void *)msg->bodyptr); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_DISASSOC_TX_COMP: + lim_disassoc_tx_complete_cnf(mac_ctx, msg->bodyval); + break; + case WMA_DEAUTH_TX_COMP: + lim_deauth_tx_complete_cnf(mac_ctx, msg->bodyval); + break; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + case WMA_UPDATE_Q2Q_IE_IND: + cdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + vdev_id = ((uint8_t *)msg->bodyptr)[i]; + session_entry = pe_find_session_by_sme_session_id( + mac_ctx, vdev_id); + if (session_entry == NULL) + continue; + session_entry->sap_advertise_avoid_ch_ie = + (uint8_t)msg->bodyval; + /* + * if message comes for DFS channel, no need to update: + * 1) We wont have MCC with DFS channels. so no need to + * add Q2Q IE + * 2) We cannot end up in DFS channel SCC by channel + * switch from non DFS MCC scenario, so no need to + * remove Q2Q IE + * 3) There is however a case where device start MCC and + * then user modifies hostapd.conf and does SAP + * restart, in such a case, beacon params will be + * reset and thus will not contain Q2Q IE, by default + */ + if (cds_get_channel_state( + session_entry->currentOperChannel) + != CHANNEL_STATE_DFS) { + beacon_params.bssIdx = session_entry->bssIdx; + beacon_params.beaconInterval = + session_entry->beaconParams.beaconInterval; + beacon_params.paramChangeBitmap |= + PARAM_BCN_INTERVAL_CHANGED; + sch_set_fixed_beacon_fields(mac_ctx, + session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } + } + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + case eWNI_SME_NSS_UPDATE_REQ: + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case SIR_HAL_SOC_SET_HW_MODE_RESP: + lim_process_set_hw_mode_resp(mac_ctx, msg->bodyptr); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_SOC_HW_MODE_TRANS_IND: + lim_process_hw_mode_trans_ind(mac_ctx, msg->bodyptr); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_SOC_DUAL_MAC_CFG_RESP: + lim_process_dual_mac_cfg_resp(mac_ctx, msg->bodyptr); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + default: + cdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + /* Unwanted messages */ + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("Discarding unexpected message received %X"), + msg->type); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + break; + + } /* switch (msg->type) */ +} /*** end lim_process_messages() ***/ + +/** + * lim_process_deferred_message_queue + * + ***FUNCTION: + * This function is called by LIM while exiting from Learn + * mode. This function fetches messages posted to the LIM + * deferred message queue limDeferredMsgQ. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_process_deferred_message_queue(tpAniSirGlobal pMac) +{ + tSirMsgQ limMsg = { 0, 0, 0 }; + + tSirMsgQ *readMsg; + uint16_t size; + + /* + ** check any deferred messages need to be processed + **/ + size = pMac->lim.gLimDeferredMsgQ.size; + if (size > 0) { + while ((readMsg = lim_read_deferred_msg_q(pMac)) != NULL) { + cdf_mem_copy((uint8_t *) &limMsg, + (uint8_t *) readMsg, sizeof(tSirMsgQ)); + size--; + lim_process_messages(pMac, &limMsg); + + if ((lim_is_system_in_scan_state(pMac)) + || (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) + || (pMac->lim.gLimSystemInScanLearnMode)) + break; + } + } +} /*** end lim_process_deferred_message_queue() ***/ + +/** + * lim_process_normal_hdd_msg() - Process the message and defer if needed + * @mac_ctx : Pointer to Global MAC structure + * @msg : The message need to be processed + * @rsp_reqd: whether return result to hdd + * + * This function checks the current lim state and decide whether the message + * passed will be deferred or not. + * + * Return: None + */ +static void lim_process_normal_hdd_msg(tpAniSirGlobal mac_ctx, tSirMsgQ *msg, + uint8_t rsp_reqd) +{ + bool defer_msg = true; + + /* Added For BT-AMP Support */ + if ((mac_ctx->lim.gLimSystemRole == eLIM_AP_ROLE) + || (mac_ctx->lim.gLimSystemRole == eLIM_BT_AMP_AP_ROLE) + || (mac_ctx->lim.gLimSystemRole == eLIM_BT_AMP_STA_ROLE) + || (mac_ctx->lim.gLimSystemRole == eLIM_UNKNOWN_ROLE)) { + /* + * This check is required only for the AP and in 2 cases. + * 1. If we are in learn mode and we receive any of these + * messages, you have to come out of scan and process the + * message, hence dont defer the message here. In handler, + * these message could be defered till we actually come out of + * scan mode. + * 2. If radar is detected, you might have to defer all of + * these messages except Stop BSS request/ Switch channel + * request. This decision is also made inside its handler. + * + * Please be careful while using the flag defer_msg. Possibly + * you might end up in an infinite loop. + */ + if ((msg->type == eWNI_SME_START_BSS_REQ) || + (msg->type == eWNI_SME_STOP_BSS_REQ) || + (msg->type == eWNI_SME_SWITCH_CHL_IND)) + defer_msg = false; + } + + if (((mac_ctx->lim.gLimAddtsSent) || + (lim_is_system_in_scan_state(mac_ctx))) && defer_msg) { + /* + * System is in DFS (Learn) mode or awaiting addts response or + * if radar is detected, Defer processsing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + lim_log_session_states(mac_ctx); + /* Release body */ + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } else { + /* + * These messages are from HDD.Since these requests may also be + * generated internally within LIM module, need to distinquish + * and send response to host + */ + if (rsp_reqd) + mac_ctx->lim.gLimRspReqd = true; +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + if (lim_process_sme_req_messages(mac_ctx, msg)) { + /* + * Release body. limProcessSmeReqMessage consumed the + * buffer. We can free it. + */ + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } +} + +void +handle_ht_capabilityand_ht_info(struct sAniSirGlobal *pMac, + tpPESession psessionEntry) +{ + tSirMacHTCapabilityInfo macHTCapabilityInfo; + tSirMacHTParametersInfo macHTParametersInfo; + tSirMacHTInfoField1 macHTInfoField1; + tSirMacHTInfoField2 macHTInfoField2; + tSirMacHTInfoField3 macHTInfoField3; + uint32_t cfgValue; + uint8_t *ptr; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_CAP_INFO value")); + return; + } + ptr = (uint8_t *) &macHTCapabilityInfo; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) macHTCapabilityInfo.lsigTXOPProtection; + pMac->lim.gHTMIMOPSState = + (tSirMacHTMIMOPowerSaveState) macHTCapabilityInfo.mimoPowerSave; + pMac->lim.gHTGreenfield = (uint8_t) macHTCapabilityInfo.greenField; + pMac->lim.gHTMaxAmsduLength = + (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + pMac->lim.gHTShortGI20Mhz = (uint8_t) macHTCapabilityInfo.shortGI20MHz; + pMac->lim.gHTShortGI40Mhz = (uint8_t) macHTCapabilityInfo.shortGI40MHz; + pMac->lim.gHTPSMPSupport = (uint8_t) macHTCapabilityInfo.psmp; + pMac->lim.gHTDsssCckRate40MHzSupport = + (uint8_t) macHTCapabilityInfo.dsssCckMode40MHz; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_PARAM_INFO value")); + return; + } + ptr = (uint8_t *) &macHTParametersInfo; + *ptr = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTAMpduDensity = (uint8_t) macHTParametersInfo.mpduDensity; + pMac->lim.gHTMaxRxAMpduFactor = + (uint8_t) macHTParametersInfo.maxRxAMPDUFactor; + + /* Get HT IE Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD1 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField1; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) macHTInfoField1.serviceIntervalGranularity; + pMac->lim.gHTControlledAccessOnly = + (uint8_t) macHTInfoField1.controlledAccessOnly; + pMac->lim.gHTRifsMode = (uint8_t) macHTInfoField1.rifsMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD2, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD2 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField2; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTOperMode = (tSirMacHTOperatingMode) macHTInfoField2.opMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD3, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD3 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField3; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTPCOActive = (uint8_t) macHTInfoField3.pcoActive; + pMac->lim.gHTPCOPhase = (uint8_t) macHTInfoField3.pcoPhase; + pMac->lim.gHTSecondaryBeacon = + (uint8_t) macHTInfoField3.secondaryBeacon; + pMac->lim.gHTDualCTSProtection = + (uint8_t) macHTInfoField3.dualCTSProtection; + pMac->lim.gHTSTBCBasicMCS = (uint8_t) macHTInfoField3.basicSTBCMCS; + + /* The lim globals for channelwidth and secondary chnl have been removed and should not be used during no session; + * instead direct cfg is read and used when no session for transmission of mgmt frames (same as old); + * For now, we might come here during init and join with sessionEntry = NULL; in that case just fill the globals which exist + * Sessionized entries values will be filled in join or add bss req. The ones which are missed in join are filled below + */ + if (psessionEntry != NULL) { + psessionEntry->htCapability = + IS_DOT11_MODE_HT(psessionEntry->dot11mode); + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) macHTInfoField3.lsigTXOPProtectionFullSupport; + } +} + +void lim_log_session_states(tpAniSirGlobal mac_ctx) +{ +#ifdef WLAN_DEBUG + int i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid) { + CDF_TRACE(CDF_MODULE_ID_PE, LOG1, + FL("sysRole(%d) Session (%d)"), + mac_ctx->lim.gLimSystemRole, i); + CDF_TRACE(CDF_MODULE_ID_PE, LOG1, + FL("SME: Curr %s,Prev %s,MLM: Curr %s,Prev %s"), + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limSmeState), + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limPrevSmeState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limMlmState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limPrevMlmState)); + } + } +#endif +} diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c new file mode 100644 index 0000000000..73f4bf0294 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -0,0 +1,2868 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_send_messages.h" +#include "lim_session_utils.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +#include "host_diag_core_log.h" +#endif +#include "wma_if.h" + +static void lim_process_mlm_start_req(tpAniSirGlobal, uint32_t *); +#ifdef FEATURE_OEM_DATA_SUPPORT +static void lim_process_mlm_oem_data_req(tpAniSirGlobal, uint32_t *); +#endif +static void lim_process_mlm_join_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_auth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_assoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_reassoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_disassoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_deauth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_set_keys_req(tpAniSirGlobal, uint32_t *); + +/* MLM Timeout event handler templates */ +static void lim_process_periodic_probe_req_timer(tpAniSirGlobal mac_ctx); +static void lim_process_join_failure_timeout(tpAniSirGlobal); +static void lim_process_auth_failure_timeout(tpAniSirGlobal); +static void lim_process_auth_rsp_timeout(tpAniSirGlobal, uint32_t); +static void lim_process_assoc_failure_timeout(tpAniSirGlobal, uint32_t); +static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal); + +/** + * lim_process_mlm_req_messages() - process mlm request messages + * @mac_ctx: global MAC context + * @msg: mlm request message + * + * This function is called by lim_post_mlm_message(). This + * function handles MLM primitives invoked by SME. + * Depending on the message type, corresponding function will be + * called. + * ASSUMPTIONS: + * 1. Upon receiving Beacon in WT_JOIN_STATE, MLM module invokes + * APIs exposed by Beacon Processing module for setting parameters + * at MAC hardware. + * 2. If attempt to Reassociate with an AP fails, link with current + * AP is restored back. + * + * Return: None + */ +void lim_process_mlm_req_messages(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + MTRACE(mac_trace_msg_rx(mac_ctx, NO_SESSION, msg->type)); + switch (msg->type) { + case LIM_MLM_START_REQ: + lim_process_mlm_start_req(mac_ctx, msg->bodyptr); + break; +#ifdef FEATURE_OEM_DATA_SUPPORT + case LIM_MLM_OEM_DATA_REQ: + lim_process_mlm_oem_data_req(mac_ctx, msg->bodyptr); + break; +#endif + case LIM_MLM_JOIN_REQ: + lim_process_mlm_join_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_AUTH_REQ: + lim_process_mlm_auth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_ASSOC_REQ: + lim_process_mlm_assoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_REASSOC_REQ: + lim_process_mlm_reassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DISASSOC_REQ: + lim_process_mlm_disassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DEAUTH_REQ: + lim_process_mlm_deauth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_SETKEYS_REQ: + lim_process_mlm_set_keys_req(mac_ctx, msg->bodyptr); + break; + case SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT: + lim_process_periodic_probe_req_timer(mac_ctx); + break; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + lim_process_join_failure_timeout(mac_ctx); + break; + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + lim_process_periodic_join_probe_req_timer(mac_ctx); + break; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + lim_process_auth_failure_timeout(mac_ctx); + break; + case SIR_LIM_AUTH_RSP_TIMEOUT: + lim_process_auth_rsp_timeout(mac_ctx, msg->bodyval); + break; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + lim_process_assoc_failure_timeout(mac_ctx, msg->bodyval); + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + lim_process_ft_preauth_rsp_timeout(mac_ctx); + break; +#endif + case SIR_LIM_REMAIN_CHN_TIMEOUT: + lim_process_remain_on_chn_timeout(mac_ctx); + break; + case SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT: + lim_process_insert_single_shot_noa_timeout(mac_ctx); + break; + case SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + lim_convert_active_channel_to_passive_channel(mac_ctx); + break; + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + lim_process_disassoc_ack_timeout(mac_ctx); + break; + case SIR_LIM_DEAUTH_ACK_TIMEOUT: + lim_process_deauth_ack_timeout(mac_ctx); + break; + case LIM_MLM_TSPEC_REQ: + default: + break; + } /* switch (msg->type) */ +} + +/* WLAN_SUSPEND_LINK Related */ + +/** + * lim_is_link_suspended()- check if link is suspended + * @mac_ctx: global MAC context + * + * This function returns is link is suspended or not. + * Since Suspend link uses init scan, it just returns + * gLimSystemInScanLearnMode flag. + * + * Return: uint8_t(gLimSystemInScanLearnMode flag) + */ +uint8_t lim_is_link_suspended(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->lim.gLimSystemInScanLearnMode; +} + +/** + * lim_change_channel_with_callback() - change channel and register callback + * @mac_ctx: global MAC context + * @new_chan: new channel to switch + * @callback: Callback function + * @cbdata: callback data + * @session_entry: PE session pointer + * + * This function is called to change channel and perform off channel operation + * if required. The caller registers a callback to be called at the end of the + * channel change. + * + * Return: None + */ +void +lim_change_channel_with_callback(tpAniSirGlobal mac_ctx, uint8_t new_chan, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession session_entry) +{ + /* Sanity checks for the current and new channel */ +#if defined WLAN_VOWIFI_DEBUG + lim_log(mac_ctx, LOGE, FL("Switching channel to %d"), new_chan); +#endif + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + + mac_ctx->lim.gpchangeChannelCallback = callback; + mac_ctx->lim.gpchangeChannelData = cbdata; + + lim_send_switch_chnl_params(mac_ctx, new_chan, 0, 0, + CH_WIDTH_20MHZ, session_entry->maxTxPower, + session_entry->peSessionId, false); + + return; +} + +/** + * lim_covert_channel_scan_type() - switch between ACTIVE and PASSIVE scan type + * @mac_ctx: global MAC context + * @chan_num: channel number to change the scan type + * @passive_to_active: flag to indicate if switch allowed + * + * This function is called to get the list, + * change the channel type and set again. + * NOTE: If a channel is ACTIVE, this function will make it as PASSIVE + * If a channel is PASSIVE, this fucntion will make it as ACTIVE + * + * Return: None + */ + +void lim_covert_channel_scan_type(tpAniSirGlobal mac_ctx, uint8_t chan_num, + bool passive_to_active) +{ + + uint32_t i; + uint8_t chan_pair[WNI_CFG_SCAN_CONTROL_LIST_LEN]; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + tSirRetStatus status; + + status = wlan_cfg_get_str(mac_ctx, WNI_CFG_SCAN_CONTROL_LIST, + chan_pair, &len); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Unable to get scan control list")); + return; + } + if (len > WNI_CFG_SCAN_CONTROL_LIST_LEN) { + lim_log(mac_ctx, LOGE, + FL("Invalid scan control list length:%d"), len); + return; + } + for (i = 0; (i + 1) < len; i += 2) { + if (chan_pair[i] != chan_num) /* skip this channel */ + continue; + if ((eSIR_PASSIVE_SCAN == chan_pair[i + 1]) && + true == passive_to_active) { + lim_log(mac_ctx, LOG1, FL + ("Channel %d changed from Passive to Active"), + chan_num); + chan_pair[i + 1] = eSIR_ACTIVE_SCAN; + break; + } + if ((eSIR_ACTIVE_SCAN == chan_pair[i + 1]) && + false == passive_to_active) { + lim_log(mac_ctx, LOG1, FL + ("Channel %d changed from Active to Passive"), + chan_num); + chan_pair[i + 1] = eSIR_PASSIVE_SCAN; + break; + } + } + + cfg_set_str_notify(mac_ctx, WNI_CFG_SCAN_CONTROL_LIST, + (uint8_t *) chan_pair, len, false); + return; +} + +/** + * lim_set_dfs_channel_list() - convert dfs channel list to active channel list + * @mac_ctx: global MAC context. + * @chan_num: channel number + * @dfs_ch_list: list of DFS channels + * + * This function is called to convert DFS channel list to active channel list + * when any beacon is present on that channel. This function store time for + * passive channels which help to know that for how much time channel has been + * passive. + * + * NOTE: If a channel is ACTIVE, it won't store any time + * If a channel is PAssive, it will store time as timestamp + * + * Return: None + */ +void lim_set_dfs_channel_list(tpAniSirGlobal mac_ctx, uint8_t chan_num, + tSirDFSChannelList *dfs_ch_list) +{ + bool pass_to_active = true; + + if (!((1 <= chan_num) && (165 >= chan_num))) { + lim_log(mac_ctx, LOGE, FL("Invalid Channel: %d"), chan_num); + return; + } + + if (true == lim_isconnected_on_dfs_channel(chan_num)) { + if (dfs_ch_list->timeStamp[chan_num] == 0) { + /* + * Received first beacon; + * Convert DFS channel to Active channel. + */ + lim_log(mac_ctx, LOG1, + FL("Received first beacon on DFS channel: %d"), + chan_num); + lim_covert_channel_scan_type(mac_ctx, chan_num, + pass_to_active); + } + dfs_ch_list->timeStamp[chan_num] = + cdf_mc_timer_get_system_time(); + } else { + lim_log(mac_ctx, LOG1, FL("Channel %d is Active"), chan_num); + return; + } + + if (!tx_timer_running + (&mac_ctx->lim.limTimers.gLimActiveToPassiveChannelTimer)) { + tx_timer_activate( + &mac_ctx->lim.limTimers.gLimActiveToPassiveChannelTimer); + } + + return; +} + +/** + * lim_restore_pre_scan_state() - restore HW state prior to scan + * + * @mac_ctx: global MAC context + * + * This function is called by lim_continue_channel_scan() + * to restore HW state prior to entering 'scan state' + * + * Return: None + */ +void lim_restore_pre_scan_state(tpAniSirGlobal mac_ctx) +{ + /* Deactivate MIN/MAX channel timers if running */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_MIN_CHANNEL_TIMER); + lim_deactivate_and_change_timer(mac_ctx, eLIM_MAX_CHANNEL_TIMER); + + mac_ctx->lim.gLimSystemInScanLearnMode = 0; + lim_log(mac_ctx, LOG1, FL("Scan ended, took %llu tu"), + (tx_time_get() - mac_ctx->lim.scanStartTime)); +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * lim_send_hal_oem_data_req() - send oem data request + * @mac_ctx: global MAC context + * + * This function is used to send OEM data request to HAL. + * + * Return: None + */ +void lim_send_hal_oem_data_req(tpAniSirGlobal mac_ctx) +{ + tSirMsgQ msg; + tpStartOemDataReq start_oem_data_req = NULL; + tSirRetStatus rc = eSIR_SUCCESS; + tpLimMlmOemDataRsp mlm_oem_data_rsp; + uint32_t reqlen = 0; + + if (NULL == mac_ctx->lim.gpLimMlmOemDataReq) { + lim_log(mac_ctx, LOGE, FL("Null pointer")); + goto error; + } + + reqlen = sizeof(tStartOemDataReq); + + start_oem_data_req = cdf_mem_malloc(reqlen); + if (NULL == start_oem_data_req) { + lim_log(mac_ctx, LOGE, FL + ("Could not allocate memory for start_oem_data_req")); + goto error; + } + + cdf_mem_set((uint8_t *) (start_oem_data_req), reqlen, 0); + + /* Now copy over the information to the OEM DATA REQ to HAL */ + cdf_mem_copy(start_oem_data_req->selfMacAddr, + mac_ctx->lim.gpLimMlmOemDataReq->selfMacAddr, + sizeof(tSirMacAddr)); + + cdf_mem_copy(start_oem_data_req->oemDataReq, + mac_ctx->lim.gpLimMlmOemDataReq->oemDataReq, + OEM_DATA_REQ_SIZE); + + /* Create the message to be passed to HAL */ + msg.type = WMA_START_OEM_DATA_REQ; + msg.bodyptr = start_oem_data_req; + msg.bodyval = 0; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); + MTRACE(mac_trace_msg_tx(mac_ctx, NO_SESSION, msg.type)); + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc == eSIR_SUCCESS) + return; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + cdf_mem_free(start_oem_data_req); + lim_log(mac_ctx, LOGE, + FL("OEM_DATA: posting WMA_START_OEM_DATA_REQ to HAL failed")); + +error: + mac_ctx->lim.gLimMlmState = mac_ctx->lim.gLimPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, NO_SESSION, + mac_ctx->lim.gLimMlmState)); + + mlm_oem_data_rsp = cdf_mem_malloc(sizeof(tLimMlmOemDataRsp)); + if (NULL == mlm_oem_data_rsp) { + lim_log(mac_ctx->hHdd, LOGP, FL + ("memory allocation for mlm_oem_data_rsp")); + return; + } + + if (NULL != mac_ctx->lim.gpLimMlmOemDataReq) { + cdf_mem_free(mac_ctx->lim.gpLimMlmOemDataReq); + mac_ctx->lim.gpLimMlmOemDataReq = NULL; + } + + lim_post_sme_message(mac_ctx, LIM_MLM_OEM_DATA_CNF, + (uint32_t *) mlm_oem_data_rsp); + + return; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/** + * mlm_add_sta() - MLM add sta + * @mac_ctx: global MAC context + * @sta_param: Add sta params + * @bssid: BSSID + * @ht_capable: HT capability + * @session_entry: PE session entry + * + * This function is called to update station parameters + * + * Return: None + */ +static void mlm_add_sta(tpAniSirGlobal mac_ctx, tpAddStaParams sta_param, + uint8_t *bssid, uint8_t ht_capable, tpPESession session_entry) +{ + uint32_t val; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_dot11mode); + sta_param->staType = STA_ENTRY_SELF; /* Identifying self */ + + cdf_mem_copy(sta_param->bssId, bssid, sizeof(tSirMacAddr)); + cdf_mem_copy(sta_param->staMac, session_entry->selfMacAddr, + sizeof(tSirMacAddr)); + + /* Configuration related parameters to be changed to support BT-AMP */ + + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val)) + lim_log(mac_ctx, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + sta_param->listenInterval = (uint16_t) val; + + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, + &val)) + lim_log(mac_ctx, LOGP, FL("Couldn't get SHORT_PREAMBLE")); + sta_param->shortPreambleSupported = (uint8_t) val; + + sta_param->assocId = 0; /* Is SMAC OK with this? */ + sta_param->wmmEnabled = 0; + sta_param->uAPSD = 0; + sta_param->maxSPLen = 0; + sta_param->us32MaxAmpduDuration = 0; + sta_param->maxAmpduSize = 0; /* 0: 8k, 1: 16k,2: 32k,3: 64k, 4:128k */ + + /* For Self STA get the LDPC capability from config.ini */ + sta_param->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + sta_param->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) { + sta_param->htCapable = ht_capable; + sta_param->greenFieldCapable = + lim_get_ht_capability(mac_ctx, eHT_GREENFIELD, + session_entry); + sta_param->ch_width = + lim_get_ht_capability(mac_ctx, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, session_entry); + sta_param->mimoPS = + (tSirMacHTMIMOPowerSaveState)lim_get_ht_capability( + mac_ctx, eHT_MIMO_POWER_SAVE, session_entry); + sta_param->rifsMode = + lim_get_ht_capability(mac_ctx, eHT_RIFS_MODE, + session_entry); + sta_param->lsigTxopProtection = + lim_get_ht_capability(mac_ctx, eHT_LSIG_TXOP_PROTECTION, + session_entry); + sta_param->maxAmpduDensity = + lim_get_ht_capability(mac_ctx, eHT_MPDU_DENSITY, + session_entry); + sta_param->maxAmsduSize = + lim_get_ht_capability(mac_ctx, eHT_MAX_AMSDU_LENGTH, + session_entry); + sta_param->fDsssCckMode40Mhz = + lim_get_ht_capability(mac_ctx, eHT_DSSS_CCK_MODE_40MHZ, + session_entry); + sta_param->fShortGI20Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_20MHZ, + session_entry); + sta_param->fShortGI40Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_40MHZ, + session_entry); + } + if (session_entry->vhtCapability) { + sta_param->vhtCapable = true; + sta_param->vhtTxBFCapable = + session_entry->txBFIniFeatureEnabled; + sta_param->vhtTxMUBformeeCapable = session_entry->txMuBformee; + sta_param->enable_su_tx_bformer = + session_entry->enable_su_tx_bformer; + } + /* + * Since this is Self-STA, need to populate Self MAX_AMPDU_SIZE + * capabilities + */ + if (IS_DOT11_MODE_VHT(self_dot11mode)) { + val = 0; /* Default 8K AMPDU size */ + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &val)) + lim_log(mac_ctx, LOGE, FL + ("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT")); + sta_param->maxAmpduSize = (uint8_t) val; + } + sta_param->enableVhtpAid = session_entry->enableVhtpAid; + sta_param->enableAmpduPs = session_entry->enableAmpduPs; + sta_param->enableHtSmps = session_entry->enableHtSmps; + sta_param->htSmpsconfig = session_entry->htSmpsvalue; + +#ifdef WLAN_FEATURE_11AC + lim_populate_own_rate_set(mac_ctx, &sta_param->supportedRates, NULL, + false, session_entry, NULL); +#else + lim_populate_own_rate_set(mac_ctx, &sta_param->supportedRates, NULL, + false, session_entry); +#endif + lim_fill_supported_rates_info(mac_ctx, NULL, &sta_param->supportedRates, + session_entry); + + lim_log(mac_ctx, LOGE, FL( + "GF: %d, ChnlWidth: %d, MimoPS: %d, lsigTXOP: %d, dsssCCK: %d," + " SGI20: %d, SGI40%d"), sta_param->greenFieldCapable, + sta_param->ch_width, sta_param->mimoPS, + sta_param->lsigTxopProtection, sta_param->fDsssCckMode40Mhz, + sta_param->fShortGI20Mhz, sta_param->fShortGI40Mhz); + + if (CDF_P2P_GO_MODE == session_entry->pePersona) + sta_param->p2pCapableSta = 1; +} + +/** + * lim_mlm_add_bss() - HAL interface for WMA_ADD_BSS_REQ + * @mac_ctx: global MAC context + * @mlm_start_req: MLM start request + * @session: PE session entry + * + * Package WMA_ADD_BSS_REQ to HAL, in order to start a BSS + * + * Return: eSIR_SME_SUCCESS on success, other error codes otherwise + */ +tSirResultCodes +lim_mlm_add_bss(tpAniSirGlobal mac_ctx, + tLimMlmStartReq *mlm_start_req, tpPESession session) +{ + tSirMsgQ msg_buf; + tpAddBssParams addbss_param = NULL; + uint32_t retcode; + + /* Package WMA_ADD_BSS_REQ message parameters */ + addbss_param = cdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == addbss_param) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory during ADD_BSS")); + /* Respond to SME with LIM_MLM_START_CNF */ + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set(addbss_param, sizeof(tAddBssParams), 0); + /* Fill in tAddBssParams members */ + cdf_mem_copy(addbss_param->bssId, mlm_start_req->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + cdf_mem_copy(addbss_param->selfMacAddr, + session->selfMacAddr, sizeof(tSirMacAddr)); + + addbss_param->bssType = mlm_start_req->bssType; + if ((mlm_start_req->bssType == eSIR_IBSS_MODE) || + (mlm_start_req->bssType == eSIR_BTAMP_AP_MODE) || + (mlm_start_req->bssType == eSIR_BTAMP_STA_MODE)) { + addbss_param->operMode = BSS_OPERATIONAL_MODE_STA; + } else if (mlm_start_req->bssType == eSIR_INFRA_AP_MODE) { + addbss_param->operMode = BSS_OPERATIONAL_MODE_AP; + } + + addbss_param->shortSlotTimeSupported = session->shortSlotTimeSupported; + addbss_param->beaconInterval = mlm_start_req->beaconPeriod; + addbss_param->dtimPeriod = mlm_start_req->dtimPeriod; + addbss_param->wps_state = mlm_start_req->wps_state; + addbss_param->cfParamSet.cfpCount = mlm_start_req->cfParamSet.cfpCount; + addbss_param->cfParamSet.cfpPeriod = + mlm_start_req->cfParamSet.cfpPeriod; + addbss_param->cfParamSet.cfpMaxDuration = + mlm_start_req->cfParamSet.cfpMaxDuration; + addbss_param->cfParamSet.cfpDurRemaining = + mlm_start_req->cfParamSet.cfpDurRemaining; + + addbss_param->rateSet.numRates = mlm_start_req->rateSet.numRates; + cdf_mem_copy(addbss_param->rateSet.rate, mlm_start_req->rateSet.rate, + mlm_start_req->rateSet.numRates); + + addbss_param->nwType = mlm_start_req->nwType; + addbss_param->htCapable = mlm_start_req->htCapable; + addbss_param->vhtCapable = session->vhtCapability; + addbss_param->ch_width = session->ch_width; + addbss_param->ch_center_freq_seg0 = + session->ch_center_freq_seg0; + addbss_param->ch_center_freq_seg1 = + session->ch_center_freq_seg1; + addbss_param->htOperMode = mlm_start_req->htOperMode; + addbss_param->dualCTSProtection = mlm_start_req->dualCTSProtection; + addbss_param->txChannelWidthSet = mlm_start_req->txChannelWidthSet; + + addbss_param->currentOperChannel = mlm_start_req->channelNumber; +#ifdef WLAN_FEATURE_11W + addbss_param->rmfEnabled = session->limRmfEnabled; +#endif + + /* Update PE sessionId */ + addbss_param->sessionId = mlm_start_req->sessionId; + + /* Send the SSID to HAL to enable SSID matching for IBSS */ + cdf_mem_copy(&(addbss_param->ssId.ssId), + mlm_start_req->ssId.ssId, mlm_start_req->ssId.length); + addbss_param->ssId.length = mlm_start_req->ssId.length; + addbss_param->bHiddenSSIDEn = mlm_start_req->ssidHidden; + lim_log(mac_ctx, LOGE, FL("TRYING TO HIDE SSID %d"), + addbss_param->bHiddenSSIDEn); + /* CR309183. Disable Proxy Probe Rsp. Host handles Probe Requests. Until FW fixed. */ + addbss_param->bProxyProbeRespEn = 0; + addbss_param->obssProtEnabled = mlm_start_req->obssProtEnabled; + +#if defined WLAN_FEATURE_VOWIFI + addbss_param->maxTxPower = session->maxTxPower; +#endif + mlm_add_sta(mac_ctx, &addbss_param->staContext, + addbss_param->bssId, addbss_param->htCapable, + session); + + addbss_param->status = CDF_STATUS_SUCCESS; + addbss_param->respReqd = 1; + + /* Set a new state for MLME */ + session->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* pass on the session persona to hal */ + addbss_param->halPersona = session->pePersona; + + addbss_param->bSpectrumMgtEnabled = session->spectrumMgtEnabled || + lim_isconnected_on_dfs_channel(mlm_start_req->channelNumber); +#if defined WLAN_FEATURE_VOWIFI_11R + addbss_param->extSetStaKeyParamValid = 0; +#endif + + addbss_param->dot11_mode = session->dot11mode; + addbss_param->nss = session->nss; + lim_log(mac_ctx, LOG2, FL("dot11_mode:%d nss value:%d"), + addbss_param->dot11_mode, addbss_param->nss); + + msg_buf.type = WMA_ADD_BSS_REQ; + msg_buf.reserved = 0; + msg_buf.bodyptr = addbss_param; + msg_buf.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, session->peSessionId, msg_buf.type)); + + lim_log(mac_ctx, LOGW, FL("Sending WMA_ADD_BSS_REQ...")); + retcode = wma_post_ctrl_msg(mac_ctx, &msg_buf); + if (eSIR_SUCCESS != retcode) { + lim_log(mac_ctx, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retcode); + cdf_mem_free(addbss_param); + return eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + + return eSIR_SME_SUCCESS; +} + +/** + * lim_process_mlm_start_req() - process MLM_START_REQ message + * + * @mac_ctx: global MAC context + * @msg_buf: Pointer to MLM message buffer + * + * This function is called to process MLM_START_REQ message + * from SME + * 1) MLME receives LIM_MLM_START_REQ from LIM + * 2) MLME sends WMA_ADD_BSS_REQ to HAL + * 3) MLME changes state to eLIM_MLM_WT_ADD_BSS_RSP_STATE + * MLME now waits for HAL to send WMA_ADD_BSS_RSP + * + * Return: None + */ +static void lim_process_mlm_start_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmStartReq *mlm_start_req; + tLimMlmStartCnf mlm_start_cnf; + tpPESession session = NULL; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_start_req = (tLimMlmStartReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_start_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + mlm_start_cnf.resultCode = eSIR_SME_REFUSED; + goto end; + } + + if (session->limMlmState != eLIM_MLM_IDLE_STATE) { + /* + * Should not have received Start req in states other than idle. + * Return Start confirm with failure code. + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected MLM_START_REQ in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto end; + } + + mlm_start_cnf.resultCode = + lim_mlm_add_bss(mac_ctx, mlm_start_req, session); + +end: + /* Update PE session Id */ + mlm_start_cnf.sessionId = mlm_start_req->sessionId; + + /* Free up buffer allocated for LimMlmScanReq */ + cdf_mem_free(msg_buf); + + /* + * Respond immediately to LIM, only if MLME has not been + * successfully able to send WMA_ADD_BSS_REQ to HAL. + * Else, LIM_MLM_START_CNF will be sent after receiving + * WMA_ADD_BSS_RSP from HAL + */ + if (eSIR_SME_SUCCESS != mlm_start_cnf.resultCode) + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * lim_process_mlm_oem_data_req() - process MLM OEM_DATA_REQ message + * @mac_ctx: global MAC context + * @msg_buf: MLM message buffer + * + * This function process MLM OEM_DATA_REQ message. + * + * Return: None + */ +static void lim_process_mlm_oem_data_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tLimMlmOemDataRsp *mlm_oem_data_rsp; + + if (((mac_ctx->lim.gLimMlmState == eLIM_MLM_IDLE_STATE) || + (mac_ctx->lim.gLimMlmState == eLIM_MLM_JOINED_STATE) || + (mac_ctx->lim.gLimMlmState == eLIM_MLM_AUTHENTICATED_STATE) || + (mac_ctx->lim.gLimMlmState == eLIM_MLM_BSS_STARTED_STATE) || + (mac_ctx->lim.gLimMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE))) { + /* + * Hold onto the oem data request criteria + * Free gpLimMlmOemDataReq to avoid memory leak due to + * second OEM data request + */ + if (mac_ctx->lim.gpLimMlmOemDataReq) { + cdf_mem_free(mac_ctx->lim.gpLimMlmOemDataReq); + mac_ctx->lim.gpLimMlmOemDataReq = NULL; + } + + mac_ctx->lim.gpLimMlmOemDataReq = (tLimMlmOemDataReq *) msg_buf; + mac_ctx->lim.gLimPrevMlmState = mac_ctx->lim.gLimMlmState; + + lim_log(mac_ctx, LOG2, FL("Calling lim_send_hal_oem_data_req")); + lim_send_hal_oem_data_req(mac_ctx); + } else { + /* Should not have received oem data req in other states */ + lim_log(mac_ctx, LOGW, FL + ("unexpected LIM_MLM_OEM_DATA_REQ in invalid state %X"), + mac_ctx->lim.gLimMlmState); + lim_print_mlm_state(mac_ctx, LOGW, mac_ctx->lim.gLimMlmState); + + /* Free up buffer allocated */ + cdf_mem_free(msg_buf); + + /* Return Meas confirm with INVALID_PARAMETERS */ + mlm_oem_data_rsp = cdf_mem_malloc(sizeof(tLimMlmOemDataRsp)); + if (mlm_oem_data_rsp != NULL) { + lim_post_sme_message(mac_ctx, LIM_MLM_OEM_DATA_CNF, + (uint32_t *) mlm_oem_data_rsp); + cdf_mem_free(mlm_oem_data_rsp); + } else { + lim_log(mac_ctx, LOGP, FL + ("Could not allocate memory for mlm_oem_data_rsp")); + return; + } + } + + return; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ +/** + * lim_post_join_set_link_state_callback()- registered callback to perform post + * peer creation operations + * + * @mac: pointer to global mac structure + * @callback_arg: registered callback argument + * @status: peer creation status + * + * this is registered callback function during association to perform + * post peer creation operation based on the peer creation status + * + * Return: none + */ +void lim_post_join_set_link_state_callback(tpAniSirGlobal mac, + void *callback_arg, bool status) +{ + uint8_t chan_num, sec_chan_offset; + tpPESession session_entry = (tpPESession) callback_arg; + tLimMlmJoinCnf mlm_join_cnf; + + lim_log(mac, LOG1, FL("Sessionid %d set link state(%d) cb status:%d"), + session_entry->peSessionId, session_entry->limMlmState, + status); + + if (!status) { + lim_log(mac, LOGE, + FL("failed to find pe session for session id:%d"), + session_entry->peSessionId); + goto failure; + } + + chan_num = session_entry->currentOperChannel; + sec_chan_offset = session_entry->htSecondaryChannelOffset; + /* + * store the channel switch session_entry in the lim + * global variable + */ + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_JOIN; +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + session_entry->pLimMlmReassocRetryReq = NULL; +#endif + lim_log(mac, LOGE, + FL("[lim_process_mlm_join_req]: suspend link success(%d) " + "on sessionid: %d setting channel to: %d with ch_width :%d " + "and maxtxPower: %d"), status, session_entry->peSessionId, + session_entry->currentOperChannel, + session_entry->ch_width, + session_entry->maxTxPower); + lim_set_channel(mac, session_entry->currentOperChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + session_entry->maxTxPower, + session_entry->peSessionId); + return; + +failure: + MTRACE(mac_trace(mac, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlm_join_cnf.sessionId = session_entry->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac, LIM_MLM_JOIN_CNF, (uint32_t *) &mlm_join_cnf); +} + +/** + * lim_process_mlm_post_join_suspend_link() - This function is called after the + * suspend link while joining off channel. + * + * @mac_ctx: Pointer to Global MAC structure + * @status: status of suspend link. + * @ctx: passed while calling suspend link(session) + * + * This function does following: + * Check for suspend state. + * If success, proceed with setting link state to recieve the + * probe response/beacon from intended AP. + * Switch to the APs channel. + * On an error case, send the MLM_JOIN_CNF with error status. + * + * @Return None + */ +static void +lim_process_mlm_post_join_suspend_link(tpAniSirGlobal mac_ctx, + CDF_STATUS status, + uint32_t *ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + tpPESession session = (tpPESession) ctx; + tSirLinkState lnk_state; + + if (CDF_STATUS_SUCCESS != status) { + lim_log(mac_ctx, LOGE, + FL("Sessionid %d Suspend link(NOTIFY_BSS) failed. Still proceeding with join"), + session->peSessionId); + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId = + session->peSessionId; + + lnk_state = (LIM_IS_BT_AMP_STA_ROLE(session) ? + eSIR_LINK_BTAMP_PREASSOC_STATE : eSIR_LINK_PREASSOC_STATE); + lim_log(mac_ctx, LOG1, FL("[lim_process_mlm_join_req]: lnk_state:%d"), + lnk_state); + + if (lim_set_link_state(mac_ctx, lnk_state, + session->pLimMlmJoinReq->bssDescription.bssId, + session->selfMacAddr, + lim_post_join_set_link_state_callback, + session) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("SessionId:%d lim_set_link_state to eSIR_LINK_PREASSOC_STATE Failed!!"), + session->peSessionId); + lim_print_mac_addr(mac_ctx, + session->pLimMlmJoinReq->bssDescription.bssId, LOGE); + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + goto error; + } + + return; +error: + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlm_join_cnf.sessionId = session->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); +} + +/** + * lim_process_mlm_join_req() - process mlm join request. + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: Pointer to the MLM message buffer + * + * This function is called to process MLM_JOIN_REQ message + * from SME. It does following: + * 1) Initialize LIM, HAL, DPH + * 2) Configure the BSS for which the JOIN REQ was received + * a) Send WMA_ADD_BSS_REQ to HAL - + * This will identify the BSS that we are interested in + * --AND-- + * Add a STA entry for the AP (in a STA context) + * b) Wait for WMA_ADD_BSS_RSP + * c) Send WMA_ADD_STA_REQ to HAL + * This will add the "local STA" entry to the STA table + * 3) Continue as before, i.e, + * a) Send a PROBE REQ + * b) Wait for PROBE RSP/BEACON containing the SSID that + * we are interested in + * c) Then start an AUTH seq + * d) Followed by the ASSOC seq + * + * @Return: None + */ +static void lim_process_mlm_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tLimMlmJoinCnf mlmjoin_cnf; + uint8_t sessionid; + tpPESession session; + + sessionid = ((tpLimMlmJoinReq) msg)->sessionId; + + session = pe_find_session_by_session_id(mac_ctx, sessionid); + if (NULL == session) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d does not exist"), + sessionid); + goto error; + } + + if ((!LIM_IS_AP_ROLE(session) && + !LIM_IS_BT_AMP_AP_ROLE(session)) && + ((session->limMlmState == eLIM_MLM_IDLE_STATE) || + (session->limMlmState == eLIM_MLM_JOINED_STATE)) && + (SIR_MAC_GET_ESS + (((tpLimMlmJoinReq) msg)->bssDescription.capabilityInfo) != + SIR_MAC_GET_IBSS(((tpLimMlmJoinReq) msg)->bssDescription. + capabilityInfo))) { + /* Hold onto Join request parameters */ + + session->pLimMlmJoinReq = (tpLimMlmJoinReq) msg; + if (is_lim_session_off_channel(mac_ctx, sessionid)) { + lim_log(mac_ctx, LOG1, + "SessionId:%d LimSession is on OffChannel", + sessionid); + /* suspend link */ + lim_log(mac_ctx, LOG1, + FL("Suspend link, sessionid %d is off channel"), + sessionid); + if (lim_is_link_suspended(mac_ctx)) { + lim_log(mac_ctx, LOGE, FL( + "link is already suspended, session %d" + ), sessionid); + goto error; + } + lim_process_mlm_post_join_suspend_link(mac_ctx, + CDF_STATUS_SUCCESS, (uint32_t *)session); + } else { + lim_log(mac_ctx, LOG1, FL("No need to Suspend link")); + /* + * No need to Suspend link as LimSession is not + * off channel, calling + * lim_process_mlm_post_join_suspend_link with + * status as SUCCESS. + */ + lim_log(mac_ctx, LOG1, + FL("SessionId:%d Join req on current chan"), + sessionid); + lim_process_mlm_post_join_suspend_link(mac_ctx, + CDF_STATUS_SUCCESS, (uint32_t *)session); + } + return; + } else { + /** + * Should not have received JOIN req in states other than + * Idle state or on AP. + * Return join confirm with invalid parameters code. + */ + lim_log(mac_ctx, LOGE, + FL("Session:%d Unexpected Join req, role %d state %X"), + session->peSessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + } + +error: + cdf_mem_free(msg); + if (session != NULL) + session->pLimMlmJoinReq = NULL; + mlmjoin_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmjoin_cnf.sessionId = sessionid; + mlmjoin_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&mlmjoin_cnf); + +} + +/** + * lim_is_auth_req_expected() - check if auth request is expected + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called by lim_process_mlm_auth_req to check + * if auth request is expected. + * + * Return: true if expected and false otherwise + */ +static bool lim_is_auth_req_expected(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + bool flag = false; + + /* + * Expect Auth request only when: + * 1. STA joined/associated with a BSS or + * 2. STA is in IBSS mode + * and STA is going to authenticate with a unicast + * address and requested authentication algorithm is + * supported. + */ + + flag = ((((LIM_IS_STA_ROLE(session) || + LIM_IS_BT_AMP_STA_ROLE(session)) && + ((session->limMlmState == eLIM_MLM_JOINED_STATE) || + (session->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE))) || + (LIM_IS_IBSS_ROLE(session) && + (session->limMlmState == + eLIM_MLM_BSS_STARTED_STATE))) && + (!lim_is_group_addr(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)) + && lim_is_auth_algo_supported(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->authType, session)); + + return flag; +} + +/** + * lim_is_preauth_ctx_exisits() - check if preauth context exists + * + * @mac_ctx: global MAC context + * @session: PE session entry + * @preauth_node_ptr: pointer to preauth node pointer + * + * This function is called by lim_process_mlm_auth_req to check + * if preauth context already exists + * + * Return: true if exists and false otherwise + */ +static bool lim_is_preauth_ctx_exists(tpAniSirGlobal mac_ctx, + tpPESession session, + struct tLimPreAuthNode **preauth_node_ptr) +{ + bool fl = false; + struct tLimPreAuthNode *preauth_node; + tpDphHashNode stads; + tSirMacAddr curr_bssid; + + preauth_node = *preauth_node_ptr; + sir_copy_mac_addr(curr_bssid, session->bssId); + stads = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + preauth_node = lim_search_pre_auth_list(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + fl = (((LIM_IS_STA_ROLE(session) || LIM_IS_BT_AMP_STA_ROLE(session)) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + ((stads != NULL) && + (mac_ctx->lim.gpLimMlmAuthReq->authType == + stads->mlmStaContext.authType)) && + (cdf_mem_compare(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr)))) || + ((preauth_node != NULL) && + (preauth_node->authType == + mac_ctx->lim.gpLimMlmAuthReq->authType))); + + return fl; +} + +/** + * lim_process_mlm_auth_req() - process lim auth request + * + * @mac_ctx: global MAC context + * @msg: MLM auth request message + * + * This function is called to process MLM_AUTH_REQ message from SME + * + * @Return: None + */ +static void lim_process_mlm_auth_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + uint32_t num_preauth_ctx; + tSirMacAddr curr_bssid; + tSirMacAuthFrameBody auth_frame_body; + tLimMlmAuthCnf mlm_auth_cnf; + struct tLimPreAuthNode *preauth_node = NULL; + uint8_t session_id; + tpPESession session; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mac_ctx->lim.gpLimMlmAuthReq = (tLimMlmAuthReq *) msg; + session_id = mac_ctx->lim.gpLimMlmAuthReq->sessionId; + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGP, FL("SessionId:%d does not exist"), + session_id); + return; + } + + lim_log(mac_ctx, LOG1, FL("Process Auth Req sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR + " with authtype %d"), session_id, + GET_LIM_SYSTEM_ROLE(session), session->limMlmState, + MAC_ADDR_ARRAY(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr), + mac_ctx->lim.gpLimMlmAuthReq->authType); + + sir_copy_mac_addr(curr_bssid, session->bssId); + + if (!lim_is_auth_req_expected(mac_ctx, session)) { + /* + * Unexpected auth request. + * Return Auth confirm with Invalid parameters code. + */ + mlm_auth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* + * This is a request for pre-authentication. Check if there exists + * context already for the requested peer OR + * if this request is for the AP we're currently associated with. + * If yes, return auth confirm immediately when + * requested auth type is same as the one used before. + */ + if (lim_is_preauth_ctx_exists(mac_ctx, session, &preauth_node)) { + lim_log(mac_ctx, LOG2, + FL("Already have pre-auth context with peer: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)); + mlm_auth_cnf.resultCode = (tSirResultCodes) + eSIR_MAC_SUCCESS_STATUS; + goto end; + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &num_preauth_ctx) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Could not retrieve NumPreAuthLimit from CFG")); + + if (mac_ctx->lim.gLimNumPreAuthContexts == num_preauth_ctx) { + lim_log(mac_ctx, LOGW, + FL("Number of pre-auth reached max limit")); + /* Return Auth confirm with reject code */ + mlm_auth_cnf.resultCode = + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED; + goto end; + } + } + + /* Delete pre-auth node if exists */ + if (preauth_node) + lim_delete_pre_auth_node(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_AUTH_FRAME2_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Prepare & send Authentication frame */ + auth_frame_body.authAlgoNumber = + (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_frame_body.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + auth_frame_body.authStatusCode = 0; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_START_EVENT, session, + eSIR_SUCCESS, auth_frame_body.authStatusCode); +#endif + + lim_send_auth_mgmt_frame(mac_ctx, + &auth_frame_body, mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + LIM_NO_WEP_IN_FC, session); + + /* assign appropriate session_id to the timer object */ + mac_ctx->lim.limTimers.gLimAuthFailureTimer.sessionId = session_id; + + /* Activate Auth failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimAuthFailureTimer) + != TX_SUCCESS) { + /* Could not start Auth failure timer. */ + lim_log(mac_ctx, LOGP, + FL("could not start Auth failure timer")); + /* Cleanup as if auth timer expired */ + lim_process_auth_failure_timeout(mac_ctx); + } + return; +end: + cdf_mem_copy((uint8_t *) &mlm_auth_cnf.peerMacAddr, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + + mlm_auth_cnf.authType = mac_ctx->lim.gpLimMlmAuthReq->authType; + mlm_auth_cnf.sessionId = session_id; + + cdf_mem_free(mac_ctx->lim.gpLimMlmAuthReq); + mac_ctx->lim.gpLimMlmAuthReq = NULL; + lim_log(mac_ctx, LOG1, "SessionId:%d LimPostSme LIM_MLM_AUTH_CNF ", + session_id); + lim_post_sme_message(mac_ctx, LIM_MLM_AUTH_CNF, + (uint32_t *) &mlm_auth_cnf); +} + +/** + * lim_process_mlm_assoc_req() - This function is called to process + * MLM_ASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_ASSOC_REQ message from SME + * + * @Return None + */ + +static void lim_process_mlm_assoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tSirMacAddr curr_bssId; + tLimMlmAssocReq *mlm_assoc_req; + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session_entry; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_assoc_req = (tLimMlmAssocReq *) msg_buf; + session_entry = pe_find_session_by_session_id(mac_ctx, + mlm_assoc_req->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGP, + FL("SessionId:%d Session Does not exist"), + mlm_assoc_req->sessionId); + cdf_mem_free(mlm_assoc_req); + return; + } + + sir_copy_mac_addr(curr_bssId, session_entry->bssId); + + if (!((!LIM_IS_AP_ROLE(session_entry) && + !LIM_IS_BT_AMP_AP_ROLE(session_entry)) && + (session_entry->limMlmState == eLIM_MLM_AUTHENTICATED_STATE || + session_entry->limMlmState == eLIM_MLM_JOINED_STATE) && + (cdf_mem_compare(mlm_assoc_req->peerMacAddr, + curr_bssId, sizeof(tSirMacAddr))))) { + /* + * Received Association request either in invalid state + * or to a peer MAC entity whose address is different + * from one that STA is currently joined with or on AP. + * Return Assoc confirm with Invalid parameters code. + */ + lim_log(mac_ctx, LOGW, + FL("received unexpected MLM_ASSOC_CNF in state %X for role=%d, MAC addr= " + MAC_ADDRESS_STR), session_entry->limMlmState, + GET_LIM_SYSTEM_ROLE(session_entry), + MAC_ADDR_ARRAY(mlm_assoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session_entry->limMlmState); + mlm_assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + /* map the session entry pointer to the AssocFailureTimer */ + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId = + mlm_assoc_req->sessionId; +#ifdef WLAN_FEATURE_11W + /* + * Store current MLM state in case ASSOC response returns with + * TRY_AGAIN_LATER return code. + */ + if (session_entry->limRmfEnabled) { + session_entry->pmfComebackTimerInfo.limPrevMlmState = + session_entry->limPrevMlmState; + session_entry->pmfComebackTimerInfo.limMlmState = + session_entry->limMlmState; + } +#endif /* WLAN_FEATURE_11W */ + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + lim_log(mac_ctx, LOG1, FL("SessionId:%d Sending Assoc_Req Frame"), + session_entry->peSessionId); + + /* Prepare and send Association request frame */ + lim_send_assoc_req_mgmt_frame(mac_ctx, mlm_assoc_req, session_entry); + + /* + * Set the link state to postAssoc, so HW can start receiving frames + * from AP. + */ + if ((session_entry->bssType == eSIR_BTAMP_STA_MODE) || + ((session_entry->bssType == eSIR_BTAMP_AP_MODE) + && LIM_IS_BT_AMP_STA_ROLE(session_entry))) { + if (lim_set_link_state(mac_ctx, eSIR_LINK_BTAMP_POSTASSOC_STATE, + curr_bssId, session_entry->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("Failed to set the LinkState")); + } + /* Start association failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_ASSOC_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimAssocFailureTimer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("SessionId:%d couldn't start Assoc failure timer"), + session_entry->peSessionId); + /* Cleanup as if assoc timer expired */ + lim_process_assoc_failure_timeout(mac_ctx, LIM_ASSOC); + } + + return; +end: + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = mlm_assoc_req->sessionId; + /* Free up buffer allocated for assocReq */ + cdf_mem_free(mlm_assoc_req); + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); +} + +/** + * lim_process_mlm_reassoc_req() - process mlm reassoc request. + * + * @mac_ctx: pointer to Global MAC structure + * @msg: pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_REQ message + * from SME + * + * Return: None + */ +static void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + uint8_t channel, sec_ch_offset; + struct tLimPreAuthNode *auth_node; + tLimMlmReassocReq *reassoc_req; + tLimMlmReassocCnf reassoc_cnf; + tpPESession session; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + reassoc_req = (tLimMlmReassocReq *) msg; + session = pe_find_session_by_session_id(mac_ctx, + reassoc_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionId %d"), + reassoc_req->sessionId); + cdf_mem_free(reassoc_req); + return; + } + + lim_log(mac_ctx, LOG1, + FL("Process ReAssoc Req on sessionID %d Systemrole %d mlmstate %d from: " MAC_ADDRESS_STR), + reassoc_req->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, MAC_ADDR_ARRAY(reassoc_req->peerMacAddr)); + + if ((LIM_IS_AP_ROLE(session) || + LIM_IS_BT_AMP_AP_ROLE(session)) || + (session->limMlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + /* + * Received Reassoc request in invalid state or + * in AP role.Return Reassoc confirm with Invalid + * parameters code. + */ + + lim_log(mac_ctx, LOGW, + FL("received unexpected MLM_REASSOC_CNF in state %X for role=%d, MAC addr= " MAC_ADDRESS_STR), + session->limMlmState, GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(reassoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + reassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + if (session->pLimMlmReassocReq) + cdf_mem_free(session->pLimMlmReassocReq); + + /* + * Hold Re-Assoc request as part of Session, knock-out mac_ctx + * Hold onto Reassoc request parameters + */ + session->pLimMlmReassocReq = reassoc_req; + + /* See if we have pre-auth context with new AP */ + auth_node = lim_search_pre_auth_list(mac_ctx, session->limReAssocbssId); + + if (!auth_node && (!cdf_mem_compare(reassoc_req->peerMacAddr, + session->bssId, + sizeof(tSirMacAddr)))) { + /* + * Either pre-auth context does not exist AND + * we are not reassociating with currently + * associated AP. + * Return Reassoc confirm with not authenticated + */ + reassoc_cnf.resultCode = eSIR_SME_STA_NOT_AUTHENTICATED; + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + + goto end; + } + /* assign the sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimReassocFailureTimer.sessionId = + reassoc_req->sessionId; + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Derive channel from BSS description and store it at CFG. */ + channel = session->limReassocChannelId; + sec_ch_offset = session->reAssocHtSecondaryChannelOffset; + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session); + + /* store the channel switch sessionEntry in the lim global var */ + session->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_REASSOC; + + /* Switch channel to the new Operating channel for Reassoc */ + lim_set_channel(mac_ctx, channel, + session->ch_center_freq_seg0, + session->ch_center_freq_seg1, + session->ch_width, + session->maxTxPower, + session->peSessionId); + + return; +end: + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + reassoc_cnf.sessionId = reassoc_req->sessionId; + /* Free up buffer allocated for reassocReq */ + cdf_mem_free(reassoc_req); + session->pLimReAssocReq = NULL; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &reassoc_cnf); +} + +/** + * lim_process_mlm_disassoc_req_ntf() - process disassoc request notification + * + * @mac_ctx: global MAC context + * @suspend_status: suspend status + * @msg: mlm message buffer + * + * This function is used to process MLM disassoc notification + * + * Return: None + */ +static void +lim_process_mlm_disassoc_req_ntf(tpAniSirGlobal mac_ctx, + CDF_STATUS suspend_status, uint32_t *msg) +{ + uint16_t aid; + tSirMacAddr curr_bssid; + tpDphHashNode stads; + tLimMlmDisassocReq *mlm_disassocreq; + tLimMlmDisassocCnf mlm_disassoccnf; + tpPESession session; + extern bool send_disassoc_frame; + tLimMlmStates mlm_state; + + if (CDF_STATUS_SUCCESS != suspend_status) + lim_log(mac_ctx, LOGE, FL("Suspend Status is not success %X"), + suspend_status); + + mlm_disassocreq = (tLimMlmDisassocReq *) msg; + + session = pe_find_session_by_session_id(mac_ctx, + mlm_disassocreq->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_disassocreq->sessionId); + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_log(mac_ctx, LOG1, + FL("Process DisAssoc Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR), + mlm_disassocreq->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_disassocreq->peerMacAddr)); + + sir_copy_mac_addr(curr_bssid, session->bssId); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + if (!cdf_mem_compare(mlm_disassocreq->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr))) { + lim_log(mac_ctx, LOGW, + FL("received MLM_DISASSOC_REQ with invalid BSS id")); + lim_print_mac_addr(mac_ctx, + mlm_disassocreq->peerMacAddr, LOGW); + + /* Prepare and Send LIM_MLM_DISASSOC_CNF */ + mlm_disassoccnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + break; + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + lim_log(mac_ctx, LOGE, + FL("CAC timer is running, drop disassoc from going out")); + mlm_disassoccnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + break; + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be disassociated with. + */ + stads = dph_lookup_hash_entry(mac_ctx, mlm_disassocreq->peerMacAddr, + &aid, &session->dph.dphHashTable); + if (stads) + mlm_state = stads->mlmStaContext.mlmState; + + if ((stads == NULL) || + (stads && + ((mlm_state != eLIM_MLM_LINK_ESTABLISHED_STATE) && + (mlm_state != eLIM_MLM_WT_ASSOC_CNF_STATE) && + (mlm_state != eLIM_MLM_ASSOCIATED_STATE)))) { + /* + * Received LIM_MLM_DISASSOC_REQ for STA that does not + * have context or in some transit state. + */ + lim_log(mac_ctx, LOGW, + FL("Invalid MLM_DISASSOC_REQ, Addr= " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_disassocreq->peerMacAddr)); + if (stads != NULL) + lim_log(mac_ctx, LOGE, FL("Sta MlmState : %d"), + stads->mlmStaContext.mlmState); + + /* Prepare and Send LIM_MLM_DISASSOC_CNF */ + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + stads->mlmStaContext.disassocReason = (tSirMacReasonCodes) + mlm_disassocreq->reasonCode; + stads->mlmStaContext.cleanupTrigger = mlm_disassocreq->disassocTrigger; + + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + /* Send Disassociate frame to peer entity */ + if (send_disassoc_frame && (mlm_disassocreq->reasonCode != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + mlm_disassocreq; + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + /* + * If the reason for disassociation is inactivity of STA, then + * dont wait for acknowledgement + */ + if ((mlm_disassocreq->reasonCode == + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON) && + LIM_IS_AP_ROLE(session)) { + lim_send_disassoc_mgmt_frame(mac_ctx, + mlm_disassocreq->reasonCode, + mlm_disassocreq->peerMacAddr, session, false); + + /* Send Disassoc CNF and receive path cleanup */ + lim_send_disassoc_cnf(mac_ctx); + } else { + lim_send_disassoc_mgmt_frame(mac_ctx, + mlm_disassocreq->reasonCode, + mlm_disassocreq->peerMacAddr, session, true); + /* + * Abort Tx so that data frames won't be sent to the AP + * after sending Disassoc. + */ + if (LIM_IS_STA_ROLE(session)) + wma_tx_abort(session->smeSessionId); + } + } else { + /* Disassoc frame is not sent OTA */ + send_disassoc_frame = 1; + /* Receive path cleanup with dummy packet */ + if (eSIR_SUCCESS != + lim_cleanup_rx_path(mac_ctx, stads, session)) { + mlm_disassoccnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* Free up buffer allocated for mlmDisassocReq */ + cdf_mem_free(mlm_disassocreq); + } + + return; + +end: + cdf_mem_copy((uint8_t *) &mlm_disassoccnf.peerMacAddr, + (uint8_t *) mlm_disassocreq->peerMacAddr, + sizeof(tSirMacAddr)); + mlm_disassoccnf.aid = mlm_disassocreq->aid; + mlm_disassoccnf.disassocTrigger = mlm_disassocreq->disassocTrigger; + + /* Update PE session ID */ + mlm_disassoccnf.sessionId = mlm_disassocreq->sessionId; + + /* Free up buffer allocated for mlmDisassocReq */ + cdf_mem_free(mlm_disassocreq); + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlm_disassoccnf); +} + +/** + * lim_check_disassoc_deauth_ack_pending() - check if deauth is pending + * + * @mac_ctx - global MAC context + * @sta_mac - station MAC + * + * This function checks if diassociation or deauthentication is pending for + * given station MAC address. + * + * Return: true if pending and false otherwise. + */ +bool lim_check_disassoc_deauth_ack_pending(tpAniSirGlobal mac_ctx, + uint8_t *sta_mac) +{ + tLimMlmDisassocReq *disassoc_req; + tLimMlmDeauthReq *deauth_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if ((disassoc_req && (cdf_mem_compare((uint8_t *) sta_mac, + (uint8_t *) &disassoc_req->peerMacAddr, + sizeof(tSirMacAddr)))) || + (deauth_req && (cdf_mem_compare((uint8_t *) sta_mac, + (uint8_t *) &deauth_req->peerMacAddr, + sizeof(tSirMacAddr))))) { + PELOG1(lim_log(mac_ctx, LOG1, + FL("Disassoc/Deauth ack pending"));) + return true; + } else { + PELOG1(lim_log(mac_ctx, LOG1, + FL("Disassoc/Deauth Ack not pending"));) + return false; + } +} + +/* + * lim_clean_up_disassoc_deauth_req() - cleans up pending disassoc or deauth req + * + * @mac_ctx: mac_ctx + * @sta_mac: sta mac address + * @clean_rx_path: flag to indicate whether to cleanup rx path or not + * + * This function cleans up pending disassoc or deauth req + * + * Return: void + */ +void lim_clean_up_disassoc_deauth_req(tpAniSirGlobal mac_ctx, + uint8_t *sta_mac, bool clean_rx_path) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + tLimMlmDeauthReq *mlm_deauth_req; + mlm_disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (mlm_disassoc_req && + (cdf_mem_compare((uint8_t *) sta_mac, + (uint8_t *) &mlm_disassoc_req->peerMacAddr, + sizeof(tSirMacAddr)))) { + if (clean_rx_path) { + lim_process_disassoc_ack_timeout(mac_ctx); + } else { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDisassocAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + } + cdf_mem_free(mlm_disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + NULL; + } + } + + mlm_deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (mlm_deauth_req && + (cdf_mem_compare((uint8_t *) sta_mac, + (uint8_t *) &mlm_deauth_req->peerMacAddr, + sizeof(tSirMacAddr)))) { + if (clean_rx_path) { + lim_process_deauth_ack_timeout(mac_ctx); + } else { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDeauthAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DEAUTH_ACK_TIMER); + } + cdf_mem_free(mlm_deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = + NULL; + } + } +} + +/* + * lim_process_disassoc_ack_timeout() - wrapper function around + * lim_send_disassoc_cnf + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_disassoc_cnf + * + * Return: void + */ +void lim_process_disassoc_ack_timeout(tpAniSirGlobal mac_ctx) +{ + lim_log(mac_ctx, LOG1, FL("")); + lim_send_disassoc_cnf(mac_ctx); +} + +/** + * lim_process_mlm_disassoc_req() - This function is called to process + * MLM_DISASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DISASSOC_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_disassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + tpPESession session; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, + FL("Buffer is Pointing to NULL")); + return; + } + + mlm_disassoc_req = (tLimMlmDisassocReq *) msg_buf; + lim_log(mac_ctx, LOG1, + FL("Process disassoc req, sessionID %d from: "MAC_ADDRESS_STR), + mlm_disassoc_req->sessionId, + MAC_ADDR_ARRAY(mlm_disassoc_req->peerMacAddr)); + + session = pe_find_session_by_session_id(mac_ctx, + mlm_disassoc_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_disassoc_req->sessionId); + return; + } + + lim_process_mlm_disassoc_req_ntf(mac_ctx, CDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +/** + * lim_process_mlm_deauth_req_ntf() - This function is process mlm deauth req + * notification + * + * @mac_ctx: Pointer to Global MAC structure + * @suspend_status: suspend status + * @msg_buf: A pointer to the MLM message buffer + * + * This function is process mlm deauth req notification + * + * @Return: None + */ +static void +lim_process_mlm_deauth_req_ntf(tpAniSirGlobal mac_ctx, + CDF_STATUS suspend_status, uint32_t *msg_buf) +{ + uint16_t aid; + tSirMacAddr curr_bssId; + tpDphHashNode sta_ds; + struct tLimPreAuthNode *auth_node; + tLimMlmDeauthReq *mlm_deauth_req; + tLimMlmDeauthCnf mlm_deauth_cnf; + tpPESession session; + + if (CDF_STATUS_SUCCESS != suspend_status) + lim_log(mac_ctx, LOGE, FL("Suspend Status is not success %X"), + suspend_status); + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_deauth_req->sessionId); + cdf_mem_free(mlm_deauth_req); + return; + } + lim_log(mac_ctx, LOG1, FL("Process Deauth Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR), + mlm_deauth_req->sessionId, + GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_deauth_req->peerMacAddr)); + sir_copy_mac_addr(curr_bssId, session->bssId); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + switch (session->limMlmState) { + case eLIM_MLM_IDLE_STATE: + /* + * Attempting to Deauthenticate with a pre-authenticated + * peer. Deauthetiate with peer if there exists a + * pre-auth context below. + */ + break; + case eLIM_MLM_AUTHENTICATED_STATE: + case eLIM_MLM_WT_ASSOC_RSP_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: + if (!cdf_mem_compare(mlm_deauth_req->peerMacAddr, + curr_bssId, sizeof(tSirMacAddr))) { + lim_log(mac_ctx, LOGE, + FL("received MLM_DEAUTH_REQ with invalid BSS id " + "Peer MAC: "MAC_ADDRESS_STR + " CFG BSSID Addr : "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + mlm_deauth_req->peerMacAddr), + MAC_ADDR_ARRAY(curr_bssId)); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + if ((session->limMlmState == + eLIM_MLM_AUTHENTICATED_STATE) || + (session->limMlmState == + eLIM_MLM_WT_ASSOC_RSP_STATE)) { + /* Send deauth frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req->peerMacAddr, + session, false); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, + session->limMlmState)); + goto end; + } + break; + default: + lim_log(mac_ctx, LOGW, + FL("received MLM_DEAUTH_REQ with in state %d for peer " + MAC_ADDRESS_STR), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_deauth_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + + goto end; + } + break; + case eLIM_STA_IN_IBSS_ROLE: + lim_log(mac_ctx, LOGE, FL("received MLM_DEAUTH_REQ IBSS Mode")); + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + lim_log(mac_ctx, LOGE, + FL("CAC timer is running, drop disassoc from going out")); + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + break; + + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be deauthenticated with. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, mlm_deauth_req->peerMacAddr, + &aid, &session->dph.dphHashTable); + + if (sta_ds == NULL) { + /* Check if there exists pre-auth context for this STA */ + auth_node = lim_search_pre_auth_list(mac_ctx, + mlm_deauth_req->peerMacAddr); + if (auth_node == NULL) { + /* + * Received DEAUTH REQ for a STA that is neither + * Associated nor Pre-authenticated. Log error, + * Prepare and Send LIM_MLM_DEAUTH_CNF + */ + lim_log(mac_ctx, LOGW, + FL("received MLM_DEAUTH_REQ in mlme state %d for STA that " + "does not have context, Addr=" + MAC_ADDRESS_STR), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_deauth_req->peerMacAddr)); + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + } else { + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + /* Delete STA from pre-auth STA list */ + lim_delete_pre_auth_node(mac_ctx, + mlm_deauth_req->peerMacAddr); + /* Send Deauthentication frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req->peerMacAddr, + session, false); + } + goto end; + } else if ((sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (sta_ds->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE)) { + /* + * received MLM_DEAUTH_REQ for STA that either has no context or + * in some transit state + */ + lim_log(mac_ctx, LOGW, + FL("Invalid MLM_DEAUTH_REQ, Addr="MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_deauth_req->peerMacAddr)); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* sta_ds->mlmStaContext.rxPurgeReq = 1; */ + sta_ds->mlmStaContext.disassocReason = (tSirMacReasonCodes) + mlm_deauth_req->reasonCode; + sta_ds->mlmStaContext.cleanupTrigger = mlm_deauth_req->deauthTrigger; + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = mlm_deauth_req; + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and disassoc from + * inactivity timer. This will make sure that we will not + * process disassoc if deauth is in progress for the station + * and thus mlmStaContext.cleanupTrigger will not be overwritten. + */ + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Send Deauthentication frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, mlm_deauth_req->reasonCode, + mlm_deauth_req->peerMacAddr, session, true); + return; +end: + cdf_mem_copy((uint8_t *) &mlm_deauth_cnf.peerMacAddr, + (uint8_t *) mlm_deauth_req->peerMacAddr, + sizeof(tSirMacAddr)); + mlm_deauth_cnf.deauthTrigger = mlm_deauth_req->deauthTrigger; + mlm_deauth_cnf.aid = mlm_deauth_req->aid; + mlm_deauth_cnf.sessionId = mlm_deauth_req->sessionId; + + /* Free up buffer allocated for mlmDeauthReq */ + cdf_mem_free(mlm_deauth_req); + lim_post_sme_message(mac_ctx, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlm_deauth_cnf); +} + +/* + * lim_process_deauth_ack_timeout() - wrapper function around + * lim_send_deauth_cnf + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_deauth_cnf + * + * Return: void + */ +void lim_process_deauth_ack_timeout(tpAniSirGlobal mac_ctx) +{ + lim_log(mac_ctx, LOG1, FL("")); + lim_send_deauth_cnf(mac_ctx); +} + +/* + * lim_process_mlm_deauth_req() - This function is called to process + * MLM_DEAUTH_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DEAUTH_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_deauth_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDeauthReq *mlm_deauth_req; + tpPESession session; + + if (msg_buf == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + lim_log(mac_ctx, LOG1, + FL("Process Deauth Req on sessionID %d from: " + MAC_ADDRESS_STR), + mlm_deauth_req->sessionId, + MAC_ADDR_ARRAY(mlm_deauth_req->peerMacAddr)); + + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_deauth_req->sessionId); + return; + } + lim_process_mlm_deauth_req_ntf(mac_ctx, CDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +/** + * lim_process_mlm_set_keys_req() - This function is called to process + * MLM_SETKEYS_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_SETKEYS_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t aid; + uint16_t sta_idx = 0; + uint32_t default_key_id = 0; + tSirMacAddr curr_bssid; + tpDphHashNode sta_ds; + tLimMlmSetKeysReq *mlm_set_keys_req; + tLimMlmSetKeysCnf mlm_set_keys_cnf; + tpPESession session; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_set_keys_req = (tLimMlmSetKeysReq *) msg_buf; + /* Hold onto the SetKeys request parameters */ + mac_ctx->lim.gpLimMlmSetKeysReq = (void *)mlm_set_keys_req; + session = pe_find_session_by_session_id(mac_ctx, + mlm_set_keys_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId")); + return; + } + + lim_log(mac_ctx, LOGW, + FL("Received MLM_SETKEYS_REQ with parameters:" + "AID [%d], ED Type [%d], # Keys [%d] & Peer MAC Addr - "), + mlm_set_keys_req->aid, mlm_set_keys_req->edType, + mlm_set_keys_req->numKeys); + lim_print_mac_addr(mac_ctx, mlm_set_keys_req->peerMacAddr, LOGW); + sir_copy_mac_addr(curr_bssid, session->bssId); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + /* + * In case of TDLS, peerMac address need not be BssId. Skip this + * check if TDLS is enabled. + */ +#ifndef FEATURE_WLAN_TDLS + if ((!lim_is_addr_bc(mlm_set_keys_req->peerMacAddr)) && + (!cdf_mem_compare(mlm_set_keys_req->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr)))) { + lim_log(mac_ctx, LOGW, + FL("Received MLM_SETKEYS_REQ with invalid BSSID" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_set_keys_req->peerMacAddr)); + /* + * Prepare and Send LIM_MLM_SETKEYS_CNF with error code + */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } +#endif + break; + case eLIM_STA_IN_IBSS_ROLE: + /* + * update the IBSS PE session encrption type based on the + * key type + */ + session->encryptType = mlm_set_keys_req->edType; + break; + default: + break; + } + + /* + * Use the "unicast" parameter to determine if the "Group Keys" + * are being set. + * mlm_set_keys_req->key.unicast = 0 -> Multicast/broadcast + * mlm_set_keys_req->key.unicast - 1 -> Unicast keys are being set + */ + if (lim_is_addr_bc(mlm_set_keys_req->peerMacAddr)) { + lim_log(mac_ctx, LOG1, FL("Trying to set Group Keys...%d "), + mlm_set_keys_req->sessionId); + /* + * When trying to set Group Keys for any security mode other + * than WEP, use the STA Index corresponding to the AP... + */ + switch (mlm_set_keys_req->edType) { + case eSIR_ED_CCMP: +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: +#endif + sta_idx = session->staId; + break; + default: + break; + } + } else { + lim_log(mac_ctx, LOG1, FL("Trying to set Unicast Keys...")); + /* + * Check if there exists a context for the + * peer entity for which keys need to be set. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, + mlm_set_keys_req->peerMacAddr, &aid, + &session->dph.dphHashTable); + if ((sta_ds == NULL) || + ((sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + !LIM_IS_AP_ROLE(session))) { + /* + * Received LIM_MLM_SETKEYS_REQ for STA that does not + * have context or in some transit state. + */ + lim_log(mac_ctx, LOG1, + FL("Invalid MLM_SETKEYS_REQ, Addr = " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_set_keys_req->peerMacAddr)); + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } else { + sta_idx = sta_ds->staIndex; + } + } + + if ((mlm_set_keys_req->numKeys == 0) + && (mlm_set_keys_req->edType != eSIR_ED_NONE)) { + /* + * Broadcast/Multicast Keys (for WEP!!) are NOT sent + * via this interface!! This indicates to HAL that the WEP Keys + * need to be extracted from the CFG and applied to hardware + */ + default_key_id = 0xff; + } else if (mlm_set_keys_req->key[0].keyId && + ((mlm_set_keys_req->edType == eSIR_ED_WEP40) || + (mlm_set_keys_req->edType == eSIR_ED_WEP104))) { + /* + * If the Key Id is non zero and encryption mode is WEP, + * the key index is coming from the upper layers so that key + * only need to be used as the default tx key, This is being + * used only in case of WEP mode in HAL + */ + default_key_id = mlm_set_keys_req->key[0].keyId; + } else { + default_key_id = 0; + } + lim_log(mac_ctx, LOG1, + FL("Trying to set keys for STA Index [%d], using default_key_id [%d]"), + sta_idx, default_key_id); + + if (lim_is_addr_bc(mlm_set_keys_req->peerMacAddr)) { + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_SET_BSS_KEY_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + lim_log(mac_ctx, LOG1, FL("Trying to set Group Keys...%d "), + session->peSessionId); + /* Package WMA_SET_BSSKEY_REQ message parameters */ + lim_send_set_bss_key_req(mac_ctx, mlm_set_keys_req, session); + return; + } else { + /* + * Package WMA_SET_STAKEY_REQ / WMA_SET_STA_BCASTKEY_REQ message + * parameters + */ + lim_send_set_sta_key_req(mac_ctx, mlm_set_keys_req, sta_idx, + (uint8_t) default_key_id, session, + true); + return; + } +end: + mlm_set_keys_cnf.sessionId = mlm_set_keys_req->sessionId; + lim_post_sme_set_keys_cnf(mac_ctx, mlm_set_keys_req, &mlm_set_keys_cnf); +} + +/** + * lim_process_periodic_probe_req_timer() - This function is called to process + * periodic probe request to send during scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process periodic probe request to send during scan + * + * @Return None + */ +static void lim_process_periodic_probe_req_timer(tpAniSirGlobal mac_ctx) +{ + uint8_t channel_num; + uint8_t i = 0; + tLimMlmScanReq *mlm_scan_req; + tSirRetStatus status = eSIR_SUCCESS; + TX_TIMER *probe_req_timer = + &mac_ctx->lim.limTimers.gLimPeriodicProbeReqTimer; + + if (cdf_mc_timer_get_current_state(&probe_req_timer->cdf_timer) + != CDF_TIMER_STATE_STOPPED) { + lim_log(mac_ctx, LOG1, FL("Invalid state of timer")); + return; + } + + if (!((mac_ctx->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) + && (probe_req_timer->sessionId != 0xff) + && (mac_ctx->lim.probeCounter < mac_ctx->lim.maxProbe))) { + lim_log(mac_ctx, LOG1, + FL("received unexpected Periodic scan timeout in state %X"), + mac_ctx->lim.gLimMlmState); + return; + } + + mlm_scan_req = mac_ctx->lim.gpLimMlmScanReq; + lim_log(mac_ctx, LOG1, FL("Scanning : Periodic scanning")); + mac_ctx->lim.probeCounter++; + /* Periodic channel timer timed out to send probe request. */ + channel_num = lim_get_current_scan_channel(mac_ctx); + do { + /* + * Prepare and send Probe Request frame for all the SSIDs + * present in the saved MLM + */ + status = lim_send_probe_req_mgmt_frame(mac_ctx, + &mlm_scan_req->ssId[i], mlm_scan_req->bssId, + channel_num, mac_ctx->lim.gSelfMacAddr, + mlm_scan_req->dot11mode, + mlm_scan_req->uIEFieldLen, + (uint8_t *) (mlm_scan_req) + + mlm_scan_req->uIEFieldOffset); + if (status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("send ProbeReq failed for SSID %s on channel: %d"), + mlm_scan_req->ssId[i].ssId, channel_num); + return; + } + i++; + } while (i < mlm_scan_req->numSsid); + /* Activate timer again */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + probe_req_timer->sessionId, + eLIM_PERIODIC_PROBE_REQ_TIMER)); + if (tx_timer_activate(probe_req_timer) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not start periodic probe req timer")); + return; + } +} + +/** + * lim_process_join_failure_timeout() - This function is called to process + * JoinFailureTimeout + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process JoinFailureTimeout + * + * @Return None + */ +static void lim_process_join_failure_timeout(tpAniSirGlobal mac_ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + uint32_t len; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + tpPESession session; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + if (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + len = sizeof(tSirMacAddr); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Change Periodic probe req timer for future activation */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Issue MLM join confirm with timeout reason code */ + lim_log(mac_ctx, LOGE, + FL("In state eLIM_MLM_WT_JOIN_BEACON_STATE.")); + lim_log(mac_ctx, LOGE, + FL("Join Failure Timeout occurred for session %d with BSS " + MAC_ADDRESS_STR), + session->peSessionId, MAC_ADDR_ARRAY(session->bssId)); + + mlm_join_cnf.resultCode = eSIR_SME_JOIN_TIMEOUT_RESULT_CODE; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session->bssId, session->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + ("Failed to set the LinkState")); + /* Update PE session Id */ + mlm_join_cnf.sessionId = session->peSessionId; + /* Freeup buffer allocated to join request */ + if (session->pLimMlmJoinReq) { + cdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + return; + } else { + lim_log(mac_ctx, LOGW, + FL("received unexpected JOIN failure timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + } +} + +/** + * lim_process_periodic_join_probe_req_timer() - This function is called to + * process periodic probe request send during joining process. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process periodic probe request send during + * joining process. + * + * @Return None + */ +static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + tSirMacSSid ssid; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given SessionId : %d"), + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer. + sessionId); + return; + } + + if ((true == + tx_timer_running(&mac_ctx->lim.limTimers.gLimJoinFailureTimer)) + && (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE)) { + cdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + ssid.length = session->ssId.length; + lim_send_probe_req_mgmt_frame(mac_ctx, &ssid, + session->pLimMlmJoinReq->bssDescription.bssId, + session->currentOperChannel /*chanNum */, + session->selfMacAddr, session->dot11mode, + session->pLimJoinReq->addIEScan.length, + session->pLimJoinReq->addIEScan.addIEdata); + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate( + &mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not activate Periodic Join req failure timer")); + return; + } + } +} + +/** + * lim_process_auth_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void lim_process_auth_failure_timeout(tpAniSirGlobal mac_ctx) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession session; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimAuthFailureTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + lim_log(mac_ctx, LOGE, + FL("received AUTH failure timeout in sessionid %d " + "limMlmstate %X limSmeState %X"), + session->peSessionId, session->limMlmState, + session->limSmeState); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + switch (session->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + /* + * Requesting STA did not receive next auth frame before Auth + * Failure timeout. Issue MLM auth confirm with timeout reason + * code. Restore default failure timeout + */ + if (CDF_P2P_CLIENT_MODE == session->pePersona + && session->defaultAuthFailureTimeout) + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_REASON, session); + break; + default: + /* + * Auth failure timer should not have timed out + * in states other than wt_auth_frame2/4 + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected AUTH failure timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + break; + } +} + +/** + * lim_process_auth_rsp_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void +lim_process_auth_rsp_timeout(tpAniSirGlobal mac_ctx, uint32_t auth_idx) +{ + struct tLimPreAuthNode *auth_node; + tpPESession session; + uint8_t session_id; + + auth_node = lim_get_pre_auth_node_from_index(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable, auth_idx); + if (NULL == auth_node) { + lim_log(mac_ctx, LOGW, FL("Invalid auth node")); + return; + } + + session = pe_find_session_by_bssid(mac_ctx, auth_node->peerMacAddr, + &session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGW, + FL("session does not exist for given BSSID ")); + return; + } + + if (LIM_IS_AP_ROLE(session) || LIM_IS_IBSS_ROLE(session)) { + if (auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) { + lim_log(mac_ctx, LOGE, + FL("received AUTH rsp timeout in unexpected " + "state for MAC address: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(auth_node->peerMacAddr)); + } else { + auth_node->mlmState = eLIM_MLM_AUTH_RSP_TIMEOUT_STATE; + auth_node->fTimerStarted = 0; + lim_log(mac_ctx, LOG1, + FL("AUTH rsp timedout for MAC address " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(auth_node->peerMacAddr)); + /* Change timer to reactivate it in future */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + lim_delete_pre_auth_node(mac_ctx, + auth_node->peerMacAddr); + } + } +} + +/** + * lim_process_assoc_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void +lim_process_assoc_failure_timeout(tpAniSirGlobal mac_ctx, uint32_t msg_type) +{ + + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + /* + * to fetch the lim/mlm state based on the session_id, use the + * below sessionEntry + */ + uint8_t session_id; + + if (msg_type == LIM_ASSOC) + session_id = + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId; + else + session_id = + mac_ctx->lim.limTimers.gLimReassocFailureTimer.sessionId; + + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + lim_log(mac_ctx, LOG1, + FL("Re/Association Response not received before timeout ")); + + if ((LIM_IS_AP_ROLE(session) || LIM_IS_BT_AMP_AP_ROLE(session)) || + ((session->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + /* + * Re/Assoc failure timer should not have timedout on AP + * or in a state other than wt_re/assoc_response. + */ + lim_log(mac_ctx, LOGW, + FL("received unexpected REASSOC failure timeout in state %X for role %d"), + session->limMlmState, + GET_LIM_SYSTEM_ROLE(session)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + return; + } + + if ((msg_type == LIM_ASSOC) || ((msg_type == LIM_REASSOC) + && (session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + lim_log(mac_ctx, LOGE, + FL("(Re)Assoc Failure Timeout occurred.")); + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + /* + * Free up buffer allocated for JoinReq held by + * MLM state machine + */ + if (session->pLimMlmJoinReq) { + cdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + /* To remove the preauth node in case of fail to associate */ + if (lim_search_pre_auth_list(mac_ctx, session->bssId)) { + lim_log(mac_ctx, LOG1, + FL(" delete pre auth node for "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(session->bssId)); + lim_delete_pre_auth_node(mac_ctx, + session->bssId); + } + + mlm_assoc_cnf.resultCode = eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session->peSessionId; + if (msg_type == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } else { + /* + * Will come here only in case of 11r, Ese FT + * when reassoc rsp is not received and we + * receive a reassoc - timesout + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } + } else { + /* + * Restore pre-reassoc req state. + * Set BSSID to currently associated AP address. + */ + session->limMlmState = session->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session); + } +} + +/** + * lim_complete_mlm_scan() - This function is called to send MLM_SCAN_CNF + * message to SME state machine. + * + * @mac_ctx: Pointer to Global MAC structure + * @ret_code: Result code to be sent + * + * This function is called to send MLM_SCAN_CNF message to SME state machine. + * + * @Return: None + */ + +void lim_complete_mlm_scan(tpAniSirGlobal mac_ctx, tSirResultCodes ret_code) +{ + tLimMlmScanCnf mlm_scan_cnf; + + /* Restore previous MLM state */ + mac_ctx->lim.gLimMlmState = mac_ctx->lim.gLimPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, NO_SESSION, + mac_ctx->lim.gLimMlmState)); + lim_restore_pre_scan_state(mac_ctx); + /* Free up mac_ctx->lim.gLimMlmScanReq */ + if (NULL != mac_ctx->lim.gpLimMlmScanReq) { + cdf_mem_free(mac_ctx->lim.gpLimMlmScanReq); + mac_ctx->lim.gpLimMlmScanReq = NULL; + } + + mlm_scan_cnf.resultCode = ret_code; + lim_post_sme_message(mac_ctx, LIM_MLM_SCAN_CNF, + (uint32_t *) &mlm_scan_cnf); +} + +/** + * lim_set_channel() - set channel api for lim + * + * @mac_ctx: Pointer to Global MAC structure + * @channel: power save state + * @ch_center_freq_seg0: center freq seq 0 + * @ch_center_freq_seg1: center freq seq 1 + * @ch_width: channel width + * @max_tx_power: max tx power + * @pe_session_id: pe session id + * + * set channel api for lim + * + * @Return: None + */ +void lim_set_channel(tpAniSirGlobal mac_ctx, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, tPowerdBm max_tx_power, + uint8_t pe_session_id) +{ +#if !defined WLAN_FEATURE_VOWIFI + uint32_t localPwrConstraint; +#endif + tpPESession pe_session; + pe_session = pe_find_session_by_session_id(mac_ctx, pe_session_id); + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGP, FL("Invalid PE session = %d"), + pe_session_id); + return; + } +#if defined WLAN_FEATURE_VOWIFI + lim_send_switch_chnl_params(mac_ctx, channel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + max_tx_power, pe_session_id, false); +#else + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't read CFG_LOCAL_POWER_CONSTRAINT")); + return; + } + /* Send WMA_CHNL_SWITCH_IND to HAL */ + lim_send_switch_chnl_params(mac_ctx, channel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + (tPowerdBm) localPwrConstraint, + pe_session_id, false); +#endif +} diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c new file mode 100644 index 0000000000..4450acd699 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -0,0 +1,4200 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_timer_utils.h" +#include "lim_send_messages.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft.h" +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_session_utils.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif +#include "wma_types.h" +#include "cds_utils.h" +#include "lim_types.h" + +#define MAX_SUPPORTED_PEERS_WEP 16 + +static void lim_handle_sme_join_result(tpAniSirGlobal, tSirResultCodes, uint16_t, + tpPESession); +static void lim_handle_sme_reaasoc_result(tpAniSirGlobal, tSirResultCodes, uint16_t, + tpPESession); + +#ifdef FEATURE_OEM_DATA_SUPPORT +void lim_process_mlm_oem_data_req_cnf(tpAniSirGlobal, uint32_t *); +#endif +void lim_process_mlm_join_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_auth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_start_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_reassoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_reassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_deauth_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_deauth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal, uint32_t *); +static void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tpPESession psessionEntry); +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, uint8_t *, uint16_t *); +static void +lim_process_btamp_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +/** + * lim_process_mlm_rsp_messages() + * + ***FUNCTION: + * This function is called to processes various MLM response (CNF/IND + * messages from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void +lim_process_mlm_rsp_messages(tpAniSirGlobal pMac, uint32_t msgType, + uint32_t *pMsgBuf) +{ + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + MTRACE(mac_trace(pMac, TRACE_CODE_TX_LIM_MSG, 0, msgType)); + switch (msgType) { + +#ifdef FEATURE_OEM_DATA_SUPPORT + case LIM_MLM_OEM_DATA_CNF: + lim_process_mlm_oem_data_req_cnf(pMac, pMsgBuf); + pMsgBuf = NULL; + break; +#endif + + case LIM_MLM_AUTH_CNF: + lim_process_mlm_auth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_CNF: + lim_process_mlm_assoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_START_CNF: + lim_process_mlm_start_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_JOIN_CNF: + lim_process_mlm_join_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_IND: + lim_process_mlm_assoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_REASSOC_CNF: + lim_process_mlm_reassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_CNF: + lim_process_mlm_disassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_IND: + lim_process_mlm_disassoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_PURGE_STA_IND: + lim_process_mlm_purge_sta_ind(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_CNF: + lim_process_mlm_deauth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_IND: + lim_process_mlm_deauth_ind(pMac, pMsgBuf); + break; + case LIM_MLM_SETKEYS_CNF: + lim_process_mlm_set_keys_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_TSPEC_CNF: + break; + default: + break; + } /* switch (msgType) */ + return; +} /*** end lim_process_mlm_rsp_messages() ***/ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * lim_process_mlm_oem_data_req_cnf() + * + ***FUNCTION: + * This function is called to processes LIM_MLM_OEM_DATA_REQ_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ + +void lim_process_mlm_oem_data_req_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmOemDataRsp *measRsp; + + tSirResultCodes resultCode = eSIR_SME_SUCCESS; + + measRsp = (tLimMlmOemDataRsp *) (pMsgBuf); + + /* Now send the meas confirm message to the sme */ + lim_send_sme_oem_data_rsp(pMac, (uint32_t *) measRsp, resultCode); + + /* Dont free the memory here. It will be freed up by the callee */ + + return; +} +#endif + +/** + * lim_process_mlm_start_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_START_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_start_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpPESession psessionEntry = NULL; + tLimMlmStartCnf *pLimMlmStartCnf; + uint8_t smesessionId; + uint16_t smetransactionId; + uint8_t channelId; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pLimMlmStartCnf = (tLimMlmStartCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pLimMlmStartCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL( + "Session does Not exist with given sessionId "));) + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + if (psessionEntry->limSmeState != eLIM_SME_WT_START_BSS_STATE) { + /* + * Should not have received Start confirm from MLM + * in other states. Log error. + */ + PELOGE(lim_log(pMac, LOGE, FL + ("received unexpected MLM_START_CNF in state %X"), + psessionEntry->limSmeState);) + return; + } + if (((tLimMlmStartCnf *) pMsgBuf)->resultCode == eSIR_SME_SUCCESS) { + + /* + * Update global SME state so that Beacon Generation + * module starts writing Beacon frames into TFP's + * Beacon file register. + */ + psessionEntry->limSmeState = eLIM_SME_NORMAL_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + if (psessionEntry->bssType == eSIR_BTAMP_STA_MODE) { + lim_log(pMac, LOG1, + FL("*** Started BSS in BT_AMP STA SIDE***")); + } else if (psessionEntry->bssType == eSIR_BTAMP_AP_MODE) { + lim_log(pMac, LOG1, + FL("*** Started BSS in BT_AMP AP SIDE***")); + } else if (psessionEntry->bssType == eSIR_INFRA_AP_MODE) { + lim_log(pMac, LOG1, + FL("*** Started BSS in INFRA AP SIDE***")); + } else + PELOG1(lim_log(pMac, LOG1, FL("*** Started BSS ***"));) + } else { + /* Start BSS is a failure */ + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + PELOGE(lim_log(pMac, LOGE, FL("Start BSS Failed "));) + } + /* Send response to Host */ + lim_send_sme_start_bss_rsp(pMac, eWNI_SME_START_BSS_RSP, + ((tLimMlmStartCnf *)pMsgBuf)->resultCode, + psessionEntry, smesessionId, smetransactionId); + if ((psessionEntry != NULL) && + (((tLimMlmStartCnf *) pMsgBuf)->resultCode == + eSIR_SME_SUCCESS)) { + channelId = psessionEntry->pLimStartBssReq->channelId; + + /* We should start beacon transmission only if the channel + * on which we are operating is non-DFS until the channel + * availability check is done. The PE will receive an explicit + * request from upper layers to start the beacon transmission + */ + + if (LIM_IS_IBSS_ROLE(psessionEntry) || + (LIM_IS_AP_ROLE(psessionEntry) && + (cds_get_channel_state(channelId) != + CHANNEL_STATE_DFS))) { + /* Configure beacon and send beacons to HAL */ + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, psessionEntry); + } + } +} + +/*** end lim_process_mlm_start_cnf() ***/ + +/** + * lim_process_mlm_join_cnf() - Processes join confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This Function handles the join confirmation message + * LIM_MLM_JOIN_CNF. + * + * Return: None + */ +void lim_process_mlm_join_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmJoinCnf *join_cnf; + tpPESession session_entry; + + join_cnf = (tLimMlmJoinCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + join_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d does not exist"), + join_cnf->sessionId); + return; + } + + if (session_entry->limSmeState != eLIM_SME_WT_JOIN_STATE) { + lim_log(mac_ctx, LOGE, + FL("received unexpected MLM_JOIN_CNF in state %X"), + session_entry->limSmeState); + return; + } + + result_code = ((tLimMlmJoinCnf *) msg)->resultCode; + /* Process Join confirm from MLM */ + if (result_code == eSIR_SME_SUCCESS) { + lim_log(mac_ctx, LOG1, FL("***SessionId:%d Joined ESS ***"), + join_cnf->sessionId); + /* Setup hardware upfront */ + if (lim_sta_send_add_bss_pre_assoc(mac_ctx, false, + session_entry) == eSIR_SUCCESS) + return; + else + result_code = eSIR_SME_REFUSED; + } + + /* Join failure */ + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, result_code, + ((tLimMlmJoinCnf *) msg)->protStatusCode, session_entry); + return; +} + +/** + * lim_send_mlm_assoc_req() - Association request will be processed + * mac_ctx: Pointer to Global MAC structure + * session_entry: Pointer to session etnry + * + * This function is sends ASSOC request MLM message to MLM State machine. + * ASSOC request packet would be by picking parameters from psessionEntry + * automatically based on the current state of MLM state machine. + * ASSUMPTIONS: + * this function is called in middle of connection state machine and is + * expected to be called after auth cnf has been received or after ASSOC rsp + * with TRY_AGAIN_LATER was received and required time has elapsed after that. + * + * Return: None + */ + +void lim_send_mlm_assoc_req(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + tLimMlmAssocReq *assoc_req; + uint32_t val; + uint16_t caps; + uint32_t tele_bcn = 0; + tpSirMacCapabilityInfo cap_info; + + /* Successful MAC based authentication. Trigger Association with BSS */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Authenticated with BSS"), + session_entry->peSessionId); + + if (NULL == session_entry->pLimJoinReq) { + lim_log(mac_ctx, LOGE, FL("Join Request is NULL.")); + /* No need to Assert. JOIN timeout will handle this error */ + return; + } + + assoc_req = cdf_mem_malloc(sizeof(tLimMlmAssocReq)); + if (NULL == assoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmAssocReq")); + return; + } + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(assoc_req->peerMacAddr, session_entry->bssId); + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &assoc_req->assocFailureTimeout) + != eSIR_SUCCESS) { + /* Could not get AssocFailureTimeout value from CFG.*/ + lim_log(mac_ctx, LOGP, + FL("could not retrieve AssocFailureTimeout value")); + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) + != eSIR_SUCCESS) + /* Could not get Capabilities value from CFG.*/ + lim_log(mac_ctx, LOGP, + FL("could not retrieve Capabilities value")); + + /* Clear spectrum management bit if AP doesn't support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) + /* + * AP doesn't support spectrum management + * clear spectrum management bit + */ + caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + + /* Clear rrm bit if AP doesn't support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo + & LIM_RRM_BIT_MASK)) + caps &= (~LIM_RRM_BIT_MASK); + + /* Clear short preamble bit if AP does not support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + (LIM_SHORT_PREAMBLE_BIT_MASK))) { + caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + lim_log(mac_ctx, LOG1, + FL("Clearing short preamble:no AP support")); + } + + /* Clear immediate block ack bit if AP does not support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + (LIM_IMMEDIATE_BLOCK_ACK_MASK))) { + caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + lim_log(mac_ctx, LOG1, + FL("Clearing Immed Blk Ack:no AP support")); + } + + assoc_req->capabilityInfo = caps; + cap_info = ((tpSirMacCapabilityInfo) &assoc_req->capabilityInfo); + lim_log(mac_ctx, LOG3, FL("Capabilities to be used in AssocReq=0x%X," + "privacy bit=%x shortSlotTime %x"), caps, + cap_info->privacy, + cap_info->shortSlotTime); + + /* + * If telescopic beaconing is enabled, set listen interval to + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, &tele_bcn) + != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + if (tele_bcn) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val) != eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_REQ_EVENT, + session_entry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + assoc_req->listenInterval = (uint16_t) val; + /* Update PE session ID */ + assoc_req->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, session_entry->limSmeState)); + lim_post_mlm_message(mac_ctx, LIM_MLM_ASSOC_REQ, + (uint32_t *) assoc_req); +} + +#ifdef WLAN_FEATURE_11W +/** + * lim_pmf_comeback_timer_callback() -PMF callback handler + * @context: Timer context + * + * This function is called to processes the PMF comeback + * callback + * + * Return: None + */ +void lim_pmf_comeback_timer_callback(void *context) +{ + tComebackTimerInfo *info = (tComebackTimerInfo *) context; + tpAniSirGlobal mac_ctx = info->pMac; + tpPESession psessionEntry = &mac_ctx->lim.gpSession[info->sessionID]; + + lim_log(mac_ctx, LOGE, + FL("comeback later timer expired. sending MLM ASSOC req")); + /* set MLM state such that ASSOC REQ packet will be sent out */ + psessionEntry->limPrevMlmState = info->limPrevMlmState; + psessionEntry->limMlmState = info->limMlmState; + lim_send_mlm_assoc_req(mac_ctx, psessionEntry); +} +#endif /* WLAN_FEATURE_11W */ + +/** + * lim_process_mlm_auth_cnf()-Process Auth confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_AUTH_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_auth_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tAniAuthType auth_type, auth_mode; + tLimMlmAuthReq *auth_req; + tLimMlmAuthCnf *auth_cnf; + tpPESession session_entry; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + auth_cnf = (tLimMlmAuthCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + auth_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d session doesn't exist"), + auth_cnf->sessionId); + return; + } + + if ((session_entry->limSmeState != eLIM_SME_WT_AUTH_STATE && + session_entry->limSmeState != eLIM_SME_WT_PRE_AUTH_STATE) || + LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + /** + * Should not have received AUTH confirm + * from MLM in other states or on AP. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d received MLM_AUTH_CNF in state %X"), + session_entry->peSessionId, session_entry->limSmeState); + return; + } + + if (((tLimMlmAuthCnf *) msg)->resultCode == eSIR_SME_SUCCESS) { + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) { + lim_send_mlm_assoc_req(mac_ctx, session_entry); + } else { + /* + * Successful Pre-authentication. Send + * Pre-auth response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + /* Return for success case */ + return; + } + /* + * Failure case handle: + * Process AUTH confirm from MLM + */ + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &auth_type) != eSIR_SUCCESS) { + /* + * Could not get AuthType value from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail to retrieve AuthType value")); + } + } else { + auth_type = mac_ctx->lim.gLimPreAuthType; + } + + if ((auth_type == eSIR_AUTO_SWITCH) && + (((tLimMlmAuthCnf *) msg)->authType == eSIR_OPEN_SYSTEM) + && (eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS == + ((tLimMlmAuthCnf *) msg)->protStatusCode)) { + /* + * When Open authentication fails with reason + * code "13" and authType set to 'auto switch', + * Try with Shared Authentication + */ + auth_mode = eSIR_SHARED_KEY; + /* Trigger MAC based Authentication */ + auth_req = cdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (NULL == auth_req) { + /* Log error */ + lim_log(mac_ctx, LOGP, + FL("mlmAuthReq :Memory alloc failed ")); + return; + } + cdf_mem_set((uint8_t *) auth_req, + sizeof(tLimMlmAuthReq), 0); + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + sir_copy_mac_addr(auth_req->peerMacAddr, + session_entry->bssId); + } else { + cdf_mem_copy((uint8_t *)&auth_req->peerMacAddr, + (uint8_t *)&mac_ctx->lim.gLimPreAuthPeerAddr, + sizeof(tSirMacAddr)); + } + auth_req->authType = auth_mode; + /* Update PE session Id */ + auth_req->sessionId = auth_cnf->sessionId; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &auth_req->authFailureTimeout) + != eSIR_SUCCESS) { + /* + * Could not get AuthFailureTimeout value from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail:retrieve AuthFailureTimeout ")); + } + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) auth_req); + return; + } else { + /* MAC based authentication failure */ + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + lim_log(mac_ctx, LOGE, + FL("Auth Failure occurred.")); + session_entry->limSmeState = + eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + session_entry->limMlmState = + eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* + * Need to send Join response with + * auth failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAuthCnf *)msg)->resultCode, + ((tLimMlmAuthCnf *)msg)->protStatusCode, + session_entry); + } else { + /* + * Pre-authentication failure. + * Send Pre-auth failure response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + } +} + +/** + * lim_process_mlm_assoc_cnf() - Process association confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_ASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_assoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tpPESession session_entry; + tLimMlmAssocCnf *assoc_cnf; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + assoc_cnf = (tLimMlmAssocCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + assoc_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Session does not exist"), + assoc_cnf->sessionId); + return; + } + if (session_entry->limSmeState != eLIM_SME_WT_ASSOC_STATE || + LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + /* + * Should not have received Assocication confirm + * from MLM in other states OR on AP. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Received MLM_ASSOC_CNF in state %X"), + session_entry->peSessionId, session_entry->limSmeState); + return; + } + if (((tLimMlmAssocCnf *) msg)->resultCode != eSIR_SME_SUCCESS) { + /* Association failure */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Association failure"), + session_entry->peSessionId); + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, mac_ctx->lim.gLimSmeState)); + /* + * Need to send Join response with + * Association failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } else { + /* Successful Association */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Associated with BSS"), + session_entry->peSessionId); + session_entry->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /** + * Need to send Join response with + * Association success to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } +} + +/** + * lim_process_mlm_reassoc_cnf() - process mlm reassoc cnf msg + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_CNF message from MLM State + * machine. + * + * @Return: void + */ +void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpPESession session; + tLimMlmReassocCnf *lim_mlm_reassoc_cnf; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + lim_mlm_reassoc_cnf = (tLimMlmReassocCnf *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + lim_mlm_reassoc_cnf->sessionId); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("session Does not exist for given session Id")); + return; + } + if ((session->limSmeState != eLIM_SME_WT_REASSOC_STATE) || + LIM_IS_AP_ROLE(session) || LIM_IS_BT_AMP_AP_ROLE(session)) { + /* + * Should not have received Reassocication confirm + * from MLM in other states OR on AP. + */ + lim_log(mac_ctx, LOGE, + FL("Rcv unexpected MLM_REASSOC_CNF in role %d, sme state 0x%X"), + GET_LIM_SYSTEM_ROLE(session), session->limSmeState); + return; + } + if (session->pLimReAssocReq) { + cdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + /* + * Upon Reassoc success or failure, freeup the cached preauth request, + * to ensure that channel switch is now allowed following any change in + * HT params. + */ + if (session->ftPEContext.pFTPreAuthReq) { + lim_log(mac_ctx, LOG1, FL("Freeing pFTPreAuthReq= %p"), + session->ftPEContext.pFTPreAuthReq); + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + cdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + cdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + session->ftPEContext.ftPreAuthSession = false; + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Re-set the LIM Ctxt Roam Synch In Progress")); + session->bRoamSynchInProgress = false; + } +#endif + + lim_log(mac_ctx, LOG1, FL("Rcv MLM_REASSOC_CNF with result code %d"), + lim_mlm_reassoc_cnf->resultCode); + if (lim_mlm_reassoc_cnf->resultCode == eSIR_SME_SUCCESS) { + /* Successful Reassociation */ + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + FL("*** Reassociated with new BSS ***")); + + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + /* Need to send Reassoc rsp with Reassoc success to Host. */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId, + session->transactionId); + } else if (lim_mlm_reassoc_cnf->resultCode + == eSIR_SME_REASSOC_REFUSED) { + /* + * Reassociation failure With the New AP but we still have the + * link with the Older AP + */ + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId, + session->transactionId); + } else { + /* Reassociation failure */ + session->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_handle_sme_reaasoc_result(mac_ctx, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session); + } +} + +/** + * lim_fill_assoc_ind_params() - Initialize association indication + * mac_ctx: Pointer to Global MAC structure + * assoc_ind: PE association indication structure + * sme_assoc_ind: SME association indication + * session_entry: PE session entry + * + * This function is called to initialzie the association + * indication strucutre to process association indication. + * + * Return: None + */ + +void +lim_fill_assoc_ind_params(tpAniSirGlobal mac_ctx, + tpLimMlmAssocInd assoc_ind, tSirSmeAssocInd *sme_assoc_ind, + tpPESession session_entry) +{ + sme_assoc_ind->length = sizeof(tSirSmeAssocInd); + sme_assoc_ind->sessionId = session_entry->smeSessionId; + + /* Required for indicating the frames to upper layer */ + sme_assoc_ind->assocReqLength = assoc_ind->assocReqLength; + sme_assoc_ind->assocReqPtr = assoc_ind->assocReqPtr; + + sme_assoc_ind->beaconPtr = session_entry->beacon; + sme_assoc_ind->beaconLength = session_entry->bcnLen; + + /* Fill in peerMacAddr */ + cdf_mem_copy(sme_assoc_ind->peerMacAddr, assoc_ind->peerMacAddr, + sizeof(tSirMacAddr)); + + /* Fill in aid */ + sme_assoc_ind->aid = assoc_ind->aid; + /* Fill in bssId */ + cdf_mem_copy(sme_assoc_ind->bssId, session_entry->bssId, + sizeof(tSirMacAddr)); + /* Fill in authType */ + sme_assoc_ind->authType = assoc_ind->authType; + /* Fill in ssId */ + cdf_mem_copy((uint8_t *) &sme_assoc_ind->ssId, + (uint8_t *) &(assoc_ind->ssId), assoc_ind->ssId.length + 1); + sme_assoc_ind->rsnIE.length = assoc_ind->rsnIE.length; + cdf_mem_copy((uint8_t *) &sme_assoc_ind->rsnIE.rsnIEdata, + (uint8_t *) &(assoc_ind->rsnIE.rsnIEdata), + assoc_ind->rsnIE.length); + +#ifdef FEATURE_WLAN_WAPI + sme_assoc_ind->wapiIE.length = assoc_ind->wapiIE.length; + cdf_mem_copy((uint8_t *) &sme_assoc_ind->wapiIE.wapiIEdata, + (uint8_t *) &(assoc_ind->wapiIE.wapiIEdata), + assoc_ind->wapiIE.length); +#endif + sme_assoc_ind->addIE.length = assoc_ind->addIE.length; + cdf_mem_copy((uint8_t *) &sme_assoc_ind->addIE.addIEdata, + (uint8_t *) &(assoc_ind->addIE.addIEdata), + assoc_ind->addIE.length); + + /* Copy the new TITAN capabilities */ + sme_assoc_ind->spectrumMgtIndicator = assoc_ind->spectrumMgtIndicator; + if (assoc_ind->spectrumMgtIndicator == eSIR_TRUE) { + sme_assoc_ind->powerCap.minTxPower = + assoc_ind->powerCap.minTxPower; + sme_assoc_ind->powerCap.maxTxPower = + assoc_ind->powerCap.maxTxPower; + sme_assoc_ind->supportedChannels.numChnl = + assoc_ind->supportedChannels.numChnl; + cdf_mem_copy((uint8_t *) &sme_assoc_ind->supportedChannels. + channelList, + (uint8_t *) &(assoc_ind->supportedChannels.channelList), + assoc_ind->supportedChannels.numChnl); + } + cdf_mem_copy(&sme_assoc_ind->chan_info, &assoc_ind->chan_info, + sizeof(tSirSmeChanInfo)); + /* Fill in WmmInfo */ + sme_assoc_ind->wmmEnabledSta = assoc_ind->WmmStaInfoPresent; +} + +/** + * lim_process_mlm_assoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_ASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_assoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint32_t len; + tSirMsgQ msgQ; + tSirSmeAssocInd *pSirSmeAssocInd; + tpDphHashNode pStaDs = 0; + tpPESession psessionEntry; + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + psessionEntry = pe_find_session_by_session_id(pMac, + ((tpLimMlmAssocInd) pMsgBuf)-> + sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionId")); + return; + } + /* / Inform Host of STA association */ + len = sizeof(tSirSmeAssocInd); + pSirSmeAssocInd = cdf_mem_malloc(len); + if (NULL == pSirSmeAssocInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_ASSOC_IND")); + return; + } + + pSirSmeAssocInd->messageType = eWNI_SME_ASSOC_IND; + lim_fill_assoc_ind_params(pMac, (tpLimMlmAssocInd) pMsgBuf, pSirSmeAssocInd, + psessionEntry); + msgQ.type = eWNI_SME_ASSOC_IND; + msgQ.bodyptr = pSirSmeAssocInd; + msgQ.bodyval = 0; + pStaDs = dph_get_hash_entry(pMac, + ((tpLimMlmAssocInd) pMsgBuf)->aid, + &psessionEntry->dph.dphHashTable); + if (!pStaDs) { /* good time to panic... */ + lim_log(pMac, LOGE, + FL + ("MLM AssocInd: Station context no longer valid (aid %d)"), + ((tpLimMlmAssocInd) pMsgBuf)->aid); + cdf_mem_free(pSirSmeAssocInd); + + return; + } + pSirSmeAssocInd->staId = pStaDs->staIndex; + pSirSmeAssocInd->reassocReq = pStaDs->mlmStaContext.subType; + pSirSmeAssocInd->timingMeasCap = pStaDs->timingMeasCap; + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ASSOC_IND_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT); + + PELOG1(lim_log(pMac, LOG1, + FL + ("Create CNF_WAIT_TIMER after received LIM_MLM_ASSOC_IND")); + ) + /* + ** turn on a timer to detect the loss of ASSOC CNF + **/ + lim_activate_cnf_timer(pMac, + (uint16_t) ((tpLimMlmAssocInd) pMsgBuf)->aid, + psessionEntry); + +} /*** end lim_process_mlm_assoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_DISASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_disassoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmDisassocInd *pMlmDisassocInd; + tpPESession psessionEntry; + pMlmDisassocInd = (tLimMlmDisassocInd *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDisassocInd->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + break; + default: /* eLIM_AP_ROLE //eLIM_BT_AMP_AP_ROLE */ + PELOG1(lim_log(pMac, LOG1, + FL("*** Peer staId=%d Disassociated ***"), + pMlmDisassocInd->aid); + ) + /* Send SME_DISASOC_IND after Polaris cleanup */ + /* (after receiving LIM_MLM_PURGE_STA_IND) */ + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_disassoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_cnf() - Processes disassociation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_DISASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_disassoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmDisassocCnf *disassoc_cnf; + tpPESession session_entry; + disassoc_cnf = (tLimMlmDisassocCnf *) msg; + + session_entry = + pe_find_session_by_session_id(mac_ctx, disassoc_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session Does not exist for given session Id")); + return; + } + result_code = (tSirResultCodes)(disassoc_cnf->disassocTrigger == + eLIM_LINK_MONITORING_DISASSOC) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + disassoc_cnf->resultCode; + if (LIM_IS_STA_ROLE(session_entry) || + LIM_IS_BT_AMP_STA_ROLE(session_entry)) { + /* Disassociate Confirm from MLM */ + if ((session_entry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (session_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + /* + * Should not have received + * Disassocate confirm + * from MLM in other states.Log error + */ + lim_log(mac_ctx, LOGE, + FL("received MLM_DISASSOC_CNF in state %X"), + session_entry->limSmeState); + return; + } + if (mac_ctx->lim.gLimRspReqd) + mac_ctx->lim.gLimRspReqd = false; + if (disassoc_cnf->disassocTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC) { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_OFFLINE_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } else { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + lim_send_sme_disassoc_ntf(mac_ctx, + disassoc_cnf->peerMacAddr, result_code, + disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + lim_send_sme_disassoc_ntf(mac_ctx, disassoc_cnf->peerMacAddr, + result_code, disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, session_entry); + } +} + +/** + * lim_process_mlm_deauth_ind() + * + ***FUNCTION: + * This function is called to processes MLM_DEAUTH_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmDeauthInd *pMlmDeauthInd; + tpPESession psessionEntry; + uint8_t sessionId; + pMlmDeauthInd = (tLimMlmDeauthInd *) pMsgBuf; + psessionEntry = pe_find_session_by_bssid(pMac, + pMlmDeauthInd->peerMacAddr, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for Addr:" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMlmDeauthInd->peerMacAddr)); + return; + } + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + psessionEntry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + default: /* eLIM_AP_ROLE */ + { + PELOG1(lim_log(pMac, LOG1, + FL + ("*** Received Deauthentication from staId=%d ***"), + pMlmDeauthInd->aid); + ) + } + /* Send SME_DEAUTH_IND after Polaris cleanup */ + /* (after receiving LIM_MLM_PURGE_STA_IND) */ + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_deauth_ind() ***/ + +/** + * lim_process_mlm_deauth_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_DEAUTH_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t aid; + tSirResultCodes resultCode; + tLimMlmDeauthCnf *pMlmDeauthCnf; + tpPESession psessionEntry; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmDeauthCnf = (tLimMlmDeauthCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDeauthCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given session Id ")); + ) + return; + } + + resultCode = (tSirResultCodes) + (pMlmDeauthCnf->deauthTrigger == + eLIM_LINK_MONITORING_DEAUTH) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + pMlmDeauthCnf->resultCode; + aid = LIM_IS_AP_ROLE(psessionEntry) ? pMlmDeauthCnf->aid : 1; + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + /* Deauth Confirm from MLM */ + if (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE) { + /** + * Should not have received Deauth confirm + * from MLM in other states. + * Log error + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received unexpected MLM_DEAUTH_CNF in state %X"), + psessionEntry->limSmeState);) + return; + } + if (pMlmDeauthCnf->resultCode == eSIR_SME_SUCCESS) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + PELOG1(lim_log(pMac, LOG1, + FL("*** Deauthenticated with BSS ***"));) + } else + psessionEntry->limSmeState = + psessionEntry->limPrevSmeState; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + if (pMac->lim.gLimRspReqd) + pMac->lim.gLimRspReqd = false; + } + /* On STA or on BASIC AP, send SME_DEAUTH_RSP to host */ + lim_send_sme_deauth_ntf(pMac, pMlmDeauthCnf->peerMacAddr, + resultCode, + pMlmDeauthCnf->deauthTrigger, + aid, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** end lim_process_mlm_deauth_cnf() ***/ + +/** + * lim_process_mlm_purge_sta_ind() + * + ***FUNCTION: + * This function is called to processes MLM_PURGE_STA_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirResultCodes resultCode; + tpLimMlmPurgeStaInd pMlmPurgeStaInd; + tpPESession psessionEntry; + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmPurgeStaInd = (tpLimMlmPurgeStaInd) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmPurgeStaInd->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given bssId")); + ) + return; + } + /* Purge STA indication from MLM */ + resultCode = (tSirResultCodes) pMlmPurgeStaInd->reasonCode; + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + default: /* eLIM_AP_ROLE */ + if (LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + /** + * Should not have received + * Purge STA indication + * from MLM in other states. + * Log error + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received unexpected MLM_PURGE_STA_IND in state %X"), + psessionEntry->limSmeState); + ) + break; + } + PELOG1(lim_log(pMac, LOG1, + FL("*** Cleanup completed for staId=%d ***"), + pMlmPurgeStaInd->aid); + ) + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + } + if (pMlmPurgeStaInd->purgeTrigger == eLIM_PEER_ENTITY_DEAUTH) { + lim_send_sme_deauth_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + } else + lim_send_sme_disassoc_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId, + psessionEntry); + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_purge_sta_ind() ***/ + +/** + * lim_process_mlm_set_keys_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_SETKEYS_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + /* Prepare and send SME_SETCONTEXT_RSP message */ + tLimMlmSetKeysCnf *pMlmSetKeysCnf; + tpPESession psessionEntry; + uint16_t aid; + tpDphHashNode sta_ds; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmSetKeysCnf = (tLimMlmSetKeysCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmSetKeysCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given sessionId ")); + ) + return; + } + psessionEntry->is_key_installed = 0; + lim_log(pMac, LOG1, + FL("Received MLM_SETKEYS_CNF with resultCode = %d"), + pMlmSetKeysCnf->resultCode); + /* if the status is success keys are installed in the + * Firmware so we can set the protection bit + */ + if (eSIR_SME_SUCCESS == pMlmSetKeysCnf->resultCode) { + psessionEntry->is_key_installed = 1; + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + sta_ds = dph_lookup_hash_entry(pMac, + pMlmSetKeysCnf->peerMacAddr, + &aid, &psessionEntry->dph.dphHashTable); + if (sta_ds != NULL) + sta_ds->is_key_installed = 1; + } + } + lim_send_sme_set_context_rsp(pMac, + pMlmSetKeysCnf->peerMacAddr, + 1, + (tSirResultCodes) pMlmSetKeysCnf->resultCode, + psessionEntry, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** end lim_process_mlm_set_keys_cnf() ***/ + +/** + * lim_handle_sme_join_result() - Handles sme join result + * @mac_ctx: Pointer to Global MAC structure + * @result_code: Failure code to be sent + * @prot_status_code : Protocol status code + * @session_entry: PE session handle + * + * This function is called to process join/auth/assoc failures + * upon receiving MLM_JOIN/AUTH/ASSOC_CNF with a failure code or + * MLM_ASSOC_CNF with a success code in case of STA role and + * MLM_JOIN_CNF with success in case of STA in IBSS role. + * + * Return: None + */ +static void +lim_handle_sme_join_result(tpAniSirGlobal mac_ctx, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry) +{ + tpDphHashNode sta_ds = NULL; + uint8_t sme_session_id; + uint16_t sme_trans_id; + + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("psessionEntry is NULL ")); + return; + } + sme_session_id = session_entry->smeSessionId; + sme_trans_id = session_entry->transactionId; + /* + * When associations is failed , delete the session created + * and pass NULL to limsendsmeJoinReassocRsp() + */ + if (result_code != eSIR_SME_SUCCESS) { + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds != NULL) { + sta_ds->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + sta_ds->mlmStaContext.resultCode = result_code; + sta_ds->mlmStaContext.protStatusCode = prot_status_code; + /* + * FIX_ME: at the end of lim_cleanup_rx_path, + * make sure PE is sending eWNI_SME_JOIN_RSP + * to SME + */ + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry); + cdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + return; + } + } + + cdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + /* Delete teh session if JOIN failure occurred. */ + if (result_code != eSIR_SME_SUCCESS) { + if (lim_set_link_state(mac_ctx, eSIR_LINK_DOWN_STATE, + session_entry->bssId, + session_entry->selfMacAddr, NULL, NULL) + != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("Failed to set the DownState.")); + if (lim_set_link_state + (mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->bssId, + session_entry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("Failed to set the LinkState.")); + pe_delete_session(mac_ctx, session_entry); + session_entry = NULL; + } + + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, result_code, + prot_status_code, session_entry, sme_session_id, sme_trans_id); +} + +/** + * lim_handle_sme_reaasoc_result() + * + ***FUNCTION: + * This function is called to process reassoc failures + * upon receiving REASSOC_CNF with a failure code or + * MLM_REASSOC_CNF with a success code in case of STA role + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param resultCode Failure code to be sent + * + * + * @return None + */ +static void +lim_handle_sme_reaasoc_result(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL "));) + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + /* When associations is failed , delete the session created and pass NULL to limsendsmeJoinReassocRsp() */ + if (resultCode != eSIR_SME_SUCCESS) { + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + pStaDs->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + pStaDs->mlmStaContext.resultCode = resultCode; + pStaDs->mlmStaContext.protStatusCode = protStatusCode; + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + return; + } + } + /* Delete teh session if REASSOC failure occurred. */ + if (resultCode != eSIR_SME_SUCCESS) { + if (NULL != psessionEntry) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + } + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, resultCode, + protStatusCode, psessionEntry, smesessionId, + smetransactionId); +} /*** end limHandleSmeReassocResult() ***/ + +/** + * lim_process_mlm_add_sta_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_STA_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +void lim_process_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_ap_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); +} + +/** + * lim_process_sta_mlm_add_sta_rsp () - Process add sta response + * @mac_ctx: Pointer to mac context + * @msg: tpSirMsgQan Message structure + * @session_entry: PE session entry + * + * Process ADD STA response sent from WMA and posts results + * to SME. + * + * Return: Null + */ + +void lim_process_sta_mlm_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tLimMlmAssocCnf mlm_assoc_cnf; + tpDphHashNode sta_ds; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + tpAddStaParams add_sta_params = (tpAddStaParams) msg->bodyptr; + tpPESession ft_session = NULL; + uint8_t ft_session_id; + + if (NULL == add_sta_params) { + lim_log(mac_ctx, LOGE, FL("Encountered NULL Pointer")); + return; + } + + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + + if (true == session_entry->fDeauthReceived) { + lim_log(mac_ctx, LOGE, + FL("Received Deauth frame in ADD_STA_RESP state")); + if (CDF_STATUS_SUCCESS == add_sta_params->status) { + lim_log(mac_ctx, LOGE, + FL("ADD_STA success, send update result code with eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA staIdx: %d limMlmState: %d"), + add_sta_params->staIdx, + session_entry->limMlmState); + + if (session_entry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + /* + * We are sending result code + * eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA which + * will trigger proper cleanup (DEL_STA/DEL_BSS both + * required) in either assoc cnf or reassoc cnf handler. + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA; + session_entry->staId = add_sta_params->staIdx; + goto end; + } + } + + if (CDF_STATUS_SUCCESS == add_sta_params->status) { + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != + session_entry->limMlmState) { + lim_log(mac_ctx, LOGE, + FL("Received WMA_ADD_STA_RSP in state %X"), + session_entry->limMlmState); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + goto end; + } + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { +#ifdef WLAN_FEATURE_VOWIFI_11R + /* check if we have keys(PTK)to install in case of 11r */ + tpftPEContext ft_ctx = &session_entry->ftPEContext; + ft_session = pe_find_session_by_bssid(mac_ctx, + session_entry->limReAssocbssId, &ft_session_id); + if (ft_session != NULL && + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid + == true) { + tpLimMlmSetKeysReq pMlmStaKeys = + &ft_ctx->PreAuthKeyInfo.extSetStaKeyParam; + lim_send_set_sta_key_req(mac_ctx, pMlmStaKeys, + 0, 0, ft_session, false); + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid = + false; + } +#endif + } + /* + * Update the DPH Hash Entry for this STA + * with proper state info + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (NULL != sta_ds) + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + else + lim_log(mac_ctx, LOGW, + FL("Fail to get DPH Hash Entry for AID - %d"), + DPH_STA_HASH_INDEX_PEER); + session_entry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* + * Storing the self StaIndex(Generated by HAL) in + * session context, instead of storing it in DPH Hash + * entry for Self STA. + * DPH entry for the self STA stores the sta index for + * the BSS entry to which the STA is associated + */ + session_entry->staId = add_sta_params->staIdx; + +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumLinkEsts++; +#endif +#ifdef FEATURE_WLAN_TDLS + /* initialize TDLS peer related data */ + lim_init_tdls_data(mac_ctx, session_entry); +#endif + /* + * Return Assoc confirm to SME with success + * FIXME - Need the correct ASSOC RSP code to + * be passed in here + */ + mlm_assoc_cnf.resultCode = (tSirResultCodes) eSIR_SME_SUCCESS; + } else { + lim_log(mac_ctx, LOGE, FL("ADD_STA failed!")); + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } +end: + if (NULL != msg->bodyptr) { + cdf_mem_free(add_sta_params); + msg->bodyptr = NULL; + } + /* Updating PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, (uint32_t *) &mlm_assoc_cnf); + if (true == session_entry->fDeauthReceived) + session_entry->fDeauthReceived = false; + return; +} + +void lim_process_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pMac->sys.gSysFrameCount[SIR_MAC_MGMT_FRAME][SIR_MAC_MGMT_DEAUTH] = 0; + + if ((LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry) || + LIM_IS_AP_ROLE(psessionEntry)) && + (psessionEntry->statypeForBss == STA_ENTRY_SELF)) { + lim_process_bt_amp_ap_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + if (eSIR_SUCCESS != + lim_send_exclude_unencrypt_ind(pMac, true, psessionEntry)) { + lim_log(pMac, LOGE, + FL + ("Could not send down Exclude Unencrypted Indication!")); + } + } +#endif +} + +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = (tpDeleteBssParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + + if (NULL == pDelBssParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + if (CDF_STATUS_SUCCESS == pDelBssParams->status) { + PELOGW(lim_log(pMac, LOGW, + FL("STA received the DEL_BSS_RSP for BSSID: %X."), + pDelBssParams->bssIdx); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_IDLE_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("Failure in setting link state to IDLE")); + ) + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (pStaDs == NULL) { + lim_log(pMac, LOGE, FL("DPH Entry for STA 1 missing.")); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != + pStaDs->mlmStaContext.mlmState) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Received unexpected WMA_DEL_BSS_RSP in state %X"), + pStaDs->mlmStaContext.mlmState); + ) + statusCode = eSIR_SME_REFUSED; + goto end; + } + PELOG1(lim_log + (pMac, LOG1, FL("STA AssocID %d MAC "), pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + ) + } else { + lim_log(pMac, LOGE, FL("DEL BSS failed!")); + statusCode = eSIR_SME_STOP_BSS_FAILURE; + } +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pDelBssParams); + limMsgQ->bodyptr = NULL; + } + if (pStaDs == NULL) + return; + if ((LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE && + psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + pStaDs->mlmStaContext.cleanupTrigger != + eLIM_JOIN_FAILURE) { + /** The Case where the DelBss is invoked from + * context of other than normal DisAssoc / Deauth OR + * as part of Join Failure. + */ + lim_handle_del_bss_in_re_assoc_context(pMac, pStaDs, psessionEntry); + return; + } + lim_prepare_and_send_del_sta_cnf(pMac, pStaDs, statusCode, psessionEntry); + return; +} + +void lim_process_bt_amp_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tSirRetStatus status; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) limMsgQ->bodyptr; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, FL("Session entry passed is NULL")); + if (pDelBss != NULL) { + cdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } + return; + } + + if (pDelBss == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("BSS: DEL_BSS_RSP with no body!"));) + rc = eSIR_SME_REFUSED; + goto end; + } + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != psessionEntry->limMlmState) { + lim_log(pMac, LOGE, + FL("Received unexpected WMA_DEL_BSS_RSP in state %X"), + psessionEntry->limMlmState); + rc = eSIR_SME_REFUSED; + goto end; + } + if (pDelBss->status != CDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, FL("BSS: DEL_BSS_RSP error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + status = lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, NULL); + if (status != eSIR_SUCCESS) { + rc = eSIR_SME_REFUSED; + goto end; + } + /** Softmac may send all the buffered packets right after resuming the transmission hence + * to occupy the medium during non channel occupancy period. So resume the transmission after + * HAL gives back the response. + */ + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + /* Initialize number of associated stations during cleanup */ + psessionEntry->gLimNumOfCurrentSTAs = 0; +end: + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + + if (pDelBss != NULL) { + cdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } +} + +/** + * lim_process_mlm_del_sta_rsp() - Process DEL STA response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_DEL_STA_RSP from + * WMA Upon receipt of this message from FW. + * + * Return: None + */ +void lim_process_mlm_del_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + /* + * we need to process the deferred message since the + * initiating req. there might be nested request + * in the case of nested request the new request + * initiated from the response will take care of resetting + * the deffered flag. + */ + tpPESession session_entry; + tpDeleteStaParams del_sta_params; + del_sta_params = (tpDeleteStaParams) msg->bodyptr; + if (NULL == del_sta_params) { + lim_log(mac_ctx, LOGE, + FL("null pointer del_sta_params msg")); + return; + } + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + + session_entry = pe_find_session_by_session_id(mac_ctx, + del_sta_params->sessionId); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGP, + FL("Session Doesn't exist")); + cdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + return; + } + + if (LIM_IS_BT_AMP_AP_ROLE(session_entry) || + LIM_IS_AP_ROLE(session_entry)) { + lim_process_bt_amp_ap_mlm_del_sta_rsp(mac_ctx, msg, + session_entry); + return; + } + lim_process_sta_mlm_del_sta_rsp(mac_ctx, msg, session_entry); +} + +void lim_process_bt_amp_ap_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tpDeleteStaParams pDelStaParams = (tpDeleteStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs; + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + if (limMsgQ->bodyptr == NULL) { + lim_log(pMac, LOGE, FL("limMsgQ->bodyptry NULL")); + return; + } + + pStaDs = + dph_get_hash_entry(pMac, pDelStaParams->assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, + FL("DPH Entry for STA %X missing."), + pDelStaParams->assocId); + statusCode = eSIR_SME_REFUSED; + cdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + + return; + } + lim_log(pMac, LOG1, FL("Received del Sta Rsp in StaD MlmState : %d"), + pStaDs->mlmStaContext.mlmState); + if (CDF_STATUS_SUCCESS == pDelStaParams->status) { + lim_log(pMac, LOGW, + FL("AP received the DEL_STA_RSP for assocID: %X."), + pDelStaParams->assocId); + + if ((eLIM_MLM_WT_DEL_STA_RSP_STATE != + pStaDs->mlmStaContext.mlmState) + && (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + pStaDs->mlmStaContext.mlmState)) { + lim_log(pMac, LOGE, + FL + ("Received unexpected WMA_DEL_STA_RSP in state %s for staId %d assocId %d "), + lim_mlm_state_str(pStaDs->mlmStaContext.mlmState), + pStaDs->staIndex, pStaDs->assocId); + statusCode = eSIR_SME_REFUSED; + goto end; + } + + lim_log(pMac, LOG1, + FL("Deleted STA AssocID %d staId %d MAC "), + pStaDs->assocId, pStaDs->staIndex); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE == + pStaDs->mlmStaContext.mlmState) { + cdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + if (lim_add_sta(pMac, pStaDs, false, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not Add STA with assocId=%d"), + pStaDs->assocId); + ) + /* delete the TS if it has already been added. */ + /* send the response with error status. */ + if (pStaDs->qos.addtsPresent) { + tpLimTspecInfo pTspecInfo; + if (eSIR_SUCCESS == + lim_tspec_find_by_assoc_id(pMac, + pStaDs->assocId, + &pStaDs->qos.addts.tspec, + &pMac->lim.tspecInfo[0], + &pTspecInfo)) { + lim_admit_control_delete_ts(pMac, + pStaDs-> + assocId, + &pStaDs-> + qos. + addts. + tspec. + tsinfo, + NULL, + &pTspecInfo-> + idx); + } + } + lim_reject_association(pMac, + pStaDs->staAddr, + pStaDs->mlmStaContext. + subType, true, + pStaDs->mlmStaContext. + authType, pStaDs->assocId, + true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + } + return; + } + } else { + lim_log(pMac, LOGW, FL("DEL STA failed!")); + statusCode = eSIR_SME_REFUSED; + } +end: + cdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + pStaDs->mlmStaContext.mlmState) { + lim_prepare_and_send_del_sta_cnf(pMac, pStaDs, statusCode, + psessionEntry); + } + return; +} + +void lim_process_sta_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + tpDeleteStaParams pDelStaParams = (tpDeleteStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + if (NULL == pDelStaParams) { + lim_log(pMac, LOGE, FL("Encountered NULL Pointer")); + goto end; + } + if (CDF_STATUS_SUCCESS == pDelStaParams->status) { + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, FL("DPH Entry for STA %X missing."), + pDelStaParams->assocId); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_STA_RSP_STATE != psessionEntry->limMlmState) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, + FL + ("Received unexpected WMA_DELETE_STA_RSP in state %s"), + lim_mlm_state_str(psessionEntry->limMlmState)); + statusCode = eSIR_SME_REFUSED; + goto end; + } + PELOG1(lim_log + (pMac, LOG1, FL("STA AssocID %d MAC "), pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + ) + lim_log(pMac, LOGW, + FL("DEL_STA_RSP received for assocID: %X"), + pDelStaParams->assocId); + /* we must complete all cleanup related to delSta before calling limDelBSS. */ + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + statusCode = + (tSirResultCodes) lim_del_bss(pMac, pStaDs, 0, psessionEntry); + return; + } else { + lim_log(pMac, LOGE, FL("DEL_STA failed for sta Id %d"), + pDelStaParams->staIdx); + statusCode = eSIR_SME_REFUSED; + } +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = (tpAddStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddStaParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + + pStaDs = + dph_get_hash_entry(pMac, pAddStaParams->assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, FL("DPH Entry for STA %X missing."), + pAddStaParams->assocId); + goto end; + } + /* */ + /* TODO & FIXME_GEN4 */ + /* Need to inspect tSirMsgQ.reserved for a valid Dialog token! */ + /* */ + /* TODO: any check for pMac->lim.gLimMlmState ? */ + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != pStaDs->mlmStaContext.mlmState) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, + FL("Received unexpected WMA_ADD_STA_RSP in state %X"), + pStaDs->mlmStaContext.mlmState); + goto end; + } + if (CDF_STATUS_SUCCESS != pAddStaParams->status) { + PELOGE(lim_log + (pMac, LOGE, + FL("Error! rcvd delSta rsp from HAL with status %d"), + pAddStaParams->status); + ) + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + goto end; + } + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + /* if the AssocRsp frame is not acknowledged, then keep alive timer will take care of the state */ + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_ASSOC_CNF_STATE; + lim_log(pMac, LOG1, + FL("AddStaRsp Success.STA AssocID %d staId %d MAC "), + pStaDs->assocId, pStaDs->staIndex); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + + /* For BTAMP-AP, the flow sequence shall be: + * 1) PE sends eWNI_SME_ASSOC_IND to SME + * 2) PE receives eWNI_SME_ASSOC_CNF from SME + * 3) BTAMP-AP sends Re/Association Response to BTAMP-STA + */ + lim_send_mlm_assoc_ind(pMac, pStaDs, psessionEntry); + /* fall though to reclaim the original Add STA Response message */ +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pAddStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +/** + * lim_process_ap_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_start_req + * tSirMsgQ.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +static void lim_process_ap_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ) +{ + tLimMlmStartCnf mlmStartCnf; + tpPESession psessionEntry; + uint8_t isWepEnabled = false; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + if (NULL == pAddBssParams) { + lim_log(pMac, LOGE, FL("Encountered NULL Pointer")); + goto end; + } + /* TBD: free the memory before returning, do it for all places where lookup fails. */ + psessionEntry = pe_find_session_by_session_id(pMac, + pAddBssParams->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given sessionId")); + ) + if (NULL != pAddBssParams) { + cdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } + return; + } + /* Update PE session Id */ + mlmStartCnf.sessionId = pAddBssParams->sessionId; + if (CDF_STATUS_SUCCESS == pAddBssParams->status) { + PELOG2(lim_log + (pMac, LOG2, + FL("WMA_ADD_BSS_RSP returned with CDF_STATUS_SUCCESS")); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_AP_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + psessionEntry->chainMask = pAddBssParams->chainMask; + psessionEntry->smpsMode = pAddBssParams->smpsMode; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + if (eSIR_IBSS_MODE == pAddBssParams->bssType) { + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + psessionEntry->statypeForBss = STA_ENTRY_PEER; /* to know session created for self/peer */ + limResetHBPktCount(psessionEntry); + } + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + + if (eSIR_INFRA_AP_MODE == pAddBssParams->bssType) + psessionEntry->limSystemRole = eLIM_AP_ROLE; + else + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + sch_edca_profile_update(pMac, psessionEntry); + lim_init_pre_auth_list(pMac); + /* Check the SAP security configuration.If configured to + * WEP then max clients supported is 16 + */ + if (psessionEntry->privacy) { + if ((psessionEntry->gStartBssRSNIe.present) + || (psessionEntry->gStartBssWPAIe.present)) + lim_log(pMac, LOG1, + FL("WPA/WPA2 SAP configuration\n")); + else { + if (pMac->lim.gLimAssocStaLimit > + MAX_SUPPORTED_PEERS_WEP) { + lim_log(pMac, LOG1, + FL("WEP SAP Configuration\n")); + pMac->lim.gLimAssocStaLimit = + MAX_SUPPORTED_PEERS_WEP; + isWepEnabled = true; + } + } + } + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Start OLBC timer */ + if (tx_timer_activate + (&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGE, FL("tx_timer_activate failed")); + } + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + + /* In lim_apply_configuration gLimAssocStaLimit is assigned from cfg. + * So update the value to 16 in case SoftAP is configured in WEP. + */ + if ((pMac->lim.gLimAssocStaLimit > MAX_SUPPORTED_PEERS_WEP) + && (isWepEnabled)) + pMac->lim.gLimAssocStaLimit = MAX_SUPPORTED_PEERS_WEP; + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + } else { + lim_log(pMac, LOGE, FL("WMA_ADD_BSS_REQ failed with status %d"), + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * lim_process_ibss_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_start_req + * tSirMsgQ.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +static void +lim_process_ibss_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tLimMlmStartCnf mlmStartCnf; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + + if (NULL == pAddBssParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + if (CDF_STATUS_SUCCESS == pAddBssParams->status) { + PELOG1(lim_log + (pMac, LOG1, + FL("WMA_ADD_BSS_RSP returned with CDF_STATUS_SUCCESS")); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_IBSS_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + limResetHBPktCount(psessionEntry); + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + psessionEntry->statypeForBss = STA_ENTRY_SELF; + sch_edca_profile_update(pMac, psessionEntry); + if (0 == psessionEntry->freePeerIdxHead) + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + /* If ADD BSS was issued as part of IBSS coalescing, don't send the message to SME, as that is internal to LIM */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + lim_ibss_add_bss_rsp_when_coalescing(pMac, limMsgQ->bodyptr, + psessionEntry); + goto end; + } + } else { + lim_log(pMac, LOGE, FL("WMA_ADD_BSS_REQ failed with status %d"), + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + /* Send this message to SME, when ADD_BSS is initiated by SME */ + /* If ADD_BSS is done as part of coalescing, this won't happen. */ + /* Update PE session Id */ + mlmStartCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx: Pointer to mac context + * @msg: message sent to HDD + * @session_entry: PE session handle + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL if the state is pre assoc. + * + * Return: Null + */ +static void +lim_process_sta_add_bss_rsp_pre_assoc(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tpAddBssParams pAddBssParams = (tpAddBssParams) msg->bodyptr; + tAniAuthType cfgAuthType, authMode; + tLimMlmAuthReq *pMlmAuthReq; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddBssParams) { + lim_log(mac_ctx, LOGE, FL("Invalid body pointer in message")); + goto joinFailure; + } + if (CDF_STATUS_SUCCESS == pAddBssParams->status) { + pStaDs = dph_add_hash_entry(mac_ctx, + pAddBssParams->staContext.staMac, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + lim_log(mac_ctx, LOGE, + FL("could not add hash entry at DPH for ")); + lim_print_mac_addr(mac_ctx, + pAddBssParams->staContext.staMac, LOGE); + goto joinFailure; + } + session_entry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + /* Trigger Authentication with AP */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &cfgAuthType) != eSIR_SUCCESS) { + /* + * Could not get AuthType from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve AuthType")); + } + /* Try Open Authentication first */ + if (cfgAuthType == eSIR_AUTO_SWITCH) + authMode = eSIR_OPEN_SYSTEM; + else + authMode = cfgAuthType; + + /* Trigger MAC based Authentication */ + pMlmAuthReq = cdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (NULL == pMlmAuthReq) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed for mlmAuthReq")); + return; + } + sir_copy_mac_addr(pMlmAuthReq->peerMacAddr, + session_entry->bssId); + + pMlmAuthReq->authType = authMode; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &pMlmAuthReq->authFailureTimeout) + != eSIR_SUCCESS) { + /* + * Could not get AuthFailureTimeout + * value from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail: retrieve AuthFailureTimeout value")); + } + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + pMlmAuthReq->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_AUTH_STATE; + /* remember staId in case of assoc timeout/failure handling */ + session_entry->staId = pAddBssParams->staContext.staIdx; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + lim_log(mac_ctx, LOG1, + FL("SessionId:%d lim_post_mlm_message " + "LIM_MLM_AUTH_REQ with limSmeState:%d"), + session_entry->peSessionId, session_entry->limSmeState); + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) pMlmAuthReq); + return; + } + +joinFailure: + { + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, eSIR_SME_REFUSED, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session_entry); + } + +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/*------------------------------------------------------------------------------------------ + * + * Function to handle WMA_ADD_BSS_RSP, in FT reassoc state. + * Function to Send ReAssociation Request. + * + * + ***------------------------------------------------------------------------------------------ + */ +static inline void +lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tpDphHashNode pStaDs = NULL; + tpAddStaParams pAddStaParams = NULL; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + uint32_t selfStaDot11Mode = 0; + + /* Sanity Checks */ + + if (pAddBssParams == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid parameters"));) + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE != + psessionEntry->limMlmState) { + goto end; + } + + pStaDs = dph_add_hash_entry(pMac, pAddBssParams->bssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + PELOGE(lim_log + (pMac, LOGE, FL("could not add hash entry at DPH for ")); + ) + lim_print_mac_addr(pMac, pAddBssParams->staContext.staMac, + LOGE); + goto end; + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) { +#endif + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate + (&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* / Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("could not start Reassociation failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + pMac->lim.pSessionEntry = psessionEntry; + if (NULL == pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) { + /* Take a copy of reassoc request for retrying */ + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq = + cdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) + goto end; + cdf_mem_set(pMac->lim.pSessionEntry-> + pLimMlmReassocRetryReq, + sizeof(tLimMlmReassocReq), 0); + cdf_mem_copy(pMac->lim.pSessionEntry-> + pLimMlmReassocRetryReq, + psessionEntry->pLimMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + pMac->lim.reAssocRetryAttempt = 0; +#endif + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, + psessionEntry-> + pLimMlmReassocReq, + psessionEntry); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +} else { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:Do not activate timer and dont send the reassoc req"); +} +#endif + psessionEntry->limPrevMlmState = psessionEntry->limMlmState; + psessionEntry->limMlmState = eLIM_MLM_WT_FT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE)); + PELOGE(lim_log + (pMac, LOG1, FL("Set the mlm state to %d session=%d"), + psessionEntry->limMlmState, psessionEntry->peSessionId); + ) + + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + pStaDs->ucUcastSig = pAddBssParams->staContext.ucUcastSig; + pStaDs->ucBcastSig = pAddBssParams->staContext.ucBcastSig; + +#if defined WLAN_FEATURE_VOWIFI + rrm_cache_mgmt_tx_power(pMac, pAddBssParams->txMgmtPower, psessionEntry); +#endif + + pAddStaParams = cdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + goto end; + } + cdf_mem_set((uint8_t *) pAddStaParams, sizeof(tAddStaParams), 0); + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + cdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) psessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) pAddStaParams->bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = CDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) +#endif + pAddStaParams->staIdx = STA_INVALID_IDX; + pAddStaParams->updateSta = false; + + pAddStaParams->shortPreambleSupported = + (uint8_t) psessionEntry->beaconParams.fShortPreamble; +#ifdef WLAN_FEATURE_11AC + lim_populate_peer_rate_set(pMac, &pAddStaParams->supportedRates, NULL, + false, psessionEntry, NULL); +#else + lim_populate_peer_rate_set(pMac, &pAddStaParams->supportedRates, NULL, + false, psessionEntry); +#endif + + if (psessionEntry->htCapability) { + pAddStaParams->htCapable = psessionEntry->htCapability; +#ifdef WLAN_FEATURE_11AC + pAddStaParams->vhtCapable = psessionEntry->vhtCapability; + pAddStaParams->ch_width = psessionEntry->ch_width; +#endif + + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + pAddStaParams->fShortGI20Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_20MHZ, psessionEntry); + pAddStaParams->fShortGI40Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_40MHZ, psessionEntry); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + pAddStaParams->supportedRates.opRateMode = + lim_get_sta_rate_mode((uint8_t) selfStaDot11Mode); + pAddStaParams->encryptType = psessionEntry->encryptType; + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* Lets save this for when we receive the Reassoc Rsp */ + psessionEntry->ftPEContext.pAddStaReq = pAddStaParams; + + if (pAddBssParams != NULL) { + cdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:Prepare and save pAddStaReq in pMac for post-assoc-rsp"); + lim_process_assoc_rsp_frame(pMac, pMac->roam.pReassocResp, + LIM_REASSOC, psessionEntry); + } +#endif + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (psessionEntry != NULL) + if (psessionEntry->pLimMlmReassocReq != NULL) { + cdf_mem_free(psessionEntry->pLimMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } + + if (pAddBssParams != NULL) { + cdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } + + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE session Id */ + if (psessionEntry != NULL) + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + else + mlmReassocCnf.sessionId = 0; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ +/** + * lim_process_sta_mlm_add_bss_rsp() - Process ADD BSS response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Now, send an ADD_STA to HAL and ADD the "local" STA itself + * + * MLME had sent WMA_ADD_BSS_REQ to HAL + * HAL responded with WMA_ADD_BSS_RSP to MLME + * MLME now sends WMA_ADD_STA_REQ to HAL + * ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_join_req + * tSirMsgQ.body will now be freed by this routine + * + * Return: None + */ +static void +lim_process_sta_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tpAddBssParams add_bss_params = (tpAddBssParams) msg->bodyptr; + tLimMlmAssocCnf mlm_assoc_cnf; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + uint32_t sub_type = LIM_ASSOC; + tpDphHashNode sta_ds = NULL; + uint16_t sta_idx = STA_INVALID_IDX; + uint8_t update_sta = false; + mlm_assoc_cnf.resultCode = eSIR_SME_SUCCESS; + + if (eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE == + session_entry->limMlmState) { + lim_log(mac_ctx, LOG1, + "SessionId:%d lim_process_sta_add_bss_rsp_pre_assoc", + session_entry->peSessionId); + lim_process_sta_add_bss_rsp_pre_assoc(mac_ctx, msg, + session_entry); + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE == session_entry->limMlmState +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + || (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) +#endif + ) { + msg_type = LIM_MLM_REASSOC_CNF; + sub_type = LIM_REASSOC; + /* + * If Reassoc is happening for the same BSS, then + * use the existing StaId and indicate to HAL to update + * the existing STA entry. + * If Reassoc is happening for the new BSS, then + * old BSS and STA entry would have been already deleted + * before PE tries to add BSS for the new BSS, so set the + * updateSta to false and pass INVALID STA Index. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) { + sta_idx = session_entry->staId; + update_sta = true; + } + } + + if (add_bss_params == 0) + goto end; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "LFR3:lim_process_sta_mlm_add_bss_rsp"); +#endif + + if (CDF_STATUS_SUCCESS == add_bss_params->status) { +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("Mlm=%d %d"), + session_entry->limMlmState, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); +#endif + lim_process_sta_mlm_add_bss_rsp_ft(mac_ctx, msg, + session_entry); + goto end; + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + /* Set MLME state */ + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* to know the session started for self or for peer */ + session_entry->statypeForBss = STA_ENTRY_PEER; + /* Now, send WMA_ADD_STA_REQ */ + lim_log(mac_ctx, LOGW, + FL("SessionId:%d On STA: ADD_BSS was successful"), + session_entry->peSessionId); + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session:%d Fail to add Self Entry for STA"), + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } else { + session_entry->bssIdx = + (uint8_t) add_bss_params->bssIdx; + /* Success, handle below */ + sta_ds->bssId = add_bss_params->bssIdx; + /* + * STA Index(genr by HAL) for the BSS + * entry is stored here + */ + sta_ds->staIndex = add_bss_params->staContext.staIdx; + sta_ds->ucUcastSig = + add_bss_params->staContext.ucUcastSig; + sta_ds->ucBcastSig = + add_bss_params->staContext.ucBcastSig; + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, session_entry); + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + sta_ds->bssId); +#if defined WLAN_FEATURE_VOWIFI + rrm_cache_mgmt_tx_power(mac_ctx, + add_bss_params->txMgmtPower, session_entry); +#endif + if (lim_add_sta_self(mac_ctx, sta_idx, update_sta, + session_entry) != eSIR_SUCCESS) { + /* Add STA context at HW */ + lim_log(mac_ctx, LOGE, + FL("Session:%d could not Add Self" + "Entry for the station"), + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } + } + } else { + lim_log(mac_ctx, LOGP, FL("SessionId:%d ADD_BSS failed!"), + session_entry->peSessionId); + /* Return Assoc confirm to SME with failure */ + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } + + if (mlm_assoc_cnf.resultCode != eSIR_SME_SUCCESS) { + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->bssId, + session_entry->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL("Failed to set the LinkState")); + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, + (uint32_t *) &mlm_assoc_cnf); + } +end: + if (0 != msg->bodyptr) { + cdf_mem_free(add_bss_params); + msg->bodyptr = NULL; + } +} + +/** + * lim_process_mlm_add_bss_rsp() - Processes ADD BSS Response + * + * @mac_ctx - Pointer to Global MAC structure + * @msg - The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * Determines the "state" in which this message was received + * Forwards it to the appropriate callback + * + *LOGIC: + * WMA_ADD_BSS_RSP can be received by MLME while the LIM is + * in the following two states: + * 1) As AP, LIM state = eLIM_SME_WT_START_BSS_STATE + * 2) As STA, LIM state = eLIM_SME_WT_JOIN_STATE + * Based on these two states, this API will determine where to + * route the message to + * + * Return None + */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tLimMlmStartCnf mlm_start_cnf; + tpPESession session_entry; + tpAddBssParams add_bss_param = (tpAddBssParams) (msg->bodyptr); + tSirBssType bss_type; + + if (NULL == add_bss_param) { + lim_log(mac_ctx, LOGE, FL("Encountered NULL Pointer")); + return; + } + + /* + * we need to process the deferred message since the + * initiating req.there might be nested request. + * in the case of nested request the new request initiated + * from the response will take care of resetting the deffered + * flag. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + /* Validate SME/LIM/MLME state */ + session_entry = pe_find_session_by_session_id(mac_ctx, + add_bss_param->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d Session Doesn't exist"), + add_bss_param->sessionId); + if (NULL != add_bss_param) { + cdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + return; + } + + session_entry->nss = add_bss_param->nss; + bss_type = session_entry->bssType; + /* update PE session Id */ + mlm_start_cnf.sessionId = session_entry->peSessionId; + if (eSIR_IBSS_MODE == bss_type) { + lim_process_ibss_mlm_add_bss_rsp(mac_ctx, msg, session_entry); + } else { + if (eLIM_SME_WT_START_BSS_STATE == session_entry->limSmeState) { + if (eLIM_MLM_WT_ADD_BSS_RSP_STATE != + session_entry->limMlmState) { + /* Mesg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Received " + " WMA_ADD_BSS_RSP in state %X"), + session_entry->peSessionId, + session_entry->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + if (0 != msg->bodyptr) { + cdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); + } else if ((bss_type == eSIR_BTAMP_AP_MODE) || + (bss_type == eSIR_BTAMP_STA_MODE)) { + lim_process_btamp_add_bss_rsp(mac_ctx, msg, + session_entry); + } else + lim_process_ap_mlm_add_bss_rsp(mac_ctx, msg); + } else { + /* Called while processing assoc response */ + lim_process_sta_mlm_add_bss_rsp(mac_ctx, msg, + session_entry); + } + } + +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) { + if (eSIR_SUCCESS != + lim_send_exclude_unencrypt_ind(mac_ctx, false, + session_entry)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Exclude Unencrypted Ind.")); + } + } +#endif +} + +/** + * lim_process_mlm_set_sta_key_rsp() - Process STA key response + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process the following two + * messages from HAL: + * 1) WMA_SET_BSSKEY_RSP + * 2) WMA_SET_STAKEY_RSP + * 3) WMA_SET_STA_BCASTKEY_RSP + * Upon receipt of this message from HAL, + * MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * LOGIC: + * WMA_SET_BSSKEY_RSP/WMA_SET_STAKEY_RSP can be + * received by MLME while in the following state: + * MLME state = eLIM_MLM_WT_SET_BSS_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_BCASTKEY_STATE + * Based on this state, this API will determine where to + * route the message to + * Assumption: + * ONLY the MLME state is being taken into account for now. + * This is because, it appears that the handling of the + * SETKEYS REQ is handled symmetrically on both the AP & STA + * + * Return: None + */ +void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + uint8_t resp_reqd = 1; + tLimMlmSetKeysCnf mlm_set_key_cnf; + uint8_t session_id = 0; + tpPESession session_entry; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + cdf_mem_set((void *)&mlm_set_key_cnf, sizeof(tLimMlmSetKeysCnf), 0); + if (NULL == msg->bodyptr) { + PELOGE(lim_log(mac_ctx, LOGE, FL("msg bodyptr is NULL"));) + return; + } + session_id = ((tpSetStaKeyParams) msg->bodyptr)->sessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, + FL("session does not exist for given session_id"));) + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (eLIM_MLM_WT_SET_STA_KEY_STATE != session_entry->limMlmState) { + /* Mesg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("Received unexpected [Mesg Id - %d] in state %X"), + msg->type, session_entry->limMlmState); + /* There's not much that MLME can do at this stage... */ + resp_reqd = 0; + } else { + mlm_set_key_cnf.resultCode = + (uint16_t)(((tpSetStaKeyParams) msg->bodyptr)->status); + } + + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, session_entry->limMlmState)); + if (resp_reqd) { + tpLimMlmSetKeysReq lpLimMlmSetKeysReq = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != lpLimMlmSetKeysReq) { + cdf_mem_copy((uint8_t *) &mlm_set_key_cnf.peerMacAddr, + (uint8_t *) lpLimMlmSetKeysReq->peerMacAddr, + sizeof(tSirMacAddr)); + /* + * Free the buffer cached for the global + * mac_ctx->lim.gpLimMlmSetKeysReq + */ + cdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + mlm_set_key_cnf.sessionId = session_id; + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &mlm_set_key_cnf); + } +} + +/** + * lim_process_mlm_set_bss_key_rsp() - handles BSS key + * + * @mac_ctx: A pointer to Global MAC structure + * @msg: Message from SME + * + * This function processes BSS key response and updates + * PE status accordingly. + * + * Return: NULL + */ +void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tLimMlmSetKeysCnf set_key_cnf; + uint16_t result_status; + uint8_t session_id = 0; + tpPESession session_entry; + tpLimMlmSetKeysReq set_key_req; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + cdf_mem_set((void *)&set_key_cnf, sizeof(tLimMlmSetKeysCnf), 0); + if (NULL == msg->bodyptr) { + PELOGE(lim_log(mac_ctx, LOGE, FL("msg bodyptr is null"));) + return; + } + session_id = ((tpSetBssKeyParams) msg->bodyptr)->sessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId [%d]"), + session_id);) + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (eLIM_MLM_WT_SET_BSS_KEY_STATE == session_entry->limMlmState) + result_status = + (uint16_t)(((tpSetBssKeyParams)msg->bodyptr)->status); + else + /* + * BCAST key also uses tpSetStaKeyParams. + * Done this way for readabilty. + */ + result_status = + (uint16_t)(((tpSetStaKeyParams)msg->bodyptr)->status); + + /* Validate MLME state */ + if (eLIM_MLM_WT_SET_BSS_KEY_STATE != session_entry->limMlmState && + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE != + session_entry->limMlmState) { + /* Msg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("Received unexpected [Mesg Id - %d] in state %X"), + msg->type, session_entry->limMlmState); + } else { + set_key_cnf.resultCode = result_status; + } + + cdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + set_key_req = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + set_key_cnf.sessionId = session_id; + + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != set_key_req) { + cdf_mem_copy((uint8_t *) &set_key_cnf.peerMacAddr, + (uint8_t *) set_key_req->peerMacAddr, + sizeof(tSirMacAddr)); + /* + * Free the buffer cached for the + * global mac_ctx->lim.gpLimMlmSetKeysReq + */ + cdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &set_key_cnf); +} + +/** + * lim_process_switch_channel_re_assoc_req() + * + ***FUNCTION: + * This function is called to send the reassoc req mgmt frame after the + * switchChannelRsp message is received from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure. + * @param psessionEntry - session related information. + * @param status - channel switch success/failure. + * + * @return None + */ +static void lim_process_switch_channel_re_assoc_req(tpAniSirGlobal pMac, + tpPESession psessionEntry, + CDF_STATUS status) +{ + tLimMlmReassocCnf mlmReassocCnf; + tLimMlmReassocReq *pMlmReassocReq; + pMlmReassocReq = + (tLimMlmReassocReq *) (psessionEntry->pLimMlmReassocReq); + if (pMlmReassocReq == NULL) { + lim_log(pMac, LOGP, + FL + ("pLimMlmReassocReq does not exist for given switchChanSession")); + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + if (status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("Change channel failed!!"));) + mlmReassocCnf.resultCode = eSIR_SME_CHANNEL_SWITCH_FAIL; + goto end; + } + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* / Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not start Reassociation failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* / Prepare and send Reassociation request frame */ + lim_send_reassoc_req_mgmt_frame(pMac, pMlmReassocReq, psessionEntry); + return; +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + /* Update PE session Id */ + mlmReassocCnf.sessionId = pMlmReassocReq->sessionId; + cdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } else { + mlmReassocCnf.sessionId = 0; + } + + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + + +/** + * lim_process_switch_channel_join_req() -Initiates probe request + * + * @mac_ctx - A pointer to Global MAC structure + * @sessionEntry - session related information. + * @status - channel switch success/failure + * + * This function is called to send the probe req mgmt frame + * after the switchChannelRsp message is received from HAL. + * + * Return None + */ +static void lim_process_switch_channel_join_req( + tpAniSirGlobal mac_ctx, tpPESession session_entry, + CDF_STATUS status) +{ + tSirMacSSid ssId; + tLimMlmJoinCnf join_cnf; + if (status != CDF_STATUS_SUCCESS) { + PELOGE(lim_log(mac_ctx, LOGE, FL("Change channel failed!!"));) + goto error; + } + + if ((NULL == session_entry) || (NULL == session_entry->pLimMlmJoinReq) + || (NULL == session_entry->pLimJoinReq)) { + PELOGE(lim_log(mac_ctx, LOGE, FL("invalid pointer!!"));) + goto error; + } + + /* + * eSIR_BTAMP_AP_MODE stroed as bss type in session + * Table when join req is received, is to be veified + */ + if (session_entry->bssType == eSIR_BTAMP_AP_MODE) { + if (lim_set_link_state + (mac_ctx, eSIR_LINK_BTAMP_PREASSOC_STATE, + session_entry->bssId, session_entry->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) { + PELOGE(lim_log + (mac_ctx, LOGE, + FL("Sessionid: %d Set link state " + "failed!! BSSID:" MAC_ADDRESS_STR), + session_entry->peSessionId, + MAC_ADDR_ARRAY(session_entry->bssId));) + goto error; + } + } + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_JOIN_BEACON_STATE; + lim_log(mac_ctx, LOG1, + FL("Sessionid %d prev lim state %d new lim state %d " + "systemrole = %d"), session_entry->peSessionId, + session_entry->limPrevMlmState, + session_entry->limMlmState, GET_LIM_SYSTEM_ROLE(session_entry)); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + + /* + * If sendDeauthBeforeCon is enabled, Send Deauth first to AP if last + * disconnection was caused by HB failure. + */ + if(mac_ctx->roam.configParam.sendDeauthBeforeCon) { + int apCount; + + for(apCount = 0; apCount < 2; apCount++) { + + if (cdf_mem_compare(session_entry->pLimMlmJoinReq->bssDescription.bssId, + mac_ctx->lim.gLimHeartBeatApMac[apCount], sizeof(tSirMacAddr))) { + + lim_log(mac_ctx, LOGE, FL("Index %d Sessionid: %d Send deauth on " + "channel %d to BSSID: "MAC_ADDRESS_STR ), apCount, + session_entry->peSessionId, session_entry->currentOperChannel, + MAC_ADDR_ARRAY(session_entry->pLimMlmJoinReq->bssDescription. + bssId)); + + lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_REASON, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry, false ); + + cdf_mem_zero(mac_ctx->lim.gLimHeartBeatApMac[apCount], + sizeof(tSirMacAddr)); + break; + } + } + } + + /* Wait for Beacon to announce join success */ + cdf_mem_copy(ssId.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + ssId.length = session_entry->ssId.length; + + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId = + session_entry->peSessionId; + lim_log(mac_ctx, LOG1, + FL("Sessionid: %d Send Probe req on channel %d ssid:%.*s " + "BSSID: " MAC_ADDRESS_STR), session_entry->peSessionId, + session_entry->currentOperChannel, ssId.length, ssId.ssId, + MAC_ADDR_ARRAY( + session_entry->pLimMlmJoinReq->bssDescription.bssId)); + + /* + * We need to wait for probe response, so start join + * timeout timer.This timer will be deactivated once + * we receive probe response. + */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_JOIN_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimJoinFailureTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't activate Join failure timer")); + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + mac_ctx->lim.gLimMlmState)); + session_entry->pLimMlmJoinReq = NULL; + goto error; + } + /* include additional IE if there is */ + lim_send_probe_req_mgmt_frame(mac_ctx, &ssId, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry->currentOperChannel, session_entry->selfMacAddr, + session_entry->dot11mode, + session_entry->pLimJoinReq->addIEScan.length, + session_entry->pLimJoinReq->addIEScan.addIEdata); + + if (session_entry->pePersona == CDF_P2P_CLIENT_MODE) { + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Periodic JoinReq timer activate failed")); + goto error; + } + } + return; +error: + if (NULL != session_entry) { + if (session_entry->pLimMlmJoinReq) { + cdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (session_entry->pLimJoinReq) { + cdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + } + join_cnf.sessionId = session_entry->peSessionId; + } else { + join_cnf.sessionId = 0; + } + join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *)&join_cnf); +} + +/** + * lim_process_switch_channel_rsp() + * + ***FUNCTION: + * This function is called to process switchChannelRsp message from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param body - message body. + * + * @return None + */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *body) +{ + tpSwitchChannelParams pChnlParams = NULL; + CDF_STATUS status; + uint16_t channelChangeReasonCode; + uint8_t peSessionId; + tpPESession psessionEntry; + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pChnlParams = (tpSwitchChannelParams) body; + status = pChnlParams->status; + peSessionId = pChnlParams->peSessionId; + + psessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("session does not exist for given sessionId")); + return; + } +#if defined WLAN_FEATURE_VOWIFI + /* HAL fills in the tx power used for mgmt frames in this field. */ + /* Store this value to use in TPC report IE. */ + rrm_cache_mgmt_tx_power(pMac, pChnlParams->txMgmtPower, psessionEntry); +#endif + channelChangeReasonCode = psessionEntry->channelChangeReasonCode; + /* initialize it back to invalid id */ + psessionEntry->chainMask = pChnlParams->chainMask; + psessionEntry->nss = pChnlParams->nss; + psessionEntry->smpsMode = pChnlParams->smpsMode; + psessionEntry->channelChangeReasonCode = 0xBAD; + lim_log(pMac, LOG1, FL("channelChangeReasonCode %d"), + channelChangeReasonCode); + switch (channelChangeReasonCode) { + case LIM_SWITCH_CHANNEL_REASSOC: + lim_process_switch_channel_re_assoc_req(pMac, psessionEntry, status); + break; + case LIM_SWITCH_CHANNEL_JOIN: + lim_process_switch_channel_join_req(pMac, psessionEntry, status); + break; + + case LIM_SWITCH_CHANNEL_OPERATION: + /* + * The above code should also use the callback. + * mechanism below, there is scope for cleanup here. + * THat way all this response handler does is call the call back + * We can get rid of the reason code here. + */ + if (pMac->lim.gpchangeChannelCallback) { + PELOG1(lim_log + (pMac, LOG1, + "Channel changed hence invoke registered call back"); + ) + pMac->lim.gpchangeChannelCallback(pMac, status, + pMac->lim. + gpchangeChannelData, + psessionEntry); + } + break; + case LIM_SWITCH_CHANNEL_SAP_DFS: + { + /* Note: This event code specific to SAP mode + * When SAP session issues channel change as performing + * DFS, we will come here. Other sessions, for e.g. P2P + * will have to define their own event code and channel + * switch handler. This is required since the SME may + * require completely different information for P2P unlike + * SAP. + */ + lim_send_sme_ap_channel_switch_resp(pMac, psessionEntry, + pChnlParams); + } + break; + default: + break; + } + cdf_mem_free(body); +} + +/** + * @function : lim_handle_del_bss_in_re_assoc_context + * @brief : While Processing the ReAssociation Response Frame in STA, + * a. immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b .If an AP rejects the ReAssociation (Disassoc / Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the DELBSS + * context only + * + * @param : pMac - tpAniSirGlobal + * pStaDs - Station Descriptor + * + * @return : none + */ +static void +lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + /* + * Skipped the DeleteDPH Hash Entry as we need it for the new BSS + * Set the MlmState to IDLE + */ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: + { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + tSirRetStatus retStatus = eSIR_SUCCESS; + tpSchBeaconStruct beacon_struct; + beacon_struct = cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon_struct) { + lim_log(pMac, LOGE, FL("beaconStruct alloc failed")); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + goto error; + } + /* Delete the older STA Table entry */ + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + /* + * Add an entry for AP to hash table + * maintained by DPH module + */ + pStaDs = dph_add_hash_entry(pMac, + psessionEntry->limReAssocbssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + lim_log(pMac, LOGE, + FL("could not add hash entry at DPH for ")); + lim_print_mac_addr(pMac, + psessionEntry->limReAssocbssId, LOGE); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + goto error; + } + /* + * While Processing the ReAssoc Response Frame the ReAssocRsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + lim_extract_ap_capabilities(pMac, + (uint8_t *) psessionEntry->pLimReAssocReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &psessionEntry->pLimReAssocReq->bssDescription), + beacon_struct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + beacon_struct, + psessionEntry); + if (beacon_struct->erpPresent) { + if (beacon_struct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams.fShortPreamble = 0; + else + psessionEntry->beaconParams.fShortPreamble = 1; + } + /* + * updateBss flag is false, as in this case, PE is first + * deleting the existing BSS and then adding a new one + */ + if (eSIR_SUCCESS != + lim_sta_send_add_bss(pMac, assocRsp, beacon_struct, + &psessionEntry->pLimReAssocReq->bssDescription, + false, psessionEntry)) { + lim_log(pMac, LOGE, + FL("Posting ADDBSS in the ReAssocCtx has Failed ")); + retStatus = eSIR_FAILURE; + } + if (retStatus != eSIR_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + cdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + cdf_mem_free(beacon_struct); + goto error; + } + cdf_mem_free(assocRsp); + cdf_mem_free(beacon_struct); + psessionEntry->limAssocResponseData = NULL; + } + break; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: + { + /** Case wherein the DisAssoc / Deauth + * being sent as response to ReAssoc Req*/ + /** Send the Reason code as the same received in Disassoc / Deauth Frame*/ + mlmReassocCnf.resultCode = + pStaDs->mlmStaContext.disassocReason; + mlmReassocCnf.protStatusCode = + pStaDs->mlmStaContext.cleanupTrigger; + /** Set the SME State back to WT_Reassoc State*/ + psessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + if (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = + eLIM_MLM_IDLE_STATE; + } + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); + } + break; + default: + lim_log(pMac, LOGE, + FL("DelBss is being invoked in the wrong system Role /unhandled SME State")); + + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto error; + } + return; +error: + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/* Added For BT -AMP Support */ +static void +lim_process_btamp_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tLimMlmStartCnf mlmStartCnf; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + + if (NULL == pAddBssParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + if (CDF_STATUS_SUCCESS == pAddBssParams->status) { + lim_log(pMac, LOG2, + FL("WMA_ADD_BSS_RSP returned with CDF_STATUS_SUCCESS")); + if (psessionEntry->bssType == eSIR_BTAMP_AP_MODE) { + if (lim_set_link_state + (pMac, eSIR_LINK_BTAMP_AP_STATE, + psessionEntry->bssId, psessionEntry->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) + goto end; + } else if (psessionEntry->bssType == eSIR_BTAMP_STA_MODE) { + if (lim_set_link_state + (pMac, eSIR_LINK_SCAN_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + goto end; + } + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + psessionEntry->statypeForBss = STA_ENTRY_SELF; /* to know session started for peer or for self */ + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + sch_edca_profile_update(pMac, psessionEntry); + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + } else { + lim_log(pMac, LOGE, FL("WMA_ADD_BSS_REQ failed with status %d"), + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + mlmStartCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + cdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * @function : lim_handle_add_bss_in_re_assoc_context + * @brief : While Processing the ReAssociation Response Frame in STA, + * a. immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b .If an AP rejects the ReAssociation (Disassoc / Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the DELBSS + * context only + * + * @param : pMac - tpAniSirGlobal + * pStaDs - Station Descriptor + * + * @return : none + */ +void +lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + /** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/ + /** Set the MlmState to IDLE*/ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + tSirRetStatus retStatus = eSIR_SUCCESS; + tSchBeaconStruct *pBeaconStruct; + pBeaconStruct = + cdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory in lim_handle_add_bss_in_re_assoc_context")); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto Error; + } + /* Get the AP entry from DPH hash table */ + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Fail to get STA PEER entry from hash")); + ) + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + cdf_mem_free(pBeaconStruct); + goto Error; + } + /** While Processing the ReAssoc Response Frame the ReAssocRsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + lim_extract_ap_capabilities(pMac, + (uint8_t *) psessionEntry-> + pLimReAssocReq->bssDescription. + ieFields, + lim_get_ielen_from_bss_description + (&psessionEntry-> + pLimReAssocReq-> + bssDescription), + pBeaconStruct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + pBeaconStruct, + psessionEntry); + + if (pBeaconStruct->erpPresent) { + if (pBeaconStruct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams. + fShortPreamble = 0; + else + psessionEntry->beaconParams. + fShortPreamble = 1; + } + + psessionEntry->isNonRoamReassoc = 1; + if (eSIR_SUCCESS != + lim_sta_send_add_bss(pMac, assocRsp, pBeaconStruct, + &psessionEntry->pLimReAssocReq-> + bssDescription, true, + psessionEntry)) { + lim_log(pMac, LOGE, + FL + ("Posting ADDBSS in the ReAssocContext has Failed ")); + retStatus = eSIR_FAILURE; + } + if (retStatus != eSIR_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + cdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + cdf_mem_free(pBeaconStruct); + goto Error; + } + cdf_mem_free(assocRsp); + psessionEntry->limAssocResponseData = NULL; + cdf_mem_free(pBeaconStruct); + } + break; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: { + /* Case wherein the DisAssoc / Deauth + * being sent as response to ReAssoc Req + * Send the Reason code as the same received + * in Disassoc / Deauth Frame + */ + mlmReassocCnf.resultCode = + pStaDs->mlmStaContext.disassocReason; + mlmReassocCnf.protStatusCode = + pStaDs->mlmStaContext.cleanupTrigger; + /** Set the SME State back to WT_Reassoc State*/ + psessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = + eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + } + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); + } + break; + default: + PELOGE(lim_log + (pMac, LOGE, + FL + ("DelBss is being invoked in the wrong system Role /unhandled SME State")); + ) + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto Error; + } + return; +Error: + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +void lim_send_beacon_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tBeaconGenParams *pBeaconGenParams = NULL; + tSirMsgQ limMsg; + /** Allocate the Memory for Beacon Pre Message and for Stations in PoweSave*/ + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL("Error:Unable to get the PESessionEntry")); + ) + return; + } + pBeaconGenParams = cdf_mem_malloc(sizeof(*pBeaconGenParams)); + if (NULL == pBeaconGenParams) { + PELOGE(lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during sending beaconPreMessage")); + ) + return; + } + cdf_mem_set(pBeaconGenParams, sizeof(*pBeaconGenParams), 0); + cdf_mem_copy((void *)pBeaconGenParams->bssId, + (void *)psessionEntry->bssId, CDF_MAC_ADDR_SIZE); + limMsg.bodyptr = pBeaconGenParams; + sch_process_pre_beacon_ind(pMac, &limMsg); + return; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * lim_send_sme_scan_cache_updated_ind() + * + ***FUNCTION: + * This function is used to post WMA_SME_SCAN_CACHE_UPDATED message to WMA. + * This message is the indication to WMA that all scan cache results + * are updated from LIM to SME. Mainly used only in PNO offload case. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * This function should be called after posting scan cache results to SME. + * + ***NOTE: + * NA + * + * @return None + */ +void lim_send_sme_scan_cache_updated_ind(uint8_t sessionId) +{ + cds_msg_t msg; + + msg.type = WMA_SME_SCAN_CACHE_UPDATED; + msg.reserved = 0; + msg.bodyptr = NULL; + msg.bodyval = sessionId; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SME_SCAN_CACHE_UPDATED message to WMA", + __func__); +} +#endif + +void lim_send_scan_offload_complete(tpAniSirGlobal pMac, + tSirScanOffloadEvent *pScanEvent) +{ + + pMac->lim.gLimRspReqd = false; + lim_send_sme_scan_rsp(pMac, pScanEvent->reasonCode, + pScanEvent->sessionId, 0, pScanEvent->scanId); +#ifdef FEATURE_WLAN_SCAN_PNO + lim_send_sme_scan_cache_updated_ind(pScanEvent->sessionId); +#endif +} + +void lim_process_rx_scan_event(tpAniSirGlobal pMac, void *buf) +{ + tSirScanOffloadEvent *pScanEvent = (tSirScanOffloadEvent *) buf; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + "scan_id = %u", pScanEvent->scanId); + switch (pScanEvent->event) { + case SCAN_EVENT_STARTED: + break; + case SCAN_EVENT_START_FAILED: + case SCAN_EVENT_COMPLETED: + if (P2P_SCAN_TYPE_LISTEN == pScanEvent->p2pScanType) { + lim_send_sme_roc_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + CDF_STATUS_SUCCESS, + pScanEvent->sessionId, + pScanEvent->scanId); + cdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + /* + * If remain on channel timer expired and action frame + * is pending then indicate confirmation with status + * failure. + */ + if (pMac->lim.mgmtFrameSessionId != 0xff) { + lim_send_sme_rsp(pMac, + eWNI_SME_ACTION_FRAME_SEND_CNF, + eSIR_SME_SEND_ACTION_FAIL, + pMac->lim.mgmtFrameSessionId, 0); + pMac->lim.mgmtFrameSessionId = 0xff; + } + } else { + lim_send_scan_offload_complete(pMac, pScanEvent); + } + break; + case SCAN_EVENT_FOREIGN_CHANNEL: + if (P2P_SCAN_TYPE_LISTEN == pScanEvent->p2pScanType) { + /*Send Ready on channel indication to SME */ + if (pMac->lim.gpLimRemainOnChanReq) { + lim_send_sme_roc_rsp(pMac, + eWNI_SME_REMAIN_ON_CHN_RDY_IND, + CDF_STATUS_SUCCESS, + pScanEvent->sessionId, + pScanEvent->scanId); + } else { + lim_log(pMac, LOGE, + FL("gpLimRemainOnChanReq is NULL")); + } + } + break; + case SCAN_EVENT_BSS_CHANNEL: + case SCAN_EVENT_DEQUEUED: + case SCAN_EVENT_PREEMPTED: + default: + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + "Received unhandled scan event %u", + pScanEvent->event); + } + cdf_mem_free(buf); +} diff --git a/core/mac/src/pe/lim/lim_process_probe_req_frame.c b/core/mac/src/pe/lim/lim_process_probe_req_frame.c new file mode 100644 index 0000000000..ccc87123e1 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_probe_req_frame.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_probe_req_frame.cc contains the code + * for processing Probe Request Frame. + * Author: Chandra Modumudi + * Date: 02/28/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_ser_des_utils.h" +#include "parser_api.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" + +void + +lim_send_sme_probe_req_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry); + +/** + * lim_get_wpspbc_sessions() - to get wps pbs sessions + * @mac_ctx: Pointer to Global MAC structure + * @addr: A pointer to probe request source MAC addresss + * @uuid_e: A pointer to UUIDE element of WPS IE in WPS PBC probe request + * @session: A pointer to station PE session + * + * This function is called to query the WPS PBC overlap. This function + * check WPS PBC probe request link list for PBC overlap + * + * @return None + */ + +void lim_get_wpspbc_sessions(tpAniSirGlobal mac_ctx, uint8_t *addr, + uint8_t *uuid_e, eWPSPBCOverlap *overlap, + tpPESession session) +{ + int count = 0; + tSirWPSPBCSession *pbc; + uint32_t cur_time; + + cur_time = (uint32_t) (cdf_mc_timer_get_system_ticks() / + CDF_TICKS_PER_SECOND); + cdf_mem_set((uint8_t *) addr, sizeof(tSirMacAddr), 0); + cdf_mem_set((uint8_t *) uuid_e, SIR_WPS_UUID_LEN, 0); + for (pbc = session->pAPWPSPBCSession; pbc; pbc = pbc->next) { + if (cur_time > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) + break; + count++; + if (count > 1) + break; + cdf_mem_copy((uint8_t *) addr, (uint8_t *) pbc->addr, + sizeof(tSirMacAddr)); + cdf_mem_copy((uint8_t *) uuid_e, (uint8_t *) pbc->uuid_e, + SIR_WPS_UUID_LEN); + } + if (count > 1) + /* Overlap */ + *overlap = eSAP_WPSPBC_OVERLAP_IN120S; + else if (count == 0) + /* no WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S; + else + /* One WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S; + + lim_log(mac_ctx, LOGE, FL("overlap = %d"), *overlap); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOGE, addr, + sizeof(tSirMacAddr)); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOGE, uuid_e, + SIR_WPS_UUID_LEN); + return; +} + +/** + * lim_remove_timeout_pb_csessions + * + ***FUNCTION: + * This function is called to remove the WPS PBC probe request entires from specific entry to end. + * + ***LOGIC: + * + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pbc The beginning entry in WPS PBC probe request link list + * + * @return None + */ +static void lim_remove_timeout_pb_csessions(tpAniSirGlobal pMac, + tSirWPSPBCSession *pbc) +{ + tSirWPSPBCSession *prev; + + while (pbc) { + prev = pbc; + pbc = pbc->next; + + PELOG4(lim_log(pMac, LOG4, FL("WPS PBC sessions remove"));) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, prev->addr, + sizeof(tSirMacAddr)); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, prev->uuid_e, + SIR_WPS_UUID_LEN); + ) + + cdf_mem_free(prev); + } +} + +void lim_remove_pbc_sessions(tpAniSirGlobal pMac, tSirMacAddr pRemoveMac, + tpPESession psessionEntry) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + prev = pbc = psessionEntry->pAPWPSPBCSession; + + while (pbc) { + if (cdf_mem_compare((uint8_t *) pbc->addr, + (uint8_t *) pRemoveMac, + sizeof(tSirMacAddr))) { + prev->next = pbc->next; + if (pbc == psessionEntry->pAPWPSPBCSession) + psessionEntry->pAPWPSPBCSession = pbc->next; + cdf_mem_free(pbc); + return; + } + prev = pbc; + pbc = pbc->next; + } + +} + +/** + * lim_update_pbc_session_entry + * + ***FUNCTION: + * This function is called when probe request with WPS PBC IE is received + * + ***LOGIC: + * This function add the WPS PBC probe request in the WPS PBC probe request link list + * The link list is in decreased time order of probe request that is received. + * The entry that is more than 120 second is removed. + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param addr A pointer to probe request source MAC addresss + * @param uuid_e A pointer to UUIDE element of WPS IE + * @param psessionEntry A pointer to station PE session + * + * @return None + */ + +static void lim_update_pbc_session_entry(tpAniSirGlobal pMac, + uint8_t *addr, uint8_t *uuid_e, + tpPESession psessionEntry) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + + uint32_t curTime; + + curTime = + (uint32_t) (cdf_mc_timer_get_system_ticks() / + CDF_TICKS_PER_SECOND); + + PELOG4(lim_log + (pMac, LOG4, FL("Receive WPS probe reques curTime=%d"), curTime); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, addr, sizeof(tSirMacAddr)); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, uuid_e, SIR_WPS_UUID_LEN); + ) + + pbc = psessionEntry->pAPWPSPBCSession; + + while (pbc) { + if (cdf_mem_compare + ((uint8_t *) pbc->addr, (uint8_t *) addr, + sizeof(tSirMacAddr)) + && cdf_mem_compare((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN)) { + if (prev) + prev->next = pbc->next; + else + psessionEntry->pAPWPSPBCSession = pbc->next; + break; + } + prev = pbc; + pbc = pbc->next; + } + + if (!pbc) { + pbc = cdf_mem_malloc(sizeof(tSirWPSPBCSession)); + if (NULL == pbc) { + PELOGE(lim_log + (pMac, LOGE, FL("memory allocate failed!")); + ) + return; + } + cdf_mem_copy((uint8_t *) pbc->addr, (uint8_t *) addr, + sizeof(tSirMacAddr)); + + if (uuid_e) + cdf_mem_copy((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN); + } + + pbc->next = psessionEntry->pAPWPSPBCSession; + psessionEntry->pAPWPSPBCSession = pbc; + pbc->timestamp = curTime; + + /* remove entries that have timed out */ + prev = pbc; + pbc = pbc->next; + + while (pbc) { + if (curTime > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) { + prev->next = NULL; + lim_remove_timeout_pb_csessions(pMac, pbc); + break; + } + prev = pbc; + pbc = pbc->next; + } +} + +/** + * lim_wpspbc_close + * + ***FUNCTION: + * This function is called when BSS is closed + * + ***LOGIC: + * This function remove all the WPS PBC entries + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param psessionEntry A pointer to station PE session + * + * @return None + */ + +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + lim_remove_timeout_pb_csessions(pMac, psessionEntry->pAPWPSPBCSession); + +} + +/** + * lim_check11b_rates + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function check 11b rates in supportedRates and extendedRates rates + * + ***NOTE: + * + * @param rate + * + * @return BOOLEAN + */ + +bool lim_check11b_rates(uint8_t rate) +{ + if ((0x02 == (rate)) + || (0x04 == (rate)) + || (0x0b == (rate)) + || (0x16 == (rate)) + ) { + return true; + } + return false; +} + +/** + * lim_process_probe_req_frame: to process probe req frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to Buffer descriptor + associated PDUs + * @session: a ponter to session entry + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function processes received + * Probe Request frame and responds with Probe Response. + * Only AP or STA in IBSS mode that sent last Beacon will respond to + * Probe Request. + * ASSUMPTIONS: + * 1. AP or STA in IBSS mode that sent last Beacon will always respond + * to Probe Request received with broadcast SSID. + * NOTE: + * 1. Dunno what to do with Rates received in Probe Request frame + * 2. Frames with out-of-order fields/IEs are dropped. + * + * + * Return: none + */ + +void +lim_process_probe_req_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + uint8_t *body_ptr; + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + tSirProbeReq probe_req; + tAniSSID ssid; + + /* Don't send probe responses if disabled */ + if (mac_ctx->lim.gLimProbeRespDisableFlag) + return; + + /* + * Don't send probe response if P2P go is scanning till scan + * come to idle state. + */ + if ((session->pePersona == CDF_P2P_GO_MODE) && + ((mac_ctx->lim.gpLimRemainOnChanReq) || + (mac_ctx->lim.gLimHalScanState != eLIM_HAL_IDLE_SCAN_STATE))) { + lim_log(mac_ctx, LOG3, + FL("GO is scanning, don't send probersp on diff chnl")); + return; + } + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (LIM_IS_AP_ROLE(session) || + LIM_IS_BT_AMP_AP_ROLE(session) || + LIM_IS_BT_AMP_STA_ROLE(session) || + (LIM_IS_IBSS_ROLE(session) && + (WMA_GET_RX_BEACON_SENT(rx_pkt_info)))) { + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG3, + FL("Received Probe Request %d bytes from "), + frame_len); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + /* Get pointer to Probe Request frame body */ + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Parse Probe Request frame */ + if (sir_convert_probe_req_frame2_struct(mac_ctx, body_ptr, + frame_len, &probe_req) == eSIR_FAILURE) { + lim_log(mac_ctx, LOGE, + FL("Parse error ProbeReq, length=%d, SA is: " + MAC_ADDRESS_STR), frame_len, + MAC_ADDR_ARRAY(mac_hdr->sa)); + mac_ctx->sys.probeError++; + return; + } + if (session->pePersona == CDF_P2P_GO_MODE) { + uint8_t i = 0, rate_11b = 0, other_rates = 0; + /* Check 11b rates in supported rates */ + for (i = 0; i < probe_req.supportedRates.numRates; + i++) { + if (lim_check11b_rates( + probe_req.supportedRates.rate[i] & + 0x7f)) + rate_11b++; + else + other_rates++; + } + + /* Check 11b rates in extended rates */ + for (i = 0; i < probe_req.extendedRates.numRates; i++) { + if (lim_check11b_rates( + probe_req.extendedRates.rate[i] & 0x7f)) + rate_11b++; + else + other_rates++; + } + + if ((rate_11b > 0) && (other_rates == 0)) { + lim_log(mac_ctx, LOG3, + FL("Received a probe req frame with only 11b rates, SA is: ")); + lim_print_mac_addr(mac_ctx, + mac_hdr->sa, LOG3); + return; + } + } + if (LIM_IS_AP_ROLE(session) && + ((session->APWPSIEs.SirWPSProbeRspIE.FieldPresent + & SIR_WPS_PROBRSP_VER_PRESENT) + && (probe_req.wscIePresent == 1) + && (probe_req.probeReqWscIeInfo.DevicePasswordID.id == + WSC_PASSWD_ID_PUSH_BUTTON) + && (probe_req.probeReqWscIeInfo.UUID_E.present == 1))) { + if (session->fwdWPSPBCProbeReq) { + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, + LOG4, mac_hdr->sa, sizeof(tSirMacAddr)); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, + LOG4, body_ptr, frame_len); + lim_send_sme_probe_req_ind(mac_ctx, mac_hdr->sa, + body_ptr, frame_len, session); + } else { + lim_update_pbc_session_entry(mac_ctx, + mac_hdr->sa, + probe_req.probeReqWscIeInfo.UUID_E.uuid, + session); + } + } + ssid.length = session->ssId.length; + /* Copy the SSID from sessio entry to local variable */ + cdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + + /* + * Compare received SSID with current SSID. If they match, + * reply with Probe Response + */ + if (probe_req.ssId.length) { + if (!ssid.length) + goto multipleSSIDcheck; + + if (cdf_mem_compare((uint8_t *) &ssid, + (uint8_t *) &(probe_req.ssId), + (uint8_t) (ssid.length + 1))) { + lim_send_probe_rsp_mgmt_frame(mac_ctx, + mac_hdr->sa, &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } else if (session->pePersona == + CDF_P2P_GO_MODE) { + uint8_t direct_ssid[7] = "DIRECT-"; + uint8_t direct_ssid_len = 7; + if (cdf_mem_compare((uint8_t *) &direct_ssid, + (uint8_t *) &(probe_req.ssId.ssId), + (uint8_t) (direct_ssid_len))) { + lim_send_probe_rsp_mgmt_frame(mac_ctx, + mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } + } else { + lim_log(mac_ctx, LOG3, + FL("Ignore ProbeReq frm with unmatch SSID received from ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, + LOG3); + mac_ctx->sys.probeBadSsid++; + } + } else { + /* + * Broadcast SSID in the Probe Request. + * Reply with SSID we're configured with. + * Turn off the SSID length to 0 if hidden SSID feature + * is present + */ + if (session->ssidHidden) + /* + * We are returning from here as probe request + * contains the broadcast SSID. So no need to + * send the probe resp + */ + return; + lim_send_probe_rsp_mgmt_frame(mac_ctx, mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } +multipleSSIDcheck: + lim_log(mac_ctx, LOG3, + FL("Ignore ProbeReq frm with unmatch SSID rcved from")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + mac_ctx->sys.probeBadSsid++; + } else { + /* Ignore received Probe Request frame */ + lim_log(mac_ctx, LOG3, + FL("Ignoring Probe Request frame received from ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + mac_ctx->sys.probeIgnore++; + } + return; +} + +/** + * lim_indicate_probe_req_to_hdd + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame_multiple_bss() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function processes received Probe Request frame and Pass + * Probe Request Frame to HDD. + * + * @param pMac Pointer to Global MAC structure + * @param *pBd A pointer to Buffer descriptor + associated PDUs + * @param psessionEntry A pointer to PE session + * + * @return None + */ + +static void +lim_indicate_probe_req_to_hdd(tpAniSirGlobal pMac, uint8_t *pBd, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + + lim_log(pMac, LOG1, "Received a probe request frame"); + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + /* send the probe req to SME. */ + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, WMA_GET_RX_CH(pBd), + psessionEntry, 0); +} /*** end lim_indicate_probe_req_to_hdd() ***/ + +/** + * lim_process_probe_req_frame_multiple_bss() - to process probe req + * @mac_ctx: Pointer to Global MAC structure + * @buf_descr: A pointer to Buffer descriptor + associated PDUs + * @session: A pointer to PE session + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function call + * lim_indicate_probe_req_to_hdd function to indicate + * Probe Request frame to HDD. It also call lim_process_probe_req_frame + * function which process received Probe Request frame and responds + * with Probe Response. + * + * @return None + */ +void +lim_process_probe_req_frame_multiple_bss(tpAniSirGlobal mac_ctx, + uint8_t *buf_descr, tpPESession session) +{ + uint8_t i; + + if (session != NULL) { + if (LIM_IS_AP_ROLE(session)) { + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + } + lim_process_probe_req_frame(mac_ctx, buf_descr, session); + return; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session = pe_find_session_by_session_id(mac_ctx, i); + if (session == NULL) + continue; + if (LIM_IS_AP_ROLE(session)) + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + if (LIM_IS_AP_ROLE(session) || + LIM_IS_IBSS_ROLE(session) || + LIM_IS_BT_AMP_AP_ROLE(session) || + LIM_IS_BT_AMP_STA_ROLE(session)) + lim_process_probe_req_frame(mac_ctx, + buf_descr, session); + } +} + +/** + * lim_send_sme_probe_req_ind() + * + ***FUNCTION: + * This function is to send + * eWNI_SME_WPS_PBC_PROBE_REQ_IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_WPS_PBC_PROBE_REQ_IND + * to host. + * + * @param peerMacAddr Indicates the peer MAC addr that the probe request + * is generated. + * @param pProbeReqIE pointer to RAW probe request IE + * @param ProbeReqIELen The length of probe request IE. + * @param psessionEntry A pointer to PE session + * + * @return None + */ +void +lim_send_sme_probe_req_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry) +{ + tSirSmeProbeReqInd *pSirSmeProbeReqInd; + tSirMsgQ msgQ; + + pSirSmeProbeReqInd = cdf_mem_malloc(sizeof(tSirSmeProbeReqInd)); + if (NULL == pSirSmeProbeReqInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_PROBE_REQ_IND")); + return; + } + + msgQ.type = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + msgQ.bodyval = 0; + msgQ.bodyptr = pSirSmeProbeReqInd; + + pSirSmeProbeReqInd->messageType = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + pSirSmeProbeReqInd->length = sizeof(tSirSmeProbeReq); + pSirSmeProbeReqInd->sessionId = psessionEntry->smeSessionId; + + cdf_mem_copy(pSirSmeProbeReqInd->bssId, psessionEntry->bssId, + sizeof(tSirMacAddr)); + cdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.peerMacAddr, + peerMacAddr, sizeof(tSirMacAddr)); + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIELen = + (uint16_t) ProbeReqIELen; + cdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE, pProbeReqIE, + ProbeReqIELen); + + if (lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("couldnt send the probe req to hdd")); + ) + } + +} /*** end lim_send_sme_probe_req_ind() ***/ diff --git a/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c b/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c new file mode 100644 index 0000000000..d3df1d31eb --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_probe_rsp_frame.cc contains the code + * for processing Probe Response Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" + +#include "parser_api.h" + +tSirRetStatus lim_validate_ie_information_in_probe_rsp_frame(uint8_t *pRxPacketInfo) +{ + tSirRetStatus status = eSIR_SUCCESS; + + if (WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) < + (SIR_MAC_B_PR_SSID_OFFSET + SIR_MAC_MIN_IE_LEN)) { + status = eSIR_FAILURE; + } + + return status; +} + +/** + * lim_process_probe_rsp_frame() - processes received Probe Response frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_Packet_info: A pointer to Buffer descriptor + associated PDUs + * @session_entry: Handle to the session. + * + * This function processes received Probe Response frame. + * Frames with out-of-order IEs are dropped. + * In case of IBSS, join 'success' makes MLM state machine + * transition into 'BSS started' state. This may have to change + * depending on supporting what kinda Authentication in IBSS. + * + * Return: None + */ +void +lim_process_probe_rsp_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_Packet_info, + tpPESession session_entry) +{ + uint8_t *body; + uint32_t frame_len = 0; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + uint8_t qos_enabled = false; + uint8_t wme_enabled = false; + + if (!session_entry) { + lim_log(mac_ctx, LOGE, FL("session_entry is NULL")); + return; + } + lim_log(mac_ctx, LOG1, "SessionId:%d ProbeRsp Frame is received", + session_entry->peSessionId); + + probe_rsp = cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == probe_rsp) { + lim_log(mac_ctx, LOGE, + FL + ("Unable to allocate memory ")); + return; + } + + probe_rsp->ssId.length = 0; + probe_rsp->wpa.length = 0; + + header = WMA_GET_RX_MAC_HEADER(rx_Packet_info); + + lim_log(mac_ctx, LOG2, + FL("Rx Probe Response with length = %d from "MAC_ADDRESS_STR), + WMA_GET_RX_MPDU_LEN(rx_Packet_info), + MAC_ADDR_ARRAY(header->sa)); + + /* Validate IE information before processing Probe Response Frame */ + if (lim_validate_ie_information_in_probe_rsp_frame(rx_Packet_info) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + cdf_mem_free(probe_rsp); + return; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Probe Resp Frame Received: BSSID " + MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(header->bssId), + (uint) abs((int8_t)WMA_GET_RX_RSSI_DB(rx_Packet_info))); + /* Get pointer to Probe Response frame body */ + body = WMA_GET_RX_MPDU_DATA(rx_Packet_info); + /* Enforce Mandatory IEs */ + if ((sir_convert_probe_frame2_struct(mac_ctx, + body, frame_len, probe_rsp) == eSIR_FAILURE) || + !probe_rsp->ssidPresent) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + cdf_mem_free(probe_rsp); + return; + } + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_Packet_info, false, true); + /* To Support BT-AMP */ + if ((mac_ctx->lim.gLimMlmState == + eLIM_MLM_WT_PROBE_RESP_STATE) || + (mac_ctx->lim.gLimMlmState == + eLIM_MLM_PASSIVE_SCAN_STATE)) { + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_Packet_info, ((mac_ctx->lim. + gLimHalScanState == eLIM_HAL_SCANNING_STATE) + ? true : false), true); + } else if (session_entry->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* + * Either Beacon/probe response is required. + * Hence store it in same buffer. + */ + if (session_entry->beacon != NULL) { + cdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + } + session_entry->bcnLen = + WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + session_entry->beacon = + cdf_mem_malloc(session_entry->bcnLen); + if (NULL == session_entry->beacon) { + lim_log(mac_ctx, LOGE, + FL("No Memory to store beacon")); + } else { + /* + * Store the Beacon/ProbeRsp. + * This is sent to csr/hdd in join cnf response. + */ + cdf_mem_copy(session_entry->beacon, + WMA_GET_RX_MPDU_DATA + (rx_Packet_info), + session_entry->bcnLen); + } + /* STA in WT_JOIN_BEACON_STATE */ + lim_check_and_announce_join_success(mac_ctx, probe_rsp, + header, + session_entry); + } else if (session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) { + tpDphHashNode sta_ds = NULL; + /* + * Check if this Probe Response is for + * our Probe Request sent upon reaching + * heart beat threshold + */ + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (!cdf_mem_compare(current_bssid, header->bssId, + sizeof(tSirMacAddr))) { + cdf_mem_free(probe_rsp); + return; + } + if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) { + lim_log(mac_ctx, LOGW, + FL("Recved Probe Resp from AP,AP-alive")); + if (probe_rsp->HTInfo.present) + lim_received_hb_handler(mac_ctx, + probe_rsp->HTInfo.primaryChannel, + session_entry); + else + lim_received_hb_handler(mac_ctx, + (uint8_t)probe_rsp->channelNumber, + session_entry); + } + if (LIM_IS_STA_ROLE(session_entry)) { + if (probe_rsp->channelSwitchPresent) { + lim_update_channel_switch(mac_ctx, + probe_rsp, + session_entry); + } else if (session_entry->gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch( + mac_ctx, session_entry); + } + } + /* + * Now Process EDCA Parameters, if EDCAParamSet + * count is different. + * -- While processing beacons in link established + * state if it is determined that + * QoS Info IE has a different count for EDCA Params, + * and EDCA IE is not present in beacon, + * then probe req is sent out to get the EDCA params. + */ + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + limGetQosMode(session_entry, &qos_enabled); + limGetWmeMode(session_entry, &wme_enabled); + lim_log(mac_ctx, LOG2, + FL("wmeEdcaPresent: %d wme_enabled: %d"), + probe_rsp->wmeEdcaPresent, wme_enabled); + lim_log(mac_ctx, LOG2, + FL("edcaPresent: %d, qos_enabled: %d"), + probe_rsp->edcaPresent, qos_enabled); + lim_log(mac_ctx, LOG2, + FL("edcaParams.qosInfo.count: %d"), + probe_rsp->edcaParams.qosInfo.count); + lim_log(mac_ctx, LOG2, + FL("schObject.gLimEdcaParamSetCount: %d"), + session_entry->gLimEdcaParamSetCount); + if (((probe_rsp->wmeEdcaPresent && wme_enabled) || + (probe_rsp->edcaPresent && qos_enabled)) && + (probe_rsp->edcaParams.qosInfo.count != + session_entry->gLimEdcaParamSetCount)) { + if (sch_beacon_edca_process(mac_ctx, + &probe_rsp->edcaParams, + session_entry) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("EDCA param process error")); + } else if (sta_ds != NULL) { + /* + * If needed, downgrade the + * EDCA parameters + */ + lim_set_active_edca_params(mac_ctx, + session_entry-> + gLimEdcaParams, + session_entry); + lim_send_edca_params(mac_ctx, + session_entry-> + gLimEdcaParamsActive, + sta_ds->bssId); + } else { + lim_log(mac_ctx, LOGE, + FL("SelfEntry missing in Hash")); + } + } + if (session_entry->fWaitForProbeRsp == true) { + lim_log(mac_ctx, LOGW, + FL("Check probe resp for caps change")); + lim_detect_change_in_ap_capabilities( + mac_ctx, probe_rsp, session_entry); + } + } else { + if (LIM_IS_IBSS_ROLE(session_entry) && + (session_entry->limMlmState == + eLIM_MLM_BSS_STARTED_STATE)) + lim_handle_ibss_coalescing(mac_ctx, probe_rsp, + rx_Packet_info, session_entry); + } + cdf_mem_free(probe_rsp); + + /* Ignore Probe Response frame in all other states */ + return; +} + +/** + * lim_process_probe_rsp_frame_no_session() - process Probe Response frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info: A pointer to Buffer descriptor + associated PDUs + * + * This function processes received Probe Response frame with no session. + * + * Return: None + */ +void +lim_process_probe_rsp_frame_no_session(tpAniSirGlobal mac_ctx, + uint8_t *rx_packet_info) +{ + uint8_t *body; + uint32_t frame_len = 0; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + + probe_rsp = cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == probe_rsp) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + + probe_rsp->ssId.length = 0; + probe_rsp->wpa.length = 0; + + header = WMA_GET_RX_MAC_HEADER(rx_packet_info); + + lim_log(mac_ctx, LOG2, + FL("Received Probe Response frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(rx_packet_info)); + lim_print_mac_addr(mac_ctx, header->sa, LOG2); + + /* Validate IE information before processing Probe Response Frame */ + if (lim_validate_ie_information_in_probe_rsp_frame(rx_packet_info) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + cdf_mem_free(probe_rsp); + return; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Probe Resp Frame Received: BSSID " + MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(header->bssId), + (uint) abs((int8_t)WMA_GET_RX_RSSI_DB(rx_packet_info))); + /* + * Get pointer to Probe Response frame body + */ + body = WMA_GET_RX_MPDU_DATA(rx_packet_info); + if (sir_convert_probe_frame2_struct(mac_ctx, body, frame_len, + probe_rsp) == eSIR_FAILURE) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d\n"), + frame_len); + cdf_mem_free(probe_rsp); + return; + } + lim_log(mac_ctx, LOG2, FL("Save this probe rsp in LFR cache")); + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_packet_info, false, true); + cdf_mem_free(probe_rsp); + return; +} diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c new file mode 100644 index 0000000000..0db6d07bfc --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -0,0 +1,5690 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_sme_req_messages.cc contains the code + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sme_req_utils.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_admit_control.h" +#include "dph_hash_table.h" +#include "lim_send_messages.h" +#include "lim_api.h" +#include "wmm_apsd.h" +#include "sir_mac_prot_def.h" + +#include "sap_api.h" + +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R +#include +#endif + +/* + * This overhead is time for sending NOA start to host in case of GO/sending + * NULL data & receiving ACK in case of P2P Client and starting actual scanning + * with init scan req/rsp plus in case of concurrency, taking care of sending + * null data and receiving ACK to/from AP/Also SetChannel with calibration + * is taking around 7ms . + */ +#define SCAN_MESSAGING_OVERHEAD 20 /* in msecs */ +#define JOIN_NOA_DURATION 2000 /* in msecs */ +#define OEM_DATA_NOA_DURATION 60 /* in msecs */ +#define DEFAULT_PASSIVE_MAX_CHANNEL_TIME 110 /* in msecs */ + +#define CONV_MS_TO_US 1024 /* conversion factor from ms to us */ + +/* SME REQ processing function templates */ +static bool __lim_process_sme_sys_ready_ind(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal, tpSirMsgQ pMsg); +static void __lim_process_sme_scan_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_join_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_reassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_deauth_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_set_context_req(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal, tpSirMsgQ pMsg); +static void lim_process_sme_channel_change_request(tpAniSirGlobal pMac, + uint32_t *pMsg); +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_sme_dfs_csa_ie_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_nss_update_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_set_ie_req(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_start_bss_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, + uint16_t srcDataLen); + +static void lim_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen); + +static void lim_process_modify_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_process_update_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +extern void pe_register_wma_handle(tpAniSirGlobal pMac); + +/** + * lim_process_set_hw_mode() - Send set HW mode command to WMA + * @mac: Globacl MAC pointer + * @msg: Message containing the hw mode index + * + * Send the set HW mode command to WMA + * + * Return: CDF_STATUS_SUCCESS if message posting is successful + */ +static CDF_STATUS lim_process_set_hw_mode(tpAniSirGlobal mac, uint32_t *msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t cds_message; + struct sir_hw_mode *req_msg; + uint32_t len; + struct s_sir_set_hw_mode *buf; + tSirMsgQ resp_msg; + struct sir_set_hw_mode_resp *param; + + buf = (struct s_sir_set_hw_mode *) msg; + if (!buf) { + lim_log(mac, LOGE, FL("Set HW mode param is NULL")); + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + lim_log(mac, LOGE, FL("cdf_mem_malloc failed")); + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + + req_msg->hw_mode_index = buf->set_hw.hw_mode_index; + /* Other parameters are not needed for WMA */ + + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_SOC_SET_HW_MODE; + + lim_log(mac, LOG1, FL("Posting SIR_HAL_SOC_SET_HW_MOD to WMA")); + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("HW mode resp failed")); + return CDF_STATUS_E_FAILURE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + resp_msg.type = eWNI_SME_SET_HW_MODE_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg, ePROT); + return CDF_STATUS_SUCCESS; +} + +/** + * lim_process_set_dual_mac_cfg_req() - Set dual mac config command to WMA + * @mac: Global MAC pointer + * @msg: Message containing the dual mac config parameter + * + * Send the set dual mac config command to WMA + * + * Return: CDF_STATUS_SUCCESS if message posting is successful + */ +static CDF_STATUS lim_process_set_dual_mac_cfg_req(tpAniSirGlobal mac, + uint32_t *msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t cds_message; + struct sir_dual_mac_config *req_msg; + uint32_t len; + struct sir_set_dual_mac_cfg *buf; + tSirMsgQ resp_msg; + struct sir_dual_mac_config_resp *param; + + buf = (struct sir_set_dual_mac_cfg *) msg; + if (!buf) { + lim_log(mac, LOGE, FL("Set Dual mac config is NULL")); + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + lim_log(mac, LOGE, FL("vos_mem_malloc failed")); + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + + req_msg->scan_config = buf->set_dual_mac.scan_config; + req_msg->fw_mode_config = buf->set_dual_mac.fw_mode_config; + /* Other parameters are not needed for WMA */ + + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_SOC_DUAL_MAC_CFG_REQ; + + lim_log(mac, LOG1, + FL("Post SIR_HAL_SOC_DUAL_MAC_CFG_REQ to WMA: %x %x"), + req_msg->scan_config, req_msg->fw_mode_config); + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("Dual mac config resp failed")); + return CDF_STATUS_E_FAILURE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + resp_msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg, ePROT); + return CDF_STATUS_SUCCESS; +} + +/** + * __lim_fresh_scan_reqd() - determine if a fresh scan request must be issued. + * @mac_ctx: Pointer to Global MAC structure + * @return_fresh_results: Trigger fresh scan. + * + * PE will do fresh scan, if all of the active sessions are in + * good state (Link Est or BSS Started). If one of the sessions + * is not in one of the above states, then PE does not do fresh + * scan. If no session exists (scanning very first time), + * then PE will always do fresh scan if SME asks it to do that. + * + * Return: true for fresh scan results, false if in invalid state. + */ +static uint8_t +__lim_fresh_scan_reqd(tpAniSirGlobal mac_ctx, uint8_t return_fresh_results) +{ + uint8_t valid_state = true; + int i; + + lim_log(mac_ctx, LOG1, FL("gLimSmeState: %d, returnFreshResults 0x%x"), + mac_ctx->lim.gLimSmeState, return_fresh_results); + + if (mac_ctx->lim.gLimSmeState != eLIM_SME_IDLE_STATE) { + lim_log(mac_ctx, LOG1, FL("return FALSE")); + return false; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + lim_log(mac_ctx, LOG1, + FL("session %d, bsstype %d, limSystemRole %d, limSmeState %d"), + i, mac_ctx->lim.gpSession[i].bssType, + mac_ctx->lim.gpSession[i].limSystemRole, + mac_ctx->lim.gpSession[i].limSmeState); + if (mac_ctx->lim.gpSession[i].valid == true) { + if (!((((mac_ctx->lim.gpSession[i].bssType == + eSIR_INFRASTRUCTURE_MODE) || + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_STA_ROLE)) && + (mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_LINK_EST_STATE)) || + (((mac_ctx->lim.gpSession[i].bssType == + eSIR_IBSS_MODE) || + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_AP_ROLE) || + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_STA_ROLE)) && + (mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_NORMAL_STATE)) || + ((((mac_ctx->lim.gpSession[i].bssType == + eSIR_INFRA_AP_MODE) && + (mac_ctx->lim.gpSession[i].pePersona == + CDF_P2P_GO_MODE)) || + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_AP_ROLE)) && + (mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_NORMAL_STATE)))) { + valid_state = false; + break; + } + } + } + + lim_log(mac_ctx, LOG1, FL("valid_state: %d"), valid_state); + + if ((valid_state) && + (return_fresh_results & SIR_BG_SCAN_RETURN_FRESH_RESULTS)) + return true; + else + return false; +} + +/** + * __lim_is_sme_assoc_cnf_valid() + * + ***FUNCTION: + * This function is called by __lim_process_sme_assoc_cnf_new() upon + * receiving SME_ASSOC_CNF. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMeasReq Pointer to Received ASSOC_CNF message + * @return true When received SME_ASSOC_CNF is formatted + * correctly + * false otherwise + */ + +static inline uint8_t __lim_is_sme_assoc_cnf_valid(tpSirSmeAssocCnf pAssocCnf) +{ + if (lim_is_group_addr(pAssocCnf->peerMacAddr)) + return false; + else + return true; +} /*** end __lim_is_sme_assoc_cnf_valid() ***/ + +/** + * __lim_get_sme_join_req_size_for_alloc() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from tSirBssDescription structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static uint16_t __lim_get_sme_join_req_size_for_alloc(uint8_t *pBuf) +{ + uint16_t len = 0; + + if (!pBuf) + return len; + + pBuf += sizeof(uint16_t); + len = lim_get_u16(pBuf); + return len + sizeof(uint16_t); +} + +/** + * __lim_is_defered_msg_for_learn() - message handling in SME learn state + * @pMac: Global MAC context + * @pMsg: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if SME is in learn state and brings + * the LIM back to normal mode. + * + * Return: true - If defered false - Otherwise + */ + +static bool __lim_is_defered_msg_for_learn(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (lim_is_system_in_scan_state(pMac)) { + if (lim_defer_msg(pMac, pMsg) != TX_SUCCESS) { + lim_log(pMac, LOGE, FL("Could not defer Msg = %d"), + pMsg->type); + return false; + } + lim_log(pMac, LOG1, + FL("Defer the message, in learn mode type = %d"), + pMsg->type); + return true; + } + return false; +} + +/** + * __lim_is_defered_msg_for_radar() - Defers the message if radar is detected + * @mac_ctx: Pointer to Global MAC structure + * @message: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if radar is detected. + * + * Return: true, if defered otherwise return false. + */ +static bool +__lim_is_defered_msg_for_radar(tpAniSirGlobal mac_ctx, tpSirMsgQ message) +{ + /* + * fRadarDetCurOperChan will be set only if we + * detect radar in current operating channel and + * System Role == AP ROLE + * + * TODO: Need to take care radar detection. + * + * if (LIM_IS_RADAR_DETECTED(mac_ctx)) + */ + if (0) { + if (lim_defer_msg(mac_ctx, message) != TX_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("Could not defer Msg = %d"), + message->type); + return false; + } + lim_log(mac_ctx, LOG1, + FL("Defer the message, in learn mode type = %d"), + message->type); + return true; + } + return false; +} + +/** + * __lim_process_sme_sys_ready_ind () - Process ready indication from WMA + * @pMac: Global MAC context + * @pMsgBuf: Message from WMA + * + * handles the notification from HDD. PE just forwards this message to HAL. + * + * Return: true-Posting to HAL failed, so PE will consume the buffer. + * false-Posting to HAL successful, so HAL will consume the buffer. + */ + +static bool __lim_process_sme_sys_ready_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + tSirSmeReadyReq *ready_req = (tSirSmeReadyReq *) pMsgBuf; + + msg.type = WMA_SYS_READY_IND; + msg.reserved = 0; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + + if (ANI_DRIVER_TYPE(pMac) != eDRIVER_TYPE_MFG) { + pe_register_wma_handle(pMac); + pMac->lim.add_bssdescr_callback = ready_req->add_bssdescr_cb; + } + PELOGW(lim_log(pMac, LOGW, FL("sending WMA_SYS_READY_IND msg to HAL"));) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + return true; + } + return false; +} + +#ifdef WLAN_FEATURE_11AC + +uint32_t lim_get_center_channel(tpAniSirGlobal pMac, uint8_t primarychanNum, + ePhyChanBondState secondaryChanOffset, + uint8_t chanWidth) +{ + if (chanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + switch (secondaryChanOffset) { + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + return primarychanNum; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + return primarychanNum + 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + return primarychanNum - 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + return primarychanNum + 6; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + return primarychanNum + 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + return primarychanNum - 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + return primarychanNum - 6; + default: + return eSIR_CFG_INVALID_ID; + } + } else if (chanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { + switch (secondaryChanOffset) { + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + return primarychanNum + 2; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + return primarychanNum - 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + return primarychanNum; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + return primarychanNum + 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + return primarychanNum - 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + return primarychanNum + 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + return primarychanNum - 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + return primarychanNum + 2; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + return primarychanNum - 2; + default: + return eSIR_CFG_INVALID_ID; + } + } + return primarychanNum; +} + +#endif + +/** + *lim_configure_ap_start_bss_session() - Configure the AP Start BSS in session. + *@mac_ctx: Pointer to Global MAC structure + *@session: A pointer to session entry + *@sme_start_bss_req: Start BSS Request from upper layers. + * + * This function is used to configure the start bss parameters + * in to the session. + * + * Return: None. + */ +static void +lim_configure_ap_start_bss_session(tpAniSirGlobal mac_ctx, tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req) +{ + session->limSystemRole = eLIM_AP_ROLE; + session->privacy = sme_start_bss_req->privacy; + session->fwdWPSPBCProbeReq = sme_start_bss_req->fwdWPSPBCProbeReq; + session->authType = sme_start_bss_req->authType; + /* Store the DTIM period */ + session->dtimPeriod = (uint8_t) sme_start_bss_req->dtimPeriod; + /* Enable/disable UAPSD */ + session->apUapsdEnable = sme_start_bss_req->apUapsdEnable; + if (session->pePersona == CDF_P2P_GO_MODE) { + session->proxyProbeRspEn = 0; + } else { + /* + * To detect PBC overlap in SAP WPS mode, + * Host handles Probe Requests. + */ + if (SAP_WPS_DISABLED == sme_start_bss_req->wps_state) + session->proxyProbeRspEn = 1; + else + session->proxyProbeRspEn = 0; + } + session->ssidHidden = sme_start_bss_req->ssidHidden; + session->wps_state = sme_start_bss_req->wps_state; + session->sap_dot11mc = sme_start_bss_req->sap_dot11mc; + lim_get_short_slot_from_phy_mode(mac_ctx, session, session->gLimPhyMode, + &session->shortSlotTimeSupported); + session->isCoalesingInIBSSAllowed = + sme_start_bss_req->isCoalesingInIBSSAllowed; + +} + +/** + * __lim_handle_sme_start_bss_request() - process SME_START_BSS_REQ message + *@mac_ctx: Pointer to Global MAC structure + *@msg_buf: A pointer to the SME message buffer + * + * This function is called to process SME_START_BSS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t size; + uint32_t val = 0; + tSirRetStatus ret_status; + tSirMacChanNum channel_number; + tLimMlmStartReq *mlm_start_req = NULL; + tpSirSmeStartBssReq sme_start_bss_req = NULL; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + /* Flag Used in case of IBSS to Auto generate BSSID. */ + uint32_t auto_gen_bssid = false; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id = 0; + uint16_t sme_transaction_id = 0; + uint32_t chanwidth; + tSirRetStatus cfg_get_wmi_dfs_master_param = eSIR_SUCCESS; + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Since the session is not created yet, sending NULL. + * The response should have the correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_START_BSS_REQ_EVENT, + NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_log(mac_ctx, LOG1, FL("Received START_BSS_REQ")); + + /* + * Global Sme state and mlm states are not defined yet, + * for BT-AMP Suppoprt . TO BE DONE + */ + if ((mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) || + (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE)) { + size = sizeof(tSirSmeStartBssReq); + + sme_start_bss_req = cdf_mem_malloc(size); + if (NULL == sme_start_bss_req) { + lim_log(mac_ctx, LOGE, + FL("Allocate Memory fail for LimStartBssReq")); + /* Send failure response to host */ + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + cdf_mem_set((void *)sme_start_bss_req, size, 0); + cdf_mem_copy(sme_start_bss_req, msg_buf, + sizeof(tSirSmeStartBssReq)); + if (!lim_is_sme_start_bss_req_valid(mac_ctx, + sme_start_bss_req)) { + lim_log(mac_ctx, LOGW, + FL("Received invalid eWNI_SME_START_BSS_REQ")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + + /* + * This is the place where PE is going to create a session. + * If session is not existed, then create a new session + */ + session = pe_find_session_by_bssid(mac_ctx, + sme_start_bss_req->bssId, &session_id); + if (session != NULL) { + lim_log(mac_ctx, LOGW, + FL("Session Already exists for given BSSID")); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + session = NULL; + goto free; + } else { + session = pe_create_session(mac_ctx, + sme_start_bss_req->bssId, + &session_id, mac_ctx->lim.maxStation, + sme_start_bss_req->bssType); + if (session == NULL) { + lim_log(mac_ctx, LOGW, + FL("Session Can not be created ")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + } + + /* Probe resp add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespData_buff, + &session->addIeParams.probeRespDataLen, + sme_start_bss_req->addIeParams.probeRespData_buff, + sme_start_bss_req->addIeParams.probeRespDataLen); + + /* Probe Beacon add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespBCNData_buff, + &session->addIeParams.probeRespBCNDataLen, + sme_start_bss_req->addIeParams.probeRespBCNData_buff, + sme_start_bss_req->addIeParams.probeRespBCNDataLen); + + /* Assoc resp IE */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.assocRespData_buff, + &session->addIeParams.assocRespDataLen, + sme_start_bss_req->addIeParams.assocRespData_buff, + sme_start_bss_req->addIeParams.assocRespDataLen); + + /* Store the session related params in newly created session */ + session->pLimStartBssReq = sme_start_bss_req; + + /* Store PE session_id in session Table */ + session->peSessionId = session_id; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_start_bss_req->sessionId; + + session->transactionId = sme_start_bss_req->transactionId; + + cdf_mem_copy(&(session->htConfig), + &(sme_start_bss_req->htConfig), + sizeof(session->htConfig)); + + sir_copy_mac_addr(session->selfMacAddr, + sme_start_bss_req->selfMacAddr); + + /* Copy SSID to session table */ + cdf_mem_copy((uint8_t *) &session->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + (sme_start_bss_req->ssId.length + 1)); + + session->bssType = sme_start_bss_req->bssType; + + session->nwType = sme_start_bss_req->nwType; + + session->beaconParams.beaconInterval = + sme_start_bss_req->beaconInterval; + + /* Store the channel number in session Table */ + session->currentOperChannel = + sme_start_bss_req->channelId; + + /* Store Persona */ + session->pePersona = sme_start_bss_req->bssPersona; + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("PE PERSONA=%d"), session->pePersona); + + /* Update the phymode */ + session->gLimPhyMode = sme_start_bss_req->nwType; + + session->maxTxPower = + cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + /* Store the dot 11 mode in to the session Table */ + session->dot11mode = sme_start_bss_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = + sme_start_bss_req->cc_switch_mode; +#endif + session->htCapability = + IS_DOT11_MODE_HT(session->dot11mode); + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("*****session->vhtCapability = %d"), + session->vhtCapability); + session->txLdpcIniFeatureEnabled = + sme_start_bss_req->txLdpcIniFeatureEnabled; + + if (mac_ctx->roam.configParam.enable2x2) + session->nss = 2; + else + session->nss = 1; +#ifdef WLAN_FEATURE_11W + session->limRmfEnabled = + sme_start_bss_req->pmfCapable ? 1 : 0; + lim_log(mac_ctx, LOG1, FL("Session RMF enabled: %d"), + session->limRmfEnabled); +#endif + + cdf_mem_copy((void *)&session->rateSet, + (void *)&sme_start_bss_req->operationalRateSet, + sizeof(tSirMacRateSet)); + cdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_start_bss_req->extendedRateSet, + sizeof(tSirMacRateSet)); + + switch (sme_start_bss_req->bssType) { + case eSIR_INFRA_AP_MODE: + lim_configure_ap_start_bss_session(mac_ctx, session, + sme_start_bss_req); + break; + case eSIR_IBSS_MODE: + session->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + lim_get_short_slot_from_phy_mode(mac_ctx, session, + session->gLimPhyMode, + &session->shortSlotTimeSupported); + + /* + * initialize to "OPEN". + * will be updated upon key installation + */ + session->encryptType = eSIR_ED_NONE; + + break; + + case eSIR_BTAMP_AP_MODE: + session->limSystemRole = eLIM_BT_AMP_AP_ROLE; + break; + + case eSIR_BTAMP_STA_MODE: + session->limSystemRole = eLIM_BT_AMP_STA_ROLE; + break; + + /* + * There is one more mode called auto mode. + * which is used no where + */ + + /* FORBUILD -TEMPFIX.. HOW TO use AUTO MODE????? */ + + default: + /* not used anywhere...used in scan function */ + break; + } + + /* + * BT-AMP: Allocate memory for the array of + * parsed (Re)Assoc request structure + */ + if ((sme_start_bss_req->bssType == eSIR_BTAMP_AP_MODE) || + (sme_start_bss_req->bssType == eSIR_INFRA_AP_MODE)) { + session->parsedAssocReq = + cdf_mem_malloc(session->dph.dphHashTable. + size * sizeof(tpSirAssocReq)); + if (NULL == session->parsedAssocReq) { + lim_log(mac_ctx, LOGW, + FL("AllocateMemory() failed")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + cdf_mem_set(session->parsedAssocReq, + (session->dph.dphHashTable.size * + sizeof(tpSirAssocReq)), 0); + } + + if (!sme_start_bss_req->channelId) { + lim_log(mac_ctx, LOGE, + FL("Received invalid eWNI_SME_START_BSS_REQ")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + channel_number = sme_start_bss_req->channelId; +#ifdef QCA_HT_2040_COEX + if (sme_start_bss_req->obssEnabled) + session->htSupportedChannelWidthSet = + session->htCapability; + else +#endif + session->htSupportedChannelWidthSet = + (sme_start_bss_req->sec_ch_offset) ? 1 : 0; + session->htSecondaryChannelOffset = + sme_start_bss_req->sec_ch_offset; + session->htRecommendedTxWidthSet = + (session->htSecondaryChannelOffset) ? 1 : 0; + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("cbMode %u"), sme_start_bss_req->cbMode); + if (session->vhtCapability || session->htCapability) { + chanwidth = sme_start_bss_req->vht_channel_width; + lim_log(mac_ctx, LOG1, FL("vht_channel_width %u"), + sme_start_bss_req->vht_channel_width); + if (channel_number <= RF_CHAN_14 && + chanwidth != eHT_CHANNEL_WIDTH_20MHZ) { + chanwidth = CH_WIDTH_20MHZ; + session->htSupportedChannelWidthSet = 0; + lim_log(mac_ctx, LOG1, + FL("Set chanwidth to 20Mhz, chan %d"), + channel_number); + } + session->ch_width = chanwidth; + if (session->htSupportedChannelWidthSet) { + session->ch_center_freq_seg0 = + sme_start_bss_req->center_freq_seg0; + session->ch_center_freq_seg1 = + sme_start_bss_req->center_freq_seg1; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_center_freq_seg1 = 0; + } + } + + if (session->vhtCapability && + (CH_WIDTH_160MHZ > session->ch_width)) { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL( + "cfg get vht su bformer failed")); + + session->enable_su_tx_bformer = val; + } else { + session->nss = 1; + } + lim_log(mac_ctx, LOG1, FL("vht su tx bformer %d"), val); + + /* Delete pre-auth list if any */ + lim_delete_pre_auth_list(mac_ctx); + + /* + * keep the RSN/WPA IE information in PE Session Entry + * later will be using this to check when received (Re)Assoc req + */ + lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(mac_ctx, + &sme_start_bss_req->rsnIE, session); + + if (LIM_IS_AP_ROLE(session) || LIM_IS_IBSS_ROLE(session)) { + session->gLimProtectionControl = + sme_start_bss_req->protEnabled; + /* + * each byte will have the following info + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * reserved reserved RIFS Lsig n-GF ht20 11g 11b + */ + cdf_mem_copy((void *)&session->cfgProtection, + (void *)&sme_start_bss_req->ht_capab, + sizeof(uint16_t)); + /* Initialize WPS PBC session link list */ + session->pAPWPSPBCSession = NULL; + } + /* Prepare and Issue LIM_MLM_START_REQ to MLM */ + mlm_start_req = cdf_mem_malloc(sizeof(tLimMlmStartReq)); + if (NULL == mlm_start_req) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed for mlmStartReq")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + + cdf_mem_set((void *)mlm_start_req, sizeof(tLimMlmStartReq), 0); + + /* Copy SSID to the MLM start structure */ + cdf_mem_copy((uint8_t *) &mlm_start_req->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + sme_start_bss_req->ssId.length + 1); + mlm_start_req->ssidHidden = sme_start_bss_req->ssidHidden; + mlm_start_req->obssProtEnabled = + sme_start_bss_req->obssProtEnabled; + + mlm_start_req->bssType = session->bssType; + + /* Fill PE session Id from the session Table */ + mlm_start_req->sessionId = session->peSessionId; + + if ((mlm_start_req->bssType == eSIR_BTAMP_STA_MODE) || + (mlm_start_req->bssType == eSIR_BTAMP_AP_MODE) || + (mlm_start_req->bssType == eSIR_INFRA_AP_MODE)) { + /* + * Copy the BSSId from sessionTable to + * mlmStartReq struct + */ + sir_copy_mac_addr(mlm_start_req->bssId, session->bssId); + } else { + /* ibss mode */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + ret_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_IBSS_AUTO_BSSID, + &auto_gen_bssid); + if (ret_status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Get Auto Gen BSSID fail,Status=%d"), + ret_status); + ret_code = eSIR_LOGP_EXCEPTION; + goto free; + } + + if (!auto_gen_bssid) { + /* + * We're not auto generating BSSID. + * Instead, get it from session entry + */ + sir_copy_mac_addr(mlm_start_req->bssId, + session->bssId); + /* + * Start IBSS group BSSID + * Auto Generating BSSID. + */ + auto_gen_bssid = ((mlm_start_req->bssId[0] & + 0x01) ? true : false); + } + + if (auto_gen_bssid) { + /* + * if BSSID is not any uc id. + * then use locally generated BSSID. + * Autogenerate the BSSID + */ + lim_get_random_bssid(mac_ctx, + mlm_start_req->bssId); + mlm_start_req->bssId[0] = 0x02; + + /* + * Copy randomly generated BSSID + * to the session Table + */ + sir_copy_mac_addr(session->bssId, + mlm_start_req->bssId); + } + } + /* store the channel num in mlmstart req structure */ + mlm_start_req->channelNumber = session->currentOperChannel; + mlm_start_req->cbMode = sme_start_bss_req->cbMode; + mlm_start_req->beaconPeriod = + session->beaconParams.beaconInterval; + + if (LIM_IS_AP_ROLE(session)) { + mlm_start_req->dtimPeriod = session->dtimPeriod; + mlm_start_req->wps_state = session->wps_state; + + } else { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_DTIM_PERIOD, &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve DTIM Period")); + mlm_start_req->dtimPeriod = (uint8_t) val; + } + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_PERIOD, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve Beacon interval")); + mlm_start_req->cfParamSet.cfpPeriod = (uint8_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_MAX_DURATION, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve CFPMaxDuration")); + mlm_start_req->cfParamSet.cfpMaxDuration = (uint16_t) val; + + /* + * this may not be needed anymore now, + * as rateSet is now included in the + * session entry and MLM has session context. + */ + cdf_mem_copy((void *)&mlm_start_req->rateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + /* Now populate the 11n related parameters */ + mlm_start_req->nwType = session->nwType; + mlm_start_req->htCapable = session->htCapability; + + mlm_start_req->htOperMode = mac_ctx->lim.gHTOperMode; + /* Unused */ + mlm_start_req->dualCTSProtection = + mac_ctx->lim.gHTDualCTSProtection; + mlm_start_req->txChannelWidthSet = + session->htRecommendedTxWidthSet; + + session->limRFBand = lim_get_rf_band(channel_number); + + /* Initialize 11h Enable Flag */ + session->lim11hEnable = 0; + if ((mlm_start_req->bssType != eSIR_IBSS_MODE) && + (SIR_BAND_5_GHZ == session->limRFBand)) { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED ")); + else + session->lim11hEnable = val; + + if (session->lim11hEnable && + (eSIR_INFRA_AP_MODE == + mlm_start_req->bssType)) { + cfg_get_wmi_dfs_master_param = + wlan_cfg_get_int(mac_ctx, + WNI_CFG_DFS_MASTER_ENABLED, + &val); + session->lim11hEnable = val; + } + if (cfg_get_wmi_dfs_master_param != eSIR_SUCCESS) + /* Failed get CFG WNI_CFG_DFS_MASTER_ENABLED */ + lim_log(mac_ctx, LOGE, + FL("Get Fail, CFG DFS ENABLE")); + } + + if (!session->lim11hEnable) { + if (cfg_set_int(mac_ctx, + WNI_CFG_LOCAL_POWER_CONSTRAINT, 0) != + eSIR_SUCCESS) + /* + * Failed to set the CFG param + * WNI_CFG_LOCAL_POWER_CONSTRAINT + */ + lim_log(mac_ctx, LOGE, + FL("Set LOCAL_POWER_CONSTRAINT failed")); + } + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_START_BSS_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + lim_post_mlm_message(mac_ctx, LIM_MLM_START_REQ, + (uint32_t *) mlm_start_req); + return; + } else { + + lim_log(mac_ctx, LOGE, + FL("Received unexpected START_BSS_REQ, in state %X"), + mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto end; + } /* if (mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) */ + +free: + if ((session != NULL) && + (session->pLimStartBssReq == sme_start_bss_req)) { + session->pLimStartBssReq = NULL; + } + cdf_mem_free(sme_start_bss_req); + cdf_mem_free(mlm_start_req); + +end: + if (sme_start_bss_req != NULL) { + sme_session_id = sme_start_bss_req->sessionId; + sme_transaction_id = sme_start_bss_req->transactionId; + } + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + lim_send_sme_start_bss_rsp(mac_ctx, eWNI_SME_START_BSS_RSP, ret_code, + session, sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_start_bss_req() - Call handler to start BSS + * + * @pMac: Global MAC context + * @pMsg: Message pointer + * + * Wrapper for the function __lim_handle_sme_start_bss_request + * This message will be defered until softmac come out of + * scan mode or if we have detected radar on the current + * operating channel. + * + * return true - If we consumed the buffer + * false - If have defered the message. + */ +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg) || + __lim_is_defered_msg_for_radar(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + + __lim_handle_sme_start_bss_request(pMac, (uint32_t *) pMsg->bodyptr); + return true; +} + +/** + * lim_get_random_bssid() + * + * FUNCTION:This function is called to process generate the random number for bssid + * This function is called to process SME_SCAN_REQ message + * from HDD or upper layer application. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * 1. geneartes the unique random number for bssid in ibss + * + * @param pMac Pointer to Global MAC structure + * @param *data Pointer to bssid buffer + * @return None + */ +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data) +{ + uint32_t random[2]; + random[0] = tx_time_get(); + random[0] |= (random[0] << 15); + random[1] = random[0] >> 1; + cdf_mem_copy(data, (uint8_t *) random, sizeof(tSirMacAddr)); +} + +static CDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, + tpSirSmeScanReq pScanReq) +{ + tSirScanOffloadReq *pScanOffloadReq; + uint8_t *p; + uint8_t *ht_cap_ie; + tSirMsgQ msg; + uint16_t i, len; + uint16_t ht_cap_len = 0, addn_ie_len = 0; +#ifdef WLAN_FEATURE_11AC + uint8_t *vht_cap_ie; + uint16_t vht_cap_len = 0; +#endif /* WLAN_FEATURE_11AC */ + tSirRetStatus status, rc = eSIR_SUCCESS; + tDot11fIEExtCap extracted_extcap = {0}; + bool extcap_present = true; + + if (pScanReq->uIEFieldLen) { + status = lim_strip_extcap_update_struct(pMac, + (uint8_t *) pScanReq + pScanReq->uIEFieldOffset, + &pScanReq->uIEFieldLen, &extracted_extcap); + + if (eSIR_SUCCESS != status) { + extcap_present = false; + lim_log(pMac, LOG1, + FL("Unable to Strip ExtCap IE from Scan Req")); + } + + if (extcap_present) { + lim_log(pMac, LOG1, + FL("Extcap was part of SCAN IE - Updating FW")); + lim_send_ext_cap_ie(pMac, pScanReq->sessionId, + &extracted_extcap, true); + } + } else { + lim_log(pMac, LOG1, + FL("No IEs in the scan request from supplicant")); + } + + /** + * The tSirScanOffloadReq will reserve the space for first channel, + * so allocate the memory for (numChannels - 1) and uIEFieldLen + */ + len = sizeof(tSirScanOffloadReq) + + (pScanReq->channelList.numChannels - 1) + pScanReq->uIEFieldLen; + + if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { + lim_log(pMac, LOG1, + FL("Adding HT Caps IE since dot11mode=%d"), + pScanReq->dot11mode); + /* 2 bytes for EID and Length */ + ht_cap_len = 2 + sizeof(tHtCaps); + len += ht_cap_len; + addn_ie_len += ht_cap_len; + } + +#ifdef WLAN_FEATURE_11AC + if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { + lim_log(pMac, LOG1, + FL("Adding VHT Caps IE since dot11mode=%d"), + pScanReq->dot11mode); + /* 2 bytes for EID and Length */ + vht_cap_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + + sizeof(tSirVhtMcsInfo); + len += vht_cap_len; + addn_ie_len += vht_cap_len; + } +#endif /* WLAN_FEATURE_11AC */ + + pScanOffloadReq = cdf_mem_malloc(len); + if (NULL == pScanOffloadReq) { + lim_log(pMac, LOGE, + FL("AllocateMemory failed for pScanOffloadReq")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set((uint8_t *) pScanOffloadReq, len, 0); + + msg.type = WMA_START_SCAN_OFFLOAD_REQ; + msg.bodyptr = pScanOffloadReq; + msg.bodyval = 0; + + cdf_mem_copy((uint8_t *) pScanOffloadReq->bssId, + (uint8_t *) pScanReq->bssId, sizeof(tSirMacAddr)); + + if (pScanReq->numSsid > SIR_SCAN_MAX_NUM_SSID) { + lim_log(pMac, LOGE, + FL("Invalid value (%d) for numSsid"), + SIR_SCAN_MAX_NUM_SSID); + cdf_mem_free(pScanOffloadReq); + return CDF_STATUS_E_FAILURE; + } + + pScanOffloadReq->numSsid = pScanReq->numSsid; + for (i = 0; i < pScanOffloadReq->numSsid; i++) { + pScanOffloadReq->ssId[i].length = pScanReq->ssId[i].length; + cdf_mem_copy((uint8_t *) pScanOffloadReq->ssId[i].ssId, + (uint8_t *) pScanReq->ssId[i].ssId, + pScanOffloadReq->ssId[i].length); + } + + pScanOffloadReq->hiddenSsid = pScanReq->hiddenSsid; + cdf_mem_copy((uint8_t *) pScanOffloadReq->selfMacAddr, + (uint8_t *) pScanReq->selfMacAddr, sizeof(tSirMacAddr)); + pScanOffloadReq->bssType = pScanReq->bssType; + pScanOffloadReq->dot11mode = pScanReq->dot11mode; + pScanOffloadReq->scanType = pScanReq->scanType; + pScanOffloadReq->minChannelTime = pScanReq->minChannelTime; + pScanOffloadReq->maxChannelTime = pScanReq->maxChannelTime; + pScanOffloadReq->restTime = pScanReq->restTime; + + /* for normal scan, the value for p2pScanType should be 0 + always */ + if (pScanReq->p2pSearch) + pScanOffloadReq->p2pScanType = P2P_SCAN_TYPE_SEARCH; + + pScanOffloadReq->sessionId = pScanReq->sessionId; + pScanOffloadReq->scan_id = pScanReq->scan_id; + + if (pScanOffloadReq->sessionId >= pMac->lim.maxBssId) + lim_log(pMac, LOGE, FL("Invalid pe sessionID : %d"), + pScanOffloadReq->sessionId); + + pScanOffloadReq->channelList.numChannels = + pScanReq->channelList.numChannels; + p = &(pScanOffloadReq->channelList.channelNumber[0]); + for (i = 0; i < pScanOffloadReq->channelList.numChannels; i++) + p[i] = pScanReq->channelList.channelNumber[i]; + + pScanOffloadReq->uIEFieldLen = pScanReq->uIEFieldLen; + pScanOffloadReq->uIEFieldOffset = len - addn_ie_len - + pScanOffloadReq->uIEFieldLen; + cdf_mem_copy((uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset, + (uint8_t *) pScanReq + pScanReq->uIEFieldOffset, + pScanReq->uIEFieldLen); + + /* Copy HT Capability info if dot11mode is HT */ + if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) { + /* Populate EID and Length field here */ + ht_cap_ie = (uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset + + pScanOffloadReq->uIEFieldLen; + cdf_mem_set(ht_cap_ie, ht_cap_len, 0); + *ht_cap_ie = SIR_MAC_HT_CAPABILITIES_EID; + *(ht_cap_ie + 1) = ht_cap_len - 2; + lim_set_ht_caps(pMac, NULL, ht_cap_ie, ht_cap_len); + pScanOffloadReq->uIEFieldLen += ht_cap_len; + } + +#ifdef WLAN_FEATURE_11AC + /* Copy VHT Capability info if dot11mode is VHT Capable */ + if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) { + /* Populate EID and Length field here */ + vht_cap_ie = (uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset + + pScanOffloadReq->uIEFieldLen; + cdf_mem_set(vht_cap_ie, vht_cap_len, 0); + *vht_cap_ie = SIR_MAC_VHT_CAPABILITIES_EID; + *(vht_cap_ie + 1) = vht_cap_len - 2; + lim_set_vht_caps(pMac, NULL, vht_cap_ie, vht_cap_len); + pScanOffloadReq->uIEFieldLen += vht_cap_len; + } +#endif /* WLAN_FEATURE_11AC */ + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure")); + cdf_mem_free(pScanOffloadReq); + return CDF_STATUS_E_FAILURE; + } + + lim_log(pMac, LOG1, FL("Processed Offload Scan Request Successfully")); + + return CDF_STATUS_SUCCESS; +} + +/** + * __lim_process_sme_scan_req() - Process the SME Scan Request + * @mac_ctx: Global MAC Context + * @msg_buf: Buffer which contains the request and pertinent parameters + * + * This function is called to process SME_SCAN_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_scan_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirSmeScanReq scan_req; + uint8_t valid_req = 0; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SCAN_REQ_EVENT, NULL, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + + scan_req = (tpSirSmeScanReq) msg_buf; + lim_log(mac_ctx, LOG1, + FL("SME SCAN REQ id %d numChan %d min %d max %d IELen %d first %d fresh %d unique %d type %d rsp %d"), + scan_req->scan_id, scan_req->channelList.numChannels, + scan_req->minChannelTime, scan_req->maxChannelTime, + scan_req->uIEFieldLen, scan_req->returnAfterFirstMatch, + scan_req->returnFreshResults, scan_req->returnUniqueResults, + scan_req->scanType, mac_ctx->lim.gLimRspReqd ? 1 : 0); + /* + * Since scan req always requires a response, we will overwrite response + * required here. This is added esp to take care of the condition where + * in p2p go case, we hold the scan req and insert single NOA. We send + * the held scan request to FW later on getting start NOA ind from FW so + * we lose state of the gLimRspReqd flag for the scan req if any other + * request comes by then. e.g. While unit testing, we found when insert + * single NOA is done, we see a get stats request which turns the flag + * gLimRspReqd to false; now when we actually start the saved scan req + * for init scan after getting NOA started, the gLimRspReqd being a + * global flag is showing false instead of true value for this saved + * scan req. Since all scan reqs coming to lim require a response, + * there is no harm in setting the global flag gLimRspReqd to true here. + */ + mac_ctx->lim.gLimRspReqd = true; + + /* + * copy the Self MAC address from SmeReq to the globalplace, + * used for sending probe req + */ + sir_copy_mac_addr(mac_ctx->lim.gSelfMacAddr, scan_req->selfMacAddr); + valid_req = lim_is_sme_scan_req_valid(mac_ctx, scan_req); + + if (!valid_req || mac_ctx->lim.scan_disabled) { + lim_log(mac_ctx, LOGE, + FL("Scan disabled %d, Valid Scan Req %d"), + mac_ctx->lim.scan_disabled, valid_req); + + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + + lim_send_sme_scan_rsp(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + scan_req->sessionId, + scan_req->transactionId, + scan_req->scan_id); + } + return; + } + + /* + * If scan request is received in idle, joinFailed + * states or in link established state (in STA role) + * or in normal state (in STA-in-IBSS/AP role) with + * 'return fresh scan results' request from HDD or + * it is periodic background scanning request, + * trigger fresh scan request to MLM + */ + if (__lim_fresh_scan_reqd(mac_ctx, scan_req->returnFreshResults)) { + + mac_ctx->lim.gLim24Band11dScanDone = 0; + mac_ctx->lim.gLim50Band11dScanDone = 0; + mac_ctx->lim.gLimReturnAfterFirstMatch = + scan_req->returnAfterFirstMatch; + mac_ctx->lim.gLimReturnUniqueResults = + ((scan_req->returnUniqueResults) > 0 ? true : false); + + if (CDF_STATUS_SUCCESS != + lim_send_hal_start_scan_offload_req(mac_ctx, + scan_req)) { + lim_log(mac_ctx, LOGE, FL( + "Couldn't send Offload scan request")); + lim_send_sme_scan_rsp(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + scan_req->sessionId, + scan_req->transactionId, + scan_req->scan_id); + return; + } + } + else { + /* In all other cases return 'cached' scan results */ + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + lim_send_sme_scan_rsp(mac_ctx, eSIR_SME_SUCCESS, + scan_req->sessionId, + scan_req->transactionId, scan_req->scan_id); + } + } +} + +#ifdef FEATURE_OEM_DATA_SUPPORT + +static void __lim_process_sme_oem_data_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirOemDataReq pOemDataReq; + tLimMlmOemDataReq *pMlmOemDataReq; + + pOemDataReq = (tpSirOemDataReq) pMsgBuf; + + /* post the lim mlm message now */ + pMlmOemDataReq = cdf_mem_malloc(sizeof(tLimMlmOemDataReq)); + if (NULL == pMlmOemDataReq) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for mlmOemDataReq")); + return; + } + /* Initialize this buffer */ + cdf_mem_set(pMlmOemDataReq, (sizeof(tLimMlmOemDataReq)), 0); + + cdf_mem_copy(pMlmOemDataReq->selfMacAddr, pOemDataReq->selfMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMlmOemDataReq->oemDataReq, pOemDataReq->oemDataReq, + OEM_DATA_REQ_SIZE); + + /* Issue LIM_MLM_OEM_DATA_REQ to MLM */ + lim_post_mlm_message(pMac, LIM_MLM_OEM_DATA_REQ, + (uint32_t *) pMlmOemDataReq); + + return; + +} /*** end __lim_process_sme_oem_data_req() ***/ + +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/** + * __lim_process_clear_dfs_channel_list() + * + ***FUNCTION: + ***Clear DFS channel list when country is changed/aquired. + .*This message is sent from SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void __lim_process_clear_dfs_channel_list(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + cdf_mem_set(&pMac->lim.dfschannelList, sizeof(tSirDFSChannelList), 0); +} + +/** + * __lim_process_sme_join_req() - process SME_JOIN_REQ message + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the SME message buffer + * + * This function is called to process SME_JOIN_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeJoinReq sme_join_req = NULL; + tLimMlmJoinReq *mlm_join_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + uint32_t val = 0; + uint16_t n_size; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id; + uint16_t sme_transaction_id; + tPowerdBm local_power_constraint = 0, reg_max = 0; + uint16_t ie_len; + uint8_t *vendor_ie; + tSirBssDescription bss_desc; + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Not sending any session, since it is not created yet. + * The response whould have correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_REQ_EVENT, NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_log(mac_ctx, LOG1, FL("Received SME_JOIN_REQ")); +#ifdef WLAN_FEATURE_VOWIFI + /* + * Need to read the CFG here itself as this is + * used in limExtractAPCapability() below. + * This CFG is actually read in rrm_update_config() + * which is called later. Because this is not + * read, RRM related path before calling rrm_update_config() + * is not getting executed causing issues + * like not honoring power constraint on 1st association + * after driver loading. + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RRM_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("cfg get rrm enabled failed")); + mac_ctx->rrm.rrmPEContext.rrmEnable = (val) ? 1 : 0; + val = 0; +#endif /* WLAN_FEATURE_VOWIFI */ + + /* + * Expect Join request in idle state. + * Reassociate request is expected in link established state. + */ + + /* Global SME and LIM states are not defined yet for BT-AMP Support */ + if (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE) { + n_size = __lim_get_sme_join_req_size_for_alloc((uint8_t *) + msg_buf); + + sme_join_req = cdf_mem_malloc(n_size); + if (NULL == sme_join_req) { + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for sme_join_req")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + return; + } + (void)cdf_mem_set((void *)sme_join_req, n_size, 0); + (void)cdf_mem_copy((void *)sme_join_req, (void *)msg_buf, + n_size); + + if (!lim_is_sme_join_req_valid(mac_ctx, sme_join_req)) { + /* Received invalid eWNI_SME_JOIN_REQ */ + /* Log the event */ + lim_log(mac_ctx, LOGW, + FL("SessionId:%d JOIN REQ with invalid data"), + sme_join_req->sessionId); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + bss_desc = sme_join_req->bssDescription; + /* check for the existence of start BSS session */ + + session = pe_find_session_by_bssid(mac_ctx, bss_desc.bssId, + &session_id); + + if (session != NULL) { + lim_log(mac_ctx, LOGE, + FL("Session(%d) Already exists for BSSID: " + MAC_ADDRESS_STR " in limSmeState = %X"), + session_id, + MAC_ADDR_ARRAY(bss_desc.bssId), + session->limSmeState); + + if (session->limSmeState == eLIM_SME_LINK_EST_STATE && + session->smeSessionId == sme_join_req->sessionId) { + /* + * Received eWNI_SME_JOIN_REQ for same + * BSS as currently associated. + * Log the event and send success + */ + lim_log(mac_ctx, LOGW, + FL("SessionId: %d"), session_id); + lim_log(mac_ctx, LOGW, + FL("JOIN_REQ for current joined BSS")); + /* Send Join success response to host */ + ret_code = eSIR_SME_ALREADY_JOINED_A_BSS; + session = NULL; + goto end; + } else { + lim_log(mac_ctx, LOGE, + FL("JOIN_REQ not for current joined BSS")); + ret_code = eSIR_SME_REFUSED; + session = NULL; + goto end; + } + } else { + /* + * Session Entry does not exist for given BSSId + * Try to Create a new session + */ + session = pe_create_session(mac_ctx, bss_desc.bssId, + &session_id, mac_ctx->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session Can not be created ")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } else + lim_log(mac_ctx, LOG1, + FL("SessionId:%d New session created"), + session_id); + } + session->isAmsduSupportInAMPDU = + sme_join_req->isAmsduSupportInAMPDU; + + /* + * Store Session related parameters + * Store PE session Id in session Table + */ + session->peSessionId = session_id; + + /* store the smejoin req handle in session table */ + session->pLimJoinReq = sme_join_req; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_join_req->sessionId; + + /* Store SME transaction Id in session Table */ + session->transactionId = sme_join_req->transactionId; + + /* Store beaconInterval */ + session->beaconParams.beaconInterval = + bss_desc.beaconInterval; + + cdf_mem_copy(&(session->htConfig), &(sme_join_req->htConfig), + sizeof(session->htConfig)); + + /* Copying of bssId is already done, while creating session */ + sir_copy_mac_addr(session->selfMacAddr, + sme_join_req->selfMacAddr); + session->bssType = sme_join_req->bsstype; + + session->statypeForBss = STA_ENTRY_PEER; + session->limWmeEnabled = sme_join_req->isWMEenabled; + session->limQosEnabled = sme_join_req->isQosEnabled; + + /* Store vendor specfic IE for CISCO AP */ + ie_len = (bss_desc.length + sizeof(bss_desc.length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + vendor_ie = cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + SIR_MAC_CISCO_OUI, SIR_MAC_CISCO_OUI_SIZE, + ((uint8_t *)&bss_desc.ieFields), ie_len); + + if (NULL != vendor_ie) { + lim_log(mac_ctx, LOGE, + FL("DUT is trying to connect to Cisco AP")); + session->isCiscoVendorAP = true; + } else { + session->isCiscoVendorAP = false; + } + + /* Copy the dot 11 mode in to the session table */ + + session->dot11mode = sme_join_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = sme_join_req->cc_switch_mode; +#endif + session->nwType = bss_desc.nwType; + session->enableAmpduPs = sme_join_req->enableAmpduPs; + session->enableHtSmps = sme_join_req->enableHtSmps; + session->htSmpsvalue = sme_join_req->htSmps; + + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("PE PERSONA=%d cbMode %u"), + session->pePersona, sme_join_req->cbMode); + if (mac_ctx->roam.configParam.enable2x2) + session->nss = 2; + else + session->nss = 1; +#ifdef WLAN_FEATURE_11AC + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_MED, + "***__lim_process_sme_join_req: vhtCapability=%d****", + session->vhtCapability); + if (session->vhtCapability) { + if (session->pePersona == CDF_STA_MODE) { + session->txBFIniFeatureEnabled = + sme_join_req->txBFIniFeatureEnabled; + } else { + session->txBFIniFeatureEnabled = 0; + } + session->txMuBformee = sme_join_req->txMuBformee; + session->enableVhtpAid = + sme_join_req->enableVhtpAid; + session->enableVhtGid = + sme_join_req->enableVhtGid; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_MED, + FL("***txBFIniFeatureEnabled=%d***"), + session->txBFIniFeatureEnabled); + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL( + "cfg get vht su bformer failed")); + + session->enable_su_tx_bformer = val; + lim_log(mac_ctx, LOGE, FL("vht su tx bformer %d"), val); + } + if (session->vhtCapability && session->txBFIniFeatureEnabled) { + if (cfg_set_int(mac_ctx, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + session->txBFIniFeatureEnabled) != + eSIR_SUCCESS) { + /* + * Set failed for + * CFG_VHT_SU_BEAMFORMEE_CAP + */ + lim_log(mac_ctx, LOGP, + FL("Failed CFG_VHT_SU_BEAMFORMEE_CAP")); + ret_code = eSIR_LOGP_EXCEPTION; + goto end; + } + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_MED, + "%s: txBFCsnValue=%d", __func__, + sme_join_req->txBFCsnValue); + if (cfg_set_int(mac_ctx, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + sme_join_req->txBFCsnValue) != eSIR_SUCCESS) { + /* + * Set Failed for CFG + * CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED + */ + lim_log(mac_ctx, LOGP, FL("Set Fail CFG")); + ret_code = eSIR_LOGP_EXCEPTION; + goto end; + } + } +#endif + + /*Phy mode */ + session->gLimPhyMode = bss_desc.nwType; + handle_ht_capabilityand_ht_info(mac_ctx, session); + /* Copy The channel Id to the session Table */ + session->currentOperChannel = bss_desc.channelId; + /* cbMode is already merged value of peer and self - + * done by csr in csr_get_cb_mode_from_ies */ + session->htSupportedChannelWidthSet = + (sme_join_req->cbMode) ? 1 : 0; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + session->htSecondaryChannelOffset = sme_join_req->cbMode; + + if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel - 2; + session->ch_width = CH_WIDTH_40MHZ; + } else if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel + 2; + session->ch_width = CH_WIDTH_40MHZ; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_width = CH_WIDTH_20MHZ; + } + + /* Record if management frames need to be protected */ +#ifdef WLAN_FEATURE_11W + if (eSIR_ED_AES_128_CMAC == sme_join_req->MgmtEncryptionType) { + CDF_STATUS cdf_status; + session->limRmfEnabled = 1; + session->pmfComebackTimerInfo.pMac = mac_ctx; + session->pmfComebackTimerInfo.sessionID = + session_id; + cdf_status = cdf_mc_timer_init( + &session->pmfComebackTimer, + CDF_TIMER_TYPE_SW, + lim_pmf_comeback_timer_callback, + (void *)&session->pmfComebackTimerInfo); + if (CDF_STATUS_SUCCESS != cdf_status) { + lim_log(mac_ctx, LOGP, + FL("cannot init pmf comeback timer.")); + ret_code = eSIR_LOGP_EXCEPTION; + goto end; + } + } else { + session->limRmfEnabled = 0; + } +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + session->rssi = bss_desc.rssi; +#endif + + /* Copy the SSID from smejoinreq to session entry */ + session->ssId.length = sme_join_req->ssId.length; + cdf_mem_copy(session->ssId.ssId, sme_join_req->ssId.ssId, + session->ssId.length); + + /* + * Determin 11r or ESE connection based on input from SME + * which inturn is dependent on the profile the user wants + * to connect to, So input is coming from supplicant + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + session->is11Rconnection = sme_join_req->is11Rconnection; +#endif +#ifdef FEATURE_WLAN_ESE + session->isESEconnection = sme_join_req->isESEconnection; +#endif +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + session->isFastTransitionEnabled = + sme_join_req->isFastTransitionEnabled; +#endif + +#ifdef FEATURE_WLAN_LFR + session->isFastRoamIniFeatureEnabled = + sme_join_req->isFastRoamIniFeatureEnabled; +#endif + session->txLdpcIniFeatureEnabled = + sme_join_req->txLdpcIniFeatureEnabled; + + if (session->bssType == eSIR_INFRASTRUCTURE_MODE) { + session->limSystemRole = eLIM_STA_ROLE; + } else if (session->bssType == eSIR_BTAMP_AP_MODE) { + session->limSystemRole = eLIM_BT_AMP_STA_ROLE; + } else { + /* + * Throw an error and return and make + * sure to delete the session. + */ + lim_log(mac_ctx, LOGE, + FL("recvd JOIN_REQ with invalid bss type %d"), + session->bssType); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + if (sme_join_req->addIEScan.length) + cdf_mem_copy(&session->pLimJoinReq->addIEScan, + &sme_join_req->addIEScan, sizeof(tSirAddie)); + + if (sme_join_req->addIEAssoc.length) + cdf_mem_copy(&session->pLimJoinReq->addIEAssoc, + &sme_join_req->addIEAssoc, sizeof(tSirAddie)); + + val = sizeof(tLimMlmJoinReq) + + session->pLimJoinReq->bssDescription.length + 2; + mlm_join_req = cdf_mem_malloc(val); + if (NULL == mlm_join_req) { + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for mlmJoinReq")); + return; + } + (void)cdf_mem_set((void *)mlm_join_req, val, 0); + + /* PE SessionId is stored as a part of JoinReq */ + mlm_join_req->sessionId = session->peSessionId; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_JOIN_FAILURE_TIMEOUT, + (uint32_t *) &mlm_join_req->joinFailureTimeout) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't retrieve JoinFailureTimer value" + " setting to default value")); + mlm_join_req->joinFailureTimeout = + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF; + } + + /* copy operational rate from session */ + cdf_mem_copy((void *)&session->rateSet, + (void *)&sme_join_req->operationalRateSet, + sizeof(tSirMacRateSet)); + cdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_join_req->extendedRateSet, + sizeof(tSirMacRateSet)); + /* + * this may not be needed anymore now, as rateSet is now + * included in the session entry and MLM has session context. + */ + cdf_mem_copy((void *)&mlm_join_req->operationalRateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + session->encryptType = sme_join_req->UCEncryptionType; + + mlm_join_req->bssDescription.length = + session->pLimJoinReq->bssDescription.length; + + cdf_mem_copy((uint8_t *) &mlm_join_req->bssDescription.bssId, + (uint8_t *) + &session->pLimJoinReq->bssDescription.bssId, + session->pLimJoinReq->bssDescription.length + 2); + + session->limCurrentBssCaps = + session->pLimJoinReq->bssDescription.capabilityInfo; + + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + local_power_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *) + session->pLimJoinReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session->pLimJoinReq->bssDescription), + &session->limCurrentBssQosCaps, + &session->limCurrentBssPropCap, + &session->gLimCurrentBssUapsd, + &local_power_constraint, session); + +#ifdef FEATURE_WLAN_ESE + session->maxTxPower = lim_get_max_tx_power(reg_max, + local_power_constraint, + mac_ctx->roam.configParam.nTxPowerCap); +#else + session->maxTxPower = + CDF_MIN(reg_max, (local_power_constraint)); +#endif +#if defined WLAN_VOWIFI_DEBUG + lim_log(mac_ctx, LOGE, + "Regulatory max = %d, local power constraint = %d" + reg_max, local_power_constraint); + lim_log(mac_ctx, LOGE, FL(" max tx = %d"), + session->maxTxPower); +#endif + + if (session->gLimCurrentBssUapsd) { + session->gUapsdPerAcBitmask = + session->pLimJoinReq->uapsdPerAcBitmask; + lim_log(mac_ctx, LOG1, + FL("UAPSD flag for all AC - 0x%2x"), + session->gUapsdPerAcBitmask); + + /* resetting the dynamic uapsd mask */ + session->gUapsdPerAcDeliveryEnableMask = 0; + session->gUapsdPerAcTriggerEnableMask = 0; + } + + session->limRFBand = + lim_get_rf_band(session->currentOperChannel); + + /* Initialize 11h Enable Flag */ + if (SIR_BAND_5_GHZ == session->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED ")); + session->lim11hEnable = + WNI_CFG_11H_ENABLED_STADEF; + } else { + session->lim11hEnable = val; + } + } else { + session->lim11hEnable = 0; + } + + /* + * To care of the scenario when STA transitions from + * IBSS to Infrastructure mode. + */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_JOIN_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + lim_log(mac_ctx, LOG1, + FL("SME JoinReq:Sessionid %d SSID len %d SSID : %s Channel %d, BSSID " MAC_ADDRESS_STR), + mlm_join_req->sessionId, session->ssId.length, + session->ssId.ssId, session->currentOperChannel, + MAC_ADDR_ARRAY(session->bssId)); + + /* Indicate whether spectrum management is enabled */ + session->spectrumMgtEnabled = + sme_join_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session->country_info_present && + lim_isconnected_on_dfs_channel( + session->currentOperChannel)) + session->spectrumMgtEnabled = true; + + session->isOSENConnection = sme_join_req->isOSENConnection; + + lim_log(mac_ctx, LOG1, + FL("SessionId:%d MLM_JOIN_REQ is posted to MLM SM"), + mlm_join_req->sessionId); + /* Issue LIM_MLM_JOIN_REQ to MLM */ + lim_post_mlm_message(mac_ctx, LIM_MLM_JOIN_REQ, + (uint32_t *) mlm_join_req); + return; + + } else { + /* Received eWNI_SME_JOIN_REQ un expected state */ + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_JOIN_REQ in state %X"), + mac_ctx->lim.gLimSmeState); + lim_print_sme_state(mac_ctx, LOGE, mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + session = NULL; + goto end; + } + +end: + sme_session_id = sme_join_req->sessionId; + sme_transaction_id = sme_join_req->transactionId; + + if (sme_join_req) { + cdf_mem_free(sme_join_req); + sme_join_req = NULL; + if (NULL != session) + session->pLimJoinReq = NULL; + } + if (ret_code != eSIR_SME_SUCCESS) { + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + } + lim_log(mac_ctx, LOG1, + FL("Send failure status on sessionid: %d with ret_code = %d"), + sme_session_id, ret_code); + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, ret_code, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session, sme_session_id, + sme_transaction_id); +} + +#if defined FEATURE_WLAN_ESE || defined WLAN_FEATURE_VOWIFI +uint8_t lim_get_max_tx_power(tPowerdBm regMax, tPowerdBm apTxPower, + uint8_t iniTxPower) +{ + uint8_t maxTxPower = 0; + uint8_t txPower = CDF_MIN(regMax, (apTxPower)); + txPower = CDF_MIN(txPower, iniTxPower); + if ((txPower >= MIN_TX_PWR_CAP) && (txPower <= MAX_TX_PWR_CAP)) + maxTxPower = txPower; + else if (txPower < MIN_TX_PWR_CAP) + maxTxPower = MIN_TX_PWR_CAP; + else + maxTxPower = MAX_TX_PWR_CAP; + + return maxTxPower; +} +#endif + +/** + * __lim_process_sme_reassoc_req() - process reassoc req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_REASSOC_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_reassoc_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t caps; + uint32_t val; + tpSirSmeJoinReq reassoc_req = NULL; + tLimMlmReassocReq *mlm_reassoc_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry = NULL; + uint8_t session_id; + uint8_t sme_session_id; + uint16_t transaction_id; + tPowerdBm local_pwr_constraint = 0, reg_max = 0; + uint32_t tele_bcn_en = 0; + uint16_t size; + + lim_log(mac_ctx, LOG3, FL("Received REASSOC_REQ")); + + size = __lim_get_sme_join_req_size_for_alloc((uint8_t *)msg_buf); + reassoc_req = cdf_mem_malloc(size); + if (NULL == reassoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for reassoc_req")); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + (void)cdf_mem_set((void *)reassoc_req, size, 0); + (void)cdf_mem_copy((void *)reassoc_req, (void *)msg_buf, size); + + if (!lim_is_sme_join_req_valid(mac_ctx, + (tpSirSmeJoinReq)reassoc_req)) { + /* + * Received invalid eWNI_SME_REASSOC_REQ + */ + lim_log(mac_ctx, LOGW, + FL("received SME_REASSOC_REQ with invalid data")); + + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + reassoc_req->bssDescription.bssId, + &session_id); + if (session_entry == NULL) { + lim_print_mac_addr(mac_ctx, reassoc_req->bssDescription.bssId, + LOGE); + lim_log(mac_ctx, LOGE, + FL("Session does not exist for given bssId")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_REQ_EVENT, + session_entry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + /* mac_ctx->lim.gpLimReassocReq = reassoc_req;//TO SUPPORT BT-AMP */ + + /* Store the reassoc handle in the session Table */ + session_entry->pLimReAssocReq = reassoc_req; + + session_entry->dot11mode = reassoc_req->dot11mode; + session_entry->vhtCapability = + IS_DOT11_MODE_VHT(reassoc_req->dot11mode); + /* + * Reassociate request is expected + * in link established state only. + */ + + if (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE) { +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { + /* + * May be from 11r FT pre-auth. So lets check it + * before we bail out + */ + lim_log(mac_ctx, LOG1, FL( + "Session in reassoc state is %d"), + session_entry->peSessionId); + + /* Make sure its our preauth bssid */ + if (!cdf_mem_compare(reassoc_req->bssDescription.bssId, + session_entry->limReAssocbssId, + 6)) { + lim_print_mac_addr(mac_ctx, + reassoc_req->bssDescription. + bssId, LOGE); + lim_log(mac_ctx, LOGP, + FL("Unknown bssId in reassoc state")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_process_mlm_ft_reassoc_req(mac_ctx, msg_buf, + session_entry); + return; + } +#endif + /* + * Should not have received eWNI_SME_REASSOC_REQ + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_REASSOC_REQ in state %X"), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto end; + } + + cdf_mem_copy(session_entry->limReAssocbssId, + session_entry->pLimReAssocReq->bssDescription.bssId, + sizeof(tSirMacAddr)); + + session_entry->limReassocChannelId = + session_entry->pLimReAssocReq->bssDescription.channelId; + + session_entry->reAssocHtSupportedChannelWidthSet = + (session_entry->pLimReAssocReq->cbMode) ? 1 : 0; + session_entry->reAssocHtRecommendedTxWidthSet = + session_entry->reAssocHtSupportedChannelWidthSet; + session_entry->reAssocHtSecondaryChannelOffset = + session_entry->pLimReAssocReq->cbMode; + + session_entry->limReassocBssCaps = + session_entry->pLimReAssocReq->bssDescription.capabilityInfo; + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session_entry->currentOperChannel); + local_pwr_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *)session_entry->pLimReAssocReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session_entry->pLimReAssocReq->bssDescription), + &session_entry->limReassocBssQosCaps, + &session_entry->limReassocBssPropCap, + &session_entry->gLimCurrentBssUapsd, + &local_pwr_constraint, session_entry); + session_entry->maxTxPower = CDF_MIN(reg_max, (local_pwr_constraint)); +#if defined WLAN_VOWIFI_DEBUG + lim_log(mac_ctx, LOGE, + "Regulatory max = %d, local pwr constraint = %d, max tx = %d", + reg_max, local_pwr_constraint, + session_entry->maxTxPower); +#endif + /* Copy the SSID from session entry to local variable */ + session_entry->limReassocSSID.length = reassoc_req->ssId.length; + cdf_mem_copy(session_entry->limReassocSSID.ssId, + reassoc_req->ssId.ssId, + session_entry->limReassocSSID.length); + if (session_entry->gLimCurrentBssUapsd) { + session_entry->gUapsdPerAcBitmask = + session_entry->pLimReAssocReq->uapsdPerAcBitmask; + lim_log(mac_ctx, LOG1, + FL("UAPSD flag for all AC - 0x%2x"), + session_entry->gUapsdPerAcBitmask); + } + + mlm_reassoc_req = cdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == mlm_reassoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmReassocReq")); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + cdf_mem_copy(mlm_reassoc_req->peerMacAddr, + session_entry->limReAssocbssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *)&mlm_reassoc_req->reassocFailureTimeout) != + eSIR_SUCCESS) { + /* + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ReassocFailureTimeout value")); + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) != + eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, FL( + "could not retrieve Capabilities value")); + } + mlm_reassoc_req->capabilityInfo = caps; + + /* Update PE session_id */ + mlm_reassoc_req->sessionId = session_id; + + /* + * If telescopic beaconing is enabled, set listen interval to + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, + &tele_bcn_en) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + + if (tele_bcn_en) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } + + mlm_reassoc_req->listenInterval = (uint16_t) val; + + /* Indicate whether spectrum management is enabled */ + session_entry->spectrumMgtEnabled = reassoc_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session_entry->country_info_present && + lim_isconnected_on_dfs_channel( + session_entry->currentOperChannel)) + session_entry->spectrumMgtEnabled = true; + + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + lim_post_mlm_message(mac_ctx, + LIM_MLM_REASSOC_REQ, (uint32_t *)mlm_reassoc_req); + return; +end: + if (reassoc_req) { + cdf_mem_free(reassoc_req); + if (session_entry) + session_entry->pLimReAssocReq = NULL; + } + + if (session_entry) { + /* + * error occurred after we determined the session so extract + * session and transaction info from there + */ + sme_session_id = session_entry->smeSessionId; + transaction_id = session_entry->transactionId; + } else + /* + * error occurred before or during the time we determined + * the session so extract the session and transaction info + * from the message + */ + lim_get_session_info(mac_ctx, (uint8_t *) msg_buf, + &sme_session_id, &transaction_id); + + /* + * Send Reassoc failure response to host + * (note session_entry may be NULL, but that's OK) + */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + ret_code, eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry, sme_session_id, + transaction_id); +} + +bool send_disassoc_frame = 1; +/** + * __lim_process_sme_disassoc_req() + * + ***FUNCTION: + * This function is called to process SME_DISASSOC_REQ message + * from HDD or upper layer application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ + +static void __lim_process_sme_disassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t disassocTrigger, reasonCode; + tLimMlmDisassocReq *pMlmDisassocReq; + tSirResultCodes retCode = eSIR_SME_SUCCESS; + tSirSmeDisassocReq smeDisassocReq; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + cdf_mem_copy(&smeDisassocReq, pMsgBuf, sizeof(tSirSmeDisassocReq)); + smesessionId = smeDisassocReq.sessionId; + smetransactionId = smeDisassocReq.transactionId; + if (!lim_is_sme_disassoc_req_valid(pMac, + &smeDisassocReq, + psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, + FL("received invalid SME_DISASSOC_REQ message"));) + if (pMac->lim.gLimRspReqd) { + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocReq.bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given bssId " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(smeDisassocReq.bssId)); + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + lim_log(pMac, LOG1, + FL("received DISASSOC_REQ message on sessionid %d Systemrole %d Reason: %u SmeState: %d from: " + MAC_ADDRESS_STR), smesessionId, + GET_LIM_SYSTEM_ROLE(psessionEntry), smeDisassocReq.reasonCode, + pMac->lim.gLimSmeState, + MAC_ADDR_ARRAY(smeDisassocReq.peerMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_REQ_EVENT, psessionEntry, + 0, smeDisassocReq.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Update SME session Id and SME transaction ID */ + + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + switch (psessionEntry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + psessionEntry->limPrevSmeState = + psessionEntry->limSmeState; + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in limSmeState: %d "), + psessionEntry->limSmeState); + break; + + case eLIM_SME_WT_DEAUTH_STATE: + /* PE shall still process the DISASSOC_REQ and proceed with + * link tear down even if it had already sent a DEAUTH_IND to + * to SME. pMac->lim.gLimPrevSmeState shall remain the same as + * its been set when PE entered WT_DEAUTH_STATE. + */ + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in SME_WT_DEAUTH_STATE. ")); + break; + + case eLIM_SME_WT_DISASSOC_STATE: + /* PE Recieved a Disassoc frame. Normally it gets DISASSOC_CNF but it + * received DISASSOC_REQ. Which means host is also trying to disconnect. + * PE can continue processing DISASSOC_REQ and send the response instead + * of failing the request. SME will anyway ignore DEAUTH_IND that was sent + * for disassoc frame. + * + * It will send a disassoc, which is ok. However, we can use the global flag + * sendDisassoc to not send disassoc frame. + */ + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in SME_WT_DISASSOC_STATE. ")); + break; + + case eLIM_SME_JOIN_FAILURE_STATE: { + /* Already in Disconnected State, return success */ + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in eLIM_SME_JOIN_FAILURE_STATE. ")); + if (pMac->lim.gLimRspReqd) { + retCode = eSIR_SME_SUCCESS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + } + break; + default: + /** + * STA is not currently associated. + * Log error and send response to host + */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_REQ in state %X"), + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + + if (pMac->lim.gLimRspReqd) { + if (psessionEntry->limSmeState != + eLIM_SME_WT_ASSOC_STATE) + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + break; + + case eLIM_AP_ROLE: + case eLIM_BT_AMP_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: + /* eLIM_UNKNOWN_ROLE */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_REQ for role %d"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } /* end switch (pMac->lim.gLimSystemRole) */ + + if (smeDisassocReq.reasonCode == eLIM_LINK_MONITORING_DISASSOC) { + /* / Disassociation is triggered by Link Monitoring */ + lim_log(pMac, LOG1, + FL("Sending Disasscoc with reason Link Monitoring")); + disassocTrigger = eLIM_LINK_MONITORING_DISASSOC; + reasonCode = eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + } else { + disassocTrigger = eLIM_HOST_DISASSOC; + reasonCode = smeDisassocReq.reasonCode; + } + + if (smeDisassocReq.doNotSendOverTheAir) { + lim_log(pMac, LOG1, FL("do not send dissoc over the air")); + send_disassoc_frame = 0; + } + /* Trigger Disassociation frame to peer MAC entity */ + lim_log(pMac, LOG1, FL("Sending Disasscoc with disassoc Trigger" + " : %d, reasonCode : %d"), + disassocTrigger, reasonCode); + + pMlmDisassocReq = cdf_mem_malloc(sizeof(tLimMlmDisassocReq)); + if (NULL == pMlmDisassocReq) { + /* Log error */ + lim_log(pMac, LOGP, + FL("call to AllocateMemory failed for mlmDisassocReq")); + + return; + } + + cdf_mem_copy((uint8_t *) &pMlmDisassocReq->peerMacAddr, + (uint8_t *) &smeDisassocReq.peerMacAddr, + sizeof(tSirMacAddr)); + + pMlmDisassocReq->reasonCode = reasonCode; + pMlmDisassocReq->disassocTrigger = disassocTrigger; + + /* Update PE session ID */ + pMlmDisassocReq->sessionId = sessionId; + + lim_post_mlm_message(pMac, + LIM_MLM_DISASSOC_REQ, (uint32_t *) pMlmDisassocReq); + return; + +sendDisassoc: + if (psessionEntry) + lim_send_sme_disassoc_ntf(pMac, smeDisassocReq.peerMacAddr, + retCode, + disassocTrigger, + 1, smesessionId, smetransactionId, + psessionEntry); + else + lim_send_sme_disassoc_ntf(pMac, smeDisassocReq.peerMacAddr, + retCode, + disassocTrigger, + 1, smesessionId, smetransactionId, NULL); + +} /*** end __lim_process_sme_disassoc_req() ***/ + +/** ----------------------------------------------------------------- + \brief __lim_process_sme_disassoc_cnf() - Process SME_DISASSOC_CNF + + This function is called to process SME_DISASSOC_CNF message + from HDD or upper layer application. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeDisassocCnf smeDisassocCnf; + uint16_t aid; + tpDphHashNode pStaDs; + tpPESession psessionEntry; + uint8_t sessionId; + + PELOG1(lim_log(pMac, LOG1, FL("received DISASSOC_CNF message"));) + + cdf_mem_copy(&smeDisassocCnf, pMsgBuf, + sizeof(struct sSirSmeDisassocCnf)); + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocCnf.bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given bssId")); + return; + } + + if (!lim_is_sme_disassoc_cnf_valid(pMac, &smeDisassocCnf, psessionEntry)) { + lim_log(pMac, LOGE, + FL("received invalid SME_DISASSOC_CNF message")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (smeDisassocCnf.messageType == eWNI_SME_DISASSOC_CNF) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); + else if (smeDisassocCnf.messageType == eWNI_SME_DEAUTH_CNF) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: /* To test reconn */ + if ((psessionEntry->limSmeState != eLIM_SME_IDLE_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + lim_log(pMac, LOGE, + FL + ("received unexp SME_DISASSOC_CNF in state %X"), + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + return; + } + break; + + case eLIM_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: /* eLIM_UNKNOWN_ROLE */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_CNF role %d"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + return; + } + + if ((psessionEntry->limSmeState == eLIM_SME_WT_DISASSOC_STATE) || + (psessionEntry->limSmeState == eLIM_SME_WT_DEAUTH_STATE) || + LIM_IS_AP_ROLE(psessionEntry)) { + pStaDs = dph_lookup_hash_entry(pMac, + smeDisassocCnf.peerMacAddr, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, + FL("DISASSOC_CNF for a STA with no context, addr= " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(smeDisassocCnf.peerMacAddr)); + return; + } +#if defined WLAN_FEATURE_VOWIFI_11R + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(pMac, psessionEntry); +#endif + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + + lim_clean_up_disassoc_deauth_req(pMac, + (char *)&smeDisassocCnf.peerMacAddr, + 0); + } + + return; +} + +/** + * __lim_process_sme_deauth_req() - process sme deauth req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_DEAUTH_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_deauth_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t deauth_trigger, reason_code; + tLimMlmDeauthReq *mlm_deauth_req; + tSirSmeDeauthReq sme_deauth_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry; + uint8_t session_id; /* PE sessionId */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + lim_log(mac_ctx, LOG1, FL("received DEAUTH_REQ message")); + + cdf_mem_copy(&sme_deauth_req, msg_buf, sizeof(tSirSmeDeauthReq)); + sme_session_id = sme_deauth_req.sessionId; + sme_transaction_id = sme_deauth_req.transactionId; + + /* + * We need to get a session first but we don't even know + * if the message is correct. + */ + session_entry = pe_find_session_by_bssid(mac_ctx, sme_deauth_req.bssId, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + + if (!lim_is_sme_deauth_req_valid(mac_ctx, &sme_deauth_req, + session_entry)) { + lim_log(mac_ctx, LOGE, + FL("received invalid SME_DEAUTH_REQ message")); + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + lim_log(mac_ctx, LOG1, + FL("received DEAUTH_REQ sessionid %d Systemrole %d reasoncode %u limSmestate %d from " + MAC_ADDRESS_STR), sme_session_id, + GET_LIM_SYSTEM_ROLE(session_entry), sme_deauth_req.reasonCode, + session_entry->limSmeState, + MAC_ADDR_ARRAY(sme_deauth_req.peerMacAddr)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + session_entry, 0, sme_deauth_req.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Update SME session ID and Transaction ID */ + session_entry->smeSessionId = sme_session_id; + session_entry->transactionId = sme_transaction_id; + + switch (GET_LIM_SYSTEM_ROLE(session_entry)) { + case eLIM_STA_ROLE: + case eLIM_BT_AMP_STA_ROLE: + + switch (session_entry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + case eLIM_SME_WT_ASSOC_STATE: + case eLIM_SME_JOIN_FAILURE_STATE: + case eLIM_SME_IDLE_STATE: + session_entry->limPrevSmeState = + session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Deauthentication request to MLM below */ + break; + case eLIM_SME_WT_DEAUTH_STATE: + case eLIM_SME_WT_DISASSOC_STATE: + /* + * PE Recieved a Deauth/Disassoc frame. Normally it get + * DEAUTH_CNF/DISASSOC_CNF but it received DEAUTH_REQ. + * Which means host is also trying to disconnect. + * PE can continue processing DEAUTH_REQ and send + * the response instead of failing the request. + * SME will anyway ignore DEAUTH_IND/DISASSOC_IND that + * was sent for deauth/disassoc frame. + */ + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + lim_log(mac_ctx, LOG1, FL( + "Rcvd SME_DEAUTH_REQ while in SME_WT_DEAUTH_STATE")); + break; + default: + /* + * STA is not in a state to deauthenticate with + * peer. Log error and send response to host. + */ + lim_log(mac_ctx, LOGE, FL( + "received unexp SME_DEAUTH_REQ in state %X"), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, + session_entry->limSmeState); + + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_STA_NOT_AUTHENTICATED; + deauth_trigger = eLIM_HOST_DEAUTH; + + /* + * here we received deauth request from AP so sme state + * is eLIM_SME_WT_DEAUTH_STATE.if we have ISSUED + * delSta then mlm state should be + * eLIM_MLM_WT_DEL_STA_RSP_STATE and ifwe got delBSS + * rsp then mlm state should be eLIM_MLM_IDLE_STATE + * so the below condition captures the state where + * delSta not done and firmware still in + * connected state. + */ + if (session_entry->limSmeState == + eLIM_SME_WT_DEAUTH_STATE && + session_entry->limMlmState != + eLIM_MLM_IDLE_STATE && + session_entry->limMlmState != + eLIM_MLM_WT_DEL_STA_RSP_STATE) + ret_code = eSIR_SME_DEAUTH_STATUS; + goto send_deauth; + } + return; + } + break; + + case eLIM_STA_IN_IBSS_ROLE: + lim_log(mac_ctx, LOGE, FL("Deauth not allowed in IBSS")); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + case eLIM_AP_ROLE: + break; + default: + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_DEAUTH_REQ for role %X"), + GET_LIM_SYSTEM_ROLE(session_entry)); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } /* end switch (mac_ctx->lim.gLimSystemRole) */ + + if (sme_deauth_req.reasonCode == eLIM_LINK_MONITORING_DEAUTH) { + /* Deauthentication is triggered by Link Monitoring */ + lim_log(mac_ctx, LOG1, FL("** Lost link with AP **")); + deauth_trigger = eLIM_LINK_MONITORING_DEAUTH; + reason_code = eSIR_MAC_UNSPEC_FAILURE_REASON; + } else { + deauth_trigger = eLIM_HOST_DEAUTH; + reason_code = sme_deauth_req.reasonCode; + } + + /* Trigger Deauthentication frame to peer MAC entity */ + mlm_deauth_req = cdf_mem_malloc(sizeof(tLimMlmDeauthReq)); + if (NULL == mlm_deauth_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmDeauthReq")); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } + + cdf_mem_copy((uint8_t *) &mlm_deauth_req->peerMacAddr, + (uint8_t *) &sme_deauth_req.peerMacAddr, + sizeof(tSirMacAddr)); + + mlm_deauth_req->reasonCode = reason_code; + mlm_deauth_req->deauthTrigger = deauth_trigger; + + /* Update PE session Id */ + mlm_deauth_req->sessionId = session_id; + + lim_post_mlm_message(mac_ctx, LIM_MLM_DEAUTH_REQ, + (uint32_t *)mlm_deauth_req); + return; + +send_deauth: + lim_send_sme_deauth_ntf(mac_ctx, sme_deauth_req.peerMacAddr, ret_code, + deauth_trigger, 1, sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_set_context_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_SETCONTEXT_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void +__lim_process_sme_set_context_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeSetContextReq set_context_req; + tLimMlmSetKeysReq *mlm_set_key_req; + tpPESession session_entry; + uint8_t session_id; /* PE sessionID */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + lim_log(mac_ctx, LOG1, FL("received SETCONTEXT_REQ message")); + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + set_context_req = cdf_mem_malloc(sizeof(struct sSirSmeSetContextReq)); + if (NULL == set_context_req) { + lim_log(mac_ctx, LOGP, FL( + "call to AllocateMemory failed for set_context_req")); + return; + } + cdf_mem_copy(set_context_req, msg_buf, + sizeof(struct sSirSmeSetContextReq)); + sme_session_id = set_context_req->sessionId; + sme_transaction_id = set_context_req->transactionId; + + if ((!lim_is_sme_set_context_req_valid(mac_ctx, set_context_req))) { + lim_log(mac_ctx, LOGW, + FL("received invalid SME_SETCONTEXT_REQ message")); + goto end; + } + + if (set_context_req->keyMaterial.numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(mac_ctx, LOGE, FL( + "numKeys:%d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS"), + set_context_req->keyMaterial.numKeys); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peerMacAddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + set_context_req->bssId, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGW, + FL("Session does not exist for given BSSID")); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peerMacAddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + session_entry, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (((LIM_IS_STA_ROLE(session_entry) || + LIM_IS_BT_AMP_STA_ROLE(session_entry)) && + (session_entry->limSmeState == eLIM_SME_LINK_EST_STATE)) || + ((LIM_IS_IBSS_ROLE(session_entry) || + LIM_IS_AP_ROLE(session_entry) || + LIM_IS_BT_AMP_AP_ROLE(session_entry)) && + (session_entry->limSmeState == eLIM_SME_NORMAL_STATE))) { + /* Trigger MLM_SETKEYS_REQ */ + mlm_set_key_req = cdf_mem_malloc(sizeof(tLimMlmSetKeysReq)); + if (NULL == mlm_set_key_req) { + lim_log(mac_ctx, LOGP, FL( + "mem alloc failed for mlmSetKeysReq")); + goto end; + } + mlm_set_key_req->edType = set_context_req->keyMaterial.edType; + mlm_set_key_req->numKeys = + set_context_req->keyMaterial.numKeys; + if (mlm_set_key_req->numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(mac_ctx, LOGP, FL( + "no.of keys exceeded max num of default keys limit")); + goto end; + } + cdf_mem_copy((uint8_t *) &mlm_set_key_req->peerMacAddr, + (uint8_t *) &set_context_req->peerMacAddr, + sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) &mlm_set_key_req->key, + (uint8_t *) &set_context_req->keyMaterial.key, + sizeof(tSirKeys) * + (mlm_set_key_req->numKeys ? mlm_set_key_req-> + numKeys : 1)); + + mlm_set_key_req->sessionId = session_id; + mlm_set_key_req->smesessionId = sme_session_id; +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL( + "received SETCONTEXT_REQ message sessionId=%d"), + mlm_set_key_req->sessionId); +#endif + + if (((set_context_req->keyMaterial.edType == eSIR_ED_WEP40) || + (set_context_req->keyMaterial.edType == eSIR_ED_WEP104)) && + LIM_IS_AP_ROLE(session_entry)) { + if (set_context_req->keyMaterial.key[0].keyLength) { + uint8_t key_id; + key_id = + set_context_req->keyMaterial.key[0].keyId; + cdf_mem_copy((uint8_t *) + &session_entry->WEPKeyMaterial[key_id], + (uint8_t *) &set_context_req->keyMaterial, + sizeof(tSirKeyMaterial)); + } else { + uint32_t i; + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + i++) { + cdf_mem_copy((uint8_t *) + &mlm_set_key_req->key[i], + (uint8_t *)session_entry->WEPKeyMaterial[i].key, + sizeof(tSirKeys)); + } + } + } + lim_post_mlm_message(mac_ctx, LIM_MLM_SETKEYS_REQ, + (uint32_t *) mlm_set_key_req); + } else { + lim_log(mac_ctx, LOGE, FL( + "rcvd unexpected SME_SETCONTEXT_REQ for role %d, state=%X"), + GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peerMacAddr, 1, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + session_entry, sme_session_id, + sme_transaction_id); + } +end: + cdf_mem_free(set_context_req); + return; +} + +/** + * lim_process_sme_get_assoc_sta_info() - process sme assoc sta req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_GET_ASSOC_STAS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +void lim_process_sme_get_assoc_sta_info(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tSirSmeGetAssocSTAsReq get_assoc_stas_req; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + tSap_Event sap_event; + tpWLAN_SAPEventCB sap_event_cb = NULL; + tpSap_AssocMacAddr assoc_sta_tmp = NULL; + uint8_t session_id = CSR_SESSION_ID_INVALID; + uint8_t assoc_id = 0; + uint8_t sta_cnt = 0; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + cdf_mem_copy(&get_assoc_stas_req, msg_buf, + sizeof(struct sSirSmeGetAssocSTAsReq)); + /* + * Get Associated stations from PE. + * Find PE session Entry + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + get_assoc_stas_req.bssId, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto lim_assoc_sta_end; + } + + if (!LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL( + "Received unexpected message in state %X, in role %X"), + session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_assoc_sta_end; + } + /* Retrieve values obtained in the request message */ + sap_event_cb = (tpWLAN_SAPEventCB)get_assoc_stas_req.pSapEventCallback; + assoc_sta_tmp = (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + + if (NULL == assoc_sta_tmp) + goto lim_assoc_sta_end; + for (assoc_id = 0; assoc_id < session_entry->dph.dphHashTable.size; + assoc_id++) { + sta_ds = dph_get_hash_entry(mac_ctx, assoc_id, + &session_entry->dph.dphHashTable); + if (NULL == sta_ds) + continue; + if (sta_ds->valid) { + cdf_mem_copy((uint8_t *) &assoc_sta_tmp->staMac, + (uint8_t *) &sta_ds->staAddr, + CDF_MAC_ADDR_SIZE); + assoc_sta_tmp->assocId = (uint8_t) sta_ds->assocId; + assoc_sta_tmp->staId = (uint8_t) sta_ds->staIndex; + + cdf_mem_copy((uint8_t *)&assoc_sta_tmp->supportedRates, + (uint8_t *)&sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + assoc_sta_tmp->ShortGI40Mhz = sta_ds->htShortGI40Mhz; + assoc_sta_tmp->ShortGI20Mhz = sta_ds->htShortGI20Mhz; + assoc_sta_tmp->Support40Mhz = + sta_ds->htDsssCckRate40MHzSupport; + + lim_log(mac_ctx, LOG1, FL("dph Station Number = %d"), + sta_cnt + 1); + lim_log(mac_ctx, LOG1, FL("MAC = " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(sta_ds->staAddr)); + lim_log(mac_ctx, LOG1, FL("Association Id = %d"), + sta_ds->assocId); + lim_log(mac_ctx, LOG1, FL("Station Index = %d"), + sta_ds->staIndex); + assoc_sta_tmp++; + sta_cnt++; + } + } +lim_assoc_sta_end: + /* + * Call hdd callback with sap event to send the list of + * associated stations from PE + */ + if (sap_event_cb != NULL) { + sap_event.sapHddEventCode = eSAP_ASSOC_STA_CALLBACK_EVENT; + sap_event.sapevt.sapAssocStaListEvent.module = + CDF_MODULE_ID_PE; + sap_event.sapevt.sapAssocStaListEvent.noOfAssocSta = sta_cnt; + sap_event.sapevt.sapAssocStaListEvent.pAssocStas = + (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + sap_event_cb(&sap_event, get_assoc_stas_req.pUsrContext); + } +} + +/** + * lim_process_sme_get_wpspbc_sessions - process sme get wpspbc req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to WPS PBC overlap query message + * + * This function parses get WPS PBC overlap information + * message and call callback to pass WPS PBC overlap + * information back to hdd. + * + * Return: None + */ +void lim_process_sme_get_wpspbc_sessions(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tSirSmeGetWPSPBCSessionsReq get_wps_pbc_sessions_req; + tpPESession session_entry = NULL; + tSap_Event sap_event; + tpWLAN_SAPEventCB sap_event_cb = NULL; + uint8_t session_id = CSR_SESSION_ID_INVALID; + tSirMacAddr zero_mac = { 0, 0, 0, 0, 0, 0 }; + tSap_GetWPSPBCSessionEvent *sap_get_wpspbc_event; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + sap_get_wpspbc_event = &sap_event.sapevt.sapGetWPSPBCSessionEvent; + sap_get_wpspbc_event->status = CDF_STATUS_E_FAULT; + + cdf_mem_copy(&get_wps_pbc_sessions_req, msg_buf, + sizeof(struct sSirSmeGetWPSPBCSessionsReq)); + /* + * Get Associated stations from PE + * Find PE session Entry + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + get_wps_pbc_sessions_req.bssId, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto lim_get_wpspbc_sessions_end; + } + + if (!LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, + FL("Received unexpected message in role %X"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_get_wpspbc_sessions_end; + } + /* + * Call hdd callback with sap event to send the + * WPS PBC overlap information + */ + sap_event.sapHddEventCode = eSAP_GET_WPSPBC_SESSION_EVENT; + sap_get_wpspbc_event->module = CDF_MODULE_ID_PE; + + if (cdf_mem_compare(zero_mac, get_wps_pbc_sessions_req.pRemoveMac, + sizeof(tSirMacAddr))) { + lim_get_wpspbc_sessions(mac_ctx, + sap_get_wpspbc_event->addr.bytes, + sap_get_wpspbc_event->UUID_E, + &sap_get_wpspbc_event->wpsPBCOverlap, + session_entry); + } else { + lim_remove_pbc_sessions(mac_ctx, + get_wps_pbc_sessions_req.pRemoveMac, + session_entry); + /* don't have to inform the HDD/Host */ + return; + } + + lim_log(mac_ctx, LOGE, FL("wpsPBCOverlap %d"), + sap_get_wpspbc_event->wpsPBCOverlap); + lim_print_mac_addr(mac_ctx, + sap_get_wpspbc_event->addr.bytes, LOG4); + + sap_get_wpspbc_event->status = CDF_STATUS_SUCCESS; + +lim_get_wpspbc_sessions_end: + sap_event_cb = + (tpWLAN_SAPEventCB)get_wps_pbc_sessions_req.pSapEventCallback; + if (NULL != sap_event_cb) + sap_event_cb(&sap_event, get_wps_pbc_sessions_req.pUsrContext); +} + +/** + * __lim_counter_measures() + * + * FUNCTION: + * This function is called to "implement" MIC counter measure + * and is *temporary* only + * + * LOGIC: on AP, disassoc all STA associated thru TKIP, + * we don't do the proper STA disassoc sequence since the + * BSS will be stoped anyway + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @return None + */ + +static void __lim_counter_measures(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) + lim_send_disassoc_mgmt_frame(pMac, eSIR_MAC_MIC_FAILURE_REASON, + mac, psessionEntry, false); +}; + +void lim_process_tkip_counter_measures(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeTkipCntrMeasReq tkipCntrMeasReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionId */ + + cdf_mem_copy(&tkipCntrMeasReq, pMsgBuf, + sizeof(struct sSirSmeTkipCntrMeasReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + tkipCntrMeasReq.bssId, + &sessionId); + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, + FL("session does not exist for given BSSID ")); + return; + } + + if (tkipCntrMeasReq.bEnable) + __lim_counter_measures(pMac, psessionEntry); + + psessionEntry->bTkipCntrMeasActive = tkipCntrMeasReq.bEnable; +} + +static void +__lim_handle_sme_stop_bss_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeStopBssReq stopBssReq; + tSirRetStatus status; + tLimSmeStates prevState; + tpPESession psessionEntry; + uint8_t smesessionId; + uint8_t sessionId; + uint16_t smetransactionId; + uint8_t i = 0; + tpDphHashNode pStaDs = NULL; + + cdf_mem_copy(&stopBssReq, pMsgBuf, sizeof(tSirSmeStopBssReq)); + smesessionId = stopBssReq.sessionId; + smetransactionId = stopBssReq.transactionId; + + if (!lim_is_sme_stop_bss_req_valid(pMsgBuf)) { + PELOGW(lim_log(pMac, LOGW, + FL("received invalid SME_STOP_BSS_REQ message"));) + /* Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + stopBssReq.bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("session does not exist for given BSSID ")); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, psessionEntry, + 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE || /* Added For BT -AMP Support */ + LIM_IS_STA_ROLE(psessionEntry)) { + /** + * Should not have received STOP_BSS_REQ in states + * other than 'normal' state or on STA in Infrastructure + * mode. Log error and return response to host. + */ + lim_log(pMac, LOGE, + FL + ("received unexpected SME_STOP_BSS_REQ in state %X, for role %d"), + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + lim_print_sme_state(pMac, LOGE, psessionEntry->limSmeState); + /* / Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, smesessionId, + smetransactionId); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_wpspbc_close(pMac, psessionEntry); + + lim_log(pMac, LOGW, + FL("RECEIVED STOP_BSS_REQ with reason code=%d"), + stopBssReq.reasonCode); + + prevState = psessionEntry->limSmeState; + + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + /* Update SME session Id and Transaction Id */ + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + + /* BTAMP_STA and STA_IN_IBSS should NOT send Disassoc frame */ + if (!LIM_IS_IBSS_ROLE(psessionEntry) && + !LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (stopBssReq.reasonCode == eSIR_SME_MIC_COUNTER_MEASURES) + /* Send disassoc all stations associated thru TKIP */ + __lim_counter_measures(pMac, psessionEntry); + else + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); + } + + /* Free the buffer allocated in START_BSS_REQ */ + cdf_mem_free(psessionEntry->addIeParams.probeRespData_buff); + psessionEntry->addIeParams.probeRespDataLen = 0; + psessionEntry->addIeParams.probeRespData_buff = NULL; + + cdf_mem_free(psessionEntry->addIeParams.assocRespData_buff); + psessionEntry->addIeParams.assocRespDataLen = 0; + psessionEntry->addIeParams.assocRespData_buff = NULL; + + cdf_mem_free(psessionEntry->addIeParams.probeRespBCNData_buff); + psessionEntry->addIeParams.probeRespBCNDataLen = 0; + psessionEntry->addIeParams.probeRespBCNData_buff = NULL; + + /* lim_del_bss is also called as part of coalescing, when we send DEL BSS followed by Add Bss msg. */ + pMac->lim.gLimIbssCoalescingHappened = false; + + for (i = 1; i < pMac->lim.gLimAssocStaLimit; i++) { + pStaDs = + dph_get_hash_entry(pMac, i, &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + status = lim_del_sta(pMac, pStaDs, false, psessionEntry); + if (eSIR_SUCCESS == status) { + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + } else { + lim_log(pMac, LOGE, + FL("lim_del_sta failed with Status : %d"), status); + CDF_ASSERT(0); + } + } + /* send a delBss to HAL and wait for a response */ + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + + if (status != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("delBss failed for bss %d"), + psessionEntry->bssIdx); + ) + psessionEntry->limSmeState = prevState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_STOP_BSS_FAILURE, smesessionId, + smetransactionId); + } +} + +/** + * __lim_process_sme_stop_bss_req() - Process STOP_BSS from SME + * @pMac: Global MAC context + * @pMsg: Message from SME + * + * Wrapper for the function __lim_handle_sme_stop_bss_request + * This message will be defered until softmac come out of + * scan mode. Message should be handled even if we have + * detected radar in the current operating channel. + * + * Return: true - If we consumed the buffer + * false - If have defered the message. + */ + +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + __lim_handle_sme_stop_bss_request(pMac, (uint32_t *) pMsg->bodyptr); + return true; +} /*** end __lim_process_sme_stop_bss_req() ***/ + +void lim_process_sme_del_bss_rsp(tpAniSirGlobal pMac, + uint32_t body, tpPESession psessionEntry) +{ + + (void)body; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_ibss_delete(pMac, psessionEntry); + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, eSIR_SME_SUCCESS, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + return; +} + +/** + * __lim_process_sme_assoc_cnf_new() - process sme assoc/reassoc cnf + * + * @mac_ctx: pointer to mac context + * @msg_type: message type + * @msg_buf: pointer to the SME message buffer + * + * This function handles SME_ASSOC_CNF/SME_REASSOC_CNF + * in BTAMP AP. + * + * Return: None + */ + +void __lim_process_sme_assoc_cnf_new(tpAniSirGlobal mac_ctx, uint32_t msg_type, + uint32_t *msg_buf) +{ + tSirSmeAssocCnf assoc_cnf; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + uint8_t session_id; + tpSirAssocReq assoc_req; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL ")); + goto end; + } + + cdf_mem_copy(&assoc_cnf, msg_buf, sizeof(struct sSirSmeAssocCnf)); + if (!__lim_is_sme_assoc_cnf_valid(&assoc_cnf)) { + lim_log(mac_ctx, LOGE, + FL("Received invalid SME_RE(ASSOC)_CNF message ")); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, assoc_cnf.bssId, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto end; + } + + if ((!LIM_IS_AP_ROLE(session_entry) && + !LIM_IS_BT_AMP_AP_ROLE(session_entry)) || + ((session_entry->limSmeState != eLIM_SME_NORMAL_STATE) && + (session_entry->limSmeState != + eLIM_SME_NORMAL_CHANNEL_SCAN_STATE))) { + lim_log(mac_ctx, LOGE, FL( + "Rcvd unexpected msg %X in state %X, in role %X"), + msg_type, session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto end; + } + sta_ds = dph_get_hash_entry(mac_ctx, assoc_cnf.aid, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Rcvd invalid msg %X due to no STA ctx, aid %d, peer "), + msg_type, assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peerMacAddr, LOG1); + + /* + * send a DISASSOC_IND message to WSM to make sure + * the state in WSM and LIM is the same + */ + lim_send_sme_disassoc_ntf(mac_ctx, assoc_cnf.peerMacAddr, + eSIR_SME_STA_NOT_ASSOCIATED, + eLIM_PEER_ENTITY_DISASSOC, assoc_cnf.aid, + session_entry->smeSessionId, + session_entry->transactionId, + session_entry); + goto end; + } + if (!cdf_mem_compare((uint8_t *)sta_ds->staAddr, + (uint8_t *) assoc_cnf.peerMacAddr, + sizeof(tSirMacAddr))) { + lim_log(mac_ctx, LOG1, FL( + "peerMacAddr mismatched for aid %d, peer "), + assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peerMacAddr, LOG1); + goto end; + } + + if ((sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ASSOC_CNF_STATE) || + ((sta_ds->mlmStaContext.subType == LIM_ASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF)) || + ((sta_ds->mlmStaContext.subType == LIM_REASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF))) { + lim_log(mac_ctx, LOG1, FL( + "not in MLM_WT_ASSOC_CNF_STATE, for aid %d, peer" + "StaD mlmState : %d"), + assoc_cnf.aid, sta_ds->mlmStaContext.mlmState); + lim_print_mac_addr(mac_ctx, assoc_cnf.peerMacAddr, LOG1); + goto end; + } + /* + * Deactivate/delet CNF_WAIT timer since ASSOC_CNF + * has been received + */ + lim_log(mac_ctx, LOG1, FL("Received SME_ASSOC_CNF. Delete Timer")); + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_CNF_WAIT_TIMER, sta_ds->assocId); + + if (assoc_cnf.statusCode == eSIR_SME_SUCCESS) { + /* + * In BTAMP-AP, PE already finished the WMA_ADD_STA sequence + * when it had received Assoc Request frame. Now, PE just needs + * to send association rsp frame to the requesting BTAMP-STA. + */ + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + lim_log(mac_ctx, LOG1, + FL("sending Assoc Rsp frame to STA (assoc id=%d) "), + sta_ds->assocId); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_SUCCESS, + sta_ds->assocId, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, sta_ds, + session_entry); + goto end; + } else { + /* + * SME_ASSOC_CNF status is non-success, so STA is not allowed + * to be associated since the HAL sta entry is created for + * denied STA we need to remove this HAL entry. + * So to do that set updateContext to 1 + */ + if (!sta_ds->mlmStaContext.updateContext) + sta_ds->mlmStaContext.updateContext = 1; + lim_log(mac_ctx, LOG1, + FL("Recv Assoc Cnf, status Code : %d(assoc id=%d) "), + assoc_cnf.statusCode, sta_ds->assocId); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, + true, sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + } +end: + if (((session_entry != NULL) && (sta_ds != NULL)) && + (session_entry->parsedAssocReq[sta_ds->assocId] != NULL)) { + assoc_req = (tpSirAssocReq) + session_entry->parsedAssocReq[sta_ds->assocId]; + if (assoc_req->assocReqFrame) { + cdf_mem_free(assoc_req->assocReqFrame); + assoc_req->assocReqFrame = NULL; + } + cdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +static void __lim_process_sme_addts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpDphHashNode pStaDs; + tSirMacAddr peerMac; + tpSirAddtsReq pSirAddts; + uint32_t timeout; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionId */ + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + pSirAddts = (tpSirAddtsReq) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pSirAddts->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, "Session Does not exist for given bssId"); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_REQ_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* if sta + * - verify assoc state + * - send addts request to ap + * - wait for addts response from ap + * if ap, just ignore with error log + */ + PELOG1(lim_log(pMac, LOG1, + FL("Received SME_ADDTS_REQ (TSid %d, UP %d)"), + pSirAddts->req.tspec.tsinfo.traffic.tsid, + pSirAddts->req.tspec.tsinfo.traffic.userPrio); + ) + + if (!LIM_IS_STA_ROLE(psessionEntry) && + !LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, "AddTs received on AP - ignoring");) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + /* Ignore the request if STA is in 11B mode. */ + if (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11B) { + PELOGE(lim_log + (pMac, LOGE, + "AddTS received while Dot11Mode is 11B - ignoring"); + ) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + PELOGE(lim_log + (pMac, LOGE, "Cannot find AP context for addts req"); + ) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if ((!pStaDs->valid) || (pStaDs->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + lim_log(pMac, LOGE, "AddTs received in invalid MLM state"); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + pSirAddts->req.wsmTspecPresent = 0; + pSirAddts->req.wmeTspecPresent = 0; + pSirAddts->req.lleTspecPresent = 0; + + if ((pStaDs->wsmEnabled) && + (pSirAddts->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + pSirAddts->req.wsmTspecPresent = 1; + else if (pStaDs->wmeEnabled) + pSirAddts->req.wmeTspecPresent = 1; + else if (pStaDs->lleEnabled) + pSirAddts->req.lleTspecPresent = 1; + else { + PELOGW(lim_log + (pMac, LOGW, FL("ADDTS_REQ ignore - qos is disabled")); + ) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(pMac, LOGE, + "AddTs received in invalid LIMsme state (%d)", + psessionEntry->limSmeState); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if (pMac->lim.gLimAddtsSent) { + lim_log(pMac, LOGE, + "Addts (token %d, tsid %d, up %d) is still pending", + pMac->lim.gLimAddtsReq.req.dialogToken, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic.tsid, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic. + userPrio); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + sir_copy_mac_addr(peerMac, psessionEntry->bssId); + + /* save the addts request */ + pMac->lim.gLimAddtsSent = true; + cdf_mem_copy((uint8_t *) &pMac->lim.gLimAddtsReq, + (uint8_t *) pSirAddts, sizeof(tSirAddtsReq)); + + /* ship out the message now */ + lim_send_addts_req_action_frame(pMac, peerMac, &pSirAddts->req, + psessionEntry); + PELOG1(lim_log(pMac, LOG1, "Sent ADDTS request");) + /* start a timer to wait for the response */ + if (pSirAddts->timeout) + timeout = pSirAddts->timeout; + else if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &timeout) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Cfg param %d (Addts Rsp Timeout)"), + WNI_CFG_ADDTS_RSP_TIMEOUT); + return; + } + + timeout = SYS_MS_TO_TICKS(timeout); + if (tx_timer_change(&pMac->lim.limTimers.gLimAddtsRspTimer, timeout, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer change failed!")); + return; + } + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_change_context(&pMac->lim.limTimers.gLimAddtsRspTimer, + pMac->lim.gLimAddtsRspTimerCount) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer change failed!")); + return; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_ADDTS_RSP_TIMER)); + + /* add the sessionId to the timer object */ + pMac->lim.limTimers.gLimAddtsRspTimer.sessionId = sessionId; + if (tx_timer_activate(&pMac->lim.limTimers.gLimAddtsRspTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer activation failed!")); + return; + } + return; +} + +static void __lim_process_sme_delts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMacAddr peerMacAddr; + uint8_t ac; + tSirMacTSInfo *pTsinfo; + tpSirDeltsReq pDeltsReq = (tpSirDeltsReq) pMsgBuf; + tpDphHashNode pStaDs = NULL; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t status = eSIR_SUCCESS; + uint8_t smesessionId; + uint16_t smetransactionId; + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + psessionEntry = pe_find_session_by_bssid(pMac, + pDeltsReq->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, "Session Does not exist for given bssId"); + status = eSIR_FAILURE; + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_REQ_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (eSIR_SUCCESS != + lim_validate_delts_req(pMac, pDeltsReq, peerMacAddr, psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, FL("lim_validate_delts_req failed"));) + status = eSIR_FAILURE; + lim_send_sme_delts_rsp(pMac, pDeltsReq, eSIR_FAILURE, psessionEntry, + smesessionId, smetransactionId); + return; + } + + lim_log(pMac, LOG1, + FL("Sent DELTS request to station with assocId = %d MacAddr = " + MAC_ADDRESS_STR), + pDeltsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDeltsReq->req.wmeTspecPresent, + &pDeltsReq->req.tsinfo, + &pDeltsReq->req.tspec, psessionEntry); + + pTsinfo = + pDeltsReq->req.wmeTspecPresent ? &pDeltsReq->req.tspec. + tsinfo : &pDeltsReq->req.tsinfo; + + /* We've successfully send DELTS frame to AP. Update the + * dynamic UAPSD mask. The AC for this TSPEC to be deleted + * is no longer trigger enabled or delivery enabled + */ + lim_set_tspec_uapsd_mask_per_session(pMac, psessionEntry, + pTsinfo, CLEAR_UAPSD_MASK); + + /* We're deleting the TSPEC, so this particular AC is no longer + * admitted. PE needs to downgrade the EDCA + * parameters(for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(pTsinfo->traffic.userPrio); + + if (pTsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + + lim_set_active_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParamsActive, + pStaDs->bssId); + status = eSIR_SUCCESS; + } else { + lim_log(pMac, LOGE, FL("Self entry missing in Hash Table ")); + status = eSIR_FAILURE; + } +#ifdef FEATURE_WLAN_ESE +#ifdef FEATURE_WLAN_ESE_UPLOAD + lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); +#else + lim_deactivate_and_change_timer(pMac, eLIM_TSM_TIMER); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ +#endif + + /* send an sme response back */ +end: + lim_send_sme_delts_rsp(pMac, pDeltsReq, eSIR_SUCCESS, psessionEntry, + smesessionId, smetransactionId); +} + +void lim_process_sme_addts_rsp_timeout(tpAniSirGlobal pMac, uint32_t param) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession psessionEntry; + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimAddtsRspTimer. + sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry) && + !LIM_IS_BT_AMP_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGW, "AddtsRspTimeout in non-Sta role (%d)", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + pMac->lim.gLimAddtsSent = false; + return; + } + + if (!pMac->lim.gLimAddtsSent) { + lim_log(pMac, LOGW, "AddtsRspTimeout but no AddtsSent"); + return; + } + + if (param != pMac->lim.gLimAddtsRspTimerCount) { + lim_log(pMac, LOGE, + FL("Invalid AddtsRsp Timer count %d (exp %d)"), param, + pMac->lim.gLimAddtsRspTimerCount); + return; + } + /* this a real response timeout */ + pMac->lim.gLimAddtsSent = false; + pMac->lim.gLimAddtsRspTimerCount++; + + lim_send_sme_addts_rsp(pMac, true, eSIR_SME_ADDTS_RSP_TIMEOUT, + psessionEntry, pMac->lim.gLimAddtsReq.req.tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); +} + +/** + * __lim_process_sme_get_statistics_request() + * + ***FUNCTION: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void +__lim_process_sme_get_statistics_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpAniGetPEStatsReq pPEStatsReq; + tSirMsgQ msgQ; + + pPEStatsReq = (tpAniGetPEStatsReq) pMsgBuf; + + msgQ.type = WMA_GET_STATISTICS_REQ; + + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (eSIR_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + cdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + lim_log(pMac, LOGP, "Unable to forward request"); + return; + } + + return; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + *FUNCTION: __lim_process_sme_get_tsm_stats_request() + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void +__lim_process_sme_get_tsm_stats_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msgQ; + + msgQ.type = WMA_TSM_STATS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (eSIR_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + cdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + lim_log(pMac, LOGP, "Unable to forward request"); + return; + } +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +static void +__lim_process_sme_update_apwpsi_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirUpdateAPWPSIEsReq pUpdateAPWPSIEsReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + PELOG1(lim_log(pMac, LOG1, FL("received UPDATE_APWPSIEs_REQ message"));); + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pUpdateAPWPSIEsReq = cdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq)); + if (NULL == pUpdateAPWPSIEsReq) { + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for pUpdateAPWPSIEsReq")); + return; + } + cdf_mem_copy(pUpdateAPWPSIEsReq, pMsgBuf, + sizeof(struct sSirUpdateAPWPSIEsReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + pUpdateAPWPSIEsReq->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("Session does not exist for given BSSID")); + goto end; + } + + cdf_mem_copy(&psessionEntry->APWPSIEs, &pUpdateAPWPSIEsReq->APWPSIEs, + sizeof(tSirAPWPSIEs)); + + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + +end: + cdf_mem_free(pUpdateAPWPSIEsReq); + return; +} + +void +lim_send_vdev_restart(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint8_t sessionId) +{ + tpHalHiddenSsidVdevRestart pHalHiddenSsidVdevRestart = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: Invalid parameters", __func__, + __LINE__); + ) + return; + } + + pHalHiddenSsidVdevRestart = + cdf_mem_malloc(sizeof(tHalHiddenSsidVdevRestart)); + if (NULL == pHalHiddenSsidVdevRestart) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: Unable to allocate memory", + __func__, __LINE__); + ) + return; + } + + pHalHiddenSsidVdevRestart->ssidHidden = psessionEntry->ssidHidden; + pHalHiddenSsidVdevRestart->sessionId = sessionId; + + msgQ.type = WMA_HIDDEN_SSID_VDEV_RESTART; + msgQ.bodyptr = pHalHiddenSsidVdevRestart; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: wma_post_ctrl_msg() failed", __func__, + __LINE__); + ) + cdf_mem_free(pHalHiddenSsidVdevRestart); + } +} + +static void __lim_process_sme_hide_ssid(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirUpdateParams pUpdateParams; + tpPESession psessionEntry; + + PELOG1(lim_log(pMac, LOG1, FL("received HIDE_SSID message"));); + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pUpdateParams = (tpSirUpdateParams) pMsgBuf; + + psessionEntry = pe_find_session_by_session_id(pMac, + pUpdateParams->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + "Session does not exist for given sessionId %d", + pUpdateParams->sessionId); + return; + } + + /* Update the session entry */ + psessionEntry->ssidHidden = pUpdateParams->ssidHidden; + + /* Send vdev restart */ + lim_send_vdev_restart(pMac, psessionEntry, pUpdateParams->sessionId); + + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + + return; +} /*** end __lim_process_sme_hide_ssid(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +static void __lim_process_sme_set_wparsni_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirUpdateAPWPARSNIEsReq pUpdateAPWPARSNIEsReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pUpdateAPWPARSNIEsReq = cdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq)); + if (NULL == pUpdateAPWPARSNIEsReq) { + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for pUpdateAPWPARSNIEsReq")); + return; + } + cdf_mem_copy(pUpdateAPWPARSNIEsReq, pMsgBuf, + sizeof(struct sSirUpdateAPWPARSNIEsReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + pUpdateAPWPARSNIEsReq->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("Session does not exist for given BSSID")); + goto end; + } + + cdf_mem_copy(&psessionEntry->pLimStartBssReq->rsnIE, + &pUpdateAPWPARSNIEsReq->APWPARSNIEs, sizeof(tSirRSNie)); + + lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(pMac, + &psessionEntry-> + pLimStartBssReq->rsnIE, + psessionEntry); + + psessionEntry->pLimStartBssReq->privacy = 1; + psessionEntry->privacy = 1; + + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + +end: + cdf_mem_free(pUpdateAPWPARSNIEsReq); + return; +} /*** end __lim_process_sme_set_wparsni_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +/* + Update the beacon Interval dynamically if beaconInterval is different in MCC + */ +static void __lim_process_sme_change_bi(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirChangeBIParams pChangeBIParams; + tpPESession psessionEntry; + uint8_t sessionId = 0; + tUpdateBeaconParams beaconParams; + + PELOG1(lim_log(pMac, LOG1, + FL("received Update Beacon Interval message")); + ); + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + cdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + pChangeBIParams = (tpSirChangeBIParams) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pChangeBIParams->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given BSSID")); + return; + } + + /*Update sessionEntry Beacon Interval */ + if (psessionEntry->beaconParams.beaconInterval != + pChangeBIParams->beaconInterval) { + psessionEntry->beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + } + + /*Update sch beaconInterval */ + if (pMac->sch.schObject.gSchBeaconInterval != + pChangeBIParams->beaconInterval) { + pMac->sch.schObject.gSchBeaconInterval = + pChangeBIParams->beaconInterval; + + PELOG1(lim_log(pMac, LOG1, + FL + ("LIM send update BeaconInterval Indication : %d"), + pChangeBIParams->beaconInterval); + ); + + if (false == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + + beaconParams.bssIdx = psessionEntry->bssIdx; + /* Set change in beacon Interval */ + beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + beaconParams.paramChangeBitmap = + PARAM_BCN_INTERVAL_CHANGED; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } + + return; +} /*** end __lim_process_sme_change_bi(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +#ifdef QCA_HT_2040_COEX +static void __lim_process_sme_set_ht2040_mode(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + tpSirSetHT2040Mode pSetHT2040Mode; + tpPESession psessionEntry; + uint8_t sessionId = 0; + cds_msg_t msg; + tUpdateVHTOpMode *pHtOpMode = NULL; + uint16_t staId = 0; + tpDphHashNode pStaDs = NULL; + + PELOG1(lim_log(pMac, LOG1, FL("received Set HT 20/40 mode message"));); + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pSetHT2040Mode = (tpSirSetHT2040Mode) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pSetHT2040Mode->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOG1, + FL("Session does not exist for given BSSID ")); + lim_print_mac_addr(pMac, pSetHT2040Mode->bssId, LOG1); + return; + } + + lim_log(pMac, LOG1, FL("Update session entry for cbMod=%d"), + pSetHT2040Mode->cbMode); + /*Update sessionEntry HT related fields */ + switch (pSetHT2040Mode->cbMode) { + case PHY_SINGLE_CHANNEL_CENTERED: + psessionEntry->htSecondaryChannelOffset = + PHY_SINGLE_CHANNEL_CENTERED; + psessionEntry->htRecommendedTxWidthSet = 0; + if (pSetHT2040Mode->obssEnabled) + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_40MHZ; + else + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_20MHZ; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + default: + lim_log(pMac, LOGE, FL("Invalid cbMode")); + return; + } + + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + + /* update OP Mode for each associated peer */ + for (staId = 0; staId < psessionEntry->dph.dphHashTable.size; staId++) { + pStaDs = dph_get_hash_entry(pMac, staId, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + + if (pStaDs->valid && pStaDs->htSupportedChannelWidthSet) { + pHtOpMode = cdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + lim_log(pMac, LOGE, + FL + ("%s: Not able to allocate memory for setting OP mode"), + __func__); + return; + } + pHtOpMode->opMode = + (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) ? + eHT_CHANNEL_WIDTH_20MHZ : eHT_CHANNEL_WIDTH_40MHZ; + pHtOpMode->staId = staId; + cdf_mem_copy(pHtOpMode->peer_mac, &pStaDs->staAddr, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + lim_log(pMac, LOGE, + FL + ("%s: Not able to post WMA_UPDATE_OP_MODE message to WMA"), + __func__); + cdf_mem_free(pHtOpMode); + return; + } + lim_log(pMac, LOG1, + FL + ("%s: Notifed FW about OP mode: %d for staId=%d"), + __func__, pHtOpMode->opMode, staId); + + } else + lim_log(pMac, LOG1, + FL("%s: station %d does not support HT40\n"), + __func__, staId); + } + + return; +} +#endif + +/* -------------------------------------------------------------------- */ +/** + * __lim_process_report_message + * + * FUNCTION: Processes the next received Radio Resource Management message + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void __lim_process_report_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ +#ifdef WLAN_FEATURE_VOWIFI + switch (pMsg->type) { + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + rrm_process_neighbor_report_req(pMac, pMsg->bodyptr); + break; + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + { + rrm_process_beacon_report_xmit(pMac, pMsg->bodyptr); + } + break; + } +#endif +} + +#if defined(FEATURE_WLAN_ESE) || defined(WLAN_FEATURE_VOWIFI) +/* -------------------------------------------------------------------- */ +/** + * lim_send_set_max_tx_power_req + * + * FUNCTION: Send SIR_HAL_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, tPowerdBm txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + if (pSessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: Inavalid parameters", __func__, + __LINE__); + ) + return eSIR_FAILURE; + } + + pMaxTxParams = cdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory for pMaxTxParams ")); + return eSIR_MEM_ALLOC_FAILED; + + } +#if defined(WLAN_VOWIFI_DEBUG) || defined(FEATURE_WLAN_ESE) + lim_log(pMac, LOG1, + FL("pMaxTxParams allocated...will be freed in other module")); +#endif + if (pMaxTxParams == NULL) { + lim_log(pMac, LOGE, FL("pMaxTxParams is NULL")); + return eSIR_FAILURE; + } + pMaxTxParams->power = txPower; + cdf_mem_copy(pMaxTxParams->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMaxTxParams->selfStaMacAddr, pSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + PELOG1(lim_log + (pMac, LOG1, FL("Posting WMA_SET_MAX_TX_POWER_REQ to WMA")); + ) + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() failed")); + cdf_mem_free(pMaxTxParams); + } + return retCode; +} +#endif + +/** + * __lim_process_sme_register_mgmt_frame_req() - process sme reg mgmt frame req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process eWNI_SME_REGISTER_MGMT_FRAME_REQ message + * from SME. It Register this information within PE. + * + * Return: None + */ +static void __lim_process_sme_register_mgmt_frame_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + CDF_STATUS cdf_status; + tpSirRegisterMgmtFrame sme_req = (tpSirRegisterMgmtFrame)msg_buf; + struct mgmt_frm_reg_info *lim_mgmt_regn = NULL; + struct mgmt_frm_reg_info *next = NULL; + bool match = false; + + lim_log(mac_ctx, LOG1, FL( + "registerFrame %d, frameType %d, matchLen %d"), + sme_req->registerFrame, sme_req->frameType, + sme_req->matchLen); + /* First check whether entry exists already */ + cdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + cdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t **) &lim_mgmt_regn); + cdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (lim_mgmt_regn != NULL) { + if (lim_mgmt_regn->frameType != sme_req->frameType) + goto skip_match; + if (sme_req->matchLen) { + if ((lim_mgmt_regn->matchLen == sme_req->matchLen) && + (cdf_mem_compare(lim_mgmt_regn->matchData, + sme_req->matchData, + lim_mgmt_regn->matchLen))) { + /* found match! */ + match = true; + break; + } + } else { + /* found match! */ + match = true; + break; + } +skip_match: + cdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + cdf_status = cdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t *)lim_mgmt_regn, + (cdf_list_node_t **)&next); + cdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + lim_mgmt_regn = next; + next = NULL; + } + if (match) { + cdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + cdf_list_remove_node( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (cdf_list_node_t *)lim_mgmt_regn); + cdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + cdf_mem_free(lim_mgmt_regn); + } + + if (sme_req->registerFrame) { + lim_mgmt_regn = + cdf_mem_malloc(sizeof(struct mgmt_frm_reg_info) + + sme_req->matchLen); + if (lim_mgmt_regn != NULL) { + cdf_mem_set((void *)lim_mgmt_regn, + sizeof(struct mgmt_frm_reg_info) + + sme_req->matchLen, 0); + lim_mgmt_regn->frameType = sme_req->frameType; + lim_mgmt_regn->matchLen = sme_req->matchLen; + lim_mgmt_regn->sessionId = sme_req->sessionId; + if (sme_req->matchLen) { + cdf_mem_copy(lim_mgmt_regn->matchData, + sme_req->matchData, + sme_req->matchLen); + } + cdf_mutex_acquire( + &mac_ctx->lim.lim_frame_register_lock); + cdf_list_insert_front(&mac_ctx->lim. + gLimMgmtFrameRegistratinQueue, + &lim_mgmt_regn->node); + cdf_mutex_release( + &mac_ctx->lim.lim_frame_register_lock); + } + } + return; +} + +static void __lim_deregister_deferred_sme_req_after_noa_start(tpAniSirGlobal pMac) +{ + lim_log(pMac, LOG1, FL("Dereg msgType %d"), + pMac->lim.gDeferMsgTypeForNOA); + pMac->lim.gDeferMsgTypeForNOA = 0; + if (pMac->lim.gpDefdSmeMsgForNOA != NULL) { + /* __lim_process_sme_scan_req consumed the buffer. We can free it. */ + cdf_mem_free(pMac->lim.gpDefdSmeMsgForNOA); + pMac->lim.gpDefdSmeMsgForNOA = NULL; + } +} + +/** + * lim_process_regd_defd_sme_req_after_noa_start() + * + * mac_ctx: Pointer to Global MAC structure + * + * This function is called to process deferred sme req message + * after noa start. + * + * Return: None + */ +void lim_process_regd_defd_sme_req_after_noa_start(tpAniSirGlobal mac_ctx) +{ + bool buf_consumed = true; + + lim_log(mac_ctx, LOG1, FL("Process defd sme req %d"), + mac_ctx->lim.gDeferMsgTypeForNOA); + + if ((mac_ctx->lim.gDeferMsgTypeForNOA == 0) || + (mac_ctx->lim.gpDefdSmeMsgForNOA == NULL)) { + lim_log(mac_ctx, LOGW, + FL("start rcvd from FW when no sme deferred msg pending. Do nothing. ")); + lim_log(mac_ctx, LOGW, + FL("It may happen when NOA start ind and timeout happen at the same time")); + return; + } + switch (mac_ctx->lim.gDeferMsgTypeForNOA) { + case eWNI_SME_SCAN_REQ: + __lim_process_sme_scan_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + break; +#ifdef FEATURE_OEM_DATA_SUPPORT + case eWNI_SME_OEM_DATA_REQ: + __lim_process_sme_oem_data_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + break; +#endif + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + buf_consumed = lim_process_remain_on_chnl_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + /* + * lim_process_remain_on_chnl_req doesnt want us to free + * the buffer since it is freed in lim_remain_on_chn_rsp. + * this change is to avoid "double free" + */ + if (false == buf_consumed) + mac_ctx->lim.gpDefdSmeMsgForNOA = NULL; + break; + case eWNI_SME_JOIN_REQ: + __lim_process_sme_join_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + break; + default: + lim_log(mac_ctx, LOGE, FL("Unknown deferred msg type %d"), + mac_ctx->lim.gDeferMsgTypeForNOA); + break; + } + __lim_deregister_deferred_sme_req_after_noa_start(mac_ctx); +} + +static void +__lim_process_sme_reset_ap_caps_change(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirResetAPCapsChange pResetCapsChange; + tpPESession psessionEntry; + uint8_t sessionId = 0; + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pResetCapsChange = (tpSirResetAPCapsChange) pMsgBuf; + psessionEntry = + pe_find_session_by_bssid(pMac, pResetCapsChange->bssId, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given BSSID")); + return; + } + + psessionEntry->limSentCapsChangeNtf = false; + return; +} + +/** + * lim_process_sme_req_messages() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ + +bool lim_process_sme_req_messages(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + bool bufConsumed = true; /* Set this flag to false within case block of any following message, that doesnt want pMsgBuf to be freed. */ + uint32_t *pMsgBuf = pMsg->bodyptr; + tpSirSmeScanReq pScanReq; + PELOG1(lim_log + (pMac, LOG1, + FL + ("LIM Received SME Message %s(%d) Global LimSmeState:%s(%d) Global LimMlmState: %s(%d)"), + lim_msg_str(pMsg->type), pMsg->type, + lim_sme_state_str(pMac->lim.gLimSmeState), pMac->lim.gLimSmeState, + lim_mlm_state_str(pMac->lim.gLimMlmState), pMac->lim.gLimMlmState); + ) + + pScanReq = (tpSirSmeScanReq) pMsgBuf; + /* If no insert NOA required then execute the code below */ + + switch (pMsg->type) { + case eWNI_SME_SYS_READY_IND: + bufConsumed = __lim_process_sme_sys_ready_ind(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BSS_REQ: + bufConsumed = __lim_process_sme_start_bss_req(pMac, pMsg); + break; + + case eWNI_SME_SCAN_REQ: + __lim_process_sme_scan_req(pMac, pMsgBuf); + break; + +#ifdef FEATURE_OEM_DATA_SUPPORT + case eWNI_SME_OEM_DATA_REQ: + __lim_process_sme_oem_data_req(pMac, pMsgBuf); + break; +#endif + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + bufConsumed = lim_process_remain_on_chnl_req(pMac, pMsgBuf); + break; + + case eWNI_SME_UPDATE_NOA: + __lim_process_sme_no_a_update(pMac, pMsgBuf); + break; + case eWNI_SME_CLEAR_DFS_CHANNEL_LIST: + __lim_process_clear_dfs_channel_list(pMac, pMsg); + break; + case eWNI_SME_JOIN_REQ: + __lim_process_sme_join_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REASSOC_REQ: + __lim_process_sme_reassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_REQ: + __lim_process_sme_disassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + __lim_process_sme_disassoc_cnf(pMac, pMsgBuf); + break; + + case eWNI_SME_DEAUTH_REQ: + __lim_process_sme_deauth_req(pMac, pMsgBuf); + break; + + case eWNI_SME_SETCONTEXT_REQ: + __lim_process_sme_set_context_req(pMac, pMsgBuf); + break; + + case eWNI_SME_STOP_BSS_REQ: + bufConsumed = __lim_process_sme_stop_bss_req(pMac, pMsg); + break; + + case eWNI_SME_ASSOC_CNF: + if (pMsg->type == eWNI_SME_ASSOC_CNF) + PELOG1(lim_log(pMac, + LOG1, FL("Received ASSOC_CNF message"));) + __lim_process_sme_assoc_cnf_new(pMac, pMsg->type, + pMsgBuf); + break; + + case eWNI_SME_ADDTS_REQ: + PELOG1(lim_log(pMac, LOG1, FL("Received ADDTS_REQ message"));) + __lim_process_sme_addts_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DELTS_REQ: + PELOG1(lim_log(pMac, LOG1, FL("Received DELTS_REQ message"));) + __lim_process_sme_delts_req(pMac, pMsgBuf); + break; + + case SIR_LIM_ADDTS_RSP_TIMEOUT: + PELOG1(lim_log + (pMac, LOG1, + FL("Received SIR_LIM_ADDTS_RSP_TIMEOUT message ")); + ) + lim_process_sme_addts_rsp_timeout(pMac, pMsg->bodyval); + break; + + case eWNI_SME_GET_STATISTICS_REQ: + __lim_process_sme_get_statistics_request(pMac, pMsgBuf); + /* HAL consumes pMsgBuf. It will be freed there. Set bufConsumed to false. */ + bufConsumed = false; + break; +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eWNI_SME_GET_TSM_STATS_REQ: + __lim_process_sme_get_tsm_stats_request(pMac, pMsgBuf); + bufConsumed = false; + break; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + case eWNI_SME_GET_ASSOC_STAS_REQ: + lim_process_sme_get_assoc_sta_info(pMac, pMsgBuf); + break; + case eWNI_SME_TKIP_CNTR_MEAS_REQ: + lim_process_tkip_counter_measures(pMac, pMsgBuf); + break; + + case eWNI_SME_HIDE_SSID_REQ: + __lim_process_sme_hide_ssid(pMac, pMsgBuf); + break; + case eWNI_SME_UPDATE_APWPSIE_REQ: + __lim_process_sme_update_apwpsi_es(pMac, pMsgBuf); + break; + case eWNI_SME_GET_WPSPBC_SESSION_REQ: + lim_process_sme_get_wpspbc_sessions(pMac, pMsgBuf); + break; + + case eWNI_SME_SET_APWPARSNIEs_REQ: + __lim_process_sme_set_wparsni_es(pMac, pMsgBuf); + break; + + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + /* Update the beaconInterval */ + __lim_process_sme_change_bi(pMac, pMsgBuf); + break; + +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + __lim_process_sme_set_ht2040_mode(pMac, pMsgBuf); + break; +#endif + +#if defined WLAN_FEATURE_VOWIFI + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + __lim_process_report_message(pMac, pMsg); + break; +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R + case eWNI_SME_FT_PRE_AUTH_REQ: + bufConsumed = (bool) lim_process_ft_pre_auth_req(pMac, pMsg); + break; + case eWNI_SME_FT_UPDATE_KEY: + lim_process_ft_update_key(pMac, pMsgBuf); + break; + + case eWNI_SME_FT_AGGR_QOS_REQ: + lim_process_ft_aggr_qos_req(pMac, pMsgBuf); + break; +#endif + + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + __lim_process_sme_register_mgmt_frame_req(pMac, pMsgBuf); + break; +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + lim_process_sme_tdls_mgmt_send_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_ADD_STA_REQ: + lim_process_sme_tdls_add_sta_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_DEL_STA_REQ: + lim_process_sme_tdls_del_sta_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_LINK_ESTABLISH_REQ: + lim_process_sme_tdls_link_establish_req(pMac, pMsgBuf); + break; +#endif + case eWNI_SME_RESET_AP_CAPS_CHANGED: + __lim_process_sme_reset_ap_caps_change(pMac, pMsgBuf); + break; + + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_channel_change_request(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_start_beacon_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_dfs_csa_ie_request(pMac, pMsgBuf); + break; + + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_update_add_ies(pMac, pMsgBuf); + break; + + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_modify_add_ies(pMac, pMsgBuf); + break; + case eWNI_SME_SET_HW_MODE_REQ: + lim_process_set_hw_mode(pMac, pMsgBuf); + break; + case eWNI_SME_NSS_UPDATE_REQ: + lim_process_nss_update_request(pMac, pMsgBuf); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + lim_process_set_dual_mac_cfg_req(pMac, pMsgBuf); + break; + case eWNI_SME_SET_IE_REQ: + lim_process_set_ie_req(pMac, pMsgBuf); + break; + default: + cdf_mem_free((void *)pMsg->bodyptr); + pMsg->bodyptr = NULL; + break; + } /* switch (msgType) */ + + return bufConsumed; +} /*** end lim_process_sme_req_messages() ***/ + +/** + * lim_process_sme_start_beacon_req() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg) +{ + tpSirStartBeaconIndication pBeaconStartInd; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + if (pMsg == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pBeaconStartInd = (tpSirStartBeaconIndication) pMsg; + psessionEntry = pe_find_session_by_bssid(pMac, + pBeaconStartInd->bssid, + &sessionId); + if (psessionEntry == NULL) { + lim_print_mac_addr(pMac, pBeaconStartInd->bssid, LOGE); + lim_log(pMac, LOGE, + FL("Session does not exist for given bssId")); + return; + } + + if (pBeaconStartInd->beaconStartStatus == true) { + /* + * Currently this Indication comes from SAP + * to start Beacon Tx on a DFS channel + * since beaconing has to be done on DFS + * channel only after CAC WAIT is completed. + * On a DFS Channel LIM does not start beacon + * Tx right after the WMA_ADD_BSS_RSP. + */ + lim_apply_configuration(pMac, psessionEntry); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, psessionEntry); + } else { + lim_log(pMac, LOGE, FL("Invalid Beacon Start Indication")); + return; + } +} + +/** + * lim_process_sme_channel_change_request() - process sme ch change req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_CHANNEL_CHANGE_REQ message + * + * Return: None + */ +static void lim_process_sme_channel_change_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirChanChangeRequest ch_change_req; + tpPESession session_entry; + uint8_t session_id; /* PE session_id */ + tPowerdBm max_tx_pwr; + uint32_t val = 0; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + ch_change_req = (tpSirChanChangeRequest)msg_buf; + + max_tx_pwr = cfg_get_regulatory_max_transmit_power(mac_ctx, + ch_change_req->targetChannel); + + if ((ch_change_req->messageType != eWNI_SME_CHANNEL_CHANGE_REQ) || + (max_tx_pwr == WMA_MAX_TXPOWER_INVALID)) { + lim_log(mac_ctx, LOGE, FL("Invalid Request/max_tx_pwr")); + return; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + ch_change_req->bssid, &session_id); + if (session_entry == NULL) { + lim_print_mac_addr(mac_ctx, ch_change_req->bssid, LOGE); + lim_log(mac_ctx, LOGE, FL( + "Session does not exist for given bssId")); + return; + } + + if (session_entry->currentOperChannel == + ch_change_req->targetChannel) { + lim_log(mac_ctx, LOGE, FL("target CH is same as current CH")); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_SAP_DFS; + else + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + + lim_log(mac_ctx, LOGW, FL( + "switch old chnl %d to new chnl %d, ch_bw %d"), + session_entry->currentOperChannel, + ch_change_req->targetChannel, + ch_change_req->channel_width); + + /* Store the New Channel Params in session_entry */ + session_entry->ch_width = ch_change_req->channel_width; + session_entry->ch_center_freq_seg0 = + ch_change_req->center_freq_seg_0; + session_entry->ch_center_freq_seg1 = + ch_change_req->center_freq_seg_1; + session_entry->htSecondaryChannelOffset = ch_change_req->cbMode; + session_entry->htSupportedChannelWidthSet = + (ch_change_req->channel_width ? 1 : 0); + session_entry->htRecommendedTxWidthSet = + session_entry->htSupportedChannelWidthSet; + session_entry->currentOperChannel = + ch_change_req->targetChannel; + session_entry->limRFBand = + lim_get_rf_band(session_entry->currentOperChannel); + /* Initialize 11h Enable Flag */ + if (SIR_BAND_5_GHZ == session_entry->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED")); + } + + session_entry->lim11hEnable = val; + session_entry->dot11mode = ch_change_req->dot11mode; + cdf_mem_copy(&session_entry->rateSet, + &ch_change_req->operational_rateset, + sizeof(session_entry->rateSet)); + cdf_mem_copy(&session_entry->extRateSet, + &ch_change_req->extended_rateset, + sizeof(session_entry->extRateSet)); + lim_set_channel(mac_ctx, ch_change_req->targetChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + max_tx_pwr, session_entry->peSessionId); +} + +/****************************************************************************** +* lim_start_bss_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and its length and then malloc for +* dst buffer update the same +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param pMac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_start_bss_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (srcDataLen > 0 && pSrcData_buff != NULL) { + *pDstDataLen = srcDataLen; + + *pDstData_buff = cdf_mem_malloc(*pDstDataLen); + + if (NULL == *pDstData_buff) { + lim_log(pMac, LOGE, + FL("AllocateMemory failed for pDstData_buff")); + return; + } + cdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + } else { + *pDstData_buff = NULL; + *pDstDataLen = 0; + } +} + +/****************************************************************************** +* lim_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and length if src buffer length more +* than dst buffer length then free the dst buffer and malloc for the new src +* length, and update the dst buffer and length. But if dst buffer is bigger +* than src buffer length then it just update the dst buffer and length +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param pMac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (NULL == pSrcData_buff) { + lim_log(pMac, LOGE, FL("src buffer is null.")); + return; + } + + if (srcDataLen > *pDstDataLen) { + *pDstDataLen = srcDataLen; + /* free old buffer */ + cdf_mem_free(*pDstData_buff); + /* allocate a new */ + *pDstData_buff = cdf_mem_malloc(*pDstDataLen); + + if (NULL == *pDstData_buff) { + lim_log(pMac, LOGE, FL("Memory allocation failed.")); + *pDstDataLen = 0; + return; + } + } + + /* copy the content of buffer into dst buffer + */ + *pDstDataLen = srcDataLen; + cdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + +} + +/* +* lim_process_modify_add_ies() - process modify additional IE req. +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_modify_add_ies(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirModifyIEsInd modify_add_ies; + tpPESession session_entry; + uint8_t session_id; + bool ret = false; + tSirAddIeParams *add_ie_params; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + + modify_add_ies = (tpSirModifyIEsInd)msg_buf; + /* Incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + modify_add_ies->modifyIE.bssid, &session_id); + + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("Session not found for given bssid. " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(modify_add_ies->modifyIE.bssid)); + goto end; + } + if ((0 == modify_add_ies->modifyIE.ieBufferlength) || + (0 == modify_add_ies->modifyIE.ieIDLen) || + (NULL == modify_add_ies->modifyIE.pIEBuffer)) { + lim_log(mac_ctx, LOGE, + FL("Invalid request pIEBuffer %p ieBufferlength %d ieIDLen %d ieID %d. update Type %d"), + modify_add_ies->modifyIE.pIEBuffer, + modify_add_ies->modifyIE.ieBufferlength, + modify_add_ies->modifyIE.ieID, + modify_add_ies->modifyIE.ieIDLen, + modify_add_ies->updateType); + goto end; + } + add_ie_params = &session_entry->addIeParams; + switch (modify_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + /* Probe resp */ + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + if (add_ie_params->assocRespDataLen == 0) { + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_ERROR, FL( + "assoc resp add ie not present %d"), + add_ie_params->assocRespDataLen); + } + /* search through the buffer and modify the IE */ + break; + case eUPDATE_IE_PROBE_BCN: + /*probe beacon IE */ + if (ret == true && modify_add_ies->modifyIE.notify) { + lim_handle_param_update(mac_ctx, + modify_add_ies->updateType); + } + break; + default: + lim_log(mac_ctx, LOGE, FL("unhandled buffer type %d"), + modify_add_ies->updateType); + break; + } +end: + cdf_mem_free(modify_add_ies->modifyIE.pIEBuffer); + modify_add_ies->modifyIE.pIEBuffer = NULL; +} + +/* +* lim_process_update_add_ies() - process additional IE update req +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_update_add_ies(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirUpdateIEsInd update_add_ies = (tpSirUpdateIEsInd)msg_buf; + uint8_t session_id; + tpPESession session_entry; + tSirAddIeParams *addn_ie; + uint16_t new_length = 0; + uint8_t *new_ptr = NULL; + tSirUpdateIE *update_ie; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + update_ie = &update_add_ies->updateIE; + /* incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + update_ie->bssid, &session_id); + + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("Session not found for given bssid. " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(update_ie->bssid)); + goto end; + } + addn_ie = &session_entry->addIeParams; + /* if len is 0, upper layer requested freeing of buffer */ + if (0 == update_ie->ieBufferlength) { + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + cdf_mem_free(addn_ie->probeRespData_buff); + addn_ie->probeRespData_buff = NULL; + addn_ie->probeRespDataLen = 0; + break; + case eUPDATE_IE_ASSOC_RESP: + cdf_mem_free(addn_ie->assocRespData_buff); + addn_ie->assocRespData_buff = NULL; + addn_ie->assocRespDataLen = 0; + break; + case eUPDATE_IE_PROBE_BCN: + cdf_mem_free(addn_ie->probeRespBCNData_buff); + addn_ie->probeRespBCNData_buff = NULL; + addn_ie->probeRespBCNDataLen = 0; + + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + break; + } + return; + } + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + if (update_ie->append) { + /* + * In case of append, allocate new memory + * with combined length + */ + new_length = update_ie->ieBufferlength + + addn_ie->probeRespDataLen; + new_ptr = cdf_mem_malloc(new_length); + if (NULL == new_ptr) { + lim_log(mac_ctx, LOGE, FL( + "Memory allocation failed.")); + goto end; + } + /* append buffer to end of local buffers */ + cdf_mem_copy(new_ptr, addn_ie->probeRespData_buff, + addn_ie->probeRespDataLen); + cdf_mem_copy(&new_ptr[addn_ie->probeRespDataLen], + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + /* free old memory */ + cdf_mem_free(addn_ie->probeRespData_buff); + /* adjust length accordingly */ + addn_ie->probeRespDataLen = new_length; + /* save refernece of local buffer in PE session */ + addn_ie->probeRespData_buff = new_ptr; + goto end; + } + lim_update_add_ie_buffer(mac_ctx, &addn_ie->probeRespData_buff, + &addn_ie->probeRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + lim_update_add_ie_buffer(mac_ctx, &addn_ie->assocRespData_buff, + &addn_ie->assocRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_PROBE_BCN: + /* probe resp Bcn IE */ + lim_update_add_ie_buffer(mac_ctx, + &addn_ie->probeRespBCNData_buff, + &addn_ie->probeRespBCNDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + lim_log(mac_ctx, LOGE, FL("unhandled buffer type %d."), + update_add_ies->updateType); + break; + } +end: + cdf_mem_free(update_ie->pAdditionIEBuffer); + update_ie->pAdditionIEBuffer = NULL; +} + +/** + * lim_process_sme_dfs_csa_ie_request() - process sme dfs csa ie req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_sme_dfs_csa_ie_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirDfsCsaIeRequest dfs_csa_ie_req; + tpPESession session_entry = NULL; + uint32_t ch_width = 0; + uint8_t session_id; + tLimWiderBWChannelSwitchInfo *wider_bw_ch_switch; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + dfs_csa_ie_req = (tSirDfsCsaIeRequest *)msg_buf; + session_entry = pe_find_session_by_bssid(mac_ctx, + dfs_csa_ie_req->bssid, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Session not found for given BSSID" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(dfs_csa_ie_req->bssid)); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL("Invalid SystemRole %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + /* target channel */ + session_entry->gLimChannelSwitch.primaryChannel = + dfs_csa_ie_req->targetChannel; + + /* Channel switch announcement needs to be included in beacon */ + session_entry->dfsIncludeChanSwIe = true; + session_entry->gLimChannelSwitch.switchCount = LIM_MAX_CSA_IE_UPDATES; + session_entry->gLimChannelSwitch.ch_width = + dfs_csa_ie_req->ch_bandwidth; + if (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false) + session_entry->gLimChannelSwitch.switchMode = 1; + + /* + * Validate if SAP is operating HT or VHT mode and set the Channel + * Switch Wrapper element with the Wide Band Switch subelement. + */ + if (true != session_entry->vhtCapability) + goto skip_vht; + + if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ == + session_entry->vhtTxChannelWidthSet) + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + else if (WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ == + session_entry->vhtTxChannelWidthSet) + ch_width = session_entry->htSupportedChannelWidthSet; + /* Now encode the Wider Ch BW element depending on the ch width */ + wider_bw_ch_switch = &session_entry->gLimWiderBWChannelSwitch; + switch (ch_width) { + case eHT_CHANNEL_WIDTH_20MHZ: + /* + * Wide channel BW sublement in channel wrapper element is not + * required in case of 20 Mhz operation. Currently It is set + * only set in case of 40/80 Mhz Operation. + */ + session_entry->dfsIncludeChanWrapperIe = false; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case eHT_CHANNEL_WIDTH_40MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case eHT_CHANNEL_WIDTH_80MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + break; + case eHT_CHANNEL_WIDTH_160MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + break; + default: + session_entry->dfsIncludeChanWrapperIe = false; + /* + * Need to handle 80+80 Mhz Scenario. When 80+80 is supported + * set the gLimWiderBWChannelSwitch.newChanWidth to 3 + */ + lim_log(mac_ctx, LOGE, FL("Invalid Channel Width")); + break; + } + /* Fetch the center channel based on the channel width */ + wider_bw_ch_switch->newCenterChanFreq0 = + lim_get_center_channel(mac_ctx, dfs_csa_ie_req->targetChannel, + session_entry->htSecondaryChannelOffset, + wider_bw_ch_switch->newChanWidth); + /* + * This is not applicable for 20/40/80 Mhz.Only used when we support + * 80+80 Mhz operation. In case of 80+80 Mhz, this parameter indicates + * center channel frequency index of 80 Mhz channel of + * frequency segment 1. + */ + wider_bw_ch_switch->newCenterChanFreq1 = 0; +skip_vht: + /* Send CSA IE request from here */ + if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("Unable to set CSA IE in beacon")); + return; + } + + /* + * First beacon update request is sent here, the remaining updates are + * done when the FW responds back after sending the first beacon after + * the template update + */ + lim_send_beacon_ind(mac_ctx, session_entry); + lim_log(mac_ctx, LOG1, FL("Updated CSA IE, IE COUNT = %d"), + session_entry->gLimChannelSwitch.switchCount); + session_entry->gLimChannelSwitch.switchCount--; +} + +/** + * lim_process_nss_update_request() - process sme nss update req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_nss_update_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_nss_update_request *nss_update_req_ptr; + tpPESession session_entry = NULL; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + nss_update_req_ptr = (struct sir_nss_update_request *)msg_buf; + session_entry = pe_find_session_by_session_id(mac_ctx, + nss_update_req_ptr->vdev_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Session not found for given session_id %d"), + nss_update_req_ptr->vdev_id); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL("Invalid SystemRole %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + /* populate nss field in the beacon */ + session_entry->gLimOperatingMode.present = 1; + session_entry->gLimOperatingMode.rxNSS = nss_update_req_ptr->new_nss; + /* Send nss update request from here */ + if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Unable to set op mode IE in beacon")); + return; + } + + lim_send_beacon_ind(mac_ctx, session_entry); +} + +/** + * lim_process_set_ie_req() - process sme set IE request + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_set_ie_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct send_extcap_ie *msg; + CDF_STATUS status; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + msg = (struct send_extcap_ie *)msg_buf; + status = lim_send_ext_cap_ie(mac_ctx, msg->session_id, NULL, false); + if (CDF_STATUS_SUCCESS != status) + lim_log(mac_ctx, LOGE, FL("Unable to send ExtCap to FW")); + +} diff --git a/core/mac/src/pe/lim/lim_process_tdls.c b/core/mac/src/pe/lim/lim_process_tdls.c new file mode 100644 index 0000000000..fa5a0ab301 --- /dev/null +++ b/core/mac/src/pe/lim/lim_process_tdls.c @@ -0,0 +1,3267 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + * lim_process_tdls.c + * OVERVIEW: + * + * DEPENDENCIES: + * + * Are listed for each API below. + * ===========================================================================*/ + +/*=========================================================================== + + * EDIT HISTORY FOR FILE + + * This section contains comments describing changes made to the module. + * Notice that changes are listed in reverse chronological order. + + * $Header$$DateTime$$Author$ + + * when who what, where, why + * ---------- --- ------------------------------------------------------ + * 05/05/2010 Ashwani Initial Creation, added TDLS action frame + * functionality,TDLS message exchange with SME..etc.. + + ===========================================================================*/ + +/** + * \file lim_process_tdls.c + * + * \brief Code for preparing,processing and sending 802.11z action frames + * + */ + +#ifdef FEATURE_WLAN_TDLS + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "utils_parser.h" +#include "lim_assoc_utils.h" +#include "dph_hash_table.h" +#include "wma_types.h" +#include "cds_regdomain_common.h" + +/* define NO_PAD_TDLS_MIN_8023_SIZE to NOT padding: See CR#447630 + There was IOT issue with cisco 1252 open mode, where it pads + discovery req/teardown frame with some junk value up to min size. + To avoid this issue, we pad QCOM_VENDOR_IE. + If there is other IOT issue because of this bandage, define NO_PAD... + */ +#ifndef NO_PAD_TDLS_MIN_8023_SIZE +#define MIN_IEEE_8023_SIZE 46 +#define MIN_VENDOR_SPECIFIC_IE_SIZE 5 +#endif + +static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq * pAddStaReq, tpPESession psessionEntry); +void populate_dot11f_link_iden(tpAniSirGlobal pMac, tpPESession psessionEntry, + tDot11fIELinkIdentifier *linkIden, + tSirMacAddr peerMac, uint8_t reqType); +void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEExtCap *extCapability); + +void populate_dot11f_tdls_offchannel_params(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIESuppChannels *suppChannels, + tDot11fIESuppOperatingClasses * + suppOperClasses); +void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f); +tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + tDot11fIEVHTCaps *pPeerVHTCaps, + tpPESession psessionEntry); +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); + +/* + * TDLS data frames will go out/come in as non-qos data. + * so, eth_890d_header will be aligned access.. + */ +static const uint8_t eth_890d_header[] = { + 0xaa, 0xaa, 0x03, 0x00, + 0x00, 0x00, 0x89, 0x0d, +}; + +/* + * type of links used in TDLS + */ +enum tdlsLinks { + TDLS_LINK_AP, + TDLS_LINK_DIRECT +} e_tdls_link; + +/* + * node status in node searching + */ +enum tdlsLinkNodeStatus { + TDLS_NODE_NOT_FOUND, + TDLS_NODE_FOUND +} e_tdls_link_node_status; + +enum tdlsReqType { + TDLS_INITIATOR, + TDLS_RESPONDER +} e_tdls_req_type; + +typedef enum tdlsLinkSetupStatus { + TDLS_SETUP_STATUS_SUCCESS = 0, + TDLS_SETUP_STATUS_FAILURE = 37 +} etdlsLinkSetupStatus; + +/* These maps to Kernel TDLS peer capability + * flags and should get changed as and when necessary + */ +enum tdls_peer_capability { + TDLS_PEER_HT_CAP = 0, + TDLS_PEER_VHT_CAP = 1, + TDLS_PEER_WMM_CAP = 2 +} e_tdls_peer_capability; + +/* some local defines */ +#define LINK_IDEN_ADDR_OFFSET(x) (&x.LinkIdentifier) +#define PTI_LINK_IDEN_OFFSET (5) +#define PTI_BUF_STATUS_OFFSET (25) + +/* TODO, Move this parameters to configuration */ +#define PEER_PSM_SUPPORT (0) +#define TDLS_SUPPORT (1) +#define TDLS_PROHIBITED (0) +#define TDLS_CH_SWITCH_PROHIBITED (1) +/** @brief Set bit manipulation macro */ +#define SET_BIT(value, mask) ((value) |= (1 << (mask))) +/** @brief Clear bit manipulation macro */ +#define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask))) +/** @brief Check bit manipulation macro */ +#define CHECK_BIT(value, mask) ((value) & (1 << (mask))) + +#define SET_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + SET_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + SET_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#define CLEAR_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + CLEAR_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + CLEAR_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#ifdef LIM_DEBUG_TDLS + +#ifdef FEATURE_WLAN_TDLS +#define WNI_CFG_TDLS_LINK_SETUP_RSP_TIMEOUT (800) +#define WNI_CFG_TDLS_LINK_SETUP_CNF_TIMEOUT (200) +#endif + +#define IS_QOS_ENABLED(psessionEntry) ((((psessionEntry)->limQosEnabled) && \ + SIR_MAC_GET_QOS((psessionEntry)->limCurrentBssCaps)) || \ + (((psessionEntry)->limWmeEnabled) && \ + LIM_BSS_CAPS_GET(WME, (psessionEntry)->limCurrentBssQosCaps))) + +#define TID_AC_VI 4 +#define TID_AC_BK 1 + +const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) +{ + switch (tdlsActionCode) { + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_CNF); + CASE_RETURN_STRING(SIR_MAC_TDLS_TEARDOWN); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_IND); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_RSP); + } + return (const uint8_t *)"UNKNOWN"; +} +#endif +/* + * initialize TDLS setup list and related data structures. + */ +void lim_init_tdls_data(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + lim_init_peer_idxpool(pMac, pSessionEntry); + + return; +} + +/* + * prepare TDLS frame header, it includes + * | | | | + * |802.11 header|RFC1042 header|TDLS_PYLOAD_TYPE|PAYLOAD + * | | | | + */ +static uint32_t lim_prepare_tdls_frame_header(tpAniSirGlobal pMac, uint8_t *pFrame, + tDot11fIELinkIdentifier *link_iden, + uint8_t tdlsLinkType, uint8_t reqType, + uint8_t tid, + tpPESession psessionEntry) +{ + tpSirMacDataHdr3a pMacHdr; + uint32_t header_offset = 0; + uint8_t *addr1 = NULL; + uint8_t *addr3 = NULL; + uint8_t toDs = (tdlsLinkType == TDLS_LINK_AP) + ? ANI_TXDIR_TODS : ANI_TXDIR_IBSS; + uint8_t *peerMac = (reqType == TDLS_INITIATOR) + ? link_iden->RespStaAddr : link_iden->InitStaAddr; + uint8_t *staMac = (reqType == TDLS_INITIATOR) + ? link_iden->InitStaAddr : link_iden->RespStaAddr; + + pMacHdr = (tpSirMacDataHdr3a) (pFrame); + + /* + * if TDLS frame goes through the AP link, it follows normal address + * pattern, if TDLS frame goes thorugh the direct link, then + * A1--> Peer STA addr, A2-->Self STA address, A3--> BSSID + */ + (tdlsLinkType == TDLS_LINK_AP) ? ((addr1 = (link_iden->bssid)), + (addr3 = (peerMac))) + : ((addr1 = (peerMac)), (addr3 = (link_iden->bssid))); + /* + * prepare 802.11 header + */ + pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + pMacHdr->fc.type = SIR_MAC_DATA_FRAME; + pMacHdr->fc.subType = + IS_QOS_ENABLED(psessionEntry) ? SIR_MAC_DATA_QOS_DATA : + SIR_MAC_DATA_DATA; + + /* + * TL is not setting up below fields, so we are doing it here + */ + pMacHdr->fc.toDS = toDs; + pMacHdr->fc.powerMgmt = 0; + pMacHdr->fc.wep = (psessionEntry->encryptType == eSIR_ED_NONE) ? 0 : 1; + + cdf_mem_copy((uint8_t *) pMacHdr->addr1, + (uint8_t *) addr1, sizeof(tSirMacAddr)); + cdf_mem_copy((uint8_t *) pMacHdr->addr2, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) pMacHdr->addr3, + (uint8_t *) (addr3), sizeof(tSirMacAddr)); + + lim_log(pMac, LOG1, + FL( + "Preparing TDLS frame header to %s A1:" + MAC_ADDRESS_STR", A2:"MAC_ADDRESS_STR", A3:" + MAC_ADDRESS_STR + ), + (tdlsLinkType == TDLS_LINK_AP) ? "AP" : "DIRECT", + MAC_ADDR_ARRAY(pMacHdr->addr1), + MAC_ADDR_ARRAY(pMacHdr->addr2), + MAC_ADDR_ARRAY(pMacHdr->addr3)); + + if (IS_QOS_ENABLED(psessionEntry)) { + pMacHdr->qosControl.tid = tid; + header_offset += sizeof(tSirMacDataHdr3a); + } else + header_offset += sizeof(tSirMacMgmtHdr); + + /* + * Now form RFC1042 header + */ + cdf_mem_copy((uint8_t *) (pFrame + header_offset), + (uint8_t *) eth_890d_header, sizeof(eth_890d_header)); + + header_offset += sizeof(eth_890d_header); + + /* add payload type as TDLS */ + *(pFrame + header_offset) = PAYLOAD_TYPE_TDLS; + header_offset += PAYLOAD_TYPE_TDLS_SIZE; + return header_offset; +} + +/* + * TX Complete for Management frames + */ +CDF_STATUS lim_mgmt_tx_complete(tpAniSirGlobal pMac, uint32_t txCompleteSuccess) +{ + tpPESession psessionEntry = NULL; + + if (0xff != pMac->lim.mgmtFrameSessionId) { + psessionEntry = + pe_find_session_by_session_id(pMac, + pMac->lim.mgmtFrameSessionId); + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("sessionID %d is not found"), + pMac->lim.mgmtFrameSessionId); + return CDF_STATUS_E_FAILURE; + } + lim_send_sme_mgmt_tx_completion(pMac, psessionEntry, + txCompleteSuccess); + pMac->lim.mgmtFrameSessionId = 0xff; + } + return CDF_STATUS_SUCCESS; +} + +/* + * This function can be used for bacst or unicast discovery request + * We are not differentiating it here, it will all depnds on peer MAC address, + */ +tSirRetStatus lim_send_tdls_dis_req_frame(tpAniSirGlobal pMac, tSirMacAddr peer_mac, + uint8_t dialog, tpPESession psessionEntry) +{ + tDot11fTDLSDisReq tdlsDisReq; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t size = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + cdf_mem_set((uint8_t *) &tdlsDisReq, sizeof(tDot11fTDLSDisReq), 0); + + /* + * setup Fixed fields, + */ + tdlsDisReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsDisReq.Action.action = SIR_MAC_TDLS_DIS_REQ; + tdlsDisReq.DialogToken.token = dialog; + + size = sizeof(tSirMacAddr); + + populate_dot11f_link_iden(pMac, psessionEntry, &tdlsDisReq.LinkIdentifier, + peer_mac, TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_req_size(pMac, &tdlsDisReq, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGP, + FL( + "Failed to calculate the packed size for a discovery Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTDLSDisReq); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a discovery Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL( + "Failed to allocate %d bytes for a TDLS Discovery Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET + (tdlsDisReq), TDLS_LINK_AP, + TDLS_INITIATOR, TID_AC_VI, + psessionEntry); + + status = dot11f_pack_tdls_dis_req(pMac, &tdlsDisReq, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS discovery req (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Request (0x%08x)." + ), + status); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = pFrame + header_offset + nPayload; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOGW, + FL("Padding Vendor Specific Ie Len = %d"), padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + cdf_mem_set(pFrame + header_offset + nPayload + + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_DIS_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_REQ), + MAC_ADDR_ARRAY(peer_mac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_VI, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Discovery Request frame")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * This static function is consistent with any kind of TDLS management + * frames we are sending. Currently it is being used by lim_send_tdls_dis_rsp_frame, + * lim_send_tdls_link_setup_req_frame and lim_send_tdls_setup_rsp_frame + */ +static void populate_dot11f_tdls_ht_vht_cap(tpAniSirGlobal pMac, + uint32_t selfDot11Mode, + tDot11fIEHTCaps *htCap, + tDot11fIEVHTCaps *vhtCap, + tpPESession psessionEntry) +{ + if (IS_DOT11_MODE_HT(selfDot11Mode)) { + /* Include HT Capability IE */ + populate_dot11f_ht_caps(pMac, NULL, htCap); + /* + * Advertise ht capability and max supported channel bandwidth + * when populating HT IE in TDLS Setup Request/Setup Response/ + * Setup Confirmation frames. + * 11.21.6.2 Setting up a 40 MHz direct link: A 40 MHz + * off-channel direct link may be started if both TDLS peer STAs + * indicated 40 MHz support in the Supported Channel Width Set + * field of the HT Capabilities element (which is included in + * the TDLS Setup Request frame and the TDLS Setup Response + * frame). Switching to a 40 MHz off-channel direct link is + * achieved by including the following information in the TDLS + * Channel Switch Request + * 11.21.1 General: The channel width of the TDLS direct link on + * the base channel shall not exceed the channel width of the + * BSS to which the TDLS peer STAs are associated. + */ + htCap->supportedChannelWidthSet = 1; + } else { + htCap->present = 0; + } + lim_log(pMac, LOG1, FL("HT present = %hu, Chan Width = %hu"), + htCap->present, htCap->supportedChannelWidthSet); +#ifdef WLAN_FEATURE_11AC + if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* Include VHT Capability IE */ + populate_dot11f_vht_caps(pMac, psessionEntry, vhtCap); + vhtCap->suBeamformeeCap = 0; + vhtCap->suBeamFormerCap = 0; + vhtCap->muBeamformeeCap = 0; + vhtCap->muBeamformerCap = 0; + } else { + vhtCap->present = 0; + } + } else { + /* Vht Disable from ini in 2.4 GHz */ + vhtCap->present = 0; + } + lim_log(pMac, LOG1, FL("VHT present = %hu, Chan Width = %hu"), + vhtCap->present, vhtCap->supportedChannelWidthSet); +#endif +} + +/* + * Send TDLS discovery response frame on direct link. + */ + +static tSirRetStatus lim_send_tdls_dis_rsp_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen) +{ + tDot11fTDLSDisRsp tdlsDisRsp; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; + uint32_t selfDot11Mode; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + cdf_mem_set((uint8_t *) &tdlsDisRsp, sizeof(tDot11fTDLSDisRsp), 0); + + /* + * setup Fixed fields, + */ + tdlsDisRsp.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; + tdlsDisRsp.Action.action = SIR_MAC_TDLS_DIS_RSP; + tdlsDisRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsDisRsp.LinkIdentifier, + peerMac, TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) + != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsDisRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsDisRsp.SuppRates, + &tdlsDisRsp.ExtSuppRates)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsDisRsp.ExtCap); + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsDisRsp.HTCaps, + &tdlsDisRsp.VHTCaps, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsDisRsp.SuppChannels, + &tdlsDisRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsDisRsp.ht2040_bss_coexistence.present = 1; + tdlsDisRsp.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_rsp_size(pMac, &tdlsDisRsp, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Discovery Response (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a Discovery Response (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + sizeof(tSirMacMgmtHdr) + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Discovery Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * response frame + */ + + /* Make public Action Frame */ + + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMac, + psessionEntry->selfMacAddr); + + { + tpSirMacMgmtHdr pMacHdr; + pMacHdr = (tpSirMacMgmtHdr) pFrame; + pMacHdr->fc.toDS = ANI_TXDIR_IBSS; + pMacHdr->fc.powerMgmt = 0; + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + } + + status = dot11f_pack_tdls_dis_rsp(pMac, &tdlsDisRsp, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to pack a TDLS discovery response (0x%08x)." + ), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Response (0x%08x)." + ), + status); + } + if (0 != addIeLen) { + lim_log(pMac, LOG1, + FL("Copy Additional Ie Len = %d"), addIeLen); + cdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, addIe, + addIeLen); + } + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -DIRECT-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_DIS_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_RSP), + MAC_ADDR_ARRAY(peerMac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + /* + * Transmit Discovery response and watch if this is delivered to + * peer STA. + */ + /* In CLD 2.0, pass Discovery Response as mgmt frame so that + * wma does not do header conversion to 802.3 before calling tx/rx + * routine and subsequenly target also sends frame as is OTA + */ + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_IBSS, + 0, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_SELF_STA_REQUESTED_MASK, + smeSessionId, false, 0); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Discovery Response frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * This static function is currently used by lim_send_tdls_link_setup_req_frame and + * lim_send_tdls_setup_rsp_frame to populate the AID if device is 11ac capable. + */ +static void populate_dotf_tdls_vht_aid(tpAniSirGlobal pMac, uint32_t selfDot11Mode, + tSirMacAddr peerMac, tDot11fIEAID *Aid, + tpPESession psessionEntry) +{ + if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + + uint16_t aid; + tpDphHashNode pStaDs; + + pStaDs = + dph_lookup_hash_entry(pMac, peerMac, &aid, + &psessionEntry->dph. + dphHashTable); + if (NULL != pStaDs) { + Aid->present = 1; + Aid->assocId = aid | LIM_AID_MASK; /* set bit 14 and 15 1's */ + } else { + Aid->present = 0; + lim_log(pMac, LOGE, + FL("pStaDs is NULL for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peerMac)); + } + } + } else { + Aid->present = 0; + lim_log(pMac, LOGW, FL("Vht not enable from ini for 2.4GHz.")); + } +} + +/* + * TDLS setup Request frame on AP link + */ + +tSirRetStatus lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen) +{ + tDot11fTDLSSetupReq tdlsSetupReq; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; + uint32_t selfDot11Mode; + uint8_t smeSessionId = 0; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &tdlsSetupReq, sizeof(tDot11fTDLSSetupReq), 0); + tdlsSetupReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupReq.Action.action = SIR_MAC_TDLS_SETUP_REQ; + tdlsSetupReq.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupReq.LinkIdentifier, peerMac, + TDLS_INITIATOR); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsSetupReq.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupReq.SuppRates, + &tdlsSetupReq.ExtSuppRates)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupReq.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + lim_log(pMac, LOG1, + FL("populate WMM IE in Setup Request Frame")); + /* include WMM IE */ + tdlsSetupReq.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupReq.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupReq.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + + tdlsSetupReq.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupReq.WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + + /* Populate QOS info, needed for Peer U-APSD session */ + + /* + * TODO: Now hardcoded, since populate_dot11f_qos_caps_station() + * depends on AP's capability, and TDLS doesn't want to depend + * on AP's capability + */ + + lim_log(pMac, LOG1, + FL("populate QOS IE in Setup Request Frame")); + tdlsSetupReq.QOSCapsStation.present = 1; + tdlsSetupReq.QOSCapsStation.max_sp_length = 0; + tdlsSetupReq.QOSCapsStation.qack = 0; + tdlsSetupReq.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupReq.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.QOSCapsStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + } + + /* + * we will always try to init TDLS link with 11n capabilities + * let TDLS setup response to come, and we will set our caps based + * of peer caps + */ + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupReq.HTCaps, + &tdlsSetupReq.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peerMac, + &tdlsSetupReq.AID, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupReq.SuppChannels, + &tdlsSetupReq. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsSetupReq.ht2040_bss_coexistence.present = 1; + tdlsSetupReq.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_req_size(pMac, &tdlsSetupReq, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a Setup Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET + (tdlsSetupReq), TDLS_LINK_AP, + TDLS_INITIATOR, TID_AC_BK, + psessionEntry); + + lim_log(pMac, LOGW, + FL( + "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" + ), + tdlsSetupReq.VHTCaps.supportedChannelWidthSet, + tdlsSetupReq.VHTCaps.rxMCSMap, + tdlsSetupReq.VHTCaps.txMCSMap, + tdlsSetupReq.VHTCaps.txSupDataRate); + + status = dot11f_pack_tdls_setup_req(pMac, &tdlsSetupReq, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Setup request (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Setup Request (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + lim_log(pMac, LOG1, FL("Copy Additional Ie Len = %d"), + addIeLen); + cdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_REQ), + MAC_ADDR_ARRAY(peerMac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_BK, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Setup Request frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + */ + +tSirRetStatus lim_send_tdls_teardown_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, uint16_t reason, + uint8_t responder, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen) +{ + tDot11fTDLSTeardown teardown; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + cdf_mem_set((uint8_t *) &teardown, sizeof(tDot11fTDLSTeardown), 0); + teardown.Category.category = SIR_MAC_ACTION_TDLS; + teardown.Action.action = SIR_MAC_TDLS_TEARDOWN; + teardown.Reason.code = reason; + + populate_dot11f_link_iden(pMac, psessionEntry, &teardown.LinkIdentifier, + peerMac, + (responder == + true) ? TDLS_RESPONDER : TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_teardown_size(pMac, &teardown, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a discovery Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a discovery Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Teardown Frame." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + lim_log(pMac, LOGE, FL("Reason of TDLS Teardown: %d"), reason); + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET + (teardown), + (reason == + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? TDLS_LINK_AP : + TDLS_LINK_DIRECT, + (responder == + true) ? TDLS_RESPONDER : + TDLS_INITIATOR, TID_AC_VI, + psessionEntry); + + status = dot11f_pack_tdls_teardown(pMac, &teardown, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Teardown frame (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Teardown frame (0x%08x)." + ), + status); + } + + if (addIeLen != 0) { + lim_log(pMac, LOGW, + FL("Copy Additional Ie Len = %d"), addIeLen); + cdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + pFrame + header_offset + nPayload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), + padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + cdf_mem_set(pFrame + header_offset + nPayload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -%s-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_TEARDOWN, + lim_trace_tdls_action_string(SIR_MAC_TDLS_TEARDOWN), + ((reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? "AP" : + "DIRECT"), + MAC_ADDR_ARRAY(peerMac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_VI, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Teardown frame")); + return eSIR_FAILURE; + + } + return eSIR_SUCCESS; + +} + +/* + * Send Setup RSP frame on AP link. + */ +static tSirRetStatus lim_send_tdls_setup_rsp_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, + uint8_t dialog, + tpPESession psessionEntry, + etdlsLinkSetupStatus setupStatus, + uint8_t *addIe, + uint16_t addIeLen) +{ + tDot11fTDLSSetupRsp tdlsSetupRsp; + uint32_t status = 0; + uint16_t caps = 0; + uint32_t nPayload = 0; + uint32_t header_offset = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; + uint32_t selfDot11Mode; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + cdf_mem_set((uint8_t *) &tdlsSetupRsp, sizeof(tDot11fTDLSSetupRsp), 0); + + /* + * setup Fixed fields, + */ + tdlsSetupRsp.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupRsp.Action.action = SIR_MAC_TDLS_SETUP_RSP; + tdlsSetupRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupRsp.LinkIdentifier, peerMac, + TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsSetupRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupRsp.SuppRates, + &tdlsSetupRsp.ExtSuppRates)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupRsp.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + lim_log(pMac, LOG1, + FL("populate WMM IE in Setup Response frame")); + /* include WMM IE */ + tdlsSetupRsp.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupRsp.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupRsp.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + tdlsSetupRsp.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupRsp.WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + /* Populate QOS info, needed for Peer U-APSD session */ + /* + * TODO: Now hardcoded, because + * populate_dot11f_qos_caps_station() depends on AP's + * capability, and TDLS doesn't want to depend on AP's + * capability + */ + lim_log(pMac, LOG1, + FL("populate QOS IE in Setup Response frame")); + tdlsSetupRsp.QOSCapsStation.present = 1; + tdlsSetupRsp.QOSCapsStation.max_sp_length = 0; + tdlsSetupRsp.QOSCapsStation.qack = 0; + tdlsSetupRsp.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupRsp.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.QOSCapsStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + } + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupRsp.HTCaps, + &tdlsSetupRsp.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peerMac, + &tdlsSetupRsp.AID, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupRsp.SuppChannels, + &tdlsSetupRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsSetupRsp.ht2040_bss_coexistence.present = 1; + tdlsSetupRsp.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + tdlsSetupRsp.Status.status = setupStatus; + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_rsp_size(pMac, &tdlsSetupRsp, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Response (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for Setup Response (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Response." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET + (tdlsSetupRsp), TDLS_LINK_AP, + TDLS_RESPONDER, TID_AC_BK, + psessionEntry); + + lim_log(pMac, LOG1, + FL( + "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" + ), + tdlsSetupRsp.VHTCaps.supportedChannelWidthSet, + tdlsSetupRsp.VHTCaps.rxMCSMap, + tdlsSetupRsp.VHTCaps.txMCSMap, + tdlsSetupRsp.VHTCaps.txSupDataRate); + status = dot11f_pack_tdls_setup_rsp(pMac, &tdlsSetupRsp, + pFrame + header_offset, + nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Setup Response (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Setup Response (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + cdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_RSP), + MAC_ADDR_ARRAY(peerMac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_BK, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Dis Request frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * Send TDLS setup CNF frame on AP link + */ + +tSirRetStatus lim_send_tdls_link_setup_cnf_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, + uint8_t dialog, + uint32_t peerCapability, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen) +{ + tDot11fTDLSSetupCnf tdlsSetupCnf; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + CDF_STATUS cdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &tdlsSetupCnf, sizeof(tDot11fTDLSSetupCnf), 0); + + /* + * setup Fixed fields, + */ + tdlsSetupCnf.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupCnf.Action.action = SIR_MAC_TDLS_SETUP_CNF; + tdlsSetupCnf.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupCnf.LinkIdentifier, peerMac, + TDLS_INITIATOR); + /* + * TODO: we need to see if we have to support conditions where we have + * EDCA parameter info element is needed a) if we need different QOS + * parameters for off channel operations or QOS is not supported on + * AP link and we wanted to QOS on direct link. + */ + + /* Check self and peer WMM capable */ + if ((1 == pMac->lim.gLimTDLSWmmMode) && + (CHECK_BIT(peerCapability, TDLS_PEER_WMM_CAP))) { + lim_log(pMac, LOG1, FL("populate WMM praram in Setup Confirm")); + populate_dot11f_wmm_params(pMac, &tdlsSetupCnf.WMMParams, + psessionEntry); + } + + /* Check peer is VHT capable */ + if (CHECK_BIT(peerCapability, TDLS_PEER_VHT_CAP)) { + populate_dot11f_vht_operation(pMac, + psessionEntry, + &tdlsSetupCnf.VHTOperation); + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } else if (CHECK_BIT(peerCapability, TDLS_PEER_HT_CAP)) { /* Check peer is HT capable */ + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_cnf_size(pMac, &tdlsSetupCnf, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Confirm (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for Setup Confirm (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Confirm." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + cdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET + (tdlsSetupCnf), TDLS_LINK_AP, + TDLS_INITIATOR, TID_AC_VI, + psessionEntry); + + status = dot11f_pack_tdls_setup_cnf(pMac, &tdlsSetupCnf, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS discovery req (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Request (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + cdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + pFrame + header_offset + nPayload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), + padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + cdf_mem_set(pFrame + header_offset + nPayload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_CNF, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_CNF), + MAC_ADDR_ARRAY(peerMac)); + + pMac->lim.mgmtFrameSessionId = psessionEntry->peSessionId; + + cdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_VI, + lim_tx_complete, pFrame, + lim_mgmt_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME, + smeSessionId, false, 0); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->lim.mgmtFrameSessionId = 0xff; + lim_log(pMac, LOGE, + FL("could not send TDLS Setup Confirm frame")); + return eSIR_FAILURE; + + } + + return eSIR_SUCCESS; +} + +/* This Function is similar to populate_dot11f_ht_caps, except that the HT Capabilities + * are considered from the AddStaReq rather from the cfg.dat as in populate_dot11f_ht_caps + */ +static tSirRetStatus lim_tdls_populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirTdlsAddStaReq * + pTdlsAddStaReq, + tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue; + uint8_t nCfgValue8; + tSirMacHTParametersInfo *pHTParametersInfo; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + nCfgValue = pTdlsAddStaReq->htCap.capInfo; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->advCodingCap = uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->shortGI20MHz = uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = uHTCapabilityInfo.htCapInfo.shortGI40MHz; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* + * All sessionized entries will need the check below + * Only in case of NO session + */ + if (psessionEntry == NULL) { + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + } else { + pDot11f->supportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + lim_log(pMac, LOG1, + FL( + "SupportedChnlWidth: %d, mimoPS: %d, GF: %d, shortGI20:%d, shortGI40: %d, dsssCck: %d" + ), + pDot11f->supportedChannelWidthSet, + pDot11f->mimoPowerSave, + pDot11f->greenField, + pDot11f->shortGI20MHz, + pDot11f->shortGI40MHz, + pDot11f->dsssCckMode40MHz); + + nCfgValue = pTdlsAddStaReq->htCap.ampduParamsInfo; + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + lim_log(pMac, LOG1, FL("AMPDU Param: %x"), nCfgValue); + + cdf_mem_copy(pDot11f->supportedMCSSet, pTdlsAddStaReq->htCap.suppMcsSet, + SIZE_OF_SUPPORTED_MCS_SET); + + nCfgValue = pTdlsAddStaReq->htCap.extendedHtCapInfo; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + nCfgValue = pTdlsAddStaReq->htCap.txBFCapInfo; + + pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + nCfgValue = pTdlsAddStaReq->htCap.antennaSelectionInfo; + + nCfgValue8 = (uint8_t) nCfgValue; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = pTdlsAddStaReq->htcap_present; + + return eSIR_SUCCESS; + +} + +tSirRetStatus +lim_tdls_populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tDot11fIEVHTCaps *pDot11f) +{ + uint32_t nCfgValue = 0; + union { + uint32_t nCfgValue32; + tSirMacVHTCapabilityInfo vhtCapInfo; + } uVHTCapabilityInfo; + union { + uint16_t nCfgValue16; + tSirMacVHTTxSupDataRateInfo vhtTxSupDataRateInfo; + tSirMacVHTRxSupDataRateInfo vhtRxsupDataRateInfo; + } uVHTSupDataRateInfo; + + pDot11f->present = pTdlsAddStaReq->vhtcap_present; + + nCfgValue = pTdlsAddStaReq->vhtCap.vhtCapInfo; + uVHTCapabilityInfo.nCfgValue32 = nCfgValue; + + pDot11f->maxMPDULen = uVHTCapabilityInfo.vhtCapInfo.maxMPDULen; + pDot11f->supportedChannelWidthSet = + uVHTCapabilityInfo.vhtCapInfo.supportedChannelWidthSet; + pDot11f->ldpcCodingCap = uVHTCapabilityInfo.vhtCapInfo.ldpcCodingCap; + pDot11f->shortGI80MHz = uVHTCapabilityInfo.vhtCapInfo.shortGI80MHz; + pDot11f->shortGI160and80plus80MHz = + uVHTCapabilityInfo.vhtCapInfo.shortGI160and80plus80MHz; + pDot11f->txSTBC = uVHTCapabilityInfo.vhtCapInfo.txSTBC; + pDot11f->rxSTBC = uVHTCapabilityInfo.vhtCapInfo.rxSTBC; + pDot11f->suBeamFormerCap = 0; + pDot11f->suBeamformeeCap = 0; + pDot11f->csnofBeamformerAntSup = + uVHTCapabilityInfo.vhtCapInfo.csnofBeamformerAntSup; + pDot11f->numSoundingDim = uVHTCapabilityInfo.vhtCapInfo.numSoundingDim; + pDot11f->muBeamformerCap = 0; + pDot11f->muBeamformeeCap = 0; + pDot11f->vhtTXOPPS = uVHTCapabilityInfo.vhtCapInfo.vhtTXOPPS; + pDot11f->htcVHTCap = uVHTCapabilityInfo.vhtCapInfo.htcVHTCap; + pDot11f->maxAMPDULenExp = uVHTCapabilityInfo.vhtCapInfo.maxAMPDULenExp; + pDot11f->vhtLinkAdaptCap = + uVHTCapabilityInfo.vhtCapInfo.vhtLinkAdaptCap; + pDot11f->rxAntPattern = uVHTCapabilityInfo.vhtCapInfo.rxAntPattern; + pDot11f->txAntPattern = uVHTCapabilityInfo.vhtCapInfo.txAntPattern; + pDot11f->reserved1 = uVHTCapabilityInfo.vhtCapInfo.reserved1; + + pDot11f->rxMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.rxMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.rxHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->rxHighSupDataRate = + uVHTSupDataRateInfo.vhtRxsupDataRateInfo.rxSupDataRate; + + pDot11f->txMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.txMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.txHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->txSupDataRate = + uVHTSupDataRateInfo.vhtTxSupDataRateInfo.txSupDataRate; + + pDot11f->reserved3 = uVHTSupDataRateInfo.vhtTxSupDataRateInfo.reserved; + + lim_log_vht_cap(pMac, pDot11f); + + return eSIR_SUCCESS; + +} + +/** + * lim_tdls_populate_matching_rate_set() - populate matching rate set + * + * @mac_ctx - global MAC context + * @stads - station hash entry + * @supp_rate_set - pointer to supported rate set + * @supp_rates_len - length of the supported rates + * @supp_mcs_set - pointer to supported MSC set + * @session_entry - pointer to PE session entry + * @vht_caps - pointer to VHT capability + * + * + * This function gets set of available rates from the config and compare them + * against the set of received supported rates. After the comparison station + * entry's rates is populated with 11A rates and 11B rates. + * + * Return: eSIR_SUCCESS on success, eSIR_FAILURE on failure. + */ +static tSirRetStatus +lim_tdls_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode stads, + uint8_t *supp_rate_set, + uint8_t supp_rates_len, + uint8_t *supp_mcs_set, + tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + uint32_t i, j, val, min, is_a_rate; + tSirMacRateSet temp_rate_set2; + uint32_t phymode; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rateindex = 0; + uint8_t b_rateindex = 0; + is_a_rate = 0; + temp_rate_set2.numRates = 0; + + lim_get_phy_mode(mac_ctx, &phymode, NULL); + + /* get own rate set */ + val = WNI_CFG_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set.rate, + &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGE, FL("could not retrieve rateset")); + val = 0; + } + temp_rate_set.numRates = val; + + if (phymode == WNI_CFG_PHY_MODE_11G) { + /* get own extended rate set */ + val = WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set2.rate, + &val) != eSIR_SUCCESS) + temp_rate_set2.numRates = val; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + lim_log(mac_ctx, LOGE, FL("more than 12 rates in CFG")); + goto error; + } + + /** + * Handling of the rate set IEs is the following: + * - keep only rates that we support and that the station supports + * - sort and the rates into the pSta->rate array + */ + + /* Copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /** + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in temp_rate_set2 + */ + temp_rate_set2.numRates = 0; + + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + + for (j = 0; j < temp_rate_set.numRates; j++) + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + + temp_rate_set2.rate[temp_rate_set2.numRates++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + /** + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 . + */ + if (supp_rates_len > SIR_MAC_RATESET_EID_MAX) { + lim_log(mac_ctx, LOGW, + FL( + "Supported rates length %d more than the Max limit, reset to Max" + ), + supp_rates_len); + supp_rates_len = SIR_MAC_RATESET_EID_MAX; + } + + for (i = 0; i < supp_rates_len; i++) + temp_rate_set.rate[i] = supp_rate_set[i]; + + temp_rate_set.numRates = supp_rates_len; + + rates = &stads->supportedRates; + cdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + + for (i = 0; i < temp_rate_set2.numRates; i++) { + for (j = 0; j < temp_rate_set.numRates; j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + +#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC + if ((b_rateindex > HAL_NUM_11B_RATES) || + (a_rateindex > HAL_NUM_11A_RATES)) { + lim_log(mac_ctx, LOGE, + FL("Invalid number of rates (11b->%d, 11a->%d)"), + b_rateindex, a_rateindex); + return eSIR_FAILURE; + } +#endif + if (sirIsArate(temp_rate_set2.rate[i] & 0x7f)) { + is_a_rate = 1; + if (a_rateindex < SIR_NUM_11A_RATES) + rates->llaRates[a_rateindex++] = temp_rate_set2.rate[i]; + } else { + if (b_rateindex < SIR_NUM_11B_RATES) + rates->llbRates[b_rateindex++] = temp_rate_set2.rate[i]; + } + break; + } + } + + /* compute the matching MCS rate set, if peer is 11n capable and self mode is 11n */ +#ifdef FEATURE_WLAN_TDLS + if (stads->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (stads->mlmStaContext.htCapability)) +#endif + { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcsSet, &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve supportedMCSSet")); + goto error; + } + + for (i = 0; i < val; i++) + stads->supportedRates.supportedMCSSet[i] = + mcsSet[i] & supp_mcs_set[i]; + + lim_log(mac_ctx, LOG1, + FL("MCS Rate Set Bitmap from CFG and DPH")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + lim_log(mac_ctx, LOG1, FL("%x %x"), mcsSet[i], + stads->supportedRates.supportedMCSSet[i]); + } + } +#ifdef WLAN_FEATURE_11AC + lim_populate_vht_mcs_set(mac_ctx, &stads->supportedRates, vht_caps, + session_entry); +#endif + /** + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phymode == WNI_CFG_PHY_MODE_11G) && is_a_rate) + stads->erpEnabled = eHAL_SET; + + return eSIR_SUCCESS; + +error: + return eSIR_FAILURE; +} + +/* + * update HASH node entry info + */ +static void lim_tdls_update_hash_node_info(tpAniSirGlobal pMac, + tDphHashNode *pStaDs, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tpPESession psessionEntry) +{ + tDot11fIEHTCaps htCap = {0,}; + tDot11fIEHTCaps *htCaps; + tDot11fIEVHTCaps *pVhtCaps = NULL; + tDot11fIEVHTCaps *pVhtCaps_txbf = NULL; +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps vhtCap; + uint8_t cbMode; +#endif + tpDphHashNode pSessStaDs = NULL; + uint16_t aid; + + if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_ADD) { + populate_dot11f_ht_caps(pMac, psessionEntry, &htCap); + } else if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE) { + lim_tdls_populate_dot11f_ht_caps(pMac, NULL, pTdlsAddStaReq, &htCap); + } + htCaps = &htCap; + if (htCaps->present) { + pStaDs->mlmStaContext.htCapability = 1; + pStaDs->htGreenfield = htCaps->greenField; + pStaDs->htSupportedChannelWidthSet = + htCaps->supportedChannelWidthSet; + pStaDs->htMIMOPSState = htCaps->mimoPowerSave; + pStaDs->htMaxAmsduLength = htCaps->maximalAMSDUsize; + pStaDs->htAMpduDensity = htCaps->mpduDensity; + pStaDs->htDsssCckRate40MHzSupport = htCaps->dsssCckMode40MHz; + pStaDs->htShortGI20Mhz = htCaps->shortGI20MHz; + pStaDs->htShortGI40Mhz = htCaps->shortGI40MHz; + pStaDs->htMaxRxAMpduFactor = htCaps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(pMac, + &pStaDs->supportedRates. + rxHighestDataRate, + htCaps->supportedMCSSet); + pStaDs->baPolicyFlag = 0xFF; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_N; + pStaDs->ht_caps = pTdlsAddStaReq->htCap.capInfo; + } else { + pStaDs->mlmStaContext.htCapability = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_BG; + } +#ifdef WLAN_FEATURE_11AC + lim_tdls_populate_dot11f_vht_caps(pMac, pTdlsAddStaReq, &vhtCap); + pVhtCaps = &vhtCap; + if (pVhtCaps->present) { + pStaDs->mlmStaContext.vhtCapability = 1; + + if (psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) { + /* + * if the channel is 2G then update the min channel + * widthset in pStaDs. These values are used when + * sending a AddSta request to firmware + * 11.21.1 General: The channel width of the TDLS direct + * link on the base channel shall not exceed the channel + * width of the BSS to which the TDLS peer STAs are + * associated. + */ + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + lim_log(pMac, LOG1, FL("vhtSupportedChannelWidthSet = %hu, htSupportedChannelWidthSet %hu"), + pStaDs->htSupportedChannelWidthSet, + pStaDs->htSupportedChannelWidthSet); + } else { + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + + pStaDs->vhtLdpcCapable = pVhtCaps->ldpcCodingCap; + pStaDs->vhtBeamFormerCapable = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_AC; + pVhtCaps_txbf = (tDot11fIEVHTCaps *) (&pTdlsAddStaReq->vhtCap); + pVhtCaps_txbf->suBeamformeeCap = 0; + pVhtCaps_txbf->suBeamFormerCap = 0; + pVhtCaps_txbf->muBeamformerCap = 0; + pVhtCaps_txbf->muBeamformeeCap = 0; + pStaDs->vht_caps = pTdlsAddStaReq->vhtCap.vhtCapInfo; + } else { + pStaDs->mlmStaContext.vhtCapability = 0; + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } +#endif + /*Calculate the Secondary Coannel Offset */ + cbMode = lim_select_cb_mode(pStaDs, psessionEntry, + psessionEntry->currentOperChannel, + pStaDs->vhtSupportedChannelWidthSet); + + pStaDs->htSecondaryChannelOffset = cbMode; + +#ifdef WLAN_FEATURE_11AC + if (pStaDs->mlmStaContext.vhtCapability) { + pStaDs->htSecondaryChannelOffset = lim_get_htcb_state(cbMode); + } +#endif + + pSessStaDs = dph_lookup_hash_entry(pMac, psessionEntry->bssId, &aid, + &psessionEntry->dph.dphHashTable); + + /* Lets enable QOS parameter */ + pStaDs->qosMode = 1; + pStaDs->wmeEnabled = 1; + pStaDs->lleEnabled = 0; + /* TDLS Dummy AddSTA does not have qosInfo , is it OK ?? + */ + pStaDs->qos.capability.qosInfo = + (*(tSirMacQosInfoStation *) &pTdlsAddStaReq->uapsd_queues); + + /* populate matching rate set */ + + /* TDLS Dummy AddSTA does not have HTCap,VHTCap,Rates info , is it OK ?? + */ + lim_tdls_populate_matching_rate_set(pMac, pStaDs, + pTdlsAddStaReq->supported_rates, + pTdlsAddStaReq->supported_rates_length, + (uint8_t *) pTdlsAddStaReq->htCap. + suppMcsSet, psessionEntry, pVhtCaps); + + /* TDLS Dummy AddSTA does not have right capability , is it OK ?? + */ + pStaDs->mlmStaContext.capabilityInfo = + (*(tSirMacCapabilityInfo *) &pTdlsAddStaReq->capability); + + return; +} + +/* + * Add STA for TDLS setup procedure + */ +static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pAddStaReq, + tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + tSirRetStatus status = eSIR_SUCCESS; + uint16_t aid = 0; + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaReq->peerMac, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + aid = lim_assign_peer_idx(pMac, psessionEntry); + + if (!aid) { + lim_log(pMac, LOGE, + FL("No more free AID for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddStaReq->peerMac)); + return eSIR_FAILURE; + } + + /* Set the aid in peerAIDBitmap as it has been assigned to TDLS peer */ + SET_PEER_AID_BITMAP(psessionEntry->peerAIDBitmap, aid); + + lim_log(pMac, LOG1, FL("Aid = %d, for peer =" MAC_ADDRESS_STR), + aid, MAC_ADDR_ARRAY(pAddStaReq->peerMac)); + pStaDs = + dph_get_hash_entry(pMac, aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, aid, + psessionEntry); + } + + pStaDs = dph_add_hash_entry(pMac, pAddStaReq->peerMac, aid, + &psessionEntry->dph.dphHashTable); + + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("add hash entry failed")); + CDF_ASSERT(0); + return eSIR_FAILURE; + } + } + + lim_tdls_update_hash_node_info(pMac, pStaDs, pAddStaReq, psessionEntry); + + pStaDs->staType = STA_ENTRY_TDLS_PEER; + + status = + lim_add_sta(pMac, pStaDs, + (pAddStaReq->tdlsAddOper == + TDLS_OPER_UPDATE) ? true : false, psessionEntry); + + if (eSIR_SUCCESS != status) { + /* should not fail */ + CDF_ASSERT(0); + } + return status; +} + +/* + * Del STA, after Link is teardown or discovery response sent on direct link + */ +static tpDphHashNode lim_tdls_del_sta(tpAniSirGlobal pMac, tSirMacAddr peerMac, + tpPESession psessionEntry) +{ + tSirRetStatus status = eSIR_SUCCESS; + uint16_t peerIdx = 0; + tpDphHashNode pStaDs = NULL; + + pStaDs = dph_lookup_hash_entry(pMac, peerMac, &peerIdx, + &psessionEntry->dph.dphHashTable); + + if (pStaDs) { + + lim_log(pMac, LOG1, FL("DEL STA peer MAC: "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + lim_log(pMac, LOG1, FL("STA type = %x, sta idx = %x"), + pStaDs->staType, + pStaDs->staIndex); + + status = lim_del_sta(pMac, pStaDs, false, psessionEntry); + } + + return pStaDs; +} + +/* + * Once Link is setup with PEER, send Add STA ind to SME + */ +static CDF_STATUS lim_send_sme_tdls_add_sta_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirMacAddr peerMac, + uint8_t updateSta, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirTdlsAddStaRsp *addStaRsp = NULL; + mmhMsg.type = eWNI_SME_TDLS_ADD_STA_RSP; + + addStaRsp = cdf_mem_malloc(sizeof(tSirTdlsAddStaRsp)); + if (NULL == addStaRsp) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return CDF_STATUS_E_NOMEM; + } + + addStaRsp->sessionId = sessionId; + addStaRsp->statusCode = status; + if (pStaDs) { + addStaRsp->staId = pStaDs->staIndex; + addStaRsp->ucastSig = pStaDs->ucUcastSig; + addStaRsp->bcastSig = pStaDs->ucBcastSig; + } + if (peerMac) { + cdf_mem_copy(addStaRsp->peerMac, + (uint8_t *) peerMac, sizeof(tSirMacAddr)); + } + if (updateSta) + addStaRsp->tdlsAddOper = TDLS_OPER_UPDATE; + else + addStaRsp->tdlsAddOper = TDLS_OPER_ADD; + + addStaRsp->length = sizeof(tSirTdlsAddStaRsp); + addStaRsp->messageType = eWNI_SME_TDLS_ADD_STA_RSP; + + mmhMsg.bodyptr = addStaRsp; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return CDF_STATUS_SUCCESS; + +} + +/* + * STA RSP received from HAL + */ +CDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tAddStaParams *pAddStaParams = (tAddStaParams *) msg; + uint8_t status = eSIR_SUCCESS; + tDphHashNode *pStaDs = NULL; + uint16_t aid = 0; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOG1, FL("staIdx=%d, staMac="MAC_ADDRESS_STR), + pAddStaParams->staIdx, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + + if (pAddStaParams->status != CDF_STATUS_SUCCESS) { + CDF_ASSERT(0); + lim_log(pMac, LOGE, FL("Add sta failed ")); + status = eSIR_FAILURE; + goto add_sta_error; + } + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("pStaDs is NULL ")); + status = eSIR_FAILURE; + goto add_sta_error; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->ucUcastSig = pAddStaParams->ucUcastSig; + pStaDs->ucBcastSig = pAddStaParams->ucBcastSig; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + pStaDs->valid = 1; +add_sta_error: + status = lim_send_sme_tdls_add_sta_rsp(pMac, psessionEntry->smeSessionId, + pAddStaParams->staMac, + pAddStaParams->updateSta, pStaDs, + status); + cdf_mem_free(pAddStaParams); + return status; +} + +void populate_dot11f_tdls_offchannel_params(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIESuppChannels *suppChannels, + tDot11fIESuppOperatingClasses * + suppOperClasses) +{ + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t i; + uint8_t valid_count = 0; + uint8_t chanOffset; + uint8_t op_class; + uint8_t numClasses; + uint8_t classes[SIR_MAC_MAX_SUPP_OPER_CLASSES]; + if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans) != eSIR_SUCCESS) { + /** + * Could not get Valid channel list from CFG. + * Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Valid channel list")); + return; + } + + /* validating the channel list for DFS channels */ + for (i = 0U; i < numChans; i++) { + if (CHANNEL_STATE_DFS == + cds_get_channel_state(validChan[i])) { + lim_log(pMac, LOG1, + FL( + "skipping DFS channel %d from the valid channel list" + ), + validChan[i]); + continue; + } + + if (valid_count >= ARRAY_SIZE(suppChannels->bands)) + break; + suppChannels->bands[valid_count][0] = validChan[i]; + suppChannels->bands[valid_count][1] = 1; + valid_count++; + } + + suppChannels->num_bands = valid_count; + suppChannels->present = 1; + + /* find channel offset and get op class for current operating channel */ + switch (psessionEntry->htSecondaryChannelOffset) { + case PHY_SINGLE_CHANNEL_CENTERED: + chanOffset = BW20; + break; + + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + chanOffset = BW40_LOW_PRIMARY; + break; + + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + chanOffset = BW40_HIGH_PRIMARY; + break; + + default: + chanOffset = BWALL; + break; + + } + + op_class = cds_regdm_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + chanOffset); + + if (op_class == 0) { + lim_log(pMac, LOGE, + FL( + "Present Operating class is wrong, countryCodeCurrent: %s, currentOperChannel: %d, htSecondaryChannelOffset: %d, chanOffset: %d" + ), + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + psessionEntry->htSecondaryChannelOffset, + chanOffset); + } else { + lim_log(pMac, LOG1, + FL( + "Present Operating channel: %d chanOffset: %d, op class=%d" + ), + psessionEntry->currentOperChannel, chanOffset, + op_class); + } + suppOperClasses->present = 1; + suppOperClasses->classes[0] = op_class; + + cds_regdm_get_curr_opclasses(&numClasses, &classes[0]); + + for (i = 0; i < numClasses; i++) { + suppOperClasses->classes[i + 1] = classes[i]; + } + /* add one for present operating class, added in the beginning */ + suppOperClasses->num_classes = numClasses + 1; + + return; +} + +/* + * FUNCTION: Populate Link Identifier element IE + * + */ + +void populate_dot11f_link_iden(tpAniSirGlobal pMac, tpPESession psessionEntry, + tDot11fIELinkIdentifier *linkIden, + tSirMacAddr peerMac, uint8_t reqType) +{ + uint8_t *initStaAddr = NULL; + uint8_t *respStaAddr = NULL; + + (reqType == TDLS_INITIATOR) ? ((initStaAddr = linkIden->InitStaAddr), + (respStaAddr = linkIden->RespStaAddr)) + : ((respStaAddr = linkIden->InitStaAddr), + (initStaAddr = linkIden->RespStaAddr)); + cdf_mem_copy((uint8_t *) linkIden->bssid, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) initStaAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) respStaAddr, (uint8_t *) peerMac, + sizeof(tSirMacAddr)); + + linkIden->present = 1; + return; + +} + +void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEExtCap *extCapability) +{ + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extCapability->bytes; + + p_ext_cap->tdls_peer_psm_supp = PEER_PSM_SUPPORT; + p_ext_cap->tdls_peer_uapsd_buffer_sta = pMac->lim.gLimTDLSBufStaEnabled; + + /* + * Set TDLS channel switching bits only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + p_ext_cap->tdls_channel_switching = 1; + p_ext_cap->tdls_chan_swit_prohibited = 0; + } else { + p_ext_cap->tdls_channel_switching = 0; + p_ext_cap->tdls_chan_swit_prohibited = TDLS_CH_SWITCH_PROHIBITED; + } + p_ext_cap->tdls_support = TDLS_SUPPORT; + p_ext_cap->tdls_prohibited = TDLS_PROHIBITED; + + extCapability->present = 1; + /* For STA cases we alwasy support 11mc - Allow MAX length */ + extCapability->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + + return; +} + +/** + * lim_process_sme_tdls_mgmt_send_req() - send out tdls management frames + * + * @mac_ctx - global mac context + * @msg - message buffer received from SME. + * + * Process Send Mgmt Request from SME and transmit to AP. + * + * Return: eSIR_SUCCESS on success, error code otherwise + */ +tSirRetStatus lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + /* get all discovery request parameters */ + tSirTdlsSendMgmtReq *send_req = (tSirTdlsSendMgmtReq *) msg; + tpPESession session_entry; + uint8_t session_id; + tSirResultCodes result_code = eSIR_SME_INVALID_PARAMETERS; + + lim_log(mac_ctx, LOG1, FL("Send Mgmt Recieved")); + session_entry = pe_find_session_by_bssid(mac_ctx, + send_req->bssid, &session_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, + FL("PE Session does not exist for given sme session_id %d"), + send_req->sessionId); + goto lim_tdls_send_mgmt_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(session_entry)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("send mgmt received in wrong system Role %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_tdls_send_mgmt_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(mac_ctx, LOGE, + FL("send mgmt received in invalid LIMsme state (%d)"), + session_entry->limSmeState); + goto lim_tdls_send_mgmt_error; + } + + switch (send_req->reqType) { + case SIR_MAC_TDLS_DIS_REQ: + lim_log(mac_ctx, LOG1, FL("Transmit Discovery Request Frame")); + /* format TDLS discovery request frame and transmit it */ + lim_send_tdls_dis_req_frame(mac_ctx, send_req->peerMac, + send_req->dialog, session_entry); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_DIS_RSP: + lim_log(mac_ctx, LOG1, FL("Transmit Discovery Response Frame")); + /* Send a response mgmt action frame */ + lim_send_tdls_dis_rsp_frame(mac_ctx, send_req->peerMac, + send_req->dialog, session_entry, &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_REQ: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Request Frame")); + lim_send_tdls_link_setup_req_frame(mac_ctx, + send_req->peerMac, send_req->dialog, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_RSP: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Response Frame")); + lim_send_tdls_setup_rsp_frame(mac_ctx, + send_req->peerMac, send_req->dialog, session_entry, + send_req->statusCode, &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_CNF: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Confirm Frame")); + lim_send_tdls_link_setup_cnf_frame(mac_ctx, + send_req->peerMac, send_req->dialog, + send_req->peerCapability, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_TEARDOWN: + lim_log(mac_ctx, LOG1, FL("Transmit Teardown Frame")); + lim_send_tdls_teardown_frame(mac_ctx, + send_req->peerMac, send_req->statusCode, + send_req->responder, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_IND: + break; + case SIR_MAC_TDLS_CH_SWITCH_REQ: + break; + case SIR_MAC_TDLS_CH_SWITCH_RSP: + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_RSP: + break; + default: + break; + } + +lim_tdls_send_mgmt_error: + lim_send_sme_rsp(mac_ctx, eWNI_SME_TDLS_SEND_MGMT_RSP, + result_code, send_req->sessionId, + send_req->transactionId); + + return eSIR_SUCCESS; +} + +/* + * Send Response to Link Establish Request to SME + */ +void lim_send_sme_tdls_link_establish_req_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr peerMac, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + + tSirTdlsLinkEstablishReqRsp *pTdlsLinkEstablishReqRsp = NULL; + + pTdlsLinkEstablishReqRsp = + cdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReqRsp)); + if (NULL == pTdlsLinkEstablishReqRsp) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return; + } + pTdlsLinkEstablishReqRsp->statusCode = status; + if (peerMac) { + cdf_mem_copy(pTdlsLinkEstablishReqRsp->peerMac, peerMac, + sizeof(tSirMacAddr)); + } + pTdlsLinkEstablishReqRsp->sessionId = sessionId; + mmhMsg.type = eWNI_SME_TDLS_LINK_ESTABLISH_RSP; + mmhMsg.bodyptr = pTdlsLinkEstablishReqRsp; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; + +} + +/* + * Once link is teardown, send Del Peer Ind to SME + */ +static CDF_STATUS lim_send_sme_tdls_del_sta_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirMacAddr peerMac, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirTdlsDelStaRsp *pDelSta = NULL; + mmhMsg.type = eWNI_SME_TDLS_DEL_STA_RSP; + + pDelSta = cdf_mem_malloc(sizeof(tSirTdlsDelStaRsp)); + if (NULL == pDelSta) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return CDF_STATUS_E_NOMEM; + } + + pDelSta->sessionId = sessionId; + pDelSta->statusCode = status; + if (pStaDs) { + pDelSta->staId = pStaDs->staIndex; + } else + pDelSta->staId = STA_INVALID_IDX; + + if (peerMac) { + cdf_mem_copy(pDelSta->peerMac, peerMac, sizeof(tSirMacAddr)); + } + + pDelSta->length = sizeof(tSirTdlsDelStaRsp); + pDelSta->messageType = eWNI_SME_TDLS_DEL_STA_RSP; + + mmhMsg.bodyptr = pDelSta; + + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return CDF_STATUS_SUCCESS; + +} + +/* + * Process Send Mgmt Request from SME and transmit to AP. + */ +tSirRetStatus lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsAddStaReq *pAddStaReq = (tSirTdlsAddStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + + lim_log(pMac, LOG1, FL("TDLS Add STA Request Recieved")); + psessionEntry = + pe_find_session_by_bssid(pMac, pAddStaReq->bssid, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL( + "PE Session does not exist for given sme sessionId %d" + ), + pAddStaReq->sessionId); + goto lim_tdls_add_sta_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "send mgmt received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_add_sta_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + lim_log(pMac, LOGE, + FL("send mgmt received in invalid LIMsme state (%d)"), + psessionEntry->limSmeState); + goto lim_tdls_add_sta_error; + } + + pMac->lim.gLimAddStaTdls = true; + + /* To start with, send add STA request to HAL */ + if (eSIR_FAILURE == lim_tdls_setup_add_sta(pMac, pAddStaReq, psessionEntry)) { + lim_log(pMac, LOGE, + FL("Add TDLS Station request failed")); + goto lim_tdls_add_sta_error; + } + return eSIR_SUCCESS; +lim_tdls_add_sta_error: + lim_send_sme_tdls_add_sta_rsp(pMac, + pAddStaReq->sessionId, pAddStaReq->peerMac, + (pAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE), + NULL, eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/* + * Process Del Sta Request from SME . + */ +tSirRetStatus lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsDelStaReq *pDelStaReq = (tSirTdlsDelStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + tpDphHashNode pStaDs = NULL; + + lim_log(pMac, LOG1, FL("TDLS Delete STA Request Recieved")); + psessionEntry = + pe_find_session_by_bssid(pMac, pDelStaReq->bssid, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL( + "PE Session does not exist for given sme sessionId %d" + ), + pDelStaReq->sessionId); + lim_send_sme_tdls_del_sta_rsp(pMac, pDelStaReq->sessionId, + pDelStaReq->peerMac, NULL, + eSIR_FAILURE); + return eSIR_FAILURE; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + "Del sta received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_del_sta_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + lim_log(pMac, LOGE, + FL("Del Sta received in invalid LIMsme state (%d)"), + psessionEntry->limSmeState); + goto lim_tdls_del_sta_error; + } + + pStaDs = lim_tdls_del_sta(pMac, pDelStaReq->peerMac, psessionEntry); + + /* now send indication to SME-->HDD->TL to remove STA from TL */ + + if (pStaDs) { + lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, + pDelStaReq->peerMac, pStaDs, + eSIR_SUCCESS); + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + + /* Clear the aid in peerAIDBitmap as this aid is now in freepool */ + CLEAR_PEER_AID_BITMAP(psessionEntry->peerAIDBitmap, + pStaDs->assocId); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, + psessionEntry); + + return eSIR_SUCCESS; + + } + +lim_tdls_del_sta_error: + lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, + pDelStaReq->peerMac, NULL, eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/* Intersects the two input arrays and outputs an array */ +/* For now the array length of uint8_t suffices */ +static void lim_tdls_get_intersection(uint8_t *input_array1, + uint8_t input1_length, + uint8_t *input_array2, + uint8_t input2_length, + uint8_t *output_array, + uint8_t *output_length) +{ + uint8_t i, j, k = 0, flag = 0; + for (i = 0; i < input1_length; i++) { + flag = 0; + for (j = 0; j < input2_length; j++) { + if (input_array1[i] == input_array2[j]) { + flag = 1; + break; + } + } + if (flag == 1) { + output_array[k] = input_array1[i]; + k++; + } + } + *output_length = k; +} + +/** + * lim_process_sme_tdls_link_establish_req() - process tdls link establishment + * request + * + * @mac_ctx - global MAC context + * @msg_buf - message buffer from SME + * + * Process Link Establishment Request from SME + * + * Return: eSIR_SUCCESS on success, failure code otherwise. + */ +tSirRetStatus lim_process_sme_tdls_link_establish_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + /* get all discovery request parameters */ + tSirTdlsLinkEstablishReq *tdls_req = + (tSirTdlsLinkEstablishReq *) msg_buf; + tpPESession session_entry; + uint8_t session_id; + tpTdlsLinkEstablishParams tdls_req_params; + tSirMsgQ msg; + uint16_t peer_idx = 0; + tpDphHashNode stads = NULL; + uint32_t self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t self_supp_chan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("Send Mgmt Recieved")); + + session_entry = pe_find_session_by_bssid(mac_ctx, tdls_req->bssid, + &session_id); + if (NULL == session_entry) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("PE Session does not exist for sme session_id %d"), + tdls_req->sessionId); + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + tdls_req->sessionId, tdls_req->peerMac, NULL, + eSIR_FAILURE); + return eSIR_FAILURE; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(session_entry)) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("TDLS Link Establish Request received in wrong system Role %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_tdls_link_establish_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(mac_ctx, LOGE, + FL("TDLS Link Establish Request received in invalid LIMsme state (%d)"), + session_entry->limSmeState); + goto lim_tdls_link_establish_error; + } + + stads = dph_lookup_hash_entry(mac_ctx, tdls_req->peerMac, &peer_idx, + &session_entry->dph.dphHashTable); + if (NULL == stads) { + lim_log(mac_ctx, LOGE, FL("stads is NULL")); + goto lim_tdls_link_establish_error; + } + tdls_req_params = cdf_mem_malloc(sizeof(tTdlsLinkEstablishParams)); + if (NULL == tdls_req_params) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory TDLS Link Establish Request")); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) tdls_req_params, + sizeof(tTdlsLinkEstablishParams), 0); + + tdls_req_params->staIdx = stads->staIndex; + tdls_req_params->isResponder = tdls_req->isResponder; + tdls_req_params->uapsdQueues = tdls_req->uapsdQueues; + tdls_req_params->maxSp = tdls_req->maxSp; + tdls_req_params->isBufsta = tdls_req->isBufSta; + tdls_req_params->isOffChannelSupported = + tdls_req->isOffChannelSupported; + + if (0 == tdls_req->supportedChannelsLen) + goto send_tdls_establish_request; + + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, + self_supp_chan, + &self_num_chan) != eSIR_SUCCESS) { + /** + * Could not get Valid channel list from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGE, + FL("could not retrieve Valid channel list")); + } + + if (self_num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + lim_log(mac_ctx, LOGE, + FL("Channel List more than Valid Channel list")); + self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; + } + + if (tdls_req->supportedChannelsLen > SIR_MAC_MAX_SUPP_CHANNELS) { + lim_log(mac_ctx, LOGE, + FL("Channel List is more than the supported Channel list")); + tdls_req->supportedChannelsLen = SIR_MAC_MAX_SUPP_CHANNELS; + } + + lim_tdls_get_intersection(self_supp_chan, self_num_chan, + tdls_req->supportedChannels, tdls_req->supportedChannelsLen, + tdls_req_params->validChannels, + &tdls_req_params->validChannelsLen); + +send_tdls_establish_request: + cdf_mem_copy(tdls_req_params->validOperClasses, + tdls_req->supportedOperClasses, + tdls_req->supportedOperClassesLen); + tdls_req_params->validOperClassesLen = + tdls_req->supportedOperClassesLen; + + msg.type = WMA_SET_TDLS_LINK_ESTABLISH_REQ; + msg.reserved = 0; + msg.bodyptr = tdls_req_params; + msg.bodyval = 0; + if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) { + lim_log(mac_ctx, LOGE, FL("halPostMsgApi failed")); + goto lim_tdls_link_establish_error; + } + return eSIR_SUCCESS; + +lim_tdls_link_establish_error: + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + session_entry->smeSessionId, tdls_req->peerMac, NULL, + eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/** + * lim_delete_tdls_peers() - delete tdls peers + * + * @mac_ctx - global MAC context + * @session_entry - PE session entry + * + * Delete all the TDLS peer connected before leaving the BSS + * + * Return: eSIR_SUCCESS on success, error code otherwise + */ +tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + tpDphHashNode stads = NULL; + int i, aid; + size_t aid_bitmap_size = sizeof(session_entry->peerAIDBitmap); + + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("NULL session_entry")); + return eSIR_FAILURE; + } + + /* + * Check all the set bit in peerAIDBitmap and delete the peer + * (with that aid) entry from the hash table and add the aid + * in free pool + */ + for (i = 0; i < aid_bitmap_size / sizeof(uint32_t); i++) { + for (aid = 0; aid < (sizeof(uint32_t) << 3); aid++) { + if (!CHECK_BIT(session_entry->peerAIDBitmap[i], aid)) + continue; + stads = dph_get_hash_entry(mac_ctx, + (aid + i * (sizeof(uint32_t) << 3)), + &session_entry->dph.dphHashTable); + + if (NULL != stads) { + lim_log(mac_ctx, LOGE, + FL("Deleting "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(stads->staAddr)); + + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + stads->staAddr, session_entry, false); + dph_delete_hash_entry(mac_ctx, + stads->staAddr, stads->assocId, + &session_entry->dph.dphHashTable); + } + lim_release_peer_idx(mac_ctx, + (aid + i * (sizeof(uint32_t) << 3)), + session_entry); + CLEAR_BIT(session_entry->peerAIDBitmap[i], aid); + } + } + lim_send_sme_tdls_delete_all_peer_ind(mac_ctx, session_entry); + + return eSIR_SUCCESS; +} + +#endif diff --git a/core/mac/src/pe/lim/lim_prop_exts_utils.c b/core/mac/src/pe/lim/lim_prop_exts_utils.c new file mode 100644 index 0000000000..d5349059ed --- /dev/null +++ b/core/mac/src/pe/lim/lim_prop_exts_utils.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_prop_exts_utils.cc contains the utility functions + * to populate, parse proprietary extensions required to + * support ANI feature set. + * + * Author: Chandra Modumudi + * Date: 11/27/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "utils_api.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_trace.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#define LIM_GET_NOISE_MAX_TRY 5 +/** + * lim_extract_ap_capability() - extract AP's HCF/WME/WSM capability + * @mac_ctx: Pointer to Global MAC structure + * @p_ie: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * @qos_cap: Bits are set according to capabilities + * @prop_cap: Pointer to prop info IE. + * @uapsd: pointer to uapsd + * @local_constraint: Pointer to local power constraint. + * @session: A pointer to session entry. + * + * This function is called to extract AP's HCF/WME/WSM capability + * from the IEs received from it in Beacon/Probe Response frames + * + * Return: None + */ +void +lim_extract_ap_capability(tpAniSirGlobal mac_ctx, uint8_t *p_ie, + uint16_t ie_len, uint8_t *qos_cap, uint16_t *prop_cap, uint8_t *uapsd, + tPowerdBm *local_constraint, tpPESession session) +{ + tSirProbeRespBeacon *beacon_struct; +#if !defined WLAN_FEATURE_VOWIFI + uint32_t local_power_constraints = 0; +#endif + uint32_t enable_txbf_20mhz; + tSirRetStatus cfg_set_status = eSIR_FAILURE; + tSirRetStatus cfg_get_status = eSIR_FAILURE; + + beacon_struct = cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == beacon_struct) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + + cdf_mem_set((uint8_t *) beacon_struct, sizeof(tSirProbeRespBeacon), 0); + *qos_cap = 0; + *prop_cap = 0; + *uapsd = 0; + lim_log(mac_ctx, LOG3, + FL("In lim_extract_ap_capability: The IE's being received:")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG3, p_ie, ie_len); + if (sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie, + (uint32_t) ie_len) == eSIR_SUCCESS) { + if (beacon_struct->wmeInfoPresent + || beacon_struct->wmeEdcaPresent) + LIM_BSS_CAPS_SET(WME, *qos_cap); + if (LIM_BSS_CAPS_GET(WME, *qos_cap) + && beacon_struct->wsmCapablePresent) + LIM_BSS_CAPS_SET(WSM, *qos_cap); + if (beacon_struct->propIEinfo.capabilityPresent) + *prop_cap = beacon_struct->propIEinfo.capability; + if (beacon_struct->HTCaps.present) + mac_ctx->lim.htCapabilityPresentInBeacon = 1; + else + mac_ctx->lim.htCapabilityPresentInBeacon = 0; + +#ifdef WLAN_FEATURE_11AC + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_MED, + "beacon.VHTCaps.present = %d BSS_VHT_Capable:%d", + beacon_struct->VHTCaps.present, + IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps)); + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO_MED, + "***beacon.SU Beamformer Capable*****=%d", + beacon_struct->VHTCaps.suBeamFormerCap); + + if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) && + beacon_struct->VHTOperation.present && + session->vhtCapability) { + session->vhtCapabilityPresentInBeacon = 1; + if (((beacon_struct->Vendor1IEPresent && + beacon_struct->vendor2_ie.present && + beacon_struct->Vendor3IEPresent)) && + (((beacon_struct->VHTCaps.txMCSMap & + VHT_MCS_3x3_MASK) == VHT_MCS_3x3_MASK) && + ((beacon_struct->VHTCaps.txMCSMap & + VHT_MCS_2x2_MASK) != VHT_MCS_2x2_MASK))) { + session->txBFIniFeatureEnabled = 0; + } + } else { + session->vhtCapabilityPresentInBeacon = 0; + } + if (session->vhtCapabilityPresentInBeacon == 1 && + session->txBFIniFeatureEnabled == 0) { + cfg_set_status = cfg_set_int(mac_ctx, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + 0); + if (cfg_set_status != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Set VHT_SU_BEAMFORMEE_CAP Fail")); + } + if (session->vhtCapabilityPresentInBeacon == 1 && + !session->htSupportedChannelWidthSet) { + cfg_get_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enable_txbf_20mhz); + if ((IS_SIR_STATUS_SUCCESS(cfg_get_status)) && + (false == enable_txbf_20mhz)) + session->txBFIniFeatureEnabled = 0; + } else if (session->vhtCapabilityPresentInBeacon == 1 && + beacon_struct->VHTOperation.chanWidth) { + session->ch_center_freq_seg0 = + beacon_struct->VHTOperation.chanCenterFreqSeg1; + session->ch_center_freq_seg1 = + beacon_struct->VHTOperation.chanCenterFreqSeg2; + session->ch_width = + beacon_struct->VHTOperation.chanWidth + 1; + if (CH_WIDTH_80MHZ < session->ch_width) { + session->enable_su_tx_bformer = 0; + session->nss = 1; + } + } + if (session->vhtCapabilityPresentInBeacon == 1 && + !session->htSupportedChannelWidthSet && + session->txBFIniFeatureEnabled == 0) { + cfg_set_status = cfg_set_int(mac_ctx, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + 0); + if (cfg_set_status != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Set VHT_SU_BEAMFORMEE_CAP Fail")); + } +#endif + /* Extract the UAPSD flag from WMM Parameter element */ + if (beacon_struct->wmeEdcaPresent) + *uapsd = beacon_struct->edcaParams.qosInfo.uapsd; +#if defined FEATURE_WLAN_ESE + /* If there is Power Constraint Element specifically, + * adapt to it. Hence there is else condition check + * for this if statement. + */ + if (beacon_struct->eseTxPwr.present) + *local_constraint = beacon_struct->eseTxPwr.power_limit; + session->is_ese_version_ie_present = + beacon_struct->is_ese_ver_ie_present; +#endif + if (beacon_struct->powerConstraintPresent) { +#if defined WLAN_FEATURE_VOWIFI + *local_constraint -= + beacon_struct->localPowerConstraint. + localPowerConstraints; +#else + local_power_constraints = + (uint32_t) beacon_struct->localPowerConstraint. + localPowerConstraints; +#endif + } +#if !defined WLAN_FEATURE_VOWIFI + if (cfg_set_int + (mac_ctx, WNI_CFG_LOCAL_POWER_CONSTRAINT, + local_power_constraints) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL + ("Could not update local power constraint to cfg.")); + } +#endif + session->country_info_present = false; + /* Initializing before first use */ + if (beacon_struct->countryInfoPresent) + session->country_info_present = true; + } + cdf_mem_free(beacon_struct); + return; +} /****** end lim_extract_ap_capability() ******/ + +/** + * lim_get_htcb_state + * + ***FUNCTION: + * This routing provides the translation of Airgo Enum to HT enum for determining + * secondary channel offset. + * Airgo Enum is required for backward compatibility purposes. + * + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return The corresponding HT enumeration + */ +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode) +{ + switch (aniCBMode) { +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: +#endif + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: +#endif + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + return PHY_SINGLE_CHANNEL_CENTERED; +#endif + default: + return PHY_SINGLE_CHANNEL_CENTERED; + } +} + +/* + * lim_get_sta_peer_type + * + ***FUNCTION: + * This API returns STA peer type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the tpDphHashNode of the STA + * under consideration + * @return tStaRateMode + */ +tStaRateMode lim_get_sta_peer_type(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{ + tStaRateMode staPeerType = eSTA_11b; +#ifdef WLAN_FEATURE_11AC + if (pStaDs->mlmStaContext.vhtCapability) + staPeerType = eSTA_11ac; +#endif + else if (pStaDs->mlmStaContext.htCapability) + staPeerType = eSTA_11n; + else if (pStaDs->erpEnabled) + staPeerType = eSTA_11bg; + else if (psessionEntry->limRFBand == SIR_BAND_5_GHZ) + staPeerType = eSTA_11a; + return staPeerType; +} diff --git a/core/mac/src/pe/lim/lim_prop_exts_utils.h b/core/mac/src/pe/lim/lim_prop_exts_utils.h new file mode 100644 index 0000000000..a648a78ddb --- /dev/null +++ b/core/mac/src/pe/lim/lim_prop_exts_utils.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_prop_exts_utils.h contains the definitions + * used by all LIM modules to support proprietary features. + * Author: Chandra Modumudi + * Date: 12/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_PROP_EXTS_UTILS_H +#define __LIM_PROP_EXTS_UTILS_H + +/* Function templates */ +void limQuietBss(tpAniSirGlobal, uint32_t); +void lim_cleanupMeasData(tpAniSirGlobal); +void limDeleteMeasTimers(tpAniSirGlobal); +void limStopMeasTimers(tpAniSirGlobal pMac); +void lim_cleanupMeasResources(tpAniSirGlobal); +void limRestorePreLearnState(tpAniSirGlobal); +void limCollectMeasurementData(tpAniSirGlobal, uint32_t *, tpSchBeaconStruct); +void limCollectRSSI(tpAniSirGlobal); +void limDeleteCurrentBssWdsNode(tpAniSirGlobal); +uint32_t limComputeAvg(tpAniSirGlobal, uint32_t, uint32_t); + +/* / Function to extract AP's HCF capability from IE fields */ +void lim_extract_ap_capability(tpAniSirGlobal, uint8_t *, uint16_t, uint8_t *, + uint16_t *, uint8_t *, tPowerdBm *, tpPESession); + +tStaRateMode lim_get_sta_peer_type(tpAniSirGlobal, tpDphHashNode, tpPESession); +#ifdef WLAN_FEATURE_11AC +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); +#endif + +#endif /* __LIM_PROP_EXTS_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_scan_result_utils.c b/core/mac/src/pe/lim/lim_scan_result_utils.c new file mode 100644 index 0000000000..387152e92f --- /dev/null +++ b/core/mac/src/pe/lim/lim_scan_result_utils.c @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_scan_result_utils.cc contains the utility functions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_api.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif +#include "cds_utils.h" + + +/** + * lim_collect_bss_description() + * + ***FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * frame matches scan criteria, collect BSS description + * and add it to cached scan results. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pBPR - Pointer to parsed Beacon/Probe Response structure + * @param pRxPacketInfo - Pointer to Received frame's BD + * ---------if defined WLAN_FEATURE_VOWIFI------ + * @param fScanning - flag to indicate if it is during scan. + * --------------------------------------------- + * + * @return None + */ +#if defined WLAN_FEATURE_VOWIFI +CDF_STATUS +lim_collect_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning) +#else +CDF_STATUS +lim_collect_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, uint8_t *pRxPacketInfo) +#endif +{ + uint8_t *pBody; + uint32_t ieLen = 0; + tpSirMacMgmtHdr pHdr; + uint8_t channelNum; + uint8_t rxChannel; + uint8_t rfBand = 0; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (SIR_MAC_B_PR_SSID_OFFSET > WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)) { + CDF_ASSERT(WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) >= + SIR_MAC_B_PR_SSID_OFFSET); + return CDF_STATUS_E_FAILURE; + } + ieLen = + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) - SIR_MAC_B_PR_SSID_OFFSET; + rxChannel = WMA_GET_RX_CH(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + rfBand = WMA_GET_RX_RFBAND(pRxPacketInfo); + + /** + * Length of BSS desription is without length of + * length itself and length of pointer that holds ieFields. + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + pBssDescr->length = (uint16_t)(offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pBssDescr->length) + ieLen); + + /* Copy BSS Id */ + cdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) pHdr->bssId, sizeof(tSirMacAddr)); + + /* Copy Timestamp, Beacon Interval and Capability Info */ + pBssDescr->scanSysTimeMsec = cdf_mc_timer_get_system_time(); + + pBssDescr->timeStamp[0] = pBPR->timeStamp[0]; + pBssDescr->timeStamp[1] = pBPR->timeStamp[1]; + pBssDescr->beaconInterval = pBPR->beaconInterval; + pBssDescr->capabilityInfo = + lim_get_u16((uint8_t *) &pBPR->capabilityInfo); + + if (!pBssDescr->beaconInterval) { + lim_log(pMac, LOGW, + FL("Beacon Interval is ZERO, making it to default 100 " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->bssId)); + pBssDescr->beaconInterval = 100; + } + /* + * There is a narrow window after Channel Switch msg is sent to HAL and before the AGC is shut + * down and beacons/Probe Rsps can trickle in and we may report the incorrect channel in 5Ghz + * band, so not relying on the 'last Scanned Channel' stored in LIM. + * Instead use the value returned by RXP in BD. This the the same value which HAL programs into + * RXP before every channel switch. + * Right now there is a problem in 5Ghz, where we are receiving beacons from a channel different from + * the currently scanned channel. so incorrect channel is reported to CSR and association does not happen. + * So for now we keep on looking for the channel info in the beacon (DSParamSet IE OR HT Info IE), and only if it + * is not present in the beacon, we go for the channel info present in RXP. + * This fix will work for 5Ghz 11n devices, but for 11a devices, we have to rely on RXP routing flag to get the correct channel. + * So The problem of incorrect channel reporting in 5Ghz will still remain for 11a devices. + */ + pBssDescr->channelId = lim_get_channel_from_beacon(pMac, pBPR); + + if (pBssDescr->channelId == 0) { + /* If the channel Id is not retrieved from Beacon, extract the channel from BD */ + if (!rxChannel) { + rxChannel = pMac->lim.gLimCurrentScanChannelId; + } + pBssDescr->channelId = rxChannel; + } + + pBssDescr->channelIdSelf = pBssDescr->channelId; + /* set the network type in bss description */ + channelNum = pBssDescr->channelId; + pBssDescr->nwType = + lim_get_nw_type(pMac, channelNum, SIR_MAC_MGMT_FRAME, pBPR); + + /* Copy RSSI & SINR from BD */ + + lim_log(pMac, LOG4, "*********BSS Description for BSSID:********* "); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, pBssDescr->bssId, 6); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, + (uint8_t *) pRxPacketInfo, 36); + + pBssDescr->rssi = (int8_t) WMA_GET_RX_RSSI_DB(pRxPacketInfo); + + /* SINR no longer reported by HW */ + pBssDescr->sinr = 0; + + pBssDescr->nReceivedTime = (uint32_t) cdf_mc_timer_get_system_ticks(); + pBssDescr->tsf_delta = WMA_GET_RX_TSF_DELTA(pRxPacketInfo); + + lim_log(pMac, LOG1, FL("BSSID: "MAC_ADDRESS_STR " tsf_delta = %u"), + MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->tsf_delta); + +#if defined WLAN_FEATURE_VOWIFI + if (fScanning) { + rrm_get_start_tsf(pMac, pBssDescr->startTSF); + pBssDescr->parentTSF = WMA_GET_RX_TIMESTAMP(pRxPacketInfo); + } +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* MobilityDomain */ + pBssDescr->mdie[0] = 0; + pBssDescr->mdie[1] = 0; + pBssDescr->mdie[2] = 0; + pBssDescr->mdiePresent = false; + /* If mdie is present in the probe resp we */ + /* fill it in the bss description */ + if (pBPR->mdiePresent) { + pBssDescr->mdiePresent = true; + pBssDescr->mdie[0] = pBPR->mdie[0]; + pBssDescr->mdie[1] = pBPR->mdie[1]; + pBssDescr->mdie[2] = pBPR->mdie[2]; + } +#endif + +#ifdef FEATURE_WLAN_ESE + pBssDescr->QBSSLoad_present = false; + pBssDescr->QBSSLoad_avail = 0; + if (pBPR->QBSSLoad.present) { + pBssDescr->QBSSLoad_present = true; + pBssDescr->QBSSLoad_avail = pBPR->QBSSLoad.avail; + } +#endif + /* Copy IE fields */ + cdf_mem_copy((uint8_t *) &pBssDescr->ieFields, + pBody + SIR_MAC_B_PR_SSID_OFFSET, ieLen); + + /*set channel number in beacon in case it is not present */ + pBPR->channelNumber = pBssDescr->channelId; + + lim_log(pMac, LOG3, + FL("Collected BSS Description for Channel(%1d), length(%u), IE Fields(%u)"), + pBssDescr->channelId, pBssDescr->length, ieLen); + + return CDF_STATUS_SUCCESS; +} /*** end lim_collect_bss_description() ***/ + +/** + * lim_is_scan_requested_ssid() + * + ***FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * SSID is present in the list of requested SSIDs in scan + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param ssId - SSID Received in beacons/Probe responses that is compared against the + requeusted SSID in scan list + * --------------------------------------------- + * + * @return bool - true if SSID is present in requested list, false otherwise + */ + +bool lim_is_scan_requested_ssid(tpAniSirGlobal pMac, tSirMacSSid *ssId) +{ + uint8_t i = 0; + + for (i = 0; i < pMac->lim.gpLimMlmScanReq->numSsid; i++) { + if (true == cdf_mem_compare((uint8_t *) ssId, + (uint8_t *) &pMac->lim. + gpLimMlmScanReq->ssId[i], + (uint8_t) (pMac->lim. + gpLimMlmScanReq->ssId[i]. + length + 1))) { + return true; + } + } + return false; +} + +/** + * lim_check_and_add_bss_description() + * @mac_ctx: Pointer to Global MAC structure + * @bpr: Pointer to parsed Beacon/Probe Response structure + * @rx_packet_info: Pointer to Received frame's BD + * @scanning: bool to indicate whether the BSS is from current scan + * or just happens to receive a beacon + * + * FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * frame matches scan criteria, collect BSS description + * and add it to cached scan results. + * + * Return: None + */ + +void +lim_check_and_add_bss_description(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon bpr, uint8_t *rx_packet_info, + bool scanning, uint8_t fProbeRsp) +{ + tSirBssDescription *bssdescr = NULL; + uint32_t frame_len, ie_len = 0; + uint8_t rx_chan_in_beacon = 0; + CDF_STATUS status; + uint8_t dont_update_all = 0; + uint8_t rf_band = 0; + uint8_t rx_chan_bd = 0; + + tSirMacAddr bssid_zero = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + tpSirMacDataHdr3a hdr; + + hdr = WMA_GET_RX_MPDUHEADER3A((uint8_t *) rx_packet_info); + + /* Check For Null BSSID and Skip in case of P2P */ + if (cdf_mem_compare(bssid_zero, &hdr->addr3, 6)) + return; + + /* + * SSID/BSSID policy: + * Accept beacons/probe responses with any SSID or BSSID because + * multiple scan requests may be running at the same time and + * firmware may forward results to CLD from scans requested through a + * different path. + * + * CSA Policy: + * There is no point in caching & reporting the scan results for APs + * which are in the process of switching the channel. So, we are not + * caching the scan results for APs which are adverzing the + * channel-switch element in their beacons and probe responses. + */ + if (bpr->channelSwitchPresent) + return; + + /* + * If beacon/probe resp DS param channel does not match with + * RX BD channel then don't save the results. It might be a beacon + * from another channel heard as noise on the current scanning channel + */ + + if ((bpr->dsParamsPresent) || (bpr->HTInfo.present)) { + /* This means that we are in 2.4GHz mode or 5GHz 11n mode */ + rx_chan_in_beacon = lim_get_channel_from_beacon(mac_ctx, bpr); + rf_band = WMA_GET_RX_RFBAND(rx_packet_info); + rx_chan_bd = WMA_GET_RX_CH(rx_packet_info); + + if (rx_chan_bd != rx_chan_in_beacon) { + /* BCAST Frame, if CH do not match, Drop */ + if (WMA_IS_RX_BCAST(rx_packet_info)) { + lim_log(mac_ctx, LOG3, + FL("Beacon/Probe Rsp dropped. Channel in BD %d. Channel in beacon %d"), + WMA_GET_RX_CH(rx_packet_info), + lim_get_channel_from_beacon(mac_ctx, + bpr)); + return; + } + /* Unit cast frame, Probe RSP, do not drop */ + else { + dont_update_all = 1; + lim_log(mac_ctx, LOG3, + FL("SSID %s, CH in ProbeRsp %d, CH in BD %d, mismatch, Do Not Drop"), + bpr->ssId.ssId, rx_chan_in_beacon, + WMA_GET_RX_CH(rx_packet_info)); + WMA_GET_RX_CH(rx_packet_info) = + rx_chan_in_beacon; + } + } + } + + /* + * Allocate buffer to hold BSS description from + * received Beacon frame. + * Include size of fixed fields and IEs length + */ + + ie_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + if (ie_len <= SIR_MAC_B_PR_SSID_OFFSET) { + lim_log(mac_ctx, LOGP, + FL("RX packet has invalid length %d"), ie_len); + return; + } + + ie_len -= SIR_MAC_B_PR_SSID_OFFSET; + + /* IEs will be overlap ieFields field. Adjust the length accordingly */ + frame_len = sizeof(*bssdescr) + ie_len - sizeof(bssdescr->ieFields[1]); + bssdescr = (tSirBssDescription *) cdf_mem_malloc(frame_len); + + if (NULL == bssdescr) { + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("cdf_mem_malloc(length=%d) failed"), frame_len); + return; + } + /* In scan state, store scan result. */ +#if defined WLAN_FEATURE_VOWIFI + status = lim_collect_bss_description(mac_ctx, bssdescr, + bpr, rx_packet_info, scanning); + if (CDF_STATUS_SUCCESS != status) + goto last; +#else + status = lim_collect_bss_description(mac_ctx, bssdescr, + bpr, rx_packet_info); + if (CDF_STATUS_SUCCESS != status) + goto last; +#endif + bssdescr->fProbeRsp = fProbeRsp; + + /* + * Send the beacon to CSR with registered callback routine. + * scan_id and flags parameters are currently unused and set to 0. + */ + if (mac_ctx->lim.add_bssdescr_callback) { + (mac_ctx->lim.add_bssdescr_callback) (mac_ctx, bssdescr, 0, 0); + } else { + lim_log(mac_ctx, LOGE, + FL("No CSR callback routine to send beacons")); + status = CDF_STATUS_E_INVAL; + } +last: + cdf_mem_free(bssdescr); + return; +} + diff --git a/core/mac/src/pe/lim/lim_scan_result_utils.h b/core/mac/src/pe/lim/lim_scan_result_utils.h new file mode 100644 index 0000000000..c622dc2c8a --- /dev/null +++ b/core/mac/src/pe/lim/lim_scan_result_utils.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_scan_result_utils.h contains the utility definitions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SCAN_UTILS_H +#define __LIM_SCAN_UTILS_H + +#include "parser_api.h" +#include "lim_types.h" + +/* Scan result hash related functions */ +uint8_t lim_scan_hash_function(tSirMacAddr); +void lim_restore_pre_scan_state(tpAniSirGlobal); +void lim_copy_scan_result(tpAniSirGlobal, uint8_t *); +void lim_check_and_add_bss_description(tpAniSirGlobal, tpSirProbeRespBeacon, + uint8_t *, bool, uint8_t); +#if defined WLAN_FEATURE_VOWIFI +CDF_STATUS lim_collect_bss_description(tpAniSirGlobal, + tSirBssDescription *, + tpSirProbeRespBeacon, uint8_t *, uint8_t); +#else +CDF_STATUS lim_collect_bss_description(tpAniSirGlobal, + tSirBssDescription *, + tpSirProbeRespBeacon, uint8_t *); +#endif + +#endif /* __LIM_SCAN_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c new file mode 100644 index 0000000000..ae0a42224d --- /dev/null +++ b/core/mac/src/pe/lim/lim_security_utils.c @@ -0,0 +1,1075 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" +#include "wni_api.h" + +#include "sir_common.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" + +#define LIM_SEED_LENGTH 16 +/* + * preauth node timeout value in interval of 10msec + */ +#define LIM_OPENAUTH_TIMEOUT 500 + +/** + * lim_is_auth_algo_supported() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed authentication algorithm is enabled + * or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param authType Indicates MAC based authentication type + * (eSIR_OPEN_SYSTEM or eSIR_SHARED_KEY) + * If Shared Key authentication to be used, + * 'Privacy Option Implemented' flag is also + * checked. + * + * @return true if passed authType is enabled else false + */ +uint8_t +lim_is_auth_algo_supported(tpAniSirGlobal pMac, tAniAuthType authType, + tpPESession psessionEntry) +{ + uint32_t algoEnable, privacyOptImp; + + if (authType == eSIR_OPEN_SYSTEM) { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_OPEN_SYSTEM) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + return true; + else + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + &algoEnable) != eSIR_SUCCESS) { + /** + * Could not get AuthAlgo1 Enable value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve AuthAlgo1 Enable value")); + + return false; + } else + return ((algoEnable > 0 ? true : false)); + } else { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_SHARED_KEY) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + algoEnable = true; + else + algoEnable = false; + + } else + + if (wlan_cfg_get_int + (pMac, WNI_CFG_SHARED_KEY_AUTH_ENABLE, + &algoEnable) != eSIR_SUCCESS) { + /** + * Could not get AuthAlgo2 Enable value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve AuthAlgo2 Enable value")); + + return false; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + privacyOptImp = psessionEntry->privacy; + } else + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &privacyOptImp) != eSIR_SUCCESS) + { + /** + * Could not get PrivacyOptionImplemented value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL + ("could not retrieve PrivacyOptImplemented value")); + + return false; + } + return (algoEnable && privacyOptImp); + } +} /****** end lim_is_auth_algo_supported() ******/ + +/** + * lim_init_pre_auth_list + * + ***FUNCTION: + * This function is called while starting a BSS at AP + * to initialize MAC authenticated STA list. This may also be called + * while joining/starting an IBSS if MAC authentication is allowed + * in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_init_pre_auth_list(tpAniSirGlobal pMac) +{ + pMac->lim.pLimPreAuthList = NULL; + +} /*** end lim_init_pre_auth_list() ***/ + +/** + * lim_delete_pre_auth_list + * + ***FUNCTION: + * This function is called cleanup Pre-auth list either on + * AP or on STA when moving from one persona to other. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_delete_pre_auth_list(tpAniSirGlobal pMac) +{ + struct tLimPreAuthNode *pCurrNode, *pTempNode; + + pCurrNode = pTempNode = pMac->lim.pLimPreAuthList; + while (pCurrNode != NULL) { + pTempNode = pCurrNode->next; + + PELOG1(lim_log(pMac, LOG1, FL("=====> lim_delete_pre_auth_list "));) + lim_release_pre_auth_node(pMac, pCurrNode); + + pCurrNode = pTempNode; + } + pMac->lim.pLimPreAuthList = NULL; +} /*** end lim_delete_pre_auth_list() ***/ + +/** + * lim_search_pre_auth_list + * + ***FUNCTION: + * This function is called when Authentication frame is received + * by AP (or at a STA in IBSS supporting MAC based authentication) + * to search if a STA is in the middle of MAC Authentication + * transaction sequence. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the STA that sent + * Authentication frame. + * + * @return Pointer to pre-auth node if found, else NULL + */ + +struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pTempNode = pMac->lim.pLimPreAuthList; + + while (pTempNode != NULL) { + if (cdf_mem_compare((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + + pTempNode = pTempNode->next; + } + + return pTempNode; +} /*** end lim_search_pre_auth_list() ***/ + +/** + * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to delete any stale preauth nodes on + * receiving authentication frame and existing preauth nodes + * reached the maximum allowed limit. + * + * Return: return true if any preauthnode deleted else false + */ +uint8_t +lim_delete_open_auth_pre_auth_node(tpAniSirGlobal mac_ctx) +{ + struct tLimPreAuthNode *prev_node, *temp_node, *found_node; + uint8_t auth_node_freed = false; + + temp_node = prev_node = mac_ctx->lim.pLimPreAuthList; + + if (temp_node == NULL) + return auth_node_freed; + + while (temp_node != NULL) { + if (temp_node->mlmState == eLIM_MLM_AUTHENTICATED_STATE && + temp_node->authType == eSIR_OPEN_SYSTEM && + (cdf_mc_timer_get_system_ticks() > + (LIM_OPENAUTH_TIMEOUT + temp_node->timestamp) || + cdf_mc_timer_get_system_ticks() < temp_node->timestamp)) { + /* Found node to be deleted */ + auth_node_freed = true; + found_node = temp_node; + if (mac_ctx->lim.pLimPreAuthList == temp_node) { + prev_node = mac_ctx->lim.pLimPreAuthList = + temp_node = found_node->next; + } else { + prev_node->next = temp_node->next; + temp_node = prev_node->next; + } + + lim_release_pre_auth_node(mac_ctx, found_node); + } else { + prev_node = temp_node; + temp_node = prev_node->next; + } + } + + return auth_node_freed; +} + +/** + * lim_add_pre_auth_node + * + ***FUNCTION: + * This function is called at AP while sending Authentication + * frame2. + * This may also be called on a STA in IBSS if MAC authentication is + * allowed in IBSS mode. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to pre-auth node to be added to the list. + * + * @return None + */ + +void lim_add_pre_auth_node(tpAniSirGlobal pMac, struct tLimPreAuthNode *pAuthNode) +{ + pMac->lim.gLimNumPreAuthContexts++; + + pAuthNode->next = pMac->lim.pLimPreAuthList; + + pMac->lim.pLimPreAuthList = pAuthNode; +} /*** end lim_add_pre_auth_node() ***/ + +/** + * lim_release_pre_auth_node + * + ***FUNCTION: + * This function is called to realease the accquired + * pre auth node from list. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to Pre Auth node to be released + * @return None + */ + +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode) +{ + pAuthNode->fFree = 1; + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, + eLIM_PRE_AUTH_CLEANUP_TIMER)); + tx_timer_deactivate(&pAuthNode->timer); + pMac->lim.gLimNumPreAuthContexts--; +} /*** end lim_release_pre_auth_node() ***/ + +/** + * lim_delete_pre_auth_node + * + ***FUNCTION: + * This function is called at AP when a pre-authenticated STA is + * Associated/Reassociated or when AuthFrame4 is received after + * Auth Response timeout. + * This may also be called on a STA in IBSS if MAC authentication and + * Association/Reassociation is allowed in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param peerMacAddr - MAC address of the STA that need to be deleted + * from pre-auth node list. + * + * @return None + */ + +void lim_delete_pre_auth_node(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pPrevNode, *pTempNode; + + pTempNode = pPrevNode = pMac->lim.pLimPreAuthList; + + if (pTempNode == NULL) + return; + + if (cdf_mem_compare((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* First node to be deleted */ + + pMac->lim.pLimPreAuthList = pTempNode->next; + + PELOG1(lim_log + (pMac, LOG1, + FL + ("=====> lim_delete_pre_auth_node : first node to delete")); + ) + PELOG1(lim_log + (pMac, LOG1, + FL("Release data entry: %x id %d peer "), pTempNode, + pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOG1); + ) + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pTempNode = pTempNode->next; + + while (pTempNode != NULL) { + if (cdf_mem_compare((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* Found node to be deleted */ + + pPrevNode->next = pTempNode->next; + + PELOG1(lim_log + (pMac, LOG1, + FL + ("=====> lim_delete_pre_auth_node : subsequent node to delete")); + lim_log(pMac, LOG1, + FL("Release data entry: %x id %d peer "), + pTempNode, pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOG1); + ) + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pPrevNode = pTempNode; + pTempNode = pTempNode->next; + } + + /* Should not be here */ + /* Log error */ + lim_log(pMac, LOGP, FL("peer not found in pre-auth list, addr= ")); + lim_print_mac_addr(pMac, macAddr, LOGP); + +} /*** end lim_delete_pre_auth_node() ***/ + +/** + * limRestoreFromPreAuthState + * + ***FUNCTION: + * This function is called on STA whenever an Authentication + * sequence is complete and state prior to auth need to be + * restored. + * + ***LOGIC: + * MLM_AUTH_CNF is prepared and sent to SME state machine. + * In case of restoring from pre-auth: + * - Channel Id is programmed at LO/RF synthesizer + * - BSSID is programmed at RHP + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param resultCode - result of authentication attempt + * @return None + */ + +void +lim_restore_from_auth_state(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession sessionEntry) +{ + tSirMacAddr currentBssId; + tLimMlmAuthCnf mlmAuthCnf; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_AUTH_COMP_EVENT, sessionEntry, + resultCode, protStatusCode); +#endif + + cdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr, + (uint8_t *) &pMac->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + mlmAuthCnf.authType = pMac->lim.gpLimMlmAuthReq->authType; + mlmAuthCnf.resultCode = resultCode; + mlmAuthCnf.protStatusCode = protStatusCode; + + /* Update PE session ID */ + mlmAuthCnf.sessionId = sessionEntry->peSessionId; + + /* / Free up buffer allocated */ + /* / for pMac->lim.gLimMlmAuthReq */ + cdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + + sessionEntry->limMlmState = sessionEntry->limPrevMlmState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->limMlmState)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_AUTH_FAIL_TIMER); + + sir_copy_mac_addr(currentBssId, sessionEntry->bssId); + + if (sessionEntry->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) { + pMac->lim.gLimPreAuthChannelNumber = 0; + } + + lim_post_sme_message(pMac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf); +} /*** end lim_restore_from_auth_state() ***/ + +/** + * lim_encrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to encrypt Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param keyId key id to used + * @param pKey Pointer to the key to be used for encryption + * @param pPlainText Pointer to the body to be encrypted + * @param pEncrBody Pointer to the encrypted auth frame body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @return None + */ + +void +lim_encrypt_auth_frame(tpAniSirGlobal pMac, uint8_t keyId, uint8_t *pKey, + uint8_t *pPlainText, uint8_t *pEncrBody, + uint32_t keyLength) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + + keyLength += 3; + + /* Bytes 3-7 of seed is key */ + cdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Compute CRC-32 and place them in last 4 bytes of plain text */ + lim_compute_crc32(icv, pPlainText, sizeof(tSirMacAuthFrameBody)); + + cdf_mem_copy(pPlainText + sizeof(tSirMacAuthFrameBody), + icv, SIR_MAC_WEP_ICV_LENGTH); + + /* Run RC4 on plain text with the seed */ + lim_rc4(pEncrBody + SIR_MAC_WEP_IV_LENGTH, + (uint8_t *) pPlainText, seed, keyLength, + LIM_ENCR_AUTH_BODY_LEN - SIR_MAC_WEP_IV_LENGTH); + + /* Prepare IV */ + pEncrBody[0] = seed[0]; + pEncrBody[1] = seed[1]; + pEncrBody[2] = seed[2]; + pEncrBody[3] = keyId << 6; +} /****** end lim_encrypt_auth_frame() ******/ + +/** + * lim_compute_crc32() + * + ***FUNCTION: + * This function is called to compute CRC-32 on a given source. + * Used while encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for computed CRC + * @param pSrc Source location to be CRC computed + * @param len Length over which CRC to be computed + * @return None + */ + +void lim_compute_crc32(uint8_t *pDest, uint8_t *pSrc, uint8_t len) +{ + uint32_t crc; + int i; + + crc = 0; + crc = ~crc; + + while (len-- > 0) + crc = lim_crc_update(crc, *pSrc++); + + crc = ~crc; + + for (i = 0; i < SIR_MAC_WEP_IV_LENGTH; i++) { + pDest[i] = (uint8_t) crc; + crc >>= 8; + } +} /****** end lim_compute_crc32() ******/ + +/** + * lim_rc4() + * + ***FUNCTION: + * This function is called to run RC4 algorithm. Called while + * encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for encrypted text + * @param pSrc Source location to be encrypted + * @param seed Contains seed (IV + key) for PRNG + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @param frameLen Length of the frame + * + * @return None + */ + +void +lim_rc4(uint8_t *pDest, uint8_t *pSrc, uint8_t *seed, uint32_t keyLength, + uint16_t frameLen) +{ + typedef struct { + uint8_t i, j; + uint8_t sbox[256]; + } tRC4Context; + + tRC4Context ctx; + + { + uint16_t i, j, k; + + /* */ + /* Initialize sbox using seed */ + /* */ + + ctx.i = ctx.j = 0; + for (i = 0; i < 256; i++) + ctx.sbox[i] = (uint8_t) i; + + j = 0; + k = 0; + for (i = 0; i < 256; i++) { + uint8_t temp; + if (k < LIM_SEED_LENGTH) + j = (uint8_t) (j + ctx.sbox[i] + seed[k]); + temp = ctx.sbox[i]; + ctx.sbox[i] = ctx.sbox[j]; + ctx.sbox[j] = temp; + + if (++k >= keyLength) + k = 0; + } + } + + { + uint8_t i = ctx.i; + uint8_t j = ctx.j; + uint8_t len = (uint8_t) frameLen; + + while (len-- > 0) { + uint8_t temp1, temp2; + + i = (uint8_t) (i + 1); + temp1 = ctx.sbox[i]; + j = (uint8_t) (j + temp1); + + ctx.sbox[i] = temp2 = ctx.sbox[j]; + ctx.sbox[j] = temp1; + + temp1 = (uint8_t) (temp1 + temp2); + temp1 = ctx.sbox[temp1]; + temp2 = (uint8_t) (pSrc ? *pSrc++ : 0); + + *pDest++ = (uint8_t) (temp1 ^ temp2); + } + + ctx.i = i; + ctx.j = j; + } +} /****** end lim_rc4() ******/ + +/** + * lim_decrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to decrypt received Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pKey Pointer to the key to be used for decryption + * @param pEncrBody Pointer to the body to be decrypted + * @param pPlainBody Pointer to the decrypted body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * + * @return Decrypt result - eSIR_SUCCESS for success and + * LIM_DECRYPT_ICV_FAIL for ICV mismatch. + * If decryption is a success, pBody will + * have decrypted auth frame body. + */ + +uint8_t +lim_decrypt_auth_frame(tpAniSirGlobal pMac, uint8_t *pKey, uint8_t *pEncrBody, + uint8_t *pPlainBody, uint32_t keyLength, uint16_t frameLen) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + int i; + keyLength += 3; + + /* Bytes 0-2 of seed is received IV */ + cdf_mem_copy((uint8_t *) seed, pEncrBody, SIR_MAC_WEP_IV_LENGTH - 1); + + /* Bytes 3-7 of seed is key */ + cdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Run RC4 on encrypted text with the seed */ + lim_rc4(pPlainBody, + pEncrBody + SIR_MAC_WEP_IV_LENGTH, seed, keyLength, frameLen); + + PELOG4(lim_log(pMac, LOG4, FL("plainbody is ")); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, pPlainBody, frameLen); + ) + /* Compute CRC-32 and place them in last 4 bytes of encrypted body */ + lim_compute_crc32(icv, + (uint8_t *) pPlainBody, + (uint8_t) (frameLen - SIR_MAC_WEP_ICV_LENGTH)); + + /* Compare RX_ICV with computed ICV */ + for (i = 0; i < SIR_MAC_WEP_ICV_LENGTH; i++) { + PELOG4(lim_log + (pMac, LOG4, FL(" computed ICV%d[%x], rxed ICV%d[%x]"), + i, icv[i], i, + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]); + ) + if (icv[i] != + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]) + return LIM_DECRYPT_ICV_FAIL; + } + + return eSIR_SUCCESS; +} /****** end lim_decrypt_auth_frame() ******/ + +/** + * lim_post_sme_set_keys_cnf + * + * A utility API to send MLM_SETKEYS_CNF to SME + */ +void lim_post_sme_set_keys_cnf(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tLimMlmSetKeysCnf *mlmSetKeysCnf) +{ + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + cdf_mem_copy((uint8_t *) &mlmSetKeysCnf->peerMacAddr, + (uint8_t *) pMlmSetKeysReq->peerMacAddr, + sizeof(tSirMacAddr)); + + cdf_mem_copy((uint8_t *) &mlmSetKeysCnf->peerMacAddr, + (uint8_t *) pMlmSetKeysReq->peerMacAddr, + sizeof(tSirMacAddr)); + + /* / Free up buffer allocated for mlmSetKeysReq */ + cdf_mem_free(pMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + + lim_post_sme_message(pMac, + LIM_MLM_SETKEYS_CNF, (uint32_t *) mlmSetKeysCnf); +} + +/** + * lim_send_set_bss_key_req() + * + ***FUNCTION: + * This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Group Keys related + * to a specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @return none + */ +void lim_send_set_bss_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpSetBssKeyParams pSetBssKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + tSirRetStatus retCode; + uint32_t val = 0; + + if (pMlmSetKeysReq->numKeys > SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(pMac, LOG1, + FL + ("numKeys = %d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS"), + pMlmSetKeysReq->numKeys); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Package WMA_SET_BSSKEY_REQ message parameters */ + + pSetBssKeyParams = cdf_mem_malloc(sizeof(tSetBssKeyParams)); + if (NULL == pSetBssKeyParams) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during SET_BSSKEY")); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } else + cdf_mem_set((void *)pSetBssKeyParams, + sizeof(tSetBssKeyParams), 0); + + /* Update the WMA_SET_BSSKEY_REQ parameters */ + pSetBssKeyParams->bssIdx = psessionEntry->bssIdx; + pSetBssKeyParams->encType = pMlmSetKeysReq->edType; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pSetBssKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session Id */ + pSetBssKeyParams->sessionId = psessionEntry->peSessionId; + + pSetBssKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + + if (pMlmSetKeysReq->key[0].keyId && + ((pMlmSetKeysReq->edType == eSIR_ED_WEP40) || + (pMlmSetKeysReq->edType == eSIR_ED_WEP104)) + ) { + /* IF the key id is non-zero and encryption type is WEP, Send all the 4 + * keys to HAL with filling the key at right index in pSetBssKeyParams->key. */ + pSetBssKeyParams->numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + cdf_mem_copy((uint8_t *) &pSetBssKeyParams-> + key[pMlmSetKeysReq->key[0].keyId], + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(pMlmSetKeysReq->key[0])); + + } else { + pSetBssKeyParams->numKeys = pMlmSetKeysReq->numKeys; + cdf_mem_copy((uint8_t *) &pSetBssKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key, + sizeof(tSirKeys) * pMlmSetKeysReq->numKeys); + } + + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_SET_BSSKEY_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pSetBssKeyParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOGW, FL("Sending WMA_SET_BSSKEY_REQ...")); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) { + lim_log(pMac, LOGE, + FL("Posting SET_BSSKEY to HAL failed, reason=%X"), + retCode); + + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } else + return; /* Continue after WMA_SET_BSSKEY_RSP... */ + +end: + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); + +} + +/** + * @function : lim_send_set_sta_key_req() + * + * @brief : This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Unicast Keys related + * to a specified STA with specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @param staIdx STA index for which the keys are being set + * @param defWEPIdx The default WEP key index [0..3] + * @return none + */ +void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp) +{ + tSirMsgQ msgQ; + tpSetStaKeyParams pSetStaKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + tSirRetStatus retCode; + uint32_t val = 0; + + /* Package WMA_SET_STAKEY_REQ message parameters */ + pSetStaKeyParams = cdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (NULL == pSetStaKeyParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during SET_BSSKEY")); + return; + } else + cdf_mem_set((void *)pSetStaKeyParams, sizeof(tSetStaKeyParams), + 0); + + /* Update the WMA_SET_STAKEY_REQ parameters */ + pSetStaKeyParams->staIdx = staIdx; + pSetStaKeyParams->encType = pMlmSetKeysReq->edType; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pSetStaKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session ID */ + pSetStaKeyParams->sessionId = sessionEntry->peSessionId; + + /** + * For WEP - defWEPIdx indicates the default WEP + * Key to be used for TX + * For all others, there's just one key that can + * be used and hence it is assumed that + * defWEPIdx = 0 (from the caller) + */ + + pSetStaKeyParams->defWEPIdx = defWEPIdx; + + pSetStaKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + cdf_mem_copy(pSetStaKeyParams->peerMacAddr, + pMlmSetKeysReq->peerMacAddr, sizeof(tSirMacAddr)); + + if (sendRsp == true) { + /** Store the Previous MlmState*/ + sessionEntry->limPrevMlmState = sessionEntry->limMlmState; + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + } + + if (LIM_IS_IBSS_ROLE(sessionEntry) + && !pMlmSetKeysReq->key[0].unicast) { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE; + msgQ.type = WMA_SET_STA_BCASTKEY_REQ; + } else { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + msgQ.type = WMA_SET_STAKEY_REQ; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->limMlmState)); + + /** + * In the Case of WEP_DYNAMIC, ED_TKIP and ED_CCMP + * the Key[0] contains the KEY, so just copy that alone, + * for the case of WEP_STATIC the hal gets the key from cfg + */ + switch (pMlmSetKeysReq->edType) { + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + /* FIXME! Is this OK? */ + if (0 == pMlmSetKeysReq->numKeys) { + uint32_t i; + + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + cdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[i], + (uint8_t *) &pMlmSetKeysReq-> + key[i], sizeof(tSirKeys)); + } + pSetStaKeyParams->wepType = eSIR_WEP_STATIC; + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + sessionEntry->peSessionId, + sessionEntry->limMlmState)); + } else { + /*This case the keys are coming from upper layer so need to fill the + * key at the default wep key index and send to the HAL */ + if (defWEPIdx < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + cdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[defWEPIdx], + (uint8_t *) &pMlmSetKeysReq-> + key[0], + sizeof(pMlmSetKeysReq->key[0])); + pMlmSetKeysReq->numKeys = + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + } else { + lim_log(pMac, LOGE, FL("Wrong Key Index %d"), + defWEPIdx); + cdf_mem_free(pSetStaKeyParams); + return; + } + } + break; + case eSIR_ED_TKIP: + case eSIR_ED_CCMP: +#ifdef FEATURE_WLAN_WAPI + case eSIR_ED_WPI: +#endif + { + cdf_mem_copy((uint8_t *) &pSetStaKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(tSirKeys)); + } + break; + default: + break; + } + + pSetStaKeyParams->sendRsp = sendRsp; + + msgQ.reserved = 0; + msgQ.bodyptr = pSetStaKeyParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("Sending WMA_SET_STAKEY_REQ...")); + MTRACE(mac_trace_msg_tx(pMac, sessionEntry->peSessionId, msgQ.type)); + if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) { + lim_log(pMac, LOGE, + FL("Posting SET_STAKEY to HAL failed, reason=%X"), + retCode); + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } else + return; /* Continue after WMA_SET_STAKEY_RSP... */ + + if (sendRsp == true) + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); +} diff --git a/core/mac/src/pe/lim/lim_security_utils.h b/core/mac/src/pe/lim/lim_security_utils.h new file mode 100644 index 0000000000..c5b30bab50 --- /dev/null +++ b/core/mac/src/pe/lim/lim_security_utils.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_security_utils.h contains the utility definitions + * related to WEP encryption/decryption etc. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SECURITY_UTILS_H +#define __LIM_SECURITY_UTILS_H +#include "sir_mac_prot_def.h" /* for tSirMacAuthFrameBody */ + +#define LIM_ENCR_AUTH_BODY_LEN (sizeof(tSirMacAuthFrameBody) + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) +struct tLimPreAuthNode; + +uint8_t lim_is_auth_algo_supported(tpAniSirGlobal, tAniAuthType, tpPESession); + +/* MAC based authentication related functions */ +void lim_init_pre_auth_list(tpAniSirGlobal); +void lim_delete_pre_auth_list(tpAniSirGlobal); +struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal, tSirMacAddr); +void lim_add_pre_auth_node(tpAniSirGlobal, struct tLimPreAuthNode *); +void lim_delete_pre_auth_node(tpAniSirGlobal, tSirMacAddr); +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode); +void lim_restore_from_auth_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +uint8_t lim_delete_open_auth_pre_auth_node(tpAniSirGlobal mac_ctx); + +/* Encryption/Decryption related functions */ +void lim_compute_crc32(uint8_t *, uint8_t *, uint8_t); +void lim_rc4(uint8_t *, uint8_t *, uint8_t *, uint32_t, uint16_t); +void lim_encrypt_auth_frame(tpAniSirGlobal, uint8_t, uint8_t *, uint8_t *, + uint8_t *, uint32_t); +uint8_t lim_decrypt_auth_frame(tpAniSirGlobal, uint8_t *, uint8_t *, uint8_t *, + uint32_t, uint16_t); + +void lim_send_set_bss_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, tpPESession); +void lim_send_set_sta_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, uint16_t, uint8_t, + tpPESession, bool sendRsp); +void lim_post_sme_set_keys_cnf(tpAniSirGlobal, tLimMlmSetKeysReq *, + tLimMlmSetKeysCnf *); + +#define PTAPS 0xedb88320 + +static inline uint32_t lim_crc_update(uint32_t crc, uint8_t x) +{ + + /* Update CRC computation for 8 bits contained in x */ + /* */ + uint32_t z; + uint32_t fb; + int i; + + z = crc ^ x; + for (i = 0; i < 8; i++) { + fb = z & 1; + z >>= 1; + if (fb) + z ^= PTAPS; + } + return z; +} + +#endif /* __LIM_SECURITY_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c new file mode 100644 index 0000000000..c7f422052b --- /dev/null +++ b/core/mac/src/pe/lim/lim_send_management_frames.c @@ -0,0 +1,5130 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file lim_send_management_frames.c + * + * \brief Code for preparing and sending 802.11 Management frames + * + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cds_utils.h" +#include "sme_trace.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#include "wma_types.h" + +/** + * + * \brief This function is called to add the sequence number to the + * management frames + * + * \param pMac Pointer to Global MAC structure + * + * \param pMacHdr Pointer to MAC management header + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the pMac structure will be incremented + * and updated to the MAC management header. The start sequence + * number is WLAN_HOST_SEQ_NUM_MIN and the end value is + * WLAN_HOST_SEQ_NUM_MAX. After reaching the MAX value, the sequence + * number will roll over. + * + */ +void lim_add_mgmt_seq_num(tpAniSirGlobal pMac, tpSirMacMgmtHdr pMacHdr) +{ + if (pMac->mgmtSeqNum >= WLAN_HOST_SEQ_NUM_MAX) { + pMac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + } + + pMac->mgmtSeqNum++; + + pMacHdr->seqControl.seqNumLo = (pMac->mgmtSeqNum & LOW_SEQ_NUM_MASK); + pMacHdr->seqControl.seqNumHi = + ((pMac->mgmtSeqNum & HIGH_SEQ_NUM_MASK) >> HIGH_SEQ_NUM_OFFSET); +} + +/** + * + * \brief This function is called before sending a p2p action frame + * inorder to add sequence numbers to action packets + * + * \param pMac Pointer to Global MAC structure + * + * \param pBD Pointer to the frame buffer that needs to be populate + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the pMac structure will be incremented + * and updated to the MAC management header. The start sequence + * number is WLAN_HOST_SEQ_NUM_MIN and the end value is + * WLAN_HOST_SEQ_NUM_MAX. After reaching the MAX value, the sequence + * number will roll over. + * + */ +void lim_populate_p2p_mac_header(tpAniSirGlobal pMac, uint8_t *pBD) +{ + tpSirMacMgmtHdr pMacHdr; + + /* / Prepare MAC management header */ + pMacHdr = (tpSirMacMgmtHdr) (pBD); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(pMac, pMacHdr); + lim_log(pMac, LOG1, "seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d", + pMacHdr->seqControl.seqNumLo, + pMacHdr->seqControl.seqNumHi, pMac->mgmtSeqNum); +} + +/** + * lim_populate_mac_header() - Fill in 802.11 header of frame + * + * @mac_ctx: Pointer to Global MAC structure + * @buf: Pointer to the frame buffer that needs to be populate + * @type: 802.11 Type of the frame + * @sub_type: 802.11 Subtype of the frame + * @peer_addr: dst address + * @self_mac_addr: local mac address + * + * This function is called by various LIM modules to prepare the + * 802.11 frame MAC header + * + * The buf argument points to the beginning of the frame buffer to + * which - a) The 802.11 MAC header is set b) Following this MAC header + * will be the MGMT frame payload The payload itself is populated by the + * caller API + * + * Return: None + */ + +void lim_populate_mac_header(tpAniSirGlobal mac_ctx, uint8_t *buf, + uint8_t type, uint8_t sub_type, tSirMacAddr peer_addr, + tSirMacAddr self_mac_addr) +{ + tpSirMacMgmtHdr mac_hdr; + + /* Prepare MAC management header */ + mac_hdr = (tpSirMacMgmtHdr) (buf); + + /* Prepare FC */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = type; + mac_hdr->fc.subType = sub_type; + + /* Prepare Address 1 */ + cdf_mem_copy((uint8_t *) mac_hdr->da, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare Address 2 */ + sir_copy_mac_addr(mac_hdr->sa, self_mac_addr); + + /* Prepare Address 3 */ + cdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(mac_ctx, mac_hdr); + lim_log(mac_ctx, LOG1, "seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d", + mac_hdr->seqControl.seqNumLo, + mac_hdr->seqControl.seqNumHi, mac_ctx->mgmtSeqNum); +} + +/** + * lim_send_probe_req_mgmt_frame() - send probe request management frame + * @mac_ctx: Pointer to Global MAC structure + * @ssid: SSID to be sent in Probe Request frame + * @bssid: BSSID to be sent in Probe Request frame + * @channel: Channel # on which the Probe Request is going out + * @self_macaddr: self MAC address + * @dot11mode: self dotllmode + * @additional_ielen: if non-zero, include additional_ie in the Probe Request + * frame + * @additional_ie: if additional_ielen is non zero, include this field in the + * Probe Request frame + * + * This function is called by various LIM modules to send Probe Request frame + * during active scan/learn phase. + * Probe request is sent out in the following scenarios: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * + * Return: tSirRetStatus (eSIR_SUCCESS on success and error codes otherwise) + */ +tSirRetStatus +lim_send_probe_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tSirMacSSid *ssid, + tSirMacAddr bssid, + uint8_t channel, + tSirMacAddr self_macaddr, + uint32_t dot11mode, + uint32_t additional_ielen, uint8_t *additional_ie) +{ + tDot11fProbeRequest pr; + uint32_t status, bytes, payload; + uint8_t *frame; + void *packet; + CDF_STATUS cdf_status, extcap_status; + tpPESession pesession; + uint8_t sessionid; + uint8_t *p2pie = NULL; + uint8_t txflag = 0; + uint8_t sme_sessionid = 0; + bool is_vht_enabled = false; + uint8_t txPower; + uint16_t addn_ielen = additional_ielen; + + /* The probe req should not send 11ac capabilieties if band is 2.4GHz, + * unless enableVhtFor24GHz is enabled in INI. So if enableVhtFor24GHz + * is false and dot11mode is 11ac set it to 11n. + */ + if (channel <= SIR_11B_CHANNEL_END && + (false == mac_ctx->roam.configParam.enableVhtFor24GHz) && + (WNI_CFG_DOT11_MODE_11AC == dot11mode || + WNI_CFG_DOT11_MODE_11AC_ONLY == dot11mode)) + dot11mode = WNI_CFG_DOT11_MODE_11N; + /* + * session context may or may not be present, when probe request needs + * to be sent out. Following cases exist: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * If session context does not exist, some IEs will be populated from + * CFGs, e.g. Supported and Extended rate set IEs + */ + pesession = pe_find_session_by_bssid(mac_ctx, bssid, &sessionid); + + if (pesession != NULL) + sme_sessionid = pesession->smeSessionId; + + /* The scheme here is to fill out a 'tDot11fProbeRequest' structure */ + /* and then hand it off to 'dot11f_pack_probe_request' (for */ + /* serialization). We start by zero-initializing the structure: */ + cdf_mem_set((uint8_t *) &pr, sizeof(pr), 0); + + /* & delegating to assorted helpers: */ + populate_dot11f_ssid(mac_ctx, ssid, &pr.SSID); + + if (addn_ielen && additional_ie) + p2pie = limGetP2pIEPtr(mac_ctx, additional_ie, addn_ielen); + + /* + * Don't include 11b rate if it is a P2P serach or probe request is + * sent by P2P Client + */ + if ((WNI_CFG_DOT11_MODE_11B != dot11mode) && (p2pie != NULL) && + (((mac_ctx->lim.gpLimMlmScanReq != NULL) && + mac_ctx->lim.gpLimMlmScanReq->p2pSearch) || + ((pesession != NULL) && + (CDF_P2P_CLIENT_MODE == pesession->pePersona)) + ) + ) { + /* + * In the below API pass channel number > 14, do that it fills + * only 11a rates in supported rates + */ + populate_dot11f_supp_rates(mac_ctx, 15, &pr.SuppRates, + pesession); + } else { + populate_dot11f_supp_rates(mac_ctx, channel, + &pr.SuppRates, pesession); + + if (WNI_CFG_DOT11_MODE_11B != dot11mode) { + populate_dot11f_ext_supp_rates1(mac_ctx, channel, + &pr.ExtSuppRates); + } + } + +#if defined WLAN_FEATURE_VOWIFI + /* + * Table 7-14 in IEEE Std. 802.11k-2008 says + * DS params "can" be present in RRM is disabled and "is" present if + * RRM is enabled. It should be ok even if we add it into probe req when + * RRM is not enabled. + */ + populate_dot11f_ds_params(mac_ctx, &pr.DSParams, channel); + /* Call RRM module to get the tx power for management used. */ + txPower = (uint8_t) rrm_get_mgmt_tx_power(mac_ctx, pesession); + populate_dot11f_wfatpc(mac_ctx, &pr.WFATPC, txPower, 0); + +#endif + + if (pesession != NULL) { + pesession->htCapability = IS_DOT11_MODE_HT(dot11mode); + /* Include HT Capability IE */ + if (pesession->htCapability) + populate_dot11f_ht_caps(mac_ctx, pesession, &pr.HTCaps); + } else { /* pesession == NULL */ + if (IS_DOT11_MODE_HT(dot11mode)) + populate_dot11f_ht_caps(mac_ctx, NULL, &pr.HTCaps); + } + + /* + * Set channelbonding information as "disabled" when tunned to a + * 2.4 GHz channel + */ + if (channel <= SIR_11B_CHANNEL_END) { + if (mac_ctx->roam.configParam.channelBondingMode24GHz + == PHY_SINGLE_CHANNEL_CENTERED) { + pr.HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + pr.HTCaps.shortGI40MHz = 0; + } else { + pr.HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } +#ifdef WLAN_FEATURE_11AC + if (pesession != NULL) { + pesession->vhtCapability = IS_DOT11_MODE_VHT(dot11mode); + /* Include VHT Capability IE */ + if (pesession->vhtCapability) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } else { + if (IS_DOT11_MODE_VHT(dot11mode)) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } +#endif + if (pesession != NULL) + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &pr.ExtCap, + pesession); + + /* That's it-- now we pack it. First, how much space are we going to */ + status = dot11f_get_packed_probe_request_size(mac_ctx, &pr, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, FL("Failed to calculate the packed size for a Probe Request (0x%08x)."), status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while calculating the packed size for a Probe Request (0x%08x)."), status); + } + + /* Strip extended capability IE (if present). FW will add that IE */ + if (addn_ielen) { + extcap_status = lim_strip_extcap_ie(mac_ctx, additional_ie, + &addn_ielen, NULL); + if (CDF_STATUS_SUCCESS != extcap_status) + lim_log(mac_ctx, LOGE, + FL("Error:%d stripping extcap IE"), extcap_status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + addn_ielen; + + /* Ok-- try to allocate some memory: */ + cdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGP, FL("Failed to allocate %d bytes for a Probe Request."), bytes); + return eSIR_MEM_ALLOC_FAILED; + } + /* Paranoia: */ + cdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_REQ, bssid, self_macaddr); + + /* That done, pack the Probe Request: */ + status = dot11f_pack_probe_request(mac_ctx, &pr, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to pack a Probe Request (0x%08x)."), status); + cds_packet_free((void *)packet); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, FL("There were warnings while packing a Probe Request (0x%08x)."), status); + } + /* Append any AddIE if present. */ + if (addn_ielen) { + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + additional_ie, addn_ielen); + payload += addn_ielen; + } + + /* If this probe request is sent during P2P Search State, then we need + * to send it at OFDM rate. + */ + if ((SIR_BAND_5_GHZ == lim_get_rf_band(channel)) + || ((mac_ctx->lim.gpLimMlmScanReq != NULL) && + mac_ctx->lim.gpLimMlmScanReq->p2pSearch) + /* + * For unicast probe req mgmt from Join function we don't set + * above variables. So we need to add one more check whether it + * is pePersona is P2P_CLIENT or not + */ + || ((pesession != NULL) && + (CDF_P2P_CLIENT_MODE == pesession->pePersona)) + ) { + txflag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + cdf_status = + wma_tx_frame(mac_ctx, packet, + (uint16_t) sizeof(tSirMacMgmtHdr) + payload, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, txflag, sme_sessionid, + 0); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGE, + FL("could not send Probe Request frame!")); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} /* End lim_send_probe_req_mgmt_frame. */ + +tSirRetStatus lim_get_addn_ie_for_probe_resp(tpAniSirGlobal pMac, + uint8_t *addIE, uint16_t *addnIELen, + uint8_t probeReqP2pIe) +{ + /* If Probe request doesn't have P2P IE, then take out P2P IE + from additional IE */ + if (!probeReqP2pIe) { + uint8_t *tempbuf = NULL; + uint16_t tempLen = 0; + int left = *addnIELen; + uint8_t *ptr = addIE; + uint8_t elem_id, elem_len; + + if (NULL == addIE) { + PELOGE(lim_log(pMac, LOGE, FL(" NULL addIE pointer"));) + return eSIR_FAILURE; + } + + tempbuf = cdf_mem_malloc(left); + if (NULL == tempbuf) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Unable to allocate memory to store addn IE")); + ) + return eSIR_MEM_ALLOC_FAILED; + } + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + cdf_mem_free(tempbuf); + return eSIR_FAILURE; + } + if (!((SIR_MAC_EID_VENDOR == elem_id) && + (memcmp + (&ptr[2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE) == 0))) { + cdf_mem_copy(tempbuf + tempLen, &ptr[0], + elem_len + 2); + tempLen += (elem_len + 2); + } + left -= elem_len; + ptr += (elem_len + 2); + } + cdf_mem_copy(addIE, tempbuf, tempLen); + *addnIELen = tempLen; + cdf_mem_free(tempbuf); + } + return eSIR_SUCCESS; +} + +/** + * lim_send_probe_rsp_mgmt_frame() - Send probe response + * + * @mac_ctx: Handle for mac context + * @peer_macaddr: Mac address of requesting peer + * @ssid: SSID for response + * @n_staid: Station ID, currently unused. + * @pe_session: PE session id + * @keepalive: Keep alive flag. Currently unused. + * @preq_p2pie: P2P IE in incoming probe request + * + * Builds and sends probe response frame to the requesting peer + * + * Return: void + */ + +void +lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer_macaddr, + tpAniSSID ssid, + short n_staid, + uint8_t keepalive, + tpPESession pe_session, uint8_t preq_p2pie) +{ + tDot11fProbeResponse *frm; + tSirRetStatus sir_status; + uint32_t cfg, payload, bytes, status; + tpSirMacMgmtHdr mac_hdr; + uint8_t *frame; + void *packet; + CDF_STATUS cdf_status; + uint32_t addn_ie_present = false; + + uint16_t addn_ie_len = 0; + uint32_t wps_ap = 0, tmp; + uint8_t tx_flag = 0; + uint8_t *add_ie = NULL; + uint8_t *p2p_ie = NULL; + uint8_t noalen = 0; + uint8_t total_noalen = 0; + uint8_t noa_stream[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t noa_ie[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t sme_sessionid = 0; + bool is_vht_enabled = false; + tDot11fIEExtCap extracted_ext_cap; + bool extracted_ext_cap_flag = true; + + /* We don't answer requests in this case*/ + if (ANI_DRIVER_TYPE(mac_ctx) == eDRIVER_TYPE_MFG) + return; + + if (NULL == pe_session) + return; + + /* + * In case when cac timer is running for this SAP session then + * avoid sending probe rsp out. It is violation of dfs specification. + */ + if (((pe_session->pePersona == CDF_SAP_MODE) || + (pe_session->pePersona == CDF_P2P_GO_MODE)) && + (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("CAC timer is running, probe response dropped")); + return; + } + sme_sessionid = pe_session->smeSessionId; + frm = cdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (NULL == frm) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + + cdf_mem_zero(&extracted_ext_cap, sizeof(extracted_ext_cap)); + + /* + * Fill out 'frm', after which we'll just hand the struct off to + * 'dot11f_pack_probe_response'. + */ + cdf_mem_set((uint8_t *) frm, sizeof(tDot11fProbeResponse), 0); + + /* + * Timestamp to be updated by TFP, below. + * + * Beacon Interval: + */ + if (LIM_IS_AP_ROLE(pe_session)) { + frm->BeaconInterval.interval = + mac_ctx->sch.schObject.gSchBeaconInterval; + } else { + sir_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, &cfg); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOGP, + FL("Failed to get WNI_CFG_BEACON_INTERVAL (%d)."), + sir_status); + goto err_ret; + } + frm->BeaconInterval.interval = (uint16_t) cfg; + } + + populate_dot11f_capabilities(mac_ctx, &frm->Capabilities, pe_session); + populate_dot11f_ssid(mac_ctx, (tSirMacSSid *) ssid, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + populate_dot11f_ds_params(mac_ctx, &frm->DSParams, + pe_session->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &frm->IBSSParams, pe_session); + + if (LIM_IS_AP_ROLE(pe_session)) { + if (pe_session->wps_state != SAP_WPS_DISABLED) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + &frm->WscProbeRes, + pe_session); + } else { + if (wlan_cfg_get_int(mac_ctx, (uint16_t) WNI_CFG_WPS_ENABLE, + &tmp) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, "Failed to cfg get id %d", + WNI_CFG_WPS_ENABLE); + + wps_ap = tmp & WNI_CFG_WPS_ENABLE_AP; + + if (wps_ap) + populate_dot11f_wsc_in_probe_res(mac_ctx, + &frm->WscProbeRes); + + if (mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info_in_probe_res(mac_ctx, + &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info_in_probe_res( + mac_ctx, &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + populate_dot11f_country(mac_ctx, &frm->Country, pe_session); + populate_dot11f_edca_param_set(mac_ctx, &frm->EDCAParamSet, pe_session); + + if (pe_session->dot11mode != WNI_CFG_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &frm->ERPInfo, pe_session); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->ExtSuppRates, pe_session); + + /* Populate HT IEs, when operating in 11n */ + if (pe_session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + populate_dot11f_ht_info(mac_ctx, &frm->HTInfo, pe_session); + } +#ifdef WLAN_FEATURE_11AC + if (pe_session->vhtCapability) { + lim_log(mac_ctx, LOG1, FL("Populate VHT IE in Probe Response")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm->VHTOperation); + /* + * we do not support multi users yet. + * populate_dot11f_vht_ext_bss_load( mac_ctx, + * &frm.VHTExtBssLoad ); + */ + is_vht_enabled = true; + } +#endif + + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &frm->ExtCap, + pe_session); + + if (pe_session->pLimStartBssReq) { + populate_dot11f_wpa(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->RSNOpaque); + } + + populate_dot11f_wmm(mac_ctx, &frm->WMMInfoAp, &frm->WMMParams, + &frm->WMMCaps, pe_session); + +#if defined(FEATURE_WLAN_WAPI) + if (pe_session->pLimStartBssReq) + populate_dot11f_wapi(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WAPI); +#endif /* defined(FEATURE_WLAN_WAPI) */ + + status = dot11f_get_packed_probe_response_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Probe Response size error (0x%08x)."), + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Probe Response size warning (0x%08x)."), + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr); + + if (mac_ctx->lim.gpLimRemainOnChanReq) + bytes += (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq)); + else + /* + * Only use CFG for non-listen mode. This CFG is not working for + * concurrency. In listening mode, probe rsp IEs is passed in + * the message from SME to PE. + */ + addn_ie_present = + (pe_session->addIeParams.probeRespDataLen != 0); + + if (addn_ie_present) { + + add_ie = cdf_mem_malloc( + pe_session->addIeParams.probeRespDataLen); + if (NULL == add_ie) { + lim_log(mac_ctx, LOGE, + FL("add_ie allocation failed")); + goto err_ret; + } + + cdf_mem_copy(add_ie, + pe_session->addIeParams.probeRespData_buff, + pe_session->addIeParams.probeRespDataLen); + addn_ie_len = pe_session->addIeParams.probeRespDataLen; + + if (eSIR_SUCCESS != lim_get_addn_ie_for_probe_resp(mac_ctx, + add_ie, &addn_ie_len, preq_p2pie)) { + lim_log(mac_ctx, LOGP, + FL("Unable to get addn_ie")); + goto err_ret; + } + + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &addn_ie_len, + &extracted_ext_cap); + if (eSIR_SUCCESS != sir_status) { + extracted_ext_cap_flag = false; + lim_log(mac_ctx, LOG1, + FL("Unable to strip off ExtCap IE")); + } + + bytes = bytes + addn_ie_len; + + if (preq_p2pie) + p2p_ie = limGetP2pIEPtr(mac_ctx, &add_ie[0], + addn_ie_len); + + if (p2p_ie != NULL) { + /* get NoA attribute stream P2P IE */ + noalen = lim_get_noa_attr_stream(mac_ctx, + noa_stream, pe_session); + if (noalen != 0) { + total_noalen = + lim_build_p2p_ie(mac_ctx, &noa_ie[0], + &noa_stream[0], noalen); + bytes = bytes + total_noalen; + } + } + } + + cdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGP, FL("Probe Response allocation failed")); + goto err_ret; + } + /* Paranoia: */ + cdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, peer_macaddr, + pe_session->selfMacAddr); + + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + /* merge ExtCap IE */ + if (extracted_ext_cap_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extracted_ext_cap); + + /* That done, pack the Probe Response: */ + status = + dot11f_pack_probe_response(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Probe Response pack failure (0x%08x)."), + status); + goto err_ret; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Probe Response pack warning (0x%08x)."), + status); + } + + lim_log(mac_ctx, LOG3, FL("Sending Probe Response frame to ")); + lim_print_mac_addr(mac_ctx, peer_macaddr, LOG3); + + mac_ctx->sys.probeRespond++; + + if (mac_ctx->lim.gpLimRemainOnChanReq) + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + mac_ctx->lim.gpLimRemainOnChanReq->probeRspIe, + (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq))); + + if (addn_ie_present) + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + + if (noalen != 0) { + if (total_noalen > + (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) { + lim_log(mac_ctx, LOGE, + FL("Not able to insert NoA, total len=%d"), + total_noalen); + goto err_ret; + } else { + cdf_mem_copy(&frame[bytes - (total_noalen)], + &noa_ie[0], total_noalen); + } + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == CDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == CDF_P2P_GO_MODE) + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + /* Queue Probe Response frame in high priority WQ */ + cdf_status = wma_tx_frame((tHalHandle) mac_ctx, packet, + (uint16_t) bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_sessionid, 0); + + /* Pkt will be freed up by the callback */ + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + lim_log(mac_ctx, LOGE, FL("Could not send Probe Response.")); + + if (add_ie != NULL) + cdf_mem_free(add_ie); + + cdf_mem_free(frm); + return; + +err_ret: + if (add_ie != NULL) + cdf_mem_free(add_ie); + if (frm != NULL) + cdf_mem_free(frm); + if (packet != NULL) + cds_packet_free((void *)packet); + return; + +} /* End lim_send_probe_rsp_mgmt_frame. */ + +void +lim_send_addts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *pAddTS, tpPESession psessionEntry) +{ + uint16_t i; + uint8_t *pFrame; + tDot11fAddTSRequest AddTSReq; + tDot11fWMMAddTSRequest WMMAddTSReq; + uint32_t nPayload, nBytes, nStatus; + tpSirMacMgmtHdr pMacHdr; + void *pPacket; +#ifdef FEATURE_WLAN_ESE + uint32_t phyMode; +#endif + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!pAddTS->wmeTspecPresent) { + cdf_mem_set((uint8_t *) &AddTSReq, sizeof(AddTSReq), 0); + + AddTSReq.Action.action = SIR_MAC_QOS_ADD_TS_REQ; + AddTSReq.DialogToken.token = pAddTS->dialogToken; + AddTSReq.Category.category = SIR_MAC_ACTION_QOS_MGMT; + if (pAddTS->lleTspecPresent) { + populate_dot11f_tspec(&pAddTS->tspec, &AddTSReq.TSPEC); + } else { + populate_dot11f_wmmtspec(&pAddTS->tspec, + &AddTSReq.WMMTSPEC); + } + + if (pAddTS->lleTspecPresent) { + AddTSReq.num_WMMTCLAS = 0; + AddTSReq.num_TCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_tclas(pMac, &pAddTS->tclasInfo[i], + &AddTSReq.TCLAS[i]); + } + } else { + AddTSReq.num_TCLAS = 0; + AddTSReq.num_WMMTCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_wmmtclas(pMac, + &pAddTS->tclasInfo[i], + &AddTSReq.WMMTCLAS[i]); + } + } + + if (pAddTS->tclasProcPresent) { + if (pAddTS->lleTspecPresent) { + AddTSReq.TCLASSPROC.processing = + pAddTS->tclasProc; + AddTSReq.TCLASSPROC.present = 1; + } else { + AddTSReq.WMMTCLASPROC.version = 1; + AddTSReq.WMMTCLASPROC.processing = + pAddTS->tclasProc; + AddTSReq.WMMTCLASPROC.present = 1; + } + } + + nStatus = + dot11f_get_packed_add_ts_request_size(pMac, &AddTSReq, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed size f" + "or an Add TS Request (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calculating" + "the packed size for an Add TS Request" + " (0x%08x)."), nStatus); + } + } else { + cdf_mem_set((uint8_t *) &WMMAddTSReq, sizeof(WMMAddTSReq), 0); + + WMMAddTSReq.Action.action = SIR_MAC_QOS_ADD_TS_REQ; + WMMAddTSReq.DialogToken.token = pAddTS->dialogToken; + WMMAddTSReq.Category.category = SIR_MAC_ACTION_WME; + + /* WMM spec 2.2.10 - status code is only filled in for ADDTS response */ + WMMAddTSReq.StatusCode.statusCode = 0; + + populate_dot11f_wmmtspec(&pAddTS->tspec, &WMMAddTSReq.WMMTSPEC); +#ifdef FEATURE_WLAN_ESE + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + if (phyMode == WNI_CFG_PHY_MODE_11G + || phyMode == WNI_CFG_PHY_MODE_11A) { + pAddTS->tsrsIE.rates[0] = TSRS_11AG_RATE_6MBPS; + } else { + pAddTS->tsrsIE.rates[0] = TSRS_11B_RATE_5_5MBPS; + } + populate_dot11_tsrsie(pMac, &pAddTS->tsrsIE, + &WMMAddTSReq.ESETrafStrmRateSet, + sizeof(uint8_t)); +#endif + /* fillWmeTspecIE */ + + nStatus = + dot11f_get_packed_wmm_add_ts_request_size(pMac, &WMMAddTSReq, + &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed size f" + "or a WMM Add TS Request (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calculating" + "the packed size for a WMM Add TS Requ" + "est (0x%08x)."), nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for an Ad" + "d TS Request."), nBytes); + return; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMacAddr, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peerMacAddr, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!pAddTS->wmeTspecPresent) { + nStatus = dot11f_pack_add_ts_request(pMac, &AddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Add TS Request " + "(0x%08x)."), nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "an Add TS Request (0x%08x)."), nStatus); + } + } else { + nStatus = dot11f_pack_wmm_add_ts_request(pMac, &WMMAddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a WMM Add TS Reque" + "st (0x%08x)."), nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a WMM Add TS Request (0x%08x)."), nStatus); + } + } + + PELOG3(lim_log(pMac, LOG3, FL("Sending an Add TS Request frame to ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG3); + ) + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + + /* Queue Addts Response frame in high priority WQ */ + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, FL("*** Could not send an Add TS Request" + " (%X) ***"), cdf_status); + /* Pkt will be freed up by the callback */ + } + +} /* End lim_send_addts_req_action_frame. */ + +/** + * lim_send_assoc_rsp_mgmt_frame() - Send assoc response + * @mac_ctx: Handle for mac context + * @status_code: Status code for assoc response frame + * @aid: Association ID + * @peer_addr: Mac address of requesting peer + * @subtype: Assoc/Reassoc + * @sta: Pointer to station node + * @pe_session: PE session id. + * + * Builds and sends association response frame to the requesting peer. + * + * Return: void + */ + +void +lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, + uint16_t status_code, uint16_t aid, tSirMacAddr peer_addr, + uint8_t subtype, tpDphHashNode sta, tpPESession pe_session) +{ + static tDot11fAssocResponse frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + tSirRetStatus sir_status; + uint8_t lle_mode = 0, addts; + tHalBitVal qos_mode, wme_mode; + uint32_t payload, bytes, status; + void *packet; + CDF_STATUS cdf_status; + tUpdateBeaconParams beacon_params; + uint8_t tx_flag = 0; + uint32_t addn_ie_len = 0; + uint8_t add_ie[WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN]; + tpSirAssocReq assoc_req = NULL; + uint8_t sme_session = 0; + bool is_vht = false; + uint16_t stripoff_len = 0; + tDot11fIEExtCap extracted_ext_cap; + bool extracted_flag = false; +#ifdef WLAN_FEATURE_11W + uint32_t retry_int; + uint32_t max_retries; +#endif + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGE, FL("pe_session is NULL")); + return; + } + + sme_session = pe_session->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + limGetQosMode(pe_session, &qos_mode); + limGetWmeMode(pe_session, &wme_mode); + + /* + * An Add TS IE is added only if the AP supports it and + * the requesting STA sent a traffic spec. + */ + addts = (qos_mode && sta && sta->qos.addtsPresent) ? 1 : 0; + + frm.Status.status = status_code; + + frm.AID.associd = aid | LIM_AID_MASK; + + if (NULL == sta) { + populate_dot11f_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, pe_session); + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, pe_session); + } else { + populate_dot11f_assoc_rsp_rates(mac_ctx, &frm.SuppRates, + &frm.ExtSuppRates, + sta->supportedRates.llbRates, + sta->supportedRates.llaRates); + } + + if (LIM_IS_AP_ROLE(pe_session) && sta != NULL && + eSIR_SUCCESS == status_code) { + assoc_req = (tpSirAssocReq) + pe_session->parsedAssocReq[sta->assocId]; + /* + * populate P2P IE in AssocRsp when assocReq from the peer + * includes P2P IE + */ + if (assoc_req != NULL && assoc_req->addIEPresent) + populate_dot11_assoc_res_p2p_ie(mac_ctx, + &frm.P2PAssocRes, + assoc_req); + } + + if (NULL != sta) { + if (eHAL_SET == qos_mode) { + if (sta->lleEnabled) { + lle_mode = 1; + populate_dot11f_edca_param_set(mac_ctx, + &frm.EDCAParamSet, pe_session); + } + } + + if ((!lle_mode) && (eHAL_SET == wme_mode) && sta->wmeEnabled) { + populate_dot11f_wmm_params(mac_ctx, &frm.WMMParams, + pe_session); + + if (sta->wsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (sta->mlmStaContext.htCapability && + pe_session->htCapability) { + lim_log(mac_ctx, LOG1, + FL("Populate HT IEs in Assoc Response")); + populate_dot11f_ht_caps(mac_ctx, pe_session, + &frm.HTCaps); + populate_dot11f_ht_info(mac_ctx, &frm.HTInfo, + pe_session); + } +#ifdef WLAN_FEATURE_11AC + if (sta->mlmStaContext.vhtCapability && + pe_session->vhtCapability) { + lim_log(mac_ctx, LOG1, + FL("Populate VHT IEs in Assoc Response")); + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm.VHTOperation); + is_vht = true; + } +#endif + + populate_dot11f_ext_cap(mac_ctx, is_vht, &frm.ExtCap, + pe_session); + +#ifdef WLAN_FEATURE_11W + if (eSIR_MAC_TRY_AGAIN_LATER == status_code) { + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &max_retries) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("get WNI_CFG_PMF_SA_QUERY_MAX_RETRIES failure")); + else if (wlan_cfg_get_int + (mac_ctx, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_int) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("get WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL failure")); + else + populate_dot11f_timeout_interval(mac_ctx, + &frm.TimeoutInterval, + SIR_MAC_TI_TYPE_ASSOC_COMEBACK, + (max_retries - + sta->pmfSaQueryRetryCount) + * retry_int); + } +#endif + } + + cdf_mem_set((uint8_t *) &beacon_params, sizeof(beacon_params), 0); + + if (LIM_IS_AP_ROLE(pe_session) && + (pe_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE)) + lim_decide_ap_protection(mac_ctx, peer_addr, + &beacon_params, pe_session); + + lim_update_short_preamble(mac_ctx, peer_addr, &beacon_params, + pe_session); + lim_update_short_slot_time(mac_ctx, peer_addr, &beacon_params, + pe_session); + + /* + * Populate Do11capabilities after updating session with + * Assos req details + */ + populate_dot11f_capabilities(mac_ctx, &frm.Capabilities, pe_session); + + beacon_params.bssIdx = pe_session->bssIdx; + + /* Send message to HAL about beacon parameter change. */ + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beacon_params.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session); + } + /* Allocate a buffer for this frame: */ + status = dot11f_get_packed_assoc_response_size(mac_ctx, &frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("get Association Response size failure (0x%08x)."), + status); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("get Association Response size warning (0x%08x)."), + status); + } + + bytes = sizeof(tSirMacMgmtHdr) + payload; + + if (assoc_req != NULL) { + addn_ie_len = (pe_session->addIeParams.assocRespDataLen != 0); + + /* Nonzero length indicates Assoc rsp IE available */ + if (addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN + && (bytes + addn_ie_len) <= SIR_MAX_PACKET_SIZE) { + cdf_mem_copy(add_ie, + pe_session->addIeParams.assocRespData_buff, + pe_session->addIeParams.assocRespDataLen); + + cdf_mem_set((uint8_t *) &extracted_ext_cap, + sizeof(extracted_ext_cap), 0); + + stripoff_len = addn_ie_len; + sir_status = + lim_strip_extcap_update_struct + (mac_ctx, &add_ie[0], &stripoff_len, + &extracted_ext_cap); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOG1, + FL("strip off extcap IE failed")); + } else { + addn_ie_len = stripoff_len; + extracted_flag = true; + } + bytes = bytes + addn_ie_len; + } + lim_log(mac_ctx, LOG1, + FL("addn_ie_len = %d for Assoc Resp : %d"), + addn_ie_len, assoc_req->addIEPresent); + } + cdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGP, FL("cds_packet_alloc failed.")); + return; + } + /* Paranoia: */ + cdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + (LIM_ASSOC == subtype) ? + SIR_MAC_MGMT_ASSOC_RSP : SIR_MAC_MGMT_REASSOC_RSP, + peer_addr, + pe_session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + /* merge the ExtCap struct */ + if (extracted_flag) + lim_merge_extcap_struct(&(frm.ExtCap), &extracted_ext_cap); + status = dot11f_pack_assoc_response(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Association Response pack failure(0x%08x)."), + status); + cds_packet_free((void *)packet); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Association Response pack warning (0x%08x)."), + status); + } + + if (subtype == LIM_ASSOC) + lim_log(mac_ctx, LOG1, + FL("*** Sending Assoc Resp status %d aid %d to "), + status_code, aid); + else + lim_log(mac_ctx, LOG1, + FL("*** Sending ReAssoc Resp status %d aid %d to "), + status_code, aid); + + lim_print_mac_addr(mac_ctx, mac_hdr->da, LOG1); + + if (addn_ie_len && addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN) + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(pe_session->currentOperChannel)) || + (pe_session->pePersona == CDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == CDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + /* Queue Association Response frame in high priority WQ */ + cdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_session, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, cdf_status)); + + /* Pkt will be freed up by the callback */ + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + lim_log(mac_ctx, LOGE, + FL("*** Could not Send Re/AssocRsp, retCode=%X ***"), + cdf_status); + + /* + * update the ANI peer station count. + * FIXME_PROTECTION : take care of different type of station + * counter inside this function. + */ + lim_util_count_sta_add(mac_ctx, sta, pe_session); + +} + +void +lim_send_delts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo *pTsinfo, + tSirMacTspecIE *pTspecIe, tpPESession psessionEntry) +{ + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + tDot11fDelTS DelTS; + tDot11fWMMDelTS WMMDelTS; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!wmmTspecPresent) { + cdf_mem_set((uint8_t *) &DelTS, sizeof(DelTS), 0); + + DelTS.Category.category = SIR_MAC_ACTION_QOS_MGMT; + DelTS.Action.action = SIR_MAC_QOS_DEL_TS_REQ; + populate_dot11f_ts_info(pTsinfo, &DelTS.TSInfo); + + nStatus = dot11f_get_packed_del_ts_size(pMac, &DelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed si" + "ze for a Del TS (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calcula" + "ting the packed size for a Del TS" + " (0x%08x)."), nStatus); + } + } else { + cdf_mem_set((uint8_t *) &WMMDelTS, sizeof(WMMDelTS), 0); + + WMMDelTS.Category.category = SIR_MAC_ACTION_WME; + WMMDelTS.Action.action = SIR_MAC_QOS_DEL_TS_REQ; + WMMDelTS.DialogToken.token = 0; + WMMDelTS.StatusCode.statusCode = 0; + populate_dot11f_wmmtspec(pTspecIe, &WMMDelTS.WMMTSPEC); + nStatus = + dot11f_get_packed_wmm_del_ts_size(pMac, &WMMDelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed si" + "ze for a WMM Del TS (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calcula" + "ting the packed size for a WMM De" + "l TS (0x%08x)."), nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for an Ad" + "d TS Response."), nBytes); + return; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!wmmTspecPresent) { + nStatus = dot11f_pack_del_ts(pMac, &DelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Del TS frame (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a Del TS frame (0x%08x)."), nStatus); + } + } else { + nStatus = dot11f_pack_wmm_del_ts(pMac, &WMMDelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to pack a WMM Del TS frame (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a WMM Del TS frame (0x%08x)."), nStatus); + } + } + + PELOG1(lim_log + (pMac, LOG1, FL("Sending DELTS REQ (size %d) to "), nBytes); + lim_print_mac_addr(pMac, pMacHdr->da, LOG1); + ) + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + /* Pkt will be freed up by the callback */ + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + lim_log(pMac, LOGE, FL("Failed to send Del TS (%X)!"), + cdf_status); + +} /* End lim_send_delts_req_action_frame. */ + +/** + * lim_send_assoc_req_mgmt_frame() - Send association request + * @mac_ctx: Handle to MAC context + * @mlm_assoc_req: Association request information + * @pe_session: PE session information + * + * Builds and transmits association request frame to AP. + * + * Return: Void + */ + +void +lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmAssocReq *mlm_assoc_req, + tpPESession pe_session) +{ + tDot11fAssocRequest *frm; + uint16_t caps; + uint8_t *frame; + tSirRetStatus sir_status; + tLimMlmAssocCnf assoc_cnf; + uint32_t bytes, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + CDF_STATUS cdf_status; + uint16_t add_ie_len; + uint8_t *add_ie; + uint8_t *wps_ie = NULL; +#if defined WLAN_FEATURE_VOWIFI + uint8_t power_caps = false; +#endif + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + bool vht_enabled = false; + tDot11fIEExtCap extr_ext_cap; + bool extr_ext_flag = true; + tpSirMacMgmtHdr mac_hdr; + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGE, FL("pe_session is NULL")); + return; + } + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimJoinReq) { + lim_log(mac_ctx, LOGE, FL("pe_session->pLimJoinReq is NULL")); + return; + } + add_ie_len = pe_session->pLimJoinReq->addIEAssoc.length; + add_ie = pe_session->pLimJoinReq->addIEAssoc.addIEdata; + + frm = cdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == frm) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + + cdf_mem_set((uint8_t *) frm, sizeof(tDot11fAssocRequest), 0); + + if (add_ie_len) { + cdf_mem_set((uint8_t *) &extr_ext_cap, sizeof(tDot11fIEExtCap), + 0); + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &add_ie_len, &extr_ext_cap); + if (eSIR_SUCCESS != sir_status) { + extr_ext_flag = false; + lim_log(mac_ctx, LOG1, + FL("Unable to Stripoff ExtCap IE from Assoc Req")); + } else { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + extr_ext_cap.bytes; + + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + else { + /* + * No need to merge the EXT Cap from Supplicant + * if interworkingService is not set, as currently + * driver is only interested in interworkingService + * capability from supplicant. if in future any other + * EXT Cap info is required from supplicant + * it needs to be handled here. + */ + extr_ext_flag = false; + } + } + } else { + lim_log(mac_ctx, LOG1, FL("No additional IE for Assoc Req")); + extr_ext_flag = false; + } + + caps = mlm_assoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 + * in transmitted Association or Reassociation management frames. + * APs ignore the Privacy subfield within received Association and + * Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm->Capabilities); + + frm->ListenInterval.interval = mlm_assoc_req->listenInterval; + populate_dot11f_ssid2(mac_ctx, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limCurrentBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limCurrentBssQosCaps); + + /* We prefer .11e asociations: */ + if (qos_enabled) + wme_enabled = false; + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limCurrentBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->pLimJoinReq->spectrumMgtIndicator == eSIR_TRUE) { +#if defined WLAN_FEATURE_VOWIFI + power_caps = true; + + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); +#endif + populate_dot11f_supp_channels(mac_ctx, &frm->SuppChannels, + LIM_ASSOC, pe_session); + + } +#if defined WLAN_FEATURE_VOWIFI + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps == false) { + power_caps = true; + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); + } + } +#endif + + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, &frm->QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm->ExtSuppRates, + pe_session); + +#if defined WLAN_FEATURE_VOWIFI + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac_ctx, &frm->RRMEnabledCap, + pe_session); +#endif + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; + * } tSirRSNie, *tpSirRSNie; + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + + if (NULL == wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm->WMMInfoStation); + + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm->WMMCaps); + } + + /* + * Populate HT IEs, when operating in 11n and + * when AP is also operating in 11n mode + */ + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, FL("Populate HT Caps in Assoc Request")); + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + } +#ifdef WLAN_FEATURE_11AC + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, FL("Populate VHT IEs in Assoc Request")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + vht_enabled = true; + } + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + lim_log(mac_ctx, LOG1, + FL("Populate Vendor VHT IEs in Assoc Request")); + frm->vendor2_ie.present = 1; + frm->vendor2_ie.type = + pe_session->vendor_specific_vht_ie_type; + frm->vendor2_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + + frm->vendor2_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm->vendor2_ie.VHTCaps); + vht_enabled = true; + } + +#endif + + populate_dot11f_ext_cap(mac_ctx, vht_enabled, &frm->ExtCap, pe_session); + +#if defined WLAN_FEATURE_VOWIFI_11R + if (pe_session->pLimJoinReq->is11Rconnection) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + tSirBssDescription *bssdescr; + + bssdescr = &pe_session->pLimJoinReq->bssDescription; + lim_log(mac_ctx, LOG1, FL("mdie = %02x %02x %02x"), + (unsigned int) bssdescr->mdie[0], + (unsigned int) bssdescr->mdie[1], + (unsigned int) bssdescr->mdie[2]); +#endif + populate_mdie(mac_ctx, &frm->MobilityDomain, + pe_session->pLimJoinReq->bssDescription.mdie); + } else { + /* No 11r IEs dont send any MDIE */ + lim_log(mac_ctx, LOG1, FL("MDIE not present")); + } +#endif + +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm->ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimJoinReq->isESEFeatureIniEnabled) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm->ESERadMgmtCap); +#endif + } +#endif + + status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Association Request packet size failure(0x%08x)."), + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fAssocRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Association request packet size warning (0x%08x)."), + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len; + + cdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGP, FL("Failed to allocate %d bytes."), + bytes); + + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + + /* Update PE session id */ + assoc_cnf.sessionId = pe_session->peSessionId; + + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + + cds_packet_free((void *)packet); + + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + + cdf_mem_free(frm); + return; + } + /* Paranoia: */ + cdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ASSOC_REQ, pe_session->bssId, + pe_session->selfMacAddr); + /* merge the ExtCap struct */ + if (extr_ext_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap); + /* That done, pack the Assoc Request: */ + status = dot11f_pack_assoc_request(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Assoc request pack failure (0x%08x)"), status); + cds_packet_free((void *)packet); + cdf_mem_free(frm); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Assoc request pack warning (0x%08x)"), status); + } + + lim_log(mac_ctx, LOG1, + FL("*** Sending Association Request length %d to "), bytes); + if (pe_session->assocReq != NULL) { + cdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + } + + if (add_ie_len) { + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + add_ie, add_ie_len); + payload += add_ie_len; + } + + pe_session->assocReq = cdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + cdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == CDF_P2P_CLIENT_MODE) + || (pe_session->pePersona == CDF_P2P_GO_MODE) + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->pePersona == CDF_P2P_CLIENT_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_START_EVENT, + pe_session, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + mac_hdr = (tpSirMacMgmtHdr) frame; + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + cdf_status = + wma_tx_frame(mac_ctx, packet, + (uint16_t) (sizeof(tSirMacMgmtHdr) + payload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, tx_flag, sme_sessionid, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Association Request (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + cdf_mem_free(frm); + return; + } + /* Free up buffer allocated for mlm_assoc_req */ + cdf_mem_free(mlm_assoc_req); + mlm_assoc_req = NULL; + cdf_mem_free(frm); + return; +} + +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) +/** + * lim_send_reassoc_req_with_ft_ies_mgmt_frame() - Send Reassoc Req with FTIEs. + * + * @mac_ctx: Handle to mac context + * @mlm_reassoc_req: Original reassoc request + * @pe_session: PE session information + * + * It builds a reassoc request with FT IEs and sends it to AP through WMA. + * Then it creates assoc request and stores it for sending after join + * confirmation. + * + * Return: void + */ + +void +lim_send_reassoc_req_with_ft_ies_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmReassocReq *mlm_reassoc_req, + tpPESession pe_session) +{ + static tDot11fReAssocRequest frm; + uint16_t caps; + uint8_t *frame; + uint32_t bytes, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + CDF_STATUS cdf_status; +#if defined WLAN_FEATURE_VOWIFI + uint8_t power_caps_populated = false; +#endif + uint16_t ft_ies_length = 0; + uint8_t *body; + uint16_t add_ie_len; + uint8_t *add_ie; +#if defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + uint8_t *wps_ie = NULL; +#endif + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + bool vht_enabled = false; + tpSirMacMgmtHdr mac_hdr; + tftSMEContext *ft_sme_context; + + if (NULL == pe_session) + return; + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimReAssocReq) + return; + + add_ie_len = pe_session->pLimReAssocReq->addIEAssoc.length; + add_ie = pe_session->pLimReAssocReq->addIEAssoc.addIEdata; + lim_log(mac_ctx, LOG1, + FL("called in state (%d)."), pe_session->limMlmState); + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + caps = mlm_reassoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield + * to 0 in transmitted Association or Reassociation management + * frames. APs ignore the Privacy subfield within received + * Association and Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm.Capabilities); + + frm.ListenInterval.interval = mlm_reassoc_req->listenInterval; + + /* + * Get the old bssid of the older AP. + * The previous ap bssid is stored in the FT Session + * while creating the PE FT Session for reassociation. + */ + cdf_mem_copy((uint8_t *)frm.CurrentAPAddress.mac, + pe_session->prev_ap_bssid, sizeof(tSirMacAddr)); + + populate_dot11f_ssid2(mac_ctx, &frm.SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limReassocBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps); + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->pLimReAssocReq->spectrumMgtIndicator == eSIR_TRUE) { +#if defined WLAN_FEATURE_VOWIFI + power_caps_populated = true; + + populate_dot11f_power_caps(mac_ctx, &frm.PowerCaps, + LIM_REASSOC, pe_session); + populate_dot11f_supp_channels(mac_ctx, &frm.SuppChannels, + LIM_REASSOC, pe_session); +#endif + } +#if defined WLAN_FEATURE_VOWIFI + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps_populated == false) { + power_caps_populated = true; + populate_dot11f_power_caps(mac_ctx, &frm.PowerCaps, + LIM_REASSOC, pe_session); + } + } +#endif + + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, &frm.QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm.ExtSuppRates, + pe_session); + +#if defined WLAN_FEATURE_VOWIFI + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limReassocBssCaps)) { + populate_dot11f_rrm_ie(mac_ctx, &frm.RRMEnabledCap, pe_session); + } +#endif + + /* + * Ideally this should be enabled for 11r also. But 11r does + * not follow the usual norm of using the Opaque object + * for rsnie and fties. Instead we just add the rsnie and fties + * at the end of the pack routine for 11r. + * This should ideally! be fixed. + */ +#if defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; + * } tSirRSNie, *tpSirRSNie; + * + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (!pe_session->is11Rconnection) { + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + if (NULL == wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm.RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm.WPAOpaque); + } +#ifdef FEATURE_WLAN_ESE + if (pe_session->pLimReAssocReq->cckmIE.length) { + populate_dot11f_ese_cckm_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->cckmIE), + &frm.ESECckmOpaque); + } +#endif + } +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in re-association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm.ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimReAssocReq->isESEFeatureIniEnabled) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm.ESERadMgmtCap); +#endif + } +#endif /* FEATURE_WLAN_ESE */ +#endif /* FEATURE_WLAN_ESE || FEATURE_WLAN_LFR */ + + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm.WMMInfoStation); + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); +#ifdef FEATURE_WLAN_ESE + if (pe_session->isESEconnection) { + uint32_t phymode; + uint8_t rate; + + populate_dot11f_re_assoc_tspec(mac_ctx, &frm, + pe_session); + + /* + * Populate the TSRS IE if TSPEC is included in + * the reassoc request + */ + lim_get_phy_mode(mac_ctx, &phymode, pe_session); + if (phymode == WNI_CFG_PHY_MODE_11G || + phymode == WNI_CFG_PHY_MODE_11A) + rate = TSRS_11AG_RATE_6MBPS; + else + rate = TSRS_11B_RATE_5_5MBPS; + + if (pe_session->pLimReAssocReq->eseTspecInfo. + numTspecs) { + tSirMacESETSRSIE tsrs_ie; + + tsrs_ie.tsid = 0; + tsrs_ie.rates[0] = rate; + populate_dot11_tsrsie(mac_ctx, &tsrs_ie, + &frm.ESETrafStrmRateSet, + sizeof(uint8_t)); + } + } +#endif + } + + ft_sme_context = &mac_ctx->roam.roamSession[sme_sessionid].ftSmeContext; + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm.HTCaps); + } +#if defined WLAN_FEATURE_VOWIFI_11R + if (pe_session->pLimReAssocReq->bssDescription.mdiePresent && + (ft_sme_context->addMDIE == true) +#if defined FEATURE_WLAN_ESE + && !pe_session->isESEconnection +#endif + ) { + populate_mdie(mac_ctx, &frm.MobilityDomain, + pe_session->pLimReAssocReq->bssDescription.mdie); + } +#endif + +#ifdef WLAN_FEATURE_11AC + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, + FL("Populate VHT IEs in Re-Assoc Request")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm.VHTCaps); + vht_enabled = true; + populate_dot11f_ext_cap(mac_ctx, vht_enabled, &frm.ExtCap, + pe_session); + } + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + lim_log(mac_ctx, LOG1, + FL("Populate Vendor VHT IEs in Re-Assoc Request")); + frm.vendor2_ie.present = 1; + frm.vendor2_ie.type = + pe_session->vendor_specific_vht_ie_type; + frm.vendor2_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + frm.vendor2_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.vendor2_ie.VHTCaps); + vht_enabled = true; + } +#endif + + status = dot11f_get_packed_re_assoc_request_size(mac_ctx, &frm, + &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Failure in size calculation (0x%08x)."), status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Warnings in size calculation(0x%08x)."), status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len; + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("FT IE Reassoc Req (%d)."), + ft_sme_context->reassoc_ft_ies_length); +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R + if (pe_session->is11Rconnection) + ft_ies_length = ft_sme_context->reassoc_ft_ies_length; +#endif + + cdf_status = cds_packet_alloc((uint16_t) bytes + ft_ies_length, + (void **)&frame, (void **)&packet); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + lim_log(mac_ctx, LOGP, FL("Failed to alloc memory %d"), bytes); + goto end; + } + /* Paranoia: */ + cdf_mem_set(frame, bytes + ft_ies_length, 0); + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + lim_print_mac_addr(mac_ctx, pe_session->limReAssocbssId, LOG1); +#endif + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId, + pe_session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + /* That done, pack the ReAssoc Request: */ + status = dot11f_pack_re_assoc_request(mac_ctx, &frm, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, FL("Failure in pack (0x%08x)."), status); + cds_packet_free((void *)packet); + goto end; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, FL("Warnings in pack (0x%08x)."), + status); + } + + lim_log(mac_ctx, LOG3, + FL("*** Sending Re-Assoc Request length %d %d to "), + bytes, payload); + + if (pe_session->assocReq != NULL) { + cdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + } + + if (add_ie_len) { + cdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + add_ie, add_ie_len); + payload += add_ie_len; + } + + pe_session->assocReq = cdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, LOGE, FL("Failed to alloc memory")); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + cdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if (pe_session->is11Rconnection && ft_sme_context->reassoc_ft_ies) { + int i = 0; + + body = frame + bytes; + for (i = 0; i < ft_ies_length; i++) { + *body = ft_sme_context->reassoc_ft_ies[i]; + body++; + } + } +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + PELOGE(lim_log(mac_ctx, LOG1, FL("Re-assoc Req Frame is: ")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG1, + (uint8_t *) frame, (bytes + ft_ies_length)); + ) +#endif + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(pe_session->currentOperChannel)) || + (pe_session->pePersona == CDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == CDF_P2P_GO_MODE)) { + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + if (NULL != pe_session->assocReq) { + cdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + } + + pe_session->assocReq = cdf_mem_malloc(ft_ies_length); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, LOGE, FL("Failed to alloc memory")); + pe_session->assocReqLen = 0; + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + cdf_mem_copy(pe_session->assocReq, + ft_sme_context->reassoc_ft_ies, (ft_ies_length)); + pe_session->assocReqLen = (ft_ies_length); + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_START_EVENT, + pe_session, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + cdf_status = wma_tx_frame(mac_ctx, packet, + (uint16_t) (bytes + ft_ies_length), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, tx_flag, sme_sessionid, + 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Re-Assoc Request (%X)!"), + cdf_status); + } + +end: + /* Free up buffer allocated for mlmAssocReq */ + cdf_mem_free(mlm_reassoc_req); + pe_session->pLimMlmReassocReq = NULL; + +} + +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tLimMlmReassocReq *pTmpMlmReassocReq = NULL; + if (NULL == pTmpMlmReassocReq) { + pTmpMlmReassocReq = cdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pTmpMlmReassocReq) + goto end; + cdf_mem_set(pTmpMlmReassocReq, sizeof(tLimMlmReassocReq), 0); + cdf_mem_copy(pTmpMlmReassocReq, pMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* Start reassociation failure timer */ + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not start Reassociation failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, pTmpMlmReassocReq, + psessionEntry); + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + cdf_mem_free(pMlmReassocReq); + pMlmReassocReq = NULL; + } + if (pTmpMlmReassocReq != NULL) { + cdf_mem_free(pTmpMlmReassocReq); + pTmpMlmReassocReq = NULL; + } + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +void +lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + static tDot11fReAssocRequest frm; + uint16_t caps; + uint8_t *pFrame; + uint32_t nBytes, nPayload, nStatus; + uint8_t fQosEnabled, fWmeEnabled, fWsmEnabled; + void *pPacket; + CDF_STATUS cdf_status; + uint16_t nAddIELen; + uint8_t *pAddIE; + uint8_t *wpsIe = NULL; + uint8_t txFlag = 0; +#if defined WLAN_FEATURE_VOWIFI + uint8_t PowerCapsPopulated = false; +#endif + uint8_t smeSessionId = 0; + bool isVHTEnabled = false; + tpSirMacMgmtHdr pMacHdr; + + if (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == psessionEntry->pLimReAssocReq) { + return; + } + nAddIELen = psessionEntry->pLimReAssocReq->addIEAssoc.length; + pAddIE = psessionEntry->pLimReAssocReq->addIEAssoc.addIEdata; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + caps = pMlmReassocReq->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* CR: 262463 : + According to WAPI standard: + 7.3.1.4 Capability Information field + In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 in transmitted + Association or Reassociation management frames. APs ignore the Privacy subfield within received Association and + Reassociation management frames. */ + if (psessionEntry->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm.Capabilities); + + frm.ListenInterval.interval = pMlmReassocReq->listenInterval; + + cdf_mem_copy((uint8_t *) frm.CurrentAPAddress.mac, + (uint8_t *) psessionEntry->bssId, 6); + + populate_dot11f_ssid2(pMac, &frm.SSID); + populate_dot11f_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, psessionEntry); + + fQosEnabled = (psessionEntry->limQosEnabled) && + SIR_MAC_GET_QOS(psessionEntry->limReassocBssCaps); + + fWmeEnabled = (psessionEntry->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, psessionEntry->limReassocBssQosCaps); + + fWsmEnabled = (psessionEntry->limWsmEnabled) && fWmeEnabled && + LIM_BSS_CAPS_GET(WSM, psessionEntry->limReassocBssQosCaps); + + if (psessionEntry->lim11hEnable && + psessionEntry->pLimReAssocReq->spectrumMgtIndicator == eSIR_TRUE) { +#if defined WLAN_FEATURE_VOWIFI + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, LIM_REASSOC, + psessionEntry); + populate_dot11f_supp_channels(pMac, &frm.SuppChannels, LIM_REASSOC, + psessionEntry); +#endif + } +#if defined WLAN_FEATURE_VOWIFI + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limCurrentBssCaps)) { + if (PowerCapsPopulated == false) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, + LIM_REASSOC, psessionEntry); + } + } +#endif + + if (fQosEnabled) + populate_dot11f_qos_caps_station(pMac, &frm.QOSCapsStation); + + populate_dot11f_ext_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, psessionEntry); + +#if defined WLAN_FEATURE_VOWIFI + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limReassocBssCaps)) { + populate_dot11f_rrm_ie(pMac, &frm.RRMEnabledCap, psessionEntry); + } +#endif + /* The join request *should* contain zero or one of the WPA and RSN */ + /* IEs. The payload send along with the request is a */ + /* 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* So, we should be able to make the following two calls harmlessly, */ + /* since they do nothing if they don't find the given IE in the */ + /* bytestream with which they're provided. */ + + /* The net effect of this will be to faithfully transmit whatever */ + /* security IE is in the join request. */ + + /**However*, if we're associating for the purpose of WPS */ + /* enrollment, and we've been configured to indicate that by */ + /* eliding the WPA or RSN IE, we just skip this: */ + if (nAddIELen && pAddIE) { + wpsIe = limGetWscIEPtr(pMac, pAddIE, nAddIELen); + } + if (NULL == wpsIe) { + populate_dot11f_rsn_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.RSNOpaque); + populate_dot11f_wpa_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(pMac, + &(psessionEntry->pLimReAssocReq-> + rsnIE), &frm.WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (fWmeEnabled) { + populate_dot11f_wmm_info_station_per_session(pMac, + psessionEntry, + &frm.WMMInfoStation); + + if (fWsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (psessionEntry->htCapability && + pMac->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(pMac, psessionEntry, &frm.HTCaps); + } +#ifdef WLAN_FEATURE_11AC + if (psessionEntry->vhtCapability && + psessionEntry->vhtCapabilityPresentInBeacon) { + lim_log(pMac, LOGW, FL("Populate VHT IEs in Re-Assoc Request")); + populate_dot11f_vht_caps(pMac, psessionEntry, &frm.VHTCaps); + isVHTEnabled = true; + } +#endif + + populate_dot11f_ext_cap(pMac, isVHTEnabled, &frm.ExtCap, psessionEntry); + + nStatus = dot11f_get_packed_re_assoc_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Re-Association Request (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Re-Association Re " + "quest(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr) + nAddIELen; + + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + psessionEntry->limMlmState = psessionEntry->limPrevMlmState; + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Re-As" + "sociation Request."), nBytes); + goto end; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, psessionEntry->limReAssocbssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* That done, pack the Probe Request: */ + nStatus = dot11f_pack_re_assoc_request(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Failed to pack a Re-Association Reque" + "st (0x%08x)."), nStatus); + cds_packet_free((void *)pPacket); + goto end; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a R" + "e-Association Request (0x%08x)."), + nStatus); + } + + PELOG1(lim_log + (pMac, LOG1, + FL("*** Sending Re-Association Request length %d" "to "), + nBytes); + ) + + if (psessionEntry->assocReq != NULL) { + cdf_mem_free(psessionEntry->assocReq); + psessionEntry->assocReq = NULL; + } + + if (nAddIELen) { + cdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + pAddIE, nAddIELen); + nPayload += nAddIELen; + } + + psessionEntry->assocReq = cdf_mem_malloc(nPayload); + if (NULL == psessionEntry->assocReq) { + PELOGE(lim_log + (pMac, LOGE, + FL("Unable to allocate memory to store assoc request")); + ) + } else { + /* Store the Assoc request. This is sent to csr/hdd in join cnf response. */ + cdf_mem_copy(psessionEntry->assocReq, + pFrame + sizeof(tSirMacMgmtHdr), nPayload); + psessionEntry->assocReqLen = nPayload; + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + if (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) { + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOC_START_EVENT, + psessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = + wma_tx_frame(pMac, pPacket, + (uint16_t) (sizeof(tSirMacMgmtHdr) + nPayload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, txFlag, smeSessionId, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send Re-Association Request (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + } + +end: + /* Free up buffer allocated for mlmAssocReq */ + cdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + +} /* lim_send_reassoc_req_mgmt_frame */ + +/** + * lim_send_auth_mgmt_frame() - Send an Authentication frame + * + * @mac_ctx: Pointer to Global MAC structure + * @auth_frame: Pointer to Authentication frame structure + * @peer_addr: MAC address of destination peer + * @wep_bit: wep bit in frame control for Authentication frame3 + * @session: PE session information + * + * This function is called by lim_process_mlm_messages(). Authentication frame + * is formatted and sent when this function is called. + * + * Return: void + */ + +void +lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tSirMacAddr peer_addr, + uint8_t wep_bit, tpPESession session) +{ + uint8_t *frame, *body; + uint32_t frame_len = 0, body_len = 0; + tpSirMacMgmtHdr mac_hdr; + void *packet; + CDF_STATUS cdf_status; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + uint16_t ft_ies_length = 0; + + if (NULL == session) { + lim_log(mac_ctx, LOGE, FL("Error: psession Entry is NULL")); + return; + } + + sme_sessionid = session->smeSessionId; + + lim_log(mac_ctx, LOG1, + FL("Sending Auth seq# %d status %d (%d) to " MAC_ADDRESS_STR), + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(peer_addr)); + + switch (auth_frame->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number + * and status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + +#if defined WLAN_FEATURE_VOWIFI_11R + if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) { + if (NULL != session->ftPEContext.pFTPreAuthReq && + 0 != session->ftPEContext.pFTPreAuthReq-> + ft_ies_length) { + ft_ies_length = session->ftPEContext. + pFTPreAuthReq->ft_ies_length; + frame_len += ft_ies_length; + lim_log(mac_ctx, LOG3, + FL("Auth frame, FTIES length added=%d"), + ft_ies_length); + } else { + lim_log(mac_ctx, LOG3, + FL("Auth frame, Does not contain FTIES!!!")); + frame_len += (2 + SIR_MDIE_SIZE); + } + } +#endif + break; + + case SIR_MAC_AUTH_FRAME_2: + if ((auth_frame->authAlgoNumber == eSIR_OPEN_SYSTEM) || + ((auth_frame->authAlgoNumber == eSIR_SHARED_KEY) && + (auth_frame->authStatusCode != + eSIR_MAC_SUCCESS_STATUS))) { + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number and status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + } else { + /* + * Shared Key algorithm with challenge text + * to be sent. + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number, status code and 128 bytes + * for challenge text. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + sizeof(tSirMacAuthFrame); + body_len = sizeof(tSirMacAuthFrameBody); + } + break; + + case SIR_MAC_AUTH_FRAME_3: + if (wep_bit == LIM_WEP_IN_FC) { + /* + * Auth frame3 to be sent with encrypted framebody + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number, + * status code, 128 bytes for challenge text and + * 4 bytes each for IV & ICV. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + LIM_ENCR_AUTH_BODY_LEN; + body_len = LIM_ENCR_AUTH_BODY_LEN; + } else { + + /* + * Auth frame3 to be sent without encrypted framebody + * + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + } + break; + + case SIR_MAC_AUTH_FRAME_4: + /* + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + + break; + } /* switch (auth_frame->authTransactionSeqNumber) */ + + cdf_status = cds_packet_alloc((uint16_t) frame_len, (void **)&frame, + (void **)&packet); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(mac_ctx, LOGP, + FL("call to bufAlloc failed for AUTH frame")); + return; + } + + cdf_mem_zero(frame, frame_len); + + /* Prepare BD */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_AUTH, peer_addr, session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + mac_hdr->fc.wep = wep_bit; + + /* Prepare BSSId */ + if (LIM_IS_AP_ROLE(session) || + LIM_IS_BT_AMP_AP_ROLE(session)) + cdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session->bssId, + sizeof(tSirMacAddr)); + + /* Prepare Authentication frame body */ + body = frame + sizeof(tSirMacMgmtHdr); + + if (wep_bit == LIM_WEP_IN_FC) { + cdf_mem_copy(body, (uint8_t *) auth_frame, body_len); + + lim_log(mac_ctx, LOG1, + FL("*** Sending Auth seq# 3 status %d (%d) to" + MAC_ADDRESS_STR), + auth_frame->authStatusCode, + (auth_frame->authStatusCode == eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(mac_hdr->da)); + + } else { + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authAlgoNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed( + auth_frame->authTransactionSeqNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authStatusCode); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + if (body_len <= (sizeof(auth_frame->type) + + sizeof(auth_frame->length) + + sizeof(auth_frame->challengeText))) + cdf_mem_copy(body, (uint8_t *) &auth_frame->type, + body_len); + +#if defined WLAN_FEATURE_VOWIFI_11R + if ((auth_frame->authAlgoNumber == eSIR_FT_AUTH) && + (auth_frame->authTransactionSeqNumber == + SIR_MAC_AUTH_FRAME_1) && + (session->ftPEContext.pFTPreAuthReq != NULL)) { + + if (ft_ies_length > 0) { + cdf_mem_copy(body, + session->ftPEContext. + pFTPreAuthReq->ft_ies, + ft_ies_length); +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG2, + FL("Auth1 Frame FTIE is: ")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + (uint8_t *) body, + ft_ies_length); +#endif + } else if (NULL != session->ftPEContext. + pFTPreAuthReq->pbssDescription) { + /* MDID attr is 54 */ + *body = SIR_MDIE_ELEMENT_ID; + body++; + *body = SIR_MDIE_SIZE; + body++; + cdf_mem_copy(body, + &session->ftPEContext.pFTPreAuthReq-> + pbssDescription->mdie[0], + SIR_MDIE_SIZE); + } + } +#endif + + lim_log(mac_ctx, LOG1, + FL("*** Sending Auth seq# %d status %d (%d) to " + MAC_ADDRESS_STR), + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == + eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(mac_hdr->da)); + } + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, frame, frame_len); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(session->currentOperChannel)) + || (session->pePersona == CDF_P2P_CLIENT_MODE) + || (session->pePersona == CDF_P2P_GO_MODE) +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + || ((NULL != session->ftPEContext.pFTPreAuthReq) && + (SIR_BAND_5_GHZ == + lim_get_rf_band(session->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum))) +#endif + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + + if (session->pePersona == CDF_P2P_CLIENT_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mac_hdr->fc.subType)); + /* Queue Authentication frame in high priority WQ */ + cdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) frame_len, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + frame, tx_flag, sme_sessionid, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + lim_log(mac_ctx, LOGE, + FL("*** Could not send Auth frame, retCode=%X ***"), + cdf_status); + + return; +} + +CDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal pMac) +{ + uint16_t aid; + tpDphHashNode pStaDs; + tLimMlmDeauthReq *pMlmDeauthReq; + tLimMlmDeauthCnf mlmDeauthCnf; + tpPESession psessionEntry; + + pMlmDeauthReq = pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (pMlmDeauthReq) { + if (tx_timer_running(&pMac->lim.limTimers.gLimDeauthAckTimer)) { + lim_deactivate_and_change_timer(pMac, + eLIM_DEAUTH_ACK_TIMER); + } + + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDeauthReq->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("session does not exist for given sessionId")); + ) + mlmDeauthCnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + pStaDs = + dph_lookup_hash_entry(pMac, pMlmDeauthReq->peerMacAddr, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + mlmDeauthCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* / Receive path cleanup with dummy packet */ + lim_ft_cleanup_pre_auth_info(pMac, psessionEntry); + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + /* / Free up buffer allocated for mlmDeauthReq */ + cdf_mem_free(pMlmDeauthReq); + pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + return CDF_STATUS_SUCCESS; +end: + cdf_mem_copy((uint8_t *) &mlmDeauthCnf.peerMacAddr, + (uint8_t *) pMlmDeauthReq->peerMacAddr, + sizeof(tSirMacAddr)); + mlmDeauthCnf.deauthTrigger = pMlmDeauthReq->deauthTrigger; + mlmDeauthCnf.aid = pMlmDeauthReq->aid; + mlmDeauthCnf.sessionId = pMlmDeauthReq->sessionId; + + /* Free up buffer allocated */ + /* for mlmDeauthReq */ + cdf_mem_free(pMlmDeauthReq); + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlmDeauthCnf); + return CDF_STATUS_SUCCESS; +} + +/** + * lim_send_disassoc_cnf() - Send disassoc confirmation to SME + * + * @mac_ctx: Handle to MAC context + * + * Sends disassoc confirmation to SME. Removes disassoc request stored + * in lim. + * + * Return: CDF_STATUS_SUCCESS + */ + +CDF_STATUS lim_send_disassoc_cnf(tpAniSirGlobal mac_ctx) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDisassocCnf disassoc_cnf; + tpPESession pe_session; + tLimMlmDisassocReq *disassoc_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (disassoc_req) { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDisassocAckTimer)) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + + pe_session = pe_find_session_by_session_id( + mac_ctx, disassoc_req->sessionId); + if (pe_session == NULL) { + lim_log(mac_ctx, LOGE, + FL("No session for given sessionId")); + disassoc_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, + disassoc_req->peerMacAddr, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("StaDs Null")); + disassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Receive path cleanup with dummy packet */ + if (eSIR_SUCCESS != + lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session)) { + disassoc_cnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + lim_log(mac_ctx, LOGE, FL("cleanup_rx_path error")); + goto end; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (LIM_IS_STA_ROLE(pe_session) && ( +#ifdef FEATURE_WLAN_ESE + (pe_session->isESEconnection) || +#endif +#ifdef FEATURE_WLAN_LFR + (pe_session->isFastRoamIniFeatureEnabled) || +#endif + (pe_session->is11Rconnection)) && + (disassoc_req->reasonCode != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + lim_log(mac_ctx, LOGE, + FL("FT Preauth Session (%p,%d) Clean up"), + pe_session, pe_session->peSessionId); + +#if defined WLAN_FEATURE_VOWIFI_11R + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(mac_ctx, pe_session); +#endif + } else { + lim_log(mac_ctx, LOGE, + FL("No FT Preauth Session Clean up in role %d" +#ifdef FEATURE_WLAN_ESE + " isESE %d" +#endif +#ifdef FEATURE_WLAN_LFR + " isLFR %d" +#endif + " is11r %d reason %d"), + GET_LIM_SYSTEM_ROLE(pe_session), +#ifdef FEATURE_WLAN_ESE + pe_session->isESEconnection, +#endif +#ifdef FEATURE_WLAN_LFR + pe_session->isFastRoamIniFeatureEnabled, +#endif + pe_session->is11Rconnection, + disassoc_req->reasonCode); + } +#endif + /* Free up buffer allocated for mlmDisassocReq */ + cdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + return CDF_STATUS_SUCCESS; + } else { + return CDF_STATUS_SUCCESS; + } +end: + cdf_mem_copy((uint8_t *) &disassoc_cnf.peerMacAddr, + (uint8_t *) disassoc_req->peerMacAddr, + sizeof(tSirMacAddr)); + disassoc_cnf.aid = disassoc_req->aid; + disassoc_cnf.disassocTrigger = disassoc_req->disassocTrigger; + + /* Update PE session ID */ + disassoc_cnf.sessionId = disassoc_req->sessionId; + + if (disassoc_req != NULL) { + /* / Free up buffer allocated for mlmDisassocReq */ + cdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + } + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &disassoc_cnf); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS lim_disassoc_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess) +{ + return lim_send_disassoc_cnf(pMac); +} + +CDF_STATUS lim_deauth_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess) +{ + return lim_send_deauth_cnf(pMac); +} + +/** + * \brief This function is called to send Disassociate frame. + * + * + * \param pMac Pointer to Global MAC structure + * + * \param nReason Indicates the reason that need to be sent in + * Disassociation frame + * + * \param peerMacAddr MAC address of the STA to which Disassociation frame is + * sent + * + * + */ + +void +lim_send_disassoc_mgmt_frame(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, bool waitForAck) +{ + tDot11fDisassociation frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; + uint8_t smeSessionId = 0; + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid sending disassoc out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == CDF_SAP_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop disassoc from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_disassociation_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Disassociation (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDisassociation); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Disassociation " + "(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a Dis" + "association."), nBytes); + return; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DISASSOC, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_disassociation(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Disassociation (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a D" + "isassociation (0x%08x)."), nStatus); + } + + lim_log(pMac, LOG1, + FL("***Sessionid %d Sending Disassociation frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR " ,From " + MAC_ADDRESS_STR), psessionEntry->peSessionId, nReason, + waitForAck, MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + if ((psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + } + + if (waitForAck) { + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + /* get the duration from the request */ + cdf_status = + wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_disassoc_tx_complete_cnf, + txFlag, smeSessionId, false, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDisassocAckTimer, val, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to change Disassoc ack Timer val")); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDisassocAckTimer)) { + lim_log(pMac, LOGP, + FL("Unable to activate Disassoc ack Timer")); + lim_deactivate_and_change_timer(pMac, + eLIM_DISASSOC_ACK_TIMER); + return; + } + } else { + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send Disassociation (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + } + } +} /* End lim_send_disassoc_mgmt_frame. */ + +/** + * \brief This function is called to send a Deauthenticate frame + * + * + * \param pMac Pointer to global MAC structure + * + * \param nReason Indicates the reason that need to be sent in the + * Deauthenticate frame + * + * \param peeer address of the STA to which the frame is to be sent + * + * + */ + +void +lim_send_deauth_mgmt_frame(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, bool waitForAck) +{ + tDot11fDeAuth frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; +#ifdef FEATURE_WLAN_TDLS + uint16_t aid; + tpDphHashNode pStaDs; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid deauth frame out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == CDF_SAP_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop the deauth from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_de_auth_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a De-Authentication (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDeAuth); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a De-Authentication " + "(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a De-" + "Authentication."), nBytes); + return; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DEAUTH, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_de_auth(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a DeAuthentication (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a D" + "e-Authentication (0x%08x)."), nStatus); + } + lim_log(pMac, LOG1, FL("***Sessionid %d Sending Deauth frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR + " ,From " MAC_ADDRESS_STR), + psessionEntry->peSessionId, nReason, waitForAck, + MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + if ((psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + } +#ifdef FEATURE_WLAN_TDLS + pStaDs = + dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); +#endif + + if (waitForAck) { + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + cdf_status = + wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_deauth_tx_complete_cnf, + txFlag, smeSessionId, false, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + /* Pkt will be freed up by the callback lim_tx_complete */ + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send De-Authentication (%X)!"), + cdf_status); + + /* Call lim_process_deauth_ack_timeout which will send + * DeauthCnf for this frame + */ + lim_process_deauth_ack_timeout(pMac); + return; + } + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDeauthAckTimer, val, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to change Deauth ack Timer val")); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDeauthAckTimer)) { + lim_log(pMac, LOGP, + FL("Unable to activate Deauth ack Timer")); + lim_deactivate_and_change_timer(pMac, + eLIM_DEAUTH_ACK_TIMER); + return; + } + } else { + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); +#ifdef FEATURE_WLAN_TDLS + if ((NULL != pStaDs) + && (STA_ENTRY_TDLS_PEER == pStaDs->staType)) { + /* Queue Disassociation frame in high priority WQ */ + cdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_IBSS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + } else { +#endif + /* Queue Disassociation frame in high priority WQ */ + cdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); +#ifdef FEATURE_WLAN_TDLS + } +#endif + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send De-Authentication (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + } + } + +} /* End lim_send_deauth_mgmt_frame. */ + +#ifdef ANI_SUPPORT_11H +/** + * \brief Send a Measurement Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pMeasReqFrame Address of a tSirMacMeasReqActionFrame + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_meas_report_frame(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fMeasurementReport frm; + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_MEASURE_REPORT_ID; + frm.DialogToken.token = pMeasReqFrame->actionHeader.dialogToken; + + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report0(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report1(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report2(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + default: + lim_log(pMac, LOGE, FL("Unknown measurement type %d in limSen" + "dMeasReportFrame."), + pMeasReqFrame->measReqIE.measType); + return eSIR_FAILURE; + } + + if (eSIR_SUCCESS != nSirStatus) + return eSIR_FAILURE; + + nStatus = dot11f_get_packed_measurement_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Measurement Report (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Measurement Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a De-" + "Authentication."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + cdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_measurement_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Measurement Report (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a M" + "easurement Report (0x%08x)."), nStatus); + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + cdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Measurement Report (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; /* just allocated... */ + } + + return eSIR_SUCCESS; + +} /* End lim_send_meas_report_frame. */ + +/** + * \brief Send a TPC Request Action frame + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which the frame should be sent + * + * + */ + +void +lim_send_tpc_request_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REQUEST_ID; + frm.DialogToken.token = 1; + frm.TPCRequest.present = 1; + + nStatus = dot11f_get_packed_tpc_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a TPC Request (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a TPC Request (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Request."), nBytes); + return; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + cdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_request(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Failed to pack a TPC Request (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a T" + "PC Request (0x%08x)."), nStatus); + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + cdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a TPC Request (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + } + +} /* End lim_send_tpc_request_frame. */ + +/** + * \brief Send a TPC Report Action frame + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param pTpcReqFrame Pointer to the received TPC Request + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_tpc_report_frame(tpAniSirGlobal pMac, + tpSirMacTpcReqActionFrame pTpcReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REPORT_ID; + frm.DialogToken.token = pTpcReqFrame->actionHeader.dialogToken; + + frm.TPCReport.tx_power = 0; + frm.TPCReport.link_margin = 0; + frm.TPCReport.present = 1; + + nStatus = dot11f_get_packed_tpc_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a TPC Report (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a TPC Report (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + cdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Failed to pack a TPC Report (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a T" + "PC Report (0x%08x)."), nStatus); + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + cdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(cdf_trace + (CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a TPC Report (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; /* just allocated... */ + } + + return eSIR_SUCCESS; + +} /* End lim_send_tpc_report_frame. */ +#endif /* ANI_SUPPORT_11H */ + +/** + * \brief Send a Channel Switch Announcement + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which this frame will be sent + * + * \param nMode + * + * \param nNewChannel + * + * \param nCount + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_channel_switch_mgmt_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, + uint8_t nNewChannel, + uint8_t nCount, tpPESession psessionEntry) +{ + tDot11fChannelSwitch frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; /* , nCfg; */ + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Session entry is NULL!!!"));) + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_CHANNEL_SWITCH_ID; + frm.ChanSwitchAnn.switchMode = nMode; + frm.ChanSwitchAnn.newChannel = nNewChannel; + frm.ChanSwitchAnn.switchCount = nCount; + frm.ChanSwitchAnn.present = 1; + + nStatus = dot11f_get_packed_channel_switch_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Channel Switch (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fChannelSwitch); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Channel Switch (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + cdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_channel_switch(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Channel Switch (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a C" + "hannel Switch (0x%08x)."), nStatus); + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Channel Switch (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} /* End lim_send_channel_switch_mgmt_frame. */ + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus +lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, tpPESession psessionEntry) +{ + tDot11fOperatingMode frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload = 0, nStatus; /* , nCfg; */ + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Session entry is NULL!!!"));) + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_VHT; + frm.Action.action = SIR_MAC_VHT_OPMODE_NOTIFICATION; + frm.OperatingMode.chanWidth = nMode; + frm.OperatingMode.rxNSS = 0; + frm.OperatingMode.rxNSSType = 0; + + nStatus = dot11f_get_packed_operating_mode_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Operating Mode (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fOperatingMode); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Operating Mode (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Operating Mode" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + if (psessionEntry->pePersona == CDF_SAP_MODE) + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + else + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, psessionEntry->bssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + cdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + nStatus = dot11f_pack_operating_mode(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Operating Mode (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing a Operating Mode" + " (0x%08x)."), nStatus); + } + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Channel Switch (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/** + * \brief Send a VHT Channel Switch Announcement + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which this frame will be sent + * + * \param nChanWidth + * + * \param nNewChannel + * + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_vht_channel_switch_mgmt_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nChanWidth, + uint8_t nNewChannel, + uint8_t ncbMode, tpPESession psessionEntry) +{ + tDot11fChannelSwitch frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; /* , nCfg; */ + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Session entry is NULL!!!"));) + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_CHANNEL_SWITCH_ID; + frm.ChanSwitchAnn.switchMode = 1; + frm.ChanSwitchAnn.newChannel = nNewChannel; + frm.ChanSwitchAnn.switchCount = 1; + frm.sec_chan_offset_ele.secondaryChannelOffset = + lim_get_htcb_state(ncbMode); + frm.sec_chan_offset_ele.present = 1; + frm.WiderBWChanSwitchAnn.newChanWidth = nChanWidth; + frm.WiderBWChanSwitchAnn.newCenterChanFreq0 = + lim_get_center_channel(pMac, nNewChannel, ncbMode, nChanWidth); + frm.WiderBWChanSwitchAnn.newCenterChanFreq1 = 0; + frm.ChanSwitchAnn.present = 1; + frm.WiderBWChanSwitchAnn.present = 1; + + nStatus = dot11f_get_packed_channel_switch_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Channel Switch (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fChannelSwitch); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Channel Switch (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + cdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + nStatus = dot11f_pack_channel_switch(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Channel Switch (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a C" + "hannel Switch (0x%08x)."), nStatus); + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Channel Switch (%X)!"), + cdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} /* End lim_send_vht_channel_switch_mgmt_frame. */ + +#endif + +#if defined WLAN_FEATURE_VOWIFI + +/** + * \brief Send a Neighbor Report Request Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pNeighborReq Address of a tSirMacNeighborReportReq + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_neighbor_report_request_frame(tpAniSirGlobal pMac, + tpSirMacNeighborReportReq pNeighborReq, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + tDot11fNeighborReportRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Neighbor Report request action frame")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_RRM_NEIGHBOR_REQ; + frm.DialogToken.token = pNeighborReq->dialogToken; + + if (pNeighborReq->ssid_present) { + populate_dot11f_ssid(pMac, &pNeighborReq->ssid, &frm.SSID); + } + + nStatus = + dot11f_get_packed_neighbor_report_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Neighbor Report Request(0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fNeighborReportRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Neighbor Rep" + "ort Request(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Neighbor " + "Report Request."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_neighbor_report_request(pMac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to pack an Neighbor Report Request (0x%08x)."), + nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing Neighbor Report " + "Request (0x%08x)."), nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Neighbor Report Request to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (CDF_STATUS_SUCCESS != cdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + cdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return eSIR_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_neighbor_report_request_frame. */ + +/** + * \brief Send a Link Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pLinkReport Address of a tSirMacLinkReport + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_link_report_action_frame(tpAniSirGlobal pMac, + tpSirMacLinkReport pLinkReport, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + tDot11fLinkMeasurementReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Link Report action frame")); + return eSIR_FAILURE; + } + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_RRM_LINK_MEASUREMENT_RPT; + frm.DialogToken.token = pLinkReport->dialogToken; + + /* IEEE Std. 802.11 7.3.2.18. for the report element. */ + /* Even though TPC report an IE, it is represented using fixed fields since it is positioned */ + /* in the middle of other fixed fields in the link report frame(IEEE Std. 802.11k section7.4.6.4 */ + /* and frame parser always expects IEs to come after all fixed fields. It is easier to handle */ + /* such case this way than changing the frame parser. */ + frm.TPCEleID.TPCId = SIR_MAC_TPC_RPT_EID; + frm.TPCEleLen.TPCLen = 2; + frm.TxPower.txPower = pLinkReport->txPower; + frm.LinkMargin.linkMargin = 0; + + frm.RxAntennaId.antennaId = pLinkReport->rxAntenna; + frm.TxAntennaId.antennaId = pLinkReport->txAntenna; + frm.RCPI.rcpi = pLinkReport->rcpi; + frm.RSNI.rsni = pLinkReport->rsni; + + nStatus = + dot11f_get_packed_link_measurement_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Link Report (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Link Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a Link " + "Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_link_measurement_report(pMac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Link Report (0x%08x)."), nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing Link Report (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Link Report to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (CDF_STATUS_SUCCESS != cdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + cdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return eSIR_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_link_report_action_frame. */ + +/** + * \brief Send a Beacon Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param dialog_token dialog token to be used in the action frame. + * + * \param num_report number of reports in pRRMReport. + * + * \param pRRMReport Address of a tSirMacRadioMeasureReport. + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_radio_measure_report_action_frame(tpAniSirGlobal pMac, + uint8_t dialog_token, + uint8_t num_report, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t i; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + tDot11fRadioMeasurementReport *frm = + cdf_mem_malloc(sizeof(tDot11fRadioMeasurementReport)); + if (!frm) { + lim_log(pMac, LOGE, + FL + ("Not enough memory to allocate tDot11fRadioMeasurementReport")); + return eSIR_MEM_ALLOC_FAILED; + } + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Beacon Report action frame")); + cdf_mem_free(frm); + return eSIR_FAILURE; + } + cdf_mem_set((uint8_t *) frm, sizeof(*frm), 0); + + frm->Category.category = SIR_MAC_ACTION_RRM; + frm->Action.action = SIR_MAC_RRM_RADIO_MEASURE_RPT; + frm->DialogToken.token = dialog_token; + + frm->num_MeasurementReport = + (num_report > + RADIO_REPORTS_MAX_IN_A_FRAME) ? RADIO_REPORTS_MAX_IN_A_FRAME : + num_report; + + for (i = 0; i < frm->num_MeasurementReport; i++) { + frm->MeasurementReport[i].type = pRRMReport[i].type; + frm->MeasurementReport[i].token = pRRMReport[i].token; + frm->MeasurementReport[i].late = 0; /* IEEE 802.11k section 7.3.22. (always zero in rrm) */ + switch (pRRMReport[i].type) { + case SIR_MAC_RRM_BEACON_TYPE: + populate_dot11f_beacon_report(pMac, + &frm->MeasurementReport[i], + &pRRMReport[i].report. + beaconReport); + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + default: + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + } + } + + nStatus = + dot11f_get_packed_radio_measurement_report_size(pMac, frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Radio Measure Report (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + cdf_mem_free(frm); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Radio Measure Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + cdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Radio Measure " + "Report."), nBytes); + cdf_mem_free(frm); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_radio_measurement_report(pMac, + frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Radio Measure Report (0x%08x)."), + nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing Radio " + "Measure Report (0x%08x)."), nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Radio Measure Report to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (CDF_STATUS_SUCCESS != cdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + cdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + cdf_mem_free(frm); + return statusCode; + } else { + cdf_mem_free(frm); + return eSIR_SUCCESS; + } + +returnAfterError: + cdf_mem_free(frm); + cds_packet_free((void *)pPacket); + return statusCode; +} + +#endif + +#ifdef WLAN_FEATURE_11W +/** + * \brief Send SA query request action frame to peer + * + * \sa lim_send_sa_query_request_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier + * + * \param peer The Mac address of the station to which this action frame is addressed + * + * \param psessionEntry The PE session entry + * + * \return eSIR_SUCCESS if setup completes successfully + * eSIR_FAILURE is some problem is encountered + */ + +tSirRetStatus lim_send_sa_query_request_frame(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + + tDot11fSaQueryReq frm; /* SA query request action frame */ + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + frm.Category.category = SIR_MAC_ACTION_SA_QUERY; + /* 11w action field is : + action: 0 --> SA Query Request action frame + action: 1 --> SA Query Response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_REQ; + /* 11w SA Query Request transId */ + cdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_req_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size " + "for an SA Query Request (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryReq); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for an SA Query Request" + " (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + cdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a SA Query Request " + "action frame"), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Request, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA Query Request frame */ + nStatus = dot11f_pack_sa_query_req(pMac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an SA Query Request (0x%08x)."), + nStatus); + /* FIXME - Need to convert to tSirRetStatus */ + nSirStatus = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing SA Query Request (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOG1, FL("Sending an SA Query Request to ")); + lim_print_mac_addr(pMac, peer, LOG1); + lim_log(pMac, LOG1, FL("Sending an SA Query Request from ")); + lim_print_mac_addr(pMac, psessionEntry->selfMacAddr, LOG1); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + smeSessionId = psessionEntry->smeSessionId; + + cdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + if (CDF_STATUS_SUCCESS != cdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + cdf_status); + ) + nSirStatus = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return eSIR_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + return nSirStatus; +} /* End lim_send_sa_query_request_frame */ + +/** + * \brief Send SA query response action frame to peer + * + * \sa lim_send_sa_query_response_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier received in SA query request action frame + * + * \param peer The Mac address of the AP to which this action frame is addressed + * + * \param psessionEntry The PE session entry + * + * \return eSIR_SUCCESS if setup completes successfully + * eSIR_FAILURE is some problem is encountered + */ + +tSirRetStatus lim_send_sa_query_response_frame(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry) +{ + + tDot11fSaQueryRsp frm; /* SA query reponse action frame */ + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + CDF_STATUS cdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + smeSessionId = psessionEntry->smeSessionId; + + cdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + frm.Category.category = SIR_MAC_ACTION_SA_QUERY; + /*11w action field is : + action: 0 --> SA query request action frame + action: 1 --> SA query response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_RSP; + /*11w SA query response transId is same as + SA query request transId */ + cdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_rsp_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a SA Query Response (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryRsp); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for an SA Query Response" + " (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + cdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a SA query response" + " action frame"), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + cdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Response, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA query response frame */ + nStatus = dot11f_pack_sa_query_rsp(pMac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an SA Query Response (0x%08x)."), + nStatus); + /* FIXME - Need to convert to tSirRetStatus */ + nSirStatus = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing SA Query Response (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOG1, FL("Sending a SA Query Response to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == CDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + cdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(cdf_trace(CDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, cdf_status)); + if (CDF_STATUS_SUCCESS != cdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + cdf_status); + ) + nSirStatus = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return eSIR_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + return nSirStatus; +} /* End lim_send_sa_query_response_frame */ +#endif diff --git a/core/mac/src/pe/lim/lim_send_messages.c b/core/mac/src/pe/lim/lim_send_messages.c new file mode 100644 index 0000000000..e47bf2fbc3 --- /dev/null +++ b/core/mac/src/pe/lim/lim_send_messages.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_send_messages.c: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#include "lim_send_messages.h" +#include "cfg_api.h" +#include "lim_trace.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +/* When beacon filtering is enabled, firmware will + * analyze the selected beacons received during BMPS, + * and monitor any changes in the IEs as listed below. + * The format of the table is: + * - EID + * - Check for IE presence + * - Byte offset + * - Byte value + * - Bit Mask + * - Byte refrence + */ +static tBeaconFilterIe beacon_filter_table[] = { + {SIR_MAC_DS_PARAM_SET_EID, 0, {0, 0, DS_PARAM_CHANNEL_MASK, 0} }, + {SIR_MAC_ERP_INFO_EID, 0, {0, 0, ERP_FILTER_MASK, 0} }, + {SIR_MAC_EDCA_PARAM_SET_EID, 0, {0, 0, EDCA_FILTER_MASK, 0} }, + {SIR_MAC_QOS_CAPABILITY_EID, 0, {0, 0, QOS_FILTER_MASK, 0} }, + {SIR_MAC_CHNL_SWITCH_ANN_EID, 1, {0, 0, 0, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {0, 0, HT_BYTE0_FILTER_MASK, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {2, 0, HT_BYTE2_FILTER_MASK, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {5, 0, HT_BYTE5_FILTER_MASK, 0} } +#if defined WLAN_FEATURE_VOWIFI + , {SIR_MAC_PWR_CONSTRAINT_EID, 0, {0, 0, 0, 0} } +#endif +#ifdef WLAN_FEATURE_11AC + , {SIR_MAC_VHT_OPMODE_EID, 0, {0, 0, 0, 0} } + , {SIR_MAC_VHT_OPERATION_EID, 0, {0, 0, VHTOP_CHWIDTH_MASK, 0} } +#endif +}; + +/** + * lim_send_cf_params() + * + ***FUNCTION: + * This function is called to send CFP Parameters to WMA, when they are changed. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param bssIdx Bss Index of the BSS to which STA is associated. + * @param cfpCount CFP Count, if that is changed. + * @param cfpPeriod CFP Period if that is changed. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod) +{ + tpUpdateCFParams pCFParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pCFParams = cdf_mem_malloc(sizeof(tUpdateCFParams)); + if (NULL == pCFParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update CF Params")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } + cdf_mem_set((uint8_t *) pCFParams, sizeof(tUpdateCFParams), 0); + pCFParams->cfpCount = cfpCount; + pCFParams->cfpPeriod = cfpPeriod; + pCFParams->bssIdx = bssIdx; + + msgQ.type = WMA_UPDATE_CF_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pCFParams; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_CF_IND...")); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pCFParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_CF_IND failed, reason=%X"), + retCode); + } +returnFailure: + return retCode; +} + +/** + * lim_send_beacon_params() - updates bcn params to WMA + * + * @pMac : pointer to Global Mac structure. + * @tpUpdateBeaconParams : pointer to the structure, which contains the beacon + * parameters which are changed. + * + * This function is called to send beacon interval, short preamble or other + * parameters to WMA, which are changed and indication is received in beacon. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry) +{ + tpUpdateBeaconParams pBcnParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pBcnParams = cdf_mem_malloc(sizeof(*pBcnParams)); + if (NULL == pBcnParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Beacon Params")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_copy((uint8_t *) pBcnParams, pUpdatedBcnParams, + sizeof(*pBcnParams)); + msgQ.type = WMA_UPDATE_BEACON_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pBcnParams; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, + FL("Sending WMA_UPDATE_BEACON_IND, paramChangeBitmap in hex = %x"), + pUpdatedBcnParams->paramChangeBitmap);) + if (NULL == psessionEntry) { + cdf_mem_free(pBcnParams); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + return eSIR_FAILURE; + } else { + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + } + pBcnParams->smeSessionId = psessionEntry->smeSessionId; + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pBcnParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_BEACON_IND, reason=%X"), + retCode); + } + lim_send_beacon_ind(pMac, psessionEntry); + return retCode; +} + +/** + * lim_send_switch_chnl_params() + * + ***FUNCTION: + * This function is called to send Channel Switch Indication to WMA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param chnlNumber New Channel Number to be switched to. + * @param ch_width an enum for channel width. + * @param localPowerConstraint 11h local power constraint value + * + * @return success if message send is ok, else false. + */ +#if !defined WLAN_FEATURE_VOWIFI +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, + uint8_t localPwrConstraint, + uint8_t peSessionId, + uint8_t is_restart) +#else +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, + tPowerdBm maxTxPower, + uint8_t peSessionId, + uint8_t is_restart) +#endif +{ + tpSwitchChannelParams pChnlParams = NULL; + tSirMsgQ msgQ; + tpPESession pSessionEntry; + pSessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (pSessionEntry == NULL) { + lim_log(pMac, LOGP, FL( + "Unable to get Session for session Id %d"), + peSessionId); + return eSIR_FAILURE; + } + pChnlParams = cdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pChnlParams) { + lim_log(pMac, LOGP, FL( + "Unable to allocate memory for Switch Ch Params")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set((uint8_t *) pChnlParams, sizeof(tSwitchChannelParams), 0); + pChnlParams->channelNumber = chnlNumber; + pChnlParams->ch_center_freq_seg0 = ch_center_freq_seg0; + pChnlParams->ch_center_freq_seg1 = ch_center_freq_seg1; + pChnlParams->ch_width = ch_width; + cdf_mem_copy(pChnlParams->selfStaMacAddr, pSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); +#if defined WLAN_FEATURE_VOWIFI + pChnlParams->maxTxPower = maxTxPower; +#else + pChnlParams->localPowerConstraint = localPwrConstraint; +#endif + cdf_mem_copy(pChnlParams->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pChnlParams->peSessionId = peSessionId; + pChnlParams->vhtCapable = pSessionEntry->vhtCapability; + pChnlParams->dot11_mode = pSessionEntry->dot11mode; + pChnlParams->nss = pSessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pChnlParams->nss); + + /*Set DFS flag for DFS channel */ + if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS) + pChnlParams->isDfsChannel = true; + else + pChnlParams->isDfsChannel = false; + + pChnlParams->restart_on_chan_switch = is_restart; + + /* we need to defer the message until we + * get the response back from WMA + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_CHNL_SWITCH_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pChnlParams; + msgQ.bodyval = 0; +#if defined WLAN_FEATURE_VOWIFI + PELOG3(lim_log(pMac, LOG3, FL( + "Sending CH_SWITCH_REQ, ch_width %d, ch_num %d, maxTxPower %d"), + pChnlParams->ch_width, + pChnlParams->channelNumber, pChnlParams->maxTxPower);) +#else + PELOG3(lim_log(pMac, LOG3, FL( + "Sending CH_SWITCH_REQ, ch_width %d, ch_num %d, local_pwr_constraint %d"), + pChnlParams->ch_width, + pChnlParams->channelNumber, + pChnlParams->localPowerConstraint);) +#endif + MTRACE(mac_trace_msg_tx(pMac, peSessionId, msgQ.type)); + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msgQ)) { + cdf_mem_free(pChnlParams); + lim_log(pMac, LOGP, FL( + "Posting CH_SWITCH_REQ to WMA failed")); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** + * lim_send_edca_params() + * + ***FUNCTION: + * This function is called to send dynamically changing EDCA Parameters to WMA. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param tpUpdatedEdcaParams pointer to the structure which contains + * dynamically changing EDCA parameters. + * @param highPerformance If the peer is Airgo (taurus) then switch to highPerformance is true. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx) +{ + tEdcaParams *pEdcaParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + uint8_t i; + + pEdcaParams = cdf_mem_malloc(sizeof(tEdcaParams)); + if (NULL == pEdcaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update EDCA Params")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + pEdcaParams->bssIdx = bssIdx; + pEdcaParams->acbe = pUpdatedEdcaParams[EDCA_AC_BE]; + pEdcaParams->acbk = pUpdatedEdcaParams[EDCA_AC_BK]; + pEdcaParams->acvi = pUpdatedEdcaParams[EDCA_AC_VI]; + pEdcaParams->acvo = pUpdatedEdcaParams[EDCA_AC_VO]; + msgQ.type = WMA_UPDATE_EDCA_PROFILE_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pEdcaParams; + msgQ.bodyval = 0; + PELOG1(lim_log(pMac, LOG1, + FL("Sending WMA_UPDATE_EDCA_PROFILE_IND, EDCA Parameters:"));) + for (i = 0; i < MAX_NUM_AC; i++) { + PELOG1(lim_log(pMac, LOG1, + FL("AC[%d]: AIFSN %d, ACM %d, CWmin %d, CWmax %d, TxOp %d "), + i, pUpdatedEdcaParams[i].aci.aifsn, + pUpdatedEdcaParams[i].aci.acm, + pUpdatedEdcaParams[i].cw.min, + pUpdatedEdcaParams[i].cw.max, + pUpdatedEdcaParams[i].txoplimit);) + } + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pEdcaParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_EDCA_PROFILE_IND failed, reason=%X"), + retCode); + } + return retCode; +} + +/** + * lim_set_active_edca_params() - Choose best EDCA parameters + * + * @mac_ctx: pointer to Global Mac structure. + * @edca_params: pointer to the local EDCA parameters + * @pe_session: point to the session entry + * + * This function is called to set the most up-to-date EDCA parameters + * given the default local EDCA parameters. The rules are as following: + * - If ACM bit is set for all ACs, then downgrade everything to Best Effort. + * - If ACM is not set for any AC, then PE will use the default EDCA + * parameters as advertised by AP. + * - If ACM is set in any of the ACs, PE will use the EDCA parameters + * from the next best AC for which ACM is not enabled. + * + * Return: none + */ + +void lim_set_active_edca_params(tpAniSirGlobal mac_ctx, + tSirMacEdcaParamRecord *edca_params, + tpPESession pe_session) +{ + uint8_t ac, new_ac, i; + uint8_t ac_admitted; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + /* Initialize gLimEdcaParamsActive[] to be same as localEdcaParams */ + pe_session->gLimEdcaParamsActive[EDCA_AC_BE] = edca_params[EDCA_AC_BE]; + pe_session->gLimEdcaParamsActive[EDCA_AC_BK] = edca_params[EDCA_AC_BK]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VI] = edca_params[EDCA_AC_VI]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VO] = edca_params[EDCA_AC_VO]; + /* An AC requires downgrade if the ACM bit is set, and the AC has not + * yet been admitted in uplink or bi-directions. + * If an AC requires downgrade, it will downgrade to the next beset AC + * for which ACM is not enabled. + * + * - There's no need to downgrade AC_BE since it IS the lowest AC. Hence + * start the for loop with AC_BK. + * - If ACM bit is set for an AC, initially downgrade it to AC_BE. Then + * traverse thru the AC list. If we do find the next best AC which is + * better than AC_BE, then use that one. For example, if ACM bits are set + * such that: BE_ACM=1, BK_ACM=1, VI_ACM=1, VO_ACM=0 + * then all AC will be downgraded to AC_BE. + */ + lim_log(mac_ctx, LOG1, FL("adAdmitMask[UPLINK] = 0x%x "), + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK]); + lim_log(mac_ctx, LOG1, FL("adAdmitMask[DOWNLINK] = 0x%x "), + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK]); + for (ac = EDCA_AC_BK; ac <= EDCA_AC_VO; ac++) { + ac_admitted = + ((pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] & + (1 << ac)) >> ac); + + lim_log(mac_ctx, LOG1, + FL("For AC[%d]: acm=%d, ac_admitted=%d "), + ac, edca_params[ac].aci.acm, ac_admitted); + if ((edca_params[ac].aci.acm == 1) && (ac_admitted == 0)) { + lim_log(mac_ctx, LOG1, + FL("We need to downgrade AC %d!! "), ac); + /* Loop backwards through AC values until it finds + * acm == 0 or reaches EDCA_AC_BE. + * Note that for block has no executable statements. + */ + for (i = ac - 1; + (i > EDCA_AC_BE && + (edca_params[i].aci.acm != 0)); + i--) + ; + new_ac = i; + lim_log(mac_ctx, LOGW, + FL("Downgrading AC %d ---> AC %d "), + ac, new_ac); + pe_session->gLimEdcaParamsActive[ac] = + edca_params[new_ac]; + } + } +/* log: LOG_WLAN_QOS_EDCA_C */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + tSirMacEdcaParamRecord *rec; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_BE]; + log_ptr->aci_be = rec->aci.aci; + log_ptr->cw_be = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_be = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_BK]; + log_ptr->aci_bk = rec->aci.aci; + log_ptr->cw_bk = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_bk = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_VI]; + log_ptr->aci_vi = rec->aci.aci; + log_ptr->cw_vi = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vi = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_VO]; + log_ptr->aci_vo = rec->aci.aci; + log_ptr->cw_vo = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vo = rec->txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return; +} + +/** --------------------------------------------------------- + \fn lim_set_link_state + \brief LIM sends a message to WMA to set the link state + \param tpAniSirGlobal pMac + \param tSirLinkState state + \return None + -----------------------------------------------------------*/ +tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMacAddr, + tpSetLinkStateCallback callback, + void *callbackArg) +{ + tSirMsgQ msgQ; + tSirRetStatus retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = cdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory while sending Set Link State")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + cdf_mem_set((uint8_t *) pLinkStateParams, sizeof(tLinkStateParams), 0); + pLinkStateParams->state = state; + pLinkStateParams->callback = callback; + pLinkStateParams->callbackArg = callbackArg; + + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != eSIR_SUCCESS) { + cdf_mem_free(pLinkStateParams); + lim_log(pMac, LOGP, + FL("Posting link state %d failed, reason = %x "), state, + retCode); + } + return retCode; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +extern tSirRetStatus lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tSirRetStatus retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = cdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory while sending Set Link State")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + cdf_mem_set((uint8_t *) pLinkStateParams, sizeof(tLinkStateParams), 0); + pLinkStateParams->state = state; + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + pLinkStateParams->ft = 1; + pLinkStateParams->session = psessionEntry; + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, msgQ.type)); + } + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != eSIR_SUCCESS) { + cdf_mem_free(pLinkStateParams); + lim_log(pMac, LOGP, + FL("Posting link state %d failed, reason = %x "), state, + retCode); + } + return retCode; +} +#endif + +/** --------------------------------------------------------- + \fn lim_send_beacon_filter_info + \brief LIM sends beacon filtering info to WMA + \param tpAniSirGlobal pMac + \return None + -----------------------------------------------------------*/ +tSirRetStatus lim_send_beacon_filter_info(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpBeaconFilterMsg pBeaconFilterMsg = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + uint8_t *ptr; + uint32_t i; + uint32_t msgSize; + tpBeaconFilterIe pIe; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, FL("Fail to find the right session ")); + retCode = eSIR_FAILURE; + return retCode; + } + msgSize = sizeof(tBeaconFilterMsg) + sizeof(beacon_filter_table); + pBeaconFilterMsg = cdf_mem_malloc(msgSize); + if (NULL == pBeaconFilterMsg) { + lim_log(pMac, LOGP, + FL("Fail to allocate memory for beaconFiilterMsg ")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + cdf_mem_set((uint8_t *) pBeaconFilterMsg, msgSize, 0); + /* Fill in capability Info and mask */ + /* Don't send this message if no active Infra session is found. */ + pBeaconFilterMsg->capabilityInfo = psessionEntry->limCurrentBssCaps; + pBeaconFilterMsg->capabilityMask = CAPABILITY_FILTER_MASK; + pBeaconFilterMsg->beaconInterval = + (uint16_t) psessionEntry->beaconParams.beaconInterval; + /* Fill in number of IEs in beacon_filter_table */ + pBeaconFilterMsg->ieNum = + (uint16_t) (sizeof(beacon_filter_table) / sizeof(tBeaconFilterIe)); + /* Fill the BSSIDX */ + pBeaconFilterMsg->bssIdx = psessionEntry->bssIdx; + + /* Fill message with info contained in the beacon_filter_table */ + ptr = (uint8_t *) pBeaconFilterMsg + sizeof(tBeaconFilterMsg); + for (i = 0; i < (pBeaconFilterMsg->ieNum); i++) { + pIe = (tpBeaconFilterIe) ptr; + pIe->elementId = beacon_filter_table[i].elementId; + pIe->checkIePresence = beacon_filter_table[i].checkIePresence; + pIe->byte.offset = beacon_filter_table[i].byte.offset; + pIe->byte.value = beacon_filter_table[i].byte.value; + pIe->byte.bitMask = beacon_filter_table[i].byte.bitMask; + pIe->byte.ref = beacon_filter_table[i].byte.ref; + ptr += sizeof(tBeaconFilterIe); + } + msgQ.type = WMA_BEACON_FILTER_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pBeaconFilterMsg; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL("Sending WMA_BEACON_FILTER_IND...")); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pBeaconFilterMsg); + lim_log(pMac, LOGP, + FL("Posting WMA_BEACON_FILTER_IND failed, reason=%X"), + retCode); + return retCode; + } + return retCode; +} + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *pTempParam, + tpPESession psessionEntry) +{ + tUpdateVHTOpMode *pVhtOpMode = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pVhtOpMode = cdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pVhtOpMode) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Op Mode")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_copy((uint8_t *) pVhtOpMode, pTempParam, + sizeof(tUpdateVHTOpMode)); + msgQ.type = WMA_UPDATE_OP_MODE; + msgQ.reserved = 0; + msgQ.bodyptr = pVhtOpMode; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL( + "Sending WMA_UPDATE_OP_MODE, op_mode %d, sta_id %d"), + pVhtOpMode->opMode, pVhtOpMode->staId); + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pVhtOpMode); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_OP_MODE failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_send_rx_nss_update(tpAniSirGlobal pMac, + tUpdateRxNss *pTempParam, + tpPESession psessionEntry) +{ + tUpdateRxNss *pRxNss = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pRxNss = cdf_mem_malloc(sizeof(tUpdateRxNss)); + if (NULL == pRxNss) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Rx Nss")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_copy((uint8_t *) pRxNss, pTempParam, sizeof(tUpdateRxNss)); + msgQ.type = WMA_UPDATE_RX_NSS; + msgQ.reserved = 0; + msgQ.bodyptr = pRxNss; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_RX_NSS"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pRxNss); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_RX_NSS failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_set_membership(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry) +{ + tUpdateMembership *pMembership = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pMembership = cdf_mem_malloc(sizeof(tUpdateMembership)); + if (NULL == pMembership) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Membership Mode")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_copy((uint8_t *) pMembership, pTempParam, + sizeof(tUpdateMembership)); + + msgQ.type = WMA_UPDATE_MEMBERSHIP; + msgQ.reserved = 0; + msgQ.bodyptr = pMembership; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_MEMBERSHIP"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pMembership); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_MEMBERSHIP failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_set_user_pos(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry) +{ + tUpdateUserPos *pUserPos = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pUserPos = cdf_mem_malloc(sizeof(tUpdateUserPos)); + if (NULL == pUserPos) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update User Position")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_copy((uint8_t *) pUserPos, pTempParam, sizeof(tUpdateUserPos)); + + msgQ.type = WMA_UPDATE_USERPOS; + msgQ.reserved = 0; + msgQ.bodyptr = pUserPos; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_USERPOS"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pUserPos); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_USERPOS failed, reason=%X"), + retCode); + } + + return retCode; +} + +#endif + +#ifdef WLAN_FEATURE_11W +/** + * lim_send_exclude_unencrypt_ind() - sends WMA_EXCLUDE_UNENCRYPTED_IND to HAL + * @pMac: mac global context + * @excludeUnenc: true: ignore, false: indicate + * @psessionEntry: session context + * + * LIM sends a message to HAL to indicate whether to ignore or indicate the + * unprotected packet error. + * + * Return: status of operation + */ +tSirRetStatus lim_send_exclude_unencrypt_ind(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + tSirWlanExcludeUnencryptParam *pExcludeUnencryptParam; + + pExcludeUnencryptParam = + cdf_mem_malloc(sizeof(tSirWlanExcludeUnencryptParam)); + if (NULL == pExcludeUnencryptParam) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during lim_send_exclude_unencrypt_ind")); + return eSIR_MEM_ALLOC_FAILED; + } + + pExcludeUnencryptParam->excludeUnencrypt = excludeUnenc; + sir_copy_mac_addr(pExcludeUnencryptParam->bssId, psessionEntry->bssId); + + msgQ.type = WMA_EXCLUDE_UNENCRYPTED_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pExcludeUnencryptParam; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_EXCLUDE_UNENCRYPTED_IND"));) + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + cdf_mem_free(pExcludeUnencryptParam); + lim_log(pMac, LOGP, + FL("Posting WMA_EXCLUDE_UNENCRYPTED_IND failed, reason=%X"), + retCode); + } + + return retCode; +} +#endif diff --git a/core/mac/src/pe/lim/lim_send_messages.h b/core/mac/src/pe/lim/lim_send_messages.h new file mode 100644 index 0000000000..d884de7572 --- /dev/null +++ b/core/mac/src/pe/lim/lim_send_messages.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_send_messages.h: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_MESSAGES_H +#define __LIM_SEND_MESSAGES_H + +#include "ani_global.h" +#include "lim_types.h" +#include "wma_if.h" +#include "sir_params.h" +tSirRetStatus lim_send_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod); +tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry); +/* tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, tpUpdateBeaconParams pUpdatedBcnParams); */ +#ifdef WLAN_FEATURE_11AC +tSirRetStatus lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *tempParam, + tpPESession psessionEntry); +tSirRetStatus lim_send_rx_nss_update(tpAniSirGlobal pMac, + tUpdateRxNss *tempParam, + tpPESession psessionEntry); + +uint32_t lim_get_center_channel(tpAniSirGlobal pMac, + uint8_t primarychanNum, + ePhyChanBondState secondaryChanOffset, + uint8_t chanWidth); + +tSirRetStatus lim_set_membership(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry); + +tSirRetStatus lim_set_user_pos(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry); +#endif +#if defined WLAN_FEATURE_VOWIFI +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, + tPowerdBm maxTxPower, + uint8_t peSessionId, + uint8_t is_restart); +#else +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, + uint8_t localPwrConstraint, + uint8_t peSessionId, + uint8_t is_restart); +#endif +tSirRetStatus lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx); +tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMac, + tpSetLinkStateCallback callback, + void *callbackArg); +#ifdef WLAN_FEATURE_VOWIFI_11R +extern tSirRetStatus lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry); +#endif +void lim_set_active_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *plocalEdcaParams, + tpPESession psessionEntry); +#define CAPABILITY_FILTER_MASK 0x73CF +#define ERP_FILTER_MASK 0xF8 +#define EDCA_FILTER_MASK 0xF0 +#define QOS_FILTER_MASK 0xF0 +#define HT_BYTE0_FILTER_MASK 0x0 +#define HT_BYTE2_FILTER_MASK 0xEB +#define HT_BYTE5_FILTER_MASK 0xFD +#define DS_PARAM_CHANNEL_MASK 0x0 +#define VHTOP_CHWIDTH_MASK 0xFC + +tSirRetStatus lim_send_beacon_filter_info(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +#ifdef WLAN_FEATURE_11W +tSirRetStatus lim_send_exclude_unencrypt_ind(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry); +#endif +#endif diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c new file mode 100644 index 0000000000..e27113cd52 --- /dev/null +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -0,0 +1,2370 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_send_sme_rspMessages.cc contains the functions + * for sending SME response/notification messages to applications + * above MAC software. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "cdf_types.h" +#include "wni_api.h" +#include "sir_common.h" +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sys_def.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_session_utils.h" +#include "lim_types.h" +#include "sir_api.h" + +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp); + +/** + * lim_send_sme_rsp() - Send Response to upper layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msg_type_REQ message + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_START_RSP, eWNI_SME_STOP_BSS_RSP + * or eWNI_SME_SWITCH_CHL_RSP messages to applications above MAC + * Software. + * + * Return: None + */ + +void +lim_send_sme_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint16_t sme_transaction_id) +{ + tSirMsgQ msg; + tSirSmeRsp *sme_rsp; + + lim_log(mac_ctx, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + sme_rsp = cdf_mem_malloc(sizeof(tSirSmeRsp)); + if (NULL == sme_rsp) { + /* Buffer not available. Log error */ + CDF_TRACE(CDF_MODULE_ID_PE, LOGP, + FL("call to AllocateMemory failed for eWNI_SME_*_RSP")); + return; + } + + sme_rsp->messageType = msg_type; + sme_rsp->length = sizeof(tSirSmeRsp); + sme_rsp->statusCode = result_code; + + sme_rsp->sessionId = sme_session_id; + sme_rsp->transactionId = sme_transaction_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, sme_session_id, msg.type)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + switch (msg_type) { + case eWNI_SME_STOP_BSS_RSP: + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + NULL, (uint16_t) result_code, 0); + break; + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + + +/** + * lim_send_sme_roc_rsp() - Send Response to SME + * @mac_ctx: Pointer to Global MAC structure + * @status: Resume link status + * @result_code: Result of the ROC request + * @sme_session_id: SME sesson Id + * @scan_id: Scan Identifier + * + * This function is called to send ROC rsp + * message to SME. + * + * Return: None + */ +void +lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id) +{ + tSirMsgQ msg; + struct sir_roc_rsp *sme_rsp; + + lim_log(mac_ctx, LOG1, + FL("Sending message %s with reasonCode %s scanId %d"), + lim_msg_str(msg_type), lim_result_code_str(result_code), + scan_id); + + sme_rsp = cdf_mem_malloc(sizeof(struct sir_roc_rsp)); + if (NULL == sme_rsp) { + CDF_TRACE(CDF_MODULE_ID_PE, LOGP, + FL("call to AllocateMemory failed for eWNI_SME_*_RSP")); + return; + } + + sme_rsp->message_type = msg_type; + sme_rsp->length = sizeof(struct sir_roc_rsp); + sme_rsp->status = result_code; + + sme_rsp->session_id = sme_session_id; + sme_rsp->scan_id = scan_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, sme_session_id, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + +/** + * lim_send_sme_join_reassoc_rsp_after_resume() - Send Response to SME + * @mac_ctx Pointer to Global MAC structure + * @status Resume link status + * @ctx context passed while calling resmune link. + * (join response to be sent) + * + * This function is called to send Join/Reassoc rsp + * message to SME after the resume link. + * + * Return: None + */ +static void lim_send_sme_join_reassoc_rsp_after_resume(tpAniSirGlobal mac_ctx, + CDF_STATUS status, uint32_t *ctx) +{ + tSirMsgQ msg; + tpSirSmeJoinRsp sme_join_rsp = (tpSirSmeJoinRsp) ctx; + + msg.type = sme_join_rsp->messageType; + msg.bodyptr = sme_join_rsp; + msg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, NO_SESSION, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + +/** + * lim_handle_join_rsp_status() - Handle the response. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE Session Info + * @result_code: Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * @sme_join_rsp The received response. + * + * This function will handle both the success and failure status + * of the received response. + * + * Return: None + */ +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp) +{ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *ht_profile; +#endif + if (result_code == eSIR_SME_SUCCESS) { + if (session_entry->beacon != NULL) { + sme_join_rsp->beaconLength = session_entry->bcnLen; + cdf_mem_copy(sme_join_rsp->frames, + session_entry->beacon, + sme_join_rsp->beaconLength); + cdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("Beacon=%d"), + session_entry->bcnLen); +#endif + } + if (session_entry->assocReq != NULL) { + sme_join_rsp->assocReqLength = + session_entry->assocReqLen; + cdf_mem_copy(sme_join_rsp->frames + + session_entry->bcnLen, session_entry->assocReq, + sme_join_rsp->assocReqLength); + cdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, + LOG1, FL("AssocReq=%d"), + session_entry->assocReqLen); +#endif + } + if (session_entry->assocRsp != NULL) { + sme_join_rsp->assocRspLength = + session_entry->assocRspLen; + cdf_mem_copy(sme_join_rsp->frames + + session_entry->bcnLen + + session_entry->assocReqLen, + session_entry->assocRsp, + sme_join_rsp->assocRspLength); + cdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (session_entry->ricData != NULL) { + sme_join_rsp->parsedRicRspLen = + session_entry->RICDataLen; + cdf_mem_copy(sme_join_rsp->frames + + session_entry->bcnLen + + session_entry->assocReqLen + + session_entry->assocRspLen, + session_entry->ricData, + sme_join_rsp->parsedRicRspLen); + cdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + lim_log(mac_ctx, LOG1, FL("RicLength=%d"), + sme_join_rsp->parsedRicRspLen); + } +#endif +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + sme_join_rsp->tspecIeLen = + session_entry->tspecLen; + cdf_mem_copy(sme_join_rsp->frames + + session_entry->bcnLen + + session_entry->assocReqLen + + session_entry->assocRspLen + + session_entry->RICDataLen, + session_entry->tspecIes, + sme_join_rsp->tspecIeLen); + cdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + lim_log(mac_ctx, LOG1, FL("ESE-TspecLen=%d"), + session_entry->tspecLen); + } +#endif + sme_join_rsp->aid = session_entry->limAID; +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(mac_ctx, LOG1, FL("AssocRsp=%d"), + session_entry->assocRspLen); +#endif + sme_join_rsp->vht_channel_width = + session_entry->ch_width; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (session_entry->cc_switch_mode != + CDF_MCC_TO_SCC_SWITCH_DISABLE) { + ht_profile = &sme_join_rsp->HTProfile; + ht_profile->htSupportedChannelWidthSet = + session_entry->htSupportedChannelWidthSet; + ht_profile->htRecommendedTxWidthSet = + session_entry->htRecommendedTxWidthSet; + ht_profile->htSecondaryChannelOffset = + session_entry->htSecondaryChannelOffset; + ht_profile->dot11mode = session_entry->dot11mode; + ht_profile->htCapability = session_entry->htCapability; +#ifdef WLAN_FEATURE_11AC + ht_profile->vhtCapability = + session_entry->vhtCapability; + ht_profile->vhtTxChannelWidthSet = + session_entry->vhtTxChannelWidthSet; + ht_profile->apCenterChan = session_entry->ch_center_freq_seg0; + ht_profile->apChanWidth = session_entry->ch_width; +#endif + } +#endif + } else { + if (session_entry->beacon != NULL) { + cdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + } + if (session_entry->assocReq != NULL) { + cdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; + } + if (session_entry->assocRsp != NULL) { + cdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (session_entry->ricData != NULL) { + cdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + } +#endif +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + cdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + } +#endif + } +} +/** + * lim_send_sme_join_reassoc_rsp() - Send Response to Upper Layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * @prot_status_code: Protocol Status Code + * @session_entry: PE Session Info + * @sme_session_id: SME Session ID + * @sme_transaction_id: SME Transaction ID + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_JOIN_RSP or eWNI_SME_REASSOC_RSP messages to applications + * above MAC Software. + * + * Return: None + */ + +void +lim_send_sme_join_reassoc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry, uint8_t sme_session_id, + uint16_t sme_transaction_id) +{ + tpSirSmeJoinRsp sme_join_rsp; + uint32_t rsp_len; + tpDphHashNode sta_ds = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (msg_type == eWNI_SME_REASSOC_RSP) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); + else + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_log(mac_ctx, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + if (session_entry == NULL) { + rsp_len = sizeof(tSirSmeJoinRsp); + sme_join_rsp = cdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + lim_log(mac_ctx, LOGP, + FL("Mem Alloc fail - JOIN/REASSOC_RSP")); + return; + } + + cdf_mem_set((uint8_t *) sme_join_rsp, rsp_len, 0); + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; + } else { + rsp_len = session_entry->assocReqLen + + session_entry->assocRspLen + session_entry->bcnLen + +#ifdef WLAN_FEATURE_VOWIFI_11R + session_entry->RICDataLen + +#endif +#ifdef FEATURE_WLAN_ESE + session_entry->tspecLen + +#endif + sizeof(tSirSmeJoinRsp) - sizeof(uint8_t); + sme_join_rsp = cdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + lim_log(mac_ctx, LOGP, + FL("MemAlloc fail - JOIN/REASSOC_RSP")); + return; + } + cdf_mem_set((uint8_t *) sme_join_rsp, rsp_len, 0); + if (result_code == eSIR_SME_SUCCESS) { + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("Get Self Sta Entry fail")); + } else { + /* Pass the peer's staId */ + sme_join_rsp->staId = sta_ds->staIndex; + sme_join_rsp->ucastSig = + sta_ds->ucUcastSig; + sme_join_rsp->bcastSig = + sta_ds->ucBcastSig; + sme_join_rsp->timingMeasCap = + sta_ds->timingMeasCap; +#ifdef FEATURE_WLAN_TDLS + sme_join_rsp->tdls_prohibited = + session_entry->tdls_prohibited; + sme_join_rsp->tdls_chan_swit_prohibited = + session_entry->tdls_chan_swit_prohibited; +#endif + } + } + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; +#ifdef WLAN_FEATURE_VOWIFI_11R + sme_join_rsp->parsedRicRspLen = 0; +#endif +#ifdef FEATURE_WLAN_ESE + sme_join_rsp->tspecIeLen = 0; +#endif + + lim_handle_join_rsp_status(mac_ctx, session_entry, result_code, + sme_join_rsp); + } + + sme_join_rsp->messageType = msg_type; + sme_join_rsp->length = (uint16_t) rsp_len; + sme_join_rsp->statusCode = result_code; + sme_join_rsp->protStatusCode = prot_status_code; + + sme_join_rsp->sessionId = sme_session_id; + sme_join_rsp->transactionId = sme_transaction_id; + + lim_send_sme_join_reassoc_rsp_after_resume(mac_ctx, CDF_STATUS_SUCCESS, + (uint32_t *)sme_join_rsp); +} + +/** + * lim_send_sme_start_bss_rsp() + * + ***FUNCTION: + * This function is called to send eWNI_SME_START_BSS_RSP + * message to applications above MAC Software. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates message type + * @param resultCode Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * + * @return None + */ + +void +lim_send_sme_start_bss_rsp(tpAniSirGlobal pMac, + uint16_t msgType, tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + + uint16_t size = 0; + tSirMsgQ mmhMsg; + tSirSmeStartBssRsp *pSirSmeRsp; + uint16_t ieLen; + uint16_t ieOffset, curLen; + + PELOG1(lim_log(pMac, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msgType), lim_result_code_str(resultCode)); + ) + + size = sizeof(tSirSmeStartBssRsp); + + if (psessionEntry == NULL) { + pSirSmeRsp = cdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP")); + return; + } + cdf_mem_set((uint8_t *) pSirSmeRsp, size, 0); + + } else { + /* subtract size of beaconLength + Mac Hdr + Fixed Fields before SSID */ + ieOffset = sizeof(tAniBeaconStruct) + SIR_MAC_B_PR_SSID_OFFSET; + ieLen = psessionEntry->schBeaconOffsetBegin + + psessionEntry->schBeaconOffsetEnd - ieOffset; + /* calculate the memory size to allocate */ + size += ieLen; + + pSirSmeRsp = cdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP")); + + return; + } + cdf_mem_set((uint8_t *) pSirSmeRsp, size, 0); + size = sizeof(tSirSmeStartBssRsp); + if (resultCode == eSIR_SME_SUCCESS) { + + sir_copy_mac_addr(pSirSmeRsp->bssDescription.bssId, + psessionEntry->bssId); + + /* Read beacon interval from session */ + pSirSmeRsp->bssDescription.beaconInterval = + (uint16_t) psessionEntry->beaconParams. + beaconInterval; + pSirSmeRsp->bssType = psessionEntry->bssType; + + if (cfg_get_capability_info + (pMac, &pSirSmeRsp->bssDescription.capabilityInfo, + psessionEntry) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL + ("could not retrieve Capabilities value")); + + lim_get_phy_mode(pMac, + (uint32_t *) &pSirSmeRsp->bssDescription. + nwType, psessionEntry); + + pSirSmeRsp->bssDescription.channelId = + psessionEntry->currentOperChannel; + + curLen = psessionEntry->schBeaconOffsetBegin - ieOffset; + cdf_mem_copy((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields, + psessionEntry->pSchBeaconFrameBegin + + ieOffset, (uint32_t) curLen); + + cdf_mem_copy(((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields) + curLen, + psessionEntry->pSchBeaconFrameEnd, + (uint32_t) psessionEntry-> + schBeaconOffsetEnd); + + /* subtracting size of length indicator itself and size of pointer to ieFields */ + pSirSmeRsp->bssDescription.length = + sizeof(tSirBssDescription) - sizeof(uint16_t) - + sizeof(uint32_t) + ieLen; + /* This is the size of the message, subtracting the size of the pointer to ieFields */ + size += ieLen - sizeof(uint32_t); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (psessionEntry->cc_switch_mode + != CDF_MCC_TO_SCC_SWITCH_DISABLE) { + pSirSmeRsp->HTProfile. + htSupportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pSirSmeRsp->HTProfile.htRecommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + pSirSmeRsp->HTProfile.htSecondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pSirSmeRsp->HTProfile.dot11mode = + psessionEntry->dot11mode; + pSirSmeRsp->HTProfile.htCapability = + psessionEntry->htCapability; +#ifdef WLAN_FEATURE_11AC + pSirSmeRsp->HTProfile.vhtCapability = + psessionEntry->vhtCapability; + pSirSmeRsp->HTProfile.vhtTxChannelWidthSet = + psessionEntry->vhtTxChannelWidthSet; + pSirSmeRsp->HTProfile.apCenterChan = + psessionEntry->ch_center_freq_seg0; + pSirSmeRsp->HTProfile.apChanWidth = + psessionEntry->ch_width; +#endif + } +#endif + } + + } + + pSirSmeRsp->messageType = msgType; + pSirSmeRsp->length = size; + + /* Update SME session Id and transaction Id */ + pSirSmeRsp->sessionId = smesessionId; + pSirSmeRsp->transactionId = smetransactionId; + pSirSmeRsp->statusCode = resultCode; + if (psessionEntry != NULL) + pSirSmeRsp->staId = psessionEntry->staId; /* else it will be always zero smeRsp StaID = 0 */ + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pSirSmeRsp; + mmhMsg.bodyval = 0; + if (psessionEntry == NULL) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_START_BSS_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} /*** end lim_send_sme_start_bss_rsp() ***/ + +#define LIM_MAX_NUM_OF_SCAN_RESULTS_REPORTED 20 +#define LIM_SIZE_OF_EACH_BSS 400 /* this is a rough estimate */ + +/** + * lim_send_sme_scan_rsp() - Send scan response to SME + * @pMac: Pointer to Global MAC structure + * @length: Indicates length of message + * @resultCode: Indicates the result of previously issued + * eWNI_SME_SCAN_REQ message + * @scan_id: scan identifier + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_SCAN_RSP message to applications above MAC + * + * return: None + */ + +void +lim_send_sme_scan_rsp(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint8_t smesessionId, uint16_t smetranscationId, + uint32_t scan_id) +{ + lim_log(pMac, LOG1, + FL("Sending message SME_SCAN_RSP reasonCode %s scanId %d"), + lim_result_code_str(resultCode), scan_id); + lim_post_sme_scan_rsp_message(pMac, resultCode, smesessionId, + smetranscationId, scan_id); +} + +/** + * lim_post_sme_scan_rsp_message() + * + ***FUNCTION: + * This function is called by lim_send_sme_scan_rsp() to send + * eWNI_SME_SCAN_RSP message with failed result code + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param length Indicates length of message + * @param resultCode failed result code + * + * @return None + */ + +void +lim_post_sme_scan_rsp_message(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint8_t smesessionId, + uint16_t smetransactionId, + uint32_t scan_id) +{ + tpSirSmeScanRsp pSirSmeScanRsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOG1, FL("send SME_SCAN_RSP (reasonCode %s)."), + lim_result_code_str(resultCode)); + + pSirSmeScanRsp = cdf_mem_malloc(sizeof(tSirSmeScanRsp)); + if (NULL == pSirSmeScanRsp) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_SCAN_RSP")); + return; + } + cdf_mem_set((void *)pSirSmeScanRsp, sizeof(tSirSmeScanRsp), 0); + + pSirSmeScanRsp->messageType = eWNI_SME_SCAN_RSP; + pSirSmeScanRsp->statusCode = resultCode; + + /*Update SME session Id and transaction Id */ + pSirSmeScanRsp->sessionId = smesessionId; + pSirSmeScanRsp->transcationId = smetransactionId; + pSirSmeScanRsp->scan_id = scan_id; + + mmhMsg.type = eWNI_SME_SCAN_RSP; + mmhMsg.bodyptr = pSirSmeScanRsp; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SCAN_RSP_EVENT, NULL, + (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; + +} /*** lim_post_sme_scan_rsp_message ***/ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * lim_send_sme_oem_data_rsp() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_OEM_DATA_RSP message to applications above MAC + * Software. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf Indicates the mlm message + * @param resultCode Indicates the result of previously issued + * eWNI_SME_OEM_DATA_RSP message + * + * @return None + */ + +void lim_send_sme_oem_data_rsp(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tSirResultCodes resultCode) +{ + tSirMsgQ mmhMsg; + tSirOemDataRsp *pSirSmeOemDataRsp = NULL; + tLimMlmOemDataRsp *pMlmOemDataRsp = NULL; + uint16_t msgLength; + + /* get the pointer to the mlm message */ + pMlmOemDataRsp = (tLimMlmOemDataRsp *) (pMsgBuf); + + msgLength = sizeof(tSirOemDataRsp); + + /* now allocate memory for the char buffer */ + pSirSmeOemDataRsp = cdf_mem_malloc(msgLength); + if (NULL == pSirSmeOemDataRsp) { + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for pSirSmeOemDataRsp")); + return; + } +#if defined (ANI_LITTLE_BYTE_ENDIAN) + sir_store_u16_n((uint8_t *) &pSirSmeOemDataRsp->length, msgLength); + sir_store_u16_n((uint8_t *) &pSirSmeOemDataRsp->messageType, + eWNI_SME_OEM_DATA_RSP); +#else + pSirSmeOemDataRsp->length = msgLength; + pSirSmeOemDataRsp->messageType = eWNI_SME_OEM_DATA_RSP; +#endif + + cdf_mem_copy(pSirSmeOemDataRsp->oemDataRsp, pMlmOemDataRsp->oemDataRsp, + OEM_DATA_RSP_SIZE); + + /* Now free the memory from MLM Rsp Message */ + cdf_mem_free(pMlmOemDataRsp); + + mmhMsg.type = eWNI_SME_OEM_DATA_RSP; + mmhMsg.bodyptr = pSirSmeOemDataRsp; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} /*** lim_send_sme_oem_data_rsp ***/ + +#endif + +void lim_send_sme_disassoc_deauth_ntf(tpAniSirGlobal pMac, + CDF_STATUS status, uint32_t *pCtx) +{ + tSirMsgQ mmhMsg; + tSirMsgQ *pMsg = (tSirMsgQ *) pCtx; + + mmhMsg.type = pMsg->type; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/** + * lim_send_sme_disassoc_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DISASSOC_CNF, + * or eWNI_SME_DISASSOC_IND to host depending on + * disassociation trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * disassociate was initiated + * @param reasonCode Indicates the reason for Disassociation + * @param disassocTrigger Indicates the trigger for Disassociation + * @param aid Indicates the STAID. This parameter is + * present only on AP. + * + * @return None + */ +void +lim_send_sme_disassoc_ntf(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, + uint16_t disassocTrigger, + uint16_t aid, + uint8_t smesessionId, + uint16_t smetransactionId, tpPESession psessionEntry) +{ + + uint8_t *pBuf; + tSirSmeDisassocRsp *pSirSmeDisassocRsp; + tSirSmeDisassocInd *pSirSmeDisassocInd; + uint32_t *pMsg; + bool failure = false; + + lim_log(pMac, LOG1, FL("Disassoc Ntf with trigger : %d reasonCode: %d"), + disassocTrigger, reasonCode); + + switch (disassocTrigger) { + case eLIM_PEER_ENTITY_DISASSOC: + if (reasonCode != eSIR_SME_STA_NOT_ASSOCIATED) { + failure = true; + goto error; + } + + case eLIM_HOST_DISASSOC: + /** + * Disassociation response due to + * host triggered disassociation + */ + + pSirSmeDisassocRsp = cdf_mem_malloc(sizeof(tSirSmeDisassocRsp)); + if (NULL == pSirSmeDisassocRsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("Memory allocation failed")); + failure = true; + goto error; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DISASSOC_RSP with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocRsp->messageType = eWNI_SME_DISASSOC_RSP; + pSirSmeDisassocRsp->length = sizeof(tSirSmeDisassocRsp); + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDisassocRsp->sessionId; + *pBuf = smesessionId; + pBuf++; + + /* transactionId */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* statusCode */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* peerMacAddr */ + cdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* Clear Station Stats */ + /* for sta, it is always 1, IBSS is handled at halInitSta */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + psessionEntry, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocRsp; + break; + + default: + /** + * Disassociation indication due to Disassociation + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDisassocInd = cdf_mem_malloc(sizeof(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + /* Log error */ + lim_log(pMac, LOGP, FL("Memory allocation failed")); + failure = true; + goto error; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DISASSOC_IND with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + /* Update SME session Id and Transaction Id */ + pSirSmeDisassocInd->sessionId = smesessionId; + pSirSmeDisassocInd->transactionId = smetransactionId; + pSirSmeDisassocInd->reasonCode = reasonCode; + pBuf = (uint8_t *) &pSirSmeDisassocInd->statusCode; + + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + cdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + cdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, + psessionEntry, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocInd; + + break; + } + +error: + /* Delete the PE session Created */ + if ((psessionEntry != NULL) && + (LIM_IS_STA_ROLE(psessionEntry) || + LIM_IS_BT_AMP_STA_ROLE(psessionEntry))) { + pe_delete_session(pMac, psessionEntry); + } + + if (false == failure) + lim_send_sme_disassoc_deauth_ntf(pMac, CDF_STATUS_SUCCESS, + (uint32_t *) pMsg); +} /*** end lim_send_sme_disassoc_ntf() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_disassoc_ind() - sends SME_DISASSOC_IND + + After receiving disassociation frame from peer entity, this + function sends a eWNI_SME_DISASSOC_IND to SME with a specific + reason code. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_disassoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeDisassocInd *pSirSmeDisassocInd; + + pSirSmeDisassocInd = cdf_mem_malloc(sizeof(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_DISASSOC_IND")); + return; + } + + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + pSirSmeDisassocInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDisassocInd->transactionId = psessionEntry->transactionId; + pSirSmeDisassocInd->statusCode = pStaDs->mlmStaContext.disassocReason; + pSirSmeDisassocInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + cdf_mem_copy(pSirSmeDisassocInd->bssId, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + cdf_mem_copy(pSirSmeDisassocInd->peerMacAddr, pStaDs->staAddr, + sizeof(tSirMacAddr)); + + pSirSmeDisassocInd->staId = pStaDs->staIndex; + + mmhMsg.type = eWNI_SME_DISASSOC_IND; + mmhMsg.bodyptr = pSirSmeDisassocInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, psessionEntry, + 0, (uint16_t) pStaDs->mlmStaContext.disassocReason); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} /*** end lim_send_sme_disassoc_ind() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_deauth_ind() - sends SME_DEAUTH_IND + + After receiving deauthentication frame from peer entity, this + function sends a eWNI_SME_DEAUTH_IND to SME with a specific + reason code. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_deauth_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeDeauthInd *pSirSmeDeauthInd; + + pSirSmeDeauthInd = cdf_mem_malloc(sizeof(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_DEAUTH_IND ")); + return; + } + + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + + pSirSmeDeauthInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDeauthInd->transactionId = psessionEntry->transactionId; + if (eSIR_INFRA_AP_MODE == psessionEntry->bssType) { + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.cleanupTrigger; + } else { + /* Need to indicatet he reascon code over the air */ + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.disassocReason; + } + /* BSSID */ + cdf_mem_copy(pSirSmeDeauthInd->bssId, psessionEntry->bssId, + sizeof(tSirMacAddr)); + /* peerMacAddr */ + cdf_mem_copy(pSirSmeDeauthInd->peerMacAddr, pStaDs->staAddr, + sizeof(tSirMacAddr)); + pSirSmeDeauthInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + pSirSmeDeauthInd->staId = pStaDs->staIndex; + + mmhMsg.type = eWNI_SME_DEAUTH_IND; + mmhMsg.bodyptr = pSirSmeDeauthInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, psessionEntry, + 0, pStaDs->mlmStaContext.cleanupTrigger); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_deauth_ind() ***/ + +#ifdef FEATURE_WLAN_TDLS +/** + * lim_send_sme_tdls_del_sta_ind() + * + ***FUNCTION: + * This function is called to send the TDLS STA context deletion to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param pStaDs - Pointer to internal STA Datastructure + * @param psessionEntry - Pointer to the session entry + * @param reasonCode - Reason for TDLS sta deletion + * @return None + */ +void +lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, uint16_t reasonCode) +{ + tSirMsgQ mmhMsg; + tSirTdlsDelStaInd *pSirTdlsDelStaInd; + + pSirTdlsDelStaInd = cdf_mem_malloc(sizeof(tSirTdlsDelStaInd)); + if (NULL == pSirTdlsDelStaInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_TDLS_DEL_STA_IND ")); + return; + } + /* messageType */ + pSirTdlsDelStaInd->messageType = eWNI_SME_TDLS_DEL_STA_IND; + pSirTdlsDelStaInd->length = sizeof(tSirTdlsDelStaInd); + + /* sessionId */ + pSirTdlsDelStaInd->sessionId = psessionEntry->smeSessionId; + + /* peerMacAddr */ + cdf_mem_copy(pSirTdlsDelStaInd->peerMac, pStaDs->staAddr, + sizeof(tSirMacAddr)); + + /* staId */ + lim_copy_u16((uint8_t *) (&pSirTdlsDelStaInd->staId), + (uint16_t) pStaDs->staIndex); + + /* reasonCode */ + lim_copy_u16((uint8_t *) (&pSirTdlsDelStaInd->reasonCode), reasonCode); + + mmhMsg.type = eWNI_SME_TDLS_DEL_STA_IND; + mmhMsg.bodyptr = pSirTdlsDelStaInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_del_sta_ind() ***/ + +/** + * lim_send_sme_tdls_delete_all_peer_ind() + * + ***FUNCTION: + * This function is called to send the eWNI_SME_TDLS_DEL_ALL_PEER_IND + * message to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param psessionEntry - Pointer to the session entry + * @return None + */ +void +lim_send_sme_tdls_delete_all_peer_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirTdlsDelAllPeerInd *pSirTdlsDelAllPeerInd; + + pSirTdlsDelAllPeerInd = cdf_mem_malloc(sizeof(tSirTdlsDelAllPeerInd)); + if (NULL == pSirTdlsDelAllPeerInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_TDLS_DEL_ALL_PEER_IND")); + return; + } + /* messageType */ + pSirTdlsDelAllPeerInd->messageType = eWNI_SME_TDLS_DEL_ALL_PEER_IND; + pSirTdlsDelAllPeerInd->length = sizeof(tSirTdlsDelAllPeerInd); + + /* sessionId */ + pSirTdlsDelAllPeerInd->sessionId = psessionEntry->smeSessionId; + + mmhMsg.type = eWNI_SME_TDLS_DEL_ALL_PEER_IND; + mmhMsg.bodyptr = pSirTdlsDelAllPeerInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +/** + * lim_send_sme_mgmt_tx_completion() + * + ***FUNCTION: + * This function is called to send the eWNI_SME_MGMT_FRM_TX_COMPLETION_IND + * message to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param psessionEntry - Pointer to the session entry + * @param txCompleteStatus - TX Complete Status of Mgmt Frames + * @return None + */ +void +lim_send_sme_mgmt_tx_completion(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint32_t txCompleteStatus) +{ + tSirMsgQ mmhMsg; + tSirMgmtTxCompletionInd *pSirMgmtTxCompletionInd; + + pSirMgmtTxCompletionInd = + cdf_mem_malloc(sizeof(tSirMgmtTxCompletionInd)); + if (NULL == pSirMgmtTxCompletionInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_MGMT_FRM_TX_COMPLETION_IND")); + return; + } + /* messageType */ + pSirMgmtTxCompletionInd->messageType = + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + pSirMgmtTxCompletionInd->length = sizeof(tSirMgmtTxCompletionInd); + + /* sessionId */ + pSirMgmtTxCompletionInd->sessionId = psessionEntry->smeSessionId; + + pSirMgmtTxCompletionInd->txCompleteStatus = txCompleteStatus; + + mmhMsg.type = eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + mmhMsg.bodyptr = pSirMgmtTxCompletionInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +void lim_send_sme_tdls_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *events) +{ + tSirMsgQ mmhMsg; + + switch (msgType) { + case SIR_HAL_TDLS_SHOULD_DISCOVER: + mmhMsg.type = eWNI_SME_TDLS_SHOULD_DISCOVER; + break; + case SIR_HAL_TDLS_SHOULD_TEARDOWN: + mmhMsg.type = eWNI_SME_TDLS_SHOULD_TEARDOWN; + break; + case SIR_HAL_TDLS_PEER_DISCONNECTED: + mmhMsg.type = eWNI_SME_TDLS_PEER_DISCONNECTED; + break; + } + + mmhMsg.bodyptr = events; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif /* FEATURE_WLAN_TDLS */ + +/** + * lim_send_sme_deauth_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DEAUTH_CNF or + * eWNI_SME_DEAUTH_IND to host depending on deauthentication trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * deauthentication was initiated + * @param reasonCode Indicates the reason for Deauthetication + * @param deauthTrigger Indicates the trigger for Deauthetication + * @param aid Indicates the STAID. This parameter is present + * only on AP. + * + * @return None + */ +void +lim_send_sme_deauth_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, uint16_t deauthTrigger, + uint16_t aid, uint8_t smesessionId, + uint16_t smetransactionId) +{ + uint8_t *pBuf; + tSirSmeDeauthRsp *pSirSmeDeauthRsp; + tSirSmeDeauthInd *pSirSmeDeauthInd; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t *pMsg; + + psessionEntry = pe_find_session_by_bssid(pMac, peerMacAddr, &sessionId); + switch (deauthTrigger) { + case eLIM_PEER_ENTITY_DEAUTH: + return; + + case eLIM_HOST_DEAUTH: + /** + * Deauthentication response to host triggered + * deauthentication. + */ + pSirSmeDeauthRsp = cdf_mem_malloc(sizeof(tSirSmeDeauthRsp)); + if (NULL == pSirSmeDeauthRsp) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_DEAUTH_RSP")); + + return; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DEAUTH_RSP with " + "retCode: %d for" MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthRsp->messageType = eWNI_SME_DEAUTH_RSP; + pSirSmeDeauthRsp->length = sizeof(tSirSmeDeauthRsp); + pSirSmeDeauthRsp->statusCode = reasonCode; + pSirSmeDeauthRsp->sessionId = smesessionId; + pSirSmeDeauthRsp->transactionId = smetransactionId; + + pBuf = (uint8_t *) pSirSmeDeauthRsp->peerMacAddr; + cdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + psessionEntry, 0, (uint16_t) reasonCode); +#endif + pMsg = (uint32_t *) pSirSmeDeauthRsp; + + break; + + default: + /** + * Deauthentication indication due to Deauthentication + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDeauthInd = cdf_mem_malloc(sizeof(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_DEAUTH_Ind")); + + return; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DEAUTH_IND with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + pSirSmeDeauthInd->reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDeauthInd->sessionId; + *pBuf++ = smesessionId; + + /* transaction ID */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* status code */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* bssId */ + cdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* peerMacAddr */ + cdf_mem_copy(pSirSmeDeauthInd->peerMacAddr, peerMacAddr, + sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, + psessionEntry, 0, (uint16_t) reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pMsg = (uint32_t *) pSirSmeDeauthInd; + + break; + } + + /*Delete the PE session created */ + if (psessionEntry != NULL) { + pe_delete_session(pMac, psessionEntry); + } + + lim_send_sme_disassoc_deauth_ntf(pMac, CDF_STATUS_SUCCESS, + (uint32_t *) pMsg); + +} /*** end lim_send_sme_deauth_ntf() ***/ + +/** + * lim_send_sme_wm_status_change_ntf() - Send Notification + * @mac_ctx: Global MAC Context + * @status_change_code: Indicates the change in the wireless medium. + * @status_change_info: Indicates the information associated with + * change in the wireless medium. + * @info_len: Indicates the length of status change information + * being sent. + * @session_id SessionID + * + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_WM_STATUS_CHANGE_NTF message to host. + * + * Return: None + */ +void +lim_send_sme_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeStatusChangeCode status_change_code, + uint32_t *status_change_info, uint16_t info_len, uint8_t session_id) +{ + tSirMsgQ msg; + tSirSmeWmStatusChangeNtf *wm_status_change_ntf; + + wm_status_change_ntf = cdf_mem_malloc(sizeof(tSirSmeWmStatusChangeNtf)); + if (NULL == wm_status_change_ntf) { + lim_log(mac_ctx, LOGE, + FL("Mem Alloc failed - eWNI_SME_WM_STATUS_CHANGE_NTF")); + return; + } + + msg.type = eWNI_SME_WM_STATUS_CHANGE_NTF; + msg.bodyval = 0; + msg.bodyptr = wm_status_change_ntf; + + switch (status_change_code) { + case eSIR_SME_RADAR_DETECTED: + break; + default: + wm_status_change_ntf->messageType = + eWNI_SME_WM_STATUS_CHANGE_NTF; + wm_status_change_ntf->statusChangeCode = status_change_code; + wm_status_change_ntf->length = sizeof(tSirSmeWmStatusChangeNtf); + wm_status_change_ntf->sessionId = session_id; + if (sizeof(wm_status_change_ntf->statusChangeInfo) >= + info_len) { + cdf_mem_copy( + (uint8_t *) &wm_status_change_ntf->statusChangeInfo, + (uint8_t *) status_change_info, info_len); + } + lim_log(mac_ctx, LOGE, + FL("**---** StatusChg: code 0x%x, length %d **---**"), + status_change_code, info_len); + break; + } + + MTRACE(mac_trace_msg_tx(mac_ctx, session_id, msg.type)); + if (eSIR_SUCCESS != lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT)) { + cdf_mem_free(wm_status_change_ntf); + lim_log(mac_ctx, LOGP, + FL("lim_sys_process_mmh_msg_api failed")); + } + +} /*** end lim_send_sme_wm_status_change_ntf() ***/ + +/** + * lim_send_sme_set_context_rsp() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_SETCONTEXT_RSP message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param peerMacAddr Indicates the peer MAC addr to which + * setContext was performed + * @param aid Indicates the aid corresponding to the peer MAC + * address + * @param resultCode Indicates the result of previously issued + * eWNI_SME_SETCONTEXT_RSP message + * + * @return None + */ +void +lim_send_sme_set_context_rsp(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, uint16_t aid, + tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + + uint8_t *pBuf; + tSirMsgQ mmhMsg; + tSirSmeSetContextRsp *pSirSmeSetContextRsp; + + pSirSmeSetContextRsp = cdf_mem_malloc(sizeof(tSirSmeSetContextRsp)); + if (NULL == pSirSmeSetContextRsp) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for SmeSetContextRsp")); + + return; + } + + pSirSmeSetContextRsp->messageType = eWNI_SME_SETCONTEXT_RSP; + pSirSmeSetContextRsp->length = sizeof(tSirSmeSetContextRsp); + pSirSmeSetContextRsp->statusCode = resultCode; + + pBuf = pSirSmeSetContextRsp->peerMacAddr; + + cdf_mem_copy(pBuf, (uint8_t *) peerMacAddr, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* Update SME session and transaction Id */ + pSirSmeSetContextRsp->sessionId = smesessionId; + pSirSmeSetContextRsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_SETCONTEXT_RSP; + mmhMsg.bodyptr = pSirSmeSetContextRsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, mmhMsg.type)); + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} /*** end lim_send_sme_set_context_rsp() ***/ + +/** + * lim_send_sme_neighbor_bss_ind() + * + ***FUNCTION: + * This function is called by lim_lookup_nadd_hash_entry() to send + * eWNI_SME_NEIGHBOR_BSS_IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_NEIGHBOR_BSS_IND to + * host upon detecting new BSS during background scanning if CFG + * option is enabled for sending such indication + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void +lim_send_sme_neighbor_bss_ind(tpAniSirGlobal pMac, tLimScanResultNode *pBssDescr) +{ + tSirMsgQ msgQ; + uint32_t val; + tSirSmeNeighborBssInd *pNewBssInd; + + if ((pMac->lim.gLimSmeState != eLIM_SME_LINK_EST_WT_SCAN_STATE) || + ((pMac->lim.gLimSmeState == eLIM_SME_LINK_EST_WT_SCAN_STATE) && + pMac->lim.gLimRspReqd)) { + /* LIM is not in background scan state OR */ + /* current scan is initiated by HDD. */ + /* No need to send new BSS indication to HDD */ + return; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_NEW_BSS_FOUND_IND, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not get NEIGHBOR_BSS_IND from CFG")); + + return; + } + + if (val == 0) + return; + + /** + * Need to indicate new BSSs found during + * background scanning to host. + * Allocate buffer for sending indication. + * Length of buffer is length of BSS description + * and length of header itself + */ + val = pBssDescr->bssDescription.length + sizeof(uint16_t) + + sizeof(uint32_t) + sizeof(uint8_t); + pNewBssInd = cdf_mem_malloc(val); + if (NULL == pNewBssInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_NEIGHBOR_BSS_IND")); + + return; + } + + pNewBssInd->messageType = eWNI_SME_NEIGHBOR_BSS_IND; + pNewBssInd->length = (uint16_t) val; + pNewBssInd->sessionId = 0; + + cdf_mem_copy((uint8_t *) pNewBssInd->bssDescription, + (uint8_t *) &pBssDescr->bssDescription, + pBssDescr->bssDescription.length + sizeof(uint16_t)); + + msgQ.type = eWNI_SME_NEIGHBOR_BSS_IND; + msgQ.bodyptr = pNewBssInd; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT); +} /*** end lim_send_sme_neighbor_bss_ind() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_addts_rsp() - sends SME ADDTS RSP + \ This function sends a eWNI_SME_ADDTS_RSP to SME. + \ SME only looks at rc and tspec field. + \param pMac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of SME_ADD_TS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId) +{ + tpSirAddtsRsp rsp; + tSirMsgQ mmhMsg; + + if (!rspReqd) + return; + + rsp = cdf_mem_malloc(sizeof(tSirAddtsRsp)); + if (NULL == rsp) { + lim_log(pMac, LOGP, FL("AllocateMemory failed for ADDTS_RSP")); + return; + } + + cdf_mem_set((uint8_t *) rsp, sizeof(*rsp), 0); + rsp->messageType = eWNI_SME_ADDTS_RSP; + rsp->rc = status; + rsp->rsp.status = (enum eSirMacStatusCodes)status; + rsp->rsp.tspec = tspec; + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_ADDTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_RSP_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +void +lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, uint32_t status, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + tpSirDeltsRsp rsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOGW, "SendSmeDeltsRsp (aid %d, tsid %d, up %d) status %d", + delts->aid, + delts->req.tsinfo.traffic.tsid, + delts->req.tsinfo.traffic.userPrio, status); + if (!delts->rspReqd) + return; + + rsp = cdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (NULL == rsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("AllocateMemory failed for DELTS_RSP")); + return; + } + cdf_mem_set((uint8_t *) rsp, sizeof(*rsp), 0); + + if (psessionEntry != NULL) { + + rsp->aid = delts->aid; + cdf_mem_copy((uint8_t *) &rsp->macAddr[0], + (uint8_t *) &delts->macAddr[0], 6); + cdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) &delts->req, + sizeof(tSirDeltsReqInfo)); + } + + rsp->messageType = eWNI_SME_DELTS_RSP; + rsp->rc = status; + + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_DELTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_RSP_EVENT, psessionEntry, + (uint16_t) status, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +void +lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, uint16_t aid, + tpPESession psessionEntry) +{ + tpSirDeltsRsp rsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOGW, "SendSmeDeltsInd (aid %d, tsid %d, up %d)", + aid, delts->tsinfo.traffic.tsid, delts->tsinfo.traffic.userPrio); + + rsp = cdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (NULL == rsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("AllocateMemory failed for DELTS_IND")); + return; + } + cdf_mem_set((uint8_t *) rsp, sizeof(*rsp), 0); + + rsp->messageType = eWNI_SME_DELTS_IND; + rsp->rc = eSIR_SUCCESS; + rsp->aid = aid; + cdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) delts, sizeof(*delts)); + + /* Update SME session Id and SME transaction Id */ + + rsp->sessionId = psessionEntry->smeSessionId; + rsp->transactionId = psessionEntry->transactionId; + + mmhMsg.type = eWNI_SME_DELTS_IND; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_IND_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/** + * lim_send_sme_pe_statistics_rsp() + * + ***FUNCTION: + * This function is called to send 802.11 statistics response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request for statistics. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param p80211Stats Statistics sent in response + * @param resultCode TODO: + * + * + * @return none + */ + +void +lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgType, void *stats) +{ + tSirMsgQ mmhMsg; + uint8_t sessionId; + tAniGetPEStatsRsp *pPeStats = (tAniGetPEStatsRsp *) stats; + tpPESession pPeSessionEntry; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } + + pPeStats->msgType = eWNI_SME_GET_STATISTICS_RSP; + + /* msgType should be WMA_GET_STATISTICS_RSP */ + mmhMsg.type = eWNI_SME_GET_STATISTICS_RSP; + + mmhMsg.bodyptr = stats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; + +} /*** end lim_send_sme_pe_statistics_rsp() ***/ + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * lim_send_sme_pe_ese_tsm_rsp() + * + ***FUNCTION: + * This function is called to send tsm stats response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request to get tsm stats. + * + ***PARAMS: + * @param pMac - Pointer to global pMac structure + * @param pStats - Pointer to TSM Stats + * + * @return none + */ + +void lim_send_sme_pe_ese_tsm_rsp(tpAniSirGlobal pMac, tAniGetTsmStatsRsp *pStats) +{ + tSirMsgQ mmhMsg; + uint8_t sessionId; + tAniGetTsmStatsRsp *pPeStats = (tAniGetTsmStatsRsp *) pStats; + tpPESession pPeSessionEntry = NULL; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } else { + PELOGE(lim_log + (pMac, LOGE, FL("Session not found for the Sta id(%d)"), + pPeStats->staId); + ) + return; + } + + pPeStats->msgType = eWNI_SME_GET_TSM_STATS_RSP; + pPeStats->tsmMetrics.RoamingCount + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingCount; + pPeStats->tsmMetrics.RoamingDly + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly; + + mmhMsg.type = eWNI_SME_GET_TSM_STATS_RSP; + mmhMsg.bodyptr = pStats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} /*** end lim_send_sme_pe_ese_tsm_rsp() ***/ + +#endif /* FEATURE_WLAN_ESE) && FEATURE_WLAN_ESE_UPLOAD */ + +void +lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint16_t staIndex, + uint8_t ucastIdx, + uint8_t bcastIdx, + uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, uint8_t sessionId) +{ + tSirMsgQ mmhMsg; + tSmeIbssPeerInd *pNewPeerInd; + + pNewPeerInd = cdf_mem_malloc(sizeof(tSmeIbssPeerInd) + beaconLen); + if (NULL == pNewPeerInd) { + PELOGE(lim_log(pMac, LOGE, FL("Failed to allocate memory"));) + return; + } + + cdf_mem_set((void *)pNewPeerInd, (sizeof(tSmeIbssPeerInd) + beaconLen), + 0); + + cdf_mem_copy((uint8_t *) pNewPeerInd->peerAddr, + peerMacAddr, sizeof(tSirMacAddr)); + pNewPeerInd->staId = staIndex; + pNewPeerInd->ucastSig = ucastIdx; + pNewPeerInd->bcastSig = bcastIdx; + pNewPeerInd->mesgLen = sizeof(tSmeIbssPeerInd) + beaconLen; + pNewPeerInd->mesgType = msgType; + pNewPeerInd->sessionId = sessionId; + + if (beacon != NULL) { + cdf_mem_copy((void *)((uint8_t *) pNewPeerInd + + sizeof(tSmeIbssPeerInd)), (void *)beacon, + beaconLen); + } + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pNewPeerInd; + MTRACE(mac_trace_msg_tx(pMac, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} + +/** + * lim_handle_csa_offload_msg() - Handle CSA offload message + * @mac_ctx: pointer to global adapter context + * @msg: Message pointer. + * + * Return: None + */ +void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + tpPESession session_entry; + tSirMsgQ mmh_msg; + tpCSAOffloadParams csa_params = (tpCSAOffloadParams) (msg->bodyptr); + tpSmeCsaOffloadInd csa_offload_ind; + tpDphHashNode sta_ds = NULL; + uint8_t session_id; + uint16_t aid = 0; + tLimWiderBWChannelSwitchInfo *chnl_switch_info = NULL; + + if (!csa_params) { + lim_log(mac_ctx, LOGE, FL("limMsgQ body ptr is NULL")); + return; + } + + session_entry = + pe_find_session_by_bssid(mac_ctx, + csa_params->bssId, &session_id); + if (!session_entry) { + lim_log(mac_ctx, LOGE, + FL("Session does not exist")); + goto err; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, session_entry->bssId, &aid, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("sta_ds does not exist")); + goto err; + } + + if (LIM_IS_STA_ROLE(session_entry)) { + session_entry->gLimChannelSwitch.switchMode = + csa_params->switchmode; + /* timer already started by firmware, switch immediately */ + session_entry->gLimChannelSwitch.switchCount = 0; + session_entry->gLimChannelSwitch.primaryChannel = + csa_params->channel; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + session_entry->gLimChannelSwitch.ch_width = CH_WIDTH_20MHZ; + + if (session_entry->vhtCapability && + session_entry->htSupportedChannelWidthSet) { + chnl_switch_info = + &session_entry->gLimWiderBWChannelSwitch; + if (csa_params->ies_present_flag & lim_wbw_ie_present) { + chnl_switch_info->newChanWidth = + csa_params->new_ch_width; + chnl_switch_info->newCenterChanFreq0 = + csa_params->new_ch_freq_seg1; + chnl_switch_info->newCenterChanFreq1 = + csa_params->new_ch_freq_seg2; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + session_entry->gLimChannelSwitch.ch_width = + csa_params->new_ch_width + 1; + } + } else if (session_entry->htSupportedChannelWidthSet) { + if (csa_params->sec_chan_offset) { + session_entry->gLimChannelSwitch.ch_width = + CH_WIDTH_40MHZ; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + } else { + session_entry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + session_entry->htRecommendedTxWidthSet = + session_entry->htSupportedChannelWidthSet; + } + } + lim_log(mac_ctx, LOG1, FL("new ch width = %d"), + session_entry->gLimChannelSwitch.ch_width); + + lim_prepare_for11h_channel_switch(mac_ctx, session_entry); + csa_offload_ind = cdf_mem_malloc(sizeof(tSmeCsaOffloadInd)); + if (NULL == csa_offload_ind) { + lim_log(mac_ctx, LOGE, + FL("memalloc fail eWNI_SME_CSA_OFFLOAD_EVENT")); + goto err; + } + + cdf_mem_set(csa_offload_ind, sizeof(tSmeCsaOffloadInd), 0); + csa_offload_ind->mesgType = eWNI_SME_CSA_OFFLOAD_EVENT; + csa_offload_ind->mesgLen = sizeof(tSmeCsaOffloadInd); + cdf_mem_copy(csa_offload_ind->bssId, session_entry->bssId, + sizeof(tSirMacAddr)); + mmh_msg.type = eWNI_SME_CSA_OFFLOAD_EVENT; + mmh_msg.bodyptr = csa_offload_ind; + mmh_msg.bodyval = 0; + lim_log(mac_ctx, LOG1, + FL("Sending eWNI_SME_CSA_OFFLOAD_EVENT to SME. ")); + MTRACE(mac_trace_msg_tx + (mac_ctx, session_entry->peSessionId, mmh_msg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, session_entry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); + } + +err: + cdf_mem_free(csa_params); +} + +/*-------------------------------------------------------------------------- + \brief pe_delete_session() - Handle the Delete BSS Response from HAL. + + \param pMac - pointer to global adapter context + \param sessionId - Message pointer. + + \sa + --------------------------------------------------------------------------*/ + +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ MsgQ) +{ + tpPESession psessionEntry; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) (MsgQ->bodyptr); + + psessionEntry = + pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID %d"), + pDelBss->sessionId); + return; + } + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + lim_ibss_del_bss_rsp(pMac, MsgQ->bodyptr, psessionEntry); + } else if (LIM_IS_UNKNOWN_ROLE(psessionEntry)) { + lim_process_sme_del_bss_rsp(pMac, MsgQ->bodyval, psessionEntry); + } + + else + lim_process_mlm_del_bss_rsp(pMac, MsgQ, psessionEntry); + +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/** ----------------------------------------------------------------- + \brief lim_send_sme_aggr_qos_rsp() - sends SME FT AGGR QOS RSP + \ This function sends a eWNI_SME_FT_AGGR_QOS_RSP to SME. + \ SME only looks at rc and tspec field. + \param pMac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of eWNI_SME_FT_AGGR_QOS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_aggr_qos_rsp(tpAniSirGlobal pMac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId) +{ + tSirMsgQ mmhMsg; + + mmhMsg.type = eWNI_SME_FT_AGGR_QOS_RSP; + mmhMsg.bodyptr = aggrQosRsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} +#endif + +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId) +{ + tSirMsgQ mmhMsg; + tSmeMaxAssocInd *pSmeMaxAssocInd; + + pSmeMaxAssocInd = cdf_mem_malloc(sizeof(tSmeMaxAssocInd)); + if (NULL == pSmeMaxAssocInd) { + PELOGE(lim_log(pMac, LOGE, FL("Failed to allocate memory"));) + return; + } + cdf_mem_set((void *)pSmeMaxAssocInd, sizeof(tSmeMaxAssocInd), 0); + cdf_mem_copy((uint8_t *) pSmeMaxAssocInd->peerMac, + (uint8_t *) peerMacAddr, sizeof(tSirMacAddr)); + pSmeMaxAssocInd->mesgType = eWNI_SME_MAX_ASSOC_EXCEEDED; + pSmeMaxAssocInd->mesgLen = sizeof(tSmeMaxAssocInd); + pSmeMaxAssocInd->sessionId = smesessionId; + mmhMsg.type = pSmeMaxAssocInd->mesgType; + mmhMsg.bodyptr = pSmeMaxAssocInd; + PELOG1(lim_log(pMac, LOG1, FL("msgType %s peerMacAddr " MAC_ADDRESS_STR + " sme session id %d"), + "eWNI_SME_MAX_ASSOC_EXCEEDED", + MAC_ADDR_ARRAY(peerMacAddr)); + ) + MTRACE(mac_trace_msg_tx(pMac, smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_dfs_event_notify() - sends + eWNI_SME_DFS_RADAR_FOUND + After receiving WMI_PHYERR_EVENTID indication frame from FW, this + function sends a eWNI_SME_DFS_RADAR_FOUND to SME to notify + that a RADAR is found on current operating channel and SAP- + has to move to a new channel. + \param pMac - global mac structure + \param msgType - message type received from lower layer + \param event - event data received from lower layer + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_dfs_event_notify(tpAniSirGlobal pMac, uint16_t msgType, void *event) +{ + tSirMsgQ mmhMsg; + mmhMsg.type = eWNI_SME_DFS_RADAR_FOUND; + mmhMsg.bodyptr = event; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +/*-------------------------------------------------------------------------- + \brief lim_send_dfs_chan_sw_ie_update() + This timer handler updates the channel switch IE in beacon template + + \param pMac - pointer to global adapter context + \return - channel to scan from valid session else zero. + \sa + --------------------------------------------------------------------------*/ +static void +lim_send_dfs_chan_sw_ie_update(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + /* Update the beacon template and send to FW */ + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("Unable to set CSA IE in beacon"));) + return; + } + + /* Send update beacon template message */ + lim_send_beacon_ind(pMac, psessionEntry); + PELOG1(lim_log(pMac, LOG1, + FL(" Updated CSA IE, IE COUNT = %d"), + psessionEntry->gLimChannelSwitch.switchCount); + ) + + return; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_ap_channel_switch_resp() - sends + eWNI_SME_CHANNEL_CHANGE_RSP + After receiving WMA_SWITCH_CHANNEL_RSP indication this + function sends a eWNI_SME_CHANNEL_CHANGE_RSP to SME to notify + that the Channel change has been done to the specified target + channel in the Channel change request + \param pMac - global mac structure + \param psessionEntry - session info + \param pChnlParams - Channel switch params + --------------------------------------------------------------------*/ +void +lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams) +{ + tSirMsgQ mmhMsg; + tpSwitchChannelParams pSmeSwithChnlParams; + uint8_t channelId; + + pSmeSwithChnlParams = (tSwitchChannelParams *) + cdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pSmeSwithChnlParams) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for pSmeSwithChnlParams\n")); + return; + } + + cdf_mem_set((void *)pSmeSwithChnlParams, + sizeof(tSwitchChannelParams), 0); + + cdf_mem_copy(pSmeSwithChnlParams, pChnlParams, + sizeof(tSwitchChannelParams)); + + channelId = pSmeSwithChnlParams->channelNumber; + + /* + * Pass the sme sessionID to SME instead + * PE session ID. + */ + pSmeSwithChnlParams->peSessionId = psessionEntry->smeSessionId; + + mmhMsg.type = eWNI_SME_CHANNEL_CHANGE_RSP; + mmhMsg.bodyptr = (void *)pSmeSwithChnlParams; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + /* + * We should start beacon transmission only if the new + * channel after channel change is Non-DFS. For a DFS + * channel, PE will receive an explicit request from + * upper layers to start the beacon transmission . + */ + + if (CHANNEL_STATE_DFS != cds_get_channel_state(channelId)) { + if (channelId == psessionEntry->currentOperChannel) { + lim_apply_configuration(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + } else { + PELOG1(lim_log(pMac, LOG1, + FL + ("Failed to Transmit Beacons on channel = %d" + "after AP channel change response"), + psessionEntry->bcnLen); + ) + } + } + return; +} + +/** ----------------------------------------------------------------- + \brief lim_process_beacon_tx_success_ind() - This function is used + explicitely to handle successful beacon transmission indication + from the FW. This is a generic event generated by the FW afer the + first beacon is sent out after the beacon template update by the + host + \param pMac - global mac structure + \param psessionEntry - session info + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_process_beacon_tx_success_ind(tpAniSirGlobal pMac, uint16_t msgType, void *event) +{ + /* Currently, this event is used only for DFS channel switch announcement + * IE update in the template. If required to be used for other IE updates + * add appropriate code by introducing a state variable + */ + tpPESession psessionEntry; + tSirMsgQ mmhMsg; + tSirSmeCSAIeTxCompleteRsp *pChanSwTxResponse; + struct sir_beacon_tx_complete_rsp *beacon_tx_comp_rsp_ptr; + uint8_t length = sizeof(tSirSmeCSAIeTxCompleteRsp); + tpSirFirstBeaconTxCompleteInd pBcnTxInd = + (tSirFirstBeaconTxCompleteInd *) event; + + psessionEntry = pe_find_session_by_bss_idx(pMac, pBcnTxInd->bssIdx); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry) && + true == psessionEntry->dfsIncludeChanSwIe) { + /* Send only 5 beacons with CSA IE Set in when a radar is detected */ + if (psessionEntry->gLimChannelSwitch.switchCount > 0) { + /* + * Send the next beacon with updated CSA IE count + */ + lim_send_dfs_chan_sw_ie_update(pMac, psessionEntry); + /* Decrement the IE count */ + psessionEntry->gLimChannelSwitch.switchCount--; + } else { + /* Done with CSA IE update, send response back to SME */ + psessionEntry->gLimChannelSwitch.switchCount = 0; + if (pMac->sap.SapDfsInfo.disable_dfs_ch_switch == false) + psessionEntry->gLimChannelSwitch.switchMode = 0; + psessionEntry->dfsIncludeChanSwIe = false; + psessionEntry->dfsIncludeChanWrapperIe = false; + + pChanSwTxResponse = (tSirSmeCSAIeTxCompleteRsp *) + cdf_mem_malloc(length); + + if (NULL == pChanSwTxResponse) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for tSirSmeCSAIeTxCompleteRsp")); + return; + } + + cdf_mem_set((void *)pChanSwTxResponse, length, 0); + pChanSwTxResponse->sessionId = + psessionEntry->smeSessionId; + pChanSwTxResponse->chanSwIeTxStatus = + CDF_STATUS_SUCCESS; + + mmhMsg.type = eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND; + mmhMsg.bodyptr = pChanSwTxResponse; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + } + } + + if (LIM_IS_AP_ROLE(psessionEntry) && + psessionEntry->gLimOperatingMode.present) { + /* Done with nss update, send response back to SME */ + psessionEntry->gLimOperatingMode.present = 0; + beacon_tx_comp_rsp_ptr = (struct sir_beacon_tx_complete_rsp *) + cdf_mem_malloc(sizeof(*beacon_tx_comp_rsp_ptr)); + if (NULL == beacon_tx_comp_rsp_ptr) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for beacon_tx_comp_rsp_ptr")); + return; + } + cdf_mem_set((void *)beacon_tx_comp_rsp_ptr, + sizeof(*beacon_tx_comp_rsp_ptr), 0); + beacon_tx_comp_rsp_ptr->session_id = + psessionEntry->smeSessionId; + beacon_tx_comp_rsp_ptr->tx_status = CDF_STATUS_SUCCESS; + mmhMsg.type = eWNI_SME_NSS_UPDATE_RSP; + mmhMsg.bodyptr = beacon_tx_comp_rsp_ptr; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + } + return; +} diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h new file mode 100644 index 0000000000..e707481ad6 --- /dev/null +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_send_sme_rsp_messages.h contains the definitions for + * sending SME response/notification messages to applications above + * MAC software. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_SME_RSP_H +#define __LIM_SEND_SME_RSP_H + +#include "sir_common.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" + +/* Functions for sending responses to Host */ +void lim_send_sme_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, uint8_t, + uint16_t); +void lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id); +void lim_send_sme_start_bss_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + tpPESession, uint8_t, uint16_t); +void lim_send_sme_scan_rsp(tpAniSirGlobal, tSirResultCodes, uint8_t, + uint16_t, uint32_t scan_id); +void lim_post_sme_scan_rsp_message(tpAniSirGlobal, tSirResultCodes, + uint8_t, uint16_t, uint32_t scan_id); + +void lim_send_sme_join_reassoc_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + uint16_t, tpPESession, uint8_t, uint16_t); +void lim_send_sme_disassoc_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, + uint16_t, uint16_t, uint8_t, uint16_t, tpPESession); +void lim_send_sme_deauth_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, uint16_t, + uint16_t, uint8_t, uint16_t); +void lim_send_sme_disassoc_ind(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_send_sme_deauth_ind(tpAniSirGlobal, tpDphHashNode, + tpPESession psessionEntry); +void lim_send_sme_wm_status_change_ntf(tpAniSirGlobal, tSirSmeStatusChangeCode, + uint32_t *, uint16_t, uint8_t); +void lim_send_sme_set_context_rsp(tpAniSirGlobal, tSirMacAddr, uint16_t, + tSirResultCodes, tpPESession, uint8_t, uint16_t); +void lim_send_sme_neighbor_bss_ind(tpAniSirGlobal, tLimScanResultNode *); +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ MsgQ); +void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg); + +#ifdef WLAN_FEATURE_VOWIFI_11R +void +lim_send_sme_aggr_qos_rsp(tpAniSirGlobal pMac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId); +#endif /*WLAN_FEATURE_VOWIFI_11R */ + +void lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId); +void lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, + uint32_t status, tpPESession psessionEntry, + uint8_t smessionId, uint16_t smetransactionId); +void lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, + uint16_t aid, tpPESession); +void lim_send_sme_stats_rsp(tpAniSirGlobal pMac, uint16_t msgtype, void *stats); + +void lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgtype, + void *stats); +#ifdef FEATURE_WLAN_ESE_UPLOAD +void lim_send_sme_pe_ese_tsm_rsp(tpAniSirGlobal pMac, tAniGetTsmStatsRsp *pStats); +#endif + +void lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t staIndex, uint8_t ucastIdx, + uint8_t bcastIdx, uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, + uint8_t sessionId); +#ifdef FEATURE_OEM_DATA_SUPPORT +void lim_send_sme_oem_data_rsp(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tSirResultCodes resultCode); +#endif + +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId); +#ifdef FEATURE_WLAN_TDLS +void lim_send_sme_tdls_link_establish_req_rsp(tpAniSirGlobal pMac, uint8_t sessionId, + tSirMacAddr peerMac, + tDphHashNode *pStaDs, uint8_t status); +void lim_send_sme_tdls_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *events); +#endif + +void lim_send_sme_dfs_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *event); +void lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams); +void +lim_process_beacon_tx_success_ind(tpAniSirGlobal pMac, uint16_t msgType, + void *event); + +typedef enum { + lim_csa_ie_present = 0x00000001, + lim_xcsa_ie_present = 0x00000002, + lim_wbw_ie_present = 0x00000004, + lim_cswarp_ie_present = 0x00000008, +} lim_csa_event_ies_present_flag; + +#endif /* __LIM_SEND_SME_RSP_H */ diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.c b/core/mac/src/pe/lim/lim_ser_des_utils.c new file mode 100644 index 0000000000..bd778f55cc --- /dev/null +++ b/core/mac/src/pe/lim/lim_ser_des_utils.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ser_des_utils.cc contains the serializer/deserializer + * utility functions LIM uses while communicating with upper layer + * software entities + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_system_defs.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" + +/**--------------------------------------------------------------- + \fn lim_get_session_info + \brief This function returns the sessionId and transactionId + \ of a message. This assumes that the message structure + \ is of format: + \ uint16_t messageType + \ uint16_t messageLength + \ uint8_t sessionId + \ uint16_t transactionId + \param pMac - pMac global structure + \param *pBuf - pointer to the message buffer + \param sessionId - returned session id value + \param transactionId - returned transaction ID value + \return None + ------------------------------------------------------------------*/ +void +lim_get_session_info(tpAniSirGlobal pMac, uint8_t *pBuf, uint8_t *sessionId, + uint16_t *transactionId) +{ + if (!pBuf) { + lim_log(pMac, LOGE, FL("NULL ptr received. ")); + return; + } + + pBuf += sizeof(uint16_t); /* skip message type */ + pBuf += sizeof(uint16_t); /* skip message length */ + + *sessionId = *pBuf; /* get sessionId */ + pBuf++; + *transactionId = lim_get_u16(pBuf); /* get transactionId */ + + return; +} diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.h b/core/mac/src/pe/lim/lim_ser_des_utils.h new file mode 100644 index 0000000000..f05f4ddd0a --- /dev/null +++ b/core/mac/src/pe/lim/lim_ser_des_utils.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ser_des_utils.h contains the utility definitions + * LIM uses while processing messages from upper layer software + * modules + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SERDES_UTILS_H +#define __LIM_SERDES_UTILS_H + +#include "sir_api.h" +#include "ani_system_defs.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_prop_exts_utils.h" + +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, + uint8_t *, uint16_t *); + +/* Byte String <--> uint16_t/uint32_t copy functions */ +static inline void lim_copy_u16(uint8_t *ptr, uint16_t u16Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u16Val & 0xff); + *ptr = (uint8_t) ((u16Val >> 8) & 0xff); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline uint16_t lim_get_u16(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((uint16_t) (*(ptr + 1) << 8)) | ((uint16_t) (*ptr)); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline void lim_copy_u32(uint8_t *ptr, uint32_t u32Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u32Val & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 8) & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 16) & 0xff); + *ptr = (uint8_t) ((u32Val >> 24) & 0xff); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline uint32_t lim_get_u32(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((*(ptr + 3) << 24) | + (*(ptr + 2) << 16) | (*(ptr + 1) << 8) | (*(ptr))); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +#endif /* __LIM_SERDES_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c new file mode 100644 index 0000000000..6c73b4ce2b --- /dev/null +++ b/core/mac/src/pe/lim/lim_session.c @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_session.c + + \brief implementation for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_debug.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#include "lim_ft.h" +#endif +#include "lim_session.h" +#include "lim_utils.h" + +#include "sch_api.h" +#include "lim_send_messages.h" + +/*-------------------------------------------------------------------------- + + \brief pe_init_beacon_params() - Initialize the beaconParams structure + + \param tpPESession - pointer to the session context or NULL if session can not be created. + \return void + \sa + + --------------------------------------------------------------------------*/ + +void pe_init_beacon_params(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + psessionEntry->beaconParams.beaconInterval = 0; + psessionEntry->beaconParams.fShortPreamble = 0; + psessionEntry->beaconParams.llaCoexist = 0; + psessionEntry->beaconParams.llbCoexist = 0; + psessionEntry->beaconParams.llgCoexist = 0; + psessionEntry->beaconParams.ht20Coexist = 0; + psessionEntry->beaconParams.llnNonGFCoexist = 0; + psessionEntry->beaconParams.fRIFSMode = 0; + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = 0; + psessionEntry->beaconParams.gHTObssMode = 0; + + /* Number of legacy STAs associated */ + cdf_mem_set((void *)&psessionEntry->gLim11bParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLim11aParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLim11gParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLimNonGfParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLimHt20Params, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLimLsigTxopParams, + sizeof(tLimProtStaParams), 0); + cdf_mem_set((void *)&psessionEntry->gLimOlbcParams, + sizeof(tLimProtStaParams), 0); +} + +/* + * pe_reset_protection_callback() - resets protection structs so that when an AP + * causing use of protection goes away, corresponding protection bit can be + * reset + * @ptr: pointer to pSessionEntry + * + * This function resets protection structs so that when an AP causing use of + * protection goes away, corresponding protection bit can be reset. This allowes + * protection bits to be reset once legacy overlapping APs are gone. + * + * Return: void + */ +void pe_reset_protection_callback(void *ptr) +{ + tpPESession pe_session_entry = (tpPESession)ptr; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)pe_session_entry->mac_ctx; + int8_t i = 0; + tUpdateBeaconParams beacon_params; + uint16_t current_protection_state = 0; + tpDphHashNode station_hash_node = NULL; + tSirMacHTOperatingMode old_op_mode; + bool bcn_prms_changed = false; + + if (pe_session_entry->valid == false) { + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_ERROR, + FL("session already deleted. exiting timer callback")); + return; + } + + current_protection_state |= + pe_session_entry->gLimOverlap11gParams.protectionEnabled | + pe_session_entry->gLimOverlap11aParams.protectionEnabled << 1 | + pe_session_entry->gLimOverlapHt20Params.protectionEnabled << 2 | + pe_session_entry->gLimOverlapNonGfParams.protectionEnabled << 3 | + pe_session_entry->gLimOlbcParams.protectionEnabled << 4; + + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_INFO, + FL("old protection state: 0x%04X, new protection state: 0x%04X\n"), + pe_session_entry->old_protection_state, + current_protection_state); + + cdf_mem_zero(&pe_session_entry->gLimOverlap11gParams, + sizeof(pe_session_entry->gLimOverlap11gParams)); + cdf_mem_zero(&pe_session_entry->gLimOverlap11aParams, + sizeof(pe_session_entry->gLimOverlap11aParams)); + cdf_mem_zero(&pe_session_entry->gLimOverlapHt20Params, + sizeof(pe_session_entry->gLimOverlapHt20Params)); + cdf_mem_zero(&pe_session_entry->gLimOverlapNonGfParams, + sizeof(pe_session_entry->gLimOverlapNonGfParams)); + + cdf_mem_zero(&pe_session_entry->gLimOlbcParams, + sizeof(pe_session_entry->gLimOlbcParams)); + + cdf_mem_zero(&pe_session_entry->beaconParams, + sizeof(pe_session_entry->beaconParams)); + + cdf_mem_zero(&mac_ctx->lim.gLimOverlap11gParams, + sizeof(mac_ctx->lim.gLimOverlap11gParams)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlap11aParams, + sizeof(mac_ctx->lim.gLimOverlap11aParams)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlapHt20Params, + sizeof(mac_ctx->lim.gLimOverlapHt20Params)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlapNonGfParams, + sizeof(mac_ctx->lim.gLimOverlapNonGfParams)); + + old_op_mode = pe_session_entry->htOperMode; + pe_session_entry->htOperMode = eSIR_HT_OP_MODE_PURE; + + cdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + /* index 0, is self node, peers start from 1 */ + for (i = 1 ; i <= mac_ctx->lim.gLimAssocStaLimit ; i++) + { + station_hash_node = dph_get_hash_entry(mac_ctx, i, + &pe_session_entry->dph.dphHashTable); + if (NULL == station_hash_node) + continue; + lim_decide_ap_protection(mac_ctx, station_hash_node->staAddr, + &beacon_params, pe_session_entry); + } + + if (pe_session_entry->htOperMode != old_op_mode) + bcn_prms_changed = true; + + if ((current_protection_state != + pe_session_entry->old_protection_state) && + (false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_ERROR, + FL("protection changed, update beacon template\n")); + /* update beacon fix params and send update to FW */ + cdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.bssIdx = pe_session_entry->bssIdx; + beacon_params.fShortPreamble = + pe_session_entry->beaconParams.fShortPreamble; + beacon_params.beaconInterval = + pe_session_entry->beaconParams.beaconInterval; + beacon_params.llaCoexist = + pe_session_entry->beaconParams.llaCoexist; + beacon_params.llbCoexist = + pe_session_entry->beaconParams.llbCoexist; + beacon_params.llgCoexist = + pe_session_entry->beaconParams.llgCoexist; + beacon_params.ht20MhzCoexist = + pe_session_entry->beaconParams.ht20Coexist; + beacon_params.llnNonGFCoexist = + pe_session_entry->beaconParams.llnNonGFCoexist; + beacon_params.fLsigTXOPProtectionFullSupport = + pe_session_entry->beaconParams. + fLsigTXOPProtectionFullSupport; + beacon_params.fRIFSMode = + pe_session_entry->beaconParams.fRIFSMode; + beacon_params.smeSessionId = + pe_session_entry->smeSessionId; + bcn_prms_changed = true; + } + + if (bcn_prms_changed) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session_entry); + } + + pe_session_entry->old_protection_state = current_protection_state; + if (cdf_mc_timer_start(&pe_session_entry-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME) + != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_ERROR, + FL("cannot create or start protectionFieldsResetTimer\n")); + } +} + +/** + * pe_create_session() creates a new PE session given the BSSID + * @param pMac: pointer to global adapter context + * @param bssid: BSSID of the new session + * @param sessionId: session ID is returned here, if session is created. + * @param bssType: station or a + * + * This function returns the session context and the session ID if the session + * corresponding to the passed BSSID is found in the PE session table. + * + * Return: tpPESession: pointer to the session context or NULL if session + * can not be created. + */ + +tpPESession +pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType) +{ + CDF_STATUS status; + uint8_t i; + tpPESession session_ptr; + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true) + continue; + break; + } + + if (i == pMac->lim.maxBssId) { + lim_log(pMac, LOGE, + FL("Session can't be created. Reached max sessions\n")); + return NULL; + } + + session_ptr = &pMac->lim.gpSession[i]; + cdf_mem_set((void *)session_ptr, sizeof(tPESession), 0); + /* Allocate space for Station Table for this session. */ + session_ptr->dph.dphHashTable.pHashTable = + cdf_mem_malloc(sizeof(tpDphHashNode) * (numSta + 1)); + if (NULL == session_ptr->dph.dphHashTable.pHashTable) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + return NULL; + } + + session_ptr->dph.dphHashTable.pDphNodeArray = + cdf_mem_malloc(sizeof(tDphHashNode) * (numSta + 1)); + if (NULL == session_ptr->dph.dphHashTable.pDphNodeArray) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + cdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + session_ptr->dph.dphHashTable. + pHashTable = NULL; + return NULL; + } + + session_ptr->dph.dphHashTable.size = numSta + 1; + dph_hash_table_class_init(pMac, &session_ptr->dph.dphHashTable); + session_ptr->gpLimPeerIdxpool = cdf_mem_malloc( + sizeof(*(session_ptr->gpLimPeerIdxpool)) * (numSta + 1)); + if (NULL == session_ptr->gpLimPeerIdxpool) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + cdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + cdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + return NULL; + } + cdf_mem_set(session_ptr->gpLimPeerIdxpool, + sizeof(*session_ptr->gpLimPeerIdxpool) * (numSta + 1), + 0); + session_ptr->freePeerIdxHead = 0; + session_ptr->freePeerIdxTail = 0; + session_ptr->gLimNumOfCurrentSTAs = 0; + /* Copy the BSSID to the session table */ + sir_copy_mac_addr(session_ptr->bssId, bssid); + session_ptr->valid = true; + /* Intialize the SME and MLM states to IDLE */ + session_ptr->limMlmState = eLIM_MLM_IDLE_STATE; + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + session_ptr->limCurrentAuthType = eSIR_OPEN_SYSTEM; + pe_init_beacon_params(pMac, &pMac->lim.gpSession[i]); +#ifdef WLAN_FEATURE_VOWIFI_11R + session_ptr->is11Rconnection = false; +#endif +#ifdef FEATURE_WLAN_ESE + session_ptr->isESEconnection = false; +#endif +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + session_ptr->isFastTransitionEnabled = false; +#endif +#ifdef FEATURE_WLAN_LFR + session_ptr->isFastRoamIniFeatureEnabled = false; +#endif + *sessionId = i; + session_ptr->gLimPhyMode = WNI_CFG_PHY_MODE_11G; + /* Initialize CB mode variables when session is created */ + session_ptr->htSupportedChannelWidthSet = 0; + session_ptr->htRecommendedTxWidthSet = 0; + session_ptr->htSecondaryChannelOffset = 0; +#ifdef FEATURE_WLAN_TDLS + cdf_mem_set(session_ptr->peerAIDBitmap, + sizeof(session_ptr->peerAIDBitmap), 0); + session_ptr->tdls_prohibited = false; + session_ptr->tdls_chan_swit_prohibited = false; +#endif + session_ptr->fWaitForProbeRsp = 0; + session_ptr->fIgnoreCapsChange = 0; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + FL("Create a new PE session(%d), BSSID: "MAC_ADDRESS_STR" Max No. of STA %d"), + session_ptr->peSessionId, MAC_ADDR_ARRAY(bssid), numSta); + + if (eSIR_INFRA_AP_MODE == bssType + || eSIR_IBSS_MODE == bssType + || eSIR_BTAMP_AP_MODE == bssType) { + session_ptr->pSchProbeRspTemplate = + cdf_mem_malloc(SCH_MAX_PROBE_RESP_SIZE); + session_ptr->pSchBeaconFrameBegin = + cdf_mem_malloc(SCH_MAX_BEACON_SIZE); + session_ptr->pSchBeaconFrameEnd = + cdf_mem_malloc(SCH_MAX_BEACON_SIZE); + if ((NULL == session_ptr->pSchProbeRspTemplate) + || (NULL == session_ptr->pSchBeaconFrameBegin) + || (NULL == session_ptr->pSchBeaconFrameEnd)) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + cdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + cdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); + cdf_mem_free(session_ptr->gpLimPeerIdxpool); + cdf_mem_free(session_ptr->pSchProbeRspTemplate); + cdf_mem_free(session_ptr->pSchBeaconFrameBegin); + cdf_mem_free(session_ptr->pSchBeaconFrameEnd); + + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + session_ptr->gpLimPeerIdxpool = NULL; + session_ptr->pSchProbeRspTemplate = NULL; + session_ptr->pSchBeaconFrameBegin = NULL; + session_ptr->pSchBeaconFrameEnd = NULL; + return NULL; + } + } +#if defined WLAN_FEATURE_VOWIFI_11R + if (eSIR_INFRASTRUCTURE_MODE == bssType) + lim_ft_open(pMac, &pMac->lim.gpSession[i]); +#endif + if (eSIR_INFRA_AP_MODE == bssType) { + session_ptr->old_protection_state = 0; + session_ptr->mac_ctx = (void *)pMac; + status = cdf_mc_timer_init( + &session_ptr->protection_fields_reset_timer, + CDF_TIMER_TYPE_SW, pe_reset_protection_callback, + (void *)&pMac->lim.gpSession[i]); + if (status == CDF_STATUS_SUCCESS) { + status = cdf_mc_timer_start( + &session_ptr->protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + } + if (status != CDF_STATUS_SUCCESS) + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("cannot create or start protectionFieldsResetTimer\n")); + } + return &pMac->lim.gpSession[i]; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bssid() - looks up the PE session given the BSSID. + + This function returns the session context and the session ID if the session + corresponding to the given BSSID is found in the PE session table. + + \param pMac - pointer to global adapter context + \param bssid - BSSID of the session + \param sessionId -session ID is returned here, if session is found. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (sir_compare_mac_addr(pMac->lim.gpSession[i].bssId, bssid))) + { + *sessionId = i; + return (&pMac->lim.gpSession[i]); + } + } + + lim_log(pMac, LOG4, FL("Session lookup fails for BSSID: \n ")); + lim_print_mac_addr(pMac, bssid, LOG4); + return (NULL); + +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + + This function returns the session context if the session + corresponding to the given bssIdx is found in the PE session table. + \param pMac - pointer to global adapter context + \param bssIdx - bss index of the session + \return tpPESession - pointer to the session context or NULL if session is not found. + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (pMac->lim.gpSession[i].bssIdx == bssIdx)) { + return &pMac->lim.gpSession[i]; + } + } + lim_log(pMac, LOG4, FL("Session lookup fails for bssIdx: %d"), bssIdx); + return NULL; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_session_id() - looks up the PE session given the session ID. + + This function returns the session context if the session + corresponding to the given session ID is found in the PE session table. + + \param pMac - pointer to global adapter context + \param sessionId -session ID for which session context needs to be looked up. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, uint8_t sessionId) +{ + if (sessionId >= pMac->lim.maxBssId) { + lim_log(pMac, LOGE, FL("Invalid sessionId: %d \n "), sessionId); + return (NULL); + } + if ((pMac->lim.gpSession[sessionId].valid == true)) { + return (&pMac->lim.gpSession[sessionId]); + } + return (NULL); + +} + +/** + * pe_find_session_by_sta_id() - looks up the PE session given staid. + * @mac_ctx: pointer to global adapter context + * @staid: StaId of the session + * @session_id: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given StaId is found in the PE session table. + * + * Return: session pointer + */ +tpPESession +pe_find_session_by_sta_id(tpAniSirGlobal mac_ctx, + uint8_t staid, + uint8_t *session_id) +{ + uint8_t i, j; + tpPESession session_ptr; + dphHashTableClass *dph_ptr; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (!mac_ctx->lim.gpSession[i].valid) + continue; + session_ptr = &mac_ctx->lim.gpSession[i]; + dph_ptr = &session_ptr->dph.dphHashTable; + for (j = 0; j < dph_ptr->size; j++) { + if (dph_ptr->pDphNodeArray[j].valid + && dph_ptr->pDphNodeArray[j].added + && staid == dph_ptr->pDphNodeArray[j].staIndex) { + *session_id = i; + return session_ptr; + } + } + } + + lim_log(mac_ctx, LOG4, + FL("Session lookup fails for StaId: %d\n "), staid); + return NULL; +} + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * @mac_ctx: pointer to global adapter context + * @session: session to be deleted. + * + * Deletes the given PE session + * + * Return: void + */ +void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint16_t i = 0; + uint16_t n; + TX_TIMER *timer_ptr; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_DEBUG, + FL("Trying to delete PE session %d Opmode %d BssIdx %d BSSID: "MAC_ADDRESS_STR), + session->peSessionId, session->operMode, + session->bssIdx, + MAC_ADDR_ARRAY(session->bssId)); + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + timer_ptr = &mac_ctx->lim.limTimers.gpLimCnfWaitTimer[n]; + if (session->peSessionId == timer_ptr->sessionId) + if (true == tx_timer_running(timer_ptr)) + tx_timer_deactivate(timer_ptr); + } + +#if defined (WLAN_FEATURE_VOWIFI_11R) + /* Delete FT related information */ + lim_ft_cleanup(mac_ctx, session); +#endif + if (session->pLimStartBssReq != NULL) { + cdf_mem_free(session->pLimStartBssReq); + session->pLimStartBssReq = NULL; + } + + if (session->pLimJoinReq != NULL) { + cdf_mem_free(session->pLimJoinReq); + session->pLimJoinReq = NULL; + } + + if (session->pLimReAssocReq != NULL) { + cdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + if (session->pLimMlmJoinReq != NULL) { + cdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + + if (session->dph.dphHashTable.pHashTable != NULL) { + cdf_mem_free(session->dph.dphHashTable.pHashTable); + session->dph.dphHashTable.pHashTable = NULL; + } + + if (session->dph.dphHashTable.pDphNodeArray != NULL) { + cdf_mem_free(session->dph.dphHashTable.pDphNodeArray); + session->dph.dphHashTable.pDphNodeArray = NULL; + } + + if (session->gpLimPeerIdxpool != NULL) { + cdf_mem_free(session->gpLimPeerIdxpool); + session->gpLimPeerIdxpool = NULL; + } + + if (session->beacon != NULL) { + cdf_mem_free(session->beacon); + session->beacon = NULL; + } + + if (session->assocReq != NULL) { + cdf_mem_free(session->assocReq); + session->assocReq = NULL; + } + + if (session->assocRsp != NULL) { + cdf_mem_free(session->assocRsp); + session->assocRsp = NULL; + } + + if (session->parsedAssocReq != NULL) { + tpSirAssocReq tmp_ptr = NULL; + /* Cleanup the individual allocation first */ + for (i = 0; i < session->dph.dphHashTable.size; i++) { + if (session->parsedAssocReq[i] == NULL) + continue; + tmp_ptr = ((tpSirAssocReq) + (session->parsedAssocReq[i])); + if (tmp_ptr->assocReqFrame) { + cdf_mem_free(tmp_ptr->assocReqFrame); + tmp_ptr->assocReqFrame = NULL; + tmp_ptr->assocReqFrameLength = 0; + } + cdf_mem_free(session->parsedAssocReq[i]); + session->parsedAssocReq[i] = NULL; + } + /* Cleanup the whole block */ + cdf_mem_free(session->parsedAssocReq); + session->parsedAssocReq = NULL; + } + if (NULL != session->limAssocResponseData) { + cdf_mem_free(session->limAssocResponseData); + session->limAssocResponseData = NULL; + } +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (NULL != session->pLimMlmReassocRetryReq) { + cdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } +#endif + if (NULL != session->pLimMlmReassocReq) { + cdf_mem_free(session->pLimMlmReassocReq); + session->pLimMlmReassocReq = NULL; + } + + if (NULL != session->pSchProbeRspTemplate) { + cdf_mem_free(session->pSchProbeRspTemplate); + session->pSchProbeRspTemplate = NULL; + } + + if (NULL != session->pSchBeaconFrameBegin) { + cdf_mem_free(session->pSchBeaconFrameBegin); + session->pSchBeaconFrameBegin = NULL; + } + + if (NULL != session->pSchBeaconFrameEnd) { + cdf_mem_free(session->pSchBeaconFrameEnd); + session->pSchBeaconFrameEnd = NULL; + } + + /* Must free the buffer before peSession invalid */ + if (NULL != session->addIeParams.probeRespData_buff) { + cdf_mem_free(session->addIeParams.probeRespData_buff); + session->addIeParams.probeRespData_buff = NULL; + session->addIeParams.probeRespDataLen = 0; + } + if (NULL != session->addIeParams.assocRespData_buff) { + cdf_mem_free(session->addIeParams.assocRespData_buff); + session->addIeParams.assocRespData_buff = NULL; + session->addIeParams.assocRespDataLen = 0; + } + if (NULL != session->addIeParams.probeRespBCNData_buff) { + cdf_mem_free(session->addIeParams.probeRespBCNData_buff); + session->addIeParams.probeRespBCNData_buff = NULL; + session->addIeParams.probeRespBCNDataLen = 0; + } +#ifdef WLAN_FEATURE_11W + /* if PMF connection */ + if (session->limRmfEnabled) + cdf_mc_timer_destroy(&session->pmfComebackTimer); +#endif + + if (LIM_IS_AP_ROLE(session)) { + cdf_mc_timer_stop(&session->protection_fields_reset_timer); + cdf_mc_timer_destroy(&session->protection_fields_reset_timer); + } + + session->valid = false; + + if (LIM_IS_AP_ROLE(session)) + lim_check_and_reset_protection_params(mac_ctx); + + return; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_peer_sta() - looks up the PE session given the Station Address. + + This function returns the session context and the session ID if the session + corresponding to the given station address is found in the PE session table. + + \param pMac - pointer to global adapter context + \param sa - Peer STA Address of the session + \param sessionId -session ID is returned here, if session is found. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ + +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId) +{ + uint8_t i; + tpDphHashNode pSta; + uint16_t aid; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid)) { + pSta = + dph_lookup_hash_entry(pMac, sa, &aid, + &pMac->lim.gpSession[i].dph. + dphHashTable); + if (pSta != NULL) { + *sessionId = i; + return &pMac->lim.gpSession[i]; + } + } + } + + lim_log(pMac, LOG1, FL("Session lookup fails for Peer StaId: \n ")); + lim_print_mac_addr(pMac, sa, LOG1); + return NULL; +} + +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_id) +{ + uint8_t i; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].smeSessionId == + sme_session_id)) { + return &mac_ctx->lim.gpSession[i]; + } + } + lim_log(mac_ctx, LOG4, + FL("Session lookup fails for smeSessionID: %d"), + sme_session_id); + return NULL; +} + +/** + * pe_get_active_session_count() - function to return active pe session count + * + * @mac_ctx: pointer to global mac structure + * + * returns number of active pe session count + * + * Return: 0 if there are no active sessions else return number of active + * sessions + */ +uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx) +{ + uint8_t i, active_session_count = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid) + active_session_count++; + + return active_session_count; +} diff --git a/core/mac/src/pe/lim/lim_session_utils.c b/core/mac/src/pe/lim/lim_session_utils.c new file mode 100644 index 0000000000..49b37a12b8 --- /dev/null +++ b/core/mac/src/pe/lim/lim_session_utils.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_session_utils.c + \brief implementation for lim Session Utility APIs + \author Sunit Bhatia + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_debug.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "lim_session_utils.h" +#include "lim_utils.h" + +/** + * is_lim_session_off_channel() - checks if any other off channel session exists + * @mac_ctx: Global MAC context. + * @sessionId: PE session ID. + * + * Return: This function returns true if the session Id passed needs to be on + * a different channel than atleast one session already active. + **/ +uint8_t is_lim_session_off_channel(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + uint8_t i; + + if (session_id >= mac_ctx->lim.maxBssId) { + lim_log(mac_ctx, LOGE, FL("Invalid session_id:%d"), session_id); + return false; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* Skip the session_id that is to be joined. */ + if (i == session_id) + continue; + /* + * if another session is valid and it is on different channel + * then it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].currentOperChannel != + mac_ctx->lim.gpSession[session_id].currentOperChannel)) + return true; + } + return false; + +} + +/** + * lim_is_chan_switch_running() - check if channel switch is happening + * @mac_ctx: Global MAC context. + * + * Return: 1 - if channel switch is happening on any session. + * 0 - if channel switch is not happening. + **/ +uint8_t lim_is_chan_switch_running(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid && + mac_ctx->lim.gpSession[i].gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) + return 1; + return 0; +} + +/** + * lim_is_in_mcc() - check if device is in MCC + * @mac_ctx: Global MAC context. + * + * Return: true - if in MCC. + * false - Not in MCC + **/ +uint8_t lim_is_in_mcc(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t chan = 0; + uint8_t curr_oper_channel = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * if another session is valid and it is on different channel + * it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid)) { + curr_oper_channel = + mac_ctx->lim.gpSession[i].currentOperChannel; + if (chan == 0) + chan = curr_oper_channel; + else if (chan != curr_oper_channel) + return true; + } + } + return false; +} + +/** + * pe_get_current_stas_count() - Total stations associated on all sessions. + * @mac_ctx: Global MAC context. + * + * Return: true - Number of stations active on all sessions. + **/ +uint8_t pe_get_current_stas_count(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t stacount = 0; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid == true) + stacount += + mac_ctx->lim.gpSession[i].gLimNumOfCurrentSTAs; + return stacount; +} diff --git a/core/mac/src/pe/lim/lim_session_utils.h b/core/mac/src/pe/lim/lim_session_utils.h new file mode 100644 index 0000000000..d1dd7d1c03 --- /dev/null +++ b/core/mac/src/pe/lim/lim_session_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__LIM_SESSION_UTILS_H) +#define __LIM_SESSION_UTILS_H + +uint8_t is_lim_session_off_channel(tpAniSirGlobal pMac, uint8_t sessionId); +uint8_t lim_is_chan_switch_running(tpAniSirGlobal pMac); +uint8_t lim_is_in_mcc(tpAniSirGlobal pMac); +uint8_t pe_get_current_stas_count(tpAniSirGlobal pMac); + +#endif /* #if !defined( __LIM_SESSION_UTILS_H ) */ diff --git a/core/mac/src/pe/lim/lim_sme_req_utils.c b/core/mac/src/pe/lim/lim_sme_req_utils.c new file mode 100644 index 0000000000..550231ff03 --- /dev/null +++ b/core/mac/src/pe/lim/lim_sme_req_utils.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sme_req_utils.cc contains the utility functions + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" + +/** + * lim_is_rs_nie_valid_in_sme_req_message() + * + * @mac_ctx Pointer to Global MAC structure + * @rsn_ie Pointer to received RSN IE + * + * This function is called to verify if the RSN IE received in various SME_REQ + * messages is valid or not + * + * Return: true when RSN IE is valid, false otherwise + * + */ + +static uint8_t +lim_is_rsn_ie_valid_in_sme_req_message(tpAniSirGlobal mac_ctx, tpSirRSNie rsn_ie) +{ + uint8_t start = 0; + uint32_t privacy, val; + int len; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, FL("Unable to retrieve POI from CFG")); + } + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, &val) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Unable to retrieve RSN_ENABLED from CFG")); + } + + if (rsn_ie->length && (!privacy || !val)) { + /* Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + PELOG1(lim_log(mac_ctx, LOG1, + FL("RSN ie len %d PRIVACY %d RSN %d"), + rsn_ie->length, privacy, val);) + } + + if (!rsn_ie->length) + return true; + + if ((rsn_ie->rsnIEdata[0] != DOT11F_EID_RSN) +#ifdef FEATURE_WLAN_WAPI + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WAPI) +#endif + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WPA)) { + lim_log(mac_ctx, LOGE, FL("RSN/WPA/WAPI EID %d not [%d || %d]"), + rsn_ie->rsnIEdata[0], DOT11F_EID_RSN, + DOT11F_EID_WPA); + return false; + } + + len = rsn_ie->length; + start = 0; + while (len > 0) { + switch (rsn_ie->rsnIEdata[start]) { + case DOT11F_EID_RSN: + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_RSN_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_RSN_MIN_LEN)) { + lim_log(mac_ctx, LOGE, + FL("RSN IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_RSN_MIN_LEN, + DOT11F_IE_RSN_MAX_LEN); + return false; + } + break; + case DOT11F_EID_WPA: + /* Check validity of WPA IE */ + if (SIR_MAC_MAX_IE_LENGTH <= start) + break; + + if (start <= (SIR_MAC_MAX_IE_LENGTH - sizeof(uint32_t))) + val = sir_read_u32((uint8_t *) & + rsn_ie->rsnIEdata[start + 2]); + + if ((rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WPA_MIN_LEN) + || (rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WPA_MAX_LEN) + || (SIR_MAC_WPA_OUI != val)) { + lim_log(mac_ctx, LOGE, + FL("WPA IE len %d not [%d,%d] OR data 0x%x not 0x%x"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WPA_MIN_LEN, + DOT11F_IE_WPA_MAX_LEN, + val, SIR_MAC_WPA_OUI); + return false; + } + break; +#ifdef FEATURE_WLAN_WAPI + case DOT11F_EID_WAPI: + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WAPI_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WAPI_MIN_LEN)) { + lim_log(mac_ctx, LOGE, + FL("WAPI IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WAPI_MIN_LEN, + DOT11F_IE_WAPI_MAX_LEN); + return false; + } + break; +#endif + default: + /* we will never be here, simply for completeness */ + return false; + } /* end of switch */ + /* EID + length field + length */ + start += 2 + rsn_ie->rsnIEdata[start + 1]; + len -= start; + } /* end while loop */ + return true; +} /*** end lim_is_rs_nie_valid_in_sme_req_message() ***/ + +/** + * lim_is_addie_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the Add IE + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * Add IE validity checks are performed on only length + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pWSCie Pointer to received WSC IE + * @return true when WSC IE is valid, false otherwise + */ + +static uint8_t +lim_is_addie_valid_in_sme_req_message(tpAniSirGlobal pMac, tpSirAddie pAddie) +{ + int left = pAddie->length; + uint8_t *ptr = pAddie->addIEdata; + uint8_t elem_id, elem_len; + + if (left == 0) + return true; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid Add IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + return false; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + /* there shouldn't be any left byte */ + + return true; +} /*** end lim_is_addie_valid_in_sme_req_message() ***/ + +/** + * lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message() - to set rsnie/wpaie + * + * @mac_ctx : Pointer to Global MAC structure + * @rsn_ie : Pointer to received RSN IE + * @session : Pointer to pe session + * + * This function is called to verify if the RSN IE received in various + * SME_REQ messages is valid or not. RSN IE validity checks are performed in + * this function + * + * Return: true when RSN IE is valid, false otherwise + */ +uint8_t +lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal mac_ctx, + tpSirRSNie rsn_ie, + tpPESession session) +{ + uint8_t wpa_idx = 0; + uint32_t privacy, val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("Unable to retrieve POI from CFG")); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, + &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Unable to retrieve RSN_ENABLED from CFG")); + + if (rsn_ie->length && (!privacy || !val)) { + /* + * Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + lim_log(mac_ctx, LOG1, + FL("RSN ie len %d but PRIVACY %d RSN %d"), + rsn_ie->length, privacy, val); + } + + if (!rsn_ie->length) + return true; + + if ((rsn_ie->rsnIEdata[0] != SIR_MAC_RSN_EID) && + (rsn_ie->rsnIEdata[0] != SIR_MAC_WPA_EID)) { + lim_log(mac_ctx, LOGE, FL("RSN/WPA EID %d not [%d || %d]"), + rsn_ie->rsnIEdata[0], SIR_MAC_RSN_EID, + SIR_MAC_WPA_EID); + return false; + } + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[0] == SIR_MAC_RSN_EID) && + (rsn_ie->rsnIEdata[1] < SIR_MAC_RSN_IE_MIN_LENGTH)) { + lim_log(mac_ctx, LOGE, FL("RSN IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[1], SIR_MAC_RSN_IE_MIN_LENGTH, + SIR_MAC_RSN_IE_MAX_LENGTH); + return false; + } + + if (rsn_ie->length > rsn_ie->rsnIEdata[1] + 2) { + if (rsn_ie->rsnIEdata[0] != SIR_MAC_RSN_EID) { + lim_log(mac_ctx, LOGE, + FL("First byte[%d] in rsnIEdata isn't RSN_EID"), + rsn_ie->rsnIEdata[1]); + return false; + } + lim_log(mac_ctx, LOG1, + FL("WPA IE is present along with WPA2 IE")); + wpa_idx = 2 + rsn_ie->rsnIEdata[1]; + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) && + (rsn_ie->rsnIEdata[0] == SIR_MAC_RSN_EID)) { + lim_log(mac_ctx, LOG1, FL("Only RSN IE is present")); + dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + (uint8_t) rsn_ie->length, + &session->gStartBssRSNIe); + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) + && (rsn_ie->rsnIEdata[0] == SIR_MAC_WPA_EID)) { + lim_log(mac_ctx, LOG1, FL("Only WPA IE is present")); + dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[6], + (uint8_t) rsn_ie->length - 4, + &session->gStartBssWPAIe); + } + /* Check validity of WPA IE */ + if (wpa_idx + 6 >= SIR_MAC_MAX_IE_LENGTH) + return false; + + val = sir_read_u32((uint8_t *)&rsn_ie->rsnIEdata[wpa_idx + 2]); + if ((rsn_ie->rsnIEdata[wpa_idx] == SIR_MAC_WPA_EID) + && ((rsn_ie->rsnIEdata[wpa_idx + 1] < SIR_MAC_WPA_IE_MIN_LENGTH) + || (SIR_MAC_WPA_OUI != val))) { + lim_log(mac_ctx, LOGE, + FL("WPA IE len %d not [%d,%d] OR data 0x%x not 0x%x"), + rsn_ie->rsnIEdata[1], + SIR_MAC_RSN_IE_MIN_LENGTH, + SIR_MAC_RSN_IE_MAX_LENGTH, val, + SIR_MAC_WPA_OUI); + return false; + } else { + /* Both RSN and WPA IEs are present */ + dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + (uint8_t) rsn_ie->length, + &session->gStartBssRSNIe); + dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[wpa_idx + 6], + rsn_ie->rsnIEdata[wpa_idx + 1] - 4, + &session->gStartBssWPAIe); + } + return true; +} + +/** + * lim_is_bss_descr_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the BSS Descr + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * BSS Descritipion validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pBssDescr Pointer to received Bss Descritipion + * @return true when BSS description is valid, false otherwise + */ + +static uint8_t +lim_is_bss_descr_valid_in_sme_req_message(tpAniSirGlobal pMac, + tpSirBssDescription pBssDescr) +{ + uint8_t valid = true; + + if (lim_is_addr_bc(pBssDescr->bssId) || !pBssDescr->channelId) { + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_bss_descr_valid_in_sme_req_message() ***/ + +/** + * lim_is_sme_start_bss_req_valid() - To validate sme start bss request + * + * @mac_ctx: Pointer to Global MAC structure + * @start_bss_req: Pointer to received SME_START_BSS_REQ message + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_START_BSS_REQ message from application. + * + * Return: true when received SME_START_BSS_REQ is formatted correctly false + * otherwise + */ + +uint8_t +lim_is_sme_start_bss_req_valid(tpAniSirGlobal mac_ctx, + tpSirSmeStartBssReq start_bss_req) +{ + uint8_t i = 0; + tSirMacRateSet *opr_rates = &start_bss_req->operationalRateSet; + + PELOG1(lim_log(mac_ctx, LOG1, + FL("Parsed START_BSS_REQ fields are bssType=%d, channelId=%d, SSID len=%d, rsnIE len=%d, nwType=%d, rateset len=%d"), + start_bss_req->bssType, start_bss_req->channelId, + start_bss_req->ssId.length, start_bss_req->rsnIE.length, + start_bss_req->nwType, opr_rates->numRates);) + + switch (start_bss_req->bssType) { + case eSIR_INFRASTRUCTURE_MODE: + /** + * Should not have received start BSS req with bssType + * Infrastructure on STA. + */ + lim_log(mac_ctx, LOGE, + FL("Invalid bssType %d in eWNI_SME_START_BSS_REQ"), + start_bss_req->bssType); + return false; + break; + case eSIR_IBSS_MODE: + break; + case eSIR_BTAMP_STA_MODE: + break; + case eSIR_BTAMP_AP_MODE: + break; + case eSIR_INFRA_AP_MODE: + break; + default: + /** + * Should not have received start BSS req with bssType + * other than Infrastructure/IBSS. + */ + lim_log(mac_ctx, LOGW, + FL("Invalid bssType %d in eWNI_SME_START_BSS_REQ"), + start_bss_req->bssType); + return false; + } + + if (start_bss_req->bssType == eSIR_IBSS_MODE + && (!start_bss_req->ssId.length + || start_bss_req->ssId.length > SIR_MAC_MAX_SSID_LENGTH)) { + lim_log(mac_ctx, LOGW, + FL("Invalid SSID length in eWNI_SME_START_BSS_REQ")); + return false; + } + + if (!lim_is_rsn_ie_valid_in_sme_req_message(mac_ctx, + &start_bss_req->rsnIE)) + return false; + + if (start_bss_req->nwType != eSIR_11A_NW_TYPE + && start_bss_req->nwType != eSIR_11B_NW_TYPE + && start_bss_req->nwType != eSIR_11G_NW_TYPE) + return false; + + if (start_bss_req->nwType == eSIR_11A_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsArate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11A rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; + } + /* check if all the rates in the opr rate set are legal 11G rates */ + if (start_bss_req->nwType == eSIR_11G_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsGrate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11G rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; + } + + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsBrate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11B rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; +} + +/** + * lim_is_sme_join_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_JOIN_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pJoinReq Pointer to received SME_JOIN_REQ message + * @return true when received SME_JOIN_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal pMac, tpSirSmeJoinReq pJoinReq) +{ + uint8_t valid = true; + + if (!lim_is_rsn_ie_valid_in_sme_req_message(pMac, &pJoinReq->rsnIE)) { + lim_log(pMac, LOGE, + FL("received SME_JOIN_REQ with invalid RSNIE")); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEScan)) { + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with invalid additional IE for scan")); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEAssoc)) { + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with invalid additional IE for assoc")); + valid = false; + goto end; + } + + if (!lim_is_bss_descr_valid_in_sme_req_message(pMac, &pJoinReq->bssDescription)) { + /* / Received eWNI_SME_JOIN_REQ with invalid BSS Info */ + /* Log the event */ + lim_log(pMac, LOGE, + FL("received SME_JOIN_REQ with invalid bssInfo")); + + valid = false; + goto end; + } + + /* + Reject Join Req if the Self Mac Address and + the Ap's Mac Address is same + */ + if (cdf_mem_compare((uint8_t *) pJoinReq->selfMacAddr, + (uint8_t *) pJoinReq->bssDescription.bssId, + (uint8_t) (sizeof(tSirMacAddr)))) { + /* Log the event */ + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with Self Mac and BSSID Same")); + + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_sme_join_req_valid() ***/ + +/** + * lim_is_sme_disassoc_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocReq Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_REQ is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_req_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocReq pDisassocReq, + tpPESession psessionEntry) +{ + if (lim_is_group_addr(pDisassocReq->peerMacAddr) && + !lim_is_addr_bc(pDisassocReq->peerMacAddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_req_valid() ***/ + +/** + * lim_is_sme_disassoc_cnf_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_CNF message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocCnf Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_CNF is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocCnf pDisassocCnf, + tpPESession psessionEntry) +{ + if (lim_is_group_addr(pDisassocCnf->peerMacAddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_cnf_valid() ***/ + +/** + * lim_is_sme_deauth_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DEAUTH_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDeauthReq Pointer to received SME_DEAUTH_REQ message + * @return true When received SME_DEAUTH_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_deauth_req_valid(tpAniSirGlobal pMac, tpSirSmeDeauthReq pDeauthReq, + tpPESession psessionEntry) +{ + if (lim_is_group_addr(pDeauthReq->peerMacAddr) && + !lim_is_addr_bc(pDeauthReq->peerMacAddr)) + return false; + + return true; +} /*** end lim_is_sme_deauth_req_valid() ***/ + +/** + * lim_is_sme_scan_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_SCAN_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pScanReq Pointer to received SME_SCAN_REQ message + * @return true when received SME_SCAN_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_scan_req_valid(tpAniSirGlobal pMac, tpSirSmeScanReq pScanReq) +{ + uint8_t valid = true; + uint8_t i = 0; + + if (pScanReq->numSsid > SIR_SCAN_MAX_NUM_SSID) { + valid = false; + lim_log(pMac, LOGE, + FL("Number of SSIDs > SIR_SCAN_MAX_NUM_SSID")); + goto end; + } + + for (i = 0; i < pScanReq->numSsid; i++) { + if (pScanReq->ssId[i].length > SIR_MAC_MAX_SSID_LENGTH) { + lim_log(pMac, LOGE, + FL + ("Requested SSID length > SIR_MAC_MAX_SSID_LENGTH")); + valid = false; + goto end; + } + } + if ((pScanReq->bssType < 0) || (pScanReq->bssType > eSIR_AUTO_MODE)) { + lim_log(pMac, LOGE, FL("Invalid BSS Type")); + valid = false; + } + if (lim_is_group_addr(pScanReq->bssId) && !lim_is_addr_bc(pScanReq->bssId)) { + valid = false; + lim_log(pMac, LOGE, + FL("BSSID is group addr and is not Broadcast Addr")); + } + if (! + (pScanReq->scanType == eSIR_PASSIVE_SCAN + || pScanReq->scanType == eSIR_ACTIVE_SCAN)) { + valid = false; + lim_log(pMac, LOGE, FL("Invalid Scan Type")); + } + if (pScanReq->channelList.numChannels > SIR_MAX_NUM_CHANNELS) { + valid = false; + lim_log(pMac, LOGE, + FL("Number of Channels > SIR_MAX_NUM_CHANNELS")); + } + + /* + ** check min/max channelTime range + **/ + if (valid) { + if ((pScanReq->scanType == eSIR_ACTIVE_SCAN) && + (pScanReq->maxChannelTime < pScanReq->minChannelTime)) { + lim_log(pMac, LOGE, + FL("Max Channel Time < Min Channel Time")); + valid = false; + goto end; + } + } + +end: + return valid; +} /*** end lim_is_sme_scan_req_valid() ***/ + +/** + * lim_is_sme_set_context_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_SET_CONTEXT_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_SET_CONTEXT_REQ message + * @return true when received SME_SET_CONTEXT_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_set_context_req_valid(tpAniSirGlobal pMac, + tpSirSmeSetContextReq pSetContextReq) +{ + uint8_t i = 0; + uint8_t valid = true; + tpSirKeys pKey = pSetContextReq->keyMaterial.key; + + if ((pSetContextReq->keyMaterial.edType != eSIR_ED_WEP40) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_WEP104) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_NONE) && +#ifdef FEATURE_WLAN_WAPI + (pSetContextReq->keyMaterial.edType != eSIR_ED_WPI) && +#endif + !pSetContextReq->keyMaterial.numKeys) { + /** + * No keys present in case of TKIP or CCMP + * Log error. + */ + lim_log(pMac, LOGW, + FL + ("No keys present in SME_SETCONTEXT_REQ for edType=%d"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.numKeys && + (pSetContextReq->keyMaterial.edType == eSIR_ED_NONE)) { + /** + * Keys present in case of no ED policy + * Log error. + */ + lim_log(pMac, LOGW, + FL("Keys present in SME_SETCONTEXT_REQ for edType=%d"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.edType >= eSIR_ED_NOT_IMPLEMENTED) { + /** + * Invalid edType in the message + * Log error. + */ + lim_log(pMac, LOGW, + FL("Invalid edType=%d in SME_SETCONTEXT_REQ"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } else if (pSetContextReq->keyMaterial.edType > eSIR_ED_NONE) { + uint32_t poi; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &poi) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve POI from CFG")); + } + + if (!poi) { + /** + * Privacy is not enabled + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + PELOG1(lim_log(pMac, LOG1, + FL + ("Privacy is not enabled, yet non-None EDtype=%d in SME_SETCONTEXT_REQ"), + pSetContextReq->keyMaterial.edType); + ) + } + } + + for (i = 0; i < pSetContextReq->keyMaterial.numKeys; i++) { + if (((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP40) && + (pKey->keyLength != 5)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP104) && + (pKey->keyLength != 13)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_TKIP) && + (pKey->keyLength != 32)) || +#ifdef FEATURE_WLAN_WAPI + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WPI) && + (pKey->keyLength != 32)) || +#endif + ((pSetContextReq->keyMaterial.edType == eSIR_ED_CCMP) && + (pKey->keyLength != 16))) { + /** + * Invalid key length for a given ED type + * Log error. + */ + lim_log(pMac, LOGW, + FL + ("Invalid keyLength =%d for edType=%d in SME_SETCONTEXT_REQ"), + pKey->keyLength, + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + pKey++; + } + +end: + return valid; +} /*** end lim_is_sme_set_context_req_valid() ***/ + +/** + * lim_is_sme_stop_bss_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_STOP_BSS_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_STOP_BSS_REQ message + * @return true when received SME_STOP_BSS_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *pMsg) +{ + uint8_t valid = true; + + return valid; +} /*** end lim_is_sme_stop_bss_req_valid() ***/ + +/** + * lim_get_bss_id_from_sme_join_req_msg() + * + ***FUNCTION: + * This function is called in various places to get BSSID + * from BSS description/Neighbor BSS Info in the SME_JOIN_REQ/ + * SME_REASSOC_REQ message. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBuf - Pointer to received SME_JOIN/SME_REASSOC_REQ + * message + * @return pBssId - Pointer to BSSID + */ + +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *pBuf) +{ + if (!pBuf) + return NULL; + + pBuf += sizeof(uint32_t); /* skip message header */ + + pBuf += lim_get_u16(pBuf) + sizeof(uint16_t); /* skip RSN IE */ + + pBuf += sizeof(uint16_t); /* skip length of BSS description */ + + return (pBuf); +} /*** end lim_get_bss_id_from_sme_join_req_msg() ***/ diff --git a/core/mac/src/pe/lim/lim_sme_req_utils.h b/core/mac/src/pe/lim/lim_sme_req_utils.h new file mode 100644 index 0000000000..7e89373ad2 --- /dev/null +++ b/core/mac/src/pe/lim/lim_sme_req_utils.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011-2012,2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sme_req_utils.h contains the utility definitions + * LIM uses while processing SME request messsages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SME_REQ_UTILS_H +#define __LIM_SME_REQ_UTILS_H + +#include "sir_api.h" +#include "lim_types.h" + +/* LIM SME request messages related utility functions */ +uint8_t lim_is_sme_start_bss_req_valid(tpAniSirGlobal, tpSirSmeStartBssReq); +uint8_t lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal, + tpSirRSNie, tpPESession); +uint8_t lim_is_sme_scan_req_valid(tpAniSirGlobal, tpSirSmeScanReq); +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal, tpSirSmeJoinReq); +uint8_t lim_is_sme_disassoc_req_valid(tpAniSirGlobal, tpSirSmeDisassocReq, + tpPESession); +uint8_t lim_is_sme_deauth_req_valid(tpAniSirGlobal, tpSirSmeDeauthReq, tpPESession); +uint8_t lim_is_sme_set_context_req_valid(tpAniSirGlobal, tpSirSmeSetContextReq); +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *); +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *); +uint8_t lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal, tpSirSmeDisassocCnf, + tpPESession); + +#endif /* __LIM_SME_REQ_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_sta_hash_api.c b/core/mac/src/pe/lim/lim_sta_hash_api.c new file mode 100644 index 0000000000..794ebaad07 --- /dev/null +++ b/core/mac/src/pe/lim/lim_sta_hash_api.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_sta_hash_api.c: Provides access functions to get/set values of station hash entry fields. + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ + +#include "lim_sta_hash_api.h" + +/** + * lim_get_sta_hash_bssidx() + * + ***FUNCTION: + * This function is called to Get the Bss Index of the currently associated Station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param assocId AssocID of the Station. + * @param bssidx pointer to the bss index, which will be returned by the function. + * + * @return success if GET operation is ok, else Failure. + */ + +tSirRetStatus lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry) +{ + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if (pSta == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA %d"), assocId);) + return eSIR_LIM_INVALID_STA; + } + + *bssidx = (uint8_t) pSta->bssId; + return eSIR_SUCCESS; +} diff --git a/core/mac/src/pe/lim/lim_sta_hash_api.h b/core/mac/src/pe/lim/lim_sta_hash_api.h new file mode 100644 index 0000000000..9a34091ad3 --- /dev/null +++ b/core/mac/src/pe/lim/lim_sta_hash_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sta_hash_api.h contains the + * function prototypes for accessing station hash entry fields. + * + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_STA_HASH_API_H__ +#define __LIM_STA_HASH_API_H__ + +#include "ani_global.h" +#include "lim_types.h" + +tSirRetStatus lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry); + +#endif diff --git a/core/mac/src/pe/lim/lim_timer_utils.c b/core/mac/src/pe/lim/lim_timer_utils.c new file mode 100644 index 0000000000..f68f7b08bb --- /dev/null +++ b/core/mac/src/pe/lim/lim_timer_utils.c @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_timer_utils.cc contains the utility functions + * LIM uses for handling various timers. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" + +/* channel Switch Timer in ticks */ +#define LIM_CHANNEL_SWITCH_TIMER_TICKS 1 +/* Lim Quite timer in ticks */ +#define LIM_QUIET_TIMER_TICKS 100 +/* Lim Quite BSS timer interval in ticks */ +#define LIM_QUIET_BSS_TIMER_TICK 100 +/* Lim KeepAlive timer default (3000)ms */ +#define LIM_KEEPALIVE_TIMER_MS 3000 +/* Lim JoinProbeRequest Retry timer default (200)ms */ +#define LIM_JOIN_PROBE_REQ_TIMER_MS 200 + +/* This timer is a periodic timer which expires at every 1 sec to + convert ACTIVE DFS channel to DFS channels */ +#define ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT 1000 + +static bool +lim_create_non_ap_timers(tpAniSirGlobal pMac) +{ + uint32_t cfgValue; + /* Create Channel Switch Timer */ + if (tx_timer_create(&pMac->lim.limTimers.gLimChannelSwitchTimer, + "CHANNEL SWITCH TIMER", + lim_channel_switch_timer_handler, 0, + LIM_CHANNEL_SWITCH_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Ch Switch timer")); + return false; + } + /* Create Quiet Timer + * This is used on the STA to go and shut-off Tx/Rx "after" the + * specified quiteInterval + */ + if (tx_timer_create(&pMac->lim.limTimers.gLimQuietTimer, + "QUIET TIMER", lim_quiet_timer_handler, + SIR_LIM_QUIET_TIMEOUT, LIM_QUIET_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Quiet Begin Timer")); + return false; + } + /* Create Quiet BSS Timer + * After the specified quiteInterval, determined by gLimQuietTimer, this + * timer, gLimQuietBssTimer, trigger and put the STA to sleep for the + * specified gLimQuietDuration + */ + if (tx_timer_create(&pMac->lim.limTimers.gLimQuietBssTimer, + "QUIET BSS TIMER", lim_quiet_bss_timer_handler, + SIR_LIM_QUIET_BSS_TIMEOUT, LIM_QUIET_BSS_TIMER_TICK, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Quiet Bss Timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve JoinFailureTimeout value")); + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Join failure timer and activate it later */ + if (tx_timer_create(&pMac->lim.limTimers.gLimJoinFailureTimer, + "JOIN FAILURE TIMEOUT", + lim_timer_handler, SIR_LIM_JOIN_FAIL_TIMEOUT, + cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + /* / Could not create Join failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not create Join failure timer")); + return false; + } + /* Send unicast probe req frame every 200 ms */ + if (tx_timer_create(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, + "Periodic Join Probe Request Timer", + lim_timer_handler, + SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT, + SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS), 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Periodic Join Probe Request tmr")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve AssocFailureTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(&pMac->lim.limTimers.gLimAssocFailureTimer, + "ASSOC FAILURE TIMEOUT", + lim_assoc_failure_timer_handler, LIM_ASSOC, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Association failure timer")); + return false; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve ReassocFailureTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Association failure timer and activate it later */ + if (tx_timer_create + (&pMac->lim.limTimers.gLimReassocFailureTimer, + "REASSOC FAILURE TIMEOUT", lim_assoc_failure_timer_handler, + LIM_REASSOC, cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Reassociation failure timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &cfgValue) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("Fail to get WNI_CFG_ADDTS_RSP_TIMEOUT ")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + + /* Create Addts response timer and activate it later */ + if (tx_timer_create(&pMac->lim.limTimers.gLimAddtsRspTimer, + "ADDTS RSP TIMEOUT", + lim_addts_response_timer_handler, + SIR_LIM_ADDTS_RSP_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Addts response timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve AuthFailureTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Auth failure timer and activate it later */ + if (tx_timer_create(&pMac->lim.limTimers.gLimAuthFailureTimer, + "AUTH FAILURE TIMEOUT", + lim_timer_handler, + SIR_LIM_AUTH_FAIL_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not create Auth failure timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value")); + + /* Change timer to reactivate it in future */ + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimProbeAfterHBTimer, + "Probe after Heartbeat TIMEOUT", + lim_timer_handler, + SIR_LIM_PROBE_HB_FAILURE_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("unable to create ProbeAfterHBTimer")); + return false; + } + + return true; +} +/** + * lim_create_timers() + * + * @pMac : Pointer to Global MAC structure + * + * This function is called upon receiving + * 1. SME_START_REQ for STA in ESS role + * 2. SME_START_BSS_REQ for AP role & STA in IBSS role + * + * @return : status of operation + */ + +uint32_t lim_create_timers(tpAniSirGlobal pMac) +{ + uint32_t cfgValue, i = 0; + uint32_t cfgValue1; + + PELOG1(lim_log(pMac, LOG1, + FL("Creating Timers used by LIM module in Role %d"), + pMac->lim.gLimSystemRole);) + + if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + &cfgValue) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not retrieve MinChannelTimeout value")); + } + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Periodic probe request timer value is half of the Min channel + * timer. Probe request sends periodically till min/max channel + * timer expires + */ + cfgValue1 = cfgValue / 2; + /* Create periodic probe request timer and activate them later */ + if (cfgValue1 >= 1 + && (tx_timer_create(&pMac->lim.limTimers.gLimPeriodicProbeReqTimer, + "Periodic Probe Request Timer", lim_timer_handler, + SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT, cfgValue1, 0, + TX_NO_ACTIVATE) != TX_SUCCESS)) { + lim_log(pMac, LOGP, + FL("could not create periodic probe timer")); + goto err_timer; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve MAXChannelTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Limiting max numm of probe req for each channel scan */ + pMac->lim.maxProbe = (cfgValue / cfgValue1); + + if (pMac->lim.gLimSystemRole != eLIM_AP_ROLE) + if (false == lim_create_non_ap_timers(pMac)) + goto err_timer; + + cfgValue = SYS_MS_TO_TICKS(LIM_HASH_MISS_TIMER_MS); + + if (tx_timer_create( + &pMac->lim.limTimers.gLimSendDisassocFrameThresholdTimer, + "Disassoc throttle TIMEOUT", + lim_send_disassoc_frame_threshold_handler, + SIR_LIM_HASH_MISS_THRES_TIMEOUT, cfgValue, cfgValue, + TX_AUTO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("create Disassociate throttle timer failed")); + goto err_timer; + } + PELOG1(lim_log(pMac, LOG1, FL("Created Disassociate throttle timer "));) + + /* Create all CNF_WAIT Timers upfront */ + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, &cfgValue) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("could not retrieve CNF timeout value")); + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (i = 0; i < (pMac->lim.maxStation + 1); i++) { + if (tx_timer_create(&pMac->lim.limTimers.gpLimCnfWaitTimer[i], + "CNF_MISS_TIMEOUT", + lim_cnf_wait_tmer_handler, + (uint32_t) i, cfgValue, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("Cannot create CNF wait timer")); + goto err_timer; + } + } + + /* Alloc and init table for the preAuth timer list */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_NUM_PRE_AUTH, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("could not retrieve mac preauth value")); + pMac->lim.gLimPreAuthTimerTable.numEntry = cfgValue; + pMac->lim.gLimPreAuthTimerTable.pTable = + cdf_mem_malloc(cfgValue * sizeof(tLimPreAuthNode)); + + if (pMac->lim.gLimPreAuthTimerTable.pTable == NULL) { + lim_log(pMac, LOGP, FL("AllocateMemory failed!")); + goto err_timer; + } + + lim_init_pre_auth_timer_table(pMac, &pMac->lim.gLimPreAuthTimerTable); + PELOG1(lim_log(pMac, LOG1, + FL("alloc and init table for preAuth timers"));) + + if (wlan_cfg_get_int(pMac, WNI_CFG_OLBC_DETECT_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve OLBD detect timeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer, + "OLBC UPDATE CACHE TIMEOUT", + lim_update_olbc_cache_timer_handler, + SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT, cfgValue, + cfgValue, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("Cannot create update OLBC cache tmr")); + goto err_timer; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + /* In future we need to use the auth timer, cause the pre auth session + * will be introduced before sending Auth frame. We need to go off + * channel and come back to home channel + */ + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimFTPreAuthRspTimer, + "FT PREAUTH RSP TIMEOUT", + lim_timer_handler, SIR_LIM_FT_PREAUTH_RSP_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not create Join failure timer")); + goto err_timer; + } +#endif + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimRemainOnChannelTimer, + "FT PREAUTH RSP TIMEOUT", + lim_timer_handler, SIR_LIM_REMAIN_CHN_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not create Join failure timer")); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimDisassocAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DISASSOC_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not DISASSOC ACK TIMEOUT timer")); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(&pMac->lim.limTimers.gLimDeauthAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DEAUTH_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create DEAUTH ACK TIMEOUT timer")); + goto err_timer; + } + + /* (> no of BI* no of TUs per BI * 1TU in msec + + * p2p start time offset*1 TU in msec = 2*100*1.024 + 5*1.024 + * = 204.8 + 5.12 = 209.20) + */ + cfgValue = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create( + &pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer, + "Single Shot NOA Insert timeout", lim_timer_handler, + SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT, cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Can't create Single Shot NOA Insert Timeout tmr")); + goto err_timer; + } + + cfgValue = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create( + &pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, + "ACTIVE TO PASSIVE CHANNEL", lim_timer_handler, + SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE, cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGW, + FL("could not create timer for passive channel to active channel")); + goto err_timer; + } + + return TX_SUCCESS; + +err_timer: + tx_timer_delete(&pMac->lim.limTimers.gLimDeauthAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimDisassocAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimRemainOnChannelTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimFTPreAuthRspTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer); + while (((int32_t)-- i) >= 0) { + tx_timer_delete(&pMac->lim.limTimers.gpLimCnfWaitTimer[i]); + } + tx_timer_delete(&pMac->lim.limTimers. + gLimSendDisassocFrameThresholdTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAuthFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAddtsRspTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimReassocFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAssocFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimJoinFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietBssTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimChannelSwitchTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicProbeReqTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer); + + if (NULL != pMac->lim.gLimPreAuthTimerTable.pTable) { + cdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->lim.gLimPreAuthTimerTable.pTable = NULL; + } + return TX_TIMER_ERROR; +} /****** end lim_create_timers() ******/ + +/** + * lim_timer_handler() + * + ***FUNCTION: + * This function is called upon + * 1. MIN_CHANNEL, MAX_CHANNEL timer expiration during scanning + * 2. JOIN_FAILURE timer expiration while joining a BSS + * 3. AUTH_FAILURE timer expiration while authenticating with a peer + * 4. Heartbeat timer expiration on STA + * 5. Background scan timer expiration on STA + * 6. AID release, Pre-auth cleanup and Link monitoring timer + * expiration on AP + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - Message corresponding to the timer that expired + * + * @return None + */ + +void lim_timer_handler(void *pMacGlobal, uint32_t param) +{ + uint32_t statusCode; + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = (uint16_t) param; + msg.bodyptr = NULL; + msg.bodyval = 0; + + if ((statusCode = lim_post_msg_api(pMac, &msg)) != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("posting message %X to LIM failed, reason=%d"), + msg.type, statusCode); +} /****** end lim_timer_handler() ******/ + +/** + * lim_addts_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Addts response timer expiration on sta + * + ***LOGIC: + * Message SIR_LIM_ADDTS_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_addts_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_ADDTS_RSP_TIMEOUT; + msg.bodyval = param; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_auth_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Auth response timer expiration on AP + * + ***LOGIC: + * Message SIR_LIM_AUTH_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_auth_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_AUTH_RSP_TIMEOUT; + msg.bodyptr = NULL; + msg.bodyval = (uint32_t) param; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_assoc_failure_timer_handler() + * + * @mac_global : Pointer to Global MAC structure + * @param : Indicates whether this is assoc or reassoc failure timeout + * + * This function is called upon Re/Assoc failure timer expiration on STA. + * Message SIR_LIM_ASSOC_FAIL_TIMEOUT is posted to gSirLimMsgQ when this + * function is executed. + * + * Return void + */ +void lim_assoc_failure_timer_handler(void *mac_global, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal) mac_global; + tpPESession session = NULL; + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + session = mac_ctx->lim.pSessionEntry; + if (LIM_REASSOC == param && NULL != session + && session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE) { + lim_log(mac_ctx, LOGE, FL("Reassoc timeout happened")); + if (mac_ctx->lim.reAssocRetryAttempt < + LIM_MAX_REASSOC_RETRY_LIMIT) { + lim_send_retry_reassoc_req_frame(mac_ctx, + session->pLimMlmReassocRetryReq, session); + mac_ctx->lim.reAssocRetryAttempt++; + lim_log(mac_ctx, LOGW, + FL("Reassoc request retry is sent %d times"), + mac_ctx->lim.reAssocRetryAttempt); + return; + } else { + lim_log(mac_ctx, LOGW, + FL("Reassoc request retry MAX(%d) reached"), + LIM_MAX_REASSOC_RETRY_LIMIT); + if (NULL != session->pLimMlmReassocRetryReq) { + cdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + } + } +#endif + /* Prepare and post message to LIM Message Queue */ + msg.type = SIR_LIM_ASSOC_FAIL_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + lim_post_msg_api(mac_ctx, &msg); +} /****** end lim_assoc_failure_timer_handler() ******/ + +/** + * lim_update_olbc_cache_timer_handler() + * + ***FUNCTION: + * This function is called upon update olbc cache timer expiration + * on STA + * + ***LOGIC: + * Message SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ +void lim_update_olbc_cache_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT; + msg.bodyval = 0; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_update_olbc_cache_timer_handler() ******/ + +/** + * lim_deactivate_and_change_timer() + * + ***FUNCTION: + * This function is called to deactivate and change a timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * + * @return None + */ + +void lim_deactivate_and_change_timer(tpAniSirGlobal pMac, uint32_t timerId) +{ + uint32_t val = 0; + + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, timerId)); + + switch (timerId) { + case eLIM_ADDTS_RSP_TIMER: + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer) + != TX_SUCCESS) { + /* Could not deactivate AddtsRsp Timer */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate AddtsRsp timer")); + } + break; + + case eLIM_PERIODIC_PROBE_REQ_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimPeriodicProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate min channel timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate periodic timer")); + } + + val = + SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTime) / + 2; + if (tx_timer_change + (&pMac->lim.limTimers.gLimPeriodicProbeReqTimer, val, + 0) != TX_SUCCESS) { + /* Could not change min channel timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to change periodic timer")); + } + + break; + + case eLIM_JOIN_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimJoinFailureTimer) + != TX_SUCCESS) { + /** + * Could not deactivate Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, + FL("Unable to deactivate Join Failure timer")); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get JoinFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve JoinFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimJoinFailureTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, + FL("Unable to change Join Failure timer")); + } + + break; + + case eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate periodic join req Times. */ + lim_log(pMac, LOGP, + FL + ("Unable to deactivate periodic join request timer")); + } + + val = SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS); + if (tx_timer_change + (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, val, + 0) != TX_SUCCESS) { + /* Could not change periodic join req times. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("Unable to change periodic join request timer")); + } + + break; + + case eLIM_AUTH_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimAuthFailureTimer) + != TX_SUCCESS) { + /* Could not deactivate Auth failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate auth failure timer")); + } + /* Change timer to reactivate it in future */ + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get AuthFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve AuthFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimAuthFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Authentication failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change Auth failure timer")); + } + + break; + + case eLIM_ASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimAssocFailureTimer) != + TX_SUCCESS) { + /* Could not deactivate Association failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to deactivate Association failure timer")); + } + /* Change timer to reactivate it in future */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get AssocFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve AssocFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimAssocFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Association failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change Assoc failure timer")); + } + + break; + + case eLIM_REASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimReassocFailureTimer) != + TX_SUCCESS) { + /* Could not deactivate Reassociation failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to deactivate Reassoc failure timer")); + } + /* Change timer to reactivate it in future */ + if (wlan_cfg_get_int(pMac, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve ReassocFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimReassocFailureTimer, val, + 0) != TX_SUCCESS) { + /* Could not change Reassociation failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to change Reassociation failure timer")); + } + + break; + + case eLIM_PROBE_AFTER_HB_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimProbeAfterHBTimer) != + TX_SUCCESS) { + /* Could not deactivate Heartbeat timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to deactivate probeAfterHBTimer")); + } else { + lim_log(pMac, LOG1, + FL("Deactivated probe after hb timer")); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get PROBE_AFTER_HB_FAILURE + * value from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value")); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimProbeAfterHBTimer, + val, 0) != TX_SUCCESS) { + /* Could not change HeartBeat timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change ProbeAfterHBTimer")); + } else { + lim_log(pMac, LOGW, + FL("Probe after HB timer value is changed = %u"), + val); + } + + break; + + case eLIM_LEARN_DURATION_TIMER: + break; + +#ifdef WLAN_FEATURE_VOWIFI_11R + case eLIM_FT_PREAUTH_RSP_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimFTPreAuthRspTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL + ("Unable to deactivate Preauth response Failure timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&pMac->lim.limTimers.gLimFTPreAuthRspTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, + FL("Unable to change Join Failure timer")); + return; + } + break; +#endif + case eLIM_REMAIN_CHN_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimRemainOnChannelTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Remain on Chn timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimRemainOnChannelTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Active to passive channel timer. + ** Log error. + **/ + lim_log(pMac, LOGP, FL("Unable to Deactivate " + "Active to passive channel timer")); + return; + } + val = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change timer to check scan type for passive channel. + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_DISASSOC_ACK_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimDisassocAckTimer) != TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Disassoc ack timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&pMac->lim.limTimers.gLimDisassocAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_DEAUTH_ACK_TIMER: + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimDeauthAckTimer) + != TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Deauth ack timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&pMac->lim.limTimers.gLimDeauthAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_INSERT_SINGLESHOT_NOA_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate SingleShot NOA Insert + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL + ("Unable to deactivate SingleShot NOA Insert timer")); + return; + } + val = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change Single Shot NOA Insert + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + default: + /* Invalid timerId. Log error */ + break; + } +} /****** end lim_deactivate_and_change_timer() ******/ + +/** + * lim_deactivate_and_change_per_sta_id_timer() + * + * + * @brief: This function is called to deactivate and change a per STA timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + * @note staId for eLIM_AUTH_RSP_TIMER is auth Node Index. + * + * @param pMac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * @param staId - staId + * + * @return None + */ + +void +lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal pMac, uint32_t timerId, + uint16_t staId) +{ + uint32_t val; + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, timerId)); + + switch (timerId) { + case eLIM_CNF_WAIT_TIMER: + + if (tx_timer_deactivate + (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("unable to deactivate CNF wait timer")); + + } + /* Change timer to reactivate it in future */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get cnf timeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL("could not retrieve cnf timeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change + (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId], val, + val) != TX_SUCCESS) { + /* Could not change cnf timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change cnf wait timer")); + } + + break; + + case eLIM_AUTH_RSP_TIMER: + { + tLimPreAuthNode *pAuthNode; + + pAuthNode = + lim_get_pre_auth_node_from_index(pMac, + &pMac->lim. + gLimPreAuthTimerTable, + staId); + + if (pAuthNode == NULL) { + lim_log(pMac, LOGP, + FL("Invalid Pre Auth Index passed :%d"), + staId); + break; + } + + if (tx_timer_deactivate(&pAuthNode->timer) != + TX_SUCCESS) { + /* Could not deactivate auth response timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to deactivate auth response timer")); + } + /* Change timer to reactivate it in future */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get auth rsp timeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve auth response timeout value")); + } + + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pAuthNode->timer, val, 0) != + TX_SUCCESS) { + /* Could not change auth rsp timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change auth rsp timer")); + } + } + break; + + default: + /* Invalid timerId. Log error */ + break; + + } +} + +/** + * lim_activate_cnf_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param StaId - staId + * + * @return None + */ + +void lim_activate_cnf_timer(tpAniSirGlobal pMac, uint16_t staId, + tpPESession psessionEntry) +{ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_CNF_WAIT_TIMER)); + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId = + psessionEntry->peSessionId; + if (tx_timer_activate(&pMac->lim.limTimers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not activate cnf wait timer")); + } +} + +/** + * lim_activate_auth_rsp_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param id - id + * + * @return None + */ + +void lim_activate_auth_rsp_timer(tpAniSirGlobal pMac, tLimPreAuthNode *pAuthNode) +{ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, NO_SESSION, + eLIM_AUTH_RESP_TIMER)); + if (tx_timer_activate(&pAuthNode->timer) != TX_SUCCESS) { + /* / Could not activate auth rsp timer. */ + /* Log error */ + lim_log(pMac, LOGP, FL("could not activate auth rsp timer")); + } +} + +/** + * lim_send_disassoc_frame_threshold_handler() + * + ***FUNCTION: + * This function reloads the credit to the send disassociate frame bucket + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ + +void lim_send_disassoc_frame_threshold_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + uint32_t statusCode; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_HASH_MISS_THRES_TIMEOUT; + msg.bodyval = 0; + msg.bodyptr = NULL; + + if ((statusCode = lim_post_msg_api(pMac, &msg)) != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("posting to LIM failed, reason=%d"), statusCode); + +} + +/** + * limAssocCnfWaitTmerHandler() + * + ***FUNCTION: + * This function post a message to send a disassociate frame out. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ + +void lim_cnf_wait_tmer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + uint32_t statusCode; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_CNF_WAIT_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + if ((statusCode = lim_post_msg_api(pMac, &msg)) != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("posting to LIM failed, reason=%d"), statusCode); + +} + +void lim_channel_switch_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + PELOG1(lim_log(pMac, LOG1, + FL("ChannelSwitch Timer expired. Posting msg to LIM ")); + ) + + msg.type = SIR_LIM_CHANNEL_SWITCH_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + PELOG1(lim_log(pMac, LOG1, FL("Post SIR_LIM_QUIET_TIMEOUT msg. "));) + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_bss_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_BSS_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + PELOG1(lim_log(pMac, LOG1, FL("Post SIR_LIM_QUIET_BSS_TIMEOUT msg. "));) + lim_post_msg_api(pMac, &msg); +} + diff --git a/core/mac/src/pe/lim/lim_timer_utils.h b/core/mac/src/pe/lim/lim_timer_utils.h new file mode 100644 index 0000000000..b133d712f9 --- /dev/null +++ b/core/mac/src/pe/lim/lim_timer_utils.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_timer_utils.h contains the utility definitions + * LIM uses for timer handling. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_TIMER_UTILS_H +#define __LIM_TIMER_UTILS_H + +#include "lim_types.h" + +/* Timer related functions */ +enum { + eLIM_MIN_CHANNEL_TIMER, + eLIM_MAX_CHANNEL_TIMER, + eLIM_JOIN_FAIL_TIMER, + eLIM_AUTH_FAIL_TIMER, + eLIM_AUTH_RESP_TIMER, + eLIM_ASSOC_FAIL_TIMER, + eLIM_REASSOC_FAIL_TIMER, + eLIM_PRE_AUTH_CLEANUP_TIMER, + eLIM_CNF_WAIT_TIMER, + eLIM_AUTH_RSP_TIMER, + eLIM_UPDATE_OLBC_CACHE_TIMER, + eLIM_PROBE_AFTER_HB_TIMER, + eLIM_ADDTS_RSP_TIMER, + eLIM_CHANNEL_SWITCH_TIMER, + eLIM_LEARN_DURATION_TIMER, + eLIM_QUIET_TIMER, + eLIM_QUIET_BSS_TIMER, + eLIM_WPS_OVERLAP_TIMER, +#ifdef WLAN_FEATURE_VOWIFI_11R + eLIM_FT_PREAUTH_RSP_TIMER, +#endif + eLIM_REMAIN_CHN_TIMER, + eLIM_PERIODIC_PROBE_REQ_TIMER, +#ifdef FEATURE_WLAN_ESE + eLIM_TSM_TIMER, +#endif + eLIM_DISASSOC_ACK_TIMER, + eLIM_DEAUTH_ACK_TIMER, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER, + eLIM_INSERT_SINGLESHOT_NOA_TIMER, + eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE +}; + +#define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT 500 +#define LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE 500 + +/* Timer Handler functions */ +uint32_t lim_create_timers(tpAniSirGlobal); +void lim_timer_handler(void *, uint32_t); +void lim_auth_response_timer_handler(void *, uint32_t); +void lim_assoc_failure_timer_handler(void *, uint32_t); +void limReassocFailureTimerHandler(void *, uint32_t); + +void lim_deactivate_and_change_timer(tpAniSirGlobal, uint32_t); +void limDummyPktExpTimerHandler(void *, uint32_t); +void lim_send_disassoc_frame_threshold_handler(void *, uint32_t); +void lim_cnf_wait_tmer_handler(void *, uint32_t); +void lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal, uint32_t, uint16_t); +void lim_activate_cnf_timer(tpAniSirGlobal, uint16_t, tpPESession); +void lim_activate_auth_rsp_timer(tpAniSirGlobal, tLimPreAuthNode *); +void lim_update_olbc_cache_timer_handler(void *, uint32_t); +void lim_addts_response_timer_handler(void *, uint32_t); +void lim_channel_switch_timer_handler(void *, uint32_t); +void lim_quiet_timer_handler(void *, uint32_t); +void lim_quiet_bss_timer_handler(void *, uint32_t); +void limCBScanIntervalTimerHandler(void *, uint32_t); +void limCBScanDurationTimerHandler(void *, uint32_t); +#endif /* __LIM_TIMER_UTILS_H */ diff --git a/core/mac/src/pe/lim/lim_trace.c b/core/mac/src/pe/lim/lim_trace.c new file mode 100644 index 0000000000..3847127120 --- /dev/null +++ b/core/mac/src/pe/lim/lim_trace.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" /* for tpAniSirGlobal */ + +#include "lim_trace.h" +#include "lim_timer_utils.h" +#include "cdf_trace.h" + +#ifdef LIM_TRACE_RECORD +uint32_t g_mgmt_frame_stats[14]; + +#define LIM_TRACE_MAX_SUBTYPES 14 + +static uint8_t *__lim_trace_get_timer_string(uint16_t timerId) +{ + switch (timerId) { + CASE_RETURN_STRING(eLIM_MIN_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_MAX_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_JOIN_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RESP_TIMER); + CASE_RETURN_STRING(eLIM_ASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_REASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_PRE_AUTH_CLEANUP_TIMER); + CASE_RETURN_STRING(eLIM_CNF_WAIT_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RSP_TIMER); + CASE_RETURN_STRING(eLIM_UPDATE_OLBC_CACHE_TIMER); + CASE_RETURN_STRING(eLIM_PROBE_AFTER_HB_TIMER); + CASE_RETURN_STRING(eLIM_ADDTS_RSP_TIMER); + CASE_RETURN_STRING(eLIM_CHANNEL_SWITCH_TIMER); + CASE_RETURN_STRING(eLIM_LEARN_DURATION_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_BSS_TIMER); + CASE_RETURN_STRING(eLIM_WPS_OVERLAP_TIMER); +#ifdef WLAN_FEATURE_VOWIFI_11R + CASE_RETURN_STRING(eLIM_FT_PREAUTH_RSP_TIMER); +#endif + CASE_RETURN_STRING(eLIM_REMAIN_CHN_TIMER); + CASE_RETURN_STRING(eLIM_PERIODIC_PROBE_REQ_TIMER); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(eLIM_TSM_TIMER); +#endif + CASE_RETURN_STRING(eLIM_DISASSOC_ACK_TIMER); + CASE_RETURN_STRING(eLIM_DEAUTH_ACK_TIMER); + CASE_RETURN_STRING(eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + CASE_RETURN_STRING(eLIM_INSERT_SINGLESHOT_NOA_TIMER); + CASE_RETURN_STRING(eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE); + default: + return ("UNKNOWN"); + break; + } +} + +static uint8_t *__lim_trace_get_mgmt_drop_reason_string(uint16_t dropReason) +{ + + switch (dropReason) { + CASE_RETURN_STRING(eMGMT_DROP_INFRA_BCN_IN_IBSS); + CASE_RETURN_STRING(eMGMT_DROP_INVALID_SIZE); + CASE_RETURN_STRING(eMGMT_DROP_NON_SCAN_MODE_FRAME); + CASE_RETURN_STRING(eMGMT_DROP_NOT_LAST_IBSS_BCN); + CASE_RETURN_STRING(eMGMT_DROP_NO_DROP); + CASE_RETURN_STRING(eMGMT_DROP_SCAN_MODE_FRAME); + + default: + return ("UNKNOWN"); + break; + } +} + +void lim_trace_init(tpAniSirGlobal pMac) +{ + cdf_trace_register(CDF_MODULE_ID_PE, (tp_cdf_trace_cb) & lim_trace_dump); +} + +void lim_trace_dump(tpAniSirGlobal pMac, tp_cdf_trace_record pRecord, + uint16_t recIndex) +{ + + static char *frameSubtypeStr[LIM_TRACE_MAX_SUBTYPES] = { + "Association request", + "Association response", + "Reassociation request", + "Reassociation response", + "Probe request", + "Probe response", + NULL, + NULL, + "Beacon", + "ATIM", + "Disassociation", + "Authentication", + "Deauthentication", + "Action" + }; + + switch (pRecord->code) { + case TRACE_CODE_MLM_STATE: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "MLM State:", + lim_trace_get_mlm_state_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_SME_STATE: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "SME State:", + lim_trace_get_sme_state_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TX_MGMT: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "TX Mgmt:", + frameSubtypeStr[pRecord->data], pRecord->data); + break; + + case TRACE_CODE_RX_MGMT: + if (LIM_TRACE_MAX_SUBTYPES <= + LIM_TRACE_GET_SUBTYPE(pRecord->data)) { + lim_log(pMac, LOGE, "Wrong Subtype - %d", + LIM_TRACE_GET_SUBTYPE(pRecord->data)); + } else { + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(%d) SN: %d ", + recIndex, pRecord->time, pRecord->session, + "RX Mgmt:", + frameSubtypeStr[LIM_TRACE_GET_SUBTYPE + (pRecord->data)], + LIM_TRACE_GET_SUBTYPE(pRecord->data), + LIM_TRACE_GET_SSN(pRecord->data)); + } + break; + case TRACE_CODE_RX_MGMT_DROP: + lim_log(pMac, LOGE, "%04d %012llu S%d %-14s %-30s(%d) ", + recIndex, pRecord->time, pRecord->session, + "Drop RX Mgmt:", + __lim_trace_get_mgmt_drop_reason_string((uint16_t) pRecord-> + data), pRecord->data); + break; + + case TRACE_CODE_RX_MGMT_TSF: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s0x%x(%d) ", + recIndex, pRecord->time, pRecord->session, + "RX Mgmt TSF:", " ", pRecord->data, pRecord->data); + break; + + case TRACE_CODE_TX_COMPLETE: + lim_log(pMac, LOGE, "%04d %012llu S%d %-14s %d ", recIndex, + pRecord->time, pRecord->session, "TX Complete", + pRecord->data); + break; + + case TRACE_CODE_TX_SME_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "TX SME Msg:", + mac_trace_get_sme_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_SME_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED(pRecord-> + data) ? "Def/Drp LIM Msg:" + : "RX Sme Msg:", + mac_trace_get_sme_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_WMA_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "TX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_RX_WMA_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED(pRecord-> + data) ? "Def/Drp LIM Msg:" + : "RX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_LIM_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "TX LIM Msg:", + mac_trace_get_lim_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_LIM_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED(pRecord-> + data) ? "Def/Drp LIM Msg:" + : "RX LIM Msg", + mac_trace_get_lim_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TX_CFG_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "TX CFG Msg:", + mac_trace_get_cfg_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_CFG_MSG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED(pRecord-> + data) ? "Def/Drp LIM Msg:" + : "RX CFG Msg:", + mac_trace_get_cfg_msg_string((uint16_t) + MAC_TRACE_GET_MSG_ID(pRecord-> + data)), + pRecord->data); + break; + + case TRACE_CODE_TIMER_ACTIVATE: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "Timer Actvtd", + __lim_trace_get_timer_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TIMER_DEACTIVATE: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->time, pRecord->session, "Timer DeActvtd", + __lim_trace_get_timer_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_INFO_LOG: + lim_log(pMac, LOGE, + "%04d %012llu S%d %-14s %-30s(0x%x) \n", + recIndex, pRecord->time, pRecord->session, + "INFORMATION_LOG", + mac_trace_get_info_log_string((uint16_t) pRecord->data), + pRecord->data); + break; + default: + lim_log(pMac, LOGE, "%04d %012llu S%d %-14s(%d) (0x%x) ", + recIndex, pRecord->time, pRecord->session, + "Unknown Code", pRecord->code, pRecord->data); + break; + } +} + +void mac_trace_msg_tx(tpAniSirGlobal pMac, uint8_t session, uint32_t data) +{ + + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(pMac, TRACE_CODE_TX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_TX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace_new(pMac, module, TRACE_CODE_TX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_TX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +/* + * bit31: Rx message defferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx(tpAniSirGlobal pMac, uint8_t session, uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(pMac, TRACE_CODE_RX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_RX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +/* + * bit31: Rx message defferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace_new(pMac, module, TRACE_CODE_RX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_RX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState) +{ + switch (mlmState) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_LEARN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_BSS_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_BCASTKEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_MIMOPS_STATE); + default: + return ("UNKNOWN"); + break; + } +} + +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState) +{ + switch (smeState) { + + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_LINK_FAIL_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + default: + return ("UNKNOWN"); + break; + } +} + +#endif diff --git a/core/mac/src/pe/lim/lim_types.h b/core/mac/src/pe/lim/lim_types.h new file mode 100644 index 0000000000..715e7751e7 --- /dev/null +++ b/core/mac/src/pe/lim/lim_types.h @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_types.h contains the definitions used by all + * all LIM modules. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_TYPES_H +#define __LIM_TYPES_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_common.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" + +#include "lim_api.h" +#include "lim_debug.h" +#include "lim_send_sme_rsp_messages.h" +#include "sys_global.h" +#include "dph_global.h" +#include "parser_api.h" +#include "wma_if.h" + +#define LINK_TEST_DEFER 1 + +#define TRACE_EVENT_CNF_TIMER_DEACT 0x6600 +#define TRACE_EVENT_CNF_TIMER_ACT 0x6601 +#define TRACE_EVENT_AUTH_RSP_TIMER_DEACT 0x6602 +#define TRACE_EVENT_AUTH_RSP_TIMER_ACT 0x6603 + +/* MLM message types */ +#define LIM_MLM_MSG_START 1000 +#define LIM_MLM_SCAN_REQ LIM_MLM_MSG_START +#define LIM_MLM_SCAN_CNF (LIM_MLM_MSG_START + 1) +#define LIM_MLM_START_REQ (LIM_MLM_MSG_START + 2) +#define LIM_MLM_START_CNF (LIM_MLM_MSG_START + 3) +#define LIM_MLM_JOIN_REQ (LIM_MLM_MSG_START + 4) +#define LIM_MLM_JOIN_CNF (LIM_MLM_MSG_START + 5) +#define LIM_MLM_AUTH_REQ (LIM_MLM_MSG_START + 6) +#define LIM_MLM_AUTH_CNF (LIM_MLM_MSG_START + 7) +#define LIM_MLM_AUTH_IND (LIM_MLM_MSG_START + 8) +#define LIM_MLM_ASSOC_REQ (LIM_MLM_MSG_START + 9) +#define LIM_MLM_ASSOC_CNF (LIM_MLM_MSG_START + 10) +#define LIM_MLM_ASSOC_IND (LIM_MLM_MSG_START + 11) +#define LIM_MLM_DISASSOC_REQ (LIM_MLM_MSG_START + 12) +#define LIM_MLM_DISASSOC_CNF (LIM_MLM_MSG_START + 13) +#define LIM_MLM_DISASSOC_IND (LIM_MLM_MSG_START + 14) +#define LIM_MLM_REASSOC_REQ (LIM_MLM_MSG_START + 15) +#define LIM_MLM_REASSOC_CNF (LIM_MLM_MSG_START + 16) +#define LIM_MLM_REASSOC_IND (LIM_MLM_MSG_START + 17) +#define LIM_MLM_DEAUTH_REQ (LIM_MLM_MSG_START + 18) +#define LIM_MLM_DEAUTH_CNF (LIM_MLM_MSG_START + 19) +#define LIM_MLM_DEAUTH_IND (LIM_MLM_MSG_START + 20) +#define LIM_MLM_TSPEC_REQ (LIM_MLM_MSG_START + 21) +#define LIM_MLM_TSPEC_CNF (LIM_MLM_MSG_START + 22) +#define LIM_MLM_TSPEC_IND (LIM_MLM_MSG_START + 23) +#define LIM_MLM_SETKEYS_REQ (LIM_MLM_MSG_START + 24) +#define LIM_MLM_SETKEYS_CNF (LIM_MLM_MSG_START + 25) +#define LIM_MLM_LINK_TEST_STOP_REQ (LIM_MLM_MSG_START + 30) +#define LIM_MLM_PURGE_STA_IND (LIM_MLM_MSG_START + 31) +/* + * Values (LIM_MLM_MSG_START + 32) through + * (LIM_MLM_MSG_START + 40) are unused. + */ +#ifdef FEATURE_OEM_DATA_SUPPORT +#define LIM_MLM_OEM_DATA_REQ (LIM_MLM_MSG_START + 41) +#define LIM_MLM_OEM_DATA_CNF (LIM_MLM_MSG_START + 42) +#endif + +#define LIM_HASH_ADD 0 +#define LIM_HASH_UPDATE 1 + +#define LIM_WEP_IN_FC 1 +#define LIM_NO_WEP_IN_FC 0 + +#define LIM_DECRYPT_ICV_FAIL 1 + +/* / Definitions to distinquish between Association/Reassociaton */ +#define LIM_ASSOC 0 +#define LIM_REASSOC 1 + +/* / Minimum Memory blocks require for different scenario */ +#define LIM_MIN_MEM_ASSOC 4 + +/* / Verifies whether given mac addr matches the CURRENT Bssid */ +#define IS_CURRENT_BSSID(pMac, addr, psessionEntry) (cdf_mem_compare(addr, \ + psessionEntry->bssId, \ + sizeof(psessionEntry->bssId))) +/* / Verifies whether given addr matches the REASSOC Bssid */ +#define IS_REASSOC_BSSID(pMac, addr, psessionEntry) (cdf_mem_compare(addr, \ + psessionEntry->limReAssocbssId, \ + sizeof(psessionEntry->limReAssocbssId))) + +#define REQ_TYPE_REGISTRAR (0x2) +#define REQ_TYPE_WLAN_MANAGER_REGISTRAR (0x3) + +#define RESP_TYPE_REGISTRAR (0x2) +#define RESP_TYPE_ENROLLEE_INFO_ONLY (0x0) +#define RESP_TYPE_ENROLLEE_OPEN_8021X (0x1) +#define RESP_TYPE_AP (0x3) +#define LIM_TX_FRAMES_THRESHOLD_ON_CHIP 300 + + +#define HAL_TXCOMP_REQUESTED_MASK 0x1 /* bit 0 for TxComp intr requested. */ +#define HAL_USE_SELF_STA_REQUESTED_MASK 0x2 /* bit 1 for STA overwrite with selfSta Requested. */ +#define HAL_TX_NO_ENCRYPTION_MASK 0x4 /* bit 2. If set, the frame is not to be encrypted */ +#if defined(LIBRA_WAPI_SUPPORT) +#define HAL_WAPI_STA_MASK 0x8 /* bit 3. If set, this frame is for WAPI station */ +#endif + +#define HAL_TRIGGER_ENABLED_AC_MASK 0x10 /* bit 4 for data frames belonging to trigger enabled AC */ +#define HAL_USE_NO_ACK_REQUESTED_MASK 0x20 + +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 /* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_PEER_STA_REQUESTED_MASK 0x80 /* bit 7 will be used to control frames for p2p interface */ + +#ifdef FEATURE_WLAN_TDLS +#define HAL_TDLS_PEER_STA_MASK 0x80 /* bit 7 set for TDLS peer station */ +#endif + + +/* enums used by LIM are as follows */ + +enum eLimDisassocTrigger { + eLIM_HOST_DISASSOC, + eLIM_PEER_ENTITY_DISASSOC, + eLIM_LINK_MONITORING_DISASSOC, + eLIM_PROMISCUOUS_MODE_DISASSOC, + eLIM_HOST_DEAUTH, + eLIM_PEER_ENTITY_DEAUTH, + eLIM_LINK_MONITORING_DEAUTH, + eLIM_JOIN_FAILURE, + eLIM_REASSOC_REJECT +}; + +/* Reason code to determine the channel change context while sending + * WMA_CHNL_SWITCH_REQ message to HAL + */ +enum eChannelChangeReasonCodes { + LIM_SWITCH_CHANNEL_REASSOC, + LIM_SWITCH_CHANNEL_JOIN, + LIM_SWITCH_CHANNEL_OPERATION, /* Generic change channel */ + LIM_SWITCH_CHANNEL_SAP_DFS, /* DFS channel change */ +}; + +typedef struct sLimAuthRspTimeout { + tSirMacAddr peerMacAddr; +} tLimAuthRspTimeout; + +typedef struct sLimMlmStartReq { + tSirMacSSid ssId; + tSirBssType bssType; + tSirMacAddr bssId; + tSirMacBeaconInterval beaconPeriod; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacChanNum channelNumber; + ePhyChanBondState cbMode; + uint16_t atimWindow; + tSirMacRateSet rateSet; + uint8_t sessionId; /* Added For BT-AMP Support */ + + /* Parameters reqd for new HAL (message) interface */ + tSirNwType nwType; + uint8_t htCapable; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t ssidHidden; + uint8_t wps_state; + uint8_t obssProtEnabled; +} tLimMlmStartReq, *tpLimMlmStartReq; + +typedef struct sLimMlmStartCnf { + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmStartCnf, *tpLimMlmStartCnf; + +typedef struct sLimMlmScanCnf { + tSirResultCodes resultCode; + uint16_t scanResultLength; + tSirBssDescription bssDescription[1]; + uint8_t sessionId; +} tLimMlmScanCnf, *tpLimMlmScanCnf; + +typedef struct sLimScanResult { + uint16_t numBssDescriptions; + tSirBssDescription bssDescription[1]; +} tLimScanResult; + +typedef struct sLimMlmJoinCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmJoinCnf, *tpLimMlmJoinCnf; + +typedef struct sLimMlmAssocReq { + tSirMacAddr peerMacAddr; + uint32_t assocFailureTimeout; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmAssocReq, *tpLimMlmAssocReq; + +typedef struct sLimMlmAssocCnf { + tSirResultCodes resultCode; /* Internal status code. */ + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmAssocCnf, *tpLimMlmAssocCnf; + +typedef struct sLimMlmAssocInd { + tSirMacAddr peerMacAddr; + uint16_t aid; + tAniAuthType authType; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which possibly includes WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + uint8_t sessionId; + + tAniBool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + tSirSmeChanInfo chan_info; +} tLimMlmAssocInd, *tpLimMlmAssocInd; + +typedef struct sLimMlmReassocReq { + tSirMacAddr peerMacAddr; + uint32_t reassocFailureTimeout; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmReassocReq, *tpLimMlmReassocReq; + +typedef struct sLimMlmReassocCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmReassocCnf, *tpLimMlmReassocCnf; + +typedef struct sLimMlmReassocInd { + tSirMacAddr peerMacAddr; + tSirMacAddr currentApAddr; + uint16_t aid; + tAniAuthType authType; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which can be WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + + tAniBool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; +} tLimMlmReassocInd, *tpLimMlmReassocInd; + +typedef struct sLimMlmAuthCnf { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmAuthCnf, *tpLimMlmAuthCnf; + +typedef struct sLimMlmDeauthReq { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; /* Added for BT-AMP SUPPORT */ + +} tLimMlmDeauthReq, *tpLimMlmDeauthReq; + +typedef struct sLimMlmDeauthCnf { + tSirMacAddr peerMacAddr; + tSirResultCodes resultCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDeauthCnf, *tpLimMLmDeauthCnf; + +typedef struct sLimMlmDeauthInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; +} tLimMlmDeauthInd, *tpLimMlmDeauthInd; + +typedef struct sLimMlmDisassocReq { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocReq, *tpLimMlmDisassocReq; + +typedef struct sLimMlmDisassocCnf { + tSirMacAddr peerMacAddr; + tSirResultCodes resultCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocCnf, *tpLimMlmDisassocCnf; + +typedef struct sLimMlmDisassocInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocInd, *tpLimMlmDisassocInd; + +typedef struct sLimMlmPurgeStaReq { + tSirMacAddr peerMacAddr; + uint16_t aid; + uint8_t sessionId; /* Added For BT-AMP Support */ +} tLimMlmPurgeStaReq, *tpLimMlmPurgeStaReq; + +typedef struct sLimMlmPurgeStaInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t purgeTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmPurgeStaInd, *tpLimMlmPurgeStaInd; + +typedef struct sLimMlmSetKeysCnf { + tSirMacAddr peerMacAddr; + uint16_t resultCode; + uint16_t aid; + uint8_t sessionId; +} tLimMlmSetKeysCnf, *tpLimMlmSetKeysCnf; + +typedef struct sLimMlmResetReq { + tSirMacAddr macAddr; + uint8_t performCleanup; + uint8_t sessionId; +} tLimMlmResetReq, *tpLimMlmResetReq; + +typedef struct sLimMlmResetCnf { + tSirMacAddr macAddr; + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmResetCnf, *tpLimMlmResetCnf; + +typedef struct sLimMlmLinkTestStopReq { + tSirMacAddr peerMacAddr; + uint8_t sessionId; +} tLimMlmLinkTestStopReq, *tpLimMlmLinkTestStopReq; + +/* Function templates */ + +bool lim_process_sme_req_messages(tpAniSirGlobal, tpSirMsgQ); +void lim_process_mlm_req_messages(tpAniSirGlobal, tpSirMsgQ); +void lim_process_mlm_rsp_messages(tpAniSirGlobal, uint32_t, uint32_t *); +void lim_process_sme_del_bss_rsp(tpAniSirGlobal, uint32_t, tpPESession); + +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data); + +/* Function to handle HT and HT IE CFG parameter intializations */ +void handle_ht_capabilityand_ht_info(struct sAniSirGlobal *pMac, + tpPESession psessionEntry); + +/* Function to handle CFG parameter updates */ +void lim_handle_cf_gparam_update(tpAniSirGlobal, uint32_t); + +void lim_handle_param_update(tpAniSirGlobal pMac, eUpdateIEsType cfgId); + +/* Function to apply CFG parameters before join/reassoc/start BSS */ +void lim_apply_configuration(tpAniSirGlobal, tpPESession); + +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry); + +/* Function to Initialize MLM state machine on STA */ +void lim_init_mlm(tpAniSirGlobal); + +/* Function to cleanup MLM state machine */ +void lim_cleanup_mlm(tpAniSirGlobal); + +/* Function to cleanup LMM state machine */ +void lim_cleanup_lmm(tpAniSirGlobal); + +/* Management frame handling functions */ +void lim_process_beacon_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_beacon_frame_no_session(tpAniSirGlobal, uint8_t *); +void lim_process_probe_req_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_rsp_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_rsp_frame_no_session(tpAniSirGlobal, uint8_t *); +void lim_process_probe_req_frame_multiple_bss(tpAniSirGlobal, uint8_t *, + tpPESession); + +/* Process Auth frame when we have a session in progress. */ +void lim_process_auth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +#ifdef WLAN_FEATURE_VOWIFI_11R +tSirRetStatus lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *, + void *body); +#endif + +void lim_process_assoc_req_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_send_mlm_assoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +void lim_process_assoc_rsp_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_process_disassoc_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_deauth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_action_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxMetaInfo); + +void lim_populate_p2p_mac_header(tpAniSirGlobal, uint8_t *); +void lim_populate_mac_header(tpAniSirGlobal, uint8_t *, uint8_t, uint8_t, + tSirMacAddr, tSirMacAddr); +tSirRetStatus lim_send_probe_req_mgmt_frame(tpAniSirGlobal, tSirMacSSid *, + tSirMacAddr, uint8_t, tSirMacAddr, + uint32_t, uint32_t, uint8_t *); +void lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal, tSirMacAddr, tpAniSSID, short, + uint8_t, tpPESession, uint8_t); +void lim_send_auth_mgmt_frame(tpAniSirGlobal, tSirMacAuthFrameBody *, tSirMacAddr, + uint8_t, tpPESession); +void lim_send_assoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmAssocReq *, tpPESession); +void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmReassocReq *, + tpPESession); +#ifdef WLAN_FEATURE_VOWIFI_11R +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry); +#endif +void lim_send_delts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo *pTsinfo, + tSirMacTspecIE *pTspecIe, + tpPESession psessionEntry); +void lim_send_addts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *addts, tpPESession); +void lim_send_addts_rsp_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t statusCode, tSirAddtsReqInfo *addts, + tSirMacScheduleIE *pSchedule, tpPESession); + +void lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal, uint16_t, uint16_t, tSirMacAddr, + uint8_t, tpDphHashNode pSta, tpPESession); + +void lim_send_disassoc_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, + tpPESession, bool waitForAck); +void lim_send_deauth_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, tpPESession, + bool waitForAck); + +tSirResultCodes lim_mlm_add_bss(tpAniSirGlobal, tLimMlmStartReq *, + tpPESession psessionEntry); + +tSirRetStatus lim_send_channel_switch_mgmt_frame(tpAniSirGlobal, tSirMacAddr, + uint8_t, uint8_t, uint8_t, + tpPESession); + +#ifdef WLAN_FEATURE_11AC +tSirRetStatus lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, uint8_t nMode, + tpPESession psessionEntry); +tSirRetStatus lim_send_vht_channel_switch_mgmt_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nChanWidth, + uint8_t nNewChannel, + uint8_t ncbMode, + tpPESession psessionEntry); +#endif + +#if defined WLAN_FEATURE_VOWIFI +tSirRetStatus lim_send_neighbor_report_request_frame(tpAniSirGlobal, + tpSirMacNeighborReportReq, + tSirMacAddr, tpPESession); +tSirRetStatus lim_send_link_report_action_frame(tpAniSirGlobal, tpSirMacLinkReport, + tSirMacAddr, tpPESession); +tSirRetStatus lim_send_radio_measure_report_action_frame(tpAniSirGlobal, uint8_t, + uint8_t, + tpSirMacRadioMeasureReport, + tSirMacAddr, tpPESession); +#endif + + +#ifdef FEATURE_WLAN_TDLS +void lim_init_tdls_data(tpAniSirGlobal, tpPESession); +tSirRetStatus lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_link_establish_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +void lim_send_sme_tdls_delete_all_peer_ind(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_send_sme_mgmt_tx_completion(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint32_t txCompleteStatus); +tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal pMac, + tpPESession psessionEntry); +CDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession); +tSirRetStatus lim_send_tdls_teardown_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMac, uint16_t reason, + uint8_t responder, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen); +#endif + +/* Algorithms & Link Monitoring related functions */ +/* / Function that handles heartbeat failure */ +void lim_handle_heart_beat_failure(tpAniSirGlobal, tpPESession); + +/* / Function that triggers link tear down with AP upon HB failure */ +void lim_tear_down_link_with_ap(tpAniSirGlobal, uint8_t, tSirMacReasonCodes); + +/* / Function that processes Max retries interrupt from TFP */ +void limHandleMaxRetriesInterrupt(uint32_t); + +/* / Function that processes messages deferred during Learn mode */ +void lim_process_deferred_message_queue(tpAniSirGlobal); + +/* / Function that defers the messages received */ +uint32_t lim_defer_msg(tpAniSirGlobal, tSirMsgQ *); + +/* / Function that Switches the Channel and sets the CB Mode */ +void lim_set_channel(tpAniSirGlobal pMac, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + phy_ch_width ch_width, tPowerdBm maxTxPower, + uint8_t peSessionId); + + +/* / Function that completes channel scan */ +void lim_complete_mlm_scan(tpAniSirGlobal, tSirResultCodes); + +#ifdef ANI_SUPPORT_11H +/* / Function that sends Measurement Report action frame */ +tSirRetStatus lim_send_meas_report_frame(tpAniSirGlobal, tpSirMacMeasReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); + +/* / Function that sends TPC Report action frame */ +tSirRetStatus lim_send_tpc_report_frame(tpAniSirGlobal, tpSirMacTpcReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); +#endif + +/* / Function that sends TPC Request action frame */ +void lim_send_tpc_request_frame(tpAniSirGlobal, tSirMacAddr, + tpPESession psessionEntry); + +/* Function(s) to handle responses received from HAL */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQt, + tpPESession psessionEntry); +void lim_process_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession); +void lim_process_sta_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); + +/* Function to process WMA_SWITCH_CHANNEL_RSP message */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *); + +void lim_covert_channel_scan_type(tpAniSirGlobal pMac, uint8_t channelNum, + bool passiveToActive); +void lim_set_dfs_channel_list(tpAniSirGlobal pMac, uint8_t channelNum, + tSirDFSChannelList *dfsChannelList); +void limContinueChannelLearn(tpAniSirGlobal); +/* WLAN_SUSPEND_LINK Related */ +uint8_t lim_is_link_suspended(tpAniSirGlobal pMac); +/* end WLAN_SUSPEND_LINK Related */ + +#ifdef WLAN_FEATURE_11W +/* 11w send SA query request action frame */ +tSirRetStatus lim_send_sa_query_request_frame(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry); +/* 11w SA query request action frame handler */ +tSirRetStatus lim_send_sa_query_response_frame(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry); +#endif + +/* Inline functions */ + +/** + * lim_post_sme_message() + * + ***FUNCTION: + * This function is called by limProcessMlmMessages(). In this + * function MLM sub-module invokes MLM ind/cnf primitives. + * + ***LOGIC: + * Initially MLM makes an SME function call to invoke MLM ind/cnf + * primitive. In future this can be enhanced to 'post' messages to SME. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_sme_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + if (msgType > eWNI_SME_MSG_TYPES_BEGIN) + lim_process_sme_req_messages(pMac, &msg); + else + lim_process_mlm_rsp_messages(pMac, msgType, pMsgBuf); +} /*** end lim_post_sme_message() ***/ + +/** + * lim_post_mlm_message() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages(). In this + * function SME invokes MLME primitives. + * + ***PARAMS: + * + ***LOGIC: + * Initially SME makes an MLM function call to invoke MLM primitive. + * In future this can be enhanced to 'post' messages to MLM. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_mlm_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + + tSirMsgQ msg; + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + lim_process_mlm_req_messages(pMac, &msg); +} /*** end lim_post_mlm_message() ***/ + +/** + * lim_get_current_scan_channel() + * + ***FUNCTION: + * This function is called in various places to get current channel + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @return Channel number + */ +static inline uint8_t lim_get_current_scan_channel(tpAniSirGlobal pMac) +{ + uint8_t *pChanNum = + pMac->lim.gpLimMlmScanReq->channelList.channelNumber; + + return *(pChanNum + pMac->lim.gLimCurrentScanChannelId); +} /*** end lim_get_current_scan_channel() ***/ + +/** + * lim_get_ielen_from_bss_description() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from tSirBssDescription structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static inline uint16_t +lim_get_ielen_from_bss_description(tpSirBssDescription pBssDescr) +{ + uint16_t ielen; + + if (!pBssDescr) + return 0; + + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * <------------sizeof(tSirBssDescription)--------------------> + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + + ielen = (uint16_t)(pBssDescr->length + sizeof(pBssDescr->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + return ielen; +} /*** end lim_get_ielen_from_bss_description() ***/ + +/** + * lim_send_beacon_ind() + * + ***FUNCTION: + * This function is called to send the beacon indication + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + */ + +void lim_send_beacon_ind(tpAniSirGlobal pMac, tpPESession psessionEntry); + +void +lim_send_vdev_restart(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t sessionId); + +void lim_get_wpspbc_sessions(tpAniSirGlobal pMac, uint8_t *addr, uint8_t *uuid_e, + eWPSPBCOverlap *overlap, tpPESession psessionEntry); +void limWPSPBCTimeout(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_remove_pbc_sessions(tpAniSirGlobal pMac, tSirMacAddr pRemoveMac, + tpPESession psessionEntry); + +#define LIM_WPS_OVERLAP_TIMER_MS 10000 +void +lim_change_channel_with_callback(tpAniSirGlobal pMac, uint8_t newChannel, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession psessionEntry); + +void lim_send_sme_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, uint32_t rxChan, + tpPESession psessionEntry, int8_t rxRssi); +void lim_process_remain_on_chn_timeout(tpAniSirGlobal pMac); +void lim_process_insert_single_shot_noa_timeout(tpAniSirGlobal pMac); +void lim_convert_active_channel_to_passive_channel(tpAniSirGlobal pMac); +void lim_send_p2p_action_frame(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +void lim_abort_remain_on_chan(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id); +tSirRetStatus __lim_process_sme_no_a_update(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +void lim_process_regd_defd_sme_req_after_noa_start(tpAniSirGlobal pMac); + +void lim_process_disassoc_ack_timeout(tpAniSirGlobal pMac); +void lim_process_deauth_ack_timeout(tpAniSirGlobal pMac); +CDF_STATUS lim_send_disassoc_cnf(tpAniSirGlobal pMac); +CDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal pMac); +CDF_STATUS lim_disassoc_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess); +CDF_STATUS lim_deauth_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess); + +#ifdef WLAN_FEATURE_VOWIFI_11R +typedef struct sSetLinkCbackParams { + void *cbackDataPtr; +} tSetLinkCbackParams; +#endif + +void lim_process_rx_scan_event(tpAniSirGlobal mac, void *buf); + +int lim_process_remain_on_chnl_req(tpAniSirGlobal pMac, uint32_t *pMsg); +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, CDF_STATUS status, uint32_t *data); + +/* / Bit value data structure */ +typedef enum sHalBitVal /* For Bit operations */ +{ + eHAL_CLEAR, + eHAL_SET +} tHalBitVal; + +enum { + eHI_PRI, + ePROT, + eDBG +}; + +#endif /* __LIM_TYPES_H */ diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c new file mode 100644 index 0000000000..d34c2a30d0 --- /dev/null +++ b/core/mac/src/pe/lim/lim_utils.c @@ -0,0 +1,7145 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sch_api.h" +#include "lim_utils.h" +#include "lim_types.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_send_messages.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "lim_sta_hash_api.h" +#include "dot11f.h" +#include "dot11fdefs.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_ibss_peer_mgmt.h" +#include "lim_session_utils.h" +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "lim_ft_defs.h" +#endif +#include "lim_session.h" +#include "cds_reg_service.h" + +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif +#define ASCII_SPACE_CHARACTER 0x20 + +#define SUCCESS 1 + +#define MAX_BA_WINDOW_SIZE_FOR_CISCO 25 + +/** ------------------------------------------------------------- + \fn lim_delete_dialogue_token_list + \brief deletes the complete lim dialogue token linked list. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac) +{ + tpDialogueToken pCurrNode = pMac->lim.pDialogueTokenHead; + + while (NULL != pMac->lim.pDialogueTokenHead) { + pCurrNode = pMac->lim.pDialogueTokenHead; + pMac->lim.pDialogueTokenHead = + pMac->lim.pDialogueTokenHead->next; + cdf_mem_free(pCurrNode); + pCurrNode = NULL; + } + pMac->lim.pDialogueTokenTail = NULL; +} + +char *lim_dot11_reason_str(uint16_t reasonCode) +{ + switch (reasonCode) { + case 0: + return " "; + CASE_RETURN_STRING(eSIR_MAC_UNSPEC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PREV_AUTH_NOT_VALID_REASON); + CASE_RETURN_STRING(eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON); + CASE_RETURN_STRING(eSIR_MAC_PWR_CAPABILITY_BAD_REASON); + CASE_RETURN_STRING(eSIR_MAC_SPRTD_CHANNELS_BAD_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_IE_REASON); + CASE_RETURN_STRING(eSIR_MAC_MIC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_RSN_IE_MISMATCH_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_MC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_UC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_AKMP_REASON); + CASE_RETURN_STRING(eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON); + CASE_RETURN_STRING(eSIR_MAC_1X_AUTH_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_SUITE_REJECTED_REASON); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); +#endif + /* Reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING + (eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION); +#endif + CASE_RETURN_STRING(eSIR_MAC_QOS_UNSPECIFIED_REASON); + CASE_RETURN_STRING(eSIR_MAC_QAP_NO_BANDWIDTH_REASON); + CASE_RETURN_STRING(eSIR_MAC_XS_UNACKED_FRAMES_REASON); + CASE_RETURN_STRING(eSIR_MAC_BAD_TXOP_USE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_REJECT_MECHANISIM_REASON); + CASE_RETURN_STRING(eSIR_MAC_MECHANISM_NOT_SETUP_REASON); + + CASE_RETURN_STRING(eSIR_MAC_PEER_TIMEDOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON); + /* Reserved 47 - 65535 */ + default: + return "Unknown"; + } +} + +char *lim_mlm_state_str(tLimMlmStates state) +{ + switch (state) { + case eLIM_MLM_OFFLINE_STATE: + return "eLIM_MLM_OFFLINE_STATE"; + case eLIM_MLM_IDLE_STATE: + return "eLIM_MLM_IDLE_STATE"; + case eLIM_MLM_WT_PROBE_RESP_STATE: + return "eLIM_MLM_WT_PROBE_RESP_STATE"; + case eLIM_MLM_PASSIVE_SCAN_STATE: + return "eLIM_MLM_PASSIVE_SCAN_STATE"; + case eLIM_MLM_WT_JOIN_BEACON_STATE: + return "eLIM_MLM_WT_JOIN_BEACON_STATE"; + case eLIM_MLM_JOINED_STATE: + return "eLIM_MLM_JOINED_STATE"; + case eLIM_MLM_BSS_STARTED_STATE: + return "eLIM_MLM_BSS_STARTED_STATE"; + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + return "eLIM_MLM_WT_AUTH_FRAME2_STATE"; + case eLIM_MLM_WT_AUTH_FRAME3_STATE: + return "eLIM_MLM_WT_AUTH_FRAME3_STATE"; + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + return "eLIM_MLM_WT_AUTH_FRAME4_STATE"; + case eLIM_MLM_AUTH_RSP_TIMEOUT_STATE: + return "eLIM_MLM_AUTH_RSP_TIMEOUT_STATE"; + case eLIM_MLM_AUTHENTICATED_STATE: + return "eLIM_MLM_AUTHENTICATED_STATE"; + case eLIM_MLM_WT_ASSOC_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_RSP_STATE"; + case eLIM_MLM_WT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_FT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_DEL_BSS_RSP_STATE: + return "eLIM_MLM_WT_DEL_BSS_RSP_STATE"; + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + return "eLIM_MLM_WT_ADD_STA_RSP_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_STATE"; + case eLIM_MLM_REASSOCIATED_STATE: + return "eLIM_MLM_REASSOCIATED_STATE"; + case eLIM_MLM_LINK_ESTABLISHED_STATE: + return "eLIM_MLM_LINK_ESTABLISHED_STATE"; + case eLIM_MLM_WT_ASSOC_CNF_STATE: + return "eLIM_MLM_WT_ASSOC_CNF_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE"; + case eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_SET_BSS_KEY_STATE: + return "eLIM_MLM_WT_SET_BSS_KEY_STATE"; + case eLIM_MLM_WT_SET_STA_KEY_STATE: + return "eLIM_MLM_WT_SET_STA_KEY_STATE"; + default: + return "INVALID MLM state"; + } +} + +void +lim_print_mlm_state(tpAniSirGlobal pMac, uint16_t logLevel, tLimMlmStates state) +{ + lim_log(pMac, logLevel, lim_mlm_state_str(state)); +} + +char *lim_sme_state_str(tLimSmeStates state) +{ + switch (state) { + case eLIM_SME_OFFLINE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_IDLE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_SUSPEND_STATE: + return "eLIM_SME_SUSPEND_STATE"; + case eLIM_SME_WT_SCAN_STATE: + return "eLIM_SME_WT_SCAN_STATE"; + case eLIM_SME_WT_JOIN_STATE: + return "eLIM_SME_WT_JOIN_STATE"; + case eLIM_SME_WT_AUTH_STATE: + return "eLIM_SME_WT_AUTH_STATE"; + case eLIM_SME_WT_ASSOC_STATE: + return "eLIM_SME_WT_ASSOC_STATE"; + case eLIM_SME_WT_REASSOC_STATE: + return "eLIM_SME_WT_REASSOC_STATE"; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: + return "eLIM_SME_WT_REASSOC_LINK_FAIL_STATE"; + case eLIM_SME_JOIN_FAILURE_STATE: + return "eLIM_SME_JOIN_FAILURE_STATE"; + case eLIM_SME_ASSOCIATED_STATE: + return "eLIM_SME_ASSOCIATED_STATE"; + case eLIM_SME_REASSOCIATED_STATE: + return "eLIM_SME_REASSOCIATED_STATE"; + case eLIM_SME_LINK_EST_STATE: + return "eLIM_SME_LINK_EST_STATE"; + case eLIM_SME_LINK_EST_WT_SCAN_STATE: + return "eLIM_SME_LINK_EST_WT_SCAN_STATE"; + case eLIM_SME_WT_PRE_AUTH_STATE: + return "eLIM_SME_WT_PRE_AUTH_STATE"; + case eLIM_SME_WT_DISASSOC_STATE: + return "eLIM_SME_WT_DISASSOC_STATE"; + case eLIM_SME_WT_DEAUTH_STATE: + return "eLIM_SME_WT_DEAUTH_STATE"; + case eLIM_SME_WT_START_BSS_STATE: + return "eLIM_SME_WT_START_BSS_STATE"; + case eLIM_SME_WT_STOP_BSS_STATE: + return "eLIM_SME_WT_STOP_BSS_STATE"; + case eLIM_SME_NORMAL_STATE: + return "eLIM_SME_NORMAL_STATE"; + case eLIM_SME_CHANNEL_SCAN_STATE: + return "eLIM_SME_CHANNEL_SCAN_STATE"; + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + return "eLIM_SME_NORMAL_CHANNEL_SCAN_STATE"; + default: + return "INVALID SME STATE"; + } +} + +void +lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, tLimSmeStates state) +{ + lim_log(pMac, logLevel, lim_sme_state_str(state)); +} + +char *lim_msg_str(uint32_t msgType) +{ +#ifdef FIXME_GEN6 + switch (msgType) { + case eWNI_SME_SYS_READY_IND: + return "eWNI_SME_SYS_READY_IND"; + case eWNI_SME_SCAN_REQ: + return "eWNI_SME_SCAN_REQ"; +#ifdef FEATURE_OEM_DATA_SUPPORT + case eWNI_SME_OEM_DATA_REQ: + return "eWNI_SME_OEM_DATA_REQ"; + case eWNI_SME_OEM_DATA_RSP: + return "eWNI_SME_OEM_DATA_RSP"; +#endif + case eWNI_SME_SCAN_RSP: + return "eWNI_SME_SCAN_RSP"; + case eWNI_SME_JOIN_REQ: + return "eWNI_SME_JOIN_REQ"; + case eWNI_SME_JOIN_RSP: + return "eWNI_SME_JOIN_RSP"; + case eWNI_SME_SETCONTEXT_REQ: + return "eWNI_SME_SETCONTEXT_REQ"; + case eWNI_SME_SETCONTEXT_RSP: + return "eWNI_SME_SETCONTEXT_RSP"; + case eWNI_SME_REASSOC_REQ: + return "eWNI_SME_REASSOC_REQ"; + case eWNI_SME_REASSOC_RSP: + return "eWNI_SME_REASSOC_RSP"; + case eWNI_SME_DISASSOC_REQ: + return "eWNI_SME_DISASSOC_REQ"; + case eWNI_SME_DISASSOC_RSP: + return "eWNI_SME_DISASSOC_RSP"; + case eWNI_SME_DISASSOC_IND: + return "eWNI_SME_DISASSOC_IND"; + case eWNI_SME_DISASSOC_CNF: + return "eWNI_SME_DISASSOC_CNF"; + case eWNI_SME_DEAUTH_REQ: + return "eWNI_SME_DEAUTH_REQ"; + case eWNI_SME_DEAUTH_RSP: + return "eWNI_SME_DEAUTH_RSP"; + case eWNI_SME_DEAUTH_IND: + return "eWNI_SME_DEAUTH_IND"; + case eWNI_SME_WM_STATUS_CHANGE_NTF: + return "eWNI_SME_WM_STATUS_CHANGE_NTF"; + case eWNI_SME_START_BSS_REQ: + return "eWNI_SME_START_BSS_REQ"; + case eWNI_SME_START_BSS_RSP: + return "eWNI_SME_START_BSS_RSP"; + case eWNI_SME_ASSOC_IND: + return "eWNI_SME_ASSOC_IND"; + case eWNI_SME_ASSOC_CNF: + return "eWNI_SME_ASSOC_CNF"; + case eWNI_SME_SWITCH_CHL_IND: + return "eWNI_SME_SWITCH_CHL_IND"; + case eWNI_SME_STOP_BSS_REQ: + return "eWNI_SME_STOP_BSS_REQ"; + case eWNI_SME_STOP_BSS_RSP: + return "eWNI_SME_STOP_BSS_RSP"; + case eWNI_SME_NEIGHBOR_BSS_IND: + return "eWNI_SME_NEIGHBOR_BSS_IND"; + case eWNI_SME_DEAUTH_CNF: + return "eWNI_SME_DEAUTH_CNF"; + case eWNI_SME_ADDTS_REQ: + return "eWNI_SME_ADDTS_REQ"; + case eWNI_SME_ADDTS_RSP: + return "eWNI_SME_ADDTS_RSP"; + case eWNI_SME_DELTS_REQ: + return "eWNI_SME_DELTS_REQ"; + case eWNI_SME_DELTS_RSP: + return "eWNI_SME_DELTS_RSP"; + case eWNI_SME_DELTS_IND: + return "eWNI_SME_DELTS_IND"; + case WMA_SUSPEND_ACTIVITY_RSP: + return "WMA_SUSPEND_ACTIVITY_RSP"; + case SIR_LIM_RETRY_INTERRUPT_MSG: + return "SIR_LIM_RETRY_INTERRUPT_MSG"; + case SIR_BB_XPORT_MGMT_MSG: + return "SIR_BB_XPORT_MGMT_MSG"; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + return "SIR_LIM_INV_KEY_INTERRUPT_MSG"; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + return "SIR_LIM_KEY_ID_INTERRUPT_MSG"; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + return "SIR_LIM_REPLAY_THRES_INTERRUPT_MSG"; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + return "SIR_LIM_JOIN_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + return "SIR_LIM_AUTH_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_RSP_TIMEOUT: + return "SIR_LIM_AUTH_RSP_TIMEOUT"; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + return "SIR_LIM_ASSOC_FAIL_TIMEOUT"; + case SIR_LIM_REASSOC_FAIL_TIMEOUT: + return "SIR_LIM_REASSOC_FAIL_TIMEOUT"; + case SIR_LIM_HEART_BEAT_TIMEOUT: + return "SIR_LIM_HEART_BEAT_TIMEOUT"; + case SIR_LIM_ADDTS_RSP_TIMEOUT: + return "SIR_LIM_ADDTS_RSP_TIMEOUT"; + case SIR_LIM_LINK_TEST_DURATION_TIMEOUT: + return "SIR_LIM_LINK_TEST_DURATION_TIMEOUT"; + case SIR_LIM_HASH_MISS_THRES_TIMEOUT: + return "SIR_LIM_HASH_MISS_THRES_TIMEOUT"; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + return "SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT"; + case SIR_LIM_CNF_WAIT_TIMEOUT: + return "SIR_LIM_CNF_WAIT_TIMEOUT"; + case SIR_LIM_RADAR_DETECT_IND: + return "SIR_LIM_RADAR_DETECT_IND"; +#ifdef WLAN_FEATURE_VOWIFI_11R + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + return "SIR_LIM_FT_PREAUTH_RSP_TIMEOUT"; +#endif + + case WNI_CFG_PARAM_UPDATE_IND: + return "WNI_CFG_PARAM_UPDATE_IND"; + case WNI_CFG_DNLD_REQ: + return "WNI_CFG_DNLD_REQ"; + case WNI_CFG_DNLD_CNF: + return "WNI_CFG_DNLD_CNF"; + case WNI_CFG_GET_RSP: + return "WNI_CFG_GET_RSP"; + case WNI_CFG_SET_CNF: + return "WNI_CFG_SET_CNF"; + case WNI_CFG_GET_ATTRIB_RSP: + return "WNI_CFG_GET_ATTRIB_RSP"; + case WNI_CFG_ADD_GRP_ADDR_CNF: + return "WNI_CFG_ADD_GRP_ADDR_CNF"; + case WNI_CFG_DEL_GRP_ADDR_CNF: + return "WNI_CFG_DEL_GRP_ADDR_CNF"; + case ANI_CFG_GET_RADIO_STAT_RSP: + return "ANI_CFG_GET_RADIO_STAT_RSP"; + case ANI_CFG_GET_PER_STA_STAT_RSP: + return "ANI_CFG_GET_PER_STA_STAT_RSP"; + case ANI_CFG_GET_AGG_STA_STAT_RSP: + return "ANI_CFG_GET_AGG_STA_STAT_RSP"; + case ANI_CFG_CLEAR_STAT_RSP: + return "ANI_CFG_CLEAR_STAT_RSP"; + case WNI_CFG_DNLD_RSP: + return "WNI_CFG_DNLD_RSP"; + case WNI_CFG_GET_REQ: + return "WNI_CFG_GET_REQ"; + case WNI_CFG_SET_REQ: + return "WNI_CFG_SET_REQ"; + case WNI_CFG_SET_REQ_NO_RSP: + return "WNI_CFG_SET_REQ_NO_RSP"; + case eWNI_PMC_ENTER_IMPS_RSP: + return "eWNI_PMC_ENTER_IMPS_RSP"; + case eWNI_PMC_EXIT_IMPS_RSP: + return "eWNI_PMC_EXIT_IMPS_RSP"; + case eWNI_PMC_ENTER_BMPS_RSP: + return "eWNI_PMC_ENTER_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_RSP: + return "eWNI_PMC_EXIT_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_IND: + return "eWNI_PMC_EXIT_BMPS_IND"; + case eWNI_SME_SET_BCN_FILTER_REQ: + return "eWNI_SME_SET_BCN_FILTER_REQ"; +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eWNI_SME_GET_TSM_STATS_REQ: + return "eWNI_SME_GET_TSM_STATS_REQ"; + case eWNI_SME_GET_TSM_STATS_RSP: + return "eWNI_SME_GET_TSM_STATS_RSP"; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + case eWNI_SME_CSA_OFFLOAD_EVENT: + return "eWNI_SME_CSA_OFFLOAD_EVENT"; + case eWNI_SME_SET_HW_MODE_REQ: + return "eWNI_SME_SET_HW_MODE_REQ"; + case eWNI_SME_SET_HW_MODE_RESP: + return "eWNI_SME_SET_HW_MODE_RESP"; + case eWNI_SME_HW_MODE_TRANS_IND: + return "eWNI_SME_HW_MODE_TRANS_IND"; + default: + return "INVALID SME message"; + } +#endif + return ""; +} + +char *lim_result_code_str(tSirResultCodes resultCode) +{ + switch (resultCode) { + case eSIR_SME_SUCCESS: + return "eSIR_SME_SUCCESS"; + case eSIR_LOGP_EXCEPTION: + return "eSIR_LOGP_EXCEPTION"; + case eSIR_SME_INVALID_PARAMETERS: + return "eSIR_SME_INVALID_PARAMETERS"; + case eSIR_SME_UNEXPECTED_REQ_RESULT_CODE: + return "eSIR_SME_UNEXPECTED_REQ_RESULT_CODE"; + case eSIR_SME_RESOURCES_UNAVAILABLE: + return "eSIR_SME_RESOURCES_UNAVAILABLE"; + case eSIR_SME_SCAN_FAILED: + return "eSIR_SME_SCAN_FAILED"; + case eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED: + return "eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED"; + case eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE: + return "eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE"; + case eSIR_SME_REFUSED: + return "eSIR_SME_REFUSED"; + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + return "eSIR_SME_JOIN_TIMEOUT_RESULT_CODE"; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + return "eSIR_SME_AUTH_TIMEOUT_RESULT_CODE"; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED: + return "eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED"; + case eSIR_SME_AUTH_REFUSED: + return "eSIR_SME_AUTH_REFUSED"; + case eSIR_SME_INVALID_WEP_DEFAULT_KEY: + return "eSIR_SME_INVALID_WEP_DEFAULT_KEY"; + case eSIR_SME_ASSOC_REFUSED: + return "eSIR_SME_ASSOC_REFUSED"; + case eSIR_SME_REASSOC_REFUSED: + return "eSIR_SME_REASSOC_REFUSED"; + case eSIR_SME_STA_NOT_AUTHENTICATED: + return "eSIR_SME_STA_NOT_AUTHENTICATED"; + case eSIR_SME_STA_NOT_ASSOCIATED: + return "eSIR_SME_STA_NOT_ASSOCIATED"; + case eSIR_SME_ALREADY_JOINED_A_BSS: + return "eSIR_SME_ALREADY_JOINED_A_BSS"; + case eSIR_SME_MORE_SCAN_RESULTS_FOLLOW: + return "eSIR_SME_MORE_SCAN_RESULTS_FOLLOW"; + case eSIR_SME_INVALID_ASSOC_RSP_RXED: + return "eSIR_SME_INVALID_ASSOC_RSP_RXED"; + case eSIR_SME_MIC_COUNTER_MEASURES: + return "eSIR_SME_MIC_COUNTER_MEASURES"; + case eSIR_SME_ADDTS_RSP_TIMEOUT: + return "eSIR_SME_ADDTS_RSP_TIMEOUT"; + case eSIR_SME_CHANNEL_SWITCH_FAIL: + return "eSIR_SME_CHANNEL_SWITCH_FAIL"; + case eSIR_SME_HAL_SCAN_INIT_FAILED: + return "eSIR_SME_HAL_SCAN_INIT_FAILED"; + case eSIR_SME_HAL_SCAN_END_FAILED: + return "eSIR_SME_HAL_SCAN_END_FAILED"; + case eSIR_SME_HAL_SCAN_FINISH_FAILED: + return "eSIR_SME_HAL_SCAN_FINISH_FAILED"; + case eSIR_SME_HAL_SEND_MESSAGE_FAIL: + return "eSIR_SME_HAL_SEND_MESSAGE_FAIL"; + + default: + return "INVALID resultCode"; + } +} + +void lim_print_msg_name(tpAniSirGlobal pMac, uint16_t logLevel, uint32_t msgType) +{ + lim_log(pMac, logLevel, lim_msg_str(msgType)); +} + +/** + * lim_init_mlm() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to + * initialize MLM state machine on STA + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @return None + */ +void lim_init_mlm(tpAniSirGlobal pMac) +{ + uint32_t retVal; + + pMac->lim.gLimTimersCreated = 0; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + + /* / Initialize number of pre-auth contexts */ + pMac->lim.gLimNumPreAuthContexts = 0; + + /* / Initialize MAC based Authentication STA list */ + lim_init_pre_auth_list(pMac); + + /* Create timers used by LIM */ + retVal = lim_create_timers(pMac); + if (retVal == TX_SUCCESS) { + pMac->lim.gLimTimersCreated = 1; + } else { + lim_log(pMac, LOGP, + FL(" lim_create_timers Failed to create lim timers ")); + } +} /*** end lim_init_mlm() ***/ + +/** + * lim_deactivate_del_sta() - This function deactivate/delete associates STA + * @mac_ctx: pointer to Global Mac Structure + * @bss_entry: index for bss_entry + * @psession_entry: pointer to session entry + * @sta_ds: pointer to tpDphHashNode + * + * Function deactivate/delete associates STA + * + * Return: none + */ +static void lim_deactivate_del_sta(tpAniSirGlobal mac_ctx, uint32_t bss_entry, + tpPESession psession_entry, tpDphHashNode sta_ds) +{ + uint32_t sta_entry; + + for (sta_entry = 1; sta_entry < mac_ctx->lim.gLimAssocStaLimit; + sta_entry++) { + psession_entry = &mac_ctx->lim.gpSession[bss_entry]; + sta_ds = dph_get_hash_entry(mac_ctx, sta_entry, + &psession_entry->dph.dphHashTable); + if (NULL == sta_ds) + continue; + + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("Deleting pmfSaQueryTimer for staid[%d]"), + sta_ds->staIndex); + tx_timer_deactivate(&sta_ds->pmfSaQueryTimer); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } +} + +/** + * lim_cleanup_mlm() - This function is called to cleanup + * @mac_ctx: Pointer to Global MAC structure + * + * Function is called to cleanup any resources allocated by the MLM + * state machine. + * + * Return: none + */ +void lim_cleanup_mlm(tpAniSirGlobal mac_ctx) +{ + uint32_t n; + tLimPreAuthNode *pAuthNode; +#ifdef WLAN_FEATURE_11W + uint32_t bss_entry; + tpDphHashNode sta_ds = NULL; + tpPESession psession_entry = NULL; +#endif + tLimTimers *lim_timer = NULL; + + if (mac_ctx->lim.gLimTimersCreated == 1) { + lim_timer = &mac_ctx->lim.limTimers; + + /* Deactivate and delete Periodic Probe channel timers. */ + tx_timer_deactivate(&lim_timer->gLimPeriodicProbeReqTimer); + tx_timer_delete(&lim_timer->gLimPeriodicProbeReqTimer); + + /* Deactivate and delete channel switch timer. */ + tx_timer_deactivate(&lim_timer->gLimChannelSwitchTimer); + tx_timer_delete(&lim_timer->gLimChannelSwitchTimer); + + /* Deactivate and delete addts response timer. */ + tx_timer_deactivate(&lim_timer->gLimAddtsRspTimer); + tx_timer_delete(&lim_timer->gLimAddtsRspTimer); + + /* Deactivate and delete Join failure timer. */ + tx_timer_deactivate(&lim_timer->gLimJoinFailureTimer); + tx_timer_delete(&lim_timer->gLimJoinFailureTimer); + + /* Deactivate and delete Periodic Join Probe Request timer. */ + tx_timer_deactivate(&lim_timer->gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&lim_timer->gLimPeriodicJoinProbeReqTimer); + + /* Deactivate and delete Association failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAssocFailureTimer); + tx_timer_delete(&lim_timer->gLimAssocFailureTimer); + + /* Deactivate and delete Reassociation failure timer. */ + tx_timer_deactivate(&lim_timer->gLimReassocFailureTimer); + tx_timer_delete(&lim_timer->gLimReassocFailureTimer); + + /* Deactivate and delete Authentication failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAuthFailureTimer); + tx_timer_delete(&lim_timer->gLimAuthFailureTimer); + + /* Deactivate and delete wait-for-probe-after-Heartbeat timer. */ + tx_timer_deactivate(&lim_timer->gLimProbeAfterHBTimer); + tx_timer_delete(&lim_timer->gLimProbeAfterHBTimer); + + /* Deactivate and delete Quiet timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietTimer); + tx_timer_delete(&lim_timer->gLimQuietTimer); + + /* Deactivate and delete Quiet BSS timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietBssTimer); + tx_timer_delete(&lim_timer->gLimQuietBssTimer); + + /* Deactivate and delete cnf wait timer */ + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + tx_timer_deactivate(&lim_timer->gpLimCnfWaitTimer[n]); + tx_timer_delete(&lim_timer->gpLimCnfWaitTimer[n]); + } + + pAuthNode = mac_ctx->lim.gLimPreAuthTimerTable.pTable; + + /* Deactivate any Authentication response timers */ + lim_delete_pre_auth_list(mac_ctx); + + for (n = 0; n < mac_ctx->lim.gLimPreAuthTimerTable.numEntry; + n++, pAuthNode++) { + /* + * Delete any Authentication response + * timers, which might have been started. + */ + tx_timer_delete(&pAuthNode->timer); + } + + /* Deactivate and delete Hash Miss throttle timer */ + tx_timer_deactivate(&lim_timer-> + gLimSendDisassocFrameThresholdTimer); + tx_timer_delete(&lim_timer-> + gLimSendDisassocFrameThresholdTimer); + + tx_timer_deactivate(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_delete(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_deactivate(&lim_timer->gLimPreAuthClnupTimer); + tx_timer_delete(&lim_timer->gLimPreAuthClnupTimer); + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Deactivate and delete FT Preauth response timer */ + tx_timer_deactivate(&lim_timer->gLimFTPreAuthRspTimer); + tx_timer_delete(&lim_timer->gLimFTPreAuthRspTimer); +#endif + + /* Deactivate and delete remain on channel timer */ + tx_timer_deactivate(&lim_timer->gLimRemainOnChannelTimer); + tx_timer_delete(&lim_timer->gLimRemainOnChannelTimer); + + + tx_timer_deactivate(&lim_timer->gLimDisassocAckTimer); + tx_timer_delete(&lim_timer->gLimDisassocAckTimer); + + tx_timer_deactivate(&lim_timer->gLimDeauthAckTimer); + tx_timer_delete(&lim_timer->gLimDeauthAckTimer); + + tx_timer_deactivate(&lim_timer-> + gLimP2pSingleShotNoaInsertTimer); + tx_timer_delete(&lim_timer-> + gLimP2pSingleShotNoaInsertTimer); + + tx_timer_deactivate(&lim_timer-> + gLimActiveToPassiveChannelTimer); + tx_timer_delete(&lim_timer-> + gLimActiveToPassiveChannelTimer); + + mac_ctx->lim.gLimTimersCreated = 0; + } +#ifdef WLAN_FEATURE_11W + /* + * When SSR is triggered, we need to loop through + * each STA associated per BSSId and deactivate/delete + * the pmfSaQueryTimer for it + */ + if (cds_is_logp_in_progress()) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_ERROR, + FL("SSR is detected, proceed to clean up pmfSaQueryTimer")); + for (bss_entry = 0; bss_entry < mac_ctx->lim.maxBssId; + bss_entry++) { + if (!mac_ctx->lim.gpSession[bss_entry].valid) + continue; + lim_deactivate_del_sta(mac_ctx, bss_entry, + psession_entry, sta_ds); + } + } +#endif + +} /*** end lim_cleanup_mlm() ***/ + +/** + * lim_cleanup_lmm() + * + ***FUNCTION: + * This function is called to cleanup any resources + * allocated by LMM sub-module. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @return None + */ + +void lim_cleanup_lmm(tpAniSirGlobal pMac) +{ +} /*** end lim_cleanup_lmm() ***/ + +/** + * lim_is_addr_bc() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a broadcast or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Broadcast address or not + * + * @return true if passed address is Broadcast address else false + */ + +uint8_t lim_is_addr_bc(tSirMacAddr macAddr) +{ + int i; + for (i = 0; i < 6; i++) { + if ((macAddr[i] & 0xFF) != 0xFF) + return false; + } + + return true; +} /****** end lim_is_addr_bc() ******/ + +/** + * lim_is_group_addr() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a group address or not + * + ***LOGIC: + * If least significant bit of first octet of the MAC address is + * set to 1, it is a Group address. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Group address or not + * + * @return true if passed address is Group address else false + */ + +uint8_t lim_is_group_addr(tSirMacAddr macAddr) +{ + if ((macAddr[0] & 0x01) == 0x01) + return true; + else + return false; +} /****** end lim_is_group_addr() ******/ + +/** + * lim_print_mac_addr() + * + ***FUNCTION: + * This function is called to print passed MAC address + * in : format. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * @param macAddr - MacAddr to be printed + * @param logLevel - Loglevel to be used + * + * @return None. + */ + +void lim_print_mac_addr(tpAniSirGlobal pMac, tSirMacAddr macAddr, uint8_t logLevel) +{ + lim_log(pMac, logLevel, FL(MAC_ADDRESS_STR), MAC_ADDR_ARRAY(macAddr)); +} /****** end lim_print_mac_addr() ******/ + +/* + * lim_reset_deferred_msg_q() + * + ***FUNCTION: + * This function resets the deferred message queue parameters. + * + ***PARAMS: + * @param pMac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + ***RETURNS: + * None + */ + +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac) +{ + pMac->lim.gLimDeferredMsgQ.size = + pMac->lim.gLimDeferredMsgQ.write = + pMac->lim.gLimDeferredMsgQ.read = 0; + +} + +#define LIM_DEFERRED_Q_CHECK_THRESHOLD (MAX_DEFERRED_QUEUE_LEN/2) +#define LIM_MAX_NUM_MGMT_FRAME_DEFERRED (MAX_DEFERRED_QUEUE_LEN/2) + +/** + * lim_write_deferred_msg_q() - This function queues up a deferred message + * + * @mac_ctx: Pointer to Global MAC structure + * @lim_msg: a LIM message + * + * Function queues up a deferred message for later processing on the + * STA side. + * + * Return: none + */ + +uint8_t lim_write_deferred_msg_q(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg) +{ + lim_log(mac_ctx, LOG1, + FL("Queue a deferred message (size %d, write %d) - type 0x%x "), + mac_ctx->lim.gLimDeferredMsgQ.size, + mac_ctx->lim.gLimDeferredMsgQ.write, + lim_msg->type); + + /* check if the deferred message queue is full */ + if (mac_ctx->lim.gLimDeferredMsgQ.size >= MAX_DEFERRED_QUEUE_LEN) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) { + lim_log(mac_ctx, LOGE, + FL("queue->MsgQ full Msg:%d Msgs Failed:%d"), + lim_msg->type, + ++mac_ctx->lim.deferredMsgCnt); + } else { + mac_ctx->lim.deferredMsgCnt++; + } + return TX_QUEUE_FULL; + } + + /* + * In the application, there should not be more than 1 message get + * queued up. If happens, flags a warning. In the future, this can + * happen. + */ + if (mac_ctx->lim.gLimDeferredMsgQ.size > 0) + lim_log(mac_ctx, LOGW, + FL("%d Deferred Msg (type 0x%x, scan %d, global sme %d, global mlme %d, addts %d)"), + mac_ctx->lim.gLimDeferredMsgQ.size, + lim_msg->type, + lim_is_system_in_scan_state(mac_ctx), + mac_ctx->lim.gLimSmeState, + mac_ctx->lim.gLimMlmState, + mac_ctx->lim.gLimAddtsSent); + + /* + * To prevent the deferred Q is full of management frames, only give + * them certain space + */ + if ((SIR_BB_XPORT_MGMT_MSG == lim_msg->type) && + (LIM_DEFERRED_Q_CHECK_THRESHOLD < + mac_ctx->lim.gLimDeferredMsgQ.size)) { + uint16_t idx, count = 0; + for (idx = 0; idx < mac_ctx->lim.gLimDeferredMsgQ.size; + idx++) { + if (SIR_BB_XPORT_MGMT_MSG == + mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[idx].type) { + count++; + } + } + if (LIM_MAX_NUM_MGMT_FRAME_DEFERRED < count) { + /* + * We reach the quota for management frames, + * drop this one + */ + lim_log(mac_ctx, LOGW, + FL("Too many queue->MsgQ Msg: %d (count=%d)"), + lim_msg->type, count); + /* Return error, caller knows what to do */ + return TX_QUEUE_FULL; + } + } + + ++mac_ctx->lim.gLimDeferredMsgQ.size; + + /* reset the count here since we are able to defer the message */ + if (mac_ctx->lim.deferredMsgCnt != 0) + mac_ctx->lim.deferredMsgCnt = 0; + + /* if the write pointer hits the end of the queue, rewind it */ + if (mac_ctx->lim.gLimDeferredMsgQ.write >= MAX_DEFERRED_QUEUE_LEN) + mac_ctx->lim.gLimDeferredMsgQ.write = 0; + + /* save the message to the queue and advanced the write pointer */ + cdf_mem_copy((uint8_t *) &mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[mac_ctx->lim.gLimDeferredMsgQ.write++], + (uint8_t *) lim_msg, sizeof(tSirMsgQ)); + return TX_SUCCESS; + +} + +/* + * lim_read_deferred_msg_q() + * + ***FUNCTION: + * This function dequeues a deferred message for processing on the + * STA side. + * + ***PARAMS: + * @param pMac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * + ***RETURNS: + * Returns the message at the head of the deferred message queue + */ + +tSirMsgQ *lim_read_deferred_msg_q(tpAniSirGlobal pMac) +{ + tSirMsgQ *msg; + + /* + ** check any messages left. If no, return + **/ + if (pMac->lim.gLimDeferredMsgQ.size <= 0) + return NULL; + + /* + ** decrement the queue size + **/ + pMac->lim.gLimDeferredMsgQ.size--; + + /* + ** retrieve the message from the head of the queue + **/ + msg = + &pMac->lim.gLimDeferredMsgQ.deferredQueue[pMac->lim. + gLimDeferredMsgQ.read]; + + /* + ** advance the read pointer + **/ + pMac->lim.gLimDeferredMsgQ.read++; + + /* + ** if the read pointer hits the end of the queue, rewind it + **/ + if (pMac->lim.gLimDeferredMsgQ.read >= MAX_DEFERRED_QUEUE_LEN) + pMac->lim.gLimDeferredMsgQ.read = 0; + + PELOG1(lim_log(pMac, LOG1, + FL + ("** DeQueue a deferred message (size %d read %d) - type 0x%x **"), + pMac->lim.gLimDeferredMsgQ.size, + pMac->lim.gLimDeferredMsgQ.read, msg->type); + ) + + PELOG1(lim_log + (pMac, LOG1, + FL + ("DQ msg -- scan %d, global sme %d, global mlme %d, addts %d"), + lim_is_system_in_scan_state(pMac), pMac->lim.gLimSmeState, + pMac->lim.gLimMlmState, pMac->lim.gLimAddtsSent); + ) + + return msg; +} + +tSirRetStatus +lim_sys_process_mmh_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg, uint8_t qType) +{ + /* FIXME */ + sys_process_mmh_msg(pMac, pMsg); + return eSIR_SUCCESS; +} + +/* + * lim_handle_update_olbc_cache() - This function update olbc cache + * + * @mac_ctx: Pointer to Global MAC structure + * + * Function updates olbc cache + * + * Return: none + */ +void lim_handle_update_olbc_cache(tpAniSirGlobal mac_ctx) +{ + int i; + static int enable; + tUpdateBeaconParams beaconParams; + + tpPESession psessionEntry = lim_is_ap_session_active(mac_ctx); + + if (psessionEntry == NULL) { + lim_log(mac_ctx, LOGE, FL(" Session not found")); + return; + } + + cdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + beaconParams.bssIdx = psessionEntry->bssIdx; + + beaconParams.paramChangeBitmap = 0; + /* + * This is doing a 2 pass check. The first pass is to invalidate + * all the cache entries. The second pass is to decide whether to + * disable protection. + */ + if (!enable) { + lim_log(mac_ctx, LOG2, FL("Resetting OLBC cache")); + psessionEntry->gLimOlbcParams.numSta = 0; + psessionEntry->gLimOverlap11gParams.numSta = 0; + psessionEntry->gLimOverlapHt20Params.numSta = 0; + psessionEntry->gLimNonGfParams.numSta = 0; + psessionEntry->gLimLsigTxopParams.numSta = 0; + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) + mac_ctx->lim.protStaOverlapCache[i].active = false; + + enable = 1; + } else { + if ((!psessionEntry->gLimOlbcParams.numSta) && + (psessionEntry->gLimOlbcParams.protectionEnabled) && + (!psessionEntry->gLim11bParams.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no 11B STA set")); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlap11gParams.numSta) && + (psessionEntry->gLimOverlap11gParams.protectionEnabled) + && (!psessionEntry->gLim11gParams.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no 11G STA set")); + lim_enable_ht_protection_from11g(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlapHt20Params.numSta) && + (psessionEntry->gLimOverlapHt20Params.protectionEnabled) + && (!psessionEntry->gLimHt20Params.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no HT20 STA set")); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + enable = 0; + } + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, psessionEntry); + lim_send_beacon_params(mac_ctx, &beaconParams, psessionEntry); + } + /* Start OLBC timer */ + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimUpdateOlbcCacheTimer) + != TX_SUCCESS) + lim_log(mac_ctx, LOGE, FL("tx_timer_activate failed")); +} + +/** + * lim_is_null_ssid() - This function checks if ssid supplied is Null SSID + * @ssid: pointer to tSirMacSSid + * + * Function checks if ssid supplied is Null SSID + * + * Return: none + */ + +uint8_t lim_is_null_ssid(tSirMacSSid *ssid) +{ + uint8_t fnull_ssid = false; + uint32_t ssid_len; + uint8_t *ssid_str; + + if (0 == ssid->length) { + fnull_ssid = true; + return fnull_ssid; + } + /* If the first charactes is space, then check if all + * characters in SSID are spaces to consider it as NULL SSID + */ + if ((ASCII_SPACE_CHARACTER == ssid->ssId[0]) && + (ssid->length == 1)){ + fnull_ssid = true; + return fnull_ssid; + } else { + /* check if all the charactes in SSID are NULL */ + ssid_len = ssid->length; + ssid_str = ssid->ssId; + + while (ssid_len) { + if (*ssid_str) + return fnull_ssid; + + ssid_str++; + ssid_len--; + } + + if (0 == ssid_len) { + fnull_ssid = true; + return fnull_ssid; + } + } + + return fnull_ssid; +} + +/** ------------------------------------------------------------- + \fn lim_update_prot_sta_params + \brief updates protection related counters. + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tLimProtStaCacheType protStaCacheType + \param tHalBitVal gfSupported + \param tHalBitVal lsigTxopSupported + \return None + -------------------------------------------------------------*/ +void +lim_update_prot_sta_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tHalBitVal gfSupported, tHalBitVal lsigTxopSupported, + tpPESession psessionEntry) +{ + uint32_t i; + + PELOG1(lim_log(pMac, LOG1, FL("A STA is associated:")); + lim_log(pMac, LOG1, FL("Addr : ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG1); + ) + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (psessionEntry->protStaCache[i].active) { + PELOG1(lim_log(pMac, LOG1, FL("Addr: "));) + PELOG1(lim_print_mac_addr + (pMac, psessionEntry->protStaCache[i].addr, + LOG1); + ) + + if (cdf_mem_compare + (psessionEntry->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr))) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("matching cache entry at %d already active."), + i); + ) + return; + } + } + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!psessionEntry->protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + PELOGE(lim_log(pMac, LOGE, FL("No space in ProtStaCache"));) + return; + } + + cdf_mem_copy(psessionEntry->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + psessionEntry->protStaCache[i].protStaCacheType = protStaCacheType; + psessionEntry->protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + lim_log(pMac, LOG1, FL("11B, ")); + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + lim_log(pMac, LOG1, FL("11G, ")); + } else if (eLIM_PROT_STA_CACHE_TYPE_HT20 == protStaCacheType) { + psessionEntry->gLimHt20Params.numSta++; + lim_log(pMac, LOG1, FL("HT20, ")); + } + + if (!gfSupported) { + psessionEntry->gLimNonGfParams.numSta++; + lim_log(pMac, LOG1, FL("NonGf, ")); + } + if (!lsigTxopSupported) { + psessionEntry->gLimLsigTxopParams.numSta++; + lim_log(pMac, LOG1, FL("!lsigTxopSupported")); + } +} /* --------------------------------------------------------------------- */ + +/** ------------------------------------------------------------- + \fn lim_decide_ap_protection + \brief Decides all the protection related staiton coexistence and also sets + \ short preamble and short slot appropriately. This function will be called + \ when AP is ready to send assocRsp tp the station joining right now. + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \return None + -------------------------------------------------------------*/ +void +lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint16_t tmpAid; + tpDphHashNode pStaDs; + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + tHalBitVal gfSupported = eHAL_SET, lsigTxopSupported = eHAL_SET; + + pBeaconParams->paramChangeBitmap = 0; + /* check whether to enable protection or not */ + pStaDs = + dph_lookup_hash_entry(pMac, peerMacAddr, &tmpAid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + PELOG1(lim_log(pMac, LOG1, FL("pStaDs is NULL"));) + return; + } + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + /* if we are in 5 GHZ band */ + if (SIR_BAND_5_GHZ == rfBand) { + /* We are 11N. we need to protect from 11A and Ht20. we don't need any other protection in 5 GHZ. */ + /* HT20 case is common between both the bands and handled down as common code. */ + if (true == psessionEntry->htCapability) { + /* we are 11N and 11A station is joining. */ + /* protection from 11A required. */ + if (false == pStaDs->mlmStaContext.htCapability) { + lim_update_11a_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + return; + } + } + } else if (SIR_BAND_2_4_GHZ == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) && + (false == psessionEntry->htCapability)) { + + if (pStaDs->erpEnabled == eHAL_CLEAR) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + PELOG3(lim_log + (pMac, LOG3, + FL("Enabling protection from 11B")); + ) + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + } + /* HT station. */ + if (true == psessionEntry->htCapability) { + /* check if we need protection from 11b station */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + PELOG3(lim_log + (pMac, LOG3, + FL("Enabling protection from 11B")); + ) + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* station being joined is non-11b and non-ht ==> 11g device */ + else if (!pStaDs->mlmStaContext.htCapability) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llG; + /* enable protection */ + lim_enable_ht_protection_from11g(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* ERP mode is enabled for the latest station joined */ + /* latest station joined is HT capable */ + /* This case is being handled in common code (commn between both the bands) below. */ + } + } + /* we are HT and HT station is joining. This code is common for both the bands. */ + if ((true == psessionEntry->htCapability) && + (true == pStaDs->mlmStaContext.htCapability)) { + if (!pStaDs->htGreenfield) { + lim_enable_ht_non_gf_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + gfSupported = eHAL_CLEAR; + } + /* Station joining is HT 20Mhz */ + if ((eHT_CHANNEL_WIDTH_20MHZ == + pStaDs->htSupportedChannelWidthSet) && + (eHT_CHANNEL_WIDTH_20MHZ != + psessionEntry->htSupportedChannelWidthSet)){ + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_HT20; + lim_enable_ht20_protection(pMac, true, false, + pBeaconParams, psessionEntry); + } + /* Station joining does not support LSIG TXOP Protection */ + if (!pStaDs->htLsigTXOPProtection) { + lim_enable_ht_lsig_txop_protection(pMac, false, false, + pBeaconParams, + psessionEntry); + lsigTxopSupported = eHAL_CLEAR; + } + } + + lim_update_prot_sta_params(pMac, peerMacAddr, protStaCacheType, + gfSupported, lsigTxopSupported, psessionEntry); + + return; +} + +/** ------------------------------------------------------------- + \fn lim_enable_overlap11g_protection + \brief wrapper function for setting overlap 11g protection. + \param tpAniSirGlobal pMac + \param tpUpdateBeaconParams pBeaconParams + \param tpSirMacMgmtHdr pMh + \return None + -------------------------------------------------------------*/ +void +lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, tpPESession psessionEntry) +{ + lim_update_overlap_sta_param(pMac, pMh->bssId, + &(psessionEntry->gLimOlbcParams)); + + if (psessionEntry->gLimOlbcParams.numSta && + !psessionEntry->gLimOlbcParams.protectionEnabled) { + /* enable protection */ + PELOG1(lim_log(pMac, LOG1, FL("OLBC happens!!!"));) + lim_enable11g_protection(pMac, true, true, pBeaconParams, + psessionEntry); + } +} + +/** + * lim_update_short_preamble() - This function Updates short preamble + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @pbeaconparams: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to tpPESession + * + * Function Updates short preamble if needed when a new station joins + * + * Return: none + */ +void +lim_update_short_preamble(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = + dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &psession_entry->dph.dphHashTable); + + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if (sta_ds == NULL || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + if (sta_ds->shortPreambleEnabled != eHAL_CLEAR) + return; + + lim_log(mac_ctx, LOG1, + FL("Short Preamble is not enabled in Assoc Req from ")); + + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOG1); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + (psession_entry->gLimNoShortParams. + staNoShortCache[i].active) && + (cdf_mem_compare + (psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)))) + return; + else if (!LIM_IS_AP_ROLE(psession_entry) && + (mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) && + (cdf_mem_compare(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, + sizeof(tSirMacAddr)))) + return; + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + !psession_entry->gLimNoShortParams. + staNoShortCache[i].active) + break; + else if (!mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + tLimNoShortParams *lim_params = + &psession_entry->gLimNoShortParams; + if (LIM_IS_AP_ROLE(psession_entry)) { + lim_log(mac_ctx, LOGE, + FL("No space in Short cache (#active %d, #sta %d) for sta "), + i, + lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } else { + lim_log(mac_ctx, LOGE, + FL("No space in Short cache (#active %d, #sta %d) for sta "), + i, + lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } + + } + + if (LIM_IS_AP_ROLE(psession_entry)) { + cdf_mem_copy(psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + psession_entry->gLimNoShortParams.staNoShortCache[i]. + active = true; + psession_entry->gLimNoShortParams.numNonShortPreambleSta++; + } else { + cdf_mem_copy(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortParams.staNoShortCache[i].active = true; + mac_ctx->lim.gLimNoShortParams.numNonShortPreambleSta++; + } + + /* enable long preamble */ + lim_log(mac_ctx, LOG1, FL("Disabling short preamble")); + + if (lim_enable_short_preamble(mac_ctx, false, beaconparams, + psession_entry) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL("Cannot enable long preamble")); +} + +/** + * lim_update_short_slot_time() - This function Updates short slot time + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @beaconparams: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to tpPESession + * + * Function Updates short slot time if needed when a new station joins + * + * Return: None + */ +void +lim_update_short_slot_time(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint32_t val; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = + dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &session_entry->dph.dphHashTable); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + if (sta_ds == NULL || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + /* + * Only in case of softap in 11g mode, slot time might change + * depending on the STA being added. In 11a case, it should + * be always 1 and in 11b case, it should be always 0. + * Only when the new STA has short slot time disabled, we need to + * change softap's overall slot time settings else the default for + * softap is always short slot enabled. When the last long slot STA + * leaves softAP, we take care of it in lim_decide_short_slot + */ + if (sta_ds->shortSlotTimeEnabled == eHAL_CLEAR) { + lim_log(mac_ctx, LOG1, + FL("Short Slot Time is not enabled in Assoc Req from ")); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOG1); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (cdf_mem_compare( + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr))) + return; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (cdf_mem_compare(mac_ctx->lim. + gLimNoShortSlotParams. + staNoShortSlotCache[i]. + addr, peer_mac_addr, + sizeof(tSirMacAddr))) + return; + } + } + } + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + !session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + else { + if (!mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + } + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, + FL("No space in ShortSlot cache (#active %d, #sta %d) for sta "), + i, + session_entry->gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, + LOGE); + return; + } else { + lim_log(mac_ctx, LOGE, + FL("No space in ShortSlot cache (#active %d, #sta %d) for sta "), + i, + mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, + LOGE); + return; + } + } + + if (LIM_IS_AP_ROLE(session_entry)) { + cdf_mem_copy(session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + session_entry->gLimNoShortSlotParams. + numNonShortSlotSta++; + } else { + cdf_mem_copy(mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta++; + } + wlan_cfg_get_int(mac_ctx, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val); + /* + * Here we check if we are AP role and short slot enabled + * (both admin and oper modes) but we have atleast one STA + * connected with only long slot enabled, we need to change + * our beacon/pb rsp to broadcast short slot disabled + */ + if ((LIM_IS_AP_ROLE(session_entry)) && (val && + session_entry->gLimNoShortSlotParams.numNonShortSlotSta + && session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beaconparams->fShortSlotTime = false; + beaconparams->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + lim_log(mac_ctx, LOG1, + FL("Disable short slot time. Enable long slot time.")); + session_entry->shortSlotTimeSupported = false; + } else if (!LIM_IS_AP_ROLE(session_entry) && + (val && mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta && + session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beaconparams->fShortSlotTime = false; + beaconparams->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + lim_log(mac_ctx, LOG1, + FL("Disable short slot time. Enable long slot time.")); + session_entry->shortSlotTimeSupported = + false; + } + } +} + +/** ------------------------------------------------------------- + \fn lim_decide_sta_protection_on_assoc + \brief Decide protection related settings on Sta while association. + \param tpAniSirGlobal pMac + \param tpSchBeaconStruct pBeaconStruct + \return None + -------------------------------------------------------------*/ +void +lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry) +{ + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + if (SIR_BAND_5_GHZ == rfBand) { + if ((eSIR_HT_OP_MODE_MIXED == pBeaconStruct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pBeaconStruct->HTInfo.opMode)) { + if (pMac->lim.cfgProtection.fromlla) + psessionEntry->beaconParams.llaCoexist = true; + } else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + pBeaconStruct->HTInfo.opMode) { + if (pMac->lim.cfgProtection.ht20) + psessionEntry->beaconParams.ht20Coexist = true; + } + + } else if (SIR_BAND_2_4_GHZ == rfBand) { + /* spec 7.3.2.13 */ + /* UseProtection will be set when nonERP STA is associated. */ + /* NonERPPresent bit will be set when: */ + /* --nonERP Sta is associated OR */ + /* --nonERP Sta exists in overlapping BSS */ + /* when useProtection is not set then protection from nonERP stations is optional. */ + + /* CFG protection from 11b is enabled and */ + /* 11B device in the BSS */ + /* TODO, This is not sessionized */ + if (phyMode != WNI_CFG_PHY_MODE_11B) { + if (pMac->lim.cfgProtection.fromllb && + pBeaconStruct->erpPresent && + (pBeaconStruct->erpIEInfo.useProtection || + pBeaconStruct->erpIEInfo.nonErpPresent)) { + psessionEntry->beaconParams.llbCoexist = true; + } + /* AP has no 11b station associated. */ + else { + psessionEntry->beaconParams.llbCoexist = false; + } + } + /* following code block is only for HT station. */ + if ((psessionEntry->htCapability) && + (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + /* Obss Non HT STA present mode */ + psessionEntry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + /* CFG protection from 11G is enabled and */ + /* our AP has at least one 11G station associated. */ + if (pMac->lim.cfgProtection.fromllg && + ((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) + && (!psessionEntry->beaconParams.llbCoexist)) { + if (pMac->lim.cfgProtection.fromllg) + psessionEntry->beaconParams.llgCoexist = + true; + } + /* AP has only HT stations associated and at least one station is HT 20 */ + /* disable protection from any non-HT devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == htInfo.opMode) { + /* Disable protection from 11G station. */ + psessionEntry->beaconParams.llgCoexist = false; + /* CFG protection from HT 20 is enabled. */ + if (pMac->lim.cfgProtection.ht20) + psessionEntry->beaconParams. + ht20Coexist = true; + } + /* Disable protection from non-HT and HT20 devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + psessionEntry->beaconParams.llgCoexist = false; + psessionEntry->beaconParams.ht20Coexist = false; + } + + } + } + /* protection related factors other than HT operating mode. Applies to 2.4 GHZ as well as 5 GHZ. */ + if ((psessionEntry->htCapability) && (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo.lsigTXOPProtectionFullSupport; + } +} + + +/** + * lim_decide_sta_11bg_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * @phy_mode: phy mode index + * + * decides 11bg protection related settings on sta while processing beacon + * + * Return: none + */ +static void +lim_decide_sta_11bg_protection(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry, + uint32_t phy_mode) +{ + + tDot11fIEHTInfo htInfo; + + /* + * spec 7.3.2.13 + * UseProtection will be set when nonERP STA is associated. + * NonERPPresent bit will be set when: + * --nonERP Sta is associated OR + * --nonERP Sta exists in overlapping BSS + * when useProtection is not set then protection from + * nonERP stations is optional. + */ + if (phy_mode != WNI_CFG_PHY_MODE_11B) { + if (beacon_struct->erpPresent && + (beacon_struct->erpIEInfo.useProtection || + beacon_struct->erpIEInfo.nonErpPresent)) { + lim_enable11g_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* AP has no 11b station associated. */ + else { + /* disable protection from 11b station */ + lim_enable11g_protection(mac_ctx, false, false, + beaconparams, + psession_entry); + } + } + + if (!(psession_entry->htCapability) || + !(beacon_struct->HTInfo.present)) + return; + + /* following code is only for HT station. */ + + htInfo = beacon_struct->HTInfo; + /* AP has at least one 11G station associated. */ + if (((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) && + (!psession_entry->beaconParams.llbCoexist)) { + lim_enable_ht_protection_from11g(mac_ctx, true, false, + beaconparams, psession_entry); + + } + /* + * no HT operating mode change ==> no change in + * protection settings except for MIXED_MODE/Legacy + * Mode. + */ + /* + * in Mixed mode/legacy Mode even if there is no + * change in HT operating mode, there might be + * change in 11bCoexist or 11gCoexist. Hence this + * check is being done after mixed/legacy mode + * check. + */ + if (mac_ctx->lim.gHTOperMode != + (tSirMacHTOperatingMode)htInfo.opMode) { + mac_ctx->lim.gHTOperMode = + (tSirMacHTOperatingMode) htInfo.opMode; + /* + * AP has only HT stations associated and + * at least one station is HT 20 + */ + + /* disable protection from any non-HT devices. */ + + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + htInfo.opMode) { + /* Disable protection from 11G station. */ + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* + * Disable protection from non-HT and + * HT20 devices. + */ + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + else if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + + } + } + +} + +/** + * lim_decide_sta_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * + * decides protection related settings on sta while processing beacon + * + * Return: none + */ +void +lim_decide_sta_protection(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry) +{ + + tSirRFBand rfband = SIR_BAND_UNKNOWN; + uint32_t phy_mode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(mac_ctx, &rfband, psession_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if ((SIR_BAND_5_GHZ == rfband) && + /* we are HT capable. */ + (true == psession_entry->htCapability) && + (beacon_struct->HTInfo.present)) { + /* + * we are HT capable, AP's HT OPMode is + * mixed / overlap legacy ==> need protection + * from 11A. + */ + if ((eSIR_HT_OP_MODE_MIXED == + beacon_struct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + beacon_struct->HTInfo.opMode)) { + lim_update_11a_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } + /* + * we are HT capable, AP's HT OPMode is + * HT20 ==> disable protection from 11A if + * enabled. + */ + /* protection from HT20 if needed. */ + else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } else if (eSIR_HT_OP_MODE_PURE == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + } + } else if (SIR_BAND_2_4_GHZ == rfband) { + lim_decide_sta_11bg_protection(mac_ctx, beacon_struct, + beaconparams, psession_entry, phy_mode); + } + /* + * following code block is only for HT station. + * (2.4 GHZ as well as 5 GHZ) + */ + if ((psession_entry->htCapability) && (beacon_struct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = beacon_struct->HTInfo; + /* + * Check for changes in protection related factors other + * than HT operating mode. + */ + /* + * Check for changes in RIFS mode, nonGFDevicesPresent, + * lsigTXOPProtectionFullSupport. + */ + if (psession_entry->beaconParams.fRIFSMode != + (uint8_t) htInfo.rifsMode) { + beaconparams->fRIFSMode = + psession_entry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + beaconparams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + + if (psession_entry->beaconParams.llnNonGFCoexist != + htInfo.nonGFDevicesPresent) { + beaconparams->llnNonGFCoexist = + psession_entry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + beaconparams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + + if (psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport != + (uint8_t) htInfo.lsigTXOPProtectionFullSupport) { + beaconparams->fLsigTXOPProtectionFullSupport = + psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo. + lsigTXOPProtectionFullSupport; + beaconparams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + /* + * For Station just update the global lim variable, + * no need to send message to HAL since Station already + * taking care of HT OPR Mode=01, + * meaning AP is seeing legacy + */ + /* stations in overlapping BSS. */ + if (psession_entry->beaconParams.gHTObssMode != + (uint8_t) htInfo.obssNonHTStaPresent) + psession_entry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + } +} + +/** + * lim_process_channel_switch_timeout() + * + ***FUNCTION: + * This function is invoked when Channel Switch Timer expires at + * the STA. Now, STA must stop traffic, and then change/disable + * primary or secondary channel. + * + * + ***NOTE: + * @param pMac - Pointer to Global MAC structure + * @return None + */ +void lim_process_channel_switch_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry = NULL; + uint8_t channel; /* This is received and stored from channelSwitch Action frame */ + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + PELOGW(lim_log + (pMac, LOGW, + "Channel switch can be done only in STA role, Current Role = %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + ) + return; + } + + channel = psessionEntry->gLimChannelSwitch.primaryChannel; + /* Restore Channel Switch parameters to default */ + psessionEntry->gLimChannelSwitch.switchTimeoutValue = 0; + + /* Channel-switch timeout has occurred. reset the state */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_END; + + /* Check if the AP is switching to a channel that we support. + * Else, just don't bother to switch. Indicate HDD to look for a + * better AP to associate + */ + if (!lim_is_channel_valid_for_channel_switch(pMac, channel)) { + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Could not restore pre-channelSwitch (11h) state, resetting the system")); + return; + } + + /* If the channel-list that AP is asking us to switch is invalid, + * then we cannot switch the channel. Just disassociate from AP. + * We will find a better AP !!! + */ + lim_tear_down_link_with_ap(pMac, + pMac->lim.limTimers. + gLimChannelSwitchTimer.sessionId, + eSIR_MAC_UNSPEC_FAILURE_REASON); + return; + } + lim_covert_channel_scan_type(pMac, psessionEntry->currentOperChannel, + false); + pMac->lim.dfschannelList.timeStamp[psessionEntry->currentOperChannel] = + 0; + switch (psessionEntry->gLimChannelSwitch.state) { + case eLIM_CHANNEL_SWITCH_PRIMARY_ONLY: + PELOGW(lim_log(pMac, LOGW, FL("CHANNEL_SWITCH_PRIMARY_ONLY "));) + lim_switch_primary_channel(pMac, + psessionEntry->gLimChannelSwitch. + primaryChannel, psessionEntry); + psessionEntry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY: + PELOGW(lim_log + (pMac, LOGW, FL("CHANNEL_SWITCH_PRIMARY_AND_SECONDARY")); + ) + lim_switch_primary_secondary_channel(pMac, psessionEntry, + psessionEntry->gLimChannelSwitch.primaryChannel, + psessionEntry->gLimChannelSwitch.ch_center_freq_seg0, + psessionEntry->gLimChannelSwitch.ch_center_freq_seg1, + psessionEntry->gLimChannelSwitch.ch_width); + psessionEntry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_IDLE; + break; + + case eLIM_CHANNEL_SWITCH_IDLE: + default: + PELOGE(lim_log(pMac, LOGE, FL("incorrect state "));) + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Could not restore pre-channelSwitch (11h) state, resetting the system")); + } + return; /* Please note, this is 'return' and not 'break' */ + } +} + +/** + * lim_update_channel_switch() - This Function updates channel switch + * @mac_ctx: pointer to Global MAC structure + * @beacon: pointer to tpSirProbeRespBeacon + * @psessionentry: pointer to tpPESession + * + * This function is invoked whenever Station receives + * either 802.11h channel switch IE or airgo proprietary + * channel switch IE. + * + * Return: none + */ +void +lim_update_channel_switch(struct sAniSirGlobal *mac_ctx, + tpSirProbeRespBeacon beacon, + tpPESession psession_entry) +{ + uint16_t beacon_period; + tDot11fIEChanSwitchAnn *chnl_switch; + tLimChannelSwitchInfo *ch_switch_params; +#ifdef WLAN_FEATURE_11AC + tDot11fIEWiderBWChanSwitchAnn *widerchnl_switch; +#endif + + beacon_period = psession_entry->beaconParams.beaconInterval; + + /* 802.11h standard channel switch IE */ + chnl_switch = &(beacon->channelSwitchIE); + ch_switch_params = &psession_entry->gLimChannelSwitch; + ch_switch_params->primaryChannel = + chnl_switch->newChannel; + ch_switch_params->switchCount = chnl_switch->switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(beacon_period) * (chnl_switch->switchCount); + ch_switch_params->switchMode = chnl_switch->switchMode; +#ifdef WLAN_FEATURE_11AC + widerchnl_switch = &(beacon->WiderBWChanSwitchAnn); + if (beacon->WiderBWChanSwitchAnnPresent) { + psession_entry->gLimWiderBWChannelSwitch.newChanWidth = + widerchnl_switch->newChanWidth; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + widerchnl_switch->newCenterChanFreq0; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + widerchnl_switch->newCenterChanFreq1; + } +#endif + + /* Only primary channel switch element is present */ + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + /* + * Do not bother to look and operate on extended channel switch element + * if our own channel-bonding state is not enabled + */ + if (psession_entry->htSupportedChannelWidthSet && + beacon->sec_chan_offset_present) { + if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + } +#ifdef WLAN_FEATURE_11AC + if (psession_entry->vhtCapability && + beacon->WiderBWChanSwitchAnnPresent) { + ch_switch_params->ch_width = + widerchnl_switch->newChanWidth + 1; + ch_switch_params->ch_center_freq_seg0 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq1; +#endif + } + } + if (eSIR_SUCCESS != lim_start_channel_switch(mac_ctx, psession_entry)) + lim_log(mac_ctx, LOGW, FL("Could not start Channel Switch")); + + lim_log(mac_ctx, LOGW, + FL("session %d primary chl %d, ch_width %d, count %d (%d ticks)"), + psession_entry->peSessionId, + psession_entry->gLimChannelSwitch.primaryChannel, + psession_entry->gLimChannelSwitch.ch_width, + psession_entry->gLimChannelSwitch.switchCount, + psession_entry->gLimChannelSwitch.switchTimeoutValue); + return; +} + +/** + * lim_cancel_dot11h_channel_switch + * + ***FUNCTION: + * This function is called when STA does not send updated channel-swith IE + * after indicating channel-switch start. This will cancel the channel-swith + * timer which is already running. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + PELOGW(lim_log + (pMac, LOGW, FL("Received a beacon without channel switch IE")); + ) + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("tx_timer_deactivate failed!"));) + } + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("LIM: Could not restore pre-channelSwitch (11h) state, resetting the system")); + ) + + } +} + +/** + * lim_cancel_dot11h_quiet() + * + * @mac_ctx: pointer to global mac structure + * @psession_entry: pointer to tppesession + * + * Cancel the quieting on Station if latest beacon + * doesn't contain quiet IE in it. + * + * Return: none + */ +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("tx_timer_deactivate failed")); + ) + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("tx_timer_deactivate failed")); + ) + } + /** + * If the channel switch is already running in silent mode, dont resume the + * transmission. Channel switch timer when timeout, transmission will be resumed. + */ + if (! + ((psessionEntry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) + && (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(pMac, psessionEntry); + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; +} + +/** + * lim_process_quiet_timeout + * + * FUNCTION: + * This function is active only on the STA. + * Handles SIR_LIM_QUIET_TIMEOUT + * + * LOGIC: + * This timeout can occur under only one circumstance: + * + * 1) When gLimQuietState = eLIM_QUIET_BEGIN + * This indicates that the timeout "interval" has + * expired. This is a trigger for the STA to now + * shut-off Tx/Rx for the specified gLimQuietDuration + * -> The TIMER object gLimQuietBssTimer is + * activated + * -> With timeout = gLimQuietDuration + * -> gLimQuietState is set to eLIM_QUIET_RUNNING + * + * ASSUMPTIONS: + * Using two TIMER objects - + * gLimQuietTimer & gLimQuietBssTimer + * + * NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_process_quiet_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimQuietTimer.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + PELOG1(lim_log + (pMac, LOG1, FL("quietState = %d"), + psessionEntry->gLimSpecMgmt.quietState); + ) + switch (psessionEntry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_BEGIN: + /* Time to Stop data traffic for quietDuration */ + /* lim_deactivate_and_change_timer(pMac, eLIM_QUIET_BSS_TIMER); */ + if (TX_SUCCESS != tx_timer_deactivate( + &pMac->lim.limTimers.gLimQuietBssTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to de-activate gLimQuietBssTimer! Will attempt to activate anyway...")); + } + /* gLimQuietDuration appears to be in units of ticks */ + /* Use it as is */ + if (TX_SUCCESS != + tx_timer_change(&pMac->lim.limTimers.gLimQuietBssTimer, + psessionEntry->gLimSpecMgmt.quietDuration, + 0)) { + lim_log(pMac, LOGE, + FL + ("Unable to change gLimQuietBssTimer! Will still attempt to activate anyway...")); + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + pMac->lim.limTimers.gLimQuietTimer.sessionId, + eLIM_QUIET_BSS_TIMER)); + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietBssTimer)) { + lim_log(pMac, LOGW, + FL + ("Unable to activate gLimQuietBssTimer! The STA will be unable to honor Quiet BSS...")); + } else { + /* Transition to eLIM_QUIET_RUNNING */ + psessionEntry->gLimSpecMgmt.quietState = + eLIM_QUIET_RUNNING; + /* Shut-off Tx/Rx for gLimSpecMgmt.quietDuration */ + /* freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_STOP_TX); + + lim_log(pMac, LOG2, + FL("Quiet BSS: STA shutting down for %d ticks"), + psessionEntry->gLimSpecMgmt.quietDuration); + } + break; + + case eLIM_QUIET_RUNNING: + case eLIM_QUIET_INIT: + case eLIM_QUIET_END: + default: + /* */ + /* As of now, nothing to be done */ + /* */ + break; + } +} + +/** + * lim_process_quiet_bss_timeout() - Handles SIR_LIM_QUIET_BSS_TIMEOUT + * @mac_ctx: pointer to Globale Mac Structure + * + * This function is active on the AP and STA. + * Handles SIR_LIM_QUIET_BSS_TIMEOUT + * + * On the AP - + * When the SIR_LIM_QUIET_BSS_TIMEOUT is triggered, it is + * an indication for the AP to START sending out the + * Quiet BSS IE. + * If 802.11H is enabled, the Quiet BSS IE is sent as per + * the 11H spec + * If 802.11H is not enabled, the Quiet BSS IE is sent as + * a Proprietary IE. This will be understood by all the + * TITAN STA's + * Transitioning gLimQuietState to eLIM_QUIET_BEGIN will + * initiate the SCH to include the Quiet BSS IE in all + * its subsequent Beacons/PR's. + * The Quiet BSS IE will be included in all the Beacons + * & PR's until the next DTIM period + * + * On the STA - + * When gLimQuietState = eLIM_QUIET_RUNNING + * This indicates that the STA was successfully shut-off + * for the specified gLimQuietDuration. This is a trigger + * for the STA to now resume data traffic. + * -> gLimQuietState is set to eLIM_QUIET_INIT + * + * + * Return: none + */ +void lim_process_quiet_bss_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession psession_entry = NULL; + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + psession_entry = pe_find_session_by_session_id(mac_ctx, + lim_timer->gLimQuietBssTimer.sessionId); + + if (psession_entry == NULL) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + lim_log(mac_ctx, LOG1, FL("quietState = %d"), + psession_entry->gLimSpecMgmt.quietState); + + if (LIM_IS_AP_ROLE(psession_entry)) + return; + + /* eLIM_STA_ROLE */ + switch (psession_entry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_RUNNING: + /* Transition to eLIM_QUIET_INIT */ + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* + * Resume data traffic only if channel switch is + * not running in silent mode. + */ + if (!((psession_entry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) && + (psession_entry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + } + lim_log(mac_ctx, LOG2, FL("Quiet BSS: Resuming traffic...")); + break; + + case eLIM_QUIET_INIT: + case eLIM_QUIET_BEGIN: + case eLIM_QUIET_END: + lim_log(mac_ctx, LOG2, FL("Quiet state not in RUNNING")); + /* + * If the quiet period has ended, then resume the + * frame transmission + */ + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + break; + + default: + /* As of now, nothing to be done */ + break; + } +} + +/**---------------------------------------------- + \fn lim_start_quiet_timer + \brief Starts the quiet timer. + + \param pMac + \return NONE + -----------------------------------------------*/ +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + /* First, de-activate Timer, if its already active */ + lim_cancel_dot11h_quiet(pMac, psessionEntry); + + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, eLIM_QUIET_TIMER)); + if (TX_SUCCESS != + tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to deactivate gLimQuietTimer! Will still attempt to re-activate anyway...")); + } + /* Set the NEW timeout value, in ticks */ + if (TX_SUCCESS != tx_timer_change(&pMac->lim.limTimers.gLimQuietTimer, + SYS_MS_TO_TICKS(psessionEntry-> + gLimSpecMgmt. + quietTimeoutValue), + 0)) { + lim_log(pMac, LOGE, + FL + ("Unable to change gLimQuietTimer! Will still attempt to re-activate anyway...")); + } + + pMac->lim.limTimers.gLimQuietTimer.sessionId = sessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to activate gLimQuietTimer! STA cannot honor Quiet BSS!")); + lim_restore_pre_quiet_state(pMac, psessionEntry); + + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + return; + } +} + +/** ------------------------------------------------------------------------ **/ +/** + * keep track of the number of ANI peers associated in the BSS + * For the first and last ANI peer, we have to update EDCA params as needed + * + * When the first ANI peer joins the BSS, we notify SCH + * When the last ANI peer leaves the BSS, we notfiy SCH + */ +void +lim_util_count_sta_add(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((!pSta) || (!pSta->valid) || (pSta->fAniCount)) + return; + + pSta->fAniCount = 1; + + if (pMac->lim.gLimNumOfAniSTAs++ != 0) + return; + + /* get here only if this is the first ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +void +lim_util_count_sta_del(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((pSta == NULL) || (!pSta->fAniCount)) + return; + + /* Only if sta is invalid and the validInDummyState bit is set to 1, + * then go ahead and update the count and profiles. This ensures + * that the "number of ani station" count is properly incremented/decremented. + */ + if (pSta->valid == 1) + return; + + pSta->fAniCount = 0; + + if (pMac->lim.gLimNumOfAniSTAs <= 0) { + lim_log(pMac, LOGE, + FL + ("CountStaDel: ignoring Delete Req when AniPeer count is %d"), + pMac->lim.gLimNumOfAniSTAs); + return; + } + + pMac->lim.gLimNumOfAniSTAs--; + + if (pMac->lim.gLimNumOfAniSTAs != 0) + return; + + /* get here only if this is the last ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +/** + * lim_switch_channel_cback() + * + ***FUNCTION: + * This is the callback function registered while requesting to switch channel + * after AP indicates a channel switch for spectrum management (11h). + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param status Status of channel switch request + * @param data User data + * @param psessionEntry Session information + * @return NONE + */ +void lim_switch_channel_cback(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirSmeSwitchChannelInd *pSirSmeSwitchChInd; + + psessionEntry->currentOperChannel = psessionEntry->currentReqChannel; + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Could not restore pre-channelSwitch (11h) state, resetting the system")); + return; + } + + mmhMsg.type = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd = cdf_mem_malloc(sizeof(tSirSmeSwitchChannelInd)); + if (NULL == pSirSmeSwitchChInd) { + lim_log(pMac, LOGP, + FL("Failed to allocate buffer for buffer descriptor")); + return; + } + + pSirSmeSwitchChInd->messageType = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd->length = sizeof(tSirSmeSwitchChannelInd); + pSirSmeSwitchChInd->newChannelId = + psessionEntry->gLimChannelSwitch.primaryChannel; + pSirSmeSwitchChInd->sessionId = psessionEntry->smeSessionId; + cdf_mem_copy(pSirSmeSwitchChInd->bssId, psessionEntry->bssId, + sizeof(tSirMacAddr)); + mmhMsg.bodyptr = pSirSmeSwitchChInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); + + sys_process_mmh_msg(pMac, &mmhMsg); +} + +/** + * lim_switch_primary_channel() + * + ***FUNCTION: + * This function changes the current operating channel + * and sets the new new channel ID in WNI_CFG_CURRENT_CHANNEL. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel new chnannel ID + * @return NONE + */ +void lim_switch_primary_channel(tpAniSirGlobal pMac, uint8_t newChannel, + tpPESession psessionEntry) +{ +#if !defined WLAN_FEATURE_VOWIFI + uint32_t localPwrConstraint; +#endif + + PELOG3(lim_log + (pMac, LOG3, + FL("lim_switch_primary_channel: old chnl %d --> new chnl %d "), + psessionEntry->currentOperChannel, newChannel); + ) + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + +#if defined WLAN_FEATURE_VOWIFI + lim_send_switch_chnl_params(pMac, newChannel, 0, 0, CH_WIDTH_20MHZ, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, false); +#else + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to read Local Power Constraint from cfg")); + return; + } + lim_send_switch_chnl_params(pMac, newChannel, 0, 0, CH_WIDTH_20MHZ, + (tPowerdBm) localPwrConstraint, + psessionEntry->peSessionId, false); +#endif + return; +} + +/** + * lim_switch_primary_secondary_channel() + * + ***FUNCTION: + * This function changes the primary and secondary channel. + * If 11h is enabled and user provides a "new channel ID" + * that is different from the current operating channel, + * then we must set this new channel in WNI_CFG_CURRENT_CHANNEL, + * assign notify LIM of such change. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel New chnannel ID (or current channel ID) + * @param subband CB secondary info: + * - eANI_CB_SECONDARY_NONE + * - eANI_CB_SECONDARY_UP + * - eANI_CB_SECONDARY_DOWN + * @return NONE + */ +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width) +{ +#if !defined WLAN_FEATURE_VOWIFI + uint32_t localPwrConstraint; +#endif + uint8_t subband = 0; +#if !defined WLAN_FEATURE_VOWIFI + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Local Power Constraint from cfg")); + return; + } +#endif + /* Assign the callback to resume TX once channel is changed. */ + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + +#if defined WLAN_FEATURE_VOWIFI + lim_send_switch_chnl_params(pMac, newChannel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + false); +#else + lim_send_switch_chnl_params(pMac, newChannel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + psessionEntry->peSessionId, + false); +#endif + + /* Store the new primary and secondary channel in session entries if different */ + if (psessionEntry->currentOperChannel != newChannel) { + lim_log(pMac, LOGW, + FL("switch old chnl %d --> new chnl %d "), + psessionEntry->currentOperChannel, newChannel); + psessionEntry->currentOperChannel = newChannel; + } + if (psessionEntry->htSecondaryChannelOffset != subband) { + lim_log(pMac, LOGW, + FL("switch old sec chnl %d --> new sec chnl %d "), + psessionEntry->htSecondaryChannelOffset, subband); + psessionEntry->htSecondaryChannelOffset = subband; + if (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + } + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->htSupportedChannelWidthSet; + } + + return; +} + +/** + * lim_active_scan_allowed() + * + ***FUNCTION: + * Checks if active scans are permitted on the given channel + * + ***LOGIC: + * The config variable SCAN_CONTROL_LIST contains pairs of (channelNum, activeScanAllowed) + * Need to check if the channelNum matches, then depending on the corresponding + * scan flag, return true (for activeScanAllowed==1) or false (otherwise). + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param channelNum channel number + * @return None + */ + +uint8_t lim_active_scan_allowed(tpAniSirGlobal pMac, uint8_t channelNum) +{ + uint32_t i; + uint8_t channelPair[WNI_CFG_SCAN_CONTROL_LIST_LEN]; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + if (wlan_cfg_get_str(pMac, WNI_CFG_SCAN_CONTROL_LIST, channelPair, &len) + != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("Unable to get scan control list")); + ) + return false; + } + + if (len > WNI_CFG_SCAN_CONTROL_LIST_LEN) { + lim_log(pMac, LOGE, FL("Invalid scan control list length:%d"), + len); + return false; + } + + for (i = 0; (i + 1) < len; i += 2) { + if (channelPair[i] == channelNum) + return ((channelPair[i + 1] == + eSIR_ACTIVE_SCAN) ? true : false); + } + return false; +} + +/** + * lim_get_ht_capability() + * + ***FUNCTION: + * A utility function that returns the "current HT capability state" for the HT + * capability of interest (as requested in the API) + * + ***LOGIC: + * This routine will return with the "current" setting of a requested HT + * capability. This state info could be retrieved from - + * a) CFG (for static entries) + * b) Run time info + * - Dynamic state maintained by LIM + * - Configured at radio init time by SME + * + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param htCap The HT capability being queried + * @return uint8_t The current state of the requested HT capability is returned in a + * uint8_t variable + */ + +uint8_t lim_get_ht_capability(tpAniSirGlobal pMac, + uint32_t htCap, tpPESession psessionEntry) +{ + uint8_t retVal = 0; + uint8_t *ptr; + uint32_t cfgValue; + tSirMacHTCapabilityInfo macHTCapabilityInfo = { 0 }; + tSirMacExtendedHTCapabilityInfo macExtHTCapabilityInfo = { 0 }; + tSirMacTxBFCapabilityInfo macTxBFCapabilityInfo = { 0 }; + tSirMacASCapabilityInfo macASCapabilityInfo = { 0 }; + + /* */ + /* Determine which CFG to read from. Not ALL of the HT */ + /* related CFG's need to be read each time this API is */ + /* accessed */ + /* */ + if (htCap >= eHT_ANTENNA_SELECTION && htCap < eHT_SI_GRANULARITY) { + /* Get Antenna Seletion HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macASCapabilityInfo; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + } else { + if (htCap >= eHT_TX_BEAMFORMING && + htCap < eHT_ANTENNA_SELECTION) { + /* Get Transmit Beam Forming HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macTxBFCapabilityInfo; + *((uint32_t *) ptr) = (uint32_t) (cfgValue); + } else { + if (htCap >= eHT_PCO && htCap < eHT_TX_BEAMFORMING) { + /* Get Extended HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_EXT_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macExtHTCapabilityInfo; + *((uint16_t *) ptr) = + (uint16_t) (cfgValue & 0xffff); + } else { + if (htCap < eHT_MAX_RX_AMPDU_FACTOR) { + /* Get HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macHTCapabilityInfo; + /* CR 265282 MDM SoftAP 2.4PL: SoftAP boot up crash in 2.4 PL builds while same WLAN SU is working on 2.1 PL */ + *ptr++ = cfgValue & 0xff; + *ptr = (cfgValue >> 8) & 0xff; + } + } + } + } + + switch (htCap) { + case eHT_LSIG_TXOP_PROTECTION: + retVal = pMac->lim.gHTLsigTXOPProtection; + break; + + case eHT_STBC_CONTROL_FRAME: + retVal = (uint8_t) macHTCapabilityInfo.stbcControlFrame; + break; + + case eHT_PSMP: + retVal = pMac->lim.gHTPSMPSupport; + break; + + case eHT_DSSS_CCK_MODE_40MHZ: + retVal = pMac->lim.gHTDsssCckRate40MHzSupport; + break; + + case eHT_MAX_AMSDU_LENGTH: + retVal = (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + break; + + case eHT_RX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_stbc; + break; + + case eHT_TX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_tx_stbc; + break; + + case eHT_SHORT_GI_40MHZ: + retVal = (uint8_t) + (psessionEntry->htConfig.ht_sgi) ? macHTCapabilityInfo. + shortGI40MHz : 0; + break; + + case eHT_SHORT_GI_20MHZ: + retVal = (uint8_t) + (psessionEntry->htConfig.ht_sgi) ? macHTCapabilityInfo. + shortGI20MHz : 0; + break; + + case eHT_GREENFIELD: + retVal = (uint8_t) macHTCapabilityInfo.greenField; + break; + + case eHT_MIMO_POWER_SAVE: + retVal = (uint8_t) pMac->lim.gHTMIMOPSState; + break; + + case eHT_SUPPORTED_CHANNEL_WIDTH_SET: + retVal = (uint8_t) psessionEntry->htSupportedChannelWidthSet; + break; + + case eHT_ADVANCED_CODING: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_ldpc; + break; + + case eHT_MAX_RX_AMPDU_FACTOR: + retVal = pMac->lim.gHTMaxRxAMpduFactor; + break; + + case eHT_MPDU_DENSITY: + retVal = pMac->lim.gHTAMpduDensity; + break; + + case eHT_PCO: + retVal = (uint8_t) macExtHTCapabilityInfo.pco; + break; + + case eHT_TRANSITION_TIME: + retVal = (uint8_t) macExtHTCapabilityInfo.transitionTime; + break; + + case eHT_MCS_FEEDBACK: + retVal = (uint8_t) macExtHTCapabilityInfo.mcsFeedback; + break; + + case eHT_TX_BEAMFORMING: + retVal = (uint8_t) macTxBFCapabilityInfo.txBF; + break; + + case eHT_ANTENNA_SELECTION: + retVal = (uint8_t) macASCapabilityInfo.antennaSelection; + break; + + case eHT_SI_GRANULARITY: + retVal = pMac->lim.gHTServiceIntervalGranularity; + break; + + case eHT_CONTROLLED_ACCESS: + retVal = pMac->lim.gHTControlledAccessOnly; + break; + + case eHT_RIFS_MODE: + retVal = psessionEntry->beaconParams.fRIFSMode; + break; + + case eHT_RECOMMENDED_TX_WIDTH_SET: + retVal = psessionEntry->htRecommendedTxWidthSet; + break; + + case eHT_EXTENSION_CHANNEL_OFFSET: + retVal = psessionEntry->htSecondaryChannelOffset; + break; + + case eHT_OP_MODE: + if (LIM_IS_AP_ROLE(psessionEntry)) + retVal = psessionEntry->htOperMode; + else + retVal = pMac->lim.gHTOperMode; + break; + + case eHT_BASIC_STBC_MCS: + retVal = pMac->lim.gHTSTBCBasicMCS; + break; + + case eHT_DUAL_CTS_PROTECTION: + retVal = pMac->lim.gHTDualCTSProtection; + break; + + case eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT: + retVal = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + break; + + case eHT_PCO_ACTIVE: + retVal = pMac->lim.gHTPCOActive; + break; + + case eHT_PCO_PHASE: + retVal = pMac->lim.gHTPCOPhase; + break; + + default: + break; + } + + return retVal; +} + +/** + * lim_enable_11a_protection() - updates protection params for enable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This fucntion updates protection params for enable 11a protection request + * + * @Return: void + */ +static void +lim_enable_11a_protection(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession pe_session) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if ((LIM_IS_AP_ROLE(pe_session) || LIM_IS_BT_AMP_AP_ROLE(pe_session)) + && (true == pe_session->htCapability)) { + if (overlap) { + mac_ctx->lim.gLimOverlap11aParams.protectionEnabled = + true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + mac_ctx->lim.gHTOperMode) + && (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode)) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } else { + pe_session->gLim11aParams.protectionEnabled = true; + if (eSIR_HT_OP_MODE_MIXED != pe_session->htOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_MIXED; + pe_session->htOperMode = eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } + } + /* This part is common for station as well. */ + if (false == pe_session->beaconParams.llaCoexist) { + lim_log(mac_ctx, LOGW, + FL(" => protection from 11A Enabled")); + bcn_prms->llaCoexist = true; + pe_session->beaconParams.llaCoexist = true; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_disable_11a_protection() - updates protection params for disable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This fucntion updates protection params for disable 11a protection request + * + * @Return: void + */ +static void +lim_disable_11a_protection(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession pe_session) +{ + if (false == pe_session->beaconParams.llaCoexist) + return; + + /* for station role */ + if (!LIM_IS_AP_ROLE(pe_session)) { + lim_log(mac_ctx, LOGW, + FL("===> Protection from 11A Disabled")); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + return; + } + /* + * for AP role. + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (overlap) { + /* Overlap Legacy protection disabled. */ + mac_ctx->lim.gLimOverlap11aParams.protectionEnabled = false; + + /* + * We need to take care of HT OP mode iff we are HT AP. + * OR no HT op-mode change is needed if any of the overlap + * protection enabled. + */ + if (!pe_session->htCapability || + (mac_ctx->lim.gLimOverlap11aParams.protectionEnabled + || mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled + || mac_ctx->lim.gLimOverlapNonGfParams.protectionEnabled)) + goto disable_11a_end; + + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + mac_ctx->lim.gHTOperMode) { + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + if (pe_session->gLimHt20Params.protectionEnabled) + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + else + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } + } else { + /* Disable protection from 11A stations. */ + pe_session->gLim11aParams.protectionEnabled = false; + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + /* + * Check if any other non-HT protection enabled. Right now we + * are in HT OP Mixed mode. Change HT op mode appropriately. + */ + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (mac_ctx->lim.gLimOverlap11aParams.protectionEnabled + || mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled + || mac_ctx->lim.gLimOverlapNonGfParams.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, overlap, + bcn_prms, pe_session); + } else if (pe_session->gLimHt20Params.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + pe_session->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } else { + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pe_session->htOperMode = eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } + } + +disable_11a_end: + if (!mac_ctx->lim.gLimOverlap11aParams.protectionEnabled && + !pe_session->gLim11aParams.protectionEnabled) { + lim_log(mac_ctx, LOGW, + FL("===> Protection from 11A Disabled")); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_update_11a_protection() - based on config setting enables\disables 11a + * protection. + * @mac_ctx: pointer to Global MAC structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @session: pe session entry + * + * This based on config setting enables\disables 11a protection. + * + * @Return: success of failure of operation + */ +tSirRetStatus +lim_update_11a_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams bcn_prms, + tpPESession session) +{ + if (NULL == session) { + lim_log(mac_ctx, LOGW, FL("session is NULL")); + return eSIR_FAILURE; + } + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session)) && + (!session->cfgProtection.fromlla)) { + /* protection disabled. */ + lim_log(mac_ctx, LOGW, + FL("protection from 11a is disabled")); + return eSIR_SUCCESS; + } + } + + if (enable) + lim_enable_11a_protection(mac_ctx, overlap, bcn_prms, session); + else + lim_disable_11a_protection(mac_ctx, overlap, bcn_prms, session); + + return eSIR_SUCCESS; +} + +/** + * lim_handle_enable11g_protection_enabled() - handle 11g protection enabled + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to tpPESession + * + * Function handles 11g protection enaled case + * + * Return: none + */ +static void +lim_handle_enable11g_protection_enabled(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOlbcParams.protectionEnabled = true; + + lim_log(mac_ctx, LOG1, FL("protection from olbc is enabled")); + + if (true == session_entry->htCapability) { + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + /* + * CR-263021: OBSS bit is not switching back to 0 after + * disabling the overlapping legacy BSS + */ + /* + * This fixes issue of OBSS bit not set after 11b, 11g + * station leaves + */ + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + /* + * Not processing OBSS bit from other APs, as we are + * already taking care of Protection from overlapping + * BSS based on erp IE or useProtection bit + */ + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLim11bParams.protectionEnabled = true; + lim_log(mac_ctx, LOG1, FL("protection from 11b is enabled")); + if (true == session_entry->htCapability) { + if (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + } + } + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && + (true == session_entry->htCapability) && overlap) { + session_entry->gLimOlbcParams.protectionEnabled = true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + mac_ctx->lim.gHTOperMode) && + (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode)) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + /* + * CR-263021: OBSS bit is not switching back to 0 after + * disabling the overlapping legacy BSS + */ + /* + * This fixes issue of OBSS bit not set after 11b, 11g station + * leaves + */ + lim_enable_ht_rifs_protection(mac_ctx, true, overlap, + beaconparams, session_entry); + /* + * Not processing OBSS bit from other APs, as we are already + * taking care of Protection from overlapping BSS based on erp + * IE or useProtection bit + */ + lim_enable_ht_obss_protection(mac_ctx, true, overlap, + beaconparams, session_entry); + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && + (true == session_entry->htCapability) && !overlap) { + session_entry->gLim11bParams.protectionEnabled = true; + if (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.llbCoexist) { + lim_log(mac_ctx, LOG1, FL("=> 11G Protection Enabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = true; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_handle_11g_protection_for_11bcoexist() - 11g protection for 11b co-ex + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to tpPESession + * + * Function handles 11g protection for 11b co-exist + * + * Return: none + */ +static void +lim_handle_11g_protection_for_11bcoexist(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession session_entry) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOlbcParams.protectionEnabled = false; + + /* We need to take care of HT OP mode if we are HT AP. */ + if (session_entry->htCapability) { + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + if (session_entry->gLimHt20Params. + protectionEnabled) { + if(eHT_CHANNEL_WIDTH_20MHZ == + session_entry->htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11B stations. */ + session_entry->gLim11bParams.protectionEnabled = false; + lim_log(mac_ctx, LOG1, FL("===> 11B Protection Disabled")); + /* Check if any other non-HT protection enabled. */ + if (!session_entry->gLim11gParams.protectionEnabled) { + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + beaconparams, session_entry); + /* + * Change HT OP mode to 01 if any overlap protection + * enabled + */ + if (session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, + session_entry); + } else if (session_entry->gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + if (!session_entry->gLimOlbcParams.protectionEnabled && + !session_entry->gLim11bParams.protectionEnabled) { + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = + false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } + if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOlbcParams.protectionEnabled = false; + + /* We need to take care of HT OP mode iff we are HT AP. */ + if (session_entry->htCapability) { + /* + * no HT op mode change if any of the overlap protection + * enabled. + */ + if (!(mac_ctx->lim.gLimOverlap11gParams. + protectionEnabled || + mac_ctx->lim.gLimOverlapHt20Params. + protectionEnabled || + mac_ctx->lim.gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + mac_ctx->lim.gHTOperMode)) { + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + if (session_entry->gLimHt20Params. + protectionEnabled) + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + else + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11B stations. */ + session_entry->gLim11bParams.protectionEnabled = false; + /* Check if any other non-HT protection enabled. */ + if (!session_entry->gLim11gParams.protectionEnabled) { + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + /* + * Change HT OP mode to 01 if any overlap protection + * enabled + */ + if (session_entry->gLimOlbcParams.protectionEnabled || + mac_ctx->lim.gLimOverlap11gParams. + protectionEnabled || + mac_ctx->lim.gLimOverlapHt20Params. + protectionEnabled || + mac_ctx->lim.gLimOverlapNonGfParams. + protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + } else if (session_entry->gLimHt20Params. + protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + } else { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + } + } + } + if (LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + if (!session_entry->gLimOlbcParams.protectionEnabled && + !session_entry->gLim11bParams.protectionEnabled) { + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = + false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } + /* For station role */ + if (!LIM_IS_AP_ROLE(session_entry) && + !LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, FL("===> 11G Protection Disabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_enable11g_protection() - Function to enable 11g protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * based on config setting enables\disables 11g protection. + * + * Return: Success - eSIR_SUCCESS - Success, Error number - Failure + */ +tSirRetStatus +lim_enable11g_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.fromllb) { + /* protection disabled. */ + lim_log(mac_ctx, LOG1, + FL("protection from 11b is disabled")); + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.fromllb) { + /* protection disabled. */ + lim_log(mac_ctx, LOG1, + FL("protection from 11b is disabled")); + return eSIR_SUCCESS; + } + } + } + + if (enable) { + lim_handle_enable11g_protection_enabled(mac_ctx, beaconparams, + overlap, session_entry); + } else if (true == session_entry->beaconParams.llbCoexist) { + lim_handle_11g_protection_for_11bcoexist(mac_ctx, beaconparams, + overlap, session_entry); + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_protection_from11g + \brief based on cofig enables\disables protection from 11g. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_protection_from11g(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* protection from 11g is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + if ((LIM_IS_AP_ROLE(psessionEntry)) + && (!psessionEntry->cfgProtection.overlapFromllg)) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("overlap protection from 11g is disabled")); + ); + return eSIR_SUCCESS; + } else if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry) && + (!pMac->lim.cfgProtection.overlapFromllg)) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("overlap protection from 11g is disabled")); + ); + return eSIR_SUCCESS; + } + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.fromllg) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from 11g is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!pMac->lim.cfgProtection.fromllg) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from 11g is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + if (enable) { + /* If we are AP and HT capable, we need to set the HT OP mode */ + /* appropriately. */ + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (overlap) { + psessionEntry->gLimOverlap11gParams. + protectionEnabled = true; + /* 11g exists in overlap BSS. */ + /* need not to change the operating mode to overlap_legacy */ + /* if higher or same protection operating mode is enabled right now. */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + psessionEntry->htOperMode) + && (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode)) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + lim_enable_ht_rifs_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + } else { + /* 11g is associated to an AP operating in 11n mode. */ + /* Change the HT operating mode to 'mixed mode'. */ + psessionEntry->gLim11gParams.protectionEnabled = + true; + if (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + } + } + } else if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + if (overlap) { + pMac->lim.gLimOverlap11gParams. + protectionEnabled = true; + /* 11g exists in overlap BSS. */ + /* need not to change the operating mode to overlap_legacy */ + /* if higher or same protection operating mode is enabled right now. */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + pMac->lim.gHTOperMode) + && (eSIR_HT_OP_MODE_MIXED != + pMac->lim.gHTOperMode)) { + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + } + } else { + /* 11g is associated to an AP operating in 11n mode. */ + /* Change the HT operating mode to 'mixed mode'. */ + psessionEntry->gLim11gParams.protectionEnabled = + true; + if (eSIR_HT_OP_MODE_MIXED != + pMac->lim.gHTOperMode) { + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + /* This part is common for staiton as well. */ + if (false == psessionEntry->beaconParams.llgCoexist) { + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } else if (true == + psessionEntry->gLimOverlap11gParams. + protectionEnabled) { + /* As operating mode changed after G station assoc some way to update beacon */ + /* This addresses the issue of mode not changing to - 11 in beacon when OBSS overlap is enabled */ + /* pMac->sch.schObject.fBeaconChanged = 1; */ + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } else if (true == psessionEntry->beaconParams.llgCoexist) { + /* for AP role. */ + /* we need to take care of HT OP mode change if needed. */ + /* We need to take care of Overlap cases. */ + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (overlap) { + /* Overlap Legacy protection disabled. */ + if (psessionEntry->gLim11gParams.numSta == 0) + psessionEntry->gLimOverlap11gParams. + protectionEnabled = false; + + /* no HT op mode change if any of the overlap protection enabled. */ + if (! + (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry->gLimOverlapHt20Params. + protectionEnabled + || psessionEntry->gLimOverlapNonGfParams. + protectionEnabled)) { + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + psessionEntry->htOperMode) { + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + + if (psessionEntry->gLimHt20Params.protectionEnabled) { + if(eHT_CHANNEL_WIDTH_20MHZ == + psessionEntry->htSupportedChannelWidthSet) + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else { + /* Disable protection from 11G stations. */ + psessionEntry->gLim11gParams.protectionEnabled = + false; + /* Check if any other non-HT protection enabled. */ + if (!psessionEntry->gLim11bParams. + protectionEnabled) { + + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(pMac, false, + overlap, + pBeaconParams, + psessionEntry); + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry-> + gLimOverlap11gParams. + protectionEnabled + || psessionEntry-> + gLimOverlapHt20Params. + protectionEnabled + || psessionEntry-> + gLimOverlapNonGfParams. + protectionEnabled) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(pMac, + true, + overlap, + pBeaconParams, + psessionEntry); + } else if (psessionEntry-> + gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* psessionEntry->htOperMode = eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } else { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + if (!psessionEntry->gLimOverlap11gParams. + protectionEnabled + && !psessionEntry->gLim11gParams. + protectionEnabled) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("===> Protection from 11G Disabled")); + ) + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = + false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } else if (LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + if (overlap) { + /* Overlap Legacy protection disabled. */ + pMac->lim.gLimOverlap11gParams. + protectionEnabled = false; + + /* no HT op mode change if any of the overlap protection enabled. */ + if (! + (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry->gLimOverlapHt20Params. + protectionEnabled + || psessionEntry->gLimOverlapNonGfParams. + protectionEnabled)) { + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pMac->lim.gHTOperMode) { + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + + if (psessionEntry-> + gLimHt20Params. + protectionEnabled) + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + else + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else { + /* Disable protection from 11G stations. */ + psessionEntry->gLim11gParams.protectionEnabled = + false; + /* Check if any other non-HT protection enabled. */ + if (!psessionEntry->gLim11bParams. + protectionEnabled) { + + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(pMac, false, + overlap, + pBeaconParams, + psessionEntry); + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (psessionEntry->gLimOlbcParams. + protectionEnabled + || pMac->lim.gLimOverlap11gParams. + protectionEnabled + || pMac->lim.gLimOverlapHt20Params. + protectionEnabled + || pMac->lim.gLimOverlapNonGfParams. + protectionEnabled) { + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(pMac, + true, + overlap, + pBeaconParams, + psessionEntry); + } else if (psessionEntry-> + gLimHt20Params. + protectionEnabled) { + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } else { + pMac->lim.gHTOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + if (!pMac->lim.gLimOverlap11gParams.protectionEnabled && + !psessionEntry->gLim11gParams.protectionEnabled) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("===> Protection from 11G Disabled")); + ) + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = + false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + /* for station role */ + else { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from 11G Disabled")); + ) + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ + +/** ------------------------------------------------------------- + \fn limEnableHtObssProtection + \brief based on cofig enables\disables obss protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_obss_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + /* overlapping protection configuration check. */ + } else { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(psessionEntry)) && + !psessionEntry->cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + PELOG1(lim_log + (pMac, LOG1, + FL("protection from Obss is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!pMac->lim.cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + PELOG1(lim_log + (pMac, LOG1, + FL("protection from Obss is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("=>obss protection enabled")); + ) + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> obss Protection disabled")); + ) + psessionEntry->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } +/* CR-263021: OBSS bit is not switching back to 0 after disabling the overlapping legacy BSS */ + if (!enable && !overlap) { + psessionEntry->gLimOverlap11gParams.protectionEnabled = + false; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("=>obss protection enabled")); + ) + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + + PELOG1(lim_log + (pMac, LOG1, + FL("===> obss Protection disabled")); + ) + psessionEntry->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } + } + return eSIR_SUCCESS; +} + +/** + * lim_handle_ht20protection_enabled() - Handle ht20 protection enabled + * @mac_ctx: pointer to Gloal Mac Structure + * @overlap: variable for overlap detection + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * Function handles ht20 protection enabled + * + * Return: none + */ +static void lim_handle_ht20protection_enabled(tpAniSirGlobal mac_ctx, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOverlapHt20Params.protectionEnabled = true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLimHt20Params.protectionEnabled = true; + if (eSIR_HT_OP_MODE_PURE == session_entry->htOperMode) { + if (session_entry->htSupportedChannelWidthSet != + eHT_CHANNEL_WIDTH_20MHZ) + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && overlap) { + mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled = + true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + mac_ctx->lim.gHTOperMode) && + (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode)) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && !overlap) { + session_entry->gLimHt20Params.protectionEnabled = true; + if (eSIR_HT_OP_MODE_PURE == mac_ctx->lim.gHTOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.ht20Coexist) { + lim_log(mac_ctx, LOG1, + FL("=> Protection from HT20 Enabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = true; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_handle_ht20coexist_ht20protection() - ht20 protection for ht20 coexist + * @mac_ctx: pointer to Gloal Mac Structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * @overlap: variable for overlap detection + * + * Function handles ht20 protection for ht20 coexist + * + * Return: none + */ +static void lim_handle_ht20coexist_ht20protection(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + tpPESession session_entry, uint8_t overlap) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOverlapHt20Params.protectionEnabled = + false; + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams.protectionEnabled || + session_entry->gLimOverlapHt20Params.protectionEnabled + || session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + if (session_entry->gLimHt20Params. + protectionEnabled) { + if(eHT_CHANNEL_WIDTH_20MHZ == + session_entry->htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11G stations. */ + session_entry->gLimHt20Params.protectionEnabled = false; + /* Change HT op mode appropriately. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, + FL("===> Protection from HT 20 Disabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } + if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled = false; + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOlbcParams.protectionEnabled || + mac_ctx->lim.gLimOverlap11gParams.protectionEnabled || + mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled || + mac_ctx->lim.gLimOverlapNonGfParams.protectionEnabled) + /* + * Check if there is a need to change + * HT OP mode. + */ + && (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + mac_ctx->lim.gHTOperMode)) { + if (session_entry->gLimHt20Params.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } else { + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_BT_AMP_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11G stations. */ + session_entry->gLimHt20Params.protectionEnabled = false; + + /* Change HT op mode appropriately. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + mac_ctx->lim.gHTOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + if (LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, + FL("===> Protection from HT 20 Disabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } + + if (!LIM_IS_AP_ROLE(session_entry) && + !LIM_IS_BT_AMP_AP_ROLE(session_entry)) { + /* For station role */ + lim_log(mac_ctx, LOG1, + FL("===> Protection from HT20 Disabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_enable_ht20_protection() - Function to enable ht20 protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * based on cofig enables\disables protection from Ht20 + * + * Return: 0 - success + */ +tSirRetStatus lim_enable_ht20_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + /* This protection is only for HT stations. */ + if (!session_entry->htCapability) + return eSIR_SUCCESS; + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.ht20) { + /* protection disabled. */ + lim_log(mac_ctx, LOG3, + FL("protection from HT20 is disabled")); + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.ht20) { + /* protection disabled. */ + lim_log(mac_ctx, LOG3, + FL("protection from HT20 is disabled")); + return eSIR_SUCCESS; + } + } + } + + if (enable) + lim_handle_ht20protection_enabled(mac_ctx, overlap, + beaconparams, session_entry); + else if (true == session_entry->beaconParams.ht20Coexist) + lim_handle_ht20coexist_ht20protection(mac_ctx, beaconparams, + session_entry, overlap); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_non_gf_protection + \brief based on cofig enables\disables protection from NonGf. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_non_gf_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.nonGf) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from NonGf is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.nonGf) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + ("protection from NonGf is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from non GF Enabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from Non GF Disabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from non GF Enabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from Non GF Disabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_lsig_txop_protection + \brief based on cofig enables\disables LsigTxop protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_lsig_txop_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.lsigTxop) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from LsigTxop not supported is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.lsigTxop) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from LsigTxop not supported is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from LsigTxop Enabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from LsigTxop Disabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } else { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from LsigTxop Enabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from LsigTxop Disabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ +/** ------------------------------------------------------------- + \fn lim_enable_ht_rifs_protection + \brief based on cofig enables\disables Rifs protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_rifs_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.rifs) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL(" protection from Rifs is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.rifs) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from Rifs is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL(" => Rifs protection Disabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Rifs Protection Enabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } else { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL(" => Rifs protection Disabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Rifs Protection Enabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------- */ +/** + * lim_enable_short_preamble + * + * FUNCTION: + * Enable/Disable short preamble + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short preamble + * @return None + */ + +tSirRetStatus +lim_enable_short_preamble(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint32_t val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + /* Could not get short preamble enabled flag from CFG. Log error. */ + lim_log(pMac, LOGP, + FL("could not retrieve short preamble flag")); + return eSIR_FAILURE; + } + + if (!val) + return eSIR_SUCCESS; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("could not retrieve 11G short preamble switching enabled flag")); + return eSIR_FAILURE; + } + + if (!val) /* 11G short preamble switching is disabled. */ + return eSIR_SUCCESS; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (enable && (psessionEntry->beaconParams.fShortPreamble == 0)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Short Preamble Enabled")); + ) + psessionEntry->beaconParams.fShortPreamble = true; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } else if (!enable + && (psessionEntry->beaconParams.fShortPreamble == + 1)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Short Preamble Disabled")); + ) + psessionEntry->beaconParams.fShortPreamble = false; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } + } + + return eSIR_SUCCESS; +} + +/** + * lim_tx_complete + * + * Function: + * This is LIM's very own "TX MGMT frame complete" completion routine. + * + * Logic: + * LIM wants to send a MGMT frame (broadcast or unicast) + * LIM allocates memory using cds_packet_alloc( ..., **pData, **pPacket ) + * LIM transmits the MGMT frame using the API: + * wma_tx_frame( ... pPacket, ..., (void *) lim_tx_complete, pData ) + * HDD, via wma_tx_frame/DXE, "transfers" the packet over to BMU + * HDD, if it determines that a TX completion routine (in this case + * lim_tx_complete) has been provided, will invoke this callback + * LIM will try to free the TX MGMT packet that was earlier allocated, in order + * to send this MGMT frame, using the PAL API cds_packet_free( ... pData, pPacket ) + * + * Assumptions: + * Presently, this is ONLY being used for MGMT frames/packets + * TODO: + * Would it do good for LIM to have some sort of "signature" validation to + * ensure that the pData argument passed in was a buffer that was actually + * allocated by LIM and/or is not corrupted? + * + * Note: FIXME and TODO + * Looks like cds_packet_free() is interested in pPacket. But, when this completion + * routine is called, only pData is made available to LIM!! + * + * @param void A pointer to pData. Shouldn't it be pPacket?! + * + * @return none + */ +void lim_tx_complete(tHalHandle hHal, void *data, bool free) +{ + if (free) + cds_packet_free((void *)data); +} + +/** + * \brief This function updates lim global structure, if CB parameters in the BSS + * have changed, and sends an indication to HAL also with the + * updated HT Parameters. + * This function does not detect the change in the primary channel, that is done as part + * of channel Swtich IE processing. + * If STA is configured with '20Mhz only' mode, then this function does not do anything + * This function changes the CB mode, only if the self capability is set to '20 as well as 40Mhz' + * + * + * \param pMac Pointer to global MAC structure + * + * \param pRcvdHTInfo Pointer to HT Info IE obtained from a Beacon or + * Probe Response + * + * \param bssIdx BSS Index of the Bss to which Station is associated. + * + * + */ + +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry) +{ + uint8_t center_freq = 0; +#if !defined WLAN_FEATURE_VOWIFI + uint32_t localPwrConstraint; +#endif + + /* If self capability is set to '20Mhz only', then do not change the CB mode. */ + if (!lim_get_ht_capability + (pMac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, psessionEntry)) + return; + +#if !defined WLAN_FEATURE_VOWIFI + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Local Power Constraint from cfg")); + return; + } +#endif + + if (psessionEntry->ftPEContext.ftPreAuthSession) { + lim_log(pMac, LOGE, + FL("FT PREAUTH channel change is in progress")); + return; + } + + if (psessionEntry->htSecondaryChannelOffset != + (uint8_t) pHTInfo->secondaryChannelOffset + || psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htSecondaryChannelOffset = + (ePhyChanBondState) pHTInfo->secondaryChannelOffset; + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + if (eHT_CHANNEL_WIDTH_40MHZ == + psessionEntry->htRecommendedTxWidthSet) { + if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel + 2; + else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel - 2; + } + + /* notify HAL */ + lim_log(pMac, LOGW, FL("Channel Information in HT IE change" + "d; sending notification to HAL.")); + lim_log(pMac, LOGW, FL("Primary Channel: %d, Secondary Chan" + "nel Offset: %d, Channel Width: %d"), + pHTInfo->primaryChannel, center_freq, + psessionEntry->htRecommendedTxWidthSet); + psessionEntry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = NULL; + pMac->lim.gpchangeChannelData = NULL; + +#if defined WLAN_FEATURE_VOWIFI + lim_send_switch_chnl_params(pMac, (uint8_t) pHTInfo->primaryChannel, + center_freq, 0, + psessionEntry->htRecommendedTxWidthSet, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + true); +#else + lim_send_switch_chnl_params(pMac, (uint8_t) pHTInfo->primaryChannel, + center_freq, 0, + psessionEntry->htRecommendedTxWidthSet, + (tPowerdBm) localPwrConstraint, + psessionEntry->peSessionId, + true); +#endif + + /* In case of IBSS, if STA should update HT Info IE in its beacons. */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + + } +} /* End limUpdateStaRunTimeHTParams. */ + +/** + * \brief This function updates the lim global structure, if any of the + * HT Capabilities have changed. + * + * + * \param pMac Pointer to Global MAC structure + * + * \param pHTCapability Pointer to HT Capability Information Element + * obtained from a Beacon or Probe Response + * + * + * + */ + +void lim_update_sta_run_time_ht_capability(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps) +{ + + if (pMac->lim.gHTLsigTXOPProtection != + (uint8_t) pHTCaps->lsigTXOPProtection) { + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) pHTCaps->lsigTXOPProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTAMpduDensity != (uint8_t) pHTCaps->mpduDensity) { + pMac->lim.gHTAMpduDensity = (uint8_t) pHTCaps->mpduDensity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTMaxRxAMpduFactor != + (uint8_t) pHTCaps->maxRxAMPDUFactor) { + pMac->lim.gHTMaxRxAMpduFactor = + (uint8_t) pHTCaps->maxRxAMPDUFactor; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_capability. */ + +/** + * \brief This function updates lim global structure, if any of the HT + * Info Parameters have changed. + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pHTInfo Pointer to the HT Info IE obtained from a Beacon or + * Probe Response + * + * + */ + +void lim_update_sta_run_time_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + tpPESession psessionEntry) +{ + if (psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fRIFSMode != + (uint8_t) pHTInfo->rifsMode) { + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) pHTInfo->rifsMode; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTServiceIntervalGranularity != + (uint8_t) pHTInfo->serviceIntervalGranularity) { + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) pHTInfo->serviceIntervalGranularity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTOperMode != (tSirMacHTOperatingMode) pHTInfo->opMode) { + pMac->lim.gHTOperMode = + (tSirMacHTOperatingMode) pHTInfo->opMode; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.llnNonGFCoexist != + pHTInfo->nonGFDevicesPresent) { + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) pHTInfo->nonGFDevicesPresent; + } + + if (pMac->lim.gHTSTBCBasicMCS != (uint8_t) pHTInfo->basicSTBCMCS) { + pMac->lim.gHTSTBCBasicMCS = (uint8_t) pHTInfo->basicSTBCMCS; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTDualCTSProtection != + (uint8_t) pHTInfo->dualCTSProtection) { + pMac->lim.gHTDualCTSProtection = + (uint8_t) pHTInfo->dualCTSProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTSecondaryBeacon != (uint8_t) pHTInfo->secondaryBeacon) { + pMac->lim.gHTSecondaryBeacon = + (uint8_t) pHTInfo->secondaryBeacon; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport != + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport) { + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOActive != (uint8_t) pHTInfo->pcoActive) { + pMac->lim.gHTPCOActive = (uint8_t) pHTInfo->pcoActive; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOPhase != (uint8_t) pHTInfo->pcoPhase) { + pMac->lim.gHTPCOPhase = (uint8_t) pHTInfo->pcoPhase; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_info. */ + +/** ------------------------------------------------------------- + \fn lim_process_hal_ind_messages + \brief callback function for HAL indication + \param tpAniSirGlobal pMac + \param uint32_t mesgId + \param void *mesgParam + \return tSirRetStatu - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t msgId, + void *msgParam) +{ + /* its PE's responsibility to free msgparam when its done extracting the message parameters. */ + tSirMsgQ msg; + + switch (msgId) { + case SIR_LIM_DEL_TS_IND: + case SIR_LIM_DELETE_STA_CONTEXT_IND: + case SIR_LIM_BEACON_GEN_IND: + msg.type = (uint16_t) msgId; + msg.bodyptr = msgParam; + msg.bodyval = 0; + break; + + default: + cdf_mem_free(msgParam); + lim_log(pMac, LOGP, FL("invalid message id = %d received"), + msgId); + return eSIR_FAILURE; + } + + if (lim_post_msg_api(pMac, &msg) != eSIR_SUCCESS) { + cdf_mem_free(msgParam); + lim_log(pMac, LOGP, FL("lim_post_msg_api failed for msgid = %d"), + msg.type); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** + * lim_validate_delts_req() - This function validates DelTs req + * @mac_ctx: pointer to Global Mac structure + * @delts_req: pointer to delete traffic stream structure + * @peer_mac_addr: variable for peer mac address + * + * Function validates DelTs req originated by SME or by HAL and also + * sends halMsg_DelTs to HAL + * + * Return: eSIR_SUCCESS - Success, eSIR_FAILURE - Failure + */ + +tSirRetStatus +lim_validate_delts_req(tpAniSirGlobal mac_ctx, tpSirDeltsReq delts_req, + tSirMacAddr peer_mac_addr, tpPESession psession_entry) +{ + tpDphHashNode sta; + uint8_t ts_status; + tSirMacTSInfo *tsinfo; + uint32_t i; + uint8_t tspec_idx; + + /* + * if sta + * - verify assoc state + * - del tspec locally + * if ap + * - verify sta is in assoc state + * - del sta tspec locally + */ + if (delts_req == NULL) { + lim_log(mac_ctx, LOGE, + FL("Delete TS request pointer is NULL")); + return eSIR_FAILURE; + } + + if (LIM_IS_STA_ROLE(psession_entry) || + LIM_IS_BT_AMP_STA_ROLE(psession_entry)) { + uint32_t val; + + /* station always talks to the AP */ + sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &psession_entry->dph.dphHashTable); + + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(peer_mac_addr, psession_entry->bssId); + + } else { + uint16_t associd; + uint8_t *macaddr = (uint8_t *) peer_mac_addr; + + associd = delts_req->aid; + if (associd != 0) + sta = dph_get_hash_entry(mac_ctx, associd, + &psession_entry->dph.dphHashTable); + else + sta = dph_lookup_hash_entry(mac_ctx, + delts_req->macAddr, + &associd, + &psession_entry->dph. + dphHashTable); + + if (sta != NULL) + /* TBD: check sta assoc state as well */ + for (i = 0; i < sizeof(tSirMacAddr); i++) + macaddr[i] = sta->staAddr[i]; + } + + if (sta == NULL) { + lim_log(mac_ctx, LOGE, + FL("Cannot find station context for delts req")); + return eSIR_FAILURE; + } + + if ((!sta->valid) || + (sta->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + lim_log(mac_ctx, LOGE, + FL("Invalid Sta (or state) for DelTsReq")); + return eSIR_FAILURE; + } + + delts_req->req.wsmTspecPresent = 0; + delts_req->req.wmeTspecPresent = 0; + delts_req->req.lleTspecPresent = 0; + + if ((sta->wsmEnabled) && + (delts_req->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + delts_req->req.wsmTspecPresent = 1; + else if (sta->wmeEnabled) + delts_req->req.wmeTspecPresent = 1; + else if (sta->lleEnabled) + delts_req->req.lleTspecPresent = 1; + else { + lim_log(mac_ctx, LOGW, + FL("DELTS_REQ ignore - qos is disabled")); + return eSIR_FAILURE; + } + + tsinfo = delts_req->req.wmeTspecPresent ? &delts_req->req.tspec.tsinfo + : &delts_req->req.tsinfo; + lim_log(mac_ctx, LOG1, + FL("received DELTS_REQ message (wmeTspecPresent = %d, lleTspecPresent = %d, wsmTspecPresent = %d, tsid %d, up %d, direction = %d)"), + delts_req->req.wmeTspecPresent, + delts_req->req.lleTspecPresent, + delts_req->req.wsmTspecPresent, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio, tsinfo->traffic.direction); + + /* if no Access Control, ignore the request */ + if (lim_admit_control_delete_ts(mac_ctx, sta->assocId, tsinfo, + &ts_status, &tspec_idx) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("ERROR DELTS request for sta assocId %d (tsid %d, up %d)"), + sta->assocId, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio); + return eSIR_FAILURE; + } else if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) { + /* edca only now. */ + } else if (tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + /* send message to HAL to delete TS */ + if (eSIR_SUCCESS != + lim_send_hal_msg_del_ts(mac_ctx, sta->staIndex, + tspec_idx, delts_req->req, + psession_entry->peSessionId, + psession_entry->bssId)) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d failed in lim_send_hal_msg_del_ts - ignoring request"), + tsinfo->traffic.userPrio); + return eSIR_FAILURE; + } + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_register_hal_ind_call_back + \brief registers callback function to HAL for any indication. + \param tpAniSirGlobal pMac + \return none. + -------------------------------------------------------------*/ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac) +{ + tSirMsgQ msg; + tpHalIndCB pHalCB; + + pHalCB = cdf_mem_malloc(sizeof(tHalIndCB)); + if (NULL == pHalCB) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return; + } + + pHalCB->pHalIndCB = lim_process_hal_ind_messages; + + msg.type = WMA_REGISTER_PE_CALLBACK; + msg.bodyptr = pHalCB; + msg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + cdf_mem_free(pHalCB); + lim_log(pMac, LOGP, FL("wma_post_ctrl_msg() failed")); + } + + return; +} + +/** + * lim_process_del_ts_ind() - handle del_ts_ind from HAL + * + * @mac_ctx: pointer to Global Mac Structure + * @lim_msg: pointer to msg buff + * + * handles the DeleteTS indication coming from HAL or generated by PE itself + * in some error cases. Validates the request, sends the DelTs action frame + * to the Peer and sends DelTs indicatoin to HDD. + * + * Return: none + */ +void lim_process_del_ts_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpDphHashNode pSta; + tpDelTsParams pDelTsParam = (tpDelTsParams) (limMsg->bodyptr); + tpSirDeltsReq pDelTsReq = NULL; + tSirMacAddr peerMacAddr; + tpSirDeltsReqInfo pDelTsReqInfo; + tpLimTspecInfo pTspecInfo; + tpPESession psessionEntry; + uint8_t sessionId; + + psessionEntry = pe_find_session_by_bssid(pMac, pDelTsParam->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given BssId")); + cdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; + } + + pTspecInfo = &(pMac->lim.tspecInfo[pDelTsParam->tspecIdx]); + if (pTspecInfo->inuse == false) { + PELOGE(lim_log + (pMac, LOGE, + FL("tspec entry with index %d is not in use"), + pDelTsParam->tspecIdx); + ) + goto error1; + } + + pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL("Could not find entry in DPH table for assocId = %d"), + pTspecInfo->assocId); + goto error1; + } + + pDelTsReq = cdf_mem_malloc(sizeof(tSirDeltsReq)); + if (NULL == pDelTsReq) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + goto error1; + } + + cdf_mem_set((uint8_t *) pDelTsReq, sizeof(tSirDeltsReq), 0); + + if (pSta->wmeEnabled) + cdf_mem_copy(&(pDelTsReq->req.tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + cdf_mem_copy(&(pDelTsReq->req.tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + /* validate the req */ + if (eSIR_SUCCESS != + lim_validate_delts_req(pMac, pDelTsReq, peerMacAddr, psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, FL("lim_validate_delts_req failed"));) + goto error2; + } + PELOG1(lim_log(pMac, LOG1, "Sent DELTS request to station with " + "assocId = %d MacAddr = " MAC_ADDRESS_STR, + pDelTsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + ) + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDelTsReq->req.wmeTspecPresent, + &pDelTsReq->req.tsinfo, + &pDelTsReq->req.tspec, psessionEntry); + + /* prepare and send an sme indication to HDD */ + pDelTsReqInfo = cdf_mem_malloc(sizeof(tSirDeltsReqInfo)); + if (NULL == pDelTsReqInfo) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + goto error3; + } + cdf_mem_set((uint8_t *) pDelTsReqInfo, sizeof(tSirDeltsReqInfo), 0); + + if (pSta->wmeEnabled) + cdf_mem_copy(&(pDelTsReqInfo->tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + cdf_mem_copy(&(pDelTsReqInfo->tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + lim_send_sme_delts_ind(pMac, pDelTsReqInfo, pDelTsReq->aid, psessionEntry); + +error3: + cdf_mem_free(pDelTsReqInfo); +error2: + cdf_mem_free(pDelTsReq); +error1: + cdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; +} + +/** + * @function : lim_post_sm_state_update() + * + * @brief : This function Updates the HAL and Softmac about the change in the STA's SMPS state. + * + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param limMsg - Lim Message structure object with the MimoPSparam in body + * @return None + */ +tSirRetStatus +lim_post_sm_state_update(tpAniSirGlobal pMac, + uint16_t staIdx, tSirMacHTMIMOPowerSaveState state, + uint8_t *pPeerStaMac, uint8_t sessionId) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + tpSetMIMOPS pMIMO_PSParams; + + msgQ.reserved = 0; + msgQ.type = WMA_SET_MIMOPS_REQ; + + /* Allocate for WMA_SET_MIMOPS_REQ */ + pMIMO_PSParams = cdf_mem_malloc(sizeof(tSetMIMOPS)); + if (NULL == pMIMO_PSParams) { + lim_log(pMac, LOGP, FL(" AllocateMemory failed")); + return eSIR_MEM_ALLOC_FAILED; + } + + pMIMO_PSParams->htMIMOPSState = state; + pMIMO_PSParams->staIdx = staIdx; + pMIMO_PSParams->fsendRsp = true; + pMIMO_PSParams->sessionId = sessionId; + cdf_mem_copy(pMIMO_PSParams->peerMac, pPeerStaMac, sizeof(tSirMacAddr)); + + msgQ.bodyptr = pMIMO_PSParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG2, FL("Sending WMA_SET_MIMOPS_REQ...")); + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGP, + FL + ("Posting WMA_SET_MIMOPS_REQ to HAL failed! Reason = %d"), + retCode); + cdf_mem_free(pMIMO_PSParams); + return retCode; + } + + return retCode; +} + +void lim_pkt_free(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pRxPacketInfo, void *pBody) +{ + (void)pMac; + (void)frmType; + (void)pRxPacketInfo; + (void)pBody; +} + +/** + * lim_get_b_dfrom_rx_packet() + * + ***FUNCTION: + * This function is called to get pointer to Polaris + * Buffer Descriptor containing MAC header & other control + * info from the body of the message posted to LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param body - Received message body + * @param pRxPacketInfo - Pointer to received BD + * @return None + */ + +void +lim_get_b_dfrom_rx_packet(tpAniSirGlobal pMac, void *body, uint32_t **pRxPacketInfo) +{ + *pRxPacketInfo = (uint32_t *) body; +} /*** end lim_get_b_dfrom_rx_packet() ***/ + +void lim_resset_scan_channel_info(tpAniSirGlobal pMac) +{ + cdf_mem_set(&pMac->lim.scanChnInfo, sizeof(tLimScanChnInfo), 0); +} + +/** + * @function : lim_is_channel_valid_for_channel_switch() + * + * @brief : This function checks if the channel to which AP + * is expecting us to switch, is a valid channel for us. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param channel - New channel to which we are expected to move + * @return None + */ +tAniBool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, uint8_t channel) +{ + uint8_t index; + uint32_t validChannelListLen = WNI_CFG_VALID_CHANNEL_LIST_LEN; + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) validChannelList, + (uint32_t *) &validChannelListLen) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve valid channel list")); + ) + return eSIR_FALSE; + } + + for (index = 0; index < validChannelListLen; index++) { + if (validChannelList[index] == channel) + return eSIR_TRUE; + } + + /* channel does not belong to list of valid channels */ + return eSIR_FALSE; +} + +/**------------------------------------------------------ + \fn __lim_fill_tx_control_params + \brief Fill the message for stopping/resuming tx. + + \param pMac + \param pTxCtrlMsg - Pointer to tx control message. + \param type - Which way we want to stop/ resume tx. + \param mode - To stop/resume. + -------------------------------------------------------*/ +static CDF_STATUS +__lim_fill_tx_control_params(tpAniSirGlobal pMac, tpTxControlParams pTxCtrlMsg, + tLimQuietTxMode type, tLimControlTx mode) +{ + + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + + if (mode == eLIM_STOP_TX) + pTxCtrlMsg->stopTx = true; + else + pTxCtrlMsg->stopTx = false; + + switch (type) { + case eLIM_TX_ALL: + /** Stops/resumes transmission completely */ + pTxCtrlMsg->fCtrlGlobal = 1; + break; + + case eLIM_TX_BSS_BUT_BEACON: + /** Stops/resumes transmission on a particular BSS. Stopping BSS, doesnt + * stop beacon transmission. + */ + pTxCtrlMsg->ctrlBss = 1; + pTxCtrlMsg->bssBitmap |= (1 << psessionEntry->bssIdx); + break; + + case eLIM_TX_STA: + /** Memory for station bitmap is allocated dynamically in caller of this + * so decode properly here and fill the bitmap. Now not implemented, + * fall through. + */ + case eLIM_TX_BSS: + /* Fall thru... */ + default: + PELOGW(lim_log(pMac, LOGW, FL("Invalid case: Not Handled"));) + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * @function : lim_frame_transmission_control() + * + * @brief : This API is called by the user to halt/resume any frame + * transmission from the device. If stopped, all frames will be + * queued starting from hardware. Then back-pressure + * is built till the driver. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode) +{ + + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpTxControlParams pTxCtrlMsg; + tSirMsgQ msgQ; + uint8_t nBytes = 0; /* No of bytes required for station bitmap. */ + + /** Allocate only required number of bytes for station bitmap + * Make it to align to 4 byte boundary */ + nBytes = (uint8_t) HALMSG_NUMBYTES_STATION_BITMAP(pMac->lim.maxStation); + + pTxCtrlMsg = cdf_mem_malloc(sizeof(*pTxCtrlMsg) + nBytes); + if (NULL == pTxCtrlMsg) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return; + } + + cdf_mem_set((void *)pTxCtrlMsg, (sizeof(*pTxCtrlMsg) + nBytes), 0); + status = __lim_fill_tx_control_params(pMac, pTxCtrlMsg, type, mode); + if (status != CDF_STATUS_SUCCESS) { + cdf_mem_free(pTxCtrlMsg); + lim_log(pMac, LOGP, + FL("__lim_fill_tx_control_params failed, status = %d"), + status); + return; + } + + msgQ.bodyptr = (void *)pTxCtrlMsg; + msgQ.bodyval = 0; + msgQ.reserved = 0; + msgQ.type = WMA_TRANSMISSION_CONTROL_IND; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + if (wma_post_ctrl_msg(pMac, &msgQ) != eSIR_SUCCESS) { + cdf_mem_free(pTxCtrlMsg); + lim_log(pMac, LOGP, FL("Posting Message to HAL failed")); + return; + } + + if (mode == eLIM_STOP_TX) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("Stopping the transmission of all packets, indicated softmac")); + ) + } else { + PELOG1(lim_log + (pMac, LOG1, + FL + ("Resuming the transmission of all packets, indicated softmac")); + ) + } + return; +} + +/** + * @function : lim_restore_pre_channel_switch_state() + * + * @brief : This API is called by the user to undo any + * specific changes done on the device during + * channel switch. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +tSirRetStatus +lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + tSirRetStatus retCode = eSIR_SUCCESS; + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return retCode; + + /* Channel switch should be ready for the next time */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_INIT; + + /* Restore the frame transmission, all the time. */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + return retCode; +} + +/**-------------------------------------------- + \fn lim_restore_pre_quiet_state + \brief Restore the pre quiet state + + \param pMac + \return NONE + ---------------------------------------------*/ +tSirRetStatus lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + + tSirRetStatus retCode = eSIR_SUCCESS; + + if (pMac->lim.gLimSystemRole != eLIM_STA_ROLE) + return retCode; + + /* Quiet should be ready for the next time */ + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Restore the frame transmission, all the time. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + return retCode; +} + +/** + * @function: lim_prepare_for11h_channel_switch() + * + * @brief : This API is called by the user to prepare for + * 11h channel switch. As of now, the API does + * very minimal work. User can add more into the + * same API if needed. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param psessionEntry + * @return None + */ +void +lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + /* Flag to indicate 11h channel switch in progress */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_RUNNING; + + if (pMac->lim.gLimSmeState == eLIM_SME_LINK_EST_WT_SCAN_STATE || + pMac->lim.gLimSmeState == eLIM_SME_CHANNEL_SCAN_STATE) { + PELOGE(lim_log + (pMac, LOG1, + FL("Posting finish scan as we are in scan state")); + ) + /* Stop ongoing scanning if any */ + if (GET_LIM_PROCESS_DEFD_MESGS(pMac)) { + /* Set the resume channel to Any valid channel (invalid). */ + /* This will instruct HAL to set it to any previous valid channel. */ + pe_set_resume_channel(pMac, 0, 0); + } else { + lim_restore_pre_channel_switch_state(pMac, psessionEntry); + } + return; + } else { + PELOGE(lim_log + (pMac, LOG1, + FL("Not in scan state, start channel switch timer")); + ) + /** We are safe to switch channel at this point */ + lim_stop_tx_and_switch_channel(pMac, psessionEntry->peSessionId); + } +} + +/**---------------------------------------------------- + \fn lim_get_nw_type + + \brief Get type of the network from data packet or beacon + \param pMac + \param channelNum - Channel number + \param type - Type of packet. + \param pBeacon - Pointer to beacon or probe response + + \return Network type a/b/g. + -----------------------------------------------------*/ +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, uint32_t type, + tpSchBeaconStruct pBeacon) +{ + tSirNwType nwType = eSIR_11B_NW_TYPE; + + if (type == SIR_MAC_DATA_FRAME) { + if ((channelNum > 0) && (channelNum < 15)) { + nwType = eSIR_11G_NW_TYPE; + } else { + nwType = eSIR_11A_NW_TYPE; + } + } else { + if ((channelNum > 0) && (channelNum < 15)) { + int i; + /* 11b or 11g packet */ + /* 11g iff extended Rate IE is present or */ + /* if there is an A rate in suppRate IE */ + for (i = 0; i < pBeacon->supportedRates.numRates; i++) { + if (sirIsArate + (pBeacon->supportedRates.rate[i] & 0x7f)) { + nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (pBeacon->extendedRatesPresent) { + PELOG3(lim_log + (pMac, LOG3, FL("Beacon, nwtype=G")); + ) + nwType = eSIR_11G_NW_TYPE; + } + } else { + /* 11a packet */ + PELOG3(lim_log(pMac, LOG3, FL("Beacon, nwtype=A"));) + nwType = eSIR_11A_NW_TYPE; + } + } + return nwType; +} + +/**--------------------------------------------------------- + \fn lim_get_channel_from_beacon + \brief To extract channel number from beacon + + \param pMac + \param pBeacon - Pointer to beacon or probe rsp + \return channel number + -----------------------------------------------------------*/ +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, tpSchBeaconStruct pBeacon) +{ + uint8_t channelNum = 0; + + if (pBeacon->dsParamsPresent) + channelNum = pBeacon->channelNumber; + else if (pBeacon->HTInfo.present) + channelNum = pBeacon->HTInfo.primaryChannel; + else + channelNum = pBeacon->channelNumber; + + return channelNum; +} + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *pTsInfo, uint32_t action) +{ + uint8_t userPrio = (uint8_t) pTsInfo->traffic.userPrio; + uint16_t direction = pTsInfo->traffic.direction; + uint8_t ac = upToAc(userPrio); + + PELOG1(lim_log + (pMac, LOG1, FL("Set UAPSD mask for AC %d, dir %d, action=%d") + , ac, direction, action); + ) + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + + if (action == CLEAR_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + } + } else if (action == SET_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + } + } + + lim_log(pMac, LOG1, + FL("New psessionEntry->gUapsdPerAcTriggerEnableMask = 0x%x "), + psessionEntry->gUapsdPerAcTriggerEnableMask); + lim_log(pMac, LOG1, + FL("New psessionEntry->gUapsdPerAcDeliveryEnableMask = 0x%x "), + psessionEntry->gUapsdPerAcDeliveryEnableMask); + + return; +} + +/** + * lim_handle_heart_beat_timeout_for_session() - Handle heart beat time out + * @mac_ctx: pointer to Global Mac Structure + * @psession_entry: pointer to tpPESession + * + * Function handles heart beat time out for session + * + * Return: none + */ +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal mac_ctx, + tpPESession psession_entry) +{ + if (psession_entry->valid == true) { + if (psession_entry->bssType == eSIR_IBSS_MODE) + lim_ibss_heart_beat_handle(mac_ctx, psession_entry); + + if ((psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry))) + lim_handle_heart_beat_failure(mac_ctx, psession_entry); + } + /* + * In the function lim_handle_heart_beat_failure things can change + * so check for the session entry valid and the other things + * again + */ + if ((psession_entry->valid == true) && + (psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry)) && + (psession_entry->LimHBFailureStatus == true)) { + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + /* + * Activate Probe After HeartBeat Timer incase HB + * Failure detected + */ + PELOGW(lim_log(mac_ctx, LOGW, + FL("Sending Probe for Session: %d"), + psession_entry->bssIdx);) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PROBE_AFTER_HB_TIMER); + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, 0, + eLIM_PROBE_AFTER_HB_TIMER)); + if (tx_timer_activate(&lim_timer->gLimProbeAfterHBTimer) + != TX_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to re-activate Probe-after-hb timer")); + } +} + +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((pMac->lim.gpSession[i].bssType == + eSIR_INFRASTRUCTURE_MODE) + && (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_ROLE)) { + return pMac->lim.gpSession[i]. + currentOperChannel; + } + } + } + return 0; +} + +void lim_process_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ) +{ + tpPESession psessionEntry; + tpAddStaParams pAddStaParams; + + pAddStaParams = (tpAddStaParams) limMsgQ->bodyptr; + + psessionEntry = pe_find_session_by_session_id(pMac, + pAddStaParams->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + cdf_mem_free(pAddStaParams); + return; + } + psessionEntry->csaOffloadEnable = pAddStaParams->csaOffloadEnable; + if (LIM_IS_IBSS_ROLE(psessionEntry)) + (void)lim_ibss_add_sta_rsp(pMac, limMsgQ->bodyptr, psessionEntry); +#ifdef FEATURE_WLAN_TDLS + else if (pMac->lim.gLimAddStaTdls) { + lim_process_tdls_add_sta_rsp(pMac, limMsgQ->bodyptr, psessionEntry); + pMac->lim.gLimAddStaTdls = false; + } +#endif + else + lim_process_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); + +} + +/** + * lim_update_beacon() - This function updates beacon + * @mac_ctx: pointer to Global Mac Structure + * + * This Function is invoked to update the beacon + * + * Return: none + */ +void lim_update_beacon(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + if (((mac_ctx->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE) + || (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_ROLE)) + && (eLIM_SME_NORMAL_STATE == + mac_ctx->lim.gpSession[i].limSmeState)) { + + sch_set_fixed_beacon_fields(mac_ctx, + &mac_ctx->lim.gpSession[i]); + + if (false == mac_ctx->sap.SapDfsInfo. + is_dfs_cac_timer_running) + lim_send_beacon_ind(mac_ctx, + &mac_ctx->lim.gpSession[i]); + } else if (((mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_AP_ROLE) || + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_STA_ROLE)) && + (mac_ctx->lim.gpSession[i].statypeForBss == + STA_ENTRY_SELF)){ + sch_set_fixed_beacon_fields(mac_ctx, + &mac_ctx->lim.gpSession[i]); + } + } +} + +/** + * lim_handle_heart_beat_failure_timeout - handle heart beat failure + * @mac_ctx: pointer to Global Mac Structure + * + * Function handle heart beat failure timeout + * + * Return: none + */ +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + tpPESession psession_entry; + /* + * Probe response is not received after HB failure. + * This is handled by LMM sub module. + */ + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + psession_entry = &mac_ctx->lim.gpSession[i]; + if (psession_entry->LimHBFailureStatus != true) + continue; + lim_log(mac_ctx, LOGE, FL("SME %d, MLME %d, HB-Count %d"), + psession_entry->limSmeState, + psession_entry->limMlmState, + psession_entry->LimRxedBeaconCntDuringHB); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + psession_entry, 0, 0); +#endif + if ((psession_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + ((!LIM_IS_CONNECTION_ACTIVE(psession_entry)) || + /* + * Disconnect even if we have not received a single + * beacon after connection. + */ + (psession_entry->currentBssBeaconCnt == 0))) { + lim_log(mac_ctx, LOGE, FL("for session:%d "), + psession_entry->peSessionId); + /* + * AP did not respond to Probe Request. + * Tear down link with it. + */ + lim_tear_down_link_with_ap(mac_ctx, + psession_entry->peSessionId, + eSIR_BEACON_MISSED); + mac_ctx->lim.gLimProbeFailureAfterHBfailedCnt++; + } else { + lim_log(mac_ctx, LOGE, + FL("Unexpected wt-probe-timeout in state ")); + lim_print_mlm_state(mac_ctx, LOGE, + psession_entry->limMlmState); + } + } + /* + * Deactivate Timer ProbeAfterHB Timer -> As its a oneshot timer, + * need not deactivate the timer + * tx_timer_deactivate(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + */ +} + +/* + * This function assumes there will not be more than one IBSS session active at any time. + */ +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_ROLE)) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid) && + ((pMac->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE) || + (pMac->lim.gpSession[i].limSystemRole == + eLIM_BT_AMP_AP_ROLE))) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +/**--------------------------------------------------------- + \fn lim_handle_defer_msg_error + \brief handles error scenario, when the msg can not be deferred. + \param pMac + \param pLimMsg LIM msg, which could not be deferred. + \return void + -----------------------------------------------------------*/ + +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, tpSirMsgQ pLimMsg) +{ + if (SIR_BB_XPORT_MGMT_MSG == pLimMsg->type) { + cds_pkt_return_packet((cds_pkt_t *) pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } else if (pLimMsg->bodyptr != NULL) { + cdf_mem_free(pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } + +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/**--------------------------------------------------------- + \fn lim_diag_event_report + \brief This function reports Diag event + \param pMac + \param eventType + \param bssid + \param status + \param reasonCode + \return void + -----------------------------------------------------------*/ +void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode) +{ + tSirMacAddr nullBssid = { 0, 0, 0, 0, 0, 0 }; + WLAN_HOST_DIAG_EVENT_DEF(peEvent, host_event_wlan_pe_payload_type); + + cdf_mem_set(&peEvent, sizeof(host_event_wlan_pe_payload_type), 0); + + if (NULL == pSessionEntry) { + cdf_mem_copy(peEvent.bssid, nullBssid, sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pMac->lim.gLimSmeState; + peEvent.mlm_state = (uint16_t) pMac->lim.gLimMlmState; + + } else { + cdf_mem_copy(peEvent.bssid, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pSessionEntry->limSmeState; + peEvent.mlm_state = (uint16_t) pSessionEntry->limMlmState; + } + peEvent.event_type = eventType; + peEvent.status = status; + peEvent.reason_code = reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&peEvent, EVENT_WLAN_PE); + return; +} + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +uint8_t *lim_get_ie_ptr_new(tpAniSirGlobal pMac, uint8_t *pIes, int length, + uint8_t eid, eSizeOfLenField size_of_len_field) +{ + int left = length; + uint8_t *ptr = pIes; + uint8_t elem_id; + uint16_t elem_len; + + while (left >= (size_of_len_field + 1)) { + elem_id = ptr[0]; + if (size_of_len_field == TWO_BYTE) { + elem_len = ((uint16_t) ptr[1]) | (ptr[2] << 8); + } else { + elem_len = ptr[1]; + } + + left -= (size_of_len_field + 1); + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + eid, elem_len, left); + return NULL; + } + if (elem_id == eid) { + return ptr; + } + + left -= elem_len; + ptr += (elem_len + (size_of_len_field + 1)); + } + return NULL; +} + +/* Returns length of P2P stream and Pointer ie passed to this function is filled with noa stream */ + +uint8_t lim_build_p2p_ie(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len) +{ + int length = 0; + uint8_t *ptr = ie; + + ptr[length++] = SIR_MAC_EID_VENDOR; + ptr[length++] = ie_len + SIR_MAC_P2P_OUI_SIZE; + cdf_mem_copy(&ptr[length], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + cdf_mem_copy(&ptr[length + SIR_MAC_P2P_OUI_SIZE], data, ie_len); + return ie_len + SIR_P2P_IE_HEADER_LEN; +} + +/* Returns length of NoA stream and Pointer pNoaStream passed to this function is filled with noa stream */ + +uint8_t lim_get_noa_attr_stream_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen) +{ + uint8_t overFlowP2pStream[SIR_MAX_NOA_ATTR_LEN]; + + if ((noaLen <= (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) && + (noaLen >= overFlowLen) && (overFlowLen <= SIR_MAX_NOA_ATTR_LEN)) { + cdf_mem_copy(overFlowP2pStream, + noaStream + noaLen - overFlowLen, overFlowLen); + noaStream[noaLen - overFlowLen] = SIR_MAC_EID_VENDOR; + noaStream[noaLen - overFlowLen + 1] = + overFlowLen + SIR_MAC_P2P_OUI_SIZE; + cdf_mem_copy(noaStream + noaLen - overFlowLen + 2, + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + cdf_mem_copy(noaStream + noaLen + 2 + SIR_MAC_P2P_OUI_SIZE - + overFlowLen, overFlowP2pStream, overFlowLen); + } + + return noaLen + SIR_P2P_IE_HEADER_LEN; + +} + +/* Returns length of NoA stream and Pointer pNoaStream passed to this function is filled with noa stream */ +uint8_t lim_get_noa_attr_stream(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry) +{ + uint8_t len = 0; + + uint8_t *pBody = pNoaStream; + + if ((psessionEntry != NULL) && (psessionEntry->valid) && + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) { + if ((!(psessionEntry->p2pGoPsUpdate.uNoa1Duration)) + && (!(psessionEntry->p2pGoPsUpdate.uNoa2Duration)) + && (!psessionEntry->p2pGoPsUpdate.oppPsFlag) + ) + return 0; /* No NoA Descriptor then return 0 */ + + pBody[0] = SIR_P2P_NOA_ATTR; + + pBody[3] = psessionEntry->p2pGoPsUpdate.index; + pBody[4] = + psessionEntry->p2pGoPsUpdate.ctWin | (psessionEntry-> + p2pGoPsUpdate. + oppPsFlag << 7); + len = 5; + pBody += len; + + if (psessionEntry->p2pGoPsUpdate.uNoa1Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa1IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + if (psessionEntry->p2pGoPsUpdate.uNoa2Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa2IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + pBody = pNoaStream + 1; + *((uint16_t *) (pBody)) = sir_swap_u16if_needed(len - 3); /*one byte for Attr and 2 bytes for length */ + + return len; + + } + return 0; + +} + +void pe_set_resume_channel(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState phyCbState) +{ + + pMac->lim.gResumeChannel = channel; + pMac->lim.gResumePhyCbState = phyCbState; +} + +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((eLIM_AP_ROLE == + pMac->lim.gpSession[i].limSystemRole) + && (CDF_P2P_GO_MODE == + pMac->lim.gpSession[i].pePersona) + ) { + return true; + } + } + } + return false; +} + +bool lim_isconnected_on_dfs_channel(uint8_t currentChannel) +{ + if (CHANNEL_STATE_DFS == + cds_get_channel_state(currentChannel)) { + return true; + } else { + return false; + } +} + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + tPmfSaQueryTimerId timerId; + tpPESession psessionEntry; + tpDphHashNode pSta; + uint32_t maxRetries; + + lim_log(pMac, LOG1, FL("SA Query timer fires")); + timerId.value = param; + + /* Check that SA Query is in progress */ + psessionEntry = pe_find_session_by_session_id(pMac, + timerId.fields.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given session ID %d"), + timerId.fields.sessionId); + return; + } + pSta = dph_get_hash_entry(pMac, timerId.fields.peerIdx, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL("Entry does not exist for given peer index %d"), + timerId.fields.peerIdx); + return; + } + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Increment the retry count, check if reached maximum */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &maxRetries) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("Could not retrieve PMF SA Query maximum retries value")); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + return; + } + pSta->pmfSaQueryRetryCount++; + if (pSta->pmfSaQueryRetryCount >= maxRetries) { + lim_log(pMac, LOGE, FL("SA Query timed out,Deleting STA")); + lim_print_mac_addr(pMac, pSta->staAddr, LOGE); + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + pSta->staAddr, psessionEntry, false); + lim_trigger_sta_deletion(pMac, pSta, psessionEntry); + pSta->pmfSaQueryState = DPH_SA_QUERY_TIMED_OUT; + return; + } + /* Retry SA Query */ + lim_send_sa_query_request_frame(pMac, + (uint8_t *) &(pSta-> + pmfSaQueryCurrentTransId), + pSta->staAddr, psessionEntry); + pSta->pmfSaQueryCurrentTransId++; + lim_log(pMac, LOGE, FL("Starting SA Query retry %d"), + pSta->pmfSaQueryRetryCount); + if (tx_timer_activate(&pSta->pmfSaQueryTimer) != TX_SUCCESS) { + lim_log(pMac, LOGE, FL("PMF SA Query timer activation failed!")); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + } +} +#endif + +#ifdef WLAN_FEATURE_11AC +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t chanWidth, uint8_t staId, + uint8_t *peerMac) +{ + tUpdateVHTOpMode tempParam; + + tempParam.opMode = chanWidth; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + cdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_mode_update(pMac, &tempParam, psessionEntry); + + return true; +} + +bool lim_set_nss_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac) +{ + tUpdateRxNss tempParam; + + tempParam.rxNss = rxNss; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + cdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_rx_nss_update(pMac, &tempParam, psessionEntry); + + return true; +} + +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId) +{ + tUpdateMembership tempParamMembership; + tUpdateUserPos tempParamUserPosition; + + tempParamMembership.membership = membership; + tempParamMembership.staId = staId; + tempParamMembership.smesessionId = psessionEntry->smeSessionId; + cdf_mem_copy(tempParamMembership.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_membership(pMac, &tempParamMembership, psessionEntry); + + tempParamUserPosition.userPos = userPosition; + tempParamUserPosition.staId = staId; + tempParamUserPosition.smesessionId = psessionEntry->smeSessionId; + cdf_mem_copy(tempParamUserPosition.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_user_pos(pMac, &tempParamUserPosition, psessionEntry); + + return true; +} +#endif + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint32_t phyMode, uint8_t *pShortSlotEnabled) +{ + uint8_t val = 0; + + /* only 2.4G band should have short slot enable, rest it should be default */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + /* short slot is default in all other modes */ + if ((psessionEntry->pePersona == CDF_SAP_MODE) || + (psessionEntry->pePersona == CDF_IBSS_MODE) || + (psessionEntry->pePersona == CDF_P2P_GO_MODE)) { + val = true; + } + /* Program Polaris based on AP capability */ + if (psessionEntry->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* Joining BSS. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + limCurrentBssCaps); + } else if (psessionEntry->limMlmState == + eLIM_MLM_WT_REASSOC_RSP_STATE) { + /* Reassociating with AP. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + limReassocBssCaps); + } + } else { + /* + * 11B does not short slot and short slot is default + * for 11A mode. Hence, not need to set this bit + */ + val = false; + } + + lim_log(pMac, LOG1, FL("phyMode = %u shortslotsupported = %u"), phyMode, + val); + *pShortSlotEnabled = val; +} + +#ifdef WLAN_FEATURE_11W +/** + * + * \brief This function is called by various LIM modules to correctly set + * the Protected bit in the Frame Control Field of the 802.11 frame MAC header + * + * + * \param pMac Pointer to Global MAC structure + * + * \param psessionEntry Pointer to session corresponding to the connection + * + * \param peer Peer address of the STA to which the frame is to be sent + * + * \param pMacHdr Pointer to the frame MAC header + * + * \return nothing + * + * + */ +void +lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr) +{ + uint16_t aid; + tpDphHashNode pStaDs; + + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_BT_AMP_AP_ROLE(psessionEntry)) { + + pStaDs = dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* rmfenabled will be set at the time of addbss. + * but sometimes EAP auth fails and keys are not + * installed then if we send any management frame + * like deauth/disassoc with this bit set then + * firmware crashes. so check for keys are + * installed or not also before setting the bit + */ + if (pStaDs->rmfEnabled && pStaDs->is_key_installed) + pMacHdr->fc.wep = 1; + } + } else if (psessionEntry->limRmfEnabled && + psessionEntry->is_key_installed) { + pMacHdr->fc.wep = 1; + } +} /*** end lim_set_protected_bit() ***/ +#endif + +void lim_set_ht_caps(tpAniSirGlobal p_mac, tpPESession p_session_entry, + uint8_t *p_ie_start, uint32_t num_bytes) +{ + uint8_t *p_ie = NULL; + tDot11fIEHTCaps dot11_ht_cap = {0,}; + + populate_dot11f_ht_caps(p_mac, p_session_entry, &dot11_ht_cap); + p_ie = lim_get_ie_ptr_new(p_mac, p_ie_start, num_bytes, + DOT11F_EID_HTCAPS, ONE_BYTE); + lim_log(p_mac, LOG2, FL("p_ie %p dot11_ht_cap.supportedMCSSet[0]=0x%x"), + p_ie, dot11_ht_cap.supportedMCSSet[0]); + if (p_ie) { + /* convert from unpacked to packed structure */ + tHtCaps *p_ht_cap = (tHtCaps *) &p_ie[2]; + + p_ht_cap->advCodingCap = dot11_ht_cap.advCodingCap; + p_ht_cap->supportedChannelWidthSet = + dot11_ht_cap.supportedChannelWidthSet; + p_ht_cap->mimoPowerSave = dot11_ht_cap.mimoPowerSave; + p_ht_cap->greenField = dot11_ht_cap.greenField; + p_ht_cap->shortGI20MHz = dot11_ht_cap.shortGI20MHz; + p_ht_cap->shortGI40MHz = dot11_ht_cap.shortGI40MHz; + p_ht_cap->txSTBC = dot11_ht_cap.txSTBC; + p_ht_cap->rxSTBC = dot11_ht_cap.rxSTBC; + p_ht_cap->delayedBA = dot11_ht_cap.delayedBA; + p_ht_cap->maximalAMSDUsize = dot11_ht_cap.maximalAMSDUsize; + p_ht_cap->dsssCckMode40MHz = dot11_ht_cap.dsssCckMode40MHz; + p_ht_cap->psmp = dot11_ht_cap.psmp; + p_ht_cap->stbcControlFrame = dot11_ht_cap.stbcControlFrame; + p_ht_cap->lsigTXOPProtection = dot11_ht_cap.lsigTXOPProtection; + p_ht_cap->maxRxAMPDUFactor = dot11_ht_cap.maxRxAMPDUFactor; + p_ht_cap->mpduDensity = dot11_ht_cap.mpduDensity; + cdf_mem_copy((void *)p_ht_cap->supportedMCSSet, + (void *)(dot11_ht_cap.supportedMCSSet), + sizeof(p_ht_cap->supportedMCSSet)); + p_ht_cap->pco = dot11_ht_cap.pco; + p_ht_cap->transitionTime = dot11_ht_cap.transitionTime; + p_ht_cap->mcsFeedback = dot11_ht_cap.mcsFeedback; + p_ht_cap->txBF = dot11_ht_cap.txBF; + p_ht_cap->rxStaggeredSounding = + dot11_ht_cap.rxStaggeredSounding; + p_ht_cap->txStaggeredSounding = + dot11_ht_cap.txStaggeredSounding; + p_ht_cap->rxZLF = dot11_ht_cap.rxZLF; + p_ht_cap->txZLF = dot11_ht_cap.txZLF; + p_ht_cap->implicitTxBF = dot11_ht_cap.implicitTxBF; + p_ht_cap->calibration = dot11_ht_cap.calibration; + p_ht_cap->explicitCSITxBF = dot11_ht_cap.explicitCSITxBF; + p_ht_cap->explicitUncompressedSteeringMatrix = + dot11_ht_cap.explicitUncompressedSteeringMatrix; + p_ht_cap->explicitBFCSIFeedback = + dot11_ht_cap.explicitBFCSIFeedback; + p_ht_cap->explicitUncompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitUncompressedSteeringMatrixFeedback; + p_ht_cap->explicitCompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitCompressedSteeringMatrixFeedback; + p_ht_cap->csiNumBFAntennae = dot11_ht_cap.csiNumBFAntennae; + p_ht_cap->uncompressedSteeringMatrixBFAntennae = + dot11_ht_cap.uncompressedSteeringMatrixBFAntennae; + p_ht_cap->compressedSteeringMatrixBFAntennae = + dot11_ht_cap.compressedSteeringMatrixBFAntennae; + p_ht_cap->antennaSelection = dot11_ht_cap.antennaSelection; + p_ht_cap->explicitCSIFeedbackTx = + dot11_ht_cap.explicitCSIFeedbackTx; + p_ht_cap->antennaIndicesFeedbackTx = + dot11_ht_cap.antennaIndicesFeedbackTx; + p_ht_cap->explicitCSIFeedback = + dot11_ht_cap.explicitCSIFeedback; + p_ht_cap->antennaIndicesFeedback = + dot11_ht_cap.antennaIndicesFeedback; + p_ht_cap->rxAS = dot11_ht_cap.rxAS; + p_ht_cap->txSoundingPPDUs = dot11_ht_cap.txSoundingPPDUs; + } +} + +#ifdef WLAN_FEATURE_11AC +void lim_set_vht_caps(tpAniSirGlobal p_mac, tpPESession p_session_entry, + uint8_t *p_ie_start, uint32_t num_bytes) +{ + uint8_t *p_ie = NULL; + tDot11fIEVHTCaps dot11_vht_cap; + + populate_dot11f_vht_caps(p_mac, p_session_entry, &dot11_vht_cap); + p_ie = lim_get_ie_ptr_new(p_mac, p_ie_start, num_bytes, + DOT11F_EID_VHTCAPS, ONE_BYTE); + + if (p_ie) { + tSirMacVHTCapabilityInfo *vht_cap = + (tSirMacVHTCapabilityInfo *) &p_ie[2]; + tSirVhtMcsInfo *vht_mcs = (tSirVhtMcsInfo *) &p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + + union { + uint16_t u_value; + tSirMacVHTRxSupDataRateInfo vht_rx_supp_rate; + tSirMacVHTTxSupDataRateInfo vht_tx_supp_rate; + } u_vht_data_rate_info; + + vht_cap->maxMPDULen = dot11_vht_cap.maxMPDULen; + vht_cap->supportedChannelWidthSet = + dot11_vht_cap.supportedChannelWidthSet; + vht_cap->ldpcCodingCap = dot11_vht_cap.ldpcCodingCap; + vht_cap->shortGI80MHz = dot11_vht_cap.shortGI80MHz; + vht_cap->shortGI160and80plus80MHz = + dot11_vht_cap.shortGI160and80plus80MHz; + vht_cap->txSTBC = dot11_vht_cap.txSTBC; + vht_cap->rxSTBC = dot11_vht_cap.rxSTBC; + vht_cap->suBeamFormerCap = dot11_vht_cap.suBeamFormerCap; + vht_cap->suBeamformeeCap = dot11_vht_cap.suBeamformeeCap; + vht_cap->csnofBeamformerAntSup = + dot11_vht_cap.csnofBeamformerAntSup; + vht_cap->numSoundingDim = dot11_vht_cap.numSoundingDim; + vht_cap->muBeamformerCap = dot11_vht_cap.muBeamformerCap; + vht_cap->muBeamformeeCap = dot11_vht_cap.muBeamformeeCap; + vht_cap->vhtTXOPPS = dot11_vht_cap.vhtTXOPPS; + vht_cap->htcVHTCap = dot11_vht_cap.htcVHTCap; + vht_cap->maxAMPDULenExp = dot11_vht_cap.maxAMPDULenExp; + vht_cap->vhtLinkAdaptCap = dot11_vht_cap.vhtLinkAdaptCap; + vht_cap->rxAntPattern = dot11_vht_cap.rxAntPattern; + vht_cap->txAntPattern = dot11_vht_cap.txAntPattern; + vht_cap->reserved1 = dot11_vht_cap.reserved1; + + /* Populate VHT MCS Information */ + vht_mcs->rxMcsMap = dot11_vht_cap.rxMCSMap; + u_vht_data_rate_info.vht_rx_supp_rate.rxSupDataRate = + dot11_vht_cap.rxHighSupDataRate; + u_vht_data_rate_info.vht_rx_supp_rate.reserved = + dot11_vht_cap.reserved2; + vht_mcs->rxHighest = u_vht_data_rate_info.u_value; + + vht_mcs->txMcsMap = dot11_vht_cap.txMCSMap; + u_vht_data_rate_info.vht_tx_supp_rate.txSupDataRate = + dot11_vht_cap.txSupDataRate; + u_vht_data_rate_info.vht_tx_supp_rate.reserved = + dot11_vht_cap.reserved3; + vht_mcs->txHighest = u_vht_data_rate_info.u_value; + } +} +#endif /* WLAN_FEATURE_11AC */ + +/** + * lim_validate_received_frame_a1_addr() - To validate received frame's A1 addr + * @mac_ctx: pointer to mac context + * @a1: received frame's a1 address which is nothing but our self address + * @session: PE session pointer + * + * This routine will validate, A1 addres of the received frame + * + * Return: true or false + */ +bool lim_validate_received_frame_a1_addr(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session) +{ + if (mac_ctx == NULL || session == NULL) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + "mac or session context is null"); + /* let main routine handle it */ + return true; + } + if (lim_is_group_addr(a1) || lim_is_addr_bc(a1)) { + /* just for fail safe, don't handle MC/BC a1 in this routine */ + return true; + } + if (!cdf_mem_compare(a1, session->selfMacAddr, 6)) { + lim_log(mac_ctx, LOGE, + FL("Invalid A1 address in received frame")); + return false; + } + return true; +} + +/** + * lim_check_and_reset_protection_params() - reset protection related parameters + * + * @mac_ctx: pointer to global mac structure + * + * resets protection related global parameters if the pe active session count + * is zero. + * + * Return: None + */ +void lim_check_and_reset_protection_params(tpAniSirGlobal mac_ctx) +{ + if (!pe_get_active_session_count(mac_ctx)) { + cdf_mem_zero(&mac_ctx->lim.gLimOverlap11gParams, + sizeof(mac_ctx->lim.gLimOverlap11gParams)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlap11aParams, + sizeof(mac_ctx->lim.gLimOverlap11aParams)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlapHt20Params, + sizeof(mac_ctx->lim.gLimOverlapHt20Params)); + cdf_mem_zero(&mac_ctx->lim.gLimOverlapNonGfParams, + sizeof(mac_ctx->lim.gLimOverlapNonGfParams)); + + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } +} + +/** + * lim_set_stads_rtt_cap() - update station node RTT capability + * @sta_ds: Station hash node + * @ext_cap: Pointer to extended capability + * @mac_ctx: global MAC context + * + * This funciton update hash node's RTT capability based on received + * Extended capability IE. + * + * Return: None + */ +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + tpAniSirGlobal mac_ctx) +{ + sta_ds->timingMeasCap = 0; + sta_ds->timingMeasCap |= (ext_cap->timing_meas) ? + RTT_TIMING_MEAS_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_initiator) ? + RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_responder) ? + RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY : + RTT_INVALID; + + lim_log(mac_ctx, LOG1, + FL("ExtCap present, timingMeas: %d Initiator: %d Responder: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); +} + +/** + * lim_send_ext_cap_ie() - send ext cap IE to FW + * @mac_ctx: global MAC context + * @session_entry: PE session + * @extra_extcap: extracted ext cap + * @merge: merge extra ext cap + * + * This function is invoked after VDEV is created to update firmware + * about the extended capabilities that the corresponding VDEV is capable + * of. Since STA/SAP can have different Extended capabilities set, this function + * is called per vdev creation. + * + * Return: CDF_STATUS + */ +CDF_STATUS lim_send_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tDot11fIEExtCap *extra_extcap, bool merge) +{ + tDot11fIEExtCap ext_cap_data = {0}; + uint32_t dot11mode, num_bytes; + bool vht_enabled = false; + struct vdev_ie_info *vdev_ie; + cds_msg_t msg = {0}; + tSirRetStatus status; + uint8_t *temp, i; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &dot11mode); + if (IS_DOT11_MODE_VHT(dot11mode)) + vht_enabled = true; + + status = populate_dot11f_ext_cap(mac_ctx, vht_enabled, &ext_cap_data, + NULL); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Failed to populate ext cap IE")); + return CDF_STATUS_E_FAILURE; + } + + num_bytes = ext_cap_data.num_bytes; + + if (merge && NULL != extra_extcap && extra_extcap->num_bytes > 0) { + if (extra_extcap->num_bytes > ext_cap_data.num_bytes) + num_bytes = extra_extcap->num_bytes; + lim_merge_extcap_struct(&ext_cap_data, extra_extcap); + } + + /* Allocate memory for the WMI request, and copy the parameter */ + vdev_ie = cdf_mem_malloc(sizeof(*vdev_ie) + num_bytes); + if (!vdev_ie) { + lim_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return CDF_STATUS_E_NOMEM; + } + + vdev_ie->vdev_id = session_id; + vdev_ie->ie_id = DOT11F_EID_EXTCAP; + vdev_ie->length = num_bytes; + + lim_log(mac_ctx, LOG1, FL("vdev %d ieid %d len %d"), session_id, + DOT11F_EID_EXTCAP, num_bytes); + temp = ext_cap_data.bytes; + for (i = 0; i < num_bytes; i++, temp++) + lim_log(mac_ctx, LOG1, FL("%d byte is %02x"), i+1, *temp); + + vdev_ie->data = (uint8_t *)vdev_ie + sizeof(*vdev_ie); + cdf_mem_copy(vdev_ie->data, ext_cap_data.bytes, num_bytes); + + msg.type = WMA_SET_IE_INFO; + msg.bodyptr = vdev_ie; + msg.reserved = 0; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + lim_log(mac_ctx, LOGE, + FL("Not able to post WMA_SET_IE_INFO to WDA")); + cdf_mem_free(vdev_ie); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * lim_strip_extcap_ie() - strip extended capability IE from IE buffer + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @extracted_ie: if not NULL, copy the stripped IE to this buffer + * + * This utility function is used to strip of the extended capability IE present + * in additional IE buffer. + * + * Return: tSirRetStatus + */ +tSirRetStatus lim_strip_extcap_ie(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, uint8_t *extracted_ie) +{ + uint8_t *tempbuf = NULL; + uint16_t templen = 0; + int left = *addn_ielen; + uint8_t *ptr = addn_ie; + uint8_t elem_id, elem_len; + + if (NULL == addn_ie) { + lim_log(mac_ctx, LOG1, FL("NULL addn_ie pointer")); + return eSIR_IGNORE_IE; + } + + tempbuf = cdf_mem_malloc(left); + if (NULL == tempbuf) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + lim_log(mac_ctx, LOGE, + FL("Invalid IEs eid = %d elem_len=%d left=%d"), + elem_id, elem_len, left); + cdf_mem_free(tempbuf); + return eSIR_FAILURE; + } + if (!(DOT11F_EID_EXTCAP == elem_id)) { + cdf_mem_copy(tempbuf + templen, &ptr[0], elem_len + 2); + templen += (elem_len + 2); + } else { + if (NULL != extracted_ie) { + cdf_mem_set(extracted_ie, + DOT11F_IE_EXTCAP_MAX_LEN + 2, 0); + if (elem_len <= DOT11F_IE_EXTCAP_MAX_LEN) + cdf_mem_copy(extracted_ie, &ptr[0], + elem_len + 2); + } + } + left -= elem_len; + ptr += (elem_len + 2); + } + cdf_mem_copy(addn_ie, tempbuf, templen); + + *addn_ielen = templen; + cdf_mem_free(tempbuf); + + return eSIR_SUCCESS; +} + +/** + * lim_update_extcap_struct() - poputlate the dot11f structure + * @mac_ctx: global MAC context + * @buf: extracted IE buffer + * @dst: extended capability IE structure to be updated + * + * This function is used to update the extended capability structure + * with @buf. + * + * Return: None + */ +void lim_update_extcap_struct(tpAniSirGlobal mac_ctx, + uint8_t *buf, tDot11fIEExtCap *dst) +{ + uint8_t out[DOT11F_IE_EXTCAP_MAX_LEN]; + + if (NULL == buf) { + lim_log(mac_ctx, LOGE, FL("Invalid Buffer Address")); + return; + } + + if (NULL == dst) { + lim_log(mac_ctx, LOGE, FL("NULL dst pointer")); + return; + } + + if (DOT11F_EID_EXTCAP != buf[0] || buf[1] > DOT11F_IE_EXTCAP_MAX_LEN) { + lim_log(mac_ctx, LOG1, FL("Invalid IEs eid = %d elem_len=%d "), + buf[0], buf[1]); + return; + } + + cdf_mem_set((uint8_t *)&out[0], DOT11F_IE_EXTCAP_MAX_LEN, 0); + cdf_mem_copy(&out[0], &buf[2], DOT11F_IE_EXTCAP_MAX_LEN); + + if (DOT11F_PARSE_SUCCESS != dot11f_unpack_ie_ext_cap(mac_ctx, &out[0], + DOT11F_IE_EXTCAP_MAX_LEN, dst)) + lim_log(mac_ctx, LOGE, FL("dot11f_unpack Parse Error ")); +} + +/** + * lim_strip_extcap_update_struct - strip extended capability IE and populate + * the dot11f structure + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @dst: extended capability IE structure to be updated + * + * This function is used to strip extended capability IE from IE buffer and + * update the passed structure. + * + * Return: tSirRetStatus + */ +tSirRetStatus lim_strip_extcap_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst) +{ + uint8_t extracted_buff[DOT11F_IE_EXTCAP_MAX_LEN + 2]; + tSirRetStatus status; + + cdf_mem_set((uint8_t *)&extracted_buff[0], DOT11F_IE_EXTCAP_MAX_LEN + 2, + 0); + status = lim_strip_extcap_ie(mac_ctx, addn_ie, addn_ielen, + extracted_buff); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOG1, + FL("Failed to strip extcap IE status = (%d)."), status); + return status; + } + + /* update the extracted ExtCap to struct*/ + lim_update_extcap_struct(mac_ctx, extracted_buff, dst); + return status; +} + +/** + * lim_merge_extcap_struct() - merge extended capabilities info + * @dst: destination extended capabilities + * @src: source extended capabilities + * + * This function is used to take @src info and merge it with @dst + * extended capabilities info. + * + * Return: None + */ +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, + tDot11fIEExtCap *src) +{ + uint8_t *tempdst = (uint8_t *)dst->bytes; + uint8_t *tempsrc = (uint8_t *)src->bytes; + uint8_t structlen = member_size(tDot11fIEExtCap, bytes); + + while (tempdst && tempsrc && structlen--) { + *tempdst |= *tempsrc; + tempdst++; + tempsrc++; + } +} + diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h new file mode 100644 index 0000000000..76b000cdd3 --- /dev/null +++ b/core/mac/src/pe/lim/lim_utils.h @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_utils.h contains the utility definitions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_UTILS_H +#define __LIM_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "lim_types.h" +#include "lim_scan_result_utils.h" +#include "lim_timer_utils.h" +#include "lim_trace.h" +typedef enum { + ONE_BYTE = 1, + TWO_BYTE = 2 +} eSizeOfLenField; + +#define MIN_TX_PWR_CAP 8 +#define MAX_TX_PWR_CAP 22 + +#define LIM_STA_ID_MASK 0x00FF +#define LIM_AID_MASK 0xC000 +#define LIM_SPECTRUM_MANAGEMENT_BIT_MASK 0x0100 +#define LIM_RRM_BIT_MASK 0x1000 +#define LIM_SHORT_PREAMBLE_BIT_MASK 0x0020 +#define LIM_IMMEDIATE_BLOCK_ACK_MASK 0x8000 +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +#define LIM_MAX_REASSOC_RETRY_LIMIT 2 +#endif + +/* classifier ID is coded as 0-3: tsid, 4-5:direction */ +#define LIM_MAKE_CLSID(tsid, dir) (((tsid) & 0x0F) | (((dir) & 0x03) << 4)) + +#define VHT_MCS_3x3_MASK 0x30 +#define VHT_MCS_2x2_MASK 0x0C + +#ifdef WLAN_FEATURE_11W +typedef union uPmfSaQueryTimerId { + struct { + uint8_t sessionId; + uint16_t peerIdx; + } fields; + uint32_t value; +} tPmfSaQueryTimerId, *tpPmfSaQueryTimerId; +#endif + +/* LIM utility functions */ +void limGetBssidFromPkt(tpAniSirGlobal, uint8_t *, uint8_t *, uint32_t *); +char *lim_dot11_reason_str(uint16_t reasonCode); +char *lim_mlm_state_str(tLimMlmStates state); +char *lim_sme_state_str(tLimSmeStates state); +char *lim_msg_str(uint32_t msgType); +char *lim_result_code_str(tSirResultCodes resultCode); +char *lim_dot11_mode_str(tpAniSirGlobal pMac, uint8_t dot11Mode); +void lim_print_mlm_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimMlmStates state); +void lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimSmeStates state); +void lim_print_msg_name(tpAniSirGlobal pMac, uint16_t logLevel, uint32_t msgType); + +#if defined FEATURE_WLAN_ESE || defined WLAN_FEATURE_VOWIFI +extern tSirRetStatus lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, + tPowerdBm txPower, + tpPESession pSessionEntry); +extern uint8_t lim_get_max_tx_power(tPowerdBm regMax, tPowerdBm apTxPower, + uint8_t iniTxPower); +#endif +uint8_t lim_is_addr_bc(tSirMacAddr); +uint8_t lim_is_group_addr(tSirMacAddr); + +/* check for type of scan allowed */ +uint8_t lim_active_scan_allowed(tpAniSirGlobal, uint8_t); + +/* AID pool management functions */ +void lim_init_peer_idxpool(tpAniSirGlobal, tpPESession); +uint16_t lim_assign_peer_idx(tpAniSirGlobal, tpPESession); + +void lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, + tpPESession psessionEntry); +void lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams); +void lim_update_short_preamble(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_update_short_slot_time(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +/* + * The below 'product' check tobe removed if 'Association' is + * allowed in IBSS. + */ +void lim_release_peer_idx(tpAniSirGlobal, uint16_t, tpPESession); + +void lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, tpPESession); +void lim_decide_ap_protection_on_delete(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +extern tSirRetStatus lim_update_11a_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession); +extern tSirRetStatus lim_enable11g_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_protection_from11g(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht20_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession sessionEntry); +extern tSirRetStatus lim_enable_ht_non_gf_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern tSirRetStatus lim_enable_ht_rifs_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_lsig_txop_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern tSirRetStatus lim_enable_short_preamble(tpAniSirGlobal pMac, + uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_obss_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +void lim_decide_sta_protection(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry); +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry); +/* Print MAC address utility function */ +void lim_print_mac_addr(tpAniSirGlobal, tSirMacAddr, uint8_t); + +/* Deferred Message Queue read/write */ +uint8_t lim_write_deferred_msg_q(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +tSirMsgQ *lim_read_deferred_msg_q(tpAniSirGlobal pMac); +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, tpSirMsgQ pLimMsg); + +/* Deferred Message Queue Reset */ +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac); + +tSirRetStatus lim_sys_process_mmh_msg_api(tpAniSirGlobal, tSirMsgQ *, uint8_t); + +void lim_handle_update_olbc_cache(tpAniSirGlobal pMac); + +uint8_t lim_is_null_ssid(tSirMacSSid *pSsid); + +/* 11h Support */ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_process_channel_switch_timeout(tpAniSirGlobal); +tSirRetStatus lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_update_channel_switch(tpAniSirGlobal, tpSirProbeRespBeacon, + tpPESession psessionEntry); +void lim_process_quiet_timeout(tpAniSirGlobal); +void lim_process_quiet_bss_timeout(tpAniSirGlobal); + +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_switch_primary_channel(tpAniSirGlobal, uint8_t, tpPESession); +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + phy_ch_width ch_width); +void limUpdateStaRunTimeHTSwtichChnlParams(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + uint8_t bssIdx); +void lim_update_sta_run_time_ht_capability(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps); +void lim_update_sta_run_time_ht_info(struct sAniSirGlobal *pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + tpPESession psessionEntry); +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry); +tAniBool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, + uint8_t channel); +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode); +tSirRetStatus lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); +tSirRetStatus lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_switch_channel_cback(tpAniSirGlobal pMac, CDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); + +static inline tSirRFBand lim_get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return SIR_BAND_5_GHZ; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return SIR_BAND_2_4_GHZ; + + return SIR_BAND_UNKNOWN; +} + +static inline tSirRetStatus +lim_get_mgmt_staid(tpAniSirGlobal pMac, uint16_t *staid, + tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry)) + *staid = 1; + else if (LIM_IS_STA_ROLE(psessionEntry)) + *staid = 0; + else + return eSIR_FAILURE; + + return eSIR_SUCCESS; +} + +static inline uint8_t lim_is_system_in_set_mimops_state(tpAniSirGlobal pMac) +{ + if (pMac->lim.gLimMlmState == eLIM_MLM_WT_SET_MIMOPS_STATE) + return true; + return false; +} + +static inline uint8_t +is_entering_mimo_ps(tSirMacHTMIMOPowerSaveState curState, + tSirMacHTMIMOPowerSaveState newState) +{ + if (curState == eSIR_HT_MIMO_PS_NO_LIMIT && + (newState == eSIR_HT_MIMO_PS_DYNAMIC + || newState == eSIR_HT_MIMO_PS_STATIC)) + return true; + return false; +} + +static inline int lim_select_cb_mode(tDphHashNode *pStaDs, + tpPESession psessionEntry, uint8_t channel, + uint8_t chan_bw) +{ + if (pStaDs->mlmStaContext.vhtCapability && chan_bw) { + if (channel == 36 || channel == 52 || channel == 100 || + channel == 116 || channel == 149) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1; + } else if (channel == 40 || channel == 56 || channel == 104 || + channel == 120 || channel == 153) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW - 1; + } else if (channel == 44 || channel == 60 || channel == 108 || + channel == 124 || channel == 157) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH - 1; + } else if (channel == 48 || channel == 64 || channel == 112 || + channel == 128 || channel == 161) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH - 1; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } else if (pStaDs->mlmStaContext.htCapability) { + if (channel == 40 || channel == 48 || channel == 56 || + channel == 64 || channel == 104 || channel == 112 || + channel == 120 || channel == 128 || channel == 136 || + channel == 144 || channel == 153 || channel == 161) { + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + } else if (channel == 36 || channel == 44 || channel == 52 || + channel == 60 || channel == 100 || + channel == 108 || channel == 116 || + channel == 124 || channel == 132 || + channel == 140 || channel == 149 || + channel == 157) { + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } + return PHY_SINGLE_CHANNEL_CENTERED; +} + +/* ANI peer station count management and associated actions */ +void lim_util_count_sta_add(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); +void lim_util_count_sta_del(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); + +uint8_t lim_get_ht_capability(tpAniSirGlobal, uint32_t, tpPESession); +void lim_tx_complete(tHalHandle hHal, void *pData, bool free); + +/** + * This function will be registered with HAL for callback when TSPEC inactivity + * timer fires. + */ + +void lim_process_del_ts_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +tSirRetStatus lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); +tSirRetStatus lim_validate_delts_req(tpAniSirGlobal pMac, + tpSirDeltsReq pDeltsReq, + tSirMacAddr peerMacAddr, + tpPESession psessionEntry); + +/* callback function registration to HAL for any indication. */ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac); +void lim_pkt_free(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pBD, void *body); + +void lim_get_b_dfrom_rx_packet(tpAniSirGlobal pMac, void *body, uint32_t **pBD); + +/** + * utils_power_xy() - calc result of base raised to power + * @base: Base value + * @power: Base raised to this Power value + * + * Given a base(X) and power(Y), this API will return + * the result of base raised to power - (X ^ Y) + * + * Return: Result of X^Y + * + */ +static inline uint32_t utils_power_xy(uint16_t base, uint16_t power) +{ + uint32_t result = 1, i; + + for (i = 0; i < power; i++) + result *= base; + + return result; +} + +tSirRetStatus lim_post_sm_state_update(tpAniSirGlobal pMac, + uint16_t StaIdx, + tSirMacHTMIMOPowerSaveState MIMOPSState, + uint8_t *pPeerStaMac, uint8_t sessionId); + +void lim_delete_sta_context(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac); +void lim_resset_scan_channel_info(tpAniSirGlobal pMac); +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon); +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, + uint32_t type, tpSchBeaconStruct pBeacon); + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *pTsInfo, uint32_t action); + +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_process_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ pMsgQ); + +void lim_update_beacon(tpAniSirGlobal pMac); + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_bt_amp_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, + tpPESession psessionEntry); + +void lim_process_bt_amp_ap_mlm_del_sta_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, + tpPESession psessionEntry); + +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac); +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac); +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal pMac); + +uint8_t *lim_get_ie_ptr_new(tpAniSirGlobal pMac, uint8_t *pIes, int length, + uint8_t eid, eSizeOfLenField size_of_len_field); + +#define limGetWscIEPtr(pMac, ie, ie_len) \ + cfg_get_vendor_ie_ptr_from_oui(pMac, SIR_MAC_WSC_OUI, \ + SIR_MAC_WSC_OUI_SIZE, ie, ie_len) + +#define limGetP2pIEPtr(pMac, ie, ie_len) \ + cfg_get_vendor_ie_ptr_from_oui(pMac, SIR_MAC_P2P_OUI, \ + SIR_MAC_P2P_OUI_SIZE, ie, ie_len) + +uint8_t lim_get_noa_attr_stream_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen); +uint8_t lim_get_noa_attr_stream(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry); + +uint8_t lim_build_p2p_ie(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len); +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac); +bool lim_isconnected_on_dfs_channel(uint8_t currentChannel); +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac); + +#ifdef WLAN_FEATURE_11AC +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t chanWidth, uint8_t staId, + uint8_t *peerMac); +bool lim_set_nss_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac); +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId); +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +typedef enum { + WLAN_PE_DIAG_SCAN_REQ_EVENT = 0, + WLAN_PE_DIAG_SCAN_ABORT_IND_EVENT, + WLAN_PE_DIAG_SCAN_RSP_EVENT, + WLAN_PE_DIAG_JOIN_REQ_EVENT, + WLAN_PE_DIAG_JOIN_RSP_EVENT, + WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + WLAN_PE_DIAG_REASSOC_REQ_EVENT, + WLAN_PE_DIAG_REASSOC_RSP_EVENT, + WLAN_PE_DIAG_AUTH_REQ_EVENT, + WLAN_PE_DIAG_AUTH_RSP_EVENT = 10, + WLAN_PE_DIAG_DISASSOC_REQ_EVENT, + WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + WLAN_PE_DIAG_DISASSOC_IND_EVENT, + WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_IND_EVENT, + WLAN_PE_DIAG_START_BSS_REQ_EVENT, + WLAN_PE_DIAG_START_BSS_RSP_EVENT, + WLAN_PE_DIAG_AUTH_IND_EVENT = 20, + WLAN_PE_DIAG_ASSOC_IND_EVENT, + WLAN_PE_DIAG_ASSOC_CNF_EVENT, + WLAN_PE_DIAG_REASSOC_IND_EVENT, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, + WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, + WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + WLAN_PE_DIAG_ADDTS_REQ_EVENT, + WLAN_PE_DIAG_ADDTS_RSP_EVENT, + WLAN_PE_DIAG_DELTS_REQ_EVENT = 30, + WLAN_PE_DIAG_DELTS_RSP_EVENT, + WLAN_PE_DIAG_DELTS_IND_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_REQ_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_REQ_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_IND_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_REQ_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_EXIT_UAPSD_REQ_EVENT = 40, + WLAN_PE_DIAG_EXIT_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_WOWL_ADD_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_WOWL_DEL_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_REQ_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_RSP_EVENT, + WLAN_PE_DIAG_EXIT_WOWL_REQ_EVENT, + WLAN_PE_DIAG_EXIT_WOWL_RSP_EVENT, + WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT = 50, + WLAN_PE_DIAG_PREAUTH_DONE, + WLAN_PE_DIAG_REASSOCIATING, + WLAN_PE_DIAG_CONNECTED, + WLAN_PE_DIAG_ASSOC_REQ_EVENT, + WLAN_PE_DIAG_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_AUTH_START_EVENT, + WLAN_PE_DIAG_ASSOC_START_EVENT, + WLAN_PE_DIAG_REASSOC_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_START_EVENT = 60, + WLAN_PE_DIAG_ROAM_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ROAM_ASSOC_START_EVENT, + WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + RESERVED1, /* = 64 for SCAN_COMPLETE */ + RESERVED2, /* = 65 for SCAN_RES_FOUND */ +} WLAN_PE_DIAG_EVENT_TYPE; + +void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void pe_set_resume_channel(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState cbState); + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t phyMode, uint8_t *pShortSlotEnable); + +void lim_clean_up_disassoc_deauth_req(tpAniSirGlobal pMac, uint8_t *staMac, + bool cleanRxPath); + +bool lim_check_disassoc_deauth_ack_pending(tpAniSirGlobal pMac, + uint8_t *staMac); + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param); +#endif + +void lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr); + +#ifdef WLAN_FEATURE_11W +void lim_pmf_comeback_timer_callback(void *context); +#endif /* WLAN_FEATURE_11W */ + +void lim_set_ht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_ntry, + uint8_t *p_ie_start, + uint32_t num_bytes); + +#ifdef WLAN_FEATURE_11AC +void lim_set_vht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_entry, + uint8_t *p_ie_start, + uint32_t num_bytes); +#endif /* WLAN_FEATURE_11AC */ +bool lim_validate_received_frame_a1_addr(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session); +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + tpAniSirGlobal mac_ctx); + +void lim_check_and_reset_protection_params(tpAniSirGlobal mac_ctx); + +CDF_STATUS lim_send_ext_cap_ie(tpAniSirGlobal mac_ctx, uint32_t session_id, + tDot11fIEExtCap *extracted_extcap, bool merge); + +tSirRetStatus lim_strip_extcap_ie(tpAniSirGlobal mac_ctx, uint8_t *addn_ie, + uint16_t *addn_ielen, uint8_t *extracted_extcap); +void lim_update_extcap_struct(tpAniSirGlobal mac_ctx, uint8_t *buf, + tDot11fIEExtCap *ext_cap); +tSirRetStatus lim_strip_extcap_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst); +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, tDot11fIEExtCap *src); + +#endif /* __LIM_UTILS_H */ diff --git a/core/mac/src/pe/rrm/rrm_api.c b/core/mac/src/pe/rrm/rrm_api.c new file mode 100644 index 0000000000..5b85bf9a73 --- /dev/null +++ b/core/mac/src/pe/rrm/rrm_api.c @@ -0,0 +1,1495 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file rrm_api.c + + \brief implementation for PE RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#if defined WLAN_FEATURE_VOWIFI + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_send_messages.h" +#include "rrm_global.h" +#include "rrm_api.h" + +uint8_t +rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, + tPowerdBm regMax, tPowerdBm apTxPower) +{ + uint8_t maxTxPower = 0; + uint8_t txPower = CDF_MIN(regMax, (apTxPower)); + if ((txPower >= RRM_MIN_TX_PWR_CAP) && (txPower <= RRM_MAX_TX_PWR_CAP)) + maxTxPower = txPower; + else if (txPower < RRM_MIN_TX_PWR_CAP) + maxTxPower = RRM_MIN_TX_PWR_CAP; + else + maxTxPower = RRM_MAX_TX_PWR_CAP; + + lim_log(pMac, LOG3, + "%s: regulatoryMax = %d, apTxPwr = %d, maxTxpwr = %d", + __func__, regMax, apTxPower, maxTxPower); + return maxTxPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cache_mgmt_tx_power + ** + * FUNCTION: Store Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return None + */ +void +rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, tPowerdBm txPower, + tpPESession pSessionEntry) +{ + lim_log(pMac, LOG3, "Cache Mgmt Tx Power = %d", txPower); + + if (pSessionEntry == NULL) { + lim_log(pMac, LOG3, "%s: pSessionEntry is NULL", __func__); + pMac->rrm.rrmPEContext.txMgmtPower = txPower; + } else + pSessionEntry->txMgmtPower = txPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_mgmt_tx_power + * + * FUNCTION: Get the Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return txPower + */ +tPowerdBm rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + lim_log(pMac, LOG3, "RrmGetMgmtTxPower called"); + + if (pSessionEntry == NULL) { + lim_log(pMac, LOG3, "%s: txpower from rrmPEContext: %d", + __func__, pMac->rrm.rrmPEContext.txMgmtPower); + return pMac->rrm.rrmPEContext.txMgmtPower; + } + + return pSessionEntry->txMgmtPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_send_set_max_tx_power_req + * + * FUNCTION: Send WMA_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, tPowerdBm txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + if (pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid parameters"));) + return eSIR_FAILURE; + } + pMaxTxParams = cdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory for pMaxTxParams ")); + return eSIR_MEM_ALLOC_FAILED; + + } + /* Allocated memory for pMaxTxParams...will be freed in other module */ + pMaxTxParams->power = txPower; + cdf_mem_copy(pMaxTxParams->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMaxTxParams->selfStaMacAddr, pSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG3, + FL("Sending WMA_SET_MAX_TX_POWER_REQ with power(%d) to HAL"), + txPower); + + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, msgQ.type)); + if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) { + lim_log(pMac, LOGP, + FL + ("Posting WMA_SET_MAX_TX_POWER_REQ to HAL failed, reason=%X"), + retCode); + cdf_mem_free(pMaxTxParams); + return retCode; + } + return retCode; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_set_max_tx_power_rsp + * + * FUNCTION: Process WMA_SET_MAX_TX_POWER_RSP message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tpMaxTxPowerParams pMaxTxParams = (tpMaxTxPowerParams) limMsgQ->bodyptr; + tpPESession pSessionEntry; + uint8_t sessionId, i; + tSirMacAddr bssid = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (cdf_mem_compare(bssid, pMaxTxParams->bssId, sizeof(tSirMacAddr))) { + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid == true)) { + pSessionEntry = &pMac->lim.gpSession[i]; + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + } else { + if ((pSessionEntry = + pe_find_session_by_bssid(pMac, pMaxTxParams->bssId, + &sessionId)) == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("Unable to find session:")); + ) + retCode = eSIR_FAILURE; + } else { + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + + cdf_mem_free(limMsgQ->bodyptr); + limMsgQ->bodyptr = NULL; + return retCode; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_link_measurement_request + * + * FUNCTION: Processes the Link measurement request and send the report. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBd pointer to BD to extract RSSI and SNR + * @param pLinkReq pointer to the Link request frame structure. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest *pLinkReq, + tpPESession pSessionEntry) +{ + tSirMacLinkReport LinkReport; + tpSirMacMgmtHdr pHdr; + int8_t currentRSSI = 0; + + lim_log(pMac, LOG3, "Received Link measurement request"); + + if (pRxPacketInfo == NULL || pLinkReq == NULL || pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + "%s Invalid parameters - Ignoring the request", + __func__); + ) + return eSIR_FAILURE; + } + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + LinkReport.txPower = lim_get_max_tx_power(pLinkReq->MaxTxPower.maxTxPower, + pLinkReq->MaxTxPower.maxTxPower, + pMac->roam.configParam. + nTxPowerCap); + + if ((LinkReport.txPower != (uint8_t) (pSessionEntry->maxTxPower)) && + (eSIR_SUCCESS == rrm_send_set_max_tx_power_req(pMac, + (tPowerdBm) (LinkReport. + txPower), + pSessionEntry))) { + PELOGW(lim_log + (pMac, LOGW, + FL(" maxTx power in link report is not same as local..." + " Local = %d Link Request TxPower = %d" + " Link Report TxPower = %d"), + pSessionEntry->maxTxPower, LinkReport.txPower, + pLinkReq->MaxTxPower.maxTxPower); + ) + pSessionEntry->maxTxPower = + (tPowerdBm) (LinkReport.txPower); + } + + LinkReport.dialogToken = pLinkReq->DialogToken.token; + LinkReport.rxAntenna = 0; + LinkReport.txAntenna = 0; + currentRSSI = WMA_GET_RX_RSSI_DB(pRxPacketInfo); + + lim_log(pMac, LOG1, "Received Link report frame with %d", currentRSSI); + + /* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ + if ((currentRSSI) <= RCPI_LOW_RSSI_VALUE) + LinkReport.rcpi = 0; + else if ((currentRSSI > RCPI_LOW_RSSI_VALUE) && (currentRSSI <= 0)) + LinkReport.rcpi = CALCULATE_RCPI(currentRSSI); + else + LinkReport.rcpi = RCPI_MAX_VALUE; + + LinkReport.rsni = WMA_GET_RX_SNR(pRxPacketInfo); + + lim_log(pMac, LOG3, "Sending Link report frame"); + + return lim_send_link_report_action_frame(pMac, &LinkReport, pHdr->sa, + pSessionEntry); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_response + * + * FUNCTION: Processes the Neighbor Report response from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborRep pointer to the Neighbor report frame structure. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse *pNeighborRep, + tpPESession pSessionEntry) +{ + tSirRetStatus status = eSIR_FAILURE; + tpSirNeighborReportInd pSmeNeighborRpt = NULL; + uint16_t length; + uint8_t i; + tSirMsgQ mmhMsg; + + if (pNeighborRep == NULL || pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL(" Invalid parameters"));) + return status; + } + + lim_log(pMac, LOG3, FL("Neighbor report response received ")); + + /* Dialog token */ + if (pMac->rrm.rrmPEContext.DialogToken != + pNeighborRep->DialogToken.token) { + PELOGE(lim_log + (pMac, LOGE, + "Dialog token mismatch in the received Neighbor report"); + ) + return eSIR_FAILURE; + } + if (pNeighborRep->num_NeighborReport == 0) { + PELOGE(lim_log + (pMac, LOGE, + "No neighbor report in the frame...Dropping it"); + ) + return eSIR_FAILURE; + } + length = (sizeof(tSirNeighborReportInd)) + + (sizeof(tSirNeighborBssDescription) * + (pNeighborRep->num_NeighborReport - 1)); + + /* Prepare the request to send to SME. */ + pSmeNeighborRpt = cdf_mem_malloc(length); + if (NULL == pSmeNeighborRpt) { + PELOGE(lim_log(pMac, LOGP, FL("Unable to allocate memory"));) + return eSIR_MEM_ALLOC_FAILED; + + } + cdf_mem_set(pSmeNeighborRpt, length, 0); + + /* Allocated memory for pSmeNeighborRpt...will be freed by other module */ + + for (i = 0; i < pNeighborRep->num_NeighborReport; i++) { + pSmeNeighborRpt->sNeighborBssDescription[i].length = sizeof(tSirNeighborBssDescription); /*+ any optional ies */ + cdf_mem_copy(pSmeNeighborRpt->sNeighborBssDescription[i].bssId, + pNeighborRep->NeighborReport[i].bssid, + sizeof(tSirMacAddr)); + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fApPreauthReachable = + pNeighborRep->NeighborReport[i].APReachability; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameSecurityMode = + pNeighborRep->NeighborReport[i].Security; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameAuthenticator = + pNeighborRep->NeighborReport[i].KeyScope; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapSpectrumMeasurement = + pNeighborRep->NeighborReport[i].SpecMgmtCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapQos = pNeighborRep->NeighborReport[i].QosCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapApsd = pNeighborRep->NeighborReport[i].apsd; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapRadioMeasurement = pNeighborRep->NeighborReport[i].rrm; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapDelayedBlockAck = + pNeighborRep->NeighborReport[i].DelayedBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapImmediateBlockAck = + pNeighborRep->NeighborReport[i].ImmBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fMobilityDomain = + pNeighborRep->NeighborReport[i].MobilityDomain; + + pSmeNeighborRpt->sNeighborBssDescription[i].regClass = + pNeighborRep->NeighborReport[i].regulatoryClass; + pSmeNeighborRpt->sNeighborBssDescription[i].channel = + pNeighborRep->NeighborReport[i].channel; + pSmeNeighborRpt->sNeighborBssDescription[i].phyType = + pNeighborRep->NeighborReport[i].PhyType; + } + + pSmeNeighborRpt->messageType = eWNI_SME_NEIGHBOR_REPORT_IND; + pSmeNeighborRpt->length = length; + pSmeNeighborRpt->sessionId = pSessionEntry->smeSessionId; + pSmeNeighborRpt->numNeighborReports = pNeighborRep->num_NeighborReport; + cdf_mem_copy(pSmeNeighborRpt->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + + /* Send request to SME. */ + mmhMsg.type = pSmeNeighborRpt->messageType; + mmhMsg.bodyptr = pSmeNeighborRpt; + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, mmhMsg.type)); + status = lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return status; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_req + * + * FUNCTION: + * + * LOGIC: Create a Neighbor report request and send it to peer. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborReq Neighbor report request params . + * @return None + */ +tSirRetStatus +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq) +{ + tSirRetStatus status = eSIR_SUCCESS; + tSirMacNeighborReportReq NeighborReportReq; + tpPESession pSessionEntry; + uint8_t sessionId; + + if (pNeighborReq == NULL) { + PELOGE(lim_log(pMac, LOGE, "NeighborReq is NULL");) + return eSIR_FAILURE; + } + if ((pSessionEntry = + pe_find_session_by_bssid(pMac, pNeighborReq->bssId, + &sessionId)) == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given bssId")); + ) + return eSIR_FAILURE; + } + + lim_log(pMac, LOG1, FL("SSID present = %d "), pNeighborReq->noSSID); + + cdf_mem_set(&NeighborReportReq, sizeof(tSirMacNeighborReportReq), 0); + + NeighborReportReq.dialogToken = ++pMac->rrm.rrmPEContext.DialogToken; + NeighborReportReq.ssid_present = !pNeighborReq->noSSID; + if (NeighborReportReq.ssid_present) { + cdf_mem_copy(&NeighborReportReq.ssid, &pNeighborReq->ucSSID, + sizeof(tSirMacSSid)); + PELOGE(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOGE, + (uint8_t *) NeighborReportReq.ssid.ssId, + NeighborReportReq.ssid.length); + ) + } + + status = + lim_send_neighbor_report_request_frame(pMac, &NeighborReportReq, + pNeighborReq->bssId, + pSessionEntry); + + return status; +} + +#define ABS(x) ((x < 0) ? -x : x) +/* -------------------------------------------------------------------- */ +/** + * rrm_process_beacon_report_req + * + * FUNCTION: Processes the Beacon report request from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pCurrentReq pointer to the current Req comtext. + * @param pBeaconReq pointer to the beacon report request IE from the peer. + * @param pSessionEntry session entry. + * @return None + */ +static tRrmRetStatus +rrm_process_beacon_report_req(tpAniSirGlobal pMac, + tpRRMReq pCurrentReq, + tDot11fIEMeasurementRequest *pBeaconReq, + tpPESession pSessionEntry) +{ + tSirMsgQ mmhMsg; + tpSirBeaconReportReqInd pSmeBcnReportReq; + uint8_t num_channels = 0, num_APChanReport; + uint16_t measDuration, maxMeasduration; + int8_t maxDuration; + uint8_t sign; + + if (pBeaconReq->measurement_request.Beacon.BeaconReporting.present && + (pBeaconReq->measurement_request.Beacon.BeaconReporting. + reportingCondition != 0)) { + /* Repeated measurement is not supported. This means number of repetitions should be zero.(Already checked) */ + /* All test case in VoWifi(as of version 0.36) use zero for number of repetitions. */ + /* Beacon reporting should not be included in request if number of repetitons is zero. */ + /* IEEE Std 802.11k-2008 Table 7-29g and section 11.10.8.1 */ + + PELOGE(lim_log + (pMac, LOGE, + "Dropping the request: Reporting condition included in beacon report request and it is not zero"); + ) + return eRRM_INCAPABLE; + } + + /* The logic here is to check the measurement duration passed in the beacon request. Following are the cases handled. + Case 1: If measurement duration received in the beacon request is greater than the max measurement duration advertised + in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 1, REFUSE the beacon request + Case 2: If measurement duration received in the beacon request is greater than the max measurement duration advertised + in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 0, perform measurement for + the duration advertised in the RRM capabilities + + maxMeasurementDuration = 2^(nonOperatingChanMax - 4) * BeaconInterval + */ + maxDuration = + pMac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4; + sign = (maxDuration < 0) ? 1 : 0; + maxDuration = (1L << ABS(maxDuration)); + if (!sign) + maxMeasduration = + maxDuration * pSessionEntry->beaconParams.beaconInterval; + else + maxMeasduration = + pSessionEntry->beaconParams.beaconInterval / maxDuration; + + measDuration = pBeaconReq->measurement_request.Beacon.meas_duration; + + lim_log(pMac, LOG3, + "maxDuration = %d sign = %d maxMeasduration = %d measDuration = %d", + maxDuration, sign, maxMeasduration, measDuration); + + if (maxMeasduration < measDuration) { + if (pBeaconReq->durationMandatory) { + PELOGE(lim_log + (pMac, LOGE, + "Dropping the request: duration mandatory and maxduration > measduration"); + ) + return eRRM_REFUSED; + } else + measDuration = maxMeasduration; + } + /* Cache the data required for sending report. */ + pCurrentReq->request.Beacon.reportingDetail = + pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + present ? pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + reportingDetail : BEACON_REPORTING_DETAIL_ALL_FF_IE; + + if (pBeaconReq->measurement_request.Beacon.RequestedInfo.present) { + pCurrentReq->request.Beacon.reqIes.pElementIds = + cdf_mem_malloc(sizeof(uint8_t) * + pBeaconReq->measurement_request.Beacon. + RequestedInfo.num_requested_eids); + if (NULL == pCurrentReq->request.Beacon.reqIes.pElementIds) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory for request IEs buffer")); + return eRRM_FAILURE; + } + lim_log(pMac, LOG3, FL(" Allocated memory for pElementIds")); + + pCurrentReq->request.Beacon.reqIes.num = + pBeaconReq->measurement_request.Beacon.RequestedInfo. + num_requested_eids; + cdf_mem_copy(pCurrentReq->request.Beacon.reqIes.pElementIds, + pBeaconReq->measurement_request.Beacon. + RequestedInfo.requested_eids, + pCurrentReq->request.Beacon.reqIes.num); + } + + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) + num_channels += + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + } + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = cdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during Beacon Report Req Ind to SME")); + + return eRRM_FAILURE; + + } + + cdf_mem_set(pSmeBcnReportReq, sizeof(tSirBeaconReportReqInd), 0); + + /* Allocated memory for pSmeBcnReportReq....will be freed by other modulea */ + cdf_mem_copy(pSmeBcnReportReq->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + pSmeBcnReportReq->uDialogToken = pBeaconReq->measurement_token; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_11K; + pSmeBcnReportReq->randomizationInterval = + SYS_TU_TO_MS(pBeaconReq->measurement_request.Beacon.randomization); + pSmeBcnReportReq->channelInfo.regulatoryClass = + pBeaconReq->measurement_request.Beacon.regClass; + pSmeBcnReportReq->channelInfo.channelNum = + pBeaconReq->measurement_request.Beacon.channel; + pSmeBcnReportReq->measurementDuration[0] = SYS_TU_TO_MS(measDuration); + pSmeBcnReportReq->fMeasurementtype[0] = + pBeaconReq->measurement_request.Beacon.meas_mode; + cdf_mem_copy(pSmeBcnReportReq->macaddrBssid, + pBeaconReq->measurement_request.Beacon.BSSID, + sizeof(tSirMacAddr)); + + if (pBeaconReq->measurement_request.Beacon.SSID.present) { + pSmeBcnReportReq->ssId.length = + pBeaconReq->measurement_request.Beacon.SSID.num_ssid; + cdf_mem_copy(pSmeBcnReportReq->ssId.ssId, + pBeaconReq->measurement_request.Beacon.SSID.ssid, + pSmeBcnReportReq->ssId.length); + } + + pCurrentReq->token = pBeaconReq->measurement_token; + + pSmeBcnReportReq->channelList.numChannels = num_channels; + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + uint8_t *pChanList = + pSmeBcnReportReq->channelList.channelNumber; + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) { + cdf_mem_copy(pChanList, + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport]. + channelList, + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport]. + num_channelList); + + pChanList += + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + } + } + /* Send request to SME. */ + mmhMsg.type = eWNI_SME_BEACON_REPORT_REQ_IND; + mmhMsg.bodyptr = pSmeBcnReportReq; + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, mmhMsg.type)); + return lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_fill_beacon_ies + * + * FUNCTION: + * + * LOGIC: Fills Fixed fields and Ies in bss description to an array of uint8_t. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pIes - pointer to the buffer that should be populated with ies. + * @param pNumIes - returns the num of ies filled in this param. + * @param pIesMaxSize - Max size of the buffer pIes. + * @param eids - pointer to array of eids. If NULL, all ies will be populated. + * @param numEids - number of elements in array eids. + * @param pBssDesc - pointer to Bss Description. + * @return None + */ +static void +rrm_fill_beacon_ies(tpAniSirGlobal pMac, + uint8_t *pIes, uint8_t *pNumIes, uint8_t pIesMaxSize, + uint8_t *eids, uint8_t numEids, tpSirBssDescription pBssDesc) +{ + uint8_t len, *pBcnIes, count = 0, i; + uint8_t BcnNumIes; + + if ((pIes == NULL) || (pNumIes == NULL) || (pBssDesc == NULL)) { + PELOGE(lim_log(pMac, LOGE, FL(" Invalid parameters"));) + return; + } + /* Make sure that if eid is null, numEids is set to zero. */ + numEids = (eids == NULL) ? 0 : numEids; + + pBcnIes = (uint8_t *) &pBssDesc->ieFields[0]; + BcnNumIes = (uint8_t) GET_IE_LEN_IN_BSS(pBssDesc->length); + + *pNumIes = 0; + + *((uint32_t *) pIes) = pBssDesc->timeStamp[0]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint32_t *) pIes) = pBssDesc->timeStamp[1]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint16_t *) pIes) = pBssDesc->beaconInterval; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + *((uint16_t *) pIes) = pBssDesc->capabilityInfo; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + + while (BcnNumIes > 0) { + len = *(pBcnIes + 1) + 2; /* element id + length. */ + lim_log(pMac, LOG3, "EID = %d, len = %d total = %d", + *pBcnIes, *(pBcnIes + 1), len); + + i = 0; + do { + if (((eids == NULL) || (*pBcnIes == eids[i])) && + ((*pNumIes) + len) < pIesMaxSize) { + lim_log(pMac, LOG3, "Adding Eid %d, len=%d", + *pBcnIes, len); + + cdf_mem_copy(pIes, pBcnIes, len); + pIes += len; + *pNumIes += len; + count++; + break; + } + i++; + } while (i < numEids); + + pBcnIes += len; + BcnNumIes -= len; + } + lim_log(pMac, LOG1, "Total length of Ies added = %d", *pNumIes); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_beacon_report_xmit + * + * FUNCTION: + * + * LOGIC: Create a Radio measurement report action frame and send it to peer. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBcnReport Data for beacon report IE from SME. + * @return None + */ +tSirRetStatus +rrm_process_beacon_report_xmit(tpAniSirGlobal pMac, + tpSirBeaconReportXmitInd pBcnReport) +{ + tSirRetStatus status = eSIR_SUCCESS; + tSirMacRadioMeasureReport *pReport = NULL; + tpRRMReq pCurrentReq = pMac->rrm.rrmPEContext.pCurrentReq; + tpPESession pSessionEntry; + uint8_t sessionId; + uint8_t flagBSSPresent = false, bssDescCnt = 0; + + lim_log(pMac, LOG1, "Received beacon report xmit indication"); + + if (NULL == pBcnReport) { + PELOGE(lim_log(pMac, LOGE, "Received pBcnReport is NULL in PE");) + return eSIR_FAILURE; + } + + if (NULL == pCurrentReq) { + PELOGE(lim_log(pMac, LOGE, + "Received report xmit while there is no request pending in PE"); + ) + return eSIR_FAILURE; + } + + if ((pBcnReport->numBssDesc) || + (!pBcnReport->numBssDesc && pCurrentReq->sendEmptyBcnRpt)) { + pBcnReport->numBssDesc = + (pBcnReport->numBssDesc == + RRM_BCN_RPT_NO_BSS_INFO) ? RRM_BCN_RPT_MIN_RPT : + pBcnReport->numBssDesc; + + if (NULL == (pSessionEntry = pe_find_session_by_bssid(pMac, + pBcnReport-> + bssId, + &sessionId))) + { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given bssId")); + ) + return eSIR_FAILURE; + } + + pReport = cdf_mem_malloc(pBcnReport->numBssDesc * + sizeof(tSirMacRadioMeasureReport)); + + if (NULL == pReport) { + PELOGE(lim_log + (pMac, LOGE, + FL("RRM Report is NULL, allocation failed")); + ) + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_zero(pReport, + pBcnReport->numBssDesc * + sizeof(tSirMacRadioMeasureReport)); + + for (bssDescCnt = 0; bssDescCnt < pBcnReport->numBssDesc; + bssDescCnt++) { + /* Prepare the beacon report and send it to the peer. */ + pReport[bssDescCnt].token = pBcnReport->uDialogToken; + pReport[bssDescCnt].refused = 0; + pReport[bssDescCnt].incapable = 0; + pReport[bssDescCnt].type = SIR_MAC_RRM_BEACON_TYPE; + + /* If the scan result is NULL then send report request with */ + /* option subelement as NULL.. */ + if (NULL != pBcnReport->pBssDescription[bssDescCnt]) { + flagBSSPresent = true; + } + /* Valid response is included if the size of beacon xmit */ + /* is == size of beacon xmit ind + ies */ + if (pBcnReport->length >= + sizeof(tSirBeaconReportXmitInd)) { + pReport[bssDescCnt].report.beaconReport. + regClass = pBcnReport->regClass; + if (flagBSSPresent) { + pReport[bssDescCnt].report.beaconReport. + channel = + pBcnReport-> + pBssDescription[bssDescCnt]-> + channelId; + cdf_mem_copy(pReport[bssDescCnt].report. + beaconReport.measStartTime, + pBcnReport-> + pBssDescription + [bssDescCnt]->startTSF, + sizeof(pBcnReport-> + pBssDescription + [bssDescCnt]-> + startTSF)); + pReport[bssDescCnt].report.beaconReport. + measDuration = + SYS_MS_TO_TU(pBcnReport->duration); + pReport[bssDescCnt].report.beaconReport. + phyType = + pBcnReport-> + pBssDescription[bssDescCnt]->nwType; + pReport[bssDescCnt].report.beaconReport. + bcnProbeRsp = 1; + pReport[bssDescCnt].report.beaconReport. + rsni = + pBcnReport-> + pBssDescription[bssDescCnt]->sinr; + pReport[bssDescCnt].report.beaconReport. + rcpi = + pBcnReport-> + pBssDescription[bssDescCnt]->rssi; + + pReport[bssDescCnt].report.beaconReport. + antennaId = 0; + pReport[bssDescCnt].report.beaconReport. + parentTSF = + pBcnReport-> + pBssDescription[bssDescCnt]-> + parentTSF; + cdf_mem_copy(pReport[bssDescCnt].report. + beaconReport.bssid, + pBcnReport-> + pBssDescription + [bssDescCnt]->bssId, + sizeof(tSirMacAddr)); + } + + switch (pCurrentReq->request.Beacon. + reportingDetail) { + case BEACON_REPORTING_DETAIL_NO_FF_IE: + /* 0 No need to include any elements. */ + lim_log(pMac, LOG3, + "No reporting detail requested"); + break; + case BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE: + /* 1: Include all FFs and Requested Ies. */ + lim_log(pMac, LOG3, + "Only requested IEs in reporting detail requested"); + + if (flagBSSPresent) { + rrm_fill_beacon_ies(pMac, + (uint8_t *) & + pReport + [bssDescCnt]. + report. + beaconReport. + Ies[0], + (uint8_t *) & + pReport + [bssDescCnt]. + report. + beaconReport. + numIes, + BEACON_REPORT_MAX_IES, + pCurrentReq-> + request.Beacon. + reqIes. + pElementIds, + pCurrentReq-> + request.Beacon. + reqIes.num, + pBcnReport-> + pBssDescription + [bssDescCnt]); + } + + break; + case BEACON_REPORTING_DETAIL_ALL_FF_IE: + /* 2 / default - Include all FFs and all Ies. */ + default: + lim_log(pMac, LOG3, + "Default all IEs and FFs"); + if (flagBSSPresent) { + rrm_fill_beacon_ies(pMac, + (uint8_t *) & + pReport + [bssDescCnt]. + report. + beaconReport. + Ies[0], + (uint8_t *) & + pReport + [bssDescCnt]. + report. + beaconReport. + numIes, + BEACON_REPORT_MAX_IES, + NULL, 0, + pBcnReport-> + pBssDescription + [bssDescCnt]); + } + break; + } + } + } + + lim_log(pMac, LOG1, "Sending Action frame with %d bss info", + bssDescCnt); + lim_send_radio_measure_report_action_frame(pMac, + pCurrentReq->dialog_token, + bssDescCnt, pReport, + pBcnReport->bssId, + pSessionEntry); + + pCurrentReq->sendEmptyBcnRpt = false; + } + + if (pBcnReport->fMeasureDone) { + lim_log(pMac, LOG3, "Measurement done....cleanup the context"); + + rrm_cleanup(pMac); + } + + if (NULL != pReport) + cdf_mem_free(pReport); + + return status; +} + +void rrm_process_beacon_request_failure(tpAniSirGlobal pMac, + tpPESession pSessionEntry, tSirMacAddr peer, + tRrmRetStatus status) +{ + tpSirMacRadioMeasureReport pReport = NULL; + tpRRMReq pCurrentReq = pMac->rrm.rrmPEContext.pCurrentReq; + + pReport = cdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return; + } + cdf_mem_set(pReport, sizeof(tSirMacRadioMeasureReport), 0); + pReport->token = pCurrentReq->token; + pReport->type = SIR_MAC_RRM_BEACON_TYPE; + + switch (status) { + case eRRM_REFUSED: + pReport->refused = 1; + break; + case eRRM_INCAPABLE: + pReport->incapable = 1; + break; + default: + PELOGE(lim_log(pMac, LOGE, + FL + (" Beacon request processing failed no report sent with status %d "), + status); + ); + cdf_mem_free(pReport); + return; + } + + lim_send_radio_measure_report_action_frame(pMac, pCurrentReq->dialog_token, 1, + pReport, peer, pSessionEntry); + + cdf_mem_free(pReport); + lim_log(pMac, LOG3, FL(" Free memory for pReport")); + return; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_radio_measurement_request + * + * FUNCTION: Processes the Radio Resource Measurement request. + * + * LOGIC: + + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param peer Macaddress of the peer requesting the radio measurement. + * @param pRRMReq Array of Measurement request IEs + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_process_radio_measurement_request(tpAniSirGlobal pMac, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest *pRRMReq, + tpPESession pSessionEntry) +{ + uint8_t i; + tSirRetStatus status = eSIR_SUCCESS; + tpSirMacRadioMeasureReport pReport = NULL; + uint8_t num_report = 0; + tpRRMReq pCurrentReq = pMac->rrm.rrmPEContext.pCurrentReq; + tRrmRetStatus rrmStatus = eRRM_SUCCESS; + + if (!pRRMReq->num_MeasurementRequest) { + /* No measurement requests.... */ + /* */ + pReport = cdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set(pReport, sizeof(tSirMacRadioMeasureReport), 0); + PELOGE(lim_log(pMac, LOGE, + FL + ("No requestIes in the measurement request, sending incapable report")); + ) + pReport->incapable = 1; + num_report = 1; + lim_send_radio_measure_report_action_frame(pMac, + pRRMReq->DialogToken.token, + num_report, pReport, peer, + pSessionEntry); + cdf_mem_free(pReport); + return eSIR_FAILURE; + } + /* PF Fix */ + if (pRRMReq->NumOfRepetitions.repetitions > 0) { + lim_log(pMac, LOG1, + FL(" number of repetitions %d"), + pRRMReq->NumOfRepetitions.repetitions); + + /* Send a report with incapable bit set. Not supporting repetitions. */ + pReport = cdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set(pReport, sizeof(tSirMacRadioMeasureReport), 0); + PELOGE(lim_log(pMac, LOGE, FL(" Allocated memory for pReport"));) + pReport->incapable = 1; + pReport->type = pRRMReq->MeasurementRequest[0].measurement_type; + num_report = 1; + goto end; + + } + + for (i = 0; i < pRRMReq->num_MeasurementRequest; i++) { + switch (pRRMReq->MeasurementRequest[i].measurement_type) { + case SIR_MAC_RRM_BEACON_TYPE: + /* Process beacon request. */ + if (pCurrentReq) { + if (pReport == NULL) /* Allocate memory to send reports for any subsequent requests. */ + { + pReport = + cdf_mem_malloc(sizeof + (tSirMacRadioMeasureReport) + * + (pRRMReq-> + num_MeasurementRequest + - i)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set(pReport, + sizeof + (tSirMacRadioMeasureReport) + * + (pRRMReq-> + num_MeasurementRequest - + i), 0); + lim_log(pMac, LOG3, + FL + (" rrm beacon type refused of %d report in beacon table"), + num_report); + + } + pReport[num_report].refused = 1; + pReport[num_report].type = + SIR_MAC_RRM_BEACON_TYPE; + pReport[num_report].token = + pRRMReq->MeasurementRequest[i]. + measurement_token; + num_report++; + continue; + } else { + pCurrentReq = + cdf_mem_malloc(sizeof(*pCurrentReq)); + if (NULL == pCurrentReq) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + cdf_mem_free(pReport); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(pMac, LOG3, + FL(" Processing Beacon Report request")); + cdf_mem_set(pCurrentReq, sizeof(*pCurrentReq), + 0); + pCurrentReq->dialog_token = + pRRMReq->DialogToken.token; + pCurrentReq->token = + pRRMReq->MeasurementRequest[i]. + measurement_token; + pCurrentReq->sendEmptyBcnRpt = true; + pMac->rrm.rrmPEContext.pCurrentReq = + pCurrentReq; + rrmStatus = + rrm_process_beacon_report_req(pMac, pCurrentReq, + &pRRMReq-> + MeasurementRequest + [i], + pSessionEntry); + if (eRRM_SUCCESS != rrmStatus) { + rrm_process_beacon_request_failure(pMac, + pSessionEntry, + peer, + rrmStatus); + rrm_cleanup(pMac); + } + } + break; + case SIR_MAC_RRM_LCI_TYPE: + case SIR_MAC_RRM_LOCATION_CIVIC_TYPE: + case SIR_MAC_RRM_FINE_TIME_MEAS_TYPE: + lim_log(pMac, LOG1, + FL("RRM with type: %d sent to userspace"), + pRRMReq->MeasurementRequest[i].measurement_type); + break; + default: + /* Send a report with incapabale bit set. */ + if (pReport == NULL) /* Allocate memory to send reports for any subsequent requests. */ + { + pReport = + cdf_mem_malloc(sizeof + (tSirMacRadioMeasureReport) + * + (pRRMReq-> + num_MeasurementRequest - + i)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + cdf_mem_set(pReport, + sizeof(tSirMacRadioMeasureReport) + * (pRRMReq->num_MeasurementRequest - + i), 0); + lim_log(pMac, LOG3, + FL + ("rrm beacon type incapable of %d report "), + num_report); + } + pReport[num_report].incapable = 1; + pReport[num_report].type = + pRRMReq->MeasurementRequest[i].measurement_type; + pReport[num_report].token = + pRRMReq->MeasurementRequest[i].measurement_token; + num_report++; + break; + } + } + +end: + if (pReport) { + lim_send_radio_measure_report_action_frame(pMac, + pRRMReq->DialogToken.token, + num_report, pReport, peer, + pSessionEntry); + + cdf_mem_free(pReport); + lim_log(pMac, LOG3, FL(" Free memory for pReport")); + } + return status; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_update_start_tsf + ** + * FUNCTION: Store start TSF of measurement. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - TSF value at the start of measurement. + * @return None + */ +void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]) +{ + pMac->rrm.rrmPEContext.startTSF[0] = startTSF[0]; + pMac->rrm.rrmPEContext.startTSF[1] = startTSF[1]; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_start_tsf + * + * FUNCTION: Get the Start TSF. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - store star TSF in this buffer. + * @return txPower + */ +void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF) +{ + pStartTSF[0] = pMac->rrm.rrmPEContext.startTSF[0]; + pStartTSF[1] = pMac->rrm.rrmPEContext.startTSF[1]; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_capabilities + * + * FUNCTION: + * Returns a pointer to tpRRMCaps with all the caps enabled in RRM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry + * @return pointer to tRRMCaps + */ +tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + return &pMac->rrm.rrmPEContext.rrmEnabledCaps; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_update_config + * + * FUNCTION: + * Update the configuration. This is called from lim_update_config. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry + * @return pointer to tRRMCaps + */ +void rrm_update_config(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint32_t val; + tpRRMCaps pRRMCaps = &pMac->rrm.rrmPEContext.rrmEnabledCaps; + + if (wlan_cfg_get_int(pMac, WNI_CFG_RRM_ENABLED, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get rrm enabled failed")); + return; + } + pMac->rrm.rrmPEContext.rrmEnable = (val) ? 1 : 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_RRM_OPERATING_CHAN_MAX, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("cfg get rrm operating channel max measurement duration failed")); + return; + } + pRRMCaps->operatingChanMax = (uint8_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_RRM_NON_OPERATING_CHAN_MAX, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("cfg get rrm non-operating channel max measurement duration failed")); + return; + } + pRRMCaps->nonOperatingChanMax = (uint8_t) val; + + lim_log(pMac, LOG1, + "RRM enabled = %d OperatingChanMax = %d NonOperatingMax = %d", + pMac->rrm.rrmPEContext.rrmEnable, + pRRMCaps->operatingChanMax, pRRMCaps->nonOperatingChanMax); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_initialize + * + * FUNCTION: + * Initialize RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @return None + */ + +tSirRetStatus rrm_initialize(tpAniSirGlobal pMac) +{ + tpRRMCaps pRRMCaps = &pMac->rrm.rrmPEContext.rrmEnabledCaps; + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + pMac->rrm.rrmPEContext.txMgmtPower = 0; + pMac->rrm.rrmPEContext.DialogToken = 0; + + pMac->rrm.rrmPEContext.rrmEnable = 0; + + cdf_mem_set(pRRMCaps, sizeof(tRRMCaps), 0); + pRRMCaps->LinkMeasurement = 1; + pRRMCaps->NeighborRpt = 1; + pRRMCaps->BeaconPassive = 1; + pRRMCaps->BeaconActive = 1; + pRRMCaps->BeaconTable = 1; + pRRMCaps->APChanReport = 1; + pRRMCaps->fine_time_meas_rpt = 1; + pRRMCaps->lci_capability = 1; + + pRRMCaps->operatingChanMax = 3; + pRRMCaps->nonOperatingChanMax = 3; + + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cleanup + * + * FUNCTION: + * cleanup RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param mode + * @param rate + * @return None + */ + +tSirRetStatus rrm_cleanup(tpAniSirGlobal pMac) +{ + if (pMac->rrm.rrmPEContext.pCurrentReq) { + if (pMac->rrm.rrmPEContext.pCurrentReq->request.Beacon.reqIes. + pElementIds) { + cdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq-> + request.Beacon.reqIes.pElementIds); + lim_log(pMac, LOG4, FL(" Free memory for pElementIds")); + } + + cdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq); + lim_log(pMac, LOG4, FL(" Free memory for pCurrentReq")); + } + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_message + * + * FUNCTION: Processes the next received Radio Resource Management message + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void rrm_process_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + switch (pMsg->type) { + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + rrm_process_neighbor_report_req(pMac, pMsg->bodyptr); + break; + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + rrm_process_beacon_report_xmit(pMac, pMsg->bodyptr); + break; + } + +} + +#endif diff --git a/core/mac/src/pe/sch/sch_api.c b/core/mac/src/pe/sch/sch_api.c new file mode 100644 index 0000000000..1a11104162 --- /dev/null +++ b/core/mac/src/pe/sch/sch_api.c @@ -0,0 +1,625 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_api.cc contains functions related to the API exposed + * by scheduler module + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" + +#include "cfg_api.h" + +#include "lim_api.h" + +#include "sch_api.h" +#include "sch_debug.h" + +#include "sch_sys_params.h" +#include "lim_trace.h" +#include "lim_types.h" + +#include "wma_types.h" + +/* -------------------------------------------------------------------- */ +/* */ +/* Static Variables */ +/* */ +/* ------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------- */ +/** + * sch_get_cfp_count + * + * FUNCTION: + * Function used by other Sirius modules to read CFPcount + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +uint8_t sch_get_cfp_count(tpAniSirGlobal pMac) +{ + return pMac->sch.schObject.gSchCFPCount; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_get_cfp_dur_remaining + * + * FUNCTION: + * Function used by other Sirius modules to read CFPDuration remaining + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +uint16_t sch_get_cfp_dur_remaining(tpAniSirGlobal pMac) +{ + return pMac->sch.schObject.gSchCFPDurRemaining; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_init_globals + * + * FUNCTION: + * Initialize globals + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_init_globals(tpAniSirGlobal pMac) +{ + pMac->sch.gSchHcfEnabled = false; + + pMac->sch.gSchScanRequested = false; + pMac->sch.gSchScanReqRcvd = false; + + pMac->sch.gSchGenBeacon = 1; + pMac->sch.gSchBeaconsSent = 0; + pMac->sch.gSchBeaconsWritten = 0; + pMac->sch.gSchBcnParseErrorCnt = 0; + pMac->sch.gSchBcnIgnored = 0; + pMac->sch.gSchBBXportRcvCnt = 0; + pMac->sch.gSchUnknownRcvCnt = 0; + pMac->sch.gSchBcnRcvCnt = 0; + pMac->sch.gSchRRRcvCnt = 0; + pMac->sch.qosNullCnt = 0; + pMac->sch.numData = 0; + pMac->sch.numPoll = 0; + pMac->sch.numCorrupt = 0; + pMac->sch.numBogusInt = 0; + pMac->sch.numTxAct0 = 0; + pMac->sch.rrTimeout = SCH_RR_TIMEOUT; + pMac->sch.pollPeriod = SCH_POLL_PERIOD; + pMac->sch.multipleSched = 1; + pMac->sch.maxPollTimeouts = 20; + pMac->sch.checkCfbFlagStuck = 0; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_post_message + * + * FUNCTION: + * Post the beacon message to the scheduler message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMsg pointer to message + * @return None + */ + +tSirRetStatus sch_post_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + sch_process_message(pMac, pMsg); + + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------------- */ +/** + * sch_send_start_scan_rsp + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_send_start_scan_rsp(tpAniSirGlobal pMac) +{ + tSirMsgQ msgQ; + uint32_t retCode; + + PELOG1(sch_log(pMac, LOG1, FL("Sending LIM message to go into scan"));) + msgQ.type = SIR_SCH_START_SCAN_RSP; + if ((retCode = lim_post_msg_api(pMac, &msgQ)) != eSIR_SUCCESS) + sch_log(pMac, LOGE, + FL("Posting START_SCAN_RSP to LIM failed, reason=%X"), + retCode); +} + +/** + * sch_send_beacon_req + * + * FUNCTION: + * + * LOGIC: + * 1) SCH received SIR_SCH_BEACON_GEN_IND + * 2) SCH updates TIM IE and other beacon related IE's + * 3) SCH sends WMA_SEND_BEACON_REQ to HAL. HAL then copies the beacon + * template to memory + * + * ASSUMPTIONS: + * Memory allocation is reqd to send this message and SCH allocates memory. + * The assumption is that HAL will "free" this memory. + * + * NOTE: + * + * @param pMac global + * + * @param beaconPayload + * + * @param size - Length of the beacon + * + * @return CDF_STATUS + */ +tSirRetStatus sch_send_beacon_req(tpAniSirGlobal pMac, uint8_t *beaconPayload, + uint16_t size, tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpSendbeaconParams beaconParams = NULL; + tSirRetStatus retCode; + + sch_log(pMac, LOG2, + FL + ("Indicating HAL to copy the beacon template [%d bytes] to memory"), + size); + + beaconParams = cdf_mem_malloc(sizeof(tSendbeaconParams)); + if (NULL == beaconParams) + return eSIR_MEM_ALLOC_FAILED; + + msgQ.type = WMA_SEND_BEACON_REQ; + + /* No Dialog Token reqd, as a response is not solicited */ + msgQ.reserved = 0; + + /* Fill in tSendbeaconParams members */ + cdf_mem_copy(beaconParams->bssId, psessionEntry->bssId, + sizeof(psessionEntry->bssId)); + + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + beaconParams->timIeOffset = 0; + } else { + beaconParams->timIeOffset = psessionEntry->schBeaconOffsetBegin; + } + + /* p2pIeOffset should be atleast greater than timIeOffset */ + if ((pMac->sch.schObject.p2pIeOffset != 0) && + (pMac->sch.schObject.p2pIeOffset < + psessionEntry->schBeaconOffsetBegin)) { + sch_log(pMac, LOGE, FL("Invalid p2pIeOffset:[%d]"), + pMac->sch.schObject.p2pIeOffset); + CDF_ASSERT(0); + cdf_mem_free(beaconParams); + return eSIR_FAILURE; + } + beaconParams->p2pIeOffset = pMac->sch.schObject.p2pIeOffset; +#ifdef WLAN_SOFTAP_FW_BEACON_TX_PRNT_LOG + sch_log(pMac, LOGE, FL("TimIeOffset:[%d]"), beaconParams->TimIeOffset); +#endif + + beaconParams->beacon = beaconPayload; + beaconParams->beaconLength = (uint32_t) size; + msgQ.bodyptr = beaconParams; + msgQ.bodyval = 0; + + /* Keep a copy of recent beacon frame sent */ + + /* free previous copy of the beacon */ + if (psessionEntry->beacon) { + cdf_mem_free(psessionEntry->beacon); + } + + psessionEntry->bcnLen = 0; + psessionEntry->beacon = NULL; + + psessionEntry->beacon = cdf_mem_malloc(size); + if (psessionEntry->beacon != NULL) { + cdf_mem_copy(psessionEntry->beacon, beaconPayload, size); + psessionEntry->bcnLen = size; + } + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) { + sch_log(pMac, LOGE, + FL("Posting SEND_BEACON_REQ to HAL failed, reason=%X"), + retCode); + } else { + sch_log(pMac, LOG2, + FL("Successfully posted WMA_SEND_BEACON_REQ to HAL")); + + if (LIM_IS_AP_ROLE(psessionEntry) && + (pMac->sch.schObject.fBeaconChanged)) { + if (eSIR_SUCCESS != + (retCode = + lim_send_probe_rsp_template_to_hal(pMac, psessionEntry, + &psessionEntry-> + DefProbeRspIeBitmap + [0]))) { + /* check whether we have to free any memory */ + sch_log(pMac, LOGE, + FL + ("FAILED to send probe response template with retCode %d"), + retCode); + } + } + } + + return retCode; +} + +uint32_t lim_remove_p2p_ie_from_add_ie(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t *addIeWoP2pIe, + uint32_t *addnIELenWoP2pIe) +{ + uint32_t left = psessionEntry->addIeParams.probeRespDataLen; + uint8_t *ptr = psessionEntry->addIeParams.probeRespData_buff; + uint8_t elem_id,elem_len; + uint32_t offset = 0; + uint8_t eid = 0xDD; + + cdf_mem_copy(addIeWoP2pIe, ptr, left); + *addnIELenWoP2pIe = left; + + if (addIeWoP2pIe != NULL) { + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if(elem_len > left) { + sch_log(pMac, LOGE, FL("Invalid IEs")); + return eSIR_FAILURE; + } + if ((elem_id == eid) && + (cdf_mem_compare(&ptr[2], + "\x50\x6f\x9a\x09", 4))) { + left -= elem_len; + ptr += (elem_len + 2); + cdf_mem_copy(&addIeWoP2pIe[offset], ptr, left); + *addnIELenWoP2pIe -= (2 + elem_len); + } else { + left -= elem_len; + ptr += (elem_len + 2); + offset += 2 + elem_len; + } + } + } + return eSIR_SUCCESS; +} + +uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t *IeBitmap) +{ + tSirMsgQ msgQ; + uint8_t *pFrame2Hal = psessionEntry->pSchProbeRspTemplate; + tpSendProbeRespParams pprobeRespParams = NULL; + uint32_t retCode = eSIR_FAILURE; + uint32_t nPayload, nBytes, nStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t addnIEPresent = false; + uint32_t addnIELen = 0; + uint8_t *addIE = NULL; + uint8_t *addIeWoP2pIe = NULL; + uint32_t addnIELenWoP2pIe = 0; + uint32_t retStatus; + + nStatus = + dot11f_get_packed_probe_response_size(pMac, + &psessionEntry->probeRespFrame, + &nPayload); + if (DOT11F_FAILED(nStatus)) { + sch_log(pMac, LOGE, FL("Failed to calculate the packed size f" + "or a Probe Response (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(nStatus)) { + sch_log(pMac, LOGE, FL("There were warnings while calculating" + "the packed size for a Probe Response " + "(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + /* Check if probe response IE is present or not */ + addnIEPresent = (psessionEntry->addIeParams.probeRespDataLen != 0); + if (addnIEPresent) { + /* + * probe response template should not have P2P IE. + * In case probe request has P2P IE or WPS IE, the + * probe request will be forwarded to the Host and + * Host will send the probe response. In other cases + * FW will send the probe response. So, if the template + * has P2P IE, the probe response sent to non P2P devices + * by the FW, may also have P2P IE which will fail + * P2P cert case 6.1.3 + */ + addIeWoP2pIe = cdf_mem_malloc(psessionEntry->addIeParams. + probeRespDataLen); + if (NULL == addIeWoP2pIe) { + sch_log(pMac, LOGE, + FL("FAILED to alloc memory when removing P2P IE")); + return eSIR_MEM_ALLOC_FAILED; + } + + retStatus = lim_remove_p2p_ie_from_add_ie(pMac, psessionEntry, + addIeWoP2pIe, &addnIELenWoP2pIe); + if (retStatus != eSIR_SUCCESS) { + cdf_mem_free(addIeWoP2pIe); + return eSIR_FAILURE; + } + + /* Probe rsp IE available */ + /*need to check the data length */ + addIE = + cdf_mem_malloc(addnIELenWoP2pIe); + if (NULL == addIE) { + sch_log(pMac, LOGE, + FL + ("Unable to get WNI_CFG_PROBE_RSP_ADDNIE_DATA1 length")); + cdf_mem_free(addIeWoP2pIe); + return eSIR_MEM_ALLOC_FAILED; + } + addnIELen = addnIELenWoP2pIe; + + if (addnIELen <= WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN && addnIELen + && (nBytes + addnIELen) <= SIR_MAX_PACKET_SIZE) { + + cdf_mem_copy(addIE, + addIeWoP2pIe, + addnIELenWoP2pIe); + } + cdf_mem_free(addIeWoP2pIe); + } + + if (addnIEPresent) { + if ((nBytes + addnIELen) <= SIR_MAX_PACKET_SIZE) + nBytes += addnIELen; + else + addnIEPresent = false; /* Dont include the IE. */ + } + /* Paranoia: */ + cdf_mem_set(pFrame2Hal, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame2Hal, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, + psessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + + pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* That done, pack the Probe Response: */ + nStatus = + dot11f_pack_probe_response(pMac, &psessionEntry->probeRespFrame, + pFrame2Hal + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + sch_log(pMac, LOGE, + FL("Failed to pack a Probe Response (0x%08x)."), + nStatus); + + cdf_mem_free(addIE); + return retCode; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + sch_log(pMac, LOGE, FL("There were warnings while packing a P" + "robe Response (0x%08x)."), nStatus); + } + + if (addnIEPresent) { + cdf_mem_copy(&pFrame2Hal[nBytes - addnIELen], + &addIE[0], addnIELen); + } + + /* free the allocated Memory */ + cdf_mem_free(addIE); + + pprobeRespParams = cdf_mem_malloc(sizeof(tSendProbeRespParams)); + if (NULL == pprobeRespParams) { + sch_log(pMac, LOGE, + FL + ("lim_send_probe_rsp_template_to_hal: HAL probe response params malloc failed for bytes %d"), + nBytes); + } else { + sir_copy_mac_addr(pprobeRespParams->bssId, psessionEntry->bssId); + pprobeRespParams->pProbeRespTemplate = pFrame2Hal; + pprobeRespParams->probeRespTemplateLen = nBytes; + cdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap, + IeBitmap, (sizeof(uint32_t) * 8)); + msgQ.type = WMA_SEND_PROBE_RSP_TMPL; + msgQ.reserved = 0; + msgQ.bodyptr = pprobeRespParams; + msgQ.bodyval = 0; + + if (eSIR_SUCCESS != (retCode = wma_post_ctrl_msg(pMac, &msgQ))) { + /* free the allocated Memory */ + sch_log(pMac, LOGE, + FL + ("lim_send_probe_rsp_template_to_hal: FAIL bytes %d retcode[%X]"), + nBytes, retCode); + cdf_mem_free(pprobeRespParams); + } else { + sch_log(pMac, LOG1, + FL + ("lim_send_probe_rsp_template_to_hal: Probe response template msg posted to HAL of bytes %d"), + nBytes); + } + } + + return retCode; +} + +/** + * sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer + * @pMac: the global MAC context + * @self_addr: the self MAC address + * @buf: the buffer that will contain the frame + * @timestamp_offset: return for the offset of the timestamp field + * @time_value_offset: return for the time_value field in the TA IE + * + * Return: the length of the buffer. + */ +int sch_gen_timing_advert_frame(tpAniSirGlobal mac_ctx, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset) +{ + tDot11fTimingAdvertisementFrame frame; + uint32_t payload_size, buf_size; + int status; + struct cdf_mac_addr wildcard_bssid = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; + + cdf_mem_zero((uint8_t *)&frame, sizeof(tDot11fTimingAdvertisementFrame)); + + /* Populate the TA fields */ + status = populate_dot11f_timing_advert_frame(mac_ctx, &frame); + if (status) { + sch_log(mac_ctx, LOGE, FL("Error populating TA frame %x"), + status); + return status; + } + + status = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, + &frame, &payload_size); + if (DOT11F_FAILED(status)) { + sch_log(mac_ctx, LOGE, FL("Error getting packed frame size %x"), + status); + return status; + } else if (DOT11F_WARNED(status)) { + sch_log(mac_ctx, LOGW, FL("Warning getting packed frame size")); + } + + buf_size = sizeof(tSirMacMgmtHdr) + payload_size; + *buf = cdf_mem_malloc(buf_size); + if (*buf == NULL) { + sch_log(mac_ctx, LOGE, FL("Cannot allocate memory")); + return eSIR_FAILURE; + } + cdf_mem_zero(*buf, buf_size); + + payload_size = 0; + status = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, + *buf + sizeof(tSirMacMgmtHdr), buf_size - + sizeof(tSirMacMgmtHdr), &payload_size); + sch_log(mac_ctx, LOGE, FL("TA payload size2 = %d"), payload_size); + if (DOT11F_FAILED(status)) { + sch_log(mac_ctx, LOGE, FL("Error packing frame %x"), status); + goto fail; + } else if (DOT11F_WARNED(status)) { + sch_log(mac_ctx, LOGE, FL("Warning packing frame")); + } + + lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr); + + /* The timestamp field is right after the header */ + *timestamp_offset = sizeof(tSirMacMgmtHdr); + + *time_value_offset = sizeof(tSirMacMgmtHdr) + + sizeof(tDot11fFfTimeStamp) + sizeof(tDot11fFfCapabilities); + + /* Add the Country IE length */ + dot11f_get_packed_ie_country(mac_ctx, &frame.Country, + time_value_offset); + /* Add 2 for Country IE EID and Length fields */ + *time_value_offset += 2; + + /* Add the PowerConstraint IE size */ + if (frame.Country.present == 1) + *time_value_offset += 3; + + /* Add the offset inside TA IE */ + *time_value_offset += 3; + + return payload_size + sizeof(tSirMacMgmtHdr); + +fail: + if (*buf) + cdf_mem_free(*buf); + return status; +} diff --git a/core/mac/src/pe/sch/sch_beacon_gen.c b/core/mac/src/pe/sch/sch_beacon_gen.c new file mode 100644 index 0000000000..365b3492fa --- /dev/null +++ b/core/mac/src/pe/sch/sch_beacon_gen.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sch_beacon_gen.cc contains beacon generation related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" + +#include "lim_utils.h" +#include "lim_api.h" + +#include "wma_if.h" +#include "cfg_api.h" +#include "sch_api.h" + +#include "parser_api.h" + +#include "sch_debug.h" + +/* */ +/* March 15, 2006 */ +/* Temporarily (maybe for all of Alpha-1), assuming TIM = 0 */ +/* */ + +const uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x9 }; + +tSirRetStatus sch_get_p2p_ie_offset(uint8_t *pExtraIe, uint32_t extraIeLen, + uint16_t *pP2pIeOffset) +{ + tSirRetStatus status = eSIR_FAILURE; + *pP2pIeOffset = 0; + + /* Extra IE is not present */ + if (0 == extraIeLen) { + return status; + } + /* Calculate the P2P IE Offset */ + do { + if (*pExtraIe == 0xDD) { + if (cdf_mem_compare + ((void *)(pExtraIe + 2), &p2p_oui, sizeof(p2p_oui))) { + status = eSIR_SUCCESS; + break; + } + } + + (*pP2pIeOffset)++; + pExtraIe++; + } while (--extraIeLen > 0); + + return status; +} + +/** + * sch_append_addn_ie() - adds additional IEs to frame + * @mac_ctx: mac global context + * @session: pe session pointer + * @frm: frame where additional IE is to be added + * @max_bcn_size: max beacon size + * @num_bytes: final size + * + * Return: status of operation + */ +tSirRetStatus +sch_append_addn_ie(tpAniSirGlobal mac_ctx, tpPESession session, + uint8_t *frm, uint32_t max_bcn_size, uint32_t *num_bytes) +{ + tSirRetStatus status = eSIR_FAILURE; + uint32_t present, len; + uint8_t add_ie[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN]; + uint8_t *p2p_ie = NULL; + uint8_t noa_len = 0; + uint8_t noa_strm[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + + present = (session->addIeParams.probeRespBCNDataLen != 0); + if (!present) + return status; + + len = session->addIeParams.probeRespBCNDataLen; + if (!(len <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && len && + ((len + *num_bytes) <= max_bcn_size))) + return status; + + cdf_mem_copy(&add_ie[0], session->addIeParams.probeRespBCNData_buff, + len); + + p2p_ie = limGetP2pIEPtr(mac_ctx, &add_ie[0], len); + if ((p2p_ie != NULL) && !mac_ctx->beacon_offload) { + /* get NoA attribute stream P2P IE */ + noa_len = lim_get_noa_attr_stream(mac_ctx, noa_strm, session); + if (noa_len) { + if ((noa_len + len) <= + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + cdf_mem_copy(&add_ie[len], noa_strm, noa_len); + len += noa_len; + p2p_ie[1] += noa_len; + } else { + sch_log(mac_ctx, LOGE, + FL("Not able to insert NoA because of length constraint")); + } + } + } + if (len <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + cdf_mem_copy(frm, &add_ie[0], len); + *num_bytes = *num_bytes + len; + } else { + sch_log(mac_ctx, LOGW, + FL("Not able to insert because of len constraint %d"), + len); + } + return status; +} + +/** + * sch_set_fixed_beacon_fields() - sets the fixed params in beacon frame + * @mac_ctx: mac global context + * @session: pe session entry + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * Return: status of operation + */ + +tSirRetStatus +sch_set_fixed_beacon_fields(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tpAniBeaconStruct bcn_struct = (tpAniBeaconStruct) + session->pSchBeaconFrameBegin; + tpSirMacMgmtHdr mac; + uint16_t offset; + uint8_t *ptr; + tDot11fBeacon1 *bcn_1; + tDot11fBeacon2 *bcn_2; + uint32_t i, n_status, n_bytes; + uint32_t wps_ap_enable = 0, tmp; + tDot11fIEWscProbeRes *wsc_prb_res; + uint8_t *extra_ie = NULL; + uint32_t extra_ie_len = 0; + uint16_t extra_ie_offset = 0; + uint16_t p2p_ie_offset = 0; + tSirRetStatus status = eSIR_SUCCESS; + bool is_vht_enabled = false; + + bcn_1 = cdf_mem_malloc(sizeof(tDot11fBeacon1)); + if (NULL == bcn_1) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + bcn_2 = cdf_mem_malloc(sizeof(tDot11fBeacon2)); + if (NULL == bcn_2) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + cdf_mem_free(bcn_1); + return eSIR_MEM_ALLOC_FAILED; + } + + wsc_prb_res = cdf_mem_malloc(sizeof(tDot11fIEWscProbeRes)); + if (NULL == wsc_prb_res) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + cdf_mem_free(bcn_1); + cdf_mem_free(bcn_2); + return eSIR_MEM_ALLOC_FAILED; + } + + sch_log(mac_ctx, LOG1, FL("Setting fixed beacon fields")); + + /* + * First set the fixed fields: + * set the TFP headers, set the mac header + */ + cdf_mem_set((uint8_t *) &bcn_struct->macHdr, sizeof(tSirMacMgmtHdr), 0); + mac = (tpSirMacMgmtHdr) &bcn_struct->macHdr; + mac->fc.type = SIR_MAC_MGMT_FRAME; + mac->fc.subType = SIR_MAC_MGMT_BEACON; + + for (i = 0; i < 6; i++) + mac->da[i] = 0xff; + + cdf_mem_copy(mac->sa, session->selfMacAddr, + sizeof(session->selfMacAddr)); + cdf_mem_copy(mac->bssId, session->bssId, sizeof(session->bssId)); + + mac->fc.fromDS = 0; + mac->fc.toDS = 0; + + /* Now set the beacon body */ + cdf_mem_set((uint8_t *) bcn_1, sizeof(tDot11fBeacon1), 0); + + /* Skip over the timestamp (it'll be updated later). */ + bcn_1->BeaconInterval.interval = + mac_ctx->sch.schObject.gSchBeaconInterval; + populate_dot11f_capabilities(mac_ctx, &bcn_1->Capabilities, session); + if (session->ssidHidden) { + bcn_1->SSID.present = 1; + /* rest of the fileds are 0 for hidden ssid */ + if ((session->ssId.length) && + (session->ssidHidden == eHIDDEN_SSID_ZERO_CONTENTS)) + bcn_1->SSID.num_ssid = session->ssId.length; + } else { + populate_dot11f_ssid(mac_ctx, &session->ssId, &bcn_1->SSID); + } + + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_1->SuppRates, session); + populate_dot11f_ds_params(mac_ctx, &bcn_1->DSParams, + session->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &bcn_1->IBSSParams, session); + + offset = sizeof(tAniBeaconStruct); + ptr = session->pSchBeaconFrameBegin + offset; + + if (LIM_IS_AP_ROLE(session)) { + /* Initialize the default IE bitmap to zero */ + cdf_mem_set((uint8_t *) &(session->DefProbeRspIeBitmap), + (sizeof(uint32_t) * 8), 0); + + /* Initialize the default IE bitmap to zero */ + cdf_mem_set((uint8_t *) &(session->probeRespFrame), + sizeof(session->probeRespFrame), 0); + + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + if (lim_update_probe_rsp_template_ie_bitmap_beacon1(mac_ctx, + bcn_1, session) != eSIR_SUCCESS) + sch_log(mac_ctx, LOGE, + FL("Failed to build ProbeRsp template")); + } + + n_status = dot11f_pack_beacon1(mac_ctx, bcn_1, ptr, + SCH_MAX_BEACON_SIZE - offset, &n_bytes); + if (DOT11F_FAILED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Failed to packed a tDot11fBeacon1 (0x%08x.)."), + n_status); + cdf_mem_free(bcn_1); + cdf_mem_free(bcn_2); + cdf_mem_free(wsc_prb_res); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Warnings while packing a tDot11fBeacon1(0x%08x.)."), + n_status); + } + /*changed to correct beacon corruption */ + cdf_mem_set((uint8_t *) bcn_2, sizeof(tDot11fBeacon2), 0); + session->schBeaconOffsetBegin = offset + (uint16_t) n_bytes; + sch_log(mac_ctx, LOG1, FL("Initialized beacon begin, offset %d"), + offset); + + /* Initialize the 'new' fields at the end of the beacon */ + + if ((session->limSystemRole == eLIM_AP_ROLE) && + session->dfsIncludeChanSwIe == true) + populate_dot_11_f_ext_chann_switch_ann(mac_ctx, + &bcn_2->ext_chan_switch_ann, + session); + + populate_dot11f_country(mac_ctx, &bcn_2->Country, session); + if (bcn_1->Capabilities.qos) + populate_dot11f_edca_param_set(mac_ctx, &bcn_2->EDCAParamSet, + session); + + if (session->lim11hEnable) { + populate_dot11f_power_constraints(mac_ctx, + &bcn_2->PowerConstraints); + populate_dot11f_tpc_report(mac_ctx, &bcn_2->TPCReport, session); + /* Need to insert channel switch announcement here */ + if ((LIM_IS_AP_ROLE(session) + || LIM_IS_P2P_DEVICE_GO(session)) + && session->dfsIncludeChanSwIe == true) { + /* + * Channel switch announcement only if radar is detected + * and SAP has instructed to announce channel switch IEs + * in beacon and probe responses + */ + populate_dot11f_chan_switch_ann(mac_ctx, + &bcn_2->ChanSwitchAnn, session); + + /* + * TODO: depending the CB mode, extended channel switch + * announcement need to be called + */ + /* + populate_dot11f_ext_chan_switch_ann(mac_ctx, + &bcn_2->ExtChanSwitchAnn, session); + */ +#ifdef WLAN_FEATURE_11AC + /* + * TODO: If in 11AC mode, wider bw channel switch + * announcement needs to be called + */ + /* + populate_dot11f_wider_bw_chan_switch_ann(mac_ctx, + &bcn_2->WiderBWChanSwitchAnn, session); + */ +#endif + /* + * Populate the Channel Switch Wrapper Element if + * SAP operates in 40/80 Mhz Channel Width. + */ + if (true == session->dfsIncludeChanWrapperIe) + populate_dot11f_chan_switch_wrapper(mac_ctx, + &bcn_2->ChannelSwitchWrapper, session); + } + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* populate proprietary IE for MDM device operating in AP-MCC */ + populate_dot11f_avoid_channel_ie(mac_ctx, &bcn_2->QComVendorIE, + session); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (session->dot11mode != WNI_CFG_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &bcn_2->ERPInfo, session); + + if (session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, session, &bcn_2->HTCaps); + populate_dot11f_ht_info(mac_ctx, &bcn_2->HTInfo, session); + } +#ifdef WLAN_FEATURE_11AC + if (session->vhtCapability) { + sch_log(mac_ctx, LOGW, FL("Populate VHT IEs in Beacon")); + populate_dot11f_vht_caps(mac_ctx, session, &bcn_2->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, session, + &bcn_2->VHTOperation); + is_vht_enabled = true; + /* following is for MU MIMO: we do not support it yet */ + /* + populate_dot11f_vht_ext_bss_load( mac_ctx, &bcn2.VHTExtBssLoad); + */ + if (session->gLimOperatingMode.present) + populate_dot11f_operating_mode(mac_ctx, + &bcn_2->OperatingMode, session); + } +#endif + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &bcn_2->ExtCap, + session); + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_2->ExtSuppRates, session); + + if (session->pLimStartBssReq != NULL) { + populate_dot11f_wpa(mac_ctx, &session->pLimStartBssReq->rsnIE, + &bcn_2->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &session->pLimStartBssReq->rsnIE, + &bcn_2->RSNOpaque); + } + + if (session->limWmeEnabled) + populate_dot11f_wmm(mac_ctx, &bcn_2->WMMInfoAp, + &bcn_2->WMMParams, &bcn_2->WMMCaps, session); + if (LIM_IS_AP_ROLE(session)) { + if (session->wps_state != SAP_WPS_DISABLED) { + populate_dot11f_beacon_wpsi_es(mac_ctx, + &bcn_2->WscBeacon, session); + } + } else { + if (wlan_cfg_get_int(mac_ctx, + (uint16_t) WNI_CFG_WPS_ENABLE, &tmp) != eSIR_SUCCESS) + sch_log(mac_ctx, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_ENABLE); + + wps_ap_enable = tmp & WNI_CFG_WPS_ENABLE_AP; + + if (wps_ap_enable) + populate_dot11f_wsc(mac_ctx, &bcn_2->WscBeacon); + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + if ((LIM_IS_AP_ROLE(session))) { + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + lim_update_probe_rsp_template_ie_bitmap_beacon2(mac_ctx, bcn_2, + &session->DefProbeRspIeBitmap[0], + &session->probeRespFrame); + + /* update probe response WPS IE instead of beacon WPS IE */ + if (session->wps_state != SAP_WPS_DISABLED) { + if (session->APWPSIEs.SirWPSProbeRspIE.FieldPresent) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + wsc_prb_res, session); + else + wsc_prb_res->present = 0; + if (wsc_prb_res->present) { + set_probe_rsp_ie_bitmap( + &session->DefProbeRspIeBitmap[0], + SIR_MAC_WPA_EID); + cdf_mem_copy((void *) + &session->probeRespFrame.WscProbeRes, + (void *)wsc_prb_res, + sizeof(tDot11fIEWscProbeRes)); + } + } + + } + + n_status = dot11f_pack_beacon2(mac_ctx, bcn_2, + session->pSchBeaconFrameEnd, + SCH_MAX_BEACON_SIZE, &n_bytes); + if (DOT11F_FAILED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Failed to packed a tDot11fBeacon2 (0x%08x.)."), + n_status); + cdf_mem_free(bcn_1); + cdf_mem_free(bcn_2); + cdf_mem_free(wsc_prb_res); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Warnings while packing a tDot11fBeacon2(0x%08x.)."), + n_status); + } + + extra_ie = session->pSchBeaconFrameEnd + n_bytes; + extra_ie_offset = n_bytes; + /* TODO: Append additional IE here. */ + sch_append_addn_ie(mac_ctx, session, + session->pSchBeaconFrameEnd + n_bytes, + SCH_MAX_BEACON_SIZE, &n_bytes); + session->schBeaconOffsetEnd = (uint16_t) n_bytes; + extra_ie_len = n_bytes - extra_ie_offset; + /* Get the p2p Ie Offset */ + status = sch_get_p2p_ie_offset(extra_ie, extra_ie_len, &p2p_ie_offset); + if (eSIR_SUCCESS == status) + /* Update the P2P Ie Offset */ + mac_ctx->sch.schObject.p2pIeOffset = + session->schBeaconOffsetBegin + TIM_IE_SIZE + + extra_ie_offset + p2p_ie_offset; + else + mac_ctx->sch.schObject.p2pIeOffset = 0; + + sch_log(mac_ctx, LOG1, FL("Initialized beacon end, offset %d"), + session->schBeaconOffsetEnd); + mac_ctx->sch.schObject.fBeaconChanged = 1; + cdf_mem_free(bcn_1); + cdf_mem_free(bcn_2); + cdf_mem_free(wsc_prb_res); + return eSIR_SUCCESS; +} + +tSirRetStatus lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal pMac, + tDot11fBeacon1 *beacon1, + tpPESession + psessionEntry) +{ + uint32_t *DefProbeRspIeBitmap; + tDot11fProbeResponse *prb_rsp; + if (!psessionEntry) { + sch_log(pMac, LOGE, FL("PESession is null!")); + return eSIR_FAILURE; + } + DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0]; + prb_rsp = &psessionEntry->probeRespFrame; + prb_rsp->BeaconInterval = beacon1->BeaconInterval; + cdf_mem_copy((void *)&prb_rsp->Capabilities, + (void *)&beacon1->Capabilities, + sizeof(beacon1->Capabilities)); + + /* SSID */ + if (beacon1->SSID.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_SSID_EID); + /* populating it, because probe response has to go with SSID even in hidden case */ + populate_dot11f_ssid(pMac, &psessionEntry->ssId, &prb_rsp->SSID); + } + /* supported rates */ + if (beacon1->SuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RATESET_EID); + cdf_mem_copy((void *)&prb_rsp->SuppRates, + (void *)&beacon1->SuppRates, + sizeof(beacon1->SuppRates)); + + } + /* DS Parameter set */ + if (beacon1->DSParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_DS_PARAM_SET_EID); + cdf_mem_copy((void *)&prb_rsp->DSParams, + (void *)&beacon1->DSParams, + sizeof(beacon1->DSParams)); + + } + + /* IBSS params will not be present in the Beacons transmitted by AP */ + return eSIR_SUCCESS; +} + +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal pMac, + tDot11fBeacon2 *beacon2, + uint32_t *DefProbeRspIeBitmap, + tDot11fProbeResponse *prb_rsp) +{ + /* IBSS parameter set - will not be present in probe response tx by AP */ + /* country */ + if (beacon2->Country.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_COUNTRY_EID); + cdf_mem_copy((void *)&prb_rsp->Country, + (void *)&beacon2->Country, + sizeof(beacon2->Country)); + + } + /* Power constraint */ + if (beacon2->PowerConstraints.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_PWR_CONSTRAINT_EID); + cdf_mem_copy((void *)&prb_rsp->PowerConstraints, + (void *)&beacon2->PowerConstraints, + sizeof(beacon2->PowerConstraints)); + + } + /* Channel Switch Annoouncement SIR_MAC_CHNL_SWITCH_ANN_EID */ + if (beacon2->ChanSwitchAnn.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_CHNL_SWITCH_ANN_EID); + cdf_mem_copy((void *)&prb_rsp->ChanSwitchAnn, + (void *)&beacon2->ChanSwitchAnn, + sizeof(beacon2->ChanSwitchAnn)); + + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (beacon2->QComVendorIE.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_QCOM_VENDOR_EID); + cdf_mem_copy((void *)&prb_rsp->QComVendorIE, + (void *)&beacon2->QComVendorIE, + sizeof(beacon2->QComVendorIE)); + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + /* ERP information */ + if (beacon2->ERPInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_ERP_INFO_EID); + cdf_mem_copy((void *)&prb_rsp->ERPInfo, + (void *)&beacon2->ERPInfo, + sizeof(beacon2->ERPInfo)); + + } + /* Extended supported rates */ + if (beacon2->ExtSuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_EXTENDED_RATE_EID); + cdf_mem_copy((void *)&prb_rsp->ExtSuppRates, + (void *)&beacon2->ExtSuppRates, + sizeof(beacon2->ExtSuppRates)); + + } + + /* WPA */ + if (beacon2->WPA.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + cdf_mem_copy((void *)&prb_rsp->WPA, (void *)&beacon2->WPA, + sizeof(beacon2->WPA)); + + } + + /* RSN */ + if (beacon2->RSNOpaque.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RSN_EID); + cdf_mem_copy((void *)&prb_rsp->RSNOpaque, + (void *)&beacon2->RSNOpaque, + sizeof(beacon2->RSNOpaque)); + } + + /* EDCA Parameter set */ + if (beacon2->EDCAParamSet.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_EDCA_PARAM_SET_EID); + cdf_mem_copy((void *)&prb_rsp->EDCAParamSet, + (void *)&beacon2->EDCAParamSet, + sizeof(beacon2->EDCAParamSet)); + + } + /* Vendor specific - currently no vendor specific IEs added */ + /* Requested IEs - currently we are not processing this will be added later */ + /* HT capability IE */ + if (beacon2->HTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_HT_CAPABILITIES_EID); + cdf_mem_copy((void *)&prb_rsp->HTCaps, (void *)&beacon2->HTCaps, + sizeof(beacon2->HTCaps)); + } + /* HT Info IE */ + if (beacon2->HTInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_HT_INFO_EID); + cdf_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo, + sizeof(beacon2->HTInfo)); + } +#ifdef WLAN_FEATURE_11AC + if (beacon2->VHTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_CAPABILITIES_EID); + cdf_mem_copy((void *)&prb_rsp->VHTCaps, + (void *)&beacon2->VHTCaps, + sizeof(beacon2->VHTCaps)); + } + if (beacon2->VHTOperation.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_OPERATION_EID); + cdf_mem_copy((void *)&prb_rsp->VHTOperation, + (void *)&beacon2->VHTOperation, + sizeof(beacon2->VHTOperation)); + } + if (beacon2->VHTExtBssLoad.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_EXT_BSS_LOAD_EID); + cdf_mem_copy((void *)&prb_rsp->VHTExtBssLoad, + (void *)&beacon2->VHTExtBssLoad, + sizeof(beacon2->VHTExtBssLoad)); + } +#endif + + /* WMM IE */ + if (beacon2->WMMParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + cdf_mem_copy((void *)&prb_rsp->WMMParams, + (void *)&beacon2->WMMParams, + sizeof(beacon2->WMMParams)); + } + /* WMM capability - most of the case won't be present */ + if (beacon2->WMMCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + cdf_mem_copy((void *)&prb_rsp->WMMCaps, + (void *)&beacon2->WMMCaps, + sizeof(beacon2->WMMCaps)); + } + + /* Extended Capability */ + if (beacon2->ExtCap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, DOT11F_EID_EXTCAP); + cdf_mem_copy((void *)&prb_rsp->ExtCap, + (void *)&beacon2->ExtCap, + sizeof(beacon2->ExtCap)); + } + +} + +void set_probe_rsp_ie_bitmap(uint32_t *IeBitmap, uint32_t pos) +{ + uint32_t index, temp; + + index = pos >> 5; + if (index >= 8) { + return; + } + temp = IeBitmap[index]; + + temp |= 1 << (pos & 0x1F); + + IeBitmap[index] = temp; +} + +/* -------------------------------------------------------------------- */ +/** + * write_beacon_to_memory + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @param size Size of the beacon to write to memory + * @param length Length field of the beacon to write to memory + * @return None + */ + +void write_beacon_to_memory(tpAniSirGlobal pMac, uint16_t size, uint16_t length, + tpPESession psessionEntry) +{ + uint16_t i; + tpAniBeaconStruct pBeacon; + + /* copy end of beacon only if length > 0 */ + if (length > 0) { + for (i = 0; i < psessionEntry->schBeaconOffsetEnd; i++) + psessionEntry->pSchBeaconFrameBegin[size++] = + psessionEntry->pSchBeaconFrameEnd[i]; + } + /* Update the beacon length */ + pBeacon = (tpAniBeaconStruct) psessionEntry->pSchBeaconFrameBegin; + /* Do not include the beaconLength indicator itself */ + if (length == 0) { + pBeacon->beaconLength = 0; + /* Dont copy entire beacon, Copy length field alone */ + size = 4; + } else + pBeacon->beaconLength = (uint32_t) size - sizeof(uint32_t); + + /* write size bytes from pSchBeaconFrameBegin */ + PELOG2(sch_log(pMac, LOG2, FL("Beacon size - %d bytes"), size);) + PELOG2(sir_dump_buf + (pMac, SIR_SCH_MODULE_ID, LOG2, + psessionEntry->pSchBeaconFrameBegin, size); + ) + + if (!pMac->sch.schObject.fBeaconChanged) + return; + + pMac->sch.gSchGenBeacon = 1; + if (pMac->sch.gSchGenBeacon) { + pMac->sch.gSchBeaconsSent++; + + /* */ + /* Copy beacon data to SoftMAC shared memory... */ + /* Do this by sending a message to HAL */ + /* */ + + size = (size + 3) & (~3); + if (eSIR_SUCCESS != + sch_send_beacon_req(pMac, psessionEntry->pSchBeaconFrameBegin, + size, psessionEntry)) + PELOGE(sch_log + (pMac, LOGE, + FL + ("sch_send_beacon_req() returned an error (zsize %d)"), + size); + ) + else { + pMac->sch.gSchBeaconsWritten++; + } + } + pMac->sch.schObject.fBeaconChanged = 0; +} + +/** + * sch_generate_tim + * + * FUNCTION: + * Generate TIM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac pointer to global mac structure + * @param **pPtr pointer to the buffer, where the TIM bit is to be written. + * @param *timLength pointer to limLength, which needs to be returned. + * @return None + */ +void sch_generate_tim(tpAniSirGlobal pMac, uint8_t **pPtr, uint16_t *timLength, + uint8_t dtimPeriod) +{ + uint8_t *ptr = *pPtr; + uint32_t val = 0; + uint32_t minAid = 1; /* Always start with AID 1 as minimum */ + uint32_t maxAid = HAL_NUM_STA; + + /* Generate partial virtual bitmap */ + uint8_t N1 = minAid / 8; + uint8_t N2 = maxAid / 8; + if (N1 & 1) + N1--; + + *timLength = N2 - N1 + 4; + val = dtimPeriod; + + /* + * Write 0xFF to firmware's field to detect firmware's mal-function + * early. DTIM count and bitmap control usually cannot be 0xFF, so it + * is easy to know that firmware never updated DTIM count/bitmap control + * field after host driver downloaded beacon template if end-user complaints + * that DTIM count and bitmapControl is 0xFF. + */ + *ptr++ = SIR_MAC_TIM_EID; + *ptr++ = (uint8_t) (*timLength); + /* location for dtimCount. will be filled in by FW. */ + *ptr++ = 0xFF; + *ptr++ = (uint8_t) val; + /* location for bitmap control. will be filled in by FW. */ + *ptr++ = 0xFF; + ptr += (N2 - N1 + 1); + + PELOG2(sir_dump_buf + (pMac, SIR_SCH_MODULE_ID, LOG2, *pPtr, (*timLength) + 2); + ) + * pPtr = ptr; +} +/* -------------------------------------------------------------------- */ +/** + * @function: SchProcessPreBeaconInd + * + * @brief : Process the PreBeacon Indication from the Lim + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param : pMac - tpAniSirGlobal + * + * @return None + */ + +void sch_process_pre_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpBeaconGenParams pMsg = (tpBeaconGenParams) limMsg->bodyptr; + uint32_t beaconSize; + tpPESession psessionEntry; + uint8_t sessionId; + + if ((psessionEntry = + pe_find_session_by_bssid(pMac, pMsg->bssId, &sessionId)) == NULL) { + PELOGE(sch_log(pMac, LOGE, FL("session lookup fails"));) + goto end; + } + + beaconSize = psessionEntry->schBeaconOffsetBegin; + + /* If SME is not in normal mode, no need to generate beacon */ + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) { + PELOGE(sch_log + (pMac, LOG1, + FL("PreBeaconInd received in invalid state: %d"), + psessionEntry->limSmeState); + ) + goto end; + } + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + + case eLIM_STA_IN_IBSS_ROLE: + case eLIM_BT_AMP_AP_ROLE: + case eLIM_BT_AMP_STA_ROLE: + /* generate IBSS parameter set */ + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry); + else + PELOGE(sch_log + (pMac, LOGE, + FL + ("can not send beacon for PEER session entry")); + ) + break; + + case eLIM_AP_ROLE: { + uint8_t *ptr = + &psessionEntry->pSchBeaconFrameBegin[psessionEntry-> + schBeaconOffsetBegin]; + uint16_t timLength = 0; + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + sch_generate_tim(pMac, &ptr, &timLength, + psessionEntry->dtimPeriod); + beaconSize += 2 + timLength; + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry); + } else + PELOGE(sch_log + (pMac, LOGE, + FL + ("can not send beacon for PEER session entry")); + ) + } + break; + + default: + PELOGE(sch_log + (pMac, LOGE, + FL + ("Error-PE has Receive PreBeconGenIndication when System is in %d role"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + ) + } + +end: + cdf_mem_free(pMsg); + + } diff --git a/core/mac/src/pe/sch/sch_beacon_process.c b/core/mac/src/pe/sch/sch_beacon_process.c new file mode 100644 index 0000000000..a8f2a468b9 --- /dev/null +++ b/core/mac/src/pe/sch/sch_beacon_process.c @@ -0,0 +1,1011 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sch_beacon_process.cc contains beacon processing related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" + +#include "cfg_api.h" +#include "lim_api.h" +#include "utils_api.h" +#include "sch_debug.h" +#include "sch_api.h" + +#include "lim_utils.h" +#include "lim_send_messages.h" +#include "lim_sta_hash_api.h" + +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * Number of bytes of variation in beacon length from the last beacon + * to trigger reprogramming of rx delay register + */ +#define SCH_BEACON_LEN_DELTA 3 + +/* calculate 2^cw - 1 */ +#define CW_GET(cw) (((cw) == 0) ? 1 : ((1 << (cw)) - 1)) + +static void +ap_beacon_process_5_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (!session->htCapability) + return; + + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + /* 11a (non HT) AP overlaps or */ + /* HT AP with HT op mode as mixed overlaps. */ + /* HT AP with HT op mode as overlap legacy overlaps. */ + if (!bcn_struct->HTInfo.present + || (eSIR_HT_OP_MODE_MIXED == bcn_struct->HTInfo.opMode) + || (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode)) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(mac_ctx->lim.gLimOverlap11aParams)); + + if (mac_ctx->lim.gLimOverlap11aParams.numSta + && !mac_ctx->lim.gLimOverlap11aParams.protectionEnabled) { + lim_update_11a_protection(mac_ctx, true, true, + bcn_prm, session); + } + return; + } + /* HT AP with HT20 op mode overlaps. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT != bcn_struct->HTInfo.opMode) + return; + + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(mac_ctx->lim.gLimOverlapHt20Params)); + + if (mac_ctx->lim.gLimOverlapHt20Params.numSta + && !mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); +} + +static void +ap_beacon_process_24_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + bool tmp_exp = false; + /* We are 11G AP. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + (false == session->htCapability)) { + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent + && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (!tmp_exp) + return; +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) + CDF_TRACE(CDF_MODULE_ID_PE, + CDF_TRACE_LEVEL_INFO, + FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + return; + } + /* handling the case when HT AP has overlapping legacy BSS. */ + if (!session->htCapability) + return; + + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (tmp_exp) { +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) { + CDF_TRACE(CDF_MODULE_ID_PE, CDF_TRACE_LEVEL_INFO, + FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); + } +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + } + /* 11g device overlaps */ + tmp_exp = bcn_struct->erpPresent + && !(bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent) + && !(bcn_struct->HTInfo.present); + if (tmp_exp) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + } + /* ht device overlaps. + * here we will check for HT related devices only which might need + * protection. check for 11b and 11g is already done in the previous + * blocks. so we will not check for HT operating mode as MIXED. + */ + if (!bcn_struct->HTInfo.present) + return; + + /* + * if we are not already in mixed mode or legacy mode as HT operating + * mode and received beacon has HT operating mode as legacy then we need + * to enable protection from 11g station. we don't need protection from + * 11b because if that's needed then our operating mode would have + * already been set to legacy in the previous blocks. + */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode) { + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == mac_ctx->lim.gHTOperMode + || eSIR_HT_OP_MODE_MIXED == mac_ctx->lim.gHTOperMode) + return; + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + return; + } + + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == bcn_struct->HTInfo.opMode) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlapHt20Params)); + if (session->gLimOverlapHt20Params.numSta + && !session->gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); + } +} + +/** + * ap_beacon_process() - processes incoming beacons + * + * @mac_ctx: mac global context + * @rx_pkt_info: incoming beacon packet + * @bcn_struct: beacon struct + * @bcn_prm: beacon params + * @session: pe session entry + * + * Return: void + */ +static void +ap_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session) +{ + uint32_t phy_mode; + tSirRFBand rf_band = SIR_BAND_UNKNOWN; + /* Get RF band from session */ + rf_band = session->limRFBand; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + if (SIR_BAND_5_GHZ == rf_band) + ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + else if (SIR_BAND_2_4_GHZ == rf_band) + ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + mac_ctx->sch.gSchBcnIgnored++; +} + +/* -------------------------------------------------------------------- */ + +/** + * __sch_beacon_process_no_session + * + * FUNCTION: + * Process the received beacon frame when + * -- Station is not scanning + * -- No corresponding session is found + * + * LOGIC: + * Following scenarios exist when Session Does not exist: + * * IBSS Beacons, when IBSS session already exists with same SSID, + * but from STA which has not yet joined and has a different BSSID. + * - invoke lim_handle_ibs_scoalescing with the session context of existing IBSS session. + * + * * IBSS Beacons when IBSS session does not exist, only Infra or BT-AMP session exists, + * then save the beacon in the scan results and throw it away. + * + * * Infra Beacons + * - beacons received when no session active + * should not come here, it should be handled as part of scanning, + * else they should not be getting received, should update scan results and drop it if that happens. + * - beacons received when IBSS session active: + * update scan results and drop it. + * - beacons received when Infra session(STA) is active: + * update scan results and drop it + * - beacons received when BT-STA session is active: + * update scan results and drop it. + * - beacons received when Infra/BT-STA or Infra/IBSS is active. + * update scan results and drop it. + * + + */ +static void __sch_beacon_process_no_session(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo) +{ + tpPESession psessionEntry = NULL; + + if ((psessionEntry = lim_is_ibss_session_active(pMac)) != NULL) { + lim_handle_ibss_coalescing(pMac, pBeacon, pRxPacketInfo, + psessionEntry); + } + /* If station(STA/BT-STA/BT-AP/IBSS) mode, Always save the beacon in the scan results, if atleast one session is active */ + /* sch_beacon_processNoSession will be called only when there is atleast one session active, so not checking */ + /* it again here. */ + lim_check_and_add_bss_description(pMac, pBeacon, pRxPacketInfo, false, + false); + return; +} + +/** + * get_operating_channel_width() - Get operating channel width + * @pStaDs - station entry. + * + * This function returns the oeprating channgl width based on + * the supported channel width entry. + * + * Return: tSirMacHTChannelWidth on success + */ +tSirMacHTChannelWidth get_operating_channel_width(tpDphHashNode stads) +{ + tSirMacHTChannelWidth ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + else if (stads->htSupportedChannelWidthSet) + ch_width = eHT_CHANNEL_WIDTH_40MHZ; + else + ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + return ch_width; +} + +/* + * sch_bcn_process_sta_bt_amp_sta() - Process the received beacon frame for sta, + * bt_amp_sta + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @beaconParams: update beacon params + * @sendProbeReq: out flag to indicate if probe rsp is to be sent + * @pMh: mac header + * + * Process the received beacon frame for sta, bt_amp_sta + * + * Return: success of failure of operation + */ +static bool +sch_bcn_process_sta_bt_amp_sta(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + uint32_t bi; + tpDphHashNode pStaDs = NULL; + /* + * This handles two cases: + * -- Infra STA receving beacons from AP + * -- BTAMP_STA receving beacons from BTAMP_AP + */ + /* Always save the beacon into LIM's cached scan results */ + lim_check_and_add_bss_description(mac_ctx, bcn, rx_pkt_info, + false, false); + + /** + * This is the Beacon received from the AP we're currently associated + * with. Check if there are any changes in AP's capabilities + */ + if ((uint8_t) bcn->channelNumber != session->currentOperChannel) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Channel Change from %d --> %d - Ignoring beacon!"), + session->currentOperChannel, + bcn->channelNumber);) + return false; + } + lim_detect_change_in_ap_capabilities(mac_ctx, bcn, session); + if (lim_get_sta_hash_bssidx(mac_ctx, DPH_STA_HASH_INDEX_PEER, bssIdx, + session) != eSIR_SUCCESS) + return false; + + beaconParams->bssIdx = *bssIdx; + cdf_mem_copy((uint8_t *) &session->lastBeaconTimeStamp, + (uint8_t *) bcn->timeStamp, sizeof(uint64_t)); + session->lastBeaconDtimCount = bcn->tim.dtimCount; + session->lastBeaconDtimPeriod = bcn->tim.dtimPeriod; + session->currentBssBeaconCnt++; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[0]);) + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[1]);) + + /* Read beacon interval session Entry */ + bi = session->beaconParams.beaconInterval; + if (bi != bcn->beaconInterval) { + PELOG1(sch_log(mac_ctx, LOG1, + FL("Beacon interval changed from %d to %d"), + bcn->beaconInterval, bi);) + + bi = bcn->beaconInterval; + session->beaconParams.beaconInterval = (uint16_t) bi; + beaconParams->paramChangeBitmap |= PARAM_BCN_INTERVAL_CHANGED; + beaconParams->beaconInterval = (uint16_t) bi; + } + + if (bcn->cfPresent) { + cfg_set_int(mac_ctx, WNI_CFG_CFP_PERIOD, + bcn->cfParamSet.cfpPeriod); + lim_send_cf_params(mac_ctx, *bssIdx, + bcn->cfParamSet.cfpCount, + bcn->cfParamSet.cfpPeriod); + } + + /* No need to send DTIM Period and Count to HAL/SMAC */ + /* SMAC already parses TIM bit. */ + if (bcn->timPresent) + cfg_set_int(mac_ctx, WNI_CFG_DTIM_PERIOD, bcn->tim.dtimPeriod); + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection(mac_ctx, bcn, beaconParams, session); + + if (bcn->erpPresent) { + if (bcn->erpIEInfo.barkerPreambleMode) + lim_enable_short_preamble(mac_ctx, false, + beaconParams, session); + else + lim_enable_short_preamble(mac_ctx, true, + beaconParams, session); + } + lim_update_short_slot(mac_ctx, bcn, beaconParams, session); + + pStaDs = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if ((bcn->wmeEdcaPresent && (session->limWmeEnabled)) + || (bcn->edcaPresent && (session->limQosEnabled))) { + if (bcn->edcaParams.qosInfo.count != + session->gLimEdcaParamSetCount) { + if (sch_beacon_edca_process(mac_ctx, &bcn->edcaParams, + session) != eSIR_SUCCESS) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("EDCA parameter processing error"));) + } else if (pStaDs != NULL) { + /* If needed, downgrade the EDCA parameters */ + lim_set_active_edca_params(mac_ctx, + session->gLimEdcaParams, session); + lim_send_edca_params(mac_ctx, + session->gLimEdcaParamsActive, + pStaDs->bssId); + } else { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Self Entry missing in Hash Table"));) + } + } + return true; + } + + if ((bcn->qosCapabilityPresent && session->limQosEnabled) + && (bcn->qosCapability.qosInfo.count != + session->gLimEdcaParamSetCount)) + *sendProbeReq = true; + + return true; +} + +/** + * update_nss() - Function to update NSS + * @mac_ctx: pointer to Global Mac structure + * @sta_ds: pointer to tpDphHashNode + * @beacon: pointer to tpSchBeaconStruct + * @session_entry: pointer to tpPESession + * @mgmt_hdr: pointer to tpSirMacMgmtHdr + * + * function to update NSS + * + * Return: none + */ +void update_nss(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpSchBeaconStruct beacon, tpPESession session_entry, + tpSirMacMgmtHdr mgmt_hdr) +{ + if (sta_ds->vhtSupportedRxNss != (beacon->OperatingMode.rxNSS + 1)) { + sta_ds->vhtSupportedRxNss = + beacon->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session_entry, + sta_ds->vhtSupportedRxNss, sta_ds->staIndex, + mgmt_hdr->sa); + } +} + +/* + * sch_bcn_process_sta_bt_amp_sta_ibss() - Process the received beacon frame + * for sta, bt_amp_sta and ibss + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @beaconParams: update beacon params + * @sendProbeReq: out flag to indicate if probe rsp is to be sent + * @pMh: mac header + * + * Process the received beacon frame for sta, bt_amp_sta and ibss + * + * Return: void + */ +static void +sch_bcn_process_sta_bt_amp_sta_ibss(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + tpDphHashNode pStaDs = NULL; + uint16_t aid; + uint8_t operMode; + uint8_t chWidth = 0; + uint8_t cb_mode; + + if (RF_CHAN_14 >= session->currentOperChannel) + cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; + else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* check for VHT capability */ + pStaDs = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid, + &session->dph.dphHashTable); + if ((NULL == pStaDs) || + (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode)) + return; + + if (session->vhtCapability && bcn->OperatingMode.present) { + operMode = get_operating_channel_width(pStaDs); + if (operMode == bcn->OperatingMode.chanWidth) + return; + + PELOGE(sch_log(mac_ctx, LOGE, + FL("received OpMode Chanwidth %d, staIdx = %d"), + bcn->OperatingMode.chanWidth, pStaDs->staIndex);) + PELOGE(sch_log(mac_ctx, LOGE, + FL("MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + pMh->sa[0], pMh->sa[1], + pMh->sa[2], pMh->sa[3], + pMh->sa[4], pMh->sa[5]);) + + if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_160MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 160MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_80MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 80MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 40MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 20MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + } + lim_check_vht_op_mode_change(mac_ctx, session, + bcn->OperatingMode.chanWidth, + pStaDs->staIndex, pMh->sa); + update_nss(mac_ctx, pStaDs, bcn, session, pMh); + return; + } + + if (!(session->vhtCapability && bcn->VHTOperation.present)) + return; + + operMode = pStaDs->vhtSupportedChannelWidthSet; + if (operMode == bcn->VHTOperation.chanWidth) + return; + + PELOGE(sch_log(mac_ctx, LOGE, + FL("received VHTOP CHWidth %d staIdx = %d"), + bcn->VHTOperation.chanWidth, pStaDs->staIndex);) + PELOGE(sch_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + pMh->sa[0], pMh->sa[1], + pMh->sa[2], pMh->sa[3], + pMh->sa[4], pMh->sa[5]);) + + if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 160MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 160MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + pStaDs->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 80MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + pStaDs->htSupportedChannelWidthSet = eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_80MHZ; + } else if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + if (bcn->HTCaps.supportedChannelWidthSet) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 40MHz"));) + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_40MHZ; + } else { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 20MHz"));) + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + chWidth = eHT_CHANNEL_WIDTH_20MHZ; + } + } + lim_check_vht_op_mode_change(mac_ctx, session, chWidth, + pStaDs->staIndex, pMh->sa); + return; +} + +/* + * __sch_beacon_process_for_session() - Process the received beacon frame when + * station is not scanning and corresponding session is found + * + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * + * Following scenarios exist when Session exists + * IBSS STA receving beacons from IBSS Peers, who are part of IBSS. + * - call lim_handle_ibs_scoalescing with that session context. + * Infra STA receving beacons from AP to which it is connected + * - call sch_beacon_processFromAP with that session's context. + * BTAMP STA receving beacons from BTAMP AP + * - call sch_beacon_processFromAP with that session's context. + * BTAMP AP receiving beacons from BTAMP STA + * (here need to make sure BTAP creates session entry for BT STA) + * - just update the beacon count for heart beat purposes for now, + * for now, don't process the beacon. + * Infra/IBSS both active and receives IBSS beacon: + * - call lim_handle_ibs_scoalescing with that session context. + * Infra/IBSS both active and receives Infra beacon: + * - call sch_beacon_processFromAP with that session's context. + * any updates to EDCA parameters will be effective for IBSS as well, + * even though no WMM for IBSS ?? Need to figure out how to handle + * this scenario. + * Infra/BTSTA both active and receive Infra beacon. + * - change in EDCA parameters on Infra affect the BTSTA link. + * Update the same parameters on BT link + * Infra/BTSTA both active and receive BT-AP beacon. + * - update beacon cnt for heartbeat + * Infra/BTAP both active and receive Infra beacon. + * - BT-AP starts advertising BE parameters from Infra AP, if they get + * changed. + * Infra/BTAP both active and receive BTSTA beacon. + * - update beacon cnt for heartbeat + * + * Return: void + */ +static void __sch_beacon_process_for_session(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session) +{ + tPowerdBm localRRMConstraint = 0; + uint8_t bssIdx = 0; + tUpdateBeaconParams beaconParams; + uint8_t sendProbeReq = false; +#ifdef WLAN_FEATURE_11AC + tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#endif +#if defined FEATURE_WLAN_ESE || defined WLAN_FEATURE_VOWIFI + tPowerdBm regMax = 0, maxTxPower = 0; +#endif + cdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.paramChangeBitmap = 0; + + if (LIM_IS_IBSS_ROLE(session)) { + lim_handle_ibss_coalescing(mac_ctx, bcn, rx_pkt_info, session); + } else if (LIM_IS_STA_ROLE(session) + || LIM_IS_BT_AMP_STA_ROLE(session)) { + if (false == sch_bcn_process_sta_bt_amp_sta(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &beaconParams, &sendProbeReq, pMh)) + return; + } + + if (session->htCapability && bcn->HTInfo.present) + lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx, + &bcn->HTInfo, bssIdx, session); + + if (LIM_IS_STA_ROLE(session) + || LIM_IS_BT_AMP_STA_ROLE(session) + || LIM_IS_IBSS_ROLE(session)) { + /* Channel Switch information element updated */ + if (bcn->channelSwitchPresent) { + lim_update_channel_switch(mac_ctx, bcn, session); + } else if (session->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch(mac_ctx, session); + } + } +#ifdef WLAN_FEATURE_11AC + if (LIM_IS_STA_ROLE(session) + || LIM_IS_BT_AMP_STA_ROLE(session) + || LIM_IS_IBSS_ROLE(session)) + sch_bcn_process_sta_bt_amp_sta_ibss(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &beaconParams, &sendProbeReq, pMh); +#endif + +#if defined (FEATURE_WLAN_ESE) || defined (WLAN_FEATURE_VOWIFI) + /* Obtain the Max Tx power for the current regulatory */ + regMax = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); +#endif + +#if defined WLAN_FEATURE_VOWIFI + if (mac_ctx->rrm.rrmPEContext.rrmEnable + && bcn->powerConstraintPresent) + localRRMConstraint = + bcn->localPowerConstraint.localPowerConstraints; + else + localRRMConstraint = 0; + maxTxPower = lim_get_max_tx_power(regMax, regMax - localRRMConstraint, + mac_ctx->roam.configParam.nTxPowerCap); +#elif defined FEATURE_WLAN_ESE + maxTxPower = regMax; +#endif + +#if defined FEATURE_WLAN_ESE + if (session->isESEconnection) { + tPowerdBm localESEConstraint = 0; + if (bcn->eseTxPwr.present) { + localESEConstraint = bcn->eseTxPwr.power_limit; + maxTxPower = lim_get_max_tx_power(maxTxPower, + localESEConstraint, + mac_ctx->roam.configParam.nTxPowerCap); + } + sch_log(mac_ctx, LOG1, + FL("RegMax = %d, localEseCons = %d, MaxTx = %d"), + regMax, localESEConstraint, maxTxPower); + } +#endif + +#if defined (FEATURE_WLAN_ESE) || defined (WLAN_FEATURE_VOWIFI) + /* If maxTxPower is increased or decreased */ + if (maxTxPower != session->maxTxPower) { + sch_log(mac_ctx, LOG1, + FL("Local power constraint change..updating new maxTx power %d to HAL"), + maxTxPower); + if (lim_send_set_max_tx_power_req(mac_ctx, maxTxPower, session) + == eSIR_SUCCESS) + session->maxTxPower = maxTxPower; + } +#endif + + /* Indicate to LIM that Beacon is received */ + if (bcn->HTInfo.present) + lim_received_hb_handler(mac_ctx, + (uint8_t) bcn->HTInfo.primaryChannel, session); + else + lim_received_hb_handler(mac_ctx, (uint8_t) bcn->channelNumber, + session); + + /* + * I don't know if any additional IE is required here. Currently, not + * include addIE. + */ + if (sendProbeReq) + lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId, + session->bssId, session->currentOperChannel, + session->selfMacAddr, session->dot11mode, 0, NULL); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + PELOGW(sch_log(mac_ctx, LOGW, + FL("Beacon for session[%d] got changed."), + session->peSessionId);) + PELOGW(sch_log(mac_ctx, LOGW, + FL("sending beacon param change bitmap: 0x%x "), + beaconParams.paramChangeBitmap);) + lim_send_beacon_params(mac_ctx, &beaconParams, session); + } +} + +/** + * sch_beacon_process() - process the beacon frame + * + * @mac_ctx: mac global context + * @rx_pkt_info: pointer to buffer descriptor + * + * @return None + */ +void +sch_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + static tSchBeaconStruct bcn; + tUpdateBeaconParams bcn_prm; + tpPESession ap_session = NULL; +#ifdef WLAN_FEATURE_MBSSID + uint8_t i; +#endif + + cdf_mem_zero(&bcn_prm, sizeof(tUpdateBeaconParams)); + bcn_prm.paramChangeBitmap = 0; + mac_ctx->sch.gSchBcnRcvCnt++; + /* Convert the beacon frame into a structure */ + if (sir_convert_beacon_frame2_struct(mac_ctx, (uint8_t *) rx_pkt_info, + &bcn) != eSIR_SUCCESS) { + PELOGE(sch_log(mac_ctx, LOGE, FL("beacon parsing failed"));) + mac_ctx->sch.gSchBcnParseErrorCnt++; + return; + } + + if (bcn.ssidPresent) + bcn.ssId.ssId[bcn.ssId.length] = 0; + /* + * First process the beacon in the context of any existing AP or BTAP + * session. This takes cares of following two scenarios: + * - session = NULL: + * e.g. beacon received from a neighboring BSS, you want to apply the + * protection settings to BTAP/InfraAP beacons + * - session is non NULL: + * e.g. beacon received is from the INFRA AP to which you are connected + * on another concurrent link. In this case also, we want to apply the + * protection settings(as advertised by Infra AP) to BTAP beacons + */ +#ifdef WLAN_FEATURE_MBSSID + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + ap_session = pe_find_session_by_session_id(mac_ctx, i); + if (!((ap_session != NULL) && + (!(WMA_GET_OFFLOADSCANLEARN(rx_pkt_info))))) + continue; + + if (!LIM_IS_AP_ROLE(ap_session)) + continue; + + bcn_prm.bssIdx = ap_session->bssIdx; + if (ap_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + ap_beacon_process(mac_ctx, rx_pkt_info, + &bcn, &bcn_prm, ap_session); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, ap_session); + PELOG1(sch_log(mac_ctx, LOG1, + FL("Beacon for PE session[%d] got changed."), + ap_session->peSessionId);) + PELOG1(sch_log(mac_ctx, LOG1, + FL("sending beacon param change bitmap: 0x%x"), + bcn_prm.paramChangeBitmap);) + lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session); + } + } +#else + ap_session = lim_is_ap_session_active(mac_ctx); + if ((ap_session != NULL) + && (!(WMA_GET_OFFLOADSCANLEARN(rx_pkt_info)))) { + bcn_prm.bssIdx = ap_session->bssIdx; + if (ap_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + ap_beacon_process(mac_ctx, rx_pkt_info, &bcn, + &bcn_prm, ap_session); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, ap_session); + PELOG1(sch_log(mac_ctx, LOG1, + FL("Beacon for PE session[%d] got changed."), + ap_session->peSessionId);) + PELOG1(sch_log(mac_ctx, LOG1, + FL("sending beacon param change bitmap: 0x%x "), + bcn_prm.paramChangeBitmap);) + lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session); + } + } +#endif + /* + * Now process the beacon in the context of the BSS which is + * transmitting the beacons, if one is found + */ + if (session == NULL) + __sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info); + else + __sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, + session); +} + +/** + * sch_beacon_edca_process(): Process the EDCA parameter set in the received + * beacon frame + * + * @mac_ctx: mac global context + * @edca: reference to edca parameters in beacon struct + * @session : pesession entry + * + * @return status of operation + */ +tSirRetStatus +sch_beacon_edca_process(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca, + tpPESession session) +{ + uint8_t i; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + PELOG1(sch_log(pMac, LOG1, + FL("Updating parameter set count: Old %d ---> new %d"), + session->gLimEdcaParamSetCount, edca->qosInfo.count);) + + session->gLimEdcaParamSetCount = edca->qosInfo.count; + session->gLimEdcaParams[EDCA_AC_BE] = edca->acbe; + session->gLimEdcaParams[EDCA_AC_BK] = edca->acbk; + session->gLimEdcaParams[EDCA_AC_VI] = edca->acvi; + session->gLimEdcaParams[EDCA_AC_VO] = edca->acvo; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + log_ptr->aci_be = session->gLimEdcaParams[EDCA_AC_BE].aci.aci; + log_ptr->cw_be = + session->gLimEdcaParams[EDCA_AC_BE].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BE].cw.min; + log_ptr->txoplimit_be = + session->gLimEdcaParams[EDCA_AC_BE].txoplimit; + log_ptr->aci_bk = + session->gLimEdcaParams[EDCA_AC_BK].aci.aci; + log_ptr->cw_bk = + session->gLimEdcaParams[EDCA_AC_BK].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BK].cw.min; + log_ptr->txoplimit_bk = + session->gLimEdcaParams[EDCA_AC_BK].txoplimit; + log_ptr->aci_vi = + session->gLimEdcaParams[EDCA_AC_VI].aci.aci; + log_ptr->cw_vi = + session->gLimEdcaParams[EDCA_AC_VI].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VI].cw.min; + log_ptr->txoplimit_vi = + session->gLimEdcaParams[EDCA_AC_VI].txoplimit; + log_ptr->aci_vo = + session->gLimEdcaParams[EDCA_AC_VO].aci.aci; + log_ptr->cw_vo = + session->gLimEdcaParams[EDCA_AC_VO].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VO].cw.min; + log_ptr->txoplimit_vo = + session->gLimEdcaParams[EDCA_AC_VO].txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + PELOG1(sch_log(pMac, LOGE, + FL("Updating Local EDCA Params(gLimEdcaParams) to: "));) + for (i = 0; i < MAX_NUM_AC; i++) { + PELOG1(sch_log(pMac, LOG1, + FL("AC[%d]: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + i, session->gLimEdcaParams[i].aci.aifsn, + session->gLimEdcaParams[i].aci.acm, + session->gLimEdcaParams[i].cw.min, + session->gLimEdcaParams[i].cw.max, + session->gLimEdcaParams[i].txoplimit);) + } + return eSIR_SUCCESS; +} diff --git a/core/mac/src/pe/sch/sch_debug.c b/core/mac/src/pe/sch/sch_debug.c new file mode 100644 index 0000000000..47c0714a83 --- /dev/null +++ b/core/mac/src/pe/sch/sch_debug.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_debug.cc contains some debug functions. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cdf_trace.h" +#include "sch_debug.h" +#define LOG_SIZE 256 + +void sch_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ + + CDF_TRACE_LEVEL cdf_debug_level; + char logBuffer[LOG_SIZE]; + va_list marker; + + /* getting proper Debug level */ + cdf_debug_level = get_vos_debug_level(loglevel); + + /* extracting arguments from pstring */ + va_start(marker, pString); + vsnprintf(logBuffer, LOG_SIZE, pString, marker); + CDF_TRACE(CDF_MODULE_ID_PE, cdf_debug_level, "%s", logBuffer); + va_end(marker); +} + +/* -------------------------------------------------------------------- */ diff --git a/core/mac/src/pe/sch/sch_debug.h b/core/mac/src/pe/sch/sch_debug.h new file mode 100644 index 0000000000..d27f72733d --- /dev/null +++ b/core/mac/src/pe/sch/sch_debug.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_debug.h contains some debug macros. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_DEBUG_H__ +#define __SCH_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) sch_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif diff --git a/core/mac/src/pe/sch/sch_message.c b/core/mac/src/pe/sch/sch_message.c new file mode 100644 index 0000000000..e746f8b742 --- /dev/null +++ b/core/mac/src/pe/sch/sch_message.c @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "lim_send_messages.h" + +#include "sch_api.h" +#include "sch_debug.h" + +/* / Minimum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MIN 10 + +/* / Maximum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MAX 10000 + +/* / convert the CW values into a uint16_t */ +#define GET_CW(pCw) ((uint16_t) ((*(pCw) << 8) + *((pCw) + 1))) + +/* local functions */ +static tSirRetStatus get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t + params[] + [WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]); +static void set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry); + +/* -------------------------------------------------------------------- */ +/** + * sch_set_beacon_interval + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t bi; + + bi = psessionEntry->beaconParams.beaconInterval; + + if (bi < SCH_BEACON_INTERVAL_MIN || bi > SCH_BEACON_INTERVAL_MAX) { + sch_log(pMac, LOGE, + FL("Invalid beacon interval %d (should be [%d,%d]"), bi, + SCH_BEACON_INTERVAL_MIN, SCH_BEACON_INTERVAL_MAX); + return; + } + + pMac->sch.schObject.gSchBeaconInterval = (uint16_t) bi; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_process_message + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_process_message(tpAniSirGlobal pMac, tpSirMsgQ pSchMsg) +{ + uint32_t val; + + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + PELOG3(sch_log(pMac, LOG3, FL("Received message (%x) "), pSchMsg->type);) + + switch (pSchMsg->type) { + + case SIR_SCH_CHANNEL_SWITCH_REQUEST: + sch_log(pMac, LOGE, FL("Channel switch request not handled")); + break; + + case SIR_SCH_START_SCAN_REQ: + pMac->sch.gSchScanReqRcvd = true; + if (pMac->sch.gSchHcfEnabled) { + /* In HCF mode, wait for TFP to stop before sending a response */ + if (pMac->sch.schObject.gSchCFBInitiated || + pMac->sch.schObject.gSchCFPInitiated) { + PELOG1(sch_log(pMac, LOG1, + FL + ("Waiting for TFP to halt before sending " + "start scan response")); + ) + } else + sch_send_start_scan_rsp(pMac); + } else { + /* In eDCF mode, send the response right away */ + sch_send_start_scan_rsp(pMac); + } + break; + + case SIR_SCH_END_SCAN_NTF: + PELOG3(sch_log(pMac, LOG3, + FL("Received STOP_SCAN_NTF from LIM")); + ) + pMac->sch.gSchScanReqRcvd = false; + break; + + case SIR_CFG_PARAM_UPDATE_IND: + + if (wlan_cfg_get_int(pMac, (uint16_t) pSchMsg->bodyval, &val) != + eSIR_SUCCESS) + sch_log(pMac, LOGP, FL("failed to cfg get id %d"), + pSchMsg->bodyval); + + switch (pSchMsg->bodyval) { + case WNI_CFG_BEACON_INTERVAL: + /* What to do for IBSS ?? - TBD */ + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_set_beacon_interval(pMac, psessionEntry); + break; + + case WNI_CFG_DTIM_PERIOD: + pMac->sch.schObject.gSchDTIMCount = 0; + break; + + case WNI_CFG_CFP_PERIOD: + pMac->sch.schObject.gSchCFPCount = 0; + break; + + case WNI_CFG_EDCA_PROFILE: + sch_edca_profile_update(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK_LOCAL: + case WNI_CFG_EDCA_ANI_ACBE_LOCAL: + case WNI_CFG_EDCA_ANI_ACVI_LOCAL: + case WNI_CFG_EDCA_ANI_ACVO_LOCAL: + case WNI_CFG_EDCA_WME_ACBK_LOCAL: + case WNI_CFG_EDCA_WME_ACBE_LOCAL: + case WNI_CFG_EDCA_WME_ACVI_LOCAL: + case WNI_CFG_EDCA_WME_ACVO_LOCAL: + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_qos_update_local(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK: + case WNI_CFG_EDCA_ANI_ACBE: + case WNI_CFG_EDCA_ANI_ACVI: + case WNI_CFG_EDCA_ANI_ACVO: + case WNI_CFG_EDCA_WME_ACBK: + case WNI_CFG_EDCA_WME_ACBE: + case WNI_CFG_EDCA_WME_ACVI: + case WNI_CFG_EDCA_WME_ACVO: + if (LIM_IS_AP_ROLE(psessionEntry)) { + psessionEntry->gLimEdcaParamSetCount++; + sch_qos_update_broadcast(pMac, psessionEntry); + } + break; + + default: + sch_log(pMac, LOGE, + FL("Cfg param %d indication not handled"), + pSchMsg->bodyval); + } + break; + + default: + sch_log(pMac, LOGE, FL("Unknown message in schMsgQ type %d"), + pSchMsg->type); + } + +} + +/* get the local or broadcast parameters based on the profile sepcified in the config */ +/* params are delivered in this order: BK, BE, VI, VO */ +tSirRetStatus +sch_get_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], uint8_t local) +{ + uint32_t val; + uint32_t i, idx; + uint32_t *prf; + + uint32_t ani_l[] = { + WNI_CFG_EDCA_ANI_ACBE_LOCAL, WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, WNI_CFG_EDCA_ANI_ACVO_LOCAL}; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + uint32_t ani_b[] = { WNI_CFG_EDCA_ANI_ACBE, WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACVI, WNI_CFG_EDCA_ANI_ACVO}; + uint32_t wme_b[] = { WNI_CFG_EDCA_WME_ACBE, WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACVI, WNI_CFG_EDCA_WME_ACVO}; + + if (wlan_cfg_get_int(pMac, WNI_CFG_EDCA_PROFILE, &val) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("failed to cfg get EDCA_PROFILE id %d"), + WNI_CFG_EDCA_PROFILE); + return eSIR_FAILURE; + } + + if (val >= WNI_CFG_EDCA_PROFILE_MAX) { + sch_log(pMac, LOGE, + FL("Invalid EDCA_PROFILE %d, using %d instead"), val, + WNI_CFG_EDCA_PROFILE_ANI); + val = WNI_CFG_EDCA_PROFILE_ANI; + } + + sch_log(pMac, LOGW, FL("EdcaProfile: Using %d (%s)"), val, + ((val == WNI_CFG_EDCA_PROFILE_WMM) ? "WMM" : "HiPerf")); + + if (local) { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_l[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_l[0]; + break; + } + } else { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_b[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_b[0]; + break; + } + } + + for (i = 0; i < 4; i++) { + uint8_t data[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("cfgGet failed for %d"), prf[i]); + return eSIR_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + sch_log(pMac, LOGE, + FL("cfgGet for %d: length is %d instead of %d"), + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return eSIR_FAILURE; + } + for (idx = 0; idx < len; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + PELOG1(sch_log + (pMac, LOG1, FL("GetParams: local=%d, profile = %d Done"), local, + val); + ) + return eSIR_SUCCESS; +} + +/** + * broadcast_wmm_of_concurrent_sta_session() - broadcasts wmm info + * @mac_ctx: mac global context + * @session: pesession entry + * + * Return: void + */ +static void +broadcast_wmm_of_concurrent_sta_session(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t i, j; + tpPESession concurrent_session = NULL; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * Find another INFRA STA AP session on same operating channel. + * The session entry passed to this API is for GO/SoftAP session + * that is getting added currently + */ + if (!((mac_ctx->lim.gpSession[i].valid == true) && + (mac_ctx->lim.gpSession[i].peSessionId != + session->peSessionId) + && (mac_ctx->lim.gpSession[i].currentOperChannel == + session->currentOperChannel) + && (mac_ctx->lim.gpSession[i].limSystemRole + == eLIM_STA_ROLE))) + continue; + + concurrent_session = &(mac_ctx->lim.gpSession[i]); + break; + } + + if (concurrent_session == NULL) + return; + /* + * Once atleast one concurrent session on same channel is found and WMM + * broadcast params for current SoftAP/GO session updated, return + */ + for (j = 0; j < MAX_NUM_AC; j++) { + session->gLimEdcaParamsBC[j].aci.acm = + concurrent_session->gLimEdcaParams[j].aci.acm; + session->gLimEdcaParamsBC[j].aci.aifsn = + concurrent_session->gLimEdcaParams[j].aci.aifsn; + session->gLimEdcaParamsBC[j].cw.min = + concurrent_session->gLimEdcaParams[j].cw.min; + session->gLimEdcaParamsBC[j].cw.max = + concurrent_session->gLimEdcaParams[j].cw.max; + session->gLimEdcaParamsBC[j].txoplimit = + concurrent_session->gLimEdcaParams[j].txoplimit; + PELOG1(sch_log(mac_ctx, LOG1, + FL("QoSUpdateBCast changed again due to concurrent INFRA STA session: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + j, session->gLimEdcaParamsBC[j].aci.aifsn, + session->gLimEdcaParamsBC[j].aci.acm, + session->gLimEdcaParamsBC[j].cw.min, + session->gLimEdcaParamsBC[j].cw.max, + session->gLimEdcaParamsBC[j].txoplimit);) + } +} + +void sch_qos_update_broadcast(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + uint8_t i; + + if (sch_get_params(pMac, params, false) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("QosUpdateBroadcast: failed"));) + return; + } + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + PELOG1(sch_log(pMac, LOG1, "QosUpdBcast: mode %d", phyMode);) + + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + psessionEntry->gLimEdcaParamsBC[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + psessionEntry->gLimEdcaParamsBC[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + psessionEntry->gLimEdcaParamsBC[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + psessionEntry->gLimEdcaParamsBC[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + psessionEntry->gLimEdcaParamsBC[i].txoplimit = + (uint16_t) params[i][txopidx]; + + PELOG1(sch_log + (pMac, LOG1, + "QoSUpdateBCast: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + i, psessionEntry->gLimEdcaParamsBC[i].aci.aifsn, + psessionEntry->gLimEdcaParamsBC[i].aci.acm, + psessionEntry->gLimEdcaParamsBC[i].cw.min, + psessionEntry->gLimEdcaParamsBC[i].cw.max, + psessionEntry->gLimEdcaParamsBC[i].txoplimit); + ) + + } + + /* If there exists a concurrent STA-AP session, use its WMM params to broadcast in beacons. WFA Wifi Direct test plan 6.1.14 requirement */ + broadcast_wmm_of_concurrent_sta_session(pMac, psessionEntry); + + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) + PELOGE(sch_log(pMac, LOGE, "Unable to set beacon fields!");) +} + +void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + + if (sch_get_params(pMac, params, true /*local */) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("sch_get_params(local) failed"));) + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + + /* For AP, the bssID is stored in LIM Global context. */ + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry->bssIdx); +} + +/** ---------------------------------------------------------- + \fn sch_set_default_edca_params + \brief This function sets the gLimEdcaParams to the default + \ local wmm profile. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + + if (get_wmm_local_params(pMac, params) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("get_wmm_local_params() failed"));) + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + return; +} + +/** ---------------------------------------------------------- + \fn set_sch_edca_params + \brief This function fills in the gLimEdcaParams structure + \ with the given edca params. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +static void +set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry) +{ + uint32_t i; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + PELOG1(sch_log(pMac, LOG1, FL("lim_get_phy_mode() = %d"), phyMode);) + /* if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11G) */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } + /* else if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11B) */ + else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + psessionEntry->gLimEdcaParams[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + psessionEntry->gLimEdcaParams[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + psessionEntry->gLimEdcaParams[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + psessionEntry->gLimEdcaParams[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + psessionEntry->gLimEdcaParams[i].txoplimit = + (uint16_t) params[i][txopidx]; + + PELOG1(sch_log + (pMac, LOG1, + FL + ("AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + i, psessionEntry->gLimEdcaParams[i].aci.aifsn, + psessionEntry->gLimEdcaParams[i].aci.acm, + psessionEntry->gLimEdcaParams[i].cw.min, + psessionEntry->gLimEdcaParams[i].cw.max, + psessionEntry->gLimEdcaParams[i].txoplimit); + ) + + } + return; +} + +/** ---------------------------------------------------------- + \fn get_wmm_local_params + \brief This function gets the WMM local edca parameters. + \param tpAniSirGlobal pMac + \param uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN] + \return none + \ ------------------------------------------------------------ */ +static tSirRetStatus +get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]) +{ + uint32_t i, idx; + uint32_t *prf; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + + prf = &wme_l[0]; + for (i = 0; i < 4; i++) { + uint8_t data[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("cfgGet failed for %d"), prf[i]); + return eSIR_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + sch_log(pMac, LOGE, + FL("cfgGet for %d: length is %d instead of %d"), + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return eSIR_FAILURE; + } + for (idx = 0; idx < len; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + return eSIR_SUCCESS; +} + +/** ---------------------------------------------------------- + \fn sch_edca_profile_update + \brief This function updates the local and broadcast + \ EDCA params in the gLimEdcaParams structure. It also + \ updates the edcaParamSetCount. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_edca_profile_update(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_qos_update_local(pMac, psessionEntry); + psessionEntry->gLimEdcaParamSetCount++; + sch_qos_update_broadcast(pMac, psessionEntry); + } +} + +/* -------------------------------------------------------------------- */ diff --git a/core/mac/src/pe/sch/sch_sys_params.h b/core/mac/src/pe/sch/sch_sys_params.h new file mode 100644 index 0000000000..adf5c19827 --- /dev/null +++ b/core/mac/src/pe/sch/sch_sys_params.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_sys_params.h contains scheduler parameter definitions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_SYS_PARAMS_H__ +#define __SCH_SYS_PARAMS_H__ + +/* / Unsolicited poll period (ms) (0 to disable) */ +#define SCH_POLL_PERIOD 1000 + +/* / RR timeout value (ms) (0 to disable) */ +#define SCH_RR_TIMEOUT_MS 40 + +/* / Default CP:CFP ratio */ +#define SCH_DEFAULT_CP_TO_CFP_RATIO 0 + +/* / Default maximum CFP duration (us) */ +#define SCH_DEFAULT_MAX_CFP_TIME 60000 + +/* / Default minimum CP duration (us) */ +#define SCH_DEFAULT_MIN_CP_TIME 100 + +/* / Amount of delay prior to starting CFP (us) */ +#define SCH_CFP_START_DELAY 100 + +/* / Unit of Txop in micro seconds */ +#define TXOP_UNIT_IN_USEC 32 + +/* / Minimum amount of time granted per instruction on average (units of txop) */ +#define MIN_TXOP_PER_INSTRUCTION 50 + +/* / Maximum amount of time granted per instruction (units of txop) */ +#define MAX_TXOP_PER_INSTRUCTION 300 /* HACK - 100 */ + +/* / Maximum amount of time granted to one entire schedule (units of txop) */ +#define MAX_TXOP_PER_SCHEDULE 400 + +/* / Scheduling quantum (units of TXOP) */ +#define SCH_QUANTUM_QUEUE 4 + +/* / Maximum unused quantum allowed to be accumulated by a queue */ +#define MAX_ACCUMULATED_QUANTUM 500 + +/* / Minimum allocated quantum for an uplink flow before a poll instruction is written */ +#define SCH_MIN_UL_ALLOC 12 + +/* ---- Scheduling Policy ---- */ + +/* / Number of QOS classes */ +#define SCH_NUM_QOS_CLASSES 2 + +#define SCH_POLICY_STRICT_PRI 0 +#define SCH_POLICY_DRR 1 + +/* / Scheduling quantum for each class if using DRR */ +#define SCH_QUANTUM_CLASS 100 + +/* / The default scheduling policy between classes */ +#define SCH_POLICY_DEFAULT SCH_POLICY_STRICT_PRI + +/* Scheduling weights for each priority */ + +#define SCH_QUANTUM_0 40 +#define SCH_QUANTUM_1 36 +#define SCH_QUANTUM_2 32 +#define SCH_QUANTUM_3 28 +#define SCH_QUANTUM_4 24 +#define SCH_QUANTUM_5 20 +#define SCH_QUANTUM_6 16 +#define SCH_QUANTUM_7 12 + +#endif diff --git a/core/mac/src/sys/common/inc/wlan_qct_sys.h b/core/mac/src/sys/common/inc/wlan_qct_sys.h new file mode 100644 index 0000000000..c80b641a20 --- /dev/null +++ b/core/mac/src/sys/common/inc/wlan_qct_sys.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( WLAN_QCT_SYS_H__ ) +#define WLAN_QCT_SYS_H__ + +/**=========================================================================== + + \file wlan_qct_sys.h + + \brief System module API + + ==========================================================================*/ + +/* $HEADER$ */ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ +#include +#include +#include + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + + \brief sysResponseCback() - SYS async resonse callback + + This is a protype for the callback function that SYS makes to various + modules in the system. + + \param pUserData - user data that is passed to the Callback function + when it is invoked. + + \return Nothing + + \sa sysMcStart(), sysMcThreadProbe(), sysTxThreadProbe() + + --------------------------------------------------------------------------*/ +typedef void (*sysResponseCback)(void *pUserData); + +typedef enum { + SYS_MSG_ID_MC_START, + SYS_MSG_ID_MC_THR_PROBE, + SYS_MSG_ID_MC_TIMER, + SYS_MSG_ID_MC_STOP, + SYS_MSG_ID_FTM_RSP, + +} SYS_MSG_ID; + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Function declarations and documenation + -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + + \brief sys_build_message_header() - Build / initialize a SYS message header + + This function will initialize the SYS message header with the message type + and any internal fields needed for a new SYS message. This function sets + all but the message body, which is up to the caller to setup based on the + specific message being built. + + \note There are internal / reserved items in a SYS message that must be + set correctly for the message to be recognized as a SYS message by + the SYS message handlers. It is important for every SYS message to + be setup / built / initialized through this function. + + \param sysMsgId - a valid message ID for a SYS message. See the + SYS_MSG_ID enum for all the valid SYS message IDs. + + \param pMsg - pointer to the message structure to be setup. + + \return + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, cds_msg_t *pMsg); + +/*---------------------------------------------------------------------------- + + \brief sysMcStart() - start the system Main Controller thread. + + This function starts the SYS (Main Controller) module. Starting this + module triggers the CFG download to the 'legacy' MAC software. + + \param p_cds_context - pointer to the CDS Context + + \param userCallback - this is a callback that is called when the SYS + has completed the 'start' funciton. + + \param pUserData - pointer to some user data entity that is passed to + the callback function as a parameter when invoked. + + \return CDF_STATUS_SUCCESS - + + \todo: We have not 'status' on the callback. How do we notify the + callback that there is a failure ? + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sysMcStart(v_CONTEXT_t p_cds_context, sysResponseCback userCallback, + void *pUserData); + +/*---------------------------------------------------------------------------- + + \brief sys_stop() - Stop the SYS module. + + This function stops the SYS module. + + \todo: What else do we need to do on sys_stop()? + + \param p_cds_context - pointer to the CDS Context + + \return CDF_STATUS_SUCCESS - the SYS module is stopped. + + CDF_STATUS_E_FAILURE - the SYS module open failed to stop. + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sys_stop(v_CONTEXT_t p_cds_context); + +/*---------------------------------------------------------------------------- + + \brief sys_mc_process_msg() - process SYS messages on the Main Controller thread + + This function processes SYS Messages on the Main Controller thread. + SYS messages consist of all 'legacy' messages (messages bound for legacy + modules like LIM, HAL, PE, etc.) as well as newly defined SYS message + types. + + SYS messages are identified by their type (in the SYS_MESSAGES enum) as + well as a 'cookie' that is in the reserved field of the message structure. + This 'cookie' is introduced to prevent any message type/ID conflicts with + the 'legacy' message types. + + Any module attempting to post a message to the SYS module must set the + message type to one of the types in the SYS_MESSAGE enum *and* must also + set the Reserved field in the message body to SYS_MSG_COOKIE. + + \param p_cds_context - pointer to the CDS Context + + \param pMsg - pointer to the message to be processed. + + \return - CDF_STATUS_SUCCESS - the message was processed successfully. + + CDF_STATUS_E_BADMSG - a bad (unknown type) message was received + and subsequently not processed. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sys_mc_process_msg(v_CONTEXT_t p_cds_context, cds_msg_t *pMsg); + +void wlan_sys_probe(void); + +#endif /* WLAN_QCT_SYS_H__ */ diff --git a/core/mac/src/sys/common/src/wlan_qct_sys.c b/core/mac/src/sys/common/src/wlan_qct_sys.c new file mode 100644 index 0000000000..c2c39d1d97 --- /dev/null +++ b/core/mac/src/sys/common/src/wlan_qct_sys.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include /* needed for tSirRetStatus */ +#include /* needed for tSirMbMsg */ +#include /* needed for SIR_... message types */ +#include /* needed for WNI_... message types */ +#include "ani_global.h" +#include "wma_types.h" +#include "sme_api.h" +#include "mac_init_api.h" + +/* Cookie for SYS messages. Note that anyone posting a SYS Message + * has to write the COOKIE in the reserved field of the message. The + * SYS Module relies on this COOKIE + */ +#define SYS_MSG_COOKIE 0xFACE + +/* SYS stop timeout 30 seconds */ +#define SYS_STOP_TIMEOUT (30000) + +static cdf_event_t g_stop_evt; + +CDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, cds_msg_t *pMsg) +{ + pMsg->type = sysMsgId; + pMsg->reserved = SYS_MSG_COOKIE; + + return (CDF_STATUS_SUCCESS); +} + +void sys_stop_complete_cb(void *pUserData) { + cdf_event_t *pStopEvt = (cdf_event_t *) pUserData; + CDF_STATUS cdf_status; +/*-------------------------------------------------------------------------*/ + + cdf_status = cdf_event_set(pStopEvt); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + +} /* cds_sys_stop_complete_cback() */ + +CDF_STATUS sys_stop(v_CONTEXT_t p_cds_context) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t sysMsg; + + /* Initialize the stop event */ + cdf_status = cdf_event_init(&g_stop_evt); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + return cdf_status; + } + + /* post a message to SYS module in MC to stop SME and MAC */ + sys_build_message_header(SYS_MSG_ID_MC_STOP, &sysMsg); + + /* Save the user callback and user data */ + /* finished. */ + sysMsg.callback = sys_stop_complete_cb; + sysMsg.bodyptr = (void *)&g_stop_evt; + + /* post the message.. */ + cdf_status = cds_mq_post_message(CDS_MQ_ID_SYS, &sysMsg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_status = CDF_STATUS_E_BADMSG; + } + + cdf_status = cdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + + cdf_status = cdf_event_destroy(&g_stop_evt); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS(cdf_status)); + + return (cdf_status); +} + +CDF_STATUS sys_mc_process_msg(v_CONTEXT_t p_cds_context, cds_msg_t *pMsg) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + void *hHal; + + if (NULL == pMsg) { + CDF_ASSERT(0); + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer to cds_msg_t", __func__); + return CDF_STATUS_E_INVAL; + } + + /* All 'new' SYS messages are identified by a cookie in the reserved + * field of the message as well as the message type. This prevents + * the possibility of overlap in the message types defined for new + * SYS messages with the 'legacy' message types. The legacy messages + * will not have this cookie in the reserved field + */ + if (SYS_MSG_COOKIE == pMsg->reserved) { + /* Process all the new SYS messages.. */ + switch (pMsg->type) { + case SYS_MSG_ID_MC_START: + { + /* Handling for this message is not needed now so adding + *debug print and CDF_ASSERT*/ + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + " Received SYS_MSG_ID_MC_START message msgType= %d [0x%08x]", + pMsg->type, pMsg->type); + CDF_ASSERT(0); + break; + } + + case SYS_MSG_ID_MC_STOP: + { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_INFO, + "Processing SYS MC STOP"); + + /* get the HAL context... */ + hHal = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal", __func__); + } else { + cdf_status = + sme_stop(hHal, + HAL_STOP_TYPE_SYS_DEEP_SLEEP); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS + (cdf_status)); + + cdf_status = + mac_stop(hHal, + HAL_STOP_TYPE_SYS_DEEP_SLEEP); + CDF_ASSERT(CDF_IS_STATUS_SUCCESS + (cdf_status)); + + ((sysResponseCback) pMsg-> + callback)((void *)pMsg->bodyptr); + + cdf_status = CDF_STATUS_SUCCESS; + } + break; + } + + /* Process MC thread probe. Just callback to the */ + /* function that is in the message. */ + case SYS_MSG_ID_MC_THR_PROBE: + { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + " Received SYS_MSG_ID_MC_THR_PROBE message msgType = %d [0x%08x]", + pMsg->type, pMsg->type); + break; + } + + case SYS_MSG_ID_MC_TIMER: + { + cdf_mc_timer_callback_t timerCB = + pMsg->callback; + + if (NULL != timerCB) { + timerCB(pMsg->bodyptr); + } + break; + } + case SYS_MSG_ID_FTM_RSP: + { + tpAniSirGlobal mac_ctx = NULL; + hHal = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + cdf_mem_free(pMsg->bodyptr); + break; + } + mac_ctx = PMAC_STRUCT(hHal); + if (NULL == mac_ctx) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + FL("Invalid mac context")); + cdf_mem_free(pMsg->bodyptr); + break; + } + if (NULL == mac_ctx->ftm_msg_processor_callback) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + FL("callback pointer is NULL")); + cdf_mem_free(pMsg->bodyptr); + break; + } + mac_ctx->ftm_msg_processor_callback( + (void *)pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; + } + + default: + { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + "Unknown message type in sys_mc_process_msg() msgType= %d [0x%08x]", + pMsg->type, pMsg->type); + break; + } + + } /* end switch on message type */ + + } /* end if cookie set */ + else { + /* Process all 'legacy' messages */ + switch (pMsg->type) { + + default: + { + CDF_ASSERT(0); + + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_ERROR, + "Received SYS message cookie with unidentified " + "MC message type= %d [0x%08X]", + pMsg->type, pMsg->type); + + cdf_status = CDF_STATUS_E_BADMSG; + if (pMsg->bodyptr) + cdf_mem_free(pMsg->bodyptr); + break; + } + } /* end switch on pMsg->type */ + } /* end else */ + + return (cdf_status); +} + + +void sys_process_mmh_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) { + CDS_MQ_ID targetMQ = CDS_MQ_ID_SYS; +/*-------------------------------------------------------------------------*/ + /* + ** The body of this pMsg is a tSirMbMsg + ** Contrary to Gen4, we cannot free it here! + ** It is up to the callee to free it + */ + + if (NULL == pMsg) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "NULL Message Pointer"); + CDF_ASSERT(0); + return; + } + + switch (pMsg->type) { + /* + ** Following messages are routed to SYS + */ + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + { + /* Forward this message to the SYS module */ + targetMQ = CDS_MQ_ID_SYS; + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed in SYS\r\n", + pMsg->type); + + CDF_ASSERT(0); + break; + } + + /* + ** Following messages are routed to HAL + */ + case WNI_CFG_DNLD_RSP: + { + /* Forward this message to the HAL module */ + targetMQ = CDS_MQ_ID_WMA; + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed as there is no HAL \r\n", + pMsg->type); + + CDF_ASSERT(0); + break; + } + + case WNI_CFG_GET_REQ: + case WNI_CFG_SET_REQ: + case WNI_CFG_SET_REQ_NO_RSP: + case eWNI_SME_SYS_READY_IND: + { + /* Forward this message to the PE module */ + targetMQ = CDS_MQ_ID_PE; + break; + } + + case WNI_CFG_GET_RSP: + case WNI_CFG_SET_CNF: + { + /* Forward this message to the SME module */ + targetMQ = CDS_MQ_ID_SME; + break; + } + + default: + { + + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + targetMQ = CDS_MQ_ID_SME; + break; + } + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Message of ID %d is not yet handled by SYS\r\n", + pMsg->type); + + CDF_ASSERT(0); + } + + } + + /* + ** Post now the message to the appropriate module for handling + */ + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(targetMQ, (cds_msg_t *) pMsg)) { + /* Caller doesn't allocate memory for the pMsg. It allocate memory for bodyptr */ + /* free the mem and return */ + if (pMsg->bodyptr) { + cdf_mem_free(pMsg->bodyptr); + } + } + +} /* sys_process_mmh_msg() */ + +void wlan_sys_probe(void) +{ + cds_msg_t cds_message; + + cds_message.reserved = SYS_MSG_COOKIE; + cds_message.type = SYS_MSG_ID_MC_THR_PROBE; + cds_message.bodyptr = NULL; + + cds_mq_post_message(CDS_MQ_ID_SYS, &cds_message); + + return; +} diff --git a/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h b/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h new file mode 100644 index 0000000000..6aeb635cd0 --- /dev/null +++ b/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * @file VossWrapper.h + * + * @brief This header file contains the various structure definitions and + * function prototypes for the RTOS abstraction layer, implemented for VOSS + */ + +#ifndef __VOSS_WRAPPER_H +#define __VOSS_WRAPPER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ + +#include "sir_types.h" +#include "sir_params.h" +#include "sys_def.h" +#include "cdf_mc_timer.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cdf_memory.h" + +/* Interlocked Compare Exchange related definitions */ + +/* Define basic constants for the ThreadX kernel. */ + +#define TX_NO_WAIT 0 +#define TX_WAIT_FOREVER 0xFFFFFFFFUL +#define TX_AUTO_ACTIVATE 1 +#define TX_NO_ACTIVATE 0 + +/* API return values. */ +#define TX_SUCCESS 0x00 +#define TX_QUEUE_FULL 0x01 +/* ... */ +#define TX_NO_INSTANCE 0x0D +/* ... */ +#define TX_TIMER_ERROR 0x15 +#define TX_TICK_ERROR 0x16 +/* ... */ + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +/* Following macro specifies the number of milliseconds which constitute 1 ThreadX timer tick. Used + for mimicking the ThreadX timer behaviour on VOSS. */ +/* Use the same MACRO used by firmware modules to calculate TICKs from mSec */ +/* Mismatch would cause worng timer value to be programmed */ +#define TX_MSECS_IN_1_TICK SYS_TICK_DUR_MS + +/* Signature with which the TX_TIMER struct is initialized, when the timer is created */ +#define TX_AIRGO_TMR_SIGNATURE 0xDEADBEEF + +#ifdef TIMER_MANAGER +#define tx_timer_create(a, b, c, d, e, f, g) tx_timer_create_intern_debug((void *)pMac, a, b, c, d, e, f, g, __FILE__, __LINE__) +#else +#define tx_timer_create(a, b, c, d, e, f, g) tx_timer_create_intern((void *)pMac, a, b, c, d, e, f, g) +#endif + +/*--------------------------------------------------------------------*/ +/* Timer structure */ +/* This structure is used to implement ThreadX timer facility. Just */ +/* like ThreadX, timer expiration handler executes at the highest */ +/* possible priority level, i.e. DISPATCH_LEVEL. */ +/*--------------------------------------------------------------------*/ +typedef struct TX_TIMER_STRUCT { +#ifdef WLAN_DEBUG +#define TIMER_MAX_NAME_LEN 50 + char timerName[TIMER_MAX_NAME_LEN]; +#endif + uint64_t tmrSignature; + void (*pExpireFunc)(void *, uint32_t); + uint32_t expireInput; + uint64_t initScheduleTimeInMsecs; + uint64_t rescheduleTimeInMsecs; + cdf_mc_timer_t cdf_timer; + + /* Pointer to the MAC global structure, which stores the context for the NIC, */ + /* for which this timer is supposed to operate. */ + void *pMac; + uint8_t sessionId; + +} TX_TIMER; + +#define TX_TIMER_VALID(timer) (timer.pMac != 0) + +extern uint64_t tx_time_get(void); +extern uint32_t tx_timer_activate(TX_TIMER *); +extern uint32_t tx_timer_change(TX_TIMER *, uint64_t, uint64_t); +extern uint32_t tx_timer_change_context(TX_TIMER *, uint32_t); +#ifdef TIMER_MANAGER +extern uint32_t tx_timer_create_intern_debug(void *, TX_TIMER *, + char *, void (*)(void *, + uint32_t), + uint32_t, uint64_t, + uint64_t, uint64_t, + char *fileName, + uint32_t lineNum); +#else +extern uint32_t tx_timer_create_intern(void *, TX_TIMER *, char *, + void (*)(void *, uint32_t), + uint32_t, uint64_t, uint64_t, + uint64_t); +#endif +extern uint32_t tx_timer_deactivate(TX_TIMER *); +extern uint32_t tx_timer_delete(TX_TIMER *); +extern bool tx_timer_running(TX_TIMER *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c b/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c new file mode 100644 index 0000000000..47499656cd --- /dev/null +++ b/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + @file VossWrapper.c + + @brief This source file contains the various function definitions for the + RTOS abstraction layer, implemented for VOSS + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + $Header:$ $DateTime: $ $Author: $ + + when who what, where, why + -------- --- -------------------------------------------------------- + 03/31/09 sho Remove the use of cdf_timerIsActive flag as it is not + thread-safe + 02/17/08 sho Fix the timer callback function to work when it is called + after the timer has stopped due to a race condition. + 02/10/08 sho Refactor the TX timer to use VOS timer directly instead + of using VOS utility timer + 12/15/08 sho Resolved errors and warnings from the AMSS compiler when + this is ported from WM + 11/20/08 sho Renamed this to VosWrapper.c; remove all dependencies on + WM platform and allow this to work on all VOSS enabled + platform + 06/24/08 tbh Modified the file to remove the dependecy on HDD files as + part of Gen6 bring up process. + 10/29/02 Neelay Das Created file. + + ===========================================================================*/ + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ +#include "sys_wrapper.h" + +#ifdef WLAN_DEBUG +#define TIMER_NAME (timer_ptr->timerName) +#else +#define TIMER_NAME "N/A" +#endif + +/**--------------------------------------------------------------------- + * tx_time_get() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return current system time in units of miliseconds + * + */ +uint64_t tx_time_get(void) +{ + return (cdf_mc_timer_get_system_ticks()); + +} /* * tx_time_get() */ + +/**--------------------------------------------------------------------- + * tx_timer_activate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_activate(TX_TIMER *timer_ptr) +{ + CDF_STATUS status; + + /* Uncomment the asserts, if the intention is to debug the occurence of the */ + /* following anomalous cnditions. */ + + /* Assert that the timer structure pointer passed, is not NULL */ + /* dbgAssert(NULL != timer_ptr); */ + + /* If the NIC is halting just spoof a successful timer activation, so that all */ + /* the timers can be cleaned up. */ + + if (NULL == timer_ptr) + return TX_TIMER_ERROR; + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + CDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + + } + /* Check for an uninitialized timer */ + CDF_ASSERT(0 != strlen(TIMER_NAME)); + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Timer %s being activated\n", TIMER_NAME); + + status = cdf_mc_timer_start(&timer_ptr->cdf_timer, + timer_ptr->initScheduleTimeInMsecs); + + if (CDF_STATUS_SUCCESS == status) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Timer %s now activated\n", TIMER_NAME); + return TX_SUCCESS; + } else if (CDF_STATUS_E_ALREADY == status) { + /* starting timer fails because timer is already started; this is okay */ + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Timer %s is already running\n", TIMER_NAME); + return TX_SUCCESS; + } else { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Timer %s fails to activate\n", TIMER_NAME); + return TX_TIMER_ERROR; + } +} /*** tx_timer_activate() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change(TX_TIMER *timer_ptr, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + CDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&timer_ptr->cdf_timer)) { + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change_context() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change_context(TX_TIMER *timer_ptr, + uint32_t expiration_input) +{ + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + CDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&timer_ptr->cdf_timer)) { + timer_ptr->expireInput = expiration_input; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_main_timer_func() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return None. + * + */ +static void tx_main_timer_func(void *functionContext) +{ + TX_TIMER *timer_ptr = (TX_TIMER *) functionContext; + + if (NULL == timer_ptr) { + CDF_ASSERT(0); + return; + } + + if (NULL == timer_ptr->pExpireFunc) { + CDF_ASSERT(0); + return; + } + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Timer %s triggered", TIMER_NAME); + + /* Now call the actual timer function, taking the function pointer, */ + /* from the timer structure. */ + (*timer_ptr->pExpireFunc)(timer_ptr->pMac, timer_ptr->expireInput); + + /* check if this needs to be rescheduled */ + if (0 != timer_ptr->rescheduleTimeInMsecs) { + CDF_STATUS status; + status = cdf_mc_timer_start(&timer_ptr->cdf_timer, + timer_ptr->rescheduleTimeInMsecs); + timer_ptr->rescheduleTimeInMsecs = 0; + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_WARN, + "Unable to reschedule timer %s; status=%d", + TIMER_NAME, status); + } + } +} /*** tx_timer_change() ***/ + +#ifdef TIMER_MANAGER +uint32_t tx_timer_create_intern_debug(void *pMacGlobal, + TX_TIMER *timer_ptr, char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate, char *fileName, + uint32_t lineNum) +{ + CDF_STATUS status; + + if (NULL == expiration_function) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "NULL timer expiration"); + CDF_ASSERT(0); + return TX_TIMER_ERROR; + } + + if (NULL == name_ptr) { + + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "NULL name pointer for timer"); + CDF_ASSERT(0); + return TX_TIMER_ERROR; + } + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->pMac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = + cdf_mc_timer_init_debug(&timer_ptr->cdf_timer, CDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr, + fileName, lineNum); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#else +uint32_t tx_timer_create_intern(void *pMacGlobal, TX_TIMER *timer_ptr, + char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate) +{ + CDF_STATUS status; + + if ((NULL == name_ptr) || (NULL == expiration_function)) + return TX_TIMER_ERROR; + + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->pMac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = cdf_mc_timer_init(&timer_ptr->cdf_timer, CDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#endif + +/**--------------------------------------------------------------------- + * tx_timer_deactivate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_deactivate(TX_TIMER *timer_ptr) +{ + CDF_STATUS vStatus; + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "tx_timer_deactivate() called for timer %s\n", TIMER_NAME); + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + /* if the timer is not running then we do not need to do anything here */ + vStatus = cdf_mc_timer_stop(&timer_ptr->cdf_timer); + if (CDF_STATUS_SUCCESS != vStatus) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO_HIGH, + "Unable to stop timer %s; status =%d\n", + TIMER_NAME, vStatus); + } + + return TX_SUCCESS; + +} /*** tx_timer_deactivate() ***/ + +uint32_t tx_timer_delete(TX_TIMER *timer_ptr) +{ + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "tx_timer_delete() called for timer %s\n", TIMER_NAME); + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + + cdf_mc_timer_destroy(&timer_ptr->cdf_timer); + return TX_SUCCESS; +} /*** tx_timer_delete() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_running() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +bool tx_timer_running(TX_TIMER *timer_ptr) +{ + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, + "tx_timer_running() called for timer %s\n", TIMER_NAME); + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) + return false; + + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&timer_ptr->cdf_timer)) { + return true; + } + return false; + +} /*** tx_timer_running() ***/ diff --git a/core/mac/src/sys/legacy/src/system/inc/sys_debug.h b/core/mac/src/sys/legacy/src/system/inc/sys_debug.h new file mode 100644 index 0000000000..4a2578885d --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/inc/sys_debug.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_global.h contains the logDump utility for system module. + * Author: V. K. Kandarpa + * Date: 01/24/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __SYS_DEBUG_H__ +#define __SYS_DEBUG_H__ + +#include +#include "utils_api.h" +#include "sir_debug.h" +#include "sir_params.h" + +void sys_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...); + +#endif /* __SYS_DEBUG_H__ */ diff --git a/core/mac/src/sys/legacy/src/system/inc/sys_def.h b/core/mac/src/sys/legacy/src/system/inc/sys_def.h new file mode 100644 index 0000000000..abdae33dc1 --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/inc/sys_def.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_def.h contains the common definitions used to bring up + * Sirius system. + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SYSDEF_H +#define __SYSDEF_H + +/* / Sirius system level definitions */ +/* NOTE: Do not program system timer tick duration to less than 1msec */ + +/* / System timer tick duration in nanoseconds */ +#define SYS_TICK_DUR_NS 10000000 /* 10ms */ +#define SYS_TICK_TO_MICRO_SECOND 10000 + +/* / System timer tick duration in milliseconds */ +#define SYS_TICK_DUR_MS (SYS_TICK_DUR_NS/1000000) + +/* / Clocks in a millisecond */ +#define SYS_CLOCKS_PER_MS 120000 /* 120 MHz */ + +/* / System timer tick duration in clocks */ +#define SYS_TICK_DUR_CLK (SYS_TICK_DUR_MS * SYS_CLOCKS_PER_MS) + +/* / Number of timer ticks in a second */ +#define SYS_TICKS_PER_SECOND (1000/SYS_TICK_DUR_MS) + +/* / Macro to convert MS to Ticks */ +#define SYS_MS_TO_TICKS(x) ((x) / SYS_TICK_DUR_MS) + +/* / Macro to convert Seconds to Ticks */ +#define SYS_SEC_TO_TICKS(x) ((x) * SYS_TICKS_PER_SECOND) + +/* / Macro to convert Minutes to Ticks */ +#define SYS_MIN_TO_TICKS(x) (((x) * 60) * SYS_TICKS_PER_SECOND) + +/* / MNT task processing interval in seconds */ +#define SYS_MNT_INTERVAL 60 + +/* / MS to Time Units */ +#define SYS_MS_TO_TU(x) ((x * 1000) >> 10) + +/* / TU to MS */ +#define SYS_TU_TO_MS(x) ((x << 10) / 1000) + +/* --------- End of Windows & RTAI ----------- */ + +/* / Message queue definitions */ + +/* / gHalMsgQ */ +#define SYS_HAL_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHhiPriorityMsgQ */ +#define SYS_MMH_HI_PRI_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHprotocolMsgQ */ +#define SYS_MMH_PROT_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / gMMHdebugMsgQ */ +#define SYS_MMH_DEBUG_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / gMAINTmsgQ */ +#define SYS_MNT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / LIM Message Queue */ +#define SYS_LIM_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / Scheduler Message Queue */ +#define SYS_SCH_Q_SIZE 800 /* Holds up to 25 messages */ + +/* / PMM Message Queue */ +#define SYS_PMM_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / TX Message Queue */ +#define SYS_TX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / RX Message Queue */ +#define SYS_RX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / PTT Message Queue */ +#define SYS_NIM_PTT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / Thread definitions */ +/* tHAL */ + +#define SYS_HAL_THREAD_ENTRY_FUNCTION halEntry +#define SYS_HAL_STACK_SIZE 8192 +#define SYS_HAL_THREAD_PRIORITY 2 + +/* tDPH */ + +#define SYS_DPH_THREAD_ENTRY_FUNCTION dphEntry +#define SYS_DPH_STACK_SIZE 8192 +#define SYS_DPH_THREAD_PRIORITY 15 + +/* tBBT */ + +#define SYS_BBT_THREAD_ENTRY_FUNCTION bbtEntry +#define SYS_BBT_STACK_SIZE 8192 +#define SYS_BBT_THREAD_PRIORITY 16 + +/* tSCH */ + +#define SYS_SCH_STACK_SIZE 8192 +#define SYS_SCH_THREAD_PRIORITY 17 + +/* tPMM */ + +#define SYS_PMM_STACK_SIZE 8192 +#define SYS_PMM_THREAD_PRIORITY 17 + +/* tLIM */ + +#define SYS_LIM_THREAD_ENTRY_FUNCTION limEntry +#define SYS_LIM_STACK_SIZE 8192 +#define SYS_LIM_THREAD_PRIORITY 18 + +/* tMAINT */ + +#define SYS_MNT_THREAD_ENTRY_FUNCTION mntEntry +#define SYS_MNT_STACK_SIZE 8192 +#define SYS_MNT_THREAD_PRIORITY 25 + +/* tMMH */ + +#define SYS_MMH_THREAD_ENTRY_FUNCTION mmhEntry +#define SYS_MMH_STACK_SIZE 8192 +#define SYS_MMH_THREAD_PRIORITY 10 + +/* tNIM_MNT_PKT_GEN */ + +#define SYS_NIM_PTT_THREAD_STACK_SIZE 8192 +#define SYS_NIM_PTT_THREAD_PRIORITY 28 + +#endif /* __SYSDEF_H */ diff --git a/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h b/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h new file mode 100644 index 0000000000..41afc8bdfd --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_entry_func.h contains module entry functions definitions + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __SYS_ENTRY_FUNC_H +#define __SYS_ENTRY_FUNC_H + +#include "ani_global.h" + +extern tSirRetStatus sys_init_globals(tpAniSirGlobal); +extern void sysBbtEntry(uint32_t dummy); +extern void sysSchEntry(uint32_t dummy); +extern void sysPmmEntry(uint32_t dummy); +extern void sysDphEntry(uint32_t dummy); +extern void sysLimEntry(uint32_t dummy); +extern void sysMmhEntry(uint32_t dummy); +extern void sysMntEntry(uint32_t dummy); +extern void sysHalEntry(uint32_t dummy); +extern void sysNimPttEntry(uint32_t dummy); + +#endif /* __SYS_ENTRY_FUNC_H */ diff --git a/core/mac/src/sys/legacy/src/system/inc/sys_startup.h b/core/mac/src/sys/legacy/src/system/inc/sys_startup.h new file mode 100644 index 0000000000..e56bd6193d --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/inc/sys_startup.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * sys_startup.h: System startup header file. + * Author: V. K. Kandarpa + * Date: 01/29/2002 + * + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ + +#ifndef __SYSSTARTUP_H +#define __SYSSTARTUP_H + +#include "sir_params.h" + +/* Defines */ + +/* Function */ + +extern void sysMACCleanup(void *); +extern tSirRetStatus sys_bbt_process_message_core(struct sAniSirGlobal *, tpSirMsgQ, + uint32_t, uint32_t); + +#endif /* __SYSSTARTUP_H */ diff --git a/core/mac/src/sys/legacy/src/system/src/mac_init_api.c b/core/mac/src/sys/legacy/src/system/src/mac_init_api.c new file mode 100644 index 0000000000..5c0877a906 --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/src/mac_init_api.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * mac_init_api.c - This file has all the mac level init functions + * for all the defined threads at system level. + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date: 04/08/2008 Modified by: Santosh Mandiganal + * Modification Information: Code to allocate and free the memory for DumpTable entry. + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ +#include "cfg_api.h" /* cfg_cleanup */ +#include "lim_api.h" /* lim_cleanup */ +#include "sir_types.h" +#include "sys_debug.h" +#include "sys_entry_func.h" +#include "mac_init_api.h" + +#ifdef TRACE_RECORD +#include "mac_trace.h" +#endif + +extern tSirRetStatus halDoCfgInit(tpAniSirGlobal pMac); +extern tSirRetStatus halProcessStartEvent(tpAniSirGlobal pMac); + +tSirRetStatus mac_start(tHalHandle hHal, void *pHalMacStartParams) +{ + tSirRetStatus status = eSIR_SUCCESS; + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + + if (NULL == pMac) { + CDF_ASSERT(0); + status = eSIR_FAILURE; + return status; + } + + pMac->gDriverType = + ((tHalMacStartParameters *) pHalMacStartParams)->driverType; + + sys_log(pMac, LOG2, FL("called\n")); + + if (ANI_DRIVER_TYPE(pMac) != eDRIVER_TYPE_MFG) { + status = pe_start(pMac); + } + + return status; +} + +/** ------------------------------------------------------------- + \fn mac_stop + \brief this function will be called from HDD to stop MAC. This function will stop all the mac modules. + \ memory with global context will only be initialized not freed here. + \param tHalHandle hHal + \param tHalStopType + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus mac_stop(tHalHandle hHal, tHalStopType stopType) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + pe_stop(pMac); + cfg_cleanup(pMac); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn mac_open + \brief this function will be called during init. This function is suppose to allocate all the + \ memory with the global context will be allocated here. + \param tHalHandle pHalHandle + \param tHddHandle hHdd + \param tHalOpenParameters* pHalOpenParams + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus mac_open(tHalHandle *pHalHandle, tHddHandle hHdd, + tMacOpenParameters *pMacOpenParms) +{ + tpAniSirGlobal p_mac = NULL; + tSirRetStatus status = eSIR_SUCCESS; + + if (pHalHandle == NULL) + return eSIR_FAILURE; + + /* + * Make sure this adapter is not already opened. (Compare pAdapter pointer in already + * allocated p_mac structures.) + * If it is opened just return pointer to previously allocated p_mac pointer. + * Or should this result in error? + */ + + /* Allocate p_mac */ + p_mac = cdf_mem_malloc(sizeof(tAniSirGlobal)); + if (NULL == p_mac) + return eSIR_MEM_ALLOC_FAILED; + + /* Initialize the p_mac structure */ + cdf_mem_set(p_mac, sizeof(tAniSirGlobal), 0); + + /* + * Set various global fields of p_mac here + * (Could be platform dependant as some variables in p_mac are platform + * dependant) + */ + p_mac->hHdd = hHdd; + *pHalHandle = (tHalHandle) p_mac; + + { + /* Call various PE (and other layer init here) */ + if (eSIR_SUCCESS != log_init(p_mac)) { + cdf_mem_free(p_mac); + return eSIR_FAILURE; + } + + /* Call routine to initialize CFG data structures */ + if (eSIR_SUCCESS != cfg_init(p_mac)) { + cdf_mem_free(p_mac); + return eSIR_FAILURE; + } + + sys_init_globals(p_mac); + } + + /* FW: 0 to 2047 and Host: 2048 to 4095 */ + p_mac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + p_mac->first_scan_done = false; + + status = pe_open(p_mac, pMacOpenParms); + if (eSIR_SUCCESS != status) { + sys_log(p_mac, LOGE, FL("mac_open failure\n")); + cdf_mem_free(p_mac); + } + + return status; +} + +/** ------------------------------------------------------------- + \fn mac_close + \brief this function will be called in shutdown sequence from HDD. All the + \ allocated memory with global context will be freed here. + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +tSirRetStatus mac_close(tHalHandle hHal) +{ + + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + + if (!pMac) + return eSIR_FAILURE; + + pe_close(pMac); + + /* Call routine to free-up all CFG data structures */ + cfg_de_init(pMac); + + log_deinit(pMac); + + /* Finally, de-allocate the global MAC datastructure: */ + cdf_mem_free(pMac); + + return eSIR_SUCCESS; +} diff --git a/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c new file mode 100644 index 0000000000..304ab3e8f7 --- /dev/null +++ b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * sys_entry_func.cc - This file has all the system level entry functions + * for all the defined threads at system level. + * Author: V. K. Kandarpa + * Date: 01/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ + +/* Application Specific include files */ +#include "sir_common.h" +#include "ani_global.h" + +#include "lim_api.h" +#include "sch_api.h" +#include "utils_api.h" + +#include "sys_debug.h" +#include "sys_def.h" +#include "sys_entry_func.h" +#include "sys_startup.h" +#include "lim_trace.h" +#include "wma_types.h" + +tSirRetStatus postPTTMsgApi(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +#include "cdf_types.h" +#include "cds_packet.h" + +#define MAX_DEAUTH_ALLOWED 5 +/* --------------------------------------------------------------------------- */ +/** + * sys_init_globals + * + * FUNCTION: + * Initializes system level global parameters + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param tpAniSirGlobal Sirius software parameter struct pointer + * @return None + */ + +tSirRetStatus sys_init_globals(tpAniSirGlobal pMac) +{ + + cdf_mem_set((uint8_t *) &pMac->sys, sizeof(pMac->sys), 0); + + pMac->sys.gSysEnableScanMode = 1; + pMac->sys.gSysEnableLinkMonitorMode = 0; + sch_init_globals(pMac); + + return eSIR_SUCCESS; +} + +/** + * sys_bbt_process_message_core() - to process BBT messages + * @mac_ctx: pointer to mac context + * @msg: message pointer + * @type: type of persona + * @subtype: subtype of persona + * + * This routine is to process some bbt messages + * + * Return: None + */ +tSirRetStatus +sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, + uint32_t type, uint32_t subtype) +{ + uint32_t framecount; + tSirRetStatus ret; + void *bd_ptr; + tMgmtFrmDropReason dropreason; + cds_pkt_t *vos_pkt = (cds_pkt_t *) msg->bodyptr; + CDF_STATUS cdf_status = + wma_ds_peek_rx_packet_info(vos_pkt, &bd_ptr, false); + uint8_t sessionid; + tpPESession pe_session; + tpSirMacMgmtHdr mac_hdr; + + mac_ctx->sys.gSysBbtReceived++; + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + goto fail; + + sys_log(mac_ctx, LOG3, FL("Rx Mgmt Frame Subtype: %d\n"), subtype); + sir_dump_buf(mac_ctx, SIR_SYS_MODULE_ID, LOG3, + (uint8_t *) WMA_GET_RX_MAC_HEADER(bd_ptr), + WMA_GET_RX_MPDU_LEN(bd_ptr)); + sir_dump_buf(mac_ctx, SIR_SYS_MODULE_ID, LOG3, + WMA_GET_RX_MPDU_DATA(bd_ptr), + WMA_GET_RX_PAYLOAD_LEN(bd_ptr)); + + mac_ctx->sys.gSysFrameCount[type][subtype]++; + framecount = mac_ctx->sys.gSysFrameCount[type][subtype]; + + if (type == SIR_MAC_MGMT_FRAME) { + if (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + pe_session = pe_find_session_by_bssid(mac_ctx, + mac_hdr->bssId, + &sessionid); + if (pe_session && + (pe_session->pePersona == CDF_SAP_MODE)) { + CDF_TRACE(CDF_MODULE_ID_SYS, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("CAC timer is running, dropping the mgmt frame")); + goto fail; + } + } + + /* + * Drop beacon frames in deferred state to avoid VOSS run out of + * message wrappers. + */ + if ((subtype == SIR_MAC_MGMT_BEACON) && + (!lim_is_system_in_scan_state(mac_ctx)) && + (GET_LIM_PROCESS_DEFD_MESGS(mac_ctx) != true) && + !mac_ctx->lim.gLimSystemInScanLearnMode) { + CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO_HIGH, + FL("dropping received beacon in deffered state")); + goto fail; + } + + dropreason = lim_is_pkt_candidate_for_drop(mac_ctx, bd_ptr, + subtype); + if (eMGMT_DROP_NO_DROP != dropreason) { + sys_log(mac_ctx, LOG1, + FL("Mgmt Frame %d being dropped, reason: %d\n"), + subtype, dropreason); + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_DROP, NO_SESSION, + dropreason);) + goto fail; + } + + if (subtype == SIR_MAC_MGMT_DEAUTH) { + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + sys_log(mac_ctx, LOGE, + FL("DEAUTH frame allowed: " + "da: " MAC_ADDRESS_STR ", " + "sa: " MAC_ADDRESS_STR ", " + "bssid: " MAC_ADDRESS_STR ", " + "DEAUTH count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DISASSOC) { + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + sys_log(mac_ctx, LOGE, + FL("DISASSOC frame allowed: " + "da: " MAC_ADDRESS_STR ", " + "sa: " MAC_ADDRESS_STR ", " + "bssid: " MAC_ADDRESS_STR ", " + "DISASSOC count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + + /* Post the message to PE Queue */ + ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); + if (ret != eSIR_SUCCESS) { + sys_log(mac_ctx, LOGE, + FL("posting to LIM2 failed, ret %d\n"), ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; + } else if (type == SIR_MAC_DATA_FRAME) { +#ifdef FEATURE_WLAN_ESE + PELOGW(sys_log(mac_ctx, LOGW, FL("IAPP Frame...\n"));); + /* Post the message to PE Queue */ + ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); + if (ret != eSIR_SUCCESS) { + sys_log(mac_ctx, LOGE, + FL("posting to LIM2 failed, ret %d\n"), ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; +#endif + } else { + sys_log(mac_ctx, LOG3, + "BBT received Invalid type %d subtype %d " + "LIM state %X. BD dump is:\n", type, subtype, + lim_get_sme_state(mac_ctx)); + goto fail; + } + return eSIR_SUCCESS; +fail: + mac_ctx->sys.gSysBbtDropped++; + return eSIR_FAILURE; +} + +void sys_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_SYS_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_SYS_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +} diff --git a/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h b/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h new file mode 100644 index 0000000000..8cc4e97899 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +#define DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +/** + * \file dot11fdefs.h + * + * \brief C defines customizing our framesc-generated code + * + * + * + * + * 'framesc' generates code written in terms of a number of macros + * intended for customization. + * + * + */ + +#include "parser_api.h" + +/* This controls how the "dot11f" code copies memory */ +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + cdf_mem_copy((uint8_t *)(dst), (uint8_t *)(src), (len)) + +/* This controls how the "dot11f" code compares memory */ +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + (!cdf_mem_compare((uint8_t *)(lhs), (uint8_t *)(rhs), (len))) + +#if defined(DBG) && (DBG != 0) + +# /* define DOT11F_ENABLE_LOGGING */ +# /* define DOT11F_DUMP_FRAMES */ +#define DOT11F_LOG_GATE (4) +#define FRAMES_SEV_FOR_FRAME(ctx, sig) \ + (DOT11F_ASSOCREQUEST == (sig) ? 3 : 5) + +#if defined(DOT11F_ENABLE_LOGGING) + +#define DOT11F_HAVE_LOG_MACROS + +#define FRAMES_LOG0(ctx, sev, fmt) \ + dot11f_log((ctx), (sev), (fmt)); + +#define FRAMES_LOG1(ctx, sev, fmt, p1) \ + dot11f_log((ctx), (sev), (fmt), (p1)); + +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) \ + dot11f_log((ctx), (sev), (fmt), (p1), (p2)); + +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) \ + dot11f_log((ctx), (sev), (fmt), (p1), (p2), (p3)); + +#define FRAMES_DUMP(ctx, sev, p, n) \ + sir_dump_buf((pCtx), SIR_DBG_MODULE_ID, (sev), (p), (n)); + +#endif /* #if defined( DOT11F_ENABLE_LOGGING ) */ + +#else + +#undef DOT11F_ENABLE_LOGGING +#undef DOT11F_DUMP_FRAMES +#define DOT11F_LOG_GATE (1) + +#endif + +/* #define DOT11F_ENABLE_DBG_BREAK ( 1 ) */ + +/* Local Variables: */ +/* fill-column: 72 */ +/* indent-tabs-mode: nil */ +/* show-trailing-whitespace: t */ +/* End: */ + +#endif /* DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 */ diff --git a/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h b/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h new file mode 100644 index 0000000000..3b63a0df73 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file utils_parser.h contains the utility function protos + * used internally by the parser + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __UTILS_PARSE_H__ +#define __UTILS_PARSE_H__ + +#include +#include "sir_api.h" +#include "dot11f.h" +#include "utils_api.h" + +void convert_ssid(tpAniSirGlobal, tSirMacSSid *, tDot11fIESSID *); +void convert_supp_rates(tpAniSirGlobal, tSirMacRateSet *, tDot11fIESuppRates *); +void convert_fh_params(tpAniSirGlobal, tSirMacFHParamSet *, + tDot11fIEFHParamSet *); +void convert_ext_supp_rates(tpAniSirGlobal, tSirMacRateSet *, + tDot11fIEExtSuppRates *); +void convert_qos_caps(tpAniSirGlobal, tSirMacQosCapabilityIE *, + tDot11fIEQOSCapsAp *); +void convert_qos_caps_station(tpAniSirGlobal, tSirMacQosCapabilityStaIE *, + tDot11fIEQOSCapsStation *); +tSirRetStatus convert_wpa(tpAniSirGlobal, tSirMacWpaInfo *, tDot11fIEWPA *); +tSirRetStatus convert_wpa_opaque(tpAniSirGlobal, tSirMacWpaInfo *, + tDot11fIEWPAOpaque *); +tSirRetStatus convert_wapi_opaque(tpAniSirGlobal, tSirMacWapiInfo *, + tDot11fIEWAPIOpaque *); +tSirRetStatus convert_rsn(tpAniSirGlobal, tSirMacRsnInfo *, tDot11fIERSN *); +tSirRetStatus convert_rsn_opaque(tpAniSirGlobal, tSirMacRsnInfo *, + tDot11fIERSNOpaque *); +void convert_power_caps(tpAniSirGlobal, tSirMacPowerCapabilityIE *, + tDot11fIEPowerCaps *); +void convert_supp_channels(tpAniSirGlobal, tSirMacSupportedChannelIE *, + tDot11fIESuppChannels *); +void convert_cf_params(tpAniSirGlobal, tSirMacCfParamSet *, tDot11fIECFParams *); +void convert_tim(tpAniSirGlobal, tSirMacTim *, tDot11fIETIM *); +void convert_country(tpAniSirGlobal, tSirCountryInformation *, + tDot11fIECountry *); +void convert_wmm_params(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEWMMParams *); +void convert_erp_info(tpAniSirGlobal, tSirMacErpInfo *, tDot11fIEERPInfo *); +void convert_edca_param(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEEDCAParamSet *); +void convert_tspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIETSPEC *); +tSirRetStatus convert_tclas(tpAniSirGlobal, tSirTclasInfo *, tDot11fIETCLAS *); +void convert_wmmtspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIEWMMTSPEC *); +tSirRetStatus convert_wmmtclas(tpAniSirGlobal, tSirTclasInfo *, + tDot11fIEWMMTCLAS *); +void convert_ts_delay(tpAniSirGlobal, tSirMacTsDelayIE *, tDot11fIETSDelay *); +void convert_schedule(tpAniSirGlobal, tSirMacScheduleIE *, tDot11fIESchedule *); +void convert_wmm_schedule(tpAniSirGlobal, tSirMacScheduleIE *, + tDot11fIEWMMSchedule *); +tSirRetStatus convert_wsc_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWscIEOpaque *); +tSirRetStatus convert_p2p_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEP2PIEOpaque *); +#ifdef WLAN_FEATURE_WFD +tSirRetStatus convert_wfd_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWFDIEOpaque *); +#endif +void convert_qos_mapset_frame(tpAniSirGlobal, tSirQosMapSet *, + tDot11fIEQosMapSet *); + +#endif diff --git a/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/core/mac/src/sys/legacy/src/utils/src/dot11f.c new file mode 100644 index 0000000000..6286a01928 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -0,0 +1,21682 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + /* + * \file dot11f.c + * + * \brief Structures, functions & definitions for + * working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Wed Oct 14 10:14:42 2015 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + */ + +#if !defined ANI_OS_TYPE_OSX && !defined ANI_OS_TYPE_LINUX && !defined ANI_OS_TYPE_ANDROID +#include /* For memcpy */ +#include /* For _vsnprintf */ +#include /* For offsetof */ +#endif + +#include +#include +#include "dot11fdefs.h" +#include "dot11f.h" + +#if defined(_MSC_VER) +#pragma warning (disable:4244) +#pragma warning (disable:4505) +#pragma warning (disable:4702) +#pragma warning (disable:4996)/* ... was declared deprecated */ +#endif /* Microsoft C/C++ */ + +typedef unsigned char tFRAMES_BOOL; +typedef void (*pfnGeneric_t)(void); + +typedef struct sFFDefn { + const char *name; + uint32_t offset; + uint16_t sig; + uint8_t size; +} tFFDefn; + +typedef struct sIEDefn { + uint32_t offset; + uint32_t presenceOffset; + uint32_t countOffset; + const char *name; + uint16_t arraybound; + uint16_t minSize; + uint16_t maxSize; + uint16_t sig; + unsigned char oui[5]; + unsigned char noui; + uint8_t eid; + tFRAMES_BOOL fMandatory; +} tIEDefn; + +#if !defined(countof) +#define countof(x) (sizeof((x)) / sizeof((x)[0])) +#endif + +#if !defined(DOT11F_MEMCPY) +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + memcpy((dst), (src), (len)) +#endif + +#if !defined(DOT11F_MEMCMP) +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + memcmp((lhs), (rhs), (len)) +#endif + +#ifndef DOT11F_HAVE_LOG_SEVERITIES +#define FRLOG_OFF (0) +#define FRLOGP (1) +#define FRLOGE (2) +#define FRLOGW (3) +#define FRLOG1 (4) +#define FRLOG2 (5) +#define FRLOG3 (6) +#define FRLOG4 (7) +#endif + +#define FRFL(x) x + +#define FRAMES_LOG0(ctx, sev, fmt) +#define FRAMES_LOG1(ctx, sev, fmt, p1) +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) +#define FRAMES_DUMP(ctx, sev, p, n) +#ifndef FRAMES_SEV_FOR_FRAME +#define FRAMES_SEV_FOR_FRAME(ctx, sig) FRLOG3 +#endif + +#if defined(DOT11F_ENABLE_DBG_BREAK) && defined (WIN32) +#define FRAMES_DBG_BREAK() { _asm int 3 } +#else +#define FRAMES_DBG_BREAK() +#endif + +#if !defined(DOT11F_PARAMETER_CHECK) +#if defined (DOT11F_HAVE_WIN32_API) + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + if (!pBuf || IsBadReadPtr(pBuf, nBuf))\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm || IsBadWritePtr(pFrm, nFrm))\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + if (!pSrc || IsBadReadPtr(pSrc, 4))\ + eturn DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf || IsBadWritePtr(pBuf, nBuf))\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (IsBadWritePtr(pnConsumed, 4))\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#else + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + if (!pBuf)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + if (!pSrc)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!pnConsumed)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#endif +#endif + +static void framesntohs(tpAniSirGlobal pCtx, + uint16_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); + else + *pOut = (uint16_t)(*pIn << 8) | *(pIn + 1); +#else + if (!fMsb) + *pOut = (uint16_t)(*pIn | (*(pIn + 1) << 8)); + else + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); +#endif +} + +static void framesntohl(tpAniSirGlobal pCtx, + uint32_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint32_t *)pOut, pIn, 4); + else + *pOut = (uint32_t)(*pIn << 24) | + (*(pIn + 1) << 16) | + (*(pIn + 2) << 8) | + (*(pIn + 3)); +#else + if (!fMsb) + *pOut = (uint32_t)(*(pIn + 3) << 24) | + (*(pIn + 2) << 16) | + (*(pIn + 1) << 8) | + (*(pIn)); +else + *pOut = *(uint32_t *)pIn; +#endif +} + +static void framesntohq(tpAniSirGlobal pCtx, + tDOT11F_U64 *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + framesntohl(pCtx, &((*pOut)[0]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[1]), pIn + 4, fMsb); +#else + framesntohl(pCtx, &((*pOut)[1]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[0]), pIn + 4, fMsb); +#endif +} + +static void frameshtons(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint16_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } else { + *pOut = (pIn & 0xff00) >> 8; + *(pOut + 1) = pIn & 0xff; + } +#else + if (!fMsb) { + *pOut = pIn & 0xff; + *(pOut + 1) = (pIn & 0xff00) >> 8; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } +#endif +} + +static void frameshtonl(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint32_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } else { + *pOut = (pIn & 0xff000000) >> 24; + *(pOut + 1) = (pIn & 0x00ff0000) >> 16; + *(pOut + 2) = (pIn & 0x0000ff00) >> 8; + *(pOut + 3) = (pIn & 0x000000ff); + } +#else + if (!fMsb) { + *pOut = (pIn & 0x000000ff); + *(pOut + 1) = (pIn & 0x0000ff00) >> 8; + *(pOut + 2) = (pIn & 0x00ff0000) >> 16; + *(pOut + 3) = (pIn & 0xff000000) >> 24; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } +#endif +} + +static void frameshtonq(tpAniSirGlobal pCtx, + uint8_t *pOut, + tDOT11F_U64 pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + frameshtonl(pCtx, pOut, pIn[0], fMsb); + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); +#else + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); + frameshtonl(pCtx, pOut, pIn[0], fMsb); +#endif +} + +static const tIEDefn *find_ie_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + (void)pCtx; + + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + if (*pBuf == pIe->eid) { + if (0 == pIe->noui) + return pIe; + + if ((nBuf > (uint32_t)(pIe->noui + 2)) && + (!DOT11F_MEMCMP(pCtx, pBuf + 2, pIe->oui, + pIe->noui))) + return pIe; + } + + ++pIe; + } + + return NULL; +} + +static uint32_t get_container_ies_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + uint8_t *pnConsumed, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe, *pIeFirst; + uint8_t *pBufRemaining = pBuf; + uint8_t len = 0; + (void)pCtx; + + pIeFirst = &(IEs[0]); + + if (*pBufRemaining != pIeFirst->eid) + return DOT11F_INTERNAL_ERROR; + len += *(pBufRemaining+1); + pBufRemaining += len + 2; + len += 2; + while (len < nBuf) { + pIe = find_ie_defn(pCtx, pBufRemaining, nBuf + len, IEs); + if (NULL == pIe) + break; + if (pIe->eid == pIeFirst->eid) + break; + len += *(pBufRemaining + 1) + 2; + pBufRemaining += *(pBufRemaining + 1) + 2; + } + + *pnConsumed = len; + return DOT11F_PARSE_SUCCESS; + +} + + +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm); +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]); +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]); + +uint32_t dot11f_unpack_tlv_common_func(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint16_t tlvlen, uint8_t *pDstPresent, + uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_common_func. */ + +uint32_t dot11f_unpack_tlv_common_func2(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint16_t tlvlen, uint8_t *pDstPresent, + uint16_t *pDstState) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + framesntohs(pCtx, pDstState, pBuf, 1); + (void)pCtx; + return status; + +} /* End dot11f_unpack_tlv_common_func2. */ + +void dot11f_unpack_ff_common_func(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint16_t *pDstField) +{ + framesntohs(pCtx, pDstField, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_common_func. */ + +uint32_t dot11f_unpack_ie_common_func(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint8_t ielen, uint8_t *pDstPresent , + uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)ielen; + (void)pBuf; + if ((*pDstPresent)) + status = DOT11F_DUPLICATE_IE; + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + + return status; +} /* End dot11f_unpack_ie_common_func */ + +typedef struct sTLVDefn { + uint32_t offset; + uint32_t presenceOffset; + const char *name; + uint16_t sig; + uint32_t id; + uint32_t pec; + uint32_t minSize; + uint32_t maxSize; + uint8_t fMandatory; + uint8_t sType; + uint8_t sLen; + uint8_t fMsb; +} tTLVDefn; + +static const tTLVDefn *find_tlv_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t pec; + uint16_t id; + + pTlv = &(TLVs[0]); + (void)pCtx; + if (pTlv->sType == 2) + framesntohs(pCtx, &id, pBuf, 1); + else + id = *pBuf; + + while (0xffff != pTlv->id) { + if (id == pTlv->id) { + if (0 == pTlv->pec) + return pTlv; + + if (nBuf > 5) { + pec = ((*(pBuf + 4)) << 16) | + ((*(pBuf + 5)) << 8) | + *(pBuf + 6); + if (pec == pTlv->pec) + return pTlv; + } + } + + ++pTlv; + } + + return NULL; +} + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm); +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx); +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]); + +#define SigFfAID (0x0001) + +void dot11f_unpack_ff_action(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfAction *pDst) +{ + pDst->action = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_action. */ + +#define SigFfAction (0x0002) + +#define SigFfAuthAlgo (0x0003) + +#define SigFfAuthSeqNo (0x0004) + +#define SigFfBeaconInterval (0x0005) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCapabilities *pDst) +{ + uint16_t tmp0__; + framesntohs(pCtx, &tmp0__, pBuf, 0); + pDst->ess = tmp0__ >> 0 & 0x1; + pDst->ibss = tmp0__ >> 1 & 0x1; + pDst->cfPollable = tmp0__ >> 2 & 0x1; + pDst->cfPollReq = tmp0__ >> 3 & 0x1; + pDst->privacy = tmp0__ >> 4 & 0x1; + pDst->shortPreamble = tmp0__ >> 5 & 0x1; + pDst->pbcc = tmp0__ >> 6 & 0x1; + pDst->channelAgility = tmp0__ >> 7 & 0x1; + pDst->spectrumMgt = tmp0__ >> 8 & 0x1; + pDst->qos = tmp0__ >> 9 & 0x1; + pDst->shortSlotTime = tmp0__ >> 10 & 0x1; + pDst->apsd = tmp0__ >> 11 & 0x1; + pDst->rrm = tmp0__ >> 12 & 0x1; + pDst->dsssOfdm = tmp0__ >> 13 & 0x1; + pDst->delayedBA = tmp0__ >> 14 & 0x1; + pDst->immediateBA = tmp0__ >> 15 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_capabilities. */ + +#define SigFfCapabilities (0x0006) + +void dot11f_unpack_ff_category(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCategory *pDst) +{ + pDst->category = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_category. */ + +#define SigFfCategory (0x0007) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCurrentAPAddress *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + (void)pCtx; +} /* End dot11f_unpack_ff_current_ap_address. */ + +#define SigFfCurrentAPAddress (0x0008) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfDialogToken *pDst) +{ + pDst->token = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_dialog_token. */ + +#define SigFfDialogToken (0x0009) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfLinkMargin *pDst) +{ + pDst->linkMargin = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_link_margin. */ + +#define SigFfLinkMargin (0x000a) + +#define SigFfListenInterval (0x000b) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfMaxTxPower *pDst) +{ + pDst->maxTxPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_max_tx_power. */ + +#define SigFfMaxTxPower (0x000c) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfNumOfRepetitions *pDst) +{ + framesntohs(pCtx, &pDst->repetitions, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_num_of_repetitions. */ + +#define SigFfNumOfRepetitions (0x000d) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfOperatingMode *pDst) +{ + uint8_t tmp1__; + tmp1__ = *pBuf; + pDst->chanWidth = tmp1__ >> 0 & 0x3; + pDst->reserved = tmp1__ >> 2 & 0x3; + pDst->rxNSS = tmp1__ >> 4 & 0x7; + pDst->rxNSSType = tmp1__ >> 7 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_operating_mode. */ + +#define SigFfOperatingMode (0x000e) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRCPI *pDst) +{ + pDst->rcpi = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rcpi. */ + +#define SigFfRCPI (0x000f) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRSNI *pDst) +{ + pDst->rsni = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rsni. */ + +#define SigFfRSNI (0x0010) + +#define SigFfReason (0x0011) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rx_antenna_id. */ + +#define SigFfRxAntennaId (0x0012) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfSMPowerModeSet *pDst) +{ + uint8_t tmp2__; + tmp2__ = *pBuf; + pDst->PowerSave_En = tmp2__ >> 0 & 0x1; + pDst->Mode = tmp2__ >> 1 & 0x1; + pDst->reserved = tmp2__ >> 2 & 0x3f; + (void)pCtx; +} /* End dot11f_unpack_ff_sm_power_mode_set. */ + +#define SigFfSMPowerModeSet (0x0013) + +#define SigFfStatus (0x0014) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfStatusCode *pDst) +{ + pDst->statusCode = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_status_code. */ + +#define SigFfStatusCode (0x0015) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleID *pDst) +{ + pDst->TPCId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_id. */ + +#define SigFfTPCEleID (0x0016) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleLen *pDst) +{ + pDst->TPCLen = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_len. */ + +#define SigFfTPCEleLen (0x0017) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTSInfo *pDst) +{ + uint32_t tmp3__; + framesntohl(pCtx, &tmp3__, pBuf, 0); + pDst->traffic_type = tmp3__ >> 0 & 0x1; + pDst->tsid = tmp3__ >> 1 & 0xf; + pDst->direction = tmp3__ >> 5 & 0x3; + pDst->access_policy = tmp3__ >> 7 & 0x3; + pDst->aggregation = tmp3__ >> 9 & 0x1; + pDst->psb = tmp3__ >> 10 & 0x1; + pDst->user_priority = tmp3__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp3__ >> 14 & 0x3; + pDst->schedule = tmp3__ >> 16 & 0x1; + pDst->unused = tmp3__ >> 17 & 0x7fff; + (void)pCtx; +} /* End dot11f_unpack_ff_ts_info. */ + +#define SigFfTSInfo (0x0018) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTimeStamp *pDst) +{ + framesntohq(pCtx, &pDst->timestamp, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_time_stamp. */ + +#define SigFfTimeStamp (0x0019) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTransactionId *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->transId, pBuf, 2); + (void)pCtx; +} /* End dot11f_unpack_ff_transaction_id. */ + +#define SigFfTransactionId (0x001a) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_antenna_id. */ + +#define SigFfTxAntennaId (0x001b) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxPower *pDst) +{ + pDst->txPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_power. */ + +#define SigFfTxPower (0x001c) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtMembershipStatusArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->membershipStatusArray, pBuf, 8); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_membership_status_array. */ + +#define SigFfVhtMembershipStatusArray (0x001d) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtUserPositionArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->userPositionArray, pBuf, 16); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_user_position_array. */ + +#define SigFfVhtUserPositionArray (0x001e) + +uint32_t dot11f_unpack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVAuthorizedMACs *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_authorized_ma_cs. */ + +#define SigTlvAuthorizedMACs (0x0001) + + +#define SigTlvRequestToEnroll (0x0002) + + +uint32_t dot11f_unpack_tlv_version2(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion2 *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp4__; + pDst->present = 1; + tmp4__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp4__ >> 0 & 0xf; + pDst->major = tmp4__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version2. */ + +#define SigTlvVersion2 (0x0003) + + +#define SigTlvAPSetupLocked (0x0004) + + +#define SigTlvAssociationState (0x0005) + + +#define SigTlvConfigMethods (0x0006) + + +#define SigTlvConfigurationError (0x0007) + + +uint32_t dot11f_unpack_tlv_device_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVDeviceName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_device_name. */ + +#define SigTlvDeviceName (0x0008) + + +#define SigTlvDevicePasswordID (0x0009) + + +uint32_t dot11f_unpack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVExtendedListenTiming *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + framesntohs(pCtx, &pDst->availibilityPeriod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + framesntohs(pCtx, &pDst->availibilityInterval, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_extended_listen_timing. */ + +#define SigTlvExtendedListenTiming (0x000a) + + +uint32_t dot11f_unpack_tlv_listen_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVListenChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_listen_channel. */ + +#define SigTlvListenChannel (0x000b) + + +uint32_t dot11f_unpack_tlv_manufacturer(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVManufacturer *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_name = (uint8_t)(tlvlen); + if (tlvlen > 64) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->name, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_manufacturer. */ + +#define SigTlvManufacturer (0x000c) + + +#define SigTlvMinorReasonCode (0x000d) + + +uint32_t dot11f_unpack_tlv_model_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_name. */ + +#define SigTlvModelName (0x000e) + + +uint32_t dot11f_unpack_tlv_model_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_number. */ + +#define SigTlvModelNumber (0x000f) + + +uint32_t dot11f_unpack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVNoticeOfAbsence *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->index = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->CTSWindowOppPS = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->num_NoADesc = (uint8_t)(tlvlen); + if (tlvlen > 36) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->NoADesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_notice_of_absence. */ + +#define SigTlvNoticeOfAbsence (0x0010) + + +uint32_t dot11f_unpack_tlv_operating_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVOperatingChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_operating_channel. */ + +#define SigTlvOperatingChannel (0x0011) + + +uint32_t dot11f_unpack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PCapability *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->deviceCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->groupCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_capability. */ + +#define SigTlvP2PCapability (0x0012) + + +uint32_t dot11f_unpack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceId *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_device_id. */ + +#define SigTlvP2PDeviceId (0x0013) + + +static const tTLVDefn TLVS_P2PDeviceInfo[] = { + { offsetof(tDot11fTLVP2PDeviceInfo, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + framesntohs(pCtx, &pDst->configMethod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->primaryDeviceType, pBuf, 8); + pBuf += 8; + tlvlen -= (uint8_t)8; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_P2PDeviceInfo, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_p2_p_device_info. */ + +#define SigTlvP2PDeviceInfo (0x0014) + + +uint32_t dot11f_unpack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PGroupInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_P2PClientInfoDesc = (uint8_t)(tlvlen); + DOT11F_MEMCPY(pCtx, pDst->P2PClientInfoDesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_group_info. */ + +#define SigTlvP2PGroupInfo (0x0015) + + +#define SigTlvP2PStatus (0x0016) + + +uint32_t dot11f_unpack_tlv_primary_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVPrimaryDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)tlvlen; /* Shutup the compiler */ + pDst->present = 1; + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_primary_device_type. */ + +#define SigTlvPrimaryDeviceType (0x0017) + + +#define SigTlvRFBands (0x0018) + + +uint32_t dot11f_unpack_tlv_request_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVRequestDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_request_device_type. */ + +#define SigTlvRequestDeviceType (0x0019) + + +#define SigTlvRequestType (0x001a) + + +#define SigTlvResponseType (0x001b) + + +#define SigTlvSelectedRegistrar (0x001c) + + +#define SigTlvSelectedRegistrarConfigMethods (0x001d) + + +uint32_t dot11f_unpack_tlv_serial_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVSerialNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_serial_number. */ + +#define SigTlvSerialNumber (0x001e) + + +uint32_t dot11f_unpack_tlv_uuid_e(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_E *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_e. */ + +#define SigTlvUUID_E (0x001f) + + +uint32_t dot11f_unpack_tlv_uuid_r(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_R *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_r. */ + +#define SigTlvUUID_R (0x0020) + + +static const tTLVDefn TLVS_VendorExtension[] = { + { offsetof(tDot11fTLVVendorExtension, Version2), + offsetof(tDot11fTLVVersion2, present), "Version2", SigTlvVersion2, + DOT11F_TLV_VERSION2, 0, 3, 3, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, AuthorizedMACs), + offsetof(tDot11fTLVAuthorizedMACs, present), "AuthorizedMACs", + SigTlvAuthorizedMACs, DOT11F_TLV_AUTHORIZEDMACS, 0, 8, 8, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, RequestToEnroll), + offsetof(tDot11fTLVRequestToEnroll, present), "RequestToEnroll", + SigTlvRequestToEnroll, DOT11F_TLV_REQUESTTOENROLL, + 0, 3, 3, 0, 1, 1, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_vendor_extension(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVendorExtension *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->vendorId, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_VendorExtension, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_vendor_extension. */ + +#define SigTlvVendorExtension (0x0021) + + +uint32_t dot11f_unpack_tlv_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp5__; + pDst->present = 1; + tmp5__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp5__ >> 0 & 0xf; + pDst->major = tmp5__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version. */ + +#define SigTlvVersion (0x0022) + + +#define SigTlvWPSState (0x0023) + + +uint32_t dot11f_unpack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PInterface *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_interface. */ + +#define SigTlvP2PInterface (0x0024) + + +#define SigTlvP2PManageability (0x0025) + + +uint32_t dot11f_unpack_ie_condensed_country_str(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECondensedCountryStr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryStr, pBuf, 2); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_condensed_country_str. */ + +#define SigIeCondensedCountryStr (0x0001) + + +uint32_t dot11f_unpack_ie_gtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEGTK *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp6__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp6__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->keyId = tmp6__ >> 0 & 0x3; + pDst->reserved = tmp6__ >> 2 & 0x3feb; + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->RSC, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + pDst->num_key = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_gtk. */ + +#define SigIeGTK (0x0002) + + +uint32_t dot11f_unpack_ie_igtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIGTK *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->keyID, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->IPN, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, 24); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_igtk. */ + +#define SigIeIGTK (0x0003) + + +uint32_t dot11f_unpack_ie_r0_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER0KH_ID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_PMK_R0_ID = (uint8_t)(ielen); + if (ielen > 48) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->PMK_R0_ID, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r0_kh_id. */ + +#define SigIeR0KH_ID (0x0004) + + +uint32_t dot11f_unpack_ie_r1_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER1KH_ID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->PMK_R1_ID, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r1_kh_id. */ + +#define SigIeR1KH_ID (0x0005) + + +uint32_t dot11f_unpack_ie_tsf_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSFInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->TsfOffset, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->BeaconIntvl, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tsf_info. */ + +#define SigIeTSFInfo (0x0006) + + +uint32_t dot11f_unpack_ie_ap_channel_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAPChannelReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channelList = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channelList, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ap_channel_report. */ + +#define SigIeAPChannelReport (0x0007) + + +uint32_t dot11f_unpack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBcnReportingDetail *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->reportingDetail = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bcn_reporting_detail. */ + +#define SigIeBcnReportingDetail (0x0008) + + +uint32_t dot11f_unpack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReportFrmBody *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_reportedFields = (uint8_t)(ielen); + if (ielen > 224) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->reportedFields, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_report_frm_body. */ + +#define SigIeBeaconReportFrmBody (0x0009) + + +uint32_t dot11f_unpack_ie_beacon_reporting(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReporting *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->reportingCondition = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->threshold = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_reporting. */ + +#define SigIeBeaconReporting (0x000a) + + +uint32_t dot11f_unpack_ie_measurement_pilot(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementPilot *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->measurementPilot = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_pilot. */ + +#define SigIeMeasurementPilot (0x000b) + + +uint32_t dot11f_unpack_ie_multi_bssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMultiBssid *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->maxBSSIDIndicator = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_multi_bssid. */ + +#define SigIeMultiBssid (0x000c) + + +uint32_t dot11f_unpack_ie_ric_data(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICData *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->Identifier = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->resourceDescCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->statusCode, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_data. */ + +#define SigIeRICData (0x000d) + + +uint32_t dot11f_unpack_ie_ric_descriptor(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDescriptor *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->resourceType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_variableData = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->variableData, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_descriptor. */ + +#define SigIeRICDescriptor (0x000e) + + +uint32_t dot11f_unpack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERRMEnabledCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp7__; + uint8_t tmp8__; + uint8_t tmp9__; + uint8_t tmp10__; + uint8_t tmp11__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp7__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->LinkMeasurement = tmp7__ >> 0 & 0x1; + pDst->NeighborRpt = tmp7__ >> 1 & 0x1; + pDst->parallel = tmp7__ >> 2 & 0x1; + pDst->repeated = tmp7__ >> 3 & 0x1; + pDst->BeaconPassive = tmp7__ >> 4 & 0x1; + pDst->BeaconActive = tmp7__ >> 5 & 0x1; + pDst->BeaconTable = tmp7__ >> 6 & 0x1; + pDst->BeaconRepCond = tmp7__ >> 7 & 0x1; + tmp8__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->FrameMeasurement = tmp8__ >> 0 & 0x1; + pDst->ChannelLoad = tmp8__ >> 1 & 0x1; + pDst->NoiseHistogram = tmp8__ >> 2 & 0x1; + pDst->statistics = tmp8__ >> 3 & 0x1; + pDst->LCIMeasurement = tmp8__ >> 4 & 0x1; + pDst->LCIAzimuth = tmp8__ >> 5 & 0x1; + pDst->TCMCapability = tmp8__ >> 6 & 0x1; + pDst->triggeredTCM = tmp8__ >> 7 & 0x1; + tmp9__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APChanReport = tmp9__ >> 0 & 0x1; + pDst->RRMMIBEnabled = tmp9__ >> 1 & 0x1; + pDst->operatingChanMax = tmp9__ >> 2 & 0x7; + pDst->nonOperatinChanMax = tmp9__ >> 5 & 0x7; + tmp10__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->MeasurementPilot = tmp10__ >> 0 & 0x7; + pDst->MeasurementPilotEnabled = tmp10__ >> 3 & 0x1; + pDst->NeighborTSFOffset = tmp10__ >> 4 & 0x1; + pDst->RCPIMeasurement = tmp10__ >> 5 & 0x1; + pDst->RSNIMeasurement = tmp10__ >> 6 & 0x1; + pDst->BssAvgAccessDelay = tmp10__ >> 7 & 0x1; + tmp11__ = *pBuf; + pDst->BSSAvailAdmission = tmp11__ >> 0 & 0x1; + pDst->AntennaInformation = tmp11__ >> 1 & 0x1; + pDst->fine_time_meas_rpt = tmp11__ >> 2 & 0x1; + pDst->lci_capability = tmp11__ >> 3 & 0x1; + pDst->reserved = tmp11__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rrm_enabled_cap. */ + +#define SigIeRRMEnabledCap (0x000f) + + +uint32_t dot11f_unpack_ie_requested_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERequestedInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_requested_eids = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->requested_eids, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_requested_info. */ + +#define SigIeRequestedInfo (0x0010) + + +uint32_t dot11f_unpack_ie_ssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESSID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) { + status = DOT11F_DUPLICATE_IE; + return status; + } + pDst->present = 1; + pDst->num_ssid = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ssid, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ssid. */ + +#define SigIeSSID (0x0011) + + +uint32_t dot11f_unpack_ie_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESchedule *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp12__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp12__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp12__ >> 0 & 0x1; + pDst->tsid = tmp12__ >> 1 & 0xf; + pDst->direction = tmp12__ >> 5 & 0x3; + pDst->reserved = tmp12__ >> 7 & 0x1ff; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_schedule. */ + +#define SigIeSchedule (0x0012) + + +uint32_t dot11f_unpack_ie_tclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETCLAS *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tclas. */ + +#define SigIeTCLAS (0x0013) + + +#define SigIeTCLASSPROC (0x0014) + + +uint32_t dot11f_unpack_ie_ts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSDelay *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ts_delay. */ + +#define SigIeTSDelay (0x0015) + + +uint32_t dot11f_unpack_ie_tspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSPEC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp13__; + uint8_t tmp14__; + uint16_t tmp15__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp13__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp13__ >> 0 & 0x1; + pDst->tsid = tmp13__ >> 1 & 0xf; + pDst->direction = tmp13__ >> 5 & 0x3; + pDst->access_policy = tmp13__ >> 7 & 0x3; + pDst->aggregation = tmp13__ >> 9 & 0x1; + pDst->psb = tmp13__ >> 10 & 0x1; + pDst->user_priority = tmp13__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp13__ >> 14 & 0x3; + tmp14__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->schedule = tmp14__ >> 0 & 0x1; + pDst->unused = tmp14__ >> 1 & 0x7f; + framesntohs(pCtx, &tmp15__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp15__ >> 0 & 0x7fff; + pDst->fixed = tmp15__ >> 15 & 0x1; + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tspec. */ + +#define SigIeTSPEC (0x0016) + + +uint32_t dot11f_unpack_ie_vht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t tmp16__; + uint16_t tmp17__; + uint16_t tmp18__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohl(pCtx, &tmp16__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->maxMPDULen = tmp16__ >> 0 & 0x3; + pDst->supportedChannelWidthSet = tmp16__ >> 2 & 0x3; + pDst->ldpcCodingCap = tmp16__ >> 4 & 0x1; + pDst->shortGI80MHz = tmp16__ >> 5 & 0x1; + pDst->shortGI160and80plus80MHz = tmp16__ >> 6 & 0x1; + pDst->txSTBC = tmp16__ >> 7 & 0x1; + pDst->rxSTBC = tmp16__ >> 8 & 0x7; + pDst->suBeamFormerCap = tmp16__ >> 11 & 0x1; + pDst->suBeamformeeCap = tmp16__ >> 12 & 0x1; + pDst->csnofBeamformerAntSup = tmp16__ >> 13 & 0x7; + pDst->numSoundingDim = tmp16__ >> 16 & 0x7; + pDst->muBeamformerCap = tmp16__ >> 19 & 0x1; + pDst->muBeamformeeCap = tmp16__ >> 20 & 0x1; + pDst->vhtTXOPPS = tmp16__ >> 21 & 0x1; + pDst->htcVHTCap = tmp16__ >> 22 & 0x1; + pDst->maxAMPDULenExp = tmp16__ >> 23 & 0x7; + pDst->vhtLinkAdaptCap = tmp16__ >> 26 & 0x3; + pDst->rxAntPattern = tmp16__ >> 28 & 0x1; + pDst->txAntPattern = tmp16__ >> 29 & 0x1; + pDst->reserved1 = tmp16__ >> 30 & 0x3; + framesntohs(pCtx, &pDst->rxMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &tmp17__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->rxHighSupDataRate = tmp17__ >> 0 & 0x1fff; + pDst->reserved2 = tmp17__ >> 13 & 0x7; + framesntohs(pCtx, &pDst->txMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &tmp18__, pBuf, 0); + pDst->txSupDataRate = tmp18__ >> 0 & 0x1fff; + pDst->reserved3 = tmp18__ >> 13 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_caps. */ + +#define SigIeVHTCaps (0x0017) + + +uint32_t dot11f_unpack_ie_vht_operation(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTOperation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->chanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->chanCenterFreqSeg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->chanCenterFreqSeg2 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->basicMCSSet, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_operation. */ + +#define SigIeVHTOperation (0x0018) + + +uint32_t dot11f_unpack_ie_wmm_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMSchedule *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp19__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &tmp19__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp19__ >> 0 & 0x1; + pDst->tsid = tmp19__ >> 1 & 0xf; + pDst->direction = tmp19__ >> 5 & 0x3; + pDst->reserved = tmp19__ >> 7 & 0x1ff; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_schedule. */ + +#define SigIeWMMSchedule (0x0019) + + +uint32_t dot11f_unpack_ie_wmmtclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLAS *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclas. */ + +#define SigIeWMMTCLAS (0x001a) + + +uint32_t dot11f_unpack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLASPROC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->processing = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclasproc. */ + +#define SigIeWMMTCLASPROC (0x001b) + + +uint32_t dot11f_unpack_ie_wmmts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSDelay *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmts_delay. */ + +#define SigIeWMMTSDelay (0x001c) + + +uint32_t dot11f_unpack_ie_wmmtspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSPEC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp20__; + uint8_t tmp21__; + uint16_t tmp22__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &tmp20__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp20__ >> 0 & 0x1; + pDst->tsid = tmp20__ >> 1 & 0xf; + pDst->direction = tmp20__ >> 5 & 0x3; + pDst->access_policy = tmp20__ >> 7 & 0x3; + pDst->aggregation = tmp20__ >> 9 & 0x1; + pDst->psb = tmp20__ >> 10 & 0x1; + pDst->user_priority = tmp20__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp20__ >> 14 & 0x3; + tmp21__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->tsinfo_rsvd = tmp21__ >> 0 & 0x7f; + pDst->burst_size_defn = tmp21__ >> 7 & 0x1; + framesntohs(pCtx, &tmp22__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp22__ >> 0 & 0x7fff; + pDst->fixed = tmp22__ >> 15 & 0x1; + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtspec. */ + +#define SigIeWMMTSPEC (0x001d) + + +uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWiderBWChanSwitchAnn *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->newChanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newCenterChanFreq0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newCenterChanFreq1 = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wider_bw_chan_switch_ann. */ + +#define SigIeWiderBWChanSwitchAnn (0x001e) + + +uint32_t dot11f_unpack_ie_aid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->assocId, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_aid. */ + +#define SigIeAID (0x001f) + + +uint32_t dot11f_unpack_ie_cf_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECFParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->cfp_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->cfp_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->cfp_maxduration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->cfp_durremaining, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_cf_params. */ + +#define SigIeCFParams (0x0020) + + +uint32_t dot11f_unpack_ie_challenge_text(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChallengeText *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_text = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_challenge_text. */ + +#define SigIeChallengeText (0x0021) + + +uint32_t dot11f_unpack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChanSwitchAnn *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->switchMode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->switchCount = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_chan_switch_ann. */ + +#define SigIeChanSwitchAnn (0x0022) + + +static const tFFDefn FFS_ChannelSwitchWrapper[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitchWrapper[] = { + { offsetof(tDot11fIEChannelSwitchWrapper, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChannelSwitchWrapper *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_channel_switch_wrapper. */ + +#define SigIeChannelSwitchWrapper (0x0023) + + +uint32_t dot11f_unpack_ie_country(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECountry *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->country, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + if (!ielen) { + pDst->num_triplets = 0U; + return 0U; + } else { + pDst->num_triplets = (uint8_t)(ielen / 3); + if (ielen > 84 * 3) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->triplets, pBuf, (ielen)); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_country. */ + +#define SigIeCountry (0x0024) + + +#define SigIeDSParams (0x0025) + + +uint32_t dot11f_unpack_ie_edca_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEEDCAParamSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp23__; + uint8_t tmp24__; + uint8_t tmp25__; + uint8_t tmp26__; + uint8_t tmp27__; + uint8_t tmp28__; + uint8_t tmp29__; + uint8_t tmp30__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->qos = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp23__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp23__ >> 0 & 0xf; + pDst->acbe_acm = tmp23__ >> 4 & 0x1; + pDst->acbe_aci = tmp23__ >> 5 & 0x3; + pDst->unused1 = tmp23__ >> 7 & 0x1; + tmp24__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp24__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp24__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp25__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp25__ >> 0 & 0xf; + pDst->acbk_acm = tmp25__ >> 4 & 0x1; + pDst->acbk_aci = tmp25__ >> 5 & 0x3; + pDst->unused2 = tmp25__ >> 7 & 0x1; + tmp26__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp26__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp26__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp27__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp27__ >> 0 & 0xf; + pDst->acvi_acm = tmp27__ >> 4 & 0x1; + pDst->acvi_aci = tmp27__ >> 5 & 0x3; + pDst->unused3 = tmp27__ >> 7 & 0x1; + tmp28__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp28__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp28__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp29__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp29__ >> 0 & 0xf; + pDst->acvo_acm = tmp29__ >> 4 & 0x1; + pDst->acvo_aci = tmp29__ >> 5 & 0x3; + pDst->unused4 = tmp29__ >> 7 & 0x1; + tmp30__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp30__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp30__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_edca_param_set. */ + +#define SigIeEDCAParamSet (0x0026) + + +uint32_t dot11f_unpack_ie_erp_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEERPInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp31__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp31__ = *pBuf; + pDst->non_erp_present = tmp31__ >> 0 & 0x1; + pDst->use_prot = tmp31__ >> 1 & 0x1; + pDst->barker_preamble = tmp31__ >> 2 & 0x1; + pDst->unused = tmp31__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_erp_info. */ + +#define SigIeERPInfo (0x0027) + + +uint32_t dot11f_unpack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESECckmOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 20) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_cckm_opaque. */ + +#define SigIeESECckmOpaque (0x0028) + + +uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESERadMgmtCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp32__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->mgmt_state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp32__ = *pBuf; + pDst->mbssid_mask = tmp32__ >> 0 & 0x7; + pDst->reserved = tmp32__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_rad_mgmt_cap. */ + +#define SigIeESERadMgmtCap (0x0029) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmMet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->msmt_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_met. */ + +#define SigIeESETrafStrmMet (0x002a) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmRateSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_tsrates = (uint8_t)(ielen); + if (ielen > 8) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tsrates, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_rate_set. */ + +#define SigIeESETrafStrmRateSet (0x002b) + + +uint32_t dot11f_unpack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETxmitPower *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->power_limit = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_txmit_power. */ + +#define SigIeESETxmitPower (0x002c) + + +uint32_t dot11f_unpack_ie_ese_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESEVersion *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_version. */ + +#define SigIeESEVersion (0x002d) + + +uint32_t dot11f_unpack_ie_ext_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + + if (!ielen) /* Check to ensure copying of ielen bytes */ + goto endUnpackIeExtCap; + pDst->num_bytes = (uint8_t)(ielen); + if (ielen > 9) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, (ielen)); + +endUnpackIeExtCap: + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_cap. */ + +#define SigIeExtCap (0x002e) + + +uint32_t dot11f_unpack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtSuppRates *pDst) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_supp_rates. */ + +#define SigIeExtSuppRates (0x002f) + + +uint32_t dot11f_unpack_ie_fh_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParamSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->dwell_time, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->hop_set = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->hop_pattern = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->hop_index = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_param_set. */ + +#define SigIeFHParamSet (0x0030) + + +uint32_t dot11f_unpack_ie_fh_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->radix = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->nchannels = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_params. */ + +#define SigIeFHParams (0x0031) + + +uint32_t dot11f_unpack_ie_fh_patt_table(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHPattTable *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->flag = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->nsets = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->modulus = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_randtable = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->randtable, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_patt_table. */ + +#define SigIeFHPattTable (0x0032) + + +static const tFFDefn FFS_FTInfo[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_FTInfo[] = { + { offsetof(tDot11fIEFTInfo, R1KH_ID), offsetof(tDot11fIER1KH_ID, present), + 0, "R1KH_ID", 0, 8, 8, SigIeR1KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R1KH_ID, 0, }, + { offsetof(tDot11fIEFTInfo, GTK), offsetof(tDot11fIEGTK, present), 0, "GTK", + 0, 18, 45, SigIeGTK, {0, 0, 0, 0, 0}, 0, DOT11F_EID_GTK, 0, }, + { offsetof(tDot11fIEFTInfo, R0KH_ID), offsetof(tDot11fIER0KH_ID, present), + 0, "R0KH_ID", 0, 3, 50, SigIeR0KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R0KH_ID, 0, }, + { offsetof(tDot11fIEFTInfo, IGTK), offsetof(tDot11fIEIGTK, present), 0, + "IGTK", 0, 35, 35, SigIeIGTK, {0, 0, 0, 0, 0}, 0, DOT11F_EID_IGTK, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ft_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFTInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp33__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp33__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->reserved = tmp33__ >> 0 & 0xff; + pDst->IECount = tmp33__ >> 8 & 0xff; + DOT11F_MEMCPY(pCtx, pDst->MIC, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->Anonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + DOT11F_MEMCPY(pCtx, pDst->Snonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_FTInfo, + IES_FTInfo, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_ft_info. */ + +#define SigIeFTInfo (0x0033) + + +uint32_t dot11f_unpack_ie_ht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp34__; + uint8_t tmp35__; + uint16_t tmp36__; + uint32_t tmp37__; + uint8_t tmp38__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp34__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->advCodingCap = tmp34__ >> 0 & 0x1; + pDst->supportedChannelWidthSet = tmp34__ >> 1 & 0x1; + pDst->mimoPowerSave = tmp34__ >> 2 & 0x3; + pDst->greenField = tmp34__ >> 4 & 0x1; + pDst->shortGI20MHz = tmp34__ >> 5 & 0x1; + pDst->shortGI40MHz = tmp34__ >> 6 & 0x1; + pDst->txSTBC = tmp34__ >> 7 & 0x1; + pDst->rxSTBC = tmp34__ >> 8 & 0x3; + pDst->delayedBA = tmp34__ >> 10 & 0x1; + pDst->maximalAMSDUsize = tmp34__ >> 11 & 0x1; + pDst->dsssCckMode40MHz = tmp34__ >> 12 & 0x1; + pDst->psmp = tmp34__ >> 13 & 0x1; + pDst->stbcControlFrame = tmp34__ >> 14 & 0x1; + pDst->lsigTXOPProtection = tmp34__ >> 15 & 0x1; + tmp35__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->maxRxAMPDUFactor = tmp35__ >> 0 & 0x3; + pDst->mpduDensity = tmp35__ >> 2 & 0x7; + pDst->reserved1 = tmp35__ >> 5 & 0x7; + DOT11F_MEMCPY(pCtx, pDst->supportedMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &tmp36__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->pco = tmp36__ >> 0 & 0x1; + pDst->transitionTime = tmp36__ >> 1 & 0x3; + pDst->reserved2 = tmp36__ >> 3 & 0x1f; + pDst->mcsFeedback = tmp36__ >> 8 & 0x3; + pDst->reserved3 = tmp36__ >> 10 & 0x3f; + framesntohl(pCtx, &tmp37__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->txBF = tmp37__ >> 0 & 0x1; + pDst->rxStaggeredSounding = tmp37__ >> 1 & 0x1; + pDst->txStaggeredSounding = tmp37__ >> 2 & 0x1; + pDst->rxZLF = tmp37__ >> 3 & 0x1; + pDst->txZLF = tmp37__ >> 4 & 0x1; + pDst->implicitTxBF = tmp37__ >> 5 & 0x1; + pDst->calibration = tmp37__ >> 6 & 0x3; + pDst->explicitCSITxBF = tmp37__ >> 8 & 0x1; + pDst->explicitUncompressedSteeringMatrix = tmp37__ >> 9 & 0x1; + pDst->explicitBFCSIFeedback = tmp37__ >> 10 & 0x7; + pDst->explicitUncompressedSteeringMatrixFeedback = tmp37__ >> 13 & 0x7; + pDst->explicitCompressedSteeringMatrixFeedback = tmp37__ >> 16 & 0x7; + pDst->csiNumBFAntennae = tmp37__ >> 19 & 0x3; + pDst->uncompressedSteeringMatrixBFAntennae = tmp37__ >> 21 & 0x3; + pDst->compressedSteeringMatrixBFAntennae = tmp37__ >> 23 & 0x3; + pDst->reserved4 = tmp37__ >> 25 & 0x7f; + tmp38__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->antennaSelection = tmp38__ >> 0 & 0x1; + pDst->explicitCSIFeedbackTx = tmp38__ >> 1 & 0x1; + pDst->antennaIndicesFeedbackTx = tmp38__ >> 2 & 0x1; + pDst->explicitCSIFeedback = tmp38__ >> 3 & 0x1; + pDst->antennaIndicesFeedback = tmp38__ >> 4 & 0x1; + pDst->rxAS = tmp38__ >> 5 & 0x1; + pDst->txSoundingPPDUs = tmp38__ >> 6 & 0x1; + pDst->reserved5 = tmp38__ >> 7 & 0x1; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_caps. */ + +#define SigIeHTCaps (0x0034) + + +uint32_t dot11f_unpack_ie_ht_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp39__; + uint16_t tmp40__; + uint16_t tmp41__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->primaryChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp39__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->secondaryChannelOffset = tmp39__ >> 0 & 0x3; + pDst->recommendedTxWidthSet = tmp39__ >> 2 & 0x1; + pDst->rifsMode = tmp39__ >> 3 & 0x1; + pDst->controlledAccessOnly = tmp39__ >> 4 & 0x1; + pDst->serviceIntervalGranularity = tmp39__ >> 5 & 0x7; + framesntohs(pCtx, &tmp40__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->opMode = tmp40__ >> 0 & 0x3; + pDst->nonGFDevicesPresent = tmp40__ >> 2 & 0x1; + pDst->transmitBurstLimit = tmp40__ >> 3 & 0x1; + pDst->obssNonHTStaPresent = tmp40__ >> 4 & 0x1; + pDst->reserved = tmp40__ >> 5 & 0x7ff; + framesntohs(pCtx, &tmp41__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->basicSTBCMCS = tmp41__ >> 0 & 0x7f; + pDst->dualCTSProtection = tmp41__ >> 7 & 0x1; + pDst->secondaryBeacon = tmp41__ >> 8 & 0x1; + pDst->lsigTXOPProtectionFullSupport = tmp41__ >> 9 & 0x1; + pDst->pcoActive = tmp41__ >> 10 & 0x1; + pDst->pcoPhase = tmp41__ >> 11 & 0x1; + pDst->reserved2 = tmp41__ >> 12 & 0xf; + DOT11F_MEMCPY(pCtx, pDst->basicMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_info. */ + +#define SigIeHTInfo (0x0035) + + +uint32_t dot11f_unpack_ie_ibss_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIBSSParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->atim, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ibss_params. */ + +#define SigIeIBSSParams (0x0036) + + +uint32_t dot11f_unpack_ie_link_identifier(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIELinkIdentifier *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->InitStaAddr, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->RespStaAddr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_link_identifier. */ + +#define SigIeLinkIdentifier (0x0037) + + +static const tFFDefn FFS_reportBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_reportBeacon[] = { + { offsetof(tDot11fIEMeasurementReport, + report.Beacon.BeaconReportFrmBody), + offsetof(tDot11fIEBeaconReportFrmBody, present), 0, "BeaconReportFrmBody", + 0, 2, 226, SigIeBeaconReportFrmBody, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTFRMBODY, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp42__; + uint8_t tmp43__; + uint8_t tmp44__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp42__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->late = tmp42__ >> 0 & 0x1; + pDst->incapable = tmp42__ >> 1 & 0x1; + pDst->refused = tmp42__ >> 2 & 0x1; + pDst->unused = tmp42__ >> 3 & 0x1f; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (!ielen) { + return 0U; + } else { + switch (pDst->type) { + case 0: + pDst->report.Basic.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.Basic.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp43__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Basic.bss = tmp43__ >> 0 & 0x1; + pDst->report.Basic.ofdm_preamble = tmp43__ >> 1 & 0x1; + pDst->report.Basic.unid_signal = tmp43__ >> 2 & 0x1; + pDst->report.Basic.rader = tmp43__ >> 3 & 0x1; + pDst->report.Basic.unmeasured = tmp43__ >> 4 & 0x1; + pDst->report.Basic.unused = tmp43__ >> 5 & 0x7; + break; + case 1: + pDst->report.CCA.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.CCA.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->report.CCA.cca_busy_fraction = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 2: + pDst->report.RPIHistogram.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.RPIHistogram.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->report.RPIHistogram.rpi0_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi1_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi2_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi3_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi4_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi5_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi6_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi7_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 5: + pDst->report.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.Beacon.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp44__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Beacon.condensed_PHY = tmp44__ >> 0 & 0x7f; + pDst->report.Beacon.reported_frame_type = tmp44__ >> 7 & 0x1; + pDst->report.Beacon.RCPI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.Beacon.RSNI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->report.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + pDst->report.Beacon.antenna_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohl(pCtx, &pDst->report.Beacon.parent_TSF, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_reportBeacon, + IES_reportBeacon, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_report. */ + +#define SigIeMeasurementReport (0x0038) + + +static const tFFDefn FFS_measurement_requestBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestBeacon[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.BeaconReporting), + offsetof(tDot11fIEBeaconReporting, present), 0, "BeaconReporting", + 0, 4, 4, SigIeBeaconReporting, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTING, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.BcnReportingDetail), + offsetof(tDot11fIEBcnReportingDetail, present), 0, "BcnReportingDetail", + 0, 3, 3, SigIeBcnReportingDetail, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BCNREPORTINGDETAIL, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), + offsetof(tDot11fIEMeasurementRequest, measurement_request.Beacon.num_APChannelReport), "APChannelReport", 2, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, 0, DOT11F_EID_APCHANNELREPORT, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementRequest *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp45__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->measurement_token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp45__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->parallel = tmp45__ >> 0 & 0x1; + pDst->enable = tmp45__ >> 1 & 0x1; + pDst->request = tmp45__ >> 2 & 0x1; + pDst->report = tmp45__ >> 3 & 0x1; + pDst->durationMandatory = tmp45__ >> 4 & 0x1; + pDst->unused = tmp45__ >> 5 & 0x7; + pDst->measurement_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->measurement_type) { + case 0: + pDst->measurement_request.Basic.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Basic.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->measurement_request.CCA.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.CCA.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 2: + pDst->measurement_request.RPIHistogram.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.RPIHistogram.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 5: + pDst->measurement_request.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->measurement_request.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->measurement_request.Beacon.randomization, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->measurement_request.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->measurement_request.Beacon.meas_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_request. */ + +#define SigIeMeasurementRequest (0x0039) + + +uint32_t dot11f_unpack_ie_mobility_domain(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMobilityDomain *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp46__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->MDID, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp46__ = *pBuf; + pDst->overDSCap = tmp46__ >> 0 & 0x1; + pDst->resourceReqCap = tmp46__ >> 1 & 0x1; + pDst->reserved = tmp46__ >> 2 & 0x3f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mobility_domain. */ + +#define SigIeMobilityDomain (0x003a) + + +static const tFFDefn FFS_NeighborReport[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReport[] = { + { offsetof(tDot11fIENeighborReport, TSFInfo), offsetof(tDot11fIETSFInfo, + present), 0, "TSFInfo", 0, 6, 6, SigIeTSFInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSFINFO, 0, }, + { offsetof(tDot11fIENeighborReport, CondensedCountryStr), + offsetof(tDot11fIECondensedCountryStr, present), 0, "CondensedCountryStr", + 0, 4, 4, SigIeCondensedCountryStr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CONDENSEDCOUNTRYSTR, 0, }, + { offsetof(tDot11fIENeighborReport, MeasurementPilot), + offsetof(tDot11fIEMeasurementPilot, present), 0, "MeasurementPilot", + 0, 3, 258, SigIeMeasurementPilot, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTPILOT, 0, }, + { offsetof(tDot11fIENeighborReport, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fIENeighborReport, MultiBssid), + offsetof(tDot11fIEMultiBssid, present), 0, "MultiBssid", + 0, 3, 258, SigIeMultiBssid, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MULTIBSSID, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_neighbor_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIENeighborReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp47__; + uint8_t tmp48__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + tmp47__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp47__ >> 0 & 0x3; + pDst->Security = tmp47__ >> 2 & 0x1; + pDst->KeyScope = tmp47__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp47__ >> 4 & 0x1; + pDst->QosCap = tmp47__ >> 5 & 0x1; + pDst->apsd = tmp47__ >> 6 & 0x1; + pDst->rrm = tmp47__ >> 7 & 0x1; + tmp48__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp48__ >> 0 & 0x1; + pDst->ImmBA = tmp48__ >> 1 & 0x1; + pDst->MobilityDomain = tmp48__ >> 2 & 0x1; + pDst->reserved = tmp48__ >> 3 & 0x1f; + framesntohs(pCtx, &pDst->reserved1, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->PhyType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_NeighborReport, + IES_NeighborReport, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_neighbor_report. */ + +#define SigIeNeighborReport (0x003b) + + +uint32_t dot11f_unpack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOBSSScanParameters *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->obssScanPassiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->bssChannelWidthTriggerScanInterval, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanPassiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->bssWidthChannelTransitionDelayFactor, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActivityThreshold, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_obss_scan_parameters. */ + +#define SigIeOBSSScanParameters (0x003c) + + +uint32_t dot11f_unpack_ie_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOperatingMode *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp49__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp49__ = *pBuf; + pDst->chanWidth = tmp49__ >> 0 & 0x3; + pDst->reserved = tmp49__ >> 2 & 0x3; + pDst->rxNSS = tmp49__ >> 4 & 0x7; + pDst->rxNSSType = tmp49__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_operating_mode. */ + +#define SigIeOperatingMode (0x003d) + + +static const tTLVDefn TLVS_P2PAssocReq[] = { + { offsetof(tDot11fIEP2PAssocReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_req. */ + +#define SigIeP2PAssocReq (0x003e) + + +static const tTLVDefn TLVS_P2PAssocRes[] = { + { offsetof(tDot11fIEP2PAssocRes, P2PStatus), + offsetof(tDot11fTLVP2PStatus, present), "P2PStatus", SigTlvP2PStatus, + DOT11F_TLV_P2PSTATUS, 0, 4, 4, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_res. */ + +#define SigIeP2PAssocRes (0x003f) + + +static const tTLVDefn TLVS_P2PBeacon[] = { + { offsetof(tDot11fIEP2PBeacon, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeacon *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon. */ + +#define SigIeP2PBeacon (0x0040) + + +static const tTLVDefn TLVS_P2PBeaconProbeRes[] = { + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeaconProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon_probe_res. */ + +#define SigIeP2PBeaconProbeRes (0x0041) + + +static const tTLVDefn TLVS_P2PDeAuth[] = { + { offsetof(tDot11fIEP2PDeAuth, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDeAuth *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDeAuth, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_de_auth. */ + +#define SigIeP2PDeAuth (0x0042) + + +static const tTLVDefn TLVS_P2PDisAssoc[] = { + { offsetof(tDot11fIEP2PDisAssoc, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDisAssoc *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDisAssoc, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_dis_assoc. */ + +#define SigIeP2PDisAssoc (0x0043) + + +uint32_t dot11f_unpack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_p2_pie_opaque. */ + +#define SigIeP2PIEOpaque (0x0044) + + +static const tTLVDefn TLVS_P2PProbeReq[] = { + { offsetof(tDot11fIEP2PProbeReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ListenChannel), + offsetof(tDot11fTLVListenChannel, present), "ListenChannel", + SigTlvListenChannel, DOT11F_TLV_LISTENCHANNEL, 0, 8, 8, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, OperatingChannel), + offsetof(tDot11fTLVOperatingChannel, present), "OperatingChannel", + SigTlvOperatingChannel, DOT11F_TLV_OPERATINGCHANNEL, + 0, 8, 8, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_req. */ + +#define SigIeP2PProbeReq (0x0045) + + +static const tTLVDefn TLVS_P2PProbeRes[] = { + { offsetof(tDot11fIEP2PProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_res. */ + +#define SigIeP2PProbeRes (0x0046) + + +uint32_t dot11f_unpack_ie_pti_control(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPTIControl *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->sequence_control, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pti_control. */ + +#define SigIePTIControl (0x0047) + + +uint32_t dot11f_unpack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPUBufferStatus *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp50__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp50__ = *pBuf; + pDst->ac_bk_traffic_aval = tmp50__ >> 0 & 0x1; + pDst->ac_be_traffic_aval = tmp50__ >> 1 & 0x1; + pDst->ac_vi_traffic_aval = tmp50__ >> 2 & 0x1; + pDst->ac_vo_traffic_aval = tmp50__ >> 3 & 0x1; + pDst->reserved = tmp50__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pu_buffer_status. */ + +#define SigIePUBufferStatus (0x0048) + + +uint32_t dot11f_unpack_ie_power_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->minTxPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->maxTxPower = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_caps. */ + +#define SigIePowerCaps (0x0049) + + +uint32_t dot11f_unpack_ie_power_constraints(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerConstraints *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->localPowerConstraints = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_constraints. */ + +#define SigIePowerConstraints (0x004a) + + +uint32_t dot11f_unpack_ie_qbss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQBSSLoad *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->stacount, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->chautil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->avail, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qbss_load. */ + +#define SigIeQBSSLoad (0x004b) + + +uint32_t dot11f_unpack_ie_QComVendorIE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQComVendorIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->channel = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_QComVendorIE. */ + +#define SigIeQComVendorIE (0x004c) + + +uint32_t dot11f_unpack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsAp *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp51__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp51__ = *pBuf; + pDst->count = tmp51__ >> 0 & 0xf; + pDst->qack = tmp51__ >> 4 & 0x1; + pDst->qreq = tmp51__ >> 5 & 0x1; + pDst->txopreq = tmp51__ >> 6 & 0x1; + pDst->reserved = tmp51__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_ap. */ + +#define SigIeQOSCapsAp (0x004d) + + +uint32_t dot11f_unpack_ie_qos_caps_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsStation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp52__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp52__ = *pBuf; + pDst->acvo_uapsd = tmp52__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp52__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp52__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp52__ >> 3 & 0x1; + pDst->qack = tmp52__ >> 4 & 0x1; + pDst->max_sp_length = tmp52__ >> 5 & 0x3; + pDst->more_data_ack = tmp52__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_station. */ + +#define SigIeQOSCapsStation (0x004e) + + +uint32_t dot11f_unpack_ie_qos_map_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQosMapSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_dscp_exceptions = (uint8_t)(ielen); + if (ielen > 60) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->dscp_exceptions, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_map_set. */ + +#define SigIeQosMapSet (0x004f) + + +uint32_t dot11f_unpack_ie_quiet(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQuiet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->offset, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_quiet. */ + +#define SigIeQuiet (0x0050) + + +uint32_t dot11f_unpack_ie_rcpiie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERCPIIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->rcpi = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rcpiie. */ + +#define SigIeRCPIIE (0x0051) + + +static const tFFDefn FFS_RICDataDesc[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RICDataDesc[] = { + { offsetof(tDot11fIERICDataDesc, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 1, }, + { offsetof(tDot11fIERICDataDesc, RICDescriptor), + offsetof(tDot11fIERICDescriptor, present), 0, "RICDescriptor", + 0, 3, 258, SigIeRICDescriptor, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDESCRIPTOR, 0, }, + { offsetof(tDot11fIERICDataDesc, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fIERICDataDesc, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fIERICDataDesc, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 0, }, + { offsetof(tDot11fIERICDataDesc, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fIERICDataDesc, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ric_data_desc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDataDesc *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_RICDataDesc, + IES_RICDataDesc, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_ric_data_desc. */ + +#define SigIeRICDataDesc (0x0052) + + +uint32_t dot11f_unpack_ie_rsn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSN *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + DOT11F_MEMCPY(pCtx, pDst->gp_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (!ielen) { + pDst->pwise_cipher_suite_count = 0U; + pDst->akm_suite_count = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->pwise_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->pwise_cipher_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pwise_cipher_suites, pBuf, (pDst->pwise_cipher_suite_count * 4)); + pBuf += (pDst->pwise_cipher_suite_count * 4); + ielen -= (pDst->pwise_cipher_suite_count * 4); + if (!ielen) { + pDst->akm_suite_count = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->akm_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->akm_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suites, pBuf, (pDst->akm_suite_count * 4)); + pBuf += (pDst->akm_suite_count * 4); + ielen -= (pDst->akm_suite_count * 4); + if (!ielen) { + pDst->pmkid_count = 0U; + return 0U; + } else { + DOT11F_MEMCPY(pCtx, pDst->RSN_Cap, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (!ielen) { + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->pmkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->pmkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pmkid, pBuf, (pDst->pmkid_count * 16)); + pBuf += (pDst->pmkid_count * 16); + ielen -= (pDst->pmkid_count * 16); + if (!ielen) { + return 0U; + } else { + DOT11F_MEMCPY(pCtx, pDst->gp_mgmt_cipher_suite, pBuf, 4); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn. */ + +#define SigIeRSN (0x0053) + + +uint32_t dot11f_unpack_ie_rsniie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNIIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->rsni = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsniie. */ + +#define SigIeRSNIIE (0x0054) + + +uint32_t dot11f_unpack_ie_rsn_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn_opaque. */ + +#define SigIeRSNOpaque (0x0055) + + +uint32_t dot11f_unpack_ie_supp_channels(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppChannels *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_bands = (uint8_t)(ielen / 2); + if (ielen > 48 * 2) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bands, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_channels. */ + +#define SigIeSuppChannels (0x0056) + + +uint32_t dot11f_unpack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppOperatingClasses *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_classes = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->classes, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_operating_classes. */ + +#define SigIeSuppOperatingClasses (0x0057) + + +uint32_t dot11f_unpack_ie_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppRates *pDst) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_rates. */ + +#define SigIeSuppRates (0x0058) + + +uint32_t dot11f_unpack_ie_tim(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETIM *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->dtim_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->dtim_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->bmpctl = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vbmp = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->vbmp, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tim. */ + +#define SigIeTIM (0x0059) + + +uint32_t dot11f_unpack_ie_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tx_power = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->link_margin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_report. */ + +#define SigIeTPCReport (0x005a) + + +uint32_t dot11f_unpack_ie_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCRequest *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_request. */ + +#define SigIeTPCRequest (0x005b) + + +uint32_t dot11f_unpack_ie_time_advertisement(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeAdvertisement *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->timing_capabilities = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->time_value, pBuf, 10); + pBuf += 10; + ielen -= (uint8_t)10; + DOT11F_MEMCPY(pCtx, pDst->time_error, pBuf, 5); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_time_advertisement. */ + +#define SigIeTimeAdvertisement (0x005c) + + +uint32_t dot11f_unpack_ie_timeout_interval(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeoutInterval *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->timeoutType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohl(pCtx, &pDst->timeoutValue, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_timeout_interval. */ + +#define SigIeTimeoutInterval (0x005d) + + +uint32_t dot11f_unpack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTExtBssLoad *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->muMIMOCapStaCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->ssUnderUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->FortyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->EightyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->OneSixtyMHzUtil = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_ext_bss_load. */ + +#define SigIeVHTExtBssLoad (0x005e) + + +uint32_t dot11f_unpack_ie_vendor1_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor1IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor1_ie. */ + +#define SigIeVendor1IE (0x005f) + + +uint32_t dot11f_unpack_ie_vendor3_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor3IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor3_ie. */ + +#define SigIeVendor3IE (0x0060) + + +uint32_t dot11f_unpack_ie_wapi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPI *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp53__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &pDst->akm_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->akm_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suites, pBuf, (pDst->akm_suite_count * 4)); + pBuf += (pDst->akm_suite_count * 4); + ielen -= (pDst->akm_suite_count * 4); + framesntohs(pCtx, &pDst->unicast_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->unicast_cipher_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_cipher_suites, pBuf, (pDst->unicast_cipher_suite_count * 4)); + pBuf += (pDst->unicast_cipher_suite_count * 4); + ielen -= (pDst->unicast_cipher_suite_count * 4); + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &tmp53__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->preauth = tmp53__ >> 0 & 0x1; + pDst->reserved = tmp53__ >> 1 & 0x7fff; + if (!ielen) { + pDst->bkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->bkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->bkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bkid, pBuf, (pDst->bkid_count * 16)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi. */ + +#define SigIeWAPI (0x0061) + + +uint32_t dot11f_unpack_ie_wapi_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPIOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi_opaque. */ + +#define SigIeWAPIOpaque (0x0062) + + +uint32_t dot11f_unpack_ie_wfatpc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFATPC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->txPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->linkMargin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfatpc. */ + +#define SigIeWFATPC (0x0063) + + +uint32_t dot11f_unpack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFDIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfdie_opaque. */ + +#define SigIeWFDIEOpaque (0x0064) + + +uint32_t dot11f_unpack_ie_wmm_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp54__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + tmp54__ = *pBuf; + pDst->reserved = tmp54__ >> 0 & 0xf; + pDst->qack = tmp54__ >> 4 & 0x1; + pDst->queue_request = tmp54__ >> 5 & 0x1; + pDst->txop_request = tmp54__ >> 6 & 0x1; + pDst->more_ack = tmp54__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_caps. */ + +#define SigIeWMMCaps (0x0065) + + +uint32_t dot11f_unpack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoAp *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp55__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp55__ = *pBuf; + pDst->param_set_count = tmp55__ >> 0 & 0xf; + pDst->reserved = tmp55__ >> 4 & 0x7; + pDst->uapsd = tmp55__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_ap. */ + +#define SigIeWMMInfoAp (0x0066) + + +uint32_t dot11f_unpack_ie_wmm_info_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoStation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp56__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp56__ = *pBuf; + pDst->acvo_uapsd = tmp56__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp56__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp56__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp56__ >> 3 & 0x1; + pDst->reserved1 = tmp56__ >> 4 & 0x1; + pDst->max_sp_length = tmp56__ >> 5 & 0x3; + pDst->reserved2 = tmp56__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_station. */ + +#define SigIeWMMInfoStation (0x0067) + + +uint32_t dot11f_unpack_ie_wmm_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp57__; + uint8_t tmp58__; + uint8_t tmp59__; + uint8_t tmp60__; + uint8_t tmp61__; + uint8_t tmp62__; + uint8_t tmp63__; + uint8_t tmp64__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->qosInfo = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved2 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp57__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp57__ >> 0 & 0xf; + pDst->acbe_acm = tmp57__ >> 4 & 0x1; + pDst->acbe_aci = tmp57__ >> 5 & 0x3; + pDst->unused1 = tmp57__ >> 7 & 0x1; + tmp58__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp58__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp58__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp59__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp59__ >> 0 & 0xf; + pDst->acbk_acm = tmp59__ >> 4 & 0x1; + pDst->acbk_aci = tmp59__ >> 5 & 0x3; + pDst->unused2 = tmp59__ >> 7 & 0x1; + tmp60__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp60__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp60__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp61__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp61__ >> 0 & 0xf; + pDst->acvi_acm = tmp61__ >> 4 & 0x1; + pDst->acvi_aci = tmp61__ >> 5 & 0x3; + pDst->unused3 = tmp61__ >> 7 & 0x1; + tmp62__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp62__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp62__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp63__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp63__ >> 0 & 0xf; + pDst->acvo_acm = tmp63__ >> 4 & 0x1; + pDst->acvo_aci = tmp63__ >> 5 & 0x3; + pDst->unused4 = tmp63__ >> 7 & 0x1; + tmp64__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp64__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp64__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_params. */ + +#define SigIeWMMParams (0x0068) + + +uint32_t dot11f_unpack_ie_wpa(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPA *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (!ielen) { + pDst->multicast_cipher_present = 0U; + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + pDst->multicast_cipher_present = 1U; + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + } + if (!ielen) { + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->unicast_cipher_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->unicast_cipher_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_ciphers, pBuf, (pDst->unicast_cipher_count * 4)); + pBuf += (pDst->unicast_cipher_count * 4); + ielen -= (pDst->unicast_cipher_count * 4); + if (!ielen) { + pDst->auth_suite_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->auth_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->auth_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->auth_suites, pBuf, (pDst->auth_suite_count * 4)); + pBuf += (pDst->auth_suite_count * 4); + ielen -= (pDst->auth_suite_count * 4); + if (!ielen) { + return 0U; + } else { + framesntohs(pCtx, &pDst->caps, pBuf, 0); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa. */ + +#define SigIeWPA (0x0069) + + +uint32_t dot11f_unpack_ie_wpa_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPAOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa_opaque. */ + +#define SigIeWPAOpaque (0x006a) + + +static const tTLVDefn TLVS_WSC[] = { + { offsetof(tDot11fIEWSC, Version), offsetof(tDot11fTLVVersion, present), + "Version", SigTlvVersion, DOT11F_TLV_VERSION, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, WPSState), offsetof(tDot11fTLVWPSState, present), + "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_E), offsetof(tDot11fTLVUUID_E, present), + "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_R), offsetof(tDot11fTLVUUID_R, present), + "UUID_R", SigTlvUUID_R, DOT11F_TLV_UUID_R, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RFBands), offsetof(tDot11fTLVRFBands, present), + "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, Manufacturer), offsetof(tDot11fTLVManufacturer, + present), "Manufacturer", SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, + 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelName), offsetof(tDot11fTLVModelName, + present), "ModelName", SigTlvModelName, DOT11F_TLV_MODELNAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelNumber), offsetof(tDot11fTLVModelNumber, + present), "ModelNumber", SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SerialNumber), offsetof(tDot11fTLVSerialNumber, + present), "SerialNumber", SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DeviceName), offsetof(tDot11fTLVDeviceName, + present), "DeviceName", SigTlvDeviceName, DOT11F_TLV_DEVICENAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestType), offsetof(tDot11fTLVRequestType, + present), "RequestType", SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ResponseType), offsetof(tDot11fTLVResponseType, + present), "ResponseType", SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWSC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WSC, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc. */ + +#define SigIeWSC (0x006b) + + +static const tTLVDefn TLVS_WscAssocReq[] = { + { offsetof(tDot11fIEWscAssocReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_req. */ + +#define SigIeWscAssocReq (0x006c) + + +static const tTLVDefn TLVS_WscAssocRes[] = { + { offsetof(tDot11fIEWscAssocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_res. */ + +#define SigIeWscAssocRes (0x006d) + + +static const tTLVDefn TLVS_WscBeacon[] = { + { offsetof(tDot11fIEWscBeacon, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeacon *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon. */ + +#define SigIeWscBeacon (0x006e) + + +static const tTLVDefn TLVS_WscBeaconProbeRes[] = { + { offsetof(tDot11fIEWscBeaconProbeRes, Version), + offsetof(tDot11fTLVVersion, present), "Version", SigTlvVersion, + DOT11F_TLV_VERSION, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, WPSState), + offsetof(tDot11fTLVWPSState, present), "WPSState", SigTlvWPSState, + DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, UUID_E), + offsetof(tDot11fTLVUUID_E, present), "UUID_E", SigTlvUUID_E, + DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, RFBands), + offsetof(tDot11fTLVRFBands, present), "RFBands", SigTlvRFBands, + DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeaconProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon_probe_res. */ + +#define SigIeWscBeaconProbeRes (0x006f) + + +uint32_t dot11f_unpack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wsc_ie_opaque. */ + +#define SigIeWscIEOpaque (0x0070) + + +static const tTLVDefn TLVS_WscProbeReq[] = { + { offsetof(tDot11fIEWscProbeReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_req. */ + +#define SigIeWscProbeReq (0x0071) + + +static const tTLVDefn TLVS_WscProbeRes[] = { + { offsetof(tDot11fIEWscProbeRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_res. */ + +#define SigIeWscProbeRes (0x0072) + + +static const tTLVDefn TLVS_WscReassocRes[] = { + { offsetof(tDot11fIEWscReassocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscReassocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscReassocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_reassoc_res. */ + +#define SigIeWscReassocRes (0x0073) + + +uint32_t dot11f_unpack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEext_chan_switch_ann *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->switch_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->new_reg_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->new_channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->switch_count = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_chan_switch_ann. */ + +#define SigIeext_chan_switch_ann (0x0074) + + +uint32_t dot11f_unpack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_coexistence *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp65__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp65__ = *pBuf; + pDst->info_request = tmp65__ >> 0 & 0x1; + pDst->forty_mhz_intolerant = tmp65__ >> 1 & 0x1; + pDst->twenty_mhz_bsswidth_req = tmp65__ >> 2 & 0x1; + pDst->obss_scan_exemption_req = tmp65__ >> 3 & 0x1; + pDst->obss_scan_exemption_grant = tmp65__ >> 4 & 0x1; + pDst->unused = tmp65__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_coexistence. */ + +#define SigIeht2040_bss_coexistence (0x0075) + + +uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_intolerant_report *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->operating_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channel_list = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channel_list, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_intolerant_report. */ + +#define SigIeht2040_bss_intolerant_report (0x0076) + + +uint32_t dot11f_unpack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEsec_chan_offset_ele *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->secondaryChannelOffset = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_sec_chan_offset_ele. */ + +#define SigIesec_chan_offset_ele (0x0077) + + +static const tFFDefn FFS_vendor2_ie[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_vendor2_ie[] = { + { offsetof(tDot11fIEvendor2_ie, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fIEvendor2_ie, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_vendor2_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEvendor2_ie *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->sub_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_vendor2_ie, + IES_vendor2_ie, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_vendor2_ie. */ + +#define SigIevendor2_ie (0x0078) + + +static const tFFDefn FFS_AddTSRequest[] = { + { "Category", offsetof(tDot11fAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSRequest[] = { + { offsetof(tDot11fAddTSRequest, TSPEC), offsetof(tDot11fIETSPEC, present), + 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 1, }, + { offsetof(tDot11fAddTSRequest, TCLAS), offsetof(tDot11fIETCLAS, present), + offsetof(tDot11fAddTSRequest, num_TCLAS), "TCLAS", 2, 7, 45, SigIeTCLAS, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fAddTSRequest, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSRequest, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSRequest, IES_AddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +static const tFFDefn FFS_AddTSResponse[] = { + { "Category", offsetof(tDot11fAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11fAddTSResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSResponse[] = { + { offsetof(tDot11fAddTSResponse, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 1, }, + { offsetof(tDot11fAddTSResponse, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 1, }, + { offsetof(tDot11fAddTSResponse, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fAddTSResponse, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fAddTSResponse, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fAddTSResponse, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, }, + { offsetof(tDot11fAddTSResponse, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSResponse, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSResponse, IES_AddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +static const tFFDefn FFS_AssocRequest[] = { + { "Capabilities", offsetof(tDot11fAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocRequest[] = { + { offsetof(tDot11fAssocRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fAssocRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fAssocRequest, PowerCaps), offsetof(tDot11fIEPowerCaps, + present), 0, "PowerCaps", 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCAPS, 0, }, + { offsetof(tDot11fAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fAssocRequest, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAssocRequest, WPAOpaque), offsetof(tDot11fIEWPAOpaque, + present), 0, "WPAOpaque", 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fAssocRequest, vendor2_ie), + offsetof(tDot11fIEvendor2_ie, present), 0, "vendor2_ie", + 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocRequest, IES_AssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_request. */ + +static const tFFDefn FFS_AssocResponse[] = { + { "Capabilities", offsetof(tDot11fAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocResponse[] = { + { offsetof(tDot11fAssocResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, }, + { offsetof(tDot11fAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, }, + { offsetof(tDot11fAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fAssocResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fAssocResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fAssocResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAssocResponse, WscAssocRes), + offsetof(tDot11fIEWscAssocRes, present), 0, "WscAssocRes", + 0, 6, 37, SigIeWscAssocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCASSOCRES, 0, }, + { offsetof(tDot11fAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, }, + { offsetof(tDot11fAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fAssocResponse, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fAssocResponse, vendor2_ie), + offsetof(tDot11fIEvendor2_ie, present), 0, "vendor2_ie", + 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocResponse, IES_AssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_response. */ + +static const tFFDefn FFS_Authentication[] = { + { "AuthAlgo", offsetof(tDot11fAuthentication, AuthAlgo), SigFfAuthAlgo, + DOT11F_FF_AUTHALGO_LEN, }, + { "AuthSeqNo", offsetof(tDot11fAuthentication, AuthSeqNo), SigFfAuthSeqNo, + DOT11F_FF_AUTHSEQNO_LEN, }, + { "Status", offsetof(tDot11fAuthentication, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Authentication[] = { + { offsetof(tDot11fAuthentication, ChallengeText), + offsetof(tDot11fIEChallengeText, present), 0, "ChallengeText", + 0, 3, 255, SigIeChallengeText, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHALLENGETEXT, 0, }, + { offsetof(tDot11fAuthentication, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fAuthentication, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAuthentication, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fAuthentication, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fAuthentication, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAuthentication, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Authentication, IES_Authentication, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_authentication. */ + +static const tFFDefn FFS_Beacon[] = { + { "TimeStamp", offsetof(tDot11fBeacon, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon[] = { + { offsetof(tDot11fBeacon, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeacon, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeacon, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fBeacon, DSParams), offsetof(tDot11fIEDSParams, present), + 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeacon, CFParams), offsetof(tDot11fIECFParams, present), + 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fBeacon, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fBeacon, TIM), offsetof(tDot11fIETIM, present), 0, "TIM", + 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, }, + { offsetof(tDot11fBeacon, Country), offsetof(tDot11fIECountry, present), 0, + "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeacon, FHParams), offsetof(tDot11fIEFHParams, present), + 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fBeacon, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fBeacon, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeacon, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeacon, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeacon, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeacon, ERPInfo), offsetof(tDot11fIEERPInfo, present), 0, + "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeacon, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeacon, RSN), offsetof(tDot11fIERSN, present), 0, "RSN", + 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fBeacon, QBSSLoad), offsetof(tDot11fIEQBSSLoad, present), + 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fBeacon, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeacon, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, }, + { offsetof(tDot11fBeacon, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeacon, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeacon, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeacon, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeacon, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeacon, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeacon, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeacon, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeacon, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeacon, WMMCaps), offsetof(tDot11fIEWMMCaps, present), 0, + "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeacon, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeacon, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeacon, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeacon, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeacon, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, }, + { offsetof(tDot11fBeacon, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, }, + { offsetof(tDot11fBeacon, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, + "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeacon, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeacon, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeacon, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeacon, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeacon, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeacon, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeacon, vendor2_ie), offsetof(tDot11fIEvendor2_ie, + present), 0, "vendor2_ie", 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + { offsetof(tDot11fBeacon, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeacon, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 7, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeacon, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fBeacon, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon, IES_Beacon, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon. */ + +static const tFFDefn FFS_Beacon1[] = { + { "TimeStamp", offsetof(tDot11fBeacon1, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon1, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon1, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon1[] = { + { offsetof(tDot11fBeacon1, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeacon1, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeacon1, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeacon1, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon1, IES_Beacon1, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon1. */ + +static const tFFDefn FFS_Beacon2[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon2[] = { + { offsetof(tDot11fBeacon2, Country), offsetof(tDot11fIECountry, present), + 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeacon2, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeacon2, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon2, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeacon2, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeacon2, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeacon2, ERPInfo), offsetof(tDot11fIEERPInfo, present), + 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeacon2, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeacon2, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fBeacon2, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeacon2, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeacon2, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeacon2, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeacon2, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeacon2, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeacon2, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeacon2, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeacon2, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeacon2, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeacon2, WMMCaps), offsetof(tDot11fIEWMMCaps, present), + 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeacon2, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, }, + { offsetof(tDot11fBeacon2, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeacon2, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeacon2, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeacon2, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeacon2, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, }, + { offsetof(tDot11fBeacon2, VHTCaps), offsetof(tDot11fIEVHTCaps, present), + 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeacon2, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeacon2, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeacon2, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeacon2, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeacon2, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon2, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeacon2, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeacon2, vendor2_ie), offsetof(tDot11fIEvendor2_ie, + present), 0, "vendor2_ie", 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + { offsetof(tDot11fBeacon2, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeacon2, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 7, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeacon2, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fBeacon2, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon2, IES_Beacon2, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon2. */ + +static const tFFDefn FFS_BeaconIEs[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_BeaconIEs[] = { + { offsetof(tDot11fBeaconIEs, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeaconIEs, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeaconIEs, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fBeaconIEs, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, TIM), offsetof(tDot11fIETIM, present), 0, + "TIM", 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, }, + { offsetof(tDot11fBeaconIEs, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeaconIEs, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fBeaconIEs, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeaconIEs, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeaconIEs, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeaconIEs, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeaconIEs, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeaconIEs, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeaconIEs, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeaconIEs, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fBeaconIEs, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fBeaconIEs, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeaconIEs, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, }, + { offsetof(tDot11fBeaconIEs, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeaconIEs, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeaconIEs, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeaconIEs, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeaconIEs, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, HTInfo), offsetof(tDot11fIEHTInfo, present), + 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeaconIEs, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeaconIEs, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeaconIEs, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeaconIEs, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fBeaconIEs, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeaconIEs, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeaconIEs, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeaconIEs, WscBeaconProbeRes), + offsetof(tDot11fIEWscBeaconProbeRes, present), 0, "WscBeaconProbeRes", + 0, 6, 319, SigIeWscBeaconProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACONPROBERES, 0, }, + { offsetof(tDot11fBeaconIEs, P2PBeaconProbeRes), + offsetof(tDot11fIEP2PBeaconProbeRes, present), 0, "P2PBeaconProbeRes", + 0, 6, 1150, SigIeP2PBeaconProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACONPROBERES, 0, }, + { offsetof(tDot11fBeaconIEs, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeaconIEs, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeaconIEs, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeaconIEs, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeaconIEs, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeaconIEs, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeaconIEs, vendor2_ie), offsetof(tDot11fIEvendor2_ie, + present), 0, "vendor2_ie", 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeaconIEs, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 7, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeaconIEs, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_BeaconIEs, IES_BeaconIEs, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +static const tFFDefn FFS_ChannelSwitch[] = { + { "Category", offsetof(tDot11fChannelSwitch, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fChannelSwitch, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitch[] = { + { offsetof(tDot11fChannelSwitch, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 1, }, + { offsetof(tDot11fChannelSwitch, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fChannelSwitch, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ChannelSwitch, IES_ChannelSwitch, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_channel_switch. */ + +static const tFFDefn FFS_DeAuth[] = { + { "Reason", offsetof(tDot11fDeAuth, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DeAuth[] = { + { offsetof(tDot11fDeAuth, P2PDeAuth), offsetof(tDot11fIEP2PDeAuth, + present), 0, "P2PDeAuth", 0, 6, 10, SigIeP2PDeAuth, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDEAUTH, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DeAuth, IES_DeAuth, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_de_auth. */ + +static const tFFDefn FFS_DelTS[] = { + { "Category", offsetof(tDot11fDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TSInfo", offsetof(tDot11fDelTS, TSInfo), SigFfTSInfo, + DOT11F_FF_TSINFO_LEN, }, + { "Reason", offsetof(tDot11fDelTS, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DelTS[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DelTS, IES_DelTS, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_del_ts. */ + +static const tFFDefn FFS_Disassociation[] = { + { "Reason", offsetof(tDot11fDisassociation, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Disassociation[] = { + { offsetof(tDot11fDisassociation, P2PDisAssoc), + offsetof(tDot11fIEP2PDisAssoc, present), 0, "P2PDisAssoc", + 0, 6, 10, SigIeP2PDisAssoc, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDISASSOC, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Disassociation, IES_Disassociation, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_disassociation. */ + +static const tFFDefn FFS_LinkMeasurementReport[] = { + { "Category", offsetof(tDot11fLinkMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TPCEleID", offsetof(tDot11fLinkMeasurementReport, TPCEleID), + SigFfTPCEleID, DOT11F_FF_TPCELEID_LEN, }, + { "TPCEleLen", offsetof(tDot11fLinkMeasurementReport, TPCEleLen), + SigFfTPCEleLen, DOT11F_FF_TPCELELEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementReport, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "LinkMargin", offsetof(tDot11fLinkMeasurementReport, LinkMargin), + SigFfLinkMargin, DOT11F_FF_LINKMARGIN_LEN, }, + { "RxAntennaId", offsetof(tDot11fLinkMeasurementReport, RxAntennaId), + SigFfRxAntennaId, DOT11F_FF_RXANTENNAID_LEN, }, + { "TxAntennaId", offsetof(tDot11fLinkMeasurementReport, TxAntennaId), + SigFfTxAntennaId, DOT11F_FF_TXANTENNAID_LEN, }, + { "RCPI", offsetof(tDot11fLinkMeasurementReport, RCPI), SigFfRCPI, + DOT11F_FF_RCPI_LEN, }, + { "RSNI", offsetof(tDot11fLinkMeasurementReport, RSNI), SigFfRSNI, + DOT11F_FF_RSNI_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementReport[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +static const tFFDefn FFS_LinkMeasurementRequest[] = { + { "Category", offsetof(tDot11fLinkMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementRequest, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "MaxTxPower", offsetof(tDot11fLinkMeasurementRequest, MaxTxPower), + SigFfMaxTxPower, DOT11F_FF_MAXTXPOWER_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementRequest[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +static const tFFDefn FFS_MeasurementReport[] = { + { "Category", offsetof(tDot11fMeasurementReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementReport[] = { + { offsetof(tDot11fMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), 0, "MeasurementReport", + 0, 5, 31, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementReport, IES_MeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_report. */ + +static const tFFDefn FFS_MeasurementRequest[] = { + { "Category", offsetof(tDot11fMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementRequest[] = { + { offsetof(tDot11fMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 4, 16, 18, SigIeMeasurementRequest, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MEASUREMENTREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementRequest, IES_MeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_request. */ + +static const tFFDefn FFS_NeighborReportRequest[] = { + { "Category", offsetof(tDot11fNeighborReportRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportRequest[] = { + { offsetof(tDot11fNeighborReportRequest, SSID), offsetof(tDot11fIESSID, + present), 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SSID, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportRequest, IES_NeighborReportRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +static const tFFDefn FFS_NeighborReportResponse[] = { + { "Category", offsetof(tDot11fNeighborReportResponse, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportResponse[] = { + { offsetof(tDot11fNeighborReportResponse, NeighborReport), + offsetof(tDot11fIENeighborReport, present), + offsetof(tDot11fNeighborReportResponse, num_NeighborReport), + "NeighborReport", 15, 15, 548, SigIeNeighborReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_NEIGHBORREPORT, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportResponse, IES_NeighborReportResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +static const tFFDefn FFS_OperatingMode[] = { + { "Category", offsetof(tDot11fOperatingMode, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fOperatingMode, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "OperatingMode", offsetof(tDot11fOperatingMode, OperatingMode), + SigFfOperatingMode, DOT11F_FF_OPERATINGMODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_OperatingMode[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_OperatingMode, IES_OperatingMode, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_operating_mode. */ + +static const tFFDefn FFS_ProbeRequest[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeRequest[] = { + { offsetof(tDot11fProbeRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fProbeRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fProbeRequest, RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, }, + { offsetof(tDot11fProbeRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fProbeRequest, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fProbeRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fProbeRequest, WscProbeReq), + offsetof(tDot11fIEWscProbeReq, present), 0, "WscProbeReq", + 0, 6, 286, SigIeWscProbeReq, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBEREQ, 0, }, + { offsetof(tDot11fProbeRequest, WFATPC), offsetof(tDot11fIEWFATPC, + present), 0, "WFATPC", 0, 9, 9, SigIeWFATPC, {0, 80, 242, 8, 0}, + 5, DOT11F_EID_WFATPC, 0, }, + { offsetof(tDot11fProbeRequest, P2PProbeReq), + offsetof(tDot11fIEP2PProbeReq, present), 0, "P2PProbeReq", + 0, 6, 43, SigIeP2PProbeReq, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBEREQ, 0, }, + { offsetof(tDot11fProbeRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fProbeRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeRequest, IES_ProbeRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_request. */ + +static const tFFDefn FFS_ProbeResponse[] = { + { "TimeStamp", offsetof(tDot11fProbeResponse, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fProbeResponse, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fProbeResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeResponse[] = { + { offsetof(tDot11fProbeResponse, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fProbeResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fProbeResponse, FHParamSet), + offsetof(tDot11fIEFHParamSet, present), 0, "FHParamSet", + 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fProbeResponse, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, IBSSParams), + offsetof(tDot11fIEIBSSParams, present), 0, "IBSSParams", + 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fProbeResponse, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, FHPattTable), + offsetof(tDot11fIEFHPattTable, present), 0, "FHPattTable", + 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fProbeResponse, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fProbeResponse, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fProbeResponse, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fProbeResponse, Quiet), offsetof(tDot11fIEQuiet, + present), 0, "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fProbeResponse, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fProbeResponse, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fProbeResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fProbeResponse, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fProbeResponse, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fProbeResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fProbeResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fProbeResponse, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fProbeResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fProbeResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fProbeResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fProbeResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fProbeResponse, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fProbeResponse, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fProbeResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fProbeResponse, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fProbeResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fProbeResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fProbeResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fProbeResponse, WscProbeRes), + offsetof(tDot11fIEWscProbeRes, present), 0, "WscProbeRes", + 0, 6, 319, SigIeWscProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBERES, 0, }, + { offsetof(tDot11fProbeResponse, P2PProbeRes), + offsetof(tDot11fIEP2PProbeRes, present), 0, "P2PProbeRes", + 0, 6, 1141, SigIeP2PProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBERES, 0, }, + { offsetof(tDot11fProbeResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fProbeResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fProbeResponse, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fProbeResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fProbeResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fProbeResponse, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fProbeResponse, vendor2_ie), + offsetof(tDot11fIEvendor2_ie, present), 0, "vendor2_ie", + 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + { offsetof(tDot11fProbeResponse, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fProbeResponse, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 7, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fProbeResponse, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fProbeResponse, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeResponse, IES_ProbeResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_response. */ + +static const tFFDefn FFS_QosMapConfigure[] = { + { "Category", offsetof(tDot11fQosMapConfigure, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fQosMapConfigure, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_QosMapConfigure[] = { + { offsetof(tDot11fQosMapConfigure, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_QosMapConfigure, IES_QosMapConfigure, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +static const tFFDefn FFS_RadioMeasurementReport[] = { + { "Category", offsetof(tDot11fRadioMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementReport[] = { + { offsetof(tDot11fRadioMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), + offsetof(tDot11fRadioMeasurementReport, num_MeasurementReport), + "MeasurementReport", 4, 5, 31, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +static const tFFDefn FFS_RadioMeasurementRequest[] = { + { "Category", offsetof(tDot11fRadioMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "NumOfRepetitions", offsetof(tDot11fRadioMeasurementRequest, + NumOfRepetitions), SigFfNumOfRepetitions, + DOT11F_FF_NUMOFREPETITIONS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementRequest[] = { + { offsetof(tDot11fRadioMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fRadioMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 2, 16, 18, SigIeMeasurementRequest, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MEASUREMENTREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +static const tFFDefn FFS_ReAssocRequest[] = { + { "Capabilities", offsetof(tDot11fReAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fReAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { "CurrentAPAddress", offsetof(tDot11fReAssocRequest, CurrentAPAddress), + SigFfCurrentAPAddress, DOT11F_FF_CURRENTAPADDRESS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocRequest[] = { + { offsetof(tDot11fReAssocRequest, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fReAssocRequest, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fReAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fReAssocRequest, PowerCaps), + offsetof(tDot11fIEPowerCaps, present), 0, "PowerCaps", + 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_POWERCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fReAssocRequest, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fReAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fReAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fReAssocRequest, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fReAssocRequest, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocRequest, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fReAssocRequest, WPAOpaque), + offsetof(tDot11fIEWPAOpaque, present), 0, "WPAOpaque", + 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fReAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fReAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fReAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fReAssocRequest, ESECckmOpaque), + offsetof(tDot11fIEESECckmOpaque, present), 0, "ESECckmOpaque", + 0, 12, 26, SigIeESECckmOpaque, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESECCKMOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocRequest, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fReAssocRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + { offsetof(tDot11fReAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fReAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fReAssocRequest, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fReAssocRequest, vendor2_ie), + offsetof(tDot11fIEvendor2_ie, present), 0, "vendor2_ie", + 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocRequest, IES_ReAssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +static const tFFDefn FFS_ReAssocResponse[] = { + { "Capabilities", offsetof(tDot11fReAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fReAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fReAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocResponse[] = { + { offsetof(tDot11fReAssocResponse, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fReAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fReAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fReAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, }, + { offsetof(tDot11fReAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, }, + { offsetof(tDot11fReAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fReAssocResponse, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fReAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fReAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fReAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fReAssocResponse, WPA), offsetof(tDot11fIEWPA, present), + 0, "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fReAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fReAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fReAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fReAssocResponse, WMMParams), + offsetof(tDot11fIEWMMParams, present), 0, "WMMParams", + 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fReAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fReAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fReAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + { offsetof(tDot11fReAssocResponse, WscReassocRes), + offsetof(tDot11fIEWscReassocRes, present), 0, "WscReassocRes", + 0, 6, 37, SigIeWscReassocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCREASSOCRES, 0, }, + { offsetof(tDot11fReAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, }, + { offsetof(tDot11fReAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fReAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fReAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fReAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fReAssocResponse, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fReAssocResponse, vendor2_ie), + offsetof(tDot11fIEvendor2_ie, present), 0, "vendor2_ie", + 0, 7, 28, SigIevendor2_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR2_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocResponse, IES_ReAssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +static const tFFDefn FFS_SMPowerSave[] = { + { "Category", offsetof(tDot11fSMPowerSave, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSMPowerSave, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "SMPowerModeSet", offsetof(tDot11fSMPowerSave, SMPowerModeSet), + SigFfSMPowerModeSet, DOT11F_FF_SMPOWERMODESET_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SMPowerSave[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SMPowerSave, IES_SMPowerSave, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +static const tFFDefn FFS_SaQueryReq[] = { + { "Category", offsetof(tDot11fSaQueryReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryReq, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryReq[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryReq, IES_SaQueryReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +static const tFFDefn FFS_SaQueryRsp[] = { + { "Category", offsetof(tDot11fSaQueryRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryRsp, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryRsp[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryRsp, IES_SaQueryRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +static const tFFDefn FFS_TDLSDisReq[] = { + { "Category", offsetof(tDot11fTDLSDisReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisReq[] = { + { offsetof(tDot11fTDLSDisReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisReq, IES_TDLSDisReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +static const tFFDefn FFS_TDLSDisRsp[] = { + { "Category", offsetof(tDot11fTDLSDisRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSDisRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisRsp[] = { + { offsetof(tDot11fTDLSDisRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fTDLSDisRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSDisRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSDisRsp, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSDisRsp, FTInfo), offsetof(tDot11fIEFTInfo, present), + 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSDisRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSDisRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSDisRsp, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSDisRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSDisRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSDisRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisRsp, IES_TDLSDisRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +static const tFFDefn FFS_TDLSPeerTrafficInd[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficInd, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficInd, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficInd, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficInd[] = { + { offsetof(tDot11fTDLSPeerTrafficInd, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PTIControl), + offsetof(tDot11fIEPTIControl, present), 0, "PTIControl", + 0, 5, 5, SigIePTIControl, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PTICONTROL, 0, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PUBufferStatus), + offsetof(tDot11fIEPUBufferStatus, present), 0, "PUBufferStatus", + 0, 3, 3, SigIePUBufferStatus, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PUBUFFERSTATUS, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +static const tFFDefn FFS_TDLSPeerTrafficRsp[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficRsp, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficRsp[] = { + { offsetof(tDot11fTDLSPeerTrafficRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +static const tFFDefn FFS_TDLSSetupCnf[] = { + { "Category", offsetof(tDot11fTDLSSetupCnf, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupCnf, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupCnf, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupCnf, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupCnf[] = { + { offsetof(tDot11fTDLSSetupCnf, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupCnf, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fTDLSSetupCnf, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupCnf, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupCnf, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fTDLSSetupCnf, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, }, + { offsetof(tDot11fTDLSSetupCnf, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fTDLSSetupCnf, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fTDLSSetupCnf, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +static const tFFDefn FFS_TDLSSetupReq[] = { + { "Category", offsetof(tDot11fTDLSSetupReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupReq, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupReq[] = { + { offsetof(tDot11fTDLSSetupReq, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fTDLSSetupReq, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSSetupReq, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSSetupReq, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fTDLSSetupReq, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupReq, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupReq, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSSetupReq, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupReq, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSSetupReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSSetupReq, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fTDLSSetupReq, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, }, + { offsetof(tDot11fTDLSSetupReq, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupReq, IES_TDLSSetupReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +static const tFFDefn FFS_TDLSSetupRsp[] = { + { "Category", offsetof(tDot11fTDLSSetupRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupRsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupRsp[] = { + { offsetof(tDot11fTDLSSetupRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fTDLSSetupRsp, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSSetupRsp, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSSetupRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, }, + { offsetof(tDot11fTDLSSetupRsp, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fTDLSSetupRsp, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, }, + { offsetof(tDot11fTDLSSetupRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +static const tFFDefn FFS_TDLSTeardown[] = { + { "Category", offsetof(tDot11fTDLSTeardown, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSTeardown, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Reason", offsetof(tDot11fTDLSTeardown, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSTeardown[] = { + { offsetof(tDot11fTDLSTeardown, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSTeardown, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSTeardown, IES_TDLSTeardown, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +static const tFFDefn FFS_TPCReport[] = { + { "Category", offsetof(tDot11fTPCReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCReport[] = { + { offsetof(tDot11fTPCReport, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCReport, IES_TPCReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_report. */ + +static const tFFDefn FFS_TPCRequest[] = { + { "Category", offsetof(tDot11fTPCRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCRequest[] = { + { offsetof(tDot11fTPCRequest, TPCRequest), offsetof(tDot11fIETPCRequest, + present), 0, "TPCRequest", 0, 2, 2, SigIeTPCRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCRequest, IES_TPCRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_request. */ + +static const tFFDefn FFS_TimingAdvertisementFrame[] = { + { "TimeStamp", offsetof(tDot11fTimingAdvertisementFrame, TimeStamp), + SigFfTimeStamp, DOT11F_FF_TIMESTAMP_LEN, }, + { "Capabilities", offsetof(tDot11fTimingAdvertisementFrame, + Capabilities), SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TimingAdvertisementFrame[] = { + { offsetof(tDot11fTimingAdvertisementFrame, Country), + offsetof(tDot11fIECountry, present), 0, "Country", 0, 5, 257, SigIeCountry, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, TimeAdvertisement), + offsetof(tDot11fIETimeAdvertisement, present), 0, "TimeAdvertisement", + 0, 18, 18, SigIeTimeAdvertisement, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEADVERTISEMENT, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, ExtCap), + offsetof(tDot11fIEExtCap, present), 0, "ExtCap", 0, 10, 11, SigIeExtCap, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor1IE), + offsetof(tDot11fIEVendor1IE, present), 0, "Vendor1IE", + 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor3IE), + offsetof(tDot11fIEVendor3IE, present), 0, "Vendor3IE", + 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +static const tFFDefn FFS_VHTGidManagementActionFrame[] = { + { "Category", offsetof(tDot11fVHTGidManagementActionFrame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fVHTGidManagementActionFrame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "VhtMembershipStatusArray", + offsetof(tDot11fVHTGidManagementActionFrame, VhtMembershipStatusArray), + SigFfVhtMembershipStatusArray, + DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN, }, + { "VhtUserPositionArray", offsetof(tDot11fVHTGidManagementActionFrame, + VhtUserPositionArray), SigFfVhtUserPositionArray, + DOT11F_FF_VHTUSERPOSITIONARRAY_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_VHTGidManagementActionFrame[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +static const tFFDefn FFS_WMMAddTSRequest[] = { + { "Category", offsetof(tDot11fWMMAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSRequest, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSRequest[] = { + { offsetof(tDot11fWMMAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 1, }, + { offsetof(tDot11fWMMAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +static const tFFDefn FFS_WMMAddTSResponse[] = { + { "Category", offsetof(tDot11fWMMAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSResponse, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSResponse[] = { + { offsetof(tDot11fWMMAddTSResponse, WMMTSPEC), + offsetof(tDot11fIEWMMTSPEC, present), 0, "WMMTSPEC", + 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fWMMAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +static const tFFDefn FFS_WMMDelTS[] = { + { "Category", offsetof(tDot11fWMMDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMDelTS, DialogToken), SigFfDialogToken, + DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMDelTS, StatusCode), SigFfStatusCode, + DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMDelTS[] = { + { offsetof(tDot11fWMMDelTS, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMDelTS, IES_WMMDelTS, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +static const tFFDefn FFS_ht2040_bss_coexistence_mgmt_action_frame[] = { + { "Category", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Category), SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Action), SigFfAction, DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ht2040_bss_coexistence_mgmt_action_frame[] = { + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_coexistence), offsetof(tDot11fIEht2040_bss_coexistence, + present), 0, "ht2040_bss_coexistence", + 0, 3, 3, SigIeht2040_bss_coexistence, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 1, }, + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_intolerant_report), + offsetof(tDot11fIEht2040_bss_intolerant_report, present), 0, + "ht2040_bss_intolerant_report", + 0, 3, 53, SigIeht2040_bss_intolerant_report, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status; + uint8_t eid, len; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + + DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm); + (void)nFrm; + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pIe = &IEs[0]; + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + *pfFound = 0U; + if (pIe->countOffset) + *(uint16_t *)(pFrm + pIe->countOffset) = 0U; + ++pIe; + } + + pFf = &FFs[0]; + while (pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("Fixed field %s is %d" + "bytes in size, but there are only %d bytes left i" + "n this frame.\n"), pFf->name, pFf->size, + nBufRemaining); + FRAMES_DBG_BREAK(); + return DOT11F_MISSING_FIXED_FIELD; + } + + switch (pFf->sig) { + + case SigFfAID: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAID *) + (pFrm + pFf->offset))->associd)); + break; + case SigFfAction: + dot11f_unpack_ff_action(pCtx, + pBufRemaining, (tDot11fFfAction *) + (pFrm + pFf->offset)); + break; + case SigFfAuthAlgo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthAlgo *) + (pFrm + pFf->offset))->algo)); + break; + case SigFfAuthSeqNo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthSeqNo *) + (pFrm + pFf->offset))->no)); + break; + case SigFfBeaconInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfBeaconInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfCapabilities: + dot11f_unpack_ff_capabilities(pCtx, + pBufRemaining, (tDot11fFfCapabilities *) + (pFrm + pFf->offset)); + break; + case SigFfCategory: + dot11f_unpack_ff_category(pCtx, + pBufRemaining, (tDot11fFfCategory *) + (pFrm + pFf->offset)); + break; + case SigFfCurrentAPAddress: + dot11f_unpack_ff_current_ap_address(pCtx, + pBufRemaining, (tDot11fFfCurrentAPAddress *) + (pFrm + pFf->offset)); + break; + case SigFfDialogToken: + dot11f_unpack_ff_dialog_token(pCtx, + pBufRemaining, (tDot11fFfDialogToken *) + (pFrm + pFf->offset)); + break; + case SigFfLinkMargin: + dot11f_unpack_ff_link_margin(pCtx, + pBufRemaining, (tDot11fFfLinkMargin *) + (pFrm + pFf->offset)); + break; + case SigFfListenInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfListenInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfMaxTxPower: + dot11f_unpack_ff_max_tx_power(pCtx, + pBufRemaining, (tDot11fFfMaxTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfNumOfRepetitions: + dot11f_unpack_ff_num_of_repetitions(pCtx, + pBufRemaining, (tDot11fFfNumOfRepetitions *) + (pFrm + pFf->offset)); + break; + case SigFfOperatingMode: + dot11f_unpack_ff_operating_mode(pCtx, + pBufRemaining, (tDot11fFfOperatingMode *) + (pFrm + pFf->offset)); + break; + case SigFfRCPI: + dot11f_unpack_ff_rcpi(pCtx, + pBufRemaining, (tDot11fFfRCPI *) + (pFrm + pFf->offset)); + break; + case SigFfRSNI: + dot11f_unpack_ff_rsni(pCtx, + pBufRemaining, (tDot11fFfRSNI *) + (pFrm + pFf->offset)); + break; + case SigFfReason: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfReason *) + (pFrm + pFf->offset))->code)); + break; + case SigFfRxAntennaId: + dot11f_unpack_ff_rx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfRxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfSMPowerModeSet: + dot11f_unpack_ff_sm_power_mode_set(pCtx, + pBufRemaining, (tDot11fFfSMPowerModeSet *) + (pFrm + pFf->offset)); + break; + case SigFfStatus: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfStatus *) + (pFrm + pFf->offset))->status)); + break; + case SigFfStatusCode: + dot11f_unpack_ff_status_code(pCtx, + pBufRemaining, (tDot11fFfStatusCode *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleID: + dot11f_unpack_ff_tpc_ele_id(pCtx, + pBufRemaining, (tDot11fFfTPCEleID *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleLen: + dot11f_unpack_ff_tpc_ele_len(pCtx, + pBufRemaining, (tDot11fFfTPCEleLen *) + (pFrm + pFf->offset)); + break; + case SigFfTSInfo: + dot11f_unpack_ff_ts_info(pCtx, + pBufRemaining, (tDot11fFfTSInfo *) + (pFrm + pFf->offset)); + break; + case SigFfTimeStamp: + dot11f_unpack_ff_time_stamp(pCtx, + pBufRemaining, (tDot11fFfTimeStamp *) + (pFrm + pFf->offset)); + break; + case SigFfTransactionId: + dot11f_unpack_ff_transaction_id(pCtx, + pBufRemaining, (tDot11fFfTransactionId *) + (pFrm + pFf->offset)); + break; + case SigFfTxAntennaId: + dot11f_unpack_ff_tx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfTxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfTxPower: + dot11f_unpack_ff_tx_power(pCtx, + pBufRemaining, (tDot11fFfTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfVhtMembershipStatusArray: + dot11f_unpack_ff_vht_membership_status_array(pCtx, + pBufRemaining, (tDot11fFfVhtMembershipStatusArray *) + (pFrm + pFf->offset)); + break; + case SigFfVhtUserPositionArray: + dot11f_unpack_ff_vht_user_position_array(pCtx, + pBufRemaining, (tDot11fFfVhtUserPositionArray *) + (pFrm + pFf->offset)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I don'" + "t know about the FF signature %d-- this is most " + "likely a 'framesc' bug.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + ++pFf; + } + + while (nBufRemaining) { + if (1 == nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "only one byte remaining after it's fixed fields.\n")); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + pIe = find_ie_defn(pCtx, pBufRemaining, nBufRemaining, IEs); + + eid = *pBufRemaining++; --nBufRemaining; + len = *pBufRemaining++; --nBufRemaining; + + if (pIe && pIe->noui) { + if (pIe->noui > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("IE %d reports " + "length %d, but it has an OUI of %d bytes.\n"), + eid, len, pIe->noui); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += pIe->noui; + nBufRemaining -= pIe->noui; + len -= pIe->noui; + } + + if (len > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("IE %d reports length %" + "d, but there are only %d bytes remaining in this" + " frame.\n"), eid, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + if (pIe) { + if (nBufRemaining < pIe->minSize - pIe->noui - 2U) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but there are onl" + "y %d bytes remaining in this frame.\n"), + pIe->name, pIe->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else { + if (len > pIe->maxSize - pIe->noui - 2U) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The IE %s reports " + "an unexpectedly large size; it is presumably " + "more up-to-date than this parser, but this wa" + "rning may also indicate a corrupt frame.\n"), + pIe->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + } + + countOffset = ((0 != pIe->arraybound) * + (*(uint16_t *)(pFrm + pIe->countOffset))); + switch (pIe->sig) { + case SigIeCondensedCountryStr: + status |= + dot11f_unpack_ie_condensed_country_str( + pCtx, pBufRemaining, len, + (tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * + countOffset)); + break; + case SigIeGTK: + status |= + dot11f_unpack_ie_gtk( + pCtx, pBufRemaining, len, + (tDot11fIEGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEGTK) * + countOffset)); + break; + case SigIeIGTK: + status |= + dot11f_unpack_ie_igtk( + pCtx, pBufRemaining, len, + (tDot11fIEIGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIGTK) * + countOffset)); + break; + case SigIeR0KH_ID: + status |= + dot11f_unpack_ie_r0_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER0KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER0KH_ID) * + countOffset)); + break; + case SigIeR1KH_ID: + status |= + dot11f_unpack_ie_r1_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER1KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER1KH_ID) * + countOffset)); + break; + case SigIeTSFInfo: + status |= + dot11f_unpack_ie_tsf_info( + pCtx, pBufRemaining, len, + (tDot11fIETSFInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSFInfo) * + countOffset)); + break; + case SigIeAPChannelReport: + status |= + dot11f_unpack_ie_ap_channel_report( + pCtx, pBufRemaining, len, + (tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * + countOffset)); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_unpack_ie_bcn_reporting_detail( + pCtx, pBufRemaining, len, + (tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * + countOffset)); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_unpack_ie_beacon_report_frm_body( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * + countOffset)); + break; + case SigIeBeaconReporting: + status |= + dot11f_unpack_ie_beacon_reporting( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * + countOffset)); + break; + case SigIeMeasurementPilot: + status |= + dot11f_unpack_ie_measurement_pilot( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * + countOffset)); + break; + case SigIeMultiBssid: + status |= + dot11f_unpack_ie_multi_bssid( + pCtx, pBufRemaining, len, + (tDot11fIEMultiBssid *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMultiBssid) * + countOffset)); + break; + case SigIeRICData: + status |= + dot11f_unpack_ie_ric_data( + pCtx, pBufRemaining, len, + (tDot11fIERICData *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICData) * + countOffset)); + break; + case SigIeRICDescriptor: + status |= + dot11f_unpack_ie_ric_descriptor( + pCtx, pBufRemaining, len, + (tDot11fIERICDescriptor *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDescriptor) * + countOffset)); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_unpack_ie_rrm_enabled_cap( + pCtx, pBufRemaining, len, + (tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * + countOffset)); + break; + case SigIeRequestedInfo: + status |= + dot11f_unpack_ie_requested_info( + pCtx, pBufRemaining, len, + (tDot11fIERequestedInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIERequestedInfo) * + countOffset)); + break; + case SigIeSSID: + status |= + dot11f_unpack_ie_ssid( + pCtx, pBufRemaining, len, + (tDot11fIESSID *) + (pFrm + pIe->offset + + sizeof(tDot11fIESSID) * + countOffset)); + break; + case SigIeSchedule: + status |= + dot11f_unpack_ie_schedule( + pCtx, pBufRemaining, len, + (tDot11fIESchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIESchedule) * + countOffset)); + break; + case SigIeTCLAS: + status |= + dot11f_unpack_ie_tclas( + pCtx, pBufRemaining, len, + (tDot11fIETCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIETCLAS) * + countOffset)); + break; + case SigIeTCLASSPROC: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->present), + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->processing)); + break; + case SigIeTSDelay: + status |= + dot11f_unpack_ie_ts_delay( + pCtx, pBufRemaining, len, + (tDot11fIETSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSDelay) * + countOffset)); + break; + case SigIeTSPEC: + status |= + dot11f_unpack_ie_tspec( + pCtx, pBufRemaining, len, + (tDot11fIETSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSPEC) * + countOffset)); + break; + case SigIeVHTCaps: + status |= + dot11f_unpack_ie_vht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEVHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTCaps) * + countOffset)); + break; + case SigIeVHTOperation: + status |= + dot11f_unpack_ie_vht_operation( + pCtx, pBufRemaining, len, + (tDot11fIEVHTOperation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTOperation) * + countOffset)); + break; + case SigIeWMMSchedule: + status |= + dot11f_unpack_ie_wmm_schedule( + pCtx, pBufRemaining, len, + (tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * + countOffset)); + break; + case SigIeWMMTCLAS: + status |= + dot11f_unpack_ie_wmmtclas( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * + countOffset)); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_unpack_ie_wmmtclasproc( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * + countOffset)); + break; + case SigIeWMMTSDelay: + status |= + dot11f_unpack_ie_wmmts_delay( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * + countOffset)); + break; + case SigIeWMMTSPEC: + status |= + dot11f_unpack_ie_wmmtspec( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * + countOffset)); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_unpack_ie_wider_bw_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * + countOffset)); + break; + case SigIeAID: + status |= + dot11f_unpack_ie_aid( + pCtx, pBufRemaining, len, + (tDot11fIEAID *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAID) * + countOffset)); + break; + case SigIeCFParams: + status |= + dot11f_unpack_ie_cf_params( + pCtx, pBufRemaining, len, + (tDot11fIECFParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIECFParams) * + countOffset)); + break; + case SigIeChallengeText: + status |= + dot11f_unpack_ie_challenge_text( + pCtx, pBufRemaining, len, + (tDot11fIEChallengeText *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChallengeText) * + countOffset)); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_unpack_ie_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * + countOffset)); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_unpack_ie_channel_switch_wrapper( + pCtx, pBufRemaining, len, + (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * + countOffset)); + break; + case SigIeCountry: + status |= + dot11f_unpack_ie_country( + pCtx, pBufRemaining, len, + (tDot11fIECountry *) + (pFrm + pIe->offset + + sizeof(tDot11fIECountry) * + countOffset)); + break; + case SigIeDSParams: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->present), + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->curr_channel)); + break; + case SigIeEDCAParamSet: + status |= + dot11f_unpack_ie_edca_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * + countOffset)); + break; + case SigIeERPInfo: + status |= + dot11f_unpack_ie_erp_info( + pCtx, pBufRemaining, len, + (tDot11fIEERPInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEERPInfo) * + countOffset)); + break; + case SigIeESECckmOpaque: + status |= + dot11f_unpack_ie_ese_cckm_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * + countOffset)); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_unpack_ie_ese_rad_mgmt_cap( + pCtx, pBufRemaining, len, + (tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * + countOffset)); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_unpack_ie_ese_traf_strm_met( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * + countOffset)); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_unpack_ie_ese_traf_strm_rate_set( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * + countOffset)); + break; + case SigIeESETxmitPower: + status |= + dot11f_unpack_ie_ese_txmit_power( + pCtx, pBufRemaining, len, + (tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * + countOffset)); + break; + case SigIeESEVersion: + status |= + dot11f_unpack_ie_ese_version( + pCtx, pBufRemaining, len, + (tDot11fIEESEVersion *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESEVersion) * + countOffset)); + break; + case SigIeExtCap: + status |= + dot11f_unpack_ie_ext_cap( + pCtx, pBufRemaining, len, + (tDot11fIEExtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtCap) * + countOffset)); + break; + case SigIeExtSuppRates: + status |= + dot11f_unpack_ie_ext_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * + countOffset)); + break; + case SigIeFHParamSet: + status |= + dot11f_unpack_ie_fh_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEFHParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParamSet) * + countOffset)); + break; + case SigIeFHParams: + status |= + dot11f_unpack_ie_fh_params( + pCtx, pBufRemaining, len, + (tDot11fIEFHParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParams) * + countOffset)); + break; + case SigIeFHPattTable: + status |= + dot11f_unpack_ie_fh_patt_table( + pCtx, pBufRemaining, len, + (tDot11fIEFHPattTable *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHPattTable) * + countOffset)); + break; + case SigIeFTInfo: + status |= + dot11f_unpack_ie_ft_info( + pCtx, pBufRemaining, len, + (tDot11fIEFTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFTInfo) * + countOffset)); + break; + case SigIeHTCaps: + status |= + dot11f_unpack_ie_ht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTCaps) * + countOffset)); + break; + case SigIeHTInfo: + status |= + dot11f_unpack_ie_ht_info( + pCtx, pBufRemaining, len, + (tDot11fIEHTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTInfo) * + countOffset)); + break; + case SigIeIBSSParams: + status |= + dot11f_unpack_ie_ibss_params( + pCtx, pBufRemaining, len, + (tDot11fIEIBSSParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIBSSParams) * + countOffset)); + break; + case SigIeLinkIdentifier: + status |= + dot11f_unpack_ie_link_identifier( + pCtx, pBufRemaining, len, + (tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * + countOffset)); + break; + case SigIeMeasurementReport: + status |= + dot11f_unpack_ie_measurement_report( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * + countOffset)); + break; + case SigIeMeasurementRequest: + status |= + dot11f_unpack_ie_measurement_request( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * + countOffset)); + break; + case SigIeMobilityDomain: + status |= + dot11f_unpack_ie_mobility_domain( + pCtx, pBufRemaining, len, + (tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * + countOffset)); + break; + case SigIeNeighborReport: + if (countOffset < MAX_SUPPORTED_NEIGHBOR_RPT) { + status |= + dot11f_unpack_ie_neighbor_report( + pCtx, pBufRemaining, len, + (tDot11fIENeighborReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIENeighborReport) * + countOffset)); + } else { + status |= DOT11F_BUFFER_OVERFLOW; + } + break; + case SigIeOBSSScanParameters: + status |= + dot11f_unpack_ie_obss_scan_parameters( + pCtx, pBufRemaining, len, + (tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * + countOffset)); + break; + case SigIeOperatingMode: + status |= + dot11f_unpack_ie_operating_mode( + pCtx, pBufRemaining, len, + (tDot11fIEOperatingMode *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOperatingMode) * + countOffset)); + break; + case SigIeP2PAssocReq: + status |= + dot11f_unpack_ie_p2_p_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * + countOffset)); + break; + case SigIeP2PAssocRes: + status |= + dot11f_unpack_ie_p2_p_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * + countOffset)); + break; + case SigIeP2PBeacon: + status |= + dot11f_unpack_ie_p2_p_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * + countOffset)); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_unpack_ie_p2_p_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * + countOffset)); + break; + case SigIeP2PDeAuth: + status |= + dot11f_unpack_ie_p2_p_de_auth( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * + countOffset)); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_unpack_ie_p2_p_dis_assoc( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * + countOffset)); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_unpack_ie_p2_pie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * + countOffset)); + break; + case SigIeP2PProbeReq: + status |= + dot11f_unpack_ie_p2_p_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * + countOffset)); + break; + case SigIeP2PProbeRes: + status |= + dot11f_unpack_ie_p2_p_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * + countOffset)); + break; + case SigIePTIControl: + status |= + dot11f_unpack_ie_pti_control( + pCtx, pBufRemaining, len, + (tDot11fIEPTIControl *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPTIControl) * + countOffset)); + break; + case SigIePUBufferStatus: + status |= + dot11f_unpack_ie_pu_buffer_status( + pCtx, pBufRemaining, len, + (tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * + countOffset)); + break; + case SigIePowerCaps: + status |= + dot11f_unpack_ie_power_caps( + pCtx, pBufRemaining, len, + (tDot11fIEPowerCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerCaps) * + countOffset)); + break; + case SigIePowerConstraints: + status |= + dot11f_unpack_ie_power_constraints( + pCtx, pBufRemaining, len, + (tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * + countOffset)); + break; + case SigIeQBSSLoad: + status |= + dot11f_unpack_ie_qbss_load( + pCtx, pBufRemaining, len, + (tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * + countOffset)); + break; + case SigIeQComVendorIE: + status |= + dot11f_unpack_ie_QComVendorIE( + pCtx, pBufRemaining, len, + (tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * + countOffset)); + break; + case SigIeQOSCapsAp: + status |= + dot11f_unpack_ie_qos_caps_ap( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * + countOffset)); + break; + case SigIeQOSCapsStation: + status |= + dot11f_unpack_ie_qos_caps_station( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * + countOffset)); + break; + case SigIeQosMapSet: + status |= + dot11f_unpack_ie_qos_map_set( + pCtx, pBufRemaining, len, + (tDot11fIEQosMapSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQosMapSet) * + countOffset)); + break; + case SigIeQuiet: + status |= + dot11f_unpack_ie_quiet( + pCtx, pBufRemaining, len, + (tDot11fIEQuiet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQuiet) * + countOffset)); + break; + case SigIeRCPIIE: + status |= + dot11f_unpack_ie_rcpiie( + pCtx, pBufRemaining, len, + (tDot11fIERCPIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERCPIIE) * + countOffset)); + break; + case SigIeRICDataDesc: + /* reset the pointers back since this is a container IE and it doesnt have its own EID and Len. */ + pBufRemaining -= 2; + nBufRemaining += 2; + if (pIe && pIe->noui) { + pBufRemaining -= pIe->noui; + nBufRemaining += pIe->noui; + len += pIe->noui; + } + status |= get_container_ies_len(pCtx, pBufRemaining, nBufRemaining, &len, IES_RICDataDesc); + if (status != DOT11F_PARSE_SUCCESS && status != DOT11F_UNKNOWN_IES) + break; + status |= + dot11f_unpack_ie_ric_data_desc( + pCtx, pBufRemaining, len, + (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDataDesc) * + countOffset)); + break; + case SigIeRSN: + status |= + dot11f_unpack_ie_rsn( + pCtx, pBufRemaining, len, + (tDot11fIERSN *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSN) * + countOffset)); + break; + case SigIeRSNIIE: + status |= + dot11f_unpack_ie_rsniie( + pCtx, pBufRemaining, len, + (tDot11fIERSNIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNIIE) * + countOffset)); + break; + case SigIeRSNOpaque: + status |= + dot11f_unpack_ie_rsn_opaque( + pCtx, pBufRemaining, len, + (tDot11fIERSNOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNOpaque) * + countOffset)); + break; + case SigIeSuppChannels: + status |= + dot11f_unpack_ie_supp_channels( + pCtx, pBufRemaining, len, + (tDot11fIESuppChannels *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppChannels) * + countOffset)); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_unpack_ie_supp_operating_classes( + pCtx, pBufRemaining, len, + (tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * + countOffset)); + break; + case SigIeSuppRates: + status |= + dot11f_unpack_ie_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIESuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppRates) * + countOffset)); + break; + case SigIeTIM: + status |= + dot11f_unpack_ie_tim( + pCtx, pBufRemaining, len, + (tDot11fIETIM *) + (pFrm + pIe->offset + + sizeof(tDot11fIETIM) * + countOffset)); + break; + case SigIeTPCReport: + status |= + dot11f_unpack_ie_tpc_report( + pCtx, pBufRemaining, len, + (tDot11fIETPCReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCReport) * + countOffset)); + break; + case SigIeTPCRequest: + status |= + dot11f_unpack_ie_tpc_request( + pCtx, pBufRemaining, len, + (tDot11fIETPCRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCRequest) * + countOffset)); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_unpack_ie_time_advertisement( + pCtx, pBufRemaining, len, + (tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * + countOffset)); + break; + case SigIeTimeoutInterval: + status |= + dot11f_unpack_ie_timeout_interval( + pCtx, pBufRemaining, len, + (tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * + countOffset)); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_unpack_ie_vht_ext_bss_load( + pCtx, pBufRemaining, len, + (tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * + countOffset)); + break; + case SigIeVendor1IE: + status |= + dot11f_unpack_ie_vendor1_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor1IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor1IE) * + countOffset)); + break; + case SigIeVendor3IE: + status |= + dot11f_unpack_ie_vendor3_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor3IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor3IE) * + countOffset)); + break; + case SigIeWAPI: + status |= + dot11f_unpack_ie_wapi( + pCtx, pBufRemaining, len, + (tDot11fIEWAPI *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPI) * + countOffset)); + break; + case SigIeWAPIOpaque: + status |= + dot11f_unpack_ie_wapi_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * + countOffset)); + break; + case SigIeWFATPC: + status |= + dot11f_unpack_ie_wfatpc( + pCtx, pBufRemaining, len, + (tDot11fIEWFATPC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFATPC) * + countOffset)); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_unpack_ie_wfdie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * + countOffset)); + break; + case SigIeWMMCaps: + status |= + dot11f_unpack_ie_wmm_caps( + pCtx, pBufRemaining, len, + (tDot11fIEWMMCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMCaps) * + countOffset)); + break; + case SigIeWMMInfoAp: + status |= + dot11f_unpack_ie_wmm_info_ap( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * + countOffset)); + break; + case SigIeWMMInfoStation: + status |= + dot11f_unpack_ie_wmm_info_station( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * + countOffset)); + break; + case SigIeWMMParams: + status |= + dot11f_unpack_ie_wmm_params( + pCtx, pBufRemaining, len, + (tDot11fIEWMMParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMParams) * + countOffset)); + break; + case SigIeWPA: + status |= + dot11f_unpack_ie_wpa( + pCtx, pBufRemaining, len, + (tDot11fIEWPA *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPA) * + countOffset)); + break; + case SigIeWPAOpaque: + status |= + dot11f_unpack_ie_wpa_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * + countOffset)); + break; + case SigIeWSC: + status |= + dot11f_unpack_ie_wsc( + pCtx, pBufRemaining, len, + (tDot11fIEWSC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWSC) * + countOffset)); + break; + case SigIeWscAssocReq: + status |= + dot11f_unpack_ie_wsc_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * + countOffset)); + break; + case SigIeWscAssocRes: + status |= + dot11f_unpack_ie_wsc_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * + countOffset)); + break; + case SigIeWscBeacon: + status |= + dot11f_unpack_ie_wsc_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeacon) * + countOffset)); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_unpack_ie_wsc_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * + countOffset)); + break; + case SigIeWscIEOpaque: + status |= + dot11f_unpack_ie_wsc_ie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * + countOffset)); + break; + case SigIeWscProbeReq: + status |= + dot11f_unpack_ie_wsc_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * + countOffset)); + break; + case SigIeWscProbeRes: + status |= + dot11f_unpack_ie_wsc_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * + countOffset)); + break; + case SigIeWscReassocRes: + status |= + dot11f_unpack_ie_wsc_reassoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * + countOffset)); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_unpack_ie_ext_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * + countOffset)); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_unpack_ie_ht2040_bss_coexistence( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * + countOffset)); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_unpack_ie_ht2040_bss_intolerant_report( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * + countOffset)); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_unpack_ie_sec_chan_offset_ele( + pCtx, pBufRemaining, len, + (tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * + countOffset)); + break; + case SigIevendor2_ie: + status |= + dot11f_unpack_ie_vendor2_ie( + pCtx, pBufRemaining, len, + (tDot11fIEvendor2_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEvendor2_ie) * + countOffset)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR" + ": I don't know about the IE signature %d" + "-- this is most likely a 'framesc' bug.\n"), + pIe->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } + if (pIe->arraybound) + (++(*(uint16_t *)(pFrm + pIe->countOffset))); + } + } else { + FRAMES_LOG2(pCtx, FRLOG3, FRFL("Skipping unknown IE %d" + " (length %d)\n"), eid, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - 2, len); + status |= DOT11F_UNKNOWN_IES; + } + + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This IE extends past " + "the buffer as it was defined to us. This could" + "mean a corrupt frame, or just an incorrect leng" + "th parameter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_IE_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } + +MandatoryCheck: + pIe = &IEs[0]; + while (0xff != pIe->eid) { + if (pIe->fMandatory) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandato" + "ry IE %s wasn't seen.\n"), + pIe->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_IE_MISSING; + } + } + ++pIe; + } + + return status; +} /* End unpack_core. */ + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm) +{ + const tTLVDefn *pTlv; + uint32_t nBufRemaining, status, npec; + uint16_t id, len; + uint8_t *pBufRemaining, *pfFound; + + (void)pCtx; /* Shutup the compiler */ + (void)nFrm; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + /* While we have data... */ + while (nBufRemaining) { + if (3 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer three byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + npec = 0U; + + /* Look for a matching TLV definition, */ + pTlv = find_tlv_defn(pCtx, pBufRemaining, nBufRemaining, TLVs); + /* consume the type, */ + if (pTlv) { + if (pTlv->sType == 2) { + framesntohs(pCtx, &id, pBufRemaining, pTlv->fMsb); + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + id = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + /* & length, */ + if (pTlv->sLen == 2) { + framesntohs(pCtx, &len, pBufRemaining, pTlv->fMsb); + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + len = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + } else { + pBufRemaining += TLVs[0].sType; + nBufRemaining -= TLVs[0].sType; + framesntohs(pCtx, &len, pBufRemaining, (TLVs[0].sType == 2)); + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 2; + nBufRemaining -= 2; + } + + if (pTlv && pTlv->pec) { + npec = 3U; + if (3 > nBufRemaining) { + FRAMES_LOG2(pCtx, FRLOGW, FRFL("TLV %d reports length" + "%d, but it has a Private Enterprise Code (3 byte" + "s.\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + "of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 3; + nBufRemaining -= 3; + len -= 3; + } + + /* Whether we found a hit or not, we can validate the reported */ + /* length of this TLV: */ + if (len > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("TLV %d reports length %" + "d, but there are only %d bytes remaining in this f" + "rame.\n"), id, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + " of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + /* Now, *if* we found a hit... */ + if (pTlv) { + if (len < pTlv->minSize - npec) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but the size is only " + "%d bytes.\n"), + pTlv->name, pTlv->minSize, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + if (nBufRemaining < pTlv->minSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but there are only " + "%d bytes remaining in this frame.\n"), + pTlv->name, pTlv->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else if (len > pTlv->maxSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The TLV %s reports " + "an illegally large size; this TLV is presumably" + "corrupt or otherwise invalid & will be skipped " + "ipped.\n"), pTlv->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + FRAMES_DBG_BREAK(); + status |= DOT11F_SKIPPED_BAD_TLV; + } else { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_unpack_tlv_authorized_ma_cs(pCtx, + pBufRemaining, len, + (tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->req)); + break; + case SigTlvVersion2: + status |= + dot11f_unpack_tlv_version2(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion2 *) + (pFrm + pTlv->offset)); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->fLocked)); + break; + case SigTlvAssociationState: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvConfigurationError: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->error)); + break; + case SigTlvDeviceName: + status |= + dot11f_unpack_tlv_device_name(pCtx, + pBufRemaining, len, + (tDot11fTLVDeviceName *) + (pFrm + pTlv->offset)); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->id)); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_unpack_tlv_extended_listen_timing(pCtx, + pBufRemaining, len, + (tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset)); + break; + case SigTlvListenChannel: + status |= + dot11f_unpack_tlv_listen_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVListenChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvManufacturer: + status |= + dot11f_unpack_tlv_manufacturer(pCtx, + pBufRemaining, len, + (tDot11fTLVManufacturer *) + (pFrm + pTlv->offset)); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->minorReasonCode)); + break; + case SigTlvModelName: + status |= + dot11f_unpack_tlv_model_name(pCtx, + pBufRemaining, len, + (tDot11fTLVModelName *) + (pFrm + pTlv->offset)); + break; + case SigTlvModelNumber: + status |= + dot11f_unpack_tlv_model_number(pCtx, + pBufRemaining, len, + (tDot11fTLVModelNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_unpack_tlv_notice_of_absence(pCtx, + pBufRemaining, len, + (tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset)); + break; + case SigTlvOperatingChannel: + status |= + dot11f_unpack_tlv_operating_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PCapability: + status |= + dot11f_unpack_tlv_p2_p_capability(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_unpack_tlv_p2_p_device_id(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_unpack_tlv_p2_p_device_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_unpack_tlv_p2_p_group_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PStatus: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->status)); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_unpack_tlv_primary_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRFBands: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->bands)); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_unpack_tlv_request_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->reqType)); + break; + case SigTlvResponseType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->resType)); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->selected)); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvSerialNumber: + status |= + dot11f_unpack_tlv_serial_number(pCtx, + pBufRemaining, len, + (tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_E: + status |= + dot11f_unpack_tlv_uuid_e(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_E *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_R: + status |= + dot11f_unpack_tlv_uuid_r(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_R *) + (pFrm + pTlv->offset)); + break; + case SigTlvVendorExtension: + status |= + dot11f_unpack_tlv_vendor_extension(pCtx, + pBufRemaining, len, + (tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset)); + break; + case SigTlvVersion: + status |= + dot11f_unpack_tlv_version(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion *) + (pFrm + pTlv->offset)); + break; + case SigTlvWPSState: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvP2PInterface: + status |= + dot11f_unpack_tlv_p2_p_interface(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PManageability: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->manageability)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I" + " don't know about the TLV signature %d-- thi" + "s is most likely a 'framesc' bug.\n"), + pTlv->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } /* End switch on sig. */ + } /* End if on length check. */ + + } else { + FRAMES_LOG2(pCtx, FRLOG3, FRFL("Skipping unknown TLV %d (" + "length %d)\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - (pTlv->sType + pTlv->sLen), len); + status |= DOT11F_UNKNOWN_TLVS; + } + + /* Advance to the next TLV */ + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This TLV extends past th" + "e buffer as it was defined to us. This could mean " + "a corrupt frame, or just an incorrect length parame" + "ter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_TLV_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } /* End iteration over TLVs.*/ + +MandatoryCheck: + pTlv = &TLVs[0]; + while (0xffff != pTlv->id) { + if (pTlv->fMandatory) { + pfFound = (uint8_t *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandatory " + "TLV %s wasn't seen.\n"), + pTlv->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_TLV_MISSING; + } + + } + ++pTlv; + } + + return status; +} /* End UnpacTlvkCore. */ +uint32_t dot11f_get_packed_ietclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ietclas. */ + +uint32_t dot11f_get_packed_iewmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewmmtclas. */ + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_ChannelSwitchWrapper); + break; + } + return status; +} /* End dot11f_get_packed_ie_channel_switch_wrapper. */ + +uint32_t dot11f_get_packed_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 3; + if (pIe->num_triplets) { + *pnNeeded += (pIe->num_triplets * 3); + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_country. */ + +uint32_t dot11f_get_packed_ieft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 16; + *pnNeeded += 32; + *pnNeeded += 32; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_FTInfo); + break; + } + return status; +} /* End dot11f_get_packed_ieft_info. */ + +uint32_t dot11f_get_packed_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + if (pIe->type) { + switch (pIe->type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 4; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_reportBeacon); + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_report. */ + +uint32_t dot11f_get_packed_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->measurement_type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 6; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestBeacon); + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_request. */ + +uint32_t dot11f_get_packed_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_NeighborReport); + break; + } + return status; +} /* End dot11f_get_packed_ie_neighbor_report. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_req. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_res. */ + +uint32_t dot11f_get_packed_iep2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeacon); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon. */ + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon_probe_res. */ + +uint32_t dot11f_get_packed_iep2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDeAuth); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_de_auth. */ + +uint32_t dot11f_get_packed_iep2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDisAssoc); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_dis_assoc. */ + +uint32_t dot11f_get_packed_iep2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_req. */ + +uint32_t dot11f_get_packed_iep2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_res. */ + +uint32_t dot11f_get_packed_ieric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_RICDataDesc); + break; + } + return status; +} /* End dot11f_get_packed_ieric_data_desc. */ + +uint32_t dot11f_get_packed_iersn(tpAniSirGlobal pCtx, + tDot11fIERSN *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 4; + if (pIe->pwise_cipher_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->pwise_cipher_suite_count * 4); + if (pIe->akm_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->akm_suite_count * 4); + if (pIe->RSN_Cap) { + *pnNeeded += 2; + } else { + break; + } + if (pIe->pmkid_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->pmkid_count * 16); + if (pIe->gp_mgmt_cipher_suite) { + *pnNeeded += 4; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iersn. */ + +uint32_t dot11f_get_packed_iewapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += (pIe->akm_suite_count * 4); + *pnNeeded += 2; + *pnNeeded += (pIe->unicast_cipher_suite_count * 4); + *pnNeeded += 4; + *pnNeeded += 2; + if (pIe->bkid_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->bkid_count * 16); + break; + } + return status; +} /* End dot11f_get_packed_iewapi. */ + +uint32_t dot11f_get_packed_iewpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + if (pIe->multicast_cipher_present) { + + *pnNeeded += 4; + } else { + break; + } + if (pIe->unicast_cipher_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->unicast_cipher_count * 4); + if (pIe->auth_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->auth_suite_count * 4); + if (pIe->caps) { + *pnNeeded += 2; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewpa. */ + +uint32_t dot11f_get_packed_iewsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WSC); + break; + } + return status; +} /* End dot11f_get_packed_iewsc. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_req. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_res. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeacon); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_req. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscReassocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_reassoc_res. */ + +uint32_t dot11f_get_packed_ie_vendor2_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor2_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_vendor2_ie); + break; + } + return status; +} /* End dot11f_get_packed_ie_vendor2_ie. */ + +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSRequest); + return status; +} /* End dot11f_get_packed_add_ts_request_size. */ + +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSResponse); + return status; +} /* End dot11f_get_packed_add_ts_response_size. */ + +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocRequest); + return status; +} /* End dot11f_get_packed_assoc_request_size. */ + +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocResponse); + return status; +} /* End dot11f_get_packed_assoc_response_size. */ + +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Authentication); + return status; +} /* End dot11f_get_packed_authentication_size. */ + +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon); + return status; +} /* End dot11f_get_packed_beacon_size. */ + +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon1); + return status; +} /* End dot11f_get_packed_beacon1_size. */ + +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon2); + return status; +} /* End dot11f_get_packed_beacon2_size. */ + +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_BeaconIEs); + return status; +} /* End dot11f_get_packed_beacon_i_es_size. */ + +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ChannelSwitch); + return status; +} /* End dot11f_get_packed_channel_switch_size. */ + +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DeAuth); + return status; +} /* End dot11f_get_packed_de_auth_size. */ + +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DelTS); + return status; +} /* End dot11f_get_packed_del_ts_size. */ + +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Disassociation); + return status; +} /* End dot11f_get_packed_disassociation_size. */ + +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 11; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementReport); + return status; +} /* End dot11f_get_packed_link_measurement_report_size. */ + +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementRequest); + return status; +} /* End dot11f_get_packed_link_measurement_request_size. */ + +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementReport); + return status; +} /* End dot11f_get_packed_measurement_report_size. */ + +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementRequest); + return status; +} /* End dot11f_get_packed_measurement_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportRequest); + return status; +} /* End dot11f_get_packed_neighbor_report_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportResponse); + return status; +} /* End dot11f_get_packed_neighbor_report_response_size. */ + +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_OperatingMode); + return status; +} /* End dot11f_get_packed_operating_mode_size. */ + +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeRequest); + return status; +} /* End dot11f_get_packed_probe_request_size. */ + +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeResponse); + return status; +} /* End dot11f_get_packed_probe_response_size. */ + +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_QosMapConfigure); + return status; +} /* End dot11f_get_packed_qos_map_configure_size. */ + +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementReport); + return status; +} /* End dot11f_get_packed_radio_measurement_report_size. */ + +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementRequest); + return status; +} /* End dot11f_get_packed_radio_measurement_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocRequest); + return status; +} /* End dot11f_get_packed_re_assoc_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocResponse); + return status; +} /* End dot11f_get_packed_re_assoc_response_size. */ + +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SMPowerSave); + return status; +} /* End dot11f_get_packed_sm_power_save_size. */ + +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryReq); + return status; +} /* End dot11f_get_packed_sa_query_req_size. */ + +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryRsp); + return status; +} /* End dot11f_get_packed_sa_query_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisReq); + return status; +} /* End dot11f_get_packed_tdls_dis_req_size. */ + +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisRsp); + return status; +} /* End dot11f_get_packed_tdls_dis_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficInd); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_ind_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficRsp); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupCnf); + return status; +} /* End dot11f_get_packed_tdls_setup_cnf_size. */ + +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupReq); + return status; +} /* End dot11f_get_packed_tdls_setup_req_size. */ + +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupRsp); + return status; +} /* End dot11f_get_packed_tdls_setup_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSTeardown); + return status; +} /* End dot11f_get_packed_tdls_teardown_size. */ + +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCReport); + return status; +} /* End dot11f_get_packed_tpc_report_size. */ + +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCRequest); + return status; +} /* End dot11f_get_packed_tpc_request_size. */ + +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TimingAdvertisementFrame); + return status; +} /* End dot11f_get_packed_timing_advertisement_frame_size. */ + +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 26; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_VHTGidManagementActionFrame); + return status; +} /* End dot11f_get_packed_vht_gid_management_action_frame_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSRequest); + return status; +} /* End dot11f_get_packed_wmm_add_ts_request_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSResponse); + return status; +} /* End dot11f_get_packed_wmm_add_ts_response_size. */ + +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMDelTS); + return status; +} /* End dot11f_get_packed_wmm_del_ts_size. */ + +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ht2040_bss_coexistence_mgmt_action_frame); + return status; +} /* End dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize. */ + +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + uint16_t i, n; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + uint32_t byteCount = 0; + uint8_t pIePresent = 0; + uint32_t offset = 0; + + status = DOT11F_PARSE_SUCCESS; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + n = 0; + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (*pfFound) { + countOffset = ((0 == pIe->arraybound) ? 1 : (*(uint16_t *)(pFrm + pIe->countOffset))); + for (i = 0U; i < countOffset; ++i) { + *pnNeeded += 2U + pIe->noui; + byteCount = 0; + switch (pIe->sig) { + case SigIeCondensedCountryStr: + offset = sizeof(tDot11fIECondensedCountryStr); + byteCount = 2; + pIePresent = ((tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeGTK: + offset = sizeof(tDot11fIEGTK); + byteCount = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + num_key + 11; + pIePresent = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeIGTK: + offset = sizeof(tDot11fIEIGTK); + byteCount = 33; + pIePresent = ((tDot11fIEIGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR0KH_ID: + offset = sizeof(tDot11fIER0KH_ID); + byteCount = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + num_PMK_R0_ID; + pIePresent = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR1KH_ID: + offset = sizeof(tDot11fIER1KH_ID); + byteCount = 6; + pIePresent = ((tDot11fIER1KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSFInfo: + offset = sizeof(tDot11fIETSFInfo); + byteCount = 4; + pIePresent = ((tDot11fIETSFInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAPChannelReport: + offset = sizeof(tDot11fIEAPChannelReport); + byteCount = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + num_channelList + 1; + pIePresent = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBcnReportingDetail: + offset = sizeof(tDot11fIEBcnReportingDetail); + byteCount = 1; + pIePresent = ((tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBeaconReportFrmBody: + offset = sizeof(tDot11fIEBeaconReportFrmBody); + byteCount = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + num_reportedFields; + pIePresent = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBeaconReporting: + offset = sizeof(tDot11fIEBeaconReporting); + byteCount = 2; + pIePresent = ((tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMeasurementPilot: + offset = sizeof(tDot11fIEMeasurementPilot); + byteCount = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMultiBssid: + offset = sizeof(tDot11fIEMultiBssid); + byteCount = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICData: + offset = sizeof(tDot11fIERICData); + byteCount = 4; + pIePresent = ((tDot11fIERICData *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDescriptor: + offset = sizeof(tDot11fIERICDescriptor); + byteCount = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + num_variableData + 1; + pIePresent = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRRMEnabledCap: + offset = sizeof(tDot11fIERRMEnabledCap); + byteCount = 5; + pIePresent = ((tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRequestedInfo: + offset = sizeof(tDot11fIERequestedInfo); + byteCount = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + num_requested_eids; + pIePresent = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSSID: + offset = sizeof(tDot11fIESSID); + byteCount = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + num_ssid; + pIePresent = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSchedule: + offset = sizeof(tDot11fIESchedule); + byteCount = 14; + pIePresent = ((tDot11fIESchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTCLAS: + offset = sizeof(tDot11fIETCLAS); + status |= + dot11f_get_packed_ietclas( + pCtx, (tDot11fIETCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeTCLASSPROC: + offset = sizeof(tDot11fIETCLASSPROC); + byteCount = 1; + pIePresent = ((tDot11fIETCLASSPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSDelay: + offset = sizeof(tDot11fIETSDelay); + byteCount = 4; + pIePresent = ((tDot11fIETSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSPEC: + offset = sizeof(tDot11fIETSPEC); + byteCount = 55; + pIePresent = ((tDot11fIETSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTCaps: + offset = sizeof(tDot11fIEVHTCaps); + byteCount = 12; + pIePresent = ((tDot11fIEVHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTOperation: + offset = sizeof(tDot11fIEVHTOperation); + byteCount = 5; + pIePresent = ((tDot11fIEVHTOperation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMSchedule: + offset = sizeof(tDot11fIEWMMSchedule); + byteCount = 15; + pIePresent = ((tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTCLAS: + offset = sizeof(tDot11fIEWMMTCLAS); + status |= + dot11f_get_packed_iewmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWMMTCLASPROC: + offset = sizeof(tDot11fIEWMMTCLASPROC); + byteCount = 2; + pIePresent = ((tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSDelay: + offset = sizeof(tDot11fIEWMMTSDelay); + byteCount = 5; + pIePresent = ((tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSPEC: + offset = sizeof(tDot11fIEWMMTSPEC); + byteCount = 56; + pIePresent = ((tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWiderBWChanSwitchAnn: + offset = sizeof(tDot11fIEWiderBWChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAID: + offset = sizeof(tDot11fIEAID); + byteCount = 2; + pIePresent = ((tDot11fIEAID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCFParams: + offset = sizeof(tDot11fIECFParams); + byteCount = 6; + pIePresent = ((tDot11fIECFParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChallengeText: + offset = sizeof(tDot11fIEChallengeText); + byteCount = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + num_text; + pIePresent = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChanSwitchAnn: + offset = sizeof(tDot11fIEChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChannelSwitchWrapper: + offset = sizeof(tDot11fIEChannelSwitchWrapper); + status |= + dot11f_get_packed_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeCountry: + offset = sizeof(tDot11fIECountry); + status |= + dot11f_get_packed_ie_country( + pCtx, (tDot11fIECountry *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeDSParams: + offset = sizeof(tDot11fIEDSParams); + byteCount = 1; + pIePresent = ((tDot11fIEDSParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeEDCAParamSet: + offset = sizeof(tDot11fIEEDCAParamSet); + byteCount = 18; + pIePresent = ((tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeERPInfo: + offset = sizeof(tDot11fIEERPInfo); + byteCount = 1; + pIePresent = ((tDot11fIEERPInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESECckmOpaque: + offset = sizeof(tDot11fIEESECckmOpaque); + byteCount = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESERadMgmtCap: + offset = sizeof(tDot11fIEESERadMgmtCap); + byteCount = 2; + pIePresent = ((tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmMet: + offset = sizeof(tDot11fIEESETrafStrmMet); + byteCount = 4; + pIePresent = ((tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmRateSet: + offset = sizeof(tDot11fIEESETrafStrmRateSet); + byteCount = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + num_tsrates + 1; + pIePresent = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETxmitPower: + offset = sizeof(tDot11fIEESETxmitPower); + byteCount = 2; + pIePresent = ((tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESEVersion: + offset = sizeof(tDot11fIEESEVersion); + byteCount = 1; + pIePresent = ((tDot11fIEESEVersion *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtCap: + offset = sizeof(tDot11fIEExtCap); + byteCount = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + num_bytes; + pIePresent = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtSuppRates: + offset = sizeof(tDot11fIEExtSuppRates); + byteCount = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParamSet: + offset = sizeof(tDot11fIEFHParamSet); + byteCount = 5; + pIePresent = ((tDot11fIEFHParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParams: + offset = sizeof(tDot11fIEFHParams); + byteCount = 2; + pIePresent = ((tDot11fIEFHParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHPattTable: + offset = sizeof(tDot11fIEFHPattTable); + byteCount = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + num_randtable + 4; + pIePresent = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFTInfo: + offset = sizeof(tDot11fIEFTInfo); + status |= + dot11f_get_packed_ieft_info( + pCtx, (tDot11fIEFTInfo *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeHTCaps: + offset = sizeof(tDot11fIEHTCaps); + byteCount = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 26; + pIePresent = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeHTInfo: + offset = sizeof(tDot11fIEHTInfo); + byteCount = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 22; + pIePresent = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeIBSSParams: + offset = sizeof(tDot11fIEIBSSParams); + byteCount = 2; + pIePresent = ((tDot11fIEIBSSParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeLinkIdentifier: + offset = sizeof(tDot11fIELinkIdentifier); + byteCount = 18; + pIePresent = ((tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMeasurementReport: + offset = sizeof(tDot11fIEMeasurementReport); + status |= + dot11f_get_packed_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMeasurementRequest: + offset = sizeof(tDot11fIEMeasurementRequest); + status |= + dot11f_get_packed_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMobilityDomain: + offset = sizeof(tDot11fIEMobilityDomain); + byteCount = 3; + pIePresent = ((tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeNeighborReport: + offset = sizeof(tDot11fIENeighborReport); + status |= + dot11f_get_packed_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeOBSSScanParameters: + offset = sizeof(tDot11fIEOBSSScanParameters); + byteCount = 14; + pIePresent = ((tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeOperatingMode: + offset = sizeof(tDot11fIEOperatingMode); + byteCount = 1; + pIePresent = ((tDot11fIEOperatingMode *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PAssocReq: + offset = sizeof(tDot11fIEP2PAssocReq); + status |= + dot11f_get_packed_iep2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PAssocRes: + offset = sizeof(tDot11fIEP2PAssocRes); + status |= + dot11f_get_packed_iep2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeacon: + offset = sizeof(tDot11fIEP2PBeacon); + status |= + dot11f_get_packed_iep2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeaconProbeRes: + offset = sizeof(tDot11fIEP2PBeaconProbeRes); + status |= + dot11f_get_packed_iep2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDeAuth: + offset = sizeof(tDot11fIEP2PDeAuth); + status |= + dot11f_get_packed_iep2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDisAssoc: + offset = sizeof(tDot11fIEP2PDisAssoc); + status |= + dot11f_get_packed_iep2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PIEOpaque: + offset = sizeof(tDot11fIEP2PIEOpaque); + byteCount = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PProbeReq: + offset = sizeof(tDot11fIEP2PProbeReq); + status |= + dot11f_get_packed_iep2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PProbeRes: + offset = sizeof(tDot11fIEP2PProbeRes); + status |= + dot11f_get_packed_iep2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIePTIControl: + offset = sizeof(tDot11fIEPTIControl); + byteCount = 3; + pIePresent = ((tDot11fIEPTIControl *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePUBufferStatus: + offset = sizeof(tDot11fIEPUBufferStatus); + byteCount = 1; + pIePresent = ((tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerCaps: + offset = sizeof(tDot11fIEPowerCaps); + byteCount = 2; + pIePresent = ((tDot11fIEPowerCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerConstraints: + offset = sizeof(tDot11fIEPowerConstraints); + byteCount = 1; + pIePresent = ((tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQBSSLoad: + offset = sizeof(tDot11fIEQBSSLoad); + byteCount = 5; + pIePresent = ((tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQComVendorIE: + offset = sizeof(tDot11fIEQComVendorIE); + byteCount = 2; + pIePresent = ((tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsAp: + offset = sizeof(tDot11fIEQOSCapsAp); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsStation: + offset = sizeof(tDot11fIEQOSCapsStation); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQosMapSet: + offset = sizeof(tDot11fIEQosMapSet); + byteCount = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + num_dscp_exceptions; + pIePresent = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQuiet: + offset = sizeof(tDot11fIEQuiet); + byteCount = 6; + pIePresent = ((tDot11fIEQuiet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRCPIIE: + offset = sizeof(tDot11fIERCPIIE); + byteCount = 1; + pIePresent = ((tDot11fIERCPIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDataDesc: + offset = sizeof(tDot11fIERICDataDesc); + pnNeeded -= 2 ; /* Subtract the length and Oui as this is our container IE to group Ies and it doesnt have its own length and OUI. */ + status |= + dot11f_get_packed_ieric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSN: + offset = sizeof(tDot11fIERSN); + status |= + dot11f_get_packed_iersn( + pCtx, (tDot11fIERSN *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSNIIE: + offset = sizeof(tDot11fIERSNIIE); + byteCount = 1; + pIePresent = ((tDot11fIERSNIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRSNOpaque: + offset = sizeof(tDot11fIERSNOpaque); + byteCount = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppChannels: + offset = sizeof(tDot11fIESuppChannels); + byteCount = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + num_bands * 2; + pIePresent = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppOperatingClasses: + offset = sizeof(tDot11fIESuppOperatingClasses); + byteCount = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + num_classes; + pIePresent = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppRates: + offset = sizeof(tDot11fIESuppRates); + byteCount = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTIM: + offset = sizeof(tDot11fIETIM); + byteCount = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + num_vbmp + 3; + pIePresent = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCReport: + offset = sizeof(tDot11fIETPCReport); + byteCount = 2; + pIePresent = ((tDot11fIETPCReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCRequest: + offset = sizeof(tDot11fIETPCRequest); + byteCount = 0; + pIePresent = ((tDot11fIETPCRequest *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeAdvertisement: + offset = sizeof(tDot11fIETimeAdvertisement); + byteCount = 16; + pIePresent = ((tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeoutInterval: + offset = sizeof(tDot11fIETimeoutInterval); + byteCount = 5; + pIePresent = ((tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTExtBssLoad: + offset = sizeof(tDot11fIEVHTExtBssLoad); + byteCount = 5; + pIePresent = ((tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor1IE: + offset = sizeof(tDot11fIEVendor1IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor1IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor3IE: + offset = sizeof(tDot11fIEVendor3IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor3IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWAPI: + offset = sizeof(tDot11fIEWAPI); + status |= + dot11f_get_packed_iewapi( + pCtx, (tDot11fIEWAPI *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWAPIOpaque: + offset = sizeof(tDot11fIEWAPIOpaque); + byteCount = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFATPC: + offset = sizeof(tDot11fIEWFATPC); + byteCount = 2; + pIePresent = ((tDot11fIEWFATPC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFDIEOpaque: + offset = sizeof(tDot11fIEWFDIEOpaque); + byteCount = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMCaps: + offset = sizeof(tDot11fIEWMMCaps); + byteCount = 2; + pIePresent = ((tDot11fIEWMMCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoAp: + offset = sizeof(tDot11fIEWMMInfoAp); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoStation: + offset = sizeof(tDot11fIEWMMInfoStation); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMParams: + offset = sizeof(tDot11fIEWMMParams); + byteCount = 19; + pIePresent = ((tDot11fIEWMMParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWPA: + offset = sizeof(tDot11fIEWPA); + status |= + dot11f_get_packed_iewpa( + pCtx, (tDot11fIEWPA *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWPAOpaque: + offset = sizeof(tDot11fIEWPAOpaque); + byteCount = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWSC: + offset = sizeof(tDot11fIEWSC); + status |= + dot11f_get_packed_iewsc( + pCtx, (tDot11fIEWSC *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocReq: + offset = sizeof(tDot11fIEWscAssocReq); + status |= + dot11f_get_packed_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocRes: + offset = sizeof(tDot11fIEWscAssocRes); + status |= + dot11f_get_packed_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeacon: + offset = sizeof(tDot11fIEWscBeacon); + status |= + dot11f_get_packed_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeaconProbeRes: + offset = sizeof(tDot11fIEWscBeaconProbeRes); + status |= + dot11f_get_packed_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscIEOpaque: + offset = sizeof(tDot11fIEWscIEOpaque); + byteCount = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWscProbeReq: + offset = sizeof(tDot11fIEWscProbeReq); + status |= + dot11f_get_packed_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscProbeRes: + offset = sizeof(tDot11fIEWscProbeRes); + status |= + dot11f_get_packed_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscReassocRes: + offset = sizeof(tDot11fIEWscReassocRes); + status |= + dot11f_get_packed_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeext_chan_switch_ann: + offset = sizeof(tDot11fIEext_chan_switch_ann); + byteCount = 4; + pIePresent = ((tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeht2040_bss_coexistence: + offset = sizeof(tDot11fIEht2040_bss_coexistence); + byteCount = 1; + pIePresent = ((tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeht2040_bss_intolerant_report: + offset = sizeof(tDot11fIEht2040_bss_intolerant_report); + byteCount = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + num_channel_list + 1; + pIePresent = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIesec_chan_offset_ele: + offset = sizeof(tDot11fIEsec_chan_offset_ele); + byteCount = 1; + pIePresent = ((tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIevendor2_ie: + offset = sizeof(tDot11fIEvendor2_ie); + status |= + dot11f_get_packed_ie_vendor2_ie( + pCtx, (tDot11fIEvendor2_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pIe->sig); + return DOT11F_INTERNAL_ERROR; + } /*End of switch Case*/ + + if (byteCount && pIePresent) + *pnNeeded += byteCount; + } /*End of for loop*/ + } + ++pIe; + } + return status; + +} + +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t byteCount = 0; + uint8_t pTlvPresent = 0; + + status = DOT11F_PARSE_SUCCESS; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound) { + *pnNeeded += (pTlv->sType + pTlv->sLen); + if (pTlv->pec) + *pnNeeded += 3U; + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + byteCount = 6; + pTlvPresent = ((tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestToEnroll: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion2: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion2 *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAPSetupLocked: + byteCount = 1; + pTlvPresent = ((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAssociationState: + byteCount = 2; + pTlvPresent = ((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigurationError: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDeviceName: + byteCount = ((tDot11fTLVDeviceName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVDeviceName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDevicePasswordID: + byteCount = 2; + pTlvPresent = ((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvExtendedListenTiming: + byteCount = 4; + pTlvPresent = ((tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvListenChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVListenChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvManufacturer: + byteCount = ((tDot11fTLVManufacturer *)(pFrm + pTlv->offset))->num_name; + pTlvPresent = ((tDot11fTLVManufacturer *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvMinorReasonCode: + byteCount = 1; + pTlvPresent = ((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelName: + byteCount = ((tDot11fTLVModelName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelNumber: + byteCount = ((tDot11fTLVModelNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvNoticeOfAbsence: + byteCount = ((tDot11fTLVNoticeOfAbsence *)(pFrm + pTlv->offset))->num_NoADesc+2; + pTlvPresent = ((tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvOperatingChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PCapability: + byteCount = 2; + pTlvPresent = ((tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceId: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceInfo: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_P2PDeviceInfo); + byteCount = 16; + pTlvPresent = ((tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PGroupInfo: + byteCount = ((tDot11fTLVP2PGroupInfo *)(pFrm + pTlv->offset))->num_P2PClientInfoDesc; + pTlvPresent = ((tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PStatus: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvPrimaryDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRFBands: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvResponseType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrar: + byteCount = 1; + pTlvPresent = ((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrarConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSerialNumber: + byteCount = ((tDot11fTLVSerialNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_E: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_E *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_R: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_R *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVendorExtension: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_VendorExtension); + byteCount = 3; + pTlvPresent = ((tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvWPSState: + byteCount = 1; + pTlvPresent = ((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PInterface: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PManageability: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present; + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the TLV signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + if (pTlvPresent) { + *pnNeeded += byteCount; + } + } + ++pTlv; + } + return status; +} +void dot11f_pack_ff_aid(tpAniSirGlobal pCtx, + tDot11fFfAID *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->associd, 0); + (void)pCtx; +} /* End dot11f_pack_ff_aid. */ + +void dot11f_pack_ff_action(tpAniSirGlobal pCtx, + tDot11fFfAction *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->action; + (void)pCtx; +} /* End dot11f_pack_ff_action. */ + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal pCtx, + tDot11fFfAuthAlgo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->algo, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_algo. */ + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal pCtx, + tDot11fFfAuthSeqNo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->no, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_seq_no. */ + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal pCtx, + tDot11fFfBeaconInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_beacon_interval. */ + +void dot11f_pack_ff_capabilities(tpAniSirGlobal pCtx, + tDot11fFfCapabilities *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp66__; + tmp66__ = 0U; + tmp66__ |= (pSrc->ess << 0); + tmp66__ |= (pSrc->ibss << 1); + tmp66__ |= (pSrc->cfPollable << 2); + tmp66__ |= (pSrc->cfPollReq << 3); + tmp66__ |= (pSrc->privacy << 4); + tmp66__ |= (pSrc->shortPreamble << 5); + tmp66__ |= (pSrc->pbcc << 6); + tmp66__ |= (pSrc->channelAgility << 7); + tmp66__ |= (pSrc->spectrumMgt << 8); + tmp66__ |= (pSrc->qos << 9); + tmp66__ |= (pSrc->shortSlotTime << 10); + tmp66__ |= (pSrc->apsd << 11); + tmp66__ |= (pSrc->rrm << 12); + tmp66__ |= (pSrc->dsssOfdm << 13); + tmp66__ |= (pSrc->delayedBA << 14); + tmp66__ |= (pSrc->immediateBA << 15); + frameshtons(pCtx, pBuf, tmp66__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_capabilities. */ + +void dot11f_pack_ff_category(tpAniSirGlobal pCtx, + tDot11fFfCategory *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->category; + (void)pCtx; +} /* End dot11f_pack_ff_category. */ + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal pCtx, + tDot11fFfCurrentAPAddress *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + (void)pCtx; +} /* End dot11f_pack_ff_current_ap_address. */ + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal pCtx, + tDot11fFfDialogToken *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->token; + (void)pCtx; +} /* End dot11f_pack_ff_dialog_token. */ + +void dot11f_pack_ff_link_margin(tpAniSirGlobal pCtx, + tDot11fFfLinkMargin *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->linkMargin; + (void)pCtx; +} /* End dot11f_pack_ff_link_margin. */ + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal pCtx, + tDot11fFfListenInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_listen_interval. */ + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal pCtx, + tDot11fFfMaxTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->maxTxPower; + (void)pCtx; +} /* End dot11f_pack_ff_max_tx_power. */ + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + tDot11fFfNumOfRepetitions *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->repetitions, 0); + (void)pCtx; +} /* End dot11f_pack_ff_num_of_repetitions. */ + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal pCtx, + tDot11fFfOperatingMode *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp67__; + tmp67__ = 0U; + tmp67__ |= (pSrc->chanWidth << 0); + tmp67__ |= (pSrc->reserved << 2); + tmp67__ |= (pSrc->rxNSS << 4); + tmp67__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp67__; + (void)pCtx; +} /* End dot11f_pack_ff_operating_mode. */ + +void dot11f_pack_ff_rcpi(tpAniSirGlobal pCtx, + tDot11fFfRCPI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rcpi; + (void)pCtx; +} /* End dot11f_pack_ff_rcpi. */ + +void dot11f_pack_ff_rsni(tpAniSirGlobal pCtx, + tDot11fFfRSNI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rsni; + (void)pCtx; +} /* End dot11f_pack_ff_rsni. */ + +void dot11f_pack_ff_reason(tpAniSirGlobal pCtx, + tDot11fFfReason *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->code, 0); + (void)pCtx; +} /* End dot11f_pack_ff_reason. */ + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfRxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_rx_antenna_id. */ + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + tDot11fFfSMPowerModeSet *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp68__; + tmp68__ = 0U; + tmp68__ |= (pSrc->PowerSave_En << 0); + tmp68__ |= (pSrc->Mode << 1); + tmp68__ |= (pSrc->reserved << 2); + *pBuf = tmp68__; + (void)pCtx; +} /* End dot11f_pack_ff_sm_power_mode_set. */ + +void dot11f_pack_ff_status(tpAniSirGlobal pCtx, + tDot11fFfStatus *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->status, 0); + (void)pCtx; +} /* End dot11f_pack_ff_status. */ + +void dot11f_pack_ff_status_code(tpAniSirGlobal pCtx, + tDot11fFfStatusCode *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->statusCode; + (void)pCtx; +} /* End dot11f_pack_ff_status_code. */ + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + tDot11fFfTPCEleID *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCId; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_id. */ + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + tDot11fFfTPCEleLen *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCLen; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_len. */ + +void dot11f_pack_ff_ts_info(tpAniSirGlobal pCtx, + tDot11fFfTSInfo *pSrc, + uint8_t *pBuf) +{ + uint32_t tmp69__; + tmp69__ = 0U; + tmp69__ |= (pSrc->traffic_type << 0); + tmp69__ |= (pSrc->tsid << 1); + tmp69__ |= (pSrc->direction << 5); + tmp69__ |= (pSrc->access_policy << 7); + tmp69__ |= (pSrc->aggregation << 9); + tmp69__ |= (pSrc->psb << 10); + tmp69__ |= (pSrc->user_priority << 11); + tmp69__ |= (pSrc->tsinfo_ack_pol << 14); + tmp69__ |= (pSrc->schedule << 16); + tmp69__ |= (pSrc->unused << 17); + frameshtonl(pCtx, pBuf, tmp69__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ts_info. */ + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal pCtx, + tDot11fFfTimeStamp *pSrc, + uint8_t *pBuf) +{ + frameshtonq(pCtx, pBuf, pSrc->timestamp, 0); + (void)pCtx; +} /* End dot11f_pack_ff_time_stamp. */ + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal pCtx, + tDot11fFfTransactionId *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->transId, 2); + (void)pCtx; +} /* End dot11f_pack_ff_transaction_id. */ + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfTxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_tx_antenna_id. */ + +void dot11f_pack_ff_tx_power(tpAniSirGlobal pCtx, + tDot11fFfTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->txPower; + (void)pCtx; +} /* End dot11f_pack_ff_tx_power. */ + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + tDot11fFfVhtMembershipStatusArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->membershipStatusArray, 8); + (void)pCtx; +} /* End dot11f_pack_ff_vht_membership_status_array. */ + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + tDot11fFfVhtUserPositionArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->userPositionArray, 16); + (void)pCtx; +} /* End dot11f_pack_ff_vht_user_position_array. */ + +uint32_t dot11f_pack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + tDot11fTLVAuthorizedMACs *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_authorized_ma_cs. */ + +uint32_t dot11f_pack_tlv_request_to_enroll(tpAniSirGlobal pCtx, + tDot11fTLVRequestToEnroll *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->req; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_to_enroll. */ + +uint32_t dot11f_pack_tlv_version2(tpAniSirGlobal pCtx, + tDot11fTLVVersion2 *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp70__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp70__ = 0U; + tmp70__ |= (pSrc->minor << 0); + tmp70__ |= (pSrc->major << 4); + *pBuf = tmp70__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version2. */ + +uint32_t dot11f_pack_tlv_ap_setup_locked(tpAniSirGlobal pCtx, + tDot11fTLVAPSetupLocked *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4183, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->fLocked; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_ap_setup_locked. */ + +uint32_t dot11f_pack_tlv_association_state(tpAniSirGlobal pCtx, + tDot11fTLVAssociationState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4098, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->state, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_association_state. */ + +uint32_t dot11f_pack_tlv_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4104, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_config_methods. */ + +uint32_t dot11f_pack_tlv_configuration_error(tpAniSirGlobal pCtx, + tDot11fTLVConfigurationError *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4105, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->error, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_configuration_error. */ + +uint32_t dot11f_pack_tlv_device_name(tpAniSirGlobal pCtx, + tDot11fTLVDeviceName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4113, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_name. */ + +uint32_t dot11f_pack_tlv_device_password_id(tpAniSirGlobal pCtx, + tDot11fTLVDevicePasswordID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4114, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->id, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_password_id. */ + +uint32_t dot11f_pack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + tDot11fTLVExtendedListenTiming *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 8; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityPeriod, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityInterval, 0); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_extended_listen_timing. */ + +uint32_t dot11f_pack_tlv_listen_channel(tpAniSirGlobal pCtx, + tDot11fTLVListenChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 6; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_listen_channel. */ + +uint32_t dot11f_pack_tlv_manufacturer(tpAniSirGlobal pCtx, + tDot11fTLVManufacturer *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_name + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4129, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->name), pSrc->num_name); + *pnConsumed += pSrc->num_name; + pBuf += pSrc->num_name; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_manufacturer. */ + +uint32_t dot11f_pack_tlv_minor_reason_code(tpAniSirGlobal pCtx, + tDot11fTLVMinorReasonCode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->minorReasonCode; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_minor_reason_code. */ + +uint32_t dot11f_pack_tlv_model_name(tpAniSirGlobal pCtx, + tDot11fTLVModelName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4131, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_name. */ + +uint32_t dot11f_pack_tlv_model_number(tpAniSirGlobal pCtx, + tDot11fTLVModelNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4132, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_number. */ + +uint32_t dot11f_pack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + tDot11fTLVNoticeOfAbsence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_NoADesc + 5) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 12; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->index; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->CTSWindowOppPS; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->NoADesc), pSrc->num_NoADesc); + *pnConsumed += pSrc->num_NoADesc; + pBuf += pSrc->num_NoADesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_notice_of_absence. */ + +uint32_t dot11f_pack_tlv_operating_channel(tpAniSirGlobal pCtx, + tDot11fTLVOperatingChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 17; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_operating_channel. */ + +uint32_t dot11f_pack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + tDot11fTLVP2PCapability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 2; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->deviceCapability; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->groupCapability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_capability. */ + +uint32_t dot11f_pack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceId *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_device_id. */ + +uint32_t dot11f_pack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 19; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 13; + pBuf += 1; nBuf -= 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->configMethod, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->primaryDeviceType, 8); + *pnConsumed += 8; + pBuf += 8; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_P2PDeviceInfo, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return status; +} /* End dot11f_pack_tlv_p2_p_device_info. */ + +uint32_t dot11f_pack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PGroupInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_P2PClientInfoDesc + 3) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 14; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->P2PClientInfoDesc), pSrc->num_P2PClientInfoDesc); + *pnConsumed += pSrc->num_P2PClientInfoDesc; + pBuf += pSrc->num_P2PClientInfoDesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_group_info. */ + +uint32_t dot11f_pack_tlv_p2_p_status(tpAniSirGlobal pCtx, + tDot11fTLVP2PStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->status; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_status. */ + +uint32_t dot11f_pack_tlv_primary_device_type(tpAniSirGlobal pCtx, + tDot11fTLVPrimaryDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4180, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_primary_device_type. */ + +uint32_t dot11f_pack_tlv_rf_bands(tpAniSirGlobal pCtx, + tDot11fTLVRFBands *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4156, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->bands; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_rf_bands. */ + +uint32_t dot11f_pack_tlv_request_device_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4202, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_device_type. */ + +uint32_t dot11f_pack_tlv_request_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4154, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->reqType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_type. */ + +uint32_t dot11f_pack_tlv_response_type(tpAniSirGlobal pCtx, + tDot11fTLVResponseType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4155, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->resType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_response_type. */ + +uint32_t dot11f_pack_tlv_selected_registrar(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrar *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4161, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->selected; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar. */ + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrarConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4179, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar_config_methods. */ + +uint32_t dot11f_pack_tlv_serial_number(tpAniSirGlobal pCtx, + tDot11fTLVSerialNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4162, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_serial_number. */ + +uint32_t dot11f_pack_tlv_uuid_e(tpAniSirGlobal pCtx, + tDot11fTLVUUID_E *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4167, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_e. */ + +uint32_t dot11f_pack_tlv_uuid_r(tpAniSirGlobal pCtx, + tDot11fTLVUUID_R *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4168, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_r. */ + +uint32_t dot11f_pack_tlv_vendor_extension(tpAniSirGlobal pCtx, + tDot11fTLVVendorExtension *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4169, 1); + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->vendorId, 3); + *pnConsumed += 3; + pBuf += 3; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_VendorExtension, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return status; +} /* End dot11f_pack_tlv_vendor_extension. */ + +uint32_t dot11f_pack_tlv_version(tpAniSirGlobal pCtx, + tDot11fTLVVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp71__; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4170, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + tmp71__ = 0U; + tmp71__ |= (pSrc->minor << 0); + tmp71__ |= (pSrc->major << 4); + *pBuf = tmp71__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version. */ + +uint32_t dot11f_pack_tlv_wps_state(tpAniSirGlobal pCtx, + tDot11fTLVWPSState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4164, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_wps_state. */ + +uint32_t dot11f_pack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + tDot11fTLVP2PInterface *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 16; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_interface. */ + +uint32_t dot11f_pack_tlv_p2_p_manageability(tpAniSirGlobal pCtx, + tDot11fTLVP2PManageability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 10; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->manageability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_manageability. */ + +uint32_t dot11f_pack_ie_condensed_country_str(tpAniSirGlobal pCtx, + tDot11fIECondensedCountryStr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryStr, 2); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_condensed_country_str. */ + +uint32_t dot11f_pack_ie_gtk(tpAniSirGlobal pCtx, + tDot11fIEGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp72__; + nNeeded += (pSrc->num_key + 11); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp72__ = 0U; + tmp72__ |= (pSrc->keyId << 0); + tmp72__ |= (pSrc->reserved << 2); + frameshtons(pCtx, pBuf, tmp72__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSC, 8); + *pnConsumed += 8; + pBuf += 8; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->key), pSrc->num_key); + *pnConsumed += pSrc->num_key; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_gtk. */ + +uint32_t dot11f_pack_ie_igtk(tpAniSirGlobal pCtx, + tDot11fIEIGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 33; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->keyID, 2); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->IPN, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->key, 24); + *pnConsumed += 24; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_igtk. */ + +uint32_t dot11f_pack_ie_r0_kh_id(tpAniSirGlobal pCtx, + tDot11fIER0KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_PMK_R0_ID; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->PMK_R0_ID), pSrc->num_PMK_R0_ID); + *pnConsumed += pSrc->num_PMK_R0_ID; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r0_kh_id. */ + +uint32_t dot11f_pack_ie_r1_kh_id(tpAniSirGlobal pCtx, + tDot11fIER1KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->PMK_R1_ID, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r1_kh_id. */ + +uint32_t dot11f_pack_ie_tsf_info(tpAniSirGlobal pCtx, + tDot11fIETSFInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->TsfOffset, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->BeaconIntvl, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tsf_info. */ + +uint32_t dot11f_pack_ie_ap_channel_report(tpAniSirGlobal pCtx, + tDot11fIEAPChannelReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channelList + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 51; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channelList), pSrc->num_channelList); + *pnConsumed += pSrc->num_channelList; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ap_channel_report. */ + +uint32_t dot11f_pack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + tDot11fIEBcnReportingDetail *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reportingDetail; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bcn_reporting_detail. */ + +uint32_t dot11f_pack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + tDot11fIEBeaconReportFrmBody *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_reportedFields; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->reportedFields), pSrc->num_reportedFields); + *pnConsumed += pSrc->num_reportedFields; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_report_frm_body. */ + +uint32_t dot11f_pack_ie_beacon_reporting(tpAniSirGlobal pCtx, + tDot11fIEBeaconReporting *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reportingCondition; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->threshold; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_reporting. */ + +uint32_t dot11f_pack_ie_measurement_pilot(tpAniSirGlobal pCtx, + tDot11fIEMeasurementPilot *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 66; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurementPilot; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_measurement_pilot. */ + +uint32_t dot11f_pack_ie_multi_bssid(tpAniSirGlobal pCtx, + tDot11fIEMultiBssid *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 71; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->maxBSSIDIndicator; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_multi_bssid. */ + +uint32_t dot11f_pack_ie_ric_data(tpAniSirGlobal pCtx, + tDot11fIERICData *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 57; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->Identifier; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->resourceDescCount; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->statusCode, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_data. */ + +uint32_t dot11f_pack_ie_ric_descriptor(tpAniSirGlobal pCtx, + tDot11fIERICDescriptor *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_variableData + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 75; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->resourceType; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->variableData), pSrc->num_variableData); + *pnConsumed += pSrc->num_variableData; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_descriptor. */ + +uint32_t dot11f_pack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + tDot11fIERRMEnabledCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp73__; + uint8_t tmp74__; + uint8_t tmp75__; + uint8_t tmp76__; + uint8_t tmp77__; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 70; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp73__ = 0U; + tmp73__ |= (pSrc->LinkMeasurement << 0); + tmp73__ |= (pSrc->NeighborRpt << 1); + tmp73__ |= (pSrc->parallel << 2); + tmp73__ |= (pSrc->repeated << 3); + tmp73__ |= (pSrc->BeaconPassive << 4); + tmp73__ |= (pSrc->BeaconActive << 5); + tmp73__ |= (pSrc->BeaconTable << 6); + tmp73__ |= (pSrc->BeaconRepCond << 7); + *pBuf = tmp73__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp74__ = 0U; + tmp74__ |= (pSrc->FrameMeasurement << 0); + tmp74__ |= (pSrc->ChannelLoad << 1); + tmp74__ |= (pSrc->NoiseHistogram << 2); + tmp74__ |= (pSrc->statistics << 3); + tmp74__ |= (pSrc->LCIMeasurement << 4); + tmp74__ |= (pSrc->LCIAzimuth << 5); + tmp74__ |= (pSrc->TCMCapability << 6); + tmp74__ |= (pSrc->triggeredTCM << 7); + *pBuf = tmp74__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp75__ = 0U; + tmp75__ |= (pSrc->APChanReport << 0); + tmp75__ |= (pSrc->RRMMIBEnabled << 1); + tmp75__ |= (pSrc->operatingChanMax << 2); + tmp75__ |= (pSrc->nonOperatinChanMax << 5); + *pBuf = tmp75__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp76__ = 0U; + tmp76__ |= (pSrc->MeasurementPilot << 0); + tmp76__ |= (pSrc->MeasurementPilotEnabled << 3); + tmp76__ |= (pSrc->NeighborTSFOffset << 4); + tmp76__ |= (pSrc->RCPIMeasurement << 5); + tmp76__ |= (pSrc->RSNIMeasurement << 6); + tmp76__ |= (pSrc->BssAvgAccessDelay << 7); + *pBuf = tmp76__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp77__ = 0U; + tmp77__ |= (pSrc->BSSAvailAdmission << 0); + tmp77__ |= (pSrc->AntennaInformation << 1); + tmp77__ |= (pSrc->fine_time_meas_rpt << 2); + tmp77__ |= (pSrc->lci_capability << 3); + tmp77__ |= (pSrc->reserved << 4); + *pBuf = tmp77__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rrm_enabled_cap. */ + +uint32_t dot11f_pack_ie_requested_info(tpAniSirGlobal pCtx, + tDot11fIERequestedInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_requested_eids; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 10; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->requested_eids), pSrc->num_requested_eids); + *pnConsumed += pSrc->num_requested_eids; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_requested_info. */ + +uint32_t dot11f_pack_ie_ssid(tpAniSirGlobal pCtx, + tDot11fIESSID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_ssid; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 0; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->ssid), pSrc->num_ssid); + *pnConsumed += pSrc->num_ssid; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ssid. */ + +uint32_t dot11f_pack_ie_schedule(tpAniSirGlobal pCtx, + tDot11fIESchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp78__; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 15; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp78__ = 0U; + tmp78__ |= (pSrc->aggregation << 0); + tmp78__ |= (pSrc->tsid << 1); + tmp78__ |= (pSrc->direction << 5); + tmp78__ |= (pSrc->reserved << 7); + frameshtons(pCtx, pBuf, tmp78__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_schedule. */ + +uint32_t dot11f_pack_ie_tclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ietclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 14; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 16); + *pnConsumed += 16; + pBuf += 16; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_tclas. */ + +uint32_t dot11f_pack_ie_tclassproc(tpAniSirGlobal pCtx, + tDot11fIETCLASSPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 44; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tclassproc. */ + +uint32_t dot11f_pack_ie_ts_delay(tpAniSirGlobal pCtx, + tDot11fIETSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 43; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ts_delay. */ + +uint32_t dot11f_pack_ie_tspec(tpAniSirGlobal pCtx, + tDot11fIETSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp79__; + uint8_t tmp80__; + uint16_t tmp81__; + nNeeded += 55; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 13; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp79__ = 0U; + tmp79__ |= (pSrc->traffic_type << 0); + tmp79__ |= (pSrc->tsid << 1); + tmp79__ |= (pSrc->direction << 5); + tmp79__ |= (pSrc->access_policy << 7); + tmp79__ |= (pSrc->aggregation << 9); + tmp79__ |= (pSrc->psb << 10); + tmp79__ |= (pSrc->user_priority << 11); + tmp79__ |= (pSrc->tsinfo_ack_pol << 14); + frameshtons(pCtx, pBuf, tmp79__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp80__ = 0U; + tmp80__ |= (pSrc->schedule << 0); + tmp80__ |= (pSrc->unused << 1); + *pBuf = tmp80__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp81__ = 0U; + tmp81__ |= (pSrc->size << 0); + tmp81__ |= (pSrc->fixed << 15); + frameshtons(pCtx, pBuf, tmp81__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tspec. */ + +uint32_t dot11f_pack_ie_vht_caps(tpAniSirGlobal pCtx, + tDot11fIEVHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t tmp82__; + uint16_t tmp83__; + uint16_t tmp84__; + nNeeded += 12; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 191; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp82__ = 0U; + tmp82__ |= (pSrc->maxMPDULen << 0); + tmp82__ |= (pSrc->supportedChannelWidthSet << 2); + tmp82__ |= (pSrc->ldpcCodingCap << 4); + tmp82__ |= (pSrc->shortGI80MHz << 5); + tmp82__ |= (pSrc->shortGI160and80plus80MHz << 6); + tmp82__ |= (pSrc->txSTBC << 7); + tmp82__ |= (pSrc->rxSTBC << 8); + tmp82__ |= (pSrc->suBeamFormerCap << 11); + tmp82__ |= (pSrc->suBeamformeeCap << 12); + tmp82__ |= (pSrc->csnofBeamformerAntSup << 13); + tmp82__ |= (pSrc->numSoundingDim << 16); + tmp82__ |= (pSrc->muBeamformerCap << 19); + tmp82__ |= (pSrc->muBeamformeeCap << 20); + tmp82__ |= (pSrc->vhtTXOPPS << 21); + tmp82__ |= (pSrc->htcVHTCap << 22); + tmp82__ |= (pSrc->maxAMPDULenExp << 23); + tmp82__ |= (pSrc->vhtLinkAdaptCap << 26); + tmp82__ |= (pSrc->rxAntPattern << 28); + tmp82__ |= (pSrc->txAntPattern << 29); + tmp82__ |= (pSrc->reserved1 << 30); + frameshtonl(pCtx, pBuf, tmp82__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + frameshtons(pCtx, pBuf, pSrc->rxMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp83__ = 0U; + tmp83__ |= (pSrc->rxHighSupDataRate << 0); + tmp83__ |= (pSrc->reserved2 << 13); + frameshtons(pCtx, pBuf, tmp83__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->txMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp84__ = 0U; + tmp84__ |= (pSrc->txSupDataRate << 0); + tmp84__ |= (pSrc->reserved3 << 13); + frameshtons(pCtx, pBuf, tmp84__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_caps. */ + +uint32_t dot11f_pack_ie_vht_operation(tpAniSirGlobal pCtx, + tDot11fIEVHTOperation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 192; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->chanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chanCenterFreqSeg1; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chanCenterFreqSeg2; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->basicMCSSet, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_operation. */ + +uint32_t dot11f_pack_ie_wmm_schedule(tpAniSirGlobal pCtx, + tDot11fIEWMMSchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp85__; + nNeeded += 15; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp85__ = 0U; + tmp85__ |= (pSrc->aggregation << 0); + tmp85__ |= (pSrc->tsid << 1); + tmp85__ |= (pSrc->direction << 5); + tmp85__ |= (pSrc->reserved << 7); + frameshtons(pCtx, pBuf, tmp85__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_schedule. */ + +uint32_t dot11f_pack_ie_wmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewmmtclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 10); + *pnConsumed += 10; + pBuf += 10; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wmmtclas. */ + +uint32_t dot11f_pack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLASPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtclasproc. */ + +uint32_t dot11f_pack_ie_wmmts_delay(tpAniSirGlobal pCtx, + tDot11fIEWMMTSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmts_delay. */ + +uint32_t dot11f_pack_ie_wmmtspec(tpAniSirGlobal pCtx, + tDot11fIEWMMTSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp86__; + uint8_t tmp87__; + uint16_t tmp88__; + nNeeded += 38; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp86__ = 0U; + tmp86__ |= (pSrc->traffic_type << 0); + tmp86__ |= (pSrc->tsid << 1); + tmp86__ |= (pSrc->direction << 5); + tmp86__ |= (pSrc->access_policy << 7); + tmp86__ |= (pSrc->aggregation << 9); + tmp86__ |= (pSrc->psb << 10); + tmp86__ |= (pSrc->user_priority << 11); + tmp86__ |= (pSrc->tsinfo_ack_pol << 14); + frameshtons(pCtx, pBuf, tmp86__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp87__ = 0U; + tmp87__ |= (pSrc->tsinfo_rsvd << 0); + tmp87__ |= (pSrc->burst_size_defn << 7); + *pBuf = tmp87__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp88__ = 0U; + tmp88__ |= (pSrc->size << 0); + tmp88__ |= (pSrc->fixed << 15); + frameshtons(pCtx, pBuf, tmp88__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtspec. */ + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEWiderBWChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 194; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->newChanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq1; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wider_bw_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_aid(tpAniSirGlobal pCtx, + tDot11fIEAID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 197; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->assocId, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_aid. */ + +uint32_t dot11f_pack_ie_cf_params(tpAniSirGlobal pCtx, + tDot11fIECFParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->cfp_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->cfp_period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->cfp_maxduration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->cfp_durremaining, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_cf_params. */ + +uint32_t dot11f_pack_ie_challenge_text(tpAniSirGlobal pCtx, + tDot11fIEChallengeText *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_text; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 16; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_challenge_text. */ + +uint32_t dot11f_pack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 37; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switchMode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newChannel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switchCount; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_channel_switch_wrapper(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 196; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_channel_switch_wrapper. */ + +uint32_t dot11f_pack_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_country(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 7; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->country, 3); + *pnConsumed += 3; + pBuf += 3; + if (pSrc->num_triplets) { + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->triplets), (pSrc->num_triplets * 3)); + *pnConsumed += (pSrc->num_triplets * 3); + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_country. */ + +uint32_t dot11f_pack_ie_ds_params(tpAniSirGlobal pCtx, + tDot11fIEDSParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->curr_channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ds_params. */ + +uint32_t dot11f_pack_ie_edca_param_set(tpAniSirGlobal pCtx, + tDot11fIEEDCAParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp89__; + uint8_t tmp90__; + uint8_t tmp91__; + uint8_t tmp92__; + uint8_t tmp93__; + uint8_t tmp94__; + uint8_t tmp95__; + uint8_t tmp96__; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 12; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->qos; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + pBuf += 1; + tmp89__ = 0U; + tmp89__ |= (pSrc->acbe_aifsn << 0); + tmp89__ |= (pSrc->acbe_acm << 4); + tmp89__ |= (pSrc->acbe_aci << 5); + tmp89__ |= (pSrc->unused1 << 7); + *pBuf = tmp89__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp90__ = 0U; + tmp90__ |= (pSrc->acbe_acwmin << 0); + tmp90__ |= (pSrc->acbe_acwmax << 4); + *pBuf = tmp90__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp91__ = 0U; + tmp91__ |= (pSrc->acbk_aifsn << 0); + tmp91__ |= (pSrc->acbk_acm << 4); + tmp91__ |= (pSrc->acbk_aci << 5); + tmp91__ |= (pSrc->unused2 << 7); + *pBuf = tmp91__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp92__ = 0U; + tmp92__ |= (pSrc->acbk_acwmin << 0); + tmp92__ |= (pSrc->acbk_acwmax << 4); + *pBuf = tmp92__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp93__ = 0U; + tmp93__ |= (pSrc->acvi_aifsn << 0); + tmp93__ |= (pSrc->acvi_acm << 4); + tmp93__ |= (pSrc->acvi_aci << 5); + tmp93__ |= (pSrc->unused3 << 7); + *pBuf = tmp93__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp94__ = 0U; + tmp94__ |= (pSrc->acvi_acwmin << 0); + tmp94__ |= (pSrc->acvi_acwmax << 4); + *pBuf = tmp94__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp95__ = 0U; + tmp95__ |= (pSrc->acvo_aifsn << 0); + tmp95__ |= (pSrc->acvo_acm << 4); + tmp95__ |= (pSrc->acvo_aci << 5); + tmp95__ |= (pSrc->unused4 << 7); + *pBuf = tmp95__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp96__ = 0U; + tmp96__ |= (pSrc->acvo_acwmin << 0); + tmp96__ |= (pSrc->acvo_acwmax << 4); + *pBuf = tmp96__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_edca_param_set. */ + +uint32_t dot11f_pack_ie_erp_info(tpAniSirGlobal pCtx, + tDot11fIEERPInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp97__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 42; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp97__ = 0U; + tmp97__ |= (pSrc->non_erp_present << 0); + tmp97__ |= (pSrc->use_prot << 1); + tmp97__ |= (pSrc->barker_preamble << 2); + tmp97__ |= (pSrc->unused << 3); + *pBuf = tmp97__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_erp_info. */ + +uint32_t dot11f_pack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + tDot11fIEESECckmOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 156; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_cckm_opaque. */ + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + tDot11fIEESERadMgmtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp98__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->mgmt_state; + *pnConsumed += 1; + pBuf += 1; + tmp98__ = 0U; + tmp98__ |= (pSrc->mbssid_mask << 0); + tmp98__ |= (pSrc->reserved << 3); + *pBuf = tmp98__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_rad_mgmt_cap. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmMet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->msmt_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_met. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmRateSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_tsrates + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tsrates), pSrc->num_tsrates); + *pnConsumed += pSrc->num_tsrates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_rate_set. */ + +uint32_t dot11f_pack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + tDot11fIEESETxmitPower *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 150; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->power_limit; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_txmit_power. */ + +uint32_t dot11f_pack_ie_ese_version(tpAniSirGlobal pCtx, + tDot11fIEESEVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x3; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_version. */ + +uint32_t dot11f_pack_ie_ext_cap(tpAniSirGlobal pCtx, + tDot11fIEExtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bytes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 127; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bytes), pSrc->num_bytes); + *pnConsumed += pSrc->num_bytes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_cap. */ + +uint32_t dot11f_pack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + tDot11fIEExtSuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 50; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_supp_rates. */ + +uint32_t dot11f_pack_ie_fh_param_set(tpAniSirGlobal pCtx, + tDot11fIEFHParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->dwell_time, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->hop_set; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_pattern; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_index; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_param_set. */ + +uint32_t dot11f_pack_ie_fh_params(tpAniSirGlobal pCtx, + tDot11fIEFHParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 8; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->radix; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nchannels; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_params. */ + +uint32_t dot11f_pack_ie_fh_patt_table(tpAniSirGlobal pCtx, + tDot11fIEFHPattTable *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_randtable + 4); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 9; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->flag; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nsets; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->modulus; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->randtable), pSrc->num_randtable); + *pnConsumed += pSrc->num_randtable; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_patt_table. */ + +uint32_t dot11f_pack_ie_ft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp99__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieft_info(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 55; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + tmp99__ = 0U; + tmp99__ |= (pSrc->reserved << 0); + tmp99__ |= (pSrc->IECount << 8); + frameshtons(pCtx, pBuf, tmp99__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->MIC, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Anonce, 32); + *pnConsumed += 32; + pBuf += 32; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Snonce, 32); + *pnConsumed += 32; + pBuf += 32; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_FTInfo, + IES_FTInfo); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_ft_info. */ + +uint32_t dot11f_pack_ie_ht_caps(tpAniSirGlobal pCtx, + tDot11fIEHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp100__; + uint8_t tmp101__; + uint16_t tmp102__; + uint32_t tmp103__; + uint8_t tmp104__; + nNeeded += (pSrc->num_rsvd + 26); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 45; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp100__ = 0U; + tmp100__ |= (pSrc->advCodingCap << 0); + tmp100__ |= (pSrc->supportedChannelWidthSet << 1); + tmp100__ |= (pSrc->mimoPowerSave << 2); + tmp100__ |= (pSrc->greenField << 4); + tmp100__ |= (pSrc->shortGI20MHz << 5); + tmp100__ |= (pSrc->shortGI40MHz << 6); + tmp100__ |= (pSrc->txSTBC << 7); + tmp100__ |= (pSrc->rxSTBC << 8); + tmp100__ |= (pSrc->delayedBA << 10); + tmp100__ |= (pSrc->maximalAMSDUsize << 11); + tmp100__ |= (pSrc->dsssCckMode40MHz << 12); + tmp100__ |= (pSrc->psmp << 13); + tmp100__ |= (pSrc->stbcControlFrame << 14); + tmp100__ |= (pSrc->lsigTXOPProtection << 15); + frameshtons(pCtx, pBuf, tmp100__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp101__ = 0U; + tmp101__ |= (pSrc->maxRxAMPDUFactor << 0); + tmp101__ |= (pSrc->mpduDensity << 2); + tmp101__ |= (pSrc->reserved1 << 5); + *pBuf = tmp101__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->supportedMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + tmp102__ = 0U; + tmp102__ |= (pSrc->pco << 0); + tmp102__ |= (pSrc->transitionTime << 1); + tmp102__ |= (pSrc->reserved2 << 3); + tmp102__ |= (pSrc->mcsFeedback << 8); + tmp102__ |= (pSrc->reserved3 << 10); + frameshtons(pCtx, pBuf, tmp102__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp103__ = 0U; + tmp103__ |= (pSrc->txBF << 0); + tmp103__ |= (pSrc->rxStaggeredSounding << 1); + tmp103__ |= (pSrc->txStaggeredSounding << 2); + tmp103__ |= (pSrc->rxZLF << 3); + tmp103__ |= (pSrc->txZLF << 4); + tmp103__ |= (pSrc->implicitTxBF << 5); + tmp103__ |= (pSrc->calibration << 6); + tmp103__ |= (pSrc->explicitCSITxBF << 8); + tmp103__ |= (pSrc->explicitUncompressedSteeringMatrix << 9); + tmp103__ |= (pSrc->explicitBFCSIFeedback << 10); + tmp103__ |= (pSrc->explicitUncompressedSteeringMatrixFeedback << 13); + tmp103__ |= (pSrc->explicitCompressedSteeringMatrixFeedback << 16); + tmp103__ |= (pSrc->csiNumBFAntennae << 19); + tmp103__ |= (pSrc->uncompressedSteeringMatrixBFAntennae << 21); + tmp103__ |= (pSrc->compressedSteeringMatrixBFAntennae << 23); + tmp103__ |= (pSrc->reserved4 << 25); + frameshtonl(pCtx, pBuf, tmp103__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp104__ = 0U; + tmp104__ |= (pSrc->antennaSelection << 0); + tmp104__ |= (pSrc->explicitCSIFeedbackTx << 1); + tmp104__ |= (pSrc->antennaIndicesFeedbackTx << 2); + tmp104__ |= (pSrc->explicitCSIFeedback << 3); + tmp104__ |= (pSrc->antennaIndicesFeedback << 4); + tmp104__ |= (pSrc->rxAS << 5); + tmp104__ |= (pSrc->txSoundingPPDUs << 6); + tmp104__ |= (pSrc->reserved5 << 7); + *pBuf = tmp104__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_caps. */ + +uint32_t dot11f_pack_ie_ht_info(tpAniSirGlobal pCtx, + tDot11fIEHTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp105__; + uint16_t tmp106__; + uint16_t tmp107__; + nNeeded += (pSrc->num_rsvd + 22); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 61; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->primaryChannel; + *pnConsumed += 1; + pBuf += 1; + tmp105__ = 0U; + tmp105__ |= (pSrc->secondaryChannelOffset << 0); + tmp105__ |= (pSrc->recommendedTxWidthSet << 2); + tmp105__ |= (pSrc->rifsMode << 3); + tmp105__ |= (pSrc->controlledAccessOnly << 4); + tmp105__ |= (pSrc->serviceIntervalGranularity << 5); + *pBuf = tmp105__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp106__ = 0U; + tmp106__ |= (pSrc->opMode << 0); + tmp106__ |= (pSrc->nonGFDevicesPresent << 2); + tmp106__ |= (pSrc->transmitBurstLimit << 3); + tmp106__ |= (pSrc->obssNonHTStaPresent << 4); + tmp106__ |= (pSrc->reserved << 5); + frameshtons(pCtx, pBuf, tmp106__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp107__ = 0U; + tmp107__ |= (pSrc->basicSTBCMCS << 0); + tmp107__ |= (pSrc->dualCTSProtection << 7); + tmp107__ |= (pSrc->secondaryBeacon << 8); + tmp107__ |= (pSrc->lsigTXOPProtectionFullSupport << 9); + tmp107__ |= (pSrc->pcoActive << 10); + tmp107__ |= (pSrc->pcoPhase << 11); + tmp107__ |= (pSrc->reserved2 << 12); + frameshtons(pCtx, pBuf, tmp107__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->basicMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_info. */ + +uint32_t dot11f_pack_ie_ibss_params(tpAniSirGlobal pCtx, + tDot11fIEIBSSParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 6; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->atim, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ibss_params. */ + +uint32_t dot11f_pack_ie_link_identifier(tpAniSirGlobal pCtx, + tDot11fIELinkIdentifier *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 101; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->InitStaAddr, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RespStaAddr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_link_identifier. */ + +uint32_t dot11f_pack_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp108__; + uint8_t tmp109__; + uint8_t tmp110__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 39; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->token; + *pnConsumed += 1; + pBuf += 1; + tmp108__ = 0U; + tmp108__ |= (pSrc->late << 0); + tmp108__ |= (pSrc->incapable << 1); + tmp108__ |= (pSrc->refused << 2); + tmp108__ |= (pSrc->unused << 3); + *pBuf = tmp108__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + if (pSrc->type) { + switch (pSrc->type) { + case 0: + *pBuf = pSrc->report.Basic.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Basic.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Basic.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp109__ = 0U; + tmp109__ |= (pSrc->report.Basic.bss << 0); + tmp109__ |= (pSrc->report.Basic.ofdm_preamble << 1); + tmp109__ |= (pSrc->report.Basic.unid_signal << 2); + tmp109__ |= (pSrc->report.Basic.rader << 3); + tmp109__ |= (pSrc->report.Basic.unmeasured << 4); + tmp109__ |= (pSrc->report.Basic.unused << 5); + *pBuf = tmp109__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + case 1: + *pBuf = pSrc->report.CCA.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.CCA.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.CCA.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.CCA.cca_busy_fraction; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->report.RPIHistogram.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.RPIHistogram.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.RPIHistogram.rpi0_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi1_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi2_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi3_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi4_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi5_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi6_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi7_density; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 5: + *pBuf = pSrc->report.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Beacon.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp110__ = 0U; + tmp110__ |= (pSrc->report.Beacon.condensed_PHY << 0); + tmp110__ |= (pSrc->report.Beacon.reported_frame_type << 7); + *pBuf = tmp110__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->report.Beacon.RCPI; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.RSNI; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->report.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->report.Beacon.antenna_id; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->report.Beacon.parent_TSF, 0); + *pnConsumed += 4; + pBuf += 4; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_reportBeacon, + IES_reportBeacon); + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_report. */ + +uint32_t dot11f_pack_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp111__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_request(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 38; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurement_token; + *pnConsumed += 1; + pBuf += 1; + tmp111__ = 0U; + tmp111__ |= (pSrc->parallel << 0); + tmp111__ |= (pSrc->enable << 1); + tmp111__ |= (pSrc->request << 2); + tmp111__ |= (pSrc->report << 3); + tmp111__ |= (pSrc->durationMandatory << 4); + tmp111__ |= (pSrc->unused << 5); + *pBuf = tmp111__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->measurement_type; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->measurement_type) { + case 0: + *pBuf = pSrc->measurement_request.Basic.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Basic.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Basic.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->measurement_request.CCA.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.CCA.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.CCA.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->measurement_request.RPIHistogram.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 5: + *pBuf = pSrc->measurement_request.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->measurement_request.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.randomization, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.Beacon.meas_mode; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon); + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_request. */ + +uint32_t dot11f_pack_ie_mobility_domain(tpAniSirGlobal pCtx, + tDot11fIEMobilityDomain *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp112__; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 54; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->MDID, 0); + *pnConsumed += 2; + pBuf += 2; + tmp112__ = 0U; + tmp112__ |= (pSrc->overDSCap << 0); + tmp112__ |= (pSrc->resourceReqCap << 1); + tmp112__ |= (pSrc->reserved << 2); + *pBuf = tmp112__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mobility_domain. */ + +uint32_t dot11f_pack_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp113__; + uint8_t tmp114__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_neighbor_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 52; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + tmp113__ = 0U; + tmp113__ |= (pSrc->APReachability << 0); + tmp113__ |= (pSrc->Security << 2); + tmp113__ |= (pSrc->KeyScope << 3); + tmp113__ |= (pSrc->SpecMgmtCap << 4); + tmp113__ |= (pSrc->QosCap << 5); + tmp113__ |= (pSrc->apsd << 6); + tmp113__ |= (pSrc->rrm << 7); + *pBuf = tmp113__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp114__ = 0U; + tmp114__ |= (pSrc->DelayedBA << 0); + tmp114__ |= (pSrc->ImmBA << 1); + tmp114__ |= (pSrc->MobilityDomain << 2); + tmp114__ |= (pSrc->reserved << 3); + *pBuf = tmp114__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->reserved1, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->PhyType; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_NeighborReport, + IES_NeighborReport); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_neighbor_report. */ + +uint32_t dot11f_pack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + tDot11fIEOBSSScanParameters *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 74; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssChannelWidthTriggerScanInterval, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssWidthChannelTransitionDelayFactor, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActivityThreshold, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_obss_scan_parameters. */ + +uint32_t dot11f_pack_ie_operating_mode(tpAniSirGlobal pCtx, + tDot11fIEOperatingMode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp115__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 199; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp115__ = 0U; + tmp115__ |= (pSrc->chanWidth << 0); + tmp115__ |= (pSrc->reserved << 2); + tmp115__ |= (pSrc->rxNSS << 4); + tmp115__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp115__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_operating_mode. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_req. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_res. */ + +uint32_t dot11f_pack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon. */ + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_de_auth(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDeAuth + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_de_auth. */ + +uint32_t dot11f_pack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_dis_assoc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDisAssoc + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_dis_assoc. */ + +uint32_t dot11f_pack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + tDot11fIEP2PIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_p2_pie_opaque. */ + +uint32_t dot11f_pack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_req. */ + +uint32_t dot11f_pack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_res. */ + +uint32_t dot11f_pack_ie_pti_control(tpAniSirGlobal pCtx, + tDot11fIEPTIControl *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 105; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tid; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->sequence_control, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pti_control. */ + +uint32_t dot11f_pack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + tDot11fIEPUBufferStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp116__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 106; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp116__ = 0U; + tmp116__ |= (pSrc->ac_bk_traffic_aval << 0); + tmp116__ |= (pSrc->ac_be_traffic_aval << 1); + tmp116__ |= (pSrc->ac_vi_traffic_aval << 2); + tmp116__ |= (pSrc->ac_vo_traffic_aval << 3); + tmp116__ |= (pSrc->reserved << 4); + *pBuf = tmp116__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pu_buffer_status. */ + +uint32_t dot11f_pack_ie_power_caps(tpAniSirGlobal pCtx, + tDot11fIEPowerCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 33; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->minTxPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->maxTxPower; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_caps. */ + +uint32_t dot11f_pack_ie_power_constraints(tpAniSirGlobal pCtx, + tDot11fIEPowerConstraints *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 32; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->localPowerConstraints; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_constraints. */ + +uint32_t dot11f_pack_ie_qbss_load(tpAniSirGlobal pCtx, + tDot11fIEQBSSLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 11; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->stacount, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->chautil; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->avail, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qbss_load. */ + +uint32_t dot11f_pack_ie_QComVendorIE(tpAniSirGlobal pCtx, + tDot11fIEQComVendorIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xc6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_QComVendorIE. */ + +uint32_t dot11f_pack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp117__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp117__ = 0U; + tmp117__ |= (pSrc->count << 0); + tmp117__ |= (pSrc->qack << 4); + tmp117__ |= (pSrc->qreq << 5); + tmp117__ |= (pSrc->txopreq << 6); + tmp117__ |= (pSrc->reserved << 7); + *pBuf = tmp117__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_ap. */ + +uint32_t dot11f_pack_ie_qos_caps_station(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp118__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp118__ = 0U; + tmp118__ |= (pSrc->acvo_uapsd << 0); + tmp118__ |= (pSrc->acvi_uapsd << 1); + tmp118__ |= (pSrc->acbk_uapsd << 2); + tmp118__ |= (pSrc->acbe_uapsd << 3); + tmp118__ |= (pSrc->qack << 4); + tmp118__ |= (pSrc->max_sp_length << 5); + tmp118__ |= (pSrc->more_data_ack << 7); + *pBuf = tmp118__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_station. */ + +uint32_t dot11f_pack_ie_qos_map_set(tpAniSirGlobal pCtx, + tDot11fIEQosMapSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_dscp_exceptions; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 110; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->dscp_exceptions), pSrc->num_dscp_exceptions); + *pnConsumed += pSrc->num_dscp_exceptions; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_map_set. */ + +uint32_t dot11f_pack_ie_quiet(tpAniSirGlobal pCtx, + tDot11fIEQuiet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 40; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->duration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->offset, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_quiet. */ + +uint32_t dot11f_pack_ie_rcpiie(tpAniSirGlobal pCtx, + tDot11fIERCPIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 53; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rcpi; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rcpiie. */ + +uint32_t dot11f_pack_ie_ric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieric_data_desc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_RICDataDesc, + IES_RICDataDesc); + break; + } + (void)pCtx; + return status; +} /* End dot11f_pack_ie_ric_data_desc. */ + +uint32_t dot11f_pack_ie_rsn(tpAniSirGlobal pCtx, + tDot11fIERSN *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iersn(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + if (pSrc->pwise_cipher_suite_count) { + frameshtons(pCtx, pBuf, pSrc->pwise_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pwise_cipher_suites), (pSrc->pwise_cipher_suite_count * 4)); + *pnConsumed += (pSrc->pwise_cipher_suite_count * 4); + pBuf += (pSrc->pwise_cipher_suite_count * 4); + if (pSrc->akm_suite_count) { + frameshtons(pCtx, pBuf, pSrc->akm_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suites), (pSrc->akm_suite_count * 4)); + *pnConsumed += (pSrc->akm_suite_count * 4); + pBuf += (pSrc->akm_suite_count * 4); + if (pSrc->RSN_Cap) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSN_Cap, 2); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + if (pSrc->pmkid_count) { + frameshtons(pCtx, pBuf, pSrc->pmkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pmkid), (pSrc->pmkid_count * 16)); + *pnConsumed += (pSrc->pmkid_count * 16); + pBuf += (pSrc->pmkid_count * 16); + if (pSrc->gp_mgmt_cipher_suite) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_mgmt_cipher_suite, 4); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_rsn. */ + +uint32_t dot11f_pack_ie_rsniie(tpAniSirGlobal pCtx, + tDot11fIERSNIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 65; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rsni; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsniie. */ + +uint32_t dot11f_pack_ie_rsn_opaque(tpAniSirGlobal pCtx, + tDot11fIERSNOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsn_opaque. */ + +uint32_t dot11f_pack_ie_supp_channels(tpAniSirGlobal pCtx, + tDot11fIESuppChannels *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bands * 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 36; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bands), (pSrc->num_bands * 2)); + *pnConsumed += (pSrc->num_bands * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_channels. */ + +uint32_t dot11f_pack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + tDot11fIESuppOperatingClasses *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_classes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 59; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->classes), pSrc->num_classes); + *pnConsumed += pSrc->num_classes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_operating_classes. */ + +uint32_t dot11f_pack_ie_supp_rates(tpAniSirGlobal pCtx, + tDot11fIESuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_rates. */ + +uint32_t dot11f_pack_ie_tim(tpAniSirGlobal pCtx, + tDot11fIETIM *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vbmp + 3); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 5; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->dtim_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->dtim_period; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->bmpctl; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vbmp), pSrc->num_vbmp); + *pnConsumed += pSrc->num_vbmp; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tim. */ + +uint32_t dot11f_pack_ie_tpc_report(tpAniSirGlobal pCtx, + tDot11fIETPCReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 35; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tx_power; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->link_margin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_report. */ + +uint32_t dot11f_pack_ie_tpc_request(tpAniSirGlobal pCtx, + tDot11fIETPCRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 34; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_request. */ + +uint32_t dot11f_pack_ie_time_advertisement(tpAniSirGlobal pCtx, + tDot11fIETimeAdvertisement *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 16; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 69; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timing_capabilities; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_value, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_error, 5); + *pnConsumed += 5; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_time_advertisement. */ + +uint32_t dot11f_pack_ie_timeout_interval(tpAniSirGlobal pCtx, + tDot11fIETimeoutInterval *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 56; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timeoutType; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->timeoutValue, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_timeout_interval. */ + +uint32_t dot11f_pack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + tDot11fIEVHTExtBssLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 193; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->muMIMOCapStaCount; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ssUnderUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->FortyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->EightyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->OneSixtyMHzUtil; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_ext_bss_load. */ + +uint32_t dot11f_pack_ie_vendor1_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor1IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x10; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x18; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor1_ie. */ + +uint32_t dot11f_pack_ie_vendor3_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor3IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x16; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x32; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor3_ie. */ + +uint32_t dot11f_pack_ie_wapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp119__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewapi(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->akm_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suites), (pSrc->akm_suite_count * 4)); + *pnConsumed += (pSrc->akm_suite_count * 4); + pBuf += (pSrc->akm_suite_count * 4); + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_cipher_suites), (pSrc->unicast_cipher_suite_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_suite_count * 4); + pBuf += (pSrc->unicast_cipher_suite_count * 4); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + tmp119__ = 0U; + tmp119__ |= (pSrc->preauth << 0); + tmp119__ |= (pSrc->reserved << 1); + frameshtons(pCtx, pBuf, tmp119__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + if (pSrc->bkid_count) { + frameshtons(pCtx, pBuf, pSrc->bkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bkid), (pSrc->bkid_count * 16)); + *pnConsumed += (pSrc->bkid_count * 16); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wapi. */ + +uint32_t dot11f_pack_ie_wapi_opaque(tpAniSirGlobal pCtx, + tDot11fIEWAPIOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wapi_opaque. */ + +uint32_t dot11f_pack_ie_wfatpc(tpAniSirGlobal pCtx, + tDot11fIEWFATPC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->txPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->linkMargin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfatpc. */ + +uint32_t dot11f_pack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWFDIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfdie_opaque. */ + +uint32_t dot11f_pack_ie_wmm_caps(tpAniSirGlobal pCtx, + tDot11fIEWMMCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp120__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x5; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp120__ = 0U; + tmp120__ |= (pSrc->reserved << 0); + tmp120__ |= (pSrc->qack << 4); + tmp120__ |= (pSrc->queue_request << 5); + tmp120__ |= (pSrc->txop_request << 6); + tmp120__ |= (pSrc->more_ack << 7); + *pBuf = tmp120__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_caps. */ + +uint32_t dot11f_pack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp121__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp121__ = 0U; + tmp121__ |= (pSrc->param_set_count << 0); + tmp121__ |= (pSrc->reserved << 4); + tmp121__ |= (pSrc->uapsd << 7); + *pBuf = tmp121__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_ap. */ + +uint32_t dot11f_pack_ie_wmm_info_station(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp122__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp122__ = 0U; + tmp122__ |= (pSrc->acvo_uapsd << 0); + tmp122__ |= (pSrc->acvi_uapsd << 1); + tmp122__ |= (pSrc->acbk_uapsd << 2); + tmp122__ |= (pSrc->acbe_uapsd << 3); + tmp122__ |= (pSrc->reserved1 << 4); + tmp122__ |= (pSrc->max_sp_length << 5); + tmp122__ |= (pSrc->reserved2 << 7); + *pBuf = tmp122__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_station. */ + +uint32_t dot11f_pack_ie_wmm_params(tpAniSirGlobal pCtx, + tDot11fIEWMMParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp123__; + uint8_t tmp124__; + uint8_t tmp125__; + uint8_t tmp126__; + uint8_t tmp127__; + uint8_t tmp128__; + uint8_t tmp129__; + uint8_t tmp130__; + nNeeded += 19; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->qosInfo; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved2; + *pnConsumed += 1; + pBuf += 1; + tmp123__ = 0U; + tmp123__ |= (pSrc->acbe_aifsn << 0); + tmp123__ |= (pSrc->acbe_acm << 4); + tmp123__ |= (pSrc->acbe_aci << 5); + tmp123__ |= (pSrc->unused1 << 7); + *pBuf = tmp123__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp124__ = 0U; + tmp124__ |= (pSrc->acbe_acwmin << 0); + tmp124__ |= (pSrc->acbe_acwmax << 4); + *pBuf = tmp124__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp125__ = 0U; + tmp125__ |= (pSrc->acbk_aifsn << 0); + tmp125__ |= (pSrc->acbk_acm << 4); + tmp125__ |= (pSrc->acbk_aci << 5); + tmp125__ |= (pSrc->unused2 << 7); + *pBuf = tmp125__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp126__ = 0U; + tmp126__ |= (pSrc->acbk_acwmin << 0); + tmp126__ |= (pSrc->acbk_acwmax << 4); + *pBuf = tmp126__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp127__ = 0U; + tmp127__ |= (pSrc->acvi_aifsn << 0); + tmp127__ |= (pSrc->acvi_acm << 4); + tmp127__ |= (pSrc->acvi_aci << 5); + tmp127__ |= (pSrc->unused3 << 7); + *pBuf = tmp127__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp128__ = 0U; + tmp128__ |= (pSrc->acvi_acwmin << 0); + tmp128__ |= (pSrc->acvi_acwmax << 4); + *pBuf = tmp128__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp129__ = 0U; + tmp129__ |= (pSrc->acvo_aifsn << 0); + tmp129__ |= (pSrc->acvo_acm << 4); + tmp129__ |= (pSrc->acvo_aci << 5); + tmp129__ |= (pSrc->unused4 << 7); + *pBuf = tmp129__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp130__ = 0U; + tmp130__ |= (pSrc->acvo_acwmin << 0); + tmp130__ |= (pSrc->acvo_acwmax << 4); + *pBuf = tmp130__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_params. */ + +uint32_t dot11f_pack_ie_wpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewpa(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + if (pSrc->multicast_cipher_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher, 4); + *pnConsumed += 4; + pBuf += 4; + } else { + break; + } + if (pSrc->unicast_cipher_count) { + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_ciphers), (pSrc->unicast_cipher_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_count * 4); + pBuf += (pSrc->unicast_cipher_count * 4); + if (pSrc->auth_suite_count) { + frameshtons(pCtx, pBuf, pSrc->auth_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->auth_suites), (pSrc->auth_suite_count * 4)); + *pnConsumed += (pSrc->auth_suite_count * 4); + pBuf += (pSrc->auth_suite_count * 4); + if (pSrc->caps) { + frameshtons(pCtx, pBuf, pSrc->caps, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wpa. */ + +uint32_t dot11f_pack_ie_wpa_opaque(tpAniSirGlobal pCtx, + tDot11fIEWPAOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wpa_opaque. */ + +uint32_t dot11f_pack_ie_wsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iewsc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WSC + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc. */ + +uint32_t dot11f_pack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_req. */ + +uint32_t dot11f_pack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_res. */ + +uint32_t dot11f_pack_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon. */ + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWscIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wsc_ie_opaque. */ + +uint32_t dot11f_pack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_req. */ + +uint32_t dot11f_pack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_reassoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscReassocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_reassoc_res. */ + +uint32_t dot11f_pack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEext_chan_switch_ann *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 60; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switch_mode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_reg_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switch_count; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_coexistence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp131__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 72; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp131__ = 0U; + tmp131__ |= (pSrc->info_request << 0); + tmp131__ |= (pSrc->forty_mhz_intolerant << 1); + tmp131__ |= (pSrc->twenty_mhz_bsswidth_req << 2); + tmp131__ |= (pSrc->obss_scan_exemption_req << 3); + tmp131__ |= (pSrc->obss_scan_exemption_grant << 4); + tmp131__ |= (pSrc->unused << 5); + *pBuf = tmp131__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_coexistence. */ + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_intolerant_report *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channel_list + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 73; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->operating_class; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channel_list), pSrc->num_channel_list); + *pnConsumed += pSrc->num_channel_list; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_intolerant_report. */ + +uint32_t dot11f_pack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + tDot11fIEsec_chan_offset_ele *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 62; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->secondaryChannelOffset; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_sec_chan_offset_ele. */ + +uint32_t dot11f_pack_ie_vendor2_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor2_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_vendor2_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x90; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4c; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->sub_type; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_vendor2_ie, + IES_vendor2_ie); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_vendor2_ie. */ + +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSRequest, IES_AddTSRequest); + + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSResponse, IES_AddTSResponse); + + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocRequest, IES_AssocRequest); + + return status; + +} /* End dot11f_unpack_assoc_request. */ + +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocResponse, IES_AssocResponse); + + return status; + +} /* End dot11f_unpack_assoc_response. */ + +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Authentication, IES_Authentication); + + return status; + +} /* End dot11f_unpack_authentication. */ + +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon, IES_Beacon); + + return status; + +} /* End dot11f_unpack_beacon. */ + +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon1, IES_Beacon1); + + return status; + +} /* End dot11f_unpack_beacon1. */ + +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon2, IES_Beacon2); + + return status; + +} /* End dot11f_unpack_beacon2. */ + +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_BeaconIEs, IES_BeaconIEs); + + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ChannelSwitch, IES_ChannelSwitch); + + return status; + +} /* End dot11f_unpack_channel_switch. */ + +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DeAuth, IES_DeAuth); + + return status; + +} /* End dot11f_unpack_de_auth. */ + +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DelTS, IES_DelTS); + + return status; + +} /* End dot11f_unpack_del_ts. */ + +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Disassociation, IES_Disassociation); + + return status; + +} /* End dot11f_unpack_disassociation. */ + +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport); + + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest); + + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementReport, IES_MeasurementReport); + + return status; + +} /* End dot11f_unpack_measurement_report. */ + +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementRequest, IES_MeasurementRequest); + + return status; + +} /* End dot11f_unpack_measurement_request. */ + +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportRequest, IES_NeighborReportRequest); + + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportResponse, IES_NeighborReportResponse); + + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_OperatingMode, IES_OperatingMode); + + return status; + +} /* End dot11f_unpack_operating_mode. */ + +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeRequest, IES_ProbeRequest); + + return status; + +} /* End dot11f_unpack_probe_request. */ + +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeResponse, IES_ProbeResponse); + + return status; + +} /* End dot11f_unpack_probe_response. */ + +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_QosMapConfigure, IES_QosMapConfigure); + + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport); + + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest); + + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocRequest, IES_ReAssocRequest); + + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocResponse, IES_ReAssocResponse); + + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SMPowerSave, IES_SMPowerSave); + + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryReq, IES_SaQueryReq); + + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryRsp, IES_SaQueryRsp); + + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisReq, IES_TDLSDisReq); + + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisRsp, IES_TDLSDisRsp); + + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf); + + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupReq, IES_TDLSSetupReq); + + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp); + + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSTeardown, IES_TDLSTeardown); + + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCReport, IES_TPCReport); + + return status; + +} /* End dot11f_unpack_tpc_report. */ + +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCRequest, IES_TPCRequest); + + return status; + +} /* End dot11f_unpack_tpc_request. */ + +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame); + + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame); + + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMDelTS, IES_WMMDelTS); + + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame); + + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint16_t i; + uint32_t nBufRemaining, status, len; + uint32_t countOffset = 0; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pFf = &(FFs[0]); + while (pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The Fixed Field %s req" + "uires %d bytes, but there are only %d remaining.\n"), + pFf->name, pFf->size, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + switch (pFf->sig) { + case SigFfAID: + dot11f_pack_ff_aid( + pCtx, (tDot11fFfAID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAction: + dot11f_pack_ff_action( + pCtx, (tDot11fFfAction *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthAlgo: + dot11f_pack_ff_auth_algo( + pCtx, (tDot11fFfAuthAlgo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthSeqNo: + dot11f_pack_ff_auth_seq_no( + pCtx, (tDot11fFfAuthSeqNo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfBeaconInterval: + dot11f_pack_ff_beacon_interval( + pCtx, (tDot11fFfBeaconInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCapabilities: + dot11f_pack_ff_capabilities( + pCtx, (tDot11fFfCapabilities *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCategory: + dot11f_pack_ff_category( + pCtx, (tDot11fFfCategory *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCurrentAPAddress: + dot11f_pack_ff_current_ap_address( + pCtx, (tDot11fFfCurrentAPAddress *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfDialogToken: + dot11f_pack_ff_dialog_token( + pCtx, (tDot11fFfDialogToken *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfLinkMargin: + dot11f_pack_ff_link_margin( + pCtx, (tDot11fFfLinkMargin *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfListenInterval: + dot11f_pack_ff_listen_interval( + pCtx, (tDot11fFfListenInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfMaxTxPower: + dot11f_pack_ff_max_tx_power( + pCtx, (tDot11fFfMaxTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfNumOfRepetitions: + dot11f_pack_ff_num_of_repetitions( + pCtx, (tDot11fFfNumOfRepetitions *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfOperatingMode: + dot11f_pack_ff_operating_mode( + pCtx, (tDot11fFfOperatingMode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRCPI: + dot11f_pack_ff_rcpi( + pCtx, (tDot11fFfRCPI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRSNI: + dot11f_pack_ff_rsni( + pCtx, (tDot11fFfRSNI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfReason: + dot11f_pack_ff_reason( + pCtx, (tDot11fFfReason *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRxAntennaId: + dot11f_pack_ff_rx_antenna_id( + pCtx, (tDot11fFfRxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfSMPowerModeSet: + dot11f_pack_ff_sm_power_mode_set( + pCtx, (tDot11fFfSMPowerModeSet *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatus: + dot11f_pack_ff_status( + pCtx, (tDot11fFfStatus *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatusCode: + dot11f_pack_ff_status_code( + pCtx, (tDot11fFfStatusCode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleID: + dot11f_pack_ff_tpc_ele_id( + pCtx, (tDot11fFfTPCEleID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleLen: + dot11f_pack_ff_tpc_ele_len( + pCtx, (tDot11fFfTPCEleLen *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTSInfo: + dot11f_pack_ff_ts_info( + pCtx, (tDot11fFfTSInfo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTimeStamp: + dot11f_pack_ff_time_stamp( + pCtx, (tDot11fFfTimeStamp *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTransactionId: + dot11f_pack_ff_transaction_id( + pCtx, (tDot11fFfTransactionId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxAntennaId: + dot11f_pack_ff_tx_antenna_id( + pCtx, (tDot11fFfTxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxPower: + dot11f_pack_ff_tx_power( + pCtx, (tDot11fFfTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtMembershipStatusArray: + dot11f_pack_ff_vht_membership_status_array( + pCtx, (tDot11fFfVhtMembershipStatusArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtUserPositionArray: + dot11f_pack_ff_vht_user_position_array( + pCtx, (tDot11fFfVhtUserPositionArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the Fixed Field %d; this is most l" + "ikely a bug in 'framesg'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + *pnConsumed += pFf->size; + ++pFf; + + } + + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pSrc + pIe->offset + + pIe->presenceOffset); + if (*pfFound && pIe->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The IE %s takes at le" + "ast %d bytes, but there are only %d left in the b" + "uffer.\n"), pIe->name, pIe->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + + countOffset = ((0 == pIe->arraybound) ? 1 : *(uint16_t *)(pSrc + pIe->countOffset)); + for (i = 0; i < countOffset; ++i) { + len = 0U; + switch (pIe->sig) { + case SigIeCondensedCountryStr: + status |= + dot11f_pack_ie_condensed_country_str( + pCtx, (tDot11fIECondensedCountryStr *) + (pSrc + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeGTK: + status |= + dot11f_pack_ie_gtk( + pCtx, (tDot11fIEGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeIGTK: + status |= + dot11f_pack_ie_igtk( + pCtx, (tDot11fIEIGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR0KH_ID: + status |= + dot11f_pack_ie_r0_kh_id( + pCtx, (tDot11fIER0KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER0KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR1KH_ID: + status |= + dot11f_pack_ie_r1_kh_id( + pCtx, (tDot11fIER1KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER1KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSFInfo: + status |= + dot11f_pack_ie_tsf_info( + pCtx, (tDot11fIETSFInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSFInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAPChannelReport: + status |= + dot11f_pack_ie_ap_channel_report( + pCtx, (tDot11fIEAPChannelReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_pack_ie_bcn_reporting_detail( + pCtx, (tDot11fIEBcnReportingDetail *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_pack_ie_beacon_report_frm_body( + pCtx, (tDot11fIEBeaconReportFrmBody *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBeaconReporting: + status |= + dot11f_pack_ie_beacon_reporting( + pCtx, (tDot11fIEBeaconReporting *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementPilot: + status |= + dot11f_pack_ie_measurement_pilot( + pCtx, (tDot11fIEMeasurementPilot *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMultiBssid: + status |= + dot11f_pack_ie_multi_bssid( + pCtx, (tDot11fIEMultiBssid *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMultiBssid) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICData: + status |= + dot11f_pack_ie_ric_data( + pCtx, (tDot11fIERICData *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICData) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDescriptor: + status |= + dot11f_pack_ie_ric_descriptor( + pCtx, (tDot11fIERICDescriptor *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDescriptor) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_pack_ie_rrm_enabled_cap( + pCtx, (tDot11fIERRMEnabledCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRequestedInfo: + status |= + dot11f_pack_ie_requested_info( + pCtx, (tDot11fIERequestedInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIERequestedInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSSID: + status |= + dot11f_pack_ie_ssid( + pCtx, (tDot11fIESSID *) + (pSrc + pIe->offset + + sizeof(tDot11fIESSID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSchedule: + status |= + dot11f_pack_ie_schedule( + pCtx, (tDot11fIESchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIESchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLAS: + status |= + dot11f_pack_ie_tclas( + pCtx, (tDot11fIETCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLASSPROC: + status |= + dot11f_pack_ie_tclassproc( + pCtx, (tDot11fIETCLASSPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLASSPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSDelay: + status |= + dot11f_pack_ie_ts_delay( + pCtx, (tDot11fIETSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSPEC: + status |= + dot11f_pack_ie_tspec( + pCtx, (tDot11fIETSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTCaps: + status |= + dot11f_pack_ie_vht_caps( + pCtx, (tDot11fIEVHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTOperation: + status |= + dot11f_pack_ie_vht_operation( + pCtx, (tDot11fIEVHTOperation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTOperation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMSchedule: + status |= + dot11f_pack_ie_wmm_schedule( + pCtx, (tDot11fIEWMMSchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLAS: + status |= + dot11f_pack_ie_wmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_pack_ie_wmmtclasproc( + pCtx, (tDot11fIEWMMTCLASPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSDelay: + status |= + dot11f_pack_ie_wmmts_delay( + pCtx, (tDot11fIEWMMTSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSPEC: + status |= + dot11f_pack_ie_wmmtspec( + pCtx, (tDot11fIEWMMTSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_pack_ie_wider_bw_chan_switch_ann( + pCtx, (tDot11fIEWiderBWChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAID: + status |= + dot11f_pack_ie_aid( + pCtx, (tDot11fIEAID *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCFParams: + status |= + dot11f_pack_ie_cf_params( + pCtx, (tDot11fIECFParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIECFParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChallengeText: + status |= + dot11f_pack_ie_challenge_text( + pCtx, (tDot11fIEChallengeText *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChallengeText) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_pack_ie_chan_switch_ann( + pCtx, (tDot11fIEChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_pack_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCountry: + status |= + dot11f_pack_ie_country( + pCtx, (tDot11fIECountry *) + (pSrc + pIe->offset + + sizeof(tDot11fIECountry) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeDSParams: + status |= + dot11f_pack_ie_ds_params( + pCtx, (tDot11fIEDSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEDSParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeEDCAParamSet: + status |= + dot11f_pack_ie_edca_param_set( + pCtx, (tDot11fIEEDCAParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeERPInfo: + status |= + dot11f_pack_ie_erp_info( + pCtx, (tDot11fIEERPInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEERPInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESECckmOpaque: + status |= + dot11f_pack_ie_ese_cckm_opaque( + pCtx, (tDot11fIEESECckmOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_pack_ie_ese_rad_mgmt_cap( + pCtx, (tDot11fIEESERadMgmtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_pack_ie_ese_traf_strm_met( + pCtx, (tDot11fIEESETrafStrmMet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_pack_ie_ese_traf_strm_rate_set( + pCtx, (tDot11fIEESETrafStrmRateSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETxmitPower: + status |= + dot11f_pack_ie_ese_txmit_power( + pCtx, (tDot11fIEESETxmitPower *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESEVersion: + status |= + dot11f_pack_ie_ese_version( + pCtx, (tDot11fIEESEVersion *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESEVersion) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtCap: + status |= + dot11f_pack_ie_ext_cap( + pCtx, (tDot11fIEExtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtSuppRates: + status |= + dot11f_pack_ie_ext_supp_rates( + pCtx, (tDot11fIEExtSuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParamSet: + status |= + dot11f_pack_ie_fh_param_set( + pCtx, (tDot11fIEFHParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParams: + status |= + dot11f_pack_ie_fh_params( + pCtx, (tDot11fIEFHParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHPattTable: + status |= + dot11f_pack_ie_fh_patt_table( + pCtx, (tDot11fIEFHPattTable *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHPattTable) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFTInfo: + status |= + dot11f_pack_ie_ft_info( + pCtx, (tDot11fIEFTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTCaps: + status |= + dot11f_pack_ie_ht_caps( + pCtx, (tDot11fIEHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTInfo: + status |= + dot11f_pack_ie_ht_info( + pCtx, (tDot11fIEHTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeIBSSParams: + status |= + dot11f_pack_ie_ibss_params( + pCtx, (tDot11fIEIBSSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIBSSParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeLinkIdentifier: + status |= + dot11f_pack_ie_link_identifier( + pCtx, (tDot11fIELinkIdentifier *) + (pSrc + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementReport: + status |= + dot11f_pack_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementRequest: + status |= + dot11f_pack_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMobilityDomain: + status |= + dot11f_pack_ie_mobility_domain( + pCtx, (tDot11fIEMobilityDomain *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeNeighborReport: + status |= + dot11f_pack_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIENeighborReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOBSSScanParameters: + status |= + dot11f_pack_ie_obss_scan_parameters( + pCtx, (tDot11fIEOBSSScanParameters *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOperatingMode: + status |= + dot11f_pack_ie_operating_mode( + pCtx, (tDot11fIEOperatingMode *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOperatingMode) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocReq: + status |= + dot11f_pack_ie_p2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocRes: + status |= + dot11f_pack_ie_p2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeacon: + status |= + dot11f_pack_ie_p2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_pack_ie_p2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDeAuth: + status |= + dot11f_pack_ie_p2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_pack_ie_p2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_pack_ie_p2_pie_opaque( + pCtx, (tDot11fIEP2PIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeReq: + status |= + dot11f_pack_ie_p2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeRes: + status |= + dot11f_pack_ie_p2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePTIControl: + status |= + dot11f_pack_ie_pti_control( + pCtx, (tDot11fIEPTIControl *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPTIControl) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePUBufferStatus: + status |= + dot11f_pack_ie_pu_buffer_status( + pCtx, (tDot11fIEPUBufferStatus *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerCaps: + status |= + dot11f_pack_ie_power_caps( + pCtx, (tDot11fIEPowerCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerConstraints: + status |= + dot11f_pack_ie_power_constraints( + pCtx, (tDot11fIEPowerConstraints *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQBSSLoad: + status |= + dot11f_pack_ie_qbss_load( + pCtx, (tDot11fIEQBSSLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQComVendorIE: + status |= + dot11f_pack_ie_QComVendorIE( + pCtx, (tDot11fIEQComVendorIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsAp: + status |= + dot11f_pack_ie_qos_caps_ap( + pCtx, (tDot11fIEQOSCapsAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsStation: + status |= + dot11f_pack_ie_qos_caps_station( + pCtx, (tDot11fIEQOSCapsStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQosMapSet: + status |= + dot11f_pack_ie_qos_map_set( + pCtx, (tDot11fIEQosMapSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQosMapSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQuiet: + status |= + dot11f_pack_ie_quiet( + pCtx, (tDot11fIEQuiet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQuiet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRCPIIE: + status |= + dot11f_pack_ie_rcpiie( + pCtx, (tDot11fIERCPIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERCPIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDataDesc: + status |= + dot11f_pack_ie_ric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDataDesc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSN: + status |= + dot11f_pack_ie_rsn( + pCtx, (tDot11fIERSN *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSN) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNIIE: + status |= + dot11f_pack_ie_rsniie( + pCtx, (tDot11fIERSNIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNOpaque: + status |= + dot11f_pack_ie_rsn_opaque( + pCtx, (tDot11fIERSNOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppChannels: + status |= + dot11f_pack_ie_supp_channels( + pCtx, (tDot11fIESuppChannels *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppChannels) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_pack_ie_supp_operating_classes( + pCtx, (tDot11fIESuppOperatingClasses *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppRates: + status |= + dot11f_pack_ie_supp_rates( + pCtx, (tDot11fIESuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTIM: + status |= + dot11f_pack_ie_tim( + pCtx, (tDot11fIETIM *) + (pSrc + pIe->offset + + sizeof(tDot11fIETIM) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCReport: + status |= + dot11f_pack_ie_tpc_report( + pCtx, (tDot11fIETPCReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCRequest: + status |= + dot11f_pack_ie_tpc_request( + pCtx, (tDot11fIETPCRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_pack_ie_time_advertisement( + pCtx, (tDot11fIETimeAdvertisement *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeoutInterval: + status |= + dot11f_pack_ie_timeout_interval( + pCtx, (tDot11fIETimeoutInterval *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_pack_ie_vht_ext_bss_load( + pCtx, (tDot11fIEVHTExtBssLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor1IE: + status |= + dot11f_pack_ie_vendor1_ie( + pCtx, (tDot11fIEVendor1IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor1IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor3IE: + status |= + dot11f_pack_ie_vendor3_ie( + pCtx, (tDot11fIEVendor3IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor3IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPI: + status |= + dot11f_pack_ie_wapi( + pCtx, (tDot11fIEWAPI *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPI) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPIOpaque: + status |= + dot11f_pack_ie_wapi_opaque( + pCtx, (tDot11fIEWAPIOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFATPC: + status |= + dot11f_pack_ie_wfatpc( + pCtx, (tDot11fIEWFATPC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFATPC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_pack_ie_wfdie_opaque( + pCtx, (tDot11fIEWFDIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMCaps: + status |= + dot11f_pack_ie_wmm_caps( + pCtx, (tDot11fIEWMMCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoAp: + status |= + dot11f_pack_ie_wmm_info_ap( + pCtx, (tDot11fIEWMMInfoAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoStation: + status |= + dot11f_pack_ie_wmm_info_station( + pCtx, (tDot11fIEWMMInfoStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMParams: + status |= + dot11f_pack_ie_wmm_params( + pCtx, (tDot11fIEWMMParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPA: + status |= + dot11f_pack_ie_wpa( + pCtx, (tDot11fIEWPA *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPA) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPAOpaque: + status |= + dot11f_pack_ie_wpa_opaque( + pCtx, (tDot11fIEWPAOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWSC: + status |= + dot11f_pack_ie_wsc( + pCtx, (tDot11fIEWSC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWSC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocReq: + status |= + dot11f_pack_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocRes: + status |= + dot11f_pack_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeacon: + status |= + dot11f_pack_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_pack_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscIEOpaque: + status |= + dot11f_pack_ie_wsc_ie_opaque( + pCtx, (tDot11fIEWscIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeReq: + status |= + dot11f_pack_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeRes: + status |= + dot11f_pack_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscReassocRes: + status |= + dot11f_pack_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_pack_ie_ext_chan_switch_ann( + pCtx, (tDot11fIEext_chan_switch_ann *) + (pSrc + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_pack_ie_ht2040_bss_coexistence( + pCtx, (tDot11fIEht2040_bss_coexistence *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_pack_ie_ht2040_bss_intolerant_report( + pCtx, (tDot11fIEht2040_bss_intolerant_report *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_pack_ie_sec_chan_offset_ele( + pCtx, (tDot11fIEsec_chan_offset_ele *) + (pSrc + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIevendor2_ie: + status |= + dot11f_pack_ie_vendor2_ie( + pCtx, (tDot11fIEvendor2_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEvendor2_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE %d; this is most likely a b" + "ug in 'framesc'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + } + + ++pIe; + + } + + return status; + +} + +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx) +{ + const tTLVDefn *pTlv; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status, len; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pSrc + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound && pTlv->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The TLV %s takes at least" + " %d bytes, but there are only %d left in the buffer." + "\n"), pTlv->name, pTlv->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + len = 0U; + + if (*pfFound) { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_pack_tlv_authorized_ma_cs( + pCtx, (tDot11fTLVAuthorizedMACs *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_pack_tlv_request_to_enroll( + pCtx, (tDot11fTLVRequestToEnroll *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion2: + status |= + dot11f_pack_tlv_version2( + pCtx, (tDot11fTLVVersion2 *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_pack_tlv_ap_setup_locked( + pCtx, (tDot11fTLVAPSetupLocked *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAssociationState: + status |= + dot11f_pack_tlv_association_state( + pCtx, (tDot11fTLVAssociationState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigMethods: + status |= + dot11f_pack_tlv_config_methods( + pCtx, (tDot11fTLVConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigurationError: + status |= + dot11f_pack_tlv_configuration_error( + pCtx, (tDot11fTLVConfigurationError *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDeviceName: + status |= + dot11f_pack_tlv_device_name( + pCtx, (tDot11fTLVDeviceName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_pack_tlv_device_password_id( + pCtx, (tDot11fTLVDevicePasswordID *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_pack_tlv_extended_listen_timing( + pCtx, (tDot11fTLVExtendedListenTiming *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvListenChannel: + status |= + dot11f_pack_tlv_listen_channel( + pCtx, (tDot11fTLVListenChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvManufacturer: + status |= + dot11f_pack_tlv_manufacturer( + pCtx, (tDot11fTLVManufacturer *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_pack_tlv_minor_reason_code( + pCtx, (tDot11fTLVMinorReasonCode *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelName: + status |= + dot11f_pack_tlv_model_name( + pCtx, (tDot11fTLVModelName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelNumber: + status |= + dot11f_pack_tlv_model_number( + pCtx, (tDot11fTLVModelNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_pack_tlv_notice_of_absence( + pCtx, (tDot11fTLVNoticeOfAbsence *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvOperatingChannel: + status |= + dot11f_pack_tlv_operating_channel( + pCtx, (tDot11fTLVOperatingChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PCapability: + status |= + dot11f_pack_tlv_p2_p_capability( + pCtx, (tDot11fTLVP2PCapability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_pack_tlv_p2_p_device_id( + pCtx, (tDot11fTLVP2PDeviceId *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_pack_tlv_p2_p_device_info( + pCtx, (tDot11fTLVP2PDeviceInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_pack_tlv_p2_p_group_info( + pCtx, (tDot11fTLVP2PGroupInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PStatus: + status |= + dot11f_pack_tlv_p2_p_status( + pCtx, (tDot11fTLVP2PStatus *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_pack_tlv_primary_device_type( + pCtx, (tDot11fTLVPrimaryDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRFBands: + status |= + dot11f_pack_tlv_rf_bands( + pCtx, (tDot11fTLVRFBands *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_pack_tlv_request_device_type( + pCtx, (tDot11fTLVRequestDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestType: + status |= + dot11f_pack_tlv_request_type( + pCtx, (tDot11fTLVRequestType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvResponseType: + status |= + dot11f_pack_tlv_response_type( + pCtx, (tDot11fTLVResponseType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_pack_tlv_selected_registrar( + pCtx, (tDot11fTLVSelectedRegistrar *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_pack_tlv_selected_registrar_config_methods( + pCtx, (tDot11fTLVSelectedRegistrarConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSerialNumber: + status |= + dot11f_pack_tlv_serial_number( + pCtx, (tDot11fTLVSerialNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_E: + status |= + dot11f_pack_tlv_uuid_e( + pCtx, (tDot11fTLVUUID_E *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_R: + status |= + dot11f_pack_tlv_uuid_r( + pCtx, (tDot11fTLVUUID_R *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVendorExtension: + status |= + dot11f_pack_tlv_vendor_extension( + pCtx, (tDot11fTLVVendorExtension *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion: + status |= + dot11f_pack_tlv_version( + pCtx, (tDot11fTLVVersion *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvWPSState: + status |= + dot11f_pack_tlv_wps_state( + pCtx, (tDot11fTLVWPSState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PInterface: + status |= + dot11f_pack_tlv_p2_p_interface( + pCtx, (tDot11fTLVP2PInterface *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PManageability: + status |= + dot11f_pack_tlv_p2_p_manageability( + pCtx, (tDot11fTLVP2PManageability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don't " + "know about the TLV %d; this is most likely a bug in " + "'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + + } /* End if on *pfFound */ + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + ++pTlv; + if (len) + ++*pidx; + } + + return status; + +} diff --git a/core/mac/src/sys/legacy/src/utils/src/log_api.c b/core/mac/src/sys/legacy/src/utils/src/log_api.c new file mode 100644 index 0000000000..8ec7b8c9e8 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/log_api.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * log_api.cc - Handles log messages for all the modules. + * Author: Kevin Nguyen + * Date: 02/27/02 + * History:- + * 02/11/02 Created. + * 03/12/02 Rearrange log_debug parameter list and add more params. + * -------------------------------------------------------------------- + * + */ + +#include +#include +#include +#include + +#include +#include "utils_global.h" +#include "mac_init_api.h" + +#include "cdf_trace.h" + +#ifdef ANI_OS_TYPE_ANDROID +#include +#endif + +/* --------------------------------------------------------------------- */ +/** + * log_init() + * + * FUNCTION: + * This function is called to prepare the logging utility. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param tpAniSirGlobal Sirius software parameter strucutre pointer + * @return None + */ +tSirRetStatus log_init(tpAniSirGlobal pMac) +{ + uint32_t i; + + /* Add code to initialize debug level from CFG module */ + /* For now, enable all logging */ + for (i = 0; i < LOG_ENTRY_NUM; i++) { +#ifdef SIR_DEBUG + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + LOG1; +#else + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + LOGW; +#endif + } + return eSIR_SUCCESS; + +} /*** log_init() ***/ + +void log_deinit(tpAniSirGlobal pMac) +{ + return; +} + +/** + * log_dbg() + * + ***FUNCTION: + * This function is called to log a debug message. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * None. + * + ***NOTE: + * + * @param tpAniSirGlobal Sirius software parameter strucutre pointer + * @param ModId 8-bit modID + * @param debugLevel debugging level for this message + * @param pStr string parameter pointer + * @return None + */ + +void log_dbg(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, ...) +{ +#ifdef WLAN_DEBUG + if (debugLevel > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(modId)]) + return; + else { + va_list marker; + + va_start(marker, pStr); /* Initialize variable arguments. */ + + log_debug(pMac, modId, debugLevel, pStr, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +CDF_TRACE_LEVEL get_vos_debug_level(uint32_t debugLevel) +{ + switch (debugLevel) { + case LOGP: + return CDF_TRACE_LEVEL_FATAL; + case LOGE: + return CDF_TRACE_LEVEL_ERROR; + case LOGW: + return CDF_TRACE_LEVEL_WARN; + case LOG1: + return CDF_TRACE_LEVEL_INFO; + case LOG2: + return CDF_TRACE_LEVEL_INFO_HIGH; + case LOG3: + return CDF_TRACE_LEVEL_INFO_MED; + case LOG4: + return CDF_TRACE_LEVEL_INFO_LOW; + default: + return CDF_TRACE_LEVEL_INFO_LOW; + } +} + +static inline CDF_MODULE_ID get_vos_module_id(uint8_t modId) +{ + switch (modId) { + case SIR_HAL_MODULE_ID: + return CDF_MODULE_ID_WMA; + + case SIR_LIM_MODULE_ID: + case SIR_SCH_MODULE_ID: + case SIR_CFG_MODULE_ID: + case SIR_MNT_MODULE_ID: + case SIR_DPH_MODULE_ID: + case SIR_DBG_MODULE_ID: + return CDF_MODULE_ID_PE; + + case SIR_SYS_MODULE_ID: + return CDF_MODULE_ID_SYS; + + case SIR_SMS_MODULE_ID: + return CDF_MODULE_ID_SME; + + default: + return CDF_MODULE_ID_SYS; + } +} + +#define LOG_SIZE 256 +void log_debug(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, va_list marker) +{ + CDF_TRACE_LEVEL cdf_debug_level; + CDF_MODULE_ID cdf_module_id; + char logBuffer[LOG_SIZE]; + + cdf_debug_level = get_vos_debug_level(debugLevel); + cdf_module_id = get_vos_module_id(modId); + + vsnprintf(logBuffer, LOG_SIZE - 1, pStr, marker); + CDF_TRACE(cdf_module_id, cdf_debug_level, "%s", logBuffer); + + /* The caller must check loglevel */ + CDF_ASSERT((debugLevel <= + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(modId)]) + && (LOGP != debugLevel)); +} /*** end log_debug() ***/ diff --git a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c new file mode 100644 index 0000000000..7d0d9ac102 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file mac_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "mac_trace.h" +#include "wma_types.h" +#include "csr_neighbor_roam.h" +#include "csr_internal.h" +#include "lim_global.h" +#include "cdf_memory.h" +#include "cdf_trace.h" +#include "wma_if.h" + +#ifdef TRACE_RECORD +/** + * mac_trace_get_neighbour_roam_state() - Get the neighbor roam state + * @neighbourroamstate: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_neighbour_roam_state(uint16_t neighbourroamstate) +{ + switch (neighbourroamstate) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); +#ifdef WLAN_FEATURE_VOWIFI_11R + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + CASE_RETURN_STRING(eNEIGHBOR_STATE_MAX); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_getcsr_roam_state() - Get the csr roam state + * @csr_roam_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roam_state) +{ + switch (csr_roam_state) { + CASE_RETURN_STRING(eCSR_ROAMING_STATE_STOP); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_IDLE); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINING); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINED); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_getcsr_roam_sub_state() - Get the csr roam sub state + * @csr_roam_sub_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roam_sub_state) +{ + switch (csr_roam_sub_state) { + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_NONE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_START_BSS_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOIN_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_REASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_AUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_CONFIG); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_FORCED); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_sme_state() - Get the lim sme state + * @lim_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_sme_state(uint16_t lim_state) +{ + switch (lim_state) { + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_LINK_FAIL_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_mlm_state() - Get the lim mlm state + * @mlmstate: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlm_state) +{ + switch (mlm_state) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_LEARN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_sme_msg_string() - Get the msg + * @sme_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_sme_msg_string(uint16_t sme_msg) +{ + switch (sme_msg) { + CASE_RETURN_STRING(eWNI_SME_SYS_READY_IND); + CASE_RETURN_STRING(eWNI_SME_SCAN_REQ); + CASE_RETURN_STRING(eWNI_SME_SCAN_ABORT_IND); + CASE_RETURN_STRING(eWNI_SME_SCAN_RSP); +#ifdef FEATURE_OEM_DATA_SUPPORT + CASE_RETURN_STRING(eWNI_SME_OEM_DATA_REQ); + CASE_RETURN_STRING(eWNI_SME_OEM_DATA_RSP); +#endif + CASE_RETURN_STRING(eWNI_SME_JOIN_REQ); + CASE_RETURN_STRING(eWNI_SME_JOIN_RSP); + CASE_RETURN_STRING(eWNI_SME_SETCONTEXT_REQ); + CASE_RETURN_STRING(eWNI_SME_SETCONTEXT_RSP); + CASE_RETURN_STRING(eWNI_SME_REASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_REASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_IND); + CASE_RETURN_STRING(eWNI_SME_WM_STATUS_CHANGE_NTF); + CASE_RETURN_STRING(eWNI_SME_IBSS_NEW_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_DEPARTED_IND); + CASE_RETURN_STRING(eWNI_SME_START_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_START_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_ASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_SWITCH_CHL_IND); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_BSS_IND); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_CNF); + CASE_RETURN_STRING(eWNI_SME_MIC_FAILURE_IND); + CASE_RETURN_STRING(eWNI_SME_ADDTS_REQ); + CASE_RETURN_STRING(eWNI_SME_ADDTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_REQ); + CASE_RETURN_STRING(eWNI_SME_DELTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_IND); + CASE_RETURN_STRING(eWNI_SME_GET_STATISTICS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_STATISTICS_RSP); + CASE_RETURN_STRING(eWNI_SME_GET_RSSI_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_ASSOC_STAS_REQ); + CASE_RETURN_STRING(eWNI_SME_TKIP_CNTR_MEAS_REQ); + CASE_RETURN_STRING(eWNI_SME_UPDATE_APWPSIE_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_WPSPBC_SESSION_REQ); + CASE_RETURN_STRING(eWNI_SME_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_SET_APWPARSNIEs_REQ); + CASE_RETURN_STRING(eWNI_SME_UPPER_LAYER_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_HIDE_SSID_REQ); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHANNEL_REQ); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHN_RSP); + CASE_RETURN_STRING(eWNI_SME_MGMT_FRM_IND); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHN_RDY_IND); + CASE_RETURN_STRING(eWNI_SME_SEND_ACTION_FRAME_IND); + CASE_RETURN_STRING(eWNI_SME_ACTION_FRAME_SEND_CNF); + CASE_RETURN_STRING(eWNI_SME_ABORT_REMAIN_ON_CHAN_IND); + CASE_RETURN_STRING(eWNI_SME_UPDATE_NOA); + CASE_RETURN_STRING(eWNI_SME_CLEAR_DFS_CHANNEL_LIST); + CASE_RETURN_STRING(eWNI_SME_GET_SNR_REQ); + CASE_RETURN_STRING(eWNI_SME_LINK_STATUS_IND); + + CASE_RETURN_STRING(eWNI_PMC_MSG_TYPES_BEGIN); + + CASE_RETURN_STRING(eWNI_PMC_SMPS_STATE_IND); +#if defined WLAN_FEATURE_VOWIFI + CASE_RETURN_STRING(eWNI_SME_RRM_MSG_TYPE_BEGIN); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_RESP_XMIT_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_ADD_STA_SELF_RSP); + CASE_RETURN_STRING(eWNI_SME_DEL_STA_SELF_RSP); +#if defined WLAN_FEATURE_VOWIFI_11R + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_FT_UPDATE_KEY); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_RSP); +#endif +#if defined FEATURE_WLAN_ESE + CASE_RETURN_STRING(eWNI_SME_ESE_ADJACENT_AP_REPORT); +#endif + CASE_RETURN_STRING(eWNI_SME_REGISTER_MGMT_FRAME_REQ); +#ifdef FEATURE_WLAN_SCAN_PNO + CASE_RETURN_STRING(eWNI_SME_PREF_NETWORK_FOUND_IND); +#endif /* FEATURE_WLAN_SCAN_PNO */ + CASE_RETURN_STRING(eWNI_SME_CHANGE_COUNTRY_CODE); + CASE_RETURN_STRING(eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE); + CASE_RETURN_STRING(eWNI_SME_MAX_ASSOC_EXCEEDED); +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(eWNI_SME_MSG_TYPES_END); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_RSP); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(eWNI_SME_ROAM_OFFLOAD_SYNCH_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_RESP); + CASE_RETURN_STRING(eWNI_SME_HW_MODE_TRANS_IND); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_wma_msg_string() - Get the msg + * @wma_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg) +{ + switch (wma_msg) { + CASE_RETURN_STRING(WMA_ADD_STA_REQ); + CASE_RETURN_STRING(WMA_ADD_STA_RSP); + CASE_RETURN_STRING(WMA_ADD_STA_SELF_RSP); + CASE_RETURN_STRING(WMA_DELETE_STA_REQ); + CASE_RETURN_STRING(WMA_DELETE_STA_RSP); + CASE_RETURN_STRING(WMA_ADD_BSS_REQ); + CASE_RETURN_STRING(WMA_ADD_BSS_RSP); + CASE_RETURN_STRING(WMA_DELETE_BSS_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_RSP); + CASE_RETURN_STRING(WMA_SEND_BEACON_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_RSP); + CASE_RETURN_STRING(WMA_SET_STAKEY_REQ); + CASE_RETURN_STRING(WMA_SET_STAKEY_RSP); + CASE_RETURN_STRING(WMA_UPDATE_EDCA_PROFILE_IND); + + CASE_RETURN_STRING(WMA_UPDATE_BEACON_IND); + CASE_RETURN_STRING(WMA_UPDATE_CF_IND); + CASE_RETURN_STRING(WMA_CHNL_SWITCH_REQ); + CASE_RETURN_STRING(WMA_ADD_TS_REQ); + CASE_RETURN_STRING(WMA_DEL_TS_REQ); + CASE_RETURN_STRING(WMA_EXIT_PS_REQ); + CASE_RETURN_STRING(WMA_ENTER_PS_REQ); + CASE_RETURN_STRING(WMA_MISSED_BEACON_IND); + + CASE_RETURN_STRING(WMA_CFG_RXP_FILTER_REQ); + CASE_RETURN_STRING(WMA_SWITCH_CHANNEL_RSP); + CASE_RETURN_STRING(WMA_P2P_NOA_ATTR_IND); + CASE_RETURN_STRING(WMA_P2P_NOA_START_IND); + CASE_RETURN_STRING(WMA_PWR_SAVE_CFG); + CASE_RETURN_STRING(WMA_REGISTER_PE_CALLBACK); + + CASE_RETURN_STRING(WMA_IBSS_STA_ADD); + CASE_RETURN_STRING(WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND); + CASE_RETURN_STRING(WMA_SET_LINK_STATE); + CASE_RETURN_STRING(WMA_SET_LINK_STATE_RSP); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_REQ); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_RSP); + CASE_RETURN_STRING(WMA_ADD_TS_RSP); + CASE_RETURN_STRING(WMA_DPU_MIC_ERROR); + + CASE_RETURN_STRING(WMA_TIMER_CHIP_MONITOR_TIMEOUT); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_ACTIVITY_REQ); + CASE_RETURN_STRING(WMA_TIMER_ADC_RSSI_STATS); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(WMA_TSM_STATS_REQ); + CASE_RETURN_STRING(WMA_TSM_STATS_RSP); +#endif + CASE_RETURN_STRING(WMA_SET_MIMOPS_REQ); + CASE_RETURN_STRING(WMA_SET_MIMOPS_RSP); + CASE_RETURN_STRING(WMA_SYS_READY_IND); + CASE_RETURN_STRING(WMA_SET_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_GET_TX_POWER_REQ); + + CASE_RETURN_STRING(WMA_TRANSMISSION_CONTROL_IND); + CASE_RETURN_STRING(WMA_ENABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_DISABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_BEACON_FILTER_IND); + CASE_RETURN_STRING(WMA_WOW_ADD_PTRN); + CASE_RETURN_STRING(WMA_WOW_DEL_PTRN); + CASE_RETURN_STRING(WMA_WOWL_ENTER_REQ); + CASE_RETURN_STRING(WMA_WOWL_EXIT_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_RSP); + CASE_RETURN_STRING(WMA_SET_KEY_DONE); + + CASE_RETURN_STRING(WMA_BTC_SET_CFG); + CASE_RETURN_STRING(WMA_HANDLE_FW_MBOX_RSP); + CASE_RETURN_STRING(WMA_SEND_PROBE_RSP_TMPL); +#ifdef FEATURE_OEM_DATA_SUPPORT + CASE_RETURN_STRING(WMA_START_OEM_DATA_REQ); + CASE_RETURN_STRING(WMA_START_OEM_DATA_RSP); +#endif /* SUPPORT_BEACON_FILTER */ + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_HOST_OFFLOAD); + CASE_RETURN_STRING(WMA_SET_KEEP_ALIVE); +#ifdef WLAN_NS_OFFLOAD + CASE_RETURN_STRING(WMA_SET_NS_OFFLOAD); +#endif /* WLAN_NS_OFFLOAD */ + CASE_RETURN_STRING(WMA_ADD_STA_SELF_REQ); + CASE_RETURN_STRING(WMA_DEL_STA_SELF_REQ); + CASE_RETURN_STRING(WMA_SET_P2P_GO_NOA_REQ); + CASE_RETURN_STRING(WMA_WLAN_SUSPEND_IND); + CASE_RETURN_STRING(WMA_WLAN_RESUME_REQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(WMA_WLAN_EXT_WOW); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE1_PARAMS); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE2_PARAMS); +#endif + CASE_RETURN_STRING(WMA_MSG_TYPES_END); +#ifdef WLAN_FEATURE_VOWIFI_11R + CASE_RETURN_STRING(WMA_AGGR_QOS_REQ); + CASE_RETURN_STRING(WMA_AGGR_QOS_RSP); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + CASE_RETURN_STRING(WMA_FTM_CMD_REQ); + CASE_RETURN_STRING(WMA_FTM_CMD_RSP); +#ifdef FEATURE_WLAN_SCAN_PNO + CASE_RETURN_STRING(WMA_SET_PNO_REQ); + CASE_RETURN_STRING(WMA_SME_SCAN_CACHE_UPDATED); +#endif /* FEATURE_WLAN_SCAN_PNO */ + CASE_RETURN_STRING(WMA_ROAM_SCAN_OFFLOAD_REQ); +#ifdef WLAN_FEATURE_PACKET_FILTERING + CASE_RETURN_STRING(WMA_8023_MULTICAST_LIST_REQ); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_SET_FILTER_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(WMA_SET_TM_LEVEL_REQ); +#ifdef WLAN_FEATURE_11AC + CASE_RETURN_STRING(WMA_UPDATE_OP_MODE); + CASE_RETURN_STRING(WMA_UPDATE_MEMBERSHIP); + CASE_RETURN_STRING(WMA_UPDATE_USERPOS); +#endif + CASE_RETURN_STRING(WMA_START_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_STOP_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_UPDATE_CHAN_LIST_REQ); + CASE_RETURN_STRING(WMA_CLI_SET_CMD); +#ifndef REMOVE_PKT_LOG + CASE_RETURN_STRING(WMA_PKTLOG_ENABLE_REQ); +#endif +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + CASE_RETURN_STRING(WMA_SET_PLM_REQ); +#endif + CASE_RETURN_STRING(WMA_CONFIG_PARAM_UPDATE_REQ); + CASE_RETURN_STRING(WMA_RATE_UPDATE_IND); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_UPDATE_FW_TDLS_STATE); + CASE_RETURN_STRING(WMA_UPDATE_TDLS_PEER_STATE); +#endif + CASE_RETURN_STRING(WMA_ADD_PERIODIC_TX_PTRN_IND); + CASE_RETURN_STRING(WMA_TX_POWER_LIMIT); +#ifdef FEATURE_WLAN_LPHB + CASE_RETURN_STRING(WMA_LPHB_CONF_REQ); +#endif + CASE_RETURN_STRING(WMA_DHCP_START_IND); + CASE_RETURN_STRING(WMA_DHCP_STOP_IND); +#ifdef FEATURE_WLAN_CH_AVOID + CASE_RETURN_STRING(WMA_CH_AVOID_UPDATE_REQ); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CASE_RETURN_STRING(WMA_SET_AUTO_SHUTDOWN_TIMER_REQ); +#endif + CASE_RETURN_STRING(WMA_INIT_THERMAL_INFO_CMD); + CASE_RETURN_STRING(WMA_SET_THERMAL_LEVEL); + CASE_RETURN_STRING(WMA_SET_SAP_INTRABSS_DIS); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_CNF); + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_FAIL); +#endif + CASE_RETURN_STRING(SIR_HAL_SET_BASE_MACADDR_IND); + CASE_RETURN_STRING(WMA_LINK_STATUS_GET_REQ); +#ifdef DHCP_SERVER_OFFLOAD + CASE_RETURN_STRING(WMA_SET_DHCP_SERVER_OFFLOAD_CMD); +#endif + CASE_RETURN_STRING(WMA_OCB_SET_CONFIG_CMD); + CASE_RETURN_STRING(WMA_OCB_SET_UTC_TIME_CMD); + CASE_RETURN_STRING(WMA_OCB_START_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_STOP_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_GET_TSF_TIMER_CMD); + CASE_RETURN_STRING(WMA_DCC_GET_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_CLEAR_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_UPDATE_NDL_CMD); + CASE_RETURN_STRING(WMA_SET_IE_INFO); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); + CASE_RETURN_STRING(SIR_HAL_UNIT_TEST_CMD); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(SIR_HAL_ROAM_INVOKE); +#endif + CASE_RETURN_STRING(SIR_HAL_SET_MAS); + CASE_RETURN_STRING(SIR_HAL_SET_MIRACAST); + CASE_RETURN_STRING(SIR_HAL_CONFIG_STATS_FACTOR); + CASE_RETURN_STRING(SIR_HAL_CONFIG_GUARD_TIME); + CASE_RETURN_STRING(SIR_HAL_START_STOP_LOGGING); + CASE_RETURN_STRING(SIR_HAL_FLUSH_LOG_TO_FW); + CASE_RETURN_STRING(SIR_HAL_SOC_SET_PCL_TO_FW); + CASE_RETURN_STRING(SIR_HAL_SOC_SET_HW_MODE); + CASE_RETURN_STRING(SIR_HAL_SOC_DUAL_MAC_CFG_REQ); + CASE_RETURN_STRING(WMA_RADAR_DETECTED_IND); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_STATS_IND); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING(WMA_EXCLUDE_UNENCRYPTED_IND); +#endif + CASE_RETURN_STRING(WMA_WOWL_ENTER_RSP); + CASE_RETURN_STRING(WMA_WOWL_EXIT_RSP); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_PER_BAND_REQ); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ); + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP); +#endif + CASE_RETURN_STRING(WMA_CSA_OFFLOAD_EVENT); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_IND); +#endif + CASE_RETURN_STRING(WMA_HIDDEN_SSID_VDEV_RESTART); +#ifdef WLAN_FEATURE_11AC + CASE_RETURN_STRING(WMA_UPDATE_RX_NSS); +#endif +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(WMA_NAN_REQUEST); +#endif + CASE_RETURN_STRING(WMA_RX_SCAN_EVENT); + CASE_RETURN_STRING(WMA_IBSS_PEER_INACTIVITY_IND); + CASE_RETURN_STRING(WMA_DEL_PERIODIC_TX_PTRN_IND); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_TDLS_SHOULD_DISCOVER_CMD); + CASE_RETURN_STRING(WMA_TDLS_SHOULD_TEARDOWN_CMD); + CASE_RETURN_STRING(WMA_TDLS_PEER_DISCONNECTED_CMD); + CASE_RETURN_STRING(WMA_TDLS_SET_OFFCHAN_MODE); +#endif + CASE_RETURN_STRING(WMA_DFS_RADAR_IND); + CASE_RETURN_STRING(WMA_DFS_BEACON_TX_SUCCESS_IND); + CASE_RETURN_STRING(WMA_DISASSOC_TX_COMP); + CASE_RETURN_STRING(WMA_DEAUTH_TX_COMP); + CASE_RETURN_STRING(WMA_GET_LINK_SPEED); + CASE_RETURN_STRING(WMA_MODEM_POWER_STATE_IND); +#ifdef WLAN_FEATURE_STATS_EXT + CASE_RETURN_STRING(WMA_STATS_EXT_REQUEST); +#endif + CASE_RETURN_STRING(WMA_IPA_OFFLOAD_ENABLE_DISABLE); + CASE_RETURN_STRING(WMA_GET_TEMPERATURE_REQ); +#ifdef FEATURE_WLAN_EXTSCAN + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CAPABILITIES_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_START_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_STOP_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CACHED_RESULTS_REQ); + CASE_RETURN_STRING(WMA_SET_EPNO_LIST_REQ); + CASE_RETURN_STRING(WMA_SET_PASSPOINT_LIST_REQ); + CASE_RETURN_STRING(WMA_RESET_PASSPOINT_LIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_SSID_HOTLIST_REQ); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_CLEAR_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_SET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_GET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_RESULTS_RSP); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + CASE_RETURN_STRING(WMA_SET_SCAN_MAC_OUI_REQ); +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + CASE_RETURN_STRING(WMA_LED_FLASHING_REQ); +#endif + CASE_RETURN_STRING(WMA_PROCESS_FW_EVENT); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + CASE_RETURN_STRING(WMA_UPDATE_Q2Q_IE_IND); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + CASE_RETURN_STRING(WMA_SET_RSSI_MONITOR_REQ); + CASE_RETURN_STRING(WMA_FW_MEM_DUMP_REQ); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_msg_string() - Get the msg + * @lim_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_lim_msg_string(uint16_t lim_msg) +{ + switch (lim_msg) { + CASE_RETURN_STRING(SIR_LIM_RETRY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_BB_XPORT_MGMT_MSG); + CASE_RETURN_STRING(SIR_LIM_INV_KEY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_KEY_ID_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_REPLAY_THRES_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_TD_DUMMY_CALLBACK_MSG); + CASE_RETURN_STRING(SIR_LIM_SCH_CLEAN_MSG); + CASE_RETURN_STRING(SIR_LIM_RADAR_DETECT_IND); + CASE_RETURN_STRING(SIR_LIM_DEL_TS_IND); + CASE_RETURN_STRING(SIR_LIM_DELETE_STA_CONTEXT_IND); + CASE_RETURN_STRING(SIR_LIM_UPDATE_BEACON); + CASE_RETURN_STRING(SIR_LIM_JOIN_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_REASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_HEART_BEAT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_PROBE_HB_FAILURE_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ADDTS_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_LINK_TEST_DURATION_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_HASH_MISS_THRES_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CNF_WAIT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CHANNEL_SWITCH_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_BSS_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_WPS_OVERLAP_TIMEOUT); +#ifdef WLAN_FEATURE_VOWIFI_11R + CASE_RETURN_STRING(SIR_LIM_FT_PREAUTH_RSP_TIMEOUT); +#endif + CASE_RETURN_STRING(SIR_LIM_REMAIN_CHN_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE); + CASE_RETURN_STRING(SIR_LIM_BEACON_GEN_IND); + CASE_RETURN_STRING(SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(SIR_LIM_ESE_TSM_TIMEOUT); +#endif + CASE_RETURN_STRING(SIR_LIM_DISASSOC_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_DEAUTH_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_MSG_TYPES_END); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_cfg_msg_string() - Get the msg + * @cfg_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_cfg_msg_string(uint16_t cfg_msg) +{ + switch (cfg_msg) { + CASE_RETURN_STRING(WNI_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); + CASE_RETURN_STRING(WNI_CFG_DNLD_CNF); + CASE_RETURN_STRING(WNI_CFG_GET_RSP); + CASE_RETURN_STRING(WNI_CFG_SET_CNF); + CASE_RETURN_STRING(SIR_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(SIR_CFG_DOWNLOAD_COMPLETE_IND); + + CASE_RETURN_STRING(WNI_CFG_SET_REQ_NO_RSP); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_info_log_string() - Get the log info + * @info_log: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_info_log_string(uint16_t info_log) +{ + switch (info_log) { + CASE_RETURN_STRING(eLOG_NODROP_MISSED_BEACON_SCENARIO); + CASE_RETURN_STRING(eLOG_PROC_DEAUTH_FRAME_SCENARIO); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace() - Main function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace(tpAniSirGlobal mac_ctx, uint8_t code, + uint16_t session, uint32_t data) +{ + /* + * Today mac_trace is being invoked by PE only, need to remove this + * function once PE is migrated to using new trace API. + */ + mac_trace_new(mac_ctx, CDF_MODULE_ID_PE, code, session, data); +} + +/** + * mac_trace_new() - New function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace_new(tpAniSirGlobal mac_ctx, uint8_t module, uint8_t code, + uint16_t session, uint32_t data) +{ + cdf_trace(module, code, session, data); +} + +#endif diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c new file mode 100644 index 0000000000..7dea42c89d --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -0,0 +1,5654 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file parser_api.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "parser_api.h" +#include "cfg_api.h" +#include "lim_utils.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "wmm_apsd.h" +#if defined WLAN_FEATURE_VOWIFI +#include "rrm_api.h" +#endif + +#include "cds_regdomain_common.h" + +/* ////////////////////////////////////////////////////////////////////// */ +void dot11f_log(tpAniSirGlobal pMac, int loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + if ((uint32_t) loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_DBG_MODULE_ID)]) { + return; + } else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_DBG_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +void swap_bit_field16(uint16_t in, uint16_t *out) +{ +#ifdef ANI_LITTLE_BIT_ENDIAN + *out = in; +#else /* Big-Endian... */ + *out = ((in & 0x8000) >> 15) | + ((in & 0x4000) >> 13) | + ((in & 0x2000) >> 11) | + ((in & 0x1000) >> 9) | + ((in & 0x0800) >> 7) | + ((in & 0x0400) >> 5) | + ((in & 0x0200) >> 3) | + ((in & 0x0100) >> 1) | + ((in & 0x0080) << 1) | + ((in & 0x0040) << 3) | + ((in & 0x0020) << 5) | + ((in & 0x0010) << 7) | + ((in & 0x0008) << 9) | + ((in & 0x0004) << 11) | + ((in & 0x0002) << 13) | ((in & 0x0001) << 15); +#endif /* ANI_LITTLE_BIT_ENDIAN */ +} + +void swap_bit_field32(uint32_t in, uint32_t *out) +{ +#ifdef ANI_LITTLE_BIT_ENDIAN + *out = in; +#else /* Big-Endian... */ + *out = ((in & 0x80000000) >> 31) | + ((in & 0x40000000) >> 29) | + ((in & 0x20000000) >> 27) | + ((in & 0x10000000) >> 25) | + ((in & 0x08000000) >> 23) | + ((in & 0x04000000) >> 21) | + ((in & 0x02000000) >> 19) | + ((in & 0x01000000) >> 17) | + ((in & 0x00800000) >> 15) | + ((in & 0x00400000) >> 13) | + ((in & 0x00200000) >> 11) | + ((in & 0x00100000) >> 9) | + ((in & 0x00080000) >> 7) | + ((in & 0x00040000) >> 5) | + ((in & 0x00020000) >> 3) | + ((in & 0x00010000) >> 1) | + ((in & 0x00008000) << 1) | + ((in & 0x00004000) << 3) | + ((in & 0x00002000) << 5) | + ((in & 0x00001000) << 7) | + ((in & 0x00000800) << 9) | + ((in & 0x00000400) << 11) | + ((in & 0x00000200) << 13) | + ((in & 0x00000100) << 15) | + ((in & 0x00000080) << 17) | + ((in & 0x00000040) << 19) | + ((in & 0x00000020) << 21) | + ((in & 0x00000010) << 23) | + ((in & 0x00000008) << 25) | + ((in & 0x00000004) << 27) | + ((in & 0x00000002) << 29) | ((in & 0x00000001) << 31); +#endif /* ANI_LITTLE_BIT_ENDIAN */ +} + +inline static void __print_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pWmm) +{ + lim_log(pMac, LOG1, FL("WMM Parameters Received: \n")); + lim_log(pMac, LOG1, + FL + ("BE: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d \n"), + pWmm->acbe_aifsn, pWmm->acbe_acm, pWmm->acbe_aci, + pWmm->acbe_acwmin, pWmm->acbe_acwmax, pWmm->acbe_txoplimit); + + lim_log(pMac, LOG1, + FL + ("BK: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d \n"), + pWmm->acbk_aifsn, pWmm->acbk_acm, pWmm->acbk_aci, + pWmm->acbk_acwmin, pWmm->acbk_acwmax, pWmm->acbk_txoplimit); + + lim_log(pMac, LOG1, + FL + ("VI: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d \n"), + pWmm->acvi_aifsn, pWmm->acvi_acm, pWmm->acvi_aci, + pWmm->acvi_acwmin, pWmm->acvi_acwmax, pWmm->acvi_txoplimit); + + lim_log(pMac, LOG1, + FL + ("VO: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d \n"), + pWmm->acvo_aifsn, pWmm->acvo_acm, pWmm->acvo_aci, + pWmm->acvo_acwmin, pWmm->acvo_acwmax, pWmm->acvo_txoplimit); + + return; +} + +/* ////////////////////////////////////////////////////////////////////// */ +/* Functions for populating "dot11f" style IEs */ + +/* return: >= 0, the starting location of the IE in rsnIEdata inside tSirRSNie */ +/* < 0, cannot find */ +int find_ie_location(tpAniSirGlobal pMac, tpSirRSNie pRsnIe, uint8_t EID) +{ + int idx, ieLen, bytesLeft; + int ret_val = -1; + + /* Here's what's going on: 'rsnIe' looks like this: */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* other code records both the WPA & RSN IEs (including their EIDs & */ + /* lengths) into the array 'rsnIEdata'. We may have: */ + + /* With WAPI support, there may be 3 IEs here */ + /* It can be only WPA IE, or only RSN IE or only WAPI IE */ + /* Or two or all three of them with no particular ordering */ + + /* The if/then/else statements that follow are here to figure out */ + /* whether we have the WPA IE, and where it is if we *do* have it. */ + + /* Save the first IE length */ + ieLen = pRsnIe->rsnIEdata[1] + 2; + idx = 0; + bytesLeft = pRsnIe->length; + + while (1) { + if (EID == pRsnIe->rsnIEdata[idx]) { + /* Found it */ + return (idx); + } else if (EID != pRsnIe->rsnIEdata[idx] && + /* & if no more IE, */ + bytesLeft <= (uint16_t) (ieLen)) { + dot11f_log(pMac, LOG3, + FL("No IE (%d) in find_ie_location.\n"), EID); + return ret_val; + } + bytesLeft -= ieLen; + ieLen = pRsnIe->rsnIEdata[idx + 1] + 2; + idx += ieLen; + } + + return ret_val; +} + +tSirRetStatus +populate_dot11f_capabilities(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry) +{ + uint16_t cfg; + tSirRetStatus nSirStatus; + + nSirStatus = cfg_get_capability_info(pMac, &cfg, psessionEntry); + if (eSIR_SUCCESS != nSirStatus) { + dot11f_log(pMac, LOGP, FL("Failed to retrieve the Capabilities b" + "itfield from CFG (%d).\n"), + nSirStatus); + return nSirStatus; + } + + swap_bit_field16(cfg, (uint16_t *) pDot11f); + + return eSIR_SUCCESS; +} /* End populate_dot11f_capabilities. */ + +/** + * populate_dot_11_f_ext_chann_switch_ann() - Function to populate ECS + * @mac_ptr: Pointer to PMAC structure + * @dot_11_ptr: ECS element + * @session_entry: PE session entry + * + * This function is used to populate the extended channel switch element + * + * Return: None + */ +void populate_dot_11_f_ext_chann_switch_ann(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry) +{ + dot_11_ptr->switch_mode = session_entry->gLimChannelSwitch.switchMode; + dot_11_ptr->new_reg_class = cds_regdm_get_opclass_from_channel( + mac_ptr->scan.countryCodeCurrent, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.ch_width); + dot_11_ptr->new_channel = + session_entry->gLimChannelSwitch.primaryChannel; + dot_11_ptr->switch_count = + session_entry->gLimChannelSwitch.switchCount; + dot_11_ptr->present = 1; +} + +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->switchMode = psessionEntry->gLimChannelSwitch.switchMode; + pDot11f->newChannel = psessionEntry->gLimChannelSwitch.primaryChannel; + pDot11f->switchCount = + (uint8_t) psessionEntry->gLimChannelSwitch.switchCount; + + pDot11f->present = 1; +} + +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry) +{ + /* + * The new country subelement is present only when + * 1. AP performs Extended Channel switching to new country. + * 2. New Operating Class table or a changed set of operating + * classes relative to the contents of the country element sent + * in the beacons. + * + * In the current scenario Channel Switch wrapper IE is included + * when we a radar is found and the AP does a channel change in + * the same regulatory domain(No country change or Operating class + * table). So, we do not need to include the New Country IE. + * + * Transmit Power Envlope Subelement is optional + * in Channel Switch Wrapper IE. So, not setting + * the TPE subelement. We include only WiderBWChanSwitchAnn. + */ + pDot11f->present = 1; + + /* + * Add the Wide Channel Bandwidth Sublement. + */ + pDot11f->WiderBWChanSwitchAnn.newChanWidth = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; + pDot11f->WiderBWChanSwitchAnn.present = 1; + +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession pe_session) +{ + if (!pe_session->sap_advertise_avoid_ch_ie) + return; + + dot11f->present = true; + dot11f->type = QCOM_VENDOR_IE_MCC_AVOID_CH; + dot11f->channel = pe_session->currentOperChannel; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef WLAN_FEATURE_11AC +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + pDot11f->newChanWidth = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; +} +#endif + +tSirRetStatus +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry) +{ + uint32_t len, maxlen, codelen; + uint16_t item; + tSirRetStatus nSirStatus; + tSirRFBand rfBand; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + + if (psessionEntry->lim11dEnabled) { + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (rfBand == SIR_BAND_5_GHZ) { + item = WNI_CFG_MAX_TX_POWER_5; + maxlen = WNI_CFG_MAX_TX_POWER_5_LEN; + } else { + item = WNI_CFG_MAX_TX_POWER_2_4; + maxlen = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } + + CFG_GET_STR(nSirStatus, pMac, item, temp, len, maxlen); + + if (3 > len) { + /* no limit on tx power, cannot include the IE because at least */ + /* one (channel,num,tx power) must be present */ + return eSIR_SUCCESS; + } + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_COUNTRY_CODE, + code, codelen, 3); + + cdf_mem_copy(pDot11f->country, code, codelen); + + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) { + dot11f_log(pMac, LOGE, + FL("len:%d is out of bounds, resetting.\n"), + len); + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + } + + pDot11f->num_triplets = (uint8_t) (len / 3); + cdf_mem_copy((uint8_t *) pDot11f->triplets, temp, len); + + pDot11f->present = 1; + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_country. */ + +#ifdef QCA_WIFI_3_0_EMU +/** + * populate_dot11f_ds_params() - To populate DS IE params + * mac_ctx: Pointer to global mac context + * dot11f_param: pointer to DS params IE + * channel: channel number + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall sucess + */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal mac_ctx, + tDot11fIEDSParams *dot11f_param, uint8_t channel) +{ + /* .11a/11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = channel; + dot11f_param->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_ds_params. */ +#else +/** + * populate_dot11f_ds_params() - To populate DS IE params + * mac_ctx: Pointer to global mac context + * dot11f_param: pointer to DS params IE + * channel: channel number + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall sucess + */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal mac_ctx, + tDot11fIEDSParams *dot11f_param, uint8_t channel) +{ + if (IS_24G_CH(channel)) { + /* .11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = channel; + dot11f_param->present = 1; + } + + return eSIR_SUCCESS; +} +#endif + +#define SET_AIFSN(aifsn) (((aifsn) < 2) ? 2 : (aifsn)) + +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry) +{ + + if (psessionEntry->limQosEnabled) { + /* change to bitwise operation, after this is fixed in frames. */ + pDot11f->qos = + (uint8_t) (0xf0 & + (psessionEntry->gLimEdcaParamSetCount << 4)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pDot11f->acbe_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pDot11f->acbe_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pDot11f->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pDot11f->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pDot11f->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pDot11f->acbe_txoplimit = + psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pDot11f->acbk_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pDot11f->acbk_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pDot11f->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pDot11f->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pDot11f->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pDot11f->acbk_txoplimit = + psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + pDot11f->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + pDot11f->acvi_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pDot11f->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pDot11f->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pDot11f->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pDot11f->acvi_txoplimit = + psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + pDot11f->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + pDot11f->acvo_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pDot11f->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pDot11f->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pDot11f->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pDot11f->acvo_txoplimit = + psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pDot11f->present = 1; + } + +} /* End PopluateDot11fEDCAParamSet. */ + +tSirRetStatus +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t val; + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (SIR_BAND_2_4_GHZ == rfBand) { + pDot11f->present = 1; + + val = psessionEntry->cfgProtection.fromllb; + if (!val) { + dot11f_log(pMac, LOGE, + FL + ("11B protection not enabled. Not populating ERP IE %d\n"), + val); + return eSIR_SUCCESS; + } + + if (psessionEntry->gLim11bParams.protectionEnabled) { + pDot11f->non_erp_present = 1; + pDot11f->use_prot = 1; + } + + if (psessionEntry->gLimOlbcParams.protectionEnabled) { + /* FIXME_PROTECTION: we should be setting non_erp present also. */ + /* check the test plan first. */ + pDot11f->use_prot = 1; + } + + if ((psessionEntry->gLimNoShortParams.numNonShortPreambleSta) + || !psessionEntry->beaconParams.fShortPreamble) { + pDot11f->barker_preamble = 1; + + } + /* if protection always flag is set, advertise protection enabled */ + /* regardless of legacy stations presence */ + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_11G_PROTECTION_ALWAYS, + val); + + if (val) { + pDot11f->use_prot = 1; + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_erp_info. */ + +tSirRetStatus +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t nRates = 0; + uint8_t rates[WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN]; + + /* Use the ext rates present in session entry whenever nChannelNum is set to OPERATIONAL + else use the ext supported rate set from CFG, which is fixed and does not change dynamically and is used for + sending mgmt frames (lile probe req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { + if (psessionEntry != NULL) { + nRates = psessionEntry->extRateSet.numRates; + cdf_mem_copy(rates, psessionEntry->extRateSet.rate, + nRates); + } else { + dot11f_log(pMac, LOGE, + FL("no session context exists while" + " populating Operational Rate Set\n")); + } + } else if (HIGHEST_24GHZ_CHANNEL_NUM >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, rates, + nRates, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN); + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + cdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ext_supp_rates. */ + +tSirRetStatus +populate_dot11f_ext_supp_rates1(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f) +{ + uint32_t nRates; + tSirRetStatus nSirStatus; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + if (14 < nChannelNum) { + pDot11f->present = 0; + return eSIR_SUCCESS; + } + /* N.B. I have *no* idea why we're calling 'wlan_cfg_get_str' with an argument */ + /* of WNI_CFG_SUPPORTED_RATES_11A here, but that's what was done */ + /* previously & I'm afraid to change it! */ + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + cdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; +} /* populate_dot11f_ext_supp_rates1. */ + +tSirRetStatus +populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t nCfgValue8; + tSirRetStatus nSirStatus; + tSirMacHTParametersInfo *pHTParametersInfo; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* All sessionized entries will need the check below */ + if (psessionEntry == NULL) /* Only in case of NO session */ + { + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + pDot11f->advCodingCap = + uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->shortGI20MHz = + uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = + uHTCapabilityInfo.htCapInfo.shortGI40MHz; + } else { + pDot11f->advCodingCap = psessionEntry->htConfig.ht_rx_ldpc; + pDot11f->supportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pDot11f->txSTBC = psessionEntry->htConfig.ht_tx_stbc; + pDot11f->rxSTBC = psessionEntry->htConfig.ht_rx_stbc; + if (psessionEntry->htConfig.ht_sgi) { + pDot11f->shortGI20MHz = + uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = + uHTCapabilityInfo.htCapInfo.shortGI40MHz; + } + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + dot11f_log(pMac, LOG2, + FL + ("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, shortGI20:%d, shortGI40: %d, dsssCck: %d\n"), + pDot11f->supportedChannelWidthSet, pDot11f->mimoPowerSave, + pDot11f->greenField, pDot11f->shortGI20MHz, + pDot11f->shortGI40MHz, pDot11f->dsssCckMode40MHz); + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_AMPDU_PARAMS, nCfgValue); + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + dot11f_log(pMac, LOG2, FL("AMPDU Param: %x\n"), nCfgValue); + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_MCS_SET, + pDot11f->supportedMCSSet, nCfgLen, + SIZE_OF_SUPPORTED_MCS_SET); + + if (psessionEntry) { + if (pMac->lteCoexAntShare + && (IS_24G_CH(psessionEntry->currentOperChannel))) { + if (!(IS_2X2_CHAIN(psessionEntry->chainMask))) { + pDot11f->supportedMCSSet[1] = 0; + if (LIM_IS_STA_ROLE(psessionEntry)) { + pDot11f->mimoPowerSave = + psessionEntry->smpsMode; + } + } + } + if (psessionEntry->nss == 1) + pDot11f->supportedMCSSet[1] = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_EXT_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_TX_BF_CAP, nCfgValue); + + pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_AS_CAP, nCfgValue); + + nCfgValue8 = (uint8_t) nCfgValue; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ht_caps. */ + +#ifdef WLAN_FEATURE_11AC + +void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("maxMPDULen (2): %d\n"), pDot11f->maxMPDULen); + lim_log(pMac, LOG1, FL("supportedChannelWidthSet (2): %d\n"), + pDot11f->supportedChannelWidthSet); + lim_log(pMac, LOG1, FL("ldpcCodingCap (1): %d\n"), + pDot11f->ldpcCodingCap); + lim_log(pMac, LOG1, FL("shortGI80MHz (1): %d\n"), pDot11f->shortGI80MHz); + lim_log(pMac, LOG1, FL("shortGI160and80plus80MHz (1): %d\n"), + pDot11f->shortGI160and80plus80MHz); + lim_log(pMac, LOG1, FL("txSTBC (1): %d\n"), pDot11f->txSTBC); + lim_log(pMac, LOG1, FL("rxSTBC (3): %d\n"), pDot11f->rxSTBC); + lim_log(pMac, LOG1, FL("suBeamFormerCap (1): %d\n"), + pDot11f->suBeamFormerCap); + lim_log(pMac, LOG1, FL("suBeamformeeCap (1): %d\n"), + pDot11f->suBeamformeeCap); + lim_log(pMac, LOG1, FL("csnofBeamformerAntSup (3): %d\n"), + pDot11f->csnofBeamformerAntSup); + lim_log(pMac, LOG1, FL("numSoundingDim (3): %d\n"), + pDot11f->numSoundingDim); + lim_log(pMac, LOG1, FL("muBeamformerCap (1): %d\n"), + pDot11f->muBeamformerCap); + lim_log(pMac, LOG1, FL("muBeamformeeCap (1): %d\n"), + pDot11f->muBeamformeeCap); + lim_log(pMac, LOG1, FL("vhtTXOPPS (1): %d\n"), pDot11f->vhtTXOPPS); + lim_log(pMac, LOG1, FL("htcVHTCap (1): %d\n"), pDot11f->htcVHTCap); + lim_log(pMac, LOG1, FL("maxAMPDULenExp (3): %d\n"), + pDot11f->maxAMPDULenExp); + lim_log(pMac, LOG1, FL("vhtLinkAdaptCap (2): %d\n"), + pDot11f->vhtLinkAdaptCap); + lim_log(pMac, LOG1, FL("rxAntPattern (1): %d\n"), + pDot11f->vhtLinkAdaptCap); + lim_log(pMac, LOG1, FL("txAntPattern (1): %d\n"), + pDot11f->vhtLinkAdaptCap); + lim_log(pMac, LOG1, FL("reserved1 (2): %d\n"), pDot11f->reserved1); + lim_log(pMac, LOG1, FL("rxMCSMap (16): %d\n"), pDot11f->rxMCSMap); + lim_log(pMac, LOG1, FL("rxHighSupDataRate (13): %d\n"), + pDot11f->rxHighSupDataRate); + lim_log(pMac, LOG1, FL("reserve (3): %d\n"), pDot11f->reserved2); + lim_log(pMac, LOG1, FL("txMCSMap (16): %d\n"), pDot11f->txMCSMap); + lim_log(pMac, LOG1, FL("txSupDataRate (13): %d\n"), + pDot11f->txSupDataRate); + lim_log(pMac, LOG1, FL("reserv (3): %d\n"), pDot11f->reserved3); +#endif /* DUMP_MGMT_CNTNTS */ +} + +void lim_log_vht_operation(tpAniSirGlobal pMac, tDot11fIEVHTOperation *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("chanWidth : %d\n"), pDot11f->chanWidth); + lim_log(pMac, LOG1, FL("chanCenterFreqSeg1: %d\n"), + pDot11f->chanCenterFreqSeg1); + lim_log(pMac, LOG1, FL("chanCenterFreqSeg2: %d\n"), + pDot11f->chanCenterFreqSeg2); + lim_log(pMac, LOG1, FL("basicMCSSet: %d\n"), pDot11f->basicMCSSet); +#endif /* DUMP_MGMT_CNTNTS */ +} + +void lim_log_vht_ext_bss_load(tpAniSirGlobal pMac, tDot11fIEVHTExtBssLoad *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("muMIMOCapStaCount : %d\n"), + pDot11f->muMIMOCapStaCount); + lim_log(pMac, LOG1, FL("ssUnderUtil: %d\n"), pDot11f->ssUnderUtil); + lim_log(pMac, LOG1, FL("FortyMHzUtil: %d\n"), pDot11f->FortyMHzUtil); + lim_log(pMac, LOG1, FL("EightyMHzUtil: %d\n"), pDot11f->EightyMHzUtil); + lim_log(pMac, LOG1, FL("OneSixtyMHzUtil: %d\n"), + pDot11f->OneSixtyMHzUtil); +#endif /* DUMP_MGMT_CNTNTS */ +} + +void lim_log_operating_mode(tpAniSirGlobal pMac, tDot11fIEOperatingMode *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("ChanWidth : %d\n"), pDot11f->chanWidth); + lim_log(pMac, LOG1, FL("reserved: %d\n"), pDot11f->reserved); + lim_log(pMac, LOG1, FL("rxNSS: %d\n"), pDot11f->rxNSS); + lim_log(pMac, LOG1, FL("rxNSS Type: %d\n"), pDot11f->rxNSSType); +#endif /* DUMP_MGMT_CNTNTS */ +} + +void lim_log_qos_map_set(tpAniSirGlobal pMac, tSirQosMapSet *pQosMapSet) +{ + uint8_t i; + lim_log(pMac, LOG1, FL("num of dscp exceptions : %d"), + pQosMapSet->num_dscp_exceptions); + for (i = 0; i < pQosMapSet->num_dscp_exceptions; i++) { + lim_log(pMac, LOG1, FL("dscp value: %d"), + pQosMapSet->dscp_exceptions[i][0]); + lim_log(pMac, LOG1, FL("User priority value: %d"), + pQosMapSet->dscp_exceptions[i][1]); + } + for (i = 0; i < 8; i++) { + lim_log(pMac, LOG1, FL("dscp low for up %d: %d"), i, + pQosMapSet->dscp_range[i][0]); + lim_log(pMac, LOG1, FL("dscp high for up %d: %d"), i, + pQosMapSet->dscp_range[i][1]); + } +} + +tSirRetStatus +populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEVHTCaps *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MAX_MPDU_LENGTH, nCfgValue); + pDot11f->maxMPDULen = (nCfgValue & 0x0003); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + nCfgValue); + pDot11f->supportedChannelWidthSet = (nCfgValue & 0x0003); + + nCfgValue = 0; + /* With VHT it suffices if we just examine HT */ + if (psessionEntry) { + if (psessionEntry->htConfig.ht_rx_ldpc) + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_LDPC_CODING_CAP, + nCfgValue); + + pDot11f->ldpcCodingCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + if (psessionEntry->htConfig.ht_sgi) + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SHORT_GI_80MHZ, + nCfgValue); + + pDot11f->shortGI80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + if (psessionEntry->htConfig.ht_sgi) + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + nCfgValue); + + pDot11f->shortGI160and80plus80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + if (psessionEntry->htConfig.ht_tx_stbc) + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TXSTBC, + nCfgValue); + + pDot11f->txSTBC = (nCfgValue & 0x0001); + + nCfgValue = 0; + if (psessionEntry->htConfig.ht_rx_stbc) + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RXSTBC, + nCfgValue); + + pDot11f->rxSTBC = (nCfgValue & 0x0007); + + pDot11f->suBeamformeeCap = psessionEntry->txBFIniFeatureEnabled; + if (psessionEntry->txBFIniFeatureEnabled) { + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->muBeamformeeCap = (nCfgValue & 0x0001); + } else { + pDot11f->muBeamformeeCap = 0; + } + pDot11f->suBeamFormerCap = psessionEntry->enable_su_tx_bformer; + } else { + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_LDPC_CODING_CAP, + nCfgValue); + pDot11f->ldpcCodingCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SHORT_GI_80MHZ, + nCfgValue); + pDot11f->shortGI80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + nCfgValue); + pDot11f->shortGI160and80plus80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TXSTBC, nCfgValue); + pDot11f->txSTBC = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RXSTBC, nCfgValue); + pDot11f->rxSTBC = (nCfgValue & 0x0007); + + pDot11f->suBeamformeeCap = 0; + pDot11f->muBeamformeeCap = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + nCfgValue); + pDot11f->suBeamFormerCap = (nCfgValue & 0x0001); + } + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + nCfgValue); + pDot11f->csnofBeamformerAntSup = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + nCfgValue); + pDot11f->numSoundingDim = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_BEAMFORMER_CAP, nCfgValue); + pDot11f->muBeamformerCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TXOP_PS, nCfgValue); + pDot11f->vhtTXOPPS = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_HTC_VHTC_CAP, nCfgValue); + pDot11f->htcVHTCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, nCfgValue); + pDot11f->maxAMPDULenExp = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_LINK_ADAPTATION_CAP, nCfgValue); + pDot11f->vhtLinkAdaptCap = (nCfgValue & 0x0003); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_ANT_PATTERN, nCfgValue); + pDot11f->rxAntPattern = nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_ANT_PATTERN, nCfgValue); + pDot11f->txAntPattern = nCfgValue; + + pDot11f->reserved1 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_MCS_MAP, nCfgValue); + pDot11f->rxMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->rxHighSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved2 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_MCS_MAP, nCfgValue); + pDot11f->txMCSMap = (nCfgValue & 0x0000FFFF); + if (psessionEntry) { + if (pMac->lteCoexAntShare + && (IS_24G_CH(psessionEntry->currentOperChannel))) { + if (!(IS_2X2_CHAIN(psessionEntry->chainMask))) { + pDot11f->txMCSMap |= DISABLE_NSS2_MCS; + pDot11f->rxMCSMap |= DISABLE_NSS2_MCS; + } + } + if (psessionEntry->nss == 1) { + pDot11f->txMCSMap |= DISABLE_NSS2_MCS; + pDot11f->rxMCSMap |= DISABLE_NSS2_MCS; + } + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->txSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved3 = 0; + + lim_log_vht_cap(pMac, pDot11f); + + return eSIR_SUCCESS; + +} + +tSirRetStatus +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + if (psessionEntry->ch_width > CH_WIDTH_40MHZ) { + pDot11f->chanWidth = psessionEntry->ch_width - 1; + pDot11f->chanCenterFreqSeg1 = + psessionEntry->ch_center_freq_seg0; + if (psessionEntry->ch_width == CH_WIDTH_80P80MHZ) + pDot11f->chanCenterFreqSeg2 = + psessionEntry->ch_center_freq_seg1; + else + pDot11f->chanCenterFreqSeg2 = 0; + } else { + pDot11f->chanWidth = 0; + pDot11f->chanCenterFreqSeg1 = 0; + pDot11f->chanCenterFreqSeg2 = 0; + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_BASIC_MCS_SET, nCfgValue); + pDot11f->basicMCSSet = (uint16_t) nCfgValue; + + lim_log_vht_operation(pMac, pDot11f); + + return eSIR_SUCCESS; + +} + +tSirRetStatus +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + nCfgValue); + pDot11f->muMIMOCapStaCount = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SS_UNDER_UTIL, nCfgValue); + pDot11f->ssUnderUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_40MHZ_UTILIZATION, nCfgValue); + pDot11f->FortyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_80MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_160MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + lim_log_vht_ext_bss_load(pMac, pDot11f); + + return eSIR_SUCCESS; +} + +tSirRetStatus +populate_dot11f_ext_cap(tpAniSirGlobal pMac, + bool isVHTEnabled, tDot11fIEExtCap *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + struct s_ext_cap *p_ext_cap; + + pDot11f->present = 1; + + if (!psessionEntry) { + lim_log(pMac, LOG1, FL("11MC - enabled for non-SAP cases")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else if (psessionEntry->sap_dot11mc) { + lim_log(pMac, LOG1, FL("11MC support enabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + if (eLIM_AP_ROLE != psessionEntry->limSystemRole) { + lim_log(pMac, LOG1, FL("11MC support enabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + lim_log(pMac, LOG1, FL("11MC support disabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MIN_LEN; + } + } + + p_ext_cap = (struct s_ext_cap *)pDot11f->bytes; +#ifdef WLAN_FEATURE_11AC + if (isVHTEnabled == true) + p_ext_cap->oper_mode_notification = 1; +#endif + + if (wlan_cfg_get_int(pMac, WNI_CFG_RTT3_ENABLE, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("could not retrieve RTT3 Variable from DAT File \n")); + return eSIR_FAILURE; + } + + if (val) { /* If set to true then set RTTv3 */ + if (!psessionEntry || LIM_IS_STA_ROLE(psessionEntry)) { + p_ext_cap->fine_time_meas_initiator = + (pMac->fine_time_meas_cap & + FINE_TIME_MEAS_STA_INITIATOR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (pMac->fine_time_meas_cap & + FINE_TIME_MEAS_STA_RESPONDER) ? 1 : 0; + } else if (LIM_IS_AP_ROLE(psessionEntry)) { + p_ext_cap->fine_time_meas_initiator = + (pMac->fine_time_meas_cap & + FINE_TIME_MEAS_SAP_INITIATOR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (pMac->fine_time_meas_cap & + FINE_TIME_MEAS_SAP_RESPONDER) ? 1 : 0; + } + } +#ifdef QCA_HT_2040_COEX + if (pMac->roam.configParam.obssEnabled) + p_ext_cap->bss_coexist_mgmt_support = 1; +#endif + p_ext_cap->ext_chan_switch = 1; + + return eSIR_SUCCESS; +} + +tSirRetStatus +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + + pDot11f->chanWidth = psessionEntry->gLimOperatingMode.chanWidth; + pDot11f->rxNSS = psessionEntry->gLimOperatingMode.rxNSS; + pDot11f->rxNSSType = psessionEntry->gLimOperatingMode.rxNSSType; + + return eSIR_SUCCESS; +} + +#endif +tSirRetStatus +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t htInfoField1; + uint16_t htInfoField2; + tSirRetStatus nSirStatus; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTInfoField2 *pHTInfoField2; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField3 infoField3; + } uHTInfoField; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField2 infoField2; + } uHTInfoField2 = { + 0 + }; + +#if 0 + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_CURRENT_CHANNEL, nCfgValue); +#endif /* TO SUPPORT BT-AMP */ + + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOG1, + FL + ("Invalid session entry in populate_dot11f_ht_info()\n")); + ) + return eSIR_FAILURE; + } + + pDot11f->primaryChannel = psessionEntry->currentOperChannel; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD1, nCfgValue); + + htInfoField1 = (uint8_t) nCfgValue; + + pHTInfoField1 = (tSirMacHTInfoField1 *) &htInfoField1; + pHTInfoField1->rifsMode = psessionEntry->beaconParams.fRIFSMode; + pHTInfoField1->serviceIntervalGranularity = + pMac->lim.gHTServiceIntervalGranularity; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOG1, + FL + ("Keep the value retrieved from cfg for secondary channel offset and recommended Tx Width set\n")); + ) + } else { + pHTInfoField1->secondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pHTInfoField1->recommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + } + + if ((psessionEntry) && LIM_IS_AP_ROLE(psessionEntry)) { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + uHTInfoField2.nCfgValue16 = nCfgValue & 0xFFFF; /* this is added for fixing CRs on MDM9K platform - 257951, 259577 */ + + uHTInfoField2.infoField2.opMode = psessionEntry->htOperMode; + uHTInfoField2.infoField2.nonGFDevicesPresent = + psessionEntry->beaconParams.llnNonGFCoexist; + uHTInfoField2.infoField2.obssNonHTStaPresent = psessionEntry->beaconParams.gHTObssMode; /*added for Obss */ + + uHTInfoField2.infoField2.reserved = 0; + + } else { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + htInfoField2 = (uint16_t) nCfgValue; + + pHTInfoField2 = (tSirMacHTInfoField2 *) &htInfoField2; + pHTInfoField2->opMode = pMac->lim.gHTOperMode; + pHTInfoField2->nonGFDevicesPresent = + pMac->lim.gHTNonGFDevicesPresent; + pHTInfoField2->obssNonHTStaPresent = pMac->lim.gHTObssMode; /*added for Obss */ + + pHTInfoField2->reserved = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD3, nCfgValue); + + uHTInfoField.nCfgValue16 = nCfgValue & 0xFFFF; + + uHTInfoField.infoField3.basicSTBCMCS = pMac->lim.gHTSTBCBasicMCS; + uHTInfoField.infoField3.dualCTSProtection = + pMac->lim.gHTDualCTSProtection; + uHTInfoField.infoField3.secondaryBeacon = pMac->lim.gHTSecondaryBeacon; + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + uHTInfoField.infoField3.pcoActive = pMac->lim.gHTPCOActive; + uHTInfoField.infoField3.pcoPhase = pMac->lim.gHTPCOPhase; + uHTInfoField.infoField3.reserved = 0; + + pDot11f->secondaryChannelOffset = pHTInfoField1->secondaryChannelOffset; + pDot11f->recommendedTxWidthSet = pHTInfoField1->recommendedTxWidthSet; + pDot11f->rifsMode = pHTInfoField1->rifsMode; + pDot11f->controlledAccessOnly = pHTInfoField1->controlledAccessOnly; + pDot11f->serviceIntervalGranularity = + pHTInfoField1->serviceIntervalGranularity; + + pDot11f->opMode = uHTInfoField2.infoField2.opMode; + pDot11f->nonGFDevicesPresent = + uHTInfoField2.infoField2.nonGFDevicesPresent; + pDot11f->obssNonHTStaPresent = + uHTInfoField2.infoField2.obssNonHTStaPresent; + pDot11f->reserved = uHTInfoField2.infoField2.reserved; + + pDot11f->basicSTBCMCS = uHTInfoField.infoField3.basicSTBCMCS; + pDot11f->dualCTSProtection = uHTInfoField.infoField3.dualCTSProtection; + pDot11f->secondaryBeacon = uHTInfoField.infoField3.secondaryBeacon; + pDot11f->lsigTXOPProtectionFullSupport = + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport; + pDot11f->pcoActive = uHTInfoField.infoField3.pcoActive; + pDot11f->pcoPhase = uHTInfoField.infoField3.pcoPhase; + pDot11f->reserved2 = uHTInfoField.infoField3.reserved; + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_BASIC_MCS_SET, + pDot11f->basicMCSSet, nCfgLen, SIZE_OF_BASIC_MCS_SET); + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ht_info. */ + +void +populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + &val) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve IBSS ATIM WIN size")); + ) + } + pDot11f->present = 1; + /* ATIM duration is always set to 0 */ + pDot11f->atim = val; + } + +} /* End populate_dot11f_ibss_params. */ + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_BASIC_MEASUREMENT_TYPE; + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End PopulatedDot11fMeasurementReport0. */ +tSirRetStatus +populate_dot11f_measurement_report1(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_CCA_MEASUREMENT_TYPE; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End PopulatedDot11fMeasurementReport1. */ +tSirRetStatus +populate_dot11f_measurement_report2(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_RPI_MEASUREMENT_TYPE; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End PopulatedDot11fMeasurementReport2. */ +#endif + +void +populate_dot11f_power_caps(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry) +{ + if (nAssocType == LIM_REASSOC) { + pCaps->minTxPower = + psessionEntry->pLimReAssocReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimReAssocReq->powerCap.maxTxPower; + } else { + pCaps->minTxPower = + psessionEntry->pLimJoinReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimJoinReq->powerCap.maxTxPower; + + } + + pCaps->present = 1; +} /* End populate_dot11f_power_caps. */ + +tSirRetStatus +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f) +{ + uint32_t cfg; + tSirRetStatus nSirStatus; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, cfg); + + pDot11f->localPowerConstraints = (uint8_t) cfg; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_power_constraints. */ + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, tpPESession psessionEntry) +{ + pDot11f->count = psessionEntry->gLimEdcaParamSetCount; + pDot11f->reserved = 0; + pDot11f->txopreq = 0; + pDot11f->qreq = 0; + pDot11f->qack = 0; + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, + tDot11fIEQOSCapsStation *pDot11f) +{ + uint32_t val = 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("could not retrieve Max SP Length \n")); + ) + + pDot11f->more_data_ack = 0; + pDot11f->max_sp_length = (uint8_t) val; + pDot11f->qack = 0; + + if (pMac->lim.gUapsdEnable) { + pDot11f->acbe_uapsd = + LIM_UAPSD_GET(ACBE, pMac->lim.gUapsdPerAcBitmask); + pDot11f->acbk_uapsd = + LIM_UAPSD_GET(ACBK, pMac->lim.gUapsdPerAcBitmask); + pDot11f->acvi_uapsd = + LIM_UAPSD_GET(ACVI, pMac->lim.gUapsdPerAcBitmask); + pDot11f->acvo_uapsd = + LIM_UAPSD_GET(ACVO, pMac->lim.gUapsdPerAcBitmask); + } + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +tSirRetStatus +populate_dot11f_rsn(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_RSN))) { + status = dot11f_unpack_ie_rsn(pMac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Parse failure in PopulateDot11fRS" + "N (0x%08x).\n"), status); + return eSIR_FAILURE; + } + dot11f_log(pMac, LOG2, + FL("dot11f_unpack_ie_rsn returned 0x%08x in " + "populate_dot11f_rsn.\n"), status); + } + + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_rsn. */ + +tSirRetStatus populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIERSNOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_RSN))) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + cdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_rsn_opaque. */ + +#if defined(FEATURE_WLAN_WAPI) + +tSirRetStatus +populate_dot11f_wapi(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WAPI))) { + status = dot11f_unpack_ie_wapi(pMac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL + ("Parse failure in populate_dot11f_wapi (0x%08x).\n"), + status); + return eSIR_FAILURE; + } + dot11f_log(pMac, LOG2, + FL("dot11f_unpack_ie_rsn returned 0x%08x in " + "populate_dot11f_wapi.\n"), status); + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_wapi. */ + +tSirRetStatus populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WAPI))) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + cdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wapi_opaque. */ + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +void +populate_dot11f_ssid(tpAniSirGlobal pMac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f) +{ + pDot11f->present = 1; + pDot11f->num_ssid = pInternal->length; + if (pInternal->length) { + cdf_mem_copy((uint8_t *) pDot11f->ssid, + (uint8_t *) &pInternal->ssId, pInternal->length); + } +} /* End populate_dot11f_ssid. */ + +tSirRetStatus populate_dot11f_ssid2(tpAniSirGlobal pMac, tDot11fIESSID *pDot11f) +{ + uint32_t nCfg; + tSirRetStatus nSirStatus; + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SSID, pDot11f->ssid, nCfg, 32); + pDot11f->num_ssid = (uint8_t) nCfg; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End populate_dot11f_ssid2. */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f) +{ + pDot11f->aggregation = pSchedule->info.aggregation; + pDot11f->tsid = pSchedule->info.tsid; + pDot11f->direction = pSchedule->info.direction; + pDot11f->reserved = pSchedule->info.rsvd; + pDot11f->service_start_time = pSchedule->svcStartTime; + pDot11f->service_interval = pSchedule->svcInterval; + pDot11f->max_service_dur = pSchedule->maxSvcDuration; + pDot11f->spec_interval = pSchedule->specInterval; + + pDot11f->present = 1; +} /* End populate_dot11f_schedule. */ + +void +populate_dot11f_supp_channels(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry) +{ + uint8_t i; + uint8_t *p; + + if (nAssocType == LIM_REASSOC) { + p = (uint8_t *) psessionEntry->pLimReAssocReq-> + supportedChannels.channelList; + pDot11f->num_bands = + psessionEntry->pLimReAssocReq->supportedChannels.numChnl; + } else { + p = (uint8_t *) psessionEntry->pLimJoinReq->supportedChannels. + channelList; + pDot11f->num_bands = + psessionEntry->pLimJoinReq->supportedChannels.numChnl; + } + for (i = 0U; i < pDot11f->num_bands; ++i, ++p) { + pDot11f->bands[i][0] = *p; + pDot11f->bands[i][1] = 1; + } + + pDot11f->present = 1; + +} /* End populate_dot11f_supp_channels. */ + +tSirRetStatus +populate_dot11f_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t nRates; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + /* Use the operational rates present in session entry whenever nChannelNum is set to OPERATIONAL + else use the supported rate set from CFG, which is fixed and does not change dynamically and is used for + sending mgmt frames (lile probe req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { +#if 0 + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_OPERATIONAL_RATE_SET, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); +#endif /* TO SUPPORT BT-AMP */ + if (psessionEntry != NULL) { + nRates = psessionEntry->rateSet.numRates; + cdf_mem_copy(rates, psessionEntry->rateSet.rate, + nRates); + } else { + dot11f_log(pMac, LOGE, + FL + ("no session context exists while populating Operational Rate Set\n")); + nRates = 0; + } + } else if (14 >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11B, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } else { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + cdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_supp_rates. */ + +/** + * populate_dot11f_rates_tdls() - populate supported rates and + * extended supported rates IE. + * @p_mac gloabl - header. + * @p_supp_rates - pointer to supported rates IE + * @p_ext_supp_rates - pointer to extended supported rates IE + * + * This function populates the supported rates and extended supported + * rates IE based in the STA capability. If the number of rates + * supported is less than MAX_NUM_SUPPORTED_RATES, only supported rates + * IE is populated. + * + * Return: tSirRetStatus eSIR_SUCCESS on Success and eSIR_FAILURE + * on failure. + */ + +tSirRetStatus +populate_dot11f_rates_tdls(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates) +{ + tSirMacRateSet temp_rateset; + tSirMacRateSet temp_rateset2; + uint32_t val, i; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(p_mac, WNI_CFG_DOT11_MODE, &self_dot11mode); + + /** + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only + */ + if ((self_dot11mode == WNI_CFG_DOT11_MODE_ALL) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11B) ) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *)&temp_rateset.rate, &val); + temp_rateset.numRates = (uint8_t) val; + } + else { + temp_rateset.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_dot11mode)) { + val = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *)&temp_rateset2.rate, &val); + temp_rateset2.numRates = (uint8_t) val; + } else { + temp_rateset2.numRates = 0; + } + + if ((temp_rateset.numRates + temp_rateset2.numRates) > + SIR_MAC_MAX_NUMBER_OF_RATES) { + lim_log(p_mac, LOGP, FL("more than %d rates in CFG"), + SIR_MAC_MAX_NUMBER_OF_RATES); + return eSIR_FAILURE; + } + + /** + * copy all rates in temp_rateset, + * there are SIR_MAC_MAX_NUMBER_OF_RATES rates max + */ + for (i = 0; i < temp_rateset2.numRates; i++) + temp_rateset.rate[i + temp_rateset.numRates] = + temp_rateset2.rate[i]; + + temp_rateset.numRates += temp_rateset2.numRates; + + if (temp_rateset.numRates <= MAX_NUM_SUPPORTED_RATES) { + p_supp_rates->num_rates = temp_rateset.numRates; + cdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + } else { /* Populate extended capability as well */ + p_supp_rates->num_rates = MAX_NUM_SUPPORTED_RATES; + cdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + + p_ext_supp_rates->num_rates = temp_rateset.numRates - + MAX_NUM_SUPPORTED_RATES; + cdf_mem_copy(p_ext_supp_rates->rates, + (uint8_t *)temp_rateset.rate + + MAX_NUM_SUPPORTED_RATES, + p_ext_supp_rates->num_rates); + p_ext_supp_rates->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_rates_tdls */ + + +tSirRetStatus +populate_dot11f_tpc_report(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, tpPESession psessionEntry) +{ + uint16_t staid, txPower; + tSirRetStatus nSirStatus; + + nSirStatus = lim_get_mgmt_staid(pMac, &staid, psessionEntry); + if (eSIR_SUCCESS != nSirStatus) { + dot11f_log(pMac, LOG1, FL("Failed to get the STAID in Populat" + "eDot11fTPCReport; lim_get_mgmt_staid " + "returned status %d.\n"), nSirStatus); + return eSIR_FAILURE; + } + /* FramesToDo: This function was "misplaced" in the move to Gen4_TVM... */ + /* txPower = halGetRateToPwrValue( pMac, staid, pMac->lim.gLimCurrentChannelId, isBeacon ); */ + txPower = 0; + pDot11f->tx_power = (uint8_t) txPower; + pDot11f->link_margin = 0; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_tpc_report. */ + +void populate_dot11f_ts_info(tSirMacTSInfo *pInfo, tDot11fFfTSInfo *pDot11f) +{ + pDot11f->traffic_type = pInfo->traffic.trafficType; + pDot11f->tsid = pInfo->traffic.tsid; + pDot11f->direction = pInfo->traffic.direction; + pDot11f->access_policy = pInfo->traffic.accessPolicy; + pDot11f->aggregation = pInfo->traffic.aggregation; + pDot11f->psb = pInfo->traffic.psb; + pDot11f->user_priority = pInfo->traffic.userPrio; + pDot11f->tsinfo_ack_pol = pInfo->traffic.ackPolicy; + pDot11f->schedule = pInfo->schedule.schedule; +} /* End PopulatedDot11fTSInfo. */ + +void populate_dot11f_wmm(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry) +{ + if (psessionEntry->limWmeEnabled) { + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + /* if ( ! sirIsPropCapabilityEnabled( pMac, SIR_MAC_PROP_CAPABILITY_WME ) ) */ + { + populate_dot11f_wmm_info_ap(pMac, pInfo, + psessionEntry); + } + } else { + { + populate_dot11f_wmm_params(pMac, pParams, + psessionEntry); + } + + if (psessionEntry->limWsmEnabled) { + populate_dot11f_wmm_caps(pCaps); + } + } + } +} /* End populate_dot11f_wmm. */ + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps) +{ + pCaps->version = SIR_MAC_OUI_VERSION_1; + pCaps->qack = 0; + pCaps->queue_request = 1; + pCaps->txop_request = 0; + pCaps->more_ack = 0; + pCaps->present = 1; +} /* End PopulateDot11fWmmCaps. */ + +#ifdef FEATURE_WLAN_ESE +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry) +{ + uint8_t numTspecs = 0, idx; + tTspecInfo *pTspec = NULL; + + numTspecs = psessionEntry->pLimReAssocReq->eseTspecInfo.numTspecs; + pTspec = &psessionEntry->pLimReAssocReq->eseTspecInfo.tspec[0]; + pReassoc->num_WMMTSPEC = numTspecs; + if (numTspecs) { + for (idx = 0; idx < numTspecs; idx++) { + populate_dot11f_wmmtspec(&pTspec->tspec, + &pReassoc->WMMTSPEC[idx]); + pTspec->tspec.mediumTime = 0; + pTspec++; + } + } +} +#endif + +void populate_dot11f_wmm_info_ap(tpAniSirGlobal pMac, tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry) +{ + pInfo->version = SIR_MAC_OUI_VERSION_1; + + /* WMM Specification 3.1.3, 3.2.3 + * An IBSS staion shall always use its default WMM parameters. + */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + pInfo->param_set_count = 0; + pInfo->uapsd = 0; + } else { + pInfo->param_set_count = + (0xf & psessionEntry->gLimEdcaParamSetCount); + if (LIM_IS_AP_ROLE(psessionEntry)) { + pInfo->uapsd = (0x1 & psessionEntry->apUapsdEnable); + } else + pInfo->uapsd = (0x1 & pMac->lim.gUapsdEnable); + } + pInfo->present = 1; +} + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo) +{ + uint32_t val = 0; + + pInfo->version = SIR_MAC_OUI_VERSION_1; + pInfo->acvo_uapsd = + LIM_UAPSD_GET(ACVO, psessionEntry->gUapsdPerAcBitmask); + pInfo->acvi_uapsd = + LIM_UAPSD_GET(ACVI, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbk_uapsd = + LIM_UAPSD_GET(ACBK, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbe_uapsd = + LIM_UAPSD_GET(ACBE, psessionEntry->gUapsdPerAcBitmask); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("could not retrieve Max SP Length \n")); + ) + + pInfo->max_sp_length = (uint8_t) val; + pInfo->present = 1; +} + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry) +{ + pParams->version = SIR_MAC_OUI_VERSION_1; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->qosInfo = + (psessionEntry-> + apUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + else + pParams->qosInfo = + (pMac->lim. + gUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pParams->acbe_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pParams->acbe_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pParams->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pParams->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pParams->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pParams->acbe_txoplimit = psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pParams->acbk_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pParams->acbk_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pParams->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pParams->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pParams->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pParams->acbk_txoplimit = psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvi_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[2].aci.aifsn); + else + pParams->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + + pParams->acvi_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pParams->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pParams->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pParams->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pParams->acvi_txoplimit = psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvo_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[3].aci.aifsn); + else + pParams->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + + pParams->acvo_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pParams->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pParams->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pParams->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pParams->acvo_txoplimit = psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pParams->present = 1; + +} /* End populate_dot11f_wmm_params. */ + +void populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f) +{ + pDot11f->version = 1; + pDot11f->aggregation = pSchedule->info.aggregation; + pDot11f->tsid = pSchedule->info.tsid; + pDot11f->direction = pSchedule->info.direction; + pDot11f->reserved = pSchedule->info.rsvd; + pDot11f->service_start_time = pSchedule->svcStartTime; + pDot11f->service_interval = pSchedule->svcInterval; + pDot11f->max_service_dur = pSchedule->maxSvcDuration; + pDot11f->spec_interval = pSchedule->specInterval; + + pDot11f->present = 1; +} /* End populate_dot11f_wmm_schedule. */ + +tSirRetStatus +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WPA))) { + status = dot11f_unpack_ie_wpa(pMac, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, length, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4, /* OUI */ + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Parse failure in PopulateDot11fWP" + "A (0x%08x).\n"), status); + return eSIR_FAILURE; + } + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_wpa. */ + +tSirRetStatus populate_dot11f_wpa_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWPAOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + if (0 <= (idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WPA))) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1] - 4; + cdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, len, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4); /* OUI */ + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wpa_opaque. */ + +/* ////////////////////////////////////////////////////////////////////// */ + +tSirRetStatus +sir_convert_probe_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirProbeReq pProbeReq) +{ + uint32_t status; + tDot11fProbeRequest pr; + + /* Ok, zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pProbeReq, sizeof(tSirProbeReq), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_request(pMac, pFrame, nFrame, &pr); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse a Probe Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Probe Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fProbeRequestto' a 'tSirProbeReq'... */ + if (!pr.SSID.present) { + PELOGW(lim_log + (pMac, LOGW, FL("Mandatory IE SSID not present!\n")); + ) + } else { + pProbeReq->ssidPresent = 1; + convert_ssid(pMac, &pProbeReq->ssId, &pr.SSID); + } + + if (!pr.SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + return eSIR_FAILURE; + } else { + pProbeReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeReq->supportedRates, + &pr.SuppRates); + } + + if (pr.ExtSuppRates.present) { + pProbeReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pProbeReq->extendedRates, + &pr.ExtSuppRates); + } + + if (pr.HTCaps.present) { + cdf_mem_copy(&pProbeReq->HTCaps, &pr.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pr.WscProbeReq.present) { + pProbeReq->wscIePresent = 1; + memcpy(&pProbeReq->probeReqWscIeInfo, &pr.WscProbeReq, + sizeof(tDot11fIEWscProbeReq)); + } +#ifdef WLAN_FEATURE_11AC + if (pr.VHTCaps.present) { + cdf_mem_copy(&pProbeReq->VHTCaps, &pr.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } +#endif + + if (pr.P2PProbeReq.present) { + pProbeReq->p2pIePresent = 1; + } + + return eSIR_SUCCESS; + +} /* End sir_convert_probe_req_frame2_struct. */ + +tSirRetStatus sir_convert_probe_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, + tpSirProbeRespBeacon pProbeResp) +{ + uint32_t status; + tDot11fProbeResponse *pr; + + /* Ok, zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pProbeResp, sizeof(tSirProbeRespBeacon), 0); + + pr = cdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (NULL == pr) { + lim_log(pMac, LOGE, FL("Failed to allocate memory\n")); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) pr, sizeof(tDot11fProbeResponse), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_response(pMac, pFrame, nFrame, pr); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse a Probe Response (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + cdf_mem_free(pr); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Probe Response (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fProbeResponse' to a 'tSirProbeRespBeacon'... */ + + /* Timestamp */ + cdf_mem_copy((uint8_t *) pProbeResp->timeStamp, + (uint8_t *) &pr->TimeStamp, sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pProbeResp->beaconInterval = pr->BeaconInterval.interval; + + /* Capabilities */ + pProbeResp->capabilityInfo.ess = pr->Capabilities.ess; + pProbeResp->capabilityInfo.ibss = pr->Capabilities.ibss; + pProbeResp->capabilityInfo.cfPollable = pr->Capabilities.cfPollable; + pProbeResp->capabilityInfo.cfPollReq = pr->Capabilities.cfPollReq; + pProbeResp->capabilityInfo.privacy = pr->Capabilities.privacy; + pProbeResp->capabilityInfo.shortPreamble = + pr->Capabilities.shortPreamble; + pProbeResp->capabilityInfo.pbcc = pr->Capabilities.pbcc; + pProbeResp->capabilityInfo.channelAgility = + pr->Capabilities.channelAgility; + pProbeResp->capabilityInfo.spectrumMgt = pr->Capabilities.spectrumMgt; + pProbeResp->capabilityInfo.qos = pr->Capabilities.qos; + pProbeResp->capabilityInfo.shortSlotTime = + pr->Capabilities.shortSlotTime; + pProbeResp->capabilityInfo.apsd = pr->Capabilities.apsd; + pProbeResp->capabilityInfo.rrm = pr->Capabilities.rrm; + pProbeResp->capabilityInfo.dsssOfdm = pr->Capabilities.dsssOfdm; + pProbeResp->capabilityInfo.delayedBA = pr->Capabilities.delayedBA; + pProbeResp->capabilityInfo.immediateBA = pr->Capabilities.immediateBA; + + if (!pr->SSID.present) { + PELOGW(lim_log + (pMac, LOGW, FL("Mandatory IE SSID not present!\n")); + ) + } else { + pProbeResp->ssidPresent = 1; + convert_ssid(pMac, &pProbeResp->ssId, &pr->SSID); + } + + if (!pr->SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + } else { + pProbeResp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeResp->supportedRates, + &pr->SuppRates); + } + + if (pr->ExtSuppRates.present) { + pProbeResp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pProbeResp->extendedRates, + &pr->ExtSuppRates); + } + + if (pr->CFParams.present) { + pProbeResp->cfPresent = 1; + convert_cf_params(pMac, &pProbeResp->cfParamSet, &pr->CFParams); + } + + if (pr->Country.present) { + pProbeResp->countryInfoPresent = 1; + convert_country(pMac, &pProbeResp->countryInfoParam, + &pr->Country); + } + + if (pr->EDCAParamSet.present) { + pProbeResp->edcaPresent = 1; + convert_edca_param(pMac, &pProbeResp->edcaParams, + &pr->EDCAParamSet); + } + + if (pr->ChanSwitchAnn.present) { + pProbeResp->channelSwitchPresent = 1; + cdf_mem_copy(&pProbeResp->channelSwitchIE, &pr->ChanSwitchAnn, + sizeof(pProbeResp->channelSwitchIE)); + } + + if (pr->ext_chan_switch_ann.present) { + pProbeResp->ext_chan_switch_present = 1; + cdf_mem_copy(&pProbeResp->ext_chan_switch, + &pr->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pr->sec_chan_offset_ele.present) { + pProbeResp->sec_chan_offset_present = 1; + cdf_mem_copy(&pProbeResp->sec_chan_offset, + &pr->sec_chan_offset_ele, + sizeof(pProbeResp->sec_chan_offset)); + } + + if (pr->TPCReport.present) { + pProbeResp->tpcReportPresent = 1; + cdf_mem_copy(&pProbeResp->tpcReport, &pr->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pr->PowerConstraints.present) { + pProbeResp->powerConstraintPresent = 1; + cdf_mem_copy(&pProbeResp->localPowerConstraint, + &pr->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pr->Quiet.present) { + pProbeResp->quietIEPresent = 1; + cdf_mem_copy(&pProbeResp->quietIE, &pr->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pr->HTCaps.present) { + cdf_mem_copy(&pProbeResp->HTCaps, &pr->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pr->HTInfo.present) { + cdf_mem_copy(&pProbeResp->HTInfo, &pr->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pr->DSParams.present) { + pProbeResp->dsParamsPresent = 1; + pProbeResp->channelNumber = pr->DSParams.curr_channel; + } else if (pr->HTInfo.present) { + pProbeResp->channelNumber = pr->HTInfo.primaryChannel; + } + + if (pr->RSNOpaque.present) { + pProbeResp->rsnPresent = 1; + convert_rsn_opaque(pMac, &pProbeResp->rsn, &pr->RSNOpaque); + } + + if (pr->WPA.present) { + pProbeResp->wpaPresent = 1; + convert_wpa(pMac, &pProbeResp->wpa, &pr->WPA); + } + + if (pr->WMMParams.present) { + pProbeResp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pProbeResp->edcaParams, &pr->WMMParams); + PELOG1(lim_log + (pMac, LOG1, + FL("WMM Parameter present in Probe Response Frame!\n")); + __print_wmm_params(pMac, &pr->WMMParams); + ) + } + + if (pr->WMMInfoAp.present) { + pProbeResp->wmeInfoPresent = 1; + PELOG1(lim_log + (pMac, LOG1, + FL + ("WMM Information Element present in Probe Response Frame!\n")); + ) + } + + if (pr->WMMCaps.present) { + pProbeResp->wsmCapablePresent = 1; + } + + if (pr->ERPInfo.present) { + pProbeResp->erpPresent = 1; + convert_erp_info(pMac, &pProbeResp->erpIEInfo, &pr->ERPInfo); + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pr->MobilityDomain.present) { + /* MobilityDomain */ + pProbeResp->mdiePresent = 1; + cdf_mem_copy((uint8_t *) &(pProbeResp->mdie[0]), + (uint8_t *) &(pr->MobilityDomain.MDID), + sizeof(uint16_t)); + pProbeResp->mdie[2] = + ((pr->MobilityDomain.overDSCap << 0) | (pr->MobilityDomain. + resourceReqCap << + 1)); +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG2, FL("mdie=%02x%02x%02x\n"), + (unsigned int)pProbeResp->mdie[0], + (unsigned int)pProbeResp->mdie[1], + (unsigned int)pProbeResp->mdie[2]); +#endif + } +#endif + +#if defined FEATURE_WLAN_ESE + if (pr->ESEVersion.present) + pProbeResp->is_ese_ver_ie_present = 1; + if (pr->QBSSLoad.present) { + cdf_mem_copy(&pProbeResp->QBSSLoad, &pr->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + if (pr->P2PProbeRes.present) { + cdf_mem_copy(&pProbeResp->P2PProbeRes, &pr->P2PProbeRes, + sizeof(tDot11fIEP2PProbeRes)); + } +#ifdef WLAN_FEATURE_11AC + if (pr->VHTCaps.present) { + cdf_mem_copy(&pProbeResp->VHTCaps, &pr->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->VHTOperation.present) { + cdf_mem_copy(&pProbeResp->VHTOperation, &pr->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pr->VHTExtBssLoad.present) { + cdf_mem_copy(&pProbeResp->VHTExtBssLoad, &pr->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } +#endif + pProbeResp->Vendor1IEPresent = pr->Vendor1IE.present; + pProbeResp->Vendor3IEPresent = pr->Vendor3IE.present; + + pProbeResp->vendor2_ie.present = pr->vendor2_ie.present; + if (pr->vendor2_ie.present) { + pProbeResp->vendor2_ie.type = pr->vendor2_ie.type; + pProbeResp->vendor2_ie.sub_type = pr->vendor2_ie.sub_type; + } + if (pr->vendor2_ie.VHTCaps.present) { + cdf_mem_copy(&pProbeResp->vendor2_ie.VHTCaps, + &pr->vendor2_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->vendor2_ie.VHTOperation.present) { + cdf_mem_copy(&pProbeResp->vendor2_ie.VHTOperation, + &pr->vendor2_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + cdf_mem_free(pr); + return eSIR_SUCCESS; + +} /* End sir_convert_probe_frame2_struct. */ + +tSirRetStatus +sir_convert_assoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + tDot11fAssocRequest *ar; + uint32_t status; + + ar = cdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == ar) { + lim_log(pMac, LOGE, FL("Failed to allocate memory\n")); + return eSIR_MEM_ALLOC_FAILED; + } + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAssocReq, sizeof(tSirAssocReq), 0); + cdf_mem_set((uint8_t *) ar, sizeof(tDot11fAssocRequest), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_request(pMac, pFrame, nFrame, ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse an Association Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + cdf_mem_free(ar); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking an Assoication Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as an assoc request */ + pAssocReq->reassocRequest = 0; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar->Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar->Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar->Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar->Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = + ar->Capabilities.shortPreamble; + pAssocReq->capabilityInfo.pbcc = ar->Capabilities.pbcc; + pAssocReq->capabilityInfo.channelAgility = + ar->Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar->Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = + ar->Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar->Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar->Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar->Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar->Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar->ListenInterval.interval; + + /* SSID */ + if (ar->SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(pMac, &pAssocReq->ssId, &ar->SSID); + } + /* Supported Rates */ + if (ar->SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar->SuppRates); + } + /* Extended Supported Rates */ + if (ar->ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar->ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar->QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar->QOSCapsStation); + } + /* WPA */ + if (ar->WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar->WPAOpaque); + } +#ifdef FEATURE_WLAN_WAPI + if (ar->WAPIOpaque.present) { + pAssocReq->wapiPresent = 1; + convert_wapi_opaque(pMac, &pAssocReq->wapi, &ar->WAPIOpaque); + } +#endif + /* RSN */ + if (ar->RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar->RSNOpaque); + } + /* WSC IE */ + if (ar->WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(pMac, &pAssocReq->addIE, &ar->WscIEOpaque); + } + + if (ar->P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar->P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar->WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar->WFDIEOpaque); + } +#endif + + /* Power Capabilities */ + if (ar->PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar->PowerCaps); + } + /* Supported Channels */ + if (ar->SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &pAssocReq->supportedChannels, + &ar->SuppChannels); + } + + if (ar->HTCaps.present) { + cdf_mem_copy(&pAssocReq->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar->WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + cdf_mem_copy(&pAssocReq->WMMInfoStation, &ar->WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar->WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + PELOG2(lim_log + (pMac, LOG2, FL("Received Assoc without SSID IE.\n")); + ) + cdf_mem_free(ar); + return eSIR_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + PELOG2(lim_log + (pMac, LOG2, + FL("Received Assoc without supp rate IE.\n")); + ) + cdf_mem_free(ar); + return eSIR_FAILURE; + } +#ifdef WLAN_FEATURE_11AC + if (ar->VHTCaps.present) { + cdf_mem_copy(&pAssocReq->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOGW, FL("Received Assoc Req with VHT Cap\n")); + lim_log_vht_cap(pMac, &pAssocReq->VHTCaps); + } + if (ar->OperatingMode.present) { + cdf_mem_copy(&pAssocReq->operMode, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + lim_log(pMac, LOGW, + FL("Received Assoc Req with Operating Mode IE\n")); + lim_log_operating_mode(pMac, &pAssocReq->operMode); + } +#endif + if (ar->ExtCap.present) { + struct s_ext_cap *ext_cap; + cdf_mem_copy(&pAssocReq->ExtCap.bytes, &ar->ExtCap.bytes, + ar->ExtCap.num_bytes); + + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + cdf_mem_free(ar); + return eSIR_SUCCESS; + +} /* End sir_convert_assoc_req_frame2_struct. */ + +tSirRetStatus +sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocRsp pAssocRsp) +{ + static tDot11fAssocResponse ar; + uint32_t status; + uint8_t cnt = 0; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAssocRsp, sizeof(tSirAssocRsp), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_response(pMac, pFrame, nFrame, &ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse an Association Response (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking an Association Response (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fAssocResponse' a 'tSirAssocRsp'... */ + + /* Capabilities */ + pAssocRsp->capabilityInfo.ess = ar.Capabilities.ess; + pAssocRsp->capabilityInfo.ibss = ar.Capabilities.ibss; + pAssocRsp->capabilityInfo.cfPollable = ar.Capabilities.cfPollable; + pAssocRsp->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq; + pAssocRsp->capabilityInfo.privacy = ar.Capabilities.privacy; + pAssocRsp->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble; + pAssocRsp->capabilityInfo.pbcc = ar.Capabilities.pbcc; + pAssocRsp->capabilityInfo.channelAgility = + ar.Capabilities.channelAgility; + pAssocRsp->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt; + pAssocRsp->capabilityInfo.qos = ar.Capabilities.qos; + pAssocRsp->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime; + pAssocRsp->capabilityInfo.apsd = ar.Capabilities.apsd; + pAssocRsp->capabilityInfo.rrm = ar.Capabilities.rrm; + pAssocRsp->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm; + pAssocRsp->capabilityInfo.delayedBA = ar.Capabilities.delayedBA; + pAssocRsp->capabilityInfo.immediateBA = ar.Capabilities.immediateBA; + + pAssocRsp->statusCode = ar.Status.status; + pAssocRsp->aid = ar.AID.associd; +#ifdef WLAN_FEATURE_11W + if (ar.TimeoutInterval.present) { + pAssocRsp->TimeoutInterval.present = 1; + pAssocRsp->TimeoutInterval.timeoutType = + ar.TimeoutInterval.timeoutType; + pAssocRsp->TimeoutInterval.timeoutValue = + ar.TimeoutInterval.timeoutValue; + } +#endif + + if (!ar.SuppRates.present) { + pAssocRsp->suppRatesPresent = 0; + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + } else { + pAssocRsp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocRsp->supportedRates, + &ar.SuppRates); + } + + if (ar.ExtSuppRates.present) { + pAssocRsp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocRsp->extendedRates, + &ar.ExtSuppRates); + } + + if (ar.EDCAParamSet.present) { + pAssocRsp->edcaPresent = 1; + convert_edca_param(pMac, &pAssocRsp->edca, &ar.EDCAParamSet); + } + + if (ar.WMMParams.present) { + pAssocRsp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pAssocRsp->edca, &ar.WMMParams); + lim_log(pMac, LOG1, FL("Received Assoc Resp with WMM Param")); + __print_wmm_params(pMac, &ar.WMMParams); + } + + if (ar.HTCaps.present) { + lim_log(pMac, LOG1, FL("Received Assoc Resp with HT Cap")); + cdf_mem_copy(&pAssocRsp->HTCaps, &ar.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar.HTInfo.present) { + lim_log(pMac, LOG1, FL("Received Assoc Resp with HT Info")); + cdf_mem_copy(&pAssocRsp->HTInfo, &ar.HTInfo, + sizeof(tDot11fIEHTInfo)); + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (ar.MobilityDomain.present) { + /* MobilityDomain */ + pAssocRsp->mdiePresent = 1; + cdf_mem_copy((uint8_t *) &(pAssocRsp->mdie[0]), + (uint8_t *) &(ar.MobilityDomain.MDID), + sizeof(uint16_t)); + pAssocRsp->mdie[2] = + ((ar.MobilityDomain.overDSCap << 0) | (ar.MobilityDomain. + resourceReqCap << + 1)); +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("new mdie=%02x%02x%02x"), + (unsigned int)pAssocRsp->mdie[0], + (unsigned int)pAssocRsp->mdie[1], + (unsigned int)pAssocRsp->mdie[2]); +#endif + } + + if (ar.FTInfo.present) { +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + lim_log(pMac, LOG1, FL("FT Info present %d %d %d"), + ar.FTInfo.R0KH_ID.num_PMK_R0_ID, + ar.FTInfo.R0KH_ID.present, ar.FTInfo.R1KH_ID.present); +#endif + pAssocRsp->ftinfoPresent = 1; + cdf_mem_copy(&pAssocRsp->FTInfo, &ar.FTInfo, + sizeof(tDot11fIEFTInfo)); + } +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + if (ar.num_RICDataDesc) { + for (cnt = 0; cnt < ar.num_RICDataDesc; cnt++) { + if (ar.RICDataDesc[cnt].present) { + cdf_mem_copy(&pAssocRsp->RICData[cnt], + &ar.RICDataDesc[cnt], + sizeof(tDot11fIERICDataDesc)); + } + } + pAssocRsp->num_RICData = ar.num_RICDataDesc; + pAssocRsp->ricPresent = true; + } +#endif + +#ifdef FEATURE_WLAN_ESE + if (ar.num_WMMTSPEC) { + pAssocRsp->num_tspecs = ar.num_WMMTSPEC; + for (cnt = 0; cnt < ar.num_WMMTSPEC; cnt++) { + cdf_mem_copy(&pAssocRsp->TSPECInfo[cnt], + &ar.WMMTSPEC[cnt], + (sizeof(tDot11fIEWMMTSPEC) * + ar.num_WMMTSPEC)); + } + pAssocRsp->tspecPresent = true; + } + + if (ar.ESETrafStrmMet.present) { + pAssocRsp->tsmPresent = 1; + cdf_mem_copy(&pAssocRsp->tsmIE.tsid, + &ar.ESETrafStrmMet.tsid, sizeof(tSirMacESETSMIE)); + } +#endif + +#ifdef WLAN_FEATURE_11AC + if (ar.VHTCaps.present) { + cdf_mem_copy(&pAssocRsp->VHTCaps, &ar.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOG1, FL("Received Assoc Response with VHT Cap")); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar.VHTOperation.present) { + cdf_mem_copy(&pAssocRsp->VHTOperation, &ar.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with VHT Operation")); + lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation); + } +#endif + + if (ar.ExtCap.present) { + struct s_ext_cap *ext_cap; + cdf_mem_copy(&pAssocRsp->ExtCap.bytes, &ar.ExtCap.bytes, + ar.ExtCap.num_bytes); + + ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + if (ar.QosMapSet.present) { + pAssocRsp->QosMapSet.present = 1; + convert_qos_mapset_frame(pMac, &pAssocRsp->QosMapSet, + &ar.QosMapSet); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Qos Map Set")); + lim_log_qos_map_set(pMac, &pAssocRsp->QosMapSet); + } + + pAssocRsp->vendor2_ie.present = ar.vendor2_ie.present; + if (ar.vendor2_ie.present) { + pAssocRsp->vendor2_ie.type = ar.vendor2_ie.type; + pAssocRsp->vendor2_ie.sub_type = ar.vendor2_ie.sub_type; + } + + if (ar.vendor2_ie.VHTCaps.present) { + cdf_mem_copy(&pAssocRsp->vendor2_ie.VHTCaps, + &ar.vendor2_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Vendor specific VHT Cap")); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar.vendor2_ie.VHTOperation.present) { + cdf_mem_copy(&pAssocRsp->vendor2_ie.VHTOperation, + &ar.vendor2_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Vendor specific VHT Oper")); + lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation); + } + return eSIR_SUCCESS; + +} /* End sir_convert_assoc_resp_frame2_struct. */ + +tSirRetStatus +sir_convert_reassoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + static tDot11fReAssocRequest ar; + uint32_t status; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAssocReq, sizeof(tSirAssocReq), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_re_assoc_request(pMac, pFrame, nFrame, &ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse a Re-association Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Re-association Request (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fReAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as a re-assoc request */ + pAssocReq->reassocRequest = 1; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar.Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar.Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar.Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar.Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble; + pAssocReq->capabilityInfo.pbcc = ar.Capabilities.pbcc; + pAssocReq->capabilityInfo.channelAgility = + ar.Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar.Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar.Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar.Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar.Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar.Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar.ListenInterval.interval; + + /* SSID */ + if (ar.SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(pMac, &pAssocReq->ssId, &ar.SSID); + } + /* Supported Rates */ + if (ar.SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar.SuppRates); + } + /* Extended Supported Rates */ + if (ar.ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar.ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar.QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar.QOSCapsStation); + } + /* WPA */ + if (ar.WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar.WPAOpaque); + } + /* RSN */ + if (ar.RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar.RSNOpaque); + } + + /* Power Capabilities */ + if (ar.PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar.PowerCaps); + } + /* Supported Channels */ + if (ar.SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &pAssocReq->supportedChannels, + &ar.SuppChannels); + } + + if (ar.HTCaps.present) { + cdf_mem_copy(&pAssocReq->HTCaps, &ar.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar.WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + cdf_mem_copy(&pAssocReq->WMMInfoStation, &ar.WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar.WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + PELOG2(lim_log + (pMac, LOG2, FL("Received Assoc without SSID IE.\n")); + ) + return eSIR_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + PELOG2(lim_log + (pMac, LOG2, + FL("Received Assoc without supp rate IE.\n")); + ) + return eSIR_FAILURE; + } + /* Why no call to 'updateAssocReqFromPropCapability' here, like */ + /* there is in 'sir_convert_assoc_req_frame2_struct'? */ + + /* WSC IE */ + if (ar.WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(pMac, &pAssocReq->addIE, &ar.WscIEOpaque); + } + + if (ar.P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar.P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar.WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar.WFDIEOpaque); + } +#endif + +#ifdef WLAN_FEATURE_11AC + if (ar.VHTCaps.present) { + cdf_mem_copy(&pAssocReq->VHTCaps, &ar.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (ar.OperatingMode.present) { + cdf_mem_copy(&pAssocReq->operMode, &ar.OperatingMode, + sizeof(tDot11fIEOperatingMode)); + lim_log(pMac, LOGW, + FL("Received Assoc Req with Operating Mode IE\n")); + lim_log_operating_mode(pMac, &pAssocReq->operMode); + } +#endif + + if (ar.ExtCap.present) { + struct s_ext_cap *ext_cap; + cdf_mem_copy(&pAssocReq->ExtCap.bytes, &ar.ExtCap.bytes, + ar.ExtCap.num_bytes); + + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + return eSIR_SUCCESS; + +} /* End sir_convert_reassoc_req_frame2_struct. */ + +#if defined(FEATURE_WLAN_ESE_UPLOAD) +tSirRetStatus +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + uint8_t *pPayload, const uint32_t nPayload, + uint8_t **outIeBuf, uint32_t *pOutIeLen) +{ + tDot11fBeaconIEs *pBies = NULL; + uint32_t status = CDF_STATUS_SUCCESS; + tSirRetStatus retStatus = eSIR_SUCCESS; + tSirEseBcnReportMandatoryIe eseBcnReportMandatoryIe; + + /* To store how many bytes are required to be allocated + for Bcn report mandatory Ies */ + uint16_t numBytes = 0, freeBytes = 0; + uint8_t *pos = NULL; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) &eseBcnReportMandatoryIe, + sizeof(eseBcnReportMandatoryIe), 0); + pBies = cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + lim_log(pMac, LOGE, FL("Failed to allocate memory\n")); + return eSIR_MEM_ALLOC_FAILED; + } + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, pPayload, nPayload, pBies); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + cdf_mem_free(pBies); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'eseBcnReportMandatoryIe'... */ + if (!pBies->SSID.present) { + PELOGW(lim_log + (pMac, LOGW, FL("Mandatory IE SSID not present!\n")); + ) + } else { + eseBcnReportMandatoryIe.ssidPresent = 1; + convert_ssid(pMac, &eseBcnReportMandatoryIe.ssId, &pBies->SSID); + /* 1 for EID, 1 for length and length bytes */ + numBytes += 1 + 1 + eseBcnReportMandatoryIe.ssId.length; + } + + if (!pBies->SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + } else { + eseBcnReportMandatoryIe.suppRatesPresent = 1; + convert_supp_rates(pMac, &eseBcnReportMandatoryIe.supportedRates, + &pBies->SuppRates); + numBytes += + 1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates; + } + + if (pBies->FHParamSet.present) { + eseBcnReportMandatoryIe.fhParamPresent = 1; + convert_fh_params(pMac, &eseBcnReportMandatoryIe.fhParamSet, + &pBies->FHParamSet); + numBytes += 1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX; + } + + if (pBies->DSParams.present) { + eseBcnReportMandatoryIe.dsParamsPresent = 1; + eseBcnReportMandatoryIe.dsParamSet.channelNumber = + pBies->DSParams.curr_channel; + numBytes += 1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX; + } + + if (pBies->CFParams.present) { + eseBcnReportMandatoryIe.cfPresent = 1; + convert_cf_params(pMac, &eseBcnReportMandatoryIe.cfParamSet, + &pBies->CFParams); + numBytes += 1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX; + } + + if (pBies->IBSSParams.present) { + eseBcnReportMandatoryIe.ibssParamPresent = 1; + eseBcnReportMandatoryIe.ibssParamSet.atim = + pBies->IBSSParams.atim; + numBytes += 1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX; + } + + if (pBies->TIM.present) { + eseBcnReportMandatoryIe.timPresent = 1; + eseBcnReportMandatoryIe.tim.dtimCount = pBies->TIM.dtim_count; + eseBcnReportMandatoryIe.tim.dtimPeriod = pBies->TIM.dtim_period; + eseBcnReportMandatoryIe.tim.bitmapControl = pBies->TIM.bmpctl; + /* As per the ESE spec, May truncate and report first 4 octets only */ + numBytes += 1 + 1 + SIR_MAC_TIM_EID_MIN; + } + + if (pBies->RRMEnabledCap.present) { + eseBcnReportMandatoryIe.rrmPresent = 1; + cdf_mem_copy(&eseBcnReportMandatoryIe.rmEnabledCapabilities, + &pBies->RRMEnabledCap, + sizeof(tDot11fIERRMEnabledCap)); + numBytes += 1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + } + + *outIeBuf = cdf_mem_malloc(numBytes); + if (NULL == *outIeBuf) { + lim_log(pMac, LOGP, FL("Memory Allocation failure")); + cdf_mem_free(pBies); + return eSIR_MEM_ALLOC_FAILED; + } + pos = *outIeBuf; + *pOutIeLen = numBytes; + freeBytes = numBytes; + + /* Start filling the output Ie with Mandatory IE information */ + /* Fill SSID IE */ + if (eseBcnReportMandatoryIe.ssidPresent) { + if (freeBytes < (1 + 1 + eseBcnReportMandatoryIe.ssId.length)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy SSID")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_SSID_EID; + pos++; + *pos = eseBcnReportMandatoryIe.ssId.length; + pos++; + cdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.ssId.ssId, + eseBcnReportMandatoryIe.ssId.length); + pos += eseBcnReportMandatoryIe.ssId.length; + freeBytes -= (1 + 1 + eseBcnReportMandatoryIe.ssId.length); + } + + /* Fill Supported Rates IE */ + if (eseBcnReportMandatoryIe.suppRatesPresent) { + if (freeBytes < + (1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy Rates IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_RATESET_EID; + pos++; + *pos = eseBcnReportMandatoryIe.supportedRates.numRates; + pos++; + cdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.supportedRates. + rate, + eseBcnReportMandatoryIe.supportedRates.numRates); + pos += eseBcnReportMandatoryIe.supportedRates.numRates; + freeBytes -= + (1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates); + } + + /* Fill FH Parameter set IE */ + if (eseBcnReportMandatoryIe.fhParamPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy FHIE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_FH_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_FH_PARAM_SET_EID_MAX; + pos++; + cdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.fhParamSet, + SIR_MAC_FH_PARAM_SET_EID_MAX); + pos += SIR_MAC_FH_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX); + } + + /* Fill DS Parameter set IE */ + if (eseBcnReportMandatoryIe.dsParamsPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy DS IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_DS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_DS_PARAM_SET_EID_MAX; + pos++; + *pos = eseBcnReportMandatoryIe.dsParamSet.channelNumber; + pos += SIR_MAC_DS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX); + } + + /* Fill CF Parameter set */ + if (eseBcnReportMandatoryIe.cfPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy CF IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_CF_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_CF_PARAM_SET_EID_MAX; + pos++; + cdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.cfParamSet, + SIR_MAC_CF_PARAM_SET_EID_MAX); + pos += SIR_MAC_CF_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX); + } + + /* Fill IBSS Parameter set IE */ + if (eseBcnReportMandatoryIe.ibssParamPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy IBSS IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_IBSS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_IBSS_PARAM_SET_EID_MAX; + pos++; + cdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.ibssParamSet. + atim, SIR_MAC_IBSS_PARAM_SET_EID_MAX); + pos += SIR_MAC_IBSS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX); + } + + /* Fill TIM IE */ + if (eseBcnReportMandatoryIe.timPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_TIM_EID_MIN)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy TIM IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_TIM_EID; + pos++; + *pos = SIR_MAC_TIM_EID_MIN; + pos++; + cdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.tim, + SIR_MAC_TIM_EID_MIN); + pos += SIR_MAC_TIM_EID_MIN; + freeBytes -= (1 + 1 + SIR_MAC_TIM_EID_MIN); + } + + /* Fill RM Capability IE */ + if (eseBcnReportMandatoryIe.rrmPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy RRM IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID; + pos++; + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + pos++; + cdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe. + rmEnabledCapabilities, + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + freeBytes -= (1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + } + + if (freeBytes != 0) { + lim_log(pMac, LOGP, + FL + ("Mismatch in allocation and copying of IE in Bcn Rep")); + retStatus = eSIR_FAILURE; + } + +err_bcnrep: + /* The message counter would not be incremented in case of + * returning failure and hence next time, this function gets + * called, it would be using the same msg ctr for a different + * BSS.So, it is good to clear the memory allocated for a BSS + * that is returning failure.On success, the caller would take + * care of freeing up the memory*/ + if (retStatus == eSIR_FAILURE) { + cdf_mem_free(*outIeBuf); + *outIeBuf = NULL; + } + + cdf_mem_free(pBies); + return retStatus; +} + +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + +tSirRetStatus +sir_parse_beacon_ie(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t nPayload) +{ + tDot11fBeaconIEs *pBies; + uint32_t status; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); + + pBies = cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + lim_log(pMac, LOGE, FL("Failed to allocate memory\n")); + return eSIR_MEM_ALLOC_FAILED; + } + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, pPayload, nPayload, pBies); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + cdf_mem_free(pBies); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'tSirProbeRespBeacon'... */ + if (!pBies->SSID.present) { + PELOGW(lim_log + (pMac, LOGW, FL("Mandatory IE SSID not present!\n")); + ) + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(pMac, &pBeaconStruct->ssId, &pBies->SSID); + } + + if (!pBies->SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBies->SuppRates); + } + + if (pBies->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBies->ExtSuppRates); + } + + if (pBies->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBies->CFParams); + } + + if (pBies->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBies->TIM); + } + + if (pBies->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &pBeaconStruct->countryInfoParam, + &pBies->Country); + } + /* 11h IEs */ + if (pBies->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + cdf_mem_copy(&pBeaconStruct->tpcReport, + &pBies->TPCReport, sizeof(tDot11fIETPCReport)); + } + + if (pBies->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + cdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBies->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } +#ifdef FEATURE_WLAN_ESE + if (pBies->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBies->ESETxmitPower.present) { + pBeaconStruct->eseTxPwr.present = 1; + pBeaconStruct->eseTxPwr.power_limit = + pBies->ESETxmitPower.power_limit; + } + if (pBies->QBSSLoad.present) { + cdf_mem_copy(&pBeaconStruct->QBSSLoad, &pBies->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + + if (pBies->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(pMac, &pBeaconStruct->edcaParams, + &pBies->EDCAParamSet); + } + /* QOS Capabilities: */ + if (pBies->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &pBeaconStruct->qosCapability, + &pBies->QOSCapsAp); + } + + if (pBies->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + cdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBies->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBies->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + cdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBies->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBies->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + cdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBies->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBies->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + cdf_mem_copy(&pBeaconStruct->quietIE, &pBies->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBies->HTCaps.present) { + cdf_mem_copy(&pBeaconStruct->HTCaps, &pBies->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBies->HTInfo.present) { + cdf_mem_copy(&pBeaconStruct->HTInfo, &pBies->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pBies->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBies->DSParams.curr_channel; + } else if (pBies->HTInfo.present) { + pBeaconStruct->channelNumber = pBies->HTInfo.primaryChannel; + } + + if (pBies->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBies->RSN); + } + + if (pBies->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBies->WPA); + } + + if (pBies->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pBeaconStruct->edcaParams, + &pBies->WMMParams); + } + + if (pBies->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + } + + if (pBies->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBies->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(pMac, &pBeaconStruct->erpIEInfo, + &pBies->ERPInfo); + } +#ifdef WLAN_FEATURE_11AC + if (pBies->VHTCaps.present) { + pBeaconStruct->VHTCaps.present = 1; + cdf_mem_copy(&pBeaconStruct->VHTCaps, &pBies->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->VHTOperation.present) { + pBeaconStruct->VHTOperation.present = 1; + cdf_mem_copy(&pBeaconStruct->VHTOperation, &pBies->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBies->VHTExtBssLoad.present) { + pBeaconStruct->VHTExtBssLoad.present = 1; + cdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBies->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBies->OperatingMode.present) { + pBeaconStruct->OperatingMode.present = 1; + cdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBies->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } +#endif + + if (pBies->MobilityDomain.present) { + pBeaconStruct->mdiePresent = 1; + cdf_mem_copy(pBeaconStruct->mdie, &pBies->MobilityDomain.MDID, + SIR_MDIE_SIZE); + } + + pBeaconStruct->Vendor1IEPresent = pBies->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBies->Vendor3IE.present; + pBeaconStruct->vendor2_ie.present = pBies->vendor2_ie.present; + if (pBies->vendor2_ie.present) { + pBeaconStruct->vendor2_ie.type = pBies->vendor2_ie.type; + pBeaconStruct->vendor2_ie.sub_type = pBies->vendor2_ie.sub_type; + } + + if (pBies->vendor2_ie.VHTCaps.present) { + pBeaconStruct->vendor2_ie.VHTCaps.present = 1; + cdf_mem_copy(&pBeaconStruct->vendor2_ie.VHTCaps, + &pBies->vendor2_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->vendor2_ie.VHTOperation.present) { + pBeaconStruct->vendor2_ie.VHTOperation.present = 1; + cdf_mem_copy(&pBeaconStruct->vendor2_ie.VHTOperation, + &pBies->vendor2_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + cdf_mem_free(pBies); + return eSIR_SUCCESS; +} /* End sir_parse_beacon_ie. */ + +tSirRetStatus +sir_convert_beacon_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirProbeRespBeacon pBeaconStruct) +{ + tDot11fBeacon *pBeacon; + uint32_t status, nPayload; + uint8_t *pPayload; + tpSirMacMgmtHdr pHdr; + uint8_t mappedRXCh; + uint8_t rfBand; + + pPayload = WMA_GET_RX_MPDU_DATA(pFrame); + nPayload = WMA_GET_RX_PAYLOAD_LEN(pFrame); + pHdr = WMA_GET_RX_MAC_HEADER(pFrame); + mappedRXCh = WMA_GET_RX_CH(pFrame); + rfBand = WMA_GET_RX_RFBAND(pFrame); + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); + + pBeacon = cdf_mem_malloc(sizeof(tDot11fBeacon)); + if (NULL == pBeacon) { + lim_log(pMac, LOGE, FL("Failed to allocate memory\n")); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_set((uint8_t *) pBeacon, sizeof(tDot11fBeacon), 0); + + /* get the MAC address out of the BD, */ + cdf_mem_copy(pBeaconStruct->bssid, pHdr->sa, 6); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon(pMac, pPayload, nPayload, pBeacon); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + cdf_mem_free(pBeacon); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):\n"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + } + /* & "transliterate" from a 'tDot11fBeacon' to a 'tSirProbeRespBeacon'... */ + /* Timestamp */ + cdf_mem_copy((uint8_t *) pBeaconStruct->timeStamp, + (uint8_t *) &pBeacon->TimeStamp, + sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pBeaconStruct->beaconInterval = pBeacon->BeaconInterval.interval; + + /* Capabilities */ + pBeaconStruct->capabilityInfo.ess = pBeacon->Capabilities.ess; + pBeaconStruct->capabilityInfo.ibss = pBeacon->Capabilities.ibss; + pBeaconStruct->capabilityInfo.cfPollable = + pBeacon->Capabilities.cfPollable; + pBeaconStruct->capabilityInfo.cfPollReq = + pBeacon->Capabilities.cfPollReq; + pBeaconStruct->capabilityInfo.privacy = pBeacon->Capabilities.privacy; + pBeaconStruct->capabilityInfo.shortPreamble = + pBeacon->Capabilities.shortPreamble; + pBeaconStruct->capabilityInfo.pbcc = pBeacon->Capabilities.pbcc; + pBeaconStruct->capabilityInfo.channelAgility = + pBeacon->Capabilities.channelAgility; + pBeaconStruct->capabilityInfo.spectrumMgt = + pBeacon->Capabilities.spectrumMgt; + pBeaconStruct->capabilityInfo.qos = pBeacon->Capabilities.qos; + pBeaconStruct->capabilityInfo.shortSlotTime = + pBeacon->Capabilities.shortSlotTime; + pBeaconStruct->capabilityInfo.apsd = pBeacon->Capabilities.apsd; + pBeaconStruct->capabilityInfo.rrm = pBeacon->Capabilities.rrm; + pBeaconStruct->capabilityInfo.dsssOfdm = pBeacon->Capabilities.dsssOfdm; + pBeaconStruct->capabilityInfo.delayedBA = + pBeacon->Capabilities.delayedBA; + pBeaconStruct->capabilityInfo.immediateBA = + pBeacon->Capabilities.immediateBA; + + if (!pBeacon->SSID.present) { + PELOGW(lim_log + (pMac, LOGW, FL("Mandatory IE SSID not present!\n")); + ) + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(pMac, &pBeaconStruct->ssId, &pBeacon->SSID); + } + + if (!pBeacon->SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!\n")); + ) + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBeacon->SuppRates); + } + + if (pBeacon->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBeacon->ExtSuppRates); + } + + if (pBeacon->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBeacon->CFParams); + } + + if (pBeacon->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBeacon->TIM); + } + + if (pBeacon->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &pBeaconStruct->countryInfoParam, + &pBeacon->Country); + } + /* QOS Capabilities: */ + if (pBeacon->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &pBeaconStruct->qosCapability, + &pBeacon->QOSCapsAp); + } + + if (pBeacon->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(pMac, &pBeaconStruct->edcaParams, + &pBeacon->EDCAParamSet); + } + + if (pBeacon->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + cdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBeacon->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBeacon->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + cdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBeacon->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBeacon->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + cdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBeacon->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBeacon->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + cdf_mem_copy(&pBeaconStruct->tpcReport, &pBeacon->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pBeacon->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + cdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBeacon->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pBeacon->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + cdf_mem_copy(&pBeaconStruct->quietIE, &pBeacon->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBeacon->HTCaps.present) { + cdf_mem_copy(&pBeaconStruct->HTCaps, &pBeacon->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBeacon->HTInfo.present) { + cdf_mem_copy(&pBeaconStruct->HTInfo, &pBeacon->HTInfo, + sizeof(tDot11fIEHTInfo)); + + } + + if (pBeacon->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBeacon->DSParams.curr_channel; + } else if (pBeacon->HTInfo.present) { + pBeaconStruct->channelNumber = pBeacon->HTInfo.primaryChannel; + } else { + pBeaconStruct->channelNumber = mappedRXCh; + lim_log(pMac, LOG1, + FL("Channel info is not present in Beacon")); + } + + if (pBeacon->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBeacon->RSN); + } + + if (pBeacon->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBeacon->WPA); + } + + if (pBeacon->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pBeaconStruct->edcaParams, + &pBeacon->WMMParams); + PELOG1(lim_log + (pMac, LOG1, + FL("WMM Parameter present in Beacon Frame!\n")); + __print_wmm_params(pMac, &pBeacon->WMMParams); + ) + } + + if (pBeacon->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + PELOG1(lim_log + (pMac, LOG1, FL("WMM Info present in Beacon Frame!\n")); + ) + } + + if (pBeacon->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBeacon->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(pMac, &pBeaconStruct->erpIEInfo, + &pBeacon->ERPInfo); + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pBeacon->MobilityDomain.present) { + /* MobilityDomain */ + pBeaconStruct->mdiePresent = 1; + cdf_mem_copy((uint8_t *) &(pBeaconStruct->mdie[0]), + (uint8_t *) &(pBeacon->MobilityDomain.MDID), + sizeof(uint16_t)); + pBeaconStruct->mdie[2] = + ((pBeacon->MobilityDomain.overDSCap << 0) | (pBeacon-> + MobilityDomain. + resourceReqCap + << 1)); + + } +#endif + +#ifdef FEATURE_WLAN_ESE + if (pBeacon->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBeacon->ESETxmitPower.present) { + /* copy ESE TPC info element */ + pBeaconStruct->eseTxPwr.present = 1; + cdf_mem_copy(&pBeaconStruct->eseTxPwr, + &pBeacon->ESETxmitPower, + sizeof(tDot11fIEESETxmitPower)); + } + if (pBeacon->QBSSLoad.present) { + cdf_mem_copy(&pBeaconStruct->QBSSLoad, + &pBeacon->QBSSLoad, sizeof(tDot11fIEQBSSLoad)); + } +#endif + +#ifdef WLAN_FEATURE_11AC + if (pBeacon->VHTCaps.present) { + cdf_mem_copy(&pBeaconStruct->VHTCaps, &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->VHTOperation.present) { + cdf_mem_copy(&pBeaconStruct->VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBeacon->VHTExtBssLoad.present) { + cdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBeacon->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBeacon->OperatingMode.present) { + cdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBeacon->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + if (pBeacon->WiderBWChanSwitchAnn.present) { + pBeaconStruct->WiderBWChanSwitchAnnPresent = 1; + cdf_mem_copy(&pBeaconStruct->WiderBWChanSwitchAnn, + &pBeacon->WiderBWChanSwitchAnn, + sizeof(tDot11fIEWiderBWChanSwitchAnn)); + } +#endif + + /* IBSS Peer Params */ + if (pBeacon->IBSSParams.present) { + pBeaconStruct->IBSSParams.present = 1; + cdf_mem_copy(&pBeaconStruct->IBSSParams, &pBeacon->IBSSParams, + sizeof(tDot11fIEIBSSParams)); + } + + pBeaconStruct->Vendor1IEPresent = pBeacon->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBeacon->Vendor3IE.present; + + pBeaconStruct->vendor2_ie.present = pBeacon->vendor2_ie.present; + if (pBeacon->vendor2_ie.present) { + pBeaconStruct->vendor2_ie.type = pBeacon->vendor2_ie.type; + pBeaconStruct->vendor2_ie.sub_type = + pBeacon->vendor2_ie.sub_type; + } + if (pBeacon->vendor2_ie.present) { + PELOG1(lim_log(pMac, LOG1, + FL("Vendor Specific VHT caps present in Beacon Frame!")); + ) + } + if (pBeacon->vendor2_ie.VHTCaps.present) { + cdf_mem_copy(&pBeaconStruct->vendor2_ie.VHTCaps, + &pBeacon->vendor2_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->vendor2_ie.VHTOperation.present) { + cdf_mem_copy(&pBeaconStruct->vendor2_ie.VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (pBeacon->QComVendorIE.present) { + pBeaconStruct->AvoidChannelIE.present = + pBeacon->QComVendorIE.present; + pBeaconStruct->AvoidChannelIE.type = + pBeacon->QComVendorIE.type; + pBeaconStruct->AvoidChannelIE.channel = + pBeacon->QComVendorIE.channel; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + + cdf_mem_free(pBeacon); + return eSIR_SUCCESS; + +} /* End sir_convert_beacon_frame2_struct. */ + +tSirRetStatus +sir_convert_auth_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirMacAuthFrameBody pAuth) +{ + static tDot11fAuthentication auth; + uint32_t status; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAuth, sizeof(tSirMacAuthFrameBody), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_authentication(pMac, pFrame, nFrame, &auth); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL + ("Failed to parse an Authentication frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking an Authentication frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fAuthentication' to a 'tSirMacAuthFrameBody'... */ + pAuth->authAlgoNumber = auth.AuthAlgo.algo; + pAuth->authTransactionSeqNumber = auth.AuthSeqNo.no; + pAuth->authStatusCode = auth.Status.status; + + if (auth.ChallengeText.present) { + pAuth->type = SIR_MAC_CHALLENGE_TEXT_EID; + pAuth->length = auth.ChallengeText.num_text; + cdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text, + auth.ChallengeText.num_text); + } + + return eSIR_SUCCESS; + +} /* End sir_convert_auth_frame2_struct. */ + +tSirRetStatus +sir_convert_addts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsReqInfo *pAddTs) +{ + tDot11fAddTSRequest addts = { {0}}; + tDot11fWMMAddTSRequest wmmaddts = { {0}}; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_REQ != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sir_convert_addts_req2_struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAddTs, sizeof(tSirAddtsReqInfo), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_add_ts_request(pMac, pFrame, nFrame, &addts); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_request(pMac, pFrame, nFrame, + &wmmaddts); + break; + default: + lim_log(pMac, LOGE, FL("sir_convert_addts_req2_struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, FL("Failed to parse an Add TS Request f" + "rame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, FL("There were warnings while unpackin" + "g an Add TS Request frame (0x%08x," + "%d bytes):\n"), status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fAddTSRequest' or a */ + /* 'tDot11WMMAddTSRequest' to a 'tSirMacAddtsReqInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + + if (addts.TSPEC.present) { + convert_tspec(pMac, &pAddTs->tspec, &addts.TSPEC); + } else { + lim_log(pMac, LOGE, + FL + ("Mandatory TSPEC element missing in Add TS Request.\n")); + return eSIR_FAILURE; + } + + if (addts.num_TCLAS) { + pAddTs->numTclas = (uint8_t) addts.num_TCLAS; + + for (i = 0U; i < addts.num_TCLAS; ++i) { + if (eSIR_SUCCESS != + convert_tclas(pMac, &(pAddTs->tclasInfo[i]), + &(addts.TCLAS[i]))) { + lim_log(pMac, LOGE, + FL + ("Failed to convert a TCLAS IE.\n")); + return eSIR_FAILURE; + } + } + } + + if (addts.TCLASSPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.TCLASSPROC.processing; + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, &addts.WMMTSPEC); + } + + if (addts.num_WMMTCLAS) { + j = (uint8_t) (pAddTs->numTclas + addts.num_WMMTCLAS); + if (SIR_MAC_TCLASIE_MAXNUM > j) + j = SIR_MAC_TCLASIE_MAXNUM; + + for (i = pAddTs->numTclas; i < j; ++i) { + if (eSIR_SUCCESS != + convert_wmmtclas(pMac, + &(pAddTs->tclasInfo[i]), + &(addts.WMMTCLAS[i]))) { + lim_log(pMac, LOGE, + FL + ("Failed to convert a TCLAS IE.\n")); + return eSIR_FAILURE; + } + } + } + + if (addts.WMMTCLASPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.WMMTCLASPROC.processing; + } + + if (1 < pAddTs->numTclas && (!pAddTs->tclasProcPresent)) { + lim_log(pMac, LOGE, + FL("%d TCLAS IE but not TCLASPROC IE.\n"), + pAddTs->numTclas); + return eSIR_FAILURE; + } + } else { + pAddTs->dialogToken = wmmaddts.DialogToken.token; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!\n")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; + +} /* End sir_convert_addts_req2_struct. */ + +tSirRetStatus +sir_convert_addts_rsp2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsRspInfo *pAddTs) +{ + tDot11fAddTSResponse addts = { {0}}; + tDot11fWMMAddTSResponse wmmaddts = { {0}}; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_RSP != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sir_convert_addts_rsp2_struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pAddTs, sizeof(tSirAddtsRspInfo), 0); + cdf_mem_set((uint8_t *) &addts, sizeof(tDot11fAddTSResponse), 0); + cdf_mem_set((uint8_t *) &wmmaddts, sizeof(tDot11fWMMAddTSResponse), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = + dot11f_unpack_add_ts_response(pMac, pFrame, nFrame, &addts); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_response(pMac, pFrame, nFrame, + &wmmaddts); + break; + default: + lim_log(pMac, LOGE, FL("sir_convert_addts_rsp2_struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, FL("Failed to parse an Add TS Response f" + "rame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, FL("There were warnings while unpackin" + "g an Add TS Response frame (0x%08x," + "%d bytes):\n"), status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fAddTSResponse' or a */ + /* 'tDot11WMMAddTSResponse' to a 'tSirMacAddtsRspInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + pAddTs->status = (tSirMacStatusCodes) addts.Status.status; + + if (addts.TSDelay.present) { + convert_ts_delay(pMac, &pAddTs->delay, &addts.TSDelay); + } + /* TS Delay is present iff status indicates its presence */ + if (eSIR_MAC_TS_NOT_CREATED_STATUS == pAddTs->status + && !addts.TSDelay.present) { + lim_log(pMac, LOGW, FL("Missing TSDelay IE.\n")); + } + + if (addts.TSPEC.present) { + convert_tspec(pMac, &pAddTs->tspec, &addts.TSPEC); + } else { + lim_log(pMac, LOGE, + FL + ("Mandatory TSPEC element missing in Add TS Response.\n")); + return eSIR_FAILURE; + } + + if (addts.num_TCLAS) { + pAddTs->numTclas = (uint8_t) addts.num_TCLAS; + + for (i = 0U; i < addts.num_TCLAS; ++i) { + if (eSIR_SUCCESS != + convert_tclas(pMac, &(pAddTs->tclasInfo[i]), + &(addts.TCLAS[i]))) { + lim_log(pMac, LOGE, + FL + ("Failed to convert a TCLAS IE.\n")); + return eSIR_FAILURE; + } + } + } + + if (addts.TCLASSPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.TCLASSPROC.processing; + } +#ifdef FEATURE_WLAN_ESE + if (addts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + cdf_mem_copy(&pAddTs->tsmIE.tsid, + &addts.ESETrafStrmMet.tsid, + sizeof(tSirMacESETSMIE)); + } +#endif + if (addts.Schedule.present) { + pAddTs->schedulePresent = 1; + convert_schedule(pMac, &pAddTs->schedule, + &addts.Schedule); + } + + if (addts.WMMSchedule.present) { + pAddTs->schedulePresent = 1; + convert_wmm_schedule(pMac, &pAddTs->schedule, + &addts.WMMSchedule); + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, &addts.WMMTSPEC); + } + + if (addts.num_WMMTCLAS) { + j = (uint8_t) (pAddTs->numTclas + addts.num_WMMTCLAS); + if (SIR_MAC_TCLASIE_MAXNUM > j) + j = SIR_MAC_TCLASIE_MAXNUM; + + for (i = pAddTs->numTclas; i < j; ++i) { + if (eSIR_SUCCESS != + convert_wmmtclas(pMac, + &(pAddTs->tclasInfo[i]), + &(addts.WMMTCLAS[i]))) { + lim_log(pMac, LOGE, + FL + ("Failed to convert a TCLAS IE.\n")); + return eSIR_FAILURE; + } + } + } + + if (addts.WMMTCLASPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.WMMTCLASPROC.processing; + } + + if (1 < pAddTs->numTclas && (!pAddTs->tclasProcPresent)) { + lim_log(pMac, LOGE, + FL("%d TCLAS IE but not TCLASPROC IE.\n"), + pAddTs->numTclas); + return eSIR_FAILURE; + } + } else { + pAddTs->dialogToken = wmmaddts.DialogToken.token; + pAddTs->status = + (tSirMacStatusCodes) wmmaddts.StatusCode.statusCode; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!\n")); + return eSIR_FAILURE; + } + +#ifdef FEATURE_WLAN_ESE + if (wmmaddts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + cdf_mem_copy(&pAddTs->tsmIE.tsid, + &wmmaddts.ESETrafStrmMet.tsid, + sizeof(tSirMacESETSMIE)); + } +#endif + + } + + return eSIR_SUCCESS; + +} /* End sir_convert_addts_rsp2_struct. */ + +tSirRetStatus +sir_convert_delts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirDeltsReqInfo *pDelTs) +{ + tDot11fDelTS delts = { {0}}; + tDot11fWMMDelTS wmmdelts = { {0}}; + uint32_t status; + + if (SIR_MAC_QOS_DEL_TS_REQ != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sirConvertDeltsRsp2Struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pDelTs, sizeof(tSirDeltsReqInfo), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_del_ts(pMac, pFrame, nFrame, &delts); + break; + case SIR_MAC_ACTION_WME: + status = dot11f_unpack_wmm_del_ts(pMac, pFrame, nFrame, &wmmdelts); + break; + default: + lim_log(pMac, LOGE, FL("sirConvertDeltsRsp2Struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, FL("Failed to parse an Del TS Request f" + "rame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, FL("There were warnings while unpackin" + "g an Del TS Request frame (0x%08x," + "%d bytes):\n"), status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fDelTSResponse' or a */ + /* 'tDot11WMMDelTSResponse' to a 'tSirMacDeltsReqInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pDelTs->tsinfo.traffic.trafficType = + (uint16_t) delts.TSInfo.traffic_type; + pDelTs->tsinfo.traffic.tsid = (uint16_t) delts.TSInfo.tsid; + pDelTs->tsinfo.traffic.direction = + (uint16_t) delts.TSInfo.direction; + pDelTs->tsinfo.traffic.accessPolicy = + (uint16_t) delts.TSInfo.access_policy; + pDelTs->tsinfo.traffic.aggregation = + (uint16_t) delts.TSInfo.aggregation; + pDelTs->tsinfo.traffic.psb = (uint16_t) delts.TSInfo.psb; + pDelTs->tsinfo.traffic.userPrio = + (uint16_t) delts.TSInfo.user_priority; + pDelTs->tsinfo.traffic.ackPolicy = + (uint16_t) delts.TSInfo.tsinfo_ack_pol; + + pDelTs->tsinfo.schedule.schedule = + (uint8_t) delts.TSInfo.schedule; + } else { + if (wmmdelts.WMMTSPEC.present) { + pDelTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pDelTs->tspec, + &wmmdelts.WMMTSPEC); + } else { + dot11f_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!\n")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; + +} /* End sir_convert_delts_req2_struct. */ + +tSirRetStatus +sir_convert_qos_map_configure_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, + tSirQosMapSet *pQosMapSet) +{ + tDot11fQosMapConfigure mapConfigure; + uint32_t status; + status = + dot11f_unpack_qos_map_configure(pMac, pFrame, nFrame, &mapConfigure); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL + ("Failed to parse Qos Map Configure frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL + ("There were warnings while unpacking Qos Map Configure frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + pQosMapSet->present = mapConfigure.QosMapSet.present; + convert_qos_mapset_frame(pMac->hHdd, pQosMapSet, &mapConfigure.QosMapSet); + lim_log_qos_map_set(pMac, pQosMapSet); + return eSIR_SUCCESS; +} + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +sir_convert_tpc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirMacTpcReqActionFrame pTpcReqFrame, + uint32_t nFrame) +{ + tDot11fTPCRequest req; + uint32_t status; + cdf_mem_set((uint8_t *) pTpcReqFrame, sizeof(tSirMacTpcReqActionFrame), + 0); + status = dot11f_unpack_tpc_request(pMac, pFrame, nFrame, &req); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL + ("Failed to parse a TPC Request frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL + ("There were warnings while unpacking a TPC Request frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fTPCRequest' to a */ + /* 'tSirMacTpcReqActionFrame'... */ + pTpcReqFrame->actionHeader.category = req.Category.category; + pTpcReqFrame->actionHeader.actionID = req.Action.action; + pTpcReqFrame->actionHeader.dialogToken = req.DialogToken.token; + if (req.TPCRequest.present) { + pTpcReqFrame->type = DOT11F_EID_TPCREQUEST; + pTpcReqFrame->length = 0; + } else { + dot11f_log(pMac, LOGW, FL("!!!Rcv TPC Req of inalid type!\n")); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} /* End sir_convert_tpc_req_frame2_struct. */ +tSirRetStatus +sir_convert_meas_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirMacMeasReqActionFrame pMeasReqFrame, + uint32_t nFrame) +{ + tDot11fMeasurementRequest mr; + uint32_t status; + + /* Zero-init our [out] parameter, */ + cdf_mem_set((uint8_t *) pMeasReqFrame, + sizeof(tpSirMacMeasReqActionFrame), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_measurement_request(pMac, pFrame, nFrame, &mr); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL + ("Failed to parse a Measurement Request frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Measurement Request frame (0x%08x, %d bytes):\n"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + } + /* & "transliterate" from a 'tDot11fMeasurementRequest' to a */ + /* 'tpSirMacMeasReqActionFrame'... */ + pMeasReqFrame->actionHeader.category = mr.Category.category; + pMeasReqFrame->actionHeader.actionID = mr.Action.action; + pMeasReqFrame->actionHeader.dialogToken = mr.DialogToken.token; + + if (0 == mr.num_MeasurementRequest) { + dot11f_log(pMac, LOGE, + FL + ("Missing mandatory IE in Measurement Request Frame.\n")); + return eSIR_FAILURE; + } else if (1 < mr.num_MeasurementRequest) { + lim_log(pMac, LOGW, + FL("Warning: dropping extra Measurement Request IEs!")); + } + + pMeasReqFrame->measReqIE.type = DOT11F_EID_MEASUREMENTREQUEST; + pMeasReqFrame->measReqIE.length = DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN; + pMeasReqFrame->measReqIE.measToken = + mr.MeasurementRequest[0].measurement_token; + pMeasReqFrame->measReqIE.measReqMode = + (mr.MeasurementRequest[0].reserved << 3) | (mr. + MeasurementRequest[0]. + enable << 2) | (mr. + MeasurementRequest + [0]. + request + << 1) | + (mr.MeasurementRequest[0].report /*<< 0 */ ); + pMeasReqFrame->measReqIE.measType = + mr.MeasurementRequest[0].measurement_type; + + pMeasReqFrame->measReqIE.measReqField.channelNumber = + mr.MeasurementRequest[0].channel_no; + + cdf_mem_copy(pMeasReqFrame->measReqIE.measReqField.measStartTime, + mr.MeasurementRequest[0].meas_start_time, 8); + + pMeasReqFrame->measReqIE.measReqField.measDuration = + mr.MeasurementRequest[0].meas_duration; + + return eSIR_SUCCESS; + +} /* End sir_convert_meas_req_frame2_struct. */ +#endif + +void populate_dot11f_tspec(tSirMacTspecIE *pOld, tDot11fIETSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->schedule = pOld->tsinfo.schedule.schedule; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->present = 1; + +} /* End populate_dot11f_tspec. */ + +void populate_dot11f_wmmtspec(tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->burst_size_defn = pOld->tsinfo.traffic.burstSizeDefn; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->version = 1; + pDot11f->present = 1; + +} /* End populate_dot11f_wmmtspec. */ + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version currently supported */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion) +{ + pESEVersion->present = 1; + pESEVersion->version = ESE_VERSION_SUPPORTED; +} + +/* Fill the ESE ie for the station. */ +/* The State is Normal (1) */ +/* The MBSSID for station is set to 0. */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap) +{ + pESERadMgmtCap->present = 1; + pESERadMgmtCap->mgmt_state = RM_STATE_NORMAL; + pESERadMgmtCap->mbssid_mask = 0; + pESERadMgmtCap->reserved = 0; +} + +tSirRetStatus populate_dot11f_ese_cckm_opaque(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f) +{ + int idx; + if (pCCKMie->length) { + if (0 <= (idx = find_ie_location(pMac, (tpSirRSNie) pCCKMie, + DOT11F_EID_ESECCKMOPAQUE))) { + pDot11f->present = 1; + /* Dont include OUI */ + pDot11f->num_data = pCCKMie->cckmIEdata[idx + 1] - 4; + cdf_mem_copy(pDot11f->data, pCCKMie->cckmIEdata + idx + 2 + 4, /* EID,len,OUI */ + pCCKMie->cckmIEdata[idx + 1] - 4); /* Skip OUI */ + } + } + return eSIR_SUCCESS; +} /* End populate_dot11f_ese_cckm_opaque. */ + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length) +{ + pDot11f->tsid = pOld->tsid; + cdf_mem_copy(pDot11f->tsrates, pOld->rates, rate_length); + pDot11f->num_tsrates = rate_length; + pDot11f->present = 1; +} +#endif + +tSirRetStatus +populate_dot11f_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f) +{ + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + cdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + cdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + cdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + source, pOld->tclasParams.ipv4.srcIpAddr, + 4); + cdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + dest, pOld->tclasParams.ipv4.dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + lim_log(pMac, LOGE, + FL("Bad TCLAS type %d in populate_dot11f_tclas.\n"), + pDot11f->classifier_type); + return eSIR_FAILURE; + } + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_tclas. */ + +tSirRetStatus +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f) +{ + pDot11f->version = 1; + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + cdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + cdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.source, + (uint8_t *) pOld->tclasParams.ipv4. + srcIpAddr, 4); + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.dest, + (uint8_t *) pOld->tclasParams.ipv4. + dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + cdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + lim_log(pMac, LOGE, + FL("Bad TCLAS type %d in populate_dot11f_tclas.\n"), + pDot11f->classifier_type); + return eSIR_FAILURE; + } + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wmmtclas. */ + +tSirRetStatus populate_dot11f_wsc(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + + uint32_t wpsState; + + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x01; + pDot11f->Version.minor = 0x00; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, "Failed to cfg get id %d\n", + WNI_CFG_WPS_STATE); + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->UUID_E.present = 0; + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != eSIR_SUCCESS) + lim_log(pMac, LOGP, "Failed to cfg get id %d\n", + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return eSIR_SUCCESS; +} + +tSirRetStatus de_populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_probe_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->APWPSIEs.SirWPSProbeRspIE; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSProbeRspIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSProbeRspIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSProbeRspIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = + pSirWPSProbeRspIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSProbeRspIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSProbeRspIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSProbeRspIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + cdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSProbeRspIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MANUFACTURE_PRESENT) { + pDot11f->Manufacturer.present = 1; + pDot11f->Manufacturer.num_name = + pSirWPSProbeRspIE->Manufacture.num_name; + cdf_mem_copy(pDot11f->Manufacturer.name, + pSirWPSProbeRspIE->Manufacture.name, + pSirWPSProbeRspIE->Manufacture.num_name); + } else + pDot11f->Manufacturer.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelName.present = 1; + pDot11f->ModelName.num_text = + pSirWPSProbeRspIE->ModelName.num_text; + cdf_mem_copy(pDot11f->ModelName.text, + pSirWPSProbeRspIE->ModelName.text, + pDot11f->ModelName.num_text); + } else + pDot11f->ModelName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelNumber.present = 1; + pDot11f->ModelNumber.num_text = + pSirWPSProbeRspIE->ModelNumber.num_text; + cdf_mem_copy(pDot11f->ModelNumber.text, + pSirWPSProbeRspIE->ModelNumber.text, + pDot11f->ModelNumber.num_text); + } else + pDot11f->ModelNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT) { + pDot11f->SerialNumber.present = 1; + pDot11f->SerialNumber.num_text = + pSirWPSProbeRspIE->SerialNumber.num_text; + cdf_mem_copy(pDot11f->SerialNumber.text, + pSirWPSProbeRspIE->SerialNumber.text, + pDot11f->SerialNumber.num_text); + } else + pDot11f->SerialNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT) { + pDot11f->PrimaryDeviceType.present = 1; + cdf_mem_copy(pDot11f->PrimaryDeviceType.oui, + pSirWPSProbeRspIE->PrimaryDeviceOUI, + sizeof(pSirWPSProbeRspIE->PrimaryDeviceOUI)); + pDot11f->PrimaryDeviceType.primary_category = + (uint16_t) pSirWPSProbeRspIE->PrimaryDeviceCategory; + pDot11f->PrimaryDeviceType.sub_category = + (uint16_t) pSirWPSProbeRspIE->DeviceSubCategory; + } else + pDot11f->PrimaryDeviceType.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICENAME_PRESENT) { + pDot11f->DeviceName.present = 1; + pDot11f->DeviceName.num_text = + pSirWPSProbeRspIE->DeviceName.num_text; + cdf_mem_copy(pDot11f->DeviceName.text, + pSirWPSProbeRspIE->DeviceName.text, + pDot11f->DeviceName.num_text); + } else + pDot11f->DeviceName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT) { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + pSirWPSProbeRspIE->ConfigMethod; + } else + pDot11f->ConfigMethods.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSProbeRspIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry) +{ + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->APWPSIEs.SirWPSProbeRspIE; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSProbeRspIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSProbeRspIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSBeaconIE *pSirWPSBeaconIE; + + pSirWPSBeaconIE = &psessionEntry->APWPSIEs.SirWPSBeaconIE; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSBeaconIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSBeaconIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSBeaconIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pSirWPSBeaconIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSBeaconIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSBeaconIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSBeaconIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + cdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSBeaconIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSBeaconIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f) +{ + uint32_t cfgMethods; + uint32_t cfgStrLen; + uint32_t val; + uint32_t wpsVersion, wpsState; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_VERSION, &wpsVersion) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, "Failed to cfg get id %d\n", + WNI_CFG_WPS_VERSION); + + pDot11f->Version.present = 1; + pDot11f->Version.major = (uint8_t) ((wpsVersion & 0xF0) >> 4); + pDot11f->Version.minor = (uint8_t) (wpsVersion & 0x0F); + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, "Failed to cfg get id %d\n", + WNI_CFG_WPS_STATE); + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->ResponseType.present = 1; + if ((pMac->lim.wscIeInfo.reqType == REQ_TYPE_REGISTRAR) || + (pMac->lim.wscIeInfo.reqType == REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + + /* UUID is a 16 byte long binary. Still use wlan_cfg_get_str to get it. */ + pDot11f->UUID_E.present = 1; + cfgStrLen = WNI_CFG_WPS_UUID_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_WPS_UUID, + pDot11f->UUID_E.uuid, &cfgStrLen) != eSIR_SUCCESS) { + *(pDot11f->UUID_E.uuid) = '\0'; + } + + pDot11f->Manufacturer.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_NAME, + pDot11f->Manufacturer.name, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->Manufacturer.num_name = 0; + } else { + pDot11f->Manufacturer.num_name = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelName.present = 1; + cfgStrLen = WNI_CFG_MODEL_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NAME, + pDot11f->ModelName.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->ModelName.num_text = 0; + } else { + pDot11f->ModelName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelNumber.present = 1; + cfgStrLen = WNI_CFG_MODEL_NUMBER_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NUMBER, + pDot11f->ModelNumber.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->ModelNumber.num_text = 0; + } else { + pDot11f->ModelNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->SerialNumber.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + pDot11f->SerialNumber.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->SerialNumber.num_text = 0; + } else { + pDot11f->SerialNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->PrimaryDeviceType.present = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get prim device category failed\n")); + } else + pDot11f->PrimaryDeviceType.primary_category = (uint16_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PIMARY_DEVICE_OUI, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get prim device OUI failed\n")); + } else { + *(pDot11f->PrimaryDeviceType.oui) = + (uint8_t) ((val >> 24) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 1) = + (uint8_t) ((val >> 16) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 2) = + (uint8_t) ((val >> 8) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 3) = + (uint8_t) ((val & 0xff)); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_DEVICE_SUB_CATEGORY, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("cfg get prim device sub category failed\n")); + } else + pDot11f->PrimaryDeviceType.sub_category = (uint16_t) val; + + pDot11f->DeviceName.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + pDot11f->DeviceName.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->DeviceName.num_text = 0; + } else { + pDot11f->DeviceName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + if (wlan_cfg_get_int(pMac, + WNI_CFG_WPS_CFG_METHOD, + &cfgMethods) != eSIR_SUCCESS) { + pDot11f->ConfigMethods.present = 0; + pDot11f->ConfigMethods.methods = 0; + } else { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + (uint16_t) (cfgMethods & 0x0000FFFF); + } + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes * + pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != eSIR_SUCCESS) + lim_log(pMac, LOGP, "Failed to cfg get id %d\n", + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return eSIR_SUCCESS; +} + +tSirRetStatus de_populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes * + pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + tDot11fIEWscAssocReq parsedWscAssocReq = { 0, }; + uint8_t *wscIe; + + wscIe = + limGetWscIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (wscIe != NULL) { + /* retreive WSC IE from given AssocReq */ + dot11f_unpack_ie_wsc_assoc_req(pMac, wscIe + 2 + 4, /* EID, length, OUI */ + wscIe[1] - 4, /* length without OUI */ + &parsedWscAssocReq); + pDot11f->present = 1; + /* version has to be 0x10 */ + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x1; + pDot11f->Version.minor = 0x0; + + pDot11f->ResponseType.present = 1; + + if ((parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_REGISTRAR) + || (parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = + RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + /* Version infomration should be taken from our capability as well as peers */ + /* TODO: currently it takes from peers only */ + if (parsedWscAssocReq.VendorExtension.present && + parsedWscAssocReq.VendorExtension.Version2.present) { + pDot11f->VendorExtension.present = 1; + pDot11f->VendorExtension.vendorId[0] = 0x00; + pDot11f->VendorExtension.vendorId[1] = 0x37; + pDot11f->VendorExtension.vendorId[2] = 0x2A; + pDot11f->VendorExtension.Version2.present = 1; + pDot11f->VendorExtension.Version2.major = + parsedWscAssocReq.VendorExtension.Version2.major; + pDot11f->VendorExtension.Version2.minor = + parsedWscAssocReq.VendorExtension.Version2.minor; + } + } + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + uint8_t *p2pIe; + + p2pIe = + limGetP2pIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (p2pIe != NULL) { + pDot11f->present = 1; + pDot11f->P2PStatus.present = 1; + pDot11f->P2PStatus.status = eSIR_SUCCESS; + pDot11f->ExtendedListenTiming.present = 0; + } + return eSIR_SUCCESS; +} + +#if defined WLAN_FEATURE_VOWIFI + +tSirRetStatus populate_dot11f_wfatpc(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin) +{ + pDot11f->txPower = txPower; + pDot11f->linkMargin = linkMargin; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport) +{ + + pDot11f->report.Beacon.regClass = pBeaconReport->regClass; + pDot11f->report.Beacon.channel = pBeaconReport->channel; + cdf_mem_copy(pDot11f->report.Beacon.meas_start_time, + pBeaconReport->measStartTime, + sizeof(pDot11f->report.Beacon.meas_start_time)); + pDot11f->report.Beacon.meas_duration = pBeaconReport->measDuration; + pDot11f->report.Beacon.condensed_PHY = pBeaconReport->phyType; + pDot11f->report.Beacon.reported_frame_type = + !pBeaconReport->bcnProbeRsp; + pDot11f->report.Beacon.RCPI = pBeaconReport->rcpi; + pDot11f->report.Beacon.RSNI = pBeaconReport->rsni; + cdf_mem_copy(pDot11f->report.Beacon.BSSID, pBeaconReport->bssid, + sizeof(tSirMacAddr)); + pDot11f->report.Beacon.antenna_id = pBeaconReport->antennaId; + pDot11f->report.Beacon.parent_TSF = pBeaconReport->parentTSF; + + if (pBeaconReport->numIes) { + pDot11f->report.Beacon.BeaconReportFrmBody.present = 1; + cdf_mem_copy(pDot11f->report.Beacon.BeaconReportFrmBody. + reportedFields, pBeaconReport->Ies, + pBeaconReport->numIes); + pDot11f->report.Beacon.BeaconReportFrmBody.num_reportedFields = + pBeaconReport->numIes; + } + + return eSIR_SUCCESS; + +} + +tSirRetStatus populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry) +{ + tpRRMCaps pRrmCaps; + + pRrmCaps = rrm_get_capabilities(pMac, psessionEntry); + + pDot11f->LinkMeasurement = pRrmCaps->LinkMeasurement; + pDot11f->NeighborRpt = pRrmCaps->NeighborRpt; + pDot11f->parallel = pRrmCaps->parallel; + pDot11f->repeated = pRrmCaps->repeated; + pDot11f->BeaconPassive = pRrmCaps->BeaconPassive; + pDot11f->BeaconActive = pRrmCaps->BeaconActive; + pDot11f->BeaconTable = pRrmCaps->BeaconTable; + pDot11f->BeaconRepCond = pRrmCaps->BeaconRepCond; + pDot11f->FrameMeasurement = pRrmCaps->FrameMeasurement; + pDot11f->ChannelLoad = pRrmCaps->ChannelLoad; + pDot11f->NoiseHistogram = pRrmCaps->NoiseHistogram; + pDot11f->statistics = pRrmCaps->statistics; + pDot11f->LCIMeasurement = pRrmCaps->LCIMeasurement; + pDot11f->LCIAzimuth = pRrmCaps->LCIAzimuth; + pDot11f->TCMCapability = pRrmCaps->TCMCapability; + pDot11f->triggeredTCM = pRrmCaps->triggeredTCM; + pDot11f->APChanReport = pRrmCaps->APChanReport; + pDot11f->RRMMIBEnabled = pRrmCaps->RRMMIBEnabled; + pDot11f->operatingChanMax = pRrmCaps->operatingChanMax; + pDot11f->nonOperatinChanMax = pRrmCaps->nonOperatingChanMax; + pDot11f->MeasurementPilot = pRrmCaps->MeasurementPilot; + pDot11f->MeasurementPilotEnabled = pRrmCaps->MeasurementPilotEnabled; + pDot11f->NeighborTSFOffset = pRrmCaps->NeighborTSFOffset; + pDot11f->RCPIMeasurement = pRrmCaps->RCPIMeasurement; + pDot11f->RSNIMeasurement = pRrmCaps->RSNIMeasurement; + pDot11f->BssAvgAccessDelay = pRrmCaps->BssAvgAccessDelay; + pDot11f->BSSAvailAdmission = pRrmCaps->BSSAvailAdmission; + pDot11f->AntennaInformation = pRrmCaps->AntennaInformation; + pDot11f->fine_time_meas_rpt = pRrmCaps->fine_time_meas_rpt; + pDot11f->lci_capability = pRrmCaps->lci_capability; + pDot11f->reserved = pRrmCaps->reserved; + + pDot11f->present = 1; + return eSIR_SUCCESS; +} +#endif + +#if defined WLAN_FEATURE_VOWIFI_11R +void populate_mdie(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain *pDot11f, + uint8_t mdie[SIR_MDIE_SIZE]) +{ + pDot11f->present = 1; + pDot11f->MDID = (uint16_t) ((mdie[1] << 8) | (mdie[0])); + + /* Plugfest fix */ + pDot11f->overDSCap = (mdie[2] & 0x01); + pDot11f->resourceReqCap = ((mdie[2] >> 1) & 0x01); + +} + +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f) +{ + pDot11f->present = 1; + pDot11f->IECount = 0; /* TODO: put valid data during reassoc. */ + /* All other info is zero. */ + +} +#endif + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates) +{ + uint8_t num_supp = 0, num_ext = 0; + uint8_t i, j; + + for (i = 0; (i < SIR_NUM_11B_RATES && _11bRates[i]); i++, num_supp++) { + pSupp->rates[num_supp] = (uint8_t) _11bRates[i]; + } + for (j = 0; (j < SIR_NUM_11A_RATES && _11aRates[j]); j++) { + if (num_supp < 8) + pSupp->rates[num_supp++] = (uint8_t) _11aRates[j]; + else + pExt->rates[num_ext++] = (uint8_t) _11aRates[j]; + } + + if (num_supp) { + pSupp->num_rates = num_supp; + pSupp->present = 1; + } + if (num_ext) { + pExt->num_rates = num_ext; + pExt->present = 1; + } +} + +void populate_dot11f_timeout_interval(tpAniSirGlobal pMac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value) +{ + pDot11f->present = 1; + pDot11f->timeoutType = type; + pDot11f->timeoutValue = value; +} + +/** + * populate_dot11f_timing_advert_frame() - Populate the TA mgmt frame fields + * @pMac: the MAC context + * @frame: pointer to the TA frame + * + * Return: The SIR status. + */ +tSirRetStatus populate_dot11f_timing_advert_frame(tpAniSirGlobal mac_ctx, + tDot11fTimingAdvertisementFrame *frame) +{ + uint32_t val, codelen, len; + uint16_t item; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + tSirRetStatus nSirStatus; + + /* Capabilities */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, &val); + if (val) + frame->Capabilities.privacy = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, &val); + if (val) + frame->Capabilities.shortPreamble = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val); + if (val) + frame->Capabilities.spectrumMgt = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_QOS_ENABLED, &val); + if (val) + frame->Capabilities.qos = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_APSD_ENABLED, &val); + if (val) + frame->Capabilities.apsd = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_BLOCK_ACK_ENABLED, &val); + frame->Capabilities.delayedBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + frame->Capabilities.immediateBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + /* Country */ + item = WNI_CFG_MAX_TX_POWER_5; + CFG_GET_STR(nSirStatus, mac_ctx, item, temp, len, + WNI_CFG_MAX_TX_POWER_5_LEN); + item = WNI_CFG_COUNTRY_CODE; + CFG_GET_STR(nSirStatus, mac_ctx, item, code, codelen, 3); + cdf_mem_copy(&frame->Country, code, codelen); + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + + frame->Country.num_triplets = (uint8_t)(len / 3); + cdf_mem_copy((uint8_t *)&frame->Country.triplets, temp, len); + frame->Country.present = 1; + + /* PowerConstraints */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_LOCAL_POWER_CONSTRAINT, &val); + frame->PowerConstraints.localPowerConstraints = (uint8_t)val; + frame->PowerConstraints.present = 1; + + /* TimeAdvertisement */ + frame->TimeAdvertisement.present = 1; + frame->TimeAdvertisement.timing_capabilities = 1; + + return nSirStatus; +} + +/* parser_api.c ends here. */ diff --git a/core/mac/src/sys/legacy/src/utils/src/utils_api.c b/core/mac/src/sys/legacy/src/utils/src/utils_api.c new file mode 100644 index 0000000000..524bbd217f --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/utils_api.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ================================================================== */ +/* */ +/* File: utils_api.cc */ +/* */ +/* Description: Implemention of a few utility routines. */ +/* */ +/* Author: Neelay Das */ +/* */ +/* // */ +/* Change gHistory: */ +/* 12/15/2003 - NDA - Initial version. */ +/* */ +/* =================================================================== */ + +#include "utils_api.h" + +/* ------------------------------------------------------------------- */ +/** + * sir_dump_buf() + * + * FUNCTION: + * This function is called to dump a buffer with a certain level + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBuf: buffer pointer + * @return None. + */ +void +sir_dump_buf(tpAniSirGlobal pMac, uint8_t modId, uint32_t level, uint8_t *buf, + uint32_t size) +{ + uint32_t i; + + if (level > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(modId)]) + return; + + log_dbg(pMac, modId, level, FL("Dumping %d bytes in host order\n"), + size); + + for (i = 0; (i + 7) < size; i += 8) { + log_dbg(pMac, modId, level, + "%02x %02x %02x %02x %02x %02x %02x %02x \n", + buf[i], + buf[i + 1], + buf[i + 2], + buf[i + 3], + buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); + } + + /* Dump the bytes in the last line */ + for (; i < size; i++) { + log_dbg(pMac, modId, level, "%02x ", buf[i]); + + if ((i + 1) == size) + log_dbg(pMac, modId, level, "\n"); + } + +} /*** end sir_dump_buf() ***/ diff --git a/core/mac/src/sys/legacy/src/utils/src/utils_parser.c b/core/mac/src/sys/legacy/src/utils/src/utils_parser.c new file mode 100644 index 0000000000..9b91902ae7 --- /dev/null +++ b/core/mac/src/sys/legacy/src/utils/src/utils_parser.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file utils_parser.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" + +void convert_ssid(tpAniSirGlobal pMac, tSirMacSSid *pOld, tDot11fIESSID *pNew) +{ + pOld->length = pNew->num_ssid; + cdf_mem_copy(pOld->ssId, pNew->ssid, pNew->num_ssid); +} + +void convert_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIESuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + cdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_ext_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIEExtSuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + cdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_qos_caps(tpAniSirGlobal pMac, + tSirMacQosCapabilityIE *pOld, tDot11fIEQOSCapsAp *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.count = pNew->count; +} + +void convert_qos_caps_station(tpAniSirGlobal pMac, + tSirMacQosCapabilityStaIE *pOld, + tDot11fIEQOSCapsStation *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.moreDataAck = pNew->more_data_ack; + pOld->qosInfo.maxSpLen = pNew->max_sp_length; + pOld->qosInfo.qack = pNew->qack; + pOld->qosInfo.acbe_uapsd = pNew->acbe_uapsd; + pOld->qosInfo.acbk_uapsd = pNew->acbk_uapsd; + pOld->qosInfo.acvi_uapsd = pNew->acvi_uapsd; + pOld->qosInfo.acvo_uapsd = pNew->acvo_uapsd; +} + +tSirRetStatus convert_wpa(tpAniSirGlobal pMac, + tSirMacWpaInfo *pOld, tDot11fIEWPA *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into an */ + /* array... */ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + status = dot11f_pack_ie_wpa(pMac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOG2, FL("Failed to re-pack the WPA IE (0x%0x" + "8).\n"), status); + return eSIR_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + cdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_wpa_opaque(tpAniSirGlobal pMac, + tSirMacWpaInfo *pOld, tDot11fIEWPAOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data + 4; + pOld->info[0] = 0x00; + pOld->info[1] = 0x50; + pOld->info[2] = 0xf2; + pOld->info[3] = 0x01; + cdf_mem_copy(pOld->info + 4, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +#ifdef FEATURE_WLAN_WAPI +tSirRetStatus convert_wapi_opaque(tpAniSirGlobal pMac, + tSirMacWapiInfo *pOld, + tDot11fIEWAPIOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data; + cdf_mem_copy(pOld->info, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} +#endif + +tSirRetStatus convert_wsc_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEWscIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x00; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0xf2; + pOld->addIEdata[curAddIELen++] = 0x04; + cdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_p2p_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEP2PIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x09; + cdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +#ifdef WLAN_FEATURE_WFD +tSirRetStatus convert_wfd_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEWFDIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x0a; + cdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} +#endif + +tSirRetStatus convert_rsn(tpAniSirGlobal pMac, + tSirMacRsnInfo *pOld, tDot11fIERSN *pNew) +{ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + status = dot11f_pack_ie_rsn(pMac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOG2, FL("Failed to re-pack the RSN IE (0x%0x" + "8).\n"), status); + return eSIR_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + cdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_rsn_opaque(tpAniSirGlobal pMac, + tSirMacRsnInfo *pOld, tDot11fIERSNOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. */ + pOld->length = pNew->num_data; + cdf_mem_copy(pOld->info, pNew->data, pOld->length); + + return eSIR_SUCCESS; +} + +void convert_power_caps(tpAniSirGlobal pMac, + tSirMacPowerCapabilityIE *pOld, + tDot11fIEPowerCaps *pNew) +{ + pOld->type = 33; + pOld->length = 2; + pOld->minTxPower = pNew->minTxPower; + pOld->maxTxPower = pNew->maxTxPower; +} + +void convert_supp_channels(tpAniSirGlobal pMac, + tSirMacSupportedChannelIE *pOld, + tDot11fIESuppChannels *pNew) +{ + pOld->type = 36; + pOld->length = (pNew->num_bands * 2); + cdf_mem_copy((uint8_t *) pOld->supportedChannels, + (uint8_t *) pNew->bands, pOld->length); +} + +void convert_cf_params(tpAniSirGlobal pMac, + tSirMacCfParamSet *pOld, tDot11fIECFParams *pNew) +{ + pOld->cfpCount = pNew->cfp_count; + pOld->cfpPeriod = pNew->cfp_period; + pOld->cfpMaxDuration = pNew->cfp_maxduration; + pOld->cfpDurRemaining = pNew->cfp_durremaining; +} + +void convert_fh_params(tpAniSirGlobal pMac, + tSirMacFHParamSet *pOld, tDot11fIEFHParamSet *pNew) +{ + pOld->dwellTime = pNew->dwell_time; + pOld->hopSet = pNew->hop_set; + pOld->hopPattern = pNew->hop_pattern; + pOld->hopIndex = pNew->hop_index; +} + +void convert_tim(tpAniSirGlobal pMac, tSirMacTim *pOld, tDot11fIETIM *pNew) +{ + pOld->dtimCount = pNew->dtim_count; + pOld->dtimPeriod = pNew->dtim_period; + pOld->bitmapControl = pNew->bmpctl; + pOld->bitmapLength = pNew->num_vbmp; + + cdf_mem_copy(pOld->bitmap, pNew->vbmp, pNew->num_vbmp); +} + +void convert_country(tpAniSirGlobal pMac, + tSirCountryInformation *pOld, tDot11fIECountry *pNew) +{ + int i; + + cdf_mem_copy(pOld->countryString, pNew->country, COUNTRY_STRING_LENGTH); + + pOld->numIntervals = pNew->num_triplets; + + for (i = 0; i < pNew->num_triplets; ++i) { + pOld->channelTransmitPower[i].channelNumber = + pNew->triplets[i][0]; + pOld->channelTransmitPower[i].numChannel = pNew->triplets[i][1]; + pOld->channelTransmitPower[i].maxTransmitPower = + pNew->triplets[i][2]; + } +} + +void convert_wmm_params(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *pOld, tDot11fIEWMMParams *pNew) +{ + pOld->type = 221; + pOld->length = 24; + + cdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qosInfo, + 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; +} + +void convert_erp_info(tpAniSirGlobal pMac, + tSirMacErpInfo *pOld, tDot11fIEERPInfo *pNew) +{ + pOld->nonErpPresent = pNew->non_erp_present; + pOld->useProtection = pNew->use_prot; + pOld->barkerPreambleMode = pNew->barker_preamble; +} + +void convert_edca_param(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *pOld, + tDot11fIEEDCAParamSet *pNew) +{ + pOld->type = 12; + pOld->length = 20; + + cdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qos, 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; + +} + +void convert_tspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pOld, tDot11fIETSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + + pOld->tsinfo.schedule.schedule = (uint8_t) pNew->schedule; + + pOld->nomMsduSz = pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +tSirRetStatus convert_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_ietclas(pMac, pNew, &length))) { + return eSIR_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_TCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + cdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + cdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + cdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + cdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return eSIR_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +void convert_wmmtspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + pOld->nomMsduSz = (pNew->fixed << 15) | pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +tSirRetStatus convert_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_iewmmtclas(pMac, pNew, &length))) { + return eSIR_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_WMMTCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + cdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + cdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + cdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + cdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + cdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return eSIR_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +void convert_ts_delay(tpAniSirGlobal pMac, + tSirMacTsDelayIE *pOld, tDot11fIETSDelay *pNew) +{ + pOld->type = DOT11F_EID_TSDELAY; + pOld->length = 4U; + pOld->delay = pNew->delay; +} + +void convert_schedule(tpAniSirGlobal pMac, + tSirMacScheduleIE *pOld, tDot11fIESchedule *pNew) +{ + pOld->type = DOT11F_EID_SCHEDULE; + pOld->length = DOT11F_IE_SCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +void convert_wmm_schedule(tpAniSirGlobal pMac, + tSirMacScheduleIE *pOld, tDot11fIEWMMSchedule *pNew) +{ + pOld->type = DOT11F_EID_WMMSCHEDULE; + pOld->length = DOT11F_IE_WMMSCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +/** + @brief : This functions converts the given buffer till given size to Big endian format assuming the + bus is 32 bit. The size should be four byte aligned. + @param : ptr to be converted, size + @return : void + */ + +void convertto_big_endian(void *ptr, uint16_t size) +{ + uint8_t *temp_ptr; + uint32_t *dest_ptr; + + dest_ptr = (uint32_t *) ptr; + while (size) { + temp_ptr = (uint8_t *) dest_ptr; + *dest_ptr = + (temp_ptr[0] << 24) | (temp_ptr[1] << 16) | (temp_ptr[2] << + 8) | + temp_ptr[3]; + dest_ptr++; + size -= 4; + } +} + +void create_scan_data_null_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + uint8_t pwrMgmt, tSirMacAddr bssid, + tSirMacAddr selfMacAddr) +{ + + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = pwrMgmt; + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + cdf_mem_copy((void *)&macMgmtHdr->da, + (void *)bssid, sizeof(tSirMacAddr)); + cdf_mem_copy((void *)&macMgmtHdr->sa, + (void *)selfMacAddr, sizeof(tSirMacAddr)); + cdf_mem_copy((void *)&macMgmtHdr->bssId, + (void *)bssid, sizeof(tSirMacAddr)); + + return; +} + +void create_scan_cts_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tSirMacAddr selfMac) +{ + macMgmtHdr->fc.type = SIR_MAC_CTRL_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_CTRL_CTS; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> 8); + cdf_mem_copy((void *)macMgmtHdr->da, (void *)selfMac, + sizeof(tSirMacAddr)); + + return; +} + +void convert_qos_mapset_frame(tpAniSirGlobal pMac, tSirQosMapSet *Qos, + tDot11fIEQosMapSet *dot11fIE) +{ + uint8_t i, j = 0; + Qos->num_dscp_exceptions = (dot11fIE->num_dscp_exceptions - 16) / 2; + for (i = 0; i < Qos->num_dscp_exceptions; i++) { + Qos->dscp_exceptions[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_exceptions[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } + for (i = 0; i < 8; i++) { + Qos->dscp_range[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_range[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } +} + +/** + @brief : This functions creates a DATA_NULL/CTS2SELF frame in Big endian format + @param : Global MAC structure, pointer to return the created packet, role which is Station/AP + @return : void + */ + +void create_init_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role) +{ +#if 0 + tpStaStruct pSta = (tpStaStruct) pMac->hal.halMac.staTable; + + if (role == eSYSTEM_STA_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 1; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 1; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + cdf_mem_copy((void *)&macMgmtHdr->da, (void *)pSta[0].bssId, 6); + cdf_mem_copy(&macMgmtHdr->sa, pSta[0].staAddr, 6); + cdf_mem_copy((void *)&macMgmtHdr->bssId, (void *)pSta[0].bssId, + 6); + } else if (role == eSYSTEM_AP_ROLE || role == eSYSTEM_STA_IN_IBSS_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_CTRL_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_CTRL_CTS; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + cdf_mem_copy((void *)macMgmtHdr->da, (void *)pSta[0].staAddr, + 6); + } + return; +#endif +} + +/** + @brief : This functions creates a DATA_NULL frame in Big endian format + @param : Global MAC structure, pointer to return the created packet, role which is Station/AP + @return : void + */ + +void create_finish_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role) +{ +#if 0 + tpStaStruct pSta = (tpStaStruct) pMac->hal.halMac.staTable; + + if (role == eSYSTEM_STA_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 1; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + cdf_mem_copy((void *)macMgmtHdr->da, (void *)pSta[0].bssId, 6); + cdf_mem_copy(macMgmtHdr->sa, pSta[0].staAddr, 6); + cdf_mem_copy((void *)macMgmtHdr->bssId, (void *)pSta[0].bssId, + 6); + + } + + return; +#endif +} + +/* utils_parser.c ends here. */ diff --git a/core/sap/dfs/inc/ath_dfs_structs.h b/core/sap/dfs/inc/ath_dfs_structs.h new file mode 100644 index 0000000000..8a3e8f853d --- /dev/null +++ b/core/sap/dfs/inc/ath_dfs_structs.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + ath_dfs_structs.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#ifndef _DFS__STRUCTS_H_ +#define _DFS__STRUCTS_H_ +#include + +#ifdef ANDROID +#include +#endif + +/* + * For the dfs_nol_clist_update() method - this is the + * update command. + */ +enum { + DFS_NOL_CLIST_CMD_NONE = 0x0, + DFS_NOL_CLIST_CMD_UPDATE = 0x1, +}; + +struct ath_dfs_caps { + uint32_t ath_dfs_ext_chan_ok:1, + /* Can radar be detected on the extension chan? */ + ath_dfs_combined_rssi_ok:1, + /* Can use combined radar RSSI? + * the following flag is used to indicate if radar detection + * scheme should use enhanced chirping detection algorithm. + * This flag also determines if certain radar data should be + * discarded to minimize false detection of radar. + */ + ath_dfs_use_enhancement:1, + ath_strong_signal_diversiry:1, + ath_chip_is_bb_tlv:1; + + /* + * goes with ath_strong_signal_diversiry: + * If we have fast diversity capability, read off + * Strong Signal fast diversity count set in the ini + * file, and store so we can restore the value when + * radar is disabled + */ + uint32_t ath_fastdiv_val; +}; + +/* + * These are defined in the HAL for now, and must be migrated outside + * of there in order to be used by the new partial offload data path. + */ + +struct dfs_pulse { + uint32_t rp_numpulses; /* Num of pulses in radar burst */ + uint32_t rp_pulsedur; /* Duration of each pulse in usecs */ + uint32_t rp_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_max_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_patterntype; /* fixed or variable pattern type */ + uint32_t rp_pulsevar; /* Time variation of pulse duration for + matched filter (single-sided) in usecs */ + uint32_t rp_threshold; /* Threshold for MF output to indicateC + radar match */ + uint32_t rp_mindur; /* Min pulse duration to be considered for + this pulse type */ + uint32_t rp_maxdur; /* Max pusle duration to be considered for + this pulse type */ + uint32_t rp_rssithresh; /* Min rssi to be considered a radar pulse */ + uint32_t rp_meanoffset; /* Offset for timing adjustment */ + int32_t rp_rssimargin; /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dBm lower than in non TURBO + * mode. This will be used to offset that + * diff. + */ + uint32_t rp_ignore_pri_window; + uint32_t rp_pulseid; /* Unique ID for identifying filter */ +}; + +struct dfs_staggered_pulse { + uint32_t rp_numpulses; /* Num of pulses in radar burst */ + uint32_t rp_pulsedur; /* Duration of each pulse in usecs */ + uint32_t rp_min_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_max_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_patterntype; /* fixed or variable pattern type */ + uint32_t rp_pulsevar; /* Time variation of pulse duration for + matched filter (single-sided) in usecs */ + uint32_t rp_threshold; /* Thershold for MF output to indicateC + radar match */ + uint32_t rp_mindur; /* Min pulse duration to be considered for + this pulse type */ + uint32_t rp_maxdur; /* Max pusle duration to be considered for + this pulse type */ + uint32_t rp_rssithresh; /* Min rssi to be considered a radar pulse */ + uint32_t rp_meanoffset; /* Offset for timing adjustment */ + int32_t rp_rssimargin; /* rssi threshold margin. In Turbo Mode HW + reports rssi 3dBm lower than in non TURBO + mode. This will be used to offset that + diff. */ + uint32_t rp_pulseid; /* Unique ID for identifying filter */ +}; + +struct dfs_bin5pulse { + uint32_t b5_threshold; /* Num of bin5 pulses to indicate detection */ + uint32_t b5_mindur; /* Min duration for a bin5 pulse */ + uint32_t b5_maxdur; /* Max duration for a bin5 pulse */ + uint32_t b5_timewindow; /* Window over which to count bin5 pulses */ + uint32_t b5_rssithresh; /* Min rssi to be considered a pulse */ + uint32_t b5_rssimargin; /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dB + */ +}; + +/* + * DFS NOL representation. + * + * This is used to represent the DFS NOL information between the + * NOL code in lmac/dfs/dfs_nol.c and any driver layer wishing + * to use it. + */ +struct dfs_nol_chan_entry { + uint32_t nol_chfreq; /* Centre frequency, MHz */ + uint32_t nol_chwidth; /* Width, MHz */ + unsigned long nol_start_ticks; /* start ticks, OS specific */ + uint32_t nol_timeout_ms; /* timeout, mS */ +}; + +/* HAL_PHYERR_PARAM; */ + +/* + * This represents the general case of the radar PHY configuration, + * across all chips. + * + * It's then up to each chip layer to translate to/from this + * (eg to HAL_PHYERR_PARAM for the HAL case.) + */ + +#define ATH_DFS_PHYERR_PARAM_NOVAL 0xFFFF +#define ATH_DFS_PHYERR_PARAM_ENABLE 0x8000 + +struct ath_dfs_phyerr_param { + int32_t pe_firpwr; /* FIR pwr out threshold */ + int32_t pe_rrssi; /* Radar rssi thresh */ + int32_t pe_height; /* Pulse height thresh */ + int32_t pe_prssi; /* Pulse rssi thresh */ + int32_t pe_inband; /* Inband thresh */ + + /* The following params are only for AR5413 and later */ + /* + * Relative power threshold in 0.5dB steps + */ + uint32_t pe_relpwr; + + /* + * Pulse Relative step threshold in 0.5dB steps + */ + uint32_t pe_relstep; + + /* + * Max length of radar sign in 0.8us units + */ + uint32_t pe_maxlen; + + /* + * Use the average in-band power measured over 128 cycles + */ + bool pe_usefir128; + + /* + * Enable to block radar check if pkt detect is done via OFDM + * weak signal detect or pkt is detected immediately after tx + * to rx transition + */ + bool pe_blockradar; + + /* + * Enable to use the max rssi instead of the last rssi during + * fine gain changes for radar detection + */ + bool pe_enmaxrssi; +}; + +static inline void ath_dfs_phyerr_param_copy(struct ath_dfs_phyerr_param *dst, + struct ath_dfs_phyerr_param *src) +{ + cdf_mem_copy(dst, src, sizeof(*dst)); +} + +static inline void ath_dfs_phyerr_init_noval(struct ath_dfs_phyerr_param *pe) +{ + pe->pe_firpwr = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_rrssi = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_height = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_prssi = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_inband = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_relpwr = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_relstep = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_maxlen = ATH_DFS_PHYERR_PARAM_NOVAL; + + /* XXX what about usefir128, blockradar, enmaxrssi? */ +} + +struct ath_dfs_radar_tab_info { + uint32_t dfsdomain; + int numradars; + struct dfs_pulse *dfs_radars; + int numb5radars; + struct dfs_bin5pulse *b5pulses; + struct ath_dfs_phyerr_param dfs_defaultparams; + int dfs_pri_multiplier; +}; +#endif /* _DFS__STRUCTS_H_ */ diff --git a/core/sap/dfs/inc/dfs.h b/core/sap/dfs/inc/dfs.h new file mode 100644 index 0000000000..18087207e0 --- /dev/null +++ b/core/sap/dfs/inc/dfs.h @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2005-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef _DFS_H_ +#define _DFS_H_ + +/* + *TO DO DFS- Need to include this file later on + *#include "ath_internal.h" + */ +/*DFS New Include Start*/ + +#include /* CDF_NBUF_EXEMPT_NO_EXEMPTION, etc. */ +#include /* cdf_nbuf_t, etc. */ +#include /* cdf_assert */ +#include /* cdf_spinlock */ +#include /* TAILQ */ +#include +#include +#include +#include +/*DFS Utility Include END*/ + +/* From wlan_modules/include/ */ +#include "ath_dfs_structs.h" +/*DFS - Newly added File to interface cld UMAC and dfs data structures*/ +#include +/* + *TO DO DFS- Need to include this file later on + #include "ah.h" + */ +/* #include "ah_desc.h" */ +#include "dfs_ioctl.h" +#include "dfs_ioctl_private.h" +#include "dfs_interface.h" +#include "cds_ieee80211_common.h" +#include "cds_api.h" + +#define ATH_SUPPORT_DFS 1 +#define CHANNEL_TURBO 0x00010 +#define DFS_PRINTK(_fmt, ...) printk((_fmt), __VA_ARGS__) +#define DFS_DPRINTK(dfs, _m, _fmt, ...) do { \ + if (((dfs) == NULL) || \ + ((dfs) != NULL && \ + ((_m) & (dfs)->dfs_debug_mask))) { \ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_DEBUG, \ + _fmt, __VA_ARGS__); \ + } \ +} while (0) + +#define DFS_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define DFS_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define DFS_DIFF(a, b) (DFS_MAX(a, b) - DFS_MIN(a, b)) +/* + * Maximum number of radar events to be processed in a single iteration. + * Allows soft watchdog to run. + */ +#define MAX_EVENTS 100 + +#define DFS_STATUS_SUCCESS 0 +#define DFS_STATUS_FAIL 1 + +/* + * Constants to use for chirping detection. + * + * All are unconverted as HW reports them. + * + * XXX Are these constants with or without fast clock 5GHz operation? + * XXX Peregrine reports pulses in microseconds, not hardware clocks! + */ +#define MIN_BIN5_DUR 63 /* 50 * 1.25 */ +#define MIN_BIN5_DUR_MICROSEC 50 +#define MAYBE_BIN5_DUR 35 /* 28 * 1.25 */ +#define MAYBE_BIN5_DUR_MICROSEC 28 +/* #define MAX_BIN5_DUR 131 / * 105 * 1.25* / */ +/* use 145 for osprey conversion is already done using dfs->dur_multiplier */ +#define MAX_BIN5_DUR 145 +#define MAX_BIN5_DUR_MICROSEC 105 + +#define DFS_MARGIN_EQUAL(a, b, margin) ((DFS_DIFF(a, b)) <= margin) +#define DFS_MAX_STAGGERED_BURSTS 3 + +/* + * All filter thresholds in the radar filter tables + * are effective at a 50% channel loading + */ +#define DFS_CHAN_LOADING_THRESH 50 +#define DFS_EXT_CHAN_LOADING_THRESH 30 +#define DFS_DEFAULT_PRI_MARGIN 6 +#define DFS_DEFAULT_FIXEDPATTERN_PRI_MARGIN 4 +#define ATH_DFSQ_LOCK(_dfs) cdf_spin_lock_bh((&(_dfs)->dfs_radarqlock)) +#define ATH_DFSQ_UNLOCK(_dfs) cdf_spin_unlock_bh((&(_dfs)->dfs_radarqlock)) +#define ATH_DFSQ_LOCK_INIT(_dfs) cdf_spinlock_init(&(_dfs)->dfs_radarqlock) + +#define ATH_ARQ_LOCK(_dfs) cdf_spin_lock_bh((&(_dfs)->dfs_arqlock)) +#define ATH_ARQ_UNLOCK(_dfs) cdf_spin_unlock_bh((&(_dfs)->dfs_arqlock)) +#define ATH_ARQ_LOCK_INIT(_dfs) cdf_spinlock_init(&(_dfs)->dfs_arqlock) + +#define ATH_DFSEVENTQ_LOCK(_dfs) cdf_spin_lock_bh((&(_dfs)->dfs_eventqlock)) +#define ATH_DFSEVENTQ_UNLOCK(_dfs) cdf_spin_unlock_bh((&(_dfs)->dfs_eventqlock)) +#define ATH_DFSEVENTQ_LOCK_INIT(_dfs) \ + cdf_spinlock_init((&(_dfs)->dfs_eventqlock)) +/* Mask for time stamp from descriptor */ +#define DFS_TSMASK 0xFFFFFFFF +/* Shift for time stamp from descriptor */ +#define DFS_TSSHIFT 32 +/* 64 bit TSF wrap value */ +#define DFS_TSF_WRAP 0xFFFFFFFFFFFFFFFFULL +/* TS mask for 64 bit value */ +#define DFS_64BIT_TSFMASK 0x0000000000007FFFULL + +#define DFS_AR_RADAR_RSSI_THR 5 /* in dB */ +#define DFS_AR_RADAR_RESET_INT 1 /* in secs */ +#define DFS_AR_RADAR_MAX_HISTORY 500 +#define DFS_AR_REGION_WIDTH 128 +#define DFS_AR_RSSI_THRESH_STRONG_PKTS 17 /* in dB */ +#define DFS_AR_RSSI_DOUBLE_THRESHOLD 15 /* in dB */ +#define DFS_AR_MAX_NUM_ACK_REGIONS 9 +#define DFS_AR_ACK_DETECT_PAR_THRESH 20 +#define DFS_AR_PKT_COUNT_THRESH 20 + +#define DFS_MAX_DL_SIZE 64 +#define DFS_MAX_DL_MASK 0x3F + +#define DFS_NOL_TIME DFS_NOL_TIMEOUT_US +/* 30 minutes in usecs */ + +#define DFS_WAIT_TIME (60 * 1000000) /* 1 minute in usecs */ + +#define DFS_DISABLE_TIME (3 * 60 * 1000000) /* 3 minutes in usecs */ + +#define DFS_MAX_B5_SIZE 128 +#define DFS_MAX_B5_MASK 0x0000007F /* 128 */ + +#define DFS_MAX_RADAR_OVERLAP 16 /* Max number of overlapping filters */ +/* Max number of dfs events which can be q'd */ +#define DFS_MAX_EVENTS 1024 + +#define DFS_RADAR_EN 0x80000000 /* Radar detect is capable */ +#define DFS_AR_EN 0x40000000 /* AR detect is capable */ +#define DFS_MAX_RSSI_VALUE 0x7fffffff /* Max rssi value */ +/* max num of pulses in a burst */ +#define DFS_BIN_MAX_PULSES 60 +#define DFS_BIN5_PRI_LOWER_LIMIT 990 /* us */ + +/* to cover the single pusle burst case, change from 2010 us to 2010000 us */ + +/* + * this is reverted back to 2010 as larger value causes false + * bin5 detect (EV76432, EV76320) + */ +#define DFS_BIN5_PRI_HIGHER_LIMIT 2010 /* us */ + +#define DFS_BIN5_WIDTH_MARGIN 4 /* us */ +#define DFS_BIN5_RSSI_MARGIN 5 /* dBm */ +/*Following threshold is not specified but should be okay statistically*/ +#define DFS_BIN5_BRI_LOWER_LIMIT 300000 /* us */ +#define DFS_BIN5_BRI_UPPER_LIMIT 12000000 /* us */ +/* Max number of pulses kept in buffer */ +#define DFS_MAX_PULSE_BUFFER_SIZE 1024 +#define DFS_MAX_PULSE_BUFFER_MASK 0x3ff + +#define DFS_FAST_CLOCK_MULTIPLIER (800/11) +#define DFS_NO_FAST_CLOCK_MULTIPLIER (80) + +#define DFS_WAR_PLUS_30_MHZ_SEPARATION 30 +#define DFS_WAR_MINUS_30_MHZ_SEPARATION -30 +#define DFS_WAR_PEAK_INDEX_ZERO 0 +#define DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT 11 +#define DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT 33 +#define DFS_TYPE4_WAR_PRI_LOWER_LIMIT 200 +#define DFS_TYPE4_WAR_PRI_UPPER_LIMIT 500 +#define DFS_TYPE4_WAR_VALID_PULSE_DURATION 12 +#define DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_LOWER_LIMIT 15 +#define DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_UPPER_LIMIT 33 +#define DFS_ETSI_TYPE2_WAR_PRI_LOWER_LIMIT 625 +#define DFS_ETSI_TYPE2_WAR_PRI_UPPER_LIMIT 5000 +#define DFS_ETSI_TYPE3_WAR_PRI_LOWER_LIMIT 250 +#define DFS_ETSI_TYPE3_WAR_PRI_UPPER_LIMIT 435 +#define DFS_ETSI_WAR_VALID_PULSE_DURATION 15 + +typedef cdf_spinlock_t dfsq_lock_t; + +#ifdef WIN32 +#pragma pack(push, dfs_pulseparams, 1) +#endif +struct dfs_pulseparams { + uint64_t p_time; /* time for start of pulse in usecs */ + uint8_t p_dur; /* Duration of pulse in usecs */ + uint8_t p_rssi; /* Duration of pulse in usecs */ +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_pulseparams) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_pulseline, 1) +#endif +struct dfs_pulseline { + /* pl_elems - array of pulses in delay line */ + struct dfs_pulseparams pl_elems[DFS_MAX_PULSE_BUFFER_SIZE]; + uint32_t pl_firstelem; /* Index of the first element */ + uint32_t pl_lastelem; /* Index of the last element */ + uint32_t pl_numelems; /* Number of elements in the delay line */ +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_pulseline) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_event, 1) +#endif + +#define DFS_EVENT_CHECKCHIRP 0x01 /* Whether to check the chirp flag */ +#define DFS_EVENT_HW_CHIRP 0x02 /* hardware chirp */ +#define DFS_EVENT_SW_CHIRP 0x04 /* software chirp */ + +/* + * Use this only if the event has CHECKCHIRP set. + */ +#define DFS_EVENT_ISCHIRP(e) \ + ((e)->re_flags & (DFS_EVENT_HW_CHIRP | DFS_EVENT_SW_CHIRP)) + +/* + * Check if the given event is to be rejected as not possibly + * a chirp. This means: + * (a) it's a hardware or software checked chirp, and + * (b) the HW/SW chirp bits are both 0. + */ +#define DFS_EVENT_NOTCHIRP(e) \ + (((e)->re_flags & (DFS_EVENT_CHECKCHIRP)) && \ + (!DFS_EVENT_ISCHIRP((e)))) + +struct dfs_event { + uint64_t re_full_ts; /* 64-bit full timestamp from interrupt time */ + uint32_t re_ts; /* Original 15 bit recv timestamp */ + uint8_t re_rssi; /* rssi of radar event */ + uint8_t re_dur; /* duration of radar pulse */ + uint8_t re_chanindex; /* Channel of event */ + uint8_t re_flags; /* Event flags */ + uint32_t re_freq; /* Centre frequency of event, KHz */ + uint32_t re_freq_lo; /* Lower bounds of frequency, KHz */ + uint32_t re_freq_hi; /* Upper bounds of frequency, KHz */ + int sidx; /* Pulse Index as in radar summary report */ + STAILQ_ENTRY(dfs_event) re_list; /* List of radar events */ +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_event) +#endif + +#define DFS_AR_MAX_ACK_RADAR_DUR 511 +#define DFS_AR_MAX_NUM_PEAKS 3 +#define DFS_AR_ARQ_SIZE 2048 /* 8K AR events for buffer size */ +#define DFS_AR_ARQ_SEQSIZE 2049 /* Sequence counter wrap for AR */ + +#define DFS_RADARQ_SIZE 512 /* 1K radar events for buffer size */ +#define DFS_RADARQ_SEQSIZE 513 /* Sequence counter wrap for radar */ +/* Number of radar channels we keep state for */ +#define DFS_NUM_RADAR_STATES 64 +/* Max number radar filters for each type */ +#define DFS_MAX_NUM_RADAR_FILTERS 10 +/* Number of different radar types */ +#define DFS_MAX_RADAR_TYPES 32 + +struct dfs_ar_state { + uint32_t ar_prevwidth; + uint32_t ar_phyerrcount[DFS_AR_MAX_ACK_RADAR_DUR]; + uint32_t ar_acksum; + uint32_t ar_packetthreshold; /* Thresh to determine traffic load */ + uint32_t ar_parthreshold; /* Thresh to determine peak */ + uint32_t ar_radarrssi; /* Rssi threshold for AR event */ + uint16_t ar_prevtimestamp; + uint16_t ar_peaklist[DFS_AR_MAX_NUM_PEAKS]; +}; + +#ifdef WIN32 +#pragma pack(push, dfs_delayelem, 1) +#endif +struct dfs_delayelem { + /* Current "filter" time for start of pulse in usecs */ + uint32_t de_time; + /* Duration of pulse in usecs */ + uint8_t de_dur; + /* rssi of pulse in dB */ + uint8_t de_rssi; + /* time stamp for this delay element */ + uint64_t de_ts; +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_delayelem) +#endif + +/* NB: The first element in the circular buffer is the oldest element */ + +#ifdef WIN32 +#pragma pack(push, dfs_delayline, 1) +#endif +struct dfs_delayline { + /* Array of pulses in delay line */ + struct dfs_delayelem dl_elems[DFS_MAX_DL_SIZE]; + /* Last timestamp the delay line was used (in usecs) */ + uint64_t dl_last_ts; + /* Index of the first element */ + uint32_t dl_firstelem; + /* Index of the last element */ + uint32_t dl_lastelem; + /* Number of elements in the delay line */ + uint32_t dl_numelems; +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_delayline) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_filter, 1) +#endif +struct dfs_filter { + /* Delay line of pulses for this filter */ + struct dfs_delayline rf_dl; + /* Number of pulses in the filter */ + uint32_t rf_numpulses; + /* min pri to be considered for this filter */ + uint32_t rf_minpri; + /* max pri to be considered for this filter */ + uint32_t rf_maxpri; + /* match filter output threshold for radar detect */ + uint32_t rf_threshold; + /* Length (in usecs) of the filter */ + uint32_t rf_filterlen; + /* fixed or variable pattern type */ + uint32_t rf_patterntype; + /* indicates if it is a fixed pri pulse */ + uint32_t rf_fixed_pri_radar_pulse; + /* Min duration for this radar filter */ + uint32_t rf_mindur; + /* Max duration for this radar filter */ + uint32_t rf_maxdur; + uint32_t rf_ignore_pri_window; + /* Unique ID corresponding to the original filter ID */ + uint32_t rf_pulseid; +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_filter) +#endif + +struct dfs_filtertype { + struct dfs_filter ft_filters[DFS_MAX_NUM_RADAR_FILTERS]; + /* Duration of pulse which specifies filter type */ + uint32_t ft_filterdur; + /* Num filters of this type */ + uint32_t ft_numfilters; + /* Last timestamp this filtertype was used(in usecs) */ + uint64_t ft_last_ts; + /* min pulse duration to be considered for this filter type */ + uint32_t ft_mindur; + /* max pulse duration to be considered for this filter type */ + uint32_t ft_maxdur; + /* min rssi to be considered for this filter type */ + uint32_t ft_rssithresh; + /* Num pulses in each filter of this type */ + uint32_t ft_numpulses; + /* fixed or variable pattern type */ + uint32_t ft_patterntype; + /* min pri to be considered for this type */ + uint32_t ft_minpri; + /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dB lower than in non TURBO + * mode. This will offset that diff. + */ + uint32_t ft_rssimargin; +}; + +struct dfs_state { + struct ieee80211_channel rs_chan; /* Channel info */ + uint8_t rs_chanindex; /* Channel index in radar structure */ + uint32_t rs_numradarevents; /* Number of radar events */ + + struct ath_dfs_phyerr_param rs_param; +}; + +/* 30 minutes in seconds */ +#define DFS_NOL_TIMEOUT_S (30*60) +/* 5 minutes in seconds - debugging */ +/* #define DFS_NOL_TIMEOUT_S (5*60) */ +#define DFS_NOL_TIMEOUT_MS (DFS_NOL_TIMEOUT_S * 1000) +#define DFS_NOL_TIMEOUT_US (DFS_NOL_TIMEOUT_MS * 1000) + +#ifdef WIN32 +#pragma pack(push, dfs_nolelem, 1) +#endif +struct dfs_nolelem { + uint32_t nol_freq; /* centre frequency */ + uint32_t nol_chwidth; /* event width (MHz) */ + unsigned long nol_start_ticks; /* NOL start time in OS ticks */ + uint32_t nol_timeout_ms; /* NOL timeout value in msec */ + os_timer_t nol_timer; /* per element NOL timer */ + struct dfs_nolelem *nol_next; /* next element pointer */ +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_nolelem) +#endif + +/* Pass structure to DFS NOL timer */ +struct dfs_nol_timer_arg { + struct ath_dfs *dfs; + uint16_t delfreq; + uint16_t delchwidth; +}; + +#ifdef WIN32 +#pragma pack(push, dfs_info, 1) +#endif +struct dfs_info { + /* Use the NOL when radar found (default: true) */ + int rn_use_nol; + /* Number of different types of radars */ + uint32_t rn_numradars; + /* Last 64 bit timstamp from recv interrupt */ + uint64_t rn_lastfull_ts; + /* last 15 bit ts from recv descriptor */ + uint16_t rn_last_ts; + /* last unique 32 bit ts from recv descriptor */ + uint32_t rn_last_unique_ts; + /* Prefix to prepend to 15 bit recv ts */ + uint64_t rn_ts_prefix; + /* Number of bin5 radar pulses to search for */ + uint32_t rn_numbin5radars; + /* Value of fast diversity gc limit from init file */ + uint32_t rn_fastdivGCval; + /* Min rssi for all radar types */ + int32_t rn_minrssithresh; + /* Max pulse width in TSF ticks */ + uint32_t rn_maxpulsedur; + + uint8_t dfs_ext_chan_busy; + uint64_t ext_chan_busy_ts; + + uint64_t dfs_bin5_chirp_ts; + uint8_t dfs_last_bin5_dur; +} cdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_info) +#endif + +struct dfs_bin5elem { + uint64_t be_ts; /* Timestamp for the bin5 element */ + uint32_t be_rssi; /* Rssi for the bin5 element */ + uint32_t be_dur; /* Duration of bin5 element */ +}; + +struct dfs_bin5radars { + /* List of bin5 elems that fall within the time window */ + struct dfs_bin5elem br_elems[DFS_MAX_B5_SIZE]; + /* Index of the first element */ + uint32_t br_firstelem; + /* Index of the last element */ + uint32_t br_lastelem; + /* Number of elements in the delay line */ + uint32_t br_numelems; + /* Original info about bin5 pulse */ + struct dfs_bin5pulse br_pulse; +}; + +struct dfs_stats { + uint32_t num_radar_detects; /* total num. of radar detects */ + uint32_t total_phy_errors; + uint32_t owl_phy_errors; + uint32_t pri_phy_errors; + uint32_t ext_phy_errors; + uint32_t dc_phy_errors; + uint32_t early_ext_phy_errors; + uint32_t bwinfo_errors; + uint32_t datalen_discards; + uint32_t rssi_discards; + uint64_t last_reset_tstamp; +}; + +/* + * This is for debuggin DFS as console log interferes with (helps) + * radar detection + */ + +#define DFS_EVENT_LOG_SIZE 256 +struct dfs_event_log { + uint64_t ts; /* 64-bit full timestamp from interrupt time */ + uint32_t diff_ts; /* diff timestamp */ + uint8_t rssi; /* rssi of radar event */ + uint8_t dur; /* duration of radar pulse */ +}; + +#define ATH_DFS_RESET_TIME_S 7 +#define ATH_DFS_WAIT (60 + ATH_DFS_RESET_TIME_S) /* 60 seconds */ +#define ATH_DFS_WAIT_MS ((ATH_DFS_WAIT) * 1000) /*in MS */ + +#define ATH_DFS_WEATHER_CHANNEL_WAIT_MIN 10 /*10 minutes */ +#define ATH_DFS_WEATHER_CHANNEL_WAIT_S (ATH_DFS_WEATHER_CHANNEL_WAIT_MIN * 60) +#define ATH_DFS_WEATHER_CHANNEL_WAIT_MS \ + ((ATH_DFS_WEATHER_CHANNEL_WAIT_S) * 1000) /*in MS */ + +#define ATH_DFS_WAIT_POLL_PERIOD 2 /* 2 seconds */ +/*in MS */ +#define ATH_DFS_WAIT_POLL_PERIOD_MS ((ATH_DFS_WAIT_POLL_PERIOD) * 1000) +#define ATH_DFS_TEST_RETURN_PERIOD 2 /* 2 seconds */ +/* n MS */ +#define ATH_DFS_TEST_RETURN_PERIOD_MS ((ATH_DFS_TEST_RETURN_PERIOD) * 1000) +#define IS_CHANNEL_WEATHER_RADAR(chan) ((chan->ic_freq >= 5600) && \ + (chan->ic_freq <= 5650)) + +#define DFS_DEBUG_TIMEOUT_S 30 /* debug timeout is 30 seconds */ +#define DFS_DEBUG_TIMEOUT_MS (DFS_DEBUG_TIMEOUT_S * 1000) + +#define RSSI_POSSIBLY_FALSE 50 +#define SEARCH_FFT_REPORT_PEAK_MAG_THRSH 40 + +struct ath_dfs { + uint32_t dfs_debug_mask; /* current debug bitmask */ + int16_t dfs_curchan_radindex; /* cur. channel radar index */ + int16_t dfs_extchan_radindex; /* extension channel radar index */ + uint32_t dfsdomain; /* cur. DFS domain */ + uint32_t dfs_proc_phyerr; /* Flags for Phy Errs to process */ + struct ieee80211com *ic; + STAILQ_HEAD(, dfs_event) dfs_eventq; /* Q of free dfs event objects */ + dfsq_lock_t dfs_eventqlock; /* Lock for free dfs event list */ + STAILQ_HEAD(, dfs_event) dfs_radarq; /* Q of radar events */ + dfsq_lock_t dfs_radarqlock; /* Lock for dfs q */ + STAILQ_HEAD(, dfs_event) dfs_arq; /* Q of AR events */ + dfsq_lock_t dfs_arqlock; /* Lock for AR q */ + + struct dfs_ar_state dfs_ar_state; /* AR state */ + + /* dfs_radar - Per-Channel Radar detector state */ + struct dfs_state dfs_radar[DFS_NUM_RADAR_STATES]; + + /* dfs_radarf - One filter for each radar pulse type */ + struct dfs_filtertype *dfs_radarf[DFS_MAX_RADAR_TYPES]; + + struct dfs_info dfs_rinfo; /* State vars for radar processing */ + struct dfs_bin5radars *dfs_b5radars; /* array of bin5 radar events */ + int8_t **dfs_radartable; /* map of radar durs to filter types */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + struct dfs_nolelem *dfs_nol; /* Non occupancy list for radar */ + int dfs_nol_count; /* How many items? */ +#endif + /* Default phy params per radar state */ + struct ath_dfs_phyerr_param dfs_defaultparams; + struct dfs_stats ath_dfs_stats; /* DFS related stats */ + struct dfs_pulseline *pulses; /* pulse history */ + struct dfs_event *events; /* Events structure */ + + uint32_t ath_radar_tasksched:1, /* radar task is scheduled */ + ath_dfswait:1, /* waiting on channel for radar detect */ + ath_dfstest:1; /* Test timer in progress */ + struct ath_dfs_caps dfs_caps; + /* IEEE chan num to return to after + * a dfs mute test + */ + uint8_t ath_dfstest_ieeechan; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + uint32_t ath_dfs_cac_time; /* CAC period */ + uint32_t ath_dfstesttime; /* Time to stay off chan during dfs test */ + os_timer_t ath_dfswaittimer; /* dfs wait timer */ + os_timer_t ath_dfstesttimer; /* dfs mute test timer */ + os_timer_t ath_dfs_debug_timer; /* dfs debug timer */ + uint8_t dfs_bangradar; +#endif + os_timer_t ath_dfs_task_timer; /* dfs wait timer */ + int dur_multiplier; + + uint16_t ath_dfs_isdfsregdomain; /* true when we are DFS domain */ + int ath_dfs_false_rssi_thres; + int ath_dfs_peak_mag; + + struct dfs_event_log radar_log[DFS_EVENT_LOG_SIZE]; + int dfs_event_log_count; + int dfs_event_log_on; + int dfs_phyerr_count; /* same as number of PHY radar interrupts */ + /* + * when TLV is supported, # of radar events ignored after TLV is parsed + */ + int dfs_phyerr_reject_count; + /* number of radar events queued for matching the filters */ + int dfs_phyerr_queued_count; + int dfs_phyerr_freq_min; + int dfs_phyerr_freq_max; + int dfs_phyerr_w53_counter; + /* allow pulse if they are within multiple of PRI for the radar type */ + int dfs_pri_multiplier; + int ath_dfs_nol_timeout; + int dfs_pri_multiplier_ini; /* dfs pri configuration from ini */ + /* + * Flag to indicate if DFS test mode is enabled and + * channel switch is disabled. + */ + int8_t disable_dfs_ch_switch; +}; + +/* This should match the table from if_ath.c */ +enum { + ATH_DEBUG_DFS = 0x00000100, /* Minimal DFS debug */ + ATH_DEBUG_DFS1 = 0x00000200, /* Normal DFS debug */ + ATH_DEBUG_DFS2 = 0x00000400, /* Maximal DFS debug */ + ATH_DEBUG_DFS3 = 0x00000800, /* matched filterID display */ + + ATH_DEBUG_DFS_PHYERR = 0x00001000, /* phy error parsing */ + ATH_DEBUG_DFS_NOL = 0x00002000, /* NOL related entries */ + ATH_DEBUG_DFS_PHYERR_SUM = 0x00004000, /* PHY error summary */ + ATH_DEBUG_DFS_PHYERR_PKT = 0x00008000, /* PHY error payload */ + + ATH_DEBUG_DFS_BIN5 = 0x00010000, /* bin5 checks */ + ATH_DEBUG_DFS_BIN5_FFT = 0x00020000, /* bin5 FFT check */ + ATH_DEBUG_DFS_BIN5_PULSE = 0x00040000, /* bin5 pulse check */ +}; + +#define IS_CHAN_HT40(_c) IEEE80211_IS_CHAN_11N_HT40(_c) +#define IS_CHAN_HT40_PLUS(_c) IEEE80211_IS_CHAN_11N_HT40PLUS(_c) +#define IS_CHAN_HT40_MINUS(_c) IEEE80211_IS_CHAN_11N_HT40MINUS(_c) + +/* + * chirp notes! + * + * Pre-Sowl chips don't do FFT reports, so chirp pulses simply show up + * as long duration pulses. + * + * The bin5 checking code would simply look for a chirp pulse of the correct + * duration (within MIN_BIN5_DUR and MAX_BIN5_DUR) and add it to the "chirp" + * pattern. + * + * For Sowl and later, an FFT was done on longer duration frames. If those + * frames looked like a chirp, their duration was adjusted to fall within + * the chirp duration limits. If the pulse failed the chirp test (it had + * no FFT data or the FFT didn't meet the chirping requirements) then the + * pulse duration was adjusted to be greater than MAX_BIN5_DUR, so it + * would always fail chirp detection. + * + * This is pretty horrible. + * + * The eventual goal for chirp handling is thus: + * + * + In case someone ever wants to do chirp detection with this code on + * chips that don't support chirp detection, you can still do it based + * on pulse duration. That's your problem to solve. + * + * + For chips that do hardware chirp detection or FFT, the "do_check_chirp" + * bit should be set. + * + * + Then, either is_hw_chirp or is_sw_chirp is set, indicating that + * the hardware or software post-processing of the chirp event found + * that indeed it was a chirp. + * + * + Finally, the bin5 code should just check whether the chirp bits are + * set and behave appropriately, falling back onto the duration checks + * if someone wishes to use this on older hardware (or with disabled + * FFTs, for whatever reason.) + */ +/* + * XXX TODO: + * + * + add duration in uS and raw duration, so the PHY error parsing + * code is responsible for doing the duration calculation; + * + add ts in raw and corrected, so the PHY error parsing + * code is responsible for doing the offsetting, not the radar + * event code. + */ +struct dfs_phy_err { + uint64_t fulltsf; /* 64-bit TSF as read from MAC */ + + uint32_t is_pri:1, /* detected on primary channel */ + is_ext:1, /* detected on extension channel */ + is_dc:1, /* detected at DC */ + is_early:1, /* early detect */ + do_check_chirp:1, /* whether to check hw_chirp/sw_chirp */ + is_hw_chirp:1, /* hardware-detected chirp */ + is_sw_chirp:1; /* software detected chirp */ + + uint32_t rs_tstamp; /* 32 bit TSF from RX descriptor (event) */ + uint32_t freq; /* Centre frequency of event - KHz */ + uint32_t freq_lo; /* Lower bounds of frequency - KHz */ + uint32_t freq_hi; /* Upper bounds of frequency - KHz */ + + uint8_t rssi; /* pulse RSSI */ + uint8_t dur; /* pulse duration, raw (not uS) */ + int sidx; /* Pulse Index as in radar summary report */ +}; + +/* Attach, detach, handle ioctl prototypes */ + +int dfs_get_thresholds(struct ieee80211com *ic, + struct ath_dfs_phyerr_param *param); +int dfs_set_thresholds(struct ieee80211com *ic, + const uint32_t threshtype, const uint32_t value); + +/* PHY error and radar event handling */ +int dfs_process_radarevent(struct ath_dfs *dfs, struct ieee80211_channel *chan); + +/* Non occupancy (NOL) handling prototypes */ +void dfs_nol_addchan(struct ath_dfs *dfs, struct ieee80211_channel *chan, + uint32_t dfs_nol_timeout); +void dfs_get_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, + int *nchan); +void dfs_set_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, + int nchan); +void dfs_nol_update(struct ath_dfs *dfs); +void dfs_nol_timer_cleanup(struct ath_dfs *dfs); + +/* FCC Bin5 detection prototypes */ +int dfs_bin5_check_pulse(struct ath_dfs *dfs, struct dfs_event *re, + struct dfs_bin5radars *br); +int dfs_bin5_addpulse(struct ath_dfs *dfs, struct dfs_bin5radars *br, + struct dfs_event *re, uint64_t thists); +int dfs_bin5_check(struct ath_dfs *dfs); +int dfs_check_chirping(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, + int is_ext, int *slope, int *is_dc); +uint8_t dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur); +uint8_t dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur); +int dfs_get_random_bin5_dur(struct ath_dfs *dfs, uint64_t tstamp); + +/* Debug prototypes */ +void dfs_print_delayline(struct ath_dfs *dfs, struct dfs_delayline *dl); +void dfs_print_nol(struct ath_dfs *dfs); +void dfs_print_filters(struct ath_dfs *dfs); +void dfs_print_activity(struct ath_dfs *dfs); +os_timer_func(dfs_debug_timeout); +void dfs_print_filter(struct ath_dfs *dfs, struct dfs_filter *rf); + +/* Misc prototypes */ +uint32_t dfs_round(int32_t val); +struct dfs_state *dfs_getchanstate(struct ath_dfs *dfs, uint8_t *index, + int ext_ch_flag); + +/* Reset and init data structures */ + +int dfs_init_radar_filters(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info); +void dfs_reset_alldelaylines(struct ath_dfs *dfs); +void dfs_reset_delayline(struct dfs_delayline *dl); +void dfs_reset_filter_delaylines(struct dfs_filtertype *dft); +void dfs_reset_radarq(struct ath_dfs *dfs); + +/* Detection algorithm prototypes */ +void dfs_add_pulse(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_event *re, uint32_t deltaT, uint64_t this_ts); + +int dfs_bin_fixedpattern_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t dur, int ext_chan_flag); +int dfs_bin_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t dur, int ext_chan_flag); + +int dfs_bin_pri_check(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_delayline *dl, uint32_t score, + uint32_t refpri, uint32_t refdur, int ext_chan_flag, + int fundamentalpri); +int dfs_staggered_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t width); +/* False detection reduction */ +int dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect, + int is_fixed_pattern); +int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf, + int is_extchan_detect); + +/* AR related prototypes */ + +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void dfs_process_ar_event(struct ath_dfs *dfs, + * struct ieee80211_channel *chan); + */ +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void ath_ar_disable(struct ath_dfs *dfs); + */ +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void ath_ar_enable(struct ath_dfs *dfs); + */ +void dfs_reset_ar(struct ath_dfs *dfs); +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void dfs_reset_arq(struct ath_dfs *dfs); + */ + +struct ieee80211_channel *ieee80211_get_extchan(struct ieee80211com *ic); + +#endif /* _DFS_H_ */ diff --git a/core/sap/dfs/inc/dfs_interface.h b/core/sap/dfs/inc/dfs_interface.h new file mode 100644 index 0000000000..ce0a49bcf9 --- /dev/null +++ b/core/sap/dfs/inc/dfs_interface.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_interface.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef _DFS__INTERFACE_H_ +#define _DFS__INTERFACE_H_ + +/* + * These are the only functions exported to the upper (device) layer. + */ + +/* + * EXPORT_SYMBOL(dfs_attach); + * EXPORT_SYMBOL(dfs_detach); + * EXPORT_SYMBOL(dfs_radar_enable); + * EXPORT_SYMBOL(dfs_process_phyerr); + * EXPORT_SYMBOL(dfs_control); + * EXPORT_SYMBOL(dfs_clear_stats); + * EXPORT_SYMBOL(dfs_usenol); + * EXPORT_SYMBOL(dfs_isdfsregdomain); + */ + +/* + * These are exported but not currently defined here; these should be + * evaluated. + * + * EXPORT_SYMBOL(dfs_process_ar_event); -- legacy adaptive radio processing + * EXPORT_SYMBOL(ath_ar_disable); + * EXPORT_SYMBOL(ath_ar_enable); + * EXPORT_SYMBOL(dfs_get_thresholds); + * EXPORT_SYMBOL(dfs_init_radar_filters); + * EXPORT_SYMBOL(dfs_getchanstate); + */ + +uint16_t dfs_isdfsregdomain(struct ieee80211com *ic); +int dfs_attach(struct ieee80211com *ic); +void dfs_detach(struct ieee80211com *ic); +int dfs_radar_enable(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *ri); +int dfs_radar_disable(struct ieee80211com *ic); +extern void dfs_process_phyerr(struct ieee80211com *ic, void *buf, + uint16_t datalen, uint8_t rssi, uint8_t ext_rssi, + uint32_t rs_tstamp, uint64_t fulltsf, + bool enable_log); +int dfs_control(struct ieee80211com *ic, u_int id, void *indata, + uint32_t insize, void *outdata, uint32_t *outsize); +void dfs_clear_stats(struct ieee80211com *ic); +#if 0 +/* The following are for FCC Bin 1-4 pulses */ +struct dfs_pulse dfs_fcc_radars[] = { + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 11, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 8, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 7, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_pulse dfs_mkk4_radars[] = { + /* following two filters are specific to Japan/MKK4 */ +/* {18, 1, 720, 720, 1, 6, 6, 0, 1, 18, 0, 3, 17}, // 1389 +/- 6 us */ +/* {18, 4, 250, 250, 1, 10, 5, 1, 6, 18, 0, 3, 18}, // 4000 +/- 6 us */ +/* {18, 5, 260, 260, 1, 10, 6, 1, 6, 18, 0, 3, 19}, // 3846 +/- 7 us */ + {18, 1, 720, 720, 0, 6, 6, 0, 1, 18, 0, 3, 0, 17}, /* 1389 +/- 6 us */ + {18, 4, 250, 250, 0, 10, 5, 1, 6, 18, 0, 3, 0, 18}, /* 4000 +/- 6 us */ + {18, 5, 260, 260, 0, 10, 6, 1, 6, 18, 0, 3, 1, 19}, /* 3846 +/- 7 us */ + + /* following filters are common to both FCC and JAPAN */ + + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 11, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 8, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 7, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_bin5pulse dfs_fcc_bin5pulses[] = { + {4, 28, 105, 12, 22, 5}, +}; + +struct dfs_bin5pulse dfs_jpn_bin5pulses[] = { + {5, 28, 105, 12, 22, 5}, +}; + +struct dfs_pulse dfs_etsi_radars[] = { + + /* TYPE staggered pulse */ + /* 0.8-2us, 2-3 bursts,300-400 PRF, 10 pulses each */ + {30, 2, 300, 400, 2, 30, 3, 0, 5, 15, 0, 0, 1, 31}, /* Type 5 */ + /* 0.8-2us, 2-3 bursts, 400-1200 PRF, 15 pulses each */ + {30, 2, 400, 1200, 2, 30, 7, 0, 5, 15, 0, 0, 0, 32}, /* Type 6 */ + + /* constant PRF based */ + /* 0.8-5us, 200 300 PRF, 10 pulses */ + {10, 5, 200, 400, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, /* Type 1 */ + {10, 5, 400, 600, 0, 24, 5, 0, 8, 15, 0, 0, 2, 37}, /* Type 1 */ + {10, 5, 600, 800, 0, 24, 5, 0, 8, 15, 0, 0, 2, 38}, /* Type 1 */ + {10, 5, 800, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 39}, /* Type 1 */ +/* {10, 5, 200, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, */ + + /* 0.8-15us, 200-1600 PRF, 15 pulses */ + {15, 15, 200, 1600, 0, 24, 8, 0, 18, 24, 0, 0, 0, 34}, /* Type 2 */ + + /* 0.8-15us, 2300-4000 PRF, 25 pulses */ + {25, 15, 2300, 4000, 0, 24, 10, 0, 18, 24, 0, 0, 0, 35}, /* Type 3 */ + + /* 20-30us, 2000-4000 PRF, 20 pulses */ + {20, 30, 2000, 4000, 0, 24, 6, 19, 33, 24, 0, 0, 0, 36}, /* Type 4 */ +}; +#endif +#endif /* _DFS__INTERFACE_H_ */ diff --git a/core/sap/dfs/inc/radar_filters.h b/core/sap/dfs/inc/radar_filters.h new file mode 100644 index 0000000000..5837d06a27 --- /dev/null +++ b/core/sap/dfs/inc/radar_filters.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + radar_filters.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +struct dfs_pulse dfs_fcc_radars[] = { + /* FCC NEW TYPE 0 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 8, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 6, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 5, 11, 23, 22, 0, 3, 0, 11}, + + /* + * FCC NEW TYPE 1 + * 518us to 938us pulses (min 56 pulses) + */ + {57, 1, 1066, 1930, 0, 6, 20, 0, 1, 22, 0, 3, 0, 21}, + + /* + * FCC NEW TYPE 1 + * 938us to 2000 pulses (min 26 pulses) + */ + {27, 1, 500, 1066, 0, 6, 13, 0, 1, 22, 0, 3, 0, 22}, + + /* + * FCC NEW TYPE 1 + * 2000 to 3067us pulses (min 17 pulses) + */ + {18, 1, 325, 500, 0, 6, 9, 0, 1, 22, 0, 3, 0, 23}, +}; + +struct dfs_pulse dfs_mkk4_radars[] = { + /* following two filters are specific to Japan/MKK4 */ +/* {18, 1, 720, 720, 1, 6, 6, 0, 1, 18, 0, 3, 17}, // 1389 +/- 6 us */ +/* {18, 4, 250, 250, 1, 10, 5, 1, 6, 18, 0, 3, 18}, // 4000 +/- 6 us */ +/* {18, 5, 260, 260, 1, 10, 6, 1, 6, 18, 0, 3, 19}, // 3846 +/- 7 us */ + {18, 1, 720, 720, 0, 6, 6, 0, 1, 18, 0, 3, 0, 17}, /* 1389 +/- 6 us */ + {18, 4, 250, 250, 0, 10, 5, 1, 6, 18, 0, 3, 0, 18}, /* 4000 +/- 6 us */ + {18, 5, 260, 260, 0, 10, 6, 1, 6, 18, 0, 3, 1, 19}, /* 3846 +/- 7 us */ + + /* following filters are common to both FCC and JAPAN */ + + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 8, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 6, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 5, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_bin5pulse dfs_fcc_bin5pulses[] = { + {4, 28, 105, 12, 17, 5}, +}; + +struct dfs_bin5pulse dfs_jpn_bin5pulses[] = { + {5, 28, 105, 12, 22, 5}, +}; + +struct dfs_pulse dfs_etsi_radars[] = { + + /* TYPE staggered pulse */ + /* 0.8-2us, 2-3 bursts,300-400 PRF, 10 pulses each */ + {30, 2, 300, 400, 2, 30, 3, 0, 5, 15, 0, 0, 1, 31}, /* Type 5 */ + /* 0.8-2us, 2-3 bursts, 400-1200 PRF, 15 pulses each */ + {30, 2, 400, 1200, 2, 30, 7, 0, 5, 15, 0, 0, 0, 32}, /* Type 6 */ + + /* constant PRF based */ + /* 0.8-5us, 200 300 PRF, 10 pulses */ + {10, 5, 200, 400, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, /* Type 1 */ + {10, 5, 400, 600, 0, 24, 5, 0, 8, 15, 0, 0, 2, 37}, /* Type 1 */ + {10, 5, 600, 800, 0, 24, 5, 0, 8, 15, 0, 0, 2, 38}, /* Type 1 */ + {10, 5, 800, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 39}, /* Type 1 */ +/* {10, 5, 200, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, */ + + /* 0.8-15us, 200-1600 PRF, 15 pulses */ + {15, 15, 200, 1600, 0, 24, 8, 0, 18, 22, 0, 0, 0, 34}, /* Type 2 */ + + /* 0.8-15us, 2300-4000 PRF, 25 pulses */ + {25, 15, 2300, 4000, 0, 24, 10, 0, 18, 22, 0, 0, 0, 35}, /* Type 3 */ + + /* 20-30us, 2000-4000 PRF, 20 pulses */ + {20, 30, 2000, 4000, 0, 24, 6, 19, 33, 24, 0, 0, 0, 36}, /* Type 4 */ +}; diff --git a/core/sap/dfs/sources b/core/sap/dfs/sources new file mode 100644 index 0000000000..3899f4156c --- /dev/null +++ b/core/sap/dfs/sources @@ -0,0 +1,62 @@ +# +# sources file for DFS module +# +LMAC=.. +TOP=$(LMAC)\.. +INC=$(TOP)\include +HAL=$(TOP)\hal +ATH=$(LMAC)\ath_dev + +!IFDEF BUILD_UMAC +MP=$(TOP)\os\win_nwf +INC_MP=$(MP)\include +IF_ATH=$(TOP)\umac\if_lmac +!ELSE +MP=$(TOP)\winvista +INC_MP=$(INC)\winvista +IF_ATH=$(TOP)\if_ath_net80211 +!ENDIF + +!include $(INC_MP)\sources.inc + +TARGETNAME=ath_dfs +TARGETPATH=$(TOP)\lib +TARGETTYPE=LIBRARY + +!IFDEF BUILD_HTC +# Put htc include dirs at the head of the list. +# This ensures that the htc/cdf header files will preempt any +# header files of the same names from the regular cdf directories. +INCLUDES= $(INCLUDES) \ + $(TOP)\htc\inc; \ + $(TOP)\htc\adf\include; \ + $(TOP)\htc\adf\winvista\nbuf; \ + $(TOP)\htc\adf\winvista\include; +!ENDIF + +INCLUDES= $(INCLUDES) \ + $(TOP); \ + $(ATH); \ + $(ATH_DFS); \ + $(TOP)\ath\winvista; \ + $(TOP)\ath\winvista; \ + $(HAL); \ + $(HAL)\winvista; \ + $(IF_ATH); \ + $(INC); \ + $(INC_MP); \ + $(SDXROOT)\net\inc; \ + $(DDK_INC_PATH) + +SOURCES=$(SOURCES) \ + dfs_staggered.c \ + dfs_bindetects.c \ + dfs_misc.c \ + dfs_debug.c \ + dfs_process_radarevent.c \ + dfs_process_phyerr.c \ + dfs_nol.c \ + dfs_ar.c \ + dfs_fcc_bin5.c \ + dfs_init.c \ + dfs.c diff --git a/core/sap/dfs/src/dfs.c b/core/sap/dfs/src/dfs.c new file mode 100644 index 0000000000..a9191517f5 --- /dev/null +++ b/core/sap/dfs/src/dfs.c @@ -0,0 +1,993 @@ +/* + * Copyright (c) 2002-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include + +#ifndef ATH_SUPPORT_DFS +#define ATH_SUPPORT_DFS 1 + +/* #include "if_athioctl.h" */ +/* #include "if_athvar.h" */ +#include "dfs_ioctl.h" +#include "dfs.h" + +int domainoverride = DFS_UNINIT_DOMAIN; + +/* +** channel switch announcement (CSA) +** usenol=1 (default) make CSA and switch to a new channel on radar detect +** usenol=0, make CSA with next channel same as current on radar detect +** usenol=2, no CSA and stay on the same channel on radar detect +**/ + +int usenol = 1; +uint32_t dfs_debug_level = ATH_DEBUG_DFS; + +#if 0 /* the code to call this is curently commented-out below */ +/* + * Mark a channel as having interference detected upon it. + * + * This adds the interference marker to both the primary and + * extension channel. + * + * XXX TODO: make the NOL and channel interference logic a bit smarter + * so only the channel with the radar event is marked, rather than + * both the primary and extension. + */ +static void +dfs_channel_mark_radar(struct ath_dfs *dfs, struct ieee80211_channel *chan) +{ + struct ieee80211_channel_list chan_info; + int i; + + /* chan->ic_flagext |= CHANNEL_INTERFERENCE; */ + + /* + * If radar is detected in 40MHz mode, add both the primary and the + * extension channels to the NOL. chan is the channel data we return + * to the ath_dev layer which passes it on to the 80211 layer. + * As we want the AP to change channels and send out a CSA, + * we always pass back the primary channel data to the ath_dev layer. + */ + if ((dfs->dfs_rinfo.rn_use_nol == 1) && + (dfs->ic->ic_opmode == IEEE80211_M_HOSTAP || + dfs->ic->ic_opmode == IEEE80211_M_IBSS)) { + chan_info.cl_nchans = 0; + dfs->ic->ic_get_ext_chan_info(dfs->ic, &chan_info); + + for (i = 0; i < chan_info.cl_nchans; i++) { + if (chan_info.cl_channels[i] == NULL) { + DFS_PRINTK("%s: NULL channel\n", __func__); + } else { + chan_info.cl_channels[i]->ic_flagext |= + CHANNEL_INTERFERENCE; + dfs_nol_addchan(dfs, chan_info.cl_channels[i], + dfs->ath_dfs_nol_timeout); + } + } + + /* + * Update the umac/driver channels with the new NOL information. + */ + dfs_nol_update(dfs); + } +} +#endif /* #if 0 */ + +static os_timer_func(dfs_task) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs = NULL; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + dfs = (struct ath_dfs *)ic->ic_dfs; + /* + * XXX no locking?! + */ + if (dfs_process_radarevent(dfs, ic->ic_curchan)) { +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + + /* + * This marks the channel (and the extension channel, if HT40) as + * having seen a radar event. It marks CHAN_INTERFERENCE and + * will add it to the local NOL implementation. + * + * This is only done for 'usenol=1', as the other two modes + * don't do radar notification or CAC/CSA/NOL; it just notes + * there was a radar. + */ + + if (dfs->dfs_rinfo.rn_use_nol == 1) { + /* dfs_channel_mark_radar(dfs, ic->ic_curchan); */ + } +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + + /* + * This calls into the umac DFS code, which sets the umac related + * radar flags and begins the channel change machinery. + * + * XXX TODO: the umac NOL code isn't used, but IEEE80211_CHAN_RADAR + * still gets set. Since the umac NOL code isn't used, that flag + * is never cleared. This needs to be fixed. See EV 105776. + */ + if (dfs->dfs_rinfo.rn_use_nol == 1) { + ic->ic_dfs_notify_radar(ic, ic->ic_curchan); + } else if (dfs->dfs_rinfo.rn_use_nol == 0) { + /* + * For the test mode, don't do a CSA here; but setup the + * test timer so we get a CSA _back_ to the original channel. + */ + OS_CANCEL_TIMER(&dfs->ath_dfstesttimer); + dfs->ath_dfstest = 1; + dfs->ath_dfstest_ieeechan = ic->ic_curchan->ic_ieee; + dfs->ath_dfstesttime = 1; /* 1ms */ + OS_SET_TIMER(&dfs->ath_dfstesttimer, + dfs->ath_dfstesttime); + } + } + dfs->ath_radar_tasksched = 0; +} + +static os_timer_func(dfs_testtimer_task) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs = NULL; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + dfs = (struct ath_dfs *)ic->ic_dfs; + + /* XXX no locking? */ + dfs->ath_dfstest = 0; + + /* + * Flip the channel back to the original channel. + * Make sure this is done properly with a CSA. + */ + DFS_PRINTK("%s: go back to channel %d\n", + __func__, dfs->ath_dfstest_ieeechan); + + /* + * XXX The mere existence of this method indirection + * to a umac function means this code belongs in + * the driver, _not_ here. Please fix this! + */ + ic->ic_start_csa(ic, dfs->ath_dfstest_ieeechan); +} + +static int dfs_get_debug_info(struct ieee80211com *ic, int type, void *data) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + if (data) { + *(uint32_t *) data = dfs->dfs_proc_phyerr; + } + return (int)dfs->dfs_proc_phyerr; +} + +int dfs_attach(struct ieee80211com *ic) +{ + int i, n; + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct ath_dfs_radar_tab_info radar_info; + + if (dfs != NULL) { + /*DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: ic_dfs was not NULL\n", + __func__); + */ + return 1; + } + + dfs = + (struct ath_dfs *)os_malloc(NULL, sizeof(struct ath_dfs), + GFP_ATOMIC); + + if (dfs == NULL) { + /*DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: ath_dfs allocation failed\n", __func__); */ + return 1; + } + + OS_MEMZERO(dfs, sizeof(struct ath_dfs)); + + ic->ic_dfs = (void *)dfs; + + dfs->ic = ic; + + ic->ic_dfs_debug = dfs_get_debug_info; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->dfs_nol = NULL; +#endif + + /* + * Zero out radar_info. It's possible that the attach function won't + * fetch an initial regulatory configuration; you really do want to + * ensure that the contents indicates there aren't any filters. + */ + OS_MEMZERO(&radar_info, sizeof(radar_info)); + ic->ic_dfs_attach(ic, &dfs->dfs_caps, &radar_info); + dfs_clear_stats(ic); + dfs->dfs_event_log_on = 0; + OS_INIT_TIMER(NULL, &(dfs->ath_dfs_task_timer), dfs_task, (void *)(ic), + CDF_TIMER_TYPE_SW); +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + OS_INIT_TIMER(NULL, &(dfs->ath_dfstesttimer), dfs_testtimer_task, + (void *)ic, CDF_TIMER_TYPE_SW); + dfs->ath_dfs_cac_time = ATH_DFS_WAIT_MS; + dfs->ath_dfstesttime = ATH_DFS_TEST_RETURN_PERIOD_MS; +#endif + ATH_DFSQ_LOCK_INIT(dfs); + STAILQ_INIT(&dfs->dfs_radarq); + ATH_ARQ_LOCK_INIT(dfs); + STAILQ_INIT(&dfs->dfs_arq); + STAILQ_INIT(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_LOCK_INIT(dfs); + dfs->events = (struct dfs_event *)os_malloc(NULL, + sizeof(struct dfs_event) * + DFS_MAX_EVENTS, GFP_ATOMIC); + if (dfs->events == NULL) { + OS_FREE(dfs); + ic->ic_dfs = NULL; + DFS_PRINTK("%s: events allocation failed\n", __func__); + return 1; + } + for (i = 0; i < DFS_MAX_EVENTS; i++) { + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i], + re_list); + } + + dfs->pulses = + (struct dfs_pulseline *)os_malloc(NULL, + sizeof(struct dfs_pulseline), + GFP_ATOMIC); + if (dfs->pulses == NULL) { + OS_FREE(dfs->events); + dfs->events = NULL; + OS_FREE(dfs); + ic->ic_dfs = NULL; + DFS_PRINTK("%s: pulse buffer allocation failed\n", __func__); + return 1; + } + + dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; + + /* Allocate memory for radar filters */ + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + dfs->dfs_radarf[n] = + (struct dfs_filtertype *)os_malloc(NULL, + sizeof(struct + dfs_filtertype), + GFP_ATOMIC); + if (dfs->dfs_radarf[n] == NULL) { + DFS_PRINTK + ("%s: cannot allocate memory for radar filter types\n", + __func__); + goto bad1; + } + OS_MEMZERO(dfs->dfs_radarf[n], sizeof(struct dfs_filtertype)); + } + /* Allocate memory for radar table */ + dfs->dfs_radartable = + (int8_t * *) os_malloc(NULL, 256 * sizeof(int8_t *), GFP_ATOMIC); + if (dfs->dfs_radartable == NULL) { + DFS_PRINTK("%s: cannot allocate memory for radar table\n", + __func__); + goto bad1; + } + for (n = 0; n < 256; n++) { + dfs->dfs_radartable[n] = + os_malloc(NULL, DFS_MAX_RADAR_OVERLAP * sizeof(int8_t), + GFP_ATOMIC); + if (dfs->dfs_radartable[n] == NULL) { + DFS_PRINTK + ("%s: cannot allocate memory for radar table entry\n", + __func__); + goto bad2; + } + } + + if (usenol == 0) + DFS_PRINTK("%s: NOL disabled\n", __func__); + else if (usenol == 2) + DFS_PRINTK("%s: NOL disabled; no CSA\n", __func__); + + dfs->dfs_rinfo.rn_use_nol = usenol; + + /* Init the cached extension channel busy for false alarm reduction */ + dfs->dfs_rinfo.ext_chan_busy_ts = ic->ic_get_TSF64(ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = 0; + /* Init the Bin5 chirping related data */ + dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts; + dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR; + dfs->dfs_b5radars = NULL; + + /* + * If dfs_init_radar_filters() fails, we can abort here and + * reconfigure when the first valid channel + radar config + * is available. + */ + if (dfs_init_radar_filters(ic, &radar_info)) { + DFS_PRINTK(" %s: Radar Filter Intialization Failed \n", + __func__); + return 1; + } + + dfs->ath_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE; + dfs->ath_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH; + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + dfs->dfs_phyerr_queued_count = 0; + dfs->dfs_phyerr_w53_counter = 0; + dfs->dfs_pri_multiplier = 2; + + dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; + return 0; + +bad2: + OS_FREE(dfs->dfs_radartable); + dfs->dfs_radartable = NULL; +bad1: + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + if (dfs->dfs_radarf[n] != NULL) { + OS_FREE(dfs->dfs_radarf[n]); + dfs->dfs_radarf[n] = NULL; + } + } + if (dfs->pulses) { + OS_FREE(dfs->pulses); + dfs->pulses = NULL; + } + if (dfs->events) { + OS_FREE(dfs->events); + dfs->events = NULL; + } + + if (ic->ic_dfs) { + OS_FREE(ic->ic_dfs); + ic->ic_dfs = NULL; + } + return 1; +#undef N +} + +void dfs_detach(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + int n, empty; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n", + __func__); + return; + } + + /* Bug 29099 make sure all outstanding timers are cancelled */ + + if (dfs->ath_radar_tasksched) { + OS_CANCEL_TIMER(&dfs->ath_dfs_task_timer); + dfs->ath_radar_tasksched = 0; + } + + if (dfs->ath_dfstest) { + OS_CANCEL_TIMER(&dfs->ath_dfstesttimer); + dfs->ath_dfstest = 0; + } +#if 0 +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + if (dfs->ic_dfswait) { + OS_CANCEL_TIMER(&dfs->ic_dfswaittimer); + dfs->ath_dfswait = 0; + } + + OS_CANCEL_TIMER(&dfs->sc_dfs_war_timer); + if (dfs->dfs_nol != NULL) { + struct dfs_nolelem *nol, *next; + nol = dfs->dfs_nol; + /* Bug 29099 - each NOL element has its own timer, cancel it and + free the element */ + while (nol != NULL) { + OS_CANCEL_TIMER(&nol->nol_timer); + next = nol->nol_next; + OS_FREE(nol); + nol = next; + } + dfs->dfs_nol = NULL; + } +#endif +#endif + /* Return radar events to free q */ + dfs_reset_radarq(dfs); + dfs_reset_alldelaylines(dfs); + + /* Free up pulse log */ + if (dfs->pulses != NULL) { + OS_FREE(dfs->pulses); + dfs->pulses = NULL; + } + + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + if (dfs->dfs_radarf[n] != NULL) { + OS_FREE(dfs->dfs_radarf[n]); + dfs->dfs_radarf[n] = NULL; + } + } + + if (dfs->dfs_radartable != NULL) { + for (n = 0; n < 256; n++) { + if (dfs->dfs_radartable[n] != NULL) { + OS_FREE(dfs->dfs_radartable[n]); + dfs->dfs_radartable[n] = NULL; + } + } + OS_FREE(dfs->dfs_radartable); + dfs->dfs_radartable = NULL; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 0; +#endif + } + + if (dfs->dfs_b5radars != NULL) { + OS_FREE(dfs->dfs_b5radars); + dfs->dfs_b5radars = NULL; + } + +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * dfs_reset_ar(dfs); + */ + ATH_ARQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_arq)); + ATH_ARQ_UNLOCK(dfs); + if (!empty) { +/* + * Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * + * dfs_reset_arq(dfs); + */ + } + if (dfs->events != NULL) { + OS_FREE(dfs->events); + dfs->events = NULL; + } + dfs_nol_timer_cleanup(dfs); + OS_FREE(dfs); + + /* XXX? */ + ic->ic_dfs = NULL; +} + +/* + * This is called each time a channel change occurs, to (potentially) enable + * the radar code. + */ +int dfs_radar_disable(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; +#ifdef ATH_ENABLE_AR + dfs->dfs_proc_phyerr &= ~DFS_AR_EN; +#endif + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + return 0; +} + +/* + * This is called each time a channel change occurs, to (potentially) enable + * the radar code. + */ +int dfs_radar_enable(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info) +{ + int is_ext_ch; + int is_fastclk = 0; + int radar_filters_init_status = 0; + /* uint32_t rfilt; */ + struct ath_dfs *dfs; + struct dfs_state *rs_pri, *rs_ext; + struct ieee80211_channel *chan = ic->ic_curchan, *ext_ch = NULL; + is_ext_ch = IEEE80211_IS_CHAN_11N_HT40(ic->ic_curchan); + dfs = (struct ath_dfs *)ic->ic_dfs; + rs_pri = NULL; + rs_ext = NULL; +#if 0 + int i; +#endif + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: ic_dfs is NULL\n", + __func__); + + return -EIO; + } + ic->ic_dfs_disable(ic); + + /* + * Setting country code might change the DFS domain + * so initialize the DFS Radar filters + */ + radar_filters_init_status = dfs_init_radar_filters(ic, radar_info); + + /* + * dfs_init_radar_filters() returns 1 on failure and + * 0 on success. + */ + if (DFS_STATUS_FAIL == radar_filters_init_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: DFS Radar Filters Initialization Failed", + __func__, __LINE__); + return -EIO; + } + + if ((ic->ic_opmode == IEEE80211_M_HOSTAP + || ic->ic_opmode == IEEE80211_M_IBSS)) { + + if (IEEE80211_IS_CHAN_DFS(chan)) { + + uint8_t index_pri, index_ext; +#ifdef ATH_ENABLE_AR + dfs->dfs_proc_phyerr |= DFS_AR_EN; +#endif + dfs->dfs_proc_phyerr |= DFS_RADAR_EN; + + if (is_ext_ch) { + ext_ch = ieee80211_get_extchan(ic); + } + dfs_reset_alldelaylines(dfs); + + rs_pri = dfs_getchanstate(dfs, &index_pri, 0); + if (ext_ch) { + rs_ext = dfs_getchanstate(dfs, &index_ext, 1); + } + if (rs_pri != NULL + && ((ext_ch == NULL) || (rs_ext != NULL))) { + struct ath_dfs_phyerr_param pe; + + OS_MEMSET(&pe, '\0', sizeof(pe)); + + if (index_pri != dfs->dfs_curchan_radindex) + dfs_reset_alldelaylines(dfs); + + dfs->dfs_curchan_radindex = (int16_t) index_pri; + dfs->dfs_pri_multiplier_ini = + radar_info->dfs_pri_multiplier; + + if (rs_ext) + dfs->dfs_extchan_radindex = + (int16_t) index_ext; + + ath_dfs_phyerr_param_copy(&pe, + &rs_pri->rs_param); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: firpwr=%d, rssi=%d, height=%d, " + "prssi=%d, inband=%d, relpwr=%d, " + "relstep=%d, maxlen=%d\n", + __func__, + pe.pe_firpwr, + pe.pe_rrssi, + pe.pe_height, + pe.pe_prssi, + pe.pe_inband, + pe.pe_relpwr, + pe.pe_relstep, pe.pe_maxlen); + + ic->ic_dfs_enable(ic, &is_fastclk, &pe); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "Enabled radar detection on channel %d\n", + chan->ic_freq); + dfs->dur_multiplier = + is_fastclk ? DFS_FAST_CLOCK_MULTIPLIER : + DFS_NO_FAST_CLOCK_MULTIPLIER; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: duration multiplier is %d\n", + __func__, dfs->dur_multiplier); + } else + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: No more radar states left\n", + __func__); + } + } + + return DFS_STATUS_SUCCESS; +} + +int +dfs_control(struct ieee80211com *ic, u_int id, + void *indata, uint32_t insize, void *outdata, uint32_t *outsize) +{ + int error = 0; + struct ath_dfs_phyerr_param peout; + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct dfs_ioctl_params *dfsparams; + uint32_t val = 0; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + struct dfsreq_nolinfo *nol; + uint32_t *data = NULL; +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + int i; + + if (dfs == NULL) { + error = -EINVAL; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s DFS is null\n", __func__); + goto bad; + } + + switch (id) { + case DFS_SET_THRESH: + if (insize < sizeof(struct dfs_ioctl_params) || !indata) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: insize=%d, expected=%zu bytes, indata=%p\n", + __func__, insize, + sizeof(struct dfs_ioctl_params), indata); + error = -EINVAL; + break; + } + dfsparams = (struct dfs_ioctl_params *)indata; + if (!dfs_set_thresholds + (ic, DFS_PARAM_FIRPWR, dfsparams->dfs_firpwr)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_RRSSI, dfsparams->dfs_rrssi)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_HEIGHT, dfsparams->dfs_height)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_PRSSI, dfsparams->dfs_prssi)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_INBAND, dfsparams->dfs_inband)) + error = -EINVAL; + /* 5413 speicfic */ + if (!dfs_set_thresholds + (ic, DFS_PARAM_RELPWR, dfsparams->dfs_relpwr)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_RELSTEP, dfsparams->dfs_relstep)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_MAXLEN, dfsparams->dfs_maxlen)) + error = -EINVAL; + break; + case DFS_GET_THRESH: + if (!outdata || !outsize + || *outsize < sizeof(struct dfs_ioctl_params)) { + error = -EINVAL; + break; + } + *outsize = sizeof(struct dfs_ioctl_params); + dfsparams = (struct dfs_ioctl_params *)outdata; + + /* + * Fetch the DFS thresholds using the internal representation. + */ + (void)dfs_get_thresholds(ic, &peout); + + /* + * Convert them to the dfs IOCTL representation. + */ + ath_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); + break; + case DFS_RADARDETECTS: + if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { + error = -EINVAL; + break; + } + *outsize = sizeof(uint32_t); + *((uint32_t *) outdata) = dfs->ath_dfs_stats.num_radar_detects; + break; + case DFS_DISABLE_DETECT: + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + dfs->ic->ic_dfs_state.ignore_dfs = 1; + DFS_PRINTK("%s enable detects, ignore_dfs %d\n", + __func__, dfs->ic->ic_dfs_state.ignore_dfs); + break; + case DFS_ENABLE_DETECT: + dfs->dfs_proc_phyerr |= DFS_RADAR_EN; + dfs->ic->ic_dfs_state.ignore_dfs = 0; + DFS_PRINTK("%s enable detects, ignore_dfs %d\n", + __func__, dfs->ic->ic_dfs_state.ignore_dfs); + break; + case DFS_DISABLE_FFT: + /* UMACDFS: TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, false); */ + DFS_PRINTK("%s TODO disable FFT val=0x%x \n", __func__, val); + break; + case DFS_ENABLE_FFT: + /* UMACDFS TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, true); */ + DFS_PRINTK("%s TODO enable FFT val=0x%x \n", __func__, val); + break; + case DFS_SET_DEBUG_LEVEL: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->dfs_debug_mask = *(uint32_t *) indata; + DFS_PRINTK("%s debug level now = 0x%x \n", + __func__, dfs->dfs_debug_mask); + if (dfs->dfs_debug_mask & ATH_DEBUG_DFS3) { + /* Enable debug Radar Event */ + dfs->dfs_event_log_on = 1; + } else { + dfs->dfs_event_log_on = 0; + } + break; + case DFS_SET_FALSE_RSSI_THRES: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->ath_dfs_false_rssi_thres = *(uint32_t *) indata; + DFS_PRINTK("%s false RSSI threshold now = 0x%x \n", + __func__, dfs->ath_dfs_false_rssi_thres); + break; + case DFS_SET_PEAK_MAG: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->ath_dfs_peak_mag = *(uint32_t *) indata; + DFS_PRINTK("%s peak_mag now = 0x%x \n", + __func__, dfs->ath_dfs_peak_mag); + break; + case DFS_IGNORE_CAC: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + if (*(uint32_t *) indata) { + dfs->ic->ic_dfs_state.ignore_cac = 1; + } else { + dfs->ic->ic_dfs_state.ignore_cac = 0; + } + DFS_PRINTK("%s ignore cac = 0x%x \n", + __func__, dfs->ic->ic_dfs_state.ignore_cac); + break; + case DFS_SET_NOL_TIMEOUT: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + if (*(int *)indata) { + dfs->ath_dfs_nol_timeout = *(int *)indata; + } else { + dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; + } + DFS_PRINTK("%s nol timeout = %d sec \n", + __func__, dfs->ath_dfs_nol_timeout); + break; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + case DFS_MUTE_TIME: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + data = (uint32_t *) indata; + dfs->ath_dfstesttime = *data; + dfs->ath_dfstesttime *= (1000); /* convert sec into ms */ + break; + case DFS_GET_USENOL: + if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { + error = -EINVAL; + break; + } + *outsize = sizeof(uint32_t); + *((uint32_t *) outdata) = dfs->dfs_rinfo.rn_use_nol; + + for (i = 0; + (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count); + i++) { + /* DFS_DPRINTK(sc, ATH_DEBUG_DFS,"ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); */ + + } + dfs->dfs_event_log_count = 0; + dfs->dfs_phyerr_count = 0; + dfs->dfs_phyerr_reject_count = 0; + dfs->dfs_phyerr_queued_count = 0; + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + break; + case DFS_SET_USENOL: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->dfs_rinfo.rn_use_nol = *(uint32_t *) indata; + /* iwpriv markdfs in linux can do the same thing... */ + break; + case DFS_GET_NOL: + if (!outdata || !outsize + || *outsize < sizeof(struct dfsreq_nolinfo)) { + error = -EINVAL; + break; + } + *outsize = sizeof(struct dfsreq_nolinfo); + nol = (struct dfsreq_nolinfo *)outdata; + dfs_get_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, + &nol->ic_nchans); + dfs_print_nol(dfs); + break; + case DFS_SET_NOL: + if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { + error = -EINVAL; + break; + } + nol = (struct dfsreq_nolinfo *)indata; + dfs_set_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, + nol->ic_nchans); + break; + + case DFS_SHOW_NOL: + dfs_print_nol(dfs); + break; + case DFS_BANGRADAR: +#if 0 /* MERGE_TBD */ + if (sc->sc_nostabeacons) { + printk("No radar detection Enabled \n"); + break; + } +#endif + dfs->dfs_bangradar = 1; + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + break; +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + default: + error = -EINVAL; + } +bad: + return error; +} + +int +dfs_set_thresholds(struct ieee80211com *ic, const uint32_t threshtype, + const uint32_t value) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + int16_t chanindex; + struct dfs_state *rs; + struct ath_dfs_phyerr_param pe; + int is_fastclk = 0; /* XXX throw-away */ + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n", + __func__); + return 0; + } + + chanindex = dfs->dfs_curchan_radindex; + if ((chanindex < 0) || (chanindex >= DFS_NUM_RADAR_STATES)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: chanindex = %d, DFS_NUM_RADAR_STATES=%d\n", + __func__, chanindex, DFS_NUM_RADAR_STATES); + return 0; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: threshtype=%d, value=%d\n", __func__, threshtype, + value); + + ath_dfs_phyerr_init_noval(&pe); + + rs = &(dfs->dfs_radar[chanindex]); + switch (threshtype) { + case DFS_PARAM_FIRPWR: + rs->rs_param.pe_firpwr = (int32_t) value; + pe.pe_firpwr = value; + break; + case DFS_PARAM_RRSSI: + rs->rs_param.pe_rrssi = value; + pe.pe_rrssi = value; + break; + case DFS_PARAM_HEIGHT: + rs->rs_param.pe_height = value; + pe.pe_height = value; + break; + case DFS_PARAM_PRSSI: + rs->rs_param.pe_prssi = value; + pe.pe_prssi = value; + break; + case DFS_PARAM_INBAND: + rs->rs_param.pe_inband = value; + pe.pe_inband = value; + break; + /* 5413 specific */ + case DFS_PARAM_RELPWR: + rs->rs_param.pe_relpwr = value; + pe.pe_relpwr = value; + break; + case DFS_PARAM_RELSTEP: + rs->rs_param.pe_relstep = value; + pe.pe_relstep = value; + break; + case DFS_PARAM_MAXLEN: + rs->rs_param.pe_maxlen = value; + pe.pe_maxlen = value; + break; + default: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: unknown threshtype (%d)\n", + __func__, threshtype); + break; + } + + /* + * The driver layer dfs_enable routine is tasked with translating + * values from the global format to the per-device (HAL, offload) + * format. + */ + ic->ic_dfs_enable(ic, &is_fastclk, &pe); + return 1; +} + +int +dfs_get_thresholds(struct ieee80211com *ic, struct ath_dfs_phyerr_param *param) +{ + /* UMACDFS : TODO:ath_hal_getdfsthresh(sc->sc_ah, param); */ + + OS_MEMZERO(param, sizeof(*param)); + + (void)ic->ic_dfs_get_thresholds(ic, param); + + return 1; +} + +uint16_t dfs_usenol(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + return dfs ? (uint16_t) dfs->dfs_rinfo.rn_use_nol : 0; +} + +uint16_t dfs_isdfsregdomain(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + return dfs ? dfs->dfsdomain : 0; +} + +#endif /* ATH_UPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_bindetects.c b/core/sap/dfs/src/dfs_bindetects.c new file mode 100644 index 0000000000..7c48309942 --- /dev/null +++ b/core/sap/dfs/src/dfs_bindetects.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_bindetects.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/*TO DO DFS removing + #include + */ +#ifdef ATH_SUPPORT_DFS + +int +dfs_bin_fixedpattern_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t dur, int ext_chan_flag) +{ + struct dfs_pulseline *pl = dfs->pulses; + int i, n, refpri, primargin, numpulses = 0; + uint64_t start_ts, end_ts, event_ts, prev_event_ts, next_event_ts, + window_start, window_end; + uint32_t index, next_index, deltadur; + + /* For fixed pattern types, rf->rf_patterntype=1 */ + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + refpri = (rf->rf_minpri + rf->rf_maxpri) / 2; + index = pl->pl_lastelem; + end_ts = pl->pl_elems[index].p_time; + start_ts = end_ts - (refpri * rf->rf_numpulses); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "lastelem ts=%llu start_ts=%llu, end_ts=%llu\n", + (unsigned long long)pl->pl_elems[index].p_time, + (unsigned long long)start_ts, (unsigned long long)end_ts); + + /* find the index of first element in our window of interest */ + for (i = 0; i < pl->pl_numelems; i++) { + index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; + if (pl->pl_elems[index].p_time >= start_ts) + continue; + else { + index = (index) & DFS_MAX_PULSE_BUFFER_MASK; + break; + } + } + for (n = 0; n <= rf->rf_numpulses; n++) { + window_start = (start_ts + (refpri * n)) - (primargin + n); + window_end = window_start + 2 * (primargin + n); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "window_start %u window_end %u \n", + (uint32_t) window_start, (uint32_t) window_end); + for (i = 0; i < pl->pl_numelems; i++) { + prev_event_ts = pl->pl_elems[index].p_time; + index = (index + 1) & DFS_MAX_PULSE_BUFFER_MASK; + event_ts = pl->pl_elems[index].p_time; + next_index = (index + 1) & DFS_MAX_PULSE_BUFFER_MASK; + next_event_ts = pl->pl_elems[next_index].p_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "ts %u \n", (uint32_t) event_ts); + if ((event_ts <= window_end) + && (event_ts >= window_start)) { + deltadur = + DFS_DIFF(pl->pl_elems[index].p_dur, dur); + if ((pl->pl_elems[index].p_dur == 1) + || ((dur != 1) && (deltadur <= 2))) { + numpulses++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numpulses %u \n", + numpulses); + break; + } + } else if (event_ts > window_end) { + index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; + break; + } else if (event_ts == prev_event_ts) { + if (((next_event_ts - event_ts) > refpri) || + ((next_event_ts - event_ts) == 0)) { + deltadur = + DFS_DIFF(pl->pl_elems[index].p_dur, + dur); + if ((pl->pl_elems[index].p_dur == 1) + || ((pl->pl_elems[index].p_dur != 1) + && (deltadur <= 2))) { + numpulses++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "zero PRI: numpulses %u \n", + numpulses); + break; + } + } + } + } + } + if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s FOUND filterID=%u numpulses=%d unadj thresh=%d\n", + __func__, rf->rf_pulseid, numpulses, + rf->rf_threshold); + return 1; + } else + return 0; +} + +void +dfs_add_pulse(struct ath_dfs *dfs, struct dfs_filter *rf, struct dfs_event *re, + uint32_t deltaT, uint64_t this_ts) +{ + uint32_t index, n, window; + struct dfs_delayline *dl; + + dl = &rf->rf_dl; + /* Circular buffer of size 2^n */ + index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK; + /* if ((dl->dl_numelems+1) == DFS_MAX_DL_SIZE) */ + if ((dl->dl_numelems) == DFS_MAX_DL_SIZE) + dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK; + else + dl->dl_numelems++; + dl->dl_lastelem = index; + dl->dl_elems[index].de_time = deltaT; + dl->dl_elems[index].de_ts = this_ts; + window = deltaT; + dl->dl_elems[index].de_dur = re->re_dur; + dl->dl_elems[index].de_rssi = re->re_rssi; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: adding: filter id %d, dur=%d, rssi=%d, ts=%llu\n", + __func__, + rf->rf_pulseid, + re->re_dur, re->re_rssi, (unsigned long long int)this_ts); + + for (n = 0; n < dl->dl_numelems - 1; n++) { + index = (index - 1) & DFS_MAX_DL_MASK; + /* + * calculate window based on full time stamp instead of deltaT + * deltaT (de_time) may result in incorrect window value + */ + window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts); + + if (window > rf->rf_filterlen) { + dl->dl_firstelem = (index + 1) & DFS_MAX_DL_MASK; + dl->dl_numelems = n + 1; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "dl firstElem = %d lastElem = %d\n", dl->dl_firstelem, + dl->dl_lastelem); +} + +int +dfs_bin_check(struct ath_dfs *dfs, struct dfs_filter *rf, uint32_t deltaT, + uint32_t width, int ext_chan_flag) +{ + uint32_t refpri, refdur, searchpri, deltapri, deltapri_2, deltapri_3, + averagerefpri; + uint32_t n, i, primargin, durmargin, highscore, highscoreindex; + int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0; + struct dfs_delayline *dl; + uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; + int numpulses = 0; + int lowprichk = 3, pri_match = 0; + + dl = &rf->rf_dl; + if (dl->dl_numelems < (rf->rf_threshold - 1)) { + return 0; + } + if (deltaT > rf->rf_filterlen) + return 0; + + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + if (rf->rf_patterntype == 1) { + found = + dfs_bin_fixedpattern_check(dfs, rf, width, ext_chan_flag); + if (found) { + dl->dl_numelems = 0; + } + return found; + } + + OS_MEMZERO(score, sizeof(int) * DFS_MAX_DL_SIZE); + /* find out the lowest pri */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + else if (refpri < lowpri) { + lowpri = dl->dl_elems[delayindex].de_time; + lowpriindex = n; + } + } + /* find out the each delay element's pri score */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + if (refpri < rf->rf_maxpri) { /* use only valid PRI range for high score */ + for (i = 0; i < dl->dl_numelems; i++) { + dindex = + (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + deltapri_2 = DFS_DIFF(searchpri, 2 * refpri); + deltapri_3 = DFS_DIFF(searchpri, 3 * refpri); + if (rf->rf_ignore_pri_window == 2) { + pri_match = ((deltapri < primargin) + || (deltapri_2 < primargin) + || (deltapri_3 < + primargin)); + } else { + pri_match = (deltapri < primargin); + } + + if (pri_match) + score[n]++; + } + } else { + score[n] = 0; + } + if (score[n] > rf->rf_threshold) { + /* we got the most possible candidate, + * no need to continue further */ + break; + } + } + /* find out the high scorer */ + highscore = 0; + highscoreindex = 0; + for (n = 0; n < dl->dl_numelems; n++) { + if (score[n] > highscore) { + highscore = score[n]; + highscoreindex = n; + } else if (score[n] == highscore) { + /*more than one pri has highscore take the least pri */ + delayindex = + (dl->dl_firstelem + + highscoreindex) & DFS_MAX_DL_MASK; + dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + if (dl->dl_elems[dindex].de_time <= + dl->dl_elems[delayindex].de_time) { + highscoreindex = n; + } + } + } + /* find the average pri of pulses around the pri of highscore or + * the pulses around the lowest pri */ + if (rf->rf_ignore_pri_window > 0) { + lowprichk = (rf->rf_threshold >> 1) + 1; + } else { + lowprichk = 3; + } + + if (highscore < lowprichk) { + scoreindex = lowpriindex; + } else { + scoreindex = highscoreindex; + } + /* We got the possible pri, save its parameters as reference */ + delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + averagerefpri = 0; + + if (rf->rf_fixed_pri_radar_pulse) { + refpri = (rf->rf_minpri + rf->rf_maxpri) / 2; + } + + numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri, + refdur, ext_chan_flag, refpri); + if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { + found = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d\n", + ext_chan_flag, rf->rf_pulseid, numpulses, + rf->rf_threshold, refdur, refpri, primargin); + dfs_print_delayline(dfs, &rf->rf_dl); + dfs_print_filter(dfs, rf); + } + return found; +} + +int +dfs_bin_pri_check(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_delayline *dl, uint32_t score, uint32_t refpri, + uint32_t refdur, int ext_chan_flag, int fundamentalpri) +{ + uint32_t searchpri, searchdur, searchrssi, deltapri = 0, deltapri1 = + 0, deltapri2 = 0, deltadur, averagerefpri = 0, MatchCount = 0; + uint32_t delta_ts_variance, delta_time_stamps, prev_good_timestamp = 0; + int delayindex, dindex; + uint32_t i, j = 0, primargin, durmargin, highscore = + score, highscoreindex = 0; + int numpulses = 1; /* first pulse in the burst is most likely being filtered out based on maxfilterlen */ + int priscorechk = 1, numpulsetochk = 2, primatch = 0; + + /* Use the adjusted PRI margin to reduce false alarms */ + /* For non fixed pattern types, rf->rf_patterntype=0 */ + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { + numpulses = 0; + return numpulses; + } + + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + if ((!rf->rf_fixed_pri_radar_pulse)) { + if (rf->rf_ignore_pri_window == 1) { + priscorechk = (rf->rf_threshold >> 1); + } else { + priscorechk = 1; + } + + MatchCount = 0; + if (score > priscorechk) { + for (i = 0; i < dl->dl_numelems; i++) { + dindex = + (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + if (deltapri < primargin) { + averagerefpri += searchpri; + MatchCount++; + } + } + if (rf->rf_patterntype != 2) { + if (MatchCount > 0) + refpri = (averagerefpri / MatchCount); /* average */ + } else { + refpri = (averagerefpri / score); + } + } + } + /* Note: Following primultiple calculation should be done once per filter + * during initialization stage (dfs_attach) and stored in its array + * atleast for fixed frequency types like FCC Bin1 to save some CPU cycles. + * multiplication, devide operators in the following code are left as it is + * for readability hoping the complier will use left/right shifts wherever possible + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "refpri = %d high score = %d index = %d numpulses = %d\n", + refpri, highscore, highscoreindex, numpulses); + /* Count the other delay elements that have pri and dur with in the + * acceptable range from the reference one */ + for (i = 0; i < dl->dl_numelems; i++) { + delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[delayindex].de_time; + if (searchpri == 0) { + /* This events PRI is zero, take it as a + * valid pulse but decrement next event's PRI by refpri + */ + dindex = (delayindex + 1) & DFS_MAX_DL_MASK; + dl->dl_elems[dindex].de_time -= refpri; + searchpri = refpri; + } + searchdur = dl->dl_elems[delayindex].de_dur; + searchrssi = dl->dl_elems[delayindex].de_rssi; + deltadur = DFS_DIFF(searchdur, refdur); + deltapri = DFS_DIFF(searchpri, refpri); + + /* deltapri3 = DFS_DIFF(searchpri, 3 * refpri); */ + primatch = 0; + + if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) { + for (j = 0; j < rf->rf_numpulses; j++) { + deltapri1 = + DFS_DIFF(searchpri, (j + 1) * refpri); + if (deltapri1 < (2 * primargin)) { + primatch = 1; + break; + } + } + } else { + if ((deltapri1 < primargin) || (deltapri2 < primargin)) { + primatch = 1; + } + } + + if (primatch && (deltadur < durmargin)) { + if ((numpulses == 1)) { + numpulses++; + } else { + delta_time_stamps = + dl->dl_elems[delayindex].de_ts - + prev_good_timestamp; + if ((rf->rf_ignore_pri_window > 0)) { + numpulsetochk = rf->rf_numpulses; + + if ((rf->rf_patterntype == 2) + && (fundamentalpri < + refpri + 100)) { + numpulsetochk = 4; + } + } else { + numpulsetochk = 4; + } + for (j = 0; j < numpulsetochk; j++) { + delta_ts_variance = + DFS_DIFF(delta_time_stamps, + ((j + + 1) * fundamentalpri)); + if (delta_ts_variance < + (2 * (j + 1) * primargin)) { + numpulses++; + if (rf->rf_ignore_pri_window > + 0) { + break; + } + } + } + } + prev_good_timestamp = dl->dl_elems[delayindex].de_ts; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d deltapri=%d j=%d\n", + rf->rf_minpri, rf->rf_maxpri, searchpri, i, + numpulses, deltapri, j); + } + + } + return numpulses; +} +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_debug.c b/core/sap/dfs/src/dfs_debug.c new file mode 100644 index 0000000000..71f917ad00 --- /dev/null +++ b/core/sap/dfs/src/dfs_debug.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_debug.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +void dfs_print_delayline(struct ath_dfs *dfs, struct dfs_delayline *dl) +{ + int i = 0, index; + struct dfs_delayelem *de; + + index = dl->dl_lastelem; + for (i = 0; i < dl->dl_numelems; i++) { + de = &dl->dl_elems[index]; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Elem %d: ts = %u (0x%x) dur=%u\n", i, + de->de_time, de->de_time, de->de_dur); + index = (index - 1) & DFS_MAX_DL_MASK; + } +} + +void dfs_print_filter(struct ath_dfs *dfs, struct dfs_filter *rf) +{ + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "filterID[%d] rf_numpulses=%u; rf->rf_minpri=%u; " + "rf->rf_maxpri=%u; rf->rf_threshold=%u; rf->rf_filterlen=%u; " + "rf->rf_mindur=%u; rf->rf_maxdur=%u\n", + rf->rf_pulseid, + rf->rf_numpulses, + rf->rf_minpri, + rf->rf_maxpri, + rf->rf_threshold, + rf->rf_filterlen, rf->rf_mindur, rf->rf_maxdur); +} + +void dfs_print_filters(struct ath_dfs *dfs) +{ + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf; + int i, j; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL\n", + __func__); + return; + } + for (i = 0; i < DFS_MAX_RADAR_TYPES; i++) { + if (dfs->dfs_radarf[i] != NULL) { + ft = dfs->dfs_radarf[i]; + if ((ft->ft_numfilters > DFS_MAX_NUM_RADAR_FILTERS) + || (!ft->ft_numfilters)) + continue; + DFS_PRINTK + ("===========ft->ft_numfilters=%u===========\n", + ft->ft_numfilters); + for (j = 0; j < ft->ft_numfilters; j++) { + rf = &(ft->ft_filters[j]); + DFS_PRINTK + ("filter[%d] filterID = %d rf_numpulses=%u; rf->rf_minpri=%u; rf->rf_maxpri=%u; rf->rf_threshold=%u; rf->rf_filterlen=%u; rf->rf_mindur=%u; rf->rf_maxdur=%u\n", + j, rf->rf_pulseid, rf->rf_numpulses, + rf->rf_minpri, rf->rf_maxpri, + rf->rf_threshold, rf->rf_filterlen, + rf->rf_mindur, rf->rf_maxdur); + } + } + } +} + +void dfs_print_activity(struct ath_dfs *dfs) +{ + int chan_busy = 0, ext_chan_busy = 0; + uint32_t rxclear = 0, rxframe = 0, txframe = 0, cycles = 0; + + cycles = + dfs->ic->ic_get_mib_cycle_counts_pct(dfs->ic, &rxclear, &rxframe, + &txframe); + chan_busy = cycles; + + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "cycles=%d rxclear=%d rxframe=%d" + " txframe=%d extchanbusy=%d\n", cycles, rxclear, + rxframe, txframe, ext_chan_busy); + return; +} + +/* + * XXX migrate this to use ath_dfs as the arg, not ieee80211com! + */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY +os_timer_func(dfs_debug_timeout) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + + dfs = (struct ath_dfs *)ic->ic_dfs; + + dfs_print_activity(dfs); + + OS_SET_TIMER(&dfs->ath_dfs_debug_timer, DFS_DEBUG_TIMEOUT_MS); +} +#endif + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_fcc_bin5.c b/core/sap/dfs/src/dfs_fcc_bin5.c new file mode 100644 index 0000000000..ccc9fe6d2b --- /dev/null +++ b/core/sap/dfs/src/dfs_fcc_bin5.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_fcc_bin5.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +/* + * Reject the pulse if: + * + It's outside the RSSI threshold; + * + It's outside the pulse duration; + * + It's been verified by HW/SW chirp checking + * and neither of those found a chirp. + */ +int +dfs_bin5_check_pulse(struct ath_dfs *dfs, struct dfs_event *re, + struct dfs_bin5radars *br) +{ + int b5_rssithresh = br->br_pulse.b5_rssithresh; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_PULSE, + "%s: re_dur=%d, rssi=%d, check_chirp=%d, " + "hw_chirp=%d, sw_chirp=%d\n", + __func__, + (int)re->re_dur, + (int)re->re_rssi, + !!(re->re_flags & DFS_EVENT_CHECKCHIRP), + !!(re->re_flags & DFS_EVENT_HW_CHIRP), + !!(re->re_flags & DFS_EVENT_SW_CHIRP)); + + /* + * If the sw/hw chirp detection says to fail the pulse, + * do so. + */ + if (DFS_EVENT_NOTCHIRP(re)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: rejecting chirp: ts=%llu, dur=%d, rssi=%d " + "checkchirp=%d, hwchirp=%d, swchirp=%d\n", + __func__, + (unsigned long long)re->re_full_ts, + (int)re->re_dur, + (int)re->re_rssi, + !!(re->re_flags & DFS_EVENT_CHECKCHIRP), + !!(re->re_flags & DFS_EVENT_HW_CHIRP), + !!(re->re_flags & DFS_EVENT_SW_CHIRP)); + return (0); + } + + /* Adjust the filter threshold for rssi in non TURBO mode */ + if (!(dfs->ic->ic_curchan->ic_flags & CHANNEL_TURBO)) + b5_rssithresh += br->br_pulse.b5_rssimargin; + + /* + * Check if the pulse is within duration and rssi + * thresholds. + */ + if ((re->re_dur >= br->br_pulse.b5_mindur) && + (re->re_dur <= br->br_pulse.b5_maxdur) && + (re->re_rssi >= b5_rssithresh)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: dur=%d, rssi=%d - adding!\n", + __func__, (int)re->re_dur, (int)re->re_rssi); + return (1); + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: too low to be Bin5 pulse tsf=%llu, dur=%d, rssi=%d\n", + __func__, + (unsigned long long)re->re_full_ts, + (int)re->re_dur, (int)re->re_rssi); + + return (0); +} + +int dfs_bin5_addpulse(struct ath_dfs *dfs, struct dfs_bin5radars *br, + struct dfs_event *re, uint64_t thists) +{ + uint32_t index, stop; + uint64_t tsDelta; + + /* Check if this pulse is a valid pulse in terms of repetition, + * if not, return without adding it to the queue. + * PRI : Pulse Repitetion Interval + * BRI : Burst Repitetion Interval */ + if (br->br_numelems != 0) { + index = br->br_lastelem; + tsDelta = thists - br->br_elems[index].be_ts; + if ((tsDelta < DFS_BIN5_PRI_LOWER_LIMIT) || + ((tsDelta > DFS_BIN5_PRI_HIGHER_LIMIT) && + (tsDelta < DFS_BIN5_BRI_LOWER_LIMIT))) { + return 0; + } + } + /* Circular buffer of size 2^n */ + index = (br->br_lastelem + 1) & DFS_MAX_B5_MASK; + br->br_lastelem = index; + if (br->br_numelems == DFS_MAX_B5_SIZE) + br->br_firstelem = (br->br_firstelem + 1) & DFS_MAX_B5_MASK; + else + br->br_numelems++; + br->br_elems[index].be_ts = thists; + br->br_elems[index].be_rssi = re->re_rssi; + br->br_elems[index].be_dur = re->re_dur; /* please note that this is in u-sec */ + stop = 0; + index = br->br_firstelem; + while ((!stop) && (br->br_numelems - 1) > 0) { + if ((thists - br->br_elems[index].be_ts) > + ((uint64_t) br->br_pulse.b5_timewindow)) { + br->br_numelems--; + br->br_firstelem = + (br->br_firstelem + 1) & DFS_MAX_B5_MASK; + index = br->br_firstelem; + } else + stop = 1; + } + return 1; +} + +/* + * If the dfs structure is NULL (which should be illegal if everyting is working + * properly, then signify that a bin5 radar was found + */ + +int dfs_bin5_check(struct ath_dfs *dfs) +{ + struct dfs_bin5radars *br; + int index[DFS_MAX_B5_SIZE]; + uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0, rssi_diff = + 0, width_diff = 0, bursts = 0; + uint32_t total_diff = 0, average_diff = 0, total_width = + 0, average_width = 0, numevents = 0; + uint64_t pri; + + if (dfs == NULL) { + DFS_PRINTK("%s: ic_dfs is NULL\n", __func__); + return 1; + } + for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) { + br = &(dfs->dfs_b5radars[n]); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "Num elems = %d\n", br->br_numelems); + + /* find a valid bin 5 pulse and use it as reference */ + for (i1 = 0; i1 < br->br_numelems; i1++) { + this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK); + if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) + && (br->br_elems[this].be_dur <= + MAX_BIN5_DUR_MICROSEC)) { + break; + } + } + + prev = this; + for (i = i1 + 1; i < br->br_numelems; i++) { + this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK); + + /* first make sure it is a bin 5 pulse by checking the duration */ + if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC) + || (br->br_elems[this].be_dur > + MAX_BIN5_DUR_MICROSEC)) { + continue; + } + + /* Rule 1: 1000 <= PRI <= 2000 + some margin */ + if (br->br_elems[this].be_ts >= + br->br_elems[prev].be_ts) { + pri = + br->br_elems[this].be_ts - + br->br_elems[prev].be_ts; + } else { /* roll over case */ + /* pri = (0xffffffffffffffff - br->br_elems[prev].be_ts) + br->br_elems[this].be_ts; */ + pri = br->br_elems[this].be_ts; + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + " pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu\n", + (unsigned long long)pri, + (unsigned long long)br->br_elems[this]. + be_ts, (int)br->br_elems[this].be_dur, + (int)br->br_elems[this].be_rssi, + (unsigned long long)br->br_elems[prev]. + be_ts); + if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) && (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) { /* pri: pulse repitition interval in us */ + /* Rule 2: pulse width of the pulses in the burst should be same (+/- margin) */ + if (br->br_elems[this].be_dur >= + br->br_elems[prev].be_dur) { + width_diff = + br->br_elems[this].be_dur - + br->br_elems[prev].be_dur; + } else { + width_diff = + br->br_elems[prev].be_dur - + br->br_elems[this].be_dur; + } + if (width_diff <= DFS_BIN5_WIDTH_MARGIN) { + /* Rule 3: RSSI of the pulses in the burst should be same (+/- margin) */ + if (br->br_elems[this].be_rssi >= + br->br_elems[prev].be_rssi) { + rssi_diff = + br->br_elems[this].be_rssi - + br->br_elems[prev].be_rssi; + } else { + rssi_diff = + br->br_elems[prev].be_rssi - + br->br_elems[this].be_rssi; + } + if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) { + bursts++; + /* Save the indexes of this pair for later width variance check */ + if (numevents >= 2) { + /* make sure the event is not duplicated, + * possible in a 3 pulse burst */ + if (index[numevents - 1] + != prev) { + index + [numevents++] + = prev; + } + } else { + index[numevents++] = + prev; + } + index[numevents++] = this; + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 rssi_diff=%d\n", + __func__, __LINE__, + rssi_diff); + } + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 width_diff=%d\n", + __func__, __LINE__, + width_diff); + } + } else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) && + (pri <= DFS_BIN5_BRI_UPPER_LIMIT)) { + /* check pulse width to make sure it is in range of bin 5 */ + /* if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) && (br->br_elems[this].be_dur <= MAX_BIN5_DUR_MICROSEC)) { */ + bursts++; + /* } */ + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 PRI check fail pri=%llu\n", + __func__, __LINE__, + (unsigned long long)pri); + } + prev = this; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u\n", + bursts, numevents); + if (bursts >= br->br_pulse.b5_threshold) { + if ((br->br_elems[br->br_lastelem].be_ts - + br->br_elems[br->br_firstelem].be_ts) < 3000000) { + return 0; + } else { + /* + * don't do this check since not all the cases have this kind of burst width variation. + * + for (i=0; ibr_elems[index[i]].be_dur; + } + average_width = total_width/bursts; + for (i=0; ibr_elems[index[i]].be_dur, average_width); + } + average_diff = total_diff/bursts; + if( average_diff > DFS_BIN5_WIDTH_MARGIN ) { + return 1; + } else { + + DFS_DPRINTK(ic, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", bursts, numevents, total_width, average_width, total_diff, average_diff); + + } + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", + bursts, numevents, total_width, + average_width, total_diff, + average_diff); + DFS_PRINTK("bin 5 radar detected, bursts=%d\n", + bursts); + return 1; + } + } + } + + return 0; +} + +/* Return true if chirping pulse, false if not. + Decision is made based on processing the FFT data included with the PHY error. + Calculate the slope using the maximum bin index reported in the FFT data. + Calculate slope between FFT packet 0 and packet n-1. Also calculate slope between + packet 1 and packet n. + If a pulse is chirping, a slope of 5 and greater is seen. + Non-chirping pulses have slopes of 0, 1, 2 or 3. + */ + +/* + * Chirp detection for Sowl/Howl. + */ +static int +dfs_check_chirping_sowl(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, int is_ext, int *slope, + int *is_dc) +{ +#define FFT_LEN 70 +#define FFT_LOWER_BIN_MAX_INDEX_BYTE 66 +#define FFT_UPPER_BIN_MAX_INDEX_BYTE 69 +#define MIN_CHIRPING_SLOPE 4 + int is_chirp = 0; + int p, num_fft_packets = 0; + int ctl_slope = 0, ext_slope = 0; + int ctl_high0, ctl_low0, ctl_slope0 = + 0, ext_high0, ext_low0, ext_slope0 = 0; + int ctl_high1, ctl_low1, ctl_slope1 = + 0, ext_high1, ext_low1, ext_slope1 = 0; + uint8_t *fft_data_ptr; + + *slope = 0; + *is_dc = 0; + + num_fft_packets = datalen / FFT_LEN; + fft_data_ptr = ((uint8_t *) buf); + + /* DEBUG - Print relevant portions of the FFT data */ + for (p = 0; p < num_fft_packets; p++) { + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, "fft_data_ptr=0x%p\t", + fft_data_ptr); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, "[66]=%d [69]=%d\n", + *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2, + *(fft_data_ptr + + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2); + + fft_data_ptr += FFT_LEN; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "datalen=%d num_fft_packets=%d\n", datalen, + num_fft_packets); + + /* There is not enough FFT data to figure out whether the pulse is chirping or not */ + if (num_fft_packets < 4) { + return 0; + } + + fft_data_ptr = ((uint8_t *) buf); + + if (is_ctl) { + + fft_data_ptr = ((uint8_t *) buf); + ctl_low0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + fft_data_ptr += FFT_LEN; + ctl_low1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + /* last packet with first packet */ + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 1)); + ctl_high1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + /* second last packet with 0th packet */ + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 2)); + ctl_high0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + ctl_slope0 = ctl_high0 - ctl_low0; + if (ctl_slope0 < 0) + ctl_slope0 *= (-1); + + ctl_slope1 = ctl_high1 - ctl_low1; + if (ctl_slope1 < 0) + ctl_slope1 *= (-1); + + ctl_slope = + ((ctl_slope0 > ctl_slope1) ? ctl_slope0 : ctl_slope1); + *slope = ctl_slope; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "ctl_slope0=%d ctl_slope1=%d ctl_slope=%d\n", + ctl_slope0, ctl_slope1, ctl_slope); + + } else if (is_ext) { + + fft_data_ptr = ((uint8_t *) buf); + ext_low0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + fft_data_ptr += FFT_LEN; + ext_low1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 1)); + ext_high1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 2)); + ext_high0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + ext_slope0 = ext_high0 - ext_low0; + if (ext_slope0 < 0) + ext_slope0 *= (-1); + + ext_slope1 = ext_high1 - ext_low1; + if (ext_slope1 < 0) + ext_slope1 *= (-1); + + ext_slope = + ((ext_slope0 > ext_slope1) ? ext_slope0 : ext_slope1); + *slope = ext_slope; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_BIN5, + "ext_slope0=%d ext_slope1=%d ext_slope=%d\n", + ext_slope0, ext_slope1, ext_slope); + } else + return 0; + + if ((ctl_slope >= MIN_CHIRPING_SLOPE) + || (ext_slope >= MIN_CHIRPING_SLOPE)) { + is_chirp = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5 | ATH_DEBUG_DFS_BIN5_FFT | + ATH_DEBUG_DFS_PHYERR_SUM, + "is_chirp=%d is_dc=%d\n", is_chirp, *is_dc); + } + return is_chirp; + +#undef FFT_LEN +#undef FFT_LOWER_BIN_MAX_INDEX_BYTE +#undef FFT_UPPER_BIN_MAX_INDEX_BYTE +#undef MIN_CHIRPING_SLOPE +} + +/* + * Merlin (and Osprey, etc) chirp radar chirp detection. + */ +static int +dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen, + int is_ctl, int is_ext, int *slope, int *is_dc) +{ +#define ABS_DIFF(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x) +#define ABS(_x) ((int)_x > 0 ? (int)_x : -(int)_x) + +#define DELTA_STEP 1 /* This should be between 1 and 3. Default is 1. */ +#define NUM_DIFFS 3 /* Number of Diffs to compute. valid range is 2-4 */ +#define MAX_DIFF 2 /* Threshold for difference of delta peaks */ +#define BIN_COUNT_MAX 6 /* Max. number of strong bins for narrow band */ + +/* + * Dynamic 20/40 mode FFT packet format related definition + */ + +#define NUM_FFT_BYTES_HT40 70 +#define NUM_BIN_BYTES_HT40 64 +#define NUM_SUBCHAN_BINS_HT40 64 +#define LOWER_INDEX_BYTE_HT40 66 +#define UPPER_INDEX_BYTE_HT40 69 +#define LOWER_WEIGHT_BYTE_HT40 64 +#define UPPER_WEIGHT_BYTE_HT40 67 +#define LOWER_MAG_BYTE_HT40 65 +#define UPPER_MAG_BYTE_HT40 68 + +/* + * Static 20 mode FFT packet format related definition + */ + +#define NUM_FFT_BYTES_HT20 31 +#define NUM_BIN_BYTES_HT20 28 +#define NUM_SUBCHAN_BINS_HT20 56 +#define LOWER_INDEX_BYTE_HT20 30 +#define UPPER_INDEX_BYTE_HT20 30 +#define LOWER_WEIGHT_BYTE_HT20 28 +#define UPPER_WEIGHT_BYTE_HT20 28 +#define LOWER_MAG_BYTE_HT20 29 +#define UPPER_MAG_BYTE_HT20 29 + + int num_fft_packets; /* number of FFT packets reported to software */ + int num_fft_bytes; + int num_bin_bytes; + int num_subchan_bins; + int lower_index_byte; + int upper_index_byte; + int lower_weight_byte; + int upper_weight_byte; + int lower_mag_byte; + int upper_mag_byte; + + int max_index_lower[DELTA_STEP + NUM_DIFFS]; + int max_index_upper[DELTA_STEP + NUM_DIFFS]; + int max_mag_lower[DELTA_STEP + NUM_DIFFS]; + int max_mag_upper[DELTA_STEP + NUM_DIFFS]; + int bin_wt_lower[DELTA_STEP + NUM_DIFFS]; + int bin_wt_upper[DELTA_STEP + NUM_DIFFS]; + int max_mag_sel[DELTA_STEP + NUM_DIFFS]; + int max_mag[DELTA_STEP + NUM_DIFFS]; + int max_index[DELTA_STEP + NUM_DIFFS]; + + int max_d[] = { 10, 19, 28 }; + int min_d[] = { 1, 2, 3 }; + + uint8_t *ptr; /* pointer to FFT data */ + int i; + int fft_start; + int chirp_found; + int delta_peak[NUM_DIFFS]; + int j; + int bin_count; + int bw_mask; + int delta_diff; + int same_sign; + int temp; + + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + num_fft_bytes = NUM_FFT_BYTES_HT40; + num_bin_bytes = NUM_BIN_BYTES_HT40; + num_subchan_bins = NUM_SUBCHAN_BINS_HT40; + lower_index_byte = LOWER_INDEX_BYTE_HT40; + upper_index_byte = UPPER_INDEX_BYTE_HT40; + lower_weight_byte = LOWER_WEIGHT_BYTE_HT40; + upper_weight_byte = UPPER_WEIGHT_BYTE_HT40; + lower_mag_byte = LOWER_MAG_BYTE_HT40; + upper_mag_byte = UPPER_MAG_BYTE_HT40; + + /* if we are in HT40MINUS then swap primary and extension */ + if (IS_CHAN_HT40_MINUS(dfs->ic->ic_curchan)) { + temp = is_ctl; + is_ctl = is_ext; + is_ext = temp; + } + + } else { + num_fft_bytes = NUM_FFT_BYTES_HT20; + num_bin_bytes = NUM_BIN_BYTES_HT20; + num_subchan_bins = NUM_SUBCHAN_BINS_HT20; + lower_index_byte = LOWER_INDEX_BYTE_HT20; + upper_index_byte = UPPER_INDEX_BYTE_HT20; + lower_weight_byte = LOWER_WEIGHT_BYTE_HT20; + upper_weight_byte = UPPER_WEIGHT_BYTE_HT20; + lower_mag_byte = LOWER_MAG_BYTE_HT20; + upper_mag_byte = UPPER_MAG_BYTE_HT20; + } + + ptr = (uint8_t *) buf; + /* + * sanity check for FFT buffer + */ + + if ((ptr == NULL) || (datalen == 0)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: FFT buffer pointer is null or size is 0\n", + __func__); + return 0; + } + + num_fft_packets = (datalen - 3) / num_fft_bytes; + if (num_fft_packets < (NUM_DIFFS + DELTA_STEP)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "datalen = %d, num_fft_packets = %d, too few packets... (exiting)\n", + datalen, num_fft_packets); + return 0; + } + + if ((((datalen - 3) % num_fft_bytes) == 2) && (datalen > num_fft_bytes)) { + /* FIXME !!! */ + ptr += 2; + datalen -= 2; + } + + for (i = 0; i < (NUM_DIFFS + DELTA_STEP); i++) { + fft_start = i * num_fft_bytes; + bin_wt_lower[i] = ptr[fft_start + lower_weight_byte] & 0x3f; + bin_wt_upper[i] = ptr[fft_start + upper_weight_byte] & 0x3f; + + max_index_lower[i] = ptr[fft_start + lower_index_byte] >> 2; + max_index_upper[i] = + (ptr[fft_start + upper_index_byte] >> 2) + num_subchan_bins; + + if (!IS_CHAN_HT40(dfs->ic->ic_curchan)) { + /* + * for HT20 mode indices are 6 bit signed number + */ + max_index_lower[i] ^= 0x20; + max_index_upper[i] = 0; + } + /* + * Reconstruct the maximum magnitude for each sub-channel. Also select + * and flag the max overall magnitude between the two sub-channels. + */ + + max_mag_lower[i] = + ((ptr[fft_start + lower_index_byte] & 0x03) << 8) + + ptr[fft_start + lower_mag_byte]; + max_mag_upper[i] = + ((ptr[fft_start + upper_index_byte] & 0x03) << 8) + + ptr[fft_start + upper_mag_byte]; + bw_mask = + ((bin_wt_lower[i] == + 0) ? 0 : is_ctl) + (((bin_wt_upper[i] == + 0) ? 0 : is_ext) << 1); + + /* + * Limit the max bin based on channel bandwidth + * If the upper sub-channel max index is stuck at '1', the signal is dominated + * by residual DC (or carrier leak) and should be ignored. + */ + + if (bw_mask == 1) { + max_mag_sel[i] = 0; + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } else if (bw_mask == 2) { + max_mag_sel[i] = 1; + max_mag[i] = max_mag_upper[i]; + max_index[i] = max_index_upper[i]; + } else if (max_index_upper[i] == num_subchan_bins) { + max_mag_sel[i] = 0; /* Ignore DC bin. */ + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } else { + if (max_mag_upper[i] > max_mag_lower[i]) { + max_mag_sel[i] = 1; + max_mag[i] = max_mag_upper[i]; + max_index[i] = max_index_upper[i]; + } else { + max_mag_sel[i] = 0; + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, max_index[i]=%d, max_index_lower[i]=%d, " + "max_index_upper[i]=%d\n", + i, max_index[i], max_index_lower[i], + max_index_upper[i]); + } + + chirp_found = 1; + delta_diff = 0; + same_sign = 1; + + /* + delta_diff computation -- look for movement in peak. + make sure that the chirp direction (i.e. sign) is always the same, + i.e. sign of the two peaks should be same. + */ + for (i = 0; i < NUM_DIFFS; i++) { + delta_peak[i] = max_index[i + DELTA_STEP] - max_index[i]; + if (i > 0) { + delta_diff = delta_peak[i] - delta_peak[i - 1]; + same_sign = + !((delta_peak[i] & 0x80) ^ + (delta_peak[i - 1] & 0x80)); + } + chirp_found &= (ABS(delta_peak[i]) >= min_d[DELTA_STEP - 1]) && + (ABS(delta_peak[i]) <= max_d[DELTA_STEP - 1]) && + same_sign && (ABS(delta_diff) <= MAX_DIFF); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, delta_peak[i]=%d, delta_diff=%d\n", + i, delta_peak[i], delta_diff); + } + + if (chirp_found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: CHIRPING_BEFORE_STRONGBIN_YES\n", __func__); + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: CHIRPING_BEFORE_STRONGBIN_NO\n", __func__); + } + + /* + Work around for potential hardware data corruption bug. Check for + wide band signal by counting strong bins indicated by bitmap flags. + This check is done if chirp_found is true. We do this as a final check + to weed out corrupt FFTs bytes. This looks expensive but in most cases it + will exit early. + */ + + for (i = 0; (i < (NUM_DIFFS + DELTA_STEP)) && (chirp_found == 1); i++) { + bin_count = 0; + /* point to the start of the 1st byte of the selected sub-channel. */ + fft_start = + (i * num_fft_bytes) + + (max_mag_sel[i] ? (num_subchan_bins >> 1) : 0); + for (j = 0; j < (num_subchan_bins >> 1); j++) { + /* + * If either bin is flagged "strong", accumulate the bin_count. + * It's not accurate, but good enough... + */ + bin_count += (ptr[fft_start + j] & 0x88) ? 1 : 0; + } + chirp_found &= (bin_count > BIN_COUNT_MAX) ? 0 : 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, computed bin_count=%d\n", i, bin_count); + } + + if (chirp_found) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: CHIRPING_YES\n", __func__); + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: CHIRPING_NO\n", __func__); + } + return chirp_found; + +#undef ABS_DIFF +#undef ABS +#undef DELTA_STEP +#undef NUM_DIFFS +#undef MAX_DIFF +#undef BIN_COUNT_MAX + +#undef NUM_FFT_BYTES_HT40 +#undef NUM_BIN_BYTES_HT40 +#undef NUM_SUBCHAN_BINS_HT40 +#undef LOWER_INDEX_BYTE_HT40 +#undef UPPER_INDEX_BYTE_HT40 +#undef LOWER_WEIGHT_BYTE_HT40 +#undef UPPER_WEIGHT_BYTE_HT40 +#undef LOWER_MAG_BYTE_HT40 +#undef UPPER_MAG_BYTE_HT40 + +#undef NUM_FFT_BYTES_HT40 +#undef NUM_BIN_BYTES_HT40 +#undef NUM_SUBCHAN_BINS_HT40 +#undef LOWER_INDEX_BYTE_HT40 +#undef UPPER_INDEX_BYTE_HT40 +#undef LOWER_WEIGHT_BYTE_HT40 +#undef UPPER_WEIGHT_BYTE_HT40 +#undef LOWER_MAG_BYTE_HT40 +#undef UPPER_MAG_BYTE_HT40 +} + +int +dfs_check_chirping(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, int is_ext, int *slope, + int *is_dc) +{ + + if (dfs->dfs_caps.ath_dfs_use_enhancement) + return dfs_check_chirping_merlin(dfs, buf, datalen, is_ctl, + is_ext, slope, is_dc); + else + return dfs_check_chirping_sowl(dfs, buf, datalen, is_ctl, + is_ext, slope, is_dc); +} + +uint8_t +dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur) +{ + + /* + * Pulses may get split into 2 during chirping, this print is only + * to show that it happened, we do not handle this condition if we + * cannot detect the chirping. + */ + /* + * SPLIT pulses will have a time stamp difference of < 50 + */ + if (diff_ts < 50) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s SPLIT pulse diffTs=%u dur=%d (old_dur=%d)\n", + __func__, diff_ts, + dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur); + } + /* + * Check if this is the 2nd or 3rd pulse in the same burst, + * PRI will be between 1000 and 2000 us + */ + if (((diff_ts >= DFS_BIN5_PRI_LOWER_LIMIT) && + (diff_ts <= DFS_BIN5_PRI_HIGHER_LIMIT))) { + /* + * This pulse belongs to the same burst as the pulse before, + * so return the same random duration for it + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s this pulse belongs to the same burst as before, give " + "it same dur=%d (old_dur=%d)\n", + __func__, dfs->dfs_rinfo.dfs_last_bin5_dur, + old_dur); + + return (dfs->dfs_rinfo.dfs_last_bin5_dur); + } + /* + * This pulse does not belong to this burst, return unchanged + * duration. + */ + return old_dur; +} + +/* + * Chirping pulses may get cut off at DC and report lower durations. + * + * This function will compute a suitable random duration for each pulse. + * Duration must be between 50 and 100 us, but remember that in + * ath_process_phyerr() which calls this function, we are dealing with the + * HW reported duration (unconverted). dfs_process_radarevent() will + * actually convert the duration into the correct value. + * + * XXX This function doesn't take into account whether the hardware + * is operating in 5GHz fast clock mode or not. + * + * XXX And this function doesn't take into account whether the hardware + * is peregrine or not. Grr. + */ +int dfs_get_random_bin5_dur(struct ath_dfs *dfs, uint64_t tstamp) +{ + uint8_t new_dur = MIN_BIN5_DUR; + int range; + + get_random_bytes(&new_dur, sizeof(uint8_t)); + + range = (MAX_BIN5_DUR - MIN_BIN5_DUR + 1); + + new_dur %= range; + + new_dur += MIN_BIN5_DUR; + + return new_dur; +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_init.c b/core/sap/dfs/src/dfs_init.c new file mode 100644 index 0000000000..ca259c4af8 --- /dev/null +++ b/core/sap/dfs/src/dfs_init.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_init.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +extern int domainoverride; + +/* + * Clear all delay lines for all filter types + * + * This may be called before any radar pulses are configured + * (eg on a non-DFS channel, with radar PHY errors still showing up.) + * In that case, just drop out early. + */ +void dfs_reset_alldelaylines(struct ath_dfs *dfs) +{ + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf; + struct dfs_delayline *dl; + struct dfs_pulseline *pl; + int i, j; + + if (dfs == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: sc_dfs is NULL", __func__, __LINE__); + return; + } + pl = dfs->pulses; + + if (pl == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: pl==NULL, dfs=%p", __func__, __LINE__, dfs); + return; + } + + if (dfs->dfs_b5radars == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: pl==NULL, b5radars=%p", __func__, __LINE__, + dfs->dfs_b5radars); + return; + } + + /* reset the pulse log */ + pl->pl_firstelem = pl->pl_numelems = 0; + pl->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; + + for (i = 0; i < DFS_MAX_RADAR_TYPES; i++) { + if (dfs->dfs_radarf[i] != NULL) { + ft = dfs->dfs_radarf[i]; + if (NULL != ft) { + for (j = 0; j < ft->ft_numfilters; j++) { + rf = &(ft->ft_filters[j]); + dl = &(rf->rf_dl); + if (dl != NULL) { + OS_MEMZERO(dl, + sizeof(struct + dfs_delayline)); + dl->dl_lastelem = + (0xFFFFFFFF) & + DFS_MAX_DL_MASK; + } + } + } + } + } + for (i = 0; i < dfs->dfs_rinfo.rn_numbin5radars; i++) { + OS_MEMZERO(&(dfs->dfs_b5radars[i].br_elems[0]), + sizeof(struct dfs_bin5elem) * DFS_MAX_B5_SIZE); + dfs->dfs_b5radars[i].br_firstelem = 0; + dfs->dfs_b5radars[i].br_numelems = 0; + dfs->dfs_b5radars[i].br_lastelem = + (0xFFFFFFFF) & DFS_MAX_B5_MASK; + } +} + +/* + * Clear only a single delay line + */ + +void dfs_reset_delayline(struct dfs_delayline *dl) +{ + OS_MEMZERO(&(dl->dl_elems[0]), sizeof(dl->dl_elems)); + dl->dl_lastelem = (0xFFFFFFFF) & DFS_MAX_DL_MASK; +} + +void dfs_reset_filter_delaylines(struct dfs_filtertype *dft) +{ + int i; + struct dfs_filter *df; + for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { + df = &dft->ft_filters[i]; + dfs_reset_delayline(&(df->rf_dl)); + } +} + +void dfs_reset_radarq(struct ath_dfs *dfs) +{ + struct dfs_event *event; + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL", __func__); + return; + } + ATH_DFSQ_LOCK(dfs); + ATH_DFSEVENTQ_LOCK(dfs); + while (!STAILQ_EMPTY(&(dfs->dfs_radarq))) { + event = STAILQ_FIRST(&(dfs->dfs_radarq)); + STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); + OS_MEMZERO(event, sizeof(struct dfs_event)); + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); + } + ATH_DFSEVENTQ_UNLOCK(dfs); + ATH_DFSQ_UNLOCK(dfs); +} + +/* This function Initialize the radar filter tables + * if the ath dfs domain is uninitalized or + * ath dfs domain is different from hal dfs domain + */ +int dfs_init_radar_filters(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info) +{ + uint32_t T, Tmax; + int numpulses, p, n, i; + int numradars = 0, numb5radars = 0; + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf = NULL; + struct dfs_pulse *dfs_radars; + struct dfs_bin5pulse *b5pulses = NULL; + int32_t min_rssithresh = DFS_MAX_RSSI_VALUE; + uint32_t max_pulsedur = 0; + + if (dfs == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: dfs is NULL", __func__, __LINE__); + return DFS_STATUS_FAIL; + } + /* clear up the dfs domain flag first */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 0; +#endif + + /* + * If radar_info is NULL or dfsdomain is NULL, treat + * the rest of the radar configuration as suspect. + */ + if (radar_info == NULL || radar_info->dfsdomain == 0) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: Unknown dfs domain %d ", + __func__, __LINE__, dfs->dfsdomain); + /* Disable radar detection since we don't have a radar domain */ + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + /* Returning success though we are not completing init. A failure + * will fail dfs_attach also. + */ + return DFS_STATUS_SUCCESS; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]:dfsdomain=%d, numradars=%d, numb5radars=%d", + __func__, __LINE__, radar_info->dfsdomain, + radar_info->numradars, radar_info->numb5radars); + dfs->dfsdomain = radar_info->dfsdomain; + dfs_radars = radar_info->dfs_radars; + numradars = radar_info->numradars; + b5pulses = radar_info->b5pulses; + numb5radars = radar_info->numb5radars; + + /* XXX this should be an explicit copy of some sort! */ + dfs->dfs_defaultparams = radar_info->dfs_defaultparams; + +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 1; +#endif + + dfs->dfs_rinfo.rn_numradars = 0; + /* Clear filter type table */ + for (n = 0; n < 256; n++) { + for (i = 0; i < DFS_MAX_RADAR_OVERLAP; i++) + (dfs->dfs_radartable[n])[i] = -1; + } + /* Now, initialize the radar filters */ + for (p = 0; p < numradars; p++) { + ft = NULL; + for (n = 0; n < dfs->dfs_rinfo.rn_numradars; n++) { + if ((dfs_radars[p].rp_pulsedur == + dfs->dfs_radarf[n]->ft_filterdur) + && (dfs_radars[p].rp_numpulses == + dfs->dfs_radarf[n]->ft_numpulses) + && (dfs_radars[p].rp_mindur == + dfs->dfs_radarf[n]->ft_mindur) + && (dfs_radars[p].rp_maxdur == + dfs->dfs_radarf[n]->ft_maxdur)) { + ft = dfs->dfs_radarf[n]; + break; + } + } + if (ft == NULL) { + /* No filter of the appropriate dur was found */ + if ((dfs->dfs_rinfo.rn_numradars + 1) > + DFS_MAX_RADAR_TYPES) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: Too many filter types", + __func__); + goto bad4; + } + ft = dfs->dfs_radarf[dfs->dfs_rinfo.rn_numradars]; + ft->ft_numfilters = 0; + ft->ft_numpulses = dfs_radars[p].rp_numpulses; + ft->ft_patterntype = dfs_radars[p].rp_patterntype; + ft->ft_mindur = dfs_radars[p].rp_mindur; + ft->ft_maxdur = dfs_radars[p].rp_maxdur; + ft->ft_filterdur = dfs_radars[p].rp_pulsedur; + ft->ft_rssithresh = dfs_radars[p].rp_rssithresh; + ft->ft_rssimargin = dfs_radars[p].rp_rssimargin; + ft->ft_minpri = 1000000; + + if (ft->ft_rssithresh < min_rssithresh) + min_rssithresh = ft->ft_rssithresh; + if (ft->ft_maxdur > max_pulsedur) + max_pulsedur = ft->ft_maxdur; + for (i = ft->ft_mindur; i <= ft->ft_maxdur; i++) { + uint32_t stop = 0, tableindex = 0; + while ((tableindex < DFS_MAX_RADAR_OVERLAP) + && (!stop)) { + if ((dfs-> + dfs_radartable[i])[tableindex] == + -1) + stop = 1; + else + tableindex++; + } + if (stop) { + (dfs->dfs_radartable[i])[tableindex] = + (int8_t) (dfs->dfs_rinfo. + rn_numradars); + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: Too many overlapping radar filters", + __func__); + goto bad4; + } + } + dfs->dfs_rinfo.rn_numradars++; + } + rf = &(ft->ft_filters[ft->ft_numfilters++]); + dfs_reset_delayline(&rf->rf_dl); + numpulses = dfs_radars[p].rp_numpulses; + + rf->rf_numpulses = numpulses; + rf->rf_patterntype = dfs_radars[p].rp_patterntype; + rf->rf_pulseid = dfs_radars[p].rp_pulseid; + rf->rf_mindur = dfs_radars[p].rp_mindur; + rf->rf_maxdur = dfs_radars[p].rp_maxdur; + rf->rf_numpulses = dfs_radars[p].rp_numpulses; + rf->rf_ignore_pri_window = dfs_radars[p].rp_ignore_pri_window; + T = (100000000 / dfs_radars[p].rp_max_pulsefreq) - + 100 * (dfs_radars[p].rp_meanoffset); + rf->rf_minpri = + dfs_round((int32_t) T - + (100 * (dfs_radars[p].rp_pulsevar))); + Tmax = + (100000000 / dfs_radars[p].rp_pulsefreq) - + 100 * (dfs_radars[p].rp_meanoffset); + rf->rf_maxpri = + dfs_round((int32_t) Tmax + + (100 * (dfs_radars[p].rp_pulsevar))); + + if (rf->rf_minpri < ft->ft_minpri) + ft->ft_minpri = rf->rf_minpri; + + rf->rf_fixed_pri_radar_pulse = + (dfs_radars[p].rp_max_pulsefreq == + dfs_radars[p].rp_pulsefreq) ? 1 : 0; + rf->rf_threshold = dfs_radars[p].rp_threshold; + rf->rf_filterlen = rf->rf_maxpri * rf->rf_numpulses; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]: minprf = %d maxprf = %d pulsevar = %d thresh=%d", + __func__, __LINE__, dfs_radars[p].rp_pulsefreq, + dfs_radars[p].rp_max_pulsefreq, + dfs_radars[p].rp_pulsevar, rf->rf_threshold); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]:minpri = %d maxpri = %d filterlen = %d filterID = %d", + __func__, __LINE__, rf->rf_minpri, rf->rf_maxpri, + rf->rf_filterlen, rf->rf_pulseid); + + } + +#ifdef DFS_DEBUG + dfs_print_filters(ic); +#endif + dfs->dfs_rinfo.rn_numbin5radars = numb5radars; + if (dfs->dfs_b5radars != NULL) + OS_FREE(dfs->dfs_b5radars); + + dfs->dfs_b5radars = (struct dfs_bin5radars *)os_malloc(NULL, + numb5radars * + sizeof(struct + dfs_bin5radars), + GFP_KERNEL); + if (dfs->dfs_b5radars == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: cannot allocate memory for bin5 radars", + __func__); + goto bad4; + } + for (n = 0; n < numb5radars; n++) { + dfs->dfs_b5radars[n].br_pulse = b5pulses[n]; + dfs->dfs_b5radars[n].br_pulse.b5_timewindow *= 1000000; + if (dfs->dfs_b5radars[n].br_pulse.b5_rssithresh < + min_rssithresh) + min_rssithresh = + dfs->dfs_b5radars[n].br_pulse.b5_rssithresh; + if (dfs->dfs_b5radars[n].br_pulse.b5_maxdur > max_pulsedur) + max_pulsedur = dfs->dfs_b5radars[n].br_pulse.b5_maxdur; + } + dfs_reset_alldelaylines(dfs); + dfs_reset_radarq(dfs); + dfs->dfs_curchan_radindex = -1; + dfs->dfs_extchan_radindex = -1; + dfs->dfs_rinfo.rn_minrssithresh = min_rssithresh; + /* Convert durations to TSF ticks */ + dfs->dfs_rinfo.rn_maxpulsedur = + dfs_round((int32_t) ((max_pulsedur * 100 / 80) * 100)); + /* relax the max pulse duration a little bit due to inaccuracy caused by chirping. */ + dfs->dfs_rinfo.rn_maxpulsedur = dfs->dfs_rinfo.rn_maxpulsedur + 20; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]: DFS min filter rssiThresh = %d", + __func__, __LINE__, min_rssithresh); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]:DFS max pulse dur = %d ticks", + __func__, __LINE__, dfs->dfs_rinfo.rn_maxpulsedur); + return DFS_STATUS_SUCCESS; + +bad4: + return DFS_STATUS_FAIL; +} + +void dfs_clear_stats(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + if (dfs == NULL) + return; + OS_MEMZERO(&dfs->ath_dfs_stats, sizeof(struct dfs_stats)); + dfs->ath_dfs_stats.last_reset_tstamp = ic->ic_get_TSF64(ic); +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_ioctl.h b/core/sap/dfs/src/dfs_ioctl.h new file mode 100644 index 0000000000..abe6c0c8c7 --- /dev/null +++ b/core/sap/dfs/src/dfs_ioctl.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_ioctl.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/* + * ioctl defines + */ + +#ifndef _DFS_IOCTL_H_ +#define _DFS_IOCTL_H_ + +#define DFS_MUTE_TIME 1 +#define DFS_SET_THRESH 2 +#define DFS_GET_THRESH 3 +#define DFS_GET_USENOL 4 +#define DFS_SET_USENOL 5 +#define DFS_RADARDETECTS 6 +#define DFS_BANGRADAR 7 +#define DFS_SHOW_NOL 8 +#define DFS_DISABLE_DETECT 9 +#define DFS_ENABLE_DETECT 10 +#define DFS_DISABLE_FFT 11 +#define DFS_ENABLE_FFT 12 +#define DFS_SET_DEBUG_LEVEL 13 +#define DFS_GET_NOL 14 +#define DFS_SET_NOL 15 + +#define DFS_SET_FALSE_RSSI_THRES 16 +#define DFS_SET_PEAK_MAG 17 +#define DFS_IGNORE_CAC 18 +#define DFS_SET_NOL_TIMEOUT 19 +#define DFS_LAST_IOCTL 20 +#ifndef IEEE80211_CHAN_MAX +#define IEEE80211_CHAN_MAX 255 +#endif + +struct dfsreq_nolelem { + uint16_t nol_freq; /* NOL channel frequency */ + uint16_t nol_chwidth; + unsigned long nol_start_ticks; /* OS ticks when the NOL timer started */ + uint32_t nol_timeout_ms; /* Nol timeout value in msec */ +}; + +struct dfsreq_nolinfo { + uint32_t ic_nchans; + struct dfsreq_nolelem dfs_nol[IEEE80211_CHAN_MAX]; +}; + +/* + * ioctl parameter types + */ + +#define DFS_PARAM_FIRPWR 1 +#define DFS_PARAM_RRSSI 2 +#define DFS_PARAM_HEIGHT 3 +#define DFS_PARAM_PRSSI 4 +#define DFS_PARAM_INBAND 5 +/* 5413 specific parameters */ +#define DFS_PARAM_RELPWR 7 +#define DFS_PARAM_RELSTEP 8 +#define DFS_PARAM_MAXLEN 9 + +struct dfs_ioctl_params { + int32_t dfs_firpwr; /* FIR pwr out threshold */ + int32_t dfs_rrssi; /* Radar rssi thresh */ + int32_t dfs_height; /* Pulse height thresh */ + int32_t dfs_prssi; /* Pulse rssi thresh */ + int32_t dfs_inband; /* Inband thresh */ + int32_t dfs_relpwr; /* pulse relative pwr thresh */ + int32_t dfs_relstep; /* pulse relative step thresh */ + int32_t dfs_maxlen; /* pulse max duration */ +}; + +/* + * XXX keep these in sync with ath_dfs_phyerr_param! + */ +#define DFS_IOCTL_PARAM_NOVAL 65535 +#define DFS_IOCTL_PARAM_ENABLE 0x8000 + +#endif /* _DFS_IOCTL_H_ */ diff --git a/core/sap/dfs/src/dfs_ioctl_private.h b/core/sap/dfs/src/dfs_ioctl_private.h new file mode 100644 index 0000000000..6b268b713e --- /dev/null +++ b/core/sap/dfs/src/dfs_ioctl_private.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_ioctl_private.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/* + * ioctl defines + */ + +#ifndef _DFS_IOCTL_PRIVATE_H_ +#define _DFS_IOCTL_PRIVATE_H_ + +/* + * Assert that the NOVAL values match. + */ +#if (ATH_DFS_PHYERR_PARAM_NOVAL != DFS_IOCTL_PARAM_NOVAL) +#error "ATH_DFS_PHYERR_PARAM_NOVAL != DFS_IOCTL_PARAM_NOVAL" +#endif + +/* + * Assert that the ENABLE values match. + */ +#if (ATH_DFS_PHYERR_PARAM_ENABLE != DFS_IOCTL_PARAM_ENABLE) +#error "ATH_DFS_PHYERR_PARAM_ENABLE != DFS_IOCTL_PARAM_ENABLE" +#endif + +/* + * These two methods are used by the lmac glue to copy between + * the DFS and HAL PHY configuration. + * + * I'm "cheating" here and assuming that the ENABLE and NOVAL + * values match - see the above macros. + */ +static inline void +ath_dfs_ioctlparam_to_dfsparam(const struct dfs_ioctl_params *src, + struct ath_dfs_phyerr_param *dst) +{ + + dst->pe_firpwr = src->dfs_firpwr; + dst->pe_rrssi = src->dfs_rrssi; + dst->pe_height = src->dfs_height; + dst->pe_prssi = src->dfs_prssi; + dst->pe_inband = src->dfs_inband; + dst->pe_relpwr = src->dfs_relpwr; + dst->pe_relstep = src->dfs_relstep; + dst->pe_maxlen = src->dfs_maxlen; +} + +static inline void +ath_dfs_dfsparam_to_ioctlparam(struct ath_dfs_phyerr_param *src, + struct dfs_ioctl_params *dst) +{ + + dst->dfs_firpwr = src->pe_firpwr; + dst->dfs_rrssi = src->pe_rrssi; + dst->dfs_height = src->pe_height; + dst->dfs_prssi = src->pe_prssi; + dst->dfs_inband = src->pe_inband; + dst->dfs_relpwr = src->pe_relpwr; + dst->dfs_relstep = src->pe_relstep; + dst->dfs_maxlen = src->pe_maxlen; +} + +#endif /* _DFS_IOCTL_PRIVATE_H_ */ diff --git a/core/sap/dfs/src/dfs_misc.c b/core/sap/dfs/src/dfs_misc.c new file mode 100644 index 0000000000..8cf4a2c8cd --- /dev/null +++ b/core/sap/dfs/src/dfs_misc.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_misc.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifndef UNINET +/* TO DO DFS + #include + */ +#endif +#ifdef ATH_SUPPORT_DFS + +static int adjust_pri_per_chan_busy(int ext_chan_busy, int pri_margin) +{ + int adjust_pri = 0; + + if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) { + + adjust_pri = + (ext_chan_busy - + DFS_EXT_CHAN_LOADING_THRESH) * (pri_margin); + adjust_pri /= 100; + + } + return adjust_pri; +} + +static int adjust_thresh_per_chan_busy(int ext_chan_busy, int thresh) +{ + int adjust_thresh = 0; + + if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) { + + adjust_thresh = + (ext_chan_busy - DFS_EXT_CHAN_LOADING_THRESH) * thresh; + adjust_thresh /= 100; + + } + return adjust_thresh; +} + +/* For the extension channel, if legacy traffic is present, we see a lot of false alarms, + so make the PRI margin narrower depending on the busy % for the extension channel.*/ + +int +dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect, + int is_fixed_pattern) +{ + + int adjust_pri = 0, ext_chan_busy = 0; + int pri_margin; + + if (is_fixed_pattern) + pri_margin = DFS_DEFAULT_FIXEDPATTERN_PRI_MARGIN; + else + pri_margin = DFS_DEFAULT_PRI_MARGIN; + + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + if (ext_chan_busy >= 0) { + dfs->dfs_rinfo.ext_chan_busy_ts = + dfs->ic->ic_get_TSF64(dfs->ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy; + } else { + /* Check to see if the cached value of ext_chan_busy can be used */ + ext_chan_busy = 0; + if (dfs->dfs_rinfo.dfs_ext_chan_busy) { + if (dfs->dfs_rinfo.rn_lastfull_ts < + dfs->dfs_rinfo.ext_chan_busy_ts) { + ext_chan_busy = + dfs->dfs_rinfo.dfs_ext_chan_busy; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " PRI Use cached copy of ext_chan_busy extchanbusy=%d \n", + ext_chan_busy); + } + } + } + adjust_pri = + adjust_pri_per_chan_busy(ext_chan_busy, pri_margin); + + pri_margin -= adjust_pri; + } + return pri_margin; +} + +/* For the extension channel, if legacy traffic is present, we see a lot of false alarms, + so make the thresholds higher depending on the busy % for the extension channel.*/ + +int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf, + int is_extchan_detect) +{ + int ext_chan_busy = 0; + int thresh, adjust_thresh = 0; + + thresh = rf->rf_threshold; + + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + if (ext_chan_busy >= 0) { + dfs->dfs_rinfo.ext_chan_busy_ts = + dfs->ic->ic_get_TSF64(dfs->ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy; + } else { + /* Check to see if the cached value of ext_chan_busy can be used */ + ext_chan_busy = 0; + if (dfs->dfs_rinfo.dfs_ext_chan_busy) { + if (dfs->dfs_rinfo.rn_lastfull_ts < + dfs->dfs_rinfo.ext_chan_busy_ts) { + ext_chan_busy = + dfs->dfs_rinfo.dfs_ext_chan_busy; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " THRESH Use cached copy of ext_chan_busy extchanbusy=%d rn_lastfull_ts=%llu ext_chan_busy_ts=%llu\n", + ext_chan_busy, + (unsigned long long)dfs-> + dfs_rinfo.rn_lastfull_ts, + (unsigned long long)dfs-> + dfs_rinfo.ext_chan_busy_ts); + } + } + } + + adjust_thresh = + adjust_thresh_per_chan_busy(ext_chan_busy, thresh); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " filterID=%d extchanbusy=%d adjust_thresh=%d\n", + rf->rf_pulseid, ext_chan_busy, adjust_thresh); + + thresh += adjust_thresh; + } + return thresh; +} + +uint32_t dfs_round(int32_t val) +{ + uint32_t ival, rem; + + if (val < 0) + return 0; + ival = val / 100; + rem = val - (ival * 100); + if (rem < 50) + return ival; + else + return (ival + 1); +} + +struct ieee80211_channel *ieee80211_get_extchan(struct ieee80211com *ic) +{ + int chan_offset = 0; + if (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(ic->ic_curchan)) { + chan_offset = 20; + } else if (IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(ic->ic_curchan)) { + chan_offset = -20; + } else { + return NULL; + } + return (ic-> + ic_find_channel(ic, ic->ic_curchan->ic_freq + chan_offset, + IEEE80211_CHAN_11NA_HT20)); +} + +/* + * Finds the radar state entry that matches the current channel + */ +struct dfs_state *dfs_getchanstate(struct ath_dfs *dfs, uint8_t *index, + int ext_chan_flag) +{ + struct dfs_state *rs = NULL; + int i; + struct ieee80211_channel *cmp_ch; + + if (dfs == NULL) { + printk("%s[%d]: sc_dfs is NULL\n", __func__, __LINE__); + /* DFS_DPRINTK(dfs, ATH_DEBUG_DFS,"%s: sc_dfs is NULL\n",__func__); */ + return NULL; + } + + if (ext_chan_flag) { + cmp_ch = ieee80211_get_extchan(dfs->ic); + if (cmp_ch) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Extension channel freq = %u flags=0x%x\n", + cmp_ch->ic_freq, cmp_ch->ic_flagext); + } else { + return NULL; + } + + } else { + cmp_ch = dfs->ic->ic_curchan; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Primary channel freq = %u flags=0x%x\n", + cmp_ch->ic_freq, cmp_ch->ic_flagext); + } + for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { + if ((dfs->dfs_radar[i].rs_chan.ic_freq == cmp_ch->ic_freq) && + (dfs->dfs_radar[i].rs_chan.ic_flags == cmp_ch->ic_flags)) { + if (index != NULL) + *index = (uint8_t) i; + return &(dfs->dfs_radar[i]); + } + } + /* No existing channel found, look for first free channel state entry */ + for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { + if (dfs->dfs_radar[i].rs_chan.ic_freq == 0) { + rs = &(dfs->dfs_radar[i]); + /* Found one, set channel info and default thresholds */ + rs->rs_chan = *cmp_ch; + + /* Copy the parameters from the default set */ + ath_dfs_phyerr_param_copy(&rs->rs_param, + &dfs->dfs_defaultparams); + + if (index != NULL) + *index = (uint8_t) i; + return (rs); + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s: No more radar states left.\n", + __func__); + return (NULL); +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_nol.c b/core/sap/dfs/src/dfs_nol.c new file mode 100644 index 0000000000..5a5ec795bc --- /dev/null +++ b/core/sap/dfs/src/dfs_nol.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2002-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_nol.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifndef UNINET +/*TO DO DFS + #include + */ +#endif +#if defined(ATH_SUPPORT_DFS) && !defined(ATH_DFS_RADAR_DETECTION_ONLY) +#include "dfs_ioctl.h" +#include "dfs_ioctl_private.h" +#include "cdf_time.h" /* cdf_time_t, cdf_system_time_after */ + +static void +dfs_nol_delete(struct ath_dfs *dfs, uint16_t delfreq, uint16_t delchwidth); + +static os_timer_func(dfs_remove_from_nol) +{ + struct dfs_nol_timer_arg *nol_arg; + struct ath_dfs *dfs; + struct ieee80211com *ic; + uint16_t delfreq; + uint16_t delchwidth; + + OS_GET_TIMER_ARG(nol_arg, struct dfs_nol_timer_arg *); + + dfs = nol_arg->dfs; + ic = dfs->ic; + delfreq = nol_arg->delfreq; + delchwidth = nol_arg->delchwidth; + + /* Only operate in HOSTAP/IBSS */ + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + ic->ic_opmode != IEEE80211_M_IBSS) + goto done; + + /* Delete the given NOL entry */ + dfs_nol_delete(dfs, delfreq, delchwidth); + + /* Update the wireless stack with the new NOL */ + dfs_nol_update(dfs); + +done: + OS_FREE(nol_arg); + return; +} + +void dfs_print_nol(struct ath_dfs *dfs) +{ + struct dfs_nolelem *nol; + uint32_t diff_ms, remaining_sec; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + nol = dfs->dfs_nol; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: NOL", __func__); + while (nol != NULL) { + diff_ms = + cdf_system_ticks_to_msecs(cdf_system_ticks() - + nol->nol_start_ticks); + diff_ms = (nol->nol_timeout_ms - diff_ms); + remaining_sec = diff_ms / 1000; /* convert to seconds */ + nol = nol->nol_next; + } +} + +void +dfs_get_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, int *nchan) +{ + struct dfs_nolelem *nol; + + *nchan = 0; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + + nol = dfs->dfs_nol; + while (nol != NULL) { + dfs_nol[*nchan].nol_freq = nol->nol_freq; + dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth; + dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks; + dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms; + ++(*nchan); + nol = nol->nol_next; + } +} + +void dfs_set_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, int nchan) +{ +#define TIME_IN_MS 1000 + uint32_t nol_time_left_ms; + struct ieee80211_channel chan; + int i; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + + for (i = 0; i < nchan; i++) { + nol_time_left_ms = + cdf_system_ticks_to_msecs(cdf_system_ticks() - + dfs_nol[i].nol_start_ticks); + if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) { + chan.ic_freq = dfs_nol[i].nol_freq; + chan.ic_flags = 0; + chan.ic_flagext = 0; + nol_time_left_ms = + (dfs_nol[i].nol_timeout_ms - nol_time_left_ms); + dfs_nol_addchan(dfs, &chan, + (nol_time_left_ms / TIME_IN_MS)); + } + } +#undef TIME_IN_MS + dfs_nol_update(dfs); +} + +void +dfs_nol_addchan(struct ath_dfs *dfs, struct ieee80211_channel *chan, + uint32_t dfs_nol_timeout) +{ +#define TIME_IN_MS 1000 +#define TIME_IN_US (TIME_IN_MS * 1000) + struct dfs_nolelem *nol, *elem, *prev; + struct dfs_nol_timer_arg *dfs_nol_arg; + /* XXX for now, assume all events are 20MHz wide */ + int ch_width = 20; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + nol = dfs->dfs_nol; + prev = dfs->dfs_nol; + elem = NULL; + while (nol != NULL) { + if ((nol->nol_freq == chan->ic_freq) && + (nol->nol_chwidth == ch_width)) { + nol->nol_start_ticks = cdf_system_ticks(); + nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: Update OS Ticks for NOL %d MHz / %d MHz", + __func__, nol->nol_freq, nol->nol_chwidth); + OS_CANCEL_TIMER(&nol->nol_timer); + OS_SET_TIMER(&nol->nol_timer, + dfs_nol_timeout * TIME_IN_MS); + return; + } + prev = nol; + nol = nol->nol_next; + } + /* Add a new element to the NOL */ + elem = + (struct dfs_nolelem *)os_malloc(NULL, sizeof(struct dfs_nolelem), + GFP_ATOMIC); + if (elem == NULL) { + goto bad; + } + dfs_nol_arg = (struct dfs_nol_timer_arg *)os_malloc(NULL, + sizeof(struct + dfs_nol_timer_arg), + GFP_ATOMIC); + if (dfs_nol_arg == NULL) { + OS_FREE(elem); + goto bad; + } + elem->nol_freq = chan->ic_freq; + elem->nol_chwidth = ch_width; + elem->nol_start_ticks = cdf_system_ticks(); + elem->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS; + elem->nol_next = NULL; + if (prev) { + prev->nol_next = elem; + } else { + /* This is the first element in the NOL */ + dfs->dfs_nol = elem; + } + dfs_nol_arg->dfs = dfs; + dfs_nol_arg->delfreq = elem->nol_freq; + dfs_nol_arg->delchwidth = elem->nol_chwidth; + + OS_INIT_TIMER(NULL, &elem->nol_timer, dfs_remove_from_nol, + dfs_nol_arg, CDF_TIMER_TYPE_SW); + OS_SET_TIMER(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS); + + /* Update the NOL counter */ + dfs->dfs_nol_count++; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: new NOL channel %d MHz / %d MHz", + __func__, elem->nol_freq, elem->nol_chwidth); + return; + +bad: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL | ATH_DEBUG_DFS, + "%s: failed to allocate memory for nol entry", __func__); + +#undef TIME_IN_MS +#undef TIME_IN_US +} + +/* + * Delete the given frequency/chwidth from the NOL. + */ +static void +dfs_nol_delete(struct ath_dfs *dfs, uint16_t delfreq, uint16_t delchwidth) +{ + struct dfs_nolelem *nol, **prev_next; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL", __func__); + return; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: remove channel=%d/%d MHz from NOL", + __func__, delfreq, delchwidth); + prev_next = &(dfs->dfs_nol); + nol = dfs->dfs_nol; + while (nol != NULL) { + if (nol->nol_freq == delfreq && nol->nol_chwidth == delchwidth) { + *prev_next = nol->nol_next; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s removing channel %d/%dMHz from NOL tstamp=%d", + __func__, nol->nol_freq, nol->nol_chwidth, + (cdf_system_ticks_to_msecs + (cdf_system_ticks()) / 1000)); + OS_CANCEL_TIMER(&nol->nol_timer); + OS_FREE(nol); + nol = NULL; + nol = *prev_next; + + /* Update the NOL counter */ + dfs->dfs_nol_count--; + + /* Be paranoid! */ + if (dfs->dfs_nol_count < 0) { + DFS_PRINTK("%s: dfs_nol_count < 0; eek!", + __func__); + dfs->dfs_nol_count = 0; + } + + } else { + prev_next = &(nol->nol_next); + nol = nol->nol_next; + } + } +} + +/* + * notify the driver/umac that it should update the channel radar/NOL + * flags based on the current NOL list. + */ +void dfs_nol_update(struct ath_dfs *dfs) +{ + struct ieee80211com *ic = dfs->ic; + struct dfs_nol_chan_entry *dfs_nol; + struct dfs_nolelem *nol; + int nlen; + + /* + * Allocate enough entries to store the NOL. + * + * At least on Linux (don't ask why), if you allocate a 0 entry + * array, the returned pointer is 0x10. Make sure you're + * aware of this when you start debugging. + */ + dfs_nol = (struct dfs_nol_chan_entry *)os_malloc(NULL, + sizeof(struct + dfs_nol_chan_entry) + * dfs->dfs_nol_count, + GFP_ATOMIC); + + if (dfs_nol == NULL) { + /* + * XXX TODO: if this fails, just schedule a task to retry + * updating the NOL at a later stage. That way the NOL + * update _DOES_ happen - hopefully the failure was just + * temporary. + */ + DFS_PRINTK("%s: failed to allocate NOL update memory!", + __func__); + return; + } + + /* populate the nol array */ + nlen = 0; + + nol = dfs->dfs_nol; + while (nol != NULL && nlen < dfs->dfs_nol_count) { + dfs_nol[nlen].nol_chfreq = nol->nol_freq; + dfs_nol[nlen].nol_chwidth = nol->nol_chwidth; + dfs_nol[nlen].nol_start_ticks = nol->nol_start_ticks; + dfs_nol[nlen].nol_timeout_ms = nol->nol_timeout_ms; + nlen++; + nol = nol->nol_next; + } + + /* Be suitably paranoid for now */ + if (nlen != dfs->dfs_nol_count) + DFS_PRINTK("%s: nlen (%d) != dfs->dfs_nol_count (%d)!", + __func__, nlen, dfs->dfs_nol_count); + + /* + * Call the driver layer to have it recalculate the NOL flags for + * each driver/umac channel. + * + * If the list is empty, pass NULL instead of dfs_nol. + * + * The operating system may have some special representation for + * "malloc a 0 byte memory region" - for example, + * Linux 2.6.38-13 (ubuntu) returns 0x10 rather than a valid + * allocation (and is likely not NULL so the pointer doesn't + * match NULL checks in any later code. + */ + ic->ic_dfs_clist_update(ic, DFS_NOL_CLIST_CMD_UPDATE, + (nlen > 0) ? dfs_nol : NULL, nlen); + + /* + * .. and we're done. + */ + OS_FREE(dfs_nol); +} + +void dfs_nol_timer_cleanup(struct ath_dfs *dfs) +{ + struct dfs_nolelem *nol = dfs->dfs_nol, *prev; + + /* First Cancel timer */ + while (nol) { + OS_CANCEL_TIMER(&nol->nol_timer); + nol = nol->nol_next; + } + /* Free NOL elem, don't mix this while loop with above loop */ + nol = dfs->dfs_nol; + while (nol) { + prev = nol; + nol = nol->nol_next; + OS_FREE(prev); + } + return; +} +#endif /* defined(ATH_SUPPORT_DFS) && !defined(ATH_DFS_RADAR_DETECTION_ONLY) */ diff --git a/core/sap/dfs/src/dfs_phyerr.h b/core/sap/dfs/src/dfs_phyerr.h new file mode 100644 index 0000000000..22a900f2e0 --- /dev/null +++ b/core/sap/dfs/src/dfs_phyerr.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * dfs_phyerr.h + * + * OVERVIEW: + * + * Source code borrowed from QCA_MAIN DFS module + * + * DEPENDENCIES: + * + * Are listed for each API below. + */ + + +#ifndef __DFS_PHYERR_H__ +#define __DFS_PHYERR_H__ + +extern int dfs_process_phyerr_bb_tlv(struct ath_dfs *dfs, void *buf, + uint16_t datalen, uint8_t rssi, + uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e, + bool enable_log); + +#endif /* __DFS_PHYERR_H__ */ diff --git a/core/sap/dfs/src/dfs_phyerr_tlv.c b/core/sap/dfs/src/dfs_phyerr_tlv.c new file mode 100644 index 0000000000..205c170873 --- /dev/null +++ b/core/sap/dfs/src/dfs_phyerr_tlv.c @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "dfs.h" +/* TO DO DFS + #include + */ +/* TO DO DFS + #include + */ +#include "dfs_phyerr.h" +#include "dfs_phyerr_tlv.h" + +/* + * Parsed radar status + */ +struct rx_radar_status { + uint32_t raw_tsf; + uint32_t tsf_offset; + int rssi; + int pulse_duration; + int is_chirp:1; + int delta_peak; + int delta_diff; + int sidx; + int freq_offset; /* in KHz */ +}; + +struct rx_search_fft_report { + uint32_t total_gain_db; + uint32_t base_pwr_db; + int fft_chn_idx; + int peak_sidx; + int relpwr_db; + int avgpwr_db; + int peak_mag; + int num_str_bins_ib; +}; + +/* + * XXX until "fastclk" is stored in the DFS configuration.. + */ +#define PERE_IS_OVERSAMPLING(_dfs) (1) + +/* + * XXX there _has_ to be a better way of doing this! + * -adrian + */ +static int32_t sign_extend_32(uint32_t v, int nb) +{ + uint32_t m = 1U << (nb - 1); + + /* Chop off high bits, just in case */ + v &= v & ((1U << nb) - 1); + + /* Extend */ + return (v ^ m) - m; +} + +/* + * Calculate the frequency offset from the given signed bin index + * from the radar summary report. + * + * This takes the oversampling mode into account. + * + * For oversampling, each bin has resolution 44MHz/128. + * For non-oversampling, each bin has resolution 40MHz/128. + * + * It returns kHz - ie, 1000th's of MHz. + */ +static int calc_freq_offset(int sindex, int is_oversampling) +{ + + if (is_oversampling) + return sindex * (44000 / 128); + else + return sindex * (40000 / 128); +} + +static void +radar_summary_print(struct ath_dfs *dfs, + struct rx_radar_status *rsu, + bool enable_log) +{ + if (!enable_log) + return; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n ############ Radar Summary ############\n"); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - pulsedur = %d micro seconds\n", __func__, + rsu->pulse_duration); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - rssi = %d dbm\n", __func__, + rsu->rssi); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - ischirp = %d\n", __func__, + rsu->is_chirp); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - sidx = %d\n", __func__, + rsu->sidx); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - delta_peak = %d\n", __func__, + rsu->delta_peak); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - delta_diff = %d\n", __func__, + rsu->delta_diff); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - raw tsf = %d\n", __func__, + rsu->raw_tsf); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - tsf_offset = %d micro seconds\n", + __func__, rsu->tsf_offset); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - cooked tsf = %d\n", __func__, + (rsu->raw_tsf - rsu->tsf_offset)); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: frequency offset = %d.%d MHz (oversampling = %d)\n", + __func__, (int) (rsu->freq_offset / 1000), + (int) abs(rsu->freq_offset % 1000), + PERE_IS_OVERSAMPLING(dfs)); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n ###################################\n"); +} + +/* + * Parse the radar summary frame. + * + * The frame contents _minus_ the TLV are passed in. + */ +static void +radar_summary_parse(struct ath_dfs *dfs, const char *buf, size_t len, + struct rx_radar_status *rsu) +{ + uint32_t rs[2]; + int freq_centre, freq; + + /* Drop out if we have < 2 DWORDs available */ + if (len < sizeof(rs)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | + ATH_DEBUG_DFS_PHYERR_SUM, + "%s: len (%zu) < expected (%zu)!", + __func__, len, sizeof(rs)); + } + + /* + * Since the TLVs may be unaligned for some reason + * we take a private copy into aligned memory. + * This enables us to use the HAL-like accessor macros + * into the DWORDs to access sub-DWORD fields. + */ + OS_MEMCPY(rs, buf, sizeof(rs)); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: two 32 bit values are: %08x %08x", __func__, rs[0], + rs[1]); +/* DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s (p=%p):", __func__, buf); */ + + /* Populate the fields from the summary report */ + rsu->tsf_offset = + MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_TSF_OFFSET); + rsu->pulse_duration = + MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_DUR); + rsu->is_chirp = + MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_IS_CHIRP); + rsu->sidx = + sign_extend_32(MS + (rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_SIDX), 10); + rsu->freq_offset = + calc_freq_offset(rsu->sidx, PERE_IS_OVERSAMPLING(dfs)); + + /* These are only relevant if the pulse is a chirp */ + rsu->delta_peak = + sign_extend_32(MS + (rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_DELTA_PEAK), 6); + rsu->delta_diff = + MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_DELTA_DIFF); + + /* WAR for FCC Type 4 */ + /* + * HW is giving longer pulse duration (in case of VHT80, with traffic) + * which fails to detect FCC type4 radar pulses. Added a work around to + * fix the pulse duration and duration delta. + * + * IF VHT80 + * && (primary_channel==30MHz || primary_channel== -30MHz) + * && -4 <= pulse_index <= 4 + * && !chirp + * && pulse duration > 20 us + * THEN + * Set pulse duration to 20 us + */ + + freq = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); + freq_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + + if ((IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan) && + (abs(freq - freq_centre) == 30) && + !rsu->is_chirp && + abs(rsu->sidx) <= 4 && rsu->pulse_duration > 20)) { + rsu->pulse_duration = 20; + } + +} + +static void +radar_fft_search_report_parse(struct ath_dfs *dfs, const char *buf, size_t len, + struct rx_search_fft_report *rsfr) +{ + uint32_t rs[2]; + + /* Drop out if we have < 2 DWORDs available */ + if (len < sizeof(rs)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | + ATH_DEBUG_DFS_PHYERR_SUM, + "%s: len (%zu) < expected (%zu)!", + __func__, len, sizeof(rs)); + } + + /* + * Since the TLVs may be unaligned for some reason + * we take a private copy into aligned memory. + * This enables us to use the HAL-like accessor macros + * into the DWORDs to access sub-DWORD fields. + */ + OS_MEMCPY(rs, buf, sizeof(rs)); + rsfr->total_gain_db = + MS(rs[SEARCH_FFT_REPORT_REG_1], + SEARCH_FFT_REPORT_TOTAL_GAIN_DB); + rsfr->base_pwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_BASE_PWR_DB); + rsfr->fft_chn_idx = + MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_FFT_CHN_IDX); + rsfr->peak_sidx = + sign_extend_32(MS + (rs[SEARCH_FFT_REPORT_REG_1], + SEARCH_FFT_REPORT_PEAK_SIDX), 12); + rsfr->relpwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_RELPWR_DB); + rsfr->avgpwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_AVGPWR_DB); + rsfr->peak_mag = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_PEAK_MAG); + rsfr->num_str_bins_ib = + MS(rs[SEARCH_FFT_REPORT_REG_2], + SEARCH_FFT_REPORT_NUM_STR_BINS_IB); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: two 32 bit values are: %08x %08x", __func__, rs[0], + rs[1]); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->total_gain_db = %d", + __func__, rsfr->total_gain_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->base_pwr_db = %d", + __func__, rsfr->base_pwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->fft_chn_idx = %d", + __func__, rsfr->fft_chn_idx); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->peak_sidx = %d", + __func__, rsfr->peak_sidx); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->relpwr_db = %d", + __func__, rsfr->relpwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->avgpwr_db = %d", + __func__, rsfr->avgpwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->peak_mag = %d", + __func__, rsfr->peak_mag); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->num_str_bins_ib = %d", + __func__, rsfr->num_str_bins_ib); +} + +/* + * Parse a Peregrine BB TLV frame. + * + * This routine parses each TLV, prints out what's going on and + * calls an appropriate sub-function. + * + * Since the TLV format doesn't _specify_ all TLV components are + * DWORD aligned, we must treat them as not and access the fields + * appropriately. + */ +static int +tlv_parse_frame(struct ath_dfs *dfs, struct rx_radar_status *rs, + struct rx_search_fft_report *rsfr, const char *buf, size_t len, + uint8_t rssi) +{ + int i = 0; + uint32_t tlv_hdr[1]; + bool first_tlv = true; + bool false_detect = false; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: total length = %zu bytes", __func__, len); + while ((i < len) && (false_detect == false)) { + /* Ensure we at least have four bytes */ + if ((len - i) < sizeof(tlv_hdr)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | + ATH_DEBUG_DFS_PHYERR_SUM, + "%s: ran out of bytes, len=%zu, i=%d", + __func__, len, i); + return 0; + } + + /* + * Copy the offset into the header, + * so the DWORD style access macros + * can be used. + */ + OS_MEMCPY(&tlv_hdr, buf + i, sizeof(tlv_hdr)); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: HDR: TLV SIG=0x%x, TAG=0x%x, LEN=%d bytes", + __func__, + MS(tlv_hdr[TLV_REG], TLV_SIG), + MS(tlv_hdr[TLV_REG], TLV_TAG), + MS(tlv_hdr[TLV_REG], TLV_LEN)); + + /* + * Sanity check the length field is available in + * the remaining frame. Drop out if this isn't + * the case - we can't trust the rest of the TLV + * entries. + */ + if (MS(tlv_hdr[TLV_REG], TLV_LEN) + i >= len) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: TLV oversize: LEN=%d, avail=%zu, i=%d", + __func__, + MS(tlv_hdr[TLV_REG], TLV_LEN), len, i); + break; + } + + /* Skip the TLV header - one DWORD */ + i += sizeof(tlv_hdr); + + /* Handle the payload */ + /* XXX TODO! */ + switch (MS(tlv_hdr[TLV_REG], TLV_SIG)) { + case TAG_ID_RADAR_PULSE_SUMMARY: /* Radar pulse summary */ + /* XXX TODO verify return value */ + /* XXX TODO validate only seeing one of these */ + radar_summary_parse(dfs, buf + i, + MS(tlv_hdr[TLV_REG], TLV_LEN), rs); + break; + case TAG_ID_SEARCH_FFT_REPORT: + radar_fft_search_report_parse(dfs, buf + i, + MS(tlv_hdr[TLV_REG], + TLV_LEN), rsfr); + /* + * we examine search FFT report and make the following + * assumption as per algorithms group's input: + * (1) There may be multiple TLV + * (2) We make false detection decison solely based on + * the first TLV + * (3) If the first TLV is a serch FFT report then we + * check the peak_mag value. When RSSI is equal to + * dfs->ath_dfs_false_rssI_thres (default 50) and + * peak_mag is less than 2 * dfs->ath_dfs_peak_mag + * (default 40) we treat it as false detect. + * Please note that 50 is not a true RSSI estimate, + * but value indicated by HW for RF saturation event. + */ + + if ((first_tlv == true) && + (rssi == dfs->ath_dfs_false_rssi_thres) && + (rsfr->peak_mag < (2 * dfs->ath_dfs_peak_mag))) { + false_detect = true; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: setting false_detect to true", + __func__); + } + + break; + default: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: unknown entry, SIG=0x%02x", + __func__, MS(tlv_hdr[TLV_REG], TLV_SIG)); + } + + /* Skip the payload */ + i += MS(tlv_hdr[TLV_REG], TLV_LEN); + first_tlv = false; + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: done", __func__); + + return false_detect ? 0 : 1; +} + +/* + * Calculate the channel centre in MHz. + */ +static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs) +{ + uint32_t chan_centre; + uint32_t chan_width; + int chan_offset; + + /* + * For now, just handle up to VHT80 correctly. + */ + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) { + DFS_PRINTK("%s: dfs->ic=%p, that or curchan is null?", + __func__, dfs->ic); + return 0; + /* + * For now, the only 11ac channel with freq1/freq2 setup is + * VHT80. + * + * XXX should have a flag macro to check this! + */ + } else if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) { + /* 11AC, so cfreq1/cfreq2 are setup */ + + /* + * XXX if it's 80+80 this won't work - need to use seg + * appropriately! + */ + + chan_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + } else { + /* HT20/HT40 */ + + /* + * XXX this is hard-coded - it should be 5 or 10 for + * half/quarter appropriately. + */ + chan_width = 20; + + /* Grab default channel centre */ + chan_centre = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); + + /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D */ + if (IEEE80211_IS_CHAN_11N_HT40PLUS(dfs->ic->ic_curchan) || + dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40PLUS) + chan_offset = chan_width; + else if (IEEE80211_IS_CHAN_11N_HT40MINUS(dfs->ic->ic_curchan) || + dfs->ic->ic_curchan-> + ic_flags & IEEE80211_CHAN_VHT40MINUS) + chan_offset = -chan_width; + else + chan_offset = 0; + + /* Calculate new _real_ channel centre */ + chan_centre += (chan_offset / 2); + } + + /* + * XXX half/quarter rate support! + */ + + /* Return ev_chan_centre in MHz */ + return chan_centre; +} + +/* + * Calculate the centre frequency and low/high range for a radar pulse event. + * + * XXX TODO: Handle half/quarter rates correctly! + * XXX TODO: handle VHT160 correctly! + * XXX TODO: handle VHT80+80 correctly! + */ +static int +tlv_calc_event_freq_pulse(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + int chan_width; + int chan_centre; + + /* Fetch the channel centre frequency in MHz */ + chan_centre = tlv_calc_freq_info(dfs, rs); + + /* Convert to KHz */ + chan_centre *= 1000; + + /* + * XXX hard-code event width to be 2 * bin size for now; + * XXX this needs to take into account the core clock speed + * XXX for half/quarter rate mode. + */ + if (PERE_IS_OVERSAMPLING(dfs)) + chan_width = (44000 * 2 / 128); + else + chan_width = (40000 * 2 / 128); + + /* XXX adjust chan_width for half/quarter rate! */ + + /* + * Now we can do the math to figure out the correct channel range. + */ + (*freq_centre) = (uint32_t) (chan_centre + rs->freq_offset); + (*freq_lo) = (uint32_t) ((chan_centre + rs->freq_offset) + - chan_width); + (*freq_hi) = (uint32_t) ((chan_centre + rs->freq_offset) + + chan_width); + + return 1; +} + +/* + * The chirp bandwidth in KHz is defined as: + * + * totalBW(KHz) = delta_peak(mean) + * * [ (bin resolution in KHz) / (radar_fft_long_period in uS) ] + * * pulse_duration (us) + * + * The bin resolution depends upon oversampling. + * + * For now, we treat the radar_fft_long_period as a hard-coded 8uS. + */ +static int +tlv_calc_event_freq_chirp(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + int32_t bin_resolution; /* KHz * 100 */ + int32_t radar_fft_long_period = 8; /* microseconds */ + int32_t delta_peak; + int32_t pulse_duration; + int32_t total_bw; + int32_t chan_centre; + int32_t freq_1, freq_2; + + /* + * KHz isn't enough resolution here! + * So treat it as deci-hertz (10Hz) and convert back to KHz + * later. + */ + if (PERE_IS_OVERSAMPLING(dfs)) + bin_resolution = (44000 * 100) / 128; + else + bin_resolution = (40000 * 100) / 128; + + delta_peak = rs->delta_peak; + pulse_duration = rs->pulse_duration; + + total_bw = delta_peak * (bin_resolution / radar_fft_long_period) * + pulse_duration; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: delta_peak=%d, pulse_duration=%d, bin_resolution=%d.%dKHz, " + "radar_fft_long_period=%d, total_bw=%d.%ldKHz", + __func__, + delta_peak, + pulse_duration, + bin_resolution / 1000, + bin_resolution % 1000, + radar_fft_long_period, total_bw / 100, abs(total_bw % 100)); + + total_bw /= 100; /* back to KHz */ + + /* Grab the channel centre frequency in MHz */ + chan_centre = tlv_calc_freq_info(dfs, rs); + + /* Early abort! */ + if (chan_centre == 0) { + (*freq_centre) = 0; + return 0; + } + + /* Convert to KHz */ + chan_centre *= 1000; + + /* + * sidx is the starting frequency; total_bw is a signed value and + * for negative chirps (ie, moving down in frequency rather than up) + * the end frequency may be less than the start frequency. + */ + if (total_bw > 0) { + freq_1 = chan_centre + rs->freq_offset; + freq_2 = chan_centre + rs->freq_offset + total_bw; + } else { + freq_1 = chan_centre + rs->freq_offset + total_bw; + freq_2 = chan_centre + rs->freq_offset; + } + + (*freq_lo) = (uint32_t) (freq_1); + (*freq_hi) = (uint32_t) (freq_2); + (*freq_centre) = (uint32_t) (freq_1 + (abs(total_bw) / 2)); + + return 1; +} + +/* + * Calculate the centre and band edge frequencies of the given radar + * event. + */ +static int +tlv_calc_event_freq(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + if (rs->is_chirp) + return tlv_calc_event_freq_chirp(dfs, rs, freq_centre, + freq_lo, freq_hi); + else + return tlv_calc_event_freq_pulse(dfs, rs, freq_centre, + freq_lo, freq_hi); +} + +/* + * This is the public facing function which parses the PHY error + * and populates the dfs_phy_err struct. + */ +int +dfs_process_phyerr_bb_tlv(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e, + bool enable_log) +{ + struct rx_radar_status rs; + struct rx_search_fft_report rsfr; + static int invalid_phyerr_count; + + OS_MEMZERO(&rs, sizeof(rs)); + + /* + * Add the ppdu_start/ppdu_end fields given to us by the upper + * layers. The firmware gives us a summary set of parameters rather + * than the whole PPDU_START/PPDU_END descriptor contenst. + */ + rs.rssi = rssi; + rs.raw_tsf = rs_tstamp; + /* + * Try parsing the TLV set. + */ + if (!tlv_parse_frame(dfs, &rs, &rsfr, buf, datalen, rssi)) { + invalid_phyerr_count++; + /* + * Print only at every 2 power times + * to avoid flushing of the kernel + * logs, since the frequency of + * invalid phyerrors is very high + * in noisy environments. + */ + if (!(invalid_phyerr_count & 0xFF)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_DEBUG, + "%s[%d]:parse failed invalid phyerror cnt = %d", + __func__, __LINE__, invalid_phyerr_count); + } + return 0; + } + /* For debugging, print what we have parsed */ + radar_summary_print(dfs, &rs, enable_log); + + /* Populate dfs_phy_err from rs */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rs.rssi; + e->dur = rs.pulse_duration; + e->sidx = rs.sidx; + e->is_pri = 1; /* XXX always PRI for now */ + e->is_ext = 0; + e->is_dc = 0; + e->is_early = 0; + /* + * XXX TODO: add a "chirp detection enabled" capability or config + * bit somewhere, in case for some reason the hardware chirp + * detection AND FFTs are disabled. + */ + /* For now, assume this hardware always does chirp detection */ + e->do_check_chirp = 1; + e->is_hw_chirp = !!(rs.is_chirp); + e->is_sw_chirp = 0; /* We don't yet do software chirp checking */ + + e->fulltsf = fulltsf; + e->rs_tstamp = rs.raw_tsf - rs.tsf_offset; + + /* XXX error check */ + (void)tlv_calc_event_freq(dfs, &rs, &e->freq, &e->freq_lo, &e->freq_hi); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: fbin=%d, freq=%d.%d MHz, raw tsf=%u, offset=%d, " + "cooked tsf=%u, rssi=%d, dur=%d, is_chirp=%d, fulltsf=%llu, " + "freq=%d.%d MHz, freq_lo=%d.%dMHz, freq_hi=%d.%d MHz", + __func__, + rs.sidx, + (int)(rs.freq_offset / 1000), + (int)abs(rs.freq_offset % 1000), + rs.raw_tsf, + rs.tsf_offset, + e->rs_tstamp, + rs.rssi, + rs.pulse_duration, + (int)rs.is_chirp, + (unsigned long long)fulltsf, + (int)e->freq / 1000, + (int)abs(e->freq) % 1000, + (int)e->freq_lo / 1000, + (int)abs(e->freq_lo) % 1000, + (int)e->freq_hi / 1000, (int)abs(e->freq_hi) % 1000); + + return 1; +} diff --git a/core/sap/dfs/src/dfs_phyerr_tlv.h b/core/sap/dfs/src/dfs_phyerr_tlv.h new file mode 100644 index 0000000000..d65375267c --- /dev/null +++ b/core/sap/dfs/src/dfs_phyerr_tlv.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_phyerr_tlv.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef __DFS_PHYERR_PEREGRINE_H__ +#define __DFS_PHYERR_PEREGRINE_H__ + +/* + * Register manipulation macros that expect bit field defines + * to follow the convention that an _S suffix is appended for + * a shift count, while the field mask has no suffix. + */ +#define SM(_v, _f) (((_v) << _f ## _S) & _f) +#define MS(_v, _f) (((_v) & _f) >> _f ## _S) + +/* + * The TLV dword is at the beginning of each TLV section. + */ +#define TLV_REG 0x00 + +#define TLV_LEN 0x0000FFFF +#define TLV_LEN_S 0 + +#define TLV_SIG 0x00FF0000 +#define TLV_SIG_S 16 + +#define TLV_TAG 0xFF000000 +#define TLV_TAG_S 24 + +#define TAG_ID_SEARCH_FFT_REPORT 0xFB +#define TAG_ID_RADAR_PULSE_SUMMARY 0xF8 +/* + * Radar pulse summary + * + * + TYPE=0xF8 (Radar pulse summary reprot) + * + SIG=0xBB (baseband PHY generated TLV components) + */ + +#define RADAR_REPORT_PULSE_REG_1 0x00 + +#define RADAR_REPORT_PULSE_IS_CHIRP 0x80000000 +#define RADAR_REPORT_PULSE_IS_CHIRP_S 31 + +#define RADAR_REPORT_PULSE_IS_MAX_WIDTH 0x40000000 +#define RADAR_REPORT_PULSE_IS_MAX_WIDTH_S 30 + +#define RADAR_REPORT_AGC_TOTAL_GAIN 0x3FF00000 +#define RADAR_REPORT_AGC_TOTAL_GAIN_S 20 + +#define RADAR_REPORT_PULSE_DELTA_DIFF 0x000F0000 +#define RADAR_REPORT_PULSE_DELTA_DIFF_S 16 + +#define RADAR_REPORT_PULSE_DELTA_PEAK 0x0000FC00 +#define RADAR_REPORT_PULSE_DELTA_PEAK_S 10 + +#define RADAR_REPORT_PULSE_SIDX 0x000003FF +#define RADAR_REPORT_PULSE_SIDX_S 0x0 + +#define RADAR_REPORT_PULSE_REG_2 0x01 + +#define RADAR_REPORT_PULSE_SRCH_FFT_A_VALID 0x80000000 +#define RADAR_REPORT_PULSE_SRCH_FFT_A_VALID_S 31 + +#define RADAR_REPORT_PULSE_AGC_MB_GAIN 0x7F000000 +#define RADAR_REPORT_PULSE_AGC_MB_GAIN_S 24 + +#define RADAR_REPORT_PULSE_SUBCHAN_MASK 0x00FF0000 +#define RADAR_REPORT_PULSE_SUBCHAN_MASK_S 16 + +#define RADAR_REPORT_PULSE_TSF_OFFSET 0x0000FF00 +#define RADAR_REPORT_PULSE_TSF_OFFSET_S 8 + +#define RADAR_REPORT_PULSE_DUR 0x000000FF +#define RADAR_REPORT_PULSE_DUR_S 0 + +#define SEARCH_FFT_REPORT_REG_1 0x00 + +#define SEARCH_FFT_REPORT_TOTAL_GAIN_DB 0xFF800000 +#define SEARCH_FFT_REPORT_TOTAL_GAIN_DB_S 23 + +#define SEARCH_FFT_REPORT_BASE_PWR_DB 0x007FC000 +#define SEARCH_FFT_REPORT_BASE_PWR_DB_S 14 + +#define SEARCH_FFT_REPORT_FFT_CHN_IDX 0x00003000 +#define SEARCH_FFT_REPORT_FFT_CHN_IDX_S 12 + +#define SEARCH_FFT_REPORT_PEAK_SIDX 0x00000FFF +#define SEARCH_FFT_REPORT_PEAK_SIDX_S 0 + +#define SEARCH_FFT_REPORT_REG_2 0x01 + +#define SEARCH_FFT_REPORT_RELPWR_DB 0xFC000000 +#define SEARCH_FFT_REPORT_RELPWR_DB_S 26 + +#define SEARCH_FFT_REPORT_AVGPWR_DB 0x03FC0000 +#define SEARCH_FFT_REPORT_AVGPWR_DB_S 18 + +#define SEARCH_FFT_REPORT_PEAK_MAG 0x0003FF00 +#define SEARCH_FFT_REPORT_PEAK_MAG_S 8 + +#define SEARCH_FFT_REPORT_NUM_STR_BINS_IB 0x000000FF +#define SEARCH_FFT_REPORT_NUM_STR_BINS_IB_S 0 + +/* + * Although this code is now not parsing the whole frame (descriptor + * and all), the relevant fields are still useful information + * for anyone who is working on the PHY error part of DFS pattern + * matching. + * + * However, to understand _where_ these descriptors start, you + * should do some digging into the peregrine descriptor format. + * The 30 second version: each RX ring has a bitmap listing which + * descriptors are to be included, and then a set of offsets + * into the RX buffer for where each descriptor will be written. + * It's not like the 802.11n generation hardware which has + * a fixed descriptor format. + */ + +/* + * RX_PPDU_START + */ +#define RX_PPDU_START_LEN (10*4) + +#define RX_PPDU_START_REG_4 0x0004 +#define RX_PPDU_START_RSSI_COMB 0x000000FF +#define RX_PPDU_START_RSSI_COMB_S 0 + +/* + * RX_PPDU_END + */ +#define RX_PPDU_END_LEN (21*4) + +#define RX_PPDU_END_REG_16 16 +#define RX_PPDU_END_TSF_TIMESTAMP 0xFFFFFFFF +#define RX_PPDU_END_TSF_TIMESTAMP_S 0 + +#define RX_PPDU_END_REG_18 18 +#define RX_PPDU_END_PHY_ERR_CODE 0x0000FF00 +#define RX_PPDU_END_PHY_ERR_CODE_S 8 +#define RX_PPDU_END_PHY_ERR 0x00010000 +#define RX_PPDU_END_PHY_ERR_S 16 + +/* + * The RSSI values can have "special meanings". + * + * If rssi=50, it means that the peak detector triggered. + */ +#define RSSI_PEAK_DETECTOR_SAT 50 + +/* + * + * If rssi=25, it means that the ADC was saturated, but that only is + * valid when there is one ADC gain change. For short pulses this + * is true - you won't have time to do a gain change before the pulse + * goes away. But for longer pulses, ADC gain changes can occur, so + * you'll get a more accurate RSSI figure. + * + * For short pulses (and the definition of "short" still isn't clear + * at the time of writing) there isn't any real time to do a gain change + * (or two, or three..) in order to get an accurate estimation of signal + * sizing. Thus, RSSI will not be very accurate for short duration pulses. + * All you can really say for certain is that yes, there's a pulse that + * met the requirements of the pulse detector. + * + * For more information, see the 802.11ac Microarchitecture guide. + * (TODO: add a twiki reference.) + */ + +#endif /* __DFS_PHYERR_PEREGRINE_H__ */ diff --git a/core/sap/dfs/src/dfs_process_phyerr.c b/core/sap/dfs/src/dfs_process_phyerr.c new file mode 100644 index 0000000000..1cabfd4dd9 --- /dev/null +++ b/core/sap/dfs/src/dfs_process_phyerr.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 2002-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "dfs.h" +#include "dfs_phyerr.h" /* For chip-specific phyerr func declarations */ +/* TO DO DFS + #include + */ +#ifndef UNINET +/* TO DO DFS + #include + */ +#endif +#ifdef ATH_SUPPORT_DFS + +/* + * Return the frequency width for the current operating channel. + * + * This isn't the channel width - it's how wide the reported event + * may be. For HT20 this is 20MHz. For HT40 on Howl and later it'll + * still be 20MHz - the hardware returns either pri or ext channel. + */ +static inline int dfs_get_event_freqwidth(struct ath_dfs *dfs) +{ + + /* Handle edge cases during startup/transition, shouldn't happen! */ + if (dfs == NULL) + return 0; + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) + return 0; + + /* + * XXX For now, assume 20MHz wide - but this is incorrect when + * operating in half/quarter mode! + */ + return 20; +} + +/* + * Return the centre frequency for the current operating channel and + * event. + * + * This is for post-Owl 11n chips which report pri/extension channel + * events. + */ +static inline uint16_t +dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc) +{ + struct ieee80211com *ic; + int chan_offset = 0, chan_width; + + /* Handle edge cases during startup/transition, shouldn't happen! */ + if (dfs == NULL) + return 0; + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) + return 0; + + ic = dfs->ic; + + /* + * + * For wide channels, DC and ext frequencies need a bit of hand-holding + * based on whether it's an upper or lower channel. + */ + chan_width = dfs_get_event_freqwidth(dfs); + + if (IEEE80211_IS_CHAN_11N_HT40PLUS(ic->ic_curchan)) + chan_offset = chan_width; + else if (IEEE80211_IS_CHAN_11N_HT40MINUS(ic->ic_curchan)) + chan_offset = -chan_width; + else + chan_offset = 0; + + /* + * Check for DC events first - the sowl code may just set all + * the bits together.. + */ + if (is_dc) { + /* + * XXX TODO: Should DC events be considered 40MHz wide here? + */ + return ieee80211_chan2freq(ic, ic->ic_curchan) + + (chan_offset / 2); + } + + /* + * For non-wide channels, the centre frequency is just ic_freq. + * The centre frequency for pri events is still ic_freq. + */ + if (is_pri) + return ieee80211_chan2freq(ic, ic->ic_curchan); + + if (is_ext) + return ieee80211_chan2freq(ic, ic->ic_curchan) + chan_width; + + /* XXX shouldn't get here */ + return ieee80211_chan2freq(ic, ic->ic_curchan); +} + +/* + * Process an Owl-style phy error. + * + * Return 1 on success or 0 on failure. + */ +int +dfs_process_phyerr_owl(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e) +{ + const char *cbuf = (const char *)buf; + uint8_t dur; + int event_width; + + /* XXX this shouldn't be kept count here */ + dfs->ath_dfs_stats.owl_phy_errors++; + + /* + * HW cannot detect extension channel radar so it only passes us + * primary channel radar data + */ + if (datalen == 0) + dur = 0; + else + dur = ((uint8_t *) cbuf)[0]; + + /* + * This is a spurious event; toss. + */ + if (rssi == 0 && dur == 0) + dfs->ath_dfs_stats.datalen_discards++; + return 0; + + /* + * Fill out dfs_phy_err with the information we have + * at hand. + */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rssi; + e->dur = dur; + e->is_pri = 1; + e->is_ext = 0; + e->is_dc = 0; + e->is_early = 1; + e->fulltsf = fulltsf; + e->rs_tstamp = rs_tstamp; + + /* + * Owl only ever reports events on the primary channel; + * it doesn't even see events on the secondary channel. + */ + event_width = dfs_get_event_freqwidth(dfs); + e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000; + e->freq_lo = e->freq - (event_width / 2) * 1000; + e->freq_hi = e->freq + (event_width / 2) * 1000; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: rssi=%u dur=%u,freq=%dMHz, freq_lo=%dMHz, freq_hi=%dMHz\n", + __func__, rssi, dur, e->freq / 1000, e->freq_lo / 1000, + e->freq_hi / 1000); + + return 1; +} + +/* + * Process a Sowl/Howl style phy error. + */ +int +dfs_process_phyerr_sowl(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e) +{ +#define EXT_CH_RADAR_FOUND 0x02 +#define PRI_CH_RADAR_FOUND 0x01 +#define EXT_CH_RADAR_EARLY_FOUND 0x04 + const char *cbuf = (const char *)buf; + uint8_t dur = 0; + uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri; + int pri_found = 0, ext_found = 0; + int early_ext = 0; + int event_width; + + /* + * If radar can be detected on the extension channel, datalen zero + * pulses are bogus, discard them. + */ + if (!datalen) { + dfs->ath_dfs_stats.datalen_discards++; + return 0; + } + + /* Ensure that we have at least three bytes of payload */ + if (datalen < 3) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: short error frame (%d bytes)\n", + __func__, datalen); + dfs->ath_dfs_stats.datalen_discards++; + return 0; + } + + /* + * Fetch the payload directly - the compiler will happily generate + * byte-read instructions with a const char * cbuf pointer. + */ + pulse_length_pri = cbuf[datalen - 3]; + pulse_length_ext = cbuf[datalen - 2]; + pulse_bw_info = cbuf[datalen - 1]; + + /* + * Only the last 3 bits of the BW info are relevant, they indicate + * which channel the radar was detected in. + */ + pulse_bw_info &= 0x07; + + /* + * If pulse on DC, both primary and extension flags will be set + */ + if (((pulse_bw_info & EXT_CH_RADAR_FOUND) && + (pulse_bw_info & PRI_CH_RADAR_FOUND))) { + /* + * Conducted testing, when pulse is on DC, both + * pri and ext durations are reported to be same. + * + * Radiated testing, when pulse is on DC, different + * pri and ext durations are reported, so take the + * larger of the two + */ + if (pulse_length_ext >= pulse_length_pri) { + dur = pulse_length_ext; + ext_found = 1; + } else { + dur = pulse_length_pri; + pri_found = 1; + } + dfs->ath_dfs_stats.dc_phy_errors++; + } else { + if (pulse_bw_info & EXT_CH_RADAR_FOUND) { + dur = pulse_length_ext; + pri_found = 0; + ext_found = 1; + dfs->ath_dfs_stats.ext_phy_errors++; + } + if (pulse_bw_info & PRI_CH_RADAR_FOUND) { + dur = pulse_length_pri; + pri_found = 1; + ext_found = 0; + dfs->ath_dfs_stats.pri_phy_errors++; + } + if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) { + dur = pulse_length_ext; + pri_found = 0; + ext_found = 1; + early_ext = 1; + dfs->ath_dfs_stats.early_ext_phy_errors++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "EARLY ext channel dur=%u rssi=%u datalen=%d\n", + dur, rssi, datalen); + } + if (!pulse_bw_info) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "dur=%u rssi=%u bw_info=0x%x datalen = %d\n", + dur, rssi, pulse_bw_info, (datalen & 0x3)); + /* + * Bogus bandwidth info received in descriptor, + * so ignore this PHY error + */ + dfs->ath_dfs_stats.bwinfo_errors++; + return 0; + } + } + + /* + * Always use combined RSSI reported, unless RSSI reported on + * extension is stronger + */ + if ((ext_rssi > rssi) && (ext_rssi < 128)) + rssi = ext_rssi; + + /* + * Fill out the rssi/duration fields from above. + */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rssi; + e->dur = dur; + e->is_pri = pri_found; + e->is_ext = ext_found; + e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) && + (pulse_bw_info & PRI_CH_RADAR_FOUND))); + e->is_early = early_ext; + e->fulltsf = fulltsf; + e->rs_tstamp = rs_tstamp; + + /* + * Sowl and later can report pri/ext events. + */ + event_width = dfs_get_event_freqwidth(dfs); + e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext, e->is_dc) + * 1000; + e->freq_lo = e->freq - (event_width / 2) * 1000; + e->freq_hi = e->freq + (event_width / 2) * 1000; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: pulse_bw_info=0x%x pulse_length_ext=%u pulse_length_pri=%u " + "rssi=%u ext_rssi=%u, freq=%d MHz, freq_lo=%d MHz, " + "freq_hi=%d MHz\n", + __func__, + pulse_bw_info, + pulse_length_ext, + pulse_length_pri, + rssi, + ext_rssi, + e->freq / 1000, e->freq_lo / 1000, e->freq_hi / 1000); + + return 1; +} + +/* + * Process a Merlin/Osprey style phy error. + */ +int +dfs_process_phyerr_merlin(struct ath_dfs *dfs, void *buf, + uint16_t datalen, uint8_t rssi, uint8_t ext_rssi, + uint32_t rs_tstamp, uint64_t fulltsf, + struct dfs_phy_err *e) +{ + const char *cbuf = (const char *)buf; + uint8_t pulse_bw_info = 0; + + /* + * Process using the sowl code + */ + if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi, + rs_tstamp, fulltsf, e)) { + return 0; + } + + /* + * For osprey (and Merlin) bw_info has implication for selecting + * RSSI value. So re-fetch the bw_info field so the RSSI values + * can be appropriately overridden. + */ + pulse_bw_info = cbuf[datalen - 1]; + + switch (pulse_bw_info & 0x03) { + case 0x00: + /* No radar in ctrl or ext channel */ + rssi = 0; + break; + case 0x01: + /* radar in ctrl channel */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi); + if (ext_rssi >= (rssi + 3)) { + /* + * cannot use ctrl channel RSSI if + * extension channel is stronger + */ + rssi = 0; + } + break; + case 0x02: + /* radar in extension channel */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi); + if (rssi >= (ext_rssi + 12)) { + /* + * cannot use extension channel RSSI if control channel + * is stronger + */ + rssi = 0; + } else { + rssi = ext_rssi; + } + break; + case 0x03: + /* when both are present use stronger one */ + if (rssi < ext_rssi) + rssi = ext_rssi; + break; + } + + /* + * Override the rssi decision made by the sowl code. + * The rest of the fields (duration, timestamp, etc) + * are left untouched. + */ + e->rssi = rssi; + + return 1; +} + +static void dump_phyerr_contents(const char *d, int len) +{ +#ifdef CONFIG_ENABLE_DUMP_PHYERR_CONTENTS + int i, n, bufsize = 64; + + /* + * This is statically sized for a 4-digit address + 16 * 2 digit + * data string. + * + * It's done so the printk() passed to the kernel is an entire + * line, so the kernel logging code will atomically print it. + * Otherwise we'll end up with interleaved lines with output + * from other kernel threads. + */ + char buf[64]; + + /* Initial conditions */ + buf[0] = '\n'; + n = 0; + + for (i = 0; i < len; i++) { + if (i % 16 == 0) + n += snprintf(buf + n, bufsize - n, "%04x: ", i); + n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff); + if (i % 16 == 15) { + n = 0; + buf[0] = '\0'; + } + } + + /* + * Print the final line if we didn't print it above. + */ + if (n != 0) + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, "%s: %s\n", + __func__, buf); +#endif /* def CONFIG_ENABLE_DUMP_PHYERR_CONTENTS */ +} + +void +dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen, + uint8_t r_rssi, uint8_t r_ext_rssi, uint32_t r_rs_tstamp, + uint64_t r_fulltsf, bool enable_log) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct ieee80211_channel *chan = ic->ic_curchan; + struct dfs_event *event; + struct dfs_phy_err e; + int empty; + + if (dfs == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: sc_dfs is NULL\n", __func__); + return; + } + + dfs->dfs_phyerr_count++; + dump_phyerr_contents(buf, datalen); + /* + * XXX The combined_rssi_ok support has been removed. + * This was only clear for Owl. + * + * XXX TODO: re-add this; it requires passing in the ctl/ext + * RSSI set from the RX status descriptor. + * + * XXX TODO TODO: this may be done for us from the legacy + * phy error path in ath_dev; please review that code. + */ + + /* + * At this time we have a radar pulse that we need to examine and + * queue. But if dfs_process_radarevent already detected radar and set + * CHANNEL_INTERFERENCE flag then do not queue any more radar data. + * When we are in a new channel this flag will be clear and we will + * start queueing data for new channel. (EV74162) + */ + if (dfs->dfs_debug_mask & ATH_DEBUG_DFS_PHYERR_PKT) + dump_phyerr_contents(buf, datalen); + + if (chan == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: chan is NULL\n", __func__); + return; + } + + if (IEEE80211_IS_CHAN_RADAR(chan)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: Radar already found in the channel, " + " do not queue radar data\n", __func__); + return; + } + + dfs->ath_dfs_stats.total_phy_errors++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s[%d] phyerr %d len %d\n", + __func__, __LINE__, + dfs->ath_dfs_stats.total_phy_errors, datalen); + + /* + * hardware stores this as 8 bit signed value. + * we will cap it at 0 if it is a negative number + */ + if (r_rssi & 0x80) + r_rssi = 0; + + if (r_ext_rssi & 0x80) + r_ext_rssi = 0; + + OS_MEMSET(&e, 0, sizeof(e)); + + /* + * This is a bit evil - instead of just passing in + * the chip version, the existing code uses a set + * of HAL capability bits to determine what is + * possible. + * + * The way I'm decoding it is thus: + * + * + DFS enhancement? Merlin or later + * + DFS extension channel? Sowl or later. (Howl?) + * + otherwise, Owl (and legacy.) + */ + if (dfs->dfs_caps.ath_chip_is_bb_tlv) { + if (dfs_process_phyerr_bb_tlv(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, + r_fulltsf, &e, + enable_log) == 0) { + dfs->dfs_phyerr_reject_count++; + return; + } else { + if (dfs->dfs_phyerr_freq_min > e.freq) + dfs->dfs_phyerr_freq_min = e.freq; + + if (dfs->dfs_phyerr_freq_max < e.freq) + dfs->dfs_phyerr_freq_max = e.freq; + } + } else if (dfs->dfs_caps.ath_dfs_use_enhancement) { + if (dfs_process_phyerr_merlin(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, + r_fulltsf, &e) == 0) { + return; + } + } else if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { + if (dfs_process_phyerr_sowl(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, r_fulltsf, + &e) == 0) { + return; + } + } else { + if (dfs_process_phyerr_owl(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, r_fulltsf, + &e) == 0) { + return; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n %s: Frequency at which the phyerror was injected = %d", + __func__, e.freq); + /* + * If the hardware supports radar reporting on the extension channel + * it will supply FFT data for longer radar pulses. + * + * TLV chips don't go through this software check - the hardware + * check should be enough. If we want to do software checking + * later on then someone will have to craft an FFT parser + * suitable for the TLV FFT data format. + */ + if ((!dfs->dfs_caps.ath_chip_is_bb_tlv) && + dfs->dfs_caps.ath_dfs_ext_chan_ok) { + /* + * HW has a known issue with chirping pulses injected at or + * around DC in 40MHz mode. Such pulses are reported with + * much lower durations and SW then discards them because + * they do not fit the minimum bin5 pulse duration. + * + * To work around this issue, if a pulse is within a 10us + * range of the bin5 min duration, check if the pulse is + * chirping. If the pulse is chirping, bump up the duration + * to the minimum bin5 duration. + * + * This makes sure that a valid chirping pulse will not be + * discarded because of incorrect low duration. + * + * TBD - Is it possible to calculate the 'real' duration of + * the pulse using the slope of the FFT data? + * + * TBD - Use FFT data to differentiate between radar pulses + * and false PHY errors. + * This will let us reduce the number of false alarms seen. + * + * BIN 5 chirping pulses are only for FCC or Japan MMK4 domain + */ + if (((dfs->dfsdomain == DFS_FCC_DOMAIN) || + (dfs->dfsdomain == DFS_MKK4_DOMAIN)) && + (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) { + int add_dur; + int slope = 0, dc_found = 0; + + /* + * Set the event chirping flags; as we're doing + * an actual chirp check. + */ + e.do_check_chirp = 1; + e.is_hw_chirp = 0; + e.is_sw_chirp = 0; + + /* + * dfs_check_chirping() expects is_pri and is_ext + * to be '1' for true and '0' for false for now, + * as the function itself uses these values in + * constructing things rather than testing them + * for 'true' or 'false'. + */ + add_dur = dfs_check_chirping(dfs, buf, datalen, + (e.is_pri ? 1 : 0), + (e.is_ext ? 1 : 0), + &slope, &dc_found); + if (add_dur) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "old dur %d slope =%d\n", e.dur, + slope); + e.is_sw_chirp = 1; + /* bump up to a random bin5 pulse duration */ + if (e.dur < MIN_BIN5_DUR) { + e.dur = dfs_get_random_bin5_dur(dfs, + e.fulltsf); + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "new dur %d\n", e.dur); + } else { + /* set the duration so that it is rejected */ + e.is_sw_chirp = 0; + e.dur = MAX_BIN5_DUR + 100; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "is_chirping = %d dur=%d\n", + add_dur, e.dur); + } + } else { + /* + * We have a pulse that is either bigger than + * MAX_BIN5_DUR or * less than MAYBE_BIN5_DUR + */ + if ((dfs->dfsdomain == DFS_FCC_DOMAIN) || + (dfs->dfsdomain == DFS_MKK4_DOMAIN)) { + /* + * XXX Would this result in very large pulses + * wrapping around to become short pulses? + */ + if (e.dur >= MAX_BIN5_DUR) { + /* + * set the duration so that it is + * rejected + */ + e.dur = MAX_BIN5_DUR + 50; + } + } + } + } + + /* + * Add the parsed, checked and filtered entry to the radar pulse + * event list. This is then checked by dfs_radar_processevent(). + * + * XXX TODO: some filtering is still done below this point - fix + * XXX this! + */ + ATH_DFSEVENTQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_UNLOCK(dfs); + if (empty) { + return; + } + + /* + * If the channel is a turbo G channel, then the event is + * for the adaptive radio (AR) pattern matching rather than + * radar detection. + */ + if ((chan->ic_flags & CHANNEL_108G) == CHANNEL_108G) { + if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: DFS_AR_EN not enabled\n", __func__); + return; + } + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: no more events space left\n", + __func__); + return; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + event->re_rssi = e.rssi; + event->re_dur = e.dur; + event->re_full_ts = e.fulltsf; + event->re_ts = (e.rs_tstamp) & DFS_TSMASK; + event->re_chanindex = dfs->dfs_curchan_radindex; + event->re_flags = 0; + event->sidx = e.sidx; + + /* + * Handle chirp flags. + */ + if (e.do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (e.is_hw_chirp) + event->re_flags |= DFS_EVENT_HW_CHIRP; + if (e.is_sw_chirp) + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + + ATH_ARQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list); + ATH_ARQ_UNLOCK(dfs); + } else { + if (IEEE80211_IS_CHAN_DFS(chan)) { + if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: DFS_RADAR_EN not enabled\n", + __func__); + return; + } + /* + * rssi is not accurate for short pulses, so do + * not filter based on that for short duration pulses + * + * XXX do this filtering above? + */ + if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { + if ((e.rssi < dfs->dfs_rinfo.rn_minrssithresh && + (e.dur > 4)) || + e.dur > (dfs->dfs_rinfo.rn_maxpulsedur)) { + dfs->ath_dfs_stats.rssi_discards++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Extension channel pulse is " + "discarded: dur=%d, " + "maxpulsedur=%d, rssi=%d, " + "minrssi=%d\n", + e.dur, + dfs->dfs_rinfo. + rn_maxpulsedur, e.rssi, + dfs->dfs_rinfo. + rn_minrssithresh); + return; + } + } else { + if (e.rssi < dfs->dfs_rinfo.rn_minrssithresh || + e.dur > dfs->dfs_rinfo.rn_maxpulsedur) { + /* XXX TODO add a debug statement? */ + dfs->ath_dfs_stats.rssi_discards++; + return; + } + } + + /* + * Add the event to the list, if there's space. + */ + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: no more events space left\n", + __func__); + return; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + + dfs->dfs_phyerr_queued_count++; + dfs->dfs_phyerr_w53_counter++; + + event->re_dur = e.dur; + event->re_full_ts = e.fulltsf; + event->re_ts = (e.rs_tstamp) & DFS_TSMASK; + event->re_rssi = e.rssi; + event->sidx = e.sidx; + + /* + * Handle chirp flags. + */ + if (e.do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (e.is_hw_chirp) + event->re_flags |= DFS_EVENT_HW_CHIRP; + if (e.is_sw_chirp) + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + + /* + * Correctly set which channel is being reported on + */ + if (e.is_pri) { + event->re_chanindex = dfs->dfs_curchan_radindex; + } else { + if (dfs->dfs_extchan_radindex == -1) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s - phyerr on ext channel\n", + __func__); + } + event->re_chanindex = dfs->dfs_extchan_radindex; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s New extension channel event is added " + "to queue\n", __func__); + } + ATH_DFSQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); + ATH_DFSQ_UNLOCK(dfs); + } + } + + /* + * Schedule the radar/AR task as appropriate. + * + * XXX isn't a lock needed for ath_radar_tasksched? + */ + +/* + * Commenting out the dfs_process_ar_event() since the function is never + * called at run time as dfs_arq will be empty and the function + * dfs_process_ar_event is obsolete and function definition is removed + * as part of dfs_ar.c file + * + * if (!STAILQ_EMPTY(&dfs->dfs_arq)) + * // XXX shouldn't this be a task/timer too? + * dfs_process_ar_event(dfs, ic->ic_curchan); + */ + + if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->ath_radar_tasksched) { + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + } +#undef EXT_CH_RADAR_FOUND +#undef PRI_CH_RADAR_FOUND +#undef EXT_CH_RADAR_EARLY_FOUND +} +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_process_radarevent.c b/core/sap/dfs/src/dfs_process_radarevent.c new file mode 100644 index 0000000000..7893648999 --- /dev/null +++ b/core/sap/dfs/src/dfs_process_radarevent.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 2002-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_radarevent.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +#define FREQ_5500_MHZ 5500 +#define FREQ_5500_MHZ 5500 + +#define DFS_MAX_FREQ_SPREAD 1375 * 1 + +static char debug_dup[33]; +static int debug_dup_cnt; + +/* + * Convert the hardware provided duration to TSF ticks (usecs) + * taking the clock (fast or normal) into account. + * + * Legacy (pre-11n, Owl, Sowl, Howl) operate 5GHz using a 40MHz + * clock. Later 11n chips (Merlin, Osprey, etc) operate 5GHz using + * a 44MHz clock, so the reported pulse durations are different. + * + * Peregrine reports the pulse duration in microseconds regardless + * of the operating mode. (XXX TODO: verify this, obviously.) + */ +static inline uint8_t dfs_process_pulse_dur(struct ath_dfs *dfs, uint8_t re_dur) +{ + /* + * Short pulses are sometimes returned as having a duration of 0, + * so round those up to 1. + * + * XXX This holds true for BB TLV chips too, right? + */ + if (re_dur == 0) + return 1; + + /* + * For BB TLV chips, the hardware always returns microsecond + * pulse durations. + */ + if (dfs->dfs_caps.ath_chip_is_bb_tlv) + return re_dur; + + /* + * This is for 11n and legacy chips, which may or may not + * use the 5GHz fast clock mode. + */ + /* Convert 0.8us durations to TSF ticks (usecs) */ + return (uint8_t) dfs_round((int32_t) ((dfs->dur_multiplier) * re_dur)); +} + +/* + * Process a radar event. + * + * If a radar event is found, return 1. Otherwise, return 0. + * + * There is currently no way to specify that a radar event has occured on + * a specific channel, so the current methodology is to mark both the pri + * and ext channels as being unavailable. This should be fixed for 802.11ac + * or we'll quickly run out of valid channels to use. + */ +int dfs_process_radarevent(struct ath_dfs *dfs, struct ieee80211_channel *chan) +{ +/* commenting for now to validate radar indication msg to SAP */ +/* #if 0 */ + struct dfs_event re, *event; + struct dfs_state *rs = NULL; + struct dfs_filtertype *ft; + struct dfs_filter *rf; + int found, retval = 0, p, empty; + int events_processed = 0; + uint32_t tabledepth, index; + uint64_t deltafull_ts = 0, this_ts, deltaT; + struct ieee80211_channel *thischan; + struct dfs_pulseline *pl; + static uint32_t test_ts = 0; + static uint32_t diff_ts = 0; + int ext_chan_event_flag = 0; +#if 0 + int pri_multiplier = 2; +#endif + int i; + + if (dfs == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: dfs is NULL", __func__, __LINE__); + return 0; + } + pl = dfs->pulses; + if (!(IEEE80211_IS_CHAN_DFS(dfs->ic->ic_curchan))) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: radar event on non-DFS chan", __func__); + dfs_reset_radarq(dfs); + dfs_reset_alldelaylines(dfs); + return 0; + } +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + /* TEST : Simulate radar bang, make sure we add the channel to NOL (bug 29968) */ + if (dfs->dfs_bangradar) { + /* bangradar will always simulate radar found on the primary channel */ + rs = &dfs->dfs_radar[dfs->dfs_curchan_radindex]; + dfs->dfs_bangradar = 0; /* reset */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: bangradar", __func__); + retval = 1; + goto dfsfound; + } +#endif + + /* + The HW may miss some pulses especially with high channel loading. + This is true for Japan W53 where channel loaoding is 50%. Also + for ETSI where channel loading is 30% this can be an issue too. + To take care of missing pulses, we introduce pri_margin multiplie. + This is normally 2 but can be higher for W53. + */ + + if ((dfs->dfsdomain == DFS_MKK4_DOMAIN) && + (dfs->dfs_caps.ath_chip_is_bb_tlv) && + (chan->ic_freq < FREQ_5500_MHZ)) { + + dfs->dfs_pri_multiplier = dfs->dfs_pri_multiplier_ini; + + /* do not process W53 pulses, + unless we have a minimum number of them + */ + if (dfs->dfs_phyerr_w53_counter >= 5) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: w53_counter=%d, freq_max=%d, " + "freq_min=%d, pri_multiplier=%d", + __func__, + dfs->dfs_phyerr_w53_counter, + dfs->dfs_phyerr_freq_max, + dfs->dfs_phyerr_freq_min, + dfs->dfs_pri_multiplier); + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + } else { + return 0; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: pri_multiplier=%d", __func__, dfs->dfs_pri_multiplier); + + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + + while ((!empty) && (!retval) && (events_processed < MAX_EVENTS)) { + ATH_DFSQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_radarq)); + if (event != NULL) + STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); + ATH_DFSQ_UNLOCK(dfs); + + if (event == NULL) { + empty = 1; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: event is NULL ", __func__, __LINE__); + break; + } + events_processed++; + re = *event; + + OS_MEMZERO(event, sizeof(struct dfs_event)); + ATH_DFSEVENTQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + + found = 0; + if (re.re_chanindex < DFS_NUM_RADAR_STATES) + rs = &dfs->dfs_radar[re.re_chanindex]; + else { + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + if (rs->rs_chan.ic_flagext & CHANNEL_INTERFERENCE) { + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + + if (dfs->dfs_rinfo.rn_lastfull_ts == 0) { + /* + * Either not started, or 64-bit rollover exactly to zero + * Just prepend zeros to the 15-bit ts + */ + dfs->dfs_rinfo.rn_ts_prefix = 0; + } else { + /* WAR 23031- patch duplicate ts on very short pulses */ + /* This pacth has two problems in linux environment. + * 1)The time stamp created and hence PRI depends entirely on the latency. + * If the latency is high, it possibly can split two consecutive + * pulses in the same burst so far away (the same amount of latency) + * that make them look like they are from differenct bursts. It is + * observed to happen too often. It sure makes the detection fail. + * 2)Even if the latency is not that bad, it simply shifts the duplicate + * timestamps to a new duplicate timestamp based on how they are processed. + * This is not worse but not good either. + * + * Take this pulse as a good one and create a probable PRI later + */ + if (re.re_dur == 0 + && re.re_ts == dfs->dfs_rinfo.rn_last_unique_ts) { + debug_dup[debug_dup_cnt++] = '1'; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + " %s deltaT is 0 ", __func__); + } else { + dfs->dfs_rinfo.rn_last_unique_ts = re.re_ts; + debug_dup[debug_dup_cnt++] = '0'; + } + if (debug_dup_cnt >= 32) { + debug_dup_cnt = 0; + } + + if (re.re_ts <= dfs->dfs_rinfo.rn_last_ts) { + dfs->dfs_rinfo.rn_ts_prefix += + (((uint64_t) 1) << DFS_TSSHIFT); + /* Now, see if it's been more than 1 wrap */ + deltafull_ts = + re.re_full_ts - + dfs->dfs_rinfo.rn_lastfull_ts; + if (deltafull_ts > + ((uint64_t) + ((DFS_TSMASK - dfs->dfs_rinfo.rn_last_ts) + + 1 + re.re_ts))) + deltafull_ts -= + (DFS_TSMASK - + dfs->dfs_rinfo.rn_last_ts) + 1 + + re.re_ts; + deltafull_ts = deltafull_ts >> DFS_TSSHIFT; + if (deltafull_ts > 1) { + dfs->dfs_rinfo.rn_ts_prefix += + ((deltafull_ts - 1) << DFS_TSSHIFT); + } + } else { + deltafull_ts = + re.re_full_ts - + dfs->dfs_rinfo.rn_lastfull_ts; + if (deltafull_ts > (uint64_t) DFS_TSMASK) { + deltafull_ts = + deltafull_ts >> DFS_TSSHIFT; + dfs->dfs_rinfo.rn_ts_prefix += + ((deltafull_ts - 1) << DFS_TSSHIFT); + } + } + } + /* + * At this stage rn_ts_prefix has either been blanked or + * calculated, so it's safe to use. + */ + this_ts = dfs->dfs_rinfo.rn_ts_prefix | ((uint64_t) re.re_ts); + dfs->dfs_rinfo.rn_lastfull_ts = re.re_full_ts; + dfs->dfs_rinfo.rn_last_ts = re.re_ts; + + /* + * The hardware returns the duration in a variety of formats, + * so it's converted from the hardware format to TSF (usec) + * values here. + * + * XXX TODO: this should really be done when the PHY error + * is processed, rather than way out here.. + */ + re.re_dur = dfs_process_pulse_dur(dfs, re.re_dur); + + /* + * Calculate the start of the radar pulse. + * + * The TSF is stamped by the MAC upon reception of the + * event, which is (typically?) at the end of the event. + * But the pattern matching code expects the event timestamps + * to be at the start of the event. So to fake it, we + * subtract the pulse duration from the given TSF. + * + * This is done after the 64-bit timestamp has been calculated + * so long pulses correctly under-wrap the counter. Ie, if + * this was done on the 32 (or 15!) bit TSF when the TSF + * value is closed to 0, it will underflow to 0xfffffXX, which + * would mess up the logical "OR" operation done above. + * + * This isn't valid for Peregrine as the hardware gives us + * the actual TSF offset of the radar event, not just the MAC + * TSF of the completed receive. + * + * XXX TODO: ensure that the TLV PHY error processing + * code will correctly calculate the TSF to be the start + * of the radar pulse. + * + * XXX TODO TODO: modify the TLV parsing code to subtract + * the duration from the TSF, based on the current fast clock + * value. + */ + if ((!dfs->dfs_caps.ath_chip_is_bb_tlv) && re.re_dur != 1) { + this_ts -= re.re_dur; + } + + /* Save the pulse parameters in the pulse buffer(pulse line) */ + index = (pl->pl_lastelem + 1) & DFS_MAX_PULSE_BUFFER_MASK; + if (pl->pl_numelems == DFS_MAX_PULSE_BUFFER_SIZE) + pl->pl_firstelem = + (pl->pl_firstelem + 1) & DFS_MAX_PULSE_BUFFER_MASK; + else + pl->pl_numelems++; + pl->pl_lastelem = index; + pl->pl_elems[index].p_time = this_ts; + pl->pl_elems[index].p_dur = re.re_dur; + pl->pl_elems[index].p_rssi = re.re_rssi; + diff_ts = (uint32_t) this_ts - test_ts; + test_ts = (uint32_t) this_ts; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "ts%u %u %u diff %u pl->pl_lastelem.p_time=%llu", + (uint32_t) this_ts, re.re_dur, re.re_rssi, diff_ts, + (unsigned long long)pl->pl_elems[index].p_time); + if (dfs->dfs_event_log_on) { + i = dfs->dfs_event_log_count % DFS_EVENT_LOG_SIZE; + dfs->radar_log[i].ts = this_ts; + dfs->radar_log[i].diff_ts = diff_ts; + dfs->radar_log[i].rssi = re.re_rssi; + dfs->radar_log[i].dur = re.re_dur; + dfs->dfs_event_log_count++; + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]:xxxxx ts =%u re.re_dur=%u re.re_rssi =%u diff =%u pl->pl_lastelem.p_time=%llu xxxxx", + __func__, __LINE__, (uint32_t) this_ts, re.re_dur, + re.re_rssi, diff_ts, + (unsigned long long)pl->pl_elems[index].p_time); + + /* If diff_ts is very small, we might be getting false pulse detects + * due to heavy interference. We might be getting spectral splatter + * from adjacent channel. In order to prevent false alarms we + * clear the delay-lines. This might impact positive detections under + * harsh environments, but helps with false detects. */ + + if (diff_ts < 100) { + dfs_reset_alldelaylines(dfs); + dfs_reset_radarq(dfs); + } + found = 0; + + /* + * Use this fix only when device is not in test mode, as + * it drops some valid phyerrors. + * In FCC or JAPAN domain,if the follwing signature matches + * its likely that this is a false radar pulse pattern + * so process the next pulse in the queue. + */ + if ((dfs->disable_dfs_ch_switch == false) && + (DFS_FCC_DOMAIN == dfs->dfsdomain || + DFS_MKK4_DOMAIN == dfs->dfsdomain) && + (re.re_dur >= 11 && re.re_dur <= 20) && + (diff_ts > 500 || diff_ts <= 305) && + (re.sidx == -4)) { + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n%s: Rejecting on Peak Index = %d,re.re_dur = %d,diff_ts = %d\n", + __func__,re.sidx, re.re_dur, diff_ts); + + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + + /* + * Modifying the pulse duration for FCC Type 4 + * or JAPAN W56 Type 6 radar pulses when the + * following condition is reported in radar + * summary report. + */ + if ((DFS_FCC_DOMAIN == dfs->dfsdomain || + DFS_MKK4_DOMAIN == dfs->dfsdomain) && + ((chan->ic_flags & IEEE80211_CHAN_VHT80) == + IEEE80211_CHAN_VHT80) && + (chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_PLUS_30_MHZ_SEPARATION || + chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_MINUS_30_MHZ_SEPARATION) && + (re.sidx == DFS_WAR_PEAK_INDEX_ZERO) && + (re.re_dur > DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT && + re.re_dur < DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT) && + (diff_ts > DFS_TYPE4_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_TYPE4_WAR_PRI_UPPER_LIMIT)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s:chan->ic_flags=0x%x, MHz separation=%d\n", + __func__, chan->ic_flags, + chan->ic_pri_freq_center_freq_mhz_separation); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: Peak Idx =%d,re.re_dur =%d,diff_ts =%d\n", + __func__, re.sidx, re.re_dur, diff_ts); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n%s: Modify pulse dur to fit valid range \n", + __func__); + + re.re_dur = DFS_TYPE4_WAR_VALID_PULSE_DURATION; + } + + /* + * Modifying the pulse duration for ETSI Type 2 + * and ETSI type 3 radar pulses when the following + * condition is reported in radar summary report. + */ + if ((DFS_ETSI_DOMAIN == dfs->dfsdomain) && + ((chan->ic_flags & IEEE80211_CHAN_VHT80) == + IEEE80211_CHAN_VHT80) && + (chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_PLUS_30_MHZ_SEPARATION || + chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_MINUS_30_MHZ_SEPARATION) && + (re.sidx == DFS_WAR_PEAK_INDEX_ZERO) && + (re.re_dur > + DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_LOWER_LIMIT && + re.re_dur < + DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_UPPER_LIMIT) && + ((diff_ts > DFS_ETSI_TYPE2_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_ETSI_TYPE2_WAR_PRI_UPPER_LIMIT) || + (diff_ts > DFS_ETSI_TYPE3_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_ETSI_TYPE3_WAR_PRI_UPPER_LIMIT))) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "\n%s:chan->ic_flags=0x%x,MHz Separation=%d\n", + __func__, chan->ic_flags, + chan->ic_pri_freq_center_freq_mhz_separation); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s:Peak Index =%d,re.re_dur =%d,diff_ts =%d\n", + __func__, re.sidx, re.re_dur, diff_ts); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s:Modify ETSI pulse dur to valid range \n", + __func__); + + re.re_dur = DFS_ETSI_WAR_VALID_PULSE_DURATION; + } + + /* BIN5 pulses are FCC and Japan specific */ + + if ((dfs->dfsdomain == DFS_FCC_DOMAIN) + || (dfs->dfsdomain == DFS_MKK4_DOMAIN)) { + for (p = 0; + (p < dfs->dfs_rinfo.rn_numbin5radars) && (!found); + p++) { + struct dfs_bin5radars *br; + + br = &(dfs->dfs_b5radars[p]); + if (dfs_bin5_check_pulse(dfs, &re, br)) { + /* This is a valid Bin5 pulse, check if it belongs to a burst */ + re.re_dur = + dfs_retain_bin5_burst_pattern(dfs, + diff_ts, + re. + re_dur); + /* Remember our computed duration for the next pulse in the burst (if needed) */ + dfs->dfs_rinfo.dfs_bin5_chirp_ts = + this_ts; + dfs->dfs_rinfo.dfs_last_bin5_dur = + re.re_dur; + + if (dfs_bin5_addpulse + (dfs, br, &re, this_ts)) { + found |= dfs_bin5_check(dfs); + } + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_PULSE, + "%s not a BIN5 pulse (dur=%d)", + __func__, re.re_dur); + } + } + } + + if (found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: Found bin5 radar", + __func__); + retval |= found; + goto dfsfound; + } + + tabledepth = 0; + rf = NULL; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + " *** chan freq (%d): ts %llu dur %u rssi %u", + rs->rs_chan.ic_freq, (unsigned long long)this_ts, + re.re_dur, re.re_rssi); + + while ((tabledepth < DFS_MAX_RADAR_OVERLAP) && + ((dfs->dfs_radartable[re.re_dur])[tabledepth] != -1) && + (!retval)) { + ft = dfs-> + dfs_radarf[((dfs-> + dfs_radartable[re. + re_dur])[tabledepth])]; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " ** RD (%d): ts %x dur %u rssi %u", + rs->rs_chan.ic_freq, re.re_ts, re.re_dur, + re.re_rssi); + + if (re.re_rssi < ft->ft_rssithresh && re.re_dur > 4) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s : Rejecting on rssi rssi=%u thresh=%u", + __func__, re.re_rssi, + ft->ft_rssithresh); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s[%d]: Rejecting on rssi rssi=%u thresh=%u", + __func__, __LINE__, re.re_rssi, + ft->ft_rssithresh); + tabledepth++; + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + deltaT = this_ts - ft->ft_last_ts; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "deltaT = %lld (ts: 0x%llx) (last ts: 0x%llx)", + (unsigned long long)deltaT, + (unsigned long long)this_ts, + (unsigned long long)ft->ft_last_ts); + if ((deltaT < ft->ft_minpri) && (deltaT != 0)) { + /* This check is for the whole filter type. Individual filters + will check this again. This is first line of filtering. */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: Rejecting on pri pri=%lld minpri=%u", + __func__, + (unsigned long long)deltaT, + ft->ft_minpri); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s[%d]:Rejecting on pri pri=%lld minpri=%u", + __func__, __LINE__, + (unsigned long long)deltaT, + ft->ft_minpri); + tabledepth++; + continue; + } + for (p = 0, found = 0; + (p < ft->ft_numfilters) && (!found); p++) { + rf = &(ft->ft_filters[p]); + if ((re.re_dur >= rf->rf_mindur) + && (re.re_dur <= rf->rf_maxdur)) { + /* The above check is probably not necessary */ + deltaT = + (this_ts < + rf->rf_dl. + dl_last_ts) + ? (int64_t) ((DFS_TSF_WRAP - + rf->rf_dl. + dl_last_ts) + + this_ts + + 1) : this_ts - + rf->rf_dl.dl_last_ts; + + if ((deltaT < rf->rf_minpri) + && (deltaT != 0)) { + /* Second line of PRI filtering. */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter min PRI deltaT=%lld rf->rf_minpri=%u", + rf->rf_pulseid, + (unsigned long long) + deltaT, + rf->rf_minpri); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d::Rejecting on individual filter min PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long long) + deltaT, + rf->rf_minpri); + continue; + } + + if (rf->rf_ignore_pri_window > 0) { + if (deltaT < rf->rf_minpri) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + rf-> + rf_pulseid, + (unsigned + long long) + deltaT, + rf-> + rf_minpri); + CDF_TRACE + (CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d :: Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long + long)deltaT, + rf->rf_minpri); + /* But update the last time stamp */ + rf->rf_dl.dl_last_ts = + this_ts; + continue; + } + } else { + + /* + The HW may miss some pulses especially with high channel loading. + This is true for Japan W53 where channel loaoding is 50%. Also + for ETSI where channel loading is 30% this can be an issue too. + To take care of missing pulses, we introduce pri_margin multiplie. + This is normally 2 but can be higher for W53. + */ + + if ((deltaT > + (dfs->dfs_pri_multiplier * + rf->rf_maxpri)) + || (deltaT < + rf->rf_minpri)) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + rf-> + rf_pulseid, + (unsigned + long long) + deltaT, + rf-> + rf_minpri); + CDF_TRACE + (CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d :: Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long + long)deltaT, + rf->rf_minpri); + /* But update the last time stamp */ + rf->rf_dl.dl_last_ts = + this_ts; + continue; + } + } + dfs_add_pulse(dfs, rf, &re, deltaT, + this_ts); + + /* If this is an extension channel event, flag it for false alarm reduction */ + if (re.re_chanindex == + dfs->dfs_extchan_radindex) { + ext_chan_event_flag = 1; + } + if (rf->rf_patterntype == 2) { + found = + dfs_staggered_check(dfs, rf, + (uint32_t) + deltaT, + re. + re_dur); + } else { + found = + dfs_bin_check(dfs, rf, + (uint32_t) + deltaT, + re.re_dur, + ext_chan_event_flag); + } + if (dfs-> + dfs_debug_mask & ATH_DEBUG_DFS2) { + dfs_print_delayline(dfs, + &rf->rf_dl); + } + rf->rf_dl.dl_last_ts = this_ts; + } + } + ft->ft_last_ts = this_ts; + retval |= found; + if (found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "Found on channel minDur = %d, filterId = %d", + ft->ft_mindur, + rf != NULL ? rf->rf_pulseid : -1); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s[%d]:### Found on channel minDur = %d,filterId = %d ###", + __func__,__LINE__,ft->ft_mindur, + rf != NULL ? rf->rf_pulseid : -1); + } + tabledepth++; + } + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + } +dfsfound: + if (retval) { + /* Collect stats */ + dfs->ath_dfs_stats.num_radar_detects++; + thischan = &rs->rs_chan; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s[%d]: ### RADAR FOUND ON CHANNEL %d (%d MHz) ###", + __func__, __LINE__, thischan->ic_ieee, + thischan->ic_freq); + DFS_PRINTK("Radar found on channel %d (%d MHz)", + thischan->ic_ieee, thischan->ic_freq); + +#if 0 /* UMACDFS : TODO */ + /* Disable radar for now */ + rfilt = ath_hal_getrxfilter(ah); + rfilt &= ~HAL_RX_FILTER_PHYRADAR; + ath_hal_setrxfilter(ah, rfilt); +#endif + dfs_reset_radarq(dfs); + dfs_reset_alldelaylines(dfs); + /* XXX Should we really enable again? Maybe not... */ +/* No reason to re-enable so far - Ajay*/ +#if 0 + pe.pe_firpwr = rs->rs_firpwr; + pe.pe_rrssi = rs->rs_radarrssi; + pe.pe_height = rs->rs_height; + pe.pe_prssi = rs->rs_pulserssi; + pe.pe_inband = rs->rs_inband; + /* 5413 specific */ + pe.pe_relpwr = rs->rs_relpwr; + pe.pe_relstep = rs->rs_relstep; + pe.pe_maxlen = rs->rs_maxlen; + + ath_hal_enabledfs(ah, &pe); + rfilt |= HAL_RX_FILTER_PHYRADAR; + ath_hal_setrxfilter(ah, rfilt); +#endif + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Primary channel freq = %u flags=0x%x", + chan->ic_freq, chan->ic_flagext); + if ((dfs->ic->ic_curchan->ic_freq != thischan->ic_freq)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Ext channel freq = %u flags=0x%x", + thischan->ic_freq, thischan->ic_flagext); + } + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + dfs->dfs_phyerr_w53_counter = 0; + } + /* CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, "IN FUNC %s[%d]: retval = %d ",__func__,__LINE__,retval); */ + return retval; +/* #endif */ +/* return 1; */ +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/dfs/src/dfs_staggered.c b/core/sap/dfs/src/dfs_staggered.c new file mode 100644 index 0000000000..71c04b573b --- /dev/null +++ b/core/sap/dfs/src/dfs_staggered.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_staggered.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +static int is_pri_multiple(uint32_t sample_pri, uint32_t refpri) +{ +#define MAX_ALLOWED_MISSED 3 + int i; + + if (sample_pri < refpri || (!refpri)) + return 0; + + for (i = 1; i <= MAX_ALLOWED_MISSED; i++) { + if ((sample_pri % (i * refpri) <= 5)) { + /* printk("sample_pri=%d is a multiple of refpri=%d\n", sample_pri, refpri); */ + return 1; + } + } + return 0; +#undef MAX_ALLOWED_MISSED +} + +static int is_unique_pri(uint32_t highestpri, uint32_t midpri, + uint32_t lowestpri, uint32_t refpri) +{ +#define DFS_STAGGERED_PRI_MARGIN_MIN 20 +#define DFS_STAGGERED_PRI_MARGIN_MAX 400 + if ((DFS_DIFF(lowestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) && + (DFS_DIFF(midpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) && + (DFS_DIFF(highestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN)) { + return 1; + } else { + if ((is_pri_multiple(refpri, highestpri)) + || (is_pri_multiple(refpri, lowestpri)) + || (is_pri_multiple(refpri, midpri))) + return 0; + } + return 0; +#undef DFS_STAGGERED_PRI_MARGIN_MIN +#undef DFS_STAGGERED_PRI_MARGIN_MAX +} + +int dfs_staggered_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t width) +{ + uint32_t refpri, refdur, searchpri = 0, deltapri; /* , averagerefpri; */ + uint32_t n, i, primargin, durmargin; + int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0; + struct dfs_delayline *dl; + uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; +#if 0 + int numpulses = 0; +#endif + int higherthan, lowerthan, numscores; + int numpulseshigh = 0, numpulsesmid = 0, numpulsestemp = 0; + uint32_t lowestscore = 0, lowestscoreindex = 0, lowestpri = 0; + uint32_t midscore = 0, midscoreindex = 0, midpri = 0; + uint32_t highestscore = 0, highestscoreindex = 0, highestpri = 0; + + dl = &rf->rf_dl; + if (dl->dl_numelems < (rf->rf_threshold - 1)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numelems %d < threshold for filter %d\n", + dl->dl_numelems, rf->rf_pulseid); + return 0; + } + if (deltaT > rf->rf_filterlen) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numelems %d < threshold for filter %d\n", + dl->dl_numelems, rf->rf_pulseid); + return 0; + } + primargin = 6; + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + OS_MEMZERO(score, sizeof(int) * DFS_MAX_DL_SIZE); + /* find out the lowest pri */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + else if (refpri < lowpri) { + lowpri = dl->dl_elems[delayindex].de_time; + lowpriindex = n; + } + } + /* find out the each delay element's pri score */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) { + continue; + } + + if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { + score[n] = 0; + continue; + } + + for (i = 0; i < dl->dl_numelems; i++) { + dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + if (deltapri < primargin) + score[n]++; + } + } + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "score[%d]=%d pri=%d\n", n, + score[n], refdur); + } + + /* find out the 2 or 3 highest scorers */ + scoreindex = 0; + highestscore = 0; + highestscoreindex = 0; + highestpri = 0; + numscores = 0; + lowestscore = 0; + + for (n = 0; n < dl->dl_numelems; n++) { + higherthan = 0; + lowerthan = 0; + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + + if ((score[n] >= highestscore) && + (is_unique_pri(highestpri, midpri, lowestpri, refpri))) { + lowestscore = midscore; + lowestpri = midpri; + lowestscoreindex = midscoreindex; + midscore = highestscore; + midpri = highestpri; + midscoreindex = highestscoreindex; + highestscore = score[n]; + highestpri = refpri; + highestscoreindex = n; + } else { + if ((score[n] >= midscore) && + (is_unique_pri + (highestpri, midpri, lowestpri, refpri))) { + lowestscore = midscore; + lowestpri = midpri; + lowestscoreindex = midscoreindex; + midscore = score[n]; + midpri = refpri; + midscoreindex = n; + } else if ((score[n] >= lowestscore) && + (is_unique_pri + (highestpri, midpri, lowestpri, refpri))) { + lowestscore = score[n]; + lowestpri = refpri; + lowestscoreindex = n; + } + } + + } + + if (midscore == 0) { + /* This means we have only 1 pulse type. It can not be staggered! */ + return 0; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL highestscore=%d highestscoreindex=%d highestpri=%d\n", + highestscore, highestscoreindex, highestpri); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL lowestscore=%d lowestscoreindex=%d lowpri=%d\n", + lowestscore, lowestscoreindex, lowestpri); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL midscore=%d midscoreindex=%d midpri=%d\n", + midscore, midscoreindex, midpri); + + delayindex = (dl->dl_firstelem + highestscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "highscoreindex=%d refdur=%d refpri=%d\n", + highestscoreindex, refdur, refpri); + + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri); + numpulseshigh = numpulsestemp; + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri + midpri); + if (numpulsestemp > numpulseshigh) { + numpulseshigh = numpulsestemp; + } + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri + midpri + lowestpri); + if (numpulsestemp > numpulseshigh) { + numpulseshigh = numpulsestemp; + } + + delayindex = (dl->dl_firstelem + midscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "midscoreindex=%d refdur=%d refpri=%d\n", + midscoreindex, refdur, refpri); + + /* numpulsesmid = dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur,0, 1); */ + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, midpri); + numpulsesmid = numpulsestemp; + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, + highestpri + midpri); + if (numpulsestemp > numpulsesmid) { + numpulsesmid = numpulsestemp; + } + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, + highestpri + midpri + lowestpri); + if (numpulsestemp > numpulsesmid) { + numpulsesmid = numpulsestemp; + } + + /*delayindex = (dl->dl_firstelem + lowestscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(ic, ATH_DEBUG_DFS1, "lowestscoreindex=%d refdur=%d refpri=%d\n", lowestscoreindex, refdur, refpri); + + numpulseslow = dfs_bin_pri_check(dfs, rf, dl, lowestscore, refpri, refdur,0, 1); + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numpulseshigh=%d, numpulsesmid=%d\n", + numpulseshigh, numpulsesmid); +/* printf("numpulseshigh=%d, numpulsesmid=%d, numpulseslow %d\n",numpulseshigh, numpulsesmid, numpulseslow); */ + + if ((numpulseshigh >= rf->rf_threshold) + && (numpulsesmid >= rf->rf_threshold)) { + /*if (numpulses >= rf->rf_threshold) { */ + found = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "MATCH filter=%u numpulseshigh=%u numpulsesmid= %u thresh=%u\n", + rf->rf_pulseid, numpulseshigh, numpulsesmid, + rf->rf_threshold); + } + return found; +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h new file mode 100644 index 0000000000..dc450e22ab --- /dev/null +++ b/core/sap/inc/sap_api.h @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WLANSAP_H +#define WLAN_QCT_WLANSAP_H + +/** + * W L A N S O F T A P P A L L A Y E R + * E X T E R N A L A P I + * + * DESCRIPTION + * This file contains the external API exposed by the wlan SAP PAL layer + * module. + */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "cds_packet.h" +#include "cdf_types.h" + +#include "p2p_api.h" +#include "sme_api.h" +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * defines and enum + *--------------------------------------------------------------------------*/ +#define MAX_SSID_LEN 32 +#define MAX_ACL_MAC_ADDRESS 32 +#define AUTO_CHANNEL_SELECT 0 +#define MAX_ASSOC_IND_IE_LEN 255 + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 +#define MAX_NAME_SIZE 64 +#define MAX_TEXT_SIZE 32 + +#define MAX_CHANNEL_LIST_LEN 256 +#ifdef WLAN_FEATURE_MBSSID +#define CDF_MAX_NO_OF_SAP_MODE 2 /* max # of SAP */ +#else +#define CDF_MAX_NO_OF_SAP_MODE 1 /* max # of SAP */ +#endif +#define SAP_MAX_NUM_SESSION 5 +#define SAP_MAX_OBSS_STA_CNT 1 /* max # of OBSS STA */ +#define SAP_ACS_WEIGHT_MAX (4444) + +/*-------------------------------------------------------------------------- + * reasonCode taken from 802.11 standard. + * ------------------------------------------------------------------------*/ + +typedef enum { + eSAP_RC_RESERVED0, /*0 */ + eSAP_RC_UNSPECIFIED, /*1 */ + eSAP_RC_PREV_AUTH_INVALID, /*2 */ + eSAP_RC_STA_LEFT_DEAUTH, /*3 */ + eSAP_RC_INACTIVITY_DISASSOC, /*4 */ + eSAP_RC_AP_CAPACITY_FULL, /*5 */ + eSAP_RC_CLS2_FROM_NON_AUTH_STA, /*6 */ + eSAP_RC_CLS3_FROM_NON_AUTH_STA, /*7 */ + eSAP_RC_STA_LEFT_DISASSOC, /*8 */ + eSAP_RC_STA_NOT_AUTH, /*9 */ + eSAP_RC_PC_UNACCEPTABLE, /*10 */ + eSAP_RC_SC_UNACCEPTABLE, /*11 */ + eSAP_RC_RESERVED1, /*12 */ + eSAP_RC_INVALID_IE, /*13 */ + eSAP_RC_MIC_FAIL, /*14 */ + eSAP_RC_4_WAY_HANDSHAKE_TO, /*15 */ + eSAP_RC_GO_KEY_HANDSHAKE_TO, /*16 */ + eSAP_RC_IE_MISMATCH, /*17 */ + eSAP_RC_INVALID_GRP_CHIPHER, /*18 */ + eSAP_RC_INVALID_PAIR_CHIPHER, /*19 */ + eSAP_RC_INVALID_AKMP, /*20 */ + eSAP_RC_UNSUPPORTED_RSN, /*21 */ + eSAP_RC_INVALID_RSN, /*22 */ + eSAP_RC_1X_AUTH_FAILED, /*23 */ + eSAP_RC_CHIPER_SUITE_REJECTED, /*24 */ +} eSapReasonCode; + +typedef enum { + eSAP_ACCEPT_UNLESS_DENIED = 0, + eSAP_DENY_UNLESS_ACCEPTED = 1, + /* this type is added to support accept & deny list at the same time */ + eSAP_SUPPORT_ACCEPT_AND_DENY = 2, + /*In this mode all MAC addresses are allowed to connect */ + eSAP_ALLOW_ALL = 3, +} eSapMacAddrACL; + +typedef enum { + eSAP_BLACK_LIST = 0, /* List of mac addresses NOT allowed to assoc */ + eSAP_WHITE_LIST = 1, /* List of mac addresses allowed to assoc */ +} eSapACLType; + +typedef enum { + ADD_STA_TO_ACL = 0, /* cmd to add STA to access control list */ + DELETE_STA_FROM_ACL = 1, /* cmd to del STA from access control list */ +} eSapACLCmdType; + +typedef enum { + eSAP_START_BSS_EVENT = 0, /* Event sent when BSS is started */ + eSAP_STOP_BSS_EVENT, /* Event sent when BSS is stopped */ + eSAP_STA_ASSOC_IND, /* Indicate assoc req to upper layers */ + /* + * Event sent when we have successfully associated a station and + * upper layer neeeds to allocate a context + */ + eSAP_STA_ASSOC_EVENT, + /* + * Event sent when we have successfully reassociated a station and + * upper layer neeeds to allocate a context + */ + eSAP_STA_REASSOC_EVENT, + /* + * Event sent when associated a station has disassociated as a + * result of various conditions + */ + eSAP_STA_DISASSOC_EVENT, + /* Event sent when user called wlansap_set_key_sta */ + eSAP_STA_SET_KEY_EVENT, + /* Event sent whenever there is MIC failure detected */ + eSAP_STA_MIC_FAILURE_EVENT, + /* Event sent when user called wlansap_get_assoc_stations */ + eSAP_ASSOC_STA_CALLBACK_EVENT, + /* Event send when user call wlansap_get_wps_session_overlap */ + eSAP_GET_WPSPBC_SESSION_EVENT, + /* Event send on WPS PBC probe request is received */ + eSAP_WPS_PBC_PROBE_REQ_EVENT, + eSAP_INDICATE_MGMT_FRAME, + eSAP_REMAIN_CHAN_READY, + eSAP_SEND_ACTION_CNF, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + /* + * Event send when a STA in neither white list or black list tries to + * associate in softap mode + */ + eSAP_UNKNOWN_STA_JOIN, + /* Event send when a new STA is rejected association since softAP + * max assoc limit has reached + */ + eSAP_MAX_ASSOC_EXCEEDED, + eSAP_CHANNEL_CHANGE_EVENT, + eSAP_DFS_CAC_START, + eSAP_DFS_CAC_INTERRUPTED, + eSAP_DFS_CAC_END, + eSAP_DFS_RADAR_DETECT, + /* Event sent when user need to get the DFS NOL from CNSS */ + eSAP_DFS_NOL_GET, + /* Event sent when user need to set the DFS NOL to CNSS */ + eSAP_DFS_NOL_SET, + /* No ch available after DFS RADAR detect */ + eSAP_DFS_NO_AVAILABLE_CHANNEL, +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + eSAP_ACS_SCAN_SUCCESS_EVENT, +#endif + eSAP_ACS_CHANNEL_SELECTED, +} eSapHddEvent; + +typedef enum { + eSAP_OPEN_SYSTEM, + eSAP_SHARED_KEY, + eSAP_AUTO_SWITCH +} eSapAuthType; + +typedef enum { + /* Disassociation was internally initated from CORE stack */ + eSAP_MAC_INITATED_DISASSOC = 0x10000, + /* + * Disassociation was internally initated from host by + * invoking wlansap_disassoc_sta call + */ + eSAP_USR_INITATED_DISASSOC +} eSapDisassocReason; + +/*Handle bool over here*/ +typedef enum { + eSAP_FALSE, + eSAP_TRUE, +} eSapBool; + +typedef enum { + eSAP_DFS_NOL_CLEAR, + eSAP_DFS_NOL_RANDOMIZE, +} eSapDfsNolType; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_STATUS_SUCCESS, /* Success. */ + eSAP_STATUS_FAILURE, /* General Failure. */ + /* Channel not selected during intial scan. */ + eSAP_START_BSS_CHANNEL_NOT_SELECTED, + eSAP_ERROR_MAC_START_FAIL, /* Failed to start Infra BSS */ +} eSapStatus; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_WPSPBC_OVERLAP_IN120S, /* Overlap */ + /* no WPS probe request in 120 second */ + eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S, + /* One WPS probe request in 120 second */ + eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S, +} eWPSPBCOverlap; + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +typedef struct sap_StartBssCompleteEvent_s { + uint8_t status; + uint8_t operatingChannel; + uint16_t staId; /* self StaID */ + uint8_t sessionId; /* SoftAP SME session ID */ +} tSap_StartBssCompleteEvent; + +typedef struct sap_StopBssCompleteEvent_s { + uint8_t status; +} tSap_StopBssCompleteEvent; + +typedef struct sap_StationAssocIndication_s { + struct cdf_mac_addr staMac; + uint8_t assoId; + uint8_t staId; + uint8_t status; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + bool fWmmEnabled; + eCsrAuthType negotiatedAuthType; + eCsrEncryptionType negotiatedUCEncryptionType; + eCsrEncryptionType negotiatedMCEncryptionType; + bool fAuthRequired; +} tSap_StationAssocIndication; + +typedef struct sap_StationAssocReassocCompleteEvent_s { + struct cdf_mac_addr staMac; + uint8_t staId; + uint8_t status; + uint8_t ies[MAX_ASSOC_IND_IE_LEN]; + uint16_t iesLen; + uint32_t statusCode; + eSapAuthType SapAuthType; + bool wmmEnabled; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + uint32_t assocRespLength; + uint8_t *assocRespPtr; + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; +} tSap_StationAssocReassocCompleteEvent; + +typedef struct sap_StationDisassocCompleteEvent_s { + struct cdf_mac_addr staMac; + uint8_t staId; /* STAID should not be used */ + uint8_t status; + uint32_t statusCode; + eSapDisassocReason reason; +} tSap_StationDisassocCompleteEvent; + +typedef struct sap_StationSetKeyCompleteEvent_s { + uint8_t status; + struct cdf_mac_addr peerMacAddr; +} tSap_StationSetKeyCompleteEvent; + +/*struct corresponding to SAP_STA_MIC_FAILURE_EVENT */ +typedef struct sap_StationMICFailureEvent_s { + struct cdf_mac_addr srcMacAddr; /* address used to compute MIC */ + struct cdf_mac_addr staMac; /* taMacAddr transmitter address */ + struct cdf_mac_addr dstMacAddr; + eSapBool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + +} tSap_StationMICFailureEvent; +/*Structure to return MAC address of associated stations */ +typedef struct sap_AssocMacAddr_s { + struct cdf_mac_addr staMac; /* Associated station's MAC address */ + uint8_t assocId; /* Associated station's Association ID */ + uint8_t staId; /* Allocated station Id */ + uint8_t ShortGI40Mhz; + uint8_t ShortGI20Mhz; + uint8_t Support40Mhz; + uint32_t requestedMCRate; + tSirSupportedRates supportedRates; +} tSap_AssocMacAddr, *tpSap_AssocMacAddr; + +/*struct corresponding to SAP_ASSOC_STA_CALLBACK_EVENT */ +typedef struct sap_AssocStaListEvent_s { + CDF_MODULE_ID module; + /* module id that was passed in wlansap_get_assoc_stations API */ + uint8_t noOfAssocSta; /* Number of associated stations */ + tpSap_AssocMacAddr pAssocStas; + /* + * Pointer to pre allocated memory to obtain list of + * associated stations passed in wlansap_get_assoc_stations API + */ +} tSap_AssocStaListEvent; + +typedef struct sap_GetWPSPBCSessionEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + CDF_MODULE_ID module; + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + struct cdf_mac_addr addr; + eWPSPBCOverlap wpsPBCOverlap; +} tSap_GetWPSPBCSessionEvent; + +typedef struct sap_WPSPBCProbeReqEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + CDF_MODULE_ID module; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSap_WPSPBCProbeReqEvent; + +typedef struct sap_ManagementFrameInfo_s { + uint32_t nFrameLength; + uint8_t frameType; + uint32_t rxChan; /* Channel of where packet is received */ + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, + * in that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; +} tSap_ManagementFrameInfo; + +typedef struct sap_SendActionCnf_s { + eSapStatus actionSendSuccess; +} tSap_SendActionCnf; + +typedef struct sap_UnknownSTAJoinEvent_s { + struct cdf_mac_addr macaddr; +} tSap_UnknownSTAJoinEvent; + +typedef struct sap_MaxAssocExceededEvent_s { + struct cdf_mac_addr macaddr; +} tSap_MaxAssocExceededEvent; + +typedef struct sap_DfsNolInfo_s { + uint16_t sDfsList; /* size of pDfsList in byte */ + void *pDfsList; /* pointer to pDfsList buffer */ +} tSap_DfsNolInfo; + +/** + * sap_acs_ch_selected_s - the structure to hold the selected channels + * @pri_channel: Holds the ACS selected primary channel + * @sec_channel: Holds the ACS selected secondary channel + * + * Holds the primary and secondary channel selected by ACS and is + * used to send it to the HDD. + */ +struct sap_ch_selected_s { + uint16_t pri_ch; + uint16_t ht_sec_ch; + uint16_t vht_seg0_center_ch; + uint16_t vht_seg1_center_ch; + uint16_t ch_width; +}; + +/** + * sap_roc_ready_ind_s - the structure to hold the scan id + * @scan_id: scan identifier + * + * Holds scan identifier + */ +struct sap_roc_ready_ind_s { + uint32_t scan_id; +}; +/* + * This struct will be filled in and passed to tpWLAN_SAPEventCB that is + * provided during wlansap_start_bss call The event id corresponding to + * structure in the union is defined in comment next to the structure + */ + +typedef struct sap_Event_s { + eSapHddEvent sapHddEventCode; + union { + /*SAP_START_BSS_EVENT */ + tSap_StartBssCompleteEvent sapStartBssCompleteEvent; + /*SAP_STOP_BSS_EVENT */ + tSap_StopBssCompleteEvent sapStopBssCompleteEvent; + /*SAP_ASSOC_INDICATION */ + tSap_StationAssocIndication sapAssocIndication; + /*SAP_STA_ASSOC_EVENT, SAP_STA_REASSOC_EVENT */ + tSap_StationAssocReassocCompleteEvent + sapStationAssocReassocCompleteEvent; + /*SAP_STA_DISASSOC_EVENT */ + tSap_StationDisassocCompleteEvent + sapStationDisassocCompleteEvent; + /*SAP_STA_SET_KEY_EVENT */ + tSap_StationSetKeyCompleteEvent sapStationSetKeyCompleteEvent; + /*SAP_STA_MIC_FAILURE_EVENT */ + tSap_StationMICFailureEvent sapStationMICFailureEvent; + /*SAP_ASSOC_STA_CALLBACK_EVENT */ + tSap_AssocStaListEvent sapAssocStaListEvent; + /*SAP_GET_WPSPBC_SESSION_EVENT */ + tSap_GetWPSPBCSessionEvent sapGetWPSPBCSessionEvent; + /*eSAP_WPS_PBC_PROBE_REQ_EVENT */ + tSap_WPSPBCProbeReqEvent sapPBCProbeReqEvent; + /*eSAP_INDICATE_MGMT_FRAME */ + tSap_ManagementFrameInfo sapManagementFrameInfo; + /* eSAP_SEND_ACTION_CNF */ + tSap_SendActionCnf sapActionCnf; + /* eSAP_UNKNOWN_STA_JOIN */ + tSap_UnknownSTAJoinEvent sapUnknownSTAJoin; + /* eSAP_MAX_ASSOC_EXCEEDED */ + tSap_MaxAssocExceededEvent sapMaxAssocExceeded; + /*eSAP_DFS_NOL_XXX */ + tSap_DfsNolInfo sapDfsNolInfo; + struct sap_ch_selected_s sap_ch_selected; + struct sap_roc_ready_ind_s sap_roc_ind; + + } sapevt; +} tSap_Event, *tpSap_Event; + +typedef struct sap_SSID { + uint8_t length; + uint8_t ssId[MAX_SSID_LEN]; +} cdf_packed tSap_SSID_t; + +typedef struct sap_SSIDInfo { + tSap_SSID_t ssid; /* SSID of the AP */ + /* SSID should/shouldn't be bcast in probe RSP & beacon */ + uint8_t ssidHidden; +} cdf_packed tSap_SSIDInfo_t; + +struct sap_acs_cfg { + /* ACS Algo Input */ + uint8_t acs_mode; + uint32_t hw_mode; + uint8_t start_ch; + uint8_t end_ch; + uint8_t *ch_list; + uint8_t ch_list_count; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t skip_scan_status; + uint8_t skip_scan_range1_stch; + uint8_t skip_scan_range1_endch; + uint8_t skip_scan_range2_stch; + uint8_t skip_scan_range2_endch; +#endif + + uint16_t ch_width; + uint8_t pcl_channels[NUM_RF_CHANNELS]; + uint32_t pcl_ch_count; + /* ACS Algo Output */ + uint8_t pri_ch; + uint8_t ht_sec_ch; + uint8_t vht_seg0_center_ch; + uint8_t vht_seg1_center_ch; +}; + +typedef struct sap_Config { + tSap_SSIDInfo_t SSIDinfo; + eCsrPhyMode SapHw_mode; /* Wireless Mode */ + eSapMacAddrACL SapMacaddr_acl; + struct cdf_mac_addr accept_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + bool ieee80211d; /* Specify if 11D is enabled or disabled */ + bool protEnabled; /* Specify if protection is enabled or disabled */ + /* Specify if OBSS protection is enabled or disabled */ + bool obssProtEnabled; + struct cdf_mac_addr deny_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + struct cdf_mac_addr self_macaddr; /* self macaddress or BSSID */ + uint8_t channel; /* Operation channel */ + uint8_t sec_ch; + chan_params_t ch_params; + uint32_t ch_width_orig; + uint8_t max_num_sta; /* maximum number of STAs in station table */ + uint8_t dtim_period; /* dtim interval */ + uint8_t num_accept_mac; + uint8_t num_deny_mac; + /* Max ie length 255 * 2(WPA+RSN) + 2 bytes(vendor specific ID) * 2 */ + uint8_t RSNWPAReqIE[(SIR_MAC_MAX_IE_LENGTH * 2) + 4]; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t RSNAuthType; + uint8_t RSNEncryptType; + uint8_t mcRSNEncryptType; + eSapAuthType authType; + bool privacy; + bool UapsdEnable; + bool fwdWPSPBCProbeReq; + /* 0 - disabled, 1 - not configured , 2 - configured */ + uint8_t wps_state; + uint16_t ht_capab; + uint16_t RSNWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint32_t beacon_int; /* Beacon Interval */ + uint32_t ap_table_max_size; + uint32_t ap_table_expiration_time; + uint32_t ht_op_mode_fixed; + tCDF_CON_MODE persona; /* Tells us which persona its GO or AP for now */ + uint8_t disableDFSChSwitch; + bool enOverLapCh; +#ifdef WLAN_FEATURE_11W + bool mfpRequired; + bool mfpCapable; +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + struct sap_acs_cfg acs_cfg; + uint16_t probeRespIEsBufferLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespIEsBuffer; + uint16_t assocRespIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pAssocRespIEsBuffer; + uint16_t probeRespBcnIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespBcnIEsBuffer; + uint8_t sap_dot11mc; /* Specify if 11MC is enabled or disabled*/ +} tsap_Config_t; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +typedef enum { + eSAP_DO_NEW_ACS_SCAN, + eSAP_DO_PAR_ACS_SCAN, + eSAP_SKIP_ACS_SCAN +} tSap_skip_acs_scan; +#endif + +typedef enum { + eSAP_WPS_PROBE_RSP_IE, + eSAP_WPS_BEACON_IE, + eSAP_WPS_ASSOC_RSP_IE +} eSapWPSIE_CODE; + +typedef struct sSapName { + uint8_t num_name; + uint8_t name[MAX_NAME_SIZE]; +} tSapName; + +typedef struct sSapText { + uint8_t num_text; + uint8_t text[MAX_TEXT_SIZE]; +} tSapText; + +typedef enum { + eSAP_DFS_DO_NOT_SKIP_CAC, + eSAP_DFS_SKIP_CAC +} eSapDfsCACState_t; + +typedef enum { + eSAP_DFS_CHANNEL_USABLE, + eSAP_DFS_CHANNEL_AVAILABLE, + eSAP_DFS_CHANNEL_UNAVAILABLE +} eSapDfsChanStatus_t; + +typedef struct sSapDfsNolInfo { + uint8_t dfs_channel_number; + eSapDfsChanStatus_t radar_status_flag; + uint64_t radar_found_timestamp; +} tSapDfsNolInfo; + +typedef struct sSapDfsInfo { + cdf_mc_timer_t sap_dfs_cac_timer; + uint8_t sap_radar_found_status; + /* + * New channel to move to when a Radar is + * detected on current Channel + */ + uint8_t target_channel; + uint8_t last_radar_found_channel; + uint8_t ignore_cac; + eSapDfsCACState_t cac_state; + uint8_t user_provided_target_channel; + + /* + * Requests for Channel Switch Announcement IE + * generation and transmission + */ + uint8_t csaIERequired; + uint8_t numCurrentRegDomainDfsChannels; + tSapDfsNolInfo sapDfsChannelNolList[NUM_5GHZ_CHANNELS]; + uint8_t is_dfs_cac_timer_running; + /* + * New channel width and new channel bonding mode + * will only be updated via channel fallback mechanism + */ + uint8_t orig_cbMode; + uint8_t orig_chanWidth; + uint8_t new_chanWidth; + uint8_t new_cbMode; + + /* + * INI param to enable/disable SAP W53 + * channel operation. + */ + uint8_t is_dfs_w53_disabled; + + /* + * sap_operating_channel_location holds SAP indoor, + * outdoor location information. Currently, if this + * param is set this Indoor/outdoor channel interop + * restriction will only be implemented for JAPAN + * regulatory domain. + * + * 0 - Indicates that location unknown + * (or) SAP Indoor/outdoor interop is allowed + * + * 1 - Indicates device is operating on Indoor channels + * and SAP cannot pick next random channel from outdoor + * list of channels when a radar is found on current operating + * DFS channel. + * + * 2 - Indicates device is operating on Outdoor Channels + * and SAP cannot pick next random channel from indoor + * list of channels when a radar is found on current + * operating DFS channel. + */ + uint8_t sap_operating_chan_preferred_location; + + /* + * Flag to indicate if DFS test mode is enabled and + * channel switch is disabled. + */ + uint8_t disable_dfs_ch_switch; +} tSapDfsInfo; + +typedef struct tagSapCtxList { + uint8_t sessionID; + void *pSapContext; + tCDF_CON_MODE sapPersona; +} tSapCtxList, tpSapCtxList; + +typedef struct tagSapStruct { + /* Information Required for SAP DFS Master mode */ + tSapDfsInfo SapDfsInfo; + tSapCtxList sapCtxList[SAP_MAX_NUM_SESSION]; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + bool enable_dfs_phy_error_logs; +} tSapStruct, *tpSapStruct; + +#define WPS_PROBRSP_VER_PRESENT 0x00000001 +#define WPS_PROBRSP_STATE_PRESENT 0x00000002 +#define WPS_PROBRSP_APSETUPLOCK_PRESENT 0x00000004 +#define WPS_PROBRSP_SELECTEDREGISTRA_PRESENT 0x00000008 +#define WPS_PROBRSP_DEVICEPASSWORDID_PRESENT 0x00000010 +#define WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define WPS_PROBRSP_RESPONSETYPE_PRESENT 0x00000040 +#define WPS_PROBRSP_UUIDE_PRESENT 0x00000080 +#define WPS_PROBRSP_MANUFACTURE_PRESENT 0x00000100 +#define WPS_PROBRSP_MODELNAME_PRESENT 0x00000200 +#define WPS_PROBRSP_MODELNUMBER_PRESENT 0x00000400 +#define WPS_PROBRSP_SERIALNUMBER_PRESENT 0x00000800 +#define WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT 0x00001000 +#define WPS_PROBRSP_DEVICENAME_PRESENT 0x00002000 +#define WPS_PROBRSP_CONFIGMETHODS_PRESENT 0x00004000 +#define WPS_PROBRSP_RF_BANDS_PRESENT 0x00008000 + +typedef struct sap_WPSProbeRspIE_s { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* indicates if user has recently activated a reg to add an Enrollee. */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t ResponseType; /* Response type */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + tSapName Manufacture; + tSapText ModelName; + tSapText ModelNumber; + tSapText SerialNumber; + /* Device Category ID: 1Computer, 2Input Device, ... */ + uint32_t PrimaryDeviceCategory; + /* Vendor specific OUI for Device Sub Category */ + uint8_t PrimaryDeviceOUI[4]; + /* + * Device Sub Category ID: 1-PC, + * 2-Server if Device Category is computer + */ + uint32_t DeviceSubCategory; + tSapText DeviceName; + uint16_t ConfigMethod; /* Configuaration method */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSap_WPSProbeRspIE; + +#define WPS_BEACON_VER_PRESENT 0x00000001 +#define WPS_BEACON_STATE_PRESENT 0x00000002 +#define WPS_BEACON_APSETUPLOCK_PRESENT 0x00000004 +#define WPS_BEACON_SELECTEDREGISTRA_PRESENT 0x00000008 +#define WPS_BEACON_DEVICEPASSWORDID_PRESENT 0x00000010 +#define WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define WPS_BEACON_UUIDE_PRESENT 0x00000080 +#define WPS_BEACON_RF_BANDS_PRESENT 0x00000100 + +typedef struct sap_WPSBeaconIE_s { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* indicates if user has recently activated a reg to add an Enrollee. */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + uint16_t SelectedRegistraCfgMethod; /* Selected reg config method */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSap_WPSBeaconIE; + +#define WPS_ASSOCRSP_VER_PRESENT 0x00000001 +#define WPS_ASSOCRSP_RESPONSETYPE_PRESENT 0x00000002 + +typedef struct sap_WPSAssocRspIE_s { + uint32_t FieldPresent; + uint32_t Version; + uint8_t ResposeType; +} tSap_WPSAssocRspIE; + +typedef struct sap_WPSIE_s { + eSapWPSIE_CODE sapWPSIECode; + union { + tSap_WPSProbeRspIE sapWPSProbeRspIE; /* WPS Set Probe Resp IE */ + tSap_WPSBeaconIE sapWPSBeaconIE; /* WPS Set Beacon IE */ + tSap_WPSAssocRspIE sapWPSAssocRspIE; /* WPS Set Assoc Resp IE */ + } sapwpsie; +} tSap_WPSIE, *tpSap_WPSIE; + +#ifdef WLANTL_DEBUG +#define MAX_RATE_INDEX 136 +#define MAX_NUM_RSSI 100 +#define MAX_RSSI_INTERVAL 5 +#endif + +typedef struct sap_SoftapStats_s { + uint32_t txUCFcnt; + uint32_t txMCFcnt; + uint32_t txBCFcnt; + uint32_t txUCBcnt; + uint32_t txMCBcnt; + uint32_t txBCBcnt; + uint32_t rxUCFcnt; + uint32_t rxMCFcnt; + uint32_t rxBCFcnt; + uint32_t rxUCBcnt; + uint32_t rxMCBcnt; + uint32_t rxBCBcnt; + uint32_t rxBcnt; + uint32_t rxBcntCRCok; + uint32_t rxRate; +#ifdef WLANTL_DEBUG + uint32_t pktCounterRateIdx[MAX_RATE_INDEX]; + uint32_t pktCounterRssi[MAX_NUM_RSSI]; +#endif +} tSap_SoftapStats, *tpSap_SoftapStats; +/* Channel/Frequency table */ +extern const tRfChannelProps rf_channels[NUM_RF_CHANNELS]; +#ifdef FEATURE_WLAN_CH_AVOID +/* Store channel safety information */ +typedef struct { + uint16_t channelNumber; + bool isSafe; +} sapSafeChannelType; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef WLAN_FEATURE_MBSSID +void sap_cleanup_channel_list(void *sapContext); +#else +void sap_cleanup_channel_list(void); +#endif +void sapCleanupAllChannelList(void); +CDF_STATUS wlansap_set_wps_ie(void *p_cds_gctx, tSap_WPSIE *pWPSIe); +CDF_STATUS wlansap_update_wps_ie(void *p_cds_gctx); +CDF_STATUS wlansap_stop_Wps(void *p_cds_gctx); +CDF_STATUS wlansap_get_wps_state(void *p_cds_gctx, bool *pbWPSState); + +#ifdef WLAN_FEATURE_MBSSID +void * +#else +CDF_STATUS +#endif +wlansap_open(void *p_cds_gctx); +CDF_STATUS wlansap_start(void *p_cds_gctx); +CDF_STATUS wlansap_stop(void *p_cds_gctx); +CDF_STATUS wlansap_close(void *p_cds_gctx); +typedef CDF_STATUS (*tpWLAN_SAPEventCB)(tpSap_Event pSapEvent, + void *pUsrContext); +uint8_t wlansap_get_state(void *p_cds_gctx); + +CDF_STATUS wlansap_start_bss(void *p_cds_gctx, + tpWLAN_SAPEventCB pSapEventCallback, + tsap_Config_t *pConfig, void *pUsrContext); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t wlansap_check_cc_intf(void *Ctx); +#endif +CDF_STATUS wlansap_set_mac_acl(void *p_cds_gctx, tsap_Config_t *pConfig); +CDF_STATUS wlansap_stop_bss(void *p_cds_gctx); +CDF_STATUS wlansap_disassoc_sta(void *p_cds_gctx, + const uint8_t *pPeerStaMac); +CDF_STATUS wlansap_deauth_sta(void *p_cds_gctx, + struct tagCsrDelStaParams *pDelStaParams); +CDF_STATUS wlansap_set_channel_change_with_csa(void *p_cds_gctx, + uint32_t targetChannel); +CDF_STATUS wlansap_set_key_sta(void *p_cds_gctx, + tCsrRoamSetKey *pSetKeyInfo); +CDF_STATUS wlansap_get_assoc_stations(void *p_cds_gctx, + CDF_MODULE_ID module, tpSap_AssocMacAddr pAssocStas); +CDF_STATUS wlansap_remove_wps_session_overlap(void *p_cds_gctx, + struct cdf_mac_addr pRemoveMac); +CDF_STATUS wlansap_get_wps_session_overlap(void *p_cds_gctx); +CDF_STATUS wlansap_set_counter_measure(void *p_cds_gctx, bool bEnable); +CDF_STATUS wlan_sap_getstation_ie_information(void *p_cds_gctx, + uint32_t *pLen, uint8_t *pBuf); +CDF_STATUS wlansap_clear_acl(void *p_cds_gctx); +CDF_STATUS wlansap_get_acl_accept_list(void *p_cds_gctx, + struct cdf_mac_addr *pAcceptList, uint8_t *nAcceptList); +CDF_STATUS wlansap_get_acl_deny_list(void *pCtx, + struct cdf_mac_addr *pDenyList, uint8_t *nDenyList); +CDF_STATUS wlansap_set_mode(void *p_cds_gctx, uint32_t mode); +CDF_STATUS wlansap_get_acl_mode(void *p_cds_gctx, eSapMacAddrACL *mode); +CDF_STATUS wlansap_modify_acl(void *p_cds_gctx, + uint8_t *pPeerStaMac, eSapACLType listType, eSapACLCmdType cmd); +CDF_STATUS wlansap_set_wparsn_ies + (void *p_cds_gctx, uint8_t *pWPARSNIEs, uint32_t WPARSNIEsLen); +CDF_STATUS wlansap_send_action + (void *p_cds_gctx, + const uint8_t *pBuf, uint32_t len, uint16_t wait, uint16_t channel_freq); +CDF_STATUS wlansap_remain_on_channel + (void *p_cds_gctx, + uint8_t channel, + uint32_t duration, remainOnChanCallback callback, void *pContext, + uint32_t *scan_id); +CDF_STATUS wlansap_cancel_remain_on_channel(void *p_cds_gctx, + uint32_t scan_id); +CDF_STATUS wlansap_register_mgmt_frame + (void *p_cds_gctx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen); +CDF_STATUS wlansap_de_register_mgmt_frame + (void *p_cds_gctx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen); +CDF_STATUS wlansap_channel_change_request(void *p_cds_gctx, + uint8_t tArgetChannel); +CDF_STATUS wlansap_start_beacon_req(void *pSapCtx); +CDF_STATUS wlansap_dfs_send_csa_ie_request(void *pSapCtx); +CDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac); +CDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac); +CDF_STATUS wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, + uint8_t disable_Dfs_JapanW3); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +CDF_STATUS +wlan_sap_set_channel_avoidance(tHalHandle hal, bool sap_channel_avoidance); +#endif + +CDF_STATUS wlansap_set_dfs_preferred_channel_location(tHalHandle hHal, + uint8_t dfs_Preferred_Channels_location); +CDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, + uint8_t target_channel); +uint32_t wlan_sap_get_vht_ch_width(void *ctx); +void wlan_sap_set_vht_ch_width(void *ctx, uint32_t vht_channel_width); +CDF_STATUS wlansap_update_sap_config_add_ie(tsap_Config_t *pConfig, + const uint8_t * + pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType); +CDF_STATUS wlansap_reset_sap_config_add_ie(tsap_Config_t *pConfig, + eUpdateIEsType updateType); +void wlansap_extend_to_acs_range(uint8_t *startChannelNum, + uint8_t *endChannelNum, + uint8_t *bandStartChannel, + uint8_t *bandEndChannel); +CDF_STATUS wlansap_get_dfs_nol(void *pSapCtx); +CDF_STATUS wlansap_set_dfs_nol(void *pSapCtx, eSapDfsNolType conf); +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct tagCsrDelStaParams *pDelStaParams); +CDF_STATUS wlansap_acs_chselect(void *pvos_gctx, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_Config_t *pconfig, + void *pusr_context); +#ifdef __cplusplus +} +#endif +#endif /* #ifndef WLAN_QCT_WLANSAP_H */ diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c new file mode 100644 index 0000000000..4ea65dcec7 --- /dev/null +++ b/core/sap/src/sap_api_link_cntl.c @@ -0,0 +1,1209 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p A p i L i n k C n t l . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + Link Control functions. + + The functions externalized by this module are to be called ONLY by other + WLAN modules (HDD) + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "cdf_trace.h" +/* Pick up the CSR callback definition */ +#include "csr_api.h" +#include "sme_api.h" +/* SAP Internal API header file */ +#include "sap_internal.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/* + * wlansap_scan_callback() - Callback for Scan (scan results) Events + * + * @hal_handle : tHalHandle passed in with the scan request + * @ctx : The second context pass in for the caller (sapContext) + * @scanID : scanID got after the scan + * + * Callback for Scan (scan results) Events + * + * Return: Status + */ +CDF_STATUS wlansap_scan_callback(tHalHandle hal_handle, + void *ctx, /* Opaque SAP handle */ + uint8_t session_id, + uint32_t scan_id, eCsrScanStatus scan_status) { + tScanResultHandle result = NULL; + CDF_STATUS get_result_status = CDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = (ptSapContext) ctx; + tWLAN_SAPEvent sapEvent; /* State machine event */ + uint8_t operChannel = 0; + CDF_STATUS sap_sm_status; + +#ifdef SOFTAP_CHANNEL_RANGE + uint32_t event; +#endif + + if (NULL == hal_handle) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return CDF_STATUS_E_FAILURE; + } + if (sap_ctx->sapsMachine == eSAP_DISCONNECTED) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + "In %s BSS already stopped", __func__); + return CDF_STATUS_E_FAILURE; + } + + switch (scan_status) { + case eCSR_SCAN_SUCCESS: + /* sapScanCompleteCallback with eCSR_SCAN_SUCCESS */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, CSR scanStatus = %s (%d)", __func__, + "eCSR_SCAN_SUCCESS", scan_status); + + /** + * Get scan results, Run channel selection algorithm, + * select channel and keep in sap_ctx->Channel + */ + get_result_status = + sme_scan_get_result(hal_handle, sap_ctx->sessionId, NULL, + &result); + + event = eSAP_MAC_SCAN_COMPLETE; + + if ((get_result_status != CDF_STATUS_SUCCESS) + && (get_result_status != CDF_STATUS_E_NULL_VALUE)) { + /* No scan results */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s, Get scan result failed! ret = %d", + __func__, get_result_status); + break; + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (scan_id != 0) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Sending ACS Scan skip event", __func__); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } else + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: ACS scan id: %d (skipped ACS SCAN)", + __func__, scan_id); +#endif + operChannel = sap_select_channel(hal_handle, sap_ctx, result); + + sme_scan_result_purge(hal_handle, result); + break; + + default: + event = eSAP_CHANNEL_SELECTION_FAILED; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, CSR scanStatus = %s (%d)", __func__, + "eCSR_SCAN_ABORT/FAILURE", scan_status); + } + + if (operChannel == SAP_CHANNEL_NOT_SELECTED) +#ifdef SOFTAP_CHANNEL_RANGE + { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: No suitable channel selected due to DFS, LTE" + "COEX and concurrent mode restrictions", __func__); + + sap_ctx->sapsMachine = eSAP_CH_SELECT; + event = eSAP_CHANNEL_SELECTION_FAILED; + } +#else + sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL; +#endif + else { + sap_ctx->channel = operChannel; + } + + sap_ctx->ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + sme_set_ch_params(hal_handle, + sap_ctx->csr_roamProfile.phyMode, + sap_ctx->channel, + sap_ctx->secondary_ch, + &sap_ctx->ch_params); +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->channelList != NULL) { + /* Always free up the memory for channel selection whatever + * the result */ + cdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + } +#endif + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel selected = %d", __func__, + sap_ctx->channel); + + /* Fill in the event structure */ + sapEvent.event = event; + /* pCsrRoamInfo; */ + sapEvent.params = 0; + /* roamstatus */ + sapEvent.u1 = scan_status; + /* roamResult */ + sapEvent.u2 = 0; + + /* Handle event */ + sap_sm_status = sap_fsm(sap_ctx, &sapEvent); + + return sap_sm_status; +} /* wlansap_scan_callback */ + + +/** + * sap_config_acs_result : Generate ACS result params based on ch constraints + * @sap_ctx: pointer to SAP context data struct + * @hal: HAL Handle pointer + * + * This function calculates the ACS result params: ht sec channel, vht channel + * information and channel bonding based on selected ACS channel. + * + * Return: None + */ + +void sap_config_acs_result(tHalHandle hal, ptSapContext sap_ctx, + uint32_t sec_ch) +{ + uint32_t channel = sap_ctx->acs_cfg->pri_ch; + chan_params_t ch_params = {0}; + + ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + sme_set_ch_params(hal, sap_ctx->csr_roamProfile.phyMode, channel, + sec_ch, &ch_params); + + sap_ctx->acs_cfg->ch_width = ch_params.ch_width; + if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ) + sap_ctx->acs_cfg->vht_seg0_center_ch = + ch_params.center_freq_seg0; + else + sap_ctx->acs_cfg->vht_seg0_center_ch = 0; + + if (sap_ctx->acs_cfg->ch_width == CH_WIDTH_80P80MHZ) + sap_ctx->acs_cfg->vht_seg1_center_ch = + ch_params.center_freq_seg1; + else + sap_ctx->acs_cfg->vht_seg1_center_ch = 0; + + if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4; + else if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4; + else + sap_ctx->acs_cfg->ht_sec_ch = 0; +} + +/** + * sap_hdd_signal_event_handler() - routine to inform hostapd via callback + * + * ctx: pointer to sap context which was passed to callback + * + * this routine will be registered as callback to sme_close_session, so upon + * closure of sap session it notifies the hostapd + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_hdd_signal_event_handler(void *ctx) +{ + ptSapContext sap_ctx = (struct sSapContext *)ctx; + CDF_STATUS status; + if (NULL == sap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("sap context is not valid")); + return CDF_STATUS_E_FAILURE; + } + status = sap_signal_hdd_event(sap_ctx, NULL, + sap_ctx->sap_state, + (void *) sap_ctx->sap_status); + return status; +} + +/** + * + * wlansap_pre_start_bss_acs_scan_callback() - callback for scan results + * + * hal_handle: the hal_handle passed in with the scan request + * pcontext: the second context pass in for the caller, opaque sap Handle. + * scanid: scan id passed + * sessionid: session identifier + * status: status of scan -success, failure or abort + * + * Api for scan callback. This function is invoked as a result of scan + * completion and reports the scan results. + * + * Return: The CDF_STATUS code associated with performing the operation + */ +CDF_STATUS +wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext, + uint8_t sessionid, uint32_t scanid, + eCsrScanStatus scan_status) +{ + tScanResultHandle presult = NULL; + CDF_STATUS scan_get_result_status = CDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = (ptSapContext)pcontext; + uint8_t oper_channel = 0; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (eCSR_SCAN_SUCCESS != scan_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CSR scan_status = eCSR_SCAN_ABORT/FAILURE (%d), choose default channel"), + scan_status); +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->acs_cfg->hw_mode == eCSR_DOT11_MODE_11a) + sap_ctx->channel = SAP_DEFAULT_5GHZ_CHANNEL; + else + sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL; +#else + sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL; +#endif + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + goto close_session; + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR scan_status = eCSR_SCAN_SUCCESS (%d)"), scan_status); + /* + * Now do + * 1. Get scan results + * 2. Run channel selection algorithm + * select channel and store in pSapContext->Channel + */ + scan_get_result_status = sme_scan_get_result(hal_handle, + sap_ctx->sessionId, + NULL, &presult); + if ((scan_get_result_status != CDF_STATUS_SUCCESS) && + (scan_get_result_status != CDF_STATUS_E_NULL_VALUE)) { + /* + * No scan results So, set the operation channel not selected + * to allow the default channel to be set when reporting to HDD + */ + oper_channel = SAP_CHANNEL_NOT_SELECTED; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Get scan result failed! ret = %d"), + scan_get_result_status); + } else { +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (scanid != 0) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Sending ACS Scan skip event")); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("ACS scanid: %d (skipped ACS SCAN)"), + scanid); + } +#endif + oper_channel = sap_select_channel(hal_handle, sap_ctx, presult); + sme_scan_result_purge(hal_handle, presult); + } + + if (oper_channel == SAP_CHANNEL_NOT_SELECTED) { +#ifdef SOFTAP_CHANNEL_RANGE + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("No suitable channel selected")); + + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_FAILURE; + goto close_session; + } else { +#else + sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL; + } else { +#endif + /* Valid Channel Found from scan results. */ + sap_ctx->acs_cfg->pri_ch = oper_channel; + sap_ctx->channel = oper_channel; + } + sap_config_acs_result(hal_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch); + +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->channelList != NULL) { + /* + * Always free up the memory for + * channel selection whatever + * the result + */ + cdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + } +#endif + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel selected = %d"), sap_ctx->channel); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; +close_session: + status = sme_close_session(hal_handle, + sap_ctx->sessionId, sap_hdd_signal_event_handler, + sap_ctx); + if (CDF_STATUS_SUCCESS != status) + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CloseSession failed")); + else + sap_ctx->isScanSessionOpen = eSAP_FALSE; + sap_ctx->sessionId = 0xff; + return status; +} + +/** + * wlansap_roam_process_ch_change_success() - handles the case for + * eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS in function wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @csr_roam_info: raom info struct + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_ch_change_success(tpAniSirGlobal mac_ctx, + ptSapContext sap_ctx, + tCsrRoamInfo *csr_roam_info, + CDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + CDF_STATUS cdf_status; + /* + * Channel change is successful. If the new channel is a DFS channel, + * then we will to perform channel availability check for 60 seconds + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: changing target channel to [%d]"), + mac_ctx->sap.SapDfsInfo.target_channel); + sap_ctx->channel = mac_ctx->sap.SapDfsInfo.target_channel; + /* Identify if this is channel change in radar detected state */ + if (eSAP_DISCONNECTING != sap_ctx->sapsMachine) + return; + + /* check if currently selected channel is a DFS channel */ + if (CHANNEL_STATE_DFS == cds_get_channel_state(sap_ctx->channel)) { + if ((false == mac_ctx->sap.SapDfsInfo.ignore_cac) + && (eSAP_DFS_DO_NOT_SKIP_CAC == + mac_ctx->sap.SapDfsInfo.cac_state)) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => DISCONNECTED with ignore cac false on sapctx[%p]"), + sap_ctx); + /* DFS Channel */ + sap_event.event = eSAP_DFS_CHANNEL_CAC_START; + sap_event.params = csr_roam_info; + sap_event.u1 = 0; + sap_event.u2 = 0; + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING with ignore cac true on sapctx[%p]"), + sap_ctx); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(sap_ctx); + sap_ctx->sapsMachine = eSAP_STARTING; + mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING on sapctx[%p]"), + sap_ctx); + /* non-DFS channel */ + sap_ctx->sapsMachine = eSAP_STARTING; + mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + + /* Handle the event */ + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + *ret_status = CDF_STATUS_E_FAILURE; +} + +/** + * wlansap_roam_process_dfs_chansw_update_fail() - handles the case for + * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE in wlansap_roam_callback() + * + * @hal: hal global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_dfs_chansw_update_fail(tHalHandle hHal, + ptSapContext sap_ctx, + CDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + uint8_t intf; + CDF_STATUS cdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + eCsrPhyMode phy_mode = sap_ctx->csr_roamProfile.phyMode; + uint8_t dfs_beacon_start_req = 0; + + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("sapdfs: DFS channel switch disabled")); + /* + * Send a beacon start request to PE. CSA IE required flag from + * beacon template will be cleared by now. A new beacon template + * with no CSA IE will be sent to firmware. + */ + dfs_beacon_start_req = eSAP_TRUE; + *ret_status = sme_roam_start_beacon_req(hHal, sap_ctx->bssid, + dfs_beacon_start_req); + return; + } + /* + * Both success and failure cases are handled intentionally handled + * together. Irrespective of whether the channel switch IE was sent out + * successfully or not, SAP should still vacate the channel immediately + */ + if (eSAP_STARTED != sap_ctx->sapsMachine) { + /* Further actions to be taken here */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state\n"), + sap_ctx->sapsMachine); + return; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_STARTED => eSAP_DISCONNECTING")); + /* SAP to be moved to DISCONNECTING state */ + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + /* + * The associated stations have been informed to move to a different + * channel. However, the AP may not always select the advertised channel + * for operation if the radar is seen. In that case, the stations will + * experience link-loss and return back through scanning if they wish to + */ + + /* + * Send channel change request. From spec it is required that the AP + * should continue to operate in the same mode as it is operating + * currently. For e.g. 20/40/80 MHz operation + */ + if (mac_ctx->sap.SapDfsInfo.target_channel) + sme_set_ch_params(hHal, phy_mode, + mac_ctx->sap.SapDfsInfo.target_channel, 0, + &sap_ctx->ch_params); + /* + * Fetch the number of SAP interfaces. If the number of sap Interface + * more than one then we will make is_sap_ready_for_chnl_chng to true + * for that sapctx. If there is only one SAP interface then process + * immediately + */ + if (sap_get_total_number_sap_intf(hHal) <= 1) { + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Posting event eWNI_SME_CHANNEL_CHANGE_REQ to sapFSM")); + /* Handle event */ + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + *ret_status = CDF_STATUS_E_FAILURE; + return; + } + + sap_ctx->is_sap_ready_for_chnl_chng = true; + /* + * now check if the con-current sap interface is ready + * for channel change. If yes then we issue channel change for + * both the SAPs. If no then simply return success & we will + * issue channel change when second AP's 5 CSA beacon Tx is + * completed. + */ + if (false == + is_concurrent_sap_ready_for_channel_change(hHal, sap_ctx)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: sapctx[%p] ready but not concurrent sap"), + sap_ctx); + *ret_status = CDF_STATUS_SUCCESS; + return; + } + + /* Issue channel change req for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext; + if (!((CDF_SAP_MODE == mac_ctx->sap.sapCtxList[intf].sapPersona) + && (mac_ctx->sap.sapCtxList[intf].pSapContext != NULL))) + continue; + + pSapContext = mac_ctx->sap.sapCtxList[intf].pSapContext; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:issue chnl change for sapctx[%p]"), + pSapContext); + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + /* Handle event */ + cdf_status = sap_fsm(pSapContext, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("post chnl chng req failed, sap[%p]"), + sap_ctx); + *ret_status = CDF_STATUS_E_FAILURE; + } else { + pSapContext->is_sap_ready_for_chnl_chng = false; + } + } + return; +} + +/** + * wlansap_roam_process_dfs_radar_found() - handles the case for + * eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND in wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_dfs_radar_found(tpAniSirGlobal mac_ctx, + ptSapContext sap_ctx, + CDF_STATUS *ret_status) +{ + CDF_STATUS cdf_status; + tWLAN_SAPEvent sap_event; + if (eSAP_DFS_CAC_WAIT == sap_ctx->sapsMachine) { + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "sapdfs: DFS channel switch disabled"); + return; + } + if (false == mac_ctx->sap.SapDfsInfo.sap_radar_found_status) + return; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:Posting event eSAP_DFS_CHANNEL_CAC_RADAR_FOUND")); + /* + * If Radar is found, while in DFS CAC WAIT State then post stop + * and destroy the CAC timer and post a + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND to sapFsm. + */ + cdf_mc_timer_stop(&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + cdf_mc_timer_destroy(&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + + /* + * User space is already indicated the CAC start and if + * CAC end on this channel is not indicated, the user + * space will be in some undefined state (e.g., UI frozen) + */ + cdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_CAC_INTERRUPTED, + (void *) eSAP_STATUS_SUCCESS); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Failed to send CAC end")); + /* Want to still proceed and try to switch channel. + * Lets try not to be on the DFS channel + */ + } + + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + sap_event.event = eSAP_DFS_CHANNEL_CAC_RADAR_FOUND; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + *ret_status = CDF_STATUS_E_FAILURE; + return; + } + if (eSAP_STARTED == sap_ctx->sapsMachine) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:Posting event eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START")); + + /* + * Radar found on the operating channel in STARTED state, + * new operating channel has already been selected. Send + * request to SME-->PE for sending CSA IE + */ + sap_event.event = eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + *ret_status = CDF_STATUS_E_FAILURE; + return; + } + /* Further actions to be taken here */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state\n"), + sap_ctx->sapsMachine); + + return; +} + +/** + * wlansap_roam_process_infra_assoc_ind() - handles the case for + * eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND in wlansap_roam_callback() + * + * @sap_ctx: sap context + * @roam_result: roam result + * @csr_roam_info: roam info struct + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_infra_assoc_ind(ptSapContext sap_ctx, + eCsrRoamResult roam_result, + tCsrRoamInfo *csr_roam_info, + CDF_STATUS *ret_status) +{ + CDF_STATUS cdf_status; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND (%d)\n"), + roam_result); + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + cdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); +#ifdef FEATURE_WLAN_WAPI + sap_ctx->nStaWAPIReqIeLength = csr_roam_info->wapiIELen; + if (sap_ctx->nStaWAPIReqIeLength) + cdf_mem_copy(sap_ctx->pStaWapiReqIE, csr_roam_info->pwapiIE, + sap_ctx->nStaWAPIReqIeLength); +#endif + sap_ctx->nStaAddIeLength = csr_roam_info->addIELen; + if (sap_ctx->nStaAddIeLength) + cdf_mem_copy(sap_ctx->pStaAddIE, csr_roam_info->paddIE, + sap_ctx->nStaAddIeLength); + sap_ctx->SapQosCfg.WmmIsEnabled = csr_roam_info->wmmEnabledSta; + /* MAC filtering */ + cdf_status = sap_is_peer_mac_allowed(sap_ctx, + (uint8_t *) csr_roam_info->peerMac.bytes); + + if (CDF_STATUS_SUCCESS == cdf_status) { + cdf_status = sap_signal_hdd_event(sap_ctx, + csr_roam_info, eSAP_STA_ASSOC_IND, + (void *) eSAP_STATUS_SUCCESS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") fail"), + roam_result, MAC_ADDR_ARRAY( + csr_roam_info->peerMac.bytes)); + *ret_status = CDF_STATUS_E_FAILURE; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") not allowed"), + roam_result, + MAC_ADDR_ARRAY(csr_roam_info->peerMac.bytes)); + *ret_status = CDF_STATUS_E_FAILURE; + } + return; +} + +/** + * wlansap_roam_callback() - Callback for Roam (connection status) Events + * @ctx : pContext passed in with the roam request + * @csr_roam_info : Pointer to a tCsrRoamInfo + * @roamId : to identify the callback related roam request. + * 0 means unsolicit + * @roam_status : Flag indicating the status of the callback + * @roam_result : Result + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: Status of operation + */ +CDF_STATUS +wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId, + eRoamCmdStatus roam_status, eCsrRoamResult roam_result) +{ + /* sap_ctx value */ + ptSapContext sap_ctx = (ptSapContext) ctx; + /* State machine event */ + tWLAN_SAPEvent sap_event; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx = NULL; + uint8_t intf; + + if (NULL == hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + cdf_ret_status = CDF_STATUS_E_NOMEM; + return cdf_ret_status; + } + + mac_ctx = PMAC_STRUCT(hal); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Before switch on roam_status = %d\n"), roam_status); + switch (roam_status) { + case eCSR_ROAM_SESSION_OPENED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Calling sme_roam_connect with eCSR_BSS_TYPE_INFRA_AP")); + sap_ctx->isSapSessionOpen = eSAP_TRUE; + cdf_ret_status = sme_roam_connect(hal, sap_ctx->sessionId, + &sap_ctx->csr_roamProfile, + &sap_ctx->csr_roamId); + break; + case eCSR_ROAM_INFRA_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_INFRA_IND (%d)\n"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_INFRA_START_FAILED) { + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_START_FAILS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_LOSTLINK: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_LOSTLINK (%d)\n"), + roam_status); + break; + case eCSR_ROAM_MIC_ERROR_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_MIC_ERROR_IND (%d)\n"), + roam_status); + break; + case eCSR_ROAM_SET_KEY_COMPLETE: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_SET_KEY_COMPLETE (%d)\n"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_ASSOCIATION_COMPLETION: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_ASSOCIATION_COMPLETION (%d)\n"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_DISASSOCIATED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_DISASSOCIATED (%d)\n"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_MIC_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_WPS_PBC_PROBE_REQ_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_WPS_PBC_PROBE_REQ_IND (%d)\n"), + roam_status); + break; + case eCSR_ROAM_INDICATE_MGMT_FRAME: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_INDICATE_MGMT_FRAME, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_REMAIN_CHAN_READY: + /* roamId contains scan identifier */ + sap_ctx->roc_ind_scan_id = csr_roam_info->roc_scan_id; + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_REMAIN_CHAN_READY, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_SEND_ACTION_CNF: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_SEND_ACTION_CNF, + (void *) ((eSapStatus) + ((roam_result == eCSR_ROAM_RESULT_NONE) ? + eSAP_STATUS_SUCCESS : eSAP_STATUS_FAILURE))); + break; + case eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_SEND_P2P_STOP_BSS: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Received stopbss")); + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_DFS_RADAR_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Received Radar Indication")); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Indicate eSAP_DFS_RADAR_DETECT to HDD")); + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_RADAR_DETECT, + (void *) eSAP_STATUS_SUCCESS); + /* sync to latest DFS-NOL */ + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_NOL_GET, + (void *) eSAP_STATUS_SUCCESS); + mac_ctx->sap.SapDfsInfo.target_channel = + sap_indicate_radar(sap_ctx, &csr_roam_info->dfs_event); + /* if there is an assigned next channel hopping */ + if (0 < mac_ctx->sap.SapDfsInfo.user_provided_target_channel) { + mac_ctx->sap.SapDfsInfo.target_channel = + mac_ctx->sap.SapDfsInfo.user_provided_target_channel; + mac_ctx->sap.SapDfsInfo.user_provided_target_channel = + 0; + } + if (mac_ctx->sap.SapDfsInfo.target_channel != 0) { + mac_ctx->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hal); + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + break; + } + /* Issue stopbss for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext; + if (((CDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (CDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].pSapContext != + NULL) { + pSapContext = + mac_ctx->sap.sapCtxList[intf].pSapContext; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("sapdfs: no available channel for sapctx[%p], StopBss"), + pSapContext); + wlansap_stop_bss(pSapContext); + } + } + break; + case eCSR_ROAM_DFS_CHAN_SW_NOTIFY: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Received Chan Sw Update Notification")); + break; + case eCSR_ROAM_SET_CHANNEL_RSP: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Received set channel response")); + break; + default: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CSR roam_status not handled roam_status = %s (%d)\n"), + get_e_roam_cmd_status_str(roam_status), + roam_status); + break; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Before switch on roam_result = %d\n"), roam_result); + + switch (roam_result) { + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND: + wlansap_roam_process_infra_assoc_ind(sap_ctx, roam_result, + csr_roam_info, &cdf_ret_status); + break; + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF (%d)\n"), + roam_result); + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + cdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, + csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); + + sap_ctx->nStaAddIeLength = csr_roam_info->addIELen; + if (sap_ctx->nStaAddIeLength) + cdf_mem_copy(sap_ctx->pStaAddIE, + csr_roam_info->paddIE, + sap_ctx->nStaAddIeLength); + + sap_ctx->SapQosCfg.WmmIsEnabled = + csr_roam_info->wmmEnabledSta; + /* Fill in the event structure */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_ASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_DISASSOC_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_DISASSOC_IND (%d)\n"), + roam_result); + /* Fill in the event structure */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_DEAUTH_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_DEAUTH_IND (%d)\n"), + roam_result); + /* + * Fill in the event structure + * we use the same event inorder to inform HDD to disassociate + * the station + */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_GROUP: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP (%d)\n"), + roam_result); + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_UNICAST: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST (%d)\n"), + roam_result); + /* + * Fill in the event structure + * TODO: support for unicast key MIC failure event to be handled + */ + cdf_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_RESULT_AUTHENTICATED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_AUTHENTICATED (%d)\n"), + roam_result); + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_ASSOCIATED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_ASSOCIATED (%d)\n"), + roam_result); + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_INFRA_STARTED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STARTED (%d)\n"), + roam_result); + /* + * In the current implementation, hostapd is not aware that + * drive will support DFS. Hence, driver should inform + * eSAP_MAC_START_BSS_SUCCESS to upper layers and then perform + * CAC underneath + */ + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_INFRA_STOPPED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STOPPED (%d)\n"), + roam_result); + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_READY_FOR_CONNECTIONS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + cdf_status = sap_fsm(sap_ctx, &sap_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND (%d)\n"), + roam_result); + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_WPS_PBC_PROBE_REQ_EVENT, + (void *) NULL); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_FORCED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_FORCED (%d)\n"), + roam_result); + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_NONE: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_NONE (%d)\n"), + roam_result); + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + if (roam_status == eCSR_ROAM_SET_KEY_COMPLETE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED (%d)\n"), + roam_result); + /* Fill in the event structure */ + cdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAX_ASSOC_EXCEEDED, + NULL); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + cdf_ret_status = CDF_STATUS_E_FAILURE; + + break; + case eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND: + wlansap_roam_process_dfs_radar_found(mac_ctx, sap_ctx, + &cdf_ret_status); + break; + case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS: + case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE: + wlansap_roam_process_dfs_chansw_update_fail(hal, sap_ctx, + &cdf_ret_status); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS: + wlansap_roam_process_ch_change_success(mac_ctx, sap_ctx, + csr_roam_info, &cdf_ret_status); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE: + /* + * This is much more serious issue, we have to vacate the + * channel due to the presence of radar but our channel change + * failed, stop the BSS operation completely and inform hostapd + */ + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + /* Inform cfg80211 and hostapd that BSS is not alive anymore */ + break; + default: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CSR roam_result = %s (%d) not handled\n"), + get_e_csr_roam_result_str(roam_result), + roam_result); + break; + } + return cdf_ret_status; +} diff --git a/core/sap/src/sap_ch_select.c b/core/sap/src/sap_ch_select.c new file mode 100644 index 0000000000..cb8e89fb8b --- /dev/null +++ b/core/sap/src/sap_ch_select.c @@ -0,0 +1,2030 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p C h S e l e c t . C + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_trace.h" +#include "csr_api.h" +#include "sme_api.h" +#include "sap_ch_select.h" +#include "sap_internal.h" +#ifdef ANI_OS_TYPE_QNX +#include "stdio.h" +#endif +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#include "lim_utils.h" +#include "parser_api.h" +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef CONFIG_CNSS +#include +#endif + +/*-------------------------------------------------------------------------- + Function definitions + --------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Defines + --------------------------------------------------------------------------*/ +#define SAP_DEBUG + +#define IS_RSSI_VALID(extRssi, rssi) \ + ( \ + ((extRssi < rssi) ? true : false) \ + ) + +#define SET_ACS_BAND(acs_band, pSapCtx) \ +{ \ + if (pSapCtx->acs_cfg->start_ch <= 14 && \ + pSapCtx->acs_cfg->end_ch <= 14) \ + acs_band = eCSR_DOT11_MODE_11g; \ + else if (pSapCtx->acs_cfg->start_ch >= 14)\ + acs_band = eCSR_DOT11_MODE_11a; \ + else \ + acs_band = eCSR_DOT11_MODE_abg; \ +} + +#ifdef FEATURE_WLAN_CH_AVOID +sapSafeChannelType safe_channels[NUM_20MHZ_RF_CHANNELS] = { + /*CH , SAFE, default safe */ + {1, true} + , /* RF_CHAN_1, */ + {2, true} + , /* RF_CHAN_2, */ + {3, true} + , /* RF_CHAN_3, */ + {4, true} + , /* RF_CHAN_4, */ + {5, true} + , /* RF_CHAN_5, */ + {6, true} + , /* RF_CHAN_6, */ + {7, true} + , /* RF_CHAN_7, */ + {8, true} + , /* RF_CHAN_8, */ + {9, true} + , /* RF_CHAN_9, */ + {10, true} + , /* RF_CHAN_10, */ + {11, true} + , /* RF_CHAN_11, */ + {12, true} + , /* RF_CHAN_12, */ + {13, true} + , /* RF_CHAN_13, */ + {14, true} + , /* RF_CHAN_14, */ + {240, true} + , /* RF_CHAN_240, */ + {244, true} + , /* RF_CHAN_244, */ + {248, true} + , /* RF_CHAN_248, */ + {252, true} + , /* RF_CHAN_252, */ + {208, true} + , /* RF_CHAN_208, */ + {212, true} + , /* RF_CHAN_212, */ + {216, true} + , /* RF_CHAN_216, */ + {36, true} + , /* RF_CHAN_36, */ + {40, true} + , /* RF_CHAN_40, */ + {44, true} + , /* RF_CHAN_44, */ + {48, true} + , /* RF_CHAN_48, */ + {52, true} + , /* RF_CHAN_52, */ + {56, true} + , /* RF_CHAN_56, */ + {60, true} + , /* RF_CHAN_60, */ + {64, true} + , /* RF_CHAN_64, */ + {100, true} + , /* RF_CHAN_100, */ + {104, true} + , /* RF_CHAN_104, */ + {108, true} + , /* RF_CHAN_108, */ + {112, true} + , /* RF_CHAN_112, */ + {116, true} + , /* RF_CHAN_116, */ + {120, true} + , /* RF_CHAN_120, */ + {124, true} + , /* RF_CHAN_124, */ + {128, true} + , /* RF_CHAN_128, */ + {132, true} + , /* RF_CHAN_132, */ + {136, true} + , /* RF_CHAN_136, */ + {140, true} + , /* RF_CHAN_140, */ + {144, true} + , /* RF_CHAN_144, */ + {149, true} + , /* RF_CHAN_149, */ + {153, true} + , /* RF_CHAN_153, */ + {157, true} + , /* RF_CHAN_157, */ + {161, true} + , /* RF_CHAN_161, */ + {165, true} + , /* RF_CHAN_165, */ +}; +#endif + +typedef struct { + uint16_t chStartNum; + uint32_t weight; +} sapAcsChannelInfo; + +sapAcsChannelInfo acs_ht40_channels5_g[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {44, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {60, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {108, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {124, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {140, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, + {157, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht80_channels[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht40_channels24_g[] = { + {1, SAP_ACS_WEIGHT_MAX}, + {2, SAP_ACS_WEIGHT_MAX}, + {3, SAP_ACS_WEIGHT_MAX}, + {4, SAP_ACS_WEIGHT_MAX}, + {9, SAP_ACS_WEIGHT_MAX}, +}; + +#define CHANNEL_165 165 + +/* rssi discount for channels in PCL */ +#define PCL_RSSI_DISCOUNT 10 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_n_add_channel() - checks and add given channel in sap context's + * avoid_channels_info struct + * @sap_ctx: sap context. + * @new_channel: channel to be added to sap_ctx's avoid ch info + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +bool +sap_check_n_add_channel(ptSapContext sap_ctx, + uint8_t new_channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == new_channel) + break; + + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = new_channel; + break; + } + } + if (i == sizeof(ie_info->channels)) + return false; + else + return true; +} +/** + * sap_check_n_add_overlapped_chnls() - checks & add overlapped channels + * to primary channel in 2.4Ghz band. + * @sap_ctx: sap context. + * @primary_chnl: primary channel to be avoided. + * + * sap_ctx contains sap_avoid_ch_info struct containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +static bool +sap_check_n_add_overlapped_chnls(ptSapContext sap_ctx, uint8_t primary_channel) +{ + uint8_t i = 0, j = 0, upper_chnl = 0, lower_chnl = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + /* + * if primary channel less than channel 1 or out of 2g band then + * no further process is required. return true in this case. + */ + if (primary_channel < CHANNEL_1 || primary_channel > CHANNEL_14) + return true; + + /* lower channel is one channel right before primary channel */ + lower_chnl = primary_channel - 1; + /* upper channel is one channel right after primary channel */ + upper_chnl = primary_channel + 1; + + /* lower channel needs to be non-zero, zero is not valid channel */ + if (lower_chnl > (CHANNEL_1 - 1)) { + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == lower_chnl) + break; + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = lower_chnl; + break; + } + } + } + /* upper channel needs to be atleast last channel in 2.4Ghz band */ + if (upper_chnl < (CHANNEL_14 + 1)) { + for (j = 0; j < sizeof(ie_info->channels); j++) { + if (ie_info->channels[j] == upper_chnl) + break; + if (ie_info->channels[j] == 0) { + ie_info->channels[j] = upper_chnl; + break; + } + } + } + if (i == sizeof(ie_info->channels) || j == sizeof(ie_info->channels)) + return false; + else + return true; +} + +/** + * sap_process_avoid_ie() - processes the detected Q2Q IE + * context's avoid_channels_info struct + * @hal: hal handle + * @sap_ctx: sap context. + * @scan_result: scan results for ACS scan. + * @spect_info: spectrum weights array to update + * + * Detection of Q2Q IE indicates presence of another MDM device with its AP + * operating in MCC mode. This function parses the scan results and processes + * the Q2Q IE if found. It then extracts the channels and populates them in + * sap_ctx struct. It also increases the weights of those channels so that + * ACS logic will avoid those channels in its selection algorithm. + * + * Return: void + */ +void sap_process_avoid_ie(tHalHandle hal, + ptSapContext sap_ctx, + tScanResultHandle scan_result, + tSapChSelSpectInfo *spect_info) +{ + uint32_t total_ie_len = 0; + uint8_t *temp_ptr = NULL; + uint8_t i = 0; + struct sAvoidChannelIE *avoid_ch_ie; + tCsrScanResultInfo *node = NULL; + tpAniSirGlobal mac_ctx = NULL; + tSapSpectChInfo *spect_ch = NULL; + + mac_ctx = PMAC_STRUCT(hal); + spect_ch = spect_info->pSpectCh; + node = sme_scan_result_get_first(hal, scan_result); + + while (node) { + total_ie_len = (node->BssDescriptor.length + + sizeof(uint16_t) + sizeof(uint32_t) - + sizeof(tSirBssDescription)); + temp_ptr = cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + SIR_MAC_QCOM_VENDOR_OUI, + SIR_MAC_QCOM_VENDOR_SIZE, + ((uint8_t *)&node->BssDescriptor.ieFields), + total_ie_len); + + if (temp_ptr) { + avoid_ch_ie = (struct sAvoidChannelIE *)temp_ptr; + if (avoid_ch_ie->type != QCOM_VENDOR_IE_MCC_AVOID_CH) + continue; + + sap_ctx->sap_detected_avoid_ch_ie.present = 1; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_DEBUG, + "Q2Q IE - avoid ch %d", + avoid_ch_ie->channel); + /* add this channel to to_avoid channel list */ + sap_check_n_add_channel(sap_ctx, + avoid_ch_ie->channel); + sap_check_n_add_overlapped_chnls(sap_ctx, + avoid_ch_ie->channel); + /* + * Mark weight of these channel present in IE to MAX + * so that ACS logic will to avoid thse channels + */ + for (i = 0; i < spect_info->numSpectChans; i++) + if (spect_ch[i].chNum == avoid_ch_ie->channel) { + /* + * weight is set more than max so that, + * in the case of other channels being + * assigned max weight due to noise, + * they may be preferred over channels + * with Q2Q IE. + */ + spect_ch[i].weight = SAP_ACS_WEIGHT_MAX + 1; + spect_ch[i].weight_copy = + SAP_ACS_WEIGHT_MAX + 1; + break; + } + } /* if (temp_ptr) */ + node = sme_scan_result_get_next(hal, scan_result); + } +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef FEATURE_WLAN_CH_AVOID +/*========================================================================== + FUNCTION sap_update_unsafe_channel_list + + DESCRIPTION + Function Undate unsafe channel list table + + DEPENDENCIES + NA. + + IN + SapContext pointer + + RETURN VALUE + NULL + ============================================================================*/ +#ifdef CONFIG_CNSS +void sap_update_unsafe_channel_list(ptSapContext pSapCtx) +{ + uint16_t i, j; + uint16_t unsafe_channel_list[NUM_20MHZ_RF_CHANNELS]; + uint16_t unsafe_channel_count = 0; + + /* Flush, default set all channel safe */ + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + safe_channels[i].isSafe = true; + } + + /* Try to find unsafe channel */ +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) || \ + defined(WLAN_FEATURE_MBSSID) + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + if (pSapCtx->dfs_ch_disable == true) { + if (CDS_IS_DFS_CH(safe_channels[i].channelNumber)) { + safe_channels[i].isSafe = false; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: DFS Ch %d is not safe in" + " Concurrent mode", + __func__, + safe_channels[i].channelNumber); + } + } + } +#endif + + cnss_get_wlan_unsafe_channel(unsafe_channel_list, + &unsafe_channel_count, + sizeof(unsafe_channel_list)); + + for (i = 0; i < unsafe_channel_count; i++) { + for (j = 0; j < NUM_20MHZ_RF_CHANNELS; j++) { + if (safe_channels[j].channelNumber == + unsafe_channel_list[i]) { + /* Found unsafe channel, update it */ + safe_channels[j].isSafe = false; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("CH %d is not safe"), + unsafe_channel_list[i]); + break; + } + } + } + + return; +} +#else +void sap_update_unsafe_channel_list(ptSapContext pSapCtx) +{ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Not implemented", __func__); + return; +} +#endif + +#endif /* FEATURE_WLAN_CH_AVOID */ + +/*========================================================================== + FUNCTION sap_cleanup_channel_list + + DESCRIPTION + Function sap_cleanup_channel_list frees up the memory allocated to the channel list. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + NULL + + RETURN VALUE + NULL + ============================================================================*/ + +void sap_cleanup_channel_list( +#ifdef WLAN_FEATURE_MBSSID + void *p_cds_gctx +#else + void +#endif + ) { +#ifndef WLAN_FEATURE_MBSSID + void *p_cds_gctx = cds_get_global_context(); +#endif + ptSapContext pSapCtx; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "Cleaning up the channel list structure"); + + if (NULL == p_cds_gctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "SAP Global Context is NULL"); + return; + } + + pSapCtx = CDS_GET_SAP_CB(p_cds_gctx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "SAP Context is NULL"); + return; + } + + pSapCtx->SapChnlList.numChannel = 0; + if (pSapCtx->SapChnlList.channelList) { + cdf_mem_free(pSapCtx->SapChnlList.channelList); + pSapCtx->SapChnlList.channelList = NULL; + } + + pSapCtx->SapAllChnlList.numChannel = 0; + if (pSapCtx->SapAllChnlList.channelList) { + cdf_mem_free(pSapCtx->SapAllChnlList.channelList); + pSapCtx->SapAllChnlList.channelList = NULL; + } +} + +/** + * sap_select_preferred_channel_from_channel_list() - to calc best cahnnel + * @best_chnl: best channel already calculated among all the chanels + * @sap_ctx: sap context + * @spectinfo_param: Pointer to tSapChSelSpectInfo structure + * + * This function calculates the best channel among the configured channel list. + * If channel list not configured then returns the best channel calculated + * among all the channel list. + * + * Return: uint8_t best channel + */ +uint8_t sap_select_preferred_channel_from_channel_list(uint8_t best_chnl, + ptSapContext sap_ctx, + tSapChSelSpectInfo *spectinfo_param) +{ + uint8_t i = 0; + + /* + * If Channel List is not Configured don't do anything + * Else return the Best Channel from the Channel List + */ + if ((NULL == sap_ctx->acs_cfg->ch_list) || + (NULL == spectinfo_param) || + (0 == sap_ctx->acs_cfg->ch_list_count)) + return best_chnl; + + if (best_chnl <= 0 || best_chnl > 252) + return SAP_CHANNEL_NOT_SELECTED; + + /* Select the best channel from allowed list */ + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) { + if (sap_ctx->acs_cfg->ch_list[i] == best_chnl) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "Best channel is: %d", + best_chnl); + return best_chnl; + } + } + + return SAP_CHANNEL_NOT_SELECTED; +} + +/*========================================================================== + FUNCTION sap_chan_sel_init + + DESCRIPTION + Function sap_chan_sel_init allocates the memory, intializes the + structures used by the channel selection algorithm + + DEPENDENCIES + NA. + + PARAMETERS + + IN + halHandle : Pointer to tHalHandle + *pSpectInfoParams : Pointer to tSapChSelSpectInfo structure + pSapCtx : Pointer to SAP Context + + RETURN VALUE + bool: Success or FAIL + + SIDE EFFECTS + ============================================================================*/ +bool sap_chan_sel_init(tHalHandle halHandle, + tSapChSelSpectInfo *pSpectInfoParams, ptSapContext pSapCtx) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint8_t *pChans = NULL; + uint16_t channelnum = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(halHandle); + bool chSafe = true; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t i; +#endif + uint32_t dfs_master_cap_enabled; + bool include_dfs_ch = true; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, "In %s", + __func__); + + pSpectInfoParams->numSpectChans = + pMac->scan.base_channels.numChannels; + + /* Allocate memory for weight computation of 2.4GHz */ + pSpectCh = + (tSapSpectChInfo *) cdf_mem_malloc((pSpectInfoParams->numSpectChans) + * sizeof(*pSpectCh)); + + if (pSpectCh == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s, CDF_MALLOC_ERR", __func__); + return eSAP_FALSE; + } + + cdf_mem_zero(pSpectCh, + (pSpectInfoParams->numSpectChans) * sizeof(*pSpectCh)); + + /* Initialize the pointers in the DfsParams to the allocated memory */ + pSpectInfoParams->pSpectCh = pSpectCh; + + pChans = pMac->scan.base_channels.channelList; + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) || defined(WLAN_FEATURE_MBSSID) + if (pSapCtx->dfs_ch_disable == true) + include_dfs_ch = false; +#endif + sme_cfg_get_int(halHandle, WNI_CFG_DFS_MASTER_ENABLED, + &dfs_master_cap_enabled); + if (dfs_master_cap_enabled == 0) + include_dfs_ch = false; + + /* Fill the channel number in the spectrum in the operating freq band */ + for (channelnum = 0; + channelnum < pSpectInfoParams->numSpectChans; + channelnum++, pChans++) { + chSafe = true; + + /* check if the channel is in NOL blacklist */ + if (sap_dfs_is_channel_in_nol_list(pSapCtx, *pChans, + PHY_SINGLE_CHANNEL_CENTERED)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is in NOL list", __func__, + *pChans); + chSafe = false; + continue; + } + + if (include_dfs_ch == false) { + if (CDS_IS_DFS_CH(*pChans)) { + chSafe = false; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, DFS Ch %d not considered for ACS", + __func__, *pChans); + continue; + } + } + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + if ((safe_channels[i].channelNumber == *pChans) && + (false == safe_channels[i].isSafe)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is not safe", __func__, + *pChans); + chSafe = false; + break; + } + } +#endif /* FEATURE_WLAN_CH_AVOID */ + + /* OFDM rates are not supported on channel 14 */ + if (*pChans == 14 && + eCSR_DOT11_MODE_11b != pSapCtx->csr_roamProfile.phyMode) { + pSpectCh++; + continue; + } + + if (true == chSafe) { + pSpectCh->chNum = *pChans; + pSpectCh->valid = eSAP_TRUE; + pSpectCh->rssiAgr = SOFTAP_MIN_RSSI; /* Initialise for all channels */ + pSpectCh->channelWidth = SOFTAP_HT20_CHANNELWIDTH; /* Initialise 20MHz for all the Channels */ + } + pSpectCh++; + } + return eSAP_TRUE; +} + +/*========================================================================== + FUNCTION sapweight_rssi_count + + DESCRIPTION + Function weightRssiCount calculates the channel weight due to rssi + and data count(here number of BSS observed) + + DEPENDENCIES + NA. + + PARAMETERS + + IN + rssi : Max signal strength receieved from a BSS for the channel + count : Number of BSS observed in the channel + + RETURN VALUE + uint32_t : Calculated channel weight based on above two + + SIDE EFFECTS + ============================================================================*/ +uint32_t sapweight_rssi_count(int8_t rssi, uint16_t count) +{ + int32_t rssiWeight = 0; + int32_t countWeight = 0; + uint32_t rssicountWeight = 0; + + /* Weight from RSSI */ + rssiWeight = SOFTAP_RSSI_WEIGHT * (rssi - SOFTAP_MIN_RSSI) + / (SOFTAP_MAX_RSSI - SOFTAP_MIN_RSSI); + + if (rssiWeight > SOFTAP_RSSI_WEIGHT) + rssiWeight = SOFTAP_RSSI_WEIGHT; + else if (rssiWeight < 0) + rssiWeight = 0; + + /* Weight from data count */ + countWeight = SOFTAP_COUNT_WEIGHT * (count - SOFTAP_MIN_COUNT) + / (SOFTAP_MAX_COUNT - SOFTAP_MIN_COUNT); + + if (countWeight > SOFTAP_COUNT_WEIGHT) + countWeight = SOFTAP_COUNT_WEIGHT; + + rssicountWeight = rssiWeight + countWeight; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, rssiWeight=%d, countWeight=%d, rssicountWeight=%d", + __func__, rssiWeight, countWeight, rssicountWeight); + + return rssicountWeight; +} + +/** + * sap_update_rssi_bsscount() - updates bss count and rssi effect. + * + * @pSpectCh: Channel Information + * @offset: Channel Offset + * @sap_24g: Channel is in 2.4G or 5G + * + * sap_update_rssi_bsscount updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +void sap_update_rssi_bsscount(tSapSpectChInfo *pSpectCh, int32_t offset, + bool sap_24g) +{ + tSapSpectChInfo *pExtSpectCh = NULL; + int32_t rssi, rsssi_effect; + + pExtSpectCh = (pSpectCh + offset); + if (pExtSpectCh != NULL) { + ++pExtSpectCh->bssCount; + switch (offset) { + case -1: + case 1: + rsssi_effect = sap_24g ? + SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND1_RSSI_EFFECT_PRIMARY; + break; + case -2: + case 2: + rsssi_effect = sap_24g ? + SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND2_RSSI_EFFECT_PRIMARY; + break; + case -3: + case 3: + rsssi_effect = sap_24g ? + SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND3_RSSI_EFFECT_PRIMARY; + break; + case -4: + case 4: + rsssi_effect = + SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY; + break; + default: + rsssi_effect = 0; + break; + } + + rssi = pSpectCh->rssiAgr + rsssi_effect; + if (IS_RSSI_VALID(pExtSpectCh->rssiAgr, rssi)) + pExtSpectCh->rssiAgr = rssi; + if (pExtSpectCh->rssiAgr < SOFTAP_MIN_RSSI) + pExtSpectCh->rssiAgr = SOFTAP_MIN_RSSI; + } +} + +/** + * sap_upd_chan_spec_params() - sap_upd_chan_spec_params + * updates channel parameters obtained from Beacon + * @pBeaconStruct Beacon strucutre populated by parse_beacon function + * @channelWidth Channel width + * @secondaryChannelOffset Secondary Channel Offset + * @vhtSupport If channel supports VHT + * @centerFreq Central frequency for the given channel. + * + * sap_upd_chan_spec_params updates the spectrum channels based on the + * pBeaconStruct obtained from Beacon IE + * + * Return: NA. + */ + +void sap_upd_chan_spec_params(tSirProbeRespBeacon *pBeaconStruct, + uint16_t *channelWidth, + uint16_t *secondaryChannelOffset, + uint16_t *vhtSupport, + uint16_t *centerFreq) +{ + if (NULL == pBeaconStruct) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("pBeaconStruct is NULL")); + return; + } + + if (pBeaconStruct->HTCaps.present && pBeaconStruct->HTInfo.present) { + *channelWidth = pBeaconStruct->HTCaps.supportedChannelWidthSet; + *secondaryChannelOffset = pBeaconStruct->HTInfo. + secondaryChannelOffset; + + if (pBeaconStruct->VHTOperation.present) { + *vhtSupport = pBeaconStruct->VHTOperation.present; + if (pBeaconStruct->VHTOperation.chanWidth > + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { + *channelWidth = eHT_CHANNEL_WIDTH_80MHZ; + *centerFreq = pBeaconStruct->VHTOperation. + chanCenterFreqSeg1; + } + } + } +} + +/** + * sap_interference_rssi_count_5G() - sap_interference_rssi_count + * considers the Adjacent channel rssi and + * data count(here number of BSS observed) + * @spect_ch: Channel Information + * @chan_width: Channel width parsed from beacon IE + * @sec_chan_offset: Secondary Channel Offset + * @center_freq: Central frequency for the given channel. + * @channel_id: channel_id + * + * sap_interference_rssi_count_5G considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: NA. + */ + +void sap_interference_rssi_count_5G(tSapSpectChInfo *spect_ch, + uint16_t chan_width, + uint16_t sec_chan_offset, + uint16_t center_freq, uint8_t channel_id) +{ + if (NULL == spect_ch) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("spect_ch is NULL")); + return; + } + + /* Updating the received ChannelWidth */ + if (spect_ch->channelWidth != chan_width) + spect_ch->channelWidth = chan_width; + /* If received ChannelWidth is other than HT20, + * we need to update the extension channel Params as well + * chan_width == 0, HT20 + * chan_width == 1, HT40 + * chan_width == 2, VHT80 + */ + + switch (spect_ch->channelWidth) { + case eHT_CHANNEL_WIDTH_40MHZ: /* HT40 */ + switch (sec_chan_offset) { + /* Above the Primary Channel */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sap_update_rssi_bsscount(spect_ch, 1, false); + break; + + /* Below the Primary channel */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sap_update_rssi_bsscount(spect_ch, -1, false); + break; + } + break; + case eHT_CHANNEL_WIDTH_80MHZ: /* VHT80 */ + if ((center_freq - channel_id) == 6) { + sap_update_rssi_bsscount(spect_ch, 1, false); + sap_update_rssi_bsscount(spect_ch, 2, false); + sap_update_rssi_bsscount(spect_ch, 3, false); + } else if ((center_freq - channel_id) == 2) { + sap_update_rssi_bsscount(spect_ch, -1, false); + sap_update_rssi_bsscount(spect_ch, 1, false); + sap_update_rssi_bsscount(spect_ch, 2, false); + } else if ((center_freq - channel_id) == -2) { + sap_update_rssi_bsscount(spect_ch, -2, false); + sap_update_rssi_bsscount(spect_ch, -1, false); + sap_update_rssi_bsscount(spect_ch, 1, false); + } else if ((center_freq - channel_id) == -6) { + sap_update_rssi_bsscount(spect_ch, -1, false); + sap_update_rssi_bsscount(spect_ch, -2, false); + sap_update_rssi_bsscount(spect_ch, -3, false); + } + break; + default: + break; + } +} + +/** + * sap_interference_rssi_count() - sap_interference_rssi_count + * considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * @spect_ch Channel Information + * + * sap_interference_rssi_count considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: None. + */ + +void sap_interference_rssi_count(tSapSpectChInfo *spect_ch) +{ + if (NULL == spect_ch) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: spect_ch is NULL", __func__); + return; + } + + switch (spect_ch->chNum) { + case CHANNEL_1: + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + sap_update_rssi_bsscount(spect_ch, 4, true); + break; + + case CHANNEL_2: + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + sap_update_rssi_bsscount(spect_ch, 4, true); + break; + case CHANNEL_3: + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + sap_update_rssi_bsscount(spect_ch, 4, true); + break; + case CHANNEL_4: + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + sap_update_rssi_bsscount(spect_ch, 4, true); + break; + + case CHANNEL_5: + case CHANNEL_6: + case CHANNEL_7: + case CHANNEL_8: + case CHANNEL_9: + case CHANNEL_10: + sap_update_rssi_bsscount(spect_ch, -4, true); + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + sap_update_rssi_bsscount(spect_ch, 4, true); + break; + + case CHANNEL_11: + sap_update_rssi_bsscount(spect_ch, -4, true); + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + sap_update_rssi_bsscount(spect_ch, 3, true); + break; + + case CHANNEL_12: + sap_update_rssi_bsscount(spect_ch, -4, true); + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + sap_update_rssi_bsscount(spect_ch, 2, true); + break; + + case CHANNEL_13: + sap_update_rssi_bsscount(spect_ch, -4, true); + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + sap_update_rssi_bsscount(spect_ch, 1, true); + break; + + case CHANNEL_14: + sap_update_rssi_bsscount(spect_ch, -4, true); + sap_update_rssi_bsscount(spect_ch, -3, true); + sap_update_rssi_bsscount(spect_ch, -2, true); + sap_update_rssi_bsscount(spect_ch, -1, true); + break; + + default: + break; + } +} + +/*========================================================================== + Function ch_in_pcl + + Description + Check if a channel is in the preferred channel list + + Parameters + sap_ctx SAP context pointer + channel input channel number + + Return Value + true: channel is in PCL + false: channel is not in PCL + ==========================================================================*/ +bool ch_in_pcl(ptSapContext sap_ctx, uint8_t channel) +{ + uint32_t i; + + for (i = 0; i < sap_ctx->acs_cfg->pcl_ch_count; i++) { + if (channel == sap_ctx->acs_cfg->pcl_channels[i]) + return true; + } + + return false; +} + +/*========================================================================== + FUNCTION sap_compute_spect_weight + + DESCRIPTION + Main function for computing the weight of each channel in the + spectrum based on the RSSI value of the BSSes on the channel + and number of BSS + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSpectInfoParams structure + halHandle : Pointer to HAL handle + pResult : Pointer to tScanResultHandle + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +void sap_compute_spect_weight(tSapChSelSpectInfo *pSpectInfoParams, + tHalHandle halHandle, tScanResultHandle pResult, + ptSapContext sap_ctx) +{ + int8_t rssi = 0; + uint8_t chn_num = 0; + uint8_t channel_id = 0; + + tCsrScanResultInfo *pScanResult; + tSapSpectChInfo *pSpectCh = pSpectInfoParams->pSpectCh; + uint32_t operatingBand; + uint16_t channelWidth; + uint16_t secondaryChannelOffset; + uint16_t centerFreq; + uint16_t vhtSupport; + uint32_t ieLen = 0; + tSirProbeRespBeacon *pBeaconStruct; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + + pBeaconStruct = cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == pBeaconStruct) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "Unable to allocate memory in sap_compute_spect_weight\n"); + return; + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Computing spectral weight", __func__); + + /** + * Soft AP specific channel weight calculation using DFS formula + */ + SET_ACS_BAND(operatingBand, sap_ctx); + + pScanResult = sme_scan_result_get_first(halHandle, pResult); + + while (pScanResult) { + pSpectCh = pSpectInfoParams->pSpectCh; + /* Defining the default values, so that any value will hold the default values */ + channelWidth = eHT_CHANNEL_WIDTH_20MHZ; + secondaryChannelOffset = PHY_SINGLE_CHANNEL_CENTERED; + vhtSupport = 0; + centerFreq = 0; + + if (pScanResult->BssDescriptor.ieFields != NULL) { + ieLen = + (pScanResult->BssDescriptor.length + + sizeof(uint16_t) + sizeof(uint32_t) - + sizeof(tSirBssDescription)); + cdf_mem_set((uint8_t *) pBeaconStruct, + sizeof(tSirProbeRespBeacon), 0); + + if ((sir_parse_beacon_ie + (pMac, pBeaconStruct, + (uint8_t *) (pScanResult->BssDescriptor.ieFields), + ieLen)) == eSIR_SUCCESS) { + sap_upd_chan_spec_params(pBeaconStruct, + &channelWidth, &secondaryChannelOffset, + &vhtSupport, ¢erFreq); + } + } + /* Processing for each tCsrScanResultInfo in the tCsrScanResult DLink list */ + for (chn_num = 0; chn_num < pSpectInfoParams->numSpectChans; + chn_num++) { + + /* + * if the Beacon has channel ID, use it other wise we will + * rely on the channelIdSelf + */ + if (pScanResult->BssDescriptor.channelId == 0) + channel_id = + pScanResult->BssDescriptor.channelIdSelf; + else + channel_id = + pScanResult->BssDescriptor.channelId; + + if (pSpectCh && (channel_id == pSpectCh->chNum)) { + if (pSpectCh->rssiAgr < + pScanResult->BssDescriptor.rssi) + pSpectCh->rssiAgr = + pScanResult->BssDescriptor.rssi; + + ++pSpectCh->bssCount; /* Increment the count of BSS */ + + /* + * Connsidering the Extension Channel + * only in a channels + */ + switch (operatingBand) { + case eCSR_DOT11_MODE_11a: + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, centerFreq, + channel_id); + break; + + case eCSR_DOT11_MODE_11g: + sap_interference_rssi_count(pSpectCh); + break; + + case eCSR_DOT11_MODE_abg: + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, centerFreq, + channel_id); + sap_interference_rssi_count(pSpectCh); + break; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, bssdes.ch_self=%d, bssdes.ch_ID=%d, bssdes.rssi=%d, SpectCh.bssCount=%d, pScanResult=%p, ChannelWidth %d, secondaryChanOffset %d, center frequency %d \n", + __func__, + pScanResult->BssDescriptor. + channelIdSelf, + pScanResult->BssDescriptor.channelId, + pScanResult->BssDescriptor.rssi, + pSpectCh->bssCount, pScanResult, + pSpectCh->channelWidth, + secondaryChannelOffset, centerFreq); + pSpectCh++; + break; + } else { + pSpectCh++; + } + } + + pScanResult = sme_scan_result_get_next(halHandle, pResult); + } + + /* Calculate the weights for all channels in the spectrum pSpectCh */ + pSpectCh = pSpectInfoParams->pSpectCh; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Spectrum Channels Weight", __func__); + + for (chn_num = 0; chn_num < (pSpectInfoParams->numSpectChans); + chn_num++) { + + /* + rssi : Maximum received signal strength among all BSS on that channel + bssCount : Number of BSS on that channel + */ + + rssi = (int8_t) pSpectCh->rssiAgr; + if (ch_in_pcl(sap_ctx, chn_num)) + rssi -= PCL_RSSI_DISCOUNT; + + pSpectCh->weight = + SAPDFS_NORMALISE_1000 * sapweight_rssi_count(rssi, + pSpectCh-> + bssCount); + pSpectCh->weight_copy = pSpectCh->weight; + + /* ------ Debug Info ------ */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Chan=%d Weight= %d rssiAgr=%d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, pSpectCh->bssCount); + /* ------ Debug Info ------ */ + pSpectCh++; + } + cdf_mem_free(pBeaconStruct); +} + +/*========================================================================== + FUNCTION sap_chan_sel_exit + + DESCRIPTION + Exit function for free out the allocated memory, to be called + at the end of the dfsSelectChannel function + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +void sap_chan_sel_exit(tSapChSelSpectInfo *pSpectInfoParams) +{ + /* Free all the allocated memory */ + cdf_mem_free(pSpectInfoParams->pSpectCh); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight + + DESCRIPTION + Funtion to sort the channels with the least weight first for 20MHz channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +void sap_sort_chl_weight(tSapChSelSpectInfo *pSpectInfoParams) +{ + tSapSpectChInfo temp; + + tSapSpectChInfo *pSpectCh = NULL; + uint32_t i = 0, j = 0, minWeightIndex = 0; + + pSpectCh = pSpectInfoParams->pSpectCh; + for (i = 0; i < pSpectInfoParams->numSpectChans; i++) { + minWeightIndex = i; + for (j = i + 1; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + cdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + cdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + cdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +} + +/** + * sap_sort_chl_weight_ht80() - to sort the channels with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Funtion to sort the channels with the least weight first for HT80 channels + * + * Return: none + */ +void sap_sort_chl_weight_ht80(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j, n; + tSapSpectChInfo *pSpectInfo; + uint8_t minIdx; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* for each HT80 channel, calculate the combined weight of the + four 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht80_channels); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht80_channels[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!(((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) && + ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) && + ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same HT80 width + */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 4) == + pSpectInfo[j + 1].chNum) + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) + pSpectInfo[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) + pSpectInfo[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 4; + continue; + } + /*found the channel, add the 4 adjacent channels' weight */ + acs_ht80_channels[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight + pSpectInfo[j + 2].weight + + pSpectInfo[j + 3].weight; + /* find best channel among 4 channels as the primary channel */ + if ((pSpectInfo[j].weight + pSpectInfo[j + 1].weight) < + (pSpectInfo[j + 2].weight + pSpectInfo[j + 3].weight)) { + /* lower 2 channels are better choice */ + if (pSpectInfo[j].weight < pSpectInfo[j + 1].weight) + minIdx = 0; + else + minIdx = 1; + } else if (pSpectInfo[j + 2].weight <= + pSpectInfo[j + 3].weight) { + /* upper 2 channels are better choice */ + minIdx = 2; + } else { + minIdx = 3; + } + + /* + * set all 4 channels to max value first, then reset the + * best channel as the selected primary channel, update its + * weightage with the combined weight value + */ + for (n = 0; n < 4; n++) + pSpectInfo[j + n].weight = SAP_ACS_WEIGHT_MAX * 4; + + pSpectInfo[j + minIdx].weight = acs_ht80_channels[i].weight; + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (CHANNEL_165 == pSpectInfo[j].chNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + break; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Weight= %d rssi=%d bssCount=%d"), + pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } +} + +/** + * sap_sort_chl_weight_ht40_24_g() - to sort channel with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Funtion to sort the channels with the least weight first for HT40 channels + * + * Return: none + */ +void sap_sort_chl_weight_ht40_24_g(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + uint32_t tmpWeight1, tmpWeight2; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* + * for each HT40 channel, calculate the combined weight of the + * two 20MHz weight + */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels24_g); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels24_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 4].chNum)) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + continue; + } + /* + * check if there is another channel combination possiblity + * e.g., {1, 5} & {5, 9} + */ + if ((pSpectInfo[j + 4].chNum + 4) == pSpectInfo[j + 8].chNum) { + /* need to compare two channel pairs */ + tmpWeight1 = pSpectInfo[j].weight + + pSpectInfo[j + 4].weight; + tmpWeight2 = pSpectInfo[j + 4].weight + + pSpectInfo[j + 8].weight; + if (tmpWeight1 <= tmpWeight2) { + if (pSpectInfo[j].weight <= + pSpectInfo[j + 4].weight) { + pSpectInfo[j].weight = + tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = + tmpWeight1; + /* for secondary channel selection */ + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } else { + if (pSpectInfo[j + 4].weight <= + pSpectInfo[j + 8].weight) { + pSpectInfo[j + 4].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + /* for secondary channel selection */ + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + } else { + pSpectInfo[j + 8].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } else { + tmpWeight1 = pSpectInfo[j].weight + + pSpectInfo[j + 4].weight; + if (pSpectInfo[j].weight <= + pSpectInfo[j + 4].weight) { + pSpectInfo[j].weight = tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = tmpWeight1; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_ht40_5_g + + DESCRIPTION + Funtion to sort the channels with the least weight first for HT40 channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +void sap_sort_chl_weight_ht40_5_g(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /*for each HT40 channel, calculate the combined weight of the + two 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels5_g); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels5_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + /* found the channel, add the two adjacent channels' weight */ + if ((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) { + acs_ht40_channels5_g[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight; + /* select better of the adjact channel as the primary channel */ + if (pSpectInfo[j].weight <= pSpectInfo[j + 1].weight) { + pSpectInfo[j].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 1].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + + } else + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + + /* avoid channel 165 by setting its weight to max */ + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (CHANNEL_165 == pSpectInfo[j].chNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + break; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + + sap_sort_chl_weight(pSpectInfoParams); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_all + + DESCRIPTION + Funtion to sort the channels with the least weight first + + DEPENDENCIES + NA. + + PARAMETERS + + IN + ptSapContext : Pointer to the ptSapContext structure + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +void sap_sort_chl_weight_all(ptSapContext pSapCtx, + tSapChSelSpectInfo *pSpectInfoParams, + uint32_t operatingBand) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint32_t j = 0; +#ifndef SOFTAP_CHANNEL_RANGE + uint32_t i = 0; +#endif + + pSpectCh = pSpectInfoParams->pSpectCh; +#ifdef SOFTAP_CHANNEL_RANGE + + switch (pSapCtx->acs_cfg->ch_width) { + case CH_WIDTH_40MHZ: + if (eCSR_DOT11_MODE_11g == operatingBand) + sap_sort_chl_weight_ht40_24_g(pSpectInfoParams); + else if (eCSR_DOT11_MODE_11a == operatingBand) + sap_sort_chl_weight_ht40_5_g(pSpectInfoParams); + else { + sap_sort_chl_weight_ht40_24_g(pSpectInfoParams); + sap_sort_chl_weight_ht40_5_g(pSpectInfoParams); + } + sap_sort_chl_weight(pSpectInfoParams); + break; + + case CH_WIDTH_80MHZ: + sap_sort_chl_weight_ht80(pSpectInfoParams); + break; + + case CH_WIDTH_20MHZ: + default: + /* Sorting the channels as per weights as 20MHz channels */ + sap_sort_chl_weight(pSpectInfoParams); + } + +#else + /* Sorting the channels as per weights */ + for (i = 0; i < SPECT_24GHZ_CH_COUNT; i++) { + minWeightIndex = i; + for (j = i + 1; j < SPECT_24GHZ_CH_COUNT; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + cdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + cdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + cdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +#endif + + /* For testing */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Sorted Spectrum Channels Weight", __func__); + pSpectCh = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, pSpectCh->bssCount); + pSpectCh++; + } + +} + +/*========================================================================== + FUNCTION sap_filter_over_lap_ch + + DESCRIPTION + return true if ch is acceptable. + This function will decide if we will filter over lap channel or not. + + DEPENDENCIES + shall called after ap start. + + PARAMETERS + + IN + pSapCtx : Pointer to ptSapContext. + chNum : Filter channel number. + + RETURN VALUE + bool : true if channel is accepted. + + SIDE EFFECTS + ============================================================================*/ +bool sap_filter_over_lap_ch(ptSapContext pSapCtx, uint16_t chNum) +{ + if (pSapCtx->enableOverLapCh) + return eSAP_TRUE; + else if ((chNum == CHANNEL_1) || + (chNum == CHANNEL_6) || (chNum == CHANNEL_11)) + return eSAP_TRUE; + + return eSAP_FALSE; +} + +/*========================================================================== + FUNCTION sap_select_channel + + DESCRIPTION + Runs a algorithm to select the best channel to operate in based on BSS + rssi and bss count on each channel + + DEPENDENCIES + NA. + + PARAMETERS + + IN + halHandle : Pointer to HAL handle + pResult : Pointer to tScanResultHandle + + RETURN VALUE + uint8_t : Success - channel number, Fail - zero + + SIDE EFFECTS + ============================================================================*/ +uint8_t sap_select_channel(tHalHandle halHandle, ptSapContext pSapCtx, + tScanResultHandle pScanResult) +{ + /* DFS param object holding all the data req by the algo */ + tSapChSelSpectInfo oSpectInfoParams = { NULL, 0 }; + tSapChSelSpectInfo *pSpectInfoParams = &oSpectInfoParams; /* Memory? NB */ + uint8_t bestChNum = SAP_CHANNEL_NOT_SELECTED; +#ifdef FEATURE_WLAN_CH_AVOID + uint8_t i; + uint8_t firstSafeChannelInRange = SAP_CHANNEL_NOT_SELECTED; +#endif +#ifdef SOFTAP_CHANNEL_RANGE + uint32_t startChannelNum; + uint32_t endChannelNum; + uint32_t operatingBand = 0; + uint32_t tmpChNum; + uint8_t count; +#endif + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Running SAP Ch Select", __func__); + +#ifdef FEATURE_WLAN_CH_AVOID + sap_update_unsafe_channel_list(pSapCtx); +#endif + + if (NULL == pScanResult) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: No external AP present\n", __func__); + +#ifndef SOFTAP_CHANNEL_RANGE + return bestChNum; +#else + startChannelNum = pSapCtx->acs_cfg->start_ch; + endChannelNum = pSapCtx->acs_cfg->end_ch; + + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: start - end: %d - %d\n", __func__, + startChannelNum, endChannelNum); + +#ifndef FEATURE_WLAN_CH_AVOID /* FEATURE_WLAN_CH_AVOID NOT defined case */ + pSapCtx->acs_cfg->pri_ch = startChannelNum; + pSapCtx->acs_cfg->ht_sec_ch = 0; + /* pick the first channel in configured range */ + return startChannelNum; +#else /* FEATURE_WLAN_CH_AVOID defined */ + + /* get a channel in PCL and within the range */ + for (i = 0; i < pSapCtx->acs_cfg->pcl_ch_count; i++) { + if ((pSapCtx->acs_cfg->pcl_channels[i] >= + startChannelNum) + && (pSapCtx->acs_cfg->pcl_channels[i] <= + endChannelNum)) { + firstSafeChannelInRange = + pSapCtx->acs_cfg->pcl_channels[i]; + break; + } + } + if (SAP_CHANNEL_NOT_SELECTED != firstSafeChannelInRange) + return firstSafeChannelInRange; + + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + if ((safe_channels[i].channelNumber >= startChannelNum) + && (safe_channels[i].channelNumber <= + endChannelNum)) { + CHANNEL_STATE channel_type = + cds_get_channel_state(safe_channels[i]. + channelNumber); + + if ((channel_type == CHANNEL_STATE_DISABLE) || + (channel_type == CHANNEL_STATE_INVALID)) + continue; + + if (safe_channels[i].isSafe == true) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: channel %d in the configuration is safe\n", + __func__, + safe_channels[i]. + channelNumber); + firstSafeChannelInRange = + safe_channels[i].channelNumber; + break; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: channel %d in the configuration is unsafe\n", + __func__, + safe_channels[i].channelNumber); + } + } + + /* if no channel selected return SAP_CHANNEL_NOT_SELECTED */ + return firstSafeChannelInRange; +#endif /* !FEATURE_WLAN_CH_AVOID */ +#endif /* SOFTAP_CHANNEL_RANGE */ + } + + /* Initialize the structure pointed by pSpectInfoParams */ + if (sap_chan_sel_init(halHandle, pSpectInfoParams, pSapCtx) != eSAP_TRUE) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s, Ch Select initialization failed", __func__); + return SAP_CHANNEL_NOT_SELECTED; + } + /* Compute the weight of the entire spectrum in the operating band */ + sap_compute_spect_weight(pSpectInfoParams, halHandle, pScanResult, + pSapCtx); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* process avoid channel IE to collect all channels to avoid */ + sap_process_avoid_ie(halHandle, pSapCtx, pScanResult, pSpectInfoParams); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef SOFTAP_CHANNEL_RANGE + startChannelNum = pSapCtx->acs_cfg->start_ch; + endChannelNum = pSapCtx->acs_cfg->end_ch; + SET_ACS_BAND(operatingBand, pSapCtx); + + pSapCtx->acsBestChannelInfo.channelNum = 0; + pSapCtx->acsBestChannelInfo.weight = SAP_ACS_WEIGHT_MAX; + + /* Sort the channel list as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(pSapCtx, pSpectInfoParams, operatingBand); + + /*Loop till get the best channel in the given range */ + for (count = 0; count < pSpectInfoParams->numSpectChans; count++) { + if ((startChannelNum <= pSpectInfoParams->pSpectCh[count].chNum) + && (endChannelNum >= + pSpectInfoParams->pSpectCh[count].chNum)) { + if (bestChNum == SAP_CHANNEL_NOT_SELECTED) { + bestChNum = + pSpectInfoParams->pSpectCh[count].chNum; + /* check if bestChNum is in preferred channel list */ + bestChNum = + sap_select_preferred_channel_from_channel_list + (bestChNum, pSapCtx, pSpectInfoParams); + if (bestChNum == SAP_CHANNEL_NOT_SELECTED) { + /* not in preferred channel list, go to next best channel */ + continue; + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* Weight of the channels(device's AP is + * operating) increased to MAX+1 so that they + * will be choosen only when there is no other + * best channel to choose + */ + if (sap_check_in_avoid_ch_list(pSapCtx, + bestChNum)) { + bestChNum = SAP_CHANNEL_NOT_SELECTED; + continue; + } +#endif + + pSapCtx->acsBestChannelInfo.channelNum = + bestChNum; + pSapCtx->acsBestChannelInfo.weight = + pSpectInfoParams-> + pSpectCh[count]. + weight_copy; + } + + if (bestChNum != SAP_CHANNEL_NOT_SELECTED) { + if (operatingBand == eCSR_DOT11_MODE_11g) { + /* Give preference to Non-overlap channels */ + if (sap_filter_over_lap_ch(pSapCtx, + pSpectInfoParams-> + pSpectCh[count]. + chNum)) { + tmpChNum = + pSpectInfoParams-> + pSpectCh[count].chNum; + tmpChNum = + sap_select_preferred_channel_from_channel_list + (tmpChNum, pSapCtx, + pSpectInfoParams); + if (tmpChNum != + SAP_CHANNEL_NOT_SELECTED) { + bestChNum = tmpChNum; + break; + } + } + } + } + } + } +#else + /* Sort the channel list as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(pSapCtx, halHandle, pSpectInfoParams); + /* Get the first channel in sorted array as best 20M Channel */ + bestChNum = (uint8_t) pSpectInfoParams->pSpectCh[0].chNum; + /* Select Best Channel from Channel List if Configured */ + bestChNum = sap_select_preferred_channel_from_channel_list(bestChNum, + pSapCtx, + pSpectInfoParams); +#endif + + /** in case the best channel seleted is not in PCL and there is another + * channel which has same weightage and is in PCL, choose the one in + * PCL + */ + for (count = 0; count < pSpectInfoParams->numSpectChans; count++) { + /** check if a pcl channel has the same weightage + * as the best channel + */ + if (ch_in_pcl(pSapCtx, pSpectInfoParams->pSpectCh[count].chNum) + && (pSpectInfoParams->pSpectCh[count].weight == + pSapCtx->acsBestChannelInfo.weight)) { + if (sap_select_preferred_channel_from_channel_list( + pSpectInfoParams->pSpectCh[count].chNum, + pSapCtx, pSpectInfoParams) == + SAP_CHANNEL_NOT_SELECTED) + continue; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (sap_check_in_avoid_ch_list(pSapCtx, bestChNum)) + continue; +#endif + bestChNum = pSpectInfoParams->pSpectCh[count].chNum; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + "change best channel to %d in PCL", + bestChNum); + break; + } + } + + pSapCtx->acs_cfg->pri_ch = bestChNum; + /* determine secondary channel for 2.4G channel 5, 6, 7 in HT40 */ + if ((operatingBand == eCSR_DOT11_MODE_11g) && + (pSapCtx->acs_cfg->ch_width == CH_WIDTH_40MHZ)) { + if ((bestChNum >= 5) && (bestChNum <= 7)) { + int weight_below, weight_above, i; + tSapSpectChInfo *pspect_info; + + weight_below = weight_above = SAP_ACS_WEIGHT_MAX; + pspect_info = pSpectInfoParams->pSpectCh; + for (i = 0; i < pSpectInfoParams->numSpectChans; + i++) { + if (pspect_info[i].chNum == (bestChNum - 4)) + weight_below = pspect_info[i].weight; + + if (pspect_info[i].chNum == (bestChNum + 4)) + weight_above = pspect_info[i].weight; + } + + if (weight_below < weight_above) + pSapCtx->acs_cfg->ht_sec_ch = + pSapCtx->acs_cfg->pri_ch - 4; + else + pSapCtx->acs_cfg->ht_sec_ch = + pSapCtx->acs_cfg->pri_ch + 4; + } else if (bestChNum >= 1 && bestChNum <= 4) { + pSapCtx->acs_cfg->ht_sec_ch = + pSapCtx->acs_cfg->pri_ch + 4; + } else if (bestChNum >= 8 && bestChNum <= 13) { + pSapCtx->acs_cfg->ht_sec_ch = + pSapCtx->acs_cfg->pri_ch - 4; + } else if (bestChNum == 14) { + pSapCtx->acs_cfg->ht_sec_ch = 0; + } + pSapCtx->secondary_ch = pSapCtx->acs_cfg->ht_sec_ch; + } + /* Free all the allocated memory */ + sap_chan_sel_exit(pSpectInfoParams); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Running SAP Ch select Completed, Ch=%d", __func__, + bestChNum); + if (bestChNum > 0 && bestChNum <= 252) + return bestChNum; + else + return SAP_CHANNEL_NOT_SELECTED; +} diff --git a/core/sap/src/sap_ch_select.h b/core/sap/src/sap_ch_select.h new file mode 100644 index 0000000000..abefd5266b --- /dev/null +++ b/core/sap/src/sap_ch_select.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SAP_CH_SELECT_H) +#define __SAP_CH_SELECT_H + +/*=========================================================================== + + sapChSelect.h + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +/*-------------------------------------------------------------------------- + defines and enum + --------------------------------------------------------------------------*/ + +#define SPECT_24GHZ_CH_COUNT (11) /* USA regulatory domain */ +#define SAPDFS_NORMALISE_1000 (1000/9) /* Case of spec20 with channel diff = 0 */ +/* Gen 5 values + #define SOFTAP_MIN_RSSI (-85) + #define SOFTAP_MAX_RSSI (-45) + */ +#define SOFTAP_MIN_RSSI (-100) +#define SOFTAP_MAX_RSSI (0) +#define SOFTAP_MIN_COUNT (0) +#define SOFTAP_MAX_COUNT (60) +#define SOFTAP_RSSI_WEIGHT (20) +#define SOFTAP_COUNT_WEIGHT (20) + +#define SAP_DEFAULT_24GHZ_CHANNEL (6) +#define SAP_DEFAULT_5GHZ_CHANNEL (40) +#define SAP_CHANNEL_NOT_SELECTED (0) + +#define SOFTAP_HT20_CHANNELWIDTH 0 +#define SAP_SUBBAND1_RSSI_EFFECT_PRIMARY (-20) /* In HT40/VHT80, Effect of primary Channel RSSi on Subband1 */ +#define SAP_SUBBAND2_RSSI_EFFECT_PRIMARY (-30) /* In VHT80, Effect of primary Channel RSSI on Subband2 */ +#define SAP_SUBBAND3_RSSI_EFFECT_PRIMARY (-40) /* In VHT80, Effect of Primary Channel RSSI on Subband3 */ + +#define SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-10) /* In 2.4GHZ, Effect of Primary Channel RSSI on First Overlapping Channel */ +#define SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-20) /* In 2.4GHZ, Effect of Primary Channel RSSI on Second Overlapping Channel */ +#define SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-30) /* In 2.4GHZ, Effect of Primary Channel RSSI on Third Overlapping Channel */ +#define SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-40) /* In 2.4GHZ, Effect of Primary Channel RSSI on Fourth Overlapping Channel */ + +typedef enum { + CHANNEL_1 = 1, + CHANNEL_2, + CHANNEL_3, + CHANNEL_4, + CHANNEL_5, + CHANNEL_6, + CHANNEL_7, + CHANNEL_8, + CHANNEL_9, + CHANNEL_10, + CHANNEL_11, + CHANNEL_12, + CHANNEL_13, + CHANNEL_14 +} tSapChannel; + +#define MAX_80MHZ_BANDS 6 +#define SAP_80MHZ_MASK 0x0F +#define SAP_40MHZ_MASK_L 0x03 +#define SAP_40MHZ_MASK_H 0x0C + +/* + * structs for holding channel bonding bitmap + * used for finding new channel when SAP is on + * DFS channel and radar is detected. + */ +typedef struct sChannelBondingInfo { + uint8_t channelMap:4; + uint8_t rsvd:4; + uint8_t startChannel; +} tChannelBondingInfo; + +typedef struct __chan_bonding_bitmap { + tChannelBondingInfo chanBondingSet[MAX_80MHZ_BANDS]; +} chan_bonding_bitmap; + +/** + * Structure holding information of each channel in the spectrum, + * it contains the channel number, the computed weight + */ +typedef struct sChannelInfo { + uint8_t channel; + bool valid; /* if the channel is valid to be picked as new channel */ +} tChannelInfo; + +typedef struct sAll5GChannelList { + uint8_t numChannel; + tChannelInfo *channelList; +} tAll5GChannelList; + +typedef struct sSapChannelListInfo { + uint8_t numChannel; + uint8_t *channelList; +} tSapChannelListInfo; + +typedef struct { + uint16_t chNum; /* Channel Number */ + uint16_t channelWidth; /* Channel Width */ + uint16_t bssCount; /* bss found in scanresult for this channel */ + int32_t rssiAgr; /* Max value of rssi among all BSS(es) from scanresult for this channel */ + uint32_t weight; /* Weightage of this channel */ + uint32_t weight_copy; /* copy of the orignal weight */ + bool valid; /* Is this a valid center frequency for regulatory domain */ +} tSapSpectChInfo; /* tDfsSpectChInfo; */ + +/** + * Structure holding all the information required to make a + * decision for the best operating channel based on dfs formula + */ + +typedef struct { + tSapSpectChInfo *pSpectCh; /* tDfsSpectChInfo *pSpectCh; // Ptr to the channels in the entire spectrum band */ + uint8_t numSpectChans; /* Total num of channels in the spectrum */ +} tSapChSelSpectInfo; /* tDfsChSelParams; */ + +/** + * Structure for channel weight calculation parameters + */ +typedef struct sSapChSelParams { + void *pSpectInfoParams; /**pDfsParams; // Filled with tSapChSelSpectInfo */ + uint16_t numChannels; +} tSapChSelParams; + +#define SAP_TX_LEAKAGE_THRES 310 +#define SAP_TX_LEAKAGE_MAX 1000 +#define SAP_TX_LEAKAGE_MIN 200 + +/* + * This define is used to block additional channels + * based on the new data gathered on auto platforms + * and to differentiate the leakage data among different + * platforms. + */ + +#define SAP_TX_LEAKAGE_AUTO_MIN 210 + +typedef struct sSapTxLeakInfo { + uint8_t leak_chan; /* leak channel */ + uint32_t leak_lvl; /* tx leakage lvl */ +} tSapTxLeakInfo; + +typedef struct sSapChanMatrixInfo { + uint8_t channel; /* channel to switch from */ + tSapTxLeakInfo chan_matrix[RF_CHAN_144 - RF_CHAN_36 + 1]; +} tSapChanMatrixInfo; + +#endif /* if !defined __SAP_CH_SELECT_H */ diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c new file mode 100644 index 0000000000..3d2021e6de --- /dev/null +++ b/core/sap/src/sap_fsm.c @@ -0,0 +1,4754 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p F s m . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP Finite + State Machine modules + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "sap_internal.h" +/* Pick up the SME API definitions */ +#include "sme_api.h" +/* Pick up the PMC API definitions */ +#include "cds_utils.h" +#include "cds_ieee80211_common_i.h" +#include "cds_reg_service.h" +#include "cdf_util.h" +#include "cds_concurrency.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_CH_AVOID +extern sapSafeChannelType safe_channels[]; +#endif /* FEATURE_WLAN_CH_AVOID */ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION +/* + * TODO: At present SAP Channel leakage matrix for ch 144 + * is not available from system's team. So to play it safe + * and avoid crash if channel 144 is request, in following + * matix channel 144 is added such that it will cause code + * to avoid selecting channel 144. + * + * THESE ENTRIES SHOULD BE REPLACED WITH CORRECT VALUES AS + * PROVIDED BY SYSTEM'S TEAM. + */ + +/* channel tx leakage table - ht80 */ +tSapChanMatrixInfo ht80_chan[] = { + {52, + {{36, 148}, {40, 199}, + {44, 193}, {48, 197}, + {52, SAP_TX_LEAKAGE_MIN}, {56, 153}, + {60, 137}, {64, 134}, + {100, 358}, {104, 350}, + {108, 404}, {112, 344}, + {116, 424}, {120, 429}, + {124, 437}, {128, 435}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + + {56, + {{36, 171}, {40, 178}, + {44, 171}, {48, 178}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, 280}, + {100, 351}, {104, 376}, + {108, 362}, {112, 362}, + {116, 403}, {120, 397}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, 156}, {40, 146}, + {44, SAP_TX_LEAKAGE_MIN}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 180}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 376}, {104, 360}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, 395}, {120, 399}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, 217}, {40, 221}, + {44, SAP_TX_LEAKAGE_MIN}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 176}, {56, 176}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 384}, {104, 390}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, 375}, {120, 374}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 357}, {40, 326}, + {44, 321}, {48, 326}, + {52, 378}, {56, 396}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, 196}, {112, 116}, + {116, 166}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {104, + {{36, 325}, {40, 325}, + {44, 305}, {48, 352}, + {52, 411}, {56, 411}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, 460}, + {116, 198}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {108, + {{36, 304}, {40, 332}, + {44, 310}, {48, 335}, + {52, 431}, {56, 391}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 280}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 185}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {112, + {{36, 327}, {40, 335}, + {44, 331}, {48, 345}, + {52, 367}, {56, 401}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 131}, {104, 132}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 189}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {116, + {{36, 384}, {40, 372}, + {44, 389}, {48, 396}, + {52, 348}, {56, 336}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 172}, {104, 169}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {120, + {{36, 395}, {40, 419}, + {44, 439}, {48, 407}, + {52, 321}, {56, 334}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 134}, {104, 186}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 159}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {124, + {{36, 469}, {40, 433}, + {44, 434}, {48, 435}, + {52, 332}, {56, 345}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 146}, {104, 177}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 350}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 138}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 408}, {40, 434}, + {44, 449}, {48, 444}, + {52, 341}, {56, 374}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 205}, {104, 208}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 142}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, +}; + +/* channel tx leakage table - ht40 */ +tSapChanMatrixInfo ht40_chan[] = { + {52, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, 230}, {48, 230}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_AUTO_MIN}, {64, SAP_TX_LEAKAGE_AUTO_MIN}, + {100, 625}, {104, 323}, + {108, 646}, {112, 646}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {56, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 611}, {104, 611}, + {108, 617}, {112, 617}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 190}, {56, 190}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 608}, {104, 608}, + {108, 623}, {112, 623}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 295}, {56, 295}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 594}, {104, 594}, + {108, 625}, {112, 625}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 618}, {40, 618}, + {44, 604}, {48, 604}, + {52, 596}, {56, 596}, + {60, 584}, {64, 584}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, 299}, {112, 299}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 538}, {136, 538}, + {140, 598}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {104, + {{36, 636}, {40, 636}, + {44, 601}, {48, 601}, + {52, 616}, {56, 616}, + {60, 584}, {64, 584}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 553}, {136, 553}, + {140, 568}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {108, + {{36, 600}, {40, 600}, + {44, 627}, {48, 627}, + {52, 611}, {56, 611}, + {60, 611}, {64, 611}, + {100, 214}, {104, 214}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, 534}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {112, + {{36, 645}, {40, 645}, + {44, 641}, {48, 641}, + {52, 618}, {56, 618}, + {60, 612}, {64, 612}, + {100, 293}, {104, 293}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, 521}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {116, + {{36, 661}, {40, 661}, + {44, 624}, {48, 624}, + {52, 634}, {56, 634}, + {60, 611}, {64, 611}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, 217}, {112, 217}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {120, + {{36, 667}, {40, 667}, + {44, 645}, {48, 645}, + {52, 633}, {56, 633}, + {60, 619}, {64, 619}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, 291}, {112, 291}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {124, + {{36, 676}, {40, 676}, + {44, 668}, {48, 668}, + {52, 595}, {56, 595}, + {60, 622}, {64, 622}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, 225}, {120, 225}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 678}, {40, 678}, + {44, 664}, {48, 664}, + {52, 651}, {56, 651}, + {60, 643}, {64, 643}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, 293}, {120, 293}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, 689}, {40, 689}, + {44, 669}, {48, 669}, + {52, 662}, {56, 662}, + {60, 609}, {64, 609}, + {100, 538}, {104, 538}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, 247}, {128, 247}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, 703}, {40, 703}, + {44, 688}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 671}, {56, 671}, + {60, 658}, {64, 658}, + {100, 504}, {104, 504}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, 289}, {128, 289}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, 695}, {40, 695}, + {44, 684}, {48, 684}, + {52, 664}, {56, 664}, + {60, 658}, {64, 658}, + {100, 601}, {104, 601}, + {108, 545}, {112, 545}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 262}, {136, 262}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + +}; + +/* channel tx leakage table - ht20 */ +tSapChanMatrixInfo ht20_chan[] = { + {52, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, 286}, + {44, 225}, {48, 121}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, 300}, {64, SAP_TX_LEAKAGE_AUTO_MIN}, + {100, 637}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {56, + {{36, 468}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, 206}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, 507}, {40, 440}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, 313}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, 516}, {40, 520}, + {44, 506}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 301}, {56, 258}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 620}, {104, 617}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 616}, {40, 601}, + {44, 604}, {48, 589}, + {52, 612}, {56, 592}, + {60, 590}, {64, 582}, + {100, SAP_TX_LEAKAGE_MIN}, {104, 131}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, 522}, + {124, 571}, {128, 589}, + {132, 593}, {136, 598}, + {140, 594}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {104, + {{36, 622}, {40, 624}, + {44, 618}, {48, 610}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, 463}, + {116, 483}, {120, 503}, + {124, 523}, {128, 565}, + {132, 570}, {136, 588}, + {140, 585}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {108, + {{36, 620}, {40, 638}, + {44, 611}, {48, 614}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 477}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 477}, {120, 497}, + {124, 517}, {128, 537}, + {132, 557}, {136, 577}, + {140, 603}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {112, + {{36, 636}, {40, 623}, + {44, 638}, {48, 628}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, 606}, + {100, 501}, {104, 481}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, 481}, + {124, 501}, {128, 421}, + {132, 541}, {136, 561}, + {140, 583}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {116, + {{36, 646}, {40, 648}, + {44, 633}, {48, 634}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, 615}, {64, 594}, + {100, 575}, {104, 554}, + {108, 534}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, 534}, {136, 554}, + {140, 574}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {120, + {{36, 643}, {40, 649}, + {44, 654}, {48, 629}, + {52, SAP_TX_LEAKAGE_MAX}, {56, 621}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 565}, {104, 545}, + {108, 525}, {112, 505}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 505}, + {132, 525}, {136, 545}, + {140, 565}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {124, + {{36, 638}, {40, 657}, + {44, 663}, {48, 649}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 581}, {104, 561}, + {108, 541}, {112, 521}, + {116, 499}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, 499}, {136, 519}, + {140, 539}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 651}, {40, 651}, + {44, 674}, {48, 640}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 603}, {104, 560}, + {108, 540}, {112, 520}, + {116, 499}, {120, 479}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, 479}, + {140, 499}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, 643}, {40, 668}, + {44, 651}, {48, 657}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MAX}, {104, 602}, + {108, 578}, {112, 570}, + {116, 550}, {120, 530}, + {124, 510}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, 490}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, 654}, {40, 667}, + {44, 666}, {48, 642}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, 596}, + {116, 555}, {120, 535}, + {124, 515}, {128, 495}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, 679}, {40, 673}, + {44, 667}, {48, 656}, + {52, 634}, {56, 663}, + {60, 662}, {64, 660}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, 590}, + {116, 573}, {120, 553}, + {124, 533}, {128, 513}, + {132, 490}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, +}; +#endif /* WLAN_ENABLE_CHNL_MATRIX_RESTRICTION */ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ +#ifdef SOFTAP_CHANNEL_RANGE +static CDF_STATUS sap_get_channel_list(ptSapContext sapContext, + uint8_t **channelList, + uint8_t *numberOfChannels); +#endif + +/*========================================================================== + FUNCTION sapGet5GHzChannelList + + DESCRIPTION + Function for initializing list of 2.4/5 Ghz [NON-DFS/DFS] available + channels in the current regulatory domain. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + + RETURN VALUE + NA + + SIDE EFFECTS + ============================================================================*/ +static CDF_STATUS sap_get5_g_hz_channel_list(ptSapContext sapContext); + +/*========================================================================== + FUNCTION sapStopDfsCacTimer + + DESCRIPTION + Function to sttop the DFS CAC timer when SAP is stopped + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_stop_dfs_cac_timer(ptSapContext sapContext); + +/*========================================================================== + FUNCTION sapStartDfsCacTimer + + DESCRIPTION + Function to start the DFS CAC timer when SAP is started on DFS Channel + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +int sap_start_dfs_cac_timer(ptSapContext sapContext); + +/** sap_hdd_event_to_string() - convert hdd event to string + * @event: eSapHddEvent event type + * + * This function converts eSapHddEvent into string + * + * Return: string for the @event. + */ +static uint8_t *sap_hdd_event_to_string(eSapHddEvent event) +{ + switch (event) { + CASE_RETURN_STRING(eSAP_START_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STA_ASSOC_IND); + CASE_RETURN_STRING(eSAP_STA_ASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_REASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_DISASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_SET_KEY_EVENT); + CASE_RETURN_STRING(eSAP_STA_MIC_FAILURE_EVENT); + CASE_RETURN_STRING(eSAP_ASSOC_STA_CALLBACK_EVENT); + CASE_RETURN_STRING(eSAP_GET_WPSPBC_SESSION_EVENT); + CASE_RETURN_STRING(eSAP_WPS_PBC_PROBE_REQ_EVENT); + CASE_RETURN_STRING(eSAP_INDICATE_MGMT_FRAME); + CASE_RETURN_STRING(eSAP_REMAIN_CHAN_READY); + CASE_RETURN_STRING(eSAP_SEND_ACTION_CNF); + CASE_RETURN_STRING(eSAP_DISCONNECT_ALL_P2P_CLIENT); + CASE_RETURN_STRING(eSAP_MAC_TRIG_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_UNKNOWN_STA_JOIN); + CASE_RETURN_STRING(eSAP_MAX_ASSOC_EXCEEDED); + CASE_RETURN_STRING(eSAP_CHANNEL_CHANGE_EVENT); + CASE_RETURN_STRING(eSAP_DFS_CAC_START); + CASE_RETURN_STRING(eSAP_DFS_CAC_END); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT); + CASE_RETURN_STRING(eSAP_DFS_NOL_GET); + CASE_RETURN_STRING(eSAP_DFS_NOL_SET); + CASE_RETURN_STRING(eSAP_DFS_NO_AVAILABLE_CHANNEL); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + CASE_RETURN_STRING(eSAP_ACS_SCAN_SUCCESS_EVENT); +#endif + CASE_RETURN_STRING(eSAP_ACS_CHANNEL_SELECTED); + default: + return "eSAP_HDD_EVENT_UNKNOWN"; + } +} + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/*========================================================================== + FUNCTION sap_event_init + + DESCRIPTION + Function for initializing sWLAN_SAPEvent structure + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapEvent : State machine event + + RETURN VALUE + + None + + SIDE EFFECTS + ============================================================================*/ +static inline void sap_event_init(ptWLAN_SAPEvent sapEvent) +{ + sapEvent->event = eSAP_MAC_SCAN_COMPLETE; + sapEvent->params = 0; + sapEvent->u1 = 0; + sapEvent->u2 = 0; +} + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION +/* + * This function gives the leakage matrix for given NOL channel and cbMode + * + * PARAMETERS + * IN + * sapContext : Pointer to vos global context structure + * cbMode : target channel bonding mode + * NOL_channel : the NOL channel whose leakage matrix is required + * pTarget_chnl_mtrx : pointer to target channel matrix returned. + * + * RETURN VALUE + * BOOLEAN + * TRUE: leakage matrix was found + * FALSE: leakage matrix was not found + */ +bool +sap_find_target_channel_in_channel_matrix(ptSapContext sapContext, + ePhyChanBondState cbMode, + uint8_t NOL_channel, + tSapTxLeakInfo **pTarget_chnl_mtrx) +{ + tSapTxLeakInfo *target_chan_matrix = NULL; + tSapChanMatrixInfo *pchan_matrix = NULL; + uint32_t nchan_matrix; + int i = 0; + + switch (cbMode) { + case PHY_SINGLE_CHANNEL_CENTERED: + /* HT20 */ + pchan_matrix = ht20_chan; + nchan_matrix = CDF_ARRAY_SIZE(ht20_chan); + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + /* HT40 */ + pchan_matrix = ht40_chan; + nchan_matrix = CDF_ARRAY_SIZE(ht40_chan); + break; +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + /* HT80 */ + pchan_matrix = ht80_chan; + nchan_matrix = CDF_ARRAY_SIZE(ht80_chan); + break; +#endif + default: + /* handle exception and fall back to HT20 table */ + pchan_matrix = ht20_chan; + nchan_matrix = CDF_ARRAY_SIZE(ht20_chan); + break; + } + + for (i = 0; i < nchan_matrix; i++) { + /* find the SAP channel to map the leakage matrix */ + if (NOL_channel == pchan_matrix[i].channel) { + target_chan_matrix = pchan_matrix[i].chan_matrix; + break; + } + } + + if (NULL == target_chan_matrix) { + return false; + } else { + *pTarget_chnl_mtrx = target_chan_matrix; + return true; + } +} + +/** + * sap_mark_channels_leaking_into_nol() - to mark channel leaking in to nol + * @sap_ctx: pointer to SAP context + * @cb_mode: channel bonding mode + * @nol: nol info + * @temp_ch_lst_sz: the target channel list + * @temp_ch_lst: the target channel list + * + * This function removes the channels from temp channel list that + * (if selected as target channel) will cause leakage in one of + * the NOL channels + * + * Return: CDF_STATUS + */ + +CDF_STATUS +sap_mark_channels_leaking_into_nol(ptSapContext sap_ctx, + ePhyChanBondState cb_mode, + tSapDfsNolInfo *nol, + uint8_t temp_ch_lst_sz, + uint8_t *temp_ch_lst) +{ + tSapTxLeakInfo *target_chan_matrix = NULL; + uint32_t num_channel = (RF_CHAN_144 - RF_CHAN_36) + 1; + uint32_t i = 0; + uint32_t j = 0; + uint32_t k = 0; + uint8_t dfs_nol_channel; + + + /* traverse target_chan_matrix and */ + for (i = 0; i < NUM_5GHZ_CHANNELS ; i++) { + dfs_nol_channel = nol[i].dfs_channel_number; + if (nol[i].radar_status_flag == eSAP_DFS_CHANNEL_USABLE || + nol[i].radar_status_flag == eSAP_DFS_CHANNEL_AVAILABLE) { + /* not present in NOL */ + continue; + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: processing NOL channel: %d"), + dfs_nol_channel); + if (false == sap_find_target_channel_in_channel_matrix( + sap_ctx, cb_mode, dfs_nol_channel, + &target_chan_matrix)) { + /* + * should never happen, we should always find a table + * here, if we don't, need a fix here! + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Couldn't find target channel matrix!")); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + /* + * following is based on assumption that both temp_ch_lst + * and target channel matrix are in increasing order of + * channelID + */ + for (j = 0, k = 0; j < temp_ch_lst_sz && k < num_channel;) { + if (temp_ch_lst[j] == 0) { + j++; + continue; + } + if (target_chan_matrix[k].leak_chan != temp_ch_lst[j]) { + k++; + continue; + } + /* + * check leakage from candidate channel + * to NOL channel + */ + if (target_chan_matrix[k].leak_lvl <= + SAP_TX_LEAKAGE_THRES) { + /* + * candidate channel will have + * bad leakage in NOL channel, + * remove from temp list + */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: channel: %d will have bad leakage due to channel: %d\n"), + dfs_nol_channel, temp_ch_lst[j]); + temp_ch_lst[j] = 0; + break; + } + j++; + k++; + } + } /* end of loop that selects each NOL */ + return CDF_STATUS_SUCCESS; +} +#endif /* end of WLAN_ENABLE_CHNL_MATRIX_RESTRICTION */ + +/* + * This function adds availabe channel to bitmap + * + * PARAMETERS + * IN + * pBitmap: bitmap to populate + * channel: channel to set in bitmap + */ +static void sap_set_bitmap(chan_bonding_bitmap *pBitmap, uint8_t channel) +{ + int i = 0; + int start_channel = 0; + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = pBitmap->chanBondingSet[i].startChannel; + if (channel >= start_channel && channel <= start_channel + 12) { + pBitmap->chanBondingSet[i].channelMap |= + 1 << ((channel - start_channel) / 4); + return; + } + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Channel=%d is not in the bitmap"), channel); +} + +/** + * sap_populate_available_channels - To populate available channel + * @bitmap: bitmap to populate + * @current_cbmode: cb mode to check for channel availability + * @avail_chnl: available channel list to populate + * + * This function reads the bitmap and populates available channel + * list according to channel bonding mode. This will be called for + * 80 MHz and 40 Mhz only. For 20 MHz no need for bitmap hence list + * is directly created while parsing the main list + * + * Return: number of channels found + */ +static uint8_t sap_populate_available_channels(chan_bonding_bitmap *bitmap, + ePhyChanBondState current_cbmode, + uint8_t *avail_chnl) +{ + uint8_t i = 0; + uint8_t chnl_count = 0; + uint8_t start_channel = 0; + + switch (current_cbmode) { +#ifdef WLAN_FEATURE_11AC + /* HT80 */ + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = bitmap->chanBondingSet[i].startChannel; + if (bitmap->chanBondingSet[i].channelMap == + SAP_80MHZ_MASK) { + avail_chnl[chnl_count++] = start_channel; + avail_chnl[chnl_count++] = start_channel + 4; + avail_chnl[chnl_count++] = start_channel + 8; + avail_chnl[chnl_count++] = start_channel + 12; + } + } + break; +#endif + /* HT40 */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = bitmap->chanBondingSet[i].startChannel; + if ((bitmap->chanBondingSet[i].channelMap & + SAP_40MHZ_MASK_L) == SAP_40MHZ_MASK_L) { + avail_chnl[chnl_count++] = start_channel; + avail_chnl[chnl_count++] = start_channel + 4; + } else if ((bitmap->chanBondingSet[i].channelMap & + SAP_40MHZ_MASK_H) == SAP_40MHZ_MASK_H) { + avail_chnl[chnl_count++] = start_channel + 8; + avail_chnl[chnl_count++] = start_channel + 12; + } + } + break; + default: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid case.")); + break; + } + + return chnl_count; +} + +/* + * FUNCTION sap_dfs_is_w53_invalid + * + * DESCRIPTION Checks if the passed channel is W53 and returns if + * SAP W53 opearation is allowed. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE : bool + * true: If W53 operation is disabled + * false: If W53 operation is enabled + * + * SIDE EFFECTS + */ +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return false; + } + + /* + * Check for JAPAN W53 Channel operation capability + */ + if (true == pMac->sap.SapDfsInfo.is_dfs_w53_disabled && + true == IS_CHAN_JAPAN_W53(channelID)) { + return true; + } + + return false; +} + +/* + * FUNCTION sap_dfs_is_channel_in_preferred_location + * + * DESCRIPTION Checks if the passed channel is in accordance with preferred + * Channel location settings. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE :bool + * true:If Channel location is same as the preferred location + * false:If Channel location is not same as the preferred location + * + * SIDE EFFECTS + */ +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return true; + } + if ((SAP_CHAN_PREFERRED_INDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) && + (true == IS_CHAN_JAPAN_OUTDOOR(channelID))) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Outdoor so invalid,preferred Indoor only"), + channelID); + return false; + } else if ((SAP_CHAN_PREFERRED_OUTDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) + && (true == IS_CHAN_JAPAN_INDOOR(channelID))) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Indoor so invalid,preferred Outdoor only"), + channelID); + return false; + } + + return true; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool sap_check_in_avoid_ch_list(ptSapContext sap_ctx, uint8_t channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + for (i = 0; i < sizeof(ie_info->channels); i++) + if (ie_info->channels[i] == channel) + return true; + return false; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/* + * This function randomly pick up an AVAILABLE channel + */ +static uint8_t sap_random_channel_sel(ptSapContext sapContext) +{ + uint32_t random_byte = 0; + uint8_t available_ch_cnt = 0; + uint8_t avail_dfs_chan_count = 0; + uint8_t avail_non_dfs_chan_count = 0; + uint8_t valid_chnl_count = 0; + uint8_t availableChannels[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0, }; + uint8_t avail_dfs_chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0,}; + uint8_t avail_non_dfs_chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0,}; + uint8_t target_channel = 0; + bool isChannelNol = false; + bool isOutOfRange = false; + chan_bonding_bitmap channelBitmap; + uint8_t i = 0; + uint8_t channelID; + tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + tpAniSirGlobal pMac; + uint32_t chanWidth; + ePhyChanBondState cbModeCurrent; + uint8_t *tmp_ch_lst = NULL; + uint8_t dfs_region; + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid hHal")); + return target_channel; + } + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return target_channel; + } + + /* + * Retrieve the original one and store it. + * use the stored original value when you call this function next time + * so fall back mechanism always starts with original ini value. + */ + if (pMac->sap.SapDfsInfo.orig_cbMode == 0) { + pMac->sap.SapDfsInfo.orig_cbMode = + (sapContext->ch_width_orig > CH_WIDTH_20MHZ ? 1 : 0); + cbModeCurrent = pMac->sap.SapDfsInfo.orig_cbMode; + } else { + cbModeCurrent = pMac->sap.SapDfsInfo.orig_cbMode; + } + + /* + * Retrieve the original one and store it. + * use the stored original value when you call this function next time + * so fall back mechanism always starts with original ini value. + */ + if (pMac->sap.SapDfsInfo.orig_chanWidth == 0) { + pMac->sap.SapDfsInfo.orig_chanWidth = + sapContext->ch_width_orig; + chanWidth = pMac->sap.SapDfsInfo.orig_chanWidth; + } else { + chanWidth = pMac->sap.SapDfsInfo.orig_chanWidth; + } + + if (sap_get5_g_hz_channel_list(sapContext)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL("Getting 5Ghz channel list failed")); + return target_channel; + } + + cds_get_dfs_region(&dfs_region); + + /* + * valid_chnl_count will be used to find number of valid channels + * after following for loop ends + */ + valid_chnl_count = sapContext->SapAllChnlList.numChannel; + /* loop to check ACS range or NOL channels */ + for (i = 0; i < sapContext->SapAllChnlList.numChannel; i++) { + channelID = sapContext->SapAllChnlList.channelList[i].channel; + + /* + * IN JAPAN REGULATORY DOMAIN CHECK IF THE FOLLOWING TWO + * TWO RULES APPLY AND FILTER THE AVAILABLE CHANNELS + * ACCORDINGLY. + * + * 1. If we are operating in Japan regulatory domain + * Check if Japan W53 Channel operation is NOT + * allowed and if its not allowed then mark all the + * W53 channels as Invalid. + * + * 2. If we are operating in Japan regulatory domain + * Check if channel switch between Indoor/Outdoor + * is allowed. If it is not allowed then limit + * the avaiable channels to Indoor or Outdoor + * channels only based up on the SAP Channel location + * indicated by "sap_operating_channel_location" param. + */ + if (DFS_MKK4_DOMAIN == dfs_region) { + /* + * Check for JAPAN W53 Channel operation capability + */ + if (true == sap_dfs_is_w53_invalid(hHal, channelID)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL + ("index:%d, Channel=%d Invalid,Japan W53 Disabled"), + i, channelID); + sapContext->SapAllChnlList.channelList[i]. + valid = false; + valid_chnl_count--; + continue; + } + + /* + * If SAP's preferred channel location is Indoor + * then set all the outdoor channels in the domain + * to invalid.If the preferred channel location is + * outdoor then set all the Indoor channels in the + * domain to Invalid. + */ + if (false == + sap_dfs_is_channel_in_preferred_location(hHal, + channelID)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is invalid,preferred Channel Location %d Only"), + channelID, + pMac->sap.SapDfsInfo. + sap_operating_chan_preferred_location); + sapContext->SapAllChnlList.channelList[i]. + valid = false; + valid_chnl_count--; + continue; + } + } + + if (cds_get_channel_state(channelID) == + CHANNEL_STATE_DFS) { + isChannelNol = + sap_dfs_is_channel_in_nol_list(sapContext, + channelID, + PHY_SINGLE_CHANNEL_CENTERED); + if (true == isChannelNol) { + /* + * Mark this channel invalid since it is still + * in DFS Non-Occupancy-Period which is 30 mins. + */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL + ("index: %d, Channel = %d Present in NOL LIST"), + i, channelID); + sapContext->SapAllChnlList.channelList[i]. + valid = false; + valid_chnl_count--; + continue; + } + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* avoid ch on which another MDM AP in MCC mode is detected */ + if (pMac->sap.sap_channel_avoidance + && sapContext->sap_detected_avoid_ch_ie.present) { + if (sap_check_in_avoid_ch_list(sapContext, channelID)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("index: %d, Channel = %d, avoided due to presence of another AP+AP MCC device in same channel."), + i, channelID); + sapContext->SapAllChnlList.channelList[i].valid + = false; + } + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + /* check if the channel is within ACS channel range */ + isOutOfRange = sap_acs_channel_check(sapContext, channelID); + if (true == isOutOfRange) { + /* + * mark this channel invalid since it is out of ACS + * channel range + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL + ("index: %d, Channel = %d out of ACS channel range"), + i, channelID); + sapContext->SapAllChnlList.channelList[i].valid = false; + valid_chnl_count--; + continue; + } + } /* end of check for NOL or ACS channels */ + + /* valid_chnl_count now have number of valid channels */ + tmp_ch_lst = cdf_mem_malloc(valid_chnl_count); + if (tmp_ch_lst == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("sapdfs: memory alloc failed")); + return target_channel; + } + + do { + uint8_t j = 0; +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + tSapDfsNolInfo *nol = pMac->sap.SapDfsInfo.sapDfsChannelNolList; +#endif + + /* prepare temp list of just the valid channels */ + for (i = 0; i < sapContext->SapAllChnlList.numChannel; i++) { + if (sapContext->SapAllChnlList.channelList[i].valid) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL + ("sapdfs: Adding Channel = %d to temp List"), + sapContext->SapAllChnlList. + channelList[i].channel); + tmp_ch_lst[j++] = sapContext->SapAllChnlList. + channelList[i].channel; + } + } + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL + ("sapdfs: Processing temp channel list against NOL.") + ); + if (CDF_STATUS_SUCCESS != + sap_mark_channels_leaking_into_nol(sapContext, + cbModeCurrent, + nol, + valid_chnl_count, + tmp_ch_lst)) { + cdf_mem_free(tmp_ch_lst); + return target_channel; + } +#endif + cdf_mem_zero(availableChannels, sizeof(availableChannels)); + cdf_mem_zero(&channelBitmap, sizeof(channelBitmap)); + channelBitmap.chanBondingSet[0].startChannel = 36; + channelBitmap.chanBondingSet[1].startChannel = 52; + channelBitmap.chanBondingSet[2].startChannel = 100; + channelBitmap.chanBondingSet[3].startChannel = 116; + channelBitmap.chanBondingSet[3].startChannel = 132; + channelBitmap.chanBondingSet[4].startChannel = 149; + /* now loop through whatever is left of channel list */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("sapdfs: Moving temp channel list to final.")); + for (i = 0; i < valid_chnl_count; i++) { + /* + * add channel from temp channel list to bitmap or fianl + * channel list (in case of 20MHz width) + */ + if (tmp_ch_lst[i] != 0) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: processing channel: %d "), + tmp_ch_lst[i]); + /* + * for 20MHz, directly create available + * channel list + */ + if (cbModeCurrent == + PHY_SINGLE_CHANNEL_CENTERED) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_DEBUG, + FL + ("sapdfs: Channel=%d added to available list"), + tmp_ch_lst[i]); + availableChannels[available_ch_cnt++] = + tmp_ch_lst[i]; + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: Channel=%d added to bitmap"), + tmp_ch_lst[i]); + sap_set_bitmap(&channelBitmap, + tmp_ch_lst[i]); + } + } + } + + /* + * if 40 MHz or 80 MHz, populate available + * channel list from bitmap + */ + if (cbModeCurrent != PHY_SINGLE_CHANNEL_CENTERED) { + available_ch_cnt = + sap_populate_available_channels(&channelBitmap, + cbModeCurrent, + availableChannels); + /* + * if no valid channel bonding found, + * fallback to lower bandwidth + */ + if (available_ch_cnt == 0) { + if (cbModeCurrent >= + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:No 80MHz cb found, falling to 40MHz")); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:Changing chanWidth from [%d] to [%d]"), + chanWidth, + CH_WIDTH_40MHZ); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:Changing CB mode from [%d] to [%d]"), + cbModeCurrent, + PHY_DOUBLE_CHANNEL_LOW_PRIMARY + ); + cbModeCurrent = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + chanWidth = CH_WIDTH_40MHZ; + /* continue to start of do loop */ + continue; + } else if (cbModeCurrent >= + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:No 40MHz cb found, falling to 20MHz")); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:Changing chanWidth from [%d] to [%d]"), + chanWidth, + CH_WIDTH_20MHZ); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + FL + ("sapdfs:Changing CB mode from [%d] to [%d]"), + cbModeCurrent, + PHY_SINGLE_CHANNEL_CENTERED); + cbModeCurrent = + PHY_SINGLE_CHANNEL_CENTERED; + chanWidth = CH_WIDTH_20MHZ; + /* continue to start of do loop */ + continue; + } + } + } + + /* + * by now, available channels list will be populated or + * no channels are avaialbe + */ + if (available_ch_cnt) { + for (i = 0; i < available_ch_cnt; i++) { + if (CDS_IS_DFS_CH(availableChannels[i])) { + avail_dfs_chan_list[ + avail_dfs_chan_count++] = + availableChannels[i]; + } else { + avail_non_dfs_chan_list[ + avail_non_dfs_chan_count++] = + availableChannels[i]; + } + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("No target channel found")); + } + + cds_rand_get_bytes(0, (uint8_t *)&random_byte, 1); + + /* Give preference to non-DFS channel */ + if (!pMac->f_prefer_non_dfs_on_radar) { + i = (random_byte + cdf_mc_timer_get_system_ticks()) % + available_ch_cnt; + target_channel = availableChannels[i]; + } else if (avail_non_dfs_chan_count) { + i = (random_byte + cdf_mc_timer_get_system_ticks()) % + avail_non_dfs_chan_count; + target_channel = avail_non_dfs_chan_list[i]; + } else { + i = (random_byte + cdf_mc_timer_get_system_ticks()) % + avail_dfs_chan_count; + target_channel = avail_dfs_chan_list[i]; + } + + pMac->sap.SapDfsInfo.new_chanWidth = chanWidth; + pMac->sap.SapDfsInfo.new_cbMode = cbModeCurrent; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: New CB mode = %d"), + pMac->sap.SapDfsInfo.new_cbMode); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: New Channel width = %d"), + pMac->sap.SapDfsInfo.new_chanWidth); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: target_channel = %d"), + target_channel); + break; + /* this loop will iterate at max 3 times */ + } while (1); + cdf_mem_free(tmp_ch_lst); + return target_channel; +} + +bool sap_acs_channel_check(ptSapContext sapContext, uint8_t channelNumber) +{ + int i = 0; + if (!sapContext->acs_cfg->acs_mode) + return false; + + if ((channelNumber >= sapContext->acs_cfg->start_ch) || + (channelNumber <= sapContext->acs_cfg->end_ch)) { + if (!sapContext->acs_cfg->ch_list) { + return false; + } else { + for (i = 0; i < sapContext->acs_cfg->ch_list_count; i++) + if (channelNumber == + sapContext->acs_cfg->ch_list[i]) + return false; + } + } + return true; +} + +/** + * sap_mark_dfs_channels() - to mark dfs channel + * @sapContext: pointer sap context + * @channels: list of channels + * @numChannels: number of channels + * @time: time + * + * Mark the channels in NOL with time and eSAP_DFS_CHANNEL_UNAVAILABLE + * + * Return: none + */ +void sap_mark_dfs_channels(ptSapContext sapContext, uint8_t *channels, + uint8_t numChannels, uint64_t time) +{ + int i, j; + tSapDfsNolInfo *psapDfsChannelNolList = NULL; + uint8_t nRegDomainDfsChannels; + tHalHandle hHal; + tpAniSirGlobal pMac; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == channels) + return; + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid hHal")); + return; + } + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return; + } + + /* + * Mark the current channel on which Radar is found + * in the NOL list as eSAP_DFS_CHANNEL_UNAVAILABLE. + */ + psapDfsChannelNolList = pMac->sap.SapDfsInfo.sapDfsChannelNolList; + nRegDomainDfsChannels = + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + + for (i = 0; i < numChannels; i++) { + for (j = 0; j <= nRegDomainDfsChannels; j++) { + if (!(psapDfsChannelNolList[j].dfs_channel_number == + channels[i])) + continue; + /* + * If channel is already in NOL, don't update it again. + * This is useful when marking bonding channels which + * are already unavailable. + */ + if (psapDfsChannelNolList[j].radar_status_flag == + eSAP_DFS_CHANNEL_UNAVAILABLE) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d already in NOL"), + channels[i]); + continue; + } + /* + * Capture the Radar Found timestamp on the + * Current Channel in ms. + */ + psapDfsChannelNolList[j].radar_found_timestamp = time; + /* Mark the Channel to be unavailble for next 30 mins */ + psapDfsChannelNolList[j].radar_status_flag = + eSAP_DFS_CHANNEL_UNAVAILABLE; + + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Added to NOL LIST"), + channels[i]); + } + } +} + +/* + * This Function is to get bonding channels from primary channel. + * + */ +uint8_t sap_get_bonding_channels(ptSapContext sapContext, uint8_t channel, + uint8_t *channels, uint8_t size, + ePhyChanBondState chanBondState) +{ + tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + tpAniSirGlobal pMac; + uint8_t numChannel; + + if (channels == NULL) + return 0; + + if (size < MAX_BONDED_CHANNELS) + return 0; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else + return 0; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("cbmode: %d, channel: %d"), chanBondState, channel); + + switch (chanBondState) { + case PHY_SINGLE_CHANNEL_CENTERED: + numChannel = 1; + channels[0] = channel; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + numChannel = 2; + channels[0] = channel - 4; + channels[1] = channel; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + numChannel = 2; + channels[0] = channel; + channels[1] = channel + 4; + break; +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + numChannel = 4; + channels[0] = channel; + channels[1] = channel + 4; + channels[2] = channel + 8; + channels[3] = channel + 12; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + numChannel = 4; + channels[0] = channel - 4; + channels[1] = channel; + channels[2] = channel + 4; + channels[3] = channel + 8; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 8; + channels[1] = channel - 4; + channels[2] = channel; + channels[3] = channel + 4; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 12; + channels[1] = channel - 8; + channels[2] = channel - 4; + channels[3] = channel; + break; +#endif + default: + numChannel = 1; + channels[0] = channel; + break; + } + + return numChannel; +} + +/** + * sap_dfs_check_if_channel_avaialable() - Check if a channel is out of NOL + * @nol: Pointer to the Non-Occupancy List. + * + * This function Checks if a given channel is available or + * usable or unavailable based on the time lapse since the + * last radar time stamp. + * + * Return: true if channel available or usable, false if unavailable. + */ +static bool sap_dfs_check_if_channel_avaialable(tSapDfsNolInfo *nol) +{ + uint64_t time_since_last_radar, time_when_radar_found, current_time = 0; + uint64_t max_jiffies; + + if ((nol->radar_status_flag == eSAP_DFS_CHANNEL_USABLE) || + (nol->radar_status_flag == eSAP_DFS_CHANNEL_AVAILABLE)) { + /* + * Allow SAP operation on this channel + * either the DFS channel has not been used + * for SAP operation or it is available for + * SAP operation since it is past + * Non-Occupancy-Period so, return false. + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d not in NOL,CHAN AVAILABLE"), + nol->dfs_channel_number); + return true; + } else if (nol->radar_status_flag == eSAP_DFS_CHANNEL_UNAVAILABLE) { + /* + * If a DFS Channel is UNAVAILABLE then + * check to see if it is past + * Non-occupancy-period + * of 30 minutes. If it is past 30 mins then + * mark the channel as AVAILABLE and return + * false as the channel is not anymore in + * NON-Occupancy-Period. + */ + time_when_radar_found = nol->radar_found_timestamp; + current_time = cds_get_monotonic_boottime(); + if (current_time < time_when_radar_found) { + /* cds_get_monotonic_boottime() can overflow. + * Jiffies is initialized such that 32 bit jiffies + * value wrap 5 minutes after boot so jiffies wrap bugs + * show up earlier + */ + max_jiffies = (uint64_t)UINT_MAX * 1000; + time_since_last_radar = (max_jiffies - + time_when_radar_found) + (current_time); + } else { + time_since_last_radar = current_time - + time_when_radar_found; + } + if (time_since_last_radar >= SAP_DFS_NON_OCCUPANCY_PERIOD) { + nol->radar_status_flag = eSAP_DFS_CHANNEL_AVAILABLE; + nol->radar_found_timestamp = 0; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d not in NOL, Channel AVAILABLE"), + nol->dfs_channel_number); + return true; + } else { + /* + * Channel is not still available for + * SAP operation so return true; As the + * Channel is still in + * Non-occupancy-Period. + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d in NOL, Channel UNAVAILBLE"), + nol->dfs_channel_number); + return false; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid Radar Status Flag")); + } + return true; +} + +/** + * sap_dfs_is_channel_in_nol_list() - given bonded channel is available + * @sap_context: Handle to SAP context. + * @channel_number: Channel on which availability should be checked. + * @chan_bondState: The channel bonding mode of the passed channel. + * + * This function Checks if a given bonded channel is available or + * usable for DFS operation. + * + * Return: false if channel is available, true if channel is in NOL. + */ +bool +sap_dfs_is_channel_in_nol_list(ptSapContext sap_context, + uint8_t channel_number, + ePhyChanBondState chan_bondState) +{ + int i, j; + tHalHandle h_hal = CDS_GET_HAL_CB(sap_context->p_cds_gctx); + tpAniSirGlobal mac_ctx; + uint8_t channels[MAX_BONDED_CHANNELS]; + uint8_t num_channels; + tSapDfsNolInfo *nol; + tSapDfsInfo *dfs_info; + bool channel_available; + + if (NULL == h_hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("invalid h_hal")); + return false; + } else { + mac_ctx = PMAC_STRUCT(h_hal); + } + + dfs_info = &mac_ctx->sap.SapDfsInfo; + if ((dfs_info->numCurrentRegDomainDfsChannels == 0) || + (dfs_info->numCurrentRegDomainDfsChannels > + NUM_5GHZ_CHANNELS)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + FL("invalid dfs channel count %d"), + dfs_info->numCurrentRegDomainDfsChannels); + return false; + } + + /* get the bonded channels */ + num_channels = sap_get_bonding_channels(sap_context, channel_number, + channels, MAX_BONDED_CHANNELS, chan_bondState); + + /* check for NOL, first on will break the loop */ + for (j = 0; j < num_channels; j++) { + for (i = 0; i < dfs_info->numCurrentRegDomainDfsChannels; i++) { + nol = &dfs_info->sapDfsChannelNolList[i]; + if (nol->dfs_channel_number != channels[j]) + continue; + + channel_available = + sap_dfs_check_if_channel_avaialable(nol); + + if (channel_available == false) + break; + + } /* loop for dfs channels */ + + if (i < dfs_info->numCurrentRegDomainDfsChannels) + break; + + } /* loop for bonded channels */ + + /* + * if any of the channel is not available, mark all available channels + * as unavailable with same time stamp. + */ + if (j < num_channels && + i < dfs_info->numCurrentRegDomainDfsChannels) { + if (num_channels > MAX_BONDED_CHANNELS) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("num_channel>MAX_BONDED_CHANNEL, reset")); + num_channels = MAX_BONDED_CHANNELS; + } + nol = &dfs_info->sapDfsChannelNolList[i]; + sap_mark_dfs_channels(sap_context, channels, num_channels, + nol->radar_found_timestamp); + + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sap_context, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + + return true; + } + + return false; +} + +/** + * sap_goto_channel_sel - Function for initiating scan request for SME + * @sap_context: Sap Context value. + * @sap_event: State machine event + * @sap_do_acs_pre_start_bss: true, if ACS scan is issued pre start BSS + * false, if ACS scan is issued post start BSS. + * + * Initiates sme scan for ACS to pick a channel. + * + * Return: The CDF_STATUS code associated with performing the operation. + */ +CDF_STATUS sap_goto_channel_sel(ptSapContext sap_context, + ptWLAN_SAPEvent sap_event, + bool sap_do_acs_pre_start_bss) +{ + + /* Initiate a SCAN request */ + CDF_STATUS cdf_ret_status; + /* To be initialised if scan is required */ + tCsrScanRequest scan_request; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + +#ifdef SOFTAP_CHANNEL_RANGE + uint8_t *channel_list = NULL; + uint8_t num_of_channels = 0; +#endif + tHalHandle h_hal; + uint8_t con_ch; + + h_hal = cds_get_context(CDF_MODULE_ID_SME); + if (NULL == h_hal) { + /* we have a serious problem */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return CDF_STATUS_E_FAULT; + } +#ifdef WLAN_FEATURE_MBSSID + if (cds_concurrent_beaconing_sessions_running()) { + con_ch = + sme_get_concurrent_operation_channel(h_hal); + + if (con_ch && sap_context->channel == AUTO_CHANNEL_SELECT) { + sap_context->dfs_ch_disable = true; + } else if (con_ch && sap_context->channel != con_ch && + CDS_IS_DFS_CH(sap_context->channel)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("MCC DFS not supported in AP_AP Mode")); + return CDF_STATUS_E_ABORTED; + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (sap_context->cc_switch_mode != + CDF_MCC_TO_SCC_SWITCH_DISABLE) { + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + if (con_ch) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + } + } +#endif + } +#endif + + if (cds_get_concurrency_mode() == (CDF_STA_MASK | CDF_SAP_MASK)) { +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (sap_context->channel == AUTO_CHANNEL_SELECT) + sap_context->dfs_ch_disable = true; + else if (CDS_IS_DFS_CH(sap_context->channel)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("DFS not supported in STA_AP Mode")); + return CDF_STATUS_E_ABORTED; + } +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (sap_context->cc_switch_mode != + CDF_MCC_TO_SCC_SWITCH_DISABLE) { + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + if (con_ch && !CDS_IS_DFS_CH(con_ch)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + } + } +#endif + } + + if (sap_context->channel == AUTO_CHANNEL_SELECT) { +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("%s skip_acs_status = %d "), __func__, + sap_context->acs_cfg->skip_scan_status); + if (sap_context->acs_cfg->skip_scan_status != + eSAP_SKIP_ACS_SCAN) { +#endif + cdf_mem_zero(&scan_request, sizeof(scan_request)); + + /* + * Set scanType to Active scan. FW takes care of using passive + * scan for DFS and active for non DFS channels. + */ + scan_request.scanType = eSIR_ACTIVE_SCAN; + + /* Set min and max channel time to zero */ + scan_request.minChnTime = 0; + scan_request.maxChnTime = 0; + + /* Set BSSType to default type */ + scan_request.BSSType = eCSR_BSS_TYPE_ANY; + +#ifndef SOFTAP_CHANNEL_RANGE + /*Scan all the channels */ + scan_request.ChannelInfo.num_of_channels = 0; + + scan_request.ChannelInfo.ChannelList = NULL; + + scan_request.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + /* eCSR_SCAN_REQUEST_11D_SCAN; */ + +#else + + sap_get_channel_list(sap_context, &channel_list, + &num_of_channels); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (num_of_channels != 0) { +#endif + /*Scan the channels in the list */ + scan_request.ChannelInfo.numOfChannels = + num_of_channels; + + scan_request.ChannelInfo.ChannelList = + channel_list; + + scan_request.requestType = + eCSR_SCAN_SOFTAP_CHANNEL_RANGE; + + sap_context->channelList = channel_list; + +#endif + /* Set requestType to Full scan */ + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("calling sme_scan_request")); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (sap_context->acs_cfg->skip_scan_status == + eSAP_DO_NEW_ACS_SCAN) +#endif + sme_scan_flush_result(h_hal); + if (true == sap_do_acs_pre_start_bss) { + /* + * when ID == 0 11D scan/active scan with callback, + * min-maxChntime set in csrScanRequest()? + * csrScanCompleteCallback callback + * pContext scan_request_id filled up + */ + cdf_ret_status = sme_scan_request(h_hal, + sap_context->sessionId, + &scan_request, + &wlansap_pre_start_bss_acs_scan_callback, + sap_context); + } else { + /* + * when ID == 0 11D scan/active scan with callback, + * min-maxChntime set in csrScanRequest()? + * csrScanCompleteCallback callback, + * pContext scan_request_id filled up + */ + cdf_ret_status = sme_scan_request(h_hal, + sap_context->sessionId, + &scan_request, + &wlansap_scan_callback, + sap_context); + } + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("sme_scan_request fail %d!!!"), + cdf_ret_status); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP Configuring default channel, Ch=%d"), + sap_context->channel); + /* In case of error, switch to default channel */ + sap_context->channel = SAP_DEFAULT_24GHZ_CHANNEL; + +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_context->channelList != NULL) { + sap_context->channel = + sap_context->channelList[0]; + cdf_mem_free(sap_context-> + channelList); + sap_context->channelList = NULL; + } +#endif + if (true == sap_do_acs_pre_start_bss) { + /* + * In case of ACS req before start Bss, + * return failure so that the calling + * fucntion can use the default channel. + */ + return CDF_STATUS_E_FAILURE; + } else { + /* Fill in the event structure */ + sap_event_init(sap_event); + /* Handle event */ + cdf_status = sap_fsm(sap_context, sap_event); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("return sme_ScanReq, scanID=%d, Ch=%d"), + scan_request.scan_id, sap_context->channel); + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + } + } else { + sap_context->acs_cfg->skip_scan_status = eSAP_SKIP_ACS_SCAN; + } + + if (sap_context->acs_cfg->skip_scan_status == eSAP_SKIP_ACS_SCAN) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("## %s SKIPPED ACS SCAN"), __func__); + wlansap_scan_callback(h_hal, sap_context, + sap_context->sessionId, 0, eCSR_SCAN_SUCCESS); + } +#endif + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("for configured channel, Ch= %d"), + sap_context->channel); + if (sap_do_acs_pre_start_bss == true) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("ACS end due to Ch override. Sel Ch = %d"), + sap_context->channel); + sap_context->acs_cfg->pri_ch = sap_context->channel; + sap_context->acs_cfg->ch_width = + sap_context->ch_width_orig; + sap_config_acs_result(h_hal, sap_context, 0); + return CDF_STATUS_E_CANCELED; + } else { + /* + * Fill in the event structure + * Eventhough scan was not done, + * means a user set channel was chosen + */ + sap_event_init(sap_event); + /* Handle event */ + cdf_status = sap_fsm(sap_context, sap_event); + } + } + + /* + * If scan failed, get default channel and advance state + * machine as success with default channel + * + * Have to wait for the call back to be called to get the + * channel cannot advance state machine here as said above + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("before exiting sap_goto_channel_sel channel=%d"), + sap_context->channel); + + return CDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION sap_OpenSession + + DESCRIPTION + Function for opening SME and SAP sessions when system is in SoftAP role + + DEPENDENCIES + NA. + + PARAMETERS + + IN + hHal : Hal handle + sapContext : Sap Context value + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext) +{ + uint32_t type, subType; + CDF_STATUS cdf_ret_status; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sapContext->csr_roamProfile.csrPersona == CDF_P2P_GO_MODE) + status = cds_get_vdev_types(CDF_P2P_GO_MODE, &type, &subType); + else + status = cds_get_vdev_types(CDF_SAP_MODE, &type, &subType); + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "failed to get vdev type"); + return CDF_STATUS_E_FAILURE; + } + /* Open SME Session for Softap */ + cdf_ret_status = sme_open_session(hHal, + &wlansap_roam_callback, + sapContext, + sapContext->self_mac_addr, + &sapContext->sessionId, type, subType); + + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_roam_connect status = %d", + __func__, cdf_ret_status); + + return CDF_STATUS_E_FAILURE; + } + + pMac->sap.sapCtxList[sapContext->sessionId].sessionID = + sapContext->sessionId; + pMac->sap.sapCtxList[sapContext->sessionId].pSapContext = sapContext; + pMac->sap.sapCtxList[sapContext->sessionId].sapPersona = + sapContext->csr_roamProfile.csrPersona; + return CDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION sapGotoStarting + + DESCRIPTION + Function for initiating start bss request for SME + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + sapEvent : State machine event + bssType : Type of bss to start, INRA AP + status : Return the SAP status here + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS +sap_goto_starting + (ptSapContext sapContext, + ptWLAN_SAPEvent sapEvent, eCsrRoamBssType bssType) { + /* tHalHandle */ + tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + CDF_STATUS cdf_ret_status; + + /*- - - - - - - - TODO:once configs from hdd available - - - - - - - - -*/ + char key_material[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, }; + sapContext->key_type = 0x05; + sapContext->key_length = 32; + cdf_mem_copy(sapContext->key_material, key_material, sizeof(key_material)); /* Need a key size define */ + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, "In %s", + __func__); + + if (NULL == hHal) { + /* we have a serious problem */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "In %s, invalid hHal", __func__); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = sap_open_session(hHal, sapContext); + + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sap_open_session status = %d", + __func__, cdf_ret_status); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} /* sapGotoStarting */ + +/*========================================================================== + FUNCTION sapGotoDisconnecting + + DESCRIPTION + Processing of SAP FSM Disconnecting state + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + status : Return the SAP status here + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS sap_goto_disconnecting(ptSapContext sapContext) +{ + CDF_STATUS cdf_ret_status; + tHalHandle hHal; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + /* we have a serious problem */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s, invalid hHal", __func__); + return CDF_STATUS_E_FAULT; + } + + sap_free_roam_profile(&sapContext->csr_roamProfile); + cdf_ret_status = sme_roam_stop_bss(hHal, sapContext->sessionId); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_roam_stop_bss status = %d", + __func__, cdf_ret_status); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS sap_roam_session_close_callback(void *pContext) +{ + ptSapContext sapContext = (ptSapContext) pContext; + return sap_signal_hdd_event(sapContext, NULL, + eSAP_STOP_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); +} + +/*========================================================================== + FUNCTION sapGotoDisconnected + + DESCRIPTION + Function for setting the SAP FSM to Disconnection state + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + sapEvent : State machine event + status : Return the SAP status here + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS sap_goto_disconnected(ptSapContext sapContext) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + tWLAN_SAPEvent sapEvent; + /* Processing has to be coded */ + /* Clean up stations from TL etc as AP BSS is shut down then set event */ + sapEvent.event = eSAP_MAC_READY_FOR_CONNECTIONS; /* hardcoded */ + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + /* Handle event */ + cdf_status = sap_fsm(sapContext, &sapEvent); + + return cdf_status; +} + +/** + * sap_signal_hdd_event() - send event notification + * @sap_ctx: Sap Context + * @csr_roaminfo: Pointer to CSR roam information + * @sap_hddevent: SAP HDD event + * @context: to pass the element for future support + * + * Function for HDD to send the event notification using callback + * + * Return: CDF_STATUS + */ +CDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx, + tCsrRoamInfo *csr_roaminfo, eSapHddEvent sap_hddevent, + void *context) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tSap_Event sap_ap_event; /* This now encodes ALL event types */ + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx; + tSirSmeChanInfo *chaninfo; + tSap_StationAssocIndication *assoc_ind; + tSap_StartBssCompleteEvent *bss_complete; + struct sap_ch_selected_s *acs_selected; + tSap_StationAssocReassocCompleteEvent *reassoc_complete; + tSap_StationDisassocCompleteEvent *disassoc_comp; + tSap_StationSetKeyCompleteEvent *key_complete; + tSap_StationMICFailureEvent *mic_failure; + tSap_ManagementFrameInfo *mgmt_frame; + + /* Format the Start BSS Complete event to return... */ + if (NULL == sap_ctx->pfnSapEventCallback) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + if (NULL == hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return CDF_STATUS_E_FAILURE; + } + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP event callback event = %s"), + sap_hdd_event_to_string(sap_hddevent)); + + switch (sap_hddevent) { + case eSAP_STA_ASSOC_IND: + /* TODO - Indicate the assoc request indication to OS */ + sap_ap_event.sapHddEventCode = eSAP_STA_ASSOC_IND; + assoc_ind = &sap_ap_event.sapevt.sapAssocIndication; + + cdf_copy_macaddr(&assoc_ind->staMac, &csr_roaminfo->peerMac); + assoc_ind->staId = csr_roaminfo->staId; + assoc_ind->status = 0; + /* Required for indicating the frames to upper layer */ + assoc_ind->beaconLength = csr_roaminfo->beaconLength; + assoc_ind->beaconPtr = csr_roaminfo->beaconPtr; + assoc_ind->assocReqLength = csr_roaminfo->assocReqLength; + assoc_ind->assocReqPtr = csr_roaminfo->assocReqPtr; + assoc_ind->fWmmEnabled = csr_roaminfo->wmmEnabledSta; + if (csr_roaminfo->u.pConnectedProfile != NULL) { + assoc_ind->negotiatedAuthType = + csr_roaminfo->u.pConnectedProfile->AuthType; + assoc_ind->negotiatedUCEncryptionType = + csr_roaminfo->u.pConnectedProfile->EncryptionType; + assoc_ind->negotiatedMCEncryptionType = + csr_roaminfo->u.pConnectedProfile->mcEncryptionType; + assoc_ind->fAuthRequired = csr_roaminfo->fAuthRequired; + } + break; + case eSAP_START_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_START_BSS_EVENT; + bss_complete = &sap_ap_event.sapevt.sapStartBssCompleteEvent; + + bss_complete->status = (eSapStatus) context; + if (csr_roaminfo != NULL) + bss_complete->staId = csr_roaminfo->staId; + else + bss_complete->staId = 0; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("(eSAP_START_BSS_EVENT): staId = %d"), + bss_complete->staId); + + bss_complete->operatingChannel = (uint8_t) sap_ctx->channel; + bss_complete->sessionId = sap_ctx->sessionId; + break; + case eSAP_DFS_CAC_START: + case eSAP_DFS_CAC_INTERRUPTED: + case eSAP_DFS_CAC_END: + case eSAP_DFS_RADAR_DETECT: + case eSAP_DFS_NO_AVAILABLE_CHANNEL: +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + case eSAP_ACS_SCAN_SUCCESS_EVENT: +#endif + sap_ap_event.sapHddEventCode = sap_hddevent; + sap_ap_event.sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + break; + + case eSAP_ACS_CHANNEL_SELECTED: + sap_ap_event.sapHddEventCode = sap_hddevent; + acs_selected = &sap_ap_event.sapevt.sap_ch_selected; + if (eSAP_STATUS_SUCCESS == (eSapStatus)context) { + acs_selected->pri_ch = sap_ctx->acs_cfg->pri_ch; + acs_selected->ht_sec_ch = sap_ctx->acs_cfg->ht_sec_ch; + acs_selected->ch_width = sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->acs_cfg->vht_seg0_center_ch; + acs_selected->vht_seg1_center_ch = + sap_ctx->acs_cfg->vht_seg1_center_ch; + } else if (eSAP_STATUS_FAILURE == (eSapStatus)context) { + acs_selected->pri_ch = 0; + } + break; + + case eSAP_STOP_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_STOP_BSS_EVENT; + sap_ap_event.sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + reassoc_complete = + &sap_ap_event.sapevt.sapStationAssocReassocCompleteEvent; + + if (csr_roaminfo->fReassocReq) + sap_ap_event.sapHddEventCode = eSAP_STA_REASSOC_EVENT; + else + sap_ap_event.sapHddEventCode = eSAP_STA_ASSOC_EVENT; + + cdf_copy_macaddr(&reassoc_complete->staMac, + &csr_roaminfo->peerMac); + reassoc_complete->staId = csr_roaminfo->staId; + reassoc_complete->statusCode = csr_roaminfo->statusCode; + reassoc_complete->iesLen = csr_roaminfo->rsnIELen; + cdf_mem_copy(reassoc_complete->ies, csr_roaminfo->prsnIE, + csr_roaminfo->rsnIELen); + +#ifdef FEATURE_WLAN_WAPI + if (csr_roaminfo->wapiIELen) { + uint8_t len = reassoc_complete->iesLen; + reassoc_complete->iesLen += csr_roaminfo->wapiIELen; + cdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->pwapiIE, + csr_roaminfo->wapiIELen); + } +#endif + if (csr_roaminfo->addIELen) { + uint8_t len = reassoc_complete->iesLen; + reassoc_complete->iesLen += csr_roaminfo->addIELen; + cdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->paddIE, + csr_roaminfo->addIELen); + } + + /* also fill up the channel info from the csr_roamInfo */ + chaninfo = &reassoc_complete->chan_info; + + chaninfo->chan_id = csr_roaminfo->chan_info.chan_id; + chaninfo->mhz = csr_roaminfo->chan_info.mhz; + chaninfo->info = csr_roaminfo->chan_info.info; + chaninfo->band_center_freq1 = + csr_roaminfo->chan_info.band_center_freq1; + chaninfo->band_center_freq2 = + csr_roaminfo->chan_info.band_center_freq2; + chaninfo->reg_info_1 = + csr_roaminfo->chan_info.reg_info_1; + chaninfo->reg_info_2 = + csr_roaminfo->chan_info.reg_info_2; + + reassoc_complete->wmmEnabled = csr_roaminfo->wmmEnabledSta; + reassoc_complete->status = (eSapStatus) context; + reassoc_complete->timingMeasCap = csr_roaminfo->timingMeasCap; + break; + + case eSAP_STA_DISASSOC_EVENT: + sap_ap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + disassoc_comp = + &sap_ap_event.sapevt.sapStationDisassocCompleteEvent; + + cdf_copy_macaddr(&disassoc_comp->staMac, + &csr_roaminfo->peerMac); + disassoc_comp->staId = csr_roaminfo->staId; + if (csr_roaminfo->reasonCode == eCSR_ROAM_RESULT_FORCED) + disassoc_comp->reason = eSAP_USR_INITATED_DISASSOC; + else + disassoc_comp->reason = eSAP_MAC_INITATED_DISASSOC; + + disassoc_comp->statusCode = csr_roaminfo->statusCode; + disassoc_comp->status = (eSapStatus) context; + break; + + case eSAP_STA_SET_KEY_EVENT: + sap_ap_event.sapHddEventCode = eSAP_STA_SET_KEY_EVENT; + key_complete = + &sap_ap_event.sapevt.sapStationSetKeyCompleteEvent; + key_complete->status = (eSapStatus) context; + cdf_copy_macaddr(&key_complete->peerMacAddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_STA_MIC_FAILURE_EVENT: + sap_ap_event.sapHddEventCode = eSAP_STA_MIC_FAILURE_EVENT; + mic_failure = &sap_ap_event.sapevt.sapStationMICFailureEvent; + + cdf_mem_copy(&mic_failure->srcMacAddr, + csr_roaminfo->u.pMICFailureInfo->srcMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&mic_failure->staMac.bytes, + csr_roaminfo->u.pMICFailureInfo->taMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&mic_failure->dstMacAddr.bytes, + csr_roaminfo->u.pMICFailureInfo->dstMacAddr, + sizeof(tSirMacAddr)); + mic_failure->multicast = + csr_roaminfo->u.pMICFailureInfo->multicast; + mic_failure->IV1 = csr_roaminfo->u.pMICFailureInfo->IV1; + mic_failure->keyId = csr_roaminfo->u.pMICFailureInfo->keyId; + cdf_mem_copy(mic_failure->TSC, + csr_roaminfo->u.pMICFailureInfo->TSC, + SIR_CIPHER_SEQ_CTR_SIZE); + break; + + case eSAP_ASSOC_STA_CALLBACK_EVENT: + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + sap_ap_event.sapHddEventCode = eSAP_WPS_PBC_PROBE_REQ_EVENT; + + cdf_mem_copy(&sap_ap_event.sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq, csr_roaminfo->u.pWPSPBCProbeReq, + sizeof(tSirWPSPBCProbeReq)); + break; + + case eSAP_INDICATE_MGMT_FRAME: + sap_ap_event.sapHddEventCode = eSAP_INDICATE_MGMT_FRAME; + mgmt_frame = &sap_ap_event.sapevt.sapManagementFrameInfo; + + mgmt_frame->nFrameLength = csr_roaminfo->nFrameLength; + mgmt_frame->pbFrames = csr_roaminfo->pbFrames; + mgmt_frame->frameType = csr_roaminfo->frameType; + mgmt_frame->rxChan = csr_roaminfo->rxChan; + break; + + case eSAP_REMAIN_CHAN_READY: + sap_ap_event.sapHddEventCode = eSAP_REMAIN_CHAN_READY; + sap_ap_event.sapevt.sap_roc_ind.scan_id = + sap_ctx->roc_ind_scan_id; + break; + case eSAP_SEND_ACTION_CNF: + sap_ap_event.sapHddEventCode = eSAP_SEND_ACTION_CNF; + sap_ap_event.sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + sap_ap_event.sapHddEventCode = eSAP_DISCONNECT_ALL_P2P_CLIENT; + sap_ap_event.sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_MAC_TRIG_STOP_BSS_EVENT; + sap_ap_event.sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_UNKNOWN_STA_JOIN: + sap_ap_event.sapHddEventCode = eSAP_UNKNOWN_STA_JOIN; + cdf_mem_copy((void *) sap_ap_event.sapevt.sapUnknownSTAJoin. + macaddr.bytes, (void *) context, + CDF_MAC_ADDR_SIZE); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + sap_ap_event.sapHddEventCode = eSAP_MAX_ASSOC_EXCEEDED; + cdf_copy_macaddr(&sap_ap_event.sapevt. + sapMaxAssocExceeded.macaddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_CHANNEL_CHANGE_EVENT: + /* + * Reconfig ACS result info. For DFS AP-AP Mode Sec AP ACS + * follows pri AP + */ + sap_ctx->acs_cfg->pri_ch = sap_ctx->channel; + sap_ctx->acs_cfg->ch_width = sap_ctx->ch_params.ch_width; + sap_config_acs_result(hal, sap_ctx, sap_ctx->secondary_ch); + + sap_ap_event.sapHddEventCode = eSAP_CHANNEL_CHANGE_EVENT; + + acs_selected = &sap_ap_event.sapevt.sap_ch_selected; + acs_selected->pri_ch = sap_ctx->acs_cfg->pri_ch; + acs_selected->ht_sec_ch = sap_ctx->acs_cfg->ht_sec_ch; + acs_selected->ch_width = sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->acs_cfg->vht_seg0_center_ch; + acs_selected->vht_seg1_center_ch = + sap_ctx->acs_cfg->vht_seg1_center_ch; + break; + + case eSAP_DFS_NOL_GET: + sap_ap_event.sapHddEventCode = eSAP_DFS_NOL_GET; + sap_ap_event.sapevt.sapDfsNolInfo.sDfsList = + NUM_5GHZ_CHANNELS * sizeof(tSapDfsNolInfo); + sap_ap_event.sapevt.sapDfsNolInfo.pDfsList = (void *) + (&mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList[0]); + break; + + case eSAP_DFS_NOL_SET: + sap_ap_event.sapHddEventCode = eSAP_DFS_NOL_SET; + sap_ap_event.sapevt.sapDfsNolInfo.sDfsList = + mac_ctx->sap.SapDfsInfo.numCurrentRegDomainDfsChannels * + sizeof(tSapDfsNolInfo); + sap_ap_event.sapevt.sapDfsNolInfo.pDfsList = (void *) + (&mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList[0]); + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("SAP Unknown callback event = %d"), + sap_hddevent); + break; + } + cdf_status = (*sap_ctx->pfnSapEventCallback) + (&sap_ap_event, sap_ctx->pUsrContext); + + return cdf_status; + +} + +/*========================================================================== + FUNCTION sap_find_valid_concurrent_session + + DESCRIPTION + This function will return sapcontext of any valid sap session. + + PARAMETERS + + IN + hHal : HAL pointer + + RETURN VALUE + ptSapContext : valid sap context + + SIDE EFFECTS + NA + ============================================================================*/ +ptSapContext sap_find_valid_concurrent_session(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t intf = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) && + pMac->sap.sapCtxList[intf].pSapContext != NULL) { + return pMac->sap.sapCtxList[intf].pSapContext; + } + } + + return NULL; +} + +/*========================================================================== + FUNCTION sap_close_session + + DESCRIPTION + This function will close all the sme sessions as well as zero-out the + sap global structure + + PARAMETERS + + IN + hHal : HAL pointer + sapContext : Sap Context value + callback : Roam Session close callback + valid : Sap context is valid or no + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + NA + ============================================================================*/ +CDF_STATUS sap_close_session(tHalHandle hHal, + ptSapContext sapContext, + csr_roamSessionCloseCallback callback, bool valid) +{ + CDF_STATUS cdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (false == valid) { + cdf_status = sme_close_session(hHal, + sapContext->sessionId, + callback, NULL); + } else { + cdf_status = sme_close_session(hHal, + sapContext->sessionId, + callback, sapContext); + } + + sapContext->isCacStartNotified = false; + sapContext->isCacEndNotified = false; + pMac->sap.sapCtxList[sapContext->sessionId].pSapContext = NULL; + + if (NULL == sap_find_valid_concurrent_session(hHal)) { + /* If timer is running then stop the timer and destory it */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: no session are valid, so clearing dfs global structure"); + /* + * CAC timer will be initiated and started only when SAP starts + * on DFS channel and it will be stopped and destroyed + * immediately once the radar detected or timedout. So + * as per design CAC timer should be destroyed after stop + */ + if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + cdf_mc_timer_stop(&pMac->sap.SapDfsInfo. + sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + cdf_mc_timer_destroy( + &pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + } + pMac->sap.SapDfsInfo.cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hHal); + cdf_mem_zero(&pMac->sap, sizeof(pMac->sap)); + } + + return cdf_status; +} + +/*========================================================================== + FUNCTION sap_cac_reset_notify + + DESCRIPTION Function will be called up on stop bss indication to clean up + DFS global structure. + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : void. + + SIDE EFFECTS + ============================================================================*/ +void sap_cac_reset_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + pSapContext->isCacStartNotified = false; + pSapContext->isCacEndNotified = false; + } + } +} + +/*========================================================================== + FUNCTION sap_cac_start_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_START event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : CDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS sap_cac_start_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL && + (false == pSapContext->isCacStartNotified)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Signaling eSAP_DFS_CAC_START to HDD for sapctx[%p]", + pSapContext); + + cdf_status = sap_signal_hdd_event(pSapContext, NULL, + eSAP_DFS_CAC_START, + (void *) + eSAP_STATUS_SUCCESS); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacStartNotified on interface[%d]", + __func__, intf); + return cdf_status; + } + pSapContext->isCacStartNotified = true; + } + } + return cdf_status; +} + +/*========================================================================== + FUNCTION sap_cac_end_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_END event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : CDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS sap_cac_end_notify(tHalHandle hHal, tCsrRoamInfo *roamInfo) +{ + uint8_t intf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + /* + * eSAP_DFS_CHANNEL_CAC_END: + * CAC Period elapsed and there was no radar + * found so, SAP can continue beaconing. + * sap_radar_found_status is set to 0 + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL && + (false == pSapContext->isCacEndNotified)) { + pSapContext = pMac->sap.sapCtxList[intf].pSapContext; + cdf_status = sap_signal_hdd_event(pSapContext, NULL, + eSAP_DFS_CAC_END, + (void *) + eSAP_STATUS_SUCCESS); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return cdf_status; + } + pSapContext->isCacEndNotified = true; + pMac->sap.SapDfsInfo.sap_radar_found_status = false; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Start beacon request on sapctx[%p]", + pSapContext); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(pSapContext); + + /* Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: channel[%d] from state %s => %s", + pSapContext->channel, "eSAP_STARTING", + "eSAP_STARTED"); + + pSapContext->sapsMachine = eSAP_STARTED; + + /*Action code for transition */ + cdf_status = sap_signal_hdd_event(pSapContext, roamInfo, + eSAP_START_BSS_EVENT, + (void *) + eSAP_STATUS_SUCCESS); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return cdf_status; + } + + /* Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, from state %s => %s", + __func__, "eSAP_DFS_CAC_WAIT", + "eSAP_STARTED"); + } + } + /* + * All APs are done with CAC timer, all APs should start beaconing. + * Lets assume AP1 and AP2 started beaconing on DFS channel, Now lets + * say AP1 goes down and comes back on same DFS channel. In this case + * AP1 shouldn't start CAC timer and start beacon immediately beacause + * AP2 is already beaconing on this channel. This case will be handled + * by checking against eSAP_DFS_SKIP_CAC while starting the timer. + */ + pMac->sap.SapDfsInfo.cac_state = eSAP_DFS_SKIP_CAC; + return cdf_status; +} + +/** + * sap_fsm_state_disconnected() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_DISCONNECTED" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_disconnected(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_START_INFRA_BSS) { + /* + * Transition from eSAP_DISCONNECTED to eSAP_CH_SELECT + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("new from state %s => %s"), + "eSAP_DISCONNECTED", "eSAP_CH_SELECT"); + + /* There can be one SAP Session for softap */ + if (sap_ctx->isSapSessionOpen == eSAP_TRUE) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + FL("SME Session is already opened")); + return CDF_STATUS_E_EXISTS; + } + + sap_ctx->sessionId = 0xff; + + if ((sap_ctx->channel == AUTO_CHANNEL_SELECT) && + (sap_ctx->isScanSessionOpen == eSAP_FALSE)) { + uint32_t type, subtype; + if (CDF_STATUS_SUCCESS == cds_get_vdev_types( + CDF_STA_MODE, &type, &subtype)) { + /* Open SME Session for scan */ + cdf_status = sme_open_session(hal, NULL, + sap_ctx, sap_ctx->self_mac_addr, + &sap_ctx->sessionId, type, subtype); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("Error: calling sme_open_session")); + } else { + sap_ctx->isScanSessionOpen = eSAP_TRUE; + } + } + } + /* init dfs channel nol */ + sap_init_dfs_channel_nol_list(sap_ctx); + + /* Set SAP device role */ + sap_ctx->sapsMachine = eSAP_CH_SELECT; + + /* + * Perform sme_ScanRequest. This scan request is post start bss + * request so, set the third to false. + */ + cdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false); + + /* + * Transition from eSAP_DISCONNECTED to eSAP_CH_SELECT + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_DISCONNECTED", "eSAP_CH_SELECT"); + } else if (msg == eSAP_DFS_CHANNEL_CAC_START) { + /* + * No need of state check here, caller is expected to perform + * the checks before sending the event + */ + sap_ctx->sapsMachine = eSAP_DFS_CAC_WAIT; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("from state eSAP_DISCONNECTED => SAP_DFS_CAC_WAIT")); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: starting dfs cac timer on sapctx[%p]"), + sap_ctx); + sap_start_dfs_cac_timer(sap_ctx); + } + + cdf_status = sap_cac_start_notify(hal); + } else if (msg == eSAP_CHANNEL_SELECTION_RETRY) { + /* Set SAP device role */ + sap_ctx->sapsMachine = eSAP_CH_SELECT; + + /* + * Perform sme_ScanRequest. This scan request is post start bss + * request so, set the third to false. + */ + cdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, event msg %d"), + "eSAP_DISCONNECTED", msg); + } + + return cdf_status; +} + +/** + * sap_fsm_state_ch_select() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_CH_SELECT" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_ch_select(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + uint32_t cbmode; + bool b_leak_chan = false; +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + uint8_t temp_chan; + tSapDfsNolInfo *p_nol; +#endif + + if (sap_ctx->isScanSessionOpen == eSAP_TRUE) { + /* scan completed, so close the session */ + cdf_status = sme_close_session(hal, sap_ctx->sessionId, + NULL, NULL); + if (CDF_STATUS_SUCCESS != cdf_status) + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("CloseSession error event msg %d"), msg); + else + sap_ctx->isScanSessionOpen = eSAP_FALSE; + sap_ctx->sessionId = 0xff; + } + + if (msg == eSAP_MAC_SCAN_COMPLETE) { + /* get the bonding mode */ + if (sap_ctx->channel <= 14) + cbmode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode24_g(hal)); + else + cbmode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode5_g(hal)); + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + temp_chan = sap_ctx->channel; + p_nol = mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList; + + sap_mark_channels_leaking_into_nol(sap_ctx, + cbmode, p_nol, 1, &temp_chan); + + /* + * if selelcted channel has leakage to channels + * in NOL, the temp_chan will be reset + */ + b_leak_chan = (temp_chan != sap_ctx->channel); +#endif + /* + * check if channel is in DFS_NOL or if the channel + * has leakage to the channels in NOL + */ + if (sap_dfs_is_channel_in_nol_list(sap_ctx, sap_ctx->channel, + cbmode) || b_leak_chan) { + uint8_t ch; + + /* find a new available channel */ + ch = sap_random_channel_sel(sap_ctx); + if (ch == 0) { + /* No available channel found */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("No available channel found!!!")); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *)eSAP_STATUS_SUCCESS); + return CDF_STATUS_E_FAULT; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("channel %d is in NOL, StartBss on new channel %d"), + sap_ctx->channel, ch); + + sap_ctx->channel = ch; + sme_set_ch_params(hal, sap_ctx->csr_roamProfile.phyMode, + sap_ctx->channel, sap_ctx->secondary_ch, + &sap_ctx->ch_params); + } + if (sap_ctx->channel > 14 && + (sap_ctx->csr_roamProfile.phyMode == eCSR_DOT11_MODE_11g || + sap_ctx->csr_roamProfile.phyMode == + eCSR_DOT11_MODE_11g_ONLY)) + sap_ctx->csr_roamProfile.phyMode = eCSR_DOT11_MODE_11a; + +#ifdef WLAN_FEATURE_MBSSID + /* + * when AP2 is started while AP1 is performing ACS, we may not + * have the AP1 channel yet.So here after the completion of AP2 + * ACS check if AP1 ACS resulting channel is DFS and if yes + * override AP2 ACS scan result with AP1 DFS channel + */ + if (cds_concurrent_beaconing_sessions_running()) { + uint16_t con_ch; + + con_ch = sme_get_concurrent_operation_channel(hal); + if (con_ch && CDS_IS_DFS_CH(con_ch)) + sap_ctx->channel = con_ch; + } +#endif + /* + * Transition from eSAP_CH_SELECT to eSAP_STARTING + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_CH_SELECT", "eSAP_STARTING"); + /* Channel selected. Now can sap_goto_starting */ + sap_ctx->sapsMachine = eSAP_STARTING; + /* Specify the channel */ + sap_ctx->csr_roamProfile.ChannelInfo.numOfChannels = + 1; + sap_ctx->csr_roamProfile.ChannelInfo.ChannelList = + &sap_ctx->csr_roamProfile.operationChannel; + sap_ctx->csr_roamProfile.operationChannel = + (uint8_t) sap_ctx->channel; + sap_ctx->csr_roamProfile.ch_params.ch_width = + sap_ctx->ch_params.ch_width; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg0 = + sap_ctx->ch_params.center_freq_seg0; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg1 = + sap_ctx->ch_params.center_freq_seg1; + sap_ctx->csr_roamProfile.ch_params.sec_ch_offset = + sap_ctx->ch_params.sec_ch_offset; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("notify hostapd about channel selection: %d"), + sap_ctx->channel); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *) eSAP_STATUS_SUCCESS); + cdf_status = sap_goto_starting(sap_ctx, sap_event, + eCSR_BSS_TYPE_INFRA_AP); + } else if (msg == eSAP_CHANNEL_SELECTION_FAILED) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Cannot start BSS, ACS Fail")); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + sap_signal_hdd_event(sap_ctx, NULL, eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_FAILURE); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: BSS stopped when Ch select in Progress", __func__); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_CH_SELECT", msg); + } + + return cdf_status; +} + +/** + * sap_fsm_state_dfs_cac_wait() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_DFS_CAC_WAIT" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_dfs_cac_wait(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + tCsrRoamInfo *roam_info = (tCsrRoamInfo *) (sap_event->params); + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + if (msg == eSAP_DFS_CHANNEL_CAC_START) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_CH_SELECT", "eSAP_DFS_CAC_WAIT"); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) + sap_start_dfs_cac_timer(sap_ctx); + cdf_status = sap_cac_start_notify(hal); + } else if (msg == eSAP_DFS_CHANNEL_CAC_RADAR_FOUND) { + uint8_t intf; + /* + * Radar found while performing channel availability + * check, need to switch the channel again + */ + eCsrPhyMode phymode = sap_ctx->csr_roamProfile.phyMode; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "ENTERTRED CAC WAIT STATE-->eSAP_DISCONNECTING\n"); + if (mac_ctx->sap.SapDfsInfo.target_channel) { + sme_set_ch_params(hal, phymode, + mac_ctx->sap.SapDfsInfo.target_channel, 0, + &sap_ctx->ch_params); + } + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext t_sap_ctx; + if (((CDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (CDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].pSapContext != NULL) { + t_sap_ctx = + mac_ctx->sap.sapCtxList[intf].pSapContext; + /* SAP to be moved to DISCONNECTING state */ + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + /* + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND: + * A Radar is found on current DFS Channel + * while in CAC WAIT period So, do a channel + * switch to randomly selected target channel. + * Send the Channel change message to SME/PE. + * sap_radar_found_status is set to 1 + */ + sap_signal_hdd_event(t_sap_ctx, NULL, + eSAP_DFS_RADAR_DETECT, + (void *)eSAP_STATUS_SUCCESS); + + wlansap_channel_change_request( + (void *)t_sap_ctx, + mac_ctx->sap.SapDfsInfo.target_channel); + } + } + } else if (msg == eSAP_DFS_CHANNEL_CAC_END) { + cdf_status = sap_cac_end_notify(hal, roam_info); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* Transition from eSAP_DFS_CAC_WAIT to eSAP_DISCONNECTING */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_DFS_CAC_WAIT", "eSAP_DISCONNECTING"); + + /* + * Stop the CAC timer only in following conditions + * single AP: if there is a single AP then stop the timer + * mulitple APs: incase of multiple APs, make sure that + * all APs are down. + */ + if (NULL == sap_find_valid_concurrent_session(hal)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: no sessions are valid, stopping timer")); + sap_stop_dfs_cac_timer(sap_ctx); + } + + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + cdf_status = sap_goto_disconnecting(sap_ctx); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_DFS_CAC_WAIT", msg); + } + + return cdf_status; +} + +/** + * sap_fsm_state_starting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_STARTING" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_starting(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + tCsrRoamInfo *roam_info = (tCsrRoamInfo *) (sap_event->params); + tSapDfsInfo *sap_dfs_info; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + if (msg == eSAP_MAC_START_BSS_SUCCESS) { + /* + * Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state channel = %d %s => %s"), + sap_ctx->channel, "eSAP_STARTING", "eSAP_STARTED"); + sap_ctx->sapsMachine = eSAP_STARTED; + + /* Action code for transition */ + cdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + /* + * The upper layers have been informed that AP is up and + * running, however, the AP is still not beaconing, until + * CAC is done if the operating channel is DFS + */ + if (CHANNEL_STATE_DFS == + cds_get_channel_state(sap_ctx->channel)) { + sap_dfs_info = &mac_ctx->sap.SapDfsInfo; + if ((false == sap_dfs_info->ignore_cac) && + (eSAP_DFS_DO_NOT_SKIP_CAC == + sap_dfs_info->cac_state)) { + /* Move the device in CAC_WAIT_STATE */ + sap_ctx->sapsMachine = eSAP_DFS_CAC_WAIT; + + /* + * Need to stop the OS transmit queues, + * so that no traffic can flow down the stack + */ + + /* Start CAC wait timer */ + if (sap_dfs_info->is_dfs_cac_timer_running != + true) + sap_start_dfs_cac_timer(sap_ctx); + cdf_status = sap_cac_start_notify(hal); + + } else { + wlansap_start_beacon_req(sap_ctx); + } + } + } else if (msg == eSAP_MAC_START_FAILS) { + /* + * Transition from STARTING to DISCONNECTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("from state %s => %s"), + "eSAP_STARTING", "eSAP_DISCONNECTED"); + + /*Action code for transition */ + cdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_FAILURE); + cdf_status = sap_goto_disconnected(sap_ctx); + /* Advance outer statevar */ + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from eSAP_STARTING to eSAP_DISCONNECTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTING", "eSAP_DISCONNECTED"); + + /* Advance outer statevar */ + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + cdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_FAILURE); + cdf_status = sap_goto_disconnected(sap_ctx); + /* Close the SME session */ + + if (eSAP_TRUE == sap_ctx->isSapSessionOpen) { + if (CDF_STATUS_SUCCESS == sap_close_session(hal, + sap_ctx, NULL, false)) + sap_ctx->isSapSessionOpen = eSAP_FALSE; + } + } else if (msg == eSAP_OPERATING_CHANNEL_CHANGED) { + /* The operating channel has changed, update hostapd */ + sap_ctx->channel = + (uint8_t) mac_ctx->sap.SapDfsInfo.target_channel; + + sap_ctx->sapsMachine = eSAP_STARTED; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTING", "eSAP_STARTED"); + + /* Indicate change in the state to upper layers */ + cdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_STARTING", msg); + } + + return cdf_status; +} + +/** + * sap_fsm_state_started() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * + * This function is called for state transition from "eSAP_STARTED" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_started(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx) +{ + uint32_t msg = sap_event->event; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from eSAP_STARTED to eSAP_DISCONNECTING + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTED", "eSAP_DISCONNECTING"); + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + cdf_status = sap_goto_disconnecting(sap_ctx); + } else if (eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START == msg) { + uint8_t intf; + /* + * Radar is seen on the current operating channel + * send CSA IE for all associated stations + * Request for CSA IE transmission + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext temp_sap_ctx; + if (((CDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (CDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].pSapContext != NULL) { + temp_sap_ctx = + mac_ctx->sap.sapCtxList[intf].pSapContext; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Sending CSAIE for sapctx[%p]"), + temp_sap_ctx); + + cdf_status = wlansap_dfs_send_csa_ie_request( + (void *) temp_sap_ctx); + } + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_STARTED", msg); + } + + return cdf_status; +} + +/** + * sap_fsm_state_disconnecting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * + * This function is called for state transition from "eSAP_DISCONNECTING" + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_fsm_state_disconnecting(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + + if (msg == eSAP_MAC_READY_FOR_CONNECTIONS) { + /* + * Transition from eSAP_DISCONNECTING to eSAP_DISCONNECTED + * (both without substates) + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_DISCONNECTING", "eSAP_DISCONNECTED"); + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + + /* Close the SME session */ + if (eSAP_TRUE == sap_ctx->isSapSessionOpen) { + sap_ctx->isSapSessionOpen = eSAP_FALSE; + cdf_status = sap_close_session(hal, sap_ctx, + sap_roam_session_close_callback, true); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_STOP_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } + } + } else if (msg == eWNI_SME_CHANNEL_CHANGE_REQ) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Send channel change request on sapctx[%p]"), + sap_ctx); + /* + * Most likely, radar has been detected and SAP wants to + * change the channel + */ + cdf_status = wlansap_channel_change_request((void *) sap_ctx, + mac_ctx->sap.SapDfsInfo.target_channel); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("Sending DFS eWNI_SME_CHANNEL_CHANGE_REQ")); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_DISCONNECTING", msg); + } + + return cdf_status; +} + +/** + * sap_fsm() - SAP statem machine entry function + * @sap_ctx: SAP context + * @sap_event: SAP event + * + * SAP statem machine entry function + * + * Return: CDF_STATUS + */ +CDF_STATUS sap_fsm(ptSapContext sap_ctx, ptWLAN_SAPEvent sap_event) +{ + /* + * Retrieve the phy link state machine structure + * from the sap_ctx value + * state var that keeps track of state machine + */ + eSapFsmStates_t state_var = sap_ctx->sapsMachine; + uint32_t msg = sap_event->event; /* State machine input event message */ + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx; + + if (NULL == hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return CDF_STATUS_E_FAILURE; + } + + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_DEBUG, + FL("sap_ctx=%p, state_var=%d, msg=0x%x"), + sap_ctx, state_var, msg); + + switch (state_var) { + case eSAP_DISCONNECTED: + cdf_status = sap_fsm_state_disconnected(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_CH_SELECT: + cdf_status = sap_fsm_state_ch_select(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_DFS_CAC_WAIT: + cdf_status = sap_fsm_state_dfs_cac_wait(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_STARTING: + cdf_status = sap_fsm_state_starting(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_STARTED: + cdf_status = sap_fsm_state_started(sap_ctx, sap_event, + mac_ctx); + break; + + case eSAP_DISCONNECTING: + cdf_status = sap_fsm_state_disconnecting(sap_ctx, sap_event, + mac_ctx, hal); + break; + } + return cdf_status; +} + +eSapStatus +sapconvert_to_csr_profile(tsap_Config_t *pconfig_params, eCsrRoamBssType bssType, + tCsrRoamProfile *profile) +{ + /* Create Roam profile for SoftAP to connect */ + profile->BSSType = eCSR_BSS_TYPE_INFRA_AP; + profile->SSIDs.numOfSSIDs = 1; + profile->csrPersona = pconfig_params->persona; + profile->disableDFSChSwitch = pconfig_params->disableDFSChSwitch; + + cdf_mem_zero(profile->SSIDs.SSIDList[0].SSID.ssId, + sizeof(profile->SSIDs.SSIDList[0].SSID.ssId)); + + /* Flag to not broadcast the SSID information */ + profile->SSIDs.SSIDList[0].ssidHidden = + pconfig_params->SSIDinfo.ssidHidden; + + profile->SSIDs.SSIDList[0].SSID.length = + pconfig_params->SSIDinfo.ssid.length; + cdf_mem_copy(&profile->SSIDs.SSIDList[0].SSID.ssId, + pconfig_params->SSIDinfo.ssid.ssId, + sizeof(pconfig_params->SSIDinfo.ssid.ssId)); + + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_SHARED_KEY; + } else { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_AUTOSWITCH; + } + + profile->AuthType.numEntries = 1; + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + /* Always set the Encryption Type */ + profile->EncryptionType.numEntries = 1; + profile->EncryptionType.encryptionType[0] = + pconfig_params->RSNEncryptType; + + profile->mcEncryptionType.numEntries = 1; + profile->mcEncryptionType.encryptionType[0] = + pconfig_params->mcRSNEncryptType; + + if (pconfig_params->privacy & eSAP_SHARED_KEY) { + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + } + + profile->privacy = pconfig_params->privacy; + profile->fwdWPSPBCProbeReq = pconfig_params->fwdWPSPBCProbeReq; + + if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->csr80211AuthType = eSIR_SHARED_KEY; + } else if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->csr80211AuthType = eSIR_OPEN_SYSTEM; + } else { + profile->csr80211AuthType = eSIR_AUTO_SWITCH; + } + + /* Initialize we are not going to use it */ + profile->pWPAReqIE = NULL; + profile->nWPAReqIELength = 0; + + /* set the RSN/WPA IE */ + profile->pRSNReqIE = NULL; + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + if (pconfig_params->RSNWPAReqIELength) { + profile->pRSNReqIE = + cdf_mem_malloc(pconfig_params->RSNWPAReqIELength); + if (NULL == profile->pRSNReqIE) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + " %s Fail to alloc memory", __func__); + return eSAP_STATUS_FAILURE; + } + cdf_mem_copy(profile->pRSNReqIE, pconfig_params->RSNWPAReqIE, + pconfig_params->RSNWPAReqIELength); + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + } + /* Turn off CB mode */ + profile->CBMode = eCSR_CB_OFF; + + /* set the phyMode to accept anything */ + /* Best means everything because it covers all the things we support */ + /* eCSR_DOT11_MODE_BEST */ + profile->phyMode = pconfig_params->SapHw_mode; + + /* Configure beaconInterval */ + profile->beaconInterval = (uint16_t) pconfig_params->beacon_int; + + /* set DTIM period */ + profile->dtimPeriod = pconfig_params->dtim_period; + + /* set Uapsd enable bit */ + profile->ApUapsdEnable = pconfig_params->UapsdEnable; + + /* Enable protection parameters */ + profile->protEnabled = pconfig_params->protEnabled; + profile->obssProtEnabled = pconfig_params->obssProtEnabled; + profile->cfg_protection = pconfig_params->ht_capab; + + /* country code */ + if (pconfig_params->countryCode[0]) + cdf_mem_copy(profile->countryCode, pconfig_params->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + profile->ieee80211d = pconfig_params->ieee80211d; + /* wps config info */ + profile->wps_state = pconfig_params->wps_state; + +#ifdef WLAN_FEATURE_11W + /* MFP capable/required */ + profile->MFPCapable = pconfig_params->mfpCapable ? 1 : 0; + profile->MFPRequired = pconfig_params->mfpRequired ? 1 : 0; +#endif + + if (pconfig_params->probeRespIEsBufferLen > 0 && + pconfig_params->pProbeRespIEsBuffer != NULL) { + profile->addIeParams.probeRespDataLen = + pconfig_params->probeRespIEsBufferLen; + profile->addIeParams.probeRespData_buff = + pconfig_params->pProbeRespIEsBuffer; + } else { + profile->addIeParams.probeRespDataLen = 0; + profile->addIeParams.probeRespData_buff = NULL; + } + /*assoc resp IE */ + if (pconfig_params->assocRespIEsLen > 0 && + pconfig_params->pAssocRespIEsBuffer != NULL) { + profile->addIeParams.assocRespDataLen = + pconfig_params->assocRespIEsLen; + profile->addIeParams.assocRespData_buff = + pconfig_params->pAssocRespIEsBuffer; + } else { + profile->addIeParams.assocRespDataLen = 0; + profile->addIeParams.assocRespData_buff = NULL; + } + + if (pconfig_params->probeRespBcnIEsLen > 0 && + pconfig_params->pProbeRespBcnIEsBuffer != NULL) { + profile->addIeParams.probeRespBCNDataLen = + pconfig_params->probeRespBcnIEsLen; + profile->addIeParams.probeRespBCNData_buff = + pconfig_params->pProbeRespBcnIEsBuffer; + } else { + profile->addIeParams.probeRespBCNDataLen = 0; + profile->addIeParams.probeRespBCNData_buff = NULL; + } + profile->sap_dot11mc = pconfig_params->sap_dot11mc; + + return eSAP_STATUS_SUCCESS; /* Success. */ +} + +void sap_free_roam_profile(tCsrRoamProfile *profile) +{ + if (profile->pRSNReqIE) { + cdf_mem_free(profile->pRSNReqIE); + profile->pRSNReqIE = NULL; + } +} + +void sap_sort_mac_list(struct cdf_mac_addr *macList, uint8_t size) +{ + uint8_t outer, inner; + struct cdf_mac_addr temp; + int32_t nRes = -1; + + if ((NULL == macList) || (size > MAX_ACL_MAC_ADDRESS)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is more"), size); + return; + } + + for (outer = 0; outer < size; outer++) { + for (inner = 0; inner < size - 1; inner++) { + nRes = + cdf_mem_compare2((macList + inner)->bytes, + (macList + inner + 1)->bytes, + CDF_MAC_ADDR_SIZE); + if (nRes > 0) { + cdf_mem_copy(temp.bytes, + (macList + inner + 1)->bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy((macList + inner + 1)->bytes, + (macList + inner)->bytes, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy((macList + inner)->bytes, + temp.bytes, CDF_MAC_ADDR_SIZE); + } + } + } +} + +eSapBool +sap_search_mac_list(struct cdf_mac_addr *macList, + uint8_t num_mac, uint8_t *peerMac, + uint8_t *index) +{ + int32_t nRes = -1; + int8_t nStart = 0, nEnd, nMiddle; + nEnd = num_mac - 1; + + if ((NULL == macList) || (num_mac > MAX_ACL_MAC_ADDRESS)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is more."), num_mac); + return eSAP_FALSE; + } + + while (nStart <= nEnd) { + nMiddle = (nStart + nEnd) / 2; + nRes = + cdf_mem_compare2(&macList[nMiddle], peerMac, + CDF_MAC_ADDR_SIZE); + + if (0 == nRes) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "search SUCC"); + /* "index equals NULL" means the caller does not need the */ + /* index value of the peerMac being searched */ + if (index != NULL) { + *index = (uint8_t) nMiddle; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, "index %d", + *index); + } + return eSAP_TRUE; + } + if (nRes < 0) + nStart = nMiddle + 1; + else + nEnd = nMiddle - 1; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "search not succ"); + return eSAP_FALSE; +} + +void sap_add_mac_to_acl(struct cdf_mac_addr *macList, + uint8_t *size, uint8_t *peerMac) +{ + int32_t nRes = -1; + int i; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "add acl entered"); + + if (NULL == macList || *size == 0 || *size > MAX_ACL_MAC_ADDRESS) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is incorrect."), + *size); + return; + } + + for (i = ((*size) - 1); i >= 0; i--) { + nRes = + cdf_mem_compare2(&macList[i], peerMac, CDF_MAC_ADDR_SIZE); + if (nRes > 0) { + /* Move alphabetically greater mac addresses one index down to allow for insertion + of new mac in sorted order */ + cdf_mem_copy((macList + i + 1)->bytes, + (macList + i)->bytes, CDF_MAC_ADDR_SIZE); + } else { + break; + } + } + /* This should also take care of if the element is the first to be added in the list */ + cdf_mem_copy((macList + i + 1)->bytes, peerMac, CDF_MAC_ADDR_SIZE); + /* increment the list size */ + (*size)++; +} + +void sap_remove_mac_from_acl(struct cdf_mac_addr *macList, + uint8_t *size, uint8_t index) +{ + int i; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "remove acl entered"); + /* + * Return if the list passed is empty. Ideally this should never happen + * since this funcn is always called after sap_search_mac_list to get + * the index of the mac addr to be removed and this will only get + * called if the search is successful. Still no harm in having the check + */ + if ((macList == NULL) || (*size == 0) || + (*size > MAX_ACL_MAC_ADDRESS)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size %d is incorrect."), + *size); + return; + } + for (i = index; i < ((*size) - 1); i++) { + /* Move mac addresses starting from "index" passed one index up to delete the void + created by deletion of a mac address in ACL */ + cdf_mem_copy((macList + i)->bytes, (macList + i + 1)->bytes, + CDF_MAC_ADDR_SIZE); + } + /* The last space should be made empty since all mac addesses moved one step up */ + cdf_mem_zero((macList + (*size) - 1)->bytes, CDF_MAC_ADDR_SIZE); + /* reduce the list size by 1 */ + (*size)--; +} + +void sap_print_acl(struct cdf_mac_addr *macList, uint8_t size) +{ + int i; + uint8_t *macArray; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "print acl entered"); + + if ((NULL == macList) || (size == 0) || (size >= MAX_ACL_MAC_ADDRESS)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, either buffer is NULL or size %d is incorrect.", + __func__, size); + return; + } + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "** ACL entry %i - " MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(macArray)); + } + return; +} + +CDF_STATUS sap_is_peer_mac_allowed(ptSapContext sapContext, uint8_t *peerMac) +{ + if (eSAP_ALLOW_ALL == sapContext->eSapMacAddrAclMode) + return CDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->acceptMacList, sapContext->nAcceptMac, peerMac, NULL)) + return CDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->denyMacList, sapContext->nDenyMac, peerMac, NULL)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR " in deny list", + __func__, MAC_ADDR_ARRAY(peerMac)); + return CDF_STATUS_E_FAILURE; + } + /* A new station CAN associate, unless in deny list. Less stringent mode */ + if (eSAP_ACCEPT_UNLESS_DENIED == sapContext->eSapMacAddrAclMode) + return CDF_STATUS_SUCCESS; + + /* A new station CANNOT associate, unless in accept list. More stringent mode */ + if (eSAP_DENY_UNLESS_ACCEPTED == sapContext->eSapMacAddrAclMode) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_DENY_UNLESS_ACCEPTED", + __func__, MAC_ADDR_ARRAY(peerMac)); + return CDF_STATUS_E_FAILURE; + } + + /* The new STA is neither in accept list nor in deny list. In this case, deny the association + * but send a wifi event notification indicating the mac address being denied + */ + if (eSAP_SUPPORT_ACCEPT_AND_DENY == sapContext->eSapMacAddrAclMode) { + sap_signal_hdd_event(sapContext, NULL, eSAP_UNKNOWN_STA_JOIN, + (void *) peerMac); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_SUPPORT_ACCEPT_AND_DENY", + __func__, MAC_ADDR_ARRAY(peerMac)); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +#ifdef SOFTAP_CHANNEL_RANGE +/** + * sap_get_channel_list() - get the list of channels + * @sap_ctx: sap context + * @ch_list: pointer to channel list array + * @num_ch: pointer to number of channels. + * + * This function populates the list of channels for scanning. + * + * Return: CDF_STATUS + */ +static CDF_STATUS sap_get_channel_list(ptSapContext sap_ctx, + uint8_t **ch_list, + uint8_t *num_ch) +{ + uint8_t loop_count; + uint8_t *list; + uint8_t ch_count; + uint8_t start_ch_num, band_start_ch; + uint8_t end_ch_num, band_end_ch; + uint32_t en_lte_coex; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); +#ifdef FEATURE_WLAN_CH_AVOID + uint8_t i; +#endif + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL == hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid HAL pointer from p_cds_gctx")); + *num_ch = 0; + *ch_list = NULL; + return CDF_STATUS_E_FAULT; + } + + start_ch_num = sap_ctx->acs_cfg->start_ch; + end_ch_num = sap_ctx->acs_cfg->end_ch; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("startChannel %d, EndChannel %d, HW:%d"), + start_ch_num, end_ch_num, + sap_ctx->acs_cfg->hw_mode); + + wlansap_extend_to_acs_range(&start_ch_num, &end_ch_num, + &band_start_ch, &band_end_ch); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("expanded startChannel %d,EndChannel %d"), + start_ch_num, end_ch_num); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("band_start_ch %d, band_end_ch %d"), + band_start_ch, band_end_ch); + + sme_cfg_get_int(hal, WNI_CFG_ENABLE_LTE_COEX, &en_lte_coex); + + /* Check if LTE coex is enabled and 2.4GHz is selected */ + if (en_lte_coex && (band_start_ch == RF_CHAN_1) && + (band_end_ch == RF_CHAN_14)) { + /* Set 2.4GHz upper limit to channel 9 for LTE COEX */ + band_end_ch = RF_CHAN_9; + } + + /* Allocate the max number of channel supported */ + list = (uint8_t *) cdf_mem_malloc(NUM_5GHZ_CHANNELS + + NUM_24GHZ_CHANNELS); + if (NULL == list) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Unable to allocate channel list")); + *num_ch = 0; + *ch_list = NULL; + return CDF_STATUS_E_NOMEM; + } + + /* Search for the Active channels in the given range */ + ch_count = 0; + for (loop_count = band_start_ch; loop_count <= band_end_ch; + loop_count++) { + /* go to next channel if rf_channel is out of range */ + if ((start_ch_num > rf_channels[loop_count].channelNum) || + (end_ch_num < rf_channels[loop_count].channelNum)) + continue; + /* + * go to next channel if none of these condition pass + * - DFS scan enabled and chan not in CHANNEL_STATE_DISABLE + * - DFS scan disable but chan in CHANNEL_STATE_ENABLE + */ + if (!(((eSAP_TRUE == mac_ctx->scan.fEnableDFSChnlScan) && + (reg_channels[loop_count].enabled)) || + ((eSAP_FALSE == mac_ctx->scan.fEnableDFSChnlScan) && + (CHANNEL_STATE_ENABLE == + reg_channels[loop_count].enabled)))) + continue; + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++) { + if ((safe_channels[i].channelNumber == + rf_channels[loop_count].channelNum)) { + /* Check if channel is safe */ + if (true == safe_channels[i].isSafe) { +#endif +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t ch; + ch = rf_channels[loop_count].channelNum; + if ((sap_ctx->acs_cfg->skip_scan_status == + eSAP_DO_PAR_ACS_SCAN)) { + if ((ch >= sap_ctx->acs_cfg->skip_scan_range1_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range1_endch) || + (ch >= sap_ctx->acs_cfg->skip_scan_range2_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range2_endch)) { + list[ch_count] = + rf_channels[loop_count].channelNum; + ch_count++; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("%d %d skipped from ACS ch range"), + ch_count, ch); + } + } else { + list[ch_count] = + rf_channels[loop_count].channelNum; + ch_count++; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } +#else + list[ch_count] = rf_channels[loop_count].channelNum; + ch_count++; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + } + break; + } + } +#endif + } + if (0 == ch_count) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("No active channels present for the current region")); + /* + * LTE COEX: channel range outside the restricted 2.4GHz + * band limits + */ + if (en_lte_coex && (start_ch_num > band_end_ch)) + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + FL("SAP can't be started as due to LTE COEX")); + } + + /* return the channel list and number of channels to scan */ + *num_ch = ch_count; + if (ch_count != 0) { + *ch_list = list; + } else { + *ch_list = NULL; + cdf_mem_free(list); + } + + for (loop_count = 0; loop_count < ch_count; loop_count++) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_DEBUG, + FL("channel number: %d"), list[loop_count]); + } + return CDF_STATUS_SUCCESS; +} +#endif + +/* + * Function for initializing list of 2.4/5 Ghz [NON-DFS/DFS] + * available channels in the current regulatory domain. + */ +static CDF_STATUS sap_get5_g_hz_channel_list(ptSapContext sapContext) +{ + uint8_t count = 0; + int i; + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Invalid sapContext pointer on sap_get_channel_list"); + return CDF_STATUS_E_FAULT; + } + + if (sapContext->SapAllChnlList.channelList) { + cdf_mem_free(sapContext->SapAllChnlList.channelList); + sapContext->SapAllChnlList.channelList = NULL; + } + + sapContext->SapAllChnlList.channelList = + (tChannelInfo *) cdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN * + sizeof(tChannelInfo)); + if (NULL == sapContext->SapAllChnlList.channelList) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + " Memory Allocation failed sap_get_channel_list"); + return CDF_STATUS_E_NOMEM; + } + + for (i = RF_CHAN_36; i <= RF_CHAN_165; i++) { + if (reg_channels[i].enabled == CHANNEL_STATE_ENABLE || + reg_channels[i].enabled == CHANNEL_STATE_DFS) { + sapContext->SapAllChnlList.channelList[count].channel = + rf_channels[i].channelNum; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] CHANNEL = %d", __func__, __LINE__, + sapContext->SapAllChnlList.channelList[count]. + channel); + sapContext->SapAllChnlList.channelList[count].valid = + true; + count++; + } + } + + sapContext->SapAllChnlList.numChannel = count; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] NUMBER OF CHANNELS count = %d" + "sapContext->SapAllChnlList.numChannel = %d", + __func__, __LINE__, count, + sapContext->SapAllChnlList.numChannel); + return CDF_STATUS_SUCCESS; +} + +/* + * This function randomly selects the channel to switch after the detection + * of radar + * param sapContext - sap context + * dfs_event - Dfs information from DFS + * return - channel to which AP wishes to switch + */ +uint8_t sap_indicate_radar(ptSapContext sapContext, + tSirSmeDfsEventInd *dfs_event) +{ + uint8_t target_channel = 0; + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (NULL == sapContext || NULL == dfs_event) { + /* Invalid sap context of dfs event passed */ + return 0; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (!dfs_event->dfs_radar_status) { + /*dfs status does not indicate a radar on the channel-- False Alarm */ + return 0; + } + + /* + * SAP needs to generate Channel Switch IE + * if the radar is found in the STARTED state + */ + if (eSAP_STARTED == sapContext->sapsMachine) + pMac->sap.SapDfsInfo.csaIERequired = eSAP_TRUE; + + if (sapContext->csr_roamProfile.disableDFSChSwitch) { + return sapContext->channel; + } + + /* set the Radar Found flag in SapDfsInfo */ + pMac->sap.SapDfsInfo.sap_radar_found_status = true; + + sap_get5_g_hz_channel_list(sapContext); + + if (dfs_event->chan_list.nchannels > SIR_DFS_MAX_20M_SUB_CH) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("nchannels >SIR_DFS_MAX_20M_SUB_CH so resetting")); + dfs_event->chan_list.nchannels = SIR_DFS_MAX_20M_SUB_CH; + } + + sap_mark_dfs_channels(sapContext, dfs_event->chan_list.channels, + dfs_event->chan_list.nchannels, + cds_get_monotonic_boottime()); + + /* + * (1) skip static turbo channel as it will require STA to be in + * static turbo to work. + * (2) skip channel which's marked with radar detction + * (3) WAR: we allow user to config not to use any DFS channel + * (4) When we pick a channel, skip excluded 11D channels + * (5) Create the available channel list with the above rules + */ + + target_channel = sap_random_channel_sel(sapContext); + if (0 == target_channel) { + sap_signal_hdd_event(sapContext, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *) eSAP_STATUS_SUCCESS); + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_WARN, + FL("sapdfs: New selected target channel is [%d]"), + target_channel); + return target_channel; +} + +/* + * CAC timer callback function. + * Post eSAP_DFS_CHANNEL_CAC_END event to sap_fsm(). + */ +void sap_dfs_cac_timer_callback(void *data) +{ + ptSapContext sapContext; + tWLAN_SAPEvent sapEvent; + tHalHandle hHal = (tHalHandle) data; + tpAniSirGlobal pMac; + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return; + } + pMac = PMAC_STRUCT(hHal); + sapContext = sap_find_valid_concurrent_session(hHal); + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s no SAP contexts are found", __func__); + return; + } + + /* Check to ensure that SAP is in DFS WAIT state */ + if (sapContext->sapsMachine == eSAP_DFS_CAC_WAIT) { + cdf_mc_timer_destroy(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + + /* + * CAC Complete, post eSAP_DFS_CHANNEL_CAC_END to sap_fsm + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Sending eSAP_DFS_CHANNEL_CAC_END for target_channel = %d on sapctx[%p]", + sapContext->channel, sapContext); + + sapEvent.event = eSAP_DFS_CHANNEL_CAC_END; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); + } + +} + +/* + * Function to stop the DFS CAC Timer + */ +static int sap_stop_dfs_cac_timer(ptSapContext sapContext) +{ + tHalHandle hHal; + tpAniSirGlobal pMac; + if (sapContext == NULL) + return 0; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (CDF_TIMER_STATE_RUNNING != + cdf_mc_timer_get_current_state(&pMac->sap.SapDfsInfo. + sap_dfs_cac_timer)) { + return 0; + } + + cdf_mc_timer_stop(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + + return 0; +} + + +/** + * sap_is_channel_bonding_etsi_weather_channel() - check weather chan bonding. + * @sap_context: SAP context + * + * Check if the current SAP operating channel is bonded to weather radar + * channel in ETSI domain. + * + * Return: True if bonded to weather channel in ETSI + */ +static bool +sap_is_channel_bonding_etsi_weather_channel(ptSapContext sap_context) +{ + if (IS_CH_BONDING_WITH_WEATHER_CH(sap_context->channel) && + (sap_context->ch_params.ch_width != CH_WIDTH_20MHZ)) + return true; + + return false; +} + +/* + * Function to start the DFS CAC Timer + * when SAP is started on a DFS channel + */ +int sap_start_dfs_cac_timer(ptSapContext sapContext) +{ + CDF_STATUS status; + uint32_t cacTimeOut; + tHalHandle hHal = NULL; + tpAniSirGlobal pMac = NULL; + uint8_t dfs_region; + + if (sapContext == NULL) { + return 0; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (pMac->sap.SapDfsInfo.ignore_cac) { + /* + * If User has set to ignore the CAC + * so, continue without CAC Timer. + */ + return 2; + } + cacTimeOut = DEFAULT_CAC_TIMEOUT; + + cds_get_dfs_region(&dfs_region); + + if ((dfs_region == DFS_ETSI_DOMAIN) + && ((IS_ETSI_WEATHER_CH(sapContext->channel)) || + (sap_is_channel_bonding_etsi_weather_channel(sapContext)))) { + cacTimeOut = ETSI_WEATHER_CH_CAC_TIMEOUT; + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: SAP_DFS_CHANNEL_CAC_START on CH - %d, CAC TIMEOUT - %d sec", + sapContext->channel, cacTimeOut / 1000); + + cdf_mc_timer_init(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer, + CDF_TIMER_TYPE_SW, + sap_dfs_cac_timer_callback, (void *) hHal); + + /*Start the CAC timer */ + status = + cdf_mc_timer_start(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer, + cacTimeOut); + if (status == CDF_STATUS_SUCCESS) { + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + return 1; + } else { + return 0; + } +} + +/* + * This function initializes the NOL list + * parameters required to track the radar + * found DFS channels in the current Reg. Domain . + */ +CDF_STATUS sap_init_dfs_channel_nol_list(ptSapContext sapContext) +{ + uint8_t count = 0; + int i; + bool bFound = false; + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Invalid sapContext pointer on sap_init_dfs_channel_nol_list"); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* to indicate hdd to get cnss dfs nol */ + if (CDF_STATUS_SUCCESS == sap_signal_hdd_event(sapContext, NULL, + eSAP_DFS_NOL_GET, + (void *) + eSAP_STATUS_SUCCESS)) { + bFound = true; + } + + for (i = RF_CHAN_36; i <= RF_CHAN_165; i++) { + if (reg_channels[i].enabled == CHANNEL_STATE_DFS) { + /* if dfs nol is not found, initialize it */ + if (!bFound) { + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .dfs_channel_number = + rf_channels[i].channelNum; + + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + "%s: CHANNEL = %d", __func__, + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[count]. + dfs_channel_number); + + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .radar_status_flag = + eSAP_DFS_CHANNEL_USABLE; + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .radar_found_timestamp = 0; + } + count++; + } + } + + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels = count; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] NUMBER OF DFS CHANNELS = %d", + __func__, __LINE__, + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels); + + return CDF_STATUS_SUCCESS; +} + +/* + * This function will calculate how many interfaces + * have sap persona and returns total number of sap persona. + */ +uint8_t sap_get_total_number_sap_intf(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t intf = 0; + uint8_t intf_count = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + intf_count++; + } + } + return intf_count; +} + +/* + * This function will find the concurrent sap context apart from + * passed sap context and return its channel change ready status + */ +bool is_concurrent_sap_ready_for_channel_change(tHalHandle hHal, + ptSapContext sapContext) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ptSapContext pSapContext; + uint8_t intf = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((CDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (CDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf]. + pSapContext; + if (pSapContext == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("sapCtx matched [%p]"), + sapContext); + continue; + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL + ("concurrent sapCtx[%p] didn't matche with [%p]"), + pSapContext, sapContext); + return pSapContext->is_sap_ready_for_chnl_chng; + } + } + } + return false; +} diff --git a/core/sap/src/sap_fsm_ext.h b/core/sap/src/sap_fsm_ext.h new file mode 100644 index 0000000000..ad98431f29 --- /dev/null +++ b/core/sap/src/sap_fsm_ext.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* This file is generated from btampFsm.cdd - do not edit manually*/ +/* Generated on: Thu Oct 16 15:40:39 PDT 2008 */ + +#ifndef __SAPFSM_EXT_H__ +#define __SAPFSM_EXT_H__ + +/* Events that can be sent to the SAP state-machine */ +typedef enum { + eSAP_TIMER_CONNECT_ACCEPT_TIMEOUT = 0U, + eSAP_MAC_CONNECT_COMPLETED, + eSAP_CHANNEL_SELECTION_FAILED, + eSAP_MAC_CONNECT_INDICATION, + eSAP_MAC_KEY_SET_SUCCESS, + eSAP_RSN_FAILURE, + eSAP_MAC_SCAN_COMPLETE, + eSAP_HDD_START_INFRA_BSS, + eSAP_MAC_READY_FOR_CONNECTIONS, + eSAP_MAC_START_BSS_SUCCESS, + eSAP_MAC_START_BSS_FAILURE, + eSAP_RSN_SUCCESS, + eSAP_MAC_START_FAILS, + eSAP_HDD_STOP_INFRA_BSS, + eSAP_WRITE_REMOTE_AMP_ASSOC, + eSAP_DFS_CHANNEL_CAC_START, + eSAP_DFS_CHANNEL_CAC_RADAR_FOUND, + eSAP_DFS_CHANNEL_CAC_END, + eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START, + eSAP_OPERATING_CHANNEL_CHANGED, + eSAP_CHANNEL_SELECTION_RETRY, + + eSAP_NO_MSG +} eSapMsg_t; + +#endif diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h new file mode 100644 index 0000000000..a94c251c58 --- /dev/null +++ b/core/sap/src/sap_internal.h @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WLANSAP_INTERNAL_H +#define WLAN_QCT_WLANSAP_INTERNAL_H + +/* + * This file contains the internal API exposed by the wlan SAP PAL layer + * module. + */ + +#include "cds_api.h" +#include "cds_packet.h" + +/* Pick up the CSR API definitions */ +#include "csr_api.h" +#include "sap_api.h" +#include "sap_fsm_ext.h" +#include "sap_ch_select.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------- + * Defines + * -------------------------------------------------------------------------*/ +/* DFS Non Occupancy Period =30 minutes, in microseconds */ +#define SAP_DFS_NON_OCCUPANCY_PERIOD (30 * 60 * 1000 * 1000) + +#define SAP_DEBUG +/* Used to enable or disable security on the BT-AMP link */ +#define WLANSAP_SECURITY_ENABLED_STATE true +#ifdef WLAN_FEATURE_MBSSID +/* When MBSSID feature is enabled, SAP context is directly passed to SAP APIs */ +#define CDS_GET_SAP_CB(ctx) (ptSapContext)(ctx) +#else +/* How do I get SAP context from cds context? */ +#define CDS_GET_SAP_CB(ctx) cds_get_context(CDF_MODULE_ID_SAP) +#endif + +#define CDS_GET_HAL_CB(ctx) cds_get_context(CDF_MODULE_ID_PE) +/* MAC Address length */ +#define ANI_EAPOL_KEY_RSN_NONCE_SIZE 32 + +#define IS_ETSI_WEATHER_CH(_ch) ((_ch >= 120) && (_ch <= 130)) +#define IS_CH_BONDING_WITH_WEATHER_CH(_ch) (_ch == 116) +#define IS_CHAN_JAPAN_W53(_ch) ((_ch >= 52) && (_ch <= 64)) +#define IS_CHAN_JAPAN_INDOOR(_ch) ((_ch >= 36) && (_ch <= 64)) +#define IS_CHAN_JAPAN_OUTDOOR(_ch)((_ch >= 100) && (_ch <= 140)) +#define DEFAULT_CAC_TIMEOUT (60 * 1000) /* msecs - 1 min */ +#define ETSI_WEATHER_CH_CAC_TIMEOUT (10 * 60 * 1000) /* msecs - 10 min */ +#define SAP_CHAN_PREFERRED_INDOOR 1 +#define SAP_CHAN_PREFERRED_OUTDOOR 2 + +extern const sRegulatoryChannel *reg_channels; + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +typedef struct sSapContext tSapContext; +/* tSapContext, *ptSapContext; */ +/*---------------------------------------------------------------------------- + * Type Declarations - For internal SAP context information + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Opaque SAP context Type Declaration + * -------------------------------------------------------------------------*/ +/* We were only using this syntax, when this was truly opaque. */ +/* (I.E., it was defined in a different file.) */ + +/* SAP FSM states for Access Point role */ +typedef enum { + eSAP_DISCONNECTED, + eSAP_CH_SELECT, + eSAP_DFS_CAC_WAIT, + eSAP_STARTING, + eSAP_STARTED, + eSAP_DISCONNECTING +} eSapFsmStates_t; + +/*---------------------------------------------------------------------------- + * SAP context Data Type Declaration + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Type Declarations - QOS related + * -------------------------------------------------------------------------*/ +/* SAP QOS config */ +typedef struct sSapQosCfg { + uint8_t WmmIsEnabled; +} tSapQosCfg; + +typedef struct sSapAcsChannelInfo { + uint32_t channelNum; + uint32_t weight; +} tSapAcsChannelInfo; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * Following struct will keep this info in sapCtx struct, and will be used + * to avoid such channels in Random Channel Select in case of radar ind. + */ +struct sap_avoid_channels_info { + bool present; + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +typedef struct sSapContext { + + cdf_mutex_t SapGlobalLock; + + /* Include the current channel of AP */ + uint32_t channel; + uint32_t secondary_ch; + + /* Include the SME(CSR) sessionId here */ + uint8_t sessionId; + + /* Include the key material for this physical link */ + uint8_t key_type; + uint8_t key_length; + uint8_t key_material[32]; + + /* Include the associations MAC addresses */ + uint8_t self_mac_addr[CDS_MAC_ADDRESS_LEN]; + + /* Own SSID */ + uint8_t ownSsid[MAX_SSID_LEN]; + uint32_t ownSsidLen; + + /* Flag for signaling if security is enabled */ + uint8_t ucSecEnabled; + + /* Include the SME(CSR) context here */ + tCsrRoamProfile csr_roamProfile; + uint32_t csr_roamId; + + /* Sap session */ + bool isSapSessionOpen; + + /* SAP event Callback to hdd */ + tpWLAN_SAPEventCB pfnSapEventCallback; + + /* Include the enclosing CDS context here */ + void *p_cds_gctx; + + /* + * Include the state machine structure here, state var that keeps + * track of state machine + */ + eSapFsmStates_t sapsMachine; + + /* Actual storage for AP and self (STA) SSID */ + tCsrSSIDInfo SSIDList[2]; + + /* Actual storage for AP bssid */ + struct cdf_mac_addr bssid; + + /* Mac filtering settings */ + eSapMacAddrACL eSapMacAddrAclMode; + struct cdf_mac_addr acceptMacList[MAX_ACL_MAC_ADDRESS]; + uint8_t nAcceptMac; + struct cdf_mac_addr denyMacList[MAX_ACL_MAC_ADDRESS]; + uint8_t nDenyMac; + + /* QOS config */ + tSapQosCfg SapQosCfg; + + void *pUsrContext; + + uint32_t nStaWPARSnReqIeLength; + uint8_t pStaWpaRsnReqIE[MAX_ASSOC_IND_IE_LEN]; + tSirAPWPSIEs APWPSIEs; + tSirRSNie APWPARSNIEs; + +#ifdef FEATURE_WLAN_WAPI + uint32_t nStaWAPIReqIeLength; + uint8_t pStaWapiReqIE[MAX_ASSOC_IND_IE_LEN]; +#endif + + uint32_t nStaAddIeLength; + uint8_t pStaAddIE[MAX_ASSOC_IND_IE_LEN]; + uint8_t *channelList; + tSapChannelListInfo SapChnlList; + uint16_t ch_width_orig; + chan_params_t ch_params; + + /* session to scan */ + bool isScanSessionOpen; + /* + * This list of channels will hold 5Ghz enabled,DFS in the + * Current RegDomain.This list will be used to select a channel, + * for SAP to start including any DFS channel and also to select + * any random channel[5Ghz-(NON-DFS/DFS)],if SAP is operating + * on a DFS channel and a RADAR is detected on the channel. + */ + tAll5GChannelList SapAllChnlList; + + tSapAcsChannelInfo acsBestChannelInfo; + bool enableOverLapCh; + struct sap_acs_cfg *acs_cfg; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) || \ + defined(WLAN_FEATURE_MBSSID) + bool dfs_ch_disable; +#endif + bool isCacEndNotified; + bool isCacStartNotified; + bool is_sap_ready_for_chnl_chng; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * this struct contains the list of channels on which another MDM AP + * in MCC mode were detected. + */ + struct sap_avoid_channels_info sap_detected_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + /* + * sap_state, sap_status are created + * to inform upper layers about ACS scan status. + * Don't use these members for anyother purposes. + */ + eSapHddEvent sap_state; + eSapStatus sap_status; + uint32_t roc_ind_scan_id; +} *ptSapContext; + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +/* The main per-Physical Link (per WLAN association) context. */ +extern ptSapContext gp_sap_ctx; + +/*---------------------------------------------------------------------------- + * SAP state machine event definition + * -------------------------------------------------------------------------*/ +/* The event structure */ +typedef struct sWLAN_SAPEvent { + /* A VOID pointer type for all possible inputs */ + void *params; + /* State machine input event message */ + uint32_t event; + /* introduced to handle csr_roam_completeCallback roamStatus */ + uint32_t u1; + /* introduced to handle csr_roam_completeCallback roamResult */ + uint32_t u2; +} tWLAN_SAPEvent, *ptWLAN_SAPEvent; + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +CDF_STATUS +wlansap_scan_callback + (tHalHandle halHandle, + void *pContext, + uint8_t sessionId, uint32_t scanID, eCsrScanStatus scanStatus); + +CDF_STATUS +wlansap_pre_start_bss_acs_scan_callback( + tHalHandle hal_handle, + void *pcontext, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status +); + +CDF_STATUS +wlansap_roam_callback + (void *pContext, + tCsrRoamInfo *pCsrRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, eCsrRoamResult roamResult); + +CDF_STATUS wlansap_clean_cb(ptSapContext pSapCtx, uint32_t freeFlag); +CDF_STATUS SapFsm(ptSapContext sapContext, ptWLAN_SAPEvent sapEvent, + uint8_t *status); + +void +wlansap_pmc_full_pwr_req_cb(void *callbackContext, CDF_STATUS status); + +uint8_t sap_select_channel(tHalHandle halHandle, ptSapContext pSapCtx, + tScanResultHandle pScanResult); + +CDF_STATUS +sap_signal_hdd_event(ptSapContext sapContext, + tCsrRoamInfo *pCsrRoamInfo, + eSapHddEvent sapHddevent, void *); + +CDF_STATUS sap_fsm(ptSapContext sapContext, ptWLAN_SAPEvent sapEvent); + +eSapStatus +sapconvert_to_csr_profile(tsap_Config_t *pconfig_params, + eCsrRoamBssType bssType, + tCsrRoamProfile *profile); + +void sap_free_roam_profile(tCsrRoamProfile *profile); + +CDF_STATUS +sap_is_peer_mac_allowed(ptSapContext sapContext, uint8_t *peerMac); + +void +sap_sort_mac_list(struct cdf_mac_addr *macList, uint8_t size); + +void +sap_add_mac_to_acl(struct cdf_mac_addr *macList, uint8_t *size, + uint8_t *peerMac); + +void +sap_remove_mac_from_acl(struct cdf_mac_addr *macList, uint8_t *size, + uint8_t index); + +void +sap_print_acl(struct cdf_mac_addr *macList, uint8_t size); + +eSapBool +sap_search_mac_list(struct cdf_mac_addr *macList, uint8_t num_mac, + uint8_t *peerMac, uint8_t *index); + +CDF_STATUS sap_acquire_global_lock(ptSapContext pSapCtx); + +CDF_STATUS sap_release_global_lock(ptSapContext pSapCtx); + +#ifdef FEATURE_WLAN_CH_AVOID +void sap_update_unsafe_channel_list(ptSapContext pSapCtx); +#endif /* FEATURE_WLAN_CH_AVOID */ + +uint8_t +sap_indicate_radar(ptSapContext sapContext, + tSirSmeDfsEventInd *dfs_event); + +CDF_STATUS sap_init_dfs_channel_nol_list(ptSapContext sapContext); + +bool sap_dfs_is_channel_in_nol_list(ptSapContext sapContext, + uint8_t channelNumber, + ePhyChanBondState chanBondState); +void sap_dfs_cac_timer_callback(void *data); + +void sap_cac_reset_notify(tHalHandle hHal); + +bool sap_acs_channel_check(ptSapContext sapContext, uint8_t channelNumber); + +bool +sap_channel_matrix_check(ptSapContext sapContext, + ePhyChanBondState cbMode, + uint8_t target_channel); + +bool is_concurrent_sap_ready_for_channel_change(tHalHandle hHal, + ptSapContext + sapContext); + +uint8_t sap_get_total_number_sap_intf(tHalHandle hHal); + +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID); + +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, + uint8_t channelID); + +CDF_STATUS sap_goto_channel_sel( + ptSapContext sapContext, + ptWLAN_SAPEvent sapEvent, + bool sap_do_acs_pre_start_bss); + +void sap_config_acs_result(tHalHandle hal, ptSapContext sap_ctx, + uint32_t sec_ch); +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * avoid_channels_info struct + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool +sap_check_in_avoid_ch_list(ptSapContext sap_ctx, uint8_t channel); +#ifdef __cplusplus +} +#endif +#endif diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c new file mode 100644 index 0000000000..5b0e28b4e0 --- /dev/null +++ b/core/sap/src/sap_module.c @@ -0,0 +1,3272 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * =========================================================================== + * sapModule.C + * OVERVIEW: + * This software unit holds the implementation of the WLAN SAP modules + * functions providing EXTERNAL APIs. It is also where the global SAP module + * context gets initialised + * DEPENDENCIES: + * Are listed for each API below. + * =========================================================================== + */ + +/* $Header$ */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "cdf_trace.h" +#include "cdf_util.h" +/* Pick up the sme callback registration API */ +#include "sme_api.h" + +/* SAP API header file */ + +#include "sap_internal.h" +#include "sme_inside.h" +#include "cds_ieee80211_common_i.h" +#include "cds_regdomain_common.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +/* No! Get this from CDS. */ +/* The main per-Physical Link (per WLAN association) context. */ +ptSapContext gp_sap_ctx; + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/** + * wlansap_open() - WLAN SAP open function call + * @p_cds_gctx: Pointer to the global cds context; a handle to SAP's + * + * Called at driver initialization (cds_open). SAP will initialize + * all its internal resources and will wait for the call to start to + * register with the other modules. + * + * Return: The result code associated with performing the operation + * + * #ifdef WLAN_FEATURE_MBSSID + * void *: Pointer to the SAP context + * #else + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL ; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + * #endif + */ +#ifdef WLAN_FEATURE_MBSSID +void * +#else +CDF_STATUS +#endif +wlansap_open(void *p_cds_gctx) { + ptSapContext pSapCtx = NULL; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +#ifdef WLAN_FEATURE_MBSSID + /* amically allocate the sapContext */ + pSapCtx = (ptSapContext) cdf_mem_malloc(sizeof(tSapContext)); +#else + if (NULL == p_cds_gctx) { + CDF_ASSERT(p_cds_gctx); + return CDF_STATUS_E_NOMEM; + } + /*------------------------------------------------------------------------ + Allocate (and sanity check?!) SAP control block + ------------------------------------------------------------------------*/ + cds_alloc_context(p_cds_gctx, CDF_MODULE_ID_SAP, (void **)&pSapCtx, + sizeof(tSapContext)); +#endif + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); +#ifdef WLAN_FEATURE_MBSSID + return NULL; +#else + return CDF_STATUS_E_FAULT; +#endif + } + + cdf_mem_zero(pSapCtx, sizeof(tSapContext)); + + /*------------------------------------------------------------------------ + Clean up SAP control block, initialize all values + ------------------------------------------------------------------------*/ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, "wlansap_open"); + + wlansap_clean_cb(pSapCtx, 0); /*do not empty */ + + /* Setup the "link back" to the CDS context */ + pSapCtx->p_cds_gctx = p_cds_gctx; + + /* Store a pointer to the SAP context provided by CDS */ + gp_sap_ctx = pSapCtx; + + /*------------------------------------------------------------------------ + Allocate internal resources + ------------------------------------------------------------------------*/ + +#ifdef WLAN_FEATURE_MBSSID + return pSapCtx; +#else + return CDF_STATUS_SUCCESS; +#endif +} /* wlansap_open */ + +/** + * wlansap_start() - wlan start SAP. + * @pCtx: Pointer to the global cds context; a handle to SAP's + * control block can be extracted from its context + * When MBSSID feature is enabled, SAP context is directly + * passed to SAP APIs + * + * Called as part of the overall start procedure (cds_enable). SAP will + * use this call to register with TL as the SAP entity for SAP RSN frames. + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault. + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_start(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start invoked successfully"); + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + For now, presume security is not enabled. + -----------------------------------------------------------------------*/ + pSapCtx->ucSecEnabled = WLANSAP_SECURITY_ENABLED_STATE; + + /*------------------------------------------------------------------------ + Now configure the roaming profile links. To SSID and bssid. + ------------------------------------------------------------------------*/ + /* We have room for two SSIDs. */ + pSapCtx->csr_roamProfile.SSIDs.numOfSSIDs = 1; /* This is true for now. */ + pSapCtx->csr_roamProfile.SSIDs.SSIDList = pSapCtx->SSIDList; /* Array of two */ + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].SSID.length = 0; + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].handoffPermitted = false; + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].ssidHidden = + pSapCtx->SSIDList[0].ssidHidden; + + pSapCtx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; /* This is true for now. */ + pSapCtx->csr_roamProfile.BSSIDs.bssid = &pSapCtx->bssid; + + /* Now configure the auth type in the roaming profile. To open. */ + pSapCtx->csr_roamProfile.negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; /* open is the default */ + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_init(&pSapCtx->SapGlobalLock))) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "wlansap_start failed init lock"); + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_stop() - stop SAP module. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs + * + * Called by cds_disable to stop operation in SAP, before close. SAP will + * suspend all BT-AMP Protocol Adaption Layer operation and will wait for the + * close request to clean up its resources. + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault. + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_stop(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_stop invoked successfully "); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sap_free_roam_profile(&pSapCtx->csr_roamProfile); + + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_destroy(&pSapCtx->SapGlobalLock))) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "wlansap_stop failed destroy lock"); + return CDF_STATUS_E_FAULT; + } + /*------------------------------------------------------------------------ + Stop SAP (de-register RSN handler!?) + ------------------------------------------------------------------------*/ + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_close - close SAP module. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * Called by cds_close during general driver close procedure. SAP will clean up + * all the internal resources. + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_close(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_close invoked"); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + Cleanup SAP control block. + ------------------------------------------------------------------------*/ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_close"); + wlansap_clean_cb(pSapCtx, + true); /* empty queues/lists/pkts if any */ + +#ifdef WLAN_FEATURE_MBSSID + cdf_mem_free(pSapCtx); +#else + /*------------------------------------------------------------------------ + Free SAP context from CDS global + ------------------------------------------------------------------------*/ + cds_free_context(pCtx, CDF_MODULE_ID_SAP, pSapCtx); +#endif + + return CDF_STATUS_SUCCESS; +} /* wlansap_close */ + +/*---------------------------------------------------------------------------- + * Utility Function implementations + * -------------------------------------------------------------------------*/ + +/** + * wlansap_clean_cb() - clean SAP callback function. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * Clear out all fields in the SAP context. + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_clean_cb(ptSapContext pSapCtx, uint32_t freeFlag /* 0 / *do not empty* /); */ + ) { + /*------------------------------------------------------------------------ + Sanity check SAP control block + ------------------------------------------------------------------------*/ + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + Clean up SAP control block, initialize all values + ------------------------------------------------------------------------*/ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_clean_cb"); + + cdf_mem_zero(pSapCtx, sizeof(tSapContext)); + + pSapCtx->p_cds_gctx = NULL; + + pSapCtx->sapsMachine = eSAP_DISCONNECTED; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing State: %d, sapContext value = %p", __func__, + pSapCtx->sapsMachine, pSapCtx); + pSapCtx->sessionId = 0; + pSapCtx->channel = 0; + pSapCtx->isSapSessionOpen = eSAP_FALSE; + + return CDF_STATUS_SUCCESS; +} /* wlansap_clean_cb */ + +/*========================================================================== + FUNCTION wlansap_pmc_full_pwr_req_cb + + DESCRIPTION + Callback provide to PMC in the pmc_request_full_power API. + + DEPENDENCIES + + PARAMETERS + + IN + callbackContext: The user passed in a context to identify + status: The cdf_ret_status + + RETURN VALUE + None + + SIDE EFFECTS + ============================================================================*/ +void +wlansap_pmc_full_pwr_req_cb(void *callbackContext, CDF_STATUS status) +{ + if (CDF_IS_STATUS_SUCCESS(status)) { + /* If success what else to be handled??? */ + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "wlansap_pmc_full_pwr_req_cb: PMC failed to put the chip in Full power"); + + } + +} /* wlansap_pmc_full_pwr_req_cb */ + +/** + * wlansap_get_state() - get SAP state + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api returns the current SAP state to the caller. + * + * Return: uint8_t - the SAP FSM state. + */ +uint8_t wlansap_get_state(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + return pSapCtx->sapsMachine; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/*========================================================================== + FUNCTION wlansap_check_cc_intf + + DESCRIPTION Restart SAP if Concurrent Channel interfering + + DEPENDENCIES NA. + + PARAMETERS + IN + Ctx: Pointer to cds Context or Sap Context based on MBSSID + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +uint16_t wlansap_check_cc_intf(void *Ctx) +{ + tHalHandle hHal; + uint16_t intf_ch; + ptSapContext pSapCtx = CDS_GET_SAP_CB(Ctx); + + hHal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context from p_cds_gctx", __func__); + return 0; + } + intf_ch = sme_check_concurrent_channel_overlap(hHal, 0, 0, + pSapCtx->cc_switch_mode); + return intf_ch; +} +#endif + + /** + * wlansap_set_scan_acs_channel_params() - Config scan and channel parameters. + * pconfig: Pointer to the SAP config + * psap_ctx: Pointer to the SAP Context. + * pusr_context: Parameter that will be passed + * back in all the SAP callback events. + * + * This api function is used to copy Scan and Channel parameters from sap + * config to sap context. + * + * Return: The result code associated with + * performing the operation + */ +CDF_STATUS +wlansap_set_scan_acs_channel_params(tsap_Config_t *pconfig, + ptSapContext psap_ctx, + void *pusr_context) +{ + tHalHandle h_hal = NULL; + + if (NULL == pconfig) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return CDF_STATUS_E_FAULT; + } + + if (NULL == psap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return CDF_STATUS_E_FAULT; + } + + /* Channel selection is auto or configured */ + psap_ctx->channel = pconfig->channel; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + psap_ctx->cc_switch_mode = pconfig->cc_switch_mode; +#endif + psap_ctx->pUsrContext = pusr_context; + psap_ctx->enableOverLapCh = pconfig->enOverLapCh; + psap_ctx->acs_cfg = &pconfig->acs_cfg; + psap_ctx->ch_width_orig = pconfig->acs_cfg.ch_width; + psap_ctx->secondary_ch = pconfig->sec_ch; + + /* + * Set the BSSID to your "self MAC Addr" read + * the mac address from Configuation ITEM received + * from HDD + */ + psap_ctx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + cdf_mem_copy(psap_ctx->csr_roamProfile.BSSIDs.bssid, + psap_ctx->self_mac_addr, + sizeof(struct cdf_mac_addr)); + + /* + * Save a copy to SAP context + */ + cdf_mem_copy(psap_ctx->csr_roamProfile.BSSIDs.bssid, + pconfig->self_macaddr.bytes, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(psap_ctx->self_mac_addr, + pconfig->self_macaddr.bytes, CDF_MAC_ADDR_SIZE); + + h_hal = (tHalHandle)CDS_GET_HAL_CB(psap_ctx->p_cds_gctx); + if (NULL == h_hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from pvosGCtx", __func__); + } else { + /* + * If concurrent session is running that is already associated + * then we just follow that sessions country info (whether + * present or not doesn't maater as we have to follow whatever + * STA session does) + */ + if ((0 == sme_get_concurrent_operation_channel(h_hal)) && + pconfig->ieee80211d) { + /* Setting the region/country information */ + sme_set_reg_info(h_hal, pconfig->countryCode); + sme_apply_channel_power_info_to_fw(h_hal); + } + } + + return CDF_STATUS_SUCCESS; +} +/** + * wlan_sap_get_vht_ch_width() - Returns SAP VHT channel width. + * @ctx: Pointer to cds Context or Sap Context based on MBSSID + * + * This function provides the SAP current VHT channel with. + * + * Return: VHT channel width + */ +uint32_t wlan_sap_get_vht_ch_width(void *ctx) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return 0; + } + + return sap_ctx->ch_params.ch_width; +} + +/** + * wlan_sap_set_vht_ch_width() - Sets SAP VHT channel width. + * @ctx: Pointer to cds Context or Sap Context based on MBSSID + * @vht_channel_width: SAP VHT channel width value. + * + * This function sets the SAP current VHT channel with. + * + * Return: None + */ +void wlan_sap_set_vht_ch_width(void *ctx, uint32_t vht_channel_width) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return; + } + + sap_ctx->ch_params.ch_width = vht_channel_width; +} + +/** + * wlansap_start_bss() - start BSS + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pQctCommitConfig: Pointer to configuration structure passed down from + * HDD(HostApd for Android) + * @hdd_SapEventCallback: Callback function in HDD called by SAP to inform HDD + * about SAP results + * @pUsrContext: Parameter that will be passed back in all the SAP callback + * events. + * + * This api function provides SAP FSM event eWLAN_SAP_PHYSICAL_LINK_CREATE for + * starting AP BSS + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_start_bss(void *pCtx, /* pwextCtx */ + tpWLAN_SAPEventCB pSapEventCallback, + tsap_Config_t *pConfig, void *pUsrContext) { + tWLAN_SAPEvent sapEvent; /* State machine event */ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + tHalHandle hHal; + tpAniSirGlobal pmac = NULL; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start_bss: sapContext=%p", pSapCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + pSapCtx->sapsMachine = eSAP_DISCONNECTED; + + /* Channel selection is auto or configured */ + pSapCtx->channel = pConfig->channel; + pSapCtx->ch_params.ch_width = pConfig->ch_params.ch_width; + pSapCtx->ch_params.center_freq_seg0 = + pConfig->ch_params.center_freq_seg0; + pSapCtx->ch_params.center_freq_seg1 = + pConfig->ch_params.center_freq_seg1; + pSapCtx->ch_params.sec_ch_offset = + pConfig->ch_params.sec_ch_offset; + pSapCtx->ch_width_orig = pConfig->ch_width_orig; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pSapCtx->cc_switch_mode = pConfig->cc_switch_mode; +#endif + pSapCtx->pUsrContext = pUsrContext; + pSapCtx->enableOverLapCh = pConfig->enOverLapCh; + pSapCtx->acs_cfg = &pConfig->acs_cfg; + /* Set the BSSID to your "self MAC Addr" read the mac address from Configuation ITEM received from HDD */ + pSapCtx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + cdf_mem_copy(pSapCtx->csr_roamProfile.BSSIDs.bssid, + pSapCtx->self_mac_addr, sizeof(struct cdf_mac_addr)); + + /* Save a copy to SAP context */ + cdf_mem_copy(pSapCtx->csr_roamProfile.BSSIDs.bssid, + pConfig->self_macaddr.bytes, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(pSapCtx->self_mac_addr, + pConfig->self_macaddr.bytes, CDF_MAC_ADDR_SIZE); + + /* copy the configuration items to csrProfile */ + sapconvert_to_csr_profile(pConfig, eCSR_BSS_TYPE_INFRA_AP, + &pSapCtx->csr_roamProfile); + hHal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } else { + /* If concurrent session is running that is already associated */ + /* then we just follow that sessions country info (whether */ + /* present or not doesn't maater as we have to follow whatever */ + /* STA session does) */ + if ((0 == sme_get_concurrent_operation_channel(hHal)) && + pConfig->ieee80211d) { + /* Setting the region/country information */ + sme_set_reg_info(hHal, pConfig->countryCode); + sme_apply_channel_power_info_to_fw(hHal); + } + } + + pmac = PMAC_STRUCT(hHal); + if (NULL == pmac) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + /* + * Copy the DFS Test Mode setting to pmac for + * access in lower layers + */ + pmac->sap.SapDfsInfo.disable_dfs_ch_switch = + pConfig->disableDFSChSwitch; + + /* Copy MAC filtering settings to sap context */ + pSapCtx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + cdf_mem_copy(pSapCtx->acceptMacList, pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + pSapCtx->nAcceptMac = pConfig->num_accept_mac; + sap_sort_mac_list(pSapCtx->acceptMacList, pSapCtx->nAcceptMac); + cdf_mem_copy(pSapCtx->denyMacList, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + pSapCtx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(pSapCtx->denyMacList, pSapCtx->nDenyMac); + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_START_INFRA_BSS; + sapEvent.params = 0; /* pSapPhysLinkCreate */ + + /* Store the HDD callback in SAP context */ + pSapCtx->pfnSapEventCallback = pSapEventCallback; + + /* Handle event */ + cdf_status = sap_fsm(pSapCtx, &sapEvent); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "SoftAp role has not been enabled"); + } + + return cdf_status; +} /* wlansap_start_bss */ + +/** + * wlansap_set_mac_acl() - set MAC list entry in ACL. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pConfig: Pointer to SAP config. + * + * This api function provides SAP to set mac list entry in accept list as well + * as deny list + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_set_mac_acl(void *pCtx, /* pwextCtx */ + tsap_Config_t *pConfig) { + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_set_mac_acl"); + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + /* Copy MAC filtering settings to sap context */ + pSapCtx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + + if (eSAP_DENY_UNLESS_ACCEPTED == pSapCtx->eSapMacAddrAclMode) { + cdf_mem_copy(pSapCtx->acceptMacList, + pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + pSapCtx->nAcceptMac = pConfig->num_accept_mac; + sap_sort_mac_list(pSapCtx->acceptMacList, + pSapCtx->nAcceptMac); + } else if (eSAP_ACCEPT_UNLESS_DENIED == + pSapCtx->eSapMacAddrAclMode) { + cdf_mem_copy(pSapCtx->denyMacList, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + pSapCtx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(pSapCtx->denyMacList, pSapCtx->nDenyMac); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s : SoftAp role has not been enabled", __func__); + return CDF_STATUS_E_FAULT; + } + + return cdf_status; +} /* wlansap_set_mac_acl */ + +/** + * wlansap_stop_bss() - stop BSS. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides SAP FSM event eSAP_HDD_STOP_INFRA_BSS for + * stopping AP BSS + * + * Return: The result code associated with performing the operation + * CDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_stop_bss(void *pCtx) +{ + tWLAN_SAPEvent sapEvent; /* State machine event */ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid Global CDS handle", __func__); + return CDF_STATUS_E_FAULT; + } + + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_STOP_INFRA_BSS; + sapEvent.params = 0; + + /* Handle event */ + cdf_status = sap_fsm(pSapCtx, &sapEvent); + + return cdf_status; +} + +/** + * wlansap_get_assoc_stations() - get list of associated stations. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @modId: Module from whom list of associtated stations is supposed to be + * probed. If an invalid module is passed then by default + * CDF_MODULE_ID_PE will be probed + * @pAssocStas: Pointer to list of associated stations that are known to the + * module specified in mod parameter + * + * This api function is used to probe the list of associated stations from + * various modules of CORE stack + * NOTE: The memory for this list will be allocated by the caller of this API + * + * Return: The result code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS +wlansap_get_assoc_stations + (void *pCtx, CDF_MODULE_ID modId, tpSap_AssocMacAddr pAssocStas) { + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sme_roam_get_associated_stas(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, modId, + pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + (uint8_t *) pAssocStas); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_remove_wps_session_overlap() - remove overlapping wps session. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pRemoveMac: pointer to struct cdf_mac_addr for session MAC address + * + * This api function provides for Ap App/HDD to remove an entry from session + * overlap info. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + * CDF_STATUS_E_FAULT: Session is not dectected. + * The parameter is function not valid. + */ +CDF_STATUS +wlansap_remove_wps_session_overlap(void *pCtx, + struct cdf_mac_addr pRemoveMac) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sme_roam_get_wps_session_overlap(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + pRemoveMac); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_get_wps_session_overlap() - get overlapping wps session. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides for Ap App/HDD to get WPS session overlap info. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_get_wps_session_overlap(void *pCtx) +{ + struct cdf_mac_addr pRemoveMac = CDF_MAC_ADDR_ZERO_INITIALIZER; + + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sme_roam_get_wps_session_overlap(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + pRemoveMac); + + return CDF_STATUS_SUCCESS; +} + +/* This routine will set the mode of operation for ACL dynamically*/ +CDF_STATUS wlansap_set_mode(void *pCtx, uint32_t mode) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + pSapCtx->eSapMacAddrAclMode = (eSapMacAddrACL) mode; + return CDF_STATUS_SUCCESS; +} + +/* Get ACL Mode */ +CDF_STATUS wlansap_get_acl_mode(void *pCtx, eSapMacAddrACL *mode) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + *mode = pSapCtx->eSapMacAddrAclMode; + return CDF_STATUS_SUCCESS; +} + +/* API to get ACL Accept List */ +CDF_STATUS +wlansap_get_acl_accept_list(void *pCtx, struct cdf_mac_addr *pAcceptList, + uint8_t *nAcceptList) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + + memcpy((void *)pAcceptList, (void *)pSapCtx->acceptMacList, + (pSapCtx->nAcceptMac * CDF_MAC_ADDR_SIZE)); + *nAcceptList = pSapCtx->nAcceptMac; + return CDF_STATUS_SUCCESS; +} + +/* API to get Deny List */ +CDF_STATUS +wlansap_get_acl_deny_list(void *pCtx, struct cdf_mac_addr *pDenyList, + uint8_t *nDenyList) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + + memcpy((void *)pDenyList, (void *)pSapCtx->denyMacList, + (pSapCtx->nDenyMac * CDF_MAC_ADDR_SIZE)); + *nDenyList = pSapCtx->nDenyMac; + return CDF_STATUS_SUCCESS; +} + +/* This routine will clear all the entries in accept list as well as deny list */ + +CDF_STATUS wlansap_clear_acl(void *pCtx) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + uint8_t i; + + if (NULL == pSapCtx) { + return CDF_STATUS_E_RESOURCES; + } + + if (pSapCtx->denyMacList != NULL) { + for (i = 0; i < (pSapCtx->nDenyMac - 1); i++) { + cdf_mem_zero((pSapCtx->denyMacList + i)->bytes, + CDF_MAC_ADDR_SIZE); + + } + } + sap_print_acl(pSapCtx->denyMacList, pSapCtx->nDenyMac); + pSapCtx->nDenyMac = 0; + + if (pSapCtx->acceptMacList != NULL) { + for (i = 0; i < (pSapCtx->nAcceptMac - 1); i++) { + cdf_mem_zero((pSapCtx->acceptMacList + i)->bytes, + CDF_MAC_ADDR_SIZE); + + } + } + sap_print_acl(pSapCtx->acceptMacList, pSapCtx->nAcceptMac); + pSapCtx->nAcceptMac = 0; + + return CDF_STATUS_SUCCESS; +} + +/* + * wlansap_modify_acl() -Update ACL entries + * + * @ctx: Global context + * @peer_sta_mac: peer sta mac to be updated. + * @list_type: white/Black list type. + * @cmd: command to be executed on ACL. + * + * This function is called when a peer needs to be added or deleted from the + * white/black ACL + * + * Return: Status + */ + +CDF_STATUS +wlansap_modify_acl + (void *ctx, + uint8_t *peer_sta_mac, eSapACLType list_type, eSapACLCmdType cmd) { + eSapBool sta_white_list = eSAP_FALSE, sta_black_list = eSAP_FALSE; + uint8_t staWLIndex, staBLIndex; + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (NULL == sap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP Context", __func__); + return CDF_STATUS_E_FAULT; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "Modify ACL entered\n" "Before modification of ACL\n" + "size of accept and deny lists %d %d", sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + + /* the expectation is a mac addr will not be in both the lists at the same time. + It is the responsiblity of userspace to ensure this */ + sta_white_list = + sap_search_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac, + peer_sta_mac, &staWLIndex); + sta_black_list = + sap_search_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac, + peer_sta_mac, &staBLIndex); + + if (sta_white_list && sta_black_list) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Peer mac " MAC_ADDRESS_STR + " found in white and black lists." + "Initial lists passed incorrect. Cannot execute this command.", + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_E_FAILURE; + + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "cmd %d", cmd); + + switch (list_type) { + case eSAP_WHITE_LIST: + if (cmd == ADD_STA_TO_ACL) { + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nAcceptMac == MAX_ACL_MAC_ADDRESS) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "White list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_E_FAILURE; + } + if (sta_white_list) { + /* Do nothing if already present in white list. Just print a warning */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "MAC address already present in white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_SUCCESS; + } + if (sta_black_list) { + /* remove it from black list before adding to the white list */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "STA present in black list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx-> + denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + } + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "... Now add to the white list"); + sap_add_mac_to_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + peer_sta_mac); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_white_list) { + + struct tagCsrDelStaParams delStaParams; + + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "Delete from white list"); + sap_remove_mac_from_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + staWLIndex); + /* If a client is deleted from white list and it is connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(ctx, &delStaParams); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_E_FAILURE; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return CDF_STATUS_E_FAILURE; + } + break; + + case eSAP_BLACK_LIST: + + if (cmd == ADD_STA_TO_ACL) { + struct tagCsrDelStaParams delStaParams; + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nDenyMac == MAX_ACL_MAC_ADDRESS) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "Black list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_E_FAILURE; + } + if (sta_black_list) { + /* Do nothing if already present in white list */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "MAC address already present in black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_SUCCESS; + } + if (sta_white_list) { + /* remove it from white list before adding to the black list */ + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "Present in white list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx-> + acceptMacList, + &sap_ctx-> + nAcceptMac, + staWLIndex); + } + /* If we are adding a client to the black list; if its connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(ctx, &delStaParams); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "... Now add to black list"); + sap_add_mac_to_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, peer_sta_mac); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_black_list) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO, + "Delete from black list"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + "no accept and deny mac %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return CDF_STATUS_E_FAILURE; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return CDF_STATUS_E_FAILURE; + } + break; + + default: + { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Invalid list type passed %d", list_type); + return CDF_STATUS_E_FAILURE; + } + } + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_LOW, + "After modification of ACL"); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_disassoc_sta() - initiate disassociation of station. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pPeerStaMac: Mac address of the station to disassociate + * + * This api function provides for Ap App/HDD initiated disassociation of station + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_disassoc_sta(void *pCtx, const uint8_t *pPeerStaMac) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sme_roam_disconnect_sta(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pPeerStaMac); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_deauth_sta() - Ap App/HDD initiated deauthentication of station + * @pCtx : Pointer to the global cds context; a handle to SAP's + * control block can be extracted from its context + * When MBSSID feature is enabled, SAP context is directly + * passed to SAP APIs + * @pDelStaParams : Pointer to parameters of the station to deauthenticate + * + * This api function provides for Ap App/HDD initiated deauthentication of + * station + * + * Return: The CDF_STATUS code associated with performing the operation + */ +CDF_STATUS wlansap_deauth_sta(void *pCtx, + struct tagCsrDelStaParams *pDelStaParams) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + CDF_STATUS cdf_status = CDF_STATUS_E_FAULT; + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return cdf_status; + } + + cdf_ret_status = + sme_roam_deauth_sta(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pDelStaParams); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + cdf_status = CDF_STATUS_SUCCESS; + } + return cdf_status; +} + +/*========================================================================== + FUNCTION wlansap_set_channel_change_with_csa + + DESCRIPTION + This api function does a channel change to the target channel specified + through an iwpriv. CSA IE is included in the beacons before doing a + channel change. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + p_cds_gctx : Pointer to cds global context structure + targetChannel : New target channel to change to. + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS +wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel) +{ + + ptSapContext sapContext = NULL; + tWLAN_SAPEvent sapEvent; + tpAniSirGlobal pMac = NULL; + void *hHal = NULL; + + sapContext = CDS_GET_SAP_CB(p_cds_gctx); + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* + * Now, validate if the passed channel is valid in the + * current regulatory domain. + */ + if (sapContext->channel != targetChannel && + ((cds_get_channel_state(targetChannel) == + CHANNEL_STATE_ENABLE) || + (cds_get_channel_state(targetChannel) == + CHANNEL_STATE_DFS && + !cds_concurrent_open_sessions_running()))) { + /* + * Post a CSA IE request to SAP state machine with + * target channel information and also CSA IE required + * flag set in sapContext only, if SAP is in eSAP_STARTED + * state. + */ + if (eSAP_STARTED == sapContext->sapsMachine) { + /* + * Copy the requested target channel + * to sap context. + */ + pMac->sap.SapDfsInfo.target_channel = targetChannel; + /* + * TODO: need to identify the allowed channel width and + * bonding mode. + */ + pMac->sap.SapDfsInfo.new_chanWidth = 0; + pMac->sap.SapDfsInfo.new_cbMode = 0; + + /* + * Set the CSA IE required flag. + */ + pMac->sap.SapDfsInfo.csaIERequired = true; + + /* + * Set the radar found status to allow the channel + * change to happen same as in the case of a radar + * detection. Since, this will allow SAP to be in + * correct state and also resume the netif queues + * that were suspended in HDD before the channel + * request was issued. + */ + pMac->sap.SapDfsInfo.sap_radar_found_status = true; + + /* + * Post the eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START + * to SAP state machine to process the channel + * request with CSA IE set in the beacons. + */ + sapEvent.event = + eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); + + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Failed to request Channel Change, since" + "SAP is not in eSAP_STARTED state", __func__); + return CDF_STATUS_E_FAULT; + } + + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Channel = %d is not valid in the current" + "regulatory domain", __func__, targetChannel); + + return CDF_STATUS_E_FAULT; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: Posted eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START" + "successfully to sap_fsm for Channel = %d", + __func__, targetChannel); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_counter_measure() - set counter measure. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @bEnable: If true than all stations will be disassociated and no more + * will be allowed to associate. If false than CORE will come out + * of this state. + * + * This api function is used to disassociate all the stations and prevent + * association for any other station.Whenever Authenticator receives 2 mic + * failures within 60 seconds, Authenticator will enable counter measure at + * SAP Layer. Authenticator will start the 60 seconds timer. Core stack will + * not allow any STA to associate till HDD disables counter meassure. Core + * stack shall kick out all the STA which are currently associated and DIASSOC + * Event will be propogated to HDD for each STA to clean up the HDD STA table. + * Once the 60 seconds timer expires, Authenticator will disable the counter + * meassure at core stack. Now core stack can allow STAs to associate. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_set_counter_measure(void *pCtx, bool bEnable) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + sme_roam_tkip_counter_measures(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, bEnable); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_key_sta() - set keys for a stations. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pSetKeyInfo : tCsrRoamSetKey structure for the station + * + * This api function provides for Ap App/HDD to set key for a station. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_set_key_sta(void *pCtx, tCsrRoamSetKey *pSetKeyInfo) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + uint32_t roamId = 0xFF; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + cdf_ret_status = + sme_roam_set_key(hHal, pSapCtx->sessionId, pSetKeyInfo, + &roamId); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + cdf_status = CDF_STATUS_SUCCESS; + } else { + cdf_status = CDF_STATUS_E_FAULT; + } + } else + cdf_status = CDF_STATUS_E_FAULT; + + return cdf_status; +} + +/** + * wlan_sap_getstation_ie_information() - RSNIE Population + * + * @ctx: Global context + * @len: Length of @buf + * @buf: RSNIE IE data + * + * Populate RSN IE from CSR to HDD context + * + * Return: CDF_STATUS enumeration + */ + +CDF_STATUS +wlan_sap_getstation_ie_information + (void *ctx, uint32_t *len, uint8_t *buf) { + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = NULL; + uint32_t ie_len = 0; + tCDF_CON_MODE mode; + + mode = cds_get_conparam(); + if (CDF_SAP_MODE != mode) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%d: called in wrong mode ", + mode); + return CDF_STATUS_E_FAULT; + } + + sap_ctx = CDS_GET_SAP_CB(ctx); + if (NULL == sap_ctx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from pCtx")); + return CDF_STATUS_E_FAULT; + } + + if (len) { + ie_len = *len; + *len = sap_ctx->nStaWPARSnReqIeLength; + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("WPAIE len : %x"), *len); + if ((buf) && (ie_len >= sap_ctx->nStaWPARSnReqIeLength)) { + cdf_mem_copy(buf, + sap_ctx->pStaWpaRsnReqIE, + sap_ctx->nStaWPARSnReqIeLength); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL("WPAIE: %02x:%02x:%02x:%02x:%02x:%02x"), + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5]); + cdf_status = CDF_STATUS_SUCCESS; + } + } + return cdf_status; +} + +/** + * wlansap_set_wps_ie() - set WPI IE + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pWPSIE: tSap_WPSIE structure that include WPS IEs + * + * This api function provides API for App/HDD to set WPS IE. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise. + */ +CDF_STATUS wlansap_set_wps_ie(void *pCtx, tSap_WPSIE *pSap_WPSIe) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s, %d", __func__, __LINE__); + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + + if (sap_acquire_global_lock(pSapCtx) == CDF_STATUS_SUCCESS) { + if (pSap_WPSIe->sapWPSIECode == eSAP_WPS_BEACON_IE) { + cdf_mem_copy(&pSapCtx->APWPSIEs.SirWPSBeaconIE, + &pSap_WPSIe->sapwpsie. + sapWPSBeaconIE, + sizeof(tSap_WPSBeaconIE)); + } else if (pSap_WPSIe->sapWPSIECode == + eSAP_WPS_PROBE_RSP_IE) { + cdf_mem_copy(&pSapCtx->APWPSIEs. + SirWPSProbeRspIE, + &pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE, + sizeof(tSap_WPSProbeRspIE)); + } else { + sap_release_global_lock(pSapCtx); + return CDF_STATUS_E_FAULT; + } + sap_release_global_lock(pSapCtx); + return CDF_STATUS_SUCCESS; + } else + return CDF_STATUS_E_FAULT; + } else + return CDF_STATUS_E_FAULT; +} + +/** + * wlansap_update_wps_ie() - update WPI IE + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides API for App/HDD to update WPS IE. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise. + */ +CDF_STATUS wlansap_update_wps_ie(void *pCtx) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAULT; + ptSapContext pSapCtx = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s, %d", __func__, __LINE__); + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = + sme_roam_update_apwpsie(hHal, pSapCtx->sessionId, + &pSapCtx->APWPSIEs); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + cdf_status = CDF_STATUS_SUCCESS; + } else { + cdf_status = CDF_STATUS_E_FAULT; + } + + } + + return cdf_status; +} + +/** + * wlansap_get_wps_state() - get WPS session state + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pbWPSState: Pointer to variable to indicate if device is in + * WPS Registration state + * + * This api function provides for Ap App/HDD to check if WPS session in process. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS wlansap_get_wps_state(void *pCtx, bool *bWPSState) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s, %d", __func__, __LINE__); + + if (CDF_SAP_MODE == cds_get_conparam()) { + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + + if (sap_acquire_global_lock(pSapCtx) == CDF_STATUS_SUCCESS) { + if (pSapCtx->APWPSIEs.SirWPSProbeRspIE. + FieldPresent & + SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT) + *bWPSState = true; + else + *bWPSState = false; + + sap_release_global_lock(pSapCtx); + + return CDF_STATUS_SUCCESS; + } else + return CDF_STATUS_E_FAULT; + } else + return CDF_STATUS_E_FAULT; + +} + +CDF_STATUS sap_acquire_global_lock(ptSapContext pSapCtx) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAULT; + + if (CDF_IS_STATUS_SUCCESS(cdf_mutex_acquire(&pSapCtx->SapGlobalLock))) { + cdf_status = CDF_STATUS_SUCCESS; + } + + return cdf_status; +} + +CDF_STATUS sap_release_global_lock(ptSapContext pSapCtx) +{ + CDF_STATUS cdf_status = CDF_STATUS_E_FAULT; + + if (CDF_IS_STATUS_SUCCESS(cdf_mutex_release(&pSapCtx->SapGlobalLock))) { + cdf_status = CDF_STATUS_SUCCESS; + } + + return cdf_status; +} + +/** + * wlansap_set_wparsn_ies() - set WPA RSN IEs + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pWPARSNIEs : buffer to the WPA/RSN IEs + * @WPARSNIEsLen: length of WPA/RSN IEs + * + * This api function provides for Ap App/HDD to set AP WPA and RSN IE in its + * beacon and probe response. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise + */ +CDF_STATUS wlansap_set_wparsn_ies + (void *pCtx, uint8_t *pWPARSNIEs, uint32_t WPARSNIEsLen) { + ptSapContext pSapCtx = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return CDF_STATUS_E_FAULT; + } + + pSapCtx->APWPARSNIEs.length = (uint16_t) WPARSNIEsLen; + cdf_mem_copy(pSapCtx->APWPARSNIEs.rsnIEdata, pWPARSNIEs, + WPARSNIEsLen); + + cdf_ret_status = + sme_roam_update_apwparsni_es(hHal, pSapCtx->sessionId, + &pSapCtx->APWPARSNIEs); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + return CDF_STATUS_SUCCESS; + } else { + return CDF_STATUS_E_FAULT; + } + } + + return CDF_STATUS_E_FAULT; +} + +/** + * wlansap_send_action() - send action frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pBuf: Pointer of the action frame to be transmitted + * @len: Length of the action frame + * + * This api function provides to send action frame sent by upper layer. + * + * Return: The CDF_STATUS code associated with performing the operation +* CDF_STATUS_SUCCESS: Success and error code otherwise + */ +CDF_STATUS wlansap_send_action(void *pCtx, const uint8_t *pBuf, + uint32_t len, uint16_t wait, uint16_t channel_freq) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = + sme_send_action(hHal, pSapCtx->sessionId, pBuf, len, 0, + 0, channel_freq); + + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + return CDF_STATUS_SUCCESS; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Failed to Send Action Frame"); + + return CDF_STATUS_E_FAULT; +} + +/** + * wlansap_remain_on_channel() - set remain on channel + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @channel: Channel on which driver has to listen + * @duration: Duration for which driver has to listen on specified channel + * @callback: Callback function to be called once Listen is done. + * @pContext: Context needs to be called in callback function. + * @scan_id: scan identifier + * + * This api function provides to set Remain On channel on specified channel + * for specified duration. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise + */ +CDF_STATUS wlansap_remain_on_channel(void *pCtx, + uint8_t channel, uint32_t duration, remainOnChanCallback callback, + void *pContext, uint32_t *scan_id) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = sme_remain_on_channel(hHal, pSapCtx->sessionId, + channel, duration, callback, pContext, + true, scan_id); + + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + return CDF_STATUS_SUCCESS; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Failed to Set Remain on Channel"); + + return CDF_STATUS_E_FAULT; +} + +/** + * wlansap_cancel_remain_on_channel() - cancel remain on channel + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api cancel previous remain on channel request. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwie + */ +CDF_STATUS wlansap_cancel_remain_on_channel(void *pCtx, + uint32_t scan_id) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || + (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = + sme_cancel_remain_on_channel(hHal, pSapCtx->sessionId, + scan_id); + + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + return CDF_STATUS_SUCCESS; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Failed to Cancel Remain on Channel"); + + return CDF_STATUS_E_FAULT; +} +/** + * wlansap_register_mgmt_frame() - register management frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @frameType: frameType that needs to be registered with PE. + * @matchData: Data pointer which should be matched after frame type is matched. + * @matchLen: Length of the matchData + * + * HDD use this API to register specified type of frame with CORE stack. + * On receiving such kind of frame CORE stack should pass this frame to HDD + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise + */ +CDF_STATUS wlansap_register_mgmt_frame + (void *pCtx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen) { + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = sme_register_mgmt_frame(hHal, pSapCtx->sessionId, + frameType, matchData, + matchLen); + + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + return CDF_STATUS_SUCCESS; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Failed to Register MGMT frame"); + + return CDF_STATUS_E_FAULT; +} + +/** + * wlansap_de_register_mgmt_frame() - de register management frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @frameType: frameType that needs to be De-registered with PE. + * @matchData: Data pointer which should be matched after frame type is matched. + * @matchLen: Length of the matchData + * + * This API is used to deregister previously registered frame. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise + */ +CDF_STATUS wlansap_de_register_mgmt_frame + (void *pCtx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen) { + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + + if (CDF_SAP_MODE == cds_get_conparam()) { + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return CDF_STATUS_E_FAULT; + } + + cdf_ret_status = + sme_deregister_mgmt_frame(hHal, pSapCtx->sessionId, frameType, + matchData, matchLen); + + if (CDF_STATUS_SUCCESS == cdf_ret_status) { + return CDF_STATUS_SUCCESS; + } + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "Failed to Deregister MGMT frame"); + + return CDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_channel_change_request + + DESCRIPTION + This API is used to send an Indication to SME/PE to change the + current operating channel to a different target channel. + + The Channel change will be issued by SAP under the following + scenarios. + 1. A radar indication is received during SAP CAC WAIT STATE and + channel change is required. + 2. A radar indication is received during SAP STARTED STATE and + channel change is required. + DEPENDENCIES + NA. + + PARAMETERS + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS +wlansap_channel_change_request(void *pSapCtx, uint8_t targetChannel) +{ + ptSapContext sapContext = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal mac_ctx = NULL; + eCsrPhyMode phy_mode; + uint32_t cb_mode; + uint32_t vht_channel_width; + chan_params_t ch_params; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + mac_ctx = PMAC_STRUCT(hHal); + phy_mode = sapContext->csr_roamProfile.phyMode; + sapContext->csr_roamProfile.ChannelInfo.ChannelList[0] = targetChannel; + /* + * We are getting channel bonding mode from sapDfsInfor structure + * because we've implemented channel width fallback mechanism for DFS + * which will result in channel width changing dynamically. + */ + cb_mode = mac_ctx->sap.SapDfsInfo.new_cbMode; + vht_channel_width = mac_ctx->sap.SapDfsInfo.new_chanWidth; + ch_params.ch_width = vht_channel_width; + sme_set_ch_params(hHal, phy_mode, targetChannel, 0, &ch_params); + sapContext->ch_params.ch_width = vht_channel_width; + sapContext->csr_roamProfile.ch_params.ch_width = vht_channel_width; + cdf_ret_status = sme_roam_channel_change_req(hHal, sapContext->bssid, + cb_mode, &sapContext->csr_roamProfile); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + sap_signal_hdd_event(sapContext, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + return CDF_STATUS_SUCCESS; + } + return CDF_STATUS_E_FAULT; +} + +/*========================================================================== + + FUNCTION wlansap_start_beacon_req + DESCRIPTION + This API is used to send an Indication to SME/PE to start + beaconing on the current operating channel. + + Brief:When SAP is started on DFS channel and when ADD BSS RESP is received + LIM temporarily holds off Beaconing for SAP to do CAC WAIT. When + CAC WAIT is done SAP resumes the Beacon Tx by sending a start beacon + request to LIM. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_start_beacon_req(void *pSapCtx) +{ + ptSapContext sapContext = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + uint8_t dfsCacWaitStatus = 0; + tpAniSirGlobal pMac = NULL; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* No Radar was found during CAC WAIT, So start Beaconing */ + if (pMac->sap.SapDfsInfo.sap_radar_found_status == false) { + /* CAC Wait done without any Radar Detection */ + dfsCacWaitStatus = true; + cdf_ret_status = sme_roam_start_beacon_req(hHal, + sapContext->bssid, + dfsCacWaitStatus); + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + return CDF_STATUS_SUCCESS; + } + return CDF_STATUS_E_FAULT; + } + + return CDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_dfs_send_csa_ie_request + + DESCRIPTION + This API is used to send channel switch announcement request to PE + DEPENDENCIES + NA. + + PARAMETERS + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_dfs_send_csa_ie_request(void *pSapCtx) +{ + ptSapContext sapContext = NULL; + CDF_STATUS cdf_ret_status = CDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + uint32_t cbmode, vht_ch_width; + uint8_t ch_bandwidth; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* + * We are getting channel bonding mode from sapDfsInfor structure + * because we've implemented channel width fallback mechanism for DFS + * which will result in channel width changing dynamically. + */ + vht_ch_width = pMac->sap.SapDfsInfo.new_chanWidth; + cbmode = pMac->sap.SapDfsInfo.new_cbMode; + + if (pMac->sap.SapDfsInfo.target_channel <= 14 || + vht_ch_width == eHT_CHANNEL_WIDTH_40MHZ || + vht_ch_width == eHT_CHANNEL_WIDTH_20MHZ) { + switch (cbmode) { + case eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_bandwidth = BW40_HIGH_PRIMARY; + break; + case eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_bandwidth = BW40_LOW_PRIMARY; + break; + case eCSR_INI_SINGLE_CHANNEL_CENTERED: + default: + ch_bandwidth = BW20; + break; + } + } else { + ch_bandwidth = BW80; + } + + cdf_ret_status = sme_roam_csa_ie_request(hHal, + sapContext->bssid, + pMac->sap.SapDfsInfo.target_channel, + pMac->sap.SapDfsInfo.csaIERequired, + ch_bandwidth); + + if (cdf_ret_status == CDF_STATUS_SUCCESS) { + return CDF_STATUS_SUCCESS; + } + + return CDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_get_dfs_ignore_cac + + DESCRIPTION + This API is used to get the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + pIgnore_cac : pointer to ignore_cac variable + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + *pIgnore_cac = pMac->sap.SapDfsInfo.ignore_cac; + return CDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_ignore_cac + + DESCRIPTION + This API is used to Set the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + ignore_cac : value to set for ignore_cac variable in DFS global structure. + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + pMac->sap.SapDfsInfo.ignore_cac = (ignore_cac >= true) ? + true : false; + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_dfs_restrict_japan_w53() - enable/disable dfS for japan + * @hHal : HAL pointer + * @disable_Dfs_JapanW3 :Indicates if Japan W53 is disabled when set to 1 + * Indicates if Japan W53 is enabled when set to 0 + * + * This API is used to enable or disable Japan W53 Band + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success + */ +CDF_STATUS +wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, uint8_t disable_Dfs_W53) +{ + tpAniSirGlobal pMac = NULL; + CDF_STATUS status; + uint8_t dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + cds_get_dfs_region(&dfs_region); + + /* + * Set the JAPAN W53 restriction only if the current + * regulatory domain is JAPAN. + */ + if (DFS_MKK4_DOMAIN == dfs_region) { + pMac->sap.SapDfsInfo.is_dfs_w53_disabled = disable_Dfs_W53; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: SET DFS JAPAN W53 DISABLED = %d"), + pMac->sap.SapDfsInfo.is_dfs_w53_disabled); + + status = CDF_STATUS_SUCCESS; + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL + ("Regdomain not japan, set disable JP W53 not valid")); + + status = CDF_STATUS_E_FAULT; + } + + return status; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wlan_sap_set_channel_avoidance() - sets sap mcc channel avoidance ini param + * @hal: hal handle + * @sap_channel_avoidance: ini parameter value + * + * sets sap mcc channel avoidance ini param, to be called in sap_start + * + * Return: success of failure of operation + */ +CDF_STATUS +wlan_sap_set_channel_avoidance(tHalHandle hal, bool sap_channel_avoidance) +{ + tpAniSirGlobal mac_ctx = NULL; + if (NULL != hal) + mac_ctx = PMAC_STRUCT(hal); + if (mac_ctx == NULL || hal == NULL) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + FL("hal or mac_ctx pointer NULL")); + return CDF_STATUS_E_FAULT; + } + mac_ctx->sap.sap_channel_avoidance = sap_channel_avoidance; + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * wlansap_set_dfs_preferred_channel_location() - set dfs preferred channel + * @hHal : HAL pointer + * @dfs_Preferred_Channels_location : + * 0 - Indicates No preferred channel location restrictions + * 1 - Indicates SAP Indoor Channels operation only. + * 2 - Indicates SAP Outdoor Channels operation only. + * + * This API is used to set sap preferred channels location + * to resetrict the DFS random channel selection algorithm + * either Indoor/Outdoor channels only. + * + * Return: The CDF_STATUS code associated with performing the operation + * CDF_STATUS_SUCCESS: Success and error code otherwise. + */ +CDF_STATUS +wlansap_set_dfs_preferred_channel_location(tHalHandle hHal, + uint8_t + dfs_Preferred_Channels_location) +{ + tpAniSirGlobal pMac = NULL; + CDF_STATUS status; + uint8_t dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + cds_get_dfs_region(&dfs_region); + + /* + * The Indoor/Outdoor only random channel selection + * restriction is currently enforeced only for + * JAPAN regulatory domain. + */ + if (DFS_MKK4_DOMAIN == dfs_region) { + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location = + dfs_Preferred_Channels_location; + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_INFO_LOW, + FL + ("sapdfs:Set Preferred Operating Channel location=%d"), + pMac->sap.SapDfsInfo. + sap_operating_chan_preferred_location); + + status = CDF_STATUS_SUCCESS; + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL + ("sapdfs:NOT JAPAN REG, Invalid Set preferred chans location")); + + status = CDF_STATUS_E_FAULT; + } + + return status; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_target_chnl + + DESCRIPTION + This API is used to set next target chnl as provided channel. + you can provide any valid channel to this API. + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + target_channel : target channel to be set + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, uint8_t target_channel) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return CDF_STATUS_E_FAULT; + } + if (target_channel > 0) { + pMac->sap.SapDfsInfo.user_provided_target_channel = + target_channel; + } else { + pMac->sap.SapDfsInfo.user_provided_target_channel = 0; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS +wlansap_update_sap_config_add_ie(tsap_Config_t *pConfig, + const uint8_t *pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t bufferValid = false; + uint16_t bufferLength = 0; + uint8_t *pBuffer = NULL; + + if (NULL == pConfig) { + return CDF_STATUS_E_FAULT; + } + + if ((pAdditionIEBuffer != NULL) && (additionIELength != 0)) { + /* initialize the buffer pointer so that pe can copy */ + if (additionIELength > 0) { + bufferLength = additionIELength; + pBuffer = cdf_mem_malloc(bufferLength); + if (NULL == pBuffer) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Could not allocate the buffer ")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(pBuffer, pAdditionIEBuffer, bufferLength); + bufferValid = true; + } + } + + switch (updateType) { + case eUPDATE_IE_PROBE_BCN: + if (bufferValid) { + pConfig->probeRespBcnIEsLen = bufferLength; + pConfig->pProbeRespBcnIEsBuffer = pBuffer; + } else { + cdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("No Probe Resp beacone IE received in set beacon")); + } + break; + case eUPDATE_IE_PROBE_RESP: + if (bufferValid) { + pConfig->probeRespIEsBufferLen = bufferLength; + pConfig->pProbeRespIEsBuffer = pBuffer; + } else { + cdf_mem_free(pConfig->pProbeRespIEsBuffer); + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("No Probe Response IE received in set beacon")); + } + break; + case eUPDATE_IE_ASSOC_RESP: + if (bufferValid) { + pConfig->assocRespIEsLen = bufferLength; + pConfig->pAssocRespIEsBuffer = pBuffer; + } else { + cdf_mem_free(pConfig->pAssocRespIEsBuffer); + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("No Assoc Response IE received in set beacon")); + } + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("No matching buffer type %d"), updateType); + if (pBuffer != NULL) + cdf_mem_free(pBuffer); + break; + } + + return status; +} + +CDF_STATUS +wlansap_reset_sap_config_add_ie(tsap_Config_t *pConfig, eUpdateIEsType updateType) +{ + if (NULL == pConfig) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid Config pointer", __func__); + return CDF_STATUS_E_FAULT; + } + + switch (updateType) { + case eUPDATE_IE_ALL: /*only used to reset */ + case eUPDATE_IE_PROBE_RESP: + cdf_mem_free(pConfig->pProbeRespIEsBuffer); + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_ASSOC_RESP: + cdf_mem_free(pConfig->pAssocRespIEsBuffer); + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_PROBE_BCN: + cdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + default: + if (eUPDATE_IE_ALL != updateType) + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Invalid buffer type %d"), updateType); + break; + } + return CDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_extend_to_acs_range + + DESCRIPTION Function extends give channel range to consider ACS chan bonding + + DEPENDENCIES PARAMETERS + + IN /OUT + *startChannelNum : ACS extend start ch + *endChannelNum : ACS extended End ch + *bandStartChannel: Band start ch + *bandEndChannel : Band end ch + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +void wlansap_extend_to_acs_range(uint8_t *startChannelNum, + uint8_t *endChannelNum, + uint8_t *bandStartChannel, + uint8_t *bandEndChannel) +{ +#define ACS_WLAN_20M_CH_INC 4 +#define ACS_2G_EXTEND ACS_WLAN_20M_CH_INC +#define ACS_5G_EXTEND (ACS_WLAN_20M_CH_INC * 3) + + uint8_t tmp_startChannelNum = 0, tmp_endChannelNum = 0; + + if (*startChannelNum <= 14 && *endChannelNum <= 14) { + *bandStartChannel = RF_CHAN_1; + *bandEndChannel = RF_CHAN_14; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_2G_EXTEND) <= 14 ? + (*endChannelNum + ACS_2G_EXTEND) : 14; + } else if (*startChannelNum >= 36 && *endChannelNum >= 36) { + *bandStartChannel = RF_CHAN_36; + *bandEndChannel = RF_CHAN_165; + tmp_startChannelNum = (*startChannelNum - ACS_5G_EXTEND) > 36 ? + (*startChannelNum - ACS_5G_EXTEND) : 36; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= 165 ? + (*endChannelNum + ACS_5G_EXTEND) : 165; + } else { + *bandStartChannel = RF_CHAN_1; + *bandEndChannel = RF_CHAN_165; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= 165 ? + (*endChannelNum + ACS_5G_EXTEND) : 165; + } + + /* Note if the ACS range include only DFS channels, do not cross range + * Active scanning in adjacent non DFS channels results in transmission + * spikes in DFS specturm channels which is due to emission spill. + * Remove the active channels from extend ACS range for DFS only range + */ + if (CDS_IS_DFS_CH(*startChannelNum)) { + while (!CDS_IS_DFS_CH(tmp_startChannelNum) && + tmp_startChannelNum < *startChannelNum) + tmp_startChannelNum += ACS_WLAN_20M_CH_INC; + + *startChannelNum = tmp_startChannelNum; + } + if (CDS_IS_DFS_CH(*endChannelNum)) { + while (!CDS_IS_DFS_CH(tmp_endChannelNum) && + tmp_endChannelNum > *endChannelNum) + tmp_endChannelNum -= ACS_WLAN_20M_CH_INC; + + *endChannelNum = tmp_endChannelNum; + } +} + +/*========================================================================== + FUNCTION wlansap_get_dfs_nol + + DESCRIPTION + This API is used to dump the dfs nol + DEPENDENCIES + NA. + + PARAMETERS + IN + sapContext: Pointer to cds global context structure + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_get_dfs_nol(void *pSapCtx) +{ + int i = 0; + ptSapContext sapContext = (ptSapContext) pSapCtx; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + uint64_t current_time, found_time, elapsed_time; + unsigned long left_time; + tSapDfsNolInfo *dfs_nol = NULL; + bool bAvailable = false; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + if (!pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: DFS NOL is empty", __func__); + return CDF_STATUS_SUCCESS; + } + + dfs_nol = pMac->sap.SapDfsInfo.sapDfsChannelNolList; + + if (!dfs_nol) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: DFS NOL context is null", __func__); + return CDF_STATUS_E_FAULT; + } + + for (i = 0; i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + if (!dfs_nol[i].dfs_channel_number) + continue; + + current_time = cds_get_monotonic_boottime(); + found_time = dfs_nol[i].radar_found_timestamp; + + elapsed_time = current_time - found_time; + + /* check if channel is available + * if either channel is usable or available, or timer expired 30mins + */ + bAvailable = + ((dfs_nol[i].radar_status_flag == + eSAP_DFS_CHANNEL_AVAILABLE) + || (dfs_nol[i].radar_status_flag == + eSAP_DFS_CHANNEL_USABLE) + || (elapsed_time >= SAP_DFS_NON_OCCUPANCY_PERIOD)); + + if (bAvailable) { + dfs_nol[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + dfs_nol[i].radar_found_timestamp = 0; + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Channel[%d] is AVAILABLE", + __func__, dfs_nol[i].dfs_channel_number); + } else { + + /* the time left in min */ + left_time = SAP_DFS_NON_OCCUPANCY_PERIOD - elapsed_time; + left_time = left_time / (60 * 1000 * 1000); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Channel[%d] is UNAVAILABLE [%lu min left]", + __func__, + dfs_nol[i].dfs_channel_number, left_time); + } + } + + return CDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_nol + + DESCRIPTION + This API is used to set the dfs nol + DEPENDENCIES + NA. + + PARAMETERS + IN + sapContext: Pointer to cds global context structure + conf: set type + + RETURN VALUE + The CDF_STATUS code associated with performing the operation + + CDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +CDF_STATUS wlansap_set_dfs_nol(void *pSapCtx, eSapDfsNolType conf) +{ + int i = 0; + ptSapContext sapContext = (ptSapContext) pSapCtx; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + + if (NULL == sapContext) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return CDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + if (!pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + "%s: DFS NOL is empty", __func__); + return CDF_STATUS_SUCCESS; + } + + if (conf == eSAP_DFS_NOL_CLEAR) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: clear the DFS NOL", __func__); + + for (i = 0; + i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + if (!pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].dfs_channel_number) + continue; + + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_found_timestamp = 0; + } + } else if (conf == eSAP_DFS_NOL_RANDOMIZE) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Randomize the DFS NOL", __func__); + + /* random 1/0 to decide to put the channel into NOL */ + for (i = 0; + i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + uint32_t random_bytes = 0; + get_random_bytes(&random_bytes, 1); + + if (!pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].dfs_channel_number) + continue; + + if ((random_bytes + jiffies) % 2) { + /* mark the channel unavailable */ + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .radar_status_flag = + eSAP_DFS_CHANNEL_UNAVAILABLE; + + /* mark the timestamp */ + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .radar_found_timestamp = + cds_get_monotonic_boottime(); + } else { + /* mark the channel available */ + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + + /* clear the timestamp */ + pMac->sap.SapDfsInfo. + sapDfsChannelNolList + [i].radar_found_timestamp = 0; + } + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Set channel[%d] %s", + __func__, + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .dfs_channel_number, + (pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag > + eSAP_DFS_CHANNEL_AVAILABLE) ? "UNAVAILABLE" : + "AVAILABLE"); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: unsupport type %d", __func__, conf); + } + + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sapContext, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + + return CDF_STATUS_SUCCESS; +} + +/** + * wlansap_populate_del_sta_params() - populate delete station parameter + * @mac: Pointer to peer mac address. + * @reason_code: Reason code for the disassoc/deauth. + * @subtype: Subtype points to either disassoc/deauth frame. + * @pDelStaParams: Address where parameters to be populated. + * + * This API is used to populate delete station parameter structure + * + * Return: none + */ + +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct tagCsrDelStaParams *pDelStaParams) +{ + if (NULL == mac) + cdf_set_macaddr_broadcast(&pDelStaParams->peerMacAddr); + else + cdf_mem_copy(pDelStaParams->peerMacAddr.bytes, mac, + CDF_MAC_ADDR_SIZE); + + if (reason_code == 0) + pDelStaParams->reason_code = eSIR_MAC_DEAUTH_LEAVING_BSS_REASON; + else + pDelStaParams->reason_code = reason_code; + + if (subtype == (SIR_MAC_MGMT_DEAUTH >> 4) || + subtype == (SIR_MAC_MGMT_DISASSOC >> 4)) + pDelStaParams->subtype = subtype; + else + pDelStaParams->subtype = (SIR_MAC_MGMT_DEAUTH >> 4); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO, + FL( + "Delete STA with RC:%hu subtype:%hhu MAC::" + MAC_ADDRESS_STR), + pDelStaParams->reason_code, pDelStaParams->subtype, + MAC_ADDR_ARRAY(pDelStaParams->peerMacAddr.bytes)); +} + +/** + * wlansap_acs_chselect() - Initiates acs channel selection + * @pvos_gctx: Pointer to vos global context structure + * @pacs_event_callback: Callback function in hdd called by sap + * to inform hdd about channel section result + * @pconfig: Pointer to configuration structure + * passed down from hdd + * @pusr_context: Parameter that will be passed back in all + * the sap callback events. + * + * This function serves as an api for hdd to initiate acs scan pre + * start bss. + * + * Return: The CDF_STATUS code associated with performing the operation. + */ +CDF_STATUS +wlansap_acs_chselect(void *pvos_gctx, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_Config_t *pconfig, + void *pusr_context) +{ + ptSapContext sap_context = NULL; + tHalHandle h_hal = NULL; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pmac = NULL; + + sap_context = CDS_GET_SAP_CB(pvos_gctx); + if (NULL == sap_context) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pvos_gctx", __func__); + + return CDF_STATUS_E_FAULT; + } + + h_hal = (tHalHandle)CDS_GET_HAL_CB(sap_context->p_cds_gctx); + if (NULL == h_hal) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context from pvosGCtx", __func__); + return CDF_STATUS_E_FAULT; + } + + if (sap_context->isSapSessionOpen == eSAP_TRUE) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_FATAL, + "%s:SME Session is already opened\n", __func__); + return CDF_STATUS_E_EXISTS; + } + + sap_context->sessionId = 0xff; + + pmac = PMAC_STRUCT(h_hal); + sap_context->acs_cfg = &pconfig->acs_cfg; + sap_context->ch_width_orig = pconfig->acs_cfg.ch_width; + sap_context->csr_roamProfile.phyMode = pconfig->acs_cfg.hw_mode; + + if (sap_context->isScanSessionOpen == eSAP_FALSE) { + uint32_t type, subType; + + /* + * Now, configure the scan and ACS channel params + * to issue a scan request. + */ + wlansap_set_scan_acs_channel_params(pconfig, sap_context, + pusr_context); + + if (CDF_STATUS_SUCCESS == + cds_get_vdev_types(CDF_STA_MODE, &type, &subType)) { + /* + * Open SME Session for scan + */ + if (CDF_STATUS_SUCCESS != sme_open_session(h_hal, + NULL, sap_context, + sap_context->self_mac_addr, + &sap_context->sessionId, + type, subType)) { + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_OpenSession", + __func__); + return CDF_STATUS_E_FAILURE; + } else { + sap_context->isScanSessionOpen = eSAP_TRUE; + } + } + + /* + * Copy the HDD callback function to report the + * ACS result after scan in SAP context callback function. + */ + sap_context->pfnSapEventCallback = pacs_event_callback; + /* + * init dfs channel nol + */ + sap_init_dfs_channel_nol_list(sap_context); + + /* + * Issue the scan request. This scan request is + * issued before the start BSS is done so + * + * 1. No need to pass the second parameter + * as the SAP state machine is not started yet + * and there is no need for any event posting. + * + * 2. Set third parameter to TRUE to indicate the + * channel selection function to register a + * different scan callback fucntion to process + * the results pre start BSS. + */ + cdf_status = sap_goto_channel_sel(sap_context, NULL, true); + + if (CDF_STATUS_E_ABORTED == cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + "In %s,DFS not supported in the current operating mode", + __func__); + return CDF_STATUS_E_FAILURE; + } else if (CDF_STATUS_E_CANCELED == cdf_status) { + /* + * ERROR is returned when either the SME scan request + * failed or ACS is overridden due to other constrainst + * So send selected channel to HDD + */ + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Scan Req Failed/ACS Overridden")); + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR, + FL("Selected channel = %d"), + sap_context->channel); + if (sap_context->isScanSessionOpen == eSAP_TRUE) { + /* ACS scan not needed so close session */ + tHalHandle h_hal = CDS_GET_HAL_CB( + sap_context->p_cds_gctx); + if (h_hal == NULL) + return CDF_STATUS_E_FAILURE; + + if (sme_close_session(h_hal, + sap_context->sessionId, NULL, NULL) == + CDF_STATUS_SUCCESS) + sap_context->isScanSessionOpen = + eSAP_FALSE; + else + CDF_TRACE(CDF_MODULE_ID_SAP, + CDF_TRACE_LEVEL_ERROR, + "ACS Scan Session close fail"); + sap_context->sessionId = 0xff; + } + + return sap_signal_hdd_event(sap_context, NULL, + eSAP_ACS_CHANNEL_SELECTED, + (void *) eSAP_STATUS_SUCCESS); + } else if (CDF_STATUS_SUCCESS == cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Successfully Issued a Pre Start Bss Scan Request")); + } + } + return cdf_status; +} + +/** + * wlan_sap_enable_phy_error_logs() - Enable DFS phy error logs + * @hal: global hal handle + * @enable_log: value to set + * + * Since the frequency of DFS phy error is very high, enabling logs for them + * all the times can cause crash and will also create lot of useless logs + * causing difficulties in debugging other issue. This function will be called + * from iwpriv cmd to eanble such logs temporarily. + * + * Return: void + */ +void wlan_sap_enable_phy_error_logs(tHalHandle hal, bool enable_log) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->sap.enable_dfs_phy_error_logs = enable_log; +} diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h new file mode 100644 index 0000000000..117240d9a7 --- /dev/null +++ b/core/sme/inc/csr_api.h @@ -0,0 +1,1644 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_api.h + * + * Exports and types for the Common Scan and Roaming Module interfaces. + */ + +#ifndef CSRAPI_H__ +#define CSRAPI_H__ + +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "csr_link_list.h" + +#define CSR_INVALID_SCANRESULT_HANDLE (NULL) + +typedef enum { + CH_WIDTH_20MHZ = 0, + CH_WIDTH_40MHZ = 1, + CH_WIDTH_80MHZ = 2, + CH_WIDTH_160MHZ = 3, + CH_WIDTH_80P80MHZ = 4 +} phy_ch_width; + +typedef struct ch_params_s { + phy_ch_width ch_width; + uint8_t sec_ch_offset; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; +} chan_params_t; + +typedef enum { + /* never used */ + eCSR_AUTH_TYPE_NONE, + /* MAC layer authentication types */ + eCSR_AUTH_TYPE_OPEN_SYSTEM, + eCSR_AUTH_TYPE_SHARED_KEY, + eCSR_AUTH_TYPE_AUTOSWITCH, + + /* Upper layer authentication types */ + eCSR_AUTH_TYPE_WPA, + eCSR_AUTH_TYPE_WPA_PSK, + eCSR_AUTH_TYPE_WPA_NONE, + + eCSR_AUTH_TYPE_RSN, + eCSR_AUTH_TYPE_RSN_PSK, +#if defined WLAN_FEATURE_VOWIFI_11R + eCSR_AUTH_TYPE_FT_RSN, + eCSR_AUTH_TYPE_FT_RSN_PSK, +#endif +#ifdef FEATURE_WLAN_WAPI + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE, + eCSR_AUTH_TYPE_WAPI_WAI_PSK, +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + eCSR_AUTH_TYPE_CCKM_WPA, + eCSR_AUTH_TYPE_CCKM_RSN, +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + eCSR_AUTH_TYPE_RSN_PSK_SHA256, + eCSR_AUTH_TYPE_RSN_8021X_SHA256, +#endif + eCSR_NUM_OF_SUPPORT_AUTH_TYPE, + eCSR_AUTH_TYPE_FAILED = 0xff, + eCSR_AUTH_TYPE_UNKNOWN = eCSR_AUTH_TYPE_FAILED, + +} eCsrAuthType; + +typedef enum { + eCSR_ENCRYPT_TYPE_NONE, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP40, + eCSR_ENCRYPT_TYPE_WEP104, + eCSR_ENCRYPT_TYPE_TKIP, + eCSR_ENCRYPT_TYPE_AES, +#ifdef FEATURE_WLAN_WAPI + /* WAPI */ + eCSR_ENCRYPT_TYPE_WPI, +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + eCSR_ENCRYPT_TYPE_KRK, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + eCSR_ENCRYPT_TYPE_BTK, +#endif +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + /* 11w BIP */ + eCSR_ENCRYPT_TYPE_AES_CMAC, +#endif + eCSR_ENCRYPT_TYPE_ANY, + eCSR_NUM_OF_ENCRYPT_TYPE = eCSR_ENCRYPT_TYPE_ANY, + + eCSR_ENCRYPT_TYPE_FAILED = 0xff, + eCSR_ENCRYPT_TYPE_UNKNOWN = eCSR_ENCRYPT_TYPE_FAILED, + +} eCsrEncryptionType; + +/*--------------------------------------------------------------------------- + Enumeration of the various Security types + ---------------------------------------------------------------------------*/ +typedef enum { + eCSR_SECURITY_TYPE_WPA, + eCSR_SECURITY_TYPE_RSN, +#ifdef FEATURE_WLAN_WAPI + eCSR_SECURITY_TYPE_WAPI, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_SECURITY_TYPE_UNKNOWN, + +} eCsrSecurityType; + +typedef enum { + /* 11a/b/g only, no HT, no proprietary */ + eCSR_DOT11_MODE_abg = 0x0001, + eCSR_DOT11_MODE_11a = 0x0002, + eCSR_DOT11_MODE_11b = 0x0004, + eCSR_DOT11_MODE_11g = 0x0008, + eCSR_DOT11_MODE_11n = 0x0010, + eCSR_DOT11_MODE_11g_ONLY = 0x0020, + eCSR_DOT11_MODE_11n_ONLY = 0x0040, + eCSR_DOT11_MODE_11b_ONLY = 0x0080, +#ifdef WLAN_FEATURE_11AC + eCSR_DOT11_MODE_11ac = 0x0100, + eCSR_DOT11_MODE_11ac_ONLY = 0x0200, +#endif + /* + * This is for WIFI test. It is same as eWNIAPI_MAC_PROTOCOL_ALL + * except when it starts IBSS in 11B of 2.4GHz + * It is for CSR internal use + */ + eCSR_DOT11_MODE_AUTO = 0x0400, + + /* specify the number of maximum bits for phyMode */ + eCSR_NUM_PHY_MODE = 16, +} eCsrPhyMode; + +typedef enum { + eCSR_BSS_TYPE_NONE, + eCSR_BSS_TYPE_INFRASTRUCTURE, + eCSR_BSS_TYPE_INFRA_AP, /* SoftAP AP */ + eCSR_BSS_TYPE_IBSS, /* IBSS network we'll NOT start */ + eCSR_BSS_TYPE_START_IBSS, /* IBSS network we'll start if no partners */ + eCSR_BSS_TYPE_WDS_AP, /* BT-AMP AP */ + eCSR_BSS_TYPE_WDS_STA, /* BT-AMP station */ + eCSR_BSS_TYPE_ANY, /* any BSS type (IBSS or Infrastructure).*/ +} eCsrRoamBssType; + +typedef enum { + eCSR_SCAN_REQUEST_11D_SCAN = 1, + eCSR_SCAN_REQUEST_FULL_SCAN, + eCSR_SCAN_IDLE_MODE_SCAN, + eCSR_SCAN_HO_PROBE_SCAN, /* direct probe on entry from candidate list */ + eCSR_SCAN_P2P_DISCOVERY, + + eCSR_SCAN_SOFTAP_CHANNEL_RANGE, + eCSR_SCAN_P2P_FIND_PEER, +} eCsrRequestType; + +typedef enum { + eCSR_SCAN_RESULT_GET = 0, + eCSR_SCAN_RESULT_FLUSH = 1, /* to delete all cached scan results */ +} eCsrScanResultCmd; + +typedef enum { + eCSR_SCAN_SUCCESS, + eCSR_SCAN_FAILURE, + eCSR_SCAN_ABORT, + eCSR_SCAN_FOUND_PEER, +} eCsrScanStatus; + +/* + * Reason to abort the scan + * The reason can used later to decide whether to update the scan results + * to upper layer or not + */ +typedef enum { + eCSR_SCAN_ABORT_DEFAULT, + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE, /* Scan abort due to band change */ + eCSR_SCAN_ABORT_SSID_ONLY +} eCsrAbortReason; + +typedef enum { + eCSR_BW_20MHz_VAL = 20, + eCSR_BW_40MHz_VAL = 40, + eCSR_BW_80MHz_VAL = 80, + eCSR_BW_160MHz_VAL = 160 +} eCSR_BW_Val; + +typedef enum { + eCSR_INI_SINGLE_CHANNEL_CENTERED = 0, + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY, + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY, +#ifdef WLAN_FEATURE_11AC + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH, +#endif + eCSR_INI_CHANNEL_BONDING_STATE_MAX +} eIniChanBondState; + +#define CSR_RSN_PMKID_SIZE 16 +#define CSR_MAX_PMKID_ALLOWED 32 +#define CSR_WEP40_KEY_LEN 5 +#define CSR_WEP104_KEY_LEN 13 +#define CSR_TKIP_KEY_LEN 32 +#define CSR_AES_KEY_LEN 16 +#define CSR_MAX_TX_POWER (WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX) +#define CSR_MAX_RSC_LEN 16 +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_BKID_SIZE 16 +#define CSR_MAX_BKID_ALLOWED 16 +#define CSR_WAPI_KEY_LEN 32 +#define CSR_MAX_KEY_LEN (CSR_WAPI_KEY_LEN) /* longest one is for WAPI */ +#else +#define CSR_MAX_KEY_LEN (CSR_TKIP_KEY_LEN) /* longest one is for TKIP */ +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE +#define CSR_KRK_KEY_LEN 16 +#endif + +typedef struct tagCsrChannelInfo { + uint8_t numOfChannels; + uint8_t *ChannelList; /* it will be an array of channels */ +} tCsrChannelInfo, *tpCsrChannelInfo; + +typedef struct tagCsrSSIDInfo { + tSirMacSSid SSID; + bool handoffPermitted; + bool ssidHidden; +} tCsrSSIDInfo; + +typedef struct tagCsrSSIDs { + uint32_t numOfSSIDs; + tCsrSSIDInfo *SSIDList; /* To be allocated for array of SSIDs */ +} tCsrSSIDs; + +typedef struct tagCsrBSSIDs { + uint32_t numOfBSSIDs; + struct cdf_mac_addr *bssid; +} tCsrBSSIDs; + +typedef struct tagCsrStaParams { + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_len; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsd_queues; + uint8_t max_sp; + uint8_t supported_channels_len; + uint8_t supported_channels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[SIR_MAC_MAX_SUPP_OPER_CLASSES]; +} tCsrStaParams; + +typedef struct tagCsrScanRequest { + tSirScanType scanType; + struct cdf_mac_addr bssid; + eCsrRoamBssType BSSType; + tCsrSSIDs SSIDs; + tCsrChannelInfo ChannelInfo; + uint32_t minChnTime; /* in units of milliseconds */ + uint32_t maxChnTime; /* in units of milliseconds */ + uint32_t restTime; /* in units of milliseconds */ + uint32_t uIEFieldLen; + uint8_t *pIEField; + eCsrRequestType requestType; /* 11d scan or full scan */ + bool p2pSearch; + bool skipDfsChnlInP2pSearch; + bool bcnRptReqScan; /* is Scan issued by Beacon Report Request */ + uint32_t scan_id; + uint32_t timestamp; +} tCsrScanRequest; + +typedef struct tagCsrScanResultInfo { + /* + * Carry the IEs for the current BSSDescription. + * A pointer to tDot11fBeaconIEs. Maybe NULL for start BSS. + */ + void *pvIes; + tAniSSID ssId; + v_TIME_t timer; /* timer is variable for hidden SSID timer */ + /* + * This member must be the last in the structure because the + * end of tSirBssDescription is an + * array with nonknown size at this time */ + tSirBssDescription BssDescriptor; +} tCsrScanResultInfo; + +typedef struct tagCsrEncryptionList { + + uint32_t numEntries; + eCsrEncryptionType encryptionType[eCSR_NUM_OF_ENCRYPT_TYPE]; + +} tCsrEncryptionList, *tpCsrEncryptionList; + +typedef struct tagCsrAuthList { + uint32_t numEntries; + eCsrAuthType authType[eCSR_NUM_OF_SUPPORT_AUTH_TYPE]; +} tCsrAuthList, *tpCsrAuthList; + +#ifdef WLAN_FEATURE_VOWIFI_11R +typedef struct tagCsrMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tCsrMobilityDomainInfo; +#endif + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseCckmInfo { + uint32_t reassoc_req_num; + bool krk_plumbed; + uint8_t krk[SIR_KRK_KEY_LEN]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t btk[SIR_BTK_KEY_LEN]; +#endif +} tCsrEseCckmInfo; +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +#define CSR_DOT11F_IE_RSN_MAX_LEN (114) +typedef struct tagCsrEseCckmIe { + uint8_t cckmIe[CSR_DOT11F_IE_RSN_MAX_LEN]; + uint8_t cckmIeLen; +} tCsrEseCckmIe; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +typedef struct sCsrChannel_ { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} sCsrChannel; + +typedef struct tagCsrScanResultFilter { + tCsrBSSIDs BSSIDs; + tCsrSSIDs SSIDs; + tCsrChannelInfo ChannelInfo; + tCsrAuthList authType; + tCsrEncryptionList EncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + eCsrRoamBssType BSSType; + /* its a bit mask of all the needed phy mode defined in eCsrPhyMode */ + eCsrPhyMode phyMode; + /* + * If countryCode[0] is not 0, countryCode is checked + * independent of fCheckUnknownCountryCode + */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t uapsd_mask; + /* For WPS filtering if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; +#if defined WLAN_FEATURE_VOWIFI + /* + * For measurement reports --> if set, only SSID, + * BSSID and channel is considered for filtering. + */ + bool fMeasurement; +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + tCsrMobilityDomainInfo MDID; +#endif + bool p2pResult; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + /* The following flag is used to distinguish the + * roaming case while building the scan filter and + * applying it on to the scan results. This is mainly + * used to support whitelist ssid feature. + */ + uint8_t scan_filter_for_roam; + struct sCsrChannel_ pcl_channels; + tCDF_CON_MODE csrPersona; +} tCsrScanResultFilter; + +typedef struct sCsrChnPower_ { + uint8_t firstChannel; + uint8_t numChannels; + uint8_t maxtxPower; +} sCsrChnPower; + +typedef struct tagCsr11dinfo { + sCsrChannel Channels; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN + 1]; + /* max power channel list */ + sCsrChnPower ChnPower[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsr11dinfo; + +typedef enum { + eCSR_ROAM_CANCELLED = 1, + /* it means error happens before assoc_start/roaming_start is called. */ + eCSR_ROAM_FAILED, + /* + * a CSR trigger roaming operation starts, + * callback may get a pointer to tCsrConnectedProfile + */ + eCSR_ROAM_ROAMING_START, + /* a CSR trigger roaming operation is completed */ + eCSR_ROAM_ROAMING_COMPLETION, + /* Connection completed status. */ + eCSR_ROAM_CONNECT_COMPLETION, + /* + * an association or start_IBSS operation starts, + * callback may get a pointer to tCsrRoamProfile and + * a pointer to tSirBssDescription + */ + eCSR_ROAM_ASSOCIATION_START, + /* + * a roaming operation is finish, see eCsrRoamResult for + * possible data passed back + */ + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_ASSOCIATION_FAILURE, + /* when callback with this flag. it gets a pointer to the BSS desc. */ + eCSR_ROAM_SHOULD_ROAM, + /* A new candidate for PMKID is found */ + eCSR_ROAM_SCAN_FOUND_NEW_BSS, + /* CSR is done lostlink roaming and still cannot reconnect */ + eCSR_ROAM_LOSTLINK, + /* a link lost is detected. CSR starts roaming. */ + eCSR_ROAM_LOSTLINK_DETECTED, + /* + * TKIP MIC error detected, callback gets a pointer + * to tpSirSmeMicFailureInd + */ + eCSR_ROAM_MIC_ERROR_IND, + /* IBSS indications. */ + eCSR_ROAM_IBSS_IND, + /* + * Update the connection status, useful for IBSS: new peer added, + * network is active etc. + */ + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_GEN_INFO, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_IBSS_LEAVE, /* IBSS indications. */ + /* BSS in WDS mode status indication */ + eCSR_ROAM_WDS_IND, + /* BSS in SoftAP mode status indication */ + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, +#ifdef WLAN_FEATURE_VOWIFI_11R + eCSR_ROAM_FT_RESPONSE, +#endif + eCSR_ROAM_FT_START, + eCSR_ROAM_INDICATE_MGMT_FRAME, + eCSR_ROAM_REMAIN_CHAN_READY, + eCSR_ROAM_SEND_ACTION_CNF, + /* this mean error happens before assoc_start/roam_start is called. */ + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_FT_REASSOC_FAILED, +#ifdef FEATURE_WLAN_LFR + eCSR_ROAM_PMK_NOTIFY, +#endif + /* + * Following 4 enums are used by FEATURE_WLAN_LFR_METRICS + * but they are needed for compilation even when + * FEATURE_WLAN_LFR_METRICS is not defined. + */ + eCSR_ROAM_PREAUTH_INIT_NOTIFY, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS, + eCSR_ROAM_PREAUTH_STATUS_FAILURE, + eCSR_ROAM_HANDOVER_SUCCESS, +#ifdef FEATURE_WLAN_TDLS + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, +#endif + /* Disaconnect all the clients */ + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + /* Stopbss triggered from SME due to different */ + eCSR_ROAM_SEND_P2P_STOP_BSS, + /* beacon interval */ +#ifdef WLAN_FEATURE_11W + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + eCSR_ROAM_TSM_IE_IND, + eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, + eCSR_ROAM_ESE_BCN_REPORT_IND, +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + + /* Radar indication from lower layers */ + eCSR_ROAM_DFS_RADAR_IND, + eCSR_ROAM_SET_CHANNEL_RSP, + + /* Channel sw update notification */ + eCSR_ROAM_DFS_CHAN_SW_NOTIFY, +} eRoamCmdStatus; + +/* comment inside indicates what roaming callback gets */ +typedef enum { + eCSR_ROAM_RESULT_NONE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION, + * tCsrRoamInfo's pBssDesc may pass back + */ + eCSR_ROAM_RESULT_FAILURE, + /* Pass back pointer to tCsrRoamInfo */ + eCSR_ROAM_RESULT_ASSOCIATED, + eCSR_ROAM_RESULT_NOT_ASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE, + eCSR_ROAM_RESULT_FORCED, + eCSR_ROAM_RESULT_DISASSOC_IND, + eCSR_ROAM_RESULT_DEAUTH_IND, + eCSR_ROAM_RESULT_CAP_CHANGED, + /* + * This means we starts an IBSS tCsrRoamInfo's + * pBssDesc may pass back + */ + eCSR_ROAM_RESULT_IBSS_STARTED, + eCSR_ROAM_RESULT_IBSS_START_FAILED, + eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS, + eCSR_ROAM_RESULT_IBSS_JOIN_FAILED, + eCSR_ROAM_RESULT_IBSS_CONNECT, + eCSR_ROAM_RESULT_IBSS_INACTIVE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION + * tCsrRoamInfo's pBssDesc may pass back and the peer's MAC address + * in peerMacOrBssid. If roamStatus is eCSR_ROAM_IBSS_IND, + * the peer's MAC address in peerMacOrBssid and a beacon frame + * of the IBSS in pbFrames + */ + eCSR_ROAM_RESULT_IBSS_NEW_PEER, + /* + * Peer departed from IBSS, Callback may get a pointer tSmeIbssPeerInd + * in pIbssPeerInd + */ + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED, + /* + * Coalescing in the IBSS network (joined an IBSS network) + * Callback pass a BSSID in peerMacOrBssid + */ + eCSR_ROAM_RESULT_IBSS_COALESCED, + /* + * If roamStatus is eCSR_ROAM_ROAMING_START, callback may get a pointer + * to tCsrConnectedProfile used to connect. + */ + eCSR_ROAM_RESULT_IBSS_STOP, + eCSR_ROAM_RESULT_LOSTLINK, + eCSR_ROAM_RESULT_MIC_ERROR_UNICAST, + eCSR_ROAM_RESULT_MIC_ERROR_GROUP, + eCSR_ROAM_RESULT_AUTHENTICATED, + eCSR_ROAM_RESULT_NEW_RSN_BSS, +#ifdef FEATURE_WLAN_WAPI + eCSR_ROAM_RESULT_NEW_WAPI_BSS, +#endif /* FEATURE_WLAN_WAPI */ + /* WDS started successfully */ + eCSR_ROAM_RESULT_WDS_STARTED, + /* WDS start failed */ + eCSR_ROAM_RESULT_WDS_START_FAILED, + /* WDS stopped */ + eCSR_ROAM_RESULT_WDS_STOPPED, + /* WDS joined successfully in STA mode */ + eCSR_ROAM_RESULT_WDS_ASSOCIATED, + /* A station joined WDS AP */ + eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND, + /* WDS join failed in STA mode */ + eCSR_ROAM_RESULT_WDS_NOT_ASSOCIATED, + /* WDS disassociated */ + eCSR_ROAM_RESULT_WDS_DISASSOCIATED, + /* INFRA started successfully */ + eCSR_ROAM_RESULT_INFRA_STARTED, + /* INFRA start failed */ + eCSR_ROAM_RESULT_INFRA_START_FAILED, + /* INFRA stopped */ + eCSR_ROAM_RESULT_INFRA_STOPPED, + /* A station joining INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND, + /* A station joined INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF, + /* INFRA disassociated */ + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_SEND_ACTION_FAIL, + /* peer rejected assoc because max assoc limit reached */ + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED, + /* Assoc rejected due to concurrent session running on a diff channel */ + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL, +#ifdef FEATURE_WLAN_TDLS + eCSR_ROAM_RESULT_ADD_TDLS_PEER, + eCSR_ROAM_RESULT_UPDATE_TDLS_PEER, + eCSR_ROAM_RESULT_DELETE_TDLS_PEER, + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND, + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP, + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER, + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN, + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED, +#endif + + eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE, + eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS, + eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_FAILURE, +} eCsrRoamResult; + +/*---------------------------------------------------------------------------- + List of link quality indications HDD can receive from SME + --------------------------------------------------------------------------*/ +typedef enum { + eCSR_ROAM_LINK_QUAL_MIN_IND = -1, + + eCSR_ROAM_LINK_QUAL_POOR_IND = 0, /* bad link */ + eCSR_ROAM_LINK_QUAL_GOOD_IND = 1, /* acceptable for voice */ + eCSR_ROAM_LINK_QUAL_VERY_GOOD_IND = 2, /* suitable for voice */ + eCSR_ROAM_LINK_QUAL_EXCELLENT_IND = 3, /* suitable for voice */ + + eCSR_ROAM_LINK_QUAL_MAX_IND /* invalid value */ +} eCsrRoamLinkQualityInd; + +typedef enum { + eCSR_DISCONNECT_REASON_UNSPECIFIED = 0, + eCSR_DISCONNECT_REASON_MIC_ERROR, + eCSR_DISCONNECT_REASON_DISASSOC, + eCSR_DISCONNECT_REASON_DEAUTH, + eCSR_DISCONNECT_REASON_HANDOFF, + eCSR_DISCONNECT_REASON_IBSS_JOIN_FAILURE, + eCSR_DISCONNECT_REASON_IBSS_LEAVE, + eCSR_DISCONNECT_REASON_STA_HAS_LEFT, +} eCsrRoamDisconnectReason; + +typedef enum { + /* Not associated in Infra or participating in an IBSS/Ad-hoc */ + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED, + /* Associated in an Infrastructure network. */ + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED, + /* Participating in IBSS network though disconnection */ + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED, + /* Participating in IBSS network with partner stations also present */ + eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED, + /* Participating in WDS network in AP/STA mode but not connected yet */ + eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED, + /* Participating in a WDS network and connected peer to peer */ + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED, + /* Participating in a Infra network in AP not yet in connected state */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED, + /* Participating in a Infra network and connected to a peer */ + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED, + +} eCsrConnectState; + +/* + * This parameter is no longer supported in the Profile. + * Need to set this in the global properties for the adapter. + */ +typedef enum eCSR_MEDIUM_ACCESS { + eCSR_MEDIUM_ACCESS_AUTO = 0, + eCSR_MEDIUM_ACCESS_DCF, + eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_HCF, + + eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p, + eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP, + eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify, + eCSR_MEDIUM_ACCESS_11e_eDCF = eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_11e_HCF = eCSR_MEDIUM_ACCESS_HCF, +} eCsrMediaAccessType; + +typedef enum { + eCSR_TX_RATE_AUTO = 0, /* use rate adaption to determine Tx rate. */ + eCSR_TX_RATE_1Mbps = 0x00000001, + eCSR_TX_RATE_2Mbps = 0x00000002, + eCSR_TX_RATE_5_5Mbps = 0x00000004, + eCSR_TX_RATE_6Mbps = 0x00000008, + eCSR_TX_RATE_9Mbps = 0x00000010, + eCSR_TX_RATE_11Mbps = 0x00000020, + eCSR_TX_RATE_12Mbps = 0x00000040, + eCSR_TX_RATE_18Mbps = 0x00000080, + eCSR_TX_RATE_24Mbps = 0x00000100, + eCSR_TX_RATE_36Mbps = 0x00000200, + eCSR_TX_RATE_42Mbps = 0x00000400, + eCSR_TX_RATE_48Mbps = 0x00000800, + eCSR_TX_RATE_54Mbps = 0x00001000, + eCSR_TX_RATE_72Mbps = 0x00002000, + eCSR_TX_RATE_84Mbps = 0x00004000, + eCSR_TX_RATE_96Mbps = 0x00008000, + eCSR_TX_RATE_108Mbps = 0x00010000, + eCSR_TX_RATE_126Mbps = 0x00020000, + eCSR_TX_RATE_144Mbps = 0x00040000, + eCSR_TX_RATE_168Mbps = 0x00080000, + eCSR_TX_RATE_192Mbps = 0x00100000, + eCSR_TX_RATE_216Mbps = 0x00200000, + eCSR_TX_RATE_240Mbps = 0x00400000, + +} eCsrExposedTxRate; + +typedef enum { + eCSR_OPERATING_CHANNEL_ALL = 0, + eCSR_OPERATING_CHANNEL_AUTO = eCSR_OPERATING_CHANNEL_ALL, + eCSR_OPERATING_CHANNEL_ANY = eCSR_OPERATING_CHANNEL_ALL, +} eOperationChannel; + +typedef enum { + eCSR_DOT11_FRAG_THRESH_AUTO = -1, + eCSR_DOT11_FRAG_THRESH_MIN = 256, + eCSR_DOT11_FRAG_THRESH_MAX = 2346, + eCSR_DOT11_FRAG_THRESH_DEFAULT = 2000 +} eCsrDot11FragThresh; + +/* for channel bonding for ibss */ +typedef enum { + eCSR_CB_OFF = 0, + eCSR_CB_AUTO = 1, + eCSR_CB_DOWN = 2, + eCSR_CB_UP = 3, +} eCsrCBChoice; + +/* + * For channel bonding, the channel number gap is 4, either up or down. + * For both 11a and 11g mode. + */ +#define CSR_CB_CHANNEL_GAP 4 +#define CSR_CB_CENTER_CHANNEL_OFFSET 2 + +/* WEP keysize (in bits) */ +typedef enum { + /* 40 bit key + 24bit IV = 64bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_40 = 40, + /* 104bit key + 24bit IV = 128bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_104 = 104, + eCSR_SECURITY_WEP_KEYSIZE_MIN = eCSR_SECURITY_WEP_KEYSIZE_40, + eCSR_SECURITY_WEP_KEYSIZE_MAX = eCSR_SECURITY_WEP_KEYSIZE_104, + eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES = + (eCSR_SECURITY_WEP_KEYSIZE_MAX / 8), +} eCsrWEPKeySize; + +/* Possible values for the WEP static key ID */ +typedef enum { + + eCSR_SECURITY_WEP_STATIC_KEY_ID_MIN = 0, + eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX = 3, + eCSR_SECURITY_WEP_STATIC_KEY_ID_DEFAULT = 0, + + eCSR_SECURITY_WEP_STATIC_KEY_ID_INVALID = -1, + +} eCsrWEPStaticKeyID; + +/* Two extra key indicies are used for the IGTK (which is used by BIP) */ +#define CSR_MAX_NUM_KEY (eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX + 2 + 1) + +typedef enum { + eCSR_SECURITY_SET_KEY_ACTION_NO_CHANGE, + eCSR_SECURITY_SET_KEY_ACTION_SET_KEY, + eCSR_SECURITY_SET_KEY_ACTION_DELETE_KEY, +} eCsrSetKeyAction; + +typedef enum { + eCSR_BAND_ALL, + eCSR_BAND_24, + eCSR_BAND_5G, + eCSR_BAND_MAX, +} eCsrBand; + +typedef enum { + /* + * Roaming because HDD requested for reassoc by changing one of the + * fields in tCsrRoamModifyProfileFields. OR Roaming because SME + * requested for reassoc by changing one of the fields in + * tCsrRoamModifyProfileFields. + */ + eCsrRoamReasonStaCapabilityChanged, + /* + * Roaming because SME requested for reassoc to a different AP, + * as part of inter AP handoff. + */ + eCsrRoamReasonBetterAP, + /* + * Roaming because SME requested it as the link is lost - placeholder, + * will clean it up once handoff code gets in + */ + eCsrRoamReasonSmeIssuedForLostLink, + +} eCsrRoamReasonCodes; + +typedef enum { + eCsrRoamWmmAuto = 0, + eCsrRoamWmmQbssOnly = 1, + eCsrRoamWmmNoQos = 2, + +} eCsrRoamWmmUserModeType; + +typedef enum { + eCSR_REQUESTER_MIN = 0, + eCSR_DIAG, + eCSR_UMA_GAN, + eCSR_HDD +} eCsrStatsRequesterType; + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +/** + * enum csr_hi_rssi_scan_id - Parameter ids for hi rssi scan feature + * + * @eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: how many times scan can be performed + * @eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: rssi difference to trigger scan + * @eCSR_HI_RSSI_SCAN_DELAY_ID: delay in millseconds between scans + * @eCSR_HI_RSSI_SCAN_RSSI_UB_ID: rssi upper bound for scan trigger + */ +enum csr_hi_rssi_scan_id { + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID, + eCSR_HI_RSSI_SCAN_DELAY_ID, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID +}; +#endif + +typedef struct tagPmkidCandidateInfo { + struct cdf_mac_addr BSSID; + bool preAuthSupported; +} tPmkidCandidateInfo; + +typedef struct tagPmkidCacheInfo { + struct cdf_mac_addr BSSID; + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; +} tPmkidCacheInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagBkidCandidateInfo { + struct cdf_mac_addr BSSID; + bool preAuthSupported; +} tBkidCandidateInfo; + +typedef struct tagBkidCacheInfo { + struct cdf_mac_addr BSSID; + uint8_t BKID[CSR_WAPI_BKID_SIZE]; +} tBkidCacheInfo; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagCsrKeys { + /* Also use to indicate whether the key index is set */ + uint8_t KeyLength[CSR_MAX_NUM_KEY]; + uint8_t KeyMaterial[CSR_MAX_NUM_KEY][CSR_MAX_KEY_LEN]; + uint8_t defaultIndex; +} tCsrKeys; + +/* + * Following fields which're part of tCsrRoamConnectedProfile might need + * modification dynamically once STA is up & running & this'd trigger reassoc + */ +typedef struct tagCsrRoamModifyProfileFields { + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc response this COULD carry confirmation of what + * ACs U-APSD got setup for. Later if an APP looking for APSD, + * SME-QoS might need to modify this field + */ + uint8_t uapsd_mask; + /* HDD might ask to modify this field */ + uint16_t listen_interval; +} tCsrRoamModifyProfileFields; + +typedef struct tagCsrRoamProfile { + /* + * For eCSR_BSS_TYPE_WDS_AP. There must be one SSID in SSIDs. + * For eCSR_BSS_TYPE_WDS_STA. There must be two SSIDs. + * Index 0 is the SSID of the WDS-AP that we need to join. + * Index 1 is the SSID for self BSS. + */ + tCsrSSIDs SSIDs; + tCsrBSSIDs BSSIDs; + /* this is bit mask of all the needed phy mode defined in eCsrPhyMode */ + uint32_t phyMode; + eCsrRoamBssType BSSType; + tCsrAuthList AuthType; + eCsrAuthType negotiatedAuthType; + tCsrEncryptionList EncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedUCEncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedMCEncryptionType; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + tCsrKeys Keys; + eCsrCBChoice CBMode; + tCsrChannelInfo ChannelInfo; + uint8_t operationChannel; + chan_params_t ch_params; + /* If this is 0, SME will fill in for caller. */ + uint16_t beaconInterval; + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc resp this'd carry cnf of what ACs U-APSD got setup for + */ + uint8_t uapsd_mask; + uint32_t nWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint8_t *pWPAReqIE; /* If not null,it's IE byte stream for WPA */ + uint32_t nRSNReqIELength; /* The byte count in the pRSNReqIE */ + uint8_t *pRSNReqIE; /* If not null,it's IE byte stream for RSN */ +#ifdef FEATURE_WLAN_WAPI + uint32_t nWAPIReqIELength;/* The byte count in the pWAPIReqIE */ + uint8_t *pWAPIReqIE; /* If not null,it's IE byte stream for WAPI */ +#endif /* FEATURE_WLAN_WAPI */ + + uint32_t nAddIEScanLength;/* pAddIE for scan (at the time of join) */ + /* + * If not null,it's the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* The byte count in the pAddIE for assoc */ + /* + * If not null, it has the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + /* WPS Association if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; + uint32_t nWSCReqIELength; /* The byte count in the pWSCReqIE */ + uint8_t *pWSCReqIE; /* If not null,it's IE byte stream for WSC */ + uint8_t ieee80211d; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + tAniAuthType csr80211AuthType; + uint32_t dtimPeriod; + bool ApUapsdEnable; + bool protEnabled; + bool obssProtEnabled; + uint16_t cfg_protection; + uint8_t wps_state; +#ifdef WLAN_FEATURE_VOWIFI_11R + tCsrMobilityDomainInfo MDID; +#endif + tCDF_CON_MODE csrPersona; + uint8_t disableDFSChSwitch; + /* addIe params */ + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; +} tCsrRoamProfile; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct tagCsrRoamHTProfile { + uint8_t phymode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; +#ifdef WLAN_FEATURE_11AC + uint8_t vhtCapability; + uint8_t vhtTxChannelWidthSet; + uint8_t apCenterChan; + uint8_t apChanWidth; +#endif +} tCsrRoamHTProfile; +#endif +typedef struct tagCsrRoamConnectedProfile { + tSirMacSSid SSID; + bool handoffPermitted; + bool ssidHidden; + struct cdf_mac_addr bssid; + eCsrRoamBssType BSSType; + eCsrAuthType AuthType; + tCsrAuthList AuthInfo; + eCsrEncryptionType EncryptionType; + tCsrEncryptionList EncryptionInfo; + eCsrEncryptionType mcEncryptionType; + tCsrEncryptionList mcEncryptionInfo; + eCsrCBChoice CBMode; + uint8_t operationChannel; + uint32_t vht_channel_width; + uint16_t beaconInterval; + tCsrKeys Keys; + /* + * meaningless on connect. It's an OUT param from CSR's point of view + * During assoc response carries the ACM bit-mask i.e. what + * ACs have ACM=1 (if any),(Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE + * all other bits are ignored) + */ + uint8_t acm_mask; + tCsrRoamModifyProfileFields modifyProfileFields; + uint32_t nAddIEAssocLength; + /* + * If not null,it's IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + tSirBssDescription *pBssDesc; + bool qap; /* AP supports QoS */ + bool qosConnection; /* A connection is QoS enabled */ +#ifdef WLAN_FEATURE_VOWIFI_11R + tCsrMobilityDomainInfo MDID; +#endif +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isESEAssoc; +#endif + uint32_t dot11Mode; + uint8_t proxyARPService; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tCsrRoamHTProfile HTProfile; +#endif +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif +} tCsrRoamConnectedProfile; + +#ifdef WLAN_FEATURE_VOWIFI_11R +typedef struct tagCsr11rConfigParams { + bool IsFTResourceReqSupported; +} tCsr11rConfigParams; +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +typedef struct tagCsrNeighborRoamConfigParams { + + uint32_t nNeighborScanTimerPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +} tCsrNeighborRoamConfigParams; +#endif + +typedef struct tagCsrConfigParam { + uint32_t FragmentationThreshold; + /* keep this uint32_t. This gets converted to ePhyChannelBondState */ + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + eCsrPhyMode phyMode; + eCsrBand eBand; + uint32_t RTSThreshold; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + eCsrCBChoice cbChoice; + eCsrBand bandCapability; /* indicate hw capability */ + uint16_t TxRate; + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11dSupportEnabledOriginal; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* + * this number minus one is the number of times a scan doesn't find it + * before it is removed + */ + uint32_t nScanResultAgeCount; + /* scan res aging time threshold when Not-Connect-No-PowerSave,in sec */ + uint32_t scanAgeTimeNCNPS; + /* scan res aging time threshold when Not-Connect-Power-Save,in sec */ + uint32_t scanAgeTimeNCPS; + /* scan res aging time threshold when Connect-No-Power-Save, in sec */ + uint32_t scanAgeTimeCNPS; + /* scan res aging time threshold when Connect-Power-Save, in sec */ + uint32_t scanAgeTimeCPS; + /* In sec, CSR'll try this long before gives up. 0 means no roaming */ + uint32_t nRoamingTime; + /* to set the RSSI difference for each category */ + uint8_t bCatRssiOffset; + /* to set MCC Enable/Disable mode */ + uint8_t fEnableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + /* + * To allow MCC GO different B.I than STA's. + * NOTE: make sure if RIVA firmware can handle this combination before + * enabling this at the moment, this flag is provided only to pass + * Wi-Fi Cert. 5.1.12 + */ + uint8_t fAllowMCCGODiffBI; + tCsr11dinfo Csr11dinfo; + + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* num of channels combined for STA in each split scan operation */ + uint8_t nNumStaChanCombinedConc; + /* number of channels combined for P2P in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; +#endif + /* + * in dBm, the maximum TX power The actual TX power is the lesser of + * this value and 11d. If 11d is disable, the lesser of this and + * default setting. + */ + uint8_t nTxPowerCap; + /* stats request frequency from PE while in full power */ + uint32_t statsReqPeriodicity; + /* stats request frequency from PE while in power save */ + uint32_t statsReqPeriodicityInPS; +#ifdef WLAN_FEATURE_VOWIFI_11R + tCsr11rConfigParams csr11rConfig; +#endif +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif +#ifdef FEATURE_WLAN_LFR + uint8_t isFastRoamIniFeatureEnabled; + uint8_t MAWCEnabled; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool isWESModeEnabled; +#endif +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + tCsrNeighborRoamConfigParams neighborRoamConfig; +#endif + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for that AC + * This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + /* + * channelPowerInfoList24 has been seen corrupted. Set this flag to true + * trying to detect when it happens. Adding this into code because we + * can't reproduce it easily. We don't know when it happens. + */ + bool fValidateList; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + /* + * To enable/disable scanning 2.4Ghz channels twice on a single scan + * request from HDD + */ + bool fScanTwice; +#ifdef WLAN_FEATURE_11AC + uint32_t nVhtChannelWidth; + uint8_t enableTxBF; + uint8_t txBFCsnValue; + uint8_t enable2x2; + bool enableVhtFor24GHz; + uint8_t enableMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; +#endif + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool ignore_peer_erp_info; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + + bool isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; +#endif + uint8_t scanCfgAgingTime; + uint8_t enableTxLdpc; + uint8_t isAmsduSupportInAMPDU; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + bool sendDeauthBeforeCon; + + /* 802.11p enable */ + bool enable_dot11p; + uint8_t max_scan_count; +} tCsrConfigParam; + +/* Tush */ +typedef struct tagCsrUpdateConfigParam { + tCsr11dinfo Csr11dinfo; +} tCsrUpdateConfigParam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define csr_roamIsRoamOffloadEnabled(pMac) \ + (pMac->roam.configParam.isRoamOffloadEnabled) +#define DEFAULT_REASSOC_FAILURE_TIMEOUT 1000 +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* connected but not authenticated */ +#define CSR_ROAM_AUTH_STATUS_CONNECTED 0x1 +/* connected and authenticated */ +#define CSR_ROAM_AUTH_STATUS_AUTHENTICATED 0x2 +#endif + +typedef struct tagCsrRoamInfo { + tCsrRoamProfile *pProfile; + tSirBssDescription *pBssDesc; + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; + uint32_t nFrameLength; + uint8_t frameType; + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, + * in that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; + bool fReassocReq; /* set to true if for re-association */ + bool fReassocRsp; /* set to true if for re-association */ + struct cdf_mac_addr bssid; + /* + * Only valid in IBSS. this is the peers MAC address for + * eCSR_ROAM_RESULT_IBSS_NEW_PEER or PEER_DEPARTED + */ + struct cdf_mac_addr peerMac; + tSirResultCodes statusCode; + /* this'd be our own defined or sent from otherBSS(per 802.11spec) */ + uint32_t reasonCode; + uint8_t staId; /* Peer stationId when connected */ + /* + * The DPU signatures will be sent eventually to TL to help it + * determine the assoc to which a packet belongs to unicast DPU sign + */ + uint8_t ucastSig; + uint8_t bcastSig; /* Broadcast DPU signature */ + /* false means auth needed from supplicant. true means authenticated */ + bool fAuthRequired; + uint8_t sessionId; + uint8_t rsnIELen; + uint8_t *prsnIE; + uint8_t wapiIELen; + uint8_t *pwapiIE; + uint8_t addIELen; + uint8_t *paddIE; + union { + tSirMicFailureInfo *pMICFailureInfo; + tCsrRoamConnectedProfile *pConnectedProfile; + tSirWPSPBCProbeReq *pWPSPBCProbeReq; + } u; + bool wmmEnabledSta; /* set to true if WMM enabled STA */ + uint32_t dtimPeriod; +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; +#ifdef FEATURE_WLAN_ESE_UPLOAD + tSirTsmIE tsmIe; + uint32_t timestamp[2]; + uint16_t tsmRoamDelay; + tSirEseBcnReportRsp *pEseBcnReportRsp; +#endif /* FEATURE_WLAN_ESE_UPLOAD */ +#endif + void *pRemainCtx; + uint32_t roc_scan_id; + uint32_t rxChan; +#ifdef FEATURE_WLAN_TDLS + uint8_t staType; + bool tdls_prohibited; /* per ExtCap in Assoc/Reassoc resp */ + bool tdls_chan_swit_prohibited; /* per ExtCap in Assoc/Reassoc resp */ +#endif + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + int8_t rxRssi; + tSirSmeDfsEventInd dfs_event; + tSirChanChangeResponse *channelChangeRespEvent; + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t roamSynchInProgress; + uint8_t synchAuthStatus; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; +#endif + tSirSmeChanInfo chan_info; +} tCsrRoamInfo; + +typedef struct tagCsrFreqScanInfo { + uint32_t nStartFreq; /* in unit of MHz */ + uint32_t nEndFreq; /* in unit of MHz */ + tSirScanType scanType; +} tCsrFreqScanInfo; + +typedef struct sSirSmeAssocIndToUpperLayerCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + tSirMacAddr bssId; /* Self BSSID */ + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr alternateBssId; + uint8_t alternateChannelId; + uint8_t wmmEnabledSta; /* set to true if WMM enabled STA */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirAddie addIE; /* this can be WSC and/or P2P IE */ + uint8_t reassocReq; /* set to true if reassoc */ + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; +} tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf; + +typedef struct tagCsrSummaryStatsInfo { + uint32_t retry_cnt[4]; + uint32_t multiple_retry_cnt[4]; + uint32_t tx_frm_cnt[4]; + /* uint32_t num_rx_frm_crc_err; same as rx_error_cnt */ + /* uint32_t num_rx_frm_crc_ok; same as rx_frm_cnt */ + uint32_t rx_frm_cnt; + uint32_t frm_dup_cnt; + uint32_t fail_cnt[4]; + uint32_t rts_fail_cnt; + uint32_t ack_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_discard_cnt; + uint32_t rx_error_cnt; + uint32_t tx_byte_cnt; + +} tCsrSummaryStatsInfo; + +typedef struct tagCsrGlobalClassAStatsInfo { + uint32_t rx_frag_cnt; + uint32_t promiscuous_rx_frag_cnt; + /* uint32_t rx_fcs_err; */ + uint32_t rx_input_sensitivity; + uint32_t max_pwr; + /* uint32_t default_pwr; */ + uint32_t sync_fail_cnt; + uint32_t tx_rate; + /* mcs index for HT20 and HT40 rates */ + uint32_t mcs_index; + /* to diff between HT20 & HT40 rates;short & long guard interval */ + uint32_t tx_rate_flags; + +} tCsrGlobalClassAStatsInfo; + +typedef struct tagCsrGlobalClassBStatsInfo { + uint32_t uc_rx_wep_unencrypted_frm_cnt; + uint32_t uc_rx_mic_fail_cnt; + uint32_t uc_tkip_icv_err; + uint32_t uc_aes_ccmp_format_err; + uint32_t uc_aes_ccmp_replay_cnt; + uint32_t uc_aes_ccmp_decrpt_err; + uint32_t uc_wep_undecryptable_cnt; + uint32_t uc_wep_icv_err; + uint32_t uc_rx_decrypt_succ_cnt; + uint32_t uc_rx_decrypt_fail_cnt; + uint32_t mcbc_rx_wep_unencrypted_frm_cnt; + uint32_t mcbc_rx_mic_fail_cnt; + uint32_t mcbc_tkip_icv_err; + uint32_t mcbc_aes_ccmp_format_err; + uint32_t mcbc_aes_ccmp_replay_cnt; + uint32_t mcbc_aes_ccmp_decrpt_err; + uint32_t mcbc_wep_undecryptable_cnt; + uint32_t mcbc_wep_icv_err; + uint32_t mcbc_rx_decrypt_succ_cnt; + uint32_t mcbc_rx_decrypt_fail_cnt; + +} tCsrGlobalClassBStatsInfo; + +typedef struct tagCsrGlobalClassCStatsInfo { + uint32_t rx_amsdu_cnt; + uint32_t rx_ampdu_cnt; + uint32_t tx_20_frm_cnt; + uint32_t rx_20_frm_cnt; + uint32_t rx_mpdu_in_ampdu_cnt; + uint32_t ampdu_delimiter_crc_err; + +} tCsrGlobalClassCStatsInfo; + +typedef struct tagCsrGlobalClassDStatsInfo { + uint32_t tx_uc_frm_cnt; + uint32_t tx_mc_frm_cnt; + uint32_t tx_bc_frm_cnt; + uint32_t rx_uc_frm_cnt; + uint32_t rx_mc_frm_cnt; + uint32_t rx_bc_frm_cnt; + uint32_t tx_uc_byte_cnt[4]; + uint32_t tx_mc_byte_cnt; + uint32_t tx_bc_byte_cnt; + uint32_t rx_uc_byte_cnt[4]; + uint32_t rx_mc_byte_cnt; + uint32_t rx_bc_byte_cnt; + uint32_t rx_byte_cnt; + uint32_t num_rx_bytes_crc_ok; + uint32_t rx_rate; + +} tCsrGlobalClassDStatsInfo; + +typedef struct tagCsrPerStaStatsInfo { + uint32_t tx_frag_cnt[4]; + uint32_t tx_ampdu_cnt; + uint32_t tx_mpdu_in_ampdu_cnt; +} tCsrPerStaStatsInfo; + +typedef struct tagCsrRoamSetKey { + eCsrEncryptionType encType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + struct cdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Key index */ + uint16_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +} tCsrRoamSetKey; + +typedef struct tagCsrRoamRemoveKey { + eCsrEncryptionType encType; + struct cdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t keyId; /* key index */ +} tCsrRoamRemoveKey; + +#ifdef FEATURE_WLAN_TDLS + +typedef struct tagCsrLinkEstablishParams { + tSirMacAddr peerMac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[SIR_MAC_MAX_SUPP_OPER_CLASSES]; +} tCsrTdlsLinkEstablishParams; + +typedef struct tagCsrTdlsSendMgmt { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; + +} tCsrTdlsSendMgmt; +#endif + +typedef void *tScanResultHandle; + +typedef enum { + REASSOC = 0, + FASTREASSOC = 1 +} handoff_src; + +typedef struct tagCsrHandoffRequest { + struct cdf_mac_addr bssid; + uint8_t channel; + uint8_t src; /* To check if its a REASSOC or a FASTREASSOC IOCTL */ +} tCsrHandoffRequest; + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +typedef struct tagCsrEseBeaconReqParams { + uint16_t measurementToken; + uint8_t channel; + uint8_t scanMode; + uint16_t measurementDuration; +} tCsrEseBeaconReqParams, *tpCsrEseBeaconReqParams; + +typedef struct tagCsrEseBeaconReq { + uint8_t numBcnReqIe; + tCsrEseBeaconReqParams bcnReq[SIR_ESE_MAX_MEAS_IE_REQS]; +} tCsrEseBeaconReq, *tpCsrEseBeaconReq; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +struct tagCsrDelStaParams { + struct cdf_mac_addr peerMacAddr; + uint16_t reason_code; + uint8_t subtype; +}; + +/* + * NOTE: p2 is the second context pass in for the caller + * NOTE: what if callback is called before requester gets the scanId?? + */ +typedef CDF_STATUS (*csr_scan_completeCallback)(tHalHandle, void *p2, + uint8_t sessionId, + uint32_t scanID, + eCsrScanStatus status); +typedef CDF_STATUS (*csr_roam_completeCallback)(void *pContext, + tCsrRoamInfo * pParam, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); +typedef CDF_STATUS (*csr_roamSessionCloseCallback)(void *pContext); + +#define CSR_IS_START_IBSS(pProfile) (eCSR_BSS_TYPE_START_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_JOIN_TO_IBSS(pProfile) (eCSR_BSS_TYPE_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_IBSS(pProfile) (CSR_IS_START_IBSS(pProfile) || \ + CSR_IS_JOIN_TO_IBSS(pProfile)) +#define CSR_IS_INFRASTRUCTURE(pProfile) (eCSR_BSS_TYPE_INFRASTRUCTURE == \ + (pProfile)->BSSType) +#define CSR_IS_ANY_BSS_TYPE(pProfile) (eCSR_BSS_TYPE_ANY == \ + (pProfile)->BSSType) +#define CSR_IS_WDS_AP(pProfile) (eCSR_BSS_TYPE_WDS_AP == (pProfile)->BSSType) +#define CSR_IS_WDS_STA(pProfile) (eCSR_BSS_TYPE_WDS_STA == (pProfile)->BSSType) +#define CSR_IS_WDS(pProfile) (CSR_IS_WDS_AP(pProfile) || \ + CSR_IS_WDS_STA(pProfile)) +#define CSR_IS_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#define CSR_IS_CONN_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#define CSR_IS_CONN_WDS_AP(pProfile) (eCSR_BSS_TYPE_WDS_AP == \ + (pProfile)->BSSType) +#define CSR_IS_CONN_WDS_STA(pProfile) (eCSR_BSS_TYPE_WDS_STA == \ + (pProfile)->BSSType) +#define CSR_IS_CONN_WDS(pProfile) (CSR_IS_WDS_AP(pProfile) || \ + CSR_IS_WDS_STA(pProfile)) +#define CSR_IS_CLOSE_SESSION_COMMAND(pCommand) \ + ((pCommand)->command == eSmeCommandDelStaSession) + +CDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam); + +CDF_STATUS csr_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode); + +/* enum to string conversion for debug output */ +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val); +const char *get_e_csr_roam_result_str(eCsrRoamResult val); +CDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, eCsrBand eBand, + bool *pfRestartNeeded); +typedef void (*csr_roamLinkQualityIndCallback) + (eCsrRoamLinkQualityInd ind, void *pContext); +typedef void (*tCsrStatsCallback)(void *stats, void *pContext); +typedef void (*tCsrRssiCallback)(int8_t rssi, uint32_t staId, void *pContext); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +typedef void (*tCsrTsmStatsCallback)(tAniTrafStrmMetrics tsmMetrics, + uint32_t staId, void *pContext); +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +typedef void (*tCsrSnrCallback)(int8_t snr, uint32_t staId, void *pContext); + +#ifdef WLAN_FEATURE_VOWIFI_11R +CDF_STATUS csr_roam_issue_ft_preauth_req(tHalHandle hHal, uint32_t sessionId, + tpSirBssDescription pBssDescription); +#endif +CDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand); +eCsrBand csr_get_current_band(tHalHandle hHal); +typedef void (*csr_readyToSuspendCallback)(void *pContext, bool suspended); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef void (*csr_readyToExtWoWCallback)(void *pContext, bool status); +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_roam_issue_ft_roam_offload_synch(tHalHandle hHal, + uint32_t sessionId, tSirBssDescription *pBssDescription); +#endif +typedef void (*tCsrLinkStatusCallback)(uint8_t status, void *pContext); +#endif diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h new file mode 100644 index 0000000000..e12fc255d2 --- /dev/null +++ b/core/sme/inc/csr_internal.h @@ -0,0 +1,1403 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_internal.h + * + * Define internal data structure for MAC. + */ +#ifndef CSRINTERNAL_H__ +#define CSRINTERNAL_H__ + +#include "cdf_status.h" +#include "cdf_lock.h" + +#include "cdf_mc_timer.h" +#include "csr_support.h" +#include "cds_reg_service.h" + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +#include "csr_neighbor_roam.h" +#endif + +#include "sir_types.h" + +#define CSR_MAX_STA (HAL_NUM_STA) + +/* define scan return criteria. LIM should use these define as well */ +#define CSR_SCAN_RETURN_AFTER_ALL_CHANNELS (0) +#define CSR_SCAN_RETURN_AFTER_FIRST_MATCH (0x01) +#define CSR_SCAN_RETURN_AFTER_5_BAND_11d_FOUND (0x80) +#define CSR_SCAN_RETURN_AFTER_24_BAND_11d_FOUND (0x40) +#define CSR_SCAN_RETURN_AFTER_EITHER_BAND_11d_FOUND \ + (CSR_SCAN_RETURN_AFTER_5_BAND_11d_FOUND | \ + CSR_SCAN_RETURN_AFTER_24_BAND_11d_FOUND) +#define CSR_NUM_RSSI_CAT 15 +#define CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME 3 + +/* session ID invalid */ +#define CSR_SESSION_ID_INVALID 0xFF +/* No of sessions to be supported, and a session is for Infra, IBSS or BT-AMP */ +#define CSR_ROAM_SESSION_MAX 5 +#define CSR_IS_SESSION_VALID(pMac, sessionId) \ + (((sessionId) < CSR_ROAM_SESSION_MAX) && \ + ((pMac)->roam.roamSession[(sessionId)].sessionActive)) + +#define CSR_GET_SESSION(pMac, sessionId) \ + ( \ + (sessionId < CSR_ROAM_SESSION_MAX) ? \ + (&(pMac)->roam.roamSession[(sessionId)]) : NULL \ + ) + +#define CSR_IS_SESSION_ANY(sessionId) (sessionId == SME_SESSION_ID_ANY) +#define CSR_MAX_NUM_COUNTRY_CODE 100 +#define CSR_IS_SELECT_5GHZ_MARGIN(pMac) \ + ( \ + (((pMac)->roam.configParam.nSelect5GHzMargin) ? true : false) \ + ) +#define CSR_IS_SELECT_5G_PREFERRED(pMac) \ + ( \ + (((pMac)->roam.configParam.roam_params.is_5g_pref_enabled) ? \ + true : false) \ + ) +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) +#define CSR_IS_ROAM_PREFER_5GHZ(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamPrefer5GHz) ? true : false) \ + ) +#define CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamIntraBand) ? true : false) \ + ) +#endif +#define CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.bFastRoamInConIniFeatureEnabled) ? \ + true : false) \ + ) + +/* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */ +#define CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15 + +/* Used to determine what to set to the WNI_CFG_DOT11_MODE */ +typedef enum { + eCSR_CFG_DOT11_MODE_ABG, + eCSR_CFG_DOT11_MODE_11A, + eCSR_CFG_DOT11_MODE_11B, + eCSR_CFG_DOT11_MODE_11G, + eCSR_CFG_DOT11_MODE_11N, +#ifdef WLAN_FEATURE_11AC + eCSR_CFG_DOT11_MODE_11AC, +#endif + eCSR_CFG_DOT11_MODE_11G_ONLY, + eCSR_CFG_DOT11_MODE_11N_ONLY, +#ifdef WLAN_FEATURE_11AC + eCSR_CFG_DOT11_MODE_11AC_ONLY, +#endif + /* This value can never set to CFG. Its for CSR's internal use */ + eCSR_CFG_DOT11_MODE_AUTO, +} eCsrCfgDot11Mode; + +typedef enum etCsrRoamCommands { + eCsrRoamNoCommand, + eCsrRoamCommandScan, + eCsrRoamCommandRoam, + eCsrRoamCommandWmStatusChange, + eCsrRoamCommandSetKey, + eCsrRoamCommandRemoveKey, + +} eCsrRoamCommands; + +typedef enum { + eCsrScanOther = 1, + eCsrScanLostLink1, + eCsrScanLostLink2, + eCsrScanLostLink3, + eCsrScanLostLink4, + eCsrScan11d1, /* First 11d scan */ + eCsrScan11d2, /* First 11d scan has failed */ + eCsrScan11dDone, /* 11d scan succeed, try rest of the channels */ + eCsrScanUserRequest, + eCsrScanForSsid, + eCsrScanIdleScan, + eCsrScanProbeBss, /* direct prb on entry from candidate list-HO */ + eCsrScanAbortNormalScan,/* aborting a normal scan */ + eCsrScanP2PFindPeer, + eCsrScanCandidateFound, +} eCsrScanReason; + +typedef enum { + /* Roaming because we've not established the initial connection. */ + eCsrNoConnection, + /* roaming because LIM reported a cap change in the associated AP. */ + eCsrCapsChange, + /* roaming because someone asked us to Disassoc & stay disassociated. */ + eCsrForcedDisassoc, + /* roaming because an 802.11 request was issued to the driver. */ + eCsrHddIssued, + /* roaming because we lost link to an associated AP */ + eCsrLostLink1, + eCsrLostLink2, + eCsrLostLink3, + /* roaming because we need to force a Disassoc due to MIC failure */ + eCsrForcedDisassocMICFailure, + eCsrHddIssuedReassocToSameAP, + eCsrSmeIssuedReassocToSameAP, + eCsrSmeIssuedReassocToDiffAP, + /* roaming becuase someone asked us to deauth and stay disassociated. */ + eCsrForcedDeauth, + /* will be issued by Handoff logic to disconect from current AP */ + eCsrSmeIssuedDisassocForHandoff, + /* will be issued by Handoff logic to join a new AP with same profile */ + eCsrSmeIssuedAssocToSimilarAP, + /* ibss jointimer fired before any peer showedup, so shutdown network */ + eCsrSmeIssuedIbssJoinFailure, + eCsrForcedIbssLeave, + eCsrStopBss, + eCsrSmeIssuedFTReassoc, + eCsrForcedDisassocSta, + eCsrForcedDeauthSta, + eCsrPerformPreauth, + eCsrLostLink1Abort, + eCsrLostLink2Abort, + eCsrLostLink3Abort, +} eCsrRoamReason; + +typedef enum { + eCSR_ROAM_SUBSTATE_NONE = 0, + eCSR_ROAM_SUBSTATE_START_BSS_REQ, + eCSR_ROAM_SUBSTATE_JOIN_REQ, + eCSR_ROAM_SUBSTATE_REASSOC_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, + /* Continue the current roam command after disconnect */ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + eCSR_ROAM_SUBSTATE_AUTH_REQ, + eCSR_ROAM_SUBSTATE_CONFIG, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT, + /* max is 15 unless the bitfield is expanded... */ +} eCsrRoamSubState; + +typedef enum { + eCSR_ROAMING_STATE_STOP = 0, + eCSR_ROAMING_STATE_IDLE, + eCSR_ROAMING_STATE_JOINING, + eCSR_ROAMING_STATE_JOINED, +} eCsrRoamState; + +typedef enum { + eCsrContinueRoaming, + eCsrStopRoaming, + eCsrStartIbss, + eCsrStartIbssSameIbss, + eCsrReassocToSelfNoCapChange, + eCsrStopRoamingDueToConcurrency, + +} eCsrJoinState; + +typedef enum { + eCsrNotRoaming, + eCsrLostlinkRoamingDisassoc, + eCsrLostlinkRoamingDeauth, + eCsrDynamicRoaming, + eCsrReassocRoaming, +} eCsrRoamingReason; + +typedef enum { + eCsrDisassociated, + eCsrDeauthenticated +} eCsrRoamWmStatusChangeTypes; + +typedef enum { + eCsrSummaryStats = 0, + eCsrGlobalClassAStats, + eCsrGlobalClassBStats, + eCsrGlobalClassCStats, + eCsrGlobalClassDStats, + eCsrPerStaStats, + eCsrMaxStats +} eCsrRoamStatsClassTypes; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +typedef enum { + eCSR_WLAN_STATUS_CONNECT = 0, + eCSR_WLAN_STATUS_DISCONNECT +} eCsrDiagWlanStatusEventSubtype; + +typedef enum { + eCSR_REASON_UNSPECIFIED = 0, + eCSR_REASON_USER_REQUESTED, + eCSR_REASON_MIC_ERROR, + eCSR_REASON_DISASSOC, + eCSR_REASON_DEAUTH, + eCSR_REASON_HANDOFF, + +} eCsrDiagWlanStatusEventReason; + +/** + * enum eCSR_WLAN_DIAG_EVENT_TYPE - enum for DIAG events + * @eCSR_EVENT_SCAN_COMPLETE - scan complete + * @eCSR_EVENT_SCAN_RES_FOUND - scan result found + */ +typedef enum { + eCSR_EVENT_TYPE_INVALID = 0, + eCSR_EVENT_SCAN_COMPLETE = 64, + eCSR_EVENT_SCAN_RES_FOUND = 65, +} eCSR_WLAN_DIAG_EVENT_TYPE; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +typedef struct tagCsrChannel { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsrChannel; + +typedef struct tagScanProfile { + uint32_t minChnTime; + uint32_t maxChnTime; + uint32_t restTime; /* This is ignored if not associated */ + uint32_t numOfChannels; + uint8_t *pChannelList; + tSirScanType scanType; + eCsrRoamBssType bssType; + uint8_t ssid[WNI_CFG_SSID_LEN]; + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + struct cdf_mac_addr bssid; +} tScanProfile; + +typedef struct tagBssConfigParam { + eCsrMediaAccessType qosType; + tSirMacSSid SSID; + uint32_t uRTSThresh; + uint32_t uDeferThresh; + eCsrCfgDot11Mode uCfgDot11Mode; + eCsrBand eBand; + uint8_t standardRate[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint8_t extendedRate[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + eCsrExposedTxRate txRate; + tAniAuthType authType; + eCsrEncryptionType encType; + uint32_t uShortSlotTime; + uint32_t uHTSupport; + uint32_t uPowerLimit; + uint32_t uHeartBeatThresh; + uint32_t uJoinTimeOut; + tSirMacCapabilityInfo BssCap; + bool f11hSupport; + ePhyChanBondState cbMode; +} tBssConfigParam; + +typedef struct tagCsrRoamStartBssParams { + tSirMacSSid ssId; + + /* + * This is the BSSID for the party we want to + * join (only use for IBSS or WDS). + */ + struct cdf_mac_addr bssid; + tSirNwType sirNwType; + ePhyChanBondState cbMode; + tSirMacRateSet operationalRateSet; + tSirMacRateSet extendedRateSet; + uint8_t operationChn; + chan_params_t ch_params; + eCsrCfgDot11Mode uCfgDot11Mode; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + tAniAuthType authType; + uint16_t beaconInterval; /* If this is 0, SME'll fill in for caller */ + uint16_t ht_protection; + uint32_t dtimPeriod; + uint8_t ApUapsdEnable; + uint8_t ssidHidden; + uint8_t wps_state; + tCDF_CON_MODE bssPersona; + uint16_t nRSNIELength; /* If 0, pRSNIE is ignored. */ + uint8_t *pRSNIE; /* If not null, it has IE byte stream for RSN */ + /* Flag used to indicate update beaconInterval */ + bool updatebeaconInterval; +#ifdef WLAN_FEATURE_11W + bool mfpCapable; + bool mfpRequired; +#endif + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; +} tCsrRoamStartBssParams; + +typedef struct tagScanCmd { + uint32_t scanID; + csr_scan_completeCallback callback; + void *pContext; + eCsrScanReason reason; + eCsrRoamState lastRoamState[CSR_ROAM_SESSION_MAX]; + tCsrRoamProfile *pToRoamProfile; + /* this is the ID related to the pToRoamProfile */ + uint32_t roamId; + union { + tCsrScanRequest scanRequest; + /* tCsrBGScanRequest bgScanRequest is no longer used */ + } u; + /* This flag will be set while aborting the scan due to band change */ + bool abortScanDueToBandChange; + cdf_mc_timer_t csr_scan_timer; +} tScanCmd; + +typedef struct tagRoamCmd { + uint32_t roamId; + eCsrRoamReason roamReason; + tCsrRoamProfile roamProfile; + tScanResultHandle hBSSList; /* BSS list fits the profile */ + /* + * point to the current BSS in the list that is roaming. + * It starts from head to tail + * */ + tListElem *pRoamBssEntry; + tSirBssDescription *pLastRoamBss; /* the last BSS we try and failed */ + bool fReleaseBssList; /* whether to free hBSSList */ + bool fReleaseProfile; /* whether to free roamProfile */ + bool fReassoc; /* whether this cmd is for reassoc */ + /* whether pMac->roam.pCurRoamProfile needs to be updated */ + bool fUpdateCurRoamProfile; + /* + * this is for CSR internal used only. And it should not be assigned + * when creating the command. This causes the roam cmd not todo anything + */ + bool fReassocToSelfNoCapChange; + + bool fStopWds; + tSirMacAddr peerMac; + tSirMacReasonCodes reason; +} tRoamCmd; + +typedef struct tagSetKeyCmd { + uint32_t roamId; + eCsrEncryptionType encType; + eCsrAuthType authType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + tSirMacAddr peerMac; /* Peer's MAC address. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Kye index */ + uint8_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +} tSetKeyCmd; + +typedef struct tagWmStatusChangeCmd { + eCsrRoamWmStatusChangeTypes Type; + union { + tSirSmeDeauthInd DeauthIndMsg; + tSirSmeDisassocInd DisassocIndMsg; + } u; + +} tWmStatusChangeCmd; + +typedef struct tagAddStaForSessionCmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + tCDF_CON_MODE currDeviceMode; + uint32_t type; + uint32_t subType; + uint8_t sessionId; +} tAddStaForSessionCmd; + +typedef struct tagDelStaForSessionCmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + csr_roamSessionCloseCallback callback; + void *pContext; +} tDelStaForSessionCmd; + +/* This structure represents one scan request */ +typedef struct tagCsrCmd { + tListElem Link; + eCsrRoamCommands command; + uint8_t sessionId; /* Session ID for this command */ + union { + tScanCmd scanCmd; + tRoamCmd roamCmd; + tWmStatusChangeCmd wmStatusChangeCmd; + tSetKeyCmd setKeyCmd; + tAddStaForSessionCmd addStaSessionCmd; + tDelStaForSessionCmd delStaSessionCmd; + } u; +} tCsrCmd; + +#ifdef WLAN_FEATURE_VOWIFI_11R +typedef struct tagCsr11rConfig { + bool IsFTResourceReqSupported; +} tCsr11rConfig; +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +typedef struct tagCsrNeighborRoamConfig { + uint32_t nNeighborScanTimerPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +} tCsrNeighborRoamConfig; +#endif + +typedef struct tagCsrConfig { + uint32_t agingCount; + uint32_t FragmentationThreshold; + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + uint32_t RTSThreshold; + eCsrPhyMode phyMode; + eCsrCfgDot11Mode uCfgDot11Mode; + eCsrBand eBand; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + eCsrCBChoice cbChoice; + eCsrBand bandCapability; /* indicate hw capability */ + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11dSupportEnabledOriginal; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + bool fenableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint16_t TxRate; + uint8_t fAllowMCCGODiffBI; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* scan res agingtime threshold when Not-Connect-No-Power-Save,in sec */ + uint32_t scanAgeTimeNCNPS; + /* scan res aging time threshold when Not-Connect-Power-Save, in sec*/ + uint32_t scanAgeTimeNCPS; + /* scan res aging time threshold when Connect-No-Power-Save, in sec*/ + uint32_t scanAgeTimeCNPS; + /* scan res aging time threshold when Connect-Power-Savein sec */ + uint32_t scanAgeTimeCPS; + /* each RSSI category has one value */ + uint32_t BssPreferValue[CSR_NUM_RSSI_CAT]; + int RSSICat[CSR_NUM_RSSI_CAT]; + uint8_t bCatRssiOffset; /* to set RSSI difference for each category */ + /* In secs, CSR'll try this long before gives up, 0 means no roaming */ + uint32_t nRoamingTime; + /* + * Whether to limit the channels to the ones set in Csr11dInfo. + * If true, the opertaional channels are limited to the default channel + * list. It is an "AND" operation between the default channels and + * the channels in the 802.11d IE. + */ + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc;/* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc;/* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* number of channels combined for Sta in each split scan operation */ + uint8_t nNumStaChanCombinedConc; + /* number of channels combined for P2P in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; +#endif + /* + * in dBm, the max TX power. The actual TX power is the lesser of this + * value & 11d. If 11d is disable, the lesser of this & default setting. + */ + uint8_t nTxPowerCap; + uint32_t statsReqPeriodicity; /* stats req freq while in fullpower */ + uint32_t statsReqPeriodicityInPS;/* stats req freq while in powersave */ + uint32_t dtimPeriod; + bool ssidHidden; +#ifdef WLAN_FEATURE_VOWIFI_11R + tCsr11rConfig csr11rConfig; +#endif +#ifdef FEATURE_WLAN_LFR + uint8_t isFastRoamIniFeatureEnabled; + uint8_t MAWCEnabled; + uint8_t isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; +#endif +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) \ + || defined(FEATURE_WLAN_LFR) + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + bool isWESModeEnabled; + bool nRoamScanControl; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; +#endif + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + tCsrNeighborRoamConfig neighborRoamConfig; +#endif + + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for + * that AC This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + bool fValidateList; + /* + * Remove this code once SLM_Sessionization is supported + * BMPS_WORKAROUND_NOT_NEEDED + */ + bool doBMPSWorkaround; + /* To enable scanning 2g channels twice on single scan req from HDD */ + bool fScanTwice; +#ifdef WLAN_FEATURE_11AC + uint32_t nVhtChannelWidth; + uint8_t txBFEnable; + uint8_t txBFCsnValue; + uint8_t enable2x2; + bool enableVhtFor24GHz; + uint8_t txMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; +#endif + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + uint8_t txLdpcEnable; + /* + * Enable/Disable heartbeat offload + */ + bool enableHeartBeatOffload; + uint8_t isAmsduSupportInAMPDU; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + bool ignore_peer_erp_info; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + struct roam_ext_params roam_params; + bool sendDeauthBeforeCon; +} tCsrConfig; + +typedef struct tagCsrChannelPowerInfo { + tListElem link; + uint8_t firstChannel; + uint8_t numChannels; + uint8_t txPower; + uint8_t interChannelOffset; +} tCsrChannelPowerInfo; + +typedef struct tagRoamJoinStatus { + tSirResultCodes statusCode; + /* + * this is set to unspecified if statusCode indicates timeout. + * Or it is the failed reason from the other BSS(per 802.11 spec) + */ + uint32_t reasonCode; + tSirMacAddr bssId; +} tCsrRoamJoinStatus; + +typedef struct tagCsrOsChannelMask { + uint8_t numChannels; + bool scanEnabled[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsrOsChannelMask; + +typedef struct tagCsrVotes11d { + uint8_t votes; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; +} tCsrVotes11d; + +typedef struct tagCsrScanStruct { + tScanProfile scanProfile; + tDblLinkList scanResultList; + tDblLinkList tempScanResults; + bool fScanEnable; + bool fFullScanIssued; +#ifdef WLAN_AP_STA_CONCURRENCY + cdf_mc_timer_t hTimerStaApConcTimer; +#endif + cdf_mc_timer_t hTimerIdleScan; + cdf_mc_timer_t hTimerResultCfgAging; + /* + * changes on every scan, it is used as a flag for whether 11d info is + * found on every scan + */ + uint8_t channelOf11dInfo; + uint8_t scanResultCfgAgingTime; + tSirScanType curScanType; + tCsrChannel channels11d; + tChannelListWithPower defaultPowerTable[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + tChannelListWithPower + defaultPowerTable40MHz[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numChannelsDefault; + tCsrChannel base_channels; /* The channel base to work on */ + tCsrChannel base40MHzChannels; /* center channels for 40MHz channels */ + tDblLinkList channelPowerInfoList24; + tDblLinkList channelPowerInfoList5G; + uint32_t nLastAgeTimeOut; + uint32_t nAgingCountDown; + uint8_t countryCodeDefault[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCodeCurrent[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCode11d[WNI_CFG_COUNTRY_CODE_LEN]; + v_REGDOMAIN_t domainIdDefault; /* default regulatory domain */ + v_REGDOMAIN_t domainIdCurrent; /* current regulatory domain */ + + /* Bssid for current country code */ + struct cdf_mac_addr currentCountryBssid; + + int8_t currentCountryRSSI; /* RSSI for current country code */ + bool fCancelIdleScan; + uint8_t countryCodeCount; + /* counts for various advertized country codes */ + tCsrVotes11d votes11d[CSR_MAX_NUM_COUNTRY_CODE]; + /* + * in 11d IE from probe rsp or beacons of neighboring APs + * will use the most popular one (max count) + */ + uint8_t countryCodeElected[WNI_CFG_COUNTRY_CODE_LEN]; + bool fRestartIdleScan; + uint32_t nIdleScanTimeGap; + /* keep a track of channels to be scnned while in traffic condition */ + tCsrOsChannelMask osScanChannelMask; + uint16_t nBssLimit; /* the maximum number of BSS in scan cache */ + /* + * channelPowerInfoList24 has been seen corrupted. Set this flag to true + * trying to detect when it happens. Adding this into code because we + * can't reproduce it easily. We don't know when it happens. + */ + bool fValidateList; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; + bool fDropScanCmd; /* true means we don't accept scan commands */ + +#ifdef WLAN_AP_STA_CONCURRENCY + tDblLinkList scanCmdPendingList; +#endif + /* This includes all channels on which candidate APs are found */ + tCsrChannel occupiedChannels[CSR_ROAM_SESSION_MAX]; + int8_t inScanResultBestAPRssi; + csr_scan_completeCallback callback11dScanDone; + bool fcc_constraint; + uint8_t max_scan_count; +} tCsrScanStruct; + +/* + * Save the connected information. This structure + connectedProfile + * should contain all information about the connection + */ +typedef struct tagRoamCsrConnectedInfo { + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; +#ifdef WLAN_FEATURE_VOWIFI_11R + /* len of the parsed RIC resp IEs received in reassoc response */ + uint32_t nRICRspLength; +#endif +#ifdef FEATURE_WLAN_ESE + uint32_t nTspecIeLength; +#endif + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, in + * that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; + uint8_t staId; +} tCsrRoamConnectedInfo; + +typedef struct tagCsrLinkQualityIndInfo { + csr_roamLinkQualityIndCallback callback; + void *context; +} tCsrLinkQualityIndInfo; + +typedef struct tagCsrPeStatsReqInfo { + tListElem link; /* list links */ + uint32_t statsMask; + uint32_t periodicity; + bool rspPending; + cdf_mc_timer_t hPeStatsTimer; + bool timerRunning; + uint8_t staId; + uint8_t numClient; + tpAniSirGlobal pMac; + /* To remember if the peStats timer is stopped successfully or not */ + bool timerStopFailed; + uint8_t sessionId; + +} tCsrPeStatsReqInfo; + +typedef struct tagCsrStatsClientReqInfo { + tListElem link; /* list links */ + eCsrStatsRequesterType requesterId; + tCsrStatsCallback callback; + uint32_t periodicity; + void *pContext; + uint32_t statsMask; + tCsrPeStatsReqInfo *pPeStaEntry; + uint8_t staId; + cdf_mc_timer_t timer; + bool timerExpired; + tpAniSirGlobal pMac; /* TODO: Confirm this change BTAMP */ + uint8_t sessionId; +} tCsrStatsClientReqInfo; + +typedef struct tagCsrTlStatsReqInfo { + uint32_t periodicity; + bool timerRunning; + cdf_mc_timer_t hTlStatsTimer; + uint8_t numClient; +} tCsrTlStatsReqInfo; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef enum { + /* reassociation is done but couldn't finish security handshake */ + eSIR_ROAM_AUTH_STATUS_CONNECTED = 1, + /* roam successfully completed by firmware */ + eSIR_ROAM_AUTH_STATUS_AUTHENTICATED = 2, + /* unknown error */ + eSIR_ROAM_AUTH_STATUS_UNKNOWN = 0xff +} tCsrRoamOffloadAuthStatus; +typedef struct tagCsrRoamOffloadSynchStruct { + uint8_t roamedVdevId; /* vdevId after roaming */ + int8_t txMgmtPower; /* HAL fills in the tx power used for */ + uint8_t rssi; /* RSSI */ + uint8_t roamReason; /* Roam reason */ + uint8_t nss; /* no of spatial streams */ + uint16_t chainMask; /* chainmask */ + uint16_t smpsMode; /* smps.mode */ + tSirMacAddr bssid; /* MAC address of roamed AP */ + bool bRoamSynchInProgress; /* a roam offload synch */ + tCsrRoamOffloadAuthStatus authStatus; /* auth status */ + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + tpSirBssDescription bss_desc_ptr; /*BSS descriptor*/ +} csr_roam_offload_synch_params; +#endif + +struct csr_roam_stored_profile { + uint32_t session_id; + tCsrRoamProfile profile; + tScanResultHandle bsslist_handle; + eCsrRoamReason reason; + uint32_t roam_id; + bool imediate_flag; + bool clear_flag; +}; + +typedef struct tagCsrRoamSession { + uint8_t sessionId; /* Session ID */ + bool sessionActive; /* true if it is used */ + + /* For BT-AMP station, this serve as BSSID for self-BSS. */ + struct cdf_mac_addr selfMacAddr; + + csr_roam_completeCallback callback; + void *pContext; + eCsrConnectState connectState; + tCsrRoamConnectedProfile connectedProfile; + tCsrRoamConnectedInfo connectedInfo; + tCsrRoamProfile *pCurRoamProfile; + tSirBssDescription *pConnectBssDesc; + uint16_t NumPmkidCache; /* valid number of pmkid in the cache*/ + uint16_t curr_cache_idx; /* the index in pmkidcache to write next to */ + tPmkidCacheInfo PmkidCacheInfo[CSR_MAX_PMKID_ALLOWED]; + uint8_t cJoinAttemps; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc memory all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + int32_t sPendingCommands; /* 0 means CSR is ok to low power */ +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCache; + tBkidCacheInfo BkidCacheInfo[CSR_MAX_BKID_ALLOWED]; +#endif /* FEATURE_WLAN_WAPI */ + /* + * indicate whether CSR is roaming + * (either via lostlink or dynamic roaming) + */ + bool fRoaming; + /* + * to remember some parameters needed for START_BSS. + * All member must be set every time we try to join or start an IBSS + */ + tCsrRoamStartBssParams bssParams; + /* the byte count of pWpaRsnIE; */ + uint32_t nWpaRsnReqIeLength; + /* contain the WPA/RSN IE in assoc req or one sent in beacon(IBSS) */ + uint8_t *pWpaRsnReqIE; + /* the byte count for pWpaRsnRspIE */ + uint32_t nWpaRsnRspIeLength; + /* this contain the WPA/RSN IE in beacon/probe rsp */ + uint8_t *pWpaRsnRspIE; +#ifdef FEATURE_WLAN_WAPI + /* the byte count of pWapiReqIE; */ + uint32_t nWapiReqIeLength; + /* this contain the WAPI IE in assoc req or one sent in beacon (IBSS) */ + uint8_t *pWapiReqIE; + /* the byte count for pWapiRspIE */ + uint32_t nWapiRspIeLength; + /* this contain the WAPI IE in beacon/probe rsp */ + uint8_t *pWapiRspIE; +#endif /* FEATURE_WLAN_WAPI */ + uint32_t nAddIEScanLength; /* the byte count of pAddIeScanIE; */ + /* contains the additional IE in (unicast) probe req at time of join */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* the byte count for pAddIeAssocIE */ + uint8_t *pAddIEAssoc; + uint32_t roamingStartTime; /* in units of 10ms */ + tCsrTimerInfo roamingTimerInfo; + eCsrRoamingReason roamingReason; + bool fCancelRoaming; + cdf_mc_timer_t hTimerRoaming; + /* the roamResult that is used when the roaming timer fires */ + eCsrRoamResult roamResult; + /* This is the reason code for join(assoc) failure */ + tCsrRoamJoinStatus joinFailStatusCode; + /* status from PE for deauth/disassoc(lostlink) or our own dyn roam */ + uint32_t roamingStatusCode; + uint16_t NumPmkidCandidate; + tPmkidCandidateInfo PmkidCandidateInfo[CSR_MAX_PMKID_ALLOWED]; +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCandidate; + tBkidCandidateInfo BkidCandidateInfo[CSR_MAX_BKID_ALLOWED]; +#endif + bool fWMMConnection; + bool fQOSConnection; +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isPrevApInfoValid; + tSirMacSSid prevApSSID; + struct cdf_mac_addr prevApBssid; + uint8_t prevOpChannel; + uint16_t clientDissSecs; + uint32_t roamTS1; +#if defined(FEATURE_WLAN_ESE_UPLOAD) + tCsrEseCckmIe suppCckmIeInfo; +#endif +#endif + uint8_t bRefAssocStartCnt; /* Tracking assoc start indication */ + tSirHTConfig htConfig; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pnoStarted; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + csr_roam_offload_synch_params roamOffloadSynchParams; + uint8_t psk_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + size_t pmk_len; + uint8_t RoamKeyMgmtOffloadEnabled; +#endif +#if defined WLAN_FEATURE_VOWIFI_11R + tftSMEContext ftSmeContext; +#endif + /* This count represents the number of bssid's we try to join. */ + uint8_t join_bssid_count; + struct csr_roam_stored_profile stored_roam_profile; +} tCsrRoamSession; + +typedef struct tagCsrRoamStruct { + uint32_t nextRoamId; + tDblLinkList roamCmdPendingList; + tDblLinkList channelList5G; + tDblLinkList channelList24; + tCsrConfig configParam; + uint32_t numChannelsEeprom; /* total channels of eeprom */ + tCsrChannel baseChannels; /* The channel base to work on */ + tCsrChannel base40MHzChannels; /* center channels for 40MHz channels */ + eCsrRoamState curState[CSR_ROAM_SESSION_MAX]; + eCsrRoamSubState curSubState[CSR_ROAM_SESSION_MAX]; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc mem all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numValidChannels; /* total number of channels in CFG */ + int32_t sPendingCommands; + cdf_mc_timer_t hTimerWaitForKey; /* support timeout for WaitForKey */ + tCsrSummaryStatsInfo summaryStatsInfo; + tCsrGlobalClassAStatsInfo classAStatsInfo; + tCsrGlobalClassBStatsInfo classBStatsInfo; + tCsrGlobalClassCStatsInfo classCStatsInfo; + tCsrGlobalClassDStatsInfo classDStatsInfo; + tCsrPerStaStatsInfo perStaStatsInfo[CSR_MAX_STA]; + tDblLinkList statsClientReqList; + tDblLinkList peStatsReqList; + tCsrTlStatsReqInfo tlStatsReqInfo; + eCsrRoamLinkQualityInd vccLinkQuality; + tCsrLinkQualityIndInfo linkQualityIndInfo; + v_CONTEXT_t g_cds_context; /* used for interaction with TL */ + tCsrTimerInfo WaitForKeyTimerInfo; + tCsrRoamSession *roamSession; + uint32_t transactionId; /* Current transaction ID for internal use. */ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + tCsrNeighborRoamControlInfo neighborRoamInfo[CSR_ROAM_SESSION_MAX]; +#endif +#ifdef FEATURE_WLAN_LFR + uint8_t isFastRoamIniFeatureEnabled; +#endif +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) \ + || defined(FEATURE_WLAN_LFR) + uint8_t RoamRssiDiff; + bool isWESModeEnabled; +#endif + uint32_t deauthRspStatus; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t *pReassocResp; /* reassociation response from new AP */ + uint16_t reassocRespLen; /* length of reassociation response */ +#endif +} tCsrRoamStruct; + +#define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ + 1 : (pRoamStruct)->nextRoamId) +#define CSR_IS_ROAM_STATE(pMac, state, sessionId) \ + ((state) == (pMac)->roam.curState[sessionId]) +#define CSR_IS_ROAM_STOP(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_STOP, sessionId) +#define CSR_IS_ROAM_INIT(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_INIT, sessionId) +#define CSR_IS_ROAM_JOINING(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINING, sessionId) +#define CSR_IS_ROAM_IDLE(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_IDLE, sessionId) +#define CSR_IS_ROAM_JOINED(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINED, sessionId) +#define CSR_IS_ROAM_SUBSTATE(pMac, subState, sessionId) \ + ((subState) == (pMac)->roam.curSubState[sessionId]) +#define CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_AUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_AUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_REASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_DISASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_START_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, sessionId) +#define CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_CONFIG, sessionId) +#define CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NRT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC,\ + sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_RT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac),\ + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, sessionId) +#define CSR_IS_PHY_MODE_B_ONLY(pMac) \ + ((eCSR_DOT11_MODE_11b == (pMac)->roam.configParam.phyMode) || \ + (eCSR_DOT11_MODE_11b_ONLY == (pMac)->roam.configParam.phyMode)) + +#define CSR_IS_PHY_MODE_G_ONLY(pMac) \ + (eCSR_DOT11_MODE_11g == (pMac)->roam.configParam.phyMode \ + || eCSR_DOT11_MODE_11g_ONLY == (pMac)->roam.configParam.phyMode) + +#define CSR_IS_PHY_MODE_A_ONLY(pMac) \ + (eCSR_DOT11_MODE_11a == (pMac)->roam.configParam.phyMode) + +#ifdef WLAN_FEATURE_11AC +#define CSR_IS_PHY_MODE_DUAL_BAND(phyMode) \ + ((eCSR_DOT11_MODE_abg & (phyMode)) || \ + (eCSR_DOT11_MODE_11n & (phyMode)) || \ + (eCSR_DOT11_MODE_11ac & (phyMode)) || \ + (eCSR_DOT11_MODE_AUTO & (phyMode))) +#else +#define CSR_IS_PHY_MODE_DUAL_BAND(phyMode) \ + ((eCSR_DOT11_MODE_abg & (phyMode)) || \ + (eCSR_DOT11_MODE_11n & (phyMode)) || \ + (eCSR_DOT11_MODE_AUTO & (phyMode))) +#endif + +#define CSR_IS_PHY_MODE_11n(phy_mode) \ + ((eCSR_DOT11_MODE_11n == phy_mode) || \ + (eCSR_DOT11_MODE_11n_ONLY == phy_mode) || \ + (eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) + +#define CSR_IS_PHY_MODE_11ac(phy_mode) \ + ((eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) +/* + * this function returns true if the NIC is operating exclusively in + * the 2.4 GHz band, meaning. it is NOT operating in the 5.0 GHz band. + */ +#define CSR_IS_24_BAND_ONLY(pMac) \ + (eCSR_BAND_24 == (pMac)->roam.configParam.eBand) + +#define CSR_IS_5G_BAND_ONLY(pMac) \ + (eCSR_BAND_5G == (pMac)->roam.configParam.eBand) + +#define CSR_IS_RADIO_DUAL_BAND(pMac) \ + (eCSR_BAND_ALL == (pMac)->roam.configParam.bandCapability) + +#define CSR_IS_RADIO_BG_ONLY(pMac) \ + (eCSR_BAND_24 == (pMac)->roam.configParam.bandCapability) + +/* + * this function returns true if the NIC is operating exclusively in the 5.0 GHz + * band, meaning. it is NOT operating in the 2.4 GHz band + */ +#define CSR_IS_RADIO_A_ONLY(pMac) \ + (eCSR_BAND_5G == (pMac)->roam.configParam.bandCapability) +/* this function returns true if the NIC is operating in both bands. */ +#define CSR_IS_OPEARTING_DUAL_BAND(pMac) \ + ((eCSR_BAND_ALL == (pMac)->roam.configParam.bandCapability) && \ + (eCSR_BAND_ALL == (pMac)->roam.configParam.eBand)) +/* + * this function returns true if the NIC can operate in the 5.0 GHz band + * (could operate in the 2.4 GHz band also) + */ +#define CSR_IS_OPERATING_A_BAND(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_A_ONLY((pMac)) || CSR_IS_5G_BAND_ONLY((pMac))) + +/* + * this function returns true if the NIC can operate in the 2.4 GHz band + * (could operate in the 5.0 GHz band also). + */ +#define CSR_IS_OPERATING_BG_BAND(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_BG_ONLY((pMac)) || CSR_IS_24_BAND_ONLY((pMac))) +#define CSR_GET_BAND(ch_num) \ + ((CDS_IS_CHANNEL_24GHZ(ch_num)) ? eCSR_BAND_24 : eCSR_BAND_5G) +#define CSR_IS_11D_INFO_FOUND(pMac) \ + (0 != (pMac)->scan.channelOf11dInfo) +#define CSR_IS_ROAMING(pSession) \ + ((CSR_IS_LOSTLINK_ROAMING((pSession)->roamingReason)) || \ + (eCsrDynamicRoaming == (pSession)->roamingReason) || \ + (eCsrReassocRoaming == (pSession)->roamingReason)) +#define CSR_IS_SET_KEY_COMMAND(pCommand) \ + (eSmeCommandSetKey == (pCommand)->command) +#define CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) \ + (pMac->roam.configParam.addTSWhenACMIsOff) +#define CSR_IS_LOSTLINK_ROAMING(reason) \ + ((eCsrLostlinkRoamingDisassoc == (reason)) || \ + (eCsrLostlinkRoamingDeauth == (reason))) + +#define CSR_IS_ROAMING_COMMAND(pCommand) \ + ((eCsrLostLink1 == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrLostLink2 == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrLostLink3 == (pCommand)->u.roamCmd.roamReason)) + +CDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac); +CDF_STATUS csrScanFilter11dResult(tpAniSirGlobal pMac); + +CDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +CDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +CDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +void csr_set_global_cfgs(tpAniSirGlobal pMac); +void csr_set_default_dot11_mode(tpAniSirGlobal pMac); +void csrScanSetChannelMask(tpAniSirGlobal pMac, tCsrChannelInfo *pChannelInfo); +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac); +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac); +bool csr_is_sta_session_connected(tpAniSirGlobal pMac); +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac); +bool csr_is_any_session_connected(tpAniSirGlobal pMac); +bool csr_is_infra_connected(tpAniSirGlobal pMac); +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac); +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac); +bool csr_is_infra_ap_started(tpAniSirGlobal pMac); +bool csr_is_ibss_started(tpAniSirGlobal pMac); +bool csr_is_btamp_started(tpAniSirGlobal pMac); +bool csr_is_btamp(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac, + uint32_t sessionId); +CDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId); +CDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, tCsrRssiCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context); +CDF_STATUS csr_get_snr(tpAniSirGlobal pMac, tCsrSnrCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, void *pContext); +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + struct cdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid); +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +CDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam); +CDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam); +CDF_STATUS csr_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +CDF_STATUS csr_open(tpAniSirGlobal pMac); +CDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2); +CDF_STATUS csr_close(tpAniSirGlobal pMac); +CDF_STATUS csr_start(tpAniSirGlobal pMac); +CDF_STATUS csr_stop(tpAniSirGlobal pMac, tHalStopType stopType); +CDF_STATUS csr_ready(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_WAPI +CDF_STATUS csr_scan_get_bkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, tBkidCandidateInfo * pBkidList, + uint32_t *pNumItems); +CDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, + uint32_t sessionId, uint32_t *pLen, uint8_t *pBuf); +CDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ + +CDF_STATUS csr_roam_update_apwpsie(tpAniSirGlobal pMac, uint32_t sessionId, + tSirAPWPSIEs * pAPWPSIES); +CDF_STATUS csr_roam_update_wparsni_es(tpAniSirGlobal pMac, uint32_t sessionId, + tSirRSNie *pAPSirRSNie); +void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile, + bool fPrivacy); +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac); +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, + uint8_t sessionId); +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal pMac, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode); +#endif +CDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile); +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId); + +void csr_set_opposite_band_channel_info(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_SCAN_PNO +CDF_STATUS csr_scan_save_preferred_network_found(tpAniSirGlobal pMac, + tSirPrefNetworkFoundInd * + pPrefNetworkFoundInd); +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +#endif + +#ifdef FEATURE_WLAN_ESE +/* Returns whether the current association is a ESE assoc or not */ +bool csr_roam_is_ese_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac); +bool csr_neighbor_roam_is_ese_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +#endif + +/* Remove this code once SLM_Sessionization is supported */ +void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_LFR +/* Returns whether "Legacy Fast Roaming" is enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal pMac); +bool csr_is_channel_present_in_list(uint8_t *pChannelList, int numChannels, + uint8_t channel); +CDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, int numChannels, + uint8_t channel); +CDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp); +CDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo); +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId); +#endif + +/* Post Channel Change Indication */ +CDF_STATUS csr_roam_channel_change_req(tpAniSirGlobal pMac, + struct cdf_mac_addr bssid, uint8_t cb_mode, + tCsrRoamProfile *profile); + +/* Post Beacon Tx Start Indication */ +CDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac, + struct cdf_mac_addr bssid, uint8_t dfsCacWaitStatus); + +CDF_STATUS +csr_roam_send_chan_sw_ie_request(tpAniSirGlobal pMac, struct cdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, uint8_t ch_bandwidth); +CDF_STATUS +csr_roam_modify_add_ies(tpAniSirGlobal pMac, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType); +CDF_STATUS +csr_roam_update_add_ies(tpAniSirGlobal pMac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void csr_process_roam_offload_synch_ind(tHalHandle hHal, + roam_offload_synch_ind * roam_synch_ind_ptr); +CDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_synch_ind_ptr); +void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf); +#endif +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id); +CDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type, + uint16_t status, uint16_t reasoncode); +#endif +CDF_STATUS csr_get_channels_and_power(tpAniSirGlobal pMac); + +/* csr_scan_process_single_bssdescr() - Add a bssdescriptor to scan table + * + * @mac_ctx - MAC context + * @bssdescr - Pointer to BSS description structure that contains + * everything from beacon/probe response frame and additional + * information. + * @scan_id - Scan identifier of the scan request that was running + * when this beacon was received. Reserved for future when + * firmware provides that information. + * @flags - Reserved for future use. + * + * Callback routine called by LIM when it receives a beacon or probe response + * from the device. 802.11 frame is already converted to internal + * tSirBssDescription data structure. + * + * Return: 0 or other error codes. + */ + +CDF_STATUS csr_scan_process_single_bssdescr(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDescription, + uint32_t scan_id, uint32_t flags); + +#endif diff --git a/core/sme/inc/csr_link_list.h b/core/sme/inc/csr_link_list.h new file mode 100644 index 0000000000..1146246831 --- /dev/null +++ b/core/sme/inc/csr_link_list.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_link_list.h + * + * Exports and types for the Common link list interfaces. + */ + +#ifndef CSR_LINK_LIST_H__ +#define CSR_LINK_LIST_H__ + +#include "cdf_lock.h" +#include "cdf_mc_timer.h" +#include "cds_api.h" +#include "sir_types.h" + +#define LL_ACCESS_LOCK true +#define LL_ACCESS_NOLOCK false + +typedef struct tagListElem { + struct tagListElem *last; + struct tagListElem *next; +} tListElem; + +typedef enum { + LIST_FLAG_CLOSE = 0, + LIST_FLAG_OPEN = 0xa1b2c4d7, +} tListFlag; + +/* This is a circular double link list */ +typedef struct tagDblLinkList { + tListElem ListHead; + cdf_mutex_t Lock; + uint32_t Count; + tHddHandle hHdd; + tListFlag Flag; + /*command debugging */ + uint32_t cmdTimeoutDuration; /* command timeout duration */ + cdf_mc_timer_t *cmdTimeoutTimer; /*command timeout Timer */ +} tDblLinkList; + +/* + * To get the address of an object of (type) base on the (address) + * of one of its (field) + */ +#define GET_BASE_ADDR(address, type, field) ((type *)( \ + (uint8_t *)(address) - \ + (uint8_t *)(&((type *)0)->field))) +/* To get the offset of (field) inside structure (type) */ +#define GET_FIELD_OFFSET(type, field) ((uintptr_t)(&(((type *)0)->field))) +#define GET_ROUND_UP(_Field, _Boundary) \ + (((_Field) + ((_Boundary) - 1)) & ~((_Boundary) - 1)) +#define BITS_ON(_Field, _Bitmask) ((_Field) |= (_Bitmask)) +#define BITS_OFF(_Field, _Bitmask) ((_Field) &= ~(_Bitmask)) +#define CSR_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CSR_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define csrIsListEmpty(pHead) ((pHead)->next == (pHead)) + +uint32_t csr_ll_count(tDblLinkList *pList); +CDF_STATUS csr_ll_open(tHddHandle hHdd, tDblLinkList *pList); +void csr_ll_close(tDblLinkList *pList); +void csr_ll_lock(tDblLinkList *pList); +void csr_ll_unlock(tDblLinkList *pList); +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked); +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +/* This function put pNewEntry before pEntry. Caller should have found pEntry */ +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked); +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked); +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked); +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked); +/* csr_ll_next return NULL if reaching the end or list is empty */ +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind); +#endif diff --git a/core/sme/inc/csr_neighbor_roam.h b/core/sme/inc/csr_neighbor_roam.h new file mode 100644 index 0000000000..6bf27d01a9 --- /dev/null +++ b/core/sme/inc/csr_neighbor_roam.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_neighbor_roam.h + * + * Exports and types for the neighbor roaming algorithm which is sepcifically + * designed for Android. + */ + +#ifndef CSR_NEIGHBOR_ROAM_H +#define CSR_NEIGHBOR_ROAM_H + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +#include "sme_api.h" + +#define ROAM_AP_AGE_LIMIT_MS 10000 + +/* Enumeration of various states in neighbor roam algorithm */ +typedef enum { + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, + eCSR_NEIGHBOR_ROAM_STATE_INIT, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, +#ifdef WLAN_FEATURE_VOWIFI_11R + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, +#endif /* WLAN_FEATURE_VOWIFI_11R */ + eNEIGHBOR_STATE_MAX +} eCsrNeighborRoamState; + +/* Parameters that are obtained from CFG */ +typedef struct sCsrNeighborRoamCfgParams { + uint8_t maxNeighborRetries; + uint32_t neighborScanPeriod; + tCsrChannelInfo channelInfo; + uint8_t neighborLookupThreshold; + uint8_t neighborReassocThreshold; + uint32_t minChannelScanTime; + uint32_t maxChannelScanTime; + uint16_t neighborResultsRefreshPeriod; + uint16_t emptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + uint32_t hi_rssi_scan_delay; + int32_t hi_rssi_scan_rssi_ub; +} tCsrNeighborRoamCfgParams, *tpCsrNeighborRoamCfgParams; + +#define CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX 255 +typedef struct sCsrNeighborRoamChannelInfo { + /* Flag to mark reception of IAPP Neighbor list */ + bool IAPPNeighborListReceived; + /* Current channel index that is being scanned */ + uint8_t currentChanIndex; + /* Max number of channels in channel list and the list of channels */ + tCsrChannelInfo currentChannelListInfo; +} tCsrNeighborRoamChannelInfo, *tpCsrNeighborRoamChannelInfo; + +typedef struct sCsrNeighborRoamBSSInfo { + tListElem List; + uint8_t apPreferenceVal; + tpSirBssDescription pBssDescription; +} tCsrNeighborRoamBSSInfo, *tpCsrNeighborRoamBSSInfo; + +#ifdef WLAN_FEATURE_VOWIFI_11R +#define CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT 1000 /* in milliseconds */ +#define CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER 10 /* in milliseconds */ +/* Max number of MAC addresses with which the pre-auth was failed */ +#define MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS 10 +#define MAX_BSS_IN_NEIGHBOR_RPT 15 +#define CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES 3 + +/* Black listed APs. List of MAC Addresses with which the Preauth was failed */ +typedef struct sCsrPreauthFailListInfo { + uint8_t numMACAddress; + tSirMacAddr macAddress[MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS]; +} tCsrPreauthFailListInfo, *tpCsrPreauthFailListInfo; + +typedef struct sCsrNeighborReportBssInfo { + uint8_t channelNum; + uint8_t neighborScore; + tSirMacAddr neighborBssId; +} tCsrNeighborReportBssInfo, *tpCsrNeighborReportBssInfo; + +typedef struct sCsr11rAssocNeighborInfo { + bool preauthRspPending; + bool neighborRptPending; + uint8_t currentNeighborRptRetryNum; + tCsrPreauthFailListInfo preAuthFailList; + uint32_t neighborReportTimeout; + uint32_t PEPreauthRespTimeout; + uint8_t numPreAuthRetries; + tDblLinkList preAuthDoneList; /* llist which consists/preauth nodes */ + uint8_t numBssFromNeighborReport; + /* Contains info needed during REPORT_SCAN State */ + tCsrNeighborReportBssInfo neighboReportBssInfo[MAX_BSS_IN_NEIGHBOR_RPT]; +} tCsr11rAssocNeighborInfo, *tpCsr11rAssocNeighborInfo; +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +#ifdef FEATURE_WLAN_LFR +typedef enum { + eFirstEmptyScan = 1, + eSecondEmptyScan, + eThirdEmptyScan, + eFourthEmptyScan, + eFifthEmptyScan, + eMaxEmptyScan = eFifthEmptyScan, +} eNeighborRoamEmptyScanCount; + +typedef enum { + DEFAULT_SCAN = 0, + SPLIT_SCAN_OCCUPIED_LIST = 1, +} eNeighborRoamScanMode; +#endif + +/* Complete control information for neighbor roam algorithm */ +typedef struct sCsrNeighborRoamControlInfo { + eCsrNeighborRoamState neighborRoamState; + eCsrNeighborRoamState prevNeighborRoamState; + tCsrNeighborRoamCfgParams cfgParams; + struct cdf_mac_addr currAPbssid; /* current assoc AP */ + uint8_t currAPoperationChannel; /* current assoc AP */ + tCsrNeighborRoamChannelInfo roamChannelInfo; + uint8_t currentNeighborLookupThreshold; + uint8_t currentOpportunisticThresholdDiff; + uint8_t currentRoamRescanRssiDiff; + tDblLinkList roamableAPList; /* List of current FT candidates */ + tCsrRoamProfile csrNeighborRoamProfile; +#ifdef WLAN_FEATURE_VOWIFI_11R + bool is11rAssoc; + tCsr11rAssocNeighborInfo FTRoamInfo; +#endif /* WLAN_FEATURE_VOWIFI_11R */ +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; + bool isVOAdmitted; + uint16_t MinQBssLoadRequired; +#endif +#ifdef FEATURE_WLAN_LFR + /* + * Previous connected profile. + * If the new profile does not match previous we re-initialize + * occupied channel list + */ + tCsrRoamConnectedProfile prevConnProfile; + /* upper layer requested a reassoc */ + uint8_t uOsRequestedHandoff; + /* handoff related info came with upper layer's req for reassoc */ + tCsrHandoffRequest handoffReqInfo; +#endif + uint8_t currentRoamBmissFirstBcnt; + uint8_t currentRoamBmissFinalBcnt; + uint8_t currentRoamBeaconRssiWeight; + uint8_t last_sent_cmd; +} tCsrNeighborRoamControlInfo, *tpCsrNeighborRoamControlInfo; + +/* All the necessary Function declarations are here */ +CDF_STATUS csr_neighbor_roam_indicate_connect(tpAniSirGlobal pMac, + uint8_t sessionId, CDF_STATUS status); +CDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId); +void csr_neighbor_roam_request_handoff(tpAniSirGlobal pMac, uint8_t sessionId); +CDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId); +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId); +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal pMac); +CDF_STATUS csr_neighbor_roam_transit_to_cfg_chan_scan(tpAniSirGlobal pMac, + uint8_t sessionId); +CDF_STATUS csrNeighborRoamTransitionToPreauthDone(tpAniSirGlobal pMac); +CDF_STATUS csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, uint8_t sessionId); +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo pHandoffNode, uint8_t sessionId); +CDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal pMac, + uint8_t sessionId, tSirRetStatus limStatus); +#ifdef WLAN_FEATURE_VOWIFI_11R +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +#endif +CDF_STATUS csr_neighbor_roam_create_chan_list_from_neighbor_report( + tpAniSirGlobal pMac, uint8_t sessionId); +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId); +CDF_STATUS csr_neighbor_roam_set_lookup_rssi_threshold(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t neighborLookupRssiThreshold); +CDF_STATUS csr_neighbor_roam_set_opportunistic_scan_threshold_diff( + tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t nOpportunisticThresholdDiff); +CDF_STATUS csr_neighbor_roam_set_roam_rescan_rssi_diff(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t nRoamRescanRssiDiff); +CDF_STATUS csr_neighbor_roam_set_roam_bmiss_first_bcnt(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t nRoamBmissFirstBcnt); +CDF_STATUS csr_neighbor_roam_set_roam_bmiss_final_bcnt(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t nRoamBmissFinalBcnt); +CDF_STATUS csr_neighbor_roam_set_roam_beacon_rssi_weight(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t nRoamBeaconRssiWeight); +CDF_STATUS csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, const bool fastRoamEnabled); +CDF_STATUS csr_neighbor_roam_update_ese_mode_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, const bool eseMode); +CDF_STATUS csr_neighbor_roam_channels_filter_by_current_band( + tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t *pMergedOutputNumOfChannels); +CDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t *pMergedOutputNumOfChannels); +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ptr); +#define ROAM_SCAN_OFFLOAD_START 1 +#define ROAM_SCAN_OFFLOAD_STOP 2 +#define ROAM_SCAN_OFFLOAD_RESTART 3 +#define ROAM_SCAN_OFFLOAD_UPDATE_CFG 4 +#define ROAM_SCAN_OFFLOAD_ABORT_SCAN 5 + +#define REASON_CONNECT 1 +#define REASON_CHANNEL_LIST_CHANGED 2 +#define REASON_LOOKUP_THRESH_CHANGED 3 +#define REASON_DISCONNECTED 4 +#define REASON_RSSI_DIFF_CHANGED 5 +#define REASON_ESE_INI_CFG_CHANGED 6 +#define REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED 7 +#define REASON_VALID_CHANNEL_LIST_CHANGED 8 +#define REASON_FLUSH_CHANNEL_LIST 9 +#define REASON_EMPTY_SCAN_REF_PERIOD_CHANGED 10 +#define REASON_PREAUTH_FAILED_FOR_ALL 11 +#define REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW 12 +#define REASON_NPROBES_CHANGED 13 +#define REASON_HOME_AWAY_TIME_CHANGED 14 +#define REASON_OS_REQUESTED_ROAMING_NOW 15 +#define REASON_SCAN_CH_TIME_CHANGED 16 +#define REASON_SCAN_HOME_TIME_CHANGED 17 +#define REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED 18 +#define REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED 19 +#define REASON_ROAM_BMISS_FIRST_BCNT_CHANGED 20 +#define REASON_ROAM_BMISS_FINAL_BCNT_CHANGED 21 +#define REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED 22 +#define REASON_ROAM_DFS_SCAN_MODE_CHANGED 23 +#define REASON_ROAM_ABORT_ROAM_SCAN 24 +#define REASON_ROAM_EXT_SCAN_PARAMS_CHANGED 25 +#define REASON_ROAM_SET_SSID_ALLOWED 26 +#define REASON_ROAM_SET_FAVORED_BSSID 27 +#define REASON_ROAM_GOOD_RSSI_CHANGED 28 +#define REASON_ROAM_SET_BLACKLIST_BSSID 29 +#define REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED 30 +#define REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED 31 +#define REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED 32 +#define REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED 33 + +CDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t command, uint8_t reason); +CDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, + void *pMsg); +CDF_STATUS csr_neighbor_roam_handoff_req_hdlr(tpAniSirGlobal pMac, void *pMsg); +CDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId); +CDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, CDF_STATUS status); +CDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, + uint8_t sessionId); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen); +CDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + const uint8_t sessionId); +#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_roam_offload_send_synch_cnf(tpAniSirGlobal pMac, + uint8_t sessionId); +CDF_STATUS csr_neighbor_roam_offload_update_preauth_list(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_synch_ind_ptr, uint8_t sessionId); +#endif +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ +#endif /* CSR_NEIGHBOR_ROAM_H */ diff --git a/core/sme/inc/csr_support.h b/core/sme/inc/csr_support.h new file mode 100644 index 0000000000..c484e6ec67 --- /dev/null +++ b/core/sme/inc/csr_support.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_support.h + * + * Exports and types for the Common Scan and Roaming supporting interfaces. + */ +#ifndef CSR_SUPPORT_H__ +#define CSR_SUPPORT_H__ + +#include "csr_link_list.h" +#include "csr_api.h" +#include "cds_reg_service.h" + +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_OUI_SIZE (4) +#define CSR_WAPI_VERSION_SUPPORTED (1) +#define CSR_WAPI_MAX_AUTH_SUITES (2) +#define CSR_WAPI_MAX_CYPHERS (5) +#define CSR_WAPI_MAX_UNICAST_CYPHERS (5) +#define CSR_WAPI_MAX_MULTICAST_CYPHERS (1) +#endif /* FEATURE_WLAN_WAPI */ + +#define CSR_RSN_OUI_SIZE (4) +#define CSR_RSN_VERSION_SUPPORTED (1) +#define CSR_RSN_MAX_AUTH_SUITES (4) +#define CSR_RSN_MAX_CYPHERS (5) +#define CSR_RSN_MAX_UNICAST_CYPHERS (5) +#define CSR_RSN_MAX_MULTICAST_CYPHERS (1) + +#define CSR_WPA_OUI_SIZE (4) +#define CSR_WPA_VERSION_SUPPORTED (1) +#define CSR_WME_OUI_SIZE (4) +#define CSR_WPA_MAX_AUTH_SUITES (2) +#define CSR_WPA_MAX_CYPHERS (5) +#define CSR_WPA_MAX_UNICAST_CYPHERS (5) +#define CSR_WPA_MAX_MULTICAST_CYPHERS (1) +/* minimum size of the IE->length is the size of the Oui + Version. */ +#define CSR_WPA_IE_MIN_SIZE (6) +#define CSR_WPA_IE_MIN_SIZE_W_MULTICAST (HDD_WPA_IE_MIN_SIZE + HDD_WPA_OUI_SIZE) +#define CSR_WPA_IE_MIN_SIZE_W_UNICAST (HDD_WPA_IE_MIN_SIZE + \ + HDD_WPA_OUI_SIZE + sizeof(pWpaIe->cUnicastCyphers)) + +#define CSR_DOT11_SUPPORTED_RATES_MAX (12) +#define CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX (8) + +#define CSR_DOT11_BASIC_RATE_MASK (0x80) + +#define CSR_OUI_USE_GROUP_CIPHER_INDEX 0x00 +#define CSR_OUI_WEP40_OR_1X_INDEX 0x01 +#define CSR_OUI_TKIP_OR_PSK_INDEX 0x02 +#define CSR_OUI_RESERVED_INDEX 0x03 +#define CSR_OUI_AES_INDEX 0x04 +#define CSR_OUI_WEP104_INDEX 0x05 + +#ifdef FEATURE_WLAN_WAPI +#define CSR_OUI_WAPI_RESERVED_INDEX 0x00 +#define CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX 0x01 +#define CSR_OUI_WAPI_WAI_PSK_INDEX 0x02 +/* max idx, should be last & highest */ +#define CSR_OUI_WAPI_WAI_MAX_INDEX 0x03 +#endif /* FEATURE_WLAN_WAPI */ + +typedef enum { + /* 11b rates */ + eCsrSuppRate_1Mbps = 1 * 2, + eCsrSuppRate_2Mbps = 2 * 2, + eCsrSuppRate_5_5Mbps = 11, /* 5.5 * 2 */ + eCsrSuppRate_11Mbps = 11 * 2, + + /* 11a / 11g rates */ + eCsrSuppRate_6Mbps = 6 * 2, + eCsrSuppRate_9Mbps = 9 * 2, + eCsrSuppRate_12Mbps = 12 * 2, + eCsrSuppRate_18Mbps = 18 * 2, + eCsrSuppRate_24Mbps = 24 * 2, + eCsrSuppRate_36Mbps = 36 * 2, + eCsrSuppRate_48Mbps = 48 * 2, + eCsrSuppRate_54Mbps = 54 * 2, + + /* airgo proprietary rates */ + eCsrSuppRate_10Mbps = 10 * 2, + eCsrSuppRate_10_5Mbps = 21, /* 10.5 * 2 */ + eCsrSuppRate_20Mbps = 20 * 2, + eCsrSuppRate_21Mbps = 21 * 2, + eCsrSuppRate_40Mbps = 40 * 2, + eCsrSuppRate_42Mbps = 42 * 2, + eCsrSuppRate_60Mbps = 60 * 2, + eCsrSuppRate_63Mbps = 63 * 2, + eCsrSuppRate_72Mbps = 72 * 2, + eCsrSuppRate_80Mbps = 80 * 2, + eCsrSuppRate_84Mbps = 84 * 2, + eCsrSuppRate_96Mbps = 96 * 2, + eCsrSuppRate_108Mbps = 108 * 2, + eCsrSuppRate_120Mbps = 120 * 2, + eCsrSuppRate_126Mbps = 126 * 2, + eCsrSuppRate_144Mbps = 144 * 2, + eCsrSuppRate_160Mbps = 160 * 2, + eCsrSuppRate_168Mbps = 168 * 2, + eCsrSuppRate_192Mbps = 192 * 2, + eCsrSuppRate_216Mbps = 216 * 2, + eCsrSuppRate_240Mbps = 240 * 2 +} eCsrSupportedRates; + +/* Generic Information Element Structure */ +typedef struct sDot11IEHeader { + uint8_t ElementID; + uint8_t Length; +} cdf_packed tDot11IEHeader; + +typedef struct tagCsrWpaIe { + tDot11IEHeader IeHeader; + uint8_t Oui[CSR_WPA_OUI_SIZE]; + uint16_t Version; + uint8_t MulticastOui[CSR_WPA_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } cdf_packed UnicastOui[1]; +} cdf_packed tCsrWpaIe; + +typedef struct tagCsrWpaAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } cdf_packed AuthOui[1]; +} cdf_packed tCsrWpaAuthIe; + +typedef struct tagCsrRSNIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint8_t MulticastOui[CSR_RSN_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } cdf_packed UnicastOui[1]; +} cdf_packed tCsrRSNIe; + +typedef struct tagCsrRSNAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } cdf_packed AuthOui[1]; +} cdf_packed tCsrRSNAuthIe; + +typedef struct tagCsrRSNCapabilities { + uint16_t PreAuthSupported:1; + uint16_t NoPairwise:1; + uint16_t PTKSAReplayCounter:2; + uint16_t GTKSAReplayCounter:2; + uint16_t MFPRequired:1; + uint16_t MFPCapable:1; + uint16_t Reserved:8; +} cdf_packed tCsrRSNCapabilities; + +typedef struct tagCsrRSNPMKIe { + uint16_t cPMKIDs; + struct { + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; + } cdf_packed PMKIDList[1]; +} cdf_packed tCsrRSNPMKIe; + +typedef struct tCsrIELenInfo { + uint8_t min; + uint8_t max; +} cdf_packed tCsrIELenInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagCsrWapiIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } cdf_packed AuthOui[1]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } cdf_packed UnicastOui[1]; + uint8_t MulticastOui[CSR_WAPI_OUI_SIZE]; + struct { + uint16_t PreAuthSupported:1; + uint16_t Reserved:15; + } cdf_packed tCsrWapiCapabilities; +} cdf_packed tCsrWapiIe; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagRoamingTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tCsrTimerInfo; + +#define CSR_IS_11A_BSS(pBssDesc) (eSIR_11A_NW_TYPE == (pBssDesc)->nwType) +#define CSR_IS_BASIC_RATE(rate) ((rate) & CSR_DOT11_BASIC_RATE_MASK) +#define CSR_IS_QOS_BSS(pIes) \ + ((pIes)->WMMParams.present || (pIes)->WMMInfoAp.present) +#define CSR_IS_UAPSD_BSS(pIes) \ + (((pIes)->WMMParams.present && \ + ((pIes)->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD)) || \ + ((pIes)->WMMInfoAp.present && (pIes)->WMMInfoAp.uapsd)) + +/* This macro returns the total len needed of Tlv with with len bytes of data */ +#define GET_TLV_MSG_LEN(len) \ + GET_ROUND_UP((sizeof(tCsrCfgMsgTlvHdr) + (len)), sizeof(uint32_t)) + +bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc, + struct cdf_mac_addr *pBssId); +bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len); +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_privacy(tSirBssDescription *pSirBssDesc); +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp); +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp); +uint32_t csr_get_frag_thresh(tHalHandle hHal); +uint32_t csr_get_rts_thresh(tHalHandle hHal); +eCsrPhyMode csr_get_phy_mode_from_bssDesc(tSirBssDescription *pSirBssDesc); +uint32_t csr_get11h_power_constraint(tHalHandle hHal, + tDot11fIEPowerConstraints *pPowerConstraint); +uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe); +uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ +/* + * If a WPAIE exists in the profile, just use it. + * Or else construct one from the BSS Caller allocated memory for pWpaIe and + * guarrantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); +bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2); +/* Null ssid means match */ +bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid, + tCsrSSIDs *pSsidList); +bool csr_is_profile_wpa(tCsrRoamProfile *pProfile); +bool csr_is_profile_rsn(tCsrRoamProfile *pProfile); +/* + * If a RSNIE exists in the profile, just use it. Or + * else construct one from the BSS Caller allocated memory for pWpaIe and + * guarrantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe); +#ifdef FEATURE_WLAN_WAPI +/* + * If a WAPI IE exists in the profile, just use it. + * Or else construct one from the BSS. Caller allocated memory for pWapiIe and + * guarrantee it can contain a max length WAPI IE + */ +uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate); +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate); +tAniEdType csr_translate_encrypt_type_to_ed_type( + eCsrEncryptionType EncryptType); +/* + * pIes shall contain IEs from pSirBssDesc. + * It shall be returned from function csr_get_parsed_bss_description_ies + */ +bool csr_is_security_match(tHalHandle hHal, tCsrAuthList *authType, + tCsrEncryptionList *pUCEncryptionType, + tCsrEncryptionList *pMCEncryptionType, bool *pMFPEnabled, + uint8_t *pMFPRequired, uint8_t *pMFPCapable, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes, + eCsrAuthType *negotiatedAuthtype, + eCsrEncryptionType *negotiatedUCCipher, + eCsrEncryptionType *negotiatedMCCipher); +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2); +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType); +bool csr_is_bss_type_wds(eCsrRoamBssType bssType); +/* + * ppIes can be NULL. If caller want to get the *ppIes allocated by + * this function, pass in *ppIes = NULL. Caller needs to free the memory + * in this case + */ +bool csr_match_bss(tHalHandle hHal, tSirBssDescription *pBssDesc, + tCsrScanResultFilter *pFilter, eCsrAuthType *pNegAuth, + eCsrEncryptionType *pNegUc, eCsrEncryptionType *pNegMc, + tDot11fBeaconIEs **ppIes); +bool csr_is_bssid_match(tHalHandle hHal, struct cdf_mac_addr *pProfBssid, + struct cdf_mac_addr *BssBssid); +bool csr_match_bss_to_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes); +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap); +bool csr_check_rate_bitmap(uint8_t rate, uint16_t RateBitmap); +bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate); +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, tSirMacPropRateSet *pPropRates); +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype); +/* Caller allocates memory for pIEStruct */ +CDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIEStruct); +/* + * This function will allocate memory for the parsed IEs to the caller. + * Caller must free the memory. after it is done with the data only if + * this function succeeds + */ +CDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs **ppIEStruct); + +bool csrValidateCountryString(tHalHandle hHal, uint8_t *pCountryString); +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId); +uint8_t csr_to_upper(uint8_t ch); +CDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes); +/* + * fForce -- force reassoc regardless of whether there is any change. + * The reason is that for UAPSD-bypass, the code underneath this call determine + * whether to allow UAPSD. The information in pModProfileFields reflects what + * the user wants. There may be discrepency in it. UAPSD-bypass logic should + * decide if it needs to reassoc + */ +CDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce); + +CDF_STATUS csr_isconcurrentsession_valid(tpAniSirGlobal pMac, + uint32_t cursessionId, tCDF_CON_MODE currBssPersona); +/* BeaconInterval validation for MCC support */ +CDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId, + uint16_t *beaconInterval, uint32_t cursessionId, + tCDF_CON_MODE currBssPersona); +#ifdef WLAN_FEATURE_VOWIFI_11R +bool csr_is_profile11r(tCsrRoamProfile *pProfile); +bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent); +#endif +#ifdef FEATURE_WLAN_ESE +bool csr_is_auth_type_ese(eCsrAuthType AuthType); +bool csr_is_profile_ese(tCsrRoamProfile *pProfile); +#endif + +#endif diff --git a/core/sme/inc/nan_api.h b/core/sme/inc/nan_api.h new file mode 100644 index 0000000000..ee275cb3af --- /dev/null +++ b/core/sme/inc/nan_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * Name: nan_api.h + * + * Description: NAN FSM defines. + * + */ + +#ifndef __NAN_API_H__ +#define __NAN_API_H__ + +#include "cdf_types.h" +#include "cdf_types.h" + +typedef struct sNanRequestReq { + uint16_t request_data_len; + const uint8_t *request_data; +} tNanRequestReq, *tpNanRequestReq; + +typedef void (*NanCallback)(void *, tSirNanEvent *); +void sme_nan_register_callback(tHalHandle hHal, NanCallback callback); +CDF_STATUS sme_nan_request(tpNanRequestReq input); + +#endif /* __NAN_API_H__ */ diff --git a/core/sme/inc/oem_data_api.h b/core/sme/inc/oem_data_api.h new file mode 100644 index 0000000000..c7ec08c3b4 --- /dev/null +++ b/core/sme/inc/oem_data_api.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * \file oem_data_api.h + * + * Exports and types for the Common OEM DATA REQ/RSP Module interfaces. + */ + +#ifndef __OEM_DATA_API_H__ +#define __OEM_DATA_API_H__ +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "csr_link_list.h" + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 280 +#endif + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +/* message subtype for internal purpose */ +#define OEM_MESSAGE_SUBTYPE_INTERNAL 0xdeadbeef + +/* Structure for defining req sent to the PE */ +typedef struct tagOemDataReq { + uint8_t sessionId; + uint8_t oemDataReq[OEM_DATA_REQ_SIZE]; +} tOemDataReq, tOemDataReqConfig; + +typedef struct tagOemDataRsp { + uint8_t oemDataRsp[OEM_DATA_RSP_SIZE]; +} tOemDataRsp; + +typedef enum { + eOEM_DATA_REQ_SUCCESS = 1, + eOEM_DATA_REQ_FAILURE, + eOEM_DATA_REQ_INVALID_MODE, +} eOemDataReqStatus; +CDF_STATUS oem_data_oem_data_req_open(tHalHandle hHal); +CDF_STATUS oem_data_oem_data_req_close(tHalHandle hHal); + +/* + * HDD Callback function for the sme to callback when + * the oem data rsp is available + */ +typedef CDF_STATUS (*oem_data_oem_data_reqCompleteCallback)(tHalHandle, + void *p2, uint32_t oemDataReqID, eOemDataReqStatus status); + +CDF_STATUS oem_data_oem_data_req(tHalHandle, uint8_t, tOemDataReqConfig *, + uint32_t *pOemDataReqID, + oem_data_oem_data_reqCompleteCallback callback, + void *pContext); +CDF_STATUS sme_handle_oem_data_rsp(tHalHandle hHal, uint8_t *); +CDF_STATUS oem_data_is_oem_data_req_allowed(tHalHandle hHal); +typedef void (*sme_send_oem_data_rsp_msg)(int length, uint8_t *oem_data_rsp); +#endif /* _OEM_DATA_API_H__ */ + +#endif /* FEATURE_OEM_DATA_SUPPORT */ diff --git a/core/sme/inc/oem_data_internal.h b/core/sme/inc/oem_data_internal.h new file mode 100644 index 0000000000..bf6a63460c --- /dev/null +++ b/core/sme/inc/oem_data_internal.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * + * \file oem_data_internal.h + * + * Exports and types for the Common OEM DATA REQ/RSP Module interfaces. + */ + +#ifndef __OEM_DATA_INTERNAL_H__ +#define __OEM_DATA_INTERNAL_H__ + +#include "csr_support.h" +#include "cds_reg_service.h" +#include "oem_data_api.h" + +typedef struct tagOemDataStruct { + /* a global req id */ + uint32_t nextOemReqId; + /* indicates that currently a request has been posted and */ + bool oemDataReqActive; + /* callback function pointer for returning the response */ + oem_data_oem_data_reqCompleteCallback callback; + /* context of the original caller */ + void *pContext; + uint32_t oemDataReqID; /* original request ID */ + tOemDataReqConfig oemDataReqConfig; /* current oem data request */ + uint8_t sessionId; /* Session on which oem data req is active */ + /* callback for sending data response to oem application */ + sme_send_oem_data_rsp_msg oem_data_rsp_callback; +} tOemDataStruct; + +typedef struct tagOemDataCmd { + uint32_t oemDataReqID; + oem_data_oem_data_reqCompleteCallback callback; + void *pContext; + tOemDataReq oemDataReq; +} tOemDataCmd; +#endif /* __OEM_DATA_INTERNAL_H__ */ + +#endif /* FEATURE_OEM_DATA_SUPPORT */ diff --git a/core/sme/inc/p2p_api.h b/core/sme/inc/p2p_api.h new file mode 100644 index 0000000000..8b16507f88 --- /dev/null +++ b/core/sme/inc/p2p_api.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * Name: p2p_api.h + * + * Description: P2P FSM defines. + * + * + */ + +#ifndef __P2P_API_H__ +#define __P2P_API_H__ + +#include "cdf_types.h" +#include "cdf_types.h" +#include "cdf_mc_timer.h" +#include "cdf_lock.h" + +typedef struct sP2pPsConfig { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; + uint8_t sessionid; +} tP2pPsConfig, *tpP2pPsConfig; + +typedef CDF_STATUS (*remainOnChanCallback)(tHalHandle, void *context, + CDF_STATUS status, uint32_t scan_id); + +typedef struct sRemainOnChn { + uint8_t chn; + uint32_t duration; + remainOnChanCallback callback; + void *pCBContext; +} tRemainOnChn, tpRemainOnChn; + +#define SIZE_OF_NOA_DESCRIPTOR 13 +#define MAX_NOA_PERIOD_IN_MICROSECS 3000000 + +#define P2P_CLEAR_POWERSAVE 0 +#define P2P_OPPORTUNISTIC_PS 1 +#define P2P_PERIODIC_NOA 2 +#define P2P_SINGLE_NOA 4 + +typedef struct sp2pContext { + v_CONTEXT_t cds_context; + tHalHandle hHal; + uint8_t sessionId; /* Session id corresponding to P2P */ + uint8_t SMEsessionId; + uint8_t probeReqForwarding; + uint8_t *probeRspIe; + uint32_t probeRspIeLength; +} tp2pContext, *tPp2pContext; + +CDF_STATUS sme_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t *scan_id); +CDF_STATUS sme_report_probe_req(tHalHandle hHal, uint8_t flag); +CDF_STATUS sme_update_p2p_ie(tHalHandle hHal, void *p2pIe, + uint32_t p2pIeLength); +CDF_STATUS sme_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, bool noack, + uint16_t channel_freq); +CDF_STATUS sme_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id); +CDF_STATUS sme_p2p_open(tHalHandle hHal); +CDF_STATUS p2p_stop(tHalHandle hHal); +CDF_STATUS sme_p2p_close(tHalHandle hHal); +CDF_STATUS sme_p2p_set_ps(tHalHandle hHal, tP2pPsConfig *data); +CDF_STATUS p2p_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t scan_id); +CDF_STATUS p2p_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, bool noack, + uint16_t channel_freq); +CDF_STATUS p2p_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id); +CDF_STATUS p2p_set_ps(tHalHandle hHal, tP2pPsConfig *pNoA); +tSirRFBand get_rf_band(uint8_t channel); +#endif /* __P2P_API_H__ */ diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h new file mode 100644 index 0000000000..1da4dcf328 --- /dev/null +++ b/core/sme/inc/sme_api.h @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_API_H) +#define __SME_API_H + +/** + * file smeApi.h + * + * brief prototype for SME APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "csr_api.h" +#include "cds_mq.h" +#include "cdf_lock.h" +#include "cdf_types.h" +#include "sir_api.h" +#include "cds_reg_service.h" +#include "p2p_api.h" +#include "cds_regdomain.h" +#include "sme_internal.h" + +#ifdef FEATURE_OEM_DATA_SUPPORT +#include "oem_data_api.h" +#endif + +#if defined WLAN_FEATURE_VOWIFI +#include "sme_rrm_internal.h" +#endif +#include "sir_types.h" +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#define SME_SUMMARY_STATS 1 +#define SME_GLOBAL_CLASSA_STATS 2 +#define SME_GLOBAL_CLASSB_STATS 4 +#define SME_GLOBAL_CLASSC_STATS 8 +#define SME_GLOBAL_CLASSD_STATS 16 +#define SME_PER_STA_STATS 32 + +#define SME_SESSION_ID_ANY 50 + +#define SME_INVALID_COUNTRY_CODE "XX" + +#define SME_2_4_GHZ_MAX_FREQ 3000 + +#define SME_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \ + reg_info_1 &= 0xff00ffff; \ + reg_info_1 |= ((val & 0xff) << 16); \ +} while (0) + +#define SME_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \ + reg_info_2 &= 0xffff00ff; \ + reg_info_2 |= ((val & 0xff) << 8); \ +} while (0) + +/* Macro to indicate invalid no of tspecs */ +#define INVALID_TSPEC 100 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef void (*hdd_ftm_msg_processor)(void *); +typedef struct _smeConfigParams { + tCsrConfigParam csrConfig; +#if defined WLAN_FEATURE_VOWIFI + tRrmConfigParam rrmConfig; +#endif +#if defined FEATURE_WLAN_LFR + uint8_t isFastRoamIniFeatureEnabled; + uint8_t MAWCEnabled; +#endif +#if defined FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool isWESModeEnabled; +#endif + uint8_t isAmsduSupportInAMPDU; + bool pnoOffload; + uint8_t fEnableDebugLog; + uint8_t max_intf_count; + bool enable5gEBT; + bool enableSelfRecovery; + uint32_t f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t f_prefer_non_dfs_on_radar; + bool is_ps_enabled; + bool policy_manager_enabled; + uint32_t fine_time_meas_cap; + uint32_t dual_mac_feature_disable; +} tSmeConfigParams, *tpSmeConfigParams; + +#ifdef FEATURE_WLAN_TDLS +#define SME_TDLS_MAX_SUPP_CHANNELS 128 +#define SME_TDLS_MAX_SUPP_OPER_CLASSES 32 + +typedef struct _smeTdlsPeerCapParams { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + uint8_t peerChan[SME_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[SME_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; + uint8_t opClassForPrefOffChanIsSet; +} tSmeTdlsPeerCapParams; + +typedef enum { + eSME_TDLS_PEER_STATE_PEERING, + eSME_TDLS_PEER_STATE_CONNECTED, + eSME_TDLS_PEER_STATE_TEARDOWN +} eSmeTdlsPeerState; + +typedef struct _smeTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tSmeTdlsPeerCapParams peerCap; +} tSmeTdlsPeerStateParams; + +#define ENABLE_CHANSWITCH 1 +#define DISABLE_CHANSWITCH 2 +#define BW_20_OFFSET_BIT 0 +#define BW_40_OFFSET_BIT 1 +#define BW_80_OFFSET_BIT 2 +#define BW_160_OFFSET_BIT 3 +typedef struct sme_tdls_chan_switch_params_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset;/* Target Off Channel Bandwidth offset */ + uint8_t tdls_off_channel; /* Target Off Channel */ + uint8_t tdls_off_ch_mode; /* TDLS Off Channel Mode */ + uint8_t is_responder; /* is peer responder or initiator */ +} sme_tdls_chan_switch_params; +#endif /* FEATURE_WLAN_TDLS */ + +/* Thermal Mitigation*/ +typedef struct { + uint16_t smeMinTempThreshold; + uint16_t smeMaxTempThreshold; +} tSmeThermalLevelInfo; + +#define SME_MAX_THERMAL_LEVELS (4) +typedef struct { + /* Array of thermal levels */ + tSmeThermalLevelInfo smeThermalLevels[SME_MAX_THERMAL_LEVELS]; + uint8_t smeThermalMgmtEnabled; + uint32_t smeThrottlePeriod; +} tSmeThermalParams; + +typedef enum { + SME_AC_BK = 0, + SME_AC_BE = 1, + SME_AC_VI = 2, + SME_AC_VO = 3 +} sme_ac_enum_type; + +/* TSPEC Direction Enum Type */ +typedef enum { + /* uplink */ + SME_TX_DIR = 0, + /* downlink */ + SME_RX_DIR = 1, + /* bidirectional */ + SME_BI_DIR = 2, +} sme_tspec_dir_type; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +CDF_STATUS sme_open(tHalHandle hHal); +CDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + COUNTRY_CODE_SOURCE cc_src); +CDF_STATUS sme_close(tHalHandle hHal); +CDF_STATUS sme_start(tHalHandle hHal); +CDF_STATUS sme_stop(tHalHandle hHal, tHalStopType stopType); +CDF_STATUS sme_open_session(tHalHandle hHal, csr_roam_completeCallback callback, + void *pContext, uint8_t *pSelfMacAddr, + uint8_t *pbSessionId, uint32_t type, + uint32_t subType); +void sme_set_curr_device_mode(tHalHandle hHal, tCDF_CON_MODE currDeviceMode); +CDF_STATUS sme_close_session(tHalHandle hHal, uint8_t sessionId, + csr_roamSessionCloseCallback callback, + void *pContext); +CDF_STATUS sme_update_roam_params(tHalHandle hHal, uint8_t session_id, + struct roam_ext_params roam_params_src, int update_param); +CDF_STATUS sme_update_config(tHalHandle hHal, + tpSmeConfigParams pSmeConfigParams); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlm); +#endif + +CDF_STATUS sme_set11dinfo(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams); +CDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, + v_REGDOMAIN_t *domainIdSoftAp); +CDF_STATUS sme_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode); +CDF_STATUS sme_change_config_params(tHalHandle hHal, + tCsrUpdateConfigParam *pUpdateConfigParam); +CDF_STATUS sme_hdd_ready_ind(tHalHandle hHal); +CDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg); +void sme_free_msg(tHalHandle hHal, cds_msg_t *pMsg); +CDF_STATUS sme_scan_request(tHalHandle hHal, uint8_t sessionId, + tCsrScanRequest *, csr_scan_completeCallback callback, + void *pContext); +CDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult); +CDF_STATUS sme_get_ap_channel_from_scan_cache(tHalHandle hHal, + tCsrRoamProfile *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id); +bool sme_store_joinreq_param(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id); +CDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id); +CDF_STATUS sme_scan_flush_result(tHalHandle hHal); +CDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId); +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle, + tScanResultHandle hScanResult); +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle, + tScanResultHandle hScanResult); +CDF_STATUS sme_scan_result_purge(tHalHandle hHal, + tScanResultHandle hScanResult); +CDF_STATUS sme_scan_get_pmkid_candidate_list(tHalHandle hHal, uint8_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems); +CDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, uint32_t *pRoamId); +CDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce); +CDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_roam_disconnect(tHalHandle hHal, uint8_t sessionId, + eCsrRoamDisconnectReason reason); +CDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + CDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); +CDF_STATUS sme_roam_disconnect_sta(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pPeerMacAddr); +CDF_STATUS sme_roam_deauth_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *pDelStaParams); +CDF_STATUS sme_roam_tkip_counter_measures(tHalHandle hHal, uint8_t sessionId, + bool bEnable); +CDF_STATUS sme_roam_get_wps_session_overlap(tHalHandle hHal, uint8_t sessionId, + void *pUsrContext, + void *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac); +CDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState); +CDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile); +CDF_STATUS sme_roam_free_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile); +CDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, + bool update_entire_cache); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); +#endif +CDF_STATUS sme_roam_get_security_req_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType); +CDF_STATUS sme_roam_get_security_rsp_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType); +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, + tPmkidCacheInfo *pPmkidCache); +CDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam); +CDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId); +CDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context); +CDF_STATUS sme_get_snr(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, void *pContext); +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS sme_get_tsm_stats(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid); +CDF_STATUS sme_set_cckm_ie(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen); +CDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq); +#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +CDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value); +CDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length); +CDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, + uint32_t *cfg_value); +CDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length); +CDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields); + +extern CDF_STATUS sme_set_host_power_save(tHalHandle hHal, bool psMode); + +void sme_set_dhcp_till_power_active_flag(tHalHandle hHal, uint8_t flag); +extern CDF_STATUS sme_register11d_scan_done_callback(tHalHandle hHal, + csr_scan_completeCallback); +#ifdef FEATURE_OEM_DATA_SUPPORT +extern CDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback); +#endif + +extern CDF_STATUS sme_wow_add_pattern(tHalHandle hHal, + struct wow_add_pattern *pattern, uint8_t sessionId); +extern CDF_STATUS sme_wow_delete_pattern(tHalHandle hHal, + struct wow_delete_pattern *pattern, uint8_t sessionId); + +void sme_register_ftm_msg_processor(tHalHandle hal, + hdd_ftm_msg_processor callback); + +extern CDF_STATUS sme_enter_wowl(tHalHandle hHal, + void (*enter_wowl_callback_routine)(void + *callbackContext, + CDF_STATUS status), + void *enter_wowl_callback_context, +#ifdef WLAN_WAKEUP_EVENTS + void (*wake_reason_ind_cb)(void *callbackContext, + tpSirWakeReasonInd + wake_reason_ind), + void *wake_reason_ind_cb_ctx, +#endif /* WLAN_WAKEUP_EVENTS */ + tpSirSmeWowlEnterParams wowl_enter_params, + uint8_t sessionId); + +extern CDF_STATUS sme_exit_wowl(tHalHandle hHal, + tpSirSmeWowlExitParams wowl_exit_params); +CDF_STATUS sme_roam_set_key(tHalHandle, uint8_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t *pRoamId); +CDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen); + + +void sme_apply_channel_power_info_to_fw(tHalHandle hHal); + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal); +bool sme_is11h_supported(tHalHandle hHal); +bool sme_is_wmm_supported(tHalHandle hHal); + +typedef void (*tSmeChangeCountryCallback)(void *pContext); +CDF_STATUS sme_change_country_code(tHalHandle hHal, + tSmeChangeCountryCallback callback, + uint8_t *pCountry, + void *pContext, + void *p_cds_context, + tAniBool countryFromUserSpace, + tAniBool sendRegHint); +CDF_STATUS sme_generic_change_country_code(tHalHandle hHal, + uint8_t *pCountry, + v_REGDOMAIN_t reg_domain); + +CDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +CDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +void sme_set_cfg_privacy(tHalHandle hHal, tCsrRoamProfile *pProfile, + bool fPrivacy); +void sme_get_recovery_stats(tHalHandle hHal); +#if defined WLAN_FEATURE_VOWIFI +CDF_STATUS sme_neighbor_report_request(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +#endif +CDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType * pVersion); +CDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion); +CDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +CDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +#ifdef FEATURE_WLAN_WAPI +CDF_STATUS sme_scan_get_bkid_candidate_list(tHalHandle hHal, uint32_t sessionId, + tBkidCandidateInfo * pBkidList, + uint32_t *pNumItems); +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_OEM_DATA_SUPPORT +CDF_STATUS sme_oem_data_req(tHalHandle hHal, + uint8_t sessionId, + tOemDataReqConfig *, + uint32_t *pOemDataReqID, + oem_data_oem_data_reqCompleteCallback callback, + void *pContext); +#endif /*FEATURE_OEM_DATA_SUPPORT */ +CDF_STATUS sme_roam_update_apwpsie(tHalHandle, uint8_t sessionId, + tSirAPWPSIEs * pAPWPSIES); +CDF_STATUS sme_roam_update_apwparsni_es(tHalHandle hHal, uint8_t sessionId, + tSirRSNie *pAPSirRSNie); +CDF_STATUS sme_change_mcc_beacon_interval(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_set_host_offload(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq pRequest); +CDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t sessionId, + tpSirKeepAliveReq pRequest); +CDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId); +CDF_STATUS sme_register_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +CDF_STATUS sme_deregister_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +CDF_STATUS sme_configure_rxp_filter(tHalHandle hHal, + tpSirWlanSetRxpFilters wlanRxpFilterParam); +CDF_STATUS sme_ConfigureAppsCpuWakeupState(tHalHandle hHal, bool isAppsAwake); +CDF_STATUS sme_configure_suspend_ind(tHalHandle hHal, + tpSirWlanSuspendParam wlanSuspendParam, + csr_readyToSuspendCallback, + void *callbackContext); +CDF_STATUS sme_configure_resume_req(tHalHandle hHal, + tpSirWlanResumeParam wlanResumeParam); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +CDF_STATUS sme_configure_ext_wo_w(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToSuspendCallback callback, + void *callbackContext); +CDF_STATUS sme_configure_app_type1_params(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params); +CDF_STATUS sme_configure_app_type2_params(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params); +#endif +int8_t sme_get_infra_session_id(tHalHandle hHal); +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId); +uint8_t sme_get_concurrent_operation_channel(tHalHandle hHal); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode); +#endif +CDF_STATUS sme_abort_mac_scan(tHalHandle hHal, uint8_t sessionId, + eCsrAbortReason reason); +CDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels, + uint32_t *len); +#ifdef FEATURE_WLAN_SCAN_PNO +CDF_STATUS sme_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq pRequest, + uint8_t sessionId, + preferred_network_found_ind_cb + callbackRoutine, void *callbackContext); + +CDF_STATUS sme_preferred_network_found_ind(tHalHandle hHal, void *pMsg); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef WLAN_FEATURE_PACKET_FILTERING +CDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs); +CDF_STATUS sme_receive_filter_set_filter(tHalHandle hHal, + tpSirRcvPktFilterCfgType pRcvPktFilterCfg, + uint8_t sessionId); +CDF_STATUS sme_receive_filter_clear_filter(tHalHandle hHal, + tpSirRcvFltPktClearParam pRcvFltPktClearParam, + uint8_t sessionId); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +CDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, + eCsrBand eBand); +CDF_STATUS sme_get_freq_band(tHalHandle hHal, eCsrBand *pBand); +#ifdef WLAN_FEATURE_GTK_OFFLOAD +CDF_STATUS sme_set_gtk_offload(tHalHandle hal_ctx, + tpSirGtkOffloadParams request, + uint8_t session_id); +CDF_STATUS sme_get_gtk_offload(tHalHandle hal_ctx, + gtk_offload_get_info_callback callback_routine, + void *callback_context, uint8_t session_id); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +uint16_t sme_chn_to_freq(uint8_t chanNum); +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +CDF_STATUS sme_set_max_tx_power(tHalHandle hHal, tSirMacAddr pBssid, + tSirMacAddr pSelfMacAddress, int8_t dB); +CDF_STATUS sme_set_max_tx_power_per_band(eCsrBand band, int8_t db); +CDF_STATUS sme_set_tx_power(tHalHandle hHal, uint8_t sessionId, + tSirMacAddr pBSSId, + tCDF_CON_MODE dev_mode, int power); +CDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr); +CDF_STATUS sme_hide_ssid(tHalHandle hHal, uint8_t sessionId, + uint8_t ssidHidden); +CDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, + uint16_t tmMode); +void sme_feature_caps_exchange(tHalHandle hHal); +void sme_disable_feature_capablity(uint8_t feature_index); +void sme_reset_power_values_for5_g(tHalHandle hHal); +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) +CDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, bool nRoamPrefer5GHz); +CDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand); +CDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes); +CDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd); + +bool sme_get_roam_intra_band(tHalHandle hHal); +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal); +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal); +CDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff); +CDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled); +CDF_STATUS sme_update_wes_mode(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId); +CDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl); +#endif /* (WLAN_FEATURE_VOWIFI_11R)||(FEATURE_WLAN_ESE)||(FEATURE_WLAN_LFR) */ + +#ifdef FEATURE_WLAN_LFR +CDF_STATUS sme_update_is_fast_roam_ini_feature_enabled(tHalHandle hHal, + uint8_t sessionId, + const bool + isFastRoamIniFeatureEnabled); +CDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled); +CDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason); +CDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, + uint8_t reason); +CDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool bFastRoamInConIniFeatureEnabled); +#endif /* FEATURE_WLAN_LFR */ +#ifdef FEATURE_WLAN_ESE +CDF_STATUS sme_update_is_ese_feature_enabled(tHalHandle hHal, uint8_t sessionId, + const bool isEseIniFeatureEnabled); +#endif /* FEATURE_WLAN_ESE */ +CDF_STATUS sme_update_config_fw_rssi_monitoring(tHalHandle hHal, + bool fEnableFwRssiMonitoring); +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +CDF_STATUS sme_set_roam_rescan_rssi_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff); +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal); + +CDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nOpportunisticThresholdDiff); +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal); +CDF_STATUS sme_set_neighbor_lookup_rssi_threshold(tHalHandle hHal, + uint8_t sessionId, uint8_t neighborLookupRssiThreshold); +CDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hHal, + uint8_t sessionId, uint8_t delay_before_vdev_stop); +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal); +CDF_STATUS sme_set_neighbor_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod); +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal); +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal); +CDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t nEmptyScanRefreshPeriod); +CDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t nNeighborScanMinChanTime, + uint8_t sessionId); +CDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId, const uint16_t nNeighborScanMaxChanTime); +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, + uint8_t sessionId); +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_state(tHalHandle hHal); +uint32_t sme_get_lim_mlm_state(tHalHandle hHal); +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId); +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId); +CDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod); +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId); +CDF_STATUS sme_set_roam_bmiss_first_bcnt(tHalHandle hHal, + uint8_t sessionId, const uint8_t nRoamBmissFirstBcnt); +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal); +CDF_STATUS sme_set_roam_bmiss_final_bcnt(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt); +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal); +CDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight); +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal); +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal); +CDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels); +#ifdef FEATURE_WLAN_ESE_UPLOAD +CDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, uint8_t *pChannelList, + uint8_t numChannels); +#endif +CDF_STATUS sme_get_roam_scan_channel_list(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId); +bool sme_get_is_ese_feature_enabled(tHalHandle hHal); +bool sme_get_wes_mode(tHalHandle hHal); +bool sme_get_roam_scan_control(tHalHandle hHal); +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal); +bool sme_get_is_ft_feature_enabled(tHalHandle hHal); +#endif +CDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled); +uint8_t sme_is_feature_supported_by_fw(uint8_t featEnumValue); +#ifdef FEATURE_WLAN_TDLS +CDF_STATUS sme_send_tdls_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams); +CDF_STATUS sme_send_tdls_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, uint8_t frame_type, + uint8_t dialog, uint16_t status, + uint32_t peerCapability, uint8_t *buf, + uint8_t len, uint8_t responder); +CDF_STATUS sme_change_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams); +CDF_STATUS sme_add_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +CDF_STATUS sme_delete_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +void sme_set_tdls_power_save_prohibited(tHalHandle hHal, uint32_t sessionId, + bool val); +CDF_STATUS sme_send_tdls_chan_switch_req( + tHalHandle hal, + sme_tdls_chan_switch_params *ch_switch_params); +#endif + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR); +CDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode); +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); +/* + * SME API to determine the channel bonding mode + */ +CDF_STATUS sme_set_ch_params(tHalHandle hHal, eCsrPhyMode eCsrPhyMode, + uint8_t channel, uint8_t ht_sec_ch, chan_params_t *ch_params); +CDF_STATUS sme_handoff_request(tHalHandle hHal, uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo); +CDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal); +#ifdef FEATURE_WLAN_LPHB +CDF_STATUS sme_lphb_config_req(tHalHandle hHal, + tSirLPHBReq * lphdReq, + void (*pCallbackfn)(void *pHddCtx, + tSirLPHBInd * indParam)); +#endif /* FEATURE_WLAN_LPHB */ +CDF_STATUS sme_add_periodic_tx_ptrn(tHalHandle hHal, tSirAddPeriodicTxPtrn + *addPeriodicTxPtrnParams); +CDF_STATUS sme_del_periodic_tx_ptrn(tHalHandle hHal, tSirDelPeriodicTxPtrn + *delPeriodicTxPtrnParams); +void sme_enable_disable_split_scan(tHalHandle hHal, uint8_t nNumStaChan, + uint8_t nNumP2PChan); +CDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams); +CDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBSSId, bool flush_cache); +void sme_get_command_q_status(tHalHandle hHal); + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +CDF_STATUS sme_set_idle_powersave_config(void *cds_context, + tHalHandle hHal, uint32_t value); +CDF_STATUS sme_notify_modem_power_state(tHalHandle hHal, uint32_t value); + +/*SME API to convert convert the ini value to the ENUM used in csr and MAC*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value); +int sme_update_ht_config(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value); +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, + uint16_t ht_capab); +#ifdef QCA_HT_2040_COEX +CDF_STATUS sme_notify_ht2040_mode(tHalHandle hHal, uint16_t staId, + struct cdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type); +CDF_STATUS sme_set_ht2040_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled); +#endif +CDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2); +#ifdef FEATURE_WLAN_TDLS +CDF_STATUS sme_update_fw_tdls_state(tHalHandle hHal, void *psmeTdlsParams, + bool useSmeLock); +CDF_STATUS sme_update_tdls_peer_state(tHalHandle hHal, + tSmeTdlsPeerStateParams *pPeerStateParams); +#endif /* FEATURE_WLAN_TDLS */ +#ifdef FEATURE_WLAN_CH_AVOID +CDF_STATUS sme_add_ch_avoid_callback(tHalHandle hHal, + void (*pCallbackfn)(void *hdd_context, void *indi_param)); +CDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal); +#else +static inline +CDF_STATUS sme_add_ch_avoid_callback(tHalHandle hHal, + void (*pCallbackfn)(void *hdd_context, void *indi_param)) +{ + return CDF_STATUS_E_NOSUPPORT; +} + +static inline +CDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal) +{ + return CDF_STATUS_E_NOSUPPORT; +} +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +CDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void)); +CDF_STATUS sme_set_auto_shutdown_timer(tHalHandle hHal, uint32_t timer_value); +#endif +CDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct cdf_mac_addr bssid, uint32_t cb_mode, + tCsrRoamProfile *profile); +CDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, + struct cdf_mac_addr bssid, uint8_t dfsCacWaitStatus); +CDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct cdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, uint8_t ch_bandwidth); +CDF_STATUS sme_init_thermal_info(tHalHandle hHal, + tSmeThermalParams thermalParam); +CDF_STATUS sme_set_thermal_level(tHalHandle hHal, uint8_t level); +CDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx); +CDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)); +CDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType); +CDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +CDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value); +CDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, + bool disablefwd); +uint32_t sme_get_channel_bonding_mode5_g(tHalHandle hHal); +uint32_t sme_get_channel_bonding_mode24_g(tHalHandle hHal); +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct sStatsExtRequestReq { + uint32_t request_data_len; + uint8_t *request_data; +} tStatsExtRequestReq, *tpStatsExtRequestReq; +typedef void (*StatsExtCallback)(void *, tStatsExtEvent *); +void sme_stats_ext_register_callback(tHalHandle hHal, + StatsExtCallback callback); +CDF_STATUS sme_stats_ext_request(uint8_t session_id, + tpStatsExtRequestReq input); +CDF_STATUS sme_stats_ext_event(tHalHandle hHal, void *pMsg); +#endif +CDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, + uint8_t sessionId, + uint8_t allowDFSChannelRoam); +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal); +bool sme_sta_in_middle_of_roaming(tHalHandle hHal, uint8_t sessionId); + +#ifdef FEATURE_WLAN_EXTSCAN +CDF_STATUS sme_get_valid_channels_by_band(tHalHandle hHal, uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels); +CDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams *pReq); +CDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd); +CDF_STATUS sme_ext_scan_stop(tHalHandle hHal, + tSirExtScanStopReqParams *pStopReq); +CDF_STATUS sme_set_bss_hotlist(tHalHandle hHal, + tSirExtScanSetBssidHotListReqParams * + pSetHotListReq); +CDF_STATUS sme_reset_bss_hotlist(tHalHandle hHal, + tSirExtScanResetBssidHotlistReqParams * + pResetReq); +CDF_STATUS sme_set_significant_change(tHalHandle hHal, + tSirExtScanSetSigChangeReqParams * + pSetSignificantChangeReq); +CDF_STATUS sme_reset_significant_change(tHalHandle hHal, + tSirExtScanResetSignificantChangeReqParams + *pResetReq); +CDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq); + +CDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *req_msg); +CDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); +CDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); +CDF_STATUS +sme_set_ssid_hotlist(tHalHandle hal, + struct sir_set_ssid_hotlist_request *request); + +CDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)); +#endif /* FEATURE_WLAN_EXTSCAN */ +CDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +CDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq * pclearStatsReq); +CDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, + tSirLLStatsSetReq *psetStatsReq); +CDF_STATUS sme_ll_stats_get_req(tHalHandle hHal, + tSirLLStatsGetReq *pgetStatsReq); +CDF_STATUS sme_set_link_layer_stats_ind_cb(tHalHandle hHal, + void (*callbackRoutine)(void *callbackCtx, + int indType, void *pRsp)); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +CDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req); +CDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hHal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)); +CDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hHal); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled); +CDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hHal, + uint8_t sessionId, + bool nRoamKeyMgmtOffloadEnabled); +#endif +#ifdef WLAN_FEATURE_NAN +CDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg); +#endif /* WLAN_FEATURE_NAN */ +CDF_STATUS sme_get_link_status(tHalHandle hHal, + tCsrLinkStatusCallback callback, + void *pContext, uint8_t sessionId); +CDF_STATUS sme_get_temperature(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)); +CDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, + tSirScanMacOui *pScanMacOui); + +#ifdef IPA_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_ipa_offload_enable_disable + \brief API to enable/disable IPA offload + \param hHal - The handle returned by macOpen. + \param sessionId - Session Identifier + \param pRequest - Pointer to the offload request. + \return eHalStatus + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, + uint8_t session_id, + struct sir_ipa_offload_enable_disable *request); +#else +static inline CDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, + uint8_t session_id, + struct sir_ipa_offload_enable_disable *request) +{ + return CDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ + +#ifdef DHCP_SERVER_OFFLOAD +CDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo * pDhcpSrvInfo); +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +CDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1); +#endif +CDF_STATUS sme_handle_dfs_chan_scan(tHalHandle hHal, uint8_t dfs_flag); +CDF_STATUS sme_set_mas(uint32_t val); +CDF_STATUS sme_set_miracast(tHalHandle hal, uint8_t filter_type); + +CDF_STATUS sme_configure_modulated_dtim(tHalHandle hal, uint8_t session_id, + uint32_t modulated_dtim); + +CDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor); + +CDF_STATUS sme_configure_guard_time(tHalHandle hal, uint8_t session_id, + uint32_t guard_time); + +CDF_STATUS sme_wifi_start_logger(tHalHandle hal, + struct sir_wifi_start_log start_log); + +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, + uint8_t sessionId); + +CDF_STATUS sme_enable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + sme_tspec_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval); + +CDF_STATUS sme_disable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, + uint32_t sessionId); + +CDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, + struct rssi_monitor_req *input); +CDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)); + +CDF_STATUS sme_update_nss(tHalHandle h_hal, uint8_t nss); + +bool sme_is_any_session_in_connected_state(tHalHandle h_hal); + +CDF_STATUS sme_soc_set_pcl(tHalHandle hal, + struct sir_pcl_list msg); +CDF_STATUS sme_soc_set_hw_mode(tHalHandle hal, + struct sir_hw_mode msg); +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback); +CDF_STATUS sme_nss_update_request(tHalHandle hHal, uint32_t vdev_id, + uint8_t new_nss, void *cback, + uint8_t next_action, void *hdd_context); + +typedef void (*sme_peer_authorized_fp) (uint32_t vdev_id); +CDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_fp, + uint32_t vdev_id); +CDF_STATUS sme_soc_set_dual_mac_config(tHalHandle hal, + struct sir_dual_mac_config msg); + +void sme_set_scan_disable(tHalHandle h_hal, int value); +void sme_setdef_dot11mode(tHalHandle hal); + +CDF_STATUS sme_disable_non_fcc_channel(tHalHandle hHal, + bool fcc_constraint); + +CDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val); + +void wlan_sap_enable_phy_error_logs(tHalHandle hal, bool enable_log); +void sme_set_dot11p_config(tHalHandle hal, bool enable_dot11p); + +CDF_STATUS sme_ocb_set_config(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_config *config); + +CDF_STATUS sme_ocb_set_utc_time(tHalHandle hHal, struct sir_ocb_utc *utc); + +CDF_STATUS sme_ocb_start_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert); + +CDF_STATUS sme_ocb_stop_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert); + +CDF_STATUS sme_ocb_get_tsf_timer(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_get_tsf_timer *request); + +CDF_STATUS sme_dcc_get_stats(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_get_stats *request); + +CDF_STATUS sme_dcc_clear_stats(tHalHandle hHal, uint32_t vdev_id, + uint32_t dcc_stats_bitmap); + +CDF_STATUS sme_dcc_update_ndl(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_update_ndl *request); + +CDF_STATUS sme_register_for_dcc_stats_event(tHalHandle hHal, void *context, + ocb_callback callback); +void sme_add_set_thermal_level_callback(tHalHandle hal, + sme_set_thermal_level_callback callback); + +#endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_ft_api.h b/core/sme/inc/sme_ft_api.h new file mode 100644 index 0000000000..59e722f43f --- /dev/null +++ b/core/sme/inc/sme_ft_api.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#if defined(WLAN_FEATURE_VOWIFI_11R) + +#if !defined(__SME_FTAPI_H) +#define __SME_FTAPI_H + +#include + +typedef enum eFTIEState { + eFT_START_READY, /* Start before and after 11r assoc */ + eFT_AUTH_REQ_READY, /* When we have recvd the 1st or nth auth req */ + /* + * Sent auth1 and waiting auth2 We are now ready for FT phase, + * send auth1, recd auth2 + */ + eFT_WAIT_AUTH2, + eFT_AUTH_COMPLETE, + /* Now we have sent Auth Rsp to the supplicant and waiting */ + /* Reassoc Req from the supplicant. */ + eFT_REASSOC_REQ_WAIT, + /* + * We have received the Reassoc request from supplicant. + * Waiting for the keys. + */ + eFT_SET_KEY_WAIT, +} tFTIEStates; + +/* FT neighbor roam callback user context */ +typedef struct sFTRoamCallbackUsrCtx { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tFTRoamCallbackUsrCtx, *tpFTRoamCallbackUsrCtx; + +typedef struct sFTSMEContext { + /* Received and processed during pre-auth */ + uint8_t *auth_ft_ies; + uint32_t auth_ft_ies_length; + /* Received and processed during re-assoc */ + uint8_t *reassoc_ft_ies; + uint16_t reassoc_ft_ies_length; + /* Pre-Auth info */ + tFTIEStates FTState; /* The state of FT in the current 11rAssoc */ + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + uint32_t smeSessionId; + /* Saved pFTPreAuthRsp */ + tpSirFTPreAuthRsp psavedFTPreAuthRsp; + bool setFTPreAuthState; + bool setFTPTKState; + /* Time to trigger reassoc once pre-auth is successful */ + cdf_mc_timer_t preAuthReassocIntvlTimer; + bool addMDIE; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t r0kh_id_len; + uint8_t r0kh_id[SIR_ROAM_R0KH_ID_MAX_LEN]; +#endif + /* User context for the timer callback */ + tpFTRoamCallbackUsrCtx pUsrCtx; +} tftSMEContext, *tpftSMEContext; + +/*-------------------------------------------------------------------------- + Prototype functions + ------------------------------------------------------------------------*/ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId); +void sme_ft_close(tHalHandle hHal, uint32_t sessionId); +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId); +void sme_set_ft_ies(tHalHandle hHal, uint32_t sessionId, const uint8_t *ft_ies, + uint16_t ft_ies_length); +CDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo); +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length); +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length); +void sme_preauth_reassoc_intvl_timer_callback(void *context); +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state); +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId); +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId); +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state); +#endif + +#endif /* #if !defined( __SME_FTAPI_H ) */ diff --git a/core/sme/inc/sme_inside.h b/core/sme/inc/sme_inside.h new file mode 100644 index 0000000000..396166f202 --- /dev/null +++ b/core/sme/inc/sme_inside.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEINSIDE_H) +#define __SMEINSIDE_H + +/** + * \file sme_inside.h + * + * \brief prototype for SME structures and APIs used insside SME + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_status.h" +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "sir_api.h" +#include "csr_internal.h" +#include "sme_qos_api.h" +#include "sme_qos_internal.h" + +#ifdef FEATURE_OEM_DATA_SUPPORT +#include "oem_data_internal.h" +#endif + +#if defined WLAN_FEATURE_VOWIFI +#include "sme_rrm_api.h" +#endif +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +#define SME_TOTAL_COMMAND 40 + +typedef struct sGenericPmcCmd { + uint32_t size; /* sizeof the data in the union, if any */ + uint32_t sessionId; + /* if true, the cmd shalln't put back to the queue, free mem instead. */ + bool fReleaseWhenDone; + union { + tSirSmeWowlEnterParams enterWowlInfo; + tSirSmeWowlExitParams exitWowlInfo; + } u; +} tGenericPmcCmd; + +typedef struct sGenericQosCmd { + sme_QosWmmTspecInfo tspecInfo; + sme_QosEdcaAcType ac; + uint8_t tspec_mask; +} tGenericQosCmd; + +typedef struct sRemainChlCmd { + uint8_t chn; + uint8_t phyMode; + uint32_t duration; + uint8_t isP2PProbeReqAllowed; + uint32_t scan_id; + void *callback; + void *callbackCtx; +} tRemainChlCmd; + +typedef struct sNoACmd { + tP2pPsConfig NoA; +} tNoACmd; +#ifdef FEATURE_WLAN_TDLS +typedef struct TdlsSendMgmtInfo { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; +} tTdlsSendMgmtCmdInfo; + +typedef struct TdlsLinkEstablishInfo { + tSirMacAddr peerMac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[SIR_MAC_MAX_SUPP_OPER_CLASSES]; +} tTdlsLinkEstablishCmdInfo; + +typedef struct TdlsAddStaInfo { + eTdlsAddOper tdlsAddOper; + tSirMacAddr peerMac; + uint16_t capability; + uint8_t extnCapability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supportedRatesLen; + uint8_t supportedRates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsdQueues; + uint8_t maxSp; +} tTdlsAddStaCmdInfo; + +typedef struct TdlsDelStaInfo { + tSirMacAddr peerMac; +} tTdlsDelStaCmdInfo; +/* + * TDLS cmd info, CMD from SME to PE. + */ +typedef struct s_tdls_cmd { + uint32_t size; + union { + tTdlsLinkEstablishCmdInfo tdlsLinkEstablishCmdInfo; + tTdlsSendMgmtCmdInfo tdlsSendMgmtCmdInfo; + tTdlsAddStaCmdInfo tdlsAddStaCmdInfo; + tTdlsDelStaCmdInfo tdlsDelStaCmdInfo; + } u; +} tTdlsCmd; +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct s_nss_update_cmd - Format of nss update request + * @new_nss: new nss value + * @session_id: Session ID + * @set_hw_mode_cb: HDD nss update callback + * @context: Adapter context + */ +struct s_nss_update_cmd { + uint32_t new_nss; + uint32_t session_id; + void *nss_update_cb; + void *context; + uint8_t next_action; +}; + +typedef struct tagSmeCmd { + tListElem Link; + eSmeCommandType command; + uint32_t sessionId; + union { + tScanCmd scanCmd; + tRoamCmd roamCmd; + tWmStatusChangeCmd wmStatusChangeCmd; + tSetKeyCmd setKeyCmd; + tGenericPmcCmd pmcCmd; + tGenericQosCmd qosCmd; +#ifdef FEATURE_OEM_DATA_SUPPORT + tOemDataCmd oemDataCmd; +#endif + tRemainChlCmd remainChlCmd; + tNoACmd NoACmd; + tAddStaForSessionCmd addStaSessionCmd; + tDelStaForSessionCmd delStaSessionCmd; +#ifdef FEATURE_WLAN_TDLS + tTdlsCmd tdlsCmd; +#endif + struct sir_hw_mode set_hw_mode_cmd; + struct s_nss_update_cmd nss_update_cmd; + struct sir_dual_mac_config set_dual_mac_cmd; + } u; +} tSmeCmd; + +/*-------------------------------------------------------------------------- + Internal to SME + ------------------------------------------------------------------------*/ +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac); +void sme_push_command(tpAniSirGlobal pMac, tSmeCmd *pCmd, bool fHighPriority); +void sme_process_pending_queue(tpAniSirGlobal pMac); +void sme_release_command(tpAniSirGlobal pMac, tSmeCmd *pCmd); +void purge_sme_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId, + tDblLinkList *pList); +bool sme_command_pending(tpAniSirGlobal pMac); +bool pmc_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +CDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +CDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_reinit_set_key_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +CDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +void csr_release_command_set_key(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, bool fStopping); + +CDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum); +bool csr_roam_is_valid40_mhz_channel(tpAniSirGlobal pmac, uint8_t channel); + +CDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme); +CDF_STATUS sme_release_global_lock(tSmeStruct *psSme); + +#ifdef FEATURE_OEM_DATA_SUPPORT +CDF_STATUS oem_data_process_oem_data_req_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +#endif + +CDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +CDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); +CDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +CDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); + +#ifdef FEATURE_WLAN_SCAN_PNO +CDF_STATUS pmc_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq pRequest, + uint8_t sessionId, + preferred_network_found_ind_cb + callbackRoutine, void *callbackContext); +#endif /* FEATURE_WLAN_SCAN_PNO */ +bool csr_roamGetConcurrencyConnectStatusForBmps(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_TDLS +CDF_STATUS csr_tdls_send_mgmt_req(tHalHandle hHal, uint8_t sessionId, + tCsrTdlsSendMgmt * tdlsSendMgmt); +CDF_STATUS csr_tdls_send_link_establish_params(tHalHandle hHal, + uint8_t sessionId, const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams *tdlsLinkEstablishParams); +CDF_STATUS csr_tdls_add_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +CDF_STATUS csr_tdls_change_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams); +CDF_STATUS csr_tdls_del_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +CDF_STATUS csr_tdls_process_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +CDF_STATUS csr_tdls_process_link_establish(tpAniSirGlobal pMac, tSmeCmd *cmd); +CDF_STATUS tdls_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); +#endif /* FEATURE_WLAN_TDLS */ + +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) +CDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId); +CDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, const uint8_t *pChannelList, + const uint8_t numChannels); +CDF_STATUS csr_update_bg_scan_config_ini_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, eCsrBand eBand); +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const eCsrBand eBand); +#endif + +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); +void active_list_cmd_timeout_handle(void *userData); +void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command); +#endif /* #if !defined( __SMEINSIDE_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h new file mode 100644 index 0000000000..4ff54c7287 --- /dev/null +++ b/core/sme/inc/sme_internal.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEINTERNAL_H) +#define __SMEINTERNAL_H + +/** + * \file sme_internal.h + * + * \brief prototype for SME internal structures and APIs used for SME and MAC + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_status.h" +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "host_diag_core_event.h" +#include "csr_link_list.h" +#include "sme_power_save.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/* Mask can be only have one bit set */ +typedef enum eSmeCommandType { + eSmeNoCommand = 0, + eSmeDropCommand, + /* this is not a command, it is to identify this is a CSR command */ + eSmeCsrCommandMask = 0x10000, + eSmeCommandScan, + eSmeCommandRoam, + eSmeCommandWmStatusChange, + eSmeCommandSetKey, + eSmeCommandAddStaSession, + eSmeCommandDelStaSession, +#ifdef FEATURE_WLAN_TDLS + /* + * eSmeTdlsCommandMask = 0x80000, + * To identify TDLS commands + * These can be considered as csr commands. + */ + eSmeCommandTdlsSendMgmt, + eSmeCommandTdlsAddPeer, + eSmeCommandTdlsDelPeer, + eSmeCommandTdlsLinkEstablish, +#endif + /* PMC */ + eSmePmcCommandMask = 0x20000, /* To identify PMC commands */ + eSmeCommandEnterBmps, + eSmeCommandExitBmps, + eSmeCommandEnterUapsd, + eSmeCommandExitUapsd, + eSmeCommandExitWowl, + eSmeCommandEnterStandby, + /* QOS */ + eSmeQosCommandMask = 0x40000, /* To identify Qos commands */ + eSmeCommandAddTs, + eSmeCommandDelTs, +#ifdef FEATURE_OEM_DATA_SUPPORT + eSmeCommandOemDataReq = 0x80000, /* To identify the oem data commands */ +#endif + eSmeCommandRemainOnChannel, + e_sme_command_set_hw_mode, + e_sme_command_nss_update, + e_sme_command_set_dual_mac_config, +} eSmeCommandType; + +typedef enum eSmeState { + SME_STATE_STOP, + SME_STATE_START, + SME_STATE_READY, +} eSmeState; + +#define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state) +#define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state) + +typedef struct sStatsExtEvent { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tStatsExtEvent, *tpStatsExtEvent; + +#define MAX_ACTIVE_CMD_STATS 16 + +typedef struct sActiveCmdStats { + eSmeCommandType command; + uint32_t reason; + uint32_t sessionId; + uint64_t timestamp; +} tActiveCmdStats; + +typedef struct sSelfRecoveryStats { + tActiveCmdStats activeCmdStats[MAX_ACTIVE_CMD_STATS]; + uint8_t cmdStatsIndx; +} tSelfRecoveryStats; + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/* GTK Offload Information Callback declaration */ +typedef void (*gtk_offload_get_info_callback)(void *callback_context, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp); +#endif +#ifdef FEATURE_WLAN_SCAN_PNO +/*Pref netw found Cb declaration*/ +typedef void (*preferred_network_found_ind_cb)(void *callback_context, + tpSirPrefNetworkFoundInd + pPrefNetworkFoundInd); +#endif + +typedef void (*ocb_callback)(void *context, void *response); +typedef void (*sme_set_thermal_level_callback)(void *context, u_int8_t level); + +typedef struct tagSmeStruct { + eSmeState state; + cdf_mutex_t lkSmeGlobalLock; + uint32_t totalSmeCmd; + void *pSmeCmdBufAddr; + tDblLinkList smeCmdActiveList; + tDblLinkList smeCmdPendingList; + tDblLinkList smeCmdFreeList; /* preallocated roam cmd list */ + tCDF_CON_MODE currDeviceMode; +#ifdef FEATURE_WLAN_LPHB + void (*pLphbIndCb)(void *pHddCtx, tSirLPHBInd *indParam); +#endif /* FEATURE_WLAN_LPHB */ + /* pending scan command list */ + tDblLinkList smeScanCmdPendingList; + /* active scan command list */ + tDblLinkList smeScanCmdActiveList; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_event_wlan_status_payload_type eventPayload; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + void (*pChAvoidNotificationCb)(void *hdd_context, void *indi_param); +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + void (*pLinkLayerStatsIndCallback)(void *callbackContext, + int indType, void *pRsp); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + void (*pAutoShutdownNotificationCb)(void); +#endif + /* Maximum interfaces allowed by the host */ + uint8_t max_intf_count; + void (*StatsExtCallback)(void *, tStatsExtEvent *); + /* linkspeed callback */ + void (*pLinkSpeedIndCb)(tSirLinkSpeedInfo *indParam, + void *pDevContext); + void *pLinkSpeedCbContext; +#ifdef FEATURE_WLAN_EXTSCAN + void (*pExtScanIndCb)(void *, const uint16_t, void *); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_NAN + void (*nanCallback)(void *, tSirNanEvent *); +#endif + bool enableSelfRecovery; + tCsrLinkStatusCallback linkStatusCallback; + void *linkStatusContext; + /* get temperature event context and callback */ + void *pTemperatureCbContext; + void (*pGetTemperatureCb)(int temperature, void *context); + uint8_t miracast_value; + struct ps_global_info ps_global_info; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + /* routine to call for GTK Offload Information */ + gtk_offload_get_info_callback gtk_offload_get_info_cb; + /* value to be passed as parameter to routine specified above */ + void *gtk_offload_get_info_cb_context; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_WLAN_SCAN_PNO + /* routine to call for Preferred Network Found Indication */ + preferred_network_found_ind_cb pref_netw_found_cb; + /* value to be passed as parameter to routine specified above */ + void *preferred_network_found_ind_cb_ctx; +#endif /* FEATURE_WLAN_SCAN_PNO */ + void (*rssi_threshold_breached_cb)(void *, struct rssi_breach_event *); +#ifdef WLAN_FEATURE_MEMDUMP + void (*fw_dump_callback)(void *context, struct fw_dump_rsp *rsp); +#endif + hw_mode_transition_cb sme_hw_mode_trans_cb; + /* OCB callbacks */ + void *ocb_set_config_context; + ocb_callback ocb_set_config_callback; + void *ocb_get_tsf_timer_context; + ocb_callback ocb_get_tsf_timer_callback; + void *dcc_get_stats_context; + ocb_callback dcc_get_stats_callback; + void *dcc_update_ndl_context; + ocb_callback dcc_update_ndl_callback; + void *dcc_stats_event_context; + ocb_callback dcc_stats_event_callback; + sme_set_thermal_level_callback set_thermal_level_cb; +} tSmeStruct, *tpSmeStruct; + +#endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/inc/sme_power_save.h b/core/sme/inc/sme_power_save.h new file mode 100644 index 0000000000..295f644dbd --- /dev/null +++ b/core/sme/inc/sme_power_save.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_POWER_SAVE_H) +#define __SME_POWER_SAVE_H +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "ani_system_defs.h" +#include "sir_api.h" + +#define MAX_SME_SESSIONS 5 +/* Auto Ps Entry Timer Default value - 1000 ms */ +#define AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE 1000 + +/* Auto Deferred Ps Entry Timer value - 20000 ms */ +#define AUTO_DEFERRED_PS_ENTRY_TIMER_DEFAULT_VALUE 20000 + + + +/** + * enum ps_state - State of the power save + * @FULL_POWER_MODE: for Full power mode + * @LEGACY_POWER_SAVE_MODE: For Legacy Power Save mode + * @UAPSD_MODE: for UAPSD power save + */ + +enum ps_state { + FULL_POWER_MODE, + LEGACY_POWER_SAVE_MODE, + UAPSD_MODE +}; + +/** + * struct ps_params - maintain power save state and USAPD params + * @mac_ctx: mac_ctx + * @session_id: Session Id. + * @ps_state : State of the power save + * @uapsd_per_ac_trigger_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTS frame. + * If a particular AC bit is set, it means AC is trigger enabled. + * @uapsd_per_ac_delivery_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. + * If a particular AC bit is set, it means AC is delivery enabled. + * @ac_admit_mask: used for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That particular AC is not admitted + * If bit is set to 1: That particular AC is admitted + * @ uapsd_per_ac_bit_mask: This is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. + * If a particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + * @enter_wowl_callback_routine: routine to call for wowl request. + * @enter_wowl_callback_context: value to be passed as parameter to + * routine specified above. + * @wowl_enter_params: WOWL mode configuration. + * @wake_reason_ind_cb: routine to call for wake reason indication. + * @wake_reason_ind_cb_ctx: value to be passed as parameter to + * routine specified above. + */ + +struct ps_params { + void *mac_ctx; + uint32_t session_id; + enum ps_state ps_state; + uint8_t uapsd_per_ac_trigger_enable_mask; + uint8_t uapsd_per_ac_delivery_enable_mask; + uint8_t ac_admit_mask[SIR_MAC_DIRECTION_DIRECT]; + uint8_t uapsd_per_ac_bit_mask; + /* WOWL param */ + void (*enter_wowl_callback_routine)(void *callback_context, + CDF_STATUS status); + void *enter_wowl_callback_context; + tSirSmeWowlEnterParams wowl_enter_params; +#ifdef WLAN_WAKEUP_EVENTS + void (*wake_reason_ind_cb)(void *callback_context, + tpSirWakeReasonInd wake_reason_ind); + void *wake_reason_ind_cb_ctx; +#endif /* WLAN_WAKEUP_EVENTS */ +#ifdef FEATURE_WLAN_TDLS + bool is_tdls_power_save_prohibited; +#endif + /* + * Auto Sta Ps Enable Timer + * Upon expiration of this timer + * Power Save Offload module will + * try to enable sta mode ps + */ + cdf_mc_timer_t auto_ps_enable_timer; + +}; + +/** + * struct ps_global_info - global struct for Power save information + * @ps_enabled: Power Save is enabled or not in ini + * @ps_params: maintain power save state and USAPD params + */ +struct ps_global_info { + bool ps_enabled; + struct ps_params ps_params[MAX_SME_SESSIONS]; + /* Remain in Power active till DHCP completes */ + bool remain_in_power_active_till_dhcp; +}; + +/** + * enum sme_ps_cmd: power save message to send WMA + * @SME_PS_ENABLE: For power save enable. + * @SME_PS_DISABLE: for Power save disable. + * @SME_PS_UAPSD_ENABLE; for UAPSD enable. + * @SME_PS_UAPSD_DISABLE: for UAPSD disable. + * @SME_PS_WOWL_ENTER: for WOWL Enter. + * @SME_PS_WOWL_EXIT: for WOWL Exit. + * @SME_PS_WOWL_ADD_BCAST_PTRN: Add bcst WOWL pattern. + * @SME_PS_WOWL_DEL_BCAST_PTRN: Del Bcsr Wowl Pattern. + */ +enum sme_ps_cmd { + SME_PS_ENABLE = 0, + SME_PS_DISABLE, + SME_PS_UAPSD_ENABLE, + SME_PS_UAPSD_DISABLE, + SME_PS_WOWL_ENTER, + SME_PS_WOWL_EXIT, + SME_PS_WOWL_ADD_BCAST_PTRN, + SME_PS_WOWL_DEL_BCAST_PTRN, +}; + +#endif diff --git a/core/sme/inc/sme_power_save_api.h b/core/sme/inc/sme_power_save_api.h new file mode 100644 index 0000000000..e4fa67b7e1 --- /dev/null +++ b/core/sme/inc/sme_power_save_api.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_POWER_SAVE_API_H) +#define __SME_POWER_SAVE_API_H + +#include "sme_power_save.h" +#include "ani_global.h" +#include "sme_inside.h" + +CDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command); + +CDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id); + +CDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id); + +/* Condition check if driver is ready to enter in PS */ +CDF_STATUS sme_enable_sta_ps_check(tpAniSirGlobal mac_ctx, uint32_t session_id); + +CDF_STATUS sme_ps_process_command(tpAniSirGlobal mac_ctx, + uint32_t session_id, + enum sme_ps_cmd command); + +void sme_set_tspec_uapsd_mask_per_session(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *ts_info, + uint8_t session_id); +/* Full Power Req Callback */ +typedef void (*uapsd_start_indication_cb)(void *callback_context, + uint32_t session_id, CDF_STATUS status); + +CDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id, + uapsd_start_indication_cb uapsd_start_ind_cb, + void *callback_context); +CDF_STATUS sme_set_ps_host_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#ifdef WLAN_NS_OFFLOAD +CDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#endif /* WLAN_NS_OFFLOAD */ +/* / Post a message to PE module */ +tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, tpSirMsgQ pMsg); + +CDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId, + bool isReassoc); +CDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId); + +CDF_STATUS sme_ps_open(tHalHandle hal_ctx); + +CDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id); + +void sme_auto_ps_entry_timer_expired(void *ps_param); +CDF_STATUS sme_ps_close(tHalHandle hal_ctx); +CDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t sessionId); + +CDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, + tpSirPNOScanReq request, + uint8_t session_id, + preferred_network_found_ind_cb + callback_routine, + void *callback_context); + +CDF_STATUS sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id); + +#endif /* #if !defined(__SME_POWER_SAVE_API_H) */ + diff --git a/core/sme/inc/sme_qos_api.h b/core/sme/inc/sme_qos_api.h new file mode 100644 index 0000000000..2dd02de651 --- /dev/null +++ b/core/sme/inc/sme_qos_api.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_QOSAPI_H) +#define __SME_QOSAPI_H + +/** + * \file sme_qos_api.h + * + * \brief prototype for SME QoS APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "ani_global.h" +#include "sir_api.h" + +/*-------------------------------------------------------------------------- + Pre-processor Definitions + ------------------------------------------------------------------------*/ +#define SME_QOS_UAPSD_VO 0x01 +#define SME_QOS_UAPSD_VI 0x02 +#define SME_QOS_UAPSD_BE 0x08 +#define SME_QOS_UAPSD_BK 0x04 + +/*--------------------------------------------------------------------------- + Enumeration of the various QoS status types that would be reported to HDD + ---------------------------------------------------------------------------*/ +typedef enum { + /* + * async: once PE notifies successful TSPEC negotiation, or CSR notifies + * for successful reassoc, notifies HDD with current QoS Params + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND = 0, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Params */ + SME_QOS_STATUS_SETUP_FAILURE_RSP, + /* sync */ + SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP, + /* sync: AP doesn't support QoS (WMM) */ + SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP, + /* + * async: in case of flow aggregation, if the new TSPEC negotiation + * is successful, OR, notify existing flows that TSPEC is modified with + * current QoS Params + */ + SME_QOS_STATUS_SETUP_MODIFIED_IND, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (CDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (CDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* + * sync: req has been sent down to PE in case of delts or addts + * for remain flows, OR if the AC doesn't have APSD or ACM + * async: once the downgrade req for QoS params is successful + */ + SME_QOS_STATUS_RELEASE_SUCCESS_RSP = 100, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_RELEASE_FAILURE_RSP, + /* async: AP sent DELTS indication */ + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + /* + * sync: an addts req has been sent down to PE to downgrade the + * QoS params or just buffered in SME + */ + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP, + /* sync */ + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP, + /* + * async: for QoS modify request if modification is successful, + * notifies HDD with current QoS Params + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND = 200, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* sync */ + SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (CDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (CDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* sync: STA is handing off to a new AP */ + SME_QOS_STATUS_HANDING_OFF = 300, + /* async:powersave mode changed by PMC from UAPSD to Full power */ + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND = 400, + /* async:powersave mode changed by PMC from Full power to UAPSD */ + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + +} sme_QosStatusType; + +/*--------------------------------------------------------------------------- + Enumeration of the various User priority (UP) types + + From 802.1D/802.11e/WMM specifications (all refer to same table) + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_WMM_UP_BE = 0, + SME_QOS_WMM_UP_BK = 1, + SME_QOS_WMM_UP_RESV = 2, /* Reserved */ + SME_QOS_WMM_UP_EE = 3, + SME_QOS_WMM_UP_CL = 4, + SME_QOS_WMM_UP_VI = 5, + SME_QOS_WMM_UP_VO = 6, + SME_QOS_WMM_UP_NC = 7, + SME_QOS_WMM_UP_MAX +} sme_QosWmmUpType; + +/*--------------------------------------------------------------------------- + Enumeration of the various TSPEC directions + + From 802.11e/WMM specifications + ---------------------------------------------------------------------------*/ + +typedef enum { + SME_QOS_WMM_TS_DIR_UPLINK = 0, + SME_QOS_WMM_TS_DIR_DOWNLINK = 1, + SME_QOS_WMM_TS_DIR_RESV = 2, /* Reserved */ + SME_QOS_WMM_TS_DIR_BOTH = 3, +} sme_QosWmmDirType; + +/*--------------------------------------------------------------------------- + Enumeration of the various TSPEC ack policies. + + From 802.11 WMM specification + ---------------------------------------------------------------------------*/ + +typedef enum { + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK = 0, + SME_QOS_WMM_TS_ACK_POLICY_RESV1 = 1, + SME_QOS_WMM_TS_ACK_POLICY_RESV2 = 2, /* Reserved */ + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 3, + +} sme_QosWmmAckPolicyType; + +/*--------------------------------------------------------------------------- + TS Info field in the WMM TSPEC + + See suggestive values above + ---------------------------------------------------------------------------*/ +typedef struct { + uint8_t burst_size_defn; + sme_QosWmmAckPolicyType ack_policy; + sme_QosWmmUpType up; /* User priority */ + uint8_t psb; /* power-save bit */ + sme_QosWmmDirType direction; /* Direction */ + uint8_t tid; /* TID : To be filled up by SME-QoS */ +} sme_QosWmmTsInfoType; + +/*--------------------------------------------------------------------------- + The WMM TSPEC Element (from the WMM spec) + ---------------------------------------------------------------------------*/ +typedef struct { + sme_QosWmmTsInfoType ts_info; + uint16_t nominal_msdu_size; + uint16_t maximum_msdu_size; + uint32_t min_service_interval; + uint32_t max_service_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t svc_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} sme_QosWmmTspecInfo; + +/*-------------------------------------------------------------------------- + External APIs + ------------------------------------------------------------------------*/ +typedef CDF_STATUS (*sme_QosCallback)(tHalHandle hHal, void *HDDcontext, + sme_QosWmmTspecInfo *pCurrentQoSInfo, + sme_QosStatusType status, uint32_t QosFlowID); +sme_QosStatusType sme_qos_setup_req(tHalHandle hHal, uint32_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, void *HDDcontext, + sme_QosWmmUpType UPType, uint32_t *pQosFlowID); +sme_QosStatusType sme_qos_modify_req(tHalHandle hHal, + sme_QosWmmTspecInfo *pQoSInfo, uint32_t QosFlowID); +sme_QosStatusType sme_qos_release_req(tHalHandle hHal, uint32_t QosFlowID); +bool sme_qos_is_ts_info_ack_policy_valid(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, uint8_t sessionId); +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff); +CDF_STATUS sme_update_dsc_pto_up_mapping(tHalHandle hHal, + sme_QosWmmUpType *dscpmapping, uint8_t sessionId); + +CDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); +CDF_STATUS sme_offload_qos_process_into_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); +bool sme_qos_tspec_active(tpAniSirGlobal pMac, sme_ac_enum_type ac, + uint8_t sessionId, uint8_t *pActiveTspec); + +#endif /* #if !defined( __SME_QOSAPI_H ) */ diff --git a/core/sme/inc/sme_qos_internal.h b/core/sme/inc/sme_qos_internal.h new file mode 100644 index 0000000000..f3db9e5d1d --- /dev/null +++ b/core/sme/inc/sme_qos_internal.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEQOSINTERNAL_H) +#define __SMEQOSINTERNAL_H + +/** + * \file sme_qos_internal.h + * + * \brief prototype for SME QoS APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_qos_api.h" +#include "sme_internal.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +#define SME_QOS_AP_SUPPORTS_APSD 0x80 + +/*--------------------------------------------------------------------------- + Enumeration of the various EDCA Access Categories: + Based on AC to ACI mapping in 802.11e spec (identical to WMM) + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_EDCA_AC_BE = 0, /* Best effort access category */ + SME_QOS_EDCA_AC_BK = 1, /* Background access category */ + SME_QOS_EDCA_AC_VI = 2, /* Video access category */ + SME_QOS_EDCA_AC_VO = 3, /* Voice access category */ + + SME_QOS_EDCA_AC_MAX +} sme_QosEdcaAcType; + +/*--------------------------------------------------------------------------- + Enumeration of the various CSR event indication types that would be reported + by CSR + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_CSR_JOIN_REQ = 0, + SME_QOS_CSR_ASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_REQ, + SME_QOS_CSR_REASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_FAILURE, + SME_QOS_CSR_DISCONNECT_REQ, + SME_QOS_CSR_DISCONNECT_IND, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + SME_QOS_CSR_HANDOFF_COMPLETE, + SME_QOS_CSR_HANDOFF_FAILURE, +#ifdef WLAN_FEATURE_VOWIFI_11R + SME_QOS_CSR_PREAUTH_SUCCESS_IND, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, +#endif +} sme_qos_csr_event_indType; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +typedef enum { + SME_QOS_DIAG_ADDTS_REQ = 0, + SME_QOS_DIAG_ADDTS_RSP, + SME_QOS_DIAG_DELTS +} sme_QosDiagQosEventSubtype; + +typedef enum { + SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED = 0, + SME_QOS_DIAG_ADDTS_INVALID_PARAMS, + SME_QOS_DIAG_ADDTS_RESERVED, + SME_QOS_DIAG_ADDTS_REFUSED, + SME_QOS_DIAG_USER_REQUESTED, + SME_QOS_DIAG_DELTS_IND_FROM_AP, + +} sme_QosDiagQosEventReasonCode; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +/*--------------------------------------------------------------------------- + The association information structure to be passed by CSR after assoc or + reassoc is done + ---------------------------------------------------------------------------*/ +typedef struct { + tSirBssDescription *pBssDesc; + tCsrRoamProfile *pProfile; +} sme_QosAssocInfo; + +/*-------------------------------------------------------------------------- + External APIs for CSR - Internal to SME + ------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_open(tpAniSirGlobal pMac); +CDF_STATUS sme_qos_close(tpAniSirGlobal pMac); +CDF_STATUS sme_qos_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); + +/*-------------------------------------------------------------------------- + Internal APIs for CSR + ------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +CDF_STATUS sme_qos_csr_event_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info); +uint8_t sme_qos_get_acm_mask(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes); +#ifdef FEATURE_WLAN_ESE +uint8_t sme_qos_ese_retrieve_tspec_info(tpAniSirGlobal pMac, uint8_t sessionId, + tTspecInfo * pTspecInfo); +#endif + +#endif /* #if !defined( __SMEQOSINTERNAL_H ) */ diff --git a/core/sme/inc/sme_rrm_api.h b/core/sme/inc/sme_rrm_api.h new file mode 100644 index 0000000000..743c77e8b2 --- /dev/null +++ b/core/sme/inc/sme_rrm_api.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMERRMAPI_H) +#define __SMERRMAPI_H + +/** + * \file sme_rrm_api.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_internal.h" +#include "sme_rrm_internal.h" + +CDF_STATUS sme_rrm_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); +CDF_STATUS rrm_close(tpAniSirGlobal pMac); +CDF_STATUS rrm_ready(tpAniSirGlobal pMac); +CDF_STATUS rrm_open(tpAniSirGlobal pMac); +CDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + tpRrmConfigParam pRrmConfig); +CDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, + uint8_t sessionId, tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +tRrmNeighborReportDesc *sme_rrm_get_first_bss_entry_from_neighbor_cache( + tpAniSirGlobal pMac); +tRrmNeighborReportDesc *sme_rrm_get_next_bss_entry_from_neighbor_cache( + tpAniSirGlobal pMac, + tpRrmNeighborReportDesc pBssEntry); +CDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, + void *pMsgBuf); + +#endif diff --git a/core/sme/inc/sme_rrm_internal.h b/core/sme/inc/sme_rrm_internal.h new file mode 100644 index 0000000000..76415d5c84 --- /dev/null +++ b/core/sme/inc/sme_rrm_internal.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMERRMINTERNAL_H) +#define __SMERRMINTERNAL_H + +/** + * \file sme_rrm_internal.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_lock.h" +#include "cdf_trace.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "rrm_global.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct sRrmConfigParam { + uint8_t rrmEnabled; + uint8_t maxRandnInterval; +} tRrmConfigParam, *tpRrmConfigParam; + +typedef struct sRrmNeighborReportDesc { + tListElem List; + tSirNeighborBssDescription *pNeighborBssDescription; + uint32_t roamScore; + uint8_t sessionId; +} tRrmNeighborReportDesc, *tpRrmNeighborReportDesc; + +typedef void (*NeighborReportRspCallback)(void *context, + CDF_STATUS cdf_status); + +typedef struct sRrmNeighborRspCallbackInfo { + uint32_t timeout; /* in ms.. min value is 10 (10ms) */ + NeighborReportRspCallback neighborRspCallback; + void *neighborRspCallbackContext; +} tRrmNeighborRspCallbackInfo, *tpRrmNeighborRspCallbackInfo; + +typedef struct sRrmNeighborRequestControlInfo { + /* To check whether a neighbor req is already sent & response pending */ + bool isNeighborRspPending; + cdf_mc_timer_t neighborRspWaitTimer; + tRrmNeighborRspCallbackInfo neighborRspCallbackInfo; +} tRrmNeighborRequestControlInfo, *tpRrmNeighborRequestControlInfo; + +typedef struct sRrmSMEContext { + uint16_t token; + struct cdf_mac_addr sessionBssId; + uint8_t regClass; + /* list of all channels to be measured. */ + tCsrChannelInfo channelList; + uint8_t currentIndex; + /* SSID used in the measuring beacon report. */ + tAniSSID ssId; + tSirMacAddr bssId; /* bssid used for beacon report measurement. */ + /* Randomization interval to be used in subsequent measurements. */ + uint16_t randnIntvl; + uint16_t duration[SIR_ESE_MAX_MEAS_IE_REQS]; + uint8_t measMode[SIR_ESE_MAX_MEAS_IE_REQS]; + tRrmConfigParam rrmConfig; + cdf_mc_timer_t IterMeasTimer; + tDblLinkList neighborReportCache; + tRrmNeighborRequestControlInfo neighborReqControlInfo; + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + tCsrEseBeaconReq eseBcnReqInfo; + bool eseBcnReqInProgress; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + tRrmMsgReqSource msgSource; +} tRrmSMEContext, *tpRrmSMEContext; + +typedef struct sRrmNeighborReq { + uint8_t no_ssid; + tSirMacSSid ssid; +} tRrmNeighborReq, *tpRrmNeighborReq; + +#endif /* #if !defined( __SMERRMINTERNAL_H ) */ diff --git a/core/sme/inc/sme_trace.h b/core/sme/inc/sme_trace.h new file mode 100644 index 0000000000..7bd1fecdd9 --- /dev/null +++ b/core/sme/inc/sme_trace.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \sme_trace.h + * + * \brief definition for trace related APIs + */ + +#ifndef __SME_TRACE_H__ +#define __SME_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF +#define TRACE_CODE_SME_COMMAND 0xFF +enum { + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, + TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT, + TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED, + TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER, + TRACE_CODE_SME_RX_HDD_REQUEST_BMPS, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, + TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY, + TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_ENTER_WOWL, + TRACE_CODE_SME_RX_HDD_EXIT_WOWL, + TRACE_CODE_SME_RX_HDD_SET_KEY, + TRACE_CODE_SME_RX_HDD_REMOVE_KEY, + TRACE_CODE_SME_RX_HDD_GET_STATS, + TRACE_CODE_SME_RX_HDD_GET_RSSI, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, + TRACE_CODE_SME_RX_HDD_DBG_READREG, + TRACE_CODE_SME_RX_HDD_DBG_WRITEREG, + TRACE_CODE_SME_RX_HDD_DBG_READMEM, + TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, + TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN, + TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_SEND_ACTION, + TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, + TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, +#endif + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, + TRACE_CODE_SME_RX_HDD_CAPS_EXCH, + TRACE_CODE_SME_RX_HDD_DISABLE_CAP, + TRACE_CODE_SME_RX_HDD_GET_DEFCCNV, + TRACE_CODE_SME_RX_HDD_GET_CURCC, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, + TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND, + TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, + TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, + TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, +}; + +void sme_trace_init(tpAniSirGlobal pMac); +#endif /* __SME_TRACE_H__ */ diff --git a/core/sme/inc/sms_debug.h b/core/sme/inc/sms_debug.h new file mode 100644 index 0000000000..adebc13604 --- /dev/null +++ b/core/sme/inc/sms_debug.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file cssDebug.h + * + * Define debug log interface for SMS. + */ + +#ifndef SMS_DEBUG_H__ +#define SMS_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) + sms_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif /* __SMS_DEBUG_H__ */ diff --git a/core/sme/inc/wlan_ps_wow_diag.h b/core/sme/inc/wlan_ps_wow_diag.h new file mode 100644 index 0000000000..3d1cbc3d2b --- /dev/null +++ b/core/sme/inc/wlan_ps_wow_diag.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_PS_WOW_DIAG_H_ +#define _WLAN_PS_WOW_DIAG_H_ + +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +typedef enum { + WLAN_BMPS_ENTER_REQ = 0, + WLAN_UAPSD_START_REQ = 1, + WLAN_UAPSD_STOP_REQ = 2, + WLAN_ENTER_STANDBY_REQ = 3, + WLAN_ENTER_DEEP_SLEEP_REQ = 4, + WLAN_START_BMPS_AUTO_TIMER_REQ = 5, + WLAN_STOP_BMPS_AUTO_TIMER_REQ = 6, + WLAN_ENTER_FULL_POWER_REQ = 7, + WLAN_PMC_CURRENT_STATE = 8, + WLAN_PS_MODE_ENABLE_REQ = 9, + WLAN_PS_MODE_DISABLE_REQ = 10, + WLAN_WINMOB_D_POWER_STATE = 11, + WLAN_BMPS_DTIM_PERIOD = 12, + WLAN_BMPS_FINAL_LI = 13, + WLAN_BMPS_SET_CONFIG = 14, + +} wlan_ps_evt_subtype_t; + +/* maps directly to eRequestFullPowerReason */ +typedef enum { + /* PE received a MAX_MISSED_BEACON_IND */ + WLAN_MISSED_BEACON_IND_RCVD, + /* PE received a SIR_HAL_BMPS_STATUS_IND */ + WLAN_BMPS_STATUS_IND_RCVD, + /* BMPS mode was disabled by HDD in SME */ + WLAN_BMPS_MODE_DISABLED, + /* Link has been disconnected requested by HDD */ + WLAN_LINK_DISCONNECTED_BY_HDD, + /* Disconnect due to linklost or requested by peer */ + WLAN_LINK_DISCONNECTED_BY_OTHER, + /* HDD request full power for some reason */ + WLAN_FULL_PWR_NEEDED_BY_HDD, + /* BAP request full power for BT_AMP */ + WLAN_FULL_PWR_NEEDED_BY_BAP, + /* CSR requests full power */ + WLAN_FULL_PWR_NEEDED_BY_CSR, + /* QOS requests full power */ + WLAN_FULL_PWR_NEEDED_BY_QOS, + /* No specific reason. General reason code */ + WLAN_REASON_OTHER +} wlan_ps_full_power_request_reason_t; + +/* maps directly to ePmcState */ +typedef enum { + WLAN_PMC_STOPPED, /* PMC is stopped */ + WLAN_PMC_FULL_POWER, /* full power */ + WLAN_PMC_LOW_POWER, /* low power */ + WLAN_PMC_REQUEST_BMPS, /* requesting BMPS */ + WLAN_PMC_BMPS, /* in BMPS */ + WLAN_PMC_REQUEST_FULL_POWER, /* requesting full power */ + WLAN_PMC_REQUEST_START_UAPSD, /* requesting Start UAPSD */ + WLAN_PMC_REQUEST_STOP_UAPSD, /* requesting Stop UAPSD */ + WLAN_PMC_UAPSD, /* in UAPSD */ + WLAN_PMC_REQUEST_STANDBY, /* requesting standby mode */ + WLAN_PMC_STANDBY, /* in standby mode */ + WLAN_PMC_REQUEST_ENTER_WOWL, /* requesting enter WOWL */ + WLAN_PMC_REQUEST_EXIT_WOWL, /* requesting exit WOWL */ + WLAN_PMC_WOWL /* Chip in WOWL mode */ +} wlan_ps_pmc_current_state_t; + +/* maps directly to ePmcPowerSavingMode */ +typedef enum { + WLAN_IDLE_MODE_POWER_SAVE, /* Idle Mode Power Save (IMPS) */ + WLAN_BEACON_MODE_POWER_SAVE, /* Beacon Mode Power Save (BMPS) */ + WLAN_SPATIAL_MULTIPLEX_POWER_SAVE, /* Spatial Multiplexing Power Save */ + WLAN_UAPSD_MODE_POWER_SAVE, /* Unscheduled Auto PS Delivery Mode */ + WLAN_STANDBY_MODE_POWER_SAVE, /* Standby Power Save Mode */ + WLAN_WOWL_MODE_POWER_SAVE /* Wake-on-Wireless Power Save Mode */ +} wlan_ps_enable_disable_ps_mode_t; + +typedef enum { + WLAN_D0, + WLAN_D1, + WLAN_D2, + WLAN_D3, + WLAN_D4 +} wlan_ps_winmob_d_power_state_t; + +typedef enum { + WLAN_WOW_ENTER_REQ = 0, + WLAN_WOW_EXIT_REQ = 1, + WLAN_WOW_DEL_PTRN_REQ = 2, + WLAN_WOW_WAKEUP = 3 +} wlan_ps_wow_evt_subtype_t; + +typedef enum { + WLAN_WOW_TYPE_NONE, + WLAN_WOW_TYPE_MAGIC_PKT_ONLY, + WLAN_WOW_TYPE_PTRN_BYTE_MATCH_ONLY, + WLAN_WOW_TYPE_MAGIC_PKT_PTRN_BYTE_MATCH, +} wlan_ps_wow_type_t; + +typedef enum { + WLAN_WOW_MAGIC_PKT_MATCH, + WLAN_WOW_PTRN_BYTE_MATCH +} wlan_ps_wos_wakeup_cause_t; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#endif /* _WLAN_PS_WOW_DIAG_H_ */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c new file mode 100644 index 0000000000..98a1f2607f --- /dev/null +++ b/core/sme/src/common/sme_api.c @@ -0,0 +1,14610 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file smeApi.c + + \brief Definitions for SME APIs + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "sms_debug.h" +#include "sme_api.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "csr_internal.h" +#include "wma_types.h" +#include "wma_if.h" +#include "cdf_trace.h" +#include "sme_trace.h" +#include "cdf_types.h" +#include "cdf_trace.h" +#include "cds_utils.h" +#include "sap_api.h" +#include "mac_trace.h" +#ifdef WLAN_FEATURE_NAN +#include "nan_api.h" +#endif +#include "cds_regdomain_common.h" +#include "cfg_api.h" +#include "sme_power_save_api.h" +#include "wma.h" + +extern tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb); + +#define LOG_SIZE 256 +#define READ_MEMORY_DUMP_CMD 9 +#define TL_INIT_STATE 0 + +static tSelfRecoveryStats g_self_recovery_stats; +/* TxMB Functions */ +extern CDF_STATUS pmc_prepare_command(tpAniSirGlobal pMac, uint32_t sessionId, + eSmeCommandType cmdType, void *pvParam, + uint32_t size, tSmeCmd **ppCmd); +extern void pmc_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +extern void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +extern CDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac, + tSmeCmd *p2pRemainonChn); +extern CDF_STATUS sme_remain_on_chn_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); +extern CDF_STATUS sme_mgmt_frm_ind(tHalHandle hHal, + tpSirSmeMgmtFrameInd pSmeMgmtFrm); +extern CDF_STATUS sme_remain_on_chn_ready(tHalHandle hHal, uint8_t *pMsg); +extern CDF_STATUS sme_send_action_cnf(tHalHandle hHal, uint8_t *pMsg); + +static CDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac); +static void sme_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fStopping); + +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); + +CDF_STATUS sme_handle_change_country_code(tpAniSirGlobal pMac, void *pMsgBuf); + +void sme_disconnect_connected_sessions(tpAniSirGlobal pMac); + +CDF_STATUS sme_handle_generic_change_country_code(tpAniSirGlobal pMac, + void *pMsgBuf); + +CDF_STATUS sme_process_nss_update_resp(tpAniSirGlobal mac, uint8_t *msg); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId); +#endif + +#ifdef WLAN_FEATURE_11W +CDF_STATUS sme_unprotected_mgmt_frm_ind(tHalHandle hHal, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm); +#endif + +/* Message processor for events from DFS */ +CDF_STATUS dfs_msg_processor(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf); + +/* Channel Change Response Indication Handler */ +CDF_STATUS sme_process_channel_change_resp(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf); + +/* Internal SME APIs */ +CDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + + if (psSme) { + if (CDF_IS_STATUS_SUCCESS + (cdf_mutex_acquire(&psSme->lkSmeGlobalLock))) { + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +CDF_STATUS sme_release_global_lock(tSmeStruct *psSme) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + + if (psSme) { + if (CDF_IS_STATUS_SUCCESS + (cdf_mutex_release(&psSme->lkSmeGlobalLock))) { + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/** + * sme_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @msg: HW mode response + * + * Processes the HW mode response and invokes the HDD callback + * to process further + */ +static CDF_STATUS sme_process_set_hw_mode_resp(tpAniSirGlobal mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + hw_mode_cb callback = NULL; + struct sir_set_hw_mode_resp *param; + + param = (struct sir_set_hw_mode_resp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("HW mode resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return CDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_hw_mode != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return CDF_STATUS_E_FAILURE; + } + + callback = command->u.set_hw_mode_cmd.set_hw_mode_cb; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed since HW mode params is NULL")); + } else { + sms_log(mac, LOGE, + FL("Calling HDD callback for HW mode response")); + callback(param->status, + param->cfgd_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exist")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the avilable command list */ + sme_release_command(mac, command); + } + sme_process_pending_queue(mac); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_process_hw_mode_trans_ind() - Process HW mode transition indication + * @mac: Global MAC pointer + * @msg: HW mode transition response + * + * Processes the HW mode transition indication and invoke the HDD callback + * to process further + */ +static CDF_STATUS sme_process_hw_mode_trans_ind(tpAniSirGlobal mac, + uint8_t *msg) +{ + hw_mode_transition_cb callback = NULL; + struct sir_hw_mode_trans_ind *param; + + param = (struct sir_hw_mode_trans_ind *)msg; + if (!param) { + sms_log(mac, LOGE, FL("HW mode trans ind param is NULL")); + return CDF_STATUS_E_FAILURE; + } + + callback = mac->sme.sme_hw_mode_trans_cb; + if (callback) { + sms_log(mac, LOGE, FL("Calling registered callback...")); + callback(param->old_hw_mode_index, + param->new_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map); + } + + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac) +{ + CDF_STATUS status; + tSmeCmd *pCmd; + uint32_t cmd_idx; + CDF_STATUS cdf_status; + cdf_mc_timer_t *cmdTimeoutTimer = NULL; + + pMac->sme.totalSmeCmd = SME_TOTAL_COMMAND; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdActiveList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdPendingList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeScanCmdActiveList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeScanCmdPendingList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdFreeList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + + pCmd = cdf_mem_malloc(sizeof(tSmeCmd) * pMac->sme.totalSmeCmd); + if (NULL == pCmd) + status = CDF_STATUS_E_NOMEM; + else { + status = CDF_STATUS_SUCCESS; + + cdf_mem_set(pCmd, sizeof(tSmeCmd) * pMac->sme.totalSmeCmd, 0); + pMac->sme.pSmeCmdBufAddr = pCmd; + + for (cmd_idx = 0; cmd_idx < pMac->sme.totalSmeCmd; cmd_idx++) { + csr_ll_insert_tail(&pMac->sme.smeCmdFreeList, + &pCmd[cmd_idx].Link, LL_ACCESS_LOCK); + } + } + + /* This timer is only to debug the active list command timeout */ + + cmdTimeoutTimer = + (cdf_mc_timer_t *) cdf_mem_malloc(sizeof(cdf_mc_timer_t)); + if (cmdTimeoutTimer) { + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = cmdTimeoutTimer; + cdf_status = + cdf_mc_timer_init(pMac->sme.smeCmdActiveList. + cmdTimeoutTimer, CDF_TIMER_TYPE_SW, + active_list_cmd_timeout_handle, (void *)pMac); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Init Timer fail for active list command process time out"); + cdf_mem_free(pMac->sme.smeCmdActiveList. + cmdTimeoutTimer); + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = NULL; + } else { + pMac->sme.smeCmdActiveList.cmdTimeoutDuration = + CSR_ACTIVE_LIST_CMD_TIMEOUT_VALUE; + } + } + +end: + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, "failed to initialize sme command list:%d\n", + status); + + return status; +} + +void sme_release_command(tpAniSirGlobal pMac, tSmeCmd *pCmd) +{ + pCmd->command = eSmeNoCommand; + csr_ll_insert_tail(&pMac->sme.smeCmdFreeList, &pCmd->Link, LL_ACCESS_LOCK); +} + +static void sme_release_cmd_list(tpAniSirGlobal pMac, tDblLinkList *pList) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_LOCK)) != NULL) { + /* TODO: base on command type to call release functions */ + /* reinitialize different command types so they can be reused */ + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_abort_command(pMac, pCommand, true); + } +} + +static void purge_sme_cmd_list(tpAniSirGlobal pMac) +{ + /* release any out standing commands back to free command list */ + sme_release_cmd_list(pMac, &pMac->sme.smeCmdPendingList); + sme_release_cmd_list(pMac, &pMac->sme.smeCmdActiveList); + sme_release_cmd_list(pMac, &pMac->sme.smeScanCmdPendingList); + sme_release_cmd_list(pMac, &pMac->sme.smeScanCmdActiveList); +} + +void purge_sme_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId, + tDblLinkList *pList) +{ + /* release any out standing commands back to free command list */ + tListElem *pEntry, *pNext; + tSmeCmd *pCommand; + tDblLinkList localList; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pNext = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->sessionId == sessionId) { + if (csr_ll_remove_entry(pList, pEntry, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + } + pEntry = pNext; + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_abort_command(pMac, pCommand, true); + } + csr_ll_close(&localList); +} + +static CDF_STATUS free_sme_cmd_list(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + purge_sme_cmd_list(pMac); + csr_ll_close(&pMac->sme.smeCmdPendingList); + csr_ll_close(&pMac->sme.smeCmdActiveList); + csr_ll_close(&pMac->sme.smeScanCmdPendingList); + csr_ll_close(&pMac->sme.smeScanCmdActiveList); + csr_ll_close(&pMac->sme.smeCmdFreeList); + + /*destroy active list command time out timer */ + cdf_mc_timer_destroy(pMac->sme.smeCmdActiveList.cmdTimeoutTimer); + cdf_mem_free(pMac->sme.smeCmdActiveList.cmdTimeoutTimer); + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = NULL; + + status = cdf_mutex_acquire(&pMac->sme.lkSmeGlobalLock); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL("Failed to acquire the lock status = %d"), status); + goto done; + } + + if (NULL != pMac->sme.pSmeCmdBufAddr) { + cdf_mem_free(pMac->sme.pSmeCmdBufAddr); + pMac->sme.pSmeCmdBufAddr = NULL; + } + + status = cdf_mutex_release(&pMac->sme.lkSmeGlobalLock); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL("Failed to release the lock status = %d"), status); + } +done: + return status; +} + +void dump_csr_command_info(tpAniSirGlobal pMac, tSmeCmd *pCmd) +{ + switch (pCmd->command) { + case eSmeCommandScan: + sms_log(pMac, LOGE, " scan command reason is %d", + pCmd->u.scanCmd.reason); + break; + + case eSmeCommandRoam: + sms_log(pMac, LOGE, " roam command reason is %d", + pCmd->u.roamCmd.roamReason); + break; + + case eSmeCommandWmStatusChange: + sms_log(pMac, LOGE, " WMStatusChange command type is %d", + pCmd->u.wmStatusChangeCmd.Type); + break; + + case eSmeCommandSetKey: + sms_log(pMac, LOGE, " setKey command auth(%d) enc(%d)", + pCmd->u.setKeyCmd.authType, pCmd->u.setKeyCmd.encType); + break; + + default: + sms_log(pMac, LOGE, " default: Unhandled command %d", + pCmd->command); + break; + } +} + +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pRetCmd = NULL, *pTempCmd = NULL; + tListElem *pEntry; + static int sme_command_queue_full; + + pEntry = csr_ll_remove_head(&pMac->sme.smeCmdFreeList, LL_ACCESS_LOCK); + + /* If we can get another MS Msg buffer, then we are ok. Just link */ + /* the entry onto the linked list. (We are using the linked list */ + /* to keep track of tfhe message buffers). */ + if (pEntry) { + pRetCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* reset when free list is available */ + sme_command_queue_full = 0; + } else { + int idx = 1; + + /* Cannot change pRetCmd here since it needs to return later. */ + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + sms_log(pMac, LOGE, + "Out of command buffer.... command (0x%X) stuck", + (pTempCmd) ? pTempCmd->command : eSmeNoCommand); + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + } /* if(pTempCmd) */ + + /* dump what is in the pending queue */ + csr_ll_lock(&pMac->sme.smeCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry && !sme_command_queue_full) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Print only 1st five commands from pending queue. */ + if (idx <= 5) + sms_log(pMac, LOGE, + "Out of command buffer.... SME pending command #%d (0x%X)", + idx, pTempCmd->command); + idx++; + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + pEntry = + csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + /* Increment static variable so that it prints + * pending command only once + */ + sme_command_queue_full++; + + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + + /* There may be some more command in CSR's own pending queue */ + csr_ll_lock(&pMac->roam.roamCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->roam.roamCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sms_log(pMac, LOGE, + "Out of command buffer.... CSR pending command #%d (0x%X)", + idx++, pTempCmd->command); + dump_csr_command_info(pMac, pTempCmd); + pEntry = + csr_ll_next(&pMac->roam.roamCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->roam.roamCmdPendingList); + } + + /* memset to zero */ + if (pRetCmd) { + cdf_mem_set((uint8_t *)&pRetCmd->command, + sizeof(pRetCmd->command), 0); + cdf_mem_set((uint8_t *)&pRetCmd->sessionId, + sizeof(pRetCmd->sessionId), 0); + cdf_mem_set((uint8_t *)&pRetCmd->u, sizeof(pRetCmd->u), 0); + } + + return pRetCmd; +} + +void sme_push_command(tpAniSirGlobal pMac, tSmeCmd *pCmd, bool fHighPriority) +{ + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGE, FL("Sme in stop state")); + CDF_ASSERT(0); + return; + } + + if (fHighPriority) { + csr_ll_insert_head(&pMac->sme.smeCmdPendingList, &pCmd->Link, + LL_ACCESS_LOCK); + } else { + csr_ll_insert_tail(&pMac->sme.smeCmdPendingList, &pCmd->Link, + LL_ACCESS_LOCK); + } + + /* process the command queue... */ + sme_process_pending_queue(pMac); + + return; +} + +/* For commands that need to do extra cleanup. */ +static void sme_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fStopping) +{ + if (eSmePmcCommandMask & pCommand->command) { + sms_log(pMac, LOG1, + "No need to process PMC commands"); + return; + } + if (eSmeCsrCommandMask & pCommand->command) { + csr_abort_command(pMac, pCommand, fStopping); + return; + } + switch (pCommand->command) { + case eSmeCommandRemainOnChannel: + if (NULL != pCommand->u.remainChlCmd.callback) { + remainOnChanCallback callback = + pCommand->u.remainChlCmd.callback; + /* process the msg */ + if (callback) { + callback(pMac, pCommand->u.remainChlCmd. + callbackCtx, eCSR_SCAN_ABORT, + pCommand->u.remainChlCmd.scan_id); + } + } + sme_release_command(pMac, pCommand); + break; + default: + sme_release_command(pMac, pCommand); + break; + } + +} + +tListElem *csr_get_cmd_to_process(tpAniSirGlobal pMac, tDblLinkList *pList, + uint8_t sessionId, bool fInterlocked) +{ + tListElem *pCurEntry = NULL; + tSmeCmd *pCommand; + + /* Go through the list and return the command whose session id is not + * matching with the current ongoing scan cmd sessionId */ + pCurEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK); + while (pCurEntry) { + pCommand = GET_BASE_ADDR(pCurEntry, tSmeCmd, Link); + if (pCommand->sessionId != sessionId) { + sms_log(pMac, LOG1, + "selected the command with different sessionId"); + return pCurEntry; + } + + pCurEntry = csr_ll_next(pList, pCurEntry, fInterlocked); + } + + sms_log(pMac, LOG1, "No command pending with different sessionId"); + return NULL; +} + +bool sme_process_scan_queue(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pSmeEntry = NULL; + tSmeCmd *pSmeCommand = NULL; + bool status = true; + + if ((!csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, + LL_ACCESS_LOCK))) { + pSmeEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (pSmeEntry) + pSmeCommand = GET_BASE_ADDR(pSmeEntry, tSmeCmd, Link); + } + csr_ll_lock(&pMac->sme.smeScanCmdActiveList); + if (csr_ll_is_list_empty(&pMac->sme.smeScanCmdPendingList, + LL_ACCESS_LOCK)) + goto end; + pEntry = csr_ll_peek_head(&pMac->sme.smeScanCmdPendingList, + LL_ACCESS_LOCK); + if (!pEntry) + goto end; + + sms_log(pMac, LOGE, + FL("scan_count in active scanlist %d "), + pMac->sme.smeScanCmdActiveList.Count); + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pSmeCommand != NULL) { + /* + * if scan is running on one interface and SME receives + * the next command on the same interface then + * dont the allow the command to be queued to + * smeCmdPendingList. If next scan is allowed on + * the same interface the CSR state machine will + * get screwed up. + */ + if (pSmeCommand->sessionId == pCommand->sessionId) { + status = false; + goto end; + } + } + /* + * We cannot execute any command in wait-for-key state until setKey is + * through. + */ + if (CSR_IS_WAIT_FOR_KEY(pMac, pCommand->sessionId)) { + if (!CSR_IS_SET_KEY_COMMAND(pCommand)) { + sms_log(pMac, LOGE, + FL("Can't process cmd(%d), waiting for key"), + pCommand->command); + status = false; + goto end; + } + } + if (csr_ll_remove_entry(&pMac->sme.smeScanCmdPendingList, pEntry, + LL_ACCESS_LOCK)) { + csr_ll_insert_head(&pMac->sme.smeScanCmdActiveList, + &pCommand->Link, LL_ACCESS_NOLOCK); + switch (pCommand->command) { + case eSmeCommandScan: + sms_log(pMac, LOG1, FL("Processing scan offload cmd.")); + cdf_mc_timer_start(&pCommand->u.scanCmd.csr_scan_timer, + CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT); + csr_process_scan_command(pMac, pCommand); + break; + case eSmeCommandRemainOnChannel: + sms_log(pMac, LOG1, + FL("Processing remain on channel offload cmd")); + p2p_process_remain_on_channel_cmd(pMac, pCommand); + break; + default: + sms_log(pMac, LOGE, + FL("Wrong cmd enqueued to ScanCmdPendingList")); + pEntry = csr_ll_remove_head( + &pMac->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_release_command(pMac, pCommand); + break; + } + } +end: + csr_ll_unlock(&pMac->sme.smeScanCmdActiveList); + return status; +} + +/** + * sme_process_command() - processes SME commnd + * @mac_ctx: mac global context + * + * This function is called by sme_process_pending_queue() in a while loop + * + * Return: true indicates that caller function can proceed to next cmd + * false otherwise. + */ +bool sme_process_command(tpAniSirGlobal pMac) +{ + bool fContinue = false; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pSmeEntry; + tSmeCmd *pSmeCommand; + + /* + * if the ActiveList is empty, then nothing is active so we can process + * a pending command... + * alwasy lock active list before locking pending list + */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + if (!csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, + LL_ACCESS_NOLOCK)) { + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + + if (csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList, + LL_ACCESS_LOCK)) { + /* No command waiting */ + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + + /* + * If scan command is pending in the smeScanCmdActive list then pick the + * command from smeCmdPendingList which is not matching with the scan + * command session id. At any point of time only one command will be + * allowed on a single session. + */ + if (!csr_ll_is_list_empty( + &pMac->sme.smeScanCmdActiveList, LL_ACCESS_LOCK)) { + pSmeEntry = csr_ll_peek_head(&pMac->sme.smeScanCmdActiveList, + LL_ACCESS_LOCK); + if (pSmeEntry) { + pSmeCommand = GET_BASE_ADDR(pSmeEntry, tSmeCmd, Link); + pEntry = csr_get_cmd_to_process(pMac, + &pMac->sme.smeCmdPendingList, + pSmeCommand->sessionId, + LL_ACCESS_LOCK); + goto sme_process_cmd; + } + } + + /* Peek the command */ + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdPendingList, LL_ACCESS_LOCK); +sme_process_cmd: + if (!pEntry) { + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* + * Allow only disconnect command in wait-for-key state until setKey is + * through. + */ + if (CSR_IS_WAIT_FOR_KEY(pMac, pCommand->sessionId) + && !CSR_IS_DISCONNECT_COMMAND(pCommand) + && !CSR_IS_SET_KEY_COMMAND(pCommand)) { + if (CSR_IS_CLOSE_SESSION_COMMAND(pCommand)) { + tSmeCmd *sme_cmd = NULL; + + sms_log(pMac, LOGE, + FL("SessionId %d: close session command issued while waiting for key, issue disconnect first"), + pCommand->sessionId); + status = csr_prepare_disconnect_command(pMac, + pCommand->sessionId, &sme_cmd); + if (status == CDF_STATUS_SUCCESS && sme_cmd) { + csr_ll_lock(&pMac->sme.smeCmdPendingList); + csr_ll_insert_head(&pMac->sme.smeCmdPendingList, + &sme_cmd->Link, LL_ACCESS_NOLOCK); + pEntry = csr_ll_peek_head( + &pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + goto sme_process_cmd; + } + } + + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + sms_log(pMac, LOGE, + FL("SessionId %d: Can't process cmd(%d), waiting for key"), + pCommand->sessionId, pCommand->command); + fContinue = false; + goto process_scan_q; + } + + if (!csr_ll_remove_entry(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_LOCK)) { + /* This is odd. Some one else pull off the command. */ + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + /* we can reuse the pCommand. Insert the command onto the ActiveList */ + csr_ll_insert_head(&pMac->sme.smeCmdActiveList, &pCommand->Link, + LL_ACCESS_NOLOCK); + /* .... and process the command. */ + MTRACE(cdf_trace(CDF_MODULE_ID_SME, TRACE_CODE_SME_COMMAND, + pCommand->sessionId, pCommand->command)); + + switch (pCommand->command) { + case eSmeCommandScan: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_process_scan_command(pMac, pCommand); + break; + case eSmeCommandRoam: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_roam_process_command(pMac, pCommand); + if (!CDF_IS_STATUS_SUCCESS(status) + && csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csr_release_command_roam(pMac, pCommand); + break; + case eSmeCommandWmStatusChange: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_roam_process_wm_status_change_command(pMac, pCommand); + break; + case eSmeCommandSetKey: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_roam_process_set_key_command(pMac, pCommand); + if (!CDF_IS_STATUS_SUCCESS(status) + && csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) { + csr_release_command_set_key(pMac, pCommand); + } + break; + case eSmeCommandAddStaSession: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_add_sta_session_command(pMac, pCommand); + break; + case eSmeCommandDelStaSession: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_del_sta_session_command(pMac, pCommand); + break; +#ifdef FEATURE_OEM_DATA_SUPPORT + case eSmeCommandOemDataReq: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + oem_data_process_oem_data_req_command(pMac, pCommand); + break; +#endif + case eSmeCommandRemainOnChannel: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + p2p_process_remain_on_channel_cmd(pMac, pCommand); + break; + /* + * Treat standby differently here because caller may not be able + * to handle the failure so we do our best here + */ + case eSmeCommandEnterStandby: + break; + case eSmeCommandAddTs: + case eSmeCommandDelTs: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + fContinue = qos_process_command(pMac, pCommand); + if (fContinue && csr_ll_remove_entry( + &pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_NOLOCK)) { + /* The command failed, remove it */ + qos_release_command(pMac, pCommand); + } +#endif + break; +#ifdef FEATURE_WLAN_TDLS + case eSmeCommandTdlsSendMgmt: + case eSmeCommandTdlsAddPeer: + case eSmeCommandTdlsDelPeer: + case eSmeCommandTdlsLinkEstablish: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("sending TDLS Command 0x%x to PE"), + pCommand->command); + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_tdls_process_cmd(pMac, pCommand); + break; +#endif + case e_sme_command_set_hw_mode: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_set_hw_mode(pMac, pCommand); + break; + case e_sme_command_nss_update: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_nss_update_req(pMac, pCommand); + break; + case e_sme_command_set_dual_mac_config: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_set_dual_mac_config(pMac, pCommand); + break; + default: + /* something is wrong */ + /* remove it from the active list */ + sms_log(pMac, LOGE, FL("unknown command %d"), + pCommand->command); + pEntry = csr_ll_remove_head(&pMac->sme.smeCmdActiveList, + LL_ACCESS_NOLOCK); + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_release_command(pMac, pCommand); + status = CDF_STATUS_E_FAILURE; + break; + } + if (!CDF_IS_STATUS_SUCCESS(status)) + fContinue = true; +process_scan_q: + if (!(sme_process_scan_queue(pMac))) + fContinue = false; + return fContinue; +} + +void sme_process_pending_queue(tpAniSirGlobal pMac) +{ + while (sme_process_command(pMac)) + ; +} + +bool sme_command_pending(tpAniSirGlobal pMac) +{ + return !csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK) + || !csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); +} + +/* Global APIs */ + +/** + * sme_open() - Initialze all SME modules and put them at idle state + * @hHal: The handle returned by mac_open + * + * The function initializes each module inside SME, PMC, CSR, etc. Upon + * successfully return, all modules are at idle state ready to start. + * smeOpen must be called before any other SME APIs can be involved. + * smeOpen must be called after mac_open. + * + * Return: CDF_STATUS_SUCCESS - SME is successfully initialized. + * Other status means SME is failed to be initialized + */ +CDF_STATUS sme_open(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); +#ifndef WLAN_FEATURE_MBSSID + void *p_cds_gctx = cds_get_global_context(); +#endif + + pMac->sme.state = SME_STATE_STOP; + pMac->sme.currDeviceMode = CDF_STA_MODE; + if (!CDF_IS_STATUS_SUCCESS(cdf_mutex_init( + &pMac->sme.lkSmeGlobalLock))) { + sms_log(pMac, LOGE, FL("sme_open failed init lock")); + return CDF_STATUS_E_FAILURE; + } + status = csr_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("csr_open failed, status=%d"), status); + return status; + } + + status = sme_ps_open(hHal); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("sme_ps_open failed during initialization with status=%d"), + status); + return status; + } +#ifdef FEATURE_WLAN_TDLS + pMac->is_tdls_power_save_prohibited = 0; +#endif + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Qos open, status=%d"), status); + return status; + } +#endif +#ifdef FEATURE_OEM_DATA_SUPPORT + status = oem_data_oem_data_req_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("oem_data_oem_data_req_open, status=%d"), + status); + return status; + } +#endif + status = init_sme_cmd_list(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; +#ifndef WLAN_FEATURE_MBSSID + if (NULL == p_cds_gctx) { + sms_log(pMac, LOGE, FL("p_cds_gctx is NULL")); + return CDF_STATUS_E_FAILURE; + } + status = wlansap_open(p_cds_gctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("wlansap_open failed, status=%d"), + status); + return status; + } +#endif + +#if defined WLAN_FEATURE_VOWIFI + status = rrm_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("rrm_open failed, status=%d"), status); + return status; + } +#endif + sme_p2p_open(pMac); + sme_trace_init(pMac); + return status; +} + +/* + * sme_init_chan_list, triggers channel setup based on country code. + */ +CDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + COUNTRY_CODE_SOURCE cc_src) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + if ((cc_src == COUNTRY_CODE_SET_BY_USER) && + (pmac->roam.configParam.fSupplicantCountryCodeHasPriority)) { + pmac->roam.configParam.Is11dSupportEnabled = false; + } + + return csr_init_chan_list(pmac, alpha2); +} + +/*-------------------------------------------------------------------------- + + \brief sme_set11dinfo() - Set the 11d information about valid channels + and there power using information from nvRAM + This function is called only for AP. + + This is a synchronous call + + \param hHal - The handle returned by mac_open. + \Param pSmeConfigParams - a pointer to a caller allocated object of + typedef struct _smeConfigParams. + + \return CDF_STATUS_SUCCESS - SME update the config parameters successfully. + + Other status means SME is failed to update the config parameters. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_set11dinfo(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, NO_SESSION, 0)); + if (NULL == pSmeConfigParams) { + sms_log(pMac, LOGE, + "Empty config param structure for SME, nothing to update"); + return status; + } + + status = csr_set_channels(hHal, &pSmeConfigParams->csrConfig); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_change_default_config_param failed with status=%d", + status); + } + return status; +} + +/** + * sme_set_scan_disable() - Dynamically enable/disable scan + * @h_hal: Handle to HAL + * + * This command gives the user an option to dynamically + * enable or disable scans. + * + * Return: None + */ +void sme_set_scan_disable(tHalHandle h_hal, int value) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + mac_ctx->lim.scan_disabled = value; + sms_log(mac_ctx, LOG1, FL("value=%d"), value); +} +/*-------------------------------------------------------------------------- + + \brief sme_get_soft_ap_domain() - Get the current regulatory domain of softAp. + + This is a synchronous call + + \param hHal - The handle returned by HostapdAdapter. + \Param v_REGDOMAIN_t - The current Regulatory Domain requested for SoftAp. + + \return CDF_STATUS_SUCCESS - SME successfully completed the request. + + Other status means, failed to get the current regulatory domain. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, v_REGDOMAIN_t *domainIdSoftAp) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + NO_SESSION, 0)); + if (NULL == domainIdSoftAp) { + sms_log(pMac, LOGE, "Uninitialized domain Id"); + return status; + } + + *domainIdSoftAp = pMac->scan.domainIdCurrent; + status = CDF_STATUS_SUCCESS; + + return status; +} + +CDF_STATUS sme_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO, NO_SESSION, 0)); + if (NULL == apCntryCode) { + sms_log(pMac, LOGE, "Empty Country Code, nothing to update"); + return status; + } + + status = csr_set_reg_info(hHal, apCntryCode); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, "csr_set_reg_info failed with status=%d", + status); + } + return status; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlmReq) +{ + CDF_STATUS status; + bool ret = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t ch_list[WNI_CFG_VALID_CHANNEL_LIST] = { 0 }; + uint8_t count, valid_count = 0; + cds_msg_t msg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pPlmReq->sessionId); + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), + pPlmReq->sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Invalid Sessionid")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!pPlmReq->enable) + goto send_plm_start; + /* validating channel numbers */ + for (count = 0; count < pPlmReq->plmNumCh; count++) { + ret = csr_is_supported_channel(pMac, pPlmReq->plmChList[count]); + if (ret && pPlmReq->plmChList[count] > 14) { + if (CHANNEL_STATE_DFS == cds_get_channel_state( + pPlmReq->plmChList[count])) { + /* DFS channel is provided, no PLM bursts can be + * transmitted. Ignoring these channels. + */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("DFS channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + } else if (!ret) { + /* Not supported, ignore the channel */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Unsupported channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + ch_list[valid_count] = pPlmReq->plmChList[count]; + valid_count++; + } /* End of for () */ + + /* Copying back the valid channel list to plm struct */ + cdf_mem_set((void *)pPlmReq->plmChList, + pPlmReq->plmNumCh, 0); + if (valid_count) + cdf_mem_copy(pPlmReq->plmChList, ch_list, + valid_count); + /* All are invalid channels, FW need to send the PLM + * report with "incapable" bit set. + */ + pPlmReq->plmNumCh = valid_count; + +send_plm_start: + /* PLM START */ + msg.type = WMA_SET_PLM_REQ; + msg.reserved = 0; + msg.bodyptr = pPlmReq; + + if (!CDF_IS_STATUS_SUCCESS(cds_mq_post_message(CDF_MODULE_ID_WMA, + &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_PLM_REQ to WMA")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + return status; +} +#endif + +/*-------------------------------------------------------------------------- + + \brief sme_update_config() - Change configurations for all SME moduels + + The function updates some configuration for modules in SME, CSR, etc + during SMEs close open sequence. + + Modules inside SME apply the new configuration at the next transaction. + + This is a synchronous call + + \param hHal - The handle returned by mac_open. + \Param pSmeConfigParams - a pointer to a caller allocated object of + typedef struct _smeConfigParams. + + \return CDF_STATUS_SUCCESS - SME update the config parameters successfully. + + Other status means SME is failed to update the config parameters. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_update_config(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, NO_SESSION, + 0)); + if (NULL == pSmeConfigParams) { + sms_log(pMac, LOGE, + "Empty config param structure for SME, nothing to update"); + return status; + } + + status = + csr_change_default_config_param(pMac, &pSmeConfigParams->csrConfig); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_change_default_config_param failed with status=%d", + status); + } +#if defined WLAN_FEATURE_VOWIFI + status = + rrm_change_default_config_param(hHal, &pSmeConfigParams->rrmConfig); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "rrm_change_default_config_param failed with status=%d", + status); + } +#endif + /* For SOC, CFG is set before start */ + /* We don't want to apply global CFG in connect state because that may cause some side affect */ + if (csr_is_all_session_disconnected(pMac)) { + csr_set_global_cfgs(pMac); + } + + /* + * If scan offload is enabled then lim has allow the sending of + * scan request to firmware even in powersave mode. The firmware has + * to take care of exiting from power save mode + */ + status = sme_cfg_set_int(hHal, WNI_CFG_SCAN_IN_POWERSAVE, true); + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Could not pass on WNI_CFG_SCAN_IN_POWERSAVE to CFG"); + } + pMac->isCoalesingInIBSSAllowed = + pSmeConfigParams->csrConfig.isCoalesingInIBSSAllowed; + + /* update p2p offload status */ + pMac->pnoOffload = pSmeConfigParams->pnoOffload; + + pMac->fEnableDebugLog = pSmeConfigParams->fEnableDebugLog; + + /* update interface configuration */ + pMac->sme.max_intf_count = pSmeConfigParams->max_intf_count; + + pMac->enable5gEBT = pSmeConfigParams->enable5gEBT; + pMac->sme.enableSelfRecovery = pSmeConfigParams->enableSelfRecovery; + + pMac->f_sta_miracast_mcc_rest_time_val = + pSmeConfigParams->f_sta_miracast_mcc_rest_time_val; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pMac->sap.sap_channel_avoidance = + pSmeConfigParams->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + pMac->f_prefer_non_dfs_on_radar = + pSmeConfigParams->f_prefer_non_dfs_on_radar; + + pMac->sme.ps_global_info.ps_enabled = + pSmeConfigParams->is_ps_enabled; + + pMac->policy_manager_enabled = pSmeConfigParams->policy_manager_enabled; + pMac->fine_time_meas_cap = pSmeConfigParams->fine_time_meas_cap; + pMac->dual_mac_feature_disable = + pSmeConfigParams->dual_mac_feature_disable; + + return status; +} + +/** + * sme_update_roam_params() - Store/Update the roaming params + * @hal: Handle for Hal layer + * @session_id: SME Session ID + * @roam_params_src: The source buffer to copy + * @update_param: Type of parameter to be updated + * + * Return: Return the status of the updation. + */ +CDF_STATUS sme_update_roam_params(tHalHandle hal, + uint8_t session_id, struct roam_ext_params roam_params_src, + int update_param) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct roam_ext_params *roam_params_dst; + uint8_t i; + + roam_params_dst = &mac_ctx->roam.configParam.roam_params; + switch (update_param) { + case REASON_ROAM_EXT_SCAN_PARAMS_CHANGED: + roam_params_dst->raise_rssi_thresh_5g = + roam_params_src.raise_rssi_thresh_5g; + roam_params_dst->drop_rssi_thresh_5g = + roam_params_src.drop_rssi_thresh_5g; + roam_params_dst->raise_factor_5g = + roam_params_src.raise_factor_5g; + roam_params_dst->drop_factor_5g = + roam_params_src.drop_factor_5g; + roam_params_dst->max_raise_rssi_5g = + roam_params_src.max_raise_rssi_5g; + roam_params_dst->max_drop_rssi_5g = + roam_params_src.max_drop_rssi_5g; + roam_params_dst->alert_rssi_threshold = + roam_params_src.alert_rssi_threshold; + roam_params_dst->is_5g_pref_enabled = true; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + cdf_mem_set(&roam_params_dst->ssid_allowed_list, 0, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); + roam_params_dst->num_ssid_allowed_list = + roam_params_src.num_ssid_allowed_list; + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + roam_params_dst->ssid_allowed_list[i].length = + roam_params_src.ssid_allowed_list[i].length; + cdf_mem_copy(roam_params_dst->ssid_allowed_list[i].ssId, + roam_params_src.ssid_allowed_list[i].ssId, + roam_params_dst->ssid_allowed_list[i].length); + } + break; + case REASON_ROAM_SET_FAVORED_BSSID: + cdf_mem_set(&roam_params_dst->bssid_favored, 0, + sizeof(tSirMacAddr) * MAX_BSSID_FAVORED); + roam_params_dst->num_bssid_favored = + roam_params_src.num_bssid_favored; + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + cdf_mem_copy(&roam_params_dst->bssid_favored[i], + &roam_params_src.bssid_favored[i], + sizeof(tSirMacAddr)); + roam_params_dst->bssid_favored_factor[i] = + roam_params_src.bssid_favored_factor[i]; + } + break; + case REASON_ROAM_SET_BLACKLIST_BSSID: + cdf_mem_set(&roam_params_dst->bssid_avoid_list, 0, + sizeof(tSirMacAddr) * MAX_BSSID_AVOID_LIST); + roam_params_dst->num_bssid_avoid_list = + roam_params_src.num_bssid_avoid_list; + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + cdf_mem_copy(&roam_params_dst->bssid_avoid_list[i], + &roam_params_src.bssid_avoid_list[i], + sizeof(tSirMacAddr)); + } + break; + case REASON_ROAM_GOOD_RSSI_CHANGED: + roam_params_dst->good_rssi_roam = + roam_params_src.good_rssi_roam; + break; + default: + break; + } + csr_roam_offload_scan(mac_ctx, session_id, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + update_param); + return 0; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +void sme_process_get_gtk_info_rsp(tHalHandle hHal, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + if (pMac->sme.gtk_offload_get_info_cb == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return; + } + pMac->sme.gtk_offload_get_info_cb( + pMac->sme.gtk_offload_get_info_cb_context, + pGtkOffloadGetInfoRsp); +} +#endif + +/*-------------------------------------------------------------------------- + + \fn - sme_process_ready_to_suspend + \brief - On getting ready to suspend indication, this function calls + callback registered (HDD callbacks) with SME to inform + ready to suspend indication. + + \param hHal - Handle returned by mac_open. + pReadyToSuspend - Parameter received along with ready to suspend + indication from WMA. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +void sme_process_ready_to_suspend(tHalHandle hHal, + tpSirReadyToSuspendInd pReadyToSuspend) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + + if (NULL != pMac->readyToSuspendCallback) { + pMac->readyToSuspendCallback(pMac->readyToSuspendContext, + pReadyToSuspend->suspended); + pMac->readyToSuspendCallback = NULL; + } +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/*-------------------------------------------------------------------------- + + \fn - sme_process_ready_to_ext_wo_w + \brief - On getting ready to Ext WoW indication, this function calls + callback registered (HDD callbacks) with SME to inform + ready to ExtWoW indication. + + \param hHal - Handle returned by mac_open. + pReadyToExtWoW - Parameter received along with ready to Ext WoW + indication from WMA. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +void sme_process_ready_to_ext_wo_w(tHalHandle hHal, + tpSirReadyToExtWoWInd pReadyToExtWoW) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + + if (NULL != pMac->readyToExtWoWCallback) { + pMac->readyToExtWoWCallback(pMac->readyToExtWoWContext, + pReadyToExtWoW->status); + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + } + +} +#endif + +/* --------------------------------------------------------------------------- + \fn sme_change_config_params + \brief The SME API exposed for HDD to provide config params to SME during + SMEs stop -> start sequence. + + If HDD changed the domain that will cause a reset. This function will + provide the new set of 11d information for the new domain. Currrently this + API provides info regarding 11d only at reset but we can extend this for + other params (PMC, QoS) which needs to be initialized again at reset. + + This is a synchronous call + + \param hHal - The handle returned by mac_open. + + \Param + pUpdateConfigParam - a pointer to a structure (tCsrUpdateConfigParam) that + currently provides 11d related information like Country code, + Regulatory domain, valid channel list, Tx power per channel, a + list with active/passive scan allowed per valid channel. + + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_change_config_params(tHalHandle hHal, + tCsrUpdateConfigParam *pUpdateConfigParam) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pUpdateConfigParam) { + sms_log(pMac, LOGE, + "Empty config param structure for SME, nothing to reset"); + return status; + } + + status = csr_change_config_params(pMac, pUpdateConfigParam); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, "csrUpdateConfigParam failed with status=%d", + status); + } + + return status; + +} + +/*-------------------------------------------------------------------------- + + \brief sme_hdd_ready_ind() - SME sends eWNI_SME_SYS_READY_IND to PE to inform + that the NIC is ready tio run. + + The function is called by HDD at the end of initialization stage so PE/HAL can + enable the NIC to running state. + + This is a synchronous call + \param hHal - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS - eWNI_SME_SYS_READY_IND is sent to PE + successfully. + + Other status means SME failed to send the message to PE. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_hdd_ready_ind(tHalHandle hHal) +{ + tSirSmeReadyReq Msg; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, NO_SESSION, 0)); + do { + + Msg.messageType = eWNI_SME_SYS_READY_IND; + Msg.length = sizeof(tSirSmeReadyReq); + Msg.add_bssdescr_cb = csr_scan_process_single_bssdescr; + + + if (eSIR_FAILURE != u_mac_post_ctrl_msg(hHal, (tSirMbMsg *) &Msg)) { + status = CDF_STATUS_SUCCESS; + } else { + sms_log(pMac, LOGE, + "u_mac_post_ctrl_msg failed to send eWNI_SME_SYS_READY_IND"); + break; + } + + status = csr_ready(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_ready failed with status=%d", + status); + break; + } + +#if defined WLAN_FEATURE_VOWIFI + if (CDF_STATUS_SUCCESS != rrm_ready(hHal)) { + status = CDF_STATUS_E_FAILURE; + sms_log(pMac, LOGE, "rrm_ready failed"); + break; + } +#endif + pMac->sme.state = SME_STATE_READY; + } while (0); + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_start() - Put all SME modules at ready state. + + The function starts each module in SME, PMC, CSR, etc. . Upon + successfully return, all modules are ready to run. + This is a synchronous call + \param hHal - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS - SME is ready. + + Other status means SME is failed to start + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_start(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + status = csr_start(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_start failed during smeStart with status=%d", + status); + break; + } + +#ifndef WLAN_FEATURE_MBSSID + status = wlansap_start(cds_get_global_context()); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "wlansap_start failed during smeStart with status=%d", + status); + break; + } +#endif + + pMac->sme.state = SME_STATE_START; + } while (0); + + return status; +} + +/** + * sme_handle_scan_req() - Scan request handler + * @mac_ctx: MAC global context + * @msg: message buffer + * + * Scan request message from upper layer is handled as + * part of this API + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_handle_scan_req(tpAniSirGlobal mac_ctx, + void *msg) +{ + struct ani_scan_req *scan_msg; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint16_t session_id; + csr_scan_completeCallback callback; + + scan_msg = msg; + session_id = scan_msg->session_id; + callback = scan_msg->callback; + status = csr_scan_request(mac_ctx, session_id, + scan_msg->scan_param, + callback, scan_msg->ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("scan request failed. session_id %d"), session_id); + } + csr_scan_free_request(mac_ctx, scan_msg->scan_param); + return status; +} + +/** + * sme_handle_roc_req() - Roc request handler + * @mac_ctx: MAC global context + * @msg: message buffer + * + * Roc request message from upper layer is handled as + * part of this API + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_handle_roc_req(tHalHandle hal, + void *msg) +{ + struct ani_roc_req *roc_msg; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + remainOnChanCallback callback; + + if (msg == NULL) { + sms_log(mac_ctx, LOGE, FL("ROC request is NULL")); + return status; + } + + roc_msg = msg; + callback = roc_msg->callback; + status = p2p_remain_on_channel(hal, roc_msg->session_id, + roc_msg->channel, roc_msg->duration, callback, + roc_msg->ctx, roc_msg->is_p2pprobe_allowed, + roc_msg->scan_id); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("scan request failed. session_id %d scan_id %d"), + roc_msg->session_id, roc_msg->scan_id); + } + return status; +} + +#ifdef WLAN_FEATURE_11W +/*------------------------------------------------------------------ + * + * Handle the unprotected management frame indication from LIM and + * forward it to HDD. + * + *------------------------------------------------------------------*/ + +CDF_STATUS sme_unprotected_mgmt_frm_ind(tHalHandle hHal, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo pRoamInfo = { 0 }; + uint32_t SessionId = pSmeMgmtFrm->sessionId; + + pRoamInfo.nFrameLength = pSmeMgmtFrm->frameLen; + pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf; + pRoamInfo.frameType = pSmeMgmtFrm->frameType; + + /* forward the mgmt frame to HDD */ + csr_roam_call_callback(pMac, SessionId, &pRoamInfo, 0, + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, 0); + + return status; +} +#endif + +/*------------------------------------------------------------------ + * + * Handle the DFS Radar Event and indicate it to the SAP + * + *------------------------------------------------------------------*/ +CDF_STATUS dfs_msg_processor(tpAniSirGlobal pMac, uint16_t msgType, void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo = { 0 }; + tSirSmeDfsEventInd *dfs_event; + tSirSmeCSAIeTxCompleteRsp *csaIeTxCompleteRsp; + uint32_t sessionId = 0; + eRoamCmdStatus roamStatus; + eCsrRoamResult roamResult; + int i; + + switch (msgType) { + case eWNI_SME_DFS_RADAR_FOUND: + { + /* Radar found !! */ + dfs_event = (tSirSmeDfsEventInd *) pMsgBuf; + if (NULL == dfs_event) { + sms_log(pMac, LOGE, + "%s: pMsg is NULL for eWNI_SME_DFS_RADAR_FOUND message", + __func__); + return CDF_STATUS_E_FAILURE; + } + sessionId = dfs_event->sessionId; + roamInfo.dfs_event.sessionId = sessionId; + roamInfo.dfs_event.chan_list.nchannels = + dfs_event->chan_list.nchannels; + for (i = 0; i < dfs_event->chan_list.nchannels; i++) { + roamInfo.dfs_event.chan_list.channels[i] = + dfs_event->chan_list.channels[i]; + } + + roamInfo.dfs_event.dfs_radar_status = + dfs_event->dfs_radar_status; + roamInfo.dfs_event.use_nol = dfs_event->use_nol; + + roamStatus = eCSR_ROAM_DFS_RADAR_IND; + roamResult = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Radar indication event occurred"); + break; + } + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + { + csaIeTxCompleteRsp = + (tSirSmeCSAIeTxCompleteRsp *) pMsgBuf; + if (NULL == csaIeTxCompleteRsp) { + sms_log(pMac, LOGE, + "%s: pMsg is NULL for eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND", + __func__); + return CDF_STATUS_E_FAILURE; + } + sessionId = csaIeTxCompleteRsp->sessionId; + roamStatus = eCSR_ROAM_DFS_CHAN_SW_NOTIFY; + roamResult = eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND for session id [%d]", + sessionId); + break; + } + default: + { + sms_log(pMac, LOG1, "%s: Invalid DFS message = 0x%x", + __func__, msgType); + status = CDF_STATUS_E_FAILURE; + return status; + } + } + + /* Indicate Radar Event to SAP */ + csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + roamStatus, roamResult); + return status; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/*------------------------------------------------------------------ + * + * Handle the tsm ie indication from LIM and forward it to HDD. + * + *------------------------------------------------------------------*/ +CDF_STATUS sme_tsm_ie_ind(tHalHandle hHal, tSirSmeTsmIEInd *pSmeTsmIeInd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo pRoamInfo = { 0 }; + uint32_t SessionId = pSmeTsmIeInd->sessionId; + pRoamInfo.tsmIe.tsid = pSmeTsmIeInd->tsmIe.tsid; + pRoamInfo.tsmIe.state = pSmeTsmIeInd->tsmIe.state; + pRoamInfo.tsmIe.msmt_interval = pSmeTsmIeInd->tsmIe.msmt_interval; + /* forward the tsm ie information to HDD */ + csr_roam_call_callback(pMac, + SessionId, &pRoamInfo, 0, eCSR_ROAM_TSM_IE_IND, 0); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_cckm_ie + \brief function to store the CCKM IE passed from supplicant and use + it while packing reassociation request + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param pCckmIe - pointer to CCKM IE data + \param pCckmIeLen - length of the CCKM IE + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_cckm_ie(tHalHandle hHal, uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_set_cckm_ie(pMac, sessionId, pCckmIe, cckmIeLen); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_ese_beacon_request + \brief function to set ESE beacon request parameters + \param hHal - HAL handle for device + \param sessionId - Session id + \param pEseBcnReq - pointer to ESE beacon request + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq) +{ + CDF_STATUS status = eSIR_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpSirBeaconReportReqInd pSmeBcnReportReq = NULL; + tCsrEseBeaconReqParams *pBeaconReq = NULL; + uint8_t counter = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (pSmeRrmContext->eseBcnReqInProgress == true) { + sms_log(pMac, LOGE, + "A Beacon Report Req is already in progress"); + return CDF_STATUS_E_RESOURCES; + } + + /* Store the info in RRM context */ + cdf_mem_copy(&pSmeRrmContext->eseBcnReqInfo, pEseBcnReq, + sizeof(tCsrEseBeaconReq)); + + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = cdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + sms_log(pMac, LOGP, + "Memory Allocation Failure!!! ESE BcnReq Ind to SME"); + return CDF_STATUS_E_NOMEM; + } + + pSmeRrmContext->eseBcnReqInProgress = true; + + sms_log(pMac, LOGE, "Sending Beacon Report Req to SME"); + cdf_mem_zero(pSmeBcnReportReq, sizeof(tSirBeaconReportReqInd)); + + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + cdf_mem_copy(pSmeBcnReportReq->bssId, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->channelInfo.channelNum = 255; + pSmeBcnReportReq->channelList.numChannels = pEseBcnReq->numBcnReqIe; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_ESE_UPLOAD; + + for (counter = 0; counter < pEseBcnReq->numBcnReqIe; counter++) { + pBeaconReq = + (tCsrEseBeaconReqParams *) &pEseBcnReq->bcnReq[counter]; + pSmeBcnReportReq->fMeasurementtype[counter] = + pBeaconReq->scanMode; + pSmeBcnReportReq->measurementDuration[counter] = + SYS_TU_TO_MS(pBeaconReq->measurementDuration); + pSmeBcnReportReq->channelList.channelNumber[counter] = + pBeaconReq->channel; + } + + status = sme_rrm_process_beacon_report_req_ind(pMac, pSmeBcnReportReq); + + if (status != CDF_STATUS_SUCCESS) + pSmeRrmContext->eseBcnReqInProgress = false; + + return status; +} + +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +/** + * sme_process_fw_mem_dump_rsp - process fw memory dump response from WMA + * + * @mac_ctx: pointer to MAC handle. + * @msg: pointer to received SME msg. + * + * This function process the received SME message and calls the corresponding + * callback which was already registered with SME. + * + * Return: None + */ +#ifdef WLAN_FEATURE_MEMDUMP +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ + if (msg->bodyptr) { + if (mac_ctx->sme.fw_dump_callback) + mac_ctx->sme.fw_dump_callback(mac_ctx->hHdd, + (struct fw_dump_rsp *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + } +} +#else +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ +} +#endif + +/** + * sme_process_dual_mac_config_resp() - Process set Dual mac config response + * @mac: Global MAC pointer + * @msg: Dual mac config response + * + * Processes the dual mac configuration response and invokes the HDD callback + * to process further + */ +static CDF_STATUS sme_process_dual_mac_config_resp(tpAniSirGlobal mac, + uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + dual_mac_cb callback = NULL; + struct sir_dual_mac_config_resp *param; + + param = (struct sir_dual_mac_config_resp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("Dual mac config resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return CDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_dual_mac_config != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return CDF_STATUS_E_FAILURE; + } + + callback = command->u.set_dual_mac_cmd.set_dual_mac_cb; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed-Dual mac config is NULL")); + } else { + sms_log(mac, LOG1, + FL("Calling HDD callback for Dual mac config")); + callback(param->status, + command->u.set_dual_mac_cmd.scan_config, + command->u.set_dual_mac_cmd.fw_mode_config); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exist")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + sme_release_command(mac, command); + + sme_process_pending_queue(mac); + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + + \brief sme_process_msg() - The main message processor for SME. + + The function is called by a message dispatcher when to process a message + targeted for SME. + + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param pMsg - A pointer to a caller allocated object of tSirMsgQ. + + \return CDF_STATUS_SUCCESS - SME successfully process the message. + + Other status means SME failed to process the message to HAL. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMsg == NULL) { + sms_log(pMac, LOGE, "Empty message for SME"); + return status; + } + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, FL("Locking failed, bailing out")); + if (pMsg->bodyptr) + cdf_mem_free(pMsg->bodyptr); + return status; + } + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGW, FL("message type %d in stop state ignored"), + pMsg->type); + if (pMsg->bodyptr) + cdf_mem_free(pMsg->bodyptr); + goto release_lock; + } + switch (pMsg->type) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eWNI_SME_ROAM_OFFLOAD_SYNCH_IND: + csr_process_roam_offload_synch_ind(pMac, + (roam_offload_synch_ind *) pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_HO_FAIL_IND: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("LFR3: Rcvd eWNI_SME_HO_FAIL_IND")); + csr_process_ho_fail_ind(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_PMC_SMPS_STATE_IND: + break; + case WNI_CFG_SET_CNF: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_GET_RSP: + case WNI_CFG_ADD_GRP_ADDR_CNF: + case WNI_CFG_DEL_GRP_ADDR_CNF: + break; + case eWNI_SME_ADDTS_RSP: + case eWNI_SME_DELTS_RSP: + case eWNI_SME_DELTS_IND: +#ifdef WLAN_FEATURE_VOWIFI_11R + case eWNI_SME_FT_AGGR_QOS_RSP: +#endif + /* QoS */ + if (pMsg->bodyptr) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); +#endif + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#if defined WLAN_FEATURE_VOWIFI + case eWNI_SME_NEIGHBOR_REPORT_IND: + case eWNI_SME_BEACON_REPORT_REQ_IND: +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, FL("Received RRM message. Message Id = %d"), + pMsg->type); +#endif + if (pMsg->bodyptr) { + status = sme_rrm_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_OEM_DATA_SUPPORT + /* Handle the eWNI_SME_OEM_DATA_RSP: */ + case eWNI_SME_OEM_DATA_RSP: + if (pMsg->bodyptr) { + status = sme_handle_oem_data_rsp(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + sme_process_pending_queue(pMac); + break; +#endif + case eWNI_SME_ADD_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_add_sta_session_rsp(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_DEL_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_del_sta_session_rsp(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_REMAIN_ON_CHN_RSP: + if (pMsg->bodyptr) { + status = sme_remain_on_chn_rsp(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_REMAIN_ON_CHN_RDY_IND: + if (pMsg->bodyptr) { + status = sme_remain_on_chn_ready(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_MGMT_FRM_IND: + if (pMsg->bodyptr) { + sme_mgmt_frm_ind(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_ACTION_FRAME_SEND_CNF: + if (pMsg->bodyptr) { + status = sme_send_action_cnf(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef FEATURE_WLAN_SCAN_PNO + case eWNI_SME_PREF_NETWORK_FOUND_IND: + if (pMsg->bodyptr) { + status = sme_preferred_network_found_ind((void *)pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ + case eWNI_SME_CHANGE_COUNTRY_CODE: + if (pMsg->bodyptr) { + status = sme_handle_change_country_code((void *)pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE: + if (pMsg->bodyptr) { + status = sme_handle_generic_change_country_code( + (void *)pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_SCAN_CMD: + if (pMsg->bodyptr) { + status = sme_handle_scan_req(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_ROC_CMD: + if (pMsg->bodyptr) { + status = sme_handle_roc_req(hHal, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef FEATURE_WLAN_TDLS + /* + * command rescived from PE, SME tdls msg processor shall be called + * to process commands recieved from PE + */ + case eWNI_SME_TDLS_SEND_MGMT_RSP: + case eWNI_SME_TDLS_ADD_STA_RSP: + case eWNI_SME_TDLS_DEL_STA_RSP: + case eWNI_SME_TDLS_DEL_STA_IND: + case eWNI_SME_TDLS_DEL_ALL_PEER_IND: + case eWNI_SME_MGMT_FRM_TX_COMPLETION_IND: + case eWNI_SME_TDLS_LINK_ESTABLISH_RSP: + case eWNI_SME_TDLS_SHOULD_DISCOVER: + case eWNI_SME_TDLS_SHOULD_TEARDOWN: + case eWNI_SME_TDLS_PEER_DISCONNECTED: + if (pMsg->bodyptr) { + status = tdls_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef WLAN_FEATURE_11W + case eWNI_SME_UNPROT_MGMT_FRM_IND: + if (pMsg->bodyptr) { + sme_unprotected_mgmt_frm_ind(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eWNI_SME_TSM_IE_IND: + if (pMsg->bodyptr) { + sme_tsm_ie_ind(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + case eWNI_SME_ROAM_SCAN_OFFLOAD_RSP: + status = csr_roam_offload_scan_rsp_hdlr((void *)pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + case eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP: + if (pMsg->bodyptr) { + sme_process_get_gtk_info_rsp(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_LPHB + /* LPHB timeout indication arrived, send IND to client */ + case eWNI_SME_LPHB_IND: + if (pMac->sme.pLphbIndCb) + pMac->sme.pLphbIndCb(pMac->hHdd, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; +#endif /* FEATURE_WLAN_LPHB */ + + case eWNI_SME_READY_TO_SUSPEND_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_suspend(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case eWNI_SME_READY_TO_EXTWOW_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_ext_wo_w(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + /* channel avoid message arrived, send IND to client */ + case eWNI_SME_CH_AVOID_IND: + if (pMac->sme.pChAvoidNotificationCb) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("CH avoid notification")); + pMac->sme.pChAvoidNotificationCb(pMac->hHdd, + pMsg->bodyptr); + } + cdf_mem_free(pMsg->bodyptr); + break; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case eWNI_SME_AUTO_SHUTDOWN_IND: + if (pMac->sme.pAutoShutdownNotificationCb) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Auto shutdown notification")); + pMac->sme.pAutoShutdownNotificationCb(); + } + cdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_DFS_RADAR_FOUND: + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + status = dfs_msg_processor(pMac, pMsg->type, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CHANNEL_CHANGE_RSP: + if (pMsg->bodyptr) { + status = sme_process_channel_change_resp(pMac, + pMsg->type, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef WLAN_FEATURE_STATS_EXT + case eWNI_SME_STATS_EXT_EVENT: + if (pMsg->bodyptr) { + status = sme_stats_ext_event(hHal, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif + case eWNI_SME_LINK_SPEED_IND: + if (pMac->sme.pLinkSpeedIndCb) + pMac->sme.pLinkSpeedIndCb(pMsg->bodyptr, + pMac->sme.pLinkSpeedCbContext); + if (pMsg->bodyptr) + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CSA_OFFLOAD_EVENT: + if (pMsg->bodyptr) { + csr_scan_flush_bss_entry(pMac, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } + break; +#ifdef WLAN_FEATURE_NAN + case eWNI_SME_NAN_EVENT: + if (pMsg->bodyptr) { + sme_nan_event(hHal, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } + break; +#endif /* WLAN_FEATURE_NAN */ + case eWNI_SME_LINK_STATUS_IND: + { + tAniGetLinkStatus *pLinkStatus = + (tAniGetLinkStatus *) pMsg->bodyptr; + if (pLinkStatus) { + if (pMac->sme.linkStatusCallback) { + pMac->sme.linkStatusCallback( + pLinkStatus->linkStatus, + pMac->sme.linkStatusContext); + } + pMac->sme.linkStatusCallback = NULL; + pMac->sme.linkStatusContext = NULL; + cdf_mem_free(pLinkStatus); + } + break; + } + case eWNI_SME_MSG_GET_TEMPERATURE_IND: + if (pMac->sme.pGetTemperatureCb) { + pMac->sme.pGetTemperatureCb(pMsg->bodyval, + pMac->sme.pTemperatureCbContext); + } + break; + case eWNI_SME_SNR_IND: + { + tAniGetSnrReq *pSnrReq = (tAniGetSnrReq *) pMsg->bodyptr; + if (pSnrReq) { + if (pSnrReq->snrCallback) { + ((tCsrSnrCallback) + (pSnrReq->snrCallback)) + (pSnrReq->snr, pSnrReq->staId, + pSnrReq->pDevContext); + } + cdf_mem_free(pSnrReq); + } + break; + } +#ifdef FEATURE_WLAN_EXTSCAN + case eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND: + if (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + pMsg->bodyptr); + else + sms_log(pMac, LOGE, + FL("callback not registered to process %d"), + pMsg->type); + + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_EPNO_NETWORK_FOUND_IND: + if (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EPNO_NETWORK_FOUND_IND, + pMsg->bodyptr); + else + sms_log(pMac, LOGE, + FL("callback not registered to process %d"), + pMsg->type); + + cdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_FW_DUMP_IND: + sme_process_fw_mem_dump_rsp(pMac, pMsg); + break; + case eWNI_SME_SET_HW_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_set_hw_mode_resp(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_HW_MODE_TRANS_IND: + if (pMsg->bodyptr) { + status = sme_process_hw_mode_trans_ind(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_NSS_UPDATE_RSP: + if (pMsg->bodyptr) { + status = sme_process_nss_update_resp(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_OCB_SET_CONFIG_RSP: + if (pMac->sme.ocb_set_config_callback) { + pMac->sme.ocb_set_config_callback( + pMac->sme.ocb_set_config_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.ocb_set_config_callback = NULL; + pMac->sme.ocb_set_config_context = NULL; + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_OCB_GET_TSF_TIMER_RSP: + if (pMac->sme.ocb_get_tsf_timer_callback) { + pMac->sme.ocb_get_tsf_timer_callback( + pMac->sme.ocb_get_tsf_timer_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.ocb_get_tsf_timer_callback = NULL; + pMac->sme.ocb_get_tsf_timer_context = NULL; + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_GET_STATS_RSP: + if (pMac->sme.dcc_get_stats_callback) { + pMac->sme.dcc_get_stats_callback( + pMac->sme.dcc_get_stats_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.dcc_get_stats_callback = NULL; + pMac->sme.dcc_get_stats_context = NULL; + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_UPDATE_NDL_RSP: + if (pMac->sme.dcc_update_ndl_callback) { + pMac->sme.dcc_update_ndl_callback( + pMac->sme.dcc_update_ndl_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.dcc_update_ndl_callback = NULL; + pMac->sme.dcc_update_ndl_context = NULL; + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_STATS_EVENT: + if (pMac->sme.dcc_stats_event_callback) { + pMac->sme.dcc_stats_event_callback( + pMac->sme.dcc_stats_event_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + cdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_RESP: + if (pMsg->bodyptr) { + status = sme_process_dual_mac_config_resp(pMac, + pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + case eWNI_SME_SET_THERMAL_LEVEL_IND: + if (pMac->sme.set_thermal_level_cb) + pMac->sme.set_thermal_level_cb(pMac->hHdd, + pMsg->bodyval); + break; + default: + + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + /* CSR */ + if (pMsg->bodyptr) { + status = csr_msg_processor(hHal, pMsg->bodyptr); + cdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + } else { + sms_log(pMac, LOGW, FL("Unknown message type %d"), + pMsg->type); + if (pMsg->bodyptr) + cdf_mem_free(pMsg->bodyptr); + } + } /* switch */ +release_lock: + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_process_nss_update_resp() - Process nss update response + * @mac: Global MAC pointer + * @msg: nss update response + * + * Processes the nss update response and invokes the HDD + * callback to process further + */ +CDF_STATUS sme_process_nss_update_resp(tpAniSirGlobal mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + nss_update_cb callback = NULL; + struct sir_beacon_tx_complete_rsp *param; + + param = (struct sir_beacon_tx_complete_rsp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("nss update resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return CDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (e_sme_command_nss_update != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return CDF_STATUS_E_FAILURE; + } + + callback = command->u.nss_update_cmd.nss_update_cb; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed since nss update params is NULL")); + } else { + sms_log(mac, LOGE, + FL("Calling HDD callback for nss update response")); + callback(command->u.nss_update_cmd.context, + param->tx_status, + param->session_id, + command->u.nss_update_cmd.next_action); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exisit")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the avilable command list */ + sme_release_command(mac, command); + } + sme_process_pending_queue(mac); + return CDF_STATUS_SUCCESS; +} + +/* No need to hold the global lock here because this function can only be called */ +/* after sme_stop. */ +void sme_free_msg(tHalHandle hHal, cds_msg_t *pMsg) +{ + if (pMsg) { + if (pMsg->bodyptr) { + cdf_mem_free(pMsg->bodyptr); + } + } + +} + +/*-------------------------------------------------------------------------- + + \brief sme_stop() - Stop all SME modules and put them at idle state + + The function stops each module in SME, PMC, CSR, etc. . Upon + return, all modules are at idle state ready to start. + + This is a synchronous call + \param hHal - The handle returned by mac_open + \param tHalStopType - reason for stopping + + \return CDF_STATUS_SUCCESS - SME is stopped. + + Other status means SME is failed to stop but caller should still + consider SME is stopped. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_stop(tHalHandle hHal, tHalStopType stopType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_STATUS fail_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + +#ifndef WLAN_FEATURE_MBSSID + status = wlansap_stop(cds_get_global_context()); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "wlansap_stop failed during smeStop with status=%d", + status); + fail_status = status; + } +#endif + + p2p_stop(hHal); + + status = csr_stop(pMac, stopType); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_stop failed during smeStop with status=%d", status); + fail_status = status; + } + + purge_sme_cmd_list(pMac); + + if (!CDF_IS_STATUS_SUCCESS(fail_status)) { + status = fail_status; + } + + pMac->sme.state = SME_STATE_STOP; + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_close() - Release all SME modules and their resources. + + The function release each module in SME, PMC, CSR, etc. . Upon + return, all modules are at closed state. + + No SME APIs can be involved after smeClose except smeOpen. + smeClose must be called before mac_close. + This is a synchronous call + \param hHal - The handle returned by mac_open + + \return CDF_STATUS_SUCCESS - SME is successfully close. + + Other status means SME is failed to be closed but caller still cannot + call any other SME functions except smeOpen. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_close(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_STATUS fail_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) + return CDF_STATUS_E_FAILURE; + + /* Note: pSession will be invalid from here on, do not access */ + status = csr_close(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_close failed during sme close with status=%d", + status); + fail_status = status; + } +#ifndef WLAN_FEATURE_MBSSID + status = wlansap_close(cds_get_global_context()); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "WLANSAP_close failed during sme close with status=%d", + status); + fail_status = status; + } +#endif + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_close(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "Qos close failed during sme close with status=%d", + status); + fail_status = status; + } +#endif +#ifdef FEATURE_OEM_DATA_SUPPORT + status = oem_data_oem_data_req_close(hHal); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "OEM DATA REQ close failed during sme close with status=%d", + status); + fail_status = status; + } +#endif + status = sme_ps_close(hHal); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "sme_ps_close failed during smeClose status=%d", + status); + fail_status = status; + } + +#if defined WLAN_FEATURE_VOWIFI + status = rrm_close(hHal); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "RRM close failed during sme close with status=%d", + status); + fail_status = status; + } +#endif + + sme_p2p_close(hHal); + + free_sme_cmd_list(pMac); + + if (!CDF_IS_STATUS_SUCCESS + (cdf_mutex_destroy(&pMac->sme.lkSmeGlobalLock))) { + fail_status = CDF_STATUS_E_FAILURE; + } + + if (!CDF_IS_STATUS_SUCCESS(fail_status)) { + status = fail_status; + } + + pMac->sme.state = SME_STATE_STOP; + + return status; +} + +/** + * sme_scan_request() - wrapper function to Request a 11d or full scan from CSR. + * @hal: hal global context + * @session_id: session id + * @scan_req: scan req + * @callback: a callback function that scan calls upon finish, will not + * be called if csr_scan_request returns error + * @ctx: a pointer passed in for the callback + * + * This is a wrapper function to Request a 11d or full scan from CSR. This is + * an asynchronous call + * + * Return: Status of operation + */ +CDF_STATUS sme_scan_request(tHalHandle hal, uint8_t session_id, + tCsrScanRequest *scan_req, + csr_scan_completeCallback callback, void *ctx) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct ani_scan_req *scan_msg; + cds_msg_t msg; + uint32_t scan_req_id, scan_count; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, session_id, + scan_req->scanType)); + if (!mac_ctx->scan.fScanEnable) { + sms_log(mac_ctx, LOGE, FL("fScanEnable false")); + return status; + } + + scan_count = csr_ll_count(&mac_ctx->sme.smeScanCmdActiveList); + if (scan_count >= mac_ctx->scan.max_scan_count) { + sms_log(mac_ctx, LOGE, FL("Max scan reached")); + return CDF_STATUS_E_FAILURE; + } + wma_get_scan_id(&scan_req_id); + scan_req->scan_id = scan_req_id; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Unable to acquire lock")); + return status; + } + sms_log(mac_ctx, LOG1, FL(" called")); + scan_msg = cdf_mem_malloc(sizeof(struct ani_scan_req)); + if (NULL == scan_msg) { + sms_log(mac_ctx, LOGE, + " scan_req: failed to allocate mem for msg"); + sme_release_global_lock(&mac_ctx->sme); + return CDF_STATUS_E_NOMEM; + } + scan_msg->msg_type = eWNI_SME_SCAN_CMD; + scan_msg->msg_len = (uint16_t) sizeof(struct ani_scan_req); + scan_msg->session_id = session_id; + scan_msg->callback = callback; + scan_msg->ctx = ctx; + scan_msg->scan_param = cdf_mem_malloc(sizeof(tCsrScanRequest)); + if (NULL == scan_msg->scan_param) { + sms_log(mac_ctx, LOGE, + "scan_req:failed to allocate mem for scanreq"); + sme_release_global_lock(&mac_ctx->sme); + cdf_mem_free(scan_msg); + return CDF_STATUS_E_NOMEM; + } + csr_scan_copy_request(mac_ctx, scan_msg->scan_param, scan_req); + msg.type = eWNI_SME_SCAN_CMD; + msg.bodyptr = scan_msg; + msg.reserved = 0; + msg.bodyval = 0; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(mac_ctx, LOGE, + " sme_scan_req failed to post msg"); + csr_scan_free_request(mac_ctx, scan_msg->scan_param); + cdf_mem_free(scan_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_result + \brief a wrapper function to request scan results from CSR. + This is a synchronous call + \param pFilter - If pFilter is NULL, all cached results are returned + \param phResult - an object for the result. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, sessionId, + 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_get_result(hHal, pFilter, phResult); + sme_release_global_lock(&pMac->sme); + } + sms_log(pMac, LOG2, FL("exit status %d"), status); + + return status; +} + +/** + * sme_get_ap_channel_from_scan_cache() - a wrapper function to get AP's + * channel id from CSR by filtering the + * result which matches our roam profile. + * @profile: SAP adapter + * @ap_chnl_id: pointer to channel id of SAP. Fill the value after finding the + * best ap from scan cache. + * + * This function is written to get AP's channel id from CSR by filtering + * the result which matches our roam profile. This is a synchronous call. + * + * Return: CDF_STATUS. + */ +CDF_STATUS sme_get_ap_channel_from_scan_cache(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + tCsrScanResultFilter *scan_filter = NULL; + tScanResultHandle filtered_scan_result = NULL; + tSirBssDescription first_ap_profile; + + if (NULL == mac_ctx) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("mac_ctx is NULL")); + return CDF_STATUS_E_FAILURE; + } + scan_filter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("scan_filter mem alloc failed")); + return CDF_STATUS_E_FAILURE; + } else { + cdf_mem_set(scan_filter, sizeof(tCsrScanResultFilter), 0); + cdf_mem_set(&first_ap_profile, sizeof(tSirBssDescription), 0); + + if (NULL == profile) { + scan_filter->EncryptionType.numEntries = 1; + scan_filter->EncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, + scan_filter); + } + + if (CDF_STATUS_SUCCESS == status) { + /* Save the WPS info */ + if (NULL != profile) { + scan_filter->bWPSAssociation = + profile->bWPSAssociation; + scan_filter->bOSENAssociation = + profile->bOSENAssociation; + } else { + scan_filter->bWPSAssociation = 0; + scan_filter->bOSENAssociation = 0; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Preparing the profile filter failed")); + cdf_mem_free(scan_filter); + return CDF_STATUS_E_FAILURE; + } + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_STATUS_SUCCESS == status) { + status = csr_scan_get_result(hal_handle, scan_filter, + &filtered_scan_result); + if (CDF_STATUS_SUCCESS == status) { + csr_get_bssdescr_from_scan_handle(filtered_scan_result, + &first_ap_profile); + *scan_cache = filtered_scan_result; + if (0 != first_ap_profile.channelId) { + *ap_chnl_id = first_ap_profile.channelId; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Found best AP & its on chnl[%d]"), + first_ap_profile.channelId); + } else { + /* + * This means scan result is empty + * so set the channel to zero, caller should + * take of zero channel id case. + */ + *ap_chnl_id = 0; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Scan is empty, set chnl to 0")); + status = CDF_STATUS_E_FAILURE; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to get scan get result")); + status = CDF_STATUS_E_FAILURE; + } + csr_free_scan_filter(mac_ctx, scan_filter); + sme_release_global_lock(&mac_ctx->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Aquiring lock failed")); + status = CDF_STATUS_E_FAILURE; + } + + cdf_mem_free(scan_filter); + + return status; +} + +/** + * sme_store_joinreq_param() - This function will pass station's join + * request to store to csr. + * @hal_handle: pointer to hal context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will pass station's join request further down to csr + * to store it. this stored parameter will be used later. + * + * Return: true or false based on function's overall success. + **/ +bool sme_store_joinreq_param(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_STATUS_SUCCESS == status) { + if (false == csr_store_joinreq_param(mac_ctx, profile, + scan_cache, roam_id, session_id)) { + ret_status = false; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_clear_joinreq_param() - This function will pass station's clear + * the join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will pass station's clear join request further down to csr + * to cleanup. + * + * Return: true or false based on function's overall success. + **/ +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_STATUS_SUCCESS == status) { + if (false == csr_clear_joinreq_param(mac_ctx, + session_id)) { + ret_status = false; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_issue_stored_joinreq() - This function will issues station's stored + * the join request to csr. + * @hal_handle: pointer to hal context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request further down to csr + * to proceed forward. + * + * Return: CDF_STATUS_SUCCESS or CDF_STATUS_E_FAILURE. + **/ +CDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_STATUS ret_status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_STATUS_SUCCESS == status) { + if (CDF_STATUS_SUCCESS != csr_issue_stored_joinreq(mac_ctx, + roam_id, + session_id)) { + ret_status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + csr_clear_joinreq_param(mac_ctx, session_id); + ret_status = CDF_STATUS_E_FAILURE; + } + return ret_status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_flush_result + \brief a wrapper function to request CSR to clear scan results. + This is a synchronous call + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_scan_flush_result(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + 0, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_result(hHal); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_filter_scan_results + \brief a wrapper function to request CSR to clear scan results. + This is a synchronous call + \param tHalHandle - HAL context handle + \param sessionId - session id + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_scan_filter_results(pMac); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +CDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_selective_result(hHal, true); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_get_first + \brief a wrapper function to request CSR to returns the first element of + scan result. + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result + \return tCsrScanResultInfo * - NULL if no result + ---------------------------------------------------------------------------*/ +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_first(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_get_next + \brief a wrapper function to request CSR to returns the next element of + scan result. It can be called without calling csr_scan_result_get_first + first + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result + \return Null if no result or reach the end + ---------------------------------------------------------------------------*/ +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_next(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_purge + \brief a wrapper function to request CSR to remove all items(tCsrScanResult) + in the list and free memory for each item + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result. hScanResult is + considered gone by + calling this function and even before this function reutrns. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_scan_result_purge(tHalHandle hHal, tScanResultHandle hScanResult) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_result_purge(hHal, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_pmkid_candidate_list + \brief a wrapper function to return the PMKID candidate list + This is a synchronous call + \param pPmkidList - caller allocated buffer point to an array of + tPmkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of + tPmkidCandidateInfo allocated when retruning, this is + either the number needed or number of items put into + pPmkidList + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems + has the number of tPmkidCandidateInfo. + \Note: pNumItems is a number of tPmkidCandidateInfo, + not sizeof(tPmkidCandidateInfo) * something + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_scan_get_pmkid_candidate_list(tHalHandle hHal, uint8_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + csr_scan_get_pmkid_candidate_list(pMac, sessionId, + pPmkidList, + pNumItems); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.phyMode; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_channel_bonding_mode5_g + \brief get the channel bonding mode for 5G band + \param hHal - HAL handle + \return channel bonding mode for 5G + ---------------------------------------------------------------------------*/ +uint32_t sme_get_channel_bonding_mode5_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeConfigParams smeConfig; + + sme_get_config_param(pMac, &smeConfig); + + return smeConfig.csrConfig.channelBondingMode5GHz; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_channel_bonding_mode24_g + \brief get the channel bonding mode for 2.4G band + \param hHal - HAL handle + \return channel bonding mode for 2.4G + ---------------------------------------------------------------------------*/ +uint32_t sme_get_channel_bonding_mode24_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeConfigParams smeConfig; + + sme_get_config_param(pMac, &smeConfig); + + return smeConfig.csrConfig.channelBondingMode24GHz; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_connect + \brief a wrapper function to request CSR to inititiate an association + This is an asynchronous call. + \param sessionId - the sessionId returned by sme_open_session. + \param pProfile - description of the network to which to connect + \param hBssListIn - a list of BSS descriptor to roam to. It is returned + from csr_scan_get_result + \param pRoamId - to get back the request ID + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, uint32_t *pRoamId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) { + return CDF_STATUS_E_FAILURE; + } + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, sessionId, 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_connect(pMac, sessionId, pProfile, + pRoamId); + } else { + sms_log(pMac, LOGE, FL("invalid sessionID %d"), + sessionId); + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } else { + sms_log(pMac, LOGE, FL("sme_acquire_global_lock failed")); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_phy_mode + + \brief Changes the PhyMode. + + \param hHal - The handle returned by mac_open. + + \param phyMode new phyMode which is to set + + \return CDF_STATUS SUCCESS. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + return CDF_STATUS_E_FAILURE; + } + + pMac->roam.configParam.phyMode = phyMode; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam.phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_reassoc + \brief a wrapper function to request CSR to inititiate a re-association + \param pProfile - can be NULL to join the currently connected AP. In that + case modProfileFields should carry the modified field(s) which could trigger + reassoc + \param modProfileFields - fields which are part of tCsrRoamConnectedProfile + that might need modification dynamically once STA is up & running and this + could trigger a reassoc + \param pRoamId - to get back the request ID + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, sessionId, 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if ((NULL == pProfile) && (fForce == 1)) { + status = + csr_reassoc(pMac, sessionId, + &modProfileFields, pRoamId, + fForce); + } else { + status = + csr_roam_reassoc(pMac, sessionId, pProfile, + modProfileFields, pRoamId); + } + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_connect_to_last_profile + \brief a wrapper function to request CSR to disconnect and reconnect with + the same profile + This is an asynchronous call. + \return CDF_STATUS. It returns fail if currently connected + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_connect_to_last_profile(pMac, sessionId); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_disconnect + \brief a wrapper function to request CSR to disconnect from a network + This is an asynchronous call. + \param reason -- To indicate the reason for disconnecting. Currently, only + eCSR_DISCONNECT_REASON_MIC_ERROR is meanful. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_disconnect(tHalHandle hHal, uint8_t sessionId, + eCsrRoamDisconnectReason reason) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, sessionId, + reason)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_disconnect(pMac, sessionId, reason); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_stop_bss + \brief To stop BSS for Soft AP. This is an asynchronous API. + \param hHal - Global structure + \param sessionId - sessionId of SoftAP + \return CDF_STATUS SUCCESS Roam callback will be called to indicate actual results + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_issue_stop_bss_cmd(pMac, sessionId, true); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_disconnect_sta + \brief To disassociate a station. This is an asynchronous API. + \param hHal - Global structure + \param sessionId - sessionId of SoftAP + \param pPeerMacAddr - Caller allocated memory filled with peer MAC address (6 bytes) + \return CDF_STATUS SUCCESS Roam callback will be called to indicate actual results + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_disconnect_sta(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pPeerMacAddr) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_issue_disassociate_sta_cmd(pMac, + sessionId, pPeerMacAddr, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_deauth_sta() - deauthenticate a station + * @hHal: Global structure + * @sessionId: SessionId of SoftAP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * To disassociate a station. This is an asynchronous API. + * + * Return: CDF_STATUS_SUCCESS on success or another CDF_STATUS error + * code on error. Roam callback will be called to indicate actual + * result + */ +CDF_STATUS sme_roam_deauth_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *pDelStaParams) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_issue_deauth_sta_cmd(pMac, sessionId, + pDelStaParams); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_tkip_counter_measures + \brief To start or stop TKIP counter measures. This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param pPeerMacAddr - Caller allocated memory filled with peer MAC address (6 bytes) + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_tkip_counter_measures(tHalHandle hHal, uint8_t sessionId, + bool bEnable) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_issue_tkip_counter_measures(pMac, sessionId, + bEnable); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_associated_stas + \brief To probe the list of associated stations from various modules + of CORE stack. + \This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param modId - Module from whom list of associtated stations is + to be probed. If an invalid module is passed then + by default CDF_MODULE_ID_PE will be probed. + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pAssocBuf - Caller allocated memory to be filled with associatd + stations info + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + CDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_associated_stas(pMac, sessionId, modId, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_wps_session_overlap + \brief To get the WPS PBC session overlap information. + \This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \pRemoveMac - pointer to Mac address which needs to be removed from session + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_wps_session_overlap(tHalHandle hHal, uint8_t sessionId, + void *pUsrContext, void + *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wps_session_overlap(pMac, sessionId, + pUsrContext, + pfnSapEventCallback, + pRemoveMac); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_connect_state + \brief a wrapper function to request CSR to return the current connect state + of Roaming + This is a synchronous call. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_connect_state(pMac, sessionId, pState); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_connect_profile + \brief a wrapper function to request CSR to return the current connect + profile. Caller must call csr_roam_free_connect_profile after it is done + and before reuse for another csr_roam_get_connect_profile call. + This is a synchronous call. + \param pProfile - pointer to a caller allocated structure + tCsrRoamConnectedProfile + \return CDF_STATUS. Failure if not connected + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_connect_profile(pMac, sessionId, pProfile); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_free_connect_profile + \brief a wrapper function to request CSR to free and reinitialize the + profile returned previously by csr_roam_get_connect_profile. + This is a synchronous call. + \param pProfile - pointer to a caller allocated structure + tCsrRoamConnectedProfile + \return CDF_STATUS. + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_free_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_free_connect_profile(pMac, pProfile); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_set_pmkid_cache + \brief a wrapper function to request CSR to return the PMKID candidate list + This is a synchronous call. + \param pPMKIDCache - caller allocated buffer point to an array of + tPmkidCacheInfo + \param numItems - a variable that has the number of tPmkidCacheInfo + allocated when retruning, this is either the number needed + or number of items put into pPMKIDCache + \param update_entire_cache - this bool value specifies if the entire pmkid + cache should be overwritten or should it be + updated entry by entry. + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems has the number of + tPmkidCacheInfo. + \Note: pNumItems is a number of tPmkidCacheInfo, + not sizeof(tPmkidCacheInfo) * something + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, sessionId, + numItems)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_set_pmkid_cache(pMac, sessionId, pPMKIDCache, + numItems, update_entire_cache); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +CDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBSSId, bool flush_cache) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_del_pmkid_from_cache(pMac, sessionId, + pBSSId, flush_cache); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* --------------------------------------------------------------------------- + * \fn sme_roam_set_psk_pmk + * \brief a wrapper function to request CSR to save PSK/PMK + * This is a synchronous call. + * \param hHal - Global structure + * \param sessionId - SME sessionId + * \param pPSK_PMK - pointer to an array of Psk[]/Pmk + * \param pmk_len - Length could be only 16 bytes in case if LEAP + * connections. Need to pass this information to + * firmware. + * \return CDF_STATUS -status whether PSK/PMK is set or not + *--------------------------------------------------------------------------- + */ +CDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_set_psk_pmk(pMac, sessionId, pPSK_PMK, + pmk_len); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif +/* --------------------------------------------------------------------------- + \fn sme_roam_get_security_req_ie + \brief a wrapper function to request CSR to return the WPA or RSN or WAPI IE CSR + passes to PE to JOIN request or START_BSS request + This is a synchronous call. + \param pLen - caller allocated memory that has the length of pBuf as input. + Upon returned, *pLen has the needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, + upon return + \param secType - Specifies whether looking for WPA/WPA2/WAPI IE + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_security_req_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wpa_rsn_req_ie(hHal, sessionId, pLen, pBuf); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_security_rsp_ie + \brief a wrapper function to request CSR to return the WPA or RSN or + WAPI IE from the beacon or probe rsp if connected + This is a synchronous call. + \param pLen - caller allocated memory that has the length of pBuf as input. + Upon returned, *pLen has the needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, + upon return + \param secType - Specifies whether looking for WPA/WPA2/WAPI IE + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_security_rsp_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wpa_rsn_rsp_ie(pMac, sessionId, pLen, pBuf); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_num_pmkid_cache + \brief a wrapper function to request CSR to return number of PMKID cache + entries + This is a synchronous call. + \return uint32_t - the number of PMKID cache entries + ---------------------------------------------------------------------------*/ +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint32_t numPmkidCache = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + numPmkidCache = + csr_roam_get_num_pmkid_cache(pMac, sessionId); + status = CDF_STATUS_SUCCESS; + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return numPmkidCache; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_pmkid_cache + \brief a wrapper function to request CSR to return PMKID cache from CSR + This is a synchronous call. + \param pNum - caller allocated memory that has the space of the number of + pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the + needed or actually number in tPmkidCacheInfo. + \param pPmkidCache - Caller allocated memory that contains PMKID cache, if + any, upon return + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_pmkid_cache(pMac, sessionId, pNum, + pPmkidCache); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_config_param + \brief a wrapper function that HDD calls to get the global settings + currently maintained by CSR. + This is a synchronous call. + \param pParam - caller allocated memory + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_config_param(pMac, &pParam->csrConfig); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, "%s csr_get_config_param failed", + __func__); + sme_release_global_lock(&pMac->sme); + return status; + } +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pParam->sap_channel_avoidance = pMac->sap.sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + pParam->max_intf_count = pMac->sme.max_intf_count; + pParam->enableSelfRecovery = pMac->sme.enableSelfRecovery; + pParam->f_prefer_non_dfs_on_radar = + pMac->f_prefer_non_dfs_on_radar; + pParam->policy_manager_enabled = pMac->policy_manager_enabled; + pParam->fine_time_meas_cap = pMac->fine_time_meas_cap; + pParam->dual_mac_feature_disable = + pMac->dual_mac_feature_disable; + pParam->is_ps_enabled = pMac->sme.ps_global_info.ps_enabled; + pParam->pnoOffload = pMac->pnoOffload; + pParam->fEnableDebugLog = pMac->fEnableDebugLog; + pParam->enable5gEBT = pMac->enable5gEBT; + pParam->f_sta_miracast_mcc_rest_time_val = + pMac->f_sta_miracast_mcc_rest_time_val; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_cfg_set_int() - Sets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @value: value to be saved in the cfg parameter. + * + * This function sets the string value in cfg parameter. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != cfg_set_int(pmac, cfg_id, value)) + status = CDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_set_str() - Sets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Length of the string. + * + * This function sets the string value in cfg parameter. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != cfg_set_str(pmac, cfg_id, str, length)) + status = CDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_int() - Gets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @cfg_value: Pointer to variable in which cfg value + * will be saved. + * + * This function gets the value of the cfg parameter. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, uint32_t *cfg_value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pmac, cfg_id, cfg_value)) + status = CDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_str() - Gets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Pointer to length of the string. + * + * This function gets the string value of the cfg parameter. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != wlan_cfg_get_str(pmac, cfg_id, str, length)) + status = CDF_STATUS_E_INVAL; + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_modify_profile_fields + \brief HDD or SME - QOS calls this function to get the current values of + connected profile fields, changing which can cause reassoc. + This function must be called after CFG is downloaded and STA is in connected + state. Also, make sure to call this function to get the current profile + fields before calling the reassoc. So that pModifyProfileFields will have + all the latest values plus the one(s) has been updated as part of reassoc + request. + \param pModifyProfileFields - pointer to the connected profile fields + changing which can cause reassoc + + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_get_modify_profile_fields(pMac, sessionId, + pModifyProfileFields); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_dhcp_till_power_active_flag + \brief Sets/Clears DHCP related flag to disable/enable auto PS + \param hal - The handle returned by mac_open. + ---------------------------------------------------------------------------*/ +void sme_set_dhcp_till_power_active_flag(tHalHandle hal, uint8_t flag) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct ps_global_info *ps_global_info = &mac->sme.ps_global_info; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, NO_SESSION, + flag)); + /* Set/Clear the DHCP flag which will disable/enable auto PS */ + ps_global_info->remain_in_power_active_till_dhcp = flag; +} + +/* --------------------------------------------------------------------------- + \fn sme_register11d_scan_done_callback + \brief Register a routine of type csr_scan_completeCallback which is + called whenever an 11d scan is done + \param hHal - The handle returned by mac_open. + \param callback - 11d scan complete routine to be registered + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_register11d_scan_done_callback(tHalHandle hHal, + csr_scan_completeCallback callback) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->scan.callback11dScanDone = callback; + + return status; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_register_oem_data_rsp_callback() - Register a routine of + * type send_oem_data_rsp_msg + * @h_hal: Handle returned by mac_open. + * @callback: Callback to send response + * to oem application. + * + * sme_oem_data_rsp_callback is used to register sme_send_oem_data_rsp_msg + * callback function. + * + * Return: CDF_STATUS. + */ +CDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(h_hal); + + pmac->oemData.oem_data_rsp_callback = callback; + + return status; + +} +#endif + +/** + * sme_register_ftm_msg_processor() - registers hdd ftm message processor + * function to MAC/SYS + * + * @hal: hal handle + * @callback: hdd function that has to be registered + * + * Return: void + */ +void sme_register_ftm_msg_processor(tHalHandle hal, + hdd_ftm_msg_processor callback) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (mac_ctx == NULL) { + sms_log(mac_ctx, LOGE, FL("mac_ctx is NULL")); + return; + } + mac_ctx->ftm_msg_processor_callback = callback; + return; +} + +/** + * sme_wow_add_pattern() - add a wow pattern in fw + * @hHal: handle returned by mac_open + * @pattern: pointer to input pattern + * + * Add a pattern for Pattern Byte Matching in WoW mode. Firmware will + * do a pattern match on these patterns when WoW is enabled during system + * suspend. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_wow_add_pattern(tHalHandle hal, + struct wow_add_pattern *pattern, + uint8_t session_id) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + struct wow_add_pattern *ptrn; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN, session_id, + 0)); + ptrn = cdf_mem_malloc(sizeof(*ptrn)); + if (NULL == ptrn) { + sms_log(pMac, LOGP, + FL("Fail to allocate memory for WoWLAN Add Bcast Pattern ")); + return CDF_STATUS_E_NOMEM; + } + (void)cdf_mem_copy(ptrn, pattern, sizeof(*ptrn)); + + msg_q.type = WMA_WOW_ADD_PTRN; + msg_q.reserved = 0; + msg_q.bodyptr = ptrn; + msg_q.bodyval = 0; + + sms_log(pMac, LOG1, FL("Sending WMA_WOWL_ADD_BCAST_PTRN to HAL")); + ret_code = wma_post_ctrl_msg(pMac, &msg_q); + if (eSIR_SUCCESS != ret_code) { + sms_log(pMac, LOGE, + FL("Posting WMA_WOWL_ADD_BCAST_PTRN failed, reason=%X"), + ret_code); + } + return ret_code; +} + +/** + * sme_wow_delete_pattern() - delete user configured wow pattern in target + * @hHal: handle returned by mac_open. + * @pattern: pointer to delete pattern parameter + * @sessionId: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_wow_delete_pattern(tHalHandle hal, + struct wow_delete_pattern *pattern, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + struct wow_delete_pattern *delete_ptrn; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN, sessionId, + 0)); + delete_ptrn = cdf_mem_malloc(sizeof(*delete_ptrn)); + if (NULL == delete_ptrn) { + sms_log(pMac, LOGP, + FL("Fail to allocate memory for WoWLAN Delete Bcast Pattern ")); + return CDF_STATUS_E_NOMEM; + } + (void)cdf_mem_copy(delete_ptrn, pattern, sizeof(*delete_ptrn)); + msg_q.type = WMA_WOW_DEL_PTRN; + msg_q.reserved = 0; + msg_q.bodyptr = delete_ptrn; + msg_q.bodyval = 0; + + sms_log(pMac, LOG1, FL("Sending WMA_WOWL_DEL_BCAST_PTRN")); + + ret_code = wma_post_ctrl_msg(pMac, &msg_q); + if (eSIR_SUCCESS != ret_code) { + sms_log(pMac, LOGE, + FL("Posting WMA_WOWL_DEL_BCAST_PTRN failed, reason=%X"), + ret_code); + } + return ret_code; +} + +/** + * sme_enter_wowl(): SME API exposed to HDD to request enabling of WOWL mode. + * @hal_ctx - The handle returned by mac_open. + * @enter_wowl_callback_routine - Callback routine provided by HDD. + * Used for success/failure notification by SME + * @enter_wowl_callback_context - A cookie passed by HDD, that is passed + * back to HDD at the time of callback. + * @wake_reason_ind_cb - Callback routine provided by HDD. + * Used for Wake Reason Indication by SME + * @wake_reason_ind_cb_ctx - A cookie passed by HDD, that is passed + * back to HDD at the time of callback. + * + * WoWLAN works on top of BMPS mode. + * If the device is not in BMPS mode, + * SME will will cache the information that + * WOWL has been enabled and attempt to put the device + * in BMPS. On entry into BMPS, SME will enable the + * WOWL mode. + * Note 1: If we exit BMPS mode (someone requests full power), + * we will NOT resume WOWL when we go back to BMPS again. + * Request for full power (while in WOWL mode) means disable + * WOWL and go to full power. + * Note 2: Both UAPSD and WOWL work on top of BMPS. + * On entry into BMPS, SME will give priority to UAPSD and + * enable only UAPSD if both UAPSD and WOWL are required. + * Currently there is no requirement or use case to support + * UAPSD and WOWL at the same time. + * + * Return: CDF_STATUS + * CDF_STATUS_SUCCESS Device is already in WoWLAN mode + * CDF_STATUS_E_FAILURE Device cannot enter WoWLAN mode. + * CDF_STATUS_PMC_PENDING Request accepted. SME will enable + * WOWL after BMPS mode is entered. + */ +CDF_STATUS sme_enter_wowl(tHalHandle hal_ctx, + void (*enter_wowl_callback_routine)(void + *callback_context, + CDF_STATUS status), + void *enter_wowl_callback_context, +#ifdef WLAN_WAKEUP_EVENTS + void (*wakeIndicationCB)(void *callback_context, + tpSirWakeReasonInd + wake_reason_ind), + void *wakeIndicationCBContext, +#endif /* WLAN_WAKEUP_EVENTS */ + tpSirSmeWowlEnterParams wowl_enter_params, + uint8_t session_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ENTER_WOWL, session_id, 0)); + + /* cache the WOWL information */ + ps_global_info->ps_params[session_id].wowl_enter_params = + *wowl_enter_params; + ps_global_info->ps_params[session_id].enter_wowl_callback_routine = + enter_wowl_callback_routine; + ps_global_info->ps_params[session_id].enter_wowl_callback_context = + enter_wowl_callback_context; +#ifdef WLAN_WAKEUP_EVENTS + /* Cache the Wake Reason Indication callback information */ + ps_global_info->ps_params[session_id].wake_reason_ind_cb = + wakeIndicationCB; + ps_global_info->ps_params[session_id].wake_reason_ind_cb_ctx = + wakeIndicationCBContext; +#endif /* WLAN_WAKEUP_EVENTS */ + + status = sme_ps_process_command(mac_ctx, session_id, SME_PS_WOWL_ENTER); + return status; +} +/** + *sme_exit_wowl(): SME API exposed to HDD to request exit from WoWLAN mode. + * @hal_ctx - The handle returned by mac_open. + * @wowl_exit_params - Carries info on which smesession + * wowl exit is requested. + * + * SME will initiate exit from WoWLAN mode and device will be + * put in BMPS mode. + * Return CDF_STATUS + * CDF_STATUS_E_FAILURE Device cannot exit WoWLAN mode. + * CDF_STATUS_SUCCESS Request accepted to exit WoWLAN mode. + */ +CDF_STATUS sme_exit_wowl(tHalHandle hal_ctx, + tpSirSmeWowlExitParams wowl_exit_params) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + uint8_t session_id; + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_EXIT_WOWL, NO_SESSION, 0)); + session_id = wowl_exit_params->sessionId; + status = sme_ps_process_command(mac_ctx, session_id, SME_PS_WOWL_EXIT); + return status; +} + +/** + * sme_roam_set_key() - To set encryption key. + * @hal: hal global context + * @session_id: session id + * @set_key: pointer to a caller allocated object of tCsrSetContextInfo + * @ptr_roam_id: Upon success return, this is the id caller can use to + * identify the request in roamcallback + * + * This function should be called only when connected. This is an asynchronous + * API. + * + * Return: Status of operation + */ +CDF_STATUS sme_roam_set_key(tHalHandle hal, uint8_t session_id, + tCsrRoamSetKey *set_key, uint32_t *ptr_roam_id) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint32_t roam_id; + uint32_t i; + tCsrRoamSession *session = NULL; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_SET_KEY, + session_id, 0)); + if (set_key->keyLength > CSR_MAX_KEY_LEN) { + sms_log(mac_ctx, LOGE, FL("Invalid key length %d"), + set_key->keyLength); + return CDF_STATUS_E_FAILURE; + } + /*Once Setkey is done, we can go in BMPS */ + if (set_key->keyLength) + ps_global_info->remain_in_power_active_till_dhcp = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (ptr_roam_id) + *ptr_roam_id = roam_id; + + sms_log(mac_ctx, LOG2, FL("keyLength %d"), set_key->keyLength); + for (i = 0; i < set_key->keyLength; i++) + sms_log(mac_ctx, LOG2, FL("%02x"), set_key->Key[i]); + + sms_log(mac_ctx, LOG2, "\n session_id=%d roam_id=%d", session_id, + roam_id); + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + sme_release_global_lock(&mac_ctx->sme); + return CDF_STATUS_E_FAILURE; + } + if (CSR_IS_INFRA_AP(&session->connectedProfile) + && set_key->keyDirection == eSIR_TX_DEFAULT) { + if ((eCSR_ENCRYPT_TYPE_WEP40 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + if ((eCSR_ENCRYPT_TYPE_WEP104 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } + status = csr_roam_set_key(mac_ctx, session_id, set_key, roam_id); + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_rssi + \brief a wrapper function that client calls to register a callback to get + RSSI + + \param hHal - HAL handle for device + \param callback - SME sends back the requested stats using the callback + \param staId - The station ID for which the stats is requested for + \param bssid - The bssid of the connected session + \param lastRSSI - RSSI value at time of request. In case fw cannot provide + RSSI, do not hold up but return this value. + \param pContext - user context to be passed back along with the callback + \param p_cds_context - cds context + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_RSSI, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_rssi(pMac, callback, + staId, bssId, lastRSSI, + pContext, p_cds_context); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_snr + \brief a wrapper function that client calls to register a callback to + get SNR + + \param callback - SME sends back the requested stats using the callback + \param staId - The station ID for which the stats is requested for + \param pContext - user context to be passed back along with the callback + \param p_cds_context - cds context + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_snr(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, void *pContext) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_snr(pMac, callback, staId, bssId, pContext); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/* --------------------------------------------------------------------------- + \fn sme_get_tsm_stats + \brief a wrapper function that client calls to register a callback to + get TSM Stats + \param callback - SME sends back the requested stats using the callback + \param staId - The station ID for which the stats is requested for + \param pContext - user context to be passed back along with the callback + \param p_cds_context - cds context + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_tsm_stats(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_tsm_stats(pMac, callback, + staId, bssId, pContext, p_cds_context, + tid); + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif + +/* --------------------------------------------------------------------------- + \fn sme_get_statistics + \brief a wrapper function that client calls to register a callback to get + different PHY level statistics from CSR. + + \param requesterId - different client requesting for statistics, + HDD, UMA/GAN etc + \param statsMask - The different category/categories of stats requester + is looking for + \param callback - SME sends back the requested stats using the callback + \param periodicity - If requester needs periodic update in millisec, 0 means + it's an one time request + \param cache - If requester is happy with cached stats + \param staId - The station ID for which the stats is requested for + \param pContext - user context to be passed back along with the callback + \param sessionId - sme session interface + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_STATS, NO_SESSION, + periodicity)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + csr_get_statistics(pMac, requesterId, statsMask, callback, + periodicity, cache, staId, pContext, + sessionId); + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +CDF_STATUS sme_get_link_status(tHalHandle hHal, + tCsrLinkStatusCallback callback, + void *pContext, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tAniGetLinkStatus *pMsg; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pMsg = cdf_mem_malloc(sizeof(tAniGetLinkStatus)); + if (NULL == pMsg) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for link status", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_LINK_STATUS_GET_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetLinkStatus); + pMsg->sessionId = sessionId; + pMac->sme.linkStatusContext = pContext; + pMac->sme.linkStatusCallback = callback; + + cds_message.type = WMA_LINK_STATUS_GET_REQ; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &cds_message))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post LINK STATUS MSG fail", __func__); + cdf_mem_free(pMsg); + pMac->sme.linkStatusContext = NULL; + pMac->sme.linkStatusCallback = NULL; + status = CDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_get_country_code + + \brief To return the current country code. If no country code is applied, + default country code is used to fill the buffer. + If 11d supported is turned off, an error is return and the last + applied/default country code is used. + This is a synchronous API. + + \param pBuf - pointer to a caller allocated buffer for returned country code. + + \param pbLen For input, this parameter indicates how big is the buffer. + Upon return, this parameter has the number of bytes for + country. If pBuf doesn't have enough space, this function + returns fail status and this parameter contains the number + that is needed. + + \return CDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, NO_SESSION, 0)); + + return csr_get_country_code(pMac, pBuf, pbLen); +} + +/** + * sme_apply_channel_power_info_to_fw() - sends channel info to fw + * @hHal: hal handle + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void sme_apply_channel_power_info_to_fw(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + csr_apply_channel_power_info_wrapper(pMac); +} + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is11d_supported(pMac); +} + +bool sme_is11h_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is11h_supported(pMac); +} + +bool sme_is_wmm_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is_wmm_supported(pMac); +} + +/* --------------------------------------------------------------------------- + + \fn sme_change_country_code + + \brief Change Country code from upperlayer during WLAN driver operation. + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param pCountry New Country Code String + + \param sendRegHint If we want to send reg hint to nl80211 + + \return CDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_change_country_code(tHalHandle hHal, + tSmeChangeCountryCallback callback, + uint8_t *pCountry, + void *pContext, + void *p_cds_context, + tAniBool countryFromUserSpace, + tAniBool sendRegHint) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + tAniChangeCountryCodeReq *pMsg; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL(" called")); + + if ((pMac->roam.configParam.Is11dSupportEnabledOriginal == true) + && (!pMac->roam.configParam. + fSupplicantCountryCodeHasPriority)) { + + sms_log(pMac, LOGW, + "Set Country Code Fail since the STA is associated and userspace does not have priority "); + + sme_release_global_lock(&pMac->sme); + status = CDF_STATUS_E_FAILURE; + return status; + } + + pMsg = cdf_mem_malloc(sizeof(tAniChangeCountryCodeReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csrChangeCountryCode: failed to allocate mem for req"); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_CHANGE_COUNTRY_CODE; + pMsg->msgLen = (uint16_t) sizeof(tAniChangeCountryCodeReq); + cdf_mem_copy(pMsg->countryCode, pCountry, 3); + pMsg->countryFromUserSpace = countryFromUserSpace; + pMsg->sendRegHint = sendRegHint; + pMsg->changeCCCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + + msg.type = eWNI_SME_CHANGE_COUNTRY_CODE; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + " sme_change_country_code failed to post msg to self "); + cdf_mem_free((void *)pMsg); + status = CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" returned")); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + + \fn sme_generic_change_country_code + + \brief Change Country code from upperlayer during WLAN driver operation. + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param pCountry New Country Code String + + \param reg_domain regulatory domain + + \return CDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -----------------------------------------------------------------------------*/ +CDF_STATUS sme_generic_change_country_code(tHalHandle hHal, + uint8_t *pCountry, + v_REGDOMAIN_t reg_domain) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + tAniGenericChangeCountryCodeReq *pMsg; + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL(" called")); + pMsg = cdf_mem_malloc(sizeof(tAniGenericChangeCountryCodeReq)); + + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " sme_generic_change_country_code: failed to allocate mem for req"); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + pMsg->msgLen = + (uint16_t) sizeof(tAniGenericChangeCountryCodeReq); + cdf_mem_copy(pMsg->countryCode, pCountry, 2); + pMsg->domain_index = reg_domain; + pMsg->countryCode[2] = ' '; /* For ASCII space */ + + msg.type = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + "sme_generic_change_country_code failed to post msg to self"); + cdf_mem_free(pMsg); + status = CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" returned")); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_dhcp_start_ind + + \brief API to signal the FW about the DHCP Start event. + + \param hHal - HAL handle for device. + + \param device_mode - mode(AP,SAP etc) of the device. + + \param macAddr - MAC address of the adapter. + + \param sessionId - session ID. + + \return CDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +CDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + CDF_STATUS status; + CDF_STATUS cdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniDHCPInd *pMsg; + tCsrRoamSession *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + pMsg = (tAniDHCPInd *) cdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + pMsg->msgType = WMA_DHCP_START_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + cdf_mem_copy(pMsg->adapterMacAddr, macAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMsg->peerMacAddr, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + cds_message.type = WMA_DHCP_START_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Start MSG fail", __func__); + cdf_mem_free(pMsg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_dhcp_stop_ind + + \brief API to signal the FW about the DHCP complete event. + + \param hHal - HAL handle for device. + + \param device_mode - mode(AP, SAP etc) of the device. + + \param macAddr - MAC address of the adapter. + + \param sessionId - session ID. + + \return CDF_STATUS SUCCESS. + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +CDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + CDF_STATUS status; + CDF_STATUS cdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniDHCPInd *pMsg; + tCsrRoamSession *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + pMsg = (tAniDHCPInd *) cdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp stop", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_DHCP_STOP_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + cdf_mem_copy(pMsg->adapterMacAddr, macAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMsg->peerMacAddr, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + cds_message.type = WMA_DHCP_STOP_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Stop MSG fail", __func__); + cdf_mem_free(pMsg); + status = CDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_cfg_privacy + \brief API to set configure privacy parameters + \param hHal - The handle returned by mac_open. + \param pProfile - Pointer CSR Roam profile. + \param fPrivacy - This parameter indicates status of privacy + + \return void + ---------------------------------------------------------------------------*/ +void sme_set_cfg_privacy(tHalHandle hHal, + tCsrRoamProfile *pProfile, bool fPrivacy) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY, NO_SESSION, 0)); + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + csr_set_cfg_privacy(pMac, pProfile, fPrivacy); + sme_release_global_lock(&pMac->sme); + } +} + +#if defined WLAN_FEATURE_VOWIFI +/* --------------------------------------------------------------------------- + \fn sme_neighbor_report_request + \brief API to request neighbor report. + \param hHal - The handle returned by mac_open. + \param pRrmNeighborReq - Pointer to a caller allocated object of type + tRrmNeighborReq. Caller owns the memory and is + responsible for freeing it. + \return CDF_STATUS + CDF_STATUS_E_FAILURE - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_neighbor_report_request(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, NO_SESSION, + 0)); + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + status = + sme_rrm_neighbor_report_request(hHal, sessionId, + pRrmNeighborReq, callbackInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif + +void sms_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_SMS_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_SMS_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_wlan_compiled_version + \brief This API returns the version of the WCNSS WLAN API with + which the HOST driver was built + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version structure to be filled + \return CDF_STATUS + CDF_STATUS_E_INVAL - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = CDF_STATUS_SUCCESS; + else + status = CDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_wlan_reported_version + \brief This API returns the version of the WCNSS WLAN API with + which the WCNSS driver reports it was built + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version structure to be filled + \return CDF_STATUS + CDF_STATUS_E_INVAL - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = CDF_STATUS_SUCCESS; + else + status = CDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_software_version + \brief This API returns the version string of the WCNSS driver + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version string buffer to be filled + \param versionBufferSize - THe size of the Version string buffer + \return CDF_STATUS + CDF_STATUS_E_INVAL - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_CONTEXT_t cds_context = cds_get_global_context(); + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) { + status = + wma_get_wcnss_software_version(cds_context, + pVersion, + versionBufferSize); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_hardware_version + \brief This API returns the version string of the WCNSS hardware + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version string buffer to be filled + \param versionBufferSize - THe size of the Version string buffer + \return CDF_STATUS + CDF_STATUS_E_INVAL - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = CDF_STATUS_SUCCESS; + else + status = CDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef FEATURE_WLAN_WAPI + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_bkid_candidate_list + \brief a wrapper function to return the BKID candidate list + \param pBkidList - caller allocated buffer point to an array of + tBkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of + tBkidCandidateInfo allocated when retruning, this is + either the number needed or number of items put into + pPmkidList + \return CDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems + has the number of tBkidCandidateInfo. + \Note: pNumItems is a number of tBkidCandidateInfo, + not sizeof(tBkidCandidateInfo) * something + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_scan_get_bkid_candidate_list(tHalHandle hHal, uint32_t sessionId, + tBkidCandidateInfo *pBkidList, + uint32_t *pNumItems) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + csr_scan_get_bkid_candidate_list(pMac, sessionId, pBkidList, + pNumItems); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_WAPI */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/***************************************************************************** + OEM DATA related modifications and function additions +*****************************************************************************/ + +/* --------------------------------------------------------------------------- + \fn sme_oem_data_req + \brief a wrapper function for OEM DATA REQ + \param sessionId - session id to be used. + \param pOemDataReqId - pointer to an object to get back the request ID + \param callback - a callback function that is called upon finish + \param pContext - a pointer passed in for the callback + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_oem_data_req(tHalHandle hHal, + uint8_t sessionId, + tOemDataReqConfig *pOemDataReqConfig, + uint32_t *pOemDataReqID, + oem_data_oem_data_reqCompleteCallback callback, + void *pContext) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + uint32_t lOemDataReqId = pMac->oemData.oemDataReqID++; /* let it wrap around */ + + if (pOemDataReqID) { + *pOemDataReqID = lOemDataReqId; + } else { + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + status = + oem_data_oem_data_req(hHal, sessionId, + pOemDataReqConfig, pOemDataReqID, + callback, pContext); + + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } while (0); + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +#endif /*FEATURE_OEM_DATA_SUPPORT */ + +/*-------------------------------------------------------------------------- + + \brief sme_open_session() - Open a session for scan/roam operation. + + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param callback - A pointer to the function caller specifies for + roam/connect status indication + \param pContext - The context passed with callback + \param pSelfMacAddr - Caller allocated memory filled with self MAC address + (6 bytes) + \param pbSessionId - pointer to a caller allocated buffer for returned session ID + + \return CDF_STATUS_SUCCESS - session is opened. sessionId returned. + + Other status means SME is failed to open the session. + CDF_STATUS_E_RESOURCES - no more session available. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_open_session(tHalHandle hHal, csr_roam_completeCallback callback, + void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType) +{ + CDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: type=%d, subType=%d", __func__, type, subType); + + if (NULL == pbSessionId) { + status = CDF_STATUS_E_INVAL; + } else { + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = + csr_roam_open_session(pMac, callback, pContext, + pSelfMacAddr, pbSessionId, type, + subType); + + sme_release_global_lock(&pMac->sme); + } + } + if (NULL != pbSessionId) + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + *pbSessionId, 0)); + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_close_session() - Open a session for scan/roam operation. + + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param sessionId - A previous opened session's ID. + + \return CDF_STATUS_SUCCESS - session is closed. + + Other status means SME is failed to open the session. + CDF_STATUS_E_INVAL - session is not opened. + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_close_session(tHalHandle hHal, uint8_t sessionId, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + CDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_close_session(pMac, sessionId, false, + callback, pContext); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_roam_update_apwpsie + + \brief To update AP's WPS IE. This function should be called after SME AP session is created + This is an asynchronous API. + + \param pAPWPSIES - pointer to a caller allocated object of tSirAPWPSIEs + + \return CDF_STATUS – SUCCESS – + + FAILURE or RESOURCES – The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_update_apwpsie(tHalHandle hHal, uint8_t sessionId, + tSirAPWPSIEs *pAPWPSIES) +{ + + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_update_apwpsie(pMac, sessionId, pAPWPSIES); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_roam_update_apwparsni_es + + \brief To update AP's WPA/RSN IEs. This function should be called after SME AP session is created + This is an asynchronous API. + + \param pAPSirRSNie - pointer to a caller allocated object of tSirRSNie with WPS/RSN IEs + + \return CDF_STATUS – SUCCESS – + + FAILURE or RESOURCES – The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_update_apwparsni_es(tHalHandle hHal, uint8_t sessionId, + tSirRSNie *pAPSirRSNie) +{ + + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_update_wparsni_es(pMac, sessionId, pAPSirRSNie); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_change_mcc_beacon_interval + + \brief To update P2P-GO beaconInterval. This function should be called after + disassociating all the station is done + This is an asynchronous API. + + \param + + \return CDF_STATUS SUCCESS + FAILURE or RESOURCES + The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_change_mcc_beacon_interval(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG1, FL("Update Beacon PARAMS ")); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_send_chng_mcc_beacon_interval(pMac, sessionId); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_host_offload(): API to set the host offload feature. + * @hHal: The handle returned by mac_open. + * @sessionId: Session Identifier + * @request: Pointer to the offload request. + * + * Return CDF_STATUS + */ +CDF_STATUS sme_set_host_offload(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq request) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { +#ifdef WLAN_NS_OFFLOAD + if (SIR_IPV6_NS_OFFLOAD == request->offloadType) { + status = sme_set_ps_ns_offload(hHal, request, + sessionId); + } else +#endif /* WLAN_NS_OFFLOAD */ + { + status = sme_set_ps_host_offload(hHal, request, + sessionId); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * sme_set_gtk_offload(): API to set GTK offload information. + * @hHal: The handle returned by mac_open. + * @sessionId: Session Identifier + * @pGtkOffload: Pointer to the GTK offload request.. + * + * Return CDF_STATUS + */ +CDF_STATUS sme_set_gtk_offload(tHalHandle hHal, + tpSirGtkOffloadParams pGtkOffload, + uint8_t sessionId) +{ + tpSirGtkOffloadParams request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "%s: KeyReplayCounter: %lld", __func__, + pGtkOffload->ullKeyReplayCounter); + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Session not found ", __func__); + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for GTK offload request")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(pGtkOffload->bssId, pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + *request_buf = *pGtkOffload; + + msg.type = WMA_GTK_OFFLOAD_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post SIR_HAL_SET_GTK_OFFLOAD message to HAL")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_get_gtk_offload(): API to get GTK offload information + * @hHal: The handle returned by mac_open. + * @callback_routine: callback_routine. + * @sessionId: Session Identifier. + * callback_context: callback_context. + * + * Return CDF_STATUS + */ +CDF_STATUS sme_get_gtk_offload(tHalHandle hHal, + gtk_offload_get_info_callback callback_routine, + void *callback_context, uint8_t session_id) +{ + tpSirGtkOffloadGetInfoRspParams request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s: Entered", + __func__); + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Session not found ", __func__); + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for Get GTK offload request")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(request_buf->bssId, pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + msg.type = WMA_GTK_OFFLOAD_GETINFO_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + + /* Cache the Get GTK Offload callback information */ + if (NULL != pMac->sme.gtk_offload_get_info_cb) { + + /* Do we need to check if the callback is in use? */ + /* Because we are not sending the same message again + * when it is pending, + * the only case when the callback is not NULL is that + * the previous message was timed out or failed. + * So, it will be safe to set the callback in this case. + */ + } + + pMac->sme.gtk_offload_get_info_cb = callback_routine; + pMac->sme.gtk_offload_get_info_cb_context = callback_context; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_GTK_OFFLOAD_GETINFO_REQ message to WMA")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/* --------------------------------------------------------------------------- + \fn sme_set_keep_alive + \brief API to set the Keep Alive feature. + \param hHal - The handle returned by mac_open. + \param request - Pointer to the Keep Alive request. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t session_id, + tpSirKeepAliveReq request) +{ + tpSirKeepAliveReq request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_LOW, + FL("WMA_SET_KEEP_ALIVE message")); + + if (pSession == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Session not Found")); + return CDF_STATUS_E_FAILURE; + } + request_buf = cdf_mem_malloc(sizeof(tSirKeepAliveReq)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for keep alive request")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(request->bssId, pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(request_buf, request, sizeof(tSirKeepAliveReq)); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_LOW, + "buff TP %d input TP %d ", request_buf->timePeriod, + request->timePeriod); + request_buf->sessionId = session_id; + + msg.type = WMA_SET_KEEP_ALIVE; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_KEEP_ALIVE message to WMA")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/* --------------------------------------------------------------------------- + \fn sme_set_preferred_network_list + \brief API to set the Preferred Network List Offload feature. + \param hHal - The handle returned by mac_open. + \param request - Pointer to the offload request. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq request, + uint8_t sessionId, + void (*callback_routine)(void *callback_context, + tSirPrefNetworkFoundInd + *pPrefNetworkFoundInd), + void *callback_context) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sme_set_ps_preferred_network_list(hHal, request, sessionId, + callback_routine, callback_context); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/* --------------------------------------------------------------------------- + \fn sme_abort_mac_scan + \brief API to cancel MAC scan. + \param hHal - The handle returned by mac_open. + \param sessionId - sessionId on which we need to abort scan. + \param reason - Reason to abort the scan. + \return CDF_STATUS + CDF_STATUS_E_FAILURE - failure + CDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_abort_mac_scan(tHalHandle hHal, uint8_t sessionId, + eCsrAbortReason reason) +{ + CDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_abort_mac_scan(pMac, sessionId, reason); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* ---------------------------------------------------------------------------- + \fn sme_get_operation_channel + \brief API to get current channel on which STA is parked + this function gives channel information only of infra station or IBSS station + \param hHal, pointer to memory location and sessionId + \returns CDF_STATUS_SUCCESS + CDF_STATUS_E_FAILURE + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if ((pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRASTRUCTURE) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_IBSS) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRA_AP) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_START_IBSS)) { + *pChannel = pSession->connectedProfile.operationChannel; + return CDF_STATUS_SUCCESS; + } + } + return CDF_STATUS_E_FAILURE; +} /* sme_get_operation_channel ends here */ + +/* --------------------------------------------------------------------------- + + \fn sme_RegisterMgtFrame + + \brief To register managment frame of specified type and subtype. + \param frameType - type of the frame that needs to be passed to HDD. + \param matchData - data which needs to be matched before passing frame + to HDD. + \param matchDataLen - Length of matched data. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_register_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set(pMsg, len, 0); + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->sessionId = sessionId; + pMsg->registerFrame = true; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + cdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = cds_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_DeregisterMgtFrame + + \brief To De-register managment frame of specified type and subtype. + \param frameType - type of the frame that needs to be passed to HDD. + \param matchData - data which needs to be matched before passing frame + to HDD. + \param matchDataLen - Length of matched data. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_deregister_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set(pMsg, len, 0); + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->registerFrame = false; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + cdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = cds_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_remain_on_channel - API to request remain on channel for 'x' duration + * + * @hHal: pointer to MAC handle + * @session_id: Session identifier + * @channel: channel information + * @duration: duration in ms + * @callback: HDD registered callback to process reaminOnChannelRsp + * @context: HDD Callback param + * @scan_id: scan identifier + * + * This function process the roc request and generates scan identifier.s + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_remain_on_channel(tHalHandle hHal, uint8_t session_id, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t *scan_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + uint32_t san_req_id, scan_count; + struct ani_roc_req *roc_msg; + cds_msg_t msg; + + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN, session_id, 0)); + + scan_count = csr_ll_count(&mac_ctx->sme.smeScanCmdActiveList); + if (scan_count >= mac_ctx->scan.max_scan_count) { + sms_log(mac_ctx, LOGE, FL("Max scan reached")); + return CDF_STATUS_E_FAILURE; + } + + wma_get_scan_id(&san_req_id); + *scan_id = san_req_id; + status = sme_acquire_global_lock(&mac_ctx->sme); + + sms_log(mac_ctx, LOG1, FL(" called")); + roc_msg = cdf_mem_malloc(sizeof(struct ani_roc_req)); + if (NULL == roc_msg) { + sms_log(mac_ctx, LOGE, + " scan_req: failed to allocate mem for msg"); + sme_release_global_lock(&mac_ctx->sme); + return CDF_STATUS_E_NOMEM; + } + roc_msg->msg_type = eWNI_SME_ROC_CMD; + roc_msg->msg_len = (uint16_t) sizeof(struct ani_roc_req); + roc_msg->session_id = session_id; + roc_msg->callback = callback; + roc_msg->duration = duration; + roc_msg->channel = channel; + roc_msg->is_p2pprobe_allowed = isP2PProbeReqAllowed; + roc_msg->ctx = pContext; + roc_msg->scan_id = *scan_id; + msg.type = eWNI_SME_ROC_CMD; + msg.bodyptr = roc_msg; + msg.reserved = 0; + msg.bodyval = 0; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(mac_ctx, LOGE, + " sme_scan_req failed to post msg"); + cdf_mem_free(roc_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_report_probe_req + \brief API to enable/disable forwarding of probeReq to apps in p2p. + \param hHal - The handle returned by mac_open. + \param falg: to set the Probe request forarding to wpa_supplicant in listen state in p2p + \return CDF_STATUS + ---------------------------------------------------------------------------*/ + +#ifndef WLAN_FEATURE_CONCURRENT_P2P +CDF_STATUS sme_report_probe_req(tHalHandle hHal, uint8_t flag) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* call set in context */ + pMac->p2pContext.probeReqForwarding = flag; + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } while (0); + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_p2p_ie + \brief API to set the P2p Ie in p2p context + \param hHal - The handle returned by mac_open. + \param p2pIe - Ptr to p2pIe from HDD. + \param p2pIeLength: length of p2pIe + \return CDF_STATUS + ---------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_p2p_ie(tHalHandle hHal, void *p2pIe, uint32_t p2pIeLength) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE, NO_SESSION, 0)); + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (NULL != pMac->p2pContext.probeRspIe) { + cdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIeLength = 0; + } + + pMac->p2pContext.probeRspIe = cdf_mem_malloc(p2pIeLength); + if (NULL == pMac->p2pContext.probeRspIe) { + sms_log(pMac, LOGE, "%s: Unable to allocate P2P IE", + __func__); + pMac->p2pContext.probeRspIeLength = 0; + status = CDF_STATUS_E_NOMEM; + } else { + pMac->p2pContext.probeRspIeLength = p2pIeLength; + + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG2, + pMac->p2pContext.probeRspIe, + pMac->p2pContext.probeRspIeLength); + cdf_mem_copy((uint8_t *) pMac->p2pContext.probeRspIe, + p2pIe, p2pIeLength); + } + + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + + sms_log(pMac, LOG2, "exiting function %s", __func__); + + return status; +} +#endif + +/* --------------------------------------------------------------------------- + \fn sme_send_action + \brief API to send action frame from supplicant. + \param hHal - The handle returned by mac_open. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ + +CDF_STATUS sme_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, + uint16_t wait, bool noack, + uint16_t channel_freq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SEND_ACTION, sessionId, 0)); + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + p2p_send_action(hHal, sessionId, pBuf, len, wait, noack, + channel_freq); + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +CDF_STATUS sme_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = p2p_cancel_remain_on_channel(hHal, sessionId, scan_id); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* Power Save Related */ +CDF_STATUS sme_p2p_set_ps(tHalHandle hHal, tP2pPsConfig *data) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = p2p_set_ps(hHal, data); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_rxp_filter + + \brief + SME will pass this request to lower mac to set/reset the filter on RXP for + multicast & broadcast traffic. + + \param + + hHal - The handle returned by mac_open. + + filterMask- Currently the API takes a 1 or 0 (set or reset) as filter. + Basically to enable/disable the filter (to filter "all" mcbc traffic) based + on this param. In future we can use this as a mask to set various types of + filters as suggested below: + FILTER_ALL_MULTICAST: + FILTER_ALL_BROADCAST: + FILTER_ALL_MULTICAST_BROADCAST: + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_rxp_filter(tHalHandle hHal, + tpSirWlanSetRxpFilters wlanRxpFilterParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = wlanRxpFilterParam; + cds_message.type = WMA_CFG_RXP_FILTER_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_suspend_ind + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be suspended + + \param + + hHal - The handle returned by mac_open. + + wlanSuspendParam- Depicts the wlan suspend params + + csr_readyToSuspendCallback - Callback to be called when ready to suspend + event is received. + callback_context - Context associated with csr_readyToSuspendCallback. + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_suspend_ind(tHalHandle hHal, + tpSirWlanSuspendParam wlanSuspendParam, + csr_readyToSuspendCallback callback, + void *callback_context) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, NO_SESSION, + 0)); + + pMac->readyToSuspendCallback = callback; + pMac->readyToSuspendContext = callback_context; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = wlanSuspendParam; + cds_message.type = WMA_WLAN_SUSPEND_IND; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->readyToSuspendCallback = NULL; + pMac->readyToSuspendContext = NULL; + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_resume_req + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be Resumed + + \param + + hHal - The handle returned by mac_open. + + wlanResumeParam- Depicts the wlan resume params + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_resume_req(tHalHandle hHal, + tpSirWlanResumeParam wlanResumeParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = wlanResumeParam; + cds_message.type = WMA_WLAN_RESUME_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/* --------------------------------------------------------------------------- + + \fn sme_configure_ext_wo_w + + \brief + SME will pass this request to lower mac to configure Extr WoW + + \param + + hHal - The handle returned by mac_open. + + wlanExtParams- Depicts the wlan Ext params + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_ext_wo_w(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToExtWoWCallback callback, + void *callback_context) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirExtWoWParams MsgPtr = cdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return CDF_STATUS_E_NOMEM; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, NO_SESSION, 0)); + + pMac->readyToExtWoWCallback = callback; + pMac->readyToExtWoWContext = callback_context; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + /* serialize the req through MC thread */ + cdf_mem_copy(MsgPtr, wlanExtParams, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_EXT_WOW; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + cdf_mem_free(MsgPtr); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + cdf_mem_free(MsgPtr); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_app_type1_params + + \brief + SME will pass this request to lower mac to configure Indoor WoW parameters. + + \param + + hHal - The handle returned by mac_open. + + wlanAppType1Params- Depicts the wlan App Type 1(Indoor) params + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_app_type1_params(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirAppType1Params MsgPtr = cdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return CDF_STATUS_E_NOMEM; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cdf_mem_copy(MsgPtr, wlanAppType1Params, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_SET_APP_TYPE1_PARAMS; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_mem_free(MsgPtr); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + cdf_mem_free(MsgPtr); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_app_type2_params + + \brief + SME will pass this request to lower mac to configure Indoor WoW parameters. + + \param + + hHal - The handle returned by mac_open. + + wlanAppType2Params- Depicts the wlan App Type 2 (Outdoor) params + + \return CDF_STATUS + + --------------------------------------------------------------------------- */ +CDF_STATUS sme_configure_app_type2_params(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirAppType2Params MsgPtr = cdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return CDF_STATUS_E_NOMEM; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cdf_mem_copy(MsgPtr, wlanAppType2Params, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_SET_APP_TYPE2_PARAMS; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_mem_free(MsgPtr); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + cdf_mem_free(MsgPtr); + } + + return status; +} +#endif + +/* --------------------------------------------------------------------------- + + \fn sme_get_infra_session_id + + \brief To get the session ID for infra session, if connected + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \return sessionid, -1 if infra session is not connected + + -------------------------------------------------------------------------------*/ +int8_t sme_get_infra_session_id(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int8_t sessionid = -1; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + sessionid = csr_get_infra_session_id(pMac); + + sme_release_global_lock(&pMac->sme); + } + + return sessionid; +} + +/* --------------------------------------------------------------------------- + + \fn sme_get_infra_operation_channel + + \brief To get the operating channel for infra session, if connected + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param sessionId - the sessionId returned by sme_open_session. + + \return operating channel, 0 if infra session is not connected + + -------------------------------------------------------------------------------*/ +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t channel = 0; + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + channel = csr_get_infra_operation_channel(pMac, sessionId); + + sme_release_global_lock(&pMac->sme); + } + + return channel; +} + +/* This routine will return poerating channel on which other BSS is operating to be used for concurrency mode. */ +/* If other BSS is not up or not connected it will return 0 */ +uint8_t sme_get_concurrent_operation_channel(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t channel = 0; + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + channel = csr_get_concurrent_operation_channel(pMac); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, "%s: " + " Other Concurrent Channel = %d", __func__, channel); + sme_release_global_lock(&pMac->sme); + } + + return channel; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t channel = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + channel = + csr_check_concurrent_channel_overlap(pMac, sap_ch, sapPhyMode, + cc_switch_mode); + sme_release_global_lock(&pMac->sme); + } + + return channel; +} +#endif + +#ifdef FEATURE_WLAN_SCAN_PNO +/****************************************************************************** +* +* Name: sme_preferred_network_found_ind +* +* Description: +* Invoke Preferred Network Found Indication +* +* Parameters: +* hHal - HAL handle for device +* pMsg - found network description +* +* Returns: CDF_STATUS +* +******************************************************************************/ +CDF_STATUS sme_preferred_network_found_ind(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd = + (tSirPrefNetworkFoundInd *) pMsg; + uint8_t dumpSsId[SIR_MAC_MAX_SSID_LENGTH + 1]; + uint8_t ssIdLength = 0; + + if (NULL == pMsg) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (pMac->pnoOffload) { + /* Call Preferred Network Found Indication callback routine. */ + if (pMac->sme.pref_netw_found_cb != NULL) { + pMac->sme.pref_netw_found_cb(pMac->sme. + preferred_network_found_ind_cb_ctx, + pPrefNetworkFoundInd); + } + return status; + } + + if (pPrefNetworkFoundInd->ssId.length > 0) { + ssIdLength = CSR_MIN(SIR_MAC_MAX_SSID_LENGTH, + pPrefNetworkFoundInd->ssId.length); + cdf_mem_copy(dumpSsId, pPrefNetworkFoundInd->ssId.ssId, + ssIdLength); + dumpSsId[ssIdLength] = 0; + sms_log(pMac, LOG2, "%s:SSID=%s frame length %d", + __func__, dumpSsId, pPrefNetworkFoundInd->frameLength); + + /* Flush scan results, So as to avoid indication/updation of + * stale entries, which may not have aged out during APPS collapse + */ + sme_scan_flush_result(hHal); + + /* Save the frame to scan result */ + if (pPrefNetworkFoundInd->mesgLen > + sizeof(tSirPrefNetworkFoundInd)) { + /* we may have a frame */ + status = csr_scan_save_preferred_network_found(pMac, + pPrefNetworkFoundInd); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to save preferred network")); + } + } else { + sms_log(pMac, LOGE, + FL(" not enough data length %d needed %zu"), + pPrefNetworkFoundInd->mesgLen, + sizeof(tSirPrefNetworkFoundInd)); + } + + /* Call Preferred Netowrk Found Indication callback routine. */ + if (CDF_IS_STATUS_SUCCESS(status) + && (pMac->sme.pref_netw_found_cb != NULL)) { + pMac->sme.pref_netw_found_cb(pMac->sme. + preferred_network_found_ind_cb_ctx, + pPrefNetworkFoundInd); + } + } else { + sms_log(pMac, LOGE, "%s: callback failed - SSID is NULL", + __func__); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +CDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels, + uint32_t *len) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_cfg_valid_channels(pMac, aValidChannels, len); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_handle_change_country_code + + \brief Change Country code, Reg Domain and channel list + + \details Country Code Priority + If Supplicant country code is priority than 11d is disabled. + If 11D is enabled, we update the country code after every scan. + Hence when Supplicant country code is priority, we don't need 11D info. + Country code from Supplicant is set as current courtry code. + User can send reset command XX (instead of country code) to reset the + country code to default values. + If 11D is priority, + Than Supplicant country code code is set to default code. But 11D code is set as current country code + + \param pMac - The handle returned by mac_open. + \param pMsgBuf - MSG Buffer + + \return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_handle_change_country_code(tpAniSirGlobal pMac, void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tAniChangeCountryCodeReq *pMsg; + v_REGDOMAIN_t domainIdIoctl; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + static country_code_t default_country; + pMsg = (tAniChangeCountryCodeReq *) pMsgBuf; + + /* + * if the reset Supplicant country code command is triggered, + * enable 11D, reset the country code and return + */ + if (true == + cdf_mem_compare(pMsg->countryCode, SME_INVALID_COUNTRY_CODE, 2)) { + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + + cdf_status = cds_read_default_country(default_country); + + /* read the country code and use it */ + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_mem_copy(pMsg->countryCode, + default_country, + WNI_CFG_COUNTRY_CODE_LEN); + } else { + status = CDF_STATUS_E_FAILURE; + return status; + } + /* + * Update the 11d country to default country so that when + * callback is received for this default country, driver will + * not disable the 11d taking it as valid country by user. + */ + sms_log(pMac, LOG1, + FL("Set default country code (%c%c) as invalid country received"), + pMsg->countryCode[0], pMsg->countryCode[1]); + cdf_mem_copy(pMac->scan.countryCode11d, + pMsg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } else { + /* if Supplicant country code has priority, disable 11d */ + if (pMac->roam.configParam.fSupplicantCountryCodeHasPriority && + pMsg->countryFromUserSpace) { + pMac->roam.configParam.Is11dSupportEnabled = false; + } + } + + if (pMac->roam.configParam.Is11dSupportEnabled) + return CDF_STATUS_SUCCESS; + + /* Set Current Country code and Current Regulatory domain */ + status = csr_set_country_code(pMac, pMsg->countryCode); + if (CDF_STATUS_SUCCESS != status) { + /* Supplicant country code failed. So give 11D priority */ + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + sms_log(pMac, LOGE, "Set Country Code Fail %d", status); + return status; + } + + /* overwrite the defualt country code */ + cdf_mem_copy(pMac->scan.countryCodeDefault, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + /* Get Domain ID from country code */ + status = csr_get_regulatory_domain_for_country(pMac, + pMac->scan.countryCodeCurrent, + (v_REGDOMAIN_t *) & + domainIdIoctl, COUNTRY_QUERY); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to get regId %d"), domainIdIoctl); + return status; + } else if (REGDOMAIN_WORLD == domainIdIoctl) { + /* Supplicant country code is invalid, so we are on world mode now. So + give 11D chance to update */ + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + sms_log(pMac, LOG1, FL("Country Code unrecognized by driver")); + } + + status = wma_set_reg_domain(pMac, domainIdIoctl); + + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to set regId %d"), domainIdIoctl); + return status; + } else { + /* if 11d has priority, clear currentCountryBssid & countryCode11d to get */ + /* set again if we find AP with 11d info during scan */ + if (!pMac->roam.configParam.fSupplicantCountryCodeHasPriority) { + sms_log(pMac, LOGW, + FL + ("Clearing currentCountryBssid, countryCode11d")); + cdf_mem_zero(&pMac->scan.currentCountryBssid, + sizeof(struct cdf_mac_addr)); + cdf_mem_zero(pMac->scan.countryCode11d, + sizeof(pMac->scan.countryCode11d)); + } + } + + if (pMsg->changeCCCallback) { + ((tSmeChangeCountryCallback) (pMsg->changeCCCallback))((void *) + pMsg-> + pDevContext); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_handle_change_country_code_by_user() - handles country ch req + * @mac_ctx: mac global context + * @msg: request msg packet + * + * If Supplicant country code is priority than 11d is disabled. + * If 11D is enabled, we update the country code after every scan. + * Hence when Supplicant country code is priority, we don't need 11D info. + * Country code from Supplicant is set as current country code. + * + * Return: status of operation + */ +CDF_STATUS +sme_handle_change_country_code_by_user(tpAniSirGlobal mac_ctx, + tAniGenericChangeCountryCodeReq *msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + v_REGDOMAIN_t reg_domain_id; + bool is_11d_country = false; + bool supplicant_priority = + mac_ctx->roam.configParam.fSupplicantCountryCodeHasPriority; + + sms_log(mac_ctx, LOG1, FL(" called")); + reg_domain_id = (v_REGDOMAIN_t) msg->domain_index; + if (memcmp(msg->countryCode, mac_ctx->scan.countryCode11d, + CDS_COUNTRY_CODE_LEN) == 0) { + is_11d_country = true; + } + /* Set the country code given by userspace when 11dOriginal is false + * when 11doriginal is True,is_11d_country =0 and + * fSupplicantCountryCodeHasPriority = 0, then revert the country code, + * and return failure + */ + if (mac_ctx->roam.configParam.Is11dSupportEnabledOriginal == true + && !is_11d_country && !supplicant_priority) { + sms_log(mac_ctx, LOGW, + FL("Incorrect country req, nullify this")); + + /* we have got a request for a country that should not have been + * added since the STA is associated; nullify this request. If + * both countryCode11d[0] and countryCode11d[1] are zero, revert + * it to World domain to avoid from causing cfg80211 call trace. + */ + if ((mac_ctx->scan.countryCode11d[0] == 0) + && (mac_ctx->scan.countryCode11d[1] == 0)) + status = csr_get_regulatory_domain_for_country(mac_ctx, + "00", (v_REGDOMAIN_t *) ®_domain_id, + COUNTRY_IE); + else + status = csr_get_regulatory_domain_for_country(mac_ctx, + mac_ctx->scan.countryCode11d, + (v_REGDOMAIN_t *) ®_domain_id, + COUNTRY_IE); + + return CDF_STATUS_E_FAILURE; + } + /* if Supplicant country code has priority, disable 11d */ + if (!is_11d_country && supplicant_priority) + mac_ctx->roam.configParam.Is11dSupportEnabled = false; + cdf_mem_copy(mac_ctx->scan.countryCodeCurrent, msg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + status = wma_set_reg_domain(mac_ctx, reg_domain_id); + if (false == is_11d_country) { + /* overwrite the defualt country code */ + cdf_mem_copy(mac_ctx->scan.countryCodeDefault, + mac_ctx->scan.countryCodeCurrent, + WNI_CFG_COUNTRY_CODE_LEN); + /* set to default domain ID */ + mac_ctx->scan.domainIdDefault = mac_ctx->scan.domainIdCurrent; + } + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, FL("fail to set regId %d"), + reg_domain_id); + return status; + } else { + /* if 11d has priority, clear currentCountryBssid & + * countryCode11d to get set again if we find AP with 11d info + * during scan + */ + if (!supplicant_priority && (false == is_11d_country)) { + sms_log(mac_ctx, LOGW, + FL("Clearing currentCountryBssid, countryCode11d")); + cdf_mem_zero(&mac_ctx->scan.currentCountryBssid, + sizeof(struct cdf_mac_addr)); + cdf_mem_zero(mac_ctx->scan.countryCode11d, + sizeof(mac_ctx->scan.countryCode11d)); + } + } + /* get the channels based on new cc */ + status = csr_get_channel_and_power_list(mac_ctx); + + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, FL("fail to get Channels")); + return status; + } + /* reset info based on new cc, and we are done */ + csr_apply_channel_power_info_wrapper(mac_ctx); + + /* Country code Changed, Purge Only scan result + * which does not have channel number belong to 11d + * channel list + */ + csr_scan_filter_results(mac_ctx); + /* Do active scans after the country is set by User hints or + * Country IE + */ + mac_ctx->scan.curScanType = eSIR_ACTIVE_SCAN; + sme_disconnect_connected_sessions(mac_ctx); + sms_log(mac_ctx, LOG1, FL(" returned")); + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_handle_change_country_code_by_core + + \brief Update Country code in the driver if set by kernel as world + + If 11D is enabled, we update the country code after every scan & notify kernel. + This is to make sure kernel & driver are in sync in case of CC found in + driver but not in kernel database + + \param pMac - The handle returned by mac_open. + \param pMsg - Carrying new CC set in kernel + + \return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_handle_change_country_code_by_core(tpAniSirGlobal pMac, + tAniGenericChangeCountryCodeReq * + pMsg) +{ + CDF_STATUS status; + + sms_log(pMac, LOG1, FL(" called")); + + /* this is to make sure kernel & driver are in sync in case of CC found in */ + /* driver but not in kernel database */ + if (('0' == pMsg->countryCode[0]) && ('0' == pMsg->countryCode[1])) { + sms_log(pMac, LOGW, + FL + ("Setting countryCode11d & countryCodeCurrent to world CC")); + cdf_mem_copy(pMac->scan.countryCode11d, pMsg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + cdf_mem_copy(pMac->scan.countryCodeCurrent, pMsg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } + + status = wma_set_reg_domain(pMac, REGDOMAIN_WORLD); + + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to set regId")); + return status; + } else { + status = csr_get_channel_and_power_list(pMac); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to get Channels ")); + } else { + csr_apply_channel_and_power_list(pMac); + } + } + /* Country code Changed, Purge Only scan result + * which does not have channel number belong to 11d + * channel list + */ + csr_scan_filter_results(pMac); + sms_log(pMac, LOG1, FL(" returned")); + return CDF_STATUS_SUCCESS; +} + +static bool +sme_search_in_base_ch_lst(tpAniSirGlobal mac_ctx, uint8_t curr_ch) +{ + uint8_t i; + tCsrChannel *ch_lst_info; + ch_lst_info = &mac_ctx->scan.base_channels; + for (i = 0; i < ch_lst_info->numChannels; i++) { + if (ch_lst_info->channelList[i] == curr_ch) + return true; + } + + ch_lst_info = &mac_ctx->scan.base40MHzChannels; + for (i = 0; i < ch_lst_info->numChannels; i++) { + if (ch_lst_info->channelList[i] == curr_ch) + return true; + } + return false; +} +/** + * sme_disconnect_connected_sessions() - Disconnect STA and P2P client session + * if channel is not supported + * @mac_ctx: mac global context + * + * If new country code does not support the channel on which STA/P2P client + * is connetced, it sends the disconnect to the AP/P2P GO + * + * Return: void + */ +void sme_disconnect_connected_sessions(tpAniSirGlobal mac_ctx) +{ + uint8_t session_id, found = false; + uint8_t curr_ch; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (!csr_is_session_client_and_connected(mac_ctx, session_id)) + continue; + found = false; + /* Session is connected.Check the channel */ + curr_ch = csr_get_infra_operation_channel(mac_ctx, + session_id); + sms_log(mac_ctx, LOGW, + FL("Current Operating channel : %d, session :%d"), + curr_ch, session_id); + found = sme_search_in_base_ch_lst(mac_ctx, curr_ch); + if (!found) { + sms_log(mac_ctx, LOGW, FL("Disconnect Session :%d"), + session_id); + csr_roam_disconnect(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + } +} + +/* --------------------------------------------------------------------------- + + \fn sme_handle_generic_change_country_code + + \brief Change Country code, Reg Domain and channel list + + If Supplicant country code is priority than 11d is disabled. + If 11D is enabled, we update the country code after every scan. + Hence when Supplicant country code is priority, we don't need 11D info. + Country code from kernel is set as current country code. + + \param pMac - The handle returned by mac_open. + \param pMsgBuf - message buffer + + \return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_handle_generic_change_country_code(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + tAniGenericChangeCountryCodeReq *pMsg; + v_REGDOMAIN_t reg_domain_id; + + sms_log(pMac, LOG1, FL(" called")); + pMsg = (tAniGenericChangeCountryCodeReq *) pMsgBuf; + reg_domain_id = (v_REGDOMAIN_t) pMsg->domain_index; + + if (REGDOMAIN_COUNT == reg_domain_id) { + sme_handle_change_country_code_by_core(pMac, pMsg); + } else { + sme_handle_change_country_code_by_user(pMac, pMsg); + } + sms_log(pMac, LOG1, FL(" returned")); + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +CDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs) +{ + tpSirRcvFltMcAddrList request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s: " + "ulMulticastAddrCnt=%d, multicastAddr[0]=%p", __func__, + pMulticastAddrs->ulMulticastAddrCnt, + pMulticastAddrs->multicastAddr[0]); + + /* + *Find the connected Infra / P2P_client connected session + */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_infra(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + } + + if (pSession == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Unable to find " "the session Id: %d", __func__, + sessionId); + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "allocate memory for 8023 Multicast List request", + __func__); + return CDF_STATUS_E_NOMEM; + } + + if (!csr_is_conn_state_connected_infra(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Ignoring the " + "indication as we are not connected", __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(request_buf, pMulticastAddrs, + sizeof(tSirRcvFltMcAddrList)); + + cdf_mem_copy(request_buf->selfMacAddr, pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(request_buf->bssId, pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + msg.type = WMA_8023_MULTICAST_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "post WMA_8023_MULTICAST_LIST message to WMA", + __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_receive_filter_set_filter(tHalHandle hHal, + tpSirRcvPktFilterCfgType pRcvPktFilterCfg, + uint8_t sessionId) +{ + tpSirRcvPktFilterCfgType request_buf; + int32_t allocSize; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint8_t idx = 0; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s: filterType=%d, " + "filterId = %d", __func__, + pRcvPktFilterCfg->filterType, pRcvPktFilterCfg->filterId); + + allocSize = sizeof(tSirRcvPktFilterCfgType); + + request_buf = cdf_mem_malloc(allocSize); + + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "allocate memory for Receive Filter Set Filter request", + __func__); + return CDF_STATUS_E_NOMEM; + } + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Session Not found ", __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(pRcvPktFilterCfg->selfMacAddr, pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(pRcvPktFilterCfg->bssId, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(request_buf, pRcvPktFilterCfg, allocSize); + + msg.type = WMA_RECEIVE_FILTER_SET_FILTER_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "Pkt Flt Req : " + "FT %d FID %d ", + request_buf->filterType, request_buf->filterId); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "Pkt Flt Req : " + "params %d CT %d", + request_buf->numFieldParams, request_buf->coalesceTime); + + for (idx = 0; idx < request_buf->numFieldParams; idx++) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Proto %d Comp Flag %d ", + request_buf->paramsData[idx].protocolLayer, + request_buf->paramsData[idx].cmpFlag); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Data Offset %d Data Len %d", + request_buf->paramsData[idx].dataOffset, + request_buf->paramsData[idx].dataLength); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "CData: %d:%d:%d:%d:%d:%d", + request_buf->paramsData[idx].compareData[0], + request_buf->paramsData[idx].compareData[1], + request_buf->paramsData[idx].compareData[2], + request_buf->paramsData[idx].compareData[3], + request_buf->paramsData[idx].compareData[4], + request_buf->paramsData[idx].compareData[5]); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "MData: %d:%d:%d:%d:%d:%d", + request_buf->paramsData[idx].dataMask[0], + request_buf->paramsData[idx].dataMask[1], + request_buf->paramsData[idx].dataMask[2], + request_buf->paramsData[idx].dataMask[3], + request_buf->paramsData[idx].dataMask[4], + request_buf->paramsData[idx].dataMask[5]); + + } + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post " + "WMA_RECEIVE_FILTER_SET_FILTER message to WMA", + __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_receive_filter_clear_filter(tHalHandle hHal, + tpSirRcvFltPktClearParam + pRcvFltPktClearParam, uint8_t sessionId) +{ + tpSirRcvFltPktClearParam request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s: filterId = %d", + __func__, pRcvFltPktClearParam->filterId); + + request_buf = cdf_mem_malloc(sizeof(tSirRcvFltPktClearParam)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for Receive Filter " + "Clear Filter request", __func__); + return CDF_STATUS_E_NOMEM; + } + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Session Not find ", __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(pRcvFltPktClearParam->selfMacAddr, + pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(pRcvFltPktClearParam->bssId, + pSession->connectedProfile.bssid.bytes, sizeof(tSirMacAddr)); + + cdf_mem_copy(request_buf, pRcvFltPktClearParam, + sizeof(tSirRcvFltPktClearParam)); + + msg.type = WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post " + "WMA_RECEIVE_FILTER_CLEAR_FILTER message to WMA", + __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* --------------------------------------------------------------------------- + + \fn sme_is_channel_valid + + \brief To check if the channel is valid for currently established domain + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param channel - channel to verify + + \return true/false, true if channel is valid + + -------------------------------------------------------------------------------*/ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + bool valid = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + valid = csr_roam_is_channel_valid(pMac, channel); + + sme_release_global_lock(&pMac->sme); + } + + return valid; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_freq_band + \brief Used to set frequency band. + \param hHal + \param sessionId - Session Identifier + \eBand band value to be configured + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_band(hHal, sessionId, eBand); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_freq_band + \brief Used to get the current band settings. + \param hHal + \pBand pointer to hold band value + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_get_freq_band(tHalHandle hHal, eCsrBand *pBand) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + *pBand = csr_get_current_band(hHal); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_max_tx_power_per_band + + \brief Set the Maximum Transmit Power specific to band dynamically. + Note: this setting will not persist over reboots. + + \param band + \param power to set in dB + \- return CDF_STATUS + + ----------------------------------------------------------------------------*/ +CDF_STATUS sme_set_max_tx_power_per_band(eCsrBand band, int8_t dB) +{ + cds_msg_t msg; + tpMaxTxPowerPerBandParams pMaxTxPowerPerBandParams = NULL; + + pMaxTxPowerPerBandParams = + cdf_mem_malloc(sizeof(tMaxTxPowerPerBandParams)); + if (NULL == pMaxTxPowerPerBandParams) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s:Not able to allocate memory for pMaxTxPowerPerBandParams", + __func__); + return CDF_STATUS_E_NOMEM; + } + + pMaxTxPowerPerBandParams->power = dB; + pMaxTxPowerPerBandParams->bandInfo = band; + + msg.type = WMA_SET_MAX_TX_POWER_PER_BAND_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxPowerPerBandParams; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s:Not able to post WMA_SET_MAX_TX_POWER_PER_BAND_REQ", + __func__); + cdf_mem_free(pMaxTxPowerPerBandParams); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_max_tx_power + + \brief Set the Maximum Transmit Power dynamically. Note: this setting will + not persist over reboots. + + \param hHal + \param pBssid BSSID to set the power cap for + \param pBssid pSelfMacAddress self MAC Address + \param pBssid power to set in dB + \- return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_set_max_tx_power(tHalHandle hHal, tSirMacAddr pBssid, + tSirMacAddr pSelfMacAddress, int8_t dB) +{ + cds_msg_t msg; + tpMaxTxPowerParams pMaxTxParams = NULL; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, NO_SESSION, 0)); + pMaxTxParams = cdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pMaxTxParams", + __func__); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(pMaxTxParams->bssId, pBssid, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(pMaxTxParams->selfStaMacAddr, pSelfMacAddress, + CDF_MAC_ADDR_SIZE); + pMaxTxParams->power = dB; + + msg.type = WMA_SET_MAX_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxParams; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_MAX_TX_POWER_REQ message to WMA", + __func__); + cdf_mem_free(pMaxTxParams); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_custom_mac_addr + + \brief Set the customer Mac Address. + + \param customMacAddr customer MAC Address + \- return CDF_STATUS + + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr) +{ + cds_msg_t msg; + tSirMacAddr *pBaseMacAddr; + + pBaseMacAddr = cdf_mem_malloc(sizeof(tSirMacAddr)); + if (NULL == pBaseMacAddr) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for pBaseMacAddr")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(*pBaseMacAddr, customMacAddr, sizeof(tSirMacAddr)); + + msg.type = SIR_HAL_SET_BASE_MACADDR_IND; + msg.reserved = 0; + msg.bodyptr = pBaseMacAddr; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Not able to post SIR_HAL_SET_BASE_MACADDR_IND message to WMA")); + cdf_mem_free(pBaseMacAddr); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------- + \fn sme_set_tx_power + \brief Set Transmit Power dynamically. + \param hHal + \param sessionId Target Session ID + \pBSSId BSSID + \dev_mode dev_mode such as station, P2PGO, SAP + \param dBm power to set + \- return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_tx_power(tHalHandle hHal, uint8_t sessionId, + tSirMacAddr pBSSId, tCDF_CON_MODE dev_mode, int dBm) +{ + cds_msg_t msg; + tpMaxTxPowerParams pTxParams = NULL; + int8_t power = (int8_t) dBm; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, sessionId, 0)); + + /* make sure there is no overflow */ + if ((int)power != dBm) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: error, invalid power = %d", __func__, dBm); + return CDF_STATUS_E_FAILURE; + } + + pTxParams = cdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pTxParams) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pTxParams", + __func__); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(pTxParams->bssId, pBSSId, CDF_MAC_ADDR_SIZE); + pTxParams->power = power; /* unit is dBm */ + pTxParams->dev_mode = dev_mode; + msg.type = WMA_SET_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pTxParams; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: failed to post WMA_SET_TX_POWER_REQ to WMA", + __func__); + cdf_mem_free(pTxParams); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_hide_ssid + + \brief hide/show SSID dynamically. Note: this setting will + not persist over reboots. + + \param hHal + \param sessionId + \param ssidHidden 0 - Broadcast SSID, 1 - Disable broadcast SSID + \- return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_hide_ssid(tHalHandle hHal, uint8_t sessionId, uint8_t ssidHidden) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t len; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + tpSirUpdateParams pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!pSession->sessionActive) + CDF_ASSERT(0); + + /* Create the message and send to lim */ + len = sizeof(tSirUpdateParams); + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set(pMsg, sizeof(tSirUpdateParams), 0); + pMsg->messageType = eWNI_SME_HIDE_SSID_REQ; + pMsg->length = len; + /* Data starts from here */ + pMsg->sessionId = sessionId; + pMsg->ssidHidden = ssidHidden; + status = cds_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_tm_level + \brief Set Thermal Mitigation Level to RIVA + \param hHal - The handle returned by mac_open. + \param newTMLevel - new Thermal Mitigation Level + \param tmMode - Thermal Mitigation handle mode, default 0 + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, uint16_t tmMode) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniSetTmLevelReq *setTmLevelReq = NULL; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + setTmLevelReq = + (tAniSetTmLevelReq *) + cdf_mem_malloc(sizeof(tAniSetTmLevelReq)); + if (NULL == setTmLevelReq) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for sme_set_tm_level", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + setTmLevelReq->tmMode = tmMode; + setTmLevelReq->newTmLevel = newTMLevel; + + /* serialize the req through MC thread */ + cds_message.bodyptr = setTmLevelReq; + cds_message.type = WMA_SET_TM_LEVEL_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post Set TM Level MSG fail", __func__); + cdf_mem_free(setTmLevelReq); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*--------------------------------------------------------------------------- + + \brief sme_feature_caps_exchange() - SME interface to exchange capabilities between + Host and FW. + + \param hHal - HAL handle for device + + \return NONE + + ---------------------------------------------------------------------------*/ +void sme_feature_caps_exchange(tHalHandle hHal) +{ + MTRACE(cdf_trace + (CDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_CAPS_EXCH, NO_SESSION, + 0)); +} + +/*--------------------------------------------------------------------------- + + \brief sme_disable_feature_capablity() - SME interface to disable Active mode offload capablity + in Host. + + \param hHal - HAL handle for device + + \return NONE + + ---------------------------------------------------------------------------*/ +void sme_disable_feature_capablity(uint8_t feature_index) +{ +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_power_values_for5_g + \brief Reset the power values for 5G band with default power values. + \param hHal - HAL handle for device + \- return NONE + -------------------------------------------------------------------------*/ +void sme_reset_power_values_for5_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, NO_SESSION, 0)); + csr_save_channel_power_for_band(pMac, true); + csr_apply_power2_current(pMac); /* Store the channel+power info in the global place: Cfg */ +} + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/* --------------------------------------------------------------------------- + \fn sme_update_roam_prefer5_g_hz + \brief enable/disable Roam prefer 5G runtime option + This function is called through dynamic setConfig callback function + to configure the Roam prefer 5G runtime option + \param hHal - HAL handle for device + \param nRoamPrefer5GHz Enable/Disable Roam prefer 5G runtime option + \- return Success or failure + -------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, bool nRoamPrefer5GHz) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: gRoamPrefer5GHz is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamPrefer5GHz, + nRoamPrefer5GHz); + pMac->roam.configParam.nRoamPrefer5GHz = nRoamPrefer5GHz; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_intra_band + \brief enable/disable Intra band roaming + This function is called through dynamic setConfig callback function + to configure the intra band roaming + \param hHal - HAL handle for device + \param nRoamIntraBand Enable/Disable Intra band roaming + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: gRoamIntraBand is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamIntraBand, + nRoamIntraBand); + pMac->roam.configParam.nRoamIntraBand = nRoamIntraBand; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_scan_n_probes + \brief function to update roam scan N probes + This function is called through dynamic setConfig callback function + to update roam scan N probes + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nProbes number of probe requests to be sent out + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: gRoamScanNProbes is changed from %d to %d", + __func__, pMac->roam.configParam.nProbes, nProbes); + pMac->roam.configParam.nProbes = nProbes; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NPROBES_CHANGED); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_scan_home_away_time + \brief function to update roam scan Home away time + This function is called through dynamic setConfig callback function + to update roam scan home away time + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamScanAwayTime Scan home away time + \param bSendOffloadCmd If true then send offload command to firmware + If false then command is not sent to firmware + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: gRoamScanHomeAwayTime is changed from %d to %d", + __func__, + pMac->roam.configParam.nRoamScanHomeAwayTime, + nRoamScanHomeAwayTime); + pMac->roam.configParam.nRoamScanHomeAwayTime = + nRoamScanHomeAwayTime; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled && bSendOffloadCmd) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_HOME_AWAY_TIME_CHANGED); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_intra_band + \brief get Intra band roaming + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +bool sme_get_roam_intra_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND, NO_SESSION, 0)); + return pMac->roam.configParam.nRoamIntraBand; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_scan_n_probes + \brief get N Probes + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nProbes; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_scan_home_away_time + \brief get Roam scan home away time + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nRoamScanHomeAwayTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_rssi_diff + \brief Update RoamRssiDiff + This function is called through dynamic setConfig callback function + to configure RoamRssiDiff + Usage: adb shell iwpriv wlan0 setConfig RoamRssiDiff=[0 .. 125] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param RoamRssiDiff - minimum rssi difference between potential + candidate and current AP. + \- return Success or failure + -------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam rssi diff to %d - old value is %d - roam state is %s", + RoamRssiDiff, + pMac->roam.configParam.RoamRssiDiff, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.RoamRssiDiff = RoamRssiDiff; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_RSSI_DIFF_CHANGED); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_fast_transition_enabled() - enable/disable Fast Transition + support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isFastTransitionEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update isFastTransitionEnabled config + successfully. + Other status means SME is failed to update isFastTransitionEnabled. + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: FastTransitionEnabled is changed from %d to %d", + __func__, + pMac->roam.configParam.isFastTransitionEnabled, + isFastTransitionEnabled); + pMac->roam.configParam.isFastTransitionEnabled = + isFastTransitionEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_wes_mode + \brief Update WES Mode + This function is called through dynamic setConfig callback function + to configure isWESModeEnabled + \param hHal - HAL handle for device + \param isWESModeEnabled - WES mode + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS - SME update isWESModeEnabled config successfully. + Other status means SME is failed to update isWESModeEnabled. + -------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_wes_mode(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set WES Mode to %d - old value is %d - roam state is %s", + isWESModeEnabled, + pMac->roam.configParam.isWESModeEnabled, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.isWESModeEnabled = isWESModeEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_scan_control + \brief Set roam scan control + This function is called to set roam scan control + if roam scan control is set to 0, roaming scan cache is cleared + any value other than 0 is treated as invalid value + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME failure to update + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + MTRACE(cdf_trace(CDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan control to %d - old value is %d - roam state is %s", + roamScanControl, + pMac->roam.configParam.nRoamScanControl, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.nRoamScanControl = roamScanControl; + if (0 == roamScanControl) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully cleared roam scan cache"); + csr_flush_cfg_bg_scan_roam_channel_list(pMac, sessionId); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_FLUSH_CHANNEL_LIST); + } + } + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif /* (WLAN_FEATURE_VOWIFI_11R) || (FEATURE_WLAN_ESE) || (FEATURE_WLAN_LFR) */ + +#ifdef FEATURE_WLAN_LFR +/*-------------------------------------------------------------------------- + \brief sme_update_is_fast_roam_ini_feature_enabled() - enable/disable LFR + support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isFastRoamIniFeatureEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS - SME update isFastRoamIniFeatureEnabled config + successfully. + Other status means SME is failed to update isFastRoamIniFeatureEnabled. + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_update_is_fast_roam_ini_feature_enabled + (tHalHandle hHal, + uint8_t sessionId, const bool isFastRoamIniFeatureEnabled) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isFastRoamIniFeatureEnabled == + isFastRoamIniFeatureEnabled) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: FastRoam is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + return CDF_STATUS_SUCCESS; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: FastRoamEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + isFastRoamIniFeatureEnabled; + csr_neighbor_roam_update_fast_roaming_enabled(pMac, sessionId, + isFastRoamIniFeatureEnabled); + + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_is_mawc_ini_feature_enabled() - + Enable/disable LFR MAWC support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isMAWCIniFeatureEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update MAWCEnabled config successfully. + Other status means SME is failed to update MAWCEnabled. + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: MAWCEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.MAWCEnabled, MAWCEnabled); + pMac->roam.configParam.MAWCEnabled = MAWCEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/*-------------------------------------------------------------------------- + \brief sme_stop_roaming() - Stop roaming for a given sessionId + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS on success + Other status on failure + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP, + reason); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_start_roaming() - Start roaming for a given sessionId + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS on success + Other status on failure + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + reason); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_enable_fast_roam_in_concurrency() - enable/disable LFR if + Concurrent session exists + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS + Other status means SME is failed + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool + bFastRoamInConIniFeatureEnabled) +{ + + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + bFastRoamInConIniFeatureEnabled; + if (0 == pMac->roam.configParam.isRoamOffloadScanEnabled) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + 0; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_LFR */ + +#ifdef FEATURE_WLAN_ESE +/*-------------------------------------------------------------------------- + \brief sme_update_is_ese_feature_enabled() - enable/disable ESE support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isEseIniFeatureEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \param isEseIniFeatureEnabled - flag to enable/disable + \return CDF_STATUS_SUCCESS - SME update isEseIniFeatureEnabled config + successfully. + Other status means SME is failed to update isEseIniFeatureEnabled. + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_update_is_ese_feature_enabled + (tHalHandle hHal, uint8_t sessionId, const bool isEseIniFeatureEnabled) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isEseIniFeatureEnabled == + isEseIniFeatureEnabled) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: ESE Mode is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + return CDF_STATUS_SUCCESS; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: EseEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + pMac->roam.configParam.isEseIniFeatureEnabled = isEseIniFeatureEnabled; + csr_neighbor_roam_update_ese_mode_enabled(pMac, sessionId, + isEseIniFeatureEnabled); + + if (true == isEseIniFeatureEnabled) { + sme_update_fast_transition_enabled(hHal, true); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ESE_INI_CFG_CHANGED); + } + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ + +/*-------------------------------------------------------------------------- + \brief sme_update_config_fw_rssi_monitoring() - enable/disable firmware RSSI + Monitoring at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + fEnableFwRssiMonitoring. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update fEnableFwRssiMonitoring. + config successfully. + Other status means SME is failed to update fEnableFwRssiMonitoring. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_config_fw_rssi_monitoring(tHalHandle hHal, + bool fEnableFwRssiMonitoring) +{ + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + + if (sme_cfg_set_int (hHal, WNI_CFG_PS_ENABLE_RSSI_MONITOR, + fEnableFwRssiMonitoring) == CDF_STATUS_E_FAILURE) { + cdf_ret_status = CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Could not pass on WNI_CFG_PS_RSSI_MONITOR to CFG"); + } + + return cdf_ret_status; +} + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +/* --------------------------------------------------------------------------- + \fn sme_set_roam_opportunistic_scan_threshold_diff + \brief Update Opportunistic Scan threshold diff + This function is called through dynamic setConfig callback function + to configure nOpportunisticThresholdDiff + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nOpportunisticThresholdDiff - Opportunistic Scan threshold diff + \return CDF_STATUS_SUCCESS - SME update nOpportunisticThresholdDiff config + successfully. + else SME is failed to update nOpportunisticThresholdDiff. + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t + nOpportunisticThresholdDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_opportunistic_scan_threshold_diff(pMac, + sessionId, + nOpportunisticThresholdDiff); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set " + "opportunistic threshold diff to %d" + " - old value is %d - roam state is %d", + nOpportunisticThresholdDiff, + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff, + pMac->roam.neighborRoamInfo[sessionId]. + neighborRoamState); + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_opportunistic_scan_threshold_diff() + \brief gets Opportunistic Scan threshold diff + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nOpportunisticThresholdDiff + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_rescan_rssi_diff + \brief Update roam rescan rssi diff + This function is called through dynamic setConfig callback function + to configure nRoamRescanRssiDiff + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamRescanRssiDiff - roam rescan rssi diff + \return CDF_STATUS_SUCCESS - SME update nRoamRescanRssiDiff config + successfully. + else SME is failed to update nRoamRescanRssiDiff. + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_rescan_rssi_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_roam_rescan_rssi_diff(pMac, sessionId, + nRoamRescanRssiDiff); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set " + "opportunistic threshold diff to %d" + " - old value is %d - roam state is %d", + nRoamRescanRssiDiff, + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff, + pMac->roam.neighborRoamInfo[sessionId]. + neighborRoamState); + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff = nRoamRescanRssiDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_rescan_rssi_diff + \brief gets roam rescan rssi diff + This is a synchronous call + \param hHal - The handle returned by mac_open + \return int8_t - nRoamRescanRssiDiff + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_bmiss_first_bcnt + \brief Update Roam count for first beacon miss + This function is called through dynamic setConfig callback function + to configure nRoamBmissFirstBcnt + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBmissFirstBcnt - Roam first bmiss count + \return CDF_STATUS_SUCCESS - SME update nRoamBmissFirstBcnt + successfully. + else SME is failed to update nRoamBmissFirstBcnt + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_bmiss_first_bcnt(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFirstBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_roam_bmiss_first_bcnt(pMac, sessionId, + nRoamBmissFirstBcnt); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set " + "beacon miss first beacon count to %d" + " - old value is %d - roam state is %d", + nRoamBmissFirstBcnt, + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt, + pMac->roam.neighborRoamInfo[sessionId]. + neighborRoamState); + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt = nRoamBmissFirstBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_bmiss_first_bcnt + \brief get neighbor roam beacon miss first count + \param hHal - The handle returned by mac_open. + \return uint8_t - neighbor roam beacon miss first count + -------------------------------------------------------------------------*/ +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_bmiss_final_bcnt + \brief Update Roam count for final beacon miss + This function is called through dynamic setConfig callback function + to configure nRoamBmissFinalBcnt + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBmissFinalBcnt - Roam final bmiss count + \return CDF_STATUS_SUCCESS - SME update nRoamBmissFinalBcnt + successfully. + else SME is failed to update nRoamBmissFinalBcnt + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_bmiss_final_bcnt(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_roam_bmiss_final_bcnt(pMac, sessionId, + nRoamBmissFinalBcnt); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set " + "beacon miss final beacon count to %d" + " - old value is %d - roam state is %d", + nRoamBmissFinalBcnt, + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt, + pMac->roam.neighborRoamInfo[sessionId]. + neighborRoamState); + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt = nRoamBmissFinalBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_bmiss_final_bcnt + \brief gets Roam count for final beacon miss + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nRoamBmissFinalBcnt + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_beacon_rssi_weight + \brief Update Roam beacon rssi weight + This function is called through dynamic setConfig callback function + to configure nRoamBeaconRssiWeight + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBeaconRssiWeight - Roam beacon rssi weight + \return CDF_STATUS_SUCCESS - SME update nRoamBeaconRssiWeight config + successfully. + else SME is failed to update nRoamBeaconRssiWeight + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_roam_beacon_rssi_weight(pMac, sessionId, + nRoamBeaconRssiWeight); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set " + "beacon miss final beacon count to %d" + " - old value is %d - roam state is %d", + nRoamBeaconRssiWeight, + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight, + pMac->roam.neighborRoamInfo[sessionId]. + neighborRoamState); + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight = nRoamBeaconRssiWeight; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_beacon_rssi_weight + \brief gets Roam beacon rssi weight + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nRoamBeaconRssiWeight + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_neighbor_lookup_rssi_threshold() - update neighbor lookup + rssi threshold + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_set_neighbor_lookup_rssi_threshold + (tHalHandle hHal, uint8_t sessionId, uint8_t neighborLookupRssiThreshold) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_set_lookup_rssi_threshold(pMac, sessionId, + neighborLookupRssiThreshold); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set Lookup threshold to %d - old value is %d - roam state is %s", + neighborLookupRssiThreshold, + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold = + neighborLookupRssiThreshold; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_delay_before_vdev_stop() - update delay before VDEV_STOP + This is a synchronous call + \param hal - The handle returned by macOpen. + \param session_id - Session Identifier + \param delay_before_vdev_stop - value to be set + \return CDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hal, + uint8_t session_id, + uint8_t delay_before_vdev_stop) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL("LFR param delay_before_vdev_stop changed from %d to %d"), + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop, + delay_before_vdev_stop); + pMac->roam.neighborRoamInfo[session_id].cfgParams. + delay_before_vdev_stop = delay_before_vdev_stop; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = delay_before_vdev_stop; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_neighbor_lookup_rssi_threshold() - get neighbor lookup + rssi threshold + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_neighbor_scan_refresh_period() - set neighbor scan results + refresh period + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return CDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +CDF_STATUS sme_set_neighbor_scan_refresh_period + (tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan refresh period to %d- old value is %d - roam state is %s", + neighborScanResultsRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_roam_scan_offload_enabled() - enable/disable roam scan + offload feaure + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + gRoamScanOffloadEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME is failed to update. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL + ("gRoamScanOffloadEnabled is changed from %d to %d"), + pMac->roam.configParam.isRoamOffloadScanEnabled, + nRoamScanOffloadEnabled); + pMac->roam.configParam.isRoamOffloadScanEnabled = + nRoamScanOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_neighbor_scan_refresh_period() - get neighbor scan results + refresh period + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return uint16_t - Neighbor scan results refresh period value + \sa + --------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_empty_scan_refresh_period() - get empty scan refresh period + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return CDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_empty_scan_refresh_period + \brief Update nEmptyScanRefreshPeriod + This function is called through dynamic setConfig callback function + to configure nEmptyScanRefreshPeriod + Usage: adb shell iwpriv wlan0 setConfig + nEmptyScanRefreshPeriod=[0 .. 60] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nEmptyScanRefreshPeriod - scan period following empty scan results. + \- return Success or failure + -------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, uint8_t sessionId, + uint16_t nEmptyScanRefreshPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan period to %d -old value is %d - roam state is %s", + nEmptyScanRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nEmptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_EMPTY_SCAN_REF_PERIOD_CHANGED); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_min_chan_time + \brief Update nNeighborScanMinChanTime + This function is called through dynamic setConfig callback function + to configure gNeighborScanChannelMinTime + Usage: adb shell iwpriv wlan0 setConfig + gNeighborScanChannelMinTime=[0 .. 60] + \param hHal - HAL handle for device + \param nNeighborScanMinChanTime - Channel minimum dwell time + \param sessionId - Session Identifier + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t + nNeighborScanMinChanTime, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel min dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMinChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime = nNeighborScanMinChanTime; + pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime = nNeighborScanMinChanTime; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_max_chan_time + \brief Update nNeighborScanMaxChanTime + This function is called through dynamic setConfig callback function + to configure gNeighborScanChannelMaxTime + Usage: adb shell iwpriv wlan0 setConfig + gNeighborScanChannelMaxTime=[0 .. 60] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nNeighborScanMinChanTime - Channel maximum dwell time + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t sessionId, + const uint16_t + nNeighborScanMaxChanTime) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel max dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMaxChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanMaxChanTime = + nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + nNeighborScanMaxChanTime; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_CH_TIME_CHANGED); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_min_chan_time + \brief get neighbor scan min channel time + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - channel min time value + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_roam_state + \brief get neighbor roam state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - neighbor roam state + -------------------------------------------------------------------------*/ +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.neighborRoamInfo[sessionId].neighborRoamState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_current_roam_state + \brief get current roam state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - current roam state + -------------------------------------------------------------------------*/ +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.curState[sessionId]; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_current_roam_sub_state + \brief get neighbor roam sub state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - current roam sub state + -------------------------------------------------------------------------*/ +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.curSubState[sessionId]; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_sme_state + \brief get Lim Sme state + \param hHal - The handle returned by mac_open. + \return uint32_t - Lim Sme state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_sme_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gLimSmeState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_mlm_state + \brief get Lim Mlm state + \param hHal - The handle returned by mac_open. + \return uint32_t - Lim Mlm state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_mlm_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gLimMlmState; +} + +/* --------------------------------------------------------------------------- + \fn sme_is_lim_session_valid + \brief is Lim session valid + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return bool - true or false + -------------------------------------------------------------------------*/ +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gpSession[sessionId].valid; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_sme_session_state + \brief get Lim Sme session state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - Lim Sme session state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gpSession[sessionId].limSmeState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_mlm_session_state + \brief get Lim Mlm session state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - Lim Mlm session state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gpSession[sessionId].limMlmState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_max_chan_time + \brief get neighbor scan max channel time + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - channel max time value + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + maxChannelScanTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_period + \brief Update nNeighborScanPeriod + This function is called through dynamic setConfig callback function + to configure nNeighborScanPeriod + Usage: adb shell iwpriv wlan0 setConfig + nNeighborScanPeriod=[0 .. 1000] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nNeighborScanPeriod - neighbor scan period + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set neighbor scan period to %d" + " - old value is %d - roam state is %s", + nNeighborScanPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanTimerPeriod = + nNeighborScanPeriod; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + nNeighborScanPeriod; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_HOME_TIME_CHANGED); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_period + \brief get neighbor scan period + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - neighbor scan period + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + neighborScanPeriod; +} + +#endif + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + +/*-------------------------------------------------------------------------- + \brief sme_get_roam_rssi_diff() - get Roam rssi diff + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return uint16_t - Rssi diff value + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.RoamRssiDiff; +} + +/** + * sme_change_roam_scan_channel_list() - to change scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to Change roam scan channel list. + * This is a synchronous call + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t i = 0, j = 0; + tCsrChannelInfo *chan_info; + + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; + } + chan_info = &pNeighborRoamInfo->cfgParams.channelInfo; + + if (NULL != chan_info->ChannelList) { + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(oldChannelList)) + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - + j, "%d", + chan_info->ChannelList[i]); + else + break; + } + } + csr_flush_cfg_bg_scan_roam_channel_list(pMac, sessionId); + csr_create_bg_scan_roam_channel_list(pMac, sessionId, pChannelList, + numChannels); + sme_set_roam_scan_control(hHal, sessionId, 1); + if (NULL != chan_info->ChannelList) { + j = 0; + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(newChannelList)) + j += snprintf(newChannelList + j, + sizeof(newChannelList) - + j, " %d", + chan_info->ChannelList[i]); + else + break; + } + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("LFR runtime successfully set roam scan channels to %s - old value is %s - roam state is %d"), + newChannelList, oldChannelList, + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState); + sme_release_global_lock(&pMac->sme); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; +} + +#ifdef FEATURE_WLAN_ESE_UPLOAD +/** + * sme_set_ese_roam_scan_channel_list() - To set ese roam scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to set ese roam scan channel list. + * This is a synchronous call + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo + = &pMac->roam.neighborRoamInfo[sessionId]; + tpCsrChannelInfo curchnl_list_info + = &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[128] = { 0 }; + uint8_t i = 0, j = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; + } + if (NULL != curchnl_list_info->ChannelList) { + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + status = csr_create_roam_scan_channel_list(pMac, sessionId, + pChannelList, numChannels, + csr_get_current_band(hHal)); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (NULL != curchnl_list_info->ChannelList) { + j = 0; + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(newChannelList + j, + sizeof(newChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "ESE roam scan chnl list successfully set to %s-old value is %s-roam state is %d", + newChannelList, oldChannelList, + pNeighborRoamInfo->neighborRoamState); + } + sme_release_global_lock(&pMac->sme); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; +} +#endif + +/** + * sme_get_roam_scan_channel_list() - To get roam scan channel list + * @hHal: HAL pointer + * @pChannelList: Output channel list + * @pNumChannels: Output number of channels + * @sessionId: Session Identifier + * + * To get roam scan channel list This is a synchronous call + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_get_roam_scan_channel_list(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId) +{ + int i = 0; + uint8_t *pOutPtr = pChannelList; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + FL("Roam Scan channel list is NOT yet initialized")); + *pNumChannels = 0; + sme_release_global_lock(&pMac->sme); + return status; + } + + *pNumChannels = pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels; + for (i = 0; i < (*pNumChannels); i++) { + pOutPtr[i] = + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i]; + } + pOutPtr[i] = '\0'; + sme_release_global_lock(&pMac->sme); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_is_ese_feature_enabled() - get ESE feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the ESE feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_ese_feature_enabled(tHalHandle hHal) +{ +#ifdef FEATURE_WLAN_ESE + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return csr_roam_is_ese_ini_feature_enabled(pMac); +#else + return false; +#endif +} + +/*-------------------------------------------------------------------------- + \brief sme_get_wes_mode() - get WES Mode + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - WES Mode Enabled(1)/Disabled(0) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_wes_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isWESModeEnabled; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_roam_scan_control() - get scan control + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return bool - Enabled(1)/Disabled(0) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_roam_scan_control(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nRoamScanControl; +} +#endif + +/*-------------------------------------------------------------------------- + \brief sme_get_is_lfr_feature_enabled() - get LFR feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal) +{ +#ifdef FEATURE_WLAN_LFR + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; +#else + return false; +#endif +} + +/*-------------------------------------------------------------------------- + \brief sme_get_is_ft_feature_enabled() - get FT feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_ft_feature_enabled(tHalHandle hHal) +{ +#ifdef WLAN_FEATURE_VOWIFI_11R + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isFastTransitionEnabled; +#else + return false; +#endif +} + +/* --------------------------------------------------------------------------- + \fn sme_is_feature_supported_by_fw + \brief Check if an feature is enabled by FW + + \param feattEnumValue - Enumeration value from placeHolderInCapBitmap + \- return 1/0 (true/false) + -------------------------------------------------------------------------*/ +uint8_t sme_is_feature_supported_by_fw(uint8_t featEnumValue) +{ + return IS_FEATURE_SUPPORTED_BY_FW(featEnumValue); +} + +#ifdef FEATURE_WLAN_TDLS + +/* --------------------------------------------------------------------------- + \fn sme_send_tdls_link_establish_params + \brief API to send TDLS Peer Link Establishment Parameters. + + \param peerMac - peer's Mac Adress. + \param tdlsLinkEstablishParams - TDLS Peer Link Establishment Parameters + \- return CDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +CDF_STATUS sme_send_tdls_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_send_link_establish_params(hHal, sessionId, + peerMac, tdlsLinkEstablishParams); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_send_tdls_mgmt_frame + \brief API to send TDLS management frames. + + \param peerMac - peer's Mac Adress. + \param frame_type - Type of TDLS mgmt frame to be sent. + \param dialog - dialog token used in the frame. + \param status - status to be incuded in the frame. + \param peerCapability - peer cpabilities + \param buf - additional IEs to be included + \param len - lenght of additional Ies + \param responder - Tdls request type + \- return CDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +CDF_STATUS sme_send_tdls_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + uint8_t frame_type, + uint8_t dialog, uint16_t statusCode, + uint32_t peerCapability, uint8_t *buf, + uint8_t len, uint8_t responder) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrTdlsSendMgmt sendTdlsReq = { {0} }; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_copy(sendTdlsReq.peerMac, peerMac, sizeof(tSirMacAddr)); + sendTdlsReq.frameType = frame_type; + sendTdlsReq.buf = buf; + sendTdlsReq.len = len; + sendTdlsReq.dialog = dialog; + sendTdlsReq.statusCode = statusCode; + sendTdlsReq.responder = responder; + sendTdlsReq.peerCapability = peerCapability; + + status = csr_tdls_send_mgmt_req(hHal, sessionId, &sendTdlsReq); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_change_tdls_peer_sta + \brief API to Update TDLS peer sta parameters. + + \param peerMac - peer's Mac Adress. + \param staParams - Peer Station Parameters + \- return CDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +CDF_STATUS sme_change_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pstaParams) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s :pstaParams is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_change_peer_sta(hHal, sessionId, peerMac, + pstaParams); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_add_tdls_peer_sta + \brief API to Add TDLS peer sta entry. + + \param peerMac - peer's Mac Adress. + \- return CDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +CDF_STATUS sme_add_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_add_peer_sta(hHal, sessionId, peerMac); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_delete_tdls_peer_sta + \brief API to Delete TDLS peer sta entry. + + \param peerMac - peer's Mac Adress. + \- return CDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +CDF_STATUS sme_delete_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_del_peer_sta(hHal, sessionId, peerMac); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_set_tdls_power_save_prohibited + \API to set/reset the is_tdls_power_save_prohibited. + + \- return void + -------------------------------------------------------------------------*/ +void sme_set_tdls_power_save_prohibited(tHalHandle hHal, uint32_t sessionId, + bool val) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[sessionId]; + ps_param->is_tdls_power_save_prohibited = val; + return; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_fw_tdls_state + + \brief + SME will send message to WMA to set TDLS state in f/w + + \param + + hHal - The handle returned by mac_open + + psmeTdlsParams - TDLS state info to update in f/w + + useSmeLock - Need to acquire SME Global Lock before state update or not + + \return CDF_STATUS + --------------------------------------------------------------------------- */ +CDF_STATUS sme_update_fw_tdls_state(tHalHandle hHal, void *psmeTdlsParams, + bool useSmeLock) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = NULL; + cds_msg_t cds_message; + + /* only acquire sme global lock before state update if asked to */ + if (useSmeLock) { + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) + return CDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS != status) + return status; + } + + /* serialize the req through MC thread */ + cds_message.bodyptr = psmeTdlsParams; + cds_message.type = WMA_UPDATE_FW_TDLS_STATE; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + /* release the lock if it was acquired */ + if (useSmeLock) + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_update_tdls_peer_state() - to update the state of TDLS peer + * @hHal: The handle returned by mac_open + * @peerStateParams: TDLS Peer state info to update in f/w + * + * SME will send message to WMA to set TDLS Peer state in f/w + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_update_tdls_peer_state(tHalHandle hHal, + tSmeTdlsPeerStateParams *peerStateParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tTdlsPeerStateParams *pTdlsPeerStateParams = NULL; + tTdlsPeerCapParams *peer_cap = NULL; + cds_msg_t cds_message; + uint8_t num; + uint8_t chanId; + uint8_t i; + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + pTdlsPeerStateParams = cdf_mem_malloc(sizeof(*pTdlsPeerStateParams)); + if (NULL == pTdlsPeerStateParams) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("failed to allocate mem for tdls peer state param")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pTdlsPeerStateParams, sizeof(*pTdlsPeerStateParams)); + cdf_mem_copy(&pTdlsPeerStateParams->peerMacAddr, + &peerStateParams->peerMacAddr, sizeof(tSirMacAddr)); + pTdlsPeerStateParams->vdevId = peerStateParams->vdevId; + pTdlsPeerStateParams->peerState = peerStateParams->peerState; + + switch (peerStateParams->peerState) { + case eSME_TDLS_PEER_STATE_PEERING: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_PEERING; + break; + + case eSME_TDLS_PEER_STATE_CONNECTED: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_CONNECTED; + break; + + case eSME_TDLS_PEER_STATE_TEARDOWN: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_TEARDOWN; + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("invalid peer state param (%d)"), + peerStateParams->peerState); + cdf_mem_free(pTdlsPeerStateParams); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + peer_cap = &(pTdlsPeerStateParams->peerCap); + peer_cap->isPeerResponder = + peerStateParams->peerCap.isPeerResponder; + peer_cap->peerUapsdQueue = + peerStateParams->peerCap.peerUapsdQueue; + peer_cap->peerMaxSp = + peerStateParams->peerCap.peerMaxSp; + peer_cap->peerBuffStaSupport = + peerStateParams->peerCap.peerBuffStaSupport; + peer_cap->peerOffChanSupport = + peerStateParams->peerCap.peerOffChanSupport; + peer_cap->peerCurrOperClass = + peerStateParams->peerCap.peerCurrOperClass; + peer_cap->selfCurrOperClass = + peerStateParams->peerCap.selfCurrOperClass; + + num = 0; + for (i = 0; i < peerStateParams->peerCap.peerChanLen; i++) { + chanId = peerStateParams->peerCap.peerChan[i]; + if (!csr_roam_is_channel_valid(pMac, chanId)) + continue; + peer_cap->peerChan[num].chanId = chanId; + peer_cap->peerChan[num].pwr = + csr_get_cfg_max_tx_power(pMac, chanId); + + if (cds_get_channel_state(chanId) == CHANNEL_STATE_DFS) + peer_cap->peerChan[num].dfsSet = + true; + else + peer_cap->peerChan[num].dfsSet = + false; + num++; + } + peer_cap->peerChanLen = num; + peer_cap->peerOperClassLen = + peerStateParams->peerCap.peerOperClassLen; + for (i = 0; i < HAL_TDLS_MAX_SUPP_OPER_CLASSES; i++) { + peer_cap->peerOperClass[i] = + peerStateParams->peerCap.peerOperClass[i]; + } + + peer_cap->prefOffChanNum = + peerStateParams->peerCap.prefOffChanNum; + peer_cap->prefOffChanBandwidth = + peerStateParams->peerCap.prefOffChanBandwidth; + + if (peerStateParams->peerCap.opClassForPrefOffChanIsSet) { + peer_cap->opClassForPrefOffChan = + peerStateParams->peerCap.opClassForPrefOffChan; + } else { + /* + * redgm opclass table contains opclass for 40MHz low + * primary, 40MHz high primary and 20MHz. No support + * for 80MHz yet. So first we will check if bit for + * 40MHz is set and if so find matching opclass either + * with low primary or high primary (a channel would + * never be in both) and then search for opclass + * matching 20MHz, else for any BW. + */ + if (peer_cap->prefOffChanBandwidth & + (1 << BW_40_OFFSET_BIT)) { + peer_cap->opClassForPrefOffChan = + cds_regdm_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + peer_cap->prefOffChanNum, + BW40_LOW_PRIMARY); + if (!peer_cap->opClassForPrefOffChan) { + peer_cap->opClassForPrefOffChan = + cds_regdm_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + peer_cap->prefOffChanNum, + BW40_HIGH_PRIMARY); + } + } else if (peer_cap->prefOffChanBandwidth & + (1 << BW_20_OFFSET_BIT)) { + peer_cap->opClassForPrefOffChan = + cds_regdm_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + peer_cap->prefOffChanNum, + BW20); + } else { + peer_cap->opClassForPrefOffChan = + cds_regdm_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + peer_cap->prefOffChanNum, + BWALL); + } + } + cds_message.type = WMA_UPDATE_TDLS_PEER_STATE; + cds_message.reserved = 0; + cds_message.bodyptr = pTdlsPeerStateParams; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + cdf_mem_free(pTdlsPeerStateParams); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_send_tdls_chan_switch_req() - send tdls channel switch request + * @hal: UMAC handler + * @ch_switch_params: Pointer to the chan switch parameter structure + * + * API to set tdls channel switch parameters. + * + * Return: CDF_STATUS_SUCCESS on success; another CDF_STATUS_* code otherwise + */ +CDF_STATUS sme_send_tdls_chan_switch_req(tHalHandle hal, + sme_tdls_chan_switch_params *ch_switch_params) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tdls_chan_switch_params *chan_switch_params = NULL; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&mac->sme); + if (CDF_STATUS_SUCCESS != status) + return status; + chan_switch_params = cdf_mem_malloc(sizeof(*chan_switch_params)); + if (NULL == chan_switch_params) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("fail to alloc mem for tdls chan switch param")); + sme_release_global_lock(&mac->sme); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_zero(chan_switch_params, sizeof(*chan_switch_params)); + + switch (ch_switch_params->tdls_off_ch_mode) { + case ENABLE_CHANSWITCH: + chan_switch_params->tdls_sw_mode = WMA_TDLS_ENABLE_OFFCHANNEL; + break; + + case DISABLE_CHANSWITCH: + chan_switch_params->tdls_sw_mode = WMA_TDLS_DISABLE_OFFCHANNEL; + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("invalid off channel command (%d)"), + ch_switch_params->tdls_off_ch_mode); + cdf_mem_free(chan_switch_params); + sme_release_global_lock(&mac->sme); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(&chan_switch_params->peer_mac_addr, + &ch_switch_params->peer_mac_addr, sizeof(tSirMacAddr)); + chan_switch_params->vdev_id = ch_switch_params->vdev_id; + chan_switch_params->tdls_off_ch = ch_switch_params->tdls_off_channel; + chan_switch_params->tdls_off_ch_bw_offset = + ch_switch_params->tdls_off_ch_bw_offset; + chan_switch_params->is_responder = ch_switch_params->is_responder; + + switch (chan_switch_params->tdls_off_ch_bw_offset) { + case (1 << BW_20_OFFSET_BIT): + chan_switch_params->oper_class = + cds_regdm_get_opclass_from_channel( + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch, + BW20); + break; + case (1 << BW_40_OFFSET_BIT): + chan_switch_params->oper_class = + cds_regdm_get_opclass_from_channel( + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch, + BW40_LOW_PRIMARY); + if (!chan_switch_params->oper_class) { + chan_switch_params->oper_class = + cds_regdm_get_opclass_from_channel( + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch, + BW40_HIGH_PRIMARY); + } + break; + default: + chan_switch_params->oper_class = + cds_regdm_get_opclass_from_channel( + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch, + BWALL); + break; + } /* end switch */ + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Country Code=%s, Req offset=%d, Selected Operate Class=%d"), + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch_bw_offset, + chan_switch_params->oper_class); + + cds_message.type = WMA_TDLS_SET_OFFCHAN_MODE; + cds_message.reserved = 0; + cds_message.bodyptr = chan_switch_params; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Message Post failed status=%d"), + cdf_status); + cdf_mem_free(chan_switch_params); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} +#endif /* FEATURE_WLAN_TDLS */ + +CDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)) +{ + + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + if ((NULL == pCallbackfn) && + (NULL == pMac->sme.pLinkSpeedIndCb)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back did not registered", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pLinkSpeedCbContext = plsContext; + pMac->sme.pLinkSpeedIndCb = pCallbackfn; + } + /* serialize the req through MC thread */ + cds_message.bodyptr = lsReq; + cds_message.type = WMA_GET_LINK_SPEED; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post Link Speed msg fail", __func__); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "SSR level is changed %d", enableSSR); + /* not serializing this messsage, as this is only going + * to set a variable in WMA/WDI + */ + WMA_SetEnableSSR(enableSSR); + sme_release_global_lock(&pMac->sme); + } + return; +} + +CDF_STATUS sme_check_ch_in_band(tpAniSirGlobal mac_ctx, uint8_t start_ch, + uint8_t ch_cnt) +{ + uint8_t i; + for (i = 0; i < ch_cnt; i++) { + if (CDF_STATUS_SUCCESS != csr_is_valid_channel(mac_ctx, + (start_ch + i*4))) + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +void sme_set_160bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, + chan_params_t *ch_params) +{ + uint8_t start_ch = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (channel >= 36 && channel <= 64) { + ch_params->center_freq_seg0 = 50; + start_ch = 36; + } else if (channel >= 100 && channel <= 128) { + ch_params->center_freq_seg0 = 114; + start_ch = 100; + } else { + ch_params->ch_width = CH_WIDTH_80MHZ; + } + + if (ch_params->ch_width == CH_WIDTH_160MHZ) + status = sme_check_ch_in_band(mac_ctx, start_ch, 8); + + if (CDF_STATUS_SUCCESS != status) + ch_params->ch_width = CH_WIDTH_80MHZ; +} + +void sme_set_80bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, + chan_params_t *ch_params) +{ + uint8_t start_ch = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (channel >= 36 && channel <= 48) { + ch_params->center_freq_seg0 = 42; + start_ch = 36; + } else if (channel >= 52 && channel <= 64) { + ch_params->center_freq_seg0 = 58; + start_ch = 52; + } else if (channel >= 100 && channel <= 112) { + ch_params->center_freq_seg0 = 106; + start_ch = 100; + } else if (channel >= 116 && channel <= 128) { + ch_params->center_freq_seg0 = 122; + start_ch = 116; + } else if (channel >= 132 && channel <= 144) { + ch_params->center_freq_seg0 = 138; + start_ch = 132; + } else if (channel >= 149 && channel <= 161) { + ch_params->center_freq_seg0 = 155; + start_ch = 149; + } else { + ch_params->ch_width = CH_WIDTH_40MHZ; + } + + if (ch_params->ch_width == CH_WIDTH_80MHZ) + status = sme_check_ch_in_band(mac_ctx, start_ch, 4); + + if (CDF_STATUS_SUCCESS != status) + ch_params->ch_width = CH_WIDTH_40MHZ; +} + +void sme_set_40bw_params(tpAniSirGlobal mac_ctx, uint8_t channel, + chan_params_t *ch_params, uint8_t is_11ac_mode) +{ + uint8_t tmp; + uint8_t center_freq = 0; + bool valid_40Mhz_ch = true; + + if (channel == 165) { + ch_params->ch_width = CH_WIDTH_20MHZ; + ch_params->center_freq_seg0 = 0; + ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; + return; + } + tmp = channel % 2; + if ((channel - tmp) % 8) { + ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + center_freq = channel + 2; + } else { + ch_params->sec_ch_offset = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + center_freq = channel - 2; + } + if ((!is_11ac_mode) || (is_11ac_mode && + (ch_params->ch_width == CH_WIDTH_40MHZ))) { + ch_params->ch_width = CH_WIDTH_40MHZ; + ch_params->center_freq_seg0 = center_freq; + valid_40Mhz_ch = csr_roam_is_valid40_mhz_channel(mac_ctx, + ch_params->center_freq_seg0); + } + if (!valid_40Mhz_ch) { + ch_params->ch_width = CH_WIDTH_20MHZ; + ch_params->center_freq_seg0 = 0; + ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; + } +} + +/* + * SME API to determine the channel bonding mode + */ +CDF_STATUS sme_set_ch_params(tHalHandle hHal, eCsrPhyMode eCsrPhyMode, + uint8_t channel, uint8_t ht_sec_ch, chan_params_t *ch_params) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + int is_11ac_mode = CSR_IS_PHY_MODE_11ac(eCsrPhyMode); + + if (!CSR_IS_PHY_MODE_11n(eCsrPhyMode) || + ch_params->ch_width == CH_WIDTH_20MHZ || + CDF_STATUS_SUCCESS != csr_is_valid_channel(mac_ctx, channel)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid Channel/phymode config: CB Mode disabled", + __func__); + ch_params->ch_width = CH_WIDTH_20MHZ; + ch_params->sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; + if (channel <= 14) + mac_ctx->roam.configParam.channelBondingMode24GHz = + PHY_SINGLE_CHANNEL_CENTERED; + else + mac_ctx->roam.configParam.channelBondingMode5GHz = + PHY_SINGLE_CHANNEL_CENTERED; + return CDF_STATUS_SUCCESS; + } + + sms_log(mac_ctx, LOGW, "%s: channel - %d, vht channel width - %d", + __func__, channel, ch_params->ch_width); + + if (CDS_IS_CHANNEL_5GHZ(channel)) { + if (ch_params->ch_width == CH_WIDTH_160MHZ) + sme_set_160bw_params(mac_ctx, channel, ch_params); + if ((ch_params->ch_width == CH_WIDTH_80MHZ) || + (ch_params->ch_width == CH_WIDTH_80P80MHZ)) + sme_set_80bw_params(mac_ctx, channel, ch_params); + + sme_set_40bw_params(mac_ctx, channel, + ch_params, is_11ac_mode); + + mac_ctx->roam.configParam.channelBondingMode5GHz = + ch_params->sec_ch_offset; + } else if (CDS_IS_CHANNEL_24GHZ(channel)) { + if (channel >= 1 && channel < 5) { + ch_params->ch_width = CH_WIDTH_40MHZ; + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + ch_params->center_freq_seg0 = channel + 2; + } else if (channel >= 5 && channel <= 9) { + ch_params->ch_width = CH_WIDTH_40MHZ; + if (0 != ht_sec_ch) { + if (ht_sec_ch > channel) { + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + ch_params->center_freq_seg0 = + channel + 2; + } else { + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = + channel - 2; + } + } else { + /* in case ht_sec_ch is not set by ACS or + * calling function, set the secondary channel + * offset value to lower channel + */ + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = channel - 2; + } + } else if (channel > 9 && channel <= 13) { + ch_params->ch_width = CH_WIDTH_40MHZ; + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = channel - 2; + } else if (channel == 14) { + ch_params->ch_width = CH_WIDTH_20MHZ; + ch_params->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + ch_params->center_freq_seg0 = 0; + } + mac_ctx->roam.configParam.channelBondingMode24GHz = + ch_params->sec_ch_offset; + } + return CDF_STATUS_SUCCESS; +} + +/*convert the ini value to the ENUM used in csr and MAC for CB state*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value) +{ + return csr_convert_cb_ini_value_to_phy_cb_state(cb_ini_value); +} + +/*-------------------------------------------------------------------------- + + \brief sme_set_curr_device_mode() - Sets the current operating device mode. + \param hHal - The handle returned by mac_open. + \param currDeviceMode - Current operating device mode. + --------------------------------------------------------------------------*/ + +void sme_set_curr_device_mode(tHalHandle hHal, tCDF_CON_MODE currDeviceMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->sme.currDeviceMode = currDeviceMode; + return; +} + +/*-------------------------------------------------------------------------- + \brief sme_handoff_request() - a wrapper function to Request a handoff + from CSR. + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \param pHandoffInfo - info provided by HDD with the handoff request (namely: + BSSID, channel etc.) + \return CDF_STATUS_SUCCESS - SME passed the request to CSR successfully. + Other status means SME is failed to send the request. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_handoff_request(tHalHandle hHal, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: invoked", __func__); + status = csr_handoff_request(pMac, sessionId, pHandoffInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef IPA_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_ipa_offload_enable_disable + \brief API to enable/disable IPA offload + \param hal - The handle returned by macOpen. + \param session_id - Session Identifier + \param request - Pointer to the offload request. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, uint8_t session_id, + struct sir_ipa_offload_enable_disable *request) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + struct sir_ipa_offload_enable_disable *request_buf; + cds_msg_t msg; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + request_buf = cdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for \ + IPA_OFFLOAD_ENABLE_DISABLE")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + request_buf->offload_type = request->offload_type; + request_buf->vdev_id = request->vdev_id; + request_buf->enable = request->enable; + + msg.type = WMA_IPA_OFFLOAD_ENABLE_DISABLE; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDS_MQ_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_IPA_OFFLOAD_\ + ENABLE_DISABLE message to WMA")); + cdf_mem_free(request_buf); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + + return CDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ + +/* + * SME API to check if there is any infra station or + * P2P client is connected + */ +CDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + if (csr_is_infra_connected(pMac)) { + return CDF_STATUS_SUCCESS; + } + return CDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_LPHB +/* --------------------------------------------------------------------------- + \fn sme_lphb_config_req + \API to make configuration LPHB within FW. + \param hHal - The handle returned by mac_open + \param lphdReq - LPHB request argument by client + \param pCallbackfn - LPHB timeout notification callback function pointer + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +CDF_STATUS sme_lphb_config_req + (tHalHandle hHal, + tSirLPHBReq *lphdReq, + void (*pCallbackfn)(void *pHddCtx, tSirLPHBInd *indParam) + ) { + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + if ((LPHB_SET_EN_PARAMS_INDID == lphdReq->cmd) && + (NULL == pCallbackfn) && (NULL == pMac->sme.pLphbIndCb)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back did not registered", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pLphbIndCb = pCallbackfn; + } + + /* serialize the req through MC thread */ + cds_message.bodyptr = lphdReq; + cds_message.type = WMA_LPHB_CONF_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post Config LPHB MSG fail", __func__); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_LPHB */ +/*-------------------------------------------------------------------------- + \brief sme_enable_disable_split_scan() - a wrapper function to set the split + scan parameter. + This is a synchronous call + \param hHal - The handle returned by mac_open + \return NONE. + \sa + --------------------------------------------------------------------------*/ +void sme_enable_disable_split_scan(tHalHandle hHal, uint8_t nNumStaChan, + uint8_t nNumP2PChan) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->roam.configParam.nNumStaChanCombinedConc = nNumStaChan; + pMac->roam.configParam.nNumP2PChanCombinedConc = nNumP2PChan; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: SCAN nNumStaChanCombinedConc : %d," + "nNumP2PChanCombinedConc : %d ", + __func__, nNumStaChan, nNumP2PChan); + + return; + +} + +/** + * sme_add_periodic_tx_ptrn() - Add Periodic TX Pattern + * @hal: global hal handle + * @addPeriodicTxPtrnParams: request message + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS +sme_add_periodic_tx_ptrn(tHalHandle hal, + struct sSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirAddPeriodicTxPtrn *req_msg; + cds_msg_t msg; + + sms_log(mac, LOG1, FL("enter")); + + req_msg = cdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return CDF_STATUS_E_NOMEM; + } + + *req_msg = *addPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_ADD_PERIODIC_TX_PTRN_IND; + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_del_periodic_tx_ptrn() - Delete Periodic TX Pattern + * @hal: global hal handle + * @delPeriodicTxPtrnParams: request message + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS +sme_del_periodic_tx_ptrn(tHalHandle hal, + struct sSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirDelPeriodicTxPtrn *req_msg; + cds_msg_t msg; + + sms_log(mac, LOG1, FL("enter")); + + req_msg = cdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return CDF_STATUS_E_NOMEM; + } + + *req_msg = *delPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_DEL_PERIODIC_TX_PTRN_IND; + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +void sme_get_command_q_status(tHalHandle hHal) +{ + tSmeCmd *pTempCmd = NULL; + tListElem *pEntry; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: pMac is NULL", __func__); + return; + } + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + sms_log(pMac, LOGE, "Currently smeCmdActiveList has command (0x%X)", + (pTempCmd) ? pTempCmd->command : eSmeNoCommand); + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + } /* if(pTempCmd) */ + + sms_log(pMac, LOGE, "Currently smeCmdPendingList has %d commands", + csr_ll_count(&pMac->sme.smeCmdPendingList)); + + sms_log(pMac, LOGE, "Currently roamCmdPendingList has %d commands", + csr_ll_count(&pMac->roam.roamCmdPendingList)); + + return; +} + +/** + * sme_set_dot11p_config() - API to set the 802.11p config + * @hHal: The handle returned by macOpen + * @enable_dot11p: 802.11p config param + */ +void sme_set_dot11p_config(tHalHandle hHal, bool enable_dot11p) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->enable_dot11p = enable_dot11p; +} + +/** + * copy_sir_ocb_config() - Performs deep copy of an OCB configuration + * @src: the source configuration + * + * Return: pointer to the copied OCB configuration + */ +static struct sir_ocb_config *sme_copy_sir_ocb_config( + struct sir_ocb_config *src) +{ + struct sir_ocb_config *dst; + uint32_t length; + void *cursor; + + length = sizeof(*src) + + src->channel_count * sizeof(*src->channels) + + src->schedule_size * sizeof(*src->schedule) + + src->dcc_ndl_chan_list_len + + src->dcc_ndl_active_state_list_len; + + dst = cdf_mem_malloc(length); + if (!dst) + return NULL; + + *dst = *src; + + cursor = dst; + cursor += sizeof(*dst); + dst->channels = cursor; + cursor += src->channel_count * sizeof(*src->channels); + cdf_mem_copy(dst->channels, src->channels, + src->channel_count * sizeof(*src->channels)); + dst->schedule = cursor; + cursor += src->schedule_size * sizeof(*src->schedule); + cdf_mem_copy(dst->schedule, src->schedule, + src->schedule_size * sizeof(*src->schedule)); + dst->dcc_ndl_chan_list = cursor; + cursor += src->dcc_ndl_chan_list_len; + cdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, + src->dcc_ndl_chan_list_len); + dst->dcc_ndl_active_state_list = cursor; + cursor += src->dcc_ndl_active_state_list_len; + cdf_mem_copy(dst->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list_len); + return dst; +} + +/** + * sme_ocb_set_config() - Set the OCB configuration + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @config: the OCB configuration + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_ocb_set_config(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_config *config) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_config *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + /* + * Check if there is a pending request and return an error if one + * exists + */ + if (pMac->sme.ocb_set_config_callback) { + status = CDF_STATUS_E_BUSY; + goto end; + } + + msg_body = sme_copy_sir_ocb_config(config); + + if (!msg_body) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + + msg.type = WMA_OCB_SET_CONFIG_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and context */ + pMac->sme.ocb_set_config_callback = callback; + pMac->sme.ocb_set_config_context = context; + + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.ocb_set_config_callback = callback; + pMac->sme.ocb_set_config_context = context; + cdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_set_utc_time() - Set the OCB UTC time + * @hHal: reference to the HAL + * @utc: the UTC time struct + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_ocb_set_utc_time(tHalHandle hHal, struct sir_ocb_utc *utc) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_utc *sme_utc; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + sme_utc = cdf_mem_malloc(sizeof(*sme_utc)); + if (!sme_utc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Malloc failed")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + *sme_utc = *utc; + + msg.type = WMA_OCB_SET_UTC_TIME_CMD; + msg.reserved = 0; + msg.bodyptr = sme_utc; + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post message to WDA")); + cdf_mem_free(utc); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_start_timing_advert() - Start sending timing advert frames + * @hHal: reference to the HAL + * @timing_advert: the timing advertisement struct + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_ocb_start_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + void *buf; + struct sir_ocb_timing_advert *sme_timing_advert; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + buf = cdf_mem_malloc(sizeof(*sme_timing_advert) + + timing_advert->template_length); + if (!buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for start TA")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + + sme_timing_advert = (struct sir_ocb_timing_advert *)buf; + *sme_timing_advert = *timing_advert; + sme_timing_advert->template_value = buf + sizeof(*sme_timing_advert); + cdf_mem_copy(sme_timing_advert->template_value, + timing_advert->template_value, timing_advert->template_length); + + msg.type = WMA_OCB_START_TIMING_ADVERT_CMD; + msg.reserved = 0; + msg.bodyptr = buf; + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_stop_timing_advert() - Stop sending timing advert frames on a channel + * @hHal: reference to the HAL + * @timing_advert: the timing advertisement struct + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_ocb_stop_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_timing_advert *sme_timing_advert; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + sme_timing_advert = cdf_mem_malloc(sizeof(*timing_advert)); + if (!sme_timing_advert) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for stop TA")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + *sme_timing_advert = *timing_advert; + + msg.type = WMA_OCB_STOP_TIMING_ADVERT_CMD; + msg.reserved = 0; + msg.bodyptr = sme_timing_advert; + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_get_tsf_timer() - Get the TSF timer value + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the TSF timer request + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_ocb_get_tsf_timer(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_get_tsf_timer *request) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_get_tsf_timer *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = cdf_mem_malloc(sizeof(*msg_body)); + if (!msg_body) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + *msg_body = *request; + + msg.type = WMA_OCB_GET_TSF_TIMER_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and the context */ + pMac->sme.ocb_get_tsf_timer_callback = callback; + pMac->sme.ocb_get_tsf_timer_context = context; + + /* Post the message to WDA */ + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.ocb_get_tsf_timer_callback = NULL; + pMac->sme.ocb_get_tsf_timer_context = NULL; + cdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_get_stats() - Get the DCC stats + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the get DCC stats request + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_dcc_get_stats(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_get_stats *request) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_get_stats *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = cdf_mem_malloc(sizeof(*msg_body) + + request->request_array_len); + if (!msg_body) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + *msg_body = *request; + msg_body->request_array = (void *)msg_body + sizeof(*msg_body); + cdf_mem_copy(msg_body->request_array, request->request_array, + request->request_array_len); + + msg.type = WMA_DCC_GET_STATS_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and context */ + pMac->sme.dcc_get_stats_callback = callback; + pMac->sme.dcc_get_stats_context = context; + + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.dcc_get_stats_callback = callback; + pMac->sme.dcc_get_stats_context = context; + cdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_clear_stats() - Clear the DCC stats + * @hHal: reference to the HAL + * @vdev_id: vdev id for OCB interface + * @dcc_stats_bitmap: the entries in the stats to clear + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_dcc_clear_stats(tHalHandle hHal, uint32_t vdev_id, + uint32_t dcc_stats_bitmap) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_clear_stats *request; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + request = cdf_mem_malloc(sizeof(struct sir_dcc_clear_stats)); + if (!request) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + + cdf_mem_zero(request, sizeof(*request)); + request->vdev_id = vdev_id; + request->dcc_stats_bitmap = dcc_stats_bitmap; + + msg.type = WMA_DCC_CLEAR_STATS_CMD; + msg.bodyptr = request; + + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + cdf_mem_free(request); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_update_ndl() - Update the DCC settings + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the update DCC request + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_dcc_update_ndl(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_update_ndl *request) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_update_ndl *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = cdf_mem_malloc(sizeof(*msg_body) + + request->dcc_ndl_chan_list_len + + request->dcc_ndl_active_state_list_len); + if (!msg_body) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + + *msg_body = *request; + + msg_body->dcc_ndl_chan_list = (void *)msg_body + sizeof(*msg_body); + msg_body->dcc_ndl_active_state_list = msg_body->dcc_ndl_chan_list + + request->dcc_ndl_chan_list_len; + cdf_mem_copy(msg_body->dcc_ndl_chan_list, request->dcc_ndl_chan_list, + request->dcc_ndl_active_state_list_len); + cdf_mem_copy(msg_body->dcc_ndl_active_state_list, + request->dcc_ndl_active_state_list, + request->dcc_ndl_active_state_list_len); + + msg.type = WMA_DCC_UPDATE_NDL_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and the context */ + pMac->sme.dcc_update_ndl_callback = callback; + pMac->sme.dcc_update_ndl_context = context; + + status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.dcc_update_ndl_callback = NULL; + pMac->sme.dcc_update_ndl_context = NULL; + cdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_register_for_dcc_stats_event() - Register for the periodic DCC stats + * event + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure + */ +CDF_STATUS sme_register_for_dcc_stats_event(tHalHandle hHal, void *context, + ocb_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&pMac->sme); + pMac->sme.dcc_stats_event_callback = callback; + pMac->sme.dcc_stats_event_context = context; + sme_release_global_lock(&pMac->sme); + + return 0; +} + +void sme_get_recovery_stats(tHalHandle hHal) +{ + uint8_t i; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Self Recovery Stats"); + for (i = 0; i < MAX_ACTIVE_CMD_STATS; i++) { + if (eSmeNoCommand != + g_self_recovery_stats.activeCmdStats[i].command) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "timestamp %llu: command 0x%0X: reason %d: session %d", + g_self_recovery_stats.activeCmdStats[i]. + timestamp, + g_self_recovery_stats.activeCmdStats[i].command, + g_self_recovery_stats.activeCmdStats[i].reason, + g_self_recovery_stats.activeCmdStats[i]. + sessionId); + } + } +} + +/** + * sme_save_active_cmd_stats() - To save active command stats + * @hHal: HAL context + * + * This routine is to save active command stats + * + * Return: None + */ +void sme_save_active_cmd_stats(tHalHandle hHal) +{ + tSmeCmd *pTempCmd = NULL; + tListElem *pEntry; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t statidx = 0; + tActiveCmdStats *actv_cmd_stat = NULL; + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("pMac is NULL")); + return; + } + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + + if (!pTempCmd) + return; + + if (eSmeCsrCommandMask & pTempCmd->command) { + statidx = g_self_recovery_stats.cmdStatsIndx; + actv_cmd_stat = &g_self_recovery_stats.activeCmdStats[statidx]; + actv_cmd_stat->command = pTempCmd->command; + actv_cmd_stat->sessionId = pTempCmd->sessionId; + actv_cmd_stat->timestamp = cds_get_monotonic_boottime(); + if (eSmeCommandRoam == pTempCmd->command) + actv_cmd_stat->reason = pTempCmd->u.roamCmd.roamReason; + else if (eSmeCommandScan == pTempCmd->command) + actv_cmd_stat->reason = pTempCmd->u.scanCmd.reason; + else + actv_cmd_stat->reason = 0xFF; + + g_self_recovery_stats.cmdStatsIndx = + ((g_self_recovery_stats.cmdStatsIndx + 1) & + (MAX_ACTIVE_CMD_STATS - 1)); + } + return; +} + +void active_list_cmd_timeout_handle(void *userData) +{ + if (NULL == userData) + return; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Active List command timeout Cmd List Count %d", __func__, + csr_ll_count(&((tpAniSirGlobal) userData)->sme. + smeCmdActiveList)); + sme_get_command_q_status((tHalHandle) userData); + + if (((tpAniSirGlobal) userData)->sme.enableSelfRecovery) { + sme_save_active_cmd_stats((tHalHandle) userData); + cds_trigger_recovery(); + } else { + CDF_BUG(0); + } +} + +CDF_STATUS sme_notify_modem_power_state(tHalHandle hHal, uint32_t value) +{ + cds_msg_t msg; + tpSirModemPowerStateInd request_buf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(tSirModemPowerStateInd)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for MODEM POWER STATE IND", + __func__); + return CDF_STATUS_E_NOMEM; + } + + request_buf->param = value; + + msg.type = WMA_MODEM_POWER_STATE_IND; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_MODEM_POWER_STATE_IND message" + " to WMA", __func__); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef QCA_HT_2040_COEX +CDF_STATUS sme_notify_ht2040_mode(tHalHandle hHal, uint16_t staId, + struct cdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type) +{ + cds_msg_t msg; + tUpdateVHTOpMode *pHtOpMode = NULL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + return CDF_STATUS_E_FAILURE; + } + + pHtOpMode = cdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for setting OP mode", + __func__); + return CDF_STATUS_E_NOMEM; + } + + switch (channel_type) { + case eHT_CHAN_HT20: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_20MHZ; + break; + + case eHT_CHAN_HT40MINUS: + case eHT_CHAN_HT40PLUS: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_40MHZ; + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid OP mode", __func__); + return CDF_STATUS_E_FAILURE; + } + + pHtOpMode->staId = staId, + cdf_mem_copy(pHtOpMode->peer_mac, macAddrSTA.bytes, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_UPDATE_OP_MODE message" + " to WMA", __func__); + cdf_mem_free(pHtOpMode); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Notifed FW about OP mode: %d for staId=%d", + __func__, pHtOpMode->opMode, staId); + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_ht2040_mode + + \brief To update HT Operation beacon IE. + + \param + + \return CDF_STATUS SUCCESS + FAILURE or RESOURCES + The API finished and failed. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_set_ht2040_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ePhyChanBondState cbMode; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Update HT operation beacon IE, channel_type=%d", + __func__, channel_type); + + switch (channel_type) { + case eHT_CHAN_HT20: + cbMode = PHY_SINGLE_CHANNEL_CENTERED; + break; + case eHT_CHAN_HT40MINUS: + cbMode = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + case eHT_CHAN_HT40PLUS: + cbMode = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s:Error!!! Invalid HT20/40 mode !", __func__); + return CDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_ht2040_mode(pMac, sessionId, + cbMode, obssEnabled); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_phy_cb_mode24_g + + \brief Changes PHY channel bonding mode + + \param hHal - The handle returned by mac_open. + + \param cbMode new channel bonding mode which is to set + + \return CDF_STATUS SUCCESS. + + -------------------------------------------------------------------------------*/ +CDF_STATUS sme_set_phy_cb_mode24_g(tHalHandle hHal, ePhyChanBondState phyCBMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + return CDF_STATUS_E_FAILURE; + } + + pMac->roam.configParam.channelBondingMode24GHz = phyCBMode; + + return CDF_STATUS_SUCCESS; +} +#endif + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +CDF_STATUS sme_set_idle_powersave_config(void *cds_context, + tHalHandle hHal, uint32_t value) +{ + void *wmaContext = cds_get_context(CDF_MODULE_ID_WMA); + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == wmaContext) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: wmaContext is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + " Idle Ps Set Value %d", value); + + pMac->imps_enabled = false; + if (CDF_STATUS_SUCCESS != wma_set_idle_ps_config(wmaContext, value)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + " Failed to Set Idle Ps Value %d", value); + return CDF_STATUS_E_FAILURE; + } + if (value) + pMac->imps_enabled = true; + return CDF_STATUS_SUCCESS; +} + +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, uint16_t ht_capab) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + return pSession->htConfig.ht_rx_ldpc; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + return pSession->htConfig.ht_tx_stbc; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + return pSession->htConfig.ht_rx_stbc; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + return pSession->htConfig.ht_sgi; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "invalid ht capability"); + return -EIO; + } +} + +int sme_update_ht_config(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + + if (CDF_STATUS_SUCCESS != wma_set_htconfig(sessionId, htCapab, value)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to set ht capability in target"); + return -EIO; + } + + switch (htCapab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pSession->htConfig.ht_rx_ldpc = value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pSession->htConfig.ht_tx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pSession->htConfig.ht_rx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + pSession->htConfig.ht_sgi = value; + break; + } + + return 0; +} + +#define HT20_SHORT_GI_MCS7_RATE 722 +/* --------------------------------------------------------------------------- + \fn sme_send_rate_update_ind + \brief API to Update rate + \param hHal - The handle returned by mac_open + \param rateUpdateParams - Pointer to rate update params + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status; + cds_msg_t msg; + tSirRateUpdateInd *rate_upd = cdf_mem_malloc(sizeof(tSirRateUpdateInd)); + + if (rate_upd == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Rate update struct alloc failed"); + return CDF_STATUS_E_FAILURE; + } + *rate_upd = *rateUpdateParams; + + if (rate_upd->mcastDataRate24GHz == HT20_SHORT_GI_MCS7_RATE) + rate_upd->mcastDataRate24GHzTxFlag = + eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + else if (rate_upd->reliableMcastDataRate == + HT20_SHORT_GI_MCS7_RATE) + rate_upd->reliableMcastDataRateTxFlag = + eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + msg.type = WMA_RATE_UPDATE_IND; + msg.bodyptr = rate_upd; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able " + "to post WMA_SET_RMC_RATE_IND to WMA!", + __func__); + + sme_release_global_lock(&pMac->sme); + cdf_mem_free(rate_upd); + return CDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_SUCCESS; + } + + return status; +} + +/** + * sme_get_reg_info() - To get registration info + * @hHal: HAL context + * @chanId: channel id + * @regInfo1: first reg info to fill + * @regInfo2: second reg info to fill + * + * This routine will give you reg info + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status; + uint8_t i; + bool found = false; + + status = sme_acquire_global_lock(&pMac->sme); + *regInfo1 = 0; + *regInfo2 = 0; + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + + for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pMac->scan.defaultPowerTable[i].chanId == chanId) { + SME_SET_CHANNEL_REG_POWER(*regInfo1, + pMac->scan.defaultPowerTable[i].pwr); + + SME_SET_CHANNEL_MAX_TX_POWER(*regInfo2, + pMac->scan.defaultPowerTable[i].pwr); + found = true; + break; + } + } + if (!found) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + return status; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/* --------------------------------------------------------------------------- + \fn sme_auto_shutdown_cb + \brief Used to plug in callback function for receiving auto shutdown evt + \param hHal + \param pCallbackfn : callback function pointer should be plugged in + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void) + ) { + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Plug in Auto shutdown event callback", __func__); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + if (NULL != pCallbackfn) { + pMac->sme.pAutoShutdownNotificationCb = pCallbackfn; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_auto_shutdown_timer + \API to set auto shutdown timer value in FW. + \param hHal - The handle returned by mac_open + \param timer_val - The auto shutdown timer value to be set + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_auto_shutdown_timer(tHalHandle hHal, uint32_t timer_val) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirAutoShutdownCmdParams *auto_sh_cmd; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + auto_sh_cmd = (tSirAutoShutdownCmdParams *) + cdf_mem_malloc(sizeof(tSirAutoShutdownCmdParams)); + if (auto_sh_cmd == NULL) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s Request Buffer Alloc Fail", __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + auto_sh_cmd->timer_val = timer_val; + + /* serialize the req through MC thread */ + cds_message.bodyptr = auto_sh_cmd; + cds_message.type = WMA_SET_AUTO_SHUTDOWN_TIMER_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post Auto shutdown MSG fail", __func__); + cdf_mem_free(auto_sh_cmd); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Posted Auto shutdown MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +/* --------------------------------------------------------------------------- + \fn sme_add_ch_avoid_callback + \brief Used to plug in callback function + Which notify channel may not be used with SAP or P2PGO mode. + Notification come from FW. + \param hHal + \param pCallbackfn : callback function pointer should be plugged in + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_add_ch_avoid_callback + (tHalHandle hHal, void (*pCallbackfn)(void *pAdapter, void *indParam) + ) { + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Plug in CH AVOID CB", __func__); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + if (NULL != pCallbackfn) { + pMac->sme.pChAvoidNotificationCb = pCallbackfn; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ch_avoid_update_req + \API to request channel avoidance update from FW. + \param hHal - The handle returned by mac_open + \param update_type - The udpate_type parameter of this request call + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirChAvoidUpdateReq *cauReq; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + cauReq = (tSirChAvoidUpdateReq *) + cdf_mem_malloc(sizeof(tSirChAvoidUpdateReq)); + if (NULL == cauReq) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "%s Request Buffer Alloc Fail", __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_NOMEM; + } + + cauReq->reserved_param = 0; + + /* serialize the req through MC thread */ + cds_message.bodyptr = cauReq; + cds_message.type = WMA_CH_AVOID_UPDATE_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Post Ch Avoid Update MSG fail", + __func__); + cdf_mem_free(cauReq); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Posted Ch Avoid Update MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * sme_set_miracast() - Function to set miracast value to UMAC + * @hal: Handle returned by macOpen + * @filter_type: 0-Disabled, 1-Source, 2-sink + * + * This function passes down the value of miracast set by + * framework to UMAC + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +CDF_STATUS sme_set_miracast(tHalHandle hal, uint8_t filter_type) +{ + cds_msg_t msg; + uint32_t *val; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + val = cdf_mem_malloc(sizeof(*val)); + if (NULL == val || NULL == mac_ptr) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Invalid pointer", __func__); + return CDF_STATUS_E_NOMEM; + } + + *val = filter_type; + + msg.type = SIR_HAL_SET_MIRACAST; + msg.reserved = 0; + msg.bodyptr = val; + + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + cdf_mem_free(val); + return CDF_STATUS_E_FAILURE; + } + + mac_ptr->sme.miracast_value = filter_type; + return CDF_STATUS_SUCCESS; +} + +/** + * sme_set_mas() - Function to set MAS value to UMAC + * @val: 1-Enable, 0-Disable + * + * This function passes down the value of MAS to the UMAC. A + * value of 1 will enable MAS and a value of 0 will disable MAS + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +CDF_STATUS sme_set_mas(uint32_t val) +{ + cds_msg_t msg; + uint32_t *ptr_val; + + ptr_val = cdf_mem_malloc(sizeof(*ptr_val)); + if (NULL == ptr_val) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: could not allocate ptr_val", __func__); + return CDF_STATUS_E_NOMEM; + } + + *ptr_val = val; + + msg.type = SIR_HAL_SET_MAS; + msg.reserved = 0; + msg.bodyptr = ptr_val; + + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + cdf_mem_free(ptr_val); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/* ------------------------------------------------------------------------- + \fn sme_roam_channel_change_req + \brief API to Indicate Channel change to new target channel + \param hHal - The handle returned by mac_open + \param targetChannel - New Channel to move the SAP to. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct cdf_mac_addr bssid, uint32_t cb_mode, tCsrRoamProfile *profile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t ch_mode; + + ch_mode = (profile->ChannelInfo.ChannelList[0] <= + CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS) ? + pMac->roam.configParam.channelBondingMode24GHz : + pMac->roam.configParam.channelBondingMode5GHz; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: requested cbmode=[%d] & new negotiated cbmode[%d]"), + cb_mode, ch_mode); + status = csr_roam_channel_change_req(pMac, bssid, ch_mode, + profile); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* ------------------------------------------------------------------------- + \fn sme_process_channel_change_resp + \brief API to Indicate Channel change response message to SAP. + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_process_channel_change_resp(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo proam_info = { 0 }; + eCsrRoamResult roamResult; + tpSwitchChannelParams pChnlParams = (tpSwitchChannelParams) pMsgBuf; + uint32_t SessionId = pChnlParams->peSessionId; + + proam_info.channelChangeRespEvent = + (tSirChanChangeResponse *) + cdf_mem_malloc(sizeof(tSirChanChangeResponse)); + if (NULL == proam_info.channelChangeRespEvent) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + "Channel Change Event Allocation Failed: %d\n", status); + return status; + } + if (msg_type == eWNI_SME_CHANNEL_CHANGE_RSP) { + proam_info.channelChangeRespEvent->sessionId = SessionId; + proam_info.channelChangeRespEvent->newChannelNumber = + pChnlParams->channelNumber; + proam_info.channelChangeRespEvent->secondaryChannelOffset = + pChnlParams->ch_width; + + if (pChnlParams->status == CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received success eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 1; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received failure eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 0; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + } + + csr_roam_call_callback(pMac, SessionId, &proam_info, 0, + eCSR_ROAM_SET_CHANNEL_RSP, roamResult); + + } else { + status = CDF_STATUS_E_FAILURE; + sms_log(pMac, LOGE, "Invalid Channel Change Resp Message: %d\n", + status); + } + cdf_mem_free(proam_info.channelChangeRespEvent); + + return status; +} + +/* ------------------------------------------------------------------------- + \fn sme_roam_start_beacon_req + \brief API to Indicate LIM to start Beacon Tx + \after SAP CAC Wait is completed. + \param hHal - The handle returned by mac_open + \param sessionId - session ID + \param dfsCacWaitStatus - CAC WAIT status flag + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, struct cdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_start_beacon_req(pMac, bssid, dfsCacWaitStatus); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* ------------------------------------------------------------------------- + \fn sme_roam_csa_ie_request + \brief API to request CSA IE transmission from PE + \param hHal - The handle returned by mac_open + \param pDfsCsaReq - CSA IE request + \param bssid - SAP bssid + \param ch_bandwidth - Channel offset + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct cdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, + uint8_t ch_bandwidth) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_send_chan_sw_ie_request(pMac, bssid, targetChannel, + csaIeReqd, ch_bandwidth); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_init_thermal_info + \brief SME API to initialize the thermal mitigation parameters + \param hHal + \param thermalParam : thermal mitigation parameters + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_init_thermal_info(tHalHandle hHal, tSmeThermalParams thermalParam) +{ + t_thermal_mgmt *pWmaParam; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pWmaParam = (t_thermal_mgmt *) cdf_mem_malloc(sizeof(t_thermal_mgmt)); + if (NULL == pWmaParam) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: could not allocate tThermalMgmt", __func__); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero((void *)pWmaParam, sizeof(t_thermal_mgmt)); + + pWmaParam->thermalMgmtEnabled = thermalParam.smeThermalMgmtEnabled; + pWmaParam->throttlePeriod = thermalParam.smeThrottlePeriod; + pWmaParam->thermalLevels[0].minTempThreshold = + thermalParam.smeThermalLevels[0].smeMinTempThreshold; + pWmaParam->thermalLevels[0].maxTempThreshold = + thermalParam.smeThermalLevels[0].smeMaxTempThreshold; + pWmaParam->thermalLevels[1].minTempThreshold = + thermalParam.smeThermalLevels[1].smeMinTempThreshold; + pWmaParam->thermalLevels[1].maxTempThreshold = + thermalParam.smeThermalLevels[1].smeMaxTempThreshold; + pWmaParam->thermalLevels[2].minTempThreshold = + thermalParam.smeThermalLevels[2].smeMinTempThreshold; + pWmaParam->thermalLevels[2].maxTempThreshold = + thermalParam.smeThermalLevels[2].smeMaxTempThreshold; + pWmaParam->thermalLevels[3].minTempThreshold = + thermalParam.smeThermalLevels[3].smeMinTempThreshold; + pWmaParam->thermalLevels[3].maxTempThreshold = + thermalParam.smeThermalLevels[3].smeMaxTempThreshold; + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + msg.type = WMA_INIT_THERMAL_INFO_CMD; + msg.bodyptr = pWmaParam; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_INFO_CMD to WMA!", + __func__); + cdf_mem_free(pWmaParam); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_SUCCESS; + } + cdf_mem_free(pWmaParam); + return CDF_STATUS_E_FAILURE; +} + +/** + * sme_add_set_thermal_level_callback() - Plug in set thermal level callback + * @hal: Handle returned by macOpen + * @callback: sme_set_thermal_level_callback + * + * Plug in set thermal level callback + * + * Return: none + */ +void sme_add_set_thermal_level_callback(tHalHandle hal, + sme_set_thermal_level_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + pMac->sme.set_thermal_level_cb = callback; +} + +/** + * sme_set_thermal_level() - SME API to set the thermal mitigation level + * @hal: Handler to HAL + * @level: Thermal mitigation level + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_set_thermal_level(tHalHandle hal, uint8_t level) +{ + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + cdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_THERMAL_LEVEL; + msg.bodyval = level; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_LEVEL to WMA!", + __func__); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_SUCCESS; + } + return CDF_STATUS_E_FAILURE; +} + +/* --------------------------------------------------------------------------- + \fn sme_txpower_limit + \brief SME API to set txpower limits + \param hHal + \param psmetx : power limits for 2g/5g + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t cds_message; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + cds_message.type = WMA_TX_POWER_LIMIT; + cds_message.reserved = 0; + cds_message.bodyptr = psmetx; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_TX_POWER_LIMIT", + __func__); + status = CDF_STATUS_E_FAILURE; + cdf_mem_free(psmetx); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +CDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->fEnableDebugLog = set_value; + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ap_disable_intra_bss_fwd + + \brief + SME will send message to WMA to set Intra BSS in txrx + + \param + + hHal - The handle returned by mac_open + + sessionId - session id ( vdev id) + + disablefwd - bool value that indicate disable intrabss fwd disable + + \return CDF_STATUS + --------------------------------------------------------------------------- */ +CDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, + bool disablefwd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + int status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t cds_message; + tpDisableIntraBssFwd pSapDisableIntraFwd = NULL; + + /* Prepare the request to send to SME. */ + pSapDisableIntraFwd = cdf_mem_malloc(sizeof(tDisableIntraBssFwd)); + if (NULL == pSapDisableIntraFwd) { + sms_log(pMac, LOGP, "Memory Allocation Failure!!! %s", __func__); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pSapDisableIntraFwd, sizeof(tDisableIntraBssFwd)); + + pSapDisableIntraFwd->sessionId = sessionId; + pSapDisableIntraFwd->disableintrabssfwd = disablefwd; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = pSapDisableIntraFwd; + cds_message.type = WMA_SET_SAP_INTRABSS_DIS; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + status = CDF_STATUS_E_FAILURE; + cdf_mem_free(pSapDisableIntraFwd); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_STATS_EXT + +/****************************************************************************** + \fn sme_stats_ext_register_callback + + \brief + a function called to register the callback that send vendor event for stats + ext + + \param callback - callback to be registered +******************************************************************************/ +void sme_stats_ext_register_callback(tHalHandle hHal, StatsExtCallback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.StatsExtCallback = callback; +} + +/****************************************************************************** + \fn sme_stats_ext_request + + \brief + a function called when HDD receives STATS EXT vendor command from userspace + + \param sessionID - vdevID for the stats ext request + + \param input - Stats Ext Request structure ptr + + \return CDF_STATUS +******************************************************************************/ +CDF_STATUS sme_stats_ext_request(uint8_t session_id, tpStatsExtRequestReq input) +{ + cds_msg_t msg; + tpStatsExtRequest data; + size_t data_len; + + data_len = sizeof(tStatsExtRequest) + input->request_data_len; + data = cdf_mem_malloc(data_len); + + if (data == NULL) { + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(data, data_len); + data->vdev_id = session_id; + data->request_data_len = input->request_data_len; + if (input->request_data_len) { + cdf_mem_copy(data->request_data, + input->request_data, input->request_data_len); + } + + msg.type = WMA_STATS_EXT_REQUEST; + msg.reserved = 0; + msg.bodyptr = data; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_STATS_EXT_REQUEST message to WMA", + __func__); + cdf_mem_free(data); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/****************************************************************************** + \fn sme_stats_ext_event + + \brief + a callback function called when SME received eWNI_SME_STATS_EXT_EVENT + response from WMA + + \param hHal - HAL handle for device + \param pMsg - Message body passed from WMA; includes NAN header + \return CDF_STATUS +******************************************************************************/ +CDF_STATUS sme_stats_ext_event(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (NULL == pMsg) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + status = CDF_STATUS_E_FAILURE; + } else { + sms_log(pMac, LOG2, "SME: entering %s", __func__); + + if (pMac->sme.StatsExtCallback) { + pMac->sme.StatsExtCallback(pMac->hHdd, + (tpStatsExtEvent) pMsg); + } + } + + return status; +} + +#endif + +/* --------------------------------------------------------------------------- + \fn sme_update_dfs_scan_mode + \brief Update DFS roam scan mode + This function is called through dynamic setConfig callback function + to configure allowDFSChannelRoam. + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param allowDFSChannelRoam - DFS roaming scan mode 0 (disable), + 1 (passive), 2 (active) + \return CDF_STATUS_SUCCESS - SME update DFS roaming scan config + successfully. + Other status means SME failed to update DFS roaming scan config. + \sa + -------------------------------------------------------------------------*/ +CDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t allowDFSChannelRoam) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set AllowDFSChannelRoam Mode to " + "%d - old value is %d - roam state is %s", + allowDFSChannelRoam, + pMac->roam.configParam.allowDFSChannelRoam, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.allowDFSChannelRoam = + allowDFSChannelRoam; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_DFS_SCAN_MODE_CHANGED); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_dfs_scan_mode() - get DFS roam scan mode + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return DFS roaming scan mode 0 (disable), 1 (passive), 2 (active) + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.allowDFSChannelRoam; +} + +/*---------------------------------------------------------------------------- + \fn sme_modify_add_ie + \brief This function sends msg to updates the additional IE buffers in PE + \param hHal - global structure + \param pModifyIE - pointer to tModifyIE structure + \param updateType - type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +CDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_modify_add_ies(pMac, pModifyIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*---------------------------------------------------------------------------- + \fn sme_update_add_ie + \brief This function sends msg to updates the additional IE buffers in PE + \param hHal - global structure + \param pUpdateIE - pointer to structure tUpdateIE + \param updateType - type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +CDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_update_add_ies(pMac, pUpdateIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_sta_in_middle_of_roaming + \brief This function returns true if STA is in the middle of roaming state + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \- return true or false + -------------------------------------------------------------------------*/ +bool sme_sta_in_middle_of_roaming(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool ret = false; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + ret = csr_neighbor_middle_of_roaming(hHal, sessionId); + sme_release_global_lock(&pMac->sme); + } + return ret; +} + + +/** + * sme_update_dsc_pto_up_mapping() + * @hHal: HAL context + * @dscpmapping: pointer to DSCP mapping structure + * @sessionId: SME session id + * + * This routine is called to update dscp mapping + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_update_dsc_pto_up_mapping(tHalHandle hHal, + sme_QosWmmUpType *dscpmapping, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t i, j, peSessionId; + tCsrRoamSession *pCsrSession = NULL; + tpPESession pSession = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + pCsrSession = CSR_GET_SESSION(pMac, sessionId); + if (pCsrSession == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Session lookup fails for CSR session")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Invalid session Id %u"), sessionId); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + pSession = pe_find_session_by_bssid(pMac, + pCsrSession->connectedProfile.bssid.bytes, + &peSessionId); + + if (pSession == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL(" Session lookup fails for BSSID")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + + if (!pSession->QosMapSet.present) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("QOS Mapping IE not present")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } + for (i = 0; i < SME_QOS_WMM_UP_MAX; i++) { + for (j = pSession->QosMapSet.dscp_range[i][0]; + j <= pSession->QosMapSet.dscp_range[i][1]; + j++) { + if ((pSession->QosMapSet.dscp_range[i][0] == 255) + && (pSession->QosMapSet.dscp_range[i][1] == + 255)) { + dscpmapping[j] = 0; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("User Priority %d isn't used"), i); + break; + } else { + dscpmapping[j] = i; + } + } + } + for (i = 0; i < pSession->QosMapSet.num_dscp_exceptions; i++) + if (pSession->QosMapSet.dscp_exceptions[i][0] != 255) + dscpmapping[pSession->QosMapSet.dscp_exceptions[i][0]] = + pSession->QosMapSet.dscp_exceptions[i][1]; + + sme_release_global_lock(&pMac->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_abort_roam_scan + \brief API to abort current roam scan cycle by roam scan offload module. + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return CDF_STATUS + ---------------------------------------------------------------------------*/ + +CDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOGW, "entering function %s", __func__); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_ABORT_SCAN, + REASON_ROAM_ABORT_ROAM_SCAN); + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } + + return status; +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * sme_get_valid_channels_by_band() - to fetch valid channels filtered by band + * @hHal: HAL context + * @wifiBand: RF band information + * @aValidChannels: output array to store channel info + * @pNumChannels: output number of channels + * + * SME API to fetch all valid channels filtered by band + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_get_valid_channels_by_band(tHalHandle hHal, + uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t chanList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t numChannels = 0; + uint8_t i = 0; + uint32_t totValidChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (!aValidChannels || !pNumChannels) { + sms_log(pMac, CDF_TRACE_LEVEL_ERROR, + FL("Output channel list/NumChannels is NULL")); + return CDF_STATUS_E_INVAL; + } + + if ((wifiBand < WIFI_BAND_UNSPECIFIED) || (wifiBand >= WIFI_BAND_MAX)) { + sms_log(pMac, CDF_TRACE_LEVEL_ERROR, + FL("Invalid wifiBand (%d)"), wifiBand); + return CDF_STATUS_E_INVAL; + } + + status = sme_get_cfg_valid_channels(hHal, &chanList[0], + &totValidChannels); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, CDF_TRACE_LEVEL_ERROR, + FL("Fail to get valid channel list (err=%d)"), status); + return status; + } + + switch (wifiBand) { + case WIFI_BAND_UNSPECIFIED: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("Unspec Band, return all (%d) valid channels"), + totValidChannels); + numChannels = totValidChannels; + for (i = 0; i < totValidChannels; i++) { + aValidChannels[i] = cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_BG: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_BG (2.4 GHz)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A (5 GHz without DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i]) && + !CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_ABG: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_ABG (2.4 GHz + 5 GHz; no DFS)")); + for (i = 0; i < totValidChannels; i++) { + if ((CDS_IS_CHANNEL_24GHZ(chanList[i]) || + CDS_IS_CHANNEL_5GHZ(chanList[i])) && + !CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A_DFS_ONLY: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A_DFS (5 GHz DFS only)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i]) && + CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A_WITH_DFS: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A_WITH_DFS (5 GHz with DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_ABG_WITH_DFS: + sms_log(pMac, CDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_ABG_WITH_DFS (2.4 GHz+5 GHz with DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(chanList[i]) || + CDS_IS_CHANNEL_5GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + default: + sms_log(pMac, CDF_TRACE_LEVEL_ERROR, + FL("Unknown wifiBand (%d))"), wifiBand); + return CDF_STATUS_E_INVAL; + break; + } + *pNumChannels = numChannels; + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_get_capabilities + \brief SME API to fetch extscan capabilities + \param hHal + \param pReq: extscan capabilities structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams * + pReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pReq; + cds_message.type = WMA_EXTSCAN_GET_CAPABILITIES_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_start + \brief SME API to issue extscan start + \param hHal + \param pStartCmd: extscan start structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pStartCmd; + cds_message.type = WMA_EXTSCAN_START_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_stop + \brief SME API to issue extscan stop + \param hHal + \param pStopReq: extscan stop structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ext_scan_stop(tHalHandle hHal, tSirExtScanStopReqParams *pStopReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pStopReq; + cds_message.type = WMA_EXTSCAN_STOP_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_bss_hotlist + \brief SME API to set BSSID hotlist + \param hHal + \param pSetHotListReq: extscan set hotlist structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_bss_hotlist(tHalHandle hHal, + tSirExtScanSetBssidHotListReqParams * + pSetHotListReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pSetHotListReq; + cds_message.type = WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_bss_hotlist + \brief SME API to reset BSSID hotlist + \param hHal + \param pSetHotListReq: extscan set hotlist structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_reset_bss_hotlist(tHalHandle hHal, + tSirExtScanResetBssidHotlistReqParams * + pResetReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pResetReq; + cds_message.type = WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_significant_change + \brief SME API to set significant change + \param hHal + \param pSetSignificantChangeReq: extscan set significant change structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_significant_change(tHalHandle hHal, + tSirExtScanSetSigChangeReqParams * + pSetSignificantChangeReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pSetSignificantChangeReq; + cds_message.type = WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_significant_change + \brief SME API to reset significant change + \param hHal + \param pResetReq: extscan reset significant change structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_reset_significant_change(tHalHandle hHal, + tSirExtScanResetSignificantChangeReqParams + *pResetReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pResetReq; + cds_message.type = WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_cached_results + \brief SME API to get cached results + \param hHal + \param pCachedResultsReq: extscan get cached results structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pCachedResultsReq; + cds_message.type = WMA_EXTSCAN_GET_CACHED_RESULTS_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_epno_list() - set epno network list + * @hHal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with %input and posts it to WDA queue. + * + * Return: eHalStatus enumeration + */ +CDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *input) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_epno_params *req_msg; + int len, i; + + sms_log(mac, LOG1, FL("enter")); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_epno_network)); + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].rssi_threshold = + input->networks[i].rssi_threshold; + req_msg->networks[i].flags = input->networks[i].flags; + req_msg->networks[i].auth_bit_field = + input->networks[i].auth_bit_field; + req_msg->networks[i].ssid.length = + input->networks[i].ssid.length; + cdf_mem_copy(req_msg->networks[i].ssid.ssId, + input->networks[i].ssid.ssId, + req_msg->networks[i].ssid.length); + } + + status = sme_acquire_global_lock(&mac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_EPNO_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_passpoint_list() - set passpoint network list + * @hal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: eHalStatus enumeration + */ +CDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_passpoint_req *req_msg; + int len, i; + + sms_log(mac, LOG1, FL("enter")); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_passpoint_network)); + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].id = + input->networks[i].id; + cdf_mem_copy(req_msg->networks[i].realm, + input->networks[i].realm, + strlen(input->networks[i].realm) + 1); + cdf_mem_copy(req_msg->networks[i].plmn, + input->networks[i].plmn, + SIR_PASSPOINT_PLMN_LEN); + cdf_mem_copy(req_msg->networks[i].roaming_consortium_ids, + input->networks[i].roaming_consortium_ids, + sizeof(req_msg->networks[i].roaming_consortium_ids)); + } + + status = sme_acquire_global_lock(&mac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_PASSPOINT_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_reset_passpoint_list() - reset passpoint network list + * @hHal: global hal handle + * @input: request message + * + * Return: eHalStatus enumeration + */ +CDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_passpoint_req *req_msg; + + sms_log(mac, LOG1, FL("enter")); + req_msg = cdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, sizeof(*req_msg)); + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + + status = sme_acquire_global_lock(&mac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_RESET_PASSPOINT_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_ssid_hotlist() - Set the SSID hotlist + * @hal: SME handle + * @request: set ssid hotlist request + * + * Return: eHalStatus + */ +CDF_STATUS +sme_set_ssid_hotlist(tHalHandle hal, + struct sir_set_ssid_hotlist_request *request) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct sir_set_ssid_hotlist_request *set_req; + + set_req = cdf_mem_malloc(sizeof(*set_req)); + if (!set_req) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_FAILURE; + } + + *set_req = *request; + status = sme_acquire_global_lock(&mac->sme); + if (CDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = set_req; + cds_message.type = WMA_EXTSCAN_SET_SSID_HOTLIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + sme_release_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(set_req); + status = CDF_STATUS_E_FAILURE; + } + } else { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(set_req); + status = CDF_STATUS_E_FAILURE; + } + return status; +} + +CDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, + const uint16_t, + void *)) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pExtScanIndCb = pExtScanIndCb; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#else +CDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)) +{ + return CDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_clear_req + \brief SME API to clear Link Layer Statistics + \param hHal + \param pclearStatsReq: Link Layer clear stats request params structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq *pclearStatsReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsClearReq *clear_stats_req; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "staId = %u", pclearStatsReq->staId); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "statsClearReqMask = 0x%X", + pclearStatsReq->statsClearReqMask); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "stopReq = %u", pclearStatsReq->stopReq); + + clear_stats_req = cdf_mem_malloc(sizeof(*clear_stats_req)); + + if (!clear_stats_req) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_CLEAR_REQ", + __func__); + return CDF_STATUS_E_NOMEM; + } + + *clear_stats_req = *pclearStatsReq; + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = clear_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_CLEAR_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_CLEAR_REQ", + __func__); + cdf_mem_free(clear_stats_req); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + cdf_mem_free(clear_stats_req); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_set_req + \brief SME API to set the Link Layer Statistics + \param hHal + \param psetStatsReq: Link Layer set stats request params structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, tSirLLStatsSetReq *psetStatsReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsSetReq *set_stats_req; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: MPDU Size = %u", __func__, + psetStatsReq->mpduSizeThreshold); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + " Aggressive Stats Collections = %u", + psetStatsReq->aggressiveStatisticsGathering); + + set_stats_req = cdf_mem_malloc(sizeof(*set_stats_req)); + + if (!set_stats_req) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_SET_REQ", + __func__); + return CDF_STATUS_E_NOMEM; + } + + *set_stats_req = *psetStatsReq; + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = set_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_SET_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_SET_REQ", + __func__); + cdf_mem_free(set_stats_req); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + cdf_mem_free(set_stats_req); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_get_req + \brief SME API to get the Link Layer Statistics + \param hHal + \param pgetStatsReq: Link Layer get stats request params structure + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_ll_stats_get_req(tHalHandle hHal, tSirLLStatsGetReq *pgetStatsReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsGetReq *get_stats_req; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "reqId = %u", pgetStatsReq->reqId); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "staId = %u", pgetStatsReq->staId); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Stats Type = %u", pgetStatsReq->paramIdMask); + + get_stats_req = cdf_mem_malloc(sizeof(*get_stats_req)); + + if (!get_stats_req) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_GET_REQ", + __func__); + return CDF_STATUS_E_NOMEM; + } + + *get_stats_req = *pgetStatsReq; + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = get_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_GET_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_GET_REQ", + __func__); + + cdf_mem_free(get_stats_req); + status = CDF_STATUS_E_FAILURE; + + } + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + cdf_mem_free(get_stats_req); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_link_layer_stats_ind_cb + \brief SME API to trigger the stats are available after get request + \param hHal + \param callback_routine - HDD callback which needs to be invoked after + getting status notification from FW + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_link_layer_stats_ind_cb + (tHalHandle hHal, + void (*callback_routine)(void *callbackCtx, int indType, void *pRsp) + ) { + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pLinkLayerStatsIndCallback = callback_routine; + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + } + + return status; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * sme_fw_mem_dump_register_cb() - Register fw memory dump callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: CDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +CDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (CDF_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = callback_routine; + sme_release_global_lock(&pmac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + + return status; +} +#else +CDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/** + * sme_fw_mem_dump_unregister_cb() - Unregister fw memory dump callback + * + * @hHal - MAC global handle + * + * This API is invoked by HDD to unregister its callback in SME + * + * Return: CDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +CDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + CDF_STATUS status; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (CDF_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = NULL; + sme_release_global_lock(&pmac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + + return status; +} +#else +CDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/*-------------------------------------------------------------------------- + \brief sme_update_roam_offload_enabled() - enable/disable roam offload feaure + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + \param hHal - The handle returned by mac_open. + \param nRoamOffloadEnabled - The bool to update with + \return CDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME is failed to update. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: LFR3:gRoamOffloadEnabled is changed from %d to %d", + __func__, pMac->roam.configParam.isRoamOffloadEnabled, + nRoamOffloadEnabled); + pMac->roam.configParam.isRoamOffloadEnabled = + nRoamOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_roam_key_mgmt_offload_enabled() - enable/disable key mgmt + offload + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \param nRoamKeyMgmtOffloadEnabled - The bool to update with + \return CDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME is failed to update. + \sa + --------------------------------------------------------------------------*/ + +CDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hHal, + uint8_t sessionId, + bool nRoamKeyMgmtOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: LFR3: KeyMgmtOffloadEnabled changed to %d", + __func__, nRoamKeyMgmtOffloadEnabled); + status = csr_roam_set_key_mgmt_offload(pMac, + sessionId, + nRoamKeyMgmtOffloadEnabled); + } else { + status = CDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_temperature + \brief SME API to get the pdev temperature + \param hHal + \param temperature context + \param pCallbackfn: callback fn with response (temperature) + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_get_temperature(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + if ((NULL == pCallbackfn) && + (NULL == pMac->sme.pGetTemperatureCb)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Indication Call back did not registered")); + sme_release_global_lock(&pMac->sme); + return CDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pTemperatureCbContext = tempContext; + pMac->sme.pGetTemperatureCb = pCallbackfn; + } + /* serialize the req through MC thread */ + cds_message.bodyptr = NULL; + cds_message.type = WMA_GET_TEMPERATURE_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Post Get Temperature msg fail")); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_scanning_mac_oui + \brief SME API to set scanning mac oui + \param hHal + \param pScanMacOui: Scanning Mac Oui (input 3 bytes) + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, tSirScanMacOui *pScanMacOui) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pScanMacOui; + cds_message.type = WMA_SET_SCAN_MAC_OUI_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Msg post Set Scan Mac OUI failed")); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif + +#ifdef DHCP_SERVER_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_set_dhcp_srv_offload + \brief SME API to set DHCP server offload info + \param hHal + \param pDhcpSrvInfo : DHCP server offload info struct + \- return CDF_STATUS + -------------------------------------------------------------------------*/ +CDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo *pDhcpSrvInfo) +{ + cds_msg_t cds_message; + tSirDhcpSrvOffloadInfo *pSmeDhcpSrvInfo; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pSmeDhcpSrvInfo = cdf_mem_malloc(sizeof(*pSmeDhcpSrvInfo)); + + if (!pSmeDhcpSrvInfo) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_SET_DHCP_SERVER_OFFLOAD_CMD", + __func__); + return CDF_STATUS_E_NOMEM; + } + + *pSmeDhcpSrvInfo = *pDhcpSrvInfo; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_STATUS_SUCCESS == status) { + /* serialize the req through MC thread */ + cds_message.type = WMA_SET_DHCP_SERVER_OFFLOAD_CMD; + cds_message.bodyptr = pSmeDhcpSrvInfo; + + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &cds_message))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_DHCP_SERVER_OFFLOAD_CMD to WMA!", + __func__); + cdf_mem_free(pSmeDhcpSrvInfo); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", __func__); + cdf_mem_free(pSmeDhcpSrvInfo); + } + + return status; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/* --------------------------------------------------------------------------- + \fn sme_set_led_flashing + \brief API to set the Led flashing parameters. + \param hHal - The handle returned by mac_open. + \param x0, x1 - led flashing parameters + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLedFlashingReq *ledflashing; + + ledflashing = cdf_mem_malloc(sizeof(*ledflashing)); + if (!ledflashing) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Not able to allocate memory for WMA_LED_TIMING_REQ")); + return CDF_STATUS_E_NOMEM; + } + + ledflashing->pattern_id = type; + ledflashing->led_x0 = x0; + ledflashing->led_x1 = x1; + + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = ledflashing; + cds_message.type = WMA_LED_FLASHING_REQ; + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + status = CDF_STATUS_E_FAILURE; + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif + +/** + * sme_handle_dfS_chan_scan() - handle DFS channel configuration + * @h_hal: corestack handler + * @dfs_flag: flag indicating dfs channel enable/disable + * Return: CDF_STATUS + */ +CDF_STATUS sme_handle_dfs_chan_scan(tHalHandle h_hal, uint8_t dfs_flag) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + + if (CDF_STATUS_SUCCESS == status) { + + mac->scan.fEnableDFSChnlScan = dfs_flag; + + /* update the channel list to the firmware */ + status = csr_update_channel_list(mac); + + sme_release_global_lock(&mac->sme); + } + + return status; +} + + +/** + * sme_configure_stats_avg_factor() - function to config avg. stats factor + * @hal: hal + * @session_id: session ID + * @stats_avg_factor: average stats factor + * + * This function configures the stats avg factor in firmware + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor) +{ + cds_msg_t msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_stats_avg_factor *stats_factor; + + stats_factor = cdf_mem_malloc(sizeof(*stats_factor)); + + if (!stats_factor) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_STATS_FACTOR", + __func__); + return CDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (CDF_STATUS_SUCCESS == status) { + + stats_factor->vdev_id = session_id; + stats_factor->stats_avg_factor = stats_avg_factor; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_STATS_FACTOR; + msg.bodyptr = stats_factor; + + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_STATS_FACTOR to WMA!", + __func__); + cdf_mem_free(stats_factor); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + cdf_mem_free(stats_factor); + } + + return status; +} + +/** + * sme_configure_guard_time() - function to configure guard time + * @hal: hal + * @session_id: session id + * @guard_time: guard time + * + * This function configures the guard time in firmware + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_configure_guard_time(tHalHandle hal, uint8_t session_id, + uint32_t guard_time) +{ + cds_msg_t msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_guard_time_request *g_time; + + g_time = cdf_mem_malloc(sizeof(*g_time)); + + if (!g_time) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_GUARD_TIME", + __func__); + return CDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (CDF_STATUS_SUCCESS == status) { + + g_time->vdev_id = session_id; + g_time->guard_time = guard_time; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_GUARD_TIME; + msg.bodyptr = g_time; + + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_GUARD_TIME to WMA!", + __func__); + cdf_mem_free(g_time); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + cdf_mem_free(g_time); + } + + return status; +} + +/** + * sme_configure_modulated_dtim() - function to configure modulated dtim + * @h_hal: SME API to enable/disable modulated DTIM instantaneously + * @session_id: session ID + * @modulated_dtim: modulated dtim value + * + * This function configures the modulated dtim in firmware + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_configure_modulated_dtim(tHalHandle h_hal, uint8_t session_id, + uint32_t modulated_dtim) +{ + cds_msg_t msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + wma_cli_set_cmd_t *iwcmd; + + iwcmd = cdf_mem_malloc(sizeof(*iwcmd)); + if (NULL == iwcmd) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_FATAL, + "%s: cdf_mem_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (CDF_STATUS_SUCCESS == status) { + + cdf_mem_zero((void *)iwcmd, sizeof(*iwcmd)); + iwcmd->param_value = modulated_dtim; + iwcmd->param_vdev_id = session_id; + iwcmd->param_id = GEN_PARAM_MODULATED_DTIM; + iwcmd->param_vp_dev = GEN_CMD; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = (void *)iwcmd; + + if (!CDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post GEN_PARAM_DYNAMIC_DTIM to WMA!", + __func__); + cdf_mem_free(iwcmd); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + cdf_mem_free(iwcmd); + } + + return status; +} + +/* + * sme_wifi_start_logger() - Send the start/stop logging command to WMA + * to either start/stop logging + * @hal: HAL context + * @start_log: Structure containing the wifi start logger params + * + * This function sends the start/stop logging command to WMA + * + * Return: CDF_STATUS_SUCCESS on successful posting + */ +CDF_STATUS sme_wifi_start_logger(tHalHandle hal, + struct sir_wifi_start_log start_log) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct sir_wifi_start_log *req_msg; + uint32_t len; + + len = sizeof(*req_msg); + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + + req_msg->verbose_level = start_log.verbose_level; + req_msg->flag = start_log.flag; + req_msg->ring_id = start_log.ring_id; + + status = sme_acquire_global_lock(&mac->sme); + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_START_STOP_LOGGING; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_neighbor_middle_of_roaming() - Function to know if + * STA is in the middle of roaming states + * @hal: Handle returned by macOpen + * @sessionId: sessionId of the STA session + * + * This function is a wrapper to call + * csr_neighbor_middle_of_roaming to know STA is in the + * middle of roaming states + * + * Return: True or False + * + */ +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, uint8_t sessionId) +{ + return csr_neighbor_middle_of_roaming(PMAC_STRUCT(hHal), sessionId); +} + +/* + * sme_send_flush_logs_cmd_to_fw() - Flush FW logs + * @mac: MAC handle + * + * This function is used to send the command that will + * be used to flush the logs in the firmware + * + * Return: eHalStatus + */ +CDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal mac) +{ + CDF_STATUS status; + cds_msg_t message; + + status = sme_acquire_global_lock(&mac->sme); + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + /* Serialize the req through MC thread */ + message.bodyptr = NULL; + message.type = SIR_HAL_FLUSH_LOG_TO_FW; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_enable_uapsd_for_ac() - enable uapsd for access catagory requerst to WMA + * @cds_ctx: cds context + * @sta_id: station id + * @ac: access catagory + * @tid: tid value + * @pri: user priority + * @srvc_int: service interval + * @sus_int: suspend interval + * @dir: tspec direction + * @psb: PSB value + * @sessionId: session id + * @delay_interval: delay interval + * + * Return: CDF status + */ +CDF_STATUS sme_enable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + sme_tspec_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval) +{ + void *wma_handle; + t_wma_trigger_uapsd_params uapsd_params; + enum uapsd_ac access_category; + + if (!psb) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "No need to configure auto trigger:psb is 0"); + return CDF_STATUS_SUCCESS; + } + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma_handle) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return CDF_STATUS_E_FAILURE; + } + + uapsd_params.wmm_ac = access_category; + uapsd_params.user_priority = pri; + uapsd_params.service_interval = srvc_int; + uapsd_params.delay_interval = delay_interval; + uapsd_params.suspend_interval = sus_int; + + if (CDF_STATUS_SUCCESS != + wma_trigger_uapsd_params(wma_handle, sessionId, &uapsd_params)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to Trigger Uapsd params for sessionId %d", + sessionId); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_disable_uapsd_for_ac() - disable uapsed access catagory request to WMA + * @cds_ctx: cds context + * @sta_id: station id + * @ac: access catagory + * @sessionId: session id + * + * Return: CDF status + */ +CDF_STATUS sme_disable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, + uint32_t sessionId) +{ + void *wma_handle; + enum uapsd_ac access_category; + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return CDF_STATUS_E_FAILURE; + } + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma_handle) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + if (CDF_STATUS_SUCCESS != + wma_disable_uapsd_per_ac(wma_handle, sessionId, access_category)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to disable uapsd for ac %d for sessionId %d", + ac, sessionId); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_update_nss() - SME API to change the number for spatial streams + * (1 or 2) + * @hal: Handle returned by mac open + * @nss: Number of spatial streams + * + * This function is used to update the number of spatial streams supported. + * + * Return: Success upon successfully changing nss else failure + * + */ +CDF_STATUS sme_update_nss(tHalHandle h_hal, uint8_t nss) +{ + CDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + uint32_t i, value = 0; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } uHTCapabilityInfo; + tCsrRoamSession *csr_session; + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (CDF_STATUS_SUCCESS == status) { + mac_ctx->roam.configParam.enable2x2 = (nss == 1) ? 0 : 1; + + /* get the HT capability info*/ + sme_cfg_get_int(mac_ctx, WNI_CFG_HT_CAP_INFO, &value); + uHTCapabilityInfo.cfg_value16 = (0xFFFF & value); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i)) { + csr_session = &mac_ctx->roam.roamSession[i]; + csr_session->htConfig.ht_tx_stbc = + uHTCapabilityInfo.ht_cap_info.txSTBC; + } + } + + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +/** + * sme_set_rssi_threshold_breached_cb() - set rssi threshold breached callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores the rssi threshold breached callback function. + * + * Return: CDF_STATUS enumeration. + */ +CDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + mac->sme.rssi_threshold_breached_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_is_any_session_in_connected_state() - SME wrapper API to + * check if any session is in connected state or not. + * + * @hal: Handle returned by mac open + * + * This function is used to check if any valid sme session is in + * connected state or not. + * + * Return: true if any session is connected, else false. + * + */ +bool sme_is_any_session_in_connected_state(tHalHandle h_hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + CDF_STATUS status; + bool ret = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_STATUS_SUCCESS == status) { + ret = csr_is_any_session_in_connect_state(mac_ctx); + sme_release_global_lock(&mac_ctx->sme); + } + return ret; +} + +/** + * sme_set_rssi_monitoring() - set rssi monitoring + * @hal: global hal handle + * @input: request message + * + * This function constructs the vos message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, + struct rssi_monitor_req *input) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct rssi_monitor_req *req_msg; + + sms_log(mac, LOG1, FL("enter")); + req_msg = cdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return CDF_STATUS_E_NOMEM; + } + + *req_msg = *input; + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_RSSI_MONITOR_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_fw_mem_dump() - Get FW memory dump + * @hHal: hal handle + * @recvd_req: received memory dump request. + * + * This API is invoked by HDD to indicate FW to start + * dumping firmware memory. + * + * Return: CDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +CDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + struct fw_dump_req *send_req; + struct fw_dump_seg_req seg_req; + int loop; + + send_req = cdf_mem_malloc(sizeof(*send_req)); + if (!send_req) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failed for WDA_FW_MEM_DUMP")); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(send_req, recvd_req, sizeof(*send_req)); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("request_id:%d num_seg:%d"), + send_req->request_id, send_req->num_seg); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Segment Information")); + for (loop = 0; loop < send_req->num_seg; loop++) { + seg_req = send_req->segment[loop]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("seg_number:%d"), loop); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + seg_req.seg_id, seg_req.seg_start_addr_lo, + seg_req.seg_start_addr_hi); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + seg_req.seg_length, seg_req.dst_addr_lo, + seg_req.dst_addr_hi); + } + + if (CDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + msg.bodyptr = send_req; + msg.type = WMA_FW_MEM_DUMP_REQ; + msg.reserved = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_WMA, &msg); + if (CDF_STATUS_SUCCESS != cdf_status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_FW_MEM_DUMP")); + cdf_mem_free(send_req); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to acquire SME Global Lock")); + cdf_mem_free(send_req); + status = CDF_STATUS_E_FAILURE; + } + + return status; +} +#else +CDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/* + * sme_soc_set_pcl() - Send WMI_SOC_SET_PCL_CMDID to the WMA + * @hal: Handle returned by macOpen + * @msg: PCL channel list and length structure + * + * Sends the command to WMA to send WMI_SOC_SET_PCL_CMDID to FW + * Return: CDF_STATUS_SUCCESS on successful posting + */ +CDF_STATUS sme_soc_set_pcl(tHalHandle hal, + struct sir_pcl_list msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct sir_pcl_list *req_msg; + uint32_t len, i; + + len = sizeof(*req_msg); + + req_msg = cdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(req_msg, len); + + for (i = 0; i < msg.pcl_len; i++) + req_msg->pcl_list[i] = msg.pcl_list[i]; + + req_msg->pcl_len = msg.pcl_len; + + status = sme_acquire_global_lock(&mac->sme); + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_AcquireGlobalLock failed!(status=%d)"), + status); + cdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_SOC_SET_PCL_TO_FW; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("vos_mq_post_message failed!(err=%d)"), + status); + cdf_mem_free(req_msg); + status = CDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/* + * sme_soc_set_hw_mode() - Send WMI_SOC_SET_HW_MODE_CMDID to the WMA + * @hal: Handle returned by macOpen + * @msg: HW mode structure containing hw mode and callback details + * + * Sends the command to CSR to send WMI_SOC_SET_HW_MODE_CMDID to FW + * Return: CDF_STATUS_SUCCESS on successful posting + */ +CDF_STATUS sme_soc_set_hw_mode(tHalHandle hal, + struct sir_hw_mode msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd = NULL; + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to acquire lock")); + return CDF_STATUS_E_RESOURCES; + } + + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return CDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_hw_mode; + cmd->u.set_hw_mode_cmd.hw_mode_index = msg.hw_mode_index; + cmd->u.set_hw_mode_cmd.set_hw_mode_cb = msg.set_hw_mode_cb; + + sms_log(mac, LOG1, FL("Queuing e_sme_command_set_hw_mode to CSR")); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_register_hw_mode_trans_cb() - HW mode transition callback registration + * @hal: Handle returned by macOpen + * @callback: HDD callback to be registered + * + * Registers the HDD callback with SME. This callback will be invoked when + * HW mode transition event is received from the FW + * + * Return: None + */ +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + mac->sme.sme_hw_mode_trans_cb = callback; + sms_log(mac, LOG1, FL("HW mode transition callback registered")); +} + +/** + * sme_nss_update_request() - Send beacon templete update to FW with new + * nss value + * @hal: Handle returned by macOpen + * @vdev_id: the session id + * @new_nss: the new nss value + * @cback: hdd callback + * @next_action: next action to happen at policy mgr after beacon update + * + * Sends the command to CSR to send to PE + * Return: CDF_STATUS_SUCCESS on successful posting + */ +CDF_STATUS sme_nss_update_request(tHalHandle hHal, uint32_t vdev_id, + uint8_t new_nss, void *cback, uint8_t next_action, + void *hdd_context) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hHal); + tSmeCmd *cmd = NULL; + + status = sme_acquire_global_lock(&mac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return CDF_STATUS_E_NULL_VALUE; + } + cmd->command = e_sme_command_nss_update; + /* Sessionized modules may require this info */ + cmd->sessionId = vdev_id; + cmd->u.nss_update_cmd.new_nss = new_nss; + cmd->u.nss_update_cmd.session_id = vdev_id; + cmd->u.nss_update_cmd.nss_update_cb = cback; + cmd->u.nss_update_cmd.context = hdd_context; + cmd->u.nss_update_cmd.next_action = next_action; + + sms_log(mac, LOG1, FL("Queuing e_sme_command_nss_update to CSR")); + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_soc_set_dual_mac_config() - Set dual mac configurations + * @hal: Handle returned by macOpen + * @msg: Structure containing the dual mac config parameters + * + * Queues configuration information to CSR to configure + * WLAN firmware for the dual MAC features + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_soc_set_dual_mac_config(tHalHandle hal, + struct sir_dual_mac_config msg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd; + + status = sme_acquire_global_lock(&mac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to acquire lock")); + return CDF_STATUS_E_RESOURCES; + } + + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return CDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_dual_mac_config; + cmd->u.set_dual_mac_cmd.scan_config = msg.scan_config; + cmd->u.set_dual_mac_cmd.fw_mode_config = msg.fw_mode_config; + cmd->u.set_dual_mac_cmd.set_dual_mac_cb = msg.set_dual_mac_cb; + + sms_log(mac, LOG1, + FL("Queuing e_sme_command_set_dual_mac_config to CSR: %x %x"), + cmd->u.set_dual_mac_cmd.scan_config, + cmd->u.set_dual_mac_cmd.fw_mode_config); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_set_peer_authorized() - call peer authorized callback + * @peer_addr: peer mac address + * @auth_cb: auth callback + * @vdev_id: vdev id + * + * Return: CDF Status + */ +CDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_cb, + uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma_handle) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + + wma_set_peer_authorized_cb(wma_handle, auth_cb); + return wma_set_peer_param(wma_handle, peer_addr, WMI_PEER_AUTHORIZE, + 1, vdev_id); +} + +/* + * sme_disable_non_fcc_channel() - non-fcc channel disable request + * @hal: HAL pointer + * @fcc_constraint: true: disable, false; enable + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_disable_non_fcc_channel(tHalHandle hal, bool fcc_constraint) +{ + CDF_STATUS status; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac_ptr->sme); + + if (CDF_STATUS_SUCCESS == status) { + + if (fcc_constraint != mac_ptr->scan.fcc_constraint) { + mac_ptr->scan.fcc_constraint = fcc_constraint; + + /* update the channel list in firmware */ + status = csr_update_channel_list(mac_ptr); + } + + sme_release_global_lock(&mac_ptr->sme); + } + + return status; +} +/** + * sme_setdef_dot11mode() - Updates pMac with default dot11mode + * @hal: Global MAC pointer + * + * Return: NULL. + */ +void sme_setdef_dot11mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + csr_set_default_dot11_mode(mac_ctx); +} + +/** + * sme_update_roam_scan_hi_rssi_scan_params() - update high rssi scan + * params + * @hal_handle - The handle returned by macOpen. + * @session_id - Session Identifier + * @notify_id - Identifies 1 of the 4 parameters to be modified + * @val New value of the parameter + * + * Return: CDF_STATUS - SME update config successful. + * Other status means SME failed to update + */ + +CDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *nr_config = NULL; + tpCsrNeighborRoamControlInfo nr_info = NULL; + uint32_t reason = 0; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + nr_config = &mac_ctx->roam.configParam.neighborRoamConfig; + nr_info = &mac_ctx->roam.neighborRoamInfo[session_id]; + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: gRoamScanHirssiMaxCount %d => %d", + __func__, nr_config->nhi_rssi_scan_max_count, + val); + nr_config->nhi_rssi_scan_max_count = val; + nr_info->cfgParams.hi_rssi_scan_max_count = val; + reason = REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiDelta %d => %d"), + nr_config->nhi_rssi_scan_rssi_delta, + val); + nr_config->nhi_rssi_scan_rssi_delta = val; + nr_info->cfgParams.hi_rssi_scan_rssi_delta = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiDelay %d => %d"), + nr_config->nhi_rssi_scan_delay, + val); + nr_config->nhi_rssi_scan_delay = val; + nr_info->cfgParams.hi_rssi_scan_delay = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiUpperBound %d => %d"), + nr_config->nhi_rssi_scan_rssi_ub, + val); + nr_config->nhi_rssi_scan_rssi_ub = val; + nr_info->cfgParams.hi_rssi_scan_rssi_ub = val; + reason = REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED; + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("invalid parameter notify_id %d"), + notify_id); + status = CDF_STATUS_E_INVAL; + break; + } + sme_release_global_lock(&mac_ctx->sme); + } +#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD + if (mac_ctx->roam.configParam.isRoamOffloadScanEnabled && + status == CDF_STATUS_SUCCESS) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + } +#endif + + return status; +} + diff --git a/core/sme/src/common/sme_ft_api.c b/core/sme/src/common/sme_ft_api.c new file mode 100644 index 0000000000..b48e13f10c --- /dev/null +++ b/core/sme/src/common/sme_ft_api.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef WLAN_FEATURE_VOWIFI_11R +/**========================================================================= + + \brief Definitions for SME FT APIs + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include + +/*-------------------------------------------------------------------------- + Initialize the FT context. + ------------------------------------------------------------------------*/ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL != pSession) { + /* Clean up the context */ + cdf_mem_set(&pSession->ftSmeContext, sizeof(tftSMEContext), 0); + + pSession->ftSmeContext.pUsrCtx = + cdf_mem_malloc(sizeof(tFTRoamCallbackUsrCtx)); + + if (NULL == pSession->ftSmeContext.pUsrCtx) { + sms_log(pMac, LOGE, FL("Memory allocation failure")); + return; + } + pSession->ftSmeContext.pUsrCtx->pMac = pMac; + pSession->ftSmeContext.pUsrCtx->sessionId = sessionId; + + status = + cdf_mc_timer_init(&pSession->ftSmeContext. + preAuthReassocIntvlTimer, + CDF_TIMER_TYPE_SW, + sme_preauth_reassoc_intvl_timer_callback, + (void *)pSession->ftSmeContext.pUsrCtx); + + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL + ("Preauth Reassoc interval Timer allocation failed")); + cdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + return; + } + } +} + +/*-------------------------------------------------------------------------- + Cleanup the SME FT Global context. + ------------------------------------------------------------------------*/ +void sme_ft_close(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + /* Clear the FT Context */ + sme_ft_reset(hHal, sessionId); + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + /* check if the timer is running */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&pSession->ftSmeContext. + preAuthReassocIntvlTimer)) { + cdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + } + + if (CDF_STATUS_SUCCESS != + cdf_mc_timer_destroy(&pSession->ftSmeContext. + preAuthReassocIntvlTimer)) { + sms_log(pMac, LOGE, + FL("preAuthReAssocTimer destroy failed")); + } + + if (pSession->ftSmeContext.pUsrCtx != NULL) { + sms_log(pMac, LOG1, + FL + ("Freeing ftSmeContext.pUsrCtx and setting to NULL")); + cdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + } + } +} + +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (pSession) + pSession->ftSmeContext.setFTPreAuthState = state; +} + +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (pSession) + return pSession->ftSmeContext.setFTPreAuthState; + + return false; +} + +/** + * sme_set_ft_ies() - to set FT IEs + * @hal_ptr: pointer to HAL + * @session_id: sme session id + * @ft_ies: pointer to FT IEs + * @ft_ies_length: length of FT IEs + * + * Each time the supplicant sends down the FT IEs to the driver. This function + * is called in SME. This fucntion packages and sends the FT IEs to PE. + * + * Return: none + */ +void sme_set_ft_ies(tHalHandle hal_ptr, uint32_t session_id, + const uint8_t *ft_ies, uint16_t ft_ies_length) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ptr); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (NULL == session || NULL == ft_ies) { + sms_log(mac_ctx, LOGE, FL(" ft ies or session is NULL")); + return; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!(CDF_IS_STATUS_SUCCESS(status))) + return; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(mac_ctx, LOG1, "FT IEs Req is received in state %d", + session->ftSmeContext.FTState); +#endif + + /* Global Station FT State */ + switch (session->ftSmeContext.FTState) { + case eFT_START_READY: + case eFT_AUTH_REQ_READY: + if ((session->ftSmeContext.auth_ft_ies) && + (session->ftSmeContext.auth_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + cdf_mem_free(session->ftSmeContext.auth_ft_ies); + session->ftSmeContext.auth_ft_ies_length = 0; + session->ftSmeContext.auth_ft_ies = NULL; + } + /* Save the FT IEs */ + session->ftSmeContext.auth_ft_ies = + cdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.auth_ft_ies) { + sms_log(mac_ctx, LOGE, + FL("Mem alloc failed for auth_ft_ies")); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.auth_ft_ies_length = ft_ies_length; + cdf_mem_copy((uint8_t *)session->ftSmeContext.auth_ft_ies, + ft_ies, ft_ies_length); + session->ftSmeContext.FTState = eFT_AUTH_REQ_READY; + +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(mac_ctx, LOG1, + FL("ft_ies_length=%d"), ft_ies_length); +#endif + break; + + case eFT_AUTH_COMPLETE: + /* + * We will need to re-start preauth. If we received FT + * IEs in eFT_PRE_AUTH_DONE state, it implies there was + * a rekey in our pre-auth state. Hence this implies we + * need Pre-auth again. OK now inform SME we have no + * pre-auth list. Delete the pre-auth node locally. Set + * your self back to restart pre-auth + */ +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(mac_ctx, LOG1, + FL("Preauth done & rcving AUTHREQ in state %d"), + session->ftSmeContext.FTState); + sms_log(mac_ctx, LOG1, + FL("Unhandled reception of FT IES in state %d"), + session->ftSmeContext.FTState); +#endif + break; + + case eFT_REASSOC_REQ_WAIT: + /* + * We are done with pre-auth, hence now waiting for + * reassoc req. This is the new FT Roaming in place At + * this juncture we'r ready to start sending Reassoc req + */ +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(mac_ctx, LOG1, FL("New Reassoc Req=%p in state %d"), + ft_ies, session->ftSmeContext.FTState); +#endif + if ((session->ftSmeContext.reassoc_ft_ies) && + (session->ftSmeContext.reassoc_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + cdf_mem_free(session->ftSmeContext.reassoc_ft_ies); + session->ftSmeContext.reassoc_ft_ies_length = 0; + } + /* Save the FT IEs */ + session->ftSmeContext.reassoc_ft_ies = + cdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.reassoc_ft_ies) { + sms_log(mac_ctx, LOGE, + FL("Mem alloc fail for reassoc_ft_ie")); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.reassoc_ft_ies_length = + ft_ies_length; + cdf_mem_copy((uint8_t *)session->ftSmeContext.reassoc_ft_ies, + ft_ies, ft_ies_length); + + session->ftSmeContext.FTState = eFT_SET_KEY_WAIT; +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(mac_ctx, LOG1, + FL("ft_ies_length=%d state=%d"), ft_ies_length, + session->ftSmeContext.FTState); +#endif + + break; + + default: + sms_log(mac_ctx, LOGE, FL("Unhandled state=%d"), + session->ftSmeContext.FTState); + break; + } + sme_release_global_lock(&mac_ctx->sme); +} + +/** + * sme_ft_send_update_key_ind() - To send key update indication for FT session + * @hal: pointer to HAL + * @session_id: sme session id + * @ftkey_info: FT key information + * + * To send key update indication for FT session + * + * Return: CDF_STATUS + */ +static +CDF_STATUS sme_ft_send_update_key_ind(tHalHandle hal, uint32_t session_id, + tCsrRoamSetKey *ftkey_info) +{ + tSirFTUpdateKeyInfo *msg; + uint16_t msglen; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSirKeyMaterial *keymaterial = NULL; + tAniEdType ed_type; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + int i = 0; + + sms_log(mac_ctx, LOG1, FL("keyLength %d"), ftkey_info->keyLength); + for (i = 0; i < ftkey_info->keyLength; i++) + sms_log(mac_ctx, LOG1, FL("%02x"), ftkey_info->Key[i]); +#endif + + if (ftkey_info->keyLength > CSR_MAX_KEY_LEN) { + sms_log(mac_ctx, LOGE, FL("invalid keyLength %d"), + ftkey_info->keyLength); + return CDF_STATUS_E_FAILURE; + } + msglen = sizeof(tSirFTUpdateKeyInfo); + + msg = cdf_mem_malloc(msglen); + if (NULL == msg) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(msg, msglen, 0); + msg->messageType = eWNI_SME_FT_UPDATE_KEY; + msg->length = msglen; + + keymaterial = &msg->keyMaterial; + keymaterial->length = ftkey_info->keyLength; + ed_type = csr_translate_encrypt_type_to_ed_type(ftkey_info->encType); + keymaterial->edType = ed_type; + keymaterial->numKeys = 1; + keymaterial->key[0].keyId = ftkey_info->keyId; + keymaterial->key[0].unicast = (uint8_t) true; + keymaterial->key[0].keyDirection = ftkey_info->keyDirection; + + cdf_mem_copy(&keymaterial->key[0].keyRsc, + ftkey_info->keyRsc, CSR_MAX_RSC_LEN); + keymaterial->key[0].paeRole = ftkey_info->paeRole; + keymaterial->key[0].keyLength = ftkey_info->keyLength; + + if (ftkey_info->keyLength && ftkey_info->Key) { + cdf_mem_copy(&keymaterial->key[0].key, ftkey_info->Key, + ftkey_info->keyLength); + if (ftkey_info->keyLength == 16) { + sms_log(mac_ctx, LOG1, + FL("set update ind keyidx(%d) encType(%d) key = %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X"), + msg->keyMaterial.key[0].keyId, + (tAniEdType) msg->keyMaterial.edType, + msg->keyMaterial.key[0].key[0], + msg->keyMaterial.key[0].key[1], + msg->keyMaterial.key[0].key[2], + msg->keyMaterial.key[0].key[3], + msg->keyMaterial.key[0].key[4], + msg->keyMaterial.key[0].key[5], + msg->keyMaterial.key[0].key[6], + msg->keyMaterial.key[0].key[7], + msg->keyMaterial.key[0].key[8], + msg->keyMaterial.key[0].key[9], + msg->keyMaterial.key[0].key[10], + msg->keyMaterial.key[0].key[11], + msg->keyMaterial.key[0].key[12], + msg->keyMaterial.key[0].key[13], + msg->keyMaterial.key[0].key[14], + msg->keyMaterial.key[0].key[15]); + } + } + + cdf_mem_copy(&msg->bssId[0], + &ftkey_info->peerMac.bytes[0], CDF_MAC_ADDR_SIZE); + msg->smeSessionId = session_id; + sms_log(mac_ctx, LOG1, "BSSID = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg->bssId)); + status = cds_send_mb_message_to_mac(msg); + + return status; +} + +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return false; + } + return pSession->ftSmeContext.setFTPTKState; +} + +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + pSession->ftSmeContext.setFTPTKState = state; +} + +CDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (pFTKeyInfo == NULL) { + sms_log(pMac, LOGE, "%s: pFTKeyInfo is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (!(CDF_IS_STATUS_SUCCESS(status))) { + return CDF_STATUS_E_FAILURE; + } +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, "sme_ft_update_key is received in state %d", + pSession->ftSmeContext.FTState); +#endif + + /* Global Station FT State */ + switch (pSession->ftSmeContext.FTState) { + case eFT_SET_KEY_WAIT: + if (sme_get_ft_pre_auth_state(hHal, sessionId) == true) { + status = + sme_ft_send_update_key_ind(pMac, sessionId, pFTKeyInfo); + if (status != 0) { + sms_log(pMac, LOGE, "%s: Key set failure %d", + __func__, status); + pSession->ftSmeContext.setFTPTKState = false; + status = CDF_STATUS_FT_PREAUTH_KEY_FAILED; + } else { + pSession->ftSmeContext.setFTPTKState = true; + status = CDF_STATUS_FT_PREAUTH_KEY_SUCCESS; + sms_log(pMac, LOG1, "%s: Key set success", + __func__); + } + sme_set_ft_pre_auth_state(hHal, sessionId, false); + } + + pSession->ftSmeContext.FTState = eFT_START_READY; +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, "%s: state changed to %d status %d", + __func__, pSession->ftSmeContext.FTState, status); +#endif + break; + + default: + sms_log(pMac, LOGW, "%s: Unhandled state=%d", __func__, + pSession->ftSmeContext.FTState); + status = CDF_STATUS_E_FAILURE; + break; + } + sme_release_global_lock(&pMac->sme); + + return status; +} + +/*-------------------------------------------------------------------------- + * + * HDD Interface to SME. SME now sends the Auth 2 and RIC IEs up to the supplicant. + * The supplicant will then proceed to send down the + * Reassoc Req. + * + *------------------------------------------------------------------------*/ +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + *ft_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(CDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing - proceed only if both BSSID and FT IE fit */ + if ((CDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length) > + ft_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + /* hdd needs to pack the bssid also along with the */ + /* auth response to supplicant */ + cdf_mem_copy(ft_ies, pSession->ftSmeContext.preAuthbssId, + CDF_MAC_ADDR_SIZE); + + /* Copy the auth resp FTIEs */ + cdf_mem_copy(&(ft_ies[CDF_MAC_ADDR_SIZE]), + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length); + + *ft_ies_length = CDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length; + + pSession->ftSmeContext.FTState = eFT_REASSOC_REQ_WAIT; + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, FL(" Filled auth resp = %d"), *ft_ies_length); +#endif + sme_release_global_lock(&pMac->sme); + return; +} + +/*-------------------------------------------------------------------------- + * + * SME now sends the RIC IEs up to the supplicant. + * The supplicant will then proceed to send down the + * Reassoc Req. + * + *------------------------------------------------------------------------*/ +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + *ric_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(CDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing */ + if (pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length > + ric_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + + cdf_mem_copy(ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length); + + *ric_ies_length = + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + +#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, FL(" Filled ric ies = %d"), *ric_ies_length); +#endif + + sme_release_global_lock(&pMac->sme); + return; +} + +/*-------------------------------------------------------------------------- + * + * Timer callback for the timer that is started between the preauth completion and + * reassoc request to the PE. In this interval, it is expected that the pre-auth response + * and RIC IEs are passed up to the WPA supplicant and received back the necessary FTIEs + * required to be sent in the reassoc request + * + *------------------------------------------------------------------------*/ +void sme_preauth_reassoc_intvl_timer_callback(void *context) +{ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + tFTRoamCallbackUsrCtx *pUsrCtx = (tFTRoamCallbackUsrCtx *) context; + + if (pUsrCtx) { + csr_neighbor_roam_request_handoff(pUsrCtx->pMac, + pUsrCtx->sessionId); + } +#endif + return; +} + +/*-------------------------------------------------------------------------- + Reset the FT context. + ------------------------------------------------------------------------*/ +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + if (pMac == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("pMac is NULL")); + return; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + if (pSession->ftSmeContext.auth_ft_ies != NULL) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, + FL("Freeing FT Auth IE %p and setting to NULL"), + pSession->ftSmeContext.auth_ft_ies); +#endif + cdf_mem_free(pSession->ftSmeContext.auth_ft_ies); + pSession->ftSmeContext.auth_ft_ies = NULL; + } + pSession->ftSmeContext.auth_ft_ies_length = 0; + + if (pSession->ftSmeContext.reassoc_ft_ies != NULL) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, + FL + ("Freeing FT Reassoc IE %p and setting to NULL"), + pSession->ftSmeContext.reassoc_ft_ies); +#endif + cdf_mem_free(pSession->ftSmeContext.reassoc_ft_ies); + pSession->ftSmeContext.reassoc_ft_ies = NULL; + } + pSession->ftSmeContext.reassoc_ft_ies_length = 0; + + if (pSession->ftSmeContext.psavedFTPreAuthRsp != NULL) { +#if defined WLAN_FEATURE_VOWIFI_11R_DEBUG + sms_log(pMac, LOG1, + FL + ("Freeing FtPreAuthRsp %p and setting to NULL"), + pSession->ftSmeContext.psavedFTPreAuthRsp); +#endif + cdf_mem_free(pSession->ftSmeContext.psavedFTPreAuthRsp); + pSession->ftSmeContext.psavedFTPreAuthRsp = NULL; + } + pSession->ftSmeContext.setFTPreAuthState = false; + pSession->ftSmeContext.setFTPTKState = false; + + cdf_mem_zero(pSession->ftSmeContext.preAuthbssId, + CDF_MAC_ADDR_SIZE); + pSession->ftSmeContext.FTState = eFT_START_READY; + } +} + +/* End of File */ +#endif /* WLAN_FEATURE_VOWIFI_11R */ diff --git a/core/sme/src/common/sme_power_save.c b/core/sme/src/common/sme_power_save.c new file mode 100644 index 0000000000..a08ce2bdb4 --- /dev/null +++ b/core/sme/src/common/sme_power_save.c @@ -0,0 +1,1214 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_power_save.h" +#include "sme_power_save_api.h" +#include "sms_debug.h" +#include "cdf_memory.h" +#include "cdf_types.h" +#include "wma_types.h" +#include "wmm_apsd.h" +#include "cfg_api.h" +#include "csr_inside_api.h" + +/** + * sme_post_ps_msg_to_wma(): post message to WMA. + * @type: type + * @body: body pointer + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_post_ps_msg_to_wma(uint16_t type, void *body) +{ + cds_msg_t msg; + + msg.type = type; + msg.reserved = 0; + msg.bodyptr = body; + msg.bodyval = 0; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message( + CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Posting message %d failed", + __func__, type); + cdf_mem_free(body); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_ps_req_params(): enables power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_enable_ps_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sEnablePsParams *enable_ps_req_params; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + enable_ps_req_params = cdf_mem_malloc(sizeof(*enable_ps_req_params)); + if (NULL == enable_ps_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for enable_ps_req_params")); + return CDF_STATUS_E_NOMEM; + } + enable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + enable_ps_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENTER_PS_REQ, enable_ps_req_params); + if (!CDF_IS_STATUS_SUCCESS(status)) + return CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Message WMA_ENTER_PS_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_ps_req_params(): Disable power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_disable_ps_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sDisablePsParams *disable_ps_req_params; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + disable_ps_req_params = cdf_mem_malloc(sizeof(*disable_ps_req_params)); + if (NULL == disable_ps_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for sDisablePsParams")); + return CDF_STATUS_E_NOMEM; + } + + disable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + disable_ps_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_EXIT_PS_REQ, disable_ps_req_params); + if (!CDF_IS_STATUS_SUCCESS(status)) + return CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Message WMA_EXIT_PS_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_uapsd_req_params(): enables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_enable_uapsd_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + + struct sEnableUapsdParams *enable_uapsd_req_params; + uint8_t uapsd_delivery_mask = 0; + uint8_t uapsd_trigger_mask = 0; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + enable_uapsd_req_params = + cdf_mem_malloc(sizeof(*enable_uapsd_req_params)); + if (NULL == enable_uapsd_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for enable_uapsd_req_params")); + return CDF_STATUS_E_NOMEM; + } + + + uapsd_delivery_mask = + ps_param->uapsd_per_ac_bit_mask | + ps_param->uapsd_per_ac_delivery_enable_mask; + + uapsd_trigger_mask = + ps_param->uapsd_per_ac_bit_mask | + ps_param->uapsd_per_ac_trigger_enable_mask; + + + enable_uapsd_req_params->uapsdParams.bkDeliveryEnabled = + LIM_UAPSD_GET(ACBK, uapsd_delivery_mask); + + enable_uapsd_req_params->uapsdParams.beDeliveryEnabled = + LIM_UAPSD_GET(ACBE, uapsd_delivery_mask); + + enable_uapsd_req_params->uapsdParams.viDeliveryEnabled = + LIM_UAPSD_GET(ACVI, uapsd_delivery_mask); + + enable_uapsd_req_params->uapsdParams.voDeliveryEnabled = + LIM_UAPSD_GET(ACVO, uapsd_delivery_mask); + + enable_uapsd_req_params->uapsdParams.bkTriggerEnabled = + LIM_UAPSD_GET(ACBK, uapsd_trigger_mask); + + enable_uapsd_req_params->uapsdParams.beTriggerEnabled = + LIM_UAPSD_GET(ACBE, uapsd_trigger_mask); + + enable_uapsd_req_params->uapsdParams.viTriggerEnabled = + LIM_UAPSD_GET(ACVI, uapsd_trigger_mask); + + enable_uapsd_req_params->uapsdParams.voTriggerEnabled = + LIM_UAPSD_GET(ACVO, uapsd_trigger_mask); + + enable_uapsd_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENABLE_UAPSD_REQ, + enable_uapsd_req_params); + if (!CDF_IS_STATUS_SUCCESS(status)) + return CDF_STATUS_E_FAILURE; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Msg WMA_ENABLE_UAPSD_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_uapsd_req_params(): disables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_disable_uapsd_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sDisableUapsdParams *disable_uapsd_req_params; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + disable_uapsd_req_params = + cdf_mem_malloc(sizeof(*disable_uapsd_req_params)); + if (NULL == disable_uapsd_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for disable_uapsd_req_params")); + return CDF_STATUS_E_NOMEM; + } + + disable_uapsd_req_params->sessionid = session_id; + status = sme_post_ps_msg_to_wma(WMA_DISABLE_UAPSD_REQ, + disable_uapsd_req_params); + if (!CDF_IS_STATUS_SUCCESS(status)) + return CDF_STATUS_E_FAILURE; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Message WMA_DISABLE_UAPSD_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enter_wowl_req_params(): enable WOWL req Parama + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_enter_wowl_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sSirHalWowlEnterParams *hal_wowl_params; + struct sSirSmeWowlEnterParams *sme_wowl_params; + uint32_t cfg_value = 0; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + sme_wowl_params = + &ps_global_info->ps_params[session_id].wowl_enter_params; + + hal_wowl_params = cdf_mem_malloc(sizeof(*hal_wowl_params)); + if (NULL == hal_wowl_params) { + sms_log(mac_ctx, LOGP, + FL("Fail to allocate memory for Enter Wowl Request ")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set((uint8_t *) hal_wowl_params, sizeof(*hal_wowl_params), 0); + + /* fill in the message field */ + hal_wowl_params->ucMagicPktEnable = sme_wowl_params->ucMagicPktEnable; + hal_wowl_params->ucPatternFilteringEnable = + sme_wowl_params->ucPatternFilteringEnable; + cdf_mem_copy((uint8_t *) hal_wowl_params->magicPtrn, + (uint8_t *) sme_wowl_params->magicPtrn, + sizeof(tSirMacAddr)); + +#ifdef WLAN_WAKEUP_EVENTS + hal_wowl_params->ucWoWEAPIDRequestEnable = + sme_wowl_params->ucWoWEAPIDRequestEnable; + hal_wowl_params->ucWoWEAPOL4WayEnable = + sme_wowl_params->ucWoWEAPOL4WayEnable; + hal_wowl_params->ucWowNetScanOffloadMatch = + sme_wowl_params->ucWowNetScanOffloadMatch; + hal_wowl_params->ucWowGTKRekeyError = + sme_wowl_params->ucWowGTKRekeyError; + hal_wowl_params->ucWoWBSSConnLoss = + sme_wowl_params->ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE")); + goto end; + } + hal_wowl_params->ucUcastPatternFilteringEnable = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE")); + goto end; + } + hal_wowl_params->ucWowChnlSwitchRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_value) != + eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_DEAUTH_ENABLE ")); + goto end; + } + hal_wowl_params->ucWowDeauthRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_value) != + eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_DISASSOC_ENABLE ")); + goto end; + } + hal_wowl_params->ucWowDisassocRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_MISSED_BEACON ")); + goto end; + } + hal_wowl_params->ucWowMaxMissedBeacons = (uint8_t) cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD ")); + goto end; + } + hal_wowl_params->ucWowMaxSleepUsec = (uint8_t) cfg_value; + + hal_wowl_params->sessionId = sme_wowl_params->sessionId; + + if (CDF_STATUS_SUCCESS == sme_post_ps_msg_to_wma(WMA_WOWL_ENTER_REQ, + hal_wowl_params)){ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Msg WMA_WOWL_ENTER_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; + } else + goto end; + +end: + if (hal_wowl_params != NULL) + cdf_mem_free(hal_wowl_params); + return CDF_STATUS_E_FAILURE; +} + +/** + * sme_ps_exit_wowl_req_params(): Exit WOWL req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_exit_wowl_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sSirHalWowlExitParams *hal_wowl_msg; + hal_wowl_msg = cdf_mem_malloc(sizeof(*hal_wowl_msg)); + if (NULL == hal_wowl_msg) { + sms_log(mac_ctx, LOGP, + FL("Fail to allocate memory for WoWLAN Add Bcast Pattern ")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set((uint8_t *) hal_wowl_msg, + sizeof(*hal_wowl_msg), 0); + hal_wowl_msg->sessionId = session_id; + + if (CDF_STATUS_SUCCESS == sme_post_ps_msg_to_wma(WMA_WOWL_EXIT_REQ, + hal_wowl_msg)){ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Msg WMA_WOWL_EXIT_REQ Successfully sent to WMA")); + return CDF_STATUS_SUCCESS; + } + if (hal_wowl_msg != NULL) + cdf_mem_free(hal_wowl_msg); + return CDF_STATUS_E_FAILURE; +} + +/** + * sme_ps_process_command(): Sme process power save messages + * and pass messages to WMA. + * @mac_ctx: global mac context + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_process_command(tpAniSirGlobal mac_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, "Invalid Session_id %x", session_id); + return eSIR_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Power Save command %d"), command); + switch (command) { + case SME_PS_ENABLE: + status = sme_ps_enable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_DISABLE: + status = sme_ps_disable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_ENABLE: + status = sme_ps_enable_uapsd_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_DISABLE: + status = sme_ps_disable_uapsd_req_params(mac_ctx, session_id); + break; + case SME_PS_WOWL_ENTER: + status = sme_ps_enter_wowl_req_params(mac_ctx, session_id); + break; + case SME_PS_WOWL_EXIT: + status = sme_ps_exit_wowl_req_params(mac_ctx, session_id); + break; + + default: + sms_log(mac_ctx, LOGE, FL("Invalid command type %d"), + command); + status = CDF_STATUS_E_FAILURE; + break; + } + if (status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to enter in PS, Command: %d"), command); + } + return status; +} + +/** + * sme_enable_sta_ps_check(): Checks if it is ok to enable power save or not. + * @mac_ctx: global mac context + * @session_id: session id + * + *Pre Condition for enabling sta mode power save + *1) Sta Mode Ps should be enabled in ini file. + *2) Session should be in infra mode and in connected state. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_enable_sta_ps_check(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + /* Check if Sta Ps is enabled. */ + if (!ps_global_info->ps_enabled) { + sms_log(mac_ctx, LOG1, + "Cannot initiate PS. PS is disabled in ini"); + return CDF_STATUS_E_FAILURE; + } + + /* Check whether the given session is Infra and in Connected State */ + if (!csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, "Sta not infra/connected state %d", + session_id); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; + +} + +/** + * sme_ps_enable_disable(): function to enable/disable PS. + * @hal_ctx: global hal_handle + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != CDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, command); + return status; +} + +/** + * sme_ps_uapsd_enable(): function to enable UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id) +{ + + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != CDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_ENABLE); + if (status == CDF_STATUS_SUCCESS) + sme_offload_qos_process_into_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_ps_uapsd_disable(): function to disable UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id) +{ + + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != CDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_DISABLE); + if (status == CDF_STATUS_SUCCESS) + sme_offload_qos_process_out_of_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_set_tspec_uapsd_mask_per_session(): set tspec UAPSD mask per session + * @mac_ctx: global mac context + * @ts_info: tspec info. + * @session_id: session id + * + * Return: CDF_STATUS + */ +void sme_set_tspec_uapsd_mask_per_session(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *ts_info, + uint8_t session_id) +{ + uint8_t user_prio = (uint8_t) ts_info->traffic.userPrio; + uint16_t direction = ts_info->traffic.direction; + uint8_t ac = upToAc(user_prio); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + sms_log(mac_ctx, LOGE, FL("Set UAPSD mask for AC %d, dir %d, action=%d") + , ac, direction, ts_info->traffic.psb); + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + if (ts_info->traffic.psb) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + } + } else { + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + } + } + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + if (direction == SIR_MAC_DIRECTION_UPLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_DNLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + + sms_log(mac_ctx, LOG1, + FL("New ps_param->uapsd_per_ac_trigger_enable_mask = 0x%x "), + ps_param->uapsd_per_ac_trigger_enable_mask); + sms_log(mac_ctx, LOG1, + FL("New ps_param->uapsd_per_ac_delivery_enable_mask = 0x%x "), + ps_param->uapsd_per_ac_delivery_enable_mask); + sms_log(mac_ctx, LOG1, + FL("New ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] = 0x%x "), + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK]); + return; +} + +/** + * sme_ps_start_uapsd(): function to start UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * @uapsd_start_ind_cb: uapsd start indiation cb + * @callback_context: callback context + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id, + uapsd_start_indication_cb uapsd_start_ind_cb, + void *callback_context) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + status = sme_ps_uapsd_enable(hal_ctx, session_id); + return status; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +static tSirRetStatus +sme_populate_mac_header(tpAniSirGlobal mac_ctx, + uint8_t *bd, + uint8_t type, + uint8_t sub_type, + tSirMacAddr peer_addr, tSirMacAddr self_mac_addr) +{ + tSirRetStatus status_code = eSIR_SUCCESS; + tpSirMacMgmtHdr mac_hdr; + + /* / Prepare MAC management header */ + mac_hdr = (tpSirMacMgmtHdr) (bd); + + /* Prepare FC */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = type; + mac_hdr->fc.subType = sub_type; + + /* Prepare Address 1 */ + cdf_mem_copy((uint8_t *) mac_hdr->da, (uint8_t *) peer_addr, + sizeof(tSirMacAddr)); + + sir_copy_mac_addr(mac_hdr->sa, self_mac_addr); + + /* Prepare Address 3 */ + cdf_mem_copy((uint8_t *) mac_hdr->bssId, (uint8_t *) peer_addr, + sizeof(tSirMacAddr)); + return status_code; +} /*** sme_populate_mac_header() ***/ + +static tSirRetStatus +sme_prepare_probe_req_template(tpAniSirGlobal mac_ctx, + uint8_t channel_num, + uint32_t dot11mode, + tSirMacAddr self_mac_addr, + uint8_t *frame, + uint16_t *pus_len, tCsrRoamSession *psession) +{ + tDot11fProbeRequest pr; + uint32_t status, bytes, payload; + tSirRetStatus sir_status; + /*Bcast tx */ + tSirMacAddr bss_id = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + /** + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + cdf_mem_set((uint8_t *) &pr, sizeof(pr), 0); + + populate_dot11f_supp_rates(mac_ctx, channel_num, &pr.SuppRates, NULL); + + if (WNI_CFG_DOT11_MODE_11B != dot11mode) { + populate_dot11f_ext_supp_rates1(mac_ctx, channel_num, + &pr.ExtSuppRates); + } + + if (IS_DOT11_MODE_HT(dot11mode)) { + populate_dot11f_ht_caps(mac_ctx, NULL, &pr.HTCaps); + pr.HTCaps.advCodingCap = psession->htConfig.ht_rx_ldpc; + pr.HTCaps.txSTBC = psession->htConfig.ht_tx_stbc; + pr.HTCaps.rxSTBC = psession->htConfig.ht_rx_stbc; + if (!psession->htConfig.ht_sgi) + pr.HTCaps.shortGI20MHz = pr.HTCaps.shortGI40MHz = 0; + } + /** + * That's it-- now we pack it. First, how much space are we going to + * need? + */ + status = dot11f_get_packed_probe_request_size(mac_ctx, &pr, &payload); + if (DOT11F_FAILED(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to calculate the packed size for a Probe Request (0x%08x)."), + status); + + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("There were warnings while calculating the packed size for a Probe Request (0x%08x)."), + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr); + + /* Prepare outgoing frame */ + cdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + sir_status = sme_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_REQ, bss_id, + self_mac_addr); + + if (eSIR_SUCCESS != sir_status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to populate the buffer descriptor for a Probe Request (%d)."), + sir_status); + return sir_status; /* allocated! */ + } + /* That done, pack the Probe Request: */ + status = dot11f_pack_probe_request(mac_ctx, &pr, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to pack a Probe Request (0x%08x).", status); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "There were warnings while packing a Probe Request"); + } + + *pus_len = payload + sizeof(tSirMacMgmtHdr); + return eSIR_SUCCESS; +} /* End sme_prepare_probe_req_template. */ + +CDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, + tpSirPNOScanReq request, + uint8_t session_id, + preferred_network_found_ind_cb callback_routine, + void *callback_context) +{ + tpSirPNOScanReq request_buf; + cds_msg_t msg; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + uint8_t uc_dot11_mode; + + if (NULL == session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: session is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: SSID = 0x%08x%08x%08x%08x%08x%08x%08x%08x, 0x%08x%08x%08x%08x%08x%08x%08x%08x", __func__, + *((uint32_t *) &request->aNetworks[0].ssId.ssId[0]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[4]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[8]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[12]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[16]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[20]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[24]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[28]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[0]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[4]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[8]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[12]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[16]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[20]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[24]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[28])); + + if (!session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: session is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for PNO request")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(request_buf, request, sizeof(tSirPNOScanReq)); + + /*Must translate the mode first */ + uc_dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + csr_find_best_phy_mode + (mac_ctx, + mac_ctx->roam. + configParam. + phyMode)); + + /*Prepare a probe request for 2.4GHz band and one for 5GHz band */ + if (eSIR_SUCCESS == + sme_prepare_probe_req_template(mac_ctx, + SIR_PNO_24G_DEFAULT_CH, + uc_dot11_mode, session->selfMacAddr.bytes, + request_buf->p24GProbeTemplate, + &request_buf->us24GProbeTemplateLen, + session)) { + /* Append IE passed by supplicant(if any) + * to probe request + */ + if ((0 < request->us24GProbeTemplateLen) && + ((request_buf->us24GProbeTemplateLen + + request->us24GProbeTemplateLen) < + SIR_PNO_MAX_PB_REQ_SIZE)) { + cdf_mem_copy((uint8_t *) &request_buf-> + p24GProbeTemplate + + request_buf->us24GProbeTemplateLen, + (uint8_t *) &request->p24GProbeTemplate, + request->us24GProbeTemplateLen); + request_buf->us24GProbeTemplateLen += + request->us24GProbeTemplateLen; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("request->us24GProbeTemplateLen = %d"), + request->us24GProbeTemplateLen); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("Extra ie discarded on 2.4G, IE len = %d"), + request->us24GProbeTemplateLen); + } + } + + if (eSIR_SUCCESS == + sme_prepare_probe_req_template(mac_ctx, + SIR_PNO_5G_DEFAULT_CH, uc_dot11_mode, + session->selfMacAddr.bytes, + request_buf->p5GProbeTemplate, + &request_buf->us5GProbeTemplateLen, + session)) { + /* Append IE passed by supplicant(if any) + * to probe request + */ + if ((0 < request->us5GProbeTemplateLen) && + ((request_buf->us5GProbeTemplateLen + + request->us5GProbeTemplateLen) < + SIR_PNO_MAX_PB_REQ_SIZE)) { + cdf_mem_copy((uint8_t *) &request_buf-> + p5GProbeTemplate + + request_buf->us5GProbeTemplateLen, + (uint8_t *) &request->p5GProbeTemplate, + request->us5GProbeTemplateLen); + request_buf->us5GProbeTemplateLen += + request->us5GProbeTemplateLen; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("request_buf->us5GProbeTemplateLen = %d"), + request->us5GProbeTemplateLen); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Extra IE discarded on 5G, IE length = %d"), + request->us5GProbeTemplateLen); + } + } + + if (mac_ctx->pnoOffload) { + if (request_buf->enable) + session->pnoStarted = true; + else + session->pnoStarted = false; + + request_buf->sessionId = session_id; + } + + msg.type = WMA_SET_PNO_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_PNO_REQ message to WMA")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + /* Cache the Preferred Network Found Indication callback information */ + mac_ctx->sme.pref_netw_found_cb = + callback_routine; + mac_ctx->sme.preferred_network_found_ind_cb_ctx = + callback_context; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "-%s", __func__); + + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/** + * sme_set_ps_host_offload(): Set the host offload feature. + * @hal_ctx - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return CDF_STATUS + * CDF_STATUS_E_FAILURE Cannot set the offload. + * CDF_STATUS_SUCCESS Request accepted. + */ +CDF_STATUS sme_set_ps_host_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpSirHostOffloadReq request_buf; + cds_msg_t msg; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: IP address = %d.%d.%d.%d", __func__, + request->params.hostIpv4Addr[0], + request->params.hostIpv4Addr[1], + request->params.hostIpv4Addr[2], + request->params.hostIpv4Addr[3]); + + if (NULL == session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: SESSION not Found", __func__); + return CDF_STATUS_E_FAILURE; + } + + request_buf = cdf_mem_malloc(sizeof(tSirHostOffloadReq)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for host offload request")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(request->bssId, session->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + cdf_mem_copy(request_buf, request, sizeof(tSirHostOffloadReq)); + + msg.type = WMA_SET_HOST_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_HOST_OFFLOAD msg to WMA")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * sme_set_ps_ns_offload(): Set the host offload feature. + * @hal_ctx - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return CDF_STATUS + * CDF_STATUS_E_FAILURE Cannot set the offload. + * CDF_STATUS_SUCCESS Request accepted. + */ +CDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tpSirHostOffloadReq request_buf; + cds_msg_t msg; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == session) { + sms_log(mac_ctx, LOGE, FL("Session not found ")); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(request->bssId, session->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + request_buf = cdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for NS offload request")); + return CDF_STATUS_E_NOMEM; + } + *request_buf = *request; + + msg.type = WMA_SET_NS_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Not able to post SIR_HAL_SET_HOST_OFFLOAD message to HAL")); + cdf_mem_free(request_buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +#endif /* WLAN_NS_OFFLOAD */ +/* -------------------------------------------------------------------- */ +/** + * sme_post_pe_message + * + * FUNCTION: + * Post a message to the pmm message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msg pointer to message + * @return None + */ + +tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + CDF_STATUS cdf_status; + cdf_status = cds_mq_post_message(CDS_MQ_ID_PE, (cds_msg_t *) msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(mac_ctx, LOGP, + FL("cds_mq_post_message failed with status code %d"), + cdf_status); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +CDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t session_id, + bool is_reassoc) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + CDF_STATUS cdf_status; + uint32_t timer_value; + + if (is_reassoc) + timer_value = AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE; + else + timer_value = AUTO_DEFERRED_PS_ENTRY_TIMER_DEFAULT_VALUE; + + sms_log(mac_ctx, LOGE, FL("Start auto_ps_timer for %d is_reassoc:%d "), + timer_value, is_reassoc); + + cdf_status = cdf_mc_timer_start(&ps_param->auto_ps_enable_timer, + timer_value); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + if (CDF_STATUS_E_ALREADY == cdf_status) { + /* Consider this ok since the timer is already started*/ + sms_log(mac_ctx, LOGW, + FL("auto_ps_timer is already started")); + } else { + sms_log(mac_ctx, LOGP, + FL("Cannot start auto_ps_timer")); + return CDF_STATUS_E_FAILURE; + } + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + /* + * Stop the auto ps entry timer if runnin + */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + sms_log(mac_ctx, LOGE, + FL("Stop auto_ps_enable_timer Timer for session ID:%d "), + session_id); + cdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + } + return CDF_STATUS_SUCCESS; +} + + +CDF_STATUS sme_ps_open(tHalHandle hal_ctx) +{ + + uint32_t i; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + sms_log(mac_ctx, LOG1, FL("Enter")); + + for (i = 0; i < MAX_SME_SESSIONS; i++) { + if (CDF_STATUS_SUCCESS != sme_ps_open_per_session(hal_ctx, i)) { + sms_log(mac_ctx, LOGE, + FL("PMC Init Failed for session %d"), i); + return CDF_STATUS_E_FAILURE; + } + } + return CDF_STATUS_SUCCESS; +} + + +CDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + ps_param->session_id = session_id; + ps_param->mac_ctx = mac_ctx; + + sms_log(mac_ctx, LOG1, FL("Enter")); + /* Allocate a timer to enable ps automatically */ + if (!CDF_IS_STATUS_SUCCESS(cdf_mc_timer_init( + &ps_param->auto_ps_enable_timer, + CDF_TIMER_TYPE_SW, + sme_auto_ps_entry_timer_expired, + ps_param))) { + sms_log(mac_ctx, LOGE, + FL("Cannot allocate timer for auto ps entry")); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; + +} + +void sme_auto_ps_entry_timer_expired(void *data) +{ + struct ps_params *ps_params = (struct ps_params *)data; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)ps_params->mac_ctx; + uint32_t session_id = ps_params->session_id; + CDF_STATUS status = CDF_STATUS_SUCCESS; + status = sme_enable_sta_ps_check(mac_ctx, session_id); + + if (CDF_STATUS_SUCCESS == status) { + sme_ps_enable_disable((tHalHandle)mac_ctx, session_id, + SME_PS_ENABLE); + } else { + status = + cdf_mc_timer_start(&ps_params->auto_ps_enable_timer, + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE); + if (!CDF_IS_STATUS_SUCCESS(status) + && (CDF_STATUS_E_ALREADY != status)) { + sms_log(mac_ctx, LOGP, + FL("Cannot start traffic timer")); + } + } +} + +CDF_STATUS sme_ps_close(tHalHandle hal_ctx) +{ + uint32_t i; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + sms_log(mac_ctx, LOG2, FL("Enter")); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + sme_ps_close_per_session(hal_ctx, i); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t session_id) +{ + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + /* + * Stop the auto ps entry timer if running + */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + cdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + } + cdf_status = + cdf_mc_timer_destroy(&ps_param->auto_ps_enable_timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + sms_log(mac_ctx, LOGE, FL("Cannot deallocate suto PS timer")); + return cdf_status; +} + +CDF_STATUS sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + bool status = false; + /* + * Check if the auto ps entry timer if running + */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + status = true; + } + return status; +} + diff --git a/core/sme/src/common/sme_trace.c b/core/sme/src/common/sme_trace.c new file mode 100644 index 0000000000..d6d85fd444 --- /dev/null +++ b/core/sme/src/common/sme_trace.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/************************************************************************ + smeTrace.c + + \brief implementation for trace related APIs + + \author Kiran Kumar Reddy CH L V + + ========================================================================*/ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "sms_debug.h" +#include "mac_trace.h" +#include "sme_trace.h" +#include "sme_internal.h" +#ifndef SME_TRACE_RECORD +void sme_trace_init(tpAniSirGlobal pMac) +{ + return; +} +#endif +#ifdef SME_TRACE_RECORD + +static uint8_t *sme_trace_get_rx_msg_string(uint32_t code) +{ + switch (code) { + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_CONNECT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_REASSOC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_BMPS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENTER_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXIT_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_KEY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_STATS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_RSSI); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_OPEN_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLOSE_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SEND_ACTION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2); +#endif + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TMLEVEL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CAPS_EXCH); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_CAP); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_DEFCCNV); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CURCC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_RESET_PW5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RP5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_SCANCTRL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ); + + default: + return "UNKNOWN"; + break; + } +} + +static uint8_t *sme_trace_get_command_string(uint32_t command) +{ + switch (command) { + CASE_RETURN_STRING(eSmeNoCommand); + CASE_RETURN_STRING(eSmeDropCommand); + CASE_RETURN_STRING(eSmeCsrCommandMask); + CASE_RETURN_STRING(eSmeCommandScan); + CASE_RETURN_STRING(eSmeCommandRoam); + CASE_RETURN_STRING(eSmeCommandWmStatusChange); + CASE_RETURN_STRING(eSmeCommandSetKey); + CASE_RETURN_STRING(eSmeCommandAddStaSession); + CASE_RETURN_STRING(eSmeCommandDelStaSession); + CASE_RETURN_STRING(eSmePmcCommandMask); + CASE_RETURN_STRING(eSmeCommandEnterBmps); + CASE_RETURN_STRING(eSmeCommandExitBmps); + CASE_RETURN_STRING(eSmeCommandEnterUapsd); + CASE_RETURN_STRING(eSmeCommandExitUapsd); + CASE_RETURN_STRING(eSmeCommandEnterStandby); + CASE_RETURN_STRING(eSmeQosCommandMask); + CASE_RETURN_STRING(eSmeCommandAddTs); + CASE_RETURN_STRING(eSmeCommandDelTs); +#ifdef FEATURE_OEM_DATA_SUPPORT + CASE_RETURN_STRING(eSmeCommandOemDataReq); +#endif + CASE_RETURN_STRING(eSmeCommandRemainOnChannel); + default: + return "UNKNOWN"; + break; + } +} + +static void sme_trace_dump(tpAniSirGlobal pMac, tp_cdf_trace_record pRecord, + uint16_t recIndex) +{ + if (TRACE_CODE_SME_COMMAND == pRecord->code) { + sms_log(pMac, LOGE, "%04d %012llu S%d %-14s %-30s(0x%x)", + recIndex, pRecord->time, pRecord->session, + "SME COMMAND:", sme_trace_get_command_string(pRecord->data), + pRecord->data); + } else { + sms_log(pMac, LOGE, "%04d %012llu S%d %-14s %-30s(0x%x)", + recIndex, pRecord->time, pRecord->session, "RX HDD MSG:", + sme_trace_get_rx_msg_string(pRecord->code), pRecord->data); + } +} + +void sme_trace_init(tpAniSirGlobal pMac) +{ + cdf_trace_register(CDF_MODULE_ID_SME, (tp_cdf_trace_cb) & sme_trace_dump); +} +#endif diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c new file mode 100644 index 0000000000..9074f37cae --- /dev/null +++ b/core/sme/src/csr/csr_api_roam.c @@ -0,0 +1,18860 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_api_roam.c + + Implementation for the Common Roaming interfaces. + ========================================================================== */ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "wma_types.h" +#include "wma_if.h" /* for STA_INVALID_IDX. */ +#include "lim_utils.h" +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "csr_internal.h" +#include "cds_reg_service.h" +#include "mac_trace.h" +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +#include "csr_neighbor_roam.h" +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ +#include "cds_regdomain_common.h" +#include "cds_utils.h" +#include "sir_types.h" +#include "cfg_api.h" +#include "sme_power_save_api.h" +#include "wma.h" +#include "cds_concurrency.h" + +#define CSR_NUM_IBSS_START_CHANNELS_50 4 +#define CSR_NUM_IBSS_START_CHANNELS_24 3 +/* 5 seconds, for WPA, WPA2, CCKM */ +#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD (5 * CDF_MC_TIMER_TO_SEC_UNIT) +/* 120 seconds, for WPS */ +#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * CDF_MC_TIMER_TO_SEC_UNIT) + +/*--------------------------------------------------------------------------- + OBIWAN recommends [8 10]% : pick 9% + ---------------------------------------------------------------------------*/ +#define CSR_VCC_UL_MAC_LOSS_THRESHOLD 9 +/*--------------------------------------------------------------------------- + OBIWAN recommends -85dBm + ---------------------------------------------------------------------------*/ +#define CSR_VCC_RSSI_THRESHOLD 80 +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD 500 /* ms */ +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS 2000 /* ms */ +#define CSR_MIN_TL_STAT_QUERY_PERIOD 500 /* ms */ +/* Flag to send/do not send disassoc frame over the air */ +#define CSR_DONT_SEND_DISASSOC_OVER_THE_AIR 1 +#define RSSI_HACK_BMPS (-40) +#define MAX_CB_VALUE_IN_INI (2) + +#define MAX_SOCIAL_CHANNELS 3 +/* Choose the largest possible value that can be accomodates in 8 bit signed */ +/* variable. */ +#define SNR_HACK_BMPS (127) + +static bool b_roam_scan_offload_started; + +/*-------------------------------------------------------------------------- + Static Type declarations + ------------------------------------------------------------------------*/ +static tCsrRoamSession csr_roam_roam_session[CSR_ROAM_SESSION_MAX]; + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +int diag_auth_type_from_csr_type(eCsrAuthType authType) +{ + int n = AUTH_OPEN; + switch (authType) { + case eCSR_AUTH_TYPE_SHARED_KEY: + n = AUTH_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + n = AUTH_WPA_EAP; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + n = AUTH_WPA_PSK; + break; + case eCSR_AUTH_TYPE_RSN: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + n = AUTH_WPA2_EAP; + break; + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: +#endif + n = AUTH_WPA2_PSK; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + n = AUTH_WAPI_CERT; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + n = AUTH_WAPI_PSK; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} + +int diag_enc_type_from_csr_type(eCsrEncryptionType encType) +{ + int n = ENC_MODE_OPEN; + switch (encType) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + n = ENC_MODE_WEP40; + break; + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + n = ENC_MODE_WEP104; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + n = ENC_MODE_TKIP; + break; + case eCSR_ENCRYPT_TYPE_AES: + n = ENC_MODE_AES; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + n = ENC_MODE_SMS4; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ +static const uint8_t + csr_start_ibss_channels50[CSR_NUM_IBSS_START_CHANNELS_50] = { 36, 40, 44, 48 }; +static const uint8_t + csr_start_ibss_channels24[CSR_NUM_IBSS_START_CHANNELS_24] = { 1, 6, 11 }; +static void init_config_param(tpAniSirGlobal pMac); +static bool csr_roam_process_results(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrRoamCompleteResult Result, + void *Context); +static CDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + bool *pfSameIbss); +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo * + pNewBss); +static void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes); +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t primaryChn, + tDot11fBeaconIEs *pIes); + +static void csr_roaming_state_config_cnf_processor(tpAniSirGlobal pMac, + uint32_t result); +CDF_STATUS csr_roam_open(tpAniSirGlobal pMac); +CDF_STATUS csr_roam_close(tpAniSirGlobal pMac); +void csr_roamMICErrorTimerHandler(void *pv); +void csr_roamTKIPCounterMeasureTimerHandler(void *pv); +bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + tCsrRoamProfile *pProfile2); + +static CDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId, + uint32_t interval); +static CDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId); +static void csr_roam_roaming_timer_handler(void *pv); +CDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval); +CDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac); +static void csr_roam_wait_for_key_time_out_handler(void *pv); +static CDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo); +static CDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, + tCsr11dinfo *ps11dinfo); +static CDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + tCsrRoamConnectedInfo * + pConnectedInfo); +CDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr peerMacAddr, uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc); +static CDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, + tCsrRoamProfile *pProfile); +void csr_roamStatisticsTimerHandler(void *pv); +void csr_roamStatsGlobalClassDTimerHandler(void *pv); +static void csr_roam_link_up(tpAniSirGlobal pMac, struct cdf_mac_addr bssid); +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_roam_vcc_trigger(tpAniSirGlobal pMac); +CDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask, + uint8_t staId, uint8_t sessionId); +/* + pStaEntry is no longer invalid upon the return of this function. + */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry); +static eCsrCfgDot11Mode csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + uint8_t operationChn, + eCsrBand *pBand); +static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac, + tDblLinkList *pStaList, + tCsrStatsClientReqInfo * + pStaEntry); +void csr_roam_stats_client_timer_handler(void *pv); +tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac, + uint32_t statsMask, + uint32_t periodicity, + bool *pFound, uint8_t staId, + uint8_t sessionId); +void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask, + tCsrStatsCallback callback, uint8_t staId, + void *pContext); +void csr_roam_tl_stats_timer_handler(void *pv); +void csr_roam_pe_stats_timer_handler(void *pv); +tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask); +void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac, + tCsrPeStatsReqInfo *pPeStaEntry); +tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask); +CDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac); +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac); +static uint32_t csr_find_session_by_type(tpAniSirGlobal, tCDF_CON_MODE); +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal pMac, uint32_t chnl); +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal pMac, uint32_t chnl); +static CDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc); +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId); +static CDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamSetKey *pSetKey, + uint32_t roamId); +static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +void csr_roam_reissue_roam_command(tpAniSirGlobal pMac); +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, + tSirSmeDisassocRsp *pRsp); +void csr_reinit_preauth_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_init_operating_classes(tHalHandle hHal); + +/* Initialize global variables */ +static void csr_roam_init_globals(tpAniSirGlobal pMac) +{ + if (pMac) { + cdf_mem_zero(&csr_roam_roam_session, sizeof(csr_roam_roam_session)); + pMac->roam.roamSession = csr_roam_roam_session; + } + return; +} + +static void csr_roam_de_init_globals(tpAniSirGlobal pMac) +{ + if (pMac) { + pMac->roam.roamSession = NULL; + } + return; +} + +CDF_STATUS csr_open(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* Initialize CSR Roam Globals */ + csr_roam_init_globals(pMac); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, i); + + init_config_param(pMac); + status = csr_scan_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_roam_open(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + pMac->roam.nextRoamId = 1; /* Must not be 0 */ + if (!CDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.statsClientReqList))) + break; + if (!CDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.peStatsReqList))) + break; + if (!CDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.roamCmdPendingList))) + break; + } while (0); + + return status; +} + +CDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2) +{ + CDF_STATUS status; + v_REGDOMAIN_t reg_id; + v_CountryInfoSource_t source = COUNTRY_INIT; + + mac->scan.countryCodeDefault[0] = alpha2[0]; + mac->scan.countryCodeDefault[1] = alpha2[1]; + mac->scan.countryCodeDefault[2] = alpha2[2]; + + sms_log(mac, LOGE, FL("init time country code %.2s"), + mac->scan.countryCodeDefault); + + status = csr_get_regulatory_domain_for_country(mac, + mac->scan.countryCodeDefault, + ®_id, source); + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("csr_get_regulatory_domain_for_country failed")); + return status; + } + + if (cds_set_reg_domain(mac, reg_id) != CDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, FL("cds_set_reg_domain failed")); + return CDF_STATUS_E_FAILURE; + } + mac->scan.domainIdDefault = reg_id; + mac->scan.domainIdCurrent = mac->scan.domainIdDefault; + cdf_mem_copy(mac->scan.countryCodeCurrent, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + cdf_mem_copy(mac->scan.countryCodeElected, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + status = csr_get_channel_and_power_list(mac); + csr_clear_votes_for_country_info(mac); + return status; +} + +CDF_STATUS csr_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_REGDOMAIN_t regId; + uint8_t cntryCodeLength; + if (NULL == apCntryCode) { + sms_log(pMac, LOGE, FL(" Invalid country Code Pointer")); + return CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" country Code %.2s"), apCntryCode); + + cntryCodeLength = WNI_CFG_COUNTRY_CODE_LEN; + status = csr_get_regulatory_domain_for_country(pMac, apCntryCode, ®Id, + COUNTRY_USER); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL(" fail to get regId for country Code %.2s"), + apCntryCode); + return status; + } + status = wma_set_reg_domain(hHal, regId); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL(" fail to get regId for country Code %.2s"), + apCntryCode); + return status; + } + pMac->scan.domainIdDefault = regId; + pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault; + /* Clear CC field */ + cdf_mem_set(pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN, 0); + + /* Copy 2 or 3 bytes country code */ + cdf_mem_copy(pMac->scan.countryCodeDefault, apCntryCode, + cntryCodeLength); + + /* If 2 bytes country code, 3rd byte must be filled with space */ + if ((WNI_CFG_COUNTRY_CODE_LEN - 1) == cntryCodeLength) { + cdf_mem_set(pMac->scan.countryCodeDefault + 2, 1, 0x20); + } + cdf_mem_copy(pMac->scan.countryCodeCurrent, + pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + status = csr_get_channel_and_power_list(pMac); + return status; +} + +CDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t index = 0; + cdf_mem_copy(pParam->Csr11dinfo.countryCode, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + pParam->Csr11dinfo.Channels.channelList[index] = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].firstChannel = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].numChannels = 1; + pParam->Csr11dinfo.ChnPower[index].maxtxPower = + pMac->scan.defaultPowerTable[index].pwr; + } + pParam->Csr11dinfo.Channels.numChannels = + pMac->scan.base_channels.numChannels; + + return status; +} + +CDF_STATUS csr_close(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + csr_roam_close(pMac); + csr_scan_close(pMac); + csr_ll_close(&pMac->roam.statsClientReqList); + csr_ll_close(&pMac->roam.peStatsReqList); + csr_ll_close(&pMac->roam.roamCmdPendingList); + /* DeInit Globals */ + csr_roam_de_init_globals(pMac); + return status; +} + +static tPowerdBm csr_find_channel_pwr(tChannelListWithPower * + pdefaultPowerTable, + uint8_t ChannelNum) +{ + uint8_t i; + /* TODO: if defaultPowerTable is guaranteed to be in ascending */ + /* order of channel numbers, we can employ binary search */ + for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pdefaultPowerTable[i].chanId == ChannelNum) + return pdefaultPowerTable[i].pwr; + } + /* could not find the channel list in default list */ + /* this should not have occured */ + CDF_ASSERT(0); + return 0; +} + +CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) +{ + tSirUpdateChanList *pChanList; + tCsrScanStruct *pScan = &pMac->scan; + uint8_t numChan = pScan->base_channels.numChannels; + uint8_t num_channel = 0; + uint32_t bufLen; + cds_msg_t msg; + uint8_t i, j, social_channel[MAX_SOCIAL_CHANNELS] = { 1, 6, 11 }; + uint8_t channel_state; + + if (CSR_IS_5G_BAND_ONLY(pMac)) { + for (i = 0; i < MAX_SOCIAL_CHANNELS; i++) { + if (cds_get_channel_state(social_channel[i]) + == CHANNEL_STATE_ENABLE) + numChan++; + } + } + + bufLen = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * (numChan)); + + csr_init_operating_classes((tHalHandle) pMac); + pChanList = (tSirUpdateChanList *) cdf_mem_malloc(bufLen); + if (!pChanList) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(pChanList, bufLen); + + for (i = 0; i < pScan->base_channels.numChannels; i++) { + /* Scan is not performed on DSRC channels*/ + if (pScan->base_channels.channelList[i] >= MIN_11P_CHANNEL) + continue; + if (pScan->fcc_constraint) { + if (pScan->base_channels.channelList[i] == 12) + continue; + if (pScan->base_channels.channelList[i] == 13) + continue; + } + channel_state = + cds_get_channel_state( + pScan->base_channels.channelList[i]); + if ((CHANNEL_STATE_ENABLE == channel_state) || + pMac->scan.fEnableDFSChnlScan) { + pChanList->chanParam[num_channel].chanId = + pScan->base_channels.channelList[i]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + pChanList->chanParam[num_channel].chanId); + if (CHANNEL_STATE_ENABLE == channel_state) + pChanList->chanParam[num_channel].dfsSet = + false; + else + pChanList->chanParam[num_channel].dfsSet = + true; + num_channel++; + } + } + + if (CSR_IS_5G_BAND_ONLY(pMac)) { + for (j = 0; j < MAX_SOCIAL_CHANNELS; j++) { + if (cds_get_channel_state(social_channel[j]) + == CHANNEL_STATE_ENABLE) { + pChanList->chanParam[num_channel].chanId = + social_channel[j]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + social_channel[j]); + pChanList->chanParam[num_channel].dfsSet = false; + num_channel++; + } + } + } + + msg.type = WMA_UPDATE_CHAN_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = pChanList; + pChanList->numChan = num_channel; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to post msg to WMA", __func__); + cdf_mem_free(pChanList); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_start(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* save the global cds context */ + pMac->roam.g_cds_context = cds_get_global_context(); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, i); + + status = csr_roam_start(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + + pMac->roam.sPendingCommands = 0; + csr_scan_enable(pMac); +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + status = csr_neighbor_roam_init(pMac, i); +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ + pMac->roam.tlStatsReqInfo.numClient = 0; + pMac->roam.tlStatsReqInfo.periodicity = 0; + pMac->roam.tlStatsReqInfo.timerRunning = false; + /* init the link quality indication also */ + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_MIN_IND; + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + " csr_start: Couldn't Init HO control blk "); + break; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Scan offload is enabled, update default chan list"); + status = csr_update_channel_list(pMac); + + } while (0); + return status; +} + +CDF_STATUS csr_stop(tpAniSirGlobal pMac, tHalStopType stopType) +{ + uint32_t sessionId; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_close_session(pMac, sessionId, true, NULL, NULL); + } + csr_scan_disable(pMac); + pMac->scan.fCancelIdleScan = false; + pMac->scan.fRestartIdleScan = false; + csr_ll_purge(&pMac->roam.roamCmdPendingList, true); + +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + csr_neighbor_roam_close(pMac, sessionId); +#endif + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + csr_scan_flush_result(pMac); + + /* Reset the domain back to the deault */ + pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, sessionId); + pMac->roam.curSubState[sessionId] = eCSR_ROAM_SUBSTATE_NONE; + } + + /* When HAL resets all the context information + * in HAL is lost, so we might need to send the + * scan offload request again when it comes + * out of reset for scan offload to be functional + */ + if (HAL_STOP_TYPE_SYS_RESET == stopType) { + b_roam_scan_offload_started = false; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_ready(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + /* If the gScanAgingTime is set to '0' then scan results aging timeout + based on timer feature is not enabled */ + + if (0 != pMac->scan.scanResultCfgAgingTime) { + csr_scan_start_result_cfg_aging_timer(pMac); + } + status = csr_apply_channel_and_power_list(pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_apply_channel_and_power_list failed during csr_ready with status=%d", + status); + } + return status; +} + +void csr_set_default_dot11_mode(tpAniSirGlobal pMac) +{ + uint32_t wniDot11mode = 0; + wniDot11mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pMac->roam.configParam.uCfgDot11Mode); + cfg_set_int(pMac, WNI_CFG_DOT11_MODE, wniDot11mode); +} + +void csr_set_global_cfgs(tpAniSirGlobal pMac) +{ + + cfg_set_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, + csr_get_frag_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_RTS_THRESHOLD, csr_get_rts_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pMac->roam.configParam.Is11hSupportEnabled) ? pMac->roam. + configParam.Is11dSupportEnabled : pMac->roam.configParam. + Is11dSupportEnabled)); + cfg_set_int(pMac, WNI_CFG_11H_ENABLED, + pMac->roam.configParam.Is11hSupportEnabled); + /* For now we will just use the 5GHz CB mode ini parameter to decide whether CB supported or not in Probes when there is no session + * Once session is established we will use the session related params stored in PE session for CB mode + */ + cfg_set_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, + !!(pMac->roam.configParam.channelBondingMode5GHz)); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + + /* Update the operating mode to configured value during initialization, */ + /* So that client can advertise full capabilities in Probe request frame. */ + csr_set_default_dot11_mode(pMac); +} + +CDF_STATUS csr_roam_open(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t i; + tCsrRoamSession *pSession; + do { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pSession = CSR_GET_SESSION(pMac, i); + pSession->roamingTimerInfo.pMac = pMac; + pSession->roamingTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + } + pMac->roam.WaitForKeyTimerInfo.pMac = pMac; + pMac->roam.WaitForKeyTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + status = + cdf_mc_timer_init(&pMac->roam.hTimerWaitForKey, + CDF_TIMER_TYPE_SW, + csr_roam_wait_for_key_time_out_handler, + &pMac->roam.WaitForKeyTimerInfo); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for WaitForKey time out timer")); + break; + } + status = + cdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer, + CDF_TIMER_TYPE_SW, + csr_roam_tl_stats_timer_handler, pMac); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for summary Statistics timer")); + return CDF_STATUS_E_FAILURE; + } + } while (0); + return status; +} + +CDF_STATUS csr_roam_close(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_close_session(pMac, sessionId, true, NULL, NULL); + } + cdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); + cdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey); + cdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + cdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_start(tpAniSirGlobal pMac) +{ + (void)pMac; + return CDF_STATUS_SUCCESS; +} + +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId) +{ + csr_roam_stop_roaming_timer(pMac, sessionId); + /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */ + csr_roam_dereg_statistics_req(pMac); +} + +CDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + if (CSR_IS_SESSION_VALID(pMac, sessionId) && (NULL != pState)) { + status = CDF_STATUS_SUCCESS; + *pState = pMac->roam.roamSession[sessionId].connectState; + } + return status; +} + +CDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t size = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrRoamConnectedProfile *connected_prof; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + if (!pProfile) { + sms_log(pMac, LOGE, FL("profile not found")); + return CDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (size) { + pProfile->pBssDesc = cdf_mem_malloc(size); + if (NULL != pProfile->pBssDesc) { + cdf_mem_copy(pProfile->pBssDesc, + pSession->pConnectBssDesc, + size); + status = CDF_STATUS_SUCCESS; + } else { + return CDF_STATUS_E_FAILURE; + } + } else { + pProfile->pBssDesc = NULL; + } + connected_prof = &(pSession->connectedProfile); + pProfile->AuthType = connected_prof->AuthType; + pProfile->EncryptionType = connected_prof->EncryptionType; + pProfile->mcEncryptionType = connected_prof->mcEncryptionType; + pProfile->BSSType = connected_prof->BSSType; + pProfile->operationChannel = connected_prof->operationChannel; + pProfile->CBMode = connected_prof->CBMode; + cdf_mem_copy(&pProfile->bssid, &connected_prof->bssid, + sizeof(struct cdf_mac_addr)); + cdf_mem_copy(&pProfile->SSID, &connected_prof->SSID, + sizeof(tSirMacSSid)); +#ifdef WLAN_FEATURE_VOWIFI_11R + if (connected_prof->MDID.mdiePresent) { + pProfile->MDID.mdiePresent = 1; + pProfile->MDID.mobilityDomain = + connected_prof->MDID.mobilityDomain; + } else { + pProfile->MDID.mdiePresent = 0; + pProfile->MDID.mobilityDomain = 0; + } +#endif +#ifdef FEATURE_WLAN_ESE + pProfile->isESEAssoc = connected_prof->isESEAssoc; + if (csr_is_auth_type_ese(connected_prof->AuthType)) { + cdf_mem_copy(pProfile->eseCckmInfo.krk, + connected_prof->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + cdf_mem_copy(pProfile->eseCckmInfo.btk, + connected_prof->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); +#endif + pProfile->eseCckmInfo.reassoc_req_num = + connected_prof->eseCckmInfo.reassoc_req_num; + pProfile->eseCckmInfo.krk_plumbed = + connected_prof->eseCckmInfo.krk_plumbed; + } +#endif + } + return status; +} + +CDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if ((csr_is_conn_state_connected(pMac, sessionId)) || + (csr_is_conn_state_ibss(pMac, sessionId))) { + if (pProfile) { + status = + csr_roam_copy_connect_profile(pMac, sessionId, + pProfile); + } + } + return status; +} + +CDF_STATUS csr_roam_free_connect_profile(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (pProfile->pBssDesc) { + cdf_mem_free(pProfile->pBssDesc); + } + if (pProfile->pAddIEAssoc) { + cdf_mem_free(pProfile->pAddIEAssoc); + } + cdf_mem_set(pProfile, sizeof(tCsrRoamConnectedProfile), 0); + + pProfile->AuthType = eCSR_AUTH_TYPE_UNKNOWN; + return status; +} + +static CDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + tCsrRoamConnectedInfo * + pConnectedInfo) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + if (pConnectedInfo->pbFrames) { + cdf_mem_free(pConnectedInfo->pbFrames); + pConnectedInfo->pbFrames = NULL; + } + pConnectedInfo->nBeaconLength = 0; + pConnectedInfo->nAssocReqLength = 0; + pConnectedInfo->nAssocRspLength = 0; + pConnectedInfo->staId = 0; +#ifdef WLAN_FEATURE_VOWIFI_11R + pConnectedInfo->nRICRspLength = 0; +#endif +#ifdef FEATURE_WLAN_ESE + pConnectedInfo->nTspecIeLength = 0; +#endif + return status; +} + +void csr_release_command_preauth(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_preauth_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_roam_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + cdf_mc_timer_stop(&pCommand->u.scanCmd.csr_scan_timer); + cdf_mc_timer_destroy(&pCommand->u.scanCmd.csr_scan_timer); + csr_reinit_scan_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_wm_status_change_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_reinit_set_key_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + cdf_mem_set(&pCommand->u.setKeyCmd, sizeof(tSetKeyCmd), 0); +} + +void csr_release_command_set_key(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_set_key_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +/** + * csr_release_roc_req_cmd() - Release the command + * @mac_ctx: Global MAC Context + * + * Release the remain on channel request command from the queue + * + * Return: None + */ +void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx) +{ + tListElem *entry; + tSmeCmd *cmd = NULL; + + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (entry) { + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel == cmd->command) { + remainOnChanCallback callback = + cmd->u.remainChlCmd.callback; + /* process the msg */ + if (callback) + callback(mac_ctx, + cmd->u.remainChlCmd.callbackCtx, 0, + cmd->u.remainChlCmd.scan_id); + sms_log(mac_ctx, LOGE, + FL("Remove RoC Request from Active Cmd List")); + /* Put this cmd back on the available command list */ + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, + entry, LL_ACCESS_LOCK)) + sme_release_command(mac_ctx, cmd); + } + } +} + +void csr_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, bool fStopping) +{ + + if (eSmeCsrCommandMask & pCommand->command) { + switch (pCommand->command) { + case eSmeCommandScan: + /* We need to inform the requester before dropping the scan command */ + sms_log(pMac, LOGW, + "%s: Drop scan reason %d callback %p", __func__, + pCommand->u.scanCmd.reason, + pCommand->u.scanCmd.callback); + if (NULL != pCommand->u.scanCmd.callback) { + sms_log(pMac, LOGW, "%s callback scan requester", + __func__); + csr_scan_call_callback(pMac, pCommand, + eCSR_SCAN_ABORT); + } + csr_release_command_scan(pMac, pCommand); + break; + case eSmeCommandRoam: + csr_release_command_roam(pMac, pCommand); + break; + + case eSmeCommandWmStatusChange: + csr_release_command_wm_status_change(pMac, pCommand); + break; + + case eSmeCommandSetKey: + csr_release_command_set_key(pMac, pCommand); + break; + + default: + sms_log(pMac, LOGW, " CSR abort standard command %d", + pCommand->command); + csr_release_command(pMac, pCommand); + break; + } + } +} + +void csr_roam_substate_change(tpAniSirGlobal pMac, eCsrRoamSubState NewSubstate, + uint32_t sessionId) +{ + sms_log(pMac, LOG1, FL("CSR RoamSubstate: [ %s <== %s ]"), + mac_trace_getcsr_roam_sub_state(NewSubstate), + mac_trace_getcsr_roam_sub_state(pMac->roam.curSubState[sessionId])); + if (pMac->roam.curSubState[sessionId] == NewSubstate) { + return; + } + pMac->roam.curSubState[sessionId] = NewSubstate; +} + +eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac, + eCsrRoamState NewRoamState, uint8_t sessionId) +{ + eCsrRoamState PreviousState; + + sms_log(pMac, LOG1, FL("CSR RoamState[%hu]: [ %s <== %s ]"), sessionId, + mac_trace_getcsr_roam_state(NewRoamState), + mac_trace_getcsr_roam_state(pMac->roam.curState[sessionId])); + PreviousState = pMac->roam.curState[sessionId]; + + if (NewRoamState != pMac->roam.curState[sessionId]) { + /* Whenever we transition OUT of the Roaming state, clear the Roaming substate... */ + if (CSR_IS_ROAM_JOINING(pMac, sessionId)) { + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + pMac->roam.curState[sessionId] = NewRoamState; + } + return PreviousState; +} + +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset) +{ + int i; + if (catOffset) { + pMac->roam.configParam.bCatRssiOffset = catOffset; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) { + pMac->roam.configParam.RSSICat[CSR_NUM_RSSI_CAT - i - + 1] = + (int)bestApRssi - + pMac->roam.configParam.nSelect5GHzMargin - + (int)(i * catOffset); + } + } +} + +static void init_config_param(tpAniSirGlobal pMac) +{ + int i; + pMac->roam.configParam.agingCount = CSR_AGING_COUNT; + pMac->roam.configParam.channelBondingMode24GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + pMac->roam.configParam.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + + pMac->roam.configParam.phyMode = eCSR_DOT11_MODE_AUTO; + pMac->roam.configParam.eBand = eCSR_BAND_ALL; + pMac->roam.configParam.uCfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + pMac->roam.configParam.FragmentationThreshold = + eCSR_DOT11_FRAG_THRESH_DEFAULT; + pMac->roam.configParam.HeartbeatThresh24 = 40; + pMac->roam.configParam.HeartbeatThresh50 = 40; + pMac->roam.configParam.Is11dSupportEnabled = false; + pMac->roam.configParam.Is11dSupportEnabledOriginal = false; + pMac->roam.configParam.Is11eSupportEnabled = true; + pMac->roam.configParam.Is11hSupportEnabled = true; + pMac->roam.configParam.RTSThreshold = 2346; + pMac->roam.configParam.shortSlotTime = true; + pMac->roam.configParam.WMMSupportMode = eCsrRoamWmmAuto; + pMac->roam.configParam.ProprietaryRatesEnabled = true; + pMac->roam.configParam.TxRate = eCSR_TX_RATE_AUTO; + pMac->roam.configParam.scanAgeTimeNCNPS = + CSR_SCAN_AGING_TIME_NOT_CONNECT_NO_PS; + pMac->roam.configParam.scanAgeTimeNCPS = + CSR_SCAN_AGING_TIME_NOT_CONNECT_W_PS; + pMac->roam.configParam.scanAgeTimeCNPS = + CSR_SCAN_AGING_TIME_CONNECT_NO_PS; + pMac->roam.configParam.scanAgeTimeCPS = + CSR_SCAN_AGING_TIME_CONNECT_W_PS; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) { + pMac->roam.configParam.BssPreferValue[i] = i; + } + csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE, + CSR_DEFAULT_RSSI_DB_GAP); + pMac->roam.configParam.nRoamingTime = CSR_DEFAULT_ROAMING_TIME; + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = false; + pMac->roam.configParam.nActiveMaxChnTime = CSR_ACTIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nActiveMinChnTime = CSR_ACTIVE_MIN_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMaxChnTime = + CSR_PASSIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMinChnTime = + CSR_PASSIVE_MIN_CHANNEL_TIME; +#ifdef WLAN_AP_STA_CONCURRENCY + pMac->roam.configParam.nActiveMaxChnTimeConc = + CSR_ACTIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nActiveMinChnTimeConc = + CSR_ACTIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMaxChnTimeConc = + CSR_PASSIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMinChnTimeConc = + CSR_PASSIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nRestTimeConc = CSR_REST_TIME_CONC; + pMac->roam.configParam.nNumStaChanCombinedConc = + CSR_NUM_STA_CHAN_COMBINED_CONC; + pMac->roam.configParam.nNumP2PChanCombinedConc = + CSR_NUM_P2P_CHAN_COMBINED_CONC; +#endif + pMac->roam.configParam.nTxPowerCap = CSR_MAX_TX_POWER; + pMac->roam.configParam.statsReqPeriodicity = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD; + pMac->roam.configParam.statsReqPeriodicityInPS = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS; +#ifdef WLAN_FEATURE_VOWIFI_11R + pMac->roam.configParam.csr11rConfig.IsFTResourceReqSupported = 0; +#endif +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + pMac->roam.configParam.neighborRoamConfig.nMaxNeighborRetries = 3; + pMac->roam.configParam.neighborRoamConfig.nNeighborLookupRssiThreshold = + 120; + pMac->roam.configParam.neighborRoamConfig.nOpportunisticThresholdDiff = + 30; + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff = 5; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime = 20; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime = 40; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod = + 200; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels = 3; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[0] = 1; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[1] = 6; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[2] = 11; + pMac->roam.configParam.neighborRoamConfig.nNeighborResultsRefreshPeriod = 20000; /* 20 seconds */ + pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod = 0; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight = 14; +#endif +#ifdef WLAN_FEATURE_11AC + pMac->roam.configParam.nVhtChannelWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1; +#endif + + pMac->roam.configParam.addTSWhenACMIsOff = 0; + pMac->roam.configParam.fScanTwice = false; + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + + pMac->roam.configParam.nInitialDwellTime = 0; + pMac->roam.configParam.initial_scan_no_dfs_chnl = 0; +} + +eCsrBand csr_get_current_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.bandCapability; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/* + This function flushes the roam scan cache + */ +CDF_STATUS csr_flush_roam_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo + = &pMac->roam.neighborRoamInfo[sessionId]; + /* Free up the memory first (if required) */ + if (NULL != + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + cdf_mem_free(pNeighborRoamInfo->roamChannelInfo. + currentChannelListInfo.ChannelList); + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList = NULL; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + } + return status; +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/* + This function flushes the roam scan cache + */ +CDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + /* Free up the memory first (if required) */ + if (NULL != pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + } + return status; +} + +/* + This function flushes the roam scan cache and creates fresh cache + based on the input channel list + */ +CDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + const uint8_t *pChannelList, + const uint8_t numChannels) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = numChannels; + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + cdf_mem_malloc(pNeighborRoamInfo->cfgParams.channelInfo. + numOfChannels); + + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Memory Allocation for CFG Channel List failed")); + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + return CDF_STATUS_E_NOMEM; + } + + /* Update the roam global structure */ + cdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pChannelList, + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels); + return status; +} + +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/* + * This function modifies the roam scan channel list as per AP neighbor + * report; AP neighbor report may be empty or may include only other AP + * channels; in any case, we merge the channel list with the learned occupied + * channels list. + * if the band is 2.4G, then make sure channel list contains only 2.4G + * valid channels if the band is 5G, then make sure channel list contains + * only 5G valid channels + */ +CDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const eCsrBand eBand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo + = &pMac->roam.neighborRoamInfo[sessionId]; + uint8_t outNumChannels = 0; + uint8_t inNumChannels = numChannels; + uint8_t *inPtr = pChannelList; + uint8_t i = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t tmpChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t mergedOutputNumOfChannels = 0; + tpCsrChannelInfo currChannelListInfo + = &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + /* + * Create a Union of occupied channel list learnt by the DUT along + * with the Neighbor report Channels. This increases the chances of + * the DUT to get a candidate AP while roaming even if the Neighbor + * Report is not able to provide sufficient information. + */ + if (pMac->scan.occupiedChannels[sessionId].numChannels) { + csr_neighbor_roam_merge_channel_lists(pMac, + &pMac->scan. + occupiedChannels[sessionId]. + channelList[0], + pMac->scan. + occupiedChannels[sessionId]. + numChannels, inPtr, + inNumChannels, + &mergedOutputNumOfChannels); + inNumChannels = mergedOutputNumOfChannels; + } + if (eCSR_BAND_24 == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(inPtr[i]) + && csr_roam_is_channel_valid(pMac, inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (eCSR_BAND_5G == eBand) { + for (i = 0; i < inNumChannels; i++) { + /* Add 5G Non-DFS channel */ + if (CDS_IS_CHANNEL_5GHZ(inPtr[i]) && + csr_roam_is_channel_valid(pMac, inPtr[i]) && + !CDS_IS_DFS_CH(inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (eCSR_BAND_ALL == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (csr_roam_is_channel_valid(pMac, inPtr[i]) && + !CDS_IS_DFS_CH(inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "Invalid band, No operation carried out (Band %d)", + eBand); + return CDF_STATUS_E_INVAL; + } + /* + * if roaming within band is enabled, then select only the + * in band channels . + * This is required only if the band capability is set to ALL, + * E.g., if band capability is only 2.4G then all the channels in the + * list are already filtered for 2.4G channels, hence ignore this check + */ + if ((eCSR_BAND_ALL == eBand) && CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) { + csr_neighbor_roam_channels_filter_by_current_band(pMac, + sessionId, + ChannelList, + outNumChannels, + tmpChannelList, + &outNumChannels); + cdf_mem_copy(ChannelList, tmpChannelList, outNumChannels); + } + /* Prepare final roam scan channel list */ + if (outNumChannels) { + /* Clear the channel list first */ + if (NULL != currChannelListInfo->ChannelList) { + cdf_mem_free(currChannelListInfo->ChannelList); + currChannelListInfo->ChannelList = NULL; + currChannelListInfo->numOfChannels = 0; + } + currChannelListInfo->ChannelList + = cdf_mem_malloc(outNumChannels * sizeof(uint8_t)); + if (NULL == currChannelListInfo->ChannelList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "Failed to allocate memory for roam scan channel list"); + currChannelListInfo->numOfChannels = 0; + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(currChannelListInfo->ChannelList, + ChannelList, outNumChannels); + } + return status; +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +CDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + if (CSR_IS_PHY_MODE_A_ONLY(pMac) && (eBand == eCSR_BAND_24)) { + /* DOT11 mode configured to 11a only and received + request to change the band to 2.4 GHz */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "failed to set band cfg80211 = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return CDF_STATUS_E_INVAL; + } + if ((CSR_IS_PHY_MODE_B_ONLY(pMac) || + CSR_IS_PHY_MODE_G_ONLY(pMac)) && (eBand == eCSR_BAND_5G)) { + /* DOT11 mode configured to 11b/11g only and received + request to change the band to 5 GHz */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "failed to set band dot11mode = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return CDF_STATUS_E_INVAL; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Band changed to %u (0 - ALL, 1 - 2.4 GHZ, 2 - 5GHZ)", eBand); + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.bandCapability = eBand; + + status = csr_get_channel_and_power_list(pMac); + if (CDF_STATUS_SUCCESS == status) + csr_apply_channel_and_power_list(pMac); + return status; +} + +/* The funcns csr_convert_cb_ini_value_to_phy_cb_state and csr_convert_phy_cb_state_to_ini_value have been + * introduced to convert the ini value to the ENUM used in csr and MAC for CB state + * Ideally we should have kept the ini value and enum value same and representing the same + * cb values as in 11n standard i.e. + * Set to 1 (SCA) if the secondary channel is above the primary channel + * Set to 3 (SCB) if the secondary channel is below the primary channel + * Set to 0 (SCN) if no secondary channel is present + * However, since our driver is already distributed we will keep the ini definition as it is which is: + * 0 - secondary none + * 1 - secondary LOW + * 2 - secondary HIGH + * and convert to enum value used within the driver in csr_change_default_config_param using this funcn + * The enum values are as follows: + * PHY_SINGLE_CHANNEL_CENTERED = 0 + * PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1 + * PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3 + */ +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue) +{ + + ePhyChanBondState phyCbState; + switch (cbIniValue) { + /* secondary none */ + case eCSR_INI_SINGLE_CHANNEL_CENTERED: + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; +#ifdef WLAN_FEATURE_11AC + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + phyCbState = + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; +#endif + default: + /* If an invalid value is passed, disable CHANNEL BONDING */ + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + } + return phyCbState; +} + +uint32_t csr_convert_phy_cb_state_to_ini_value(ePhyChanBondState phyCbState) +{ + + uint32_t cbIniValue; + switch (phyCbState) { + /* secondary none */ + case PHY_SINGLE_CHANNEL_CENTERED: + cbIniValue = eCSR_INI_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + break; +#ifdef WLAN_FEATURE_11AC + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; +#endif + default: + /* return some invalid value */ + cbIniValue = eCSR_INI_CHANNEL_BONDING_STATE_MAX; + break; + } + return cbIniValue; +} + +CDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (pParam) { + pMac->roam.configParam.WMMSupportMode = pParam->WMMSupportMode; + cfg_set_int(pMac, WNI_CFG_WME_ENABLED, + (pParam->WMMSupportMode == eCsrRoamWmmNoQos) ? 0 : 1); + pMac->roam.configParam.Is11eSupportEnabled = + pParam->Is11eSupportEnabled; + pMac->roam.configParam.FragmentationThreshold = + pParam->FragmentationThreshold; + pMac->roam.configParam.Is11dSupportEnabled = + pParam->Is11dSupportEnabled; + pMac->roam.configParam.Is11dSupportEnabledOriginal = + pParam->Is11dSupportEnabled; + pMac->roam.configParam.Is11hSupportEnabled = + pParam->Is11hSupportEnabled; + + pMac->roam.configParam.fenableMCCMode = pParam->fEnableMCCMode; + pMac->roam.configParam.mcc_rts_cts_prot_enable = + pParam->mcc_rts_cts_prot_enable; + pMac->roam.configParam.mcc_bcast_prob_resp_enable = + pParam->mcc_bcast_prob_resp_enable; + pMac->roam.configParam.fAllowMCCGODiffBI = + pParam->fAllowMCCGODiffBI; + + /* channelBondingMode5GHz plays a dual role right now + * INFRA STA will use this non zero value as CB enabled and SOFTAP will use this non-zero value to determine the secondary channel offset + * This is how channelBondingMode5GHz works now and this is kept intact to avoid any cfg.ini change + */ + if (pParam->channelBondingMode24GHz > MAX_CB_VALUE_IN_INI) { + sms_log(pMac, LOGW, + "Invalid CB value from ini in 2.4GHz band %d, CB DISABLED", + pParam->channelBondingMode24GHz); + } + pMac->roam.configParam.channelBondingMode24GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode24GHz); + if (pParam->channelBondingMode5GHz > MAX_CB_VALUE_IN_INI) { + sms_log(pMac, LOGW, + "Invalid CB value from ini in 5GHz band %d, CB DISABLED", + pParam->channelBondingMode5GHz); + } + pMac->roam.configParam.channelBondingMode5GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode5GHz); + pMac->roam.configParam.RTSThreshold = pParam->RTSThreshold; + pMac->roam.configParam.phyMode = pParam->phyMode; + pMac->roam.configParam.shortSlotTime = pParam->shortSlotTime; + pMac->roam.configParam.HeartbeatThresh24 = + pParam->HeartbeatThresh24; + pMac->roam.configParam.HeartbeatThresh50 = + pParam->HeartbeatThresh50; + pMac->roam.configParam.ProprietaryRatesEnabled = + pParam->ProprietaryRatesEnabled; + pMac->roam.configParam.TxRate = pParam->TxRate; + pMac->roam.configParam.AdHocChannel24 = pParam->AdHocChannel24; + pMac->roam.configParam.AdHocChannel5G = pParam->AdHocChannel5G; + pMac->roam.configParam.bandCapability = pParam->bandCapability; + pMac->roam.configParam.cbChoice = pParam->cbChoice; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = + pParam->neighborRoamConfig.delay_before_vdev_stop; + + /* if HDD passed down non zero values then only update, */ + /* otherwise keep using the defaults */ + if (pParam->initial_scan_no_dfs_chnl) { + pMac->roam.configParam.initial_scan_no_dfs_chnl = + pParam->initial_scan_no_dfs_chnl; + } + if (pParam->nInitialDwellTime) { + pMac->roam.configParam.nInitialDwellTime = + pParam->nInitialDwellTime; + } + if (pParam->nActiveMaxChnTime) { + pMac->roam.configParam.nActiveMaxChnTime = + pParam->nActiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + pParam->nActiveMaxChnTime); + } + if (pParam->nActiveMinChnTime) { + pMac->roam.configParam.nActiveMinChnTime = + pParam->nActiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + pParam->nActiveMinChnTime); + } + if (pParam->nPassiveMaxChnTime) { + pMac->roam.configParam.nPassiveMaxChnTime = + pParam->nPassiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pParam->nPassiveMaxChnTime); + } + if (pParam->nPassiveMinChnTime) { + pMac->roam.configParam.nPassiveMinChnTime = + pParam->nPassiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + pParam->nPassiveMinChnTime); + } +#ifdef WLAN_AP_STA_CONCURRENCY + if (pParam->nActiveMaxChnTimeConc) { + pMac->roam.configParam.nActiveMaxChnTimeConc = + pParam->nActiveMaxChnTimeConc; + } + if (pParam->nActiveMinChnTimeConc) { + pMac->roam.configParam.nActiveMinChnTimeConc = + pParam->nActiveMinChnTimeConc; + } + if (pParam->nPassiveMaxChnTimeConc) { + pMac->roam.configParam.nPassiveMaxChnTimeConc = + pParam->nPassiveMaxChnTimeConc; + } + if (pParam->nPassiveMinChnTimeConc) { + pMac->roam.configParam.nPassiveMinChnTimeConc = + pParam->nPassiveMinChnTimeConc; + } + if (pParam->nRestTimeConc) { + pMac->roam.configParam.nRestTimeConc = + pParam->nRestTimeConc; + } + if (pParam->nNumStaChanCombinedConc) { + pMac->roam.configParam.nNumStaChanCombinedConc = + pParam->nNumStaChanCombinedConc; + } + if (pParam->nNumP2PChanCombinedConc) { + pMac->roam.configParam.nNumP2PChanCombinedConc = + pParam->nNumP2PChanCombinedConc; + } +#endif + pMac->roam.configParam.eBand = pParam->eBand; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam. + phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + /* if HDD passed down non zero values for age params, then only update, */ + /* otherwise keep using the defaults */ + if (pParam->nScanResultAgeCount) { + pMac->roam.configParam.agingCount = + pParam->nScanResultAgeCount; + } + if (pParam->scanAgeTimeNCNPS) { + pMac->roam.configParam.scanAgeTimeNCNPS = + pParam->scanAgeTimeNCNPS; + } + if (pParam->scanAgeTimeNCPS) { + pMac->roam.configParam.scanAgeTimeNCPS = + pParam->scanAgeTimeNCPS; + } + if (pParam->scanAgeTimeCNPS) { + pMac->roam.configParam.scanAgeTimeCNPS = + pParam->scanAgeTimeCNPS; + } + if (pParam->scanAgeTimeCPS) { + pMac->roam.configParam.scanAgeTimeCPS = + pParam->scanAgeTimeCPS; + } + + csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE, + pParam->bCatRssiOffset); + pMac->roam.configParam.nRoamingTime = pParam->nRoamingTime; + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = + pParam->fSupplicantCountryCodeHasPriority; + pMac->roam.configParam.vccRssiThreshold = + pParam->vccRssiThreshold; + pMac->roam.configParam.vccUlMacLossThreshold = + pParam->vccUlMacLossThreshold; + pMac->roam.configParam.statsReqPeriodicity = + pParam->statsReqPeriodicity; + pMac->roam.configParam.statsReqPeriodicityInPS = + pParam->statsReqPeriodicityInPS; + /* Assign this before calling csr_init11d_info */ + pMac->roam.configParam.nTxPowerCap = pParam->nTxPowerCap; + if (csr_is11d_supported(pMac)) { + status = csr_init11d_info(pMac, &pParam->Csr11dinfo); + } else { + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + } + + /* Initialize the power + channel information if 11h is enabled. + If 11d is enabled this information has already been initialized */ + if (csr_is11h_supported(pMac) && !csr_is11d_supported(pMac)) { + csr_init_channel_power_list(pMac, &pParam->Csr11dinfo); + } + +#ifdef WLAN_FEATURE_VOWIFI_11R + cdf_mem_copy(&pMac->roam.configParam.csr11rConfig, + &pParam->csr11rConfig, + sizeof(tCsr11rConfigParams)); + sms_log(pMac, LOG1, "IsFTResourceReqSupp = %d", + pMac->roam.configParam.csr11rConfig. + IsFTResourceReqSupported); +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + pMac->roam.configParam.isFastTransitionEnabled = + pParam->isFastTransitionEnabled; + pMac->roam.configParam.RoamRssiDiff = pParam->RoamRssiDiff; + pMac->roam.configParam.nRoamPrefer5GHz = + pParam->nRoamPrefer5GHz; + pMac->roam.configParam.nRoamIntraBand = pParam->nRoamIntraBand; + pMac->roam.configParam.isWESModeEnabled = + pParam->isWESModeEnabled; + pMac->roam.configParam.nProbes = pParam->nProbes; + pMac->roam.configParam.nRoamScanHomeAwayTime = + pParam->nRoamScanHomeAwayTime; +#endif + pMac->roam.configParam.isRoamOffloadScanEnabled = + pParam->isRoamOffloadScanEnabled; + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + pParam->bFastRoamInConIniFeatureEnabled; +#ifdef FEATURE_WLAN_LFR + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + pParam->isFastRoamIniFeatureEnabled; + pMac->roam.configParam.MAWCEnabled = pParam->MAWCEnabled; +#endif + +#ifdef FEATURE_WLAN_ESE + pMac->roam.configParam.isEseIniFeatureEnabled = + pParam->isEseIniFeatureEnabled; +#endif +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + cdf_mem_copy(&pMac->roam.configParam.neighborRoamConfig, + &pParam->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sms_log(pMac, LOG1, "nNeighborScanTimerPerioid = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod); + sms_log(pMac, LOG1, "nNeighborLookupRssiThreshold = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold); + sms_log(pMac, LOG1, "nOpportunisticThresholdDiff = %d", + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff); + sms_log(pMac, LOG1, "nRoamRescanRssiDiff = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff); + sms_log(pMac, LOG1, "nNeighborScanMinChanTime = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime); + sms_log(pMac, LOG1, "nNeighborScanMaxChanTime = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime); + sms_log(pMac, LOG1, "nMaxNeighborRetries = %d", + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries); + sms_log(pMac, LOG1, "nNeighborResultsRefreshPeriod = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod); + sms_log(pMac, LOG1, "nEmptyScanRefreshPeriod = %d", + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod); + { + int i; + sms_log(pMac, LOG1, + FL("Num of Channels in CFG Channel List: %d"), + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; + i < + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sms_log(pMac, LOG1, "%d ", + pMac->roam.configParam. + neighborRoamConfig.neighborScanChanList. + channelList[i]); + } + } + sms_log(pMac, LOG1, "nRoamBmissFirstBcnt = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt); + sms_log(pMac, LOG1, "nRoamBmissFinalBcnt = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt); + sms_log(pMac, LOG1, "nRoamBeaconRssiWeight = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight); +#endif + pMac->roam.configParam.addTSWhenACMIsOff = + pParam->addTSWhenACMIsOff; + pMac->scan.fValidateList = pParam->fValidateList; + pMac->scan.fEnableBypass11d = pParam->fEnableBypass11d; + pMac->scan.fEnableDFSChnlScan = pParam->fEnableDFSChnlScan; + pMac->scan.scanResultCfgAgingTime = pParam->scanCfgAgingTime; + pMac->roam.configParam.fScanTwice = pParam->fScanTwice; + pMac->scan.fFirstScanOnly2GChnl = pParam->fFirstScanOnly2GChnl; + pMac->scan.max_scan_count = pParam->max_scan_count; + /* This parameter is not available in cfg and not passed from upper layers. Instead it is initialized here + * This paramtere is used in concurrency to determine if there are concurrent active sessions. + * Is used as a temporary fix to disconnect all active sessions when BMPS enabled so the active session if Infra STA + * will automatically connect back and resume BMPS since resume BMPS is not working when moving from concurrent to + * single session + */ + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + +#ifdef WLAN_FEATURE_11AC + pMac->roam.configParam.nVhtChannelWidth = + pParam->nVhtChannelWidth; + pMac->roam.configParam.txBFEnable = pParam->enableTxBF; + pMac->roam.configParam.txBFCsnValue = pParam->txBFCsnValue; + pMac->roam.configParam.enable2x2 = pParam->enable2x2; + pMac->roam.configParam.enableVhtFor24GHz = + pParam->enableVhtFor24GHz; + pMac->roam.configParam.txMuBformee = pParam->enableMuBformee; + pMac->roam.configParam.enableVhtpAid = pParam->enableVhtpAid; + pMac->roam.configParam.enableVhtGid = pParam->enableVhtGid; +#endif + pMac->roam.configParam.enableAmpduPs = pParam->enableAmpduPs; + pMac->roam.configParam.enableHtSmps = pParam->enableHtSmps; + pMac->roam.configParam.htSmps = pParam->htSmps; + pMac->roam.configParam.txLdpcEnable = pParam->enableTxLdpc; + pMac->roam.configParam.ignore_peer_erp_info = + pParam->ignore_peer_erp_info; + pMac->roam.configParam.isAmsduSupportInAMPDU = + pParam->isAmsduSupportInAMPDU; + pMac->roam.configParam.nSelect5GHzMargin = + pParam->nSelect5GHzMargin; + pMac->roam.configParam.isCoalesingInIBSSAllowed = + pParam->isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMac->roam.configParam.cc_switch_mode = pParam->cc_switch_mode; +#endif + pMac->roam.configParam.allowDFSChannelRoam = + pParam->allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pMac->roam.configParam.isRoamOffloadEnabled = + pParam->isRoamOffloadEnabled; +#endif + pMac->roam.configParam.obssEnabled = pParam->obssEnabled; + pMac->roam.configParam.conc_custom_rule1 = + pParam->conc_custom_rule1; + pMac->roam.configParam.conc_custom_rule2 = + pParam->conc_custom_rule2; + pMac->roam.configParam.is_sta_connection_in_5gz_enabled = + pParam->is_sta_connection_in_5gz_enabled; + pMac->roam.configParam.sendDeauthBeforeCon = + pParam->sendDeauthBeforeCon; + + pMac->enable_dot11p = pParam->enable_dot11p; + } + + return status; +} + +CDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) +{ + int i; + tCsrConfig *cfg_params = &pMac->roam.configParam; + + if (!pParam) + return CDF_STATUS_E_INVAL; + + pParam->WMMSupportMode = cfg_params->WMMSupportMode; + pParam->Is11eSupportEnabled = cfg_params->Is11eSupportEnabled; + pParam->FragmentationThreshold = cfg_params->FragmentationThreshold; + pParam->Is11dSupportEnabled = cfg_params->Is11dSupportEnabled; + pParam->Is11dSupportEnabledOriginal = + cfg_params->Is11dSupportEnabledOriginal; + pParam->Is11hSupportEnabled = cfg_params->Is11hSupportEnabled; + pParam->channelBondingMode24GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode24GHz); + pParam->channelBondingMode5GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode5GHz); + pParam->RTSThreshold = cfg_params->RTSThreshold; + pParam->phyMode = cfg_params->phyMode; + pParam->shortSlotTime = cfg_params->shortSlotTime; + pParam->HeartbeatThresh24 = cfg_params->HeartbeatThresh24; + pParam->HeartbeatThresh50 = cfg_params->HeartbeatThresh50; + pParam->ProprietaryRatesEnabled = cfg_params->ProprietaryRatesEnabled; + pParam->TxRate = cfg_params->TxRate; + pParam->AdHocChannel24 = cfg_params->AdHocChannel24; + pParam->AdHocChannel5G = cfg_params->AdHocChannel5G; + pParam->bandCapability = cfg_params->bandCapability; + pParam->cbChoice = cfg_params->cbChoice; + pParam->nActiveMaxChnTime = cfg_params->nActiveMaxChnTime; + pParam->nActiveMinChnTime = cfg_params->nActiveMinChnTime; + pParam->nPassiveMaxChnTime = cfg_params->nPassiveMaxChnTime; + pParam->nPassiveMinChnTime = cfg_params->nPassiveMinChnTime; +#ifdef WLAN_AP_STA_CONCURRENCY + pParam->nActiveMaxChnTimeConc = cfg_params->nActiveMaxChnTimeConc; + pParam->nActiveMinChnTimeConc = cfg_params->nActiveMinChnTimeConc; + pParam->nPassiveMaxChnTimeConc = cfg_params->nPassiveMaxChnTimeConc; + pParam->nPassiveMinChnTimeConc = cfg_params->nPassiveMinChnTimeConc; + pParam->nRestTimeConc = cfg_params->nRestTimeConc; + pParam->nNumStaChanCombinedConc = cfg_params->nNumStaChanCombinedConc; + pParam->nNumP2PChanCombinedConc = cfg_params->nNumP2PChanCombinedConc; +#endif + pParam->eBand = cfg_params->eBand; + pParam->nScanResultAgeCount = cfg_params->agingCount; + pParam->scanAgeTimeNCNPS = cfg_params->scanAgeTimeNCNPS; + pParam->scanAgeTimeNCPS = cfg_params->scanAgeTimeNCPS; + pParam->scanAgeTimeCNPS = cfg_params->scanAgeTimeCNPS; + pParam->scanAgeTimeCPS = cfg_params->scanAgeTimeCPS; + pParam->bCatRssiOffset = cfg_params->bCatRssiOffset; + pParam->nRoamingTime = cfg_params->nRoamingTime; + pParam->fSupplicantCountryCodeHasPriority = + cfg_params->fSupplicantCountryCodeHasPriority; + pParam->vccRssiThreshold = cfg_params->vccRssiThreshold; + pParam->vccUlMacLossThreshold = cfg_params->vccUlMacLossThreshold; + pParam->nTxPowerCap = cfg_params->nTxPowerCap; + pParam->statsReqPeriodicity = cfg_params->statsReqPeriodicity; + pParam->statsReqPeriodicityInPS = cfg_params->statsReqPeriodicityInPS; + pParam->addTSWhenACMIsOff = cfg_params->addTSWhenACMIsOff; + pParam->fValidateList = cfg_params->fValidateList; + pParam->fEnableBypass11d = pMac->scan.fEnableBypass11d; + pParam->fEnableDFSChnlScan = pMac->scan.fEnableDFSChnlScan; + pParam->fScanTwice = cfg_params->fScanTwice; + pParam->fFirstScanOnly2GChnl = pMac->scan.fFirstScanOnly2GChnl; + pParam->fEnableMCCMode = cfg_params->fenableMCCMode; + pParam->fAllowMCCGODiffBI = cfg_params->fAllowMCCGODiffBI; + pParam->scanCfgAgingTime = pMac->scan.scanResultCfgAgingTime; +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + cdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); +#endif +#ifdef WLAN_FEATURE_11AC + pParam->nVhtChannelWidth = cfg_params->nVhtChannelWidth; + pParam->enableTxBF = cfg_params->txBFEnable; + pParam->txBFCsnValue = cfg_params->txBFCsnValue; + pParam->enableMuBformee = cfg_params->txMuBformee; + pParam->enableVhtFor24GHz = cfg_params->enableVhtFor24GHz; + pParam->ignore_peer_erp_info = cfg_params->ignore_peer_erp_info; + pParam->enable2x2 = cfg_params->enable2x2; +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + cdf_mem_copy(&cfg_params->csr11rConfig, &pParam->csr11rConfig, + sizeof(tCsr11rConfigParams)); +#endif +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + pParam->isFastTransitionEnabled = cfg_params->isFastTransitionEnabled; + pParam->RoamRssiDiff = cfg_params->RoamRssiDiff; + pParam->nRoamPrefer5GHz = cfg_params->nRoamPrefer5GHz; + pParam->nRoamIntraBand = cfg_params->nRoamIntraBand; + pParam->isWESModeEnabled = cfg_params->isWESModeEnabled; + pParam->nProbes = cfg_params->nProbes; + pParam->nRoamScanHomeAwayTime = cfg_params->nRoamScanHomeAwayTime; +#endif + pParam->isRoamOffloadScanEnabled = cfg_params->isRoamOffloadScanEnabled; + pParam->bFastRoamInConIniFeatureEnabled = + cfg_params->bFastRoamInConIniFeatureEnabled; +#ifdef FEATURE_WLAN_LFR + pParam->isFastRoamIniFeatureEnabled = + cfg_params->isFastRoamIniFeatureEnabled; +#endif +#ifdef FEATURE_WLAN_ESE + pParam->isEseIniFeatureEnabled = cfg_params->isEseIniFeatureEnabled; +#endif +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + cdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sms_log(pMac, LOG1, + FL("Num of Channels in CFG Channel List: %d"), + cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; i < cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sms_log(pMac, LOG1, "%d ", + cfg_params->neighborRoamConfig. + neighborScanChanList.channelList[i]); + } +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pParam->cc_switch_mode = cfg_params->cc_switch_mode; +#endif + pParam->enableTxLdpc = cfg_params->txLdpcEnable; + pParam->isAmsduSupportInAMPDU = cfg_params->isAmsduSupportInAMPDU; + pParam->nSelect5GHzMargin = cfg_params->nSelect5GHzMargin; + pParam->isCoalesingInIBSSAllowed = cfg_params->isCoalesingInIBSSAllowed; + pParam->allowDFSChannelRoam = cfg_params->allowDFSChannelRoam; + pParam->nInitialDwellTime = cfg_params->nInitialDwellTime; + pParam->initial_scan_no_dfs_chnl = cfg_params->initial_scan_no_dfs_chnl; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pParam->isRoamOffloadEnabled = cfg_params->isRoamOffloadEnabled; +#endif + pParam->enable_dot11p = pMac->enable_dot11p; + csr_set_channels(pMac, pParam); + pParam->obssEnabled = cfg_params->obssEnabled; + pParam->conc_custom_rule1 = cfg_params->conc_custom_rule1; + pParam->conc_custom_rule2 = cfg_params->conc_custom_rule2; + pParam->is_sta_connection_in_5gz_enabled = + cfg_params->is_sta_connection_in_5gz_enabled; + pParam->sendDeauthBeforeCon = + cfg_params->sendDeauthBeforeCon; + pParam->max_scan_count = pMac->scan.max_scan_count; + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, eCsrBand eBand, + bool *pfRestartNeeded) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRestartNeeded = false; + eCsrPhyMode newPhyMode = eCSR_DOT11_MODE_AUTO; + if (eCSR_BAND_24 == eBand) { + if (CSR_IS_RADIO_A_ONLY(pMac)) + goto end; + if (eCSR_DOT11_MODE_11a & phyMode) + goto end; + } + if (eCSR_BAND_5G == eBand) { + if (CSR_IS_RADIO_BG_ONLY(pMac)) + goto end; + if ((eCSR_DOT11_MODE_11b & phyMode) + || (eCSR_DOT11_MODE_11b_ONLY & phyMode) + || (eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11g_ONLY & phyMode)) + goto end; + } + if (eCSR_DOT11_MODE_AUTO & phyMode) + newPhyMode = eCSR_DOT11_MODE_AUTO; + else { + /* Check for dual band and higher capability first */ + if (eCSR_DOT11_MODE_11n_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11n_ONLY != phyMode) + goto end; + newPhyMode = eCSR_DOT11_MODE_11n_ONLY; + } else if (eCSR_DOT11_MODE_11g_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11g_ONLY != phyMode) + goto end; + if (eCSR_BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11g_ONLY; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11b_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11b_ONLY != phyMode) + goto end; + if (eCSR_BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11b_ONLY; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11n & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11n; + } else if (eCSR_DOT11_MODE_abg & phyMode) { + newPhyMode = eCSR_DOT11_MODE_abg; + } else if (eCSR_DOT11_MODE_11a & phyMode) { + if ((eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11b & phyMode)) { + if (eCSR_BAND_ALL == eBand) + newPhyMode = eCSR_DOT11_MODE_abg; + else + goto end; + } else { + newPhyMode = eCSR_DOT11_MODE_11a; + eBand = eCSR_BAND_5G; + } + } else if (eCSR_DOT11_MODE_11g & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11g; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11b & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11b; + eBand = eCSR_BAND_24; + } else { + /* We will never be here */ + sms_log(pMac, LOGE, + FL("can't recognize phymode 0x%08X"), + phyMode); + newPhyMode = eCSR_DOT11_MODE_AUTO; + } + } + /* Done validating */ + status = CDF_STATUS_SUCCESS; + /* Now we need to check whether a restart is needed. */ + if (eBand != pMac->roam.configParam.eBand) { + fRestartNeeded = true; + goto end; + } + if (newPhyMode != pMac->roam.configParam.phyMode) { + fRestartNeeded = true; + goto end; + } +end: + if (CDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.phyMode = newPhyMode; + if (pfRestartNeeded) + *pfRestartNeeded = fRestartNeeded; + } + return status; +} + +/** + * csr_prune_ch_list() - prunes the channel list to keep only a type of channels + * @ch_lst: existing channel list + * @is_24_GHz: indicates if 2.5 GHz or 5 GHz channels are required + * + * Return: void + */ +void csr_prune_ch_list(tCsrChannel *ch_lst, bool is_24_GHz) +{ + uint8_t idx = 0, num_channels = 0; + for ( ; idx < ch_lst->numChannels; idx++) { + if (is_24_GHz) { + if (CDS_IS_CHANNEL_24GHZ(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[idx]; + num_channels++; + } + } else { + if (CDS_IS_CHANNEL_5GHZ(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[idx]; + num_channels++; + } + } + } + /* + * Cleanup the rest of channels. Note we only need to clean up the + * channels if we had to trim the list. Calling cdf_mem_set() with a 0 + * size is going to throw asserts on the debug builds so let's be a bit + * smarter about that. Zero out the reset of the channels only if we + * need to. The amount of memory to clear is the number of channesl that + * we trimmed (ch_lst->numChannels - num_channels) times the size of a + * channel in the structure. + */ + if (ch_lst->numChannels > num_channels) { + cdf_mem_set(&ch_lst->channelList[num_channels], + sizeof(ch_lst->channelList[0]) * + (ch_lst->numChannels - num_channels), 0); + } + ch_lst->numChannels = num_channels; +} + +/** + * csr_prune_channel_list_for_mode() - prunes the channel list + * @mac_ctx: global mac context + * @ch_lst: existing channel list + * + * Prunes the channel list according to band stored in mac_ctx + * + * Return: void + */ +void csr_prune_channel_list_for_mode(tpAniSirGlobal mac_ctx, + tCsrChannel *ch_lst) +{ + /* for dual band NICs, don't need to trim the channel list.... */ + if (CSR_IS_OPEARTING_DUAL_BAND(mac_ctx)) + return; + /* + * 2.4 GHz band operation requires the channel list to be trimmed to + * the 2.4 GHz channels only + */ + if (CSR_IS_24_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, true); + else if (CSR_IS_5G_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, false); +} + +#define INFRA_AP_DEFAULT_CHANNEL 6 +CDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum) +{ + uint8_t index = 0; + CDF_STATUS status = CDF_STATUS_E_NOSUPPORT; + + /* regulatory check */ + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + if (pMac->scan.base_channels.channelList[index] == chnNum) { + status = CDF_STATUS_SUCCESS; + break; + } + } + + if (status == CDF_STATUS_SUCCESS) { + /* dfs nol */ + for (index = 0; + index < + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + index++) { + tSapDfsNolInfo *dfsChan = + &pMac->sap.SapDfsInfo.sapDfsChannelNolList[index]; + if ((dfsChan->dfs_channel_number == chnNum) + && (dfsChan->radar_status_flag == + eSAP_DFS_CHANNEL_UNAVAILABLE)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("channel %d is in dfs nol"), + chnNum); + status = CDF_STATUS_E_FAILURE; + break; + } + } + } + + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("channel %d is not available"), chnNum); + } + + return status; +} + +CDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t num20MHzChannelsFound = 0; + CDF_STATUS cdf_status; + uint8_t Index = 0; + uint8_t num40MHzChannelsFound = 0; + + /* TODO: this interface changed to include the 40MHz channel list */ + /* this needs to be tied into the adapter structure somehow and referenced appropriately for CB operation */ + /* Read the scan channel list (including the power limit) from EEPROM */ + cdf_status = + cds_get_channel_list_with_power(pMac->scan.defaultPowerTable, + &num20MHzChannelsFound, + pMac->scan.defaultPowerTable40MHz, + &num40MHzChannelsFound); + if ((CDF_STATUS_SUCCESS != cdf_status) || (num20MHzChannelsFound == 0)) { + sms_log(pMac, LOGE, FL("failed to get channels ")); + status = CDF_STATUS_E_FAILURE; + } else { + if (num20MHzChannelsFound > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + num20MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN; + } + pMac->scan.numChannelsDefault = num20MHzChannelsFound; + /* Move the channel list to the global data */ + /* structure -- this will be used as the scan list */ + for (Index = 0; Index < num20MHzChannelsFound; Index++) { + pMac->scan.base_channels.channelList[Index] = + pMac->scan.defaultPowerTable[Index].chanId; + } + pMac->scan.base_channels.numChannels = + num20MHzChannelsFound; + if (num40MHzChannelsFound > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + num40MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN; + } + for (Index = 0; Index < num40MHzChannelsFound; Index++) { + pMac->scan.base40MHzChannels.channelList[Index] = + pMac->scan.defaultPowerTable40MHz[Index].chanId; + } + pMac->scan.base40MHzChannels.numChannels = + num40MHzChannelsFound; + } + return status; +} + +CDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + /* Apply the base channel list, power info, and set the Country code... */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, + pMac->scan.countryCodeCurrent); + + csr_init_operating_classes((tHalHandle) pMac); + return status; +} + +CDF_STATUS csr_change_config_params(tpAniSirGlobal pMac, + tCsrUpdateConfigParam *pUpdateConfigParam) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsr11dinfo *ps11dinfo = NULL; + ps11dinfo = &pUpdateConfigParam->Csr11dinfo; + status = csr_init11d_info(pMac, ps11dinfo); + return status; +} + +static CDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + bool applyConfig = true; + + pMac->scan.currentCountryRSSI = -128; + if (!ps11dinfo) { + return status; + } + if (ps11dinfo->Channels.numChannels + && (WNI_CFG_VALID_CHANNEL_LIST_LEN >= + ps11dinfo->Channels.numChannels)) { + pMac->scan.base_channels.numChannels = + ps11dinfo->Channels.numChannels; + cdf_mem_copy(pMac->scan.base_channels.channelList, + ps11dinfo->Channels.channelList, + ps11dinfo->Channels.numChannels); + } else { + /* No change */ + return CDF_STATUS_SUCCESS; + } + /* legacy maintenance */ + + cdf_mem_copy(pMac->scan.countryCodeDefault, ps11dinfo->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + + /* Tush: at csropen get this initialized with default, during csr reset if this */ + /* already set with some value no need initilaize with default again */ + if (0 == pMac->scan.countryCodeCurrent[0]) { + cdf_mem_copy(pMac->scan.countryCodeCurrent, + ps11dinfo->countryCode, WNI_CFG_COUNTRY_CODE_LEN); + } + /* need to add the max power channel list */ + pChanInfo = + cdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + cdf_mem_set(pChanInfo, + sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN, 0); + + pChanInfoStart = pChanInfo; + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + CDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + pChanInfoStart); + } + cdf_mem_free(pChanInfoStart); + } + /* Only apply them to CFG when not in STOP state. Otherwise they will be applied later */ + if (CDF_IS_STATUS_SUCCESS(status)) { + for (index = 0; index < CSR_ROAM_SESSION_MAX; index++) { + if ((CSR_IS_SESSION_VALID(pMac, index)) + && CSR_IS_ROAM_STOP(pMac, index)) { + applyConfig = false; + } + } + + if (true == applyConfig) { + /* Apply the base channel list, power info, and set the Country code... */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan. + base_channels, + pMac->scan. + countryCodeCurrent); + } + } + return status; +} + +/* Initialize the Channel + Power List in the local cache and in the CFG */ +CDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) +{ + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + + if (!ps11dinfo || !pMac) { + return CDF_STATUS_E_FAILURE; + } + + pChanInfo = + cdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + cdf_mem_set(pChanInfo, + sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN, 0); + pChanInfoStart = pChanInfo; + + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + CDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + pChanInfoStart); + } + cdf_mem_free(pChanInfoStart); + } + + return CDF_STATUS_SUCCESS; +} + +/* pCommand may be NULL */ +/* Pass in sessionId in case pCommand is NULL. sessionId is not used in case pCommand is not NULL. */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId, + tSmeCmd *pCommand, + eCsrRoamReason eRoamReason) +{ + tListElem *pEntry, *pNextEntry; + tSmeCmd *pDupCommand; + tDblLinkList localList; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(&pMac->sme.smeCmdPendingList); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK); + while (pEntry) { + pNextEntry = + csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Remove the previous command if.. */ + /* - the new roam command is for the same RoamReason... */ + /* - the new roam command is a NewProfileList. */ + /* - the new roam command is a Forced Dissoc */ + /* - the new roam command is from an 802.11 OID (OID_SSID or OID_BSSID). */ + if ((pCommand && (pCommand->sessionId == pDupCommand->sessionId) + && ((pCommand->command == pDupCommand->command) && + /* + * This peermac check is requried for Softap/GO + * scenarios. For STA scenario below OR check will + * suffice as pCommand will always be NULL for STA + * scenarios + */ + (cdf_mem_compare + (pDupCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.peerMac, + CDF_MAC_ADDR_SIZE)) + && (pCommand->u.roamCmd.roamReason == + pDupCommand->u.roamCmd.roamReason + || eCsrForcedDisassoc == + pCommand->u.roamCmd.roamReason + || eCsrHddIssued == + pCommand->u.roamCmd.roamReason))) + || + /* below the pCommand is NULL */ + ((sessionId == pDupCommand->sessionId) && + (eSmeCommandRoam == pDupCommand->command) && + ((eCsrForcedDisassoc == eRoamReason) || + (eCsrHddIssued == eRoamReason)) + ) + ) { + sms_log(pMac, LOGW, FL(" roamReason = %d"), + pDupCommand->u.roamCmd.roamReason); + /* Remove the 'stale' roam command from the pending list... */ + if (csr_ll_remove_entry + (&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + } + pEntry = pNextEntry; + } + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Tell caller that the command is cancelled */ + csr_roam_call_callback(pMac, pDupCommand->sessionId, NULL, + pDupCommand->u.roamCmd.roamId, + eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); + csr_release_command_roam(pMac, pDupCommand); + } + csr_ll_close(&localList); +} + +/** + * csr_roam_populate_channels() - Helper function to populate channels + * @beacon_ies: pointer to beacon ie + * @roam_info: Roaming related information + * @chan1: center freq 1 + * @chan2: center freq2 + * + * This function will issue populate chan1 and chan2 based on beacon ie + * + * Return: none. + */ +static void csr_roam_populate_channels(tDot11fBeaconIEs *beacon_ies, + tCsrRoamInfo *roam_info, + uint8_t *chan1, uint8_t *chan2) +{ + ePhyChanBondState phy_state; + if (beacon_ies->VHTOperation.present) { + *chan1 = beacon_ies->VHTOperation.chanCenterFreqSeg1; + *chan2 = beacon_ies->VHTOperation.chanCenterFreqSeg2; + roam_info->chan_info.info = MODE_11AC_VHT80; + } else if (beacon_ies->HTInfo.present) { + if (beacon_ies->HTInfo.recommendedTxWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + phy_state = beacon_ies->HTInfo.secondaryChannelOffset; + if (phy_state == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel + + CSR_CB_CENTER_CHANNEL_OFFSET; + else if (phy_state == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel - + CSR_CB_CENTER_CHANNEL_OFFSET; + else + *chan1 = beacon_ies->HTInfo.primaryChannel; + + roam_info->chan_info.info = MODE_11NA_HT40; + } else { + *chan1 = beacon_ies->HTInfo.primaryChannel; + roam_info->chan_info.info = MODE_11NA_HT20; + } + *chan2 = 0; + } else { + *chan1 = 0; + *chan2 = 0; + roam_info->chan_info.info = MODE_11A; + } +} + +CDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + uint32_t rssi = 0; + WLAN_HOST_DIAG_EVENT_DEF(connectionStatus, + host_event_wlan_status_payload_type); +#endif + tCsrRoamSession *pSession; + tDot11fBeaconIEs *beacon_ies = NULL; + uint8_t chan1, chan2; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, "Session ID:%d is not valid", sessionId); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (false == pSession->sessionActive) { + sms_log(pMac, LOG1, "%s Session is not Active", __func__); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG4, "Received RoamCmdStatus %d with Roam Result %d", u1, + u2); + + if (eCSR_ROAM_ASSOCIATION_COMPLETION == u1 && + eCSR_ROAM_RESULT_ASSOCIATED == u2 && pRoamInfo) { + sms_log(pMac, LOGW, + FL("Assoc complete result=%d status=%d reason=%d"), + u2, pRoamInfo->statusCode, pRoamInfo->reasonCode); + beacon_ies = cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((NULL != beacon_ies) && (NULL != pRoamInfo->pBssDesc)) { + status = csr_parse_bss_description_ies( + (tHalHandle) pMac, pRoamInfo->pBssDesc, + beacon_ies); + csr_roam_populate_channels(beacon_ies, pRoamInfo, + &chan1, &chan2); + if (0 != chan1) + pRoamInfo->chan_info.band_center_freq1 = + cds_chan_to_freq(chan1); + else + pRoamInfo->chan_info.band_center_freq1 = 0; + if (0 != chan2) + pRoamInfo->chan_info.band_center_freq2 = + cds_chan_to_freq(chan2); + else + pRoamInfo->chan_info.band_center_freq2 = 0; + } else { + pRoamInfo->chan_info.band_center_freq1 = 0; + pRoamInfo->chan_info.band_center_freq2 = 0; + pRoamInfo->chan_info.info = 0; + } + pRoamInfo->chan_info.chan_id = + pRoamInfo->u.pConnectedProfile->operationChannel; + pRoamInfo->chan_info.mhz = + cds_chan_to_freq(pRoamInfo->chan_info.chan_id); + pRoamInfo->chan_info.reg_info_1 = + (csr_get_cfg_max_tx_power(pMac, + pRoamInfo->chan_info.chan_id) << 16); + pRoamInfo->chan_info.reg_info_2 = + (csr_get_cfg_max_tx_power(pMac, + pRoamInfo->chan_info.chan_id) << 8); + cdf_mem_free(beacon_ies); + } else if ((u1 == eCSR_ROAM_FT_REASSOC_FAILED) + && (pSession->bRefAssocStartCnt)) { + /* + * Decrement bRefAssocStartCnt for FT reassoc failure. + * Reason: For FT reassoc failures, we first call + * csr_roam_call_callback before notifying a failed roam + * completion through csr_roam_complete. The latter in + * turn calls csr_roam_process_results which tries to + * once again call csr_roam_call_callback if bRefAssocStartCnt + * is non-zero. Since this is redundant for FT reassoc + * failure, decrement bRefAssocStartCnt. + */ + pSession->bRefAssocStartCnt--; + } else if (u1 == eCSR_ROAM_SET_CHANNEL_RSP && u2 == + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS) + pSession->connectedProfile.operationChannel = + pRoamInfo->channelChangeRespEvent->newChannelNumber; + + if (NULL != pSession->callback) { + if (pRoamInfo) { + pRoamInfo->sessionId = (uint8_t) sessionId; + /* + * the reasonCode will be passed to supplicant by + * cfg80211_disconnected. Based on the document, + * the reason code passed to supplicant needs to set + * to 0 if unknow. eSIR_BEACON_MISSED reason code is not + * recognizable so that we set to 0 instead. + */ + pRoamInfo->reasonCode = + (pRoamInfo->reasonCode == eSIR_BEACON_MISSED) ? + 0 : pRoamInfo->reasonCode; + } + status = pSession->callback(pSession->pContext, pRoamInfo, + roamId, u1, u2); + } + /* + * EVENT_WLAN_STATUS: eCSR_ROAM_ASSOCIATION_COMPLETION, + * eCSR_ROAM_LOSTLINK, + * eCSR_ROAM_DISASSOCIATED, + */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + cdf_mem_set(&connectionStatus, + sizeof(host_event_wlan_status_payload_type), 0); + + if ((eCSR_ROAM_ASSOCIATION_COMPLETION == u1) + && (eCSR_ROAM_RESULT_ASSOCIATED == u2) && pRoamInfo) { + connectionStatus.eventId = eCSR_WLAN_STATUS_CONNECT; + connectionStatus.bssType = + pRoamInfo->u.pConnectedProfile->BSSType; + + if (NULL != pRoamInfo->pBssDesc) { + connectionStatus.rssi = + pRoamInfo->pBssDesc->rssi * (-1); + connectionStatus.channel = + pRoamInfo->pBssDesc->channelId; + } + if (cfg_set_int(pMac, WNI_CFG_CURRENT_RSSI, + connectionStatus.rssi) == eSIR_FAILURE) + sms_log(pMac, LOGE, + FL("Can't pass WNI_CFG_CURRENT_RSSI to cfg")); + + connectionStatus.qosCapability = + pRoamInfo->u.pConnectedProfile->qosConnection; + connectionStatus.authType = + (uint8_t) diag_auth_type_from_csr_type( + pRoamInfo->u.pConnectedProfile->AuthType); + connectionStatus.encryptionType = + (uint8_t) diag_enc_type_from_csr_type( + pRoamInfo->u.pConnectedProfile->EncryptionType); + cdf_mem_copy(connectionStatus.ssid, + pRoamInfo->u.pConnectedProfile->SSID.ssId, 6); + + connectionStatus.reason = eCSR_REASON_UNSPECIFIED; + cdf_mem_copy(&pMac->sme.eventPayload, &connectionStatus, + sizeof(host_event_wlan_status_payload_type)); + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS); + } + if ((eCSR_ROAM_MIC_ERROR_IND == u1) + || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) { + cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_MIC_ERROR; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS); + } + if (eCSR_ROAM_RESULT_FORCED == u2) { + cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS); + } + if (eCSR_ROAM_RESULT_DISASSOC_IND == u2) { + cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DISASSOC; + if (pRoamInfo) + connectionStatus.reasonDisconnect = + pRoamInfo->reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS); + } + if (eCSR_ROAM_RESULT_DEAUTH_IND == u2) { + cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DEAUTH; + if (pRoamInfo) + connectionStatus.reasonDisconnect = + pRoamInfo->reasonCode; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + return status; +} + +/* Returns whether handoff is currently in progress or not */ +bool csr_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId) +{ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + return csr_neighbor_roam_is_handoff_in_progress(pMac, sessionId); +#else + return false; +#endif +} + +CDF_STATUS csr_roam_issue_disassociate(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate, + bool fMICFailure) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER; + uint16_t reasonCode; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (fMICFailure) { + reasonCode = eSIR_MAC_MIC_FAILURE_REASON; + } else if (NewSubstate == eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF) { + reasonCode = eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON; + } else if (eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT == NewSubstate) { + reasonCode = eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("set to reason code eSIR_MAC_DISASSOC_LEAVING_BSS_REASON" + " and set back NewSubstate")); + } else { + reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if ((csr_roam_is_handoff_in_progress(pMac, sessionId)) && + (NewSubstate != eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF)) { + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + cdf_copy_macaddr(&bssId, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs. + bssid); + } else +#endif + if (pSession->pConnectBssDesc) { + cdf_mem_copy(&bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + } + + sms_log(pMac, LOG2, + FL("CSR Attempting to Disassociate Bssid=" MAC_ADDRESS_STR + " subState = %s reason=%d"), MAC_ADDR_ARRAY(bssId.bytes), + mac_trace_getcsr_roam_sub_state(NewSubstate), reasonCode); + + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, bssId.bytes, + reasonCode); + + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_link_down(pMac, sessionId); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* no need to tell QoS that we are disassociating, it will be taken care off in assoc req for HO */ + if (eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF != NewSubstate) { + /* notify QoS module that disassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_REQ, NULL); + } +#endif + } else { + sms_log(pMac, LOGW, + FL("csr_send_mb_disassoc_req_msg failed with status %d"), + status); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn csr_roam_issue_disassociate_sta_cmd + \brief csr function that HDD calls to disassociate a associated station + \param sessionId - session Id for Soft AP + \param pPeerMacAddr - MAC of associated station to delete + \param reason - reason code, be one of the tSirMacReasonCodes + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pPeerMacAddr, + uint32_t reason) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDisassocSta; + cdf_mem_copy(pCommand->u.roamCmd.peerMac, pPeerMacAddr, 6); + pCommand->u.roamCmd.reason = (tSirMacReasonCodes) reason; + status = csr_queue_sme_command(pMac, pCommand, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +/** + * csr_roam_issue_deauthSta() - delete a associated station + * @sessionId: Session Id for Soft AP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to delete a associated station + * + * Return: CDF_STATUS_SUCCESS on success or another CDF_STATUS_* on error + */ +CDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams *pDelStaParams) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDeauthSta; + cdf_mem_copy(pCommand->u.roamCmd.peerMac, + pDelStaParams->peerMacAddr.bytes, + sizeof(tSirMacAddr)); + pCommand->u.roamCmd.reason = + (tSirMacReasonCodes)pDelStaParams->reason_code; + status = csr_queue_sme_command(pMac, pCommand, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +CDF_STATUS +csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac, uint32_t sessionId, + bool bEnable) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_issue_tkip_counter_measures:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_issue_tkip_counter_measures:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR issuing tkip counter measures for Bssid = " MAC_ADDRESS_STR + ", Enable = %d", MAC_ADDR_ARRAY(bssId.bytes), bEnable); + status = + csr_send_mb_tkip_counter_measures_req_msg(pMac, sessionId, + bEnable, bssId.bytes); + return status; +} + +CDF_STATUS +csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + CDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, uint8_t *pAssocStasBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_get_associated_stas:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_get_associated_stas:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR getting associated stations for Bssid = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + status = + csr_send_mb_get_associated_stas_req_msg(pMac, sessionId, modId, + bssId.bytes, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + return status; +} + +CDF_STATUS +csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId, + void *pUsrContext, void *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_get_wps_session_overlap:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_get_wps_session_overlap:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR getting WPS Session Overlap for Bssid = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + + status = + csr_send_mb_get_wpspbc_sessions(pMac, sessionId, bssId.bytes, pUsrContext, + pfnSapEventCallback, pRemoveMac); + + return status; +} + +CDF_STATUS csr_roam_issue_deauth(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + } + sms_log(pMac, LOG2, "CSR Attempting to Deauth Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = + csr_send_mb_deauth_req_msg(pMac, sessionId, bssId.bytes, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + if (CDF_IS_STATUS_SUCCESS(status)) + csr_roam_link_down(pMac, sessionId); + else { + sms_log(pMac, LOGE, + FL + ("csr_send_mb_deauth_req_msg failed with status %d Session ID: %d" + MAC_ADDRESS_STR), status, sessionId, + MAC_ADDR_ARRAY(bssId.bytes)); + } + + return status; +} + +CDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t size; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + /* If no BSS description was found in this connection (happens with start IBSS), then */ + /* nix the BSS description that we keep around for the connected BSS) and get out... */ + if (NULL == pBssDesc) { + csr_free_connect_bss_desc(pMac, sessionId); + } else { + size = pBssDesc->length + sizeof(pBssDesc->length); + if (NULL != pSession->pConnectBssDesc) { + if (((pSession->pConnectBssDesc->length) + + sizeof(pSession->pConnectBssDesc->length)) < + size) { + /* not enough room for the new BSS, pMac->roam.pConnectBssDesc is freed inside */ + csr_free_connect_bss_desc(pMac, sessionId); + } + } + if (NULL == pSession->pConnectBssDesc) { + pSession->pConnectBssDesc = cdf_mem_malloc(size); + } + if (NULL == pSession->pConnectBssDesc) + status = CDF_STATUS_E_NOMEM; + else + cdf_mem_copy(pSession->pConnectBssDesc, pBssDesc, size); + } + return status; +} + +CDF_STATUS csr_roam_prepare_bss_config(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + eCsrCfgDot11Mode cfgDot11Mode; + CDF_ASSERT(pIes != NULL); + if (pIes == NULL) + return CDF_STATUS_E_FAILURE; + + cdf_mem_copy(&pBssConfig->BssCap, &pBssDesc->capabilityInfo, + sizeof(tSirMacCapabilityInfo)); + /* get qos */ + pBssConfig->qosType = csr_get_qo_s_from_bss_desc(pMac, pBssDesc, pIes); + /* get SSID */ + if (pIes->SSID.present) { + cdf_mem_copy(&pBssConfig->SSID.ssId, pIes->SSID.ssid, + pIes->SSID.num_ssid); + pBssConfig->SSID.length = pIes->SSID.num_ssid; + } else + pBssConfig->SSID.length = 0; + if (csr_is_nullssid(pBssConfig->SSID.ssId, pBssConfig->SSID.length)) { + sms_log(pMac, LOGW, FL("BSS desc SSID is a wild card")); + /* Return failed if profile doesn't have an SSID either. */ + if (pProfile->SSIDs.numOfSSIDs == 0) { + sms_log(pMac, LOGW, + FL("BSS desc and profile doesn't have SSID")); + return CDF_STATUS_E_FAILURE; + } + } + if (CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId)) + pBssConfig->eBand = eCSR_BAND_5G; + else + pBssConfig->eBand = eCSR_BAND_24; + /* phymode */ + if (csr_is_phy_mode_match(pMac, pProfile->phyMode, pBssDesc, + pProfile, &cfgDot11Mode, pIes)) { + pBssConfig->uCfgDot11Mode = cfgDot11Mode; + } else { + sms_log(pMac, LOGW, "Can not find match phy mode"); + /* force it */ + if (eCSR_BAND_24 == pBssConfig->eBand) + pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + else + pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + /* Qos */ + if ((pBssConfig->uCfgDot11Mode != eCSR_CFG_DOT11_MODE_11N) && + (pMac->roam.configParam.WMMSupportMode == eCsrRoamWmmNoQos)) { + /* + * Joining BSS is not 11n capable and WMM is disabled on client. + * Disable QoS and WMM + */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + if (((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC)) + && ((pBssConfig->qosType != eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP) + || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_HCF) + || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_eDCF))) { + /* Joining BSS is 11n capable and WMM is disabled on AP. */ + /* Assume all HT AP's are QOS AP's and enable WMM */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } + /* auth type */ + switch (pProfile->negotiatedAuthType) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + } + /* short slot time */ + if (eCSR_CFG_DOT11_MODE_11B != cfgDot11Mode) + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + else + pBssConfig->uShortSlotTime = 0; + + if (pBssConfig->BssCap.ibss) + /* We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + else + pBssConfig->f11hSupport = + pMac->roam.configParam.Is11hSupportEnabled; + /* power constraint */ + pBssConfig->uPowerLimit = + csr_get11h_power_constraint(pMac, &pIes->PowerConstraints); + /* heartbeat */ + if (CSR_IS_11A_BSS(pBssDesc)) + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + else + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + + /* + * Join timeout: if we find a BeaconInterval in the BssDescription, + * then set the Join Timeout to be 10 x the BeaconInterval. + */ + if (pBssDesc->beaconInterval) + /* Make sure it is bigger than the minimal */ + pBssConfig->uJoinTimeOut = + CDF_MAX(10 * pBssDesc->beaconInterval, + CSR_JOIN_FAILURE_TIMEOUT_MIN); + else + pBssConfig->uJoinTimeOut = + CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + /* validate CB */ + pBssConfig->cbMode = csr_get_cb_mode_from_ies(pMac, pBssDesc->channelId, + pIes); + + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS csr_roam_prepare_bss_config_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tBssConfigParam * + pBssConfig, + tSirBssDescription * + pBssDesc) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t operationChannel = 0; + uint8_t qAPisEnabled = false; + /* SSID */ + pBssConfig->SSID.length = 0; + if (pProfile->SSIDs.numOfSSIDs) { + /* only use the first one */ + cdf_mem_copy(&pBssConfig->SSID, + &pProfile->SSIDs.SSIDList[0].SSID, + sizeof(tSirMacSSid)); + } else { + /* SSID must present */ + return CDF_STATUS_E_FAILURE; + } + /* Settomg up the capabilities */ + if (csr_is_bss_type_ibss(pProfile->BSSType)) { + pBssConfig->BssCap.ibss = 1; + } else { + pBssConfig->BssCap.ess = 1; + } + if (eCSR_ENCRYPT_TYPE_NONE != + pProfile->EncryptionType.encryptionType[0]) { + pBssConfig->BssCap.privacy = 1; + } + pBssConfig->eBand = pMac->roam.configParam.eBand; + /* phymode */ + if (pProfile->ChannelInfo.ChannelList) { + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + } + pBssConfig->uCfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel, + &pBssConfig->eBand); + /* QOS */ + /* Is this correct to always set to this // *** */ + if (pBssConfig->BssCap.ess == 1) { + /*For Softap case enable WMM */ + if (CSR_IS_INFRA_AP(pProfile) + && (eCsrRoamWmmNoQos != + pMac->roam.configParam.WMMSupportMode)) { + qAPisEnabled = true; + } else + if (csr_roam_get_qos_info_from_bss(pMac, pBssDesc) == + CDF_STATUS_SUCCESS) { + qAPisEnabled = true; + } else { + qAPisEnabled = false; + } + } else { + qAPisEnabled = true; + } + if ((eCsrRoamWmmNoQos != pMac->roam.configParam.WMMSupportMode && + qAPisEnabled) || + ((eCSR_CFG_DOT11_MODE_11N == pBssConfig->uCfgDot11Mode && + qAPisEnabled))) { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } else { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + /* auth type */ + /* Take the preferred Auth type. */ + switch (pProfile->AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + } + /* short slot time */ + if (WNI_CFG_PHY_MODE_11B != pBssConfig->uCfgDot11Mode) { + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + } else { + pBssConfig->uShortSlotTime = 0; + } + /* power constraint. We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + pBssConfig->uPowerLimit = 0; + /* heartbeat */ + if (eCSR_BAND_5G == pBssConfig->eBand) { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + } else { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + } + /* Join timeout */ + pBssConfig->uJoinTimeOut = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + + return status; +} + +static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tDot11fBeaconIEs *pIes = NULL; + + do { + if (!CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "csr_roam_get_qos_info_from_bss() failed"); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (CSR_IS_QOS_BSS(pIes)) { + status = CDF_STATUS_SUCCESS; + } + } while (0); + + if (NULL != pIes) { + cdf_mem_free(pIes); + } + + return status; +} + +void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile, + bool fPrivacy) +{ + /* + * the only difference between this function and + * the csr_set_cfg_privacyFromProfile() is the setting of the privacy + * CFG based on the advertised privacy setting from the AP for WPA + * associations. See note below in this function... + */ + uint32_t PrivacyEnabled = 0, RsnEnabled = 0, WepDefaultKeyId = 0; + uint32_t WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + uint32_t Key0Length = 0, Key1Length = 0, Key2Length = 0, Key3Length = 0; + + /* Reserve for the biggest key */ + uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN]; + uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN]; + uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN]; + uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN]; + + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + /* for NO encryption, turn off Privacy and Rsn. */ + PrivacyEnabled = 0; + RsnEnabled = 0; + /* clear out the WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 5 bytes (40 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + /* + * set encryption keys in the CFG database or + * clear those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + cdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_5); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + cdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_5); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + cdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_5); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + cdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_5); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 13 bytes (104 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_13; + /* + * set encryption keys in the CFG database or clear + * those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + cdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_13); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + cdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_13); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + cdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_13); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + cdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_13); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: +#endif /* FEATURE_WLAN_WAPI */ + /* + * this is the only difference between this function and + * the csr_set_cfg_privacyFromProfile(). + * (setting of the privacy CFG based on the advertised + * privacy setting from AP for WPA/WAPI associations). + */ + PrivacyEnabled = (0 != fPrivacy); + /* turn on RSN enabled for WPA associations */ + RsnEnabled = 1; + /* clear static WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + default: + PrivacyEnabled = 0; + RsnEnabled = 0; + break; + } + + cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, PrivacyEnabled); + cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, RsnEnabled); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, Key0Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, Key1Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, Key2Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, Key3Length); + cfg_set_int(pMac, WNI_CFG_WEP_KEY_LENGTH, WepKeyLength); + cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, WepDefaultKeyId); +} + +static void csr_set_cfg_ssid(tpAniSirGlobal pMac, tSirMacSSid *pSSID) +{ + uint32_t len = 0; + if (pSSID->length <= WNI_CFG_SSID_LEN) { + len = pSSID->length; + } + cfg_set_str(pMac, WNI_CFG_SSID, (uint8_t *) pSSID->ssId, len); +} + +CDF_STATUS csr_set_qos_to_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrMediaAccessType qosType) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t QoSEnabled; + uint32_t WmeEnabled; + /* set the CFG enable/disable variables based on the qosType being configured... */ + switch (qosType) { + case eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_11e_eDCF: + QoSEnabled = true; + WmeEnabled = false; + break; + case eCSR_MEDIUM_ACCESS_11e_HCF: + QoSEnabled = true; + WmeEnabled = false; + break; + default: + case eCSR_MEDIUM_ACCESS_DCF: + QoSEnabled = false; + WmeEnabled = false; + break; + } + /* save the WMM setting for later use */ + pMac->roam.roamSession[sessionId].fWMMConnection = (bool) WmeEnabled; + pMac->roam.roamSession[sessionId].fQOSConnection = (bool) QoSEnabled; + return status; +} + +static CDF_STATUS csr_get_rate_set(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, eCsrPhyMode phyMode, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + tSirMacRateSet *pOpRateSet, + tSirMacRateSet *pExRateSet) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int i; + eCsrCfgDot11Mode cfgDot11Mode; + uint8_t *pDstRate; + uint16_t rateBitmap = 0; + cdf_mem_set(pOpRateSet, sizeof(tSirMacRateSet), 0); + cdf_mem_set(pExRateSet, sizeof(tSirMacRateSet), 0); + CDF_ASSERT(pIes != NULL); + + if (NULL == pIes) { + sms_log(pMac, LOGE, FL("failed to parse BssDesc")); + return status; + } + + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* + * Originally, we thought that for 11a networks, the 11a rates + * are always in the Operational Rate set & for 11b and 11g + * networks, the 11b rates appear in the Operational Rate set. + * Consequently, in either case, we would blindly put the rates + * we support into our Operational Rate set. + * (including the basic rates, which we've already verified are + * supported earlier in the roaming decision). + * However, it turns out that this is not always the case. + * Some AP's (e.g. D-Link DI-784) ram 11g rates into the + * Operational Rate set too. Now, we're a little more careful. + */ + pDstRate = pOpRateSet->rate; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->SuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->SuppRates.rates[i], + rateBitmap)) { + csr_add_rate_bitmap(pIes->SuppRates. + rates[i], &rateBitmap); + *pDstRate++ = pIes->SuppRates.rates[i]; + pOpRateSet->numRates++; + } + } + } + if ((eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode +#ifdef WLAN_FEATURE_11AC + || eCSR_CFG_DOT11_MODE_11AC == cfgDot11Mode +#endif + ) && pIes->ExtSuppRates.present) { + /* + * If there are extended rates in the beacon, + * we will reflect those extended rates that we support in our + * extended operational rate + */ + pDstRate = pExRateSet->rate; + for (i = 0; i < pIes->ExtSuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->ExtSuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->ExtSuppRates.rates[i], + rateBitmap)) { + *pDstRate++ = pIes->ExtSuppRates.rates[i]; + pExRateSet->numRates++; + } + } + } + if (pOpRateSet->numRates > 0 || pExRateSet->numRates > 0) + status = CDF_STATUS_SUCCESS; + return status; +} + +static void csr_set_cfg_rate_set(tpAniSirGlobal pMac, eCsrPhyMode phyMode, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + int i; + uint8_t *pDstRate; + eCsrCfgDot11Mode cfgDot11Mode; + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */ + uint32_t OperationalRatesLength = 0; + uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */ + uint32_t ExtendedOperationalRatesLength = 0; + uint8_t MCSRateIdxSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t MCSRateLength = 0; + CDF_ASSERT(pIes != NULL); + if (NULL != pIes) { + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* Originally, we thought that for 11a networks, the 11a rates are always */ + /* in the Operational Rate set & for 11b and 11g networks, the 11b rates */ + /* appear in the Operational Rate set. Consequently, in either case, we */ + /* would blindly put the rates we support into our Operational Rate set */ + /* (including the basic rates, which we have already verified are */ + /* supported earlier in the roaming decision). */ + /* However, it turns out that this is not always the case. Some AP's */ + /* (e.g. D-Link DI-784) ram 11g rates into the Operational Rate set, */ + /* too. Now, we're a little more careful: */ + pDstRate = OperationalRates; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->SuppRates.rates[i]) + && (OperationalRatesLength < + CSR_DOT11_SUPPORTED_RATES_MAX)) { + *pDstRate++ = pIes->SuppRates.rates[i]; + OperationalRatesLength++; + } + } + } + if (eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode) { + /* If there are Extended Rates in the beacon, we will reflect those */ + /* extended rates that we support in out Extended Operational Rate */ + /* set: */ + pDstRate = ExtendedOperationalRates; + if (pIes->ExtSuppRates.present) { + for (i = 0; i < pIes->ExtSuppRates.num_rates; + i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->ExtSuppRates.rates[i]) + && (ExtendedOperationalRatesLength < + CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX)) { + *pDstRate++ = + pIes->ExtSuppRates.rates[i]; + ExtendedOperationalRatesLength++; + } + } + } + } + /* Enable proprietary MAC features if peer node is Airgo node and STA */ + /* user wants to use them */ + /* For ANI network companions, we need to populate the proprietary rate */ + /* set with any proprietary rates we found in the beacon, only if user */ + /* allows them... */ + /* No proprietary modes... */ + /* Get MCS Rate */ + pDstRate = MCSRateIdxSet; + if (pIes->HTCaps.present) { + for (i = 0; i < VALID_MAX_MCS_INDEX; i++) { + if ((unsigned int)pIes->HTCaps. + supportedMCSSet[0] & (1 << i)) { + MCSRateLength++; + *pDstRate++ = i; + } + } + } + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, + OperationalRates, OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, + ExtendedOperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_CURRENT_MCS_SET, MCSRateIdxSet, + MCSRateLength); + } /* Parsing BSSDesc */ + else { + sms_log(pMac, LOGE, FL("failed to parse BssDesc")); + } +} + +static void csr_set_cfg_rate_set_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile) +{ + tSirMacRateSetIE DefaultSupportedRates11a = { SIR_MAC_RATESET_EID, + {8, + {SIR_MAC_RATE_6, + SIR_MAC_RATE_9, + SIR_MAC_RATE_12, + SIR_MAC_RATE_18, + SIR_MAC_RATE_24, + SIR_MAC_RATE_36, + SIR_MAC_RATE_48, + SIR_MAC_RATE_54} } }; + tSirMacRateSetIE DefaultSupportedRates11b = { SIR_MAC_RATESET_EID, + {4, + {SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11} } }; + + tSirMacPropRateSet DefaultSupportedPropRates = { 3, + {SIR_MAC_RATE_72, + SIR_MAC_RATE_96, + SIR_MAC_RATE_108} }; + eCsrCfgDot11Mode cfgDot11Mode; + eCsrBand eBand; + /* leave enough room for the max number of rates */ + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t OperationalRatesLength = 0; + /* leave enough room for the max number of rates */ + uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ExtendedOperationalRatesLength = 0; + /* leave enough room for the max number of proprietary rates */ + uint8_t ProprietaryOperationalRates[4]; + uint32_t ProprietaryOperationalRatesLength = 0; + uint32_t PropRatesEnable = 0; + uint8_t operationChannel = 0; + if (pProfile->ChannelInfo.ChannelList) { + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + } + cfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel, + &eBand); + /* For 11a networks, the 11a rates go into the Operational Rate set. For 11b and 11g */ + /* networks, the 11b rates appear in the Operational Rate set. In either case, */ + /* we can blindly put the rates we support into our Operational Rate set */ + /* (including the basic rates, which we have already verified are supported */ + /* earlier in the roaming decision). */ + if (eCSR_BAND_5G == eBand) { + /* 11a rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + cdf_mem_copy(OperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + OperationalRatesLength); + + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + /* populate proprietary rates if user allows them */ + if (pMac->roam.configParam.ProprietaryRatesEnabled) { + ProprietaryOperationalRatesLength = + DefaultSupportedPropRates.numPropRates * + sizeof(*DefaultSupportedPropRates.propRate); + cdf_mem_copy(ProprietaryOperationalRates, + DefaultSupportedPropRates.propRate, + ProprietaryOperationalRatesLength); + } else { + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } + } else if (eCSR_CFG_DOT11_MODE_11B == cfgDot11Mode) { + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + cdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } else { + /* 11G */ + + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + cdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + + /* 11a rates go in the Extended rate set. */ + ExtendedOperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + cdf_mem_copy(ExtendedOperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + ExtendedOperationalRatesLength); + + /* populate proprietary rates if user allows them */ + if (pMac->roam.configParam.ProprietaryRatesEnabled) { + ProprietaryOperationalRatesLength = + DefaultSupportedPropRates.numPropRates * + sizeof(*DefaultSupportedPropRates.propRate); + cdf_mem_copy(ProprietaryOperationalRates, + DefaultSupportedPropRates.propRate, + ProprietaryOperationalRatesLength); + } else { + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } + } + /* set this to 1 if prop. rates need to be advertised in to the IBSS beacon and user wants to use them */ + if (ProprietaryOperationalRatesLength + && pMac->roam.configParam.ProprietaryRatesEnabled) { + PropRatesEnable = 1; + } else { + PropRatesEnable = 0; + } + + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, OperationalRates, + OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, ExtendedOperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + ProprietaryOperationalRates, + ProprietaryOperationalRatesLength); +} + +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result) +{ + tListElem *pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + uint32_t sessionId; + tSmeCmd *pCommand = NULL; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tCsrRoamSession *pSession = NULL; +#endif + if (NULL == pEntry) { + sms_log(pMac, LOGW, "CFG_CNF with active list empty"); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sessionId = pCommand->sessionId; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pSession = &pMac->roam.roamSession[sessionId]; + if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_roam_cfg_set_callback"); + } +#endif + + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + csr_roaming_state_config_cnf_processor(pMac, (uint32_t) result); + } +} + +/* This function is very dump. It is here because PE still need WNI_CFG_PHY_MODE */ +uint32_t csr_roam_get_phy_mode_from_dot11_mode(eCsrCfgDot11Mode dot11Mode, + eCsrBand band) +{ + if (eCSR_CFG_DOT11_MODE_11B == dot11Mode) { + return WNI_CFG_PHY_MODE_11B; + } else { + if (eCSR_BAND_24 == band) + return WNI_CFG_PHY_MODE_11G; + } + return WNI_CFG_PHY_MODE_11A; +} + +#ifdef WLAN_FEATURE_11AC +ePhyChanBondState csr_get_htcb_state_from_vhtcb_state(ePhyChanBondState aniCBMode) +{ + switch (aniCBMode) { + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + default: + return PHY_SINGLE_CHANNEL_CENTERED; + } +} +#endif + +/* pIes may be NULL */ +CDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes, bool resetCountry) +{ + tSirRetStatus status; + uint32_t cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + uint8_t channel = 0; + /* Make sure we have the domain info for the BSS we try to connect to. */ + /* Do we need to worry about sequence for OSs that are not Windows?? */ + if (pBssDesc) { + if (csr_learn_11dcountry_information(pMac, pBssDesc, pIes, true)) { + csr_apply_country_information(pMac); + } + if ((csr_is11d_supported(pMac)) && pIes) { + if (!pIes->Country.present) { + csr_apply_channel_power_info_wrapper(pMac); + } else { + /* Let's also update the below to make sure we don't update CC while */ + /* connected to an AP which is advertising some CC */ + cdf_mem_copy(pMac->scan.currentCountryBssid.bytes, + pBssDesc->bssId, + sizeof(tSirMacAddr)); + } + } + } + /* Qos */ + csr_set_qos_to_cfg(pMac, sessionId, pBssConfig->qosType); + /* SSID */ + csr_set_cfg_ssid(pMac, &pBssConfig->SSID); + + /* Auth type */ + cfg_set_int(pMac, WNI_CFG_AUTHENTICATION_TYPE, pBssConfig->authType); + /* encryption type */ + csr_set_cfg_privacy(pMac, pProfile, (bool) pBssConfig->BssCap.privacy); + /* short slot time */ + cfg_set_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + pBssConfig->uShortSlotTime); + /* 11d */ + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pBssConfig->f11hSupport) ? pBssConfig->f11hSupport : + pProfile->ieee80211d)); + cfg_set_int(pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + pBssConfig->uPowerLimit); + /* CB */ + + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_WDS_AP(pProfile) + || CSR_IS_IBSS(pProfile)) { + channel = pProfile->operationChannel; + } else { + if (pBssDesc) { + channel = pBssDesc->channelId; + } + } + if (0 != channel) { + if (CDS_IS_CHANNEL_24GHZ(channel)) { /* for now if we are on 2.4 Ghz, CB will be always disabled */ + cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + cfgCb = pBssConfig->cbMode; + } + } + /* Rate */ + /* Fixed Rate */ + if (pBssDesc) { + csr_set_cfg_rate_set(pMac, (eCsrPhyMode) pProfile->phyMode, + pProfile, pBssDesc, pIes); + } else { + csr_set_cfg_rate_set_from_profile(pMac, pProfile); + } + /* Make this the last CFG to set. The callback will trigger a join_req */ + /* Join time out */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_CONFIG, sessionId); + + status = cfg_set_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + pBssConfig->uJoinTimeOut); + csr_roam_ccm_cfg_set_callback(pMac, status); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_stop_network(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status; + tBssConfigParam *pBssConfig; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + pBssConfig = cdf_mem_malloc(sizeof(tBssConfigParam)); + if (NULL == pBssConfig) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pBssConfig, sizeof(tBssConfigParam), 0); + status = csr_roam_prepare_bss_config(pMac, pProfile, pBssDesc, + pBssConfig, pIes); + if (CDF_IS_STATUS_SUCCESS(status)) { + eCsrRoamSubState substate; + substate = eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING; + pSession->bssParams.uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* This will allow to pass cbMode during join req */ + pSession->bssParams.cbMode = pBssConfig->cbMode; + /* For IBSS, we need to prepare some more information */ + if (csr_is_bss_type_ibss(pProfile->BSSType) || + CSR_IS_WDS(pProfile) || + CSR_IS_INFRA_AP(pProfile)) + csr_roam_prepare_bss_params(pMac, sessionId, pProfile, + pBssDesc, pBssConfig, pIes); + + /* + * If we are in an IBSS, then stop the IBSS... + * Not worry about WDS connection for now + */ + if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + substate); + } else if (csr_is_conn_state_infra(pMac, sessionId)) { + /* + * the new Bss is an Ibss OR we are roaming from + * Infra to Infra across SSIDs + * (roaming to a new SSID)... + * Not worry about WDS connection for now + */ + if (pBssDesc && (csr_is_ibss_bss_desc(pBssDesc) || + !csr_is_ssid_equal(pMac, + pSession->pConnectBssDesc, + pBssDesc, pIes))) + status = csr_roam_issue_disassociate(pMac, + sessionId, substate, false); + else if (pBssDesc) + /* + * In an infra & going to an infra network with + * the same SSID. This calls for a reassoc seq. + * So issue the CFG sets for this new AP. Set + * parameters for this Bss. + */ + status = csr_roam_set_bss_config_cfg(pMac, + sessionId, pProfile, pBssDesc, + pBssConfig, pIes, false); + } else if (pBssDesc || CSR_IS_WDS_AP(pProfile) || + CSR_IS_INFRA_AP(pProfile)) { + /* + * Neither in IBSS nor in Infra. We can go ahead and set + * the cfg for tne new network... nothing to stop. + */ + bool is11rRoamingFlag = false; + is11rRoamingFlag = csr_roam_is11r_assoc(pMac, + sessionId); + /* Set parameters for this Bss. */ + status = csr_roam_set_bss_config_cfg(pMac, sessionId, + pProfile, pBssDesc, pBssConfig, pIes, + is11rRoamingFlag); + } + } /* Success getting BSS config info */ + cdf_mem_free(pBssConfig); + return status; +} + +/** + * csr_roam_state_for_same_profile() - Determine roam state for same profile + * @mac_ctx: pointer to mac context + * @profile: Roam profile + * @session: Roam session + * @session_id: session id + * @ies_local: local ies + * @bss_descr: bss description + * + * This function will determine the roam state for same profile + * + * Return: Roaming state. + */ +static eCsrJoinState csr_roam_state_for_same_profile(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, tCsrRoamSession *session, + uint32_t session_id, tDot11fBeaconIEs *ies_local, + tSirBssDescription *bss_descr) +{ + CDF_STATUS status; + tBssConfigParam bssConfig; + if (csr_roam_is_same_profile_keys(mac_ctx, &session->connectedProfile, + profile)) + return eCsrReassocToSelfNoCapChange; + /* The key changes */ + cdf_mem_set(&bssConfig, sizeof(bssConfig), 0); + status = csr_roam_prepare_bss_config(mac_ctx, profile, bss_descr, + &bssConfig, ies_local); + if (CDF_IS_STATUS_SUCCESS(status)) { + session->bssParams.uCfgDot11Mode = + bssConfig.uCfgDot11Mode; + session->bssParams.cbMode = + bssConfig.cbMode; + /* reapply the cfg including keys so reassoc happens. */ + status = csr_roam_set_bss_config_cfg(mac_ctx, session_id, + profile, bss_descr, &bssConfig, + ies_local, false); + if (CDF_IS_STATUS_SUCCESS(status)) + return eCsrContinueRoaming; + } + + return eCsrStopRoaming; + +} + +eCsrJoinState csr_roam_join(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrScanResultInfo *pScanResult, + tCsrRoamProfile *pProfile) +{ + eCsrJoinState eRoamState = eCsrContinueRoaming; + tSirBssDescription *pBssDesc = &pScanResult->BssDescriptor; + tDot11fBeaconIEs *pIesLocal = (tDot11fBeaconIEs *) (pScanResult->pvIes); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return eCsrStopRoaming; + } + + if (CSR_IS_WDS_STA(pProfile) && + !CDF_IS_STATUS_SUCCESS(csr_roam_start_wds(pMac, sessionId, + pProfile, pBssDesc))) + return eCsrStopRoaming; + if (!pIesLocal && + !CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(pMac, + pBssDesc, &pIesLocal))) { + sms_log(pMac, LOGE, FL("fail to parse IEs")); + return eCsrStopRoaming; + } + if (csr_is_infra_bss_desc(pBssDesc)) { + /* + * If we are connected in infra mode and the join bss descr is + * for the same BssID, then we are attempting to join the AP we + * are already connected with. In that case, see if the Bss or + * sta capabilities have changed and handle the changes + * without disturbing the current association + */ + + if (csr_is_conn_state_connected_infra(pMac, sessionId) && + csr_is_bss_id_equal(pMac, + pBssDesc, pSession->pConnectBssDesc) && + csr_is_ssid_equal(pMac, pSession->pConnectBssDesc, + pBssDesc, pIesLocal)) { + /* + * Check to see if the Auth type has changed in the + * profile. If so, we don't want to reassociate with + * authenticating first. To force this, stop the + * current association (Disassociate) and then re 'Join' + * the AP, wihch will force an Authentication (with the + * new Auth type) followed by a new Association. + */ + if (csr_is_same_profile(pMac, + &pSession->connectedProfile, pProfile)) { + sms_log(pMac, LOGW, + FL("detect same profile")); + eRoamState = + csr_roam_state_for_same_profile(pMac, + pProfile, pSession, sessionId, + pIesLocal, pBssDesc); + } else if (!CDF_IS_STATUS_SUCCESS( + csr_roam_issue_disassociate(pMac, + sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + false))) { + sms_log(pMac, LOGE, + FL("fail disassoc session %d"), + sessionId); + eRoamState = eCsrStopRoaming; + } + } else if (!CDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, + sessionId, pProfile, pBssDesc, pIesLocal))) { + /* we used to pre-auth here with open auth + * networks but that wasn't working so well. + * stop the existing network before attempting + * to join the new network... */ + eRoamState = eCsrStopRoaming; + } + } else if (!CDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, sessionId, + pProfile, pBssDesc, + pIesLocal))) { + eRoamState = eCsrStopRoaming; + } + + if (pIesLocal && !pScanResult->pvIes) + cdf_mem_free(pIesLocal); + return eRoamState; +} + +CDF_STATUS csr_roam_should_roam(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc, uint32_t roamId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.pBssDesc = pBssDesc; + status = + csr_roam_call_callback(pMac, sessionId, &roamInfo, roamId, + eCSR_ROAM_SHOULD_ROAM, eCSR_ROAM_RESULT_NONE); + return status; +} + +/* In case no matching BSS is found, use whatever default we can find */ +static void csr_roam_assign_default_param(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + /* Need to get all negotiated types in place first */ + /* auth type */ + /* Take the preferred Auth type. */ + switch (pCommand->u.roamCmd.roamProfile.AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_SHARED_KEY; + break; + + case eCSR_AUTH_TYPE_AUTOSWITCH: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_AUTOSWITCH; + break; + } + pCommand->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0]; + /* In this case, the multicast encryption needs to follow the uncast ones. */ + pCommand->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0]; +} + +static void csr_set_abort_roaming_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + switch (pCommand->u.roamCmd.roamReason) { + case eCsrLostLink1: + pCommand->u.roamCmd.roamReason = eCsrLostLink1Abort; + break; + case eCsrLostLink2: + pCommand->u.roamCmd.roamReason = eCsrLostLink2Abort; + break; + case eCsrLostLink3: + pCommand->u.roamCmd.roamReason = eCsrLostLink3Abort; + break; + default: + sms_log(pMac, LOGE, + FL(" aborting roaming reason %d not recognized"), + pCommand->u.roamCmd.roamReason); + break; + } +} + +/** + * csr_roam_select_bss() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @roam_bss_entry: The next BSS to join + * @csr_result_info: Result of join + * @csr_scan_result: Global scan result + * @session_id: SME Session ID + * @roam_id: Roaming ID + * @roam_state: Current roaming state + * @bss_list: BSS List + * + * Return: true if the entire BSS list is done, false otherwise. + */ +static bool csr_roam_select_bss(tpAniSirGlobal mac_ctx, + tListElem *roam_bss_entry, tCsrScanResultInfo **csr_result_info, + tCsrScanResult **csr_scan_result, uint32_t session_id, + uint32_t roam_id, eCsrJoinState *roam_state, + tScanResultList *bss_list) +{ + uint8_t conc_channel = 0; + bool status = false; + tCsrScanResult *scan_result = NULL; + tCsrScanResultInfo *result = NULL; + + while (roam_bss_entry) { + scan_result = GET_BASE_ADDR(roam_bss_entry, tCsrScanResult, + Link); + /* + * If concurrency enabled take the + * concurrent connected channel first. + * Valid multichannel concurrent + * sessions exempted + */ + result = &scan_result->Result; + if (cds_concurrent_open_sessions_running() && + !csr_is_valid_mc_concurrent_session(mac_ctx, + session_id, &result->BssDescriptor)) { + conc_channel = csr_get_concurrent_operation_channel( + mac_ctx); + sms_log(mac_ctx, LOG1, FL("csr Conc Channel = %d"), + conc_channel); + if ((conc_channel) && (conc_channel == + result->BssDescriptor.channelId)) { + /* + * make this 0 because we do not want the below + * check to pass as we don't want to connect on + * other channel + */ + sms_log(mac_ctx, LOG1, FL("Conc chnl match=%d"), + conc_channel); + conc_channel = 0; + } + } + + /* Ok to roam this */ + if (!conc_channel && + CDF_IS_STATUS_SUCCESS(csr_roam_should_roam(mac_ctx, + session_id, &result->BssDescriptor, roam_id))) { + status = false; + break; + } else { + *roam_state = eCsrStopRoamingDueToConcurrency; + status = true; + } + roam_bss_entry = csr_ll_next(&bss_list->List, roam_bss_entry, + LL_ACCESS_LOCK); + } + *csr_result_info = result; + *csr_scan_result = scan_result; + return status; +} + +/** + * csr_roam_join_handle_profile() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * @cmd: Command + * @roam_info_ptr: Pointed to the roaming info for join + * @roam_state: Current roaming state + * @result: Result of join + * @scan_result: Global scan result + * + * Return: None + */ +static void csr_roam_join_handle_profile(tpAniSirGlobal mac_ctx, + uint32_t session_id, tSmeCmd *cmd, tCsrRoamInfo *roam_info_ptr, + eCsrJoinState *roam_state, tCsrScanResultInfo *result, + tCsrScanResult *scan_result) +{ +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + uint8_t acm_mask = 0; +#endif + CDF_STATUS status; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tDot11fBeaconIEs *ies_local = NULL; + /* + * We have something to roam, tell HDD when it is infra. + * For IBSS, the indication goes back to HDD via eCSR_ROAM_IBSS_IND + * For WDS, the indication is eCSR_ROAM_WDS_IND + */ + if (CSR_IS_INFRASTRUCTURE(profile)) { + if (roam_info_ptr && session->bRefAssocStartCnt) { + session->bRefAssocStartCnt--; + roam_info_ptr->pProfile = profile; + /* + * Complete the last assoc attempt as a + * new one is about to be tried + */ + csr_roam_call_callback(mac_ctx, session_id, + roam_info_ptr, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + /* If roaming has stopped, don't continue the roaming command */ + if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) { + /* No need to complete roaming as it already complete */ + sms_log(mac_ctx, LOGW, + FL( + "Roam cmd(reason %d)aborted as roam complete"), + cmd->u.roamCmd.roamReason); + *roam_state = eCsrStopRoaming; + csr_set_abort_roaming_command(mac_ctx, cmd); + return; + } + cdf_mem_set(roam_info_ptr, sizeof(tCsrRoamInfo), 0); + if (!scan_result) + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + else + ies_local = scan_result->Result.pvIes; + + if (scan_result && !ies_local && + (!CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + mac_ctx, + &result->BssDescriptor, + &ies_local)))) { + sms_log(mac_ctx, LOGE, FL(" cannot parse IEs")); + *roam_state = eCsrStopRoaming; + return; + } + roam_info_ptr->pBssDesc = &result->BssDescriptor; + cmd->u.roamCmd.pLastRoamBss = roam_info_ptr->pBssDesc; + /* dont put uapsd_mask if BSS doesn't support uAPSD */ + if (scan_result && cmd->u.roamCmd.roamProfile.uapsd_mask + && CSR_IS_QOS_BSS(ies_local) + && CSR_IS_UAPSD_BSS(ies_local)) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, + &result->BssDescriptor, ies_local); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + } else { + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + } + if (ies_local && !result->pvIes) + cdf_mem_free(ies_local); + roam_info_ptr->pProfile = profile; + session->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info_ptr, + cmd->u.roamCmd.roamId, eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + } + if (NULL != cmd->u.roamCmd.pRoamBssEntry) { + /* + * We have BSS + * Need to assign these value because + * they are used in csr_is_same_profile + */ + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + /* + * The OSEN IE doesn't provide the cipher suite.Therefore set + * to constant value of AES + */ + if (cmd->u.roamCmd.roamProfile.bOSENAssociation) { + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + } else { + /* Negotiated while building scan result. */ + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + scan_result->ucEncryptionType; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + scan_result->mcEncryptionType; + } + cmd->u.roamCmd.roamProfile.negotiatedAuthType = + scan_result->authType; + if (CSR_IS_START_IBSS(&cmd->u.roamCmd.roamProfile)) { + if (csr_is_same_profile(mac_ctx, + &session->connectedProfile, profile)) { + *roam_state = eCsrStartIbssSameIbss; + return; + } + } + if (cmd->u.roamCmd.fReassocToSelfNoCapChange) { + /* trying to connect to the one already connected */ + cmd->u.roamCmd.fReassocToSelfNoCapChange = false; + *roam_state = eCsrReassocToSelfNoCapChange; + return; + } + /* Attempt to Join this Bss... */ + *roam_state = csr_roam_join(mac_ctx, session_id, + &scan_result->Result, profile); + return; + } + + /* For an IBSS profile, then we need to start the IBSS. */ + if (CSR_IS_START_IBSS(profile)) { + bool same_ibss = false; + /* Attempt to start this IBSS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + status = csr_roam_start_ibss(mac_ctx, session_id, + profile, &same_ibss); + if (CDF_IS_STATUS_SUCCESS(status)) { + if (same_ibss) + *roam_state = eCsrStartIbssSameIbss; + else + *roam_state = eCsrContinueRoaming; + } else { + /* it somehow fail need to stop */ + *roam_state = eCsrStopRoaming; + } + return; + } else if ((CSR_IS_WDS_AP(profile)) || + (CSR_IS_INFRA_AP(profile))) { + /* Attempt to start this WDS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + /* For AP WDS, we dont have any BSSDescription */ + status = csr_roam_start_wds(mac_ctx, session_id, profile, NULL); + if (CDF_IS_STATUS_SUCCESS(status)) + *roam_state = eCsrContinueRoaming; + else + *roam_state = eCsrStopRoaming; + } else { + /* Nothing we can do */ + sms_log(mac_ctx, LOGW, FL("cannot continue without BSS list")); + *roam_state = eCsrStopRoaming; + return; + } + +} +/** + * csr_roam_join_next_bss() - Pick the next BSS for join + * @mac_ctx: Global MAC Context + * @cmd: Command + * @use_same_bss: Use Same BSS to Join + * + * Return: The Join State + */ +static eCsrJoinState csr_roam_join_next_bss(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, bool use_same_bss) +{ + tCsrScanResult *scan_result = NULL; + eCsrJoinState roam_state = eCsrStopRoaming; + tScanResultList *bss_list = + (tScanResultList *) cmd->u.roamCmd.hBSSList; + bool done = false; + tCsrRoamInfo roam_info, *roam_info_ptr = NULL; + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamJoinStatus *join_status; + tCsrScanResultInfo *result = NULL; + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return eCsrStopRoaming; + } + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + cdf_mem_copy(&roam_info.bssid, &session->joinFailStatusCode.bssId, + sizeof(tSirMacAddr)); + /* + * When handling AP's capability change, continue to associate + * to same BSS and make sure pRoamBssEntry is not Null. + */ + if ((NULL != bss_list) && + ((false == use_same_bss) || + (cmd->u.roamCmd.pRoamBssEntry == NULL))) { + if (cmd->u.roamCmd.pRoamBssEntry == NULL) { + /* Try the first BSS */ + cmd->u.roamCmd.pLastRoamBss = NULL; + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_peek_head(&bss_list->List, + LL_ACCESS_LOCK); + } else { + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_next(&bss_list->List, + cmd->u.roamCmd.pRoamBssEntry, + LL_ACCESS_LOCK); + /* + * Done with all the BSSs. + * In this case, will tell HDD the + * completion + */ + if (NULL == cmd->u.roamCmd.pRoamBssEntry) + goto end; + /* + * We need to indicate to HDD that we + * are done with this one. + */ + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + join_status = &session->joinFailStatusCode; + roam_info.statusCode = join_status->statusCode; + roam_info.reasonCode = join_status->reasonCode; + roam_info_ptr = &roam_info; + } + done = csr_roam_select_bss(mac_ctx, + cmd->u.roamCmd.pRoamBssEntry, &result, + &scan_result, session_id, cmd->u.roamCmd.roamId, + &roam_state, bss_list); + if (done) + goto end; + } + if (!roam_info_ptr) + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + csr_roam_join_handle_profile(mac_ctx, session_id, cmd, roam_info_ptr, + &roam_state, result, scan_result); +end: + if ((eCsrStopRoaming == roam_state) && CSR_IS_INFRASTRUCTURE(profile) && + (session->bRefAssocStartCnt > 0)) { + /* + * Need to indicate association_completion if association_start + * has been done + */ + session->bRefAssocStartCnt--; + /* + * Complete the last assoc attempte as a + * new one is about to be tried + */ + roam_info_ptr = &roam_info; + roam_info_ptr->pProfile = profile; + csr_roam_call_callback(mac_ctx, session_id, + roam_info_ptr, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + + return roam_state; +} + +static CDF_STATUS csr_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + eCsrJoinState RoamState; + eCsrRoamSubState substate; + uint32_t sessionId = pCommand->sessionId; + + /* Attept to join a Bss... */ + RoamState = csr_roam_join_next_bss(pMac, pCommand, false); + + /* if nothing to join.. */ + if ((eCsrStopRoaming == RoamState) || + (eCsrStopRoamingDueToConcurrency == RoamState)) { + bool fComplete = false; + /* and if connected in Infrastructure mode... */ + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* ... then we need to issue a disassociation */ + substate = eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN; + status = csr_roam_issue_disassociate(pMac, sessionId, + substate, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing disassoc status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing stop bss status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_connected_infra_ap(pMac, + sessionId)) { + substate = eCSR_ROAM_SUBSTATE_STOP_BSS_REQ; + status = csr_roam_issue_stop_bss(pMac, sessionId, + substate); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing stop bss status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else { + fComplete = true; + } + + if (fComplete) { + /* otherwise, we can complete the Roam command here. */ + if (eCsrStopRoamingDueToConcurrency == RoamState) + csr_roam_complete(pMac, + eCsrJoinFailureDueToConcurrency, NULL); + else + csr_roam_complete(pMac, + eCsrNothingToJoin, NULL); + } + } else if (eCsrReassocToSelfNoCapChange == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoamingSaveState, + NULL); + } else if (eCsrStartIbssSameIbss == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoaming, NULL); + } + + return status; +} + +CDF_STATUS csr_process_ft_reassoc_roam_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + uint32_t sessionId; + tCsrRoamSession *pSession; + tCsrScanResult *pScanResult = NULL; + tSirBssDescription *pBssDesc = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (CSR_IS_ROAMING(pSession) && pSession->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sms_log(pMac, LOG1, FL("Roam command canceled")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + return CDF_STATUS_E_FAILURE; + } + if (pCommand->u.roamCmd.pRoamBssEntry) { + pScanResult = + GET_BASE_ADDR(pCommand->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + pBssDesc = &pScanResult->Result.BssDescriptor; + } else { + /* the roaming is cancelled. Simply complete the command */ + sms_log(pMac, LOG1, FL("Roam command canceled")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + return CDF_STATUS_E_FAILURE; + } + status = csr_roam_issue_reassociate(pMac, sessionId, pBssDesc, + (tDot11fBeaconIEs *) (pScanResult-> + Result.pvIes), + &pCommand->u.roamCmd.roamProfile); + return status; +} + +/** + * csr_roam_trigger_reassociate() - Helper function to trigger reassociate + * @mac_ctx: pointer to mac context + * @cmd: sme command + * @roam_info: Roaming infor structure + * @session_ptr: session pointer + * @session_id: session id + * + * This function will trigger reassociate. + * + * Return: CDF_STATUS for success or failure. + */ +static CDF_STATUS csr_roam_trigger_reassociate(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, tCsrRoamInfo *roam_info, + tCsrRoamSession *session_ptr, uint32_t session_id) +{ + tDot11fBeaconIEs *pIes = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (session_ptr->pConnectBssDesc) { + status = csr_get_parsed_bss_description_ies(mac_ctx, + session_ptr->pConnectBssDesc, &pIes); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("fail to parse IEs")); + } else { + roam_info->reasonCode = + eCsrRoamReasonStaCapabilityChanged; + csr_roam_call_callback(mac_ctx, session_ptr->sessionId, + roam_info, 0, eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + session_ptr->roamingReason = eCsrReassocRoaming; + roam_info->pBssDesc = session_ptr->pConnectBssDesc; + roam_info->pProfile = &cmd->u.roamCmd.roamProfile; + session_ptr->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + + sms_log(mac_ctx, LOG1, + FL("calling csr_roam_issue_reassociate")); + status = csr_roam_issue_reassociate(mac_ctx, session_id, + session_ptr->pConnectBssDesc, pIes, + &cmd->u.roamCmd.roamProfile); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("failed status %d"), + status); + csr_release_command_roam(mac_ctx, cmd); + } + + cdf_mem_free(pIes); + pIes = NULL; + } + } else { + sms_log(mac_ctx, LOGE, FL + ("reassoc to same AP failed as connected BSS is NULL")); + status = CDF_STATUS_E_FAILURE; + } + return status; +} + +CDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + uint32_t sessionId = pCommand->sessionId; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL("Roam Reason : %d, sessionId: %d"), + pCommand->u.roamCmd.roamReason, sessionId); + + switch (pCommand->u.roamCmd.roamReason) { + case eCsrForcedDisassoc: + if (eCSR_ROAMING_STATE_IDLE == pMac->roam.curState[sessionId]) { + sms_log(pMac, LOGE, + FL("Ignore eCsrForcedDisassoc cmd on roam state" + " %d"), eCSR_ROAMING_STATE_IDLE); + return CDF_STATUS_E_FAILURE; + } + + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrSmeIssuedDisassocForHandoff: + /* Not to free pMac->roam.pCurRoamProfile (via + * csr_free_roam_profile) because its needed after disconnect */ + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + + break; + case eCsrForcedDisassocMICFailure: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, true); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrForcedDeauth: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + false, false); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + status = csr_roam_trigger_reassociate(pMac, pCommand, &roamInfo, + pSession, sessionId); + break; + case eCsrCapsChange: + sms_log(pMac, LOGE, FL("received eCsrCapsChange ")); + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + break; + case eCsrSmeIssuedFTReassoc: + sms_log(pMac, LOG1, FL("received FT Reassoc Req ")); + status = csr_process_ft_reassoc_roam_command(pMac, pCommand); + break; + + case eCsrStopBss: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + break; + + case eCsrForcedDisassocSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + sessionId); + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrForcedDeauthSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + sessionId); + status = csr_send_mb_deauth_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrPerformPreauth: + sms_log(pMac, LOG1, FL("Attempting FT PreAuth Req")); + status = csr_roam_issue_ft_preauth_req(pMac, sessionId, + pCommand->u.roamCmd.pLastRoamBss); + break; + default: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + + if (pCommand->u.roamCmd.fUpdateCurRoamProfile) { + /* Remember the roaming profile */ + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL != pSession->pCurRoamProfile) { + cdf_mem_set(pSession->pCurRoamProfile, + sizeof(tCsrRoamProfile), 0); + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + &pCommand->u.roamCmd.roamProfile); + } + } + /* + * At this point original uapsd_mask is saved in + * pCurRoamProfile. uapsd_mask in the pCommand may change from + * this point on. Attempt to roam with the new scan results + * (if we need to..) + */ + status = csr_roam(pMac, pCommand); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGW, + FL("csr_roam() failed with status = 0x%08X"), + status); + break; + } + return status; +} + +void csr_reinit_preauth_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + pCommand->u.roamCmd.pLastRoamBss = NULL; + pCommand->u.roamCmd.pRoamBssEntry = NULL; + /* Because u.roamCmd is union and share with scanCmd and StatusChange */ + cdf_mem_set(&pCommand->u.roamCmd, sizeof(tRoamCmd), 0); +} + +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pCommand->u.roamCmd.fReleaseBssList) { + csr_scan_result_purge(pMac, pCommand->u.roamCmd.hBSSList); + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + } + if (pCommand->u.roamCmd.fReleaseProfile) { + csr_release_profile(pMac, &pCommand->u.roamCmd.roamProfile); + pCommand->u.roamCmd.fReleaseProfile = false; + } + pCommand->u.roamCmd.pRoamBssEntry = NULL; + /* Because u.roamCmd is union and share with scanCmd and StatusChange */ + cdf_mem_set(&pCommand->u.roamCmd, sizeof(tRoamCmd), 0); +} + +void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + cdf_mem_set(&pCommand->u.wmStatusChangeCmd, sizeof(tWmStatusChangeCmd), + 0); +} + +void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result, + void *Context) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + bool fReleaseCommand = true; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: Roam Completion ...", __func__); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* If the head of the queue is Active and it is a ROAM command, remove */ + /* and put this on the Free queue. */ + if (eSmeCommandRoam == pCommand->command) { + /* we need to process the result first before removing it from active list because state changes */ + /* still happening insides roamQProcessRoamResults so no other roam command should be issued */ + fReleaseCommand = + csr_roam_process_results(pMac, pCommand, Result, + Context); + if (fReleaseCommand) { + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_roam(pMac, pCommand); + } else { + sms_log(pMac, LOGE, + " **********csr_roam_complete fail to release command reason %d", + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGE, + " **********csr_roam_complete fail to release command reason %d", + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGW, + "CSR: Roam Completion called but ROAM command is not ACTIVE ..."); + } + } else { + sms_log(pMac, LOGW, + "CSR: Roam Completion called but NO commands are ACTIVE ..."); + } + if (fReleaseCommand) { + sme_process_pending_queue(pMac); + } +} + +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + cdf_mem_set(&(pSession->PmkidCandidateInfo[0]), + sizeof(tPmkidCandidateInfo) * CSR_MAX_PMKID_ALLOWED, 0); + pSession->NumPmkidCandidate = 0; +} + +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + cdf_mem_set(&(pSession->BkidCandidateInfo[0]), + sizeof(tBkidCandidateInfo) * CSR_MAX_BKID_ALLOWED, 0); + pSession->NumBkidCandidate = 0; +} +#endif /* FEATURE_WLAN_WAPI */ +extern uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE]; + +/** + * csr_roam_save_params() - Helper function to save params + * @mac_ctx: pointer to mac context + * @session_ptr: Session pointer + * @auth_type: auth type + * @ie_ptr: pointer to ie + * @ie_local: pointr to local ie + * + * This function will save params to session + * + * Return: none. + */ +static CDF_STATUS csr_roam_save_params(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session_ptr, + eCsrAuthType auth_type, + tDot11fBeaconIEs *ie_ptr, + tDot11fBeaconIEs *ie_local) +{ + uint32_t nIeLen; + uint8_t *pIeBuf; + + if ((eCSR_AUTH_TYPE_RSN == auth_type) || +#if defined WLAN_FEATURE_VOWIFI_11R + (eCSR_AUTH_TYPE_FT_RSN == auth_type) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == auth_type) || +#endif /* WLAN_FEATURE_VOWIFI_11R */ +#if defined WLAN_FEATURE_11W + (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == auth_type) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == auth_type) || +#endif + (eCSR_AUTH_TYPE_RSN_PSK == auth_type)) { + if (ie_local->RSN.present) { + tDot11fIERSN *rsnie = &ie_local->RSN; + /* + * Calculate the actual length + * version + gp_cipher_suite + pwise_cipher_suite_count + * + akm_suite_count + reserved + pwise_cipher_suites + */ + nIeLen = 8 + 2 + 2 + + (rsnie->pwise_cipher_suite_count * 4) + + (rsnie->akm_suite_count * 4); + if (rsnie->pmkid_count) + /* pmkid */ + nIeLen += 2 + rsnie->pmkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWpaRsnRspIE = cdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(session_ptr->pWpaRsnRspIE, + nIeLen + 2, 0); + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_RSN; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + /* copy upto akm_suites */ + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + cdf_mem_copy(pIeBuf, &rsnie->version, + sizeof(rsnie->version)); + pIeBuf += sizeof(rsnie->version); + cdf_mem_copy(pIeBuf, &rsnie->gp_cipher_suite, + sizeof(rsnie->gp_cipher_suite)); + pIeBuf += sizeof(rsnie->gp_cipher_suite); + cdf_mem_copy(pIeBuf, &rsnie->pwise_cipher_suite_count, + sizeof(rsnie->pwise_cipher_suite_count)); + pIeBuf += sizeof(rsnie->pwise_cipher_suite_count); + if (rsnie->pwise_cipher_suite_count) { + /* copy pwise_cipher_suites */ + cdf_mem_copy(pIeBuf, rsnie->pwise_cipher_suites, + rsnie->pwise_cipher_suite_count * 4); + pIeBuf += rsnie->pwise_cipher_suite_count * 4; + } + cdf_mem_copy(pIeBuf, &rsnie->akm_suite_count, 2); + pIeBuf += 2; + if (rsnie->akm_suite_count) { + /* copy akm_suites */ + cdf_mem_copy(pIeBuf, rsnie->akm_suites, + rsnie->akm_suite_count * 4); + pIeBuf += rsnie->akm_suite_count * 4; + } + /* copy the rest */ + cdf_mem_copy(pIeBuf, rsnie->akm_suites + + rsnie->akm_suite_count * 4, + 2 + rsnie->pmkid_count * 4); + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } else if ((eCSR_AUTH_TYPE_WPA == auth_type) || + (eCSR_AUTH_TYPE_WPA_PSK == auth_type)) { + if (ie_local->WPA.present) { + tDot11fIEWPA *wpaie = &ie_local->WPA; + /* Calculate the actual length wpaie */ + nIeLen = 12 + 2 /* auth_suite_count */ + + wpaie->unicast_cipher_count * 4 + + wpaie->auth_suite_count * 4; + + /* The WPA capabilities follows the Auth Suite + * (two octects)-- this field is optional, and + * we always "send" zero, so just remove it. This is + * consistent with our assumptions in the frames + * compiler; nIeLen doesn't count EID & length fields */ + session_ptr->pWpaRsnRspIE = cdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return CDF_STATUS_E_NOMEM; + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_WPA; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + /* Copy WPA OUI */ + cdf_mem_copy(pIeBuf, &csr_wpa_oui[1], 4); + pIeBuf += 4; + cdf_mem_copy(pIeBuf, &wpaie->version, + 8 + wpaie->unicast_cipher_count * 4); + pIeBuf += 8 + wpaie->unicast_cipher_count * 4; + cdf_mem_copy(pIeBuf, &wpaie->auth_suite_count, + 2 + wpaie->auth_suite_count * 4); + pIeBuf += wpaie->auth_suite_count * 4; + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } +#ifdef FEATURE_WLAN_WAPI + else if ((eCSR_AUTH_TYPE_WAPI_WAI_PSK == auth_type) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == + auth_type)) { + if (ie_local->WAPI.present) { + tDot11fIEWAPI *wapi_ie = &ie_local->WAPI; + /* Calculate the actual length of wapi ie*/ + nIeLen = 4 + 2 /* pwise_cipher_suite_count */ + + wapi_ie->akm_suite_count * 4 + + wapi_ie->unicast_cipher_suite_count * 4 + + 6; /* gp_cipher_suite + preauth + reserved */ + + if (wapi_ie->bkid_count) + nIeLen += 2 + wapi_ie->bkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWapiRspIE = + cdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWapiRspIE) + return CDF_STATUS_E_NOMEM; + session_ptr->pWapiRspIE[0] = DOT11F_EID_WAPI; + session_ptr->pWapiRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWapiRspIE + 2; + /* copy upto akm_suite_count */ + cdf_mem_copy(pIeBuf, &wapi_ie->version, 2); + pIeBuf += 4; + if (wapi_ie->akm_suite_count) { + /* copy akm_suites */ + cdf_mem_copy(pIeBuf, + wapi_ie->akm_suites, + wapi_ie->akm_suite_count * 4); + pIeBuf += wapi_ie->akm_suite_count * 4; + } + cdf_mem_copy(pIeBuf, + &wapi_ie->unicast_cipher_suite_count, 2); + pIeBuf += 2; + if (wapi_ie->unicast_cipher_suite_count) { + uint16_t suite_size = + wapi_ie->unicast_cipher_suite_count * 4; + /* copy pwise_cipher_suites */ + cdf_mem_copy(pIeBuf, + wapi_ie->unicast_cipher_suites, + suite_size); + pIeBuf += suite_size; + } + /* gp_cipher_suite */ + cdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite, 4); + pIeBuf += 4; + /* preauth + reserved */ + cdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite + 4, 2); + pIeBuf += 2; + if (wapi_ie->bkid_count) { + /* bkid_count */ + cdf_mem_copy(pIeBuf, &wapi_ie->bkid_count, 2); + pIeBuf += 2; + /* copy akm_suites */ + cdf_mem_copy(pIeBuf, wapi_ie->bkid, + wapi_ie->bkid_count * 4); + pIeBuf += wapi_ie->bkid_count * 4; + } + session_ptr->nWapiRspIeLength = nIeLen + 2; + } + } +#endif /* FEATURE_WLAN_WAPI */ + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS csr_roam_save_security_rsp_ie(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrAuthType authType, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tDot11fBeaconIEs *pIesLocal = pIes; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:csr_roam_save_security_rsp_ie")); + } +#endif + + if ((eCSR_AUTH_TYPE_WPA == authType) || + (eCSR_AUTH_TYPE_WPA_PSK == authType) || + (eCSR_AUTH_TYPE_RSN == authType) || + (eCSR_AUTH_TYPE_RSN_PSK == authType) +#if defined WLAN_FEATURE_VOWIFI_11R + || (eCSR_AUTH_TYPE_FT_RSN == authType) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == authType) +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_WAPI + || (eCSR_AUTH_TYPE_WAPI_WAI_PSK == authType) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == authType) +#endif /* FEATURE_WLAN_WAPI */ +#ifdef WLAN_FEATURE_11W + || (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == authType) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == authType) +#endif /* FEATURE_WLAN_WAPI */ + ) { + if (!pIesLocal && !CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc, &pIesLocal))) + sms_log(pMac, LOGE, FL(" cannot parse IEs")); + if (pIesLocal) { + status = csr_roam_save_params(pMac, pSession, authType, + pIes, pIesLocal); + if (!pIes) + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + } + return status; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId) +{ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + return csr_neighbor_roam_is11r_assoc(pMac, sessionId); +#else + return false; +#endif +} +#endif +#ifdef FEATURE_WLAN_ESE +/* Returns whether the current association is a ESE assoc or not */ +bool csr_roam_is_ese_assoc(tpAniSirGlobal pMac, uint8_t sessionId) +{ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + return csr_neighbor_roam_is_ese_assoc(pMac, sessionId); +#else + return false; +#endif +} +#endif +#ifdef FEATURE_WLAN_LFR +/* Returns whether "Legacy Fast Roaming" is currently enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona != + CDF_STA_MODE) { + return false; + } + } + } + if (true == CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; + } else { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled && + (!csr_is_concurrent_session_running(pMac)); + } +} + +#ifdef FEATURE_WLAN_ESE +/** + * csr_neighbor_roam_is_ese_assoc() - Check the Association type + * @mac_ctx: Global MAC Context + * @session_id: Session ID on which the check should be done + * + * This function returns whether the current association + * is a ESE assoc or not + * + * Return: True if ESE association, false otherwise. + **/ +bool csr_neighbor_roam_is_ese_assoc(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].isESEAssoc; +} +#endif /* FEATURE_WLAN_ESE */ + +/* Returns whether "FW based BG scan" is currently enabled...or not */ +bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.isRoamOffloadScanEnabled; +} +#endif + +#if defined(FEATURE_WLAN_ESE) +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.isEseIniFeatureEnabled; +} +#endif /*FEATURE_WLAN_ESE */ + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +eCsrPhyMode csr_roamdot11mode_to_phymode(uint8_t dot11mode) +{ + eCsrPhyMode phymode = eCSR_DOT11_MODE_abg; + + switch (dot11mode) { + case WNI_CFG_DOT11_MODE_ALL: + phymode = eCSR_DOT11_MODE_abg; + break; + case WNI_CFG_DOT11_MODE_11A: + phymode = eCSR_DOT11_MODE_11a; + break; + case WNI_CFG_DOT11_MODE_11B: + phymode = eCSR_DOT11_MODE_11b; + break; + case WNI_CFG_DOT11_MODE_11G: + phymode = eCSR_DOT11_MODE_11g; + break; + case WNI_CFG_DOT11_MODE_11N: + phymode = eCSR_DOT11_MODE_11n; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + phymode = eCSR_DOT11_MODE_11g_ONLY; + break; + case WNI_CFG_DOT11_MODE_11N_ONLY: + phymode = eCSR_DOT11_MODE_11n_ONLY; + break; + case WNI_CFG_DOT11_MODE_11AC: + phymode = eCSR_DOT11_MODE_11ac; + break; + case WNI_CFG_DOT11_MODE_11AC_ONLY: + phymode = eCSR_DOT11_MODE_11ac_ONLY; + break; + default: + break; + } + + return phymode; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_roam_offload_send_synch_cnf(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpSirSmeRoamOffloadSynchCnf pRoamOffloadSynchCnf; + cds_msg_t msg; + tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId]; + pRoamOffloadSynchCnf = + cdf_mem_malloc(sizeof(tSirSmeRoamOffloadSynchCnf)); + if (NULL == pRoamOffloadSynchCnf) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: not able to allocate memory for roam" + "offload synch confirmation data", __func__); + pSession->roamOffloadSynchParams.bRoamSynchInProgress = + false; + return CDF_STATUS_E_NOMEM; + } + pRoamOffloadSynchCnf->sessionId = sessionId; + msg.type = WMA_ROAM_OFFLOAD_SYNCH_CNF; + msg.reserved = 0; + msg.bodyptr = pRoamOffloadSynchCnf; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "LFR3: Posting WMA_ROAM_OFFLOAD_SYNCH_CNF"); + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: Not able to post WMA_ROAM_OFFLOAD_SYNCH_CNF message to WMA", + __func__); + cdf_mem_free(pRoamOffloadSynchCnf); + pSession->roamOffloadSynchParams.bRoamSynchInProgress = + false; + return CDF_STATUS_E_FAILURE; + } + pSession->roamOffloadSynchParams.bRoamSynchInProgress = false; + return CDF_STATUS_SUCCESS; +} + +void csr_roam_synch_clean_up (tpAniSirGlobal mac, uint8_t session_id) +{ + cds_msg_t msg; + struct roam_offload_synch_fail *roam_offload_failed = NULL; + tCsrRoamSession *session = &mac->roam.roamSession[session_id]; + + /* Clean up the roam synch in progress for LFR3 */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Roam Synch Failed, Clean Up", __func__); + session->roamOffloadSynchParams.bRoamSynchInProgress = false; + + roam_offload_failed = cdf_mem_malloc( + sizeof(struct roam_offload_synch_fail)); + if (NULL == roam_offload_failed) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: unable to allocate memory for roam synch fail" , + __func__); + return; + } + + roam_offload_failed->session_id = session_id; + msg.type = WMA_ROAM_OFFLOAD_SYNCH_FAIL; + msg.reserved = 0; + msg.bodyptr = roam_offload_failed; + if (!CDF_IS_STATUS_SUCCESS(cds_mq_post_message(CDF_MODULE_ID_WMA, + &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: Unable to post WMA_ROAM_OFFLOAD_SYNCH_FAIL to WMA", + __func__); + cdf_mem_free(roam_offload_failed); + } +} +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * csr_roam_copy_ht_profile() - Copy from src to dst + * @dst_profile: Destination HT profile + * @src_profile: Source HT profile + * + * Copy the HT profile from the given source to destination + * + * Return: None + */ +static void csr_roam_copy_ht_profile(tCsrRoamHTProfile *dst_profile, + tSirSmeHTProfile *src_profile) +{ + dst_profile->phymode = + csr_roamdot11mode_to_phymode(src_profile->dot11mode); + dst_profile->htCapability = src_profile->htCapability; + dst_profile->htSupportedChannelWidthSet = + src_profile->htSupportedChannelWidthSet; + dst_profile->htRecommendedTxWidthSet = + src_profile->htRecommendedTxWidthSet; + dst_profile->htSecondaryChannelOffset = + src_profile->htSecondaryChannelOffset; +#ifdef WLAN_FEATURE_11AC + dst_profile->vhtCapability = src_profile->vhtCapability; + dst_profile->vhtTxChannelWidthSet = src_profile->vhtTxChannelWidthSet; + dst_profile->apCenterChan = src_profile->apCenterChan; + dst_profile->apChanWidth = src_profile->apChanWidth; +#endif +} +#endif + +/** + * csr_roam_process_results_default() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context, eCsrRoamCompleteResult res) +{ + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamInfo roam_info; + CDF_STATUS status; + + sms_log(mac_ctx, LOGW, FL("receives no association indication")); + sms_log(mac_ctx, LOG1, FL("Assoc ref count %d"), + session->bRefAssocStartCnt); + if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile) + || CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) { + /* + * do not free for the other profiles as we need + * to send down stop BSS later + */ + csr_free_connect_bss_desc(mac_ctx, session_id); + csr_roam_free_connect_profile(mac_ctx, + &session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_set_default_dot11_mode(mac_ctx); + } + + switch (cmd->u.roamCmd.roamReason) { + /* + * If this transition is because of an 802.11 OID, then we + * transition back to INIT state so we sit waiting for more + * OIDs to be issued and we don't start the IDLE timer. + */ + case eCsrSmeIssuedFTReassoc: + case eCsrSmeIssuedAssocToSimilarAP: + case eCsrHddIssued: + case eCsrSmeIssuedDisassocForHandoff: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + roam_info.pProfile = &cmd->u.roamCmd.roamProfile; + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + cdf_mem_copy(&roam_info.bssid, + &session->joinFailStatusCode.bssId, + sizeof(struct cdf_mac_addr)); + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + /* + * If Join fails while Handoff is in progress, indicate + * disassociated event to supplicant to reconnect + */ + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)) { + csr_neighbor_roam_indicate_connect(mac_ctx, + (uint8_t)session_id, CDF_STATUS_E_FAILURE); + } +#endif + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (eCsrJoinFailureDueToConcurrency == res) + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL); + else + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } else { + /* + * bRefAssocStartCnt is not incremented when + * eRoamState == eCsrStopRoamingDueToConcurrency + * in csr_roam_join_next_bss API. so handle this in + * else case by sending assoc failure + */ + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_FAILURE); + } + sms_log(mac_ctx, LOG1, FL("roam(reason %d) failed"), + cmd->u.roamCmd.roamReason); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_update_hand_off((uint8_t) session_id, false); + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); +#ifdef FEATURE_WLAN_BTAMP_UT_RF + /* + * For WDS STA. To fix the issue where the WDS AP side may + * be too busy by BT activity and not able to receive + * WLAN traffic. Retry the join + */ + if (CSR_IS_WDS_STA(profile)) + csr_roam_start_join_retry_timer(mac_ctx, session_id, + CSR_JOIN_RETRY_TIMEOUT_PERIOD); +#endif + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); + break; + case eCsrForcedDisassoc: + case eCsrForcedDeauth: + case eCsrSmeIssuedIbssJoinFailure: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + if (eCsrSmeIssuedIbssJoinFailure == cmd->u.roamCmd.roamReason) + /* notify HDD that IBSS join failed */ + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_IBSS_IND, + eCSR_ROAM_RESULT_IBSS_JOIN_FAILED); + else + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, + NULL); +#endif + csr_roam_link_down(mac_ctx, session_id); + + if (mac_ctx->roam.deauthRspStatus == eSIR_SME_DEAUTH_STATUS) { + sms_log(mac_ctx, LOGW, + FL("FW still in connected state")); + break; + } + break; + case eCsrForcedIbssLeave: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_LEAVE, + eCSR_ROAM_RESULT_IBSS_STOP); + break; + case eCsrForcedDisassocMICFailure: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_REQ, NULL); +#endif + break; + case eCsrStopBss: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_STOPPED); + break; + case eCsrForcedDisassocSta: + case eCsrForcedDeauthSta: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + session = CSR_GET_SESSION(mac_ctx, session_id); + if (CSR_IS_SESSION_VALID(mac_ctx, session_id) && + CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info.u.pConnectedProfile = + &session->connectedProfile; + cdf_mem_copy(roam_info.peerMac.bytes, + cmd->u.roamCmd.peerMac, + sizeof(tSirMacAddr)); + roam_info.reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info.statusCode = eSIR_SME_SUCCESS; + status = csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + break; + case eCsrLostLink1: + /* if lost link roam1 failed, then issue lost link Scan2 ... */ + csr_scan_request_lost_link2(mac_ctx, session_id); + break; + case eCsrLostLink2: + /* if lost link roam2 failed, then issue lost link scan3 ... */ + csr_scan_request_lost_link3(mac_ctx, session_id); + break; + case eCsrLostLink3: + default: + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_IDLE, session_id); + + /* We are done with one round of lostlink roaming here */ + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + } +} + +/** + * csr_roam_process_start_bss_success() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context) +{ + uint32_t session_id = cmd->sessionId; + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tSirBssDescription *bss_desc = NULL; + tCsrRoamInfo roam_info; + tSirSmeStartBssRsp *start_bss_rsp = NULL; + tCsrScanResult *scan_res = NULL; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + tDot11fBeaconIEs *ies_ptr = NULL; + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + CDF_STATUS status; + host_log_ibss_pkt_type *ibss_log; + uint32_t bi; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + + /* + * on the StartBss Response, LIM is returning the Bss Description that + * we are beaconing. Add this Bss Description to our scan results and + * chain the Profile to this Bss Description. On a Start BSS, there was + * no detected Bss description (no partner) so we issued the Start Bss + * to start the Ibss without any Bss description. Lim was kind enough + * to return the Bss Description that we start beaconing for the newly + * started Ibss. + */ + sms_log(mac_ctx, LOG2, FL("receives start BSS ok indication")); + status = CDF_STATUS_E_FAILURE; + start_bss_rsp = (tSirSmeStartBssRsp *) context; + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + if (CSR_IS_IBSS(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + else if (CSR_IS_INFRA_AP(profile)) + session->connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED; + if (!CSR_IS_WDS_STA(profile)) { + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + bss_desc = &start_bss_rsp->bssDescription; + if (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ies_ptr))) { + sms_log(mac_ctx, LOGW, FL("cannot parse IBSS IEs")); + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_IND, + eCSR_ROAM_RESULT_IBSS_START_FAILED); + return; + } + if (!CSR_IS_INFRA_AP(profile)) { + scan_res = + csr_scan_append_bss_description(mac_ctx, + bss_desc, ies_ptr, false, + session_id); + } + csr_roam_save_connected_bss_desc(mac_ctx, session_id, bss_desc); + csr_roam_free_connect_profile(mac_ctx, + &session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + if (bss_desc) { + csr_roam_save_connected_infomation(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct cdf_mac_addr)); + } + /* We are done with the IEs so free it */ + cdf_mem_free(ies_ptr); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + if (CSR_INVALID_SCANRESULT_HANDLE == + cmd->u.roamCmd.hBSSList) { + /* + * We start the IBSS (didn't find any + * matched IBSS out there) + */ + ibss_log->eventId = + WLAN_IBSS_EVENT_START_IBSS_RSP; + } else { + ibss_log->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_RSP; + } + if (bss_desc) { + cdf_mem_copy(ibss_log->bssid, + bss_desc->bssId, 6); + ibss_log->operatingChannel = + bss_desc->channelId; + } + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int( + mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for BI */ + ibss_log->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + /* + * Only set context for non-WDS_STA. We don't even need it for + * WDS_AP. But since the encryption. + * is WPA2-PSK so it won't matter. + */ + if (CSR_IS_ENC_TYPE_STATIC(profile->negotiatedUCEncryptionType) + && session->pCurRoamProfile + && !CSR_IS_INFRA_AP(session->pCurRoamProfile)) { + /* + * Issue the set Context request to LIM to establish + * the Broadcast STA context for the Ibss. In Rome IBSS + * case, dummy key installation will break proper BSS + * key installation, so skip it. + */ + if (!CSR_IS_IBSS(session->pCurRoamProfile)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, + false, eSIR_TX_RX, 0, 0, NULL, 0); + } + + } + } else { + /* + * Keep the state to eCSR_ROAMING_STATE_JOINING. + * Need to send join_req. + */ + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_res = GET_BASE_ADDR(cmd->u.roamCmd. + pRoamBssEntry, tCsrScanResult, Link); + if (scan_res) { + bss_desc = &scan_res->Result.BssDescriptor; + ies_ptr = (tDot11fBeaconIEs *) + (scan_res->Result.pvIes); + /* Set the roaming substate to join attempt */ + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_JOIN_REQ, + session_id); + status = csr_send_join_req_msg(mac_ctx, + session_id, bss_desc, + profile, ies_ptr, + eWNI_SME_JOIN_REQ); + } + } else { + sms_log(mac_ctx, LOGE, + "StartBSS for WDS station with no BssDesc"); + CDF_ASSERT(0); + } + } + /* + * Only tell upper layer is we start the BSS because Vista doesn't like + * multiple connection indications. If we don't start the BSS ourself, + * handler of eSIR_SME_JOINED_NEW_BSS will trigger the connection start + * indication in Vista + */ + if (!CSR_IS_JOIN_TO_IBSS(profile)) { + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_WDS(profile)) { + roam_status = eCSR_ROAM_WDS_IND; + roam_result = eCSR_ROAM_RESULT_WDS_STARTED; + } + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_STARTED; + } + /* + * Only tell upper layer is we start the BSS because Vista + * doesn't like multiple connection indications. If we don't + * start the BSS ourself, handler of eSIR_SME_JOINED_NEW_BSS + * will trigger the connection start indication in Vista + */ + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + /* We start the IBSS (didn't find any matched IBSS out there) */ + roam_info.pBssDesc = bss_desc; + roam_info.staId = (uint8_t) start_bss_rsp->staId; + cdf_mem_copy(roam_info.bssid.bytes, bss_desc->bssId, + sizeof(struct cdf_mac_addr)); + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + dst_profile = &session->connectedProfile.HTProfile; + src_profile = &start_bss_rsp->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != CDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, src_profile); +#endif + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + + + if (CSR_IS_WDS_STA(profile)) { + /* need to send stop BSS because we fail to send join_req */ + csr_roam_issue_disassociate_cmd(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_STOPPED); + } +} + +/** + * csr_roam_process_join_res() - Process the Join results + * @mac_ctx: Global MAC Context + * @result: Result after the command was processed + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Process the join results which are obtained in a succesful join + * + * Return: None + */ +static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx, + eCsrRoamCompleteResult res, tSmeCmd *cmd, void *context) +{ + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + sme_QosAssocInfo assoc_info; + uint32_t key_timeout_interval = 0; + uint8_t acm_mask = 0; /* HDD needs ACM mask in assoc rsp callback */ + uint32_t session_id = cmd->sessionId; + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tSirBssDescription *bss_desc = NULL; + tCsrScanResult *scan_res = NULL; + sme_qos_csr_event_indType ind_qos; + csr_roam_offload_synch_params *roam_offload_params = NULL; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + tCsrRoamConnectedProfile *conn_profile = NULL; + tDot11fBeaconIEs *ies_ptr = NULL; + tCsrRoamInfo roam_info; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + tSirSmeJoinRsp *join_rsp = (tSirSmeJoinRsp *) context; + uint32_t len; + + roam_offload_params = &session->roamOffloadSynchParams; + conn_profile = &session->connectedProfile; + if (eCsrReassocSuccess == res) + ind_qos = SME_QOS_CSR_REASSOC_COMPLETE; + else + ind_qos = SME_QOS_CSR_ASSOC_COMPLETE; + sms_log(mac_ctx, LOGW, FL("receives association indication")); + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + /* always free the memory here */ + if (session->pWpaRsnRspIE) { + session->nWpaRsnRspIeLength = 0; + cdf_mem_free(session->pWpaRsnRspIE); + session->pWpaRsnRspIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (session->pWapiRspIE) { + session->nWapiRspIeLength = 0; + cdf_mem_free(session->pWapiRspIE); + session->pWapiRspIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_BTAMP_UT_RF + session->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(mac_ctx, session_id); +#endif + /* + * Reset remain_in_power_active_till_dhcp as + * it might have been set by last failed secured connection. + * It should be set only for secured connection. + */ + ps_global_info->remain_in_power_active_till_dhcp = false; + if (CSR_IS_INFRASTRUCTURE(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED; + /* + * Use the last connected bssdesc for reassoc-ing to the same AP. + * NOTE: What to do when reassoc to a different AP??? + */ + if ((eCsrHddIssuedReassocToSameAP == cmd->u.roamCmd.roamReason) + || (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) { + bss_desc = session->pConnectBssDesc; + if (bss_desc) + cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct cdf_mac_addr)); + } else { + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_res = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + if (scan_res != NULL) { + bss_desc = &scan_res->Result.BssDescriptor; + ies_ptr = (tDot11fBeaconIEs *) + (scan_res->Result.pvIes); + cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct cdf_mac_addr)); + } + } + } + if (bss_desc) { + roam_info.staId = STA_INVALID_IDX; + csr_roam_save_connected_infomation(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + /* Save WPA/RSN IE */ + csr_roam_save_security_rsp_ie(mac_ctx, session_id, + profile->negotiatedAuthType, bss_desc, ies_ptr); +#ifdef FEATURE_WLAN_ESE + roam_info.isESEAssoc = conn_profile->isESEAssoc; +#endif + + /* + * csr_roam_state_change also affects sub-state. + * Hence, csr_roam_state_change happens first and then + * substate change. + * Moving even save profile above so that below + * mentioned conditon is also met. + * JEZ100225: Moved to after saving the profile. + * Fix needed in main/latest + */ + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_JOINED, session_id); + + /* + * Make sure the Set Context is issued before link + * indication to NDIS. After link indication is + * made to NDIS, frames could start flowing. + * If we have not set context with LIM, the frames + * will be dropped for the security context may not + * be set properly. + * + * this was causing issues in the 2c_wlan_wep WHQL test + * when the SetContext was issued after the link + * indication. (Link Indication happens in the + * profFSMSetConnectedInfra call). + * + * this reordering was done on titan_prod_usb branch + * and is being replicated here. + */ + + if (CSR_IS_ENC_TYPE_STATIC + (profile->negotiatedUCEncryptionType) && + !profile->bWPSAssociation) { + /* + * Issue the set Context request to LIM to establish + * the Unicast STA context + */ + if (!CDF_IS_STATUS_SUCCESS( + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedUCEncryptionType, + bss_desc, &(bss_desc->bssId), + false, true, + eSIR_TX_RX, 0, 0, NULL, 0))) { + /* NO keys. these key parameters don't matter */ + sms_log(mac_ctx, LOGE, + FL("Set context for unicast fail")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_id); + } + /* + * Issue the set Context request to LIM + * to establish the Broadcast STA context + * NO keys. these key parameters don't matter + */ + csr_roam_issue_set_context_req(mac_ctx, session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } else { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_offload_params->bRoamSynchInProgress + && (roam_offload_params->authStatus + == CSR_ROAM_AUTH_STATUS_AUTHENTICATED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Don't start waitforkey timer")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_id); + } else { +#endif + /* Need to wait for supplicant authtication */ + roam_info.fAuthRequired = true; + /* + * Set the substate to WaitForKey in case + * authentiation is needed + */ + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + session_id); + + /* + * Set remain_in_power_active_till_dhcp to make + * sure we wait for until keys are set before + * going into BMPS. + */ + ps_global_info->remain_in_power_active_till_dhcp + = true; + + if (profile->bWPSAssociation) + key_timeout_interval = + CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD; + else + key_timeout_interval = + CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD; + + /* Save session_id in case of timeout */ + mac_ctx->roam.WaitForKeyTimerInfo.sessionId = + (uint8_t) session_id; + /* + * This time should be long enough for the rest + * of the process plus setting key + */ + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_start_wait_for_key_timer( + mac_ctx, key_timeout_interval)) + ) { + /* Reset state so nothing is blocked. */ + sms_log(mac_ctx, LOGE, FL + ("Failed preauth timer start")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, + session_id); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } +#endif + } + + assoc_info.pBssDesc = bss_desc; /* could be NULL */ + assoc_info.pProfile = profile; + if (context) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_offload_params->bRoamSynchInProgress) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Clear Connected info")); +#endif + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + len = join_rsp->assocReqLength + + join_rsp->assocRspLength + + join_rsp->beaconLength; +#ifdef WLAN_FEATURE_VOWIFI_11R + len += join_rsp->parsedRicRspLen; +#endif /* WLAN_FEATURE_VOWIFI_11R */ +#ifdef FEATURE_WLAN_ESE + len += join_rsp->tspecIeLen; +#endif + if (len) { + session->connectedInfo.pbFrames = + cdf_mem_malloc(len); + if (session->connectedInfo.pbFrames != + NULL) { + cdf_mem_copy( + session->connectedInfo.pbFrames, + join_rsp->frames, len); + session->connectedInfo.nAssocReqLength = + join_rsp->assocReqLength; + session->connectedInfo.nAssocRspLength = + join_rsp->assocRspLength; + session->connectedInfo.nBeaconLength = + join_rsp->beaconLength; +#ifdef WLAN_FEATURE_VOWIFI_11R + session->connectedInfo.nRICRspLength = + join_rsp->parsedRicRspLen; +#endif /* WLAN_FEATURE_VOWIFI_11R */ +#ifdef FEATURE_WLAN_ESE + session->connectedInfo.nTspecIeLength = + join_rsp->tspecIeLen; +#endif + roam_info.nAssocReqLength = + join_rsp->assocReqLength; + roam_info.nAssocRspLength = + join_rsp->assocRspLength; + roam_info.nBeaconLength = + join_rsp->beaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + if (cmd->u.roamCmd.fReassoc) + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + conn_profile->vht_channel_width = + join_rsp->vht_channel_width; + session->connectedInfo.staId = + (uint8_t) join_rsp->staId; + roam_info.staId = (uint8_t) join_rsp->staId; + roam_info.ucastSig = (uint8_t) join_rsp->ucastSig; + roam_info.bcastSig = (uint8_t) join_rsp->bcastSig; + roam_info.timingMeasCap = join_rsp->timingMeasCap; +#ifdef FEATURE_WLAN_TDLS + roam_info.tdls_prohibited = join_rsp->tdls_prohibited; + roam_info.tdls_chan_swit_prohibited = + join_rsp->tdls_chan_swit_prohibited; + sms_log(mac_ctx, LOG1, + FL("tdls:prohibit: %d, chan_swit_prohibit: %d"), + roam_info.tdls_prohibited, + roam_info.tdls_chan_swit_prohibited); +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + src_profile = &join_rsp->HTProfile; + dst_profile = &conn_profile->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != CDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, + src_profile); +#endif + } else { + if (cmd->u.roamCmd.fReassoc) { + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.nBeaconLength = + session->connectedInfo.nBeaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + + /* + * Update the staId from the previous connected profile info + * as the reassociation is triggred at SME/HDD + */ + + if ((eCsrHddIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason) || + (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) + roam_info.staId = session->connectedInfo.staId; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* + * Indicate SME-QOS with reassoc success event, + * only after copying the frames + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, ind_qos, + &assoc_info); +#endif + roam_info.pBssDesc = bss_desc; + roam_info.statusCode = + session->joinFailStatusCode.statusCode; + roam_info.reasonCode = + session->joinFailStatusCode.reasonCode; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, bss_desc, NULL); +#endif + conn_profile->acm_mask = acm_mask; + /* + * start UAPSD if uapsd_mask is not 0 because HDD will + * configure for trigger frame It may be better to let QoS do + * this???? + */ + if (conn_profile->modifyProfileFields.uapsd_mask) { + sms_log(mac_ctx, LOGE, + " uapsd_mask (0x%X) set, request UAPSD now", + conn_profile->modifyProfileFields.uapsd_mask); + sme_ps_start_uapsd(mac_ctx, session_id, + NULL, NULL); + } + conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode; + roam_info.u.pConnectedProfile = conn_profile; + + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (!IS_FEATURE_SUPPORTED_BY_FW + (SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_offload_params->bRoamSynchInProgress) { + roam_info.roamSynchInProgress = 1; + roam_info.synchAuthStatus = + roam_offload_params->authStatus; + cdf_mem_copy(roam_info.kck, + roam_offload_params->kck, + SIR_KCK_KEY_LEN); + cdf_mem_copy(roam_info.kek, + roam_offload_params->kek, + SIR_KEK_KEY_LEN); + cdf_mem_copy(roam_info.replay_ctr, + roam_offload_params->replay_ctr, + SIR_REPLAY_CTR_LEN); + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL + ("LFR3: Copy KCK, KEK and Replay Ctr")); + } +#endif + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_offload_params->bRoamSynchInProgress + && (roam_offload_params->authStatus + == CSR_ROAM_AUTH_STATUS_CONNECTED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Send Synch Cnf for Auth status connected")); + csr_roam_offload_send_synch_cnf(mac_ctx, + session_id); + } +#endif + } + + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_NONE, true); + csr_reset_pmkid_candidate_list(mac_ctx, session_id); +#ifdef FEATURE_WLAN_WAPI + csr_reset_bkid_candidate_list(mac_ctx, session_id); +#endif + } else { + sms_log(mac_ctx, LOGW, + "Roam command doesn't have a BSS desc"); + } + /* Not to signal link up because keys are yet to be set. + * The linkup function will overwrite the sub-state that + * we need to keep at this point. + */ + if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_offload_params->bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + FL + ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up")); + } +#endif + csr_roam_link_up(mac_ctx, conn_profile->bssid); + } +} + +/** + * csr_roam_process_results() - Process the Roam Results + * @mac_ctx: Global MAC Context + * @cmd: Command that has been processed + * @res: Results available after processing the command + * @context: Context + * + * Process the available results and make an appropriate decision + * + * Return: true if the command can be released, else not. + */ +static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + eCsrRoamCompleteResult res, void *context) +{ + bool release_cmd = true; + tSirBssDescription *bss_desc = NULL; + tCsrRoamInfo roam_info; + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + host_log_ibss_pkt_type *ibss_log; + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found "), session_id); + return false; + } + sms_log(mac_ctx, LOG1, FL("Processing ROAM results...")); + switch (res) { + case eCsrJoinSuccess: + case eCsrReassocSuccess: + csr_roam_process_join_res(mac_ctx, res, cmd, context); + break; + case eCsrStartBssSuccess: + csr_roam_process_start_bss_success(mac_ctx, cmd, context); + break; + case eCsrStartBssFailure: +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + ibss_log->status = WLAN_IBSS_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_WDS(profile)) { + roam_status = eCSR_ROAM_WDS_IND; + roam_result = eCSR_ROAM_RESULT_WDS_STARTED; + } + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_START_FAILED; + } + if (context) { + bss_desc = (tSirBssDescription *) context; + } else { + bss_desc = NULL; + } + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, roam_status, + roam_result); + csr_set_default_dot11_mode(mac_ctx); + break; + case eCsrSilentlyStopRoaming: + /* + * We are here because we try to start the same IBSS. + * No message to PE. return the roaming state to Joined. + */ + sms_log(mac_ctx, LOGW, FL("receives silently stop roam ind")); + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + session_id); + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + cdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + /* + * Since there is no change in the current state, simply pass + * back no result otherwise HDD may be mistakenly mark to + * disconnected state. + */ + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_IBSS_IND, eCSR_ROAM_RESULT_NONE); + break; + case eCsrSilentlyStopRoamingSaveState: + /* We are here because we try to connect to the same AP */ + /* No message to PE */ + sms_log(mac_ctx, LOGW, + FL("receives silently stop roaming indication")); + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + + /* to aviod resetting the substate to NONE */ + mac_ctx->roam.curState[session_id] = eCSR_ROAMING_STATE_JOINED; + /* + * No need to change substate to wai_for_key because there + * is no state change + */ + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + cdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + roam_info.nBeaconLength = session->connectedInfo.nBeaconLength; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.pbFrames = session->connectedInfo.pbFrames; + roam_info.staId = session->connectedInfo.staId; + roam_info.u.pConnectedProfile = &session->connectedProfile; + if (0 == roam_info.staId) { + CDF_ASSERT(0); + return false; + } + session->bRefAssocStartCnt--; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_ASSOCIATED, true); + break; + case eCsrReassocFailure: +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_REASSOC_FAILURE, NULL); +#endif + case eCsrJoinWdsFailure: + sms_log(mac_ctx, LOGW, FL("failed to join WDS")); + csr_free_connect_bss_desc(mac_ctx, session_id); + csr_roam_free_connect_profile(mac_ctx, + &session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_NOT_ASSOCIATED); + /* Need to issue stop_bss */ + break; + case eCsrJoinFailure: + case eCsrNothingToJoin: + case eCsrJoinFailureDueToConcurrency: + default: + csr_roam_process_results_default(mac_ctx, cmd, context, res); + break; + } + return release_cmd; +} + +CDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pDstProfile, + tCsrRoamProfile *pSrcProfile) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t size = 0; + + cdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0); + if (pSrcProfile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct cdf_mac_addr) * pSrcProfile->BSSIDs.numOfBSSIDs; + pDstProfile->BSSIDs.bssid = cdf_mem_malloc(size); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = + pSrcProfile->BSSIDs.numOfBSSIDs; + cdf_mem_copy(pDstProfile->BSSIDs.bssid, + pSrcProfile->BSSIDs.bssid, size); + } + if (pSrcProfile->SSIDs.numOfSSIDs) { + size = sizeof(tCsrSSIDInfo) * pSrcProfile->SSIDs.numOfSSIDs; + pDstProfile->SSIDs.SSIDList = cdf_mem_malloc(size); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = + pSrcProfile->SSIDs.numOfSSIDs; + cdf_mem_copy(pDstProfile->SSIDs.SSIDList, + pSrcProfile->SSIDs.SSIDList, size); + } + if (pSrcProfile->nWPAReqIELength) { + pDstProfile->pWPAReqIE = + cdf_mem_malloc(pSrcProfile->nWPAReqIELength); + if (NULL == pDstProfile->pWPAReqIE) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWPAReqIELength = + pSrcProfile->nWPAReqIELength; + cdf_mem_copy(pDstProfile->pWPAReqIE, pSrcProfile->pWPAReqIE, + pSrcProfile->nWPAReqIELength); + } + if (pSrcProfile->nRSNReqIELength) { + pDstProfile->pRSNReqIE = + cdf_mem_malloc(pSrcProfile->nRSNReqIELength); + if (NULL == pDstProfile->pRSNReqIE) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nRSNReqIELength = + pSrcProfile->nRSNReqIELength; + cdf_mem_copy(pDstProfile->pRSNReqIE, pSrcProfile->pRSNReqIE, + pSrcProfile->nRSNReqIELength); + } +#ifdef FEATURE_WLAN_WAPI + if (pSrcProfile->nWAPIReqIELength) { + pDstProfile->pWAPIReqIE = + cdf_mem_malloc(pSrcProfile->nWAPIReqIELength); + if (NULL == pDstProfile->pWAPIReqIE) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWAPIReqIELength = + pSrcProfile->nWAPIReqIELength; + cdf_mem_copy(pDstProfile->pWAPIReqIE, pSrcProfile->pWAPIReqIE, + pSrcProfile->nWAPIReqIELength); + } +#endif /* FEATURE_WLAN_WAPI */ + if (pSrcProfile->nAddIEScanLength) { + pDstProfile->pAddIEScan = + cdf_mem_malloc(pSrcProfile->nAddIEScanLength); + if (NULL == pDstProfile->pAddIEScan) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEScanLength = + pSrcProfile->nAddIEScanLength; + cdf_mem_copy(pDstProfile->pAddIEScan, pSrcProfile->pAddIEScan, + pSrcProfile->nAddIEScanLength); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + cdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEAssocLength = + pSrcProfile->nAddIEAssocLength; + cdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + if (pSrcProfile->ChannelInfo.ChannelList) { + pDstProfile->ChannelInfo.ChannelList = + cdf_mem_malloc(pSrcProfile->ChannelInfo. + numOfChannels); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = + pSrcProfile->ChannelInfo.numOfChannels; + cdf_mem_copy(pDstProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.numOfChannels); + } + pDstProfile->AuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType = pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType = pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->negotiatedUCEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->negotiatedMCEncryptionType; + pDstProfile->negotiatedAuthType = pSrcProfile->negotiatedAuthType; +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + pDstProfile->BSSType = pSrcProfile->BSSType; + pDstProfile->phyMode = pSrcProfile->phyMode; + pDstProfile->csrPersona = pSrcProfile->csrPersona; + +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pSrcProfile)) + if (pDstProfile->phyMode & eCSR_DOT11_MODE_11n) + pDstProfile->phyMode &= ~eCSR_DOT11_MODE_11n; +#endif /* FEATURE_WLAN_WAPI */ + pDstProfile->CBMode = pSrcProfile->CBMode; + pDstProfile->ch_params.ch_width = pSrcProfile->ch_params.ch_width; + pDstProfile->ch_params.center_freq_seg0 = + pSrcProfile->ch_params.center_freq_seg0; + pDstProfile->ch_params.center_freq_seg1 = + pSrcProfile->ch_params.center_freq_seg1; + pDstProfile->ch_params.sec_ch_offset = + pSrcProfile->ch_params.sec_ch_offset; + /*Save the WPS info */ + pDstProfile->bWPSAssociation = pSrcProfile->bWPSAssociation; + pDstProfile->bOSENAssociation = pSrcProfile->bOSENAssociation; + pDstProfile->uapsd_mask = pSrcProfile->uapsd_mask; + pDstProfile->beaconInterval = pSrcProfile->beaconInterval; + pDstProfile->privacy = pSrcProfile->privacy; + pDstProfile->fwdWPSPBCProbeReq = pSrcProfile->fwdWPSPBCProbeReq; + pDstProfile->csr80211AuthType = pSrcProfile->csr80211AuthType; + pDstProfile->dtimPeriod = pSrcProfile->dtimPeriod; + pDstProfile->ApUapsdEnable = pSrcProfile->ApUapsdEnable; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->SSIDs.SSIDList[0].ssidHidden; + pDstProfile->protEnabled = pSrcProfile->protEnabled; + pDstProfile->obssProtEnabled = pSrcProfile->obssProtEnabled; + pDstProfile->cfg_protection = pSrcProfile->cfg_protection; + pDstProfile->wps_state = pSrcProfile->wps_state; + pDstProfile->ieee80211d = pSrcProfile->ieee80211d; + pDstProfile->sap_dot11mc = pSrcProfile->sap_dot11mc; + cdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } +#endif + cdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams, + sizeof(tSirAddIeParams)); +end: + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +CDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamProfile *pDstProfile) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamConnectedProfile *pSrcProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + + cdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0); + + pDstProfile->BSSIDs.bssid = cdf_mem_malloc(sizeof(struct cdf_mac_addr)); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate memory for BSSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = 1; + cdf_copy_macaddr(pDstProfile->BSSIDs.bssid, &pSrcProfile->bssid); + + if (pSrcProfile->SSID.ssId) { + pDstProfile->SSIDs.SSIDList = + cdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate memory for SSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = 1; + pDstProfile->SSIDs.SSIDList[0].handoffPermitted = + pSrcProfile->handoffPermitted; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->ssidHidden; + cdf_mem_copy(&pDstProfile->SSIDs.SSIDList[0].SSID, + &pSrcProfile->SSID, sizeof(tSirMacSSid)); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + cdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate mem for additional ie")); + goto end; + } + pDstProfile->nAddIEAssocLength = pSrcProfile->nAddIEAssocLength; + cdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + pDstProfile->ChannelInfo.ChannelList = cdf_mem_malloc(1); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = 1; + pDstProfile->ChannelInfo.ChannelList[0] = pSrcProfile->operationChannel; + pDstProfile->AuthType.numEntries = 1; + pDstProfile->AuthType.authType[0] = pSrcProfile->AuthType; + pDstProfile->negotiatedAuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType.numEntries = 1; + pDstProfile->EncryptionType.encryptionType[0] = + pSrcProfile->EncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType.numEntries = 1; + pDstProfile->mcEncryptionType.encryptionType[0] = + pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->mcEncryptionType; + pDstProfile->BSSType = pSrcProfile->BSSType; + pDstProfile->CBMode = pSrcProfile->CBMode; + cdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } +#endif + +end: + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +CDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tScanResultHandle hBSSList, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate, bool fClearScan) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + } else { + if (fClearScan) { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + } + pCommand->u.roamCmd.fReleaseProfile = false; + if (NULL == pProfile) { + /* We can roam now */ + /* Since pProfile is NULL, we need to build our own profile, set everything to default */ + /* We can only support open and no encryption */ + pCommand->u.roamCmd.roamProfile.AuthType.numEntries = 1; + pCommand->u.roamCmd.roamProfile.AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + pCommand->u.roamCmd.roamProfile.EncryptionType. + numEntries = 1; + pCommand->u.roamCmd.roamProfile.EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE; + pCommand->u.roamCmd.roamProfile.csrPersona = + CDF_STA_MODE; + } else { + /* make a copy of the profile */ + status = + csr_roam_copy_profile(pMac, + &pCommand->u.roamCmd.roamProfile, + pProfile); + if (CDF_IS_STATUS_SUCCESS(status)) { + pCommand->u.roamCmd.fReleaseProfile = true; + } + } + + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.hBSSList = hBSSList; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + pCommand->u.roamCmd.fReleaseBssList = true; + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("CSR PERSONA=%d"), + pCommand->u.roamCmd.roamProfile.csrPersona); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } + + return status; +} + +CDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields *pMmodProfileFields, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + } else { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + if (pProfile) { + /* This is likely trying to reassoc to different profile */ + pCommand->u.roamCmd.fReleaseProfile = false; + /* make a copy of the profile */ + status = + csr_roam_copy_profile(pMac, + &pCommand->u.roamCmd.roamProfile, + pProfile); + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + } else { + status = + csr_roam_copy_connected_profile(pMac, sessionId, + &pCommand->u.roamCmd. + roamProfile); + /* how to update WPA/WPA2 info in roamProfile?? */ + pCommand->u.roamCmd.roamProfile.uapsd_mask = + pMmodProfileFields->uapsd_mask; + } + if (CDF_IS_STATUS_SUCCESS(status)) { + pCommand->u.roamCmd.fReleaseProfile = true; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + /* For reassoc there is no BSS list, so the bool set to false */ + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.fReassoc = true; + csr_roam_remove_duplicate_command(pMac, sessionId, pCommand, + reason); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_roam_completion(pMac, sessionId, NULL, pCommand, + eCSR_ROAM_RESULT_FAILURE, false); + csr_release_command_roam(pMac, pCommand); + } + } + return status; +} + +CDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId, + tpSirBssDescription pBssDescription, + eCsrRoamReason reason, bool fImmediate) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + } else { + if (pBssDescription) { + /* copy over the parameters we need later */ + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = reason; + /* this is the important parameter */ + /* in this case we are using this field for the "next" BSS */ + pCommand->u.roamCmd.pLastRoamBss = pBssDescription; + status = csr_queue_sme_command(pMac, pCommand, fImmediate); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + (" fail to enqueue preauth command, status = %d"), + status); + csr_release_command_preauth(pMac, pCommand); + } + } else { + /* Return failure */ + status = CDF_STATUS_E_RESOURCES; + } + } + return status; +} + +CDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) && + (eCsrPerformPreauth == reason)) { + sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"), + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_preauth(pMac, pCommand); + } + } else if ((eSmeCommandRoam == pCommand->command) && + (eCsrSmeIssuedFTReassoc == reason)) { + sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"), + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_roam(pMac, pCommand); + } + } else { + sms_log(pMac, LOGE, FL("Command = %d, Reason = %d "), + pCommand->command, + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGE, + FL("pEntry NULL for eWNI_SME_FT_PRE_AUTH_RSP")); + } + sme_process_pending_queue(pMac); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + uint32_t *pRoamId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tScanResultHandle hBSSList; + tCsrScanResultFilter *pScanFilter; + uint32_t roamId = 0; + bool fCallCallback = false; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription first_ap_profile; + + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL("session does not exist for given sessionId:%d"), + sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (NULL == pProfile) { + sms_log(pMac, LOGP, FL("No profile specified")); + return CDF_STATUS_E_FAILURE; + } + /* Initialize the count before proceeding with the Join requests */ + pSession->join_bssid_count = 0; + sms_log(pMac, LOG1, + FL("called BSSType = %d authtype = %d encryType = %d"), + pProfile->BSSType, pProfile->AuthType.authType[0], + pProfile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(pMac, sessionId); + csr_scan_remove_fresh_scan_command(pMac, sessionId); + /* Only abort the scan if its not used for other roam/connect purpose */ + csr_scan_abort_mac_scan(pMac, sessionId, eCSR_SCAN_ABORT_DEFAULT); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + /* Check whether ssid changes */ + if (csr_is_conn_state_connected(pMac, sessionId) && + pProfile->SSIDs.numOfSSIDs && !csr_is_ssid_in_list(pMac, + &pSession->connectedProfile.SSID, &pProfile->SSIDs)) + csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); +#ifdef FEATURE_WLAN_BTAMP_UT_RF + pSession->maxRetryCount = CSR_JOIN_MAX_RETRY_COUNT; +#endif + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), + 0); + /* Try to connect to any BSS */ + if (NULL == pProfile) { + /* No encryption */ + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pProfile, pScanFilter); + } + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) + *pRoamId = roamId; + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pScanFilter); + goto end; + } + + /*Save the WPS info */ + if (NULL != pProfile) { + pScanFilter->bWPSAssociation = + pProfile->bWPSAssociation; + pScanFilter->bOSENAssociation = + pProfile->bOSENAssociation; + } else { + pScanFilter->bWPSAssociation = 0; + pScanFilter->bOSENAssociation = 0; + } + if ((pProfile && CSR_IS_WDS_AP(pProfile)) || (pProfile + && CSR_IS_INFRA_AP(pProfile))) { + /* This can be started right away */ + status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL, + eCsrHddIssued, roamId, false, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue start BSS cmd with status = 0x%08X"), + status); + fCallCallback = true; + } else { + sms_log(pMac, LOG1, + FL("Connect request to proceed for sap mode")); + } + + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + goto end; + } + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + sms_log(pMac, LOG1, + FL("******* csr_scan_get_result Status ****** %d"), status); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* check if set hw mode needs to be done */ + if ((pMac->policy_manager_enabled) && + (pScanFilter->csrPersona == CDF_STA_MODE)) { + csr_get_bssdescr_from_scan_handle(hBSSList, + &first_ap_profile); + if (!cds_handle_conc_multiport(sessionId, + first_ap_profile.channelId)) { + sms_log(pMac, LOG1, FL("conc multiport error")); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + goto error; + } + } + + status = csr_roam_issue_connect(pMac, sessionId, pProfile, + hBSSList, eCsrHddIssued, roamId, false, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue connect cmd with status = 0x%08X"), + status); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + } + } else if (NULL != pProfile) { + /* Check whether it is for start ibss */ + if (CSR_IS_START_IBSS(pProfile)) { + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, NULL, eCsrHddIssued, + roamId, false, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue startIBSS cmd with status = 0x%08X"), + status); + fCallCallback = true; + } + } else { + /* scan for this SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue SSID scan cmd with status = 0x%08X"), + status); + fCallCallback = true; + } else { + sms_log(pMac, LOG1, + FL("SSID scan requested")); + } + } + } else { + fCallCallback = true; + } + +error: + if (NULL != pProfile) + /* + * we need to free memory for filter + * if profile exists + */ + csr_free_scan_filter(pMac, pScanFilter); + + cdf_mem_free(pScanFilter); +end: + /* tell the caller if we fail to trigger a join request */ + if (fCallCallback) { + csr_roam_call_callback(pMac, sessionId, NULL, roamId, + eCSR_ROAM_FAILED, eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +/** + * csr_roam_reassoc() - process reassoc command + * @mac_ctx: mac global context + * @session_id: session id + * @profile: roam profile + * @mod_fields: AC info being modified in reassoc + * @roam_id: roam id to be populated + * + * Return: status of operation + */ +CDF_STATUS +csr_roam_reassoc(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile, + tCsrRoamModifyProfileFields mod_fields, + uint32_t *roam_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool fCallCallback = true; + uint32_t roamId = 0; + + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == profile) { + sms_log(mac_ctx, LOGP, FL("No profile specified")); + return CDF_STATUS_E_FAILURE; + } + sms_log(mac_ctx, LOG1, + FL("called BSSType = %d authtype = %d encryType = %d"), + profile->BSSType, profile->AuthType.authType[0], + profile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(mac_ctx, session_id); + csr_scan_remove_fresh_scan_command(mac_ctx, session_id); + csr_scan_abort_mac_scan_not_for_connect(mac_ctx, session_id); + csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL, + eCsrHddIssuedReassocToSameAP); + if (csr_is_conn_state_connected(mac_ctx, session_id)) { + if (profile) { + if (profile->SSIDs.numOfSSIDs && + csr_is_ssid_in_list(mac_ctx, + &session->connectedProfile.SSID, + &profile->SSIDs)) { + fCallCallback = false; + } else { + /* + * Connected SSID did not match with what is + * asked in profile + */ + sms_log(mac_ctx, LOG1, FL("SSID mismatch")); + } + } else if (!cdf_mem_compare(&mod_fields, + &session->connectedProfile.modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))) { + fCallCallback = false; + } else { + sms_log(mac_ctx, LOG1, + /* + * Either the profile is NULL or none of the + * fields in tCsrRoamModifyProfileFields got + * modified + */ + FL("Profile NULL or nothing to modify.")); + } + } else { + sms_log(mac_ctx, LOG1, FL("Not connected! No need to reassoc")); + } + if (!fCallCallback) { + roamId = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (roam_id) + *roam_id = roamId; + status = csr_roam_issue_reassoc(mac_ctx, session_id, profile, + &mod_fields, eCsrHddIssuedReassocToSameAP, + roamId, false); + } else { + status = csr_roam_call_callback(mac_ctx, session_id, NULL, + roamId, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +CDF_STATUS csr_roam_join_last_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = NULL; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId; + tCsrRoamProfile *pProfile = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pSession->pCurRoamProfile) { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + /* We have to make a copy of pCurRoamProfile because it + * will be free inside csr_roam_issue_connect */ + pProfile = cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == pProfile) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0); + status = csr_roam_copy_profile(pMac, pProfile, + pSession->pCurRoamProfile); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = CDF_STATUS_E_NOMEM; + goto end; + } + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* we want to put the last connected BSS to the + * very beginning, if possible */ + csr_move_bss_to_head_from_bssid(pMac, + &pSession->connectedProfile.bssid, hBSSList); + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, hBSSList, eCsrHddIssued, + roamId, false, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, hBSSList); + goto end; + } + } else { + /* scan for this SSID only incase AP suppresses SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto end; + } + } /* We have a profile */ + else { + sms_log(pMac, LOGW, FL("cannot find a roaming profile")); + goto end; + } +end: + if (pScanFilter) { + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + } + if (NULL != pProfile) { + csr_release_profile(pMac, pProfile); + cdf_mem_free(pProfile); + } + return status; +} + +CDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + if (csr_is_conn_state_connected(pMac, sessionId)) { + status = + csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_join_last_profile(pMac, sessionId); + } + } + return status; +} + +CDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + sms_log(pMac, LOGW, FL("is called")); + csr_roam_cancel_roaming(pMac, sessionId); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + if (csr_is_conn_state_disconnected(pMac, sessionId)) { + status = csr_roam_join_last_profile(pMac, sessionId); + } + return status; +} + +CDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool fComplete = false; + eCsrRoamSubState NewSubstate; + uint32_t sessionId = pCommand->sessionId; + + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + sms_log(pMac, LOG1, + FL(" Stop Wait for key timer and change substate to" + " eCSR_ROAM_SUBSTATE_NONE")); + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, sessionId); + } + /* change state to 'Roaming'... */ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* If we are in an IBSS, then stop the IBSS... */ + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + fComplete = (!CDF_IS_STATUS_SUCCESS(status)); + } else if (csr_is_conn_state_infra(pMac, sessionId)) { + /* + * in Infrastructure, we need to disassociate from the + * Infrastructure network... + */ + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + if (eCsrSmeIssuedDisassocForHandoff == + pCommand->u.roamCmd.roamReason) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF; + } else + if ((eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason) + && (eSIR_MAC_DISASSOC_LEAVING_BSS_REASON == + pCommand->u.roamCmd.reason)) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("set to substate eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT")); + } + if (fDisassoc) { + status = + csr_roam_issue_disassociate(pMac, sessionId, + NewSubstate, fMICFailure); + } else { + status = + csr_roam_issue_deauth(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + } + fComplete = (!CDF_IS_STATUS_SUCCESS(status)); + } else if (csr_is_conn_state_wds(pMac, sessionId)) { + if (CSR_IS_WDS_AP + (&pMac->roam.roamSession[sessionId].connectedProfile)) { + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + fComplete = (!CDF_IS_STATUS_SUCCESS(status)); + } + /* This has to be WDS station */ + else if (csr_is_conn_state_connected_wds(pMac, sessionId)) { + /* This has to be WDS station */ + pCommand->u.roamCmd.fStopWds = true; + if (fDisassoc) { + status = + csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + fMICFailure); + fComplete = (!CDF_IS_STATUS_SUCCESS(status)); + } + } + } else { + /* we got a dis-assoc request while not connected to any peer */ + /* just complete the command */ + fComplete = true; + status = CDF_STATUS_E_FAILURE; + } + if (fComplete) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + + if (CDF_IS_STATUS_SUCCESS(status)) { + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* Set the state to disconnect here */ + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + } else { + sms_log(pMac, LOGW, FL(" failed with status %d"), status); + } + return status; +} + +/** + * csr_prepare_disconnect_command() - function to prepare disconnect command + * @mac: pointer to global mac structure + * @session_id: sme session index + * @sme_cmd: pointer to sme command being prepared + * + * Function to prepare internal sme disconnect command + * Return: CDF_STATUS_SUCCESS on success else CDF_STATUS_E_RESOURCES on failure + */ + +CDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd) +{ + tSmeCmd *command; + + command = csr_get_command_buffer(mac); + if (!command) { + sms_log(mac, LOGE, FL("fail to get command buffer")); + return CDF_STATUS_E_RESOURCES; + } + + command->command = eSmeCommandRoam; + command->sessionId = (uint8_t)session_id; + command->u.roamCmd.roamReason = eCsrForcedDisassoc; + + *sme_cmd = command; + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + bool fHighPriority = false; + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + break; + } + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + sms_log(pMac, LOG1, + FL("Disassociate reason: %d, sessionId: %d"), + reason, sessionId); + switch (reason) { + case eCSR_DISCONNECT_REASON_MIC_ERROR: + pCommand->u.roamCmd.roamReason = + eCsrForcedDisassocMICFailure; + break; + case eCSR_DISCONNECT_REASON_DEAUTH: + pCommand->u.roamCmd.roamReason = eCsrForcedDeauth; + break; + case eCSR_DISCONNECT_REASON_HANDOFF: + fHighPriority = true; + pCommand->u.roamCmd.roamReason = + eCsrSmeIssuedDisassocForHandoff; + break; + case eCSR_DISCONNECT_REASON_UNSPECIFIED: + case eCSR_DISCONNECT_REASON_DISASSOC: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + break; + case eCSR_DISCONNECT_REASON_IBSS_JOIN_FAILURE: + pCommand->u.roamCmd.roamReason = + eCsrSmeIssuedIbssJoinFailure; + break; + case eCSR_DISCONNECT_REASON_IBSS_LEAVE: + pCommand->u.roamCmd.roamReason = eCsrForcedIbssLeave; + break; + case eCSR_DISCONNECT_REASON_STA_HAS_LEFT: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + pCommand->u.roamCmd.reason = + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL + ("SME convert to internal reason code eCsrStaHasLeft")); + break; + default: + break; + } + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + return status; +} + +CDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL != pCommand) { + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrStopBss; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } else { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = CDF_STATUS_E_RESOURCES; + } + return status; +} + +CDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_BTAMP_UT_RF + /* Stop the retry */ + pSession->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(pMac, sessionId); +#endif + /* Not to call cancel roaming here */ + /* Only issue disconnect when necessary */ + if (csr_is_conn_state_connected(pMac, sessionId) + || csr_is_bss_type_ibss(pSession->connectedProfile.BSSType) + || csr_is_bss_type_wds(pSession->connectedProfile.BSSType) + || csr_is_roam_command_waiting_for_session(pMac, sessionId)) { + sms_log(pMac, LOG2, FL("called")); + status = csr_roam_issue_disassociate_cmd(pMac, sessionId, + reason); + } else { + csr_scan_abort_scan_for_ssid(pMac, sessionId); + status = CDF_STATUS_CMD_NOT_QUEUED; + sms_log(pMac, LOG1, + FL + (" Disconnect cmd not queued, Roam command is not present" + " return with status %d"), status); + } + return status; +} + +CDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + csr_roam_cancel_roaming(pMac, sessionId); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, + eCsrForcedDisassoc); + + return csr_roam_disconnect_internal(pMac, sessionId, reason); +} + +CDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pIesTemp = pIes; + uint8_t index; + tCsrRoamSession *pSession = NULL; + tCsrRoamConnectedProfile *pConnectProfile = NULL; + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + pConnectProfile = &pSession->connectedProfile; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("csr_roam_save_connected_infomation")); + } +#endif + if (pConnectProfile->pAddIEAssoc) { + cdf_mem_free(pConnectProfile->pAddIEAssoc); + pConnectProfile->pAddIEAssoc = NULL; + } + cdf_mem_set(&pSession->connectedProfile, + sizeof(tCsrRoamConnectedProfile), 0); + pConnectProfile->AuthType = pProfile->negotiatedAuthType; + pConnectProfile->AuthInfo = pProfile->AuthType; + pConnectProfile->CBMode = pProfile->CBMode; /* *** this may not be valid */ + pConnectProfile->EncryptionType = pProfile->negotiatedUCEncryptionType; + pConnectProfile->EncryptionInfo = pProfile->EncryptionType; + pConnectProfile->mcEncryptionType = + pProfile->negotiatedMCEncryptionType; + pConnectProfile->mcEncryptionInfo = pProfile->mcEncryptionType; + pConnectProfile->BSSType = pProfile->BSSType; + pConnectProfile->modifyProfileFields.uapsd_mask = pProfile->uapsd_mask; + pConnectProfile->operationChannel = pSirBssDesc->channelId; + pConnectProfile->beaconInterval = pSirBssDesc->beaconInterval; + if (!pConnectProfile->beaconInterval) { + sms_log(pMac, LOGW, FL("ERROR: Beacon interval is ZERO")); + } + cdf_mem_copy(&pConnectProfile->Keys, &pProfile->Keys, sizeof(tCsrKeys)); + /* saving the addional IE`s like Hot spot indication element and extended capabilities */ + if (pProfile->nAddIEAssocLength) { + pConnectProfile->pAddIEAssoc = + cdf_mem_malloc(pProfile->nAddIEAssocLength); + if (NULL == pConnectProfile->pAddIEAssoc) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("Failed to allocate memory for additional IEs")); + return CDF_STATUS_E_FAILURE; + } + pConnectProfile->nAddIEAssocLength = + pProfile->nAddIEAssocLength; + cdf_mem_copy(pConnectProfile->pAddIEAssoc, + pProfile->pAddIEAssoc, + pProfile->nAddIEAssocLength); + } +#ifdef WLAN_FEATURE_11W + pConnectProfile->MFPEnabled = pProfile->MFPEnabled; + pConnectProfile->MFPRequired = pProfile->MFPRequired; + pConnectProfile->MFPCapable = pProfile->MFPCapable; +#endif + /* Save bssid */ + csr_get_bss_id_bss_desc(pMac, pSirBssDesc, &pConnectProfile->bssid); +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSirBssDesc->mdiePresent) { + pConnectProfile->MDID.mdiePresent = 1; + pConnectProfile->MDID.mobilityDomain = + (pSirBssDesc->mdie[1] << 8) | (pSirBssDesc->mdie[0]); + } +#endif + if (NULL == pIesTemp) { + status = + csr_get_parsed_bss_description_ies(pMac, pSirBssDesc, + &pIesTemp); + } +#ifdef FEATURE_WLAN_ESE + if ((csr_is_profile_ese(pProfile) || + (CDF_IS_STATUS_SUCCESS(status) && (pIesTemp->ESEVersion.present) + && (pProfile->negotiatedAuthType == eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (pMac->roam.configParam.isEseIniFeatureEnabled)) { + pConnectProfile->isESEAssoc = 1; + } +#endif + /* save ssid */ + if (CDF_IS_STATUS_SUCCESS(status)) { + if (pIesTemp->SSID.present) { + pConnectProfile->SSID.length = pIesTemp->SSID.num_ssid; + cdf_mem_copy(pConnectProfile->SSID.ssId, + pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid); + } + /* Save the bss desc */ + status = + csr_roam_save_connected_bss_desc(pMac, sessionId, pSirBssDesc); + + if (CSR_IS_QOS_BSS(pIesTemp) || pIesTemp->HTCaps.present) { + /* Some HT AP's dont send WMM IE so in that case we assume all HT Ap's are Qos Enabled AP's */ + pConnectProfile->qap = true; + } else { + pConnectProfile->qap = false; + } + + if (pIesTemp->ExtCap.present) { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + pIesTemp->ExtCap.bytes; + pConnectProfile->proxyARPService = p_ext_cap-> + proxy_arp_service; + } + + if (NULL == pIes) { + /* Free memory if it allocated locally */ + cdf_mem_free(pIesTemp); + } + } + /* Save Qos connection */ + pConnectProfile->qosConnection = + pMac->roam.roamSession[sessionId].fWMMConnection; + + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_free_connect_bss_desc(pMac, sessionId); + } + for (index = 0; index < pProfile->SSIDs.numOfSSIDs; index++) { + if ((pProfile->SSIDs.SSIDList[index].SSID.length == + pConnectProfile->SSID.length) + && cdf_mem_compare(pProfile->SSIDs.SSIDList[index].SSID. + ssId, pConnectProfile->SSID.ssId, + pConnectProfile->SSID.length)) { + pConnectProfile->handoffPermitted = + pProfile->SSIDs.SSIDList[index].handoffPermitted; + break; + } + pConnectProfile->handoffPermitted = false; + } + + return status; +} + + +static bool is_disconnect_pending(tpAniSirGlobal pmac, + uint8_t sessionid) +{ + tListElem *entry = NULL; + tListElem *next_entry = NULL; + tSmeCmd *command = NULL; + bool disconnect_cmd_exist = false; + + csr_ll_lock(&pmac->sme.smeCmdPendingList); + entry = csr_ll_peek_head(&pmac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK); + while (entry) { + next_entry = csr_ll_next(&pmac->sme.smeCmdPendingList, + entry, LL_ACCESS_NOLOCK); + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (command && CSR_IS_DISCONNECT_COMMAND(command) && + command->sessionId == sessionid){ + disconnect_cmd_exist = true; + break; + } + entry = next_entry; + } + csr_ll_unlock(&pmac->sme.smeCmdPendingList); + return disconnect_cmd_exist; +} + +static void csr_roam_join_rsp_processor(tpAniSirGlobal pMac, + tSirSmeJoinRsp *pSmeJoinRsp) +{ + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tCsrRoamSession *session_ptr; + + if (pSmeJoinRsp) { + session_ptr = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Sme Join Response is NULL")); + return; + } + if (!session_ptr) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), pSmeJoinRsp->sessionId); + return; + } + /* The head of the active list is the request we sent */ + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + if (pCommand + && eCsrSmeIssuedAssocToSimilarAP == + pCommand->u.roamCmd.roamReason) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); +#endif + } + /* * + * The join bssid count can be reset as soon as + * we are done with the join requests and returning + * the response to upper layers + * */ + session_ptr->join_bssid_count = 0; + csr_roam_complete(pMac, eCsrJoinSuccess, (void *)pSmeJoinRsp); + } else { + uint32_t roamId = 0; + bool is_dis_pending; + + /* The head of the active list is the request we sent */ + /* Try to get back the same profile and roam again */ + if (pCommand) { + roamId = pCommand->u.roamCmd.roamId; + } + session_ptr->joinFailStatusCode.statusCode = + pSmeJoinRsp->statusCode; + session_ptr->joinFailStatusCode.reasonCode = + pSmeJoinRsp->protStatusCode; + sms_log(pMac, LOGW, + "SmeJoinReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + /* If Join fails while Handoff is in progress, indicate disassociated event to supplicant to reconnect */ + if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) { + csr_roam_call_callback(pMac, pSmeJoinRsp->sessionId, NULL, + roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); + /* Should indicate neighbor roam algorithm about the connect failure here */ + csr_neighbor_roam_indicate_connect(pMac, + pSmeJoinRsp->sessionId, + CDF_STATUS_E_FAILURE); + } +#endif + /* + * if userspace has issued disconnection, + * driver should not continue connecting + */ + is_dis_pending = is_disconnect_pending(pMac, session_ptr->sessionId); + if (pCommand && (session_ptr->join_bssid_count < + CSR_MAX_BSSID_COUNT) && !is_dis_pending) { + if (CSR_IS_WDS_STA(&pCommand->u.roamCmd.roamProfile)) { + pCommand->u.roamCmd.fStopWds = true; + session_ptr->connectedProfile.BSSType = + eCSR_BSS_TYPE_WDS_STA; + csr_roam_reissue_roam_command(pMac); + } else if (CSR_IS_WDS(&pCommand->u.roamCmd.roamProfile)) { + session_ptr->join_bssid_count = 0; + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else { + csr_roam(pMac, pCommand); + } + } else { + /* **************************************************** + * When the upper layers issue a connect command, there + * is a roam command with reason eCsrHddIssued that + * gets enqueued and an associated timer for the SME + * command timeout is started which is currently 120 + * seconds. This command would be dequeued only upon + * succesfull connections. In case of join failures, if + * there are too many BSS in the cache, and if we fail + * Join requests with all of them, there is a chance of + * timing out the above timer. + * ***************************************************/ + if (session_ptr->join_bssid_count >= + CSR_MAX_BSSID_COUNT) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Excessive Join Req Failures")); + + if (is_dis_pending) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("disconnect is pending, complete roam")); + + session_ptr->join_bssid_count = 0; + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + } /*else: ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode ) */ +} + +CDF_STATUS csr_roam_issue_join(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRoamProfile *pProfile, + uint32_t roamId) +{ + CDF_STATUS status; + sms_log(pMac, LOG1, "Attempting to Join Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSirBssDesc->bssId)); + + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId); + /* attempt to Join this BSS... */ + status = + csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, pIes, + eWNI_SME_JOIN_REQ); + return status; +} + +static CDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, + tCsrRoamProfile *pProfile) +{ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_REASSOC_REQ, sessionId); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL(" calling csr_send_join_req_msg (eWNI_SME_REASSOC_REQ)")); + /* attempt to Join this BSS... */ + return csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, pIes, + eWNI_SME_REASSOC_REQ); +} + +void csr_roam_reissue_roam_command(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + tCsrRoamInfo roamInfo; + uint32_t sessionId; + tCsrRoamSession *pSession; + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (NULL == pEntry) { + sms_log(pMac, LOGE, + FL("Disassoc rsp can't continue, no active CMD")); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRoam != pCommand->command) { + sms_log(pMac, LOGW, FL("Active cmd, is not a roaming CMD")); + return; + } + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (!pCommand->u.roamCmd.fStopWds) { + if (pSession->bRefAssocStartCnt > 0) { + /* + * bRefAssocStartCnt was incremented in + * csr_roam_join_next_bss when the roam command issued + * previously. As part of reissuing the roam command + * again csr_roam_join_next_bss is going increment + * RefAssocStartCnt. So make sure to decrement the + * bRefAssocStartCnt + */ + pSession->bRefAssocStartCnt--; + } + if (eCsrStopRoaming == csr_roam_join_next_bss(pMac, pCommand, + true)) { + sms_log(pMac, LOGW, + FL("Failed to reissue join command")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + return; + } + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.pBssDesc = pCommand->u.roamCmd.pLastRoamBss; + roamInfo.statusCode = pSession->joinFailStatusCode.statusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + if (CSR_IS_WDS(&pSession->connectedProfile)) { + pSession->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED; + csr_roam_call_callback(pMac, sessionId, &roamInfo, + pCommand->u.roamCmd.roamId, + eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_DISASSOCIATED); + } else if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) { + pSession->connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + csr_roam_call_callback(pMac, sessionId, &roamInfo, + pCommand->u.roamCmd.roamId, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED); + } + + if (!CDF_IS_STATUS_SUCCESS(csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ))) { + sms_log(pMac, LOGE, + FL("Failed to reissue stop_bss command for WDS")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } +} + +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + bool fRet = false; + tListElem *pEntry; + tSmeCmd *pCommand = NULL; + /* alwasy lock active list before locking pending list */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + } + } + if (false == fRet) { + csr_ll_lock(&pMac->sme.smeCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + break; + } + pEntry = + csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + } + if (false == fRet) { + csr_ll_lock(&pMac->roam.roamCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->roam.roamCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + break; + } + pEntry = + csr_ll_next(&pMac->roam.roamCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->roam.roamCmdPendingList); + } + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + return fRet; +} + +bool csr_is_roam_command_waiting(tpAniSirGlobal pMac) +{ + bool fRet = false; + uint32_t i; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + fRet = csr_is_roam_command_waiting_for_session(pMac, i); + if (CSR_IS_SESSION_VALID(pMac, i) + && (fRet)) { + break; + } + } + return fRet; +} + +bool csr_is_command_waiting(tpAniSirGlobal pMac) +{ + bool fRet = false; + /* alwasy lock active list before locking pending list */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + fRet = csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK); + if (false == fRet) { + fRet = + csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList, + LL_ACCESS_LOCK); + } + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + return fRet; +} + +bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac) +{ + bool fRet = false; + tListElem *pEntry; + tCsrCmd *pCommand; + /* alwasy lock active list before locking pending list */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tCsrCmd, Link); + if ((eCsrRoamCommandScan == pCommand->command) && + ((eCsrScanForSsid == pCommand->u.scanCmd.reason) || + (eCsrScanP2PFindPeer == pCommand->u.scanCmd.reason))) { + fRet = true; + } + } + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + return fRet; +} + +CDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand = NULL; + bool fHighPriority = true; + bool fRemoveCmd = false; + tListElem *pEntry; + /* Delete the old assoc command. All is setup for reassoc to be serialized */ + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + return CDF_STATUS_E_RESOURCES; + } + if (eSmeCommandRoam == pCommand->command) { + if (pCommand->u.roamCmd.roamReason == + eCsrSmeIssuedAssocToSimilarAP) { + fRemoveCmd = + csr_ll_remove_entry(&pMac->sme. + smeCmdActiveList, pEntry, + LL_ACCESS_LOCK); + } else { + sms_log(pMac, LOGE, + FL + (" Unexpected active roam command present ")); + } + if (fRemoveCmd == false) { + /* Implies we did not get the serialized assoc command we */ + /* were expecting */ + pCommand = NULL; + } + } + } + if (NULL == pCommand) { + sms_log(pMac, LOGE, + FL + (" fail to get command buffer as expected based on previous connect roam command")); + return CDF_STATUS_E_RESOURCES; + } + do { + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrSmeIssuedFTReassoc; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +static void +csr_roaming_state_config_cnf_processor(tpAniSirGlobal mac_ctx, + uint32_t result) +{ + tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + tCsrScanResult *scan_result = NULL; + tSirBssDescription *bss_desc = NULL; + tSmeCmd *cmd = NULL; + uint32_t session_id; + tCsrRoamSession *session; + tDot11fBeaconIEs *local_ies = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (NULL == entry) { + sms_log(mac_ctx, LOGE, FL("CFG_CNF with active list empty")); + return; + } + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + session_id = cmd->sessionId; + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return; + } + + if (CSR_IS_ROAMING(session) && session->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sms_log(mac_ctx, LOGW, FL("Roam command canceled")); + csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL); + return; + } + + /* If the roaming has stopped, not to continue the roaming command */ + if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) { + /* No need to complete roaming here as it already completes */ + sms_log(mac_ctx, LOGW, + FL("Roam cmd (reason %d) aborted(roaming completed)"), + cmd->u.roamCmd.roamReason); + csr_set_abort_roaming_command(mac_ctx, cmd); + csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL); + return; + } + + if (!IS_SIR_STATUS_SUCCESS(result)) { + /* + * In the event the configuration failed, for infra let the roam + * processor attempt to join something else... + */ + if (cmd->u.roamCmd.pRoamBssEntry + && CSR_IS_INFRASTRUCTURE(&cmd->u.roamCmd.roamProfile)) { + csr_roam(mac_ctx, cmd); + } else { + /* We need to complete the command */ + if (csr_is_bss_type_ibss + (cmd->u.roamCmd.roamProfile.BSSType)) { + csr_roam_complete(mac_ctx, eCsrStartBssFailure, + NULL); + } else { + csr_roam_complete(mac_ctx, eCsrNothingToJoin, + NULL); + } + } + return; + } + + /* we have active entry */ + sms_log(mac_ctx, LOG2, "Cfg sequence complete"); + /* + * Successfully set the configuration parameters for the new Bss. + * Attempt to join the roaming Bss + */ + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, + Link); + bss_desc = &scan_result->Result.BssDescriptor; + } + if (csr_is_bss_type_ibss(cmd->u.roamCmd.roamProfile.BSSType) + || CSR_IS_WDS(&cmd->u.roamCmd.roamProfile) + || CSR_IS_INFRA_AP(&cmd->u.roamCmd.roamProfile)) { + if (!CDF_IS_STATUS_SUCCESS(csr_roam_issue_start_bss(mac_ctx, + session_id, &session->bssParams, + &cmd->u.roamCmd.roamProfile, + bss_desc, + cmd->u.roamCmd.roamId))) { + sms_log(mac_ctx, LOGE, FL("CSR start BSS failed")); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrStartBssFailure, NULL); + } + return; + } + + if (!cmd->u.roamCmd.pRoamBssEntry) { + sms_log(mac_ctx, LOGE, FL("pRoamBssEntry is NULL")); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL); + return; + } + + if (NULL == scan_result) { + /* If we are roaming TO an Infrastructure BSS... */ + CDF_ASSERT(scan_result != NULL); + return; + } + + if (!csr_is_infra_bss_desc(bss_desc)) { + sms_log(mac_ctx, LOGW, + FL("found BSSType mismatching the one in BSS descp")); + return; + } + + local_ies = (tDot11fBeaconIEs *) scan_result->Result.pvIes; + if (!local_ies) { + status = csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &local_ies); + if (!CDF_IS_STATUS_SUCCESS(status)) + return; + } + + if (csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + if (csr_is_ssid_equal(mac_ctx, session->pConnectBssDesc, + bss_desc, local_ies)) { + cmd->u.roamCmd.fReassoc = true; + csr_roam_issue_reassociate(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile); + } else { + /* + * otherwise, we have to issue a new Join request to LIM + * because we disassociated from the previously + * associated AP. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + } else { + status = CDF_STATUS_SUCCESS; + /* + * We need to come with other way to figure out that this is + * because of HO in BMP The below API will be only available for + * Android as it uses a different HO algorithm. Reassoc request + * will be used only for ESE and 11r handoff whereas other + * legacy roaming should use join request + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is11r_assoc(mac_ctx, session_id)) { + status = csr_roam_issue_reassociate(mac_ctx, + session_id, bss_desc, + (tDot11fBeaconIEs *) + (scan_result->Result.pvIes), + &cmd->u.roamCmd.roamProfile); + } else +#endif +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_ese_assoc(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else +#endif +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else +#endif + { + /* + * else we are not connected and attempting to Join. Issue the + * Join request. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, + (tDot11fBeaconIEs *) + (scan_result->Result.pvIes), + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + } + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + if (!scan_result->Result.pvIes) { + /* Locally allocated */ + cdf_mem_free(local_ies); + } +} + +static void csr_roam_roaming_state_reassoc_rsp_processor(tpAniSirGlobal pMac, + tpSirSmeJoinRsp pSmeJoinRsp) +{ + eCsrRoamCompleteResult result; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pSmeJoinRsp->sessionId]; + tCsrRoamInfo roamInfo; + uint32_t roamId = 0; + + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("CSR SmeReassocReq Successful")); + result = eCsrReassocSuccess; + /* Defeaturize this part later if needed */ +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + /* Since the neighbor roam algorithm uses reassoc req for handoff instead of join, + * we need the response contents while processing the result in csr_roam_process_results() */ + if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) { + /* Need to dig more on indicating events to SME QoS module */ + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); + csr_roam_complete(pMac, result, pSmeJoinRsp); + } else +#endif + { + csr_roam_complete(pMac, result, NULL); + } + } + /* Should we handle this similar to handling the join failure? Is it ok + * to call csr_roam_complete() with state as CsrJoinFailure */ + else { + sms_log(pMac, LOGW, + "CSR SmeReassocReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); + result = eCsrReassocFailure; +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \ + defined(FEATURE_WLAN_LFR) + if ((eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_FT_REASSOC_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_INVALID_PARAMETERS == + pSmeJoinRsp->statusCode)) { + /* Inform HDD to turn off FT flag in HDD */ + if (pNeighborRoamInfo) { + cdf_mem_zero(&roamInfo, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(pMac, + pSmeJoinRsp->sessionId, + &roamInfo, roamId, + eCSR_ROAM_FT_REASSOC_FAILED, + eSIR_SME_SUCCESS); + /* + * Since the above callback sends a disconnect + * to HDD, we should clean-up our state + * machine as well to be in sync with the upper + * layers. There is no need to send a disassoc + * since: 1) we will never reassoc to the current + * AP in LFR, and 2) there is no need to issue a + * disassoc to the AP with which we were trying + * to reassoc. + */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + return; + } + } +#endif + /* In the event that the Reassociation fails, then we need to Disassociate the current association and keep */ + /* roaming. Note that we will attempt to Join the AP instead of a Reassoc since we may have attempted a */ + /* 'Reassoc to self', which AP's that don't support Reassoc will force a Disassoc. */ + /* The disassoc rsp message will remove the command from active list */ + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate + (pMac, pSmeJoinRsp->sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false))) { + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + } + } +} + +static void csr_roam_roaming_state_stop_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeRsp *pSmeRsp) +{ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_RSP; + if (eSIR_SME_SUCCESS != pSmeRsp->statusCode) { + pIbssLog->status = WLAN_IBSS_STATUS_FAILURE; + } + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + pMac->roam.roamSession[pSmeRsp->sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, pSmeRsp->sessionId)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else + if (CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE + (pMac, pSmeRsp->sessionId)) { + csr_roam_reissue_roam_command(pMac); + } +} + +/** + * csr_dequeue_command() - removes a command from active cmd list + * @pMac: mac global context + * + * Return: void + */ +static void +csr_dequeue_command(tpAniSirGlobal mac_ctx) +{ + bool fRemoveCmd; + tSmeCmd *cmd = NULL; + tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, FL("NO commands are active")); + return; + } + + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* + * If the head of the queue is Active and it is a given cmd type, remove + * and put this on the Free queue. + */ + if (eSmeCommandRoam != cmd->command) { + sms_log(mac_ctx, LOGE, FL("Roam command not active")); + return; + } + /* + * we need to process the result first before removing it from active + * list because state changes still happening insides + * roamQProcessRoamResults so no other roam command should be issued. + */ + fRemoveCmd = csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (cmd->u.roamCmd.fReleaseProfile) { + csr_release_profile(mac_ctx, &cmd->u.roamCmd.roamProfile); + cmd->u.roamCmd.fReleaseProfile = false; + } + if (fRemoveCmd) + csr_release_command_roam(mac_ctx, cmd); + else + sms_log(mac_ctx, LOGE, FL("fail to remove cmd reason %d"), + cmd->u.roamCmd.roamReason); +} + +/** + * csr_post_roam_failure() - post roam failure back to csr and issues a disassoc + * @pMac: mac global context + * @session_id: session id + * @roam_info: roam info struct + * @scan_filter: scan filter to free + * @cur_roam_profile: current csr roam profile + * + * Return: void + */ +static void +csr_post_roam_failure(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamInfo *roam_info, + tCsrScanResultFilter *scan_filter, + tCsrRoamProfile *cur_roam_profile) +{ + CDF_STATUS status; + + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + cdf_mem_free(scan_filter); + } + if (cur_roam_profile) + cdf_mem_free(cur_roam_profile); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + csr_roam_synch_clean_up(mac_ctx, session_id); +#endif + /* Inform the upper layers that the reassoc failed */ + cdf_mem_zero(roam_info, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + eCSR_ROAM_FT_REASSOC_FAILED, eSIR_SME_SUCCESS); + /* + * Issue a disassoc request so that PE/LIM uses this to clean-up the FT + * session. Upon success, we would re-enter this routine after receiving + * the disassoc response and will fall into the reassoc fail sub-state. + * And, eventually call csr_roam_complete which would remove the roam + * command from SME active queue. + */ + status = csr_roam_issue_disassociate(mac_ctx, session_id, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("csr_roam_issue_disassociate failed, status %d"), + status); + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL); + } +} + +/** + * csr_check_profile_in_scan_cache() - finds if roam profile is present in scan + * cache or not + * @pMac: mac global context + * @scan_filter: out param, scan filter + * @neighbor_roam_info: roam info struct + * @hBSSList: scan result + * + * Return: true if found else false. + */ +static bool +csr_check_profile_in_scan_cache(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter **scan_filter, + tpCsrNeighborRoamControlInfo neighbor_roam_info, + tScanResultHandle *hBSSList) +{ + CDF_STATUS status; + *scan_filter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == *scan_filter) { + sms_log(mac_ctx, LOGE, FL("alloc for ScanFilter failed.")); + return false; + } + cdf_mem_set(*scan_filter, sizeof(tCsrScanResultFilter), 0); + (*scan_filter)->scan_filter_for_roam = 1; + status = csr_roam_prepare_filter_from_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile, + *scan_filter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("failed to prepare scan filter, status %d"), + status); + return false; + } + status = csr_scan_get_result(mac_ctx, *scan_filter, hBSSList); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("csr_scan_get_result failed, status %d"), + status); + return false; + } + return true; +} + +void csr_roam_roaming_state_disassoc_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDisassocRsp *pSmeRsp) +{ +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + tScanResultHandle hBSSList; + tCsrRoamInfo roamInfo; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId = 0; + tCsrRoamProfile *pCurRoamProfile = NULL; +#endif + CDF_STATUS status; + uint32_t sessionId; + tCsrRoamSession *pSession; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tSirSmeDisassocRsp SmeDisassocRsp; + + csr_ser_des_unpack_diassoc_rsp((uint8_t *) pSmeRsp, &SmeDisassocRsp); + sessionId = SmeDisassocRsp.sessionId; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, FL("sessionId %d"), + sessionId); + + if (csr_is_conn_state_infra(pMac, sessionId)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId)) { + sms_log(pMac, LOG2, "***eCsrNothingToJoin***"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) || + CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId)) { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + sms_log(pMac, LOG2, + FL("CSR force disassociated successful")); + /* + * A callback to HDD will be issued from + * csr_roam_complete so no need to do anything here + */ + } + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("CSR SmeDisassocReq due to HO on session %d"), + sessionId); + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + /* + * First ensure if the roam profile is in the scan cache. + * If not, post a reassoc failure and disconnect. + */ + if (!csr_check_profile_in_scan_cache(pMac, &pScanFilter, + pNeighborRoamInfo, &hBSSList)) + goto POST_ROAM_FAILURE; + + /* + * After ensuring that the roam profile is in the scan result + * list, dequeue the command from the active list. + */ + csr_dequeue_command(pMac); + + /* notify HDD about handoff and provide the BSSID too */ + roamInfo.reasonCode = eCsrRoamReasonBetterAP; + + cdf_copy_macaddr(&roamInfo.bssid, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs.bssid); + + csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + + /* + * Copy the connected profile to apply the same for this + * connection as well + */ + pCurRoamProfile = cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (pCurRoamProfile != NULL) { + /* + * notify sub-modules like QoS etc. that handoff + * happening + */ + sme_qos_csr_event_ind(pMac, sessionId, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + NULL); + cdf_mem_set(pCurRoamProfile, sizeof(tCsrRoamProfile), + 0); + csr_roam_copy_profile(pMac, pCurRoamProfile, + pSession->pCurRoamProfile); + /* make sure to put it at the head of the cmd queue */ + status = csr_roam_issue_connect(pMac, sessionId, + pCurRoamProfile, hBSSList, + eCsrSmeIssuedAssocToSimilarAP, + roamId, true, false); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("issue_connect failed. status %d"), + status); + + csr_release_profile(pMac, pCurRoamProfile); + cdf_mem_free(pCurRoamProfile); + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return; + } + +POST_ROAM_FAILURE: + csr_post_roam_failure(pMac, sessionId, &roamInfo, + pScanFilter, pCurRoamProfile); +#endif + } /* else if ( CSR_IS_ROAM_SUBSTATE_DISASSOC_HO( pMac ) ) */ + else if (CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId)) { + /* Disassoc due to Reassoc failure falls into this codepath */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + } else { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + /* + * Successfully disassociated from the 'old' Bss. + * We get Disassociate response in three conditions. + * 1) The case where we are disasociating from an Infra + * Bss to start an IBSS. + * 2) When we are disassociating from an Infra Bss to + * join an IBSS or a new infra network. + * 3) Where we are doing an Infra to Infra roam between + * networks with different SSIDs. + * In all cases, we set the new Bss configuration here + * and attempt to join + */ + sms_log(pMac, LOG2, + FL("Disassociated successfully")); + } else { + sms_log(pMac, LOGE, + FL("DisassocReq failed, statusCode= 0x%08X"), + SmeDisassocRsp.statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac); + } +} + +static void csr_roam_roaming_state_deauth_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDeauthRsp *pSmeRsp) +{ + tSirResultCodes statusCode; + /* No one is sending eWNI_SME_DEAUTH_REQ to PE. */ + sms_log(pMac, LOGW, FL("is no-op")); + statusCode = csr_get_de_auth_rsp_status_code(pSmeRsp); + pMac->roam.deauthRspStatus = statusCode; + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else { + if (eSIR_SME_SUCCESS == statusCode) { + /* Successfully deauth from the 'old' Bss... */ + /* */ + sms_log(pMac, LOG2, + "CSR SmeDeauthReq disassociated Successfully"); + } else { + sms_log(pMac, LOGW, + "SmeDeauthReq failed with statusCode= 0x%08X", + statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac); + } +} + +static void csr_roam_roaming_state_start_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeStartBssRsp * + pSmeStartBssRsp) +{ + eCsrRoamCompleteResult result; + + if (eSIR_SME_SUCCESS == pSmeStartBssRsp->statusCode) { + sms_log(pMac, LOGW, "SmeStartBssReq Successful"); + result = eCsrStartBssSuccess; + } else { + sms_log(pMac, LOGW, + "SmeStartBssReq failed with statusCode= 0x%08X", + pSmeStartBssRsp->statusCode); + /* Let csr_roam_complete decide what to do */ + result = eCsrStartBssFailure; + } + csr_roam_complete(pMac, result, pSmeStartBssRsp); +} + +/** + * csr_roaming_state_msg_processor() - process roaming messages + * @pMac: mac global context + * @pMsgBuf: message buffer + * + * We need to be careful on whether to cast pMsgBuf (pSmeRsp) to other type of + * strucutres. It depends on how the message is constructed. If the message is + * sent by lim_send_sme_rsp, the pMsgBuf is only a generic response and can only + * be used as pointer to tSirSmeRsp. For the messages where sender allocates + * memory for specific structures, then it can be cast accordingly. + * + * Return: status of operation + */ +void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSmeRsp; + tSmeIbssPeerInd *pIbssPeerInd; + tCsrRoamInfo roamInfo; + pSmeRsp = (tSirSmeRsp *) pMsgBuf; + sms_log(pMac, LOG2, FL("Message %d[0x%04X] received in substate %s"), + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + pSmeRsp->messageType = pSmeRsp->messageType; + pSmeRsp->length = pSmeRsp->length; + pSmeRsp->statusCode = pSmeRsp->statusCode; + + switch (pSmeRsp->messageType) { + + case eWNI_SME_JOIN_RSP: + /* in Roaming state, process the Join response message... */ + if (CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, pSmeRsp->sessionId)) + /* We sent a JOIN_REQ */ + csr_roam_join_rsp_processor(pMac, + (tSirSmeJoinRsp *) pSmeRsp); + break; + case eWNI_SME_REASSOC_RSP: + /* or the Reassociation response message... */ + if (CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, pSmeRsp->sessionId)) + csr_roam_roaming_state_reassoc_rsp_processor(pMac, + (tpSirSmeJoinRsp) pSmeRsp); + break; + case eWNI_SME_STOP_BSS_RSP: + /* or the Stop Bss response message... */ + csr_roam_roaming_state_stop_bss_rsp_processor(pMac, pSmeRsp); + break; + case eWNI_SME_DISASSOC_RSP: + /* or the Disassociate response message... */ + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, + pSmeRsp->sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("eWNI_SME_DISASSOC_RSP subState = %s"), + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + csr_roam_roaming_state_disassoc_rsp_processor(pMac, + (tSirSmeDisassocRsp *) pSmeRsp); + } + break; + case eWNI_SME_DEAUTH_RSP: + /* or the Deauthentication response message... */ + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) + csr_roam_roaming_state_deauth_rsp_processor(pMac, + (tSirSmeDeauthRsp *) pSmeRsp); + break; + case eWNI_SME_START_BSS_RSP: + /* or the Start BSS response message... */ + if (CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, + pSmeRsp->sessionId)) + csr_roam_roaming_state_start_bss_rsp_processor(pMac, + (tSirSmeStartBssRsp *) pSmeRsp); + break; + /* In case CSR issues STOP_BSS, we need to tell HDD about peer departed + * becasue PE is removing them + */ + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + pIbssPeerInd = (tSmeIbssPeerInd *) pSmeRsp; + sms_log(pMac, LOGE, + FL("Peer departed ntf from LIM in joining state")); + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.staId = (uint8_t) pIbssPeerInd->staId; + roamInfo.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roamInfo.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + cdf_mem_copy(&roamInfo.peerMac, pIbssPeerInd->peerAddr, + sizeof(struct cdf_mac_addr)); + csr_roam_call_callback(pMac, pSmeRsp->sessionId, &roamInfo, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + break; + case eWNI_SME_GET_RSSI_REQ: + { + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsgBuf; + if (NULL != pGetRssiReq->rssiCallback) + ((tCsrRssiCallback) pGetRssiReq->rssiCallback) + (pGetRssiReq->lastRSSI, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sms_log(pMac, LOGE, + FL("pGetRssiReq->rssiCallback is NULL")); + } + break; + default: + sms_log(pMac, LOG1, + FL("Unexpected message type = %d[0x%X] received in substate %s"), + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + /* If we are connected, check the link status change */ + if (!csr_is_conn_state_disconnected(pMac, pSmeRsp->sessionId)) + csr_roam_check_for_link_status_change(pMac, pSmeRsp); + break; + } +} + +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSirMsg = (tSirSmeRsp *) pMsgBuf; + switch (pSirMsg->messageType) { + case eWNI_SME_GET_STATISTICS_RSP: + sms_log(pMac, LOG2, FL("Stats rsp from PE")); + csr_roam_stats_rsp_processor(pMac, pSirMsg); + break; + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + { + tCsrRoamSession *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + tCsrRoamInfo roamInfo; + tCsrRoamInfo *pRoamInfo = NULL; + uint32_t sessionId; + CDF_STATUS status; + sms_log(pMac, LOG1, + FL + ("ASSOCIATION confirmation can be given to upper layer ")); + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + pUpperLayerAssocCnf = + (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf; + status = + csr_roam_get_session_id_from_bssid(pMac, + (struct cdf_mac_addr *) + pUpperLayerAssocCnf-> + bssId, &sessionId); + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, + FL(" session %d not found "), + sessionId); + return; + } + + pRoamInfo->statusCode = eSIR_SME_SUCCESS; /* send the status code as Success */ + pRoamInfo->u.pConnectedProfile = + &pSession->connectedProfile; + pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid; + pRoamInfo->rsnIELen = + (uint8_t) pUpperLayerAssocCnf->rsnIE.length; + pRoamInfo->prsnIE = + pUpperLayerAssocCnf->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + pRoamInfo->wapiIELen = + (uint8_t) pUpperLayerAssocCnf->wapiIE.length; + pRoamInfo->pwapiIE = + pUpperLayerAssocCnf->wapiIE.wapiIEdata; +#endif + pRoamInfo->addIELen = + (uint8_t) pUpperLayerAssocCnf->addIE.length; + pRoamInfo->paddIE = + pUpperLayerAssocCnf->addIE.addIEdata; + cdf_mem_copy(pRoamInfo->peerMac.bytes, + pUpperLayerAssocCnf->peerMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&pRoamInfo->bssid, + pUpperLayerAssocCnf->bssId, + sizeof(struct cdf_mac_addr)); + pRoamInfo->wmmEnabledSta = + pUpperLayerAssocCnf->wmmEnabledSta; + pRoamInfo->timingMeasCap = + pUpperLayerAssocCnf->timingMeasCap; + cdf_mem_copy(&pRoamInfo->chan_info, + &pUpperLayerAssocCnf->chan_info, + sizeof(tSirSmeChanInfo)); + if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + pRoamInfo->fReassocReq = + pUpperLayerAssocCnf->reassocReq; + status = + csr_roam_call_callback(pMac, sessionId, + pRoamInfo, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + if (CSR_IS_WDS_AP(pRoamInfo->u.pConnectedProfile)) { + cdf_sleep(100); + pMac->roam.roamSession[sessionId].connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED; /* Sta */ + status = csr_roam_call_callback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_WDS_IND, eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND); /* Sta */ + } + + } + break; + default: + csr_roam_check_for_link_status_change(pMac, pSirMsg); + break; + } +} + +CDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tAniEdType edType; + + if (eCSR_ENCRYPT_TYPE_UNKNOWN == EncryptType) { + EncryptType = eCSR_ENCRYPT_TYPE_NONE; + } + + edType = csr_translate_encrypt_type_to_ed_type(EncryptType); + + /* + * Allow 0 keys to be set for the non-WPA encrypt types. For WPA encrypt + * types, the num keys must be non-zero or LIM will reject the set + * context (assumes the SET_CONTEXT does not occur until the keys are + * distrubuted). + */ + if (CSR_IS_ENC_TYPE_STATIC(EncryptType) || addKey) { + tCsrRoamSetKey setKey; + setKey.encType = EncryptType; + setKey.keyDirection = aniKeyDirection; + cdf_mem_copy(&setKey.peerMac, bssId, sizeof(struct cdf_mac_addr)); + /* 0 for supplicant */ + setKey.paeRole = paeRole; + /* Key index */ + setKey.keyId = keyId; + setKey.keyLength = keyLength; + if (keyLength) { + cdf_mem_copy(setKey.Key, pKey, keyLength); + } + status = csr_roam_issue_set_key_command(pMac, sessionId, + &setKey, 0); + } + return status; +} + +/** + * csr_update_key_cmd() - update key info in set key command + * @mac_ctx: mac global context + * @session: roam session + * @set_key: input set key command + * @set_key_cmd: set key command to update + * @enqueue_cmd: indicates if command need to be enqueued to sme + * + * This function will validate the key length, adjust if too long. Tt will + * update bool enqueue_cmd, to false if some error has occured key are local. + * + * Return: status of operation + */ +static CDF_STATUS +csr_update_key_cmd(tpAniSirGlobal mac_ctx, tCsrRoamSession *session, + tCsrRoamSetKey *set_key, tSmeCmd *set_key_cmd, + bool *enqueue_cmd) +{ + switch (set_key->encType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP40_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WEP40 keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + + set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP40_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WEP40_KEY_LEN); + } + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP104_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WEP104 keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + + set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP104_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WEP104_KEY_LEN); + } + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + if (set_key->keyLength < CSR_TKIP_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid TKIP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_TKIP_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_TKIP_KEY_LEN); + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_AES: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid AES/CCMP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_AES_KEY_LEN); + *enqueue_cmd = true; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + if (set_key->keyLength < CSR_WAPI_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WAPI keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_WAPI_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WAPI_KEY_LEN); + if (session->pCurRoamProfile) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WPI; + } else { + sms_log(mac_ctx, LOGW, + FL("pCurRoamProfile is NULL.")); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + *enqueue_cmd = true; + break; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_ENCRYPT_TYPE_KRK: + /* no need to enqueue KRK key request, since they are local */ + *enqueue_cmd = false; + if (set_key->keyLength < CSR_KRK_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid KRK keylength [= %d]"), + set_key->keyLength); + return CDF_STATUS_E_INVAL; + } + cdf_mem_copy(session->eseCckmInfo.krk, set_key->Key, + CSR_KRK_KEY_LEN); + session->eseCckmInfo.reassoc_req_num = 1; + session->eseCckmInfo.krk_plumbed = true; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eCSR_ENCRYPT_TYPE_BTK: + /* no need to enqueue KRK key request, since they are local */ + *enqueue_cmd = false; + if (set_key->keyLength < SIR_BTK_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("LFR3:Invalid BTK keylength [= %d]"), + set_key->keyLength); + return CDF_STATUS_E_INVAL; + } + cdf_mem_copy(session->eseCckmInfo.btk, set_key->Key, + SIR_BTK_KEY_LEN); + break; +#endif +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + /* Check for 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid AES/CCMP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return CDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN; + cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_AES_KEY_LEN); + *enqueue_cmd = true; + break; +#endif /* WLAN_FEATURE_11W */ + default: + /* for open security also we want to enqueue command */ + *enqueue_cmd = true; + return CDF_STATUS_SUCCESS; + } /* end of switch */ + return CDF_STATUS_SUCCESS; +} + + +static CDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamSetKey *pSetKey, + uint32_t roamId) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + bool enqueue_cmd = true; + tSmeCmd *pCommand = NULL; +#if defined(FEATURE_WLAN_ESE) || defined (FEATURE_WLAN_WAPI) + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } +#endif /* FEATURE_WLAN_ESE */ + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + return CDF_STATUS_E_RESOURCES; + } + cdf_mem_zero(pCommand, sizeof(tSmeCmd)); + pCommand->command = eSmeCommandSetKey; + pCommand->sessionId = (uint8_t) sessionId; + /* + * following function will validate the key length, Adjust if too long. + * for static WEP the keys are not set thru' SetContextReq + * + * it will update bool enqueue_cmd, to false if some error has occured + * key are local. enqueue sme command only if enqueue_cmd is true + * status is indication of success or failure and will be returned to + * called of current function if command is not enqueued due to key req + * being local + */ + status = csr_update_key_cmd(pMac, pSession, pSetKey, + pCommand, &enqueue_cmd); + if (enqueue_cmd) { + pCommand->u.setKeyCmd.roamId = roamId; + pCommand->u.setKeyCmd.encType = pSetKey->encType; + pCommand->u.setKeyCmd.keyDirection = pSetKey->keyDirection; + cdf_mem_copy(&pCommand->u.setKeyCmd.peerMac, &pSetKey->peerMac, + sizeof(struct cdf_mac_addr)); + /* 0 for supplicant */ + pCommand->u.setKeyCmd.paeRole = pSetKey->paeRole; + pCommand->u.setKeyCmd.keyId = pSetKey->keyId; + cdf_mem_copy(pCommand->u.setKeyCmd.keyRsc, pSetKey->keyRsc, + CSR_MAX_RSC_LEN); + /* + * Always put set key to the head of the Q because it is the + * only thing to get executed in case of WT_KEY state + */ + + status = csr_queue_sme_command(pMac, pCommand, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to send message status = %d"), status); + /* update to false so that command can be freed */ + enqueue_cmd = false; + } + } + + /* + * Free the command if enqueue_cmd == false: + * this means that command was not enqueued because either there has + * been a failure, or it is a "local" operation like the set ESE CCKM + * KRK key. + */ + if (false == enqueue_cmd) + csr_release_command_set_key(pMac, pCommand); + + return status; +} + +CDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status; + uint8_t numKeys = (pCommand->u.setKeyCmd.keyLength) ? 1 : 0; + tAniEdType edType = + csr_translate_encrypt_type_to_ed_type(pCommand->u.setKeyCmd.encType); + bool fUnicast = + (pCommand->u.setKeyCmd.peerMac[0] == 0xFF) ? false : true; + uint32_t sessionId = pCommand->sessionId; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (eSIR_ED_NONE != edType) { + cdf_mem_set(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type), 0); + if (*((uint8_t *) &pCommand->u.setKeyCmd.peerMac) & 0x01) { + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_REQ; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type(pCommand->u. + setKeyCmd.encType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type(pSession-> + connectedProfile. + EncryptionType); + } else { + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_REQ; + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type(pCommand->u. + setKeyCmd.encType); + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type(pSession-> + connectedProfile. + mcEncryptionType); + } + cdf_mem_copy(setKeyEvent.bssid, + pSession->connectedProfile.bssid.bytes, + CDF_MAC_ADDR_SIZE); + if (CSR_IS_ENC_TYPE_STATIC(pCommand->u.setKeyCmd.encType)) { + uint32_t defKeyId; + /* It has to be static WEP here */ + if (IS_SIR_STATUS_SUCCESS + (wlan_cfg_get_int + (pMac, WNI_CFG_WEP_DEFAULT_KEYID, &defKeyId))) { + setKeyEvent.keyId = (uint8_t) defKeyId; + } + } else { + setKeyEvent.keyId = pCommand->u.setKeyCmd.keyId; + } + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type(pSession-> + connectedProfile. + AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (csr_is_set_key_allowed(pMac, sessionId)) { + status = csr_send_mb_set_context_req_msg(pMac, sessionId, + (uint8_t *) &pCommand->u. + setKeyCmd.peerMac, numKeys, + edType, fUnicast, + pCommand->u.setKeyCmd. + keyDirection, + pCommand->u.setKeyCmd.keyId, + pCommand->u.setKeyCmd. + keyLength, + pCommand->u.setKeyCmd.Key, + pCommand->u.setKeyCmd. + paeRole, + pCommand->u.setKeyCmd. + keyRsc); + } else { + sms_log(pMac, LOGW, FL(" cannot process not connected")); + /* Set this status so the error handling take care of the case. */ + status = CDF_STATUS_CSR_WRONG_STATE; + } + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL(" error status %d"), status); + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.setKeyCmd.roamId, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_FAILURE); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + if (eSIR_ED_NONE != edType) { + if (*((uint8_t *) &pCommand->u.setKeyCmd.peerMac) & + 0x01) { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_GTK_RSP; + } else { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_PTK_RSP; + } + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, + EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + } + return status; +} + +CDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId) +{ + CDF_STATUS status; + + if (!csr_is_set_key_allowed(pMac, sessionId)) { + status = CDF_STATUS_CSR_WRONG_STATE; + } else { + status = + csr_roam_issue_set_key_command(pMac, sessionId, pSetKey, roamId); + } + return status; +} + +/* + Prepare a filter base on a profile for parsing the scan results. + Upon successful return, caller MUST call csr_free_scan_filter on + pScanFilter when it is done with the filter. + */ +CDF_STATUS +csr_roam_prepare_filter_from_profile(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tCsrScanResultFilter *scan_fltr) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t size = 0; + uint8_t idx = 0; + tCsrChannelInfo *fltr_ch_info = &scan_fltr->ChannelInfo; + tCsrChannelInfo *profile_ch_info = &profile->ChannelInfo; + struct roam_ext_params *roam_params; + uint8_t i; + + roam_params = &mac_ctx->roam.configParam.roam_params; + + if (profile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct cdf_mac_addr) * profile->BSSIDs.numOfBSSIDs; + scan_fltr->BSSIDs.bssid = cdf_mem_malloc(size); + if (NULL == scan_fltr->BSSIDs.bssid) { + status = CDF_STATUS_E_NOMEM; + goto free_filter; + } + scan_fltr->BSSIDs.numOfBSSIDs = profile->BSSIDs.numOfBSSIDs; + cdf_mem_copy(scan_fltr->BSSIDs.bssid, + profile->BSSIDs.bssid, size); + } + + if (profile->SSIDs.numOfSSIDs) { + if (!CSR_IS_WDS_STA(profile)) { + scan_fltr->SSIDs.numOfSSIDs = profile->SSIDs.numOfSSIDs; + } else { + /* + * For WDS station we always use idx 1 for self SSID. + * Index 0 for peer's SSID that we want to join + */ + scan_fltr->SSIDs.numOfSSIDs = 1; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("No of Allowed List:%d"), + roam_params->num_ssid_allowed_list); + if (scan_fltr->scan_filter_for_roam + && roam_params->num_ssid_allowed_list) { + scan_fltr->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + size = sizeof(tCsrSSIDInfo) * + scan_fltr->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = cdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) + status = CDF_STATUS_E_FAILURE; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + for (i = 0; + i < roam_params->num_ssid_allowed_list; + i++) { + cdf_mem_copy((void *) + scan_fltr->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + scan_fltr->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + scan_fltr->SSIDs.SSIDList[i].handoffPermitted = + 1; + scan_fltr->SSIDs.SSIDList[i].ssidHidden = 0; + } + } else { + size = sizeof(tCsrSSIDInfo) * + profile->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = cdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) { + status = CDF_STATUS_E_NOMEM; + goto free_filter; + } + cdf_mem_copy(scan_fltr->SSIDs.SSIDList, + profile->SSIDs.SSIDList, size); + } + } + + if (!profile_ch_info->ChannelList + || (profile_ch_info->ChannelList[0] == 0)) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = NULL; + } else if (profile_ch_info->numOfChannels) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = + cdf_mem_malloc(sizeof(*(fltr_ch_info->ChannelList)) * + profile_ch_info->numOfChannels); + if (NULL == fltr_ch_info->ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto free_filter; + } + + for (idx = 0; idx < profile_ch_info->numOfChannels; idx++) { + if (csr_roam_is_channel_valid(mac_ctx, + profile_ch_info->ChannelList[idx])) { + fltr_ch_info-> + ChannelList[fltr_ch_info->numOfChannels] + = profile_ch_info->ChannelList[idx]; + fltr_ch_info->numOfChannels++; + } else { + sms_log(mac_ctx, LOG1, + FL("Channel (%d) is invalid"), + profile_ch_info->ChannelList[idx]); + } + } + } else { + sms_log(mac_ctx, LOGE, FL("Channel list empty")); + status = CDF_STATUS_E_FAILURE; + goto free_filter; + } + scan_fltr->uapsd_mask = profile->uapsd_mask; + scan_fltr->authType = profile->AuthType; + scan_fltr->EncryptionType = profile->EncryptionType; + scan_fltr->mcEncryptionType = profile->mcEncryptionType; + scan_fltr->BSSType = profile->BSSType; + scan_fltr->phyMode = profile->phyMode; +#ifdef FEATURE_WLAN_WAPI + /* + * check if user asked for WAPI with 11n or auto mode, in that + * case modify the phymode to 11g + */ + if (csr_is_profile_wapi(profile)) { + if (scan_fltr->phyMode & eCSR_DOT11_MODE_11n) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_11n; + if (scan_fltr->phyMode & eCSR_DOT11_MODE_AUTO) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_AUTO; + if (!scan_fltr->phyMode) + scan_fltr->phyMode = eCSR_DOT11_MODE_11g; + } +#endif /* FEATURE_WLAN_WAPI */ + /*Save the WPS info */ + scan_fltr->bWPSAssociation = profile->bWPSAssociation; + scan_fltr->bOSENAssociation = profile->bOSENAssociation; + if (profile->countryCode[0]) { + /* + * This causes the matching function to use countryCode as one + * of the criteria. + */ + cdf_mem_copy(scan_fltr->countryCode, profile->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (profile->MDID.mdiePresent) { + scan_fltr->MDID.mdiePresent = 1; + scan_fltr->MDID.mobilityDomain = profile->MDID.mobilityDomain; + } +#endif + +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + scan_fltr->MFPEnabled = profile->MFPEnabled; + scan_fltr->MFPRequired = profile->MFPRequired; + scan_fltr->MFPCapable = profile->MFPCapable; +#endif + scan_fltr->csrPersona = profile->csrPersona; + +free_filter: + if (!CDF_IS_STATUS_SUCCESS(status)) + csr_free_scan_filter(mac_ctx, scan_fltr); + + return status; +} + +bool csr_roam_issue_wm_status_change(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamWmStatusChangeTypes Type, + tSirSmeRsp *pSmeRsp) +{ + bool fCommandQueued = false; + tSmeCmd *pCommand; + do { + /* Validate the type is ok... */ + if ((eCsrDisassociated != Type) + && (eCsrDeauthenticated != Type)) + break; + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + break; + } + /* Change the substate in case it is waiting for key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandWmStatusChange; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.wmStatusChangeCmd.Type = Type; + if (eCsrDisassociated == Type) { + cdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg)); + } else { + cdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg)); + } + if (CDF_IS_STATUS_SUCCESS + (csr_queue_sme_command(pMac, pCommand, true))) { + fCommandQueued = true; + } else { + sms_log(pMac, LOGE, FL(" fail to send message ")); + csr_release_command_wm_status_change(pMac, pCommand); + } + + /* AP has issued Dissac/Deauth, Set the operating mode value to configured value */ + csr_set_default_dot11_mode(pMac); + } while (0); + return fCommandQueued; +} + +static CDF_STATUS csr_send_snr_request(void *pGetRssiReq) +{ + void *wma_handle; + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma_handle) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + + if (CDF_STATUS_SUCCESS != + wma_send_snr_request(wma_handle, pGetRssiReq)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to Trigger wma stats request"); + return CDF_STATUS_E_FAILURE; + } + + /* dont send success, otherwise call back + * will released with out values */ + return CDF_STATUS_E_BUSY; +} + +static void csr_update_rssi(tpAniSirGlobal pMac, void *pMsg) +{ + int8_t rssi = 0; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsg; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + if (pGetRssiReq) { + if (NULL != pGetRssiReq->p_cds_context) { + cdf_status = csr_send_snr_request(pGetRssiReq); + } else { + sms_log(pMac, LOGE, + FL("pGetRssiReq->p_cds_context is NULL")); + return; + } + + if (NULL != pGetRssiReq->rssiCallback) { + if (cdf_status != CDF_STATUS_E_BUSY) + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback)) + (rssi, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sms_log(pMac, LOG1, + FL + ("rssi request is posted. waiting for reply")); + } else { + sms_log(pMac, LOGE, + FL("pGetRssiReq->rssiCallback is NULL")); + return; + } + } else { + sms_log(pMac, LOGE, FL("pGetRssiReq is NULL")); + } + return; + +} + +static void csr_update_snr(tpAniSirGlobal pMac, void *pMsg) +{ + tAniGetSnrReq *pGetSnrReq = (tAniGetSnrReq *) pMsg; + + if (pGetSnrReq) { + if (CDF_STATUS_SUCCESS != wma_get_snr(pGetSnrReq)) { + sms_log(pMac, LOGE, FL("Error in wma_get_snr")); + return; + } + + } else { + sms_log(pMac, LOGE, FL("pGetSnrReq is NULL")); + } + return; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +void csr_tsm_stats_rsp_processor(tpAniSirGlobal pMac, void *pMsg) +{ + tAniGetTsmStatsRsp *pTsmStatsRsp = (tAniGetTsmStatsRsp *) pMsg; + + if (NULL != pTsmStatsRsp) { + /* Get roam Rssi request is backed up and passed back to the response, + Extract the request message to fetch callback */ + tpAniGetTsmStatsReq reqBkp + = (tAniGetTsmStatsReq *) pTsmStatsRsp->tsmStatsReq; + + if (NULL != reqBkp) { + if (NULL != reqBkp->tsmStatsCallback) { + ((tCsrTsmStatsCallback) + (reqBkp->tsmStatsCallback))(pTsmStatsRsp-> + tsmMetrics, + pTsmStatsRsp-> + staId, + reqBkp-> + pDevContext); + reqBkp->tsmStatsCallback = NULL; + } + cdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } else { + sms_log(pMac, LOGE, FL("reqBkp is NULL")); + if (NULL != reqBkp) { + cdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } + } + } else { + sms_log(pMac, LOGE, FL("pTsmStatsRsp is NULL")); + } + return; +} + +void csr_send_ese_adjacent_ap_rep_ind(tpAniSirGlobal pMac, tCsrRoamSession *pSession) +{ + uint32_t roamTS2 = 0; + tCsrRoamInfo roamInfo; + tpPESession pSessionEntry = NULL; + uint8_t sessionId = CSR_SESSION_ID_INVALID; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + roamTS2 = cdf_mc_timer_get_system_time(); + roamInfo.tsmRoamDelay = roamTS2 - pSession->roamTS1; + sms_log(pMac, LOG1, "Bssid(" MAC_ADDRESS_STR ") Roaming Delay(%u ms)", + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes), + roamInfo.tsmRoamDelay); + + pSessionEntry = pe_find_session_by_bssid(pMac, + pSession->connectedProfile.bssid.bytes, + &sessionId); + if (NULL == pSessionEntry) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + pSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly + = roamInfo.tsmRoamDelay; + + csr_roam_call_callback(pMac, pSession->sessionId, &roamInfo, + 0, eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, 0); +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +CDF_STATUS csr_send_reset_ap_caps_changed(tpAniSirGlobal pMac, tSirMacAddr *bssId) +{ + tpSirResetAPCapsChange pMsg; + uint16_t len; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* Create the message and send to lim */ + len = sizeof(tSirResetAPCapsChange); + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(pMsg, sizeof(tSirResetAPCapsChange), 0); + pMsg->messageType = eWNI_SME_RESET_AP_CAPS_CHANGED; + pMsg->length = len; + cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr)); + sms_log(pMac, LOG1, + FL("CSR reset caps change for Bssid= " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMsg->bssId)); + status = cds_send_mb_message_to_mac(pMsg); + } else { + sms_log(pMac, LOGE, FL("Memory allocation failed\n")); + } + return status; +} + +static void +csr_roam_chk_lnk_assoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeAssocInd *pAssocInd; + tCsrRoamInfo roam_info; + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + + sms_log(mac_ctx, LOG1, FL("Receive WNI_SME_ASSOC_IND from SME")); + pAssocInd = (tSirSmeAssocInd *) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *) pAssocInd->bssId, &sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOG1, + FL("Couldn't find session_id for given BSSID")); + return; + } + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + roam_info_ptr = &roam_info; + /* Required for indicating the frames to upper layer */ + roam_info_ptr->assocReqLength = pAssocInd->assocReqLength; + roam_info_ptr->assocReqPtr = pAssocInd->assocReqPtr; + roam_info_ptr->beaconPtr = pAssocInd->beaconPtr; + roam_info_ptr->beaconLength = pAssocInd->beaconLength; + roam_info_ptr->statusCode = eSIR_SME_SUCCESS; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + roam_info_ptr->staId = (uint8_t) pAssocInd->staId; + roam_info_ptr->rsnIELen = (uint8_t) pAssocInd->rsnIE.length; + roam_info_ptr->prsnIE = pAssocInd->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + roam_info_ptr->wapiIELen = (uint8_t) pAssocInd->wapiIE.length; + roam_info_ptr->pwapiIE = pAssocInd->wapiIE.wapiIEdata; +#endif + roam_info_ptr->addIELen = (uint8_t) pAssocInd->addIE.length; + roam_info_ptr->paddIE = pAssocInd->addIE.addIEdata; + cdf_mem_copy(roam_info_ptr->peerMac.bytes, + pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(roam_info_ptr->bssid.bytes, + pAssocInd->bssId, + sizeof(struct cdf_mac_addr)); + roam_info_ptr->wmmEnabledSta = pAssocInd->wmmEnabledSta; + roam_info_ptr->timingMeasCap = pAssocInd->timingMeasCap; + cdf_mem_copy(&roam_info_ptr->chan_info, + &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + if (CSR_IS_WDS_AP(roam_info_ptr->u.pConnectedProfile)) + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND); + if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)) { + if (session->pCurRoamProfile && + CSR_IS_ENC_TYPE_STATIC( + session->pCurRoamProfile->negotiatedUCEncryptionType)) { + /* NO keys... these key parameters don't matter. */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->pCurRoamProfile->negotiatedUCEncryptionType, + session->pConnectBssDesc, + &(roam_info_ptr->peerMac.bytes), + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + roam_info_ptr->fAuthRequired = false; + } else { + roam_info_ptr->fAuthRequired = true; + } + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + if (!CDF_IS_STATUS_SUCCESS(status)) + /* Refused due to Mac filtering */ + roam_info_ptr->statusCode = eSIR_SME_ASSOC_REFUSED; + } + + /* Send Association completion message to PE */ + status = csr_send_assoc_cnf_msg(mac_ctx, pAssocInd, status); + /* + * send a message to CSR itself just to avoid the EAPOL frames going + * OTA before association response + */ + if (CSR_IS_WDS_AP(roam_info_ptr->u.pConnectedProfile)) { + status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx, + pAssocInd, status, sessionId); + } else if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile) + && (roam_info_ptr->statusCode != eSIR_SME_ASSOC_REFUSED)) { + roam_info_ptr->fReassocReq = pAssocInd->reassocReq; + status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx, + pAssocInd, status, sessionId); + } +} + +static void +csr_roam_chk_lnk_disassoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeDisassocInd *pDisassocInd; + tSmeCmd cmd; + tCsrRoamInfo roam_info; + + /* + * Check if AP dis-associated us because of MIC failure. If so, + * then we need to take action immediately and not wait till the + * the WmStatusChange requests is pushed and processed + */ + pDisassocInd = (tSirSmeDisassocInd *) msg_ptr; + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *) pDisassocInd->bssId, &sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Session Id not found for BSSID " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pDisassocInd->bssId)); + return; + } + + sms_log(mac_ctx, LOGE, + FL("DISASSOCIATION Indication from MAC for session %d "), + sessionId); + sms_log(mac_ctx, LOGE, + FL("DISASSOCIATION from peer =" MAC_ADDRESS_STR + " " " reason = %d status = %d "), + MAC_ADDR_ARRAY(pDisassocInd->peerMacAddr), + pDisassocInd->reasonCode, + pDisassocInd->statusCode); + /* + * If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDisassociated, msg_ptr); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->statusCode = pDisassocInd->statusCode; + roam_info_ptr->reasonCode = pDisassocInd->reasonCode; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + roam_info_ptr->staId = (uint8_t) pDisassocInd->staId; + cdf_mem_copy(roam_info_ptr->peerMac.bytes, + pDisassocInd->peerMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&roam_info_ptr->bssid.bytes, + pDisassocInd->bssId, + sizeof(struct cdf_mac_addr)); + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_DISASSOC_IND); + /* + * STA/P2P client got disassociated so remove any pending + * deauth commands in sme pending list + */ + cmd.command = eSmeCommandRoam; + cmd.sessionId = (uint8_t) sessionId; + cmd.u.roamCmd.roamReason = eCsrForcedDeauthSta; + cdf_mem_copy(cmd.u.roamCmd.peerMac, + pDisassocInd->peerMacAddr, + sizeof(tSirMacAddr)); + csr_roam_remove_duplicate_command(mac_ctx, sessionId, &cmd, + eCsrForcedDeauthSta); + } +} + +static void +csr_roam_chk_lnk_deauth_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeDeauthInd *pDeauthInd; + tCsrRoamInfo roam_info; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOG1, FL("DEAUTHENTICATION Indication from MAC")); + pDeauthInd = (tpSirSmeDeauthInd) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *) pDeauthInd-> + bssId, &sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) + return; + /* If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDeauthenticated, + msg_ptr); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->statusCode = pDeauthInd->statusCode; + roam_info_ptr->reasonCode = pDeauthInd->reasonCode; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + roam_info_ptr->staId = (uint8_t) pDeauthInd->staId; + cdf_mem_copy(roam_info_ptr->peerMac.bytes, + pDeauthInd->peerMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&roam_info_ptr->bssid.bytes, + pDeauthInd->bssId, + sizeof(struct cdf_mac_addr)); + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_DEAUTH_IND); + } +} + +static void +csr_roam_chk_lnk_swt_ch_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tpSirSmeSwitchChannelInd pSwitchChnInd; + + /* in case of STA, the SWITCH_CHANNEL originates from its AP */ + sms_log(mac_ctx, LOGW, FL("eWNI_SME_SWITCH_CHL_IND from SME")); + pSwitchChnInd = (tpSirSmeSwitchChannelInd) msg_ptr; + /* Update with the new channel id. The channel id is hidden in the + * statusCode. + */ + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *) pSwitchChnInd->bssId, &sessionId); + if (CDF_IS_STATUS_SUCCESS(status)) { + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("session %d not found"), sessionId); + return; + } + session->connectedProfile.operationChannel = + (uint8_t) pSwitchChnInd->newChannelId; + if (session->pConnectBssDesc) { + session->pConnectBssDesc->channelId = + (uint8_t) pSwitchChnInd->newChannelId; + } + } +} + +static void +csr_roam_chk_lnk_deauth_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeDeauthRsp *pDeauthRsp = (tSirSmeDeauthRsp *) msg_ptr; + tCsrRoamInfo roam_info; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOGW, FL("eWNI_SME_DEAUTH_RSP from SME")); + sessionId = pDeauthRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + cdf_mem_copy(roam_info_ptr->peerMac.bytes, + pDeauthRsp->peerMacAddr, + sizeof(tSirMacAddr)); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDeauthRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +static void +csr_roam_chk_lnk_disassoc_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tCsrRoamInfo roam_info; + /* + * session id is invalid here so cant use it to access the array + * curSubstate as index + */ + tSirSmeDisassocRsp *pDisassocRsp = (tSirSmeDisassocRsp *) msg_ptr; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOGW, FL("eWNI_SME_DISASSOC_RSP from SME ")); + sessionId = pDisassocRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + cdf_mem_copy(roam_info_ptr->peerMac.bytes, + pDisassocRsp->peerMacAddr, + sizeof(tSirMacAddr)); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDisassocRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_mic_fail(tpAniSirGlobal mac_ctx, uint32_t sessionId) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + cdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type), + 0); + secEvent.eventId = WLAN_SECURITY_EVENT_MIC_ERROR; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + secEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + cdf_mem_copy(secEvent.bssid, session->connectedProfile.bssid.bytes, + CDF_MAC_ADDR_SIZE); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_mic_fail_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tCsrRoamInfo roam_info; + tpSirSmeMicFailureInd pMicInd = (tpSirSmeMicFailureInd) msg_ptr; + eCsrRoamResult result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *) pMicInd->bssId, &sessionId); + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.u.pMICFailureInfo = &pMicInd->info; + roam_info_ptr = &roam_info; + if (pMicInd->info.multicast) + result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP; + else + result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + eCSR_ROAM_MIC_ERROR_IND, result); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_mic_fail(mac_ctx, sessionId); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ +} + +static void +csr_roam_chk_lnk_pbs_probe_req_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo roam_info; + tpSirSmeProbeReqInd pProbeReqInd = (tpSirSmeProbeReqInd) msg_ptr; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOG1, FL("WPS PBC Probe request Indication from SME")); + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *)pProbeReqInd->bssId, &sessionId); + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.u.pWPSPBCProbeReq = &pProbeReqInd->WPSPBCProbeReq; + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + 0, eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_joined_new_bss(tpAniSirGlobal mac_ctx, + tSirSmeNewBssInfo *pNewBss) +{ + host_log_ibss_pkt_type *pIbssLog; + uint32_t bi; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (!pIbssLog) + return; + pIbssLog->eventId = WLAN_IBSS_EVENT_COALESCING; + if (pNewBss) { + cdf_mem_copy(pIbssLog->bssid, pNewBss->bssId, 6); + if (pNewBss->ssId.length) + cdf_mem_copy(pIbssLog->ssid, pNewBss->ssId.ssId, + pNewBss->ssId.length); + pIbssLog->operatingChannel = pNewBss->channelNumber; + } + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for beacon interval */ + pIbssLog->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeWmStatusChangeNtf *pStatusChangeMsg; + tCsrRoamInfo roam_info; + tSirSmeApNewCaps *pApNewCaps; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirSmeNewBssInfo *pNewBss; + eRoamCmdStatus roamStatus = eCSR_ROAM_FAILED; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + pStatusChangeMsg = (tSirSmeWmStatusChangeNtf *) msg_ptr; + switch (pStatusChangeMsg->statusChangeCode) { + case eSIR_SME_IBSS_ACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + sessionId); + return; + } + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED; + if (session->pConnectBssDesc) { + cdf_mem_copy(&roam_info.bssid, + session->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + roam_info.u.pConnectedProfile = + &session->connectedProfile; + roam_info_ptr = &roam_info; + } else { + sms_log(mac_ctx, LOGE, + FL("CSR: connected BSS is empty")); + } + result = eCSR_ROAM_RESULT_IBSS_CONNECT; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + break; + + case eSIR_SME_IBSS_INACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("session %d not found"), sessionId); + return; + } + session->connectState = + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + result = eCSR_ROAM_RESULT_IBSS_INACTIVE; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + } + break; + + case eSIR_SME_JOINED_NEW_BSS: + /* IBSS coalescing. */ + sms_log(mac_ctx, LOGW, + FL("CSR: eSIR_SME_JOINED_NEW_BSS received from PE")); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + sessionId); + return; + } + /* update the connection state information */ + pNewBss = &pStatusChangeMsg->statusChangeInfo.newBssInfo; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_joined_new_bss(mac_ctx, pNewBss); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_roam_update_connected_profile_from_new_bss(mac_ctx, + sessionId, + pNewBss); + + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + csr_roam_issue_set_context_req(mac_ctx, + sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, + &Broadcastaddr, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } + result = eCSR_ROAM_RESULT_IBSS_COALESCED; + roamStatus = eCSR_ROAM_IBSS_IND; + cdf_mem_copy(&roam_info.bssid, &pNewBss->bssId, + sizeof(struct cdf_mac_addr)); + roam_info_ptr = &roam_info; + /* This BSSID is the real BSSID, save it */ + if (session->pConnectBssDesc) + cdf_mem_copy(session->pConnectBssDesc->bssId, + &pNewBss->bssId, sizeof(struct cdf_mac_addr)); + break; + + /* + * detection by LIM that the capabilities of the associated + * AP have changed. + */ + case eSIR_SME_AP_CAPS_CHANGED: + pApNewCaps = &pStatusChangeMsg->statusChangeInfo.apNewCaps; + sms_log(mac_ctx, LOGW, + FL("CSR handling eSIR_SME_AP_CAPS_CHANGED")); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct cdf_mac_addr *)pApNewCaps->bssId, &sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + if (eCSR_ROAMING_STATE_JOINED == + mac_ctx->roam.curState[sessionId] + && ((eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_NONE == + mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC == + mac_ctx->roam.curSubState[sessionId]))) { + sms_log(mac_ctx, LOGW, + FL("Calling csr_roam_disconnect_internal")); + csr_roam_disconnect_internal(mac_ctx, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } else { + sms_log(mac_ctx, LOGW, + FL("Skipping the new scan as CSR is in state %s and sub-state %s"), + mac_trace_getcsr_roam_state( + mac_ctx->roam.curState[sessionId]), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[sessionId])); + /* We ignore the caps change event if CSR is not in full + * connected state. Send one event to PE to reset + * limSentCapsChangeNtf Once limSentCapsChangeNtf set + * 0, lim can send sub sequent CAPS change event + * otherwise lim cannot send any CAPS change events to + * SME + */ + csr_send_reset_ap_caps_changed(mac_ctx, + &pApNewCaps->bssId); + } + break; + + default: + roamStatus = eCSR_ROAM_FAILED; + result = eCSR_ROAM_RESULT_NONE; + break; + } /* end switch on statusChangeCode */ + if (eCSR_ROAM_RESULT_NONE != result) { + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + roamStatus, result); + } +} + +static void +csr_roam_chk_lnk_ibss_new_peer_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSmeIbssPeerInd *pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + tCsrRoamInfo roam_info; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_JOIN; + cdf_mem_copy(pIbssLog->peerMacAddr, &pIbssPeerInd->peerAddr, 6); + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + /* + * Issue the set Context request to LIM to establish the Unicast STA + * context for the new peer... + */ + if (!session->pConnectBssDesc) { + sms_log(mac_ctx, LOGW, FL("CSR: connected BSS is empty")); + goto callback_and_free; + } + cdf_mem_copy(&roam_info.peerMac, pIbssPeerInd->peerAddr, + sizeof(struct cdf_mac_addr)); + cdf_mem_copy(&roam_info.bssid, session->pConnectBssDesc->bssId, + sizeof(struct cdf_mac_addr)); + if (pIbssPeerInd->mesgLen > sizeof(tSmeIbssPeerInd)) { + roam_info.pbFrames = cdf_mem_malloc((pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd))); + if (NULL == roam_info.pbFrames) { + status = CDF_STATUS_E_NOMEM; + } else { + status = CDF_STATUS_SUCCESS; + roam_info.nBeaconLength = pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd); + cdf_mem_copy(roam_info.pbFrames, + ((uint8_t *) pIbssPeerInd) + + sizeof(tSmeIbssPeerInd), + roam_info.nBeaconLength); + } + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + roam_info.pBssDesc = cdf_mem_malloc( + session->pConnectBssDesc->length); + if (NULL == roam_info.pBssDesc) { + status = CDF_STATUS_E_NOMEM; + if (roam_info.pbFrames) + cdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + cdf_mem_free(roam_info.pBssDesc); + } else { + status = CDF_STATUS_SUCCESS; + cdf_mem_copy(roam_info.pBssDesc, + session->pConnectBssDesc, + session->pConnectBssDesc->length); + roam_info_ptr = &roam_info; + } + } else { + roam_info_ptr = &roam_info; + } + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, &(pIbssPeerInd->peerAddr), + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + } + +callback_and_free: + /* send up the sec type for the new peer */ + if (roam_info_ptr) + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_NEW_PEER); + if (roam_info_ptr) { + if (roam_info.pbFrames) + cdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + cdf_mem_free(roam_info.pBssDesc); + } +} + +static void +csr_roam_chk_lnk_ibss_peer_departed_ind(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tCsrRoamInfo roam_info; + tSmeIbssPeerInd *pIbssPeerInd; + + if (NULL == msg_ptr) { + sms_log(mac_ctx, LOGE, FL("IBSS peer ind. message is NULL")); + return; + } + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_LEAVE; + if (pIbssPeerInd) { + cdf_mem_copy(pIbssLog->peerMacAddr, + &pIbssPeerInd->peerAddr, 6); + } + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + sms_log(mac_ctx, LOGW, + FL("CSR: Peer departed notification from LIM")); + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + cdf_mem_copy(&roam_info.peerMac, pIbssPeerInd->peerAddr, + sizeof(struct cdf_mac_addr)); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_ctx_rsp(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + tSirSmeSetContextRsp *pRsp) +{ + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + if (eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType) + return; + cdf_mem_set(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type), 0); + if (pRsp->peerMacAddr[0] & 0x01) + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_RSP; + else + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_RSP; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + cdf_mem_copy(setKeyEvent.bssid, session->connectedProfile.bssid.bytes, + CDF_MAC_ADDR_SIZE); + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + if (eSIR_SME_SUCCESS != pRsp->statusCode) + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_set_ctx_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + CDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSmeCmd *cmd; + tCsrRoamInfo roam_info; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirSmeSetContextRsp *pRsp = (tSirSmeSetContextRsp *) msg_ptr; + tListElem *entry; + tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, FL("CSR: NO commands are ACTIVE ...")); + goto process_pending_n_exit; + } + + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandSetKey != cmd->command) { + sms_log(mac_ctx, LOGE, FL("CSR: setkey cmd is not ACTIVE ...")); + goto process_pending_n_exit; + } + sessionId = cmd->sessionId; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_ctx_rsp(mac_ctx, session, pRsp); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sessionId)) { + csr_roam_stop_wait_for_key_timer(mac_ctx); + /* We are done with authentication, whethere succeed or not */ + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + /* We do it here because this linkup function is not called + * after association when a key needs to be set. + */ + if (csr_is_conn_state_connected_infra(mac_ctx, sessionId)) + csr_roam_link_up(mac_ctx, + session->connectedProfile.bssid); + } + if (eSIR_SME_SUCCESS == pRsp->statusCode) { + cdf_mem_copy(&roam_info.peerMac, &pRsp->peerMacAddr, + sizeof(struct cdf_mac_addr)); + /* Make sure we install the GTK before indicating to HDD as + * authenticated. This is to prevent broadcast packets go out + * after PTK and before GTK. + */ + if (cdf_mem_compare(&Broadcastaddr, pRsp->peerMacAddr, + sizeof(tSirMacAddr))) { + tpSirSetActiveModeSetBncFilterReq pMsg; + pMsg = cdf_mem_malloc( + sizeof(tSirSetActiveModeSetBncFilterReq)); + pMsg->messageType = eWNI_SME_SET_BCN_FILTER_REQ; + pMsg->length = sizeof(uint8_t); + pMsg->seesionId = sessionId; + status = cds_send_mb_message_to_mac(pMsg); + result = eCSR_ROAM_RESULT_AUTHENTICATED; + } else { + result = eCSR_ROAM_RESULT_NONE; + } + roam_info_ptr = &roam_info; + } else { + result = eCSR_ROAM_RESULT_FAILURE; + sms_log(mac_ctx, LOGE, + FL("CSR: setkey command failed(%d) PeerMac " + MAC_ADDRESS_STR), + pRsp->statusCode, MAC_ADDR_ARRAY(pRsp->peerMacAddr)); + } + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + cmd->u.setKeyCmd.roamId, + eCSR_ROAM_SET_KEY_COMPLETE, result); + /* Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS + * can go ahead and initiate the TSPEC if any are pending + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, NULL); +#ifdef FEATURE_WLAN_ESE + /* Send Adjacent AP repot to new AP. */ + if (result == eCSR_ROAM_RESULT_AUTHENTICATED + && session->isPrevApInfoValid + && session->connectedProfile.isESEAssoc) { +#ifdef FEATURE_WLAN_ESE_UPLOAD + csr_send_ese_adjacent_ap_rep_ind(mac_ctx, session); +#else + csr_ese_send_adjacent_ap_rep_msg(mac_ctx, session); +#endif + session->isPrevApInfoValid = false; + } +#endif + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) + csr_release_command_set_key(mac_ctx, cmd); + +process_pending_n_exit: + sme_process_pending_queue(mac_ctx); +} + + +static void +csr_roam_chk_lnk_max_assoc_exceeded(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tSmeMaxAssocInd *pSmeMaxAssocInd; + tCsrRoamInfo roam_info; + + cdf_mem_set(&roam_info, sizeof(roam_info), 0); + pSmeMaxAssocInd = (tSmeMaxAssocInd *) msg_ptr; + sms_log(mac_ctx, LOG1, + FL("max assoc have been reached, new peer cannot be accepted")); + sessionId = pSmeMaxAssocInd->sessionId; + roam_info.sessionId = sessionId; + cdf_mem_copy(&roam_info.peerMac, pSmeMaxAssocInd->peerMac, + sizeof(struct cdf_mac_addr)); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); +} + +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) +{ + if (NULL == pSirMsg) { + sms_log(pMac, LOGE, FL("pSirMsg is NULL")); + return; + } + switch (pSirMsg->messageType) { + case eWNI_SME_ASSOC_IND: + csr_roam_chk_lnk_assoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_IND: + csr_roam_chk_lnk_disassoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_IND: + csr_roam_chk_lnk_deauth_ind(pMac, pSirMsg); + break; + case eWNI_SME_SWITCH_CHL_IND: + csr_roam_chk_lnk_swt_ch_ind(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_RSP: + csr_roam_chk_lnk_deauth_rsp(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_RSP: + csr_roam_chk_lnk_disassoc_rsp(pMac, pSirMsg); + break; + case eWNI_SME_MIC_FAILURE_IND: + csr_roam_chk_lnk_mic_fail_ind(pMac, pSirMsg); + break; + case eWNI_SME_WPS_PBC_PROBE_REQ_IND: + csr_roam_chk_lnk_pbs_probe_req_ind(pMac, pSirMsg); + break; + case eWNI_SME_WM_STATUS_CHANGE_NTF: + csr_roam_chk_lnk_wm_status_change_ntf(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_NEW_PEER_IND: + csr_roam_chk_lnk_ibss_new_peer_ind(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + csr_roam_chk_lnk_ibss_peer_departed_ind(pMac, pSirMsg); + break; + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_chk_lnk_set_ctx_rsp(pMac, pSirMsg); + break; + case eWNI_SME_GET_STATISTICS_RSP: + sms_log(pMac, LOG2, FL("Stats rsp from PE")); + csr_roam_stats_rsp_processor(pMac, pSirMsg); + break; +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case eWNI_SME_GET_TSM_STATS_RSP: + sms_log(pMac, LOG2, FL("TSM Stats rsp from PE")); + csr_tsm_stats_rsp_processor(pMac, pSirMsg); + break; +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + case eWNI_SME_GET_RSSI_REQ: + sms_log(pMac, LOG2, FL("GetRssiReq from self")); + csr_update_rssi(pMac, pSirMsg); + break; + case eWNI_SME_GET_SNR_REQ: + sms_log(pMac, LOG2, FL("GetSnrReq from self")); + csr_update_snr(pMac, pSirMsg); + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eWNI_SME_FT_PRE_AUTH_RSP: + csr_roam_ft_pre_auth_rsp_processor(pMac, (tpSirFTPreAuthRsp) pSirMsg); + break; +#endif + case eWNI_SME_MAX_ASSOC_EXCEEDED: + csr_roam_chk_lnk_max_assoc_exceeded(pMac, pSirMsg); + break; + case eWNI_SME_CANDIDATE_FOUND_IND: + sms_log(pMac, LOG2, FL("Candidate found indication from PE")); + csr_neighbor_roam_candidate_found_ind_hdlr(pMac, pSirMsg); + break; + case eWNI_SME_HANDOFF_REQ: + sms_log(pMac, LOG2, FL("Handoff Req from self")); + csr_neighbor_roam_handoff_req_hdlr(pMac, pSirMsg); + break; + default: + break; + } /* end switch on message type */ +} + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + tCsrRoamSession *pSession, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eCsrRoamResult roamResult) +{ + if (pSession) { + if (pSession->bRefAssocStartCnt) { + pSession->bRefAssocStartCnt--; + + if (0 != pSession->bRefAssocStartCnt) { + CDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + /* Need to call association_completion because there is an assoc_start pending. */ + csr_roam_call_callback(pMac, pSession->sessionId, NULL, + roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } + csr_roam_call_callback(pMac, pSession->sessionId, pRoamInfo, + roamId, eCSR_ROAM_ROAMING_COMPLETION, + roamResult); + } else { + sms_log(pMac, LOGW, FL(" pSession is NULL")); + } +} + +CDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamingReason roamingReason) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + if (CSR_IS_LOSTLINK_ROAMING(roamingReason) && + (false == pMac->roam.roamSession[sessionId].fCancelRoaming)) { + status = csr_scan_request_lost_link1(pMac, sessionId); + } + return status; +} + +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult) +{ + bool fCompleted = true; + uint32_t roamTime = + (uint32_t) (pMac->roam.configParam.nRoamingTime * + CDF_TICKS_PER_SECOND); + uint32_t curTime = (uint32_t) cdf_mc_timer_get_system_ticks(); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + /* Check whether time is up */ + if (pSession->fCancelRoaming || fForce || + ((curTime - pSession->roamingStartTime) > roamTime) || + eCsrReassocRoaming == pSession->roamingReason || + eCsrDynamicRoaming == pSession->roamingReason) { + sms_log(pMac, LOGW, FL(" indicates roaming completion")); + if (pSession->fCancelRoaming + && CSR_IS_LOSTLINK_ROAMING(pSession->roamingReason)) { + /* roaming is cancelled, tell HDD to indicate disconnect */ + /* Because LIM overload deauth_ind for both deauth frame and missed beacon */ + /* we need to use this logic to detinguish it. For missed beacon, LIM set reason */ + /* to be eSIR_BEACON_MISSED */ + if (eSIR_BEACON_MISSED == pSession->roamingStatusCode) { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } else if (eCsrLostlinkRoamingDisassoc == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DISASSOC_IND; + } else if (eCsrLostlinkRoamingDeauth == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DEAUTH_IND; + } else { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } + } + csr_call_roaming_completion_callback(pMac, pSession, NULL, 0, + roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + pSession->roamResult = roamResult; + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_start_roaming_timer + (pMac, sessionId, CDF_MC_TIMER_TO_SEC_UNIT))) { + csr_call_roaming_completion_callback(pMac, pSession, NULL, + 0, roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + fCompleted = false; + } + } + return fCompleted; +} + +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (CSR_IS_ROAMING(pSession)) { + sms_log(pMac, LOGW, "Cancel roaming"); + pSession->fCancelRoaming = true; + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + /* No need to do anything in here because the handler takes care of it */ + } else { + eCsrRoamResult roamResult = + CSR_IS_LOSTLINK_ROAMING(pSession-> + roamingReason) ? + eCSR_ROAM_RESULT_LOSTLINK : eCSR_ROAM_RESULT_NONE; + /* Roaming is stopped after here */ + csr_roam_complete_roaming(pMac, sessionId, true, + roamResult); + /* Since CSR may be in lostlink roaming situation, abort all roaming related activities */ + csr_scan_abort_mac_scan(pMac, sessionId, + eCSR_SCAN_ABORT_DEFAULT); + csr_roam_stop_roaming_timer(pMac, sessionId); + } + } +} + +void csr_roam_roaming_timer_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + uint32_t sessionId = pInfo->sessionId; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (false == pSession->fCancelRoaming) { + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_start_roaming + (pMac, sessionId, pSession->roamingReason))) { + csr_call_roaming_completion_callback(pMac, pSession, NULL, + 0, + pSession->roamResult); + pSession->roamingReason = eCsrNotRoaming; + } + } +} + +CDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t interval) +{ + CDF_STATUS status; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, " csrScanStartRoamingTimer"); + pSession->roamingTimerInfo.sessionId = (uint8_t) sessionId; + status = cdf_mc_timer_start(&pSession->hTimerRoaming, + interval / CDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +CDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return cdf_mc_timer_stop + (&pMac->roam.roamSession[sessionId].hTimerRoaming); +} + +void csr_roam_wait_for_key_time_out_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pInfo->sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (pSession == NULL) { + sms_log(pMac, LOGE, "%s: session not found", __func__); + return; + } + + sms_log(pMac, LOGW, + FL("WaitForKey timer expired in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo[pInfo->sessionId]. + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pInfo->sessionId])); + + if (CSR_IS_WAIT_FOR_KEY(pMac, pInfo->sessionId)) { +#ifdef FEATURE_WLAN_LFR + if (csr_neighbor_roam_is_handoff_in_progress(pMac, pInfo->sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer expired. + */ + sms_log(pMac, LOG2, + "Enabling HB timer after WaitKey expiry" + " (nHBCount=%d)", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } +#endif + sms_log(pMac, LOGE, " SME pre-auth state timeout. "); + + /* Change the substate so command queue is unblocked. */ + if (CSR_ROAM_SESSION_MAX > pInfo->sessionId) { + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + pInfo->sessionId); + } + + if (csr_is_conn_state_connected_infra(pMac, pInfo->sessionId)) { + csr_roam_link_up(pMac, + pSession->connectedProfile.bssid); + sme_process_pending_queue(pMac); + status = sme_acquire_global_lock(&pMac->sme); + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_disconnect(pMac, pInfo->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + sme_release_global_lock(&pMac->sme); + } + } else { + sms_log(pMac, LOGE, "%s: session not found", __func__); + } + } + +} + +CDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval) +{ + CDF_STATUS status; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; +#ifdef FEATURE_WLAN_LFR + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* Disable heartbeat timer when hand-off is in progress */ + sms_log(pMac, LOG2, + FL("disabling HB timer in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pMac->roam. + WaitForKeyTimerInfo. + sessionId] + )); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, 0); + } +#endif + sms_log(pMac, LOG1, " csrScanStartWaitForKeyTimer"); + status = cdf_mc_timer_start(&pMac->roam.hTimerWaitForKey, + interval / CDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +CDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; + + sms_log(pMac, LOG2, + FL("WaitForKey timer stopped in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pMac->roam. + WaitForKeyTimerInfo. + sessionId])); +#ifdef FEATURE_WLAN_LFR + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer got stopped for some reason + */ + sms_log(pMac, LOG2, "Enabling HB timer after WaitKey stop" + " (nHBCount=%d)", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } +#endif + return cdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); +} + +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess) +{ + eRoamCmdStatus roamStatus = csr_get_roam_complete_status(pMac, sessionId); + uint32_t roamId = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pCommand) { + roamId = pCommand->u.roamCmd.roamId; + if (sessionId != pCommand->sessionId) { + CDF_ASSERT(sessionId == pCommand->sessionId); + return; + } + } + if (eCSR_ROAM_ROAMING_COMPLETION == roamStatus) { + /* if success, force roaming completion */ + csr_roam_complete_roaming(pMac, sessionId, fSuccess, roamResult); + } else { + if (pSession->bRefAssocStartCnt != 0) { + CDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + sms_log(pMac, LOGW, + FL + (" indicates association completion. roamResult = %d"), + roamResult); + csr_roam_call_callback(pMac, sessionId, pRoamInfo, roamId, + roamStatus, roamResult); + } +} + +CDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t type, tSirSmeRsp *pSirMsg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeDeauthInd *pDeauthIndMsg = NULL; + tSirSmeDisassocInd *pDisassocIndMsg = NULL; + eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK; + tCsrRoamInfo *pRoamInfo = NULL; + tCsrRoamInfo roamInfo; + bool fToRoam; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + /* Only need to roam for infra station. In this case P2P client will roam as well */ + fToRoam = CSR_IS_INFRASTRUCTURE(&pSession->connectedProfile); + pSession->fCancelRoaming = false; + if (eWNI_SME_DISASSOC_IND == type) { + result = eCSR_ROAM_RESULT_DISASSOC_IND; + pDisassocIndMsg = (tSirSmeDisassocInd *) pSirMsg; + pSession->roamingStatusCode = pDisassocIndMsg->statusCode; + pSession->joinFailStatusCode.reasonCode = + pDisassocIndMsg->reasonCode; + } else if (eWNI_SME_DEAUTH_IND == type) { + result = eCSR_ROAM_RESULT_DEAUTH_IND; + pDeauthIndMsg = (tSirSmeDeauthInd *) pSirMsg; + pSession->roamingStatusCode = pDeauthIndMsg->statusCode; + /* Convert into proper reason code */ + if ((pDeauthIndMsg->reasonCode == eSIR_BEACON_MISSED) || + (pDeauthIndMsg->reasonCode == + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON)) + pSession->joinFailStatusCode.reasonCode = 0; + else + pSession->joinFailStatusCode.reasonCode = + pDeauthIndMsg->reasonCode; + /* + * cfg layer expects 0 as reason code if + * the driver dosent know the reason code + * eSIR_BEACON_MISSED is defined as locally + */ + } else { + sms_log(pMac, LOGW, FL("gets an unknown type (%d)"), type); + result = eCSR_ROAM_RESULT_NONE; + pSession->joinFailStatusCode.reasonCode = 1; + } + + /* call profile lost link routine here */ + if (!CSR_IS_INFRA_AP(&pSession->connectedProfile)) { + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK_DETECTED, result); + /*Move the state to Idle after disconnection */ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, sessionId); + + } + + if (eWNI_SME_DISASSOC_IND == type) { + status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg); + } else if (eWNI_SME_DEAUTH_IND == type) { + status = csr_send_mb_deauth_cnf_msg(pMac, pDeauthIndMsg); + } + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* If fail to send confirmation to PE, not to trigger roaming */ + fToRoam = false; + } + /* prepare to tell HDD to disconnect */ + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.statusCode = (tSirResultCodes) pSession->roamingStatusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + if (eWNI_SME_DISASSOC_IND == type) { + /* staMacAddr */ + cdf_mem_copy(roamInfo.peerMac.bytes, + pDisassocIndMsg->peerMacAddr, + sizeof(tSirMacAddr)); + roamInfo.staId = (uint8_t) pDisassocIndMsg->staId; + roamInfo.reasonCode = pDisassocIndMsg->reasonCode; + } else if (eWNI_SME_DEAUTH_IND == type) { + /* staMacAddr */ + cdf_mem_copy(roamInfo.peerMac.bytes, + pDeauthIndMsg->peerMacAddr, + sizeof(tSirMacAddr)); + roamInfo.staId = (uint8_t) pDeauthIndMsg->staId; + roamInfo.reasonCode = pDeauthIndMsg->reasonCode; + } + sms_log(pMac, LOGW, FL("roamInfo.staId (%d)"), roamInfo.staId); + + /* See if we can possibly roam. If so, start the roaming process and notify HDD + that we are roaming. But if we cannot possibly roam, or if we are unable to + currently roam, then notify HDD of the lost link */ + if (fToRoam) { + /* Only remove the connected BSS in infrastructure mode */ + csr_roam_remove_connected_bss_from_scan_cache(pMac, + &pSession-> + connectedProfile); + /* Not to do anying for lostlink with WDS */ + status = csr_roam_start_roaming(pMac, sessionId, + (eWNI_SME_DEAUTH_IND == type) ? + eCsrLostlinkRoamingDeauth : + eCsrLostlinkRoamingDisassoc); + if (pMac->roam.configParam.nRoamingTime) { + status = csr_roam_start_roaming(pMac, sessionId, + (eWNI_SME_DEAUTH_IND == type) ? + eCsrLostlinkRoamingDeauth : + eCsrLostlinkRoamingDisassoc); + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + /* For IBSS, we need to give some more info to HDD */ + if (csr_is_bss_type_ibss + (pSession->connectedProfile.BSSType)) { + roamInfo.u.pConnectedProfile = + &pSession->connectedProfile; + roamInfo.statusCode = + (tSirResultCodes) pSession-> + roamingStatusCode; + roamInfo.reasonCode = + pSession->joinFailStatusCode. + reasonCode; + } else { + roamInfo.reasonCode = + eCsrRoamReasonSmeIssuedForLostLink; + } + pRoamInfo = &roamInfo; + pSession->roamingReason = + (eWNI_SME_DEAUTH_IND == + type) ? eCsrLostlinkRoamingDeauth : + eCsrLostlinkRoamingDisassoc; + pSession->roamingStartTime = + (uint32_t) cdf_mc_timer_get_system_ticks(); + csr_roam_call_callback(pMac, sessionId, pRoamInfo, + 0, eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_LOSTLINK); + } else { + sms_log(pMac, LOGW, + " %s Fail to start roaming, status = %d", + __func__, status); + fToRoam = false; + } + } else { + /* We are told not to roam, indicate lostlink */ + fToRoam = false; + } + } + if (!fToRoam) { + /* Tell HDD about the lost link */ + if (!CSR_IS_INFRA_AP(&pSession->connectedProfile)) { + /* Don't call csr_roam_call_callback for GO/SoftAp case as this indication + * was already given as part of eWNI_SME_DISASSOC_IND msg handling in + * csr_roam_check_for_link_status_change API. + */ + csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + eCSR_ROAM_LOSTLINK, result); + } + + } + + return status; +} + +CDF_STATUS csr_roam_lost_link_afterhandoff_failure(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + pSession->fCancelRoaming = false; + /* Only remove the connected BSS in infrastructure mode */ + csr_roam_remove_connected_bss_from_scan_cache(pMac, + &pSession->connectedProfile); + if (pMac->roam.configParam.nRoamingTime) { + status = csr_roam_start_roaming(pMac, sessionId, + pSession->roamingReason); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* + * before starting the lost link logic release + * the roam command for handoff + */ + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + if (pCommand) { + if ((eSmeCommandRoam == pCommand->command) && + (eCsrSmeIssuedAssocToSimilarAP == + pCommand->u.roamCmd.roamReason)) { + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, + pEntry, LL_ACCESS_LOCK)) { + csr_release_command_roam(pMac, + pCommand); + } + } + } + sms_log(pMac, LOGW, "Lost link roaming started ..."); + } + } else { + /* We are told not to roam, indicate lostlink */ + status = CDF_STATUS_E_FAILURE; + } + + return status; +} + +void csr_roam_wm_status_change_complete(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandWmStatusChange == pCommand->command) { + /* Nothing to process in a Lost Link completion.... It just kicks off a */ + /* roaming sequence. */ + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_wm_status_change(pMac, pCommand); + } else { + sms_log(pMac, LOGE, + " ******csr_roam_wm_status_change_complete fail to release command"); + } + + } else { + sms_log(pMac, LOGW, + "CSR: WmStatusChange Completion called but LOST LINK command is not ACTIVE ..."); + } + } else { + sms_log(pMac, LOGW, + "CSR: WmStatusChange Completion called but NO commands are ACTIVE ..."); + } + sme_process_pending_queue(pMac); +} + +void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSirSmeRsp *pSirSmeMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pCommand->sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + pCommand->sessionId); + return; + } + sms_log(pMac, LOG1, FL("session:%d, CmdType : %d"), + pCommand->sessionId, pCommand->u.wmStatusChangeCmd.Type); + + switch (pCommand->u.wmStatusChangeCmd.Type) { + case eCsrDisassociated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DISASSOC_IND, pSirSmeMsg); + break; + case eCsrDeauthenticated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DEAUTH_IND, pSirSmeMsg); + break; + default: + sms_log(pMac, LOGW, FL("gets an unknown command %d"), + pCommand->u.wmStatusChangeCmd.Type); + break; + } + /* For WDS, we want to stop BSS as well when it is indicated that it is disconnected. */ + if (CSR_IS_CONN_WDS(&pSession->connectedProfile)) { + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_issue_stop_bss_cmd(pMac, pCommand->sessionId, true))) { + /* This is not good */ + sms_log(pMac, LOGE, + FL(" failed to issue stopBSS command")); + } + } + /* Lost Link just triggers a roaming sequence. We can complte the Lost Link */ + /* command here since there is nothing else to do. */ + csr_roam_wm_status_change_complete(pMac); +} + + +/** + * csr_compute_mode_and_band() - computes dot11mode + * @pMac: mac global context + * @dot11_mode: out param, do11 mode calculated + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: void + */ +static void +csr_compute_mode_and_band(tpAniSirGlobal mac_ctx, + eCsrCfgDot11Mode *dot11_mode, + eCsrBand *band, + uint8_t opr_ch) +{ + bool vht_24_ghz = mac_ctx->roam.configParam.enableVhtFor24GHz; + switch (mac_ctx->roam.configParam.uCfgDot11Mode) { + case eCSR_CFG_DOT11_MODE_11A: + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = eCSR_BAND_5G; + break; + case eCSR_CFG_DOT11_MODE_11B: + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = eCSR_BAND_24; + break; + case eCSR_CFG_DOT11_MODE_11G: + *dot11_mode = eCSR_CFG_DOT11_MODE_11G; + *band = eCSR_BAND_24; + break; + case eCSR_CFG_DOT11_MODE_11N: + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + *band = CSR_GET_BAND(opr_ch); + break; +#ifdef WLAN_FEATURE_11AC + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = CSR_GET_BAND(opr_ch); + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = CSR_GET_BAND(opr_ch); + break; +#endif + case eCSR_CFG_DOT11_MODE_AUTO: +#ifdef WLAN_FEATURE_11AC + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, + * check for INI item to disable VHT operation + * in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) + && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } +#else + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; +#endif + *band = CSR_GET_BAND(opr_ch); + break; + default: + /* + * Global dot11 Mode setting is 11a/b/g. use the channel number + * to determine the Mode setting. + */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_ch) { + *band = mac_ctx->roam.configParam.eBand; + if (eCSR_BAND_24 == *band) { + /* + * See reason in else if ( CDS_IS_CHANNEL_24GHZ + * (opr_ch) ) to pick 11B + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } else { + /* prefer 5GHz */ + *band = eCSR_BAND_5G; + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + } else if (CDS_IS_CHANNEL_24GHZ(opr_ch)) { + /* + * WiFi tests require IBSS networks to start in 11b mode + * without any change to the default parameter settings + * on the adapter. We use ACU to start an IBSS through + * creation of a startIBSS profile. This startIBSS + * profile has Auto MACProtocol and the adapter property + * setting for dot11Mode is also AUTO. So in this case, + * let's start the IBSS network in 11b mode instead of + * 11g mode. So this is for Auto=profile->MacProtocol && + * Auto=Global. dot11Mode && profile->channel is < 14, + * then start the IBSS in b mode. + * + * Note: we used to have this start as an 11g IBSS for + * best performance. now to specify that the user will + * have to set the do11Mode in the property page to 11g + * to force it. + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = eCSR_BAND_24; + } else { + /* else, it's a 5.0GHz channel. Set mode to 11a. */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = eCSR_BAND_5G; + } + break; + } /* switch */ +} + +/** + * csr_roam_get_phy_mode_band_for_bss() - This function returns band and mode + * information. + * @mac_ctx: mac global context + * @profile: bss profile + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. The only tricky part is that if phyMode is set to 11abg, + * this function may return eCSR_CFG_DOT11_MODE_11B instead of + * eCSR_CFG_DOT11_MODE_11G if everything is set to auto-pick. + * + * Return: dot11mode + */ +static eCsrCfgDot11Mode +csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + uint8_t opr_chn, + eCsrBand *p_band) +{ + eCsrBand band; + eCsrCfgDot11Mode curr_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + eCsrCfgDot11Mode cfg_dot11_mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(profile, + (eCsrPhyMode) profile->phyMode, + mac_ctx->roam.configParam.ProprietaryRatesEnabled); + + /* + * If the global setting for dot11Mode is set to auto/abg, we overwrite + * the setting in the profile. + */ + if (((!CSR_IS_INFRA_AP(profile) && !CSR_IS_WDS(profile)) + && ((eCSR_CFG_DOT11_MODE_AUTO == curr_mode) + || (eCSR_CFG_DOT11_MODE_ABG == curr_mode))) + || (eCSR_CFG_DOT11_MODE_AUTO == cfg_dot11_mode) + || (eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode)) { + csr_compute_mode_and_band(mac_ctx, &cfg_dot11_mode, + &band, opr_chn); + } /* if( eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode ) */ + else { + /* dot11 mode is set, lets pick the band */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_chn) { + /* channel is Auto also. */ + band = mac_ctx->roam.configParam.eBand; + if (eCSR_BAND_ALL == band) { + /* prefer 5GHz */ + band = eCSR_BAND_5G; + } + } else{ + band = CSR_GET_BAND(opr_chn); + } + } + if (p_band) + *p_band = band; + + if (opr_chn == 14) { + sms_log(mac_ctx, LOGE, FL("Switching to Dot11B mode")); + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } + + /* + * Incase of WEP Security encryption type is coming as part of add key. + * So while STart BSS dont have information + */ + if ((!CSR_IS_11n_ALLOWED(profile->EncryptionType.encryptionType[0]) + || ((profile->privacy == 1) + && (profile->EncryptionType.encryptionType[0] == + eCSR_ENCRYPT_TYPE_NONE))) + && ((eCSR_CFG_DOT11_MODE_11N == cfg_dot11_mode) || +#ifdef WLAN_FEATURE_11AC + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode) +#endif + )) { + /* We cannot do 11n here */ + if (CDS_IS_CHANNEL_24GHZ(opr_chn)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G; + else + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + return cfg_dot11_mode; +} + +CDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate) +{ + CDF_STATUS status; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_REQ; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Set the roaming substate to 'stop Bss request'... */ + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + /* attempt to stop the Bss (reason code is ignored...) */ + status = csr_send_mb_stop_bss_req_msg(pMac, sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("csr_send_mb_stop_bss_req_msg failed with status %d"), + status); + } + return status; +} + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +CDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan) +{ + if (!IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac, + WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) pChannels, pNumChan))) + return CDF_STATUS_E_FAILURE; + return CDF_STATUS_SUCCESS; +} + +tPowerdBm csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + tPowerdBm maxTxPwr = 0; + uint8_t *pCountryInfo = NULL; + CDF_STATUS status; + uint8_t count = 0; + uint8_t firstChannel; + uint8_t maxChannels; + + if (CDS_IS_CHANNEL_5GHZ(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + } else if (CDS_IS_CHANNEL_24GHZ(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } else + return maxTxPwr; + + pCountryInfo = cdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (status != CDF_STATUS_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("%s: failed to allocate memory, status = %d"), + __FUNCTION__, status); + goto error; + } + if (wlan_cfg_get_str(pMac, cfgId, (uint8_t *)pCountryInfo, + &cfgLength) != eSIR_SUCCESS) { + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + cdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idxValidChannels; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (CDF_IS_STATUS_SUCCESS + (csr_get_cfg_valid_channels(pMac, pMac->roam.validChannelList, &len))) { + for (idxValidChannels = 0; (idxValidChannels < len); + idxValidChannels++) { + if (channel == + pMac->roam.validChannelList[idxValidChannels]) { + fValid = true; + break; + } + } + } + pMac->roam.numValidChannels = len; + return fValid; +} + +bool csr_roam_is_valid40_mhz_channel(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint8_t i; + for (i = 0; i < pMac->scan.base40MHzChannels.numChannels; i++) { + if (channel == pMac->scan.base40MHzChannels.channelList[i]) { + fValid = true; + break; + } + } + return fValid; +} + +/* This function check and validate whether the NIC can do CB (40MHz) */ +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t primaryChn, + tDot11fBeaconIEs *pIes) +{ + ePhyChanBondState eRet = PHY_SINGLE_CHANNEL_CENTERED; + uint8_t centerChn; + uint32_t ChannelBondingMode; + if (CDS_IS_CHANNEL_24GHZ(primaryChn)) { + /* + * gChannelBondingMode24GHz configuration item is common for + * SAP and STA mode and currently MDM does not support + * HT40 in 2.4Ghz STA mode. + * So disabling the HT40 in 2.4GHz station mode + */ +#ifdef QCA_HT_20_24G_STA_ONLY + ChannelBondingMode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; +#else + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode24GHz; +#endif + } else { + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode5GHz; + } + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == ChannelBondingMode) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* Figure what the other side's CB mode */ + if (!(pIes->HTCaps.present && (eHT_CHANNEL_WIDTH_40MHZ == + pIes->HTCaps.supportedChannelWidthSet))) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + + /* Check set as TKIP or not. */ + if (((NULL != &(pIes->RSN.pwise_cipher_suites[0][0]) && + (pIes->RSN.pwise_cipher_suite_count == 1)) && + !memcmp(&(pIes->RSN.pwise_cipher_suites[0][0]), + "\x00\x0f\xac\x02", 4)) + || (((NULL != &(pIes->WPA)) && + (pIes->WPA.unicast_cipher_count == 1)) + && ((NULL != &(pIes->WPA.unicast_ciphers[0])) + && !memcmp(&(pIes->WPA.unicast_ciphers[0]), + "\x00\x0f\xac\x02", 4)))) { + sms_log(pMac, LOGW, + " No channel bonding in TKIP mode "); + return PHY_SINGLE_CHANNEL_CENTERED; + } + + if (!pIes->HTInfo.present) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* + * This is called during INFRA STA/CLIENT and should use the merged + * value of supported channel width and recommended tx width as per + * standard + */ + sms_log(pMac, LOG1, "scws %u rtws %u sco %u", + pIes->HTCaps.supportedChannelWidthSet, + pIes->HTInfo.recommendedTxWidthSet, + pIes->HTInfo.secondaryChannelOffset); + + if (pIes->HTInfo.recommendedTxWidthSet == eHT_CHANNEL_WIDTH_40MHZ) + eRet = (ePhyChanBondState)pIes->HTInfo.secondaryChannelOffset; + else + eRet = PHY_SINGLE_CHANNEL_CENTERED; + + switch (eRet) { + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + centerChn = primaryChn + CSR_CB_CENTER_CHANNEL_OFFSET; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + centerChn = primaryChn - CSR_CB_CENTER_CHANNEL_OFFSET; + break; + case PHY_SINGLE_CHANNEL_CENTERED: + default: + centerChn = primaryChn; + break; + } + + if ((PHY_SINGLE_CHANNEL_CENTERED != eRet) + && !csr_roam_is_valid40_mhz_channel(pMac, centerChn)) { + sms_log(pMac, LOGE, + "Invalid center channel (%d), disable 40MHz mode", + centerChn); + eRet = PHY_SINGLE_CHANNEL_CENTERED; + } + return eRet; +} + +bool csr_is_encryption_in_list(tpAniSirGlobal pMac, + tCsrEncryptionList *pCipherList, + eCsrEncryptionType encryptionType) +{ + bool fFound = false; + uint32_t idx; + for (idx = 0; idx < pCipherList->numEntries; idx++) { + if (pCipherList->encryptionType[idx] == encryptionType) { + fFound = true; + break; + } + } + return fFound; +} + +bool csr_is_auth_in_list(tpAniSirGlobal pMac, tCsrAuthList *pAuthList, + eCsrAuthType authType) +{ + bool fFound = false; + uint32_t idx; + for (idx = 0; idx < pAuthList->numEntries; idx++) { + if (pAuthList->authType[idx] == authType) { + fFound = true; + break; + } + } + return fFound; +} + +bool csr_is_same_profile(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile1, + tCsrRoamProfile *pProfile2) +{ + uint32_t i; + bool fCheck = false; + tCsrScanResultFilter *pScanFilter = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (!(pProfile1 && pProfile2)) + return fCheck; + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return fCheck; + + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(pMac, pProfile2, + pScanFilter); + if (!(CDF_IS_STATUS_SUCCESS(status))) + goto free_scan_filter; + + for (i = 0; i < pScanFilter->SSIDs.numOfSSIDs; i++) { + fCheck = csr_is_ssid_match(pMac, + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + pScanFilter->SSIDs.SSIDList[i].SSID.length, + pProfile1->SSID.ssId, + pProfile1->SSID.length, + false); + if (fCheck) + break; + } + if (!fCheck) + goto free_scan_filter; + + if (!csr_is_auth_in_list(pMac, &pProfile2->AuthType, + pProfile1->AuthType) + || (pProfile2->BSSType != pProfile1->BSSType) + || !csr_is_encryption_in_list(pMac, &pProfile2->EncryptionType, + pProfile1->EncryptionType)) { + fCheck = false; + goto free_scan_filter; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pProfile1->MDID.mdiePresent || pProfile2->MDID.mdiePresent) { + if (pProfile1->MDID.mobilityDomain + != pProfile2->MDID.mobilityDomain) { + fCheck = false; + goto free_scan_filter; + } + } +#endif + /* Match found */ + fCheck = true; +free_scan_filter: + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return fCheck; +} + +bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + tCsrRoamProfile *pProfile2) +{ + bool fCheck = false; + int i; + do { + /* Only check for static WEP */ + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) + && !csr_is_encryption_in_list(pMac, + &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { + fCheck = true; + break; + } + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + pConnProfile->EncryptionType)) + break; + if (pConnProfile->Keys.defaultIndex != + pProfile2->Keys.defaultIndex) + break; + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (pConnProfile->Keys.KeyLength[i] != + pProfile2->Keys.KeyLength[i]) + break; + if (!cdf_mem_compare(&pConnProfile->Keys.KeyMaterial[i], + &pProfile2->Keys.KeyMaterial[i], + pProfile2->Keys.KeyLength[i])) { + break; + } + } + if (i == CSR_MAX_NUM_KEY) { + fCheck = true; + } + } while (0); + return fCheck; +} + +/* IBSS */ + +uint8_t csr_roam_get_ibss_start_channel_number50(tpAniSirGlobal pMac) +{ + uint8_t channel = 0; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel5G) { + channel = pMac->roam.configParam.AdHocChannel5G; + if (!csr_roam_is_channel_valid(pMac, channel)) { + channel = 0; + } + } + if (0 == channel + && + CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels + (pMac, + (uint8_t *) pMac->roam.validChannelList, + &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_50) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels50[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = csr_start_ibss_channels50[idx]; + } + } + } + /* + * this is rare, but if it does happen, + * we find anyone in 11a bandwidth and + * return the first 11a channel found! + */ + if (!fFound) { + for (idxValidChannels = 0; idxValidChannels < len; + idxValidChannels++) { + if (CDS_IS_CHANNEL_5GHZ(pMac->roam. + validChannelList[idxValidChannels])) { + /* the max channel# in 11g is 14 */ + if (idxValidChannels < + CSR_NUM_IBSS_START_CHANNELS_50) { + channel = + pMac->roam.validChannelList + [idxValidChannels]; + } + break; + } + } + } + } /* if */ + + return channel; +} + +uint8_t csr_roam_get_ibss_start_channel_number24(tpAniSirGlobal pMac) +{ + uint8_t channel = 1; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel24) { + channel = pMac->roam.configParam.AdHocChannel24; + if (!csr_roam_is_channel_valid(pMac, channel)) { + channel = 0; + } + } + + if (0 == channel + && + CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels + (pMac, + (uint8_t *) pMac->roam.validChannelList, + &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_24) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels24[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = csr_start_ibss_channels24[idx]; + } + } + } + } + + return channel; +} + +/** + * csr_populate_basic_rates() - populates OFDM or CCK rates + * @rates: rate struct to populate + * @type: true: ofdm rates, false: cck rates + * @masked: indicates if rates are to be masked with + * CSR_DOT11_BASIC_RATE_MASK + * + * This function will populate OFDM or CCK rates + * + * Return: void + */ +static void +csr_populate_basic_rates(tSirMacRateSet *rate_set, bool type, bool masked) +{ + uint8_t ofdm_rates[8] = { + SIR_MAC_RATE_6, + SIR_MAC_RATE_9, + SIR_MAC_RATE_12, + SIR_MAC_RATE_18, + SIR_MAC_RATE_24, + SIR_MAC_RATE_36, + SIR_MAC_RATE_48, + SIR_MAC_RATE_54 + }; + uint8_t cck_rates[4] = { + SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11 + }; + + if (type == true) { + rate_set->numRates = 8; + cdf_mem_copy(rate_set->rate, ofdm_rates, sizeof(ofdm_rates)); + if (masked) { + rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[4] |= CSR_DOT11_BASIC_RATE_MASK; + } + } else { + rate_set->numRates = 4; + cdf_mem_copy(rate_set->rate, cck_rates, sizeof(cck_rates)); + if (masked) { + rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[1] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[3] |= CSR_DOT11_BASIC_RATE_MASK; + } + } +} + +/** + * csr_convert_mode_to_nw_type() - convert mode into network type + * @dot11_mode: dot11_mode + * @band: 2.4 or 5 GHz + * + * Return: tSirNwType + */ +static tSirNwType +csr_convert_mode_to_nw_type(eCsrCfgDot11Mode dot11_mode, eCsrBand band) +{ + switch (dot11_mode) { + case eCSR_CFG_DOT11_MODE_11G: + return eSIR_11G_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11B: + return eSIR_11B_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11A: + return eSIR_11A_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11N: + default: + /* + * Because LIM only verifies it against 11a, 11b or 11g, set + * only 11g or 11a here + */ + if (eCSR_BAND_24 == band) + return eSIR_11G_NW_TYPE; + else + return eSIR_11A_NW_TYPE; + } + return eSIR_DONOT_USE_NW_TYPE; +} + +/** + * csr_roam_get_bss_start_parms() - get bss start param from profile + * @pMac: mac global context + * @pProfile: roam profile + * @pParam: out param, start bss params + * + * This function populates start bss param from roam profile + * + * Return: void + */ +static void +csr_roam_get_bss_start_parms(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tCsrRoamStartBssParams *pParam) +{ + eCsrBand band; + uint8_t opr_ch = 0; + tSirNwType nw_type; + uint8_t tmp_opr_ch = 0; + tSirMacRateSet *opr_rates = &pParam->operationalRateSet; + tSirMacRateSet *ext_rates = &pParam->extendedRateSet; + + if (pProfile->ChannelInfo.numOfChannels + && pProfile->ChannelInfo.ChannelList) { + tmp_opr_ch = pProfile->ChannelInfo.ChannelList[0]; + } + + pParam->uCfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac, + pProfile, tmp_opr_ch, &band); + + if (((pProfile->csrPersona == CDF_P2P_CLIENT_MODE) + || (pProfile->csrPersona == CDF_P2P_GO_MODE)) + && (pParam->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11B)) { + /* This should never happen */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + FL("For P2P (persona %d) dot11_mode is 11B"), + pProfile->csrPersona); + CDF_ASSERT(0); + } + + nw_type = csr_convert_mode_to_nw_type(pParam->uCfgDot11Mode, band); + ext_rates->numRates = 0; + + switch (nw_type) { + default: + sms_log(pMac, LOGE, FL("sees an unknown pSirNwType (%d)"), + nw_type); + case eSIR_11A_NW_TYPE: + csr_populate_basic_rates(opr_rates, true, true); + if (eCSR_OPERATING_CHANNEL_ANY != tmp_opr_ch) { + opr_ch = tmp_opr_ch; + break; + } + opr_ch = csr_roam_get_ibss_start_channel_number50(pMac); + if (0 == opr_ch && + CSR_IS_PHY_MODE_DUAL_BAND(pProfile->phyMode) && + CSR_IS_PHY_MODE_DUAL_BAND(pMac->roam.configParam.phyMode)) { + /* + * We could not find a 5G channel by auto pick, let's + * try 2.4G channels. We only do this here because + * csr_roam_get_phy_mode_band_for_bss always picks 11a + * for AUTO + */ + nw_type = eSIR_11B_NW_TYPE; + opr_ch = csr_roam_get_ibss_start_channel_number24(pMac); + csr_populate_basic_rates(opr_rates, false, true); + } + break; + case eSIR_11B_NW_TYPE: + csr_populate_basic_rates(opr_rates, false, true); + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + case eSIR_11G_NW_TYPE: + /* For P2P Client and P2P GO, disable 11b rates */ + if ((pProfile->csrPersona == CDF_P2P_CLIENT_MODE) + || (pProfile->csrPersona == CDF_P2P_GO_MODE) + || (eCSR_CFG_DOT11_MODE_11G_ONLY == + pParam->uCfgDot11Mode)) { + csr_populate_basic_rates(opr_rates, true, true); + } else { + csr_populate_basic_rates(opr_rates, false, true); + csr_populate_basic_rates(ext_rates, true, false); + } + + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + } + pParam->operationChn = opr_ch; + pParam->sirNwType = nw_type; + pParam->ch_params.ch_width = pProfile->ch_params.ch_width; + pParam->ch_params.center_freq_seg0 = + pProfile->ch_params.center_freq_seg0; + pParam->ch_params.center_freq_seg1 = + pProfile->ch_params.center_freq_seg1; + pParam->ch_params.sec_ch_offset = + pProfile->ch_params.sec_ch_offset; +} + +static void +csr_roam_get_bss_start_parms_from_bss_desc(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + tCsrRoamStartBssParams *pParam) +{ + if (!pParam) { + sms_log(pMac, LOGE, FL("BSS param's pointer is NULL")); + return; + } + + pParam->sirNwType = pBssDesc->nwType; + pParam->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + pParam->operationChn = pBssDesc->channelId; + cdf_mem_copy(&pParam->bssid, pBssDesc->bssId, sizeof(struct cdf_mac_addr)); + + if (!pIes) { + pParam->ssId.length = 0; + pParam->operationalRateSet.numRates = 0; + sms_log(pMac, LOGE, FL("IEs struct pointer is NULL")); + return; + } + + if (pIes->SuppRates.present) { + pParam->operationalRateSet.numRates = pIes->SuppRates.num_rates; + if (pIes->SuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sms_log(pMac, LOGE, + FL("num_rates: %d > max val, resetting"), + pIes->SuppRates.num_rates); + pIes->SuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + cdf_mem_copy(pParam->operationalRateSet.rate, + pIes->SuppRates.rates, + sizeof(*pIes->SuppRates.rates) * + pIes->SuppRates.num_rates); + } + if (pIes->ExtSuppRates.present) { + pParam->extendedRateSet.numRates = pIes->ExtSuppRates.num_rates; + if (pIes->ExtSuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sms_log(pMac, LOGE, + FL("num_rates: %d > max val, resetting"), + pIes->ExtSuppRates.num_rates); + pIes->ExtSuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + cdf_mem_copy(pParam->extendedRateSet.rate, + pIes->ExtSuppRates.rates, + sizeof(*pIes->ExtSuppRates.rates) * + pIes->ExtSuppRates.num_rates); + } + if (pIes->SSID.present) { + pParam->ssId.length = pIes->SSID.num_ssid; + cdf_mem_copy(pParam->ssId.ssId, pIes->SSID.ssid, + pParam->ssId.length); + } + pParam->cbMode = csr_get_cb_mode_from_ies(pMac, pParam->operationChn, + pIes); +} + +static void csr_roam_determine_max_rate_for_ad_hoc(tpAniSirGlobal pMac, + tSirMacRateSet *pSirRateSet) +{ + uint8_t MaxRate = 0; + uint32_t i; + uint8_t *pRate; + + pRate = pSirRateSet->rate; + for (i = 0; i < pSirRateSet->numRates; i++) { + MaxRate = + CSR_MAX(MaxRate, (pRate[i] & (~CSR_DOT11_BASIC_RATE_MASK))); + } + + /* Save the max rate in the connected state information... */ + + /* modify LastRates variable as well */ + + return; +} + +CDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamStartBssParams *pParam, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, uint32_t roamId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + eCsrBand eBand; + /* Set the roaming substate to 'Start BSS attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_START_BSS_REQ, + sessionId); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + /* Need to figure out whether we need to log WDS??? */ + if (CSR_IS_IBSS(pProfile)) { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + if (pBssDesc) { + pIbssLog->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_REQ; + cdf_mem_copy(pIbssLog->bssid, pBssDesc->bssId, + 6); + } else { + pIbssLog->eventId = + WLAN_IBSS_EVENT_START_IBSS_REQ; + } + cdf_mem_copy(pIbssLog->ssid, pParam->ssId.ssId, + pParam->ssId.length); + if (pProfile->ChannelInfo.numOfChannels == 0) { + pIbssLog->channelSetting = AUTO_PICK; + } else { + pIbssLog->channelSetting = SPECIFIED; + } + pIbssLog->operatingChannel = pParam->operationChn; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Put RSN information in for Starting BSS */ + pParam->nRSNIELength = (uint16_t) pProfile->nRSNReqIELength; + pParam->pRSNIE = pProfile->pRSNReqIE; + + pParam->privacy = pProfile->privacy; + pParam->fwdWPSPBCProbeReq = pProfile->fwdWPSPBCProbeReq; + pParam->authType = pProfile->csr80211AuthType; + pParam->beaconInterval = pProfile->beaconInterval; + pParam->dtimPeriod = pProfile->dtimPeriod; + pParam->ApUapsdEnable = pProfile->ApUapsdEnable; + pParam->ssidHidden = pProfile->SSIDs.SSIDList[0].ssidHidden; + if (CSR_IS_INFRA_AP(pProfile) && (pParam->operationChn != 0)) { + if (csr_is_valid_channel(pMac, pParam->operationChn) != + CDF_STATUS_SUCCESS) { + pParam->operationChn = INFRA_AP_DEFAULT_CHANNEL; + } + } + pParam->protEnabled = pProfile->protEnabled; + pParam->obssProtEnabled = pProfile->obssProtEnabled; + pParam->ht_protection = pProfile->cfg_protection; + pParam->wps_state = pProfile->wps_state; + + pParam->uCfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, + pParam-> + operationChn, + &eBand); + pParam->bssPersona = pProfile->csrPersona; + +#ifdef WLAN_FEATURE_11W + pParam->mfpCapable = (0 != pProfile->MFPCapable); + pParam->mfpRequired = (0 != pProfile->MFPRequired); +#endif + + pParam->addIeParams.probeRespDataLen = + pProfile->addIeParams.probeRespDataLen; + pParam->addIeParams.probeRespData_buff = + pProfile->addIeParams.probeRespData_buff; + + pParam->addIeParams.assocRespDataLen = + pProfile->addIeParams.assocRespDataLen; + pParam->addIeParams.assocRespData_buff = + pProfile->addIeParams.assocRespData_buff; + + if (CSR_IS_IBSS(pProfile)) { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->nWPAReqIELength; + pParam->addIeParams.probeRespBCNData_buff = pProfile->pWPAReqIE; + } else { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->addIeParams.probeRespBCNDataLen; + pParam->addIeParams.probeRespBCNData_buff = + pProfile->addIeParams.probeRespBCNData_buff; + } + pParam->sap_dot11mc = pProfile->sap_dot11mc; + + /* When starting an IBSS, start on the channel from the Profile. */ + status = + csr_send_mb_start_bss_req_msg(pMac, sessionId, pProfile->BSSType, pParam, + pBssDesc); + return status; +} + +static void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + uint8_t Channel; + ePhyChanBondState cbMode = PHY_SINGLE_CHANNEL_CENTERED; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pBssDesc) { + csr_roam_get_bss_start_parms_from_bss_desc(pMac, pBssDesc, pIes, + &pSession->bssParams); + /* Since csr_roam_get_bss_start_parms_from_bss_desc fills in the bssid for pSession->bssParams */ + /* The following code has to be do after that. */ + /* For WDS station, use selfMac as the self BSSID */ + if (CSR_IS_WDS_STA(pProfile)) { + cdf_mem_copy(&pSession->bssParams.bssid, + &pSession->selfMacAddr, + sizeof(struct cdf_mac_addr)); + } + } else { + csr_roam_get_bss_start_parms(pMac, pProfile, &pSession->bssParams); + /* Use the first SSID */ + if (pProfile->SSIDs.numOfSSIDs) { + cdf_mem_copy(&pSession->bssParams.ssId, + pProfile->SSIDs.SSIDList, + sizeof(tSirMacSSid)); + } + /* For WDS station, use selfMac as the self BSSID */ + if (CSR_IS_WDS_STA(pProfile)) { + cdf_mem_copy(&pSession->bssParams.bssid, + &pSession->selfMacAddr, + sizeof(struct cdf_mac_addr)); + } + /* Use the first BSSID */ + else if (pProfile->BSSIDs.numOfBSSIDs) { + cdf_mem_copy(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid, + sizeof(struct cdf_mac_addr)); + } else { + cdf_mem_set(&pSession->bssParams.bssid, + sizeof(struct cdf_mac_addr), 0); + } + } + Channel = pSession->bssParams.operationChn; + /* Set operating channel in pProfile which will be used */ + /* in csr_roam_set_bss_config_cfg() to determine channel bonding */ + /* mode and will be configured in CFG later */ + pProfile->operationChannel = Channel; + + if (Channel == 0) { + sms_log(pMac, LOGE, + " CSR cannot find a channel to start IBSS"); + } else { + + csr_roam_determine_max_rate_for_ad_hoc(pMac, + &pSession->bssParams. + operationalRateSet); + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_START_IBSS(pProfile)) { + if (CDS_IS_CHANNEL_24GHZ(Channel)) { + cbMode = + pMac->roam.configParam. + channelBondingMode24GHz; + } else { + cbMode = + pMac->roam.configParam. + channelBondingMode5GHz; + } + sms_log(pMac, LOG1, "## cbMode %d", cbMode); + pBssConfig->cbMode = cbMode; + pSession->bssParams.cbMode = cbMode; + } + } +} + +static CDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + bool *pfSameIbss) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool fSameIbss = false; + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* Check if any profile parameter has changed ? If any profile parameter */ + /* has changed then stop old BSS and start a new one with new parameters */ + if (csr_is_same_profile + (pMac, &pMac->roam.roamSession[sessionId].connectedProfile, + pProfile)) { + fSameIbss = true; + } else { + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + } + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) { + /* Disassociate from the connected Infrastructure network... */ + status = + csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + } else { + tBssConfigParam *pBssConfig; + + pBssConfig = cdf_mem_malloc(sizeof(tBssConfigParam)); + if (NULL == pBssConfig) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(pBssConfig, sizeof(tBssConfigParam), 0); + /* there is no Bss description before we start an IBSS so we need to adopt */ + /* all Bss configuration parameters from the Profile. */ + status = + csr_roam_prepare_bss_config_from_profile(pMac, pProfile, + pBssConfig, + NULL); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* save dotMode */ + pMac->roam.roamSession[sessionId].bssParams. + uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* Prepare some more parameters for this IBSS */ + csr_roam_prepare_bss_params(pMac, sessionId, + pProfile, NULL, + pBssConfig, NULL); + status = + csr_roam_set_bss_config_cfg(pMac, sessionId, + pProfile, NULL, + pBssConfig, NULL, + false); + } + + cdf_mem_free(pBssConfig); + } /* Allocate memory */ + } + + if (pfSameIbss) { + *pfSameIbss = fSameIbss; + } + return status; +} + +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo *pNewBss) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pNewBss) { + /* Set the operating channel. */ + pSession->connectedProfile.operationChannel = + pNewBss->channelNumber; + /* move the BSSId from the BSS description into the connected state information. */ + cdf_mem_copy(&pSession->connectedProfile.bssid.bytes, + &(pNewBss->bssId), sizeof(struct cdf_mac_addr)); + } + return; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(pSession->psk_pmk, pPSK_PMK, sizeof(pSession->psk_pmk)); + pSession->pmk_len = pmk_len; + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_pmkid(tCsrRoamSession *pSession) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + cdf_mem_set(&secEvent, + sizeof(host_event_wlan_security_payload_type), 0); + secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_UPDATE; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.EncryptionType); + cdf_mem_copy(secEvent.bssid, + pSession->connectedProfile.bssid.bytes, + CDF_MAC_ADDR_SIZE); + secEvent.authMode = (uint8_t) diag_auth_type_from_csr_type( + pSession->connectedProfile.AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +CDF_STATUS +csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, uint32_t numItems, + bool update_entire_cache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t i = 0; + tPmkidCacheInfo *pmksa; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("numItems = %d"), numItems); + + if (numItems > CSR_MAX_PMKID_ALLOWED) + return CDF_STATUS_E_INVAL; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_pmkid(pSession); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (update_entire_cache) { + if (numItems && pPMKIDCache) { + pSession->NumPmkidCache = (uint16_t) numItems; + cdf_mem_copy(pSession->PmkidCacheInfo, pPMKIDCache, + sizeof(tPmkidCacheInfo) * numItems); + pSession->curr_cache_idx = (uint16_t)numItems; + } + return CDF_STATUS_SUCCESS; + } + + for (i = 0; i < numItems; i++) { + pmksa = &pPMKIDCache[i]; + + /* Delete the entry if present */ + csr_roam_del_pmkid_from_cache(pMac, sessionId, + pmksa->BSSID.bytes, false); + + /* Add entry to the cache */ + cdf_copy_macaddr( + &pSession->PmkidCacheInfo[pSession->curr_cache_idx].BSSID, + &pmksa->BSSID); + cdf_mem_copy( + pSession->PmkidCacheInfo[pSession->curr_cache_idx].PMKID, + pmksa->PMKID, CSR_RSN_PMKID_SIZE); + + /* Increment the CSR local cache index */ + if (pSession->curr_cache_idx < (CSR_MAX_PMKID_ALLOWED - 1)) + pSession->curr_cache_idx++; + else + pSession->curr_cache_idx = 0; + + pSession->NumPmkidCache++; + if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) + pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pBSSId, + bool flush_cache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + bool fMatchFound = false; + uint32_t Index; + uint32_t curr_idx; + uint32_t i; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + /* Check if there are no entries to delete */ + if (0 == pSession->NumPmkidCache) { + sms_log(pMac, LOG1, FL("No entries to delete/Flush")); + return CDF_STATUS_SUCCESS; + } + + if (flush_cache) { + /* Flush the entire cache */ + cdf_mem_zero(pSession->PmkidCacheInfo, + sizeof(tPmkidCacheInfo) * CSR_MAX_PMKID_ALLOWED); + pSession->NumPmkidCache = 0; + pSession->curr_cache_idx = 0; + return CDF_STATUS_SUCCESS; + } + + /* !flush_cache - so look up in the cache */ + for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) { + if (cdf_mem_compare(pSession->PmkidCacheInfo[Index].BSSID.bytes, + pBSSId, CDF_MAC_ADDR_SIZE)) { + fMatchFound = 1; + + /* Clear this - the matched entry */ + cdf_mem_zero(&pSession->PmkidCacheInfo[Index], + sizeof(tPmkidCacheInfo)); + break; + } + } + + if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) { + sms_log(pMac, LOG1, FL("No such PMKSA entry exists" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBSSId)); + return CDF_STATUS_SUCCESS; + } + + /* Match Found, Readjust the other entries */ + curr_idx = pSession->curr_cache_idx; + if (Index < curr_idx) { + for (i = Index; i < (curr_idx - 1); i++) { + cdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i + 1], + sizeof(tPmkidCacheInfo)); + } + + pSession->curr_cache_idx--; + cdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } else if (Index > curr_idx) { + for (i = Index; i > (curr_idx); i--) { + cdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i - 1], + sizeof(tPmkidCacheInfo)); + } + + cdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } + + /* Decrement the count since an entry has been deleted */ + pSession->NumPmkidCache--; + return CDF_STATUS_SUCCESS; +} + +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return pMac->roam.roamSession[sessionId].NumPmkidCache; +} + +CDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tPmkidCacheInfo *pmksa; + uint16_t i, j; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (!pNum || !pPmkidCache) { + sms_log(pMac, LOGE, FL("Either pNum or pPmkidCache is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (pSession->NumPmkidCache == 0) { + *pNum = 0; + return CDF_STATUS_SUCCESS; + } + + if (*pNum < pSession->NumPmkidCache) { + return CDF_STATUS_E_FAILURE; + } + + if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) { + sms_log(pMac, LOGE, + FL( + "NumPmkidCache :%d is more than CSR_MAX_PMKID_ALLOWED, resetting to CSR_MAX_PMKID_ALLOWED"), + pSession->NumPmkidCache); + pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } + + for (i = 0, j = 0; ((j < pSession->NumPmkidCache) && + (i < CSR_MAX_PMKID_ALLOWED)); i++) { + /* Fill the valid entries */ + pmksa = &pSession->PmkidCacheInfo[i]; + if (!cdf_is_macaddr_zero(&pmksa->BSSID)) { + cdf_mem_copy(pPmkidCache, pmksa, + sizeof(tPmkidCacheInfo)); + pPmkidCache++; + j++; + } + } + + *pNum = pSession->NumPmkidCache; + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnReqIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnReqIeLength) { + cdf_mem_copy(pBuf, pSession->pWpaRsnReqIE, + pSession->nWpaRsnReqIeLength); + status = CDF_STATUS_SUCCESS; + } + } + } + return status; +} + +CDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnRspIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnRspIeLength) { + cdf_mem_copy(pBuf, pSession->pWpaRsnRspIE, + pSession->nWpaRsnRspIeLength); + status = CDF_STATUS_SUCCESS; + } + } + } + return status; +} + +#ifdef FEATURE_WLAN_WAPI +CDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiReqIeLength; + if (pBuf) { + if (len >= pSession->nWapiReqIeLength) { + cdf_mem_copy(pBuf, pSession->pWapiReqIE, + pSession->nWapiReqIeLength); + status = CDF_STATUS_SUCCESS; + } + } + } + return status; +} + +CDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiRspIeLength; + if (pBuf) { + if (len >= pSession->nWapiRspIeLength) { + cdf_mem_copy(pBuf, pSession->pWapiRspIE, + pSession->nWapiRspIeLength); + status = CDF_STATUS_SUCCESS; + } + } + } + return status; +} +#endif /* FEATURE_WLAN_WAPI */ +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, uint32_t sessionId) +{ + eRoamCmdStatus retStatus = eCSR_ROAM_CONNECT_COMPLETION; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return retStatus; + } + + if (CSR_IS_ROAMING(pSession)) { + retStatus = eCSR_ROAM_ROAMING_COMPLETION; + pSession->fRoaming = false; + } + return retStatus; +} + +/* This function remove the connected BSS from te cached scan result */ +CDF_STATUS +csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsrScanResultFilter *pScanFilter = NULL; + tListElem *pEntry; + tCsrScanResult *pResult; + tDot11fBeaconIEs *pIes; + bool fMatch; + + if ((cdf_is_macaddr_zero(&pConnProfile->bssid) || + cdf_is_macaddr_broadcast(&pConnProfile->bssid))) + return status; + /* + * Prepare the filter. Only fill in the necessary fields. Not all fields + * are needed + */ + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + pScanFilter->BSSIDs.bssid = cdf_mem_malloc(sizeof(struct cdf_mac_addr)); + if (NULL == pScanFilter->BSSIDs.bssid) { + cdf_mem_free(pScanFilter); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(pScanFilter->BSSIDs.bssid, + &pConnProfile->bssid, sizeof(struct cdf_mac_addr)); + pScanFilter->BSSIDs.numOfBSSIDs = 1; + if (!csr_is_nullssid(pConnProfile->SSID.ssId, + pConnProfile->SSID.length)) { + pScanFilter->SSIDs.SSIDList = cdf_mem_malloc( + sizeof(tCsrSSIDInfo)); + if (NULL == pScanFilter->SSIDs.SSIDList) { + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(&pScanFilter->SSIDs.SSIDList[0].SSID, + &pConnProfile->SSID, sizeof(tSirMacSSid)); + } + pScanFilter->authType.numEntries = 1; + pScanFilter->authType.authType[0] = pConnProfile->AuthType; + pScanFilter->BSSType = pConnProfile->BSSType; + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + pConnProfile->EncryptionType; + pScanFilter->mcEncryptionType.numEntries = 1; + pScanFilter->mcEncryptionType.encryptionType[0] = + pConnProfile->mcEncryptionType; + /* We ignore the channel for now, BSSID should be enough */ + pScanFilter->ChannelInfo.numOfChannels = 0; + /* Also ignore the following fields */ + pScanFilter->uapsd_mask = 0; + pScanFilter->bWPSAssociation = false; + pScanFilter->bOSENAssociation = false; + pScanFilter->countryCode[0] = 0; + pScanFilter->phyMode = eCSR_DOT11_MODE_AUTO; + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pResult->Result.pvIes); + fMatch = csr_match_bss(pMac, &pResult->Result.BssDescriptor, + pScanFilter, NULL, NULL, NULL, &pIes); + /* Release the IEs allocated by csr_match_bss is needed */ + if (!pResult->Result.pvIes) { + /* + * need to free the IEs since it is allocated + * by csr_match_bss + */ + cdf_mem_free(pIes); + } + if (fMatch) { + /* We found the one */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK)) + /* Free the memory */ + csr_free_scan_result_entry(pMac, pResult); + break; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return status; +} + +static CDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tBssConfigParam bssConfig; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) { + /* Disassociate from the connected Infrastructure network... */ + status = + csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + } else { + /* We don't expect Bt-AMP HDD not to disconnect the last connection first at this time. */ + /* Otherwise we need to add code to handle the */ + /* situation just like IBSS. Though for WDS station, we need to send disassoc to PE first then */ + /* send stop_bss to PE, before we can continue. */ + + if (csr_is_conn_state_wds(pMac, sessionId)) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_set(&bssConfig, sizeof(tBssConfigParam), 0); + /* Assume HDD provide bssid in profile */ + cdf_copy_macaddr(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid); + /* there is no Bss description before we start an WDS so we need */ + /* to adopt all Bss configuration parameters from the Profile. */ + status = + csr_roam_prepare_bss_config_from_profile(pMac, pProfile, + &bssConfig, pBssDesc); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Save profile for late use */ + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (pSession->pCurRoamProfile != NULL) { + cdf_mem_set(pSession->pCurRoamProfile, + sizeof(tCsrRoamProfile), 0); + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + pProfile); + } + /* Prepare some more parameters for this WDS */ + csr_roam_prepare_bss_params(pMac, sessionId, pProfile, NULL, + &bssConfig, NULL); + status = + csr_roam_set_bss_config_cfg(pMac, sessionId, pProfile, + NULL, &bssConfig, NULL, + false); + } + } + + return status; +} + +/** + * csr_add_supported_5Ghz_channels()- Add valid 5Ghz channels + * in Join req. + * @mac_ctx: pointer to global mac structure + * @csr_join_req: join req sent to lim + * + * This function is called to update valid 5Ghz channels + * in Join req. + * + * Return: void + */ +static void csr_add_supported_5Ghz_channels(tpAniSirGlobal mac_ctx, + tSirSmeJoinReq *csr_join_req) +{ + uint16_t i, j; + uint32_t size = 0; + + if (!csr_join_req) { + sms_log(mac_ctx, LOGE, FL(" csr_join_reqis NULL")); + return; + } + + size = sizeof(mac_ctx->roam.validChannelList); + if (CDF_IS_STATUS_SUCCESS + (csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, + &size))) { + for (i = 0, j = 0; i < size; i++) { + /* Only add 5ghz channels.*/ + if (CDS_IS_CHANNEL_5GHZ + (mac_ctx->roam.validChannelList[i])) { + csr_join_req->supportedChannels.channelList[j] = + mac_ctx->roam.validChannelList[i]; + j++; + } + } + csr_join_req->supportedChannels.numChnl = j; + } else { + sms_log(mac_ctx, LOGE, + FL("can not find any valid channel")); + csr_join_req->supportedChannels.numChnl = 0; + } +} + +/** + * The communication between HDD and LIM is thru mailbox (MB). + * Both sides will access the data structure "tSirSmeJoinReq". + * The rule is, while the components of "tSirSmeJoinReq" can be accessed in the + * regular way like tSirSmeJoinReq.assocType, this guideline stops at component + * tSirRSNie; + * any acces to the components after tSirRSNie is forbidden because the space + * from tSirRSNie is squeezed with the component "tSirBssDescription" and since + * the size of actual 'tSirBssDescription' varies, the receiving side should + * keep in mind not to access the components DIRECTLY after tSirRSNie. + */ +CDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + tCsrRoamProfile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t acm_mask = 0, uapsd_mask; + uint16_t msgLen, ieLen; + tSirMacRateSet OpRateSet; + tSirMacRateSet ExRateSet; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t dwTmp, ucDot11Mode = 0; + /* RSN MAX is bigger than WPA MAX */ + uint8_t wpaRsnIE[DOT11F_IE_RSN_MAX_LEN]; + uint8_t txBFCsnValue = 0; + tSirSmeJoinReq *csr_join_req; + tSirMacCapabilityInfo *pAP_capabilityInfo; + tAniBool fTmp; + int8_t pwrLimit = 0; + struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[sessionId]; + uint8_t ese_config = 0; + + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + /* To satisfy klockworks */ + if (NULL == pBssDescription) { + sms_log(pMac, LOGE, FL(" pBssDescription is NULL")); + return CDF_STATUS_E_FAILURE; + } + + do { + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + cdf_mem_copy(&pSession->joinFailStatusCode.bssId, + &pBssDescription->bssId, sizeof(tSirMacAddr)); + /* + * the tSirSmeJoinReq which includes a single + * bssDescription. it includes a single uint32_t for the + * IE fields, but the length field in the bssDescription + * needs to be interpreted to determine length of IE fields + * So, take the size of the tSirSmeJoinReq, subtract size of + * bssDescription, add the number of bytes indicated by the + * length field of the bssDescription, add the size of length + * field because it not included in the lenghth field. + */ + msgLen = sizeof(tSirSmeJoinReq) - sizeof(*pBssDescription) + + pBssDescription->length + + sizeof(pBssDescription->length) + + /* + * add in the size of the WPA IE that + * we may build. + */ + sizeof(tCsrWpaIe) + sizeof(tCsrWpaAuthIe) + + sizeof(uint16_t); + csr_join_req = cdf_mem_malloc(msgLen); + if (NULL == csr_join_req) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(csr_join_req, msgLen, 0); + csr_join_req->messageType = messageType; + csr_join_req->length = msgLen; + csr_join_req->sessionId = (uint8_t) sessionId; + csr_join_req->transactionId = 0; + if (pIes->SSID.present && pIes->SSID.num_ssid) { + csr_join_req->ssId.length = pIes->SSID.num_ssid; + cdf_mem_copy(&csr_join_req->ssId.ssId, pIes->SSID.ssid, + pIes->SSID.num_ssid); + } else + csr_join_req->ssId.length = 0; + cdf_mem_copy(&csr_join_req->selfMacAddr, &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + /* bsstype */ + dwTmp = csr_translate_bsstype_to_mac_type + (pProfile->BSSType); + /* Override BssType for BTAMP */ + if (dwTmp == eSIR_BTAMP_STA_MODE) + dwTmp = eSIR_BTAMP_AP_MODE; + csr_join_req->bsstype = dwTmp; + /* dot11mode */ + ucDot11Mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pSession->bssParams. + uCfgDot11Mode); + if (pBssDescription->channelId <= 14 + && false == pMac->roam.configParam.enableVhtFor24GHz + && WNI_CFG_DOT11_MODE_11AC == ucDot11Mode) { + /* Need to disable VHT operation in 2.4 GHz band */ + ucDot11Mode = WNI_CFG_DOT11_MODE_11N; + } + csr_join_req->dot11mode = (uint8_t) ucDot11Mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + csr_join_req->cc_switch_mode = + pMac->roam.configParam.cc_switch_mode; +#endif + csr_join_req->staPersona = (uint8_t) pProfile->csrPersona; + csr_join_req->cbMode = (uint8_t) pSession->bssParams.cbMode; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("CSR PERSONA=%d CSR CbMode %d"), + pProfile->csrPersona, pSession->bssParams.cbMode); + csr_join_req->uapsdPerAcBitmask = pProfile->uapsd_mask; + status = + csr_get_rate_set(pMac, pProfile, + (eCsrPhyMode) pProfile->phyMode, + pBssDescription, pIes, &OpRateSet, + &ExRateSet); + ps_param->uapsd_per_ac_bit_mask = + pProfile->uapsd_mask; + if (CDF_IS_STATUS_SUCCESS(status)) { + /* OperationalRateSet */ + if (OpRateSet.numRates) { + csr_join_req->operationalRateSet.numRates = + OpRateSet.numRates; + cdf_mem_copy(&csr_join_req->operationalRateSet. + rate, OpRateSet.rate, + OpRateSet.numRates); + } else + csr_join_req->operationalRateSet.numRates = 0; + + /* ExtendedRateSet */ + if (ExRateSet.numRates) { + csr_join_req->extendedRateSet.numRates = + ExRateSet.numRates; + cdf_mem_copy(&csr_join_req->extendedRateSet. + rate, ExRateSet.rate, + ExRateSet.numRates); + } else + csr_join_req->extendedRateSet.numRates = 0; + } else { + csr_join_req->operationalRateSet.numRates = 0; + csr_join_req->extendedRateSet.numRates = 0; + } + /* rsnIE */ + if (csr_is_profile_wpa(pProfile)) { + /* Insert the Wpa IE into the join request */ + ieLen = + csr_retrieve_wpa_ie(pMac, pProfile, + pBssDescription, pIes, + (tCsrWpaIe *) (wpaRsnIE)); + } else if (csr_is_profile_rsn(pProfile)) { + /* Insert the RSN IE into the join request */ + ieLen = + csr_retrieve_rsn_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrRSNIe *) (wpaRsnIE)); + } +#ifdef FEATURE_WLAN_WAPI + else if (csr_is_profile_wapi(pProfile)) { + /* Insert the WAPI IE into the join request */ + ieLen = + csr_retrieve_wapi_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrWapiIe *) (wpaRsnIE)); + } +#endif /* FEATURE_WLAN_WAPI */ + else { + ieLen = 0; + } + /* remember the IE for future use */ + if (ieLen) { + if (ieLen > DOT11F_IE_RSN_MAX_LEN) { + sms_log(pMac, LOGE, + FL + (" WPA RSN IE length :%d is more than DOT11F_IE_RSN_MAX_LEN, resetting to %d"), + ieLen, DOT11F_IE_RSN_MAX_LEN); + ieLen = DOT11F_IE_RSN_MAX_LEN; + } +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pProfile)) { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWapiReqIeLength) { + if (pSession->pWapiReqIE + && pSession->nWapiReqIeLength) { + cdf_mem_free(pSession-> + pWapiReqIE); + } + pSession->pWapiReqIE = + cdf_mem_malloc(ieLen); + if (NULL == pSession->pWapiReqIE) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWapiReqIeLength = ieLen; + cdf_mem_copy(pSession->pWapiReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + cdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } else /* should be WPA/WPA2 otherwise */ +#endif /* FEATURE_WLAN_WAPI */ + { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWpaRsnReqIeLength) { + if (pSession->pWpaRsnReqIE + && pSession->nWpaRsnReqIeLength) { + cdf_mem_free(pSession-> + pWpaRsnReqIE); + } + pSession->pWpaRsnReqIE = + cdf_mem_malloc(ieLen); + if (NULL == pSession->pWpaRsnReqIE) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWpaRsnReqIeLength = ieLen; + cdf_mem_copy(pSession->pWpaRsnReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + cdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } + } else { + /* free whatever old info */ + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnReqIE) { + cdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiReqIE) { + cdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + csr_join_req->rsnIE.length = 0; + } +#ifdef FEATURE_WLAN_ESE + if (eWNI_SME_JOIN_REQ == messageType) + csr_join_req->cckmIE.length = 0; + else if (eWNI_SME_REASSOC_REQ == messageType) { + /* cckmIE */ + if (csr_is_profile_ese(pProfile)) { + /* Insert the CCKM IE into the join request */ +#ifdef FEATURE_WLAN_ESE_UPLOAD + ieLen = pSession->suppCckmIeInfo.cckmIeLen; + cdf_mem_copy((void *)(wpaRsnIE), + pSession->suppCckmIeInfo.cckmIe, + ieLen); +#else + ieLen = csrConstructEseCckmIe(pMac, + pSession, + pProfile, + pBssDescription, + pSession-> + pWpaRsnReqIE, + pSession-> + nWpaRsnReqIeLength, + (void *)(wpaRsnIE)); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + } else + ieLen = 0; + /* + * If present, copy the IE into the + * eWNI_SME_REASSOC_REQ message buffer + */ + if (ieLen) { + /* + * Copy the CCKM IE over from the temp + * buffer (wpaRsnIE) + */ + csr_join_req->cckmIE.length = ieLen; + cdf_mem_copy(&csr_join_req->cckmIE.cckmIEdata, + wpaRsnIE, ieLen); + } else + csr_join_req->cckmIE.length = 0; + } +#endif /* FEATURE_WLAN_ESE */ + /* addIEScan */ + if (pProfile->nAddIEScanLength && pProfile->pAddIEScan) { + ieLen = pProfile->nAddIEScanLength; + if (ieLen > pSession->nAddIEScanLength) { + if (pSession->pAddIEScan + && pSession->nAddIEScanLength) { + cdf_mem_free(pSession->pAddIEScan); + } + pSession->pAddIEScan = cdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEScan) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEScanLength = ieLen; + cdf_mem_copy(pSession->pAddIEScan, pProfile->pAddIEScan, + ieLen); + csr_join_req->addIEScan.length = ieLen; + cdf_mem_copy(&csr_join_req->addIEScan.addIEdata, + pProfile->pAddIEScan, ieLen); + } else { + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEScan) { + cdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + csr_join_req->addIEScan.length = 0; + } + /* addIEAssoc */ + if (pProfile->nAddIEAssocLength && pProfile->pAddIEAssoc) { + ieLen = pProfile->nAddIEAssocLength; + if (ieLen > pSession->nAddIEAssocLength) { + if (pSession->pAddIEAssoc + && pSession->nAddIEAssocLength) { + cdf_mem_free(pSession->pAddIEAssoc); + } + pSession->pAddIEAssoc = cdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEAssoc) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEAssocLength = ieLen; + cdf_mem_copy(pSession->pAddIEAssoc, + pProfile->pAddIEAssoc, ieLen); + csr_join_req->addIEAssoc.length = ieLen; + cdf_mem_copy(&csr_join_req->addIEAssoc.addIEdata, + pProfile->pAddIEAssoc, ieLen); + } else { + pSession->nAddIEAssocLength = 0; + if (pSession->pAddIEAssoc) { + cdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + csr_join_req->addIEAssoc.length = 0; + } + + if (eWNI_SME_REASSOC_REQ == messageType) { + /* Unmask any AC in reassoc that is ACM-set */ + uapsd_mask = (uint8_t) pProfile->uapsd_mask; + if (uapsd_mask && (NULL != pBssDescription)) { + if (CSR_IS_QOS_BSS(pIes) + && CSR_IS_UAPSD_BSS(pIes)) +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = + sme_qos_get_acm_mask(pMac, + pBssDescription, + pIes); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + else + uapsd_mask = 0; + } + } + + csr_join_req->UCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedUCEncryptionType); + + csr_join_req->MCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedMCEncryptionType); +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled) + csr_join_req->MgmtEncryptionType = eSIR_ED_AES_128_CMAC; + else + csr_join_req->MgmtEncryptionType = eSIR_ED_NONE; +#endif +#ifdef FEATURE_WLAN_ESE + ese_config = pMac->roam.configParam.isEseIniFeatureEnabled; +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + pProfile->MDID.mdiePresent = pBssDescription->mdiePresent; + if (csr_is_profile11r(pProfile) +#ifdef FEATURE_WLAN_ESE + && + !((pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM) && (pIes->ESEVersion.present) + && (ese_config)) +#endif + ) + csr_join_req->is11Rconnection = true; + else + csr_join_req->is11Rconnection = false; +#endif +#ifdef FEATURE_WLAN_ESE + if (true == ese_config) + csr_join_req->isESEFeatureIniEnabled = true; + else + csr_join_req->isESEFeatureIniEnabled = false; + + /* A profile can not be both ESE and 11R. But an 802.11R AP + * may be advertising support for ESE as well. So if we are + * associating Open or explicitly ESE then we will get ESE. + * If we are associating explictly 11R only then we will get + * 11R. + */ + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) && + (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (ese_config)) + csr_join_req->isESEconnection = true; + else + csr_join_req->isESEconnection = false; + + if (eWNI_SME_JOIN_REQ == messageType) { + tESETspecInfo eseTspec; + /* + * ESE-Tspec IEs in the ASSOC request is presently not + * supported. so nullify the TSPEC parameters + */ + cdf_mem_set(&eseTspec, sizeof(tESETspecInfo), 0); + cdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, sizeof(tESETspecInfo)); + } else if (eWNI_SME_REASSOC_REQ == messageType) { + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) + && (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) && + (ese_config)) { + tESETspecInfo eseTspec; + cdf_mem_set(&eseTspec, sizeof(tESETspecInfo), + 0); + eseTspec.numTspecs = + sme_qos_ese_retrieve_tspec_info(pMac, + sessionId, + (tTspecInfo *) &eseTspec. + tspec[0]); + csr_join_req->eseTspecInfo.numTspecs = + eseTspec.numTspecs; + if (eseTspec.numTspecs) { + cdf_mem_copy(&csr_join_req->eseTspecInfo + .tspec[0], + &eseTspec.tspec[0], + (eseTspec.numTspecs * + sizeof(tTspecInfo))); + } + } else { + tESETspecInfo eseTspec; + /** + * ESE-Tspec IEs in the ASSOC request is + * presently not supported. so nullify the TSPEC + * parameters + */ + cdf_mem_set(&eseTspec, sizeof(tESETspecInfo), + 0); + cdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, + sizeof(tESETspecInfo)); + } + } +#endif /* FEATURE_WLAN_ESE */ +#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR) + if (ese_config +#ifdef FEATURE_WLAN_LFR + || csr_roam_is_fast_roam_enabled(pMac, sessionId) +#endif + ) { + csr_join_req->isFastTransitionEnabled = true; + } else { + csr_join_req->isFastTransitionEnabled = false; + } +#endif +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) + csr_join_req->isFastRoamIniFeatureEnabled = true; + else + csr_join_req->isFastRoamIniFeatureEnabled = false; +#endif + + csr_join_req->txLdpcIniFeatureEnabled = + (uint8_t) pMac->roam.configParam.txLdpcEnable; + + if ((csr_is11h_supported(pMac)) + && (CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId)) + && (pIes->Country.present) + && (!pMac->roam.configParam. + fSupplicantCountryCodeHasPriority)) { + csr_save_to_channel_power2_g_5_g(pMac, + pIes->Country.num_triplets * + sizeof(tSirMacChanInfo), + (tSirMacChanInfo *) + (&pIes->Country.triplets[0])); + csr_apply_power2_current(pMac); + } + cdf_mem_copy(&csr_join_req->htConfig, + &pSession->htConfig, sizeof(tSirHTConfig)); +#ifdef WLAN_FEATURE_11AC + csr_join_req->txBFIniFeatureEnabled = + (uint8_t) pMac->roam.configParam.txBFEnable; + + if (pMac->roam.configParam.txBFEnable) { + txBFCsnValue = + (uint8_t)pMac->roam.configParam.txBFCsnValue; + if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) && + pIes->VHTCaps.numSoundingDim) + txBFCsnValue = CDF_MIN(txBFCsnValue, + pIes->VHTCaps.numSoundingDim); + else if (IS_BSS_VHT_CAPABLE(pIes->vendor2_ie.VHTCaps) + && pIes->vendor2_ie.VHTCaps.numSoundingDim) + txBFCsnValue = CDF_MIN(txBFCsnValue, + pIes->vendor2_ie.VHTCaps.numSoundingDim); + } + csr_join_req->txBFCsnValue = txBFCsnValue; + + csr_join_req->txMuBformee = + (uint8_t) pMac->roam.configParam.txMuBformee; + + csr_join_req->enableVhtpAid = + (uint8_t) pMac->roam.configParam.enableVhtpAid; + + csr_join_req->enableVhtGid = + (uint8_t) pMac->roam.configParam.enableVhtGid; + +#endif + csr_join_req->enableAmpduPs = + (uint8_t) pMac->roam.configParam.enableAmpduPs; + + csr_join_req->enableHtSmps = + (uint8_t) pMac->roam.configParam.enableHtSmps; + + csr_join_req->htSmps = (uint8_t) pMac->roam.configParam.htSmps; + + csr_join_req->isAmsduSupportInAMPDU = + (uint8_t) pMac->roam.configParam.isAmsduSupportInAMPDU; + + if (pMac->roam.roamSession[sessionId].fWMMConnection) + csr_join_req->isWMEenabled = true; + else + csr_join_req->isWMEenabled = false; + + if (pMac->roam.roamSession[sessionId].fQOSConnection) + csr_join_req->isQosEnabled = true; + else + csr_join_req->isQosEnabled = false; + + if (pProfile->bOSENAssociation) + csr_join_req->isOSENConnection = true; + else + csr_join_req->isOSENConnection = false; + + pAP_capabilityInfo = + (tSirMacCapabilityInfo *) + &pBssDescription->capabilityInfo; + /* + * tell the target AP my 11H capability only if both AP and STA + * support + * 11H and the channel being used is 11a + */ + if (csr_is11h_supported(pMac) && pAP_capabilityInfo->spectrumMgt + && eSIR_11A_NW_TYPE == pBssDescription->nwType) { + fTmp = (tAniBool) 1; + } else + fTmp = (tAniBool) 0; + + csr_join_req->spectrumMgtIndicator = fTmp; + csr_join_req->powerCap.minTxPower = MIN_TX_PWR_CAP; + /* + * This is required for 11k test VoWiFi Ent: Test 2. + * We need the power capabilities for Assoc Req. + * This macro is provided by the halPhyCfg.h. We pick our + * max and min capability by the halPhy provided macros + */ + pwrLimit = csr_get_cfg_max_tx_power(pMac, + pBssDescription->channelId); + if (0 != pwrLimit) + csr_join_req->powerCap.maxTxPower = pwrLimit; + else + csr_join_req->powerCap.maxTxPower = MAX_TX_PWR_CAP; + + csr_add_supported_5Ghz_channels(pMac, csr_join_req); + + csr_join_req->uapsdPerAcBitmask = (uint8_t)pProfile->uapsd_mask; + /* Move the entire BssDescription into the join request. */ + cdf_mem_copy(&csr_join_req->bssDescription, pBssDescription, + pBssDescription->length + + sizeof(pBssDescription->length)); + + /* + * conc_custom_rule1: + * If SAP comes up first and STA comes up later then SAP + * need to follow STA's channel in 2.4Ghz. In following if + * condition we are adding sanity check, just to make sure that + * if this rule is enabled then don't allow STA to connect on + * 5gz channel and also by this time SAP's channel should be the + * same as STA's channel. + */ + if (pMac->roam.configParam.conc_custom_rule1) { + if ((0 == + pMac-> + roam.configParam.is_sta_connection_in_5gz_enabled) + && CDS_IS_CHANNEL_5GHZ(pBssDescription-> + channelId)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("STA-conn on 5G isn't allowed")); + status = CDF_STATUS_E_FAILURE; + break; + } + if (!CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId) && + (false == csr_is_conn_allow_2g_band(pMac, + pBssDescription->channelId))) { + status = CDF_STATUS_E_FAILURE; + break; + } + } + + /* + * conc_custom_rule2: + * If P2PGO comes up first and STA comes up later then P2PGO + * need to follow STA's channel in 5Ghz. In following if + * condition we are just adding sanity check to make sure that + * by this time P2PGO's channel is same as STA's channel. + */ + if (pMac->roam.configParam.conc_custom_rule2) { + if (!CDS_IS_CHANNEL_24GHZ(pBssDescription->channelId) && + (false == csr_is_conn_allow_5g_band(pMac, + pBssDescription->channelId))) { + status = CDF_STATUS_E_FAILURE; + break; + } + } + status = cds_send_mb_message_to_mac(csr_join_req); + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* + * cds_send_mb_message_to_mac would've released the mem + * allocated by csr_join_req. Let's make it defensive by + * assigning NULL to the pointer. + */ + csr_join_req = NULL; + break; + } else { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + if (eWNI_SME_JOIN_REQ == messageType) { + /* Notify QoS module that join happening */ + pSession->join_bssid_count++; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + "BSSID Count = %d", + pSession->join_bssid_count); + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_JOIN_REQ, NULL); + } else if (eWNI_SME_REASSOC_REQ == messageType) { + /* Notify QoS module that reassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_REASSOC_REQ, + NULL); + } +#endif + } + } while (0); + + /* Clean up the memory in case of any failure */ + if (!CDF_IS_STATUS_SUCCESS(status) && (NULL != csr_join_req)) + cdf_mem_free(csr_join_req); + + return status; +} + +/* */ +CDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDisassocReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return CDF_STATUS_E_FAILURE; + + pMsg = cdf_mem_malloc(sizeof(tSirSmeDisassocReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pMsg, sizeof(tSirSmeDisassocReq), 0); + pMsg->messageType = eWNI_SME_DISASSOC_REQ; + pMsg->length = sizeof(tSirSmeDisassocReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + if ((pSession->pCurRoamProfile != NULL) + && ((CSR_IS_INFRA_AP(pSession->pCurRoamProfile)) + || (CSR_IS_WDS_AP(pSession->pCurRoamProfile)))) { + cdf_mem_copy(&pMsg->bssId, + &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(&pMsg->peerMacAddr, + bssId, + sizeof(tSirMacAddr)); + } else { + cdf_mem_copy(&pMsg->bssId, + bssId, + sizeof(tSirMacAddr)); + cdf_mem_copy(&pMsg->peerMacAddr, + bssId, + sizeof(tSirMacAddr)); + } + pMsg->reasonCode = reasonCode; + /* + * The state will be DISASSOC_HANDOFF only when we are doing + * handoff. Here we should not send the disassoc over the air + * to the AP + */ + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) +#ifdef WLAN_FEATURE_VOWIFI_11R + && csr_roam_is11r_assoc(pMac, sessionId) +#endif + ) { + /* Set DoNotSendOverTheAir flag to 1 only for handoff case */ + pMsg->doNotSendOverTheAir = CSR_DONT_SEND_DISASSOC_OVER_THE_AIR; + } + return cds_send_mb_message_to_mac(pMsg); +} + +CDF_STATUS csr_send_mb_tkip_counter_measures_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, bool bEnable, + tSirMacAddr bssId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeTkipCntrMeasReq *pMsg; + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeTkipCntrMeasReq)); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(pMsg, sizeof(tSirSmeTkipCntrMeasReq), 0); + pMsg->messageType = eWNI_SME_TKIP_CNTR_MEAS_REQ; + pMsg->length = sizeof(tSirSmeTkipCntrMeasReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr)); + pMsg->bEnable = bEnable; + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS +csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + CDF_MODULE_ID modId, tSirMacAddr bssId, + void *pUsrContext, void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeGetAssocSTAsReq *pMsg; + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeGetAssocSTAsReq)); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(pMsg, sizeof(tSirSmeGetAssocSTAsReq), 0); + pMsg->messageType = eWNI_SME_GET_ASSOC_STAS_REQ; + cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr)); + pMsg->modId = modId; + cdf_mem_copy(pMsg->pUsrContext, + pUsrContext, sizeof(void *)); + cdf_mem_copy(pMsg->pSapEventCallback, + pfnSapEventCallback, sizeof(void *)); + cdf_mem_copy(pMsg->pAssocStasArray, + pAssocStasBuf, sizeof(void *)); + pMsg->length = sizeof(struct sSirSmeGetAssocSTAsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS +csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, void *pUsrContext, + void *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeGetWPSPBCSessionsReq *pMsg; + + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeGetWPSPBCSessionsReq)); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(pMsg, sizeof(tSirSmeGetWPSPBCSessionsReq), 0); + pMsg->messageType = eWNI_SME_GET_WPSPBC_SESSION_REQ; + cdf_mem_copy(pMsg->pUsrContext, pUsrContext, sizeof(void *)); + cdf_mem_copy(pMsg->pSapEventCallback, pfnSapEventCallback, + sizeof(void *)); + cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr)); + cdf_mem_copy(pMsg->pRemoveMac, pRemoveMac.bytes, + CDF_MAC_ADDR_SIZE); + pMsg->length = sizeof(struct sSirSmeGetWPSPBCSessionsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tpSirChangeBIParams pMsg; + uint16_t len = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + /* NO need to update the Beacon Params if update beacon parameter flag is not set */ + if (!pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval) + return CDF_STATUS_SUCCESS; + + pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = + false; + + /* Create the message and send to lim */ + len = sizeof(tSirChangeBIParams); + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(pMsg, sizeof(tSirChangeBIParams), 0); + pMsg->messageType = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + pMsg->length = len; + + /* bssId */ + cdf_mem_copy((tSirMacAddr *) pMsg->bssId, + &pSession->selfMacAddr, sizeof(tSirMacAddr)); + sms_log(pMac, LOG1, + FL("CSR Attempting to change BI for Bssid= " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssId)); + pMsg->sessionId = sessionId; + sms_log(pMac, LOG1, FL(" session %d BeaconInterval %d"), + sessionId, + pMac->roam.roamSession[sessionId].bssParams. + beaconInterval); + pMsg->beaconInterval = + pMac->roam.roamSession[sessionId].bssParams.beaconInterval; + status = cds_send_mb_message_to_mac(pMsg); + } + return status; +} + +#ifdef QCA_HT_2040_COEX +CDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled) +{ + tpSirSetHT2040Mode pMsg; + uint16_t len = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + /* Create the message and send to lim */ + len = sizeof(tSirSetHT2040Mode); + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_set(pMsg, sizeof(tSirSetHT2040Mode), 0); + pMsg->messageType = eWNI_SME_SET_HT_2040_MODE; + pMsg->length = len; + + /* bssId */ + cdf_mem_copy((tSirMacAddr *) pMsg->bssId, + &pSession->selfMacAddr, sizeof(tSirMacAddr)); + sms_log(pMac, LOG1, + FL("CSR Attempting to set HT20/40 mode for Bssid= " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssId)); + pMsg->sessionId = sessionId; + sms_log(pMac, LOG1, FL(" session %d HT20/40 mode %d"), + sessionId, cbMode); + pMsg->cbMode = cbMode; + pMsg->obssEnabled = obssEnabled; + status = cds_send_mb_message_to_mac(pMsg); + } + return status; +} +#endif + +CDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDeauthReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return CDF_STATUS_E_FAILURE; + + pMsg = cdf_mem_malloc(sizeof(tSirSmeDeauthReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pMsg, sizeof(tSirSmeDeauthReq), 0); + pMsg->messageType = eWNI_SME_DEAUTH_REQ; + pMsg->length = sizeof(tSirSmeDeauthReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + + if ((pSession->pCurRoamProfile != NULL) + && ((CSR_IS_INFRA_AP(pSession->pCurRoamProfile)) + || (CSR_IS_WDS_AP(pSession->pCurRoamProfile)))) { + cdf_mem_copy(&pMsg->bssId, + &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + } else { + cdf_mem_copy(&pMsg->bssId, + bssId, + sizeof(tSirMacAddr)); + } + + /* Set the peer MAC address before sending the message to LIM */ + cdf_mem_copy(&pMsg->peerMacAddr, + bssId, + sizeof(tSirMacAddr)); + pMsg->reasonCode = reasonCode; + + return cds_send_mb_message_to_mac(pMsg); +} + +CDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeDisassocCnf *pMsg; + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeDisassocCnf)); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(pMsg, sizeof(tSirSmeDisassocCnf), 0); + pMsg->messageType = eWNI_SME_DISASSOC_CNF; + pMsg->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDisassocCnf); + cdf_mem_copy(pMsg->peerMacAddr, pDisassocInd->peerMacAddr, + sizeof(pMsg->peerMacAddr)); + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pMsg); + break; + } + + cdf_mem_copy(pMsg->bssId, pDisassocInd->bssId, + sizeof(pMsg->peerMacAddr)); + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pMsg); + break; + } + + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeDeauthCnf *pMsg; + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeDeauthCnf)); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + cdf_mem_set(pMsg, sizeof(tSirSmeDeauthCnf), 0); + pMsg->messageType = eWNI_SME_DEAUTH_CNF; + pMsg->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDeauthCnf); + cdf_mem_copy(pMsg->bssId, pDeauthInd->bssId, + sizeof(pMsg->bssId)); + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pMsg); + break; + } + cdf_mem_copy(pMsg->peerMacAddr, pDeauthInd->peerMacAddr, + sizeof(pMsg->peerMacAddr)); + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pMsg); + break; + } + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, + CDF_STATUS Halstatus) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeAssocCnf *pMsg; + + sms_log(pMac, LOG1, + FL("Posting eWNI_SME_ASSOC_CNF to LIM.HalStatus :%d"), + Halstatus); + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeAssocCnf)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, sizeof(tSirSmeAssocCnf), 0); + pMsg->messageType = eWNI_SME_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocCnf); + if (CDF_IS_STATUS_SUCCESS(Halstatus)) + pMsg->statusCode = eSIR_SME_SUCCESS; + else + pMsg->statusCode = eSIR_SME_ASSOC_REFUSED; + /* bssId */ + cdf_mem_copy(pMsg->bssId, pAssocInd->bssId, + sizeof(tSirMacAddr)); + /* peerMacAddr */ + cdf_mem_copy(pMsg->peerMacAddr, pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + /* aid */ + pMsg->aid = pAssocInd->aid; + /* alternateBssId */ + cdf_mem_copy(pMsg->alternateBssId, pAssocInd->bssId, + sizeof(tSirMacAddr)); + /* alternateChannelId */ + pMsg->alternateChannelId = 11; + /* pMsg is freed by cds_send_mb_message_to_mac in anycase*/ + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + CDF_STATUS Halstatus, + uint8_t sessionId) +{ + tSirMsgQ msgQ; + tSirSmeAssocIndToUpperLayerCnf *pMsg; + uint8_t *pBuf; + tSirResultCodes statusCode; + uint16_t wTmp; + do { + pMsg = cdf_mem_malloc(sizeof(tSirSmeAssocIndToUpperLayerCnf)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, sizeof(tSirSmeAssocIndToUpperLayerCnf), 0); + + pMsg->messageType = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocIndToUpperLayerCnf); + + pMsg->sessionId = sessionId; + + pBuf = (uint8_t *) &pMsg->statusCode; + if (CDF_IS_STATUS_SUCCESS(Halstatus)) + statusCode = eSIR_SME_SUCCESS; + else + statusCode = eSIR_SME_ASSOC_REFUSED; + cdf_mem_copy(pBuf, &statusCode, sizeof(tSirResultCodes)); + pBuf += sizeof(tSirResultCodes); + /* bssId */ + cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* peerMacAddr */ + cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* StaId */ + wTmp = pAssocInd->staId; + cdf_mem_copy(pBuf, &wTmp, sizeof(uint16_t)); + pBuf += sizeof(uint16_t); + /* alternateBssId */ + cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* alternateChannelId */ + *pBuf = 11; + pBuf += sizeof(uint8_t); + /* Instead of copying roam Info, we just copy only WmmEnabled, RsnIE information */ + /* Wmm */ + *pBuf = pAssocInd->wmmEnabledSta; + pBuf += sizeof(uint8_t); + /* RSN IE */ + cdf_mem_copy((tSirRSNie *) pBuf, &pAssocInd->rsnIE, + sizeof(tSirRSNie)); + pBuf += sizeof(tSirRSNie); +#ifdef FEATURE_WLAN_WAPI + /* WAPI IE */ + cdf_mem_copy((tSirWAPIie *) pBuf, &pAssocInd->wapiIE, + sizeof(tSirWAPIie)); + pBuf += sizeof(tSirWAPIie); +#endif + /* Additional IE */ + cdf_mem_copy((void *)pBuf, &pAssocInd->addIE, + sizeof(tSirAddie)); + pBuf += sizeof(tSirAddie); + /* reassocReq */ + *pBuf = pAssocInd->reassocReq; + pBuf += sizeof(uint8_t); + /* timingMeasCap */ + *pBuf = pAssocInd->timingMeasCap; + pBuf += sizeof(uint8_t); + cdf_mem_copy((void *)pBuf, &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + msgQ.bodyptr = pMsg; + msgQ.bodyval = 0; + sys_process_mmh_msg(pMac, &msgQ); + } while (0); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr peerMacAddr, uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc) +{ + tSirSmeSetContextReq *pMsg; + uint16_t msgLen; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + sms_log(pMac, LOG1, FL("keylength is %d, Encry type is : %d"), + keyLength, edType); + do { + if ((1 != numKeys) && (0 != numKeys)) + break; + /* + * All of these fields appear in every SET_CONTEXT message. + * Below we'll add in the size for each key set. Since we only support + * up to one key, we always allocate memory for 1 key. + */ + msgLen = sizeof(struct sSirSmeSetContextReq); + + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, msgLen, 0); + pMsg->messageType = eWNI_SME_SETCONTEXT_REQ; + pMsg->length = msgLen; + pMsg->sessionId = (uint8_t) sessionId; + pMsg->transactionId = 0; + cdf_mem_copy(pMsg->peerMacAddr, peerMacAddr, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMsg->bssId, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + + /** + * Set the pMsg->keyMaterial.length field + * (this length is defined as all data that follows the + * edType field in the tSirKeyMaterial keyMaterial; field). + * + * NOTE: This keyMaterial.length contains the length of a + * MAX size key, though the keyLength can be shorter than this + * max size. Is LIM interpreting this ok ? + */ + pMsg->keyMaterial.length = + sizeof(pMsg->keyMaterial.numKeys) + + (numKeys * sizeof(pMsg->keyMaterial.key)); + pMsg->keyMaterial.edType = edType; + pMsg->keyMaterial.numKeys = numKeys; + pMsg->keyMaterial.key[0].keyId = keyId; + pMsg->keyMaterial.key[0].unicast = fUnicast; + pMsg->keyMaterial.key[0].keyDirection = aniKeyDirection; + cdf_mem_copy(pMsg->keyMaterial.key[0].keyRsc, + pKeyRsc, CSR_MAX_RSC_LEN); + /* 0 is Supplicant */ + pMsg->keyMaterial.key[0].paeRole = paeRole; + pMsg->keyMaterial.key[0].keyLength = keyLength; + if (keyLength && pKey) { + cdf_mem_copy(pMsg->keyMaterial.key[0].key, + pKey, keyLength); + sms_log(pMac, LOG1, + FL("SME set keyIndx (%d) encType (%d) key"), + keyId, edType); + sir_dump_buf(pMac, SIR_SMS_MODULE_ID, LOG1, pKey, + keyLength); + } + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamBssType bssType, + tCsrRoamStartBssParams *pParam, + tSirBssDescription *pBssDesc) +{ + tSirSmeStartBssReq *pMsg; + uint16_t wTmp; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + pMsg = cdf_mem_malloc(sizeof(tSirSmeStartBssReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pMsg, sizeof(tSirSmeStartBssReq), 0); + pMsg->messageType = eWNI_SME_START_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStartBssReq); + pMsg->transactionId = 0; + cdf_mem_copy(pMsg->bssId, pParam->bssid.bytes, sizeof(tSirMacAddr)); + /* selfMacAddr */ + cdf_mem_copy(pMsg->selfMacAddr, + pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + /* beaconInterval */ + if (pBssDesc && pBssDesc->beaconInterval) + wTmp = pBssDesc->beaconInterval; + else if (pParam->beaconInterval) + wTmp = pParam->beaconInterval; + else + wTmp = WNI_CFG_BEACON_INTERVAL_STADEF; + + if (csr_isconcurrentsession_valid(pMac, sessionId, pParam->bssPersona) + == CDF_STATUS_SUCCESS) { + csr_validate_mcc_beacon_interval(pMac, + pParam->operationChn, + &wTmp, + sessionId, + pParam->bssPersona); + /* Update the beacon Interval */ + pParam->beaconInterval = wTmp; + } else { + sms_log(pMac, LOGE, + FL("****Start BSS failed persona already exists***")); + cdf_mem_free(pMsg); + return CDF_STATUS_E_FAILURE; + } + pMsg->beaconInterval = wTmp; + pMsg->dot11mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pParam->uCfgDot11Mode); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMsg->cc_switch_mode = pMac->roam.configParam.cc_switch_mode; +#endif + pMsg->bssType = csr_translate_bsstype_to_mac_type(bssType); + cdf_mem_copy(&pMsg->ssId, &pParam->ssId, sizeof(pParam->ssId)); + pMsg->channelId = pParam->operationChn; + /* What should we really do for the cbmode. */ + pMsg->cbMode = (ePhyChanBondState) pParam->cbMode; + pMsg->vht_channel_width = pParam->ch_params.ch_width; + pMsg->center_freq_seg0 = pParam->ch_params.center_freq_seg0; + pMsg->center_freq_seg1 = pParam->ch_params.center_freq_seg1; + pMsg->sec_ch_offset = pParam->ch_params.sec_ch_offset; + pMsg->privacy = pParam->privacy; + pMsg->apUapsdEnable = pParam->ApUapsdEnable; + pMsg->ssidHidden = pParam->ssidHidden; + pMsg->fwdWPSPBCProbeReq = (uint8_t) pParam->fwdWPSPBCProbeReq; + pMsg->protEnabled = (uint8_t) pParam->protEnabled; + pMsg->obssProtEnabled = (uint8_t) pParam->obssProtEnabled; + /* set cfg related to protection */ + pMsg->ht_capab = pParam->ht_protection; + pMsg->authType = pParam->authType; + pMsg->dtimPeriod = pParam->dtimPeriod; + pMsg->wps_state = pParam->wps_state; + pMsg->isCoalesingInIBSSAllowed = pMac->isCoalesingInIBSSAllowed; + pMsg->bssPersona = pParam->bssPersona; + pMsg->txLdpcIniFeatureEnabled = pMac->roam.configParam.txLdpcEnable; +#ifdef WLAN_FEATURE_11W + pMsg->pmfCapable = pParam->mfpCapable; + pMsg->pmfRequired = pParam->mfpRequired; +#endif + + if (pParam->nRSNIELength > sizeof(pMsg->rsnIE.rsnIEdata)) { + cdf_mem_free(pMsg); + return CDF_STATUS_E_INVAL; + } + pMsg->rsnIE.length = pParam->nRSNIELength; + cdf_mem_copy(pMsg->rsnIE.rsnIEdata, + pParam->pRSNIE, + pParam->nRSNIELength); + pMsg->nwType = (tSirNwType)pParam->sirNwType; + cdf_mem_copy(&pMsg->operationalRateSet, + &pParam->operationalRateSet, + sizeof(tSirMacRateSet)); + cdf_mem_copy(&pMsg->extendedRateSet, + &pParam->extendedRateSet, + sizeof(tSirMacRateSet)); + cdf_mem_copy(&pMsg->htConfig, + &pSession->htConfig, + sizeof(tSirHTConfig)); + cdf_mem_copy(&pMsg->addIeParams, + &pParam->addIeParams, + sizeof(pParam->addIeParams)); + pMsg->obssEnabled = pMac->roam.configParam.obssEnabled; + pMsg->sap_dot11mc = pParam->sap_dot11mc; + + return cds_send_mb_message_to_mac(pMsg); +} + +CDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tSirSmeStopBssReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + pMsg = cdf_mem_malloc(sizeof(tSirSmeStopBssReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, sizeof(tSirSmeStopBssReq), 0); + pMsg->messageType = eWNI_SME_STOP_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStopBssReq); + pMsg->transactionId = 0; + pMsg->reasonCode = 0; + /* + * if BSSType is WDS sta, use selfmacAddr as bssid, + * else use bssid in connectedProfile + */ + if (CSR_IS_CONN_WDS_STA(&pSession->connectedProfile)) + cdf_mem_copy(&pMsg->bssId, + &pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + else + cdf_mem_copy(&pMsg->bssId, + &pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + return cds_send_mb_message_to_mac(pMsg); +} + +CDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t roamId = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if ((csr_is_conn_state_connected(pMac, sessionId)) && + (fForce || (!cdf_mem_compare(&pModProfileFields, + &pSession->connectedProfile. + modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))))) { + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) { + *pRoamId = roamId; + } + + status = + csr_roam_issue_reassoc(pMac, sessionId, NULL, + pModProfileFields, + eCsrSmeIssuedReassocToSameAP, + roamId, false); + } + return status; +} + +static CDF_STATUS csr_roam_session_opened(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + status = csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_RESULT_NONE); + return status; +} + +CDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + struct add_sta_self_params *rsp; + struct send_extcap_ie *msg; + CDF_STATUS status; + + if (pMsg == NULL) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, "in %s NO commands are ACTIVE ...", + __func__); + return CDF_STATUS_E_FAILURE; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandAddStaSession != pCommand->command) { + sms_log(pMac, LOGE, "in %s Cmd not in active list ...", + __func__); + return CDF_STATUS_E_FAILURE; + } + rsp = (struct add_sta_self_params *) pMsg; + sms_log(pMac, LOG1, "Add Sta self rsp status = %d", rsp->status); + + if (CDF_STATUS_SUCCESS == rsp->status && + (WMI_VDEV_TYPE_STA == rsp->type || + (WMI_VDEV_TYPE_AP == rsp->type && + WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == rsp->sub_type))) { + sms_log(pMac, LOG1, FL("send SET IE msg to PE")); + msg = cdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sms_log(pMac, LOGE, FL("Memory allocation failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set(msg, sizeof(*msg), 0); + msg->msg_type = eWNI_SME_SET_IE_REQ; + msg->session_id = rsp->session_id; + msg->length = sizeof(*msg); + status = cds_send_mb_message_to_mac(msg); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("Failed to send down the set IE req ")); + } + + csr_roam_session_opened(pMac, pCommand->sessionId); + /* Remove this command out of the active list */ + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + /* Now put this command back on the avilable command list */ + csr_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_issue_add_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr sessionMacAddr, + uint32_t type, uint32_t subType) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + status = CDF_STATUS_E_RESOURCES; + } else { + pCommand->command = eSmeCommandAddStaSession; + pCommand->sessionId = (uint8_t) sessionId; + cdf_mem_copy(pCommand->u.addStaSessionCmd.selfMacAddr, + sessionMacAddr, sizeof(tSirMacAddr)); + pCommand->u.addStaSessionCmd.currDeviceMode = + pMac->sme.currDeviceMode; + pCommand->u.addStaSessionCmd.type = type; + pCommand->u.addStaSessionCmd.subType = subType; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* Should be panic?? */ + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + } + } + return status; +} + +CDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + tAddStaForSessionCmd *pAddStaReq = + &pCommand->u.addStaSessionCmd; + uint8_t sessionId = pCommand->sessionId; + struct add_sta_self_params *add_sta_self_req; + CDF_STATUS status = CDF_STATUS_E_NOMEM; + tSirMsgQ msg; + + add_sta_self_req = cdf_mem_malloc(sizeof(struct add_sta_self_params)); + if (NULL == add_sta_self_req) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory for tAddSelfStaParams")); + return status; + } + + cdf_mem_copy(add_sta_self_req->self_mac_addr, pAddStaReq->selfMacAddr, + sizeof(tSirMacAddr)); + add_sta_self_req->curr_device_mode = pAddStaReq->currDeviceMode; + add_sta_self_req->session_id = sessionId; + add_sta_self_req->type = pAddStaReq->type; + add_sta_self_req->sub_type = pAddStaReq->subType; + + msg.type = WMA_ADD_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = add_sta_self_req; + msg.bodyval = 0; + + lim_log(pMac, LOG1, + FL + ("Send WMA_ADD_STA_SELF_REQ for selfMac=" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(add_sta_self_req->self_mac_addr)); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + status = wma_post_ctrl_msg(pMac, &msg); + + if (status != CDF_STATUS_SUCCESS) { + lim_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + cdf_mem_free(add_sta_self_req); + add_sta_self_req = NULL; + } + return status; +} + +CDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac, + csr_roam_completeCallback callback, + void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t i, value = 0; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + tCsrRoamSession *pSession; + *pbSessionId = CSR_SESSION_ID_INVALID; + + for (i = 0; i < pMac->sme.max_intf_count; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) { + pSession = CSR_GET_SESSION(pMac, i); + if (!pSession) { + sms_log(pMac, LOGE, + FL + ("Session does not exist for interface %d"), + i); + break; + } + status = CDF_STATUS_SUCCESS; + pSession->sessionActive = true; + pSession->sessionId = (uint8_t) i; + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Initialize FT related data structures only in STA mode */ + sme_ft_open(pMac, pSession->sessionId); +#endif + + pSession->callback = callback; + pSession->pContext = pContext; + cdf_mem_copy(&pSession->selfMacAddr, pSelfMacAddr, + sizeof(struct cdf_mac_addr)); + *pbSessionId = (uint8_t) i; + status = + cdf_mc_timer_init(&pSession->hTimerRoaming, + CDF_TIMER_TYPE_SW, + csr_roam_roaming_timer_handler, + &pSession->roamingTimerInfo); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for Roaming timer")); + break; + } + /* get the HT capability info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &value) + != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_CDF, + CDF_TRACE_LEVEL_ERROR, + "%s: could not get HT capability info", + __func__); + break; + } +#ifdef FEATURE_WLAN_BTAMP_UT_RF + status = cdf_mc_timer_init(&pSession->hTimerJoinRetry, + CDF_TIMER_TYPE_SW, + csr_roam_join_retry_timer_handler, + &pSession-> + joinRetryTimerInfo); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for join retry timer")); + break; + } +#endif + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value; + pSession->htConfig.ht_rx_ldpc = + uHTCapabilityInfo.htCapInfo.advCodingCap; + pSession->htConfig.ht_tx_stbc = + uHTCapabilityInfo.htCapInfo.txSTBC; + pSession->htConfig.ht_rx_stbc = + uHTCapabilityInfo.htCapInfo.rxSTBC; + pSession->htConfig.ht_sgi = true; + status = + csr_issue_add_sta_for_session_req(pMac, i, pSelfMacAddr, + type, subType); + break; + } + } + if (pMac->sme.max_intf_count == i) { + /* No session is available */ + sms_log(pMac, LOGE, + "%s: Reached max interfaces: %d! Session creation will fail", + __func__, pMac->sme.max_intf_count); + status = CDF_STATUS_E_RESOURCES; + } + return status; +} + +CDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + struct del_sta_self_params *rsp; + uint8_t sessionId; + + if (pMsg == NULL) { + sms_log(pMac, LOGE, FL("msg ptr is NULL")); + return status; + } + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, FL("NO commands are ACTIVE ...")); + return status; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sessionId = pCommand->sessionId; + if (eSmeCommandDelStaSession != pCommand->command) { + sms_log(pMac, LOGE, FL("NO Del sta session command ACTIVE")); + return status; + } + rsp = (struct del_sta_self_params *) pMsg; + sms_log(pMac, LOG1, FL("Del Sta rsp status = %d"), rsp->status); + /* This session is done. */ + csr_cleanup_session(pMac, sessionId); + if (pCommand->u.delStaSessionCmd.callback) { + status = sme_release_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOG1, FL("Failed to Release Lock")); + else { + pCommand->u.delStaSessionCmd. + callback(pCommand->u.delStaSessionCmd.pContext); + status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("Failed to get Lock")); + return status; + } + } + } + /* Remove this command out of the active list */ + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + /* Now put this command back on the avilable command list */ + csr_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + status = CDF_STATUS_SUCCESS; + return status; +} + + +CDF_STATUS csr_issue_del_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr sessionMacAddr, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + status = CDF_STATUS_E_RESOURCES; + } else { + pCommand->command = eSmeCommandDelStaSession; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.delStaSessionCmd.callback = callback; + pCommand->u.delStaSessionCmd.pContext = pContext; + cdf_mem_copy(pCommand->u.delStaSessionCmd.selfMacAddr, + sessionMacAddr, sizeof(tSirMacAddr)); + status = csr_queue_sme_command(pMac, pCommand, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* Should be panic?? */ + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + } + } + return status; +} + +CDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + struct del_sta_self_params *del_sta_self_req; + tSirMsgQ msg; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + del_sta_self_req = cdf_mem_malloc(sizeof(struct del_sta_self_params)); + if (NULL == del_sta_self_req) { + lim_log(pMac, LOGP, + FL(" mem alloc failed for tDelStaSelfParams")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(del_sta_self_req->self_mac_addr, + pCommand->u.delStaSessionCmd.selfMacAddr, + sizeof(tSirMacAddr)); + + del_sta_self_req->session_id = pCommand->sessionId; + msg.type = WMA_DEL_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = del_sta_self_req; + msg.bodyval = 0; + + sms_log(pMac, LOG1, + FL("sending WMA_DEL_STA_SELF_REQ")); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + status = wma_post_ctrl_msg(pMac, &msg); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + cdf_mem_free(del_sta_self_req); + } + return status; +} + +static void purge_csr_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tDblLinkList *pList = &pMac->roam.roamCmdPendingList; + tListElem *pEntry, *pNext; + tSmeCmd *pCommand; + tDblLinkList localList; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pNext = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->sessionId == sessionId) { + if (csr_ll_remove_entry(pList, pEntry, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + } + pEntry = pNext; + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + csr_abort_command(pMac, pCommand, true); + } + csr_ll_close(&localList); +} + +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + csr_roam_stop(pMac, sessionId); + + /* Clean up FT related data structures */ +#if defined WLAN_FEATURE_VOWIFI_11R + sme_ft_close(pMac, sessionId); +#endif + csr_free_connect_bss_desc(pMac, sessionId); + csr_roam_free_connect_profile(pMac, &pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + cdf_mc_timer_destroy(&pSession->hTimerRoaming); +#ifdef FEATURE_WLAN_BTAMP_UT_RF + cdf_mc_timer_destroy(&pSession->hTimerJoinRetry); +#endif + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeCmdPendingList); + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme. + smeScanCmdPendingList); + + purge_csr_session_cmd_list(pMac, sessionId); + csr_init_session(pMac, sessionId); + } +} + +CDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId, + bool fSync, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (fSync) { + csr_cleanup_session(pMac, sessionId); + } else { + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeCmdPendingList); + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeScanCmdPendingList); + + purge_csr_session_cmd_list(pMac, sessionId); + status = csr_issue_del_sta_for_session_req(pMac, + sessionId, + pSession->selfMacAddr.bytes, + callback, pContext); + } + } else { + status = CDF_STATUS_E_INVAL; + } + return status; +} + +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + pSession->sessionActive = false; + pSession->sessionId = CSR_SESSION_ID_INVALID; + pSession->callback = NULL; + pSession->pContext = NULL; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + csr_free_roam_profile(pMac, sessionId); + csr_roam_free_connect_profile(pMac, &pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + csr_free_connect_bss_desc(pMac, sessionId); + csr_scan_enable(pMac); + cdf_mem_set(&pSession->selfMacAddr, sizeof(struct cdf_mac_addr), 0); + if (pSession->pWpaRsnReqIE) { + cdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnRspIE) { + cdf_mem_free(pSession->pWpaRsnRspIE); + pSession->pWpaRsnRspIE = NULL; + } + pSession->nWpaRsnRspIeLength = 0; +#ifdef FEATURE_WLAN_WAPI + if (pSession->pWapiReqIE) { + cdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiRspIE) { + cdf_mem_free(pSession->pWapiRspIE); + pSession->pWapiRspIE = NULL; + } + pSession->nWapiRspIeLength = 0; +#endif /* FEATURE_WLAN_WAPI */ + if (pSession->pAddIEScan) { + cdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEAssoc) { + cdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + pSession->nAddIEAssocLength = 0; +} + +CDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, + struct cdf_mac_addr *bssid, + uint32_t *pSessionId) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint32_t i; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + if (cdf_is_macaddr_equal(bssid, + &pMac->roam.roamSession[i].connectedProfile. + bssid)) { + /* Found it */ + status = CDF_STATUS_SUCCESS; + *pSessionId = i; + break; + } + } + } + return status; +} + +/* This function assumes that we only support one IBSS session. We cannot use BSSID to identify */ +/* session because for IBSS, the bssid changes. */ +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac) +{ + uint32_t i, nRet = CSR_SESSION_ID_INVALID; + tCsrRoamSession *pSession; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + pSession = CSR_GET_SESSION(pMac, i); + if (pSession->pCurRoamProfile + && + (csr_is_bss_type_ibss + (pSession->connectedProfile.BSSType))) { + /* Found it */ + nRet = i; + break; + } + } + } + return nRet; +} + +static void csr_roam_link_up(tpAniSirGlobal pMac, struct cdf_mac_addr bssid) +{ + /* Update the current BSS info in ho control block based on connected + profile info from pmac global structure */ + + sms_log(pMac, LOGW, + " csr_roam_link_up: WLAN link UP with AP= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssid.bytes)); + /* Check for user misconfig of RSSI trigger threshold */ + pMac->roam.configParam.vccRssiThreshold = + (0 == pMac->roam.configParam.vccRssiThreshold) ? + CSR_VCC_RSSI_THRESHOLD : pMac->roam.configParam.vccRssiThreshold; + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; + /* Check for user misconfig of UL MAC Loss trigger threshold */ + pMac->roam.configParam.vccUlMacLossThreshold = + (0 == pMac->roam.configParam.vccUlMacLossThreshold) ? + CSR_VCC_UL_MAC_LOSS_THRESHOLD : pMac->roam.configParam. + vccUlMacLossThreshold; +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + { + uint32_t sessionId = 0; + /* Indicate the neighbor roal algorithm about the connect indication */ + csr_roam_get_session_id_from_bssid(pMac, &bssid, + &sessionId); + csr_neighbor_roam_indicate_connect(pMac, sessionId, + CDF_STATUS_SUCCESS); + } +#endif +} + +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + /* Only to handle the case for Handover on infra link */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) { + return; + } + /* + * Incase of station mode, immediately stop data transmission whenever + * link down is detected. + */ + if (csr_roam_is_sta_mode(pMac, sessionId) + && !CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) +#ifdef WLAN_FEATURE_VOWIFI_11R + && !csr_roam_is11r_assoc(pMac, sessionId) +#endif + ) { + sms_log(pMac, LOG1, FL("Inform Link lost for session %d"), + sessionId); + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_LOSTLINK); + } + /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */ + csr_roam_dereg_statistics_req(pMac); + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; +#if defined WLAN_FEATURE_NEIGHBOR_ROAMING + /* Indicate the neighbor roal algorithm about the disconnect indication */ + csr_neighbor_roam_indicate_disconnect(pMac, sessionId); +#endif + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + csr_is_infra_ap_started(pMac) && + pMac->roam.configParam.doBMPSWorkaround) { + pMac->roam.configParam.doBMPSWorkaround = 0; + } + +} + +void csr_roam_tl_stats_timer_handler(void *pv) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + CDF_STATUS status; + pMac->roam.tlStatsReqInfo.timerRunning = false; + + sms_log(pMac, LOG1, + FL + (" TL stat timer is no-op. It needs to support multiple stations")); + + if (!pMac->roam.tlStatsReqInfo.timerRunning) { + if (pMac->roam.tlStatsReqInfo.periodicity) { + /* start timer */ + status = + cdf_mc_timer_start(&pMac->roam.tlStatsReqInfo. + hTlStatsTimer, + pMac->roam.tlStatsReqInfo. + periodicity); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_tl_stats_timer_handler:cannot start TlStatsTimer timer")); + return; + } + pMac->roam.tlStatsReqInfo.timerRunning = true; + } + } +} + +void csr_roam_pe_stats_timer_handler(void *pv) +{ + tCsrPeStatsReqInfo *pPeStatsReqListEntry = (tCsrPeStatsReqInfo *) pv; + CDF_STATUS status; + tpAniSirGlobal pMac = pPeStatsReqListEntry->pMac; + CDF_STATUS cdf_status; + pPeStatsReqListEntry->timerRunning = false; + if (pPeStatsReqListEntry->timerStopFailed == true) { + /* If we entered here, meaning the timer could not be successfully */ + /* stopped in csr_roam_remove_entry_from_pe_stats_req_list(). So do it here. */ + + /* Destroy the timer */ + cdf_status = + cdf_mc_timer_destroy(&pPeStatsReqListEntry->hPeStatsTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:failed to destroy hPeStatsTimer timer")); + } + /* Free the entry */ + cdf_mem_free(pPeStatsReqListEntry); + pPeStatsReqListEntry = NULL; + } else { + if (!pPeStatsReqListEntry->rspPending) { + status = + csr_send_mb_stats_req_msg(pMac, + pPeStatsReqListEntry-> + statsMask & ~(1 << + eCsrGlobalClassDStats), + pPeStatsReqListEntry->staId, + pPeStatsReqListEntry-> + sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:failed to send down stats req to PE")); + } else { + pPeStatsReqListEntry->rspPending = true; + } + } + /* send down a req */ + if (pPeStatsReqListEntry->periodicity && + (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&pPeStatsReqListEntry-> + hPeStatsTimer))) { + if (pPeStatsReqListEntry->periodicity < + pMac->roam.configParam. + statsReqPeriodicityInPS) { + pPeStatsReqListEntry->periodicity = + pMac->roam.configParam. + statsReqPeriodicityInPS; + } + /* start timer */ + cdf_status = + cdf_mc_timer_start(&pPeStatsReqListEntry-> + hPeStatsTimer, + pPeStatsReqListEntry-> + periodicity); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:cannot start hPeStatsTimer timer")); + return; + } + pPeStatsReqListEntry->timerRunning = true; + + } + + } +} + +void csr_roam_stats_client_timer_handler(void *pv) +{ + tCsrStatsClientReqInfo *pStaEntry = (tCsrStatsClientReqInfo *) pv; + if (CDF_TIMER_STATE_STOPPED == + cdf_mc_timer_get_current_state(&pStaEntry->timer)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("roam stats client timer is stopped")); + } +} + +CDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask, + uint8_t staId, uint8_t sessionId) +{ + tAniGetPEStatsReq *pMsg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + pMsg = cdf_mem_malloc(sizeof(tAniGetPEStatsReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, FL("Failed to allocate mem for stats req ")); + return CDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_STATISTICS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetPEStatsReq); + pMsg->staId = staId; + pMsg->statsMask = statsMask; + pMsg->sessionId = sessionId; + status = cds_send_mb_message_to_mac(pMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("Failed to send down the stats req ")); + } + return status; +} + +/** + * csr_update_stats() - updates correct stats struct in mac_ctx + * @mac: mac global context + * @stats_type: stats type + * @sme_stats_rsp: stats rsp msg packet + * @stats: input stats data buffer to fill in mac_ctx struct + * @length: out param - stats length + * + * This function fills corresponding stats struct in mac_cts based on stats type + * passed + * + * Return: void + */ +static void +csr_update_stats(tpAniSirGlobal mac, uint8_t stats_type, + tAniGetPEStatsRsp *sme_stats_rsp, + uint8_t **stats, uint32_t *length) +{ + switch (stats_type) { + case eCsrSummaryStats: + sms_log(mac, LOG2, FL("summary stats")); + cdf_mem_copy((uint8_t *) &mac->roam.summaryStatsInfo, *stats, + sizeof(tCsrSummaryStatsInfo)); + *stats += sizeof(tCsrSummaryStatsInfo); + *length -= sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sms_log(mac, LOG2, FL("ClassA stats")); + cdf_mem_copy((uint8_t *) &mac->roam.classAStatsInfo, *stats, + sizeof(tCsrGlobalClassAStatsInfo)); + *stats += sizeof(tCsrGlobalClassAStatsInfo); + *length -= sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + sms_log(mac, LOG2, FL("ClassB stats")); + cdf_mem_copy((uint8_t *) &mac->roam.classBStatsInfo, *stats, + sizeof(tCsrGlobalClassBStatsInfo)); + *stats += sizeof(tCsrGlobalClassBStatsInfo); + *length -= sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + sms_log(mac, LOG2, FL("ClassC stats")); + cdf_mem_copy((uint8_t *) &mac->roam.classCStatsInfo, *stats, + sizeof(tCsrGlobalClassCStatsInfo)); + *stats += sizeof(tCsrGlobalClassCStatsInfo); + *length -= sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrPerStaStats: + sms_log(mac, LOG2, FL("PerSta stats")); + if (CSR_MAX_STA > sme_stats_rsp->staId) { + cdf_mem_copy( + &mac->roam.perStaStatsInfo[sme_stats_rsp->staId], + *stats, sizeof(tCsrPerStaStatsInfo)); + } else { + sms_log(mac, LOGE, FL("out bound staId:%d. failed to copy PerSta stats"), + sme_stats_rsp->staId); + CDF_ASSERT(0); + } + *stats += sizeof(tCsrPerStaStatsInfo); + *length -= sizeof(tCsrPerStaStatsInfo); + break; + default: + sms_log(mac, LOGW, FL("unknown stats type")); + break; + } +} + +/** + * csr_roam_stats_rsp_processor() - processes stats rsp msg + * @pMac mac global context + * @pSirMsg: incoming message + * + * Return: void + */ +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) +{ + tAniGetPEStatsRsp *pSmeStatsRsp; + tListElem *pEntry = NULL; + tCsrStatsClientReqInfo *pTempStaEntry = NULL; + tCsrPeStatsReqInfo *pPeStaEntry = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + uint8_t *pStats = NULL; + uint32_t length = 0; + void *p_cds_gctx; + int8_t rssi = 0, snr = 0; + uint32_t *pRssi = NULL, *pSnr = NULL; + uint32_t linkCapacity; + pSmeStatsRsp = (tAniGetPEStatsRsp *) pSirMsg; + + if (pSmeStatsRsp->rc) { + sms_log(pMac, LOGW, FL("stats rsp from PE shows failure")); + goto post_update; + } + tempMask = pSmeStatsRsp->statsMask; + pStats = ((uint8_t *) &pSmeStatsRsp->statsMask) + + sizeof(pSmeStatsRsp->statsMask); + /* + * subtract all statistics from this length, and after processing the + * entire 'stat' part of the message, if the length is not zero, then + * rssi is piggy packed in this 'stats' message. + */ + length = pSmeStatsRsp->msgLen - sizeof(tAniGetPEStatsRsp); + /* new stats info from PE, fill up the stats strucutres in PMAC */ + while (tempMask) { + if (tempMask & 1) { + csr_update_stats(pMac, counter, pSmeStatsRsp, + &pStats, &length); + } + tempMask >>= 1; + counter++; + } + p_cds_gctx = cds_get_global_context(); + if (length != 0) { + pRssi = (uint32_t *) pStats; + rssi = (int8_t) *pRssi; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else { + /* If riva is not sending rssi, continue to use the hack */ + rssi = RSSI_HACK_BMPS; + } + + if (length != 0) { + linkCapacity = *(uint32_t *) pStats; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else { + linkCapacity = 0; + } + + if (length != 0) { + pSnr = (uint32_t *) pStats; + snr = (int8_t) *pSnr; + } else { + snr = SNR_HACK_BMPS; + } + +post_update: + /* make sure to update the pe stats req list */ + pEntry = csr_roam_find_in_pe_stats_req_list(pMac, pSmeStatsRsp->statsMask); + if (pEntry) { + pPeStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + pPeStaEntry->rspPending = false; + + } + /* check the one timer cases */ + pEntry = csr_roam_check_client_req_list(pMac, pSmeStatsRsp->statsMask); + if (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if (pTempStaEntry->timerExpired) { + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + /* also remove from the client list */ + csr_roam_remove_stat_list_entry(pMac, pEntry); + pTempStaEntry = NULL; + } + } +} + +tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask) +{ + tListElem *pEntry = NULL; + tCsrPeStatsReqInfo *pTempStaEntry = NULL; + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_find_in_pe_stats_req_list: List empty, no request to PE"); + return NULL; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + if (pTempStaEntry->statsMask == statsMask) { + sms_log(pMac, LOG3, + "csr_roam_find_in_pe_stats_req_list: match found"); + break; + } + pEntry = + csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +tListElem *csr_roam_checkn_update_client_req_list(tpAniSirGlobal pMac, + tCsrStatsClientReqInfo *pStaEntry, + bool update) +{ + tListElem *pEntry; + tCsrStatsClientReqInfo *pTempStaEntry; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_checkn_update_client_req_list: List empty, no request from " + "upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if ((pTempStaEntry->requesterId == pStaEntry->requesterId) + && (pTempStaEntry->statsMask == pStaEntry->statsMask)) { + sms_log(pMac, LOG3, + "csr_roam_checkn_update_client_req_list: match found"); + if (update) { + pTempStaEntry->periodicity = + pStaEntry->periodicity; + pTempStaEntry->callback = pStaEntry->callback; + pTempStaEntry->pContext = pStaEntry->pContext; + } + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask) +{ + tListElem *pEntry; + tCsrStatsClientReqInfo *pTempStaEntry; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_check_client_req_list: List empty, no request from " + "upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if ((pTempStaEntry-> + statsMask & ~(1 << eCsrGlobalClassDStats)) == statsMask) { + sms_log(pMac, LOG3, + "csr_roam_check_client_req_list: match found"); + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +void csr_roam_vcc_trigger(tpAniSirGlobal pMac) +{ + eCsrRoamLinkQualityInd newVccLinkQuality; + uint32_t ul_mac_loss = 0; + uint32_t ul_mac_loss_trigger_threshold; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + /*------------------------------------------------------------------------- + Link quality is currently binary based on OBIWAN recommended triggers + Check for a change in link quality and notify client if necessary + -------------------------------------------------------------------------*/ + ul_mac_loss_trigger_threshold = + pMac->roam.configParam.vccUlMacLossThreshold; + if (0 == ul_mac_loss_trigger_threshold) { + CDF_ASSERT(ul_mac_loss_trigger_threshold != 0); + return; + } + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: UL_MAC_LOSS_THRESHOLD is %d", + ul_mac_loss_trigger_threshold); + if (ul_mac_loss_trigger_threshold < ul_mac_loss) { + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is POOR "); + newVccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; + } else { + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is GOOD"); + newVccLinkQuality = eCSR_ROAM_LINK_QUAL_GOOD_IND; + } + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link qual : *** UL_MAC_LOSS %d *** ", + ul_mac_loss); + if (newVccLinkQuality != pMac->roam.vccLinkQuality) { + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link quality changed: trigger necessary"); + if (NULL != pMac->roam.linkQualityIndInfo.callback) { + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link quality indication %d", + newVccLinkQuality); + + /* we now invoke the callback once to notify client of initial value */ + pMac->roam.linkQualityIndInfo. + callback(newVccLinkQuality, + pMac->roam.linkQualityIndInfo.context); + /* event: EVENT_WLAN_VCC */ + } + } + pMac->roam.vccLinkQuality = newVccLinkQuality; + +} + +tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac, + tDblLinkList *pStaList, + tCsrStatsClientReqInfo * + pStaEntry) +{ + tCsrStatsClientReqInfo *pNewStaEntry = NULL; + /* if same entity requested for same set of stats with different periodicity & */ + /* callback update it */ + if (NULL == csr_roam_checkn_update_client_req_list(pMac, pStaEntry, true)) { + + pNewStaEntry = cdf_mem_malloc(sizeof(tCsrStatsClientReqInfo)); + if (NULL == pNewStaEntry) { + sms_log(pMac, LOGW, + "csr_roam_insert_entry_into_list: couldn't allocate memory for the " + "entry"); + return NULL; + } + + pNewStaEntry->callback = pStaEntry->callback; + pNewStaEntry->pContext = pStaEntry->pContext; + pNewStaEntry->periodicity = pStaEntry->periodicity; + pNewStaEntry->requesterId = pStaEntry->requesterId; + pNewStaEntry->statsMask = pStaEntry->statsMask; + pNewStaEntry->pPeStaEntry = pStaEntry->pPeStaEntry; + pNewStaEntry->pMac = pStaEntry->pMac; + pNewStaEntry->staId = pStaEntry->staId; + pNewStaEntry->timerExpired = pStaEntry->timerExpired; + + csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK); + } + return pNewStaEntry; +} + +tCsrPeStatsReqInfo *csr_roam_insert_entry_into_pe_stats_req_list(tpAniSirGlobal pMac, + tDblLinkList * + pStaList, + tCsrPeStatsReqInfo * + pStaEntry) +{ + tCsrPeStatsReqInfo *pNewStaEntry = NULL; + pNewStaEntry = cdf_mem_malloc(sizeof(tCsrPeStatsReqInfo)); + if (NULL == pNewStaEntry) { + sms_log(pMac, LOGW, + "csr_roam_insert_entry_into_pe_stats_req_list: couldn't allocate memory for the " + "entry"); + return NULL; + } + + pNewStaEntry->hPeStatsTimer = pStaEntry->hPeStatsTimer; + pNewStaEntry->numClient = pStaEntry->numClient; + pNewStaEntry->periodicity = pStaEntry->periodicity; + pNewStaEntry->statsMask = pStaEntry->statsMask; + pNewStaEntry->pMac = pStaEntry->pMac; + pNewStaEntry->staId = pStaEntry->staId; + pNewStaEntry->timerRunning = pStaEntry->timerRunning; + pNewStaEntry->rspPending = pStaEntry->rspPending; + + csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK); + return pNewStaEntry; +} + +CDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, + tCsrRssiCallback callback, + uint8_t staId, + struct cdf_mac_addr bssId, + int8_t lastRSSI, void *pContext, void *p_cds_context) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t msg; + uint32_t sessionId; + + tAniGetRssiReq *pMsg; + sms_log(pMac, LOG2, FL("called")); + + status = csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + callback(lastRSSI, staId, pContext); + sms_log(pMac, LOGE, FL("Failed to get SessionId")); + return CDF_STATUS_E_FAILURE; + } + + pMsg = cdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csr_get_rssi: failed to allocate mem for req "); + return CDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GET_RSSI_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetRssiReq); + pMsg->sessionId = sessionId; + pMsg->staId = staId; + pMsg->rssiCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + /* + * store RSSI at time of calling, so that if RSSI request cannot + * be sent to firmware, this value can be used to return immediately + */ + pMsg->lastRSSI = lastRSSI; + msg.type = eWNI_SME_GET_RSSI_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, " csr_get_rssi failed to post msg to self "); + cdf_mem_free((void *)pMsg); + status = CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG2, FL("returned")); + return status; +} + +CDF_STATUS csr_get_snr(tpAniSirGlobal pMac, + tCsrSnrCallback callback, + uint8_t staId, struct cdf_mac_addr bssId, void *pContext) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t msg; + uint32_t sessionId; + + tAniGetSnrReq *pMsg; + + sms_log(pMac, LOG2, FL("called")); + + pMsg = (tAniGetSnrReq *) cdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, "%s: failed to allocate mem for req", + __func__); + return CDF_STATUS_E_NOMEM; + } + + csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId); + + pMsg->msgType = eWNI_SME_GET_SNR_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetSnrReq); + pMsg->sessionId = sessionId; + pMsg->staId = staId; + pMsg->snrCallback = callback; + pMsg->pDevContext = pContext; + msg.type = eWNI_SME_GET_SNR_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, "%s failed to post msg to self", __func__); + cdf_mem_free((void *)pMsg); + status = CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG2, FL("returned")); + return status; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + struct cdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tAniGetTsmStatsReq *pMsg = NULL; + pMsg = cdf_mem_malloc(sizeof(tAniGetTsmStatsReq)); + if (!pMsg) { + sms_log(pMac, LOGE, + "csr_get_tsm_stats: failed to allocate mem for req"); + return CDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_TSM_STATS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetTsmStatsReq); + pMsg->staId = staId; + pMsg->tid = tid; + cdf_mem_copy(pMsg->bssId, bssId.bytes, sizeof(tSirMacAddr)); + pMsg->tsmStatsCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + status = cds_send_mb_message_to_mac(pMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, + " csr_get_tsm_stats: failed to send down the rssi req"); + /* pMsg is freed by cds_send_mb_message_to_mac */ + status = CDF_STATUS_E_FAILURE; + } + return status; +} +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +/** + * csr_deregister_client_request() - deregisters a get stats request + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * + * Return: status of operation + */ +static CDF_STATUS +csr_deregister_client_request(tpAniSirGlobal mac_ctx, + tCsrStatsClientReqInfo *sta_entry) +{ + CDF_STATUS status; + tListElem *entry = NULL; + tCsrStatsClientReqInfo *ptr_sta_entry = NULL; + + entry = csr_roam_checkn_update_client_req_list(mac_ctx, sta_entry, + false); + if (!entry) { + sms_log(mac_ctx, LOGW, + FL("callback is empty in the request & couldn't find any existing request in statsClientReqList")); + return CDF_STATUS_E_FAILURE; + } + /* clean up & return */ + ptr_sta_entry = GET_BASE_ADDR(entry, tCsrStatsClientReqInfo, link); + if (NULL != ptr_sta_entry->pPeStaEntry) { + ptr_sta_entry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from peStatsReqList */ + if (!ptr_sta_entry->pPeStaEntry->numClient) + csr_roam_remove_entry_from_pe_stats_req_list(mac_ctx, + ptr_sta_entry->pPeStaEntry); + } + /* check if we need to stop the tl stats timer too */ + mac_ctx->roam.tlStatsReqInfo.numClient--; + if (!mac_ctx->roam.tlStatsReqInfo.numClient) { + if (mac_ctx->roam.tlStatsReqInfo.timerRunning) { + status = cdf_mc_timer_stop( + &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot stop TlStatsTimer timer")); + return status; + } + } + mac_ctx->roam.tlStatsReqInfo.periodicity = 0; + mac_ctx->roam.tlStatsReqInfo.timerRunning = false; + } + cdf_mc_timer_stop(&ptr_sta_entry->timer); + /* Destroy the cdf timer... */ + status = cdf_mc_timer_destroy(&ptr_sta_entry->timer); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(mac_ctx, LOGE, + FL("failed to destroy Client req timer")); + + csr_roam_remove_stat_list_entry(mac_ctx, entry); + return CDF_STATUS_SUCCESS; +} + +/** + * csr_insert_stats_request_to_list() - inserts request to existing list + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * @periodicity: periodicity of stats + * + * Return: status of operation + */ +static CDF_STATUS +csr_insert_stats_request_to_list(tpAniSirGlobal mac_ctx, + tCsrStatsClientReqInfo *sta_entry, + uint32_t periodicity) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrStatsClientReqInfo *ptr_sta_entry = csr_roam_insert_entry_into_list( + mac_ctx, &mac_ctx->roam.statsClientReqList, + sta_entry); + if (!ptr_sta_entry) { + sms_log(mac_ctx, LOGW, + FL("Failed to insert req in statsClientReqList")); + return CDF_STATUS_E_FAILURE; + } + /* Init & start timer if needed */ + ptr_sta_entry->periodicity = periodicity; + if (ptr_sta_entry->periodicity) { + status = cdf_mc_timer_init(&ptr_sta_entry->timer, + CDF_TIMER_TYPE_SW, + csr_roam_stats_client_timer_handler, + ptr_sta_entry); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot init StatsClient timer")); + return CDF_STATUS_E_FAILURE; + } + status = cdf_mc_timer_start(&ptr_sta_entry->timer, + ptr_sta_entry->periodicity); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot start StatsClient timer")); + return CDF_STATUS_E_FAILURE; + } + } + return status; +} + +/** + * csr_get_statistics_from_tl() - fetch stats from tl layer + * @mac_ctx: mac global context + * @cache: indicate if cached stats are required + * @staId: station id + * @periodicity: periodicity of stats + * + * Return: status of operation + */ +static CDF_STATUS +csr_get_statistics_from_tl(tpAniSirGlobal mac_ctx, + bool cache, + uint8_t staId, + uint32_t periodicity) +{ + CDF_STATUS status; + + if (cache && mac_ctx->roam.tlStatsReqInfo.numClient) { + sms_log(mac_ctx, LOGE, FL("Looking for cached stats from TL")); + mac_ctx->roam.tlStatsReqInfo.numClient++; + return CDF_STATUS_SUCCESS; + } + + /* update periodicity */ + if (mac_ctx->roam.tlStatsReqInfo.periodicity) + mac_ctx->roam.tlStatsReqInfo.periodicity = + CDF_MIN(periodicity, + mac_ctx->roam.tlStatsReqInfo.periodicity); + else + mac_ctx->roam.tlStatsReqInfo.periodicity = periodicity; + + if (mac_ctx->roam.tlStatsReqInfo.periodicity + < CSR_MIN_TL_STAT_QUERY_PERIOD) { + mac_ctx->roam.tlStatsReqInfo.periodicity = + CSR_MIN_TL_STAT_QUERY_PERIOD; + } + + if (!mac_ctx->roam.tlStatsReqInfo.timerRunning) { + + if (mac_ctx->roam.tlStatsReqInfo.periodicity) { + /* start timer */ + status = cdf_mc_timer_start( + &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer, + mac_ctx->roam.tlStatsReqInfo.periodicity); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot start TlStatsTimer timer")); + return CDF_STATUS_E_FAILURE; + } + mac_ctx->roam.tlStatsReqInfo.timerRunning = true; + } + } + mac_ctx->roam.tlStatsReqInfo.numClient++; + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, + tCsrStatsCallback callback, + uint32_t periodicity, + bool cache, + uint8_t staId, + void *pContext, + uint8_t sessionId) +{ + tCsrStatsClientReqInfo staEntry; + tCsrPeStatsReqInfo *pPeStaEntry = NULL; + bool found = false; + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool insertInClientList = false; + uint32_t temp_mask = 0; + + if (csr_is_all_session_disconnected(pMac)) + return CDF_STATUS_E_FAILURE; + + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) { + sms_log(pMac, LOG1, FL("in the middle of roaming states")); + return CDF_STATUS_E_FAILURE; + } + + if ((!statsMask) && (!callback)) { + sms_log(pMac, LOGW, + FL("statsMask & callback empty in the request")); + return CDF_STATUS_E_FAILURE; + } + /* for the search list method for deregister */ + staEntry.requesterId = requesterId; + staEntry.statsMask = statsMask; + /* requester wants to deregister or just an error */ + if ((statsMask) && (!callback)) + return csr_deregister_client_request(pMac, &staEntry); + + if (cache && !periodicity) { + /* return the cached stats */ + csr_roam_report_statistics(pMac, statsMask, callback, staId, + pContext); + return CDF_STATUS_SUCCESS; + } + /* add the request in the client req list */ + staEntry.callback = callback; + staEntry.pContext = pContext; + staEntry.periodicity = periodicity; + staEntry.pPeStaEntry = NULL; + staEntry.staId = staId; + staEntry.pMac = pMac; + staEntry.timerExpired = false; + staEntry.sessionId = sessionId; + + /* if periodic report requested with non cached result from PE/TL */ + if (periodicity) { + /* if looking for stats from PE */ + temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats); + if (temp_mask) { + /* check if same req made already & waiting for rsp */ + pPeStaEntry = csr_roam_check_pe_stats_req_list(pMac, + temp_mask, periodicity, &found, + staId, sessionId); + if (!pPeStaEntry) + /* bail out, maxed out on num of req for PE */ + return CDF_STATUS_E_FAILURE; + else + staEntry.pPeStaEntry = pPeStaEntry; + } + /* + * request stats from TL rightaway if requested by client, + * update tlStatsReqInfo if needed + */ + temp_mask = statsMask & (1 << eCsrGlobalClassDStats); + if (temp_mask) { + status = csr_get_statistics_from_tl(pMac, cache, staId, + periodicity); + if (!CDF_IS_STATUS_SUCCESS(status)) + return status; + } + insertInClientList = true; + } + /* if one time report requested with non cached result from PE/TL */ + else if (!cache && !periodicity) { + temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats); + if (temp_mask) { + /* send down a req */ + status = csr_send_mb_stats_req_msg(pMac, + temp_mask, staId, sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("failed to send down stats req")); + /* + * so that when the stats rsp comes back from PE we + * respond to upper layer right away + */ + staEntry.timerExpired = true; + insertInClientList = true; + } + /* if looking for stats from TL only */ + if (!insertInClientList) { + /* return the stats */ + csr_roam_report_statistics(pMac, statsMask, callback, + staId, pContext); + return CDF_STATUS_SUCCESS; + } + } + if (insertInClientList) + return csr_insert_stats_request_to_list(pMac, &staEntry, + periodicity); + + return CDF_STATUS_SUCCESS; +} + +static tSirRetStatus +csr_roam_scan_offload_populate_mac_header(tpAniSirGlobal pMac, + uint8_t *pBD, + uint8_t type, + uint8_t subType, + tSirMacAddr peerAddr, + tSirMacAddr selfMacAddr) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + tpSirMacMgmtHdr pMacHdr; + + /* Prepare MAC management header */ + pMacHdr = (tpSirMacMgmtHdr) (pBD); + + /* Prepare FC */ + pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + pMacHdr->fc.type = type; + pMacHdr->fc.subType = subType; + + /* Prepare Address 1 */ + cdf_mem_copy((uint8_t *) pMacHdr->da, (uint8_t *) peerAddr, + sizeof(tSirMacAddr)); + + sir_copy_mac_addr(pMacHdr->sa, selfMacAddr); + + /* Prepare Address 3 */ + cdf_mem_copy((uint8_t *) pMacHdr->bssId, (uint8_t *) peerAddr, + sizeof(tSirMacAddr)); + return statusCode; +} /*** csr_roam_scan_offload_populate_mac_header() ***/ + +static tSirRetStatus +csr_roam_scan_offload_prepare_probe_req_template(tpAniSirGlobal pMac, + uint8_t nChannelNum, + uint32_t dot11mode, + tSirMacAddr selfMacAddr, + uint8_t *pFrame, + uint16_t *pusLen, + tCsrRoamSession *psession) +{ + tDot11fProbeRequest pr; + uint32_t nStatus, nBytes, nPayload; + tSirRetStatus nSirStatus; + /*Bcast tx */ + tSirMacAddr bssId = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + cdf_mem_set((uint8_t *) &pr, sizeof(pr), 0); + + populate_dot11f_supp_rates(pMac, nChannelNum, &pr.SuppRates, NULL); + + if (WNI_CFG_DOT11_MODE_11B != dot11mode) { + populate_dot11f_ext_supp_rates1(pMac, nChannelNum, + &pr.ExtSuppRates); + } + + if (IS_DOT11_MODE_HT(dot11mode)) { + populate_dot11f_ht_caps(pMac, NULL, &pr.HTCaps); + pr.HTCaps.advCodingCap = psession->htConfig.ht_rx_ldpc; + pr.HTCaps.txSTBC = psession->htConfig.ht_tx_stbc; + pr.HTCaps.rxSTBC = psession->htConfig.ht_rx_stbc; + if (!psession->htConfig.ht_sgi) { + pr.HTCaps.shortGI20MHz = pr.HTCaps.shortGI40MHz = 0; + } + } + + nStatus = dot11f_get_packed_probe_request_size(pMac, &pr, &nPayload); + if (DOT11F_FAILED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to calculate the packed size f" + "or a Probe Request (0x%08x).\n", nStatus); + + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "There were warnings while calculating" + "the packed size for a Probe Request (" + "0x%08x).\n", nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + /* Prepare outgoing frame */ + cdf_mem_set(pFrame, nBytes, 0); + + nSirStatus = + csr_roam_scan_offload_populate_mac_header(pMac, pFrame, + SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_REQ, bssId, + selfMacAddr); + + if (eSIR_SUCCESS != nSirStatus) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to populate the buffer descriptor for a Probe Request (%d).\n", + nSirStatus); + return nSirStatus; + } + + nStatus = dot11f_pack_probe_request(pMac, &pr, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Failed to pack a Probe Request (0x%08x).\n", + nStatus); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "There were warnings while packing a Probe Request (0x%08x).\n", + nStatus); + } + + *pusLen = nPayload + sizeof(tSirMacMgmtHdr); + return eSIR_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal pMac, + uint32_t sessionId, + bool nRoamKeyMgmtOffloadEnabled) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + pSession->RoamKeyMgmtOffloadEnabled = nRoamKeyMgmtOffloadEnabled; + return CDF_STATUS_SUCCESS; +} + +/** + * csr_update_roam_scan_offload_request() - updates req msg with roam offload + * paramters + * @pMac: mac global context + * @req_buf: out param, roam offload scan request packet + * @session: roam session + * + * Return: void + */ +static void +csr_update_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, + tCsrRoamSession *session) +{ + cdf_mem_copy(req_buf->PSK_PMK, session->psk_pmk, + sizeof(req_buf->PSK_PMK)); + req_buf->pmk_len = session->pmk_len; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR3: PMK Length = %d", req_buf->pmk_len); + req_buf->R0KH_ID_Length = session->ftSmeContext.r0kh_id_len; + cdf_mem_copy(req_buf->R0KH_ID, + session->ftSmeContext.r0kh_id, + req_buf->R0KH_ID_Length); + req_buf->Prefer5GHz = mac_ctx->roam.configParam.nRoamPrefer5GHz; + req_buf->RoamRssiCatGap = mac_ctx->roam.configParam.bCatRssiOffset; + req_buf->Select5GHzMargin = mac_ctx->roam.configParam.nSelect5GHzMargin; + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &req_buf->ReassocFailureTimeout) + != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGE, + FL("could not retrieve ReassocFailureTimeout value")); + req_buf->ReassocFailureTimeout = + DEFAULT_REASSOC_FAILURE_TIMEOUT; + } +#ifdef FEATURE_WLAN_ESE + if (csr_is_auth_type_ese(req_buf->ConnectedNetwork.authentication)) { + cdf_mem_copy(req_buf->KRK, session->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); + cdf_mem_copy(req_buf->BTK, session->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); + } +#endif + req_buf->AcUapsd.acbe_uapsd = + SIR_UAPSD_GET(ACBE, mac_ctx->lim.gUapsdPerAcBitmask); + req_buf->AcUapsd.acbk_uapsd = + SIR_UAPSD_GET(ACBK, mac_ctx->lim.gUapsdPerAcBitmask); + req_buf->AcUapsd.acvi_uapsd = + SIR_UAPSD_GET(ACVI, mac_ctx->lim.gUapsdPerAcBitmask); + req_buf->AcUapsd.acvo_uapsd = + SIR_UAPSD_GET(ACVO, mac_ctx->lim.gUapsdPerAcBitmask); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * csr_check_band_channel_match() - check if passed band and channel match + * paramters + * @band: band to match with channel + * @channel: channel to match with band + * + * Return: bool if match else false + */ +static bool +csr_check_band_channel_match(eCsrBand band, uint8_t channel) +{ + if (eCSR_BAND_ALL == band) + return true; + + if (eCSR_BAND_24 == band && CDS_IS_CHANNEL_24GHZ(channel)) + return true; + + if (eCSR_BAND_5G == band && CDS_IS_CHANNEL_5GHZ(channel)) + return true; + + return false; +} + +/** + * csr_fetch_ch_lst_from_ini() - fetch channel list from ini and update req msg + * paramters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @req_buf: out param, roam offload scan request packet + * + * Return: result of operation + */ +static CDF_STATUS +csr_fetch_ch_lst_from_ini(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tSirRoamOffloadScanReq *req_buf) +{ + eCsrBand band; + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = roam_info->cfgParams.channelInfo.ChannelList; + /* + * The INI channels need to be filtered with respect to the current band + * that is supported. + */ + band = mac_ctx->roam.configParam.bandCapability; + if ((eCSR_BAND_24 != band) && (eCSR_BAND_5G != band) + && (eCSR_BAND_ALL != band)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Invalid band(%d), roam scan offload req aborted"), + band); + return CDF_STATUS_E_FAILURE; + } + + for (i = 0; i < roam_info->cfgParams.channelInfo.numOfChannels; i++) { + if (!csr_check_band_channel_match(band, *ch_lst)) + continue; + /* Allow DFS channels only if the DFS roaming is enabled */ + if (((mac_ctx->roam.configParam.allowDFSChannelRoam != + CSR_ROAMING_DFS_CHANNEL_DISABLED) + || (!CDS_IS_DFS_CH(*ch_lst))) + && csr_roam_is_channel_valid(mac_ctx, *ch_lst) + && *ch_lst && (num_channels < SIR_ROAM_MAX_CHANNELS)) { + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + } + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_STATIC; + return CDF_STATUS_SUCCESS; +} + +/** + * csr_fetch_ch_lst_from_occupied_lst() - fetch channel list from occupied list + * and update req msg + * paramters + * @mac_ctx: global mac ctx + * @session_id: session id + * @reason: reason to roam + * @req_buf: out param, roam offload scan request packet + * @roam_info: roam info struct + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_occupied_lst(tpAniSirGlobal mac_ctx, + uint8_t session_id, + uint8_t reason, + tSirRoamOffloadScanReq *req_buf, + tpCsrNeighborRoamControlInfo roam_info) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = + mac_ctx->scan.occupiedChannels[session_id].channelList; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Num of channels before filtering=%d", + mac_ctx->scan.occupiedChannels[session_id].numChannels); + for (i = 0; i < mac_ctx->scan.occupiedChannels[session_id].numChannels; + i++) { + if (((mac_ctx->roam.configParam.allowDFSChannelRoam != + CSR_ROAMING_DFS_CHANNEL_DISABLED) + || (!CDS_IS_DFS_CH(*ch_lst))) + && *ch_lst && (num_channels < SIR_ROAM_MAX_CHANNELS)) { + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + } + if (*ch_lst) + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "DFSRoam=%d, ChnlState=%d, Chnl=%d, num_ch=%d", + mac_ctx->roam.configParam.allowDFSChannelRoam, + cds_get_channel_state(*ch_lst), *ch_lst, + num_channels); + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + /* + * If the profile changes as to what it was earlier, inform the FW + * through FLUSH as ChannelCacheType in which case, the FW will flush + * the occupied channels for the earlier profile and try to learn them + * afresh + */ + if (reason == REASON_FLUSH_CHANNEL_LIST) + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_FLUSH; + else { + if (csr_neighbor_roam_is_new_connected_profile(mac_ctx, + session_id)) + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_INIT; + else + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE; + } +} + +#ifdef FEATURE_WLAN_ESE +/** + * csr_fetch_ch_lst_from_received_list() - fetch channel list from received list + * and update req msg + * paramters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @curr_ch_lst_info: current channel list info + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_received_list(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tpCsrChannelInfo curr_ch_lst_info, + tSirRoamOffloadScanReq *req_buf) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = NULL; + + if (curr_ch_lst_info->numOfChannels == 0) + return; + + ch_lst = curr_ch_lst_info->ChannelList; + for (i = 0; i < curr_ch_lst_info->numOfChannels; i++) { + if (((mac_ctx->roam.configParam.allowDFSChannelRoam + != CSR_ROAMING_DFS_CHANNEL_DISABLED) || + (!CDS_IS_DFS_CH(*ch_lst))) && *ch_lst) { + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + } + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE; +} +#endif + +/** + * csr_fetch_valid_ch_lst() - fetch channel list from valid channel list and + * update req msg + * paramters + * @mac_ctx: global mac ctx + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static CDF_STATUS +csr_fetch_valid_ch_lst(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf) +{ + CDF_STATUS status; + uint32_t host_channels = 0; + uint8_t *ch_lst = NULL; + uint8_t i = 0, num_channels = 0; + + host_channels = sizeof(mac_ctx->roam.validChannelList); + status = csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &host_channels); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to get the valid channel list")); + return status; + } + ch_lst = mac_ctx->roam.validChannelList; + mac_ctx->roam.numValidChannels = host_channels; + for (i = 0; i < mac_ctx->roam.numValidChannels; i++) { + if (((mac_ctx->roam.configParam.allowDFSChannelRoam + != CSR_ROAMING_DFS_CHANNEL_DISABLED) || + (!CDS_IS_DFS_CH(*ch_lst))) && *ch_lst) { + req_buf->ValidChannelList[num_channels++] = *ch_lst; + } + ch_lst++; + } + req_buf->ValidChannelCount = num_channels; + return status; +} + +/** + * csr_create_roam_scan_offload_request() - init roam offload scan request + * + * paramters + * @mac_ctx: global mac ctx + * @command: roam scan offload command input + * @session_id: session id + * @reason: reason to roam + * @session: roam session + * @roam_info: roam info struct + * + * Return: roam offload scan request packet buffer + */ +static tSirRoamOffloadScanReq * +csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + uint8_t command, + uint8_t session_id, + uint8_t reason, + tCsrRoamSession *session, + tpCsrNeighborRoamControlInfo roam_info) +{ + CDF_STATUS status; + uint8_t i, j, dot11_mode; + bool ese_neighbor_list_recvd = false; + uint8_t ch_cache_str[128] = { 0 }; + tSirRoamOffloadScanReq *req_buf = NULL; + tpCsrChannelInfo curr_ch_lst_info = + &roam_info->roamChannelInfo.currentChannelListInfo; +#ifdef FEATURE_WLAN_ESE + /* + * this flag will be true if connection is ESE and no neighbor + * list received or if the connection is not ESE + */ + ese_neighbor_list_recvd = ((roam_info->isESEAssoc) + && (roam_info->roamChannelInfo.IAPPNeighborListReceived + == false)) + || (roam_info->isESEAssoc == false); +#endif /* FEATURE_WLAN_ESE */ + + req_buf = cdf_mem_malloc(sizeof(tSirRoamOffloadScanReq)); + if (NULL == req_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Mem alloc for roam scan offload req failed.")); + return NULL; + } + cdf_mem_zero(req_buf, sizeof(tSirRoamOffloadScanReq)); + req_buf->Command = command; + /* + * If command is STOP, then pass down ScanOffloadEnabled as Zero. This + * will handle the case of host driver reloads, but Riva still up and + * running + */ + if (command == ROAM_SCAN_OFFLOAD_STOP) { + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (csr_neighbor_middle_of_roaming((tHalHandle)mac_ctx, + session_id)) + req_buf->middle_of_roaming = 1; + else + csr_roam_reset_roam_params(mac_ctx); + req_buf->RoamScanOffloadEnabled = 0; + } else { + req_buf->RoamScanOffloadEnabled = + mac_ctx->roam.configParam.isRoamOffloadScanEnabled; + } + cdf_mem_copy(req_buf->ConnectedNetwork.currAPbssid, + roam_info->currAPbssid.bytes, sizeof(struct cdf_mac_addr)); + req_buf->ConnectedNetwork.ssId.length = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.length; + cdf_mem_copy(req_buf->ConnectedNetwork.ssId.ssId, + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.ssId, + req_buf->ConnectedNetwork.ssId.length); + req_buf->ConnectedNetwork.authentication = + mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType; + req_buf->ConnectedNetwork.encryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.EncryptionType; + req_buf->ConnectedNetwork.mcencryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.mcEncryptionType; +#ifdef WLAN_FEATURE_11W + req_buf->ConnectedNetwork.mfp_enabled = + mac_ctx->roam.roamSession[session_id].connectedProfile.MFPEnabled; +#endif + req_buf->delay_before_vdev_stop = + roam_info->cfgParams.delay_before_vdev_stop; + req_buf->OpportunisticScanThresholdDiff = + roam_info->cfgParams.nOpportunisticThresholdDiff; + req_buf->RoamRescanRssiDiff = + roam_info->cfgParams.nRoamRescanRssiDiff; + req_buf->RoamRssiDiff = mac_ctx->roam.configParam.RoamRssiDiff; + req_buf->reason = reason; + req_buf->NeighborScanTimerPeriod = + roam_info->cfgParams.neighborScanPeriod; + req_buf->NeighborRoamScanRefreshPeriod = + roam_info->cfgParams.neighborResultsRefreshPeriod; + req_buf->NeighborScanChannelMinTime = + roam_info->cfgParams.minChannelScanTime; + req_buf->NeighborScanChannelMaxTime = + roam_info->cfgParams.maxChannelScanTime; + req_buf->EmptyRefreshScanPeriod = + roam_info->cfgParams.emptyScanRefreshPeriod; + req_buf->RoamBmissFirstBcnt = + roam_info->cfgParams.nRoamBmissFirstBcnt; + req_buf->RoamBmissFinalBcnt = + roam_info->cfgParams.nRoamBmissFinalBcnt; + req_buf->RoamBeaconRssiWeight = + roam_info->cfgParams.nRoamBeaconRssiWeight; + /* MAWC feature */ + req_buf->MAWCEnabled = mac_ctx->roam.configParam.MAWCEnabled; +#ifdef FEATURE_WLAN_ESE + req_buf->IsESEAssoc = + csr_neighbor_roam_is_ese_assoc(mac_ctx, session_id) && + ((req_buf->ConnectedNetwork.authentication == + eCSR_AUTH_TYPE_OPEN_SYSTEM) || + (csr_is_auth_type_ese(req_buf-> + ConnectedNetwork.authentication))); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("LFR3:IsEseAssoc=%d\n"), req_buf->IsESEAssoc); +#endif + if (ese_neighbor_list_recvd || curr_ch_lst_info->numOfChannels == 0) { + /* + * Retrieve the Channel Cache either from ini or from the + * occupied channels list. Give Preference to INI Channels + */ + if (roam_info->cfgParams.channelInfo.numOfChannels) { + status = csr_fetch_ch_lst_from_ini(mac_ctx, roam_info, + req_buf); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(req_buf); + return NULL; + } + } else { + csr_fetch_ch_lst_from_occupied_lst(mac_ctx, session_id, + reason, req_buf, roam_info); + } + } +#ifdef FEATURE_WLAN_ESE + else { + /* + * If ESE is enabled, and a neighbor Report is received,then + * Ignore the INI Channels or the Occupied Channel List. + * Consider the channels in the neighbor list sent by the ESE AP + */ + csr_fetch_ch_lst_from_received_list(mac_ctx, roam_info, + curr_ch_lst_info, req_buf); + } +#endif + for (i = 0, j = 0; i < req_buf->ConnectedNetwork.ChannelCount; i++) { + if (j < sizeof(ch_cache_str)) { + j += snprintf(ch_cache_str + j, + sizeof(ch_cache_str) - j, " %d", + req_buf->ConnectedNetwork. + ChannelCache[i]); + } else + break; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("ChnlCacheType:%d, No of Chnls:%d,Channels: %s"), + req_buf->ChannelCacheType, + req_buf->ConnectedNetwork.ChannelCount, ch_cache_str); + + /* Maintain the Valid Channels List */ + status = csr_fetch_valid_ch_lst(mac_ctx, req_buf); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(req_buf); + return NULL; + } + + req_buf->MDID.mdiePresent = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mdiePresent; + req_buf->MDID.mobilityDomain = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mobilityDomain; + req_buf->sessionId = session_id; + req_buf->nProbes = mac_ctx->roam.configParam.nProbes; + req_buf->HomeAwayTime = mac_ctx->roam.configParam.nRoamScanHomeAwayTime; + + /* + * Home Away Time should be at least equal to (MaxDwell time + (2*RFS)), + * where RFS is the RF Switching time. It is twice RFS to consider the + * time to go off channel and return to the home channel. + */ + if (req_buf->HomeAwayTime < (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + FL("Invalid config, Home away time(%d) is less than (twice RF switching time + channel max time)(%d). Hence enforcing home away time to disable (0)"), + req_buf->HomeAwayTime, + (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))); + req_buf->HomeAwayTime = 0; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("HomeAwayTime:%d"), req_buf->HomeAwayTime); + + /*Prepare a probe request for 2.4GHz band and one for 5GHz band */ + dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + csr_find_best_phy_mode(mac_ctx, + mac_ctx->roam.configParam.phyMode)); + csr_roam_scan_offload_prepare_probe_req_template(mac_ctx, + SIR_ROAM_SCAN_24G_DEFAULT_CH, dot11_mode, + session->selfMacAddr.bytes, req_buf->p24GProbeTemplate, + &req_buf->us24GProbeTemplateLen, session); + + csr_roam_scan_offload_prepare_probe_req_template(mac_ctx, + SIR_ROAM_SCAN_5G_DEFAULT_CH, dot11_mode, + session->selfMacAddr.bytes, + req_buf->p5GProbeTemplate, &req_buf->us5GProbeTemplateLen, + session); + req_buf->allowDFSChannelRoam = + mac_ctx->roam.configParam.allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx); + req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled; + /* Roam Offload piggybacks upon the Roam Scan offload command. */ + if (req_buf->RoamOffloadEnabled) + csr_update_roam_scan_offload_request(mac_ctx, req_buf, session); + cdf_mem_copy(&req_buf->roam_params, + &mac_ctx->roam.configParam.roam_params, + sizeof(req_buf->roam_params)); +#endif + return req_buf; +} +/** + * check_allowed_ssid_list() - Check the WhiteList + * @req_buffer: Buffer which contains the connected profile SSID. + * @roam_params: Buffer which contains the whitelist SSID's. + * + * Check if the connected profile SSID exists in the whitelist. + * It is assumed that the framework provides this also in the whitelist. + * If it exists there is no issue. Otherwise add it to the list. + * + * Return: None + */ +static void check_allowed_ssid_list(tSirRoamOffloadScanReq *req_buffer, + struct roam_ext_params *roam_params) +{ + int i = 0; + bool match = false; + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + if ((roam_params->ssid_allowed_list[i].length == + req_buffer->ConnectedNetwork.ssId.length) && + cdf_mem_compare(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + roam_params->ssid_allowed_list[i].length)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Whitelist contains connected profile SSID"); + match = true; + break; + } + } + if (!match) { + if (roam_params->num_ssid_allowed_list >= + MAX_SSID_ALLOWED_LIST) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Whitelist is FULL. Cannot Add another entry"); + return; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Adding Connected profile SSID to whitelist"); + /* i is the next available index to add the entry.*/ + i = roam_params->num_ssid_allowed_list; + cdf_mem_copy(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + req_buffer->ConnectedNetwork.ssId.length); + roam_params->ssid_allowed_list[i].length = + req_buffer->ConnectedNetwork.ssId.length; + roam_params->num_ssid_allowed_list++; + } +} + +/* + * Below Table describe whether RSO command can be send down to fimrware or not. + * Host check it on the basis of previous RSO command sent down to firmware. + *||==========================================================================|| + *|| New cmd | LAST SENT COMMAND ---> || + *||====|=====================================================================|| + *|| V | RSO_START | RSO_STOP | RSO_RESTART | RSO_UPDATE_CFG|| + *|| -------------------------------------------------------------------------|| + *|| RSO_START | NO | YES | NO | NO || + *|| RSO_STOP | YES | YES | YES | YES || + *|| RSO_RESTART | YES | NO | NO | YES || + *|| RSO_UPDATE_CFG | YES | NO | YES | YES || + *||==========================================================================|| + **/ +#define RSO_START_BIT (1<roam.neighborRoamInfo[session_id]; + uint8_t desiredMask = 0; + bool ret_val; + + switch (command) { + case ROAM_SCAN_OFFLOAD_START: + desiredMask = RSO_START_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_STOP: + desiredMask = RSO_STOP_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_RESTART: + desiredMask = RSO_RESTART_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + desiredMask = RSO_UPDATE_CFG_ALLOW_MASK; + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Wrong RSO command %d, not allowed"), command); + return 0;/*Cmd Not allowed*/ + } + ret_val = desiredMask & (1 << neigh_roam_info->last_sent_cmd); + return ret_val; +} + +/** + * csr_roam_offload_scan() - populates roam offload scan request and sends to + * WMA + * + * paramters + * @mac_ctx: global mac ctx + * @session_id: session id + * @command: roam scan offload command input + * @reason: reason to roam + * + * Return: result of operation + */ +CDF_STATUS +csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id, + uint8_t command, uint8_t reason) +{ + uint8_t *state = NULL; + cds_msg_t msg; + tSirRoamOffloadScanReq *req_buf; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tpCsrNeighborRoamControlInfo roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct roam_ext_params *roam_params_dst; + struct roam_ext_params *roam_params_src; + uint8_t i; + + if (NULL == session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session is null")); + return CDF_STATUS_E_FAILURE; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roamOffloadSynchParams.bRoamSynchInProgress + && (ROAM_SCAN_OFFLOAD_STOP == command)) { + /* + * When roam synch is in progress for propagation, there is no + * need to send down the STOP command since the firmware is not + * expecting any WMI commands when the roam synch is in progress + */ + b_roam_scan_offload_started = false; + return CDF_STATUS_SUCCESS; + } +#endif + if (0 == csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + sms_log(mac_ctx, LOGE, "isRoamOffloadScanEnabled not set"); + return CDF_STATUS_E_FAILURE; + } + if (!csr_is_RSO_cmd_allowed(mac_ctx, command, session_id) && + reason != REASON_ROAM_SET_BLACKLIST_BSSID) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("RSO out-of-sync command %d lastSentCmd %d"), + command, roam_info->last_sent_cmd); + return CDF_STATUS_E_FAILURE; + } + + if ((true == b_roam_scan_offload_started) + && (ROAM_SCAN_OFFLOAD_START == command)) { + sms_log(mac_ctx, LOGE, "Roam Scan Offload is already started"); + return CDF_STATUS_E_FAILURE; + } + /* + * The Dynamic Config Items Update may happen even if the state is in + * INIT. It is important to ensure that the command is passed down to + * the FW only if the Infra Station is in a connected state.A connected + * station could also be in a PREAUTH or REASSOC states.So, consider not + * sending the command down in INIT state. We also have to ensure that + * if there is a STOP command we always have to inform Riva, + * irrespective of whichever state we are in + */ + + if ((roam_info->neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_INIT) && + (command != ROAM_SCAN_OFFLOAD_STOP) && + (reason != REASON_ROAM_SET_BLACKLIST_BSSID)) { + state = mac_trace_get_neighbour_roam_state( + roam_info->neighborRoamState); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("Scan Command not sent to FW state=%s and cmd=%d"), + state, command); + return CDF_STATUS_E_FAILURE; + } + + req_buf = csr_create_roam_scan_offload_request(mac_ctx, command, + session_id, reason, + session, roam_info); + if (!req_buf) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Failed to create req packet")); + return CDF_STATUS_E_FAILURE; + } + roam_params_dst = &req_buf->roam_params; + roam_params_src = &mac_ctx->roam.configParam.roam_params; + if (reason == REASON_ROAM_SET_SSID_ALLOWED) + check_allowed_ssid_list(req_buf, roam_params_src); + /* + * Configure the lookup threshold either from INI or from framework. + * If both are present, give higher priority to the one from framework. + */ + if (roam_params_src->alert_rssi_threshold) + req_buf->LookupThreshold = + roam_params_src->alert_rssi_threshold; + else + req_buf->LookupThreshold = + (int8_t)roam_info->cfgParams.neighborLookupThreshold * + (-1); + cdf_mem_copy(roam_params_dst, roam_params_src, + sizeof(struct roam_ext_params)); + /* + * rssi_diff which is updated via framework is equivalent to the + * INI RoamRssiDiff parameter and hence should be updated. + */ + if (roam_params_src->rssi_diff) + req_buf->RoamRssiDiff = roam_params_src->rssi_diff; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "num_bssid_avoid_list: %d, num_ssid_allowed_list: %d, " + "num_bssid_favored: %d, raise_rssi_thresh_5g: %d, " + "drop_rssi_thresh_5g: %d, raise_rssi_type_5g: %d, " + "raise_factor_5g: %d, drop_rssi_type_5g: %d, " + "drop_factor_5g: %d, max_raise_rssi_5g: %d, " + "max_drop_rssi_5g: %d, rssi_diff: %d, alert_rssi_threshold:%d", + roam_params_dst->num_bssid_avoid_list, + roam_params_dst->num_ssid_allowed_list, + roam_params_dst->num_bssid_favored, + roam_params_dst->raise_rssi_thresh_5g, + roam_params_dst->drop_rssi_thresh_5g, + roam_params_dst->raise_rssi_type_5g, + roam_params_dst->raise_factor_5g, + roam_params_dst->drop_rssi_type_5g, + roam_params_dst->drop_factor_5g, + roam_params_dst->max_raise_rssi_5g, + roam_params_dst->max_drop_rssi_5g, + req_buf->RoamRssiDiff, roam_params_dst->alert_rssi_threshold); + + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Blacklist Bssid: ("MAC_ADDRESS_STR")", + MAC_ADDR_ARRAY(roam_params_dst->bssid_avoid_list[i])); + } + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Whitelist: %.*s", + roam_params_dst->ssid_allowed_list[i].length, + roam_params_dst->ssid_allowed_list[i].ssId); + } + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Preferred Bssid: ("MAC_ADDRESS_STR") score: %d", + MAC_ADDR_ARRAY(roam_params_dst->bssid_favored[i]), + roam_params_dst->bssid_favored_factor[i]); + } + + req_buf->hi_rssi_scan_max_count = + roam_info->cfgParams.hi_rssi_scan_max_count; + req_buf->hi_rssi_scan_rssi_delta = + roam_info->cfgParams.hi_rssi_scan_rssi_delta; + req_buf->hi_rssi_scan_delay = + roam_info->cfgParams.hi_rssi_scan_delay; + req_buf->hi_rssi_scan_rssi_ub = + roam_info->cfgParams.hi_rssi_scan_rssi_ub; + + msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ; + msg.reserved = 0; + msg.bodyptr = req_buf; + if (!CDF_IS_STATUS_SUCCESS + (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Not able to post message to WMA", + __func__); + cdf_mem_free(req_buf); + return CDF_STATUS_E_FAILURE; + } else { + if (ROAM_SCAN_OFFLOAD_START == command) + b_roam_scan_offload_started = true; + else if (ROAM_SCAN_OFFLOAD_STOP == command) + b_roam_scan_offload_started = false; + } + /* update the last sent cmd */ + roam_info->last_sent_cmd = command; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Roam Scan Offload Command %d, Reason %d", command, reason); + return status; +} + +CDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp) +{ + switch (scanOffloadRsp->reason) { + case 0: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Rsp for Roam Scan Offload with failure status"); + break; + case REASON_OS_REQUESTED_ROAMING_NOW: + csr_neighbor_roam_proceed_with_handoff_req(pMac, + scanOffloadRsp->sessionId); + break; + + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Rsp for Roam Scan Offload with reason %d", + scanOffloadRsp->reason); + } + return CDF_STATUS_SUCCESS; +} + +tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac, + uint32_t statsMask, + uint32_t periodicity, + bool *pFound, + uint8_t staId, uint8_t sessionId) +{ + bool found = false; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrPeStatsReqInfo staEntry; + tCsrPeStatsReqInfo *pTempStaEntry = NULL; + tListElem *pStaEntry = NULL; + CDF_STATUS cdf_status; + *pFound = false; + + pStaEntry = csr_roam_find_in_pe_stats_req_list(pMac, statsMask); + if (pStaEntry) { + pTempStaEntry = + GET_BASE_ADDR(pStaEntry, tCsrPeStatsReqInfo, link); + if (pTempStaEntry->periodicity) { + pTempStaEntry->periodicity = + CDF_MIN(periodicity, + pTempStaEntry->periodicity); + } else { + pTempStaEntry->periodicity = periodicity; + } + pTempStaEntry->numClient++; + found = true; + } else { + cdf_mem_set(&staEntry, sizeof(tCsrPeStatsReqInfo), 0); + staEntry.numClient = 1; + staEntry.periodicity = periodicity; + staEntry.pMac = pMac; + staEntry.rspPending = false; + staEntry.staId = staId; + staEntry.statsMask = statsMask; + staEntry.timerRunning = false; + staEntry.sessionId = sessionId; + pTempStaEntry = + csr_roam_insert_entry_into_pe_stats_req_list(pMac, + &pMac->roam. + peStatsReqList, + &staEntry); + if (!pTempStaEntry) { + /* msg */ + sms_log(pMac, LOGW, + "csr_roam_check_pe_stats_req_list: Failed to insert req in peStatsReqList"); + return NULL; + } + } + pTempStaEntry->periodicity = + pMac->roam.configParam.statsReqPeriodicityInPS; + + if (!pTempStaEntry->timerRunning) { + /* send down a req in case of one time req, for periodic ones wait for timer to expire */ + if (!pTempStaEntry->rspPending && !pTempStaEntry->periodicity) { + status = csr_send_mb_stats_req_msg(pMac, + statsMask & ~(1 << + eCsrGlobalClassDStats), + staId, sessionId); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:failed to send down stats req to PE")); + } else { + pTempStaEntry->rspPending = true; + } + } + if (pTempStaEntry->periodicity) { + if (!found) { + + cdf_status = + cdf_mc_timer_init(&pTempStaEntry-> + hPeStatsTimer, + CDF_TIMER_TYPE_SW, + csr_roam_pe_stats_timer_handler, + pTempStaEntry); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:cannot init hPeStatsTimer timer")); + return NULL; + } + } + /* start timer */ + sms_log(pMac, LOG1, + "csr_roam_check_pe_stats_req_list:peStatsTimer period %d", + pTempStaEntry->periodicity); + cdf_status = + cdf_mc_timer_start(&pTempStaEntry->hPeStatsTimer, + pTempStaEntry->periodicity); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:cannot start hPeStatsTimer timer")); + return NULL; + } + pTempStaEntry->timerRunning = true; + } + } + *pFound = found; + return pTempStaEntry; +} + +/* + pStaEntry is no longer invalid upon the return of this function. + */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry) +{ + if (pEntry) { + if (csr_ll_remove_entry + (&pMac->roam.statsClientReqList, pEntry, LL_ACCESS_LOCK)) { + cdf_mem_free(GET_BASE_ADDR + (pEntry, tCsrStatsClientReqInfo, link)); + } + } +} + +void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac, + tCsrPeStatsReqInfo *pPeStaEntry) +{ + tListElem *pEntry; + tCsrPeStatsReqInfo *pTempStaEntry; + CDF_STATUS cdf_status; + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, FL(" List empty, no stats req for PE")); + return; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + if (NULL == pTempStaEntry + || (pTempStaEntry->statsMask != + pPeStaEntry->statsMask)) { + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + continue; + } + sms_log(pMac, LOGW, FL("Match found")); + if (pTempStaEntry->timerRunning) { + cdf_status = cdf_mc_timer_stop( + &pTempStaEntry->hPeStatsTimer); + /* + * If we are not able to stop the timer here, just + * remove the entry from the linked list. Destroy the + * timer object and free the memory in the timer CB + */ + if (cdf_status == CDF_STATUS_SUCCESS) { + /* the timer is successfully stopped */ + pTempStaEntry->timerRunning = false; + /* Destroy the timer */ + cdf_status = cdf_mc_timer_destroy( + &pTempStaEntry->hPeStatsTimer); + } else { + /* + * the timer could not be stopped. Hence destroy + * and free the memory for the PE stat entry in + * the timer CB. + */ + pTempStaEntry->timerStopFailed = true; + } + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL("failed to stop/destroy timer")); + } + } + + if (csr_ll_remove_entry(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_LOCK)) { + /* + * Only free the memory if we could stop the timer + * successfully + */ + if (!pTempStaEntry->timerStopFailed) { + cdf_mem_free(pTempStaEntry); + pTempStaEntry = NULL; + } + break; + } + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } /* end of while loop */ + return; +} + +void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask, + tCsrStatsCallback callback, uint8_t staId, + void *pContext) +{ + uint8_t stats[500]; + uint8_t *pStats = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + if (!callback) { + sms_log(pMac, LOGE, FL("Cannot report callback NULL")); + return; + } + if (!statsMask) { + sms_log(pMac, LOGE, FL("Cannot report statsMask is 0")); + return; + } + pStats = stats; + tempMask = statsMask; + while (tempMask) { + if (tempMask & 1) { + /* new stats info from PE, fill up the stats strucutres in PMAC */ + switch (counter) { + case eCsrSummaryStats: + sms_log(pMac, LOG2, FL("Summary stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + summaryStatsInfo, + sizeof(tCsrSummaryStatsInfo)); + pStats += sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sms_log(pMac, LOG2, FL("ClassA stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classAStatsInfo, + sizeof(tCsrGlobalClassAStatsInfo)); + pStats += sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + sms_log(pMac, LOG2, FL("ClassB stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classBStatsInfo, + sizeof(tCsrGlobalClassBStatsInfo)); + pStats += sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + sms_log(pMac, LOG2, FL("ClassC stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classCStatsInfo, + sizeof(tCsrGlobalClassCStatsInfo)); + pStats += sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrGlobalClassDStats: + sms_log(pMac, LOG2, FL("ClassD stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classDStatsInfo, + sizeof(tCsrGlobalClassDStatsInfo)); + pStats += sizeof(tCsrGlobalClassDStatsInfo); + break; + case eCsrPerStaStats: + sms_log(pMac, LOG2, FL("PerSta stats")); + cdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + perStaStatsInfo[staId], + sizeof(tCsrPerStaStatsInfo)); + pStats += sizeof(tCsrPerStaStatsInfo); + break; + default: + sms_log(pMac, LOGE, + FL("Unknown stats type and counter %d"), + counter); + break; + } + } + tempMask >>= 1; + counter++; + } + callback(stats, pContext); +} + +CDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac) +{ + tListElem *pEntry = NULL; + tListElem *pPrevEntry = NULL; + tCsrStatsClientReqInfo *pTempStaEntry = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOGW, + "csr_roam_dereg_statistics_req: List empty, no request from " + "upper layer client(s)"); + return status; + } + while (pEntry) { + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo, + link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if (pTempStaEntry->pPeStaEntry) { + /* pPeStaEntry can be NULL */ + pTempStaEntry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from peStatsReqList too */ + if (!pTempStaEntry->pPeStaEntry->numClient) { + csr_roam_remove_entry_from_pe_stats_req_list(pMac, + pTempStaEntry-> + pPeStaEntry); + } + } + /* check if we need to stop the tl stats timer too */ + pMac->roam.tlStatsReqInfo.numClient--; + if (!pMac->roam.tlStatsReqInfo.numClient) { + if (pMac->roam.tlStatsReqInfo.timerRunning) { + status = + cdf_mc_timer_stop(&pMac->roam. + tlStatsReqInfo. + hTlStatsTimer); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_dereg_statistics_req:cannot stop TlStatsTimer timer")); + /* we will continue */ + } + } + pMac->roam.tlStatsReqInfo.periodicity = 0; + pMac->roam.tlStatsReqInfo.timerRunning = false; + } + if (pTempStaEntry->periodicity) { + /* While creating StaEntry in csr_get_statistics, */ + /* Initializing and starting timer only when periodicity is set. */ + /* So Stop and Destroy timer only when periodicity is set. */ + + cdf_mc_timer_stop(&pTempStaEntry->timer); + /* Destroy the cdf timer... */ + cdf_status = + cdf_mc_timer_destroy(&pTempStaEntry->timer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_dereg_statistics_req:failed to destroy Client req timer")); + } + } + + pPrevEntry = pEntry; + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + /* the last one */ + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo, link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + return status; + +} + +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pCmd = sme_get_command_buffer(pMac); + if (pCmd) { + pMac->roam.sPendingCommands++; + } + return pCmd; +} + +void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pMac->roam.sPendingCommands > 0) { + /* All command allocated through csr_get_command_buffer need to */ + /* decrement the pending count when releasing. */ + pMac->roam.sPendingCommands--; + sme_release_command(pMac, pCommand); + } else { + sms_log(pMac, LOGE, FL("no pending commands")); + CDF_ASSERT(0); + } +} + +/* Return SUCCESS is the command is queued, failed */ +CDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fHighPriority) +{ + bool fNoCmdPending; + + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGE, FL("Sme in stop state")); + CDF_ASSERT(0); + return CDF_STATUS_E_PERM; + } + + if ((eSmeCommandScan == pCommand->command) && pMac->scan.fDropScanCmd) { + sms_log(pMac, LOGW, FL(" drop scan (scan reason %d) command"), + pCommand->u.scanCmd.reason); + return CDF_STATUS_CSR_WRONG_STATE; + } + + if ((pCommand->command == eSmeCommandScan) + || (pCommand->command == eSmeCommandRemainOnChannel)) { + sms_log(pMac, LOGW, + FL("scan pending list count %d scan_id %d"), + pMac->sme.smeScanCmdPendingList.Count, + pCommand->u.scanCmd.scanID); + csr_ll_insert_tail(&pMac->sme.smeScanCmdPendingList, + &pCommand->Link, LL_ACCESS_LOCK); + /* process the command queue... */ + sme_process_pending_queue(pMac); + return CDF_STATUS_SUCCESS; + } + /* Make sure roamCmdPendingList is not empty first */ + fNoCmdPending = + csr_ll_is_list_empty(&pMac->roam.roamCmdPendingList, false); + if (fNoCmdPending) { + sme_push_command(pMac, pCommand, fHighPriority); + } else { + /* no list lock is needed since SME lock is held */ + if (!fHighPriority) { + csr_ll_insert_tail(&pMac->roam.roamCmdPendingList, + &pCommand->Link, false); + } else { + csr_ll_insert_head(&pMac->roam.roamCmdPendingList, + &pCommand->Link, false); + } + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_roam_update_apwpsie(tpAniSirGlobal pMac, uint32_t sessionId, + tSirAPWPSIEs *pAPWPSIES) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirUpdateAPWPSIEsReq *pMsg; + + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL(" Session does not exist for session id %d"), + sessionId); + return CDF_STATUS_E_FAILURE; + } + + do { + pMsg = cdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, sizeof(tSirUpdateAPWPSIEsReq), 0); + pMsg->messageType = eWNI_SME_UPDATE_APWPSIE_REQ; + pMsg->transactionId = 0; + cdf_mem_copy(pMsg->bssId, &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + pMsg->sessionId = sessionId; + cdf_mem_copy(&pMsg->APWPSIEs, pAPWPSIES, + sizeof(tSirAPWPSIEs)); + pMsg->length = sizeof(struct sSirUpdateAPWPSIEsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +CDF_STATUS csr_roam_update_wparsni_es(tpAniSirGlobal pMac, uint32_t sessionId, + tSirRSNie *pAPSirRSNie) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirUpdateAPWPARSNIEsReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL(" Session does not exist for session id %d"), + sessionId); + return CDF_STATUS_E_FAILURE; + } + do { + pMsg = cdf_mem_malloc(sizeof(tSirUpdateAPWPARSNIEsReq)); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + cdf_mem_set(pMsg, sizeof(tSirUpdateAPWPARSNIEsReq), 0); + pMsg->messageType = eWNI_SME_SET_APWPARSNIEs_REQ; + pMsg->transactionId = 0; + cdf_mem_copy(pMsg->bssId, &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + pMsg->sessionId = sessionId; + cdf_mem_copy(&pMsg->APWPARSNIEs, pAPSirRSNie, + sizeof(tSirRSNie)); + pMsg->length = sizeof(struct sSirUpdateAPWPARSNIEsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +CDF_STATUS +csr_roam_issue_ft_preauth_req(tHalHandle hHal, uint32_t sessionId, + tpSirBssDescription pBssDescription) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpSirFTPreAuthReq pftPreAuthReq; + uint16_t auth_req_len = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL("Session does not exist for session id(%d)"), + sessionId); + return CDF_STATUS_E_FAILURE; + } + + auth_req_len = sizeof(tSirFTPreAuthReq); + pftPreAuthReq = (tpSirFTPreAuthReq) cdf_mem_malloc(auth_req_len); + if (NULL == pftPreAuthReq) { + sms_log(pMac, LOGE, + FL("Memory allocation for FT Preauth request failed")); + return CDF_STATUS_E_NOMEM; + } + /* Save the SME Session ID here. We need it while processing the preauth response */ + pSession->ftSmeContext.smeSessionId = sessionId; + cdf_mem_zero(pftPreAuthReq, auth_req_len); + + pftPreAuthReq->pbssDescription = + (tpSirBssDescription) cdf_mem_malloc(sizeof(pBssDescription->length) + + pBssDescription->length); + if (NULL == pftPreAuthReq->pbssDescription) { + sms_log(pMac, LOGE, + FL("Memory allocation for FT Preauth request failed")); + return CDF_STATUS_E_NOMEM; + } + + pftPreAuthReq->messageType = eWNI_SME_FT_PRE_AUTH_REQ; + + pftPreAuthReq->preAuthchannelNum = pBssDescription->channelId; + + cdf_mem_copy((void *)&pftPreAuthReq->currbssId, + (void *)pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy((void *)&pftPreAuthReq->preAuthbssId, + (void *)pBssDescription->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_VOWIFI_11R + if (csr_roam_is11r_assoc(pMac, sessionId) && + (pMac->roam.roamSession[sessionId].connectedProfile.AuthType != + eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + pftPreAuthReq->ft_ies_length = + (uint16_t) pSession->ftSmeContext.auth_ft_ies_length; + cdf_mem_copy(pftPreAuthReq->ft_ies, + pSession->ftSmeContext.auth_ft_ies, + pSession->ftSmeContext.auth_ft_ies_length); + } else +#endif + { + pftPreAuthReq->ft_ies_length = 0; + } + cdf_mem_copy(pftPreAuthReq->pbssDescription, pBssDescription, + sizeof(pBssDescription->length) + pBssDescription->length); + pftPreAuthReq->length = auth_req_len; + return cds_send_mb_message_to_mac(pftPreAuthReq); +} + +/*-------------------------------------------------------------------------- + * This will receive and process the FT Pre Auth Rsp from the current + * associated ap. + * + * This will invoke the hdd call back. This is so that hdd can now + * send the FTIEs from the Auth Rsp (Auth Seq 2) to the supplicant. + ------------------------------------------------------------------------*/ +void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal, + tpSirFTPreAuthRsp pFTPreAuthRsp) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; +#if defined(FEATURE_WLAN_LFR) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD) + tCsrRoamInfo roamInfo; +#endif + eCsrAuthType conn_Auth_type; + uint32_t sessionId = pFTPreAuthRsp->smeSessionId; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING + status = + csr_neighbor_roam_preauth_rsp_handler(pMac, pFTPreAuthRsp->smeSessionId, + pFTPreAuthRsp->status); + if (status != CDF_STATUS_SUCCESS) { + /* + * Bail out if pre-auth was not even processed. + */ + sms_log(pMac, LOGE, + FL("Preauth was not processed: %d SessionID: %d"), + status, sessionId); + return; + } +#endif + + /* The below function calls/timers should be invoked only if the pre-auth is successful */ + if (CDF_STATUS_SUCCESS != (CDF_STATUS) pFTPreAuthRsp->status) + return; + /* Implies a success */ + pSession->ftSmeContext.FTState = eFT_AUTH_COMPLETE; + /* Indicate SME QoS module the completion of Preauth success. This will trigger the creation of RIC IEs */ + pSession->ftSmeContext.psavedFTPreAuthRsp = pFTPreAuthRsp; + /* No need to notify qos module if this is a non 11r & ESE roam */ + if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId) +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD) + || csr_roam_is_ese_assoc(pMac, pFTPreAuthRsp->smeSessionId) +#endif + ) { + sme_qos_csr_event_ind(pMac, + pSession->ftSmeContext.smeSessionId, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL); + } + /* Start the pre-auth reassoc interval timer with a period of 400ms. When this expires, + * actual transition from the current to handoff AP is triggered */ + status = + cdf_mc_timer_start(&pSession->ftSmeContext.preAuthReassocIntvlTimer, + 60); + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL + ("Preauth reassoc interval timer start failed to start with status %d"), + status); + return; + } + /* Save the received response */ + cdf_mem_copy((void *)&pSession->ftSmeContext.preAuthbssId, + (void *)pFTPreAuthRsp->preAuthbssId, sizeof(struct cdf_mac_addr)); + if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId)) + csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId, NULL, 0, + eCSR_ROAM_FT_RESPONSE, + eCSR_ROAM_RESULT_NONE); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + if (csr_roam_is_ese_assoc(pMac, pFTPreAuthRsp->smeSessionId)) { + /* read TSF */ + csr_roam_read_tsf(pMac, (uint8_t *) roamInfo.timestamp, + pFTPreAuthRsp->smeSessionId); + /* Save the bssid from the received response */ + cdf_mem_copy((void *)&roamInfo.bssid, + (void *)pFTPreAuthRsp->preAuthbssId, + sizeof(struct cdf_mac_addr)); + csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId, + &roamInfo, 0, eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + 0); + } +#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +#ifdef FEATURE_WLAN_LFR + /* If Legacy Fast Roaming is enabled, signal the supplicant */ + /* So he can send us a PMK-ID for this candidate AP. */ + if (csr_roam_is_fast_roam_enabled(pMac, pFTPreAuthRsp->smeSessionId)) { + /* Save the bssid from the received response */ + cdf_mem_copy((void *)&roamInfo.bssid, + (void *)pFTPreAuthRsp->preAuthbssId, + sizeof(struct cdf_mac_addr)); + csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId, + &roamInfo, 0, eCSR_ROAM_PMK_NOTIFY, 0); + } +#endif + + /* If its an Open Auth, FT IEs are not provided by supplicant */ + /* Hence populate them here */ + conn_Auth_type = + pMac->roam.roamSession[sessionId].connectedProfile.AuthType; + + pSession->ftSmeContext.addMDIE = false; + if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId) && + (conn_Auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + uint16_t ft_ies_length; + ft_ies_length = pFTPreAuthRsp->ric_ies_length; + + if ((pSession->ftSmeContext.reassoc_ft_ies) && + (pSession->ftSmeContext.reassoc_ft_ies_length)) { + cdf_mem_free(pSession->ftSmeContext.reassoc_ft_ies); + pSession->ftSmeContext.reassoc_ft_ies_length = 0; + pSession->ftSmeContext.reassoc_ft_ies = NULL; + } + + pSession->ftSmeContext.reassoc_ft_ies = + cdf_mem_malloc(ft_ies_length); + if (NULL == pSession->ftSmeContext.reassoc_ft_ies) { + sms_log(pMac, LOGE, + FL("Memory allocation failed for ft_ies")); + return; + } else { + /* Copy the RIC IEs to reassoc IEs */ + cdf_mem_copy(((uint8_t *) pSession->ftSmeContext. + reassoc_ft_ies), + (uint8_t *) pFTPreAuthRsp->ric_ies, + pFTPreAuthRsp->ric_ies_length); + pSession->ftSmeContext.reassoc_ft_ies_length = + ft_ies_length; + pSession->ftSmeContext.addMDIE = true; + } + } + /* Done with it, init it. */ + pSession->ftSmeContext.psavedFTPreAuthRsp = NULL; +} +#endif + + +/* + pBuf points to the beginning of the message + LIM packs disassoc rsp as below, + messageType - 2 bytes + messageLength - 2 bytes + sessionId - 1 byte + transactionId - 2 bytes (uint16_t) + reasonCode - 4 bytes (sizeof(tSirResultCodes)) + peerMacAddr - 6 bytes + The rest is conditionally defined of (WNI_POLARIS_FW_PRODUCT == AP) and not used + */ +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, tSirSmeDisassocRsp *pRsp) +{ + if (pBuf && pRsp) { + pBuf += 4; /* skip type and length */ + pRsp->sessionId = *pBuf++; + cdf_get_u16(pBuf, (uint16_t *) &pRsp->transactionId); + pBuf += 2; + cdf_get_u32(pBuf, (uint32_t *) &pRsp->statusCode); + pBuf += 4; + cdf_mem_copy(pRsp->peerMacAddr, pBuf, 6); + } +} + +/* Returns whether a session is in CDF_STA_MODE...or not */ +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" %s: session %d not found "), __func__, + sessionId); + return false; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, FL(" %s: Inactive session"), __func__); + return false; + } + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) { + return false; + } + /* There is a possibility that the above check may fail,because + * P2P CLI also uses the same BSSType (eCSR_BSS_TYPE_INFRASTRUCTURE) + * when it is connected.So,we may sneak through the above check even + * if we are not a STA mode INFRA station. So, if we sneak through + * the above condition, we can use the following check if we are + * really in STA Mode.*/ + + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona == CDF_STA_MODE) { + return true; + } else { + sms_log(pMac, LOGE, FL(" %s: pCurRoamProfile is NULL\n"), + __func__); + return false; + } + } + + return false; +} + +CDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t msg; + + tAniHandoffReq *pMsg; + pMsg = cdf_mem_malloc(sizeof(tAniHandoffReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csr_handoff_request: failed to allocate mem for req "); + return CDF_STATUS_E_NOMEM; + } + pMsg->msgType = eWNI_SME_HANDOFF_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniHandoffReq); + pMsg->sessionId = sessionId; + pMsg->channel = pHandoffInfo->channel; + pMsg->handoff_src = pHandoffInfo->src; + cdf_mem_copy(pMsg->bssid, pHandoffInfo->bssid.bytes, CDF_MAC_ADDR_SIZE); + msg.type = eWNI_SME_HANDOFF_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + " csr_handoff_request failed to post msg to self "); + cdf_mem_free((void *)pMsg); + status = CDF_STATUS_E_FAILURE; + } + return status; +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +/* --------------------------------------------------------------------------- + \fn csr_set_cckm_ie + \brief This function stores the CCKM IE passed by the supplicant + in a place holder data structure and this IE will be packed inside + reassociation request + \param pMac - pMac global structure + \param sessionId - Current session id + \param pCckmIe - pointer to CCKM IE data + \param ccKmIeLen - length of the CCKM IE + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(pSession->suppCckmIeInfo.cckmIe, pCckmIe, ccKmIeLen); + pSession->suppCckmIeInfo.cckmIeLen = ccKmIeLen; + return status; +} + +/* --------------------------------------------------------------------------- + \fn csr_roam_read_tsf + \brief This function reads the TSF; and also add the time elapsed since + last beacon or probe response reception from the hand off AP to arrive at + the latest TSF value. + \param pMac - pMac global structure + \param pTimestamp - output TSF timestamp + \- return Success or failure + -------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrNeighborRoamBSSInfo handoffNode; + uint32_t timer_diff = 0; + uint32_t timeStamp[2]; + tpSirBssDescription pBssDescription = NULL; + csr_neighbor_roam_get_handoff_ap_info(pMac, &handoffNode, sessionId); + pBssDescription = handoffNode.pBssDescription; + /* Get the time diff in milli seconds */ + timer_diff = + cdf_mc_timer_get_system_time() - pBssDescription->scanSysTimeMsec; + /* Convert msec to micro sec timer */ + timer_diff = (uint32_t) (timer_diff * SYSTEM_TIME_MSEC_TO_USEC); + timeStamp[0] = pBssDescription->timeStamp[0]; + timeStamp[1] = pBssDescription->timeStamp[1]; + update_cckmtsf(&(timeStamp[0]), &(timeStamp[1]), &timer_diff); + cdf_mem_copy(pTimestamp, (void *)&timeStamp[0], sizeof(uint32_t) * 2); + return status; +} +#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ + +/* + * Post Channel Change Request to LIM + * This API is primarily used to post + * Channel Change Req for SAP + */ +CDF_STATUS +csr_roam_channel_change_req(tpAniSirGlobal pMac, struct cdf_mac_addr bssid, + uint8_t cbMode, tCsrRoamProfile *profile) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirChanChangeRequest *pMsg; + tCsrRoamStartBssParams param; + + csr_roam_get_bss_start_parms(pMac, profile, ¶m); + pMsg = cdf_mem_malloc(sizeof(tSirChanChangeRequest)); + if (!pMsg) { + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set((void *)pMsg, sizeof(tSirChanChangeRequest), 0); + + pMsg->messageType = eWNI_SME_CHANNEL_CHANGE_REQ; + pMsg->messageLen = sizeof(tSirChanChangeRequest); + pMsg->targetChannel = profile->ChannelInfo.ChannelList[0]; + pMsg->cbMode = cbMode; + pMsg->channel_width = profile->ch_params.ch_width; + pMsg->dot11mode = csr_translate_to_wni_cfg_dot11_mode(pMac, + pMac->roam.configParam.uCfgDot11Mode); + pMsg->center_freq_seg_0 = pMsg->targetChannel; + pMsg->center_freq_seg_1 = 0; + cdf_mem_copy(pMsg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(&pMsg->operational_rateset, + ¶m.operationalRateSet, sizeof(pMsg->operational_rateset)); + cdf_mem_copy(&pMsg->extended_rateset, + ¶m.extendedRateSet, sizeof(pMsg->extended_rateset)); + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +/* + * Post Beacon Tx Start request to LIM + * immediately after SAP CAC WAIT is + * completed without any RADAR indications. + */ +CDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac, + struct cdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirStartBeaconIndication *pMsg; + + pMsg = cdf_mem_malloc(sizeof(tSirStartBeaconIndication)); + + if (!pMsg) { + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set((void *)pMsg, sizeof(tSirStartBeaconIndication), 0); + pMsg->messageType = eWNI_SME_START_BEACON_REQ; + pMsg->messageLen = sizeof(tSirStartBeaconIndication); + pMsg->beaconStartStatus = dfsCacWaitStatus; + cdf_mem_copy(pMsg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE); + + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +/*---------------------------------------------------------------------------- + \fn csr_roam_modify_add_ies + \brief This function sends msg to modify the additional IE buffers in PE + \param pMac - pMac global structure + \param pModifyIE - pointer to tSirModifyIE structure + \param updateType - Type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +CDF_STATUS +csr_roam_modify_add_ies(tpAniSirGlobal pMac, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + tpSirModifyIEsInd pModifyAddIEInd = NULL; + uint8_t *pLocalBuffer = NULL; + CDF_STATUS status; + + /* following buffer will be freed by consumer (PE) */ + pLocalBuffer = cdf_mem_malloc(pModifyIE->ieBufferlength); + + if (NULL == pLocalBuffer) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + return CDF_STATUS_E_NOMEM; + } + + pModifyAddIEInd = cdf_mem_malloc(sizeof(tSirModifyIEsInd)); + if (NULL == pModifyAddIEInd) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + cdf_mem_free(pLocalBuffer); + return CDF_STATUS_E_NOMEM; + } + + /*copy the IE buffer */ + cdf_mem_copy(pLocalBuffer, pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + cdf_mem_zero(pModifyAddIEInd, sizeof(tSirModifyIEsInd)); + + pModifyAddIEInd->msgType = eWNI_SME_MODIFY_ADDITIONAL_IES; + pModifyAddIEInd->msgLen = sizeof(tSirModifyIEsInd); + + cdf_mem_copy(pModifyAddIEInd->modifyIE.bssid, pModifyIE->bssid, + sizeof(tSirMacAddr)); + + pModifyAddIEInd->modifyIE.smeSessionId = pModifyIE->smeSessionId; + pModifyAddIEInd->modifyIE.notify = pModifyIE->notify; + pModifyAddIEInd->modifyIE.ieID = pModifyIE->ieID; + pModifyAddIEInd->modifyIE.ieIDLen = pModifyIE->ieIDLen; + pModifyAddIEInd->modifyIE.pIEBuffer = pLocalBuffer; + pModifyAddIEInd->modifyIE.ieBufferlength = pModifyIE->ieBufferlength; + + pModifyAddIEInd->updateType = updateType; + + status = cds_send_mb_message_to_mac(pModifyAddIEInd); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg" + "!!! status %d"), status); + cdf_mem_free(pLocalBuffer); + } + return status; +} + +/*---------------------------------------------------------------------------- + \fn csr_roam_update_add_ies + \brief This function sends msg to updates the additional IE buffers in PE + \param pMac - pMac global structure + \param sessionId - SME session id + \param bssid - BSSID + \param additionIEBuffer - buffer containing addition IE from hostapd + \param length - length of buffer + \param updateType - Type of buffer + \param append - append or replace completely + \- return Success or failure + -----------------------------------------------------------------------------*/ +CDF_STATUS +csr_roam_update_add_ies(tpAniSirGlobal pMac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + tpSirUpdateIEsInd pUpdateAddIEs = NULL; + uint8_t *pLocalBuffer = NULL; + CDF_STATUS status; + + if (pUpdateIE->ieBufferlength != 0) { + /* Following buffer will be freed by consumer (PE) */ + pLocalBuffer = cdf_mem_malloc(pUpdateIE->ieBufferlength); + if (NULL == pLocalBuffer) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(pLocalBuffer, pUpdateIE->pAdditionIEBuffer, + pUpdateIE->ieBufferlength); + } + + pUpdateAddIEs = cdf_mem_malloc(sizeof(tSirUpdateIEsInd)); + if (NULL == pUpdateAddIEs) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + if (pLocalBuffer != NULL) { + cdf_mem_free(pLocalBuffer); + } + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pUpdateAddIEs, sizeof(tSirUpdateIEsInd)); + + pUpdateAddIEs->msgType = eWNI_SME_UPDATE_ADDITIONAL_IES; + pUpdateAddIEs->msgLen = sizeof(tSirUpdateIEsInd); + + cdf_mem_copy(pUpdateAddIEs->updateIE.bssid, pUpdateIE->bssid, + sizeof(tSirMacAddr)); + + pUpdateAddIEs->updateIE.smeSessionId = pUpdateIE->smeSessionId; + pUpdateAddIEs->updateIE.append = pUpdateIE->append; + pUpdateAddIEs->updateIE.notify = pUpdateIE->notify; + pUpdateAddIEs->updateIE.ieBufferlength = pUpdateIE->ieBufferlength; + pUpdateAddIEs->updateIE.pAdditionIEBuffer = pLocalBuffer; + + pUpdateAddIEs->updateType = updateType; + + status = cds_send_mb_message_to_mac(pUpdateAddIEs); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg" + "!!! status %d"), status); + cdf_mem_free(pLocalBuffer); + } + return status; +} + +/** + * csr_roam_send_chan_sw_ie_request() - Request to transmit CSA IE + * @mac_ctx: Global MAC context + * @bssid: BSSID + * @target_channel: Channel on which to send the IE + * @csa_ie_reqd: Include/Exclude CSA IE. + * @ch_bandwidth: Channel offset + * + * This function sends request to transmit channel switch announcement + * IE to lower layers + * + * Return: success or failure + **/ +CDF_STATUS +csr_roam_send_chan_sw_ie_request(tpAniSirGlobal mac_ctx, + struct cdf_mac_addr bssid, uint8_t target_channel, + uint8_t csa_ie_reqd, uint8_t ch_bandwidth) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirDfsCsaIeRequest *msg; + + msg = cdf_mem_malloc(sizeof(tSirDfsCsaIeRequest)); + if (!msg) { + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set((void *)msg, sizeof(tSirDfsCsaIeRequest), 0); + msg->msgType = eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ; + msg->msgLen = sizeof(tSirDfsCsaIeRequest); + + msg->targetChannel = target_channel; + msg->csaIeRequired = csa_ie_reqd; + cdf_mem_copy(msg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE); + msg->ch_bandwidth = ch_bandwidth; + + status = cds_send_mb_message_to_mac(msg); + + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/*---------------------------------------------------------------------------- +* fn csr_process_roam_offload_synch_ind +* brief This will process the roam synch indication received from +* lower layers.This function also calls another API to +* parse the beacon IE and fill the appropriate fields +* param pMac - pMac global structure +* param pMsgBuf - Message buffer received from lower layers +* --------------------------------------------------------------------------*/ +void csr_process_roam_offload_synch_ind(tHalHandle hHal, + roam_offload_synch_ind *roam_synch_ind_ptr) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *session_ptr = NULL; + uint8_t session_id = roam_synch_ind_ptr->roamedVdevId; + session_ptr = CSR_GET_SESSION(pMac, roam_synch_ind_ptr->roamedVdevId); + if (!session_ptr) { + sms_log(pMac, LOGE, FL("LFR3: session %d not found "), + roam_synch_ind_ptr->roamedVdevId); + goto err_synch_rsp; + } + if (!CDF_IS_STATUS_SUCCESS(csr_scan_save_roam_offload_ap_to_scan_cache( + pMac, roam_synch_ind_ptr))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "fail to save roam offload AP to scan cache"); + goto err_synch_rsp; + } + session_ptr->roamOffloadSynchParams.rssi = roam_synch_ind_ptr->rssi; + session_ptr->roamOffloadSynchParams.roamReason = + roam_synch_ind_ptr->roamReason; + session_ptr->roamOffloadSynchParams.roamedVdevId = + roam_synch_ind_ptr->roamedVdevId; + cdf_mem_copy(session_ptr->roamOffloadSynchParams.bssid, + roam_synch_ind_ptr->bssId, sizeof(tSirMacAddr)); + session_ptr->roamOffloadSynchParams.txMgmtPower = + roam_synch_ind_ptr->txMgmtPower; + session_ptr->roamOffloadSynchParams.authStatus = + roam_synch_ind_ptr->authStatus; + session_ptr->roamOffloadSynchParams.bRoamSynchInProgress = true; + /*Save the BSS descriptor for later use*/ + session_ptr->roamOffloadSynchParams.bss_desc_ptr = + roam_synch_ind_ptr->bss_desc_ptr; + pMac->roam.reassocRespLen = roam_synch_ind_ptr->reassocRespLength; + pMac->roam.pReassocResp = + cdf_mem_malloc(pMac->roam.reassocRespLen); + if (NULL == pMac->roam.pReassocResp) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "Memory allocation for reassoc response failed"); + goto err_synch_rsp; + } + cdf_mem_copy(pMac->roam.pReassocResp, + (uint8_t *)roam_synch_ind_ptr + + roam_synch_ind_ptr->reassocRespOffset, + pMac->roam.reassocRespLen); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "LFR3:%s: the reassoc resp frame data:", __func__); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + pMac->roam.pReassocResp, pMac->roam.reassocRespLen); + + cdf_mem_copy(session_ptr->roamOffloadSynchParams.kck, + roam_synch_ind_ptr->kck, SIR_KCK_KEY_LEN); + cdf_mem_copy(session_ptr->roamOffloadSynchParams.kek, + roam_synch_ind_ptr->kek, SIR_KEK_KEY_LEN); + cdf_mem_copy(session_ptr->roamOffloadSynchParams.replay_ctr, + roam_synch_ind_ptr->replay_ctr, SIR_REPLAY_CTR_LEN); + if (CDF_STATUS_SUCCESS != csr_neighbor_roam_offload_update_preauth_list( + pMac, roam_synch_ind_ptr, session_id)) { + /** + *Bail out if Roam Offload Synch Response was not even handled. + **/ + sms_log(pMac, LOGE, FL("Roam Offload Synch Response " + "was not processed")); + goto err_synch_rsp; + } + + csr_neighbor_roam_request_handoff(pMac, session_id); + +err_synch_rsp: + cdf_mem_free(roam_synch_ind_ptr->bss_desc_ptr); + roam_synch_ind_ptr->bss_desc_ptr = NULL; +} + +/*---------------------------------------------------------------------------- +* fn csr_process_ho_fail_ind +* brief This function will process the Hand Off Failure indication +* received from the firmware. It will trigger a disconnect on +* the session which the firmware reported a hand off failure +* param pMac global structure +* param pMsgBuf - Contains the session ID for which the handler should apply +* --------------------------------------------------------------------------*/ +void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeHOFailureInd *pSmeHOFailInd = (tSirSmeHOFailureInd *) pMsgBuf; + uint32_t sessionId; + + if (pSmeHOFailInd) + sessionId = pSmeHOFailInd->sessionId; + else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "LFR3: Hand-Off Failure Ind is NULL"); + return; + } + /* Roaming is supported only on Infra STA Mode. */ + if (!csr_roam_is_sta_mode(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "LFR3:HO Fail cannot be handled for session %d", + sessionId); + return; + } + csr_roam_synch_clean_up(pMac, sessionId); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "LFR3:Issue Disconnect on session %d", sessionId); + csr_roam_disconnect(pMac, sessionId, eCSR_DISCONNECT_REASON_UNSPECIFIED); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * csr_update_op_class_array() - update op class for each band + * @mac_ctx: mac global context + * @op_classes: out param, operating class array to update + * @channel_info: channel info + * @ch_name: channel band name to display in debug messages + * @i: out param, stores number of operating classes + * + * Return: void + */ +static void +csr_update_op_class_array(tpAniSirGlobal mac_ctx, + uint8_t *op_classes, + tCsrChannel *channel_info, + char *ch_name, + uint8_t *i) +{ + uint8_t j = 0, idx = 0, class = 0; + bool found = false; + uint8_t num_channels = channel_info->numChannels; + + sms_log(mac_ctx, LOG1, + FL("Num of %s channels, %d"), + ch_name, num_channels); + + for (idx = 0; idx < num_channels + && *i < (SIR_MAC_MAX_SUPP_OPER_CLASSES - 1); idx++) { + class = cds_regdm_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel_info->channelList[idx], + BWALL); + sms_log(mac_ctx, LOG4, FL("for chan %d, op class: %d"), + channel_info->channelList[idx], class); + + found = false; + for (j = 0; j < SIR_MAC_MAX_SUPP_OPER_CLASSES - 1; j++) { + if (op_classes[j] == class) { + found = true; + break; + } + } + if (!found) { + op_classes[*i] = class; + *i = *i + 1; + } + } +} + +/** + * csr_update_op_class_array() - update op class for all bands + * @hHal: global hal context + * + * Return: void + */ +void csr_init_operating_classes(tHalHandle hHal) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t swap = 0; + uint8_t numClasses = 0; + uint8_t opClasses[SIR_MAC_MAX_SUPP_OPER_CLASSES] = {0,}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG1, FL("Current Country = %c%c"), + pMac->scan.countryCodeCurrent[0], + pMac->scan.countryCodeCurrent[1]); + + csr_update_op_class_array(pMac, opClasses, + &pMac->scan.base_channels, "20MHz", &i); + csr_update_op_class_array(pMac, opClasses, + &pMac->scan.base40MHzChannels, "40MHz", &i); + numClasses = i; + + /* As per spec the operating classes should be in ascending order. + * Bubble sort is fine since we don't have many classes + */ + for (i = 0; i < (numClasses - 1); i++) { + for (j = 0; j < (numClasses - i - 1); j++) { + /* For decreasing order use < */ + if (opClasses[j] > opClasses[j + 1]) { + swap = opClasses[j]; + opClasses[j] = opClasses[j + 1]; + opClasses[j + 1] = swap; + } + } + } + + sms_log(pMac, LOG1, FL("Number of unique supported op classes %d"), + numClasses); + for (i = 0; i < numClasses; i++) { + sms_log(pMac, LOG1, FL("supported opClasses[%d] = %d"), i, + opClasses[i]); + } + + /* Set the ordered list of op classes in regdomain + * for use by other modules + */ + cds_regdm_set_curr_opclasses(numClasses, &opClasses[0]); +} + +/** + * csr_find_session_by_type() - This function will find given session type from + * all sessions. + * @mac_ctx: pointer to mac context. + * @type: session type + * + * Return: session id for give session type. + **/ +static uint32_t +csr_find_session_by_type(tpAniSirGlobal mac_ctx, tCDF_CON_MODE type) +{ + uint32_t i, session_id = CSR_SESSION_ID_INVALID; + tCsrRoamSession *session_ptr; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session_ptr = CSR_GET_SESSION(mac_ctx, i); + if (type == session_ptr->bssParams.bssPersona) { + session_id = i; + break; + } + } + return session_id; +} +/** + * csr_is_conn_allow_2g_band() - This function will check if station's conn + * is allowed in 2.4Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with SAP's operating channel. If SAP's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t sap_session_id; + tCsrRoamSession *sap_session; + + if (0 == chnl) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("channel is zero, connection not allowed")); + + return false; + } + + sap_session_id = csr_find_session_by_type(mac_ctx, CDF_SAP_MODE); + if (CSR_SESSION_ID_INVALID != sap_session_id) { + sap_session = CSR_GET_SESSION(mac_ctx, sap_session_id); + if ((0 != sap_session->bssParams.operationChn) && + (sap_session->bssParams.operationChn != chnl)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Can't allow STA to connect, chnls not same")); + return false; + } + } + return true; +} + +/** + * csr_is_conn_allow_5g_band() - This function will check if station's conn + * is allowed in 5Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with P2PGO's operating channel. If P2PGO's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t p2pgo_session_id; + tCsrRoamSession *p2pgo_session; + + if (0 == chnl) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("channel is zero, connection not allowed")); + return false; + } + + p2pgo_session_id = csr_find_session_by_type(mac_ctx, CDF_P2P_GO_MODE); + if (CSR_SESSION_ID_INVALID != p2pgo_session_id) { + p2pgo_session = CSR_GET_SESSION(mac_ctx, p2pgo_session_id); + if ((0 != p2pgo_session->bssParams.operationChn) && + (eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED != + p2pgo_session->connectState) && + (p2pgo_session->bssParams.operationChn != + chnl)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Can't allow STA to connect, chnls not same")); + return false; + } + } + return true; +} + +/** + * csr_clear_joinreq_param() - This function will clear station's params + * for stored join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will clear station's allocated memory for cached join + * request. + * + * Return: true or false based on function's overall success. + **/ +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + tCsrRoamSession *sta_session; + tScanResultList *bss_list; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + /* Release the memory allocated by previous join request */ + bss_list = + (tScanResultList *)&sta_session->stored_roam_profile. + bsslist_handle; + if (NULL != bss_list) { + csr_scan_result_purge(mac_ctx, + sta_session->stored_roam_profile.bsslist_handle); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("bss list is released for session %d"), session_id); + sta_session->stored_roam_profile.bsslist_handle = NULL; + } + sta_session->stored_roam_profile.bsslist_handle = NULL; + csr_release_profile(mac_ctx, &sta_session->stored_roam_profile.profile); + sta_session->stored_roam_profile.reason = 0; + sta_session->stored_roam_profile.roam_id = 0; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + return true; +} + +/** + * csr_store_joinreq_param() - This function will store station's join + * request to that station's session. + * @mac_ctx: pointer to mac context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will store station's join request to one of the + * csr structure and add it to station's session. + * + * Return: true or false based on function's overall success. + **/ +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + tCsrRoamSession *sta_session; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + sta_session->stored_roam_profile.session_id = session_id; + csr_roam_copy_profile(mac_ctx, + &sta_session->stored_roam_profile.profile, profile); + /* new bsslist_handle's memory will be relased later */ + sta_session->stored_roam_profile.bsslist_handle = scan_cache; + sta_session->stored_roam_profile.reason = eCsrHddIssued; + sta_session->stored_roam_profile.roam_id = *roam_id; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + + return true; +} + +/** + * csr_issue_stored_joinreq() - This function will issues station's stored + * the join request. + * @mac_ctx: pointer to mac context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request, from this point + * onwards the flow will be just like normal connect request. + * + * Return: CDF_STATUS_SUCCESS or CDF_STATUS_E_FAILURE. + **/ +CDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *sta_session; + uint32_t new_roam_id; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return CDF_STATUS_E_FAILURE; + new_roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + *roam_id = new_roam_id; + status = csr_roam_issue_connect(mac_ctx, + sta_session->stored_roam_profile.session_id, + &sta_session->stored_roam_profile.profile, + sta_session->stored_roam_profile.bsslist_handle, + sta_session->stored_roam_profile.reason, + new_roam_id, + sta_session->stored_roam_profile.imediate_flag, + sta_session->stored_roam_profile.clear_flag); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("CSR failed issuing connect cmd with status = 0x%08X"), + status); + csr_clear_joinreq_param(mac_ctx, session_id); + } + return status; +} + +/** + * csr_process_set_hw_mode() - Set HW mode command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the set HW mode command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct s_sir_set_hw_mode *cmd; + CDF_STATUS status; + tSirMsgQ msg; + struct sir_set_hw_mode_resp *param; + + /* Setting HW mode is for the entire system. + * So, no need to check session + */ + + if (!command) { + sms_log(mac, LOGE, FL("Set HW mode param is NULL")); + goto fail; + } + + len = sizeof(*cmd); + cmd = cdf_mem_malloc(len); + if (!cmd) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + cdf_mem_set(cmd, len, 0); + + cmd->messageType = eWNI_SME_SET_HW_MODE_REQ; + cmd->length = len; + cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same s_sir_set_hw_mode format. + */ + cmd->set_hw.set_hw_mode_cb = command->u.set_hw_mode_cmd.set_hw_mode_cb; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_SET_HW_MODE_REQ to PE")); + + status = cds_send_mb_message_to_mac(cmd); + if (CDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending set HW fail response to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_set_dual_mac_config() - Set HW mode command to PE + * @mac: Global MAC pointer + * @command: Command received from SME + * + * Posts the set dual mac config command to PE. + * + * Return: None + */ +void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_set_dual_mac_cfg *cmd; + CDF_STATUS status; + tSirMsgQ msg; + struct sir_dual_mac_config_resp *param; + + /* Setting MAC configuration is for the entire system. + * So, no need to check session + */ + + if (!command) { + sms_log(mac, LOGE, FL("Set HW mode param is NULL")); + goto fail; + } + + len = sizeof(*cmd); + cmd = cdf_mem_malloc(len); + if (!cmd) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + cmd->message_type = eWNI_SME_SET_DUAL_MAC_CFG_REQ; + cmd->length = len; + cmd->set_dual_mac.scan_config = command->u.set_dual_mac_cmd.scan_config; + cmd->set_dual_mac.fw_mode_config = + command->u.set_dual_mac_cmd.fw_mode_config; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same sir_set_dual_mac_cfg format. + */ + cmd->set_dual_mac.set_dual_mac_cb = + command->u.set_dual_mac_cmd.set_dual_mac_cb; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_SET_DUAL_MAC_CFG_REQ to PE: %x %x"), + cmd->set_dual_mac.scan_config, + cmd->set_dual_mac.fw_mode_config); + + status = cds_send_mb_message_to_mac(cmd); + if (CDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending set dual mac fail response to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_nss_update_req() - Update nss command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the nss update command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_nss_update_request *msg; + CDF_STATUS status; + tSirMsgQ msg_return; + struct sir_beacon_tx_complete_rsp *param; + + tCsrRoamSession *session = + CSR_GET_SESSION(mac, command->sessionId); + + if (!session) { + sms_log(mac, LOGE, FL("Session not found")); + goto fail; + } + + if (!command) { + sms_log(mac, LOGE, FL("nss update param is NULL")); + goto fail; + } + + len = sizeof(*msg); + msg = cdf_mem_malloc(len); + if (!msg) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response is also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + cdf_mem_set((void *)msg, sizeof(*msg), 0); + msg->msgType = eWNI_SME_NSS_UPDATE_REQ; + msg->msgLen = sizeof(*msg); + + msg->new_nss = command->u.nss_update_cmd.new_nss; + msg->vdev_id = command->u.nss_update_cmd.session_id; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_NSS_UPDATE_REQ to PE")); + + status = cds_send_mb_message_to_mac(msg); + if (CDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending nss update fail response to SME")); + param->tx_status = CDF_STATUS_E_FAILURE; + param->session_id = command->u.nss_update_cmd.session_id; + msg_return.type = eWNI_SME_NSS_UPDATE_RSP; + msg_return.bodyptr = param; + msg_return.bodyval = 0; + sys_process_mmh_msg(mac, &msg_return); +} diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c new file mode 100644 index 0000000000..68f0aeeef8 --- /dev/null +++ b/core/sme/src/csr/csr_api_scan.c @@ -0,0 +1,6941 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_api_scan.c + + Implementation for the Common Scan interfaces. + ========================================================================== */ + +#include "ani_global.h" + +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" + +#include "cds_reg_service.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "wma.h" + +#include "cds_concurrency.h" +#include "wlan_hdd_main.h" + +#define MIN_CHN_TIME_TO_FIND_GO 100 +#define MAX_CHN_TIME_TO_FIND_GO 100 +#define DIRECT_SSID_LEN 7 + +/* Purpose of HIDDEN_TIMER +** When we remove hidden ssid from the profile i.e., forget the SSID via GUI that SSID shouldn't see in the profile +** For above requirement we used timer limit, logic is explained below +** Timer value is initialsed to current time when it receives corresponding probe response of hidden SSID (The probe request is +** received regularly till SSID in the profile. Once it is removed from profile probe request is not sent.) when we receive probe response +** for broadcast probe request, during update SSID with saved SSID we will diff current time with saved SSID time if it is greater than 1 min +** then we are not updating with old one +*/ + +#define HIDDEN_TIMER (1*60*1000) +#define CSR_SCAN_RESULT_RSSI_WEIGHT 80 /* must be less than 100, represent the persentage of new RSSI */ + +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120 + +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20 + +#define PCL_ADVANTAGE 30 +#define PCL_RSSI_THRESHOLD -75 + +#define CSR_SCAN_IS_OVER_BSS_LIMIT(pMac) \ + ((pMac)->scan.nBssLimit <= (csr_ll_count(&(pMac)->scan.scanResultList))) + +void csr_scan_get_result_timer_handler(void *); +static void csr_scan_result_cfg_aging_timer_handler(void *pv); +static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType, + tCsrScanRequest *pScanRequest); +#ifdef WLAN_AP_STA_CONCURRENCY +static void csr_sta_ap_conc_timer_handler(void *); +#endif +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId); +CDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList, + uint8_t NumChannels); +void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId); +void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode); +void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList); +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac, uint8_t *pChannels, + uint8_t numChn, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIes); +bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel); +void csr_prune_channel_list_for_mode(tpAniSirGlobal pMac, + tCsrChannel *pChannelList); + +#define CSR_IS_SOCIAL_CHANNEL(channel) \ + (((channel) == 1) || ((channel) == 6) || ((channel) == 11)) + +static void csr_release_scan_cmd_pending_list(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + while ((pEntry = + csr_ll_remove_head(&pMac->scan.scanCmdPendingList, + LL_ACCESS_LOCK)) != NULL) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCsrCommandMask & pCommand->command) { + csr_abort_command(pMac, pCommand, true); + } else { + sms_log(pMac, LOGE, FL("Error: Received command : %d"), + pCommand->command); + } + } +} + +/* pResult is invalid calling this function. */ +void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult) +{ + if (NULL != pResult->Result.pvIes) { + cdf_mem_free(pResult->Result.pvIes); + } + cdf_mem_free(pResult); +} + +static CDF_STATUS csr_ll_scan_purge_result(tpAniSirGlobal pMac, + tDblLinkList *pList) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry; + tCsrScanResult *pBssDesc; + + csr_ll_lock(pList); + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + csr_free_scan_result_entry(pMac, pBssDesc); + } + + csr_ll_unlock(pList); + + return status; +} + +CDF_STATUS csr_scan_open(tpAniSirGlobal mac_ctx) +{ + CDF_STATUS status; + + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanResultList); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.tempScanResults); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList24); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList5G); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanCmdPendingList); +#endif + mac_ctx->scan.fFullScanIssued = false; + mac_ctx->scan.nBssLimit = CSR_MAX_BSS_SUPPORT; +#ifdef WLAN_AP_STA_CONCURRENCY + status = cdf_mc_timer_init(&mac_ctx->scan.hTimerStaApConcTimer, + CDF_TIMER_TYPE_SW, + csr_sta_ap_conc_timer_handler, + mac_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("Mem Alloc failed for hTimerStaApConcTimer timer")); + return status; + } +#endif + status = cdf_mc_timer_init(&mac_ctx->scan.hTimerResultCfgAging, + CDF_TIMER_TYPE_SW, + csr_scan_result_cfg_aging_timer_handler, + mac_ctx); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(mac_ctx, LOGE, + FL("Mem Alloc failed for CFG ResultAging timer")); + + return status; +} + +CDF_STATUS csr_scan_close(tpAniSirGlobal pMac) +{ + csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults); + csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_release_scan_cmd_pending_list(pMac); +#endif + csr_ll_close(&pMac->scan.scanResultList); + csr_ll_close(&pMac->scan.tempScanResults); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_ll_close(&pMac->scan.scanCmdPendingList); +#endif + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList24); + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList5G); + csr_ll_close(&pMac->scan.channelPowerInfoList24); + csr_ll_close(&pMac->scan.channelPowerInfoList5G); + csr_scan_disable(pMac); + cdf_mc_timer_destroy(&pMac->scan.hTimerResultCfgAging); +#ifdef WLAN_AP_STA_CONCURRENCY + cdf_mc_timer_destroy(&pMac->scan.hTimerStaApConcTimer); +#endif + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_scan_enable(tpAniSirGlobal pMac) +{ + + pMac->scan.fScanEnable = true; + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_scan_disable(tpAniSirGlobal pMac) +{ + + csr_scan_stop_timers(pMac); + pMac->scan.fScanEnable = false; + + return CDF_STATUS_SUCCESS; +} + +/* Set scan timing parameters according to state of other driver sessions */ +/* No validation of the parameters is performed. */ +static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType, + tCsrScanRequest *pScanRequest) +{ +#ifdef WLAN_AP_STA_CONCURRENCY + if (csr_is_any_session_connected(pMac)) { + /* Reset passive scan time as per ini parameter. */ + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pMac->roam.configParam.nPassiveMaxChnTimeConc); + /* If multi-session, use the appropriate default scan times */ + if (scanType == eSIR_ACTIVE_SCAN) { + pScanRequest->maxChnTime = + pMac->roam.configParam.nActiveMaxChnTimeConc; + pScanRequest->minChnTime = + pMac->roam.configParam.nActiveMinChnTimeConc; + } else { + pScanRequest->maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTimeConc; + pScanRequest->minChnTime = + pMac->roam.configParam.nPassiveMinChnTimeConc; + } + pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc; + + /* Return so that fields set above will not be overwritten. */ + return; + } +#endif + + /* This portion of the code executed if multi-session not supported */ + /* (WLAN_AP_STA_CONCURRENCY not defined) or no multi-session. */ + /* Use the "regular" (non-concurrency) default scan timing. */ + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pMac->roam.configParam.nPassiveMaxChnTime); + if (pScanRequest->scanType == eSIR_ACTIVE_SCAN) { + pScanRequest->maxChnTime = + pMac->roam.configParam.nActiveMaxChnTime; + pScanRequest->minChnTime = + pMac->roam.configParam.nActiveMinChnTime; + } else { + pScanRequest->maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTime; + pScanRequest->minChnTime = + pMac->roam.configParam.nPassiveMinChnTime; + } +#ifdef WLAN_AP_STA_CONCURRENCY + /* No rest time if no sessions are connected. */ + pScanRequest->restTime = 0; +#endif +} + +/** + * csr_scan_2g_only_request() - This function will update the scan request with + * only 2.4GHz valid channel list. + * @mac_ctx: Pointer to Global MAC structure + * @scan_cmd scan cmd + * @scan_req scan req + * + * This function will update the scan request with only 2.4GHz valid channel + * list. + * + * @Return: status of operation + */ +static CDF_STATUS +csr_scan_2g_only_request(tpAniSirGlobal mac_ctx, + tSmeCmd *scan_cmd, + tCsrScanRequest *scan_req) +{ + uint8_t idx, lst_sz = 0; + + CDF_ASSERT(scan_cmd && scan_req); + /* To silence the KW tool null check is added */ + if ((scan_cmd == NULL) || (scan_req == NULL)) { + sms_log(mac_ctx, LOGE, + FL(" Scan Cmd or Scan Request is NULL ")); + return CDF_STATUS_E_INVAL; + } + + if (eCSR_SCAN_REQUEST_FULL_SCAN != scan_req->requestType) + return CDF_STATUS_SUCCESS; + + sms_log(mac_ctx, LOG1, + FL("Scanning only 2G Channels during first scan")); + + /* Contsruct valid Supported 2.4 GHz Channel List */ + if (NULL == scan_req->ChannelInfo.ChannelList) { + scan_req->ChannelInfo.ChannelList = + cdf_mem_malloc(NUM_24GHZ_CHANNELS); + if (NULL == scan_req->ChannelInfo.ChannelList) { + sms_log(mac_ctx, LOGE, FL("Memory allocation failed.")); + return CDF_STATUS_E_NOMEM; + } + for (idx = 1; idx <= NUM_24GHZ_CHANNELS; idx++) { + if (csr_is_supported_channel(mac_ctx, idx)) { + scan_req->ChannelInfo.ChannelList[lst_sz] = idx; + lst_sz++; + } + } + } else { + for (idx = 0; + idx < scan_req->ChannelInfo.numOfChannels; + idx++) { + if (scan_req->ChannelInfo.ChannelList[idx] <= + CDS_24_GHZ_CHANNEL_14 + && csr_is_supported_channel(mac_ctx, + scan_req->ChannelInfo.ChannelList[idx])) { + scan_req->ChannelInfo.ChannelList[lst_sz] = + scan_req->ChannelInfo.ChannelList[idx]; + lst_sz++; + } + } + } + scan_req->ChannelInfo.numOfChannels = lst_sz; + return CDF_STATUS_SUCCESS; +} + +static void +csr_set_scan_reason(tSmeCmd *scan_cmd, eCsrRequestType req_type) +{ + switch (req_type) { + case eCSR_SCAN_REQUEST_11D_SCAN: + scan_cmd->u.scanCmd.reason = eCsrScan11d1; + break; +#ifdef SOFTAP_CHANNEL_RANGE + case eCSR_SCAN_SOFTAP_CHANNEL_RANGE: +#endif + case eCSR_SCAN_REQUEST_FULL_SCAN: + case eCSR_SCAN_P2P_DISCOVERY: + scan_cmd->u.scanCmd.reason = eCsrScanUserRequest; + break; + case eCSR_SCAN_HO_PROBE_SCAN: + scan_cmd->u.scanCmd.reason = eCsrScanProbeBss; + break; + case eCSR_SCAN_P2P_FIND_PEER: + scan_cmd->u.scanCmd.reason = eCsrScanP2PFindPeer; + break; + default: + break; + } +} + +static CDF_STATUS +csr_issue_11d_scan(tpAniSirGlobal mac_ctx, tSmeCmd *scan_cmd, + tCsrScanRequest *scan_req, uint16_t session_id) +{ + CDF_STATUS status; + tSmeCmd *scan_11d_cmd = NULL; + tCsrScanRequest tmp_rq; + tCsrChannelInfo *pChnInfo = &tmp_rq.ChannelInfo; + uint32_t numChn = mac_ctx->scan.base_channels.numChannels; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id); + + if (csr_session == NULL) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + session_id); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + if (!(((false == mac_ctx->first_scan_done) + && (eCSR_SCAN_REQUEST_11D_SCAN != scan_req->requestType)) +#ifdef SOFTAP_CHANNEL_RANGE + && (eCSR_SCAN_SOFTAP_CHANNEL_RANGE != scan_req->requestType) +#endif + && (false == mac_ctx->scan.fEnableBypass11d))) + return CDF_STATUS_SUCCESS; + + cdf_mem_set(&tmp_rq, sizeof(tCsrScanRequest), 0); + scan_11d_cmd = csr_get_command_buffer(mac_ctx); + if (!scan_11d_cmd) { + sms_log(mac_ctx, LOGE, FL("scan_11d_cmd failed")); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_set(&scan_11d_cmd->u.scanCmd, sizeof(tScanCmd), 0); + pChnInfo->ChannelList = cdf_mem_malloc(numChn); + if (NULL == pChnInfo->ChannelList) { + sms_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(pChnInfo->ChannelList, + mac_ctx->scan.base_channels.channelList, numChn); + + pChnInfo->numOfChannels = (uint8_t) numChn; + scan_11d_cmd->command = eSmeCommandScan; + scan_11d_cmd->u.scanCmd.callback = mac_ctx->scan.callback11dScanDone; + scan_11d_cmd->u.scanCmd.pContext = NULL; + wma_get_scan_id(&scan_11d_cmd->u.scanCmd.scanID); + tmp_rq.BSSType = eCSR_BSS_TYPE_ANY; + tmp_rq.scan_id = scan_11d_cmd->u.scanCmd.scanID; + + status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, &scan_11d_cmd); + + if (csr_is11d_supported(mac_ctx)) { + tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan; + if (scan_req->bcnRptReqScan) + tmp_rq.scanType = scan_req->scanType ? + eSIR_PASSIVE_SCAN : scan_req->scanType; + else + tmp_rq.scanType = eSIR_PASSIVE_SCAN; + tmp_rq.requestType = eCSR_SCAN_REQUEST_11D_SCAN; + scan_11d_cmd->u.scanCmd.reason = eCsrScan11d1; + tmp_rq.maxChnTime = + mac_ctx->roam.configParam.nPassiveMaxChnTime; + tmp_rq.minChnTime = + mac_ctx->roam.configParam.nPassiveMinChnTime; + } else { + tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan; + if (scan_req->bcnRptReqScan) + tmp_rq.scanType = scan_req->scanType; + else + tmp_rq.scanType = eSIR_ACTIVE_SCAN; + tmp_rq.requestType = scan_req->requestType; + scan_11d_cmd->u.scanCmd.reason = scan_cmd->u.scanCmd.reason; + tmp_rq.maxChnTime = mac_ctx->roam.configParam.nActiveMaxChnTime; + tmp_rq.minChnTime = mac_ctx->roam.configParam.nActiveMinChnTime; + } + if (mac_ctx->roam.configParam.nInitialDwellTime) { + tmp_rq.maxChnTime = mac_ctx->roam.configParam.nInitialDwellTime; + sms_log(mac_ctx, LOG1, FL("11d scan, updating dwell time for first scan %u"), + tmp_rq.maxChnTime); + } + + status = csr_scan_copy_request(mac_ctx, + &scan_11d_cmd->u.scanCmd.u.scanRequest, &tmp_rq); + /* Free the channel list */ + cdf_mem_free(pChnInfo->ChannelList); + pChnInfo->ChannelList = NULL; + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("csr_scan_copy_request failed")); + return CDF_STATUS_E_FAILURE; + } + + mac_ctx->scan.scanProfile.numOfChannels = + scan_11d_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + + + status = csr_queue_sme_command(mac_ctx, scan_11d_cmd, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Failed to send message status = %d"), + status); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_scan_request(tpAniSirGlobal pMac, uint16_t sessionId, + tCsrScanRequest *scan_req, + csr_scan_completeCallback callback, void *pContext) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSmeCmd *scan_cmd = NULL; + tCsrScanRequest *pTempScanReq = NULL; + tCsrConfig *cfg_prm = &pMac->roam.configParam; + + if (scan_req == NULL) { + sms_log(pMac, LOGE, FL("scan_req is NULL")); + CDF_ASSERT(0); + return status; + } + + /* + * During group formation, the P2P client scans for GO with the specific + * SSID. There will be chances of GO switching to other channels because + * of scan or to STA channel in case of STA+GO MCC scenario. So to + * increase the possibility of client to find the GO, the dwell time of + * scan is increased to 100ms. + * If the scan request is for specific SSId the length of SSID will be + * greater than 7 as SSID for p2p search contains "DIRECT-") + */ + if (scan_req->p2pSearch + && scan_req->SSIDs.numOfSSIDs + && (NULL != scan_req->SSIDs.SSIDList) + && (scan_req->SSIDs.SSIDList->SSID.length > DIRECT_SSID_LEN)) { + sms_log(pMac, LOG1, FL("P2P: Increasing the min and max Dwell time to %d for specific SSID scan %.*s"), + MAX_CHN_TIME_TO_FIND_GO, + scan_req->SSIDs.SSIDList->SSID.length, + scan_req->SSIDs.SSIDList->SSID.ssId); + scan_req->maxChnTime = MAX_CHN_TIME_TO_FIND_GO; + scan_req->minChnTime = MIN_CHN_TIME_TO_FIND_GO; + } + + if (!pMac->scan.fScanEnable) { + sms_log(pMac, LOGE, FL("SId: %d Scanning not enabled Scan type=%u, numOfSSIDs=%d P2P search=%d"), + sessionId, scan_req->requestType, + scan_req->SSIDs.numOfSSIDs, + scan_req->p2pSearch); + goto release_cmd; + } + + scan_cmd = csr_get_command_buffer(pMac); + if (!scan_cmd) { + sms_log(pMac, LOGE, FL("scan_cmd is NULL")); + goto release_cmd; + } + + cdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0); + scan_cmd->command = eSmeCommandScan; + scan_cmd->sessionId = sessionId; + if (scan_cmd->sessionId >= CSR_ROAM_SESSION_MAX) + sms_log(pMac, LOGE, FL("Invalid Sme SessionID: %d"), sessionId); + scan_cmd->u.scanCmd.callback = callback; + scan_cmd->u.scanCmd.pContext = pContext; + csr_set_scan_reason(scan_cmd, scan_req->requestType); + if (scan_req->minChnTime == 0 && scan_req->maxChnTime == 0) { + /* The caller doesn't set the time correctly. Set it here */ + csr_set_default_scan_timing(pMac, scan_req->scanType, scan_req); + sms_log(pMac, LOG1, + FL("Setting default min %d and max %d ChnTime"), + scan_req->minChnTime, scan_req->maxChnTime); + } +#ifdef WLAN_AP_STA_CONCURRENCY + /* Need to set restTime only if at least one session is connected */ + if (scan_req->restTime == 0 && csr_is_any_session_connected(pMac)) { + scan_req->restTime = cfg_prm->nRestTimeConc; + if (scan_req->scanType == eSIR_ACTIVE_SCAN) { + scan_req->maxChnTime = cfg_prm->nActiveMaxChnTimeConc; + scan_req->minChnTime = cfg_prm->nActiveMinChnTimeConc; + } else { + scan_req->maxChnTime = cfg_prm->nPassiveMaxChnTimeConc; + scan_req->minChnTime = cfg_prm->nPassiveMinChnTimeConc; + } + } +#endif + /* Increase dwell time in case P2P Search and Miracast is not present */ + if (scan_req->p2pSearch && scan_req->ChannelInfo.numOfChannels + == P2P_SOCIAL_CHANNELS && (!(pMac->sme.miracast_value))) { + scan_req->maxChnTime += P2P_SEARCH_DWELL_TIME_INCREASE; + } + scan_cmd->u.scanCmd.scanID = scan_req->scan_id; + /* + * If it is the first scan request from HDD, CSR checks if it is for 11d + * If it is not, CSR will save the scan request in the pending cmd queue + * & issue an 11d scan request to PE. + */ + status = csr_issue_11d_scan(pMac, scan_cmd, scan_req, sessionId); + if (status != CDF_STATUS_SUCCESS) + goto release_cmd; + + /* + * Scan only 2G Channels if set in ini file. This is mainly to reduce + * the First Scan duration once we turn on Wifi + */ + if (pMac->scan.fFirstScanOnly2GChnl + && false == pMac->first_scan_done) { + csr_scan_2g_only_request(pMac, scan_cmd, scan_req); + pMac->first_scan_done = true; + } + + + if (cfg_prm->nInitialDwellTime) { + scan_req->maxChnTime = cfg_prm->nInitialDwellTime; + cfg_prm->nInitialDwellTime = 0; + sms_log(pMac, LOG1, FL("updating dwell time for first scan %u"), + scan_req->maxChnTime); + } + + status = csr_scan_copy_request(pMac, &scan_cmd->u.scanCmd.u.scanRequest, + scan_req); + /* + * Reset the variable after the first scan is queued after loading the + * driver. The purpose of this parameter is that DFS channels are + * skipped during the first scan after loading the driver. The above API + * builds the target scan request in which this variable is used. + */ + cfg_prm->initial_scan_no_dfs_chnl = 0; + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to copy request status = %d"), status); + goto release_cmd; + } + + pTempScanReq = &scan_cmd->u.scanCmd.u.scanRequest; + pMac->scan.scanProfile.numOfChannels = + pTempScanReq->ChannelInfo.numOfChannels; + status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, scan_cmd); + sms_log(pMac, LOG1, + FL("SId=%d scanId=%d Scan reason=%u numSSIDs=%d numChan=%d P2P search=%d minCT=%d maxCT=%d uIEFieldLen=%d"), + sessionId, scan_cmd->u.scanCmd.scanID, + scan_cmd->u.scanCmd.reason, pTempScanReq->SSIDs.numOfSSIDs, + pTempScanReq->ChannelInfo.numOfChannels, + pTempScanReq->p2pSearch, pTempScanReq->minChnTime, + pTempScanReq->maxChnTime, pTempScanReq->uIEFieldLen); + + status = csr_queue_sme_command(pMac, scan_cmd, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to send message status = %d"), status); + } + +release_cmd: + if (!CDF_IS_STATUS_SUCCESS(status) && scan_cmd) { + sms_log(pMac, LOGE, FL(" SId: %d Failed with status=%d" + " Scan reason=%u numOfSSIDs=%d" + " P2P search=%d scanId=%d"), + sessionId, status, scan_cmd->u.scanCmd.reason, + scan_req->SSIDs.numOfSSIDs, scan_req->p2pSearch, + scan_cmd->u.scanCmd.scanID); + csr_release_command_scan(pMac, scan_cmd); + } + + return status; +} + +CDF_STATUS csr_issue_roam_after_lostlink_scan(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrRoamReason reason) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = NULL; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId = 0; + tCsrRoamProfile *pProfile = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, FL("Entry")); + if (pSession->fCancelRoaming) { + sms_log(pMac, LOGW, FL("lost link roaming canceled")); + status = CDF_STATUS_SUCCESS; + goto free_filter; + } + /* Here is the profile we need to connect to */ + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = CDF_STATUS_E_NOMEM; + goto free_filter; + } + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + if (NULL == pSession->pCurRoamProfile) { + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + } else { + /* + * We have to make a copy of pCurRoamProfile because it will + * be free inside csr_roam_issue_connect + */ + pProfile = cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == pProfile) { + status = CDF_STATUS_E_NOMEM; + goto free_filter; + } + cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0); + status = csr_roam_copy_profile(pMac, pProfile, + pSession->pCurRoamProfile); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + } /* We have a profile */ + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + + if (eCsrLostLink1 == reason) { + /* if possible put the last connected BSS in beginning */ + csr_move_bss_to_head_from_bssid(pMac, + &pSession->connectedProfile.bssid, hBSSList); + } + status = csr_roam_issue_connect(pMac, sessionId, pProfile, hBSSList, + reason, roamId, true, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, hBSSList); + } + +free_filter: + if (pScanFilter) { + /* we need to free memory for filter if profile exists */ + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + } + if (NULL != pProfile) { + csr_release_profile(pMac, pProfile); + cdf_mem_free(pProfile); + } + return status; +} + +CDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOGW, "Lost link scan 1 failed"); + if (pSession->fCancelRoaming) + return CDF_STATUS_E_FAILURE; + if (!pSession->pCurRoamProfile) + return csr_scan_request_lost_link3(pMac, sessionId); + /* + * We fail lostlink1 but there may be other BSS in the cached result + * fit the profile. Give it a try first + */ + if (pSession->pCurRoamProfile->SSIDs.numOfSSIDs == 0 || + pSession->pCurRoamProfile->SSIDs.numOfSSIDs > 1) + /* try lostlink scan2 */ + return csr_scan_request_lost_link2(pMac, sessionId); + if (!pSession->pCurRoamProfile->ChannelInfo.ChannelList + || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) { + /* go straight to lostlink scan3 */ + return csr_scan_request_lost_link3(pMac, sessionId); + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, "Lost link scan 2 failed"); + if (pSession->fCancelRoaming) + return CDF_STATUS_E_FAILURE; + + if (!pSession->pCurRoamProfile + || !pSession->pCurRoamProfile->ChannelInfo.ChannelList + || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) { + /* try lostlink scan3 */ + return csr_scan_request_lost_link3(pMac, sessionId); + } + return CDF_STATUS_E_FAILURE; +} + +CDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sms_log(pMac, LOGW, "Lost link scan 3 failed"); + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS +csr_update_lost_link1_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + tCsrRoamSession *pSession, uint32_t session_id) +{ + uint8_t i, num_ch = 0; + tScanResultHandle bss_lst = NULL; + tCsrScanResultInfo *scan_result = NULL; + tCsrScanResultFilter *scan_filter = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrSSIDs *ssid_list = &cmd->u.scanCmd.u.scanRequest.SSIDs; + tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink1; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, &cmd); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + + if (pSession->connectedProfile.SSID.length) { + /* + * on error: following memory will be released by call to + * csr_release_command_scan in the end + */ + ssid_list->SSIDList = cdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == ssid_list->SSIDList) + return CDF_STATUS_E_NOMEM; + ssid_list->numOfSSIDs = 1; + cdf_mem_copy(&ssid_list->SSIDList[0].SSID, + &pSession->connectedProfile.SSID, + sizeof(tSirMacSSid)); + } else { + ssid_list->numOfSSIDs = 0; + } + + if (!pSession->pCurRoamProfile) + return CDF_STATUS_SUCCESS; + + scan_filter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(scan_filter, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(mac_ctx, + pSession->pCurRoamProfile, scan_filter); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link1_local_mem; + + if (!(CDF_IS_STATUS_SUCCESS(csr_scan_get_result(mac_ctx, scan_filter, + &bss_lst)) && bss_lst)) { + if (csr_roam_is_channel_valid(mac_ctx, + pSession->connectedProfile.operationChannel)) { + ch_info->ChannelList = cdf_mem_malloc(1); + if (NULL == ch_info->ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto free_lost_link1_local_mem; + } + ch_info->ChannelList[0] = + pSession->connectedProfile.operationChannel; + ch_info->numOfChannels = 1; + } + return status; + } + + /* on error: this mem will be released by csr_release_command_scan */ + ch_info->ChannelList = cdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == ch_info->ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto free_lost_link1_local_mem; + } + + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + scan_result->BssDescriptor.channelId) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + scan_result->BssDescriptor.channelId; + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + } + /* Include the last connected BSS' channel */ + if (csr_roam_is_channel_valid(mac_ctx, + pSession->connectedProfile.operationChannel)) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + pSession->connectedProfile.operationChannel) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + pSession->connectedProfile.operationChannel; + } + ch_info->numOfChannels = num_ch; +free_lost_link1_local_mem: + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + cdf_mem_free(scan_filter); + } + if (bss_lst) + csr_scan_result_purge(mac_ctx, bss_lst); + return status; +} + +/** + * csr_scan_request_lost_link1() - start scan on link lost 1 + * @mac_ctx: mac global context + * @session_id: session id + * + * Lostlink1 scan is to actively scan the last connected profile's SSID on all + * matched BSS channels. If no roam profile (it should not), it is like + * lostlinkscan3 + * + * Return: status of operation + */ +CDF_STATUS +csr_scan_request_lost_link1(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *cmd = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return CDF_STATUS_E_FAILURE; + } + + sms_log(mac_ctx, LOGW, FL("Entry")); + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = CDF_STATUS_E_RESOURCES; + goto release_lost_link1_cmd; + } + cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + status = csr_update_lost_link1_cmd(mac_ctx, cmd, session, session_id); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto release_lost_link1_cmd; + + cdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid, + sizeof(struct cdf_mac_addr), 0xFF); + status = csr_queue_sme_command(mac_ctx, cmd, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + } + +release_lost_link1_cmd: + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + status = csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + } + return status; +} + +static CDF_STATUS +csr_update_lost_link2_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + uint32_t session_id, tCsrRoamSession *session) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t i, num_ch = 0; + tScanResultHandle bss_lst = NULL; + tCsrScanResultInfo *scan_result = NULL; + tCsrScanResultFilter *scan_fltr = NULL; + tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink2; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + if (!session->pCurRoamProfile) + return CDF_STATUS_SUCCESS; + status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, &cmd); + scan_fltr = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_fltr) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(scan_fltr, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(mac_ctx, + session->pCurRoamProfile, scan_fltr); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link2_local_mem; + + status = csr_scan_get_result(mac_ctx, scan_fltr, &bss_lst); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link2_local_mem; + + if (!bss_lst) + goto free_lost_link2_local_mem; + + ch_info->ChannelList = cdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == ch_info->ChannelList) { + status = CDF_STATUS_E_NOMEM; + goto free_lost_link2_local_mem; + } + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + scan_result->BssDescriptor.channelId) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + scan_result->BssDescriptor.channelId; + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + } + ch_info->numOfChannels = num_ch; + +free_lost_link2_local_mem: + if (scan_fltr) { + csr_free_scan_filter(mac_ctx, scan_fltr); + cdf_mem_free(scan_fltr); + } + if (bss_lst) + csr_scan_result_purge(mac_ctx, bss_lst); + return status; +} + +/** + * csr_scan_request_lost_link2() - start scan on link lost 2 + * @mac_ctx: mac global context + * @session_id: session id + * + * Lostlink2 scan is to actively scan the all SSIDs of the last roaming + * profile's on all matched BSS channels. Since MAC doesn't support multiple + * SSID, we scan all SSIDs and filter them afterwards + * + * Return: status of operation + */ +CDF_STATUS +csr_scan_request_lost_link2(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *cmd = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return CDF_STATUS_E_FAILURE; + } + + sms_log(mac_ctx, LOGW, FL(" called")); + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = CDF_STATUS_E_RESOURCES; + goto release_lost_link2_cmd; + } + cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + status = csr_update_lost_link2_cmd(mac_ctx, cmd, session_id, session); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto release_lost_link2_cmd; + + cdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid, + sizeof(struct cdf_mac_addr), 0xFF); + /* Put to the head in pending queue */ + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + goto release_lost_link2_cmd; + } + +release_lost_link2_cmd: + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + status = csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + } + return status; +} + +/** + * csr_scan_request_lost_link3() - To actively scan all valid channels + * @mac_ctx: mac global context + * @session_id: session id + * + * Return: status of operation + */ +CDF_STATUS +csr_scan_request_lost_link3(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSmeCmd *cmd; + + sms_log(mac_ctx, LOGW, FL(" called")); + do { + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = CDF_STATUS_E_RESOURCES; + break; + } + cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink3; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, &cmd); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + cdf_set_macaddr_broadcast(&cmd->u.scanCmd.u.scanRequest.bssid); + /* Put to the head of pending queue */ + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + break; + } + } while (0); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + } + + return status; +} + +CDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + tCsrScanResultFilter *pScanFilter = NULL; + tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile; + uint32_t sessionId = pCommand->sessionId; + + do { + /* If this scan is for LFR */ + if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done(pMac, + sessionId, CDF_STATUS_SUCCESS); + if (CDF_STATUS_SUCCESS != status) + csr_neighbor_roam_start_lfr_scan(pMac, + sessionId); + status = CDF_STATUS_SUCCESS; + break; + } + /* + * If there is roam command waiting, ignore this roam because + * the newer roam command is the one to execute + */ + if (csr_is_roam_command_waiting_for_session(pMac, sessionId)) { + sms_log(pMac, LOGW, + FL("aborts because roam command waiting")); + break; + } + if (pProfile == NULL) + break; + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = CDF_STATUS_E_NOMEM; + break; + } + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_roam_issue_connect(pMac, sessionId, pProfile, + hBSSList, eCsrHddIssued, + pCommand->u.scanCmd.roamId, + true, true); + } while (0); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + if (CSR_INVALID_SCANRESULT_HANDLE != hBSSList) { + csr_scan_result_purge(pMac, hBSSList); + } + /* We haven't done anything to this profile */ + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_FAILURE); + } + if (pScanFilter) { + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + } + return status; +} + +CDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t sessionId = pCommand->sessionId; + tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + eCsrRoamResult roam_result; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + /* If this scan is for LFR */ + if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done(pMac, sessionId, + CDF_STATUS_E_FAILURE); + if (CDF_STATUS_SUCCESS != status) + csr_neighbor_roam_start_lfr_scan(pMac, sessionId); + return CDF_STATUS_SUCCESS; + } +#ifdef WLAN_DEBUG + if (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs == 1) { + char str[36]; + tSirMacSSid *ptr_ssid = + &pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID; + cdf_mem_copy(str, ptr_ssid->ssId, ptr_ssid->length); + str[ptr_ssid->length] = 0; + sms_log(pMac, LOGW, FL("SSID = %s"), str); + } +#endif + /* + * Check whether it is for start ibss. No need to do anything if it + * is a JOIN request + */ + if (pProfile && CSR_IS_START_IBSS(pProfile)) { + status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL, + eCsrHddIssued, pCommand->u.scanCmd.roamId, + true, true); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("failed to issue startIBSS, status: 0x%08X"), + status); + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; + } + roam_result = eCSR_ROAM_RESULT_FAILURE; + if (NULL != pProfile && csr_is_bss_type_ibss(pProfile->BSSType)) { + roam_result = eCSR_ROAM_RESULT_IBSS_START_FAILED; + goto roam_completion; + } + /* Only indicate assoc_completion if we indicate assoc_start. */ + if (pSession->bRefAssocStartCnt > 0) { + tCsrRoamInfo *pRoamInfo = NULL, roamInfo; + + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + if (pCommand->u.roamCmd.pRoamBssEntry) { + tCsrScanResult *pScanResult = GET_BASE_ADDR( + pCommand->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + roamInfo.pBssDesc = &pScanResult->Result.BssDescriptor; + } + roamInfo.statusCode = pSession->joinFailStatusCode.statusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + pSession->bRefAssocStartCnt--; + csr_roam_call_callback(pMac, sessionId, pRoamInfo, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } else { + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_FAILURE); + } +roam_completion: + csr_roam_completion(pMac, sessionId, NULL, pCommand, roam_result, + false); + return status; +} + +CDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + tScanResultHandle hScanList) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + tScanResultList *pScanList = (tScanResultList *) hScanList; + + if (pScanList) { + status = csr_ll_scan_purge_result(pMac, &pScanList->List); + csr_ll_close(&pScanList->List); + cdf_mem_free(pScanList); + } + return status; +} + +/** + * csr_derive_prefer_value_from_rssi() - to derive prefer value + * @mac_ctx: Global MAC Context + * @rssi: RSSI of the BSS + * + * This routine will derive preferred value from given rssi + * + * Return: value between 0 to 14 + */ +static int csr_derive_prefer_value_from_rssi(tpAniSirGlobal mac_ctx, int rssi) +{ + int i = CSR_NUM_RSSI_CAT - 1, pref_val = 0; + while (i >= 0) { + if (rssi >= mac_ctx->roam.configParam.RSSICat[i]) { + pref_val = mac_ctx->roam.configParam.BssPreferValue[i]; + break; + } + i--; + }; + return pref_val; +} + +/** + * is_channel_found_in_pcl() - to check if channel is present in pcl + * @mac_ctx: Global MAC Context + * @channel_id: channel of bss + * @filter: pointer to filter created through profile + * + * to check if provided channel is present in pcl + * + * Return: true or false + */ +static bool is_channel_found_in_pcl(tpAniSirGlobal mac_ctx, int channel_id, + tCsrScanResultFilter *filter) +{ + int i; + bool status = false; + + if (NULL == filter) + return status; + + for (i = 0; i < filter->pcl_channels.numChannels; i++) { + if (filter->pcl_channels.channelList[i] == channel_id) { + status = true; + break; + } + } + return status; +} +/** + * csr_get_altered_rssi() - Artificially increase/decrease RSSI + * @mac_ctx: Global MAC Context pointer. + * @rssi: Actual RSSI of the AP. + * @channel_id: Channel on which the AP is parked. + * @bssid: BSSID of the AP to connect to. + * + * This routine will apply the boost and penalty parameters + * if the channel_id is of 5G band and it will also apply + * the preferred bssid score if there is a match between + * the bssid and the global preferred bssid list. + * + * Return: The modified RSSI Value + */ +static int csr_get_altered_rssi(tpAniSirGlobal mac_ctx, int rssi, + uint8_t channel_id, struct cdf_mac_addr *bssid) +{ + int modified_rssi; + int boost_factor; + int penalty_factor; + int i; + struct roam_ext_params *roam_params; + struct cdf_mac_addr fav_bssid; + struct cdf_mac_addr local_bssid; + + modified_rssi = rssi; + cdf_mem_zero(&local_bssid.bytes, CDF_MAC_ADDR_SIZE); + if (bssid) + cdf_mem_copy(local_bssid.bytes, bssid->bytes, + CDF_MAC_ADDR_SIZE); + roam_params = &mac_ctx->roam.configParam.roam_params; + /* + * If the 5G pref feature is enabled, apply the roaming + * parameters to boost or penalize the rssi. + * Boost Factor = boost_factor * (Actual RSSI - boost Threshold) + * Penalty Factor = penalty factor * (penalty threshold - Actual RSSI) + */ + if (CSR_IS_SELECT_5G_PREFERRED(mac_ctx) && + CDS_IS_CHANNEL_5GHZ(channel_id)) { + if (rssi > roam_params->raise_rssi_thresh_5g) { + /* Check and boost the threshold*/ + boost_factor = roam_params->raise_factor_5g * + (rssi - roam_params->raise_rssi_thresh_5g); + /* Check and penalize the threshold */ + modified_rssi += CSR_MIN(roam_params->max_raise_rssi_5g, + boost_factor); + } else if (rssi < roam_params->drop_rssi_thresh_5g) { + penalty_factor = roam_params->drop_factor_5g * + (roam_params->drop_rssi_thresh_5g - rssi); + modified_rssi -= CSR_MAX(roam_params->max_drop_rssi_5g, + penalty_factor); + } + sms_log(mac_ctx, LOG2, + FL("5G BSSID"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"), + MAC_ADDR_ARRAY(local_bssid.bytes), + rssi, modified_rssi, channel_id); + } + /* + * Check if there are preferred bssid and then apply the + * preferred score + */ + cdf_mem_zero(&fav_bssid.bytes, CDF_MAC_ADDR_SIZE); + if (roam_params->num_bssid_favored) { + for (i = 0; i < roam_params->num_bssid_favored; i++) { + cdf_mem_copy(fav_bssid.bytes, + &roam_params->bssid_favored[i], + CDF_MAC_ADDR_SIZE); + if (!cdf_is_macaddr_equal(&fav_bssid, bssid)) + continue; + modified_rssi += roam_params->bssid_favored_factor[i]; + sms_log(mac_ctx, LOG2, + FL("Pref"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"), + MAC_ADDR_ARRAY(local_bssid.bytes), + rssi, modified_rssi, channel_id); + } + } + return modified_rssi; +} + +/** + * csr_get_bss_prefer_value() - Get the preference value for BSS + * @mac_ctx: Global MAC Context + * @rssi: RSSI of the BSS + * @bssid: BSSID to which the preference value is returned + * @channel_id: Channel on which the AP is parked + * + * Each BSS descriptor should be assigned a preference value ranging from + * 14-0, which will be used as an RSSI bucket score while sorting the + * scan results. + * + * Return: Preference value for the BSSID + */ +static uint32_t csr_get_bss_prefer_value(tpAniSirGlobal mac_ctx, int rssi, + struct cdf_mac_addr *bssid, int channel_id) +{ + uint32_t ret = 0; + int modified_rssi; + + /* + * The RSSI does not get modified in case the 5G + * preference or preferred BSSID is not applicable + */ + modified_rssi = csr_get_altered_rssi(mac_ctx, rssi, channel_id, bssid); + ret = csr_derive_prefer_value_from_rssi(mac_ctx, modified_rssi); + + return ret; +} + +/* Return a CapValue base on the capabilities of a BSS */ +static uint32_t csr_get_bss_cap_value(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + uint32_t ret = CSR_BSS_CAP_VALUE_NONE; +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (CSR_IS_ROAM_PREFER_5GHZ(pMac) || CSR_IS_SELECT_5G_PREFERRED(pMac)) { + if ((pBssDesc) && CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId)) { + ret += CSR_BSS_CAP_VALUE_5GHZ; + } + } +#endif + /* + * if strict select 5GHz is non-zero then ignore the capability checking + */ + if (pIes && !CSR_IS_SELECT_5GHZ_MARGIN(pMac)) { + /* We only care about 11N capability */ + if (pIes->VHTCaps.present) + ret += CSR_BSS_CAP_VALUE_VHT; + else if (pIes->HTCaps.present) + ret += CSR_BSS_CAP_VALUE_HT; + if (CSR_IS_QOS_BSS(pIes)) { + ret += CSR_BSS_CAP_VALUE_WMM; + /* Give advantage to UAPSD */ + if (CSR_IS_UAPSD_BSS(pIes)) { + ret += CSR_BSS_CAP_VALUE_UAPSD; + } + } + } + + return ret; +} + +/** + * csr_is_better_rssi() - Is bss1 better than bss2 + * @mac_ctx: Global MAC Context pointer. + * @bss1: Pointer to the first BSS. + * @bss2: Pointer to the second BSS. + * + * This routine helps in determining the preference value + * of a particular BSS in the scan result which is further + * used in the sorting logic of the final candidate AP's. + * + * Return: true, if bss1 is better than bss2 + * false, if bss2 is better than bss1. + */ +static bool csr_is_better_rssi(tpAniSirGlobal mac_ctx, + tCsrScanResult *bss1, tCsrScanResult *bss2) +{ + bool ret; + int rssi1, rssi2; + struct cdf_mac_addr local_mac; + + rssi1 = bss1->Result.BssDescriptor.rssi; + rssi2 = bss2->Result.BssDescriptor.rssi; + /* + * Apply the boost and penlty logic and check + * which is the best RSSI + */ + cdf_mem_zero(&local_mac.bytes, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(&local_mac.bytes, + &bss1->Result.BssDescriptor.bssId, CDF_MAC_ADDR_SIZE); + rssi1 = csr_get_altered_rssi(mac_ctx, rssi1, + bss1->Result.BssDescriptor.channelId, + &local_mac); + cdf_mem_copy(&local_mac.bytes, + &bss2->Result.BssDescriptor.bssId, CDF_MAC_ADDR_SIZE); + rssi2 = csr_get_altered_rssi(mac_ctx, rssi2, + bss2->Result.BssDescriptor.channelId, + &local_mac); + if (CSR_IS_BETTER_RSSI(rssi1, rssi2)) + ret = true; + else + ret = false; + return ret; +} + +/** + * csr_is_better_bss() - Is bss1 better than bss2 + * @mac_ctx: Global MAC Context pointer. + * @bss1: Pointer to the first BSS. + * @bss2: Pointer to the second BSS. + * + * This routine helps in determining the preference value + * of a particular BSS in the scan result which is further + * used in the sorting logic of the final candidate AP's. + * + * Return: true, if bss1 is better than bss2 + * false, if bss2 is better than bss1. + */ +static bool csr_is_better_bss(tpAniSirGlobal mac_ctx, + tCsrScanResult *bss1, tCsrScanResult *bss2) +{ + bool ret; + + if (CSR_IS_BETTER_PREFER_VALUE(bss1->preferValue, bss2->preferValue)) { + ret = true; + } else if (CSR_IS_EQUAL_PREFER_VALUE + (bss1->preferValue, bss2->preferValue)) { + if (CSR_IS_BETTER_CAP_VALUE(bss1->capValue, bss2->capValue)) + ret = true; + else if (CSR_IS_EQUAL_CAP_VALUE + (bss1->capValue, bss2->capValue)) { + if (csr_is_better_rssi(mac_ctx, bss1, bss2)) + ret = true; + else + ret = false; + } else { + ret = false; + } + } else { + ret = false; + } + + return ret; +} + +#ifdef FEATURE_WLAN_LFR +/* Add the channel to the occupiedChannels array */ +static void csr_scan_add_to_occupied_channels(tpAniSirGlobal pMac, + tCsrScanResult *pResult, + uint8_t sessionId, + tCsrChannel *occupied_ch, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status; + uint8_t ch; + uint8_t num_occupied_ch = occupied_ch->numChannels; + uint8_t *occupied_ch_lst = occupied_ch->channelList; + + ch = pResult->Result.BssDescriptor.channelId; + if (csr_is_channel_present_in_list(occupied_ch_lst, num_occupied_ch, ch) + || !csr_neighbor_roam_connected_profile_match(pMac, sessionId, + pResult, pIes)) + return; + + status = csr_add_to_channel_list_front(occupied_ch_lst, + num_occupied_ch, ch); + if (CDF_IS_STATUS_SUCCESS(status)) { + occupied_ch->numChannels++; + sms_log(pMac, LOG2, + FL("Added channel %d to the list (count=%d)"), + ch, occupied_ch->numChannels); + if (occupied_ch->numChannels > + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN) + occupied_ch->numChannels = + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN; + } +} +#endif + +/* Put the BSS into the scan result list */ +/* pIes can not be NULL */ +static void csr_scan_add_result(tpAniSirGlobal pMac, tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes, uint32_t sessionId) +{ +#ifdef FEATURE_WLAN_LFR + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; +#endif + + struct cdf_mac_addr bssid; + uint8_t channel_id = pResult->Result.BssDescriptor.channelId; + cdf_mem_zero(&bssid.bytes, CDF_MAC_ADDR_SIZE); + cdf_mem_copy(bssid.bytes, &pResult->Result.BssDescriptor.bssId, + CDF_MAC_ADDR_SIZE); + pResult->preferValue = csr_get_bss_prefer_value(pMac, + (int)pResult->Result.BssDescriptor.rssi, + &bssid, channel_id); + pResult->capValue = csr_get_bss_cap_value(pMac, + &pResult->Result.BssDescriptor, pIes); + csr_ll_insert_tail(&pMac->scan.scanResultList, &pResult->Link, + LL_ACCESS_LOCK); +#ifdef FEATURE_WLAN_LFR + if (0 == pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) { + /* + * Build the occupied channel list, only if + * "gNeighborScanChannelList" is NOT set in the cfg.ini file + */ + csr_scan_add_to_occupied_channels(pMac, pResult, sessionId, + &pMac->scan.occupiedChannels[sessionId], pIes); + } +#endif +} + +static void +csr_parser_scan_result_for_5ghz_preference(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter) +{ + bool fMatch; + CDF_STATUS status; + tListElem *pEntry; + tDot11fBeaconIEs *pIes; + tCsrScanResult *pBssDesc; + uint8_t i = 0; + + /* Find out the best AP Rssi going thru the scan results */ + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (NULL != pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + fMatch = false; + + for (i = 0; pFilter && (i < pFilter->SSIDs.numOfSSIDs); i++) { + fMatch = csr_is_ssid_match(pMac, + pFilter->SSIDs.SSIDList[i].SSID.ssId, + pFilter->SSIDs.SSIDList[i].SSID.length, + pBssDesc->Result.ssId.ssId, + pBssDesc->Result.ssId.length, true); + if (!fMatch) + continue; + + pIes = (tDot11fBeaconIEs *)(pBssDesc->Result.pvIes); + /* At this time, Result.pvIes may be NULL */ + status = csr_get_parsed_bss_description_ies(pMac, + &pBssDesc->Result.BssDescriptor, &pIes); + if (!pIes && (!CDF_IS_STATUS_SUCCESS(status))) + continue; + + sms_log(pMac, LOG1, FL("SSID Matched")); + if (pFilter->bOSENAssociation) { + fMatch = true; + sms_log(pMac, LOG1, FL("Security Matched")); + if ((pBssDesc->Result.pvIes == NULL) && pIes) + cdf_mem_free(pIes); + continue; + } +#ifdef WLAN_FEATURE_11W + fMatch = csr_is_security_match(pMac, &pFilter->authType, + &pFilter->EncryptionType, + &pFilter->mcEncryptionType, + &pFilter->MFPEnabled, + &pFilter->MFPRequired, + &pFilter->MFPCapable, + &pBssDesc->Result.BssDescriptor, + pIes, NULL, NULL, NULL); +#else + fMatch = csr_is_security_match(pMac, &pFilter->authType, + &pFilter->EncryptionType, + &pFilter->mcEncryptionType, + NULL, NULL, NULL, + &pBssDesc->Result.BssDescriptor, + pIes, NULL, NULL, NULL); +#endif + if ((pBssDesc->Result.pvIes == NULL) && pIes) + cdf_mem_free(pIes); + if (fMatch) + sms_log(pMac, LOG1, FL("Security Matched")); + } /* for loop ends */ + + if (fMatch + && (pBssDesc->Result.BssDescriptor.rssi > + pMac->scan.inScanResultBestAPRssi)) { + sms_log(pMac, LOG1, + FL("Best AP Rssi changed from %d to %d"), + pMac->scan.inScanResultBestAPRssi, + pBssDesc->Result.BssDescriptor.rssi); + pMac->scan.inScanResultBestAPRssi = + pBssDesc->Result.BssDescriptor.rssi; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } +} + +static void +csr_prefer_5ghz(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter) +{ + tListElem *pEntry; + tCsrScanResult *pBssDesc; + struct roam_ext_params *roam_params = NULL; + + if (!pMac->roam.configParam.nSelect5GHzMargin && + !CSR_IS_SELECT_5G_PREFERRED(pMac)) + return; + + pMac->scan.inScanResultBestAPRssi = -128; + roam_params = &pMac->roam.configParam.roam_params; +#ifdef WLAN_DEBUG_ROAM_OFFLOAD + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("nSelect5GHzMargin")); +#endif + csr_ll_lock(&pMac->scan.scanResultList); + /* + * For 5G preference feature, there is no + * need to check the filter match and also re-program the + * RSSI bucket categories, since we use the RSSI values + * while setting the preference value for the BSS. + * There is no need to check the match for roaming since + * it is already done. + */ + if (!CSR_IS_SELECT_5G_PREFERRED(pMac)) + csr_parser_scan_result_for_5ghz_preference(pMac, pFilter); + if (-128 != pMac->scan.inScanResultBestAPRssi || + CSR_IS_SELECT_5G_PREFERRED(pMac)) { + sms_log(pMac, LOG1, FL("Best AP Rssi is %d"), + pMac->scan.inScanResultBestAPRssi); + /* Modify Rssi category based on best AP Rssi */ + if (-128 != pMac->scan.inScanResultBestAPRssi) + csr_assign_rssi_for_category(pMac, + pMac->scan.inScanResultBestAPRssi, + pMac->roam.configParam.bCatRssiOffset); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, + LL_ACCESS_NOLOCK); + while (NULL != pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + /* + * re-assign preference value based on modified + * rssi bucket (or) 5G Preference feature. + */ + pBssDesc->preferValue = csr_get_bss_prefer_value(pMac, + (int)pBssDesc->Result.BssDescriptor.rssi, + (struct cdf_mac_addr *) + &pBssDesc->Result.BssDescriptor.bssId, + pBssDesc->Result.BssDescriptor.channelId); + + sms_log(pMac, LOG2, FL("BSSID("MAC_ADDRESS_STR") Rssi(%d) Chnl(%d) PrefVal(%u) SSID=%.*s"), + MAC_ADDR_ARRAY( + pBssDesc->Result.BssDescriptor.bssId), + pBssDesc->Result.BssDescriptor.rssi, + pBssDesc->Result.BssDescriptor.channelId, + pBssDesc->preferValue, + pBssDesc->Result.ssId.length, + pBssDesc->Result.ssId.ssId); + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } + } + csr_ll_unlock(&pMac->scan.scanResultList); +} + +static CDF_STATUS +csr_save_ies(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tCsrScanResult *pBssDesc, + tDot11fBeaconIEs **pNewIes, + bool *fMatch, + eCsrEncryptionType *uc, + eCsrEncryptionType *mc, + eCsrAuthType *auth) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pIes = NULL; + + if (!pFilter) + return status; + *fMatch = csr_match_bss(pMac, &pBssDesc->Result.BssDescriptor, + pFilter, auth, uc, mc, &pIes); +#ifdef WLAN_DEBUG_ROAM_OFFLOAD + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("csr_match_bss fmatch %d"), *fMatch); +#endif + if (NULL == pIes) + return status; + /* Only save it when matching */ + if (!(*fMatch) && !pBssDesc->Result.pvIes) { + cdf_mem_free(pIes); + return status; + } + if (!pBssDesc->Result.pvIes) { + /* + * csr_match_bss allocates the memory. Simply pass it and it + * is freed later + */ + *pNewIes = pIes; + return status; + } + /* + * The pIes is allocated by someone else. make a copy + * Only to save parsed IEs if caller provides a filter. Most likely the + * caller is using to for association, hence save the parsed IEs + */ + *pNewIes = cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == *pNewIes) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, FL("fail to allocate memory for IEs")); + /* Need to free memory allocated by csr_match_bss */ + if (!pBssDesc->Result.pvIes) + cdf_mem_free(pIes); + return status; + } + cdf_mem_copy(*pNewIes, pIes, sizeof(tDot11fBeaconIEs)); + return status; +} + +static CDF_STATUS +csr_save_scan_entry(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + bool fMatch, + tCsrScanResult *pBssDesc, + tDot11fBeaconIEs *pNewIes, + tScanResultList *pRetList, + uint32_t *count, + eCsrEncryptionType uc, + eCsrEncryptionType mc, + eCsrAuthType *auth) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrScanResult *pResult; + uint32_t bssLen, allocLen; + /* To sort the list */ + tListElem *pTmpEntry; + tCsrScanResult *pTmpResult; + + if (!(NULL == pFilter || fMatch)) + return status; + + bssLen = pBssDesc->Result.BssDescriptor.length + + sizeof(pBssDesc->Result.BssDescriptor.length); + allocLen = sizeof(tCsrScanResult) + bssLen; + pResult = cdf_mem_malloc(allocLen); + if (NULL == pResult) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("fail to allocate memory for scan result, len=%d"), + allocLen); + if (pNewIes) + cdf_mem_free(pNewIes); + return status; + } + cdf_mem_set(pResult, allocLen, 0); + pResult->capValue = pBssDesc->capValue; + pResult->preferValue = pBssDesc->preferValue; + pResult->ucEncryptionType = uc; + pResult->mcEncryptionType = mc; + pResult->authType = *auth; + pResult->Result.ssId = pBssDesc->Result.ssId; + pResult->Result.timer = pBssDesc->Result.timer; + /* save the pIes for later use */ + pResult->Result.pvIes = pNewIes; + /* save bss description */ + cdf_mem_copy(&pResult->Result.BssDescriptor, + &pBssDesc->Result.BssDescriptor, + bssLen); + /* + * No need to lock pRetList because it is locally allocated and no + * outside can access it at this time + */ + if (csr_ll_is_list_empty(&pRetList->List, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + (*count)++; + return status; + } + + pTmpEntry = csr_ll_peek_head(&pRetList->List, LL_ACCESS_NOLOCK); + while (pTmpEntry) { + pTmpResult = GET_BASE_ADDR(pTmpEntry, tCsrScanResult, Link); + if (csr_is_better_bss(pMac, pResult, pTmpResult)) { + csr_ll_insert_entry(&pRetList->List, pTmpEntry, + &pResult->Link, LL_ACCESS_NOLOCK); + /* To indicate we are done */ + pResult = NULL; + break; + } + pTmpEntry = csr_ll_next(&pRetList->List, + pTmpEntry, LL_ACCESS_NOLOCK); + } + if (pResult != NULL) { + /* This one is not better than any one */ + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + } + (*count)++; + return status; +} + +/** + * csr_calc_pref_val_by_pcl() - to calculate preferred value + * @mac_ctx: mac context + * @filter: filter to find match from scan result + * @bss_descr: pointer to bss descriptor + * + * this routine calculates the new preferred value to be given to + * provided bss if its channel falls under preferred channel list. + * Thump rule is higer the RSSI better the boost. + * + * Return: success or failure + */ +static CDF_STATUS csr_calc_pref_val_by_pcl(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter *filter, + tCsrScanResult *bss_descr) +{ + int temp_rssi = 0, new_pref_val = 0; + int orig_pref_val = 0; + + if (NULL == mac_ctx || NULL == bss_descr) + return CDF_STATUS_E_FAILURE; + + if (mac_ctx->policy_manager_enabled && + is_channel_found_in_pcl(mac_ctx, + bss_descr->Result.BssDescriptor.channelId, filter) && + (bss_descr->Result.BssDescriptor.rssi > PCL_RSSI_THRESHOLD)) { + orig_pref_val = csr_derive_prefer_value_from_rssi(mac_ctx, + bss_descr->Result.BssDescriptor.rssi); + temp_rssi = bss_descr->Result.BssDescriptor.rssi + + (PCL_ADVANTAGE/(CSR_NUM_RSSI_CAT - + orig_pref_val)); + if (temp_rssi > 0) + temp_rssi = 0; + new_pref_val = csr_derive_prefer_value_from_rssi(mac_ctx, + temp_rssi); + + sms_log(mac_ctx, LOG1, + FL("%pM: rssi:%d org pref=%d temp rssi:%d new pref=%d pref=%d updated pref=%d"), + bss_descr->Result.BssDescriptor.bssId, + bss_descr->Result.BssDescriptor.rssi, + orig_pref_val, temp_rssi, new_pref_val, + bss_descr->preferValue, + CSR_MAX(new_pref_val, bss_descr->preferValue)); + + bss_descr->preferValue = + CSR_MAX(new_pref_val, bss_descr->preferValue); + } + return CDF_STATUS_SUCCESS; +} + +static CDF_STATUS +csr_parse_scan_results(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tScanResultList *pRetList, + uint32_t *count) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry; + bool fMatch = false; + tCsrScanResult *pBssDesc = NULL; + tDot11fBeaconIEs *pIes, *pNewIes = NULL; + eCsrEncryptionType uc, mc; + eCsrAuthType auth = eCSR_AUTH_TYPE_OPEN_SYSTEM; + uint32_t len = 0; + enum cds_con_mode new_mode; + + + csr_ll_lock(&pMac->scan.scanResultList); + + if (pFilter) { + if (cds_map_concurrency_mode(pMac->hHdd, + &pFilter->csrPersona, &new_mode)) { + status = cds_get_pcl(pMac->hHdd, new_mode, + &pFilter->pcl_channels.channelList[0], &len); + pFilter->pcl_channels.numChannels = (uint8_t)len; + } + } + + if (CDF_STATUS_E_FAILURE == status) + sms_log(pMac, CDF_TRACE_LEVEL_ERROR, + FL("Retrieving pcl failed from HDD")); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes); + /* + * if pBssDesc->Result.pvIes is NULL, we need to free any memory + * allocated by csr_match_bss for any error condition, + * otherwiase, it will be freed later + */ + fMatch = false; + pNewIes = NULL; + status = csr_save_ies(pMac, pFilter, pBssDesc, &pNewIes, + &fMatch, &uc, &mc, &auth); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + /* + * Modify the prefer value to honor PCL list + */ + if (pFilter && pFilter->pcl_channels.numChannels > 0) + csr_calc_pref_val_by_pcl(pMac, pFilter, pBssDesc); + status = csr_save_scan_entry(pMac, pFilter, fMatch, pBssDesc, + pNewIes, pRetList, count, uc, mc, + &auth); + if (!CDF_IS_STATUS_SUCCESS(status)) + break; + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); + return status; +} + +CDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult) +{ + CDF_STATUS status; + tScanResultList *pRetList; + uint32_t count = 0; + + if (phResult) + *phResult = CSR_INVALID_SCANRESULT_HANDLE; + + csr_prefer_5ghz(pMac, pFilter); + + pRetList = cdf_mem_malloc(sizeof(tScanResultList)); + if (NULL == pRetList) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pRetList, sizeof(tScanResultList), 0); + csr_ll_open(pMac->hHdd, &pRetList->List); + pRetList->pCurEntry = NULL; + status = csr_parse_scan_results(pMac, pFilter, pRetList, &count); + sms_log(pMac, LOG2, FL("return %d BSS"), csr_ll_count(&pRetList->List)); + if (!CDF_IS_STATUS_SUCCESS(status) || (phResult == NULL)) { + /* Fail or No one wants the result. */ + csr_scan_result_purge(pMac, (tScanResultHandle) pRetList); + } else { + if (0 == count) { + /* We are here meaning the there is no match */ + csr_ll_close(&pRetList->List); + cdf_mem_free(pRetList); + status = CDF_STATUS_E_NULL_VALUE; + } else if (phResult) { + *phResult = pRetList; + } + } + return status; +} + +/* + * NOTE: This routine is being added to make + * sure that scan results are not being flushed + * while roaming. If the scan results are flushed, + * we are unable to recover from + * csr_roam_roaming_state_disassoc_rsp_processor. + * If it is needed to remove this routine, + * first ensure that we recover gracefully from + * csr_roam_roaming_state_disassoc_rsp_processor if + * csr_scan_get_result returns with a failure because + * of not being able to find the roaming BSS. + */ +bool csr_scan_flush_denied(tpAniSirGlobal pMac) +{ + uint8_t sessionId; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) + return 1; + } + } + return 0; +} + +CDF_STATUS csr_scan_flush_result(tpAniSirGlobal pMac) +{ + bool isFlushDenied = csr_scan_flush_denied(pMac); + + if (isFlushDenied) { + sms_log(pMac, LOGW, "%s: scan flush denied in roam state %d", + __func__, isFlushDenied); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG4, "%s: Flushing all scan results", __func__); + csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults); + csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList); + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal pMac, bool flushP2P) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry, *pFreeElem; + tCsrScanResult *pBssDesc; + tDblLinkList *pList = &pMac->scan.scanResultList; + + csr_ll_lock(pList); + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (flushP2P == cdf_mem_compare(pBssDesc->Result.ssId.ssId, + "DIRECT-", 7)) { + pFreeElem = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(pMac, pBssDesc); + continue; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(pList); + + return status; +} + +void csr_scan_flush_bss_entry(tpAniSirGlobal pMac, + tpSmeCsaOffloadInd pCsaOffloadInd) +{ + tListElem *pEntry, *pFreeElem; + tCsrScanResult *pBssDesc; + tDblLinkList *pList = &pMac->scan.scanResultList; + + csr_ll_lock(pList); + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (cdf_mem_compare(pBssDesc->Result.BssDescriptor.bssId, + pCsaOffloadInd->bssId, sizeof(tSirMacAddr))) { + pFreeElem = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(pMac, pBssDesc); + sms_log(pMac, LOG1, FL("Removed BSS entry:%pM"), + pCsaOffloadInd->bssId); + continue; + } + + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(pList); +} + +/** + * csr_check11d_channel + * + ***FUNCTION: + * This function is called from csr_scan_filter_results function and + * compare channel number with given channel list. + * + ***LOGIC: + * Check Scan result channel number with CFG channel list + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param channelId channel number + * @param pChannelList Pointer to channel list + * @param numChannels Number of channel in channel list + * + * @return Status + */ + +CDF_STATUS csr_check11d_channel(uint8_t channelId, uint8_t *pChannelList, + uint32_t numChannels) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint8_t i = 0; + + for (i = 0; i < numChannels; i++) { + if (pChannelList[i] == channelId) { + status = CDF_STATUS_SUCCESS; + break; + } + } + return status; +} + +/** + * csr_scan_filter_results + * + ***FUNCTION: + * This function is called from csr_apply_country_information function and + * filter scan result based on valid channel list number. + * + ***LOGIC: + * Get scan result from scan list and Check Scan result channel number + * with 11d channel list if channel number is found in 11d channel list + * then do not remove scan result entry from scan list + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * + * @return Status + */ + +CDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry, *pTempEntry; + tCsrScanResult *pBssDesc; + uint32_t len = sizeof(pMac->roam.validChannelList); + + /* Get valid channels list from CFG */ + if (!CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels(pMac, + pMac->roam. + validChannelList, + &len))) { + sms_log(pMac, LOGE, "Failed to get Channel list from CFG"); + } + + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pTempEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId, + pMac->roam.validChannelList, len)) { + /* Remove Scan result which does not have 11d channel */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK)) { + csr_free_scan_result_entry(pMac, pBssDesc); + } + } else { + sms_log(pMac, LOG1, FL("%d is a Valid channel"), + pBssDesc->Result.BssDescriptor.channelId); + } + pEntry = pTempEntry; + } + + csr_ll_unlock(&pMac->scan.scanResultList); + csr_ll_lock(&pMac->scan.tempScanResults); + + pEntry = csr_ll_peek_head(&pMac->scan.tempScanResults, + LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pTempEntry = csr_ll_next(&pMac->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK); + if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId, + pMac->roam.validChannelList, len)) { + /* Remove Scan result which does not have 11d channel */ + if (csr_ll_remove_entry + (&pMac->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK)) { + csr_free_scan_result_entry(pMac, pBssDesc); + } + } else { + sms_log(pMac, LOG1, FL("%d is a Valid channel"), + pBssDesc->Result.BssDescriptor.channelId); + } + pEntry = pTempEntry; + } + + csr_ll_unlock(&pMac->scan.tempScanResults); + return status; +} + +CDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn, + tScanResultHandle *phResult) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tScanResultList *pRetList, *pInList = (tScanResultList *) hIn; + tCsrScanResult *pResult, *pScanResult; + uint32_t count = 0; + tListElem *pEntry; + uint32_t bssLen, allocLen; + + if (phResult) { + *phResult = CSR_INVALID_SCANRESULT_HANDLE; + } + pRetList = cdf_mem_malloc(sizeof(tScanResultList)); + if (NULL == pRetList) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set(pRetList, sizeof(tScanResultList), 0); + csr_ll_open(pMac->hHdd, &pRetList->List); + pRetList->pCurEntry = NULL; + csr_ll_lock(&pMac->scan.scanResultList); + csr_ll_lock(&pInList->List); + + pEntry = csr_ll_peek_head(&pInList->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pScanResult = + GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + bssLen = + pScanResult->Result.BssDescriptor.length + + sizeof(pScanResult->Result.BssDescriptor.length); + allocLen = sizeof(tCsrScanResult) + bssLen; + pResult = cdf_mem_malloc(allocLen); + if (NULL == pResult) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, + (tScanResultHandle *) + pRetList); + count = 0; + break; + } + cdf_mem_set(pResult, allocLen, 0); + cdf_mem_copy(&pResult->Result.BssDescriptor, + &pScanResult->Result.BssDescriptor, + bssLen); + if (pScanResult->Result.pvIes) { + pResult->Result.pvIes = + cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pResult->Result.pvIes) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (!CDF_IS_STATUS_SUCCESS(status)) { + /* Free the memory we allocate above first */ + cdf_mem_free(pResult); + csr_scan_result_purge(pMac, + (tScanResultHandle *) + pRetList); + count = 0; + break; + } + cdf_mem_copy(pResult->Result.pvIes, + pScanResult->Result.pvIes, + sizeof(tDot11fBeaconIEs)); + } + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_LOCK); + count++; + pEntry = + csr_ll_next(&pInList->List, pEntry, LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pInList->List); + csr_ll_unlock(&pMac->scan.scanResultList); + + if (CDF_IS_STATUS_SUCCESS(status)) { + if (0 == count) { + csr_ll_close(&pRetList->List); + cdf_mem_free(pRetList); + status = CDF_STATUS_E_NULL_VALUE; + } else if (phResult) { + *phResult = pRetList; + } + } + } /* Allocated pRetList */ + + return status; +} + +CDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirMbMsg *pMsg = (tSirMbMsg *) pMsgBuf; + tCsrRoamSession *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + tCsrRoamInfo roamInfo; + tCsrRoamInfo *pRoamInfo = NULL; + uint32_t sessionId; + + if (eWNI_SME_SCAN_RSP == pMsg->type) + return csr_scan_sme_scan_response(pMac, pMsgBuf); + + if (pMsg->type != eWNI_SME_UPPER_LAYER_ASSOC_CNF) { + if (csr_is_any_session_in_connect_state(pMac)) { + /* + * In case of we are connected, we need to check whether + * connect status changes because scan may also run + * while connected. + */ + csr_roam_check_for_link_status_change(pMac, + (tSirSmeRsp *) pMsgBuf); + } else { + sms_log(pMac, LOGW, + FL("Message [0x%04x] received in wrong state"), + pMsg->type); + } + return status; + } + + sms_log(pMac, LOG1, + FL("Scanning: ASSOC cnf can be given to upper layer")); + cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + pUpperLayerAssocCnf = (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf; + status = csr_roam_get_session_id_from_bssid(pMac, + (struct cdf_mac_addr *)pUpperLayerAssocCnf->bssId, &sessionId); + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + + /* send the status code as Success */ + pRoamInfo->statusCode = eSIR_SME_SUCCESS; + pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; + pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid; + pRoamInfo->rsnIELen = (uint8_t) pUpperLayerAssocCnf->rsnIE.length; + pRoamInfo->prsnIE = pUpperLayerAssocCnf->rsnIE.rsnIEdata; + pRoamInfo->addIELen = (uint8_t) pUpperLayerAssocCnf->addIE.length; + pRoamInfo->paddIE = pUpperLayerAssocCnf->addIE.addIEdata; + cdf_mem_copy(pRoamInfo->peerMac.bytes, + pUpperLayerAssocCnf->peerMacAddr, + CDF_MAC_ADDR_SIZE); + cdf_mem_copy(&pRoamInfo->bssid.bytes, pUpperLayerAssocCnf->bssId, + CDF_MAC_ADDR_SIZE); + pRoamInfo->wmmEnabledSta = pUpperLayerAssocCnf->wmmEnabledSta; + if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + pRoamInfo->fReassocReq = pUpperLayerAssocCnf->reassocReq; + status = csr_roam_call_callback(pMac, sessionId, + pRoamInfo, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + if (CSR_IS_WDS_AP(pRoamInfo->u.pConnectedProfile)) { + cdf_sleep(100); + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED; + status = csr_roam_call_callback(pMac, sessionId, pRoamInfo, 0, + eCSR_ROAM_WDS_IND, + eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND); + } + return status; +} + +void csr_check_n_save_wsc_ie(tpAniSirGlobal pMac, tSirBssDescription *pNewBssDescr, + tSirBssDescription *pOldBssDescr) +{ + int idx, len; + uint8_t *pbIe; + + /* If failed to remove, assuming someone else got it. */ + if ((pNewBssDescr->fProbeRsp != pOldBssDescr->fProbeRsp) && + (0 == pNewBssDescr->WscIeLen)) { + idx = 0; + len = pOldBssDescr->length - sizeof(tSirBssDescription) + + sizeof(uint16_t) + sizeof(uint32_t) - + DOT11F_IE_WSCPROBERES_MIN_LEN - 2; + pbIe = (uint8_t *) pOldBssDescr->ieFields; + /* Save WPS IE if it exists */ + pNewBssDescr->WscIeLen = 0; + while (idx < len) { + if ((DOT11F_EID_WSCPROBERES == pbIe[0]) && + (0x00 == pbIe[2]) && (0x50 == pbIe[3]) + && (0xf2 == pbIe[4]) && (0x04 == pbIe[5])) { + /* Founrd it */ + if ((DOT11F_IE_WSCPROBERES_MAX_LEN - 2) >= + pbIe[1]) { + cdf_mem_copy(pNewBssDescr-> + WscIeProbeRsp, pbIe, + pbIe[1] + 2); + pNewBssDescr->WscIeLen = pbIe[1] + 2; + } + break; + } + idx += pbIe[1] + 2; + pbIe += pbIe[1] + 2; + } + } +} + +/* pIes may be NULL */ +bool csr_remove_dup_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *bss_dscp, + tDot11fBeaconIEs *pIes, tAniSSID *pSsid, + v_TIME_t *timer, bool fForced) +{ + tListElem *pEntry; + tCsrScanResult *scan_entry; + bool fRC = false; + int8_t scan_entry_rssi = 0; + + /* + * Walk through all the chained BssDescriptions. If we find a chained + * BssDescription that matches the BssID of the BssDescription passed + * in, then these must be duplicate scan results for this Bss. In that + * case, remove the 'old' Bss description from the linked list. + */ + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + + while (pEntry) { + scan_entry = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + /* + * we have a duplicate scan results only when BSSID, SSID, + * Channel and NetworkType matches + */ + if (csr_is_duplicate_bss_description(pMac, + &scan_entry->Result.BssDescriptor, + bss_dscp, pIes, fForced)) { + /* + * Following is mathematically a = (aX + b(100-X))/100 + * where: + * a = bss_dscp->rssi, b = scan_entry_rssi + * and X = CSR_SCAN_RESULT_RSSI_WEIGHT + */ + scan_entry_rssi = scan_entry->Result.BssDescriptor.rssi; + bss_dscp->rssi = (int8_t) ((((int32_t) bss_dscp->rssi * + CSR_SCAN_RESULT_RSSI_WEIGHT) + + ((int32_t) scan_entry_rssi * + (100 - CSR_SCAN_RESULT_RSSI_WEIGHT))) / 100); + /* Remove the old entry from the list */ + if (csr_ll_remove_entry + (&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK)) { + /* + * we need to free the memory associated with + * this node. If failed to remove, assuming + * someone else got it. + */ + *pSsid = scan_entry->Result.ssId; + *timer = scan_entry->Result.timer; + csr_check_n_save_wsc_ie(pMac, bss_dscp, + &scan_entry->Result. + BssDescriptor); + csr_free_scan_result_entry(pMac, scan_entry); + } else { + sms_log(pMac, LOGW, FL("fail to remove entry")); + } + fRC = true; + /* + * If we found a match, we can stop looking through + * the list. + */ + break; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(&pMac->scan.scanResultList); + return fRC; +} + +CDF_STATUS csr_add_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tPmkidCandidateInfo *pmkid_info = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("NumPmkidCandidate = %d"), + pSession->NumPmkidCandidate); + if (!pIes) + return status; + /* check if this is a RSN BSS */ + if (!pIes->RSN.present) + return status; + + if (pSession->NumPmkidCandidate >= CSR_MAX_PMKID_ALLOWED) + return CDF_STATUS_E_FAILURE; + + /* BSS is capable of doing pre-authentication */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + cdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type), + 0); + secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND; + secEvent.encryptionModeMulticast = (uint8_t)diag_enc_type_from_csr_type( + pSession->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = (uint8_t)diag_enc_type_from_csr_type( + pSession->connectedProfile.EncryptionType); + cdf_mem_copy(secEvent.bssid, pSession->connectedProfile.bssid.bytes, + CDF_MAC_ADDR_SIZE); + secEvent.authMode = (uint8_t)diag_auth_type_from_csr_type( + pSession->connectedProfile.AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + pmkid_info = &pSession->PmkidCandidateInfo[pSession->NumPmkidCandidate]; + /* if yes, then add to PMKIDCandidateList */ + cdf_mem_copy(pmkid_info->BSSID.bytes, pBssDesc->bssId, + CDF_MAC_ADDR_SIZE); + /* Bit 0 offirst byte - PreAuthentication Capability */ + if ((pIes->RSN.RSN_Cap[0] >> 0) & 0x1) + pmkid_info->preAuthSupported = true; + else + pmkid_info->preAuthSupported = false; + pSession->NumPmkidCandidate++; + return status; +} + +/* + * This function checks whether new AP is found for the current connected + * profile. If it is found, it return the sessionId, else it return invalid + * sessionID + */ +CDF_STATUS csr_process_bss_desc_for_pmkid_list(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + uint8_t sessionId) +{ + tCsrRoamSession *pSession; + tDot11fBeaconIEs *pIesLocal = pIes; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (!(pIesLocal || + CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIesLocal)))) + return status; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + if (!pIes) + cdf_mem_free(pIesLocal); + return status; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (csr_is_conn_state_connected_infra(pMac, sessionId) + && (eCSR_AUTH_TYPE_RSN == pSession->connectedProfile.AuthType) + && csr_match_bss_to_connect_profile(pMac, + &pSession->connectedProfile, + pBssDesc, pIesLocal)) { + /* This new BSS fits the current profile connected */ + status = csr_add_pmkid_candidate_list(pMac, sessionId, + pBssDesc, pIesLocal); + if (!CDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("csr_add_pmkid_candidate_list failed")); + else + status = CDF_STATUS_SUCCESS; + } + + if (!pIes) + cdf_mem_free(pIesLocal); + + return status; +} + +#ifdef FEATURE_WLAN_WAPI +CDF_STATUS csr_add_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, + "csr_add_bkid_candidate_list called pMac->scan.NumBkidCandidate = %d", + pSession->NumBkidCandidate); + if (pIes) { + /* check if this is a WAPI BSS */ + if (pIes->WAPI.present) { + /* Check if the BSS is capable of doing pre-authentication */ + if (pSession->NumBkidCandidate < CSR_MAX_BKID_ALLOWED) { + + /* if yes, then add to BKIDCandidateList */ + cdf_mem_copy(pSession-> + BkidCandidateInfo[pSession-> + NumBkidCandidate]. + BSSID.bytes, pBssDesc->bssId, + CDF_MAC_ADDR_SIZE); + if (pIes->WAPI.preauth) { + pSession->BkidCandidateInfo[pSession-> + NumBkidCandidate]. + preAuthSupported = true; + } else { + pSession->BkidCandidateInfo[pSession-> + NumBkidCandidate]. + preAuthSupported = false; + } + pSession->NumBkidCandidate++; + } else { + status = CDF_STATUS_E_FAILURE; + } + } + } + + return status; +} + +/* + * This function checks whether new AP is found for the current connected + * profile, if so add to BKIDCandidateList + */ +bool csr_process_bss_desc_for_bkid_list(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + bool fRC = false; + tDot11fBeaconIEs *pIesLocal = pIes; + uint32_t sessionId; + tCsrRoamSession *pSession; + CDF_STATUS status; + + if (!(pIesLocal || + CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIesLocal)))) + return fRC; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + continue; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (csr_is_conn_state_connected_infra(pMac, sessionId) + && (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == + pSession->connectedProfile.AuthType) + && csr_match_bss_to_connect_profile(pMac, + &pSession->connectedProfile, + pBssDesc, pIesLocal)) { + /* this new BSS fits the current profile connected */ + status = csr_add_bkid_candidate_list(pMac, sessionId, + pBssDesc, pIesLocal); + if (CDF_IS_STATUS_SUCCESS(status)) + fRC = true; + } + } + if (!pIes) + cdf_mem_free(pIesLocal); + return fRC; +} + +#endif + +static void +csr_remove_from_tmp_list(tpAniSirGlobal mac_ctx, + uint8_t reason, + uint8_t session_id) +{ + CDF_STATUS status; + tListElem *entry; + tCsrScanResult *bss_dscp; + tDot11fBeaconIEs *local_ie = NULL; + bool dup_bss; + tAniSSID tmpSsid; + v_TIME_t timer = 0; + + tmpSsid.length = 0; + while ((entry = csr_ll_remove_tail(&mac_ctx->scan.tempScanResults, + LL_ACCESS_LOCK)) != NULL) { + bss_dscp = GET_BASE_ADDR(entry, tCsrScanResult, Link); + sms_log(mac_ctx, LOG2, + FL("...Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = -%d"), + MAC_ADDR_ARRAY(bss_dscp->Result.BssDescriptor. + bssId), + bss_dscp->Result.BssDescriptor.channelId, + bss_dscp->Result.BssDescriptor.rssi * (-1)); + + /* At this time, bss_dscp->Result.pvIes may be NULL */ + local_ie = (tDot11fBeaconIEs *)(bss_dscp->Result.pvIes); + status = csr_get_parsed_bss_description_ies(mac_ctx, + &bss_dscp->Result.BssDescriptor, &local_ie); + if (!(local_ie || CDF_IS_STATUS_SUCCESS(status))) { + sms_log(mac_ctx, LOGE, FL("Cannot pared IEs")); + csr_free_scan_result_entry(mac_ctx, bss_dscp); + continue; + } + dup_bss = csr_remove_dup_bss_description(mac_ctx, + &bss_dscp->Result.BssDescriptor, + local_ie, &tmpSsid, &timer, false); + /* + * Check whether we have reach out limit, but don't lose the + * LFR candidates came from FW + */ + if (CSR_SCAN_IS_OVER_BSS_LIMIT(mac_ctx)) { + sms_log(mac_ctx, LOGW, FL("BSS limit reached")); + if ((bss_dscp->Result.pvIes == NULL) && local_ie) + cdf_mem_free(local_ie); + csr_free_scan_result_entry(mac_ctx, bss_dscp); + /* Continue because there may be duplicated BSS */ + continue; + } + /* check for duplicate scan results */ + if (!dup_bss) { + status = csr_process_bss_desc_for_pmkid_list(mac_ctx, + &bss_dscp->Result.BssDescriptor, + local_ie, session_id); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Found a new BSS */ + csr_roam_call_callback(mac_ctx, session_id, + NULL, 0, eCSR_ROAM_SCAN_FOUND_NEW_BSS, + eCSR_ROAM_RESULT_NONE); + } + } else { + /* + * Check if the new one has SSID it it, if not, use + * the older SSID if it exists. + * + * New BSS has a hidden SSID and old one has the SSID. + * Keep the SSID only if diff of saved SSID time and + * current time is less than 1 min to avoid side effect + * of saving SSID with old one is that if AP changes + * its SSID while remain hidden, we may never see it + * and also to address the requirement of When we remove + * hidden ssid from the profile i.e., forget the SSID + * via GUI that SSID shouldn't see in the profile + */ + v_TIME_t time_gap = cdf_mc_timer_get_system_time() - + timer; + if ((0 == bss_dscp->Result.ssId.length) + && (time_gap <= HIDDEN_TIMER) + && tmpSsid.length) { + bss_dscp->Result.timer = timer; + bss_dscp->Result.ssId = tmpSsid; + } + } + + if (csr_is11d_supported(mac_ctx) + && local_ie->Country.present) { + csr_add_vote_for_country_info(mac_ctx, + local_ie->Country.country); + sms_log(mac_ctx, LOGW, + FL("11d AP Bssid "MAC_ADDRESS_STR + " chan= %d, rssi = -%d, countryCode %c%c"), + MAC_ADDR_ARRAY( + bss_dscp->Result.BssDescriptor.bssId), + bss_dscp->Result.BssDescriptor.channelId, + bss_dscp->Result.BssDescriptor.rssi * (-1), + local_ie->Country.country[0], + local_ie->Country.country[1]); + } + /* append to main list */ + csr_scan_add_result(mac_ctx, bss_dscp, local_ie, session_id); + if ((bss_dscp->Result.pvIes == NULL) && local_ie) + cdf_mem_free(local_ie); + } /* end of loop */ +} + +static void csr_move_temp_scan_results_to_main_list(tpAniSirGlobal pMac, + uint8_t reason, + uint8_t sessionId) +{ + tCsrRoamSession *pSession; + uint32_t i; + + /* remove the BSS descriptions from temporary list */ + csr_remove_from_tmp_list(pMac, reason, sessionId); + /* + * We don't need to update CC while connected to an AP which is + * advertising CC already + */ + if (!csr_is11d_supported(pMac)) + return; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + pSession = CSR_GET_SESSION(pMac, i); + if (csr_is_conn_state_connected(pMac, i)) { + sms_log(pMac, LOGW, + FL("No need to update CC in connected state")); + return; + } + } + csr_elected_country_info(pMac); + csr_learn_11dcountry_information(pMac, NULL, NULL, true); +} + +static tCsrScanResult *csr_scan_save_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pBSSDescription, + tDot11fBeaconIEs *pIes, + uint8_t sessionId) +{ + tCsrScanResult *pCsrBssDescription = NULL; + uint32_t cbBSSDesc; + uint32_t cbAllocated; + + /* figure out how big the BSS description is (the BSSDesc->length does NOT */ + /* include the size of the length field itself). */ + cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length); + + cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc; + + pCsrBssDescription = cdf_mem_malloc(cbAllocated); + if (NULL != pCsrBssDescription) { + cdf_mem_set(pCsrBssDescription, cbAllocated, 0); + pCsrBssDescription->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOGW, + FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "), + pCsrBssDescription->AgingCount, + MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor. + bssId)); + cdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor, + pBSSDescription, cbBSSDesc); +#if defined(CDF_ENSBALED) + if (NULL != pCsrBssDescription->Result.pvIes) { + CDF_ASSERT(pCsrBssDescription->Result.pvIes == NULL); + return NULL; + } +#endif + csr_scan_add_result(pMac, pCsrBssDescription, pIes, sessionId); + } + + return pCsrBssDescription; +} + +/* Append a Bss Description... */ +tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pSirBssDescription, + tDot11fBeaconIEs *pIes, + bool fForced, uint8_t sessionId) +{ + tCsrScanResult *pCsrBssDescription = NULL; + tAniSSID tmpSsid; + v_TIME_t timer = 0; + int result; + + tmpSsid.length = 0; + result = csr_remove_dup_bss_description(pMac, pSirBssDescription, + pIes, &tmpSsid, &timer, + fForced); + pCsrBssDescription = csr_scan_save_bss_description(pMac, + pSirBssDescription, pIes, sessionId); + if (result && (pCsrBssDescription != NULL)) { + /* + * Check if the new one has SSID it it, if not, use the older + * SSID if it exists. + */ + if ((0 == pCsrBssDescription->Result.ssId.length) + && tmpSsid.length) { + /* + * New BSS has a hidden SSID and old one has the SSID. + * Keep the SSID only if diff of saved SSID time and + * current time is less than 1 min to avoid side effect + * of saving SSID with old one is that if AP changes its + * SSID while remain hidden, we may never see it and + * also to address the requirement of. When we remove + * hidden ssid from the profile i.e., forget the SSID + * via GUI that SSID shouldn't see in the profile + */ + if ((cdf_mc_timer_get_system_time() - timer) <= + HIDDEN_TIMER) { + pCsrBssDescription->Result.ssId = tmpSsid; + pCsrBssDescription->Result.timer = timer; + } + } + } + + return pCsrBssDescription; +} + +void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList) +{ + tCsrChannelPowerInfo *pChannelSet; + tListElem *pEntry; + + csr_ll_lock(pChannelList); + /* + * Remove the channel sets from the learned list and put them + * in the free list + */ + while ((pEntry = csr_ll_remove_head(pChannelList, + LL_ACCESS_NOLOCK)) != NULL) { + pChannelSet = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link); + if (pChannelSet) + cdf_mem_free(pChannelSet); + } + csr_ll_unlock(pChannelList); + return; +} + +/* + * Save the channelList into the ultimate storage as the final stage of channel + * Input: pCountryInfo -- the country code (e.g. "USI"), channel list, and power + * limit are all stored inside this data structure + */ +CDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, + uint32_t tableSize, + tSirMacChanInfo *channelTable) +{ + uint32_t i = tableSize / sizeof(tSirMacChanInfo); + tSirMacChanInfo *pChannelInfo; + tCsrChannelPowerInfo *pChannelSet; + bool f2GHzInfoFound = false; + bool f2GListPurged = false, f5GListPurged = false; + + pChannelInfo = channelTable; + /* atleast 3 bytes have to be remaining -- from "countryString" */ + while (i--) { + pChannelSet = cdf_mem_malloc(sizeof(tCsrChannelPowerInfo)); + if (NULL == pChannelSet) { + pChannelInfo++; + continue; + } + cdf_mem_set(pChannelSet, sizeof(tCsrChannelPowerInfo), 0); + pChannelSet->firstChannel = pChannelInfo->firstChanNum; + pChannelSet->numChannels = pChannelInfo->numChannels; + /* + * Now set the inter-channel offset based on the frequency band + * the channel set lies in + */ + if ((CDS_IS_CHANNEL_24GHZ(pChannelSet->firstChannel)) && + ((pChannelSet->firstChannel + + (pChannelSet->numChannels - 1)) <= + CDS_MAX_24GHz_CHANNEL_NUMBER)) { + pChannelSet->interChannelOffset = 1; + f2GHzInfoFound = true; + } else if ((CDS_IS_CHANNEL_5GHZ(pChannelSet->firstChannel)) + && ((pChannelSet->firstChannel + + ((pChannelSet->numChannels - 1) * 4)) <= + CDS_MAX_5GHz_CHANNEL_NUMBER)) { + pChannelSet->interChannelOffset = 4; + f2GHzInfoFound = false; + } else { + sms_log(pMac, LOGW, + FL("Invalid Channel %d Present in Country IE"), + pChannelSet->firstChannel); + cdf_mem_free(pChannelSet); + return CDF_STATUS_E_FAILURE; + } + pChannelSet->txPower = CDF_MIN(pChannelInfo->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + if (f2GHzInfoFound) { + if (!f2GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList24); + f2GListPurged = true; + } + if (CSR_IS_OPERATING_BG_BAND(pMac)) { + /* add to the list of 2.4 GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList24, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sms_log(pMac, LOGW, + FL("Adding 11B/G ch in 11A. 1st ch %d"), + pChannelSet->firstChannel); + cdf_mem_free(pChannelSet); + } + } else { + /* 5GHz info found */ + if (!f5GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList5G); + f5GListPurged = true; + } + if (CSR_IS_OPERATING_A_BAND(pMac)) { + /* add to the list of 5GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList5G, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sms_log(pMac, LOGW, + FL("Adding 11A ch in B/G. 1st ch %d"), + pChannelSet->firstChannel); + cdf_mem_free(pChannelSet); + } + } + pChannelInfo++; /* move to next entry */ + } + return CDF_STATUS_SUCCESS; +} + +static void csr_clear_dfs_channel_list(tpAniSirGlobal pMac) +{ + tSirMbMsg *pMsg; + uint16_t msgLen; + + msgLen = (uint16_t) (sizeof(tSirMbMsg)); + pMsg = cdf_mem_malloc(msgLen); + if (NULL != pMsg) { + cdf_mem_set((void *)pMsg, msgLen, 0); + pMsg->type = eWNI_SME_CLEAR_DFS_CHANNEL_LIST; + pMsg->msgLen = msgLen; + cds_send_mb_message_to_mac(pMsg); + } +} + +void csr_apply_power2_current(tpAniSirGlobal pMac) +{ + sms_log(pMac, LOG3, FL(" Updating Cfg with power settings")); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList24, + WNI_CFG_MAX_TX_POWER_2_4); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList5G, + WNI_CFG_MAX_TX_POWER_5); +} + +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal mac_ctx, + tCsrChannel *ch_lst, + uint8_t *countryCode) +{ + int i; + uint8_t num_ch = 0; + uint8_t tempNumChannels = 0; + tCsrChannel tmp_ch_lst; + + if (ch_lst->numChannels) { + tempNumChannels = CSR_MIN(ch_lst->numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + for (i = 0; i < tempNumChannels; i++) { + tmp_ch_lst.channelList[num_ch] = ch_lst->channelList[i]; + num_ch++; + } + tmp_ch_lst.numChannels = num_ch; + /* Store the channel+power info in the global place: Cfg */ + csr_apply_power2_current(mac_ctx); + csr_set_cfg_valid_channel_list(mac_ctx, tmp_ch_lst.channelList, + tmp_ch_lst.numChannels); + /* + * extend scan capability, build a scan list based on the + * channel list : channel# + active/passive scan + */ + csr_set_cfg_scan_control_list(mac_ctx, countryCode, + &tmp_ch_lst); + /* Send msg to Lim to clear DFS channel list */ + csr_clear_dfs_channel_list(mac_ctx); + } else { + sms_log(mac_ctx, LOGE, FL("11D channel list is empty")); + } + csr_set_cfg_country_code(mac_ctx, countryCode); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_reset_country_information(tpAniSirGlobal pMac) +{ + + host_log_802_11d_pkt_type *p11dLog; + int Index; + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_RESET; + cdf_mem_copy(p11dLog->countryCode, pMac->scan.countryCodeCurrent, 3); + p11dLog->numChannel = pMac->scan.base_channels.numChannels; + if (p11dLog->numChannel <= HOST_LOG_MAX_NUM_CHANNEL) { + cdf_mem_copy(p11dLog->Channels, + pMac->scan.base_channels.channelList, + p11dLog->numChannel); + for (Index = 0; + Index < pMac->scan.base_channels.numChannels; + Index++) { + p11dLog->TxPwr[Index] = CDF_MIN( + pMac->scan.defaultPowerTable[Index].pwr, + pMac->roam.configParam.nTxPowerCap); + } + } + if (!pMac->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_channel_power_info_wrapper() - sends channel info to fw + * @pMac: main MAC data structure + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac) +{ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_reset_country_information(pMac); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + /* apply the channel list, power settings, and the country code. */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, pMac->scan.countryCodeCurrent); + /* clear the 11d channel list */ + cdf_mem_set(&pMac->scan.channels11d, sizeof(pMac->scan.channels11d), 0); +} + +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac) +{ + pMac->scan.countryCodeCount = 0; + cdf_mem_set(pMac->scan.votes11d, + sizeof(tCsrVotes11d) * CSR_MAX_NUM_COUNTRY_CODE, 0); +} + +void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode) +{ + bool match = false; + uint8_t i; + + /* convert to UPPER here so we are assured + * the strings are always in upper case. + */ + for (i = 0; i < 3; i++) { + pCountryCode[i] = (uint8_t) csr_to_upper(pCountryCode[i]); + } + + /* Some of the 'old' Cisco 350 series AP's advertise NA as the + * country code (for North America ??). NA is not a valid country code + * or domain so let's allow this by changing it to the proper + * country code (which is US). We've also seen some NETGEAR AP's + * that have "XX " as the country code with valid 2.4 GHz US channel + * information. If we cannot find the country code advertised in the + * 11d information element, let's default to US. + */ + + if (!CDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country(pMac, + pCountryCode, NULL, + COUNTRY_QUERY))) { + pCountryCode[0] = '0'; + pCountryCode[1] = '0'; + } + + /* We've seen some of the AP's improperly put a 0 for the + * third character of the country code. spec says valid charcters are + * 'O' (for outdoor), 'I' for Indoor, or ' ' (space; for either). + * if we see a 0 in this third character, let's change it to a ' '. + */ + if (0 == pCountryCode[2]) { + pCountryCode[2] = ' '; + } + + for (i = 0; i < pMac->scan.countryCodeCount; i++) { + match = (cdf_mem_compare(pMac->scan.votes11d[i].countryCode, + pCountryCode, 2)); + if (match) { + break; + } + } + + if (match) { + pMac->scan.votes11d[i].votes++; + } else { + cdf_mem_copy(pMac->scan.votes11d[pMac->scan.countryCodeCount]. + countryCode, pCountryCode, 3); + pMac->scan.votes11d[pMac->scan.countryCodeCount].votes = 1; + pMac->scan.countryCodeCount++; + } + + return; +} + +bool csr_elected_country_info(tpAniSirGlobal pMac) +{ + bool fRet = false; + uint8_t maxVotes = 0; + uint8_t i, j = 0; + + if (!pMac->scan.countryCodeCount) { + return fRet; + } + maxVotes = pMac->scan.votes11d[0].votes; + fRet = true; + + for (i = 1; i < pMac->scan.countryCodeCount; i++) { + /* If we have a tie for max votes for 2 different country codes, + * pick random.we can put some more intelligence - TBD + */ + if (maxVotes < pMac->scan.votes11d[i].votes) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + " Votes for Country %c%c : %d\n", + pMac->scan.votes11d[i].countryCode[0], + pMac->scan.votes11d[i].countryCode[1], + pMac->scan.votes11d[i].votes); + + maxVotes = pMac->scan.votes11d[i].votes; + j = i; + fRet = true; + } + + } + if (fRet) { + cdf_mem_copy(pMac->scan.countryCodeElected, + pMac->scan.votes11d[j].countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + cdf_mem_copy(pMac->scan.countryCode11d, + pMac->scan.votes11d[j].countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Selected Country is %c%c With count %d\n", + pMac->scan.votes11d[j].countryCode[0], + pMac->scan.votes11d[j].countryCode[1], + pMac->scan.votes11d[j].votes); + } + return fRet; +} + +/** + * csr_set_country_code() - Set country code + * @pMac: main MAC data structure + * @pCountry: ptr to Country Code + * + * This function sends the channel power info to firmware + * + * Return: none + */ +CDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + v_REGDOMAIN_t domainId; + + if (pCountry) { + + status = csr_get_regulatory_domain_for_country(pMac, pCountry, + &domainId, + COUNTRY_USER); + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_copy(pMac->scan.countryCodeCurrent, + pCountry, + WNI_CFG_COUNTRY_CODE_LEN); + csr_set_cfg_country_code(pMac, pCountry); + } + } + return status; +} + +/* caller allocated memory for pNumChn and pChnPowerInfo */ +/* As input, *pNumChn has the size of the array of pChnPowerInfo */ +/* Upon return, *pNumChn has the number of channels assigned. */ +void csr_get_channel_power_info(tpAniSirGlobal pMac, tDblLinkList *list, + uint32_t *num_ch, + tChannelListWithPower *chn_pwr_info) +{ + tListElem *entry; + uint32_t chn_idx = 0, idx; + tCsrChannelPowerInfo *ch_set; + + /* Get 2.4Ghz first */ + entry = csr_ll_peek_head(list, LL_ACCESS_LOCK); + while (entry && (chn_idx < *num_ch)) { + ch_set = GET_BASE_ADDR(entry, tCsrChannelPowerInfo, link); + for (idx = 0; (idx < ch_set->numChannels) + && (chn_idx < *num_ch); idx++) { + chn_pwr_info[chn_idx].chanId = + (uint8_t) (ch_set->firstChannel + + (idx * ch_set->interChannelOffset)); + chn_pwr_info[chn_idx++].pwr = ch_set->txPower; + } + entry = csr_ll_next(list, entry, LL_ACCESS_LOCK); + } + *num_ch = chn_idx; + + return; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +void csr_diag_apply_country_info(tpAniSirGlobal mac_ctx) +{ + host_log_802_11d_pkt_type *p11dLog; + tChannelListWithPower chnPwrInfo[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN, nTmp; + + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_COUNTRY_SET; + cdf_mem_copy(p11dLog->countryCode, mac_ctx->scan.countryCode11d, 3); + p11dLog->numChannel = mac_ctx->scan.channels11d.numChannels; + if (p11dLog->numChannel > HOST_LOG_MAX_NUM_CHANNEL) + goto diag_end; + + cdf_mem_copy(p11dLog->Channels, + mac_ctx->scan.channels11d.channelList, + p11dLog->numChannel); + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList24, + &nChnInfo, chnPwrInfo); + nTmp = nChnInfo; + nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN - nTmp; + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList5G, + &nChnInfo, &chnPwrInfo[nTmp]); + for (nTmp = 0; nTmp < p11dLog->numChannel; nTmp++) { + for (nChnInfo = 0; + nChnInfo < WNI_CFG_VALID_CHANNEL_LIST_LEN; + nChnInfo++) { + if (p11dLog->Channels[nTmp] == + chnPwrInfo[nChnInfo].chanId) { + p11dLog->TxPwr[nTmp] = + chnPwrInfo[nChnInfo].pwr; + break; + } + } + } +diag_end: + if (!mac_ctx->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_country_information() - apply country code information + * @pMac: core MAC data structure + * + * This function programs the new country code + * + * Return: none + */ +void csr_apply_country_information(tpAniSirGlobal pMac) +{ + v_REGDOMAIN_t domainId; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (!csr_is11d_supported(pMac) + || 0 == pMac->scan.channelOf11dInfo) + return; + status = csr_get_regulatory_domain_for_country(pMac, + pMac->scan.countryCode11d, &domainId, COUNTRY_QUERY); + if (!CDF_IS_STATUS_SUCCESS(status)) + return; + /* Check whether we need to enforce default domain */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_apply_country_info(pMac); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (pMac->scan.domainIdCurrent != domainId) + return; + if (pMac->scan.domainIdCurrent != domainId) { + sms_log(pMac, LOGW, FL("Domain Changed Old %d, new %d"), + pMac->scan.domainIdCurrent, domainId); + status = wma_set_reg_domain(pMac, domainId); + } + if (status != CDF_STATUS_SUCCESS) + sms_log(pMac, LOGE, FL("fail to set regId %d"), domainId); + pMac->scan.domainIdCurrent = domainId; + /* switch to active scans using this new channel list */ + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; +} + +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fill_5f) +{ + uint32_t idx, count = 0; + tSirMacChanInfo *chan_info; + tSirMacChanInfo *ch_info_start; + int32_t max_ch_idx; + bool tmp_bool; + uint8_t ch = 0; + + max_ch_idx = + (pMac->scan.base_channels.numChannels < + WNI_CFG_VALID_CHANNEL_LIST_LEN) ? + pMac->scan.base_channels.numChannels : + WNI_CFG_VALID_CHANNEL_LIST_LEN; + + chan_info = cdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == chan_info) + return; + + cdf_mem_set(chan_info, sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN, 0); + ch_info_start = chan_info; + for (idx = 0; idx < max_ch_idx; idx++) { + ch = pMac->scan.defaultPowerTable[idx].chanId; + tmp_bool = (fill_5f && CDS_IS_CHANNEL_5GHZ(ch)) + || (!fill_5f && CDS_IS_CHANNEL_24GHZ(ch)); + if (!tmp_bool) + continue; + + if (count >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + sms_log(pMac, LOGW, FL("count(%d) exceeded"), count); + break; + } + + chan_info->firstChanNum = + pMac->scan.defaultPowerTable[idx].chanId; + chan_info->numChannels = 1; + chan_info->maxTxPower = + CDF_MIN(pMac->scan.defaultPowerTable[idx].pwr, + pMac->roam.configParam.nTxPowerCap); + chan_info++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * sizeof(tSirMacChanInfo), ch_info_start); + } + cdf_mem_free(ch_info_start); +} + +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId) +{ + bool fRet = false; + uint32_t i; + + for (i = 0; i < pMac->scan.base_channels.numChannels; i++) { + if (channelId == + pMac->scan.base_channels.channelList[i]) { + fRet = true; + break; + } + } + + return fRet; +} + +/* + * 802.11D only: Gather 11d IE via beacon or Probe response and store them in pAdapter->channels11d + */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce) +{ + CDF_STATUS status; + uint8_t *pCountryCodeSelected; + bool fRet = false; + v_REGDOMAIN_t domainId; + tDot11fBeaconIEs *pIesLocal = pIes; + bool useVoting = false; + + if (CDF_SAP_MODE == cds_get_conparam()) + return CDF_STATUS_SUCCESS; + + if ((NULL == pSirBssDesc) && (NULL == pIes)) + useVoting = true; + + /* check if .11d support is enabled */ + if (!csr_is11d_supported(pMac)) + goto free_ie; + + if (false == useVoting) { + if (!pIesLocal && + (!CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pSirBssDesc, &pIesLocal)))) + goto free_ie; + /* check if country information element is present */ + if (!pIesLocal->Country.present) + /* No country info */ + goto free_ie; + status = csr_get_regulatory_domain_for_country(pMac, + pIesLocal->Country.country, &domainId, + COUNTRY_QUERY); + if (CDF_IS_STATUS_SUCCESS(status) + && (domainId == REGDOMAIN_WORLD)) + goto free_ie; + } /* useVoting == false */ + + if (false == useVoting) + pCountryCodeSelected = pIesLocal->Country.country; + else + pCountryCodeSelected = pMac->scan.countryCodeElected; + + status = csr_get_regulatory_domain_for_country(pMac, + pCountryCodeSelected, &domainId, COUNTRY_IE); + if (status != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL("fail to get regId %d"), domainId); + fRet = false; + goto free_ie; + } + + /* updating 11d Country Code with Country code selected. */ + cdf_mem_copy(pMac->scan.countryCode11d, pCountryCodeSelected, + WNI_CFG_COUNTRY_CODE_LEN); + fRet = true; +free_ie: + if (!pIes && pIesLocal) { + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + return fRet; +} + +void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason, + uint8_t sessionId) +{ + sms_log(pMac, LOG4, "%s: Saving scan results", __func__); + + /* initialize this to false. profMoveInterimScanResultsToMainList() routine */ + /* will set this to the channel where an .11d beacon is seen */ + pMac->scan.channelOf11dInfo = 0; + /* move the scan results from interim list to the main scan list */ + csr_move_temp_scan_results_to_main_list(pMac, reason, sessionId); + + /* Now check if we gathered any domain/country specific information */ + /* If so, we should update channel list and apply Tx power settings */ + if (csr_is11d_supported(pMac)) { + csr_apply_country_information(pMac); + } +} + +void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + switch (pCommand->u.scanCmd.reason) { + case eCsrScanAbortNormalScan: + default: + csr_scan_free_request(pMac, &pCommand->u.scanCmd.u.scanRequest); + break; + } + if (pCommand->u.scanCmd.pToRoamProfile) { + csr_release_profile(pMac, pCommand->u.scanCmd.pToRoamProfile); + cdf_mem_free(pCommand->u.scanCmd.pToRoamProfile); + } + cdf_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0); +} + +eCsrScanCompleteNextCommand csr_scan_get_next_command_state(tpAniSirGlobal pMac, + tSmeCmd *pCommand, + bool fSuccess) +{ + eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing; + + switch (pCommand->u.scanCmd.reason) { + case eCsrScan11d1: + NextCommand = + (fSuccess) ? eCsrNext11dScan1Success : + eCsrNext11dScan1Failure; + break; + case eCsrScan11d2: + NextCommand = + (fSuccess) ? eCsrNext11dScan2Success : + eCsrNext11dScan2Failure; + break; + case eCsrScan11dDone: + NextCommand = eCsrNext11dScanComplete; + break; + case eCsrScanLostLink1: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan1Success : + eCsrNextLostLinkScan1Failed; + break; + case eCsrScanLostLink2: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan2Success : + eCsrNextLostLinkScan2Failed; + break; + case eCsrScanLostLink3: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan3Success : + eCsrNextLostLinkScan3Failed; + break; + case eCsrScanForSsid: + NextCommand = + (fSuccess) ? eCsrNexteScanForSsidSuccess : + eCsrNexteScanForSsidFailure; + break; + default: + NextCommand = eCsrNextScanNothing; + break; + } + return NextCommand; +} + +/* Return whether the pCommand is finished. */ +bool csr_handle_scan11d1_failure(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + bool fRet = true; + + /* Apply back the default setting and passively scan one more time. */ + csr_apply_channel_power_info_wrapper(pMac); + pCommand->u.scanCmd.reason = eCsrScan11d2; + if (CDF_IS_STATUS_SUCCESS(csr_scan_channels(pMac, pCommand))) { + fRet = false; + } + + return fRet; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_diag_scan_complete(tpAniSirGlobal pMac, + tSmeCmd *pCommand, + tSirSmeScanRsp *pScanRsp) +{ + host_log_scan_pkt_type *pScanLog = NULL; + tScanResultHandle hScanResult; + tCsrScanResultInfo *pScanResult; + tDot11fBeaconIEs *pIes; + int n = 0, c = 0; + CDF_STATUS status; + + WLAN_HOST_DIAG_LOG_ALLOC(pScanLog, + host_log_scan_pkt_type, + LOG_WLAN_SCAN_C); + if (!pScanLog) + return; + + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) { + pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_RSP; + } else { + if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType) + pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP; + else + pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP; + } + if (eSIR_SME_SUCCESS != pScanRsp->statusCode) { + pScanLog->status = WLAN_SCAN_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + return; + } + + status = csr_scan_get_result(pMac, NULL, &hScanResult); + if (!CDF_IS_STATUS_SUCCESS(status)) { + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + return; + } + + pScanResult = csr_scan_result_get_next(pMac, hScanResult); + while (pScanResult != NULL) { + if (n < HOST_LOG_MAX_NUM_BSSID) { + status = csr_get_parsed_bss_description_ies(pMac, + &pScanResult->BssDescriptor, &pIes); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("fail to parse IEs")); + break; + } + cdf_mem_copy(pScanLog->bssid[n], + pScanResult->BssDescriptor.bssId, 6); + if (pIes && pIes->SSID.present && + HOST_LOG_MAX_SSID_SIZE >= pIes->SSID.num_ssid) { + cdf_mem_copy(pScanLog->ssid[n], + pIes->SSID.ssid, + pIes->SSID.num_ssid); + } + cdf_mem_free(pIes); + n++; + } + c++; + pScanResult = csr_scan_result_get_next(pMac, hScanResult); + } + pScanLog->numSsid = (uint8_t) n; + pScanLog->totalSsid = (uint8_t) c; + csr_scan_result_purge(pMac, hScanResult); + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + + csr_diag_event_report(pMac, eCSR_EVENT_SCAN_COMPLETE, eSIR_SUCCESS, + eSIR_SUCCESS); + if (c > 0) + csr_diag_event_report(pMac, eCSR_EVENT_SCAN_RES_FOUND, + eSIR_SUCCESS, eSIR_SUCCESS); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_handle_nxt_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *pCommand, + eCsrScanCompleteNextCommand *nxt_cmd, + bool *remove_cmd, uint32_t session_id) +{ + CDF_STATUS status; + switch (*nxt_cmd) { + case eCsrNext11dScan1Success: + case eCsrNext11dScan2Success: + sms_log(mac_ctx, LOG2, + FL("11dScan1/3 produced results. Reissue Active scan")); + /* + * if we found country information, no need to continue scanning + * further, bail out + */ + *remove_cmd = true; + *nxt_cmd = eCsrNext11dScanComplete; + break; + case eCsrNext11dScan1Failure: + /* + * We are not done yet. 11d scan fail once. We will try to reset + * anything and do it over again. The only meaningful thing for + * this retry is that we cannot find 11d information after a + * reset so we clear the "old" 11d info and give it once more + * chance + */ + *remove_cmd = csr_handle_scan11d1_failure(mac_ctx, pCommand); + if (*remove_cmd) + *nxt_cmd = eCsrNext11dScanComplete; + break; + case eCsrNextLostLinkScan1Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink1); + if (!CDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan2Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink2); + if (!CDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan3Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink3); + if (!CDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan1Failed: + csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan2Failed: + csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan3Failed: + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + case eCsrNexteScanForSsidSuccess: + csr_scan_handle_search_for_ssid(mac_ctx, pCommand); + break; + case eCsrNexteScanForSsidFailure: + csr_scan_handle_search_for_ssid_failure(mac_ctx, pCommand); + break; + default: + break; + } +} + +/** + * csr_get_active_scan_entry() - To get scan entry from active command list + * + * @mac_ctx - MAC context + * @scan_id - Scan identifier of the scan request + * @entry - scan entry returned. + * + * Scan entry in the active scan list mapping to the sent scan id + * is returned to the caller. + * + * Return: CDF_STATUS. + */ +CDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac_ctx, + uint32_t scan_id, tListElem **entry) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tListElem *localentry; + tSmeCmd *cmd; + uint32_t cmd_scan_id = 0; + + csr_ll_lock(&mac_ctx->sme.smeScanCmdActiveList); + + if (csr_ll_is_list_empty(&mac_ctx->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK)) { + sms_log(mac_ctx, LOGE, + FL(" Active list Empty scanId: %d"), scan_id); + return CDF_STATUS_SUCCESS; + } + localentry = csr_ll_peek_head(&mac_ctx->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK); + do { + cmd = GET_BASE_ADDR(localentry, tSmeCmd, Link); + if (cmd->command == eSmeCommandScan) + cmd_scan_id = cmd->u.scanCmd.u.scanRequest.scan_id; + else if (cmd->command == eSmeCommandRemainOnChannel) + cmd_scan_id = cmd->u.remainChlCmd.scan_id; + if (cmd_scan_id == scan_id) { + sms_log(mac_ctx, LOG1, FL(" scanId Matched %d"), + scan_id); + *entry = localentry; + csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList); + return CDF_STATUS_SUCCESS; + } + localentry = csr_ll_next(&mac_ctx->sme.smeScanCmdActiveList, + localentry, LL_ACCESS_NOLOCK); + } while (localentry); + csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList); + return status; +} + +/* Return whether the command should be removed */ +bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp) +{ + eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing; + tListElem *pEntry = NULL; + tSmeCmd *pCommand; + bool fRemoveCommand = true; + bool fSuccess; + uint32_t sessionId = 0; + + csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, + FL("Scan Completion called but NO cmd ACTIVE ...")); + return false; + } + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* + * If the head of the queue is Active and it is a SCAN command, remove + * and put this on the Free queue. + */ + if (eSmeCommandScan != pCommand->command) { + sms_log(pMac, LOGW, + FL("Scan Completion called, but active SCAN cmd")); + return false; + } + + sessionId = pCommand->sessionId; + if (eSIR_SME_SUCCESS != pScanRsp->statusCode) { + fSuccess = false; + } else { + /* + * pMac->scan.tempScanResults is not empty meaning the scan + * found something. This check only valid here because + * csrSaveScanresults is not yet called + */ + fSuccess = (!csr_ll_is_list_empty(&pMac->scan.tempScanResults, + LL_ACCESS_LOCK)); + } + if (pCommand->u.scanCmd.abortScanDueToBandChange) { + /* + * Scan aborted due to band change + * The scan results need to be flushed + */ + if (pCommand->u.scanCmd.callback + != pMac->scan.callback11dScanDone) { + sms_log(pMac, LOG1, FL("Filtering the scan results")); + csr_scan_filter_results(pMac); + } else { + sms_log(pMac, LOG1, + FL("11d_scan_done, flushing the scan results")); + } + pCommand->u.scanCmd.abortScanDueToBandChange = false; + } + csr_save_scan_results(pMac, pCommand->u.scanCmd.reason, sessionId); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_scan_complete(pMac, pCommand, pScanRsp); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + NextCommand = csr_scan_get_next_command_state(pMac, pCommand, fSuccess); + /* We reuse the command here instead reissue a new command */ + csr_handle_nxt_cmd(pMac, pCommand, &NextCommand, + &fRemoveCommand, sessionId); + return fRemoveCommand; +} + +static void +csr_scan_remove_dup_bss_description_from_interim_list(tpAniSirGlobal mac_ctx, + tSirBssDescription *bss_dscp, + tDot11fBeaconIEs *pIes) +{ + tListElem *pEntry; + tCsrScanResult *scan_bss_dscp; + int8_t scan_entry_rssi = 0; + /* + * Walk through all the chained BssDescriptions. If we find a chained + * BssDescription that matches the BssID of the BssDescription passed + * in, then these must be duplicate scan results for this Bss. In that + * case, remove the 'old' Bss description from the linked list. + */ + sms_log(mac_ctx, LOG4, FL(" for BSS " MAC_ADDRESS_STR " "), + MAC_ADDR_ARRAY(bss_dscp->bssId)); + csr_ll_lock(&mac_ctx->scan.tempScanResults); + pEntry = csr_ll_peek_head(&mac_ctx->scan.tempScanResults, + LL_ACCESS_NOLOCK); + while (pEntry) { + scan_bss_dscp = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + /* + * we have a duplicate scan results only when BSSID, SSID, + * Channel and NetworkType matches + */ + scan_entry_rssi = scan_bss_dscp->Result.BssDescriptor.rssi; + if (csr_is_duplicate_bss_description(mac_ctx, + &scan_bss_dscp->Result.BssDescriptor, bss_dscp, + pIes, false)) { + /* + * Following is mathematically a = (aX + b(100-X))/100 + * where: + * a = bss_dscp->rssi, b = scan_entry_rssi + * and X = CSR_SCAN_RESULT_RSSI_WEIGHT + */ + bss_dscp->rssi = (int8_t) ((((int32_t) bss_dscp->rssi * + CSR_SCAN_RESULT_RSSI_WEIGHT) + + ((int32_t) scan_entry_rssi * + (100 - CSR_SCAN_RESULT_RSSI_WEIGHT))) / 100); + /* Remove the 'old' entry from the list */ + if (csr_ll_remove_entry(&mac_ctx->scan.tempScanResults, + pEntry, LL_ACCESS_NOLOCK)) { + csr_check_n_save_wsc_ie(mac_ctx, bss_dscp, + &scan_bss_dscp->Result. + BssDescriptor); + /* + * we need to free the memory associated with + * this node + */ + csr_free_scan_result_entry(mac_ctx, + scan_bss_dscp); + } + /* + * If we found a match, we can stop looking through + * the list. + */ + break; + } + pEntry = csr_ll_next(&mac_ctx->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(&mac_ctx->scan.tempScanResults); +} + +/* Caller allocated memory pfNewBssForConn to return whether new candidate for */ +/* current connection is found. Cannot be NULL */ +tCsrScanResult *csr_scan_save_bss_description_to_interim_list(tpAniSirGlobal pMac, + tSirBssDescription * + pBSSDescription, + tDot11fBeaconIEs *pIes) +{ + tCsrScanResult *pCsrBssDescription = NULL; + uint32_t cbBSSDesc; + uint32_t cbAllocated; + + /* figure out how big the BSS description is (the BSSDesc->length does NOT */ + /* include the size of the length field itself). */ + cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length); + + cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc; + + sms_log(pMac, LOG4, FL("new BSS description, length %d, cbBSSDesc %d"), + cbAllocated, cbBSSDesc); + pCsrBssDescription = cdf_mem_malloc(cbAllocated); + if (NULL != pCsrBssDescription) { + cdf_mem_set(pCsrBssDescription, cbAllocated, 0); + cdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor, + pBSSDescription, cbBSSDesc); + pCsrBssDescription->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOG4, + FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "), + pCsrBssDescription->AgingCount, + MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor. + bssId)); + /* Save SSID separately for later use */ + if (pIes->SSID.present + && !csr_is_nullssid(pIes->SSID.ssid, pIes->SSID.num_ssid)) { + /* SSID not hidden */ + uint32_t len = pIes->SSID.num_ssid; + if (len > SIR_MAC_MAX_SSID_LENGTH) { + /* truncate to fit in our struct */ + len = SIR_MAC_MAX_SSID_LENGTH; + } + pCsrBssDescription->Result.ssId.length = len; + pCsrBssDescription->Result.timer = + cdf_mc_timer_get_system_time(); + cdf_mem_copy(pCsrBssDescription->Result.ssId.ssId, + pIes->SSID.ssid, len); + } + csr_ll_insert_tail(&pMac->scan.tempScanResults, + &pCsrBssDescription->Link, LL_ACCESS_LOCK); + } + + return pCsrBssDescription; +} + +bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2, bool fForced) +{ + bool fMatch = false; + tSirMacCapabilityInfo *pCap1, *pCap2; + tDot11fBeaconIEs *pIes1 = NULL; + tDot11fBeaconIEs *pIesTemp = pIes2; + CDF_STATUS status; + + pCap1 = (tSirMacCapabilityInfo *) &pSirBssDesc1->capabilityInfo; + pCap2 = (tSirMacCapabilityInfo *) &pSirBssDesc2->capabilityInfo; + + if (pCap1->ess != pCap2->ess) + goto free_ies; + + if (pCap1->ess && + cdf_is_macaddr_equal((struct cdf_mac_addr *) pSirBssDesc1->bssId, + (struct cdf_mac_addr *) pSirBssDesc2->bssId) + && (fForced + || (cds_chan_to_band(pSirBssDesc1->channelId) == + cds_chan_to_band((pSirBssDesc2->channelId))))) { + fMatch = true; + /* Check for SSID match, if exists */ + status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1, + &pIes1); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + + if (NULL == pIesTemp) { + status = csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc2, &pIesTemp); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + } + if (pIes1->SSID.present && pIesTemp->SSID.present) { + fMatch = csr_is_ssid_match(pMac, pIes1->SSID.ssid, + pIes1->SSID.num_ssid, + pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid, + true); + } + } else if (pCap1->ibss && (pSirBssDesc1->channelId == + pSirBssDesc2->channelId)) { + status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1, + &pIes1); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + + if (NULL == pIesTemp) { + status = csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc2, &pIesTemp); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + } + + /* Same channel cannot have same SSID for different IBSS */ + if (pIes1->SSID.present && pIesTemp->SSID.present) { + fMatch = csr_is_ssid_match(pMac, pIes1->SSID.ssid, + pIes1->SSID.num_ssid, + pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid, + true); + } + } + /* In case of P2P devices, ess and ibss will be set to zero */ + else if (!pCap1->ess && + cdf_is_macaddr_equal( + (struct cdf_mac_addr *) pSirBssDesc1->bssId, + (struct cdf_mac_addr *) pSirBssDesc2->bssId)) { + fMatch = true; + } + +free_ies: + if (pIes1) + cdf_mem_free(pIes1); + if ((NULL == pIes2) && pIesTemp) + /* locally allocated */ + cdf_mem_free(pIesTemp); + return fMatch; +} + +bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2) +{ + return pSirBssDesc1->nwType == pSirBssDesc2->nwType; +} + +/* to check whether the BSS matches the dot11Mode */ +static bool csr_scan_is_bss_allowed(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + bool fAllowed = false; + eCsrPhyMode phyMode; + + if (CDF_IS_STATUS_SUCCESS + (csr_get_phy_mode_from_bss(pMac, pBssDesc, &phyMode, pIes))) { + switch (pMac->roam.configParam.phyMode) { + case eCSR_DOT11_MODE_11b: + fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode); + break; + case eCSR_DOT11_MODE_11g: + fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode); + break; + case eCSR_DOT11_MODE_11g_ONLY: + fAllowed = (bool) (eCSR_DOT11_MODE_11g == phyMode); + break; + case eCSR_DOT11_MODE_11a: + fAllowed = (bool) ((eCSR_DOT11_MODE_11b != phyMode) + && (eCSR_DOT11_MODE_11g != phyMode)); + break; + case eCSR_DOT11_MODE_11n_ONLY: + fAllowed = (bool) ((eCSR_DOT11_MODE_11n == phyMode)); + break; + +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac_ONLY: + fAllowed = (bool) ((eCSR_DOT11_MODE_11ac == phyMode)); + break; +#endif + case eCSR_DOT11_MODE_11b_ONLY: + fAllowed = (bool) (eCSR_DOT11_MODE_11b == phyMode); + break; + case eCSR_DOT11_MODE_11n: +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: +#endif + default: + fAllowed = true; + break; + } + } + + return fAllowed; +} + +/* Return pIes to caller for future use when returning true. */ +static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac, + uint8_t *pChannels, + uint8_t numChn, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIes) +{ + bool valid = false; + tDot11fBeaconIEs *pIes = NULL; + uint8_t index; + CDF_STATUS status; + + for (index = 0; index < numChn; index++) { + /* + * This check relies on the fact that a single BSS description + * is returned in each ScanRsp call, which is the way LIM + * implemented the scan req/rsp funtions. We changed to this + * model when we ran with a large number of APs. If this were to + * change, then this check would have to mess with removing the + * bssDescription from somewhere in an arbitrary index in the + * bssDescription array. + */ + if (pChannels[index] == pBssDesc->channelId) { + valid = true; + break; + } + } + *ppIes = NULL; + if (valid) { + status = csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIes); + if (!CDF_IS_STATUS_SUCCESS(status)) + return false; + + valid = csr_scan_is_bss_allowed(pMac, pBssDesc, pIes); + if (valid) + *ppIes = pIes; + else + cdf_mem_free(pIes); + } + return valid; +} + +static void csr_update_scantype(tpAniSirGlobal pMac, tDot11fBeaconIEs *pIes, + uint8_t channelId) +{ + if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType) + return; + + if (csr_is11d_supported(pMac)) { + /* Check whether the BSS is acceptable based on + * 11d info and our config. + */ + if (!csr_match_country_code(pMac, NULL, pIes)) + return; + + /* check if channel is acceptable by config */ + if (csr_is_supported_channel(pMac, channelId)) + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + + } else + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + +} + +/* Return whether last scan result is received */ +static bool csr_scan_process_scan_results(tpAniSirGlobal pMac, tSmeCmd *pCommand, + tSirSmeScanRsp *pScanRsp, + bool *pfRemoveCommand) +{ + bool fRet = false, fRemoveCommand = false; + + sms_log(pMac, LOG1, FL("scan reason = %d, response status code = %d"), + pCommand->u.scanCmd.reason, pScanRsp->statusCode); + fRemoveCommand = csr_scan_complete(pMac, pScanRsp); + fRet = true; + if (pfRemoveCommand) { + *pfRemoveCommand = fRemoveCommand; + } + return fRet; +} + +/* csr_scan_process_single_bssdescr() - Add a bssdescriptor to scan table + * + * @mac_ctx - MAC context + * @bssdescr - Pointer to BSS description structure that contains + * everything from beacon/probe response frame and additional + * information. + * @scan_id - Scan identifier of the scan request that was running + * when this beacon was received. Reserved for future when + * firmware provides that information. + * @flags - Reserved for future use. + * + * Callback routine called by LIM when it receives a beacon or probe response + * from the device. 802.11 frame is already converted to internal + * tSirBssDescription data structure. + * + * Return: 0 or other error codes. + */ + +CDF_STATUS csr_scan_process_single_bssdescr(tpAniSirGlobal mac_ctx, + tSirBssDescription *bssdescr, + uint32_t scan_id, uint32_t flags) +{ + tDot11fBeaconIEs *ies = NULL; + uint8_t *chanlist = NULL; + uint8_t cnt_channels = 0; + uint32_t len = sizeof(mac_ctx->roam.validChannelList); + + sms_log(mac_ctx, LOG4, "CSR: Processing single bssdescr"); + if (CDF_IS_STATUS_SUCCESS( + csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, + &len))) { + chanlist = mac_ctx->roam.validChannelList; + cnt_channels = (uint8_t) len; + } else { + /* Cannot continue */ + sms_log(mac_ctx, LOGW, + FL("Received results on invalid channel")); + return CDF_STATUS_E_INVAL; + } + + if (csr_scan_validate_scan_result(mac_ctx, chanlist, + cnt_channels, bssdescr, &ies)) { + csr_scan_remove_dup_bss_description_from_interim_list + (mac_ctx, bssdescr, ies); + csr_scan_save_bss_description_to_interim_list + (mac_ctx, bssdescr, ies); + csr_update_scantype(mac_ctx, ies, bssdescr->channelId); + /* Free the resource */ + if (ies != NULL) + cdf_mem_free(ies); + } + return CDF_STATUS_SUCCESS; +} + + +bool csr_scan_is_wild_card_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + uint8_t bssid[CDF_MAC_ADDR_SIZE] = {0}; + bool f = cdf_mem_compare(pCommand->u.scanCmd.u.scanRequest.bssid.bytes, + bssid, sizeof(struct cdf_mac_addr)); + /* + * It is not a wild card scan if the bssid is not broadcast and + * the number of SSID is 1. + */ + return (f || (0xff == pCommand->u.scanCmd.u.scanRequest.bssid.bytes[0])) + && (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs != 1); +} + +CDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand; + eCsrScanStatus scanStatus; + tSirSmeScanRsp *pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + bool fRemoveCommand = true; + eCsrScanReason reason = eCsrScanOther; + + csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry); + if (!pEntry) + goto error_handling; + + sms_log(pMac, LOG1, FL("Scan completion called:scan_id %d, entry = %p"), + pScanRsp->scan_id, pEntry); + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandScan != pCommand->command) + goto error_handling; + + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; + reason = pCommand->u.scanCmd.reason; + switch (pCommand->u.scanCmd.reason) { + case eCsrScanAbortNormalScan: + break; + case eCsrScanP2PFindPeer: + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_FOUND_PEER : eCSR_SCAN_FAILURE; + csr_scan_process_scan_results(pMac, pCommand, pScanRsp, NULL); + break; + default: + if (csr_scan_process_scan_results(pMac, pCommand, pScanRsp, + &fRemoveCommand) + && csr_scan_is_wild_card_scan(pMac, pCommand) + && !pCommand->u.scanCmd.u.scanRequest.p2pSearch) { + + /* Age out logic will be taken care by the age out timer */ + } + break; + } + if (fRemoveCommand) + csr_release_scan_command(pMac, pCommand, scanStatus); + sme_process_pending_queue(pMac); + return status; + +error_handling: +#ifdef FEATURE_WLAN_SCAN_PNO + if (pMac->pnoOffload && pScanRsp->statusCode == eSIR_PNO_SCAN_SUCCESS) { + sms_log(pMac, LOGE, FL("PNO Scan completion called.")); + csr_save_scan_results(pMac, eCsrScanCandidateFound, + pScanRsp->sessionId); + return CDF_STATUS_SUCCESS; + } else { + /* + * Scan completion was called, PNO is active, but scan + * response was not PNO + */ + sms_log(pMac, LOGE, + FL("Scan completion called, scan rsp was not PNO.")); + return CDF_STATUS_E_FAILURE; + } +#endif + sms_log(pMac, LOGE, FL("Scan completion called, but no active SCAN command.")); + return CDF_STATUS_E_FAILURE; +} + +tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal pMac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry; + tCsrScanResult *pResult; + tCsrScanResultInfo *pRet = NULL; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + + if (pResultList) { + csr_ll_lock(&pResultList->List); + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + csr_ll_unlock(&pResultList->List); + } + + return pRet; +} + +tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal pMac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry = NULL; + tCsrScanResult *pResult = NULL; + tCsrScanResultInfo *pRet = NULL; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + + if (!pResultList) + return NULL; + + csr_ll_lock(&pResultList->List); + if (NULL == pResultList->pCurEntry) { + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + } else { + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + } + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + csr_ll_unlock(&pResultList->List); + return pRet; +} + +/* + * This function moves the first BSS that matches the bssid to the + * head of the result + */ +CDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct cdf_mac_addr *bssid, + tScanResultHandle hScanResult) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + tCsrScanResult *pResult = NULL; + tListElem *pEntry = NULL; + + if (!(pResultList && bssid)) + return status; + + csr_ll_lock(&pResultList->List); + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (cdf_mem_compare(bssid, pResult->Result.BssDescriptor.bssId, + sizeof(struct cdf_mac_addr))) { + status = CDF_STATUS_SUCCESS; + csr_ll_remove_entry(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + csr_ll_insert_head(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + break; + } + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pResultList->List); + return status; +} + +/* Remove the BSS if possible. */ +/* Return -- true == the BSS is remove. False == Fail to remove it */ +/* This function is called when list lock is held. Be caution what functions it can call. */ +bool csr_scan_age_out_bss(tpAniSirGlobal pMac, tCsrScanResult *pResult) +{ + bool fRet = false; + uint32_t i; + tCsrRoamSession *pSession; + bool isConnBssfound = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + pSession = CSR_GET_SESSION(pMac, i); + /* Not to remove the BSS we are connected to. */ + if (csr_is_conn_state_connected_infra(pMac, i) + && (NULL != pSession->pConnectBssDesc) + && (csr_is_duplicate_bss_description(pMac, + &pResult->Result.BssDescriptor, + pSession->pConnectBssDesc, NULL, false))) { + isConnBssfound = true; + break; + } + } + if (isConnBssfound) { + /* + * Reset the counter so that aging out of connected BSS won't + * hapeen too soon + */ + pResult->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOGW, + FL("Connected BSS, Set Aging Count=%d for BSS " + MAC_ADDRESS_STR), pResult->AgingCount, + MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId)); + pResult->Result.BssDescriptor.nReceivedTime = + (uint32_t) cdf_mc_timer_get_system_ticks(); + return fRet; + } + sms_log(pMac, LOGW, + "Aging out BSS " MAC_ADDRESS_STR " Channel %d", + MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId), + pResult->Result.BssDescriptor.channelId); + /* + * No need to hold the spin lock because caller should hold the lock for + * pMac->scan.scanResultList + */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, &pResult->Link, + LL_ACCESS_NOLOCK)) { + if (cdf_is_macaddr_equal( + (struct cdf_mac_addr *) &pResult->Result.BssDescriptor.bssId, + (struct cdf_mac_addr *) &pMac->scan.currentCountryBssid)) { + sms_log(pMac, LOGW, + FL("Aging out 11d BSS " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pResult->Result.BssDescriptor.bssId)); + pMac->scan.currentCountryRSSI = -128; + } + csr_free_scan_result_entry(pMac, pResult); + fRet = true; + } + return fRet; +} + +CDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac, + tSmeGetScanChnRsp *pScanChnInfo) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry, *tmpEntry; + tCsrScanResult *pResult; + tLimScanChn *pChnInfo; + uint8_t i; + + csr_ll_lock(&pMac->scan.scanResultList); + for (i = 0; i < pScanChnInfo->numChn; i++) { + pChnInfo = &pScanChnInfo->scanChn[i]; + pEntry = + csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + tmpEntry = + csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (pResult->Result.BssDescriptor.channelId == + pChnInfo->channelId) { + if (pResult->AgingCount <= 0) { + sms_log(pMac, LOGW, + " age out due to ref count"); + csr_scan_age_out_bss(pMac, pResult); + } else { + pResult->AgingCount--; + sms_log(pMac, LOGW, + FL + ("Decremented AgingCount=%d for BSS " + MAC_ADDRESS_STR ""), + pResult->AgingCount, + MAC_ADDR_ARRAY(pResult->Result. + BssDescriptor. + bssId)); + } + } + pEntry = tmpEntry; + } + } + csr_ll_unlock(&pMac->scan.scanResultList); + + return status; +} + +CDF_STATUS csr_send_mb_scan_req(tpAniSirGlobal pMac, uint16_t sessionId, + tCsrScanRequest *pScanReq, + tScanReqParam *pScanReqParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeScanReq *pMsg; + uint16_t msgLen; + tSirScanType scanType = pScanReq->scanType; + uint32_t minChnTime; /* in units of milliseconds */ + uint32_t maxChnTime; /* in units of milliseconds */ + uint32_t i; + uint8_t selfMacAddr[CDF_MAC_ADDR_SIZE]; + uint8_t *pSelfMac = NULL; + + msgLen = (uint16_t) (sizeof(tSirSmeScanReq) - + sizeof(pMsg->channelList.channelNumber) + + (sizeof(pMsg->channelList.channelNumber) * + pScanReq->ChannelInfo.numOfChannels)) + + (pScanReq->uIEFieldLen); + + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) { + sms_log(pMac, LOGE, FL("memory allocation failed")); + sms_log(pMac, LOG1, FL("Failed: SId: %d FirstMatch = %d" + " UniqueResult = %d freshScan = %d hiddenSsid = %d"), + sessionId, pScanReqParam->bReturnAfter1stMatch, + pScanReqParam->fUniqueResult, pScanReqParam->freshScan, + pScanReqParam->hiddenSsid); + sms_log(pMac, LOG1, + FL("scanType = %u BSSType = %u numOfSSIDs = %d" + " numOfChannels = %d requestType = %d p2pSearch = %d\n"), + pScanReq->scanType, pScanReq->BSSType, + pScanReq->SSIDs.numOfSSIDs, + pScanReq->ChannelInfo.numOfChannels, + pScanReq->requestType, pScanReq->p2pSearch); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set(pMsg, msgLen, 0); + pMsg->messageType = eWNI_SME_SCAN_REQ; + pMsg->length = msgLen; + /* ToDO: Fill in session info when we need to do scan base on session */ + if ((sessionId != CSR_SESSION_ID_INVALID)) { + pMsg->sessionId = sessionId; + } else { + /* if sessionId == CSR_SESSION_ID_INVALID, then send the scan + request on first available session */ + pMsg->sessionId = 0; + } + if (pMsg->sessionId >= CSR_ROAM_SESSION_MAX) + sms_log(pMac, LOGE, FL(" Invalid Sme Session ID = %d"), + pMsg->sessionId); + pMsg->transactionId = 0; + pMsg->dot11mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(pMac, + csr_find_best_phy_mode(pMac, + pMac->roam.configParam.phyMode)); + pMsg->bssType = csr_translate_bsstype_to_mac_type(pScanReq->BSSType); + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSelfMac = (uint8_t *) + &pMac->roam.roamSession[sessionId].selfMacAddr; + } else { + /* + * Since we don't have session for the scanning, we find a valid + * session. In case we fail to do so, get the WNI_CFG_STA_ID + */ + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + pSelfMac = (uint8_t *) + &pMac->roam.roamSession[i].selfMacAddr; + break; + } + } + if (CSR_ROAM_SESSION_MAX == i) { + uint32_t len = CDF_MAC_ADDR_SIZE; + pSelfMac = selfMacAddr; + status = wlan_cfg_get_str(pMac, WNI_CFG_STA_ID, + pSelfMac, &len); + if (!CDF_IS_STATUS_SUCCESS(status) + || (len < CDF_MAC_ADDR_SIZE)) { + sms_log(pMac, LOGE, + FL("Can't get self MAC address = %d"), + status); + /* Force failed status */ + status = CDF_STATUS_E_FAILURE; + goto send_scan_req; + } + } + } + cdf_mem_copy((uint8_t *) pMsg->selfMacAddr, + pSelfMac, sizeof(tSirMacAddr)); + + /* sir_copy_mac_addr */ + cdf_mem_copy(pMsg->bssId, &pScanReq->bssid, sizeof(tSirMacAddr)); + if (cdf_is_macaddr_zero(&pScanReq->bssid)) + cdf_mem_set(pMsg->bssId, sizeof(tSirMacAddr), 0xff); + else + cdf_mem_copy(pMsg->bssId, pScanReq->bssid.bytes, + CDF_MAC_ADDR_SIZE); + minChnTime = pScanReq->minChnTime; + maxChnTime = pScanReq->maxChnTime; + + /* + * Verify the scan type first, if the scan is active scan, we need to + * make sure we are allowed to do so. if 11d is enabled & we don't see + * any beacon around, scan type falls back to passive. But in BT AMP STA + * mode we need to send out a directed probe + */ + if ((eSIR_PASSIVE_SCAN != scanType) + && (eCSR_SCAN_P2P_DISCOVERY != + pScanReq->requestType) + && (eCSR_BSS_TYPE_WDS_STA != pScanReq->BSSType) + && (false == pMac->scan.fEnableBypass11d)) { + scanType = pMac->scan.curScanType; + if (eSIR_PASSIVE_SCAN == pMac->scan.curScanType) { + if (minChnTime < + pMac->roam.configParam.nPassiveMinChnTime) { + minChnTime = + pMac->roam.configParam.nPassiveMinChnTime; + } + if (maxChnTime < + pMac->roam.configParam.nPassiveMaxChnTime) { + maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTime; + } + } + } + pMsg->scanType = scanType; + + pMsg->numSsid = (pScanReq->SSIDs.numOfSSIDs < SIR_SCAN_MAX_NUM_SSID) ? + pScanReq->SSIDs.numOfSSIDs : SIR_SCAN_MAX_NUM_SSID; + if ((pScanReq->SSIDs.numOfSSIDs != 0) + && (eSIR_PASSIVE_SCAN != scanType)) { + for (i = 0; i < pMsg->numSsid; i++) { + cdf_mem_copy(&pMsg->ssId[i], + &pScanReq->SSIDs.SSIDList[i].SSID, + sizeof(tSirMacSSid)); + } + } else { + /* Otherwise we scan all SSID and let the result filter later */ + for (i = 0; i < SIR_SCAN_MAX_NUM_SSID; i++) + pMsg->ssId[i].length = 0; + } + + pMsg->minChannelTime = minChnTime; + pMsg->maxChannelTime = maxChnTime; + /* hidden SSID option */ + pMsg->hiddenSsid = pScanReqParam->hiddenSsid; + /* rest time */ + pMsg->restTime = pScanReq->restTime; + pMsg->returnAfterFirstMatch = pScanReqParam->bReturnAfter1stMatch; + /* All the scan results caching will be done by Roaming */ + /* We do not want LIM to do any caching of scan results, */ + /* so delete the LIM cache on all scan requests */ + pMsg->returnFreshResults = pScanReqParam->freshScan; + /* Always ask for unique result */ + pMsg->returnUniqueResults = pScanReqParam->fUniqueResult; + pMsg->channelList.numChannels = + (uint8_t) pScanReq->ChannelInfo.numOfChannels; + if (pScanReq->ChannelInfo.numOfChannels) { + /* Assuming the channelNumber is uint8_t (1 byte) */ + cdf_mem_copy(pMsg->channelList.channelNumber, + pScanReq->ChannelInfo.ChannelList, + pScanReq->ChannelInfo.numOfChannels); + } + + pMsg->uIEFieldLen = (uint16_t) pScanReq->uIEFieldLen; + pMsg->uIEFieldOffset = (uint16_t) (sizeof(tSirSmeScanReq) - + sizeof(pMsg->channelList.channelNumber) + + (sizeof(pMsg->channelList.channelNumber) * + pScanReq->ChannelInfo.numOfChannels)); + if (pScanReq->uIEFieldLen != 0) { + cdf_mem_copy((uint8_t *) pMsg + pMsg->uIEFieldOffset, + pScanReq->pIEField, pScanReq->uIEFieldLen); + } + pMsg->p2pSearch = pScanReq->p2pSearch; + pMsg->scan_id = pScanReq->scan_id; + +send_scan_req: + sms_log(pMac, LOG1, + FL("scanId %d domainIdCurrent %d scanType %d bssType %d requestType %d numChannels %d"), + pMsg->scan_id, pMac->scan.domainIdCurrent, pMsg->scanType, + pMsg->bssType, pScanReq->requestType, + pMsg->channelList.numChannels); + + for (i = 0; i < pMsg->channelList.numChannels; i++) { + sms_log(pMac, LOG1, FL("channelNumber[%d]= %d"), i, + pMsg->channelList.channelNumber[i]); + } + + if (CDF_IS_STATUS_SUCCESS(status)) { + status = cds_send_mb_message_to_mac(pMsg); + } else { + sms_log(pMac, LOGE, + FL("failed to send down scan req with status = %d"), + status); + cdf_mem_free(pMsg); + } + return status; +} + +CDF_STATUS csr_send_mb_scan_result_req(tpAniSirGlobal pMac, + uint32_t sessionId, + tScanReqParam *pScanReqParam) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeScanReq *pMsg; + uint16_t msgLen; + + msgLen = (uint16_t) (sizeof(tSirSmeScanReq)); + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pMsg, msgLen, 0); + pMsg->messageType = eWNI_SME_SCAN_REQ; + pMsg->length = msgLen; + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + pMsg->returnFreshResults = pScanReqParam->freshScan; + /* Always ask for unique result */ + pMsg->returnUniqueResults = pScanReqParam->fUniqueResult; + pMsg->returnAfterFirstMatch = + pScanReqParam->bReturnAfter1stMatch; + status = cds_send_mb_message_to_mac(pMsg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to send down scan req with status = %d\n"), + status); + } + return status; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + host_log_scan_pkt_type *pScanLog = NULL; + + WLAN_HOST_DIAG_LOG_ALLOC(pScanLog, + host_log_scan_pkt_type, + LOG_WLAN_SCAN_C); + if (!pScanLog) + return; + + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) { + pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_REQ; + } else { + if ((eSIR_PASSIVE_SCAN != + pCommand->u.scanCmd.u.scanRequest.scanType) + && (eSIR_PASSIVE_SCAN != pMac->scan.curScanType)) { + pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ; + } else { + pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ; + } + } + pScanLog->minChnTime = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.minChnTime; + pScanLog->maxChnTime = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.maxChnTime; + pScanLog->numChannel = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + if (pScanLog->numChannel && + (pScanLog->numChannel < HOST_LOG_MAX_NUM_CHANNEL)) { + cdf_mem_copy(pScanLog->channels, + pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList, + pScanLog->numChannel); + } + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); +} +#else +#define csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) (void)0; +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +CDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tScanReqParam scanReq; + + /* + * Don't delete cached results. Rome rssi based scan candidates may land + * up in scan cache instead of LFR cache. They will be deleted upon + * query + */ + scanReq.freshScan = SIR_BG_SCAN_RETURN_FRESH_RESULTS; + scanReq.fUniqueResult = true; + scanReq.hiddenSsid = SIR_SCAN_NO_HIDDEN_SSID; + if (eCsrScanForSsid == pCommand->u.scanCmd.reason) { + scanReq.bReturnAfter1stMatch = + CSR_SCAN_RETURN_AFTER_FIRST_MATCH; + } else { + /* + * Basically do scan on all channels even for 11D 1st scan case + */ + scanReq.bReturnAfter1stMatch = + CSR_SCAN_RETURN_AFTER_ALL_CHANNELS; + } + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) + scanReq.hiddenSsid = SIR_SCAN_HIDDEN_SSID_PE_DECISION; + csr_diag_scan_channels(pMac, pCommand); + csr_clear_votes_for_country_info(pMac); + status = csr_send_mb_scan_req(pMac, pCommand->sessionId, + &pCommand->u.scanCmd.u.scanRequest, + &scanReq); + return status; +} + +static CDF_STATUS +csr_issue_user_scan(tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + int i, j; + CDF_STATUS status; + uint32_t len = 0; + uint8_t *ch_lst = NULL; + tCsrChannelInfo new_ch_info = { 0, NULL }; + + if (!mac_ctx->roam.configParam.fScanTwice) + return csr_scan_channels(mac_ctx, cmd); + + /* We scan 2.4 channel twice */ + if (cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels + && (NULL != cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList)) { + len = cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + /* allocate twice the channel */ + new_ch_info.ChannelList = (uint8_t *) cdf_mem_malloc(len * 2); + ch_lst = cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList; + } else { + /* get the valid channel list to scan all. */ + len = sizeof(mac_ctx->roam.validChannelList); + status = csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, &len); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* allocate twice the channel */ + new_ch_info.ChannelList = + (uint8_t *) cdf_mem_malloc(len * 2); + ch_lst = mac_ctx->roam.validChannelList; + } + } + if (NULL == new_ch_info.ChannelList) { + new_ch_info.numOfChannels = 0; + } else { + j = 0; + for (i = 0; i < len; i++) { + new_ch_info.ChannelList[j++] = ch_lst[i]; + if (CDS_MAX_24GHz_CHANNEL_NUMBER >= ch_lst[i]) + new_ch_info.ChannelList[j++] = ch_lst[i]; + } + if (NULL != + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList) { + /* + * ch_lst points to the channellist from the command, + * free it. + */ + cdf_mem_free( + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList); + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = + NULL; + } + cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = j; + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = + new_ch_info.ChannelList; + } + + return csr_scan_channels(mac_ctx, cmd); +} + +CDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + sms_log(pMac, LOG3, + FL("starting SCAN cmd in %d state. reason %d"), + pCommand->u.scanCmd.lastRoamState[pCommand->sessionId], + pCommand->u.scanCmd.reason); + + switch (pCommand->u.scanCmd.reason) { + case eCsrScanUserRequest: + status = csr_issue_user_scan(pMac, pCommand); + break; + default: + status = csr_scan_channels(pMac, pCommand); + break; + } + + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_release_scan_command(pMac, pCommand, eCSR_SCAN_FAILURE); + } + + return status; +} + +/** + * csr_scan_copy_request_valid_channels_only() - scan request of valid channels + * @mac_ctx : pointer to Global Mac Structure + * @dst_req: pointer to tCsrScanRequest + * @skip_dfs_chnl: 1 - skip dfs channel, 0 - don't skip dfs channel + * @src_req: pointer to tCsrScanRequest + * + * This function makes a copy of scan request with valid channels + * + * Return: none + */ +static void csr_scan_copy_request_valid_channels_only(tpAniSirGlobal mac_ctx, + tCsrScanRequest *dst_req, uint8_t skip_dfs_chnl, + tCsrScanRequest *src_req) +{ + uint32_t index = 0; + uint32_t new_index = 0; + + for (index = 0; index < src_req->ChannelInfo.numOfChannels; index++) { + /* Allow scan on valid channels only. + * If it is p2p scan and valid channel list doesnt contain + * social channels, enforce scan on social channels because + * that is the only way to find p2p peers. + * This can happen only if band is set to 5Ghz mode. + */ + if (src_req->ChannelInfo.ChannelList[index] < MIN_11P_CHANNEL && + ((csr_roam_is_valid_channel(mac_ctx, + src_req->ChannelInfo.ChannelList[index])) || + ((eCSR_SCAN_P2P_DISCOVERY == src_req->requestType) && + CSR_IS_SOCIAL_CHANNEL( + src_req->ChannelInfo.ChannelList[index])))) { + if (((src_req->skipDfsChnlInP2pSearch || skip_dfs_chnl) + && (CHANNEL_STATE_DFS == + cds_get_channel_state(src_req-> + ChannelInfo. + ChannelList + [index]))) + ) { +#ifdef FEATURE_WLAN_LFR + sms_log(mac_ctx, LOG2, + FL(" reqType=%d, numOfChannels=%d, ignoring DFS channel %d"), + src_req->requestType, + src_req->ChannelInfo.numOfChannels, + src_req->ChannelInfo.ChannelList + [index]); +#endif + continue; + } + + dst_req->ChannelInfo.ChannelList[new_index] = + src_req->ChannelInfo.ChannelList[index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = new_index; +} + +/** + * csr_scan_copy_request() - Function to copy scan request + * @mac_ctx : pointer to Global Mac Structure + * @dst_req: pointer to tCsrScanRequest + * @src_req: pointer to tCsrScanRequest + * + * This function makes a copy of scan request + * + * Return: 0 - Success, Error number - Failure + */ +CDF_STATUS csr_scan_copy_request(tpAniSirGlobal mac_ctx, + tCsrScanRequest *dst_req, + tCsrScanRequest *src_req) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t len = sizeof(mac_ctx->roam.validChannelList); + uint32_t index = 0; + uint32_t new_index = 0; + CHANNEL_STATE channel_state; + bool skip_dfs_chnl = + mac_ctx->roam.configParam.initial_scan_no_dfs_chnl || + !mac_ctx->scan.fEnableDFSChnlScan; + + status = csr_scan_free_request(mac_ctx, dst_req); + if (!CDF_IS_STATUS_SUCCESS(status)) + goto complete; + cdf_mem_copy(dst_req, src_req, sizeof(tCsrScanRequest)); + /* Re-initialize the pointers to NULL since we did a copy */ + dst_req->pIEField = NULL; + dst_req->ChannelInfo.ChannelList = NULL; + dst_req->SSIDs.SSIDList = NULL; + + if (src_req->uIEFieldLen) { + dst_req->pIEField = + cdf_mem_malloc(src_req->uIEFieldLen); + if (NULL == dst_req->pIEField) { + status = CDF_STATUS_E_NOMEM; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning IE fields")); + goto complete; + } else { + status = CDF_STATUS_SUCCESS; + cdf_mem_copy(dst_req->pIEField, src_req->pIEField, + src_req->uIEFieldLen); + dst_req->uIEFieldLen = src_req->uIEFieldLen; + } + } + + /* Allocate memory for IE field */ + if (src_req->ChannelInfo.numOfChannels == 0) { + dst_req->ChannelInfo.ChannelList = NULL; + dst_req->ChannelInfo.numOfChannels = 0; + } else { + dst_req->ChannelInfo.ChannelList = + cdf_mem_malloc(src_req->ChannelInfo.numOfChannels * + sizeof(*dst_req->ChannelInfo.ChannelList)); + if (NULL == dst_req->ChannelInfo.ChannelList) { + status = CDF_STATUS_E_NOMEM; + dst_req->ChannelInfo.numOfChannels = 0; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning Channel List")); + goto complete; + } + + if ((src_req->scanType == eSIR_PASSIVE_SCAN) && + (src_req->requestType == eCSR_SCAN_REQUEST_11D_SCAN)) { + for (index = 0; index < src_req->ChannelInfo. + numOfChannels; index++) { + channel_state = + cds_get_channel_state(src_req-> + ChannelInfo. + ChannelList[index]); + if (src_req->ChannelInfo.ChannelList[index] < + MIN_11P_CHANNEL && + ((CHANNEL_STATE_ENABLE == + channel_state) || + ((CHANNEL_STATE_DFS == channel_state) && + !skip_dfs_chnl))) { + dst_req->ChannelInfo.ChannelList + [new_index] = + src_req-> + ChannelInfo. + ChannelList + [index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = new_index; + } else if (CDF_IS_STATUS_SUCCESS( + csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &len))) { + new_index = 0; + mac_ctx->roam.numValidChannels = len; + csr_scan_copy_request_valid_channels_only(mac_ctx, + dst_req, skip_dfs_chnl, + src_req); + } else { + sms_log(mac_ctx, LOGE, + FL("Couldn't get the valid Channel List, keeping requester's list")); + new_index = 0; + for (index = 0; index < src_req->ChannelInfo. + numOfChannels; index++) { + if (src_req->ChannelInfo.ChannelList[index] < + MIN_11P_CHANNEL) { + dst_req->ChannelInfo. + ChannelList[new_index] = + src_req->ChannelInfo. + ChannelList[index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = + new_index; + } + } /* Allocate memory for Channel List */ + if (src_req->SSIDs.numOfSSIDs == 0) { + dst_req->SSIDs.numOfSSIDs = 0; + dst_req->SSIDs.SSIDList = NULL; + } else { + dst_req->SSIDs.SSIDList = + cdf_mem_malloc(src_req->SSIDs.numOfSSIDs * + sizeof(*dst_req->SSIDs.SSIDList)); + if (NULL == dst_req->SSIDs.SSIDList) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + if (CDF_IS_STATUS_SUCCESS(status)) { + dst_req->SSIDs.numOfSSIDs = + src_req->SSIDs.numOfSSIDs; + cdf_mem_copy(dst_req->SSIDs.SSIDList, + src_req->SSIDs.SSIDList, + src_req->SSIDs.numOfSSIDs * + sizeof(*dst_req->SSIDs.SSIDList)); + } else { + dst_req->SSIDs.numOfSSIDs = 0; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning SSID List")); + goto complete; + } + } /* Allocate memory for SSID List */ + dst_req->p2pSearch = src_req->p2pSearch; + dst_req->skipDfsChnlInP2pSearch = + src_req->skipDfsChnlInP2pSearch; + dst_req->scan_id = src_req->scan_id; + dst_req->timestamp = src_req->timestamp; + +complete: + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_scan_free_request(mac_ctx, dst_req); + } + + return status; +} + +CDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq) +{ + + if (pReq->ChannelInfo.ChannelList) { + cdf_mem_free(pReq->ChannelInfo.ChannelList); + pReq->ChannelInfo.ChannelList = NULL; + } + pReq->ChannelInfo.numOfChannels = 0; + if (pReq->pIEField) { + cdf_mem_free(pReq->pIEField); + pReq->pIEField = NULL; + } + pReq->uIEFieldLen = 0; + if (pReq->SSIDs.SSIDList) { + cdf_mem_free(pReq->SSIDs.SSIDList); + pReq->SSIDs.SSIDList = NULL; + } + pReq->SSIDs.numOfSSIDs = 0; + + return CDF_STATUS_SUCCESS; +} + +void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus) +{ + if (pCommand->u.scanCmd.callback) { + pCommand->u.scanCmd.callback(pMac, pCommand->u.scanCmd.pContext, + pCommand->sessionId, + pCommand->u.scanCmd.scanID, + scanStatus); + } else { + sms_log(pMac, LOG2, "%s:%d - Callback NULL!!!", __func__, + __LINE__); + } +} + +void csr_scan_stop_timers(tpAniSirGlobal pMac) +{ + if (0 != pMac->scan.scanResultCfgAgingTime) { + csr_scan_stop_result_cfg_aging_timer(pMac); + } + +} + +#ifdef WLAN_AP_STA_CONCURRENCY +/** + * csr_sta_ap_conc_timer_handler - Function to handle STA,AP concurrency timer + * @pv: pointer variable + * + * Function handles STA,AP concurrency timer + * + * Return: none + */ +static void csr_sta_ap_conc_timer_handler(void *pv) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv); + tListElem *entry; + tSmeCmd *scan_cmd; + uint32_t session_id = CSR_SESSION_ID_INVALID; + tCsrScanRequest scan_req; + tSmeCmd *send_scancmd = NULL; + uint8_t num_chn = 0; + uint8_t numchan_combinedconc = 0; + uint8_t i, j; + tCsrChannelInfo *chn_info = NULL; + uint8_t channel_to_scan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + CDF_STATUS status; + + csr_ll_lock(&mac_ctx->scan.scanCmdPendingList); + + entry = csr_ll_peek_head(&mac_ctx->scan.scanCmdPendingList, + LL_ACCESS_NOLOCK); + + if (NULL == entry) { + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + + + chn_info = &scan_req.ChannelInfo; + scan_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + num_chn = + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + session_id = scan_cmd->sessionId; + + /* + * if any session is connected and the number of channels to scan is + * greater than 1 then split the scan into multiple scan operations + * on each individual channel else continue to perform scan on all + * specified channels */ + + /* + * split scan if number of channels to scan is greater than 1 and + * any one of the following: + * - STA session is connected and the scan is not a P2P search + * - any P2P session is connected + * Do not split scans if no concurrent infra connections are + * active and if the scan is a BG scan triggered by LFR (OR) + * any scan if LFR is in the middle of a BG scan. Splitting + * the scan is delaying the time it takes for LFR to find + * candidates and resulting in disconnects. + */ + + if ((csr_is_sta_session_connected(mac_ctx) && + !csr_is_p2p_session_connected(mac_ctx))) + numchan_combinedconc = + mac_ctx->roam.configParam.nNumStaChanCombinedConc; + else if (csr_is_p2p_session_connected(mac_ctx)) + numchan_combinedconc = + mac_ctx->roam.configParam.nNumP2PChanCombinedConc; + + if ((num_chn > numchan_combinedconc) && + ((csr_is_sta_session_connected(mac_ctx) && +#ifdef FEATURE_WLAN_LFR + (csr_is_concurrent_infra_connected(mac_ctx)) && +#endif + (scan_cmd->u.scanCmd.u.scanRequest.p2pSearch != 1)) || + (csr_is_p2p_session_connected(mac_ctx)))) { + cdf_mem_set(&scan_req, sizeof(tCsrScanRequest), 0); + + /* optimize this to use 2 command buffer only */ + send_scancmd = csr_get_command_buffer(mac_ctx); + if (!send_scancmd) { + sms_log(mac_ctx, LOGE, + FL(" Failed to get Queue command buffer")); + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + send_scancmd->command = scan_cmd->command; + send_scancmd->sessionId = scan_cmd->sessionId; + send_scancmd->u.scanCmd.callback = NULL; + send_scancmd->u.scanCmd.pContext = + scan_cmd->u.scanCmd.pContext; + send_scancmd->u.scanCmd.reason = + scan_cmd->u.scanCmd.reason; + /* let it wrap around */ + wma_get_scan_id(&send_scancmd->u.scanCmd.scanID); + + /* + * First copy all the parameters to local variable of scan + * request + */ + csr_scan_copy_request(mac_ctx, &scan_req, + &scan_cmd->u.scanCmd.u.scanRequest); + + /* + * Now modify the elements of local var scan request required + * to be modified for split scan + */ + if (scan_req.ChannelInfo.ChannelList != NULL) { + cdf_mem_free(scan_req.ChannelInfo.ChannelList); + scan_req.ChannelInfo.ChannelList = NULL; + } + + chn_info->numOfChannels = numchan_combinedconc; + cdf_mem_copy(&channel_to_scan[0], + &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo. + ChannelList[0], chn_info->numOfChannels + * sizeof(uint8_t)); + chn_info->ChannelList = &channel_to_scan[0]; + + for (i = 0, j = numchan_combinedconc; + i < (num_chn - numchan_combinedconc); + i++, j++) { + /* Move all the channels one step */ + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo. + ChannelList[i] = + scan_cmd->u.scanCmd.u.scanRequest. + ChannelInfo.ChannelList[j]; + } + + /* reduce outstanding # of channels to be scanned */ + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = + num_chn - numchan_combinedconc; + + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + /* Modify callers parameters in case of concurrency */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + /* Use concurrency values for min/maxChnTime. */ + csr_set_default_scan_timing(mac_ctx, scan_req.scanType, + &scan_req); + + status = csr_scan_copy_request(mac_ctx, + &send_scancmd->u.scanCmd.u. + scanRequest, &scan_req); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" Failed to get copy csr_scan_request = %d"), + status); + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + /* Clean the local scan variable */ + scan_req.ChannelInfo.ChannelList = NULL; + scan_req.ChannelInfo.numOfChannels = 0; + csr_scan_free_request(mac_ctx, &scan_req); + } else { + /* + * no active connected session present or numChn == 1 + * scan all remaining channels + */ + send_scancmd = scan_cmd; + /* remove this command from pending list */ + if (csr_ll_remove_head(&mac_ctx->scan.scanCmdPendingList, + /* + * In case between PeekHead and here, the entry + * got removed by another thread. + */ + LL_ACCESS_NOLOCK) == NULL) { + sms_log(mac_ctx, LOGE, + FL(" Failed to remove entry from scanCmdPendingList")); + } + + } + csr_queue_sme_command(mac_ctx, send_scancmd, false); + + + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + +} +#endif + +CDF_STATUS csr_scan_start_result_cfg_aging_timer(tpAniSirGlobal pMac) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (pMac->scan.fScanEnable) { + status = + cdf_mc_timer_start(&pMac->scan.hTimerResultCfgAging, + CSR_SCAN_RESULT_CFG_AGING_INTERVAL / + CDF_MC_TIMER_TO_MS_UNIT); + } + return status; +} + +CDF_STATUS csr_scan_stop_result_cfg_aging_timer(tpAniSirGlobal pMac) +{ + return cdf_mc_timer_stop(&pMac->scan.hTimerResultCfgAging); +} + +/** + * csr_scan_result_cfg_aging_timer_handler() - Time based scan aging handler + * @pv: Global context + * + * This routine is to handle scan aging based on user configured timer value. + * + * Return: None + */ +static void csr_scan_result_cfg_aging_timer_handler(void *pv) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv); + tListElem *entry, *tmp_entry; + tCsrScanResult *result; + uint32_t ageout_time = + mac_ctx->scan.scanResultCfgAgingTime * CDF_TICKS_PER_SECOND/10; + uint32_t cur_time = (uint32_t) cdf_mc_timer_get_system_ticks(); + uint8_t *bssId; + + csr_ll_lock(&mac_ctx->scan.scanResultList); + entry = csr_ll_peek_head(&mac_ctx->scan.scanResultList, LL_ACCESS_NOLOCK); + while (entry) { + tmp_entry = csr_ll_next(&mac_ctx->scan.scanResultList, entry, + LL_ACCESS_NOLOCK); + result = GET_BASE_ADDR(entry, tCsrScanResult, Link); + /* + * cdf_mc_timer_get_system_ticks() returns in 10ms interval. + * so ageout time value also updated to 10ms interval value. + */ + if ((cur_time - result->Result.BssDescriptor.nReceivedTime) > + ageout_time) { + bssId = result->Result.BssDescriptor.bssId; + sms_log(mac_ctx, LOGW, + FL("age out due to time out"MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(bssId)); + csr_scan_age_out_bss(mac_ctx, result); + } + entry = tmp_entry; + } + csr_ll_unlock(&mac_ctx->scan.scanResultList); + cdf_mc_timer_start(&mac_ctx->scan.hTimerResultCfgAging, + CSR_SCAN_RESULT_CFG_AGING_INTERVAL / + CDF_MC_TIMER_TO_MS_UNIT); +} + +bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId) +{ + bool fRet = false; + tListElem *pEntry, *pEntryTmp; + tSmeCmd *pCommand; + tDblLinkList localList; + tDblLinkList *pCmdList; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return fRet; + } + + pCmdList = &pMac->sme.smeScanCmdPendingList; + + csr_ll_lock(pCmdList); + pEntry = csr_ll_peek_head(pCmdList, LL_ACCESS_NOLOCK); + while (pEntry) { + pEntryTmp = csr_ll_next(pCmdList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (!((eSmeCommandScan == pCommand->command) + && (sessionId == pCommand->sessionId))) { + pEntry = pEntryTmp; + continue; + } + sms_log(pMac, LOGW, + FL("-------- abort scan command reason = %d"), + pCommand->u.scanCmd.reason); + /* The rest are fresh scan requests */ + if (csr_ll_remove_entry(pCmdList, pEntry, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + fRet = true; + pEntry = pEntryTmp; + } + + csr_ll_unlock(pCmdList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->u.scanCmd.callback) { + /* + * User scan request is pending, send response with + * status eCSR_SCAN_ABORT + */ + pCommand->u.scanCmd.callback(pMac, + pCommand->u.scanCmd.pContext, sessionId, + pCommand->u.scanCmd.scanID, eCSR_SCAN_ABORT); + } + csr_release_command_scan(pMac, pCommand); + } + csr_ll_close(&localList); + + return fRet; +} + +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus) +{ + eCsrScanReason reason = pCommand->u.scanCmd.reason; + bool status; + tDblLinkList *cmd_list = NULL; + + csr_scan_call_callback(pMac, pCommand, scanStatus); + sms_log(pMac, LOG1, FL("Remove Scan command reason = %d, scan_id %d"), + reason, pCommand->u.scanCmd.scanID); + cmd_list = &pMac->sme.smeScanCmdActiveList; + status = csr_ll_remove_entry(cmd_list, &pCommand->Link, LL_ACCESS_LOCK); + if (!status) { + sms_log(pMac, LOGE, + FL("cannot release command reason %d scan_id %d"), + pCommand->u.scanCmd.reason, + pCommand->u.scanCmd.scanID); + return; + } + csr_release_command_scan(pMac, pCommand); +} + +CDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrScanResultFilter *pScanFilter; + tCsrScanResultInfo *pScanResult; + tScanResultHandle hBSSList; + uint32_t nItems = *pNumItems; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("pMac->scan.NumPmkidCandidate = %d"), + pSession->NumPmkidCandidate); + csr_reset_pmkid_candidate_list(pMac, sessionId); + if (!(csr_is_conn_state_connected(pMac, sessionId) + && pSession->pCurRoamProfile)) + return status; + + *pNumItems = 0; + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pSession->pCurRoamProfile, pScanFilter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pScanFilter); + return status; + } + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return status; + } + + if (pSession->NumPmkidCandidate < nItems) { + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + while (pScanResult != NULL) { + /* NumPmkidCandidate adds up here */ + csr_process_bss_desc_for_pmkid_list(pMac, + &pScanResult->BssDescriptor, + (tDot11fBeaconIEs *)(pScanResult->pvIes), + sessionId); + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + } + } + + if (pSession->NumPmkidCandidate) { + *pNumItems = pSession->NumPmkidCandidate; + cdf_mem_copy(pPmkidList, pSession->PmkidCandidateInfo, + pSession->NumPmkidCandidate * + sizeof(tPmkidCandidateInfo)); + } + + csr_scan_result_purge(pMac, hBSSList); + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return status; +} + +#ifdef FEATURE_WLAN_WAPI +CDF_STATUS csr_scan_get_bkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tBkidCandidateInfo *pBkidList, + uint32_t *pNumItems) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrScanResultFilter *pScanFilter; + tCsrScanResultInfo *pScanResult; + tScanResultHandle hBSSList; + uint32_t nItems = *pNumItems; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("pMac->scan.NumBkidCandidate = %d"), + pSession->NumBkidCandidate); + csr_reset_bkid_candidate_list(pMac, sessionId); + if (!(csr_is_conn_state_connected(pMac, sessionId) + && pSession->pCurRoamProfile)) + return status; + + *pNumItems = 0; + pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return CDF_STATUS_E_NOMEM; + + cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0); + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pSession->pCurRoamProfile, pScanFilter); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(pScanFilter); + return status; + } + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!CDF_IS_STATUS_SUCCESS(status)) { + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return status; + } + + if (pSession->NumBkidCandidate < nItems) { + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + while (pScanResult != NULL) { + /* pMac->scan.NumBkidCandidate adds up here */ + csr_process_bss_desc_for_bkid_list(pMac, + &pScanResult->BssDescriptor, + (tDot11fBeaconIEs *)(pScanResult->pvIes)); + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + } + } + + if (pSession->NumBkidCandidate) { + *pNumItems = pSession->NumBkidCandidate; + cdf_mem_copy(pBkidList, pSession->BkidCandidateInfo, + pSession->NumBkidCandidate * + sizeof(tBkidCandidateInfo)); + } + + csr_scan_result_purge(pMac, hBSSList); + csr_free_scan_filter(pMac, pScanFilter); + cdf_mem_free(pScanFilter); + return status; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_roam_copy_channellist() - Function to copy channel list + * @mac_ctx: pointer to Global Mac structure + * @profile: pointer to tCsrRoamProfile + * @scan_cmd: pointer to tSmeCmd + * @index: index for channellist + * + * Function copies channel list + * + * Return: none + */ +static void csr_roam_copy_channellist(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tSmeCmd *scan_cmd, uint8_t index) +{ + tCsrChannelInfo *channel_info = + &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + for (index = 0; index < profile->ChannelInfo.numOfChannels; + index++) { + if (!csr_roam_is_valid_channel(mac_ctx, + profile->ChannelInfo.ChannelList[index])) { + sms_log(mac_ctx, LOGW, + FL("process a channel (%d) that is invalid"), + profile->ChannelInfo.ChannelList[index]); + continue; + } + channel_info->ChannelList[channel_info->numOfChannels] = + profile->ChannelInfo.ChannelList[index]; + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels++; + } +} + +/** + * csr_scan_for_ssid() - Function usually used for BSSs that suppresses SSID + * @mac_ctx: Pointer to Global Mac structure + * @profile: pointer to tCsrRoamProfile + * @roam_id: variable representing roam id + * @notify: boolean variable + * + * Function is usually used for BSSs that suppresses SSID so the profile + * shall have one and only one SSID. + * + * Return: Success - CDF_STATUS_SUCCESS, Failure - error number + */ +CDF_STATUS csr_scan_for_ssid(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile, uint32_t roam_id, + bool notify) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + tSmeCmd *scan_cmd = NULL; + tCsrScanRequest *scan_req = NULL; + uint8_t index = 0; + uint32_t num_ssid = profile->SSIDs.numOfSSIDs; + tpCsrNeighborRoamControlInfo neighbor_roaminfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrSSIDs *ssids = NULL; + + sms_log(mac_ctx, LOG2, FL("called")); + + /* For WDS, we use the index 0. There must be at least one in there */ + if (CSR_IS_WDS_STA(profile) && num_ssid) + num_ssid = 1; + + if (!(mac_ctx->scan.fScanEnable) && (num_ssid != 1)) { + sms_log(mac_ctx, LOGE, + FL("cannot scan because scanEnable (%d) or numSSID (%d) is invalid"), + mac_ctx->scan.fScanEnable, profile->SSIDs.numOfSSIDs); + return status; + } + + scan_cmd = csr_get_command_buffer(mac_ctx); + + if (!scan_cmd) { + sms_log(mac_ctx, LOGE, + FL("failed to allocate command buffer")); + goto error; + } + + cdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0); + scan_cmd->u.scanCmd.pToRoamProfile = + cdf_mem_malloc(sizeof(tCsrRoamProfile)); + + if (NULL == scan_cmd->u.scanCmd.pToRoamProfile) + status = CDF_STATUS_E_NOMEM; + else + status = csr_roam_copy_profile(mac_ctx, + scan_cmd->u.scanCmd.pToRoamProfile, + profile); + + if (!CDF_IS_STATUS_SUCCESS(status)) + goto error; + + scan_cmd->u.scanCmd.roamId = roam_id; + scan_cmd->command = eSmeCommandScan; + scan_cmd->sessionId = (uint8_t) session_id; + scan_cmd->u.scanCmd.callback = NULL; + scan_cmd->u.scanCmd.pContext = NULL; + scan_cmd->u.scanCmd.reason = eCsrScanForSsid; + + /* let it wrap around */ + wma_get_scan_id(&scan_cmd->u.scanCmd.scanID); + cdf_mem_set(&scan_cmd->u.scanCmd.u.scanRequest, + sizeof(tCsrScanRequest), 0); + status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + CDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, &scan_cmd); + scan_req = &scan_cmd->u.scanCmd.u.scanRequest; + scan_req->scanType = eSIR_ACTIVE_SCAN; + scan_req->BSSType = profile->BSSType; + scan_req->scan_id = scan_cmd->u.scanCmd.scanID; + /* + * To avoid 11b rate in probe request Set p2pSearch + * flag as 1 for P2P Client Mode + */ + if (CDF_P2P_CLIENT_MODE == profile->csrPersona) + scan_req->p2pSearch = 1; + + /* Allocate memory for IE field */ + if (profile->pAddIEScan) { + scan_req->pIEField = + cdf_mem_malloc(profile->nAddIEScanLength); + + if (NULL == scan_req->pIEField) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + cdf_mem_set(scan_req->pIEField, + profile->nAddIEScanLength, 0); + + if (CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_copy(scan_req->pIEField, + profile->pAddIEScan, + profile->nAddIEScanLength); + scan_req->uIEFieldLen = profile->nAddIEScanLength; + } else { + sms_log(mac_ctx, LOGE, + "No memory for scanning IE fields"); + } + } else + scan_req->uIEFieldLen = 0; + + /* + * For one channel be good enpugh time to receive beacon + * atleast + */ + if (1 == profile->ChannelInfo.numOfChannels) { + if (neighbor_roaminfo->handoffReqInfo.src == + FASTREASSOC) { + scan_req->maxChnTime = + MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + scan_req->minChnTime = + MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + /* Reset this value */ + neighbor_roaminfo->handoffReqInfo.src = 0; + } else { + scan_req->maxChnTime = + MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL; + scan_req->minChnTime = + MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL; + } + } else { + scan_req->maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + scan_req->minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + } + + if (profile->BSSIDs.numOfBSSIDs == 1) + cdf_copy_macaddr(&scan_req->bssid, + profile->BSSIDs.bssid); + else + cdf_set_macaddr_broadcast(&scan_req->bssid); + + if (profile->ChannelInfo.numOfChannels) { + scan_req->ChannelInfo.ChannelList = + cdf_mem_malloc(sizeof(*scan_req->ChannelInfo.ChannelList) * + profile->ChannelInfo.numOfChannels); + + if (NULL == scan_req->ChannelInfo.ChannelList) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + scan_req->ChannelInfo.numOfChannels = 0; + + if (CDF_IS_STATUS_SUCCESS(status)) { + csr_roam_is_channel_valid(mac_ctx, + profile->ChannelInfo.ChannelList[0]); + csr_roam_copy_channellist(mac_ctx, + profile, scan_cmd, index); + } else { + goto error; + } + } else { + scan_req->ChannelInfo.numOfChannels = 0; + } + + if (profile->SSIDs.numOfSSIDs) { + scan_req->SSIDs.SSIDList = + cdf_mem_malloc(profile->SSIDs.numOfSSIDs * + sizeof(tCsrSSIDInfo)); + + if (NULL == scan_req->SSIDs.SSIDList) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + if (!CDF_IS_STATUS_SUCCESS(status)) + goto error; + + ssids = &scan_req->SSIDs; + ssids->numOfSSIDs = 1; + + cdf_mem_copy(scan_req->SSIDs.SSIDList, + profile->SSIDs.SSIDList, + sizeof(tCsrSSIDInfo)); + } + + /* Start process the command */ + status = csr_queue_sme_command(mac_ctx, scan_cmd, false); +error: + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" failed to iniate scan with status = %d"), status); + if (scan_cmd) + csr_release_command_scan(mac_ctx, scan_cmd); + if (notify) + csr_roam_call_callback(mac_ctx, session_id, NULL, + roam_id, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList, + uint8_t NumChannels) +{ + uint32_t dataLen = sizeof(uint8_t) * NumChannels; + CDF_STATUS status; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: dump valid channel list(NumChannels(%d))", + __func__, NumChannels); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + pChannelList, NumChannels); + cfg_set_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, pChannelList, + dataLen); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "Scan offload is enabled, update default chan list"); + /* + * disable fcc constraint since new country code + * is being set + */ + pMac->scan.fcc_constraint = false; + status = csr_update_channel_list(pMac); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "failed to update the supported channel list"); + } + return; +} + +/* + * The Tx power limits are saved in the cfg for future usage. + */ +void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId) +{ + tListElem *pEntry; + uint32_t cbLen = 0, dataLen, tmp_len; + tCsrChannelPowerInfo *ch_set; + uint32_t idx; + tSirMacChanInfo *ch_pwr_set; + uint8_t *pBuf = NULL; + + /* allocate maximum space for all channels */ + dataLen = WNI_CFG_VALID_CHANNEL_LIST_LEN * sizeof(tSirMacChanInfo); + pBuf = cdf_mem_malloc(dataLen); + if (pBuf == NULL) + return; + + cdf_mem_set(pBuf, dataLen, 0); + ch_pwr_set = (tSirMacChanInfo *) (pBuf); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK); + /* + * write the tuples (startChan, numChan, txPower) for each channel found + * in the channel power list. + */ + while (pEntry) { + ch_set = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link); + if (1 != ch_set->interChannelOffset) { + /* + * we keep the 5G channel sets internally with an + * interchannel offset of 4. Expand these to the right + * format. (inter channel offset of 1 is the only option + * for the triplets that 11d advertises. + */ + tmp_len = cbLen + (ch_set->numChannels * + sizeof(tSirMacChanInfo)); + if (tmp_len >= dataLen) { + /* + * expanding this entry will overflow our + * allocation + */ + sms_log(pMac, LOGE, + FL("Buffer overflow, start %d, num %d, offset %d"), + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + + for (idx = 0; idx < ch_set->numChannels; idx++) { + ch_pwr_set->firstChanNum = (tSirMacChanNum) + (ch_set->firstChannel + (idx * + ch_set->interChannelOffset)); + sms_log(pMac, LOG3, + FL("Setting Channel Number %d"), + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = 1; + ch_pwr_set->maxTxPower = + CDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sms_log(pMac, LOG3, + FL("Setting Max Transmit Power %d"), + ch_pwr_set->maxTxPower); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + } else { + if (cbLen >= dataLen) { + /* this entry will overflow our allocation */ + sms_log(pMac, LOGE, + FL("Buffer overflow, start %d, num %d, offset %d"), + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + ch_pwr_set->firstChanNum = ch_set->firstChannel; + sms_log(pMac, LOG3, FL("Setting Channel Number %d"), + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = ch_set->numChannels; + ch_pwr_set->maxTxPower = CDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sms_log(pMac, LOG3, + FL("Setting Max Tx Power %d, nTxPower %d"), + ch_pwr_set->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_LOCK); + } + if (cbLen) + cfg_set_str(pMac, cfgId, (uint8_t *) pBuf, cbLen); + + cdf_mem_free(pBuf); +} + +void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode) +{ + uint8_t cc[WNI_CFG_COUNTRY_CODE_LEN]; + /* v_REGDOMAIN_t DomainId */ + + sms_log(pMac, LOG3, FL("Setting Country Code in Cfg %s"), countryCode); + cdf_mem_copy(cc, countryCode, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * don't program the bogus country codes that we created for Korea in the + * MAC. if we see the bogus country codes, program the MAC with the right + * country code. + */ + if (('K' == countryCode[0] && '1' == countryCode[1]) || + ('K' == countryCode[0] && '2' == countryCode[1]) || + ('K' == countryCode[0] && '3' == countryCode[1]) || + ('K' == countryCode[0] && '4' == countryCode[1])) { + /* + * replace the alternate Korea country codes, 'K1', 'K2', .. + * with 'KR' for Korea + */ + cc[1] = 'R'; + } + cfg_set_str(pMac, WNI_CFG_COUNTRY_CODE, cc, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * Need to let HALPHY know about the current domain so it can apply some + * domain-specific settings (TX filter...) + */ + /* + if(CDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country( + pMac, cc, &DomainId))) { + halPhySetRegDomain(pMac, DomainId); + } */ +} + +CDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + uint32_t len; + + if (pBuf && pbLen && (*pbLen >= WNI_CFG_COUNTRY_CODE_LEN)) { + len = *pbLen; + status = wlan_cfg_get_str(pMac, WNI_CFG_COUNTRY_CODE, pBuf, &len); + if (CDF_IS_STATUS_SUCCESS(status)) { + *pbLen = (uint8_t) len; + } + } + + return status; +} + +void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode, + tCsrChannel *pChannelList) +{ + uint8_t i, j; + bool found = false; + uint8_t *pControlList = NULL; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + + pControlList = cdf_mem_malloc(WNI_CFG_SCAN_CONTROL_LIST_LEN); + if (pControlList != NULL) { + cdf_mem_set((void *)pControlList, WNI_CFG_SCAN_CONTROL_LIST_LEN, + 0); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac, + WNI_CFG_SCAN_CONTROL_LIST, + pControlList, &len))) { + for (i = 0; i < pChannelList->numChannels; i++) { + for (j = 0; j < len; j += 2) { + if (pControlList[j] == + pChannelList->channelList[i]) { + found = true; + break; + } + } + + if (found) { + /* insert a pair(channel#, flag) */ + pControlList[j + 1] = + csr_get_scan_type(pMac, + pControlList[j]); + found = false; /* reset the flag */ + } + + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: dump scan control list", __func__); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, pControlList, + len); + + cfg_set_str(pMac, WNI_CFG_SCAN_CONTROL_LIST, + pControlList, len); + } /* Successfully getting scan control list */ + cdf_mem_free(pControlList); + } /* AllocateMemory */ +} + +CDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId, + eCsrAbortReason reason) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + pMac->scan.fDropScanCmd = true; + csr_remove_cmd_with_session_id_from_pending_list(pMac, + sessionId, &pMac->sme.smeScanCmdPendingList, + eSmeCommandScan); + pMac->scan.fDropScanCmd = false; + csr_abort_scan_from_active_list(pMac, + &pMac->sme.smeScanCmdActiveList, sessionId, + eSmeCommandScan, reason); + + return status; +} + +void csr_remove_cmd_with_session_id_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, + tDblLinkList *pList, + eSmeCommandType commandType) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL("failed to open list")); + return; + } + + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + if (pEntry) { + /* + * Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list + */ + while (pEntry) { + pEntryToRemove = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + + if (!((pCommand->command == commandType) && + (pCommand->sessionId == sessionId))) + continue; + /* Remove that entry only */ + if (csr_ll_remove_entry(pList, pEntryToRemove, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + } + } + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sms_log(pMac, LOG1, FL("Sending abort for scan command ID %d"), + pCommand->u.scanCmd.scanID); + csr_abort_command(pMac, pCommand, false); + } + + csr_ll_close(&localList); +} + +void csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac, + tDblLinkList *pList, + eSmeCommandType commandType) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + + csr_ll_lock(pList); + if (!csr_ll_is_list_empty(pList, LL_ACCESS_NOLOCK)) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + /* + * Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list... + */ + while (pEntry) { + pEntryToRemove = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + /* Remove that entry only that matches cmd type */ + if (pCommand->command == commandType && + csr_ll_remove_entry(pList, pEntryToRemove, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + } + } + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + csr_abort_command(pMac, pCommand, false); + } + csr_ll_close(&localList); + +} + +CDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + pMac->scan.fDropScanCmd = true; + csr_remove_scan_for_ssid_from_pending_list(pMac, + &pMac->sme.smeScanCmdPendingList, sessionId); + pMac->scan.fDropScanCmd = false; + csr_abort_scan_from_active_list(pMac, &pMac->sme.smeScanCmdActiveList, + sessionId, eSmeCommandScan, eCSR_SCAN_ABORT_SSID_ONLY); + return status; +} + +void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac, + tDblLinkList *pList, + uint32_t sessionId) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + + cdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(pList); + if (!csr_ll_is_list_empty(pList, LL_ACCESS_NOLOCK)) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + /* + * Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list... + */ + while (pEntry) { + pEntryToRemove = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + + if (!((eSmeCommandScan == pCommand->command) && + (sessionId == pCommand->sessionId))) + continue; + if (eCsrScanForSsid != pCommand->u.scanCmd.reason) + continue; + /* Remove that entry only */ + if (csr_ll_remove_entry(pList, pEntryToRemove, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + } + } + } + csr_ll_unlock(pList); + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + csr_abort_command(pMac, pCommand, false); + } + csr_ll_close(&localList); +} + + +/** + * csr_send_scan_abort() - Sends scan abort command to firmware + * @mac_ctx: Pointer to Global Mac structure + * @session_id: CSR session identification + * @scan_id: scan identifier + * + * .Sends scan abort command to firmware + * + * Return: None + */ +static void csr_send_scan_abort(tpAniSirGlobal mac_ctx, + uint32_t session_id, uint32_t scan_id) +{ + tSirSmeScanAbortReq *msg; + uint16_t msg_len; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq)); + msg = cdf_mem_malloc(msg_len); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Failed to alloc memory for SmeScanAbortReq")); + return; + } + cdf_mem_zero((void *)msg, msg_len); + msg->type = eWNI_SME_SCAN_ABORT_IND; + msg->msgLen = msg_len; + msg->sessionId = session_id; + msg->scan_id = scan_id; + sms_log(mac_ctx, LOG2, + FL("Abort scan sent to Firmware scan_id %d session %d"), + scan_id, session_id); + status = cds_send_mb_message_to_mac(msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(msg); + sms_log(mac_ctx, LOGE, + FL("Failed to send abort scan.scan_id %d session %d"), + scan_id, session_id); + } + return; +} + +/** + * csr_abort_scan_from_active_list() - Remove Scan command from active list + * @mac_ctx: Pointer to Global Mac structure + * @list: pointer to scan active list + * @session_id: CSR session identification + * @scan_cmd_type: scan command type + * @abort_reason: abort reason + * + * .Remove Scan command from active scan list + * + * Return: Success - CDF_STATUS_SUCCESS, Failure - error number + */ +CDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal mac_ctx, + tDblLinkList *list, uint32_t session_id, + eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason) +{ + tListElem *entry; + tSmeCmd *cmd; + tListElem *entry_remove; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + csr_ll_lock(list); + if (!csr_ll_is_list_empty(list, LL_ACCESS_NOLOCK)) { + entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK); + while (entry) { + entry_remove = entry; + entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + cmd = GET_BASE_ADDR(entry_remove, tSmeCmd, Link); + + /* Skip if command and session id not matched */ + if (!((scan_cmd_type == cmd->command) && + (session_id == cmd->sessionId))) + continue; + /*skip if abort reason is for SSID*/ + if ((abort_reason == eCSR_SCAN_ABORT_SSID_ONLY) && + (eCsrScanForSsid != cmd->u.scanCmd.reason)) + continue; + if (abort_reason == eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE) + cmd->u.scanCmd.abortScanDueToBandChange = + true; + csr_send_scan_abort(mac_ctx, cmd->sessionId, + cmd->u.scanCmd.scanID); + } + } + csr_ll_unlock(list); + + return status; +} + + +CDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + if (!csr_is_scan_for_roam_command_active(pMac)) { + /* + * Only abort the scan if it is not used for other roam/connect + * purpose + */ + status = csr_scan_abort_mac_scan(pMac, sessionId, + eCSR_SCAN_ABORT_DEFAULT); + } + return status; +} +bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idx_valid_ch; + uint32_t len = pMac->roam.numValidChannels; + + for (idx_valid_ch = 0; (idx_valid_ch < len); idx_valid_ch++) { + if (channel == pMac->roam.validChannelList[idx_valid_ch]) { + fValid = true; + break; + } + } + return fValid; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +CDF_STATUS csr_scan_save_preferred_network_found(tpAniSirGlobal pMac, + tSirPrefNetworkFoundInd * + pPrefNetworkFoundInd) +{ + uint32_t uLen = 0; + tpSirProbeRespBeacon parsed_frm; + tCsrScanResult *pScanResult = NULL; + tSirBssDescription *pBssDescr = NULL; + bool fDupBss; + tDot11fBeaconIEs *local_ie = NULL; + tAniSSID tmpSsid; + v_TIME_t timer = 0; + CDF_STATUS status; + + tpSirMacMgmtHdr macHeader = + (tpSirMacMgmtHdr) pPrefNetworkFoundInd->data; + parsed_frm = + (tpSirProbeRespBeacon) cdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + + if (NULL == parsed_frm) { + sms_log(pMac, LOGE, FL("fail to allocate memory for frame")); + return CDF_STATUS_E_NOMEM; + } + if (pPrefNetworkFoundInd->frameLength <= SIR_MAC_HDR_LEN_3A) { + sms_log(pMac, LOGE, + FL("Incorrect len(%d)"), + pPrefNetworkFoundInd->frameLength); + cdf_mem_free(parsed_frm); + return CDF_STATUS_E_FAILURE; + } + if (sir_convert_probe_frame2_struct(pMac, + &pPrefNetworkFoundInd->data[SIR_MAC_HDR_LEN_3A], + pPrefNetworkFoundInd->frameLength - SIR_MAC_HDR_LEN_3A, + parsed_frm) != eSIR_SUCCESS + || !parsed_frm->ssidPresent) { + sms_log(pMac, LOGE, FL("Parse error ProbeResponse, length=%d"), + pPrefNetworkFoundInd->frameLength); + cdf_mem_free(parsed_frm); + return CDF_STATUS_E_FAILURE; + } + /* 24 byte MAC header and 12 byte to ssid IE */ + if (pPrefNetworkFoundInd->frameLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + uLen = pPrefNetworkFoundInd->frameLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } + pScanResult = cdf_mem_malloc(sizeof(tCsrScanResult) + uLen); + if (NULL == pScanResult) { + sms_log(pMac, LOGE, FL("fail to allocate memory for frame")); + cdf_mem_free(parsed_frm); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set(pScanResult, sizeof(tCsrScanResult) + uLen, 0); + pBssDescr = &pScanResult->Result.BssDescriptor; + /* + * Length of BSS desription is without length of length itself and + * length of pointer that holds the next BSS description + */ + pBssDescr->length = (uint16_t) (sizeof(tSirBssDescription) - + sizeof(uint16_t) - sizeof(uint32_t) + uLen); + if (parsed_frm->dsParamsPresent) + pBssDescr->channelId = parsed_frm->channelNumber; + else if (parsed_frm->HTInfo.present) + pBssDescr->channelId = parsed_frm->HTInfo.primaryChannel; + else + pBssDescr->channelId = parsed_frm->channelNumber; + + if ((pBssDescr->channelId > 0) && (pBssDescr->channelId < 15)) { + int i; + /* 11b or 11g packet */ + /* 11g iff extended Rate IE is present or */ + /* if there is an A rate in suppRate IE */ + for (i = 0; i < parsed_frm->supportedRates.numRates; i++) { + if (sirIsArate(parsed_frm->supportedRates.rate[i] + & 0x7f)) { + pBssDescr->nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (parsed_frm->extendedRatesPresent) + pBssDescr->nwType = eSIR_11G_NW_TYPE; + } else { + /* 11a packet */ + pBssDescr->nwType = eSIR_11A_NW_TYPE; + } + pBssDescr->sinr = 0; + pBssDescr->rssi = -1 * pPrefNetworkFoundInd->rssi; + pBssDescr->beaconInterval = parsed_frm->beaconInterval; + if (!pBssDescr->beaconInterval) { + sms_log(pMac, LOGW, FL("Bcn Interval is Zero , default to 100" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBssDescr->bssId)); + pBssDescr->beaconInterval = 100; + } + pBssDescr->timeStamp[0] = parsed_frm->timeStamp[0]; + pBssDescr->timeStamp[1] = parsed_frm->timeStamp[1]; + pBssDescr->capabilityInfo = *((uint16_t *)&parsed_frm->capabilityInfo); + cdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) macHeader->bssId, sizeof(tSirMacAddr)); + pBssDescr->nReceivedTime = (uint32_t) cdf_mc_timer_get_system_ticks(); + sms_log(pMac, LOG2, FL("Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = %d"), + MAC_ADDR_ARRAY(pBssDescr->bssId), pBssDescr->channelId, + pBssDescr->rssi); + /* IEs */ + if (uLen) { + cdf_mem_copy(&pBssDescr->ieFields, + pPrefNetworkFoundInd->data + (SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET), uLen); + } + local_ie = (tDot11fBeaconIEs *) (pScanResult->Result.pvIes); + status = csr_get_parsed_bss_description_ies(pMac, + &pScanResult->Result.BssDescriptor, &local_ie); + if (!(local_ie || CDF_IS_STATUS_SUCCESS(status))) { + sms_log(pMac, LOGE, FL("Cannot parse IEs")); + csr_free_scan_result_entry(pMac, pScanResult); + cdf_mem_free(parsed_frm); + return CDF_STATUS_E_RESOURCES; + } + + fDupBss = csr_remove_dup_bss_description(pMac, + &pScanResult->Result.BssDescriptor, + local_ie, &tmpSsid, &timer, false); + /* Check whether we have reach out limit */ + if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) { + /* Limit reach */ + sms_log(pMac, LOGE, FL("BSS limit reached")); + /* Free the resources */ + if ((pScanResult->Result.pvIes == NULL) && local_ie) + cdf_mem_free(local_ie); + csr_free_scan_result_entry(pMac, pScanResult); + cdf_mem_free(parsed_frm); + return CDF_STATUS_E_RESOURCES; + } + /* Add to scan cache */ + csr_scan_add_result(pMac, pScanResult, local_ie, + pPrefNetworkFoundInd->sessionId); + + if ((pScanResult->Result.pvIes == NULL) && local_ie) + cdf_mem_free(local_ie); + cdf_mem_free(parsed_frm); + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef FEATURE_WLAN_LFR +void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tListElem *pEntry = NULL; + tCsrScanResult *pBssDesc = NULL; + tDot11fBeaconIEs *pIes = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (0 != pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) { + /* + * Ini file contains neighbor scan channel list, hence NO need + * to build occupied channel list" + */ + sms_log(pMac, LOG1, FL("Ini contains neighbor scan ch list")); + return; + } + + if (!csr_neighbor_roam_is_new_connected_profile(pMac, sessionId)) { + /* + * Do not flush occupied list since current roam profile matches + * previous + */ + sms_log(pMac, LOG2, FL("Current roam profile matches prev")); + return; + } + + /* Empty occupied channels here */ + pMac->scan.occupiedChannels[sessionId].numChannels = 0; + + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes); + /* At this time, pBssDescription->Result.pvIes may be NULL */ + if (!pIes && !CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, + &pBssDesc->Result.BssDescriptor, &pIes))) + continue; + csr_scan_add_to_occupied_channels(pMac, pBssDesc, sessionId, + &pMac->scan.occupiedChannels[sessionId], pIes); + /* + * Free the memory allocated for pIes in + * csr_get_parsed_bss_description_ies + */ + if ((pBssDesc->Result.pvIes == NULL) && pIes) + cdf_mem_free(pIes); + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); +} +#endif + +CDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct cdf_mac_addr bssid, + uint8_t channel) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pNewIes = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription *pNewBssDescriptor = NULL; + uint32_t size = 0; + + if (NULL == pSession) { + status = CDF_STATUS_E_FAILURE; + return status; + } + sms_log(pMac, LOG2, FL("Current bssid::"MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSession->pConnectBssDesc->bssId)); + sms_log(pMac, LOG2, FL("My bssid::"MAC_ADDRESS_STR" channel %d"), + MAC_ADDR_ARRAY(bssid.bytes), channel); + + if (!CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies( + pMac, pSession->pConnectBssDesc, + &pNewIes))) { + sms_log(pMac, LOGE, FL("Failed to parse IEs")); + status = CDF_STATUS_E_FAILURE; + goto free_mem; + } + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (!size) { + sms_log(pMac, LOGE, FL("length of bss descriptor is 0")); + status = CDF_STATUS_E_FAILURE; + goto free_mem; + } + pNewBssDescriptor = cdf_mem_malloc(size); + if (NULL == pNewBssDescriptor) { + sms_log(pMac, LOGE, FL("memory allocation failed")); + status = CDF_STATUS_E_FAILURE; + goto free_mem; + } + cdf_mem_copy(pNewBssDescriptor, pSession->pConnectBssDesc, size); + /* change the BSSID & channel as passed */ + cdf_mem_copy(pNewBssDescriptor->bssId, bssid.bytes, + sizeof(tSirMacAddr)); + pNewBssDescriptor->channelId = channel; + if (NULL == csr_scan_append_bss_description(pMac, pNewBssDescriptor, + pNewIes, true, sessionId)) { + sms_log(pMac, LOGE, + FL("csr_scan_append_bss_description failed")); + status = CDF_STATUS_E_FAILURE; + goto free_mem; + } + sms_log(pMac, LOGE, FL("entry successfully added in scan cache")); + +free_mem: + if (pNewIes) { + cdf_mem_free(pNewIes); + } + if (pNewBssDescriptor) { + cdf_mem_free(pNewBssDescriptor); + } + return status; +} + +#ifdef FEATURE_WLAN_ESE +/* Update the TSF with the difference in system time */ +void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1, + uint32_t *incr) +{ + uint64_t timeStamp64 = ((uint64_t) *timeStamp1 << 32) | (*timeStamp0); + timeStamp64 = (uint64_t) (timeStamp64 + (uint64_t) *incr); + *timeStamp0 = (uint32_t) (timeStamp64 & 0xffffffff); + *timeStamp1 = (uint32_t) ((timeStamp64 >> 32) & 0xffffffff); +} +#endif + +/** + * csr_scan_save_roam_offload_ap_to_scan_cache + * This function parses the received beacon/probe response + * from the firmware as part of the roam synch indication. + * The beacon or the probe response is parsed and is also + * saved into the scan cache + * + * @param pMac Pointer to Global Mac + * @param roam_sync_ind_ptr Roam Synch Indication from + * firmware which also contains the beacon/probe + * response + * @return Status + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_sync_ind_ptr) +{ + uint32_t length = 0; + bool dup_bss; + tDot11fBeaconIEs *ies_local_ptr = NULL; + tAniSSID tmpSsid; + v_TIME_t timer = 0; + tCsrScanResult *scan_res_ptr = NULL; + uint8_t session_id = roam_sync_ind_ptr->roamedVdevId; + + length = roam_sync_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + scan_res_ptr = cdf_mem_malloc(sizeof(tCsrScanResult) + length); + if (scan_res_ptr == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + " fail to allocate memory for frame"); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(scan_res_ptr, sizeof(tCsrScanResult) + length); + cdf_mem_copy(&scan_res_ptr->Result.BssDescriptor, + roam_sync_ind_ptr->bss_desc_ptr, + (sizeof(tSirBssDescription) + length)); + ies_local_ptr = (tDot11fBeaconIEs *)(scan_res_ptr->Result.pvIes); + if (!ies_local_ptr && + (!CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies( + pMac, &scan_res_ptr->Result. + BssDescriptor, + &ies_local_ptr)))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s:Cannot Parse IEs", __func__); + csr_free_scan_result_entry(pMac, scan_res_ptr); + return CDF_STATUS_E_RESOURCES; + } + + dup_bss = csr_remove_dup_bss_description(pMac, + &scan_res_ptr->Result.BssDescriptor, + ies_local_ptr, &tmpSsid, &timer, true); + if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s:BSS Limit Exceed", __func__); + if ((scan_res_ptr->Result.pvIes == NULL) && ies_local_ptr) + cdf_mem_free(ies_local_ptr); + + csr_free_scan_result_entry(pMac, scan_res_ptr); + return CDF_STATUS_E_RESOURCES; + } + csr_scan_add_result(pMac, scan_res_ptr, ies_local_ptr, session_id); + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * csr_get_bssdescr_from_scan_handle() - This function to extract + * first bss description from scan handle + * @result_handle: an object for the result. + * + * This function is written to extract first bss from scan handle. + * + * Return: first bss descriptor from the scan handle. + */ +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr) +{ + tListElem *first_element = NULL; + tCsrScanResult *scan_result = NULL; + tScanResultList *bss_list = (tScanResultList *)result_handle; + + if (NULL == bss_list) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + return NULL; + } + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + cdf_mem_free(bss_list); + return NULL; + } + first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + if (first_element) { + scan_result = GET_BASE_ADDR(first_element, + tCsrScanResult, + Link); + cdf_mem_copy(bss_descr, + &scan_result->Result.BssDescriptor, + sizeof(tSirBssDescription)); + } + return bss_descr; +} + +/** + * scan_active_list_cmd_timeout_handle() - To handle scan active command timeout + * @userData: scan context + * + * This routine is to handle scan active command timeout + * + * Return: None + */ +void csr_scan_active_list_timeout_handle(void *userData) +{ + tSmeCmd *scan_cmd = (tSmeCmd *) userData; + tHalHandle *hal_ctx = cds_get_context(CDF_MODULE_ID_PE); + tpAniSirGlobal mac_ctx; + uint16_t scan_id; + tSirSmeScanAbortReq *msg; + uint16_t msg_len; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (scan_cmd == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Scan Timeout: Scan command is NULL")); + return; + } + mac_ctx = PMAC_STRUCT(hal_ctx); + scan_id = scan_cmd->u.scanCmd.scanID; + sms_log(mac_ctx, LOGE, + FL("Scan Timeout:Sending abort to Firmware ID %d session %d "), + scan_id, scan_cmd->sessionId); + msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq)); + msg = cdf_mem_malloc(msg_len); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Failed to alloc memory for SmeScanAbortReq")); + return; + } + cdf_mem_zero((void *)msg, msg_len); + msg->type = eWNI_SME_SCAN_ABORT_IND; + msg->msgLen = msg_len; + msg->sessionId = scan_cmd->sessionId; + msg->scan_id = scan_id; + status = cds_send_mb_message_to_mac(msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" Failed to post message to LIM")); + cdf_mem_free(msg); + } + csr_release_scan_command(mac_ctx, scan_cmd, eCSR_SCAN_FAILURE); + return; +} diff --git a/core/sme/src/csr/csr_cmd_process.c b/core/sme/src/csr/csr_cmd_process.c new file mode 100644 index 0000000000..7fa7ec8aaa --- /dev/null +++ b/core/sme/src/csr/csr_cmd_process.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + \file csr_cmd_process.c + + Implementation for processing various commands. + ========================================================================== */ + +#include "ani_global.h" + +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" +#include "mac_trace.h" + +/** + * csr_msg_processor() - To process all csr msg + * @mac_ctx: mac context + * @msg_buf: message buffer + * + * This routine will handle all the message for csr to process + * + * Return: CDF_STATUS + */ +CDF_STATUS csr_msg_processor(tpAniSirGlobal mac_ctx, void *msg_buf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirSmeRsp *sme_rsp = (tSirSmeRsp *) msg_buf; +#ifdef FEATURE_WLAN_SCAN_PNO + tSirMbMsg *msg = (tSirMbMsg *) msg_buf; + tCsrRoamSession *session; +#endif + uint8_t session_id = sme_rsp->sessionId; + eCsrRoamState cur_state = mac_ctx->roam.curState[session_id]; + + sms_log(mac_ctx, LOG2, + FL("msg %d[0x%04X] recvd in curstate %s & substate %s id(%d)"), + sme_rsp->messageType, sme_rsp->messageType, + mac_trace_getcsr_roam_state(cur_state), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[session_id]), + session_id); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* + * PNO scan responses have to be handled irrespective of CSR roam state. + * Check if PNO has been started & only then process the PNO scan result + * Also note that normal scan isn't allowed when PNO scan is in progress + * and so the scan responses reaching here when PNO is started must be + * PNO responses. For normal scan, the PNO started flag will be false + * and it'll be processed as usual based on the current CSR roam state. + */ + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found, msgType : %d"), + session_id, msg->type); + return CDF_STATUS_E_FAILURE; + } + + if (eWNI_SME_SCAN_RSP == msg->type) { + status = csr_scanning_state_msg_processor(mac_ctx, msg_buf); + if (CDF_STATUS_SUCCESS != status) + sms_log(mac_ctx, LOGE, + FL("handling PNO scan resp 0x%X CSR state %d"), + sme_rsp->messageType, cur_state); + return status; + } +#endif + + /* Process the message based on the state of the roaming states... */ +#if defined(ANI_RTT_DEBUG) + if (!pAdapter->fRttModeEnabled) { +#endif + switch (cur_state) { + case eCSR_ROAMING_STATE_JOINED: + /* are we in joined state */ + csr_roam_joined_state_msg_processor(mac_ctx, msg_buf); + break; + case eCSR_ROAMING_STATE_JOINING: + /* are we in roaming states */ +#if defined(ANI_EMUL_ASSOC) + emulRoamingStateMsgProcessor(pAdapter, pMBBufHdr); +#endif + csr_roaming_state_msg_processor(mac_ctx, msg_buf); + break; + + default: + /* + * For all other messages, we ignore it + * To work-around an issue where checking for set/remove + * key base on connection state is no longer workable + * due to failure or finding the condition meets both + * SAP and infra/IBSS requirement. + */ + if (eWNI_SME_SETCONTEXT_RSP == sme_rsp->messageType) { + sms_log(mac_ctx, LOGW, + FL("handling msg 0x%X CSR state is %d"), + sme_rsp->messageType, cur_state); + csr_roam_check_for_link_status_change(mac_ctx, + sme_rsp); + } else if (eWNI_SME_GET_RSSI_REQ == + sme_rsp->messageType) { + tAniGetRssiReq *pGetRssiReq = + (tAniGetRssiReq *) msg_buf; + if (NULL == pGetRssiReq->rssiCallback) { + sms_log(mac_ctx, LOGE, + FL("rssiCallback is NULL")); + return status; + } + sms_log(mac_ctx, LOGW, + FL("msg eWNI_SME_GET_RSSI_REQ is not handled by CSR in state %d. calling RSSI callback"), + cur_state); + ((tCsrRssiCallback)(pGetRssiReq->rssiCallback))( + pGetRssiReq->lastRSSI, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } else { + sms_log(mac_ctx, LOGE, + FL("Message 0x%04X is not handled by CSR state is %d session Id %d"), + sme_rsp->messageType, cur_state, + session_id); + + if (eWNI_SME_FT_PRE_AUTH_RSP == + sme_rsp->messageType) { + sms_log(mac_ctx, LOGE, + FL("Dequeue eSmeCommandRoam command with reason eCsrPerformPreauth")); + csr_dequeue_roam_command(mac_ctx, + eCsrPerformPreauth); + } else if (eWNI_SME_REASSOC_RSP == + sme_rsp->messageType) { + sms_log(mac_ctx, LOGE, + FL("Dequeue eSmeCommandRoam command with reason eCsrSmeIssuedFTReassoc")); + csr_dequeue_roam_command(mac_ctx, + eCsrSmeIssuedFTReassoc); + } + } + break; + } /* switch */ +#if defined(ANI_RTT_DEBUG) + } +#endif + return status; +} + +bool csr_check_ps_ready(void *pv) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + if (pMac->roam.sPendingCommands < 0) { + CDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return 0; + } + return pMac->roam.sPendingCommands == 0; +} + +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + CDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return pMac->roam.sPendingCommands == 0; +} + diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h new file mode 100644 index 0000000000..1679784082 --- /dev/null +++ b/core/sme/src/csr/csr_inside_api.h @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_inside_api.h + + Define interface only used by CSR. + ========================================================================== */ +#ifndef CSR_INSIDE_API_H__ +#define CSR_INSIDE_API_H__ + +#include "csr_support.h" +#include "sme_inside.h" +#include "cds_reg_service.h" + +#define CSR_PASSIVE_MAX_CHANNEL_TIME 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME 40 +#define CSR_ACTIVE_MIN_CHANNEL_TIME 20 + +#ifdef WLAN_AP_STA_CONCURRENCY +#define CSR_PASSIVE_MAX_CHANNEL_TIME_CONC 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME_CONC 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME_CONC 27 +#define CSR_ACTIVE_MIN_CHANNEL_TIME_CONC 20 + +#define CSR_REST_TIME_CONC 100 + +#define CSR_NUM_STA_CHAN_COMBINED_CONC 3 +#define CSR_NUM_P2P_CHAN_COMBINED_CONC 1 +#endif + +#define CSR_MAX_NUM_SUPPORTED_CHANNELS 55 + +#define CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS 14 + +#define CSR_MAX_BSS_SUPPORT 300 +#define SYSTEM_TIME_MSEC_TO_USEC 1000 + +/* This number minus 1 means the number of times a channel is scanned before a BSS is remvoed from */ +/* cache scan result */ +#define CSR_AGING_COUNT 3 +#define CSR_SCAN_GET_RESULT_INTERVAL (5 * CDF_MC_TIMER_TO_SEC_UNIT) /* 5 seconds */ +#define CSR_MIC_ERROR_TIMEOUT (60 * CDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */ +#define CSR_TKIP_COUNTER_MEASURE_TIMEOUT (60 * CDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */ + +#define CSR_SCAN_RESULT_CFG_AGING_INTERVAL (CDF_MC_TIMER_TO_SEC_UNIT) /* 1 second */ +/* the following defines are NOT used by palTimer */ +#define CSR_SCAN_AGING_TIME_NOT_CONNECT_NO_PS 50 /* 50 seconds */ +#define CSR_SCAN_AGING_TIME_NOT_CONNECT_W_PS 300 /* 300 seconds */ +#define CSR_SCAN_AGING_TIME_CONNECT_NO_PS 150 /* 150 seconds */ +#define CSR_SCAN_AGING_TIME_CONNECT_W_PS 600 /* 600 seconds */ +#define CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000) +#define CSR_JOIN_FAILURE_TIMEOUT_MIN (1000) /* minimal value */ +/* These are going against the signed RSSI (int8_t) so it is between -+127 */ +#define CSR_BEST_RSSI_VALUE (-30) /* RSSI >= this is in CAT4 */ +#define CSR_DEFAULT_RSSI_DB_GAP 30 /* every 30 dbm for one category */ +#define CSR_BSS_CAP_VALUE_NONE 0 /* not much value */ +#define CSR_BSS_CAP_VALUE_HT 1 +#define CSR_BSS_CAP_VALUE_VHT 2 +#define CSR_BSS_CAP_VALUE_WMM 1 +#define CSR_BSS_CAP_VALUE_UAPSD 1 +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +#define CSR_BSS_CAP_VALUE_5GHZ 2 +#endif +#define CSR_DEFAULT_ROAMING_TIME 10 /* 10 seconds */ + +#define CSR_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) + +/* *************************************************************************** + * The MAX BSSID Count should be lower than the command timeout value and it + * can be of a fraction of 3/4 of the total command timeout value. + * ***************************************************************************/ +#define CSR_ACTIVE_LIST_CMD_TIMEOUT_VALUE (1000*30*4) +#define CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT (1000*30) + +#define CSR_MAX_BSSID_COUNT ((CSR_ACTIVE_LIST_CMD_TIMEOUT_VALUE/4000) * 3) +#define CSR_CUSTOM_CONC_GO_BI 100 +#define MIN_11P_CHANNEL (rf_channels[MIN_5_9GHZ_CHANNEL].channelNum) + +typedef enum { + eCsrNextScanNothing, + eCsrNextLostLinkScan1Success, + eCsrNextLostLinkScan1Failed, + eCsrNextLostLinkScan2Success, + eCsrNextLostLinkScan2Failed, + eCsrNextLostLinkScan3Success, + eCsrNexteScanForSsidSuccess, + eCsrNextLostLinkScan3Failed, + eCsrNext11dScan1Failure, + eCsrNext11dScan1Success, + eCsrNext11dScan2Failure, + eCsrNext11dScan2Success, + eCsrNext11dScanComplete, + eCsrNexteScanForSsidFailure, + +} eCsrScanCompleteNextCommand; + +typedef enum { + eCsrJoinSuccess, + eCsrJoinFailure, + eCsrReassocSuccess, + eCsrReassocFailure, + eCsrNothingToJoin, + eCsrStartBssSuccess, + eCsrStartBssFailure, + eCsrSilentlyStopRoaming, + eCsrSilentlyStopRoamingSaveState, + eCsrJoinWdsFailure, + eCsrJoinFailureDueToConcurrency, + +} eCsrRoamCompleteResult; + +typedef struct tagScanReqParam { + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + uint8_t hiddenSsid; + uint8_t reserved; +} tScanReqParam; + +typedef struct tagCsrScanResult { + tListElem Link; + int32_t AgingCount; /* This BSS is removed when it reaches 0 or less */ + uint32_t preferValue; /* The bigger the number, the better the BSS. This value override capValue */ + uint32_t capValue; /* The biggger the better. This value is in use only if we have equal preferValue */ + /* This member must be the last in the structure because the end of tSirBssDescription (inside) is an */ + /* array with nonknown size at this time */ + + eCsrEncryptionType ucEncryptionType; /* Preferred Encryption type that matched with profile. */ + eCsrEncryptionType mcEncryptionType; + eCsrAuthType authType; /* Preferred auth type that matched with the profile. */ + + tCsrScanResultInfo Result; +} tCsrScanResult; + +typedef struct { + tDblLinkList List; + tListElem *pCurEntry; +} tScanResultList; + +#define CSR_IS_ROAM_REASON(pCmd, reason) ((reason) == (pCmd)->roamCmd.roamReason) +#define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_PREFER_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_CAP_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_CAP_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_RSSI(v1, v2) ((v1) > (v2)) +#define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) || \ + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType))) +#define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \ + (CSR_IS_ROAM_JOINED(pMac, sessionId) && \ + CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId)) +/* WIFI has a test case for not using HT rates with TKIP as encryption */ +/* We may need to add WEP but for now, TKIP only. */ + +#define CSR_IS_11n_ALLOWED(encType) ((eCSR_ENCRYPT_TYPE_TKIP != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40 != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104 != (encType))) + +#define CSR_IS_DISCONNECT_COMMAND(pCommand) ((eSmeCommandRoam == (pCommand)->command) && \ + ((eCsrForcedDisassoc == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDeauth == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrSmeIssuedDisassocForHandoff == \ + (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDisassocMICFailure == \ + (pCommand)->u.roamCmd.roamReason))) + +extern const tRfChannelProps rf_channels[NUM_RF_CHANNELS]; +eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac, + eCsrRoamState NewRoamState, uint8_t sessionId); +CDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp); +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand); +extern void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx); + +bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2, bool fForced); +CDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +CDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac, void *pMsgBuf); +/* + Prepare a filter base on a profile for parsing the scan results. + Upon successful return, caller MUST call csr_free_scan_filter on + pScanFilter when it is done with the filter. + */ +CDF_STATUS csr_roam_prepare_filter_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tCsrScanResultFilter *pScanFilter); +CDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pDstProfile, + tCsrRoamProfile *pSrcProfile); +CDF_STATUS csr_roam_start(tpAniSirGlobal pMac); +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_roam_startMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_stopMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_startTKIPCounterMeasureTimer(tpAniSirGlobal pMac); +void csr_roam_stopTKIPCounterMeasureTimer(tpAniSirGlobal pMac); + +CDF_STATUS csr_scan_open(tpAniSirGlobal pMac); +CDF_STATUS csr_scan_close(tpAniSirGlobal pMac); +CDF_STATUS csr_scan_request_lost_link1(tpAniSirGlobal pMac, uint32_t sessionId); +CDF_STATUS csr_scan_request_lost_link2(tpAniSirGlobal pMac, uint32_t sessionId); +CDF_STATUS csr_scan_request_lost_link3(tpAniSirGlobal pMac, uint32_t sessionId); +CDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac, + uint32_t sessionId); +CDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac, + uint32_t sessionId); +CDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac, + uint32_t sessionId); +tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pSirBssDescription, + tDot11fBeaconIEs *pIes, + bool fForced, uint8_t sessionId); +void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +CDF_STATUS csr_scan_copy_request(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, + tCsrScanRequest *pSrcReq); +CDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq); +CDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn, + tScanResultHandle *phResult); +CDF_STATUS csr_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, uint32_t roamId, + bool notify); +CDF_STATUS csr_scan_start_result_cfg_aging_timer(tpAniSirGlobal pMac); +CDF_STATUS csr_scan_stop_result_cfg_aging_timer(tpAniSirGlobal pMac); +void csr_scan_stop_timers(tpAniSirGlobal pMac); +/* To remove fresh scan commands from the pending queue */ +bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId); +CDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId, + eCsrAbortReason reason); +void csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac, tDblLinkList *pList, + eSmeCommandType commandType); +void csr_remove_cmd_with_session_id_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, + tDblLinkList *pList, + eSmeCommandType commandType); +CDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac, + uint8_t sessionId); +CDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac, + tDblLinkList *pList, + uint32_t sessionId); + +CDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal pMac, + tDblLinkList *pList, uint32_t sessionId, + eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason); + +/* To age out scan results base. tSmeGetScanChnRsp is a pointer returned by LIM that */ +/* has the information regarding scanned channels. */ +/* The logic is that whenever CSR add a BSS to scan result, it set the age count to */ +/* a value. This function deduct the age count if channelId matches the BSS' channelId */ +/* The BSS is remove if the count reaches 0. */ +CDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac, + tSmeGetScanChnRsp *pScanChnInfo); + +/* If fForce is true we will save the new String that is learn't. */ +/* Typically it will be true in case of Join or user initiated ioctl */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce); +void csr_apply_country_information(tpAniSirGlobal pMac); +void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode, + tCsrChannel *pChannelList); +void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult); + +CDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2); +CDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tScanResultHandle hBSSList, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate, bool fClearScan); +CDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields *pModProfileFields, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate); +void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result, + void *Context); +CDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole); +CDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure); +CDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg); +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg); +CDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamStartBssParams *pParam, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, uint32_t roamId); +CDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate); +bool csr_is_same_profile(tpAniSirGlobal pMac, tCsrRoamConnectedProfile *pProfile1, + tCsrRoamProfile *pProfile2); +bool csr_is_roam_command_waiting(tpAniSirGlobal pMac); +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac); +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, + uint32_t sessionId); +/* pBand can be NULL if caller doesn't need to get it */ +CDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); +CDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); +/* pCommand may be NULL */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId, + tSmeCmd *pCommand, + eCsrRoamReason eRoamReason); + +CDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + tCsrRoamProfile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType); +CDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +CDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +CDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd); +CDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd); +CDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, + CDF_STATUS status); +CDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + CDF_STATUS Halstatus, + uint8_t sessionId); +CDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamBssType bssType, + tCsrRoamStartBssParams *pParam, + tSirBssDescription *pBssDesc); +CDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId); + +/* Caller should put the BSS' ssid to fiedl bssSsid when comparing SSID for a BSS. */ +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired); +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + tCsrRoamProfile *pProfile, + eCsrCfgDot11Mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes); +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel); + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +CDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan); +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result); + +tPowerdBm csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel); + +/* To free the last roaming profile */ +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId); +CDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct cdf_mac_addr *bssid, + tScanResultHandle hScanResult); +bool csr_check_ps_ready(void *pv); +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId); + +/* to free memory allocated inside the profile structure */ +void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile); +/* To free memory allocated inside scanFilter */ +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter); +eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary); +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + eCsrCfgDot11Mode csrDot11Mode); +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fPopulate5GBand); +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal pMac, + tCsrChannel *pChannelList, + uint8_t *countryCode); +void csr_apply_power2_current(tpAniSirGlobal pMac); +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset); +CDF_STATUS csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile * + pConnProfile); +CDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamingReason roamingReason); +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult); +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess); +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac); +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#endif /* FEATURE_WLAN_WAPI */ +CDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, uint32_t tableSize, + tSirMacChanInfo *channelTable); + +/* To check whether a country code matches the one in the IE */ +/* Only check the first two characters, ignoring in/outdoor */ +/* pCountry -- caller allocated buffer contain the country code that is checking against */ +/* the one in pIes. It can be NULL. */ +/* caller must provide pIes, it cannot be NULL */ +/* This function always return true if 11d support is not turned on. */ +/* pIes cannot be NULL */ +bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry, + tDot11fBeaconIEs *pIes); +CDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId); +CDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac, + csr_roam_completeCallback callback, void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType); +/* fSync: true means cleanupneeds to handle synchronously. */ +CDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId, + bool fSync, + csr_roamSessionCloseCallback callback, + void *pContext); +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId); +CDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, struct cdf_mac_addr *bssid, + uint32_t *pSessionId); +eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode); + +/* --------------------------------------------------------------------------- + \fn csr_scan_enable + \brief Enable the scanning feature of CSR. It must be called before any scan request can be performed. + \param tHalHandle - HAL context handle + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_enable(tpAniSirGlobal); + +/* --------------------------------------------------------------------------- + \fn csr_scan_disable + \brief Disableing the scanning feature of CSR. After this function return success, no scan is performed until + a successfull to csr_scan_enable + \param tHalHandle - HAL context handle + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_disable(tpAniSirGlobal); +/* --------------------------------------------------------------------------- + \fn csr_scan_request + \brief Request a 11d or full scan. + \param callback - a callback function that scan calls upon finish, will not be called if csr_scan_request returns error + \param pContext - a pointer passed in for the callback + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_request(tpAniSirGlobal, uint16_t, tCsrScanRequest *, + csr_scan_completeCallback callback, void *pContext); + +/* --------------------------------------------------------------------------- + \fn csrScanAbort + \brief If a scan request is abort, the scan complete callback will be called first before csrScanAbort returns. + \param pScanRequestID - The request ID returned from csr_scan_request + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csrScanAbort(tpAniSirGlobal, uint32_t scanRequestID); + +/* --------------------------------------------------------------------------- + \fn csr_scan_get_result + \brief Return scan results. + \param pFilter - If pFilter is NULL, all cached results are returned + \param phResult - an object for the result. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_get_result(tpAniSirGlobal, tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult); + +/* --------------------------------------------------------------------------- + \fn csr_scan_flush_result + \brief Clear scan results. + \param pMac - pMac global pointer + \param sessionId - Session Identifier + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_flush_result(tpAniSirGlobal); +/* --------------------------------------------------------------------------- + * \fn csr_scan_filter_results + * \brief Filter scan results based on valid channel list. + * \param pMac - Pointer to Global MAC structure + * \return CDF_STATUS + ***------------------------------------------------------------------------------- + */ +CDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason, + uint8_t sessionId); + +CDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal, bool flushP2P); + +/* --------------------------------------------------------------------------- + \fn csr_scan_result_get_first + \brief Returns the first element of scan result. + \param hScanResult - returned from csr_scan_get_result + \return tCsrScanResultInfo * - NULL if no result + -------------------------------------------------------------------------------*/ +tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal, + tScanResultHandle hScanResult); +/* --------------------------------------------------------------------------- + \fn csr_scan_result_get_next + \brief Returns the next element of scan result. It can be called without calling csr_scan_result_get_first first + \param hScanResult - returned from csr_scan_get_result + \return Null if no result or reach the end + -------------------------------------------------------------------------------*/ +tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal, + tScanResultHandle hScanResult); + +/* --------------------------------------------------------------------------- + \fn csr_get_country_code + \brief this function is to get the country code current being used + \param pBuf - Caller allocated buffer with at least 3 bytes, upon success return, this has the country code + \param pbLen - Caller allocated, as input, it indicates the length of pBuf. Upon success return, + this contains the length of the data in pBuf + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen); + +/* --------------------------------------------------------------------------- + \fn csr_set_country_code + \brief this function is to set the country code so channel/power setting matches the countrycode and + the domain it belongs to. + \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry); + +/* --------------------------------------------------------------------------- + \fn csr_get_regulatory_domain_for_country + \brief this function is to get the regulatory domain for a country. + This function must be called after CFG is downloaded and all the band/mode setting already passed into + CSR. + \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code + \param pDomainId - Caller allocated buffer to get the return domain ID upon success return. Can be NULL. + \param source - the source of country information. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, + v_CountryInfoSource_t source); + +/* some support functions */ +bool csr_is11d_supported(tpAniSirGlobal pMac); +bool csr_is11h_supported(tpAniSirGlobal pMac); +bool csr_is11e_supported(tpAniSirGlobal pMac); +bool csr_is_wmm_supported(tpAniSirGlobal pMac); +bool csr_is_mcc_supported(tpAniSirGlobal pMac); + +/* Return SUCCESS is the command is queued, failed */ +CDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fHighPriority); +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac); +void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_scan_flush_bss_entry(tpAniSirGlobal pMac, + tpSmeCsaOffloadInd pCsaOffloadInd); +CDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac, uint32_t scan_id, + tListElem **entry); + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + +/* Security */ +#define WLAN_SECURITY_EVENT_SET_PTK_REQ 1 +#define WLAN_SECURITY_EVENT_SET_PTK_RSP 2 +#define WLAN_SECURITY_EVENT_SET_GTK_REQ 3 +#define WLAN_SECURITY_EVENT_SET_GTK_RSP 4 +#define WLAN_SECURITY_EVENT_REMOVE_KEY_REQ 5 +#define WLAN_SECURITY_EVENT_REMOVE_KEY_RSP 6 +#define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7 +#define WLAN_SECURITY_EVENT_PMKID_UPDATE 8 +#define WLAN_SECURITY_EVENT_MIC_ERROR 9 + +#define AUTH_OPEN 0 +#define AUTH_SHARED 1 +#define AUTH_WPA_EAP 2 +#define AUTH_WPA_PSK 3 +#define AUTH_WPA2_EAP 4 +#define AUTH_WPA2_PSK 5 +#ifdef FEATURE_WLAN_WAPI +#define AUTH_WAPI_CERT 6 +#define AUTH_WAPI_PSK 7 +#endif /* FEATURE_WLAN_WAPI */ + +#define ENC_MODE_OPEN 0 +#define ENC_MODE_WEP40 1 +#define ENC_MODE_WEP104 2 +#define ENC_MODE_TKIP 3 +#define ENC_MODE_AES 4 +#ifdef FEATURE_WLAN_WAPI +#define ENC_MODE_SMS4 5 /* WAPI */ +#endif /* FEATURE_WLAN_WAPI */ + +#define NO_MATCH 0 +#define MATCH 1 + +#define WLAN_SECURITY_STATUS_SUCCESS 0 +#define WLAN_SECURITY_STATUS_FAILURE 1 + +/* Scan */ +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ 1 +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP 2 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ 3 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP 4 +#define WLAN_SCAN_EVENT_HO_SCAN_REQ 5 +#define WLAN_SCAN_EVENT_HO_SCAN_RSP 6 + +#define WLAN_SCAN_STATUS_SUCCESS 0 +#define WLAN_SCAN_STATUS_FAILURE 1 +#define WLAN_SCAN_STATUS_ABORT 2 + +/* Ibss */ +#define WLAN_IBSS_EVENT_START_IBSS_REQ 0 +#define WLAN_IBSS_EVENT_START_IBSS_RSP 1 +#define WLAN_IBSS_EVENT_JOIN_IBSS_REQ 2 +#define WLAN_IBSS_EVENT_JOIN_IBSS_RSP 3 +#define WLAN_IBSS_EVENT_COALESCING 4 +#define WLAN_IBSS_EVENT_PEER_JOIN 5 +#define WLAN_IBSS_EVENT_PEER_LEAVE 6 +#define WLAN_IBSS_EVENT_STOP_REQ 7 +#define WLAN_IBSS_EVENT_STOP_RSP 8 + +#define AUTO_PICK 0 +#define SPECIFIED 1 + +#define WLAN_IBSS_STATUS_SUCCESS 0 +#define WLAN_IBSS_STATUS_FAILURE 1 + +/* 11d */ +#define WLAN_80211D_EVENT_COUNTRY_SET 0 +#define WLAN_80211D_EVENT_RESET 1 + +#define WLAN_80211D_DISABLED 0 +#define WLAN_80211D_SUPPORT_MULTI_DOMAIN 1 +#define WLAN_80211D_NOT_SUPPORT_MULTI_DOMAIN 2 + +int diag_auth_type_from_csr_type(eCsrAuthType authType); +int diag_enc_type_from_csr_type(eCsrEncryptionType encType); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ +/* --------------------------------------------------------------------------- + \fn csr_scan_result_purge + \brief remove all items(tCsrScanResult) in the list and free memory for each item + \param hScanResult - returned from csr_scan_get_result. hScanResult is considered gone by + calling this function and even before this function reutrns. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + tScanResultHandle hScanResult); + +/* /////////////////////////////////////////Common Scan ends */ + +/* --------------------------------------------------------------------------- + \fn csr_roam_connect + \brief To inititiate an association + \param pProfile - can be NULL to join to any open ones + \param pRoamId - to get back the request ID + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + uint32_t *pRoamId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_reassoc + \brief To inititiate a re-association + \param pProfile - can be NULL to join the currently connected AP. In that + case modProfileFields should carry the modified field(s) which could trigger + reassoc + \param modProfileFields - fields which are part of tCsrRoamConnectedProfile + that might need modification dynamically once STA is up & running and this + could trigger a reassoc + \param pRoamId - to get back the request ID + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_reconnect + \brief To disconnect and reconnect with the same profile + \return CDF_STATUS. It returns fail if currently not connected + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_set_pmkid_cache + \brief return the PMKID candidate list + \param pPMKIDCache - caller allocated buffer point to an array of tPmkidCacheInfo + \param numItems - a variable that has the number of tPmkidCacheInfo allocated + when retruning, this is either the number needed or number of items put into pPMKIDCache + \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems + has the number of tPmkidCacheInfo. + \Note: pNumItems is a number of tPmkidCacheInfo, not sizeof(tPmkidCacheInfo) * something + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* --------------------------------------------------------------------------- + *\fn csr_roam_set_psk_pmk + *\brief store PSK/PMK + *\param pMac - pointer to global structure for MAC + *\param sessionId - Sme session id + *\param pPSK_PMK - pointer to an array of Psk/Pmk + *\return CDF_STATUS - usually it succeed unless sessionId is not found + *\Note: + *-------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); + +/* --------------------------------------------------------------------------- + *\fn csr_roam_set_key_mgmt_offload + *\brief sets nRoamKeyMgmtOffloadEnabled + *\param pMac - pointer to global structure for MAC + *\param sessionId - Sme session id + *\param nRoamKeyMgmtOffloadEnabled - value of key mgmt offload enable + *\return CDF_STATUS - usually it succeed unless sessionId is not found + *\Note: + *-------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal pMac, + uint32_t sessionId, + bool nRoamKeyMgmtOffloadEnabled); +#endif +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wpa_rsn_req_ie + \brief return the WPA or RSN IE CSR passes to PE to JOIN request or START_BSS request + \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the + needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, upon return + \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wpa_rsn_rsp_ie + \brief return the WPA or RSN IE from the beacon or probe rsp if connected + \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the + needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, upon return + \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_num_pmkid_cache + \brief return number of PMKID cache entries + \return uint32_t - the number of PMKID cache entries + -------------------------------------------------------------------------------*/ +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_pmkid_cache + \brief return PMKID cache from CSR + \param pNum - caller allocated memory that has the space of the number of pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the + needed or actually number in tPmkidCacheInfo. + \param pPmkidCache - Caller allocated memory that contains PMKID cache, if any, upon return + \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache); + +/** + * csr_roam_get_connect_profile() - To return the current connect profile, + * caller must call csr_roam_free_connect_profile after it is done and before + * reuse for another csr_roam_get_connect_profile call. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID + * @pProfile: pointer to a caller allocated structure + * tCsrRoamConnectedProfile + * + * Return: CDF_STATUS. Failure if not connected, success otherwise + */ +CDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_connect_state + \brief To return the current connect state of Roaming + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState); + +/* --------------------------------------------------------------------------- + \fn csr_roam_free_connect_profile + \brief To free and reinitialize the profile return previous by csr_roam_get_connect_profile. + \param pProfile - pointer to a caller allocated structure tCsrRoamConnectedProfile + \return CDF_STATUS. + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_free_connect_profile(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile); + +/* --------------------------------------------------------------------------- + \fn csr_apply_channel_and_power_list + \brief HDD calls this function to set the WNI_CFG_VALID_CHANNEL_LIST base on the band/mode settings. + This function must be called after CFG is downloaded and all the band/mode setting already passed into + CSR. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac); + +/** + * csr_change_config_params() - The CSR API exposed for HDD to provide config + * params to CSR during SMEs stop -> start sequence. + * + * @pMac: pointer to global adapter context + * @pUpdateConfigParam: a pointer to a structure (tCsrUpdateConfigParam) that + * currently provides 11d related information like country code, Regulatory + * domain, valid channel list, Tx power per channel, a list with active/passive + * scan allowed per valid channel. + * + * If HDD changed the domain that will cause a reset. This function will + * provide the new set of 11d information for the new domain. Currrently this + * API provides info regarding 11d only at reset but we can extend this for + * other params (PMC, QoS) which needs to be initialized again at reset. + * + * Return: CDF_STATUS. status of operation + */ +CDF_STATUS csr_change_config_params(tpAniSirGlobal pMac, + tCsrUpdateConfigParam *pUpdateConfigParam); + +/* --------------------------------------------------------------------------- + \fn csr_roam_connect_to_last_profile + \brief To disconnect and reconnect with the same profile + \return CDF_STATUS. It returns fail if currently connected + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_disconnect + \brief To disconnect from a network + \param reason -- To indicate the reason for disconnecting. Currently, only eCSR_DISCONNECT_REASON_MIC_ERROR is meanful. + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); + +/* --------------------------------------------------------------------------- + \fn csr_scan_get_pmkid_candidate_list + \brief return the PMKID candidate list + \param pPmkidList - caller allocated buffer point to an array of tPmkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of tPmkidCandidateInfo allocated + when retruning, this is either the number needed or number of items put into pPmkidList + \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems + has the number of tPmkidCandidateInfo. + \Note: pNumItems is a number of tPmkidCandidateInfo, not sizeof(tPmkidCandidateInfo) * something + -------------------------------------------------------------------------------*/ +CDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems); + +/* This function is used to stop a BSS. It is similar of csr_roamIssueDisconnect but this function */ +/* doesn't have any logic other than blindly trying to stop BSS */ +CDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority); + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + tCsrRoamSession *pSession, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eCsrRoamResult roamResult); + +/* --------------------------------------------------------------------------- + \fn csr_roam_issue_disassociate_sta_cmd + \brief csr function that HDD calls to disassociate a associated station + \param sessionId - session Id for Soft AP + \param pPeerMacAddr - MAC of associated station to delete + \param reason - reason code, be one of the tSirMacReasonCodes + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pPeerMacAddr, + uint32_t reason); + +/** + * csr_roam_issue_deauth_sta_cmd() - issue deauthenticate station command + * @pMac: Pointer to global structure for MAC + * @sessionId: Session Id for Soft AP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to issue a deauthenticate station command + * + * Return: CDF_STATUS_SUCCESS on success or another CDF_STATUS_* on error + */ +CDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams *pDelStaParams); + +/* --------------------------------------------------------------------------- + \fn csr_roam_issue_tkip_counter_measures + \brief csr function that HDD calls to start and stop tkip countermeasures + \param sessionId - session Id for Soft AP + \param bEnable - Flag to start/stop countermeasures + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac, + uint32_t sessionId, bool bEnable); + +CDF_STATUS csr_send_mb_tkip_counter_measures_req_msg(tpAniSirGlobal pMac, + uint32_t sessinId, bool bEnable, + tSirMacAddr bssId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_associated_stas + \brief csr function that HDD calls to get list of associated stations based on module ID + \param sessionId - session Id for Soft AP + \param modId - module ID - PE/HAL/TL + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pAssocStasBuf - Caller allocated memory to be filled with associatd stations info + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + CDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +CDF_STATUS csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + CDF_MODULE_ID modId, + tSirMacAddr bssId, + void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wps_session_overlap + \brief csr function that HDD calls to get WPS PBC session overlap information + \param sessionId - session Id for Soft AP + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pRemoveMac - pointer to MAC address of session to be removed + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId, + void *pUsrContext, + void *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac); + +CDF_STATUS csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, void *pUsrContext, + void *pfnSapEventCallback, + struct cdf_mac_addr pRemoveMac); + +/* --------------------------------------------------------------------------- + \fn csr_send_chng_mcc_beacon_interval + \brief csr function that HDD calls to send Update beacon interval + \param sessionId - session Id for Soft AP + \return CDF_STATUS + ---------------------------------------------------------------------------*/ +CDF_STATUS +csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId); + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* --------------------------------------------------------------------------- + \fn csr_roam_ft_pre_auth_rsp_processor + \brief csr function that handles pre auth response from LIM + ---------------------------------------------------------------------------*/ +void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal, + tpSirFTPreAuthRsp pFTPreAuthRsp); +#endif + + +#if defined(FEATURE_WLAN_ESE) +void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1, + uint32_t *incr); +#endif + +CDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId, + tpSirBssDescription pBssDescription, + eCsrRoamReason reason, bool fImmediate); +CDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason); +#ifdef FEATURE_WLAN_LFR +void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes); +#endif + +CDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct cdf_mac_addr bssid, + uint8_t channel); + +CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac); +CDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pBSSId, + bool flush_cache); + +bool csr_elected_country_info(tpAniSirGlobal pMac); +void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode); +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac); + +#endif + +#ifdef QCA_HT_2040_COEX +CDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled); +#endif +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr); +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +void csr_scan_active_list_timeout_handle(void *userData); +CDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd); diff --git a/core/sme/src/csr/csr_link_list.c b/core/sme/src/csr/csr_link_list.c new file mode 100644 index 0000000000..1fa0b8b6f5 --- /dev/null +++ b/core/sme/src/csr/csr_link_list.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + \file csr_link_list.c + + Implementation for the Common link list interfaces. + ========================================================================== */ + +#include "csr_link_list.h" +#include "cdf_lock.h" +#include "cdf_memory.h" +#include "cdf_trace.h" +#include "cdf_mc_timer.h" + +CDF_INLINE_FN void csr_list_init(tListElem *pList) +{ + pList->last = pList->next = pList; +} + +CDF_INLINE_FN void csr_list_remove_entry(tListElem *pEntry) +{ + tListElem *pLast; + tListElem *pNext; + + pLast = pEntry->last; + pNext = pEntry->next; + pLast->next = pNext; + pNext->last = pLast; +} + +CDF_INLINE_FN tListElem *csr_list_remove_head(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pNext; + + pEntry = pHead->next; + pNext = pEntry->next; + pHead->next = pNext; + pNext->last = pHead; + + return pEntry; +} + +CDF_INLINE_FN tListElem *csr_list_remove_tail(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pLast; + + pEntry = pHead->last; + pLast = pEntry->last; + pHead->last = pLast; + pLast->next = pHead; + + return pEntry; +} + +CDF_INLINE_FN void csr_list_insert_tail(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pLast; + + pLast = pHead->last; + pEntry->last = pLast; + pEntry->next = pHead; + pLast->next = pEntry; + pHead->last = pEntry; +} + +CDF_INLINE_FN void csr_list_insert_head(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pNext; + + pNext = pHead->next; + pEntry->next = pNext; + pEntry->last = pHead; + pNext->last = pEntry; + pHead->next = pEntry; +} + +/* Insert pNewEntry before pEntry */ +void csr_list_insert_entry(tListElem *pEntry, tListElem *pNewEntry) +{ + tListElem *pLast; + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pEntry is Null", __func__); + return; + } + + pLast = pEntry->last; + pLast->next = pNewEntry; + pEntry->last = pNewEntry; + pNewEntry->next = pEntry; + pNewEntry->last = pLast; +} + +uint32_t csr_ll_count(tDblLinkList *pList) +{ + uint32_t c = 0; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return c; + } + + if (pList && (LIST_FLAG_OPEN == pList->Flag)) { + c = pList->Count; + } + + return c; +} + +void csr_ll_lock(tDblLinkList *pList) +{ + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + cdf_mutex_acquire(&pList->Lock); + } +} + +void csr_ll_unlock(tDblLinkList *pList) +{ + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + cdf_mutex_release(&pList->Lock); + } +} + +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked) +{ + bool fEmpty = true; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fEmpty; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + fEmpty = csrIsListEmpty(&pList->ListHead); + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + return fEmpty; +} + +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the list, which will */ + /* happen if the entry is NOT on the list... */ + + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToFind) { + fFound = true; + break; + } + pEntry = pEntry->next; + } + + } + return fFound; +} + +CDF_STATUS csr_ll_open(tHddHandle hHdd, tDblLinkList *pList) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS cdf_status; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (LIST_FLAG_OPEN != pList->Flag) { + pList->Count = 0; + pList->cmdTimeoutTimer = NULL; + cdf_status = cdf_mutex_init(&pList->Lock); + + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + csr_list_init(&pList->ListHead); + pList->Flag = LIST_FLAG_OPEN; + pList->hHdd = hHdd; + } else { + status = CDF_STATUS_E_FAILURE; + } + } + return status; +} + +void csr_ll_close(tDblLinkList *pList) +{ + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + /* Make sure the list is empty... */ + csr_ll_purge(pList, LL_ACCESS_LOCK); + cdf_mutex_destroy(&pList->Lock); + pList->Flag = LIST_FLAG_CLOSE; + } +} + +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_tail(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_head(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + if (pList->cmdTimeoutTimer && pList->cmdTimeoutDuration) { + /* timer to detect pending command in activelist */ + cdf_mc_timer_start(pList->cmdTimeoutTimer, + pList->cmdTimeoutDuration); + } + } +} + +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked) +{ + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_entry(pEntry, pNewEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + + pEntry = csr_list_remove_tail(&pList->ListHead); + pList->Count--; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = pList->ListHead.last; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = csr_list_remove_head(&pList->ListHead); + pList->Count--; + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = pList->ListHead.next; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK))) { + /* just remove everything from the list until */ + /* nothing left on the list. */ + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the list, which will */ + /* happen if the entry is NOT on the list... */ + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToRemove) { + csr_list_remove_entry(pEntry); + pList->Count--; + + fFound = true; + break; + } + + pEntry = pEntry->next; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + if (pList->cmdTimeoutTimer) { + cdf_mc_timer_stop(pList->cmdTimeoutTimer); + } + } + + return fFound; +} + +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->next; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) { + pNextEntry = NULL; + } + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pNextEntry; +} + +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->last; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) { + pNextEntry = NULL; + } + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pNextEntry; +} diff --git a/core/sme/src/csr/csr_neighbor_roam.c b/core/sme/src/csr/csr_neighbor_roam.c new file mode 100644 index 0000000000..5aef6cf3e0 --- /dev/null +++ b/core/sme/src/csr/csr_neighbor_roam.c @@ -0,0 +1,3541 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_neighbor_roam.c + + Implementation for the simple roaming algorithm for 802.11r Fast + transitions and Legacy roaming for Android platform. + ========================================================================== */ + +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING +#include "wma_types.h" +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" + +#define WLAN_FEATURE_NEIGHBOR_ROAMING_DEBUG 1 +#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING_DEBUG +#define NEIGHBOR_ROAM_DEBUG sms_log +#else +#define NEIGHBOR_ROAM_DEBUG(x ...) +#endif + +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo); +static void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal pMac, + uint8_t sessionId); + +CDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pDstProfile); + +#ifdef WLAN_FEATURE_VOWIFI_11R +static CDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal pMac, + uint8_t sessionId); +#endif + +#define CSR_NEIGHBOR_ROAM_STATE_TRANSITION(mac_ctx, newstate, session) \ +{ \ + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState = \ + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState; \ + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState = newstate; \ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, \ + FL("Sessionid (%d) NeighborRoam transition from %s to %s"), \ + session, csr_neighbor_roam_state_to_string( \ + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState),\ + csr_neighbor_roam_state_to_string(newstate)); \ +} + +uint8_t *csr_neighbor_roam_state_to_string(uint8_t state) +{ + switch (state) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); + default: + return "eCSR_NEIGHBOR_ROAM_STATE_UNKNOWN"; + } + +} + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * csr_neighbor_roam_send_lfr_metric_event() - Send event of LFR metric + * @mac_ctx: Handle returned by mac_open. + * @session_id: Session information + * @bssid: BSSID of attempted AP + * @status: Result of LFR operation + * + * LFR metrics - pre-auth completion metric + * Send the event to supplicant indicating pre-auth result + * + * Return: void + */ + +static void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirMacAddr bssid, + eRoamCmdStatus status) +{ + tCsrRoamInfo *roam_info; + + roam_info = cdf_mem_malloc(sizeof(tCsrRoamInfo)); + if (NULL == roam_info) { + sms_log(mac_ctx, LOG1, FL("Memory allocation failed!")); + } else { + cdf_mem_copy((void *)roam_info->bssid, + (void *)bssid, sizeof(*roam_info)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + status, 0); + cdf_mem_free(roam_info); + } +} +#else +/* Empty inline function will be a no-op */ +static inline void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirMacAddr bssid, + eRoamCmdStatus status) +{ + ; +} +#endif + +/** + * csr_neighbor_roam_free_neighbor_roam_bss_node() + * + * @mac_ctx: Pointer to Global MAC structure + * @neighborRoamBSSNode: Neighbor Roam BSS Node to be freed + * + * This function frees all the internal pointers CSR NeighborRoam BSS Info + * and also frees the node itself + * + * Return: None + */ +void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo + neighborRoamBSSNode) +{ + if (neighborRoamBSSNode) { + if (neighborRoamBSSNode->pBssDescription) { + cdf_mem_free(neighborRoamBSSNode->pBssDescription); + neighborRoamBSSNode->pBssDescription = NULL; + } + cdf_mem_free(neighborRoamBSSNode); + neighborRoamBSSNode = NULL; + } + + return; +} + +/** + * csr_neighbor_roam_remove_roamable_ap_list_entry() + * + * @mac_ctx: Pointer to Global MAC structure + * @pList: The list from which the entry should be removed + * @pNeighborEntry: Neighbor Roam BSS Node to be removed + * + * This function removes a given entry from the given list + * + * Return: true if successfully removed, else false + */ +bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac, + tDblLinkList *pList, + tpCsrNeighborRoamBSSInfo + pNeighborEntry) +{ + if (pList) { + return csr_ll_remove_entry(pList, &pNeighborEntry->List, + LL_ACCESS_LOCK); + } + + sms_log(pMac, LOGE, + FL + ("Removing neighbor BSS node from list failed. Current count = %d"), + csr_ll_count(pList)); + + return false; +} + +/** + * csr_neighbor_roam_next_roamable_ap() - Get next AP from roamable AP list + * @mac_ctx - The handle returned by mac_open. + * @plist - The list from which the entry should be returned + * @neighbor_entry - Neighbor Roam BSS Node whose next entry should be returned + * + * Gets the entry next to passed entry. If NULL is passed, return the entry + * in the head of the list + * + * Return: Neighbor Roam BSS Node to be returned + */ +tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap( + tpAniSirGlobal mac_ctx, tDblLinkList *llist, + tpCsrNeighborRoamBSSInfo neighbor_entry) +{ + tListElem *entry = NULL; + tpCsrNeighborRoamBSSInfo result = NULL; + + if (llist) { + if (NULL == neighbor_entry) + entry = csr_ll_peek_head(llist, LL_ACCESS_LOCK); + else + entry = csr_ll_next(llist, &neighbor_entry->List, + LL_ACCESS_LOCK); + if (entry) + result = GET_BASE_ADDR(entry, tCsrNeighborRoamBSSInfo, + List); + } + + return result; +} + +/** + * csr_neighbor_roam_free_roamable_bss_list() - Frees roamable APs list + * @mac_ctx: The handle returned by mac_open. + * @llist: Neighbor Roam BSS List to be emptied + * + * Empties and frees all the nodes in the roamable AP list + * + * Return: none + */ +void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx, + tDblLinkList *llist) +{ + tpCsrNeighborRoamBSSInfo result = NULL; + + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOG2, + FL("Emptying the BSS list. Current count = %d"), + csr_ll_count(llist)); + + /* + * Pick up the head, remove and free the node till + * the list becomes empty + */ + while ((result = csr_neighbor_roam_next_roamable_ap(mac_ctx, llist, + NULL)) != NULL) { + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + llist, result); + csr_neighbor_roam_free_neighbor_roam_bss_node(mac_ctx, result); + } + return; +} + +static void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) { + csr_neighbor_roam_issue_preauth_req(pMac, sessionId); + } else { + sms_log(pMac, LOGE, FL("Roaming is diisabled")); + } +} + +CDF_STATUS +csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, + const bool fastRoamEnabled) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + /* set fast roam enable/disable flag */ + pMac->roam.configParam.isFastRoamIniFeatureEnabled = fastRoamEnabled; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + if (true == fastRoamEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } else { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + break; + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL + ("Currently in INIT state, Nothing to do")); + break; + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL + ("Unexpected state %s, returning failure"), + mac_trace_get_neighbour_roam_state + (pNeighborRoamInfo->neighborRoamState)); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +#ifdef FEATURE_WLAN_ESE +CDF_STATUS csr_neighbor_roam_update_ese_mode_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, + const bool eseMode) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + if (true == eseMode) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } else if (false == eseMode) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, + LOG2, + FL + ("Currently in INIT state, Nothing to do")); + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL + ("Unexpected state %d, returning failure"), + pNeighborRoamInfo->neighborRoamState); + break; + } + return cdf_status; +} +#endif + +CDF_STATUS csr_neighbor_roam_set_lookup_rssi_threshold(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t + neighborLookupRssiThreshold) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG.")); + pNeighborRoamInfo->cfgParams.neighborLookupThreshold = + neighborLookupRssiThreshold; + pNeighborRoamInfo->currentNeighborLookupThreshold = + pNeighborRoamInfo->cfgParams.neighborLookupThreshold; + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_LOOKUP_THRESH_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in INIT state, " + "just set lookupRssi threshold.")); + pNeighborRoamInfo->cfgParams.neighborLookupThreshold = + neighborLookupRssiThreshold; + pNeighborRoamInfo->currentNeighborLookupThreshold = + pNeighborRoamInfo->cfgParams.neighborLookupThreshold; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL + ("Unexpected state %s, returning failure"), + mac_trace_get_neighbour_roam_state + (pNeighborRoamInfo->neighborRoamState)); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +CDF_STATUS +csr_neighbor_roam_set_opportunistic_scan_threshold_diff(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t + nOpportunisticThresholdDiff) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG")); + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + + csr_roam_offload_scan(pMac, + sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in INIT state, " + "just set opportunistic threshold diff")); + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL("Unexpected state %d returning failure"), + pNeighborRoamInfo->neighborRoamState); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +CDF_STATUS +csr_neighbor_roam_set_roam_rescan_rssi_diff(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t nRoamRescanRssiDiff) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG.")); + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff = + nRoamRescanRssiDiff; + pNeighborRoamInfo->currentRoamRescanRssiDiff = + nRoamRescanRssiDiff; + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in INIT state, " + "just set rescan rssi diff")); + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff = + nRoamRescanRssiDiff; + pNeighborRoamInfo->currentRoamRescanRssiDiff = + nRoamRescanRssiDiff; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL("Unexpected state %d returning failure"), + pNeighborRoamInfo->neighborRoamState); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +CDF_STATUS +csr_neighbor_roam_set_roam_bmiss_first_bcnt(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t nRoamBmissFirstBcnt) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG.")); + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt = + nRoamBmissFirstBcnt; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = + nRoamBmissFirstBcnt; + + csr_roam_offload_scan(pMac, + sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, + LOG2, FL + ("Currently in INIT state, safe to set roam rescan rssi diff")); + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt = + nRoamBmissFirstBcnt; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = + nRoamBmissFirstBcnt; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, + LOGE, + FL("Unexpected state %d returning failure"), + pNeighborRoamInfo->neighborRoamState); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +CDF_STATUS +csr_neighbor_roam_set_roam_bmiss_final_bcnt(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t nRoamBmissFinalBcnt) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG.")); + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt = + nRoamBmissFinalBcnt; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = + nRoamBmissFinalBcnt; + + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in INIT state, " + "just set roam fianl bmiss count")); + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt = + nRoamBmissFinalBcnt; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = + nRoamBmissFinalBcnt; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, + LOGE, + FL("Unexpected state %d returning failure"), + pNeighborRoamInfo->neighborRoamState); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +CDF_STATUS +csr_neighbor_roam_set_roam_beacon_rssi_weight(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t nRoamBeaconRssiWeight) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in CONNECTED state, " + "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG.")); + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight = + nRoamBeaconRssiWeight; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = + nRoamBeaconRssiWeight; + + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("Currently in INIT state, " + "just set roam beacon rssi weight")); + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight = + nRoamBeaconRssiWeight; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = + nRoamBeaconRssiWeight; + break; + + default: + NEIGHBOR_ROAM_DEBUG(pMac, + LOGE, + FL("Unexpected state %d returning failure"), + pNeighborRoamInfo->neighborRoamState); + cdf_status = CDF_STATUS_E_FAILURE; + break; + } + return cdf_status; +} + +/*CleanUP Routines*/ +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo) +{ + if ((rChInfo->IAPPNeighborListReceived == false) && + (rChInfo->currentChannelListInfo.numOfChannels)) { + rChInfo->currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + rChInfo->currentChannelListInfo.numOfChannels = 0; + + if (rChInfo->currentChannelListInfo.ChannelList) + cdf_mem_free(rChInfo->currentChannelListInfo. + ChannelList); + + rChInfo->currentChannelListInfo.ChannelList = NULL; + } else { + rChInfo->currentChanIndex = 0; + } +} + +static void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + +#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + pNeighborRoamInfo->is11rAssoc = false; + /* Purge pre-auth fail list */ + csr_neighbor_roam_purge_preauth_failed_list(pMac); +#endif + + pNeighborRoamInfo->FTRoamInfo.preauthRspPending = false; + pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0; +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Do not free up the preauth done list here */ + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); +#endif + pNeighborRoamInfo->uOsRequestedHandoff = 0; + cdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +/** + * csr_neighbor_roam_reset_connected_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * any state other than INIT state + * + * Return: None + */ +void csr_neighbor_roam_reset_connected_state_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + csr_neighbor_roam_reset_channel_info(&pNeighborRoamInfo->roamChannelInfo); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Do not free up the preauth done list here */ + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false; + pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + pNeighborRoamInfo->FTRoamInfo.preauthRspPending = 0; + cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); +#endif + pNeighborRoamInfo->uOsRequestedHandoff = 0; + cdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +void csr_neighbor_roam_reset_report_scan_state_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + cdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); +#ifdef FEATURE_WLAN_ESE + pNeighborRoamInfo->isESEAssoc = false; + pNeighborRoamInfo->isVOAdmitted = false; + pNeighborRoamInfo->MinQBssLoadRequired = 0; +#endif + + /* Purge roamable AP list */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + return; +} + +/** + * csr_neighbor_roam_reset_init_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * INIT state + * + * Return: None + */ +void csr_neighbor_roam_reset_init_state_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + csr_neighbor_roam_reset_connected_state_control_info(pMac, sessionId); + + /* In addition to the above resets, + we should clear off the curAPBssId/Session ID in the timers */ + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, sessionId); +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_purge_preauth_fail_list + + \brief This function empties the preauth fail list + + \param pMac - The handle returned by mac_open. + + \return VOID + + ---------------------------------------------------------------------------*/ +void csr_neighbor_roam_purge_preauth_fail_list(tpAniSirGlobal pMac) +{ + uint8_t i; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, FL("Purging the preauth fail list")); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i]; + while (pNeighborRoamInfo->FTRoamInfo.preAuthFailList. + numMACAddress) { + cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList. + macAddress[pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.numMACAddress - + 1], sizeof(tSirMacAddr)); + pNeighborRoamInfo->FTRoamInfo.preAuthFailList. + numMACAddress--; + } + } + return; +} + +/** + * csr_neighbor_roam_add_preauth_fail() - add bssid to preauth failed list + * @mac_ctx: The handle returned by mac_open. + * @bssid: BSSID to be added to the preauth fail list + * + * This function adds the given BSSID to the Preauth fail list + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirMacAddr bssid) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + uint8_t num_mac_addr = neighbor_roam_info->FTRoamInfo.preAuthFailList. + numMACAddress; + + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGE, + FL(" Added BSSID " MAC_ADDRESS_STR " to Preauth failed list"), + MAC_ADDR_ARRAY(bssid)); + + for (i = 0; + i < neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (true == cdf_mem_compare( + neighbor_roam_info->FTRoamInfo.preAuthFailList.macAddress[i], + bssid, sizeof(tSirMacAddr))) { + sms_log(mac_ctx, LOGW, FL("BSSID "MAC_ADDRESS_STR" already present in preauth fail list"), + MAC_ADDR_ARRAY(bssid)); + return CDF_STATUS_SUCCESS; + } + } + + if ((num_mac_addr + 1) > MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS) { + sms_log(mac_ctx, LOGE, + FL("Cannot add, preauth fail list is full.")); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(neighbor_roam_info->FTRoamInfo.preAuthFailList. + macAddress[num_mac_addr], bssid, sizeof(tSirMacAddr)); + neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress++; + + return CDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_is_preauth_candidate() + * + * @mac_ctx: Pointer to Global MAC structure + * @bssId : BSSID of the candidate + * + * This function checks whether the given MAC address is already present + * in the preauth fail list and returns true/false accordingly + * + * Return: true if preauth candidate, false otherwise + */ +bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr bssId) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + return true; + } + if (0 == pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress) + return true; + + for (i = 0; + i < pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (true == + cdf_mem_compare(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.macAddress[i], bssId, + sizeof(tSirMacAddr))) { + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL("BSSID " MAC_ADDRESS_STR + " already present in preauth fail list"), + MAC_ADDR_ARRAY(bssId)); + return false; + } + } + + return true; +} + +/** + * csr_neighbor_roam_issue_preauth_req() - Send preauth request to first AP + * @mac_ctx: The handle returned by mac_open. + * @session_id: Session information + * + * This function issues preauth request to PE with the 1st AP entry in the + * roamable AP list + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +static CDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo neighbor_bss_node; + + + if (false != neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* This must not be true here */ + CDF_ASSERT(neighbor_roam_info->FTRoamInfo.preauthRspPending == + false); + return CDF_STATUS_E_FAILURE; + } + + /* + * Issue Preauth request to PE here. + * Need to issue the preauth request with the BSSID that is in the + * head of the roamable AP list. Parameters that should be passed are + * BSSID, Channel number and the neighborScanPeriod(probably). If + * roamableAPList gets empty, should transition to REPORT_SCAN state + */ + neighbor_bss_node = csr_neighbor_roam_next_roamable_ap(mac_ctx, + &neighbor_roam_info->roamableAPList, NULL); + + if (NULL == neighbor_bss_node) { + sms_log(mac_ctx, LOGW, FL("Roamable AP list is empty.. ")); + return CDF_STATUS_E_FAILURE; + } else { + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_INIT_NOTIFY); + status = csr_roam_enqueue_preauth(mac_ctx, session_id, + neighbor_bss_node->pBssDescription, + eCsrPerformPreauth, true); + + sms_log(mac_ctx, LOG1, + FL("Before Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"), + MAC_ADDR_ARRAY( + neighbor_bss_node->pBssDescription->bssId), + (int)neighbor_bss_node->pBssDescription->channelId); + + if (CDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("Return failed preauth request status %d"), + status); + return status; + } + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = true; + + /* Increment the preauth retry count */ + neighbor_roam_info->FTRoamInfo.numPreAuthRetries++; + + /* Transition the state to preauthenticating */ + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, + session_id) + + return status; +} + +/** + * csr_neighbor_roam_preauth_rsp_handler() - handle preauth response + * @mac_ctx: The handle returned by mac_open. + * @session_id: SME session + * @lim_status: eSIR_SUCCESS/eSIR_FAILURE/eSIR_LIM_MAX_STA_REACHED_ERROR/ + * eSIT_LIM_AUTH_RSP_TIMEOUT status from PE + * + * This function handle the Preauth response from PE + * Every preauth is allowed max 3 tries if it fails. If a bssid failed + * for more than MAX_TRIES, we will remove it from the list and try + * with the next node in the roamable AP list and add the BSSID to + * pre-auth failed list. If no more entries present in roamable AP list, + * transition to REPORT_SCAN state. + * + * Return: CDF_STATUS_SUCCESS on success (i.e. pre-auth processed), + * CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirRetStatus lim_status) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + CDF_STATUS preauth_processed = CDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo preauth_rsp_node = NULL; + + if (false == neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* + * This can happen when we disconnect immediately + * after sending a pre-auth request. During processing + * of the disconnect command, we would have reset + * preauthRspPending and transitioned to INIT state. + */ + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW, + FL("Unexpected pre-auth response in state %d"), + neighbor_roam_info->neighborRoamState); + preauth_processed = CDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + /* We can receive it in these 2 states. */ + if ((neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING)) { + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW, + FL("Preauth response received in state %s"), + mac_trace_get_neighbour_roam_state + (neighbor_roam_info->neighborRoamState)); + preauth_processed = CDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = false; + + if (eSIR_SUCCESS == lim_status) + preauth_rsp_node = + csr_neighbor_roam_next_roamable_ap( + mac_ctx, + &neighbor_roam_info->roamableAPList, + NULL); + if ((eSIR_SUCCESS == lim_status) && (NULL != preauth_rsp_node)) { + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOG1, + FL("Preauth completed successfully after %d tries"), + neighbor_roam_info->FTRoamInfo.numPreAuthRetries); + sms_log(mac_ctx, LOG1, + FL("After Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"), + MAC_ADDR_ARRAY( + preauth_rsp_node->pBssDescription->bssId), + (int)preauth_rsp_node->pBssDescription->channelId); + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + preauth_rsp_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS); + /* + * Preauth completed successfully. Insert the preauthenticated + * node to tail of preAuthDoneList. + */ + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + &neighbor_roam_info->roamableAPList, + preauth_rsp_node); + csr_ll_insert_tail( + &neighbor_roam_info->FTRoamInfo.preAuthDoneList, + &preauth_rsp_node->List, LL_ACCESS_LOCK); + + /* Pre-auth successful. Transition to PREAUTH Done state */ + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, + session_id) + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The caller of this function would start a timer and by + * the time it expires, supplicant should have provided + * the updated FTIEs to SME. So, when it expires, handoff + * will be triggered then. + */ + } else { + tpCsrNeighborRoamBSSInfo neighbor_bss_node = NULL; + tListElem *entry; + + sms_log(mac_ctx, LOGE, + FL("Preauth failed retry number %d, status = 0x%x"), + neighbor_roam_info->FTRoamInfo.numPreAuthRetries, + lim_status); + + /* + * Preauth failed. Add the bssId to the preAuth failed list + * of MAC Address. Also remove the AP from roamable AP list. + */ + if ((neighbor_roam_info->FTRoamInfo.numPreAuthRetries >= + CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES) || + (eSIR_LIM_MAX_STA_REACHED_ERROR == lim_status)) { + /* + * We are going to remove the node as it fails for + * more than MAX tries. Reset this count to 0 + */ + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The one in the head of the list should be one with + * which we issued pre-auth and failed + */ + entry = csr_ll_remove_head( + &neighbor_roam_info->roamableAPList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, + FL("Preauth list is empty")); + goto NEXT_PREAUTH; + } + neighbor_bss_node = GET_BASE_ADDR(entry, + tCsrNeighborRoamBSSInfo, + List); + /* + * Add the BSSID to pre-auth fail list if + * it is not requested by HDD + */ + if (!neighbor_roam_info->uOsRequestedHandoff) + status = + csr_neighbor_roam_add_preauth_fail( + mac_ctx, session_id, + neighbor_bss_node-> + pBssDescription->bssId); + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, + session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_FAILURE); + /* Now we can free this node */ + csr_neighbor_roam_free_neighbor_roam_bss_node( + mac_ctx, neighbor_bss_node); + } +NEXT_PREAUTH: + /* Issue preauth request for the same/next entry */ + if (CDF_STATUS_SUCCESS == csr_neighbor_roam_issue_preauth_req( + mac_ctx, session_id)) + goto DEQ_PREAUTH; + + if (csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + if (neighbor_roam_info->uOsRequestedHandoff) { + neighbor_roam_info->uOsRequestedHandoff = 0; + csr_roam_offload_scan(mac_ctx, 0, + ROAM_SCAN_OFFLOAD_START, + REASON_PREAUTH_FAILED_FOR_ALL); + } else { + csr_roam_offload_scan(mac_ctx, 0, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_PREAUTH_FAILED_FOR_ALL); + } + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, + session_id); + } + } + +DEQ_PREAUTH: + csr_dequeue_roam_command(mac_ctx, eCsrPerformPreauth); + return preauth_processed; +} +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * csr_neighbor_roam_offload_update_preauth_list() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @roam_sync_ind_ptr: Roam offload sync Ind Info + * + * This function handles the RoamOffloadSynch and adds the + * roamed AP to the preauth done list + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS +csr_neighbor_roam_offload_update_preauth_list(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_sync_ind_ptr, uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info_ptr = + &pMac->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamBSSInfo bss_info_ptr; + uint16_t bss_desc_len; + + if (neighbor_roam_info_ptr->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) { + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, + FL("LFR3:Roam Offload Synch Ind received in state %d"), + neighbor_roam_info_ptr->neighborRoamState); + return CDF_STATUS_E_FAILURE; + } + + bss_info_ptr = cdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo)); + if (NULL == bss_info_ptr) { + sms_log(pMac, LOGE, + FL("LFR3:Memory allocation for Neighbor Roam BSS Info failed")); + return CDF_STATUS_E_NOMEM; + } + bss_desc_len = roam_sync_ind_ptr->bss_desc_ptr->length + + sizeof(roam_sync_ind_ptr->bss_desc_ptr->length); + bss_info_ptr->pBssDescription = cdf_mem_malloc(bss_desc_len); + if (bss_info_ptr->pBssDescription != NULL) { + cdf_mem_copy(bss_info_ptr->pBssDescription, + roam_sync_ind_ptr->bss_desc_ptr, + bss_desc_len); + } else { + sms_log(pMac, LOGE, + FL("LFR3:Mem alloc for Neighbor Roam BSS Descriptor failed")); + cdf_mem_free(bss_info_ptr); + return CDF_STATUS_E_NOMEM; + + } + csr_ll_insert_tail(&neighbor_roam_info_ptr->FTRoamInfo.preAuthDoneList, + &bss_info_ptr->List, LL_ACCESS_LOCK); + + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (pMac, eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, session_id) + neighbor_roam_info_ptr->FTRoamInfo.numPreAuthRetries = 0; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR3:Entry added to Auth Done List"); + + return CDF_STATUS_SUCCESS; +} +#endif +/** + * csr_neighbor_roam_prepare_scan_profile_filter() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @scan_filter: Populated scan filter based on the connected profile + * + * This function creates a scan filter based on the currently + * connected profile. Based on this filter, scan results are obtained + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS +csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo nbr_roam_info = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + uint8_t i = 0; + struct roam_ext_params *roam_params; + uint8_t num_ch = 0; + + CDF_ASSERT(pScanFilter != NULL); + if (pScanFilter == NULL) + return CDF_STATUS_E_FAILURE; + + cdf_mem_zero(pScanFilter, sizeof(tCsrScanResultFilter)); + roam_params = &pMac->roam.configParam.roam_params; + /* We dont want to set BSSID based Filter */ + pScanFilter->BSSIDs.numOfBSSIDs = 0; + pScanFilter->scan_filter_for_roam = 1; + /* only for HDD requested handoff fill in the BSSID in the filter */ + if (nbr_roam_info->uOsRequestedHandoff) { + pScanFilter->BSSIDs.numOfBSSIDs = 1; + pScanFilter->BSSIDs.bssid = + cdf_mem_malloc(sizeof(tSirMacAddr) * + pScanFilter->BSSIDs.numOfBSSIDs); + if (NULL == pScanFilter->BSSIDs.bssid) { + sms_log(pMac, LOGE, + FL("Scan Filter BSSID mem alloc failed")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pScanFilter->BSSIDs.bssid, + sizeof(tSirMacAddr) * + pScanFilter->BSSIDs.numOfBSSIDs); + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < pScanFilter->BSSIDs.numOfBSSIDs; i++) { + cdf_copy_macaddr(&pScanFilter->BSSIDs.bssid[i], + &nbr_roam_info->handoffReqInfo.bssid); + } + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("No of Allowed SSID List:%d"), + roam_params->num_ssid_allowed_list); + if (roam_params->num_ssid_allowed_list) { + pScanFilter->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + pScanFilter->SSIDs.SSIDList = + cdf_mem_malloc(sizeof(tCsrSSIDInfo) * + pScanFilter->SSIDs.numOfSSIDs); + if (NULL == pScanFilter->SSIDs.SSIDList) { + sms_log(pMac, LOGE, + FL("Scan Filter SSID mem alloc failed")); + return CDF_STATUS_E_NOMEM; + } + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + pScanFilter->SSIDs.SSIDList[i].handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList[i].ssidHidden = 0; + cdf_mem_copy((void *) + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + pScanFilter->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + } + } else { + /* Populate all the information from the connected profile */ + pScanFilter->SSIDs.numOfSSIDs = 1; + pScanFilter->SSIDs.SSIDList = + cdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == pScanFilter->SSIDs.SSIDList) { + sms_log(pMac, LOGE, + FL("Scan Filter SSID mem alloc failed")); + return CDF_STATUS_E_NOMEM; + } + pScanFilter->SSIDs.SSIDList->handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList->ssidHidden = 0; + pScanFilter->SSIDs.SSIDList->SSID.length = + pCurProfile->SSID.length; + cdf_mem_copy((void *)pScanFilter->SSIDs.SSIDList->SSID.ssId, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length); + + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Filtering for SSID %.*s,length of SSID = %u"), + pScanFilter->SSIDs.SSIDList->SSID.length, + pScanFilter->SSIDs.SSIDList->SSID.ssId, + pScanFilter->SSIDs.SSIDList->SSID.length); + } + pScanFilter->authType.numEntries = 1; + pScanFilter->authType.authType[0] = pCurProfile->AuthType; + + pScanFilter->EncryptionType.numEntries = 1; /* This must be 1 */ + pScanFilter->EncryptionType.encryptionType[0] = + pCurProfile->EncryptionType; + + pScanFilter->mcEncryptionType.numEntries = 1; + pScanFilter->mcEncryptionType.encryptionType[0] = + pCurProfile->mcEncryptionType; + + pScanFilter->BSSType = pCurProfile->BSSType; + + num_ch = + nbr_roam_info->roamChannelInfo.currentChannelListInfo.numOfChannels; + if (num_ch) { + /* + * We are intrested only in the scan results on channels we + * scanned + */ + pScanFilter->ChannelInfo.numOfChannels = num_ch; + pScanFilter->ChannelInfo.ChannelList = + cdf_mem_malloc(num_ch * sizeof(uint8_t)); + if (NULL == pScanFilter->ChannelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Scan Filter Ch list mem alloc failed")); + cdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + return CDF_STATUS_E_NOMEM; + } + for (i = 0; i < pScanFilter->ChannelInfo.numOfChannels; i++) { + pScanFilter->ChannelInfo.ChannelList[i] = + nbr_roam_info->roamChannelInfo.currentChannelListInfo. + ChannelList[i]; + } + } else { + pScanFilter->ChannelInfo.numOfChannels = 0; + pScanFilter->ChannelInfo.ChannelList = NULL; + } + +#ifdef WLAN_FEATURE_VOWIFI_11R + if (nbr_roam_info->is11rAssoc) { + /* + * MDIE should be added as a part of profile. This should be + * added as a part of filter as well + */ + pScanFilter->MDID.mdiePresent = pCurProfile->MDID.mdiePresent; + pScanFilter->MDID.mobilityDomain = + pCurProfile->MDID.mobilityDomain; + } +#endif + +#ifdef WLAN_FEATURE_11W + pScanFilter->MFPEnabled = pCurProfile->MFPEnabled; + pScanFilter->MFPRequired = pCurProfile->MFPRequired; + pScanFilter->MFPCapable = pCurProfile->MFPCapable; +#endif + return CDF_STATUS_SUCCESS; +} + +uint32_t csr_get_current_ap_rssi(tpAniSirGlobal pMac, + tScanResultHandle *pScanResultList, + uint8_t sessionId) +{ + tCsrScanResultInfo *pScanResult; + tpCsrNeighborRoamControlInfo nbr_roam_info = + &pMac->roam.neighborRoamInfo[sessionId]; + /* We are setting this as default value to make sure we return this value, + when we do not see this AP in the scan result for some reason.However,it is + less likely that we are associated to an AP and do not see it in the scan list */ + uint32_t CurrAPRssi = -125; + + while (NULL != + (pScanResult = csr_scan_result_get_next(pMac, *pScanResultList))) { + if (true == + cdf_mem_compare(pScanResult->BssDescriptor.bssId, + nbr_roam_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + /* We got a match with the currently associated AP. + * Capture the RSSI value and complete the while loop. + * The while loop is completed in order to make the current entry go back to NULL, + * and in the next while loop, it properly starts searching from the head of the list. + * TODO: Can also try setting the current entry directly to NULL as soon as we find the new AP*/ + + CurrAPRssi = + (int)pScanResult->BssDescriptor.rssi * (-1); + + } else { + continue; + } + } + + return CurrAPRssi; + +} + +/** + * csr_neighbor_roam_process_scan_results() - build roaming candidate list + * + * @mac_ctx: The handle returned by mac_open. + * @sessionid: Session information + * @scan_results_list: List obtained from csr_scan_get_result() + * + * This function applies various candidate checks like LFR, 11r, preauth, ESE + * and builds a roamable AP list. It applies age limit only if no suitable + * recent candidates are found. + * + * Output list is built in mac_ctx->roam.neighborRoamInfo[sessionid]. + * + * Return: void + */ + +static void +csr_neighbor_roam_process_scan_results(tpAniSirGlobal mac_ctx, + uint8_t sessionid, + tScanResultHandle *scan_results_list) +{ + tCsrScanResultInfo *scan_result; + tpCsrNeighborRoamControlInfo n_roam_info = + &mac_ctx->roam.neighborRoamInfo[sessionid]; + tpCsrNeighborRoamBSSInfo bss_info; + uint32_t cur_ap_rssi; + uint32_t age_ticks = 0; + uint32_t limit_ticks = + cdf_system_msecs_to_ticks(ROAM_AP_AGE_LIMIT_MS); + uint8_t num_candidates = 0; + uint8_t num_dropped = 0; + /* + * first iteration of scan list should consider + * age constraint for candidates + */ + bool age_constraint = true; +#ifdef FEATURE_WLAN_ESE + uint16_t qpresent; + uint16_t qavail; + bool voadmitted; +#endif + /* + * Find out the Current AP RSSI and keep it handy to check if + * it is better than the RSSI of the AP which we are + * going to roam.If so, we are going to continue with the + * current AP. + */ + cur_ap_rssi = csr_get_current_ap_rssi(mac_ctx, scan_results_list, + sessionid); + + /* + * Expecting the scan result already to be in the sorted order based on + * RSSI. Based on the previous state we need to check whether the list + * should be sorted again taking neighbor score into consideration. If + * previous state is CFG_CHAN_LIST_SCAN, there should not be a neighbor + * score associated with any of the BSS. If the previous state is + * REPORT_QUERY, then there will be neighbor score for each of the APs. + * For now, let us take top of the list provided as it is by CSR Scan + * result API. Hence it is assumed that neighbor score and rssi score + * are in the same order. This will be taken care later. + */ + + do { + while (true) { + tSirBssDescription *descr; + + scan_result = csr_scan_result_get_next( + mac_ctx, *scan_results_list); + if (NULL == scan_result) + break; + descr = &scan_result->BssDescriptor; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("Scan result: BSSID " MAC_ADDRESS_STR + " (Rssi %ld, Ch:%d)"), + MAC_ADDR_ARRAY(descr->bssId), + abs(descr->rssi), descr->channelId); + + if (true == cdf_mem_compare(descr->bssId, + n_roam_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + /* + * currently associated AP. Do not have this + * in the roamable AP list + */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "SKIP-currently associated AP"); + continue; + } +#ifdef FEATURE_WLAN_LFR + /* + * In case of reassoc requested by upper layer, look + * for exact match of bssid & channel. csr cache might + * have duplicates + */ + if ((n_roam_info->uOsRequestedHandoff) && + ((false == cdf_mem_compare(descr->bssId, + n_roam_info->handoffReqInfo.bssid.bytes, + sizeof(tSirMacAddr))) + || (descr->channelId != + n_roam_info->handoffReqInfo.channel))) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "SKIP-not a candidate AP for OS requested roam"); + continue; + } +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + if ((n_roam_info->is11rAssoc) && + (!csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId))) { + sms_log(mac_ctx, LOGE, + FL("BSSID present in pre-auth fail list.. Ignoring")); + continue; + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +#ifdef FEATURE_WLAN_ESE + if (!csr_roam_is_roam_offload_scan_enabled(mac_ctx) && + (n_roam_info->isESEAssoc) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sms_log(mac_ctx, LOGE, + FL("BSSID present in pre-auth fail list.. Ignoring")); + continue; + } + + qpresent = descr->QBSSLoad_present; + qavail = descr->QBSSLoad_avail; + voadmitted = n_roam_info->isVOAdmitted; + if (voadmitted) + sms_log(mac_ctx, LOG1, + FL("New AP QBSS present = %s, BW available = 0x%x, required = 0x%x"), + ((qpresent) ? "yes" : "no"), qavail, + n_roam_info->MinQBssLoadRequired); + if (voadmitted && qpresent && + (qavail < n_roam_info->MinQBssLoadRequired)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "BSSID : " MAC_ADDRESS_STR " has no bandwidth, ignoring", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } + if (voadmitted && !qpresent) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "BSSID : " MAC_ADDRESS_STR " has no QBSS LOAD IE, ignoring", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } +#endif /* FEATURE_WLAN_ESE */ + +#ifdef FEATURE_WLAN_LFR + /* + * If we are supporting legacy roaming, and + * if the candidate is on the "pre-auth failed" list, + * ignore it. + */ + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionid) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sms_log(mac_ctx, LOGE, + FL("BSSID present in pre-auth fail list.. Ignoring")); + continue; + } +#endif /* FEATURE_WLAN_LFR */ + + /* check the age of the AP */ + age_ticks = (uint32_t) cdf_mc_timer_get_system_ticks() - + descr->nReceivedTime; + if (age_constraint == true && age_ticks > limit_ticks) { + num_dropped++; + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_WARN, + FL("Old AP (probe rsp/beacon) skipped.") + ); + continue; + } + + /* Finished all checks, now add it to candidate list */ + bss_info = + cdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo)); + if (NULL == bss_info) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed. Ignored candidate.")); + continue; + } + bss_info->pBssDescription = + cdf_mem_malloc(descr->length + + sizeof(descr->length)); + if (bss_info->pBssDescription != NULL) { + cdf_mem_copy(bss_info->pBssDescription, descr, + descr->length + sizeof(descr->length)); + } else { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed. Ignored candidate.")); + cdf_mem_free(bss_info); + continue; + } + /* + * Assign some preference value for now. Need to + * calculate theactual score based on RSSI and neighbor + * AP score + */ + bss_info->apPreferenceVal = 10; + num_candidates++; + csr_ll_insert_tail(&n_roam_info->roamableAPList, + &bss_info->List, LL_ACCESS_LOCK); + } /* end of while (csr_scan_result_get_next) */ + + /* if some candidates were found, then no need to repeat */ + if (num_candidates) + break; + /* + * if age_constraint is already false, we have done two + * iterations and no candidate were found + */ + if (age_constraint == false) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: No roam able candidates found", + __func__); + break; + } + /* + * if all candidates were dropped rescan the scan + * list but this time without age constraint. + */ + age_constraint = false; + /* if no candidates were dropped no need to repeat */ + } while (num_dropped); + + /* + * Now we have all the scan results in our local list. Good time to free + * up the the list we got as a part of csrGetScanResult + */ + csr_scan_result_purge(mac_ctx, *scan_results_list); +} + +static CDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrScanResultFilter scanFilter; + tScanResultHandle scanResult; + uint32_t tempVal = 0; + CDF_STATUS hstatus; + + hstatus = csr_neighbor_roam_prepare_scan_profile_filter(pMac, + &scanFilter, + sessionId); + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, + FL + ("11R/ESE/Other Association: Prepare scan to find neighbor AP filter status = %d"), + hstatus); + if (CDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL + ("Scan Filter preparation failed for Assoc type %d.. Bailing out.."), + tempVal); + return CDF_STATUS_E_FAILURE; + } + hstatus = csr_scan_get_result(pMac, &scanFilter, &scanResult); + if (hstatus != CDF_STATUS_SUCCESS) { + NEIGHBOR_ROAM_DEBUG(pMac, LOGE, + FL("Get Scan Result status code %d"), + hstatus); + } + /* Process the scan results and update roamable AP list */ + csr_neighbor_roam_process_scan_results(pMac, sessionId, &scanResult); + + /* Free the scan filter */ + csr_free_scan_filter(pMac, &scanFilter); + + tempVal = csr_ll_count(&pNeighborRoamInfo->roamableAPList); + + if (tempVal) { + csr_neighbor_roam_trigger_handoff(pMac, sessionId); + return CDF_STATUS_SUCCESS; + } + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + if (pNeighborRoamInfo->uOsRequestedHandoff) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } else { + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan */ + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + } + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (pMac, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, sessionId); + } + return CDF_STATUS_SUCCESS; + +} + + +#if defined WLAN_FEATURE_VOWIFI_11R && defined WLAN_FEATURE_VOWIFI +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The input channel list + * @input_num_of_ch: The number of channels in input channel list + * @output_ch_list: The output channel list + * @output_num_of_ch: The number of channels in output channel list + * @merged_output_num_of_ch: The final number of channels in the + * output channel list. + * + * This function is used to filter out the channels based on the + * currently associated AP channel + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS csr_neighbor_roam_channels_filter_by_current_band(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t * + pInputChannelList, + uint8_t + inputNumOfChannels, + uint8_t * + pOutputChannelList, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t numChannels = 0; + uint8_t currAPoperationChannel = + pMac->roam.neighborRoamInfo[sessionId].currAPoperationChannel; + /* Check for NULL pointer */ + if (!pInputChannelList) + return CDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return CDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return CDF_STATUS_E_INVAL; + } + for (i = 0; i < inputNumOfChannels; i++) { + if (get_rf_band(currAPoperationChannel) == + get_rf_band(pInputChannelList[i])) { + pOutputChannelList[numChannels] = pInputChannelList[i]; + numChannels++; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return CDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The additional channels to merge in to the + * "merged" channels list. + * @input_num_of_ch: The number of additional channels. + * @output_ch_list: The place to put the "merged" channel list. + * @output_num_of_ch: The original number of channels in the + * "merged" channels list. + * @merged_output_num_of_ch: The final number of channels in the + * "merged" channel list. + * + * This function is used to merge two channel list. + * NB: If called with outputNumOfChannels == 0, this routines simply + * copies the input channel list to the output channel list. if number + * of merged channels are more than 100, num of channels set to 100 + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t numChannels = outputNumOfChannels; + + /* Check for NULL pointer */ + if (!pInputChannelList) + return CDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return CDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return CDF_STATUS_E_INVAL; + } + if (outputNumOfChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Output Channels %d", + __func__, outputNumOfChannels); + return CDF_STATUS_E_INVAL; + } + /* Add the "new" channels in the input list to the end of the output list. */ + for (i = 0; i < inputNumOfChannels; i++) { + for (j = 0; j < outputNumOfChannels; j++) { + if (pInputChannelList[i] == pOutputChannelList[j]) + break; + } + if (j == outputNumOfChannels) { + if (pInputChannelList[i]) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "%s: [INFOLOG] Adding extra %d to Neighbor channel list", + __func__, pInputChannelList[i]); + pOutputChannelList[numChannels] = + pInputChannelList[i]; + numChannels++; + } + } + if (numChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Merge Neighbor channel list reached Max " + "limit %d", __func__, numChannels); + break; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return CDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_create_chan_list_from_neighbor_report() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function is invoked when neighbor report is received for the + * neighbor request. Based on the channels present in the neighbor report, + * it generates channel list which will be used in REPORT_SCAN state to + * scan for these neighbor APs + * + * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise + */ +CDF_STATUS csr_neighbor_roam_create_chan_list_from_neighbor_report(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpRrmNeighborReportDesc pNeighborBssDesc; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + uint8_t numChannels = 0; + uint8_t i = 0; + uint8_t channelList[MAX_BSS_IN_NEIGHBOR_RPT]; + uint8_t mergedOutputNumOfChannels = 0; + + /* This should always start from 0 whenever we create a channel list out of neighbor AP list */ + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + + pNeighborBssDesc = sme_rrm_get_first_bss_entry_from_neighbor_cache(pMac); + + while (pNeighborBssDesc) { + if (pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport >= + MAX_BSS_IN_NEIGHBOR_RPT) + break; + + /* Update the neighbor BSS Info in the 11r FT Roam Info */ + pNeighborRoamInfo->FTRoamInfo. + neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo. + numBssFromNeighborReport].channelNum = + pNeighborBssDesc->pNeighborBssDescription->channel; + pNeighborRoamInfo->FTRoamInfo. + neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo. + numBssFromNeighborReport]. + neighborScore = (uint8_t) pNeighborBssDesc->roamScore; + cdf_mem_copy(pNeighborRoamInfo->FTRoamInfo. + neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo. + numBssFromNeighborReport]. + neighborBssId, + pNeighborBssDesc->pNeighborBssDescription->bssId, + sizeof(tSirMacAddr)); + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport++; + + /* Saving the channel list non-redundantly */ + for (i = 0; (i < numChannels && i < MAX_BSS_IN_NEIGHBOR_RPT); + i++) { + if (pNeighborBssDesc->pNeighborBssDescription-> + channel == channelList[i]) + break; + } + + if (i == numChannels) { + if (pNeighborBssDesc->pNeighborBssDescription->channel) { + if (CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) { + /* Make sure to add only if its the same band */ + if (get_rf_band + (pNeighborRoamInfo-> + currAPoperationChannel) == + get_rf_band(pNeighborBssDesc-> + pNeighborBssDescription-> + channel)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "%s: [INFOLOG] Adding %d to Neighbor channel list (Same band)\n", + __func__, + pNeighborBssDesc-> + pNeighborBssDescription-> + channel); + channelList[numChannels] = + pNeighborBssDesc-> + pNeighborBssDescription-> + channel; + numChannels++; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "%s: [INFOLOG] Adding %d to Neighbor channel list\n", + __func__, + pNeighborBssDesc-> + pNeighborBssDescription-> + channel); + channelList[numChannels] = + pNeighborBssDesc-> + pNeighborBssDescription->channel; + numChannels++; + } + } + } + + pNeighborBssDesc = + sme_rrm_get_next_bss_entry_from_neighbor_cache(pMac, + pNeighborBssDesc); + } + + if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + cdf_mem_free(pNeighborRoamInfo->roamChannelInfo. + currentChannelListInfo.ChannelList); + } + + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + /* Store the obtained channel list to the Neighbor Control data structure */ + if (numChannels) + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList = + cdf_mem_malloc((numChannels) * sizeof(uint8_t)); + if (NULL == + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + sms_log(pMac, LOGE, + FL + ("Memory allocation for Channel list failed.. TL event ignored")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_copy(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList, channelList, (numChannels) * sizeof(uint8_t)); + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = numChannels; + /* + * Create a Union of occupied channel list learnt by the DUT along with the Neighbor + * report Channels. This increases the chances of the DUT to get a candidate AP while + * roaming even if the Neighbor Report is not able to provide sufficient information. + * */ + if (pMac->scan.occupiedChannels[sessionId].numChannels) { + csr_neighbor_roam_merge_channel_lists(pMac, + &pMac->scan. + occupiedChannels[sessionId]. + channelList[0], + pMac->scan. + occupiedChannels[sessionId]. + numChannels, + &pNeighborRoamInfo-> + roamChannelInfo. + currentChannelListInfo. + ChannelList[0], + pNeighborRoamInfo-> + roamChannelInfo. + currentChannelListInfo. + numOfChannels, + &mergedOutputNumOfChannels); + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = mergedOutputNumOfChannels; + + } + /*Indicate the firmware about the update only if any new channels are added. + * Otherwise, the firmware would already be knowing the non-IAPPneighborlist + * channels. There is no need to update.*/ + if (numChannels) { + sms_log(pMac, LOG1, + FL("IAPP Neighbor list callback received as expected" + "in state %s."), + mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> + neighborRoamState)); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + true; + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + } + } + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = 0; + + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +#ifdef FEATURE_WLAN_LFR +/** + * csr_neighbor_roam_is_ssid_and_security_match() - to match ssid/security + * @pMac: Pointer to mac context + * @pCurProfile: pointer to current roam profile + * @pBssDesc: pointer to bss description + * @pIes: pointer to local ies + * + * This routine will be called to see if SSID and security parameters + * are matching. + * + * Return: bool + */ +bool csr_neighbor_roam_is_ssid_and_security_match(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pCurProfile, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes) +{ + tCsrAuthList authType; + tCsrEncryptionList uCEncryptionType; + tCsrEncryptionList mCEncryptionType; + bool fMatch = false; + + authType.numEntries = 1; + authType.authType[0] = pCurProfile->AuthType; + uCEncryptionType.numEntries = 1; + uCEncryptionType.encryptionType[0] = pCurProfile->EncryptionType; + mCEncryptionType.numEntries = 1; + mCEncryptionType.encryptionType[0] = pCurProfile->mcEncryptionType; + + /* Again, treat missing pIes as a non-match. */ + if (!pIes) + return false; + + /* Treat a missing SSID as a non-match. */ + if (!pIes->SSID.present) + return false; + + fMatch = csr_is_ssid_match(pMac, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length, + pIes->SSID.ssid, + pIes->SSID.num_ssid, true); + if (true == fMatch) { + /* + * for now we are sending NULL for all PMF related filter + * parameters during roam to the neighbor AP because + * so far 80211W spec doesn't specify anything about + * roaming scenario. + * + * Once roaming scenario is defined, we should re-visit + * this section and remove this comment. + */ + fMatch = csr_is_security_match(pMac, &authType, + &uCEncryptionType, + &mCEncryptionType, NULL, + NULL, NULL, pBssDesc, + pIes, NULL, NULL, NULL); + return fMatch; + } else { + return fMatch; + } + +} + +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurrProfile = NULL; + tCsrRoamConnectedProfile *pPrevProfile = NULL; + tDot11fBeaconIEs *pIes = NULL; + tSirBssDescription *pBssDesc = NULL; + bool fNew = true; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) { + return fNew; + } + + pCurrProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + if (!pCurrProfile) { + return fNew; + } + + pPrevProfile = &pNeighborRoamInfo->prevConnProfile; + if (!pPrevProfile) { + return fNew; + } + + pBssDesc = pPrevProfile->pBssDesc; + if (pBssDesc) { + if (CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, &pIes)) + && csr_neighbor_roam_is_ssid_and_security_match(pMac, + pCurrProfile, pBssDesc, pIes)) { + fNew = false; + } + if (pIes) { + cdf_mem_free(pIes); + } + } + + if (fNew) { + sms_log(pMac, LOG1, + FL("Prev roam profile did not match current")); + } else { + sms_log(pMac, LOG1, FL("Prev roam profile matches current")); + } + + return fNew; +} + +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes) +{ + tCsrRoamConnectedProfile *pCurProfile = NULL; + tSirBssDescription *pBssDesc = &pResult->Result.BssDescriptor; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) { + return false; + } + + pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + + if (!pCurProfile) { + return false; + } + + return csr_neighbor_roam_is_ssid_and_security_match(pMac, pCurProfile, + pBssDesc, pIes); +} + +/** + * csr_neighbor_roam_prepare_non_occupied_channel_list() - prepare non-occup CL + * @pMac: The handle returned by mac_open + * @pInputChannelList: The default channels list + * @numOfChannels: The number of channels in the default channels list + * @pOutputChannelList: The place to put the non-occupied channel list + * @pOutputNumOfChannels: Number of channels in the non-occupied channel list + * + * This function is used to prepare a channel list that is derived from + * the list of valid channels and does not include those in the occupied list + * + * Return CDF_STATUS + */ +CDF_STATUS +csr_neighbor_roam_prepare_non_occupied_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t *pInputChannelList, + uint8_t numOfChannels, uint8_t *pOutputChannelList, + uint8_t *pOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t outputNumOfChannels = 0; + uint8_t numOccupiedChannels = + pMac->scan.occupiedChannels[sessionId].numChannels; + uint8_t *pOccupiedChannelList = + pMac->scan.occupiedChannels[sessionId].channelList; + + for (i = 0; i < numOfChannels; i++) { + if (csr_is_channel_present_in_list + (pOccupiedChannelList, numOccupiedChannels, + pInputChannelList[i])) + continue; + /* + * DFS channel will be added in the list only when the + * DFS Roaming scan flag is enabled + */ + if (CDS_IS_DFS_CH(pInputChannelList[i])) { + if (CSR_ROAMING_DFS_CHANNEL_DISABLED != + pMac->roam.configParam.allowDFSChannelRoam) { + pOutputChannelList[outputNumOfChannels++] = + pInputChannelList[i]; + } + } else { + pOutputChannelList[outputNumOfChannels++] = + pInputChannelList[i]; + } + } + + sms_log(pMac, LOG2, + FL("Number of channels in the valid channel list=%d; " + "Number of channels in the non-occupied list list=%d"), + numOfChannels, outputNumOfChannels); + + /* Return the number of channels */ + *pOutputNumOfChannels = outputNumOfChannels; + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_LFR */ + +/** + * csr_roam_reset_roam_params - API to reset the roaming parameters + * @mac_ctx: Pointer to the global MAC structure + * + * The BSSID blacklist should not be cleared since it has to + * be used across connections. These parameters will be cleared + * and sent to firmware with with the roaming STOP command. + * + * Return: VOID + */ +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ctx) +{ + struct roam_ext_params *roam_params = NULL; + + /* + * clear all the whitelist parameters and remaining + * needs to be retained across connections. + */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("Roaming parameters are reset")); + roam_params = &mac_ctx->roam.configParam.roam_params; + roam_params->num_ssid_allowed_list = 0; + cdf_mem_set(&roam_params->ssid_allowed_list, 0, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); +} + +/** + * csr_neighbor_roam_indicate_disconnect() - To indicate disconnect + * @pMac: The handle returned by mac_open + * @sessionId: CSR session id that got disconnected + * + * This function is called by CSR as soon as the station disconnects + * from the AP. This function does the necessary cleanup of neighbor roam + * data structures. Neighbor roam state transitions to INIT state whenever + * this function is called except if the current state is REASSOCIATING + * + * Return: CDF_STATUS + */ +CDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; +#ifdef FEATURE_WLAN_LFR + tCsrRoamConnectedProfile *pPrevProfile = + &pNeighborRoamInfo->prevConnProfile; +#endif + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrRoamSession *roam_session = NULL; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Disconn ind on session %d in state %d from bss :" + MAC_ADDRESS_STR), sessionId, + pNeighborRoamInfo->neighborRoamState, + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes)); +#ifdef FEATURE_WLAN_LFR + /* + * Free the current previous profile and move + * the current profile to prev profile. + */ + csr_roam_free_connect_profile(pMac, pPrevProfile); + csr_roam_copy_connect_profile(pMac, sessionId, pPrevProfile); +#endif + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (!csr_neighbor_middle_of_roaming((tHalHandle)pMac, sessionId)) + csr_roam_reset_roam_params(pMac); + if (NULL != pSession) { + roam_session = &pMac->roam.roamSession[sessionId]; + if (NULL != pSession->pCurRoamProfile && (CDF_STA_MODE != + roam_session->pCurRoamProfile->csrPersona)) { + sms_log(pMac, LOGE, + FL("Ignore disconn ind rcvd from nonSTA persona" + "sessionId: %d, csrPersonna %d"), + sessionId, + (int)roam_session->pCurRoamProfile->csrPersona); + return CDF_STATUS_SUCCESS; + } +#ifdef FEATURE_WLAN_ESE + if (pSession->connectedProfile.isESEAssoc) { + cdf_mem_copy(&pSession->prevApSSID, + &pSession->connectedProfile.SSID, + sizeof(tSirMacSSid)); + cdf_copy_macaddr(&pSession->prevApBssid, + &pSession->connectedProfile.bssid); + pSession->prevOpChannel = + pSession->connectedProfile.operationChannel; + pSession->isPrevApInfoValid = true; + pSession->roamTS1 = cdf_mc_timer_get_system_time(); + } +#endif + } + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + /* + * Stop scan and neighbor refresh timers. + * These are indeed not required when we'r in reassoc state. + */ + if (!CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + /* + * Disconnect indication during Disassoc Handoff + * sub-state is received when we are trying to + * disconnect with the old AP during roam. + * BUT, if receive a disconnect indication outside of + * Disassoc Handoff sub-state, then it means that + * this is a genuine disconnect and we need to clean up. + * Otherwise, we will be stuck in reassoc state which'll + * in-turn block scans. + */ + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, + sessionId); + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + } + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + csr_neighbor_roam_reset_init_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + CSR_NEIGHBOR_ROAM_STATE_TRANSITION( + pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId) + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_connected_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE: + /* Stop pre-auth to reassoc interval timer */ + cdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING: + CSR_NEIGHBOR_ROAM_STATE_TRANSITION( + pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId) + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_preauth_control_info(pMac, sessionId); + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, + sessionId); + break; + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Received disconnect event" + "in state %s "), + mac_trace_get_neighbour_roam_state( + pNeighborRoamInfo->neighborRoamState)); + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Transit to INIT state")); + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId) + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + break; + } + /*Inform the Firmware to STOP Scanning as the host has a disconnect. */ + if (csr_roam_is_sta_mode(pMac, sessionId)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_info_ctx_init() - Initialize neighbor roam struct + * @pMac: mac context + * @session_id: Session Id + * + * This initializes all the necessary data structures related to the + * associated AP. + * + * Return: CDF status + */ +static void csr_neighbor_roam_info_ctx_init( + tpAniSirGlobal pMac, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tCsrRoamSession *session = &pMac->roam.roamSession[session_id]; + +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + int init_ft_flag = false; +#endif + +#ifdef FEATURE_WLAN_LFR + /* + * Initialize the occupied list ONLY if we are + * transitioning from INIT state to CONNECTED state. + */ + if (eCSR_NEIGHBOR_ROAM_STATE_INIT == + ngbr_roam_info->neighborRoamState) + csr_init_occupied_channels_list(pMac, session_id); +#endif + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (pMac, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id); + + cdf_copy_macaddr(&ngbr_roam_info->currAPbssid, + &session->connectedProfile.bssid); + ngbr_roam_info->currAPoperationChannel = + session->connectedProfile.operationChannel; + ngbr_roam_info->currentNeighborLookupThreshold = + ngbr_roam_info->cfgParams.neighborLookupThreshold; + ngbr_roam_info->currentOpportunisticThresholdDiff = + ngbr_roam_info->cfgParams.nOpportunisticThresholdDiff; + ngbr_roam_info->currentRoamRescanRssiDiff = + ngbr_roam_info->cfgParams.nRoamRescanRssiDiff; + ngbr_roam_info->currentRoamBmissFirstBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFirstBcnt; + ngbr_roam_info->currentRoamBmissFinalBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFinalBcnt; + ngbr_roam_info->currentRoamBeaconRssiWeight = + ngbr_roam_info->cfgParams.nRoamBeaconRssiWeight; + +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + /** + * Now we can clear the preauthDone that + * was saved as we are connected afresh */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList); +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Based on the auth scheme tell if we are 11r */ + if (csr_is_auth_type11r + (session->connectedProfile.AuthType, + session->connectedProfile.MDID.mdiePresent)) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->is11rAssoc = true; + } else + ngbr_roam_info->is11rAssoc = false; + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, FL("11rAssoc is = %d"), + ngbr_roam_info->is11rAssoc); +#endif + +#ifdef FEATURE_WLAN_ESE + /* Based on the auth scheme tell if we are 11r */ + if (session->connectedProfile.isESEAssoc) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->isESEAssoc = true; + } else + ngbr_roam_info->isESEAssoc = false; + NEIGHBOR_ROAM_DEBUG(pMac, LOG2, + FL("isESEAssoc is = %d ft = %d"), + ngbr_roam_info->isESEAssoc, init_ft_flag); +#endif +#ifdef FEATURE_WLAN_LFR + /* If "Legacy Fast Roaming" is enabled */ + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) + init_ft_flag = true; +#endif +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + if (init_ft_flag == false) + return; + /* Initialize all the data structures needed for the 11r FT Preauth */ + ngbr_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0; + csr_neighbor_roam_purge_preauth_failed_list(pMac); + if (!cds_is_multiple_active_sta_sessions() && + csr_roam_is_roam_offload_scan_enabled(pMac)) { + /* + * If this is not a INFRA type BSS, then do not send the command + * down to firmware.Do not send the START command for + * other session connections.*/ + if (!csr_roam_is_sta_mode(pMac, session_id)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "Wrong Mode %d", + session->connectedProfile.BSSType); + return; + } + ngbr_roam_info->uOsRequestedHandoff = 0; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roamOffloadSynchParams.bRoamSynchInProgress) { + if (pMac->roam.pReassocResp != NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_DEBUG, + "Free Reassoc Rsp"); + cdf_mem_free(pMac->roam.pReassocResp); + pMac->roam.pReassocResp = NULL; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR3:Send SynchCnf auth, authenticated"); + csr_roam_offload_send_synch_cnf(pMac, session_id); + } else +#endif + csr_roam_offload_scan(pMac, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } +#endif +} + +/** + * csr_neighbor_roam_indicate_connect() + * @pMac: mac context + * @session_id: Session Id + * @cdf_status: CDF status + * + * This function is called by CSR as soon as the station connects to an AP. + * This initializes all the necessary data structures related to the + * associated AP and transitions the state to CONNECTED state + * + * Return: CDF status + */ +CDF_STATUS csr_neighbor_roam_indicate_connect( + tpAniSirGlobal pMac, uint8_t session_id, + CDF_STATUS cdf_status) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tCsrRoamInfo roamInfo; + tCsrRoamSession *session = &pMac->roam.roamSession[session_id]; + tpSirSetActiveModeSetBncFilterReq msg; +#endif + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* if session id invalid then we need return failure */ + if (NULL == ngbr_roam_info || !CSR_IS_SESSION_VALID(pMac, session_id) + || (NULL == pMac->roam.roamSession[session_id].pCurRoamProfile)) { + return CDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG2, + FL("Connect ind. received with session id %d in state %s"), + session_id, mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + + /* Bail out if this is NOT a STA persona */ + if (pMac->roam.roamSession[session_id].pCurRoamProfile->csrPersona != + CDF_STA_MODE) { + sms_log(pMac, LOGE, + FL("Ignoring Connect ind received from a non STA." + "session_id: %d, csrPersonna %d"), session_id, + (int)session->pCurRoamProfile->csrPersona); + return CDF_STATUS_SUCCESS; + } + /* if a concurrent session is running */ + if ((false == + CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) && + (csr_is_concurrent_session_running(pMac))) { + sms_log(pMac, LOGE, + FL("Ignoring Connect ind. received in multisession %d"), + csr_is_concurrent_session_running(pMac)); + return CDF_STATUS_SUCCESS; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roamOffloadSynchParams.bRoamSynchInProgress && + (eSIR_ROAM_AUTH_STATUS_AUTHENTICATED == + session->roamOffloadSynchParams.authStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_neighbor_roam_indicate_connect"); + msg = cdf_mem_malloc(sizeof(tSirSetActiveModeSetBncFilterReq)); + if (msg == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "LFR3:Mem Alloc failed for beacon Filter Req"); + return CDF_STATUS_E_NOMEM; + } + msg->messageType = eWNI_SME_SET_BCN_FILTER_REQ; + msg->length = sizeof(uint8_t); + msg->seesionId = session_id; + status = cds_send_mb_message_to_mac(msg); + cdf_copy_macaddr(&roamInfo.peerMac, + &session->connectedProfile.bssid); + roamInfo.roamSynchInProgress = + session->roamOffloadSynchParams.bRoamSynchInProgress; + csr_roam_call_callback(pMac, session_id, &roamInfo, 0, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_AUTHENTICATED); + } +#endif + + switch (ngbr_roam_info->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + if (CDF_STATUS_SUCCESS != cdf_status) { + /** + * Just transition the state to INIT state.Rest of the + * clean up happens when we get next connect indication + */ + CSR_NEIGHBOR_ROAM_STATE_TRANSITION( + pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, + session_id) + ngbr_roam_info->roamChannelInfo.IAPPNeighborListReceived = + false; + break; + } + /* Fall through if the status is SUCCESS */ + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + /* Reset all the data structures here */ + csr_neighbor_roam_reset_init_state_control_info(pMac, + session_id); + csr_neighbor_roam_info_ctx_init(pMac, session_id); + break; + default: + sms_log(pMac, LOGE, + FL("Connect evt received in invalid state %s Ignoring"), + mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + break; + } + return status; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_purge_preauth_failed_list + + \brief This function purges all the MAC addresses in the pre-auth fail list + + \param pMac - The handle returned by mac_open. + + \return VOID + + ---------------------------------------------------------------------------*/ +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal pMac) +{ + uint8_t i, j; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + for (j = 0; j < CSR_ROAM_SESSION_MAX; j++) { + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[j]; + for (i = 0; + i < + pNeighborRoamInfo->FTRoamInfo.preAuthFailList. + numMACAddress; i++) { + cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.macAddress[i], + sizeof(tSirMacAddr)); + } + pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress = 0; + } +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_init11r_assoc_info + + \brief This function initializes 11r related neighbor roam data structures + + \param pMac - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_neighbor_roam_init11r_assoc_info(tpAniSirGlobal pMac) +{ + CDF_STATUS status; + uint8_t i; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tpCsr11rAssocNeighborInfo pFTRoamInfo = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i]; + pFTRoamInfo = &pNeighborRoamInfo->FTRoamInfo; + + pNeighborRoamInfo->is11rAssoc = false; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries; + + pFTRoamInfo->neighborReportTimeout = + CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT; + pFTRoamInfo->PEPreauthRespTimeout = + CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER * + pNeighborRoamInfo->cfgParams.neighborScanPeriod; + pFTRoamInfo->neighborRptPending = false; + pFTRoamInfo->preauthRspPending = false; + + pFTRoamInfo->currentNeighborRptRetryNum = 0; + pFTRoamInfo->numBssFromNeighborReport = 0; + + cdf_mem_zero(pFTRoamInfo->neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + + status = csr_ll_open(pMac->hHdd, &pFTRoamInfo->preAuthDoneList); + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL("LL Open of preauth done AP List failed")); + return CDF_STATUS_E_RESOURCES; + } + } + return status; +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_init + + \brief This function initializes neighbor roam data structures + + \param pMac - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId) +{ + CDF_STATUS status; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->neighborRoamState = eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->prevNeighborRoamState = + eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.minChannelScanTime = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = 0; + pNeighborRoamInfo->cfgParams.neighborLookupThreshold = + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; + pNeighborRoamInfo->cfgParams.delay_before_vdev_stop = + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop; + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff = + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff = + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight = + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels; + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + cdf_mem_malloc(pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Memory Allocation for CFG Channel List failed")); + return CDF_STATUS_E_NOMEM; + } + + /* Update the roam global structure from CFG */ + cdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.channelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + pNeighborRoamInfo->cfgParams.hi_rssi_scan_max_count = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_max_count; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_delta = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_delta; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_delay = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_delay; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_ub = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_ub; + + cdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); + pNeighborRoamInfo->currentNeighborLookupThreshold = + pNeighborRoamInfo->cfgParams.neighborLookupThreshold; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff; + pNeighborRoamInfo->currentRoamRescanRssiDiff = + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight; +#ifdef FEATURE_WLAN_LFR + cdf_mem_set(&pNeighborRoamInfo->prevConnProfile, + sizeof(tCsrRoamConnectedProfile), 0); +#endif + + status = csr_ll_open(pMac->hHdd, &pNeighborRoamInfo->roamableAPList); + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed")); + cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + return CDF_STATUS_E_RESOURCES; + } + + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + +#ifdef WLAN_FEATURE_VOWIFI_11R + status = csr_neighbor_roam_init11r_assoc_info(pMac); + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed")); + cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + return CDF_STATUS_E_RESOURCES; + } +#endif + + CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, + sessionId) + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + /* Set the Last Sent Cmd as RSO_STOP */ + pNeighborRoamInfo->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP; + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_close + + \brief This function closes/frees all the neighbor roam data structures + + \param pMac - The handle returned by mac_open. + \param sessionId - Session identifier + \return VOID + + ---------------------------------------------------------------------------*/ +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (eCSR_NEIGHBOR_ROAM_STATE_CLOSED == + pNeighborRoamInfo->neighborRoamState) { + sms_log(pMac, LOGW, + FL("Neighbor Roam Algorithm Already Closed")); + return; + } + + if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) + cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + + /* Should free up the nodes in the list before closing the double Linked list */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + + if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + cdf_mem_free(pNeighborRoamInfo->roamChannelInfo. + currentChannelListInfo.ChannelList); + } + + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + + /* Free the profile.. */ + csr_release_profile(pMac, &pNeighborRoamInfo->csrNeighborRoamProfile); +#ifdef FEATURE_WLAN_LFR + csr_roam_free_connect_profile(pMac, &pNeighborRoamInfo->prevConnProfile); +#endif +#ifdef WLAN_FEATURE_VOWIFI_11R + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->FTRoamInfo. + preAuthDoneList); + csr_ll_close(&pNeighborRoamInfo->FTRoamInfo.preAuthDoneList); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, sessionId) + + return; +} + +/** + * csr_neighbor_roam_request_handoff() - Handoff to a different AP + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function triggers actual switching from one AP to the new AP. + * It issues disassociate with reason code as Handoff and CSR as a part of + * handling disassoc rsp, issues reassociate to the new AP + * + * Return: none + */ +void csr_neighbor_roam_request_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tCsrRoamInfo roam_info; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrNeighborRoamBSSInfo handoff_node; + uint32_t roamid = 0; + CDF_STATUS status; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, "%s session_id=%d", + __func__, session_id); + + if (neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) { + sms_log(mac_ctx, LOGE, + FL("Roam requested when Neighbor roam is in %s state"), + mac_trace_get_neighbour_roam_state( + neighbor_roam_info->neighborRoamState)); + return; + } + + if (false == csr_neighbor_roam_get_handoff_ap_info(mac_ctx, + &handoff_node, session_id)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("failed to obtain handoff AP")); + return; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("HANDOFF CANDIDATE BSSID "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(handoff_node.pBssDescription->bssId)); + + cdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, roamid, + eCSR_ROAM_FT_START, eSIR_SME_SUCCESS); + + cdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo)); + CSR_NEIGHBOR_ROAM_STATE_TRANSITION + (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, session_id) + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + handoff_node.pBssDescription->bssId, + eCSR_ROAM_HANDOVER_SUCCESS); + /* Free the profile.. Just to make sure we dont leak memory here */ + csr_release_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile); + /* + * Create the Handoff AP profile. Copy the currently connected profile + * and update only the BSSID and channel number. This should happen + * before issuing disconnect + */ + status = csr_roam_copy_connected_profile(mac_ctx, session_id, + &neighbor_roam_info->csrNeighborRoamProfile); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("csr_roam_copy_connected_profile failed %d"), + status); + return; + } + cdf_mem_copy(neighbor_roam_info->csrNeighborRoamProfile.BSSIDs.bssid, + handoff_node.pBssDescription->bssId, sizeof(tSirMacAddr)); + neighbor_roam_info->csrNeighborRoamProfile.ChannelInfo.ChannelList[0] = + handoff_node.pBssDescription->channelId; + + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW, + " csr_roamHandoffRequested: disassociating with current AP"); + + if (!CDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate_cmd + (mac_ctx, session_id, + eCSR_DISCONNECT_REASON_HANDOFF))) { + sms_log(mac_ctx, LOGW, + "csr_roamHandoffRequested: fail to issue disassociate"); + return; + } + /* notify HDD for handoff, providing the BSSID too */ + roam_info.reasonCode = eCsrRoamReasonBetterAP; + + cdf_mem_copy(roam_info.bssid.bytes, + handoff_node.pBssDescription->bssId, + sizeof(struct cdf_mac_addr)); + + csr_roam_call_callback(mac_ctx, session_id, &roam_info, 0, + eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_NONE); + + return; +} + +/** + * csr_neighbor_roam_is_handoff_in_progress() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function returns whether handoff is in progress or not based on + * the current neighbor roam state + * + * Return: true if reassoc in progress, false otherwise + */ +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId) +{ + if (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState) + return true; + + return false; +} + +#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(WLAN_FEATURE_NEIGHBOR_ROAMING) +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_is11r_assoc + + \brief This function returns whether the current association is a 11r assoc or not + + \param pMac - The handle returned by mac_open. + + \return true if current assoc is 11r, false otherwise + + ---------------------------------------------------------------------------*/ +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return pMac->roam.neighborRoamInfo[sessionId].is11rAssoc; +} +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/** + * csr_neighbor_roam_get_handoff_ap_info - Identifies the best AP for roaming + * + * @pMac: mac context + * @session_id: Session Id + * @hand_off_node: AP node that is the handoff candidate returned + * + * This function returns the best possible AP for handoff. For 11R case, it + * returns the 1st entry from pre-auth done list. For non-11r case, it returns + * the 1st entry from roamable AP list + * + * Return: true if able find handoff AP, false otherwise + */ + +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo hand_off_node, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamBSSInfo bss_node = NULL; + + if (NULL == hand_off_node) { + CDF_ASSERT(NULL != hand_off_node); + return false; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (ngbr_roam_info->is11rAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = csr_neighbor_roam_next_roamable_ap( + pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(& + ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else +#endif +#ifdef FEATURE_WLAN_ESE + if (ngbr_roam_info->isESEAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(&ngbr_roam_info->FTRoamInfo. + preAuthDoneList)); + } else +#endif +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count( + &ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else +#endif + { + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->roamableAPList, + NULL); + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(&ngbr_roam_info->roamableAPList)); + } + if (NULL == bss_node) + return false; + cdf_mem_copy(hand_off_node, bss_node, sizeof(tCsrNeighborRoamBSSInfo)); + return true; +} + +/* --------------------------------------------------------------------------- + \brief This function returns true if preauth is completed + + \param pMac - The handle returned by mac_open. + + \return bool + + ---------------------------------------------------------------------------*/ +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return pMac->roam.neighborRoamInfo[sessionId].neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE; +} + +/* --------------------------------------------------------------------------- + \brief In the event that we are associated with AP1 and we have + completed pre auth with AP2. Then we receive a deauth/disassoc from + AP1. + At this point neighbor roam is in pre auth done state, pre auth timer + is running. We now handle this case by stopping timer and clearing + the pre-auth state. We basically clear up and just go to disconnected + state. + + \param pMac - The handle returned by mac_open. + + \return bool + ---------------------------------------------------------------------------*/ +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamSession *session = CSR_GET_SESSION(pMac, sessionId); + + if (!session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + FL("session is NULL")); + return; + } + + if (pNeighborRoamInfo->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) + return; + + /* Stop timer */ + cdf_mc_timer_stop(&session->ftSmeContext.preAuthReassocIntvlTimer); + + /* Transition to init state */ + CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, + sessionId) + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; +} + +/* --------------------------------------------------------------------------- + \brief This function returns true if STA is in the middle of roaming states + + \param halHandle - The handle from HDD context. + \param sessionId - Session identifier + + \return bool + + ---------------------------------------------------------------------------*/ +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + bool val = (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE == + pNeighborRoamInfo->neighborRoamState); + return val; +} + +/** + * csr_neighbor_roam_candidate_found_ind_hdlr() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to msg buff + * + * This function is called by CSR as soon as TL posts the candidate + * found indication to SME via MC thread + * + * Return: CDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +CDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, void *pMsg) +{ + tSirSmeCandidateFoundInd *pSirSmeCandidateFoundInd = + (tSirSmeCandidateFoundInd *) pMsg; + uint32_t sessionId = pSirSmeCandidateFoundInd->sessionId; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("Received indication from firmware")); + + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (pNeighborRoamInfo->uOsRequestedHandoff)) { + sms_log(pMac, LOGE, + FL + ("Received in not CONNECTED state OR uOsRequestedHandoff is set. Ignore it")); + status = CDF_STATUS_E_FAILURE; + } else { + /* Firmware indicated that roaming candidate is found. Beacons + * are already in the SME scan results table. + * Process the results for choosing best roaming candidate. + */ + csr_save_scan_results(pMac, eCsrScanCandidateFound, + sessionId); + /* Future enhancements: + * If firmware tags candidate beacons, give them preference + * for roaming. + * Age out older entries so that new candidate beacons + * will get preference. + */ + status = csr_neighbor_roam_process_scan_complete(pMac, + sessionId); + if (CDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL("Neighbor scan process complete failed with status %d"), + status); + return CDF_STATUS_E_FAILURE; + } + } + + return status; +} + +/** + * csr_neighbor_roam_process_handoff_req - Processes handoff request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * + * This function is called start with the handoff process. First do a + * SSID scan for the BSSID provided. + * + * Return: status + */ +CDF_STATUS csr_neighbor_roam_process_handoff_req( + tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t roam_id; + tCsrRoamProfile *profile = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + uint8_t i = 0; + + if (NULL == session) { + sms_log(mac_ctx, LOGE, FL("session is NULL ")); + return CDF_STATUS_E_FAILURE; + } + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + profile = cdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == profile) { + sms_log(mac_ctx, LOGE, FL("Memory alloc failed")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set(profile, sizeof(tCsrRoamProfile), 0); + status = + csr_roam_copy_profile(mac_ctx, profile, + session->pCurRoamProfile); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Profile copy failed")); + goto end; + } + /* Add the BSSID & Channel */ + profile->BSSIDs.numOfBSSIDs = 1; + if (NULL == profile->BSSIDs.bssid) { + profile->BSSIDs.bssid = + cdf_mem_malloc(sizeof(tSirMacAddr) * + profile->BSSIDs.numOfBSSIDs); + if (NULL == profile->BSSIDs.bssid) { + sms_log(mac_ctx, LOGE, FL("mem alloc failed for BSSID")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + } + + cdf_mem_zero(profile->BSSIDs.bssid, + sizeof(tSirMacAddr) * + profile->BSSIDs.numOfBSSIDs); + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < profile->BSSIDs.numOfBSSIDs; i++) { + cdf_copy_macaddr(&profile->BSSIDs.bssid[i], + &roam_ctrl_info->handoffReqInfo.bssid); + } + + profile->ChannelInfo.numOfChannels = 1; + if (NULL == profile->ChannelInfo.ChannelList) { + profile->ChannelInfo.ChannelList = + cdf_mem_malloc(sizeof(*profile-> + ChannelInfo.ChannelList) * + profile->ChannelInfo.numOfChannels); + if (NULL == profile->ChannelInfo.ChannelList) { + sms_log(mac_ctx, LOGE, + FL("mem alloc failed for ChannelList")); + status = CDF_STATUS_E_NOMEM; + goto end; + } + } + profile->ChannelInfo.ChannelList[0] = + roam_ctrl_info->handoffReqInfo.channel; + + /* do a SSID scan */ + status = + csr_scan_for_ssid(mac_ctx, session_id, profile, roam_id, false); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("SSID scan failed")); + } + +end: + if (NULL != profile) { + csr_release_profile(mac_ctx, profile); + cdf_mem_free(profile); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_sssid_scan_done + + \brief This function is called once SSID scan is done. If SSID scan failed + to find our candidate add an entry to csr scan cache ourself before starting + the handoff process + + \param pMac - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, CDF_STATUS status) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + CDF_STATUS hstatus; + + sms_log(pMac, LOGE, FL("called ")); + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) { + sms_log(pMac, LOGE, + FL("Received in not CONNECTED state. Ignore it")); + return CDF_STATUS_E_FAILURE; + } + /* if SSID scan failed to find our candidate add an entry to csr scan cache ourself */ + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Add an entry to csr scan cache")); + hstatus = csr_scan_create_entry_in_scan_cache(pMac, sessionId, + pNeighborRoamInfo-> + handoffReqInfo.bssid, + pNeighborRoamInfo-> + handoffReqInfo.channel); + if (CDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL + ("csr_scan_create_entry_in_scan_cache failed with status %d"), + hstatus); + return CDF_STATUS_E_FAILURE; + } + } + + /* Now we have completed scanning for the candidate provided by HDD. Let move on to HO */ + hstatus = csr_neighbor_roam_process_scan_complete(pMac, sessionId); + + if (CDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL + ("Neighbor scan process complete failed with status %d"), + hstatus); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx Pointer to mac context + * @msg message sent to HDD + * + * This function is called by CSR as soon as it gets a handoff request + * to SME via MC thread + * + * Return: status + */ +CDF_STATUS csr_neighbor_roam_handoff_req_hdlr( + tpAniSirGlobal mac_ctx, void *msg) +{ + tAniHandoffReq *handoff_req = (tAniHandoffReq *) msg; + uint32_t session_id = handoff_req->sessionId; + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + roam_ctrl_info->neighborRoamState) { + sms_log(mac_ctx, LOGE, + FL("Received in not CONNECTED state. Ignore it")); + return CDF_STATUS_E_FAILURE; + } + + /* save the handoff info came from HDD as part of the reassoc req */ + handoff_req = (tAniHandoffReq *) msg; + if (NULL == handoff_req) { + sms_log(mac_ctx, LOGE, FL("Received msg is NULL")); + return CDF_STATUS_E_FAILURE; + } + + /* sanity check */ + if (true == cdf_mem_compare(handoff_req->bssid, + roam_ctrl_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + sms_log(mac_ctx, LOGE, + FL + ("Received req has same BSSID as current AP!!")); + return CDF_STATUS_E_FAILURE; + } + roam_ctrl_info->handoffReqInfo.channel = + handoff_req->channel; + roam_ctrl_info->handoffReqInfo.src = + handoff_req->handoff_src; + cdf_mem_copy(&roam_ctrl_info->handoffReqInfo.bssid.bytes, + &handoff_req->bssid, CDF_MAC_ADDR_SIZE); + roam_ctrl_info->uOsRequestedHandoff = 1; + status = csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_OS_REQUESTED_ROAMING_NOW); + if (CDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("csr_roam_offload_scan failed")); + roam_ctrl_info->uOsRequestedHandoff = 0; + } + return status; +} + +/** + * csr_neighbor_roam_proceed_with_handoff_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function is called by CSR as soon as it gets rsp back for + * ROAM_SCAN_OFFLOAD_STOP with reason REASON_OS_REQUESTED_ROAMING_NOW + * + * Return: CDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +CDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + CDF_STATUS status = CDF_STATUS_SUCCESS; + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (!pNeighborRoamInfo->uOsRequestedHandoff)) { + sms_log(pMac, LOGE, + FL + ("Received in not CONNECTED state or uOsRequestedHandoff is not set. Ignore it")); + status = CDF_STATUS_E_FAILURE; + } else { + /* Let's go ahead with handoff */ + status = csr_neighbor_roam_process_handoff_req(pMac, sessionId); + } + if (!CDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_start_lfr_scan + + \brief This function is called if HDD requested handoff failed for some + reason. start the LFR logic at that point.By the time, this function is + called, a STOP command has already been issued. + + \param pMac - The handle returned by mac_open. + + \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +CDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan */ + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */ diff --git a/core/sme/src/csr/csr_tdls_process.c b/core/sme/src/csr/csr_tdls_process.c new file mode 100644 index 0000000000..30fadcd205 --- /dev/null +++ b/core/sme/src/csr/csr_tdls_process.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_tdls_process.c + + Implementation for the TDLS interface to PE. + ========================================================================== */ + +#ifdef FEATURE_WLAN_TDLS + +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" +#include "csr_internal.h" + +/* + * common routine to remove TDLS cmd from SME command list.. + * commands are removed after getting reponse from PE. + */ +CDF_STATUS csr_tdls_remove_sme_cmd(tpAniSirGlobal pMac, eSmeCommandType cmdType) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tListElem *pEntry; + tSmeCmd *pCommand; + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (cmdType == pCommand->command) { + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + pEntry, LL_ACCESS_LOCK)) { + cdf_mem_zero(&pCommand->u.tdlsCmd, + sizeof(tTdlsCmd)); + csr_release_command(pMac, pCommand); + sme_process_pending_queue(pMac); + status = CDF_STATUS_SUCCESS; + } + } + } + return status; +} + +/** + * csr_tdls_send_mgmt_req() - to send a TDLS frame to PE through SME + * @hHal: HAL context + * @sessionId: SME session id + * @tdlsSendMgmt: tdls mgmt pointer + * + * TDLS request API, called from HDD to send a TDLS frame in SME/CSR and + * send message to PE to trigger TDLS discovery procedure. + */ +CDF_STATUS csr_tdls_send_mgmt_req(tHalHandle hHal, uint8_t sessionId, + tCsrTdlsSendMgmt *tdlsSendMgmt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsSendMgmtCmd; + tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (!CSR_IS_SESSION_VALID(pMac, sessionId) || + !csr_is_conn_state_connected_infra(pMac, sessionId) || + (NULL == tdlsSendMgmt)) + return status; + tdlsSendMgmtCmd = csr_get_command_buffer(pMac); + if (!tdlsSendMgmtCmd) + return status; + tdlsSendMgmtCmdInfo = &tdlsSendMgmtCmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo; + tdlsSendMgmtCmd->sessionId = sessionId; + tdlsSendMgmtCmdInfo->frameType = tdlsSendMgmt->frameType; + tdlsSendMgmtCmdInfo->dialog = tdlsSendMgmt->dialog; + tdlsSendMgmtCmdInfo->statusCode = tdlsSendMgmt->statusCode; + tdlsSendMgmtCmdInfo->responder = tdlsSendMgmt->responder; + tdlsSendMgmtCmdInfo->peerCapability = tdlsSendMgmt->peerCapability; + cdf_mem_copy(tdlsSendMgmtCmdInfo->peerMac, tdlsSendMgmt->peerMac, + sizeof(tSirMacAddr)); + + if ((0 != tdlsSendMgmt->len) && (NULL != tdlsSendMgmt->buf)) { + tdlsSendMgmtCmdInfo->buf = cdf_mem_malloc(tdlsSendMgmt->len); + if (NULL == tdlsSendMgmtCmdInfo->buf) { + status = CDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, FL("Alloc Failed")); + CDF_ASSERT(0); + return status; + } + cdf_mem_copy(tdlsSendMgmtCmdInfo->buf, tdlsSendMgmt->buf, + tdlsSendMgmt->len); + tdlsSendMgmtCmdInfo->len = tdlsSendMgmt->len; + } else { + tdlsSendMgmtCmdInfo->buf = NULL; + tdlsSendMgmtCmdInfo->len = 0; + } + + tdlsSendMgmtCmd->command = eSmeCommandTdlsSendMgmt; + tdlsSendMgmtCmd->u.tdlsCmd.size = sizeof(tTdlsSendMgmtCmdInfo); + sme_push_command(pMac, tdlsSendMgmtCmd, false); + status = CDF_STATUS_SUCCESS; + return status; +} + +/* + * TDLS request API, called from HDD to add a TDLS peer + */ +CDF_STATUS csr_tdls_change_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsAddStaCmd; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac) && (NULL != pstaParams)) { + + tdlsAddStaCmd = csr_get_command_buffer(pMac); + + if (tdlsAddStaCmd) { + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + + tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_UPDATE; + + tdlsAddStaCmd->sessionId = sessionId; + + cdf_mem_copy(tdlsAddStaCmdInfo->peerMac, + peerMac, sizeof(tSirMacAddr)); + tdlsAddStaCmdInfo->capability = pstaParams->capability; + tdlsAddStaCmdInfo->uapsdQueues = + pstaParams->uapsd_queues; + tdlsAddStaCmdInfo->maxSp = pstaParams->max_sp; + cdf_mem_copy(tdlsAddStaCmdInfo->extnCapability, + pstaParams->extn_capability, + sizeof(pstaParams->extn_capability)); + + tdlsAddStaCmdInfo->htcap_present = + pstaParams->htcap_present; + if (pstaParams->htcap_present) + cdf_mem_copy(&tdlsAddStaCmdInfo->HTCap, + &pstaParams->HTCap, + sizeof(pstaParams->HTCap)); + else + cdf_mem_set(&tdlsAddStaCmdInfo->HTCap, + sizeof(pstaParams->HTCap), 0); + + tdlsAddStaCmdInfo->vhtcap_present = + pstaParams->vhtcap_present; + if (pstaParams->vhtcap_present) + cdf_mem_copy(&tdlsAddStaCmdInfo->VHTCap, + &pstaParams->VHTCap, + sizeof(pstaParams->VHTCap)); + else + cdf_mem_set(&tdlsAddStaCmdInfo->VHTCap, + sizeof(pstaParams->VHTCap), 0); + + tdlsAddStaCmdInfo->supportedRatesLen = + pstaParams->supported_rates_len; + + if (0 != pstaParams->supported_rates_len) + cdf_mem_copy(&tdlsAddStaCmdInfo->supportedRates, + pstaParams->supported_rates, + pstaParams->supported_rates_len); + + tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer; + tdlsAddStaCmd->u.tdlsCmd.size = + sizeof(tTdlsAddStaCmdInfo); + sme_push_command(pMac, tdlsAddStaCmd, false); + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to Send Link Establishment Parameters + */ +CDF_STATUS csr_tdls_send_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsLinkEstablishCmd; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsLinkEstablishCmd = csr_get_command_buffer(pMac); + + if (tdlsLinkEstablishCmd) { + tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo = + &tdlsLinkEstablishCmd->u.tdlsCmd.u. + tdlsLinkEstablishCmdInfo; + + tdlsLinkEstablishCmd->sessionId = sessionId; + + cdf_mem_copy(tdlsLinkEstablishCmdInfo->peerMac, + peerMac, sizeof(tSirMacAddr)); + tdlsLinkEstablishCmdInfo->isBufSta = + tdlsLinkEstablishParams->isBufSta; + tdlsLinkEstablishCmdInfo->isResponder = + tdlsLinkEstablishParams->isResponder; + tdlsLinkEstablishCmdInfo->maxSp = + tdlsLinkEstablishParams->maxSp; + tdlsLinkEstablishCmdInfo->uapsdQueues = + tdlsLinkEstablishParams->uapsdQueues; + tdlsLinkEstablishCmdInfo->isOffChannelSupported = + tdlsLinkEstablishParams->isOffChannelSupported; + cdf_mem_copy(tdlsLinkEstablishCmdInfo-> + supportedChannels, + tdlsLinkEstablishParams->supportedChannels, + tdlsLinkEstablishParams-> + supportedChannelsLen); + tdlsLinkEstablishCmdInfo->supportedChannelsLen = + tdlsLinkEstablishParams->supportedChannelsLen; + cdf_mem_copy(tdlsLinkEstablishCmdInfo-> + supportedOperClasses, + tdlsLinkEstablishParams-> + supportedOperClasses, + tdlsLinkEstablishParams-> + supportedOperClassesLen); + tdlsLinkEstablishCmdInfo->supportedOperClassesLen = + tdlsLinkEstablishParams->supportedOperClassesLen; + tdlsLinkEstablishCmdInfo->isResponder = + tdlsLinkEstablishParams->isResponder; + tdlsLinkEstablishCmdInfo->maxSp = + tdlsLinkEstablishParams->maxSp; + tdlsLinkEstablishCmdInfo->uapsdQueues = + tdlsLinkEstablishParams->uapsdQueues; + tdlsLinkEstablishCmd->command = + eSmeCommandTdlsLinkEstablish; + tdlsLinkEstablishCmd->u.tdlsCmd.size = + sizeof(tTdlsLinkEstablishCmdInfo); + sme_push_command(pMac, tdlsLinkEstablishCmd, false); + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to add a TDLS peer + */ +CDF_STATUS csr_tdls_add_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsAddStaCmd; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsAddStaCmd = csr_get_command_buffer(pMac); + + if (tdlsAddStaCmd) { + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + + tdlsAddStaCmd->sessionId = sessionId; + tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_ADD; + + cdf_mem_copy(tdlsAddStaCmdInfo->peerMac, + peerMac, sizeof(tSirMacAddr)); + + tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer; + tdlsAddStaCmd->u.tdlsCmd.size = + sizeof(tTdlsAddStaCmdInfo); + sme_push_command(pMac, tdlsAddStaCmd, false); + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to delete a TDLS peer + */ +CDF_STATUS csr_tdls_del_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsDelStaCmd; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsDelStaCmd = csr_get_command_buffer(pMac); + + if (tdlsDelStaCmd) { + tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo = + &tdlsDelStaCmd->u.tdlsCmd.u.tdlsDelStaCmdInfo; + + tdlsDelStaCmd->sessionId = sessionId; + + cdf_mem_copy(tdlsDelStaCmdInfo->peerMac, + peerMac, sizeof(tSirMacAddr)); + + tdlsDelStaCmd->command = eSmeCommandTdlsDelPeer; + tdlsDelStaCmd->u.tdlsCmd.size = + sizeof(tTdlsDelStaCmdInfo); + sme_push_command(pMac, tdlsDelStaCmd, false); + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* + * TDLS messages sent to PE . + */ +CDF_STATUS tdls_send_message(tpAniSirGlobal pMac, uint16_t msg_type, + void *msg_data, uint32_t msg_size) +{ + + tSirMbMsg *pMsg = (tSirMbMsg *) msg_data; + pMsg->type = msg_type; + pMsg->msgLen = (uint16_t) (msg_size); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + ("sending msg = %d"), pMsg->type); + /* Send message. */ + if (cds_send_mb_message_to_mac(pMsg) != CDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL("Cannot send message")); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_tdls_process_send_mgmt(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo = + &cmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo; + tSirTdlsSendMgmtReq *tdlsSendMgmtReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS Description is not present")); + return CDF_STATUS_E_FAILURE; + } + + tdlsSendMgmtReq = + cdf_mem_malloc(sizeof(tSirTdlsSendMgmtReq) + + tdlsSendMgmtCmdInfo->len); + if (NULL == tdlsSendMgmtReq) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + CDF_ASSERT(0); + return status; + } + tdlsSendMgmtReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsSendMgmtReq->transactionId = tdlsSendMgmtCmdInfo->dialog; + tdlsSendMgmtReq->reqType = tdlsSendMgmtCmdInfo->frameType; + tdlsSendMgmtReq->dialog = tdlsSendMgmtCmdInfo->dialog; + tdlsSendMgmtReq->statusCode = tdlsSendMgmtCmdInfo->statusCode; + tdlsSendMgmtReq->responder = tdlsSendMgmtCmdInfo->responder; + tdlsSendMgmtReq->peerCapability = tdlsSendMgmtCmdInfo->peerCapability; + + cdf_mem_copy(tdlsSendMgmtReq->bssid, + pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr)); + + cdf_mem_copy(tdlsSendMgmtReq->peerMac, + tdlsSendMgmtCmdInfo->peerMac, sizeof(tSirMacAddr)); + + if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) { + cdf_mem_copy(tdlsSendMgmtReq->addIe, tdlsSendMgmtCmdInfo->buf, + tdlsSendMgmtCmdInfo->len); + + } + /* Send the request to PE. */ + sms_log(pMac, LOG1, "sending TDLS Mgmt Frame req to PE "); + status = tdls_send_message(pMac, eWNI_SME_TDLS_SEND_MGMT_REQ, + (void *)tdlsSendMgmtReq, + sizeof(tSirTdlsSendMgmtReq) + + tdlsSendMgmtCmdInfo->len); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) { + /* Done with the buf. Free it. */ + cdf_mem_free(tdlsSendMgmtCmdInfo->buf); + tdlsSendMgmtCmdInfo->buf = NULL; + tdlsSendMgmtCmdInfo->len = 0; + } + + return status; +} + +CDF_STATUS csr_tdls_process_add_sta(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &cmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + tSirTdlsAddStaReq *tdlsAddStaReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS description is not present")); + return CDF_STATUS_E_FAILURE; + } + + tdlsAddStaReq = cdf_mem_malloc(sizeof(tSirTdlsAddStaReq)); + if (NULL == tdlsAddStaReq) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + CDF_ASSERT(0); + return status; + } + tdlsAddStaReq->sessionId = cmd->sessionId; + tdlsAddStaReq->tdlsAddOper = tdlsAddStaCmdInfo->tdlsAddOper; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsAddStaReq->transactionId = 0; + + cdf_mem_copy(tdlsAddStaReq->bssid, + pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr)); + + cdf_mem_copy(tdlsAddStaReq->peerMac, + tdlsAddStaCmdInfo->peerMac, sizeof(tSirMacAddr)); + + tdlsAddStaReq->capability = tdlsAddStaCmdInfo->capability; + tdlsAddStaReq->uapsd_queues = tdlsAddStaCmdInfo->uapsdQueues; + tdlsAddStaReq->max_sp = tdlsAddStaCmdInfo->maxSp; + + cdf_mem_copy(tdlsAddStaReq->extn_capability, + tdlsAddStaCmdInfo->extnCapability, SIR_MAC_MAX_EXTN_CAP); + tdlsAddStaReq->htcap_present = tdlsAddStaCmdInfo->htcap_present; + cdf_mem_copy(&tdlsAddStaReq->htCap, + &tdlsAddStaCmdInfo->HTCap, + sizeof(tdlsAddStaCmdInfo->HTCap)); + tdlsAddStaReq->vhtcap_present = tdlsAddStaCmdInfo->vhtcap_present; + cdf_mem_copy(&tdlsAddStaReq->vhtCap, + &tdlsAddStaCmdInfo->VHTCap, + sizeof(tdlsAddStaCmdInfo->VHTCap)); + tdlsAddStaReq->supported_rates_length = + tdlsAddStaCmdInfo->supportedRatesLen; + cdf_mem_copy(&tdlsAddStaReq->supported_rates, + tdlsAddStaCmdInfo->supportedRates, + tdlsAddStaCmdInfo->supportedRatesLen); + + /* Send the request to PE. */ + sms_log(pMac, LOGE, "sending TDLS Add Sta req to PE "); + status = tdls_send_message(pMac, eWNI_SME_TDLS_ADD_STA_REQ, + (void *)tdlsAddStaReq, + sizeof(tSirTdlsAddStaReq)); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + return status; +} + +CDF_STATUS csr_tdls_process_del_sta(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo = + &cmd->u.tdlsCmd.u.tdlsDelStaCmdInfo; + tSirTdlsDelStaReq *tdlsDelStaReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS description is not present")); + return CDF_STATUS_E_FAILURE; + } + + tdlsDelStaReq = cdf_mem_malloc(sizeof(tSirTdlsDelStaReq)); + if (NULL == tdlsDelStaReq) + status = CDF_STATUS_E_NOMEM; + else + status = CDF_STATUS_SUCCESS; + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + CDF_ASSERT(0); + return status; + } + tdlsDelStaReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsDelStaReq->transactionId = 0; + + cdf_mem_copy(tdlsDelStaReq->bssid, + pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr)); + + cdf_mem_copy(tdlsDelStaReq->peerMac, + tdlsDelStaCmdInfo->peerMac, sizeof(tSirMacAddr)); + + /* Send the request to PE. */ + sms_log(pMac, LOG1, + "sending TDLS Del Sta " MAC_ADDRESS_STR " req to PE", + MAC_ADDR_ARRAY(tdlsDelStaCmdInfo->peerMac)); + status = tdls_send_message(pMac, eWNI_SME_TDLS_DEL_STA_REQ, + (void *)tdlsDelStaReq, + sizeof(tSirTdlsDelStaReq)); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + return status; +} + +/* + * commands received from CSR + */ +CDF_STATUS csr_tdls_process_cmd(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + eSmeCommandType cmdType = cmd->command; + bool status = true; + switch (cmdType) { + case eSmeCommandTdlsSendMgmt: + { + status = csr_tdls_process_send_mgmt(pMac, cmd); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsAddPeer: + { + status = csr_tdls_process_add_sta(pMac, cmd); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsDelPeer: + { + status = csr_tdls_process_del_sta(pMac, cmd); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsLinkEstablish: + { + status = csr_tdls_process_link_establish(pMac, cmd); + if (CDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + default: + { + /* TODO: Add defualt handling */ + break; + } + + } + return status; +} + +CDF_STATUS csr_tdls_process_link_establish(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo = + &cmd->u.tdlsCmd.u.tdlsLinkEstablishCmdInfo; + tSirTdlsLinkEstablishReq *tdlsLinkEstablishReq = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return CDF_STATUS_E_FAILURE; + } + + tdlsLinkEstablishReq = cdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReq)); + + if (tdlsLinkEstablishReq == NULL) { + sms_log(pMac, LOGE, FL("alloc failed")); + CDF_ASSERT(0); + return CDF_STATUS_E_NOMEM; + } + tdlsLinkEstablishReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsLinkEstablishReq->transactionId = 0; + cdf_mem_copy(tdlsLinkEstablishReq->peerMac, + tdlsLinkEstablishCmdInfo->peerMac, sizeof(tSirMacAddr)); + cdf_mem_copy(tdlsLinkEstablishReq->bssid, + pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr)); + cdf_mem_copy(tdlsLinkEstablishReq->supportedChannels, + tdlsLinkEstablishCmdInfo->supportedChannels, + tdlsLinkEstablishCmdInfo->supportedChannelsLen); + tdlsLinkEstablishReq->supportedChannelsLen = + tdlsLinkEstablishCmdInfo->supportedChannelsLen; + cdf_mem_copy(tdlsLinkEstablishReq->supportedOperClasses, + tdlsLinkEstablishCmdInfo->supportedOperClasses, + tdlsLinkEstablishCmdInfo->supportedOperClassesLen); + tdlsLinkEstablishReq->supportedOperClassesLen = + tdlsLinkEstablishCmdInfo->supportedOperClassesLen; + tdlsLinkEstablishReq->isBufSta = tdlsLinkEstablishCmdInfo->isBufSta; + tdlsLinkEstablishReq->isResponder = + tdlsLinkEstablishCmdInfo->isResponder; + tdlsLinkEstablishReq->uapsdQueues = + tdlsLinkEstablishCmdInfo->uapsdQueues; + tdlsLinkEstablishReq->maxSp = tdlsLinkEstablishCmdInfo->maxSp; + + /* Send the request to PE. */ + sms_log(pMac, LOGE, "sending TDLS Link Establish Request to PE \n"); + status = tdls_send_message(pMac, eWNI_SME_TDLS_LINK_ESTABLISH_REQ, + (void *)tdlsLinkEstablishReq, + sizeof(tSirTdlsLinkEstablishReq)); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC\n")); + } + return status; +} + +/* + * TDLS Message processor, will be called after TDLS message recieved from + * PE + */ +CDF_STATUS tdls_msg_processor(tpAniSirGlobal pMac, uint16_t msgType, + void *pMsgBuf) +{ + tCsrRoamInfo roamInfo = { 0 }; + eCsrRoamResult roamResult; + tSirTdlsAddStaRsp *addStaRsp = (tSirTdlsAddStaRsp *) pMsgBuf; + tSirTdlsDelStaRsp *delStaRsp = (tSirTdlsDelStaRsp *) pMsgBuf; + tpSirTdlsDelStaInd pSirTdlsDelStaInd = (tpSirTdlsDelStaInd) pMsgBuf; + tpSirTdlsDelAllPeerInd pSirTdlsDelAllPeerInd = + (tpSirTdlsDelAllPeerInd) pMsgBuf; + tpSirMgmtTxCompletionInd tdls_tx_comp_ind = + (tpSirMgmtTxCompletionInd) pMsgBuf; + tSirTdlsLinkEstablishReqRsp *linkEstablishReqRsp = + (tSirTdlsLinkEstablishReqRsp *) pMsgBuf; + tSirTdlsEventnotify *tevent = (tSirTdlsEventnotify *) pMsgBuf; + + switch (msgType) { + case eWNI_SME_TDLS_SEND_MGMT_RSP: + /* remove pending eSmeCommandTdlsDiscovery command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsSendMgmt); + break; + case eWNI_SME_TDLS_ADD_STA_RSP: + cdf_mem_copy(&roamInfo.peerMac, addStaRsp->peerMac, + sizeof(tSirMacAddr)); + roamInfo.staId = addStaRsp->staId; + roamInfo.ucastSig = addStaRsp->ucastSig; + roamInfo.bcastSig = addStaRsp->bcastSig; + roamInfo.statusCode = addStaRsp->statusCode; + /* + * register peer with TL, we have to go through HDD as + * this is the only way to register any STA with TL. + */ + if (addStaRsp->tdlsAddOper == TDLS_OPER_ADD) + roamResult = eCSR_ROAM_RESULT_ADD_TDLS_PEER; + else /* addStaRsp->tdlsAddOper must be TDLS_OPER_UPDATE */ + roamResult = eCSR_ROAM_RESULT_UPDATE_TDLS_PEER; + csr_roam_call_callback(pMac, addStaRsp->sessionId, + &roamInfo, 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + roamResult); + + /* remove pending eSmeCommandTdlsDiscovery command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsAddPeer); + break; + case eWNI_SME_TDLS_DEL_STA_RSP: + cdf_mem_copy(&roamInfo.peerMac, delStaRsp->peerMac, + sizeof(tSirMacAddr)); + roamInfo.staId = delStaRsp->staId; + roamInfo.statusCode = delStaRsp->statusCode; + /* + * register peer with TL, we have to go through HDD as + * this is the only way to register any STA with TL. + */ + csr_roam_call_callback(pMac, delStaRsp->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_DELETE_TDLS_PEER); + + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsDelPeer); + break; + case eWNI_SME_TDLS_DEL_STA_IND: + cdf_mem_copy(&roamInfo.peerMac, + pSirTdlsDelStaInd->peerMac, + sizeof(tSirMacAddr)); + roamInfo.staId = pSirTdlsDelStaInd->staId; + roamInfo.reasonCode = pSirTdlsDelStaInd->reasonCode; + + /* Sending the TEARDOWN indication to HDD. */ + csr_roam_call_callback(pMac, + pSirTdlsDelStaInd->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND); + break; + case eWNI_SME_TDLS_DEL_ALL_PEER_IND: + /* Sending the TEARDOWN indication to HDD. */ + csr_roam_call_callback(pMac, + pSirTdlsDelAllPeerInd->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND); + break; + case eWNI_SME_MGMT_FRM_TX_COMPLETION_IND: + roamInfo.reasonCode = + tdls_tx_comp_ind->txCompleteStatus; + + csr_roam_call_callback(pMac, + tdls_tx_comp_ind->sessionId, + &roamInfo, 0, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, + 0); + break; + case eWNI_SME_TDLS_LINK_ESTABLISH_RSP: + csr_roam_call_callback(pMac, + linkEstablishReqRsp->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); + /* remove pending eSmeCommandTdlsLinkEstablish command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsLinkEstablish); + break; + case eWNI_SME_TDLS_SHOULD_DISCOVER: + cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac, + sizeof(tSirMacAddr)); + roamInfo.reasonCode = tevent->peer_reason; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_SHOULD_DISCOVER for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peerMac), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER); + break; + case eWNI_SME_TDLS_SHOULD_TEARDOWN: + cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac, + sizeof(tSirMacAddr)); + roamInfo.reasonCode = tevent->peer_reason; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_SHOULD_TEARDOWN for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peerMac), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN); + break; + case eWNI_SME_TDLS_PEER_DISCONNECTED: + cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac, + sizeof(tSirMacAddr)); + roamInfo.reasonCode = tevent->peer_reason; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_PEER_DISCONNECTED for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peerMac), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED); + break; + default: + break; + } + + return CDF_STATUS_SUCCESS; +} +#endif diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c new file mode 100644 index 0000000000..eea8cbd2fb --- /dev/null +++ b/core/sme/src/csr/csr_util.c @@ -0,0 +1,5626 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_util.c + + Implementation supporting routines for CSR. + ========================================================================== */ + +#include "ani_global.h" + +#include "csr_support.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "wma_types.h" +#include "cds_utils.h" + + +uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE] = { + {0x00, 0x50, 0xf2, 0x00} + , + {0x00, 0x50, 0xf2, 0x01} + , + {0x00, 0x50, 0xf2, 0x02} + , + {0x00, 0x50, 0xf2, 0x03} + , + {0x00, 0x50, 0xf2, 0x04} + , + {0x00, 0x50, 0xf2, 0x05} + , +#ifdef FEATURE_WLAN_ESE + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ +#endif /* FEATURE_WLAN_ESE */ +}; + +uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = { + {0x00, 0x0F, 0xAC, 0x00} + , /* group cipher */ + {0x00, 0x0F, 0xAC, 0x01} + , /* WEP-40 or RSN */ + {0x00, 0x0F, 0xAC, 0x02} + , /* TKIP or RSN-PSK */ + {0x00, 0x0F, 0xAC, 0x03} + , /* Reserved */ + {0x00, 0x0F, 0xAC, 0x04} + , /* AES-CCMP */ + {0x00, 0x0F, 0xAC, 0x05} + , /* WEP-104 */ + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ + {0x00, 0x0F, 0xAC, 0x06} + , /* BIP (encryption type) or + RSN-PSK-SHA256 (authentication type) */ + /* RSN-8021X-SHA256 (authentication type) */ + {0x00, 0x0F, 0xAC, 0x05} +}; + +#ifdef FEATURE_WLAN_WAPI +uint8_t csr_wapi_oui[][CSR_WAPI_OUI_SIZE] = { + {0x00, 0x14, 0x72, 0x00} + , /* Reserved */ + {0x00, 0x14, 0x72, 0x01} + , /* WAI certificate or SMS4 */ + {0x00, 0x14, 0x72, 0x02} /* WAI PSK */ +}; +#endif /* FEATURE_WLAN_WAPI */ +uint8_t csr_wme_info_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t csr_wme_parm_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; + + +/* ////////////////////////////////////////////////////////////////////// */ + +/** + * \var g_phy_rates_suppt + * + * \brief Rate support lookup table + * + * + * This is a lookup table indexing rates & configuration parameters to + * support. Given a rate (in unites of 0.5Mpbs) & three bools (MIMO + * Enabled, Channel Bonding Enabled, & Concatenation Enabled), one can + * determine whether the given rate is supported by computing two + * indices. The first maps the rate to table row as indicated below + * (i.e. eHddSuppRate_6Mbps maps to row zero, eHddSuppRate_9Mbps to row + * 1, and so on). Index two can be computed like so: + * + * \code + * idx2 = ( fEsf ? 0x4 : 0x0 ) | + * ( fCb ? 0x2 : 0x0 ) | + * ( fMimo ? 0x1 : 0x0 ); + * \endcode + * + * + * Given that: + * + * \code + * fSupported = g_phy_rates_suppt[idx1][idx2]; + * \endcode + * + * + * This table is based on the document "PHY Supported Rates.doc". This + * table is permissive in that a rate is reflected as being supported + * even when turning off an enabled feature would be required. For + * instance, "PHY Supported Rates" lists 42Mpbs as unsupported when CB, + * ESF, & MIMO are all on. However, if we turn off either of CB or + * MIMO, it then becomes supported. Therefore, we mark it as supported + * even in index 7 of this table. + * + * + */ + +static const bool g_phy_rates_suppt[24][8] = { + + /* SSF SSF SSF SSF ESF ESF ESF ESF */ + /* SIMO MIMO SIMO MIMO SIMO MIMO SIMO MIMO */ + /* No CB No CB CB CB No CB No CB CB CB */ + {true, true, true, true, true, true, true, true}, /* 6Mbps */ + {true, true, true, true, true, true, true, true}, /* 9Mbps */ + {true, true, true, true, true, true, true, true}, /* 12Mbps */ + {true, true, true, true, true, true, true, true}, /* 18Mbps */ + {false, false, true, true, false, false, true, true}, /* 20Mbps */ + {true, true, true, true, true, true, true, true}, /* 24Mbps */ + {true, true, true, true, true, true, true, true}, /* 36Mbps */ + {false, false, true, true, false, true, true, true}, /* 40Mbps */ + {false, false, true, true, false, true, true, true}, /* 42Mbps */ + {true, true, true, true, true, true, true, true}, /* 48Mbps */ + {true, true, true, true, true, true, true, true}, /* 54Mbps */ + {false, true, true, true, false, true, true, true}, /* 72Mbps */ + {false, false, true, true, false, true, true, true}, /* 80Mbps */ + {false, false, true, true, false, true, true, true}, /* 84Mbps */ + {false, true, true, true, false, true, true, true}, /* 96Mbps */ + {false, true, true, true, false, true, true, true}, /* 108Mbps */ + {false, false, true, true, false, true, true, true}, /* 120Mbps */ + {false, false, true, true, false, true, true, true}, /* 126Mbps */ + {false, false, false, true, false, false, false, true}, /* 144Mbps */ + {false, false, false, true, false, false, false, true}, /* 160Mbps */ + {false, false, false, true, false, false, false, true}, /* 168Mbps */ + {false, false, false, true, false, false, false, true}, /* 192Mbps */ + {false, false, false, true, false, false, false, true}, /* 216Mbps */ + {false, false, false, true, false, false, false, true}, /* 240Mbps */ + +}; + +#define CASE_RETURN_STR(n) {\ + case (n): return (# n);\ +} + +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_CANCELLED); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_START); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_START); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_DISASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_SHOULD_ROAM); + CASE_RETURN_STR(eCSR_ROAM_SCAN_FOUND_NEW_BSS); + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK); + default: + return "unknown"; + } +} + +const char *get_e_csr_roam_result_str(eCsrRoamResult val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_RESULT_NONE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NOT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FORCED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DISASSOC_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DEAUTH_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CAP_CHANGED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_CONNECT); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_INACTIVE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_NEW_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_COALESCED); + default: + return "unknown"; + } +} + +bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc, + struct cdf_mac_addr *pBssId) +{ + cdf_mem_copy(pBssId, &pSirBssDesc->bssId[0], + sizeof(struct cdf_mac_addr)); + return true; +} + +bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fEqual = false; + struct cdf_mac_addr bssId1; + struct cdf_mac_addr bssId2; + + do { + if (!pSirBssDesc1) + break; + if (!pSirBssDesc2) + break; + + if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc1, &bssId1)) + break; + if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc2, &bssId2)) + break; + + fEqual = cdf_is_macaddr_equal(&bssId1, &bssId2); + } while (0); + + return fEqual; +} + +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + if (csr_is_conn_state_connected_ibss(pMac, sessionId) + || csr_is_conn_state_connected_infra(pMac, sessionId) + || csr_is_conn_state_connected_wds(pMac, sessionId)) + return true; + else + return false; +} + +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_infra(pMac, sessionId); +} + +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_ibss(pMac, sessionId) || + csr_is_conn_state_disconnected_ibss(pMac, sessionId); +} + +bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + pMac->roam.roamSession[sessionId].connectState) || + (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState); +} + +bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_wds(pMac, sessionId) || + csr_is_conn_state_disconnected_wds(pMac, sessionId); +} + +bool csr_is_conn_state_ap(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) + return false; + if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) + return true; + return false; +} + +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) && + (csr_is_conn_state_infra(pMac, i) + || csr_is_conn_state_ibss(pMac, i) + || csr_is_conn_state_ap(pMac, i))) { + fRc = true; + break; + } + } + + return fRc; +} + +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac) +{ + uint8_t i; + int8_t sessionid = -1; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_infra(pMac, i)) { + sessionid = i; + break; + } + } + + return sessionid; +} + +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + uint8_t channel; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + channel = + pMac->roam.roamSession[sessionId].connectedProfile. + operationChannel; + } else { + channel = 0; + } + return channel; +} + +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + if (CSR_IS_SESSION_VALID(pMac, sessionId) + && csr_is_conn_state_infra(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if ((pSession->pCurRoamProfile->csrPersona == + CDF_STA_MODE) + || (pSession->pCurRoamProfile->csrPersona == + CDF_P2P_CLIENT_MODE)) + return true; + } + } + return false; +} + +/** + * csr_get_concurrent_operation_channel() - To get concurrent operating channel + * @mac_ctx: Pointer to mac context + * + * This routine will return operating channel on FIRST BSS that is + * active/operating to be used for concurrency mode. + * If other BSS is not up or not connected it will return 0 + * + * Return: uint8_t + */ +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx) +{ + tCsrRoamSession *session = NULL; + uint8_t i = 0; + tCDF_CON_MODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + persona = session->pCurRoamProfile->csrPersona; + if ((((persona == CDF_STA_MODE) || + (persona == CDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) || + (((persona == CDF_P2P_GO_MODE) || + (persona == CDF_SAP_MODE)) + && (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED))) + return session->connectedProfile.operationChannel; + + } + return 0; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + +#define HALF_BW_OF(eCSR_bw_val) ((eCSR_bw_val)/2) + +/* calculation of center channel based on V/HT BW and WIFI channel bw=5MHz) */ + +#define CSR_GET_HT40_PLUS_CCH(och) ((och)+2) +#define CSR_GET_HT40_MINUS_CCH(och) ((och)-2) + +#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och)+6) +#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och)+2) +#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och)-2) +#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och)-6) + +/** + * csr_get_ch_from_ht_profile() - to get channel from HT profile + * @pMac: pointer to Mac context + * @htp: pointer to HT profile + * @och: operating channel + * @cfreq: channel frequency + * @hbw: half bandwidth + * + * This function will fill half bandwidth and channel frequency based + * on the HT profile + * + * Return: none + */ +void csr_get_ch_from_ht_profile(tpAniSirGlobal pMac, tCsrRoamHTProfile *htp, + uint16_t och, uint16_t *cfreq, uint16_t *hbw) +{ + uint16_t cch, ch_bond; + + if (och > 14) + ch_bond = pMac->roam.configParam.channelBondingMode5GHz; + else + ch_bond = pMac->roam.configParam.channelBondingMode24GHz; + + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (!ch_bond) + goto ret; + + sms_log(pMac, LOG1, FL("##HTC: %d scbw: %d rcbw: %d sco: %d" +#ifdef WLAN_FEATURE_11AC + "VHTC: %d apc: %d apbw: %d" +#endif + ), + htp->htCapability, htp->htSupportedChannelWidthSet, + htp->htRecommendedTxWidthSet, + htp->htSecondaryChannelOffset, +#ifdef WLAN_FEATURE_11AC + htp->vhtCapability, htp->apCenterChan, htp->apChanWidth +#endif + ); + +#ifdef WLAN_FEATURE_11AC + if (htp->vhtCapability) { + cch = htp->apCenterChan; + if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + *hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + else if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + *hbw = HALF_BW_OF(eCSR_BW_160MHz_VAL); + + if (!*hbw && htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + else + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } else +#endif + if (htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + cch = CSR_GET_HT40_PLUS_CCH(och); + else if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + cch = CSR_GET_HT40_MINUS_CCH(och); + } else { + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } + +ret: + *cfreq = cds_chan_to_freq(cch); + return; +} + +/** + * csr_calc_chb_for_sap_phymode() - to calc channel bandwidth for sap phymode + * @mac_ctx: pointer to mac context + * @sap_ch: SAP operating channel + * @sap_phymode: SAP physical mode + * @sap_cch: concurrency channel + * @sap_hbw: SAP half bw + * @chb: channel bandwidth + * + * This routine is called to calculate channel bandwidth + * + * Return: none + */ +static void csr_calc_chb_for_sap_phymode(tpAniSirGlobal mac_ctx, + uint16_t *sap_ch, eCsrPhyMode *sap_phymode, + uint16_t *sap_cch, uint16_t *sap_hbw, uint8_t *chb) +{ + if (*sap_phymode == eCSR_DOT11_MODE_11n || + *sap_phymode == eCSR_DOT11_MODE_11n_ONLY) { + + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + + } +#ifdef WLAN_FEATURE_11AC + else if (*sap_phymode == eCSR_DOT11_MODE_11ac || + *sap_phymode == eCSR_DOT11_MODE_11ac_ONLY) { + /*11AC only 80/40/20 Mhz supported in Rome */ + if (mac_ctx->roam.configParam.nVhtChannelWidth == + (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1)) { + *sap_hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1)) + *sap_cch = CSR_GET_HT80_PLUS_LL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT80_PLUS_HL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_LH_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_HH_CCH(*sap_ch); + } else { + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + } + } +#endif +} + +/** + * csr_handle_conc_chnl_overlap_for_sap_go - To handle overlap for AP+AP + * @mac_ctx: pointer to mac context + * @session: Current session + * @sap_ch: SAP/GO operating channel + * @sap_hbw: SAP/GO half bw + * @sap_cfreq: SAP/GO channel frequency + * @intf_ch: concurrent SAP/GO operating channel + * @intf_hbw: concurrent SAP/GO half bw + * @intf_cfreq: concurrent SAP/GO channel frequency + * + * This routine is called to check if one SAP/GO channel is overlapping with + * other SAP/GO channel + * + * Return: none + */ +static void csr_handle_conc_chnl_overlap_for_sap_go(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + uint16_t *sap_ch, uint16_t *sap_hbw, uint16_t *sap_cfreq, + uint16_t *intf_ch, uint16_t *intf_hbw, uint16_t *intf_cfreq) +{ + /* + * if conc_custom_rule1 is defined then we don't + * want p2pgo to follow SAP's channel or SAP to + * follow P2PGO's channel. + */ + if (0 == mac_ctx->roam.configParam.conc_custom_rule1 && + 0 == mac_ctx->roam.configParam.conc_custom_rule2) { + if (*sap_ch == 0) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } else if (*sap_ch != + session->connectedProfile.operationChannel) { + *intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *intf_ch, intf_cfreq, intf_hbw); + } + } else if (*sap_ch == 0 && + (session->pCurRoamProfile->csrPersona == + CDF_SAP_MODE)) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } +} + + +/** + * csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls + * @mac_ctx: Pointer to mac context + * @sap_ch: SAP channel + * @sap_phymode: SAP phy mode + * @cc_switch_mode: concurrent switch mode + * + * This routine will be called to check concurrent overlap channels + * + * Return: uint16_t + */ +uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal mac_ctx, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode) +{ + tCsrRoamSession *session = NULL; + uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED; + uint16_t intf_ch = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0; + uint16_t sap_cfreq = 0; + uint16_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq, sap_cch; + + if (mac_ctx->roam.configParam.cc_switch_mode == + CDF_MCC_TO_SCC_SWITCH_DISABLE) + return 0; + + if (sap_ch != 0) { + sap_cch = sap_ch; + sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (sap_ch > 14) + chb = mac_ctx->roam.configParam.channelBondingMode5GHz; + else + chb = mac_ctx->roam.configParam.channelBondingMode24GHz; + + if (chb) + csr_calc_chb_for_sap_phymode(mac_ctx, &sap_ch, + &sap_phymode, &sap_cch, &sap_hbw, &chb); + sap_cfreq = cds_chan_to_freq(sap_cch); + } + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + if (((session->pCurRoamProfile->csrPersona == CDF_STA_MODE) || + (session->pCurRoamProfile->csrPersona == + CDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) { + intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + intf_ch, &intf_cfreq, &intf_hbw); + } else if (((session->pCurRoamProfile->csrPersona == + CDF_P2P_GO_MODE) || + (session->pCurRoamProfile->csrPersona == + CDF_SAP_MODE)) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + csr_handle_conc_chnl_overlap_for_sap_go(mac_ctx, + session, &sap_ch, &sap_hbw, &sap_cfreq, + &intf_ch, &intf_hbw, &intf_cfreq); + } + } + + if (intf_ch && sap_ch != intf_ch && + cc_switch_mode != CDF_MCC_TO_SCC_SWITCH_FORCE) { + sap_lfreq = sap_cfreq - sap_hbw; + sap_hfreq = sap_cfreq + sap_hbw; + intf_lfreq = intf_cfreq - intf_hbw; + intf_hfreq = intf_cfreq + intf_hbw; + + sms_log(mac_ctx, LOGE, + FL("\nSAP: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d\n" + "INTF: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d"), + sap_ch, cds_chan_to_freq(sap_ch), + cds_freq_to_chan(sap_cfreq), sap_cfreq, sap_hbw * 2, + sap_lfreq, sap_hfreq, intf_ch, + cds_chan_to_freq(intf_ch), cds_freq_to_chan(intf_cfreq), + intf_cfreq, intf_hbw * 2, intf_lfreq, intf_hfreq); + + if (!(((sap_lfreq > intf_lfreq && sap_lfreq < intf_hfreq) || + (sap_hfreq > intf_lfreq && sap_hfreq < intf_hfreq)) || + ((intf_lfreq > sap_lfreq && intf_lfreq < sap_hfreq) || + (intf_hfreq > sap_lfreq && intf_hfreq < sap_hfreq)))) + intf_ch = 0; + } else if (intf_ch && sap_ch != intf_ch && + cc_switch_mode == CDF_MCC_TO_SCC_SWITCH_FORCE) { + if (!((intf_ch < 14 && sap_ch < 14) || + (intf_ch > 14 && sap_ch > 14))) + intf_ch = 0; + } else if (intf_ch == sap_ch) { + intf_ch = 0; + } + + sms_log(mac_ctx, LOGE, FL("##Concurrent Channels %s Interfering"), + intf_ch == 0 ? "Not" : "Are"); + return intf_ch; +} +#endif + +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = true; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + fRc = false; + break; + } + } + + return fRc; +} + +/** + * csr_is_sta_session_connected() - to find if concurrent sta is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if sta + * session exist and active + * + * Return: true or false + */ +bool csr_is_sta_session_connected(tpAniSirGlobal mac_ctx) +{ + uint32_t i; + tCsrRoamSession *pSession = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i) && + !csr_is_conn_state_disconnected(mac_ctx, i)) { + pSession = CSR_GET_SESSION(mac_ctx, i); + + if ((NULL != pSession->pCurRoamProfile) && + (CDF_STA_MODE == + pSession->pCurRoamProfile->csrPersona)) + return true; + } + } + + return false; +} + +/** + * csr_is_p2p_session_connected() - to find if any p2p session is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if any p2p + * session exist and active + * + * Return: true or false + */ +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + tCsrRoamSession *pSession = NULL; + tCDF_CON_MODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + pSession = CSR_GET_SESSION(pMac, i); + persona = pSession->pCurRoamProfile->csrPersona; + if ((NULL != pSession->pCurRoamProfile) && + ((CDF_P2P_CLIENT_MODE == persona) || + (CDF_P2P_GO_MODE == persona))) { + return true; + } + } + } + + return false; +} + +bool csr_is_any_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i, count; + bool fRc = false; + + count = 0; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) + count++; + } + + if (count > 0) + fRc = true; + return fRc; +} + +bool csr_is_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i, noOfConnectedInfra = 0; + + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + ++noOfConnectedInfra; + } + } + + /* More than one Infra Sta Connected */ + if (noOfConnectedInfra > 1) + fRc = true; + return fRc; +} + +bool csr_is_ibss_started(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_ibss(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_btamp_started(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_wds(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac) +{ + uint32_t sessionId, noOfCocurrentSession = 0; + eCsrConnectState connectState; + + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + connectState = + pMac->roam.roamSession[sessionId].connectState; + if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED == + connectState)) { + ++noOfCocurrentSession; + } + } + } + + /* More than one session is Up and Running */ + if (noOfCocurrentSession > 1) + fRc = true; + return fRc; +} + +bool csr_is_infra_ap_started(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId) + && (csr_is_conn_state_connected_infra_ap(pMac, sessionId))) { + fRc = true; + break; + } + } + + return fRc; + +} + +bool csr_is_btamp(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_wds(pMac, sessionId); +} + +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +/** + * csr_is_valid_mc_concurrent_session() - To check concurren session is valid + * @mac_ctx: pointer to mac context + * @session_id: session id + * @bss_descr: bss description + * + * This function validates the concurrent session + * + * Return: true or false + */ +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tSirBssDescription *bss_descr) +{ + tCsrRoamSession *pSession = NULL; + + /* Check for MCC support */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return false; + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) + return false; + /* Validate BeaconInterval */ + pSession = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == pSession->pCurRoamProfile) + return false; + if (CDF_STATUS_SUCCESS == + csr_isconcurrentsession_valid(mac_ctx, session_id, + pSession->pCurRoamProfile->csrPersona)) { + if (CDF_STATUS_SUCCESS == + csr_validate_mcc_beacon_interval(mac_ctx, + bss_descr->channelId, + &bss_descr->beaconInterval, session_id, + pSession->pCurRoamProfile->csrPersona)) + return true; + } + return false; +} + +static tSirMacCapabilityInfo csr_get_bss_capabilities(tSirBssDescription * + pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps; + + /* tSirMacCapabilityInfo is 16-bit */ + cdf_get_u16((uint8_t *) &pSirBssDesc->capabilityInfo, + (uint16_t *) &dot11Caps); + + return dot11Caps; +} + +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ess; +} + +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ibss; +} + +bool csr_is_qo_s_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.qos; +} + +bool csr_is_privacy(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.privacy; +} + +bool csr_is11d_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11dSupportEnabled; +} + +bool csr_is11h_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11hSupportEnabled; +} + +bool csr_is11e_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11eSupportEnabled; +} + +bool csr_is_mcc_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.fenableMCCMode; + +} + +bool csr_is_wmm_supported(tpAniSirGlobal pMac) +{ + if (eCsrRoamWmmNoQos == pMac->roam.configParam.WMMSupportMode) + return false; + else + return true; +} + +/* pIes is the IEs for pSirBssDesc2 */ +bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, tDot11fBeaconIEs *pIes2) +{ + bool fEqual = false; + tSirMacSSid Ssid1, Ssid2; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tDot11fBeaconIEs *pIes1 = NULL; + tDot11fBeaconIEs *pIesLocal = pIes2; + + do { + if ((NULL == pSirBssDesc1) || (NULL == pSirBssDesc2)) + break; + if (!pIesLocal + && + !CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc2, + &pIesLocal))) { + sms_log(pMac, LOGE, FL(" fail to parse IEs")); + break; + } + if (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc1, &pIes1))) { + break; + } + if ((!pIes1->SSID.present) || (!pIesLocal->SSID.present)) + break; + if (pIes1->SSID.num_ssid != pIesLocal->SSID.num_ssid) + break; + cdf_mem_copy(Ssid1.ssId, pIes1->SSID.ssid, + pIes1->SSID.num_ssid); + cdf_mem_copy(Ssid2.ssId, pIesLocal->SSID.ssid, + pIesLocal->SSID.num_ssid); + + fEqual = + cdf_mem_compare(Ssid1.ssId, Ssid2.ssId, + pIesLocal->SSID.num_ssid); + + } while (0); + if (pIes1) + cdf_mem_free(pIes1); + if (pIesLocal && !pIes2) + cdf_mem_free(pIesLocal); + + return fEqual; +} + +/* pIes can be passed in as NULL if the caller doesn't have one prepared */ +bool csr_is_bss_description_wme(tHalHandle hHal, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + /* Assume that WME is found... */ + bool fWme = true; + tDot11fBeaconIEs *pIesTemp = pIes; + + do { + if (pIesTemp == NULL) { + if (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesTemp))) { + fWme = false; + break; + } + } + /* if the Wme Info IE is found, then WME is supported... */ + if (CSR_IS_QOS_BSS(pIesTemp)) + break; + /* if none of these are found, then WME is NOT supported... */ + fWme = false; + } while (0); + if (!csr_is_wmm_supported(pMac) && fWme) { + if (!pIesTemp->HTCaps.present) { + fWme = false; + } + } + if ((pIes == NULL) && (NULL != pIesTemp)) { + /* we allocate memory here so free it before returning */ + cdf_mem_free(pIesTemp); + } + + return fWme; +} + +eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + eCsrMediaAccessType qosType = eCSR_MEDIUM_ACCESS_DCF; + + if (NULL == pIes) { + CDF_ASSERT(pIes != NULL); + return qosType; + } + + do { + /* if we find WMM in the Bss Description, then we let this */ + /* override and use WMM. */ + if (csr_is_bss_description_wme(hHal, pSirBssDesc, pIes)) { + qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } else { + /* if the QoS bit is on, then the AP is advertising 11E QoS... */ + if (csr_is_qo_s_bss_desc(pSirBssDesc)) { + qosType = eCSR_MEDIUM_ACCESS_11e_eDCF; + } else { + qosType = eCSR_MEDIUM_ACCESS_DCF; + } + /* scale back based on the types turned on for the adapter... */ + if (eCSR_MEDIUM_ACCESS_11e_eDCF == qosType + && !csr_is11e_supported(hHal)) { + qosType = eCSR_MEDIUM_ACCESS_DCF; + } + } + + } while (0); + + return qosType; +} + +/* Caller allocates memory for pIEStruct */ +CDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIEStruct) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + int ieLen = + (int)(pBssDesc->length + sizeof(pBssDesc->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + if (ieLen > 0 && pIEStruct) { + if (!DOT11F_FAILED + (dot11f_unpack_beacon_i_es + (pMac, (uint8_t *) pBssDesc->ieFields, ieLen, + pIEStruct))) { + status = CDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* This function will allocate memory for the parsed IEs to the caller. Caller must free the memory */ +/* after it is done with the data only if this function succeeds */ +CDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIEStruct) +{ + CDF_STATUS status = CDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pBssDesc && ppIEStruct) { + *ppIEStruct = cdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((*ppIEStruct) != NULL) { + cdf_mem_set((void *)*ppIEStruct, + sizeof(tDot11fBeaconIEs), 0); + status = + csr_parse_bss_description_ies(hHal, pBssDesc, + *ppIEStruct); + if (!CDF_IS_STATUS_SUCCESS(status)) { + cdf_mem_free(*ppIEStruct); + *ppIEStruct = NULL; + } + } else { + sms_log(pMac, LOGE, FL(" failed to allocate memory")); + CDF_ASSERT(0); + return CDF_STATUS_E_NOMEM; + } + } + + return status; +} + +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len) +{ + bool fNullSsid = false; + + uint32_t SsidLength; + uint8_t *pSsidStr; + + do { + if (0 == len) { + fNullSsid = true; + break; + } + /* Consider 0 or space for hidden SSID */ + if (0 == pBssSsid[0]) { + fNullSsid = true; + break; + } + + SsidLength = len; + pSsidStr = pBssSsid; + + while (SsidLength) { + if (*pSsidStr) + break; + + pSsidStr++; + SsidLength--; + } + + if (0 == SsidLength) { + fNullSsid = true; + break; + } + } while (0); + + return fNullSsid; +} + +uint32_t csr_get_frag_thresh(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.FragmentationThreshold; +} + +uint32_t csr_get_rts_thresh(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.RTSThreshold; +} + +eCsrPhyMode csr_translate_to_phy_mode_from_bss_desc(tSirBssDescription *pSirBssDesc) +{ + eCsrPhyMode phyMode; + + switch (pSirBssDesc->nwType) { + case eSIR_11A_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11a; + break; + + case eSIR_11B_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11b; + break; + + case eSIR_11G_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11g; + break; + + case eSIR_11N_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11n; + break; +#ifdef WLAN_FEATURE_11AC + case eSIR_11AC_NW_TYPE: + default: + phyMode = eCSR_DOT11_MODE_11ac; +#else + default: + phyMode = eCSR_DOT11_MODE_11n; +#endif + break; + } + return phyMode; +} + +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + eCsrCfgDot11Mode csrDot11Mode) +{ + uint32_t ret; + + switch (csrDot11Mode) { + case eCSR_CFG_DOT11_MODE_AUTO: + sms_log(pMac, LOGW, + FL(" Warning: sees eCSR_CFG_DOT11_MODE_AUTO ")); + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11A: + ret = WNI_CFG_DOT11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret = WNI_CFG_DOT11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret = WNI_CFG_DOT11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + ret = WNI_CFG_DOT11_MODE_11G_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + ret = WNI_CFG_DOT11_MODE_11N_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC_ONLY; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + default: + sms_log(pMac, LOGW, FL("doesn't expect %d as csrDo11Mode"), + csrDot11Mode); + if (eCSR_BAND_24 == pMac->roam.configParam.eBand) { + ret = WNI_CFG_DOT11_MODE_11G; + } else { + ret = WNI_CFG_DOT11_MODE_11A; + } + break; + } + + return ret; +} + +/** + * csr_get_phy_mode_from_bss() - Get Phy Mode + * @pMac: Global MAC context + * @pBSSDescription: BSS Descriptor + * @pPhyMode: Physical Mode + * @pIes: Pointer to the IE fields + * + * This function should only return the super set of supported modes + * 11n implies 11b/g/a/n. + * + * Return: success + **/ +CDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + eCsrPhyMode phyMode = + csr_translate_to_phy_mode_from_bss_desc(pBSSDescription); + + if (pIes) { + if (pIes->HTCaps.present) { + phyMode = eCSR_DOT11_MODE_11n; +#ifdef WLAN_FEATURE_11AC + if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) || + IS_BSS_VHT_CAPABLE(pIes->vendor2_ie.VHTCaps)) + phyMode = eCSR_DOT11_MODE_11ac; +#endif + } + *pPhyMode = phyMode; + } + + return status; +} + +/** + * csr_get_phy_mode_in_use() - to get phymode + * @phyModeIn: physical mode + * @bssPhyMode: physical mode in bss + * @f5GhzBand: 5Ghz band + * @pCfgDot11ModeToUse: dot11 mode in use + * + * This function returns the correct eCSR_CFG_DOT11_MODE is the two phyModes + * matches. bssPhyMode is the mode derived from the BSS description + * f5GhzBand is derived from the channel id of BSS description + * + * Return: true or false + */ +bool csr_get_phy_mode_in_use(eCsrPhyMode phyModeIn, eCsrPhyMode bssPhyMode, + bool f5GhzBand, eCsrCfgDot11Mode *pCfgDot11ModeToUse) +{ + bool fMatch = false; + eCsrCfgDot11Mode cfgDot11Mode; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + + switch (phyModeIn) { + /* 11a or 11b or 11g */ + case eCSR_DOT11_MODE_abg: + fMatch = true; + if (f5GhzBand) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + else if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + + case eCSR_DOT11_MODE_11a: + if (f5GhzBand) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + break; + + case eCSR_DOT11_MODE_11g: + if (!f5GhzBand) { + fMatch = true; + if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11g_ONLY: + if (eCSR_DOT11_MODE_11g == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11b: + if (!f5GhzBand) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + } + break; + + case eCSR_DOT11_MODE_11b_ONLY: + if (eCSR_DOT11_MODE_11b == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + } + break; + + case eCSR_DOT11_MODE_11n: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: +#endif + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + + default: +#ifdef WLAN_FEATURE_11AC + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; +#else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; +#endif + break; + } + break; + + case eCSR_DOT11_MODE_11n_ONLY: + if ((eCSR_DOT11_MODE_11n == bssPhyMode)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + + } + + break; +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + } + break; + + case eCSR_DOT11_MODE_11ac_ONLY: + if ((eCSR_DOT11_MODE_11ac == bssPhyMode)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + } + break; +#endif + + default: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; +#endif + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + } + break; + } + + if (fMatch && pCfgDot11ModeToUse) { +#ifdef WLAN_FEATURE_11AC + if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC + && (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))) + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + else +#endif + *pCfgDot11ModeToUse = cfgDot11Mode; + } + return fMatch; +} + +/** + * csr_is_phy_mode_match() - to find if phy mode matches + * @pMac: pointer to mac context + * @phyMode: physical mode + * @pSirBssDesc: bss description + * @pProfile: pointer to roam profile + * @pReturnCfgDot11Mode: dot1 mode to return + * @pIes: pointer to IEs + * + * This function decides whether the one of the bit of phyMode is matching the + * mode in the BSS and allowed by the user setting + * + * Return: true or false based on mode that fits the criteria + */ +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + tCsrRoamProfile *pProfile, + eCsrCfgDot11Mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes) +{ + bool fMatch = false; + eCsrPhyMode phyModeInBssDesc = eCSR_DOT11_MODE_AUTO, phyMode2; + eCsrCfgDot11Mode cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_AUTO; + uint32_t bitMask, loopCount; + + if (!CDF_IS_STATUS_SUCCESS(csr_get_phy_mode_from_bss(pMac, pSirBssDesc, + &phyModeInBssDesc, pIes))) + return fMatch; + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (eCSR_CFG_DOT11_MODE_ABG == + pMac->roam.configParam.uCfgDot11Mode) + phyMode = eCSR_DOT11_MODE_abg; + else if (eCSR_CFG_DOT11_MODE_AUTO == + pMac->roam.configParam.uCfgDot11Mode) +#ifdef WLAN_FEATURE_11AC + phyMode = eCSR_DOT11_MODE_11ac; +#else + phyMode = eCSR_DOT11_MODE_11n; +#endif + + else + /* user's pick */ + phyMode = pMac->roam.configParam.phyMode; + } + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (0 != phyMode) { + if (eCSR_DOT11_MODE_AUTO & phyMode) { + phyMode2 = + eCSR_DOT11_MODE_AUTO & phyMode; + } + } else { + phyMode2 = phyMode; + } + fMatch = csr_get_phy_mode_in_use(phyMode2, phyModeInBssDesc, + CDS_IS_CHANNEL_5GHZ(pSirBssDesc->channelId), + &cfgDot11ModeToUse); + } else { + bitMask = 1; + loopCount = 0; + while (loopCount < eCSR_NUM_PHY_MODE) { + phyMode2 = (phyMode & (bitMask << loopCount++)); + if (0 != phyMode2 && csr_get_phy_mode_in_use(phyMode2, + phyModeInBssDesc, + CDS_IS_CHANNEL_5GHZ + (pSirBssDesc->channelId), + &cfgDot11ModeToUse)) { + fMatch = true; + break; + } + } + } + if (fMatch && pReturnCfgDot11Mode) { + if (pProfile) { + /* + * IEEE 11n spec (8.4.3): HT STA shall + * eliminate TKIP as a choice for the pairwise + * cipher suite if CCMP is advertised by the AP + * or if the AP included an HT capabilities + * element in its Beacons and Probe Response. + */ + if ((!CSR_IS_11n_ALLOWED( + pProfile->negotiatedUCEncryptionType)) + && ((eCSR_CFG_DOT11_MODE_11N == + cfgDot11ModeToUse) || +#ifdef WLAN_FEATURE_11AC + (eCSR_CFG_DOT11_MODE_11AC == + cfgDot11ModeToUse) +#endif + )) { + /* We cannot do 11n here */ + if (!CDS_IS_CHANNEL_5GHZ + (pSirBssDesc->channelId)) { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11G; + } else { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11A; + } + } + } + *pReturnCfgDot11Mode = cfgDot11ModeToUse; + } + + return fMatch; +} + +eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode) +{ + eCsrCfgDot11Mode cfgDot11ModeToUse; + eCsrBand eBand = pMac->roam.configParam.eBand; + + if ((0 == phyMode) || +#ifdef WLAN_FEATURE_11AC + (eCSR_DOT11_MODE_11ac & phyMode) || +#endif + (eCSR_DOT11_MODE_AUTO & phyMode)) { +#ifdef WLAN_FEATURE_11AC + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC; + } else +#endif + { + /* Default to 11N mode if user has configured 11ac mode + * and FW doesn't supports 11ac mode . + */ + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } + } else { + if ((eCSR_DOT11_MODE_11n | eCSR_DOT11_MODE_11n_ONLY) & phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } else if (eCSR_DOT11_MODE_abg & phyMode) { + if (eCSR_BAND_24 != eBand) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + } else { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + } + } else if (eCSR_DOT11_MODE_11a & phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + } else if ((eCSR_DOT11_MODE_11g | eCSR_DOT11_MODE_11g_ONLY) & + phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + } else { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11B; + } + } + + return cfgDot11ModeToUse; +} + +uint32_t csr_get11h_power_constraint(tHalHandle hHal, + tDot11fIEPowerConstraints *pPowerConstraint) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint32_t localPowerConstraint = 0; + + /* check if .11h support is enabled, if not, the power constraint is 0. */ + if (pMac->roam.configParam.Is11hSupportEnabled + && pPowerConstraint->present) { + localPowerConstraint = pPowerConstraint->localPowerConstraints; + } + + return localPowerConstraint; +} + +bool csr_is_profile_wpa(tCsrRoamProfile *pProfile) +{ + bool fWpaProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: +#endif + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + + if (fWpaProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + } + return fWpaProfile; +} + +bool csr_is_profile_rsn(tCsrRoamProfile *pProfile) +{ + bool fRSNProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_RSN: + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN: + case eCSR_AUTH_TYPE_FT_RSN_PSK: +#endif +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + + if (fRSNProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + /* !!REVIEW - For WPA2, use of RSN IE mandates */ + /* use of AES as encryption. Here, we qualify */ + /* even if encryption type is WEP or TKIP */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + } + return fRSNProfile; +} + +/** + * csr_isconcurrentsession_valid() - check if concurrent session is valid + * @mac_ctx: pointer to mac context + * @cur_sessionid: current session id + * @cur_bss_persona: current BSS persona + * + * This function will check if concurrent session is valid + * + * Return: CDF_STATUS + */ +CDF_STATUS +csr_isconcurrentsession_valid(tpAniSirGlobal mac_ctx, uint32_t cur_sessionid, + tCDF_CON_MODE cur_bss_persona) +{ + uint32_t sessionid = 0; + tCDF_CON_MODE bss_persona; + eCsrConnectState connect_state, temp; + tCsrRoamSession *roam_session; + + for (sessionid = 0; sessionid < CSR_ROAM_SESSION_MAX; sessionid++) { + if (cur_sessionid == sessionid) + continue; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionid)) + continue; + roam_session = &mac_ctx->roam.roamSession[sessionid]; + bss_persona = roam_session->bssParams.bssPersona; + connect_state = roam_session->connectState; + + switch (cur_bss_persona) { + case CDF_STA_MODE: + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("** STA session **")); + return CDF_STATUS_SUCCESS; + + case CDF_SAP_MODE: + temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; +#ifndef WLAN_FEATURE_MBSSID + if ((bss_persona == CDF_SAP_MODE) && + (connect_state != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("sap mode already exist")); + return CDF_STATUS_E_FAILURE; + } else +#endif + if ((bss_persona == CDF_IBSS_MODE) + && (connect_state != temp)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Can't start GO")); + return CDF_STATUS_E_FAILURE; + } + break; + + case CDF_P2P_GO_MODE: + temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + if ((bss_persona == CDF_P2P_GO_MODE) && + (connect_state != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("GO mode already exists")); + return CDF_STATUS_E_FAILURE; + } else if ((bss_persona == CDF_IBSS_MODE) + && (connect_state != temp)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Can't start SAP")); + return CDF_STATUS_E_FAILURE; + } + break; + case CDF_IBSS_MODE: + if ((bss_persona == CDF_IBSS_MODE) && (connect_state != + eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("IBSS mode already exist")); + return CDF_STATUS_E_FAILURE; + } else if (((bss_persona == CDF_P2P_GO_MODE) || + (bss_persona == CDF_SAP_MODE)) && + (connect_state != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Can't start GO")); + return CDF_STATUS_E_FAILURE; + } + break; + case CDF_P2P_CLIENT_MODE: + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("**P2P-Client session**")); + return CDF_STATUS_SUCCESS; + default: + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Persona not handled = %d"), + cur_bss_persona); + break; + } + } + return CDF_STATUS_SUCCESS; + +} + +/** + * csr_update_mcc_p2p_beacon_interval() - update p2p beacon interval + * @mac_ctx: pointer to mac context + * + * This function is to update the mcc p2p beacon interval + * + * Return: CDF_STATUS + */ +CDF_STATUS csr_update_mcc_p2p_beacon_interval(tpAniSirGlobal mac_ctx) +{ + uint32_t session_id = 0; + tCsrRoamSession *roam_session; + + /* If MCC is not supported just break and return SUCCESS */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return CDF_STATUS_E_FAILURE; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + /* + * If GO in MCC support different beacon interval, + * change the BI of the P2P-GO + */ + roam_session = &mac_ctx->roam.roamSession[session_id]; + if (roam_session->bssParams.bssPersona != CDF_P2P_GO_MODE) + continue; + /* + * Handle different BI scneario based on the + * configuration set.If Config is set to 0x02 then + * Disconnect all the P2P clients associated. If config + * is set to 0x04 then update the BI without + * disconnecting all the clients + */ + if ((mac_ctx->roam.configParam.fAllowMCCGODiffBI == 0x04) + && (roam_session->bssParams. + updatebeaconInterval)) { + return csr_send_chng_mcc_beacon_interval(mac_ctx, + session_id); + } else if (roam_session->bssParams.updatebeaconInterval) { + /* + * If the configuration of fAllowMCCGODiffBI is set to + * other than 0x04 + */ + return csr_roam_call_callback(mac_ctx, + session_id, + NULL, 0, + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + eCSR_ROAM_RESULT_NONE); + } + } + return CDF_STATUS_E_FAILURE; +} + +uint16_t csr_calculate_mcc_beacon_interval(tpAniSirGlobal pMac, uint16_t sta_bi, + uint16_t go_gbi) +{ + uint8_t num_beacons = 0; + uint8_t is_multiple = 0; + uint16_t go_cbi = 0; + uint16_t go_fbi = 0; + uint16_t sta_cbi = 0; + + /* If GO's given beacon Interval is less than 100 */ + if (go_gbi < 100) + go_cbi = 100; + /* if GO's given beacon Interval is greater than or equal to 100 */ + else + go_cbi = 100 + (go_gbi % 100); + + if (sta_bi == 0) { + /* There is possibility to receive zero as value. + Which will cause divide by zero. Hence initialise with 100 + */ + sta_bi = 100; + sms_log(pMac, LOGW, + FL("sta_bi 2nd parameter is zero, initialize to %d"), + sta_bi); + } + /* check, if either one is multiple of another */ + if (sta_bi > go_cbi) { + is_multiple = !(sta_bi % go_cbi); + } else { + is_multiple = !(go_cbi % sta_bi); + } + /* if it is multiple, then accept GO's beacon interval range [100,199] as it is */ + if (is_multiple) { + return go_cbi; + } + /* else , if it is not multiple, then then check for number of beacons to be */ + /* inserted based on sta BI */ + num_beacons = sta_bi / 100; + if (num_beacons) { + /* GO's final beacon interval will be aligned to sta beacon interval, but */ + /* in the range of [100, 199]. */ + sta_cbi = sta_bi / num_beacons; + go_fbi = sta_cbi; + } else { + /* if STA beacon interval is less than 100, use GO's change bacon interval */ + /* instead of updating to STA's beacon interval. */ + go_fbi = go_cbi; + } + return go_fbi; +} + +CDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId, + uint16_t *beaconInterval, + uint32_t cursessionId, + tCDF_CON_MODE currBssPersona) +{ + uint32_t sessionId = 0; + uint16_t new_beaconInterval = 0; + + /* If MCC is not supported just break */ + if (!pMac->roam.configParam.fenableMCCMode) { + return CDF_STATUS_E_FAILURE; + } + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (cursessionId != sessionId) { + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + continue; + } + + switch (currBssPersona) { + case CDF_STA_MODE: + if (pMac->roam.roamSession[sessionId]. + pCurRoamProfile && + (pMac->roam.roamSession[sessionId]. + pCurRoamProfile->csrPersona == + CDF_P2P_CLIENT_MODE)) { + /* check for P2P client mode */ + sms_log(pMac, LOG1, + FL + (" Beacon Interval Validation not required for STA/CLIENT")); + } + /* + * IF SAP has started and STA wants to connect + * on different channel MCC should + * MCC should not be enabled so making it + * false to enforce on same channel + */ + else if (pMac->roam.roamSession[sessionId]. + bssParams.bssPersona == + CDF_SAP_MODE) { + if (pMac->roam.roamSession[sessionId]. + bssParams.operationChn != + channelId) { + sms_log(pMac, LOGE, + FL + ("*** MCC with SAP+STA sessions ****")); + return CDF_STATUS_SUCCESS; + } + } else if (pMac->roam.roamSession[sessionId]. + bssParams.bssPersona == + CDF_P2P_GO_MODE) { + /* + * Check for P2P go scenario + * if GO in MCC support different + * beacon interval, + * change the BI of the P2P-GO + */ + if ((pMac->roam.roamSession[sessionId]. + bssParams.operationChn != + channelId) + && (pMac->roam. + roamSession[sessionId]. + bssParams.beaconInterval != + *beaconInterval)) { + /* if GO in MCC support different beacon interval, return success */ + if (pMac->roam.configParam. + fAllowMCCGODiffBI == 0x01) { + return + CDF_STATUS_SUCCESS; + } + /* Send only Broadcast disassoc and update beaconInterval */ + /* If configuration is set to 0x04 then dont */ + /* disconnect all the station */ + else if ((pMac->roam. + configParam. + fAllowMCCGODiffBI == + 0x02) + || (pMac->roam. + configParam. + fAllowMCCGODiffBI + == 0x04)) { + /* Check to pass the right beacon Interval */ + if (pMac->roam.configParam.conc_custom_rule1 || + pMac->roam.configParam.conc_custom_rule2) { + new_beaconInterval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_beaconInterval = + csr_calculate_mcc_beacon_interval(pMac, + *beaconInterval, + pMac->roam. + roamSession + [sessionId]. + bssParams. + beaconInterval); + } + sms_log(pMac, LOG1, + FL + (" Peer AP BI : %d, new Beacon Interval: %d"), + *beaconInterval, + new_beaconInterval); + /* Update the becon Interval */ + if (new_beaconInterval + != + pMac->roam. + roamSession + [sessionId]. + bssParams. + beaconInterval) { + /* Update the beaconInterval now */ + sms_log(pMac, + LOGE, + FL + (" Beacon Interval got changed config used: %d\n"), + pMac-> + roam. + configParam. + fAllowMCCGODiffBI); + + pMac->roam. + roamSession + [sessionId]. + bssParams. + beaconInterval + = + new_beaconInterval; + pMac->roam. + roamSession + [sessionId]. + bssParams. + updatebeaconInterval + = true; + return + csr_update_mcc_p2p_beacon_interval + (pMac); + } + return + CDF_STATUS_SUCCESS; + } + /* Disconnect the P2P session */ + else if (pMac->roam.configParam. + fAllowMCCGODiffBI == + 0x03) { + pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = false; + return + csr_roam_call_callback + (pMac, sessionId, + NULL, 0, + eCSR_ROAM_SEND_P2P_STOP_BSS, + eCSR_ROAM_RESULT_NONE); + } else { + sms_log(pMac, LOGE, + FL + ("BeaconInterval is different cannot connect to preferred AP...")); + return + CDF_STATUS_E_FAILURE; + } + } + } + break; + + case CDF_P2P_CLIENT_MODE: + if (pMac->roam.roamSession[sessionId]. + pCurRoamProfile && + (pMac->roam.roamSession[sessionId]. + pCurRoamProfile->csrPersona == + CDF_STA_MODE)) { + /* check for P2P client mode */ + sms_log(pMac, LOG1, + FL + (" Ignore Beacon Interval Validation...")); + } else if (pMac->roam.roamSession[sessionId]. + bssParams.bssPersona == + CDF_P2P_GO_MODE) { + /* Check for P2P go scenario */ + if ((pMac->roam.roamSession[sessionId]. + bssParams.operationChn != + channelId) + && (pMac->roam. + roamSession[sessionId]. + bssParams.beaconInterval != + *beaconInterval)) { + sms_log(pMac, LOGE, + FL + ("BeaconInterval is different cannot connect to P2P_GO network ...")); + return CDF_STATUS_E_FAILURE; + } + } + break; + + case CDF_SAP_MODE: + break; + + case CDF_P2P_GO_MODE: + { + if (pMac->roam.roamSession[sessionId]. + pCurRoamProfile && + ((pMac->roam.roamSession[sessionId]. + pCurRoamProfile->csrPersona == + CDF_P2P_CLIENT_MODE) || + (pMac->roam.roamSession[sessionId]. + pCurRoamProfile->csrPersona == + CDF_STA_MODE))) { + /* check for P2P_client scenario */ + if ((pMac->roam. + roamSession[sessionId]. + connectedProfile. + operationChannel == 0) + && (pMac->roam. + roamSession[sessionId]. + connectedProfile. + beaconInterval == 0)) { + continue; + } + + if (csr_is_conn_state_connected_infra + (pMac, sessionId) + && (pMac->roam. + roamSession[sessionId]. + connectedProfile. + operationChannel != + channelId) + && (pMac->roam. + roamSession[sessionId]. + connectedProfile. + beaconInterval != + *beaconInterval)) { + /* + * Updated beaconInterval should be used only when we are starting a new BSS + * not incase of client or STA case + */ + /* Calculate beacon Interval for P2P-GO incase of MCC */ + if (pMac->roam.configParam.conc_custom_rule1 || + pMac->roam.configParam.conc_custom_rule2) { + new_beaconInterval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_beaconInterval = + csr_calculate_mcc_beacon_interval + (pMac, + pMac->roam. + roamSession + [sessionId]. + connectedProfile. + beaconInterval, + *beaconInterval); + } + if (*beaconInterval != + new_beaconInterval) + *beaconInterval + = + new_beaconInterval; + return + CDF_STATUS_SUCCESS; + } + } + } + break; + + default: + sms_log(pMac, LOGE, + FL(" Persona not supported : %d"), + currBssPersona); + return CDF_STATUS_E_FAILURE; + } + } + } + + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/* Function to return true if the authtype is 11r */ +bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent) +{ + switch (AuthType) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + if (mdiePresent) + return true; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + case eCSR_AUTH_TYPE_FT_RSN: + return true; + break; + default: + break; + } + return false; +} + +/* Function to return true if the profile is 11r */ +bool csr_is_profile11r(tCsrRoamProfile *pProfile) +{ + return csr_is_auth_type11r(pProfile->negotiatedAuthType, + pProfile->MDID.mdiePresent); +} + +#endif + +#ifdef FEATURE_WLAN_ESE + +/* Function to return true if the authtype is ESE */ +bool csr_is_auth_type_ese(eCsrAuthType AuthType) +{ + switch (AuthType) { + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: + return true; + break; + default: + break; + } + return false; +} + +/* Function to return true if the profile is ESE */ +bool csr_is_profile_ese(tCsrRoamProfile *pProfile) +{ + return csr_is_auth_type_ese(pProfile->negotiatedAuthType); +} + +#endif + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile) +{ + bool fWapiProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + + if (fWapiProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WPI: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + } + return fWapiProfile; +} + +static bool csr_is_wapi_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return cdf_mem_compare(Oui1, Oui2, CSR_WAPI_OUI_SIZE); +} + +static bool csr_is_wapi_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], + uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wapi_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) { + cdf_mem_copy(Oui, AllCyphers[idx], CSR_WAPI_OUI_SIZE); + } + + return fYes; +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_is_wpa_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return cdf_mem_compare(Oui1, Oui2, CSR_WPA_OUI_SIZE); +} + +static bool csr_is_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WPA_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wpa_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) { + cdf_mem_copy(Oui, AllCyphers[idx], CSR_WPA_OUI_SIZE); + } + + return fYes; +} + +static bool csr_match_rsnoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, csr_rsn_oui[ouiIndex], Oui); + +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_match_wapi_oui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllCyphers, cAllCyphers, csr_wapi_oui[ouiIndex], Oui); + +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_match_wpaoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, csr_wpa_oui[ouiIndex], Oui); + +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_is_auth_wapi_cert(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[1], Oui); +} + +static bool csr_is_auth_wapi_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[2], Oui); +} +#endif /* FEATURE_WLAN_WAPI */ + +#ifdef WLAN_FEATURE_VOWIFI_11R + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the 802.1X exchange. + */ +static bool csr_is_ft_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[03], Oui); +} + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the PSK. + */ +static bool csr_is_ft_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[04], Oui); +} + +#endif + +#ifdef FEATURE_WLAN_ESE + +/* + * Function for ESE CCKM AKM Authentication. We match the CCKM AKM + * Authentication Key Management suite here. This matches for CCKM AKM Auth + * with the 802.1X exchange. + */ +static bool csr_is_ese_cckm_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[06], Oui); +} + +static bool csr_is_ese_cckm_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[06], Oui); +} + +#endif + +static bool csr_is_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[01], Oui); +} + +static bool csr_is_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[02], Oui); +} + +#ifdef WLAN_FEATURE_11W +static bool csr_is_auth_rsn_psk_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[07], Oui); +} +static bool csr_is_auth_rsn8021x_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[8], Oui); +} +#endif + +static bool csr_is_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[01], Oui); +} + +static bool csr_is_auth_wpa_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[02], Oui); +} + +uint8_t csr_get_oui_index_from_cipher(eCsrEncryptionType enType) +{ + uint8_t OUIIndex; + + switch (enType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + OUIIndex = CSR_OUI_WEP40_OR_1X_INDEX; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + OUIIndex = CSR_OUI_WEP104_INDEX; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + OUIIndex = CSR_OUI_TKIP_OR_PSK_INDEX; + break; + case eCSR_ENCRYPT_TYPE_AES: + OUIIndex = CSR_OUI_AES_INDEX; + break; + case eCSR_ENCRYPT_TYPE_NONE: + OUIIndex = CSR_OUI_USE_GROUP_CIPHER_INDEX; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + OUIIndex = CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: /* HOWTO handle this? */ + OUIIndex = CSR_OUI_RESERVED_INDEX; + break; + } /* switch */ + + return OUIIndex; +} +/** + * csr_get_rsn_information() - to get RSN infomation + * @hal: pointer to HAL + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @rsn_ie: pointer to RSN IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @capabilities: RSN capabilities + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all RSN information + * + * Return: bool + */ +bool csr_get_rsn_information(tHalHandle hal, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIERSN *rsn_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + tCsrRSNCapabilities *capabilities, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_RSN_OUI_SIZE]; + uint8_t multicast[CSR_RSN_OUI_SIZE]; + uint8_t authsuites[CSR_RSN_MAX_AUTH_SUITES][CSR_RSN_OUI_SIZE]; + uint8_t authentication[CSR_RSN_OUI_SIZE]; + uint8_t mccipher_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!rsn_ie->present) + goto end; + c_mcast_cipher++; + cdf_mem_copy(mccipher_arr, rsn_ie->gp_cipher_suite, + CSR_RSN_OUI_SIZE); + c_ucast_cipher = + (uint8_t) (rsn_ie->pwise_cipher_suite_count); + c_auth_suites = (uint8_t) (rsn_ie->akm_suite_count); + for (i = 0; i < c_auth_suites && i < CSR_RSN_MAX_AUTH_SUITES; i++) { + cdf_mem_copy((void *)&authsuites[i], + (void *)&rsn_ie->akm_suites[i], CSR_RSN_OUI_SIZE); + } + + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + rsn_ie->pwise_cipher_suites, c_ucast_cipher, + csr_get_oui_index_from_cipher(encr_type), + unicast); + + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]), + multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype. + */ +#ifdef WLAN_FEATURE_VOWIFI_11R + /* Changed the AKM suites according to order of preference */ + if (csr_is_ft_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ft_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN_PSK == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN_PSK; + } +#endif +#ifdef FEATURE_WLAN_ESE + /* ESE only supports 802.1X. No PSK. */ + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_ese_cckm_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_CCKM_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_RSN; + } +#endif + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK; + } +#ifdef WLAN_FEATURE_11W + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_rsn8021x_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } +#endif + + /* + * The 1st auth type in the APs RSN IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the RSN IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } /* for */ +end: + if (acceptable_cipher) { + if (mcast_cipher) + cdf_mem_copy(mcast_cipher, multicast, + CSR_RSN_OUI_SIZE); + + if (ucast_cipher) + cdf_mem_copy(ucast_cipher, unicast, CSR_RSN_OUI_SIZE); + + if (auth_suite) + cdf_mem_copy(auth_suite, authentication, + CSR_RSN_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + + if (capabilities) { + /* Bit 0 Preauthentication */ + capabilities->PreAuthSupported = + (rsn_ie->RSN_Cap[0] >> 0) & 0x1; + /* Bit 1 No Pairwise */ + capabilities->NoPairwise = + (rsn_ie->RSN_Cap[0] >> 1) & 0x1; + /* Bit 2, 3 PTKSA Replay Counter */ + capabilities->PTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 2) & 0x3; + /* Bit 4, 5 GTKSA Replay Counter */ + capabilities->GTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 4) & 0x3; +#ifdef WLAN_FEATURE_11W + /* Bit 6 MFPR */ + capabilities->MFPRequired = + (rsn_ie->RSN_Cap[0] >> 6) & 0x1; + /* Bit 7 MFPC */ + capabilities->MFPCapable = + (rsn_ie->RSN_Cap[0] >> 7) & 0x1; +#else + /* Bit 6 MFPR */ + capabilities->MFPRequired = 0; + /* Bit 7 MFPC */ + capabilities->MFPCapable = 0; +#endif + /* remaining reserved */ + capabilities->Reserved = rsn_ie->RSN_Cap[1] & 0xff; + } + } + return acceptable_cipher; +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_is_pmf_capabilities_in_rsn_match() - check for PMF capability + * @hHal: Global HAL handle + * @pFilterMFPEnabled: given by supplicant to us to specify what kind + * of connection supplicant is expecting to make + * if it is enabled then make PMF connection. + * if it is disabled then make normal connection. + * @pFilterMFPRequired: given by supplicant based on our configuration + * if it is 1 then we will require mandatory + * PMF connection and if it is 0 then we PMF + * connection is optional. + * @pFilterMFPCapable: given by supplicant based on our configuration + * if it 1 then we are PMF capable and if it 0 + * then we are not PMF capable. + * @pRSNIe: RSNIe from Beacon/probe response of + * neighbor AP against which we will compare + * our capabilities. + * + * This function is to match our current capabilities with the AP + * to which we are expecting make the connection. + * + * Return: if our PMF capabilities matches with AP then we + * will return true to indicate that we are good + * to make connection with it. Else we will return false + **/ +static bool +csr_is_pmf_capabilities_in_rsn_match(tHalHandle hHal, + bool *pFilterMFPEnabled, + uint8_t *pFilterMFPRequired, + uint8_t *pFilterMFPCapable, + tDot11fIERSN *pRSNIe) +{ + uint8_t apProfileMFPCapable = 0; + uint8_t apProfileMFPRequired = 0; + if (pRSNIe && pFilterMFPEnabled && pFilterMFPCapable + && pFilterMFPRequired) { + /* Extracting MFPCapable bit from RSN Ie */ + apProfileMFPCapable = (pRSNIe->RSN_Cap[0] >> 7) & 0x1; + apProfileMFPRequired = (pRSNIe->RSN_Cap[0] >> 6) & 0x1; + if (*pFilterMFPEnabled && *pFilterMFPCapable + && *pFilterMFPRequired && (apProfileMFPCapable == 0)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "AP is not capable to make PMF connection"); + return false; + } else if (*pFilterMFPEnabled && *pFilterMFPCapable && + !(*pFilterMFPRequired) && + (apProfileMFPCapable == 0)) { + /* + * This is tricky, because supplicant asked us to + * make mandatory PMF connection eventhough PMF + * connection is optional here. + * so if AP is not capable of PMF then drop it. + * Don't try to connect with it. + */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "we need PMF connection & AP isn't capable to make PMF connection"); + return false; + } else if (!(*pFilterMFPCapable) && + apProfileMFPCapable && apProfileMFPRequired) { + + /* + * In this case, AP with whom we trying to connect + * requires mandatory PMF connections and we are not + * capable so this AP is not good choice to connect + */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "AP needs PMF connection and we are not capable of pmf connection"); + return false; + } else if (!(*pFilterMFPEnabled) && *pFilterMFPCapable && + (apProfileMFPCapable == 1)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "we don't need PMF connection even though both parties are capable"); + return false; + } + } + return true; +} +#endif + +bool csr_is_rsn_match(tHalHandle hHal, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + bool *pMFPEnabled, uint8_t *pMFPRequired, + uint8_t *pMFPCapable, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fRSNMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fRSNMatch = + csr_get_rsn_information(hHal, pAuthType, enType, pEnMcType, &pIes->RSN, + NULL, NULL, NULL, NULL, pNegotiatedAuthType, + pNegotiatedMCCipher); +#ifdef WLAN_FEATURE_11W + /* If all the filter matches then finally checks for PMF capabilities */ + if (fRSNMatch) { + fRSNMatch = csr_is_pmf_capabilities_in_rsn_match(hHal, pMFPEnabled, + pMFPRequired, + pMFPCapable, + &pIes->RSN); + } +#endif + return fRSNMatch; +} + +bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId, + uint8_t *pPMKId) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + + do { + for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) { + sms_log(pMac, LOG1, + "match PMKID " MAC_ADDRESS_STR " to ", + MAC_ADDR_ARRAY(pBSSId)); + if (cdf_mem_compare + (pBSSId, pSession->PmkidCacheInfo[Index].BSSID.bytes, + sizeof(struct cdf_mac_addr))) { + /* match found */ + fMatchFound = true; + break; + } + } + + if (!fMatchFound) + break; + + cdf_mem_copy(pPMKId, pSession->PmkidCacheInfo[Index].PMKID, + CSR_RSN_PMKID_SIZE); + + fRC = true; + } while (0); + sms_log(pMac, LOGW, + "csr_lookup_pmkid called return match = %d pMac->roam.NumPmkidCache = %d", + fRC, pSession->NumPmkidCache); + + return fRC; +} + +uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRSNMatch; + uint8_t cbRSNIe = 0; + uint8_t UnicastCypher[CSR_RSN_OUI_SIZE]; + uint8_t MulticastCypher[CSR_RSN_OUI_SIZE]; + uint8_t AuthSuite[CSR_RSN_OUI_SIZE]; + tCsrRSNAuthIe *pAuthSuite; + tCsrRSNCapabilities RSNCapabilities; + tCsrRSNPMKIe *pPMK; + uint8_t PMKId[CSR_RSN_PMKID_SIZE]; +#ifdef WLAN_FEATURE_11W + uint8_t *pGroupMgmtCipherSuite; +#endif + tDot11fBeaconIEs *pIesLocal = pIes; + eCsrAuthType negAuthType = eCSR_AUTH_TYPE_UNKNOWN; + + sms_log(pMac, LOGW, "%s called...", __func__); + + do { + if (!csr_is_profile_rsn(pProfile)) + break; + + if (!pIesLocal + && + (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fRSNMatch = + csr_get_rsn_information(hHal, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->RSN, UnicastCypher, + MulticastCypher, AuthSuite, + &RSNCapabilities, &negAuthType, NULL); + if (!fRSNMatch) + break; + + pRSNIe->IeHeader.ElementID = SIR_MAC_RSN_EID; + + pRSNIe->Version = CSR_RSN_VERSION_SUPPORTED; + + cdf_mem_copy(pRSNIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pRSNIe->cUnicastCyphers = 1; + + cdf_mem_copy(&pRSNIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrRSNAuthIe *) (&pRSNIe-> + UnicastOui[pRSNIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* RSN capabilities follows the Auth Suite (two octects) */ + /* !!REVIEW - What should STA put in RSN capabilities, currently */ + /* just putting back APs capabilities */ + /* For one, we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */ + /* For another, we should use the Management Frame Protection values given by the supplicant */ + RSNCapabilities.PreAuthSupported = 0; +#ifdef WLAN_FEATURE_11W + if (RSNCapabilities.MFPCapable && pProfile->MFPCapable) { + RSNCapabilities.MFPCapable = pProfile->MFPCapable; + RSNCapabilities.MFPRequired = pProfile->MFPRequired; + } else { + RSNCapabilities.MFPCapable = 0; + RSNCapabilities.MFPRequired = 0; + } +#endif + *(uint16_t *) (&pAuthSuite->AuthOui[1]) = + *((uint16_t *) (&RSNCapabilities)); + + pPMK = + (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) + + sizeof(uint16_t)); + + /* Don't include the PMK SA IDs for CCKM associations. */ + if ( +#ifdef FEATURE_WLAN_ESE + (eCSR_AUTH_TYPE_CCKM_RSN != negAuthType) && +#endif + csr_lookup_pmkid(pMac, sessionId, pSirBssDesc->bssId, + &(PMKId[0]))) { + pPMK->cPMKIDs = 1; + + cdf_mem_copy(pPMK->PMKIDList[0].PMKID, PMKId, + CSR_RSN_PMKID_SIZE); + } else { + pPMK->cPMKIDs = 0; + } + +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled) { + pGroupMgmtCipherSuite = + (uint8_t *) pPMK + sizeof(uint16_t) + + (pPMK->cPMKIDs * CSR_RSN_PMKID_SIZE); + cdf_mem_copy(pGroupMgmtCipherSuite, csr_rsn_oui[07], + CSR_WPA_OUI_SIZE); + } +#endif + + /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */ + /* Add in the size of the Auth suite (count plus a single OUI) */ + /* Add in the RSN caps field. */ + /* Add PMKID count and PMKID (if any) */ + /* Add group management cipher suite */ + pRSNIe->IeHeader.Length = + (uint8_t) (sizeof(*pRSNIe) - sizeof(pRSNIe->IeHeader) + + sizeof(*pAuthSuite) + + sizeof(tCsrRSNCapabilities)); + if (pPMK->cPMKIDs) { + pRSNIe->IeHeader.Length += (uint8_t) (sizeof(uint16_t) + + (pPMK->cPMKIDs * + CSR_RSN_PMKID_SIZE)); + } +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled) { + if (0 == pPMK->cPMKIDs) + pRSNIe->IeHeader.Length += sizeof(uint16_t); + pRSNIe->IeHeader.Length += CSR_WPA_OUI_SIZE; + } +#endif + + /* return the size of the IE header (total) constructed... */ + cbRSNIe = pRSNIe->IeHeader.Length + sizeof(pRSNIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + + return cbRSNIe; +} + +#ifdef FEATURE_WLAN_WAPI +/** + * csr_get_wapi_information() - to get WAPI infomation + * @hal: pointer to HAL + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wapi_ie: pointer to WAPI IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WAPI information + * + * Return: bool + */ +bool csr_get_wapi_information(tHalHandle hal, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIEWAPI *wapi_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_WAPI_OUI_SIZE]; + uint8_t multicast[CSR_WAPI_OUI_SIZE]; + uint8_t authsuites[CSR_WAPI_MAX_AUTH_SUITES][CSR_WAPI_OUI_SIZE]; + uint8_t authentication[CSR_WAPI_OUI_SIZE]; + uint8_t mccipher_arr[CSR_WAPI_MAX_MULTICAST_CYPHERS][CSR_WAPI_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + uint8_t wapioui_idx = 0; + + if (!wapi_ie->present) + goto end; + + c_mcast_cipher++; + cdf_mem_copy(mccipher_arr, wapi_ie->multicast_cipher_suite, + CSR_WAPI_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wapi_ie->unicast_cipher_suite_count); + c_auth_suites = (uint8_t) (wapi_ie->akm_suite_count); + for (i = 0; i < c_auth_suites && i < CSR_WAPI_MAX_AUTH_SUITES; i++) + cdf_mem_copy((void *)&authsuites[i], + (void *)&wapi_ie->akm_suites[i], CSR_WAPI_OUI_SIZE); + + wapioui_idx = csr_get_oui_index_from_cipher(encr_type); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sms_log(mac_ctx, LOGE, + FL("Wapi OUI index = %d out of limit"), + wapioui_idx); + acceptable_cipher = false; + goto end; + } + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + wapi_ie->unicast_cipher_suites, + c_ucast_cipher, wapioui_idx, unicast); + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + wapioui_idx = csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sms_log(mac_ctx, LOGE, + FL("Wapi OUI index = %d out of limit"), + wapioui_idx); + acceptable_cipher = false; + break; + } + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + wapioui_idx, multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = + mc_encryption->encryptionType[i]; + + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wapi_cert + (mac_ctx, authsuites, c_auth_suites, authentication)) { + neg_authtype = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + } else if (csr_is_auth_wapi_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + neg_authtype = eCSR_AUTH_TYPE_WAPI_WAI_PSK; + } else { + acceptable_cipher = false; + neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + } + + /* Caller doesn't care about auth type, or BSS doesn't match */ + if ((0 == auth_type->numEntries) || (false == acceptable_cipher)) + goto end; + + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + if (auth_type->authType[i] == neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + cdf_mem_copy(mcast_cipher, multicast, + CSR_WAPI_OUI_SIZE); + if (ucast_cipher) + cdf_mem_copy(ucast_cipher, unicast, CSR_WAPI_OUI_SIZE); + if (auth_suite) + cdf_mem_copy(auth_suite, authentication, + CSR_WAPI_OUI_SIZE); + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + return acceptable_cipher; +} + +bool csr_is_wapi_match(tHalHandle hHal, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWapiMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWapiMatch = + csr_get_wapi_information(hHal, pAuthType, enType, pEnMcType, + &pIes->WAPI, NULL, NULL, NULL, + pNegotiatedAuthType, pNegotiatedMCCipher); + + return fWapiMatch; +} + +bool csr_lookup_bkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId, + uint8_t *pBKId) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + + do { + for (Index = 0; Index < pSession->NumBkidCache; Index++) { + sms_log(pMac, LOGW, "match BKID " MAC_ADDRESS_STR " to ", + MAC_ADDR_ARRAY(pBSSId)); + if (cdf_mem_compare + (pBSSId, pSession->BkidCacheInfo[Index].BSSID.bytes, + sizeof(struct cdf_mac_addr))) { + /* match found */ + fMatchFound = true; + break; + } + } + + if (!fMatchFound) + break; + + cdf_mem_copy(pBKId, pSession->BkidCacheInfo[Index].BKID, + CSR_WAPI_BKID_SIZE); + + fRC = true; + } while (0); + sms_log(pMac, LOGW, + "csr_lookup_bkid called return match = %d pMac->roam.NumBkidCache = %d", + fRC, pSession->NumBkidCache); + + return fRC; +} + +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + bool fWapiMatch = false; + uint8_t cbWapiIe = 0; + uint8_t UnicastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t AuthSuite[CSR_WAPI_OUI_SIZE]; + uint8_t BKId[CSR_WAPI_BKID_SIZE]; + uint8_t *pWapi = NULL; + bool fBKIDFound = false; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + + if (!pIesLocal + && + (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWapiMatch = + csr_get_wapi_information(pMac, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WAPI, UnicastCypher, + MulticastCypher, AuthSuite, NULL, + NULL); + if (!fWapiMatch) + break; + + cdf_mem_set(pWapiIe, sizeof(tCsrWapiIe), 0); + + pWapiIe->IeHeader.ElementID = DOT11F_EID_WAPI; + + pWapiIe->Version = CSR_WAPI_VERSION_SUPPORTED; + + pWapiIe->cAuthenticationSuites = 1; + cdf_mem_copy(&pWapiIe->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + pWapi = (uint8_t *) (&pWapiIe->AuthOui[1]); + + *pWapi = (uint16_t) 1; /* cUnicastCyphers */ + pWapi += 2; + cdf_mem_copy(pWapi, UnicastCypher, sizeof(UnicastCypher)); + pWapi += sizeof(UnicastCypher); + + cdf_mem_copy(pWapi, MulticastCypher, sizeof(MulticastCypher)); + pWapi += sizeof(MulticastCypher); + + /* WAPI capabilities follows the Auth Suite (two octects) */ + /* we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */ + /* & since we already did a memset pWapiIe to 0, skip these fields */ + pWapi += 2; + + fBKIDFound = + csr_lookup_bkid(pMac, sessionId, pSirBssDesc->bssId, + &(BKId[0])); + + if (fBKIDFound) { + /* Do we need to change the endianness here */ + *pWapi = (uint16_t) 1; /* cBKIDs */ + pWapi += 2; + cdf_mem_copy(pWapi, BKId, CSR_WAPI_BKID_SIZE); + } else { + *pWapi = 0; + pWapi += 1; + *pWapi = 0; + pWapi += 1; + } + + /* Add in the IE fields except the IE header */ + /* Add BKID count and BKID (if any) */ + pWapiIe->IeHeader.Length = + (uint8_t) (sizeof(*pWapiIe) - sizeof(pWapiIe->IeHeader)); + + /*2 bytes for BKID Count field */ + pWapiIe->IeHeader.Length += sizeof(uint16_t); + + if (fBKIDFound) { + pWapiIe->IeHeader.Length += CSR_WAPI_BKID_SIZE; + } + /* return the size of the IE header (total) constructed... */ + cbWapiIe = pWapiIe->IeHeader.Length + sizeof(pWapiIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_get_wpa_cyphers() - to get WPA cipher info + * @mac_ctx: pointer to mac context + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wpa_ie: pointer to WPA IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WPA information + * + * Return: bool + */ +bool csr_get_wpa_cyphers(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, tCsrEncryptionList *mc_encryption, + tDot11fIEWPA *wpa_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0; + uint8_t unicast[CSR_WPA_OUI_SIZE]; + uint8_t multicast[CSR_WPA_OUI_SIZE]; + uint8_t authentication[CSR_WPA_OUI_SIZE]; + uint8_t mccipher_arr[1][CSR_WPA_OUI_SIZE]; + uint8_t i; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!wpa_ie->present) + goto end; + c_mcast_cipher = 1; + cdf_mem_copy(mccipher_arr, wpa_ie->multicast_cipher, CSR_WPA_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wpa_ie->unicast_cipher_count); + c_auth_suites = (uint8_t) (wpa_ie->auth_suite_count); + + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + wpa_ie->unicast_ciphers, c_ucast_cipher, + csr_get_oui_index_from_cipher(encr_type), + unicast); + if (!acceptable_cipher) + goto end; + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]), + multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wpa(mac_ctx, wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_wpa_psk(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA_PSK; + } +#ifdef FEATURE_WLAN_ESE + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ese_cckm_auth_wpa(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_CCKM_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_WPA; + } +#endif /* FEATURE_WLAN_ESE */ + + /* + * The 1st auth type in the APs WPA IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the WPA IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + cdf_mem_copy((uint8_t **) mcast_cipher, multicast, + CSR_WPA_OUI_SIZE); + + if (ucast_cipher) + cdf_mem_copy((uint8_t **) ucast_cipher, unicast, + CSR_WPA_OUI_SIZE); + + if (auth_suite) + cdf_mem_copy((uint8_t **) auth_suite, authentication, + CSR_WPA_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + + return acceptable_cipher; +} + +bool csr_is_wpa_encryption_match(tpAniSirGlobal pMac, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthtype, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWpaMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWpaMatch = + csr_get_wpa_cyphers(pMac, pAuthType, enType, pEnMcType, &pIes->WPA, + NULL, NULL, NULL, pNegotiatedAuthtype, + pNegotiatedMCCipher); + + return fWpaMatch; +} + +uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fWpaMatch; + uint8_t cbWpaIe = 0; + uint8_t UnicastCypher[CSR_WPA_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WPA_OUI_SIZE]; + uint8_t AuthSuite[CSR_WPA_OUI_SIZE]; + tCsrWpaAuthIe *pAuthSuite; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + + if (!pIesLocal + && + (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWpaMatch = + csr_get_wpa_cyphers(hHal, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WPA, UnicastCypher, + MulticastCypher, AuthSuite, NULL, NULL); + if (!fWpaMatch) + break; + + pWpaIe->IeHeader.ElementID = SIR_MAC_WPA_EID; + + cdf_mem_copy(pWpaIe->Oui, csr_wpa_oui[01], sizeof(pWpaIe->Oui)); + + pWpaIe->Version = CSR_WPA_VERSION_SUPPORTED; + + cdf_mem_copy(pWpaIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pWpaIe->cUnicastCyphers = 1; + + cdf_mem_copy(&pWpaIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrWpaAuthIe *) (&pWpaIe-> + UnicastOui[pWpaIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* The WPA capabilities follows the Auth Suite (two octects)-- */ + /* this field is optional, and we always "send" zero, so just */ + /* remove it. This is consistent with our assumptions in the */ + /* frames compiler; c.f. bug 15234: */ + /* http://gold.woodsidenet.com/bugzilla/show_bug.cgi?id=15234 */ + + /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */ + /* Add in the size of the Auth suite (count plus a single OUI) */ + pWpaIe->IeHeader.Length = + sizeof(*pWpaIe) - sizeof(pWpaIe->IeHeader) + + sizeof(*pAuthSuite); + + /* return the size of the IE header (total) constructed... */ + cbWpaIe = pWpaIe->IeHeader.Length + sizeof(pWpaIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + + return cbWpaIe; +} + +/* If a WPAIE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */ +uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbWpaIe = 0; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + if (pProfile->nWPAReqIELength && pProfile->pWPAReqIE) { + if (SIR_MAC_WPA_IE_MAX_LENGTH >= + pProfile->nWPAReqIELength) { + cbWpaIe = (uint8_t) pProfile->nWPAReqIELength; + cdf_mem_copy(pWpaIe, pProfile->pWPAReqIE, + cbWpaIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_wpa_ie detect invalid WPA IE length (%d) ", + pProfile->nWPAReqIELength); + } + } else { + cbWpaIe = + csr_construct_wpa_ie(pMac, pProfile, pSirBssDesc, pIes, + pWpaIe); + } + } while (0); + + return cbWpaIe; +} + +/* If a RSNIE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */ +uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbRsnIe = 0; + + do { + if (!csr_is_profile_rsn(pProfile)) + break; +#ifdef FEATURE_WLAN_LFR + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) { + /* If "Legacy Fast Roaming" is enabled ALWAYS rebuild the RSN IE from */ + /* scratch. So it contains the current PMK-IDs */ + cbRsnIe = + csr_construct_rsn_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pRsnIe); + } else +#endif + if (pProfile->nRSNReqIELength && pProfile->pRSNReqIE) { + /* If you have one started away, re-use it. */ + if (SIR_MAC_WPA_IE_MAX_LENGTH >= + pProfile->nRSNReqIELength) { + cbRsnIe = (uint8_t) pProfile->nRSNReqIELength; + cdf_mem_copy(pRsnIe, pProfile->pRSNReqIE, + cbRsnIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_rsn_ie detect invalid RSN IE length (%d) ", + pProfile->nRSNReqIELength); + } + } else { + cbRsnIe = + csr_construct_rsn_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pRsnIe); + } + } while (0); + + return cbRsnIe; +} + +#ifdef FEATURE_WLAN_WAPI +/* If a WAPI IE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWapiIe and guarrantee it can contain a max length WAPI IE */ +uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbWapiIe = 0; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + if (pProfile->nWAPIReqIELength && pProfile->pWAPIReqIE) { + if (DOT11F_IE_WAPI_MAX_LEN >= + pProfile->nWAPIReqIELength) { + cbWapiIe = (uint8_t) pProfile->nWAPIReqIELength; + cdf_mem_copy(pWapiIe, pProfile->pWAPIReqIE, + cbWapiIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_wapi_ie detect invalid WAPI IE length (%d) ", + pProfile->nWAPIReqIELength); + } + } else { + cbWapiIe = + csr_construct_wapi_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pWapiIe); + } + } while (0); + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +tAniEdType csr_translate_encrypt_type_to_ed_type(eCsrEncryptionType EncryptType) +{ + tAniEdType edType; + + switch (EncryptType) { + default: + case eCSR_ENCRYPT_TYPE_NONE: + edType = eSIR_ED_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + edType = eSIR_ED_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + edType = eSIR_ED_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + edType = eSIR_ED_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + edType = eSIR_ED_CCMP; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + edType = eSIR_ED_WPI; + break; +#endif +#ifdef WLAN_FEATURE_11W + /* 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + edType = eSIR_ED_AES_128_CMAC; + break; +#endif + } + + return edType; +} + +/** + * csr_validate_wep() - to validate wep + * @uc_encry_type: unicast encryption type + * @auth_list: Auth list + * @mc_encryption_list: multicast encryption type + * @negotiated_authtype: negotiated auth type + * @negotiated_mc_encry: negotiated mc encry type + * @bss_descr: BSS description + * @ie_ptr: IE pointer + * + * This function just checks whether HDD is giving correct values for + * Multicast cipher and Auth + * + * Return: bool + */ +bool csr_validate_wep(tpAniSirGlobal mac_ctx, eCsrEncryptionType uc_encry_type, + tCsrAuthList *auth_list, + tCsrEncryptionList *mc_encryption_list, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mc_encry, + tSirBssDescription *bss_descr, tDot11fBeaconIEs *ie_ptr) +{ + uint32_t idx; + bool match = false; + eCsrAuthType negotiated_auth = eCSR_AUTH_TYPE_OPEN_SYSTEM; + eCsrEncryptionType negotiated_mccipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + + /* If privacy bit is not set, consider no match */ + if (!csr_is_privacy(bss_descr)) + goto end; + + for (idx = 0; idx < mc_encryption_list->numEntries; idx++) { + switch (mc_encryption_list->encryptionType[idx]) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + /* + * Multicast list may contain WEP40/WEP104. + * Check whether it matches UC. + */ + if (uc_encry_type == + mc_encryption_list->encryptionType[idx]) { + match = true; + negotiated_mccipher = + mc_encryption_list->encryptionType[idx]; + } + break; + default: + match = false; + break; + } + if (match) + break; + } + + if (!match) + goto end; + + for (idx = 0; idx < auth_list->numEntries; idx++) { + switch (auth_list->authType[idx]) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + case eCSR_AUTH_TYPE_SHARED_KEY: + case eCSR_AUTH_TYPE_AUTOSWITCH: + match = true; + negotiated_auth = auth_list->authType[idx]; + break; + default: + match = false; + } + if (match) + break; + } + + if (!match) + goto end; + + if (!ie_ptr) + goto end; + + /* + * In case of WPA / WPA2, check whether it supports WEP as well. + * Prepare the encryption type for WPA/WPA2 functions + */ + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP40; + else if (eCSR_ENCRYPT_TYPE_WEP104 == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP104; + + /* else we can use the encryption type directly */ + if (ie_ptr->WPA.present) { + match = cdf_mem_compare(ie_ptr->WPA.multicast_cipher, + csr_wpa_oui[csr_get_oui_index_from_cipher( + uc_encry_type)], + CSR_WPA_OUI_SIZE); + if (match) + goto end; + } + if (ie_ptr->RSN.present) { + match = cdf_mem_compare(ie_ptr->RSN.gp_cipher_suite, + csr_rsn_oui[csr_get_oui_index_from_cipher( + uc_encry_type)], + CSR_RSN_OUI_SIZE); + } + + +end: + if (match) { + if (negotiated_authtype) + *negotiated_authtype = negotiated_auth; + if (negotiated_mc_encry) + *negotiated_mc_encry = negotiated_mccipher; + } + return match; +} + +/** + * csr_validate_open_none() - Check if the security is matching + * @bss_desc: BSS Descriptor on which the check is done + * @mc_enc_type: Multicast encryption type + * @mc_cipher: Multicast Cipher + * @auth_type: Authentication type + * @neg_auth_type: Negotiated Auth type with the AP + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_open_none(tSirBssDescription *bss_desc, + tCsrEncryptionList *mc_enc_type, eCsrEncryptionType *mc_cipher, + tCsrAuthList *auth_type, eCsrAuthType *neg_auth_type) +{ + bool match; + uint8_t idx; + + /* + * for NO encryption, if the Bss description has the + * Privacy bit turned on, then encryption is required + * so we have to reject this Bss. + */ + if (csr_is_privacy(bss_desc)) + match = false; + else + match = true; + if (match) { + match = false; + /* Check MC cipher and Auth type requested. */ + for (idx = 0; idx < mc_enc_type->numEntries; idx++) { + if (eCSR_ENCRYPT_TYPE_NONE == + mc_enc_type->encryptionType[idx]) { + match = true; + *mc_cipher = mc_enc_type->encryptionType[idx]; + break; + } + } + if (!match) + return match; + + match = false; + /* Check Auth list. It should contain AuthOpen. */ + for (idx = 0; idx < auth_type->numEntries; idx++) { + if ((eCSR_AUTH_TYPE_OPEN_SYSTEM == + auth_type->authType[idx]) || + (eCSR_AUTH_TYPE_AUTOSWITCH == + auth_type->authType[idx])) { + match = true; + *neg_auth_type = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + } + } + if (!match) + return match; + + } + return match; +} + +/** + * csr_validate_any_default() - Check if the security is matching + * @hal: Global HAL handle + * @auth_type: Authentication type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Mangement frame protection mandatory + * @mfp_capable: Device capable of MFP + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @bss_desc: BSS Descriptor + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_any_default(tHalHandle hal, tCsrAuthList *auth_type, + tCsrEncryptionList *mc_enc_type, bool *mfp_enabled, + uint8_t *mfp_required, uint8_t *mfp_capable, + tDot11fBeaconIEs *ies_ptr, eCsrAuthType *neg_auth_type, + tSirBssDescription *bss_desc, eCsrEncryptionType *uc_cipher, + eCsrEncryptionType *mc_cipher) +{ + bool match_any = false; + bool match = true; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + /* It is allowed to match anything. Try the more secured ones first. */ + if (ies_ptr) { + /* Check AES first */ + *uc_cipher = eCSR_ENCRYPT_TYPE_AES; + match_any = csr_is_rsn_match(hal, auth_type, + *uc_cipher, mc_enc_type, mfp_enabled, + mfp_required, mfp_capable, ies_ptr, + neg_auth_type, mc_cipher); + if (!match_any) { + /* Check TKIP */ + *uc_cipher = eCSR_ENCRYPT_TYPE_TKIP; + match_any = csr_is_rsn_match(hal, auth_type, *uc_cipher, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, neg_auth_type, + mc_cipher); + } +#ifdef FEATURE_WLAN_WAPI + if (!match_any) { + /* Check WAPI */ + *uc_cipher = eCSR_ENCRYPT_TYPE_WPI; + match_any = csr_is_wapi_match(hal, auth_type, + *uc_cipher, mc_enc_type, ies_ptr, + neg_auth_type, mc_cipher); + } +#endif + } + if (match_any) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + /* It must be open and no enc */ + if (csr_is_privacy(bss_desc)) { + match = false; + return match; + } + + *neg_auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + *mc_cipher = eCSR_ENCRYPT_TYPE_NONE; + *uc_cipher = eCSR_ENCRYPT_TYPE_NONE; + return match; + +} + +/** + * csr_is_security_match() - Check if the security is matching + * @hal: Global HAL handle + * @auth_type: Authentication type + * @uc_enc_type: Unicast Encryption type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Mangement frame protection mandatory + * @mfp_capable: Device capable of MFP + * @bss_desc: BSS Descriptor + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +bool csr_is_security_match(tHalHandle hal, tCsrAuthList *auth_type, + tCsrEncryptionList *uc_enc_type, + tCsrEncryptionList *mc_enc_type, bool *mfp_enabled, + uint8_t *mfp_required, uint8_t *mfp_capable, + tSirBssDescription *bss_desc, tDot11fBeaconIEs *ies_ptr, + eCsrAuthType *neg_auth_type, + eCsrEncryptionType *neg_uc_cipher, + eCsrEncryptionType *neg_mc_cipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool match = false; + uint8_t i; + eCsrEncryptionType mc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrEncryptionType uc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrAuthType local_neg_auth_type = eCSR_AUTH_TYPE_UNKNOWN; + + for (i = 0; ((i < uc_enc_type->numEntries) && (!match)); i++) { + uc_cipher = uc_enc_type->encryptionType[i]; + /* + * If the Bss description shows the Privacy bit is on, then we + * must have some sort of encryption configured for the profile + * to work. Don't attempt to join networks with Privacy bit + * set when profiles say NONE for encryption type. + */ + switch (uc_cipher) { + case eCSR_ENCRYPT_TYPE_NONE: + match = csr_validate_open_none(bss_desc, mc_enc_type, + &mc_cipher, auth_type, + &local_neg_auth_type); + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* + * !! might want to check for WEP keys set in the + * Profile.... ? !! don't need to have the privacy bit + * in the Bss description. Many AP policies make + * legacy encryption 'optional' so we don't know if we + * can associate or not. The AP will reject if + * encryption is not allowed without the Privacy bit + * turned on. + */ + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + + break; + /* these are all of the WPA encryption types... */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + if (!ies_ptr) { + match = false; + break; + } + /* First check if there is a RSN match */ + match = csr_is_rsn_match(mac_ctx, auth_type, + uc_cipher, mc_enc_type, + mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + /* If not RSN, then check WPA match */ + if (!match) + match = csr_is_wpa_encryption_match( + mac_ctx, auth_type, + uc_cipher, mc_enc_type, + ies_ptr, + &local_neg_auth_type, + &mc_cipher); + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: /* WAPI */ + if (ies_ptr) + match = csr_is_wapi_match(hal, auth_type, + uc_cipher, mc_enc_type, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + else + match = false; + break; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + default: + match = csr_validate_any_default(hal, auth_type, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, bss_desc, + &uc_cipher, &mc_cipher); + break; + } + + } + + if (match) { + if (neg_uc_cipher) + *neg_uc_cipher = uc_cipher; + if (neg_mc_cipher) + *neg_mc_cipher = mc_cipher; + if (neg_auth_type) + *neg_auth_type = local_neg_auth_type; + } + return match; +} + +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired) +{ + bool fMatch = false; + + do { + /* + * Check for the specification of the Broadcast SSID at the + * beginning of the list. If specified, then all SSIDs are + * matches (broadcast SSID means accept all SSIDs). + */ + if (ssid1Len == 0) { + fMatch = true; + break; + } + + /* There are a few special cases. If the Bss description has a Broadcast SSID, */ + /* then our Profile must have a single SSID without Wildcards so we can program */ + /* the SSID. */ + /* SSID could be suppressed in beacons. In that case SSID IE has valid length */ + /* but the SSID value is all NULL characters. That condition is trated same */ + /* as NULL SSID */ + if (csr_is_nullssid(bssSsid, bssSsidLen)) { + if (false == fSsidRequired) { + fMatch = true; + break; + } + } + + if (ssid1Len != bssSsidLen) + break; + if (cdf_mem_compare(bssSsid, ssid1, bssSsidLen)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +/* Null ssid means match */ +bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid, + tCsrSSIDs *pSsidList) +{ + bool fMatch = false; + uint32_t i; + + if (pSsidList && pSsid) { + for (i = 0; i < pSsidList->numOfSSIDs; i++) { + if (csr_is_nullssid + (pSsidList->SSIDList[i].SSID.ssId, + pSsidList->SSIDList[i].SSID.length) + || + ((pSsidList->SSIDList[i].SSID.length == + pSsid->length) + && cdf_mem_compare(pSsid->ssId, + pSsidList->SSIDList[i].SSID. + ssId, pSsid->length))) { + fMatch = true; + break; + } + } + } + + return fMatch; +} + +bool csr_is_bssid_match(tHalHandle hHal, struct cdf_mac_addr *pProfBssid, + struct cdf_mac_addr *BssBssid) +{ + bool fMatch = false; + struct cdf_mac_addr ProfileBssid; + + /* for efficiency of the MAC_ADDRESS functions, move the */ + /* Bssid's into MAC_ADDRESS structs. */ + cdf_mem_copy(&ProfileBssid, pProfBssid, sizeof(struct cdf_mac_addr)); + + do { + + /* Give the profile the benefit of the doubt... accept either all 0 or */ + /* the real broadcast Bssid (all 0xff) as broadcast Bssids (meaning to */ + /* match any Bssids). */ + if (cdf_is_macaddr_zero(&ProfileBssid) || + cdf_is_macaddr_broadcast(&ProfileBssid)) { + fMatch = true; + break; + } + + if (cdf_is_macaddr_equal(BssBssid, &ProfileBssid)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2) +{ + if ((eCSR_BSS_TYPE_ANY != bssType1 && eCSR_BSS_TYPE_ANY != bssType2) + && (bssType1 != bssType2)) + return false; + else + return true; +} + +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType) +{ + return (bool) + (eCSR_BSS_TYPE_START_IBSS == bssType + || eCSR_BSS_TYPE_IBSS == bssType); +} + +bool csr_is_bss_type_wds(eCsrRoamBssType bssType) +{ + return (bool) + (eCSR_BSS_TYPE_WDS_STA == bssType + || eCSR_BSS_TYPE_WDS_AP == bssType); +} + +bool csr_is_bss_type_caps_match(eCsrRoamBssType bssType, + tSirBssDescription *pSirBssDesc) +{ + bool fMatch = true; + + do { + switch (bssType) { + case eCSR_BSS_TYPE_ANY: + break; + + case eCSR_BSS_TYPE_INFRASTRUCTURE: + case eCSR_BSS_TYPE_WDS_STA: + if (!csr_is_infra_bss_desc(pSirBssDesc)) + fMatch = false; + + break; + + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + if (!csr_is_ibss_bss_desc(pSirBssDesc)) + fMatch = false; + + break; + + case eCSR_BSS_TYPE_WDS_AP: /* For WDS AP, no need to match anything */ + default: + fMatch = false; + break; + } + } while (0); + + return fMatch; +} + +static bool csr_is_capabilities_match(tpAniSirGlobal pMac, eCsrRoamBssType bssType, + tSirBssDescription *pSirBssDesc) +{ + return csr_is_bss_type_caps_match(bssType, pSirBssDesc); +} + +static bool csr_is_specific_channel_match(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + uint8_t Channel) +{ + bool fMatch = true; + + do { + /* if the channel is ANY, then always match... */ + if (eCSR_OPERATING_CHANNEL_ANY == Channel) + break; + if (Channel == pSirBssDesc->channelId) + break; + + /* didn't match anything.. so return NO match */ + fMatch = false; + + } while (0); + + return fMatch; +} + +bool csr_is_channel_band_match(tpAniSirGlobal pMac, uint8_t channelId, + tSirBssDescription *pSirBssDesc) +{ + bool fMatch = true; + + do { + /* if the profile says Any channel AND the global settings says ANY channel, then we */ + /* always match... */ + if (eCSR_OPERATING_CHANNEL_ANY == channelId) + break; + + if (eCSR_OPERATING_CHANNEL_ANY != channelId) { + fMatch = + csr_is_specific_channel_match(pMac, pSirBssDesc, + channelId); + } + + } while (0); + + return fMatch; +} + +/** + * csr_is_aggregate_rate_supported() - to check if aggregate rate is supported + * @mac_ctx: pointer to mac context + * @rate: A rate in units of 500kbps + * + * + * The rate encoding is just as in 802.11 Information Elements, except + * that the high bit is \em not interpreted as indicating a Basic Rate, + * and proprietary rates are allowed, too. + * + * Note that if the adapter's dot11Mode is g, we don't restrict the + * rates. According to hwReadEepromParameters, this will happen when: + * ... the card is configured for ALL bands through the property + * page. If this occurs, and the card is not an ABG card ,then this + * code is setting the dot11Mode to assume the mode that the + * hardware can support. For example, if the card is an 11BG card + * and we are configured to support ALL bands, then we change the + * dot11Mode to 11g because ALL in this case is only what the + * hardware can support. + * + * Return: true if the adapter is currently capable of supporting this rate + */ + +static bool csr_is_aggregate_rate_supported(tpAniSirGlobal mac_ctx, + uint16_t rate) +{ + bool supported = false; + uint16_t idx, new_rate; + + /* In case basic rate flag is set */ + new_rate = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + if (eCSR_CFG_DOT11_MODE_11A == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + + } else if (eCSR_CFG_DOT11_MODE_11B == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) { + + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_11Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (eCsrSuppRate_1Mbps == new_rate || + eCsrSuppRate_2Mbps == new_rate || + eCsrSuppRate_5_5Mbps == new_rate || + eCsrSuppRate_11Mbps == new_rate) { + supported = true; + } else { + idx = 0x1; + + switch (new_rate) { + case eCsrSuppRate_6Mbps: + supported = g_phy_rates_suppt[0][idx]; + break; + case eCsrSuppRate_9Mbps: + supported = g_phy_rates_suppt[1][idx]; + break; + case eCsrSuppRate_12Mbps: + supported = g_phy_rates_suppt[2][idx]; + break; + case eCsrSuppRate_18Mbps: + supported = g_phy_rates_suppt[3][idx]; + break; + case eCsrSuppRate_20Mbps: + supported = g_phy_rates_suppt[4][idx]; + break; + case eCsrSuppRate_24Mbps: + supported = g_phy_rates_suppt[5][idx]; + break; + case eCsrSuppRate_36Mbps: + supported = g_phy_rates_suppt[6][idx]; + break; + case eCsrSuppRate_40Mbps: + supported = g_phy_rates_suppt[7][idx]; + break; + case eCsrSuppRate_42Mbps: + supported = g_phy_rates_suppt[8][idx]; + break; + case eCsrSuppRate_48Mbps: + supported = g_phy_rates_suppt[9][idx]; + break; + case eCsrSuppRate_54Mbps: + supported = g_phy_rates_suppt[10][idx]; + break; + case eCsrSuppRate_72Mbps: + supported = g_phy_rates_suppt[11][idx]; + break; + case eCsrSuppRate_80Mbps: + supported = g_phy_rates_suppt[12][idx]; + break; + case eCsrSuppRate_84Mbps: + supported = g_phy_rates_suppt[13][idx]; + break; + case eCsrSuppRate_96Mbps: + supported = g_phy_rates_suppt[14][idx]; + break; + case eCsrSuppRate_108Mbps: + supported = g_phy_rates_suppt[15][idx]; + break; + case eCsrSuppRate_120Mbps: + supported = g_phy_rates_suppt[16][idx]; + break; + case eCsrSuppRate_126Mbps: + supported = g_phy_rates_suppt[17][idx]; + break; + case eCsrSuppRate_144Mbps: + supported = g_phy_rates_suppt[18][idx]; + break; + case eCsrSuppRate_160Mbps: + supported = g_phy_rates_suppt[19][idx]; + break; + case eCsrSuppRate_168Mbps: + supported = g_phy_rates_suppt[20][idx]; + break; + case eCsrSuppRate_192Mbps: + supported = g_phy_rates_suppt[21][idx]; + break; + case eCsrSuppRate_216Mbps: + supported = g_phy_rates_suppt[22][idx]; + break; + case eCsrSuppRate_240Mbps: + supported = g_phy_rates_suppt[23][idx]; + break; + default: + supported = false; + break; + } + } + return supported; +} + +/** + * csr_is_rate_set_match() - to check if rate set is matching + * @mac_ctx: pointer to mac context + * @bss_supported_rates: supported rates of BSS + * @bss_ext_supp_rates: extended rates of bss + * + * This routine is to checke if rate set is matched or no + * + * Return: bool + */ +static bool csr_is_rate_set_match(tpAniSirGlobal mac_ctx, + tDot11fIESuppRates *bss_supported_rates, + tDot11fIEExtSuppRates *bss_ext_supp_rates) +{ + bool match = true; + uint32_t i; + + /* + * Validate that all of the Basic rates advertised in the Bss + * description are supported + */ + if (bss_supported_rates) { + for (i = 0; i < bss_supported_rates->num_rates; i++) { + if (!CSR_IS_BASIC_RATE(bss_supported_rates->rates[i])) + continue; + if (!csr_is_aggregate_rate_supported(mac_ctx, + bss_supported_rates->rates[i])) { + match = false; + break; + } + } + } + if (match && bss_ext_supp_rates) { + for (i = 0; i < bss_ext_supp_rates->num_rates; i++) { + if (!CSR_IS_BASIC_RATE(bss_ext_supp_rates->rates[i])) + continue; + if (!csr_is_aggregate_rate_supported(mac_ctx, + bss_ext_supp_rates->rates[i])) { + match = false; + break; + } + } + } + return match; +} + +/** + * csr_match_bss() - to compare the bss + * @hal: pointer to hal context + * @bss_descr: pointer bss description + * @filter: scan filter + * @neg_auth: negotiated auth + * @neg_uc: negotiated for unicast + * @neg_mc: negotiated for multicast + * @ie_dblptr: double pointer to IE + * + * This routine will be called to match the bss + * If caller want to get the *ie_dblptr allocated by this function, + * pass in *ie_dblptr = NULL + * + * Return: bool + */ +bool csr_match_bss(tHalHandle hal, tSirBssDescription *bss_descr, + tCsrScanResultFilter *filter, eCsrAuthType *neg_auth, + eCsrEncryptionType *neg_uc, eCsrEncryptionType *neg_mc, + tDot11fBeaconIEs **ie_dblptr) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool rc = false, check, blacklist_check; + uint32_t i; + tDot11fBeaconIEs *ie_ptr = NULL; + uint8_t *pb; + struct roam_ext_params *roam_params; + uint8_t *p2p_macaddr = NULL; + + roam_params = &mac_ctx->roam.configParam.roam_params; + if ((NULL == ie_dblptr) || (*ie_dblptr) == NULL) { + /* If no IEs passed in, get our own. */ + if (!CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(mac_ctx, + bss_descr, &ie_ptr))) { + goto end; + } + } else { + /* Save the one pass in for local use */ + ie_ptr = *ie_dblptr; + } + + /* Check if caller wants P2P */ + check = (!filter->p2pResult || ie_ptr->P2PBeaconProbeRes.present); + if (!check) + goto end; + + /* Check for Blacklist BSSID's and avoid connections */ + blacklist_check = false; + for (i = 0; i < roam_params->num_bssid_avoid_list; i++) { + if (cdf_is_macaddr_equal((struct cdf_mac_addr *) + &roam_params->bssid_avoid_list[i], + (struct cdf_mac_addr *)bss_descr->bssId)) { + blacklist_check = true; + break; + } + } + if (blacklist_check) { + sms_log(mac_ctx, LOGE, + FL("Don't Attempt connect to blacklist bssid")); + goto end; + } + + if (ie_ptr->SSID.present) { + for (i = 0; i < filter->SSIDs.numOfSSIDs; i++) { + check = csr_is_ssid_match(mac_ctx, + filter->SSIDs.SSIDList[i].SSID.ssId, + filter->SSIDs.SSIDList[i].SSID.length, + ie_ptr->SSID.ssid, + ie_ptr->SSID.num_ssid, true); + if (check) + break; + } + if (!check) + goto end; + } + check = true; + p2p_macaddr = ie_ptr->P2PBeaconProbeRes.P2PDeviceInfo.P2PDeviceAddress; + for (i = 0; i < filter->BSSIDs.numOfBSSIDs; i++) { + check = csr_is_bssid_match(mac_ctx, + (struct cdf_mac_addr *)&filter->BSSIDs.bssid[i], + (struct cdf_mac_addr *)bss_descr->bssId); + if (check) + break; + + if (filter->p2pResult && ie_ptr->P2PBeaconProbeRes.present) { + check = csr_is_bssid_match(mac_ctx, + (struct cdf_mac_addr *) + &filter->BSSIDs.bssid[i], + (struct cdf_mac_addr *)p2p_macaddr); + if (check) + break; + } + } + if (!check) + goto end; + + check = true; + for (i = 0; i < filter->ChannelInfo.numOfChannels; i++) { + check = csr_is_channel_band_match(mac_ctx, + filter->ChannelInfo.ChannelList[i], bss_descr); + if (check) + break; + } + if (!check) + goto end; +#if defined WLAN_FEATURE_VOWIFI + /* If this is for measurement filtering */ + if (filter->fMeasurement) { + rc = true; + goto end; + } +#endif + if (!csr_is_phy_mode_match(mac_ctx, filter->phyMode, bss_descr, + NULL, NULL, ie_ptr)) + goto end; + +#ifdef WLAN_FEATURE_11W + if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) && + !csr_is_security_match(mac_ctx, &filter->authType, + &filter->EncryptionType, + &filter->mcEncryptionType, + &filter->MFPEnabled, + &filter->MFPRequired, + &filter->MFPCapable, + bss_descr, ie_ptr, neg_auth, + neg_uc, neg_mc)) +#else + if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) && + !csr_is_security_match(mac_ctx, &filter->authType, + &filter->EncryptionType, + &filter->mcEncryptionType, + NULL, NULL, NULL, + bss_descr, ie_ptr, neg_auth, + neg_uc, neg_mc)) +#endif + goto end; + if (!csr_is_capabilities_match(mac_ctx, filter->BSSType, bss_descr)) + goto end; + if (!csr_is_rate_set_match(mac_ctx, &ie_ptr->SuppRates, + &ie_ptr->ExtSuppRates)) + goto end; + if ((eCsrRoamWmmQbssOnly == mac_ctx->roam.configParam.WMMSupportMode) + && !CSR_IS_QOS_BSS(ie_ptr)) + goto end; + /* + * Check country. check even when pb is NULL because we may + * want to make sure + */ + pb = (filter->countryCode[0]) ? (filter->countryCode) : NULL; + check = csr_match_country_code(mac_ctx, pb, ie_ptr); + if (!check) + goto end; + +#ifdef WLAN_FEATURE_VOWIFI_11R + if (filter->MDID.mdiePresent && csr_roam_is11r_assoc(mac_ctx, + mac_ctx->roam.roamSession->sessionId)) { + if (bss_descr->mdiePresent) { + if (filter->MDID.mobilityDomain != + (bss_descr->mdie[1] << 8 | + bss_descr->mdie[0])) + goto end; + } else { + goto end; + } + } +#endif + rc = true; + +end: + if (ie_dblptr) + *ie_dblptr = ie_ptr; + else if (ie_ptr) + cdf_mem_free(ie_ptr); + return rc; +} + +bool csr_match_connected_bss_security(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + tCsrEncryptionList ucEncryptionList, mcEncryptionList; + tCsrAuthList authList; + + ucEncryptionList.numEntries = 1; + ucEncryptionList.encryptionType[0] = pProfile->EncryptionType; + + mcEncryptionList.numEntries = 1; + mcEncryptionList.encryptionType[0] = pProfile->mcEncryptionType; + + authList.numEntries = 1; + authList.authType[0] = pProfile->AuthType; + + return csr_is_security_match(pMac, &authList, &ucEncryptionList, + &mcEncryptionList, NULL, NULL, NULL, + pBssDesc, pIes, NULL, NULL, NULL); + +} + +bool csr_match_bss_to_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRC = false, fCheck; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!pIes) { + if (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pBssDesc, &pIesLocal))) { + break; + } + } + fCheck = true; + if (pIesLocal->SSID.present) { + bool fCheckSsid = false; + if (pProfile->SSID.length) { + fCheckSsid = true; + } + fCheck = + csr_is_ssid_match(pMac, pProfile->SSID.ssId, + pProfile->SSID.length, + pIesLocal->SSID.ssid, + pIesLocal->SSID.num_ssid, + fCheckSsid); + if (!fCheck) + break; + } + if (!csr_match_connected_bss_security + (pMac, pProfile, pBssDesc, pIesLocal)) + break; + if (!csr_is_capabilities_match(pMac, pProfile->BSSType, pBssDesc)) + break; + if (!csr_is_rate_set_match + (pMac, &pIesLocal->SuppRates, &pIesLocal->ExtSuppRates)) + break; + fCheck = + csr_is_channel_band_match(pMac, pProfile->operationChannel, + pBssDesc); + if (!fCheck) + break; + + fRC = true; + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + cdf_mem_free(pIesLocal); + } + + return fRC; +} + +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap) +{ + uint16_t rateBitmap; + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + rateBitmap = *pRateBitmap; + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap |= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap |= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap |= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap |= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap |= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap |= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap |= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap |= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap |= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap |= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap |= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap |= SIR_MAC_RATE_54_BITMAP; + break; + } + *pRateBitmap = rateBitmap; +} + +bool csr_check_rate_bitmap(uint8_t rate, uint16_t rateBitmap) +{ + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap &= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap &= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap &= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap &= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap &= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap &= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap &= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap &= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap &= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap &= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap &= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap &= SIR_MAC_RATE_54_BITMAP; + break; + } + return !!rateBitmap; +} + +bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + return csr_is_aggregate_rate_supported(pMac, n); +} + +uint16_t csr_rates_mac_prop_to_dot11(uint16_t Rate) +{ + uint16_t ConvertedRate = Rate; + + switch (Rate) { + case SIR_MAC_RATE_1: + ConvertedRate = 2; + break; + case SIR_MAC_RATE_2: + ConvertedRate = 4; + break; + case SIR_MAC_RATE_5_5: + ConvertedRate = 11; + break; + case SIR_MAC_RATE_11: + ConvertedRate = 22; + break; + + case SIR_MAC_RATE_6: + ConvertedRate = 12; + break; + case SIR_MAC_RATE_9: + ConvertedRate = 18; + break; + case SIR_MAC_RATE_12: + ConvertedRate = 24; + break; + case SIR_MAC_RATE_18: + ConvertedRate = 36; + break; + case SIR_MAC_RATE_24: + ConvertedRate = 48; + break; + case SIR_MAC_RATE_36: + ConvertedRate = 72; + break; + case SIR_MAC_RATE_42: + ConvertedRate = 84; + break; + case SIR_MAC_RATE_48: + ConvertedRate = 96; + break; + case SIR_MAC_RATE_54: + ConvertedRate = 108; + break; + + case SIR_MAC_RATE_72: + ConvertedRate = 144; + break; + case SIR_MAC_RATE_84: + ConvertedRate = 168; + break; + case SIR_MAC_RATE_96: + ConvertedRate = 192; + break; + case SIR_MAC_RATE_108: + ConvertedRate = 216; + break; + case SIR_MAC_RATE_126: + ConvertedRate = 252; + break; + case SIR_MAC_RATE_144: + ConvertedRate = 288; + break; + case SIR_MAC_RATE_168: + ConvertedRate = 336; + break; + case SIR_MAC_RATE_192: + ConvertedRate = 384; + break; + case SIR_MAC_RATE_216: + ConvertedRate = 432; + break; + case SIR_MAC_RATE_240: + ConvertedRate = 480; + break; + + case 0xff: + ConvertedRate = 0; + break; + } + + return ConvertedRate; +} + +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, + tSirMacPropRateSet *pPropRates) +{ + uint8_t i; + uint16_t nBest; + + nBest = pSuppRates->rate[0] & (~CSR_DOT11_BASIC_RATE_MASK); + + if (pSuppRates->numRates > SIR_MAC_RATESET_EID_MAX) { + pSuppRates->numRates = SIR_MAC_RATESET_EID_MAX; + } + + for (i = 1U; i < pSuppRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pSuppRates-> + rate[i] & (~CSR_DOT11_BASIC_RATE_MASK)); + } + + if (NULL != pExtRates) { + for (i = 0U; i < pExtRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pExtRates-> + rate[i] & + (~CSR_DOT11_BASIC_RATE_MASK)); + } + } + + if (NULL != pPropRates) { + for (i = 0U; i < pPropRates->numPropRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + csr_rates_mac_prop_to_dot11 + (pPropRates->propRate[i])); + } + } + + return nBest; +} + +void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile) +{ + if (pProfile) { + if (pProfile->BSSIDs.bssid) { + cdf_mem_free(pProfile->BSSIDs.bssid); + pProfile->BSSIDs.bssid = NULL; + } + if (pProfile->SSIDs.SSIDList) { + cdf_mem_free(pProfile->SSIDs.SSIDList); + pProfile->SSIDs.SSIDList = NULL; + } + if (pProfile->pWPAReqIE) { + cdf_mem_free(pProfile->pWPAReqIE); + pProfile->pWPAReqIE = NULL; + } + if (pProfile->pRSNReqIE) { + cdf_mem_free(pProfile->pRSNReqIE); + pProfile->pRSNReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (pProfile->pWAPIReqIE) { + cdf_mem_free(pProfile->pWAPIReqIE); + pProfile->pWAPIReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + + if (pProfile->pAddIEScan) { + cdf_mem_free(pProfile->pAddIEScan); + pProfile->pAddIEScan = NULL; + } + + if (pProfile->pAddIEAssoc) { + cdf_mem_free(pProfile->pAddIEAssoc); + pProfile->pAddIEAssoc = NULL; + } + if (pProfile->ChannelInfo.ChannelList) { + cdf_mem_free(pProfile->ChannelInfo.ChannelList); + pProfile->ChannelInfo.ChannelList = NULL; + } + cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0); + } +} + +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter) +{ + if (pScanFilter->BSSIDs.bssid) { + cdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + } + if (pScanFilter->ChannelInfo.ChannelList) { + cdf_mem_free(pScanFilter->ChannelInfo.ChannelList); + pScanFilter->ChannelInfo.ChannelList = NULL; + } + if (pScanFilter->SSIDs.SSIDList) { + cdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + } +} + +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pCurRoamProfile) { + csr_release_profile(pMac, pSession->pCurRoamProfile); + cdf_mem_free(pSession->pCurRoamProfile); + pSession->pCurRoamProfile = NULL; + } +} + +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pConnectBssDesc) { + cdf_mem_free(pSession->pConnectBssDesc); + pSession->pConnectBssDesc = NULL; + } +} + +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeDisassocRsp; + uint32_t ret; + + pBuffer += (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(tSirMacAddr)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + cdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeRsp; + uint32_t ret; + + pBuffer += + (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(uint16_t)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + cdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId) +{ + tSirScanType scanType = eSIR_PASSIVE_SCAN; + CHANNEL_STATE channelEnabledType; + + channelEnabledType = cds_get_channel_state(chnId); + if (CHANNEL_STATE_ENABLE == channelEnabledType) { + scanType = eSIR_ACTIVE_SCAN; + } + return scanType; +} + +uint8_t csr_to_upper(uint8_t ch) +{ + uint8_t chOut; + + if (ch >= 'a' && ch <= 'z') { + chOut = ch - 'a' + 'A'; + } else { + chOut = ch; + } + return chOut; +} + +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype) +{ + tSirBssType ret; + + switch (csrtype) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + ret = eSIR_INFRASTRUCTURE_MODE; + break; + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + ret = eSIR_IBSS_MODE; + break; + case eCSR_BSS_TYPE_WDS_AP: + ret = eSIR_BTAMP_AP_MODE; + break; + case eCSR_BSS_TYPE_WDS_STA: + ret = eSIR_BTAMP_STA_MODE; + break; + case eCSR_BSS_TYPE_INFRA_AP: + ret = eSIR_INFRA_AP_MODE; + break; + case eCSR_BSS_TYPE_ANY: + default: + ret = eSIR_AUTO_MODE; + break; + } + + return ret; +} + +/* This function use the parameters to decide the CFG value. */ +/* CSR never sets WNI_CFG_DOT11_MODE_ALL to the CFG */ +/* So PE should not see WNI_CFG_DOT11_MODE_ALL when it gets the CFG value */ +eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary) +{ + uint32_t cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + + switch (phyMode) { + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + if (pProfile && (CSR_IS_INFRA_AP(pProfile)) + && (phyMode == eCSR_DOT11_MODE_11g_ONLY)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11n_ONLY: + if (pProfile && CSR_IS_INFRA_AP(pProfile)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_abg: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + break; + case eCSR_DOT11_MODE_AUTO: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + +#ifdef WLAN_FEATURE_11AC + case eCSR_DOT11_MODE_11ac: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + } + break; + case eCSR_DOT11_MODE_11ac_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + } else { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + } + break; +#endif + default: + /* No need to assign anything here */ + break; + } + + return cfgDot11Mode; +} + +CDF_STATUS csr_get_regulatory_domain_for_country + (tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, v_CountryInfoSource_t source) { + CDF_STATUS status = CDF_STATUS_E_INVAL; + CDF_STATUS cdf_status; + country_code_t countryCode; + v_REGDOMAIN_t domainId; + + if (pCountry) { + countryCode[0] = pCountry[0]; + countryCode[1] = pCountry[1]; + cdf_status = cds_get_reg_domain_from_country_code(&domainId, + countryCode, + source); + + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + if (pDomainId) { + *pDomainId = domainId; + } + status = CDF_STATUS_SUCCESS; + } else { + sms_log(pMac, LOGW, + FL + (" Couldn't find domain for country code %c%c"), + pCountry[0], pCountry[1]); + status = CDF_STATUS_E_INVAL; + } + } + + return status; +} + +/* To check whether a country code matches the one in the IE */ +/* Only check the first two characters, ignoring in/outdoor */ +/* pCountry -- caller allocated buffer contain the country code that is checking against */ +/* the one in pIes. It can be NULL. */ +/* caller must provide pIes, it cannot be NULL */ +/* This function always return true if 11d support is not turned on. */ +bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry, + tDot11fBeaconIEs *pIes) +{ + bool fRet = true; + + do { + if (!csr_is11d_supported(pMac)) { + break; + } + if (!pIes) { + sms_log(pMac, LOGE, FL(" No IEs")); + break; + } + + if (pCountry) { + uint32_t i; + + if (!pIes->Country.present) { + fRet = false; + break; + } + /* Convert the CountryCode characters to upper */ + for (i = 0; i < WNI_CFG_COUNTRY_CODE_LEN - 1; i++) { + pCountry[i] = csr_to_upper(pCountry[i]); + } + if (!cdf_mem_compare(pIes->Country.country, pCountry, + WNI_CFG_COUNTRY_CODE_LEN - 1)) { + fRet = false; + break; + } + } + } while (0); + + return fRet; +} + +CDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + + if (!pModifyProfileFields) { + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_copy(pModifyProfileFields, + &pMac->roam.roamSession[sessionId].connectedProfile. + modifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + cdf_mem_copy(&pSession->connectedProfile.modifyProfileFields, + pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return CDF_STATUS_SUCCESS; +} + + +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId) +{ + bool fRet = true; + tCsrRoamSession *pSession; + + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* + * This condition is not working for infra state. When infra is in + * not-connected state the pSession->pCurRoamProfile is NULL, this + * function returns true, that is incorrect. + * Since SAP requires to set key without any BSS started, it needs + * this condition to be met. In other words, this function is useless. + * The current work-around is to process setcontext_rsp no matter + * what the state is. + */ + sms_log(pMac, LOG2, + FL(" is not what it intends to. Must be revisit or removed")); + if ((NULL == pSession) + || (csr_is_conn_state_disconnected(pMac, sessionId) + && (pSession->pCurRoamProfile != NULL) + && (!(CSR_IS_INFRA_AP(pSession->pCurRoamProfile)))) + ) { + fRet = false; + } + + return fRet; +} + +/* no need to acquire lock for this basic function */ +uint16_t sme_chn_to_freq(uint8_t chanNum) +{ + int i; + + for (i = 0; i < NUM_RF_CHANNELS; i++) { + if (rf_channels[i].channelNum == chanNum) { + return rf_channels[i].targetFreq; + } + } + + return 0; +} + +/* Disconnect all active sessions by sending disassoc. This is mainly used to disconnect the remaining session when we + * transition from concurrent sessions to a single session. The use case is Infra STA and wifi direct multiple sessions are up and + * P2P session is removed. The Infra STA session remains and should resume BMPS if BMPS is enabled by default. However, there + * are some issues seen with BMPS resume during this transition and this is a workaround which will allow the Infra STA session to + * disconnect and auto connect back and enter BMPS this giving the same effect as resuming BMPS + */ + +/* Remove this code once SLM_Sessionization is supported */ +/* BMPS_WORKAROUND_NOT_NEEDED */ +void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac) +{ + uint8_t i; + + /* Disconnect all the active sessions */ + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + csr_roam_disconnect_internal(pMac, i, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + } +} + +#ifdef FEATURE_WLAN_LFR +bool csr_is_channel_present_in_list(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList || (numChannels == 0)) { + return false; + } + /* Look for the channel in the list */ + for (i = 0; (i < numChannels) && + (i < WNI_CFG_VALID_CHANNEL_LIST_LEN); i++) { + if (pChannelList[i] == channel) + return true; + } + + return false; +} + +CDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList) + return CDF_STATUS_E_NULL_VALUE; + + /* Make room for the addition. (Start moving from the back.) */ + for (i = numChannels; i > 0; i--) { + pChannelList[i] = pChannelList[i - 1]; + } + + /* Now add the NEW channel...at the front */ + pChannelList[0] = channel; + + return CDF_STATUS_SUCCESS; +} +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * csr_diag_event_report() - send PE diag event + * @pmac: pointer to global MAC context. + * @event_typev: sub event type for DIAG event. + * @status: status of the event + * @reasoncode: reasoncode for the given status + * + * This function is called to send diag event + * + * Return: NA + */ +void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type, + uint16_t status, uint16_t reasoncode) +{ + WLAN_HOST_DIAG_EVENT_DEF(diag_event, host_event_wlan_pe_payload_type); + + cdf_mem_zero(&diag_event, sizeof(host_event_wlan_pe_payload_type)); + + /* diag_event.bssid is already all zeroes */ + diag_event.sme_state = sme_get_lim_sme_state(pmac); + diag_event.mlm_state = sme_get_lim_mlm_state(pmac); + diag_event.event_type = event_type; + diag_event.status = status; + diag_event.reason_code = reasoncode; + + WLAN_HOST_DIAG_EVENT_REPORT(&diag_event, EVENT_WLAN_PE); + return; +} +#endif diff --git a/core/sme/src/nan/nan_api.c b/core/sme/src/nan/nan_api.c new file mode 100644 index 0000000000..f2008ef03b --- /dev/null +++ b/core/sme/src/nan/nan_api.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_api.h" +#include "sms_debug.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "nan_api.h" +#include "lim_api.h" +#include "cfg_api.h" + +/****************************************************************************** + * Function: sme_nan_register_callback + * + * Description: + * This function gets called when HDD wants register nan rsp callback with + * sme layer. + * + * Args: + * hHal and callback which needs to be registered. + * + * Returns: + * void + *****************************************************************************/ +void sme_nan_register_callback(tHalHandle hHal, NanCallback callback) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL == hHal) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pMac = PMAC_STRUCT(hHal); + pMac->sme.nanCallback = callback; +} + +/****************************************************************************** + * Function: sme_nan_request + * + * Description: + * This function gets called when HDD receives NAN vendor command + * from userspace + * + * Args: + * Nan Request structure ptr + * + * Returns: + * CDF_STATUS + *****************************************************************************/ +CDF_STATUS sme_nan_request(tpNanRequestReq input) +{ + cds_msg_t msg; + tpNanRequest data; + size_t data_len; + + data_len = sizeof(tNanRequest) + input->request_data_len; + data = cdf_mem_malloc(data_len); + + if (data == NULL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(data, data_len); + data->request_data_len = input->request_data_len; + if (input->request_data_len) { + cdf_mem_copy(data->request_data, + input->request_data, input->request_data_len); + } + + msg.type = WMA_NAN_REQUEST; + msg.reserved = 0; + msg.bodyptr = data; + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Not able to post WMA_NAN_REQUEST message to WMA")); + cdf_mem_free(data); + return CDF_STATUS_SUCCESS; + } + + return CDF_STATUS_SUCCESS; +} + +/****************************************************************************** +* Function: sme_nan_event +* +* Description: +* This callback function will be called when SME received eWNI_SME_NAN_EVENT +* event from WMA +* +* Args: +* hHal - HAL handle for device +* pMsg - Message body passed from WMA; includes NAN header +* +* Returns: +* CDF_STATUS +******************************************************************************/ +CDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + if (NULL == pMsg) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("msg ptr is NULL")); + status = CDF_STATUS_E_FAILURE; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + FL("SME: Received sme_nan_event")); + if (pMac->sme.nanCallback) { + pMac->sme.nanCallback(pMac->hHdd, + (tSirNanEvent *) pMsg); + } + } + + return status; +} diff --git a/core/sme/src/oem_data/oem_data_api.c b/core/sme/src/oem_data/oem_data_api.c new file mode 100644 index 0000000000..aeb0a0db45 --- /dev/null +++ b/core/sme/src/oem_data/oem_data_api.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file oem_data_api.c + + Implementation for the OEM DATA REQ/RSP interfaces. + ========================================================================== */ +#include "ani_global.h" +#include "oem_data_api.h" +#include "cds_mq.h" +#include "sme_inside.h" +#include "sms_debug.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" + +/* --------------------------------------------------------------------------- + \fn oem_data_oem_data_req_open + \brief This function must be called before any API call to (OEM DATA REQ/RSP module) + \return CDF_STATUS + -------------------------------------------------------------------------------*/ + +CDF_STATUS oem_data_oem_data_req_open(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + /* initialize all the variables to null */ + cdf_mem_set(&(pMac->oemData), sizeof(tOemDataStruct), 0); + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "oem_data_oem_data_req_open: Cannot allocate memory for the timer function"); + break; + } + } while (0); + + return status; +} + +/* --------------------------------------------------------------------------- + \fn oem_data_oem_data_req_close + \brief This function must be called before closing the csr module + \return CDF_STATUS + -------------------------------------------------------------------------------*/ + +CDF_STATUS oem_data_oem_data_req_close(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "oem_data_oem_data_req_close: Failed in oem_data_oem_data_req_close at StopTimers"); + break; + } + + /* initialize all the variables to null */ + cdf_mem_set(&(pMac->oemData), sizeof(tOemDataStruct), 0); + } while (0); + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + \fn oem_data_release_oem_data_req_command + \brief This function removes the oemDataCommand from the active list and + and frees up any memory occupied by this + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +void oem_data_release_oem_data_req_command(tpAniSirGlobal pMac, + tSmeCmd *pOemDataCmd, + eOemDataReqStatus oemDataReqStatus) +{ + + /* First take this command out of the active list */ + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, &pOemDataCmd->Link, LL_ACCESS_LOCK)) { + cdf_mem_set(&(pOemDataCmd->u.oemDataCmd), sizeof(tOemDataCmd), + 0); + + /* Now put this command back on the avilable command list */ + sme_release_command(pMac, pOemDataCmd); + } else { + sms_log(pMac, LOGE, + "OEM_DATA: **************** oem_data_release_oem_data_req_command cannot release the command"); + } +} + +/* --------------------------------------------------------------------------- + \fn oem_data_oem_data_req + \brief Request an OEM DATA RSP + \param sessionId - Id of session to be used + \param pOemDataReqID - pointer to an object to get back the request ID + \param callback - a callback function that is called upon finish + \param pContext - a pointer passed in for the callback + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS oem_data_oem_data_req(tHalHandle hHal, + uint8_t sessionId, + tOemDataReqConfig *oemDataReqConfig, + uint32_t *pOemDataReqID, + oem_data_oem_data_reqCompleteCallback callback, + void *pContext) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *pOemDataCmd = NULL; + + do { + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = CDF_STATUS_E_FAILURE; + break; + } + + pMac->oemData.oemDataReqConfig.sessionId = sessionId; + pMac->oemData.callback = callback; + pMac->oemData.pContext = pContext; + pMac->oemData.oemDataReqID = *(pOemDataReqID); + + cdf_mem_copy((void *)(pMac->oemData.oemDataReqConfig. + oemDataReq), + (void *)(oemDataReqConfig->oemDataReq), + OEM_DATA_REQ_SIZE); + + pMac->oemData.oemDataReqActive = false; + + pOemDataCmd = sme_get_command_buffer(pMac); + + /* fill up the command before posting it. */ + if (pOemDataCmd) { + pOemDataCmd->command = eSmeCommandOemDataReq; + pOemDataCmd->u.oemDataCmd.callback = callback; + pOemDataCmd->u.oemDataCmd.pContext = pContext; + pOemDataCmd->u.oemDataCmd.oemDataReqID = + pMac->oemData.oemDataReqID; + + /* set the oem data request */ + pOemDataCmd->u.oemDataCmd.oemDataReq.sessionId = + pMac->oemData.oemDataReqConfig.sessionId; + cdf_mem_copy((void *)(pOemDataCmd->u.oemDataCmd. + oemDataReq.oemDataReq), + (void *)(pMac->oemData.oemDataReqConfig. + oemDataReq), OEM_DATA_REQ_SIZE); + } else { + status = CDF_STATUS_E_FAILURE; + break; + } + + /* now queue this command in the sme command queue */ + /* Here since this is not interacting with the csr just push the command */ + /* into the sme queue. Also push this command with the normal priority */ + sme_push_command(pMac, pOemDataCmd, false); + + } while (0); + + if (!CDF_IS_STATUS_SUCCESS(status) && pOemDataCmd) { + oem_data_release_oem_data_req_command(pMac, pOemDataCmd, + eOEM_DATA_REQ_FAILURE); + pMac->oemData.oemDataReqActive = false; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn oem_data_send_mb_oem_data_req + \brief Request an OEM DATA REQ to be passed down to PE + \param pMac: + \param pOemDataReq: Pointer to the oem data request + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS oem_data_send_mb_oem_data_req(tpAniSirGlobal pMac, + tOemDataReq *pOemDataReq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirOemDataReq *pMsg; + uint16_t msgLen; + tCsrRoamSession *pSession = + CSR_GET_SESSION(pMac, pOemDataReq->sessionId); + + sms_log(pMac, LOGW, "OEM_DATA: entering Function %s", __func__); + + msgLen = (uint16_t) (sizeof(tSirOemDataReq)); + + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) { + sms_log(pMac, LOGP, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set(pMsg, msgLen, 0); + pMsg->messageType = eWNI_SME_OEM_DATA_REQ; + pMsg->messageLen = msgLen; + cdf_mem_copy(pMsg->selfMacAddr, pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + cdf_mem_copy(pMsg->oemDataReq, pOemDataReq->oemDataReq, + OEM_DATA_REQ_SIZE); + sms_log(pMac, LOGW, "OEM_DATA: sending message to pe%s", __func__); + status = cds_send_mb_message_to_mac(pMsg); + + sms_log(pMac, LOGW, "OEM_DATA: exiting Function %s", __func__); + + return status; +} + +/** + * oem_data_process_oem_data_req_command() - process oem data request command + * @pMac: Mac context + * @pOemDataReqCmd: pointer to oem data request command + * + * This function is called by the sme_process_command when the case hits + * eSmeCommandOemDataReq. + * + * Return: CDF_STATUS + */ +CDF_STATUS oem_data_process_oem_data_req_command(tpAniSirGlobal pMac, + tSmeCmd *pOemDataReqCmd) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* check if the system is in proper mode of operation for + * oem data req/rsp to be functional. Currently, concurrency is not + * supported and the driver must be operational only as + * STA for oem data req/rsp to be functional. We return an invalid + * mode flag if it is operational as any one of the following + * in any of the active sessions + * 1. AP Mode + * 2. IBSS Mode + * 3. BTAMP Mode + */ + + if (CDF_STATUS_SUCCESS == oem_data_is_oem_data_req_allowed(pMac)) { + sms_log(pMac, LOG1, + FL("OEM_DATA REQ allowed in the current mode")); + pMac->oemData.oemDataReqActive = true; + status = oem_data_send_mb_oem_data_req(pMac, + &(pOemDataReqCmd->u.oemDataCmd.oemDataReq)); + } else { + sms_log(pMac, LOG1, + FL("OEM_DATA REQ not allowed in the current mode")); + status = CDF_STATUS_E_FAILURE; + } + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("OEM_DATA Failure, Release command")); + oem_data_release_oem_data_req_command(pMac, pOemDataReqCmd, + eOEM_DATA_REQ_INVALID_MODE); + pMac->oemData.oemDataReqActive = false; + } + + return status; +} + +/** + * sme_handle_oem_data_rsp() - processes the oem data response + * @hHal: Handle returned by mac_open. + * @pMsg: Pointer to the pSirOemDataRsp + * + * This function processes the oem data response obtained from the PE + * + * Return: CDF_STATUS. + */ +CDF_STATUS sme_handle_oem_data_rsp(tHalHandle hHal, uint8_t *pMsg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tSirOemDataRsp *pOemDataRsp = NULL; + uint32_t *msgSubType; + + pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG1, "%s: OEM_DATA Entering", __func__); + + do { + if (pMsg == NULL) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + status = CDF_STATUS_E_FAILURE; + break; + } + + /* In this case, there can be multiple OEM Data Responses for one + * OEM Data request, SME does not peek into data response so SME + * can not know which response is the last one. So SME clears active + * request command on receiving first response and thereafter SME + * passes each sunsequent response to upper user layer. + */ + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandOemDataReq == pCommand->command) { + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) { + cdf_mem_set(&(pCommand->u.oemDataCmd), + sizeof(tOemDataCmd), 0); + sme_release_command(pMac, pCommand); + } + } + } + + pOemDataRsp = (tSirOemDataRsp *) pMsg; + + /* check if message is to be forwarded to oem application or not */ + msgSubType = (uint32_t *) (&pOemDataRsp->oemDataRsp[0]); + if (*msgSubType != OEM_MESSAGE_SUBTYPE_INTERNAL) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: calling send_oem_data_rsp_msg, msgSubType(0x%x)", + __func__, *msgSubType); + if (pMac->oemData.oem_data_rsp_callback != NULL) { + pMac->oemData.oem_data_rsp_callback( + sizeof(tOemDataRsp), + &pOemDataRsp->oemDataRsp[0]); + } + } else + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: received internal oem data resp, msgSubType (0x%x)", + __func__, *msgSubType); + } while (0); + + return status; +} + +/* --------------------------------------------------------------------------- + \fn oem_data_is_oem_data_req_allowed + \brief This function checks if OEM DATA REQs can be performed in the + current driver state + \return CDF_STATUS + -------------------------------------------------------------------------------*/ +CDF_STATUS oem_data_is_oem_data_req_allowed(tHalHandle hHal) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint32_t sessionId; + + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + /* co-exist with IBSS or BT-AMP mode is not supported */ + if (csr_is_conn_state_ibss(pMac, sessionId) + || csr_is_btamp(pMac, sessionId)) { + /* co-exist with IBSS or BT-AMP mode is not supported */ + sms_log(pMac, LOGW, + "OEM DATA REQ is not allowed due to IBSS|BTAMP exist in session %d", + sessionId); + status = CDF_STATUS_CSR_WRONG_STATE; + break; + } + } + } + + sms_log(pMac, LOG1, "Exiting oem_data_is_oem_data_req_allowed with status %d", + status); + + return (status); +} + +#endif /*FEATURE_OEM_DATA_SUPPORT */ diff --git a/core/sme/src/p2p/p2p_api.c b/core/sme/src/p2p/p2p_api.c new file mode 100644 index 0000000000..ec8b742263 --- /dev/null +++ b/core/sme/src/p2p/p2p_api.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_api.h" +#include "sms_debug.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "p2p_api.h" +#include "lim_api.h" +#include "cfg_api.h" +#include "wma.h" + +/*------------------------------------------------------------------ + * + * handle SME remain on channel request. + * + *------------------------------------------------------------------*/ + +CDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac, + tSmeCmd *p2pRemainonChn) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSirRemainOnChnReq *pMsg; + uint32_t len; + tCsrRoamSession *pSession = + CSR_GET_SESSION(pMac, p2pRemainonChn->sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + p2pRemainonChn->sessionId); + goto error; + } + + if (!pSession->sessionActive) { + sms_log(pMac, LOGE, + FL(" session %d is invalid or listen is disabled "), + p2pRemainonChn->sessionId); + goto error; + } + len = sizeof(tSirRemainOnChnReq) + pMac->p2pContext.probeRspIeLength; + + if (len > 0xFFFF) { + /*In coming len for Msg is more then 16bit value */ + sms_log(pMac, LOGE, FL(" Message length is very large, %d"), + len); + goto error; + } + + pMsg = cdf_mem_malloc(len); + if (NULL == pMsg) + goto error; + else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, "%s call", + __func__); + cdf_mem_set(pMsg, sizeof(tSirRemainOnChnReq), 0); + pMsg->messageType = eWNI_SME_REMAIN_ON_CHANNEL_REQ; + pMsg->length = (uint16_t) len; + cdf_mem_copy(pMsg->selfMacAddr, pSession->selfMacAddr.bytes, + sizeof(tSirMacAddr)); + pMsg->chnNum = p2pRemainonChn->u.remainChlCmd.chn; + pMsg->phyMode = p2pRemainonChn->u.remainChlCmd.phyMode; + pMsg->duration = p2pRemainonChn->u.remainChlCmd.duration; + pMsg->sessionId = p2pRemainonChn->sessionId; + pMsg->isProbeRequestAllowed = + p2pRemainonChn->u.remainChlCmd.isP2PProbeReqAllowed; + pMsg->scan_id = p2pRemainonChn->u.remainChlCmd.scan_id; + if (pMac->p2pContext.probeRspIeLength) + cdf_mem_copy((void *)pMsg->probeRspIe, + (void *)pMac->p2pContext.probeRspIe, + pMac->p2pContext.probeRspIeLength); + status = cds_send_mb_message_to_mac(pMsg); + } +error: + if (CDF_STATUS_E_FAILURE == status) + csr_release_roc_req_cmd(pMac); + return status; +} + +/*------------------------------------------------------------------ + * + * handle LIM remain on channel rsp: Success/failure. + * + *------------------------------------------------------------------*/ + +CDF_STATUS sme_remain_on_chn_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + bool fFound; + remainOnChanCallback callback = NULL; + struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg; + + csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, FL("No cmd found in active list.")); + return status; + } + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel != pCommand->command) + return status; + + callback = pCommand->u.remainChlCmd.callback; + if (callback) + callback(pMac, pCommand->u.remainChlCmd.callbackCtx, + rsp->status, rsp->scan_id); + + fFound = csr_ll_remove_entry(&pMac->sme.smeScanCmdActiveList, pEntry, + LL_ACCESS_LOCK); + if (fFound) { + /* Now put this command back on the avilable command list */ + sme_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + return status; +} + +/*------------------------------------------------------------------ + * + * Handle the Mgmt frm ind from LIM and forward to HDD. + * + *------------------------------------------------------------------*/ + +CDF_STATUS sme_mgmt_frm_ind(tHalHandle hHal, tpSirSmeMgmtFrameInd pSmeMgmtFrm) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo pRoamInfo = { 0 }; + uint8_t i = 0; + uint32_t SessionId = pSmeMgmtFrm->sessionId; + + pRoamInfo.nFrameLength = + pSmeMgmtFrm->mesgLen - sizeof(tSirSmeMgmtFrameInd); + pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf; + pRoamInfo.frameType = pSmeMgmtFrm->frameType; + pRoamInfo.rxChan = pSmeMgmtFrm->rxChan; + pRoamInfo.rxRssi = pSmeMgmtFrm->rxRssi; + if (CSR_IS_SESSION_ANY(SessionId)) { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + SessionId = i; + break; + } + } + } + + if (i == CSR_ROAM_SESSION_MAX) { + sms_log(pMac, LOGE, FL("No valid sessions found.")); + return CDF_STATUS_E_FAILURE; + } + /* forward the mgmt frame to HDD */ + csr_roam_call_callback(pMac, SessionId, &pRoamInfo, 0, + eCSR_ROAM_INDICATE_MGMT_FRAME, 0); + + return status; +} + +/*------------------------------------------------------------------ + * + * Handle the remain on channel ready indication from PE + * + *------------------------------------------------------------------*/ + +CDF_STATUS sme_remain_on_chn_ready(tHalHandle hHal, uint8_t *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tCsrRoamInfo RoamInfo; + struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg; + + csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, FL("No cmd found in active list.")); + return status; + } + sms_log(pMac, LOG1, + FL("Ready Ind %d %d"), rsp->session_id, rsp->scan_id); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel == pCommand->command) { + RoamInfo.roc_scan_id = rsp->scan_id; + /* forward the indication to HDD */ + RoamInfo.pRemainCtx = pCommand->u.remainChlCmd.callbackCtx; + csr_roam_call_callback(pMac, rsp->session_id, + &RoamInfo, 0, + eCSR_ROAM_REMAIN_CHAN_READY, 0); + } + + return status; +} + +CDF_STATUS sme_send_action_cnf(tHalHandle hHal, uint8_t *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamInfo RoamInfo; + tSirSmeRsp *pSmeRsp = (tSirSmeRsp *) pMsg; + + /* forward the indication to HDD */ + /* RoamInfo can be passed as NULL....todo */ + csr_roam_call_callback(pMac, pSmeRsp->sessionId, &RoamInfo, 0, + eCSR_ROAM_SEND_ACTION_CNF, + (pSmeRsp->statusCode == eSIR_SME_SUCCESS) ? 0 : + eCSR_ROAM_RESULT_SEND_ACTION_FAIL); + return status; +} + +CDF_STATUS sme_p2p_open(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* If static structure is too big, Need to change this function to allocate memory dynamically */ + cdf_mem_zero(&pMac->p2pContext, sizeof(tp2pContext)); + + if (!CDF_IS_STATUS_SUCCESS(status)) { + sme_p2p_close(hHal); + } + + return status; +} + +CDF_STATUS p2p_stop(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->p2pContext.probeRspIe) { + cdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIe = NULL; + } + + pMac->p2pContext.probeRspIeLength = 0; + + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_p2p_close(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->p2pContext.probeRspIe) { + cdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIe = NULL; + } + + pMac->p2pContext.probeRspIeLength = 0; + + return CDF_STATUS_SUCCESS; +} + +tSirRFBand get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return SIR_BAND_5_GHZ; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return SIR_BAND_2_4_GHZ; + + return SIR_BAND_UNKNOWN; +} + +/* --------------------------------------------------------------------------- + + \fn p2p_remain_on_channel + \brief API to post the remain on channel command. + \param hHal - The handle returned by mac_open. + \param sessinId - HDD session ID. + \param channel - Channel to remain on channel. + \param duration - Duration for which we should remain on channel + \param callback - callback function. + \param pContext - argument to the callback function + \return CDF_STATUS + + -------------------------------------------------------------------------------*/ +CDF_STATUS p2p_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t scan_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *pRemainChlCmd = NULL; + uint32_t phyMode; + + pRemainChlCmd = sme_get_command_buffer(pMac); + if (pRemainChlCmd == NULL) + return CDF_STATUS_E_FAILURE; + + if (SIR_BAND_5_GHZ == get_rf_band(channel)) { + phyMode = WNI_CFG_PHY_MODE_11A; + } else { + phyMode = WNI_CFG_PHY_MODE_11G; + } + + cfg_set_int(pMac, WNI_CFG_PHY_MODE, phyMode); + + do { + /* call set in context */ + pRemainChlCmd->command = eSmeCommandRemainOnChannel; + pRemainChlCmd->sessionId = sessionId; + pRemainChlCmd->u.remainChlCmd.chn = channel; + pRemainChlCmd->u.remainChlCmd.duration = duration; + pRemainChlCmd->u.remainChlCmd.isP2PProbeReqAllowed = + isP2PProbeReqAllowed; + pRemainChlCmd->u.remainChlCmd.callback = callback; + pRemainChlCmd->u.remainChlCmd.callbackCtx = pContext; + pRemainChlCmd->u.remainChlCmd.scan_id = scan_id; + + /* Put it at the head of the Q if we just finish finding the peer and ready to send a frame */ + status = csr_queue_sme_command(pMac, pRemainChlCmd, false); + } while (0); + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return (status); +} + +CDF_STATUS p2p_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, + bool noack, uint16_t channel_freq) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirMbMsgP2p *pMsg; + uint16_t msgLen; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + " %s sends action frame", __func__); + msgLen = (uint16_t) ((sizeof(tSirMbMsgP2p)) + len); + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set((void *)pMsg, msgLen, 0); + pMsg->type = eWNI_SME_SEND_ACTION_FRAME_IND; + pMsg->msgLen = msgLen; + pMsg->sessionId = sessionId; + pMsg->noack = noack; + pMsg->channel_freq = channel_freq; + pMsg->wait = (uint16_t) wait; + cdf_mem_copy(pMsg->data, pBuf, len); + status = cds_send_mb_message_to_mac(pMsg); + } + return (status); +} + +CDF_STATUS p2p_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tSirMbMsgP2p *pMsg; + uint16_t msgLen; + + /* Need to check session ID to support concurrency */ + + msgLen = (uint16_t) (sizeof(tSirMbMsgP2p)); + pMsg = cdf_mem_malloc(msgLen); + if (NULL == pMsg) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set((void *)pMsg, msgLen, 0); + pMsg->type = eWNI_SME_ABORT_REMAIN_ON_CHAN_IND; + pMsg->msgLen = msgLen; + pMsg->sessionId = sessionId; + pMsg->scan_id = scan_id; + status = cds_send_mb_message_to_mac(pMsg); + } + + return (status); +} + +CDF_STATUS p2p_set_ps(tHalHandle hHal, tP2pPsConfig *pNoA) +{ + tpP2pPsConfig pNoAParam; + tSirMsgQ msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pNoAParam = cdf_mem_malloc(sizeof(tP2pPsConfig)); + if (NULL == pNoAParam) + status = CDF_STATUS_E_NOMEM; + else { + cdf_mem_set(pNoAParam, sizeof(tP2pPsConfig), 0); + cdf_mem_copy(pNoAParam, pNoA, sizeof(tP2pPsConfig)); + msg.type = eWNI_SME_UPDATE_NOA; + msg.bodyval = 0; + msg.bodyptr = pNoAParam; + lim_post_msg_api(pMac, &msg); + } + return status; +} diff --git a/core/sme/src/qos/sme_qos.c b/core/sme/src/qos/sme_qos.c new file mode 100644 index 0000000000..7506fab486 --- /dev/null +++ b/core/sme/src/qos/sme_qos.c @@ -0,0 +1,7834 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file sme_qos.c + + \brief implementation for SME QoS APIs + + ========================================================================*/ +/* $Header$ */ +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" + +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#ifdef WLAN_FEATURE_VOWIFI_11R +#include "sms_debug.h" +#include "utils_parser.h" +#endif +#include "sme_power_save_api.h" + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/* TODO : 6Mbps as Cisco APs seem to like only this value; analysis req. */ +#define SME_QOS_MIN_PHY_RATE 0x5B8D80 +#define SME_QOS_SURPLUS_BW_ALLOWANCE 0x2000 /* Ratio of 1.0 */ +/*--------------------------------------------------------------------------- + Max values to bound tspec params against and avoid rollover + ---------------------------------------------------------------------------*/ +#define SME_QOS_32BIT_MAX 0xFFFFFFFF +#define SME_QOS_16BIT_MAX 0xFFFF +#define SME_QOS_16BIT_MSB 0x8000 +/*--------------------------------------------------------------------------- + Adds y to x, but saturates at 32-bit max to avoid rollover + ---------------------------------------------------------------------------*/ +#define SME_QOS_BOUNDED_U32_ADD_Y_TO_X(_x, _y) \ + do { \ + (_x) = ((SME_QOS_32BIT_MAX - (_x)) < (_y)) ? \ + (SME_QOS_32BIT_MAX) : (_x) + (_y); \ + } while (0) + +/*--------------------------------------------------------------------------- + As per WMM spec there could be max 2 TSPEC running on the same AC with + different direction. We will refer each TSPEC with an index + ---------------------------------------------------------------------------*/ +#define SME_QOS_TSPEC_INDEX_0 0 +#define SME_QOS_TSPEC_INDEX_1 1 +#define SME_QOS_TSPEC_INDEX_MAX 2 +#define SME_QOS_TSPEC_MASK_BIT_1_SET 1 +#define SME_QOS_TSPEC_MASK_BIT_2_SET 2 +#define SME_QOS_TSPEC_MASK_BIT_1_2_SET 3 +#define SME_QOS_TSPEC_MASK_CLEAR 0 + +/* which key to search on, in the flowlist (1 = flowID, 2 = AC, 4 = reason) */ +#define SME_QOS_SEARCH_KEY_INDEX_1 1 +#define SME_QOS_SEARCH_KEY_INDEX_2 2 +#define SME_QOS_SEARCH_KEY_INDEX_3 4 +#define SME_QOS_SEARCH_KEY_INDEX_4 8 /* ac + direction */ +#define SME_QOS_SEARCH_KEY_INDEX_5 0x10 /* ac + tspec_mask */ +/* special value for searching any Session Id */ +#define SME_QOS_SEARCH_SESSION_ID_ANY CSR_ROAM_SESSION_MAX +#define SME_QOS_ACCESS_POLICY_EDCA 1 +#define SME_QOS_MAX_TID 255 +#define SME_QOS_TSPEC_IE_LENGTH 61 +#define SME_QOS_TSPEC_IE_TYPE 2 +#define SME_QOS_MIN_FLOW_ID 1 +#define SME_QOS_MAX_FLOW_ID 0xFFFFFFFE +#define SME_QOS_INVALID_FLOW_ID 0xFFFFFFFF +/* per the WMM Specification v1.2 Section 2.2.10 */ +/* The Dialog Token field shall be set [...] to a non-zero value */ +#define SME_QOS_MIN_DIALOG_TOKEN 1 +#define SME_QOS_MAX_DIALOG_TOKEN 0xFF +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------- + Enumeration of the various states in the QoS state m/c + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_CLOSED = 0, + SME_QOS_INIT, + SME_QOS_LINK_UP, + SME_QOS_REQUESTED, + SME_QOS_QOS_ON, + SME_QOS_HANDOFF, + +} sme_QosStates; +/*--------------------------------------------------------------------------- + Enumeration of the various Release QoS trigger + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_RELEASE_DEFAULT = 0, + SME_QOS_RELEASE_BY_AP, +} sme_QosRelTriggers; +/*--------------------------------------------------------------------------- + Enumeration of the various QoS cmds + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_SETUP_REQ = 0, + SME_QOS_RELEASE_REQ, + SME_QOS_MODIFY_REQ, + SME_QOS_RESEND_REQ, + SME_QOS_CMD_MAX +} sme_QosCmdType; +/*--------------------------------------------------------------------------- + Enumeration of the various QoS reason codes to be used in the Flow list + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_REASON_SETUP = 0, + SME_QOS_REASON_RELEASE, + SME_QOS_REASON_MODIFY, + SME_QOS_REASON_MODIFY_PENDING, + SME_QOS_REASON_REQ_SUCCESS, + SME_QOS_REASON_MAX +} sme_QosReasonType; + +/*--------------------------------------------------------------------------- + Table to map user priority passed in as an argument to appropriate Access + Category as specified in 802.11e/WMM + ---------------------------------------------------------------------------*/ +sme_QosEdcaAcType sme_qos_u_pto_ac_map[SME_QOS_WMM_UP_MAX] = { + SME_QOS_EDCA_AC_BE, /* User Priority 0 */ + SME_QOS_EDCA_AC_BK, /* User Priority 1 */ + SME_QOS_EDCA_AC_BK, /* User Priority 2 */ + SME_QOS_EDCA_AC_BE, /* User Priority 3 */ + SME_QOS_EDCA_AC_VI, /* User Priority 4 */ + SME_QOS_EDCA_AC_VI, /* User Priority 5 */ + SME_QOS_EDCA_AC_VO, /* User Priority 6 */ + SME_QOS_EDCA_AC_VO /* User Priority 7 */ +}; + +/*--------------------------------------------------------------------------- + Table to map access category (AC) to appropriate user priority as specified + in 802.11e/WMM + Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs + Mapping is done for consistency + ---------------------------------------------------------------------------*/ +sme_QosWmmUpType sme_qos_a_cto_up_map[SME_QOS_EDCA_AC_MAX] = { + SME_QOS_WMM_UP_BE, /* AC BE */ + SME_QOS_WMM_UP_BK, /* AC BK */ + SME_QOS_WMM_UP_VI, /* AC VI */ + SME_QOS_WMM_UP_VO /* AC VO */ +}; + +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's FLOW Link List structure. This list can hold information per + flow/request, like TSPEC params requested, which AC it is running on + ---------------------------------------------------------------------------*/ +typedef struct sme_QosFlowInfoEntry_s { + tListElem link; /* list links */ + uint8_t sessionId; + uint8_t tspec_mask; + sme_QosReasonType reason; + uint32_t QosFlowID; + sme_QosEdcaAcType ac_type; + sme_QosWmmTspecInfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +} sme_QosFlowInfoEntry; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's setup request cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_qos_setupCmdInfo_s { + uint32_t QosFlowID; + sme_QosWmmTspecInfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + sme_QosWmmUpType UPType; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +} sme_qos_setupCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's modify cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosModifyCmdInfo_s { + uint32_t QosFlowID; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo QoSInfo; +} sme_QosModifyCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's resend cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosResendCmdInfo_s { + uint8_t tspecMask; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo QoSInfo; +} sme_QosResendCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's release cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosReleaseCmdInfo_s { + uint32_t QosFlowID; +} sme_QosReleaseCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's buffered cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosCmdInfo_s { + sme_QosCmdType command; + tpAniSirGlobal pMac; + uint8_t sessionId; + union { + sme_qos_setupCmdInfo setupCmdInfo; + sme_QosModifyCmdInfo modifyCmdInfo; + sme_QosResendCmdInfo resendCmdInfo; + sme_QosReleaseCmdInfo releaseCmdInfo; + } u; +} sme_QosCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's buffered cmd List structure. This list can hold information + related to any pending cmd from HDD + ---------------------------------------------------------------------------*/ +typedef struct sme_QosCmdInfoEntry_s { + tListElem link; /* list links */ + sme_QosCmdInfo cmdInfo; +} sme_QosCmdInfoEntry; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's Per AC information structure. This can hold information on + how many flows running on the AC, the current, previous states the AC is in + ---------------------------------------------------------------------------*/ +typedef struct sme_QosACInfo_s { + uint8_t num_flows[SME_QOS_TSPEC_INDEX_MAX]; + sme_QosStates curr_state; + sme_QosStates prev_state; + sme_QosWmmTspecInfo curr_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + sme_QosWmmTspecInfo requested_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + bool reassoc_pending; /* reassoc requested for APSD */ + /* As per WMM spec there could be max 2 TSPEC running on the same AC with */ + /* different direction. We will refer each TSPEC with an index */ + uint8_t tspec_mask_status; /* status showing if both the indices are in use */ + uint8_t tspec_pending; /* tspec negotiation going on for which index */ + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +#ifdef WLAN_FEATURE_VOWIFI_11R + uint8_t ricIdentifier[SME_QOS_TSPEC_INDEX_MAX]; + /* stores the ADD TS response for each AC. The ADD TS response is formed by + parsing the RIC received in the the reassoc response */ + tSirAddtsRsp addTsRsp[SME_QOS_TSPEC_INDEX_MAX]; +#endif + sme_QosRelTriggers relTrig; + +} sme_QosACInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's Per session information structure. This can hold information + on the state of the session + ---------------------------------------------------------------------------*/ +typedef struct sme_QosSessionInfo_s { + /* what is this entry's session id */ + uint8_t sessionId; + /* is the session currently active */ + bool sessionActive; + /* All AC info for this session */ + sme_QosACInfo ac_info[SME_QOS_EDCA_AC_MAX]; + /* Bitmask of the ACs with APSD on */ + /* Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored */ + uint8_t apsdMask; + /* association information for this session */ + sme_QosAssocInfo assocInfo; + /* ID assigned to our reassoc request */ + uint32_t roamID; + /* maintaining a powersave status in QoS module, to be fed back to PMC at */ + /* times through the sme_qos_pmc_check_routine */ + bool readyForPowerSave; + /* are we in the process of handing off to a different AP */ + bool handoffRequested; + /* following reassoc or AddTS has UAPSD already been requested from PMC */ + bool uapsdAlreadyRequested; + /* commands that are being buffered for this session */ + tDblLinkList bufferedCommandList; + +#ifdef WLAN_FEATURE_VOWIFI_11R + bool ftHandoffInProgress; +#endif + +} sme_QosSessionInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + Search key union. We can use the flowID, ac type, or reason to find an entry + in the flow list + ---------------------------------------------------------------------------*/ +typedef union sme_QosSearchKey_s { + uint32_t QosFlowID; + sme_QosEdcaAcType ac_type; + sme_QosReasonType reason; +} sme_QosSearchKey; +/*--------------------------------------------------------------------------- + DESCRIPTION + We can either use the flowID or the ac type to find an entry in the flow list. + The index is a bitmap telling us which key to use. Starting from LSB, + bit 0 - Flow ID + bit 1 - AC type + ---------------------------------------------------------------------------*/ +typedef struct sme_QosSearchInfo_s { + uint8_t sessionId; + uint8_t index; + sme_QosSearchKey key; + sme_QosWmmDirType direction; + uint8_t tspec_mask; +} sme_QosSearchInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's internal control block. + ---------------------------------------------------------------------------*/ +struct sme_qos_cb_s { + /* global Mac pointer */ + tpAniSirGlobal pMac; + /* All Session Info */ + sme_QosSessionInfo sessionInfo[CSR_ROAM_SESSION_MAX]; + /* All FLOW info */ + tDblLinkList flow_list; + /* default TSPEC params */ + sme_QosWmmTspecInfo def_QoSInfo[SME_QOS_EDCA_AC_MAX]; + /* counter for assigning Flow IDs */ + uint32_t nextFlowId; + /* counter for assigning Dialog Tokens */ + uint8_t nextDialogToken; +} sme_qos_cb; +typedef CDF_STATUS (*sme_QosProcessSearchEntry)(tpAniSirGlobal pMac, + tListElem *pEntry); + +sme_QosStatusType sme_qos_internal_setup_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal); +sme_QosStatusType sme_qos_internal_modify_req(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd); +sme_QosStatusType sme_qos_internal_release_req(tpAniSirGlobal pMac, + uint32_t QosFlowID, + bool buffered_cmd); +sme_QosStatusType sme_qos_setup(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac); +CDF_STATUS sme_qos_add_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac); +CDF_STATUS sme_qos_del_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask); +CDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +CDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, void *pMsgBuf); +CDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +CDF_STATUS sme_qos_process_assoc_complete_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_reassoc_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_reassoc_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +CDF_STATUS sme_qos_process_reassoc_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +CDF_STATUS sme_qos_process_disconnect_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_join_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_handoff_assoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_handoff_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +CDF_STATUS sme_qos_process_handoff_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +#ifdef WLAN_FEATURE_VOWIFI_11R +CDF_STATUS sme_qos_process_preauth_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +CDF_STATUS sme_qos_process_set_key_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +CDF_STATUS sme_qos_process_aggr_qos_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +CDF_STATUS sme_qos_ft_aggr_qos_req(tpAniSirGlobal pMac, uint8_t sessionId); +#endif +CDF_STATUS sme_qos_process_add_ts_success_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +CDF_STATUS sme_qos_process_add_ts_failure_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +CDF_STATUS sme_qos_aggregate_params(sme_QosWmmTspecInfo *pInput_Tspec_Info, + sme_QosWmmTspecInfo *pCurrent_Tspec_Info, + sme_QosWmmTspecInfo *pUpdated_Tspec_Info); +static CDF_STATUS sme_qos_update_params(uint8_t sessionId, + sme_QosEdcaAcType ac, + uint8_t tspec_mask, + sme_QosWmmTspecInfo *pTspec_Info); +sme_QosWmmUpType sme_qos_ac_to_up(sme_QosEdcaAcType ac); +sme_QosEdcaAcType sme_qos_up_to_ac(sme_QosWmmUpType up); +bool sme_qos_is_acm(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes); +tListElem *sme_qos_find_in_flow_list(sme_QosSearchInfo search_key); +CDF_STATUS sme_qos_find_all_in_flow_list(tpAniSirGlobal pMac, + sme_QosSearchInfo search_key, + sme_QosProcessSearchEntry fnp); +static void sme_qos_state_transition(uint8_t sessionId, + sme_QosEdcaAcType ac, + sme_QosStates new_state); +CDF_STATUS sme_qos_buffer_cmd(sme_QosCmdInfo *pcmd, bool insert_head); +static CDF_STATUS sme_qos_process_buffered_cmd(uint8_t sessionId); +CDF_STATUS sme_qos_save_assoc_info(sme_QosSessionInfo *pSession, + sme_QosAssocInfo *pAssoc_info); +CDF_STATUS sme_qos_setup_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +CDF_STATUS sme_qos_modification_notify_fnp(tpAniSirGlobal pMac, + tListElem *pEntry); +CDF_STATUS sme_qos_modify_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +CDF_STATUS sme_qos_del_ts_ind_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +CDF_STATUS sme_qos_reassoc_success_ev_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +CDF_STATUS sme_qos_add_ts_failure_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +CDF_STATUS sme_qos_add_ts_success_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +static bool sme_qos_is_rsp_pending(uint8_t sessionId, sme_QosEdcaAcType ac); +static bool sme_qos_is_uapsd_active(void); + +void sme_qos_pmc_offload_start_uapsd_callback(void *callbackContext, + uint32_t sessionId, CDF_STATUS status); +bool sme_qos_pmc_offload_check_routine(void *callbackContext, uint32_t sessionId); + +static CDF_STATUS sme_qos_buffer_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static CDF_STATUS sme_qos_delete_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static void sme_qos_cleanup_ctrl_blk_for_handoff(tpAniSirGlobal pMac, + uint8_t sessionId); +static CDF_STATUS sme_qos_delete_buffered_requests(tpAniSirGlobal pMac, + uint8_t sessionId); +bool sme_qos_validate_requested_params(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId); + +extern CDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme); +extern CDF_STATUS sme_release_global_lock(tSmeStruct *psSme); +static CDF_STATUS qos_issue_command(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, uint8_t tspec_mask); +/* + sme_qos_re_request_add_ts to re-send AddTS for the combined QoS request + */ +static sme_QosStatusType sme_qos_re_request_add_ts(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, + uint8_t tspecMask); +static void sme_qos_init_a_cs(tpAniSirGlobal pMac, uint8_t sessionId); +static CDF_STATUS sme_qos_request_reassoc(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce); +static uint32_t sme_qos_assign_flow_id(void); +static uint8_t sme_qos_assign_dialog_token(void); +static CDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionId, + sme_QosSearchInfo search_key, + uint8_t new_tspec_mask); + +/* External APIs definitions */ + +/** + * sme_qos_open() - called to initialize SME QoS module. + * @pMac: global MAC context + * + * This function must be called before any API call to + * SME QoS module. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_open(tpAniSirGlobal pMac) +{ + sme_QosSessionInfo *pSession; + uint8_t sessionId; + CDF_STATUS status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: initializing SME-QoS module", __func__, __LINE__); + /* init the control block */ + /* (note that this will make all sessions invalid) */ + cdf_mem_zero(&sme_qos_cb, sizeof(sme_qos_cb)); + sme_qos_cb.pMac = pMac; + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + /* init flow list */ + status = csr_ll_open(pMac->hHdd, &sme_qos_cb.flow_list); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: %d: cannot initialize Flow List", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pSession->sessionId = sessionId; + /* initialize the session's per-AC information */ + sme_qos_init_a_cs(pMac, sessionId); + /* initialize the session's buffered command list */ + status = csr_ll_open(pMac->hHdd, &pSession->bufferedCommandList); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: %d: cannot initialize cmd list for session %d", + __func__, __LINE__, sessionId); + return CDF_STATUS_E_FAILURE; + } + pSession->readyForPowerSave = true; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: done initializing SME-QoS module", + __func__, __LINE__); + return CDF_STATUS_SUCCESS; +} + +/* -------------------------------------------------------------------------- + \brief sme_qos_close() - To close down SME QoS module. There should not be + any API call into this module after calling this function until another + call of sme_qos_open. + \param pMac - Pointer to the global MAC parameter structure. + + \return CDF_STATUS + ----------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_close(tpAniSirGlobal pMac) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + uint8_t sessionId; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: closing down SME-QoS", __func__, __LINE__); + + /* cleanup control block */ + /* close the flow list */ + csr_ll_close(&sme_qos_cb.flow_list); + /* shut down all of the sessions */ + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession == NULL) + continue; + + sme_qos_init_a_cs(pMac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + pSession->uapsdAlreadyRequested = false; + pSession->handoffRequested = false; + pSession->readyForPowerSave = true; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + + /* Clean up the assoc info if already allocated */ + if (pSession->assocInfo.pBssDesc) { + cdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + /* close the session's buffered command list */ + csr_ll_close(&pSession->bufferedCommandList); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + sme_qos_state_transition(sessionId, ac, SME_QOS_CLOSED); + } + pSession->sessionActive = false; + pSession->readyForPowerSave = true; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: closed down QoS", __func__, __LINE__); + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_setup_req() - The SME QoS API exposed to HDD to request for QoS + * on a particular AC. + * @hHal: The handle returned by mac_open. + * @sessionId: sessionId returned by sme_open_session. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callabck) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @pQosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * This function should be called after a link has been + * established, i.e. STA is associated with an AP etc. If the request involves + * admission control on the requested AC, HDD needs to provide the necessary + * Traffic Specification (TSPEC) parameters otherwise SME is going to use the + * default params. + * Return: CDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +sme_QosStatusType sme_qos_setup_req(tHalHandle hHal, uint32_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t *pQosFlowID) +{ + sme_QosSessionInfo *pSession; + CDF_STATUS lock_status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Setup requested by client on session %d", + __func__, __LINE__, sessionId); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(lock_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + /* Make sure the session is valid */ + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is invalid", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Make sure the session is active */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is inactive", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Assign a Flow ID */ + *pQosFlowID = sme_qos_assign_flow_id(); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS request on session %d assigned Flow ID %d", + __func__, __LINE__, sessionId, *pQosFlowID); + /* Call the internal function for QoS setup, */ + /* adding a layer of abstraction */ + status = + sme_qos_internal_setup_req(pMac, (uint8_t) sessionId, + pQoSInfo, QoSCallback, + HDDcontext, UPType, + *pQosFlowID, false, + false); + } + } + sme_release_global_lock(&pMac->sme); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS setup return status on session %d is %d", + __func__, __LINE__, sessionId, status); + return status; +} + +/** + * sme_qos_modify_req() - The SME QoS API exposed to HDD to request for + * modification of certain QoS params on a flow running on a particular AC. + * @hHal: The handle returned by mac_open. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * This function should be called after a link has been established, + * i.e. STA is associated with an AP etc. & a QoS setup has been succesful for + * that flow. If the request involves admission control on the requested AC, + * HDD needs to provide the necessary Traffic Specification (TSPEC) parameters & + * SME might start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +sme_QosStatusType sme_qos_modify_req(tHalHandle hHal, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID) +{ + CDF_STATUS lock_status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Modify requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(lock_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + /* Call the internal function for QoS modify, adding a layer of abstraction */ + status = sme_qos_internal_modify_req(pMac, pQoSInfo, QosFlowID, false); + sme_release_global_lock(&pMac->sme); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Modify return status on Flow %d is %d", + __func__, __LINE__, QosFlowID, status); + return status; +} + +/** + * sme_qos_release_req() - The SME QoS API exposed to HDD to request for + * releasing a QoS flow running on a particular AC. + * + * @hHal: The handle returned by mac_open. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * This function should be called only if a QoS is set up with a valid FlowID. + * HDD sould invoke this API only if an explicit request for QoS release has + * come from Application + * + * Return: CDF_STATUS_SUCCESS - Release is successful. + */ +sme_QosStatusType sme_qos_release_req(tHalHandle hHal, uint32_t QosFlowID) +{ + CDF_STATUS lock_status = CDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(lock_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + /* Call the internal function for QoS release, adding a layer of abstraction */ + status = sme_qos_internal_release_req(pMac, QosFlowID, false); + sme_release_global_lock(&pMac->sme); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, QosFlowID, status); + return status; +} + +void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + cdf_mem_zero(&pCommand->u.qosCmd, sizeof(tGenericQosCmd)); + sme_release_command(pMac, pCommand); +} + +/** + * sme_qos_msg_processor() - Processes QOS messages + * @mac_ctx: Pointer to the global MAC parameter structure. + * @msg_type: the type of msg passed by PE as defined in wni_api.h + * @msg: a pointer to a buffer that maps to various structures bases. + * + * sme_process_msg() calls this function for the messages that + * are handled by SME QoS module. + * + * Return: CDF_STATUS enumeration. + */ +CDF_STATUS sme_qos_msg_processor(tpAniSirGlobal mac_ctx, + uint16_t msg_type, void *msg) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tListElem *entry = NULL; + tSmeCmd *command; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL(" msg = %d for QoS"), msg_type); + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_ADDTS_RSP: + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (NULL == entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandAddTs == command->command) { + status = sme_qos_process_add_ts_rsp(mac_ctx, msg); + if (csr_ll_remove_entry + (&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + sme_process_pending_queue(mac_ctx); + } + break; + case eWNI_SME_DELTS_RSP: + entry = + csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (NULL == entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandDelTs == command->command) { + status = sme_qos_process_del_ts_rsp(mac_ctx, msg); + if (csr_ll_remove_entry + (&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + sme_process_pending_queue(mac_ctx); + } + break; + case eWNI_SME_DELTS_IND: + status = sme_qos_process_del_ts_ind(mac_ctx, msg); + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case eWNI_SME_FT_AGGR_QOS_RSP: + status = sme_qos_process_aggr_qos_rsp(mac_ctx, msg); + break; +#endif + default: + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("unknown msg type = %d"), + msg_type); + break; + } + return status; +} + +/** + * sme_qos_validate_params() - validate SME QOS parameters. + * @pMac: Pointer to the global MAC parameter structure. + * @pBssDesc: Pointer to the BSS Descriptor information passed down by + * CSR to PE while issuing the Join request + * + * The SME QoS API exposed to CSR to validate AP + * capabilities regarding QoS support & any other QoS parameter validation. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + tDot11fBeaconIEs *pIes = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: validation for QAP & APSD", __func__, __LINE__); + do { + if (!CDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (!CSR_IS_QOS_BSS(pIes)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support QoS", + __func__, __LINE__); + + break; + } + if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) && + !(pIes->WMMInfoAp.uapsd)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support APSD", + __func__, __LINE__); + break; + } + status = CDF_STATUS_SUCCESS; + } while (0); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: validated with status = %d", + __func__, __LINE__, status); + if (pIes) { + cdf_mem_free(pIes); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_csr_event_ind() - The QoS sub-module in SME expects notifications + from CSR when certain events occur as mentioned in sme_qos_csr_event_indType. + \param pMac - Pointer to the global MAC parameter structure. + \param ind - The event occurred of type sme_qos_csr_event_indType. + \param pEvent_info - Information related to the event + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_csr_event_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On Session %d Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + switch (ind) { + case SME_QOS_CSR_ASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_assoc_complete_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_REASSOC_REQ: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_req_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_REASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_reassoc_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_failure_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_DISCONNECT_REQ: + case SME_QOS_CSR_DISCONNECT_IND: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_disconnect_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_JOIN_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_join_req_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_ASSOC_REQ: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_assoc_req_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_COMPLETE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_failure_ev(pMac, sessionId, + pEvent_info); + break; +#ifdef WLAN_FEATURE_VOWIFI_11R + case SME_QOS_CSR_PREAUTH_SUCCESS_IND: + status = + sme_qos_process_preauth_success_ind(pMac, sessionId, + pEvent_info); + break; +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) + case SME_QOS_CSR_SET_KEY_SUCCESS_IND: + status = + sme_qos_process_set_key_success_ind(pMac, sessionId, + pEvent_info); + break; +#endif +#endif + default: + /* Err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On Session %d Unknown Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + break; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On Session %d processed Event %d with status %d", + __func__, __LINE__, sessionId, ind, status); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_get_acm_mask() - The QoS sub-module API to find out on which ACs + AP mandates Admission Control (ACM = 1) + (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) + \param pMac - Pointer to the global MAC parameter structure. + \param pSirBssDesc - The event occurred of type sme_qos_csr_event_indType. + + \return a bit mask indicating for which ACs AP has ACM set to 1 + + \sa + + --------------------------------------------------------------------------*/ +uint8_t sme_qos_get_acm_mask(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + sme_QosEdcaAcType ac; + uint8_t acm_mask = 0; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked", __func__, __LINE__); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + if (sme_qos_is_acm(pMac, pSirBssDesc, ac, pIes)) { + acm_mask = acm_mask | (1 << (SME_QOS_EDCA_AC_VO - ac)); + } + + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: mask is %d", __func__, __LINE__, acm_mask); + return acm_mask; +} + +/* Internal function definitions */ + +/** + * sme_qos_internal_setup_req() - The SME QoS internal setup request handling + * function. + * + * @pMac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callabck) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * @buffered_cmd: tells us if the cmd was a buffered one or fresh from + * client + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters otherwise SME + * is going to use the default params. + * + * Return: CDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +sme_QosStatusType sme_qos_internal_setup_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo Tspec_Info; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosFlowInfoEntry *pentry = NULL; + sme_QosCmdInfo cmd; + sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + uint8_t tmask = 0; + uint8_t new_tmask = 0; + sme_QosSearchInfo search_key; + CDF_STATUS hstatus; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for flow %d", + __func__, __LINE__, sessionId, QosFlowID); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* if caller sent an empty TSPEC, fill up with the default one */ + if (!pQoSInfo) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "%s: %d: caller sent an empty QoS param list, using defaults", + __func__, __LINE__); + /* find the AC with UPType passed in */ + ac = sme_qos_up_to_ac(UPType); + if (SME_QOS_EDCA_AC_MAX == ac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, UPType); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = sme_qos_cb.def_QoSInfo[ac]; + } else { + /* find the AC */ + ac = sme_qos_up_to_ac(pQoSInfo->ts_info.up); + if (SME_QOS_EDCA_AC_MAX == ac) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, pQoSInfo->ts_info.up); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + /* validate QoS params */ + if (!sme_qos_validate_requested_params(pMac, pQoSInfo, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = *pQoSInfo; + } + pACInfo = &pSession->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending + * on any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the setup request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the setup request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered setup request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + } + /* get into the state m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + /* call the internal qos setup logic to decide on if the */ + /* request is NOP, or need reassoc for APSD and/or need to send out ADDTS */ + status = sme_qos_setup(pMac, sessionId, &Tspec_Info, ac); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_LINK_UP " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = cdf_mem_malloc(sizeof(*pentry)); + if (!pentry) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, + __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + /* since we are in state SME_QOS_LINK_UP this must be the */ + /* first TSPEC on this AC, so use index 0 (mask bit 1) */ + pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + if (pACInfo->tspec_mask_status && + !pACInfo->reassoc_pending) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d with AC %d in state " + "SME_QOS_LINK_UP tspec_mask_status is %d " + "but should not be set yet", + __func__, __LINE__, sessionId, + ac, + pACInfo->tspec_mask_status); + CDF_ASSERT(0); + cdf_mem_free(pentry); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + if (!pACInfo->reassoc_pending) { + /* we didn't request for reassoc, it must be a tspec negotiation */ + pACInfo->tspec_pending = 1; + } + + pentry->reason = SME_QOS_REASON_SETUP; + new_state = SME_QOS_REQUESTED; + } else { + /* SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP or */ + /* SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY */ + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + new_state = SME_QOS_QOS_ON; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + pentry->hoRenewal = false; + } + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]++; + + /* indicate on which index the flow entry belongs to & add it to the */ + /* Flow List at the end */ + pentry->tspec_mask = pACInfo->tspec_mask_status; + pentry->QoSInfo = Tspec_Info; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Creating entry on session %d at %p with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + if (buffered_cmd && hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + QosFlowID); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: Buffering setup request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d couldn't buffer the setup " + "request for flow %d in state = %d", + __func__, __LINE__, + sessionId, QosFlowID, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + new_state = pACInfo->curr_state; + break; + case SME_QOS_QOS_ON: + + /* check if multiple flows running on the ac */ + if ((pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] > 0) || + (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + /* do we need to care about the case where APSD needed on ACM = 0 below? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, ac, + NULL)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac); + if (!pACInfo->tspec_mask_status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: tspec_mask_status can't be 0 for ac = %d in " + "state = %d", __func__, + __LINE__, ac, + pACInfo->curr_state); + CDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return status; + } + /* Flow aggregation */ + if (((pACInfo->tspec_mask_status > 0) && + (pACInfo->tspec_mask_status <= + SME_QOS_TSPEC_INDEX_MAX))) { + /* Either of upstream, downstream or bidirectional flows are present */ + /* If either of new stream or current stream is for bidirecional, aggregate + * the new stream with the current streams present and send out aggregated Tspec.*/ + if ((Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) + || (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status - + 1].ts_info. + direction == + SME_QOS_WMM_TS_DIR_BOTH)) { + /* Aggregate the new stream with the current stream(s). */ + tmask = + pACInfo->tspec_mask_status; + } + /* None of new stream or current (aggregated) streams are for bidirectional. + * Check if the new stream direction matches the current stream direction. */ + else if (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status + - + 1].ts_info. + direction == + Tspec_Info.ts_info.direction) { + /* Aggregate the new stream with the current stream(s). */ + tmask = + pACInfo->tspec_mask_status; + } + /* New stream is in different direction. */ + else { + /* No Aggregation. Mark the 2nd tpsec index also as active. */ + tmask = + SME_QOS_TSPEC_MASK_CLEAR; + new_tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & ~pACInfo-> + tspec_mask_status; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + } + } else if (SME_QOS_TSPEC_MASK_BIT_1_2_SET == + pACInfo->tspec_mask_status) { + /* Both uplink and downlink streams are present. */ + /* If new stream is bidirectional, aggregate new stream with all existing + * upstreams and downstreams. Send out new aggregated tpsec. */ + if (Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + /* Only one tspec index (0) will be in use after this aggregation. */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } + /* New stream is also uni-directional + * Find out the tsepc index with which it needs to be aggregated */ + else if (pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0]. + ts_info.direction != + Tspec_Info.ts_info.direction) { + /* Aggregate with 2nd tspec index */ + tmask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + } else { + /* Aggregate with 1st tspec index */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: wrong tmask = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status); + } + } else { + /* ACM = 0 */ + /* We won't be sending a TSPEC to the AP but we still need */ + /* to aggregate to calculate trigger frame parameters */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tmask = %d, new_tmask = %d in state = %d", + __func__, __LINE__, + tmask, new_tmask, pACInfo->curr_state); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac); + if (tmask) { + /* create the aggregate TSPEC */ + if (tmask != SME_QOS_TSPEC_MASK_BIT_1_2_SET) { + hstatus = + sme_qos_aggregate_params(&Tspec_Info, + &pACInfo-> + curr_QoSInfo + [tmask - 1], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + } else { + /* Aggregate the new bidirectional stream with the existing upstreams and + * downstreams in tspec indices 0 and 1. */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + + hstatus = sme_qos_aggregate_params( + &Tspec_Info, &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + if (hstatus == CDF_STATUS_SUCCESS) { + hstatus = + sme_qos_aggregate_params + (&pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_1], + &pACInfo-> + requested_QoSInfo[tmask - + 1], + NULL); + } + } + + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: failed to aggregate params", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + } else { + if (! + (new_tmask > 0 + && new_tmask <= SME_QOS_TSPEC_INDEX_MAX)) { + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + tmask = new_tmask; + pACInfo->requested_QoSInfo[tmask - 1] = + Tspec_Info; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: no flows running for ac = %d while in state = %d", + __func__, __LINE__, ac, pACInfo->curr_state); + CDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return status; + } + /* although aggregating, make sure to request on the correct UP,TID,PSB and direction */ + pACInfo->requested_QoSInfo[tmask - 1].ts_info.up = + Tspec_Info.ts_info.up; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.tid = + Tspec_Info.ts_info.tid; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.direction = + Tspec_Info.ts_info.direction; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.psb = + Tspec_Info.ts_info.psb; + status = + sme_qos_setup(pMac, sessionId, + &pACInfo->requested_QoSInfo[tmask - 1], ac); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", __func__, + __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = + (sme_QosFlowInfoEntry *) + cdf_mem_malloc(sizeof(*pentry)); + if (!pentry) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, + __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Creating flow %d", + __func__, __LINE__, QosFlowID); + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + new_state = pACInfo->curr_state; + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + /* if we are not in handoff, then notify all flows on */ + /* this AC that the aggregate TSPEC may have changed */ + if (!pentry->hoRenewal) { + cdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_setup_fnp); + if (!CDF_IS_STATUS_SUCCESS + (hstatus)) { + CDF_TRACE + (CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } + } + pentry->hoRenewal = false; + } else { + /* SME_QOS_STATUS_SETUP_REQ_PENDING_RSP */ + new_state = SME_QOS_REQUESTED; + pentry->reason = SME_QOS_REASON_SETUP; + /* Need this info when addts comes back from PE to know on */ + /* which index of the AC the request was from */ + pACInfo->tspec_pending = tmask; + } + pACInfo->num_flows[tmask - 1]++; + /* indicate on which index the flow entry belongs to & add it to the */ + /* Flow List at the end */ + pentry->tspec_mask = tmask; + pentry->QoSInfo = Tspec_Info; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d creating entry at %p with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + } + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: setup requested in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + CDF_ASSERT(0); + new_state = pACInfo->curr_state; + } + /* if current state is same as previous no need for transistion, + if we are doing reassoc & we are already in handoff state, no need to move + to requested state. But make sure to set the previous state as requested + state + */ + if ((new_state != pACInfo->curr_state) && + (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)))) { + sme_qos_state_transition(sessionId, ac, new_state); + } + + if (pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)) { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_internal_modify_req() - The SME QoS internal function to request + * for modification of certain QoS params on a flow running on a particular AC. + * @pMac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters & SME might + * start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +sme_QosStatusType sme_qos_internal_modify_req(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *pNewEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosEdcaAcType ac; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + sme_QosWmmTspecInfo Aggr_Tspec_Info; + sme_QosSearchInfo search_key; + sme_QosCmdInfo cmd; + uint8_t sessionId; + CDF_STATUS hstatus; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked for flow %d", __func__, __LINE__, QosFlowID); + + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + if (!pEntry) { + /* Err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + + sessionId = flow_info->sessionId; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + /* validate QoS params */ + if (!sme_qos_validate_requested_params(pMac, pQoSInfo, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* For modify, make sure that direction, TID and UP are not being altered */ + if ((pQoSInfo->ts_info.direction != + flow_info->QoSInfo.ts_info.direction) + || (pQoSInfo->ts_info.up != flow_info->QoSInfo.ts_info.up) + || (pQoSInfo->ts_info.tid != flow_info->QoSInfo.ts_info.tid)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Modification of direction/tid/up is not allowed", + __func__, __LINE__); + + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + + /* should not be same as previous ioctl parameters */ + if ((pQoSInfo->nominal_msdu_size == + flow_info->QoSInfo.nominal_msdu_size) && + (pQoSInfo->maximum_msdu_size == + flow_info->QoSInfo.maximum_msdu_size) && + (pQoSInfo->min_data_rate == + flow_info->QoSInfo.min_data_rate) && + (pQoSInfo->mean_data_rate == + flow_info->QoSInfo.mean_data_rate) && + (pQoSInfo->peak_data_rate == + flow_info->QoSInfo.peak_data_rate) && + (pQoSInfo->min_service_interval == + flow_info->QoSInfo.min_service_interval) && + (pQoSInfo->max_service_interval == + flow_info->QoSInfo.max_service_interval) && + (pQoSInfo->inactivity_interval == + flow_info->QoSInfo.inactivity_interval) && + (pQoSInfo->suspension_interval == + flow_info->QoSInfo.suspension_interval) && + (pQoSInfo->surplus_bw_allowance == + flow_info->QoSInfo.surplus_bw_allowance)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: the addts parameters are same as last request," + "dropping the current request", __func__, __LINE__); + + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the modify request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered modify request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + /* save the new params adding a new (duplicate) entry in the Flow List */ + /* Once we have decided on OTA exchange needed or not we can delete the */ + /* original one from the List */ + pNewEntry = + (sme_QosFlowInfoEntry *) cdf_mem_malloc(sizeof(*pNewEntry)); + if (!pNewEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + pNewEntry->ac_type = ac; + pNewEntry->sessionId = sessionId; + pNewEntry->HDDcontext = flow_info->HDDcontext; + pNewEntry->QoSCallback = flow_info->QoSCallback; + pNewEntry->QosFlowID = flow_info->QosFlowID; + pNewEntry->reason = SME_QOS_REASON_MODIFY_PENDING; + /* since it is a modify request, use the same index on which the flow */ + /* entry originally was running & add it to the Flow List at the end */ + pNewEntry->tspec_mask = flow_info->tspec_mask; + pNewEntry->QoSInfo = *pQoSInfo; + /* update the entry from Flow List which needed to be modified */ + flow_info->reason = SME_QOS_REASON_MODIFY; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d creating modified " + "entry at %p with flowID %d", + __func__, __LINE__, + sessionId, pNewEntry, pNewEntry->QosFlowID); + /* add the new entry under construction to the Flow List */ + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pNewEntry->link, + true); + /* update TSPEC with the new param set */ + hstatus = sme_qos_update_params(sessionId, + ac, pNewEntry->tspec_mask, + &Aggr_Tspec_Info); + if (CDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[pNewEntry->tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(pMac, sessionId, + &pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1], + ac); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + pACInfo->tspec_pending = pNewEntry->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) + || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY + == status)) { + new_state = SME_QOS_QOS_ON; + + cdf_mem_zero(&search_key, + sizeof(sme_QosSearchInfo)); + /* delete the original entry in FLOW list which got modified */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + hstatus = + sme_qos_find_all_in_flow_list(pMac, search_key, + sme_qos_modify_fnp); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + status = + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP != + status) { + pACInfo->curr_QoSInfo[pNewEntry-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1]; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; + cdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_modification_notify_fnp); + if (!CDF_IS_STATUS_SUCCESS + (hstatus)) { + CDF_TRACE + (CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } else + if + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) { + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + } + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [pNewEntry-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + + } else { + /* unexpected status returned by sme_qos_setup() */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", __func__, + __LINE__, sessionId, status); + new_state = SME_QOS_QOS_ON; + } + } else { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + new_state = SME_QOS_LINK_UP; + } + /* if we are doing reassoc & we are already in handoff state, no need + to move to requested state. But make sure to set the previous state + as requested state + */ + if (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state))) { + sme_qos_state_transition(sessionId, ac, new_state); + } else { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: Buffering modify request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: modify requested in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_internal_release_req() - release QOS flow on a particular AC + * @pMac: Pointer to the global MAC parameter structure. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * The SME QoS internal function to request + * for releasing a QoS flow running on a particular AC. + + * Return: CDF_STATUS_SUCCESS - Release is successful. + */ +sme_QosStatusType sme_qos_internal_release_req(tpAniSirGlobal pMac, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosFlowInfoEntry *pDeletedFlow = NULL; + sme_QosEdcaAcType ac; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosStatusType status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + sme_QosWmmTspecInfo Aggr_Tspec_Info; + sme_QosSearchInfo search_key; + sme_QosCmdInfo cmd; + tCsrRoamModifyProfileFields modifyProfileFields; + bool deltsIssued = false; + uint8_t sessionId; + CDF_STATUS hstatus; + bool biDirectionalFlowsPresent = false; + bool uplinkFlowsPresent = false; + bool downlinkFlowsPresent = false; + tListElem *pResult = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked for flow %d", __func__, __LINE__, QosFlowID); + + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + + if (!pEntry) { + /* Err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + sessionId = flow_info->sessionId; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the release request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered release request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d with " + "entry tspec_mask = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac, + flow_info->tspec_mask); + + /* check if multiple flows running on the ac */ + if (pACInfo->num_flows[flow_info->tspec_mask - 1] > 1) { + /* don't want to include the flow in the new TSPEC on which release */ + /* is requested */ + flow_info->reason = SME_QOS_REASON_RELEASE; + + /* Check if the flow being released is for bi-diretional. + * Following flows may present in the system. + * a) bi-directional flows + * b) uplink flows + * c) downlink flows. + * If the flow being released is for bidirectional, splitting of existing + * streams into two tspec indices is required in case ff (b), (c) are present + * and not (a). + * In case if split occurs, all upstreams are aggregated into tspec index 0, + * downstreams are aggregaed into tspec index 1 and two tspec requests for + * (aggregated) upstream(s) followed by (aggregated) downstream(s) is sent + * to AP. */ + if (flow_info->QoSInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + cdf_mem_zero(&search_key, + sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = sessionId; + search_key.direction = SME_QOS_WMM_TS_DIR_BOTH; + pResult = sme_qos_find_in_flow_list(search_key); + if (pResult) + biDirectionalFlowsPresent = true; + + if (!biDirectionalFlowsPresent) { + /* The only existing bidirectional flow is being released */ + + /* Check if uplink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_UPLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + uplinkFlowsPresent = true; + + /* Check if downlink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + downlinkFlowsPresent = true; + + if (uplinkFlowsPresent + && downlinkFlowsPresent) { + /* Need to split the uni-directional flows into SME_QOS_TSPEC_INDEX_0 and SME_QOS_TSPEC_INDEX_1 */ + + cdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + /* Mark all downstream flows as using tspec index 1 */ + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = + sessionId; + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + sme_qos_update_tspec_mask + (sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_2_SET); + + /* Aggregate all downstream flows */ + hstatus = + sme_qos_update_params + (sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + &Aggr_Tspec_Info); + + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d buffering the AddTS request " + "for AC %d in state %d as Addts is pending " + "on other Tspec index of this AC", + __func__, __LINE__, + sessionId, ac, + pACInfo->curr_state); + + /* Buffer the (aggregated) tspec request for downstream flows. */ + /* Please note that the (aggregated) tspec for upstream flows is sent */ + /* out by the susequent logic. */ + cmd.command = + SME_QOS_RESEND_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + cmd.u.resendCmdInfo.QoSInfo = + Aggr_Tspec_Info; + pACInfo-> + requested_QoSInfo + [SME_QOS_TSPEC_MASK_BIT_2_SET + - 1] = Aggr_Tspec_Info; + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd + (&cmd, false))) { + CDF_TRACE + (CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to buffer the AddTS " + "request for AC %d TSPEC %d in state %d", + __func__, __LINE__, + sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + pACInfo-> + curr_state); + + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession-> + readyForPowerSave = + true; + + return + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + + } + } + } + + /* In case of splitting of existing streams, + * tspec_mask will be pointing to tspec index 0 and + * aggregated tspec for upstream(s) is sent out here. */ + hstatus = sme_qos_update_params(sessionId, + ac, flow_info->tspec_mask, + &Aggr_Tspec_Info); + if (CDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[flow_info-> + tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(pMac, sessionId, + &pACInfo-> + requested_QoSInfo + [flow_info->tspec_mask - + 1], ac); + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, + status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != + status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == + status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + pACInfo->tspec_pending = + flow_info->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { + new_state = SME_QOS_QOS_ON; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, + QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, + pEntry, true); + pDeletedFlow = flow_info; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + cdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_setup_fnp); + if (!CDF_IS_STATUS_SUCCESS + (hstatus)) { + CDF_TRACE + (CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } + status = + SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask + - 1], + status, + flow_info-> + QosFlowID); + } + } else { + /* unexpected status returned by sme_qos_setup() */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, + status); + new_state = SME_QOS_LINK_UP; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d deleting entry at " + "%p with flowID %d", __func__, + __LINE__, sessionId, + flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, + pEntry, true); + pDeletedFlow = flow_info; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask + - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + new_state = SME_QOS_LINK_UP; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* this is the only flow aggregated in this TSPEC */ + status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + /* check if delts needs to be sent */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, ac, + NULL)) { + /* check if other TSPEC for this AC is also in use */ + if (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + pACInfo->tspec_mask_status) { + /* this is the only TSPEC active on this AC */ + /* so indicate that we no longer require APSD */ + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + /* Also update modifyProfileFields.uapsd_mask in CSR for consistency */ + csr_get_modify_profile_fields(pMac, + flow_info-> + sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask = + pSession->apsdMask; + csr_set_modify_profile_fields(pMac, + flow_info-> + sessionId, + &modifyProfileFields); + if (!pSession->apsdMask) { + /* this session no longer needs UAPSD */ + /* do any sessions still require UAPSD? */ + if (!sme_qos_is_uapsd_active()) { + /* No sessions require UAPSD so turn it off */ + /* (really don't care when PMC stops it) */ + sme_ps_uapsd_disable( + pMac, sessionId); + } + } + } + if (SME_QOS_RELEASE_DEFAULT == pACInfo->relTrig) { + /* send delts */ + hstatus = + qos_issue_command(pMac, sessionId, + eSmeCommandDelTs, + NULL, ac, + flow_info-> + tspec_mask); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_del_ts_req() failed", + __func__, __LINE__); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = + true; + } else { + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & (~flow_info->tspec_mask); + deltsIssued = true; + } + } else { + pSession->readyForPowerSave = true; + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~flow_info->tspec_mask); + deltsIssued = true; + } + } else if (pSession->apsdMask & + (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* reassoc logic */ + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + if (!pSession->apsdMask) { + /* this session no longer needs UAPSD */ + /* do any sessions still require UAPSD? */ + if (!sme_qos_is_uapsd_active()) { + /* No sessions require UAPSD so turn it off */ + /* (really don't care when PMC stops it) */ + sme_ps_uapsd_disable( + pMac, sessionId); + } + } + hstatus = sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: Reassoc failed", + __func__, __LINE__); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } else { + pACInfo->reassoc_pending = false; /* no need to wait */ + pACInfo->prev_state = SME_QOS_LINK_UP; + pACInfo->tspec_pending = 0; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: nothing to do for AC = %d", + __func__, __LINE__, ac); + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + + if (SME_QOS_RELEASE_BY_AP == pACInfo->relTrig) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + &pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - + 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, + flow_info->QosFlowID); + } else if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + NULL, status, + flow_info->QosFlowID); + } + + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == status) { + break; + } + + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) > 0) + && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) <= SME_QOS_TSPEC_INDEX_MAX)) { + if (pACInfo-> + num_flows[(SME_QOS_TSPEC_MASK_BIT_1_2_SET & + ~flow_info->tspec_mask) - 1] > + 0) { + new_state = SME_QOS_QOS_ON; + } else { + new_state = SME_QOS_LINK_UP; + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Exceeded the array bounds of pACInfo->num_flows", + __func__, __LINE__); + CDF_ASSERT(0); + return + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + + if (false == deltsIssued) { + cdf_mem_zero(&pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - 1], + sizeof(sme_QosWmmTspecInfo)); + } + cdf_mem_zero(&pACInfo-> + requested_QoSInfo[flow_info->tspec_mask - + 1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->num_flows[flow_info->tspec_mask - 1]--; + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d deleting entry at %p with flowID %d", + __func__, __LINE__, + sessionId, flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + pDeletedFlow = flow_info; + pACInfo->relTrig = SME_QOS_RELEASE_DEFAULT; + } + /* if we are doing reassoc & we are already in handoff state, no need + to move to requested state. But make sure to set the previous state + as requested state + */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) { + sme_qos_state_transition(sessionId, ac, new_state); + } + if (pACInfo->reassoc_pending) { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + /* buffer cmd */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: release request in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + CDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + break; + } + /* if we deleted a flow, reclaim the memory */ + if (pDeletedFlow) { + cdf_mem_free(pDeletedFlow); + } + if ((SME_QOS_STATUS_RELEASE_SUCCESS_RSP == status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_setup() - internal SME QOS setup function. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which setup is being performed + * @pTspec_Info: Pointer to sme_QosWmmTspecInfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * The internal qos setup function which has the intelligence + * if the request is NOP, or for APSD and/or need to send out ADDTS. + * It also does the sanity check for QAP, AP supports APSD etc. + * The logic used in the code might be confusing. + * + * Trying to cover all the cases here. + * AP supports App wants ACM = 1 Already set APSD Result + * | 0 | 0 | 0 | 0 | NO ACM NO APSD + * | 0 | 0 | 0 | 1 | NO ACM NO APSD/INVALID + * | 0 | 0 | 1 | 0 | ADDTS + * | 0 | 0 | 1 | 1 | ADDTS + * | 0 | 1 | 0 | 0 | FAILURE + * | 0 | 1 | 0 | 1 | INVALID + * | 0 | 1 | 1 | 0 | ADDTS + * | 0 | 1 | 1 | 1 | ADDTS + * | 1 | 0 | 0 | 0 | NO ACM NO APSD + * | 1 | 0 | 0 | 1 | NO ACM NO APSD + * | 1 | 0 | 1 | 0 | ADDTS + * | 1 | 0 | 1 | 1 | ADDTS + * | 1 | 1 | 0 | 0 | REASSOC + * | 1 | 1 | 0 | 1 | NOP: APSD SET ALREADY + * | 1 | 1 | 1 | 0 | ADDTS + * | 1 | 1 | 1 | 1 | ADDTS + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP if the setup is successful' + */ +sme_QosStatusType sme_qos_setup(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + tDot11fBeaconIEs *pIes = NULL; + tCsrRoamModifyProfileFields modifyProfileFields; + CDF_STATUS hstatus; + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return status; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return status; + } + if (!pSession->assocInfo.pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return status; + } + hstatus = csr_get_parsed_bss_description_ies(pMac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, sessionId); + return status; + } + + /* success so pIes was allocated */ + + if (!CSR_IS_QOS_BSS(pIes)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support QoS", + __func__, __LINE__, sessionId); + cdf_mem_free(pIes); + /* notify HDD through the synchronous status msg */ + return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, + "%s: %d: UAPSD/PSB set %d: ", __func__, __LINE__, + pTspec_Info->ts_info.psb); + + pACInfo = &pSession->ac_info[ac]; + do { + /* is ACM enabled for this AC? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, + ac, NULL)) { + /* ACM is enabled for this AC so we must send an AddTS */ + if (pTspec_Info->ts_info.psb && + !(pIes->WMMParams. + qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP doesn't support it */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, sessionId); + break; + } + + if (SME_QOS_MAX_TID == pTspec_Info->ts_info.tid) { + /* App didn't set TID, generate one */ + pTspec_Info->ts_info.tid = + (uint8_t) (SME_QOS_WMM_UP_NC - + pTspec_Info->ts_info.up); + } + /* addts logic */ + hstatus = + qos_issue_command(pMac, sessionId, eSmeCommandAddTs, + pTspec_Info, ac, 0); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_add_ts_req() failed", + __func__, __LINE__); + break; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AddTS on AC %d is pending", + __func__, __LINE__, sessionId, ac); + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + break; + } + /* ACM is not enabled for this AC */ + /* Is the application looking for APSD? */ + if (0 == pTspec_Info->ts_info.psb) { + /* no, we don't need APSD */ + /* but check the case, if the setup is called as a result of a release */ + /* or modify which boils down to the fact that APSD was set on this AC */ + /* but no longer needed - so we need a reassoc for the above case to */ + /* let the AP know */ + if (pSession-> + apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* APSD was formerly enabled on this AC but is no longer required */ + /* so we must reassociate */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d reassoc needed " + "to disable APSD on AC %d", __func__, + __LINE__, sessionId, ac); + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + hstatus = + sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d reassociation to enable " + "APSD on AC %d is pending", + __func__, __LINE__, sessionId, + ac); + status = + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } else { + /* we don't need APSD on this AC */ + /* and we don't currently have APSD on this AC */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Request is not looking for APSD & Admission " + "Control isn't mandatory for the AC", + __func__, __LINE__); + /* return success right away */ + status = + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + break; + } else if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP doesn't support it */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, sessionId); + break; + } else if (pSession-> + apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* application is looking for APSD */ + /* and it is already enabled on this AC */ + status = SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Request is looking for APSD and it is already " + "set for the AC", __func__, __LINE__); + break; + } else { + /* application is looking for APSD */ + /* but it is not enabled on this AC */ + /* so we need to reassociate */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("On session %d reassoc needed to enable APSD on AC %d"), + sessionId, ac); + /* reassoc logic */ + /* update the UAPSD mask to include the new */ + /* AC on which APSD is requested */ + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask |= + 1 << (SME_QOS_EDCA_AC_VO - ac); + hstatus = + sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("On session %d reassociation to enable APSD on AC %d is pending"), + sessionId, ac); + status = + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } + } while (0); + + cdf_mem_free(pIes); + return status; +} + +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR) +/* This is a dummy function now. But the purpose of me adding this was to + * delay the TSPEC processing till SET_KEY completes. This function can be + * used to do any SME_QOS processing after the SET_KEY. As of now, it is + * not required as we are ok with tspec getting programmed before set_key + * as the roam timings are measured without tspec in reassoc! + */ +CDF_STATUS sme_qos_process_set_key_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "########### Set Key Complete #############"); + (void)sme_qos_process_buffered_cmd(sessionId); + return CDF_STATUS_SUCCESS; +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * sme_qos_ese_save_tspec_response() - save TSPEC parameters. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspec: Pointer to the TSPEC IE from the reassoc rsp + * @ac: Access Category for which this TSPEC rsp is received + * @tspecIndex: flow/direction + * + * This function saves the TSPEC parameters that came along in the TSPEC IE + * in the reassoc response + * + * Return: CDF_STATUS_SUCCESS - Release is successful. + */ +CDF_STATUS sme_qos_ese_save_tspec_response(tpAniSirGlobal pMac, uint8_t sessionId, + tDot11fIEWMMTSPEC *pTspec, uint8_t ac, + uint8_t tspecIndex) +{ + tpSirAddtsRsp pAddtsRsp = + &sme_qos_cb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex]; + + ac = sme_qos_u_pto_ac_map[pTspec->user_priority]; + + cdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = eSIR_SUCCESS; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = 0; + pAddtsRsp->rsp.status = eSIR_SUCCESS; + pAddtsRsp->rsp.wmeTspecPresent = pTspec->present; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: Copy Tspec to local data structure ac=%d, tspecIdx=%d", + __func__, ac, tspecIndex); + + if (pAddtsRsp->rsp.wmeTspecPresent) { + /* Copy TSPEC params received in assoc response to addts response */ + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, pTspec); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_ese_process_reassoc_tspec_rsp() - process ese reassoc tspec response + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pEven_info: Pointer to the smeJoinRsp structure + * + * This function processes the WMM TSPEC IE in the reassoc response. + * Reassoc triggered as part of ESE roaming to another ESE capable AP. + * If the TSPEC was added before reassoc, as part of Call Admission Control, + * the reasso req from the STA would carry the TSPEC parameters which were + * already negotiated with the older AP. + * + * Return: CDF_STATUS_SUCCESS - Release is successful. + */ +CDF_STATUS sme_qos_ese_process_reassoc_tspec_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + tDot11fIEWMMTSPEC *pTspecIE = NULL; + tCsrRoamSession *pCsrSession = NULL; + tCsrRoamConnectedInfo *pCsrConnectedInfo = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + uint8_t ac, numTspec, cnt; + uint8_t tspec_flow_index, tspec_mask_status; + uint32_t tspecIeLen; + + pCsrSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pCsrSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return CDF_STATUS_E_FAILURE; + } + pCsrConnectedInfo = &pCsrSession->connectedInfo; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + /* Get the TSPEC IEs which came along with the reassoc response */ + /* from the pbFrames pointer */ + pTspecIE = + (tDot11fIEWMMTSPEC *) (pCsrConnectedInfo->pbFrames + + pCsrConnectedInfo->nBeaconLength + + pCsrConnectedInfo->nAssocReqLength + + pCsrConnectedInfo->nAssocRspLength + + pCsrConnectedInfo->nRICRspLength); + + /* Get the number of tspecs Ies in the frame, the min length */ + /* should be atleast equal to the one TSPEC IE */ + tspecIeLen = pCsrConnectedInfo->nTspecIeLength; + if (tspecIeLen < sizeof(tDot11fIEWMMTSPEC)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("ESE Tspec IE len %d less than min %zu"), + tspecIeLen, sizeof(tDot11fIEWMMTSPEC)); + return CDF_STATUS_E_FAILURE; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "TspecLen = %d, pbFrames = %p, pTspecIE = %p", + tspecIeLen, pCsrConnectedInfo->pbFrames, pTspecIE); + + numTspec = (tspecIeLen) / sizeof(tDot11fIEWMMTSPEC); + for (cnt = 0; cnt < numTspec; cnt++) { + ac = sme_qos_up_to_ac(pTspecIE->user_priority); + if (ac >= SME_QOS_EDCA_AC_MAX) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("ac %d more than it`s max value"), ac); + return CDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + tspec_mask_status = pACInfo->tspec_mask_status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + FL("UP=%d, ac=%d, tspec_mask_status=%x"), + pTspecIE->user_priority, ac, tspec_mask_status); + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_index++) { + if (tspec_mask_status & (1 << tspec_flow_index)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_WARN, + FL + ("Found Tspec entry flow = %d AC = %d"), + tspec_flow_index, ac); + sme_qos_ese_save_tspec_response(pMac, sessionId, + pTspecIE, ac, + tspec_flow_index); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_WARN, + FL + ("Not found Tspec entry flow = %d AC = %d"), + tspec_flow_index, ac); + } + } + /* Increment the pointer to point it to the next TSPEC IE */ + pTspecIE++; + } + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(pMac, sessionId); + + return status; +} + +/** + * sme_qos_copy_tspec_info() - copy tspec info. + * @pMac: Pointer to the global MAC parameter structure. + * @pTspec_Info: source structure + * @pTspec: destination structure + * + * This function copies the existing TSPEC parameters from the source structure + * to the destination structure. + * + * Return: None + */ +static void sme_qos_copy_tspec_info(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pTspec_Info, + tSirMacTspecIE *pTspec) +{ + /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + * Interval, Service Start Time, Suspension Interval and Delay Bound are + * all intended for HCCA operation and therefore must be set to zero*/ + pTspec->delayBound = pTspec_Info->delay_bound; + pTspec->inactInterval = pTspec_Info->inactivity_interval; + pTspec->length = SME_QOS_TSPEC_IE_LENGTH; + pTspec->maxBurstSz = pTspec_Info->max_burst_size; + pTspec->maxMsduSz = pTspec_Info->maximum_msdu_size; + pTspec->maxSvcInterval = pTspec_Info->max_service_interval; + pTspec->meanDataRate = pTspec_Info->mean_data_rate; + pTspec->mediumTime = pTspec_Info->medium_time; + pTspec->minDataRate = pTspec_Info->min_data_rate; + pTspec->minPhyRate = pTspec_Info->min_phy_rate; + pTspec->minSvcInterval = pTspec_Info->min_service_interval; + pTspec->nomMsduSz = pTspec_Info->nominal_msdu_size; + pTspec->peakDataRate = pTspec_Info->peak_data_rate; + pTspec->surplusBw = pTspec_Info->surplus_bw_allowance; + pTspec->suspendInterval = pTspec_Info->suspension_interval; + pTspec->svcStartTime = pTspec_Info->svc_start_time; + pTspec->tsinfo.traffic.direction = pTspec_Info->ts_info.direction; + + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + pTspec->tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + } else { + pTspec->tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pTspec->tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pTspec->tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pTspec->tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA; + pTspec->tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pTspec->tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy; + pTspec->type = SME_QOS_TSPEC_IE_TYPE; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +} + +/** + * sme_qos_ese_retrieve_tspec_info() - retrieve tspec info. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspecInfo: Pointer to the structure to carry back the TSPEC parameters + * + * This function is called by CSR when try to create reassoc request message to + * PE - csrSendSmeReassocReqMsg. This functions get the existing tspec + * parameters to be included in the reassoc request. + * + * Return: uint8_t - number of existing negotiated TSPECs + */ +uint8_t sme_qos_ese_retrieve_tspec_info(tpAniSirGlobal mac_ctx, + uint8_t session_id, tTspecInfo *tspec_info) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + uint8_t ac, num_tspec = 0; + tTspecInfo *dst_tspec = tspec_info; + uint8_t tspec_mask; + uint8_t tspec_pending; + + /* + * TODO: Check if TSPEC has already been established + * if not return + */ + session = &sme_qos_cb.sessionInfo[session_id]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + volatile uint8_t index = 0; + ac_info = &session->ac_info[ac]; + tspec_pending = ac_info->tspec_pending; + tspec_mask = ac_info->tspec_mask_status; + do { + /* + * If a tspec status is pending, take + * requested_QoSInfo for RIC request, + * else use curr_QoSInfo for the + * RIC request + */ + if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && (tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->requested_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } else if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && !(tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->curr_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } + tspec_mask >>= 1; + tspec_pending >>= 1; + index++; + } while (tspec_mask); + } + return num_tspec; +} + +#endif + +#ifdef WLAN_FEATURE_VOWIFI_11R + +CDF_STATUS sme_qos_create_tspec_ricie(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pTspec_Info, + uint8_t *pRICBuffer, uint32_t *pRICLength, + uint8_t *pRICIdentifier) +{ + tDot11fIERICDataDesc ricIE; + uint32_t nStatus; + + if (pRICBuffer == NULL || pRICIdentifier == NULL || pRICLength == NULL) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_zero(&ricIE, sizeof(tDot11fIERICDataDesc)); + + ricIE.present = 1; + ricIE.RICData.present = 1; + ricIE.RICData.resourceDescCount = 1; + ricIE.RICData.statusCode = 0; + ricIE.RICData.Identifier = sme_qos_assign_dialog_token(); +#ifndef USE_80211_WMMTSPEC_FOR_RIC + ricIE.TSPEC.present = 1; + ricIE.TSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.TSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.TSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.TSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.TSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.TSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.TSPEC.medium_time = 0; + ricIE.TSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.TSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.TSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.TSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.TSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.TSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.TSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.TSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.TSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + ricIE.TSPEC.psb = pTspec_Info->ts_info.psb; + } else { + ricIE.TSPEC.psb = 0; + } + ricIE.TSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.TSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + *pRICIdentifier = ricIE.RICData.Identifier; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), + pRICLength); + if (DOT11F_FAILED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Packing of RIC Data of length %d failed with status %d"), + *pRICLength, nStatus); + } +#else /* WMM TSPEC */ + /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + Interval, Service Start Time, Suspension Interval and Delay Bound are + all intended for HCCA operation and therefore must be set to zero */ + ricIE.WMMTSPEC.present = 1; + ricIE.WMMTSPEC.version = 1; + ricIE.WMMTSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.WMMTSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.WMMTSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.WMMTSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.WMMTSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.WMMTSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.WMMTSPEC.medium_time = 0; + ricIE.WMMTSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.WMMTSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.WMMTSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.WMMTSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.WMMTSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.WMMTSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.WMMTSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.WMMTSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.WMMTSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + ricIE.WMMTSPEC.psb = pTspec_Info->ts_info.psb; + } else { + ricIE.WMMTSPEC.psb = 0; + } + ricIE.WMMTSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.WMMTSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), + pRICLength); + if (DOT11F_FAILED(nStatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL + ("Packing of RIC Data of length %d failed with status %d"), + *pRICLength, nStatus); + } +#endif /* 80211_TSPEC */ + *pRICIdentifier = ricIE.RICData.Identifier; + return nStatus; +} +/** + * sme_qos_process_ft_reassoc_req_ev()- processes reassoc request + * + * @session_id: SME Session Id + * + * This function Process reassoc request related to QOS + * + * Return: CDF_STATUS enumeration value. + */ +static CDF_STATUS sme_qos_process_ft_reassoc_req_ev( + uint8_t sessionId) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + uint8_t ac, qos_requested = false; + uint8_t tspec_index; + sme_QosFlowInfoEntry *flow_info = NULL; + tListElem *entry = NULL; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Invoked on session %d"), sessionId); + + session = &sme_qos_cb.sessionInfo[sessionId]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &session->ac_info[ac]; + qos_requested = false; + + for (tspec_index = 0; + tspec_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_index++) { + /* + * Only in the below case, copy the AC's curr + * QoS Info to requested QoS info + */ + if ((ac_info->ricIdentifier[tspec_index] + && !ac_info->tspec_pending) + || (ac_info-> + tspec_mask_status & (1 << tspec_index))) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("Copying the currentQos to " + "requestedQos for AC=%d, flow=%d"), + ac, tspec_index); + + ac_info->requested_QoSInfo[tspec_index] = + ac_info->curr_QoSInfo[tspec_index]; + cdf_mem_zero( + &ac_info->curr_QoSInfo[tspec_index], + sizeof(sme_QosWmmTspecInfo)); + qos_requested = true; + } + } + + /* + * Only if the tspec is required, transition the state to + * SME_QOS_REQUESTED for this AC + */ + if (qos_requested) { + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + SME_QOS_REQUESTED); + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("FT Reassoc req event in" + " unexpected state %d"), + ac_info->curr_state); + CDF_ASSERT(0); + } + } + } + + /* + * At this point of time, we are + * disconnected from the old AP, so it is safe + * to reset all these session variables + */ + session->apsdMask = 0; + session->uapsdAlreadyRequested = 0; + session->readyForPowerSave = 0; + + /* + * Now change reason and HO renewal of + * all the flow in this session only + */ + entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!entry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + FL("Flow List empty, nothing to update")); + return CDF_STATUS_E_FAILURE; + } + + do { + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + if (sessionId == flow_info->sessionId) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Changing FlowID %d reason to SETUP" + "and HO renewal to false"), + flow_info->QosFlowID); + flow_info->reason = SME_QOS_REASON_SETUP; + flow_info->hoRenewal = true; + } + entry = csr_ll_next(&sme_qos_cb.flow_list, entry, false); + } while (entry); + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_fill_aggr_info - fill QOS Aggregation info + * + * @ac_id - index to the AC + * @ts_id - index to TS for a given AC + * @direction - traffic direction + * @msg - QOS message + * @session - sme session information + * + * this is a helper function to populate aggregation information + * for QOS message. + * + * Return: None + */ +static void sme_qos_fill_aggr_info(int ac_id, int ts_id, + sme_QosWmmDirType direction, + tSirAggrQosReq *msg, + sme_QosSessionInfo *session) +{ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + FL("Found tspec entry AC=%d, flow=%d, direction = %d"), + ac_id, ts_id, direction); + + msg->aggrInfo.aggrAddTsInfo[ac_id].dialogToken = + sme_qos_assign_dialog_token(); + msg->aggrInfo.aggrAddTsInfo[ac_id].lleTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.lleTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].numTclas = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.numTclas; + cdf_mem_copy(msg->aggrInfo.aggrAddTsInfo[ac_id].tclasInfo, + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasInfo, + SIR_MAC_TCLASIE_MAXNUM); + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProc = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProc; + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProcPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProcPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].tspec = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tspec; + msg->aggrInfo.aggrAddTsInfo[ac_id].wmeTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wmeTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].wsmTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wsmTspecPresent; + msg->aggrInfo.tspecIdx |= (1 << ac_id); + + /* Mark the index for this AC as pending for response, which would be */ + /* used to validate the AddTS response from HAL->PE->SME */ + session->ac_info[ac_id].tspec_pending = (1 << ts_id); + + return; +} + +/** + * sme_qos_ft_aggr_qos_req - send aggregated QOS request + * + * @mac_ctx - global MAC context + * @session_id - sme session Id + * + * This function is used to send aggregated QOS request to HAL. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_ft_aggr_qos_req(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tSirAggrQosReq *aggr_req = NULL; + sme_QosSessionInfo *session; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + int i, j = 0; + uint8_t direction; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), session_id); + + session = &sme_qos_cb.sessionInfo[session_id]; + + aggr_req = (tSirAggrQosReq *) cdf_mem_malloc(sizeof(tSirAggrQosReq)); + + if (!aggr_req) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("couldn't allocate memory for the msg buffer")); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(aggr_req, sizeof(tSirAggrQosReq)); + + aggr_req->messageType = eWNI_SME_FT_AGGR_QOS_REQ; + aggr_req->length = sizeof(tSirAggrQosReq); + aggr_req->sessionId = session_id; + aggr_req->timeout = 0; + aggr_req->rspReqd = true; + cdf_mem_copy(&aggr_req->bssId[0], + &session->assocInfo.pBssDesc->bssId[0], + sizeof(struct cdf_mac_addr)); + + for (i = 0; i < SME_QOS_EDCA_AC_MAX; i++) { + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("ac=%d, tspec_mask_staus=%x, tspec_index=%d"), + i, session->ac_info[i].tspec_mask_status, j); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("direction = %d"), + session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction); + /* Check if any flow is active on this AC */ + if (!((session->ac_info[i].tspec_mask_status) & + (1 << j))) + continue; + + direction = session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction; + + if ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)) { + sme_qos_fill_aggr_info(i, j, direction, + aggr_req, session); + } + } + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Sending aggregated message to HAL 0x%x"), + aggr_req->aggrInfo.tspecIdx); + + if (CDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(aggr_req))) { + status = CDF_STATUS_SUCCESS; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("sent down a AGGR QoS req to PE")); + } + + return status; +} + +CDF_STATUS sme_qos_process_ftric_response(tpAniSirGlobal pMac, uint8_t sessionId, + tDot11fIERICDataDesc *pRicDataDesc, + uint8_t ac, uint8_t tspecIndex) +{ + uint8_t i = 0; + tpSirAddtsRsp pAddtsRsp + = + &sme_qos_cb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex]; + + cdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = pRicDataDesc->RICData.statusCode; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = pRicDataDesc->RICData.Identifier; + pAddtsRsp->rsp.status = pRicDataDesc->RICData.statusCode; + pAddtsRsp->rsp.wmeTspecPresent = pRicDataDesc->TSPEC.present; + if (pAddtsRsp->rsp.wmeTspecPresent) { + /* Copy TSPEC params received in RIC response to addts response */ + convert_tspec(pMac, &pAddtsRsp->rsp.tspec, &pRicDataDesc->TSPEC); + } + + pAddtsRsp->rsp.numTclas = pRicDataDesc->num_TCLAS; + if (pAddtsRsp->rsp.numTclas) { + for (i = 0; i < pAddtsRsp->rsp.numTclas; i++) { + /* Copy TCLAS info per index to the addts response */ + convert_tclas(pMac, &pAddtsRsp->rsp.tclasInfo[i], + &pRicDataDesc->TCLAS[i]); + } + } + + pAddtsRsp->rsp.tclasProcPresent = pRicDataDesc->TCLASSPROC.present; + if (pAddtsRsp->rsp.tclasProcPresent) + pAddtsRsp->rsp.tclasProc = pRicDataDesc->TCLASSPROC.processing; + + pAddtsRsp->rsp.schedulePresent = pRicDataDesc->Schedule.present; + if (pAddtsRsp->rsp.schedulePresent) { + /* Copy Schedule IE params to addts response */ + convert_schedule(pMac, &pAddtsRsp->rsp.schedule, + &pRicDataDesc->Schedule); + } + /* Need to check the below portion is a part of WMM TSPEC */ + /* Process Delay element */ + if (pRicDataDesc->TSDelay.present) + convert_ts_delay(pMac, &pAddtsRsp->rsp.delay, + &pRicDataDesc->TSDelay); + + /* Need to call for WMMTSPEC */ + if (pRicDataDesc->WMMTSPEC.present) { + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, + &pRicDataDesc->WMMTSPEC); + } + /* return sme_qos_process_add_ts_rsp(pMac, &addtsRsp); */ + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_aggr_qos_rsp - process qos aggregation response + * + * @mac_ctx - global mac context + * @msgbuf - SME message buffer + * + * this function process the QOS aggregation response received. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_process_aggr_qos_rsp(tpAniSirGlobal mac_ctx, void *msgbuf) +{ + tpSirAggrQosRsp rsp = (tpSirAggrQosRsp) msgbuf; + tSirAddtsRsp addtsrsp; + CDF_STATUS status = CDF_STATUS_SUCCESS; + int i, j = 0; + uint8_t sessionid = rsp->sessionId; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Received AGGR_QOS resp from LIM")); + + /* Copy the updated response information for TSPEC of all the ACs */ + for (i = 0; i < SIR_QOS_NUM_AC_MAX; i++) { + uint8_t tspec_mask_status = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + tspec_mask_status; + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + uint8_t direction = + sme_qos_cb.sessionInfo[sessionid]. + ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic. + direction; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("Addts rsp from LIM AC=%d, flow=%d dir=%d, tspecIdx=%x"), + i, j, direction, rsp->aggrInfo.tspecIdx); + + /* Check if the direction is Uplink or bi-directional */ + if (!(((1 << i) & rsp->aggrInfo.tspecIdx) && + ((tspec_mask_status) & (1 << j)) && + ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)))) { + continue; + } + addtsrsp = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + addTsRsp[j]; + addtsrsp.rc = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.status = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.tspec = rsp->aggrInfo.aggrRsp[i].tspec; + + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("Processing Addts rsp from LIM AC=%d, flow=%d"), + i, j); + /* post ADD TS response for each */ + if (sme_qos_process_add_ts_rsp(mac_ctx, &addtsrsp) != + CDF_STATUS_SUCCESS) + status = CDF_STATUS_E_FAILURE; + } + } + return status; +} + +/** + * sme_qos_find_matching_tspec() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @ac_info: Current AC info + * @ric_data_desc: pointer to ric data + * @ric_rsplen: pointer to ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_qos_find_matching_tspec(tpAniSirGlobal mac_ctx, + uint8_t sessionid, uint8_t ac, sme_QosACInfo *ac_info, + tDot11fIERICDataDesc *ric_data_desc, uint32_t *ric_rsplen) +{ + uint8_t tspec_flow_index; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++) { + /* + * Only in the below case, copy the AC's curr QoS Info + * to requested QoS info + */ + if (!ac_info->ricIdentifier[tspec_flow_index]) + continue; + + if (!*ric_rsplen) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("RIC Response not received for AC %d on " + "TSPEC Index %d, RIC Req Identifier = %d"), + ac, tspec_flow_index, + ac_info->ricIdentifier[tspec_flow_index]); + CDF_ASSERT(0); + continue; + } + /* Now we got response for this identifier. Process it. */ + if (!ric_data_desc->present) + continue; + if (!ric_data_desc->RICData.present) + continue; + + if (ric_data_desc->RICData.Identifier != + ac_info->ricIdentifier[tspec_flow_index]) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("RIC response order not same as request sent. " + "Request ID = %d, Response ID = %d"), + ac_info->ricIdentifier[tspec_flow_index], + ric_data_desc->RICData.Identifier); + CDF_ASSERT(0); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + FL("Processing RIC Response for AC %d, " + "TSPEC Flow index %d with RIC ID %d "), + ac, tspec_flow_index, + ric_data_desc->RICData.Identifier); + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data_desc, ac, + tspec_flow_index); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Failed with status %d for AC %d in " + "TSPEC Flow index = %d"), + status, ac, tspec_flow_index); + } + } + ric_data_desc++; + *ric_rsplen -= sizeof(tDot11fIERICDataDesc); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_qos_find_matching_tspec_lfr3() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @qos_session: QOS session + * @ric_data_desc: pointer to ric data + * @ric_rsplen: ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec while LFR3 is enabled. + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_qos_find_matching_tspec_lfr3(tpAniSirGlobal mac_ctx, + uint8_t sessionid, uint8_t ac, sme_QosSessionInfo *qos_session, + tDot11fIERICDataDesc *ric_data_desc, uint32_t ric_rsplen) +{ + sme_QosACInfo *ac_info; + uint8_t tspec_flow_idx; + bool found = false; + sme_QosWmmDirType direction, qos_dir; + uint8_t ac1; + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + ric_data = ric_data_desc; + ric_len = ric_rsplen; + ac_info = &qos_session->ac_info[ac]; + for (tspec_flow_idx = 0; tspec_flow_idx < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_idx++) { + if (!((qos_session->ac_info[ac].tspec_mask_status) & + (1 << tspec_flow_idx))) + goto sme_qos_next_ric; + qos_dir = + ac_info->requested_QoSInfo[tspec_flow_idx].ts_info.direction; + do { + ac1 = sme_qos_up_to_ac( + ric_data->WMMTSPEC.user_priority); + if (ac == SME_QOS_EDCA_AC_MAX) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Invalid AC %d UP %d"), ac, + ric_data->WMMTSPEC.user_priority); + break; + } + direction = ric_data->WMMTSPEC.direction; + if (ac == ac1 && direction == qos_dir) { + found = true; + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data, ac, + tspec_flow_idx); + if (CDF_STATUS_SUCCESS != status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Failed with status %d for AC %d " + "in TSPEC Flow index = %d"), + status, ac, tspec_flow_idx); + } + break; + } + ric_data++; + ric_len -= sizeof(tDot11fIERICDataDesc); + } while (ric_len); +sme_qos_next_ric: + ric_data = ric_data_desc; + ric_len = ric_rsplen; + found = false; + } + + return status; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +CDF_STATUS sme_qos_process_ft_reassoc_rsp_ev(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + uint8_t ac; + tDot11fIERICDataDesc *ric_data_desc = NULL; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, sessionid); + tCsrRoamConnectedInfo *csr_conn_info = NULL; + uint32_t ric_rsplen; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; +#endif + + if (NULL == csr_session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("The Session pointer is NULL")); + return CDF_STATUS_E_FAILURE; + } + csr_conn_info = &csr_session->connectedInfo; + ric_rsplen = csr_conn_info->nRICRspLength; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + ric_data_desc = (tDot11fIERICDataDesc *) ((csr_conn_info->pbFrames) + + (csr_conn_info->nBeaconLength + + csr_conn_info->nAssocReqLength + + csr_conn_info->nAssocRspLength)); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!csr_session->roamOffloadSynchParams.bRoamSynchInProgress) { +#endif + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + sme_qos_find_matching_tspec(mac_ctx, sessionid, ac, + ac_info, ric_data_desc, &ric_rsplen); + } + + if (ric_rsplen) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("RIC Response still follows despite traversing " + "through all ACs. Remaining len = %d"), ric_rsplen); + CDF_ASSERT(0); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("LFR3-11r Compare RIC in Reassoc Resp to find" + " matching tspec in host.")); + ric_data = ric_data_desc; + ric_len = ric_rsplen; + if (ric_rsplen && ric_data_desc->present && + ric_data_desc->WMMTSPEC.present) { + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; + ac++) { + sme_qos_find_matching_tspec_lfr3(mac_ctx, + sessionid, ac, qos_session, ric_data, + ric_len); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("LFR3-11r ric_rsplen is zero or ric_data_desc is" + " not present or wmmtspec is not present")); + } + } +#endif + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(mac_ctx, sessionid); + + return status; +} + +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/** + * sme_qos_add_ts_req() - send ADDTS request. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which the TSPEC should be added + * @pTspec_Info: Pointer to sme_QosWmmTspecInfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * This function is used to send down the ADDTS request with TSPEC params to PE + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_add_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac) +{ + tSirAddtsReq *pMsg = NULL; + sme_QosSessionInfo *pSession; + CDF_STATUS status = CDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_ESE + tCsrRoamSession *pCsrSession = CSR_GET_SESSION(pMac, sessionId); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + if (sessionId >= CSR_ROAM_SESSION_MAX) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: sessionId(%d) is invalid", + __func__, __LINE__, sessionId); + return CDF_STATUS_E_FAILURE; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pMsg = (tSirAddtsReq *) cdf_mem_malloc(sizeof(tSirAddtsReq)); + if (!pMsg) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(pMsg, sizeof(tSirAddtsReq)); + pMsg->messageType = eWNI_SME_ADDTS_REQ; + pMsg->length = sizeof(tSirAddtsReq); + pMsg->sessionId = sessionId; + pMsg->timeout = 0; + pMsg->rspReqd = true; + pMsg->req.dialogToken = sme_qos_assign_dialog_token(); + /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + Interval, Service Start Time, Suspension Interval and Delay Bound are + all intended for HCCA operation and therefore must be set to zero */ + pMsg->req.tspec.delayBound = 0; + pMsg->req.tspec.inactInterval = pTspec_Info->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspec_Info->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspec_Info->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspec_Info->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspec_Info->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspec_Info->medium_time; + pMsg->req.tspec.minDataRate = pTspec_Info->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspec_Info->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspec_Info->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspec_Info->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspec_Info->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspec_Info->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspec_Info->suspension_interval; + pMsg->req.tspec.svcStartTime = 0; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + pMsg->req.tspec.tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + } else { + pMsg->req.tspec.tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pMsg->req.tspec.tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspec_Info->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (NULL == pSession->assocInfo.pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + cdf_mem_free(pMsg); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(&pMsg->bssId[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct cdf_mac_addr)); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +#ifdef FEATURE_WLAN_ESE + if (pCsrSession->connectedProfile.isESEAssoc) { + pMsg->req.tsrsIE.tsid = pTspec_Info->ts_info.up; + pMsg->req.tsrsPresent = 1; + } +#endif + if (CDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(pMsg))) { + status = CDF_STATUS_SUCCESS; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: sent down a ADDTS req to PE", + __func__, __LINE__); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_REQ; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_del_ts_req() - To send down the DELTS request with TSPEC params + to PE + + \param pMac - Pointer to the global MAC parameter structure. + \param sessionId - Session from which the TSPEC should be deleted + \param ac - Enumeration of the various EDCA Access Categories. + \param tspec_mask - on which tspec per AC, the delts is requested + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_del_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + tSirDeltsReq *pMsg; + sme_QosWmmTspecInfo *pTspecInfo; + CDF_STATUS status = CDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + pMsg = (tSirDeltsReq *) cdf_mem_malloc(sizeof(tSirDeltsReq)); + if (!pMsg) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(pMsg, sizeof(tSirDeltsReq)); + /* get pointer to the TSPEC being deleted */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pTspecInfo = &pACInfo->curr_QoSInfo[tspec_mask - 1]; + pMsg->messageType = eWNI_SME_DELTS_REQ; + pMsg->length = sizeof(tSirDeltsReq); + pMsg->sessionId = sessionId; + pMsg->rspReqd = true; + pMsg->req.tspec.delayBound = pTspecInfo->delay_bound; + pMsg->req.tspec.inactInterval = pTspecInfo->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspecInfo->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspecInfo->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspecInfo->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspecInfo->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspecInfo->medium_time; + pMsg->req.tspec.minDataRate = pTspecInfo->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspecInfo->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspecInfo->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspecInfo->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspecInfo->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspecInfo->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspecInfo->suspension_interval; + pMsg->req.tspec.svcStartTime = pTspecInfo->svc_start_time; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspecInfo->ts_info.direction; + pMsg->req.tspec.tsinfo.traffic.psb = pTspecInfo->ts_info.psb; + pMsg->req.tspec.tsinfo.traffic.tsid = pTspecInfo->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspecInfo->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspecInfo->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspecInfo->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (NULL == pSession->assocInfo.pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + cdf_mem_free(pMsg); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(&pMsg->bssId[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct cdf_mac_addr)); + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspecInfo->ts_info.up, pTspecInfo->ts_info.tid); + cdf_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1], + sizeof(sme_QosWmmTspecInfo)); + if (CDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(pMsg))) { + status = CDF_STATUS_SUCCESS; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: sme_qos_del_ts_req:Test: sent down a DELTS req to PE", + __func__, __LINE__); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + } + sme_set_tspec_uapsd_mask_per_session(pMac, + &pMsg->req.tspec.tsinfo, + sessionId); + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_rsp() - Function to process the + eWNI_SME_ADDTS_RSP came from PE + + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + uint8_t sessionId = paddts_rsp->sessionId; + CDF_STATUS status = CDF_STATUS_E_FAILURE; +#ifdef WLAN_FEATURE_VOWIFI_11R + sme_QosWmmUpType up = + (sme_QosWmmUpType) paddts_rsp->rsp.tspec.tsinfo.traffic.userPrio; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + +#ifdef WLAN_FEATURE_VOWIFI_11R + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + + return CDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_HANDOFF == pACInfo->curr_state) { + sms_log(pMac, LOG1, + FL + ("ADDTS Response received for AC %d in HANDOFF State.. Dropping"), + ac); + pSession->readyForPowerSave = true; + return CDF_STATUS_SUCCESS; + } +#endif + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, sessionId, paddts_rsp->rc); + /* our outstanding request has been serviced */ + /* we can go into powersave */ + pSession->readyForPowerSave = true; + if (paddts_rsp->rc) { + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_REFUSED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + status = + sme_qos_process_add_ts_failure_rsp(pMac, sessionId, + &paddts_rsp->rsp); + } else { + status = + sme_qos_process_add_ts_success_rsp(pMac, sessionId, + &paddts_rsp->rsp); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_del_ts_rsp() - Function to process the + eWNI_SME_DELTS_RSP came from PE + + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + uint8_t sessionId = pDeltsRsp->sessionId; + /* msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, sessionId, pDeltsRsp->rc); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* our outstanding request has been serviced */ + /* we can go into powersave */ + pSession->readyForPowerSave = true; + (void)sme_qos_process_buffered_cmd(sessionId); + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_del_ts_ind() - Function to process the + eWNI_SME_DELTS_IND came from PE + + Since it's a DELTS indication from AP, will notify all the flows running on + this AC about QoS release + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t sessionId = pdeltsind->sessionId; + sme_QosEdcaAcType ac; + sme_QosSearchInfo search_key; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pdeltsind->rsp.tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return CDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* find all Flows on the perticular AC & delete them, also send HDD indication */ + /* through the callback it registered per request */ + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list(pMac, search_key, sme_qos_del_ts_ind_fnp))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for ac = %d", __func__, + __LINE__, search_key.key.ac_type); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } +/* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_DELTS_IND_FROM_AP; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_assoc_complete_ev() - Function to process the + SME_QOS_CSR_ASSOC_COMPLETE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_assoc_complete_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_BE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (((SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state)) + || (pSession->handoffRequested)) { + /* get the association info */ + if (!pEvent_info) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: pEvent_info is NULL", + __func__, __LINE__); + return status; + } + if (!((sme_QosAssocInfo *) pEvent_info)->pBssDesc) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: pBssDesc is NULL", + __func__, __LINE__); + return status; + } + if ((pSession->assocInfo.pBssDesc) && + (csr_is_bssid_match + (pMac, (struct cdf_mac_addr *) &pSession->assocInfo.pBssDesc->bssId, + (struct cdf_mac_addr *) &(((sme_QosAssocInfo *) pEvent_info)-> + pBssDesc->bssId)))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: assoc with the same BSS, no update needed", + __func__, __LINE__); + } else { + status = sme_qos_save_assoc_info(pSession, pEvent_info); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: wrong state: BE %d, BK %d, VI %d, VO %d", + __func__, __LINE__, + pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state); + CDF_ASSERT(0); + return status; + } + /* the session is active */ + pSession->sessionActive = true; + if (pSession->handoffRequested) { + pSession->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionId); + status = CDF_STATUS_SUCCESS; + } else { + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_INIT: + sme_qos_state_transition(sessionId, ac, + SME_QOS_LINK_UP); + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + case SME_QOS_HANDOFF: + case SME_QOS_CLOSED: + default: + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, sessionId, ac, + pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_reassoc_req_ev() - Function to process the + SME_QOS_CSR_REASSOC_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_reassoc_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSession->ftHandoffInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + sme_qos_process_ft_reassoc_req_ev(sessionId); + return CDF_STATUS_SUCCESS; + } +#endif + + if (pSession->handoffRequested) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + /* buffer the existing flows to be renewed after handoff is done */ + sme_qos_buffer_existing_flows(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return CDF_STATUS_SUCCESS; + } +/* TBH: Assuming both handoff algo & 11r willn't be enabled at the same time */ +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSession->ftHandoffInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + sme_qos_process_ft_reassoc_req_ev(sessionId); + return CDF_STATUS_SUCCESS; + } +#endif + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* This is normal because sme_qos_request_reassoc may already change the state */ + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_handle_handoff_state() - utility function called by + * sme_qos_process_reassoc_success_ev + * @mac_ctx: global MAC context + * @qos_session: QOS session + * @ac_info: AC information + * @ac: current AC index + * @sessionid: session id + * + * This function is called by sme_qos_process_reassoc_success_ev + * to update the state machine on the reception of reassoc success + * notificaiton + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_handle_handoff_state(tpAniSirGlobal mac_ctx, + sme_QosSessionInfo *qos_session, sme_QosACInfo *ac_info, + sme_QosEdcaAcType ac, uint8_t sessionid) + +{ + sme_QosSearchInfo search_key; + sme_QosSearchInfo search_key1; + sme_QosEdcaAcType ac_index; + tListElem *list_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + /* return to our previous state */ + sme_qos_state_transition(sessionid, ac, ac_info->prev_state); + /* for which ac APSD (hence the reassoc) is requested */ + if (!ac_info->reassoc_pending) + return CDF_STATUS_SUCCESS; + + /* + * update the apsd mask in CB - make sure to take care of the + * case where we are resetting the bit in apsd_mask + */ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb) + qos_session->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac); + else + qos_session->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + + ac_info->reassoc_pending = false; + /* + * during setup it gets set as addts & reassoc both gets a + * pending flag ac_info->tspec_pending = 0; + */ + sme_qos_state_transition(sessionid, ac, SME_QOS_QOS_ON); + /* notify HDD with new Service Interval */ + ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionid; + /* notify PMC that reassoc is done for APSD on certain AC?? */ + + cdf_mem_zero(&search_key1, sizeof(sme_QosSearchInfo)); + /* set the hoRenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionid; + for (ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + ac_index++) { + list_elt = sme_qos_find_in_flow_list(search_key1); + if (list_elt) { + flow_info = GET_BASE_ADDR(list_elt, + sme_QosFlowInfoEntry, link); + if (flow_info->ac_type == ac) { + ac_info->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + /* + * notify HDD the success for the requested flow notify all the + * other flows running on the AC that QoS got modified + */ + status = sme_qos_find_all_in_flow_list(mac_ctx, search_key, + sme_qos_reassoc_success_ev_fnp); + if (!CDF_IS_STATUS_SUCCESS(status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("no match found for ac = %d"), + search_key.key.ac_type); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + ac_info->hoRenewal = false; + cdf_mem_zero(&ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + + return status; +} + +/** + * sme_qos_process_reassoc_success_ev() - process SME_QOS_CSR_REASSOC_COMPLETE + * + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer from CSR + * + * Function to process the SME_QOS_CSR_REASSOC_COMPLETE event indication + * from CSR + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_process_reassoc_success_ev(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + + tCsrRoamSession *csr_roam_session = NULL; + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosEdcaAcType ac; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), sessionid); + + if (CSR_ROAM_SESSION_MAX <= sessionid) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("invoked on session %d"), sessionid); + return status; + } + + csr_roam_session = CSR_GET_SESSION(mac_ctx, sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + /* + * our pending reassociation has completed + * we can allow powersave + */ + qos_session->readyForPowerSave = true; + + /* get the association info */ + if (!event_info) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("event_info is NULL")); + return status; + } + + if (!((sme_QosAssocInfo *) event_info)->pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("pBssDesc is NULL")); + return status; + } + status = sme_qos_save_assoc_info(qos_session, event_info); + if (status) + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_save_assoc_info() failed")); + + /* + * Assuming both handoff algo & 11r willn't be enabled + * at the same time + */ + if (qos_session->handoffRequested) { + qos_session->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionid); + return CDF_STATUS_SUCCESS; + } +#ifdef WLAN_FEATURE_VOWIFI_11R + if (qos_session->ftHandoffInProgress) { + if (csr_roam_is11r_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nRICRspLength) { + status = sme_qos_process_ft_reassoc_rsp_ev( + mac_ctx, sessionid, event_info); + } + } +#ifdef FEATURE_WLAN_ESE + /* + * If ESE association check for TSPEC IEs in the + * reassoc rsp frame + */ + if (csr_roam_is_ese_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nTspecIeLength) { + status = sme_qos_ese_process_reassoc_tspec_rsp( + mac_ctx, sessionid, event_info); + } + } +#endif + qos_session->ftHandoffInProgress = false; + qos_session->handoffRequested = false; + return status; + } +#endif + + qos_session->sessionActive = true; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + status = sme_qos_handle_handoff_state(mac_ctx, + qos_session, ac_info, ac, sessionid); + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + status = CDF_STATUS_SUCCESS; + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("session %d AC %d is in wrong state %d"), + sessionid, ac, ac_info->curr_state); + CDF_ASSERT(0); + break; + } + } + (void)sme_qos_process_buffered_cmd(sessionid); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_reassoc_failure_ev() - Function to process the + SME_QOS_CSR_REASSOC_FAILURE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_reassoc_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* our pending reassociation has completed */ + /* we can allow powersave */ + pSession->readyForPowerSave = true; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + if (pACInfo->reassoc_pending) { + pACInfo->reassoc_pending = false; + } + cdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; + pACInfo->tspec_pending = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_assoc_req_ev() - Function to process the + SME_QOS_CSR_HANDOFF_ASSOC_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_handoff_assoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ +#ifdef WLAN_FEATURE_VOWIFI_11R + if (pSession->ftHandoffInProgress) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO, + "%s: %d: SME_QOS_CSR_HANDOFF_ASSOC_REQ received in " + "SME_QOS_HANDOFF state with FT in progress", + __func__, __LINE__); + break; + } +#endif + + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (csr_roam_is11r_assoc(pMac, sessionId)) { + pSession->ftHandoffInProgress = true; + } +#endif + /* If FT handoff is in progress, legacy handoff need not be enabled */ + if (!pSession->ftHandoffInProgress) { + pSession->handoffRequested = true; + } + /* this session no longer needs UAPSD */ + pSession->apsdMask = 0; + /* do any sessions still require UAPSD? */ + sme_ps_uapsd_disable(pMac, sessionId); + pSession->uapsdAlreadyRequested = false; + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_success_ev() - Function to process the + SME_QOS_CSR_HANDOFF_COMPLETE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_handoff_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* go back to original state before handoff */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + pACInfo->prev_state); + /* we will retry for the requested flow(s) with the new AP */ + if (SME_QOS_REQUESTED == pACInfo->curr_state) { + pACInfo->curr_state = SME_QOS_LINK_UP; + } + status = CDF_STATUS_SUCCESS; + break; + /* FT logic, has already moved it to QOS_REQUESTED state during the */ + /* reassoc request event, which would include the Qos (TSPEC) params */ + /* in the reassoc req frame */ + case SME_QOS_REQUESTED: + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + case SME_QOS_LINK_UP: + case SME_QOS_QOS_ON: + default: +#ifdef WLAN_FEATURE_VOWIFI_11R +/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the + state may be SME_QOS_REQUESTED */ + if (pSession->ftHandoffInProgress) + break; +#endif + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_failure_ev() - Function to process the + SME_QOS_CSR_HANDOFF_FAILURE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_handoff_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + /* need to clean up flows: TODO */ + cdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + cdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; + pACInfo->tspec_pending = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + CDF_ASSERT(0); + break; + } + } + /* no longer in handoff */ + pSession->handoffRequested = false; + /* clean up the assoc info */ + if (pSession->assocInfo.pBssDesc) { + cdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_disconnect_ev() - Function to process the + SME_QOS_CSR_DISCONNECT_REQ or SME_QOS_CSR_DISCONNECT_IND event indication + from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_disconnect_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if ((pSession->handoffRequested) +#ifdef WLAN_FEATURE_VOWIFI_11R +/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the + state may be SME_QOS_REQUESTED */ + && !pSession->ftHandoffInProgress +#endif + ) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + CDF_ASSERT(0); + return CDF_STATUS_SUCCESS; + } + + return CDF_STATUS_SUCCESS; + } + sme_qos_init_a_cs(pMac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + sme_ps_uapsd_disable(pMac, sessionId); + + pSession->uapsdAlreadyRequested = false; + pSession->handoffRequested = false; + pSession->readyForPowerSave = true; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + /* clean up the assoc info */ + if (pSession->assocInfo.pBssDesc) { + cdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + sme_qos_cb.sessionInfo[sessionId].sessionActive = false; + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_join_req_ev() - Function to process the + SME_QOS_CSR_JOIN_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_join_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession->handoffRequested) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + /* just print */ + CDF_ASSERT(0); + } + /* buffer the existing flows to be renewed after handoff is done */ + sme_qos_buffer_existing_flows(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return CDF_STATUS_SUCCESS; + } + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + cdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_VOWIFI_11R +/** + * sme_qos_process_preauth_success_ind() - process preauth success indication + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer + * + * Function to process the SME_QOS_CSR_PREAUTH_SUCCESS_IND event indication + * from CSR + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_process_preauth_success_ind(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + sme_QosSessionInfo *qos_session; + tCsrRoamSession *sme_session = CSR_GET_SESSION(mac_ctx, sessionid); + sme_QosACInfo *ac_info; + uint8_t ac; + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint16_t ric_offset = 0; + uint32_t ric_ielen = 0; + uint8_t *ric_ie; + uint8_t tspec_mask_status = 0; + uint8_t tspec_pending_status = 0; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on SME session %d"), sessionid); + + if (NULL == sme_session) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_session is NULL")); + return CDF_STATUS_E_INVAL; + } + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + + switch (ac_info->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionid, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Session %d AC %d is in wrong state %d"), + sessionid, ac, ac_info->curr_state); + CDF_ASSERT(0); + break; + } + } + + qos_session->ftHandoffInProgress = true; + + /* Check if its a 11R roaming before preparing the RIC IEs */ + if (!csr_roam_is11r_assoc(mac_ctx, sessionid)) + return status; + + /* Data is accessed from saved PreAuth Rsp */ + if (NULL == sme_session->ftSmeContext.psavedFTPreAuthRsp) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("psavedFTPreAuthRsp is NULL")); + return CDF_STATUS_E_INVAL; + } + + /* + * Any Block Ack info there, should have been already filled by PE and + * present in this buffer and the ric_ies_length should contain the + * length of the whole RIC IEs. Filling of TSPEC info should start + * from this length + */ + ric_ie = sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies; + ric_offset = + sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + + /* + * Now we have to process the currentTspeInfo inside this session and + * create the RIC IEs + */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + volatile uint8_t tspec_idx = 0; + ric_ielen = 0; + ac_info = &qos_session->ac_info[ac]; + tspec_pending_status = ac_info->tspec_pending; + tspec_mask_status = ac_info->tspec_mask_status; + cdf_mem_zero(ac_info->ricIdentifier, SME_QOS_TSPEC_INDEX_MAX); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + FL("AC %d ==> TSPEC status = %d, tspec pending = %d"), + ac, tspec_mask_status, tspec_pending_status); + + do { + if (!(tspec_mask_status & 0x1)) + goto add_next_ric; + + /* + * If a tspec status is pending, take requested_QoSInfo + * for RIC request, else use curr_QoSInfo for the + * RIC request + */ + if (tspec_pending_status & 0x1) { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->requested_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } else { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->curr_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } +add_next_ric: + ric_offset += ric_ielen; + sme_session->ftSmeContext.psavedFTPreAuthRsp-> + ric_ies_length += ric_ielen; + tspec_mask_status >>= 1; + tspec_pending_status >>= 1; + tspec_idx++; + } while (tspec_mask_status); + } + return status; +} + +#endif + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_failure_rsp() - Function to process the + Addts request failure response came from PE + + We will notify HDD only for the requested Flow, other Flows running on the AC + stay intact + + \param pMac - Pointer to the global MAC parameter structure. + \param pRsp - Pointer to the addts response structure came from PE. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_add_ts_failure_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + sme_QosSearchInfo search_key; + uint8_t tspec_pending; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pRsp->tspec.tsinfo.traffic.userPrio; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", __func__, __LINE__, + sessionId, up); + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return CDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, sessionId, ac); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (pMac, search_key, sme_qos_add_ts_failure_fnp))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac = %d", + __func__, __LINE__, sessionId, + search_key.key.ac_type); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(sme_QosWmmTspecInfo)); + + if ((!pACInfo->num_flows[0]) && (!pACInfo->num_flows[1])) { + pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~pACInfo->tspec_pending); + sme_qos_state_transition(sessionId, ac, SME_QOS_LINK_UP); + } else { + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + } + pACInfo->tspec_pending = 0; + + (void)sme_qos_process_buffered_cmd(sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_update_tspec_mask() - Utiltity function to update the tspec. + * @sessionid: Session upon which the TSPEC is being updated + * @search_key: search key + * @new_tspec_mask: tspec to be set for this AC + * + * Typical usage while aggregating unidirectional flows into a bi-directional + * flow on AC which is running multiple flows + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionid, + sme_QosSearchInfo search_key, + uint8_t new_tspec_mask) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d for AC %d TSPEC %d"), + sessionid, search_key.key.ac_type, new_tspec_mask); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + if (search_key.key.ac_type < SME_QOS_EDCA_AC_MAX) { + ac_info = &qos_session->ac_info[search_key.key.ac_type]; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Exceeded the array bounds")); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, nothing to update")); + return CDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + + if (search_key.sessionId != flow_info->sessionId) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow %d matches"), flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_5) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.tspec_mask == flow_info->tspec_mask)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow %d matches"), flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } + list_elt = list_next_elt; + } + + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_success_rsp() - Function to process the + Addts request success response came from PE + + We will notify HDD with addts success for the requested Flow, & for other + Flows running on the AC we will send an addts modify status + + \param pMac - Pointer to the global MAC parameter structure. + \param pRsp - Pointer to the addts response structure came from PE. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_process_add_ts_success_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac, ac_index; + sme_QosSearchInfo search_key; + sme_QosSearchInfo search_key1; + uint8_t tspec_pending; + tListElem *pEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pRsp->tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); + host_log_qos_tspec_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return CDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, sessionId, ac); + return CDF_STATUS_E_FAILURE; + } + /* App is looking for APSD or the App which was looking for APSD has been */ + /* released, so STA re-negotiated with AP */ + if (pACInfo->requested_QoSInfo[tspec_pending - 1].ts_info.psb) { + /* update the session's apsd mask */ + pSession->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac); + } else { + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) > 0) && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) <= + SME_QOS_TSPEC_INDEX_MAX)) { + if (!pACInfo->requested_QoSInfo + [(SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) - + 1].ts_info.psb) { + /* update the session's apsd mask */ + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + } + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Exceeded the array bounds of pACInfo->requested_QosInfo", + __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + } + + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.burst_size_defn = + pRsp->tspec.tsinfo.traffic.burstSizeDefn; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.ack_policy = + pRsp->tspec.tsinfo.traffic.ackPolicy; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.up = + pRsp->tspec.tsinfo.traffic.userPrio; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.psb = + pRsp->tspec.tsinfo.traffic.psb; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.direction = + pRsp->tspec.tsinfo.traffic.direction; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.tid = + pRsp->tspec.tsinfo.traffic.tsid; + pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size = + pRsp->tspec.nomMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size = + pRsp->tspec.maxMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_service_interval = + pRsp->tspec.minSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_service_interval = + pRsp->tspec.maxSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].inactivity_interval = + pRsp->tspec.inactInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].suspension_interval = + pRsp->tspec.suspendInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time = + pRsp->tspec.svcStartTime; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate = + pRsp->tspec.minDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate = + pRsp->tspec.meanDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate = + pRsp->tspec.peakDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size = + pRsp->tspec.maxBurstSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound = + pRsp->tspec.delayBound; + + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate = + pRsp->tspec.minPhyRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance = + pRsp->tspec.surplusBw; + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time = + pRsp->tspec.mediumTime; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AddTspec Medium Time %d", + __func__, __LINE__, sessionId, pRsp->tspec.mediumTime); + + /* Check if the current flow is for bi-directional. If so, update the number of flows + * to reflect that all flows are aggregated into tspec index 0. */ + if ((pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1].ts_info. + direction == SME_QOS_WMM_TS_DIR_BOTH) + && (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* update tspec_mask for all the flows having SME_QOS_TSPEC_MASK_BIT_2_SET to SME_QOS_TSPEC_MASK_BIT_1_SET */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_5; + search_key.sessionId = sessionId; + search_key.tspec_mask = SME_QOS_TSPEC_MASK_BIT_2_SET; + sme_qos_update_tspec_mask(sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_1_SET); + } + + cdf_mem_zero(&search_key1, sizeof(sme_QosSearchInfo)); + /* set the horenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionId; + for (ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + ac_index++) { + pEntry = sme_qos_find_in_flow_list(search_key1); + if (pEntry) { + flow_info = + GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if (flow_info->ac_type == ac) { + pACInfo->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + cdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* notify HDD the success for the requested flow */ + /* notify all the other flows running on the AC that QoS got modified */ + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (pMac, search_key, sme_qos_add_ts_success_fnp))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac %d", + __func__, __LINE__, sessionId, + search_key.key.ac_type); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + pACInfo->hoRenewal = false; + cdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(sme_QosWmmTspecInfo)); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_tspec_pkt_type, + LOG_WLAN_QOS_TSPEC_C); + if (log_ptr) { + log_ptr->delay_bound = + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound; + log_ptr->inactivity_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].inactivity_interval; + log_ptr->max_burst_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size; + log_ptr->max_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].max_service_interval; + log_ptr->maximum_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size; + log_ptr->mean_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate; + log_ptr->medium_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time; + log_ptr->min_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate; + log_ptr->min_phy_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate; + log_ptr->min_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].min_service_interval; + log_ptr->nominal_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size; + log_ptr->peak_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate; + log_ptr->surplus_bw_allowance = + pACInfo->curr_QoSInfo[tspec_pending - + 1].surplus_bw_allowance; + log_ptr->suspension_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].surplus_bw_allowance; + log_ptr->suspension_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].suspension_interval; + log_ptr->svc_start_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time; + log_ptr->tsinfo[0] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.direction << 5 | pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.tid << 1; + log_ptr->tsinfo[1] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.up << 11 | pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.psb << 10; + log_ptr->tsinfo[2] = 0; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pACInfo->tspec_pending = 0; + + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + + sme_set_tspec_uapsd_mask_per_session(pMac, + &pRsp->tspec.tsinfo, sessionId); + + (void)sme_qos_process_buffered_cmd(sessionId); + return CDF_STATUS_SUCCESS; + +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_aggregate_params() - Utiltity function to increament the TSPEC + params per AC. Typical usage while using flow aggregation or deletion of flows + + \param pInput_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains the + WMM TSPEC related info with which pCurrent_Tspec_Info will be updated + \param pCurrent_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains + current the WMM TSPEC related info + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_aggregate_params(sme_QosWmmTspecInfo *pInput_Tspec_Info, + sme_QosWmmTspecInfo *pCurrent_Tspec_Info, + sme_QosWmmTspecInfo *pUpdated_Tspec_Info) +{ + sme_QosWmmTspecInfo TspecInfo; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked", __func__, __LINE__); + if (!pInput_Tspec_Info) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: input is NULL, nothing to aggregate", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + if (!pCurrent_Tspec_Info) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Current is NULL, can't aggregate", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_copy(&TspecInfo, pCurrent_Tspec_Info, + sizeof(sme_QosWmmTspecInfo)); + TspecInfo.ts_info.psb = pInput_Tspec_Info->ts_info.psb; + /*------------------------------------------------------------------------- + APSD preference is only meaningful if service interval was set by app + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->min_service_interval && + pInput_Tspec_Info->min_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.min_service_interval = + CDF_MIN(pCurrent_Tspec_Info->min_service_interval, + pInput_Tspec_Info->min_service_interval); + } else if (pInput_Tspec_Info->min_service_interval) { + TspecInfo.min_service_interval = + pInput_Tspec_Info->min_service_interval; + } + if (pCurrent_Tspec_Info->max_service_interval && + pInput_Tspec_Info->max_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.max_service_interval = + CDF_MIN(pCurrent_Tspec_Info->max_service_interval, + pInput_Tspec_Info->max_service_interval); + } else { + TspecInfo.max_service_interval = + pInput_Tspec_Info->max_service_interval; + } + /*------------------------------------------------------------------------- + If directions don't match, it must necessarily be both uplink and + downlink + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction) { + TspecInfo.ts_info.direction = + pInput_Tspec_Info->ts_info.direction; + } + /*------------------------------------------------------------------------- + Max MSDU size : these sizes are `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.maximum_msdu_size = + CDF_MAX(pCurrent_Tspec_Info->maximum_msdu_size, + pInput_Tspec_Info->maximum_msdu_size); + + /*------------------------------------------------------------------------- + Inactivity interval : these sizes are `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.inactivity_interval = + CDF_MAX(pCurrent_Tspec_Info->inactivity_interval, + pInput_Tspec_Info->inactivity_interval); + + /*------------------------------------------------------------------------- + Delay bounds: min of all values + Check on 0: if 0, it means initial value since delay can never be 0!! + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->delay_bound) { + TspecInfo.delay_bound = + CDF_MIN(pCurrent_Tspec_Info->delay_bound, + pInput_Tspec_Info->delay_bound); + } else { + TspecInfo.delay_bound = pInput_Tspec_Info->delay_bound; + } + TspecInfo.max_burst_size = CDF_MAX(pCurrent_Tspec_Info->max_burst_size, + pInput_Tspec_Info->max_burst_size); + + /*------------------------------------------------------------------------- + Nominal MSDU size also has a fixed bit that needs to be `handled' before + aggregation + This can be handled only if previous size is the same as new or both have + the fixed bit set + These sizes are not added: but `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.nominal_msdu_size = + CDF_MAX(pCurrent_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB, + pInput_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB); + + if (((pCurrent_Tspec_Info->nominal_msdu_size == 0) || + (pCurrent_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)) && + ((pInput_Tspec_Info->nominal_msdu_size == 0) || + (pInput_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB))) { + TspecInfo.nominal_msdu_size |= SME_QOS_16BIT_MSB; + } + + /*------------------------------------------------------------------------- + Data rates: + Add up the rates for aggregation + -------------------------------------------------------------------------*/ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.peak_data_rate, + pInput_Tspec_Info->peak_data_rate); + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.min_data_rate, + pInput_Tspec_Info->min_data_rate); + /* mean data rate = peak data rate: aggregate to be flexible on apps */ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.mean_data_rate, + pInput_Tspec_Info->mean_data_rate); + + /*------------------------------------------------------------------------- + Suspension interval : this is set to the inactivity interval since per + spec it is less than or equal to inactivity interval + This is not provided by app since we currently don't support the HCCA + mode of operation + Currently set it to 0 to avoid confusion: Cisco ESE needs ~0; spec + requires inactivity interval to be > suspension interval: this could + be tricky! + -------------------------------------------------------------------------*/ + TspecInfo.suspension_interval = pInput_Tspec_Info->suspension_interval; + /*------------------------------------------------------------------------- + Remaining parameters do not come from app as they are very WLAN + air interface specific + Set meaningful values here + -------------------------------------------------------------------------*/ + TspecInfo.medium_time = 0; /* per WMM spec */ + TspecInfo.min_phy_rate = SME_QOS_MIN_PHY_RATE; + TspecInfo.svc_start_time = 0; /* arbitrary */ + TspecInfo.surplus_bw_allowance += + pInput_Tspec_Info->surplus_bw_allowance; + if (TspecInfo.surplus_bw_allowance > SME_QOS_SURPLUS_BW_ALLOWANCE) { + TspecInfo.surplus_bw_allowance = SME_QOS_SURPLUS_BW_ALLOWANCE; + } + /* Set ack_policy to block ack even if one stream requests block ack policy */ + if ((pInput_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) + || (pCurrent_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)) { + TspecInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + } + + if (pInput_Tspec_Info->ts_info.burst_size_defn + || pCurrent_Tspec_Info->ts_info.burst_size_defn) { + TspecInfo.ts_info.burst_size_defn = 1; + } + if (pUpdated_Tspec_Info) { + cdf_mem_copy(pUpdated_Tspec_Info, &TspecInfo, + sizeof(sme_QosWmmTspecInfo)); + } else { + cdf_mem_copy(pCurrent_Tspec_Info, &TspecInfo, + sizeof(sme_QosWmmTspecInfo)); + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_update_params() - Utiltity function to update the TSPEC + params per AC. Typical usage while deleting flows on AC which is running + multiple flows + + \param sessionId - Session upon which the TSPEC is being updated + \param ac - Enumeration of the various EDCA Access Categories. + \param tspec_mask - on which tspec per AC, the update is requested + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static CDF_STATUS sme_qos_update_params(uint8_t sessionId, + sme_QosEdcaAcType ac, + uint8_t tspec_mask, + sme_QosWmmTspecInfo *pTspec_Info) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosWmmTspecInfo Tspec_Info; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d TSPEC %d", + __func__, __LINE__, sessionId, ac, tspec_mask); + if (!pTspec_Info) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: output is NULL, can't aggregate", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + cdf_mem_zero(&Tspec_Info, sizeof(sme_QosWmmTspecInfo)); + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, nothing to update", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* init the TS info field */ + Tspec_Info.ts_info.up = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.up; + Tspec_Info.ts_info.psb = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.psb; + Tspec_Info.ts_info.tid = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.tid; + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if ((sessionId == flow_info->sessionId) && + (ac == flow_info->ac_type) && + (tspec_mask == flow_info->tspec_mask)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Flow %d matches", + __func__, __LINE__, flow_info->QosFlowID); + + if ((SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + /* msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Skipping Flow %d as it is marked " + "for release/modify", __func__, + __LINE__, flow_info->QosFlowID); + } else + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_aggregate_params + (&flow_info->QoSInfo, &Tspec_Info, NULL))) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_aggregate_params() failed", + __func__, __LINE__); + } + } + pEntry = pNextEntry; + } + /* return the aggregate */ + *pTspec_Info = Tspec_Info; + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_ac_to_up() - Utiltity function to map an AC to UP + Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs + Mapping is done for consistency + \param ac - Enumeration of the various EDCA Access Categories. + \return an User Priority + + \sa + + --------------------------------------------------------------------------*/ +sme_QosWmmUpType sme_qos_ac_to_up(sme_QosEdcaAcType ac) +{ + sme_QosWmmUpType up = SME_QOS_WMM_UP_MAX; + if (ac >= 0 && ac < SME_QOS_EDCA_AC_MAX) { + up = sme_qos_a_cto_up_map[ac]; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: ac = %d up = %d returned", + __func__, __LINE__, ac, up); + return up; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_up_to_ac() - Utiltity function to map an UP to AC + \param up - Enumeration of the various User priorities (UP). + \return an Access Category + + \sa + + --------------------------------------------------------------------------*/ +sme_QosEdcaAcType sme_qos_up_to_ac(sme_QosWmmUpType up) +{ + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_MAX; + if (up >= 0 && up < SME_QOS_WMM_UP_MAX) { + ac = sme_qos_u_pto_ac_map[up]; + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: up = %d ac = %d returned", + __func__, __LINE__, up, ac); + return ac; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_state_transition() - The state transition function per AC. We + save the previous state also. + \param sessionId - Session upon which the state machine is running + \param ac - Enumeration of the various EDCA Access Categories. + \param new_state - The state FSM is moving to. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +static void sme_qos_state_transition(uint8_t sessionId, + sme_QosEdcaAcType ac, + sme_QosStates new_state) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->prev_state = pACInfo->curr_state; + pACInfo->curr_state = new_state; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d new state=%d, old state=%d, for AC=%d", + __func__, __LINE__, + sessionId, pACInfo->curr_state, pACInfo->prev_state, ac); +} + +/** + * sme_qos_find_in_flow_list() - find a flow entry from the flow list + * @search_key: We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in sme_QosSearchInfo tells which key to use. + * Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Utility function to find an flow entry from the flow_list. + * + * Return: pointer to the list element + */ +tListElem *sme_qos_find_in_flow_list(sme_QosSearchInfo search_key) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, can't search")); + return NULL; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) { + if (search_key.key.QosFlowID == flow_info->QosFlowID) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on flowID, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) { + if (search_key.key.ac_type == flow_info->ac_type) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on ac, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_3) { + if (search_key.key.reason == flow_info->reason) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on reason, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on reason, ending search")); + break; + } + } + list_elt = list_next_elt; + } + return list_elt; +} + +/** + * sme_qos_find_all_in_flow_list() - find a flow entry in the flow list + * @mac_ctx: global MAC context + * @search_key: search key + * @fnp: function pointer specifying the action type for the entry found + * + * Utility function to find an flow entry from the flow_list & act on it. + * search_key - We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in sme_QosSearchInfo tells which key to use. Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Return: None + */ +CDF_STATUS sme_qos_find_all_in_flow_list(tpAniSirGlobal mac_ctx, + sme_QosSearchInfo search_key, + sme_QosProcessSearchEntry fnp) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosSessionInfo *qos_session; + sme_QosFlowInfoEntry *flow_info = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + sme_QosEdcaAcType ac_type; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, can't search")); + return CDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) && + (search_key.key.QosFlowID == flow_info->QosFlowID)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on flowID, ending search")); + status = fnp(mac_ctx, list_elt); + if (CDF_STATUS_E_FAILURE == status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Failed to process entry")); + break; + } + } else if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) && + (search_key.key.ac_type == flow_info->ac_type)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on ac, ending search")); + ac_type = flow_info->ac_type; + flow_info->hoRenewal = + qos_session->ac_info[ac_type].hoRenewal; + status = fnp(mac_ctx, list_elt); + if (CDF_STATUS_E_FAILURE == status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("Failed to process entry")); + break; + } + } + list_elt = list_next_elt; + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_acm() - Utility function to check if a particular AC + mandates Admission Control. + \param ac - Enumeration of the various EDCA Access Categories. + + \return true if the AC mandates Admission Control + + \sa + + --------------------------------------------------------------------------*/ +bool sme_qos_is_acm(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes) +{ + bool ret_val = false; + tDot11fBeaconIEs *pIesLocal; + if (!pSirBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: pSirBssDesc is NULL", __func__, __LINE__); + return false; + } + + if (NULL != pIes) { + /* IEs were provided so use them locally */ + pIesLocal = pIes; + } else { + /* IEs were not provided so parse them ourselves */ + if (!CDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal))) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + return false; + } + + /* if success then pIesLocal was allocated */ + } + + if (CSR_IS_QOS_BSS(pIesLocal)) { + switch (ac) { + case SME_QOS_EDCA_AC_BE: + if (pIesLocal->WMMParams.acbe_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_BK: + if (pIesLocal->WMMParams.acbk_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VI: + if (pIesLocal->WMMParams.acvi_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VO: + if (pIesLocal->WMMParams.acvo_acm) + ret_val = true; + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: unknown AC = %d", + __func__, __LINE__, ac); + /* Assert */ + CDF_ASSERT(0); + break; + } + } /* IS_QOS_BSS */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: ACM = %d for AC = %d", + __func__, __LINE__, ret_val, ac); + if (NULL == pIes) { + /* IEs were allocated locally so free them */ + cdf_mem_free(pIesLocal); + } + return ret_val; +} + +/** + * sme_qos_buffer_existing_flows() - buffer existing flows in flow_list + * @mac_ctx: global MAC context + * @sessionid: session ID + * + * Utility function to buffer the existing flows in flow_list, + * so that we can renew them after handoff is done. + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_qos_buffer_existing_flows(tpAniSirGlobal mac_ctx, + uint8_t sessionid) +{ + tListElem *list_entry = NULL, *list_nextentry = NULL; + sme_QosSessionInfo *qos_session; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosCmdInfo cmd; + sme_qos_setupCmdInfo *setupinfo; + + list_entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_entry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow List empty, nothing to buffer")); + return CDF_STATUS_E_FAILURE; + } + + while (list_entry) { + list_nextentry = csr_ll_next(&sme_qos_cb.flow_list, list_entry, + false); + flow_info = GET_BASE_ADDR(list_entry, sme_QosFlowInfoEntry, + link); + if (flow_info->sessionId != sessionid) { + list_entry = list_nextentry; + continue; + } + + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason)) { + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + setupinfo = &cmd.u.setupCmdInfo; + + setupinfo->HDDcontext = flow_info->HDDcontext; + setupinfo->QoSInfo = flow_info->QoSInfo; + setupinfo->QoSCallback = flow_info->QoSCallback; + /* shouldn't be needed */ + setupinfo->UPType = SME_QOS_WMM_UP_MAX; + setupinfo->QosFlowID = flow_info->QosFlowID; + if (SME_QOS_REASON_SETUP == flow_info->reason) + setupinfo->hoRenewal = false; + else + setupinfo->hoRenewal = true; + + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the setup request" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a setup request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } else if (SME_QOS_REASON_RELEASE == flow_info->reason) { + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID; + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the release req" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a release request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } else if (SME_QOS_REASON_MODIFY_PENDING == + flow_info->reason) { + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.modifyCmdInfo.QosFlowID = flow_info->QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = flow_info->QoSInfo; + if (!CDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the modify req" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a modify request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting original entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, list_entry, true); + cdf_mem_free(flow_info); + + list_entry = list_nextentry; + } + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + qos_session->uapsdAlreadyRequested = false; + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_delete_existing_flows() - Utility function to Delete the existing + flows in flow_list, if we lost connectivity. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static CDF_STATUS sme_qos_delete_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, true); + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "%s: %d: Flow List empty, nothing to delete", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, true); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if (flow_info->sessionId == sessionId) { + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason) || + (SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + NULL, + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + cdf_mem_free(flow_info); + } + pEntry = pNextEntry; + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_buffer_cmd() - buffer a request. + * @pcmd: a pointer to the cmd structure to be saved inside the buffered + * cmd link list + * @insert_head: flag indicate if cmd should be added to the list head. + * + * Utility function to buffer a request (setup/modify/release) from client + * while processing another one on the same AC. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_buffer_cmd(sme_QosCmdInfo *pcmd, bool insert_head) +{ + sme_QosSessionInfo *pSession; + sme_QosCmdInfoEntry *pentry = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked", __func__, __LINE__); + pentry = + (sme_QosCmdInfoEntry *) cdf_mem_malloc(sizeof(sme_QosCmdInfoEntry)); + if (!pentry) { + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Memory allocation failure", + __func__, __LINE__); + return CDF_STATUS_E_NOMEM; + } + /* copy the entire CmdInfo */ + pentry->cmdInfo = *pcmd; + + pSession = &sme_qos_cb.sessionInfo[pcmd->sessionId]; + if (insert_head) { + csr_ll_insert_head(&pSession->bufferedCommandList, &pentry->link, + true); + } else { + csr_ll_insert_tail(&pSession->bufferedCommandList, &pentry->link, + true); + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_buffered_cmd() - process qos buffered request + * @session_id: Session ID + * + * Utility function to process a buffered request (setup/modify/release) + * initially came from the client. + * + * Return:CDF_STATUS + */ +static CDF_STATUS sme_qos_process_buffered_cmd(uint8_t session_id) +{ + sme_QosSessionInfo *qos_session; + sme_QosCmdInfoEntry *pcmd = NULL; + tListElem *list_elt = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + sme_QosCmdInfo *qos_cmd = NULL; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Invoked on session %d"), session_id); + qos_session = &sme_qos_cb.sessionInfo[session_id]; + if (!csr_ll_is_list_empty(&qos_session->bufferedCommandList, false)) { + list_elt = csr_ll_remove_head(&qos_session->bufferedCommandList, + true); + if (!list_elt) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("no more buffered commands on session %d"), + session_id); + qos_session->readyForPowerSave = true; + return CDF_STATUS_E_FAILURE; + } + pcmd = GET_BASE_ADDR(list_elt, sme_QosCmdInfoEntry, link); + qos_cmd = &pcmd->cmdInfo; + switch (qos_cmd->command) { + case SME_QOS_SETUP_REQ: + hdd_status = sme_qos_internal_setup_req( + qos_cmd->pMac, qos_cmd->sessionId, + &qos_cmd->u.setupCmdInfo.QoSInfo, + qos_cmd->u.setupCmdInfo.QoSCallback, + qos_cmd->u.setupCmdInfo.HDDcontext, + qos_cmd->u.setupCmdInfo.UPType, + qos_cmd->u.setupCmdInfo.QosFlowID, + true, qos_cmd->u.setupCmdInfo.hoRenewal); + if (SME_QOS_STATUS_SETUP_FAILURE_RSP == hdd_status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_setup_req failed on session %d"), + session_id); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RELEASE_REQ: + hdd_status = sme_qos_internal_release_req(qos_cmd->pMac, + qos_cmd->u.releaseCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_release_req failed on session %d"), + session_id); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_MODIFY_REQ: + hdd_status = sme_qos_internal_modify_req(qos_cmd->pMac, + &qos_cmd->u.modifyCmdInfo.QoSInfo, + qos_cmd->u.modifyCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_modify_req failed on session %d"), + session_id); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RESEND_REQ: + hdd_status = sme_qos_re_request_add_ts(qos_cmd->pMac, + qos_cmd->sessionId, + &qos_cmd->u.resendCmdInfo.QoSInfo, + qos_cmd->u.resendCmdInfo.ac, + qos_cmd->u.resendCmdInfo.tspecMask); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_re_request_add_ts failed on session %d"), + session_id); + cdf_ret_status = CDF_STATUS_E_FAILURE; + } + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("On session %d unknown cmd = %d"), + session_id, qos_cmd->command); + CDF_ASSERT(0); + break; + } + /* buffered command has been processed, reclaim the memory */ + cdf_mem_free(pcmd); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("cmd buffer empty")); + qos_session->readyForPowerSave = true; + } + return cdf_ret_status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_delete_buffered_requests() - Utility function to Delete the buffered + requests in the buffered_cmd_list, if we lost connectivity. + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static CDF_STATUS sme_qos_delete_buffered_requests(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosCmdInfoEntry *pcmd = NULL; + tListElem *pEntry = NULL, *pNextEntry = NULL; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pEntry = csr_ll_peek_head(&pSession->bufferedCommandList, true); + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN, + "%s: %d: Buffered List empty, nothing to delete on session %d", + __func__, __LINE__, sessionId); + return CDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = + csr_ll_next(&pSession->bufferedCommandList, pEntry, true); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: %d: deleting entry from buffered List", __func__, + __LINE__); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&pSession->bufferedCommandList, pEntry, + true); + /* reclaim the memory */ + pcmd = GET_BASE_ADDR(pEntry, sme_QosCmdInfoEntry, link); + cdf_mem_free(pcmd); + pEntry = pNextEntry; + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_save_assoc_info() - save assoc info. + * @pSession: pointer to QOS session + * @pAssoc_info: pointer to the assoc structure to store the BSS descriptor + * of the AP, the profile that HDD sent down with the + * connect request + * + * Utility function to save the assoc info in the CB like BSS descriptor + * of the AP, the profile that HDD sent down with the connect request, + * while CSR notifies for assoc/reassoc success. + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_qos_save_assoc_info(sme_QosSessionInfo *pSession, + sme_QosAssocInfo *pAssoc_info) +{ + tSirBssDescription *pBssDesc = NULL; + uint32_t bssLen = 0; + if (NULL == pAssoc_info) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: pAssoc_info is NULL", __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + cdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + bssLen = pAssoc_info->pBssDesc->length + + sizeof(pAssoc_info->pBssDesc->length); + /* save the bss Descriptor */ + pBssDesc = (tSirBssDescription *) cdf_mem_malloc(bssLen); + if (!pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the bss Descriptor", + __func__, __LINE__); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_copy(pBssDesc, pAssoc_info->pBssDesc, bssLen); + pSession->assocInfo.pBssDesc = pBssDesc; + /* save the apsd info from assoc */ + if (pAssoc_info->pProfile) { + pSession->apsdMask |= pAssoc_info->pProfile->uapsd_mask; + } + /* [TODO] Do we need to update the global APSD bitmap? */ + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_setup_fnp() - Utility function (pointer) to notify other entries + in FLOW list on the same AC that qos params got modified + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_setup_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + sme_QosEdcaAcType ac; + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, flow_info->QosFlowID); + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_modification_notify_fnp() - Utility function (pointer) to notify + other entries in FLOW list on the same AC that qos params got modified + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_modification_notify_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + sme_QosEdcaAcType ac; + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, flow_info->QosFlowID); + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_modify_fnp() - Utility function (pointer) to delete the origianl + entry in FLOW list & add the modified one + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_modify_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosFlowInfoEntry *flow_info = NULL; + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + switch (flow_info->reason) { + case SME_QOS_REASON_MODIFY_PENDING: + /* set the proper reason code for the new (with modified params) entry */ + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + break; + case SME_QOS_REASON_MODIFY: + /* delete the original entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting original entry at %p with flowID %d", + __func__, __LINE__, flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + cdf_mem_free(flow_info); + break; + default: + break; + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_del_ts_ind_fnp() - Utility function (pointer) to find all Flows on + the perticular AC & delete them, also send HDD indication through the callback + it registered per request + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_del_ts_ind_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosEdcaAcType ac; + CDF_STATUS lock_status = CDF_STATUS_E_FAILURE; + sme_QosStatusType status; + + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + /* delete the entry from Flow List */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->relTrig = SME_QOS_RELEASE_BY_AP; + + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!CDF_IS_STATUS_SUCCESS(lock_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + /* Call the internal function for QoS release, adding a layer of abstraction */ + status = + sme_qos_internal_release_req(pMac, flow_info->QosFlowID, false); + sme_release_global_lock(&pMac->sme); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, flow_info->QosFlowID, status); + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_reassoc_success_ev_fnp Notification function to HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list + * + * Utility function (pointer) to notify HDD + * the success for the requested flow & notify all the other flows + * running on the same AC that QoS params got modified + * + * Return: CDF_STATUS enumaration + */ +CDF_STATUS +sme_qos_reassoc_success_ev_fnp(tpAniSirGlobal mac_ctx, + tListElem *entry) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosFlowInfoEntry *flow_info = NULL; + bool delete_entry = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + CDF_STATUS pmc_status = CDF_STATUS_E_FAILURE; + if (!entry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + /* -Check for the case where we had to do reassoc to + * reset the apsd bit for the ac - release or modify + * scenario.Notify PMC as App is looking for APSD + * If we already requested then we don't need to + * do anything.*/ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state */ + if (CDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (CDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[SME_QOS_TSPEC_INDEX_0]--; + /* fall through */ + case SME_QOS_REASON_MODIFY: + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & + * later to UAPSD state */ + if (CDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (CDF_STATUS_PMC_PENDING == pmc_status) { + qos_session->uapsdAlreadyRequested = + true; + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + /* fall through */ + default: + delete_entry = false; + break; + } + if (!delete_entry) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(mac_ctx, flow_info->HDDcontext, + &ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + hdd_status, flow_info->QosFlowID); + } else { + flow_info->hoRenewal = false; + } + } else { + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + cdf_mem_free(flow_info); + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_add_ts_failure_fnp() - Utility function (pointer), + if the Addts request was for for an flow setup request, delete the entry from + Flow list & notify HDD + if the Addts request was for downgrading of QoS params because of an flow + release requested on the AC, delete the entry from Flow list & notify HDD + if the Addts request was for change of QoS params because of an flow + modification requested on the AC, delete the new entry from Flow list & notify + HDD + + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return CDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +CDF_STATUS sme_qos_add_ts_failure_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + bool inform_hdd = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_RELEASE: + hdd_status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY: + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + case SME_QOS_REASON_REQ_SUCCESS: + default: + inform_hdd = false; + break; + } + if (inform_hdd) { + /* notify HDD, only the requested Flow, other Flows running on the AC stay */ + /* intact */ + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + cdf_mem_free(flow_info); + } + return CDF_STATUS_SUCCESS; +} + +/** + * sme_qos_add_ts_success_fnp() - Utility function (pointer) to notify HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list(i.e. tListElem structure). + * + * Description : Utility function (pointer), + * If the Addts request was for for an flow setup request, notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * if the Addts request was for downgrading of QoS params + * because of an flow release requested on the AC, delete + * the entry from Flow list & notify HDD if the Addts request + * was for change of QoS params because of an flow modification + * requested on the AC, delete the old entry from Flow list & notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * + * Return: Status + */ + +CDF_STATUS sme_qos_add_ts_success_fnp(tpAniSirGlobal mac_ctx, + tListElem *entry) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosFlowInfoEntry *flow_info = NULL; + bool inform_hdd = false; + bool delete_entry = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + CDF_STATUS pmc_status = CDF_STATUS_E_FAILURE; + tCsrRoamModifyProfileFields profile_fields; + uint8_t psb; + uint8_t tspec_index; + + if (!entry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Entry is NULL")); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + tspec_index = ac_info->tspec_pending - 1; + if (flow_info->tspec_mask != ac_info->tspec_pending) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL(" No need to notify the HDD, the ADDTS " + "success is not for index = %d of the AC = %d"), + flow_info->tspec_mask, ac); + return CDF_STATUS_SUCCESS; + } + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + delete_entry = false; + inform_hdd = true; + /* check if App is looking for APSD + * notify PMC as App is looking for APSD. If we already + * requested then we don't need to do anything */ + if (ac_info->requested_QoSInfo[tspec_index].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state */ + if (CDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (CDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + } + /* for any other pmc status we declare success */ + } + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[tspec_index]--; + hdd_status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + inform_hdd = true; + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY: + delete_entry = true; + inform_hdd = false; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + inform_hdd = true; + psb = ac_info->requested_QoSInfo[tspec_index].ts_info.psb; + /* notify PMC if App is looking for APSD + * notify PMC as App is looking for APSD. If we already + * requested then we don't need to do anything. */ + if (psb && !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect + * we need PMC in UAPSD mode */ + pmc_status = + sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right + * away means it is yet to put + * the module in BMPS state & later to UAPSD state */ + if (CDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (CDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + } + /* for any other pmc status we declare success */ + } else if (!psb && + ((ac_info->num_flows[flow_info->tspec_mask - 1] == 1) + && (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + ac_info->tspec_mask_status))) { + /* this is the only TSPEC active on this AC */ + /* so indicate that we no longer require APSD */ + qos_session->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + /* Also update modifyProfileFields.uapsd_mask + * in CSR for consistency */ + csr_get_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + profile_fields.uapsd_mask = + qos_session->apsdMask; + csr_set_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + if (!qos_session->apsdMask) { + sme_ps_uapsd_disable(mac_ctx, + flow_info->sessionId); + } + } + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + inform_hdd = true; + default: + delete_entry = false; + break; + } + if (inform_hdd) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(mac_ctx, flow_info->HDDcontext, + &ac_info->curr_QoSInfo[tspec_index], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->hoRenewal = false; + } + } + if (delete_entry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + cdf_mem_free(flow_info); + } + return CDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_rsp_pending() - Utility function to check if we are waiting + for an AddTS or reassoc response on some AC other than the given AC + + \param sessionId - Session we are interted in + \param ac - Enumeration of the various EDCA Access Categories. + + \return bool + true - Response is pending on an AC + + \sa + + --------------------------------------------------------------------------*/ +static bool sme_qos_is_rsp_pending(uint8_t sessionId, sme_QosEdcaAcType ac) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType acIndex; + bool status = false; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (acIndex = SME_QOS_EDCA_AC_BE; acIndex < SME_QOS_EDCA_AC_MAX; + acIndex++) { + if (acIndex == ac) { + continue; + } + pACInfo = &pSession->ac_info[acIndex]; + if ((pACInfo->tspec_pending) || (pACInfo->reassoc_pending)) { + status = true; + break; + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_update_hand_off() - Function which can be called to update + Hand-off state of SME QoS Session + \param sessionId - session id + \param updateHandOff - value True/False to update the handoff flag + + \sa + + -------------------------------------------------------------------------*/ +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff) +{ + sme_QosSessionInfo *pSession; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_MED, + "%s: %d: handoffRequested %d updateHandOff %d", + __func__, __LINE__, pSession->handoffRequested, + updateHandOff); + + pSession->handoffRequested = updateHandOff; + +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_uapsd_active() - Function which can be called to determine + if any sessions require PMC to be in U-APSD mode. + \return bool + + Returns true if at least one session required PMC to be in U-APSD mode + Returns false if no sessions require PMC to be in U-APSD mode + + \sa + + --------------------------------------------------------------------------*/ +static bool sme_qos_is_uapsd_active(void) +{ + sme_QosSessionInfo *pSession; + uint8_t sessionId; + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if ((pSession->sessionActive) && (pSession->apsdMask)) { + return true; + } + } + /* no active sessions have U-APSD active */ + return false; +} + +/*-------------------------------------------------------------------------- + \brief sme_QosPmcStartUAPSDCallback() - Callback function registered with PMC + to notify SME-QoS when it puts the chip into UAPSD mode + + \param callbackContext - The context passed to PMC during pmc_start_uapsd call. + \param status - CDF_STATUS returned by PMC. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +void sme_qos_pmc_offload_start_uapsd_callback(void *callbackContext, + uint32_t sessionId, CDF_STATUS status) +{ + sme_QosSessionInfo *pSession = callbackContext; + pSession->uapsdAlreadyRequested = false; +} + +bool sme_qos_pmc_offload_check_routine(void *callbackContext, uint32_t sessionId) +{ + sme_QosSessionInfo *pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if ((pSession->sessionActive) && (!pSession->readyForPowerSave)) { + return false; + } + return true; + +} + + +CDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sme_QosSessionInfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup UAPSD */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS sme_offload_qos_process_into_uapsd_mode(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sme_QosSessionInfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + return CDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup UAPSD */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return CDF_STATUS_SUCCESS; +} + +void sme_qos_cleanup_ctrl_blk_for_handoff(tpAniSirGlobal pMac, uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + cdf_mem_zero(pACInfo->curr_QoSInfo, + sizeof(sme_QosWmmTspecInfo) * + SME_QOS_TSPEC_INDEX_MAX); + cdf_mem_zero(pACInfo->requested_QoSInfo, + sizeof(sme_QosWmmTspecInfo) * + SME_QOS_TSPEC_INDEX_MAX); + pACInfo->num_flows[0] = 0; + pACInfo->num_flows[1] = 0; + pACInfo->reassoc_pending = false; + pACInfo->tspec_mask_status = 0; + pACInfo->tspec_pending = false; + pACInfo->hoRenewal = false; + pACInfo->prev_state = SME_QOS_LINK_UP; + } +} + +/** + * sme_qos_is_ts_info_ack_policy_valid() - check if ACK policy is allowed. + * @pMac: The handle returned by mac_open. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * @ related info, provided by HDD + * @sessionId: sessionId returned by sme_open_session. + * + * The SME QoS API exposed to HDD to check if TS info ack policy field can be + * set to "HT-immediate block acknowledgement" + * + * Return: true - Current Association is HT association and so TS info ack + * policy can be set to "HT-immediate block acknowledgement" + */ +bool sme_qos_is_ts_info_ack_policy_valid(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId) +{ + tDot11fBeaconIEs *pIes = NULL; + sme_QosSessionInfo *pSession; + CDF_STATUS hstatus; + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return false; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (!pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return false; + } + + if (!pSession->assocInfo.pBssDesc) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return false; + } + + hstatus = csr_get_parsed_bss_description_ies(pMac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!CDF_IS_STATUS_SUCCESS(hstatus)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, sessionId); + return false; + } + + /* success means pIes was allocated */ + + if (!pIes->HTCaps.present && + pQoSInfo->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d HT Caps aren't present but application set ack policy to HT ", + __func__, __LINE__, sessionId); + + cdf_mem_free(pIes); + return false; + } + + cdf_mem_free(pIes); + return true; +} + +bool sme_qos_validate_requested_params(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId) +{ + bool rc = false; + + do { + if (SME_QOS_WMM_TS_DIR_RESV == pQoSInfo->ts_info.direction) + break; + if (!sme_qos_is_ts_info_ack_policy_valid(pMac, pQoSInfo, sessionId)) + break; + + rc = true; + } while (0); + return rc; +} + +static CDF_STATUS qos_issue_command(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + CDF_STATUS status = CDF_STATUS_E_RESOURCES; + tSmeCmd *pCommand = NULL; + do { + pCommand = sme_get_command_buffer(pMac); + if (!pCommand) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: fail to get command buffer for command %d", + __func__, __LINE__, cmdType); + break; + } + pCommand->command = cmdType; + pCommand->sessionId = sessionId; + switch (cmdType) { + case eSmeCommandAddTs: + if (pQoSInfo) { + status = CDF_STATUS_SUCCESS; + pCommand->u.qosCmd.tspecInfo = *pQoSInfo; + pCommand->u.qosCmd.ac = ac; + } else { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + "%s: %d: NULL pointer passed", + __func__, __LINE__); + status = CDF_STATUS_E_INVAL; + } + break; + case eSmeCommandDelTs: + status = CDF_STATUS_SUCCESS; + pCommand->u.qosCmd.ac = ac; + pCommand->u.qosCmd.tspec_mask = tspec_mask; + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, cmdType); + status = CDF_STATUS_E_INVAL; + break; + } + } while (0); + if (CDF_IS_STATUS_SUCCESS(status) && pCommand) { + sme_push_command(pMac, pCommand, false); + } else if (pCommand) { + qos_release_command(pMac, pCommand); + } + return status; +} + +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + bool fRemoveCmd = true; + do { + switch (pCommand->command) { + case eSmeCommandAddTs: + status = + sme_qos_add_ts_req(pMac, (uint8_t) pCommand->sessionId, + &pCommand->u.qosCmd.tspecInfo, + pCommand->u.qosCmd.ac); + if (CDF_IS_STATUS_SUCCESS(status)) { + fRemoveCmd = false; + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + } + break; + case eSmeCommandDelTs: + status = + sme_qos_del_ts_req(pMac, (uint8_t) pCommand->sessionId, + pCommand->u.qosCmd.ac, + pCommand->u.qosCmd.tspec_mask); + if (CDF_IS_STATUS_SUCCESS(status)) { + fRemoveCmd = false; + } + break; + default: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, pCommand->command); + break; + } /* switch */ + } while (0); + return fRemoveCmd; +} + +/** + * sme_qos_re_request_add_ts - Re-send AddTS for the combined QoS request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * @qos_info - Tspec information + * @ac - Access category + * @tspec_mask - Tspec Mask + * + * This function is called to re-send AddTS for the combined QoS request + * + * Return: status + */ +static +sme_QosStatusType sme_qos_re_request_add_ts(tpAniSirGlobal mac_ctx, + uint8_t session_id, sme_QosWmmTspecInfo *qos_info, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + sme_QosCmdInfo cmd; + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL(" Invoked on session %d for AC %d TSPEC %d"), + session_id, ac, tspec_mask); + session = &sme_qos_cb.sessionInfo[session_id]; + ac_info = &session->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + session->readyForPowerSave = false; + /* + * call PMC's request for power function + * AND another check is added considering the flowing scenario + * Addts reqest is pending on one AC, while APSD requested on + * another which needs a reassoc. Will buffer a request if Addts + * is pending on any AC, which will safegaurd the above scenario, + * 2& also won't confuse PE with back to back Addts or Addts + * followed by Reassoc. + */ + if (sme_qos_is_rsp_pending(session_id, ac)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL(" On session %d buffering the AddTS request " + "for AC %d in state %d as Addts is pending " + "on other AC or waiting for full power"), + session_id, ac, + ac_info->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_RESEND_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!CDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + CDF_TRACE(CDF_MODULE_ID_SME, + CDF_TRACE_LEVEL_ERROR, + FL("On session %d unable to buffer the AddTS " + "request for AC %d TSPEC %d in state %d"), + session_id, ac, tspec_mask, + ac_info->curr_state); + /* unable to buffer the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + + /* get into the stat m/c to see if the request can be granted */ + switch (ac_info->curr_state) { + case SME_QOS_QOS_ON: + { + /* if ACM, send out a new ADDTS */ + ac_info->hoRenewal = true; + status = sme_qos_setup(mac_ctx, session_id, qos_info, ac); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("sme_qos_setup returned in SME_QOS_QOS_ON state")); + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL("sme_qos_setup AC %d with status =%d"), ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + session->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + ac_info->tspec_pending = tspec_mask; + } else if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING == + status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("UAPSD is setup already status = %d "), + status); + } else { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_qos_setup return status = %d "), + status); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Re-Add request in state = %d buffer the request"), + ac_info->curr_state); + cmd.command = SME_QOS_RESEND_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!CDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL(" couldn't buf the read request state = %d"), + ac_info->curr_state); + /* unable to buffer the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg, */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("ReAdd request in unexpected state = %d"), + ac_info->curr_state); + /* unable to service the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + (void)sme_qos_process_buffered_cmd(session_id); + } + return status; +} + +static void sme_qos_init_a_cs(tpAniSirGlobal pMac, uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + cdf_mem_zero(&pSession->ac_info[ac], sizeof(sme_QosACInfo)); + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + } +} + +static CDF_STATUS sme_qos_request_reassoc(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + CDF_STATUS status; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with UAPSD mask 0x%X", + __func__, __LINE__, sessionId, pModFields->uapsd_mask); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + status = + csr_reassoc(pMac, sessionId, pModFields, &pSession->roamID, fForce); + if (CDF_IS_STATUS_SUCCESS(status)) { + /* Update the state to Handoff so subsequent requests are queued until */ + /* this one is finished */ + sme_QosEdcaAcType ac; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO, + "%s: %d: AC[%d] is in state [%d]", + __func__, __LINE__, ac, pACInfo->curr_state); + /* If it is already in HANDOFF state, don't do anything since we */ + /* MUST preserve the previous state and sme_qos_state_transition */ + /* will change the previous state */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) { + sme_qos_state_transition(sessionId, ac, + SME_QOS_HANDOFF); + } + } + } + return status; +} + +static uint32_t sme_qos_assign_flow_id(void) +{ + uint32_t flowId; + flowId = sme_qos_cb.nextFlowId; + if (SME_QOS_MAX_FLOW_ID == flowId) { + /* The Flow ID wrapped. This is obviously not a real life scenario */ + /* but handle it to keep the software test folks happy */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + "%s: %d: Software Test made the flow counter wrap, " + "QoS may no longer be functional", + __func__, __LINE__); + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + } else { + sme_qos_cb.nextFlowId++; + } + return flowId; +} + +static uint8_t sme_qos_assign_dialog_token(void) +{ + uint8_t token; + token = sme_qos_cb.nextDialogToken; + if (SME_QOS_MAX_DIALOG_TOKEN == token) { + /* wrap is ok */ + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + } else { + sme_qos_cb.nextDialogToken++; + } + return token; +} + +/** + * sme_qos_tspec_active() - API exposed to HDD to check no of active Tspecs + * + * @pMac: The handle returned by macOpen + * @ac: Determines type of Access Category + * @sessionId: sessionId returned by sme_OpenSession + * @pActiveTspec: return the number of active Tspecs + * + * Return: true if success, otherwise false + */ +bool sme_qos_tspec_active(tpAniSirGlobal pMac, sme_ac_enum_type ac, + uint8_t sessionId, uint8_t *pActiveTspec) +{ + sme_QosSessionInfo *pSession = NULL; + sme_QosACInfo *pACInfo = NULL; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return false; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (NULL == pSession) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d pSession not found sessionId:%d", + __func__, __LINE__, sessionId); + return false; + } + + if (!pSession->sessionActive) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return false; + } + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Session %d is active", + __func__, __LINE__, sessionId); + + pACInfo = &pSession->ac_info[ac]; + + /* Does this AC have QoS active? */ + if (SME_QOS_QOS_ON == pACInfo->curr_state) { + /* Yes, QoS is active on this AC */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AC %d has QoS active", + __func__, __LINE__, sessionId, ac); + + /* Are any TSPECs active? */ + if (pACInfo->tspec_mask_status) { + /* at least 1 TSPEC is active. Are they both active? */ + if (SME_QOS_TSPEC_MASK_BIT_1_2_SET == + pACInfo->tspec_mask_status) { + /* both TSPECS are active */ + *pActiveTspec = 2; + } else { + /* only one TSPEC is active */ + *pActiveTspec = 1; + } + } else { + *pActiveTspec = 0; + } + } else { + /* Hardcoding value to INVALID_TSPEC to indicate the caller + * not to update UAPSD parameters as QOS is not active + */ + *pActiveTspec = INVALID_TSPEC; + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AC %d has no QoS active", + __func__, __LINE__, sessionId, ac); + } + + return true; +} + +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ diff --git a/core/sme/src/rrm/sme_rrm.c b/core/sme/src/rrm/sme_rrm.c new file mode 100644 index 0000000000..a68f71c09d --- /dev/null +++ b/core/sme/src/rrm/sme_rrm.c @@ -0,0 +1,1566 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file sme_Rrm.c + + \brief implementation for SME RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#if defined WLAN_FEATURE_VOWIFI +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "sme_inside.h" +#include "sme_api.h" +#include "sms_debug.h" +#include "cfg_api.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "csr_inside_api.h" + +#include "rrm_global.h" + + +/* Roam score for a neighbor AP will be calculated based on the below definitions. + The calculated roam score will be used to select the roamable candidate from neighbor AP list */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY 0 /* When we support 11r over the DS, this should have a non-zero value */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY 10 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE 20 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT 0 /* Not used */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS 5 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM 8 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA 0 /* We dont support delayed BA */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN 30 + +#ifdef FEATURE_WLAN_ESE +#define RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST 30 +#endif + +v_TIME_t rrm_scan_timer; + +/** + * rrm_ll_purge_neighbor_cache() -Purges all the entries in the neighbor cache + * + * @pMac: Pointer to the Hal Handle. + * @pList: Pointer the List that should be purged. + * + * This function purges all the entries in the neighbor cache and frees up all + * the internal nodes + * + * Return: void + */ +static void rrm_ll_purge_neighbor_cache(tpAniSirGlobal pMac, + tDblLinkList *pList) +{ + tListElem *pEntry; + tRrmNeighborReportDesc *pNeighborReportDesc; + csr_ll_lock(pList); + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pNeighborReportDesc = + GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + cdf_mem_free(pNeighborReportDesc->pNeighborBssDescription); + cdf_mem_free(pNeighborReportDesc); + } + csr_ll_unlock(pList); + return; +} + +/** + * rrm_indicate_neighbor_report_result() -calls the callback registered for + * neighbor report + * @pMac: Pointer to the Hal Handle. + * @cdf_status - CDF_STATUS_SUCCESS/CDF_STATUS_FAILURE based on whether a valid + * report is received or neighbor timer expired + * + * This function calls the callback register by the caller while requesting for + * neighbor report. This function gets invoked if a neighbor report is received + * from an AP or neighbor response wait timer expires. + * + * Return: void + */ +void rrm_indicate_neighbor_report_result(tpAniSirGlobal pMac, CDF_STATUS cdf_status) +{ + NeighborReportRspCallback callback; + void *callbackContext; + + /* Reset the neighbor response pending status */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = + false; + + /* Stop the timer if it is already running. The timer should be running only in the SUCCESS case. */ + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo. + neighborRspWaitTimer)) { + sms_log(pMac, LOG1, FL("No entry in neighbor report cache")); + cdf_mc_timer_stop(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo.neighborRspWaitTimer); + } + callback = + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback; + callbackContext = + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallbackContext; + + /* Reset the callback and the callback context before calling the callback. It is very likely that there may be a registration in + callback itself. */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = NULL; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallbackContext = NULL; + + /* Call the callback with the status received from caller */ + if (callback) + callback(callbackContext, cdf_status); + + return; + +} + +/** + * sme_RrmBeaconReportXmitInd () - Send beacon report + * @mac_ctx Pointer to mac context + * @result_arr scan results + * @msrmnt_status flag to indicate that the measurement is done. + * @bss_count bss count + * + * Create and send the beacon report Xmit ind message to PE. + * + * Return: status + */ + +static CDF_STATUS +sme_rrm_send_beacon_report_xmit_ind(tpAniSirGlobal mac_ctx, + tCsrScanResultInfo **result_arr, uint8_t msrmnt_status, + uint8_t bss_count) +{ + tpSirBssDescription bss_desc = NULL; + tpSirBeaconReportXmitInd beacon_rep; + uint16_t length, ie_len; + uint8_t i = 0, j = 0; + tCsrScanResultInfo *cur_result = NULL; + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to PE"); +#endif + + if (NULL == result_arr && !msrmnt_status) { + sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to PE Failed"); + return CDF_STATUS_E_FAILURE; + } + + if (result_arr) + cur_result = result_arr[j]; + + do { + length = sizeof(tSirBeaconReportXmitInd); + beacon_rep = cdf_mem_malloc(length); + if (NULL == beacon_rep) { + sms_log(mac_ctx, LOGP, + "Unable to allocate memory for beacon report"); + return CDF_STATUS_E_NOMEM; + } + cdf_mem_zero(beacon_rep, length); +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Allocated memory for beacon_rep")); +#endif + beacon_rep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND; + beacon_rep->length = length; + beacon_rep->uDialogToken = rrm_ctx->token; + beacon_rep->duration = rrm_ctx->duration[0]; + beacon_rep->regClass = rrm_ctx->regClass; + cdf_mem_copy(beacon_rep->bssId, rrm_ctx->sessionBssId.bytes, + CDF_MAC_ADDR_SIZE); + + i = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (bss_desc == NULL) + break; + ie_len = GET_IE_LEN_IN_BSS(bss_desc->length); + beacon_rep->pBssDescription[i] = + cdf_mem_malloc(ie_len + + sizeof(tSirBssDescription)); + if (NULL == + beacon_rep->pBssDescription[i]) + break; + cdf_mem_copy(beacon_rep->pBssDescription[i], + bss_desc, sizeof(tSirBssDescription)); + cdf_mem_copy( + &beacon_rep->pBssDescription[i]->ieFields[0], + bss_desc->ieFields, ie_len); + sms_log(mac_ctx, LOG1, + ".RRM Result Bssid = " MAC_ADDRESS_STR + " chan= %d, rssi = -%d", + MAC_ADDR_ARRAY( + beacon_rep->pBssDescription[i]->bssId), + beacon_rep->pBssDescription[i]->channelId, + beacon_rep->pBssDescription[i]->rssi * (-1)); + beacon_rep->numBssDesc++; + if (++i >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + cur_result = + result_arr[j + i]; + } + + j += i; + if (!result_arr || (cur_result == NULL) + || (j >= bss_count)) { + cur_result = NULL; + sms_log(mac_ctx, LOG1, + "Reached to max/last BSS in cur_result list"); + } else { + cur_result = result_arr[j]; + sms_log(mac_ctx, LOG1, + "Move to the next BSS set in cur_result list"); + } + beacon_rep->fMeasureDone = + (cur_result) ? false : msrmnt_status; + sms_log(mac_ctx, LOG1, + "SME Sending BcnRepXmit to PE numBss %d i %d j %d", + beacon_rep->numBssDesc, i, j); + status = cds_send_mb_message_to_mac(beacon_rep); + } while (cur_result); + + return status; +} + +#if defined(FEATURE_WLAN_ESE_UPLOAD) +/** + * sme_ese_send_beacon_req_scan_results () - Send beacon report + * @mac_ctx Pointer to mac context + * @session_id - session id + * @result_arr scan results + * @msrmnt_status flag to indicate that the measurement is done. + * @bss_count number of bss found + * + * This function sends up the scan results received as a part of + * beacon request scanning. + * This function is called after receiving the scan results per channel + * Due to the limitation on the size of the IWEVCUSTOM buffer, we send + * 3 BSSIDs of beacon report information in one custom event; + * + * Return: status + */ +static CDF_STATUS sme_ese_send_beacon_req_scan_results( + tpAniSirGlobal mac_ctx, uint32_t session_id, + uint8_t channel, tCsrScanResultInfo **result_arr, + uint8_t msrmnt_status, uint8_t bss_count) +{ + CDF_STATUS status = CDF_STATUS_E_FAILURE; + tSirRetStatus fill_ie_status; + tpSirBssDescription bss_desc = NULL; + uint32_t ie_len = 0; + uint32_t out_ie_len = 0; + uint8_t bss_counter = 0; + tCsrScanResultInfo *cur_result = NULL; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + tCsrRoamInfo roam_info; + tSirEseBcnReportRsp bcn_rpt_rsp; + tpSirEseBcnReportRsp bcn_report = &bcn_rpt_rsp; + tpCsrEseBeaconReqParams cur_meas_req = NULL; + uint8_t i = 0, j = 0; + tBcnReportFields *bcn_rpt_fields; + + if (NULL == rrm_ctx) { + sms_log(mac_ctx, LOGE, "rrm_ctx is NULL"); + return CDF_STATUS_E_FAILURE; + } + + if (NULL == result_arr && !msrmnt_status) { + sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to HDD Failed"); + return CDF_STATUS_E_FAILURE; + } + + if (result_arr) + cur_result = result_arr[bss_counter]; + + cdf_mem_zero(&bcn_rpt_rsp, sizeof(tSirEseBcnReportRsp)); + do { + cur_meas_req = NULL; + for (i = 0; i < rrm_ctx->eseBcnReqInfo.numBcnReqIe; i++) { + if (rrm_ctx->eseBcnReqInfo.bcnReq[i].channel == + channel) { + cur_meas_req = + &rrm_ctx->eseBcnReqInfo.bcnReq[i]; + break; + } + } + if (NULL != cur_meas_req) + bcn_report->measurementToken = + cur_meas_req->measurementToken; + sms_log(mac_ctx, LOG1, "Channel(%d) MeasToken(%d)", channel, + bcn_report->measurementToken); + + j = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (NULL == bss_desc) { + cur_result = NULL; + break; + } + ie_len = GET_IE_LEN_IN_BSS(bss_desc->length); + bcn_rpt_fields = + &bcn_report->bcnRepBssInfo[j].bcnReportFields; + bcn_rpt_fields->ChanNum = + bss_desc->channelId; + bcn_report->bcnRepBssInfo[j].bcnReportFields.Spare = 0; + if (NULL != cur_meas_req) + bcn_rpt_fields->MeasDuration = + cur_meas_req->measurementDuration; + bcn_rpt_fields->PhyType = bss_desc->nwType; + bcn_rpt_fields->RecvSigPower = bss_desc->rssi; + bcn_rpt_fields->ParentTsf = bss_desc->parentTSF; + bcn_rpt_fields->TargetTsf[0] = bss_desc->timeStamp[0]; + bcn_rpt_fields->TargetTsf[1] = bss_desc->timeStamp[1]; + bcn_rpt_fields->BcnInterval = bss_desc->beaconInterval; + bcn_rpt_fields->CapabilityInfo = + bss_desc->capabilityInfo; + + cdf_mem_copy(bcn_rpt_fields->Bssid, + bss_desc->bssId, sizeof(tSirMacAddr)); + fill_ie_status = + sir_beacon_ie_ese_bcn_report(mac_ctx, + (uint8_t *) bss_desc->ieFields, + ie_len, + &(bcn_report->bcnRepBssInfo[j].pBuf), + &out_ie_len); + if (eSIR_FAILURE == fill_ie_status) + continue; + bcn_report->bcnRepBssInfo[j].ieLen = out_ie_len; + + sms_log(mac_ctx, LOG1, "Bssid(" MAC_ADDRESS_STR")" + "Channel=%d Rssi=%d", + MAC_ADDR_ARRAY(bss_desc->bssId), + bss_desc->channelId, (-1) * bss_desc->rssi); + bcn_report->numBss++; + if (++j >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + cur_result = result_arr[j]; + } + + bss_counter += j; + if (!result_arr || !cur_result + || (bss_counter >= SIR_BCN_REPORT_MAX_BSS_DESC)) { + cur_result = NULL; + sms_log(mac_ctx, LOGE, + "Reached to the max/last BSS in cur_result list"); + } else { + cur_result = result_arr[bss_counter]; + sms_log(mac_ctx, LOGE, + "Move to the next BSS set in cur_result list"); + } + + bcn_report->flag = + (msrmnt_status << 1) | ((cur_result) ? true : false); + + sms_log(mac_ctx, LOG1, "SME Sending BcnRep to HDD numBss(%d)" + " j(%d) bss_counter(%d) flag(%d)", + bcn_report->numBss, j, bss_counter, + bcn_report->flag); + + roam_info.pEseBcnReportRsp = bcn_report; + status = csr_roam_call_callback(mac_ctx, session_id, &roam_info, + 0, eCSR_ROAM_ESE_BCN_REPORT_IND, 0); + + /* Free the memory allocated to IE */ + for (i = 0; i < j; i++) + if (bcn_report->bcnRepBssInfo[i].pBuf) + cdf_mem_free(bcn_report->bcnRepBssInfo[i].pBuf); + } while (cur_result); + return status; +} + +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + +/** + * sme_rrm_send_scan_result() - to get scan result and send the beacon report + * @mac_ctx: pointer to mac context + * @num_chan: number of channels + * @chan_list: list of channels to fetch the result from + * @measurementdone: Flag to indicate measurement done or no + * + * This function is called to get the scan result from CSR and send the beacon + * report xmit ind message to PE + * + * Return: CDF_STATUS + */ +static CDF_STATUS sme_rrm_send_scan_result(tpAniSirGlobal mac_ctx, + uint8_t num_chan, + uint8_t *chan_list, + uint8_t measurementdone) +{ + tCsrScanResultFilter filter; + tScanResultHandle result_handle; + tCsrScanResultInfo *scan_results, *next_result; + tCsrScanResultInfo *scanresults_arr[SIR_BCN_REPORT_MAX_BSS_DESC]; + CDF_STATUS status; + uint8_t counter = 0; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Send scan result to PE ")); +#endif + + cdf_mem_zero(&filter, sizeof(filter)); + cdf_mem_zero(scanresults_arr, + sizeof(next_result) * SIR_BCN_REPORT_MAX_BSS_DESC); + filter.BSSIDs.numOfBSSIDs = 1; + filter.BSSIDs.bssid = (struct cdf_mac_addr *)&rrm_ctx->bssId; + + if (rrm_ctx->ssId.length) { + filter.SSIDs.SSIDList = + (tCsrSSIDInfo *) cdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (filter.SSIDs.SSIDList == NULL) { + sms_log(mac_ctx, LOGP, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Allocated memory for SSIDList")); +#endif + cdf_mem_zero(filter.SSIDs.SSIDList, sizeof(tCsrSSIDInfo)); + + filter.SSIDs.SSIDList->SSID.length = + rrm_ctx->ssId.length; + cdf_mem_copy(filter.SSIDs.SSIDList->SSID.ssId, + rrm_ctx->ssId.ssId, rrm_ctx->ssId.length); + filter.SSIDs.numOfSSIDs = 1; + } else { + filter.SSIDs.numOfSSIDs = 0; + } + + filter.ChannelInfo.numOfChannels = num_chan; + filter.ChannelInfo.ChannelList = chan_list; + filter.fMeasurement = true; + + /* + * In case this is beacon report request from last AP (before roaming) + * following call to csr_roam_get_session_id_from_bssid will fail, + * hence use current session ID instead of one stored in SME rrm context + */ + if (CDF_STATUS_E_FAILURE == csr_roam_get_session_id_from_bssid(mac_ctx, + &rrm_ctx->sessionBssId, &session_id)) { + sms_log(mac_ctx, LOG1, + FL("BSSID mismatch, using current session_id")); + session_id = mac_ctx->roam.roamSession->sessionId; + } + status = sme_scan_get_result(mac_ctx, (uint8_t) session_id, + &filter, &result_handle); + + if (filter.SSIDs.SSIDList) { + /* Free the memory allocated for SSIDList */ + cdf_mem_free(filter.SSIDs.SSIDList); +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Free memory for SSIDList")); +#endif + } + + if (NULL == result_handle) { + /* + * no scan results + * Spec. doesnt say anything about such condition + * Since section 7.4.6.2 (IEEE802.11k-2008) says-rrm report + * frame should contain one or more report IEs. It probably + * means dont send any respose if no matching BSS found. + * Moreover, there is no flag or field in measurement report + * IE(7.3.2.22) OR beacon report IE(7.3.2.22.6) that can be set + * to indicate no BSS found on a given channel. If we finished + * measurement on all the channels, we still need to send a + * xmit indication with moreToFollow set to MEASURMENT_DONE so + * that PE can clean any context allocated. + */ + if (!measurementdone) + return status; +#if defined(FEATURE_WLAN_ESE_UPLOAD) + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, chan_list[0], + NULL, measurementdone, 0); + else +#endif /*FEATURE_WLAN_ESE_UPLOAD */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + NULL, measurementdone, 0); + return status; + } + scan_results = sme_scan_result_get_first(mac_ctx, result_handle); + if (NULL == scan_results && measurementdone) { +#if defined(FEATURE_WLAN_ESE_UPLOAD) + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) { + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, + chan_list[0], + NULL, + measurementdone, + 0); + } else +#endif /*FEATURE_WLAN_ESE_UPLOAD */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + NULL, measurementdone, 0); + } + counter = 0; + while (scan_results) { + next_result = sme_scan_result_get_next(mac_ctx, result_handle); + if (scan_results->timer >= rrm_scan_timer) + scanresults_arr[counter++] = scan_results; + scan_results = next_result; + if (counter >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + } + if (counter) { + sms_log(mac_ctx, LOG1, + FL(" Number of BSS Desc with RRM Scan %d "), + counter); +#if defined(FEATURE_WLAN_ESE_UPLOAD) + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, chan_list[0], + scanresults_arr, measurementdone, + counter); + else +#endif /*FEATURE_WLAN_ESE_UPLOAD */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + scanresults_arr, measurementdone, + counter); + } + sme_scan_result_purge(mac_ctx, result_handle); + return status; +} + +/** + * sme_rrm_scan_request_callback() -Sends the beacon report xmit to PE + * @halHandle - Pointer to the Hal Handle. + * @pContext - Pointer to the data context. + * @scanId - Scan ID. + * @status - CSR Status. + * + * The sme module calls this callback function once it finish the scan request + * and this function send the beacon report xmit to PE and starts a timer of + * random interval to issue next request. + * + * Return : 0 for success, non zero for failure + */ + +static CDF_STATUS sme_rrm_scan_request_callback(tHalHandle halHandle, + void *pContext, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + + uint16_t interval; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t time_tick; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "Scan Request callback "); +#endif + /* if any more channels are pending, start a timer of a random value within randomization interval. */ + /* */ + /* */ + if ((pSmeRrmContext->currentIndex + 1) < + pSmeRrmContext->channelList.numOfChannels) { + sme_rrm_send_scan_result(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->currentIndex], + false); + + pSmeRrmContext->currentIndex++; /* Advance the current index. */ + /* start the timer to issue next request. */ + /* From timer tick get a random number within 10ms and max randmization interval. */ + time_tick = cdf_mc_timer_get_system_ticks(); + interval = + time_tick % (pSmeRrmContext->randnIntvl - 10 + 1) + 10; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "Set timer for interval %d ", interval); +#endif + cdf_mc_timer_start(&pSmeRrmContext->IterMeasTimer, interval); + + } else { + /* Done with the measurement. Clean up all context and send a message to PE with measurement done flag set. */ + sme_rrm_send_scan_result(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->currentIndex], + true); + cdf_mem_free(pSmeRrmContext->channelList.ChannelList); +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + pSmeRrmContext->eseBcnReqInProgress = false; +#endif +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, FL("Free memory for ChannelList")); +#endif + } + + return CDF_STATUS_SUCCESS; +} + +/** + * sme_rrm_issue_scan_req() - To issue rrm scan request + * @mac_ctx: pointer to mac context + * + * This routine is called to issue rrm scan request + * + * Return: CDF_STATUS + */ +CDF_STATUS sme_rrm_issue_scan_req(tpAniSirGlobal mac_ctx) +{ + /* Issue scan request. */ + tCsrScanRequest scan_req; + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + tSirScanType scan_type; + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &sme_rrm_ctx->sessionBssId, &session_id); + if (status != CDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, FL("Invalid sme Session ID")); + return CDF_STATUS_E_FAILURE; + } + + if ((sme_rrm_ctx->currentIndex) >= + sme_rrm_ctx->channelList.numOfChannels) + return status; + + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + scan_type = sme_rrm_ctx->measMode[sme_rrm_ctx->currentIndex]; + else + scan_type = sme_rrm_ctx->measMode[0]; + + if ((eSIR_ACTIVE_SCAN == scan_type) || + (eSIR_PASSIVE_SCAN == scan_type)) { +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Issue scan request")); +#endif + cdf_mem_zero(&scan_req, sizeof(scan_req)); + /* set scan_type, active or passive */ + scan_req.bcnRptReqScan = true; + scan_req.scanType = scan_type; + cdf_mem_copy(&scan_req.bssid.bytes, sme_rrm_ctx->bssId, + CDF_MAC_ADDR_SIZE); + if (sme_rrm_ctx->ssId.length) { + scan_req.SSIDs.numOfSSIDs = 1; + scan_req.SSIDs.SSIDList = + (tCsrSSIDInfo *)cdf_mem_malloc( + sizeof(tCsrSSIDInfo)); + if (NULL == scan_req.SSIDs.SSIDList) { + sms_log(mac_ctx, LOGP, + FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, + FL("Allocated memory for pSSIDList")); +#endif + cdf_mem_zero(scan_req.SSIDs.SSIDList, + sizeof(tCsrSSIDInfo)); + scan_req.SSIDs.SSIDList->SSID.length = + sme_rrm_ctx->ssId.length; + cdf_mem_copy(scan_req.SSIDs.SSIDList->SSID.ssId, + sme_rrm_ctx->ssId.ssId, + sme_rrm_ctx->ssId.length); + } + + /* + * set min and max channel time + * sme_rrm_ctx->duration; Dont use min timeout. + */ + scan_req.minChnTime = 0; + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + scan_req.maxChnTime = sme_rrm_ctx->duration[ + sme_rrm_ctx->currentIndex]; + else + scan_req.maxChnTime = sme_rrm_ctx->duration[0]; + + sms_log(mac_ctx, LOG1, FL("Scan Type(%d) Max Dwell Time(%d)"), + scan_req.scanType, scan_req.maxChnTime); + + rrm_scan_timer = cdf_mc_timer_get_system_time(); + +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("For Duration %d "), + scan_req.maxChnTime); +#endif + /* set BSSType to default type */ + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + /*Scan all the channels */ + scan_req.ChannelInfo.numOfChannels = 1; + scan_req.ChannelInfo.ChannelList = + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex]; +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("On channel %d "), + sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex]); +#endif + /* set requestType to full scan */ + scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + status = sme_scan_request(mac_ctx, (uint8_t) session_id, + &scan_req, + &sme_rrm_scan_request_callback, NULL); + + if (sme_rrm_ctx->ssId.length) { + cdf_mem_free(scan_req.SSIDs.SSIDList); +#if defined WLAN_VOWIFI_DEBUG + sms_log(mac_ctx, LOGE, FL("Free memory for SSIDList")); +#endif + } + } else if (eSIR_BEACON_TABLE == scan_type) { + /* + * In beacon table mode, scan results are taken directly from + * scan cache without issuing any scan request. So, it is not + * proper to update rrm_scan_timer with latest time and hence + * made it to zero to satisfy + * pScanResult->timer >= rrm_scan_timer + */ + rrm_scan_timer = 0; + if ((sme_rrm_ctx->currentIndex + 1) < + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_scan_result(mac_ctx, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], false); + /* Advance the current index. */ + sme_rrm_ctx->currentIndex++; + sme_rrm_issue_scan_req(mac_ctx); +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + sme_rrm_ctx->eseBcnReqInProgress = false; +#endif + } else { + /* + * Done with the measurement. Clean up all context and + * send a message to PE with measurement done flag set. + */ + sme_rrm_send_scan_result(mac_ctx, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], true); + cdf_mem_free(sme_rrm_ctx->channelList.ChannelList); + } + } else { + sms_log(mac_ctx, LOGE, FL("Unknown beacon report req mode(%d)"), + scan_type); + /* + * Indicate measurement completion to PE + * If this is not done, pCurrentReq pointer will not be freed + * and PE will not handle subsequent Beacon requests + */ + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, NULL, true, 0); + } + return status; +} + +/** + * sme_rrm_process_beacon_report_req_ind() -Process beacon report request + * @pMac:- Global Mac structure + * @pMsgBuf:- a pointer to a buffer that maps to various structures base + * on the message type.The beginning of the buffer can always + * map to tSirSmeRsp. + * + * This is called to process the Beacon + * report request from peer AP forwarded through PE . + * + * Return : CDF_STATUS_SUCCESS - Validation is successful. + */ +CDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirBeaconReportReqInd pBeaconReq = (tpSirBeaconReportReqInd) pMsgBuf; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t len = 0, i = 0; + CDF_STATUS status = CDF_STATUS_SUCCESS; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "Received Beacon report request ind Channel = %d", + pBeaconReq->channelInfo.channelNum); +#endif + /* section 11.10.8.1 (IEEE Std 802.11k-2008) */ + /* channel 0 and 255 has special meaning. */ + if ((pBeaconReq->channelInfo.channelNum == 0) || + ((pBeaconReq->channelInfo.channelNum == 255) + && (pBeaconReq->channelList.numChannels == 0))) { + /* Add all the channel in the regulatory domain. */ + wlan_cfg_get_str_len(pMac, WNI_CFG_VALID_CHANNEL_LIST, &len); + pSmeRrmContext->channelList.ChannelList = cdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sms_log(pMac, LOGP, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, FL("Allocated memory for ChannelList")); +#endif + csr_get_cfg_valid_channels(pMac, + pSmeRrmContext->channelList.ChannelList, + &len); + pSmeRrmContext->channelList.numOfChannels = (uint8_t) len; +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "channel == 0 performing on all channels"); +#endif + } else { + len = 0; + pSmeRrmContext->channelList.numOfChannels = 0; + + /* If valid channel is present. We first Measure on the given channel. and */ + /* if there are additional channels present in APchannelreport, measure on these also. */ + if (pBeaconReq->channelInfo.channelNum != 255) + len = 1; +#if defined WLAN_VOWIFI_DEBUG + else + sms_log(pMac, LOGE, "channel == 255"); +#endif + + len += pBeaconReq->channelList.numChannels; + + pSmeRrmContext->channelList.ChannelList = cdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sms_log(pMac, LOGP, FL("cdf_mem_malloc failed")); + return CDF_STATUS_E_NOMEM; + } +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, FL("Allocated memory for ChannelList")); +#endif + + if (pBeaconReq->channelInfo.channelNum != 255) { +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "channel == %d ", + pBeaconReq->channelInfo.channelNum); +#endif + if (csr_roam_is_channel_valid + (pMac, pBeaconReq->channelInfo.channelNum)) + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels++] = + pBeaconReq->channelInfo.channelNum; +#if defined WLAN_VOWIFI_DEBUG + else + sms_log(pMac, LOGE, + "is Invalid channel, Ignoring this channel"); +#endif + } + + for (i = 0; i < pBeaconReq->channelList.numChannels; i++) { + if (csr_roam_is_channel_valid + (pMac, pBeaconReq->channelList.channelNumber[i])) { + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels] = + pBeaconReq->channelList.channelNumber[i]; + pSmeRrmContext->channelList.numOfChannels++; + } + } + } + + /* Copy session bssid */ + cdf_mem_copy(pSmeRrmContext->sessionBssId.bytes, pBeaconReq->bssId, + sizeof(tSirMacAddr)); + + /* copy measurement bssid */ + cdf_mem_copy(pSmeRrmContext->bssId, pBeaconReq->macaddrBssid, + sizeof(tSirMacAddr)); + + /* Copy ssid */ + cdf_mem_copy(&pSmeRrmContext->ssId, &pBeaconReq->ssId, + sizeof(tAniSSID)); + + pSmeRrmContext->token = pBeaconReq->uDialogToken; + pSmeRrmContext->regClass = pBeaconReq->channelInfo.regulatoryClass; + pSmeRrmContext->randnIntvl = + CDF_MAX(pBeaconReq->randomizationInterval, + pSmeRrmContext->rrmConfig.maxRandnInterval); + pSmeRrmContext->currentIndex = 0; + pSmeRrmContext->msgSource = pBeaconReq->msgSource; + cdf_mem_copy((uint8_t *) &pSmeRrmContext->measMode, + (uint8_t *) &pBeaconReq->fMeasurementtype, + SIR_ESE_MAX_MEAS_IE_REQS); + cdf_mem_copy((uint8_t *) &pSmeRrmContext->duration, + (uint8_t *) &pBeaconReq->measurementDuration, + SIR_ESE_MAX_MEAS_IE_REQS); + + status = sme_rrm_issue_scan_req(pMac); + + return status; +} + +/** + * sme_rrm_neighbor_report_request() - This is API can be used to trigger a + * Neighbor report from the peer. + * @sessionId: session identifier on which the request should be made. + * @pNeighborReq: a pointer to a neighbor report request. + * + * This is API can be used to trigger a Neighbor report from the peer. + * + * Return: CDF_STATUS_SUCCESS - Validation is successful. + */ +CDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, uint8_t sessionId, + tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo + callbackInfo) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpSirNeighborReportReqInd pMsg; + tCsrRoamSession *pSession; + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, + FL("Request to send Neighbor report request received ")); +#endif + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, FL("Invalid session %d"), sessionId); + return CDF_STATUS_E_INVAL; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* If already a report is pending, return failure */ + if (true == + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + isNeighborRspPending) { + sms_log(pMac, LOGE, + FL("Neighbor request already pending.. Not allowed")); + return CDF_STATUS_E_AGAIN; + } + + pMsg = cdf_mem_malloc(sizeof(tSirNeighborReportReqInd)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + "Unable to allocate memory for Neighbor request"); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_zero(pMsg, sizeof(tSirNeighborReportReqInd)); +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, FL(" Allocated memory for Neighbor request")); +#endif + + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext.neighborReportCache); + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, + FL + ("Purged the neighbor cache before sending Neighbor request: Status = %d"), + status); +#endif + + pMsg->messageType = eWNI_SME_NEIGHBOR_REPORT_REQ_IND; + pMsg->length = sizeof(tSirNeighborReportReqInd); + cdf_mem_copy(&pMsg->bssId, &pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); + pMsg->noSSID = pNeighborReq->no_ssid; + cdf_mem_copy(&pMsg->ucSSID, &pNeighborReq->ssid, sizeof(tSirMacSSid)); + + status = cds_send_mb_message_to_mac(pMsg); + if (status != CDF_STATUS_SUCCESS) + return CDF_STATUS_E_FAILURE; + + /* Neighbor report request message sent successfully to PE. Now register the callbacks */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = callbackInfo->neighborRspCallback; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallbackContext = + callbackInfo->neighborRspCallbackContext; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = + true; + + /* Start neighbor response wait timer now */ + cdf_mc_timer_start(&pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspWaitTimer, callbackInfo->timeout); + + return CDF_STATUS_SUCCESS; +} + +/** + * rrm_calculate_neighbor_ap_roam_score() - caclulates roam score + * @mac_ctx: mac global context + * @pNeighborReportDesc: Neighbor BSS Descriptor node for which roam score + * should be calculated + * + * This API is called while handling individual neighbor reports from the APs + * neighbor AP report to calculate the cumulative roam score before storing it + * in neighbor cache. + * + * Return: void + */ +static void +rrm_calculate_neighbor_ap_roam_score(tpAniSirGlobal mac_ctx, + tpRrmNeighborReportDesc nbr_report_desc) +{ + tpSirNeighborBssDescripton nbr_bss_desc; + uint32_t roam_score = 0; +#ifdef FEATURE_WLAN_ESE + uint8_t session_id; +#endif + if (NULL == nbr_report_desc) { + CDF_ASSERT(0); + return; + } + + if (NULL == nbr_report_desc->pNeighborBssDescription) { + CDF_ASSERT(0); + return; + } + + nbr_bss_desc = nbr_report_desc->pNeighborBssDescription; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fMobilityDomain) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameSecurityMode) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameAuthenticator) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fCapRadioMeasurement) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM; + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapSpectrumMeasurement) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapQos) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapApsd) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapDelayedBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapImmediateBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fApPreauthReachable) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY; + +check_11r_assoc: +#ifdef FEATURE_WLAN_ESE + session_id = nbr_report_desc->sessionId; + /* It has come in the report so its the best score */ + if (csr_neighbor_roam_is11r_assoc(mac_ctx, session_id) == false) { + /* IAPP Route so lets make use of this info save all AP, as the + * list does not come all the time. Save and reuse till the next + * AP List comes to us. Even save our own MAC address. Will be + * useful next time around. + */ + roam_score += RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST; + } +#endif + nbr_report_desc->roamScore = roam_score; +} + +/** + * rrm_store_neighbor_rpt_by_roam_score()-store Neighbor BSS descriptor + * @pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache + * + * This API is called to store a given + * Neighbor BSS descriptor to the neighbor cache. This function + * stores the neighbor BSS descriptors in such a way that descriptors + * are sorted by roamScore in descending order + * + * Return: void. + */ +void rrm_store_neighbor_rpt_by_roam_score(tpAniSirGlobal pMac, + tpRrmNeighborReportDesc pNeighborReportDesc) +{ + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + tListElem *pEntry; + tRrmNeighborReportDesc *pTempNeighborReportDesc; + + if (NULL == pNeighborReportDesc) { + CDF_ASSERT(0); + return; + } + if (NULL == pNeighborReportDesc->pNeighborBssDescription) { + CDF_ASSERT(0); + return; + } + + if (csr_ll_is_list_empty + (&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK)) { + sms_log(pMac, LOGE, + FL + ("Neighbor report cache is empty.. Adding a entry now")); + /* Neighbor list cache is empty. Insert this entry in the tail */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, LL_ACCESS_LOCK); + return; + } else { + /* Should store the neighbor BSS description in the order sorted by roamScore in descending + order. APs with highest roamScore should be the 1st entry in the list */ + pEntry = + csr_ll_peek_head(&pSmeRrmContext->neighborReportCache, + LL_ACCESS_LOCK); + while (pEntry != NULL) { + pTempNeighborReportDesc = + GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + if (pTempNeighborReportDesc->roamScore < + pNeighborReportDesc->roamScore) + break; + pEntry = + csr_ll_next(&pSmeRrmContext->neighborReportCache, + pEntry, LL_ACCESS_LOCK); + } + + if (pEntry) + /* This BSS roamscore is better than something in the list. Insert this before that one */ + csr_ll_insert_entry(&pSmeRrmContext->neighborReportCache, + pEntry, &pNeighborReportDesc->List, + LL_ACCESS_LOCK); + else + /* All the entries in the list has a better roam Score than this one. Insert this at the last */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, + LL_ACCESS_LOCK); + } + return; +} + +/** + * sme_rrm_process_neighbor_report() -Process the Neighbor report received + * from PE + * @pMac - Global MAC structure + * @pMsgBuf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * This is called to process the Neighbor report received from PE. + * + * Return: CDF_STATUS_SUCCESS - Validation is successful + */ +CDF_STATUS sme_rrm_process_neighbor_report(tpAniSirGlobal pMac, void *pMsgBuf) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + tpSirNeighborReportInd pNeighborRpt = (tpSirNeighborReportInd) pMsgBuf; + tpRrmNeighborReportDesc pNeighborReportDesc; + uint8_t i = 0; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + uint8_t sessionId; + + /* Get the session id */ + status = + csr_roam_get_session_id_from_bssid(pMac, + (struct cdf_mac_addr *) pNeighborRpt->bssId, + (uint32_t *) &sessionId); + if (CDF_IS_STATUS_SUCCESS(status)) { +#ifdef FEATURE_WLAN_ESE + /* Clear the cache for ESE. */ + if (csr_neighbor_roam_is_ese_assoc(pMac, sessionId)) { + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext. + neighborReportCache); + } +#endif + } + + for (i = 0; i < pNeighborRpt->numNeighborReports; i++) { + pNeighborReportDesc = + cdf_mem_malloc(sizeof(tRrmNeighborReportDesc)); + if (NULL == pNeighborReportDesc) { + sms_log(pMac, LOGE, + "Failed to allocate memory for RRM Neighbor report desc"); + status = CDF_STATUS_E_NOMEM; + goto end; + + } + + cdf_mem_zero(pNeighborReportDesc, + sizeof(tRrmNeighborReportDesc)); + pNeighborReportDesc->pNeighborBssDescription = + cdf_mem_malloc(sizeof(tSirNeighborBssDescription)); + if (NULL == pNeighborReportDesc->pNeighborBssDescription) { + sms_log(pMac, LOGE, + "Failed to allocate memory for RRM Neighbor report BSS Description"); + cdf_mem_free(pNeighborReportDesc); + status = CDF_STATUS_E_NOMEM; + goto end; + } + cdf_mem_zero(pNeighborReportDesc->pNeighborBssDescription, + sizeof(tSirNeighborBssDescription)); + cdf_mem_copy(pNeighborReportDesc->pNeighborBssDescription, + &pNeighborRpt->sNeighborBssDescription[i], + sizeof(tSirNeighborBssDescription)); + +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, + "Received neighbor report with Neighbor BSSID: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pNeighborRpt->sNeighborBssDescription[i]. + bssId)); +#endif + + /* Calculate the roam score based on the BSS Capability in the BSSID Information and store it in Neighbor report Desc */ + rrm_calculate_neighbor_ap_roam_score(pMac, pNeighborReportDesc); + + /* Store the Neighbor report Desc in the cache based on the roam score */ + if (pNeighborReportDesc->roamScore > 0) { + rrm_store_neighbor_rpt_by_roam_score(pMac, + pNeighborReportDesc); + } else { + sms_log(pMac, LOGE, + FL("Roam score of BSSID " MAC_ADDRESS_STR + " is 0, Ignoring.."), + MAC_ADDR_ARRAY(pNeighborRpt-> + sNeighborBssDescription[i]. + bssId)); + + cdf_mem_free(pNeighborReportDesc-> + pNeighborBssDescription); + cdf_mem_free(pNeighborReportDesc); + } + } +end: + + if (!csr_ll_count(&pMac->rrm.rrmSmeContext.neighborReportCache)) + cdf_status = CDF_STATUS_E_FAILURE; + + /* Received a report from AP. Indicate SUCCESS to the caller if there are some valid reports */ + rrm_indicate_neighbor_report_result(pMac, cdf_status); + + return status; +} + +/** + * sme_rrm_msg_processor()-Process RRM message + * @pMac - Pointer to the global MAC parameter structure. + * @msg_type - the type of msg passed by PE as defined in wni_api.h + * @pMsgBuf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * sme_process_msg() calls this function for the + * messages that are handled by SME RRM module. + * + * Return: CDF_STATUS_SUCCESS - Validation is successful. + */ +CDF_STATUS sme_rrm_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf) +{ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO_HIGH, + FL(" Msg = %d for RRM measurement"), msg_type); + + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_NEIGHBOR_REPORT_IND: + sme_rrm_process_neighbor_report(pMac, pMsgBuf); + break; + + case eWNI_SME_BEACON_REPORT_REQ_IND: + sme_rrm_process_beacon_report_req_ind(pMac, pMsgBuf); + break; + + default: + /* err msg */ + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("sme_rrm_msg_processor:unknown msg type = %d"), + msg_type); + + break; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * rrm_iter_meas_timer_handle() - Timer handler to handlet the timeout + * @ pMac - The handle returned by mac_open. + * + * Timer handler to handlet the timeout condition when a specific BT + * stop event does not come back, in which case to restore back the + * heartbeat timer. + * + * Return: NULL + */ +void rrm_iter_meas_timer_handle(void *userData) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, + "Randomization timer expired...send on next channel "); +#endif + /* Issue a scan req for next channel. */ + sme_rrm_issue_scan_req(pMac); +} +/** + * rrm_neighbor_rsp_timeout_handler() - Timer handler to handlet the timeout + * @pMac - The handle returned by mac_open. + * + * Timer handler to handle the timeout condition when a neighbor request is sent + * and no neighbor response is received from the AP + * + * Return: NULL + */ +void rrm_neighbor_rsp_timeout_handler(void *userData) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; +#if defined WLAN_VOWIFI_DEBUG + sms_log(pMac, LOGE, "Neighbor Response timed out "); +#endif + rrm_indicate_neighbor_report_result(pMac, CDF_STATUS_E_FAILURE); + return; +} + +/** + * rrm_open() - Initialze all RRM module + * @ pMac: The handle returned by mac_open. + * + * Initialze all RRM module. + * + * Return: CDF_STATUS + */ +CDF_STATUS rrm_open(tpAniSirGlobal pMac) +{ + + CDF_STATUS cdf_status; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS; + + pSmeRrmContext->rrmConfig.maxRandnInterval = 50; /* ms */ + + cdf_status = cdf_mc_timer_init(&pSmeRrmContext->IterMeasTimer, + CDF_TIMER_TYPE_SW, + rrm_iter_meas_timer_handle, (void *)pMac); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return CDF_STATUS_E_FAILURE; + } + + cdf_status = + cdf_mc_timer_init(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer, CDF_TIMER_TYPE_SW, + rrm_neighbor_rsp_timeout_handler, (void *)pMac); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return CDF_STATUS_E_FAILURE; + } + + pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = false; + + cdf_ret_status = + csr_ll_open(pMac->hHdd, &pSmeRrmContext->neighborReportCache); + if (CDF_STATUS_SUCCESS != cdf_ret_status) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to open neighbor cache result"); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * rrm_close() - Release all RRM modules and their resources. + * @pMac - The handle returned by mac_open. + * + * Release all RRM modules and their resources. + * + * Return: CDF_STATUS + * CDF_STATUS_E_FAILURE success + * CDF_STATUS_SUCCESS failure + */ + +CDF_STATUS rrm_close(tpAniSirGlobal pMac) +{ + + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&pSmeRrmContext->IterMeasTimer)) { + cdf_status = cdf_mc_timer_stop(&pSmeRrmContext->IterMeasTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Timer stop fail")); + } + } + + cdf_status = cdf_mc_timer_destroy(&pSmeRrmContext->IterMeasTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR, + FL("Fail to destroy timer")); + + } + + if (CDF_TIMER_STATE_RUNNING == + cdf_mc_timer_get_current_state(&pSmeRrmContext-> + neighborReqControlInfo. + neighborRspWaitTimer)) { + cdf_status = + cdf_mc_timer_stop(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + FL("Timer stop fail")); + } + } + + cdf_status = + cdf_mc_timer_destroy(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL, + FL("Fail to destroy timer")); + + } + + rrm_ll_purge_neighbor_cache(pMac, &pSmeRrmContext->neighborReportCache); + + csr_ll_close(&pSmeRrmContext->neighborReportCache); + + return cdf_status; + +} + +/* --------------------------------------------------------------------------- + + \fn rrm_ready + + \brief fn + + \param pMac - The handle returned by mac_open. + + \return CDF_STATUS + + ---------------------------------------------------------------------------*/ + +CDF_STATUS rrm_ready(tpAniSirGlobal pMac) +{ + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn rrm_change_default_config_param + \brief fn + + \param pMac - The handle returned by mac_open. + \param pRrmConfig - pointer to new rrm configs. + + \return CDF_STATUS + + ---------------------------------------------------------------------------*/ +CDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + tpRrmConfigParam pRrmConfig) +{ + cdf_mem_copy(&pMac->rrm.rrmSmeContext.rrmConfig, pRrmConfig, + sizeof(tRrmConfigParam)); + + return CDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_rrm_get_first_bss_entry_from_neighbor_cache() + + \brief This function returns the first entry from the neighbor cache to the caller + + \param pMac - The handle returned by mac_open. + + \return VOID + + ---------------------------------------------------------------------------*/ +tRrmNeighborReportDesc *sme_rrm_get_first_bss_entry_from_neighbor_cache(tpAniSirGlobal + pMac) +{ + tListElem *pEntry; + tRrmNeighborReportDesc *pTempBssEntry = NULL; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + pEntry = + csr_ll_peek_head(&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK); + + if (!pEntry || !csr_ll_count(&pSmeRrmContext->neighborReportCache)) { + /* list empty */ + sms_log(pMac, LOGW, FL("List empty")); + return NULL; + } + + pTempBssEntry = GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + + return pTempBssEntry; +} + +/** + * sme_rrm_get_next_bss_entry_from_neighbor_cache() - returns the entry next to + * the given entry + * @ pMac - The handle returned by mac_open. + * @pBssEntry- BSS entry + * + * This function returns the entry next to the given entry from the + * neighbor cache to the caller + * + * Return: NULL + */ +tRrmNeighborReportDesc *sme_rrm_get_next_bss_entry_from_neighbor_cache( + tpAniSirGlobal pMac, tpRrmNeighborReportDesc pBssEntry) +{ + tListElem *pEntry; + tRrmNeighborReportDesc *pTempBssEntry = NULL; + + pEntry = + csr_ll_next(&pMac->rrm.rrmSmeContext.neighborReportCache, + &pBssEntry->List, LL_ACCESS_LOCK); + + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOGW, FL("List empty")); + return NULL; + } + + pTempBssEntry = GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + + return pTempBssEntry; +} + +#endif diff --git a/core/utils/epping/inc/epping_internal.h b/core/utils/epping/inc/epping_internal.h new file mode 100644 index 0000000000..ee32b4c7d4 --- /dev/null +++ b/core/utils/epping/inc/epping_internal.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EPPING_INTERNAL_H +#define EPPING_INTERNAL_H +/**=========================================================================== + + \file epping_internal.h + + \brief Linux epping internal head file + + ==========================================================================*/ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include "htc_api.h" +#include "htc_packet.h" +#include "epping_test.h" +#include +#include +#include + +#define EPPING_LOG_MASK (1< + +#define WLAN_EPPING_ENABLE_BIT (1 << 8) +#define WLAN_EPPING_IRQ_BIT (1 << 9) +#define WLAN_EPPING_FW_UART_BIT (1 << 10) +#define WLAN_IS_EPPING_ENABLED(x) (x & WLAN_EPPING_ENABLE_BIT) +#define WLAN_IS_EPPING_IRQ(x) (x & WLAN_EPPING_IRQ_BIT) +#define WLAN_IS_EPPING_FW_UART(x) (x & WLAN_EPPING_FW_UART_BIT) + +/* epping_main signatures */ +int epping_open(void); +void epping_close(void); +void epping_disable(void); +int epping_enable(struct device *parent_dev); +#endif /* end #ifndef EPPING_MAIN_H */ diff --git a/core/utils/epping/src/epping_helper.c b/core/utils/epping/src/epping_helper.c new file mode 100644 index 0000000000..0e8e3ecd2f --- /dev/null +++ b/core/utils/epping/src/epping_helper.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" + +int epping_cookie_init(epping_context_t *pEpping_ctx) +{ + A_UINT32 i, j; + + pEpping_ctx->cookie_list = NULL; + pEpping_ctx->cookie_count = 0; + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + pEpping_ctx->s_cookie_mem[i] = + cdf_mem_malloc(sizeof(struct epping_cookie) * + MAX_COOKIE_SLOT_SIZE); + if (pEpping_ctx->s_cookie_mem == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: no mem for cookie (idx = %d)", __func__, + i); + goto error; + } + cdf_mem_zero(pEpping_ctx->s_cookie_mem[i], + sizeof(struct epping_cookie) * + MAX_COOKIE_SLOT_SIZE); + } + cdf_spinlock_init(&pEpping_ctx->cookie_lock); + + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + struct epping_cookie *cookie_mem = pEpping_ctx->s_cookie_mem[i]; + for (j = 0; j < MAX_COOKIE_SLOT_SIZE; j++) { + epping_free_cookie(pEpping_ctx, &cookie_mem[j]); + } + } + return 0; +error: + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + if (pEpping_ctx->s_cookie_mem[i]) { + cdf_mem_free(pEpping_ctx->s_cookie_mem[i]); + pEpping_ctx->s_cookie_mem[i] = NULL; + } + } + return -ENOMEM; +} + +/* cleanup cookie queue */ +void epping_cookie_cleanup(epping_context_t *pEpping_ctx) +{ + int i; + cdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + pEpping_ctx->cookie_list = NULL; + pEpping_ctx->cookie_count = 0; + cdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + if (pEpping_ctx->s_cookie_mem[i]) { + cdf_mem_free(pEpping_ctx->s_cookie_mem[i]); + pEpping_ctx->s_cookie_mem[i] = NULL; + } + } +} + +void epping_free_cookie(epping_context_t *pEpping_ctx, + struct epping_cookie *cookie) +{ + cdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + cookie->next = pEpping_ctx->cookie_list; + pEpping_ctx->cookie_list = cookie; + pEpping_ctx->cookie_count++; + cdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); +} + +struct epping_cookie *epping_alloc_cookie(epping_context_t *pEpping_ctx) +{ + struct epping_cookie *cookie; + + cdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + cookie = pEpping_ctx->cookie_list; + if (cookie != NULL) { + pEpping_ctx->cookie_list = cookie->next; + pEpping_ctx->cookie_count--; + } + cdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); + return cookie; +} + +void epping_get_dummy_mac_addr(tSirMacAddr macAddr) +{ + macAddr[0] = 69; /* E */ + macAddr[1] = 80; /* P */ + macAddr[2] = 80; /* P */ + macAddr[3] = 73; /* I */ + macAddr[4] = 78; /* N */ + macAddr[5] = 71; /* G */ +} + +void epping_hex_dump(void *data, int buf_len, const char *str) +{ + char *buf = (char *)data; + int i; + + printk("%s: E, %s\n", __func__, str); + for (i = 0; (i + 7) < buf_len; i += 8) { + printk("%02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[i], + buf[i + 1], + buf[i + 2], + buf[i + 3], + buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); + } + + /* Dump the bytes in the last line */ + for (; i < buf_len; i++) { + printk("%02x ", buf[i]); + } + printk("\n%s: X %s\n", __func__, str); +} + +void *epping_get_cdf_ctx(void) +{ + cdf_device_t *p_cdf_ctx; + + p_cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + return p_cdf_ctx; +} + +void epping_log_packet(epping_adapter_t *pAdapter, + EPPING_HEADER *eppingHdr, int ret, const char *str) +{ + if (eppingHdr->Cmd_h & EPPING_LOG_MASK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: cmd = %d, seqNo = %u, flag = 0x%x, ret = %d, " + "txCount = %lu, txDrop = %lu, txBytes = %lu," + "rxCount = %lu, rxDrop = %lu, rxBytes = %lu\n", + str, eppingHdr->Cmd_h, eppingHdr->SeqNo, + eppingHdr->CmdFlags_h, ret, + pAdapter->stats.tx_packets, + pAdapter->stats.tx_dropped, + pAdapter->stats.tx_bytes, + pAdapter->stats.rx_packets, + pAdapter->stats.rx_dropped, + pAdapter->stats.rx_bytes); + } +} + +void epping_log_stats(epping_adapter_t *pAdapter, const char *str) +{ + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: txCount = %lu, txDrop = %lu, tx_bytes = %lu, " + "rxCount = %lu, rxDrop = %lu, rx_bytes = %lu, tx_acks = %u\n", + str, + pAdapter->stats.tx_packets, + pAdapter->stats.tx_dropped, + pAdapter->stats.tx_bytes, + pAdapter->stats.rx_packets, + pAdapter->stats.rx_dropped, + pAdapter->stats.rx_bytes, + pAdapter->pEpping_ctx->total_tx_acks); +} + +void epping_set_kperf_flag(epping_adapter_t *pAdapter, + HTC_ENDPOINT_ID eid, A_UINT8 kperf_flag) +{ + pAdapter->pEpping_ctx->kperf_num_rx_recv[eid] = 0; + pAdapter->pEpping_ctx->kperf_num_tx_acks[eid] = 0; +} diff --git a/core/utils/epping/src/epping_main.c b/core/utils/epping/src/epping_main.c new file mode 100644 index 0000000000..dd0c463e17 --- /dev/null +++ b/core/utils/epping/src/epping_main.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bmi.h" +#include "ol_fw.h" +#include "ol_if_athvar.h" +#include "hif.h" +#include "epping_main.h" +#include "epping_internal.h" + +#ifdef TIMER_MANAGER +#define TIMER_MANAGER_STR " +TIMER_MANAGER" +#else +#define TIMER_MANAGER_STR "" +#endif + +#ifdef MEMORY_DEBUG +#define MEMORY_DEBUG_STR " +MEMORY_DEBUG" +#else +#define MEMORY_DEBUG_STR "" +#endif + +#ifdef HIF_SDIO +#define WLAN_WAIT_TIME_WLANSTART 10000 +#else +#define WLAN_WAIT_TIME_WLANSTART 2000 +#endif + +/** + * epping_open(): End point ping driver open Function + * + * This function is called by HDD to open epping module + * + * + * return - 0 for success, negative for failure + */ +int epping_open(void) +{ + epping_context_t *pEpping_ctx; + v_CONTEXT_t cds_context; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); + + cds_context = cds_get_global_context(); + status = cds_alloc_context(cds_context, CDF_MODULE_ID_EPPING, + (void **)&pEpping_ctx, + sizeof(*pEpping_ctx)); + if (status != CDF_STATUS_SUCCESS) { + EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: cannot alloc epping context", __func__); + return -ENOMEM; + } + + pEpping_ctx->con_mode = cds_get_conparam(); + return 0; +} + +/** + * epping_disable(): End point ping driver disable Function + * + * This is the driver disable function - called by HDD to + * disable epping module + * + * return: none + */ +void epping_disable(void) +{ + epping_context_t *pEpping_ctx; + + pEpping_ctx = cds_get_context(CDF_MODULE_ID_EPPING); + if (pEpping_ctx == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: error: pEpping_ctx = NULL", __func__); + return; + } + if (pEpping_ctx->epping_adapter) { + epping_destroy_adapter(pEpping_ctx->epping_adapter); + pEpping_ctx->epping_adapter = NULL; + } + hif_disable_isr(cds_get_context(CDF_MODULE_ID_HIF)); + hif_reset_soc(cds_get_context(CDF_MODULE_ID_HIF)); + htc_stop(cds_get_context(CDF_MODULE_ID_HTC)); + epping_cookie_cleanup(pEpping_ctx); +} + +/** + * epping_close(): End point ping driver close Function + * + * This is the driver close function - called by HDD to close epping module + * + * return: none + */ +void epping_close(void) +{ + epping_context_t *pEpping_ctx; + + pEpping_ctx = cds_get_context(CDF_MODULE_ID_EPPING); + if (pEpping_ctx == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: error: pEpping_ctx = NULL", __func__); + return; + } + cds_free_context(NULL, CDF_MODULE_ID_EPPING, + cds_get_context(CDF_MODULE_ID_EPPING)); +} + +static void epping_target_suspend_acknowledge(void *context) +{ + epping_context_t *pEpping_ctx = cds_get_context(CDF_MODULE_ID_EPPING); + int wow_nack = *((int *)context); + + if (NULL == pEpping_ctx) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: epping_ctx is NULL", __func__); + return; + } + /* EPPING_TODO: do we need wow_nack? */ + pEpping_ctx->wow_nack = wow_nack; +} + +/** + * epping_enable(): End point ping driver enable Function + * + * This is the driver enable function - called by HDD to enable + * epping module + * + * return - 0 : success, negative: error + */ +int epping_enable(struct device *parent_dev) +{ + int ret = 0; + epping_context_t *pEpping_ctx = NULL; + cds_context_type *p_cds_context = NULL; + cdf_device_t cdf_ctx; + HTC_INIT_INFO htcInfo; + struct ol_softc *scn; + tSirMacAddr adapter_macAddr; + + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); + + p_cds_context = cds_get_global_context(); + + if (p_cds_context == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Failed cds_get_global_context", __func__); + ret = -1; + return ret; + } + + pEpping_ctx = cds_get_context(CDF_MODULE_ID_EPPING); + if (pEpping_ctx == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Failed to get pEpping_ctx", __func__); + ret = -1; + return ret; + } + pEpping_ctx->parent_dev = (void *)parent_dev; + epping_get_dummy_mac_addr(adapter_macAddr); + + /* Initialize the timer module */ + cdf_timer_module_init(); + + scn = cds_get_context(CDF_MODULE_ID_HIF); + if (!scn) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + return -1; + } + scn->enableuartprint = 0; + scn->enablefwlog = 0; + /* store target type and target version info in hdd ctx */ + pEpping_ctx->target_type = scn->target_type; + +#ifndef FEATURE_BMI_2 + /* Initialize BMI and Download firmware */ + if (bmi_download_firmware(scn)) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: BMI failed to download target", __func__); + bmi_cleanup(scn); + return -1; + } +#endif + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, + "%s: bmi_download_firmware done", __func__); + + htcInfo.pContext = p_cds_context->pHIFContext; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = epping_target_suspend_acknowledge; + cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + + /* Create HTC */ + p_cds_context->htc_ctx = htc_create(htcInfo.pContext, &htcInfo, cdf_ctx); + if (!p_cds_context->htc_ctx) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_FATAL, + "%s: Failed to Create HTC", __func__); + bmi_cleanup(scn); + return -1; + } + pEpping_ctx->HTCHandle = + cds_get_context(CDF_MODULE_ID_HTC); + if (pEpping_ctx->HTCHandle == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: HTCHandle is NULL", __func__); + return -1; + } + scn->htc_handle = pEpping_ctx->HTCHandle; + + hif_claim_device(scn->hif_hdl, scn); + + if (bmi_done(scn)) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto error_end; + } + /* start HIF */ + if (htc_wait_target(scn->htc_handle) != A_OK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: htc_wait_target error", __func__); + goto error_end; + } + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC ready", __func__); + + ret = epping_connect_service(pEpping_ctx); + if (ret != 0) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: htc_wait_targetdone", __func__); + goto error_end; + } + if (htc_start(pEpping_ctx->HTCHandle) != A_OK) { + goto error_end; + } + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__); + + /* init the tx cookie resource */ + ret = epping_cookie_init(pEpping_ctx); + if (ret == 0) { + pEpping_ctx->epping_adapter = epping_add_adapter(pEpping_ctx, + adapter_macAddr, + CDF_STA_MODE); + } + if (ret < 0 || pEpping_ctx->epping_adapter == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: epping_add_adaptererror error", __func__); + htc_stop(pEpping_ctx->HTCHandle); + epping_cookie_cleanup(pEpping_ctx); + goto error_end; + } + + EPPING_LOG(CDF_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__); + return ret; + +error_end: + htc_destroy(p_cds_context->htc_ctx); + p_cds_context->htc_ctx = NULL; + bmi_cleanup(scn); + return -1; +} diff --git a/core/utils/epping/src/epping_rx.c b/core/utils/epping/src/epping_rx.c new file mode 100644 index 0000000000..15928e120b --- /dev/null +++ b/core/utils/epping/src/epping_rx.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" +#include "epping_test.h" +#include + +#define AR6000_MAX_RX_BUFFERS 16 +#define AR6000_BUFFER_SIZE 1664 +#define AR6000_MIN_HEAD_ROOM 64 + +static bool enb_rx_dump = 0; + +#ifdef HIF_SDIO +void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + void *osBuf; + int RxBuffers; + int buffersToRefill; + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE queue; + + buffersToRefill = (int)AR6000_MAX_RX_BUFFERS - + htc_get_num_recv_buffers(pEpping_ctx->HTCHandle, Endpoint); + + if (buffersToRefill <= 0) { + /* fast return, nothing to fill */ + return; + } + + INIT_HTC_PACKET_QUEUE(&queue); + + EPPING_LOG(CDF_TRACE_LEVEL_INFO, + "%s: providing htc with %d buffers at eid=%d\n", + __func__, buffersToRefill, Endpoint); + + for (RxBuffers = 0; RxBuffers < buffersToRefill; RxBuffers++) { + osBuf = cdf_nbuf_alloc(NULL, AR6000_BUFFER_SIZE, + AR6000_MIN_HEAD_ROOM, 4, false); + if (NULL == osBuf) { + break; + } + /* the HTC packet wrapper is at the head of the reserved area + * in the skb */ + pPacket = (HTC_PACKET *) (A_NETBUF_HEAD(osBuf)); + /* set re-fill info */ + SET_HTC_PACKET_INFO_RX_REFILL(pPacket, osBuf, + cdf_nbuf_data(osBuf), + AR6000_BUFFER_SIZE, Endpoint); + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, osBuf); + /* add to queue */ + HTC_PACKET_ENQUEUE(&queue, pPacket); + } + + if (!HTC_QUEUE_EMPTY(&queue)) { + /* add packets */ + htc_add_receive_pkt_multiple(pEpping_ctx->HTCHandle, &queue); + } +} +#endif /* HIF_SDIO */ + +void epping_rx(void *ctx, HTC_PACKET *pPacket) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; + struct net_device *dev = pAdapter->dev; + A_STATUS status = pPacket->Status; + HTC_ENDPOINT_ID eid = pPacket->Endpoint; + struct sk_buff *pktSkb = (struct sk_buff *)pPacket->pPktContext; + + EPPING_LOG(CDF_TRACE_LEVEL_INFO, + "%s: pAdapter = 0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d", + __func__, pAdapter, eid, pktSkb, pPacket->pBuffer, + pPacket->ActualLength, status); + + if (status != A_OK) { + if (status != A_ECANCELED) { + printk("%s: RX ERR (%d) \n", __func__, status); + } + cdf_nbuf_free(pktSkb); + return; + } + + /* deliver to up layer */ + if (pktSkb) { + if (EPPING_ALIGNMENT_PAD > 0) { + A_NETBUF_PULL(pktSkb, EPPING_ALIGNMENT_PAD); + } + if (enb_rx_dump) + epping_hex_dump((void *)cdf_nbuf_data(pktSkb), + pktSkb->len, __func__); + pktSkb->dev = dev; + if ((pktSkb->dev->flags & IFF_UP) == IFF_UP) { + pktSkb->protocol = eth_type_trans(pktSkb, pktSkb->dev); + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += pktSkb->len; + if (hdd_napi_enabled(HDD_NAPI_ANY)) + netif_receive_skb(pktSkb); + else + netif_rx_ni(pktSkb); + if ((pAdapter->stats.rx_packets % + EPPING_STATS_LOG_COUNT) == 0) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: total_rx_pkts = %lu", + __func__, + pAdapter->stats.rx_packets); + } + } else { + ++pAdapter->stats.rx_dropped; + cdf_nbuf_free(pktSkb); + } + } +} diff --git a/core/utils/epping/src/epping_tx.c b/core/utils/epping/src/epping_tx.c new file mode 100644 index 0000000000..38489b25ff --- /dev/null +++ b/core/utils/epping/src/epping_tx.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" +#include "epping_test.h" + +#define TX_RETRY_TIMEOUT_IN_MS 1 + +static bool enb_tx_dump = 0; + +void epping_tx_dup_pkt(epping_adapter_t *pAdapter, + HTC_ENDPOINT_ID eid, cdf_nbuf_t skb) +{ + struct epping_cookie *cookie = NULL; + int skb_len, ret; + cdf_nbuf_t new_skb; + + cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); + if (cookie == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: epping_alloc_cookie returns no resource\n", + __func__); + return; + } + new_skb = cdf_nbuf_copy(skb); + if (!new_skb) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: cdf_nbuf_copy returns no resource\n", __func__); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + return; + } + SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, + cookie, cdf_nbuf_data(skb), + cdf_nbuf_len(new_skb), eid, 0); + SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb); + skb_len = (int)cdf_nbuf_len(new_skb); + /* send the packet */ + ret = htc_send_pkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); + if (ret != A_OK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: htc_send_pkt failed, ret = %d\n", __func__, ret); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + cdf_nbuf_free(new_skb); + return; + } + pAdapter->stats.tx_bytes += skb_len; + ++pAdapter->stats.tx_packets; + if (((pAdapter->stats.tx_packets + + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && + (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { + epping_log_stats(pAdapter, __func__); + } +} + +static int epping_tx_send_int(cdf_nbuf_t skb, epping_adapter_t *pAdapter) +{ + EPPING_HEADER *eppingHdr = (EPPING_HEADER *) cdf_nbuf_data(skb); + HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED; + struct epping_cookie *cookie = NULL; + A_UINT8 ac = 0; + A_STATUS ret = A_OK; + int skb_len; + EPPING_HEADER tmpHdr = *eppingHdr; + + /* allocate resource for this packet */ + cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); + /* no resource */ + if (cookie == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: epping_alloc_cookie returns no resource\n", + __func__); + return -1; + } + + if (enb_tx_dump) + epping_hex_dump((void *)eppingHdr, skb->len, __func__); + /* + * a quirk of linux, the payload of the frame is 32-bit aligned and thus + * the addition of the HTC header will mis-align the start of the HTC + * frame, so we add some padding which will be stripped off in the target + */ + if (EPPING_ALIGNMENT_PAD > 0) { + A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD); + } + /* prepare ep/HTC information */ + ac = eppingHdr->StreamNo_h; + eid = pAdapter->pEpping_ctx->EppingEndpoint[ac]; + if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: invalid eid = %d, ac = %d\n", __func__, eid, + ac); + return -1; + } + if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT || + tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) { + epping_set_kperf_flag(pAdapter, eid, tmpHdr.CmdBuffer_t[0]); + } + SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, + cookie, cdf_nbuf_data(skb), cdf_nbuf_len(skb), + eid, 0); + SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb); + skb_len = skb->len; + /* send the packet */ + ret = htc_send_pkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); + epping_log_packet(pAdapter, &tmpHdr, ret, __func__); + if (ret != A_OK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: htc_send_pkt failed, status = %d\n", __func__, + ret); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + return -1; + } + pAdapter->stats.tx_bytes += skb_len; + ++pAdapter->stats.tx_packets; + if (((pAdapter->stats.tx_packets + + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && + (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { + epping_log_stats(pAdapter, __func__); + } + + return 0; +} + +void epping_tx_timer_expire(epping_adapter_t *pAdapter) +{ + cdf_nbuf_t nodrop_skb; + + EPPING_LOG(CDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__, + cdf_nbuf_queue_len(&pAdapter->nodrop_queue)); + + if (!cdf_nbuf_queue_len(&pAdapter->nodrop_queue)) { + /* nodrop queue is empty so no need to arm timer */ + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + return; + } + + /* try to flush nodrop queue */ + while ((nodrop_skb = cdf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { + if (epping_tx_send_int(nodrop_skb, pAdapter)) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p xmit fail in timer\n", + __func__, nodrop_skb); + /* fail to xmit so put the nodrop packet to the nodrop queue */ + cdf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, + nodrop_skb); + break; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_INFO, + "%s: nodrop: %p xmit ok in timer\n", + __func__, nodrop_skb); + } + } + + /* if nodrop queue is not empty, continue to arm timer */ + if (nodrop_skb) { + cdf_spin_lock_bh(&pAdapter->data_lock); + /* if nodrop queue is not empty, continue to arm timer */ + if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { + pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; + cdf_softirq_timer_mod(&pAdapter->epping_timer, + TX_RETRY_TIMEOUT_IN_MS); + } + cdf_spin_unlock_bh(&pAdapter->data_lock); + } else { + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + } +} + +int epping_tx_send(cdf_nbuf_t skb, epping_adapter_t *pAdapter) +{ + cdf_nbuf_t nodrop_skb; + EPPING_HEADER *eppingHdr; + A_UINT8 ac = 0; + + eppingHdr = (EPPING_HEADER *) cdf_nbuf_data(skb); + + if (!IS_EPPING_PACKET(eppingHdr)) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Recived non endpoint ping packets\n", __func__); + /* no packet to send, cleanup */ + cdf_nbuf_free(skb); + return -ENOMEM; + } + + /* the stream ID is mapped to an access class */ + ac = eppingHdr->StreamNo_h; + /* hard coded two ep ids */ + if (ac != 0 && ac != 1) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: ac %d is not mapped to mboxping service\n", + __func__, ac); + cdf_nbuf_free(skb); + return -ENOMEM; + } + + /* + * some EPPING packets cannot be dropped no matter what access class + * it was sent on. A special care has been taken: + * 1. when there is no TX resource, queue the control packets to + * a special queue + * 2. when there is TX resource, send the queued control packets first + * and then other packets + * 3. a timer launches to check if there is queued control packets and + * flush them + */ + + /* check the nodrop queue first */ + while ((nodrop_skb = cdf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { + if (epping_tx_send_int(nodrop_skb, pAdapter)) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p xmit fail\n", __func__, + nodrop_skb); + /* fail to xmit so put the nodrop packet to the nodrop queue */ + cdf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, + nodrop_skb); + /* no cookie so free the current skb */ + goto tx_fail; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_INFO, + "%s: nodrop: %p xmit ok\n", __func__, + nodrop_skb); + } + } + + /* send the original packet */ + if (epping_tx_send_int(skb, pAdapter)) + goto tx_fail; + + return 0; + +tx_fail: + if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) { + /* allow to drop the skb so drop it */ + cdf_nbuf_free(skb); + ++pAdapter->stats.tx_dropped; + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Tx skb %p dropped, stats.tx_dropped = %ld\n", + __func__, skb, pAdapter->stats.tx_dropped); + return -ENOMEM; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p queued\n", __func__, skb); + cdf_nbuf_queue_add(&pAdapter->nodrop_queue, skb); + cdf_spin_lock_bh(&pAdapter->data_lock); + if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { + pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; + cdf_softirq_timer_mod(&pAdapter->epping_timer, + TX_RETRY_TIMEOUT_IN_MS); + } + cdf_spin_unlock_bh(&pAdapter->data_lock); + } + + return 0; +} + +#ifdef HIF_SDIO +HTC_SEND_FULL_ACTION epping_tx_queue_full(void *Context, HTC_PACKET *pPacket) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) Context; + epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; + HTC_SEND_FULL_ACTION action = HTC_SEND_FULL_KEEP; + netif_stop_queue(pAdapter->dev); + return action; +} +#endif /* HIF_SDIO */ +void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; + struct net_device *dev = pAdapter->dev; + A_STATUS status; + HTC_ENDPOINT_ID eid; + cdf_nbuf_t pktSkb; + struct epping_cookie *cookie; + A_BOOL flushing = false; + cdf_nbuf_queue_t skb_queue; + HTC_PACKET *htc_pkt; + + cdf_nbuf_queue_init(&skb_queue); + + cdf_spin_lock_bh(&pAdapter->data_lock); + + while (!HTC_QUEUE_EMPTY(pPacketQueue)) { + htc_pkt = htc_packet_dequeue(pPacketQueue); + if (htc_pkt == NULL) + break; + status = htc_pkt->Status; + eid = htc_pkt->Endpoint; + pktSkb = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); + cookie = htc_pkt->pPktContext; + + ASSERT(pktSkb); + ASSERT(htc_pkt->pBuffer == cdf_nbuf_data(pktSkb)); + + /* add this to the list, use faster non-lock API */ + cdf_nbuf_queue_add(&skb_queue, pktSkb); + + if (A_SUCCESS(status)) { + ASSERT(htc_pkt->ActualLength == cdf_nbuf_len(pktSkb)); + } + EPPING_LOG(CDF_TRACE_LEVEL_INFO, + "%s skb=%p data=%p len=0x%x eid=%d ", + __func__, pktSkb, htc_pkt->pBuffer, + htc_pkt->ActualLength, eid); + + if (A_FAILED(status)) { + if (status == A_ECANCELED) { + /* a packet was flushed */ + flushing = true; + } + if (status != A_NO_RESOURCE) { + printk("%s() -TX ERROR, status: 0x%x\n", + __func__, status); + } + } else { + EPPING_LOG(CDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__); + flushing = false; + } + + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + } + + cdf_spin_unlock_bh(&pAdapter->data_lock); + + /* free all skbs in our local list */ + while (cdf_nbuf_queue_len(&skb_queue)) { + /* use non-lock version */ + pktSkb = cdf_nbuf_queue_remove(&skb_queue); + if (pktSkb == NULL) + break; + cdf_nbuf_free(pktSkb); + pEpping_ctx->total_tx_acks++; + } + + if (!flushing) { + netif_wake_queue(dev); + } +} diff --git a/core/utils/epping/src/epping_txrx.c b/core/utils/epping/src/epping_txrx.c new file mode 100644 index 0000000000..240d43aede --- /dev/null +++ b/core/utils/epping/src/epping_txrx.c @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(MSM_PLATFORM) && defined(HIF_PCI) +#include +#endif /* MSM_PLATFORM */ +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" + +static int epping_start_adapter(epping_adapter_t *pAdapter); +static void epping_stop_adapter(epping_adapter_t *pAdapter); + +static void epping_timer_expire(void *data) +{ + struct net_device *dev = (struct net_device *)data; + epping_adapter_t *pAdapter; + + if (dev == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: netdev = NULL", __func__); + return; + } + + pAdapter = netdev_priv(dev); + if (pAdapter == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: adapter = NULL", __func__); + return; + } + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + epping_tx_timer_expire(pAdapter); +} + +static int epping_ndev_open(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + epping_start_adapter(pAdapter); + return ret; +} + +static int epping_ndev_stop(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + epping_stop_adapter(pAdapter); +end: + return ret; +} + +static void epping_ndev_uninit(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + goto end; + } + epping_stop_adapter(pAdapter); +end: + return; +} + +void epping_tx_queue_timeout(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + goto end; + } + + EPPING_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: Transmission timeout occurred, pAdapter->started= %d", + __func__, pAdapter->started); + + /* Getting here implies we disabled the TX queues + * for too long. Since this is epping + * (not because of disassociation or low resource scenarios), + * try to restart the queue + */ + if (pAdapter->started) + netif_wake_queue(dev); +end: + return; + +} + +int epping_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + ret = epping_tx_send(skb, pAdapter); +end: + return ret; +} + +struct net_device_stats *epping_get_stats(struct net_device *dev) +{ + epping_adapter_t *pAdapter = netdev_priv(dev); + + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: pAdapter = NULL", + __func__); + return NULL; + } + + return &pAdapter->stats; +} + +int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + if (dev != pAdapter->dev) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: HDD adapter/dev inconsistency", __func__); + ret = -ENODEV; + goto end; + } + + if ((!ifr) || (!ifr->ifr_data)) { + ret = -EINVAL; + goto end; + } + + switch (cmd) { + case (SIOCDEVPRIVATE + 1): + EPPING_LOG(CDF_TRACE_LEVEL_ERROR, + "%s: do not support ioctl %d (SIOCDEVPRIVATE + 1)", + __func__, cmd); + break; + default: + EPPING_LOG(CDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d", + __func__, cmd); + ret = -EINVAL; + break; + } + +end: + return ret; +} + +static int epping_set_mac_address(struct net_device *dev, void *addr) +{ + epping_adapter_t *pAdapter = netdev_priv(dev); + struct sockaddr *psta_mac_addr = addr; + cdf_mem_copy(&pAdapter->macAddressCurrent, + psta_mac_addr->sa_data, ETH_ALEN); + cdf_mem_copy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + return 0; +} + +static void epping_stop_adapter(epping_adapter_t *pAdapter) +{ + if (pAdapter && pAdapter->started) { + EPPING_LOG(LOG1, FL("Disabling queues")); + netif_tx_disable(pAdapter->dev); + netif_carrier_off(pAdapter->dev); + pAdapter->started = false; +#if defined(MSM_PLATFORM) && defined(HIF_PCI) && defined(CONFIG_CNSS) + cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_LOW); +#endif + } +} + +static int epping_start_adapter(epping_adapter_t *pAdapter) +{ + if (!pAdapter) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: pAdapter= NULL\n", __func__); + return -1; + } + if (!pAdapter->started) { +#if defined(MSM_PLATFORM) && defined(HIF_PCI) && defined(CONFIG_CNSS) + cnss_request_bus_bandwidth(CNSS_BUS_WIDTH_HIGH); +#endif + netif_carrier_on(pAdapter->dev); + EPPING_LOG(LOG1, FL("Enabling queues")); + netif_tx_start_all_queues(pAdapter->dev); + pAdapter->started = true; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_WARN, + "%s: pAdapter %p already started\n", __func__, + pAdapter); + } + return 0; +} + +static int epping_register_adapter(epping_adapter_t *pAdapter) +{ + int ret = 0; + + if ((ret = register_netdev(pAdapter->dev)) != 0) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: unable to register device\n", + pAdapter->dev->name); + } else { + pAdapter->registered = true; + } + return ret; +} + +static void epping_unregister_adapter(epping_adapter_t *pAdapter) +{ + if (pAdapter) { + epping_stop_adapter(pAdapter); + if (pAdapter->registered) { + unregister_netdev(pAdapter->dev); + pAdapter->registered = false; + } + } else { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: pAdapter = NULL, unable to unregister device\n", + __func__); + } +} + +void epping_destroy_adapter(epping_adapter_t *pAdapter) +{ + struct net_device *dev = NULL; + epping_context_t *pEpping_ctx; + + if (!pAdapter || !pAdapter->pEpping_ctx) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: pAdapter = NULL\n", __func__); + return; + } + + dev = pAdapter->dev; + pEpping_ctx = pAdapter->pEpping_ctx; + epping_unregister_adapter(pAdapter); + + cdf_spinlock_destroy(&pAdapter->data_lock); + cdf_softirq_timer_free(&pAdapter->epping_timer); + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + + while (cdf_nbuf_queue_len(&pAdapter->nodrop_queue)) { + cdf_nbuf_t tmp_nbuf = NULL; + tmp_nbuf = cdf_nbuf_queue_remove(&pAdapter->nodrop_queue); + if (tmp_nbuf) + cdf_nbuf_free(tmp_nbuf); + } + + free_netdev(dev); + if (!pEpping_ctx) + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: pEpping_ctx = NULL\n", __func__); + else + pEpping_ctx->epping_adapter = NULL; +} + +static struct net_device_ops epping_drv_ops = { + .ndo_open = epping_ndev_open, + .ndo_stop = epping_ndev_stop, + .ndo_uninit = epping_ndev_uninit, + .ndo_start_xmit = epping_hard_start_xmit, + .ndo_tx_timeout = epping_tx_queue_timeout, + .ndo_get_stats = epping_get_stats, + .ndo_do_ioctl = epping_ndev_ioctl, + .ndo_set_mac_address = epping_set_mac_address, + .ndo_select_queue = NULL, +}; + +#define EPPING_TX_QUEUE_MAX_LEN 128 /* need to be power of 2 */ + +epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx, + tSirMacAddr macAddr, + tCDF_CON_MODE device_mode) +{ + struct net_device *dev; + epping_adapter_t *pAdapter; + + dev = alloc_netdev(sizeof(epping_adapter_t), "wifi%d", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + NET_NAME_UNKNOWN, +#endif + ether_setup); + if (dev == NULL) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "%s: Cannot allocate epping_adapter_t\n", __func__); + return NULL; + } + + pAdapter = netdev_priv(dev); + cdf_mem_zero(pAdapter, sizeof(*pAdapter)); + pAdapter->dev = dev; + pAdapter->pEpping_ctx = pEpping_ctx; + pAdapter->device_mode = device_mode; /* station, SAP, etc */ + cdf_mem_copy(dev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr)); + cdf_mem_copy(pAdapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr)); + cdf_spinlock_init(&pAdapter->data_lock); + cdf_nbuf_queue_init(&pAdapter->nodrop_queue); + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + cdf_softirq_timer_init(epping_get_cdf_ctx(), &pAdapter->epping_timer, + epping_timer_expire, dev, CDF_TIMER_TYPE_SW); + dev->type = ARPHRD_IEEE80211; + dev->netdev_ops = &epping_drv_ops; + dev->watchdog_timeo = 5 * HZ; /* XXX */ + dev->tx_queue_len = EPPING_TXBUF - 1; /* 1 for mgmt frame */ + if (epping_register_adapter(pAdapter) == 0) { + EPPING_LOG(LOG1, FL("Disabling queues")); + netif_tx_disable(dev); + netif_carrier_off(dev); + return pAdapter; + } else { + epping_destroy_adapter(pAdapter); + return NULL; + } +} + +int epping_connect_service(epping_context_t *pEpping_ctx) +{ + int status, i; + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP response; + + cdf_mem_zero(&connect, sizeof(connect)); + cdf_mem_zero(&response, sizeof(response)); + + /* these fields are the same for all service endpoints */ + connect.EpCallbacks.pContext = pEpping_ctx; + connect.EpCallbacks.EpTxCompleteMultiple = epping_tx_complete_multiple; + connect.EpCallbacks.EpRecv = epping_rx; + /* epping_tx_complete use Multiple version */ + connect.EpCallbacks.EpTxComplete = NULL; + connect.MaxSendQueueDepth = 64; + +#ifdef HIF_SDIO + connect.EpCallbacks.EpRecvRefill = epping_refill; + connect.EpCallbacks.EpSendFull = + epping_tx_queue_full /* ar6000_tx_queue_full */; +#elif defined(HIF_USB) || defined(HIF_PCI) + connect.EpCallbacks.EpRecvRefill = NULL /* provided by HIF */; + connect.EpCallbacks.EpSendFull = NULL /* provided by HIF */; + /* disable flow control for hw flow control */ + connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; +#endif + + /* connect to service */ + connect.ServiceID = WMI_DATA_BE_SVC; + status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); + if (status != EOK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "Failed to connect to Endpoint Ping BE service status:%d \n", + status); + return -1;; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "eppingtest BE endpoint:%d\n", response.Endpoint); + } + pEpping_ctx->EppingEndpoint[0] = response.Endpoint; + +#if defined(HIF_PCI) || defined(HIF_USB) + connect.ServiceID = WMI_DATA_BK_SVC; + status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); + if (status != EOK) { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "Failed to connect to Endpoint Ping BK service status:%d \n", + status); + return -1;; + } else { + EPPING_LOG(CDF_TRACE_LEVEL_FATAL, + "eppingtest BK endpoint:%d\n", response.Endpoint); + } + pEpping_ctx->EppingEndpoint[1] = response.Endpoint; + /* Since we do not create other two SVC use BK endpoint + * for rest ACs (2, 3) */ + for (i = 2; i < EPPING_MAX_NUM_EPIDS; i++) { + pEpping_ctx->EppingEndpoint[i] = response.Endpoint; + } +#else + /* we only use one endpoint for high latenance bus. + * Map all AC's EPIDs to the same endpoint ID returned by HTC */ + for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { + pEpping_ctx->EppingEndpoint[i] = response.Endpoint; + } +#endif + return 0; +} diff --git a/core/utils/fwlog/dbglog_host.c b/core/utils/fwlog/dbglog_host.c new file mode 100644 index 0000000000..242c685456 --- /dev/null +++ b/core/utils/fwlog/dbglog_host.c @@ -0,0 +1,4464 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Host Debug log implementation */ + +#include "athdefs.h" +#include "a_types.h" +#include "dbglog_host.h" +#include "wmi.h" +#include "wmi_unified_api.h" +#include "wma.h" +#include "ol_defines.h" +#include +#include "host_diag_core_event.h" +#include "qwlan_version.h" +#include +#include +#include + +#ifdef WLAN_OPEN_SOURCE +#include +#endif /* WLAN_OPEN_SOURCE */ +#include "wmi_unified_priv.h" + +#define CLD_DEBUGFS_DIR "cld" +#define DEBUGFS_BLOCK_NAME "dbglog_block" + +#define ATH_MODULE_NAME fwlog +#include +#define FWLOG_DEBUG ATH_DEBUG_MAKE_MODULE_MASK(0) + +#if defined(DEBUG) + +static bool appstarted = false; +static bool senddriverstatus = false; +static bool kd_nl_init = false; +static int cnss_diag_pid = INVALID_PID; +static int get_version = 0; +static int gprint_limiter = 0; + +static ATH_DEBUG_MASK_DESCRIPTION g_fwlog_debug_description[] = { + {FWLOG_DEBUG, "fwlog"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(fwlog, + "fwlog", + "Firmware Debug Log", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | + ATH_DEBUG_ERR, + ATH_DEBUG_DESCRIPTION_COUNT + (g_fwlog_debug_description), + g_fwlog_debug_description); +#endif + +module_dbg_print mod_print[WLAN_MODULE_ID_MAX]; + +A_UINT32 dbglog_process_type = DBGLOG_PROCESS_NET_RAW; + +A_STATUS +wmi_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len); + +const char *dbglog_get_module_str(A_UINT32 module_id) +{ + switch (module_id) { + case WLAN_MODULE_INF: + return "INF"; + case WLAN_MODULE_WMI: + return "WMI"; + case WLAN_MODULE_STA_PWRSAVE: + return "STA PS"; + case WLAN_MODULE_WHAL: + return "WHAL"; + case WLAN_MODULE_COEX: + return "COEX"; + case WLAN_MODULE_ROAM: + return "ROAM"; + case WLAN_MODULE_RESMGR_CHAN_MANAGER: + return "CHANMGR"; + case WLAN_MODULE_RESMGR: + return "RESMGR"; + case WLAN_MODULE_VDEV_MGR: + return "VDEV"; + case WLAN_MODULE_SCAN: + return "SCAN"; + case WLAN_MODULE_RATECTRL: + return "RC"; + case WLAN_MODULE_AP_PWRSAVE: + return "AP PS"; + case WLAN_MODULE_BLOCKACK: + return "BA"; + case WLAN_MODULE_MGMT_TXRX: + return "MGMT"; + case WLAN_MODULE_DATA_TXRX: + return "DATA"; + case WLAN_MODULE_HTT: + return "HTT"; + case WLAN_MODULE_HOST: + return "HOST"; + case WLAN_MODULE_BEACON: + return "BEACON"; + case WLAN_MODULE_OFFLOAD: + return "OFFLOAD"; + case WLAN_MODULE_WAL: + return "WAL"; + case WAL_MODULE_DE: + return "DE"; + case WLAN_MODULE_PCIELP: + return "PCIELP"; + case WLAN_MODULE_RTT: + return "RTT"; + case WLAN_MODULE_DCS: + return "DCS"; + case WLAN_MODULE_CACHEMGR: + return "CACHEMGR"; + case WLAN_MODULE_ANI: + return "ANI"; + case WLAN_MODULE_TEST: + return "TESTPOINT"; + case WLAN_MODULE_STA_SMPS: + return "STA_SMPS"; + case WLAN_MODULE_TDLS: + return "TDLS"; + case WLAN_MODULE_P2P: + return "P2P"; + case WLAN_MODULE_WOW: + return "WoW"; + case WLAN_MODULE_IBSS_PWRSAVE: + return "IBSS PS"; + case WLAN_MODULE_EXTSCAN: + return "ExtScan"; + case WLAN_MODULE_UNIT_TEST: + return "UNIT_TEST"; + case WLAN_MODULE_MLME: + return "MLME"; + case WLAN_MODULE_SUPPL: + return "SUPPLICANT"; + default: + return "UNKNOWN"; + } +} + +char *DBG_MSG_ARR[WLAN_MODULE_ID_MAX][MAX_DBG_MSGS] = { + { + "INF_MSG_START", + "INF_ASSERTION_FAILED", + "INF_TARGET_ID", + "INF_MSG_END" + }, + { + "WMI_DBGID_DEFINITION_START", + "WMI_CMD_RX_XTND_PKT_TOO_SHORT", + "WMI_EXTENDED_CMD_NOT_HANDLED", + "WMI_CMD_RX_PKT_TOO_SHORT", + "WMI_CALLING_WMI_EXTENSION_FN", + "WMI_CMD_NOT_HANDLED", + "WMI_IN_SYNC", + "WMI_TARGET_WMI_SYNC_CMD", + "WMI_SET_SNR_THRESHOLD_PARAMS", + "WMI_SET_RSSI_THRESHOLD_PARAMS", + "WMI_SET_LQ_TRESHOLD_PARAMS", + "WMI_TARGET_CREATE_PSTREAM_CMD", + "WMI_WI_DTM_INUSE", + "WMI_TARGET_DELETE_PSTREAM_CMD", + "WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD", + "WMI_TARGET_GET_BIT_RATE_CMD", + "WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS", + "WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD", + "WMI_TARGET_GET_TX_PWR_CMD", + "WMI_FREE_EVBUF_WMIBUF", + "WMI_FREE_EVBUF_DATABUF", + "WMI_FREE_EVBUF_BADFLAG", + "WMI_HTC_RX_ERROR_DATA_PACKET", + "WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX", + "WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT", + "WMI_SENDING_READY_EVENT", + "WMI_SETPOWER_MDOE_TO_MAXPERF", + "WMI_SETPOWER_MDOE_TO_REC", + "WMI_BSSINFO_EVENT_FROM", + "WMI_TARGET_GET_STATS_CMD", + "WMI_SENDING_SCAN_COMPLETE_EVENT", + "WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT ", + "WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT", + "WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT", + "WMI_SENDING_ERROR_REPORT_EVENT", + "WMI_SENDING_CAC_EVENT", + "WMI_TARGET_GET_ROAM_TABLE_CMD", + "WMI_TARGET_GET_ROAM_DATA_CMD", + "WMI_SENDING_GPIO_INTR_EVENT", + "WMI_SENDING_GPIO_ACK_EVENT", + "WMI_SENDING_GPIO_DATA_EVENT", + "WMI_CMD_RX", + "WMI_CMD_RX_XTND", + "WMI_EVENT_SEND", + "WMI_EVENT_SEND_XTND", + "WMI_CMD_PARAMS_DUMP_START", + "WMI_CMD_PARAMS_DUMP_END", + "WMI_CMD_PARAMS", + "WMI_EVENT_ALLOC_FAILURE", + "WMI_DBGID_DCS_PARAM_CMD", + "WMI_SEND_EVENT_WRONG_TLV", + "WMI_SEND_EVENT_NO_TLV_DEF", + "WMI_DBGID_DEFNITION_END", + }, + { + "PS_STA_DEFINITION_START", + "PS_STA_PM_ARB_REQUEST", + "PS_STA_DELIVER_EVENT", + "PS_STA_PSPOLL_SEQ_DONE", + "PS_STA_COEX_MODE", + "PS_STA_PSPOLL_ALLOW", + "PS_STA_SET_PARAM", + "PS_STA_SPECPOLL_TIMER_STARTED", + "PS_STA_SPECPOLL_TIMER_STOPPED", + }, + { + "WHAL_DBGID_DEFINITION_START", + "WHAL_ERROR_ANI_CONTROL", + "WHAL_ERROR_CHIP_TEST1", + "WHAL_ERROR_CHIP_TEST2", + "WHAL_ERROR_EEPROM_CHECKSUM", + "WHAL_ERROR_EEPROM_MACADDR", + "WHAL_ERROR_INTERRUPT_HIU", + "WHAL_ERROR_KEYCACHE_RESET", + "WHAL_ERROR_KEYCACHE_SET", + "WHAL_ERROR_KEYCACHE_TYPE", + "WHAL_ERROR_KEYCACHE_TKIPENTRY", + "WHAL_ERROR_KEYCACHE_WEPLENGTH", + "WHAL_ERROR_PHY_INVALID_CHANNEL", + "WHAL_ERROR_POWER_AWAKE", + "WHAL_ERROR_POWER_SET", + "WHAL_ERROR_RECV_STOPDMA", + "WHAL_ERROR_RECV_STOPPCU", + "WHAL_ERROR_RESET_CHANNF1", + "WHAL_ERROR_RESET_CHANNF2", + "WHAL_ERROR_RESET_PM", + "WHAL_ERROR_RESET_OFFSETCAL", + "WHAL_ERROR_RESET_RFGRANT", + "WHAL_ERROR_RESET_RXFRAME", + "WHAL_ERROR_RESET_STOPDMA", + "WHAL_ERROR_RESET_ERRID", + "WHAL_ERROR_RESET_ADCDCCAL1", + "WHAL_ERROR_RESET_ADCDCCAL2", + "WHAL_ERROR_RESET_TXIQCAL", + "WHAL_ERROR_RESET_RXIQCAL", + "WHAL_ERROR_RESET_CARRIERLEAK", + "WHAL_ERROR_XMIT_COMPUTE", + "WHAL_ERROR_XMIT_NOQUEUE", + "WHAL_ERROR_XMIT_ACTIVEQUEUE", + "WHAL_ERROR_XMIT_BADTYPE", + "WHAL_ERROR_XMIT_STOPDMA", + "WHAL_ERROR_INTERRUPT_BB_PANIC", + "WHAL_ERROR_PAPRD_MAXGAIN_ABOVE_WINDOW", + "WHAL_ERROR_QCU_HW_PAUSE_MISMATCH", + "WHAL_DBGID_DEFINITION_END", + }, + { + "COEX_DEBUGID_START", + "BTCOEX_DBG_MCI_1", + "BTCOEX_DBG_MCI_2", + "BTCOEX_DBG_MCI_3", + "BTCOEX_DBG_MCI_4", + "BTCOEX_DBG_MCI_5", + "BTCOEX_DBG_MCI_6", + "BTCOEX_DBG_MCI_7", + "BTCOEX_DBG_MCI_8", + "BTCOEX_DBG_MCI_9", + "BTCOEX_DBG_MCI_10", + "COEX_WAL_BTCOEX_INIT", + "COEX_WAL_PAUSE", + "COEX_WAL_RESUME", + "COEX_UPDATE_AFH", + "COEX_HWQ_EMPTY_CB", + "COEX_MCI_TIMER_HANDLER", + "COEX_MCI_RECOVER", + "ERROR_COEX_MCI_ISR", + "ERROR_COEX_MCI_GPM", + "COEX_ProfileType", + "COEX_LinkID", + "COEX_LinkState", + "COEX_LinkRole", + "COEX_LinkRate", + "COEX_VoiceType", + "COEX_TInterval", + "COEX_WRetrx", + "COEX_Attempts", + "COEX_PerformanceState", + "COEX_LinkType", + "COEX_RX_MCI_GPM_VERSION_QUERY", + "COEX_RX_MCI_GPM_VERSION_RESPONSE", + "COEX_RX_MCI_GPM_STATUS_QUERY", + "COEX_STATE_WLAN_VDEV_DOWN", + "COEX_STATE_WLAN_VDEV_START", + "COEX_STATE_WLAN_VDEV_CONNECTED", + "COEX_STATE_WLAN_VDEV_SCAN_STARTED", + "COEX_STATE_WLAN_VDEV_SCAN_END", + "COEX_STATE_WLAN_DEFAULT", + "COEX_CHANNEL_CHANGE", + "COEX_POWER_CHANGE", + "COEX_CONFIG_MGR", + "COEX_TX_MCI_GPM_BT_CAL_REQ", + "COEX_TX_MCI_GPM_BT_CAL_GRANT", + "COEX_TX_MCI_GPM_BT_CAL_DONE", + "COEX_TX_MCI_GPM_WLAN_CAL_REQ", + "COEX_TX_MCI_GPM_WLAN_CAL_GRANT", + "COEX_TX_MCI_GPM_WLAN_CAL_DONE", + "COEX_TX_MCI_GPM_BT_DEBUG", + "COEX_TX_MCI_GPM_VERSION_QUERY", + "COEX_TX_MCI_GPM_VERSION_RESPONSE", + "COEX_TX_MCI_GPM_STATUS_QUERY", + "COEX_TX_MCI_GPM_HALT_BT_GPM", + "COEX_TX_MCI_GPM_WLAN_CHANNELS", + "COEX_TX_MCI_GPM_BT_PROFILE_INFO", + "COEX_TX_MCI_GPM_BT_STATUS_UPDATE", + "COEX_TX_MCI_GPM_BT_UPDATE_FLAGS", + "COEX_TX_MCI_GPM_UNKNOWN", + "COEX_TX_MCI_SYS_WAKING", + "COEX_TX_MCI_LNA_TAKE", + "COEX_TX_MCI_LNA_TRANS", + "COEX_TX_MCI_SYS_SLEEPING", + "COEX_TX_MCI_REQ_WAKE", + "COEX_TX_MCI_REMOTE_RESET", + "COEX_TX_MCI_TYPE_UNKNOWN", + "COEX_WHAL_MCI_RESET", + "COEX_POLL_BT_CAL_DONE_TIMEOUT", + "COEX_WHAL_PAUSE", + "COEX_RX_MCI_GPM_BT_CAL_REQ", + "COEX_RX_MCI_GPM_BT_CAL_DONE", + "COEX_RX_MCI_GPM_BT_CAL_GRANT", + "COEX_WLAN_CAL_START", + "COEX_WLAN_CAL_RESULT", + "COEX_BtMciState", + "COEX_BtCalState", + "COEX_WlanCalState", + "COEX_RxReqWakeCount", + "COEX_RxRemoteResetCount", + "COEX_RESTART_CAL", + "COEX_SENDMSG_QUEUE", + "COEX_RESETSEQ_LNAINFO_TIMEOUT", + "COEX_MCI_ISR_IntRaw", + "COEX_MCI_ISR_Int1Raw", + "COEX_MCI_ISR_RxMsgRaw", + "COEX_WHAL_COEX_RESET", + "COEX_WAL_COEX_INIT", + "COEX_TXRX_CNT_LIMIT_ISR", + "COEX_CH_BUSY", + "COEX_REASSESS_WLAN_STATE", + "COEX_BTCOEX_WLAN_STATE_UPDATE", + "COEX_BT_NUM_OF_PROFILES", + "COEX_BT_NUM_OF_HID_PROFILES", + "COEX_BT_NUM_OF_ACL_PROFILES", + "COEX_BT_NUM_OF_HI_ACL_PROFILES", + "COEX_BT_NUM_OF_VOICE_PROFILES", + "COEX_WLAN_AGGR_LIMIT", + "COEX_BT_LOW_PRIO_BUDGET", + "COEX_BT_HI_PRIO_BUDGET", + "COEX_BT_IDLE_TIME", + "COEX_SET_COEX_WEIGHT", + "COEX_WLAN_WEIGHT_GROUP", + "COEX_BT_WEIGHT_GROUP", + "COEX_BT_INTERVAL_ALLOC", + "COEX_BT_SCHEME", + "COEX_BT_MGR", + "COEX_BT_SM_ERROR", + "COEX_SYSTEM_UPDATE", + "COEX_LOW_PRIO_LIMIT", + "COEX_HI_PRIO_LIMIT", + "COEX_BT_INTERVAL_START", + "COEX_WLAN_INTERVAL_START", + "COEX_NON_LINK_BUDGET", + "COEX_CONTENTION_MSG", + "COEX_SET_NSS", + "COEX_SELF_GEN_MASK", + "COEX_PROFILE_ERROR", + "COEX_WLAN_INIT", + "COEX_BEACON_MISS", + "COEX_BEACON_OK", + "COEX_BTCOEX_SCAN_ACTIVITY", + "COEX_SCAN_ACTIVITY", + "COEX_FORCE_QUIETTIME", + "COEX_BT_MGR_QUIETTIME", + "COEX_BT_INACTIVITY_TRIGGER", + "COEX_BT_INACTIVITY_REPORTED", + "COEX_TX_MCI_GPM_WLAN_PRIO", + "COEX_TX_MCI_GPM_BT_PAUSE_PROFILE", + "COEX_TX_MCI_GPM_WLAN_SET_ACL_INACTIVITY", + "COEX_RX_MCI_GPM_BT_ACL_INACTIVITY_REPORT", + "COEX_GENERIC_ERROR", + "COEX_RX_RATE_THRESHOLD", + "COEX_RSSI", + "COEX_WLAN_VDEV_NOTIF_START", /* 133 */ + "COEX_WLAN_VDEV_NOTIF_UP", /* 134 */ + "COEX_WLAN_VDEV_NOTIF_DOWN", /* 135 */ + "COEX_WLAN_VDEV_NOTIF_STOP", /* 136 */ + "COEX_WLAN_VDEV_NOTIF_ADD_PEER", /* 137 */ + "COEX_WLAN_VDEV_NOTIF_DELETE_PEER", /* 138 */ + "COEX_WLAN_VDEV_NOTIF_CONNECTED_PEER", /* 139 */ + "COEX_WLAN_VDEV_NOTIF_PAUSE", /* 140 */ + "COEX_WLAN_VDEV_NOTIF_UNPAUSED", /* 141 */ + "COEX_STATE_WLAN_VDEV_PEER_ADD", /* 142 */ + "COEX_STATE_WLAN_VDEV_CONNECTED_PEER", /* 143 */ + "COEX_STATE_WLAN_VDEV_DELETE_PEER", /* 144 */ + "COEX_STATE_WLAN_VDEV_PAUSE", /* 145 */ + "COEX_STATE_WLAN_VDEV_UNPAUSED", /* 146 */ + "COEX_SCAN_CALLBACK", /* 147 */ + "COEX_RC_SET_CHAINMASK", /* 148 */ + "COEX_TX_MCI_GPM_WLAN_SET_BT_RXSS_THRES", /* 149 */ + "COEX_TX_MCI_GPM_BT_RXSS_THRES_QUERY", /* 150 */ + "COEX_BT_RXSS_THRES", /* 151 */ + "COEX_BT_PROFILE_ADD_RMV", /* 152 */ + "COEX_BT_SCHED_INFO", /* 153 */ + "COEX_TRF_MGMT", /* 154 */ + "COEX_SCHED_START", /* 155 */ + "COEX_SCHED_RESULT", /* 156 */ + "COEX_SCHED_ERROR", /* 157 */ + "COEX_SCHED_PRE_OP", /* 158 */ + "COEX_SCHED_POST_OP", /* 159 */ + "COEX_RX_RATE", /* 160 */ + "COEX_ACK_PRIORITY", /* 161 */ + "COEX_STATE_WLAN_VDEV_UP", /* 162 */ + "COEX_STATE_WLAN_VDEV_PEER_UPDATE", /* 163 */ + "COEX_STATE_WLAN_VDEV_STOP", /* 164 */ + "COEX_WLAN_PAUSE_PEER", /* 165 */ + "COEX_WLAN_UNPAUSE_PEER", /* 166 */ + "COEX_WLAN_PAUSE_INTERVAL_START", /* 167 */ + "COEX_WLAN_POSTPAUSE_INTERVAL_START", /* 168 */ + "COEX_TRF_FREERUN", /* 169 */ + "COEX_TRF_SHAPE_PM", /* 170 */ + "COEX_TRF_SHAPE_PSP", /* 171 */ + "COEX_TRF_SHAPE_S_CTS", /* 172 */ + "COEX_CHAIN_CONFIG", /* 173 */ + "COEX_SYSTEM_MONITOR", /* 174 */ + "COEX_SINGLECHAIN_INIT", /* 175 */ + "COEX_MULTICHAIN_INIT", /* 176 */ + "COEX_SINGLECHAIN_DBG_1", /* 177 */ + "COEX_SINGLECHAIN_DBG_2", /* 178 */ + "COEX_SINGLECHAIN_DBG_3", /* 179 */ + "COEX_MULTICHAIN_DBG_1", /* 180 */ + "COEX_MULTICHAIN_DBG_2", /* 181 */ + "COEX_MULTICHAIN_DBG_3", /* 182 */ + "COEX_PSP_TX_CB", /* 183 */ + "COEX_PSP_RX_CB", /* 184 */ + "COEX_PSP_STAT_1", /* 185 */ + "COEX_PSP_SPEC_POLL", /* 186 */ + "COEX_PSP_READY_STATE", /* 187 */ + "COEX_PSP_TX_STATUS_STATE", /* 188 */ + "COEX_PSP_RX_STATUS_STATE_1", /* 189 */ + "COEX_PSP_NOT_READY_STATE", /* 190 */ + "COEX_PSP_DISABLED_STATE", /* 191 */ + "COEX_PSP_ENABLED_STATE", /* 192 */ + "COEX_PSP_SEND_PSPOLL", /* 193 */ + "COEX_PSP_MGR_ENTER", /* 194 */ + "COEX_PSP_MGR_RESULT", /* 195 */ + "COEX_PSP_NONWLAN_INTERVAL", /* 196 */ + "COEX_PSP_STAT_2", /* 197 */ + "COEX_PSP_RX_STATUS_STATE_2", /* 198 */ + "COEX_PSP_ERROR", /* 199 */ + "COEX_T2BT", /* 200 */ + "COEX_BT_DURATION", /* 201 */ + "COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG", /* 202 */ + "COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG_RSP", /* 203 */ + "COEX_TX_MCI_GPM_SCAN_OP", /* 204 */ + "COEX_TX_MCI_GPM_BT_PAUSE_GPM_TX", /* 205 */ + "COEX_CTS2S_SEND", /* 206 */ + "COEX_CTS2S_RESULT", /* 207 */ + "COEX_ENTER_OCS", /* 208 */ + "COEX_EXIT_OCS", /* 209 */ + "COEX_UPDATE_OCS", /* 210 */ + "COEX_STATUS_OCS", /* 211 */ + "COEX_STATS_BT", /* 212 */ + "COEX_MWS_WLAN_INIT", + "COEX_MWS_WBTMR_SYNC", + "COEX_MWS_TYPE2_RX", + "COEX_MWS_TYPE2_TX", + "COEX_MWS_WLAN_CHAVD", + "COEX_MWS_WLAN_CHAVD_INSERT", + "COEX_MWS_WLAN_CHAVD_MERGE", + "COEX_MWS_WLAN_CHAVD_RPT", + "COEX_MWS_CP_MSG_SEND", + "COEX_MWS_CP_ESCAPE", + "COEX_MWS_CP_UNFRAME", + "COEX_MWS_CP_SYNC_UPDATE", + "COEX_MWS_CP_SYNC", + "COEX_MWS_CP_WLAN_STATE_IND", + "COEX_MWS_CP_SYNCRESP_TIMEOUT", + "COEX_MWS_SCHEME_UPDATE", + "COEX_MWS_WLAN_EVENT", + "COEX_MWS_UART_UNESCAPE", + "COEX_MWS_UART_ENCODE_SEND", + "COEX_MWS_UART_RECV_DECODE", + "COEX_MWS_UL_HDL", + "COEX_MWS_REMOTE_EVENT", + "COEX_MWS_OTHER", + "COEX_MWS_ERROR", + "COEX_MWS_ANT_DIVERSITY", /* 237 */ + "COEX_P2P_GO", + "COEX_P2P_CLIENT", + "COEX_SCC_1", + "COEX_SCC_2", + "COEX_MCC_1", + "COEX_MCC_2", + "COEX_TRF_SHAPE_NOA", + "COEX_NOA_ONESHOT", + "COEX_NOA_PERIODIC", + "COEX_LE_1", + "COEX_LE_2", + "COEX_ANT_1", + "COEX_ANT_2", + "COEX_ENTER_NOA", + "COEX_EXIT_NOA", + "COEX_BT_SCAN_PROTECT", /* 253 */ + "COEX_DEBUG_ID_END" /* 254 */ + }, + { + "ROAM_DBGID_DEFINITION_START", + "ROAM_MODULE_INIT", + "ROAM_DEV_START", + "ROAM_CONFIG_RSSI_THRESH", + "ROAM_CONFIG_SCAN_PERIOD", + "ROAM_CONFIG_AP_PROFILE", + "ROAM_CONFIG_CHAN_LIST", + "ROAM_CONFIG_SCAN_PARAMS", + "ROAM_CONFIG_RSSI_CHANGE", + "ROAM_SCAN_TIMER_START", + "ROAM_SCAN_TIMER_EXPIRE", + "ROAM_SCAN_TIMER_STOP", + "ROAM_SCAN_STARTED", + "ROAM_SCAN_COMPLETE", + "ROAM_SCAN_CANCELLED", + "ROAM_CANDIDATE_FOUND", + "ROAM_RSSI_ACTIVE_SCAN", + "ROAM_RSSI_ACTIVE_ROAM", + "ROAM_RSSI_GOOD", + "ROAM_BMISS_FIRST_RECV", + "ROAM_DEV_STOP", + "ROAM_FW_OFFLOAD_ENABLE", + "ROAM_CANDIDATE_SSID_MATCH", + "ROAM_CANDIDATE_SECURITY_MATCH", + "ROAM_LOW_RSSI_INTERRUPT", + "ROAM_HIGH_RSSI_INTERRUPT", + "ROAM_SCAN_REQUESTED", + "ROAM_BETTER_CANDIDATE_FOUND", + "ROAM_BETTER_AP_EVENT", + "ROAM_CANCEL_LOW_PRIO_SCAN", + "ROAM_FINAL_BMISS_RECVD", + "ROAM_CONFIG_SCAN_MODE", + "ROAM_BMISS_FINAL_SCAN_ENABLE", + "ROAM_SUITABLE_AP_EVENT", + "ROAM_RSN_IE_PARSE_ERROR", + "ROAM_WPA_IE_PARSE_ERROR", + "ROAM_SCAN_CMD_FROM_HOST", + "ROAM_HO_SORT_CANDIDATE", + "ROAM_HO_SAVE_CANDIDATE", + "ROAM_HO_GET_CANDIDATE", + "ROAM_HO_OFFLOAD_SET_PARAM", + "ROAM_HO_SM", + "ROAM_HO_HTT_SAVED", + "ROAM_HO_SYNC_START", + "ROAM_HO_START", + "ROAM_HO_COMPLETE", + "ROAM_HO_STOP", + "ROAM_HO_HTT_FORWARD", + "ROAM_DBGID_DEFINITION_END" + }, + { + "RESMGR_CHMGR_DEFINITION_START", + "RESMGR_CHMGR_PAUSE_COMPLETE", + "RESMGR_CHMGR_CHANNEL_CHANGE", + "RESMGR_CHMGR_RESUME_COMPLETE", + "RESMGR_CHMGR_VDEV_PAUSE", + "RESMGR_CHMGR_VDEV_UNPAUSE", + "RESMGR_CHMGR_CTS2S_TX_COMP", + "RESMGR_CHMGR_CFEND_TX_COMP", + "RESMGR_CHMGR_DEFINITION_END" + }, + { + "RESMGR_DEFINITION_START", + "RESMGR_OCS_ALLOCRAM_SIZE", + "RESMGR_OCS_RESOURCES", + "RESMGR_LINK_CREATE", + "RESMGR_LINK_DELETE", + "RESMGR_OCS_CHREQ_CREATE", + "RESMGR_OCS_CHREQ_DELETE", + "RESMGR_OCS_CHREQ_START", + "RESMGR_OCS_CHREQ_STOP", + "RESMGR_OCS_SCHEDULER_INVOKED", + "RESMGR_OCS_CHREQ_GRANT", + "RESMGR_OCS_CHREQ_COMPLETE", + "RESMGR_OCS_NEXT_TSFTIME", + "RESMGR_OCS_TSF_TIMEOUT_US", + "RESMGR_OCS_CURR_CAT_WINDOW", + "RESMGR_OCS_CURR_CAT_WINDOW_REQ", + "RESMGR_OCS_CURR_CAT_WINDOW_TIMESLOT", + "RESMGR_OCS_CHREQ_RESTART", + "RESMGR_OCS_CLEANUP_CH_ALLOCATORS", + "RESMGR_OCS_PURGE_CHREQ", + "RESMGR_OCS_CH_ALLOCATOR_FREE", + "RESMGR_OCS_RECOMPUTE_SCHEDULE", + "RESMGR_OCS_NEW_CAT_WINDOW_REQ", + "RESMGR_OCS_NEW_CAT_WINDOW_TIMESLOT", + "RESMGR_OCS_CUR_CH_ALLOC", + "RESMGR_OCS_WIN_CH_ALLOC", + "RESMGR_OCS_SCHED_CH_CHANGE", + "RESMGR_OCS_CONSTRUCT_CAT_WIN", + "RESMGR_OCS_CHREQ_PREEMPTED", + "RESMGR_OCS_CH_SWITCH_REQ", + "RESMGR_OCS_CHANNEL_SWITCHED", + "RESMGR_OCS_CLEANUP_STALE_REQS", + "RESMGR_OCS_CHREQ_UPDATE", + "RESMGR_OCS_REG_NOA_NOTIF", + "RESMGR_OCS_DEREG_NOA_NOTIF", + "RESMGR_OCS_GEN_PERIODIC_NOA", + "RESMGR_OCS_RECAL_QUOTAS", + "RESMGR_OCS_GRANTED_QUOTA_STATS", + "RESMGR_OCS_ALLOCATED_QUOTA_STATS", + "RESMGR_OCS_REQ_QUOTA_STATS", + "RESMGR_OCS_TRACKING_TIME_FIRED", + "RESMGR_VC_ARBITRATE_ATTRIBUTES", + "RESMGR_OCS_LATENCY_STRICT_TIME_SLOT", + "RESMGR_OCS_CURR_TSF", + "RESMGR_OCS_QUOTA_REM", + "RESMGR_OCS_LATENCY_CASE_NO", + "RESMGR_OCS_WIN_CAT_DUR", + "RESMGR_VC_UPDATE_CUR_VC", + "RESMGR_VC_REG_UNREG_LINK", + "RESMGR_VC_PRINT_LINK", + "RESMGR_OCS_MISS_TOLERANCE", + "RESMGR_DYN_SCH_ALLOCRAM_SIZE", + "RESMGR_DYN_SCH_ENABLE", + "RESMGR_DYN_SCH_ACTIVE", + "RESMGR_DYN_SCH_CH_STATS_START", + "RESMGR_DYN_SCH_CH_SX_STATS", + "RESMGR_DYN_SCH_TOT_UTIL_PER", + "RESMGR_DYN_SCH_HOME_CH_QUOTA", + "RESMGR_OCS_REG_RECAL_QUOTA_NOTIF", + "RESMGR_OCS_DEREG_RECAL_QUOTA_NOTIF", + "RESMGR_DEFINITION_END" + }, + { + "VDEV_MGR_DEBID_DEFINITION_START", /* vdev Mgr */ + "VDEV_MGR_FIRST_BEACON_MISS_DETECTED", + "VDEV_MGR_FINAL_BEACON_MISS_DETECTED", + "VDEV_MGR_BEACON_IN_SYNC", + "VDEV_MGR_AP_KEEPALIVE_IDLE", + "VDEV_MGR_AP_KEEPALIVE_INACTIVE", + "VDEV_MGR_AP_KEEPALIVE_UNRESPONSIVE", + "VDEV_MGR_AP_TBTT_CONFIG", + "VDEV_MGR_FIRST_BCN_RECEIVED", + "VDEV_MGR_VDEV_START", + "VDEV_MGR_VDEV_UP", + "VDEV_MGR_PEER_AUTHORIZED", + "VDEV_MGR_OCS_HP_LP_REQ_POSTED", + "VDEV_MGR_VDEV_START_OCS_HP_REQ_COMPLETE", + "VDEV_MGR_VDEV_START_OCS_HP_REQ_STOP", + "VDEV_MGR_HP_START_TIME", + "VDEV_MGR_VDEV_PAUSE_DELAY_UPDATE", + "VDEV_MGR_VDEV_PAUSE_FAIL", + "VDEV_MGR_GEN_PERIODIC_NOA", + "VDEV_MGR_OFF_CHAN_GO_CH_REQ_SETUP", + "VDEV_MGR_DEFINITION_END", + }, + { + "SCAN_START_COMMAND_FAILED", /* scan */ + "SCAN_STOP_COMMAND_FAILED", + "SCAN_EVENT_SEND_FAILED", + "SCAN_ENGINE_START", + "SCAN_ENGINE_CANCEL_COMMAND", + "SCAN_ENGINE_STOP_DUE_TO_TIMEOUT", + "SCAN_EVENT_SEND_TO_HOST", + "SCAN_FWLOG_EVENT_ADD", + "SCAN_FWLOG_EVENT_REM", + "SCAN_FWLOG_EVENT_PREEMPTED", + "SCAN_FWLOG_EVENT_RESTARTED", + "SCAN_FWLOG_EVENT_COMPLETED", + }, + { + "RATECTRL_DBGID_DEFINITION_START", /* Rate ctrl */ + "RATECTRL_DBGID_ASSOC", + "RATECTRL_DBGID_NSS_CHANGE", + "RATECTRL_DBGID_CHAINMASK_ERR", + "RATECTRL_DBGID_UNEXPECTED_FRAME", + "RATECTRL_DBGID_WAL_RCQUERY", + "RATECTRL_DBGID_WAL_RCUPDATE", + "RATECTRL_DBGID_GTX_UPDATE", + "RATECTRL_DBGID_DEFINITION_END" + }, + { + "AP_PS_DBGID_DEFINITION_START", + "AP_PS_DBGID_UPDATE_TIM", + "AP_PS_DBGID_PEER_STATE_CHANGE", + "AP_PS_DBGID_PSPOLL", + "AP_PS_DBGID_PEER_CREATE", + "AP_PS_DBGID_PEER_DELETE", + "AP_PS_DBGID_VDEV_CREATE", + "AP_PS_DBGID_VDEV_DELETE", + "AP_PS_DBGID_SYNC_TIM", + "AP_PS_DBGID_NEXT_RESPONSE", + "AP_PS_DBGID_START_SP", + "AP_PS_DBGID_COMPLETED_EOSP", + "AP_PS_DBGID_TRIGGER", + "AP_PS_DBGID_DUPLICATE_TRIGGER", + "AP_PS_DBGID_UAPSD_RESPONSE", + "AP_PS_DBGID_SEND_COMPLETE", + "AP_PS_DBGID_SEND_N_COMPLETE", + "AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA", + "AP_PS_DBGID_DELIVER_CAB", + }, + { + "" /* Block Ack */ + }, + /* Mgmt TxRx */ + { + "MGMT_TXRX_DBGID_DEFINITION_START", + "MGMT_TXRX_FORWARD_TO_HOST", + "MGMT_TXRX_DBGID_DEFINITION_END", + }, + { /* Data TxRx */ + "DATA_TXRX_DBGID_DEFINITION_START", + "DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO", + "DATA_TXRX_DBGID_DEFINITION_END", + }, + {"" /* HTT */ + }, + {"" /* HOST */ + }, + {"" /* BEACON */ + "BEACON_EVENT_SWBA_SEND_FAILED", + "BEACON_EVENT_EARLY_RX_BMISS_STATUS", + "BEACON_EVENT_EARLY_RX_SLEEP_SLOP", + "BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT", + "BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM", + "BEACON_EVENT_EARLY_RX_CLK_DRIFT", + "BEACON_EVENT_EARLY_RX_AP_DRIFT", + "BEACON_EVENT_EARLY_RX_BCN_TYPE",}, + { /* Offload Mgr */ + "OFFLOAD_MGR_DBGID_DEFINITION_START", + "OFFLOADMGR_REGISTER_OFFLOAD", + "OFFLOADMGR_DEREGISTER_OFFLOAD", + "OFFLOADMGR_NO_REG_DATA_HANDLERS", + "OFFLOADMGR_NO_REG_EVENT_HANDLERS", + "OFFLOADMGR_REG_OFFLOAD_FAILED", + "OFFLOADMGR_DBGID_DEFINITION_END", + }, + { + "WAL_DBGID_DEFINITION_START", + "WAL_DBGID_FAST_WAKE_REQUEST", + "WAL_DBGID_FAST_WAKE_RELEASE", + "WAL_DBGID_SET_POWER_STATE", + "WAL_DBGID_MISSING", + "WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET", + "WAL_DBGID_CHANNEL_CHANGE", + "WAL_DBGID_VDEV_START", + "WAL_DBGID_VDEV_STOP", + "WAL_DBGID_VDEV_UP", + "WAL_DBGID_VDEV_DOWN", + "WAL_DBGID_SW_WDOG_RESET", + "WAL_DBGID_TX_SCH_REGISTER_TIDQ", + "WAL_DBGID_TX_SCH_UNREGISTER_TIDQ", + "WAL_DBGID_TX_SCH_TICKLE_TIDQ", + "WAL_DBGID_XCESS_FAILURES", + "WAL_DBGID_AST_ADD_WDS_ENTRY", + "WAL_DBGID_AST_DEL_WDS_ENTRY", + "WAL_DBGID_AST_WDS_ENTRY_PEER_CHG", + "WAL_DBGID_AST_WDS_SRC_LEARN_FAIL", + "WAL_DBGID_STA_KICKOUT", + "WAL_DBGID_BAR_TX_FAIL", + "WAL_DBGID_BAR_ALLOC_FAIL", + "WAL_DBGID_LOCAL_DATA_TX_FAIL", + "WAL_DBGID_SECURITY_PM4_QUEUED", + "WAL_DBGID_SECURITY_GM1_QUEUED", + "WAL_DBGID_SECURITY_PM4_SENT", + "WAL_DBGID_SECURITY_ALLOW_DATA", + "WAL_DBGID_SECURITY_UCAST_KEY_SET", + "WAL_DBGID_SECURITY_MCAST_KEY_SET", + "WAL_DBGID_SECURITY_ENCR_EN", + "WAL_DBGID_BB_WDOG_TRIGGERED", + "WAL_DBGID_RX_LOCAL_BUFS_LWM", + "WAL_DBGID_RX_LOCAL_DROP_LARGE_MGMT", + "WAL_DBGID_VHT_ILLEGAL_RATE_PHY_ERR_DETECTED", + "WAL_DBGID_DEV_RESET", + "WAL_DBGID_TX_BA_SETUP", + "WAL_DBGID_RX_BA_SETUP", + "WAL_DBGID_DEV_TX_TIMEOUT", + "WAL_DBGID_DEV_RX_TIMEOUT", + "WAL_DBGID_STA_VDEV_XRETRY", + "WAL_DBGID_DCS", + "WAL_DBGID_MGMT_TX_FAIL", + "WAL_DBGID_SET_M4_SENT_MANUALLY", + "WAL_DBGID_PROCESS_4_WAY_HANDSHAKE", + "WAL_DBGID_WAL_CHANNEL_CHANGE_START", + "WAL_DBGID_WAL_CHANNEL_CHANGE_COMPLETE", + "WAL_DBGID_WHAL_CHANNEL_CHANGE_START", + "WAL_DBGID_WHAL_CHANNEL_CHANGE_COMPLETE", + "WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN", + "WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN", + "WAL_DBGID_TX_DISCARD", + "WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS", + "WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS", + "WAL_DBGID_RESET_PCU_CYCLE_CNT", + "WAL_DBGID_SETUP_RSSI_INTERRUPTS", + "WAL_DBGID_BRSSI_CONFIG", + "WAL_DBGID_CURRENT_BRSSI_AVE", + "WAL_DBGID_BCN_TX_COMP", + "WAL_DBGID_SET_HW_CHAINMASK", + "WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL", + "WAL_DBGID_GET_HW_CHAINMASK", + "WAL_DBGID_SMPS_DISABLE", + "WAL_DBGID_SMPS_ENABLE_HW_CNTRL", + "WAL_DBGID_SMPS_SWSEL_CHAINMASK", + "WAL_DBGID_DEFINITION_END", + }, + { + "" /* DE */ + }, + { + "" /* pcie lp */ + }, + { + /* RTT */ + "RTT_CALL_FLOW", + "RTT_REQ_SUB_TYPE", + "RTT_MEAS_REQ_HEAD", + "RTT_MEAS_REQ_BODY", + "", + "", + "RTT_INIT_GLOBAL_STATE", + "", + "RTT_REPORT", + "", + "RTT_ERROR_REPORT", + "RTT_TIMER_STOP", + "RTT_SEND_TM_FRAME", + "RTT_V3_RESP_CNT", + "RTT_V3_RESP_FINISH", + "RTT_CHANNEL_SWITCH_REQ", + "RTT_CHANNEL_SWITCH_GRANT", + "RTT_CHANNEL_SWITCH_COMPLETE", + "RTT_CHANNEL_SWITCH_PREEMPT", + "RTT_CHANNEL_SWITCH_STOP", + "RTT_TIMER_START", + }, + { /* RESOURCE */ + "RESOURCE_DBGID_DEFINITION_START", + "RESOURCE_PEER_ALLOC", + "RESOURCE_PEER_FREE", + "RESOURCE_PEER_ALLOC_WAL_PEER", + "RESOURCE_PEER_NBRHOOD_MGMT_ALLOC", + "RESOURCE_PEER_NBRHOOD_MGMT_INFO," "RESOURCE_DBGID_DEFINITION_END", + }, + { /* DCS */ + "WLAN_DCS_DBGID_INIT", + "WLAN_DCS_DBGID_WMI_CWINT", + "WLAN_DCS_DBGID_TIMER", + "WLAN_DCS_DBGID_CMDG", + "WLAN_DCS_DBGID_CMDS", + "WLAN_DCS_DBGID_DINIT" + }, + { /* CACHEMGR */ + "" + }, + { /* ANI */ + "ANI_DBGID_POLL", + "ANI_DBGID_CONTROL", + "ANI_DBGID_OFDM_PARAMS", + "ANI_DBGID_CCK_PARAMS", + "ANI_DBGID_RESET", + "ANI_DBGID_RESTART", + "ANI_DBGID_OFDM_LEVEL", + "ANI_DBGID_CCK_LEVEL", + "ANI_DBGID_FIRSTEP", + "ANI_DBGID_CYCPWR", + "ANI_DBGID_MRC_CCK", + "ANI_DBGID_SELF_CORR_LOW", + "ANI_DBGID_ENABLE", + "ANI_DBGID_CURRENT_LEVEL", + "ANI_DBGID_POLL_PERIOD", + "ANI_DBGID_LISTEN_PERIOD", + "ANI_DBGID_OFDM_LEVEL_CFG", + "ANI_DBGID_CCK_LEVEL_CFG" + }, + { + "P2P_DBGID_DEFINITION_START", + "P2P_DEV_REGISTER", + "P2P_HANDLE_NOA", + "P2P_UPDATE_SCHEDULE_OPPS", + "P2P_UPDATE_SCHEDULE", + "P2P_UPDATE_START_TIME", + "P2P_UPDATE_START_TIME_DIFF_TSF32", + "P2P_UPDATE_START_TIME_FINAL", + "P2P_SETUP_SCHEDULE_TIMER", + "P2P_PROCESS_SCHEDULE_AFTER_CALC", + "P2P_PROCESS_SCHEDULE_STARTED_TIMER", + "P2P_CALC_SCHEDULES_FIRST_CALL_ALL_NEXT_EVENT", + "P2P_CALC_SCHEDULES_FIRST_VALUE", + "P2P_CALC_SCHEDULES_EARLIEST_NEXT_EVENT", + "P2P_CALC_SCHEDULES_SANITY_COUNT", + "P2P_CALC_SCHEDULES_CALL_ALL_NEXT_EVENT_FROM_WHILE_LOOP", + "P2P_CALC_SCHEDULES_TIMEOUT_1", + "P2P_CALC_SCHEDULES_TIMEOUT_2", + "P2P_FIND_ALL_NEXT_EVENTS_REQ_EXPIRED", + "P2P_FIND_ALL_NEXT_EVENTS_REQ_ACTIVE", + "P2P_FIND_NEXT_EVENT_REQ_NOT_STARTED", + "P2P_FIND_NEXT_EVENT_REQ_COMPLETE_NON_PERIODIC", + "P2P_FIND_NEXT_EVENT_IN_MID_OF_NOA", + "P2P_FIND_NEXT_EVENT_REQ_COMPLETE", + "P2P_SCHEDULE_TIMEOUT", + "P2P_CALC_SCHEDULES_ENTER", + "P2P_PROCESS_SCHEDULE_ENTER", + "P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_AFTER_CHANGE", + "P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_BEFORE_CHANGE", + "P2P_FIND_ALL_NEXT_EVENTS_ENTER", + "P2P_FIND_NEXT_EVENT_ENTER", + "P2P_NOA_GO_PRESENT", + "P2P_NOA_GO_ABSENT", + "P2P_GO_NOA_NOTIF", + "P2P_GO_TBTT_OFFSET", + "P2P_GO_GET_NOA_INFO", + "P2P_GO_ADD_ONE_SHOT_NOA", + "P2P_GO_GET_NOA_IE", + "P2P_GO_BCN_TX_COMP", + "P2P_DBGID_DEFINITION_END", + }, + { + "CSA_DBGID_DEFINITION_START", + "CSA_OFFLOAD_POOL_INIT", + "CSA_OFFLOAD_REGISTER_VDEV", + "CSA_OFFLOAD_DEREGISTER_VDEV", + "CSA_DEREGISTER_VDEV_ERROR", + "CSA_OFFLOAD_BEACON_RECEIVED", + "CSA_OFFLOAD_BEACON_CSA_RECV", + "CSA_OFFLOAD_CSA_RECV_ERROR_IE", + "CSA_OFFLOAD_CSA_TIMER_ERROR", + "CSA_OFFLOAD_CSA_TIMER_EXP", + "CSA_OFFLOAD_WMI_EVENT_ERROR", + "CSA_OFFLOAD_WMI_EVENT_SENT", + "CSA_OFFLOAD_WMI_CHANSWITCH_RECV", + "CSA_DBGID_DEFINITION_END", + }, + { /* NLO offload */ + "" + }, + { + "WLAN_CHATTER_DBGID_DEFINITION_START", + "WLAN_CHATTER_ENTER", + "WLAN_CHATTER_EXIT", + "WLAN_CHATTER_FILTER_HIT", + "WLAN_CHATTER_FILTER_MISS", + "WLAN_CHATTER_FILTER_FULL", + "WLAN_CHATTER_FILTER_TM_ADJ", + "WLAN_CHATTER_BUFFER_FULL", + "WLAN_CHATTER_TIMEOUT", + "WLAN_CHATTER_DBGID_DEFINITION_END", + }, + { + "WOW_DBGID_DEFINITION_START", + "WOW_ENABLE_CMDID", + "WOW_RECV_DATA_PKT", + "WOW_WAKE_HOST_DATA", + "WOW_RECV_MGMT", + "WOW_WAKE_HOST_MGMT", + "WOW_RECV_EVENT", + "WOW_WAKE_HOST_EVENT", + "WOW_INIT", + "WOW_RECV_MAGIC_PKT", + "WOW_RECV_BITMAP_PATTERN", + "WOW_AP_VDEV_DISALLOW", + "WOW_STA_VDEV_DISALLOW", + "WOW_P2PGO_VDEV_DISALLOW", + "WOW_NS_OFLD_ENABLE", + "WOW_ARP_OFLD_ENABLE", + "WOW_NS_ARP_OFLD_DISABLE", + "WOW_NS_RECEIVED", + "WOW_NS_REPLIED", + "WOW_ARP_RECEIVED", + "WOW_ARP_REPLIED", + "WOW_DBGID_DEFINITION_END", + }, + { /* WAL VDEV */ + "" + }, + { /* WAL PDEV */ + "" + }, + { /* TEST */ + "TP_CHANGE_CHANNEL", + "TP_LOCAL_SEND", + }, + { /* STA SMPS */ + "STA_SMPS_DBGID_DEFINITION_START", + "STA_SMPS_DBGID_CREATE_PDEV_INSTANCE", + "STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE", + "STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE", + "STA_SMPS_DBGID_CREATE_STA_INSTANCE", + "STA_SMPS_DBGID_DELETE_STA_INSTANCE", + "STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START", + "STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP", + "STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME", + "STA_SMPS_DBGID_HOST_FORCED_MODE", + "STA_SMPS_DBGID_FW_FORCED_MODE", + "STA_SMPS_DBGID_RSSI_THRESHOLD_CROSSED", + "STA_SMPS_DBGID_SMPS_ACTION_FRAME_COMPLETION", + "STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE", + "SMPS_DBGID_DEFINITION_END", + }, + { /* SWBMISS */ + "SWBMISS_DBGID_DEFINITION_START", + "SWBMISS_ENABLED", + "SWBMISS_DISABLED", + "SWBMISS_DBGID_DEFINITION_END", + }, + { /* WMMAC */ + "" + }, + { /* TDLS */ + "TDLS_DBGID_DEFINITION_START", + "TDLS_DBGID_VDEV_CREATE", + "TDLS_DBGID_VDEV_DELETE", + "TDLS_DBGID_ENABLED_PASSIVE", + "TDLS_DBGID_ENABLED_ACTIVE", + "TDLS_DBGID_DISABLED", + "TDLS_DBGID_CONNTRACK_TIMER", + "TDLS_DBGID_WAL_SET", + "TDLS_DBGID_WAL_GET", + "TDLS_DBGID_WAL_PEER_UPDATE_SET", + "TDLS_DBGID_WAL_PEER_UPDATE_EVT", + "TDLS_DBGID_WAL_VDEV_CREATE", + "TDLS_DBGID_WAL_VDEV_DELETE", + "TDLS_DBGID_WLAN_EVENT", + "TDLS_DBGID_WLAN_PEER_UPDATE_SET", + "TDLS_DBGID_PEER_EVT_DRP_THRESH", + "TDLS_DBGID_PEER_EVT_DRP_RATE", + "TDLS_DBGID_PEER_EVT_DRP_RSSI", + "TDLS_DBGID_PEER_EVT_DISCOVER", + "TDLS_DBGID_PEER_EVT_DELETE", + "TDLS_DBGID_PEER_CAP_UPDATE", + "TDLS_DBGID_UAPSD_SEND_PTI_FRAME", + "TDLS_DBGID_UAPSD_SEND_PTI_FRAME2PEER", + "TDLS_DBGID_UAPSD_START_PTR_TIMER", + "TDLS_DBGID_UAPSD_CANCEL_PTR_TIMER", + "TDLS_DBGID_UAPSD_PTR_TIMER_TIMEOUT", + "TDLS_DBGID_UAPSD_STA_PS_EVENT_HANDLER", + "TDLS_DBGID_UAPSD_PEER_EVENT_HANDLER", + "TDLS_DBGID_UAPSD_PS_DEFAULT_SETTINGS", + "TDLS_DBGID_UAPSD_GENERIC", + }, + { /* HB */ + "WLAN_HB_DBGID_DEFINITION_START", + "WLAN_HB_DBGID_INIT", + "WLAN_HB_DBGID_TCP_GET_TXBUF_FAIL", + "WLAN_HB_DBGID_TCP_SEND_FAIL", + "WLAN_HB_DBGID_BSS_PEER_NULL", + "WLAN_HB_DBGID_UDP_GET_TXBUF_FAIL", + "WLAN_HB_DBGID_UDP_SEND_FAIL", + "WLAN_HB_DBGID_WMI_CMD_INVALID_PARAM", + "WLAN_HB_DBGID_WMI_CMD_INVALID_OP", + "WLAN_HB_DBGID_WOW_NOT_ENTERED", + "WLAN_HB_DBGID_ALLOC_SESS_FAIL", + "WLAN_HB_DBGID_CTX_NULL", + "WLAN_HB_DBGID_CHKSUM_ERR", + "WLAN_HB_DBGID_UDP_TX", + "WLAN_HB_DBGID_TCP_TX", + "WLAN_HB_DBGID_DEFINITION_END", + }, + { /* TXBF */ + "TXBFEE_DBGID_START", + "TXBFEE_DBGID_NDPA_RECEIVED", + "TXBFEE_DBGID_HOST_CONFIG_TXBFEE_TYPE", + "TXBFER_DBGID_SEND_NDPA", + "TXBFER_DBGID_GET_NDPA_BUF_FAIL", + "TXBFER_DBGID_SEND_NDPA_FAIL", + "TXBFER_DBGID_GET_NDP_BUF_FAIL", + "TXBFER_DBGID_SEND_NDP_FAIL", + "TXBFER_DBGID_GET_BRPOLL_BUF_FAIL", + "TXBFER_DBGID_SEND_BRPOLL_FAIL", + "TXBFER_DBGID_HOST_CONFIG_CMDID", + "TXBFEE_DBGID_HOST_CONFIG_CMDID", + "TXBFEE_DBGID_ENABLED_ENABLED_UPLOAD_H", + "TXBFEE_DBGID_UPLOADH_CV_TAG", + "TXBFEE_DBGID_UPLOADH_H_TAG", + "TXBFEE_DBGID_CAPTUREH_RECEIVED", + "TXBFEE_DBGID_PACKET_IS_STEERED", + "TXBFEE_UPLOADH_EVENT_ALLOC_MEM_FAIL", + "TXBFEE_DBGID_END", + }, + { /*BATCH SCAN */ + }, + { /*THERMAL MGR */ + "THERMAL_MGR_DBGID_DEFINITION_START", + "THERMAL_MGR_NEW_THRESH", + "THERMAL_MGR_THRESH_CROSSED", + "THERMAL_MGR_DBGID_DEFINITION END", + }, + { /* WLAN_MODULE_PHYERR_DFS */ + "" + }, + { + /* WLAN_MODULE_RMC */ + "RMC_DBGID_DEFINITION_START", + "RMC_CREATE_INSTANCE", + "RMC_DELETE_INSTANCE", + "RMC_LDR_SEL", + "RMC_NO_LDR", + "RMC_LDR_NOT_SEL", + "RMC_LDR_INF_SENT", + "RMC_PEER_ADD", + "RMC_PEER_DELETE", + "RMC_PEER_UNKNOWN", + "RMC_SET_MODE", + "RMC_SET_ACTION_PERIOD", + "RMC_ACRION_FRAME_RX", + "RMC_DBGID_DEFINITION_END", + }, + { + /* WLAN_MODULE_STATS */ + "WLAN_STATS_DBGID_DEFINITION_START", + "WLAN_STATS_DBGID_EST_LINKSPEED_VDEV_EN_DIS", + "WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_START", + "WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_END", + "WLAN_STATS_DBGID_EST_LINKSPEED_CALC", + "WLAN_STATS_DBGID_EST_LINKSPEED_UPDATE_HOME_CHAN", + "WLAN_STATS_DBGID_DEFINITION_END", + }, + { + /* WLAN_MODULE_NAN */ + }, + { + /* WLAN_MODULE_IBSS_PWRSAVE */ + "IBSS_PS_DBGID_DEFINITION_START", + "IBSS_PS_DBGID_PEER_CREATE", + "IBSS_PS_DBGID_PEER_DELETE", + "IBSS_PS_DBGID_VDEV_CREATE", + "IBSS_PS_DBGID_VDEV_DELETE", + "IBSS_PS_DBGID_VDEV_EVENT", + "IBSS_PS_DBGID_PEER_EVENT", + "IBSS_PS_DBGID_DELIVER_CAB", + "IBSS_PS_DBGID_DELIVER_UC_DATA", + "IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR", + "IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART", + "IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART", + "IBSS_PS_DBGID_NULL_TX_COMPLETION", + "IBSS_PS_DBGID_ATIM_TIMER_START", + "IBSS_PS_DBGID_UC_ATIM_SEND", + "IBSS_PS_DBGID_BC_ATIM_SEND", + "IBSS_PS_DBGID_UC_TIMEOUT", + "IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED", + "IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED", + "IBSS_PS_DBGID_SET_PARAM", + "IBSS_PS_DBGID_HOST_TX_PAUSE", + "IBSS_PS_DBGID_HOST_TX_UNPAUSE", + "IBSS_PS_DBGID_PS_DESC_BIN_HWM", + "IBSS_PS_DBGID_PS_DESC_BIN_LWM", + "IBSS_PS_DBGID_PS_KICKOUT_PEER", + "IBSS_PS_DBGID_SET_PEER_PARAM", + "IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH", + "IBSS_PS_DBGID_RX_CHAINMASK_CHANGE", + }, + { + /* HIF UART Interface DBGIDs */ + "HIF_UART_DBGID_START", + "HIF_UART_DBGID_POWER_STATE", + "HIF_UART_DBGID_TXRX_FLOW", + "HIF_UART_DBGID_TXRX_CTRL_CHAR", + "HIF_UART_DBGID_TXRX_BUF_DUMP", + }, + { + /* LPI */ + "" + }, + { + /* EXTSCAN DBGIDs */ + "EXTSCAN_START", + "EXTSCAN_STOP", + "EXTSCAN_CLEAR_ENTRY_CONTENT", + "EXTSCAN_GET_FREE_ENTRY_SUCCESS", + "EXTSCAN_GET_FREE_ENTRY_INCONSISTENT", + "EXTSCAN_GET_FREE_ENTRY_NO_MORE_ENTRIES", + "EXTSCAN_CREATE_ENTRY_SUCCESS", + "EXTSCAN_CREATE_ENTRY_ERROR", + "EXTSCAN_SEARCH_SCAN_ENTRY_QUEUE", + "EXTSCAN_SEARCH_SCAN_ENTRY_KEY_FOUND", + "EXTSCAN_SEARCH_SCAN_ENTRY_KEY_NOT_FOUND", + "EXTSCAN_ADD_ENTRY", + "EXTSCAN_BUCKET_SEND_OPERATION_EVENT", + "EXTSCAN_BUCKET_SEND_OPERATION_EVENT_FAILED", + "EXTSCAN_BUCKET_START_SCAN_CYCLE", + "EXTSCAN_BUCKET_PERIODIC_TIMER", + "EXTSCAN_SEND_START_STOP_EVENT", + "EXTSCAN_NOTIFY_WLAN_CHANGE", + "EXTSCAN_NOTIFY_WLAN_HOTLIST_MATCH", + "EXTSCAN_MAIN_RECEIVED_FRAME", + "EXTSCAN_MAIN_NO_SSID_IE", + "EXTSCAN_MAIN_MALFORMED_FRAME", + "EXTSCAN_FIND_BSSID_BY_REFERENCE", + "EXTSCAN_FIND_BSSID_BY_REFERENCE_ERROR", + "EXTSCAN_NOTIFY_TABLE_USAGE", + "EXTSCAN_FOUND_RSSI_ENTRY", + "EXTSCAN_BSSID_FOUND_RSSI_SAMPLE", + "EXTSCAN_BSSID_ADDED_RSSI_SAMPLE", + "EXTSCAN_BSSID_REPLACED_RSSI_SAMPLE", + "EXTSCAN_BSSID_TRANSFER_CURRENT_SAMPLES", + "EXTSCAN_BUCKET_PROCESS_SCAN_EVENT", + "EXTSCAN_BUCKET_CANNOT_FIND_BUCKET", + "EXTSCAN_START_SCAN_REQUEST_FAILED", + "EXTSCAN_BUCKET_STOP_CURRENT_SCANS", + "EXTSCAN_BUCKET_SCAN_STOP_REQUEST", + "EXTSCAN_BUCKET_PERIODIC_TIMER_ERROR", + "EXTSCAN_BUCKET_START_OPERATION", + "EXTSCAN_START_INTERNAL_ERROR", + "EXTSCAN_NOTIFY_HOTLIST_MATCH", + "EXTSCAN_CONFIG_HOTLIST_TABLE", + "EXTSCAN_CONFIG_WLAN_CHANGE_TABLE", + }, + { /* UNIT_TEST */ + "UNIT_TEST_GEN", + }, + { /* MLME */ + "MLME_DEBUG_CMN", + "MLME_IF", + "MLME_AUTH", + "MLME_REASSOC", + "MLME_DEAUTH", + "MLME_DISASSOC", + "MLME_ROAM", + "MLME_RETRY", + "MLME_TIMER", + "MLME_FRMPARSE", + }, + { /*SUPPLICANT */ + "SUPPL_INIT", + "SUPPL_RECV_EAPOL", + "SUPPL_RECV_EAPOL_TIMEOUT", + "SUPPL_SEND_EAPOL", + "SUPPL_MIC_MISMATCH", + "SUPPL_FINISH", + }, +}; + +int dbglog_module_log_enable(wmi_unified_t wmi_handle, A_UINT32 mod_id, + bool isenable) +{ + A_UINT32 val = 0; + + if (mod_id > WLAN_MODULE_ID_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_module_log_enable: Invalid module id %d\n", + mod_id)); + return -EINVAL; + } + + WMI_DBGLOG_SET_MODULE_ID(val, mod_id); + if (isenable) { + /* set it to global module level */ + WMI_DBGLOG_SET_LOG_LEVEL(val, DBGLOG_INFO); + } else { + /* set it to ERROR level */ + WMI_DBGLOG_SET_LOG_LEVEL(val, DBGLOG_ERR); + } + wmi_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + val, NULL, 0); + + return 0; +} + +int dbglog_vap_log_enable(wmi_unified_t wmi_handle, A_UINT16 vap_id, + bool isenable) +{ + if (vap_id > DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_vap_log_enable:Invalid vap_id %d\n", + vap_id)); + return -EINVAL; + } + + wmi_config_debug_module_cmd(wmi_handle, + isenable ? WMI_DEBUG_LOG_PARAM_VDEV_ENABLE : + WMI_DEBUG_LOG_PARAM_VDEV_DISABLE, vap_id, + NULL, 0); + + return 0; +} + +int dbglog_set_log_lvl(wmi_unified_t wmi_handle, DBGLOG_LOG_LVL log_lvl) +{ + A_UINT32 val = 0; + + if (log_lvl > DBGLOG_LVL_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_set_log_lvl:Invalid log level %d\n", + log_lvl)); + return -EINVAL; + } + + WMI_DBGLOG_SET_MODULE_ID(val, WMI_DEBUG_LOG_MODULE_ALL); + WMI_DBGLOG_SET_LOG_LEVEL(val, log_lvl); + wmi_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + val, NULL, 0); + + return 0; +} + +int dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, A_UINT32 mod_log_lvl) +{ + A_UINT32 val = 0; + /* set the global module level to log_lvl */ + WMI_DBGLOG_SET_MODULE_ID(val, (mod_log_lvl / 10)); + WMI_DBGLOG_SET_LOG_LEVEL(val, (mod_log_lvl % 10)); + wmi_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + val, NULL, 0); + + return 0; +} + +A_STATUS +wmi_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len) +{ + wmi_buf_t buf; + wmi_debug_log_config_cmd_fixed_param *configmsg; + A_STATUS status = A_OK; + int i; + int len; + int8_t *buf_ptr; + int32_t *module_id_bitmap_array; /* Used to fomr the second tlv */ + + ASSERT(bitmap_len < MAX_MODULE_ID_BITMAP_WORDS); + + /* Allocate size for 2 tlvs - including tlv hdr space for second tlv */ + len = sizeof(wmi_debug_log_config_cmd_fixed_param) + WMI_TLV_HDR_SIZE + + (sizeof(int32_t) * MAX_MODULE_ID_BITMAP_WORDS); + buf = wmi_buf_alloc(wmi_handle, len); + if (buf == NULL) + return A_NO_MEMORY; + + configmsg = + (wmi_debug_log_config_cmd_fixed_param *) (wmi_buf_data(buf)); + buf_ptr = (int8_t *) configmsg; + WMITLV_SET_HDR(&configmsg->tlv_header, + WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_debug_log_config_cmd_fixed_param)); + configmsg->dbg_log_param = param; + configmsg->value = val; + /* Filling in the data part of second tlv -- should follow first tlv _ WMI_TLV_HDR_SIZE */ + module_id_bitmap_array = (A_UINT32 *) (buf_ptr + + sizeof + (wmi_debug_log_config_cmd_fixed_param) + + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(buf_ptr + sizeof(wmi_debug_log_config_cmd_fixed_param), + WMITLV_TAG_ARRAY_UINT32, + sizeof(A_UINT32) * MAX_MODULE_ID_BITMAP_WORDS); + if (module_id_bitmap) { + for (i = 0; i < bitmap_len; ++i) { + module_id_bitmap_array[i] = module_id_bitmap[i]; + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("wmi_dbg_cfg_send: param 0x%x val 0x%x \n ", param, + val)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_DBGLOG_CFG_CMDID); + + if (status != A_OK) + cdf_nbuf_free(buf); + + return status; +} + +void +dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 vap_enable_bitmap) +{ + wmi_config_debug_module_cmd(wmi_handle, + WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP, + vap_enable_bitmap, NULL, 0); +} + +void +dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle, A_UINT32 log_level, + A_UINT32 *mod_enable_bitmap, A_UINT32 bitmap_len) +{ + wmi_config_debug_module_cmd(wmi_handle, + WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP, + log_level, mod_enable_bitmap, bitmap_len); +} + +int dbglog_report_enable(wmi_unified_t wmi_handle, bool isenable) +{ + int bitmap[2] = { 0 }; + + if (isenable > true) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_report_enable:Invalid value %d\n", + isenable)); + return -EINVAL; + } + + if (isenable) { + /* set the vap enable bitmap */ + dbglog_set_vap_enable_bitmap(wmi_handle, 0xFFFF); + bitmap[0] = 0xFFFFFFFF; + bitmap[1] = 0x1F; + /* set the module level bitmap */ + dbglog_set_mod_enable_bitmap(wmi_handle, 0x0, bitmap, 2); + } else { + dbglog_set_vap_enable_bitmap(wmi_handle, bitmap[0]); + dbglog_set_mod_enable_bitmap(wmi_handle, DBGLOG_LVL_MAX, bitmap, + 2); + } + return 0; +} + +static char *dbglog_get_msg(A_UINT32 moduleid, A_UINT32 debugid) +{ + static char unknown_str[64]; + + if (moduleid < WLAN_MODULE_ID_MAX && debugid < MAX_DBG_MSGS) { + char *str = DBG_MSG_ARR[moduleid][debugid]; + if (str && str[0] != '\0') { + return str; + } + } + + snprintf(unknown_str, sizeof(unknown_str), + "UNKNOWN %u:%u", moduleid, debugid); + + return unknown_str; +} + +void dbglog_printf(A_UINT32 timestamp, A_UINT16 vap_id, const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u ", timestamp, + vap_id)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] ", timestamp)); + } + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s\n", buf)); +} + +void +dbglog_printf_no_line_break(A_UINT32 timestamp, + A_UINT16 vap_id, const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u ", timestamp, + vap_id)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] ", timestamp)); + } + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s", buf)); +} + +#define USE_NUMERIC 0 + +A_BOOL +dbglog_default_print_handler(A_UINT32 mod_id, A_UINT16 vap_id, A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, + A_UINT32 *args) +{ + int i; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u %s ( ", + timestamp, vap_id, dbglog_get_msg(mod_id, + dbg_id))); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] %s ( ", timestamp, + dbglog_get_msg(mod_id, dbg_id))); + } + + for (i = 0; i < numargs; i++) { +#if USE_NUMERIC + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%u", args[i])); +#else + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%#x", args[i])); +#endif + if ((i + 1) < numargs) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (", ")); + } + } + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (" )\n")); + + return true; +} + +#define DBGLOG_PARSE_ARGS_STRING_LENGTH (DBGLOG_NUM_ARGS_MAX * 11 + 10) +static int dbglog_print_raw_data(A_UINT32 *buffer, A_UINT32 length) +{ + A_UINT32 timestamp; + A_UINT32 debugid; + A_UINT32 moduleid; + A_UINT16 numargs, curArgs; + A_UINT32 count = 0, totalWriteLen, writeLen; + char parseArgsString[DBGLOG_PARSE_ARGS_STRING_LENGTH]; + char *dbgidString; + + while (count < length) { + + debugid = DBGLOG_GET_DBGID(buffer[count + 1]); + moduleid = DBGLOG_GET_MODULEID(buffer[count + 1]); + numargs = DBGLOG_GET_NUMARGS(buffer[count + 1]); + timestamp = DBGLOG_GET_TIME_STAMP(buffer[count]); + + if (moduleid < WLAN_MODULE_ID_MAX && debugid < MAX_DBG_MSGS + && numargs <= DBGLOG_NUM_ARGS_MAX) { + + OS_MEMZERO(parseArgsString, sizeof(parseArgsString)); + totalWriteLen = 0; + + for (curArgs = 0; curArgs < numargs; curArgs++) { + /* Using sprintf_s instead of sprintf, to avoid length overflow */ + writeLen = + snprintf(parseArgsString + totalWriteLen, + DBGLOG_PARSE_ARGS_STRING_LENGTH - + totalWriteLen, "%x ", + buffer[count + 2 + curArgs]); + totalWriteLen += writeLen; + } + + if (debugid < MAX_DBG_MSGS) { + dbgidString = DBG_MSG_ARR[moduleid][debugid]; + if (dbgidString != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s(%x %x):%s\n", + dbgidString, timestamp, + buffer[count + 1], + parseArgsString)); + } else { + /* host need sync with FW id */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "UNKNOWN", moduleid, + debugid, timestamp, + buffer[count + 1], + parseArgsString)); + } + } else if (debugid == + DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG) { + /* specific debugid */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "DBGLOG_SM_MSG", moduleid, + debugid, timestamp, + buffer[count + 1], + parseArgsString)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "UNKNOWN", moduleid, debugid, + timestamp, buffer[count + 1], + parseArgsString)); + } + } + + count += numargs + 2; /* 32 bit Time stamp + 32 bit Dbg header */ + } + + return 0; + +} + +#ifdef WLAN_OPEN_SOURCE +static int +dbglog_debugfs_raw_data(wmi_unified_t wmi_handle, const uint8_t *buf, + A_UINT32 length, A_UINT32 dropped) +{ + struct fwdebug *fwlog = (struct fwdebug *)&wmi_handle->dbglog; + struct dbglog_slot *slot; + struct sk_buff *skb; + size_t slot_len; + + if (WARN_ON(length > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; + + skb = alloc_skb(slot_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + slot = (struct dbglog_slot *)skb_put(skb, slot_len); + slot->diag_type = (A_UINT32) DIAG_TYPE_FW_DEBUG_MSG; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(length); + slot->dropped = cpu_to_le32(dropped); + memcpy(slot->payload, buf, length); + + /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ + memset(slot->payload + length, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - length); + + spin_lock(&fwlog->fwlog_queue.lock); + + __skb_queue_tail(&fwlog->fwlog_queue, skb); + + complete(&fwlog->fwlog_completion); + + /* drop oldest entries */ + while (skb_queue_len(&fwlog->fwlog_queue) > ATH6KL_FWLOG_MAX_ENTRIES) { + skb = __skb_dequeue(&fwlog->fwlog_queue); + kfree_skb(skb); + } + + spin_unlock(&fwlog->fwlog_queue.lock); + + return true; +} +#endif /* WLAN_OPEN_SOURCE */ + +/* + * Package the data from the fw diag WMI event handler. + * Pass this data to cnss-diag service + */ +int +send_fw_diag_nl_data(wmi_unified_t wmi_handle, const uint8_t *buffer, + A_UINT32 len, A_UINT32 event_type) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + if (cds_is_multicast_logging()) { + skb_out = nlmsg_new(len, 0); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -1; + } + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, len, 0); + memcpy(nlmsg_data(nlh), buffer, len); + + res = nl_srv_bcast(skb_out); + if (res < 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_bcast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +static int +send_diag_netlink_data(const uint8_t *buffer, A_UINT32 len, A_UINT32 cmd) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + struct dbglog_slot *slot; + size_t slot_len; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + if (cds_is_multicast_logging()) { + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; + + skb_out = nlmsg_new(slot_len, 0); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, + slot_len, 0); + slot = (struct dbglog_slot *)nlmsg_data(nlh); + slot->diag_type = cmd; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + /* Version mapped to get_version here */ + slot->dropped = get_version; + memcpy(slot->payload, buffer, len); + + res = nl_srv_bcast(skb_out); + if (res < 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_bcast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +int +dbglog_process_netlink_data(wmi_unified_t wmi_handle, const uint8_t *buffer, + A_UINT32 len, A_UINT32 dropped) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + struct dbglog_slot *slot; + size_t slot_len; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + if (cds_is_multicast_logging()) { + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; + + skb_out = nlmsg_new(slot_len, 0); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, + slot_len, 0); + slot = (struct dbglog_slot *)nlmsg_data(nlh); + slot->diag_type = (A_UINT32) DIAG_TYPE_FW_DEBUG_MSG; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + slot->dropped = cpu_to_le32(dropped); + memcpy(slot->payload, buffer, len); + + res = nl_srv_bcast(skb_out); + if (res < 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_ucast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +/* + * WMI diag data event handler, this function invoked as a CB + * when there DIAG_EVENT, DIAG_MSG, DIAG_DBG to be + * forwarded from the FW. This is the new implementation for + * replacement of fw_dbg and dbg messages + */ + +static int diag_fw_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + + tp_wma_handle wma = (tp_wma_handle) scn; + wmitlv_cmd_param_info *param_buf; + uint8_t *datap; + uint32_t len = 0; + uint32_t *buffer; + + if (!wma) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NULL Pointer assigned\n")); + return -1; + } + /* when fw asser occurs,host can't use TLV format. */ + if (wma->is_fw_assert) { + datap = data; + len = datalen; + wma->is_fw_assert = 0; + } else { + param_buf = (wmitlv_cmd_param_info *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Get NULL point message from FW\n")); + return -1; + } + + param_buf = (wmitlv_cmd_param_info *) data; + datap = param_buf->tlv_ptr; + len = param_buf->num_elements; + if (!get_version) { + buffer = (uint32_t *) datap; + buffer++; /* skip offset */ + if (WLAN_DIAG_TYPE_CONFIG == DIAG_GET_TYPE(*buffer)) { + buffer++; /* skip */ + if (DIAG_VERSION_INFO == DIAG_GET_ID(*buffer)) { + buffer++; /* skip */ + /* get payload */ + get_version = *buffer; + } + } + } + } + if (dbglog_process_type == DBGLOG_PROCESS_PRINT_RAW) { + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + return 0; + } + + if (dbglog_process_type == DBGLOG_PROCESS_NET_RAW) { + return send_diag_netlink_data((A_UINT8 *) datap, + len, DIAG_TYPE_FW_MSG); + } +#ifdef WLAN_OPEN_SOURCE + if (dbglog_process_type == DBGLOG_PROCESS_POOL_RAW) { + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + return 0; + } +#endif /* WLAN_OPEN_SOURCE */ + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + /* Always returns zero */ + return (0); +} + +/* + * WMI diag data event handler, this function invoked as a CB + * when there DIAG_DATA to be forwarded from the FW. + */ + +int fw_diag_data_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + + tp_wma_handle wma = (tp_wma_handle) scn; + struct wlan_diag_data *diag_data; + WMI_DIAG_DATA_CONTAINER_EVENTID_param_tlvs *param_buf; + wmi_diag_data_container_event_fixed_param *fixed_param; + uint8_t *datap; + uint32_t num_data = 0; /* Total events */ + uint32_t diag_data_len = 0; /* each fw diag payload */ + uint32_t diag_type = 0; + uint32_t i = 0; + uint32_t nl_data_len = 0; /* diag hdr + payload */ + + param_buf = (WMI_DIAG_DATA_CONTAINER_EVENTID_param_tlvs *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Got NULL point message from FW\n")); + return -1; + } + + if (!wma) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NULL Pointer assigned\n")); + return -1; + } + + fixed_param = param_buf->fixed_param; + num_data = param_buf->num_bufp; + + datap = (uint8_t *) param_buf->bufp; + + /* If cnss-diag service started triggered during the init of services */ + if (appstarted) { + for (i = 0; i < num_data; i++) { + diag_data = (struct wlan_diag_data *)datap; + diag_type = WLAN_DIAG_0_TYPE_GET(diag_data->word0); + diag_data_len = WLAN_DIAG_0_LEN_GET(diag_data->word0); + + /* Length of diag struct and len of payload */ + nl_data_len = + sizeof(struct wlan_diag_data) + diag_data_len; +#if 0 + print_hex_dump_bytes("payload: ", DUMP_PREFIX_ADDRESS, + diag_data->payload, diag_data_len); +#endif + switch (diag_type) { + case DIAG_TYPE_FW_EVENT: + return send_fw_diag_nl_data((wmi_unified_t) + wma->wmi_handle, + datap, nl_data_len, + diag_type); + break; + case DIAG_TYPE_FW_LOG: + return send_fw_diag_nl_data((wmi_unified_t) + wma->wmi_handle, + datap, nl_data_len, + diag_type); + break; + } + /* Move to the next event and send to cnss-diag */ + datap += nl_data_len; + } + } + return 0; +} + +int dbglog_parse_debug_logs(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) scn; + A_UINT32 count; + A_UINT32 *buffer; + A_UINT32 timestamp; + A_UINT32 debugid; + A_UINT32 moduleid; + A_UINT16 vapid; + A_UINT16 numargs; + cdf_size_t length; + A_UINT32 dropped; + WMI_DEBUG_MESG_EVENTID_param_tlvs *param_buf; + uint8_t *datap; + uint32_t len; + + if (!wma) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NULL Pointer assigned\n")); + return -1; + } + /*when fw asser occurs,host can't use TLV format. */ + if (wma->is_fw_assert) { + datap = data; + len = datalen; + wma->is_fw_assert = 0; + } else { + param_buf = (WMI_DEBUG_MESG_EVENTID_param_tlvs *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Get NULL point message from FW\n")); + return -1; + } + + datap = param_buf->bufp; + len = param_buf->num_bufp; + } + + dropped = *((A_UINT32 *) datap); + if (dropped > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%d log buffers are dropped \n", dropped)); + } + datap += sizeof(dropped); + len -= sizeof(dropped); + + count = 0; + buffer = (A_UINT32 *) datap; + length = (len >> 2); + + if (dbglog_process_type == DBGLOG_PROCESS_PRINT_RAW) { + return dbglog_print_raw_data(buffer, length); + } + + if (dbglog_process_type == DBGLOG_PROCESS_NET_RAW) { + if (appstarted) { + return dbglog_process_netlink_data((wmi_unified_t) wma-> + wmi_handle, + (A_UINT8 *) buffer, + len, dropped); + } else { + return 0; + } + + } +#ifdef WLAN_OPEN_SOURCE + if (dbglog_process_type == DBGLOG_PROCESS_POOL_RAW) { + return dbglog_debugfs_raw_data((wmi_unified_t) wma->wmi_handle, + (A_UINT8 *) buffer, len, + dropped); + } +#endif /* WLAN_OPEN_SOURCE */ + + while ((count + 2) < length) { + timestamp = DBGLOG_GET_TIME_STAMP(buffer[count]); + debugid = DBGLOG_GET_DBGID(buffer[count + 1]); + moduleid = DBGLOG_GET_MODULEID(buffer[count + 1]); + vapid = DBGLOG_GET_VDEVID(buffer[count + 1]); + numargs = DBGLOG_GET_NUMARGS(buffer[count + 1]); + + if ((count + 2 + numargs) > length) + return 0; + + if (moduleid >= WLAN_MODULE_ID_MAX) + return 0; + + if (mod_print[moduleid] == NULL) { + /* No module specific log registered use the default handler */ + dbglog_default_print_handler(moduleid, vapid, debugid, + timestamp, numargs, + (((A_UINT32 *) buffer) + + 2 + count)); + } else { + if (! + (mod_print[moduleid] + (moduleid, vapid, debugid, timestamp, numargs, + (((A_UINT32 *) buffer) + 2 + count)))) { + /* The message is not handled by the module specific handler */ + dbglog_default_print_handler(moduleid, vapid, + debugid, timestamp, + numargs, + (((A_UINT32 *) + buffer) + 2 + + count)); + + } + } + + count += numargs + 2; /* 32 bit Time stamp + 32 bit Dbg header */ + } + /* Always returns zero */ + return (0); +} + +void dbglog_reg_modprint(A_UINT32 mod_id, module_dbg_print printfn) +{ + if (!mod_print[mod_id]) { + mod_print[mod_id] = printfn; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("module print is already registered for this module %d\n", + mod_id)); + } +} + +void +dbglog_sm_print(A_UINT32 timestamp, + A_UINT16 vap_id, + A_UINT16 numargs, + A_UINT32 *args, + const char *module_prefix, + const char *states[], A_UINT32 num_states, + const char *events[], A_UINT32 num_events) +{ + A_UINT8 type, arg1, arg2, arg3; + A_UINT32 extra, extra2, extra3; + + if (numargs != 4) { + return; + } + + type = (args[0] >> 24) & 0xff; + arg1 = (args[0] >> 16) & 0xff; + arg2 = (args[0] >> 8) & 0xff; + arg3 = (args[0] >> 0) & 0xff; + + extra = args[1]; + extra2 = args[2]; + extra3 = args[3]; + + switch (type) { + case 0: /* state transition */ + if (arg1 < num_states && arg2 < num_states) { + dbglog_printf(timestamp, vap_id, + "%s: %s => %s (%#x, %#x, %#x)", + module_prefix, states[arg1], states[arg2], + extra, extra2, extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %u => %u (%#x, %#x, %#x)", + module_prefix, arg1, arg2, extra, extra2, + extra3); + } + break; + case 1: /* dispatch event */ + if (arg1 < num_states && arg2 < num_events) { + dbglog_printf(timestamp, vap_id, + "%s: %s < %s (%#x, %#x, %#x)", + module_prefix, states[arg1], events[arg2], + extra, extra2, extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %u < %u (%#x, %#x, %#x)", + module_prefix, arg1, arg2, extra, extra2, + extra3); + } + break; + case 2: /* warning */ + switch (arg1) { + case 0: /* unhandled event */ + if (arg2 < num_states && arg3 < num_events) { + dbglog_printf(timestamp, vap_id, + "%s: unhandled event %s in state %s (%#x, %#x, %#x)", + module_prefix, events[arg3], + states[arg2], extra, extra2, + extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: unhandled event %u in state %u (%#x, %#x, %#x)", + module_prefix, arg3, arg2, extra, + extra2, extra3); + } + break; + default: + break; + + } + break; + } +} + +A_BOOL +dbglog_sta_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "IDLE", + "ACTIVE", + "SLEEP_TXQ_FLUSH", + "SLEEP_TX_SENT", + "PAUSE", + "SLEEP_DOZE", + "SLEEP_AWAKE", + "ACTIVE_TXQ_FLUSH", + "ACTIVE_TX_SENT", + "PAUSE_TXQ_FLUSH", + "PAUSE_TX_SENT", + "IDLE_TXQ_FLUSH", + "IDLE_TX_SENT", + }; + + static const char *events[] = { + "START", + "STOP", + "PAUSE", + "UNPAUSE", + "TIM", + "DTIM", + "SEND_COMPLETE", + "PRE_SEND", + "RX", + "HWQ_EMPTY", + "PAUSE_TIMEOUT", + "TXRX_INACTIVITY_TIMEOUT", + "PSPOLL_TIMEOUT", + "UAPSD_TIMEOUT", + "DELAYED_SLEEP_TIMEOUT", + "SEND_N_COMPLETE", + "TIDQ_PAUSE_COMPLETE", + "SEND_PSPOLL", + "SEND_SPEC_PSPOLL", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "STA PS", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + case PS_STA_PM_ARB_REQUEST: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "PM ARB request flags=%x, last_time=%x %s: %s", + args[1], args[2], + dbglog_get_module_str(args[0]), + args[3] ? "SLEEP" : "WAKE"); + } + break; + case PS_STA_DELIVER_EVENT: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, "STA PS: %s %s", + (args[0] == 0 ? "PAUSE_COMPLETE" : + (args[0] == 1 ? "UNPAUSE_COMPLETE" : + (args[0] == 2 ? "SLEEP" : + (args[0] == + 3 ? "AWAKE" : "UNKNOWN")))), + (args[1] == + 0 ? "SUCCESS" : (args[1] == + 1 ? "TXQ_FLUSH_TIMEOUT" + : (args[1] == + 2 ? "NO_ACK" + : (args[1] == + 3 ? + "RX_LEAK_TIMEOUT" + : (args[1] == + 4 ? + "PSPOLL_UAPSD_BUSY_TIMEOUT" + : + "UNKNOWN")))))); + } + break; + case PS_STA_PSPOLL_SEQ_DONE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "STA PS poll: queue=%u comp=%u rsp=%u rsp_dur=%u fc=%x qos=%x %s", + args[0], args[1], args[2], args[3], + (args[4] >> 16) & 0xffff, + (args[4] >> 8) & 0xff, + (args[4] & 0xff) == + 0 ? "SUCCESS" : (args[4] & 0xff) == + 1 ? "NO_ACK" : (args[4] & 0xff) == + 2 ? "DROPPED" : (args[4] & 0xff) == + 3 ? "FILTERED" : (args[4] & 0xff) == + 4 ? "RSP_TIMEOUT" : "UNKNOWN"); + } + break; + case PS_STA_COEX_MODE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, "STA PS COEX MODE %s", + args[0] ? "ENABLED" : "DISABLED"); + } + break; + case PS_STA_PSPOLL_ALLOW: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "STA PS-Poll %s flags=%x time=%u", + args[0] ? "ALLOW" : "DISALLOW", args[1], + args[2]); + } + break; + case PS_STA_SET_PARAM: + if (numargs == 2) { + struct { + char *name; + int is_time_param; + } params[] = { + { + "MAX_SLEEP_ATTEMPTS", 0 + }, { + "DELAYED_SLEEP", 1 + }, { + "TXRX_INACTIVITY", 1 + }, { + "MAX_TX_BEFORE_WAKE", 0 + }, { + "UAPSD_TIMEOUT", 1 + }, { + "UAPSD_CONFIG", 0 + }, { + "PSPOLL_RESPONSE_TIMEOUT", 1 + }, { + "MAX_PSPOLL_BEFORE_WAKE", 0 + }, { + "RX_WAKE_POLICY", 0 + }, { + "DELAYED_PAUSE_RX_LEAK", 1 + }, { + "TXRX_INACTIVITY_BLOCKED_RETRY", 1 + }, { + "SPEC_WAKE_INTERVAL", 1 + }, { + "MAX_SPEC_NODATA_PSPOLL", 0 + }, { + "ESTIMATED_PSPOLL_RESP_TIME", 1 + }, { + "QPOWER_MAX_PSPOLL_BEFORE_WAKE", 0 + }, { + "QPOWER_ENABLE", 0 + }, + }; + A_UINT32 param = args[0]; + A_UINT32 value = args[1]; + + if (param < CDF_ARRAY_SIZE(params)) { + if (params[param].is_time_param) { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %s => %u (us)", + params[param].name, + value); + } else { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %s => %#x", + params[param].name, + value); + } + } else { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %x => %#x", + param, value); + } + } + break; + case PS_STA_SPECPOLL_TIMER_STARTED: + dbglog_printf(timestamp, vap_id, + "SPEC Poll Timer Started: Beacon time Remaining:%d wakeup interval:%d", + args[0], args[1]); + break; + case PS_STA_SPECPOLL_TIMER_STOPPED: + dbglog_printf(timestamp, vap_id, "SPEC Poll Timer Stopped"); + break; + default: + return false; + } + + return true; +} + +/* IBSS PS sub modules */ +enum wlan_ibss_ps_sub_module { + WLAN_IBSS_PS_SUB_MODULE_IBSS_NW_SM = 0, + WLAN_IBSS_PS_SUB_MODULE_IBSS_SELF_PS = 1, + WLAN_IBSS_PS_SUB_MODULE_IBSS_PEER_PS = 2, + WLAN_IBSS_PS_SUB_MODULE_MAX = 3, +}; + +#define WLAN_IBSS_PS_SUB_MODULE_OFFSET 0x1E + +A_BOOL +dbglog_ibss_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *nw_states[] = { + "WAIT_FOR_TBTT", + "ATIM_WINDOW_PRE_BCN", + "ATIM_WINDOW_POST_BCN", + "OUT_OF_ATIM_WINDOW", + "PAUSE_PENDING", + "PAUSED", + }; + + static const char *ps_states[] = { + "ACTIVE", + "SLEEP_TX_SEND", + "SLEEP_DOZE_PAUSE_PENDING", + "SLEEP_DOZE", + "SLEEP_AWAKE", + "ACTIVE_TX_SEND", + "PAUSE_TX_SEND", + "PAUSED", + }; + + static const char *peer_ps_states[] = { + "ACTIVE", + "SLEEP_AWAKE", + "SLEEP_DOZE", + "PS_UNKNOWN", + }; + + static const char *events[] = { + "START", + "STOP", + "SWBA", + "TBTT", + "TX_BCN_CMP", + "SEND_COMPLETE", + "SEND_N_COMPLETE", + "PRE_SEND", + "RX", + "UC_INACTIVITY_TIMEOUT", + "BC_INACTIVITY_TIMEOUT", + "ATIM_WINDOW_BEGIN", + "ATIM_WINDOW_END", + "HWQ_EMPTY", + "UC_ATIM_RCVD", + "TRAFFIC_EXCHANGE_DONE", + "POWER_SAVE_STATE_CHANGE", + "NEW_PEER_JOIN", + "IBSS_VDEV_PAUSE_REQUEST", + "IBSS_VDEV_PAUSE_RESPONSE", + "IBSS_VDEV_PAUSE_TIMEOUT", + "IBSS_VDEV_UNPAUSE_REQUEST", + "PS_STATE_CHANGE", + }; + + enum wlan_ibss_ps_sub_module sub_module; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + sub_module = (args[1] >> WLAN_IBSS_PS_SUB_MODULE_OFFSET) & 0x3; + switch (sub_module) { + case WLAN_IBSS_PS_SUB_MODULE_IBSS_NW_SM: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS NW", nw_states, + CDF_ARRAY_SIZE(nw_states), events, + CDF_ARRAY_SIZE(events)); + break; + case WLAN_IBSS_PS_SUB_MODULE_IBSS_SELF_PS: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS Self", ps_states, + CDF_ARRAY_SIZE(ps_states), events, + CDF_ARRAY_SIZE(events)); + break; + case WLAN_IBSS_PS_SUB_MODULE_IBSS_PEER_PS: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS Peer", peer_ps_states, + CDF_ARRAY_SIZE(peer_ps_states), events, + CDF_ARRAY_SIZE(events)); + break; + default: + break; + } + break; + case IBSS_PS_DBGID_PEER_CREATE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: peer alloc failed for peer ID:%u", + args[0]); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: create peer ID=%u", args[0]); + } + break; + case IBSS_PS_DBGID_PEER_DELETE: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: delete peer ID=%u num_peers:%d num_sleeping_peers:%d ps_enabled_for_this_peer:%d", + args[0], args[1], args[2], args[3]); + } + break; + case IBSS_PS_DBGID_VDEV_CREATE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev alloc failed", args[0]); + } else if (numargs == 0) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev created"); + } + break; + case IBSS_PS_DBGID_VDEV_DELETE: + dbglog_printf(timestamp, vap_id, "IBSS PS: vdev deleted"); + break; + + case IBSS_PS_DBGID_VDEV_EVENT: + if (numargs == 1) { + if (args[0] == 5) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event for peer add"); + } else if (args[0] == 7) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event for peer delete"); + } else { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event %u", + args[0]); + } + } + break; + + case IBSS_PS_DBGID_PEER_EVENT: + if (numargs == 4) { + if (args[0] == 0xFFFF) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: pre_send for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x20000) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: send_complete for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x10) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: send_n_complete for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x40) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: rx event for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: hw_q_empty for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } + } + break; + + case IBSS_PS_DBGID_DELIVER_CAB: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver CAB n_mpdu:%d send_flags:%0x tid_cur:%d q_depth_for_other_tid:%d", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_DELIVER_UC_DATA: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver UC data peer:%d tid:%d n_mpdu:%d send_flags:%0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver UC data error peer:%d tid:%d allowed_tidmask:%0x, pending_tidmap:%0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: UC timer restart peer:%d timer_val:%0x", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: MC timer restart timer_val:%0x", + args[0]); + } + break; + + case IBSS_PS_DBGID_NULL_TX_COMPLETION: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: null tx completion peer:%d tx_completion_status:%d flags:%0x", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_ATIM_TIMER_START: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: ATIM timer start tsf:%0x %0x tbtt:%0x %0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_UC_ATIM_SEND: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Send ATIM to peer:%d", args[1]); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: no peers to send UC ATIM", + args[1]); + } + break; + + case IBSS_PS_DBGID_BC_ATIM_SEND: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: MC Data, num_of_peers:%d bc_atim_sent:%d", + args[1], args[0]); + } + break; + + case IBSS_PS_DBGID_UC_TIMEOUT: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: UC timeout for peer:%d send_null:%d", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED: + dbglog_printf(timestamp, vap_id, + "IBSS PS: allow power collapse"); + break; + + case IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED: + if (numargs == 0) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by INI"); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed since peer id:%d is not PS capable", + args[0]); + } else if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed - no peers in NW"); + } else if (numargs == 3) { + if (args[0] == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed, non-zero qdepth %d %d", + args[1], args[2]); + } else if (args[0] == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by peer:%d peer_flags:%0x", + args[1], args[2]); + } + } else if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by state m/c nw_cur_state:%d nw_next_state:%d ps_cur_state:%d flags:%0x", + args[1], args[2], args[3], args[4]); + } + break; + + case IBSS_PS_DBGID_SET_PARAM: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Set Param ID:%0x Value:%0x", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_HOST_TX_PAUSE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Pausing host, vdev_map:%0x", + args[0]); + } + break; + + case IBSS_PS_DBGID_HOST_TX_UNPAUSE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Unpausing host, vdev_map:%0x", + args[0]); + } + break; + case IBSS_PS_DBGID_PS_DESC_BIN_LWM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: LWM, vdev_map:%0x", args[0]); + } + break; + + case IBSS_PS_DBGID_PS_DESC_BIN_HWM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: HWM, vdev_map:%0x", args[0]); + } + break; + + case IBSS_PS_DBGID_PS_KICKOUT_PEER: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Kickout peer id:%d atim_fail_cnt:%d status:%d", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_SET_PEER_PARAM: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Set Peer Id:%d Param ID:%0x Value:%0x", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH: + if (numargs == 4) { + if (args[0] == 0xDEAD) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: ATIM window length mismatch, our's:%d, peer id:%d, peer's:%d", + args[1], args[2], args[3]); + } else if (args[0] == 0xBEEF) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Peer ATIM window length changed, peer id:%d, peer recorded atim window:%d new atim window:%d", + args[1], args[2], args[3]); + } + } + break; + + case IBSS_PS_DBGID_RX_CHAINMASK_CHANGE: + if (numargs == 2) { + if (args[1] == 0x1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Voting for low power chainmask from :%d", + args[0]); + } else { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Voting for high power chainmask from :%d", + args[0]); + } + } + break; + + default: + return false; + } + + return true; +} + +A_BOOL dbglog_ratectrl_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case RATECTRL_DBGID_ASSOC: + dbglog_printf(timestamp, vap_id, + "RATE: ChainMask %d, phymode %d, ni_flags 0x%08x, vht_mcs_set 0x%04x, ht_mcs_set 0x%04x", + args[0], args[1], args[2], args[3], args[4]); + break; + case RATECTRL_DBGID_NSS_CHANGE: + dbglog_printf(timestamp, vap_id, "RATE: NEW NSS %d\n", args[0]); + break; + case RATECTRL_DBGID_CHAINMASK_ERR: + dbglog_printf(timestamp, vap_id, + "RATE: Chainmask ERR %d %d %d\n", args[0], + args[1], args[2]); + break; + case RATECTRL_DBGID_UNEXPECTED_FRAME: + dbglog_printf(timestamp, vap_id, + "RATE: WARN1: rate %d flags 0x%08x\n", args[0], + args[1]); + break; + case RATECTRL_DBGID_WAL_RCQUERY: + dbglog_printf(timestamp, vap_id, + "ratectrl_dbgid_wal_rcquery [rix1 %d rix2 %d rix3 %d proberix %d ppduflag 0x%x] ", + args[0], args[1], args[2], args[3], args[4]); + break; + case RATECTRL_DBGID_WAL_RCUPDATE: + dbglog_printf(timestamp, vap_id, + "ratectrl_dbgid_wal_rcupdate [numelems %d ppduflag 0x%x] ", + args[0], args[1]); + break; + case RATECTRL_DBGID_GTX_UPDATE: + { + switch (args[0]) { + case 255: + dbglog_printf(timestamp, vap_id, + "GtxInitPwrCfg [bw[last %d|cur %d] rtcode 0x%x tpc %d tpc_init_pwr_cfg %d] ", + args[1] >> 8, args[1] & 0xff, + args[2], args[3], args[4]); + break; + case 254: + dbglog_printf(timestamp, vap_id, + "gtx_cfg_addr [RTMask0@0x%x PERThreshold@0x%x gtxTPCMin@0x%x userGtxMask@0x%x] ", + args[1], args[2], args[3], + args[4]); + break; + default: + dbglog_printf(timestamp, vap_id, + "gtx_update [act %d bw %d rix 0x%x tpc %d per %d lastrssi %d] ", + args[0], args[1], args[2], + args[3], args[4], args[5]); + } + } + break; + } + return true; +} + +A_BOOL dbglog_ani_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case ANI_DBGID_ENABLE: + dbglog_printf(timestamp, vap_id, "ANI Enable: %d", args[0]); + break; + case ANI_DBGID_POLL: + dbglog_printf(timestamp, vap_id, + "ANI POLLING: AccumListenTime %d ListenTime %d ofdmphyerr %d cckphyerr %d", + args[0], args[1], args[2], args[3]); + break; + case ANI_DBGID_RESTART: + dbglog_printf(timestamp, vap_id, "ANI Restart"); + break; + case ANI_DBGID_CURRENT_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI CURRENT LEVEL ofdm level %d cck level %d", + args[0], args[1]); + break; + case ANI_DBGID_OFDM_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI UPDATE ofdm level %d firstep %d firstep_low %d cycpwr_thr %d self_corr_low %d", + args[0], args[1], args[2], args[3], args[4]); + break; + case ANI_DBGID_CCK_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI UPDATE cck level %d firstep %d firstep_low %d mrc_cck %d", + args[0], args[1], args[2], args[3]); + break; + case ANI_DBGID_CONTROL: + dbglog_printf(timestamp, vap_id, + "ANI CONTROL ofdmlevel %d ccklevel %d\n", + args[0]); + + break; + case ANI_DBGID_OFDM_PARAMS: + dbglog_printf(timestamp, vap_id, + "ANI ofdm_control firstep %d cycpwr %d\n", + args[0], args[1]); + break; + case ANI_DBGID_CCK_PARAMS: + dbglog_printf(timestamp, vap_id, + "ANI cck_control mrc_cck %d barker_threshold %d\n", + args[0], args[1]); + break; + case ANI_DBGID_RESET: + dbglog_printf(timestamp, vap_id, + "ANI resetting resetflag %d resetCause %8x channel index %d", + args[0], args[1], args[2]); + break; + case ANI_DBGID_SELF_CORR_LOW: + dbglog_printf(timestamp, vap_id, "ANI self_corr_low %d", + args[0]); + break; + case ANI_DBGID_FIRSTEP: + dbglog_printf(timestamp, vap_id, + "ANI firstep %d firstep_low %d", args[0], + args[1]); + break; + case ANI_DBGID_MRC_CCK: + dbglog_printf(timestamp, vap_id, "ANI mrc_cck %d", args[0]); + break; + case ANI_DBGID_CYCPWR: + dbglog_printf(timestamp, vap_id, "ANI cypwr_thresh %d", + args[0]); + break; + case ANI_DBGID_POLL_PERIOD: + dbglog_printf(timestamp, vap_id, + "ANI Configure poll period to %d", args[0]); + break; + case ANI_DBGID_LISTEN_PERIOD: + dbglog_printf(timestamp, vap_id, + "ANI Configure listen period to %d", args[0]); + break; + case ANI_DBGID_OFDM_LEVEL_CFG: + dbglog_printf(timestamp, vap_id, + "ANI Configure ofdm level to %d", args[0]); + break; + case ANI_DBGID_CCK_LEVEL_CFG: + dbglog_printf(timestamp, vap_id, + "ANI Configure cck level to %d", args[0]); + break; + default: + dbglog_printf(timestamp, vap_id, "ANI arg1 %d arg2 %d arg3 %d", + args[0], args[1], args[2]); + break; + } + return true; +} + +A_BOOL +dbglog_ap_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case AP_PS_DBGID_UPDATE_TIM: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "AP PS: TIM update AID=%u %s", + args[0], args[1] ? "set" : "clear"); + } + break; + case AP_PS_DBGID_PEER_STATE_CHANGE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u power save %s", + args[0], + args[1] ? "enabled" : "disabled"); + } + break; + case AP_PS_DBGID_PSPOLL: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u pspoll response tid=%u flags=%x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_PEER_CREATE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "AP PS: create peer AID=%u", args[0]); + } + break; + case AP_PS_DBGID_PEER_DELETE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "AP PS: delete peer AID=%u", args[0]); + } + break; + case AP_PS_DBGID_VDEV_CREATE: + dbglog_printf(timestamp, vap_id, "AP PS: vdev create"); + break; + case AP_PS_DBGID_VDEV_DELETE: + dbglog_printf(timestamp, vap_id, "AP PS: vdev delete"); + break; + case AP_PS_DBGID_SYNC_TIM: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u advertised=%#x buffered=%#x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_NEXT_RESPONSE: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u select next response %s%s%s", + args[0], args[1] ? "(usp active) " : "", + args[2] ? "(pending usp) " : "", + args[3] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_START_SP: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u START SP tsf=%#x (%u)", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_COMPLETED_EOSP: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u EOSP eosp_tsf=%#x trigger_tsf=%#x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_TRIGGER: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u TRIGGER tsf=%#x %s%s", + args[0], args[1], + args[2] ? "(usp active) " : "", + args[3] ? "(send_n in progress)" : ""); + } + break; + case AP_PS_DBGID_DUPLICATE_TRIGGER: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u DUP TRIGGER tsf=%#x seq=%u ac=%u", + args[0], args[1], args[2], args[3]); + } + break; + case AP_PS_DBGID_UAPSD_RESPONSE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u UAPSD response tid=%u, n_mpdu=%u flags=%#x max_sp=%u current_sp=%u", + args[0], args[1], args[2], args[3], + (args[4] >> 16) & 0xffff, + args[4] & 0xffff); + } + break; + case AP_PS_DBGID_SEND_COMPLETE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u SEND_COMPLETE fc=%#x qos=%#x %s%s", + args[0], args[1], args[2], + args[3] ? "(usp active) " : "", + args[4] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_SEND_N_COMPLETE: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u SEND_N_COMPLETE %s%s", + args[0], + args[1] ? "(usp active) " : "", + args[2] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u detected out-of-sync now=%u tx_waiting=%u txq_depth=%u", + args[0], args[1], args[2], args[3]); + } + break; + case AP_PS_DBGID_DELIVER_CAB: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: CAB %s n_mpdus=%u, flags=%x, extra=%u", + (args[0] == 17) ? "MGMT" : "DATA", + args[1], args[2], args[3]); + } + break; + default: + return false; + } + + return true; +} + +A_BOOL +dbglog_wal_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "ACTIVE", + "WAIT", + "WAIT_FILTER", + "PAUSE", + "PAUSE_SEND_N", + "BLOCK", + }; + + static const char *events[] = { + "PAUSE", + "PAUSE_FILTER", + "UNPAUSE", + + "BLOCK", + "BLOCK_FILTER", + "UNBLOCK", + + "HWQ_EMPTY", + "ALLOW_N", + }; + +#define WAL_VDEV_TYPE(type) \ + (type == 0 ? "AP" : \ + (type == 1 ? "STA" : \ + (type == 2 ? "IBSS" : \ + (type == 2 ? "MONITOR" : \ + "UNKNOWN")))) + +#define WAL_SLEEP_STATE(state) \ + (state == 1 ? "NETWORK SLEEP" : \ + (state == 2 ? "AWAKE" : \ + (state == 3 ? "SYSTEM SLEEP" : \ + "UNKNOWN"))) + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "TID PAUSE", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + case WAL_DBGID_SET_POWER_STATE: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "WAL %s => %s, req_count=%u", + WAL_SLEEP_STATE(args[0]), + WAL_SLEEP_STATE(args[1]), args[2]); + } + break; + case WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "WAL channel change (force reset) freq=%u, flags=%u mode=%u rx_ok=%u tx_ok=%u", + args[0] & 0x0000ffff, + (args[0] & 0xffff0000) >> 16, args[1], + args[2], args[3]); + } + break; + case WAL_DBGID_CHANNEL_CHANGE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "WAL channel change freq=%u, mode=%u flags=%u rx_ok=1 tx_ok=1", + args[0] & 0x0000ffff, + (args[0] & 0xffff0000) >> 16, args[1]); + } + break; + case WAL_DBGID_VDEV_START: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, "WAL %s vdev started", + WAL_VDEV_TYPE(args[0])); + } + break; + case WAL_DBGID_VDEV_STOP: + dbglog_printf(timestamp, vap_id, "WAL %s vdev stopped", + WAL_VDEV_TYPE(args[0])); + break; + case WAL_DBGID_VDEV_UP: + dbglog_printf(timestamp, vap_id, "WAL %s vdev up, count=%u", + WAL_VDEV_TYPE(args[0]), args[1]); + break; + case WAL_DBGID_VDEV_DOWN: + dbglog_printf(timestamp, vap_id, "WAL %s vdev down, count=%u", + WAL_VDEV_TYPE(args[0]), args[1]); + break; + case WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN: + dbglog_printf(timestamp, vap_id, + "WAL Tx Mgmt frame desc_id=0x%x, seq=0x%x, type=0x%x, len=0x%x islocal=0x%x", + args[0], args[1], args[2], + (args[3] & 0xffff0000) >> 16, + args[3] & 0x0000ffff); + break; + case WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS: + dbglog_printf(timestamp, vap_id, + "WAL Tx Mgmt frame completion desc_id=0x%x, status=0x%x, islocal=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN: + dbglog_printf(timestamp, vap_id, + "WAL Tx Data frame msdu_id=0x%x, seq=0x%x, type=0x%x, len=0x%x", + args[0], args[1], args[2], args[3]); + break; + case WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS: + dbglog_printf(timestamp, vap_id, + "WAL Tx Data frame completion desc_id=0x%x, status=0x%x, seq=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_RESET_PCU_CYCLE_CNT: + dbglog_printf(timestamp, vap_id, + "WAL PCU cycle counter value at reset:%x", + args[0]); + break; + case WAL_DBGID_TX_DISCARD: + dbglog_printf(timestamp, vap_id, + "WAL Tx enqueue discard msdu_id=0x%x", args[0]); + break; + case WAL_DBGID_SET_HW_CHAINMASK: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_SET_HW_CHAINMASK " + "pdev=%d, txchain=0x%x, rxchain=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL rxstop=%d, txstop=%d", + args[0], args[1]); + break; + case WAL_DBGID_GET_HW_CHAINMASK: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_GET_HW_CHAINMASK " + "txchain=0x%x, rxchain=0x%x", args[0], args[1]); + break; + case WAL_DBGID_SMPS_DISABLE: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_SMPS_DISABLE"); + break; + case WAL_DBGID_SMPS_ENABLE_HW_CNTRL: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SMPS_ENABLE_HW_CNTRL low_pwr_mask=0x%x, high_pwr_mask=0x%x", + args[0], args[1]); + break; + case WAL_DBGID_SMPS_SWSEL_CHAINMASK: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SMPS_SWSEL_CHAINMASK low_pwr=0x%x, chain_mask=0x%x", + args[0], args[1]); + break; + default: + return false; + } + + return true; +} + +A_BOOL +dbglog_scan_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "IDLE", + "BSSCHAN", + "WAIT_FOREIGN_CHAN", + "FOREIGN_CHANNEL", + "TERMINATING" + }; + + static const char *events[] = { + "REQ", + "STOP", + "BSSCHAN", + "FOREIGN_CHAN", + "CHECK_ACTIVITY", + "REST_TIME_EXPIRE", + "DWELL_TIME_EXPIRE", + "PROBE_TIME_EXPIRE", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "SCAN", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +A_BOOL dbglog_coex_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + A_UINT8 i; + char *dbg_id_str; + + static const char *wlan_rx_xput_status[] = { + "WLAN_XPUT_NORMAL", + "WLAN_XPUT_UNDER_THRESH", + "WLAN_XPUT_CRITICAL", + "WLAN_XPUT_RECOVERY_TIMEOUT", + }; + + static const char *coex_sched_req[] = { + "SCHED_REQ_NEXT", + "SCHED_REQ_BT", + "SCHED_REQ_WLAN", + "SCHED_REQ_POSTPAUSE", + "SCHED_REQ_UNPAUSE", + }; + + static const char *coex_sched_type[] = { + "SCHED_NONE", + "SCHED_WLAN", + "SCHED_BT", + "SCHED_WLAN_PAUSE", + "SCHED_WLAN_POSTPAUSE", + "SCHED_WLAN_UNPAUSE", + "COEX_SCHED_MWS", + }; + + static const char *coex_trf_mgmt_type[] = { + "TRF_MGMT_FREERUN", + "TRF_MGMT_SHAPE_PM", + "TRF_MGMT_SHAPE_PSP", + "TRF_MGMT_SHAPE_S_CTS", + "TRF_MGMT_SHAPE_OCS", + "TRF_MGMT_SHAPE_FIXED_TIME", + "TRF_MGMT_SHAPE_NOA", + "TRF_MGMT_SHAPE_OCS_CRITICAL", + "TRF_MGMT_NONE", + }; + + static const char *coex_system_status[] = { + "ALL_OFF", + "BTCOEX_NOT_REQD", + "WLAN_IS_IDLE", + "EXECUTE_SCHEME", + "BT_FULL_CONCURRENCY", + "WLAN_SLEEPING", + "WLAN_IS_PAUSED", + "WAIT_FOR_NEXT_ACTION", + "SOC_WAKE", + }; + + static const char *wlan_rssi_type[] = { + "LOW_RSSI", + "MID_RSSI", + "HI_RSSI", + "INVALID_RSSI", + }; + + static const char *coex_bt_scheme[] = { + "IDLE_CTRL", + "ACTIVE_ASYNC_CTRL", + "PASSIVE_SYNC_CTRL", + "ACTIVE_SYNC_CTRL", + "DEFAULT_CTRL", + "CONCURRENCY_CTRL", + }; + + static const char *wal_peer_rx_rate_stats_event_sent[] = { + "PR_RX_EVT_SENT_NONE", + "PR_RX_EVT_SENT_LOWER", + "PR_RX_EVT_SENT_UPPER", + }; + + static const char *wlan_psp_stimulus[] = { + "ENTRY", + "EXIT", + "PS_READY", + "PS_NOT_READY", + "RX_MORE_DATA_RCVD", + "RX_NO_MORE_DATA_RCVD", + "TX_DATA_COMPLT", + "TX_COMPLT", + "TIM_SET", + "REQ", + "DONE_SUCCESS", + "DONE_NO_PS_POLL_ACK", + "DONE_RESPONSE_TMO", + "DONE_DROPPED", + "DONE_FILTERED", + "WLAN_START", + "NONWLAN_START", + "NONWLAN_INTVL_UPDATE", + "NULL_TX", + "NULL_TX_COMPLT", + "BMISS_FIRST", + "NULL_TX_FAIL", + "RX_NO_MORE_DATA_DATAFRM", + }; + + static const char *coex_pspoll_state[] = { + "STATE_DISABLED", + "STATE_NOT_READY", + "STATE_ENABLED", + "STATE_READY", + "STATE_TX_STATUS", + "STATE_RX_STATUS", + }; + + static const char *coex_scheduler_interval[] = { + "COEX_SCHED_NONWLAN_INT", + "COEX_SCHED_WLAN_INT", + }; + + static const char *wlan_weight[] = { + "BT_COEX_BASE", + "BT_COEX_LOW", + "BT_COEX_MID", + "BT_COEX_MID_NONSYNC", + "BT_COEX_HI_NONVOICE", + "BT_COEX_HI", + "BT_COEX_CRITICAL", + }; + + static const char *wlan_power_state[] = { + "SLEEP", + "AWAKE", + "FULL_SLEEP", + }; + + static const char *coex_psp_error_type[] = { + "DISABLED_STATE", + "VDEV_NULL", + "COEX_PSP_ENTRY", + "ZERO_INTERVAL", + "COEX_PSP_EXIT", + "READY_DISABLED", + "READY_NOT_DISABLED", + "POLL_PKT_DROPPED", + "SET_TIMER_PARAM", + }; + + static const char *wlan_phymode[] = { + "A", + "G", + "B", + "G_ONLY", + "NA_HT20", + "NG_HT20", + "NA_HT40", + "NG_HT40", + "AC_VHT20", + "AC_VHT40", + "AC_VHT80", + "AC_VHT20_2G", + "AC_VHT40_2G", + "AC_VHT80_2G", + "UNKNOWN", + }; + + static const char *wlan_curr_band[] = { + "2G", + "5G", + }; + + dbg_id_str = dbglog_get_msg(mod_id, dbg_id); + + switch (dbg_id) { + case COEX_SYSTEM_UPDATE: + if (numargs == 1 && args[0] < 9) { + dbglog_printf(timestamp, vap_id, "%s: %s", dbg_id_str, + coex_system_status[args[0]]); + } else if (numargs >= 5 && args[0] < 9 && args[2] < 9) { + dbglog_printf(timestamp, vap_id, + "%s: %s, WlanSysState(0x%x), %s, NumChains(%u), AggrLimit(%u)", + dbg_id_str, coex_system_status[args[0]], + args[1], coex_trf_mgmt_type[args[2]], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_SCHED_START: + if (numargs >= 5 && args[0] < 5 && args[2] < 9 && args[3] < 4 + && args[4] < 4) { + if (args[1] == 0xffffffff) { + dbglog_printf(timestamp, vap_id, + "%s: %s, DETERMINE_DURATION, %s, %s, %s", + dbg_id_str, + coex_sched_req[args[0]], + coex_trf_mgmt_type[args[2]], + wlan_rx_xput_status[args[3]], + wlan_rssi_type[args[4]]); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %s, IntvlDur(%u), %s, %s, %s", + dbg_id_str, + coex_sched_req[args[0]], args[1], + coex_trf_mgmt_type[args[2]], + wlan_rx_xput_status[args[3]], + wlan_rssi_type[args[4]]); + } + } else { + return false; + } + break; + case COEX_SCHED_RESULT: + if (numargs >= 5 && args[0] < 5 && args[1] < 9 && args[2] < 9) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, %s, CoexMgrPolicy(%u), IdleOverride(%u)", + dbg_id_str, coex_sched_req[args[0]], + coex_trf_mgmt_type[args[1]], + coex_trf_mgmt_type[args[2]], args[3], + args[4]); + } else { + return false; + } + break; + case COEX_BT_SCHEME: + if (numargs >= 1 && args[0] < 6) { + dbglog_printf(timestamp, vap_id, "%s: %s", dbg_id_str, + coex_bt_scheme[args[0]]); + } else { + return false; + } + break; + case COEX_TRF_FREERUN: + if (numargs >= 5 && args[0] < 7) { + dbglog_printf(timestamp, vap_id, + "%s: %s, AllocatedBtIntvls(%u), BtIntvlCnt(%u), AllocatedWlanIntvls(%u), WlanIntvlCnt(%u)", + dbg_id_str, coex_sched_type[args[0]], + args[1], args[2], args[3], args[4]); + } else { + return false; + } + break; + case COEX_TRF_SHAPE_PM: /* used by ocs now */ + if (numargs >= 3) { + dbglog_printf(timestamp, vap_id, + "%s: IntvlLength(%u), BtDuration(%u), WlanDuration(%u)", + dbg_id_str, args[0], args[1], args[2]); + } else { + return false; + } + break; + case COEX_SYSTEM_MONITOR: + if (numargs >= 5 && args[1] < 4 && args[4] < 4) { + dbglog_printf(timestamp, vap_id, + "%s: WlanRxCritical(%u), %s, MinDirectRxRate(%u), MonitorActiveNum(%u), %s", + dbg_id_str, args[0], + wlan_rx_xput_status[args[1]], args[2], + args[3], wlan_rssi_type[args[4]]); + } else { + return false; + } + break; + case COEX_RX_RATE: + if (numargs >= 5 && args[4] < 3) { + dbglog_printf(timestamp, vap_id, + "%s: NumUnderThreshPeers(%u), MinDirectRate(%u), LastRateSample(%u), DeltaT(%u), %s", + dbg_id_str, args[0], args[1], args[2], + args[3], + wal_peer_rx_rate_stats_event_sent[args + [4]]); + } else { + return false; + } + break; + case COEX_WLAN_INTERVAL_START: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: WlanIntvlCnt(%u), Duration(%u), Weight(%u), BaseIdleOverride(%u), WeightMat[0](0x%x)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_WLAN_POSTPAUSE_INTERVAL_START: + if (numargs >= 4) { + dbglog_printf(timestamp, vap_id, + "%s: WlanPostPauseIntvlCnt(%u), XputMonitorActiveNum(%u), Duration(%u), Weight(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3]); + } else { + return false; + } + break; + case COEX_BT_INTERVAL_START: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: BtIntvlCnt(%u), Duration(%u), Weight(%u), BaseIdleOverride(%u), WeightMat[0](0x%x), ", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_POWER_CHANGE: + if (numargs >= 3 && args[1] < 3 && args[2] < 3) { + dbglog_printf(timestamp, vap_id, + "%s: Event(0x%x) %s->%s", dbg_id_str, + args[0], wlan_power_state[args[1]], + wlan_power_state[args[2]]); + } else { + return false; + } + break; + case COEX_CHANNEL_CHANGE: + if (numargs >= 5 && args[3] < 2 && args[4] < 15) { + dbglog_printf(timestamp, vap_id, + "%s: %uMhz->%uMhz, WlanSysState(0x%x), CurrBand(%s), PhyMode(%s)", + dbg_id_str, args[0], args[1], args[2], + wlan_curr_band[args[3]], + wlan_phymode[args[4]]); + } else { + return false; + } + break; + case COEX_PSP_MGR_ENTER: + if (numargs >= 5 && args[0] < 23 && args[1] < 6 && args[3] < 2) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, PsPollAvg(%u), %s, CurrT(%u)", + dbg_id_str, wlan_psp_stimulus[args[0]], + coex_pspoll_state[args[1]], args[2], + coex_scheduler_interval[args[3]], + args[4]); + } else { + return false; + } + break; + /* Translate following into decimal */ + case COEX_SINGLECHAIN_DBG_1: + case COEX_SINGLECHAIN_DBG_2: + case COEX_SINGLECHAIN_DBG_3: + case COEX_MULTICHAIN_DBG_1: + case COEX_MULTICHAIN_DBG_2: + case COEX_MULTICHAIN_DBG_3: + case BTCOEX_DBG_MCI_1: + case BTCOEX_DBG_MCI_2: + case BTCOEX_DBG_MCI_3: + case BTCOEX_DBG_MCI_4: + case BTCOEX_DBG_MCI_5: + case BTCOEX_DBG_MCI_6: + case BTCOEX_DBG_MCI_7: + case BTCOEX_DBG_MCI_8: + case BTCOEX_DBG_MCI_9: + case BTCOEX_DBG_MCI_10: + + if (numargs > 0) { + dbglog_printf_no_line_break(timestamp, vap_id, "%s: %u", + dbg_id_str, args[0]); + for (i = 1; i < numargs; i++) { + printk(", %u", args[i]); + } + printk("\n"); + } else { + return false; + } + break; + case COEX_LinkID: + if (numargs >= 4) { + if (args[0]) { /* Add profile */ + dbglog_printf(timestamp, vap_id, + "%s Alloc: LocalID(%u), RemoteID(%u), MinFreeLocalID(%u)", + dbg_id_str, args[1], args[2], + args[3]); + } else { /* Remove profile */ + dbglog_printf(timestamp, vap_id, + "%s Dealloc: LocalID(%u), RemoteID(%u), MinFreeLocalID(%u)", + dbg_id_str, args[1], args[2], + args[3]); + } + } else { + return false; + } + break; + case COEX_PSP_MGR_RESULT: + if (numargs >= 5 && args[0] < 6) { + dbglog_printf(timestamp, vap_id, + "%s: %s, PsPollAvg(%u), EstimationOverrun(%u), EstimationUnderun(%u), NotReadyErr(%u)", + dbg_id_str, coex_pspoll_state[args[0]], + args[1], args[2], args[3], args[4]); + } else { + return false; + } + break; + case COEX_TRF_SHAPE_PSP: + if (numargs >= 5 && args[0] < 7 && args[1] < 7) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, Dur(%u), BtTriggerRecvd(%u), PspWlanCritical(%u)", + dbg_id_str, coex_sched_type[args[0]], + wlan_weight[args[1]], args[2], args[3], + args[4]); + } else { + return false; + } + break; + case COEX_PSP_SPEC_POLL: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: PsPollSpecEna(%u), Count(%u), NextTS(%u), AllowSpecPsPollTx(%u), Intvl(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_READY_STATE: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: T2NonWlan(%u), CoexSchedulerEndTS(%u), MoreData(%u), PSPRespExpectedTS(%u), NonWlanIdleT(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_NONWLAN_INTERVAL: + if (numargs >= 4) { + dbglog_printf(timestamp, vap_id, + "%s: NonWlanBaseIntvl(%u), NonWlanIdleT(%u), PSPSpecIntvl(%u), ApRespTimeout(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3]); + } else { + return false; + } + break; + case COEX_PSP_ERROR: + if (numargs >= 1 && args[0] < 9) { + dbglog_printf_no_line_break(timestamp, vap_id, "%s: %s", + dbg_id_str, + coex_psp_error_type[args + [0]]); + for (i = 1; i < numargs; i++) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (", %u", args[i])); + } + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("\n")); + } else { + return false; + } + break; + case COEX_PSP_STAT_1: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: ApResp0(%u), ApResp1(%u), ApResp2(%u), ApResp3(%u), ApResp4(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_STAT_2: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: DataPt(%u), Max(%u), NextApRespIndex(%u), NumOfValidDataPts(%u), PsPollAvg(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_RX_STATUS_STATE_1: + if (numargs >= 5) { + if (args[2]) { + dbglog_printf(timestamp, vap_id, + "%s: RsExpectedTS(%u), RespActualTS(%u), Overrun, RsOverrunT(%u), RsRxDur(%u)", + dbg_id_str, args[0], args[1], + args[3], args[4]); + } else { + dbglog_printf(timestamp, vap_id, + "%s: RsExpectedTS(%u), RespActualTS(%u), Underrun, RsUnderrunT(%u), RsRxDur(%u)", + dbg_id_str, args[0], args[1], + args[3], args[4]); + } + } else { + return false; + } + break; + default: + return false; + } + + return true; +} + +A_BOOL +dbglog_beacon_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "INIT", + "ADJUST_START", + "ADJUSTING", + "ADJUST_HOLD", + }; + + static const char *events[] = { + "ADJUST_START", + "ADJUST_RESTART", + "ADJUST_STOP", + "ADJUST_PAUSE", + "ADJUST_UNPAUSE", + "ADJUST_INC_SLOP_STEP", + "ADJUST_HOLD", + "ADJUST_HOLD_TIME_OUT", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "EARLY_RX", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + case BEACON_EVENT_EARLY_RX_BMISS_STATUS: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "early_rx bmiss status:rcv=%d total=%d miss=%d", + args[0], args[1], args[2]); + } + break; + case BEACON_EVENT_EARLY_RX_SLEEP_SLOP: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx update sleep_slop:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx cont bmiss timeout,update sleep_slop:%d", + args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx skip bcn num:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_CLK_DRIFT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx clk drift:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_AP_DRIFT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx ap drift:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_BCN_TYPE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx bcn type:%d", args[0]); + } + break; + default: + return false; + } + + return true; +} + +A_BOOL +dbglog_data_txrx_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO: + dbglog_printf(timestamp, vap_id, + "DATA RX seq=0x%x, len=0x%x, stored=0x%x, duperr=0x%x", + args[0], args[1], (args[2] & 0xffff0000) >> 16, + args[2] & 0x0000ffff); + break; + default: + return false; + } + + return true; +} + +A_BOOL dbglog_smps_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "S_INACTIVE", + "S_STATIC", + "S_DYNAMIC", + "S_STALLED", + "S_INACTIVE_WAIT", + "S_STATIC_WAIT", + "S_DYNAMIC_WAIT", + }; + + static const char *events[] = { + "E_STOP", + "E_STOP_COMPL", + "E_START", + "E_STATIC", + "E_STATIC_COMPL", + "E_DYNAMIC", + "E_DYNAMIC_COMPL", + "E_STALL", + "E_RSSI_ABOVE_THRESH", + "E_RSSI_BELOW_THRESH", + "E_FORCED_NONE", + }; + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "STA_SMPS SM", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + case STA_SMPS_DBGID_CREATE_PDEV_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Create PDEV ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS Create Virtual Chan ctx %#x", args[0]); + break; + case STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS Delete Virtual Chan ctx %#x", args[0]); + break; + case STA_SMPS_DBGID_CREATE_STA_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Create STA ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_DELETE_STA_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Delete STA ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START: + break; + case STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP: + break; + case STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME: + dbglog_printf(timestamp, vap_id, + "STA_SMPS STA %#x Signal SMPS mode as %s; cb_flags %#x", + args[0], + (args[1] == + 0 ? "DISABLED" : (args[1] == + 0x1 ? "STATIC" : (args[1] == + 0x3 ? + "DYNAMIC" : + "UNKNOWN"))), + args[2]); + break; + case STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE"); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE " + "tx_mask %#x rx_mask %#x arb_dtim_mask %#x", + args[0], args[1], args[2]); + break; + case STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE"); + break; + case STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE cur_pwr_state %s new_pwr_state %s", + (args[0] == + 0x1 ? "SLEEP" : (args[0] == + 0x2 ? "AWAKE" : (args[0] == + 0x3 ? + "FULL_SLEEP" : + "UNKNOWN"))), + (args[1] == + 0x1 ? "SLEEP" : (args[1] == + 0x2 ? "AWAKE" : (args[1] == + 0x3 ? + "FULL_SLEEP" : + "UNKNOWN")))); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP " + "tx_mask %#x rx_mask %#x orig_rx %#x dtim_rx %#x", + args[0], args[1], args[2], args[3]); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE " + "tx_mask %#x rx_mask %#x orig_rx %#x", args[0], + args[1], args[2]); + break; + default: + dbglog_printf(timestamp, vap_id, "STA_SMPS: UNKNOWN DBGID!"); + return false; + } + + return true; +} + +A_BOOL +dbglog_p2p_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "ACTIVE", + "DOZE", + "TX_BCN", + "CTWIN", + "OPPPS", + }; + + static const char *events[] = { + "ONESHOT_NOA", + "CTWINDOW", + "PERIODIC_NOA", + "IDLE", + "NOA_CHANGED", + "TBTT", + "TX_BCN_CMP", + "OPPPS_OK", + "OPPPS_CHANGED", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "P2P GO PS", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +A_BOOL +dbglog_pcielp_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "STOP", + "TX", + "RX", + "SLEEP", + "SUSPEND", + }; + + static const char *events[] = { + "VDEV_UP", + "ALL_VDEV_DOWN", + "AWAKE", + "SLEEP", + "TX_ACTIVITY", + "TX_INACTIVITY", + "TX_AC_CHANGE", + "SUSPEND", + "RESUME", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "PCIELP", + states, CDF_ARRAY_SIZE(states), events, + CDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +#ifdef WLAN_OPEN_SOURCE +static int dbglog_block_open(struct inode *inode, struct file *file) +{ + struct fwdebug *fwlog = inode->i_private; + + if (fwlog->fwlog_open) + return -EBUSY; + + fwlog->fwlog_open = true; + + file->private_data = inode->i_private; + return 0; +} + +static int dbglog_block_release(struct inode *inode, struct file *file) +{ + struct fwdebug *fwlog = inode->i_private; + + fwlog->fwlog_open = false; + + return 0; +} + +static ssize_t dbglog_block_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct fwdebug *fwlog = file->private_data; + struct sk_buff *skb; + ssize_t ret_cnt; + size_t len = 0, not_copied; + char *buf; + int ret; + + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + + spin_lock_bh(&fwlog->fwlog_queue.lock); + + if (skb_queue_len(&fwlog->fwlog_queue) == 0) { + /* we must init under queue lock */ + init_completion(&fwlog->fwlog_completion); + + spin_unlock_bh(&fwlog->fwlog_queue.lock); + + ret = + wait_for_completion_interruptible(&fwlog->fwlog_completion); + if (ret == -ERESTARTSYS) { + vfree(buf); + return ret; + } + + spin_lock_bh(&fwlog->fwlog_queue.lock); + } + + while ((skb = __skb_dequeue(&fwlog->fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&fwlog->fwlog_queue, skb); + break; + } + + memcpy(buf + len, skb->data, skb->len); + len += skb->len; + + kfree_skb(skb); + } + + spin_unlock_bh(&fwlog->fwlog_queue.lock); + + /* FIXME: what to do if len == 0? */ + not_copied = copy_to_user(user_buf, buf, len); + if (not_copied != 0) { + ret_cnt = -EFAULT; + goto out; + } + + *ppos = *ppos + len; + + ret_cnt = len; + +out: + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_dbglog_block = { + .open = dbglog_block_open, + .release = dbglog_block_release, + .read = dbglog_block_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int dbglog_debugfs_init(wmi_unified_t wmi_handle) +{ + + wmi_handle->debugfs_phy = debugfs_create_dir(CLD_DEBUGFS_DIR, NULL); + if (!wmi_handle->debugfs_phy) + return -ENOMEM; + + debugfs_create_file(DEBUGFS_BLOCK_NAME, S_IRUSR, + wmi_handle->debugfs_phy, &wmi_handle->dbglog, + &fops_dbglog_block); + + return true; +} + +int dbglog_debugfs_remove(wmi_unified_t wmi_handle) +{ + debugfs_remove_recursive(wmi_handle->debugfs_phy); + return true; +} +#endif /* WLAN_OPEN_SOURCE */ + +static void +cnss_diag_event_report(A_UINT16 event_Id, A_UINT16 length, void *pPayload) +{ + A_UINT8 *pBuf, *pBuf1; + event_report_t *pEvent_report; + A_UINT16 total_len; + total_len = sizeof(event_report_t) + length; + pBuf = cdf_mem_malloc(total_len); + if (!pBuf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: cdf_mem_malloc failed \n", __func__)); + return; + } + pBuf1 = pBuf; + pEvent_report = (event_report_t *) pBuf; + pEvent_report->diag_type = DIAG_TYPE_EVENTS; + pEvent_report->event_id = event_Id; + pEvent_report->length = length; + pBuf += sizeof(event_report_t); + memcpy(pBuf, pPayload, length); + send_diag_netlink_data((A_UINT8 *) pBuf1, total_len, + DIAG_TYPE_HOST_MSG); + cdf_mem_free((void *)pBuf1); + return; + +} + +static void cnss_diag_send_driver_loaded(void) +{ + if (appstarted) { + host_event_wlan_bringup_status_payload_type wlan_bringup_status; + /* Send Driver up command */ + strlcpy(&wlan_bringup_status.driverVersion[0], QWLAN_VERSIONSTR, + sizeof(wlan_bringup_status.driverVersion)); + wlan_bringup_status.wlanStatus = DIAG_WLAN_DRIVER_LOADED; + cnss_diag_event_report(EVENT_WLAN_BRINGUP_STATUS, + sizeof(wlan_bringup_status), + &wlan_bringup_status); + senddriverstatus = false; + } else + senddriverstatus = true; +} + +static void cnss_diag_send_driver_unloaded(void) +{ + host_event_wlan_bringup_status_payload_type wlan_bringup_status; + /* Send Driver down command */ + memset(&wlan_bringup_status, 0, + sizeof(host_event_wlan_bringup_status_payload_type)); + wlan_bringup_status.wlanStatus = DIAG_WLAN_DRIVER_UNLOADED; + cnss_diag_event_report(EVENT_WLAN_BRINGUP_STATUS, + sizeof(wlan_bringup_status), + &wlan_bringup_status); +} + +/**--------------------------------------------------------------------------- + \brief cnss_diag_msg_callback() - Call back invoked by netlink service + + This function gets invoked by netlink service when a message is recevied + from the cnss-diag application in user-space. + + \param - + - skb - skb with netlink message + + \return - 0 for success, non zero for failure + --------------------------------------------------------------------------*/ +int cnss_diag_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct dbglog_slot *slot; + A_UINT8 *msg; + + nlh = (struct nlmsghdr *)skb->data; + if (!nlh) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Netlink header null \n", __func__)); + return -1; + } + + msg = NLMSG_DATA(nlh); + + /* This check added for backward compatability */ + if (!memcmp(msg, "Hello", 5)) { + appstarted = true; + cnss_diag_pid = nlh->nlmsg_pid; + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: registered pid %d \n", __func__, + cnss_diag_pid)); + if (senddriverstatus) + cnss_diag_send_driver_loaded(); + return 0; + } else + slot = (struct dbglog_slot *)msg; + switch (slot->diag_type) { + case DIAG_TYPE_CRASH_INJECT: + if (slot->length == 2) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s : DIAG_TYPE_CRASH_INJECT: %d %d\n", + __func__, slot->payload[0], slot->payload[1])); + wma_cli_set2_command(0, GEN_PARAM_CRASH_INJECT, + slot->payload[0], slot->payload[1], + GEN_CMD); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("crash_inject cmd error\n")); + } + break; + default: + break; + } + return 0; + +} + +/**--------------------------------------------------------------------------- + \brief cnss_diag_notify_wlan_close() - notify APP driver closed + + This function notifies the user cnss-diag app that wlan driver is closed. + + \param - + - None + + \return - 0 for success, non zero for failure + --------------------------------------------------------------------------*/ +int cnss_diag_notify_wlan_close() +{ + /* Send nl msg about the wlan close */ + if (INVALID_PID != cnss_diag_pid) { + cnss_diag_send_driver_unloaded(); + cnss_diag_pid = INVALID_PID; + } + return 0; + +} + +/**--------------------------------------------------------------------------- + \brief cnss_diag_activate_service() - Activate cnss_diag message handler + + This function registers a handler to receive netlink message from + an cnss-diag application process. + + \param - + - None + + \return - 0 for success, non zero for failure + --------------------------------------------------------------------------*/ +int cnss_diag_activate_service() +{ + int ret = 0; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + ret = nl_srv_register(WLAN_NL_MSG_CNSS_DIAG, cnss_diag_msg_callback); + if (ret == -EINVAL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("CNSS-DIAG Registeration failed \n")); + return ret; + } + kd_nl_init = true; + return 0; +} + +A_BOOL +dbglog_wow_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + + switch (dbg_id) { + case WOW_NS_OFLD_ENABLE: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "Enable NS offload, for sender %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\ + :%02x%02x:%02x%02x:%02x%02x", *(A_UINT8 *) &args[0], *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), *((A_UINT8 *) &args[0] + 3), *(A_UINT8 *) &args[1], *((A_UINT8 *) &args[1] + 1), *((A_UINT8 *) &args[1] + 2), *((A_UINT8 *) &args[1] + 3), + *(A_UINT8 *) &args[2], *((A_UINT8 *) &args[2] + 1), *((A_UINT8 *) &args[2] + 2), *((A_UINT8 *) &args[2] + 3), *(A_UINT8 *) &args[3], *((A_UINT8 *) &args[3] + 1), + *((A_UINT8 *) &args[3] + 2), *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_ARP_OFLD_ENABLE: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "Enable ARP offload, for sender %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + case WOW_NS_ARP_OFLD_DISABLE: + if (0 == numargs) { + dbglog_printf(timestamp, vap_id, + "disable NS/ARP offload"); + } else { + return false; + } + break; + case WOW_NS_RECEIVED: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "NS requested from %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\ + :%02x%02x:%02x%02x:%02x%02x", *(A_UINT8 *) &args[0], *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), *((A_UINT8 *) &args[0] + 3), *(A_UINT8 *) &args[1], *((A_UINT8 *) &args[1] + 1), *((A_UINT8 *) &args[1] + 2), + *((A_UINT8 *) &args[1] + 3), *(A_UINT8 *) &args[2], *((A_UINT8 *) &args[2] + 1), *((A_UINT8 *) &args[2] + 2), *((A_UINT8 *) &args[2] + 3), + *(A_UINT8 *) &args[3], *((A_UINT8 *) &args[3] + 1), *((A_UINT8 *) &args[3] + 2), *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_NS_REPLIED: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "NS replied to %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\ + :%02x%02x:%02x%02x:%02x%02x", *(A_UINT8 *) &args[0], *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), *((A_UINT8 *) &args[0] + 3), *(A_UINT8 *) &args[1], *((A_UINT8 *) &args[1] + 1), *((A_UINT8 *) &args[1] + 2), + *((A_UINT8 *) &args[1] + 3), *(A_UINT8 *) &args[2], *((A_UINT8 *) &args[2] + 1), *((A_UINT8 *) &args[2] + 2), *((A_UINT8 *) &args[2] + 3), + *(A_UINT8 *) &args[3], *((A_UINT8 *) &args[3] + 1), *((A_UINT8 *) &args[3] + 2), *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_ARP_RECEIVED: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "ARP requested from %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + break; + case WOW_ARP_REPLIED: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "ARP replied to %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + default: + return false; + } + + return true; +} + +int dbglog_parser_type_init(wmi_unified_t wmi_handle, int type) +{ + if (type >= DBGLOG_PROCESS_MAX) { + return A_ERROR; + } + + dbglog_process_type = type; + gprint_limiter = false; + + return A_OK; +} + +int dbglog_init(wmi_unified_t wmi_handle) +{ + int res = 0; + OS_MEMSET(mod_print, 0, sizeof(mod_print)); + + dbglog_reg_modprint(WLAN_MODULE_STA_PWRSAVE, + dbglog_sta_powersave_print_handler); + dbglog_reg_modprint(WLAN_MODULE_AP_PWRSAVE, + dbglog_ap_powersave_print_handler); + dbglog_reg_modprint(WLAN_MODULE_WAL, dbglog_wal_print_handler); + dbglog_reg_modprint(WLAN_MODULE_SCAN, dbglog_scan_print_handler); + dbglog_reg_modprint(WLAN_MODULE_RATECTRL, + dbglog_ratectrl_print_handler); + dbglog_reg_modprint(WLAN_MODULE_ANI, dbglog_ani_print_handler); + dbglog_reg_modprint(WLAN_MODULE_COEX, dbglog_coex_print_handler); + dbglog_reg_modprint(WLAN_MODULE_BEACON, dbglog_beacon_print_handler); + dbglog_reg_modprint(WLAN_MODULE_WOW, dbglog_wow_print_handler); + dbglog_reg_modprint(WLAN_MODULE_DATA_TXRX, + dbglog_data_txrx_print_handler); + dbglog_reg_modprint(WLAN_MODULE_STA_SMPS, dbglog_smps_print_handler); + dbglog_reg_modprint(WLAN_MODULE_P2P, dbglog_p2p_print_handler); + dbglog_reg_modprint(WLAN_MODULE_PCIELP, dbglog_pcielp_print_handler); + dbglog_reg_modprint(WLAN_MODULE_IBSS_PWRSAVE, + dbglog_ibss_powersave_print_handler); + + /* Register handler for F3 or debug messages */ + res = + wmi_unified_register_event_handler(wmi_handle, + WMI_DEBUG_MESG_EVENTID, + dbglog_parse_debug_logs); + if (res != 0) + return res; + + /* Register handler for FW diag events */ + res = wmi_unified_register_event_handler(wmi_handle, + WMI_DIAG_DATA_CONTAINER_EVENTID, + fw_diag_data_event_handler); + if (res != 0) + return res; + + /* Register handler for new FW diag Event, LOG, MSG combined */ + res = wmi_unified_register_event_handler(wmi_handle, WMI_DIAG_EVENTID, + diag_fw_handler); + if (res != 0) + return res; + + cnss_diag_send_driver_loaded(); +#ifdef WLAN_OPEN_SOURCE + /* Initialize the fw debug log queue */ + skb_queue_head_init(&wmi_handle->dbglog.fwlog_queue); + init_completion(&wmi_handle->dbglog.fwlog_completion); + + /* Initialize debugfs */ + dbglog_debugfs_init(wmi_handle); +#endif /* WLAN_OPEN_SOURCE */ + + return res; +} + +int dbglog_deinit(wmi_unified_t wmi_handle) +{ + int res = 0; + +#ifdef WLAN_OPEN_SOURCE + /* DeInitialize the fw debug log queue */ + skb_queue_purge(&wmi_handle->dbglog.fwlog_queue); + complete(&wmi_handle->dbglog.fwlog_completion); + + /* Deinitialize the debugfs */ + dbglog_debugfs_remove(wmi_handle); +#endif /* WLAN_OPEN_SOURCE */ + + res = + wmi_unified_unregister_event_handler(wmi_handle, + WMI_DEBUG_MESG_EVENTID); + if (res != 0) + return res; + + kd_nl_init = false; + return res; +} diff --git a/core/utils/fwlog/dbglog_host.h b/core/utils/fwlog/dbglog_host.h new file mode 100644 index 0000000000..9b9e0e4e1f --- /dev/null +++ b/core/utils/fwlog/dbglog_host.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_HOST_H_ +#define _DBGLOG_HOST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dbglog_common.h" +#include "ol_defines.h" + +/* + * set the dbglog parser type + */int +dbglog_parser_type_init(wmi_unified_t wmi_handle, int type); + +/** dbglog_int - Registers a WMI event handle for WMI_DBGMSG_EVENT + * @brief wmi_handle - handle to wmi module + */ +int +dbglog_init(wmi_unified_t wmi_handle); + +/** dbglog_deinit - UnRegisters a WMI event handle for WMI_DBGMSG_EVENT + * @brief wmi_handle - handle to wmi module + */ +int +dbglog_deinit(wmi_unified_t wmi_handle); + +/** set the size of the report size + * @brief wmi_handle - handle to Wmi module + * @brief size - Report size + */ +int +dbglog_set_report_size(wmi_unified_t wmi_handle, A_UINT16 size); + +/** Set the resolution for time stamp + * @brief wmi_handle - handle to Wmi module + * @ brief tsr - time stamp resolution + */ +int +dbglog_set_timestamp_resolution(wmi_unified_t wmi_handle, + A_UINT16 tsr); + +/** Enable reporting. If it is set to false then Traget wont deliver + * any debug information + */ +int +dbglog_report_enable(wmi_unified_t wmi_handle, A_BOOL isenable); + +/** Set the log level + * @brief DBGLOG_INFO - Information lowest log level + * @brief DBGLOG_WARNING + * @brief DBGLOG_ERROR - default log level + */ +int +dbglog_set_log_lvl(wmi_unified_t wmi_handle, DBGLOG_LOG_LVL log_lvl); + +/* + * set the debug log level for a given module + * mod_id_lvl : the format is more user friendly. + * module_id = mod_id_lvl/10; + * log_level = mod_id_lvl%10; + * example : mod_id_lvl is 153. then module id is 15 and log level is 3. this format allows + * user to pass a sinlge value (which is the most convenient way for most of the OSs) + * to be passed from user to the driver. + */ +int +dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, A_UINT32 mod_id_lvl); + +/** Enable/Disable the logging for VAP */ +int +dbglog_vap_log_enable(wmi_unified_t wmi_handle, A_UINT16 vap_id, + A_BOOL isenable); +/** Enable/Disable logging for Module */ +int +dbglog_module_log_enable(wmi_unified_t wmi_handle, A_UINT32 mod_id, + A_BOOL isenable); + +/** set vap enablie bitmap */ +void +dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 vap_enable_bitmap); + +/** set log level for all the modules specified in the bitmap. for all other modules + * with 0 in the bitmap (or) outside the bitmap , the log level be reset to DBGLOG_ERR. + */ +void +dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 log_level, + A_UINT32 *mod_enable_bitmap, + A_UINT32 bitmap_len); + +/** Register the cnss_diag activate with the wlan driver */ +int cnss_diag_activate_service(void); +int cnss_diag_notify_wlan_close(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DBGLOG_HOST_H_ */ diff --git a/core/utils/host_diag_log/inc/host_diag_core_event.h b/core/utils/host_diag_log/inc/host_diag_core_event.h new file mode 100644 index 0000000000..7962dda352 --- /dev/null +++ b/core/utils/host_diag_log/inc/host_diag_core_event.h @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __HOST_DIAG_CORE_EVENT_H ) +#define __HOST_DIAG_CORE_EVENT_H + +/**========================================================================= + + \file host_diag_core_event.h + + \brief WLAN UTIL host DIAG Events + + Definitions for DIAG Events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_types.h" +#include "cds_pack_align.h" +#include "i_host_diag_core_event.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define WAKE_LOCK_NAME_LEN 80 + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_SECURITY + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t authMode; + uint8_t encryptionModeUnicast; + uint8_t encryptionModeMulticast; + uint8_t pmkIDMatch; + uint8_t bssid[6]; + uint8_t keyId; + uint8_t status; +} host_event_wlan_security_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_STATUS + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t ssid[6]; + uint8_t bssType; + uint8_t rssi; + uint8_t channel; + uint8_t qosCapability; + uint8_t authType; + uint8_t encryptionType; + uint8_t reason; + uint8_t reasonDisconnect; +} host_event_wlan_status_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_HANDOFF + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t currentApBssid[6]; + uint8_t currentApRssi; + uint8_t candidateApBssid[6]; + uint8_t candidateApRssi; +} host_event_wlan_handoff_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_VCC + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t rssi; + uint8_t txPer; + uint8_t rxPer; + int linkQuality; +} host_event_wlan_vcc_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_QOS + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t reasonCode; +} host_event_wlan_qos_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_PE + ------------------------------------------------------------------------*/ +typedef struct { + char bssid[6]; + uint16_t event_type; + uint16_t sme_state; + uint16_t mlm_state; + uint16_t status; + uint16_t reason_code; +} host_event_wlan_pe_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_ADD_BLOCK_ACK_SUCCESS + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucBaBufferSize; + uint16_t usBaSSN; + uint8_t fInitiator; +} host_event_wlan_add_block_ack_success_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_ADD_BLOCK_ACK_FAILED + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucReasonCode; + uint8_t fInitiator; +} host_event_wlan_add_block_ack_failed_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_SUCCESS + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucDeleteReasonCode; +} host_event_wlan_add_block_ack_deleted_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_FAILED + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucDeleteReasonCode; + uint8_t ucFailReasonCode; +} host_event_wlan_add_block_ack_delete_failed_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BSS_PROTECTION + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t event_type; + uint8_t prot_type; +} host_event_wlan_bss_prot_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BRINGUP_STATUS + ------------------------------------------------------------------------*/ +typedef struct { + uint16_t wlanStatus; + char driverVersion[10]; +} host_event_wlan_bringup_status_payload_type; + +CDS_PACK_START +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_POWERSAVE_GENERIC + ------------------------------------------------------------------------*/ +typedef CDS_PACK_PRE struct { + uint8_t event_subtype; + uint8_t full_power_request_reason; + uint8_t pmc_current_state; + uint8_t enable_disable_powersave_mode; + uint8_t winmob_d_power_state; + uint8_t dtim_period; + uint16_t final_listen_intv; + uint16_t bmps_auto_timer_duration; + uint16_t bmps_period; +} CDS_PACK_POST host_event_wlan_powersave_payload_type; + +CDS_PACK_END +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_POWERSAVE_WOW + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t event_subtype; + uint8_t wow_type; + uint8_t wow_magic_pattern[6]; + uint8_t wow_del_ptrn_id; + uint8_t wow_wakeup_cause; + uint8_t wow_wakeup_cause_pbm_ptrn_id; +} host_event_wlan_powersave_wow_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BTC + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t btAddr[6]; + uint16_t connHandle; + uint8_t connStatus; + uint8_t linkType; + uint8_t scoInterval; + uint8_t scoWindow; + uint8_t retransWindow; + uint8_t mode; +} host_event_wlan_btc_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_EAPOL + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_eapol - Structure holding the eapol information + * @event_sub_type: 0-Transmitted, 1-Received + * @eapol_packet_type: 0 - EAP Start, 1 - EAPOL Start, 2 - EAPOL Logoff + 3 - EAPOL Key, 4 - EAPOL Encapsulated Alert + * @eapol_key_info: This field from the driver is in big endian format. + * So, the masks .0x8013. can be used to extract the + * message type. After masking, the values corresponding + * to messages 1/2/3/4 are given below: + * Msg. 1 0x8000 + * Msg. 2 0x0001 + * Msg. 3 0x8013 + * Msg. 4 0x0003 + * @eapol_rate: Rate at which the frame is received + * @dest_addr: Destination address + * @src_addr: Source address + * + * This structure contains the EAPOL information related to logging + */ +struct host_event_wlan_eapol { + uint8_t event_sub_type; + uint8_t eapol_packet_type; + uint16_t eapol_key_info; + uint16_t eapol_rate; + uint8_t dest_addr[6]; + uint8_t src_addr[6]; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_WAKE_LOCK + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_wake_lock - Structure holding the wakelock information + * @status: Whether the wakelock is taken/released + * @reason: Reason for taking this wakelock + * @timeout: Timeout value in case of timed wakelocks + * @name_len: Length of the name of the wakelock that will follow + * @name: Name of the wakelock + * + * This structure will hold the wakelock information + */ +struct host_event_wlan_wake_lock { + uint32_t status; + uint32_t reason; + uint32_t timeout; + uint32_t name_len; + char name[WAKE_LOCK_NAME_LEN]; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_LOG_COMPLETE + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_log_complete - Holds log completion details + * @is_fatal: Indicates if the event is fatal or not + * @indicator: Source of the bug report - Framework/Host/Firmware + * @reason_code: Reason for triggering bug report + * @reserved: Reserved field + * + * This structure holds the log completion related information + */ +struct host_event_wlan_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + uint32_t reserved; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +/** + * enum wifi_connectivity_events - Enum containing EAPOL sub type + * @WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED: EAPOL transmitted + * @WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED: EAPOL received + * + * This enum contains the EAPOL subtype + */ +enum wifi_connectivity_events { + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, +}; + +/** + * enum wake_lock_reason - Reason for taking/releasing wakelock + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT: Driver initialization + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT: Driver re-initialization + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT: Driver shutdown + * @WIFI_POWER_EVENT_WAKELOCK_SCAN: Scan request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN: Extended scan request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN: Driver resume + * @WIFI_POWER_EVENT_WAKELOCK_ROC: Remain on channel request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND: Auto suspend related handling + * @WIFI_POWER_EVENT_WAKELOCK_IPA: IPA related handling + * @WIFI_POWER_EVENT_WAKELOCK_ADD_STA: Addition of STA + * @WIFI_POWER_EVENT_WAKELOCK_HOLD_RX: Wakelocks taken for receive + * @WIFI_POWER_EVENT_WAKELOCK_SAP: SoftAP related wakelocks + * @WIFI_POWER_EVENT_WAKELOCK_WOW: WoW feature related + * @WIFI_POWER_EVENT_WAKELOCK_PNO: PNO feature related + * @WIFI_POWER_EVENT_WAKELOCK_DEL_STA: Deletion of a station + * @WIFI_POWER_EVENT_WAKELOCK_DFS: DFS related wakelocks + * @WIFI_POWER_EVENT_WAKELOCK_MISC: Miscellaneous wakelocks + * + * Indicates the reason for which the wakelock was taken/released + */ +enum wake_lock_reason { + WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT, + WIFI_POWER_EVENT_WAKELOCK_SCAN, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN, + WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN, + WIFI_POWER_EVENT_WAKELOCK_ROC, + WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND, + WIFI_POWER_EVENT_WAKELOCK_IPA, + WIFI_POWER_EVENT_WAKELOCK_ADD_STA, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX, + WIFI_POWER_EVENT_WAKELOCK_SAP, + WIFI_POWER_EVENT_WAKELOCK_WOW, + WIFI_POWER_EVENT_WAKELOCK_PNO, + WIFI_POWER_EVENT_WAKELOCK_DEL_STA, + WIFI_POWER_EVENT_WAKELOCK_DFS, + WIFI_POWER_EVENT_WAKELOCK_MISC, +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __HOST_DIAG_CORE_EVENT_H */ diff --git a/core/utils/host_diag_log/inc/host_diag_core_log.h b/core/utils/host_diag_log/inc/host_diag_core_log.h new file mode 100644 index 0000000000..d17ad46dec --- /dev/null +++ b/core/utils/host_diag_log/inc/host_diag_core_log.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __HOST_DIAG_CORE_LOG_H ) +#define __HOST_DIAG_CORE_LOG_H + +/**========================================================================= + + \file host_diag_core_log.h + + \brief WLAN UTIL host DIAG logs + + Definitions for WLAN UTIL host diag events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cdf_types.h" +#include "i_host_diag_core_log.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define HOST_LOG_MAX_NUM_SSID (21) +#define HOST_LOG_MAX_NUM_BSSID (21) +#define HOST_LOG_MAX_SSID_SIZE (32) +#define HOST_LOG_MAX_BSSID_SIZE (6) +#define HOST_LOG_MAX_NUM_CHANNEL (64) +#define HOST_LOG_MAX_NUM_HO_CANDIDATE_APS (20) +#define HOST_LOG_MAX_WOW_PTRN_SIZE (128) +#define HOST_LOG_MAX_WOW_PTRN_MASK_SIZE (16) +#define VOS_LOG_PKT_LOG_SIZE (2048) +#define HOST_LOG_PKT_LOG_THRESHOLD 40960 + +/* Version to be updated whenever format of vos_log_pktlog_info changes */ +#define VERSION_LOG_WLAN_PKT_LOG_INFO_C 1 + +/*--------------------------------------------------------------------------- + This packet contains the scan results of the recent scan operation + LOG_WLAN_SCAN_C 0x1496 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t numSsid; + uint8_t ssid[HOST_LOG_MAX_NUM_SSID][HOST_LOG_MAX_SSID_SIZE]; + uint8_t bssid[HOST_LOG_MAX_NUM_BSSID][HOST_LOG_MAX_BSSID_SIZE]; + uint8_t totalSsid; + uint8_t minChnTime; + uint8_t maxChnTime; + uint16_t timeBetweenBgScan; + uint8_t BSSMode; + uint8_t numChannel; + uint8_t channels[HOST_LOG_MAX_NUM_CHANNEL]; + uint16_t status; +} host_log_scan_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to IBSS connection setup + LOG_WLAN_IBSS_C 0x1497 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t channelSetting; + uint8_t bssid[HOST_LOG_MAX_BSSID_SIZE]; + uint8_t peerMacAddr[HOST_LOG_MAX_BSSID_SIZE]; + uint8_t ssid[HOST_LOG_MAX_SSID_SIZE]; + uint8_t operatingChannel; + uint8_t beaconInterval; + uint8_t status; +} host_log_ibss_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to 802.11D + LOG_WLAN_80211D_C 0x1498 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t numChannel; + uint8_t Channels[HOST_LOG_MAX_NUM_CHANNEL]; + uint8_t TxPwr[HOST_LOG_MAX_NUM_CHANNEL]; + uint8_t countryCode[3]; + uint8_t supportMultipleDomain; +} host_log_802_11d_pkt_type; + +/*--------------------------------------------------------------------------- + This is a log packet which contains below handoff information: + - Current AP + RSSI (if already associated) + - Candidate AP + RSSI (before association and when the list is updated) + - For each BSSID in candidate list, provide RSSI, QoS and security compatibility + LOG_WLAN_HANDOFF_C 0x1499 + ---------------------------------------------------------------------------*/ +typedef struct { + uint8_t ssid[9]; + uint8_t bssid[HOST_LOG_MAX_BSSID_SIZE]; + uint8_t channel_id; + uint32_t qos_score; + uint32_t sec_score; + uint32_t rssi_score; + uint32_t overall_score; + uint32_t tx_per; /* represented as a % */ + uint32_t rx_per; /* represented as a % */ + +} host_log_ho_ap_info; + +typedef struct { + log_hdr_type hdr; + uint32_t num_aps; + host_log_ho_ap_info current_ap_info; + host_log_ho_ap_info + candidate_ap_info[HOST_LOG_MAX_NUM_HO_CANDIDATE_APS]; +} host_log_ho_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to the EDCA parameters + advertised by the AP + LOG_WLAN_QOS_EDCA_C 0x149A + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t aci_be; + uint8_t cw_be; + uint16_t txoplimit_be; + uint8_t aci_bk; + uint8_t cw_bk; + uint16_t txoplimit_bk; + uint8_t aci_vi; + uint8_t cw_vi; + uint16_t txoplimit_vi; + uint8_t aci_vo; + uint8_t cw_vo; + uint16_t txoplimit_vo; +} host_log_qos_edca_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the total number of beacon received value + LOG_WLAN_BEACON_UPDATE_C 0x149B + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint32_t bcn_rx_cnt; +} host_log_beacon_update_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to a WoW patern value when set + LOG_WLAN_POWERSAVE_WOW_ADD_PTRN_C 0x149C + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t pattern_id; + uint8_t pattern_byte_offset; + uint8_t pattern_size; + uint8_t pattern[HOST_LOG_MAX_WOW_PTRN_SIZE]; + uint8_t pattern_mask_size; + uint8_t pattern_mask[HOST_LOG_MAX_WOW_PTRN_MASK_SIZE]; +} host_log_powersave_wow_add_ptrn_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the PHY & MAC layer statistics sent by lower layer + _WLAN_LINKLAYER_STAT_C 0x14A1 + ---------------------------------------------------------------------------*/ +typedef struct { + uint32_t retry_cnt[4]; + uint32_t multiple_retry_cnt[4]; + uint32_t tx_frm_cnt[4]; + uint32_t rx_frm_cnt; + uint32_t frm_dup_cnt; + uint32_t fail_cnt[4]; + uint32_t rts_fail_cnt; + uint32_t ack_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_discard_cnt; + uint32_t rx_error_cnt; + uint32_t tx_byte_cnt; + +} summaryStatsInfo; + +typedef struct { + uint32_t rx_frag_cnt; + uint32_t promiscuous_rx_frag_cnt; + uint32_t rx_input_sensitivity; + uint32_t max_pwr; + uint32_t sync_fail_cnt; + uint32_t tx_rate; + +} globalClassAStatsInfo; + +typedef struct { + uint32_t uc_rx_wep_unencrypted_frm_cnt; + uint32_t uc_rx_mic_fail_cnt; + uint32_t uc_tkip_icv_err; + uint32_t uc_aes_ccmp_format_err; + uint32_t uc_aes_ccmp_replay_cnt; + uint32_t uc_aes_ccmp_decrpt_err; + uint32_t uc_wep_undecryptable_cnt; + uint32_t uc_wep_icv_err; + uint32_t uc_rx_decrypt_succ_cnt; + uint32_t uc_rx_decrypt_fail_cnt; + uint32_t mcbc_rx_wep_unencrypted_frm_cnt; + uint32_t mcbc_rx_mic_fail_cnt; + uint32_t mcbc_tkip_icv_err; + uint32_t mcbc_aes_ccmp_format_err; + uint32_t mcbc_aes_ccmp_replay_cnt; + uint32_t mcbc_aes_ccmp_decrpt_err; + uint32_t mcbc_wep_undecryptable_cnt; + uint32_t mcbc_wep_icv_err; + uint32_t mcbc_rx_decrypt_succ_cnt; + uint32_t mcbc_rx_decrypt_fail_cnt; + +} globalClassBStatsInfo; + +typedef struct { + uint32_t rx_amsdu_cnt; + uint32_t rx_ampdu_cnt; + uint32_t tx_20_frm_cnt; + uint32_t rx_20_frm_cnt; + uint32_t rx_mpdu_in_ampdu_cnt; + uint32_t ampdu_delimiter_crc_err; + +} globalClassCStatsInfo; + +typedef struct { + uint32_t tx_uc_frm_cnt; + uint32_t tx_mc_frm_cnt; + uint32_t tx_bc_frm_cnt; + uint32_t rx_uc_frm_cnt; + uint32_t rx_mc_frm_cnt; + uint32_t rx_bc_frm_cnt; + uint32_t tx_uc_byte_cnt[4]; + uint32_t tx_mc_byte_cnt; + uint32_t tx_bc_byte_cnt; + uint32_t rx_uc_byte_cnt[4]; + uint32_t rx_mc_byte_cnt; + uint32_t rx_bc_byte_cnt; + uint32_t rx_byte_cnt; + uint32_t num_rx_bytes_crc_ok; + uint32_t rx_rate; + +} globalClassDStatsInfo; + +typedef struct { + uint32_t tx_frag_cnt[4]; + uint32_t tx_ampdu_cnt; + uint32_t tx_mpdu_in_ampdu_cnt; +} perStaStatsInfo; + +typedef struct { + log_hdr_type hdr; + uint8_t version; + uint8_t reserved[3]; + uint32_t stat_mask; + summaryStatsInfo summaryStats; + globalClassAStatsInfo globalClassAStats; + globalClassBStatsInfo globalClassBStats; + globalClassCStatsInfo globalClassCStats; + globalClassDStatsInfo globalClassDStats; + perStaStatsInfo perStaStats; +} host_log_statistics_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the Tspec info negotiated with the AP for the + specific AC + LOG_WLAN_QOS_TSPEC_C 0x14A2 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t tsinfo[3]; + uint16_t nominal_msdu_size; + uint16_t maximum_msdu_size; + uint32_t min_service_interval; + uint32_t max_service_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t svc_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} host_log_qos_tspec_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains data information when stall detected + LOG_TRSP_DATA_STALL_C 0x1801 + ---------------------------------------------------------------------------*/ + +typedef struct { + char channelName[4]; + uint32_t numDesc; + uint32_t numFreeDesc; + uint32_t numRsvdDesc; + uint32_t headDescOrder; + uint32_t tailDescOrder; + uint32_t ctrlRegVal; + uint32_t statRegVal; + uint32_t numValDesc; + uint32_t numInvalDesc; +} host_log_data_stall_channel_type; + +typedef struct { + log_hdr_type hdr; + uint32_t PowerState; + uint32_t numFreeBd; + host_log_data_stall_channel_type dxeChannelInfo[4]; +} host_log_data_stall_type; + +/*--------------------------------------------------------------------------- + This packet contains the rssi value from BSS descriptor + LOG_WLAN_RSSI_UPDATE_C 0x1354 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + int8_t rssi; +} host_log_rssi_pkt_type; + +/** + * struct host_log_pktlog_info - Packet log info + * @log_hdr: Log header + * @buf_len: Length of the buffer that follows + * @buf: Buffer containing the packet log info + * + * Structure containing the packet log information + * LOG_WLAN_PKT_LOG_INFO_C 0x18E0 + */ +struct host_log_pktlog_info { + log_hdr_type log_hdr; + uint32_t version; + uint32_t seq_no; + uint32_t buf_len; + uint8_t buf[]; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __HOST_DIAG_CORE_LOG_H */ diff --git a/core/utils/host_diag_log/inc/host_diag_event_defs.h b/core/utils/host_diag_log/inc/host_diag_event_defs.h new file mode 100644 index 0000000000..ca250c592d --- /dev/null +++ b/core/utils/host_diag_log/inc/host_diag_event_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EVENT_DEFS_H +#define EVENT_DEFS_H + +typedef enum { + EVENT_DROP_ID = 0, + + /* Events between 0x1 to 0x674 are not used */ + + EVENT_WLAN_SECURITY = 0x675, /* 13 byte payload */ + EVENT_WLAN_STATUS, /* 15 byte payload */ + + /* Events 0x677 and 0x678 are not used */ + + EVENT_WLAN_QOS = 0x679, /* 2 byte payload */ + EVENT_WLAN_PE, /* 16 byte payload */ + + /* Events between 0x67b to 0x67f are not used */ + + EVENT_WLAN_BRINGUP_STATUS = 0x680, /* 12 byte payload */ + EVENT_WLAN_POWERSAVE_GENERIC, /* 16 byte payload */ + EVENT_WLAN_POWERSAVE_WOW, /* 11 byte payload */ + + /* Events between 0x683 to 0x690 are not used */ + + EVENT_WLAN_BTC = 0x691, /* 15 byte payload */ + EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */ + EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */ + EVENT_WLAN_BEACON_RECEIVED = 0xAA6, /* FW event: 2726 */ + EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */ + + EVENT_MAX_ID = 0x0FFF +} event_id_enum_type; + +#endif /* EVENT_DEFS_H */ diff --git a/core/utils/host_diag_log/inc/log_codes.h b/core/utils/host_diag_log/inc/log_codes.h new file mode 100644 index 0000000000..462ce9cc83 --- /dev/null +++ b/core/utils/host_diag_log/inc/log_codes.h @@ -0,0 +1,2078 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef LOG_CODES_H +#define LOG_CODES_H + +/*=========================================================================== + + Log Code Definitions + + General Description + This file contains log code definitions and is shared with the tools. + + ===========================================================================*/ + +/* DO NOT MODIFY THIS FILE WITHOUT PRIOR APPROVAL +** +** Log codes, by design, are a tightly controlled set of values. +** Developers may not create log codes at will. +** +** Request new logs using the following process: +** +** 1. Send email to asw.diag.request requesting log codassignments. +** 2. Identify the log needed by name. +** 3. Provide a brief description for the log. +** +*/ + +/*=========================================================================== + + Edit History + + $Header: //source/qcom/qct/core/services/diag/api/inc/main/latest/log_codes.h#9 $ + + when who what, where, why + -------- --- ---------------------------------------------------------- + 07/30/09 dhao Consolidate log_codes_apps.h + 07/30/09 dhao Add Last log code definition for Equip ID 11 + 06/26/09 dhao Update format the macro + 06/24/09 sar Reverted last change. + 06/24/09 sar Added log code for LOG_MC_STM_C. + 11/02/01 sfh Featurize common NAS log codes for UMTS. + 10/30/01 sfh Added log code for LOG_GPS_FATPATH_INFO_C. + 10/24/01 sfh Added updates for UMTS equipment ID and log codes. + 06/27/01 lad Added multiple equipment ID support. + 05/22/01 sfh Reserved log codes 158 - 168. + 05/21/01 sfh Keep confusing XXX_BASE_C names for backwards compatibility. + 05/16/01 sfh Reserved log code 155. + 05/08/01 sfh Reserved log codes 150 - 154. + 04/06/01 lad Added definitions of base IDs (such as LOG_WCDMA_BASE_C). + This is currently using temporary ID values in the 0x1000 + range. + 02/23/01 lad Created file from DMSS log.h. Log codes only + + ===========================================================================*/ +#include + +/* ------------------------------------------------------------------------- + * Data Declarations + * ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- + * Log equipment IDs. + * The most significant 4 bits of the 16 bit log code is the equipment ID. + * Orignally, the mobile was to have an ID, and base stations and other + * IDs. As QCT technology diversifies, new equipment IDs are assigned to new + * technology areas. 0x2000 and 0x3000 are reserved for legacy reasons, so + * the first + * addition starts at 0x4000. + * ------------------------------------------------------------------------- */ + +#define LOG_1X_BASE_C ((uint16_t) 0x1000) +#define LOG_WCDMA_BASE_C ((uint16_t) 0x4000) +#define LOG_GSM_BASE_C ((uint16_t) 0x5000) +#define LOG_LBS_BASE_C ((uint16_t) 0x6000) +#define LOG_UMTS_BASE_C ((uint16_t) 0x7000) +#define LOG_TDMA_BASE_C ((uint16_t) 0x8000) +#define LOG_DTV_BASE_C ((uint16_t) 0xA000) +#define LOG_APPS_BASE_C ((uint16_t) 0xB000) +#define LOG_LTE_BASE_C ((uint16_t) (0xB000 + 0x0010)) +#define LOG_LTE_LAST_C ((uint16_t) 0xB1FF) +#define LOG_WIMAX_BASE_C ((uint16_t) 0xB400) +#define LOG_DSP_BASE_C ((uint16_t) 0xC000) + +#define LOG_TOOLS_BASE_C ((uint16_t) 0xF000) + +/* LOG_BASE_C is what was used before expanding the use of the equipment ID. + * TODO: Once all targets are using the "core" diag system, this should be + * ommitted. */ +#define LOG_BASE_C LOG_1X_BASE_C + +/* ------------------------------------------------------------------------- + * Log Codes + * These codes identify the kind of information contained in a log entry. + * They are used in conjunction with the 'code' field of the log entry + * header. The data types associated with each code are defined below. + * ------------------------------------------------------------------------- */ + +/* The upper 4 bits of the 16 bit log entry code specify which type + * of equipment created the log entry. */ + +/* 0 Mobile Station temporal analyzer entry */ +#define LOG_TA_C (0x0 + LOG_1X_BASE_C) + +/* 1 AGC values and closed loop power control entry */ +#define LOG_AGC_PCTL_C (0x1 + LOG_1X_BASE_C) + +/* 2 Forward link frame rates and types entry */ +#define LOG_F_MUX1_C (0x2 + LOG_1X_BASE_C) + +/* 3 Reverse link frame rates and types entry */ +#define LOG_R_MUX1_C (0x3 + LOG_1X_BASE_C) + +/* 4 Access channel message entry */ +#define LOG_AC_MSG_C (0x4 + LOG_1X_BASE_C) + +/* 5 Reverse link traffic channel message entry */ +#define LOG_R_TC_MSG_C (0x5 + LOG_1X_BASE_C) + +/* 6 Sync channel message entry */ +#define LOG_SC_MSG_C (0x6 + LOG_1X_BASE_C) + +/* 7 Paging channel message entry */ +#define LOG_PC_MSG_C (0x7 + LOG_1X_BASE_C) + +/* 8 Forward link traffic channel message entry */ +#define LOG_F_TC_MSG_C (0x8 + LOG_1X_BASE_C) + +/* 9 Forward link vocoder packet entry */ +#define LOG_VOC_FOR_C (0x9 + LOG_1X_BASE_C) + +/* 10 Reverse link vocoder packet entry */ +#define LOG_VOC_REV_C (0xA + LOG_1X_BASE_C) + +/* 11 Temporal analyzer finger info only */ +#define LOG_FING_C (0xB + LOG_1X_BASE_C) + +/* 12 Searcher pathlog info (Reused old SRCH logtype) */ +#define LOG_SRCH_C (0xC + LOG_1X_BASE_C) + +/* 13 Position and speed information read from ETAK */ +#define LOG_ETAK_C (0xD + LOG_1X_BASE_C) + +/* 14 Markov frame statistics */ +#define LOG_MAR_C (0xE + LOG_1X_BASE_C) + +/* 15 New and improved temporal analyzer searcher info */ +#define LOG_SRCH2_C (0xF + LOG_1X_BASE_C) + +/* 16 The Fujitsu handset information */ +#define LOG_HANDSET_C (0x10 + LOG_1X_BASE_C) + +/* 17 Vocoder bit error rate mask */ +#define LOG_ERRMASK_C (0x11 + LOG_1X_BASE_C) + +/* 18 Analog voice channel information */ +#define LOG_ANALOG_INFO_C (0x12 + LOG_1X_BASE_C) + +/* 19 Access probe information */ +#define LOG_ACC_INFO_C (0x13 + LOG_1X_BASE_C) + +/* 20 Position & speed info read from GPS receiver */ +#define LOG_GPS_C (0x14 + LOG_1X_BASE_C) + +/* 21 Test Command information */ +#define LOG_TEST_CMD_C (0x15 + LOG_1X_BASE_C) + +/* 22 Sparse (20ms) AGC / closed loop power control entry */ +#define LOG_S_AGC_PCTL_C (0x16 + LOG_1X_BASE_C) + +/* 23 Notification of a band class change */ +#define LOG_BAND_CHANGE_C (0x17 + LOG_1X_BASE_C) + +/* 24 DM debug messages, if being logged via log services */ +#define LOG_DBG_MSG_C (0x18 + LOG_1X_BASE_C) + +/* 25 General temporal analyzer entry */ +#define LOG_GENRL_TA_C (0x19 + LOG_1X_BASE_C) + +/* 26 General temporal analyzer w/supplemental channels */ +#define LOG_GENRL_TA_SUP_CH_C (0x1A + LOG_1X_BASE_C) + +/* Featurization Removal requested by CMI + #ifdef FEATURE_PLT + */ + +/* 27 Decoder raw bits logging */ +#define LOG_PLT_C (0x1B + LOG_1X_BASE_C) + +/* Featurization Removal requested by CMI + #else + 27 EFS Usage Info - No implementation as yet + #define LOG_EFS_INFO_C (0x1B + LOG_1X_BASE_C) + #endif + */ + +/* 28 Analog Forward Channel */ +#define LOG_ANALOG_FORW_C (0x1C + LOG_1X_BASE_C) + +/* 29 Analog Reverse Channel */ +#define LOG_ANALOG_REVS_C (0x1D + LOG_1X_BASE_C) + +/* 30 Analog Handoff Entry */ +#define LOG_ANALOG_HANDOFF_C (0x1E + LOG_1X_BASE_C) + +/* 31 FM Slot Statistis entry */ +#define LOG_ANALOG_FMSLOT_C (0x1F + LOG_1X_BASE_C) + +/* 32 FOCC Word Sync Count entry */ +#define LOG_ANALOG_WS_COUNT_C (0x20 + LOG_1X_BASE_C) + +/* 33 */ +#define LOG_RLP_PACKET_C (0x21 + LOG_1X_BASE_C) + +/* 34 */ +#define LOG_ASYNC_TCP_SEG_C (0x22 + LOG_1X_BASE_C) + +/* 35 */ +#define LOG_PACKET_DATA_IP_PACKETS_C (0x23 + LOG_1X_BASE_C) + +/* 36 */ +#define LOG_FNBDT_MESSAGE_LOG_C (0x24 + LOG_1X_BASE_C) + +/* Begin IS-2000 LOG features */ + +/* 37 RLP RX Frames logging */ +#define LOG_RLP_RX_FRAMES_C (0x25 + LOG_1X_BASE_C) + +/* 38 RLP TX Frames logging */ +#define LOG_RLP_TX_FRAMES_C (0x26 + LOG_1X_BASE_C) + +/* 39 Reserved for additions to RLP frames */ +#define LOG_RLP_RSVD1_C (0x27 + LOG_1X_BASE_C) + +/* 40 Reserved for additions to RLP frames */ +#define LOG_RLP_RSVD2_C (0x28 + LOG_1X_BASE_C) + +/* 41 Forward Link Frame Types logging */ +#define LOG_FWD_FRAME_TYPES_C (0x29 + LOG_1X_BASE_C) + +/* 42 Reverse Link Frame Types logging */ +#define LOG_REV_FRAME_TYPES_C (0x2A + LOG_1X_BASE_C) + +/* 43 Fast Forward Power Control Parameters logging */ +#define LOG_FFWD_PCTRL_C (0x2B + LOG_1X_BASE_C) + +/* 44 Reverse Power Control Parameters logging */ +#define LOG_REV_PCTRL_C (0x2C + LOG_1X_BASE_C) + +/* 45 Searcher and Finger Information logging */ +#define LOG_SRCH_FING_INFO_C (0x2D + LOG_1X_BASE_C) + +/* 46 Service Configuration logging */ +#define LOG_SVC_CONFIG_C (0x2E + LOG_1X_BASE_C) + +/* 47 Active Set Configuration logging */ +#define LOG_ASET_CONFIG_C (0x2F + LOG_1X_BASE_C) + +/* 48 Quick Paging Channel logging */ +#define LOG_QPCH_C (0x30 + LOG_1X_BASE_C) + +/* 49 RLP Statistics logging */ +#define LOG_RLP_STAT_C (0x31 + LOG_1X_BASE_C) + +/* 50 Simple Test Data Service Option logging */ +#define LOG_STDSO_C (0x32 + LOG_1X_BASE_C) + +/* 51 Pilot Phase Measurement results logging */ +#define LOG_SRCH_PPM_RES_C (0x33 + LOG_1X_BASE_C) + +/* 52 Pilot Phase Measurement Data Base logging */ +#define LOG_SRCH_PPM_DB_C (0x34 + LOG_1X_BASE_C) + +/* 53 Pilot Phase Measurement search results logging */ +#define LOG_SRCH_PPM_C (0x35 + LOG_1X_BASE_C) + +/* 54 IS-801 forward link message */ +#define LOG_GPS_FWD_MSG_C (0x36 + LOG_1X_BASE_C) + +/* 55 IS-801 reverse link message */ +#define LOG_GPS_REV_MSG_C (0x37 + LOG_1X_BASE_C) + +/* 56 GPS search session statistics */ +#define LOG_GPS_STATS_MSG_C (0x38 + LOG_1X_BASE_C) + +/* 57 GPS search results */ +#define LOG_GPS_SRCH_PEAKS_MSG_C (0x39 + LOG_1X_BASE_C) + +/* 58 Factory Testmode logging */ +#define LOG_FTM_C (0x3A + LOG_1X_BASE_C) + +/* 59 Multiple Peak Logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_INFO_C (0x3B + LOG_1X_BASE_C) + +/* 60 Post processed search results logs */ +#define LOG_SRCH_GPS_POST_PROC_C (0x3C + LOG_1X_BASE_C) + +/* 61 FULL Test Data Service Option logging */ +#define LOG_FTDSO_C (0x3D + LOG_1X_BASE_C) + +/* 62 Bluetooth logging */ +#define LOG_BT_RESERVED_CODES_BASE_C (0x3E + LOG_1X_BASE_C) +/* Keep confusing name for backwards compatibility. */ +#define LOG_BT_BASE_C LOG_BT_RESERVED_CODES_BASE_C + +/* 92 Bluetooth's last log code */ +#define LOG_BT_LAST_C (30 + LOG_BT_RESERVED_CODES_BASE_C) + +/* 93 HDR log codes */ +#define LOG_HDR_RESERVED_CODES_BASE_C (0x5D + LOG_1X_BASE_C) +/* Keep confusing name for backwards compatibility. */ +#define LOG_HDR_BASE_C LOG_HDR_RESERVED_CODES_BASE_C + +/* 143 is HDR's last log code */ +#define LOG_HDR_LAST_C (50 + LOG_HDR_RESERVED_CODES_BASE_C) + +/* 144 IS2000 DCCH Forward link channel */ +#define LOG_FOR_DCCH_MSG_C (0x90 + LOG_1X_BASE_C) +#define LOG_DCCH_FWD_C LOG_FOR_DCCH_MSG_C + +/* 145 IS2000 DCCH Forward link channel */ +#define LOG_REV_DCCH_MSG_C (0x91 + LOG_1X_BASE_C) +#define LOG_DCCH_REV_C LOG_REV_DCCH_MSG_C + +/* 146 IS2000 DCCH Forward link channel */ +#define LOG_ZREX_C (0x92 + LOG_1X_BASE_C) + +/* 147 Active set info logging, similar to ASET_CONFIG, but simpler. */ +#define LOG_ASET_INFO_C (0x93 + LOG_1X_BASE_C) + +/* 148 Pilot Phase Measurement four-shoulder-search resutlts logging */ +#define LOG_SRCH_PPM_4SHOULDER_RES_C (0x94 + LOG_1X_BASE_C) + +/* 149 Extended Pilot Phase Measurement Data Base logging */ +#define LOG_SRCH_EXT_PPM_DB_C (0x95 + LOG_1X_BASE_C) + +/* 150 GPS Visit Parameters */ +#define LOG_GPS_VISIT_PARAMETERS_C (0x96 + LOG_1X_BASE_C) + +/* 151 GPS Measurement */ +#define LOG_GPS_MEASUREMENT_C (0x97 + LOG_1X_BASE_C) + +/* 152 UIM Data */ +#define LOG_UIM_DATA_C (0x98 + LOG_1X_BASE_C) + +/* 153 STDSO plus P2 */ +#define LOG_STDSO_P2_C (0x99 + LOG_1X_BASE_C) + +/* 154 FTDSO plus P2 */ +#define LOG_FTDSO_P2_C (0x9A + LOG_1X_BASE_C) + +/* 155 Search PPM Statistics */ +#define LOG_SRCH_PPM_STATS_C (0x9B + LOG_1X_BASE_C) + +/* 156 PPP Tx Frames */ +#define LOG_PPP_TX_FRAMES_C (0x9C + LOG_1X_BASE_C) + +/* 157 PPP Rx Frames */ +#define LOG_PPP_RX_FRAMES_C (0x9D + LOG_1X_BASE_C) + +/* 158-187 SSL reserved log codes */ +#define LOG_SSL_RESERVED_CODES_BASE_C (0x9E + LOG_1X_BASE_C) +#define LOG_SSL_LAST_C (29 + LOG_SSL_RESERVED_CODES_BASE_C) + +/* 188-199 Puma reserved log codes */ +/* 188 QPCH, version 2 */ +#define LOG_QPCH_VER_2_C (0xBC + LOG_1X_BASE_C) + +/* 189 Enhanced Access Probe */ +#define LOG_EA_PROBE_C (0xBD + LOG_1X_BASE_C) + +/* 190 BCCH Frame Information */ +#define LOG_BCCH_FRAME_INFO_C (0xBE + LOG_1X_BASE_C) + +/* 191 FCCCH Frame Information */ +#define LOG_FCCCH_FRAME_INFO_C (0xBF + LOG_1X_BASE_C) + +/* 192 FDCH Frame Information */ +#define LOG_FDCH_FRAME_INFO_C (0xC0 + LOG_1X_BASE_C) + +/* 193 RDCH Frame Information */ +#define LOG_RDCH_FRAME_INFO_C (0xC1 + LOG_1X_BASE_C) + +/* 194 FFPC Information */ +#define LOG_FFPC_INFO_C (0xC2 + LOG_1X_BASE_C) + +/* 195 RPC Information */ +#define LOG_RPC_INFO_C (0xC3 + LOG_1X_BASE_C) + +/* 196 Searcher and Finger Information */ +#define LOG_SRCH_FING_INFO_VER_2_C (0xC4 + LOG_1X_BASE_C) + +/* 197 Service Configuration, version 2 */ +#define LOG_SRV_CONFIG_VER_2_C (0xC5 + LOG_1X_BASE_C) + +/* 198 Active Set Information, version 2 */ +#define LOG_ASET_INFO_VER_2_C (0xC6 + LOG_1X_BASE_C) + +/* 199 Reduced Active Set */ +#define LOG_REDUCED_ASET_INFO_C (0xC7 + LOG_1X_BASE_C) + +/* 200 Search Triage Info */ +#define LOG_SRCH_TRIAGE_INFO_C (0xC8 + LOG_1X_BASE_C) + +/* 201 RDA Frame Information */ +#define LOG_RDA_FRAME_INFO_C (0xC9 + LOG_1X_BASE_C) + +/* 202 gpsOne fatpath information */ +#define LOG_GPS_FATPATH_INFO_C (0xCA + LOG_1X_BASE_C) + +/* 203 Extended AGC */ +#define LOG_EXTENDED_AGC_C (0xCB + LOG_1X_BASE_C) + +/* 204 Transmit AGC */ +#define LOG_TRANSMIT_AGC_C (0xCC + LOG_1X_BASE_C) + +/* 205 I/Q Offset registers */ +#define LOG_IQ_OFFSET_REGISTERS_C (0xCD + LOG_1X_BASE_C) + +/* 206 DACC I/Q Accumulator registers */ +#define LOG_DACC_IQ_ACCUMULATOR_C (0xCE + LOG_1X_BASE_C) + +/* 207 Register polling results */ +#define LOG_REGISTER_POLLING_RESULTS_C (0xCF + LOG_1X_BASE_C) + +/* 208 System arbitration module */ +#define LOG_AT_SAM_C (0xD0 + LOG_1X_BASE_C) + +/* 209 Diablo searcher finger log */ +#define LOG_DIABLO_SRCH_FING_INFO_C (0xD1 + LOG_1X_BASE_C) + +/* 210 log reserved for dandrus */ +#define LOG_SD20_LAST_ACTION_C (0xD2 + LOG_1X_BASE_C) + +/* 211 log reserved for dandrus */ +#define LOG_SD20_LAST_ACTION_HYBRID_C (0xD3 + LOG_1X_BASE_C) + +/* 212 log reserved for dandrus */ +#define LOG_SD20_SS_OBJECT_C (0xD4 + LOG_1X_BASE_C) + +/* 213 log reserved for dandrus */ +#define LOG_SD20_SS_OBJECT_HYBRID_C (0xD5 + LOG_1X_BASE_C) + +/* 214 log reserved for jpinos */ +#define LOG_BCCH_SIGNALING_C (0xD6 + LOG_1X_BASE_C) + +/* 215 log reserved for jpinos */ +#define LOG_REACH_SIGNALING_C (0xD7 + LOG_1X_BASE_C) + +/* 216 log reserved for jpinos */ +#define LOG_FCCCH_SIGNALING_C (0xD8 + LOG_1X_BASE_C) + +/* 217 RDA Frame Information 2 */ +#define LOG_RDA_FRAME_INFO_2_C (0xD9 + LOG_1X_BASE_C) + +/* 218 */ +#define LOG_GPS_BIT_EDGE_RESULTS_C (0xDA + LOG_1X_BASE_C) + +/* 219 */ +#define LOG_PE_DATA_C (0xDB + LOG_1X_BASE_C) + +/* 220 */ +#define LOG_PE_PARTIAL_DATA_C (0xDC + LOG_1X_BASE_C) + +/* 221 */ +#define LOG_GPS_SINGLE_PEAK_SRCH_RESULTS_C (0xDD + LOG_1X_BASE_C) + +/* 222 */ +#define LOG_SRCH4_SAMPRAM_C (0xDE + LOG_1X_BASE_C) + +/* 223 */ +#define HDR_AN_PPP_TX_FRAMES (0xDF + LOG_1X_BASE_C) + +/* 224 */ +#define HDR_AN_PPP_RX_FRAMES (0xE0 + LOG_1X_BASE_C) + +/* 225 */ +#define LOG_GPS_SCHEDULER_TRACE_C (0xE1 + LOG_1X_BASE_C) + +/* 226 */ +#define LOG_MPEG4_YUV_FRAME_C (0xE2 + LOG_1X_BASE_C) + +/* 227 */ +#define LOG_MPEG4_CLIP_STATS_C (0xE3 + LOG_1X_BASE_C) + +/* 228 */ +#define LOG_MPEG4_CLIP_STATS_VER2_C (0xE4 + LOG_1X_BASE_C) + +/* 226-241 MMEG reserved. */ +#define LOG_MPEG_RESERVED_CODES_BASE_C (0xF1 + LOG_1X_BASE_C) + +/* 242-274 BREW reserved log range */ +#define LOG_BREW_RESERVED_CODES_BASE_C (0xF2 + LOG_1X_BASE_C) +#define LOG_BREW_LAST_C (32 + LOG_BREW_RESERVED_CODES_BASE_C) + +/* 275-339 PPP Extended Frames */ +#define LOG_PPP_FRAMES_RESERVED_CODES_BASE_C (0x113 + LOG_1X_BASE_C) +#define LOG_PPP_FRAMES_LAST_C (64 + LOG_PPP_FRAMES_RESERVED_CODES_BASE_C) + +#define LOG_PPP_EXT_FRAMED_RX_UM_C (0x113 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_RX_RM_C (0x114 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_RX_AN_C (0x115 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_FRAMED_TX_UM_C (0x123 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_TX_RM_C (0x124 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_TX_AN_C (0x125 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_UNFRAMED_RX_UM_C (0x133 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_RX_RM_C (0x134 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_RX_AN_C (0x135 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_UNFRAMED_TX_UM_C (0x143 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_TX_RM_C (0x144 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_TX_AN_C (0x145 + LOG_1X_BASE_C) + +/* 340 LOG_PE_DATA_EXT_C */ +#define LOG_PE_DATA_EXT_C (0x154 + LOG_1X_BASE_C) + +/* REX Subsystem logs */ +#define LOG_MEMDEBUG_C (0x155 + LOG_1X_BASE_C) +#define LOG_SYSPROFILE_C (0x156 + LOG_1X_BASE_C) +#define LOG_TASKPROFILE_C (0x157 + LOG_1X_BASE_C) +#define LOG_COREDUMP_C (0x158 + LOG_1X_BASE_C) + +/* 341-349 REX subsystem logs */ +#define LOG_REX_RESERVED_CODES_BASE_C (0x155 + LOG_1X_BASE_C) +#define LOG_REX_LAST_C (8 + LOG_REX_RESERVED_CODES_BASE_C) + +/* 350 LOG_PE_PARTIAL_DATA_EXT_C */ +#define LOG_PE_PARTIAL_DATA_EXT_C (0x15E + LOG_1X_BASE_C) + +/* 351 LOG_DIAG_STRESS_TEST_C */ +#define LOG_DIAG_STRESS_TEST_C (0x15F + LOG_1X_BASE_C) + +/* 352 LOG_WMS_READ_C */ +#define LOG_WMS_READ_C (0x160 + LOG_1X_BASE_C) + +/* 353 Search Triage Info Version 2 */ +#define LOG_SRCH_TRIAGE_INFO2_C (0x161 + LOG_1X_BASE_C) + +/* 354 RLP Rx FDCH Frames */ +#define LOG_RLP_RX_FDCH_FRAMES_C (0x162 + LOG_1X_BASE_C) + +/* 355 RLP Tx FDCH Frames */ +#define LOG_RLP_TX_FDCH_FRAMES_C (0x163 + LOG_1X_BASE_C) + +/* 356-371 QTV subsystem logs */ +#define LOG_QTV_RESERVED_CODES_BASE_C (0x164 + LOG_1X_BASE_C) +#define LOG_QTV_LAST_C (15 + LOG_QTV_RESERVED_CODES_BASE_C) + +/* 372 Searcher 4 1X */ +#define LOG_SRCH4_1X_C (0x174 + LOG_1X_BASE_C) + +/* 373 Searcher sleep statistics */ +#define LOG_SRCH_SLEEP_STATS_C (0x175 + LOG_1X_BASE_C) + +/* 374 Service Configuration, version 3 */ +#define LOG_SRV_CONFIG_VER_3_C (0x176 + LOG_1X_BASE_C) + +/* 375 Searcher 4 HDR */ +#define LOG_SRCH4_HDR_C (0x177 + LOG_1X_BASE_C) + +/* 376 Searcher 4 AFLT */ +#define LOG_SRCH4_AFLT_C (0x178 + LOG_1X_BASE_C) + +/* 377 Enhanced Finger Information */ +#define LOG_ENH_FING_INFO_C (0x179 + LOG_1X_BASE_C) + +/* 378 DV Information */ +#define LOG_DV_INFO_C (0x17A + LOG_1X_BASE_C) + +/* 379 WMS set routes information */ +#define LOG_WMS_SET_ROUTES_C (0x17B + LOG_1X_BASE_C) + +/* 380 FTM Version 2 Logs */ +#define LOG_FTM_VER_2_C (0x17C + LOG_1X_BASE_C) + +/* 381 GPS Multipeak logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_SIMPLIFIED_INFO_C (0x17D + LOG_1X_BASE_C) + +/* 382 GPS Multipeak logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_VERBOSE_INFO_C (0x17E + LOG_1X_BASE_C) + +/* 383-403 HDR reserved logs */ +#define LOG_HDR_RESERVED_CODES_BASE_2_C (0x17F + LOG_1X_BASE_C) +#define LOG_HDR_LAST_2_C (20 + LOG_HDR_RESERVED_CODES_BASE_2_C) + +/* RLP Rx - PDCH partial MuxPDU5 frames */ +#define LOG_RLP_RX_PDCH_PARTIAL_MUXPDU5_FRAMES_C (0x194 + LOG_1X_BASE_C) + +/* RLP Tx - PDCH partial MuxPDU5 frames */ +#define LOG_RLP_TX_PDCH_PARTIAL_MUXPDU5_FRAMES_C (0x195 + LOG_1X_BASE_C) + +/* RLP Rx internal details */ +#define LOG_RLP_RX_INTERNAL_DETAILS_C (0x196 + LOG_1X_BASE_C) + +/* RLP Tx internal details */ +#define LOG_RLP_TX_INTERNAL_DETAILS_C (0x197 + LOG_1X_BASE_C) + +/* MPEG4 Clip Statistics version 3 */ +#define LOG_MPEG4_CLIP_STATS_VER3_C (0x198 + LOG_1X_BASE_C) + +/* Mobile IP Performance */ +#define LOG_MOBILE_IP_PERFORMANCE_C (0x199 + LOG_1X_BASE_C) + +/* 410-430 Searcher reserved logs */ +#define LOG_SEARCHER_RESERVED_CODES_BASE_C (0x19A + LOG_1X_BASE_C) +#define LOG_SEARCHER_LAST_2_C (21 + LOG_SEARCHER_RESERVED_CODES_BASE_C) + +/* 432-480 QTV reserved logs */ +#define LOG_QTV2_RESERVED_CODES_BASE_C (0x1B0 + LOG_1X_BASE_C) +#define LOG_QTV2_LAST_C (48 + LOG_QTV2_RESERVED_CODES_BASE_C) + +#define LOG_QTV_PDS2_STATS (0x1B6 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_REQUEST (0x1B7 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_RESP_HEADER (0x1B8 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_RESP_PCKT (0x1B9 + LOG_1X_BASE_C) +#define LOG_QTV_CMX_AUDIO_INPUT_DATA_C (0x1BA + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_OPTIONS_C (0x1BB + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_GET_PARAMETER_C (0x1BC + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_SET_PARAMETER_C (0x1BD + LOG_1X_BASE_C) +#define LOG_QTV_VIDEO_BITSTREAM (0x1BE + LOG_1X_BASE_C) +#define LOG_ARM_VIDEO_DECODE_STATS (0x1BF + LOG_1X_BASE_C) +#define LOG_QTV_DSP_SLICE_BUFFER_C (0x1C0 + LOG_1X_BASE_C) +#define LOG_QTV_CMD_LOGGING_C (0x1C1 + LOG_1X_BASE_C) +#define LOG_QTV_AUDIO_FRAME_PTS_INFO_C (0x1C2 + LOG_1X_BASE_C) +#define LOG_QTV_VIDEO_FRAME_DECODE_INFO_C (0x1C3 + LOG_1X_BASE_C) +#define LOG_QTV_RTCP_COMPOUND_RR_C (0x1C4 + LOG_1X_BASE_C) +#define LOG_QTV_FRAME_BUFFER_RELEASE_REASON_C (0x1C5 + LOG_1X_BASE_C) +#define LOG_QTV_AUDIO_CHANNEL_SWITCH_FRAME_C (0x1C6 + LOG_1X_BASE_C) +#define LOG_QTV_RTP_DECRYPTED_PKT_C (0x1C7 + LOG_1X_BASE_C) +#define LOG_QTV_PCR_DRIFT_RATE_C (0x1C8 + LOG_1X_BASE_C) + +/* GPS PDSM logs */ +#define LOG_PDSM_POSITION_REPORT_CALLBACK_C (0x1E1 + LOG_1X_BASE_C) +#define LOG_PDSM_PD_EVENT_CALLBACK_C (0x1E2 + LOG_1X_BASE_C) +#define LOG_PDSM_PA_EVENT_CALLBACK_C (0x1E3 + LOG_1X_BASE_C) +#define LOG_PDSM_NOTIFY_VERIFY_REQUEST_C (0x1E4 + LOG_1X_BASE_C) +#define LOG_PDSM_RESERVED1_C (0x1E5 + LOG_1X_BASE_C) +#define LOG_PDSM_RESERVED2_C (0x1E6 + LOG_1X_BASE_C) + +/* Searcher Demodulation Status log */ +#define LOG_SRCH_DEMOD_STATUS_C (0x1E7 + LOG_1X_BASE_C) + +/* Searcher Call Statistics log */ +#define LOG_SRCH_CALL_STATISTICS_C (0x1E8 + LOG_1X_BASE_C) + +/* GPS MS-MPC Forward link */ +#define LOG_MS_MPC_FWD_LINK_C (0x1E9 + LOG_1X_BASE_C) + +/* GPS MS-MPC Reverse link */ +#define LOG_MS_MPC_REV_LINK_C (0x1EA + LOG_1X_BASE_C) + +/* Protocol Services Data */ +#define LOG_DATA_PROTOCOL_LOGGING_C (0x1EB + LOG_1X_BASE_C) + +/* MediaFLO reserved log codes */ +#define LOG_MFLO_RESERVED_CODES_BASE_C (0x1EC + LOG_1X_BASE_C) +#define LOG_MFLO_LAST_C (99 + LOG_MFLO_RESERVED_CODES_BASE_C) + +/* GPS demodulation tracking header info */ +#define LOG_GPS_DEMOD_TRACKING_HEADER_C (0x250 + LOG_1X_BASE_C) + +/* GPS demodulation tracking results */ +#define LOG_GPS_DEMOD_TRACKING_C (0x251 + LOG_1X_BASE_C) + +/* GPS bit edge logs from demod tracking */ +#define LOG_GPS_DEMOD_BIT_EDGE_C (0x252 + LOG_1X_BASE_C) + +/* GPS demodulation soft decisions */ +#define LOG_GPS_DEMOD_SOFT_DECISIONS_C (0x253 + LOG_1X_BASE_C) + +/* GPS post-processed demod tracking results */ +#define LOG_GPS_DEMOD_TRACKING_POST_PROC_C (0x254 + LOG_1X_BASE_C) + +/* GPS subframe log */ +#define LOG_GPS_DEMOD_SUBFRAME_C (0x255 + LOG_1X_BASE_C) + +/* F-CPCCH Quality Information */ +#define LOG_F_CPCCH_QUALITY_INFO_C (0x256 + LOG_1X_BASE_C) + +/* Reverse PDCCH/PDCH Frame Information */ +#define LOG_R_PDCCH_R_PDCH_FRAME_INFO_C (0x257 + LOG_1X_BASE_C) + +/* Forward G Channel Information */ +#define LOG_F_GCH_INFO_C (0x258 + LOG_1X_BASE_C) + +/* Forward G Channel Frame Information */ +#define LOG_F_GCH_FRAME_INFO_C (0x259 + LOG_1X_BASE_C) + +/* Forward RC Channel Information */ +#define LOG_F_RCCH_INFO_C (0x25A + LOG_1X_BASE_C) + +/* Forward ACK Channel Information */ +#define LOG_F_ACKCH_INFO_C (0x25B + LOG_1X_BASE_C) + +/* Forward ACK Channel ACKDA Information */ +#define LOG_F_ACKCH_ACKDA_C (0x25C + LOG_1X_BASE_C) + +/* Reverse REQ Channel Information */ +#define LOG_R_REQCH_INFO_C (0x25D + LOG_1X_BASE_C) + +/* Sleep Task Statistics */ +#define LOG_SLEEP_STATS_C (0x25E + LOG_1X_BASE_C) + +/* Sleep controller statistics 1X */ +#define LOG_1X_SLEEP_CONTROLLER_STATS_C (0x25F + LOG_1X_BASE_C) + +/* Sleep controller statistics HDR */ +#define LOG_HDR_SLEEP_CONTROLLER_STATS_C (0x260 + LOG_1X_BASE_C) + +/* Sleep controller statistics GSM */ +#define LOG_GSM_SLEEP_CONTROLLER_STATS_C (0x261 + LOG_1X_BASE_C) + +/* Sleep controller statistics WCDMA */ +#define LOG_WCDMA_SLEEP_CONTROLLER_STATS_C (0x262 + LOG_1X_BASE_C) + +/* Sleep task and controller reserved logs */ +#define LOG_SLEEP_APPS_STATS_C (0x263 + LOG_1X_BASE_C) +#define LOG_SLEEP_STATS_RESERVED2_C (0x264 + LOG_1X_BASE_C) +#define LOG_SLEEP_STATS_RESERVED3_C (0x265 + LOG_1X_BASE_C) + +/* DV Information placeholder channel logs */ +#define LOG_PDCCH_LO_SELECTED_C (0x266 + LOG_1X_BASE_C) +#define LOG_PDCCH_HI_SELECTED_C (0x267 + LOG_1X_BASE_C) +#define LOG_WALSH_SELECTED_C (0x268 + LOG_1X_BASE_C) +#define LOG_PDCH_BE_SELECTED_C (0x269 + LOG_1X_BASE_C) +#define LOG_PDCCH_LLR_SELECTED_C (0x26A + LOG_1X_BASE_C) +#define LOG_CQI_ACK_LO_SELECTED_C (0x26B + LOG_1X_BASE_C) +#define LOG_CQI_ACK_HI_SELECTED_C (0x26C + LOG_1X_BASE_C) +#define LOG_RL_GAIN_SELECTED_C (0x26D + LOG_1X_BASE_C) +#define LOG_PDCCH0_SNDA_SELECTED_C (0x26E + LOG_1X_BASE_C) +#define LOG_PDCCH1_SNDA_SELECTED_C (0x26F + LOG_1X_BASE_C) + +/* 624 WMS Message List */ +#define LOG_WMS_MESSAGE_LIST_C (0x270 + LOG_1X_BASE_C) + +/* 625 Multimode Generic SIM Driver Interface */ +#define LOG_MM_GENERIC_SIM_DRIVER_C (0x271 + LOG_1X_BASE_C) + +/* 626 Generic SIM Toolkit Task */ +#define LOG_GENERIC_SIM_TOOLKIT_TASK_C (0x272 + LOG_1X_BASE_C) + +/* 627 Call Manager Phone events log */ +#define LOG_CM_PH_EVENT_C (0x273 + LOG_1X_BASE_C) + +/* 628 WMS Set Message List */ +#define LOG_WMS_SET_MESSAGE_LIST_C (0x274 + LOG_1X_BASE_C) + +/* 629-704 HDR reserved logs */ +#define LOG_HDR_RESERVED_CODES_BASE_3_C (0x275 + LOG_1X_BASE_C) +#define LOG_HDR_LAST_3_C (75 + LOG_HDR_RESERVED_CODES_BASE_3_C) + +/* 705 Call Manager call event log */ +#define LOG_CM_CALL_EVENT_C (0x2C1 + LOG_1X_BASE_C) + +/* 706-738 QVP reserved logs */ +#define LOG_QVP_RESERVED_CODES_BASE_C (0x2C2 + LOG_1X_BASE_C) +#define LOG_QVP_LAST_C (32 + LOG_QVP_RESERVED_CODES_BASE_C) + +/* 739 GPS PE Position Report log */ +#define LOG_GPS_PE_POSITION_REPORT_C (0x2E3 + LOG_1X_BASE_C) + +/* 740 GPS PE Position Report Extended log */ +#define LOG_GPS_PE_POSITION_REPORT_EXT_C (0x2E4 + LOG_1X_BASE_C) + +/* 741 log */ +#define LOG_MDDI_HOST_STATS_C (0x2E5 + LOG_1X_BASE_C) + +/* GPS Decoded Ephemeris */ +#define LOG_GPS_DECODED_EPHEMERIS_C (0x2E6 + LOG_1X_BASE_C) + +/* GPS Decoded Almanac */ +#define LOG_GPS_DECODED_ALMANAC_C (0x2E7 + LOG_1X_BASE_C) + +/* Transceiver Resource Manager */ +#define LOG_TRANSCEIVER_RESOURCE_MGR_C (0x2E8 + LOG_1X_BASE_C) + +/* GPS Position Engine Info */ +#define LOG_GPS_POSITION_ENGINE_INFO_C (0x2E9 + LOG_1X_BASE_C) + +/* 746-810 RAPTOR reserved log range */ +#define LOG_RAPTOR_RESERVED_CODES_BASE_C (0x2EA + LOG_1X_BASE_C) +#define LOG_RAPTOR_LAST_C (64 + LOG_RAPTOR_RESERVED_CODES_BASE_C) + +/* QOS Specification Logging */ + +/* QOS Requested Log */ +#define LOG_QOS_REQUESTED_C (0x32B + LOG_1X_BASE_C) + +/* QOS Granted Log */ +#define LOG_QOS_GRANTED_C (0x32C + LOG_1X_BASE_C) + +/* QOS State Log */ +#define LOG_QOS_STATE_C (0x32D + LOG_1X_BASE_C) + +#define LOG_QOS_MODIFIED_C (0x32E + LOG_1X_BASE_C) + +#define LOG_QDJ_ENQUEUE_C (0x32F + LOG_1X_BASE_C) +#define LOG_QDJ_DEQUEUE_C (0x330 + LOG_1X_BASE_C) +#define LOG_QDJ_UPDATE_C (0x331 + LOG_1X_BASE_C) +#define LOG_QDTX_ENCODER_C (0x332 + LOG_1X_BASE_C) +#define LOG_QDTX_DECODER_C (0x333 + LOG_1X_BASE_C) + +#define LOG_PORT_ASSIGNMENT_STATUS_C (0x334 + LOG_1X_BASE_C) + +/* Protocol Services reserved log codes */ +#define LOG_PS_RESERVED_CODES_BASE_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_LAST_C (25 + LOG_PS_RESERVED_C) + +#define LOG_PS_STAT_IP_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_IPV4_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_IPV6_C (0x336 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_ICMPV4_C (0x337 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_ICMPV6_C (0x338 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_TCP_C (0x339 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_UDP_C (0x33A + LOG_1X_BASE_C) + +/* Protocol Services describe all TCP instances */ +#define LOG_PS_STAT_DESC_ALL_TCP_INST_C (0x33B + LOG_1X_BASE_C) + +/* Protocol Services describe all memory pool instances */ +#define LOG_PS_STAT_DESC_ALL_MEM_POOL_INST_C (0x33C + LOG_1X_BASE_C) + +/* Protocol Services describe all IFACE instances */ +#define LOG_PS_STAT_DESC_ALL_IFACE_INST_C (0x33D + LOG_1X_BASE_C) + +/* Protocol Services describe all PPP instances */ +#define LOG_PS_STAT_DESC_ALL_PPP_INST_C (0x33E + LOG_1X_BASE_C) + +/* Protocol Services describe all ARP instances */ +#define LOG_PS_STAT_DESC_ALL_ARP_INST_C (0x33F + LOG_1X_BASE_C) + +/* Protocol Services describe delta instance */ +#define LOG_PS_STAT_DESC_DELTA_INST_C (0x340 + LOG_1X_BASE_C) + +/* Protocol Services instance TCP statistics */ +#define LOG_PS_STAT_TCP_INST_C (0x341 + LOG_1X_BASE_C) + +/* Protocol Services instance UDP statistics */ +#define LOG_PS_STAT_UDP_INST_C (0x342 + LOG_1X_BASE_C) + +/* Protocol Services instance PPP statistics */ +#define LOG_PS_STAT_PPP_INST_C (0x343 + LOG_1X_BASE_C) + +/* Protocol Services instance IFACE statistics */ +#define LOG_PS_STAT_IFACE_INST_C (0x344 + LOG_1X_BASE_C) + +/* Protocol Services instance memory statistics */ +#define LOG_PS_STAT_MEM_INST_C (0x345 + LOG_1X_BASE_C) + +/* Protocol Services instance flow statistics */ +#define LOG_PS_STAT_FLOW_INST_C (0x346 + LOG_1X_BASE_C) + +/* Protocol Services instance physical link statistics */ +#define LOG_PS_STAT_PHYS_LINK_INST_C (0x347 + LOG_1X_BASE_C) + +/* Protocol Services instance ARP statistics */ +#define LOG_PS_STAT_ARP_INST_C (0x348 + LOG_1X_BASE_C) + +/* Protocol Services instance LLC statistics */ +#define LOG_PS_STAT_LLC_INST_C (0x349 + LOG_1X_BASE_C) + +/* Protocol Services instance IPHC statistics */ +#define LOG_PS_STAT_IPHC_INST_C (0x34A + LOG_1X_BASE_C) + +/* Protocol Services instance ROHC statistics */ +#define LOG_PS_STAT_ROHC_INST_C (0x34B + LOG_1X_BASE_C) + +/* Protocol Services instance RSVP statistics */ +#define LOG_PS_STAT_RSVP_INST_C (0x34C + LOG_1X_BASE_C) + +/* Protocol Services describe all LLC instances */ +#define LOG_PS_STAT_DESC_ALL_LLC_INST_C (0x34D + LOG_1X_BASE_C) + +/* Protocol Services describe all RSVP instances */ +#define LOG_PS_STAT_DESC_ALL_RSVP_INST_C (0x34E + LOG_1X_BASE_C) + +/* Call Manager Serving System event log */ +#define LOG_CM_SS_EVENT_C (0x34F + LOG_1X_BASE_C) + +/* VcTcxo manager’s automatic frequency control log */ +#define LOG_TCXOMGR_AFC_DATA_C (0x350 + LOG_1X_BASE_C) + +/* Clock transactions and general clocks status log */ +#define LOG_CLOCK_C (0x351 + LOG_1X_BASE_C) + +/* GPS search processed peak results and their associated search parameters */ +#define LOG_GPS_PROCESSED_PEAK_C (0x352 + LOG_1X_BASE_C) + +#define LOG_MDSP_LOG_CHUNKS_C (0x353 + LOG_1X_BASE_C) + +/* Periodic RSSI update log */ +#define LOG_WLAN_RSSI_UPDATE_C (0x354 + LOG_1X_BASE_C) + +/* Periodic Link Layer statistics log */ +#define LOG_WLAN_LL_STAT_C (0x355 + LOG_1X_BASE_C) + +/* QOS Extended State Log */ +#define LOG_QOS_STATE_EX_C (0x356 + LOG_1X_BASE_C) + +/* Bluetooth host HCI transmitted data */ +#define LOG_BT_HOST_HCI_TX_C (0x357 + LOG_1X_BASE_C) + +/* Bluetooth host HCI received data */ +#define LOG_BT_HOST_HCI_RX_C (0x358 + LOG_1X_BASE_C) + +/* Internal - GPS PE Position Report Part 3 */ +#define LOG_GPS_PE_POSITION_REPORT_PART3_C (0x359 + LOG_1X_BASE_C) + +/* Extended log code which logs requested QoS */ +#define LOG_QOS_REQUESTED_EX_C (0x35A + LOG_1X_BASE_C) + +/* Extended log code which logs granted QoS */ +#define LOG_QOS_GRANTED_EX_C (0x35B + LOG_1X_BASE_C) + +/* Extended log code which logs modified QoS */ +#define LOG_QOS_MODIFIED_EX_C (0x35C + LOG_1X_BASE_C) + +/* Bus Monitor Profiling Info */ +#define LOG_BUS_MON_PROF_INFO_C (0x35D + LOG_1X_BASE_C) + +/* Pilot Phase Measurement Search results */ +#define LOG_SRCH_PPM_RES_VER_2_C (0x35E + LOG_1X_BASE_C) + +/* Pilot Phase Measurement Data Base */ +#define LOG_SRCH_PPM_DB_VER_2_C (0x35F + LOG_1X_BASE_C) + +/* Pilot Phase Measurement state machine */ +#define LOG_PPM_SM_C (0x360 + LOG_1X_BASE_C) + +/* Robust Header Compression - Compressor */ +#define LOG_ROHC_COMPRESSOR_C (0x361 + LOG_1X_BASE_C) + +/* Robust Header Compression - Decompressor */ +#define LOG_ROHC_DECOMPRESSOR_C (0x362 + LOG_1X_BASE_C) + +/* Robust Header Compression - Feedback Compressor */ +#define LOG_ROHC_FEEDBACK_COMPRESSOR_C (0x363 + LOG_1X_BASE_C) + +/* Robust Header Compression - Feedback Decompressor */ +#define LOG_ROHC_FEEDBACK_DECOMPRESSOR_C (0x364 + LOG_1X_BASE_C) + +/* Bluetooth HCI commands */ +#define LOG_BT_HCI_CMD_C (0x365 + LOG_1X_BASE_C) + +/* Bluetooth HCI events */ +#define LOG_BT_HCI_EV_C (0x366 + LOG_1X_BASE_C) + +/* Bluetooth HCI Transmitted ACL data */ +#define LOG_BT_HCI_TX_ACL_C (0x367 + LOG_1X_BASE_C) + +/* Bluetooth HCI Received ACL data */ +#define LOG_BT_HCI_RX_ACL_C (0x368 + LOG_1X_BASE_C) + +/* Bluetooth SOC H4 Deep Sleep */ +#define LOG_BT_SOC_H4DS_C (0x369 + LOG_1X_BASE_C) + +/* UMTS to CDMA Handover Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_MSG_C (0x36A + LOG_1X_BASE_C) + +/* Graphic Event Data */ +#define LOG_PROFILER_GRAPHIC_DATA_C (0x36B + LOG_1X_BASE_C) + +/* Audio Event Data */ +#define LOG_PROFILER_AUDIO_DATA_C (0x36C + LOG_1X_BASE_C) + +/* GPS Spectral Information */ +#define LOG_GPS_SPECTRAL_INFO_C (0x36D + LOG_1X_BASE_C) + +/* AHB Performance Monitor LOG data */ +#define LOG_APM_C (0x36E + LOG_1X_BASE_C) + +/* GPS Clock Report */ +#define LOG_CONVERGED_GPS_CLOCK_REPORT_C (0x36F + LOG_1X_BASE_C) + +/* GPS Position Report */ +#define LOG_CONVERGED_GPS_POSITION_REPORT_C (0x370 + LOG_1X_BASE_C) + +/* GPS Measurement Report */ +#define LOG_CONVERGED_GPS_MEASUREMENT_REPORT_C (0x371 + LOG_1X_BASE_C) + +/* GPS RF Status Report */ +#define LOG_CONVERGED_GPS_RF_STATUS_REPORT_C (0x372 + LOG_1X_BASE_C) + +/* VOIP To CDMA Handover Message - Obsoleted by 0x138B - 0x138D */ +#define LOG_VOIP_TO_CDMA_HANDOVER_MSG_C (0x373 + LOG_1X_BASE_C) + +/* GPS Prescribed Dwell Result */ +#define LOG_GPS_PRESCRIBED_DWELL_RESULT_C (0x374 + LOG_1X_BASE_C) + +/* CGPS IPC Data */ +#define LOG_CGPS_IPC_DATA_C (0x375 + LOG_1X_BASE_C) + +/* CGPS Non IPC Data */ +#define LOG_CGPS_NON_IPC_DATA_C (0x376 + LOG_1X_BASE_C) + +/* CGPS Session Report */ +#define LOG_CGPS_REP_EVT_LOG_PACKET_C (0x377 + LOG_1X_BASE_C) + +/* CGPS PDSM Get Position */ +#define LOG_CGPS_PDSM_GET_POSITION_C (0x378 + LOG_1X_BASE_C) + +/* CGPS PDSM Set Parameters */ +#define LOG_CGPS_PDSM_SET_PARAMETERS_C (0x379 + LOG_1X_BASE_C) + +/* CGPS PDSM End Session */ +#define LOG_CGPS_PDSM_END_SESSION_C (0x37A + LOG_1X_BASE_C) + +/* CGPS PDSM notify Verify Response */ +#define LOG_CGPS_PDSM_NOTIFY_VERIFY_RESP_C (0x37B + LOG_1X_BASE_C) + +/* CGPS PDSM Position Report Callback */ +#define LOG_CGPS_PDSM_POSITION_REPORT_CALLBACK_C (0x37C + LOG_1X_BASE_C) + +/* CGPS PDSM PD Event Callback */ +#define LOG_CGPS_PDSM_PD_EVENT_CALLBACK_C (0x37D + LOG_1X_BASE_C) + +/* CGPS PDSM PA Event Callback */ +#define LOG_CGPS_PDSM_PA_EVENT_CALLBACK_C (0x37E + LOG_1X_BASE_C) + +/* CGPS PDSM notify Verify Request Callback */ +#define LOG_CGPS_PDSM_NOTIFY_VERIFY_REQUEST_C (0x37F + LOG_1X_BASE_C) + +/* CGPS PDSM PD Command Error Callback */ +#define LOG_CGPS_PDSM_PD_CMD_ERR_CALLBACK_C (0x380 + LOG_1X_BASE_C) + +/* CGPS PDSM PA Command Error Callback */ +#define LOG_CGPS_PDSM_PA_CMD_ERR_CALLBACK_C (0x381 + LOG_1X_BASE_C) + +/* CGPS PDSM Position Error */ +#define LOG_CGPS_PDSM_POS_ERROR_C (0x382 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status Position Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_POS_REPORT_C (0x383 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status NMEA Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_NMEA_REPORT_C (0x384 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status Measurement Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_MEAS_REPORT_C (0x385 + LOG_1X_BASE_C) + +/* CGPS Report Server TX Packet */ +#define LOG_CGPS_REP_SVR_TX_LOG_PACKET_C (0x386 + LOG_1X_BASE_C) + +/* CGPS Report Server RX Packet */ +#define LOG_CGPS_REP_SVR_RX_LOG_PACKET_C (0x387 + LOG_1X_BASE_C) + +/* UMTS To CDMA Handover Paging Channel Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_PCH_MSG_C (0x388 + LOG_1X_BASE_C) + +/* UMTS To CDMA Handover Traffic Channel Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_TCH_MSG_C (0x389 + LOG_1X_BASE_C) + +/* Converged GPS IQ Report */ +#define LOG_CONVERGED_GPS_IQ_REPORT_C (0x38A + LOG_1X_BASE_C) + +/* VOIP To CDMA Paging Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_PCH_HANDOVER_MSG_C (0x38B + LOG_1X_BASE_C) + +/* VOIP To CDMA Access Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_ACH_HANDOVER_MSG_C (0x38C + LOG_1X_BASE_C) + +/* VOIP To CDMA Forward Traffic Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_FTC_HANDOVER_MSG_C (0x38D + LOG_1X_BASE_C) + +/* QMI reserved logs */ +#define LOG_QMI_RESERVED_CODES_BASE_C (0x38E + LOG_1X_BASE_C) +#define LOG_QMI_LAST_C (32 + LOG_QMI_RESERVED_CODES_BASE_C) + +/* QOS Info Code Update Log */ +#define LOG_QOS_INFO_CODE_UPDATE_C (0x3AF + LOG_1X_BASE_C) + +/* Transmit(Uplink) Vocoder PCM Packet Log */ +#define LOG_TX_PCM_PACKET_C (0x3B0 + LOG_1X_BASE_C) + +/* Audio Vocoder Data Paths */ +#define LOG_AUDVOC_DATA_PATHS_PACKET_C (0x3B0 + LOG_1X_BASE_C) + +/* Receive(Downlink) Vocoder PCM Packet Log */ +#define LOG_RX_PCM_PACKET_C (0x3B1 + LOG_1X_BASE_C) + +/* CRC of YUV frame log */ +#define LOG_DEC_CRC_FRAME_C (0x3B2 + LOG_1X_BASE_C) + +/* FLUTE Session Information */ +#define LOG_FLUTE_SESSION_INFO_C (0x3B3 + LOG_1X_BASE_C) + +/* FLUTE ADP File Information */ +#define LOG_FLUTE_ADP_FILE_INFO_C (0x3B4 + LOG_1X_BASE_C) + +/* FLUTE File Request Information */ +#define LOG_FLUTE_FILE_REQ_INFO_C (0x3B5 + LOG_1X_BASE_C) + +/* FLUTE FDT Instance Information */ +#define LOG_FLUTE_FDT_INST_C (0x3B6 + LOG_1X_BASE_C) + +/* FLUTE FDT Information */ +#define LOG_FLUTE_FDT_INFO_C (0x3B7 + LOG_1X_BASE_C) + +/* FLUTE File Log Packet Information */ +#define LOG_FLUTE_FILE_INFO_C (0x3B8 + LOG_1X_BASE_C) + +/* 3G 1X Parameter Overhead Information */ +#define LOG_VOIP_TO_CDMA_3G1X_PARAMETERS_C (0x3B9 + LOG_1X_BASE_C) + +/* CGPS ME Job Info */ +#define LOG_CGPS_ME_JOB_INFO_C (0x3BA + LOG_1X_BASE_C) + +/* CGPS ME SV Lists */ +#define LOG_CPGS_ME_SV_LISTS_C (0x3BB + LOG_1X_BASE_C) + +/* Flexible Profiling Status */ +#define LOG_PROFDIAG_GEN_STATUS_C (0x3BC + LOG_1X_BASE_C) + +/* Flexible Profiling Results */ +#define LOG_PROFDIAG_GEN_PROF_C (0x3BD + LOG_1X_BASE_C) + +/* FLUTE ADP File Content Log Packet Information */ +#define LOG_FLUTE_ADP_FILE_C (0x3BE + LOG_1X_BASE_C) + +/* FLUTE FDT Instance File Content Log Packet Information */ +#define LOG_FLUTE_FDT_INST_FILE_C (0x3BF + LOG_1X_BASE_C) + +/* FLUTE FDT Entries Information */ +#define LOG_FLUTE_FDT_ENTRIES_INFO_C (0x3C0 + LOG_1X_BASE_C) + +/* FLUTE File Contents Log Packet Information */ +#define LOG_FLUTE_FILE_C (0x3C1 + LOG_1X_BASE_C) + +/* CGPS ME Time-Transfer Info */ +#define LOG_CGPS_ME_TIME_TRANSFER_INFO_C (0x3C2 + LOG_1X_BASE_C) + +/* CGPS ME UMTS Time-Tagging Info */ +#define LOG_CGPS_ME_UMTS_TIME_TAGGING_INFO_C (0x3C3 + LOG_1X_BASE_C) + +/* CGPS ME Generic Time Estimate Put lnfo */ +#define LOG_CGPS_ME_TIME_EST_PUT_INFO_C (0x3C4 + LOG_1X_BASE_C) + +/* CGPS ME Generic Freq Estimate Put lnfo */ +#define LOG_CGPS_ME_FREQ_EST_PUT_INFO_C (0x3C5 + LOG_1X_BASE_C) + +/* CGPS Slow Clock Report */ +#define LOG_CGPS_SLOW_CLOCK_REPORT_C (0x3C6 + LOG_1X_BASE_C) + +/* Converged GPS Medium Grid */ +#define LOG_CONVERGED_GPS_MEDIUM_GRID_C (0x3C7 + LOG_1X_BASE_C) + +/* Static information about the driver or device */ +#define LOG_SNSD_INFO_C (0x3C8 + LOG_1X_BASE_C) + +/* Dynamic state information about the device or driver */ +#define LOG_SNSD_STATE_C (0x3C9 + LOG_1X_BASE_C) + +/* Data from a driver */ +#define LOG_SNSD_DATA (0x3CA + LOG_1X_BASE_C) +#define LOG_SNSD_DATA_C (0x3CA + LOG_1X_BASE_C) + +/* CGPS Cell DB Cell Change Info */ +#define LOG_CGPS_CELLDB_CELL_CHANGE_INFO_C (0x3CB + LOG_1X_BASE_C) + +/* xScalar YUV frame log */ +#define LOG_DEC_XSCALE_YUV_FRAME_C (0x3CC + LOG_1X_BASE_C) + +/* CRC of xScaled YUV frame log */ +#define LOG_DEC_XSCALE_CRC_FRAME_C (0x3CD + LOG_1X_BASE_C) + +/* CGPS Frequency Estimate Report */ +#define LOG_CGPS_FREQ_EST_REPORT_C (0x3CE + LOG_1X_BASE_C) + +/* GPS DCME Srch Job Completed */ +#define LOG_GPS_DCME_SRCH_JOB_COMPLETED_C (0x3CF + LOG_1X_BASE_C) + +/* CGPS ME Fastscan results */ +#define LOG_CGPS_ME_FASTSCAN_RESULTS_C (0x3D0 + LOG_1X_BASE_C) + +/* XO frequency Estimation log */ +#define LOG_XO_FREQ_EST_C (0x3D1 + LOG_1X_BASE_C) + +/* Tcxomgr field calibration data */ +#define LOG_TCXOMGR_FIELD_CAL_C (0x3D2 + LOG_1X_BASE_C) + +/* UMB Call Processing Connection Attempt */ +#define LOG_UMBCP_CONNECTION_ATTEMPT_C (0x3D3 + LOG_1X_BASE_C) + +/* UMB Call Processing Connection Release */ +#define LOG_UMBCP_CONNECTION_RELEASE_C (0x3D4 + LOG_1X_BASE_C) + +/* UMB Call Processing Page Message */ +#define LOG_UMBCP_PAGE_MESSAGE_C (0x3D5 + LOG_1X_BASE_C) + +/* UMB Call Processing OVHD Information */ +#define LOG_UMBCP_OVHD_INFO_C (0x3D6 + LOG_1X_BASE_C) + +/* UMB Call Processing Session Attempt */ +#define LOG_UMBCP_SESSION_ATTEMPT_C (0x3D7 + LOG_1X_BASE_C) + +/* UMB Call Processing Route Information */ +#define LOG_UMBCP_ROUTE_INFO_C (0x3D8 + LOG_1X_BASE_C) + +/* UMB Call Processing State Information */ +#define LOG_UMBCP_STATE_INFO_C (0x3D9 + LOG_1X_BASE_C) + +/* UMB Call Processing SNP */ +#define LOG_UMBCP_SNP_C (0x3DA + LOG_1X_BASE_C) + +/* CGPS Session Early Exit Decision */ +#define LOG_CGPS_SESSION_EARLY_EXIT_DECISION_C (0x3DB + LOG_1X_BASE_C) + +/* GPS RF Linearity Status */ +#define LOG_CGPS_ME_RF_LINEARITY_INFO_C (0x3DC + LOG_1X_BASE_C) + +/* CGPS ME 5ms IQ Sums */ +#define LOG_CGPS_ME_5MS_IQ_SUMS_C (0x3DD + LOG_1X_BASE_C) + +/* CGPS ME 20ms IQ Sums */ +#define LOG_CPGS_ME_20MS_IQ_SUMS_C (0x3DE + LOG_1X_BASE_C) + +/* ROHC Compressor Statistics */ +#define LOG_ROHC_COMPRESSOR_STATS_C (0x3DF + LOG_1X_BASE_C) + +/* ROHC Decompressor Statistics */ +#define LOG_ROHC_DECOMPRESSOR_STATS_C (0x3E0 + LOG_1X_BASE_C) + +/* Sensors - Kalman filter information */ +#define LOG_SENSOR_KF_INFO_C (0x3E1 + LOG_1X_BASE_C) + +/* Sensors - Integrated measurements */ +#define LOG_SENSOR_INT_MEAS_C (0x3E2 + LOG_1X_BASE_C) + +/* Sensors - Bias calibration values */ +#define LOG_SENSOR_BIAS_CALIBRATION_C (0x3E3 + LOG_1X_BASE_C) + +/* Log codes 0x13E4-0x13E7 are not following standard log naming convention */ + +/* DTV ISDB-T Transport Stream Packets */ +#define LOG_DTV_ISDB_TS_PACKETS (0x3E4 + LOG_1X_BASE_C) + +/* DTV ISDB-T PES Packets */ +#define LOG_DTV_ISDB_PES_PACKETS (0x3E5 + LOG_1X_BASE_C) + +/* DTV ISDB-T Sections */ +#define LOG_DTV_ISDB_SECTIONS (0x3E6 + LOG_1X_BASE_C) + +/* DTV ISDB-T Buffering */ +#define LOG_DTV_ISDB_BUFFERING (0x3E7 + LOG_1X_BASE_C) + +/* WLAN System Acquisition and Handoff */ +#define LOG_WLAN_SYS_ACQ_HO_C (0x3E8 + LOG_1X_BASE_C) + +/* WLAN General Configurable Parameters */ +#define LOG_WLAN_GEN_CONFIG_PARAMS_C (0x3E9 + LOG_1X_BASE_C) + +/* UMB Physical Layer Channel and Interference Estimation */ +#define LOG_UMB_PHY_RX_DPICH_CIE_C (0x3EA + LOG_1X_BASE_C) + +/* UMB Physical Layer MMSE/MRC Demodulated Data Symbols (Low) */ +#define LOG_UMB_PHY_RX_DATA_DEMOD_LOW_C (0x3EB + LOG_1X_BASE_C) + +/* UMB Physical Layer MMSE/MRC Demodulated Data Symbols (High) */ +#define LOG_UMB_PHY_RX_DATA_DEMOD_HIGH_C (0x3EC + LOG_1X_BASE_C) + +/* UMB Physical Layer DCH Decoder */ +#define LOG_UMB_PHY_RX_DCH_DECODER_C (0x3ED + LOG_1X_BASE_C) + +/* UMB Physical Layer DCH Statistics */ +#define LOG_UMB_PHY_DCH_STATISTICS_C (0x3EE + LOG_1X_BASE_C) + +/* UMB Physical Layer CqiPich Processing */ +#define LOG_UMB_PHY_RX_CQIPICH_C (0x3EF + LOG_1X_BASE_C) + +/* UMB Physical Layer MIMO/SIMO in CqiPich (High) */ +#define LOG_UMB_PHY_RX_CQIPICH_CHANTAPS_HIGH_C (0x3F0 + LOG_1X_BASE_C) + +/* UMB Physical Layer MIMO/SIMO in CquiPich (Low) */ +#define LOG_UMB_PHY_RX_CQIPICH_CHANTAPS_LOW_C (0x3F1 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time-Domain Channel Taps (High) */ +#define LOG_UMB_PHY_RX_PPICH_CHAN_EST_HIGH_C (0x3F2 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time-Domain Channel Taps (Low) */ +#define LOG_UMB_PHY_RX_PPICH_CHAN_EST_LOW_C (0x3F3 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator */ +#define LOG_UMB_PHY_TX_PICH_CONFIG_C (0x3F4 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACK (High) */ +#define LOG_UMB_PHY_TX_ACK_HIGH_C (0x3F5 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACK (Low) */ +#define LOG_UMB_PHY_TX_ACK_LOW_C (0x3F6 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-PICH */ +#define LOG_UMB_PHY_TX_PICH_C (0x3F7 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACH (Access) */ +#define LOG_UMB_PHY_TX_ACH_C (0x3F8 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ODDCCH (High) */ +#define LOG_UMB_PHY_TX_ODCCH_HIGH_C (0x3F9 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ODDCCH (Low) */ +#define LOG_UMB_PHY_TX_ODCCH_LOW_C (0x3FA + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-CDCCH */ +#define LOG_UMB_PHY_TX_RCDCCH_CONFIG_C (0x3FB + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for CQI sent on RCDCCH */ +#define LOG_UMB_PHY_TX_NONFLSS_CQICH_C (0x3FC + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for CQI sent on RCDCCH */ +#define LOG_UMB_PHY_TX_FLSS_CQICH_C (0x3FD + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for PACH sent on RCDCCH */ +#define LOG_UMB_PHY_TX_PAHCH_C (0x3FE + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for REQ sent on RCDCCH */ +#define LOG_UMB_PHY_TX_REQCH_C (0x3FF + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for PSD sent on RCDCCH */ +#define LOG_UMB_PHY_TX_PSDCH_C (0x400 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-DCH */ +#define LOG_UMB_PHY_TX_DCH_C (0x401 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time/Frequency/RxPower Estimate */ +#define LOG_UMB_PHY_RX_TIME_FREQ_POWER_ESTIMATE_C (0x402 + LOG_1X_BASE_C) + +/* UMB Physical Layer FLCS Processing */ +#define LOG_UMB_PHY_RX_FLCS_PROCESSING_C (0x403 + LOG_1X_BASE_C) + +/* UMB Physical Layer PBCCH Processing */ +#define LOG_UMB_PHY_RX_PBCCH_PROCESSING_C (0x404 + LOG_1X_BASE_C) + +/* UMB Physical Layer SBCCH Processing */ +#define LOG_UMB_PHY_RX_SBCCH_PROCESSING_C (0x405 + LOG_1X_BASE_C) + +/* UMB Physical Layer QPCH Processing */ +#define LOG_UMB_PHY_RX_QPCH_PROCESSING_C (0x406 + LOG_1X_BASE_C) + +/* UMB Physical Layer MRC Demodulated Data Symbols (Preamble SBCCH/QPCH) */ +#define LOG_UMB_PHY_RX_SBCCH_DEMOD_C (0x407 + LOG_1X_BASE_C) + +/* UMB Physical Layer MRC Demodulated Data Symbols (Preamble PBCCH) */ +#define LOG_UMB_PHY_RX_PBCCH_DEMOD_C (0x408 + LOG_1X_BASE_C) + +/* UMB Physical Layer VCQI */ +#define LOG_UMB_PHY_RX_VCQI_C (0x409 + LOG_1X_BASE_C) + +/* UMB Physical Layer Acquisition Algorithm */ +#define LOG_UMB_PHY_RX_INITIAL_ACQUISITION_C (0x40A + LOG_1X_BASE_C) + +/* UMB Physical Layer Handoff Search Algorithm */ +#define LOG_UMB_PHY_RX_HANDOFF_SEARCH_C (0x40B + LOG_1X_BASE_C) + +/* UMB RF RFFE Configuration Info */ +#define LOG_UMB_AT_RFFE_CONFG_C (0x40C + LOG_1X_BASE_C) + +/* UMB RF Calibrated Values After Powerup */ +#define LOG_UMB_AT_RFFE_RX_CALIB_C (0x40D + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Acquisition Mode */ +#define LOG_UMB_AT_RFFE_RX_ACQ_C (0x40E + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Idle Mode */ +#define LOG_UMB_AT_RFFE_RX_IDLE_C (0x40F + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Connected Mode */ +#define LOG_UMB_AT_RFFE_RX_CONNECTED_C (0x410 + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Connected Mode (FTM) */ +#define LOG_UMB_AT_RFFE_RX_CONNECTED_FTM_C (0x411 + LOG_1X_BASE_C) + +/* UMB RF Jammer Detector Functionality */ +#define LOG_UMB_AT_RFFE_RX_JAMMER_DETECTOR_FUNCTIONALITY_C (0x412 + LOG_1X_BASE_C) + +/* UMB RF Jammer Detector Response */ +#define LOG_UMB_AT_RFFE_RX_JAMMER_DETECTOR_RESPONSE_C (0x413 + LOG_1X_BASE_C) + +/* UMB RF RFFE TX Power Control */ +#define LOG_UMB_AT_RFFE_TX_BETA_SCALING_C (0x414 + LOG_1X_BASE_C) + +/* UMB Searcher Dump */ +#define LOG_UMB_SEARCHER_DUMP_C (0x415 + LOG_1X_BASE_C) + +/* UMB System Acquire */ +#define LOG_UMB_SYSTEM_ACQUIRE_C (0x416 + LOG_1X_BASE_C) + +/* UMB Set Maintenance */ +#define LOG_UMB_SET_MAINTENANCE_C (0x417 + LOG_1X_BASE_C) + +/* UMB QPCH */ +#define LOG_UMB_QPCH_C (0x418 + LOG_1X_BASE_C) + +/* UMB RLL Forward Partial RP Packet */ +#define LOG_UMB_RLL_FORWARD_PARTIAL_RP_C (0x419 + LOG_1X_BASE_C) + +/* UMB RLL Reverse Partial RP Packet */ +#define LOG_UMB_RLL_REVERSE_PARTIAL_RP_C (0x41A + LOG_1X_BASE_C) + +/* UMB RLL Forward Signal Packet */ +#define LOG_UMB_RLL_FORWARD_SIGNAL_C (0x41B + LOG_1X_BASE_C) + +/* UMB RLL Reverse Signal Packet */ +#define LOG_UMB_RLL_REVERSE_SIGNAL_C (0x41C + LOG_1X_BASE_C) + +/* UMB RLL Forward Statistics */ +#define LOG_UMB_RLL_FORWARD_STATS_C (0x41D + LOG_1X_BASE_C) + +/* UMB RLL Reverse Statistics */ +#define LOG_UMB_RLL_REVERSE_STATS_C (0x41E + LOG_1X_BASE_C) + +/* UMB RLL IRTP */ +#define LOG_UMB_RLL_IRTP_C (0x41F + LOG_1X_BASE_C) + +/* UMB AP Forward Link MAC Packets */ +#define LOG_UMB_AP_FL_MAC_PACKET_C (0x420 + LOG_1X_BASE_C) + +/* UMB AP Reverse Link MAC Packets */ +#define LOG_UMB_AP_RL_MAC_PACKET_C (0x421 + LOG_1X_BASE_C) + +/* GPS Performance Statistics log */ +#define LOG_CGPS_PERFORMANCE_STATS_C (0x422 + LOG_1X_BASE_C) + +/* UMB Searcher General Status */ +#define LOG_UMB_SRCH_GENERAL_STATUS_C (0x423 + LOG_1X_BASE_C) + +/* UMB Superframe Scheduler */ +#define LOG_UMB_SUPERFRAME_SCHEDULER_C (0x424 + LOG_1X_BASE_C) + +/* UMB Sector List */ +#define LOG_UMB_SECTOR_LIST_C (0x425 + LOG_1X_BASE_C) + +/* UMB MAC Access Attempt Command */ +#define LOG_UMB_MAC_ACCESS_ATTEMPT_CMD_C (0x426 + LOG_1X_BASE_C) + +/* UMB MAC Access Probe Information */ +#define LOG_UMB_MAC_ACCESS_PROBE_INFO_C (0x427 + LOG_1X_BASE_C) + +/* UMB MAC RTCMAC Package Information */ +#define LOG_UMB_MAC_RTCMAC_PKG_INFO_C (0x428 + LOG_1X_BASE_C) + +/* UMB MAC Super Frame Information */ +#define LOG_UMB_MAC_SI_INFO_C (0x429 + LOG_1X_BASE_C) + +/* UMB MAC Quick Channel Information */ +#define LOG_UMB_MAC_QCI_INFO_C (0x42A + LOG_1X_BASE_C) + +/* UMB MAC Paging Id List */ +#define LOG_UMB_MAC_PAGING_ID_LIST_C (0x42B + LOG_1X_BASE_C) + +/* UMB MAC Quick Paging Channel Information */ +#define LOG_UMB_MAC_QPCH_INFO_C (0x42C + LOG_1X_BASE_C) + +/* UMB MAC FTCMAC Information */ +#define LOG_UMB_MAC_FTCMAC_PKG_INFO_C (0x42D + LOG_1X_BASE_C) + +/* UMB MAC Access Grant Receiving */ +#define LOG_UMB_MAC_ACCESS_GRANT_C (0x42E + LOG_1X_BASE_C) + +/* UMB MAC Generic Debug Log */ +#define LOG_UMB_MAC_GEN_DEBUG_LOG_PKG_C (0x42F + LOG_1X_BASE_C) + +/* CGPS Frequency Bias Estimate */ +#define LOG_CGPS_MC_FREQ_BIAS_EST_C (0x430 + LOG_1X_BASE_C) + +/* UMB MAC Request Report Information Log */ +#define LOG_UMB_MAC_REQCH_REPORT_INFO_C (0x431 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Token Bucket Information Log */ +#define LOG_UMB_MAC_RLQOS_TOKEN_BUCKET_INFO_C (0x432 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Stream Information Log */ +#define LOG_UMB_MAC_RLQOS_STREAM_INFO_C (0x433 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Allotment Information Log */ +#define LOG_UMB_MAC_RLQOS_ALLOTMENT_INFO_C (0x434 + LOG_1X_BASE_C) + +/* UMB Searcher Recent State Machine Transactions */ +#define LOG_UMB_SRCH_STM_ACTIVITY_C (0x435 + LOG_1X_BASE_C) + +/* Performance Counters on ARM11 Profiling Information */ +#define LOG_ARM11_PERF_CNT_INFO_C (0x436 + LOG_1X_BASE_C) + +/* Protocol Services describe all flow instances */ +#define LOG_PS_STAT_DESC_ALL_FLOW_INST_C (0x437 + LOG_1X_BASE_C) + +/* Protocol Services describe all physical link instances */ +#define LOG_PS_STAT_DESC_ALL_PHYS_LINK_INST_C (0x438 + LOG_1X_BASE_C) + +/* Protocol Services describe all UDP instances */ +#define LOG_PS_STAT_DESC_ALL_UDP_INST_C (0x439 + LOG_1X_BASE_C) + +/* Searcher 4 Multi-Carrier HDR */ +#define LOG_SRCH4_MC_HDR_C (0x43A + LOG_1X_BASE_C) + +/* Protocol Services describe all IPHC instances */ +#define LOG_PS_STAT_DESC_ALL_IPHC_INST_C (0x43B + LOG_1X_BASE_C) + +/* Protocol Services describe all ROHC instances */ +#define LOG_PS_STAT_DESC_ALL_ROHC_INST_C (0x43C + LOG_1X_BASE_C) + +/* BCast security add program information */ +#define LOG_BCAST_SEC_ADD_PROGRAM_INFO_C (0x43D + LOG_1X_BASE_C) + +/* BCast security add program complete */ +#define LOG_BCAST_SEC_ADD_PROGRAM_COMPLETE_C (0x43E + LOG_1X_BASE_C) + +/* BCast security SDP parse */ +#define LOG_BCAST_SEC_SDP_PARSE_C (0x43F + LOG_1X_BASE_C) + +/* CGPS ME dynamic power optimization status */ +#define LOG_CGPS_ME_DPO_STATUS_C (0x440 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session start */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_START_C (0x441 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session stop */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_STOP_C (0x442 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session not started */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_NOT_STARTED_C (0x443 + LOG_1X_BASE_C) + +/* CGPS PDSM extern coarse position inject start */ +#define LOG_CGPS_PDSM_EXTERN_COARSE_POS_INJ_START_C (0x444 + LOG_1X_BASE_C) + +/* DTV ISDB-T TMCC information */ +#define LOG_DTV_ISDB_TMCC_C (0x445 + LOG_1X_BASE_C) + +/* RF development */ +#define LOG_RF_DEV_C (0x446 + LOG_1X_BASE_C) + +/* RF RFM API */ +#define LOG_RF_RFM_API_C (0x447 + LOG_1X_BASE_C) + +/* RF RFM state */ +#define LOG_RF_RFM_STATE_C (0x448 + LOG_1X_BASE_C) + +/* 1X RF Warmup */ +#define LOG_1X_RF_WARMUP_C (0x449 + LOG_1X_BASE_C) + +/* 1X RF power limiting */ +#define LOG_1X_RF_PWR_LMT_C (0x44A + LOG_1X_BASE_C) + +/* 1X RF state */ +#define LOG_1X_RF_STATE_C (0x44B + LOG_1X_BASE_C) + +/* 1X RF sleep */ +#define LOG_1X_RF_SLEEP_C (0x44C + LOG_1X_BASE_C) + +/* 1X RF TX state */ +#define LOG_1X_RF_TX_STATE_C (0x44D + LOG_1X_BASE_C) + +/* 1X RF IntelliCeiver state */ +#define LOG_1X_RF_INT_STATE_C (0x44E + LOG_1X_BASE_C) + +/* 1X RF RX ADC clock */ +#define LOG_1X_RF_RX_ADC_CLK_C (0x44F + LOG_1X_BASE_C) + +/* 1X RF LNA switch point */ +#define LOG_1X_RF_LNA_SWITCHP_C (0x450 + LOG_1X_BASE_C) + +/* 1X RF RX calibration */ +#define LOG_1X_RF_RX_CAL_C (0x451 + LOG_1X_BASE_C) + +/* 1X RF API */ +#define LOG_1X_RF_API_C (0x452 + LOG_1X_BASE_C) + +/* 1X RF RX PLL locking status */ +#define LOG_1X_RF_RX_PLL_LOCK_C (0x453 + LOG_1X_BASE_C) + +/* 1X RF voltage regulator */ +#define LOG_1X_RF_VREG_C (0x454 + LOG_1X_BASE_C) + +/* CGPS DIAG successful fix count */ +#define LOG_CGPS_DIAG_SUCCESSFUL_FIX_COUNT_C (0x455 + LOG_1X_BASE_C) + +/* CGPS MC track dynamic power optimization status */ +#define LOG_CGPS_MC_TRACK_DPO_STATUS_C (0x456 + LOG_1X_BASE_C) + +/* CGPS MC SBAS demodulated bits */ +#define LOG_CGPS_MC_SBAS_DEMOD_BITS_C (0x457 + LOG_1X_BASE_C) + +/* CGPS MC SBAS demodulated soft symbols */ +#define LOG_CGPS_MC_SBAS_DEMOD_SOFT_SYMBOLS_C (0x458 + LOG_1X_BASE_C) + +/* Data Services PPP configuration */ +#define LOG_DS_PPP_CONFIG_PARAMS_C (0x459 + LOG_1X_BASE_C) + +/* Data Services physical link configuration */ +#define LOG_DS_PHYS_LINK_CONFIG_PARAMS_C (0x45A + LOG_1X_BASE_C) + +/* Data Services PPP device configuration */ +#define LOG_PS_PPP_DEV_CONFIG_PARAMS_C (0x45B + LOG_1X_BASE_C) + +/* CGPS PDSM GPS state information */ +#define LOG_CGPS_PDSM_GPS_STATE_INFO_C (0x45C + LOG_1X_BASE_C) + +/* CGPS PDSM EXT status GPS state information */ +#define LOG_CGPS_PDSM_EXT_STATUS_GPS_STATE_INFO_C (0x45D + LOG_1X_BASE_C) + +/* CGPS ME Rapid Search Report */ +#define LOG_CGPS_ME_RAPID_SEARCH_REPORT_C (0x45E + LOG_1X_BASE_C) + +/* CGPS PDSM XTRA-T session */ +#define LOG_CGPS_PDSM_XTRA_T_SESSION_C (0x45F + LOG_1X_BASE_C) + +/* CGPS PDSM XTRA-T upload */ +#define LOG_CGPS_PDSM_XTRA_T_UPLOAD_C (0x460 + LOG_1X_BASE_C) + +/* CGPS Wiper Position Report */ +#define LOG_CGPS_WIPER_POSITION_REPORT_C (0x461 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard HTTP Digest Request Info */ +#define LOG_DTV_DVBH_SEC_SC_HTTP_DIGEST_REQ_C (0x462 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard HTTP Digest Response Info */ +#define LOG_DTV_DVBH_SEC_SC_HTTP_DIGEST_RSP_C (0x463 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Registration Request Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_REG_REQ_C (0x464 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Registration Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_REG_COMPLETE_C (0x465 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Deregistration Request Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_DEREG_REQ_C (0x466 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Deregistration Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_DEREG_COMPLETE_C (0x467 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Request Info */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_REQ_C (0x468 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Request Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_REQ_COMPLETE_C (0x469 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Program Selection Info */ +#define LOG_DTV_DVBH_SEC_SC_PROG_SEL_C (0x46A + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Program Selection Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_PROG_SEL_COMPLETE_C (0x46B + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_C (0x46C + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Verification Message */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_VERIFICATION_C (0x46D + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Parental Control Message */ +#define LOG_DTV_DVBH_SEC_SC_PARENTAL_CTRL_C (0x46E + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard STKM */ +#define LOG_DTV_DVBH_SEC_SC_STKM_C (0x46F + LOG_1X_BASE_C) + +/* Protocol Services Statistics Global Socket */ +#define LOG_PS_STAT_GLOBAL_SOCK_C (0x470 + LOG_1X_BASE_C) + +/* MCS Application Manager */ +#define LOG_MCS_APPMGR_C (0x471 + LOG_1X_BASE_C) + +/* MCS MSGR */ +#define LOG_MCS_MSGR_C (0x472 + LOG_1X_BASE_C) + +/* MCS QTF */ +#define LOG_MCS_QTF_C (0x473 + LOG_1X_BASE_C) + +/* Sensors Stationary Detector Output */ +#define LOG_STATIONARY_DETECTOR_OUTPUT_C (0x474 + LOG_1X_BASE_C) + +/* Print out the ppm data portion */ +#define LOG_CGPS_PDSM_EXT_STATUS_MEAS_REPORT_PPM_C (0x475 + LOG_1X_BASE_C) + +/* GNSS Position Report */ +#define LOG_GNSS_POSITION_REPORT_C (0x476 + LOG_1X_BASE_C) + +/* GNSS GPS Measurement Report */ +#define LOG_GNSS_GPS_MEASUREMENT_REPORT_C (0x477 + LOG_1X_BASE_C) + +/* GNSS Clock Report */ +#define LOG_GNSS_CLOCK_REPORT_C (0x478 + LOG_1X_BASE_C) + +/* GNSS Demod Soft Decision */ +#define LOG_GNSS_DEMOD_SOFT_DECISIONS_C (0x479 + LOG_1X_BASE_C) + +/* GNSS ME 5MS IQ sum */ +#define LOG_GNSS_ME_5MS_IQ_SUMS_C (0x47A + LOG_1X_BASE_C) + +/* GNSS CD DB report */ +#define LOG_GNSS_CD_DB_REPORT_C (0x47B + LOG_1X_BASE_C) + +/* GNSS PE WLS position report */ +#define LOG_GNSS_PE_WLS_POSITION_REPORT_C (0x47C + LOG_1X_BASE_C) + +/* GNSS PE KF position report */ +#define LOG_GNSS_PE_KF_POSITION_REPORT_C (0x47D + LOG_1X_BASE_C) + +/* GNSS PRX RF HW status report */ +#define LOG_GNSS_PRX_RF_HW_STATUS_REPORT_C (0x47E + LOG_1X_BASE_C) + +/* GNSS DRX RF HW status report */ +#define LOG_GNSS_DRX_RF_HW_STATUS_REPORT_C (0x47F + LOG_1X_BASE_C) + +/* GNSS Glonass Measurement report */ +#define LOG_GNSS_GLONASS_MEASUREMENT_REPORT_C (0x480 + LOG_1X_BASE_C) + +/* GNSS GPS HBW RXD measurement */ +#define LOG_GNSS_GPS_HBW_RXD_MEASUREMENT_C (0x481 + LOG_1X_BASE_C) + +/* GNSS PDSM position report callback */ +#define LOG_GNSS_PDSM_POSITION_REPORT_CALLBACK_C (0x482 + LOG_1X_BASE_C) + +/* ISense Request String */ +#define LOG_ISENSE_REQUEST_STR_C (0x483 + LOG_1X_BASE_C) + +/* ISense Response String */ +#define LOG_ISENSE_RESPONSE_STR_C (0x484 + LOG_1X_BASE_C) + +/* Bluetooth SOC General Log Packet*/ +#define LOG_BT_SOC_GENERAL_C (0x485 + LOG_1X_BASE_C) + +/* QCRil Call Flow */ +#define LOG_QCRIL_CALL_FLOW_C (0x486 + LOG_1X_BASE_C) + +/* CGPS Wideband FFT stats */ +#define LOG_CGPS_WB_FFT_STATS_C (0x487 + LOG_1X_BASE_C) + +/* CGPS Slow Clock Calibration Report*/ +#define LOG_CGPS_SLOW_CLOCK_CALIB_REPORT_C (0x488 + LOG_1X_BASE_C) + +/* SNS GPS TIMESTAMP */ +#define LOG_SNS_GPS_TIMESTAMP_C (0x489 + LOG_1X_BASE_C) + +/* GNSS Search Strategy Task Allocation */ +#define LOG_GNSS_SEARCH_STRATEGY_TASK_ALLOCATION_C (0x48A + LOG_1X_BASE_C) + +/* RF MC STM state */ +#define LOG_1XHDR_MC_STATE_C (0x48B + LOG_1X_BASE_C) + +/* Record in the Sparse Network DB */ +#define LOG_CGPS_SNDB_RECORD_C (0x48C + LOG_1X_BASE_C) + +/* Record removed from the DB */ +#define LOG_CGPS_SNDB_REMOVE_C (0x48D + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_GNSS_CC_PERFORMANCE_STATS_C (0x48E + LOG_1X_BASE_C) + +/* GNSS PDSM Set Paramerters */ +#define LOG_GNSS_PDSM_SET_PARAMETERS_C (0x48F + LOG_1X_BASE_C) + +/* GNSS PDSM PD Event Callback */ +#define LOG_GNSS_PDSM_PD_EVENT_CALLBACK_C (0x490 + LOG_1X_BASE_C) + +/* GNSS PDSM PA Event Callback */ +#define LOG_GNSS_PDSM_PA_EVENT_CALLBACK_C (0x491 + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_CGPS_RESERVED2_C (0x492 + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_CGPS_RESERVED3_C (0x493 + LOG_1X_BASE_C) + +/* GNSS PDSM EXT Status MEAS Report */ +#define LOG_GNSS_PDSM_EXT_STATUS_MEAS_REPORT_C (0x494 + LOG_1X_BASE_C) + +/* GNSS SM Error */ +#define LOG_GNSS_SM_ERROR_C (0x495 + LOG_1X_BASE_C) + +/* WLAN Scan */ +#define LOG_WLAN_SCAN_C (0x496 + LOG_1X_BASE_C) + +/* WLAN IBSS */ +#define LOG_WLAN_IBSS_C (0x497 + LOG_1X_BASE_C) + +/* WLAN 802.11d*/ +#define LOG_WLAN_80211D_C (0x498 + LOG_1X_BASE_C) + +/* WLAN Handoff */ +#define LOG_WLAN_HANDOFF_C (0x499 + LOG_1X_BASE_C) + +/* WLAN QoS EDCA */ +#define LOG_WLAN_QOS_EDCA_C (0x49A + LOG_1X_BASE_C) + +/* WLAN Beacon Update */ +#define LOG_WLAN_BEACON_UPDATE_C (0x49B + LOG_1X_BASE_C) + +/* WLAN Power save wow add pattern */ +#define LOG_WLAN_POWERSAVE_WOW_ADD_PTRN_C (0x49C + LOG_1X_BASE_C) + +/* WLAN WCM link metrics */ +#define LOG_WLAN_WCM_LINKMETRICS_C (0x49D + LOG_1X_BASE_C) + +/* WLAN wps scan complete*/ +#define LOG_WLAN_WPS_SCAN_COMPLETE_C (0x49E + LOG_1X_BASE_C) + +/* WLAN WPS WSC Message */ +#define LOG_WLAN_WPS_WSC_MESSAGE_C (0x49F + LOG_1X_BASE_C) + +/* WLAN WPS credentials */ +#define LOG_WLAN_WPS_CREDENTIALS_C (0x4A0 + LOG_1X_BASE_C) + +/* WLAN Linklayer stat*/ +#define LOG_WLAN_LINKLAYER_STAT_C (0x4A1 + LOG_1X_BASE_C) + +/* WLAN Qos TSpec*/ +#define LOG_WLAN_QOS_TSPEC_C (0x4A2 + LOG_1X_BASE_C) + +/* PMIC Vreg Control */ +#define LOG_PM_VREG_CONTROL_C (0x4A3 + LOG_1X_BASE_C) + +/* PMIC Vreg Level */ +#define LOG_PM_VREG_LEVEL_C (0x4A4 + LOG_1X_BASE_C) + +/* PMIC Vreg State */ +#define LOG_PM_VREG_STATE_C (0x4A5 + LOG_1X_BASE_C) + +/* CGPS SM EPH Randomization info */ +#define LOG_CGPS_SM_EPH_RANDOMIZATION_INFO_C (0x4A6 + LOG_1X_BASE_C) + +/* Audio calibration data */ +#define LOG_QACT_DATA_C (0x4A7 + LOG_1X_BASE_C) + +/* Compass 2D Tracked Calibration Set */ +#define LOG_SNS_VCPS_2D_TRACKED_CAL_SET (0x4A8 + LOG_1X_BASE_C) + +/* Compass 3D Tracked Calibration Set */ +#define LOG_SNS_VCPS_3D_TRACKED_CAL_SET (0x4A9 + LOG_1X_BASE_C) + +/* Calibration metric */ +#define LOG_SNS_VCPS_CAL_METRIC (0x4AA + LOG_1X_BASE_C) + +/* Accelerometer distance */ +#define LOG_SNS_VCPS_ACCEL_DIST (0x4AB + LOG_1X_BASE_C) + +/* Plane update */ +#define LOG_SNS_VCPS_PLANE_UPDATE (0x4AC + LOG_1X_BASE_C) + +/* Location report */ +#define LOG_SNS_VCPS_LOC_REPORT (0x4AD + LOG_1X_BASE_C) + +/* CM Active subscription */ +#define LOG_CM_PH_EVENT_SUBSCRIPTION_PREF_INFO_C (0x4AE + LOG_1X_BASE_C) + +/* DSDS version of CM call event */ +#define LOG_CM_DS_CALL_EVENT_C (0x4AF + LOG_1X_BASE_C) + +/* Sensors ?MobiSens Output */ +#define LOG_MOBISENS_OUTPUT_C (0x4B0 + LOG_1X_BASE_C) + +/* Accelerometer Data */ +#define LOG_ACCEL_DATA_C (0x4B1 + LOG_1X_BASE_C) + +/* Accelerometer Compensated Data */ +#define LOG_ACCEL_COMP_DATA_C (0x4B2 + LOG_1X_BASE_C) + +/* Motion State Data */ +#define LOG_MOTION_STATE_DATA_C (0x4B3 + LOG_1X_BASE_C) + +/* Stationary Position Indicator */ +#define LOG_STAT_POS_IND_C (0x4B4 + LOG_1X_BASE_C) + +/* Motion State Features */ +#define LOG_MOTION_STATE_FEATURES_C (0x4B5 + LOG_1X_BASE_C) + +/* Motion State Hard Decision */ +#define LOG_MOTION_STATE_HARD_DECISION_C (0x4B6 + LOG_1X_BASE_C) + +/* Motion State Soft Decision */ +#define LOG_MOTION_STATE_SOFT_DECISION_C (0x4B7 + LOG_1X_BASE_C) + +/* Sensors Software Version */ +#define LOG_SENSORS_SOFTWARE_VERSION_C (0x4B8 + LOG_1X_BASE_C) + +/* MobiSens Stationary Position Indicator Log Packet */ +#define LOG_MOBISENS_SPI_C (0x4B9 + LOG_1X_BASE_C) + +/* XO calibration raw IQ data */ +#define LOG_XO_IQ_DATA_C (0x4BA + LOG_1X_BASE_C) + +/*DTV CMMB Control Tabl Updated*/ +#define LOG_DTV_CMMB_CONTROL_TABLE_UPDATE ((0x4BB) + LOG_1X_BASE_C) + +/*DTV CMMB Media API Buffering Status*/ +#define LOG_DTV_CMMB_MEDIA_BUFFERING_STATUS ((0x4BC) + LOG_1X_BASE_C) + +/*DTV CMMB *Emergency Broadcast Data*/ +#define LOG_DTV_CMMB_CONTROL_EMERGENCY_BCAST ((0x4BD) + LOG_1X_BASE_C) + +/*DTV CMMB EMM/ECM Data*/ +#define LOG_DTV_CMMB_CAS_EMM_ECM ((0x4BE) + LOG_1X_BASE_C) + +/*DTV CMMB HW Status*/ +#define LOG_DTV_CMMB_HW_PERFORMANCE ((0x4BF) + LOG_1X_BASE_C) + +/*DTV CMMB ESSG Program Indication Information*/ +#define LOG_DTV_CMMB_ESG_PROGRAM_INDICATION_INFORMATION ((0x4C0) + LOG_1X_BASE_C) + +/* Sensors ¨C binary output of converted sensor data */ +#define LOG_CONVERTED_SENSOR_DATA_C ((0x4C1) + LOG_1X_BASE_C) + +/* CM Subscription event */ +#define LOG_CM_SUBSCRIPTION_EVENT_C ((0x4C2) + LOG_1X_BASE_C) + +/* Sensor Ambient Light Data */ +#define LOG_SNS_ALS_DATA_C ((0x4C3) + LOG_1X_BASE_C) + +/*Sensor Ambient Light Adaptive Data */ +#define LOG_SNS_ALS_DATA_ADAPTIVE_C ((0x4C4) + LOG_1X_BASE_C) + +/*Sensor Proximity Distance Data */ +#define LOG_SNS_PRX_DIST_DATA_C ((0x4C5) + LOG_1X_BASE_C) + +/*Sensor Proximity Data */ +#define LOG_SNS_PRX_DATA_C ((0x4C6) + LOG_1X_BASE_C) + +#define LOG_GNSS_SBAS_REPORT_C ((0x4C7) + LOG_1X_BASE_C) + +#define LOG_CPU_MONITOR_MODEM_C ((0x4C8) + LOG_1X_BASE_C) + +#define LOG_CPU_MONITOR_APPS_C ((0x4C9) + LOG_1X_BASE_C) + +#define LOG_BLAST_TASKPROFILE_C ((0x4CA) + LOG_1X_BASE_C) + +#define LOG_BLAST_SYSPROFILE_C ((0x4CB) + LOG_1X_BASE_C) + +#define LOG_FM_RADIO_FTM_C ((0x4CC) + LOG_1X_BASE_C) + +#define LOG_FM_RADIO_C ((0x4CD) + LOG_1X_BASE_C) + +#define LOG_UIM_DS_DATA_C ((0x4CE) + LOG_1X_BASE_C) + +#define LOG_QMI_CALL_FLOW_C ((0x4CF) + LOG_1X_BASE_C) + +#define LOG_APR_MODEM_C ((0x4D0) + LOG_1X_BASE_C) + +#define LOG_APR_APPS_C ((0x4D1) + LOG_1X_BASE_C) + +#define LOG_APR_ADSP_C ((0x4D2) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_RX_RAW_PACKET_C ((0x4D3) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_TX_RAW_PACKET_C ((0x4D4) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_RX_FRAME_PACKET_C ((0x4D5) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_TX_FRAME_PACKET_C ((0x4D6) + LOG_1X_BASE_C) + +#define LOG_CGPS_PDSM_EXT_STATUS_POS_INJ_REQ_INFO_C ((0x4D7) + LOG_1X_BASE_C) + +#define LOG_TEMPERATURE_MONITOR_C ((0x4D8) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_REST_DETECT_C ((0x4D9) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_ORIENTATION_C ((0x4DA) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_FACING_C ((0x4DB) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_BASIC_C ((0x4DC) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_HINBYE_C ((0x4DD) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_MEASUREMENT_REPORT_C ((0x4DE) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_POSITION_REPORT_C ((0x4E0) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_SVPOLY_REPORT_C ((0x4E1) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRSYNC_C ((0x4E2) + LOG_1X_BASE_C) + +#define LOG_SNS_MGR_EVENT_NOTIFY_C ((0x4E3) + LOG_1X_BASE_C) + +#define LOG_SNS_MGR_EVENT_REGISTER_C ((0x4E4) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_BEGIN_C ((0x4E5) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_PPM_SUSPEND_C ((0x4E6) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_REPORT_THROTTLED_C ((0x4E7) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_REPORT_FIRED_C ((0x4E8) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_END_C ((0x4E9) + LOG_1X_BASE_C) + +#define LOG_TRSP_DATA_STALL_C ((0x801) + LOG_1X_BASE_C) + +#define LOG_WLAN_PKT_LOG_INFO_C ((0x8E0) + LOG_1X_BASE_C) + +/* The last defined DMSS log code */ +#define LOG_1X_LAST_C ((0x8E0) + LOG_1X_BASE_C) + +/* This is only here for old (pre equipment ID update) logging code */ +#define LOG_LAST_C ( LOG_1X_LAST_C & 0xFFF ) + +/* ------------------------------------------------------------------------- + * APPS LOG definition: + * The max number of 16 log codes is assigned for Apps. + * The last apps log code could be 0xB00F. + * Below definition is consolidated from log_codes_apps.h + * ------------------------------------------------------------------------- */ + +/* ======================== APPS Profiling ======================== */ +#define LOG_APPS_SYSPROFILE_C (0x01 + LOG_APPS_BASE_C) +#define LOG_APPS_TASKPROFILE_C (0x02 + LOG_APPS_BASE_C) + +/* The last defined APPS log code */ +/* Change it to (0x02 + LOG_LTE_LAST_C) to allow LTE log codes */ +#define LOG_APPS_LAST_C (0x02 + LOG_LTE_LAST_C) + +/* ------------------------------------------------------------------------- + * Log Equipment IDs. + * The number is represented by 4 bits. + * ------------------------------------------------------------------------- */ +typedef enum { + LOG_EQUIP_ID_OEM = 0, /* 3rd party OEM (licensee) use */ + LOG_EQUIP_ID_1X = 1, /* Traditional 1X line of products */ + LOG_EQUIP_ID_RSVD2 = 2, + LOG_EQUIP_ID_RSVD3 = 3, + LOG_EQUIP_ID_WCDMA = 4, + LOG_EQUIP_ID_GSM = 5, + LOG_EQUIP_ID_LBS = 6, + LOG_EQUIP_ID_UMTS = 7, + LOG_EQUIP_ID_TDMA = 8, + LOG_EQUIP_ID_BOA = 9, + LOG_EQUIP_ID_DTV = 10, + LOG_EQUIP_ID_APPS = 11, + LOG_EQUIP_ID_DSP = 12, + + LOG_EQUIP_ID_LAST_DEFAULT = LOG_EQUIP_ID_DSP +} log_equip_id_enum_type; + +#define LOG_EQUIP_ID_MAX 0xF /* The equipment ID is 4 bits */ + +/* Note that these are the official values and are used by default in + diagtune.h. + */ +#define LOG_EQUIP_ID_0_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_1_LAST_CODE_DEFAULT LOG_1X_LAST_C +#define LOG_EQUIP_ID_2_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_3_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_4_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_5_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_6_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_7_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_8_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_9_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_10_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_11_LAST_CODE_DEFAULT LOG_LTE_LAST_C +#define LOG_EQUIP_ID_12_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_13_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_14_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_15_LAST_CODE_DEFAULT 0 + +#endif /* LOG_CODES_H */ diff --git a/core/utils/host_diag_log/src/host_diag_log.c b/core/utils/host_diag_log/src/host_diag_log.c new file mode 100644 index 0000000000..4fd357eb15 --- /dev/null +++ b/core/utils/host_diag_log/src/host_diag_log.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: host_diag_log.c + + OVERVIEW: This source file contains definitions for WLAN UTIL diag APIs + + DEPENDENCIES: + ============================================================================*/ + +#include "cdf_types.h" +#include "i_host_diag_core_log.h" +#include "host_diag_core_event.h" +#include "wlan_nlink_common.h" +#include "cds_sched.h" +#include "wlan_ptt_sock_svc.h" +#include "wlan_nlink_srv.h" +#include "cds_api.h" + +#define PTT_MSG_DIAG_CMDS_TYPE (0x5050) + +#define DIAG_TYPE_LOGS (1) +#define DIAG_TYPE_EVENTS (2) + +#define DIAG_SWAP16(A) ((((uint16_t)(A) & 0xff00) >> 8) | (((uint16_t)(A) & 0x00ff) << 8)) + +typedef struct event_report_s { + uint32_t diag_type; + uint16_t event_id; + uint16_t length; +} event_report_t; + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_set_code() - + + This function sets the logging code in the given log record. + + \param - ptr - Pointer to the log header type. + - code - log code. + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_set_code(void *ptr, uint16_t code) +{ + if (ptr) { + /* All log packets are required to start with 'log_header_type' */ + ((log_hdr_type *) ptr)->code = code; + } +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_set_length() - + + This function sets the length field in the given log record. + + \param - ptr - Pointer to the log header type. + - length - log length. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_set_length(void *ptr, uint16_t length) +{ + if (ptr) { + /* All log packets are required to start with 'log_header_type' */ + ((log_hdr_type *) ptr)->len = (uint16_t) length; + } +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_submit() - + + This function sends the log data to the ptt socket app only if it is registered with the driver. + + \param - ptr - Pointer to the log header type. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_submit(void *plog_hdr_ptr) +{ + log_hdr_type *pHdr = (log_hdr_type *) plog_hdr_ptr; + tAniHdr *wmsg = NULL; + uint8_t *pBuf; + uint16_t data_len; + uint16_t total_len; + + if (cds_is_load_unload_in_progress()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Unloading/Loading in Progress. Ignore!!!", + __func__); + return; + } + + if (nl_srv_is_initialized() != 0) + return; + + if (cds_is_multicast_logging()) { + data_len = pHdr->len; + + total_len = sizeof(tAniHdr) + sizeof(uint32_t) + data_len; + + pBuf = (uint8_t *) cdf_mem_malloc(total_len); + + if (!pBuf) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "cdf_mem_malloc failed"); + return; + } + + cdf_mem_zero((void *)pBuf, total_len); + + wmsg = (tAniHdr *) pBuf; + wmsg->type = PTT_MSG_DIAG_CMDS_TYPE; + wmsg->length = total_len; + wmsg->length = DIAG_SWAP16(wmsg->length); + pBuf += sizeof(tAniHdr); + + /* Diag Type events or log */ + *(uint32_t *) pBuf = DIAG_TYPE_LOGS; + pBuf += sizeof(uint32_t); + + memcpy(pBuf, pHdr, data_len); + ptt_sock_send_msg_to_app (wmsg, 0, ANI_NL_MSG_PUMAC, + INVALID_PID); + cdf_mem_free((void *)wmsg); + } + return; +} + +/** + * host_diag_log_wlock() - This function is used to send wake lock diag events + * @reason: Reason why the wakelock was taken or released + * @wake_lock_name: Function in which the wakelock was taken or released + * @timeout: Timeout value in case of timed wakelocks + * @status: Status field indicating whether the wake lock was taken/released + * + * This function is used to send wake lock diag events to user space + * + * Return: None + * + */ +void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name, + uint32_t timeout, uint32_t status) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct host_event_wlan_wake_lock); + + if ((nl_srv_is_initialized() != 0) || + (cds_is_wakelock_enabled() == false)) + return; + + wlan_diag_event.status = status; + wlan_diag_event.reason = reason; + wlan_diag_event.timeout = timeout; + wlan_diag_event.name_len = strlen(wake_lock_name); + strlcpy(&wlan_diag_event.name[0], + wake_lock_name, + wlan_diag_event.name_len+1); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_WAKE_LOCK); +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_event_report_payload() - + + This function sends the event data to the ptt socket app only if it is + registered with the driver. + + \param - ptr - Pointer to the log header type. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_event_report_payload(uint16_t event_Id, uint16_t length, + void *pPayload) +{ + tAniHdr *wmsg = NULL; + uint8_t *pBuf; + event_report_t *pEvent_report; + uint16_t total_len; + + if (cds_is_load_unload_in_progress()) { + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "%s: Unloading/Loading in Progress. Ignore!!!", + __func__); + return; + } + + if (nl_srv_is_initialized() != 0) + return; + + if (cds_is_multicast_logging()) { + total_len = sizeof(tAniHdr) + sizeof(event_report_t) + length; + + pBuf = (uint8_t *) cdf_mem_malloc(total_len); + + if (!pBuf) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "cdf_mem_malloc failed"); + return; + } + wmsg = (tAniHdr *) pBuf; + wmsg->type = PTT_MSG_DIAG_CMDS_TYPE; + wmsg->length = total_len; + wmsg->length = DIAG_SWAP16(wmsg->length); + pBuf += sizeof(tAniHdr); + + pEvent_report = (event_report_t *) pBuf; + pEvent_report->diag_type = DIAG_TYPE_EVENTS; + pEvent_report->event_id = event_Id; + pEvent_report->length = length; + + pBuf += sizeof(event_report_t); + + memcpy(pBuf, pPayload, length); + + if (ptt_sock_send_msg_to_app + (wmsg, 0, ANI_NL_MSG_PUMAC, INVALID_PID) < 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "Ptt Socket error sending message to the app!!"); + cdf_mem_free((void *)wmsg); + return; + } + + cdf_mem_free((void *)wmsg); + } + + return; + +} diff --git a/core/utils/host_diag_log/src/i_host_diag_core_event.h b/core/utils/host_diag_log/src/i_host_diag_core_event.h new file mode 100644 index 0000000000..cd4d0c3d55 --- /dev/null +++ b/core/utils/host_diag_log/src/i_host_diag_core_event.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __I_HOST_DIAG_CORE_EVENT_H ) +#define __I_HOST_DIAG_CORE_EVENT_H + +/**========================================================================= + + \file i_host_diag_core_event.h + + \brief Android specific definitions for WLAN UTIL DIAG events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include +#endif + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +void host_diag_event_report_payload(uint16_t event_Id, uint16_t length, + void *pPayload); +/*--------------------------------------------------------------------------- + Allocate an event payload holder + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_EVENT_DEF( payload_name, payload_type ) \ + payload_type(payload_name) + +/*--------------------------------------------------------------------------- + Report the event + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_EVENT_REPORT( payload_ptr, ev_id ) \ + do { \ + host_diag_event_report_payload( ev_id, \ + sizeof( *(payload_ptr) ), \ + (void *)(payload_ptr) ); \ + } while (0) + +#else /* FEATURE_WLAN_DIAG_SUPPORT */ + +#define WLAN_HOST_DIAG_EVENT_DEF( payload_name, payload_type ) +#define WLAN_HOST_DIAG_EVENT_REPORT( payload_ptr, ev_id ) + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name, + uint32_t timeout, uint32_t status); +#else +static inline void host_diag_log_wlock(uint32_t reason, + const char *wake_lock_name, + uint32_t timeout, uint32_t status) +{ + +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_HOST_DIAG_CORE_EVENT_H */ diff --git a/core/utils/host_diag_log/src/i_host_diag_core_log.h b/core/utils/host_diag_log/src/i_host_diag_core_log.h new file mode 100644 index 0000000000..d670d5339f --- /dev/null +++ b/core/utils/host_diag_log/src/i_host_diag_core_log.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __I_HOST_DIAG_CORE_LOG_H ) +#define __I_HOST_DIAG_CORE_LOG_H + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include +#endif + +/**========================================================================= + + \file i_host_diag_core_event.h + + \brief android-specific definitions for WLAN UTIL DIAG logs + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +/* FIXME To be removed when DIAG support is added. This definiton should be */ +/* picked from log.h file above. */ +typedef struct { + /* Specifies the length, in bytes of the entry, including this header. */ + uint16_t len; + + /* Specifies the log code for the entry */ + uint16_t code; + + /*Time Stamp lo */ + uint32_t ts_lo; + + /*Time Stamp hi */ + uint32_t ts_hi; +} __packed log_hdr_type; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void host_diag_log_set_code(void *ptr, uint16_t code); +void host_diag_log_set_length(void *ptr, uint16_t length); +void host_diag_log_set_timestamp(void *plog_hdr_ptr); +void host_diag_log_submit(void *plog_hdr_ptr); + +/*--------------------------------------------------------------------------- + Allocate an event payload holder + ---------------------------------------------------------------------------*/ + +#define WLAN_HOST_DIAG_LOG_ALLOC( payload_ptr, payload_type, log_code ) \ + do { \ + payload_ptr = ( payload_type *)cdf_mem_malloc(sizeof(payload_type)); \ + if(payload_ptr) { \ + cdf_mem_zero(payload_ptr, sizeof(payload_type)); \ + host_diag_log_set_code(payload_ptr, log_code); \ + host_diag_log_set_length(payload_ptr, sizeof(payload_type)); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------- + Report the event + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_LOG_REPORT( payload_ptr ) \ + do { \ + if(payload_ptr) { \ + host_diag_log_submit( payload_ptr); \ + cdf_mem_free(payload_ptr); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------- + Free the payload + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_LOG_FREE( payload_ptr ) \ + do \ + { \ + if( payload_ptr) \ + { \ + cdf_mem_free(payload_ptr); \ + } \ + } while (0) + +#else /* FEATURE_WLAN_DIAG_SUPPORT */ + +#define WLAN_HOST_DIAG_LOG_ALLOC( payload_ptr, payload_type, log_code ) +#define WLAN_HOST_DIAG_LOG_REPORT( payload_ptr ) +#define WLAN_HOST_DIAG_LOG_FREE( payload_ptr ) + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_HOST_DIAG_CORE_LOG_H */ diff --git a/core/utils/logging/inc/wlan_logging_sock_svc.h b/core/utils/logging/inc/wlan_logging_sock_svc.h new file mode 100644 index 0000000000..c9070ab234 --- /dev/null +++ b/core/utils/logging/inc/wlan_logging_sock_svc.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_logging_sock_svc.h +* +******************************************************************************/ + +#ifndef WLAN_LOGGING_SOCK_SVC_H +#define WLAN_LOGGING_SOCK_SVC_H + +#include +#include +#include +#include + +int wlan_logging_sock_init_svc(void); +int wlan_logging_sock_deinit_svc(void); +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf); +int wlan_logging_sock_deactivate_svc(void); +int wlan_log_to_user(CDF_TRACE_LEVEL log_level, char *to_be_sent, int length); +void wlan_logging_set_per_pkt_stats(void); +void wlan_logging_set_log_level(void); +void wlan_logging_set_fw_flush_complete(void); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code); +#else +static inline void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code) +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/core/utils/logging/src/wlan_logging_sock_svc.c b/core/utils/logging/src/wlan_logging_sock_svc.c new file mode 100644 index 0000000000..d82e008ce4 --- /dev/null +++ b/core/utils/logging/src/wlan_logging_sock_svc.c @@ -0,0 +1,817 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_logging_sock_svc.c +* +******************************************************************************/ + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +#include +#include +#include +#include +#include +#include +#include "pktlog_ac.h" +#include + +#define LOGGING_TRACE(level, args ...) \ + CDF_TRACE(CDF_MODULE_ID_HDD, level, ## args) + +/* Global variables */ + +#define ANI_NL_MSG_LOG_TYPE 89 +#define ANI_NL_MSG_READY_IND_TYPE 90 +#define MAX_LOGMSG_LENGTH 4096 + +#define HOST_LOG_DRIVER_MSG 0x001 +#define HOST_LOG_PER_PKT_STATS 0x002 +#define HOST_LOG_FW_FLUSH_COMPLETE 0x003 + +struct log_msg { + struct list_head node; + unsigned int radio; + unsigned int index; + /* indicates the current filled log length in logbuf */ + unsigned int filled_length; + /* + * Buf to hold the log msg + * tAniHdr + log + */ + char logbuf[MAX_LOGMSG_LENGTH]; +}; + +struct wlan_logging { + /* Log Fatal and ERROR to console */ + bool log_fe_to_console; + /* Number of buffers to be used for logging */ + int num_buf; + /* Lock to synchronize access to shared logging resource */ + spinlock_t spin_lock; + /* Holds the free node which can be used for filling logs */ + struct list_head free_list; + /* Holds the filled nodes which needs to be indicated to APP */ + struct list_head filled_list; + /* Wait queue for Logger thread */ + wait_queue_head_t wait_queue; + /* Logger thread */ + struct task_struct *thread; + /* Logging thread sets this variable on exit */ + struct completion shutdown_comp; + /* Indicates to logger thread to exit */ + bool exit; + /* Holds number of dropped logs */ + unsigned int drop_count; + /* current logbuf to which the log will be filled to */ + struct log_msg *pcur_node; + /* Event flag used for wakeup and post indication*/ + unsigned long eventFlag; + /* Indicates logger thread is activated */ + bool is_active; + /* Flush completion check */ + bool is_flush_complete; +}; + +static struct wlan_logging gwlan_logging; +static struct log_msg *gplog_msg; + +/* PID of the APP to log the message */ +static int gapp_pid = INVALID_PID; + +/* Utility function to send a netlink message to an application + * in user space + */ +static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio, + int src_mod, int pid) +{ + int err = -1; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl = NULL; + struct sk_buff *skb; + struct nlmsghdr *nlh; + int wmsg_length = wmsg->length; + static int nlmsg_seq; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: invalid radio id [%d]", __func__, radio); + return -EINVAL; + } + + payload_len = wmsg_length + sizeof(wnl->radio); + tot_msg_len = NLMSG_SPACE(payload_len); + skb = dev_alloc_skb(tot_msg_len); + if (skb == NULL) { + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: dev_alloc_skb() failed for msg size[%d]", + __func__, tot_msg_len); + return -ENOMEM; + } + nlh = nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len, + NLM_F_REQUEST); + if (NULL == nlh) { + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]", + __func__, tot_msg_len); + kfree_skb(skb); + return -ENOMEM; + } + + wnl = (tAniNlHdr *) nlh; + wnl->radio = radio; + memcpy(&wnl->wmsg, wmsg, wmsg_length); + LOGGING_TRACE(CDF_TRACE_LEVEL_INFO, + "%s: Sending Msg Type [0x%X] to pid[%d]\n", + __func__, be16_to_cpu(wmsg->type), pid); + + err = nl_srv_ucast(skb, pid, MSG_DONTWAIT); + return err; +} + +/** + * is_data_path_module() - To check for a Datapath module + * @mod_id: Module id + * + * Checks if the input module id belongs to data path. + * + * Return: True if the module belongs to data path, false otherwise + */ +static bool is_data_path_module(CDF_MODULE_ID mod_id) +{ + switch (mod_id) { + case CDF_MODULE_ID_HDD_DATA: + case CDF_MODULE_ID_HDD_SAP_DATA: + case CDF_MODULE_ID_HTC: + case CDF_MODULE_ID_TXRX: + case CDF_MODULE_ID_HIF: + return true; + default: + return false; + } +} + +static void set_default_logtoapp_log_level(void) +{ + int i; + + /* module id 0 is reserved */ + for (i = 1; i < CDF_MODULE_ID_MAX; i++) { + if (is_data_path_module(i)) + cdf_trace_set_module_trace_level(i, + CDF_DATA_PATH_TRACE_LEVEL); + else + cdf_trace_set_value(i, CDF_TRACE_LEVEL_ALL, true); + } +} + +static void clear_default_logtoapp_log_level(void) +{ + int module; + + for (module = 0; module < CDF_MODULE_ID_MAX; module++) { + cdf_trace_set_value(module, CDF_TRACE_LEVEL_NONE, false); + cdf_trace_set_value(module, CDF_TRACE_LEVEL_FATAL, true); + cdf_trace_set_value(module, CDF_TRACE_LEVEL_ERROR, true); + } + + cdf_trace_set_value(CDF_MODULE_ID_RSV4, CDF_TRACE_LEVEL_NONE, + false); +} + +/* Need to call this with spin_lock acquired */ +static int wlan_queue_logmsg_for_app(void) +{ + char *ptr; + int ret = 0; + ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)]; + ptr[gwlan_logging.pcur_node->filled_length] = '\0'; + + *(unsigned short *)(gwlan_logging.pcur_node->logbuf) = + ANI_NL_MSG_LOG_TYPE; + *(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) = + gwlan_logging.pcur_node->filled_length; + list_add_tail(&gwlan_logging.pcur_node->node, + &gwlan_logging.filled_list); + + if (!list_empty(&gwlan_logging.free_list)) { + /* Get buffer from free list */ + gwlan_logging.pcur_node = + (struct log_msg *)(gwlan_logging.free_list.next); + list_del_init(gwlan_logging.free_list.next); + } else if (!list_empty(&gwlan_logging.filled_list)) { + /* Get buffer from filled list */ + /* This condition will drop the packet from being + * indicated to app + */ + gwlan_logging.pcur_node = + (struct log_msg *)(gwlan_logging.filled_list.next); + ++gwlan_logging.drop_count; + /* print every 64th drop count */ + if (cds_is_multicast_logging() && + (!(gwlan_logging.drop_count % 0x40))) { + pr_err + ("%s: drop_count = %u index = %d filled_length = %d\n", + __func__, gwlan_logging.drop_count, + gwlan_logging.pcur_node->index, + gwlan_logging.pcur_node->filled_length); + } + list_del_init(gwlan_logging.filled_list.next); + ret = 1; + } + + /* Reset the current node values */ + gwlan_logging.pcur_node->filled_length = 0; + return ret; +} + +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * wlan_add_user_log_time_stamp() - add time stamp in WLAN log buffer + * @tbuf: Pointer to time stamp buffer + * @tbuf_sz: Time buffer size + * @ts: Time stamp value + * + * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag + * to convert it into user visible time stamp. In adrstea FW also uses QTIMER + * raw ticks which is needed to synchronize host and fw log time stamps + * + * + * For discrete solution e.g rome use system tick and convert it into + * seconds.milli seconds + */ +static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts) +{ + int tlen; + + tlen = scnprintf(tbuf, tbuf_sz, "[%s][%llu] ", current->comm, ts); + return tlen; +} +#else +/** + * wlan_add_user_log_time_stamp() - add time stamp in WLAN log buffer + * @tbuf: Pointer to time stamp buffer + * @tbuf_sz: Time buffer size + * @ts: Time stamp value + * + * For adrastea time stamp QTIMER raw tick which will be used by cnss_diag + * to convert it into user visible time stamp + * + * For discrete solution e.g rome use system tick and convert it into + * seconds.milli seconds + */ +static int wlan_add_user_log_time_stamp(char *tbuf, size_t tbuf_sz, uint64_t ts) +{ + int tlen; + uint32_t rem; + + rem = do_div(ts, CDF_MC_TIMER_TO_SEC_UNIT); + tlen = scnprintf(tbuf, tbuf_sz, "[%s][%lu.%06lu] ", current->comm, + (unsigned long) ts, (unsigned long)rem); + return tlen; +} +#endif + +int wlan_log_to_user(CDF_TRACE_LEVEL log_level, char *to_be_sent, int length) +{ + /* Add the current time stamp */ + char *ptr; + char tbuf[50]; + int tlen; + int total_log_len; + unsigned int *pfilled_length; + bool wake_up_thread = false; + unsigned long flags; + uint64_t ts; + + if (!cds_is_multicast_logging()) { + /* + * This is to make sure that we print the logs to kmsg console + * when no logger app is running. This is also needed to + * log the initial messages during loading of driver where even + * if app is running it will not be able to + * register with driver immediately and start logging all the + * messages. + */ + pr_info("%s\n", to_be_sent); + return 0; + } + + ts = cdf_get_log_timestamp(); + tlen = wlan_add_user_log_time_stamp(tbuf, sizeof(tbuf), ts); + + /* 1+1 indicate '\n'+'\0' */ + total_log_len = length + tlen + 1 + 1; + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + /* wlan logging svc resources are not yet initialized */ + if (!gwlan_logging.pcur_node) { + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + return -EIO; + } + + pfilled_length = &gwlan_logging.pcur_node->filled_length; + + /* Check if we can accomodate more log into current node/buffer */ + if ((MAX_LOGMSG_LENGTH <= (*pfilled_length + + sizeof(tAniNlHdr))) || + ((MAX_LOGMSG_LENGTH - (*pfilled_length + + sizeof(tAniNlHdr))) < total_log_len)) { + wake_up_thread = true; + wlan_queue_logmsg_for_app(); + pfilled_length = &gwlan_logging.pcur_node->filled_length; + } + + ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)]; + + /* Assumption here is that we receive logs which is always less than + * MAX_LOGMSG_LENGTH, where we can accomodate the + * tAniNlHdr + [context][timestamp] + log + * CDF_ASSERT if we cannot accomodate the the complete log into + * the available buffer. + * + * Continue and copy logs to the available length and discard the rest. + */ + if (MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len)) { + CDF_ASSERT(0); + total_log_len = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - 2; + } + + memcpy(&ptr[*pfilled_length], tbuf, tlen); + memcpy(&ptr[*pfilled_length + tlen], to_be_sent, + min(length, (total_log_len - tlen))); + *pfilled_length += tlen + min(length, total_log_len - tlen); + ptr[*pfilled_length] = '\n'; + *pfilled_length += 1; + + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + + /* Wakeup logger thread */ + if ((true == wake_up_thread)) { + set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + + if (gwlan_logging.log_fe_to_console + && ((CDF_TRACE_LEVEL_FATAL == log_level) + || (CDF_TRACE_LEVEL_ERROR == log_level))) { + pr_info("%s\n", to_be_sent); + } + + return 0; +} + +static int send_filled_buffers_to_user(void) +{ + int ret = -1; + struct log_msg *plog_msg; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + static int nlmsg_seq; + unsigned long flags; + static int rate_limit; + + while (!list_empty(&gwlan_logging.filled_list) + && !gwlan_logging.exit) { + + skb = dev_alloc_skb(MAX_LOGMSG_LENGTH); + if (skb == NULL) { + if (!rate_limit) { + pr_err + ("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n", + __func__, MAX_LOGMSG_LENGTH, + gwlan_logging.drop_count); + } + rate_limit = 1; + ret = -ENOMEM; + break; + } + rate_limit = 0; + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + + plog_msg = (struct log_msg *) + (gwlan_logging.filled_list.next); + list_del_init(gwlan_logging.filled_list.next); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + /* 4 extra bytes for the radio idx */ + payload_len = plog_msg->filled_length + + sizeof(wnl->radio) + sizeof(tAniHdr); + + tot_msg_len = NLMSG_SPACE(payload_len); + nlh = nlmsg_put(skb, 0, nlmsg_seq++, + ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST); + if (NULL == nlh) { + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + list_add_tail(&plog_msg->node, + &gwlan_logging.free_list); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + pr_err("%s: drop_count = %u\n", __func__, + ++gwlan_logging.drop_count); + pr_err("%s: nlmsg_put() failed for msg size[%d]\n", + __func__, tot_msg_len); + dev_kfree_skb(skb); + skb = NULL; + ret = -EINVAL; + continue; + } + + wnl = (tAniNlHdr *) nlh; + wnl->radio = plog_msg->radio; + memcpy(&wnl->wmsg, plog_msg->logbuf, + plog_msg->filled_length + sizeof(tAniHdr)); + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + list_add_tail(&plog_msg->node, &gwlan_logging.free_list); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + + ret = nl_srv_bcast(skb); + /* print every 64th drop count */ + if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) { + pr_err("%s: Send Failed %d drop_count = %u\n", + __func__, ret, ++gwlan_logging.drop_count); + skb = NULL; + } else { + skb = NULL; + ret = 0; + } + } + + return ret; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wlan_report_log_completion() - Report bug report completion to userspace + * @is_fatal: Type of event, fatal or not + * @indicator: Source of bug report, framework/host/firmware + * @reason_code: Reason for triggering bug report + * + * This function is used to report the bug report completion to userspace + * + * Return: None + */ +void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct host_event_wlan_log_complete); + + wlan_diag_event.is_fatal = is_fatal; + wlan_diag_event.indicator = indicator; + wlan_diag_event.reason_code = reason_code; + wlan_diag_event.reserved = 0; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE); +} +#endif + +/** + * send_flush_completion_to_user() - Indicate flush completion to the user + * + * This function is used to send the flush completion message to user space + * + * Return: None + */ +void send_flush_completion_to_user(void) +{ + uint32_t is_fatal, indicator, reason_code; + + cds_get_log_completion(&is_fatal, &indicator, &reason_code); + + /* Error on purpose, so that it will get logged in the kmsg */ + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: Sending flush done to userspace", __func__); + + wlan_report_log_completion(is_fatal, indicator, reason_code); +} + +/** + * wlan_logging_thread() - The WLAN Logger thread + * @Arg - pointer to the HDD context + * + * This thread logs log message to App registered for the logs. + */ +static int wlan_logging_thread(void *Arg) +{ + int ret_wait_status = 0; + int ret = 0; + + set_user_nice(current, -2); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) + daemonize("wlan_logging_thread"); +#endif + + while (!gwlan_logging.exit) { + ret_wait_status = + wait_event_interruptible(gwlan_logging.wait_queue, + (!list_empty + (&gwlan_logging.filled_list) + || test_bit( + HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag) + || test_bit( + HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag) + || test_bit( + HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag) + || gwlan_logging.exit)); + + if (ret_wait_status == -ERESTARTSYS) { + pr_err + ("%s: wait_event_interruptible returned -ERESTARTSYS", + __func__); + break; + } + + if (gwlan_logging.exit) { + pr_err("%s: Exiting the thread\n", __func__); + break; + } + + if (test_and_clear_bit(HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag)) { + ret = send_filled_buffers_to_user(); + if (-ENOMEM == ret) + msleep(200); + } + + if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag)) { + ret = pktlog_send_per_pkt_stats_to_user(); + if (-ENOMEM == ret) + msleep(200); + } + + if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag)) { + /* Flush bit could have been set while we were mid + * way in the logging thread. So, need to check other + * buffers like log messages, per packet stats again + * to flush any residual data in them + */ + if (gwlan_logging.is_flush_complete == true) { + gwlan_logging.is_flush_complete = false; + send_flush_completion_to_user(); + } else { + gwlan_logging.is_flush_complete = true; + set_bit(HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag); + set_bit(HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag); + set_bit(HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag); + wake_up_interruptible( + &gwlan_logging.wait_queue); + } + } + } + + pr_info("%s: Terminating\n", __func__); + + complete_and_exit(&gwlan_logging.shutdown_comp, 0); + + return 0; +} + +/* + * Process all the Netlink messages from Logger Socket app in user space + */ +static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) +{ + tAniNlHdr *wnl; + int radio; + int type; + int ret; + + wnl = (tAniNlHdr *) skb->data; + radio = wnl->radio; + type = wnl->nlh.nlmsg_type; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: invalid radio id [%d]\n", __func__, radio); + return -EINVAL; + } + + if (gapp_pid != INVALID_PID) { + if (wnl->nlh.nlmsg_pid > gapp_pid) { + gapp_pid = wnl->nlh.nlmsg_pid; + } + + spin_lock_bh(&gwlan_logging.spin_lock); + if (gwlan_logging.pcur_node->filled_length) { + wlan_queue_logmsg_for_app(); + } + spin_unlock_bh(&gwlan_logging.spin_lock); + set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } else { + /* This is to set the default levels (WLAN logging + * default values not the CDF trace default) when + * logger app is registered for the first time. + */ + gapp_pid = wnl->nlh.nlmsg_pid; + } + + ret = wlan_send_sock_msg_to_app(&wnl->wmsg, 0, + ANI_NL_MSG_LOG, wnl->nlh.nlmsg_pid); + if (ret < 0) { + LOGGING_TRACE(CDF_TRACE_LEVEL_ERROR, + "wlan_send_sock_msg_to_app: failed"); + } + + return ret; +} + +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) +{ + int i = 0; + unsigned long irq_flag; + + pr_info("%s: Initalizing FEConsoleLog = %d NumBuff = %d\n", + __func__, log_fe_to_console, num_buf); + + gapp_pid = INVALID_PID; + + gplog_msg = (struct log_msg *)vmalloc(num_buf * sizeof(struct log_msg)); + if (!gplog_msg) { + pr_err("%s: Could not allocate memory\n", __func__); + return -ENOMEM; + } + + cdf_mem_zero(gplog_msg, (num_buf * sizeof(struct log_msg))); + + gwlan_logging.log_fe_to_console = !!log_fe_to_console; + gwlan_logging.num_buf = num_buf; + + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + INIT_LIST_HEAD(&gwlan_logging.free_list); + INIT_LIST_HEAD(&gwlan_logging.filled_list); + + for (i = 0; i < num_buf; i++) { + list_add(&gplog_msg[i].node, &gwlan_logging.free_list); + gplog_msg[i].index = i; + } + gwlan_logging.pcur_node = (struct log_msg *) + (gwlan_logging.free_list.next); + list_del_init(gwlan_logging.free_list.next); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + + init_waitqueue_head(&gwlan_logging.wait_queue); + gwlan_logging.exit = false; + clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + init_completion(&gwlan_logging.shutdown_comp); + gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL, + "wlan_logging_thread"); + if (IS_ERR(gwlan_logging.thread)) { + pr_err("%s: Could not Create LogMsg Thread Controller", + __func__); + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + vfree(gplog_msg); + gplog_msg = NULL; + gwlan_logging.pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + return -ENOMEM; + } + wake_up_process(gwlan_logging.thread); + gwlan_logging.is_active = true; + gwlan_logging.is_flush_complete = false; + + nl_srv_register(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg); + + pr_info("%s: Activated wlan_logging svc\n", __func__); + return 0; +} + +int wlan_logging_sock_deactivate_svc(void) +{ + unsigned long irq_flag; + + if (!gplog_msg) + return 0; + + nl_srv_unregister(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg); + clear_default_logtoapp_log_level(); + gapp_pid = INVALID_PID; + + INIT_COMPLETION(gwlan_logging.shutdown_comp); + gwlan_logging.exit = true; + gwlan_logging.is_active = false; + cds_set_multicast_logging(0); + gwlan_logging.is_flush_complete = false; + clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + wait_for_completion(&gwlan_logging.shutdown_comp); + + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + vfree(gplog_msg); + gplog_msg = NULL; + gwlan_logging.pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + + pr_info("%s: Deactivate wlan_logging svc\n", __func__); + + return 0; +} + +int wlan_logging_sock_init_svc(void) +{ + spin_lock_init(&gwlan_logging.spin_lock); + gapp_pid = INVALID_PID; + gwlan_logging.pcur_node = NULL; + + return 0; +} + +int wlan_logging_sock_deinit_svc(void) +{ + gwlan_logging.pcur_node = NULL; + gapp_pid = INVALID_PID; + + return 0; +} + +/** + * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging + * + * This function is used to send signal to the logger thread for logging per + * packet stats + * + * Return: None + * + */ +void wlan_logging_set_per_pkt_stats(void) +{ + if (gwlan_logging.is_active == false) + return; + + set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); +} + +/** + * wlan_logging_set_log_level() - Set the logging level + * + * This function is used to set the logging level of host debug messages + * + * Return: None + */ +void wlan_logging_set_log_level(void) +{ + set_default_logtoapp_log_level(); +} + +/* + * wlan_logging_set_fw_flush_complete() - FW log flush completion + * + * This function is used to send signal to the logger thread to indicate + * that the flushing of FW logs is complete by the FW + * + * Return: None + * + */ +void wlan_logging_set_fw_flush_complete(void) +{ + if (gwlan_logging.is_active == false) + return; + + set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); +} +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/core/utils/nlink/inc/wlan_nlink_common.h b/core/utils/nlink/inc/wlan_nlink_common.h new file mode 100644 index 0000000000..7dc7646832 --- /dev/null +++ b/core/utils/nlink/inc/wlan_nlink_common.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + \file wlan_nlink_common.h + + Exports and types for the Netlink Service interface. This header file contains + message types and definitions that is shared between the user space service + (e.g. logging service) and WLAN kernel module. + + ===========================================================================*/ + +#ifndef WLAN_NLINK_COMMON_H__ +#define WLAN_NLINK_COMMON_H__ + +#include + +/*--------------------------------------------------------------------------- + * External Functions + *-------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *-------------------------------------------------------------------------*/ +#define WLAN_NL_MAX_PAYLOAD 256 /* maximum size for netlink message */ +#define WLAN_NLINK_PROTO_FAMILY NETLINK_USERSOCK +#define WLAN_NLINK_MCAST_GRP_ID 0x01 + +/*--------------------------------------------------------------------------- + * Type Declarations + *-------------------------------------------------------------------------*/ + +/* + * The following enum defines the target service within WLAN driver for which the + * message is intended for. Each service along with its counterpart + * in the user space, define a set of messages they recognize. + * Each of this message will have an header of type tAniMsgHdr defined below. + * Each Netlink message to/from a kernel module will contain only one + * message which is preceded by a tAniMsgHdr. The maximun size (in bytes) of + * a netlink message is assumed to be MAX_PAYLOAD bytes. + * + * +------------+-------+----------+----------+ + * |Netlink hdr | Align |tAniMsgHdr| msg body | + * +------------+-------+----------|----------+ + */ + +/* Message Types */ +#define WLAN_SVC_FW_CRASHED_IND 0x100 +#define WLAN_SVC_LTE_COEX_IND 0x101 +#define WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND 0x102 +#define WLAN_SVC_DFS_CAC_START_IND 0x103 +#define WLAN_SVC_DFS_CAC_END_IND 0x104 +#define WLAN_SVC_DFS_RADAR_DETECT_IND 0x105 +#define WLAN_SVC_WLAN_STATUS_IND 0x106 +#define WLAN_SVC_WLAN_VERSION_IND 0x107 +#define WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND 0x108 +#define WLAN_SVC_WLAN_TP_IND 0x109 + +#define WLAN_SVC_MAX_SSID_LEN 32 +#define WLAN_SVC_MAX_BSSID_LEN 6 +#define WLAN_SVC_MAX_STR_LEN 16 +#define WLAN_SVC_MAX_NUM_CHAN 128 +#define WLAN_SVC_COUNTRY_CODE_LEN 3 + +#define ANI_NL_MSG_BASE 0x10 /* Some arbitrary base */ + +typedef enum eAniNlModuleTypes { + ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01, /* PTT Socket App */ + ANI_NL_MSG_PTT = ANI_NL_MSG_BASE + 0x07, /* Quarky GUI */ + WLAN_NL_MSG_OEM = ANI_NL_MSG_BASE + 0x09, + WLAN_NL_MSG_SVC, + WLAN_NL_MSG_CNSS_DIAG = ANI_NL_MSG_BASE + 0x0B, /* Value needs to be 27 */ + ANI_NL_MSG_LOG, + ANI_NL_MSG_MAX +} tAniNlModTypes, tWlanNlModTypes; + +#define WLAN_NL_MSG_BASE ANI_NL_MSG_BASE +#define WLAN_NL_MSG_MAX ANI_NL_MSG_MAX + +/* All Netlink messages must contain this header */ +typedef struct sAniHdr { + unsigned short type; + unsigned short length; +} tAniHdr, tAniMsgHdr; + +struct wlan_status_data { + uint8_t lpss_support; + uint8_t is_on; + uint8_t vdev_id; + uint8_t is_connected; + int8_t rssi; + uint8_t ssid_len; + uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN]; + uint32_t vdev_mode; + uint32_t freq; + uint32_t numChannels; + uint8_t channel_list[WLAN_SVC_MAX_NUM_CHAN]; + uint8_t ssid[WLAN_SVC_MAX_SSID_LEN]; + uint8_t bssid[WLAN_SVC_MAX_BSSID_LEN]; +}; + +struct wlan_version_data { + uint32_t chip_id; + char chip_name[WLAN_SVC_MAX_STR_LEN]; + char chip_from[WLAN_SVC_MAX_STR_LEN]; + char host_version[WLAN_SVC_MAX_STR_LEN]; + char fw_version[WLAN_SVC_MAX_STR_LEN]; +}; + +struct wlan_dfs_info { + uint16_t channel; + uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN]; +}; + +#endif /* WLAN_NLINK_COMMON_H__ */ diff --git a/core/utils/nlink/inc/wlan_nlink_srv.h b/core/utils/nlink/inc/wlan_nlink_srv.h new file mode 100644 index 0000000000..a973a7b1bf --- /dev/null +++ b/core/utils/nlink/inc/wlan_nlink_srv.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_nlink_srv.h +* +* wlan_nlink_srv is used to RX/TX Netlink messages from user space to kernel +* modules and vice versa. Kernel modules must register a message handler for a +* message type so that the wlan_nlink_srv can invoke the corresponding msg handler +* whenever a Netlink message of a particular type has been received from an +* application. In the opposite direction, wlan_nlink_srv provides a mechanism +* which kernel modules can use to send Netlink messages to applications. +* +******************************************************************************/ + +#ifndef WLAN_NLINK_SRV_H +#define WLAN_NLINK_SRV_H + +#include +#include +#include + +#define INVALID_PID -1 +#define NLINK_MAX_CALLBACKS (WLAN_NL_MSG_MAX - WLAN_NL_MSG_BASE) + +typedef int (*nl_srv_msg_callback)(struct sk_buff *skb); + +int nl_srv_init(void); +void nl_srv_exit(void); +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler); +int nl_srv_unregister(tWlanNlModTypes msg_type, + nl_srv_msg_callback msg_handler); +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag); +int nl_srv_bcast(struct sk_buff *skb); +int nl_srv_is_initialized(void); +#endif diff --git a/core/utils/nlink/src/wlan_nlink_srv.c b/core/utils/nlink/src/wlan_nlink_srv.c new file mode 100644 index 0000000000..8ed084b878 --- /dev/null +++ b/core/utils/nlink/src/wlan_nlink_srv.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_nlink_srv.c +* +* This file contains the definitions specific to the wlan_nlink_srv +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global variables */ +static DEFINE_MUTEX(nl_srv_sem); +static struct sock *nl_srv_sock; +static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS]; + +/* Forward declaration */ +static void nl_srv_rcv(struct sk_buff *sk); +static void nl_srv_rcv_skb(struct sk_buff *skb); +static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh); + +/* + * Initialize the netlink service. + * Netlink service is usable after this. + */ +int nl_srv_init(void) +{ + int retcode = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = nl_srv_rcv + }; +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_PROTO_FAMILY, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + THIS_MODULE, +#endif + &cfg); +#else + nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_PROTO_FAMILY, + WLAN_NLINK_MCAST_GRP_ID, nl_srv_rcv, + NULL, THIS_MODULE); +#endif + + if (nl_srv_sock != NULL) { + memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler)); + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR, + "NLINK: netlink_kernel_create failed"); + retcode = -ECONNREFUSED; + } + return retcode; +} + +/* + * Deinit the netlink service. + * Netlink service is unusable after this. + */ +void nl_srv_exit(void) +{ + if (nl_srv_is_initialized() == 0) + netlink_kernel_release(nl_srv_sock); + + nl_srv_sock = NULL; +} + +/* + * Register a message handler for a specified module. + * Each module (e.g. WLAN_NL_MSG_BTC )will register a + * handler to handle messages addressed to it. + */ +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int retcode = 0; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler; + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: nl_srv_register failed for msg_type %d", + msg_type); + retcode = -EINVAL; + } + + return retcode; +} + +/* + * Unregister the message handler for a specified module. + */ +int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int retcode = 0; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) { + nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL; + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: nl_srv_unregister failed for msg_type %d", + msg_type); + retcode = -EINVAL; + } + + return retcode; +} + +/* + * Unicast the message to the process in user space identfied + * by the dst-pid + */ +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) +{ + int err; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; /* sender's pid */ +#else + NETLINK_CB(skb).portid = 0; /* sender's pid */ +#endif + NETLINK_CB(skb).dst_group = 0; /* not multicast */ + + err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag); + + if (err < 0) + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: netlink_unicast to pid[%d] failed, ret[0x%X]", + dst_pid, err); + + return err; +} + +/* + * Broadcast the message. Broadcast will return an error if + * there are no listeners + */ +int nl_srv_bcast(struct sk_buff *skb) +{ + int err; + int flags = GFP_KERNEL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; /* sender's pid */ +#else + NETLINK_CB(skb).portid = 0; /* sender's pid */ +#endif + NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */ + + err = + netlink_broadcast(nl_srv_sock, skb, 0, WLAN_NLINK_MCAST_GRP_ID, + flags); + + if (err < 0) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: netlink_broadcast failed err = %d", err); + } + return err; +} + +/* + * Processes the Netlink socket input queue. + * Dequeue skb's from the socket input queue and process + * all the netlink messages in that skb, before moving + * to the next skb. + */ +static void nl_srv_rcv(struct sk_buff *sk) +{ + mutex_lock(&nl_srv_sem); + nl_srv_rcv_skb(sk); + mutex_unlock(&nl_srv_sem); +} + +/* + * Each skb could contain multiple Netlink messages. Process all the + * messages in one skb and discard malformed skb's silently. + */ +static void nl_srv_rcv_skb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + + while (skb->len >= NLMSG_SPACE(0)) { + u32 rlen; + + nlh = (struct nlmsghdr *)skb->data; + + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: Invalid " + "Netlink message: skb[%p], len[%d], nlhdr[%p], nlmsg_len[%d]", + skb, skb->len, nlh, nlh->nlmsg_len); + return; + } + + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; + nl_srv_rcv_msg(skb, nlh); + skb_pull(skb, rlen); + } +} + +/* + * Process a netlink message. + * Each netlink message will have a message of type tAniMsgHdr inside. + */ +static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + int type; + + /* Only requests are handled by kernel now */ + if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: Received Invalid NL Req type [%x]", + nlh->nlmsg_flags); + return; + } + + type = nlh->nlmsg_type; + + /* Unknown message */ + if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: Received Invalid NL Msg type [%x]", type); + return; + } + + /* + * All the messages must at least carry the tAniMsgHdr + * Drop any message with invalid length + */ + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: Received NL Msg with invalid len[%x]", + nlh->nlmsg_len); + return; + } + + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO, + "NLINK: Received NL msg type [%d]", type); + + /* turn type into dispatch table offset */ + type -= WLAN_NL_MSG_BASE; + + /* dispatch to handler */ + if (nl_srv_msg_handler[type] != NULL) { + (nl_srv_msg_handler[type])(skb); + } else { + CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN, + "NLINK: No handler for Netlink Msg [0x%X]", type); + } +} + +/** + * nl_srv_is_initialized() - This function is used check if the netlink + * service is initialized + * + * This function is used check if the netlink service is initialized + * + * Return: Return -EPERM if the service is not initialized + * + */ +int nl_srv_is_initialized() +{ + if (nl_srv_sock) + return 0; + + return -EPERM; +} diff --git a/core/utils/pktlog/include/pktlog.h b/core/utils/pktlog/include/pktlog.h new file mode 100644 index 0000000000..cfbf221847 --- /dev/null +++ b/core/utils/pktlog/include/pktlog.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_ +#define _PKTLOG_ +#ifndef REMOVE_PKT_LOG + +/** + * @typedef ol_pktlog_dev_handle + * @brief opaque handle for pktlog device object + */ +struct ol_pktlog_dev_t; +typedef struct ol_pktlog_dev_t *ol_pktlog_dev_handle; +#endif /* #ifndef REMOVE_PKT_LOG */ +#endif /* _PKTLOG_ */ diff --git a/core/utils/pktlog/include/pktlog_ac.h b/core/utils/pktlog/include/pktlog_ac.h new file mode 100644 index 0000000000..0a5a784fe5 --- /dev/null +++ b/core/utils/pktlog/include/pktlog_ac.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_AC_H_ +#define _PKTLOG_AC_H_ +#ifndef REMOVE_PKT_LOG + +#include "ol_if_athvar.h" +#include +#include +#include "osdep.h" +#include +#include +#include +#include "hif.h" + +#define NO_REG_FUNCS 4 + +/* Locking interface for pktlog */ +#define PKTLOG_LOCK_INIT(_pl_info) spin_lock_init(&(_pl_info)->log_lock) +#define PKTLOG_LOCK_DESTROY(_pl_info) +#define PKTLOG_LOCK(_pl_info) spin_lock(&(_pl_info)->log_lock) +#define PKTLOG_UNLOCK(_pl_info) spin_unlock(&(_pl_info)->log_lock) + +#define PKTLOG_MODE_SYSTEM 1 +#define PKTLOG_MODE_ADAPTER 2 + +/* + * The proc entry starts with magic number and version field which will be + * used by post processing scripts. These fields are not needed by applications + * that do not use these scripts. This is skipped using the offset value. + */ +#define PKTLOG_READ_OFFSET 8 + +/* Opaque softc */ +struct ol_ath_generic_softc_t; +typedef struct ol_ath_generic_softc_t *ol_ath_generic_softc_handle; +extern void pktlog_disable_adapter_logging(struct ol_softc *scn); +extern int pktlog_alloc_buf(struct ol_softc *scn); +extern void pktlog_release_buf(struct ol_softc *scn); + +ssize_t pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos, + struct ath_pktlog_info *pl_info, bool *read_complete); +int pktlog_send_per_pkt_stats_to_user(void); + +struct ol_pl_arch_dep_funcs { + void (*pktlog_init)(struct ol_softc *scn); + int (*pktlog_enable)(struct ol_softc *scn, int32_t log_state); + int (*pktlog_setsize)(struct ol_softc *scn, int32_t log_state); + int (*pktlog_disable)(struct ol_softc *scn); +}; + +struct ol_pl_os_dep_funcs { + int (*pktlog_attach)(struct ol_softc *scn); + void (*pktlog_detach)(struct ol_softc *scn); +}; + +struct ath_pktlog_wmi_params { + WMI_PKTLOG_EVENT pktlog_event; + WMI_CMD_ID cmd_id; +}; + +extern struct ol_pl_arch_dep_funcs ol_pl_funcs; +extern struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs; + +/* Pktlog handler to save the state of the pktlogs */ +struct ol_pktlog_dev_t { + struct ol_pl_arch_dep_funcs *pl_funcs; + struct ath_pktlog_info *pl_info; + ol_ath_generic_softc_handle scn; + char *name; + bool tgt_pktlog_enabled; + osdev_t sc_osdev; +}; + +#define PKTLOG_SYSCTL_SIZE 14 + +/* + * Linux specific pktlog state information + */ +struct ath_pktlog_info_lnx { + struct ath_pktlog_info info; + struct ctl_table sysctls[PKTLOG_SYSCTL_SIZE]; + struct proc_dir_entry *proc_entry; + struct ctl_table_header *sysctl_header; +}; + +#define PL_INFO_LNX(_pl_info) ((struct ath_pktlog_info_lnx *)(_pl_info)) + +extern struct ol_pktlog_dev_t ol_pl_dev; + +/* + * WDI related data and functions + * Callback function to the WDI events + */ +void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data); + +void pktlog_init(struct ol_softc *scn); +int pktlog_enable(struct ol_softc *scn, int32_t log_state); +int pktlog_setsize(struct ol_softc *scn, int32_t log_state); +int pktlog_disable(struct ol_softc *scn); +int pktlogmod_init(void *context); +void pktlogmod_exit(void *context); + +#define ol_pktlog_attach(_scn) \ + do { \ + if (g_ol_pl_os_dep_funcs) { \ + g_ol_pl_os_dep_funcs->pktlog_attach(_scn); \ + } \ + } while (0) + +#define ol_pktlog_detach(_scn) \ + do { \ + if (g_ol_pl_os_dep_funcs) { \ + g_ol_pl_os_dep_funcs->pktlog_detach(_scn); \ + } \ + } while (0) + +#else /* REMOVE_PKT_LOG */ +#define ol_pktlog_attach(_scn) ({ (void)_scn; }) +#define ol_pktlog_detach(_scn) ({ (void)_scn; }) +static inline void pktlog_init(struct ol_softc *scn) +{ + return; +} +static int pktlog_enable(struct ol_softc *scn, int32_t log_state) +{ + return 0; +} +static int pktlog_setsize(struct ol_softc *scn, int32_t log_state) +{ + return 0; +} +static int pktlog_disable(struct ol_softc *scn) +{ + return 0; +} +#endif /* REMOVE_PKT_LOG */ +#endif /* _PKTLOG_AC_H_ */ diff --git a/core/utils/pktlog/include/pktlog_ac_api.h b/core/utils/pktlog/include/pktlog_ac_api.h new file mode 100644 index 0000000000..04b32f70f1 --- /dev/null +++ b/core/utils/pktlog/include/pktlog_ac_api.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * The file is used to define structures that are shared between + * kernel space and user space pktlog application. + */ + +#ifndef _PKTLOG_AC_API_ +#define _PKTLOG_AC_API_ +#ifndef REMOVE_PKT_LOG + +/** + * @typedef ol_pktlog_dev_handle + * @brief opaque handle for pktlog device object + */ +struct ol_pktlog_dev_t; +typedef struct ol_pktlog_dev_t *ol_pktlog_dev_handle; + +/** + * @typedef ol_softc_handle + * @brief opaque handle for ol_softc + */ +struct ol_softc; +typedef struct ol_softc *ol_softc_handle; + +/** + * @typedef net_device_handle + * @brief opaque handle linux phy device object + */ +struct net_device; +typedef struct net_device *net_device_handle; + +void ol_pl_set_name(ol_softc_handle scn, net_device_handle dev); + +void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle, ol_softc_handle scn); + +/* Packet log state information */ +#ifndef _PKTLOG_INFO +#define _PKTLOG_INFO +struct ath_pktlog_info { + struct ath_pktlog_buf *buf; + uint32_t log_state; + uint32_t saved_state; + uint32_t options; + + /* Size of buffer in bytes */ + int32_t buf_size; + spinlock_t log_lock; + + /* Threshold of TCP SACK packets for triggered stop */ + int sack_thr; + + /* # of tail packets to log after triggered stop */ + int tail_length; + + /* throuput threshold in bytes for triggered stop */ + uint32_t thruput_thresh; + + /* (aggregated or single) packet size in bytes */ + uint32_t pktlen; + + /* a temporary variable for counting TX throughput only */ + /* PER threshold for triggered stop, 10 for 10%, range [1, 99] */ + uint32_t per_thresh; + + /* Phyerr threshold for triggered stop */ + uint32_t phyerr_thresh; + + /* time period for counting trigger parameters, in milisecond */ + uint32_t trigger_interval; + uint32_t start_time_thruput; + uint32_t start_time_per; +}; +#endif /* _PKTLOG_INFO */ +#else /* REMOVE_PKT_LOG */ +typedef void *ol_pktlog_dev_handle; +#define ol_pl_sethandle(pl_handle, scn) \ + do { \ + (void)pl_handle; \ + (void)scn; \ + } while (0) + +#define ol_pl_set_name(scn, dev) \ + do { \ + (void)scn; \ + (void)dev; \ + } while (0) + +#endif /* REMOVE_PKT_LOG */ +#endif /* _PKTLOG_AC_API_ */ diff --git a/core/utils/pktlog/include/pktlog_ac_i.h b/core/utils/pktlog/include/pktlog_ac_i.h new file mode 100644 index 0000000000..07bbac07a1 --- /dev/null +++ b/core/utils/pktlog/include/pktlog_ac_i.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_AC_I_ +#define _PKTLOG_AC_I_ +#ifndef REMOVE_PKT_LOG + +#include +#include + +#define PKTLOG_DEFAULT_BUFSIZE (1024 * 1024) +#define PKTLOG_DEFAULT_SACK_THR 3 +#define PKTLOG_DEFAULT_TAIL_LENGTH 100 +#define PKTLOG_DEFAULT_THRUPUT_THRESH (64 * 1024) +#define PKTLOG_DEFAULT_PER_THRESH 30 +#define PKTLOG_DEFAULT_PHYERR_THRESH 300 +#define PKTLOG_DEFAULT_TRIGGER_INTERVAL 500 +struct ath_pktlog_arg { + struct ath_pktlog_info *pl_info; + uint32_t flags; + uint16_t missed_cnt; + uint16_t log_type; + size_t log_size; + uint16_t timestamp; +#ifdef HELIUMPLUS + uint32_t type_specific_data; +#endif + char *buf; +}; + +void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg); +char *pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev, + struct ath_pktlog_info *pl_info, + size_t log_size, struct ath_pktlog_hdr *pl_hdr); + +A_STATUS process_tx_info(struct ol_txrx_pdev_t *pdev, void *data); +A_STATUS process_rx_info(void *pdev, void *data); +A_STATUS process_rx_info_remote(void *pdev, cdf_nbuf_t amsdu); +A_STATUS process_rate_find(void *pdev, void *data); +A_STATUS process_rate_update(void *pdev, void *data); + +#endif /* REMOVE_PKT_LOG */ +#endif diff --git a/core/utils/pktlog/linux_ac.c b/core/utils/pktlog/linux_ac.c new file mode 100644 index 0000000000..3b5dc1b943 --- /dev/null +++ b/core/utils/pktlog/linux_ac.c @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef REMOVE_PKT_LOG +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +/* + * Linux specific implementation of Pktlogs for 802.11ac + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "i_host_diag_core_log.h" +#include "host_diag_core_log.h" +#include "ani_global.h" + +#define PKTLOG_TAG "ATH_PKTLOG" +#define PKTLOG_DEVNAME_SIZE 32 +#define MAX_WLANDEV 1 + +#define PKTLOG_PROC_DIR "ath_pktlog" + +/* Permissions for creating proc entries */ +#define PKTLOG_PROC_PERM 0444 +#define PKTLOG_PROCSYS_DIR_PERM 0555 +#define PKTLOG_PROCSYS_PERM 0644 + +#ifndef __MOD_INC_USE_COUNT +#define PKTLOG_MOD_INC_USE_COUNT \ + if (!try_module_get(THIS_MODULE)) { \ + printk(KERN_WARNING "try_module_get failed\n"); \ + } + +#define PKTLOG_MOD_DEC_USE_COUNT module_put(THIS_MODULE) +#else +#define PKTLOG_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define PKTLOG_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#endif + +static struct ath_pktlog_info *g_pktlog_info; + +static struct proc_dir_entry *g_pktlog_pde; + +static int pktlog_attach(struct ol_softc *sc); +static void pktlog_detach(struct ol_softc *sc); +static int pktlog_open(struct inode *i, struct file *f); +static int pktlog_release(struct inode *i, struct file *f); +static int pktlog_mmap(struct file *f, struct vm_area_struct *vma); +static ssize_t pktlog_read(struct file *file, char *buf, size_t nbytes, + loff_t *ppos); + +static struct file_operations pktlog_fops = { + open: pktlog_open, + release:pktlog_release, + mmap: pktlog_mmap, + read: pktlog_read, +}; + +/* + * Linux implementation of helper functions + */ + +static struct ol_pktlog_dev_t *get_pl_handle(struct ol_softc *scn) +{ + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev_txrx_handle) + return NULL; + return pdev_txrx_handle->pl_dev; +} + +void ol_pl_set_name(ol_softc_handle scn, net_device_handle dev) +{ + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); + if (pdev_txrx_handle && pdev_txrx_handle->pl_dev && dev) + pdev_txrx_handle->pl_dev->name = dev->name; +} + +void pktlog_disable_adapter_logging(struct ol_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev = get_pl_handle(scn); + if (pl_dev) + pl_dev->pl_info->log_state = 0; +} + +int pktlog_alloc_buf(struct ol_softc *scn) +{ + uint32_t page_cnt; + unsigned long vaddr; + struct page *vpg; + struct ath_pktlog_info *pl_info; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); + + if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer " + "scn or scn->pdev_txrx_handle->pl_dev is null\n", + __func__); + return -EINVAL; + } + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + page_cnt = (sizeof(*(pl_info->buf)) + pl_info->buf_size) / PAGE_SIZE; + + if ((pl_info->buf = vmalloc((page_cnt + 2) * PAGE_SIZE)) == NULL) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer " + "(%d pages)\n", __func__, page_cnt); + return -ENOMEM; + } + + pl_info->buf = (struct ath_pktlog_buf *) + (((unsigned long)(pl_info->buf) + PAGE_SIZE - 1) + & PAGE_MASK); + + for (vaddr = (unsigned long)(pl_info->buf); + vaddr < ((unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE)); + vaddr += PAGE_SIZE) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + vpg = vmalloc_to_page((const void *)vaddr); +#else + vpg = virt_to_page(pktlog_virt_to_logical((void *)vaddr)); +#endif + SetPageReserved(vpg); + } + + return 0; +} + +void pktlog_release_buf(struct ol_softc *scn) +{ + unsigned long page_cnt; + unsigned long vaddr; + struct page *vpg; + struct ath_pktlog_info *pl_info; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); + + if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer" + "scn or scn->pdev_txrx_handle->pl_dev is null\n", + __func__); + return; + } + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + page_cnt = ((sizeof(*(pl_info->buf)) + pl_info->buf_size) / + PAGE_SIZE) + 1; + + for (vaddr = (unsigned long)(pl_info->buf); + vaddr < (unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE); + vaddr += PAGE_SIZE) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + vpg = vmalloc_to_page((const void *)vaddr); +#else + vpg = virt_to_page(pktlog_virt_to_logical((void *)vaddr)); +#endif + ClearPageReserved(vpg); + } + + vfree(pl_info->buf); + pl_info->buf = NULL; +} + +void pktlog_cleanup(struct ath_pktlog_info *pl_info) +{ + pl_info->log_state = 0; + PKTLOG_LOCK_DESTROY(pl_info); +} + +/* sysctl procfs handler to enable pktlog */ +static int +ath_sysctl_decl(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ppos) +{ + int ret, enable; + ol_ath_generic_softc_handle scn; + struct ol_pktlog_dev_t *pl_dev; + + scn = (ol_ath_generic_softc_handle) ctl->extra1; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct ol_softc *)scn); + + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return -ENODEV; + } + + ctl->data = &enable; + ctl->maxlen = sizeof(enable); + + if (write) { + ret = ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret == 0) + ret = pl_dev->pl_funcs->pktlog_enable((struct ol_softc + *)scn, enable); + else + printk(PKTLOG_TAG "%s:proc_dointvec failed\n", + __func__); + } else { + ret = ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret) + printk(PKTLOG_TAG "%s:proc_dointvec failed\n", + __func__); + } + + ctl->data = NULL; + ctl->maxlen = 0; + + return ret; +} + +static int get_pktlog_bufsize(struct ol_pktlog_dev_t *pl_dev) +{ + return pl_dev->pl_info->buf_size; +} + +/* sysctl procfs handler to set/get pktlog size */ +static int +ath_sysctl_decl(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ppos) +{ + int ret, size; + ol_ath_generic_softc_handle scn; + struct ol_pktlog_dev_t *pl_dev; + + scn = (ol_ath_generic_softc_handle) ctl->extra1; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct ol_softc *)scn); + + if (!pl_dev) { + printk("%s: Invalid pktlog handle\n", __func__); + ASSERT(0); + return -ENODEV; + } + + ctl->data = &size; + ctl->maxlen = sizeof(size); + + if (write) { + ret = ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret == 0) + ret = pl_dev->pl_funcs->pktlog_setsize((struct ol_softc + *)scn, size); + } else { + size = get_pktlog_bufsize(pl_dev); + ret = ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + } + + ctl->data = NULL; + ctl->maxlen = 0; + + return ret; +} + +/* Register sysctl table */ +static int pktlog_sysctl_register(struct ol_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev = get_pl_handle(scn); + struct ath_pktlog_info_lnx *pl_info_lnx; + char *proc_name; + + if (pl_dev) { + pl_info_lnx = PL_INFO_LNX(pl_dev->pl_info); + proc_name = pl_dev->name; + } else { + pl_info_lnx = PL_INFO_LNX(g_pktlog_info); + proc_name = PKTLOG_PROC_SYSTEM; + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) +#define set_ctl_name(a, b) /* nothing */ +#else +#define set_ctl_name(a, b) pl_info_lnx->sysctls[a].ctl_name = b +#endif + + /* + * Setup the sysctl table for creating the following sysctl entries: + * /proc/sys/PKTLOG_PROC_DIR//enable for enabling/disabling + * pktlog + * /proc/sys/PKTLOG_PROC_DIR//size for changing the buffer size + */ + memset(pl_info_lnx->sysctls, 0, sizeof(pl_info_lnx->sysctls)); + set_ctl_name(0, CTL_AUTO); + pl_info_lnx->sysctls[0].procname = PKTLOG_PROC_DIR; + pl_info_lnx->sysctls[0].mode = PKTLOG_PROCSYS_DIR_PERM; + pl_info_lnx->sysctls[0].child = &pl_info_lnx->sysctls[2]; + /* [1] is NULL terminator */ + set_ctl_name(2, CTL_AUTO); + pl_info_lnx->sysctls[2].procname = proc_name; + pl_info_lnx->sysctls[2].mode = PKTLOG_PROCSYS_DIR_PERM; + pl_info_lnx->sysctls[2].child = &pl_info_lnx->sysctls[4]; + /* [3] is NULL terminator */ + set_ctl_name(4, CTL_AUTO); + pl_info_lnx->sysctls[4].procname = "enable"; + pl_info_lnx->sysctls[4].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[4].proc_handler = ath_sysctl_pktlog_enable; + pl_info_lnx->sysctls[4].extra1 = scn; + + set_ctl_name(5, CTL_AUTO); + pl_info_lnx->sysctls[5].procname = "size"; + pl_info_lnx->sysctls[5].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[5].proc_handler = ath_sysctl_pktlog_size; + pl_info_lnx->sysctls[5].extra1 = scn; + + set_ctl_name(6, CTL_AUTO); + pl_info_lnx->sysctls[6].procname = "options"; + pl_info_lnx->sysctls[6].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[6].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[6].data = &pl_info_lnx->info.options; + pl_info_lnx->sysctls[6].maxlen = sizeof(pl_info_lnx->info.options); + + set_ctl_name(7, CTL_AUTO); + pl_info_lnx->sysctls[7].procname = "sack_thr"; + pl_info_lnx->sysctls[7].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[7].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[7].data = &pl_info_lnx->info.sack_thr; + pl_info_lnx->sysctls[7].maxlen = sizeof(pl_info_lnx->info.sack_thr); + + set_ctl_name(8, CTL_AUTO); + pl_info_lnx->sysctls[8].procname = "tail_length"; + pl_info_lnx->sysctls[8].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[8].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[8].data = &pl_info_lnx->info.tail_length; + pl_info_lnx->sysctls[8].maxlen = sizeof(pl_info_lnx->info.tail_length); + + set_ctl_name(9, CTL_AUTO); + pl_info_lnx->sysctls[9].procname = "thruput_thresh"; + pl_info_lnx->sysctls[9].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[9].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[9].data = &pl_info_lnx->info.thruput_thresh; + pl_info_lnx->sysctls[9].maxlen = + sizeof(pl_info_lnx->info.thruput_thresh); + + set_ctl_name(10, CTL_AUTO); + pl_info_lnx->sysctls[10].procname = "phyerr_thresh"; + pl_info_lnx->sysctls[10].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[10].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[10].data = &pl_info_lnx->info.phyerr_thresh; + pl_info_lnx->sysctls[10].maxlen = + sizeof(pl_info_lnx->info.phyerr_thresh); + + set_ctl_name(11, CTL_AUTO); + pl_info_lnx->sysctls[11].procname = "per_thresh"; + pl_info_lnx->sysctls[11].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[11].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[11].data = &pl_info_lnx->info.per_thresh; + pl_info_lnx->sysctls[11].maxlen = sizeof(pl_info_lnx->info.per_thresh); + + set_ctl_name(12, CTL_AUTO); + pl_info_lnx->sysctls[12].procname = "trigger_interval"; + pl_info_lnx->sysctls[12].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[12].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[12].data = &pl_info_lnx->info.trigger_interval; + pl_info_lnx->sysctls[12].maxlen = + sizeof(pl_info_lnx->info.trigger_interval); + /* [13] is NULL terminator */ + + /* and register everything */ + /* register_sysctl_table changed from 2.6.21 onwards */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)) + pl_info_lnx->sysctl_header = + register_sysctl_table(pl_info_lnx->sysctls); +#else + pl_info_lnx->sysctl_header = + register_sysctl_table(pl_info_lnx->sysctls, 1); +#endif + if (!pl_info_lnx->sysctl_header) { + printk("%s: failed to register sysctls!\n", proc_name); + return -1; + } + + return 0; +} + +/* + * Initialize logging for system or adapter + * Parameter scn should be NULL for system wide logging + */ +static int pktlog_attach(struct ol_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info_lnx *pl_info_lnx; + char *proc_name; + struct proc_dir_entry *proc_entry; + + pl_dev = get_pl_handle(scn); + + if (pl_dev != NULL) { + pl_info_lnx = kmalloc(sizeof(*pl_info_lnx), GFP_KERNEL); + if (pl_info_lnx == NULL) { + printk(PKTLOG_TAG "%s:allocation failed for pl_info\n", + __func__); + return -ENOMEM; + } + pl_dev->pl_info = &pl_info_lnx->info; + pl_dev->name = WLANDEV_BASENAME; + proc_name = pl_dev->name; + if (!pl_dev->pl_funcs) + pl_dev->pl_funcs = &ol_pl_funcs; + + /* + * Valid for both direct attach and offload architecture + */ + pl_dev->pl_funcs->pktlog_init(scn); + } else { + return -1; + } + + /* + * initialize log info + * might be good to move to pktlog_init + */ + /* pl_dev->tgt_pktlog_enabled = false; */ + pl_info_lnx->proc_entry = NULL; + pl_info_lnx->sysctl_header = NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + proc_entry = proc_create_data(proc_name, PKTLOG_PROC_PERM, + g_pktlog_pde, &pktlog_fops, + &pl_info_lnx->info); + + if (proc_entry == NULL) { + printk(PKTLOG_TAG "%s: create_proc_entry failed for %s\n", + __func__, proc_name); + goto attach_fail1; + } +#else + proc_entry = create_proc_entry(proc_name, PKTLOG_PROC_PERM, + g_pktlog_pde); + + if (proc_entry == NULL) { + printk(PKTLOG_TAG "%s: create_proc_entry failed for %s\n", + __func__, proc_name); + goto attach_fail1; + } + + proc_entry->data = &pl_info_lnx->info; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + proc_entry->owner = THIS_MODULE; +#endif + proc_entry->proc_fops = &pktlog_fops; +#endif + + pl_info_lnx->proc_entry = proc_entry; + + if (pktlog_sysctl_register(scn)) { + printk(PKTLOG_TAG "%s: sysctl register failed for %s\n", + __func__, proc_name); + goto attach_fail2; + } + return 0; + +attach_fail2: + remove_proc_entry(proc_name, g_pktlog_pde); + +attach_fail1: + if (pl_dev) + kfree(pl_dev->pl_info); + return -1; +} + +static void pktlog_sysctl_unregister(struct ol_pktlog_dev_t *pl_dev) +{ + struct ath_pktlog_info_lnx *pl_info_lnx; + + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return; + } + + pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) : + PL_INFO_LNX(g_pktlog_info); + + if (pl_info_lnx->sysctl_header) { + unregister_sysctl_table(pl_info_lnx->sysctl_header); + pl_info_lnx->sysctl_header = NULL; + } +} + +static void pktlog_detach(struct ol_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev = (struct ol_pktlog_dev_t *) + get_pl_handle(scn); + struct ath_pktlog_info *pl_info; + + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return; + } + + pl_info = pl_dev->pl_info; + remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde); + pktlog_sysctl_unregister(pl_dev); + pktlog_cleanup(pl_info); + + if (pl_info->buf) + pktlog_release_buf(scn); + + if (pl_dev) { + kfree(pl_info); + pl_dev->pl_info = NULL; + } +} + +static int pktlog_open(struct inode *i, struct file *f) +{ + PKTLOG_MOD_INC_USE_COUNT; + return 0; +} + +static int pktlog_release(struct inode *i, struct file *f) +{ + PKTLOG_MOD_DEC_USE_COUNT; + return 0; +} + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/** + * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per + * packet statistics to the user + * + * This function is used to send the per packet statistics to the user + * + * Return: Success if the message is posted to user + * + */ +int pktlog_send_per_pkt_stats_to_user(void) +{ + ssize_t ret_val; + struct host_log_pktlog_info *pktlog = NULL; + ol_txrx_pdev_handle txrx_pdev = + cds_get_context(CDF_MODULE_ID_TXRX); + struct ath_pktlog_info *pl_info; + bool read_complete; + uint32_t num_bytes_read = 0; + + /* + * We do not want to do this packet stats related processing when + * packet log tool is run. i.e., we want this processing to be + * done only when start logging command of packet stats is initiated. + */ + if ((cds_get_ring_log_level(RING_ID_PER_PACKET_STATS) < + WLAN_LOG_LEVEL_ACTIVE)) { + printk(PKTLOG_TAG " %s: Shouldnt happen. Logging not started\n", + __func__); + return -EINVAL; + } + + if (!txrx_pdev) { + printk(PKTLOG_TAG " %s: Invalid TxRx handle\n", __func__); + return -EINVAL; + } + + pl_info = txrx_pdev->pl_dev->pl_info; + + if (!pl_info || !pl_info->buf) { + printk(PKTLOG_TAG " %s: Shouldnt happen. pl_info is invalid\n", + __func__); + return -EINVAL; + } + + if (pl_info->buf->rd_offset == -1) { + printk(PKTLOG_TAG " %s: Shouldnt happen. No write yet!\n", + __func__); + return -EINVAL; + } + + do { + pktlog = (struct host_log_pktlog_info *) + cdf_mem_malloc(sizeof(struct host_log_pktlog_info) + + VOS_LOG_PKT_LOG_SIZE); + if (!pktlog) { + printk(PKTLOG_TAG " %s: Memory allocation failed\n", + __func__); + return -ENOMEM; + } + + cdf_mem_zero(pktlog, VOS_LOG_PKT_LOG_SIZE); + host_diag_log_set_code(pktlog, LOG_WLAN_PKT_LOG_INFO_C); + + pktlog->buf_len = 0; + pktlog->version = VERSION_LOG_WLAN_PKT_LOG_INFO_C; + + /* + * @ret_val: ret_val gives the actual data read from the buffer. + * When there is no more data to read, this value will be zero + * @offset: offset in the ring buffer. Initially it is zero and + * is incremented during every read based on number of bytes + * read + */ + ret_val = pktlog_read_proc_entry(pktlog->buf, + VOS_LOG_PKT_LOG_SIZE, + &pl_info->buf->offset, + pl_info, &read_complete); + if (ret_val) { + int index = 0; + struct ath_pktlog_hdr *temp; + while (1) { + if ((ret_val - index) < + sizeof(struct ath_pktlog_hdr)) { + /* Partial header */ + pl_info->buf->offset -= + (ret_val - index); + ret_val = index; + break; + } + temp = (struct ath_pktlog_hdr *) + (pktlog->buf + index); + if ((ret_val - index) < (temp->size + + sizeof(struct ath_pktlog_hdr))) { + /* Partial record payload */ + pl_info->buf->offset -= + (ret_val - index); + ret_val = index; + break; + } + index += temp->size + + sizeof(struct ath_pktlog_hdr); + } + } + + /* Data will include message index/seq number and buf length */ + pktlog->buf_len = ret_val; + if (ret_val) { + host_diag_log_set_length(pktlog, ret_val + + sizeof(struct host_log_pktlog_info)); + pktlog->seq_no = pl_info->buf->msg_index++; + WLAN_HOST_DIAG_LOG_REPORT(pktlog); + } else { + cdf_mem_free(pktlog); + } + num_bytes_read += ret_val; + + /* + * If the logger thread is scheduled late and the proc entry + * is having too much data to be read, we might start to starve + * the other threads if we continuously keep reading the proc + * entry. So, having a threshold to break this read from proc + * entry. + */ + if (num_bytes_read > HOST_LOG_PKT_LOG_THRESHOLD) { + read_complete = true; + printk(PKTLOG_TAG " %s: Break read to prevent starve\n", + __func__); + } + } while (read_complete == false); + + return 0; +} + +/** + * pktlog_read_proc_entry() - This function is used to read data from the + * proc entry into the readers buffer + * @buf: Readers buffer + * @nbytes: Number of bytes to read + * @ppos: Offset within the drivers buffer + * @pl_info: Packet log information pointer + * @read_complete: Boolean value indication whether read is complete + * + * This function is used to read data from the proc entry into the readers + * buffer. Its functionality is similar to 'pktlog_read' which does + * copy to user to the user space buffer + * + * Return: Number of bytes read from the buffer + * + */ + ssize_t +pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos, + struct ath_pktlog_info *pl_info, bool *read_complete) +{ + size_t bufhdr_size; + size_t count = 0, ret_val = 0; + int rem_len; + int start_offset, end_offset; + int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset; + struct ath_pktlog_buf *log_buf = pl_info->buf; + *read_complete = false; + + if (log_buf == NULL) { + *read_complete = true; + return 0; + } + + if (*ppos == 0 && pl_info->log_state) { + pl_info->saved_state = pl_info->log_state; + pl_info->log_state = 0; + } + + bufhdr_size = sizeof(log_buf->bufhdr); + + /* copy valid log entries from circular buffer into user space */ + rem_len = nbytes; + count = 0; + + if (*ppos < bufhdr_size) { + count = MIN((bufhdr_size - *ppos), rem_len); + cdf_mem_copy(buf, ((char *)&log_buf->bufhdr) + *ppos, + count); + rem_len -= count; + ret_val += count; + } + + start_offset = log_buf->rd_offset; + cur_wr_offset = log_buf->wr_offset; + + if ((rem_len == 0) || (start_offset < 0)) + goto rd_done; + + fold_offset = -1; + cur_rd_offset = start_offset; + + /* Find the last offset and fold-offset if the buffer is folded */ + do { + struct ath_pktlog_hdr *log_hdr; + int log_data_offset; + + log_hdr = (struct ath_pktlog_hdr *) (log_buf->log_data + + cur_rd_offset); + + log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr); + + if ((fold_offset == -1) + && ((pl_info->buf_size - log_data_offset) + <= log_hdr->size)) + fold_offset = log_data_offset - 1; + + PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size); + + if ((fold_offset == -1) && (cur_rd_offset == 0) + && (cur_rd_offset != cur_wr_offset)) + fold_offset = log_data_offset + log_hdr->size - 1; + + end_offset = log_data_offset + log_hdr->size - 1; + } while (cur_rd_offset != cur_wr_offset); + + ppos_data = *ppos + ret_val - bufhdr_size + start_offset; + + if (fold_offset == -1) { + if (ppos_data > end_offset) + goto rd_done; + + count = MIN(rem_len, (end_offset - ppos_data + 1)); + cdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } else { + if (ppos_data <= fold_offset) { + count = MIN(rem_len, (fold_offset - ppos_data + 1)); + cdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } + + if (rem_len == 0) + goto rd_done; + + ppos_data = + *ppos + ret_val - (bufhdr_size + + (fold_offset - start_offset + 1)); + + if (ppos_data <= end_offset) { + count = MIN(rem_len, (end_offset - ppos_data + 1)); + cdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } + } + +rd_done: + if ((ret_val < nbytes) && pl_info->saved_state) { + pl_info->log_state = pl_info->saved_state; + pl_info->saved_state = 0; + } + *ppos += ret_val; + + if (ret_val == 0) { + PKTLOG_LOCK(pl_info); + /* Write pointer might have been updated during the read. + * So, if some data is written into, lets not reset the pointers + * We can continue to read from the offset position + */ + if (cur_wr_offset != log_buf->wr_offset) { + *read_complete = false; + } else { + pl_info->buf->rd_offset = -1; + pl_info->buf->wr_offset = 0; + pl_info->buf->bytes_written = 0; + pl_info->buf->offset = PKTLOG_READ_OFFSET; + *read_complete = true; + } + PKTLOG_UNLOCK(pl_info); + } + + return ret_val; +} + +static ssize_t +pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + size_t bufhdr_size; + size_t count = 0, ret_val = 0; + int rem_len; + int start_offset, end_offset; + int fold_offset, ppos_data, cur_rd_offset; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + struct ath_pktlog_info *pl_info = (struct ath_pktlog_info *) + PDE_DATA(file->f_dentry->d_inode); +#else + struct proc_dir_entry *proc_entry = PDE(file->f_dentry->d_inode); + struct ath_pktlog_info *pl_info = (struct ath_pktlog_info *) + proc_entry->data; +#endif + struct ath_pktlog_buf *log_buf = pl_info->buf; + + if (log_buf == NULL) + return 0; + + if (*ppos == 0 && pl_info->log_state) { + pl_info->saved_state = pl_info->log_state; + pl_info->log_state = 0; + } + + bufhdr_size = sizeof(log_buf->bufhdr); + + /* copy valid log entries from circular buffer into user space */ + rem_len = nbytes; + count = 0; + + if (*ppos < bufhdr_size) { + count = CDF_MIN((bufhdr_size - *ppos), rem_len); + if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos, + count)) + return -EFAULT; + rem_len -= count; + ret_val += count; + } + + start_offset = log_buf->rd_offset; + + if ((rem_len == 0) || (start_offset < 0)) + goto rd_done; + + fold_offset = -1; + cur_rd_offset = start_offset; + + /* Find the last offset and fold-offset if the buffer is folded */ + do { + struct ath_pktlog_hdr *log_hdr; + int log_data_offset; + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + + cur_rd_offset); + + log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr); + + if ((fold_offset == -1) + && ((pl_info->buf_size - log_data_offset) + <= log_hdr->size)) + fold_offset = log_data_offset - 1; + + PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size); + + if ((fold_offset == -1) && (cur_rd_offset == 0) + && (cur_rd_offset != log_buf->wr_offset)) + fold_offset = log_data_offset + log_hdr->size - 1; + + end_offset = log_data_offset + log_hdr->size - 1; + } while (cur_rd_offset != log_buf->wr_offset); + + ppos_data = *ppos + ret_val - bufhdr_size + start_offset; + + if (fold_offset == -1) { + if (ppos_data > end_offset) + goto rd_done; + + count = CDF_MIN(rem_len, (end_offset - ppos_data + 1)); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + } else { + if (ppos_data <= fold_offset) { + count = CDF_MIN(rem_len, (fold_offset - ppos_data + 1)); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + } + + if (rem_len == 0) + goto rd_done; + + ppos_data = + *ppos + ret_val - (bufhdr_size + + (fold_offset - start_offset + 1)); + + if (ppos_data <= end_offset) { + count = CDF_MIN(rem_len, (end_offset - ppos_data + 1)); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + } + } + +rd_done: + if ((ret_val < nbytes) && pl_info->saved_state) { + pl_info->log_state = pl_info->saved_state; + pl_info->saved_state = 0; + } + *ppos += ret_val; + + return ret_val; +} + +#ifndef VMALLOC_VMADDR +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) +/* Convert a kernel virtual address to a kernel logical address */ +static volatile void *pktlog_virt_to_logical(volatile void *addr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) || \ + (defined(__i386__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11))) + pud_t *pud; +#endif + unsigned long vaddr, ret = 0UL; + + vaddr = VMALLOC_VMADDR((unsigned long)addr); + + pgd = pgd_offset_k(vaddr); + + if (!pgd_none(*pgd)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) || \ + (defined(__i386__) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11))) + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); +#else + pmd = pmd_offset(pgd, vaddr); +#endif + + if (!pmd_none(*pmd)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + ptep = pte_offset_map(pmd, vaddr); +#else + ptep = pte_offset(pmd, vaddr); +#endif + pte = *ptep; + + if (pte_present(pte)) { + ret = (unsigned long) + page_address(pte_page(pte)); + ret |= (vaddr & (PAGE_SIZE - 1)); + } + } + } + return (volatile void *)ret; +} +#endif + +/* vma operations for mapping vmalloced area to user space */ +static void pktlog_vopen(struct vm_area_struct *vma) +{ + PKTLOG_MOD_INC_USE_COUNT; +} + +static void pktlog_vclose(struct vm_area_struct *vma) +{ + PKTLOG_MOD_DEC_USE_COUNT; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) +int pktlog_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned long address = (unsigned long)vmf->virtual_address; + + if (address == 0UL) + return VM_FAULT_NOPAGE; + + if (vmf->pgoff > vma->vm_end) + return VM_FAULT_SIGBUS; + + get_page(virt_to_page((void *)address)); + vmf->page = virt_to_page((void *)address); + return VM_FAULT_MINOR; +} +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) +struct page *pktlog_vmmap(struct vm_area_struct *vma, unsigned long addr, + int *type) +#else +struct page *pktlog_vmmap(struct vm_area_struct *vma, unsigned long addr, + int write_access) +#endif +{ + unsigned long offset, vaddr; + struct proc_dir_entry *proc_entry; + struct ath_pktlog_info *pl_info = + proc_entry = PDE(vma->vm_file->f_dentry->d_inode); + pl_info = (struct ath_pktlog_info *)proc_entry->data; + + offset = addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); + vaddr = (unsigned long)pktlog_virt_to_logical((void *)(pl_info->buf) + + offset); + + if (vaddr == 0UL) { + printk(PKTLOG_TAG "%s: page fault out of range\n", __func__); + return ((struct page *)0UL); + } + + /* increment the usage count of the page */ + get_page(virt_to_page((void *)vaddr)); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + if (type) + *type = VM_FAULT_MINOR; +#endif + + return virt_to_page((void *)vaddr); +} +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) */ + +static struct vm_operations_struct pktlog_vmops = { + open: pktlog_vopen, + close:pktlog_vclose, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) + fault:pktlog_fault, +#else + nopage:pktlog_vmmap, +#endif +}; + +static int pktlog_mmap(struct file *file, struct vm_area_struct *vma) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + struct ath_pktlog_info *pl_info = (struct ath_pktlog_info *) + PDE_DATA(file->f_dentry->d_inode); +#else + struct proc_dir_entry *proc_entry = PDE(file->f_dentry->d_inode); + struct ath_pktlog_info *pl_info = (struct ath_pktlog_info *) + proc_entry->data; +#endif + + if (vma->vm_pgoff != 0) { + /* Entire buffer should be mapped */ + return -EINVAL; + } + + if (!pl_info->buf) { + printk(PKTLOG_TAG "%s: Log buffer unavailable\n", __func__); + return -ENOMEM; + } + + vma->vm_flags |= VM_LOCKED; + vma->vm_ops = &pktlog_vmops; + pktlog_vopen(vma); + return 0; +} + +int pktlogmod_init(void *context) +{ + int ret; + + /* create the proc directory entry */ + g_pktlog_pde = proc_mkdir(PKTLOG_PROC_DIR, NULL); + + if (g_pktlog_pde == NULL) { + printk(PKTLOG_TAG "%s: proc_mkdir failed\n", __func__); + return -1; + } + + /* Attach packet log */ + if ((ret = pktlog_attach((struct ol_softc *)context))) + goto attach_fail; + + return ret; + +attach_fail: + remove_proc_entry(PKTLOG_PROC_DIR, NULL); + g_pktlog_pde = NULL; + return ret; +} + +void pktlogmod_exit(void *context) +{ + struct ol_softc *scn = (struct ol_softc *)context; + struct ol_pktlog_dev_t *pl_dev; + + if (!scn) + return; + + pl_dev = get_pl_handle(scn); + + if (!pl_dev || g_pktlog_pde == NULL) + return; + /* + * Disable firmware side pktlog function + */ + if (pl_dev->tgt_pktlog_enabled) { + if (pl_dev->pl_funcs->pktlog_enable(scn, 0)) { + printk("%s: cannot disable pktlog in the target\n", + __func__); + } + } + pktlog_detach(scn); + /* + * pdev kill needs to be implemented + */ + remove_proc_entry(PKTLOG_PROC_DIR, NULL); +} +#endif diff --git a/core/utils/pktlog/pktlog_ac.c b/core/utils/pktlog/pktlog_ac.c new file mode 100644 index 0000000000..7bc10efb88 --- /dev/null +++ b/core/utils/pktlog/pktlog_ac.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * 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. + */ + +#ifndef REMOVE_PKT_LOG +#include "cdf_memory.h" +#include "athdefs.h" +#include "pktlog_ac_i.h" +#include "cds_api.h" +#include "wma_types.h" + +wdi_event_subscribe PKTLOG_TX_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RX_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RX_REMOTE_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RCFIND_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RCUPDATE_SUBSCRIBER; + +struct ol_pl_arch_dep_funcs ol_pl_funcs = { + .pktlog_init = pktlog_init, + .pktlog_enable = pktlog_enable, + .pktlog_setsize = pktlog_setsize, + .pktlog_disable = pktlog_disable, /* valid for f/w disable */ +}; + +struct ol_pktlog_dev_t ol_pl_dev = { + .pl_funcs = &ol_pl_funcs, +}; + +void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle, struct ol_softc *scn) +{ + ol_pl_dev.scn = (ol_ath_generic_softc_handle) scn; + *pl_handle = &ol_pl_dev; +} + +static A_STATUS pktlog_wma_post_msg(WMI_PKTLOG_EVENT event_types, + WMI_CMD_ID cmd_id) +{ + cds_msg_t msg = { 0 }; + CDF_STATUS status; + struct ath_pktlog_wmi_params *param; + + param = cdf_mem_malloc(sizeof(struct ath_pktlog_wmi_params)); + + if (!param) + return A_NO_MEMORY; + + param->cmd_id = cmd_id; + param->pktlog_event = event_types; + + msg.type = WMA_PKTLOG_ENABLE_REQ; + msg.bodyptr = param; + msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_WMA, &msg); + + if (status != CDF_STATUS_SUCCESS) { + cdf_mem_free(param); + return A_ERROR; + } + + return A_OK; +} + +static inline A_STATUS +pktlog_enable_tgt(struct ol_softc *_scn, uint32_t log_state) +{ + uint32_t types = 0; + + if (log_state & ATH_PKTLOG_TX) + types |= WMI_PKTLOG_EVENT_TX; + + if (log_state & ATH_PKTLOG_RX) + types |= WMI_PKTLOG_EVENT_RX; + + if (log_state & ATH_PKTLOG_RCFIND) + types |= WMI_PKTLOG_EVENT_RCF; + + if (log_state & ATH_PKTLOG_RCUPDATE) + types |= WMI_PKTLOG_EVENT_RCU; + + return pktlog_wma_post_msg(types, WMI_PDEV_PKTLOG_ENABLE_CMDID); +} + +static inline A_STATUS +wdi_pktlog_subscribe(struct ol_txrx_pdev_t *txrx_pdev, int32_t log_state) +{ + if (!txrx_pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (log_state & ATH_PKTLOG_TX) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_TX_SUBSCRIBER, WDI_EVENT_TX_STATUS)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RX) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) { + return A_ERROR; + } + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RX_REMOTE_SUBSCRIBER, + WDI_EVENT_RX_DESC_REMOTE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCFIND) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RCFIND_SUBSCRIBER, + WDI_EVENT_RATE_FIND)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCUPDATE) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RCUPDATE_SUBSCRIBER, + WDI_EVENT_RATE_UPDATE)) { + return A_ERROR; + } + } + return A_OK; +} + +void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data) +{ + switch (event) { + case WDI_EVENT_TX_STATUS: + { + /* + * process TX message + */ + if (process_tx_info(pdev, log_data)) { + printk("Unable to process TX info\n"); + return; + } + break; + } + case WDI_EVENT_RX_DESC: + { + /* + * process RX message for local frames + */ + if (process_rx_info(pdev, log_data)) { + printk("Unable to process RX info\n"); + return; + } + break; + } + case WDI_EVENT_RX_DESC_REMOTE: + { + /* + * process RX message for remote frames + */ + if (process_rx_info_remote(pdev, log_data)) { + printk("Unable to process RX info\n"); + return; + } + break; + } + case WDI_EVENT_RATE_FIND: + { + /* + * process RATE_FIND message + */ + if (process_rate_find(pdev, log_data)) { + printk("Unable to process RC_FIND info\n"); + return; + } + break; + } + case WDI_EVENT_RATE_UPDATE: + { + /* + * process RATE_UPDATE message + */ + if (process_rate_update(pdev, log_data)) { + printk("Unable to process RC_UPDATE\n"); + return; + } + break; + } + default: + break; + } +} + +static inline A_STATUS +wdi_pktlog_unsubscribe(struct ol_txrx_pdev_t *txrx_pdev, uint32_t log_state) +{ + if (log_state & ATH_PKTLOG_TX) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_TX_SUBSCRIBER, + WDI_EVENT_TX_STATUS)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RX) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) { + return A_ERROR; + } + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RX_REMOTE_SUBSCRIBER, + WDI_EVENT_RX_DESC_REMOTE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCFIND) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RCFIND_SUBSCRIBER, + WDI_EVENT_RATE_FIND)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCUPDATE) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RCUPDATE_SUBSCRIBER, + WDI_EVENT_RATE_UPDATE)) { + return A_ERROR; + } + } + return A_OK; +} + +int pktlog_disable(struct ol_softc *scn) +{ + struct ol_txrx_pdev_t *txrx_pdev = + cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + + if (txrx_pdev == NULL || + txrx_pdev->pl_dev == NULL || + txrx_pdev->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = txrx_pdev->pl_dev; + pl_info = pl_dev->pl_info; + + if (pktlog_wma_post_msg(0, WMI_PDEV_PKTLOG_DISABLE_CMDID)) { + printk("Failed to disable pktlog in target\n"); + return -1; + } + + if (wdi_pktlog_unsubscribe(txrx_pdev, pl_info->log_state)) { + printk("Cannot unsubscribe pktlog from the WDI\n"); + return -1; + } + + return 0; +} + +void pktlog_init(struct ol_softc *scn) +{ + struct ath_pktlog_info *pl_info; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(CDF_MODULE_ID_TXRX); + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return; + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + OS_MEMZERO(pl_info, sizeof(*pl_info)); + PKTLOG_LOCK_INIT(pl_info); + + pl_info->buf_size = PKTLOG_DEFAULT_BUFSIZE; + pl_info->buf = NULL; + pl_info->log_state = 0; + pl_info->sack_thr = PKTLOG_DEFAULT_SACK_THR; + pl_info->tail_length = PKTLOG_DEFAULT_TAIL_LENGTH; + pl_info->thruput_thresh = PKTLOG_DEFAULT_THRUPUT_THRESH; + pl_info->per_thresh = PKTLOG_DEFAULT_PER_THRESH; + pl_info->phyerr_thresh = PKTLOG_DEFAULT_PHYERR_THRESH; + pl_info->trigger_interval = PKTLOG_DEFAULT_TRIGGER_INTERVAL; + pl_info->pktlen = 0; + pl_info->start_time_thruput = 0; + pl_info->start_time_per = 0; + + PKTLOG_TX_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RX_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RX_REMOTE_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RCFIND_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RCUPDATE_SUBSCRIBER.callback = pktlog_callback; +} + +int pktlog_enable(struct ol_softc *scn, int32_t log_state) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct ol_txrx_pdev_t *txrx_pdev; + int error; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -1; + } + + txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + printk("%s: Invalid txrx_pdev context\n", __func__); + ASSERT(0); + return -1; + } + + pl_dev = txrx_pdev->pl_dev; + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return -1; + } + + pl_info = pl_dev->pl_info; + pl_dev->sc_osdev = &scn->aps_osdev; + + if (!pl_info) + return 0; + + if (log_state != 0 && !pl_dev->tgt_pktlog_enabled) { + if (pl_info->buf == NULL) { + error = pktlog_alloc_buf(scn); + + if (error != 0) + return error; + + if (!pl_info->buf) { + printk("%s: pktlog buf alloc failed\n", + __func__); + ASSERT(0); + return -1; + } + + } + + pl_info->buf->bufhdr.version = CUR_PKTLOG_VER; + pl_info->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM; + pl_info->buf->wr_offset = 0; + pl_info->buf->rd_offset = -1; + /* These below variables are used by per packet stats*/ + pl_info->buf->bytes_written = 0; + pl_info->buf->msg_index = 1; + pl_info->buf->offset = PKTLOG_READ_OFFSET; + + pl_info->start_time_thruput = os_get_timestamp(); + pl_info->start_time_per = pl_info->start_time_thruput; + + /* WDI subscribe */ + if (wdi_pktlog_subscribe(txrx_pdev, log_state)) { + printk("Unable to subscribe to the WDI %s\n", __func__); + return -1; + } + /* WMI command to enable pktlog on the firmware */ + if (pktlog_enable_tgt(scn, log_state)) { + printk("Device cannot be enabled, %s\n", __func__); + return -1; + } else { + pl_dev->tgt_pktlog_enabled = true; + } + } else if (!log_state && pl_dev->tgt_pktlog_enabled) { + pl_dev->pl_funcs->pktlog_disable(scn); + pl_dev->tgt_pktlog_enabled = false; + if (wdi_pktlog_unsubscribe(txrx_pdev, pl_info->log_state)) { + printk("Cannot unsubscribe pktlog from the WDI\n"); + return -1; + } + } + + pl_info->log_state = log_state; + return 0; +} + +int pktlog_setsize(struct ol_softc *scn, int32_t size) +{ + ol_txrx_pdev_handle pdev_txrx_handle = + cds_get_context(CDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = pdev_txrx_handle->pl_dev; + pl_info = pl_dev->pl_info; + + if (size < 0) + return -EINVAL; + + if (size == pl_info->buf_size) + return 0; + + if (pl_info->log_state) { + printk + ("Logging should be disabled before changing bufer size\n"); + return -EINVAL; + } + + if (pl_info->buf != NULL) + pktlog_release_buf(scn); + + if (size != 0) + pl_info->buf_size = size; + + return 0; +} +#endif /* REMOVE_PKT_LOG */ diff --git a/core/utils/pktlog/pktlog_internal.c b/core/utils/pktlog/pktlog_internal.c new file mode 100644 index 0000000000..23c01b456f --- /dev/null +++ b/core/utils/pktlog/pktlog_internal.c @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * 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. + */ + +#ifndef REMOVE_PKT_LOG +#include "ol_txrx_types.h" +#include "ol_htt_tx_api.h" +#include "ol_tx_desc.h" +#include "cdf_memory.h" +#include "htt.h" +#include "htt_internal.h" +#include "pktlog_ac_i.h" +#include "wma_api.h" +#include "wlan_logging_sock_svc.h" + +#define TX_DESC_ID_LOW_MASK 0xffff +#define TX_DESC_ID_LOW_SHIFT 0 +#define TX_DESC_ID_HIGH_MASK 0xffff0000 +#define TX_DESC_ID_HIGH_SHIFT 16 + +#define PER_PACKET_STATS_THRESHOLD 4096 + +void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg) +{ + struct ath_pktlog_buf *log_buf; + int32_t buf_size; + struct ath_pktlog_hdr *log_hdr; + int32_t cur_wr_offset; + char *log_ptr; + struct ath_pktlog_info *pl_info; + uint16_t log_type; + size_t log_size; + uint32_t flags; + + if (!plarg) { + printk("Invalid parg in %s\n", __func__); + return; + } + + pl_info = plarg->pl_info; + log_type = plarg->log_type; + log_size = plarg->log_size; + log_buf = pl_info->buf; + flags = plarg->flags; + + if (!log_buf) { + printk("Invalid log_buf in %s\n", __func__); + return; + } + buf_size = pl_info->buf_size; + cur_wr_offset = log_buf->wr_offset; + /* Move read offset to the next entry if there is a buffer overlap */ + if (log_buf->rd_offset >= 0) { + if ((cur_wr_offset <= log_buf->rd_offset) + && (cur_wr_offset + sizeof(struct ath_pktlog_hdr)) > + log_buf->rd_offset) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, + buf_size); + } + } else { + log_buf->rd_offset = cur_wr_offset; + } + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + cur_wr_offset); + log_hdr->log_type = log_type; + log_hdr->flags = flags; + log_hdr->size = (uint16_t) log_size; + log_hdr->missed_cnt = plarg->missed_cnt; + log_hdr->timestamp = plarg->timestamp; +#ifdef HELIUMPLUS + log_hdr->type_specific_data = plarg->type_specific_data; +#endif + cur_wr_offset += sizeof(*log_hdr); + + if ((buf_size - cur_wr_offset) < log_size) { + while ((cur_wr_offset <= log_buf->rd_offset) + && (log_buf->rd_offset < buf_size)) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, + buf_size); + } + cur_wr_offset = 0; + } + + while ((cur_wr_offset <= log_buf->rd_offset) + && (cur_wr_offset + log_size) > log_buf->rd_offset) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, buf_size); + } + + log_ptr = &(log_buf->log_data[cur_wr_offset]); + cur_wr_offset += log_hdr->size; + + log_buf->wr_offset = ((buf_size - cur_wr_offset) >= + sizeof(struct ath_pktlog_hdr)) ? cur_wr_offset : + 0; + + plarg->buf = log_ptr; +} + +/** + * pktlog_check_threshold() - This function checks threshold for triggering + * packet stats + * @pl_info: Packet log information pointer + * @log_size: Size of current packet log information + * + * This function internally triggers logging of per packet stats when the + * incoming data crosses threshold limit + * + * Return: None + * + */ +void pktlog_check_threshold(struct ath_pktlog_info *pl_info, + size_t log_size) +{ + PKTLOG_LOCK(pl_info); + pl_info->buf->bytes_written += log_size + sizeof(struct ath_pktlog_hdr); + + if (pl_info->buf->bytes_written >= PER_PACKET_STATS_THRESHOLD) { + wlan_logging_set_per_pkt_stats(); + pl_info->buf->bytes_written = 0; + } + PKTLOG_UNLOCK(pl_info); +} + +char *pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev, + struct ath_pktlog_info *pl_info, + size_t log_size, struct ath_pktlog_hdr *pl_hdr) +{ + struct ath_pktlog_arg plarg = { 0, }; + uint8_t flags = 0; + + plarg.pl_info = pl_info; + plarg.log_type = pl_hdr->log_type; + plarg.log_size = log_size; + plarg.flags = pl_hdr->flags; + plarg.missed_cnt = pl_hdr->missed_cnt; + plarg.timestamp = pl_hdr->timestamp; +#ifdef HELIUMPLUS + plarg.type_specific_data = pl_hdr->type_specific_data; +#endif + if (flags & PHFLAGS_INTERRUPT_CONTEXT) { + /* + * We are already in interupt context, no need to make it + * intsafe. call the function directly. + */ + pktlog_getbuf_intsafe(&plarg); + } else { + PKTLOG_LOCK(pl_info); + pktlog_getbuf_intsafe(&plarg); + PKTLOG_UNLOCK(pl_info); + } + + /* + * We do not want to do this packet stats related processing when + * packet log tool is run. i.e., we want this processing to be + * done only when start logging command of packet stats is initiated. + */ + if (cds_get_ring_log_level(RING_ID_PER_PACKET_STATS) == + WLAN_LOG_LEVEL_ACTIVE) + pktlog_check_threshold(pl_info, log_size); + + return plarg.buf; +} + +static struct txctl_frm_hdr frm_hdr; + +static void process_ieee_hdr(void *data) +{ + uint8_t dir; + struct ieee80211_frame *wh = (struct ieee80211_frame *)(data); + + frm_hdr.framectrl = *(uint16_t *) (wh->i_fc); + frm_hdr.seqctrl = *(uint16_t *) (wh->i_seq); + dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); + + if (dir == IEEE80211_FC1_DIR_TODS) { + frm_hdr.bssid_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + } else if (dir == IEEE80211_FC1_DIR_FROMDS) { + frm_hdr.bssid_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + } else { + frm_hdr.bssid_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + } +} + +A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + /* + * Must include to process different types + * TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR + */ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + uint32_t *pl_tgt_hdr; + + if (!txrx_pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + cdf_assert(txrx_pdev->pl_dev); + cdf_assert(data); + pl_dev = txrx_pdev->pl_dev; + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); +#ifdef HELIUMPLUS + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); +#endif + pl_info = pl_dev->pl_info; + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_FRM_HDR) { + /* Valid only for the TX CTL */ + process_ieee_hdr(data + sizeof(pl_hdr)); + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_VIRT_ADDR) { + A_UINT32 desc_id = (A_UINT32) + *((A_UINT32 *) (data + sizeof(pl_hdr))); + A_UINT32 vdev_id = desc_id; + + /* if the pkt log msg is for the bcn frame the vdev id + * is piggybacked in desc_id and the MSB of the desc ID + * would be set to FF + */ +#define BCN_DESC_ID 0xFF + if ((desc_id >> 24) == BCN_DESC_ID) { + void *data; + A_UINT32 buf_size; + + vdev_id &= 0x00FFFFFF; + data = wma_get_beacon_buffer_by_vdev_id(vdev_id, + &buf_size); + if (data) { + process_ieee_hdr(data); + cdf_mem_free(data); + } + } else { + /* + * TODO: get the hdr content for mgmt frames from + * Tx mgmt desc pool + */ + } + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) { +#if !defined(HELIUMPLUS) + struct ath_pktlog_txctl txctl_log; + size_t log_size = sizeof(txctl_log.priv); + + txctl_log.txdesc_hdr_ctl = (void *)pktlog_getbuf(pl_dev, + pl_info, + log_size, + &pl_hdr); + + if (!txctl_log.txdesc_hdr_ctl) { + printk + ("failed to get buf for txctl_log.txdesc_hdr_ctl\n"); + return A_ERROR; + } + + /* + * frm hdr is currently Valid only for local frames + * Add capability to include the fmr hdr for remote frames + */ + txctl_log.priv.frm_hdr = frm_hdr; + cdf_assert(txctl_log.priv.txdesc_ctl); + cdf_mem_copy((void *)&txctl_log.priv.txdesc_ctl, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + cdf_assert(txctl_log.txdesc_hdr_ctl); + cdf_mem_copy(txctl_log.txdesc_hdr_ctl, &txctl_log.priv, + sizeof(txctl_log.priv)); + /* Add Protocol information and HT specific information */ +#else + size_t log_size = sizeof(frm_hdr) + pl_hdr.size; + void *txdesc_hdr_ctl = (void *) + pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr); + cdf_assert(txdesc_hdr_ctl); + cdf_assert(pl_hdr.size < (370 * sizeof(u_int32_t))); + + cdf_mem_copy(txdesc_hdr_ctl, &frm_hdr, sizeof(frm_hdr)); + cdf_mem_copy((char *)txdesc_hdr_ctl + sizeof(frm_hdr), + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); +#endif /* !defined(HELIUMPLUS) */ + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) { + struct ath_pktlog_tx_status txstat_log; + size_t log_size = pl_hdr.size; + + txstat_log.ds_status = (void *) + pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr); + cdf_assert(txstat_log.ds_status); + cdf_mem_copy(txstat_log.ds_status, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) { + struct ath_pktlog_msdu_info pl_msdu_info; + uint32_t i; + uint32_t *htt_tx_desc; + size_t log_size; + struct ol_tx_desc_t *tx_desc; + uint8_t msdu_id_offset = MSDU_ID_INFO_ID_OFFSET; + uint16_t tx_desc_id; + uint32_t *msdu_id_info = (uint32_t *) + ((void *)data + sizeof(struct ath_pktlog_hdr)); + uint32_t *msdu_id = (uint32_t *) ((char *)msdu_id_info + + msdu_id_offset); + uint8_t *addr, *vap_addr; + uint8_t vdev_id; + cdf_nbuf_t netbuf; + uint32_t len; + + cdf_mem_set(&pl_msdu_info, sizeof(pl_msdu_info), 0); + + pl_msdu_info.num_msdu = *msdu_id_info; + pl_msdu_info.priv_size = sizeof(uint32_t) * + pl_msdu_info.num_msdu + sizeof(uint32_t); + log_size = sizeof(pl_msdu_info.priv); + + for (i = 0; i < pl_msdu_info.num_msdu; i++) { + /* + * Handle big endianess + * Increment msdu_id once after retrieving + * lower 16 bits and uppper 16 bits + */ + if (!(i % 2)) { + tx_desc_id = ((*msdu_id & TX_DESC_ID_LOW_MASK) + >> TX_DESC_ID_LOW_SHIFT); + } else { + tx_desc_id = ((*msdu_id & TX_DESC_ID_HIGH_MASK) + >> TX_DESC_ID_HIGH_SHIFT); + msdu_id += 1; + } + tx_desc = ol_tx_desc_find(txrx_pdev, tx_desc_id); + cdf_assert(tx_desc); + netbuf = tx_desc->netbuf; + htt_tx_desc = (uint32_t *) tx_desc->htt_tx_desc; + cdf_assert(htt_tx_desc); + + cdf_nbuf_peek_header(netbuf, &addr, &len); + + if (len < (2 * IEEE80211_ADDR_LEN)) { + cdf_print("TX frame does not have a valid" + " address\n"); + return -1; + } + /* Adding header information for the TX data frames */ + vdev_id = (uint8_t) (*(htt_tx_desc + + HTT_TX_VDEV_ID_WORD) >> + HTT_TX_VDEV_ID_SHIFT) & + HTT_TX_VDEV_ID_MASK; + + vap_addr = wma_get_vdev_address_by_vdev_id(vdev_id); + + frm_hdr.da_tail = (addr[IEEE80211_ADDR_LEN - 2] << 8) | + (addr[IEEE80211_ADDR_LEN - 1]); + frm_hdr.sa_tail = + (addr[2 * IEEE80211_ADDR_LEN - 2] << 8) | + (addr[2 * IEEE80211_ADDR_LEN - 1]); + if (vap_addr) { + frm_hdr.bssid_tail = + (vap_addr[IEEE80211_ADDR_LEN - 2] << 8) | + (vap_addr[IEEE80211_ADDR_LEN - 1]); + } else { + frm_hdr.bssid_tail = 0x0000; + } + pl_msdu_info.priv.msdu_len[i] = *(htt_tx_desc + + HTT_TX_MSDU_LEN_DWORD) + & HTT_TX_MSDU_LEN_MASK; + /* + * Add more information per MSDU + * e.g., protocol information + */ + } + pl_msdu_info.ath_msdu_info = pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + cdf_mem_copy((void *)&pl_msdu_info.priv.msdu_id_info, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + sizeof(pl_msdu_info.priv.msdu_id_info)); + cdf_mem_copy(pl_msdu_info.ath_msdu_info, &pl_msdu_info.priv, + sizeof(pl_msdu_info.priv)); + } + return A_OK; +} + +A_STATUS process_rx_info_remote(void *pdev, cdf_nbuf_t amsdu) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct htt_host_rx_desc_base *rx_desc; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_rx_info rxstat_log; + size_t log_size; + cdf_nbuf_t msdu; + + if (!pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!amsdu) { + printk("Invalid data in %s\n", __func__); + return A_ERROR; + } + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + msdu = amsdu; + + while (msdu) { + rx_desc = + (struct htt_host_rx_desc_base *)(cdf_nbuf_data(msdu)) - 1; + log_size = + sizeof(*rx_desc) - sizeof(struct htt_host_fw_desc_base); + + /* + * Construct the pktlog header pl_hdr + * Because desc is DMA'd to the host memory + */ + pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S); + pl_hdr.missed_cnt = 0; + pl_hdr.log_type = PKTLOG_TYPE_RX_STAT; + pl_hdr.size = sizeof(*rx_desc) - + sizeof(struct htt_host_fw_desc_base); +#if defined(HELIUMPLUS) + pl_hdr.timestamp = + rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32; + pl_hdr.type_specific_data = 0xDEADAA; +#else + pl_hdr.timestamp = rx_desc->ppdu_end.tsf_timestamp; +#endif /* !defined(HELIUMPLUS) */ + rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + cdf_mem_copy(rxstat_log.rx_desc, (void *)rx_desc + + sizeof(struct htt_host_fw_desc_base), pl_hdr.size); + msdu = cdf_nbuf_next(msdu); + } + return A_OK; +} + +A_STATUS process_rx_info(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_rx_info rxstat_log; + struct ath_pktlog_hdr pl_hdr; + size_t log_size; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + printk("Invalid pdev in %s", __func__); + return A_ERROR; + } + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + pl_tgt_hdr = (uint32_t *) data; + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + log_size = pl_hdr.size; + rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + + cdf_mem_copy(rxstat_log.rx_desc, + (void *)data + sizeof(struct ath_pktlog_hdr), pl_hdr.size); + + return A_OK; +} + +A_STATUS process_rate_find(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + size_t log_size; + + /* + * Will be uncommented when the rate control find + * for pktlog is implemented in the firmware. + * Currently derived from the TX PPDU status + */ + struct ath_pktlog_rc_find rcf_log; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + cdf_print("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!data) { + cdf_print("Invalid data in %s\n", __func__); + return A_ERROR; + } + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + log_size = pl_hdr.size; + rcf_log.rcFind = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + + cdf_mem_copy(rcf_log.rcFind, + ((char *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + + return A_OK; +} + +A_STATUS process_rate_update(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + size_t log_size; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_rc_update rcu_log; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!data) { + printk("Invalid data in %s\n", __func__); + return A_ERROR; + } + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + log_size = pl_hdr.size; + pl_info = pl_dev->pl_info; + + /* + * Will be uncommented when the rate control update + * for pktlog is implemented in the firmware. + * Currently derived from the TX PPDU status + */ + rcu_log.txRateCtrl = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + cdf_mem_copy(rcu_log.txRateCtrl, + ((char *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + return A_OK; +} +#endif /*REMOVE_PKT_LOG */ diff --git a/core/utils/ptt/inc/wlan_ptt_sock_svc.h b/core/utils/ptt/inc/wlan_ptt_sock_svc.h new file mode 100644 index 0000000000..7e17dd8329 --- /dev/null +++ b/core/utils/ptt/inc/wlan_ptt_sock_svc.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_ptt_sock_svc.c +* +******************************************************************************/ +#ifndef PTT_SOCK_SVC_H +#define PTT_SOCK_SVC_H +#include +#include +#include +#include +#include +/* + * Quarky Message Format: + * The following is the messaging protocol between Quarky and PTT Socket App. + * The totalMsgLen is the length from Radio till msgBody. The value of Radio + * is always defaulted to 0. The MsgLen is the length from msgId till msgBody. + * The length of the msgBody varies with respect to the MsgId. Buffer space + * for MsgBody is already allocated in the received buffer. So in case of READ + * we just need to populate the values in the received message and send it + * back + * +------------+-------+-------+--------+-------+---------+ + * |TotalMsgLen | Radio | MsgId | MsgLen |Status |MsgBody | + * +------------+-------+-------|--------+-------+---------+ + * <------4----><--4---><---2--><---2---><---4--><---------> + */ +/* PTT Socket App Message Ids */ +#define PTT_MSG_READ_REGISTER 0x3040 +#define PTT_MSG_WRITE_REGISTER 0x3041 +#define PTT_MSG_READ_MEMORY 0x3044 +#define PTT_MSG_WRITE_MEMORY 0x3045 +#define PTT_MSG_LOG_DUMP_DBG 0x32A1 +#define PTT_MSG_FTM_CMDS_TYPE 0x4040 +#define ANI_DRIVER_MSG_START 0x0001 +#define ANI_MSG_APP_REG_REQ (ANI_DRIVER_MSG_START + 0) +#define ANI_MSG_APP_REG_RSP (ANI_DRIVER_MSG_START + 1) +#define ANI_MSG_OEM_DATA_REQ (ANI_DRIVER_MSG_START + 2) +#define ANI_MSG_OEM_DATA_RSP (ANI_DRIVER_MSG_START + 3) +#define ANI_MSG_CHANNEL_INFO_REQ (ANI_DRIVER_MSG_START + 4) +#define ANI_MSG_CHANNEL_INFO_RSP (ANI_DRIVER_MSG_START + 5) +#define ANI_MSG_OEM_ERROR (ANI_DRIVER_MSG_START + 6) +#define ANI_MSG_PEER_STATUS_IND (ANI_DRIVER_MSG_START + 7) + +#define ANI_MAX_RADIOS 3 +#define ANI_NL_MSG_OK 0 +#define ANI_NL_MSG_ERROR -1 +#define ANI_NL_MSG_OVERHEAD (NLMSG_SPACE(tAniHdr + 4)) +/* + * Packet Format for READ_REGISTER & WRITE_REGISTER: + * TotalMsgLen : 4 bytes [value=20 bytes] + * Radio : 4 bytes + * MsgId : 2 bytes + * MsgLen : 2 bytes + * Status : 4 bytes + * Address : 4 bytes + * Payload : 4 bytes + */ +/* + * Packet Format for READ_MEMORY & WRITE_MEMORY : + * TotalMsgLen : 4 bytes [value= 20+LEN_PAYLOAD bytes] + * Radio : 4 bytes + * MsgId : 2 bytes + * MsgLen : 2 bytes + * Status : 4 bytes + * Address : 4 bytes + * Length : 4 bytes [LEN_PAYLOAD] + * Payload : LEN_PAYLOAD bytes + */ +int ptt_sock_activate_svc(void); +void ptt_sock_deactivate_svc(void); +int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid); + +/* + * Format of message exchanged between the PTT Socket App in userspace and the + * WLAN Driver, in either direction. Each msg will begin with this header and + * will followed by the Quarky message + */ +typedef struct sAniNlMsg { + struct nlmsghdr nlh; /* Netlink Header */ + int radio; /* unit number of the radio */ + tAniHdr wmsg; /* Airgo Message Header */ +} tAniNlHdr; +typedef struct sAniAppRegReq { + tAniNlModTypes type; /* module id */ + int pid; /* process id */ +} tAniNlAppRegReq; +typedef struct sAniNlAppRegRsp { + tAniHdr wniHdr; /* Generic WNI msg header */ + tAniNlAppRegReq regReq; /* The original request msg */ + int ret; /* Return code */ +} tAniNlAppRegRsp; +#endif diff --git a/core/utils/ptt/src/wlan_ptt_sock_svc.c b/core/utils/ptt/src/wlan_ptt_sock_svc.c new file mode 100644 index 0000000000..b9a9c12c33 --- /dev/null +++ b/core/utils/ptt/src/wlan_ptt_sock_svc.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_ptt_sock_svc.c +* +******************************************************************************/ +#ifdef PTT_SOCK_SVC_ENABLE +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTT_SOCK_DEBUG +#ifdef PTT_SOCK_DEBUG +#define PTT_TRACE(level, args ...) CDF_TRACE(CDF_MODULE_ID_CDF, level, ## args) +#else +#define PTT_TRACE(level, args ...) +#endif + +/** ptt Process ID */ +static int32_t ptt_pid = INVALID_PID; + +#ifdef PTT_SOCK_DEBUG_VERBOSE +/* Utility function to perform a hex dump */ +static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt) +{ + int i; + for (i = 0; i < cnt; i++) { + if ((i % 16) == 0) + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, + "\n%p:", pbuf); + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, " %02X", + *pbuf); + pbuf++; + } + CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_INFO, "\n"); +} +#endif + +/** + * ptt_sock_send_msg_to_app() - Send nl message to user space + * wmsg: Message header + * radio: Unit number of the radio + * src_mod: Message type + * pid: Process ID to which message will be unicast. Message + * will be broadcast when PID is INVALID_PID + * + * Utility function to send a netlink message to an application in user space + * + * Return: 0 on success and negative value on failure + */ +int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid) +{ + int err = -1; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl; + struct sk_buff *skb; + struct nlmsghdr *nlh; + int wmsg_length = be16_to_cpu(wmsg->length); + static int nlmsg_seq; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n", + __func__, radio); + return -EINVAL; + } + payload_len = wmsg_length + 4; /* 4 extra bytes for the radio idx */ + tot_msg_len = NLMSG_SPACE(payload_len); + if ((skb = dev_alloc_skb(tot_msg_len)) == NULL) { + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: dev_alloc_skb() failed for msg size[%d]\n", + __func__, tot_msg_len); + return -ENOMEM; + } + nlh = + nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len, + NLM_F_REQUEST); + if (NULL == nlh) { + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]\n", __func__, + tot_msg_len); + kfree_skb(skb); + return -ENOMEM; + } + wnl = (tAniNlHdr *) nlh; + wnl->radio = radio; + memcpy(&wnl->wmsg, wmsg, wmsg_length); + PTT_TRACE(CDF_TRACE_LEVEL_INFO, + "%s: Sending Msg Type [0x%X] to pid[%d]\n", __func__, + be16_to_cpu(wmsg->type), pid); +#ifdef PTT_SOCK_DEBUG_VERBOSE + ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len); +#endif + + if (pid != INVALID_PID) + err = nl_srv_ucast(skb, pid, MSG_DONTWAIT); + else + err = nl_srv_bcast(skb); + + return err; +} + +/* + * Process tregisteration request and send registration response messages + * to the PTT Socket App in user space + */ +static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio) +{ + tAniNlAppRegReq *reg_req; + tAniNlAppRegRsp rspmsg; + reg_req = (tAniNlAppRegReq *) (wmsg + 1); + memset((char *)&rspmsg, 0, sizeof(rspmsg)); + /* send reg response message to the application */ + rspmsg.ret = ANI_NL_MSG_OK; + rspmsg.regReq.type = reg_req->type; + /*Save the pid */ + ptt_pid = reg_req->pid; + rspmsg.regReq.pid = reg_req->pid; + rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP); + rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg)); + if (ptt_sock_send_msg_to_app((tAniHdr *) &rspmsg.wniHdr, radio, + ANI_NL_MSG_PUMAC, ptt_pid) < 0) { + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: Error sending ANI_MSG_APP_REG_RSP to pid[%d]\n", + __func__, ptt_pid); + } +} + +/* + * Process all the messages from the PTT Socket App in user space + */ +static void ptt_proc_pumac_msg(struct sk_buff *skb, tAniHdr *wmsg, int radio) +{ + u16 ani_msg_type = be16_to_cpu(wmsg->type); + switch (ani_msg_type) { + case ANI_MSG_APP_REG_REQ: + PTT_TRACE(CDF_TRACE_LEVEL_INFO, + "%s: Received ANI_MSG_APP_REG_REQ [0x%X]\n", __func__, + ani_msg_type); + ptt_sock_proc_reg_req(wmsg, radio); + break; + default: + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, + "%s: Received Unknown Msg Type[0x%X]\n", __func__, + ani_msg_type); + break; + } +} + +/* + * Process all the Netlink messages from PTT Socket app in user space + */ +static int ptt_sock_rx_nlink_msg(struct sk_buff *skb) +{ + tAniNlHdr *wnl; + int radio; + int type; + wnl = (tAniNlHdr *) skb->data; + radio = wnl->radio; + type = wnl->nlh.nlmsg_type; + switch (type) { + case ANI_NL_MSG_PUMAC: /* Message from the PTT socket APP */ + PTT_TRACE(CDF_TRACE_LEVEL_INFO, + "%s: Received ANI_NL_MSG_PUMAC Msg [0x%X]\n", + __func__, type); + ptt_proc_pumac_msg(skb, &wnl->wmsg, radio); + break; + default: + PTT_TRACE(CDF_TRACE_LEVEL_ERROR, "%s: Unknown NL Msg [0x%X]\n", + __func__, type); + break; + } + return 0; +} + +/** + * ptt_sock_activate_svc() - activate PTT service + * + * Return: 0 + */ +int ptt_sock_activate_svc(void) +{ + ptt_pid = INVALID_PID; + nl_srv_register(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg); + nl_srv_register(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg); + return 0; +} + +/** + * ptt_sock_deactivate_svc() - deactivate PTT service + * + * Return: Void + */ +void ptt_sock_deactivate_svc(void) +{ + ptt_pid = INVALID_PID; +} + +#endif /* PTT_SOCK_SVC_ENABLE */ diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h new file mode 100644 index 0000000000..9eec65bdad --- /dev/null +++ b/core/wma/inc/wma.h @@ -0,0 +1,1981 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_H +#define WMA_H + +#include "a_types.h" +#include "cdf_types.h" +#include "osapi_linux.h" +#include "htc_packet.h" +#include "i_cdf_event.h" +#include "wmi_services.h" +#include "wmi_unified.h" +#include "wmi_version.h" +#include "cdf_types.h" +#include "cfg_api.h" +#include "cdf_status.h" +#include "cds_sched.h" +#include "ol_txrx_api.h" +#include "sir_mac_prot_def.h" +#include "wma_types.h" +#include "ol_txrx_types.h" +#include +#include "utils_api.h" +#include "lim_types.h" +#include "wmi_unified_api.h" + +/* Platform specific configuration for max. no. of fragments */ +#define QCA_OL_11AC_TX_MAX_FRAGS 2 + +/* Private */ + +#ifndef QCA_WIFI_3_0_EMU + +#define WMA_READY_EVENTID_TIMEOUT 2000 +#define WMA_TGT_SUSPEND_COMPLETE_TIMEOUT 6000 +#define WMA_WAKE_LOCK_TIMEOUT 1000 +#define WMA_MAX_RESUME_RETRY 1000 +#define WMA_RESUME_TIMEOUT 6000 +#define MAX_MEM_CHUNKS 32 + +#else + +#define WMA_READY_EVENTID_TIMEOUT 200000 +#define WMA_TGT_SUSPEND_COMPLETE_TIMEOUT 300000 +#define WMA_WAKE_LOCK_TIMEOUT 1000 +#define WMA_MAX_RESUME_RETRY 1000 +#define WMA_RESUME_TIMEOUT 300000 +#define MAX_MEM_CHUNKS 32 + +#endif + +#define WMA_CRASH_INJECT_TIMEOUT 5000 + +/* In prima 12 HW stations are supported including BCAST STA(staId 0) + * and SELF STA(staId 1) so total ASSOC stations which can connect to Prima + * SoftAP = 12 - 1(Self STa) - 1(Bcast Sta) = 10 Stations. + */ + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define WMA_MAX_SUPPORTED_STAS 38 +#else +#define WMA_MAX_SUPPORTED_STAS 12 +#endif +#define WMA_MAX_SUPPORTED_BSS 5 + +#define FRAGMENT_SIZE 3072 + +#define WMA_INVALID_VDEV_ID 0xFF +#define MAX_MEM_CHUNKS 32 +#define WMA_MAX_VDEV_SIZE 20 +#define WMA_VDEV_TBL_ENTRY_ADD 1 +#define WMA_VDEV_TBL_ENTRY_DEL 0 + +/* 11A/G channel boundary */ +#define WMA_11A_CHANNEL_BEGIN 34 +#define WMA_11A_CHANNEL_END 165 +#define WMA_11G_CHANNEL_BEGIN 1 +#define WMA_11G_CHANNEL_END 14 + +#define WMA_11P_CHANNEL_BEGIN (170) +#define WMA_11P_CHANNEL_END (184) + +#define WMA_LOGD(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_DEBUG, ## args) +#define WMA_LOGI(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO, ## args) +#define WMA_LOGW(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_WARN, ## args) +#define WMA_LOGE(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, ## args) +#define WMA_LOGP(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_FATAL, ## args) + +#define WMA_DEBUG_ALWAYS + +#ifdef WMA_DEBUG_ALWAYS +#define WMA_LOGA(args ...) \ + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_FATAL, ## args) +#else +#define WMA_LOGA(args ...) +#endif + +#define ALIGNED_WORD_SIZE 4 +#define WLAN_HAL_MSG_TYPE_MAX_ENUM_SIZE 0x7FFF + +/* Prefix used by scan req ids generated on the host */ +#define WMA_HOST_SCAN_REQID_PREFIX 0xA000 +/* Prefix used by roam scan req ids generated on the host */ +#define WMA_HOST_ROAM_SCAN_REQID_PREFIX 0xA800 +/* Prefix used by scan requestor id on host */ +#define WMA_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000 + +#define WMA_HW_DEF_SCAN_MAX_DURATION 30000 /* 30 secs */ + +/* Max offchannel duration */ +#define WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS (3) +#define WMA_SCAN_NPROBES_DEFAULT (2) +#define WMA_SCAN_IDLE_TIME_DEFAULT (25) +#define WMA_P2P_SCAN_MAX_BURST_DURATION (180) +#define WMA_CTS_DURATION_MS_MAX (32) +#define WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION (40) +#define WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION (120) +#define WMA_DWELL_TIME_PASSIVE_DEFAULT (110) +#define WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE (11) +#define WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION (25) + +#define WMA_SEC_TO_USEC (1000000) + +#define BEACON_TX_BUFFER_SIZE (512) + +/* WMA_ETHER_TYPE_OFFSET = sa(6) + da(6) */ +#define WMA_ETHER_TYPE_OFFSET (6 + 6) +/* WMA_ICMP_V6_HEADER_OFFSET = sa(6) + da(6) + eth_type(2) + icmp_v6_hdr(6)*/ +#define WMA_ICMP_V6_HEADER_OFFSET (6 + 6 + 2 + 6) +/* WMA_ICMP_V6_TYPE_OFFSET = sa(6) + da(6) + eth_type(2) + 40 */ +#define WMA_ICMP_V6_TYPE_OFFSET (6 + 6 + 2 + 40) +#define WMA_ICMP_V6_HEADER_TYPE (0x3A) +#define WMA_ICMP_V6_RA_TYPE (0x86) +#define WMA_ICMP_V6_NS_TYPE (0x87) +#define WMA_ICMP_V6_NA_TYPE (0x88) +#define WMA_BCAST_MAC_ADDR (0xFF) +#define WMA_MCAST_IPV4_MAC_ADDR (0x01) +#define WMA_MCAST_IPV6_MAC_ADDR (0x33) + + +/* Roaming default values + * All time and period values are in milliseconds. + * All rssi values are in dB except for WMA_NOISE_FLOOR_DBM_DEFAULT. + */ + +#define WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME (4) +#define WMA_NOISE_FLOOR_DBM_DEFAULT (-96) +#define WMA_ROAM_RSSI_DIFF_DEFAULT (5) +#define WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT (100) +#define WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT (110) +#define WMA_ROAM_MIN_REST_TIME_DEFAULT (50) +#define WMA_ROAM_MAX_REST_TIME_DEFAULT (500) +#define WMA_ROAM_LOW_RSSI_TRIGGER_DEFAULT (20) +#define WMA_ROAM_LOW_RSSI_TRIGGER_VERYLOW (10) +#define WMA_ROAM_BEACON_WEIGHT_DEFAULT (14) +#define WMA_ROAM_OPP_SCAN_PERIOD_DEFAULT (120000) +#define WMA_ROAM_OPP_SCAN_AGING_PERIOD_DEFAULT (WMA_ROAM_OPP_SCAN_PERIOD_DEFAULT * 5) +#define WMA_ROAM_PREAUTH_SCAN_TIME (50) +#define WMA_ROAM_PREAUTH_REST_TIME (0) +#define WMA_ROAM_PREAUTH_MAX_SCAN_TIME (10000) +#define WMA_ROAM_BMISS_FIRST_BCNT_DEFAULT (10) +#define WMA_ROAM_BMISS_FINAL_BCNT_DEFAULT (10) +#define WMA_ROAM_BMISS_FIRST_BCNT_DEFAULT_P2P (15) +#define WMA_ROAM_BMISS_FINAL_BCNT_DEFAULT_P2P (45) + +#define WMA_INVALID_KEY_IDX 0xff +#define WMA_DFS_RADAR_FOUND 1 + +#define WMA_MAX_RF_CHAINS(x) ((1 << x) - 1) +#define WMA_MIN_RF_CHAINS (1) + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_MAX_EXTSCAN_MSG_SIZE 1536 +#define WMA_EXTSCAN_REST_TIME 100 +#define WMA_EXTSCAN_MAX_SCAN_TIME 50000 +#define WMA_EXTSCAN_BURST_DURATION 150 +#endif + +#define WMA_BCN_BUF_MAX_SIZE 2500 +#define WMA_NOA_IE_SIZE(num_desc) (2 + (13 * (num_desc))) +#define WMA_MAX_NOA_DESCRIPTORS 4 + +#define WMA_TIM_SUPPORTED_PVB_LENGTH ((HAL_NUM_STA / 8) + 1) + +#define WMA_WOW_PTRN_MASK_VALID 0xFF +#define WMA_NUM_BITS_IN_BYTE 8 + +#define WMA_AP_WOW_DEFAULT_PTRN_MAX 4 +#define WMA_STA_WOW_DEFAULT_PTRN_MAX 4 + +#define WMA_BSS_STATUS_STARTED 0x1 +#define WMA_BSS_STATUS_STOPPED 0x2 + +#define WMA_FW_PHY_STATS 0x1 +#define WMA_FW_RX_REORDER_STATS 0x2 +#define WMA_FW_RX_RC_STATS 0x3 +#define WMA_FW_TX_PPDU_STATS 0x4 +#define WMA_FW_TX_CONCISE_STATS 0x5 +#define WMA_FW_TX_RC_STATS 0x6 +#define WMA_FW_TXBF_INFO_STATS 0x07 +#define WMA_FW_SND_INFO_STATS 0x08 +#define WMA_FW_ERROR_INFO_STATS 0x09 +#define WMA_FW_TX_SELFGEN_INFO_STATS 0xa +#define WMA_FW_RX_REM_RING_BUF 0xc +#define WMA_FW_RX_TXBF_MUSU_NDPA 0xf + +#define WMA_TARGET_REQ_TYPE_VDEV_START 0x1 +#define WMA_TARGET_REQ_TYPE_VDEV_STOP 0x2 +#define WMA_TARGET_REQ_TYPE_VDEV_DEL 0x3 + +#define WMA_PEER_ASSOC_CNF_START 0x01 +#define WMA_PEER_ASSOC_TIMEOUT (3000) /* 3 seconds */ + +#define WMA_VDEV_START_REQUEST_TIMEOUT (3000) /* 3 seconds */ +#define WMA_VDEV_STOP_REQUEST_TIMEOUT (3000) /* 3 seconds */ + +#define WMA_TGT_INVALID_SNR (-1) + +#define WMA_TX_Q_RECHECK_TIMER_WAIT 2 /* 2 ms */ +#define WMA_TX_Q_RECHECK_TIMER_MAX_WAIT 20 /* 20 ms */ +#define WMA_MAX_NUM_ARGS 8 + +#define WMA_SMPS_MASK_LOWER_16BITS 0xFF +#define WMA_SMPS_MASK_UPPER_3BITS 0x7 +#define WMA_SMPS_PARAM_VALUE_S 29 + +#define WMA_MAX_SCAN_ID 0x00FF + +/* + * Setting the Tx Comp Timeout to 1 secs. + * TODO: Need to Revist the Timing + */ +#define WMA_TX_FRAME_COMPLETE_TIMEOUT 1000 +#define WMA_TX_FRAME_BUFFER_NO_FREE 0 +#define WMA_TX_FRAME_BUFFER_FREE 1 + + +/* Default InActivity Time is 200 ms */ +#define POWERSAVE_DEFAULT_INACTIVITY_TIME 200 + +/* Default Listen Interval */ +#define POWERSAVE_DEFAULT_LISTEN_INTERVAL 1 + +/* + * TODO: Add WMI_CMD_ID_MAX as part of WMI_CMD_ID + * instead of assigning it to the last valid wmi + * cmd+1 to avoid updating this when a command is + * added/deleted. + */ +#define WMI_CMDID_MAX (WMI_TXBF_CMDID + 1) + +#define WMA_NLO_FREQ_THRESH 1000 /* in MHz */ +#define WMA_SEC_TO_MSEC(sec) (sec * 1000) /* sec to msec */ +#define WMA_MSEC_TO_USEC(msec) (msec * 1000) /* msec to usec */ + +/* Default rssi threshold defined in CFG80211 */ +#define WMA_RSSI_THOLD_DEFAULT -300 + +#ifdef FEATURE_WLAN_SCAN_PNO +#define WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT (5 * 1000) /* in msec */ +#define WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT (2 * 1000) /* in msec */ +#endif +#define WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT (5 * 1000) /* in msec */ +#define WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#define WMA_DEAUTH_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#define WMA_DISASSOC_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#endif +#define WMA_BMISS_EVENT_WAKE_LOCK_DURATION (4 * 1000) /* in msec */ + +#define WMA_TXMIC_LEN 8 +#define WMA_RXMIC_LEN 8 + +/* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + +#define WMA_P2P_NOA_IE_OPP_PS_SET (0x80) +#define WMA_P2P_NOA_IE_CTWIN_MASK (0x7F) + +#define WMA_P2P_IE_ID 0xdd +#define WMA_P2P_WFA_OUI { 0x50, 0x6f, 0x9a } +#define WMA_P2P_WFA_VER 0x09 /* ver 1.0 */ +#define WMA_WSC_OUI { 0x00, 0x50, 0xF2 } /* Microsoft WSC OUI byte */ + +/* P2P Sub element defintions (according to table 5 of Wifi's P2P spec) */ +#define WMA_P2P_SUB_ELEMENT_STATUS 0 +#define WMA_P2P_SUB_ELEMENT_MINOR_REASON 1 +#define WMA_P2P_SUB_ELEMENT_CAPABILITY 2 +#define WMA_P2P_SUB_ELEMENT_DEVICE_ID 3 +#define WMA_P2P_SUB_ELEMENT_GO_INTENT 4 +#define WMA_P2P_SUB_ELEMENT_CONFIGURATION_TIMEOUT 5 +#define WMA_P2P_SUB_ELEMENT_LISTEN_CHANNEL 6 +#define WMA_P2P_SUB_ELEMENT_GROUP_BSSID 7 +#define WMA_P2P_SUB_ELEMENT_EXTENDED_LISTEN_TIMING 8 +#define WMA_P2P_SUB_ELEMENT_INTENDED_INTERFACE_ADDR 9 +#define WMA_P2P_SUB_ELEMENT_MANAGEABILITY 10 +#define WMA_P2P_SUB_ELEMENT_CHANNEL_LIST 11 +#define WMA_P2P_SUB_ELEMENT_NOA 12 +#define WMA_P2P_SUB_ELEMENT_DEVICE_INFO 13 +#define WMA_P2P_SUB_ELEMENT_GROUP_INFO 14 +#define WMA_P2P_SUB_ELEMENT_GROUP_ID 15 +#define WMA_P2P_SUB_ELEMENT_INTERFACE 16 +#define WMA_P2P_SUB_ELEMENT_OP_CHANNEL 17 +#define WMA_P2P_SUB_ELEMENT_INVITATION_FLAGS 18 +#define WMA_P2P_SUB_ELEMENT_VENDOR 221 + +/* Macros for handling unaligned memory accesses */ +#define P2PIE_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define P2PIE_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + + +#define WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE 1 + +#define WMA_DEFAULT_QPOWER_MAX_PSPOLL_BEFORE_WAKE 1 +#define WMA_DEFAULT_QPOWER_TX_WAKE_THRESHOLD 2 +#define WMA_DEFAULT_SIFS_BURST_DURATION 8160 + +#define WMA_VHT_PPS_PAID_MATCH 1 +#define WMA_VHT_PPS_GID_MATCH 2 +#define WMA_VHT_PPS_DELIM_CRC_FAIL 3 + +#define WMA_DFS_MAX_20M_SUB_CH 8 + +#define WMA_DEFAULT_HW_MODE_INDEX 0xFFFF + +/** + * struct probeTime_dwellTime - probe time, dwell time map + * @dwell_time: dwell time + * @probe_time: repeat probe time + */ +typedef struct probeTime_dwellTime { + uint8_t dwell_time; + uint8_t probe_time; +} t_probeTime_dwellTime; + +static const t_probeTime_dwellTime + probe_time_dwell_time_map[WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE] = { + {28, 0}, /* 0 SSID */ + {28, 20}, /* 1 SSID */ + {28, 20}, /* 2 SSID */ + {28, 20}, /* 3 SSID */ + {28, 20}, /* 4 SSID */ + {28, 20}, /* 5 SSID */ + {28, 20}, /* 6 SSID */ + {28, 11}, /* 7 SSID */ + {28, 11}, /* 8 SSID */ + {28, 11}, /* 9 SSID */ + {28, 8} /* 10 SSID */ +}; + +/** + * enum t_wma_drv_type - wma driver type + * @WMA_DRIVER_TYPE_PRODUCTION: production driver type + * @WMA_DRIVER_TYPE_MFG: manufacture driver type + * @WMA_DRIVER_TYPE_INVALID: invalid driver type + */ +typedef enum { + WMA_DRIVER_TYPE_PRODUCTION = 0, + WMA_DRIVER_TYPE_MFG = 1, + WMA_DRIVER_TYPE_INVALID = 0x7FFFFFFF +} t_wma_drv_type; + +#ifdef FEATURE_WLAN_TDLS +/** + * enum t_wma_tdls_mode: TDLS mode + * @WMA_TDLS_SUPPORT_NOT_ENABLED: tdls is disable + * @WMA_TDLS_SUPPORT_DISABLED: suppress implicit trigger and not respond to peer + * @WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY: suppress implicit trigger, + * but respond to the peer + * @WMA_TDLS_SUPPORT_ENABLED: implicit trigger + */ +typedef enum { + WMA_TDLS_SUPPORT_NOT_ENABLED = 0, + WMA_TDLS_SUPPORT_DISABLED, + WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY, + WMA_TDLS_SUPPORT_ENABLED, +} t_wma_tdls_mode; + +/** + * enum wma_tdls_peer_notification - TDLS events + * @WMA_TDLS_SHOULD_DISCOVER: tdls discovery recommended for peer (always based + * on tx bytes per second > tx_discover threshold + * NB: notification will be re-sent after + * discovery_request_interval_ms + * @WMA_TDLS_SHOULD_TEARDOWN: tdls link tear down recommended for peer + * due to tx bytes per second below + * tx_teardown_threshold + * NB: this notification sent once + * @WMA_TDLS_PEER_DISCONNECTED: tx peer TDLS link tear down complete + */ +enum wma_tdls_peer_notification { + WMA_TDLS_SHOULD_DISCOVER, + WMA_TDLS_SHOULD_TEARDOWN, + WMA_TDLS_PEER_DISCONNECTED, +}; + +/** + * enum wma_tdls_peer_reason - TDLS peer reason + * @WMA_TDLS_TEARDOWN_REASON_TX: tdls teardown recommended due to low transmits + * @WMA_TDLS_TEARDOWN_REASON_RATE: tdls tear down recommended due to + * packet rates < AP rates + * @WMA_TDLS_TEARDOWN_REASON_RSSI: tdls link tear down recommended + * due to poor RSSI + * @WMA_TDLS_TEARDOWN_REASON_SCAN: tdls link tear down recommended + * due to offchannel scan + * @WMA_TDLS_DISCONNECTED_REASON_PEER_DELETE: tdls peer disconnected + * due to peer deletion + */ +enum wma_tdls_peer_reason { + WMA_TDLS_TEARDOWN_REASON_TX, + WMA_TDLS_TEARDOWN_REASON_RATE, + WMA_TDLS_TEARDOWN_REASON_RSSI, + WMA_TDLS_TEARDOWN_REASON_SCAN, + WMA_TDLS_DISCONNECTED_REASON_PEER_DELETE, +}; +#endif /* FEATURE_WLAN_TDLS */ + + +/** + * enum t_wma_roam_preauth_chan_state_t - Roaming preauth channel state + * @WMA_ROAM_PREAUTH_CHAN_NONE: no preauth in progress + * @WMA_ROAM_PREAUTH_CHAN_REQUESTED: preaduth channel requested + * @WMA_ROAM_PREAUTH_ON_CHAN: preauth on channel + * @WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED: preauth channel cancel requested + * @WMA_ROAM_PREAUTH_CHAN_COMPLETED: preauth completed + */ +typedef enum { + WMA_ROAM_PREAUTH_CHAN_NONE, + WMA_ROAM_PREAUTH_CHAN_REQUESTED, + WMA_ROAM_PREAUTH_ON_CHAN, + WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED, + WMA_ROAM_PREAUTH_CHAN_COMPLETED +} t_wma_roam_preauth_chan_state_t; + +/** + * struct wma_mem_chunk - memory chunks + * @vaddr: virtual address + * @paddr: physical address + * @memctx: dma mapped memory + * @len: length of data + * @req_id: request id + * + * memory chunck allocated by Host to be managed by FW + * used only for low latency interfaces like pcie + */ +struct wma_mem_chunk { + uint32_t *vaddr; + uint32_t paddr; + cdf_dma_mem_context(memctx); + uint32_t len; + uint32_t req_id; +}; + +/** + * struct p2p_scan_param - p2p scan listen parameters + * @scan_id: scan id + * @p2p_scan_type: p2p scan type + */ +struct p2p_scan_param { + uint32_t scan_id; + tSirP2pScanType p2p_scan_type; +}; + +/** + * struct scan_param - scan parameters + * @scan_id: scan id + * @scan_requestor_id: scan requestor id + * @p2p_scan_type: p2p scan type + */ +struct scan_param { + uint32_t scan_id; + uint32_t scan_requestor_id; + tSirP2pScanType p2p_scan_type; +}; + +/** + * struct beacon_info - structure to store beacon template + * @buf: skb ptr + * @len: length + * @dma_mapped: is it dma mapped or not + * @tim_ie_offset: TIM IE offset + * @dtim_count: DTIM count + * @seq_no: sequence no + * @noa_sub_ie: NOA sub IE + * @noa_sub_ie_len: NOA sub IE length + * @noa_ie: NOA IE + * @p2p_ie_offset: p2p IE offset + * @lock: lock + */ +struct beacon_info { + cdf_nbuf_t buf; + uint32_t len; + uint8_t dma_mapped; + uint32_t tim_ie_offset; + uint8_t dtim_count; + uint16_t seq_no; + uint8_t noa_sub_ie[2 + WMA_NOA_IE_SIZE(WMA_MAX_NOA_DESCRIPTORS)]; + uint16_t noa_sub_ie_len; + uint8_t *noa_ie; + uint16_t p2p_ie_offset; + cdf_spinlock_t lock; +}; + +/** + * struct beacon_tim_ie - structure to store TIM IE of beacon + * @tim_ie: tim ie + * @tim_len: tim ie length + * @dtim_count: dtim count + * @dtim_period: dtim period + * @tim_bitctl: tim bit control + * @tim_bitmap: tim bitmap + */ +struct beacon_tim_ie { + uint8_t tim_ie; + uint8_t tim_len; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t tim_bitctl; + uint8_t tim_bitmap[1]; +} __ATTRIB_PACK; + +/** + * struct pps - packet power save parameter + * @paid_match_enable: paid match enable + * @gid_match_enable: gid match enable + * @tim_clear: time clear + * @dtim_clear: dtim clear + * @eof_delim: eof delim + * @mac_match: mac match + * @delim_fail: delim fail + * @nsts_zero: nsts zero + * @rssi_chk: RSSI check + * @ebt_5g: ebt 5GHz + */ +struct pps { + bool paid_match_enable; + bool gid_match_enable; + bool tim_clear; + bool dtim_clear; + bool eof_delim; + bool mac_match; + bool delim_fail; + bool nsts_zero; + bool rssi_chk; + bool ebt_5g; +}; + +/** + * struct qpower_params - qpower related parameters + * @max_ps_poll_cnt: max ps poll count + * @max_tx_before_wake: max tx before wake + * @spec_ps_poll_wake_interval: ps poll wake interval + * @max_spec_nodata_ps_poll: no data ps poll + */ +struct qpower_params { + uint32_t max_ps_poll_cnt; + uint32_t max_tx_before_wake; + uint32_t spec_ps_poll_wake_interval; + uint32_t max_spec_nodata_ps_poll; +}; + + +/** + * struct gtx_config_t - GTX config + * @gtxRTMask: for HT and VHT rate masks + * @gtxUsrcfg: host request for GTX mask + * @gtxPERThreshold: PER Threshold (default: 10%) + * @gtxPERMargin: PER margin (default: 2%) + * @gtxTPCstep: TCP step (default: 1) + * @gtxTPCMin: TCP min (default: 5) + * @gtxBWMask: BW mask (20/40/80/160 Mhz) + */ +typedef struct { + uint32_t gtxRTMask[2]; + uint32_t gtxUsrcfg; + uint32_t gtxPERThreshold; + uint32_t gtxPERMargin; + uint32_t gtxTPCstep; + uint32_t gtxTPCMin; + uint32_t gtxBWMask; +} gtx_config_t; + +/** + * struct pdev_cli_config_t - store pdev parameters + * @ani_enable: ANI is enabled/disable on target + * @ani_poll_len: store ANI polling period + * @ani_listen_len: store ANI listening period + * @ani_ofdm_level: store ANI OFDM immunity level + * @ani_cck_level: store ANI CCK immunity level + * @cwmenable: Dynamic bw is enable/disable in fw + * @txchainmask: tx chain mask + * @rxchainmask: rx chain mask + * @txpow2g: tx power limit for 2GHz + * @txpow5g: tx power limit for 5GHz + * @pwrgating: enable/disable power gating sleep + * @burst_enable: is burst enable/disable + * @burst_dur: burst duration + * + * This structure stores pdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t ani_enable; + uint32_t ani_poll_len; + uint32_t ani_listen_len; + uint32_t ani_ofdm_level; + uint32_t ani_cck_level; + uint32_t cwmenable; + uint32_t cts_cbw; + uint32_t txchainmask; + uint32_t rxchainmask; + uint32_t txpow2g; + uint32_t txpow5g; + uint32_t pwrgating; + uint32_t burst_enable; + uint32_t burst_dur; +} pdev_cli_config_t; + +/** + * struct vdev_cli_config_t - store vdev parameters + * @nss: nss width + * @ldpc: is ldpc is enable/disable + * @tx_stbc: TX STBC is enable/disable + * @rx_stbc: RX STBC is enable/disable + * @shortgi: short gi is enable/disable + * @rtscts_en: RTS/CTS is enable/disable + * @chwidth: channel width + * @tx_rate: tx rate + * @ampdu: ampdu size + * @amsdu: amsdu size + * @erx_adjust: enable/disable early rx enable + * @erx_bmiss_num: target bmiss number per sample + * @erx_bmiss_cycle: sample cycle + * @erx_slop_step: slop_step value + * @erx_init_slop: init slop + * @erx_adj_pause: pause adjust enable/disable + * @erx_dri_sample: enable/disable drift sample + * @pps_params: packet power save parameters + * @qpower_params: qpower parameters + * @gtx_info: GTX offload info + * + * This structure stores vdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t nss; + uint32_t ldpc; + uint32_t tx_stbc; + uint32_t rx_stbc; + uint32_t shortgi; + uint32_t rtscts_en; + uint32_t chwidth; + uint32_t tx_rate; + uint32_t ampdu; + uint32_t amsdu; + uint32_t erx_adjust; + uint32_t erx_bmiss_num; + uint32_t erx_bmiss_cycle; + uint32_t erx_slop_step; + uint32_t erx_init_slop; + uint32_t erx_adj_pause; + uint32_t erx_dri_sample; + struct pps pps_params; + struct qpower_params qpower_params; + gtx_config_t gtx_info; +} vdev_cli_config_t; + +/** + * struct wma_wow - store wow patterns + * @magic_ptrn_enable: magic pattern enable/disable + * @wow_enable: wow enable/disable + * @wow_enable_cmd_sent: is wow enable command sent to fw + * @deauth_enable: is deauth wakeup enable/disable + * @disassoc_enable: is disassoc wakeup enable/disable + * @bmiss_enable: is bmiss wakeup enable/disable + * @gtk_pdev_enable: is GTK based wakeup enable/disable + * @gtk_err_enable: is GTK error wakeup enable/disable + * @lphb_cache: lphb cache + * + * This structure stores wow patterns and + * wow related parameters in host. + */ +struct wma_wow { + bool magic_ptrn_enable; + bool wow_enable; + bool wow_enable_cmd_sent; + bool deauth_enable; + bool disassoc_enable; + bool bmiss_enable; + bool gtk_pdev_enable; + bool gtk_err_enable[WMA_MAX_SUPPORTED_BSS]; +#ifdef FEATURE_WLAN_LPHB + /* currently supports only vdev 0. + * cache has two entries: one for TCP and one for UDP. + */ + tSirLPHBReq lphb_cache[2]; +#endif +}; + +#ifdef WLAN_FEATURE_11W +#define CMAC_IPN_LEN (6) +#define WMA_IGTK_KEY_INDEX_4 (4) +#define WMA_IGTK_KEY_INDEX_5 (5) + +/** + * struct wma_igtk_ipn_t - GTK IPN info + * @ipn: IPN info + */ +typedef struct { + uint8_t ipn[CMAC_IPN_LEN]; +} wma_igtk_ipn_t; + +/** + * struct wma_igtk_key_t - GTK key + * @key_length: key length + * @key: key + * @key_id: key id + */ +typedef struct { + uint16_t key_length; + uint8_t key[CSR_AES_KEY_LEN]; + + /* IPN is maintained per iGTK keyID + * 0th index for iGTK keyID = 4; + * 1st index for iGTK KeyID = 5 + */ + wma_igtk_ipn_t key_id[2]; +} wma_igtk_key_t; +#endif + +/** + * struct vdev_restart_params_t - vdev restart parameters + * @vdev_id: vdev id + * @ssid: ssid + * @flags: flags + * @requestor_id: requestor id + * @chan: channel + * @hidden_ssid_restart_in_progress: hidden ssid restart flag + * @ssidHidden: is ssid hidden or not + */ +typedef struct { + A_UINT32 vdev_id; + wmi_ssid ssid; + A_UINT32 flags; + A_UINT32 requestor_id; + A_UINT32 disable_hw_ack; + wmi_channel chan; + cdf_atomic_t hidden_ssid_restart_in_progress; + uint8_t ssidHidden; +} vdev_restart_params_t; + +/** + * struct wma_txrx_node - txrx node + * @addr: mac address + * @bssid: bssid + * @handle: wma handle + * @beacon: beacon info + * @vdev_restart_params: vdev restart parameters + * @config: per vdev config parameters + * @scan_info: scan info + * @type: type + * @sub_type: sub type + * @nlo_match_evt_received: is nlo match event received or not + * @pno_in_progress: is pno in progress or not + * @plm_in_progress: is plm in progress or not + * @ptrn_match_enable: is pattern match is enable or not + * @num_wow_default_patterns: number of default wow patterns configured for vdev + * @num_wow_user_patterns: number of user wow patterns configured for vdev + * @conn_state: connection state + * @beaconInterval: beacon interval + * @llbCoexist: 11b coexist + * @shortSlotTimeSupported: is short slot time supported or not + * @dtimPeriod: DTIM period + * @chanmode: channel mode + * @vht_capable: VHT capablity flag + * @ht_capable: HT capablity flag + * @mhz: channel frequency in KHz + * @vdev_up: is vdev up or not + * @tsfadjust: TSF adjust + * @addBssStaContext: add bss context + * @aid: association id + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @key: GTK key + * @uapsd_cached_val: uapsd cached value + * @stats_rsp: stats response + * @fw_stats_set: fw stats value + * @del_staself_req: delete sta self request + * @bss_status: bss status + * @rate_flags: rate flags + * @nss: nss value + * @is_channel_switch: is channel switch + * @pause_bitmap: pause bitmap + * @tx_power: tx power in dbm + * @max_tx_power: max tx power in dbm + * @nwType: network type (802.11a/b/g/n/ac) + * @staKeyParams: sta key parameters + * @ps_enabled: is powersave enable/disable + * @dtim_policy: DTIM policy + * @peer_count: peer count + * @roam_synch_in_progress: flag is in progress or not + * @plink_status_req: link status request + * @psnr_req: snr request + * @delay_before_vdev_stop: delay + * @tx_streams: number of tx streams can be used by the vdev + * @rx_streams: number of rx streams can be used by the vdev + * @chain_mask: chain mask can be used by the vdev + * @mac_id: the mac on which vdev is on + * + * It stores parameters per vdev in wma. + */ +struct wma_txrx_node { + uint8_t addr[IEEE80211_ADDR_LEN]; + uint8_t bssid[IEEE80211_ADDR_LEN]; + void *handle; + struct beacon_info *beacon; + vdev_restart_params_t vdev_restart_params; + vdev_cli_config_t config; + struct scan_param scan_info; + struct p2p_scan_param p2p_scan_info; + uint32_t type; + uint32_t sub_type; +#ifdef FEATURE_WLAN_SCAN_PNO + bool nlo_match_evt_received; + bool pno_in_progress; +#endif +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + bool plm_in_progress; +#endif + bool ptrn_match_enable; + uint8_t num_wow_default_patterns; + uint8_t num_wow_user_patterns; + bool conn_state; + tSirMacBeaconInterval beaconInterval; + uint8_t llbCoexist; + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + WLAN_PHY_MODE chanmode; + uint8_t vht_capable; + uint8_t ht_capable; + A_UINT32 mhz; + bool vdev_up; + uint64_t tsfadjust; + void *addBssStaContext; + uint8_t aid; + uint8_t rmfEnabled; +#ifdef WLAN_FEATURE_11W + wma_igtk_key_t key; +#endif /* WLAN_FEATURE_11W */ + uint32_t uapsd_cached_val; + tAniGetPEStatsRsp *stats_rsp; + uint8_t fw_stats_set; + void *del_staself_req; + cdf_atomic_t bss_status; + uint8_t rate_flags; + uint8_t nss; + bool is_channel_switch; + uint16_t pause_bitmap; + tPowerdBm tx_power; + tPowerdBm max_tx_power; + uint32_t nwType; +#if defined WLAN_FEATURE_VOWIFI_11R + void *staKeyParams; +#endif + bool ps_enabled; + uint32_t dtim_policy; + uint32_t peer_count; + bool roam_synch_in_progress; + void *plink_status_req; + void *psnr_req; + uint8_t delay_before_vdev_stop; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_in_progress; +#endif + uint32_t alt_modulated_dtim; + bool alt_modulated_dtim_enabled; + uint32_t tx_streams; + uint32_t rx_streams; + uint32_t chain_mask; + uint32_t mac_id; +}; + +#if defined(QCA_WIFI_FTM) +#define MAX_UTF_EVENT_LENGTH 2048 +#define MAX_WMI_UTF_LEN 252 + +/** + * struct SEG_HDR_INFO_STRUCT - header info + * @len: length + * @msgref: message refrence + * @segmentInfo: segment info + * @pad: padding + */ +typedef struct { + A_UINT32 len; + A_UINT32 msgref; + A_UINT32 segmentInfo; + A_UINT32 pad; +} SEG_HDR_INFO_STRUCT; + +/** + * struct utf_event_info - UTF event info + * @data: data ptr + * @length: length + * @offset: offset + * @currentSeq: curent squence + * @expectedSeq: expected sequence + */ +struct utf_event_info { + uint8_t *data; + uint32_t length; + cdf_size_t offset; + uint8_t currentSeq; + uint8_t expectedSeq; +}; +#endif + +/** + * struct scan_timer_info - scan timer info + * @vdev_id: vdev id + * @scan_id: scan id + */ +typedef struct { + uint8_t vdev_id; + uint32_t scan_id; +} scan_timer_info; + +/** + * struct ibss_power_save_params - IBSS power save parameters + * @atimWindowLength: ATIM window length + * @isPowerSaveAllowed: is power save allowed + * @isPowerCollapseAllowed: is power collapsed allowed + * @isAwakeonTxRxEnabled: is awake on tx/rx enabled + * @inactivityCount: inactivity count + * @txSPEndInactivityTime: tx SP end inactivity time + * @ibssPsWarmupTime: IBSS power save warm up time + * @ibssPs1RxChainInAtimEnable: IBSS power save rx chain in ATIM enable + */ +typedef struct { + uint32_t atimWindowLength; + uint32_t isPowerSaveAllowed; + uint32_t isPowerCollapseAllowed; + uint32_t isAwakeonTxRxEnabled; + uint32_t inactivityCount; + uint32_t txSPEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; +} ibss_power_save_params; + +/** + * struct dbs_hw_mode_info - WLAN_DBS_HW_MODES_TLV Format + * @tlv_header: TLV header, TLV tag and len; tag equals WMITLV_TAG_ARRAY_UINT32 + * @hw_mode_list: WLAN_DBS_HW_MODE_LIST entries + */ +struct dbs_hw_mode_info { + uint32_t tlv_header; + uint32_t *hw_mode_list; +}; + +/* Current HTC credit is 2, pool size of 50 is sufficient */ +#define WMI_DESC_POOL_MAX 50 + +/** + * struct wmi_desc_t - wmi management Tx descriptor. + * @tx_cmpl_cb_func: completion callback function, when DL completion and + * OTA done. + * @ota_post_proc_func: Post process callback function registered. + * @nbuf: Network buffer to be freed. + * @desc_id: WMI descriptor. + */ + +struct wmi_desc_t { + pWMATxRxCompFunc tx_cmpl_cb; + pWMAAckFnTxComp ota_post_proc_cb; + cdf_nbuf_t nbuf; + uint32_t desc_id; +}; + +/** + * union wmi_desc_elem_t - linked list wmi desc pool. + * @next: Pointer next descritor in the pool. + * @wmi_desc: wmi descriptor element. + */ +union wmi_desc_elem_t { + union wmi_desc_elem_t *next; + struct wmi_desc_t wmi_desc; +}; + +/** + * struct dual_mac_config - Dual MAC configurations + * @prev_scan_config: Previous scan configuration + * @prev_fw_mode_config: Previous FW mode configuration + * @cur_scan_config: Current scan configuration + * @cur_fw_mode_config: Current FW mode configuration + * @req_scan_config: Requested scan configuration + * @req_fw_mode_config: Requested FW mode configuration + */ +struct dual_mac_config { + uint32_t prev_scan_config; + uint32_t prev_fw_mode_config; + uint32_t cur_scan_config; + uint32_t cur_fw_mode_config; + uint32_t req_scan_config; + uint32_t req_fw_mode_config; + +}; + +/** + * struct wmi_init_cmd - Saved wmi INIT command + * @buf: Buffer containing the wmi INIT command + * @buf_len: Length of the buffer + */ +struct wmi_init_cmd { + wmi_buf_t buf; + uint32_t buf_len; +}; + +/** + * struct t_wma_handle - wma context + * @wmi_handle: wmi handle + * @htc_handle: htc handle + * @cds_context: cds handle + * @mac_context: mac context + * @wma_ready_event: wma rx ready event + * @wma_resume_event: wma resume event + * @target_suspend: target suspend event + * @recovery_event: wma FW recovery event + * @max_station: max stations + * @max_bssid: max bssid + * @frame_xln_reqd: frame transmission required + * @driver_type: driver type + * @myaddr: current mac address + * @hwaddr: mac address from EEPROM + * @target_abi_vers: target firmware version + * @final_abi_vers: The final ABI version to be used for communicating + * @target_fw_version: Target f/w build version + * @lpss_support: LPSS feature is supported in target or not + * @wmi_ready: wmi status flag + * @wlan_init_status: wlan init status + * @cdf_dev: cdf device + * @phy_capability: PHY Capability from Target + * @max_frag_entry: Max number of Fragment entry + * @wmi_service_bitmap: wmi services bitmap received from Target + * @wlan_resource_config: resource config + * @frameTransRequired: frame transmission required + * @wmaGlobalSystemRole: global system role + * @tx_frm_download_comp_cb: Tx Frame Compl Cb registered by umac + * @tx_frm_download_comp_event: Event to wait for tx download completion + * @tx_queue_empty_event: wait for tx queue to get flushed + * @umac_ota_ack_cb: Ack Complete Callback registered by umac + * @umac_data_ota_ack_cb: ack complete callback + * @last_umac_data_ota_timestamp: timestamp when OTA of last umac data was done + * @last_umac_data_nbuf: cache nbuf ptr for the last umac data buf + * @needShutdown: is shutdown needed or not + * @num_mem_chunks: number of memory chunk + * @mem_chunks: memory chunks + * @tgt_cfg_update_cb: configuration update callback + * @dfs_radar_indication_cb: Callback to indicate radar to HDD + * @reg_cap: regulatory capablities + * @scan_id: scan id + * @interfaces: txrx nodes(per vdev) + * @pdevconfig: pdev related configrations + * @vdev_resp_queue: vdev response queue + * @vdev_respq_lock: vdev response queue lock + * @ht_cap_info: HT capablity info + * @vht_cap_info: VHT capablity info + * @vht_supp_mcs: VHT supported MCS + * @num_rf_chains: number of RF chains + * @utf_event_info: UTF event information + * @is_fw_assert: is fw asserted + * @wow: wow related patterns & parameters + * @no_of_suspend_ind: number of suspend indications + * @no_of_resume_ind: number of resume indications + * @mArpInfo: arp info + * @powersave_mode: power save mode + * @ptrn_match_enable_all_vdev: is pattern match is enable/disable + * @pGetRssiReq: get RSSI request + * @thermal_mgmt_info: Thermal mitigation related info + * @roam_offload_enabled: is roam offload enable/disable + * @roam_preauth_scan_state: roam preauth scan state + * @roam_preauth_scan_id: roam preauth scan id + * @roam_preauth_chanfreq: roam preauth channel frequency + * @roam_preauth_chan_context: roam preauth chan context + * @ol_ini_info: store ini status of arp offload, ns offload + * @ssdp: ssdp flag + * @ibss_started: is IBSS started or not + * @ibsskey_info: IBSS key info + * @dfs_ic: DFS umac interface information + * @hddTxFailCb: tx fail indication callback + * @pno_wake_lock: PNO wake lock + * @extscan_wake_lock: extscan wake lock + * @wow_wake_lock: wow wake lock + * @wow_nack: wow negative ack flag + * @ap_client_cnt: ap client count + * @is_wow_bus_suspended: is wow bus suspended flag + * @wma_scan_comp_timer: scan completion timer + * @dfs_phyerr_filter_offload: dfs phy error filter is offloaded or not + * @suitable_ap_hb_failure: better ap found + * @wma_ibss_power_save_params: IBSS Power Save config Parameters + * @IsRArateLimitEnabled: RA rate limiti s enabled or not + * @RArateLimitInterval: RA rate limit interval + * @is_lpass_enabled: Flag to indicate if LPASS feature is enabled or not + * @is_nan_enabled: Flag to indicate if NaN feature is enabled or not + * @staMaxLIModDtim: station max listen interval + * @staModDtim: station mode DTIM + * @staDynamicDtim: station dynamic DTIM + * @enable_mhf_offload: is MHF offload enable/disable + * @last_mhf_entries_timestamp: timestamp when last entries where set + * @dfs_pri_multiplier: DFS multiplier + * @hw_bd_id: hardware board id + * @hw_bd_info: hardware board info + * @in_d0wow: D0WOW is enable/disable + * @miracast_value: miracast value + * @log_completion_timer: log completion timer + * @mgmt_rx: management rx callback + * @num_dbs_hw_modes: Number of HW modes supported by the FW + * @dbs_mode: DBS HW mode list + * @old_hw_mode_index: Previous configured HW mode index + * @new_hw_mode_index: Current configured HW mode index + * @peer_authorized_cb: peer authorized hdd callback + * @ocb_callback: callback to OCB commands + * @ocb_resp: response to OCB commands + * @wow_pno_match_wake_up_count: PNO match wake up count + * @wow_pno_complete_wake_up_count: PNO complete wake up count + * @wow_gscan_wake_up_count: Gscan wake up count + * @wow_low_rssi_wake_up_count: Low rssi wake up count + * @wow_rssi_breach_wake_up_count: RSSI breach wake up count + * @wow_ucast_wake_up_count: WoW unicast packet wake up count + * @wow_bcast_wake_up_count: WoW brodcast packet wake up count + * @wow_ipv4_mcast_wake_up_count: WoW IPV4 mcast packet wake up count + * @wow_ipv6_mcast_wake_up_count: WoW IPV6 mcast packet wake up count + * @wow_ipv6_mcast_ra_stats: WoW IPV6 mcast RA packet wake up count + * @wow_ipv6_mcast_ns_stats: WoW IPV6 mcast NS packet wake up count + * @wow_ipv6_mcast_na_stats: WoW IPV6 mcast NA packet wake up count + * @dual_mac_cfg: Dual mac configuration params for scan and fw mode + * + * @max_scan: maximum scan requests than can be queued + * This structure is global wma context + * It contains global wma module parameters and + * handle of other modules. + * @saved_wmi_init_cmd: Saved WMI INIT command + * @service_ready_ext_evt: Wait event for service ready ext + */ +typedef struct { + void *wmi_handle; + void *htc_handle; + void *cds_context; + void *mac_context; + cdf_event_t wma_ready_event; + cdf_event_t wma_resume_event; + cdf_event_t target_suspend; + cdf_event_t recovery_event; + uint16_t max_station; + uint16_t max_bssid; + uint32_t frame_xln_reqd; + t_wma_drv_type driver_type; + uint8_t myaddr[IEEE80211_ADDR_LEN]; + uint8_t hwaddr[IEEE80211_ADDR_LEN]; + wmi_abi_version target_abi_vers; + wmi_abi_version final_abi_vers; + uint32_t target_fw_version; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + bool wmi_ready; + uint32_t wlan_init_status; + cdf_device_t cdf_dev; + uint32_t phy_capability; + uint32_t max_frag_entry; + uint32_t wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + wmi_resource_config wlan_resource_config; + uint32_t frameTransRequired; + tBssSystemRole wmaGlobalSystemRole; + pWMATxRxCompFunc tx_frm_download_comp_cb; + cdf_event_t tx_frm_download_comp_event; + /* + * Dummy event to wait for draining MSDUs left in hardware tx + * queue and before requesting VDEV_STOP. Nobody will set this + * and wait will timeout, and code will poll the pending tx + * descriptors number to be zero. + */ + cdf_event_t tx_queue_empty_event; + pWMAAckFnTxComp umac_ota_ack_cb[SIR_MAC_MGMT_RESERVED15]; + pWMAAckFnTxComp umac_data_ota_ack_cb; + v_TIME_t last_umac_data_ota_timestamp; + cdf_nbuf_t last_umac_data_nbuf; + bool needShutdown; + uint32_t num_mem_chunks; + struct wma_mem_chunk mem_chunks[MAX_MEM_CHUNKS]; + wma_tgt_cfg_cb tgt_cfg_update_cb; + wma_dfs_radar_indication_cb dfs_radar_indication_cb; + HAL_REG_CAPABILITIES reg_cap; + uint32_t scan_id; + struct wma_txrx_node *interfaces; + pdev_cli_config_t pdevconfig; + struct list_head vdev_resp_queue; + cdf_spinlock_t vdev_respq_lock; + cdf_list_t wma_hold_req_queue; + cdf_spinlock_t wma_hold_req_q_lock; + uint32_t ht_cap_info; +#ifdef WLAN_FEATURE_11AC + uint32_t vht_cap_info; + uint32_t vht_supp_mcs; +#endif + uint32_t num_rf_chains; +#if defined(QCA_WIFI_FTM) + struct utf_event_info utf_event_info; +#endif + uint8_t is_fw_assert; + struct wma_wow wow; + uint8_t no_of_suspend_ind; + uint8_t no_of_resume_ind; + /* Have a back up of arp info to send along + * with ns info suppose if ns also enabled + */ + tSirHostOffloadReq mArpInfo; + struct wma_tx_ack_work_ctx *ack_work_ctx; + uint8_t powersave_mode; + bool ptrn_match_enable_all_vdev; + void *pGetRssiReq; + t_thermal_mgmt thermal_mgmt_info; + bool roam_offload_enabled; + t_wma_roam_preauth_chan_state_t roam_preauth_scan_state; + uint32_t roam_preauth_scan_id; + uint16_t roam_preauth_chanfreq; + void *roam_preauth_chan_context; + /* Here ol_ini_info is used to store ini + * status of arp offload, ns offload + * and others. Currently 1st bit is used + * for arp off load and 2nd bit for ns + * offload currently, rest bits are unused + */ + uint8_t ol_ini_info; + bool ssdp; + uint8_t ibss_started; + tSetBssKeyParams ibsskey_info; + struct ieee80211com *dfs_ic; + +#ifdef FEATURE_WLAN_SCAN_PNO + cdf_wake_lock_t pno_wake_lock; +#endif +#ifdef FEATURE_WLAN_EXTSCAN + cdf_wake_lock_t extscan_wake_lock; +#endif + cdf_wake_lock_t wow_wake_lock; + int wow_nack; + cdf_atomic_t is_wow_bus_suspended; + cdf_mc_timer_t wma_scan_comp_timer; + uint8_t dfs_phyerr_filter_offload; + bool suitable_ap_hb_failure; + ibss_power_save_params wma_ibss_power_save_params; +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + uint8_t staMaxLIModDtim; + uint8_t staModDtim; + uint8_t staDynamicDtim; + int32_t dfs_pri_multiplier; + uint32_t hw_bd_id; + uint32_t hw_bd_info[HW_BD_INFO_SIZE]; + uint32_t miracast_value; + cdf_mc_timer_t log_completion_timer; + wma_mgmt_frame_rx_callback mgmt_rx; + uint32_t num_dbs_hw_modes; + struct dbs_hw_mode_info hw_mode; + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + cdf_atomic_t scan_id_counter; + wma_peer_authorized_fp peer_authorized_cb; + uint32_t num_of_diag_events_logs; + uint32_t *events_logs_list; + + uint32_t wow_pno_match_wake_up_count; + uint32_t wow_pno_complete_wake_up_count; + uint32_t wow_gscan_wake_up_count; + uint32_t wow_low_rssi_wake_up_count; + uint32_t wow_rssi_breach_wake_up_count; + uint32_t wow_ucast_wake_up_count; + uint32_t wow_bcast_wake_up_count; + uint32_t wow_ipv4_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_ra_stats; + uint32_t wow_ipv6_mcast_ns_stats; + uint32_t wow_ipv6_mcast_na_stats; + + /* OCB request contexts */ + struct sir_ocb_config *ocb_config_req; + struct dual_mac_config dual_mac_cfg; + struct { + uint16_t pool_size; + uint16_t num_free; + union wmi_desc_elem_t *array; + union wmi_desc_elem_t *freelist; + cdf_spinlock_t wmi_desc_pool_lock; + } wmi_desc_pool; + uint8_t max_scan; + struct wmi_init_cmd saved_wmi_init_cmd; + cdf_event_t service_ready_ext_evt; + uint16_t self_gen_frm_pwr; + bool tx_chain_mask_cck; +} t_wma_handle, *tp_wma_handle; + +/** + * struct wma_target_cap - target capabality + * @wmi_service_bitmap: wmi services bitmap + * @wlan_resource_config: resource config + */ +struct wma_target_cap { + /* wmi services bitmap received from Target */ + uint32_t wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + /* default resource config,the os shim can overwrite it */ + wmi_resource_config wlan_resource_config; +}; + +/** + * struct t_wma_start_req - wma start request parameters + * @pConfigBuffer: config buffer + * @usConfigBufferLen: Length of the config buffer above + * @driver_type: Production or FTM driver + * @pUserData: user data + * @pIndUserData: indication function pointer to send to UMAC + * + * The shared memory between WDI and HAL is 4K so maximum data can be + * transferred from WDI to HAL is 4K + */ +typedef struct { + void *pConfigBuffer; + uint16_t usConfigBufferLen; + t_wma_drv_type driver_type; + void *pUserData; + void *pIndUserData; +} t_wma_start_req; + +/* Enumeration for Version */ +typedef enum { + WLAN_HAL_MSG_VERSION0 = 0, + WLAN_HAL_MSG_VERSION1 = 1, + WLAN_HAL_MSG_WCNSS_CTRL_VERSION = 0x7FFF, /*define as 2 bytes data */ + WLAN_HAL_MSG_VERSION_MAX_FIELD = WLAN_HAL_MSG_WCNSS_CTRL_VERSION +} tHalHostMsgVersion; + +/** + * struct sHalMacStartParameter - mac start request parameters + * @driverType: driver type (production/FTM) + * @uConfigBufferLen: length of config buffer + */ +typedef struct cdf_packed sHalMacStartParameter { + tDriverType driverType; + uint32_t uConfigBufferLen; + + /* Following this there is a TLV formatted buffer of length + * "uConfigBufferLen" bytes containing all config values. + * The TLV is expected to be formatted like this: + * 0 15 31 31+CFG_LEN-1 length-1 + * | CFG_ID | CFG_LEN | CFG_BODY | CFG_ID |......| + */ +} tHalMacStartParameter, *tpHalMacStartParameter; + +extern void cds_wma_complete_cback(void *p_cds_context); +extern void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G); +void wma_get_modeselect(tp_wma_handle wma, uint32_t *modeSelect); + +/** + * enum frame_index - Frame index + * @GENERIC_NODOWNLD_NOACK_COMP_INDEX: Frame index for no download comp no ack + * @GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX: Frame index for download comp no ack + * @GENERIC_DOWNLD_COMP_ACK_COMP_INDEX: Frame index for download comp and ack + * @GENERIC_NODOWLOAD_ACK_COMP_INDEX: Frame index for no download comp and ack + * @FRAME_INDEX_MAX: maximum frame index + */ +enum frame_index { + GENERIC_NODOWNLD_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX, + GENERIC_NODOWLOAD_ACK_COMP_INDEX, + FRAME_INDEX_MAX +}; + +/** + * struct wma_tx_ack_work_ctx - tx ack work context + * @wma_handle: wma handle + * @sub_type: sub type + * @status: status + * @ack_cmp_work: work structure + */ +struct wma_tx_ack_work_ctx { + tp_wma_handle wma_handle; + uint16_t sub_type; + int32_t status; + struct work_struct ack_cmp_work; +}; + +/** + * struct wma_target_req - target request parameters + * @event_timeout: event timeout + * @node: list + * @user_data: user data + * @msg_type: message type + * @vdev_id: vdev id + * @type: type + */ +struct wma_target_req { + cdf_mc_timer_t event_timeout; + cdf_list_node_t node; + void *user_data; + uint32_t msg_type; + uint8_t vdev_id; + uint8_t type; +}; + +/** + * struct wma_vdev_start_req - vdev start request parameters + * @beacon_intval: beacon interval + * @dtim_period: dtim period + * @max_txpow: max tx power + * @chan_offset: channel offset + * @is_dfs: is dfs supported or not + * @vdev_id: vdev id + * @chan: channel + * @oper_mode: operating mode + * @ssid: ssid + * @hidden_ssid: hidden ssid + * @pmf_enabled: is pmf enabled or not + * @vht_capable: VHT capabality + * @ht_capable: HT capabality + * @dfs_pri_multiplier: DFS multiplier + * @dot11_mode: 802.11 mode + * @is_half_rate: is the channel operating at 10MHz + * @is_quarter_rate: is the channel operating at 5MHz + * @preferred_tx_streams: policy manager indicates the preferred + * number of transmit streams + * @preferred_rx_streams: policy manager indicates the preferred + * number of receive streams + */ +struct wma_vdev_start_req { + uint32_t beacon_intval; + uint32_t dtim_period; + int32_t max_txpow; + phy_ch_width chan_width; + bool is_dfs; + uint8_t vdev_id; + uint8_t chan; + uint8_t oper_mode; + tSirMacSSid ssid; + uint8_t hidden_ssid; + uint8_t pmf_enabled; + uint8_t vht_capable; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t ht_capable; + int32_t dfs_pri_multiplier; + uint8_t dot11_mode; + bool is_half_rate; + bool is_quarter_rate; + uint32_t preferred_tx_streams; + uint32_t preferred_rx_streams; +}; + +/** + * struct wma_set_key_params - set key parameters + * @vdev_id: vdev id + * @def_key_idx: used to see if we have to read the key from cfg + * @key_len: key length + * @peer_mac: peer mac address + * @singl_tid_rc: 1=Single TID based Replay Count, 0=Per TID based RC + * @key_type: key type + * @key_idx: key index + * @unicast: unicast flag + * @key_data: key data + */ +struct wma_set_key_params { + uint8_t vdev_id; + /* def_key_idx can be used to see if we have to read the key from cfg */ + uint32_t def_key_idx; + uint16_t key_len; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + uint8_t singl_tid_rc; + enum eAniEdType key_type; + uint32_t key_idx; + bool unicast; + uint8_t key_data[SIR_MAC_MAX_KEY_LENGTH]; +}; + +/** + * struct t_thermal_cmd_params - thermal command parameters + * @minTemp: minimum temprature + * @maxTemp: maximum temprature + * @thermalEnable: thermal enable + */ +typedef struct { + uint16_t minTemp; + uint16_t maxTemp; + uint8_t thermalEnable; +} t_thermal_cmd_params, *tp_thermal_cmd_params; + +/** + * enum wma_cfg_cmd_id - wma cmd ids + * @WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: txrx firmware stats enable command + * @WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: txrx firmware stats reset command + * @WMA_VDEV_MCC_SET_TIME_LATENCY: set MCC latency time + * @WMA_VDEV_MCC_SET_TIME_QUOTA: set MCC time quota + * @WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE: set IBSS ATIM window size + * @WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: set IBSS enable power save + * @WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: set IBSS power collapse enable + * @WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: awake IBSS on TX/RX + * @WMA_VDEV_IBSS_SET_INACTIVITY_TIME: set IBSS inactivity time + * @WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: set IBSS TXSP + * @WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: set IBSS power save warmup time + * @WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: set IBSS power save ATIM + * @WMA_VDEV_DFS_CONTROL_CMDID: DFS control command + * @WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: get IPA microcontroller fw stats + * + * wma command ids for configuration request which + * does not involve sending a wmi command. + */ +enum wma_cfg_cmd_id { + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID = WMI_CMDID_MAX, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + WMA_VDEV_MCC_SET_TIME_LATENCY, + WMA_VDEV_MCC_SET_TIME_QUOTA, + WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + WMA_VDEV_DFS_CONTROL_CMDID, + WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID, + WMA_CMD_ID_MAX +}; + +/** + * struct wma_trigger_uapsd_params - trigger uapsd parameters + * @wmm_ac: wmm access catagory + * @user_priority: user priority + * @service_interval: service interval + * @suspend_interval: suspend interval + * @delay_interval: delay interval + */ +typedef struct wma_trigger_uapsd_params { + uint32_t wmm_ac; + uint32_t user_priority; + uint32_t service_interval; + uint32_t suspend_interval; + uint32_t delay_interval; +} t_wma_trigger_uapsd_params, *tp_wma_trigger_uapsd_params; + +/** + * enum uapsd_peer_param_max_sp - U-APSD maximum service period of peer station + * @UAPSD_MAX_SP_LEN_UNLIMITED: unlimited max service period + * @UAPSD_MAX_SP_LEN_2: max service period = 2 + * @UAPSD_MAX_SP_LEN_4: max service period = 4 + * @UAPSD_MAX_SP_LEN_6: max service period = 6 + */ +enum uapsd_peer_param_max_sp { + UAPSD_MAX_SP_LEN_UNLIMITED = 0, + UAPSD_MAX_SP_LEN_2 = 2, + UAPSD_MAX_SP_LEN_4 = 4, + UAPSD_MAX_SP_LEN_6 = 6 +}; + +/** + * enum uapsd_peer_param_enabled_ac - U-APSD Enabled AC's of peer station + * @UAPSD_VO_ENABLED: enable uapsd for voice + * @UAPSD_VI_ENABLED: enable uapsd for video + * @UAPSD_BK_ENABLED: enable uapsd for background + * @UAPSD_BE_ENABLED: enable uapsd for best effort + */ +enum uapsd_peer_param_enabled_ac { + UAPSD_VO_ENABLED = 0x01, + UAPSD_VI_ENABLED = 0x02, + UAPSD_BK_ENABLED = 0x04, + UAPSD_BE_ENABLED = 0x08 +}; + +/** + * struct p2p_ie - P2P IE structural definition. + * @p2p_id: p2p id + * @p2p_len: p2p length + * @p2p_oui: p2p OUI + * @p2p_oui_type: p2p OUI type + */ +struct p2p_ie { + uint8_t p2p_id; + uint8_t p2p_len; + uint8_t p2p_oui[3]; + uint8_t p2p_oui_type; +} __packed; + +/** + * struct p2p_noa_descriptor - noa descriptor + * @type_count: 255: continuous schedule, 0: reserved + * @duration: Absent period duration in micro seconds + * @interval: Absent period interval in micro seconds + * @start_time: 32 bit tsf time when in starts + */ +struct p2p_noa_descriptor { + uint8_t type_count; + uint32_t duration; + uint32_t interval; + uint32_t start_time; +} __packed; + +/** + * struct p2p_sub_element_noa - p2p noa element + * @p2p_sub_id: p2p sub id + * @p2p_sub_len: p2p sub length + * @index: identifies instance of NOA su element + * @oppPS: oppPS state of the AP + * @ctwindow: ctwindow in TUs + * @num_descriptors: number of NOA descriptors + * @noa_descriptors: noa descriptors + */ +struct p2p_sub_element_noa { + uint8_t p2p_sub_id; + uint8_t p2p_sub_len; + uint8_t index; /* identifies instance of NOA su element */ + uint8_t oppPS:1, /* oppPS state of the AP */ + ctwindow:7; /* ctwindow in TUs */ + uint8_t num_descriptors; /* number of NOA descriptors */ + struct p2p_noa_descriptor noa_descriptors[WMA_MAX_NOA_DESCRIPTORS]; +}; + +/** + * struct wma_decap_info_t - decapsulation info + * @hdr: header + * @hdr_len: header length + */ +struct wma_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_addr4)]; + int32_t hdr_len; +}; + +/** + * enum packet_power_save - packet power save params + * @WMI_VDEV_PPS_PAID_MATCH: paid match param + * @WMI_VDEV_PPS_GID_MATCH: gid match param + * @WMI_VDEV_PPS_EARLY_TIM_CLEAR: early tim clear param + * @WMI_VDEV_PPS_EARLY_DTIM_CLEAR: early dtim clear param + * @WMI_VDEV_PPS_EOF_PAD_DELIM: eof pad delim param + * @WMI_VDEV_PPS_MACADDR_MISMATCH: macaddr mismatch param + * @WMI_VDEV_PPS_DELIM_CRC_FAIL: delim CRC fail param + * @WMI_VDEV_PPS_GID_NSTS_ZERO: gid nsts zero param + * @WMI_VDEV_PPS_RSSI_CHECK: RSSI check param + * @WMI_VDEV_PPS_5G_EBT: 5G ebt param + */ +typedef enum { + WMI_VDEV_PPS_PAID_MATCH = 0, + WMI_VDEV_PPS_GID_MATCH = 1, + WMI_VDEV_PPS_EARLY_TIM_CLEAR = 2, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR = 3, + WMI_VDEV_PPS_EOF_PAD_DELIM = 4, + WMI_VDEV_PPS_MACADDR_MISMATCH = 5, + WMI_VDEV_PPS_DELIM_CRC_FAIL = 6, + WMI_VDEV_PPS_GID_NSTS_ZERO = 7, + WMI_VDEV_PPS_RSSI_CHECK = 8, + WMI_VDEV_VHT_SET_GID_MGMT = 9, + WMI_VDEV_PPS_5G_EBT = 10 +} packet_power_save; + +/** + * enum green_tx_param - green tx parameters + * @WMI_VDEV_PARAM_GTX_HT_MCS: ht mcs param + * @WMI_VDEV_PARAM_GTX_VHT_MCS: vht mcs param + * @WMI_VDEV_PARAM_GTX_USR_CFG: user cfg param + * @WMI_VDEV_PARAM_GTX_THRE: thre param + * @WMI_VDEV_PARAM_GTX_MARGIN: green tx margin param + * @WMI_VDEV_PARAM_GTX_STEP: green tx step param + * @WMI_VDEV_PARAM_GTX_MINTPC: mintpc param + * @WMI_VDEV_PARAM_GTX_BW_MASK: bandwidth mask + */ +typedef enum { + WMI_VDEV_PARAM_GTX_HT_MCS, + WMI_VDEV_PARAM_GTX_VHT_MCS, + WMI_VDEV_PARAM_GTX_USR_CFG, + WMI_VDEV_PARAM_GTX_THRE, + WMI_VDEV_PARAM_GTX_MARGIN, + WMI_VDEV_PARAM_GTX_STEP, + WMI_VDEV_PARAM_GTX_MINTPC, + WMI_VDEV_PARAM_GTX_BW_MASK, +} green_tx_param; + +#ifdef FEATURE_WLAN_TDLS +/** + * struct wma_tdls_params - TDLS parameters + * @vdev_id: vdev id + * @tdls_state: TDLS state + * @notification_interval_ms: notification inerval + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threashold + * @rssi_teardown_threshold: RSSI teardown threshold + * @rssi_delta: RSSI delta + * @tdls_options: TDLS options + * @peer_traffic_ind_window: raffic indication window + * @peer_traffic_response_timeout: traffic response timeout + * @puapsd_mask: uapsd mask + * @puapsd_inactivity_time: uapsd inactivity time + * @puapsd_rx_frame_threshold: uapsd rx frame threshold + */ +typedef struct wma_tdls_params { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; +} t_wma_tdls_params; + +/** + * struct wma_tdls_peer_event - TDLS peer event + * @vdev_id: vdev id + * @peer_macaddr: peer MAC address + * @peer_status: TDLS peer status + * @peer_reason: TDLS peer reason + */ +typedef struct { + A_UINT32 vdev_id; + wmi_mac_addr peer_macaddr; + A_UINT32 peer_status; + A_UINT32 peer_reason; +} wma_tdls_peer_event; + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct wma_dfs_radar_channel_list - dfs radar channel list + * @nchannels: nuber of channels + * @channels: Channel number including bonded channels on which + * radar is present + */ +struct wma_dfs_radar_channel_list { + A_UINT32 nchannels; + uint8_t channels[WMA_DFS_MAX_20M_SUB_CH]; +}; + +/** + * struct wma_dfs_radar_indication - Structure to indicate RADAR + * @vdev_id: vdev id + * @chan_list: Channel list on which RADAR is detected + * @dfs_radar_status: Flag to Indicate RADAR presence on the current channel + * @use_nol: Flag to indicate use NOL + */ +struct wma_dfs_radar_indication { + A_UINT32 vdev_id; + struct wma_dfs_radar_channel_list chan_list; + uint32_t dfs_radar_status; + int use_nol; +}; + +/** + * enum uapsd_ac - U-APSD Access Categories + * @UAPSD_BE: best effort + * @UAPSD_BK: back ground + * @UAPSD_VI: video + * @UAPSD_VO: voice + */ +enum uapsd_ac { + UAPSD_BE, + UAPSD_BK, + UAPSD_VI, + UAPSD_VO +}; + +CDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac); + +/** + * enum uapsd_up - U-APSD User Priorities + * @UAPSD_UP_BE: best effort + * @UAPSD_UP_BK: back ground + * @UAPSD_UP_RESV: reserve + * @UAPSD_UP_EE: Excellent Effort + * @UAPSD_UP_CL: Critical Applications + * @UAPSD_UP_VI: video + * @UAPSD_UP_VO: voice + * @UAPSD_UP_NC: Network Control + */ +enum uapsd_up { + UAPSD_UP_BE, + UAPSD_UP_BK, + UAPSD_UP_RESV, + UAPSD_UP_EE, + UAPSD_UP_CL, + UAPSD_UP_VI, + UAPSD_UP_VO, + UAPSD_UP_NC, + UAPSD_UP_MAX +}; + +/** + * struct wma_unit_test_cmd - unit test command parameters + * @vdev_id: vdev id + * @module_id: module id + * @num_args: number of arguments + * @args: arguments + */ +typedef struct wma_unit_test_cmd { + uint32_t vdev_id; + WLAN_MODULE_ID module_id; + uint32_t num_args; + uint32_t args[WMA_MAX_NUM_ARGS]; +} t_wma_unit_test_cmd; + +/** + * struct wma_roam_invoke_cmd - roam invoke command + * @vdev_id: vdev id + * @bssid: mac address + * @channel: channel + */ +struct wma_roam_invoke_cmd { + uint32_t vdev_id; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint32_t channel; +}; + +/** + * struct wma_process_fw_event_params - fw event parameters + * @wmi_handle: wmi handle + * @evt_buf: event buffer + */ +typedef struct { + void *wmi_handle; + void *evt_buf; +} wma_process_fw_event_params; + +int wma_process_fw_event_handler(struct wmi_unified *wmi_handle, + wmi_buf_t evt_buf); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +/* + * WMA-DFS Hooks + */ +int ol_if_dfs_attach(struct ieee80211com *ic, void *ptr, void *radar_info); +uint64_t ol_if_get_tsf64(struct ieee80211com *ic); +int ol_if_dfs_disable(struct ieee80211com *ic); +struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *ic, + int freq, uint32_t flags); +int ol_if_dfs_enable(struct ieee80211com *ic, int *is_fastclk, void *pe); +uint32_t ieee80211_ieee2mhz(uint32_t chan, uint32_t flags); +int ol_if_dfs_get_ext_busy(struct ieee80211com *ic); +int ol_if_dfs_get_mib_cycle_counts_pct(struct ieee80211com *ic, + uint32_t *rxc_pcnt, uint32_t *rxf_pcnt, + uint32_t *txf_pcnt); +uint16_t ol_if_dfs_usenol(struct ieee80211com *ic); +void ieee80211_mark_dfs(struct ieee80211com *ic, + struct ieee80211_channel *ichan); +int wma_dfs_indicate_radar(struct ieee80211com *ic, + struct ieee80211_channel *ichan); +uint16_t dfs_usenol(struct ieee80211com *ic); + +CDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params); + +/* added to get average snr for both data and beacon */ +CDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, void *pGetRssiReq); + + +CDF_STATUS wma_update_vdev_tbl(tp_wma_handle wma_handle, uint8_t vdev_id, + ol_txrx_vdev_handle tx_rx_vdev_handle, + uint8_t *mac, uint32_t vdev_type, bool add_del); + +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle); +void wma_log_completion_timeout(void *data); + +CDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req); + +CDF_STATUS wma_send_soc_set_pcl_cmd(tp_wma_handle wma_handle, + struct sir_pcl_list *msg); + +CDF_STATUS wma_send_soc_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct sir_hw_mode *msg); +CDF_STATUS wma_get_scan_id(uint32_t *scan_id); + +CDF_STATUS wma_send_soc_set_dual_mac_config(tp_wma_handle wma_handle, + struct sir_dual_mac_config *msg); +int wma_crash_inject(tp_wma_handle wma_handle, uint32_t type, + uint32_t delay_time_ms); + +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout); +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +CDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +int wmi_desc_pool_init(tp_wma_handle wma_handle, uint32_t pool_size); +void wmi_desc_pool_deinit(tp_wma_handle wma_handle); +struct wmi_desc_t *wmi_desc_get(tp_wma_handle wma_handle); +void wmi_desc_put(tp_wma_handle wma_handle, struct wmi_desc_t *wmi_desc); +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len); +void wma_set_dfs_region(tp_wma_handle wma, uint8_t dfs_region); + +#if defined(FEATURE_LRO) +CDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd); +#else +static inline CDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd) +{ + return CDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h new file mode 100644 index 0000000000..ad78989f38 --- /dev/null +++ b/core/wma/inc/wma_api.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_API_H +#define WMA_API_H + +#include "osdep.h" +#include "cds_mq.h" +#include "ani_global.h" +#include "a_types.h" +#include "wmi_unified.h" +#ifdef NOT_YET +#include "htc_api.h" +#endif +#include "lim_global.h" + +typedef void *WMA_HANDLE; + +/** + * enum GEN_PARAM - general parameters + * @GEN_VDEV_PARAM_AMPDU: Set ampdu size + * @GEN_VDEV_PARAM_AMSDU: Set amsdu size + * @GEN_PARAM_DUMP_AGC_START: dump agc start + * @GEN_PARAM_DUMP_AGC: dump agc + * @GEN_PARAM_DUMP_CHANINFO_START: dump channel info start + * @GEN_PARAM_DUMP_CHANINFO: dump channel info + * @GEN_PARAM_CRASH_INJECT: inject crash + * @GEN_PARAM_DUMP_PCIE_ACCESS_LOG: dump pcie access log + * @GEN_PARAM_TX_CHAIN_MASK_CCK: cck tx chain mask + */ +typedef enum { + GEN_VDEV_PARAM_AMPDU = 0x1, + GEN_VDEV_PARAM_AMSDU, + GEN_PARAM_DUMP_AGC_START, + GEN_PARAM_DUMP_AGC, + GEN_PARAM_DUMP_CHANINFO_START, + GEN_PARAM_DUMP_CHANINFO, + GEN_PARAM_DUMP_WATCHDOG, + GEN_PARAM_CRASH_INJECT, +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + GEN_PARAM_DUMP_PCIE_ACCESS_LOG, +#endif + GEN_PARAM_MODULATED_DTIM, +} GEN_PARAM; + +#define VDEV_CMD 1 +#define PDEV_CMD 2 +#define GEN_CMD 3 +#define DBG_CMD 4 +#define PPS_CMD 5 +#define QPOWER_CMD 6 +#define GTX_CMD 7 + +typedef void (*wma_peer_authorized_fp) (uint32_t vdev_id); + + +CDF_STATUS wma_pre_start(void *cds_context); + +CDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg); + +CDF_STATUS wma_start(void *cds_context); + +CDF_STATUS wma_stop(void *cds_context, uint8_t reason); + +CDF_STATUS wma_close(void *cds_context); + +CDF_STATUS wma_wmi_service_close(void *cds_context); + +void wma_rx_ready_event(WMA_HANDLE handle, void *ev); + +void wma_rx_service_ready_event(WMA_HANDLE handle, void *ev); + +void wma_rx_service_ready_ext_event(WMA_HANDLE handle, void *ev); + +void wma_setneedshutdown(void *cds_context); + +bool wma_needshutdown(void *cds_context); + +CDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle); + +uint8_t wma_map_channel(uint8_t mapChannel); + +int wma_cli_get_command(int vdev_id, int param_id, int vpdev); +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev); + +CDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value); +CDF_STATUS wma_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId); + +CDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx, + uint8_t *pVersion, + uint32_t versionBufferSize); +int wma_bus_suspend(void); +int wma_suspend_target(WMA_HANDLE handle, int disable_target_intr); +void wma_target_suspend_acknowledge(void *context); +int wma_bus_resume(void); +int wma_resume_target(WMA_HANDLE handle); +CDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle); +CDF_STATUS wma_disable_d0wow_in_fw(WMA_HANDLE handle); +int wma_is_wow_mode_selected(WMA_HANDLE handle); +CDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle); +CDF_STATUS wma_enable_d0wow_in_fw(WMA_HANDLE handle); +bool wma_check_scan_in_progress(WMA_HANDLE handle); +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb); +int wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, uint32_t param_id, + uint32_t param_value, uint32_t vdev_id); +#ifdef NOT_YET +CDF_STATUS wma_update_channel_list(WMA_HANDLE handle, void *scan_chan_info); +#endif + +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id); +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id); +bool wma_is_vdev_up(uint8_t vdev_id); + +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size); + +uint8_t wma_get_fw_wlan_feat_caps(uint8_t featEnumValue); +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +void wma_enable_disable_wakeup_event(WMA_HANDLE handle, + uint32_t vdev_id, + uint32_t bitmap, + bool enable); +void wma_register_wow_wakeup_events(WMA_HANDLE handle, uint8_t vdev_id, + uint8_t vdev_type, uint8_t sub_type); +void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id); +int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs); +CDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx, + struct sir_hw_mode_params *hw_mode); +int8_t wma_get_num_dbs_hw_modes(void); +bool wma_is_hw_dbs_capable(void); +bool wma_is_hw_agile_dfs_capable(void); +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id); +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index); +CDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index); +void wma_set_dbs_capability_ut(uint32_t dbs); +CDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs); +CDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode); +bool wma_is_dbs_enable(void); +bool wma_is_agile_dfs_enable(void); +CDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs); +CDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs); +bool wma_get_dbs_scan_config(void); +bool wma_get_dbs_plus_agile_scan_config(void); +bool wma_get_single_mac_scan_with_dfs_config(void); +bool wma_get_dbs_config(void); +bool wma_get_agile_dfs_config(void); +bool wma_is_dual_mac_disabled_in_ini(void); +bool wma_get_prev_dbs_config(void); +bool wma_get_prev_agile_dfs_config(void); +bool wma_get_prev_dbs_scan_config(void); +bool wma_get_prev_dbs_plus_agile_scan_config(void); +bool wma_get_prev_single_mac_scan_with_dfs_config(void); + +#define LRO_IPV4_SEED_ARR_SZ 5 +#define LRO_IPV6_SEED_ARR_SZ 11 + +/** + * struct wma_lro_init_cmd_t - set LRO init parameters + * @lro_enable: indicates whether lro is enabled + * @tcp_flag: If the TCP flags from the packet do not match + * the values in this field after masking with TCP flags mask + * below, packet is not LRO eligible + * @tcp_flag_mask: field for comparing the TCP values provided + * above with the TCP flags field in the received packet + * @toeplitz_hash_ipv4: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv4 packets + * @toeplitz_hash_ipv6: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv6 packets + */ +struct wma_lro_config_cmd_t { + uint32_t lro_enable; + uint32_t tcp_flag:9, + tcp_flag_mask:9; + uint32_t toeplitz_hash_ipv4[LRO_IPV4_SEED_ARR_SZ]; + uint32_t toeplitz_hash_ipv6[LRO_IPV6_SEED_ARR_SZ]; +}; + +#if defined(FEATURE_LRO) +int wma_lro_init(struct wma_lro_config_cmd_t *lro_config); +#endif +bool wma_is_scan_simultaneous_capable(void); +#endif diff --git a/core/wma/inc/wma_dfs_interface.h b/core/wma/inc/wma_dfs_interface.h new file mode 100644 index 0000000000..4bfc3fccad --- /dev/null +++ b/core/wma/inc/wma_dfs_interface.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ath_dfs_structs.h" +#include +#include "cds_ieee80211_common.h" + +#define IEEE80211_CHAN_MAX 255 + +/* channel attributes */ + +/* Turbo channel */ +#define IEEE80211_CHAN_TURBO 0x00000010 +/* CCK channel */ +#define IEEE80211_CHAN_CCK 0x00000020 +/* OFDM channel */ +#define IEEE80211_CHAN_OFDM 0x00000040 +/* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_2GHZ 0x00000080 +/* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_5GHZ 0x00000100 +/* Only passive scan allowed */ +#define IEEE80211_CHAN_PASSIVE 0x00000200 +/* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_DYN 0x00000400 +/* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_GFSK 0x00000800 +/* Radar found on channel */ +#define IEEE80211_CHAN_RADAR 0x00001000 +/* 11a static turbo channel only */ +#define IEEE80211_CHAN_STURBO 0x00002000 +/* Half rate channel */ +#define IEEE80211_CHAN_HALF 0x00004000 +/* Quarter rate channel */ +#define IEEE80211_CHAN_QUARTER 0x00008000 +/* HT 20 channel */ +#define IEEE80211_CHAN_HT20 0x00010000 +/* HT 40 with extension channel above */ +#define IEEE80211_CHAN_HT40PLUS 0x00020000 +/* HT 40 with extension channel below */ +#define IEEE80211_CHAN_HT40MINUS 0x00040000 +/* HT 40 Intolerant */ +#define IEEE80211_CHAN_HT40INTOL 0x00080000 +/* VHT 20 channel */ +#define IEEE80211_CHAN_VHT20 0x00100000 +/* VHT 40 with extension channel above */ +#define IEEE80211_CHAN_VHT40PLUS 0x00200000 +/* VHT 40 with extension channel below */ +#define IEEE80211_CHAN_VHT40MINUS 0x00400000 +/* VHT 80 channel */ +#define IEEE80211_CHAN_VHT80 0x00800000 + +/* token for ``any channel'' */ +#define IEEE80211_CHAN_ANY (-1) +#define IEEE80211_CHAN_ANYC \ + ((struct ieee80211_channel *) IEEE80211_CHAN_ANY) + +#define IEEE80211_IS_CHAN_11N_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) != 0) +#define IEEE80211_IS_CHAN_11N_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) != 0) +#define IEEE80211_CHAN_11AC_VHT80 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT80) + +#define IEEE80211_IS_CHAN_11AC_VHT80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80) == \ + IEEE80211_CHAN_11AC_VHT80) +#define CHANNEL_108G \ + (IEEE80211_CHAN_2GHZ|IEEE80211_CHAN_OFDM|IEEE80211_CHAN_TURBO) + +/* + * Software use: channel interference + * used for as AR as well as RADAR + * interference detection + */ +#define CHANNEL_INTERFERENCE 0x01 +/* In case of VHT160, we can have 8 20Mhz channels */ +#define IEE80211_MAX_20M_SUB_CH 8 + +/** + * struct ieee80211_channel - channel info + * @ic_freq: frequency in MHz + * @ic_flags: channel flags + * @ic_flagext: flags extension + * @ic_ieee: IEEE channel number + * @ic_maxregpower: max regulatory power in dbm + * @ic_maxpower: max tx power in dbm + * @ic_minpower: min tx power in dbm + * @ic_regClassId: reg class id of this channel + * @ic_antennamax: max antenna gain from regulatory + * @ic_vhtop_ch_freq_seg1: channel center frequency + * @ic_vhtop_ch_freq_seg2: Channel Center frequency applicable + * @ic_pri_freq_center_freq_mhz_separation: separation b/w pri and center freq + */ +struct ieee80211_channel { + uint32_t ic_freq; + uint32_t ic_flags; + uint8_t ic_flagext; + uint8_t ic_ieee; + int8_t ic_maxregpower; + int8_t ic_maxpower; + int8_t ic_minpower; + uint8_t ic_regClassId; + uint8_t ic_antennamax; + uint32_t ic_vhtop_ch_freq_seg1; + uint32_t ic_vhtop_ch_freq_seg2; + int ic_pri_freq_center_freq_mhz_separation; +}; + +/** + * struct ieee80211_channel_list - channel list + * @cl_nchans: number of channels + * @cl_channels: channel info + */ +struct ieee80211_channel_list { + int cl_nchans; + struct ieee80211_channel *cl_channels[IEE80211_MAX_20M_SUB_CH]; +}; + +/** + * struct ieee80211_dfs_state - dfs state + * @nol_event: nol event list + * @nol_timer: nol list processing + * @cac_timer: cac timer + * @cureps: current events/second + * @lastchan: chan w/ last radar event + * @newchan: chan selected next + * @cac_timeout_override: overridden cac timeout + * @flags: dfs flags + */ +struct ieee80211_dfs_state { + int nol_event[IEEE80211_CHAN_MAX]; + os_timer_t nol_timer; + os_timer_t cac_timer; + int cureps; + const struct ieee80211_channel *lastchan; + struct ieee80211_channel *newchan; + int cac_timeout_override; + uint8_t enable : 1, cac_timer_running : 1, ignore_dfs : 1, ignore_cac : 1; +}; + +/** + * struct ieee80211com - per device structure + * @ic_opmode: operation mode + * @ic_channels: ieee80211 channel list + * @ic_nchans: number of channels + * @ic_curchan: current channel + * @ic_isdfsregdomain: is opearting in dfs region + * @current_dfs_regdomain: current dfs regulatory domain + * @vdev_id: vdev id + * @last_radar_found_chan: last radar found channel + * @dfs_pri_multiplier: dfs multiplier + */ +typedef struct ieee80211com { + void (*ic_start_csa)(struct ieee80211com *ic, uint8_t ieeeChan); + void (*ic_get_ext_chan_info)(struct ieee80211com *ic, + struct ieee80211_channel_list *chan); + enum ieee80211_opmode ic_opmode; + struct ieee80211_channel *(*ic_find_channel)(struct ieee80211com *ic, + int freq, uint32_t flags); + uint64_t (*ic_get_TSF64)(struct ieee80211com *ic); + unsigned int (*ic_ieee2mhz)(u_int chan, u_int flags); + struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX + 1]; + int ic_nchans; + struct ieee80211_channel *ic_curchan; + uint8_t ic_isdfsregdomain; + int (*ic_get_dfsdomain)(struct ieee80211com *); + uint16_t (*ic_dfs_usenol)(struct ieee80211com *ic); + uint16_t (*ic_dfs_isdfsregdomain)(struct ieee80211com *ic); + int (*ic_dfs_attached)(struct ieee80211com *ic); + void *ic_dfs; + struct ieee80211_dfs_state ic_dfs_state; + int (*ic_dfs_attach)(struct ieee80211com *ic, + void *pCap, void *radar_info); + int (*ic_dfs_detach)(struct ieee80211com *ic); + int (*ic_dfs_enable)(struct ieee80211com *ic, int *is_fastclk, + void *); + int (*ic_dfs_disable)(struct ieee80211com *ic); + int (*ic_get_ext_busy)(struct ieee80211com *ic); + int (*ic_get_mib_cycle_counts_pct)(struct ieee80211com *ic, + uint32_t *rxc_pcnt, + uint32_t *rxf_pcnt, + uint32_t *txf_pcnt); + int (*ic_dfs_get_thresholds)(struct ieee80211com *ic, void *pe); + + int (*ic_dfs_debug)(struct ieee80211com *ic, int type, void *data); + /* + * Update the channel list with the current set of DFS + * NOL entries. + * + * + 'cmd' indicates what to do; for now it should just + * be DFS_NOL_CLIST_CMD_UPDATE which will update all + * channels, given the _entire_ NOL. (Rather than + * the earlier behaviour with clist_update, which + * was to either add or remove a set of channel + * entries.) + */ + void (*ic_dfs_clist_update)(struct ieee80211com *ic, int cmd, + struct dfs_nol_chan_entry *, int nentries); + void (*ic_dfs_notify_radar)(struct ieee80211com *ic, + struct ieee80211_channel *chan); + void (*ic_dfs_unmark_radar)(struct ieee80211com *ic, + struct ieee80211_channel *chan); + int (*ic_dfs_control)(struct ieee80211com *ic, + u_int id, void *indata, uint32_t insize, + void *outdata, uint32_t *outsize); + HAL_DFS_DOMAIN current_dfs_regdomain; + uint8_t vdev_id; + uint8_t last_radar_found_chan; + int32_t dfs_pri_multiplier; + cdf_mutex_t chan_lock; +} IEEE80211COM, *PIEEE80211COM; + +/** + * ieee80211_chan2freq() - Convert channel to frequency value. + * @ic: ieee80211com ptr + * @c: ieee80211 channel + * + * Return: freqency in MHz + */ +static INLINE u_int +ieee80211_chan2freq(struct ieee80211com *ic, const struct ieee80211_channel *c) +{ + if (c == NULL) { + return 0; + } + return (c == IEEE80211_CHAN_ANYC ? IEEE80211_CHAN_ANY : c->ic_freq); +} diff --git a/core/wma/inc/wma_if.h b/core/wma/inc/wma_if.h new file mode 100644 index 0000000000..75c50f84ee --- /dev/null +++ b/core/wma/inc/wma_if.h @@ -0,0 +1,1429 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HALMSGAPI_H_ +#define _HALMSGAPI_H_ + +#include "cdf_types.h" +#include "sir_api.h" +#include "sir_params.h" + + +/* + * Validate the OS Type being built + */ + +#if defined(ANI_OS_TYPE_ANDROID) /* ANDROID */ + +#if defined(ANI_OS_TYPE_QNX) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif defined (ANI_OS_TYPE_QNX) /* QNX */ + +#if defined(ANI_OS_TYPE_ANDROID) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif !defined(ANI_OS_TYPE_ANDROID) && !defined(ANI_OS_TYPE_QNX) /* NONE */ +#error "NONE of the ANI_OS_TYPE_xxx are defined for this build" +#endif + +/* + * Validate the compiler + */ +#if (defined (ANI_COMPILER_TYPE_MSVC) && defined (ANI_COMPILER_TYPE_GCC) && defined (ANI_COMPILER_TYPE_RVCT)) +#error "more than one ANI_COMPILER_TYPE_xxx is defined for this build" + +#elif !(defined (ANI_COMPILER_TYPE_MSVC) || defined (ANI_COMPILER_TYPE_GCC) || defined (ANI_COMPILER_TYPE_RVCT)) +#error "NONE of the ANI_COMPILER_TYPE_xxx are defined for this build" + +#endif + + +#define WMA_CONFIG_PARAM_UPDATE_REQ SIR_CFG_PARAM_UPDATE_IND + +#define HAL_NUM_BSSID 2 +/* operMode in ADD BSS message */ +#define BSS_OPERATIONAL_MODE_AP 0 +#define BSS_OPERATIONAL_MODE_STA 1 +#define BSS_OPERATIONAL_MODE_IBSS 2 + +/* STA entry type in add sta message */ +#define STA_ENTRY_SELF 0 +#define STA_ENTRY_OTHER 1 +#define STA_ENTRY_BSSID 2 +/* Special station id for transmitting broadcast frames. */ +#define STA_ENTRY_BCAST 3 +#define STA_ENTRY_PEER STA_ENTRY_OTHER +#ifdef FEATURE_WLAN_TDLS +#define STA_ENTRY_TDLS_PEER 4 +#endif /* FEATURE_WLAN_TDLS */ + +#define STA_INVALID_IDX 0xFF + +/* invalid channel id. */ +#define INVALID_CHANNEL_ID 0 + +/* + * From NOVA Mac Arch document + * Encryp. mode The encryption mode + * 000: Encryption functionality is not enabled + * 001: Encryption is set to WEP + * 010: Encryption is set to WEP 104 + * 011: Encryption is set to TKIP + * 100: Encryption is set to AES + * 101 - 111: Reserved for future + */ +#define ENC_POLICY_NULL 0 +#define ENC_POLICY_WEP40 1 +#define ENC_POLICY_WEP104 2 +#define ENC_POLICY_TKIP 3 +#define ENC_POLICY_AES_CCM 4 + +/* Max number of bytes required for stations bitmap aligned at 4 bytes boundary + */ +#define HALMSG_NUMBYTES_STATION_BITMAP(x) (((x / 32) + ((x % 32) ? 1 : 0)) * 4) + + +#define HAL_MAX_SUPP_CHANNELS 128 +#define HAL_MAX_SUPP_OPER_CLASSES 32 + +/** + * enum eFrameType - frame types + * @TXRX_FRM_RAW: raw frame + * @TXRX_FRM_ETH2: ethernet frame + * @TXRX_FRM_802_3: 802.3 frame + * @TXRX_FRM_802_11_MGMT: 802.11 mgmt frame + * @TXRX_FRM_802_11_CTRL: 802.11 control frame + * @TXRX_FRM_802_11_DATA: 802.11 data frame + */ +typedef enum { + TXRX_FRM_RAW, + TXRX_FRM_ETH2, + TXRX_FRM_802_3, + TXRX_FRM_802_11_MGMT, + TXRX_FRM_802_11_CTRL, + TXRX_FRM_802_11_DATA, + TXRX_FRM_IGNORED, /* This frame will be dropped */ + TXRX_FRM_MAX +} eFrameType; + +/** + * enum eFrameTxDir - frame tx direction + * @ANI_TXDIR_IBSS: IBSS frame + * @ANI_TXDIR_TODS: frame to DS + * @ANI_TXDIR_FROMDS: Frame from DS + * @ANI_TXDIR_WDS: WDS frame + */ +typedef enum { + ANI_TXDIR_IBSS = 0, + ANI_TXDIR_TODS, + ANI_TXDIR_FROMDS, + ANI_TXDIR_WDS +} eFrameTxDir; + +/** + *struct sAniBeaconStruct - Beacon structure + * @beaconLength: beacon length + * @macHdr: mac header for beacon + */ +typedef struct sAniBeaconStruct { + uint32_t beaconLength; + tSirMacMgmtHdr macHdr; +} cdf_packed tAniBeaconStruct, *tpAniBeaconStruct; + +/** + * struct sAniProbeRspStruct - probeRsp template structure + * @macHdr: mac header for probe response + */ +typedef struct sAniProbeRspStruct { + tSirMacMgmtHdr macHdr; + /* probeRsp body follows here */ +} cdf_packed tAniProbeRspStruct, *tpAniProbeRspStruct; + +/** + * struct tAddStaParams - add sta related parameters + * @bssId: bssid of sta + * @assocId: associd + * @staType: 0 - Self, 1 other/remote, 2 - bssid + * @staMac: MAC Address of STA + * @shortPreambleSupported: is short preamble supported or not + * @listenInterval: Listen interval + * @wmmEnabled: Support for 11e/WMM + * @uAPSD: U-APSD Flags: 1b per AC + * @maxSPLen: Max SP Length + * @htCapable: 11n HT capable STA + * @greenFieldCapable: 11n Green Field preamble support + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @mimoPS: MIMO Power Save + * @rifsMode: RIFS mode: 0 - NA, 1 - Allowed + * @lsigTxopProtection: L-SIG TXOP Protection mechanism + * @us32MaxAmpduDuration: in units of 32 us + * @maxAmpduSize: 0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k + * @maxAmpduDensity: 3 : 0~7 : 2^(11nAMPDUdensity -4) + * @maxAmsduSize: 1 : 3839 bytes, 0 : 7935 bytes + * @fDsssCckMode40Mhz: DSSS CCK supported 40MHz + * @fShortGI40Mhz: short GI support for 40Mhz packets + * @fShortGI20Mhz: short GI support for 20Mhz packets + * @supportedRates: legacy supported rates + * @status: CDF status + * @staIdx: station index + * @bssIdx: BSSID of BSS to which the station is associated + * @updateSta: pdate the existing STA entry, if this flag is set + * @respReqd: A flag to indicate to HAL if the response message is required + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @encryptType: The unicast encryption type in the association + * @ucUcastSig: Unicast DPU index + * @ucBcastSig: Broadcast DPU index + * @sessionId: PE session id + * @p2pCapableSta: if this is a P2P Capable Sta + * @csaOffloadEnable: CSA offload enable flag + * @vhtCapable: is VHT capabale or not + * @vhtTxChannelWidthSet: VHT channel width + * @vhtSupportedRxNss: VHT supported RX NSS + * @vhtTxBFCapable: txbf capable or not + * @vhtTxMUBformeeCapable: Bformee capable or not + * @enableVhtpAid: enable VHT AID + * @enableVhtGid: enable VHT GID + * @enableAmpduPs: AMPDU power save + * @enableHtSmps: enable HT SMPS + * @htSmpsconfig: HT SMPS config + * @htLdpcCapable: HT LDPC capable + * @vhtLdpcCapable: VHT LDPC capable + * @smesessionId: sme session id + * @wpa_rsn: RSN capable + * @capab_info: capabality info + * @ht_caps: HT capabalities + * @vht_caps: VHT vapabalities + * @nwType: NW Type + * @maxTxPower: max tx power + * @atimIePresent: Peer Atim Info + * @peerAtimWindowLength: peer ATIM Window length + * + * This structure contains parameter required for + * add sta request of upper layer. + */ +typedef struct { + tSirMacAddr bssId; + uint16_t assocId; + /* Field to indicate if this is sta entry for itself STA adding entry + * for itself or remote (AP adding STA after successful association. + * This may or may not be required in production driver. + */ + uint8_t staType; + uint8_t shortPreambleSupported; + tSirMacAddr staMac; + uint16_t listenInterval; + uint8_t wmmEnabled; + uint8_t uAPSD; + uint8_t maxSPLen; + uint8_t htCapable; + /* 11n Green Field preamble support + * 0 - Not supported, 1 - Supported + * Add it to RA related fields of sta entry in HAL + */ + uint8_t greenFieldCapable; + uint8_t ch_width; + + tSirMacHTMIMOPowerSaveState mimoPS; + uint8_t rifsMode; + /* L-SIG TXOP Protection mechanism + * 0 - No Support, 1 - Supported + * SG - there is global field. + */ + uint8_t lsigTxopProtection; + uint8_t us32MaxAmpduDuration; + uint8_t maxAmpduSize; + uint8_t maxAmpduDensity; + uint8_t maxAmsduSize; + + /* 11n Parameters */ + /* HT STA should set it to 1 if it is enabled in BSS + * HT STA should set it to 0 if AP does not support it. + * This indication is sent to HAL and HAL uses this flag + * to pickup up appropriate 40Mhz rates. + */ + uint8_t fDsssCckMode40Mhz; + uint8_t fShortGI40Mhz; + uint8_t fShortGI20Mhz; + tSirSupportedRates supportedRates; + /* + * Following parameters are for returning status and station index from + * HAL to PE via response message. HAL does not read them. + */ + /* The return status of SIR_HAL_ADD_STA_REQ is reported here */ + CDF_STATUS status; + /* Station index; valid only when 'status' field value is + * CDF_STATUS_SUCCESS + */ + uint8_t staIdx; + /* BSSID of BSS to which the station is associated. + * This should be filled back in by HAL, and sent back to LIM as part of + * the response message, so LIM can cache it in the station entry of + * hash table. When station is deleted, LIM will make use of this bssIdx + * to delete BSS from hal tables and from softmac. + */ + uint8_t bssIdx; + uint8_t updateSta; + uint8_t respReqd; + uint8_t rmfEnabled; + uint32_t encryptType; + uint8_t ucUcastSig; + uint8_t ucBcastSig; + uint8_t sessionId; + uint8_t p2pCapableSta; + uint8_t csaOffloadEnable; + uint8_t vhtCapable; + uint8_t vhtSupportedRxNss; + uint8_t vhtTxBFCapable; + uint8_t enable_su_tx_bformer; + uint8_t vhtTxMUBformeeCapable; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsconfig; + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; + uint8_t smesessionId; + uint8_t wpa_rsn; + uint16_t capab_info; + uint16_t ht_caps; + uint32_t vht_caps; + tSirNwType nwType; + tPowerdBm maxTxPower; + uint8_t atimIePresent; + uint32_t peerAtimWindowLength; + uint8_t nonRoamReassoc; +} tAddStaParams, *tpAddStaParams; + +/** + * struct tDeleteStaParams - parameters required for del sta request + * @staIdx: station index + * @assocId: association index + * @status: status + * @respReqd: is response required + * @sessionId: PE session id + * @smesessionId: SME session id + * @staType: station type + * @staMac: station mac + */ +typedef struct { + uint16_t staIdx; + uint16_t assocId; + CDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + uint8_t smesessionId; + uint8_t staType; + tSirMacAddr staMac; +} tDeleteStaParams, *tpDeleteStaParams; + +/** + * struct tSetStaKeyParams - set key params + * @staIdx: station id + * @encType: encryption type + * @wepType: WEP type + * @defWEPIdx: Default WEP key, valid only for static WEP, must between 0 and 3 + * @key: valid only for non-static WEP encyrptions + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @peerMacAddr: peer mac address + * @status: status + * @sessionId: session id + * @sendRsp: send response + * + * This is used by PE to configure the key information on a given station. + * When the secType is WEP40 or WEP104, the defWEPIdx is used to locate + * a preconfigured key from a BSS the station assoicated with; otherwise + * a new key descriptor is created based on the key field. + */ +typedef struct { + uint16_t staIdx; + tAniEdType encType; + tAniWepType wepType; + uint8_t defWEPIdx; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + tSirMacAddr peerMacAddr; + CDF_STATUS status; + uint8_t sessionId; + uint8_t sendRsp; +} tSetStaKeyParams, *tpSetStaKeyParams; + +/** + * struct sLimMlmSetKeysReq - set key request parameters + * @peerMacAddr: peer mac address + * @sessionId: PE session id + * @smesessionId: SME session id + * @aid: association id + * @edType: Encryption/Decryption type + * @numKeys: number of keys + * @key: key data + */ +typedef struct sLimMlmSetKeysReq { + tSirMacAddr peerMacAddr; + uint8_t sessionId; /* Added For BT-AMP Support */ + uint8_t smesessionId; /* Added for drivers based on wmi interface */ + uint16_t aid; + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; +} tLimMlmSetKeysReq, *tpLimMlmSetKeysReq; + +/** + * struct tAddBssParams - parameters required for add bss params + * @bssId: MAC Address/BSSID + * @selfMacAddr: Self Mac Address + * @bssType: BSS type + * @operMode: AP - 0; STA - 1; + * @nwType: network type + * @shortSlotTimeSupported: is short slot time supported or not + * @llaCoexist: is 11a coexist or not + * @llbCoexist: 11b coexist supported or not + * @llgCoexist: 11g coexist supported or not + * @ht20Coexist: HT20 coexist supported or not + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS is supported or not + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @cfParamSet: CF Param Set + * @rateSet: MAC Rate Set + * @htCapable: Enable/Disable HT capabilities + * @obssProtEnabled: Enable/Disable OBSS protection + * @rmfEnabled: RMF enabled/disabled + * @htOperMode: HT Operating Mode + * @HT Operating Mode: Dual CTS Protection: 0 - Unused, 1 - Used + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @currentOperChannel: Current Operating Channel + * @currentExtChannel: Current Extension Channel, if applicable + * @staContext: sta context + * @status: status + * @bssIdx: BSS index allocated by HAL + * @updateBss: update the existing BSS entry, if this flag is set + * @ssId: Add BSSID info for rxp filter + * @respReqd: send the response message to LIM only when this flag is set + * @sessionId: PE session id + * @txMgmtPower: tx power used for mgmt frames + * @maxTxPower: max power to be used after applying the power constraint + * @extSetStaKeyParamValid: Ext Bss Config Msg if set + * @extSetStaKeyParam: SetStaKeyParams for ext bss msg + * @ucMaxProbeRespRetryLimit: probe Response Max retries + * @bHiddenSSIDEn: To Enable Hidden ssid. + * @bProxyProbeRespEn: To Enable Disable FW Proxy Probe Resp + * @halPersona: Persona for the BSS can be STA,AP,GO,CLIENT value + * @bSpectrumMgtEnabled: Spectrum Management Capability, 1:Enabled, 0:Disabled. + * @vhtCapable: VHT capablity + * @vhtTxChannelWidthSet: VHT tx channel width + * @reassocReq: Set only during roaming reassociation + * @chainMask: chain mask + * @smpsMode: SMPS mode + * @dot11_mode: 802.11 mode + */ +typedef struct { + tSirMacAddr bssId; +#ifdef HAL_SELF_STA_PER_BSS + tSirMacAddr selfMacAddr; +#endif /* HAL_SELF_STA_PER_BSS */ + tSirBssType bssType; + uint8_t operMode; + tSirNwType nwType; + uint8_t shortSlotTimeSupported; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + tSirMacBeaconInterval beaconInterval; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacRateSet rateSet; + uint8_t htCapable; + uint8_t obssProtEnabled; + uint8_t rmfEnabled; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t currentOperChannel; + tAddStaParams staContext; + CDF_STATUS status; + uint16_t bssIdx; + /* HAL should update the existing BSS entry, if this flag is set. + * PE will set this flag in case of reassoc, where we want to resue the + * the old bssID and still return success. + */ + uint8_t updateBss; + tSirMacSSid ssId; + uint8_t respReqd; + uint8_t sessionId; +#if defined WLAN_FEATURE_VOWIFI + tPowerdBm txMgmtPower; + tPowerdBm maxTxPower; +#endif /* WLAN_FEATURE_VOWIFI */ + +#if defined WLAN_FEATURE_VOWIFI_11R + uint8_t extSetStaKeyParamValid; + tSetStaKeyParams extSetStaKeyParam; +#endif /* WLAN_FEATURE_VOWIFI_11R */ + + uint8_t ucMaxProbeRespRetryLimit; + uint8_t bHiddenSSIDEn; + uint8_t bProxyProbeRespEn; + uint8_t halPersona; + uint8_t bSpectrumMgtEnabled; + uint8_t vhtCapable; + phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t reassocReq; /* Set only during roaming reassociation */ + uint16_t chainMask; + uint16_t smpsMode; + uint8_t dot11_mode; + uint8_t nonRoamReassoc; + uint8_t wps_state; + uint8_t nss; +} tAddBssParams, *tpAddBssParams; + +/** + * struct tDeleteBssParams - params required for del bss request + * @bssIdx: BSSID + * @status: CDF status + * @respReqd: response message to LIM only when this flag is set + * @sessionId: PE session id + * @bssid: BSSID mac address + * @smesessionId: sme session id + */ +typedef struct { + uint8_t bssIdx; + CDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + tSirMacAddr bssid; + uint8_t smesessionId; +} tDeleteBssParams, *tpDeleteBssParams; + +/** + * struct sSirScanEntry - scan entry + * @bssIdx: BSSID + * @activeBSScnt: active BSS count + */ +typedef struct sSirScanEntry { + uint8_t bssIdx[HAL_NUM_BSSID]; + uint8_t activeBSScnt; +} tSirScanEntry, *ptSirScanEntry; + +/** + * struct tInitScanParams - params required for init scan request + * @bssid: BSSID + * @notifyBss: notify BSS + * @useNoA: use NOA + * @notifyHost: notify UMAC if set + * @frameLength: frame length + * @frameType: frame type + * @scanDuration: Indicates the scan duration (in ms) + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @checkLinkTraffic: when this flag is set, HAL should check for + * link traffic prior to scan + * @status: status + */ +typedef struct { + tSirMacAddr bssid; + uint8_t notifyBss; + uint8_t useNoA; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + uint16_t scanDuration; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + tSirLinkTrafficCheck checkLinkTraffic; + CDF_STATUS status; +} tInitScanParams, *tpInitScanParams; + +typedef enum eDelStaReasonCode { + HAL_DEL_STA_REASON_CODE_KEEP_ALIVE = 0x1, + HAL_DEL_STA_REASON_CODE_TIM_BASED = 0x2, + HAL_DEL_STA_REASON_CODE_RA_BASED = 0x3, + HAL_DEL_STA_REASON_CODE_UNKNOWN_A2 = 0x4 +} tDelStaReasonCode; + +typedef enum eSmpsModeValue { + STATIC_SMPS_MODE = 0x0, + DYNAMIC_SMPS_MODE = 0x1, + SMPS_MODE_RESERVED = 0x2, + SMPS_MODE_DISABLED = 0x3 +} tSmpsModeValue; + +/** + * struct tDeleteStaContext - params required for delete sta request + * @assocId: association id + * @staId: station id + * @bssId: mac address + * @addr2: mac address + * @reasonCode: reason code + */ +typedef struct { + uint16_t assocId; + uint16_t staId; + tSirMacAddr bssId; + tSirMacAddr addr2; + uint16_t reasonCode; +} tDeleteStaContext, *tpDeleteStaContext; + +/** + * struct tStartScanParams - params required for start scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + * @startTSF: TSF value + * @txMgmtPower: TX mgmt power + */ +typedef struct { + uint8_t scanChannel; + CDF_STATUS status; +#if defined WLAN_FEATURE_VOWIFI + uint32_t startTSF[2]; + tPowerdBm txMgmtPower; +#endif /* WLAN_FEATURE_VOWIFI */ +} tStartScanParams, *tpStartScanParams; + +/** + * struct tEndScanParams - params required for end scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + */ +typedef struct { + uint8_t scanChannel; + CDF_STATUS status; +} tEndScanParams, *tpEndScanParams; + +/** + * struct tFinishScanParams - params required for finish scan request + * @bssid: BSSID + * @currentOperChannel: Current operating channel + * @cbState: channel bond state + * @notifyBss: notify BSS flag + * @notifyHost: notify host flag + * @frameLength: frame length + * @frameType: frame type + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @status: return status + * Request Type = SIR_HAL_FINISH_SCAN_REQ + */ +typedef struct { + tSirMacAddr bssid; + uint8_t currentOperChannel; + /* If 20/40 MHz is operational, this will indicate the 40 MHz extension + * channel in combination with the control channel + */ + ePhyChanBondState cbState; + /* For an STA, indicates if a Data NULL frame needs to be sent + * to the AP with FrameControl.PwrMgmt bit set to 0 + */ + uint8_t notifyBss; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + CDF_STATUS status; +} tFinishScanParams, *tpFinishScanParams; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 280 +#endif +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +/** + * struct tStartOemDataReq - start OEM Data request + * @selfMacAddr: self mac address + * @status: return status + * @oemDataReq: OEM Data request + */ +typedef struct { + tSirMacAddr selfMacAddr; + CDF_STATUS status; + uint8_t oemDataReq[OEM_DATA_REQ_SIZE]; +} tStartOemDataReq, *tpStartOemDataReq; + +/** + * struct tStartOemDataRsp - start OEM Data response + * @oemDataRsp: OEM Data response + */ +typedef struct { + uint8_t oemDataRsp[OEM_DATA_RSP_SIZE]; +} tStartOemDataRsp, *tpStartOemDataRsp; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/** + * struct tBeaconGenParams - params required for beacon gen request + * @bssIdx: Identifies the BSSID for which it is time to generate a beacon + * @bssId: BSSID + * @numOfSta: Number of stations in power save, who have data pending + * @numOfStaWithoutData: Number of stations in power save, + * who don't have any data pending + * @fBroadcastTrafficPending: broadcast traffic pending flag + * @dtimCount: DTIM count + * @rsvd: reserved(padding) + */ +typedef struct sBeaconGenParams { + uint8_t bssIdx; + tSirMacAddr bssId; +#ifdef FIXME_VOLANS + uint8_t numOfSta; + uint8_t numOfStaWithoutData; + uint8_t fBroadcastTrafficPending; + uint8_t dtimCount; +#endif /* FIXME_VOLANS */ + uint8_t rsvd[3]; +} tBeaconGenParams, *tpBeaconGenParams; + +/** + * struct tSendbeaconParams - send beacon parameters + * @bssId: BSSID mac address + * @beacon: beacon data + * @beaconLength: beacon length of template + * @timIeOffset: TIM IE offset + * @p2pIeOffset: P2P IE offset + */ +typedef struct { + tSirMacAddr bssId; + uint8_t *beacon; + uint32_t beaconLength; + uint32_t timIeOffset; + uint16_t p2pIeOffset; +} tSendbeaconParams, *tpSendbeaconParams; + +/** + * struct tSendProbeRespParams - send probe response parameters + * @bssId: BSSID + * @pProbeRespTemplate: probe response template + * @probeRespTemplateLen: probe response template length + * @ucProxyProbeReqValidIEBmap: valid IE bitmap + */ +typedef struct sSendProbeRespParams { + tSirMacAddr bssId; + uint8_t *pProbeRespTemplate; + uint32_t probeRespTemplateLen; + uint32_t ucProxyProbeReqValidIEBmap[8]; +} tSendProbeRespParams, *tpSendProbeRespParams; + +/** + * struct tSetBssKeyParams - BSS key parameters + * @bssIdx: BSSID index + * @encType: encryption Type + * @numKeys: number of keys + * @key: key data + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @status: return status of command + * @sessionId: PE session id + */ +typedef struct { + uint8_t bssIdx; + tAniEdType encType; + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + CDF_STATUS status; + uint8_t sessionId; +} tSetBssKeyParams, *tpSetBssKeyParams; + +/** + * struct tUpdateBeaconParams - update beacon request parameters + * @bssIdx: BSSID index + * @fShortPreamble: shortPreamble mode + * @fShortSlotTime: short Slot time + * @beaconInterval: Beacon Interval + * @llaCoexist: 11a coexist + * @llbCoexist: 11b coexist + * @llgCoexist: 11g coexist + * @ht20MhzCoexist: HT 20MHz coexist + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS mode + * @paramChangeBitmap: change bitmap + * @smeSessionId: SME session id + */ +typedef struct { + uint8_t bssIdx; + uint8_t fShortPreamble; + uint8_t fShortSlotTime; + uint16_t beaconInterval; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20MhzCoexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + uint16_t paramChangeBitmap; + uint8_t smeSessionId; +} tUpdateBeaconParams, *tpUpdateBeaconParams; + +#ifdef WLAN_FEATURE_11AC +/** + * struct tUpdateVHTOpMode - VHT operating mode + * @opMode: VHT operating mode + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t opMode; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateVHTOpMode, *tpUpdateVHTOpMode; + +/** + * struct tUpdateRxNss - update rx nss parameters + * @rxNss: rx nss value + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t rxNss; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateRxNss, *tpUpdateRxNss; + +/** + * struct tUpdateMembership - update membership parmaters + * @membership: membership value + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t membership; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateMembership, *tpUpdateMembership; + +/** + * struct tUpdateUserPos - update user position parmeters + * @userPos: user position + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t userPos; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateUserPos, *tpUpdateUserPos; + +#endif /* WLAN_FEATURE_11AC */ + +/** + * struct tUpdateCFParams -CF parameters + * @bssIdx: BSSID index + * @cfpCount: CFP count + * @cfpPeriod: the number of DTIM intervals between the start of CFPs + */ +typedef struct { + uint8_t bssIdx; + /* + * cfpCount indicates how many DTIMs (including the current frame) + * appear before the next CFP start. A CFPCount of 0 indicates that + * the current DTIM marks the start of the CFP. + */ + uint8_t cfpCount; + uint8_t cfpPeriod; +} tUpdateCFParams, *tpUpdateCFParams; + +/** + * struct tSwitchChannelParams - switch channel request parameter + * @channelNumber: channel number + * @localPowerConstraint: local power constraint + * @secondaryChannelOffset: scondary channel offset + * @peSessionId: PE session id + * @txMgmtPower: TX mgmt power + * @maxTxPower: max tx power + * @selfStaMacAddr: self mac address + * @bssId: bssid + * @status: CDF status + * @chainMask: chanin mask + * @smpsMode: SMPS mode + * @isDfsChannel: is DFS channel + * @vhtCapable: VHT capable + * @dot11_mode: 802.11 mode + */ +typedef struct { + uint8_t channelNumber; +#ifndef WLAN_FEATURE_VOWIFI + uint8_t localPowerConstraint; +#endif /* WLAN_FEATURE_VOWIFI */ + uint8_t peSessionId; +#if defined WLAN_FEATURE_VOWIFI + tPowerdBm txMgmtPower; + tPowerdBm maxTxPower; +#endif /* WLAN_FEATURE_VOWIFI */ + tSirMacAddr selfStaMacAddr; + /* the request has power constraints, this should be applied only to + * that session + * VO Wifi comment: BSSID is needed to identify which session issued + * this request. As the request has power constraints, this should be + * applied only to that session + * V IMP: Keep bssId field at the end of this msg. + * It is used to mantain backward compatbility by way of ignoring if + * using new host/old FW or old host/new FW since it is at the end of + * this struct + */ + tSirMacAddr bssId; + CDF_STATUS status; + uint16_t chainMask; + uint16_t smpsMode; + uint8_t isDfsChannel; + uint8_t vhtCapable; + phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t dot11_mode; + + uint8_t restart_on_chan_switch; + uint8_t nss; +} tSwitchChannelParams, *tpSwitchChannelParams; + +/** + * struct tpCSAOffloadParams - CSA offload request parameters + * @channel: channel + * @switchmode: switch mode + * @sec_chan_offset: second channel offset + * @new_ch_width: new channel width + * @new_ch_freq_seg1: channel center freq 1 + * @new_ch_freq_seg2: channel center freq 2 + * @ies_present_flag: IE present flag + */ +typedef struct CSAOffloadParams { + uint8_t channel; + uint8_t switchmode; + uint8_t sec_chan_offset; + uint8_t new_ch_width; + uint8_t new_ch_freq_seg1; + uint8_t new_ch_freq_seg2; + uint32_t ies_present_flag; + tSirMacAddr bssId; +} *tpCSAOffloadParams, tCSAOffloadParams; + +typedef void (*tpSetLinkStateCallback)(tpAniSirGlobal pMac, void *msgParam, + bool status); + +/** + * struct tLinkStateParams - link state parameters + * @bssid: BSSID + * @selfMacAddr: self mac address + * @state: link state + * @callback: callback function pointer + * @callbackArg: callback argument + * @session: session context + */ +typedef struct sLinkStateParams { + /* SIR_HAL_SET_LINK_STATE */ + tSirMacAddr bssid; + tSirMacAddr selfMacAddr; + tSirLinkState state; + tpSetLinkStateCallback callback; + void *callbackArg; +#ifdef WLAN_FEATURE_VOWIFI_11R + int ft; + void *session; +#endif /* WLAN_FEATURE_VOWIFI_11R */ + bool status; +} tLinkStateParams, *tpLinkStateParams; + +/** + * struct tAddTsParams - ADDTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: CDF status + * @sessionId: session id + * @tsm_interval: TSM interval period passed from lim to WMA + * @setRICparams: RIC parameters + * @sme_session_id: sme session id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec; + CDF_STATUS status; + uint8_t sessionId; +#ifdef FEATURE_WLAN_ESE + uint16_t tsm_interval; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + uint8_t sme_session_id; +} tAddTsParams, *tpAddTsParams; + +/** + * struct tDelTsParams - DELTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS + * @bssId: BSSID + * @sessionId: session id + * @userPrio: user priority + * @delTsInfo: DELTS info + * @setRICparams: RIC parameters + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacAddr bssId; + uint8_t sessionId; + uint8_t userPrio; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tSirDeltsReqInfo delTsInfo; + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +} tDelTsParams, *tpDelTsParams; + +#ifdef WLAN_FEATURE_VOWIFI_11R + +#define HAL_QOS_NUM_TSPEC_MAX 2 +#define HAL_QOS_NUM_AC_MAX 4 + +/** + * struct tAggrAddTsParams - ADDTS parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: CDF status + * @sessionId: session id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec[HAL_QOS_NUM_AC_MAX]; + CDF_STATUS status[HAL_QOS_NUM_AC_MAX]; + uint8_t sessionId; +} tAggrAddTsParams, *tpAggrAddTsParams; + +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +typedef tSirRetStatus (*tHalMsgCallback)(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); + +/** + * struct tEdcaParams - EDCA parameters + * @bssIdx: BSSID index + * @acbe: best effort access catagory + * @acbk: Background access catagory + * @acvi: video access catagory + * @acvo: voice access catagory + */ +typedef struct { + uint16_t bssIdx; + tSirMacEdcaParamRecord acbe; + tSirMacEdcaParamRecord acbk; + tSirMacEdcaParamRecord acvi; + tSirMacEdcaParamRecord acvo; +} tEdcaParams, *tpEdcaParams; + +/** + * struct tSetMIMOPS - MIMO power save related parameters + * @staIdx: station index + * @htMIMOPSState: MIMO Power Save State + * @status: response status + * @fsendRsp: send response flag + * @peerMac: peer mac address + * @sessionId: session id + */ +typedef struct sSet_MIMOPS { + uint16_t staIdx; + tSirMacHTMIMOPowerSaveState htMIMOPSState; + CDF_STATUS status; + uint8_t fsendRsp; + tSirMacAddr peerMac; + uint8_t sessionId; +} tSetMIMOPS, *tpSetMIMOPS; + +/** + * struct tUapsdParams - Uapsd related parameters + * @bkDeliveryEnabled: BK delivery enable flag + * @beDeliveryEnabled: BE delivery enable flag + * @viDeliveryEnabled: VI delivery enable flag + * @voDeliveryEnabled: VO delivery enable flag + * @bkTriggerEnabled: BK trigger enable flag + * @beTriggerEnabled: BE trigger enable flag + * @viTriggerEnabled: VI trigger enable flag + * @voTriggerEnabled: VO trigger enable flag + * @status: response status + * @bssIdx: BSSID index + * Request Type = SIR_HAL_ENTER_UAPSD_REQ + */ +typedef struct sUapsdParams { + uint8_t bkDeliveryEnabled:1; + uint8_t beDeliveryEnabled:1; + uint8_t viDeliveryEnabled:1; + uint8_t voDeliveryEnabled:1; + uint8_t bkTriggerEnabled:1; + uint8_t beTriggerEnabled:1; + uint8_t viTriggerEnabled:1; + uint8_t voTriggerEnabled:1; + CDF_STATUS status; + uint8_t bssIdx; +} tUapsdParams, *tpUapsdParams; + +/** + * struct tHalIndCB - hal message indication callback + * @pHalIndCB: hal message indication callabck + */ +typedef struct tHalIndCB { + tHalMsgCallback pHalIndCB; +} tHalIndCB, *tpHalIndCB; + +/** + * struct sControlTxParams - control tx parameters + * @stopTx: stop transmission + * @fCtrlGlobal: Master flag to stop or resume all transmission + * @ctrlSta: If this flag is set, staBitmap + * @ctrlBss: If this flag is set, bssBitmap and beaconBitmap is valid + * @bssBitmap: bitmap of BSS indices to be stopped for resumed + * @beaconBitmap: this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission + */ +typedef struct sControlTxParams { + bool stopTx; + uint8_t fCtrlGlobal; + uint8_t ctrlSta; + uint8_t ctrlBss; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for transmission. + * This is 32 bit bitmap, not array of bytes. + */ + uint32_t bssBitmap; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission. + */ + uint32_t beaconBitmap; +} tTxControlParams, *tpTxControlParams; + +/** + * struct tMaxTxPowerParams - Max Tx Power parameters + * @bssId: BSSID is needed to identify which session issued this request + * @selfStaMacAddr: self mac address + * @power: tx power in dbm + * @dev_mode: device mode + * Request Type = SIR_HAL_SET_MAX_TX_POWER_REQ + */ +typedef struct sMaxTxPowerParams { + tSirMacAddr bssId; + tSirMacAddr selfStaMacAddr; + /* In request, + * power == MaxTx power to be used. + * In response, + * power == tx power used for management frames. + */ + tPowerdBm power; + tCDF_CON_MODE dev_mode; +} tMaxTxPowerParams, *tpMaxTxPowerParams; + +/** + * struct tMaxTxPowerPerBandParams - max tx power per band info + * @bandInfo: band info + * @power: power in dbm + */ +typedef struct sMaxTxPowerPerBandParams { + eCsrBand bandInfo; + tPowerdBm power; +} tMaxTxPowerPerBandParams, *tpMaxTxPowerPerBandParams; + +/** + * struct add_sta_self_params - Add Sta Self params + * @self_mac_addr: self MAC Address + * @curr_device_mode: operating device mode + * @type: Vdev Type + * @sub_type: Vdev Sub Type + * @session_id: SME Session ID + * @status: response status code + */ +struct add_sta_self_params { + tSirMacAddr self_mac_addr; + tCDF_CON_MODE curr_device_mode; + uint32_t type; + uint32_t sub_type; + uint8_t session_id; + uint32_t status; +}; + +#ifdef FEATURE_WLAN_TDLS + +#define HAL_TDLS_MAX_SUPP_CHANNELS 128 +#define HAL_TDLS_MAX_SUPP_OPER_CLASSES 32 + +/** + * struct tTdlsPeerCapParams - TDLS peer capablities parameters + * @isPeerResponder: is peer responder or not + * @peerUapsdQueue: peer uapsd queue + * @peerMaxSp: peer max SP value + * @peerBuffStaSupport: peer buffer sta supported or not + * @peerOffChanSupport: peer offchannel support + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @peerChanLen: peer channel length + * @peerChan: peer channel list + * @peerOperClassLen: peer operating class length + * @peerOperClass: peer operating class + * @prefOffChanNum: peer offchannel number + * @prefOffChanBandwidth: peer offchannel bandwidth + * @opClassForPrefOffChan: operating class for offchannel + */ +typedef struct { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + tSirUpdateChanParam peerChan[HAL_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[HAL_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +} tTdlsPeerCapParams; + +/** + * struct tTdlsPeerStateParams - TDLS peer state parameters + * @vdevId: vdev id + * @peerMacAddr: peer mac address + * @peerCap: peer capabality + */ +typedef struct sTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tTdlsPeerCapParams peerCap; +} tTdlsPeerStateParams; + +/** + * struct tdls_chan_switch_params - channel switch parameter structure + * @vdev_id: vdev ID + * @peer_mac_addr: Peer mac address + * @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset + * @tdls_off_ch: Target Off Channel + * @oper_class: Operating class for target channel + * @is_responder: Responder or initiator + */ +typedef struct tdls_chan_switch_params_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch; + uint8_t tdls_sw_mode; + uint8_t oper_class; + uint8_t is_responder; +} tdls_chan_switch_params; + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct tAbortScanParams - Abort scan parameters + * @SessionId: session id + */ +typedef struct sAbortScanParams { + uint8_t SessionId; + uint32_t scan_id; +} tAbortScanParams, *tpAbortScanParams; + +/** + * struct del_sta_self_params - Del Sta Self params + * @session_id: SME Session ID + * @status: response status code + */ +struct del_sta_self_params { + tSirMacAddr self_mac_addr; + uint8_t session_id; + uint32_t status; +}; + +/** + * struct tP2pPsParams - P2P powersave related params + * @opp_ps: opportunistic power save + * @ctWindow: CT window + * @count: count + * @duration: duration + * @interval: interval + * @single_noa_duration: single shot noa duration + * @psSelection: power save selection + * @sessionId: session id + */ +typedef struct sP2pPsParams { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; + uint8_t sessionId; +} tP2pPsParams, *tpP2pPsParams; + +/** + * struct tTdlsLinkEstablishParams - TDLS Link establish parameters + * @staIdx: station index + * @isResponder: responder flag + * @uapsdQueues: uapsd queue + * @maxSp: max SP period + * @isBufsta: is station flag + * @isOffChannelSupported: offchannel supported or not + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @validChannelsLen: valid channel length + * @validChannels: valid channels + * @validOperClassesLen: valid operating class length + * @validOperClasses: valid operating class + * @status: return status of command + */ +typedef struct sTdlsLinkEstablishParams { + uint16_t staIdx; + uint8_t isResponder; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufsta; + uint8_t isOffChannelSupported; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t validChannelsLen; + uint8_t validChannels[HAL_MAX_SUPP_CHANNELS]; + uint8_t validOperClassesLen; + uint8_t validOperClasses[HAL_MAX_SUPP_OPER_CLASSES]; + uint32_t status; +} tTdlsLinkEstablishParams, *tpTdlsLinkEstablishParams; + +/** + * struct tHalHiddenSsidVdevRestart - hidden ssid vdev restart params + * @ssidHidden: is hidden ssid or not + * @sessionId: session id + */ +typedef struct tHalHiddenSsidVdevRestart { + uint8_t ssidHidden; + uint8_t sessionId; +} tHalHiddenSsidVdevRestart, *tpHalHiddenSsidVdevRestart; + + +extern void sys_process_mmh_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +/** + * struct tBeaconFilterMsg - Beacon Filtering data structure + * @capabilityInfo: capability info + * @capabilityMask: capabality mask + * @beaconInterval: beacon interval + * @ieNum: IE number + * @reserved: reserved + */ +typedef struct sBeaconFilterMsg { + uint16_t capabilityInfo; + uint16_t capabilityMask; + uint16_t beaconInterval; + uint16_t ieNum; + uint8_t bssIdx; + uint8_t reserved; +} cdf_packed tBeaconFilterMsg, *tpBeaconFilterMsg; + +/** + * struct tEidByteInfo - Eid byte info + * @offset: offset + * @value: value + * @bitMask: BIT mask + * @ref: refrence + */ +typedef struct sEidByteInfo { + uint8_t offset; + uint8_t value; + uint8_t bitMask; + uint8_t ref; +} cdf_packed tEidByteInfo, *tpEidByteInfo; + +/** + * struct tBeaconFilterIe - beacon filter IE + * @elementId: element IE + * @checkIePresence: check IE presence + * @byte: Eid byte info + */ +typedef struct sBeaconFilterIe { + uint8_t elementId; + uint8_t checkIePresence; + tEidByteInfo byte; +} cdf_packed tBeaconFilterIe, *tpBeaconFilterIe; + +/** + * struct tDisableIntraBssFwd - intra bss forward parameters + * @sessionId: session id + * @disableintrabssfwd: disable intra bss forward flag + */ +typedef struct sDisableIntraBssFwd { + uint16_t sessionId; + bool disableintrabssfwd; +} cdf_packed tDisableIntraBssFwd, *tpDisableIntraBssFwd; + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * struct tStatsExtRequest - ext stats request + * @vdev_id: vdev id + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sStatsExtRequest { + uint32_t vdev_id; + uint32_t request_data_len; + uint8_t request_data[]; +} tStatsExtRequest, *tpStatsExtRequest; +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_NAN +/** + * struct tNanRequest - NAN request params + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sNanRequest { + uint16_t request_data_len; + uint8_t request_data[]; +} tNanRequest, *tpNanRequest; +#endif /* WLAN_FEATURE_NAN */ + +#endif /* _HALMSGAPI_H_ */ diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h new file mode 100644 index 0000000000..a737fa2f10 --- /dev/null +++ b/core/wma/inc/wma_internal.h @@ -0,0 +1,1097 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_INTERNAL_H +#define WMA_INTERNAL_H + +/* ################### defines ################### */ +/* + * TODO: Following constant should be shared by firwmare in + * wmi_unified.h. This will be done once wmi_unified.h is updated. + */ +#define WMI_PEER_STATE_AUTHORIZED 0x2 + +#define WMA_2_4_GHZ_MAX_FREQ 3000 +#define WOW_CSA_EVENT_OFFSET 12 + +#define WMA_DEFAULT_SCAN_REQUESTER_ID 1 +#define WMI_SCAN_FINISH_EVENTS (WMI_SCAN_EVENT_START_FAILED | \ + WMI_SCAN_EVENT_COMPLETED | \ + WMI_SCAN_EVENT_DEQUEUED) +/* default value */ +#define DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD 20 +/* pdev vdev and peer stats*/ +#define FW_PDEV_STATS_SET 0x1 +#define FW_VDEV_STATS_SET 0x2 +#define FW_PEER_STATS_SET 0x4 +#define FW_STATS_SET 0x7 + +/*AR9888/AR6320 noise floor approx value + * similar to the mentioned the WMA + */ +#define WMA_TGT_NOISE_FLOOR_DBM (-96) + +/* + * Make sure that link monitor and keep alive + * default values should be in sync with CFG. + */ +#define WMA_LINK_MONITOR_DEFAULT_TIME_SECS 10 +#define WMA_KEEP_ALIVE_DEFAULT_TIME_SECS 5 + +#define AGC_DUMP 1 +#define CHAN_DUMP 2 +#define WD_DUMP 3 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_DUMP 4 +#endif + +/* conformance test limits */ +#define FCC 0x10 +#define MKK 0x40 +#define ETSI 0x30 + +/* Maximum Buffer length allowed for DFS phyerrors */ +#define DFS_MAX_BUF_LENGHT 4096 + +#define WMI_DEFAULT_NOISE_FLOOR_DBM (-96) + +#define WMI_MCC_MIN_CHANNEL_QUOTA 20 +#define WMI_MCC_MAX_CHANNEL_QUOTA 80 +#define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30 + +/* The maximum number of patterns that can be transmitted by the firmware + * and maximum patterns size. + */ +#define WMA_MAXNUM_PERIODIC_TX_PTRNS 6 + +#define WMI_MAX_HOST_CREDITS 2 +#define WMI_WOW_REQUIRED_CREDITS 1 + +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 +#define INVALID_MCS_IDX 255 + +#define LINK_STATUS_LEGACY 0 +#define LINK_STATUS_VHT 0x1 +#define LINK_STATUS_MIMO 0x2 +#define LINK_SUPPORT_VHT 0x4 +#define LINK_SUPPORT_MIMO 0x8 + +#define LINK_RATE_VHT 0x3 + +#define MAX_ENTRY_HOLD_REQ_QUEUE 2 +/** + * struct index_data_rate_type - non vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_rate: Supported rate table + */ +struct index_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +}; + +#ifdef WLAN_FEATURE_11AC +/** + * struct index_vht_data_rate_type - vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_VHT80_rate: VHT80 rate + * @supported_VHT40_rate: VHT40 rate + * @supported_VHT20_rate: VHT20 rate + */ +struct index_vht_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_VHT80_rate[2]; + uint16_t supported_VHT40_rate[2]; + uint16_t supported_VHT20_rate[2]; +}; +#endif + +/* + * wma_main.c functions declarations + */ + +int +wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id, + uint32_t param_value); + +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val); + +void wma_data_tx_ack_comp_hdlr(void *wma_context, + cdf_nbuf_t netbuf, int32_t status); + +CDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int value); + +/* + * wma_scan_roam.c functions declarations + */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke); + +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail); + +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len); +#endif + +CDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, + wmi_buf_t *buf, int *buf_len); + +CDF_STATUS wma_get_buf_stop_scan_cmd(tp_wma_handle wma_handle, + wmi_buf_t *buf, + int *buf_len, + tAbortScanParams *abort_scan_req); + +CDF_STATUS wma_start_scan(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, uint16_t msg_type); + +CDF_STATUS wma_stop_scan(tp_wma_handle wma_handle, + tAbortScanParams *abort_scan_req); + +CDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +CDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + wmi_roam_offload_tlv_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req); +#endif + +CDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id); + +CDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +CDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +CDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +CDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); + +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_ap_profile *ap_profile_p); + +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params); + +CDF_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id); + +CDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id); + +CDF_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id); + +CDF_STATUS wma_process_roam_scan_req(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +CDF_STATUS wma_roam_preauth_chan_set(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +CDF_STATUS wma_roam_preauth_chan_cancel(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +void wma_roam_preauth_scan_event_handler(tp_wma_handle wma_handle, + uint8_t vdev_id, + wmi_scan_event_fixed_param * + wmi_event); + +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params); + +#ifdef FEATURE_WLAN_SCAN_PNO +CDF_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno); + +CDF_STATUS wma_pno_stop(tp_wma_handle wma, uint8_t vdev_id); + +void wma_config_pno(tp_wma_handle wma, tpSirPNOScanReq pno); + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +CDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm); + +CDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm); + +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm); +#endif + +void wma_scan_cache_updated_ind(tp_wma_handle wma, uint8_t sessionId); +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts); +#endif + +#ifdef FEATURE_WLAN_EXTSCAN + +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int +wma_extscan_hotlist_ssid_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); +#endif + +void wma_register_extscan_event_handler(tp_wma_handle wma_handle); + +#ifdef FEATURE_WLAN_EXTSCAN +CDF_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle, + tSirWifiScanCmdReqParams *pstart, + wmi_buf_t *buf, int *buf_len); + +CDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart); + +CDF_STATUS wma_stop_extscan(tp_wma_handle wma, + tSirExtScanStopReqParams *pstopcmd); + +CDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle, + tSirExtScanSetBssidHotListReqParams * + photlist, int *buf_len); + +CDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + tSirExtScanSetBssidHotListReqParams + *photlist); + +CDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + tSirExtScanResetBssidHotlistReqParams + *photlist_reset); + +CDF_STATUS wma_get_buf_extscan_change_monitor_cmd(tp_wma_handle wma_handle, + tSirExtScanSetSigChangeReqParams + *psigchange, wmi_buf_t *buf, + int *buf_len); + +CDF_STATUS wma_extscan_start_change_monitor(tp_wma_handle wma, + tSirExtScanSetSigChangeReqParams * + psigchange); + +CDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + tSirExtScanResetSignificantChangeReqParams + *pResetReq); + +CDF_STATUS wma_extscan_get_cached_results(tp_wma_handle wma, + tSirExtScanGetCachedResultsReqParams * + pcached_results); + +CDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab); +CDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req); + +CDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); + +CDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); +CDF_STATUS +wma_set_ssid_hotlist(tp_wma_handle wma, + struct sir_set_ssid_hotlist_request *request); +#endif + +CDF_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma, + struct sir_ipa_offload_enable_disable *ipa_offload); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_unit_test_cmd(WMA_HANDLE handle, + t_wma_unit_test_cmd *wma_utest); +#endif + +CDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui); + +int wma_scan_event_callback(WMA_HANDLE handle, uint8_t *data, uint32_t len); + +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id); + +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len); + +#ifdef FEATURE_WLAN_SCAN_PNO +int wma_nlo_match_evt_handler(void *handle, uint8_t *event, uint32_t len); + +int wma_nlo_scan_cmp_evt_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_roam_synch_complete(WMA_HANDLE handle, + tSirSmeRoamOffloadSynchCnf *synchcnf); +#endif + +/* + * wma_dev_if.c functions declarations + */ + +void *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id); + +/** + * wma_find_vdev_by_id() - Returns vdev handle for given vdev id. + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns vdev handle if given vdev id is valid. + * Otherwise returns NULL. + */ +static inline void *wma_find_vdev_by_id(tp_wma_handle wma, uint8_t vdev_id) +{ + if (vdev_id > wma->max_bssid) + return NULL; + + return wma->interfaces[vdev_id].handle; +} + +/** + * wma_get_vdev_count() - Returns number of active vdev. + * @wma - wma handle + * + * Return: Returns valid vdev count. + */ +static inline uint8_t wma_get_vdev_count(tp_wma_handle wma) +{ + uint8_t vdev_count = 0, i; + + for (i = 0; i < wma->max_bssid; i++) { + if (wma->interfaces[i].handle) + vdev_count++; + } + return vdev_count; +} + +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef QCA_IBSS_SUPPORT +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id); +#endif + +/** + * wma_find_bssid_by_vdev_id() - Get the BSS ID corresponding to the vdev ID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns pointer to bssid on success, + * otherwise returns NULL. + */ +static inline uint8_t *wma_find_bssid_by_vdev_id(tp_wma_handle wma, + uint8_t vdev_id) +{ + if (vdev_id >= wma->max_bssid) + return NULL; + + return wma->interfaces[vdev_id].bssid; +} + +void *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id); + +int wma_unified_vdev_create_send(wmi_unified_t wmi_handle, uint8_t if_id, + uint32_t type, uint32_t subtype, + uint8_t macaddr[IEEE80211_ADDR_LEN]); + +CDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp); + +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +int wmi_unified_vdev_set_param_send(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value); + +int32_t wmi_unified_peer_flush_tids_send(wmi_unified_t wmi, + uint8_t peer_addr + [IEEE80211_ADDR_LEN], + uint32_t peer_tid_bitmap, + uint8_t vdev_id); + +void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, + uint8_t vdev_id, ol_txrx_peer_handle peer, + bool roam_synch_in_progress); + +CDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress); + +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len); + +ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp); + +CDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart); + +void wma_vdev_resp_timer(void *data); + +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout); + +void wma_hold_req_timer(void *data); +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +void wma_add_bss(tp_wma_handle wma, tpAddBssParams params); + +int wmi_unified_vdev_up_send(wmi_unified_t wmi, + uint8_t vdev_id, uint16_t aid, + uint8_t bssid[IEEE80211_ADDR_LEN]); + +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta); + +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta); + +int32_t wmi_unified_vdev_stop_send(wmi_unified_t wmi, uint8_t vdev_id); + +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params); + +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type); + +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd); + +/* + * wma_mgmt.c functions declarations + */ + +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len); + +int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len); + +void wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len); + +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + + +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac); + +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len); + +int32_t wmi_unified_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params); + +int wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, uint32_t if_id, + gtx_config_t *gtx_info); + +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist); + +void wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params); + +void wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam); + +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info); + +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta); + +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info); + +CDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params); + +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len); + +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info); + +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info); + +void wma_set_keepalive_req(tp_wma_handle wma, + tSirKeepAliveReq *keepalive); + +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id); + +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode); + +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss); + +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership); + +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos); + +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle, + tHalHiddenSsidVdevRestart *pReq); + +/* + * wma_power.c functions declarations + */ + +void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req); + +int32_t wmi_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value); + +CDF_STATUS +wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id); + +int32_t wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp); + +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + wmi_wmm_vparams *wmm_param, int ac); + +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +int32_t wmi_unified_set_sta_ps(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val); + +void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req); + +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req); + +void wma_disable_uapsd_mode(tp_wma_handle wma, + tpDisableUapsdParams ps_req); + +CDF_STATUS wma_get_temperature(tp_wma_handle wma_handle); + +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +CDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + tSirTxPowerLimit *ptxlim); + +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie); + +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie); + +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len); + +void wma_process_set_p2pgo_noa_req(tp_wma_handle wma, + tP2pPsParams *ps_params); + +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops); + +CDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value); + +CDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq); + +CDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value); + +void wma_set_suspend_dtim(tp_wma_handle wma); + +void wma_set_resume_dtim(tp_wma_handle wma); + +/* + * wma_data.c functions declarations + */ + + +void wma_set_bss_rate_flags(struct wma_txrx_node *iface, + tpAddBssParams add_bss); + +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params); + +void wma_update_txrx_chainmask(int num_rf_chains, int *cmd_value); + +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len); + +CDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler); + +CDF_STATUS wma_set_mcc_channel_time_latency + (tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency); + +CDF_STATUS wma_set_mcc_channel_time_quota + (tp_wma_handle wma, + uint32_t adapter_1_chan_number, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_number); + +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params); + +void wma_unpause_vdev(tp_wma_handle wma); + +CDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams); + +CDF_STATUS wma_tx_attach(tp_wma_handle wma_handle); + +CDF_STATUS wma_tx_detach(tp_wma_handle wma_handle); + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len); +#endif + +CDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams); + +CDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level); + +CDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info); + +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +/* + * wma_utils.c functions declarations + */ + +#ifdef WLAN_FEATURE_STATS_EXT +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); +#endif + +tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle); + +CDF_STATUS wma_process_ll_stats_clear_req + (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq); + +CDF_STATUS wma_process_ll_stats_set_req + (tp_wma_handle wma, const tpSirLLStatsSetReq setReq); + +CDF_STATUS wma_process_ll_stats_get_req + (tp_wma_handle wma, const tpSirLLStatsGetReq getReq) ; + +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); +#endif + +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status); + +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +CDF_STATUS wma_send_link_speed(uint32_t link_speed); + +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +CDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle); + +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len); + +bool wma_is_sap_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_go_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle); + +bool wma_is_sta_active(tp_wma_handle wma_handle); + +WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht); + +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +int wmi_crash_inject(wmi_unified_t wmi_handle, uint32_t type, + uint32_t delay_time_ms); + +void wma_get_stats_req(WMA_HANDLE handle, + tAniGetPEStatsReq *get_stats_param); + +#if defined(QCA_WIFI_FTM) +void wma_utf_detach(tp_wma_handle wma_handle); + +void wma_utf_attach(tp_wma_handle wma_handle); + +CDF_STATUS +wma_process_ftm_command(tp_wma_handle wma_handle, + struct ar6k_testmode_cmd_data *msg_buffer); +#endif + +/* + * wma_features.c functions declarations + */ + +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus); + +#ifdef FEATURE_WLAN_LPHB +CDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req); + +#endif + +CDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle, + tAniDHCPInd *ta_dhcp_ind); + +WLAN_PHY_MODE wma_chan_to_mode(u8 chan, phy_ch_width chan_width, + u8 vht_capable, u8 dot11_mode); + +CDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed); + +#ifdef FEATURE_GREEN_AP +int32_t wmi_unified_pdev_green_ap_ps_enable_cmd(wmi_unified_t wmi_handle, + uint32_t value); +#endif + +void wma_wow_tx_complete(void *wma); + +int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id); + +int wmi_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_NAN +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, uint32_t len); +#endif + +#ifdef FEATURE_WLAN_TDLS +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len); + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +int wma_gtk_offload_status_event(void *handle, uint8_t *event, uint32_t len); +#endif + +#ifdef FEATURE_OEM_DATA_SUPPORT +int wma_oem_capability_event_callback(void *handle, + uint8_t *datap, uint32_t len); + +int wma_oem_measurement_report_event_callback(void *handle, uint8_t *datap, + uint32_t len); + +int wma_oem_error_report_event_callback(void *handle, uint8_t *datap, + uint32_t len); +#endif + +void wma_register_dfs_event_handler(tp_wma_handle wma_handle); + +int +wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle); + +#if !defined(REMOVE_PKT_LOG) +CDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params); +#endif + +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, + uint32_t len); +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len); + +/** + * wma_get_wow_bus_suspend() - check is wow bus suspended or not + * @wma: wma handle + * + * Return: true/false + */ +static inline int wma_get_wow_bus_suspend(tp_wma_handle wma) +{ + + return cdf_atomic_read(&wma->is_wow_bus_suspended); +} + +CDF_STATUS wma_resume_req(tp_wma_handle wma); + +CDF_STATUS wma_wow_add_pattern(tp_wma_handle wma, + struct wow_add_pattern *ptrn); + +CDF_STATUS wma_wow_delete_user_pattern(tp_wma_handle wma, + struct wow_delete_pattern *pattern); + +CDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info); + +CDF_STATUS wma_wow_exit(tp_wma_handle wma, tpSirHalWowlExitParams info); + +CDF_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info); + +void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg); + +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg); + +void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg); + +int wma_process_receive_filter_set_filter_req(tp_wma_handle wma_handle, + tSirRcvPktFilterCfgType * + rcv_filter_param); + +int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma_handle, + tSirRcvFltPktClearParam * + rcv_clear_param); + +#ifdef FEATURE_OEM_DATA_SUPPORT +void wma_start_oem_data_req(tp_wma_handle wma_handle, + tStartOemDataReq *startOemDataReq); +#endif + +#ifdef FEATURE_WLAN_ESE +CDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg); +#endif + +CDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList *mcbc_param); +#ifdef WLAN_FEATURE_GTK_OFFLOAD +CDF_STATUS wma_process_gtk_offload_req(tp_wma_handle wma, + tpSirGtkOffloadParams params); + +CDF_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma, + tpSirGtkOffloadGetInfoRspParams + params); +#endif + +CDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, + tpSirHostOffloadReq pHostOffloadParams, + bool bArpOnly); + +CDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams); + +CDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams); + +#ifdef WLAN_FEATURE_STATS_EXT +CDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq); +#endif + +CDF_STATUS wma_process_ibss_route_table_update_ind(void *wma_handle, + tAniIbssRouteTable *pData); + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +int wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params); + +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params); + +int wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params); +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len); + +CDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + auto_sh_cmd); +#endif + +#ifdef WLAN_FEATURE_NAN + +CDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req); +#endif + +#ifdef DHCP_SERVER_OFFLOAD +int wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo); +#endif + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +CDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + tSirLedFlashingReq *flashing); +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +int wma_channel_avoid_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +CDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req); +#endif + +int wma_suspend_target(WMA_HANDLE handle, int disable_target_intr); + +#ifdef FEATURE_WLAN_TDLS + +int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams); +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams); +/** + * wma_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +int wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle, + tdls_chan_switch_params *chan_switch_params); +#endif + +struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic); + +void wma_dfs_detach(struct ieee80211com *dfs_ic); + +void wma_dfs_configure(struct ieee80211com *ic); + +struct ieee80211_channel *wma_dfs_configure_channel(struct ieee80211com *dfs_ic, + wmi_channel *chan, + WLAN_PHY_MODE chanmode, + struct wma_vdev_start_req + *req); +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef REMOVE_PKT_LOG +static inline void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ + return; +} +#endif +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len); +#ifdef WLAN_FEATURE_MEMDUMP +int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len); +CDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + struct fw_dump_req *mem_dump_req); +#else +static inline int wma_fw_mem_dump_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + return 0; +} + +static inline CDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + void *mem_dump_req) +{ + return CDF_STATUS_SUCCESS; +} +#endif +CDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info); +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +#endif diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h new file mode 100644 index 0000000000..eab91f69a8 --- /dev/null +++ b/core/wma/inc/wma_tgt_cfg.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_TGT_CFG_H +#define WMA_TGT_CFG_H + +/** + * struct wma_tgt_services - target services + * @sta_power_save: sta power save + * @uapsd: uapsd + * @ap_dfs: ap dfs + * @en_11ac: enable 11ac + * @arp_offload: arp offload + * @early_rx: early rx + * @pno_offload: pno offload + * @beacon_offload: beacon offload + * @lte_coex_ant_share: LTE coex ant share + * @en_tdls: enable tdls + * @en_tdls_offchan: enable tdls offchan + * @en_tdls_uapsd_buf_sta: enable sta tdls uapsd buf + * @en_tdls_uapsd_sleep_sta: enable sta tdls uapsd sleep + * @en_roam_offload: enable roam offload + */ +struct wma_tgt_services { + uint32_t sta_power_save; + uint32_t uapsd; + uint32_t ap_dfs; + uint32_t en_11ac; + uint32_t arp_offload; + uint32_t early_rx; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_offload; +#endif /* FEATURE_WLAN_SCAN_PNO */ + bool beacon_offload; + uint32_t lte_coex_ant_share; +#ifdef FEATURE_WLAN_TDLS + bool en_tdls; + bool en_tdls_offchan; + bool en_tdls_uapsd_buf_sta; + bool en_tdls_uapsd_sleep_sta; +#endif /* FEATURE_WLAN_TDLS */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool en_roam_offload; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +}; + +/** + * struct wma_tgt_ht_cap - ht capabalitiy + * @mpdu_density: mpdu density + * @ht_rx_stbc: ht rx stbc + * @ht_tx_stbc: ht tx stbc + * @ht_rx_ldpc: ht rx ldpc + * @ht_sgi_20: ht sgi 20 + * @ht_sgi_40: ht sgi 40 + * @num_rf_chains: num of rf chains + */ +struct wma_tgt_ht_cap { + uint32_t mpdu_density; + bool ht_rx_stbc; + bool ht_tx_stbc; + bool ht_rx_ldpc; + bool ht_sgi_20; + bool ht_sgi_40; + uint32_t num_rf_chains; +}; + +#ifdef WLAN_FEATURE_11AC +/** + * struct wma_tgt_vht_cap - vht capabalities + * @vht_max_mpdu: vht max mpdu + * @supp_chan_width: supported channel width + * @vht_rx_ldpc: vht rx ldpc + * @vht_short_gi_80: vht short gi 80 + * @vht_short_gi_160: vht short gi 160 + * @vht_tx_stbc: vht tx stbc + * @vht_rx_stbc: vht rx stbc + * @vht_su_bformer: vht su bformer + * @vht_su_bformee: vht su bformee + * @vht_mu_bformer: vht mu bformer + * @vht_mu_bformee: vht mu bformee + * @vht_max_ampdu_len_exp: vht max ampdu len exp + * @vht_txop_ps: vht txop ps + */ +struct wma_tgt_vht_cap { + uint32_t vht_max_mpdu; + uint32_t supp_chan_width; + uint32_t vht_rx_ldpc; + uint32_t vht_short_gi_80; + uint32_t vht_short_gi_160; + uint32_t vht_tx_stbc; + uint32_t vht_rx_stbc; + uint32_t vht_su_bformer; + uint32_t vht_su_bformee; + uint32_t vht_mu_bformer; + uint32_t vht_mu_bformee; + uint32_t vht_max_ampdu_len_exp; + uint32_t vht_txop_ps; +}; +#endif /* WLAN_FEATURE_11AC */ + +/** + * struct wma_dfs_radar_ind - dfs radar indication + * @ieee_chan_number: ieee channel number + * @chan_freq: channel freq + * @dfs_radar_status: dfs radar status + */ +struct wma_dfs_radar_ind { + uint8_t ieee_chan_number; + uint32_t chan_freq; + uint32_t dfs_radar_status; +}; + +/** + * struct wma_tgt_cfg - target config + * @target_fw_version: target fw version + * @band_cap: band capability + * @reg_domain: reg domain + * @eeprom_rd_ext: eeprom rd ext + * @hw_macaddr: hw mcast addr + * @services: struct wma_tgt_services + * @ht_cap: struct wma_tgt_ht_cap + * @vht_cap: struct wma_tgt_vht_cap + * @max_intf_count: max interface count + * @lpss_support: lpass support + */ +struct wma_tgt_cfg { + uint32_t target_fw_version; + uint8_t band_cap; + uint32_t reg_domain; + uint32_t eeprom_rd_ext; + struct cdf_mac_addr hw_macaddr; + struct wma_tgt_services services; + struct wma_tgt_ht_cap ht_cap; +#ifdef WLAN_FEATURE_11AC + struct wma_tgt_vht_cap vht_cap; +#endif + uint8_t max_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; +}; +#endif /* WMA_TGT_CFG_H */ diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h new file mode 100644 index 0000000000..5f0a1883ca --- /dev/null +++ b/core/wma/inc/wma_types.h @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WMA_H +#define WLAN_QCT_WMA_H + +#include "ani_global.h" + +#include "wma_api.h" +#include "wma_tgt_cfg.h" +#include "i_cds_packet.h" + +#define IS_MCC_SUPPORTED 1 +#define IS_FEATURE_SUPPORTED_BY_FW(feat_enum_value) wma_get_fw_wlan_feat_caps(feat_enum_value) + +#define IS_ROAM_SCAN_OFFLOAD_FEATURE_ENABLE 1 + +#define IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE 1 + +#ifdef FEATURE_WLAN_TDLS +#define IS_ADVANCE_TDLS_ENABLE 0 +#endif + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define WMA_MAX_STA (41) +#else +#define WMA_MAX_STA (16) +#endif + +#define WMA_NVDownload_Start(x) ({ CDF_STATUS_SUCCESS; }) + +#define DPU_FEEDBACK_UNPROTECTED_ERROR 0x0F + +#define WMA_GET_RX_MAC_HEADER(pRxMeta) \ + (tpSirMacMgmtHdr)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDUHEADER3A(pRxMeta) \ + (tpSirMacDataHdr3a)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDU_HEADER_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_hdr_len) + +#define WMA_GET_RX_MPDU_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_len) + +#define WMA_GET_RX_PAYLOAD_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_len) + +#define WMA_GET_RX_TSF_DELTA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->tsf_delta) + +#define WMA_GET_RX_MAC_RATE_IDX(pRxMeta) 0 + +#define WMA_GET_RX_MPDU_DATA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_ptr) + +#define WMA_GET_RX_MPDU_HEADER_OFFSET(pRxMeta) 0 + +#define WMA_GET_RX_UNKNOWN_UCAST(pRxMeta) 0 + +#define WMA_GET_RX_CH(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->channel) + +#define WMA_IS_RX_BCAST(pRxMeta) 0 + +#define WMA_GET_RX_FT_DONE(pRxMeta) 0 + +#define WMA_GET_RX_DPU_FEEDBACK(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->dpuFeedback) + +#define WMA_GET_RX_BEACON_SENT(pRxMeta) 0 + +#define WMA_GET_RX_TSF_LATER(pRxMeta) 0 + +#define WMA_GET_RX_TIMESTAMP(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->timestamp) + +#define WMA_IS_RX_IN_SCAN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan) + +#define WMA_GET_OFFLOADSCANLEARN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->offloadScanLearn) +#define WMA_GET_ROAMCANDIDATEIND(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->roamCandidateInd) +#define WMA_GET_SESSIONID(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->sessionId) +#define WMA_GET_SCAN_SRC(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan_src) + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_IS_EXTSCAN_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) == WMI_MGMT_RX_HDR_EXTSCAN) +#define WMA_IS_EPNO_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) & WMI_MGMT_RX_HDR_ENLO) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#define WMA_GET_RX_SNR(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->snr) + +#define WMA_GET_RX_RFBAND(pRxMeta) 0 + +#define WMA_MAX_TXPOWER_INVALID 127 +#define WMA_GET_RX_RSSI_DB(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->rssi) + +/* WMA Messages */ +#define WMA_MSG_TYPES_BEGIN SIR_HAL_MSG_TYPES_BEGIN +#define WMA_ITC_MSG_TYPES_BEGIN SIR_HAL_ITC_MSG_TYPES_BEGIN +#define WMA_RADAR_DETECTED_IND SIR_HAL_RADAR_DETECTED_IND + +#define WMA_ADD_STA_REQ SIR_HAL_ADD_STA_REQ +#define WMA_ADD_STA_RSP SIR_HAL_ADD_STA_RSP +#define WMA_ADD_STA_SELF_RSP SIR_HAL_ADD_STA_SELF_RSP +#define WMA_DELETE_STA_REQ SIR_HAL_DELETE_STA_REQ +#define WMA_DELETE_STA_RSP SIR_HAL_DELETE_STA_RSP +#define WMA_ADD_BSS_REQ SIR_HAL_ADD_BSS_REQ +#define WMA_ADD_BSS_RSP SIR_HAL_ADD_BSS_RSP +#define WMA_DELETE_BSS_REQ SIR_HAL_DELETE_BSS_REQ +#define WMA_DELETE_BSS_RSP SIR_HAL_DELETE_BSS_RSP +#define WMA_SEND_BEACON_REQ SIR_HAL_SEND_BEACON_REQ +#define WMA_SEND_PROBE_RSP_TMPL SIR_HAL_SEND_PROBE_RSP_TMPL + +#define WMA_SET_BSSKEY_REQ SIR_HAL_SET_BSSKEY_REQ +#define WMA_SET_BSSKEY_RSP SIR_HAL_SET_BSSKEY_RSP +#define WMA_SET_STAKEY_REQ SIR_HAL_SET_STAKEY_REQ +#define WMA_SET_STAKEY_RSP SIR_HAL_SET_STAKEY_RSP +#define WMA_UPDATE_EDCA_PROFILE_IND SIR_HAL_UPDATE_EDCA_PROFILE_IND + +#define WMA_UPDATE_BEACON_IND SIR_HAL_UPDATE_BEACON_IND +#define WMA_UPDATE_CF_IND SIR_HAL_UPDATE_CF_IND +#define WMA_CHNL_SWITCH_REQ SIR_HAL_CHNL_SWITCH_REQ +#define WMA_ADD_TS_REQ SIR_HAL_ADD_TS_REQ +#define WMA_DEL_TS_REQ SIR_HAL_DEL_TS_REQ + +#define WMA_MISSED_BEACON_IND SIR_HAL_MISSED_BEACON_IND + +#define WMA_ENTER_PS_REQ SIR_HAL_ENTER_PS_REQ +#define WMA_EXIT_PS_REQ SIR_HAL_EXIT_PS_REQ + +#define WMA_CFG_RXP_FILTER_REQ SIR_HAL_CFG_RXP_FILTER_REQ + +#define WMA_SWITCH_CHANNEL_RSP SIR_HAL_SWITCH_CHANNEL_RSP +#define WMA_P2P_NOA_ATTR_IND SIR_HAL_P2P_NOA_ATTR_IND +#define WMA_P2P_NOA_START_IND SIR_HAL_P2P_NOA_START_IND +#define WMA_PWR_SAVE_CFG SIR_HAL_PWR_SAVE_CFG +#define WMA_REGISTER_PE_CALLBACK SIR_HAL_REGISTER_PE_CALLBACK + +#define WMA_IBSS_STA_ADD SIR_HAL_IBSS_STA_ADD +#define WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND +#define WMA_SET_LINK_STATE SIR_HAL_SET_LINK_STATE +#define WMA_SET_LINK_STATE_RSP SIR_HAL_SET_LINK_STATE_RSP +#define WMA_SET_STA_BCASTKEY_REQ SIR_HAL_SET_STA_BCASTKEY_REQ +#define WMA_SET_STA_BCASTKEY_RSP SIR_HAL_SET_STA_BCASTKEY_RSP +#define WMA_ADD_TS_RSP SIR_HAL_ADD_TS_RSP +#define WMA_DPU_MIC_ERROR SIR_HAL_DPU_MIC_ERROR +#define WMA_TIMER_CHIP_MONITOR_TIMEOUT SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT +#define WMA_TIMER_TRAFFIC_ACTIVITY_REQ SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ +#define WMA_TIMER_ADC_RSSI_STATS SIR_HAL_TIMER_ADC_RSSI_STATS +#define WMA_TIMER_TRAFFIC_STATS_IND SIR_HAL_TRAFFIC_STATS_IND + +#ifdef WLAN_FEATURE_11W +#define WMA_EXCLUDE_UNENCRYPTED_IND SIR_HAL_EXCLUDE_UNENCRYPTED_IND +#endif + +#ifdef FEATURE_WLAN_ESE +#define WMA_TSM_STATS_REQ SIR_HAL_TSM_STATS_REQ +#define WMA_TSM_STATS_RSP SIR_HAL_TSM_STATS_RSP +#endif + +#define WMA_SET_MIMOPS_REQ SIR_HAL_SET_MIMOPS_REQ +#define WMA_SET_MIMOPS_RSP SIR_HAL_SET_MIMOPS_RSP +#define WMA_SYS_READY_IND SIR_HAL_SYS_READY_IND +#define WMA_SET_TX_POWER_REQ SIR_HAL_SET_TX_POWER_REQ +#define WMA_SET_TX_POWER_RSP SIR_HAL_SET_TX_POWER_RSP +#define WMA_GET_TX_POWER_REQ SIR_HAL_GET_TX_POWER_REQ + +/* Messages to support transmit_halt and transmit_resume */ +#define WMA_TRANSMISSION_CONTROL_IND SIR_HAL_TRANSMISSION_CONTROL_IND +#define WMA_BEACON_FILTER_IND SIR_HAL_BEACON_FILTER_IND + +#define WMA_ENABLE_UAPSD_REQ SIR_HAL_ENABLE_UAPSD_REQ +#define WMA_DISABLE_UAPSD_REQ SIR_HAL_DISABLE_UAPSD_REQ + +/* / PE <-> HAL WOWL messages */ +#define WMA_WOW_ADD_PTRN SIR_HAL_WOW_ADD_PTRN +#define WMA_WOW_DEL_PTRN SIR_HAL_WOW_DEL_PTRN +#define WMA_WOWL_ENTER_REQ SIR_HAL_WOWL_ENTER_REQ +#define WMA_WOWL_ENTER_RSP SIR_HAL_WOWL_ENTER_RSP +#define WMA_WOWL_EXIT_REQ SIR_HAL_WOWL_EXIT_REQ +#define WMA_WOWL_EXIT_RSP SIR_HAL_WOWL_EXIT_RSP +/* / PE <-> HAL statistics messages */ +#define WMA_GET_STATISTICS_REQ SIR_HAL_GET_STATISTICS_REQ +#define WMA_GET_STATISTICS_RSP SIR_HAL_GET_STATISTICS_RSP +#define WMA_SET_KEY_DONE SIR_HAL_SET_KEY_DONE + +/* / PE <-> HAL BTC messages */ +#define WMA_BTC_SET_CFG SIR_HAL_BTC_SET_CFG +#define WMA_HANDLE_FW_MBOX_RSP SIR_HAL_HANDLE_FW_MBOX_RSP + +#ifdef FEATURE_OEM_DATA_SUPPORT +/* PE <-> HAL OEM_DATA RELATED MESSAGES */ +#define WMA_START_OEM_DATA_REQ SIR_HAL_START_OEM_DATA_REQ +#define WMA_START_OEM_DATA_RSP SIR_HAL_START_OEM_DATA_RSP +#endif + +#define WMA_SET_MAX_TX_POWER_REQ SIR_HAL_SET_MAX_TX_POWER_REQ +#define WMA_SET_MAX_TX_POWER_RSP SIR_HAL_SET_MAX_TX_POWER_RSP +#define WMA_SET_TX_POWER_REQ SIR_HAL_SET_TX_POWER_REQ + +#define WMA_SET_MAX_TX_POWER_PER_BAND_REQ \ + SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ + +/* / PE <-> HAL Host Offload message */ +#define WMA_SET_HOST_OFFLOAD SIR_HAL_SET_HOST_OFFLOAD + +/* / PE <-> HAL Keep Alive message */ +#define WMA_SET_KEEP_ALIVE SIR_HAL_SET_KEEP_ALIVE + +#ifdef WLAN_NS_OFFLOAD +#define WMA_SET_NS_OFFLOAD SIR_HAL_SET_NS_OFFLOAD +#endif /* WLAN_NS_OFFLOAD */ +#define WMA_ADD_STA_SELF_REQ SIR_HAL_ADD_STA_SELF_REQ +#define WMA_DEL_STA_SELF_REQ SIR_HAL_DEL_STA_SELF_REQ + +#define WMA_SET_P2P_GO_NOA_REQ SIR_HAL_SET_P2P_GO_NOA_REQ + +#ifdef FEATURE_WLAN_TDLS +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ SIR_HAL_TDLS_LINK_ESTABLISH_REQ +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP +#endif + +#define WMA_WLAN_SUSPEND_IND SIR_HAL_WLAN_SUSPEND_IND +#define WMA_WLAN_RESUME_REQ SIR_HAL_WLAN_RESUME_REQ +#define WMA_MSG_TYPES_END SIR_HAL_MSG_TYPES_END + +#ifdef WLAN_FEATURE_VOWIFI_11R +#define WMA_AGGR_QOS_REQ SIR_HAL_AGGR_QOS_REQ +#define WMA_AGGR_QOS_RSP SIR_HAL_AGGR_QOS_RSP +#endif /* WLAN_FEATURE_VOWIFI_11R */ + +/* FTM CMD MSG */ +#define WMA_FTM_CMD_REQ SIR_PTT_MSG_TYPES_BEGIN +#define WMA_FTM_CMD_RSP SIR_PTT_MSG_TYPES_END +#define WMA_CSA_OFFLOAD_EVENT SIR_CSA_OFFLOAD_EVENT + +#ifdef FEATURE_WLAN_SCAN_PNO +/*Requests sent to lower driver*/ +#define WMA_SET_PNO_REQ SIR_HAL_SET_PNO_REQ + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) +#define WMA_SET_PLM_REQ SIR_HAL_SET_PLM_REQ +#endif + +#define WMA_ROAM_SCAN_OFFLOAD_REQ SIR_HAL_ROAM_SCAN_OFFLOAD_REQ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define WMA_ROAM_OFFLOAD_SYNCH_CNF SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF +#define WMA_ROAM_OFFLOAD_SYNCH_IND SIR_HAL_ROAM_OFFLOAD_SYNCH_IND +#define WMA_ROAM_OFFLOAD_SYNCH_FAIL SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL +#endif + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define WMA_8023_MULTICAST_LIST_REQ SIR_HAL_8023_MULTICAST_LIST_REQ +#define WMA_RECEIVE_FILTER_SET_FILTER_REQ SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP +#define WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +#define WMA_DHCP_START_IND SIR_HAL_DHCP_START_IND +#define WMA_DHCP_STOP_IND SIR_HAL_DHCP_STOP_IND + +#define WMA_HIDDEN_SSID_VDEV_RESTART SIR_HAL_HIDE_SSID_VDEV_RESTART + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define WMA_GTK_OFFLOAD_REQ SIR_HAL_GTK_OFFLOAD_REQ +#define WMA_GTK_OFFLOAD_GETINFO_REQ SIR_HAL_GTK_OFFLOAD_GETINFO_REQ +#define WMA_GTK_OFFLOAD_GETINFO_RSP SIR_HAL_GTK_OFFLOAD_GETINFO_RSP +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#define WMA_SET_TM_LEVEL_REQ SIR_HAL_SET_TM_LEVEL_REQ + +#ifdef WLAN_FEATURE_11AC +#define WMA_UPDATE_OP_MODE SIR_HAL_UPDATE_OP_MODE +#define WMA_UPDATE_RX_NSS SIR_HAL_UPDATE_RX_NSS +#define WMA_UPDATE_MEMBERSHIP SIR_HAL_UPDATE_MEMBERSHIP +#define WMA_UPDATE_USERPOS SIR_HAL_UPDATE_USERPOS +#endif + +#ifdef WLAN_FEATURE_NAN +#define WMA_NAN_REQUEST SIR_HAL_NAN_REQUEST +#endif + +#define WMA_START_SCAN_OFFLOAD_REQ SIR_HAL_START_SCAN_OFFLOAD_REQ +#define WMA_STOP_SCAN_OFFLOAD_REQ SIR_HAL_STOP_SCAN_OFFLOAD_REQ +#define WMA_UPDATE_CHAN_LIST_REQ SIR_HAL_UPDATE_CHAN_LIST_REQ +#define WMA_RX_SCAN_EVENT SIR_HAL_RX_SCAN_EVENT +#define WMA_IBSS_PEER_INACTIVITY_IND SIR_HAL_IBSS_PEER_INACTIVITY_IND + +#define WMA_CLI_SET_CMD SIR_HAL_CLI_SET_CMD +#ifdef FEATURE_WLAN_SCAN_PNO +#define WMA_SME_SCAN_CACHE_UPDATED SIR_HAL_SME_SCAN_CACHE_UPDATED +#endif + +#ifndef REMOVE_PKT_LOG +#define WMA_PKTLOG_ENABLE_REQ SIR_HAL_PKTLOG_ENABLE_REQ +#endif + +#ifdef FEATURE_WLAN_LPHB +#define WMA_LPHB_CONF_REQ SIR_HAL_LPHB_CONF_IND +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define WMA_CH_AVOID_UPDATE_REQ SIR_HAL_CH_AVOID_UPDATE_REQ +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_SET_AUTO_SHUTDOWN_TIMER_REQ SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ +#endif + +#define WMA_ADD_PERIODIC_TX_PTRN_IND SIR_HAL_ADD_PERIODIC_TX_PTRN_IND +#define WMA_DEL_PERIODIC_TX_PTRN_IND SIR_HAL_DEL_PERIODIC_TX_PTRN_IND + +#define WMA_TX_POWER_LIMIT SIR_HAL_SET_TX_POWER_LIMIT + +#define WMA_RATE_UPDATE_IND SIR_HAL_RATE_UPDATE_IND + +#define WMA_INIT_THERMAL_INFO_CMD SIR_HAL_INIT_THERMAL_INFO_CMD +#define WMA_SET_THERMAL_LEVEL SIR_HAL_SET_THERMAL_LEVEL + +#ifdef FEATURE_WLAN_TDLS +#define WMA_UPDATE_FW_TDLS_STATE SIR_HAL_UPDATE_FW_TDLS_STATE +#define WMA_UPDATE_TDLS_PEER_STATE SIR_HAL_UPDATE_TDLS_PEER_STATE +#define WMA_TDLS_SHOULD_DISCOVER_CMD SIR_HAL_TDLS_SHOULD_DISCOVER +#define WMA_TDLS_SHOULD_TEARDOWN_CMD SIR_HAL_TDLS_SHOULD_TEARDOWN +#define WMA_TDLS_PEER_DISCONNECTED_CMD SIR_HAL_TDLS_PEER_DISCONNECTED +#define WMA_TDLS_SET_OFFCHAN_MODE SIR_HAL_TDLS_SET_OFFCHAN_MODE +#endif +#define WMA_SET_SAP_INTRABSS_DIS SIR_HAL_SET_SAP_INTRABSS_DIS + +/* Message to Indicate Radar Presence on SAP Channel */ +#define WMA_DFS_RADAR_IND SIR_HAL_DFS_RADAR_IND + +/* Message to indicate beacon tx completion after beacon template update + * beacon offload case + */ +#define WMA_DFS_BEACON_TX_SUCCESS_IND SIR_HAL_BEACON_TX_SUCCESS_IND +#define WMA_DISASSOC_TX_COMP SIR_HAL_DISASSOC_TX_COMP +#define WMA_DEAUTH_TX_COMP SIR_HAL_DEAUTH_TX_COMP +#define WMA_GET_LINK_SPEED SIR_HAL_GET_LINK_SPEED + +#define WMA_MODEM_POWER_STATE_IND SIR_HAL_MODEM_POWER_STATE_IND + +#ifdef WLAN_FEATURE_STATS_EXT +#define WMA_STATS_EXT_REQUEST SIR_HAL_STATS_EXT_REQUEST +#endif + +#define WMA_IPA_OFFLOAD_ENABLE_DISABLE SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE + +#define WMA_GET_TEMPERATURE_REQ SIR_HAL_GET_TEMPERATURE_REQ + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_EXTSCAN_GET_CAPABILITIES_REQ SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ +#define WMA_EXTSCAN_START_REQ SIR_HAL_EXTSCAN_START_REQ +#define WMA_EXTSCAN_STOP_REQ SIR_HAL_EXTSCAN_STOP_REQ +#define WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_GET_CACHED_RESULTS_REQ SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ +#define WMA_SET_EPNO_LIST_REQ SIR_HAL_SET_EPNO_LIST_REQ +#define WMA_SET_PASSPOINT_LIST_REQ SIR_HAL_SET_PASSPOINT_LIST_REQ +#define WMA_RESET_PASSPOINT_LIST_REQ SIR_HAL_RESET_PASSPOINT_LIST_REQ +#define WMA_EXTSCAN_SET_SSID_HOTLIST_REQ SIR_HAL_EXTSCAN_SET_SSID_HOTLIST_REQ + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define WMA_LINK_LAYER_STATS_CLEAR_REQ SIR_HAL_LL_STATS_CLEAR_REQ +#define WMA_LINK_LAYER_STATS_SET_REQ SIR_HAL_LL_STATS_SET_REQ +#define WMA_LINK_LAYER_STATS_GET_REQ SIR_HAL_LL_STATS_GET_REQ +#define WMA_LINK_LAYER_STATS_RESULTS_RSP SIR_HAL_LL_STATS_RESULTS_RSP +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#define WMA_LINK_STATUS_GET_REQ SIR_HAL_LINK_STATUS_GET_REQ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WMA_WLAN_EXT_WOW SIR_HAL_CONFIG_EXT_WOW +#define WMA_WLAN_SET_APP_TYPE1_PARAMS SIR_HAL_CONFIG_APP_TYPE1_PARAMS +#define WMA_WLAN_SET_APP_TYPE2_PARAMS SIR_HAL_CONFIG_APP_TYPE2_PARAMS +#endif + +#define WMA_SET_SCAN_MAC_OUI_REQ SIR_HAL_SET_SCAN_MAC_OUI_REQ + +#ifdef DHCP_SERVER_OFFLOAD +#define WMA_SET_DHCP_SERVER_OFFLOAD_CMD SIR_HAL_SET_DHCP_SERVER_OFFLOAD +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WMA_LED_FLASHING_REQ SIR_HAL_LED_FLASHING_REQ +#endif + +/* Message posted by wmi when wmi event is received from FW */ +#define WMA_PROCESS_FW_EVENT SIR_HAL_PROCESS_FW_EVENT + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define WMA_UPDATE_Q2Q_IE_IND SIR_HAL_UPDATE_Q2Q_IE_IND +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define WMA_SET_RSSI_MONITOR_REQ SIR_HAL_SET_RSSI_MONITOR_REQ + +#define WMA_FW_MEM_DUMP_REQ SIR_HAL_FW_MEM_DUMP_REQ + +#define WMA_OCB_SET_CONFIG_CMD SIR_HAL_OCB_SET_CONFIG_CMD +#define WMA_OCB_SET_UTC_TIME_CMD SIR_HAL_OCB_SET_UTC_TIME_CMD +#define WMA_OCB_START_TIMING_ADVERT_CMD SIR_HAL_OCB_START_TIMING_ADVERT_CMD +#define WMA_OCB_STOP_TIMING_ADVERT_CMD SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD +#define WMA_OCB_GET_TSF_TIMER_CMD SIR_HAL_OCB_GET_TSF_TIMER_CMD +#define WMA_DCC_GET_STATS_CMD SIR_HAL_DCC_GET_STATS_CMD +#define WMA_DCC_CLEAR_STATS_CMD SIR_HAL_DCC_CLEAR_STATS_CMD +#define WMA_DCC_UPDATE_NDL_CMD SIR_HAL_DCC_UPDATE_NDL_CMD +#define WMA_SET_IE_INFO SIR_HAL_SET_IE_INFO + +#define WMA_LRO_CONFIG_CMD SIR_HAL_LRO_CONFIG_CMD + +/* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 + +#define wma_tx_frame(hHal, pFrmBuf, frmLen, frmType, txDir, tid, pCompFunc, \ + pData, txFlag, sessionid, channel_freq) \ + (CDF_STATUS)( wma_tx_packet( \ + cds_get_context(CDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (NULL), \ + (txFlag), \ + (sessionid), \ + (false), \ + (channel_freq))) + +#define wma_tx_frameWithTxComplete(hHal, pFrmBuf, frmLen, frmType, txDir, tid, \ + pCompFunc, pData, pCBackFnTxComp, txFlag, sessionid, tdlsflag, \ + channel_freq) \ + (CDF_STATUS)( wma_tx_packet( \ + cds_get_context(CDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (pCBackFnTxComp), \ + (txFlag), \ + (sessionid), \ + (tdlsflag), \ + (channel_freq))) + + +#define WMA_SetEnableSSR(enable_ssr) ((void)enable_ssr) + +/** + * struct sUapsd_Params - Powersave Offload Changes + * @bkDeliveryEnabled: BK delivery enabled flag + * @beDeliveryEnabled: BE delivery enabled flag + * @viDeliveryEnabled: VI delivery enabled flag + * @voDeliveryEnabled: VO delivery enabled flag + * @bkTriggerEnabled: BK trigger enabled flag + * @beTriggerEnabled: BE trigger enabled flag + * @viTriggerEnabled: VI trigger enabled flag + * @voTriggerEnabled: VO trigger enabled flag + */ +typedef struct sUapsd_Params { + uint8_t bkDeliveryEnabled:1; + uint8_t beDeliveryEnabled:1; + uint8_t viDeliveryEnabled:1; + uint8_t voDeliveryEnabled:1; + uint8_t bkTriggerEnabled:1; + uint8_t beTriggerEnabled:1; + uint8_t viTriggerEnabled:1; + uint8_t voTriggerEnabled:1; +} tUapsd_Params, *tpUapsd_Params; + +/** + * struct sEnablePsParams - Enable PowerSave Params + * @psSetting: power save setting + * @uapsdParams: UAPSD Parameters + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @bcnDtimPeriod: beacon DTIM Period + * @status: success/failure + */ +typedef struct sEnablePsParams { + tSirAddonPsReq psSetting; + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint8_t bcnDtimPeriod; + uint32_t status; +} tEnablePsParams, *tpEnablePsParams; + +/** + * struct sDisablePsParams - Disable PowerSave Params + * @psSetting: power save setting + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @status: success/failure + */ +typedef struct sDisablePsParams { + tSirAddonPsReq psSetting; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tDisablePsParams, *tpDisablePsParams; + +/** + * struct sEnableUapsdParams - Enable Uapsd Params + * @uapsdParams: UAPSD parameters + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sEnableUapsdParams { + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tEnableUapsdParams, *tpEnableUapsdParams; + +/** + * struct sDisableUapsdParams - Disable Uapsd Params + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sDisableUapsdParams { + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tDisableUapsdParams, *tpDisableUapsdParams; + +typedef void (*pWMATxRxCompFunc)(void *pContext, void *pData, + bool bFreeData); + +/* callback function for TX complete */ +/* parameter 1 - global pMac pointer */ +/* parameter 2 - txComplete status : 1- success, 0 - failure. */ +typedef CDF_STATUS (*pWMAAckFnTxComp)(tpAniSirGlobal, uint32_t); + +/* generic callback for updating parameters from target to UMAC */ +typedef void (*wma_tgt_cfg_cb)(void *context, void *param); + +/* + * callback for Indicating Radar to HDD and disable Tx Queues + * to stop accepting data Tx packets from netif as radar is + * found on the current operating channel + */ +typedef void (*wma_dfs_radar_indication_cb)(void *context, void *param); + +/** + * struct wma_cli_set_cmd_t - set command parameters + * @param_id: parameter id + * @param_value: parameter value + * @param_sec_value: parameter sec value + * @param_vdev_id: parameter vdev id + * @param_vp_dev: is it per vdev/pdev + */ +typedef struct { + uint32_t param_id; + uint32_t param_value; + uint32_t param_sec_value; + uint32_t param_vdev_id; + uint32_t param_vp_dev; +} wma_cli_set_cmd_t; + +#if defined(QCA_WIFI_FTM) +#define AR6K_TM_DATA_MAX_LEN 5000 +struct ar6k_testmode_cmd_data { + void *data; + int len; +}; +#endif + +#ifdef FEATURE_WLAN_TDLS +/** + * enum WMA_TdlsPeerState - TDLS PEER state + * @WMA_TDLS_PEER_STATE_PEERING: peer is making connection + * @WMA_TDLS_PEER_STATE_CONNECTED: peer is connected + * @WMA_TDLS_PEER_STATE_TEARDOWN: peer is teardown + */ +typedef enum { + WMA_TDLS_PEER_STATE_PEERING, + WMA_TDLS_PEER_STATE_CONNECTED, + WMA_TDLS_PEER_STATE_TEARDOWN, +} WMA_TdlsPeerState; + +/** + * enum wma_tdls_off_chan_mode - modes for WMI_TDLS_SET_OFFCHAN_MODE_CMDID + * @WMA_TDLS_ENABLE_OFFCHANNEL: enable off channel + * @WMA_TDLS_DISABLE_OFFCHANNEL: disable off channel + */ +typedef enum { + WMA_TDLS_ENABLE_OFFCHANNEL, + WMA_TDLS_DISABLE_OFFCHANNEL +} wma_tdls_off_chan_mode; + +#endif /* FEATURE_WLAN_TDLS */ + +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb); + +CDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps); +CDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req); + +CDF_STATUS +wma_ds_peek_rx_packet_info + (cds_pkt_t *vosDataBuff, void **ppRxHeader, bool bSwap); + + +void wma_tx_abort(uint8_t vdev_id); + +CDF_STATUS wma_tx_packet(void *pWMA, + void *pFrmBuf, + uint16_t frmLen, + eFrameType frmType, + eFrameTxDir txDir, + uint8_t tid, + pWMATxRxCompFunc pCompFunc, + void *pData, + pWMAAckFnTxComp pAckTxComp, + uint8_t txFlag, uint8_t sessionId, bool tdlsflag, + uint16_t channel_freq); + +CDF_STATUS wma_open(void *p_cds_context, + wma_tgt_cfg_cb pTgtUpdCB, + wma_dfs_radar_indication_cb radar_ind_cb, + tMacOpenParameters *pMacParams); + +typedef CDF_STATUS (*wma_mgmt_frame_rx_callback)(void *p_cds_gctx, + void *cds_buff); + +CDF_STATUS wma_register_mgmt_frm_client(void *p_cds_gctx, + wma_mgmt_frame_rx_callback mgmt_rx_cb); + +CDF_STATUS wma_de_register_mgmt_frm_client(void *p_cds_gctx); + + +#endif diff --git a/core/wma/src/wlan_qct_wma_legacy.c b/core/wma/src/wlan_qct_wma_legacy.c new file mode 100644 index 0000000000..e11d46ece7 --- /dev/null +++ b/core/wma/src/wlan_qct_wma_legacy.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_qct_wma_legacy.c + * + * This software unit holds the implementation of the WLAN Device Adaptation + * Layer for the legacy functionalities that were part of the old HAL. + * + * The functions externalized by this module are to be called ONLY by other + * WLAN modules that properly register with the Transport Layer initially. + * + */ + +/* Standard include files */ +/* Application Specific include files */ +#include "lim_api.h" +#include "cfg_api.h" +#include "wma.h" +#include "sme_power_save_api.h" +/* Locally used Defines */ + +#define HAL_MMH_MB_MSG_TYPE_MASK 0xFF00 + +/** + * wma_post_ctrl_msg() - Posts WMA messages to MC thread + * @pMac: MAC parameters structure + * @pMsg: pointer with message + * + * Return: Success or Failure + */ + +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_WMA, (cds_msg_t *) pMsg)) + return eSIR_FAILURE; + else + return eSIR_SUCCESS; +} + +/** + * wma_post_cfg_msg() - Posts MNT messages to gSirMntMsgQ + * @pMac: MAC parameters structure + * @pMsg: A pointer to the msg + * + * Return: Success or Failure + */ + +tSirRetStatus wma_post_cfg_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + tSirRetStatus rc = eSIR_SUCCESS; + + do { + /* + *For Windows based MAC, instead of posting message to different + * queues we will call the handler routines directly + */ + + cfg_process_mb_msg(pMac, (tSirMbMsg *) pMsg->bodyptr); + rc = eSIR_SUCCESS; + } while (0); + + return rc; +} + +/** + * u_mac_post_ctrl_msg() - post ctrl msg + * @pMb: A pointer to the maibox message + * + * Forwards the completely received message to the respective + * modules for further processing. + * + * NOTE: + * This function has been moved to the API file because for MAC running + * on Windows host, the host module will call this routine directly to + * send any mailbox messages. Making this function an API makes sure that + * outside world (any module outside MMH) only calls APIs to use MMH + * services and not an internal function. + * + * Return: success/error code + */ + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pSirGlobal; + + tSirMbMsg *pMbLocal; + msg.type = pMb->type; + msg.bodyval = 0; + + pMbLocal = cdf_mem_malloc(pMb->msgLen); + if (!pMbLocal) { + WMA_LOGE("Memory allocation failed! Can't send 0x%x\n", + msg.type); + return eSIR_MEM_ALLOC_FAILED; + } + + cdf_mem_copy((void *)pMbLocal, (void *)pMb, pMb->msgLen); + msg.bodyptr = pMbLocal; + + switch (msg.type & HAL_MMH_MB_MSG_TYPE_MASK) { + case WMA_MSG_TYPES_BEGIN: /* Posts a message to the HAL MsgQ */ + wma_post_ctrl_msg(pMac, &msg); + break; + + case SIR_LIM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + lim_post_msg_api(pMac, &msg); + break; + + case SIR_CFG_MSG_TYPES_BEGIN: /* Posts a message to the CFG MsgQ */ + wma_post_cfg_msg(pMac, &msg); + break; + + case SIR_PMM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + sme_post_pe_message(pMac, &msg); + break; + + case SIR_PTT_MSG_TYPES_BEGIN: + cdf_mem_free(msg.bodyptr); + break; + + default: + WMA_LOGD("Unknown message type = 0x%X\n", msg.type); + cdf_mem_free(msg.bodyptr); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} /* u_mac_post_ctrl_msg() */ + diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c new file mode 100644 index 0000000000..872863abd5 --- /dev/null +++ b/core/wma/src/wma_data.c @@ -0,0 +1,3084 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_data.c + * This file contains tx/rx and data path related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +typedef struct { + int32_t rate; + uint8_t flag; +} wma_search_rate_t; + +#define WMA_MAX_OFDM_CCK_RATE_TBL_SIZE 12 +/* In ofdm_cck_rate_tbl->flag, if bit 7 is 1 it's CCK, otherwise it ofdm. + * Lower bit carries the ofdm/cck index for encoding the rate + */ +static wma_search_rate_t ofdm_cck_rate_tbl[WMA_MAX_OFDM_CCK_RATE_TBL_SIZE] = { + {540, 4}, /* 4: OFDM 54 Mbps */ + {480, 0}, /* 0: OFDM 48 Mbps */ + {360, 5}, /* 5: OFDM 36 Mbps */ + {240, 1}, /* 1: OFDM 24 Mbps */ + {180, 6}, /* 6: OFDM 18 Mbps */ + {120, 2}, /* 2: OFDM 12 Mbps */ + {110, (1 << 7)}, /* 0: CCK 11 Mbps Long */ + {90, 7}, /* 7: OFDM 9 Mbps */ + {60, 3}, /* 3: OFDM 6 Mbps */ + {55, ((1 << 7) | 1)}, /* 1: CCK 5.5 Mbps Long */ + {20, ((1 << 7) | 2)}, /* 2: CCK 2 Mbps Long */ + {10, ((1 << 7) | 3)} /* 3: CCK 1 Mbps Long */ +}; + +#define WMA_MAX_VHT20_RATE_TBL_SIZE 9 +/* In vht20_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht20_400ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {867, 8}, /* MCS8 1SS short GI */ + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +/* In vht20_800ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht20_800ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {780, 8}, /* MCS8 1SS long GI */ + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT40_RATE_TBL_SIZE 10 +/* In vht40_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht40_400ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {2000, 9}, /* MCS9 1SS short GI */ + {1800, 8}, /* MCS8 1SS short GI */ + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0}, /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t vht40_800ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {1800, 9}, /* MCS9 1SS long GI */ + {1620, 8}, /* MCS8 1SS long GI */ + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT80_RATE_TBL_SIZE 10 +static wma_search_rate_t vht80_400ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {4333, 9}, /* MCS9 1SS short GI */ + {3900, 8}, /* MCS8 1SS short GI */ + {3250, 7}, /* MCS7 1SS short GI */ + {2925, 6}, /* MCS6 1SS short GI */ + {2600, 5}, /* MCS5 1SS short GI */ + {1950, 4}, /* MCS4 1SS short GI */ + {1300, 3}, /* MCS3 1SS short GI */ + {975, 2}, /* MCS2 1SS short GI */ + {650, 1}, /* MCS1 1SS short GI */ + {325, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t vht80_800ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {3900, 9}, /* MCS9 1SS long GI */ + {3510, 8}, /* MCS8 1SS long GI */ + {2925, 7}, /* MCS7 1SS long GI */ + {2633, 6}, /* MCS6 1SS long GI */ + {2340, 5}, /* MCS5 1SS long GI */ + {1755, 4}, /* MCS4 1SS long GI */ + {1170, 3}, /* MCS3 1SS long GI */ + {878, 2}, /* MCS2 1SS long GI */ + {585, 1}, /* MCS1 1SS long GI */ + {293, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT20_RATE_TBL_SIZE 8 +static wma_search_rate_t ht20_400ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t ht20_800ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT40_RATE_TBL_SIZE 8 +static wma_search_rate_t ht40_400ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t ht40_800ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +/** + * wma_bin_search_rate() - binary search function to find rate + * @tbl: rate table + * @tbl_size: table size + * @mbpsx10_rate: return mbps rate + * @ret_flag: return flag + * + * Return: none + */ +static void wma_bin_search_rate(wma_search_rate_t *tbl, int32_t tbl_size, + int32_t *mbpsx10_rate, uint8_t *ret_flag) +{ + int32_t upper, lower, mid; + + /* the table is descenting. index holds the largest value and the + * bottom index holds the smallest value */ + + upper = 0; /* index 0 */ + lower = tbl_size - 1; /* last index */ + + if (*mbpsx10_rate >= tbl[upper].rate) { + /* use the largest rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; + } else if (*mbpsx10_rate <= tbl[lower].rate) { + /* use the smallest rate */ + *mbpsx10_rate = tbl[lower].rate; + *ret_flag = tbl[lower].flag; + return; + } + /* now we do binery search to get the floor value */ + while (lower - upper > 1) { + mid = (upper + lower) >> 1; + if (*mbpsx10_rate == tbl[mid].rate) { + /* found the exact match */ + *mbpsx10_rate = tbl[mid].rate; + *ret_flag = tbl[mid].flag; + return; + } else { + /* not found. if mid's rate is larger than input move + * upper to mid. If mid's rate is larger than input + * move lower to mid. + */ + if (*mbpsx10_rate > tbl[mid].rate) + lower = mid; + else + upper = mid; + } + } + /* after the bin search the index is the ceiling of rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; +} + +/** + * wma_fill_ofdm_cck_mcast_rate() - fill ofdm cck mcast rate + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_ofdm_cck_mcast_rate(int32_t mbpsx10_rate, + uint8_t nss, uint8_t *rate) +{ + uint8_t idx = 0; + wma_bin_search_rate(ofdm_cck_rate_tbl, WMA_MAX_OFDM_CCK_RATE_TBL_SIZE, + &mbpsx10_rate, &idx); + + /* if bit 7 is set it uses CCK */ + if (idx & 0x80) + *rate |= (1 << 6) | (idx & 0xF); /* set bit 6 to 1 for CCK */ + else + *rate |= (idx & 0xF); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_ht_vht_mcast_rate() - set ht/vht mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @sgi_idx: shortgi index + * @sgi_rate: shortgi rate + * @lgi_idx: longgi index + * @lgi_rate: longgi rate + * @premable: preamble + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: none + */ +static void wma_set_ht_vht_mcast_rate(uint32_t shortgi, int32_t mbpsx10_rate, + uint8_t sgi_idx, int32_t sgi_rate, + uint8_t lgi_idx, int32_t lgi_rate, + uint8_t premable, uint8_t *rate, + int32_t *streaming_rate) +{ + if (shortgi == 0) { + *rate |= (premable << 6) | (lgi_idx & 0xF); + *streaming_rate = lgi_rate; + } else { + *rate |= (premable << 6) | (sgi_idx & 0xF); + *streaming_rate = sgi_rate; + } +} + +/** + * wma_fill_ht20_mcast_rate() - fill ht20 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_ht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht20_400ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht20_800ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht40_mcast_rate() - fill ht40 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_ht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht40_400ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht40_800ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht20_mcast_rate() - fill vht20 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_vht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht20_400ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht20_800ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht40_mcast_rate() - fill vht40 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_vht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht40_400ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht40_800ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, + sgi_idx, sgi_rate, lgi_idx, lgi_rate, + 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht80_mcast_rate() - fill vht80 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_vht80_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht80_400ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht80_800ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht_mcast_rate() - fill ht mcast rate + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_ht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, int32_t mbpsx10_rate, + uint8_t nss, WLAN_PHY_MODE chanmode, + uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_ht20_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_ht40_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else + WMA_LOGE("%s: Error, Invalid chwidth enum %d", __func__, + chwidth); + return (*streaming_rate != 0) ? CDF_STATUS_SUCCESS : CDF_STATUS_E_INVAL; +} + +/** + * wma_fill_vht_mcast_rate() - fill vht mcast rate + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: CDF status + */ +static CDF_STATUS wma_fill_vht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, + int32_t mbpsx10_rate, uint8_t nss, + WLAN_PHY_MODE chanmode, + uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_vht20_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_vht40_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 2) + ret = wma_fill_vht80_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else + WMA_LOGE("%s: chwidth enum %d not supported", + __func__, chwidth); + return (*streaming_rate != 0) ? CDF_STATUS_SUCCESS : CDF_STATUS_E_INVAL; +} + +#define WMA_MCAST_1X1_CUT_OFF_RATE 2000 +/** + * wma_encode_mc_rate() - fill mc rates + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: CDF status + */ +static CDF_STATUS wma_encode_mc_rate(uint32_t shortgi, uint32_t chwidth, + WLAN_PHY_MODE chanmode, A_UINT32 mhz, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate) +{ + int32_t ret = 0; + + /* nss input value: 0 - 1x1; 1 - 2x2; 2 - 3x3 + * the phymode selection is based on following assumption: + * (1) if the app specifically requested 1x1 or 2x2 we hornor it + * (2) if mbpsx10_rate <= 540: always use BG + * (3) 540 < mbpsx10_rate <= 2000: use 1x1 HT/VHT + * (4) 2000 < mbpsx10_rate: use 2x2 HT/VHT + */ + WMA_LOGE("%s: Input: nss = %d, chanmode = %d, " + "mbpsx10 = 0x%x, chwidth = %d, shortgi = %d", + __func__, nss, chanmode, mbpsx10_rate, chwidth, shortgi); + if ((mbpsx10_rate & 0x40000000) && nss > 0) { + /* bit 30 indicates user inputed nss, + * bit 28 and 29 used to encode nss + */ + uint8_t user_nss = (mbpsx10_rate & 0x30000000) >> 28; + + nss = (user_nss < nss) ? user_nss : nss; + /* zero out bits 19 - 21 to recover the actual rate */ + mbpsx10_rate &= ~0x70000000; + } else if (mbpsx10_rate <= WMA_MCAST_1X1_CUT_OFF_RATE) { + /* if the input rate is less or equal to the + * 1x1 cutoff rate we use 1x1 only + */ + nss = 0; + } + /* encode NSS bits (bit 4, bit 5) */ + *rate = (nss & 0x3) << 4; + /* if mcast input rate exceeds the ofdm/cck max rate 54mpbs + * we try to choose best ht/vht mcs rate + */ + if (540 < mbpsx10_rate) { + /* cannot use ofdm/cck, choose closest ht/vht mcs rate */ + uint8_t rate_ht = *rate; + uint8_t rate_vht = *rate; + int32_t stream_rate_ht = 0; + int32_t stream_rate_vht = 0; + int32_t stream_rate = 0; + + ret = wma_fill_ht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, chanmode, &rate_ht, + &stream_rate_ht); + if (ret != CDF_STATUS_SUCCESS) { + stream_rate_ht = 0; + } + if (mhz < WMA_2_4_GHZ_MAX_FREQ) { + /* not in 5 GHZ frequency */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + /* capable doing 11AC mcast so that search vht tables */ + ret = wma_fill_vht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, chanmode, &rate_vht, + &stream_rate_vht); + if (ret != CDF_STATUS_SUCCESS) { + if (stream_rate_ht != 0) + ret = CDF_STATUS_SUCCESS; + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + if (stream_rate_ht == 0) { + /* only vht rate available */ + *rate = rate_vht; + stream_rate = stream_rate_vht; + } else { + /* set ht as default first */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + if (stream_rate < mbpsx10_rate) { + if (mbpsx10_rate <= stream_rate_vht || + stream_rate < stream_rate_vht) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } else { + if (stream_rate_vht >= mbpsx10_rate && + stream_rate_vht < stream_rate) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } + } +ht_vht_done: + WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, " + "freq = %d, input_rate = %d, chwidth = %d " + "rate = 0x%x, streaming_rate = %d", + __func__, nss, chanmode, mhz, + mbpsx10_rate, chwidth, *rate, stream_rate); + } else { + if (mbpsx10_rate > 0) + ret = wma_fill_ofdm_cck_mcast_rate(mbpsx10_rate, + nss, rate); + else + *rate = 0xFF; + + WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, " + "input_rate = %d, rate = 0x%x", + __func__, nss, chanmode, mbpsx10_rate, *rate); + } + return ret; +} + +/** + * wma_set_bss_rate_flags() - set rate flags based on BSS capability + * @iface: txrx_node ctx + * @add_bss: add_bss params + * + * Return: none + */ +void wma_set_bss_rate_flags(struct wma_txrx_node *iface, + tpAddBssParams add_bss) +{ + iface->rate_flags = 0; + + if (add_bss->vhtCapable) { + if (add_bss->ch_width == CH_WIDTH_80P80MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_160MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_80MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + else if (add_bss->ch_width) + iface->rate_flags |= eHAL_TX_RATE_VHT40; + else + iface->rate_flags |= eHAL_TX_RATE_VHT20; + } + /* avoid to conflict with htCapable flag */ + else if (add_bss->htCapable) { + if (add_bss->ch_width) + iface->rate_flags |= eHAL_TX_RATE_HT40; + else + iface->rate_flags |= eHAL_TX_RATE_HT20; + } + + if (add_bss->staContext.fShortGI20Mhz || + add_bss->staContext.fShortGI40Mhz) + iface->rate_flags |= eHAL_TX_RATE_SGI; + + if (!add_bss->htCapable && !add_bss->vhtCapable) + iface->rate_flags = eHAL_TX_RATE_LEGACY; +} + +/** + * wmi_unified_send_txbf() - set txbf parameter to fw + * @wma: wma handle + * @params: txbf parameters + * + * Return: 0 for success or error code + */ +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params) +{ + wmi_vdev_txbf_en txbf_en; + + /* This is set when Other partner is Bformer + * and we are capable bformee(enabled both in ini and fw) + */ + txbf_en.sutxbfee = params->vhtTxBFCapable; + txbf_en.mutxbfee = params->vhtTxMUBformeeCapable; + txbf_en.sutxbfer = params->enable_su_tx_bformer; + txbf_en.mutxbfer = 0; + + /* When MU TxBfee is set, SU TxBfee must be set by default */ + if (txbf_en.mutxbfee) + txbf_en.sutxbfee = txbf_en.mutxbfee; + + WMA_LOGD("txbf_en.sutxbfee %d txbf_en.mutxbfee %d, sutxbfer %d", + txbf_en.sutxbfee, txbf_en.mutxbfee, txbf_en.sutxbfer); + + return wmi_unified_vdev_set_param_send(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_TXBF, + *((A_UINT8 *) &txbf_en)); +} + +/** + * wma_data_tx_ack_work_handler() - process data tx ack + * @ack_work: work structure + * + * Return: none + */ +static void wma_data_tx_ack_work_handler(struct work_struct *ack_work) +{ + struct wma_tx_ack_work_ctx *work; + tp_wma_handle wma_handle; + pWMAAckFnTxComp ack_cb; + + if (cds_is_load_unload_in_progress()) { + WMA_LOGE("%s: Driver load/unload in progress", __func__); + return; + } + + work = container_of(ack_work, struct wma_tx_ack_work_ctx, ack_cmp_work); + wma_handle = work->wma_handle; + ack_cb = wma_handle->umac_data_ota_ack_cb; + + if (work->status) + WMA_LOGE("Data Tx Ack Cb Status %d", work->status); + else + WMA_LOGD("Data Tx Ack Cb Status %d", work->status); + + /* Call the Ack Cb registered by UMAC */ + if (ack_cb) + ack_cb((tpAniSirGlobal) (wma_handle->mac_context), + work->status ? 0 : 1); + else + WMA_LOGE("Data Tx Ack Cb is NULL"); + + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + cdf_mem_free(work); + wma_handle->ack_work_ctx = NULL; +} + +/** + * wma_data_tx_ack_comp_hdlr() - handles tx data ack completion + * @context: context with which the handler is registered + * @netbuf: tx data nbuf + * @err: status of tx completion + * + * This is the cb registered with TxRx for + * Ack Complete + * + * Return: none + */ +void +wma_data_tx_ack_comp_hdlr(void *wma_context, cdf_nbuf_t netbuf, int32_t status) +{ + ol_txrx_pdev_handle pdev; + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid WMA Handle", __func__); + return; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return; + } + + /* + * if netBuf does not match with pending nbuf then just free the + * netbuf and do not call ack cb + */ + if (wma_handle->last_umac_data_nbuf != netbuf) { + if (wma_handle->umac_data_ota_ack_cb) { + WMA_LOGE("%s: nbuf does not match but umac_data_ota_ack_cb is not null", + __func__); + } else { + WMA_LOGE("%s: nbuf does not match and umac_data_ota_ack_cb is also null", + __func__); + } + goto free_nbuf; + } + + if (wma_handle && wma_handle->umac_data_ota_ack_cb) { + struct wma_tx_ack_work_ctx *ack_work; + + ack_work = cdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + wma_handle->ack_work_ctx = ack_work; + if (ack_work) { +#ifdef CONFIG_CNSS + cnss_init_work(&ack_work->ack_cmp_work, + wma_data_tx_ack_work_handler); +#else + INIT_WORK(&ack_work->ack_cmp_work, + wma_data_tx_ack_work_handler); +#endif /* CONFIG_CNSS */ + ack_work->wma_handle = wma_handle; + ack_work->sub_type = 0; + ack_work->status = status; + + /* Schedue the Work */ + schedule_work(&ack_work->ack_cmp_work); + } + } + +free_nbuf: + /* unmap and freeing the tx buf as txrx is not taking care */ + cdf_nbuf_unmap_single(pdev->osdev, netbuf, CDF_DMA_TO_DEVICE); + cdf_nbuf_free(netbuf); +} + +/** + * wma_update_txrx_chainmask() - update txrx chainmask + * @num_rf_chains: number rf chains + * @cmd_value: command value + * + * Return: none + */ +void wma_update_txrx_chainmask(int num_rf_chains, int *cmd_value) +{ + if (*cmd_value > WMA_MAX_RF_CHAINS(num_rf_chains)) { + WMA_LOGE("%s: Chainmask value exceeds the maximum" + " supported range setting it to" + " maximum value. Requested value %d" + " Updated value %d", __func__, *cmd_value, + WMA_MAX_RF_CHAINS(num_rf_chains)); + *cmd_value = WMA_MAX_RF_CHAINS(num_rf_chains); + } else if (*cmd_value < WMA_MIN_RF_CHAINS) { + WMA_LOGE("%s: Chainmask value is less than the minimum" + " supported range setting it to" + " minimum value. Requested value %d" + " Updated value %d", __func__, *cmd_value, + WMA_MIN_RF_CHAINS); + *cmd_value = WMA_MIN_RF_CHAINS; + } +} + +/** + * wma_peer_state_change_event_handler() - peer state change event handler + * @handle: wma handle + * @event_buff: event buffer + * @len: length of buffer + * + * This event handler unpauses vdev if peer state change to AUTHORIZED STATE + * + * Return: 0 for success or error code + */ +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len) +{ + WMI_PEER_STATE_EVENTID_param_tlvs *param_buf; + wmi_peer_state_event_fixed_param *event; + ol_txrx_vdev_handle vdev; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!event_buff) { + WMA_LOGE("%s: Received NULL event ptr from FW", __func__); + return -EINVAL; + } + param_buf = (WMI_PEER_STATE_EVENTID_param_tlvs *) event_buff; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + event = param_buf->fixed_param; + vdev = wma_find_vdev_by_id(wma_handle, event->vdev_id); + if (NULL == vdev) { + WMA_LOGP("%s: Couldn't find vdev for vdev_id: %d", + __func__, event->vdev_id); + return -EINVAL; + } + + if (vdev->opmode == wlan_op_mode_sta + && event->state == WMI_PEER_STATE_AUTHORIZED) { + /* + * set event so that hdd + * can procced and unpause tx queue + */ +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (!wma_handle->peer_authorized_cb) { + WMA_LOGE("%s: peer authorized cb not registered", + __func__); + return -EINVAL; + } + wma_handle->peer_authorized_cb(vdev->vdev_id); +#endif + } + + return 0; +} + +/** + * wma_set_enable_disable_mcc_adaptive_scheduler() -enable/disable mcc scheduler + * @mcc_adaptive_scheduler: enable/disable + * + * This function enable/disable mcc adaptive scheduler in fw. + * + * Return: CDF_STATUS_SUCCESS for sucess or error code + */ +CDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler) +{ + int ret = -1; + wmi_buf_t buf = 0; + wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL; + tp_wma_handle wma = NULL; + uint16_t len = + sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param); + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s : Failed to get wma", __func__); + return CDF_STATUS_E_FAULT; + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param)); + cmd->enable = mcc_adaptive_scheduler; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + if (ret) { + WMA_LOGP("%s: Failed to send enable/disable MCC" + " adaptive scheduler command", __func__); + cdf_nbuf_free(buf); + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_mcc_channel_time_latency() -set MCC channel time latency + * @wma: wma handle + * @mcc_channel: mcc channel + * @mcc_channel_time_latency: MCC channel time latency. + * + * Currently used to set time latency for an MCC vdev/adapter using operating + * channel of it and channel number. The info is provided run time using + * iwpriv command: iwpriv setMccLatency . + * + * Return: CDF status + */ +CDF_STATUS wma_set_mcc_channel_time_latency + (tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency) +{ + int ret = -1; + wmi_buf_t buf = 0; + wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL; + uint16_t len = 0; + uint8_t *buf_ptr = NULL; + uint32_t cfg_val = 0; + wmi_resmgr_chan_latency chan_latency; + struct sAniSirGlobal *pMac = NULL; + /* Note: we only support MCC time latency for a single channel */ + uint32_t num_channels = 1; + uint32_t channel1 = mcc_channel; + uint32_t chan1_freq = cds_chan_to_freq(channel1); + uint32_t latency_chan1 = mcc_channel_time_latency; + + if (!wma) { + WMA_LOGE("%s:NULL wma ptr. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGE("%s: MCC is not active. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel latency while MCC " + "ADAPTIVE SCHED is enabled. Exit", __func__); + return CDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to get value for MCC_ADAPTIVE_SCHED, " + "Exit w/o setting latency", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + /* If 0ms latency is provided, then FW will set to a default. + * Otherwise, latency must be at least 30ms. + */ + if ((latency_chan1 > 0) && + (latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) { + WMA_LOGE("%s: Invalid time latency for Channel #1 = %dms " + "Minimum is 30ms (or 0 to use default value by " + "firmware)", __func__, latency_chan1); + return CDF_STATUS_E_INVAL; + } + + /* Set WMI CMD for channel time latency here */ + len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + /*Place holder for chan_time_latency array */ + num_channels * sizeof(wmi_resmgr_chan_latency); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmdTL->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_set_chan_latency_cmd_fixed_param)); + cmdTL->num_chans = num_channels; + /* Update channel time latency information for home channel(s) */ + buf_ptr += sizeof(*cmdTL); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + num_channels * sizeof(wmi_resmgr_chan_latency)); + buf_ptr += WMI_TLV_HDR_SIZE; + chan_latency.chan_mhz = chan1_freq; + chan_latency.latency = latency_chan1; + cdf_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency)); + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send MCC Channel Time Latency command", + __func__); + cdf_nbuf_free(buf); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_mcc_channel_time_quota() -set MCC channel time quota + * @wma: wma handle + * @adapter_1_chan_number: adapter 1 channel number + * @adapter_1_quota: adapter 1 quota + * @adapter_2_chan_number: adapter 2 channel number + * + * Currently used to set time quota for 2 MCC vdevs/adapters using (operating + * channel, quota) for each mode . The info is provided run time using + * iwpriv command: iwpriv setMccQuota . + * Note: the quota provided in command is for the same mode in cmd. HDD + * checks if MCC mode is active, gets the second mode and its operating chan. + * Quota for the 2nd role is calculated as 100 - quota of first mode. + * + * Return: CDF status + */ +CDF_STATUS wma_set_mcc_channel_time_quota + (tp_wma_handle wma, + uint32_t adapter_1_chan_number, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_number) +{ + int ret = -1; + wmi_buf_t buf = 0; + uint16_t len = 0; + uint8_t *buf_ptr = NULL; + uint32_t cfg_val = 0; + struct sAniSirGlobal *pMac = NULL; + wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL; + wmi_resmgr_chan_time_quota chan_quota; + uint32_t channel1 = adapter_1_chan_number; + uint32_t channel2 = adapter_2_chan_number; + uint32_t quota_chan1 = adapter_1_quota; + /* Knowing quota of 1st chan., derive quota for 2nd chan. */ + uint32_t quota_chan2 = 100 - quota_chan1; + /* Note: setting time quota for MCC requires info for 2 channels */ + uint32_t num_channels = 2; + uint32_t chan1_freq = cds_chan_to_freq(adapter_1_chan_number); + uint32_t chan2_freq = cds_chan_to_freq(adapter_2_chan_number); + + WMA_LOGD("%s: Channel1:%d, freq1:%dMHz, Quota1:%dms, " + "Channel2:%d, freq2:%dMHz, Quota2:%dms", __func__, + channel1, chan1_freq, quota_chan1, channel2, chan2_freq, + quota_chan2); + + if (!wma) { + WMA_LOGE("%s:NULL wma ptr. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGD("%s: MCC is not active. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel quota while " + "MCC_ADAPTIVE_SCHED is enabled. Exit", + __func__); + return CDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to retrieve " + "WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED. Exit", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + /* + * Perform sanity check on time quota values provided. + */ + if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA || + quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) { + WMA_LOGE("%s: Invalid time quota for Channel #1=%dms. Minimum " + "is 20ms & maximum is 80ms", __func__, quota_chan1); + return CDF_STATUS_E_INVAL; + } + /* Set WMI CMD for channel time quota here */ + len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + /* Place holder for chan_time_quota array */ + num_channels * sizeof(wmi_resmgr_chan_time_quota); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmdTQ->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_set_chan_time_quota_cmd_fixed_param)); + cmdTQ->num_chans = num_channels; + + /* Update channel time quota information for home channel(s) */ + buf_ptr += sizeof(*cmdTQ); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + num_channels * sizeof(wmi_resmgr_chan_time_quota)); + buf_ptr += WMI_TLV_HDR_SIZE; + chan_quota.chan_mhz = chan1_freq; + chan_quota.channel_time_quota = quota_chan1; + cdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); + /* Construct channel and quota record for the 2nd MCC mode. */ + buf_ptr += sizeof(chan_quota); + chan_quota.chan_mhz = chan2_freq; + chan_quota.channel_time_quota = quota_chan2; + cdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + if (ret) { + WMA_LOGE("Failed to send MCC Channel Time Quota command"); + cdf_nbuf_free(buf); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_linkstate() - set wma linkstate + * @wma: wma handle + * @params: link state params + * + * Return: none + */ +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t vdev_id, peer_id; + bool roam_synch_in_progress = false; + CDF_STATUS status; + + params->status = true; + WMA_LOGD("%s: state %d selfmac %pM", __func__, + params->state, params->selfMacAddr); + if ((params->state != eSIR_LINK_PREASSOC_STATE) && + (params->state != eSIR_LINK_DOWN_STATE)) { + WMA_LOGD("%s: unsupported link state %d", + __func__, params->state); + goto out; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get TXRX context", __func__); + goto out; + } + + vdev = wma_find_vdev_by_addr(wma, params->selfMacAddr, &vdev_id); + if (!vdev) { + WMA_LOGP("%s: vdev not found for addr: %pM", + __func__, params->selfMacAddr); + goto out; + } + + if (wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGD("%s: Ignoring set link req in ap mode", __func__); + goto out; + } + + if (params->state == eSIR_LINK_PREASSOC_STATE) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (wma->interfaces[vdev_id].roam_synch_in_progress) { + roam_synch_in_progress = true; + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + status = wma_create_peer(wma, pdev, vdev, params->bssid, + WMI_PEER_TYPE_DEFAULT, vdev_id, + roam_synch_in_progress); + if (status != CDF_STATUS_SUCCESS) + params->status = false; + } else { + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", + __func__, vdev_id); + ol_txrx_vdev_pause(wma->interfaces[vdev_id].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma->interfaces[vdev_id].pause_bitmap |= (1 << PAUSE_TYPE_HOST); + if (wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id)) { + WMA_LOGP("%s: %d Failed to send vdev stop", + __func__, __LINE__); + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + if (peer) { + WMA_LOGP("%s: Deleting peer %pM vdev id %d", + __func__, params->bssid, vdev_id); + wma_remove_peer(wma, params->bssid, vdev_id, peer, + roam_synch_in_progress); + } + } +out: + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); +} + +/** + * wma_unpause_vdev - unpause all vdev + * @wma: wma handle + * + * unpause all vdev aftter resume/coming out of wow mode + * + * Return: none + */ +void wma_unpause_vdev(tp_wma_handle wma) +{ + int8_t vdev_id; + struct wma_txrx_node *iface; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (!wma->interfaces[vdev_id].handle) + continue; + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + /* When host resume, by default, unpause all active vdev */ + if (wma->interfaces[vdev_id].pause_bitmap) { + ol_txrx_vdev_unpause(wma->interfaces[vdev_id].handle, + 0xffffffff); + wma->interfaces[vdev_id].pause_bitmap = 0; + } +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + iface = &wma->interfaces[vdev_id]; + iface->conn_state = false; + } +} + +/** + * wma_process_rate_update_indate() - rate update indication + * @wma: wma handle + * @pRateUpdateParams: Rate update params + * + * This function update rate & short GI interval to fw based on params + * send by SME. + * + * Return: CDF status + */ +CDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams) +{ + int32_t ret = 0; + uint8_t vdev_id = 0; + void *pdev; + int32_t mbpsx10_rate = -1; + uint32_t paramId; + uint8_t rate = 0; + uint32_t short_gi; + struct wma_txrx_node *intr = wma->interfaces; + + /* Get the vdev id */ + pdev = wma_find_vdev_by_addr(wma, pRateUpdateParams->bssid, &vdev_id); + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + pRateUpdateParams->bssid); + cdf_mem_free(pRateUpdateParams); + return CDF_STATUS_E_INVAL; + } + short_gi = intr[vdev_id].config.shortgi; + if (short_gi == 0) + short_gi = (intr[vdev_id].rate_flags & eHAL_TX_RATE_SGI) ? + true : false; + /* first check if reliable TX mcast rate is used. If not check the bcast. + * Then is mcast. Mcast rate is saved in mcastDataRate24GHz + */ + if (pRateUpdateParams->reliableMcastDataRateTxFlag > 0) { + mbpsx10_rate = pRateUpdateParams->reliableMcastDataRate; + paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE; + if (pRateUpdateParams-> + reliableMcastDataRateTxFlag & eHAL_TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } else if (pRateUpdateParams->bcastDataRate > -1) { + mbpsx10_rate = pRateUpdateParams->bcastDataRate; + paramId = WMI_VDEV_PARAM_BCAST_DATA_RATE; + } else { + mbpsx10_rate = pRateUpdateParams->mcastDataRate24GHz; + paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE; + if (pRateUpdateParams-> + mcastDataRate24GHzTxFlag & eHAL_TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } + WMA_LOGE("%s: dev_id = %d, dev_type = %d, dev_mode = %d, " + "mac = %pM, config.shortgi = %d, rate_flags = 0x%x", + __func__, vdev_id, intr[vdev_id].type, + pRateUpdateParams->dev_mode, pRateUpdateParams->bssid, + intr[vdev_id].config.shortgi, intr[vdev_id].rate_flags); + ret = wma_encode_mc_rate(short_gi, intr[vdev_id].config.chwidth, + intr[vdev_id].chanmode, intr[vdev_id].mhz, + mbpsx10_rate, pRateUpdateParams->nss, &rate); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Error, Invalid input rate value", __func__); + cdf_mem_free(pRateUpdateParams); + return ret; + } + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SGI, short_gi); + if (ret) { + WMA_LOGE("%s: Failed to Set WMI_VDEV_PARAM_SGI (%d), ret = %d", + __func__, short_gi, ret); + cdf_mem_free(pRateUpdateParams); + return CDF_STATUS_E_FAILURE; + } + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + vdev_id, paramId, rate); + cdf_mem_free(pRateUpdateParams); + if (ret) { + WMA_LOGE("%s: Failed to Set rate, ret = %d", __func__, ret); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_mgmt_tx_ack_work_handler() - mgmt tx ack work queue + * @ack_work: work structure + * + * Return: none + */ +static void wma_mgmt_tx_ack_work_handler(struct work_struct *ack_work) +{ + struct wma_tx_ack_work_ctx *work; + tp_wma_handle wma_handle; + pWMAAckFnTxComp ack_cb; + + if (cds_is_load_unload_in_progress()) { + WMA_LOGE("%s: Driver load/unload in progress", __func__); + return; + } + + work = container_of(ack_work, struct wma_tx_ack_work_ctx, ack_cmp_work); + wma_handle = work->wma_handle; + ack_cb = wma_handle->umac_ota_ack_cb[work->sub_type]; + + WMA_LOGD("Tx Ack Cb SubType %d Status %d", + work->sub_type, work->status); + + /* Call the Ack Cb registered by UMAC */ + ack_cb((tpAniSirGlobal) (wma_handle->mac_context), + work->status ? 0 : 1); + + cdf_mem_free(work); + wma_handle->ack_work_ctx = NULL; +} + +/** + * wma_mgmt_tx_comp_conf_ind() - Post mgmt tx complete indication to PE. + * @wma_handle: Pointer to WMA handle + * @sub_type: Tx mgmt frame sub type + * @status: Mgmt frame tx status + * + * This function sends mgmt complition confirmation to PE for deauth + * and deassoc frames. + * + * Return: none + */ +static void +wma_mgmt_tx_comp_conf_ind(tp_wma_handle wma_handle, uint8_t sub_type, + int32_t status) +{ + int32_t tx_comp_status; + + tx_comp_status = status ? 0 : 1; + if (sub_type == SIR_MAC_MGMT_DISASSOC) { + wma_send_msg(wma_handle, WMA_DISASSOC_TX_COMP, NULL, + tx_comp_status); + } else if (sub_type == SIR_MAC_MGMT_DEAUTH) { + wma_send_msg(wma_handle, WMA_DEAUTH_TX_COMP, NULL, + tx_comp_status); + } +} + +/** + * wma_mgmt_tx_ack_comp_hdlr() - handles tx ack mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This is callback registered with TxRx for + * Ack Complete. + * + * Return: none + */ +static void +wma_mgmt_tx_ack_comp_hdlr(void *wma_context, cdf_nbuf_t netbuf, int32_t status) +{ + tpSirMacFrameCtl pFc = (tpSirMacFrameCtl) (cdf_nbuf_data(netbuf)); + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + + if (wma_handle && wma_handle->umac_ota_ack_cb[pFc->subType]) { + if ((pFc->subType == SIR_MAC_MGMT_DISASSOC) || + (pFc->subType == SIR_MAC_MGMT_DEAUTH)) { + wma_mgmt_tx_comp_conf_ind(wma_handle, + (uint8_t) pFc->subType, + status); + } else { + struct wma_tx_ack_work_ctx *ack_work; + + ack_work = + cdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + + if (ack_work) { +#ifdef CONFIG_CNSS + cnss_init_work(&ack_work->ack_cmp_work, + wma_mgmt_tx_ack_work_handler); +#else + INIT_WORK(&ack_work->ack_cmp_work, + wma_mgmt_tx_ack_work_handler); +#endif /* CONFIG_CNSS */ + ack_work->wma_handle = wma_handle; + ack_work->sub_type = pFc->subType; + ack_work->status = status; + + /* Schedue the Work */ + schedule_work(&ack_work->ack_cmp_work); + } + } + } +} + +/** + * wma_mgmt_tx_dload_comp_hldr() - handles tx mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This function calls registered download callback while sending mgmt packet. + * + * Return: none + */ +static void +wma_mgmt_tx_dload_comp_hldr(void *wma_context, cdf_nbuf_t netbuf, + int32_t status) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + void *mac_context = wma_handle->mac_context; + + WMA_LOGD("Tx Complete Status %d", status); + + if (!wma_handle->tx_frm_download_comp_cb) { + WMA_LOGE("Tx Complete Cb not registered by umac"); + return; + } + + /* Call Tx Mgmt Complete Callback registered by umac */ + wma_handle->tx_frm_download_comp_cb(mac_context, netbuf, 0); + + /* Reset Callback */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Set the Tx Mgmt Complete Event */ + cdf_status = cdf_event_set(&wma_handle->tx_frm_download_comp_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + WMA_LOGP("%s: Event Set failed - tx_frm_comp_event", __func__); +} + +/** + * wma_tx_attach() - attach tx related callbacks + * @pwmaCtx: wma context + * + * attaches tx fn with underlying layer. + * + * Return: CDF status + */ +CDF_STATUS wma_tx_attach(tp_wma_handle wma_handle) +{ + /* Get the Vos Context */ + p_cds_contextType cds_handle = + (p_cds_contextType) (wma_handle->cds_context); + + /* Get the txRx Pdev handle */ + ol_txrx_pdev_handle txrx_pdev = + (ol_txrx_pdev_handle) (cds_handle->pdev_txrx_ctx); + + /* Register for Tx Management Frames */ + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_NODOWLOAD_ACK_COMP_INDEX, + NULL, wma_mgmt_tx_ack_comp_hdlr, wma_handle); + + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX, + wma_mgmt_tx_dload_comp_hldr, NULL, wma_handle); + + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_ACK_COMP_INDEX, + wma_mgmt_tx_dload_comp_hldr, + wma_mgmt_tx_ack_comp_hdlr, wma_handle); + + /* Store the Mac Context */ + wma_handle->mac_context = cds_handle->pMACContext; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_tx_detach() - detach tx related callbacks + * @tp_wma_handle: wma context + * + * Deregister with TxRx for Tx Mgmt Download and Ack completion. + * + * Return: CDF status + */ +CDF_STATUS wma_tx_detach(tp_wma_handle wma_handle) +{ + uint32_t frame_index = 0; + + /* Get the Vos Context */ + p_cds_contextType cds_handle = + (p_cds_contextType) (wma_handle->cds_context); + + /* Get the txRx Pdev handle */ + ol_txrx_pdev_handle txrx_pdev = + (ol_txrx_pdev_handle) (cds_handle->pdev_txrx_ctx); + + /* Deregister with TxRx for Tx Mgmt completion call back */ + for (frame_index = 0; frame_index < FRAME_INDEX_MAX; frame_index++) + ol_txrx_mgmt_tx_cb_set(txrx_pdev, frame_index, NULL, NULL, + txrx_pdev); + + /* Destroy Tx Frame Complete event */ + cdf_event_destroy(&wma_handle->tx_frm_download_comp_event); + + /* Tx queue empty check event (dummy event) */ + cdf_event_destroy(&wma_handle->tx_queue_empty_event); + + /* Reset Tx Frm Callbacks */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Reset Tx Data Frame Ack Cb */ + wma_handle->umac_data_ota_ack_cb = NULL; + + /* Reset last Tx Data Frame nbuf ptr */ + wma_handle->last_umac_data_nbuf = NULL; + + return CDF_STATUS_SUCCESS; +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +/** + * wma_mcc_vdev_tx_pause_evt_handler() - pause event handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * This function handle pause event from fw and pause/unpause + * vdev. + * + * Return: 0 for success or error code. + */ +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf; + wmi_tx_pause_event_fixed_param *wmi_event; + uint8_t vdev_id; + A_UINT32 vdev_map; + + param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + if (wma_get_wow_bus_suspend(wma)) { + WMA_LOGD(" Suspend is in progress: Pause/Unpause Tx is NoOp"); + return 0; + } + + wmi_event = param_buf->fixed_param; + vdev_map = wmi_event->vdev_map; + /* FW mapped vdev from ID + * vdev_map = (1 << vdev_id) + * So, host should unmap to ID */ + for (vdev_id = 0; vdev_map != 0; vdev_id++) { + if (!(vdev_map & 0x1)) { + /* No Vdev */ + } else { + if (!wma->interfaces[vdev_id].handle) { + WMA_LOGE("%s: invalid vdev ID %d", __func__, + vdev_id); + /* Test Next VDEV */ + vdev_map >>= 1; + continue; + } + + /* PAUSE action, add bitmap */ + if (ACTION_PAUSE == wmi_event->action) { + /* + * Now only support per-dev pause so it is not + * necessary to pause a paused queue again. + */ + if (!wma->interfaces[vdev_id].pause_bitmap) + ol_txrx_vdev_pause( + wma->interfaces[vdev_id]. + handle, + OL_TXQ_PAUSE_REASON_FW); + wma->interfaces[vdev_id].pause_bitmap |= + (1 << wmi_event->pause_type); + } + /* UNPAUSE action, clean bitmap */ + else if (ACTION_UNPAUSE == wmi_event->action) { + /* Handle unpause only if already paused */ + if (wma->interfaces[vdev_id].pause_bitmap) { + wma->interfaces[vdev_id].pause_bitmap &= + ~(1 << wmi_event->pause_type); + + if (!wma->interfaces[vdev_id]. + pause_bitmap) { + /* PAUSE BIT MAP is cleared + * UNPAUSE VDEV */ + ol_txrx_vdev_unpause( + wma->interfaces[vdev_id] + .handle, + OL_TXQ_PAUSE_REASON_FW); + } + } + } else { + WMA_LOGE("Not Valid Action Type %d", + wmi_event->action); + } + + WMA_LOGD + ("vdev_id %d, pause_map 0x%x, pause type %d, action %d", + vdev_id, wma->interfaces[vdev_id].pause_bitmap, + wmi_event->pause_type, wmi_event->action); + } + /* Test Next VDEV */ + vdev_map >>= 1; + } + + return 0; +} + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * wma_process_init_thermal_info() - initialize thermal info + * @wma: Pointer to WMA handle + * @pThermalParams: Pointer to thermal mitigation parameters + * + * This function initializes the thermal management table in WMA, + * sends down the initial temperature thresholds to the firmware + * and configures the throttle period in the tx rx module + * + * Returns: CDF_STATUS_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams) +{ + t_thermal_cmd_params thermal_params; + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma || NULL == pThermalParams) { + WMA_LOGE("TM Invalid input"); + return CDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("TM enable %d period %d", pThermalParams->thermalMgmtEnabled, + pThermalParams->throttlePeriod); + + wma->thermal_mgmt_info.thermalMgmtEnabled = + pThermalParams->thermalMgmtEnabled; + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold = + pThermalParams->thermalLevels[0].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold = + pThermalParams->thermalLevels[0].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold = + pThermalParams->thermalLevels[1].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold = + pThermalParams->thermalLevels[1].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold = + pThermalParams->thermalLevels[2].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold = + pThermalParams->thermalLevels[2].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold = + pThermalParams->thermalLevels[3].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold = + pThermalParams->thermalLevels[3].maxTempThreshold; + wma->thermal_mgmt_info.thermalCurrLevel = WLAN_WMA_THERMAL_LEVEL_0; + + WMA_LOGD("TM level min max:\n" + "0 %d %d\n" + "1 %d %d\n" + "2 %d %d\n" + "3 %d %d", + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold); + + if (wma->thermal_mgmt_info.thermalMgmtEnabled) { + ol_tx_throttle_init_period(curr_pdev, + pThermalParams->throttlePeriod); + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + + WMA_LOGE("TM sending the following to firmware: min %d max %d enable %d", + thermal_params.minTemp, thermal_params.maxTemp, + thermal_params.thermalEnable); + + if (CDF_STATUS_SUCCESS != + wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + } + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_thermal_level_ind() - send SME set thermal level indication message + * @level: thermal level + * + * Send SME SET_THERMAL_LEVEL_IND message + * + * Returns: none + */ +static void wma_set_thermal_level_ind(u_int8_t level) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = {0}; + + WMA_LOGI(FL("Thermal level: %d"), level); + + sme_msg.type = eWNI_SME_SET_THERMAL_LEVEL_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = level; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) + WMA_LOGE(FL( + "Fail to post set thermal level ind msg")); +} + +/** + * wma_process_set_thermal_level() - sets thermal level + * @wma: Pointer to WMA handle + * @thermal_level : Thermal level + * + * This function sets the new thermal throttle level in the + * txrx module and sends down the corresponding temperature + * thresholds to the firmware + * + * Returns: CDF_STATUS_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level) +{ + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma) { + WMA_LOGE("TM Invalid input"); + return CDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGE("TM set level %d", thermal_level); + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring set level command"); + return CDF_STATUS_E_FAILURE; + } + + if (thermal_level >= WLAN_WMA_MAX_THERMAL_LEVELS) { + WMA_LOGE("Invalid thermal level set %d", thermal_level); + return CDF_STATUS_E_FAILURE; + } + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return CDF_STATUS_SUCCESS; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + ol_tx_throttle_set_level(curr_pdev, thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + return CDF_STATUS_SUCCESS; +} + + +/** + * wma_set_thermal_mgmt() - set thermal mgmt command to fw + * @wma_handle: Pointer to WMA handle + * @thermal_info: Thermal command information + * + * This function sends the thermal management command + * to the firmware + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info) +{ + wmi_thermal_mgmt_cmd_fixed_param *cmd = NULL; + wmi_buf_t buf = NULL; + int status = 0; + uint32_t len = 0; + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set key cmd"); + return CDF_STATUS_E_FAILURE; + } + + cmd = (wmi_thermal_mgmt_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_thermal_mgmt_cmd_fixed_param)); + + cmd->lower_thresh_degreeC = thermal_info.minTemp; + cmd->upper_thresh_degreeC = thermal_info.maxTemp; + cmd->enable = thermal_info.thermalEnable; + + WMA_LOGE("TM Sending thermal mgmt cmd: low temp %d, upper temp %d, enabled %d", + cmd->lower_thresh_degreeC, cmd->upper_thresh_degreeC, cmd->enable); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_THERMAL_MGMT_CMDID); + if (status) { + cdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send thermal mgmt command", __func__); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_thermal_mgmt_get_level() - returns throttle level + * @handle: Pointer to WMA handle + * @temp: temperature + * + * This function returns the thermal(throttle) level + * given the temperature + * + * Return: thermal (throttle) level + */ +uint8_t wma_thermal_mgmt_get_level(void *handle, uint32_t temp) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int i; + uint8_t level; + + level = i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp < wma->thermal_mgmt_info.thermalLevels[i].minTempThreshold + && i > 0) { + i--; + level = i; + } + + i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp > wma->thermal_mgmt_info.thermalLevels[i].maxTempThreshold + && i < (WLAN_WMA_MAX_THERMAL_LEVELS - 1)) { + i++; + level = i; + } + + WMA_LOGW("Change thermal level from %d -> %d\n", + wma->thermal_mgmt_info.thermalCurrLevel, level); + + return level; +} + +/** + * wma_thermal_mgmt_evt_handler() - thermal mgmt event handler + * @wma_handle: Pointer to WMA handle + * @event: Thermal event information + * + * This function handles the thermal mgmt event from the firmware len + * + * Return: 0 for success otherwise failure + */ +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma; + wmi_thermal_mgmt_event_fixed_param *tm_event; + uint8_t thermal_level; + t_thermal_cmd_params thermal_params; + WMI_THERMAL_MGMT_EVENTID_param_tlvs *param_buf; + ol_txrx_pdev_handle curr_pdev; + + if (NULL == event || NULL == handle) { + WMA_LOGE("Invalid thermal mitigation event buffer"); + return -EINVAL; + } + + wma = (tp_wma_handle) handle; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma handle", __func__); + return -EINVAL; + } + + param_buf = (WMI_THERMAL_MGMT_EVENTID_param_tlvs *) event; + + curr_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return -EINVAL; + } + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring event"); + return -EINVAL; + } + + tm_event = param_buf->fixed_param; + WMA_LOGD("Thermal mgmt event received with temperature %d", + tm_event->temperature_degreeC); + + /* Get the thermal mitigation level for the reported temperature */ + thermal_level = + wma_thermal_mgmt_get_level(handle, tm_event->temperature_degreeC); + WMA_LOGD("Thermal mgmt level %d", thermal_level); + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return 0; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + /* Inform txrx */ + ol_tx_throttle_set_level(curr_pdev, thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + + if (CDF_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + return -EINVAL; + } + + return 0; +} + +/** + * wma_decap_to_8023() - Decapsulate to 802.3 format + * @msdu: skb buffer + * @info: decapsulate info + * + * Return: none + */ +static void wma_decap_to_8023(cdf_nbuf_t msdu, struct wma_decap_info_t *info) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_qosframe_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + struct ethernet_hdr_t *ethr_hdr; + + buf = (uint8_t *) cdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) { + buf = cdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + } else if (l2_hdr_space < ETHERNET_HDR_LEN) { + buf = cdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + } + + /* mpdu hdr should be present in info,re-create ethr_hdr based on mpdu hdr */ + wh = (struct ieee80211_qosframe_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + cdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + cdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + + if (llc_hdr == NULL) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + cdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + ether_type = (uint16_t) pktlen; + ether_type = cdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + cdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +/** + * wma_ieee80211_hdrsize() - get 802.11 header size + * @data: 80211 frame + * + * Return: size of header + */ +static int32_t wma_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int32_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + if (IEEE80211_QOS_HAS_SEQ(wh)) + size += sizeof(uint16_t); + return size; +} + +/** + * wmi_desc_pool_init() - Initialize the WMI descriptor pool + * @wma_handle: handle to wma + * @pool_size: Size of wma pool + * + * Return: 0 for success, error code on failure. + */ +int wmi_desc_pool_init(tp_wma_handle wma_handle, uint32_t pool_size) +{ + int i; + + if (!pool_size) { + WMA_LOGE("%s: failed to allocate desc pool", __func__); + cdf_assert_always(pool_size); + return -EINVAL; + } + WMA_LOGE("%s: initialize desc pool of size %d", __func__, pool_size); + wma_handle->wmi_desc_pool.pool_size = pool_size; + wma_handle->wmi_desc_pool.num_free = pool_size; + wma_handle->wmi_desc_pool.array = cdf_mem_malloc(pool_size * + sizeof(union wmi_desc_elem_t)); + if (!wma_handle->wmi_desc_pool.array) { + WMA_LOGE("%s: failed to allocate desc pool", __func__); + return -ENOMEM; + } + wma_handle->wmi_desc_pool.freelist = &wma_handle-> + wmi_desc_pool.array[0]; + + for (i = 0; i < (pool_size - 1); i++) { + wma_handle->wmi_desc_pool.array[i].wmi_desc.desc_id = i; + wma_handle->wmi_desc_pool.array[i].next = + &wma_handle->wmi_desc_pool.array[i + 1]; + } + + wma_handle->wmi_desc_pool.array[i].next = NULL; + wma_handle->wmi_desc_pool.array[i].wmi_desc.desc_id = i; + + cdf_spinlock_init(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + return 0; +} + +/** + * wmi_desc_pool_deinit() - Deinitialize the WMI descriptor pool + * @wma_handle: handle to wma + * + * Return: None + */ +void wmi_desc_pool_deinit(tp_wma_handle wma_handle) +{ + cdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + if (wma_handle->wmi_desc_pool.array) { + cdf_mem_free(wma_handle->wmi_desc_pool.array); + wma_handle->wmi_desc_pool.array = NULL; + } else { + WMA_LOGE("%s: Empty WMI descriptor pool", __func__); + } + + wma_handle->wmi_desc_pool.freelist = NULL; + wma_handle->wmi_desc_pool.pool_size = 0; + wma_handle->wmi_desc_pool.num_free = 0; + cdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + cdf_spinlock_destroy(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); +} + +/** + * wmi_desc_get() - Get wmi descriptor from wmi free descriptor pool + * @wma_handle: handle to wma + * + * Return: pointer to wmi descriptor, NULL on failure + */ +struct wmi_desc_t *wmi_desc_get(tp_wma_handle wma_handle) +{ + struct wmi_desc_t *wmi_desc = NULL; + + cdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + if (wma_handle->wmi_desc_pool.freelist) { + wma_handle->wmi_desc_pool.num_free--; + wmi_desc = &wma_handle->wmi_desc_pool.freelist->wmi_desc; + wma_handle->wmi_desc_pool.freelist = + wma_handle->wmi_desc_pool.freelist->next; + } + cdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + + return wmi_desc; +} + +/** + * wmi_desc_put() - Put wmi descriptor to wmi free descriptor pool + * @wma_handle: handle to wma + * @wmi_desc: wmi descriptor + * + * Return: None + */ +void wmi_desc_put(tp_wma_handle wma_handle, struct wmi_desc_t *wmi_desc) +{ + cdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + ((union wmi_desc_elem_t *)wmi_desc)->next = + wma_handle->wmi_desc_pool.freelist; + wma_handle->wmi_desc_pool.freelist = (union wmi_desc_elem_t *)wmi_desc; + wma_handle->wmi_desc_pool.num_free++; + cdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); +} + +#define mgmt_tx_dl_frm_len 64 +static inline CDF_STATUS +mgmt_wmi_unified_cmd_send(tp_wma_handle wma_handle, void *tx_frame, + uint16_t frmLen, uint8_t vdev_id, + pWMATxRxCompFunc tx_complete_cb, + pWMAAckFnTxComp tx_ota_post_proc_cb, + uint16_t chanfreq, void *pData) +{ + wmi_buf_t buf; + wmi_mgmt_tx_send_cmd_fixed_param *cmd; + int32_t cmd_len; + uint64_t dma_addr; + struct wmi_desc_t *wmi_desc = NULL; + void *cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + uint8_t *bufp; + int32_t bufp_len = (frmLen < mgmt_tx_dl_frm_len) ? frmLen : + mgmt_tx_dl_frm_len; + + cmd_len = sizeof(wmi_mgmt_tx_send_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + roundup(bufp_len, sizeof(uint32_t)); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, cmd_len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_mgmt_tx_send_cmd_fixed_param *)wmi_buf_data(buf); + bufp = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_mgmt_tx_send_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + + wmi_desc = wmi_desc_get(wma_handle); + if (!wmi_desc) { + WMA_LOGE("%s: Failed to get wmi_desc", __func__); + goto err2; + } + wmi_desc->nbuf = tx_frame; + wmi_desc->tx_cmpl_cb = tx_complete_cb; + wmi_desc->ota_post_proc_cb = tx_ota_post_proc_cb; + + cmd->desc_id = wmi_desc->desc_id; + cmd->chanfreq = chanfreq; + bufp += sizeof(wmi_mgmt_tx_send_cmd_fixed_param); + WMITLV_SET_HDR(bufp, WMITLV_TAG_ARRAY_BYTE, roundup(bufp_len, + sizeof(uint32_t))); + bufp += WMI_TLV_HDR_SIZE; + cdf_mem_copy(bufp, pData, bufp_len); + cdf_nbuf_map_single(cdf_ctx, tx_frame, CDF_DMA_TO_DEVICE); + dma_addr = cdf_nbuf_get_frag_paddr_lo(tx_frame, 0); + cmd->paddr_lo = (uint32_t)(dma_addr & 0xffffffff); +#if defined(HELIUMPLUS_PADDR64) + cmd->paddr_hi = (uint32_t)((dma_addr >> 32) & 0x1F); +#endif + cmd->frame_len = frmLen; + cmd->buf_len = bufp_len; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, cmd_len, + WMI_MGMT_TX_SEND_CMDID)) { + WMA_LOGE("%s: Failed to send mgmt Tx", __func__); + goto err1; + } + return CDF_STATUS_SUCCESS; +err1: + wmi_desc_put(wma_handle, wmi_desc); +err2: + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; +} + +/** + * wma_tx_packet() - Sends Tx Frame to TxRx + * @wma_context: wma context + * @tx_frame: frame buffer + * @frmLen: frame length + * @frmType: frame type + * @txDir: tx diection + * @tid: TID + * @tx_frm_download_comp_cb: tx download callback handler + * @tx_frm_ota_comp_cb: OTA complition handler + * @tx_flag: tx flag + * @vdev_id: vdev id + * @tdlsFlag: tdls flag + * + * This function sends the frame corresponding to the + * given vdev id. + * This is blocking call till the downloading of frame is complete. + * + * Return: CDF status + */ +CDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, + eFrameType frmType, eFrameTxDir txDir, uint8_t tid, + pWMATxRxCompFunc tx_frm_download_comp_cb, void *pData, + pWMAAckFnTxComp tx_frm_ota_comp_cb, uint8_t tx_flag, + uint8_t vdev_id, bool tdlsFlag, uint16_t channel_freq) +{ + tp_wma_handle wma_handle = (tp_wma_handle) (wma_context); + int32_t status; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int32_t is_high_latency; + ol_txrx_vdev_handle txrx_vdev; + enum frame_index tx_frm_index = GENERIC_NODOWNLD_NOACK_COMP_INDEX; + tpSirMacFrameCtl pFc = (tpSirMacFrameCtl) (cdf_nbuf_data(tx_frame)); + uint8_t use_6mbps = 0; + uint8_t downld_comp_required = 0; + uint16_t chanfreq; +#ifdef WLAN_FEATURE_11W + uint8_t *pFrame = NULL; + void *pPacket = NULL; + uint16_t newFrmLen = 0; +#endif /* WLAN_FEATURE_11W */ + struct wma_txrx_node *iface; + tpAniSirGlobal pMac; + tpSirMacMgmtHdr mHdr; +#ifdef QCA_PKT_PROTO_TRACE + uint8_t proto_type = 0; +#endif /* QCA_PKT_PROTO_TRACE */ + + if (NULL == wma_handle) { + WMA_LOGE("wma_handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + iface = &wma_handle->interfaces[vdev_id]; + /* Get the vdev handle from vdev id */ + txrx_vdev = wma_handle->interfaces[vdev_id].handle; + + if (!txrx_vdev) { + WMA_LOGE("TxRx Vdev Handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + + if (frmType >= TXRX_FRM_MAX) { + WMA_LOGE("Invalid Frame Type Fail to send Frame"); + return CDF_STATUS_E_FAILURE; + } + + pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("pMac Handle is NULL"); + return CDF_STATUS_E_FAILURE; + } + /* + * Currently only support to + * send 80211 Mgmt and 80211 Data are added. + */ + if (!((frmType == TXRX_FRM_802_11_MGMT) || + (frmType == TXRX_FRM_802_11_DATA))) { + WMA_LOGE("No Support to send other frames except 802.11 Mgmt/Data"); + return CDF_STATUS_E_FAILURE; + } + mHdr = (tpSirMacMgmtHdr)cdf_nbuf_data(tx_frame); +#ifdef WLAN_FEATURE_11W + if ((iface && iface->rmfEnabled) && + (frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_DISASSOC || + pFc->subType == SIR_MAC_MGMT_DEAUTH || + pFc->subType == SIR_MAC_MGMT_ACTION)) { + struct ieee80211_frame *wh = + (struct ieee80211_frame *)cdf_nbuf_data(tx_frame); + if (!IEEE80211_IS_BROADCAST(wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (pFc->wep) { + /* Allocate extra bytes for privacy header and trailer */ + newFrmLen = frmLen + IEEE80211_CCMP_HEADERLEN + + IEEE80211_CCMP_MICLEN; + cdf_status = + cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("%s: Failed to allocate %d bytes for RMF status " + "code (%x)", __func__, newFrmLen, + cdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + + /* + * Initialize the frame with 0's and only fill + * MAC header and data, Keep the CCMP header and + * trailer as 0's, firmware shall fill this + */ + cdf_mem_set(pFrame, newFrmLen, 0); + cdf_mem_copy(pFrame, wh, sizeof(*wh)); + cdf_mem_copy(pFrame + sizeof(*wh) + + IEEE80211_CCMP_HEADERLEN, + pData + sizeof(*wh), + frmLen - sizeof(*wh)); + + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + frmLen = newFrmLen; + } + } else { + /* Allocate extra bytes for MMIE */ + newFrmLen = frmLen + IEEE80211_MMIE_LEN; + cdf_status = cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("%s: Failed to allocate %d bytes for RMF status " + "code (%x)", __func__, newFrmLen, + cdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + /* + * Initialize the frame with 0's and only fill + * MAC header and data. MMIE field will be + * filled by cds_attach_mmie API + */ + cdf_mem_set(pFrame, newFrmLen, 0); + cdf_mem_copy(pFrame, wh, sizeof(*wh)); + cdf_mem_copy(pFrame + sizeof(*wh), + pData + sizeof(*wh), frmLen - sizeof(*wh)); + if (!cds_attach_mmie(iface->key.key, + iface->key.key_id[0].ipn, + WMA_IGTK_KEY_INDEX_4, + pFrame, + pFrame + newFrmLen, newFrmLen)) { + WMA_LOGP("%s: Failed to attach MMIE at the end of " + "frame", __func__); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + frmLen = newFrmLen; + } + } +#endif /* WLAN_FEATURE_11W */ + + if ((frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_PROBE_RSP)) { + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)cdf_nbuf_data(tx_frame); + + /* Make the TSF offset negative to match TSF in beacons */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma_handle->interfaces[vdev_id]. + tsfadjust); + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + } + if (frmType == TXRX_FRM_802_11_DATA) { + cdf_nbuf_t ret; + cdf_nbuf_t skb = (cdf_nbuf_t) tx_frame; + ol_txrx_pdev_handle pdev = + cds_get_context(CDF_MODULE_ID_TXRX); + + struct wma_decap_info_t decap_info; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)cdf_nbuf_data(skb); + v_TIME_t curr_timestamp = cdf_mc_timer_get_system_ticks(); + + if (pdev == NULL) { + WMA_LOGE("%s: pdev pointer is not available", __func__); + return CDF_STATUS_E_FAULT; + } + + /* + * 1) TxRx Module expects data input to be 802.3 format + * So Decapsulation has to be done. + * 2) Only one Outstanding Data pending for Ack is allowed + */ + if (tx_frm_ota_comp_cb) { + if (wma_handle->umac_data_ota_ack_cb) { + /* + * If last data frame was sent more than 5 seconds + * ago and still we did not receive ack/nack from + * fw then allow Tx of this data frame + */ + if (curr_timestamp >= + wma_handle->last_umac_data_ota_timestamp + + 500) { + WMA_LOGE("%s: No Tx Ack for last data frame for more than 5 secs, allow Tx of current data frame", + __func__); + } else { + WMA_LOGE("%s: Already one Data pending for Ack, reject Tx of data frame", + __func__); + return CDF_STATUS_E_FAILURE; + } + } + } else { + /* + * Data Frames are sent through TxRx Non Standard Data Path + * so Ack Complete Cb is must + */ + WMA_LOGE("No Ack Complete Cb. Don't Allow"); + return CDF_STATUS_E_FAILURE; + } + + /* Take out 802.11 header from skb */ + decap_info.hdr_len = wma_ieee80211_hdrsize(wh); + cdf_mem_copy(decap_info.hdr, wh, decap_info.hdr_len); + cdf_nbuf_pull_head(skb, decap_info.hdr_len); + + /* Decapsulate to 802.3 format */ + wma_decap_to_8023(skb, &decap_info); + + /* Zero out skb's context buffer for the driver to use */ + cdf_mem_set(skb->cb, sizeof(skb->cb), 0); + + /* Do the DMA Mapping */ + cdf_nbuf_map_single(pdev->osdev, skb, CDF_DMA_TO_DEVICE); + + /* Terminate the (single-element) list of tx frames */ + skb->next = NULL; + + /* Store the Ack Complete Cb */ + wma_handle->umac_data_ota_ack_cb = tx_frm_ota_comp_cb; + + /* Store the timestamp and nbuf for this data Tx */ + wma_handle->last_umac_data_ota_timestamp = curr_timestamp; + wma_handle->last_umac_data_nbuf = skb; + + /* Send the Data frame to TxRx in Non Standard Path */ + ret = ol_tx_non_std(txrx_vdev, ol_tx_spec_no_free, skb); + + if (ret) { + WMA_LOGE("TxRx Rejected. Fail to do Tx"); + cdf_nbuf_unmap_single(pdev->osdev, skb, + CDF_DMA_TO_DEVICE); + /* Call Download Cb so that umac can free the buffer */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + return CDF_STATUS_E_FAILURE; + } + + /* Call Download Callback if passed */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_NO_FREE); + + return CDF_STATUS_SUCCESS; + } + + is_high_latency = + ol_cfg_is_high_latency(txrx_vdev->pdev->ctrl_pdev); + + downld_comp_required = tx_frm_download_comp_cb && is_high_latency; + + /* Fill the frame index to send */ + if (pFc->type == SIR_MAC_MGMT_FRAME) { + if (tx_frm_ota_comp_cb) { + if (downld_comp_required) + tx_frm_index = + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX; + else + tx_frm_index = GENERIC_NODOWLOAD_ACK_COMP_INDEX; + + /* Store the Ack Cb sent by UMAC */ + if (pFc->subType < SIR_MAC_MGMT_RESERVED15) { + wma_handle->umac_ota_ack_cb[pFc->subType] = + tx_frm_ota_comp_cb; + } +#ifdef QCA_PKT_PROTO_TRACE + if (pFc->subType == SIR_MAC_MGMT_ACTION) + proto_type = cds_pkt_get_proto_type(tx_frame, + pMac->fEnableDebugLog, + NBUF_PKT_TRAC_TYPE_MGMT_ACTION); + if (proto_type & NBUF_PKT_TRAC_TYPE_MGMT_ACTION) + cds_pkt_trace_buf_update("WM:T:MACT"); + cdf_nbuf_trace_set_proto_type(tx_frame, proto_type); +#endif /* QCA_PKT_PROTO_TRACE */ + } else { + if (downld_comp_required) + tx_frm_index = + GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX; + else + tx_frm_index = + GENERIC_NODOWNLD_NOACK_COMP_INDEX; + } + } + + /* + * If Dowload Complete is required + * Wait for download complete + */ + if (downld_comp_required) { + /* Store Tx Comp Cb */ + wma_handle->tx_frm_download_comp_cb = tx_frm_download_comp_cb; + + /* Reset the Tx Frame Complete Event */ + cdf_status = + cdf_event_reset(&wma_handle->tx_frm_download_comp_event); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("%s: Event Reset failed tx comp event %x", + __func__, cdf_status); + goto error; + } + } + + /* If the frame has to be sent at BD Rate2 inform TxRx */ + if (tx_flag & HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME) + use_6mbps = 1; + + if (wma_handle->roam_preauth_scan_state == WMA_ROAM_PREAUTH_ON_CHAN) { + chanfreq = wma_handle->roam_preauth_chanfreq; + WMA_LOGI("%s: Preauth frame on channel %d", __func__, chanfreq); + } else if (pFc->subType == SIR_MAC_MGMT_PROBE_RSP) { + chanfreq = wma_handle->interfaces[vdev_id].mhz; + WMA_LOGI("%s: Probe response frame on channel %d", __func__, + chanfreq); + WMA_LOGI("%s: Probe response frame on vdev id %d", __func__, + vdev_id); + } else if (pFc->subType == SIR_MAC_MGMT_ACTION) { + chanfreq = channel_freq; + } else { + chanfreq = 0; + } + if (pMac->fEnableDebugLog & 0x1) { + if ((pFc->type == SIR_MAC_MGMT_FRAME) && + (pFc->subType != SIR_MAC_MGMT_PROBE_REQ) && + (pFc->subType != SIR_MAC_MGMT_PROBE_RSP)) { + WMA_LOGE("TX MGMT - Type %hu, SubType %hu seq_num[%d]", + pFc->type, pFc->subType, + ((mHdr->seqControl.seqNumHi << 4) | + mHdr->seqControl.seqNumLo)); + } + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + status = mgmt_wmi_unified_cmd_send(wma_handle, tx_frame, frmLen, + vdev_id, + tx_frm_download_comp_cb, + tx_frm_ota_comp_cb, + chanfreq, pData); + } else { + /* Hand over the Tx Mgmt frame to TxRx */ + status = ol_txrx_mgmt_send(txrx_vdev, tx_frame, tx_frm_index, + use_6mbps, chanfreq); + } + + /* + * Failed to send Tx Mgmt Frame + */ + if (status) { + /* Call Download Cb so that umac can free the buffer */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + WMA_LOGP("%s: Failed to send Mgmt Frame", __func__); + goto error; + } + + if (!tx_frm_download_comp_cb) + return CDF_STATUS_SUCCESS; + + /* + * Wait for Download Complete + * if required + */ + if (downld_comp_required) { + /* + * Wait for Download Complete + * @ Integrated : Dxe Complete + * @ Discrete : Target Download Complete + */ + cdf_status = + cdf_wait_single_event(&wma_handle-> + tx_frm_download_comp_event, + WMA_TX_FRAME_COMPLETE_TIMEOUT); + + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("Wait Event failed txfrm_comp_event"); + /* + * @Integrated: Something Wrong with Dxe + * TODO: Some Debug Code + * Here We need to trigger SSR since + * since system went into a bad state where + * we didn't get Download Complete for almost + * WMA_TX_FRAME_COMPLETE_TIMEOUT (1 sec) + */ + } + } else { + /* + * For Low Latency Devices + * Call the download complete + * callback once the frame is successfully + * given to txrx module + */ + tx_frm_download_comp_cb(wma_handle->mac_context, tx_frame, + WMA_TX_FRAME_BUFFER_NO_FREE); + } + + return CDF_STATUS_SUCCESS; + +error: + wma_handle->tx_frm_download_comp_cb = NULL; + return CDF_STATUS_E_FAILURE; +} + +/** + * wma_ds_peek_rx_packet_info() - peek rx packet info + * @pkt: packet + * @pkt_meta: packet meta + * @bSwap: byte swap + * + * Function fills the rx packet meta info from the the cds packet + * + * Return: CDF status + */ +CDF_STATUS wma_ds_peek_rx_packet_info(cds_pkt_t *pkt, void **pkt_meta, + bool bSwap) +{ + /* Sanity Check */ + if (pkt == NULL) { + WMA_LOGE("wma:Invalid parameter sent on wma_peek_rx_pkt_info"); + return CDF_STATUS_E_FAULT; + } + + *pkt_meta = &(pkt->pkt_meta); + + return CDF_STATUS_SUCCESS; +} + +/** + * ol_rx_err() - ol rx err handler + * @pdev: ol pdev + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * @tid: TID + * @tsf32: TSF + * @err_type: error type + * @rx_frame: rx frame + * @pn: PN Number + * @key_id: key id + * + * This function handles rx error and send MIC error failure to LIM + * + * Return: none + */ +void ol_rx_err(ol_pdev_handle pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, cdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + tpSirSmeMicFailureInd mic_err_ind; + struct ether_header *eth_hdr; + cds_msg_t cds_msg; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return; + } + + if (err_type != OL_RX_ERR_TKIP_MIC) + return; + + if (cdf_nbuf_len(rx_frame) < sizeof(*eth_hdr)) + return; + eth_hdr = (struct ether_header *)cdf_nbuf_data(rx_frame); + mic_err_ind = cdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) { + WMA_LOGE("%s: Failed to allocate memory for MIC indication message", + __func__); + return; + } + cdf_mem_set((void *)mic_err_ind, sizeof(*mic_err_ind), 0); + + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + mic_err_ind->sessionId = vdev_id; + cdf_mem_copy(mic_err_ind->bssId, + (struct cdf_mac_addr *) wma->interfaces[vdev_id].bssid, + sizeof(tSirMacAddr)); + cdf_mem_copy(mic_err_ind->info.taMacAddr, + (struct cdf_mac_addr *) peer_mac_addr, + sizeof(tSirMacAddr)); + cdf_mem_copy(mic_err_ind->info.srcMacAddr, + (struct cdf_mac_addr *) eth_hdr->ether_shost, + sizeof(tSirMacAddr)); + cdf_mem_copy(mic_err_ind->info.dstMacAddr, + (struct cdf_mac_addr *) eth_hdr->ether_dhost, + sizeof(tSirMacAddr)); + mic_err_ind->info.keyId = key_id; + mic_err_ind->info.multicast = + IEEE80211_IS_MULTICAST(eth_hdr->ether_dhost); + cdf_mem_copy(mic_err_ind->info.TSC, pn, SIR_CIPHER_SEQ_CTR_SIZE); + + cdf_mem_set(&cds_msg, sizeof(cds_msg_t), 0); + cds_msg.type = eWNI_SME_MIC_FAILURE_IND; + cds_msg.bodyptr = (void *) mic_err_ind; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg)) { + WMA_LOGE("%s: could not post mic failure indication to SME", + __func__); + cdf_mem_free((void *)mic_err_ind); + } +} + +/** + * wma_tx_abort() - abort tx + * @vdev_id: vdev id + * + * In case of deauth host abort transmitting packet. + * + * Return: none + */ +void wma_tx_abort(uint8_t vdev_id) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + tp_wma_handle wma; + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + struct wma_txrx_node *iface; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: %p", + __func__, iface->handle); + return; + } + WMA_LOGA("%s: vdevid %d bssid %pM", __func__, vdev_id, iface->bssid); + iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST); + ol_txrx_vdev_pause(iface->handle, OL_TXQ_PAUSE_REASON_TX_ABORT); + + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + wmi_unified_peer_flush_tids_send(wma->wmi_handle, iface->bssid, + peer_tid_bitmap, vdev_id); +} + +#if defined(FEATURE_LRO) +/** + * wma_lro_config_cmd() - process the LRO config command + * @wma: Pointer to WMA handle + * @wma_lro_cmd: Pointer to LRO configuration parameters + * + * This function sends down the LRO configuration parameters to + * the firmware to enable LRO, sets the TCP flags and sets the + * seed values for the toeplitz hash generation + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd) +{ + wmi_lro_info_cmd_fixed_param *cmd; + wmi_buf_t buf; + int status; + + if (NULL == wma_handle || NULL == wma_lro_cmd) { + WMA_LOGE("wma_lro_config_cmd': invalid input!"); + return CDF_STATUS_E_FAILURE; + } + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set key cmd"); + return CDF_STATUS_E_FAILURE; + } + + cmd = (wmi_lro_info_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_lro_info_cmd_fixed_param)); + + cmd->lro_enable = wma_lro_cmd->lro_enable; + WMI_LRO_INFO_TCP_FLAG_VALS_SET(cmd->tcp_flag_u32, + wma_lro_cmd->tcp_flag); + WMI_LRO_INFO_TCP_FLAGS_MASK_SET(cmd->tcp_flag_u32, + wma_lro_cmd->tcp_flag_mask); + cmd->toeplitz_hash_ipv4_0_3 = + wma_lro_cmd->toeplitz_hash_ipv4[0]; + cmd->toeplitz_hash_ipv4_4_7 = + wma_lro_cmd->toeplitz_hash_ipv4[1]; + cmd->toeplitz_hash_ipv4_8_11 = + wma_lro_cmd->toeplitz_hash_ipv4[2]; + cmd->toeplitz_hash_ipv4_12_15 = + wma_lro_cmd->toeplitz_hash_ipv4[3]; + cmd->toeplitz_hash_ipv4_16 = + wma_lro_cmd->toeplitz_hash_ipv4[4]; + + cmd->toeplitz_hash_ipv6_0_3 = + wma_lro_cmd->toeplitz_hash_ipv6[0]; + cmd->toeplitz_hash_ipv6_4_7 = + wma_lro_cmd->toeplitz_hash_ipv6[1]; + cmd->toeplitz_hash_ipv6_8_11 = + wma_lro_cmd->toeplitz_hash_ipv6[2]; + cmd->toeplitz_hash_ipv6_12_15 = + wma_lro_cmd->toeplitz_hash_ipv6[3]; + cmd->toeplitz_hash_ipv6_16_19 = + wma_lro_cmd->toeplitz_hash_ipv6[4]; + cmd->toeplitz_hash_ipv6_20_23 = + wma_lro_cmd->toeplitz_hash_ipv6[5]; + cmd->toeplitz_hash_ipv6_24_27 = + wma_lro_cmd->toeplitz_hash_ipv6[6]; + cmd->toeplitz_hash_ipv6_28_31 = + wma_lro_cmd->toeplitz_hash_ipv6[7]; + cmd->toeplitz_hash_ipv6_32_35 = + wma_lro_cmd->toeplitz_hash_ipv6[8]; + cmd->toeplitz_hash_ipv6_36_39 = + wma_lro_cmd->toeplitz_hash_ipv6[9]; + cmd->toeplitz_hash_ipv6_40 = + wma_lro_cmd->toeplitz_hash_ipv6[10]; + + WMA_LOGD("WMI_LRO_CONFIG: lro_enable %d, tcp_flag 0x%x", + cmd->lro_enable, cmd->tcp_flag_u32); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), WMI_LRO_CONFIG_CMDID); + if (status) { + cdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send WMI_LRO_CONFIG_CMDID", __func__); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c new file mode 100644 index 0000000000..587b327cf8 --- /dev/null +++ b/core/wma/src/wma_dev_if.c @@ -0,0 +1,4470 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_dev_if.c + * This file contains vdev & peer related operations. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +/* FIXME: Inclusion of .c looks odd but this is how it is in internal codebase */ +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +#include "wma_ocb.h" + +/** + * wma_find_vdev_by_addr() - find vdev_id from mac address + * @wma: wma handle + * @addr: mac address + * @vdev_id: return vdev_id + * + * Return: Returns vdev handle or NULL if mac address don't match + */ +void *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id) +{ + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + if (cdf_is_macaddr_equal( + (struct cdf_mac_addr *) wma->interfaces[i].addr, + (struct cdf_mac_addr *) addr) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + return NULL; +} + + +/** + * wma_is_vdev_in_ap_mode() - check that vdev is in ap mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in AP mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id > wma->max_bssid) { + WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); + CDF_ASSERT(0); + return false; + } + + if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && + ((intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) || + (intf[vdev_id].sub_type == 0))) + return true; + + return false; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_is_vdev_in_ibss_mode() - check that vdev is in ibss mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in IBSS mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id > wma->max_bssid) { + WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); + CDF_ASSERT(0); + return false; + } + + if (intf[vdev_id].type == WMI_VDEV_TYPE_IBSS) + return true; + + return false; +} +#endif /* QCA_IBSS_SUPPORT */ + + +/** + * wma_find_vdev_by_bssid() - Get the corresponding vdev_id from BSSID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: fill vdev_id with appropriate vdev id and return vdev + * handle or NULL if not found. + */ +void *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id) +{ + int i; + + for (i = 0; i < wma->max_bssid; i++) { + if (cdf_is_macaddr_equal( + (struct cdf_mac_addr *) wma->interfaces[i].bssid, + (struct cdf_mac_addr *) bssid) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + + return NULL; +} + +/** + * wma_get_txrx_vdev_type() - return operating mode of vdev + * @type: vdev_type + * + * Return: return operating mode as enum wlan_op_mode type + */ +enum wlan_op_mode wma_get_txrx_vdev_type(uint32_t type) +{ + enum wlan_op_mode vdev_type = wlan_op_mode_unknown; + switch (type) { + case WMI_VDEV_TYPE_AP: + vdev_type = wlan_op_mode_ap; + break; + case WMI_VDEV_TYPE_STA: + vdev_type = wlan_op_mode_sta; + break; +#ifdef QCA_IBSS_SUPPORT + case WMI_VDEV_TYPE_IBSS: + vdev_type = wlan_op_mode_ibss; + break; +#endif /* QCA_IBSS_SUPPORT */ + case WMI_VDEV_TYPE_OCB: + vdev_type = wlan_op_mode_ocb; + break; + case WMI_VDEV_TYPE_MONITOR: + default: + WMA_LOGE("Invalid vdev type %u", type); + vdev_type = wlan_op_mode_unknown; + } + + return vdev_type; +} + +/** + * wma_unified_vdev_create_send() - send VDEV create command to fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * @type: vdev type + * @subtype: vdev subtype + * @macaddr: vdev mac address + * + * Return: 0 for success or error code + */ +int wma_unified_vdev_create_send(wmi_unified_t wmi_handle, uint8_t if_id, + uint32_t type, uint32_t subtype, + uint8_t macaddr[IEEE80211_ADDR_LEN]) +{ + wmi_vdev_create_cmd_fixed_param *cmd; + wmi_buf_t buf; + int len = sizeof(*cmd); + int ret; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGP("%s:wmi_buf_alloc failed", __FUNCTION__); + return -ENOMEM; + } + cmd = (wmi_vdev_create_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_create_cmd_fixed_param)); + cmd->vdev_id = if_id; + cmd->vdev_type = type; + cmd->vdev_subtype = subtype; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->vdev_macaddr); + WMA_LOGE("%s: ID = %d VAP Addr = %02x:%02x:%02x:%02x:%02x:%02x", + __func__, if_id, + macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_CREATE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_VDEV_CREATE_CMDID"); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wma_unified_vdev_delete_send() - send VDEV delete command to fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * + * Return: 0 for success or error code + */ +static int wma_unified_vdev_delete_send(wmi_unified_t wmi_handle, uint8_t if_id) +{ + wmi_vdev_delete_cmd_fixed_param *cmd; + wmi_buf_t buf; + int ret; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGP("%s:wmi_buf_alloc failed", __FUNCTION__); + return -ENOMEM; + } + + cmd = (wmi_vdev_delete_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_delete_cmd_fixed_param)); + cmd->vdev_id = if_id; + ret = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(wmi_vdev_delete_cmd_fixed_param), + WMI_VDEV_DELETE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_VDEV_DELETE_CMDID"); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wma_find_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + cdf_list_node_t *node1 = NULL, *node2 = NULL; + CDF_STATUS status; + + cdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (CDF_STATUS_SUCCESS != cdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("unable to get msg node from request queue")); + return NULL; + } + + do { + node1 = node2; + req_msg = cdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + status = cdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (CDF_STATUS_SUCCESS != status) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGD(FL("Failed to remove request for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + break; + } while (CDF_STATUS_SUCCESS == + cdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + if (!found) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGD(FL("target request found for vdev id: %d type %d"), + vdev_id, type); + + return req_msg; +} + +/** + * wma_find_vdev_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL, *tmp; + bool found = false; + + cdf_spin_lock_bh(&wma->vdev_respq_lock); + list_for_each_entry_safe(req_msg, tmp, &wma->vdev_resp_queue, node) { + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + list_del(&req_msg->node); + break; + } + cdf_spin_unlock_bh(&wma->vdev_respq_lock); + if (!found) { + WMA_LOGP("%s: target request not found for vdev_id %d type %d", + __func__, vdev_id, type); + return NULL; + } + WMA_LOGD("%s: target request found for vdev id: %d type %d msg %d", + __func__, vdev_id, type, req_msg->msg_type); + return req_msg; +} + +/** + * wma_vdev_detach_callback() - send vdev detach response to upper layer + * @ctx: txrx node ptr + * + * Return: none + */ +void wma_vdev_detach_callback(void *ctx) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface = (struct wma_txrx_node *)ctx; + struct del_sta_self_params *param; + struct wma_target_req *req_msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + + if (!wma || !iface->del_staself_req) { + WMA_LOGP("%s: wma %p iface %p", __func__, wma, + iface->del_staself_req); + return; + } + param = (struct del_sta_self_params *) iface->del_staself_req; + WMA_LOGD("%s: sending eWNI_SME_DEL_STA_SELF_RSP for vdev %d", + __func__, param->session_id); + + req_msg = wma_find_vdev_req(wma, param->session_id, + WMA_TARGET_REQ_TYPE_VDEV_DEL); + if (req_msg) { + WMA_LOGD("%s: Found vdev request for vdev id %d", + __func__, param->session_id); + cdf_mc_timer_stop(&req_msg->event_timeout); + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); + } + if (iface->addBssStaContext) + cdf_mem_free(iface->addBssStaContext); + +#if defined WLAN_FEATURE_VOWIFI_11R + if (iface->staKeyParams) + cdf_mem_free(iface->staKeyParams); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + cdf_mem_zero(iface, sizeof(*iface)); + param->status = CDF_STATUS_SUCCESS; + sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + + status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + cdf_mem_free(param); + } +} + +/** + * wma_vdev_detach() - send vdev delete command to fw + * @wma_handle: wma handle + * @pdel_sta_self_req_param: del sta params + * @generateRsp: generate Response flag + * + * Return: CDF status + */ +CDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + uint8_t vdev_id = pdel_sta_self_req_param->session_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct wma_target_req *msg; + cds_msg_t sme_msg = { 0 }; + + if ((iface->type == WMI_VDEV_TYPE_AP) && + (iface->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) { + + WMA_LOGA("P2P Device: removing self peer %pM", + pdel_sta_self_req_param->self_mac_addr); + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return CDF_STATUS_E_FAULT; + } + + peer = ol_txrx_find_peer_by_addr(pdev, + pdel_sta_self_req_param->self_mac_addr, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + pdel_sta_self_req_param->self_mac_addr); + } + wma_remove_peer(wma_handle, + pdel_sta_self_req_param->self_mac_addr, + vdev_id, peer, false); + } + if (cdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) { + WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion", + vdev_id); + iface->del_staself_req = pdel_sta_self_req_param; + return status; + } + + if (!iface->handle) { + WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed", + vdev_id); + cdf_mem_free(pdel_sta_self_req_param); + pdel_sta_self_req_param = NULL; + return status; + } + + + /* remove the interface from ath_dev */ + if (wma_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id)) { + WMA_LOGE("Unable to remove an interface for ath_dev."); + status = CDF_STATUS_E_FAILURE; + goto out; + } + + WMA_LOGA("vdev_id:%hu vdev_hdl:%p", vdev_id, iface->handle); + if (!generateRsp) { + WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id); + ol_txrx_vdev_detach(iface->handle, NULL, NULL); + goto out; + } + + iface->del_staself_req = pdel_sta_self_req_param; + msg = wma_fill_vdev_req(wma_handle, vdev_id, WMA_DEL_STA_SELF_REQ, + WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 2000); + if (!msg) { + WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d", + __func__, vdev_id); + status = CDF_STATUS_E_NOMEM; + goto out; + } + WMA_LOGE("Call txrx detach with callback for vdev %d", vdev_id); + ol_txrx_vdev_detach(iface->handle, NULL, NULL); + wma_vdev_detach_callback(iface); + return status; +out: + if (iface->addBssStaContext) + cdf_mem_free(iface->addBssStaContext); +#if defined WLAN_FEATURE_VOWIFI_11R + if (iface->staKeyParams) + cdf_mem_free(iface->staKeyParams); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + cdf_mem_zero(iface, sizeof(*iface)); + pdel_sta_self_req_param->status = status; + if (generateRsp) { + sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP; + sme_msg.bodyptr = pdel_sta_self_req_param; + sme_msg.bodyval = 0; + + status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + cdf_mem_free(pdel_sta_self_req_param); + } + } + return status; +} + +/** + * wmi_unified_peer_delete_send() - send PEER delete command to fw + * @wmi: wmi handle + * @peer_addr: peer mac addr + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +static int32_t wmi_unified_peer_delete_send(wmi_unified_t wmi, + uint8_t + peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id) +{ + wmi_peer_delete_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_peer_delete_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_delete_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->vdev_id = vdev_id; + + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_DELETE_CMDID)) { + WMA_LOGP("%s: Failed to send peer delete command", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); + return 0; +} + +/** + * wma_vdev_start_rsp() - send vdev start response to upper layer + * @wma: wma handle + * @add_bss: add bss params + * @resp_event: response params + * + * Return: none + */ +static void wma_vdev_start_rsp(tp_wma_handle wma, + tpAddBssParams add_bss, + wmi_vdev_start_response_event_fixed_param * + resp_event) +{ + struct beacon_info *bcn; + +#ifdef QCA_IBSS_SUPPORT + WMA_LOGD("%s: vdev start response received for %s mode", __func__, + add_bss->operMode == + BSS_OPERATIONAL_MODE_IBSS ? "IBSS" : "non-IBSS"); +#endif /* QCA_IBSS_SUPPORT */ + + if (resp_event->status) { + add_bss->status = CDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + + if ((add_bss->operMode == BSS_OPERATIONAL_MODE_AP) +#ifdef QCA_IBSS_SUPPORT + || (add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS) +#endif /* QCA_IBSS_SUPPORT */ + ) { + wma->interfaces[resp_event->vdev_id].beacon = + cdf_mem_malloc(sizeof(struct beacon_info)); + + bcn = wma->interfaces[resp_event->vdev_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Failed alloc memory for beacon struct", + __func__); + add_bss->status = CDF_STATUS_E_NOMEM; + goto send_fail_resp; + } + cdf_mem_zero(bcn, sizeof(*bcn)); + bcn->buf = cdf_nbuf_alloc(NULL, WMA_BCN_BUF_MAX_SIZE, 0, + sizeof(uint32_t), 0); + if (!bcn->buf) { + WMA_LOGE("%s: No memory allocated for beacon buffer", + __func__); + cdf_mem_free(bcn); + add_bss->status = CDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + bcn->seq_no = MIN_SW_SEQ; + cdf_spinlock_init(&bcn->lock); + cdf_atomic_set(&wma->interfaces[resp_event->vdev_id].bss_status, + WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: AP mode (type %d subtype %d) BSS is started", + __func__, wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + + WMA_LOGD("%s: Allocated beacon struct %p, template memory %p", + __func__, bcn, bcn->buf); + } + add_bss->status = CDF_STATUS_SUCCESS; + add_bss->bssIdx = resp_event->vdev_id; + add_bss->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + add_bss->nss = 1; + } + add_bss->smpsMode = host_map_smps_mode(resp_event->smps_mode); + if (WMA_DEFAULT_HW_MODE_INDEX == wma->new_hw_mode_index) { + WMA_LOGE("%s: Invalid index to update for vdev_id %d", + __func__, resp_event->vdev_id); + } else { + wma_update_intf_hw_mode_params(resp_event->vdev_id, + resp_event->mac_id, wma->new_hw_mode_index); + } +send_fail_resp: + WMA_LOGD("%s: Sending add bss rsp to umac(vdev %d status %d)", + __func__, resp_event->vdev_id, add_bss->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wma_find_mcc_ap() - finds if device is operating AP in MCC mode or not + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * @add: flag indicating if current device is added or deleted + * + * This function parses through all the interfaces in wma and finds if + * any of those devces are in MCC mode with AP. If such a vdev is found + * involved AP vdevs are sent WDA_UPDATE_Q2Q_IE_IND msg to update their + * beacon template to include Q2Q IE. + * + * Return: none + */ +void wma_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id, bool add) +{ + uint8_t i; + uint16_t prev_ch_freq = 0; + bool is_ap = false; + bool result = false; + uint8_t *ap_vdev_ids = NULL; + uint8_t num_ch = 0; + + ap_vdev_ids = cdf_mem_malloc(wma->max_bssid); + if (!ap_vdev_ids) + return; + + for (i = 0; i < wma->max_bssid; i++) { + ap_vdev_ids[i] = -1; + if (add == false && i == vdev_id) + continue; + + if (wma->interfaces[i].vdev_up || (i == vdev_id && add)) { + if (wma->interfaces[i].type == WMI_VDEV_TYPE_AP) { + is_ap = true; + ap_vdev_ids[i] = i; + } + + if (wma->interfaces[i].mhz != prev_ch_freq) { + num_ch++; + prev_ch_freq = wma->interfaces[i].mhz; + } + } + } + + if (is_ap && (num_ch > 1)) + result = true; + else + result = false; + + wma_send_msg(wma, WMA_UPDATE_Q2Q_IE_IND, (void *)ap_vdev_ids, result); +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * wma_vdev_start_resp_handler() - vdev start response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_start_response_event_fixed_param *resp_event; + struct wma_target_req *req_msg; + struct wma_txrx_node *iface; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + return -EINVAL; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + WMA_LOGD("%s: Enter", __func__); + param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid start response event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + if (!resp_event) { + WMA_LOGE("Invalid start response event buffer"); + return -EINVAL; + } + + if (resp_event->status == CDF_STATUS_SUCCESS) { + wma->interfaces[resp_event->vdev_id].tx_streams = + resp_event->cfgd_tx_streams; + wma->interfaces[resp_event->vdev_id].rx_streams = + resp_event->cfgd_rx_streams; + wma->interfaces[resp_event->vdev_id].chain_mask = + resp_event->chain_mask; + wma->interfaces[resp_event->vdev_id].mac_id = + resp_event->mac_id; + WMA_LOGI("%s: vdev:%d tx ss=%d rx ss=%d chain mask=%d mac=%d", + __func__, + resp_event->vdev_id, + wma->interfaces[resp_event->vdev_id].tx_streams, + wma->interfaces[resp_event->vdev_id].rx_streams, + wma->interfaces[resp_event->vdev_id].chain_mask, + wma->interfaces[resp_event->vdev_id].mac_id); + } + + if ((resp_event->vdev_id <= wma->max_bssid) && + (cdf_atomic_read + (&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) + && (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) { + WMA_LOGE("%s: vdev restart event recevied for hidden ssid set using IOCTL", + __func__); + + if (wmi_unified_vdev_up_send + (wma->wmi_handle, resp_event->vdev_id, 0, + wma->interfaces[resp_event->vdev_id].bssid) < 0) { + WMA_LOGE("%s : failed to send vdev up", __func__); + return -EEXIST; + } + cdf_atomic_set(&wma->interfaces[resp_event->vdev_id]. + vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + wma->interfaces[resp_event->vdev_id].vdev_up = true; + } + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + + if (!req_msg) { + WMA_LOGE("%s: Failed to lookup request message for vdev %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + cdf_mc_timer_stop(&req_msg->event_timeout); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (resp_event->status == CDF_STATUS_SUCCESS + && mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, resp_event->vdev_id, true); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + iface = &wma->interfaces[resp_event->vdev_id]; + if (req_msg->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) req_msg->user_data; + if (!params) { + WMA_LOGE("%s: channel switch params is NULL for vdev %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + WMA_LOGD("%s: Send channel switch resp vdev %d status %d", + __func__, resp_event->vdev_id, resp_event->status); + params->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + params->nss = 1; + } + params->smpsMode = host_map_smps_mode(resp_event->smps_mode); + params->status = resp_event->status; + if (resp_event->resp_type == WMI_VDEV_RESTART_RESP_EVENT && + (iface->type == WMI_VDEV_TYPE_STA)) { + if (wmi_unified_vdev_up_send(wma->wmi_handle, + resp_event->vdev_id, + iface->aid, + iface->bssid)) { + WMA_LOGE("%s:vdev_up failed vdev_id %d", + __func__, resp_event->vdev_id); + wma->interfaces[resp_event->vdev_id].vdev_up = + false; + } else { + wma->interfaces[resp_event->vdev_id].vdev_up = + true; + } + } + + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams bssParams = (tpAddBssParams) req_msg->user_data; + cdf_mem_copy(iface->bssid, bssParams->bssId, + IEEE80211_ADDR_LEN); + wma_vdev_start_rsp(wma, bssParams, resp_event); + } else if (req_msg->msg_type == WMA_OCB_SET_CONFIG_CMD) { + if (wmi_unified_vdev_up_send(wma->wmi_handle, + resp_event->vdev_id, iface->aid, + iface->bssid) < 0) { + WMA_LOGE(FL("failed to send vdev up")); + return -EEXIST; + } + iface->vdev_up = true; + + wma_ocb_start_resp_ind_cont(wma); + } + + if ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && + wma->interfaces[resp_event->vdev_id].vdev_up) + wma_set_sap_keepalive(wma, resp_event->vdev_id); + + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); + + return 0; +} + +/** + * wmi_unified_vdev_set_param_send() - set per vdev params in fw + * @wmi_handle: wmi handle + * @if_if: vdev id + * @param_id: parameter id + * @param_value: parameter value + * + * Return: 0 for success or error code + */ +int +wmi_unified_vdev_set_param_send(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value) +{ + int ret; + wmi_vdev_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_vdev_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_param_cmd_fixed_param)); + cmd->vdev_id = if_id; + cmd->param_id = param_id; + cmd->param_value = param_value; + WMA_LOGD("Setting vdev %d param = %x, value = %u", + if_id, param_id, param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_PARAM_CMDID); + if (ret < 0) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wmi_unified_peer_flush_tids_send() - flush peer tids packets in fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @peer_tid_bitmap: peer tid bitmap + * @vdev_id: vdev id + * + * Return: 0 for sucess or error code + */ +int32_t wmi_unified_peer_flush_tids_send(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_tid_bitmap, + uint8_t vdev_id) +{ + wmi_peer_flush_tids_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_peer_flush_tids_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_flush_tids_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->peer_tid_bitmap = peer_tid_bitmap; + cmd->vdev_id = vdev_id; + + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_FLUSH_TIDS_CMDID)) { + WMA_LOGP("%s: Failed to send flush tid command", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); + return 0; +} + +/** + * wma_set_peer_authorized_cb() - set peer authorized callback function + * @wma_Ctx: wma handle + * @auth_cb: peer authorized callback + * + * Return: none + */ +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + wma_handle->peer_authorized_cb = auth_cb; +} + +/** + * wma_set_peer_param() - set peer parameter in fw + * @wma_ctx: wma handle + * @peer_addr: peer mac address + * @param_id: parameter id + * @param_value: parameter value + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, uint32_t param_id, + uint32_t param_value, uint32_t vdev_id) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + wmi_peer_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set_param cmd"); + return -ENOMEM; + } + cmd = (wmi_peer_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_set_param_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param_id = param_id; + cmd->param_value = param_value; + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(wmi_peer_set_param_cmd_fixed_param), + WMI_PEER_SET_PARAM_CMDID); + if (err) { + WMA_LOGE("Failed to send set_param cmd"); + cdf_mem_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_remove_peer() - send remove peer command to fw + * @wma: wma handle + * @bssid: mac address + * @vdev_id: vdev id + * @peer: peer ptr + * @roam_synch_in_progress: roam in progress flag + * + * Return: none + */ +void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, + uint8_t vdev_id, ol_txrx_peer_handle peer, + bool roam_synch_in_progress) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + uint8_t *peer_addr = bssid; + if (!wma->interfaces[vdev_id].peer_count) { + WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, bssid, vdev_id, + wma->interfaces[vdev_id].peer_count); + return; + } + if (peer) + ol_txrx_peer_detach(peer); + + wma->interfaces[vdev_id].peer_count--; + WMA_LOGE("%s: Removed peer with peer_addr %pM vdevid %d peer_count %d", + __func__, bssid, vdev_id, wma->interfaces[vdev_id].peer_count); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_synch_in_progress) + return; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid, + peer_tid_bitmap, vdev_id); + +#if defined(QCA_IBSS_SUPPORT) + if ((peer) && (wma_is_vdev_in_ibss_mode(wma, vdev_id))) { + WMA_LOGD("%s: bssid %pM peer->mac_addr %pM", __func__, + bssid, peer->mac_addr.raw); + peer_addr = peer->mac_addr.raw; + } +#endif /* QCA_IBSS_SUPPORT */ + + wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, vdev_id); +#undef PEER_ALL_TID_BITMASK +} + +/** + * wmi_unified_peer_create_send() - send peer create command to fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @peer_type: peer type + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +static int wmi_unified_peer_create_send(wmi_unified_t wmi, + const uint8_t *peer_addr, + uint32_t peer_type, uint32_t vdev_id) +{ + wmi_peer_create_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_peer_create_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_create_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->peer_type = peer_type; + cmd->vdev_id = vdev_id; + + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_CREATE_CMDID)) { + WMA_LOGP("%s: failed to send WMI_PEER_CREATE_CMDID", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + WMA_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); + return 0; +} + +/** + * wma_create_peer() - send peer create command to fw + * @wma: wma handle + * @pdev: txrx pdev ptr + * @vdev: txrx vdev ptr + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + * @roam_synch_in_progress: roam in progress + * + * Return: CDF status + */ +CDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress) +{ + ol_txrx_peer_handle peer; + + if (++wma->interfaces[vdev_id].peer_count > + wma->wlan_resource_config.num_peers) { + WMA_LOGP("%s, the peer count exceeds the limit %d", __func__, + wma->interfaces[vdev_id].peer_count - 1); + goto err; + } + peer = ol_txrx_peer_attach(pdev, vdev, peer_addr); + if (!peer) { + WMA_LOGE("%s : Unable to attach peer %pM", __func__, peer_addr); + goto err; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_synch_in_progress) { + + WMA_LOGE("%s: Created peer with peer_addr %pM vdev_id %d," + "peer_count - %d", __func__, peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + return CDF_STATUS_SUCCESS; + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + if (wmi_unified_peer_create_send(wma->wmi_handle, peer_addr, + peer_type, vdev_id) < 0) { + WMA_LOGP("%s : Unable to create peer in Target", __func__); + ol_txrx_peer_detach(peer); + goto err; + } + WMA_LOGE("%s: Created peer with peer_addr %pM vdev_id %d, peer_count - %d", + __func__, peer_addr, vdev_id, wma->interfaces[vdev_id].peer_count); + +#ifdef QCA_IBSS_SUPPORT + /* for each remote ibss peer, clear its keys */ + if (wma_is_vdev_in_ibss_mode(wma, vdev_id) && + !cdf_mem_compare(peer_addr, vdev->mac_addr.raw, + IEEE80211_ADDR_LEN)) { + + tSetStaKeyParams key_info; + WMA_LOGD("%s: remote ibss peer %pM key clearing\n", __func__, + peer_addr); + cdf_mem_set(&key_info, sizeof(key_info), 0); + key_info.smesessionId = vdev_id; + cdf_mem_copy(key_info.peerMacAddr, peer_addr, + IEEE80211_ADDR_LEN); + key_info.sendRsp = false; + + wma_set_stakey(wma, &key_info); + } +#endif /* QCA_IBSS_SUPPORT */ + + return CDF_STATUS_SUCCESS; +err: + wma->interfaces[vdev_id].peer_count--; + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_down_send() - send vdev down command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +static int wmi_unified_vdev_down_send(wmi_unified_t wmi, uint8_t vdev_id) +{ + wmi_vdev_down_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s : wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_vdev_down_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_down_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_DOWN_CMDID)) { + WMA_LOGP("%s: Failed to send vdev down", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + WMA_LOGE("%s: vdev_id %d", __func__, vdev_id); + return 0; +} + +#ifdef QCA_IBSS_SUPPORT + +/** + * wma_delete_all_ibss_peers() - delete all ibss peer for vdev_id + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send peer delete command to fw for all + * peers in peer_list and remove ref count for peer id + * peer will actually remove from list after receving + * unmap event from firmware. + * + * Return: none + */ +static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) +{ + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer, temp; + + if (!wma || vdev_id > wma->max_bssid) + return; + + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) + return; + + /* remove all remote peers of IBSS */ + cdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + + temp = NULL; + TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, peer_list_elem) { + if (temp) { + cdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + if (cdf_atomic_read(&temp->delete_in_progress) == 0) { + wma_remove_peer(wma, temp->mac_addr.raw, + vdev_id, temp, false); + } + cdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + } + /* self peer is deleted last */ + if (peer == TAILQ_FIRST(&vdev->peer_list)) { + WMA_LOGE("%s: self peer removed by caller ", __func__); + break; + } else + temp = peer; + } + cdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + + /* remove IBSS bss peer last */ + peer = TAILQ_FIRST(&vdev->peer_list); + wma_remove_peer(wma, wma->interfaces[vdev_id].bssid, vdev_id, peer, + false); +} + +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_delete_all_ap_remote_peers() - delete all ap peer for vdev_id + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send peer delete command to fw for all + * peers in peer_list and remove ref count for peer id + * peer will actually remove from list after receving + * unmap event from firmware. + * + * Return: none + */ +static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) +{ + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer, temp; + + if (!wma || vdev_id > wma->max_bssid) + return; + + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) + return; + + WMA_LOGE("%s: vdev_id - %d", __func__, vdev_id); + /* remove all remote peers of SAP */ + cdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + + temp = NULL; + TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, + peer_list_elem) { + if (temp) { + cdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + if (cdf_atomic_read(&temp->delete_in_progress) == 0) { + wma_remove_peer(wma, temp->mac_addr.raw, + vdev_id, temp, false); + } + cdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + } + /* self peer is deleted by caller */ + if (peer == TAILQ_FIRST(&vdev->peer_list)) { + WMA_LOGE("%s: self peer removed by caller ", __func__); + break; + } else + temp = peer; + } + + cdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); +} + +#ifdef QCA_IBSS_SUPPORT + +/** + * wma_recreate_ibss_vdev_and_bss_peer() - recreate IBSS vdev and create peer + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_recreate_ibss_vdev_and_bss_peer(tp_wma_handle wma, + uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + struct add_sta_self_params add_sta_self_param; + struct del_sta_self_params del_sta_param; + CDF_STATUS status; + + if (!wma) { + WMA_LOGE("%s: Null wma handle", __func__); + return; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s: Can't find vdev with id %d", __func__, vdev_id); + return; + } + + cdf_copy_macaddr( + (struct cdf_mac_addr *) &(add_sta_self_param.self_mac_addr), + (struct cdf_mac_addr *) &(vdev->mac_addr)); + add_sta_self_param.session_id = vdev_id; + add_sta_self_param.type = WMI_VDEV_TYPE_IBSS; + add_sta_self_param.sub_type = 0; + add_sta_self_param.status = 0; + + /* delete old ibss vdev */ + del_sta_param.session_id = vdev_id; + cdf_mem_copy((void *)del_sta_param.self_mac_addr, + (void *)&(vdev->mac_addr), CDF_MAC_ADDR_SIZE); + wma_vdev_detach(wma, &del_sta_param, 0); + + /* create new vdev for ibss */ + vdev = wma_vdev_attach(wma, &add_sta_self_param, 0); + if (!vdev) { + WMA_LOGE("%s: Failed to create vdev", __func__); + return; + } + + /* Register with TxRx Module for Data Ack Complete Cb */ + ol_txrx_data_tx_cb_set(vdev, wma_data_tx_ack_comp_hdlr, wma); + WMA_LOGA("new IBSS vdev created with mac %pM", + add_sta_self_param.self_mac_addr); + + /* create ibss bss peer */ + status = wma_create_peer(wma, vdev->pdev, vdev, vdev->mac_addr.raw, + WMI_PEER_TYPE_DEFAULT, vdev_id, false); + if (status != CDF_STATUS_SUCCESS) + WMA_LOGE("%s: Failed to create IBSS bss peer", __func__); + else + WMA_LOGA("IBSS BSS peer created with mac %pM", + vdev->mac_addr.raw); +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_hidden_ssid_vdev_restart_on_vdev_stop() - restart vdev to set hidden ssid + * @wma_handle: wma handle + * @sessionId: session id + * + * Return: none + */ +void wma_hidden_ssid_vdev_restart_on_vdev_stop(tp_wma_handle wma_handle, + uint8_t sessionId) +{ + wmi_vdev_start_request_cmd_fixed_param *cmd; + wmi_buf_t buf; + wmi_channel *chan; + int32_t len; + uint8_t *buf_ptr; + struct wma_txrx_node *intr = wma_handle->interfaces; + int32_t ret = 0; + + len = sizeof(*cmd) + sizeof(wmi_channel) + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + cdf_atomic_set(&intr[sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + return; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr; + chan = (wmi_channel *) (buf_ptr + sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_start_request_cmd_fixed_param)); + + WMITLV_SET_HDR(&chan->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + + cmd->vdev_id = sessionId; + cmd->ssid.ssid_len = intr[sessionId].vdev_restart_params.ssid.ssid_len; + cdf_mem_copy(cmd->ssid.ssid, + intr[sessionId].vdev_restart_params.ssid.ssid, + cmd->ssid.ssid_len); + cmd->flags = intr[sessionId].vdev_restart_params.flags; + if (intr[sessionId].vdev_restart_params.ssidHidden) + cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + else + cmd->flags &= (0xFFFFFFFE); + cmd->requestor_id = intr[sessionId].vdev_restart_params.requestor_id; + cmd->disable_hw_ack = + intr[sessionId].vdev_restart_params.disable_hw_ack; + + chan->mhz = intr[sessionId].vdev_restart_params.chan.mhz; + chan->band_center_freq1 = + intr[sessionId].vdev_restart_params.chan.band_center_freq1; + chan->band_center_freq2 = + intr[sessionId].vdev_restart_params.chan.band_center_freq2; + chan->info = intr[sessionId].vdev_restart_params.chan.info; + chan->reg_info_1 = intr[sessionId].vdev_restart_params.chan.reg_info_1; + chan->reg_info_2 = intr[sessionId].vdev_restart_params.chan.reg_info_2; + + cmd->num_noa_descriptors = 0; + buf_ptr = (uint8_t *) (((uint8_t *) cmd) + sizeof(*cmd) + + sizeof(wmi_channel)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->num_noa_descriptors * + sizeof(wmi_p2p_noa_descriptor)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_RESTART_REQUEST_CMDID); + if (ret < 0) { + WMA_LOGE("%s: Failed to send vdev restart command", __func__); + cdf_atomic_set(&intr[sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + cdf_nbuf_free(buf); + } +} + +/** + * wma_vdev_stop_resp_handler() - vdev stop response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf; + wmi_vdev_stopped_event_fixed_param *resp_event; + struct wma_target_req *req_msg; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + struct wma_txrx_node *iface; + int32_t status = 0; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + return -EINVAL; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + WMA_LOGI("%s: Enter", __func__); + param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid event buffer"); + return -EINVAL; + } + resp_event = param_buf->fixed_param; + + if ((resp_event->vdev_id <= wma->max_bssid) && + (cdf_atomic_read + (&wma->interfaces[resp_event->vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) + && ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) + && (wma->interfaces[resp_event->vdev_id].sub_type == 0))) { + WMA_LOGE("%s: vdev stop event recevied for hidden ssid set using IOCTL ", + __func__); + wma_hidden_ssid_vdev_restart_on_vdev_stop(wma, + resp_event->vdev_id); + } + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + if (!req_msg) { + WMA_LOGP("%s: Failed to lookup vdev request for vdev id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + status = -EINVAL; + cdf_mc_timer_stop(&req_msg->event_timeout); + goto free_req_msg; + } + + cdf_mc_timer_stop(&req_msg->event_timeout); + if (req_msg->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) req_msg->user_data; + struct beacon_info *bcn; + if (resp_event->vdev_id > wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d", __func__, + resp_event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + iface = &wma->interfaces[resp_event->vdev_id]; + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, resp_event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } +#ifdef QCA_IBSS_SUPPORT + if (wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id)) + wma_delete_all_ibss_peers(wma, resp_event->vdev_id); + else +#endif /* QCA_IBSS_SUPPORT */ + { + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { + wma_delete_all_ap_remote_peers(wma, + resp_event->vdev_id); + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, + &peer_id); + if (!peer) + WMA_LOGD("%s Failed to find peer %pM", + __func__, params->bssid); + wma_remove_peer(wma, params->bssid, resp_event->vdev_id, + peer, false); + } + + if (wmi_unified_vdev_down_send + (wma->wmi_handle, resp_event->vdev_id) < 0) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + resp_event->vdev_id); + } else { + wma->interfaces[resp_event->vdev_id].vdev_up = false; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, resp_event->vdev_id, false); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + } + ol_txrx_vdev_flush(iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + __func__, resp_event->vdev_id); + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + cdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + bcn = wma->interfaces[resp_event->vdev_id].beacon; + + if (bcn) { + WMA_LOGD("%s: Freeing beacon struct %p, " + "template memory %p", __func__, bcn, bcn->buf); + if (bcn->dma_mapped) + cdf_nbuf_unmap_single(pdev->osdev, bcn->buf, + CDF_DMA_TO_DEVICE); + cdf_nbuf_free(bcn->buf); + cdf_mem_free(bcn); + wma->interfaces[resp_event->vdev_id].beacon = NULL; + } +#ifdef QCA_IBSS_SUPPORT + /* recreate ibss vdev and bss peer for scan purpose */ + if (wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id)) + wma_recreate_ibss_vdev_and_bss_peer(wma, + resp_event->vdev_id); +#endif /* QCA_IBSS_SUPPORT */ + /* Timeout status means its WMA generated DEL BSS REQ when ADD + * BSS REQ was timed out to stop the VDEV in this case no need + * to send response to UMAC + */ + if (params->status == CDF_STATUS_FW_MSG_TIMEDOUT) { + cdf_mem_free(params); + WMA_LOGE("%s: DEL BSS from ADD BSS timeout do not send " + "resp to UMAC (vdev id %x)", + __func__, resp_event->vdev_id); + } else { + params->status = CDF_STATUS_SUCCESS; + wma_send_msg(wma, WMA_DELETE_BSS_RSP, (void *)params, + 0); + } + + if (iface->del_staself_req) { + WMA_LOGA("scheduling defered deletion (vdev id %x)", + resp_event->vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } + } +free_req_msg: + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); + return status; +} + +/** + * wma_vdev_attach() - create vdev in fw + * @wma_handle: wma handle + * @self_sta_req: self sta request + * @generateRsp: generate response + * + * This function creates vdev in target and + * attach this vdev to txrx module. It also set + * vdev related params to fw. + * + * Return: txrx vdev handle + */ +ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp) +{ + ol_txrx_vdev_handle txrx_vdev_handle = NULL; + ol_txrx_pdev_handle txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + enum wlan_op_mode txrx_vdev_type; + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE); + uint32_t cfg_val; + uint16_t val16; + int ret; + tSirMacHTCapabilityInfo *phtCapInfo; + cds_msg_t sme_msg = { 0 }; + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + goto end; + } + + /* Create a vdev in target */ + if (wma_unified_vdev_create_send(wma_handle->wmi_handle, + self_sta_req->session_id, + self_sta_req->type, + self_sta_req->sub_type, + self_sta_req->self_mac_addr)) { + WMA_LOGP("%s: Unable to add an interface for ath_dev", + __func__); + status = CDF_STATUS_E_RESOURCES; + goto end; + } + + txrx_vdev_type = wma_get_txrx_vdev_type(self_sta_req->type); + + if (wlan_op_mode_unknown == txrx_vdev_type) { + WMA_LOGE("Failed to get txrx vdev type"); + wma_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + + txrx_vdev_handle = ol_txrx_vdev_attach(txrx_pdev, + self_sta_req->self_mac_addr, + self_sta_req->session_id, + txrx_vdev_type); + wma_handle->interfaces[self_sta_req->session_id].pause_bitmap = 0; + + WMA_LOGA("vdev_id %hu, txrx_vdev_handle = %p", self_sta_req->session_id, + txrx_vdev_handle); + + if (NULL == txrx_vdev_handle) { + WMA_LOGP("%s: ol_txrx_vdev_attach failed", __func__); + status = CDF_STATUS_E_FAILURE; + wma_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + wma_handle->interfaces[self_sta_req->session_id].handle = + txrx_vdev_handle; + + wma_handle->interfaces[self_sta_req->session_id].ptrn_match_enable = + wma_handle->ptrn_match_enable_all_vdev ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.deauth_enable = true; + else + wma_handle->wow.deauth_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.disassoc_enable = true; + else + wma_handle->wow.disassoc_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.bmiss_enable = true; + else + wma_handle->wow.bmiss_enable = cfg_val ? true : false; + + cdf_mem_copy(wma_handle->interfaces[self_sta_req->session_id].addr, + self_sta_req->self_mac_addr, + sizeof(wma_handle->interfaces[self_sta_req->session_id]. + addr)); + switch (self_sta_req->type) { + case WMI_VDEV_TYPE_STA: + if (wlan_cfg_get_int(mac, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + &cfg_val) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for " + "WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD"); + cfg_val = DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD; + } + + wma_set_sta_keep_alive(wma_handle, + self_sta_req->session_id, + SIR_KEEP_ALIVE_NULL_PKT, + cfg_val, NULL, NULL, NULL); + break; + } + + wma_handle->interfaces[self_sta_req->session_id].type = + self_sta_req->type; + wma_handle->interfaces[self_sta_req->session_id].sub_type = + self_sta_req->sub_type; + cdf_atomic_init(&wma_handle->interfaces + [self_sta_req->session_id].bss_status); + + if (((self_sta_req->type == WMI_VDEV_TYPE_AP) && + (self_sta_req->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) || + (self_sta_req->type == WMI_VDEV_TYPE_OCB)) { + WMA_LOGA("P2P Device: creating self peer %pM, vdev_id %hu", + self_sta_req->self_mac_addr, self_sta_req->session_id); + status = wma_create_peer(wma_handle, txrx_pdev, + txrx_vdev_handle, + self_sta_req->self_mac_addr, + WMI_PEER_TYPE_DEFAULT, + self_sta_req->session_id, false); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + status = CDF_STATUS_E_FAILURE; + wma_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + } + } + + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE, + mac->roam.configParam.mcc_rts_cts_prot_enable); + if (ret) + WMA_LOGE("Failed to set WMI VDEV MCC_RTSCTS_PROTECTION_ENABLE"); + + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE, + mac->roam.configParam.mcc_bcast_prob_resp_enable); + if (ret) + WMA_LOGE("Failed to set WMI VDEV MCC_BROADCAST_PROBE_ENABLE"); + + if (wlan_cfg_get_int(mac, WNI_CFG_RTS_THRESHOLD, + &cfg_val) == eSIR_SUCCESS) { + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_RTS_THRESHOLD, + cfg_val); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_RTS_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_RTS_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_FRAGMENTATION_THRESHOLD, + &cfg_val) == eSIR_SUCCESS) { + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + cfg_val); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_FRAGMENTATION_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_HT_CAP_INFO, &cfg_val) == eSIR_SUCCESS) { + val16 = (uint16_t) cfg_val; + phtCapInfo = (tSirMacHTCapabilityInfo *) &cfg_val; + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_TX_STBC, + phtCapInfo->txSTBC); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_TX_STBC"); + } else { + WMA_LOGE("Failed to get value of HT_CAP, TX STBC unchanged"); + } + /* Initialize roaming offload state */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) { + wma_handle->roam_offload_enabled = true; + wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, + (WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG | + WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG)); + } + + /* Initialize BMISS parameters */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) + wma_roam_scan_bmiss_cnt(wma_handle, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt, + self_sta_req->session_id); + + if (wlan_cfg_get_int(mac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + WMA_LOGD("%s: setting ini value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED: %d", + __func__, cfg_val); + ret = wma_set_enable_disable_mcc_adaptive_scheduler(cfg_val); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to set WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED"); + } + } else { + WMA_LOGE("Failed to get value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, leaving unchanged"); + } + + wma_register_wow_wakeup_events(wma_handle, self_sta_req->session_id, + self_sta_req->type, + self_sta_req->sub_type); + wma_register_wow_default_patterns(wma_handle, self_sta_req->session_id); + +end: + self_sta_req->status = status; + +#ifdef QCA_IBSS_SUPPORT + if (generateRsp) +#endif + { + sme_msg.type = eWNI_SME_ADD_STA_SELF_RSP; + sme_msg.bodyptr = self_sta_req; + sme_msg.bodyval = 0; + + status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + cdf_mem_free(self_sta_req); + } + } + return txrx_vdev_handle; +} + +/** + * wma_get_center_channel() - get center channel + * @chan: channel number + * @chan_offset: channel offset + * + * Return: center channel + */ +uint8_t wma_get_center_channel(uint8_t chan, uint8_t chan_offset) +{ + uint8_t band_center_chan = 0; + + if ((chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED) || + (chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW)) + band_center_chan = chan + 2; + else if (chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW) + band_center_chan = chan + 6; + else if ((chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH) || + (chan_offset == + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED)) + band_center_chan = chan - 2; + else if (chan_offset == PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH) + band_center_chan = chan - 6; + + return band_center_chan; +} + +/** + * wma_vdev_start() - send vdev start request to fw + * @wma: wma handle + * @req: vdev start params + * @isRestart: isRestart flag + * + * Return: CDF status + */ +CDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart) +{ + wmi_vdev_start_request_cmd_fixed_param *cmd; + wmi_buf_t buf; + wmi_channel *chan; + int32_t len, ret; + WLAN_PHY_MODE chanmode; + uint8_t *buf_ptr; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal mac_ctx = NULL; + struct ath_dfs *dfs; + + mac_ctx = cds_get_context(CDF_MODULE_ID_PE); + if (mac_ctx == NULL) { + WMA_LOGE("%s: vdev start failed as mac_ctx is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + dfs = (struct ath_dfs *)wma->dfs_ic->ic_dfs; + + WMA_LOGD("%s: Enter isRestart=%d vdev=%d", __func__, isRestart, + req->vdev_id); + len = sizeof(*cmd) + sizeof(wmi_channel) + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr; + chan = (wmi_channel *) (buf_ptr + sizeof(*cmd)); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_start_request_cmd_fixed_param)); + WMITLV_SET_HDR(&chan->tlv_header, WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + cmd->vdev_id = req->vdev_id; + + /* Fill channel info */ + chan->mhz = cds_chan_to_freq(req->chan); + chanmode = wma_chan_to_mode(req->chan, req->chan_width, + req->vht_capable, req->dot11_mode); + + intr[cmd->vdev_id].chanmode = chanmode; /* save channel mode */ + intr[cmd->vdev_id].ht_capable = req->ht_capable; + intr[cmd->vdev_id].vht_capable = req->vht_capable; + intr[cmd->vdev_id].config.gtx_info.gtxRTMask[0] = + CFG_TGT_DEFAULT_GTX_HT_MASK; + intr[cmd->vdev_id].config.gtx_info.gtxRTMask[1] = + CFG_TGT_DEFAULT_GTX_VHT_MASK; + intr[cmd->vdev_id].config.gtx_info.gtxUsrcfg = + CFG_TGT_DEFAULT_GTX_USR_CFG; + intr[cmd->vdev_id].config.gtx_info.gtxPERThreshold = + CFG_TGT_DEFAULT_GTX_PER_THRESHOLD; + intr[cmd->vdev_id].config.gtx_info.gtxPERMargin = + CFG_TGT_DEFAULT_GTX_PER_MARGIN; + intr[cmd->vdev_id].config.gtx_info.gtxTPCstep = + CFG_TGT_DEFAULT_GTX_TPC_STEP; + intr[cmd->vdev_id].config.gtx_info.gtxTPCMin = + CFG_TGT_DEFAULT_GTX_TPC_MIN; + intr[cmd->vdev_id].config.gtx_info.gtxBWMask = + CFG_TGT_DEFAULT_GTX_BW_MASK; + intr[cmd->vdev_id].mhz = chan->mhz; + + WMI_SET_CHANNEL_MODE(chan, chanmode); + chan->band_center_freq1 = chan->mhz; + + if (CH_WIDTH_20MHZ != req->chan_width) + chan->band_center_freq1 = + cds_chan_to_freq(req->ch_center_freq_seg0); + if (CH_WIDTH_80P80MHZ == req->chan_width) + chan->band_center_freq2 = + cds_chan_to_freq(req->ch_center_freq_seg1); + else + chan->band_center_freq2 = 0; + + /* Set half or quarter rate WMI flags */ + if (req->is_half_rate) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE); + else if (req->is_quarter_rate) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE); + + /* + * If the channel has DFS set, flip on radar reporting. + * + * It may be that this should only be done for IBSS/hostap operation + * as this flag may be interpreted (at some point in the future) + * by the firmware as "oh, and please do radar DETECTION." + * + * If that is ever the case we would insert the decision whether to + * enable the firmware flag here. + */ + + /* + * If the Channel is DFS, + * set the WMI_CHAN_FLAG_DFS flag + */ + if (req->is_dfs) { + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_DFS); + cmd->disable_hw_ack = true; + + req->dfs_pri_multiplier = wma->dfs_pri_multiplier; + + /* + * Configure the current operating channel + * to DFS module only if the device operating + * mode is AP. + * Enable/Disable Phyerr filtering offload + * depending on dfs_phyerr_filter_offload + * flag status as set in ini for SAP mode. + * Currently, only AP supports DFS master + * mode operation on DFS channels, P2P-GO + * does not support operation on DFS Channels. + */ + if (wma_is_vdev_in_ap_mode(wma, cmd->vdev_id) == true) { + /* + * If DFS regulatory domain is invalid, + * then, DFS radar filters intialization + * will fail. So, do not configure the + * channel in to DFS modlue, do not + * indicate if phyerror filtering offload + * is enabled or not to the firmware, simply + * fail the VDEV start on the DFS channel + * early on, to protect the DFS module from + * processing phyerrors without being intialized. + */ + if (DFS_UNINIT_DOMAIN == + wma->dfs_ic->current_dfs_regdomain) { + WMA_LOGE("%s[%d]:DFS Configured with Invalid regdomain" + " Failed to send VDEV START command", + __func__, __LINE__); + + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + cdf_mutex_acquire(&wma->dfs_ic->chan_lock); + if (wma->dfs_ic->ic_curchan) { + OS_FREE(wma->dfs_ic->ic_curchan); + wma->dfs_ic->ic_curchan = NULL; + } + + /* provide the current channel to DFS */ + wma->dfs_ic->ic_curchan = + wma_dfs_configure_channel(wma->dfs_ic, chan, + chanmode, req); + cdf_mutex_release(&wma->dfs_ic->chan_lock); + + wma_unified_dfs_phyerr_filter_offload_enable(wma); + dfs->disable_dfs_ch_switch = + mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch; + } + } + + cmd->beacon_interval = req->beacon_intval; + cmd->dtim_period = req->dtim_period; + /* FIXME: Find out min, max and regulatory power levels */ + WMI_SET_CHANNEL_REG_POWER(chan, req->max_txpow); + WMI_SET_CHANNEL_MAX_TX_POWER(chan, req->max_txpow); + + /* TODO: Handle regulatory class, max antenna */ + if (!isRestart) { + cmd->beacon_interval = req->beacon_intval; + cmd->dtim_period = req->dtim_period; + + /* Copy the SSID */ + if (req->ssid.length) { + if (req->ssid.length < sizeof(cmd->ssid.ssid)) + cmd->ssid.ssid_len = req->ssid.length; + else + cmd->ssid.ssid_len = sizeof(cmd->ssid.ssid); + cdf_mem_copy(cmd->ssid.ssid, req->ssid.ssId, + cmd->ssid.ssid_len); + } + + if (req->hidden_ssid) + cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + + if (req->pmf_enabled) + cmd->flags |= WMI_UNIFIED_VDEV_START_PMF_ENABLED; + } + + cmd->num_noa_descriptors = 0; + cmd->preferred_rx_streams = req->preferred_rx_streams; + cmd->preferred_tx_streams = req->preferred_tx_streams; + + buf_ptr = (uint8_t *) (((uintptr_t) cmd) + sizeof(*cmd) + + sizeof(wmi_channel)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->num_noa_descriptors * + sizeof(wmi_p2p_noa_descriptor)); + WMA_LOGA("\n%s: vdev_id %d freq %d channel %d chanmode %d is_dfs %d " + "beacon interval %d dtim %d center_chan %d center_freq2 %d " + "reg_info_1: 0x%x reg_info_2: 0x%x, req->max_txpow: 0x%x " + "Tx SS %d, Rx SS %d", + __func__, req->vdev_id, chan->mhz, req->chan, chanmode, + req->is_dfs, req->beacon_intval, cmd->dtim_period, + chan->band_center_freq1, chan->band_center_freq2, + chan->reg_info_1, chan->reg_info_2, req->max_txpow, + req->preferred_tx_streams, req->preferred_rx_streams); + + /* Store vdev params in SAP mode which can be used in vdev restart */ + if (intr[req->vdev_id].type == WMI_VDEV_TYPE_AP && + intr[req->vdev_id].sub_type == 0) { + intr[req->vdev_id].vdev_restart_params.vdev_id = req->vdev_id; + intr[req->vdev_id].vdev_restart_params.ssid.ssid_len = + cmd->ssid.ssid_len; + cdf_mem_copy(intr[req->vdev_id].vdev_restart_params.ssid.ssid, + cmd->ssid.ssid, cmd->ssid.ssid_len); + intr[req->vdev_id].vdev_restart_params.flags = cmd->flags; + intr[req->vdev_id].vdev_restart_params.requestor_id = + cmd->requestor_id; + intr[req->vdev_id].vdev_restart_params.disable_hw_ack = + cmd->disable_hw_ack; + intr[req->vdev_id].vdev_restart_params.chan.mhz = chan->mhz; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq1 = + chan->band_center_freq1; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq2 = + chan->band_center_freq2; + intr[req->vdev_id].vdev_restart_params.chan.info = chan->info; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_1 = + chan->reg_info_1; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_2 = + chan->reg_info_2; + } + + if (isRestart) { + /* + * Marking the VDEV UP STATUS to false + * since, VDEV RESTART will do a VDEV DOWN + * in the firmware. + */ + intr[cmd->vdev_id].vdev_up = false; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_RESTART_REQUEST_CMDID); + + } else { + WMA_LOGD("%s, vdev_id: %d, unpausing tx_ll_queue at VDEV_START", + __func__, cmd->vdev_id); + ol_txrx_vdev_unpause(wma->interfaces[cmd->vdev_id].handle, + 0xffffffff); + wma->interfaces[cmd->vdev_id].pause_bitmap = 0; + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_START_REQUEST_CMDID); + } + + if (ret < 0) { + WMA_LOGP("%s: Failed to send vdev start command", __func__); + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_peer_assoc_conf_handler() - peer assoc conf handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *param_buf; + wmi_peer_assoc_conf_event_fixed_param *event; + struct wma_target_req *req_msg; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + int status = 0; + + WMA_LOGD(FL("Enter")); + param_buf = (WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + WMA_LOGD(FL("peer assoc conf for vdev:%d mac=%pM"), + event->vdev_id, macaddr); + + req_msg = wma_find_req(wma, event->vdev_id, + WMA_PEER_ASSOC_CNF_START); + + if (!req_msg) { + WMA_LOGE(FL("Failed to lookup request message for vdev %d"), + event->vdev_id); + return -EINVAL; + } + + cdf_mc_timer_stop(&req_msg->event_timeout); + + if (req_msg->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams)req_msg->user_data; + if (!params) { + WMA_LOGE(FL("add STA params is NULL for vdev %d"), + event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + /* peer assoc conf event means the cmd succeeds */ + params->status = CDF_STATUS_SUCCESS; + WMA_LOGE(FL("Send ADD_STA_RSP: statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + params->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) req_msg->user_data; + if (!params) { + WMA_LOGE(FL("add BSS params is NULL for vdev %d"), + event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + /* peer assoc conf event means the cmd succeeds */ + params->status = CDF_STATUS_SUCCESS; + WMA_LOGE(FL("Send ADD BSS RSP: opermode %d update_bss %d nw_type %d bssid %pM" + " staIdx %d status %d"), params->operMode, + params->updateBss, params->nwType, params->bssId, + params->staContext.staIdx, params->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + } else { + WMA_LOGE(FL("Unhandled request message type: %d"), + req_msg->msg_type); + } + +free_req_msg: + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); + + return status; +} + +/** + * wma_hold_req_timer() - wma hold request timeout function + * @data: target request params + * + * Return: none + */ +void wma_hold_req_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + struct wma_target_req *msg; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE(FL("Failed to get wma")); + goto free_tgt_req; + } + + WMA_LOGA(FL("request %d is timed out for vdev_id - %d"), + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_req(wma, tgt_req->vdev_id, tgt_req->type); + + if (!msg) { + WMA_LOGE(FL("Failed to lookup request message - %d"), + tgt_req->msg_type); + goto free_tgt_req; + } + + if (tgt_req->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams) tgt_req->user_data; + params->status = CDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("WMA_ADD_STA_REQ timed out")); + WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"), + params->staMac, params->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); + } +free_tgt_req: + cdf_mc_timer_destroy(&tgt_req->event_timeout); + cdf_mem_free(tgt_req); +} + +/** + * wma_fill_hold_req() - fill wma request + * @wma: wma handle + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout) +{ + struct wma_target_req *req; + CDF_STATUS status; + + req = cdf_mem_malloc(sizeof(*req)); + if (!req) { + WMA_LOGP(FL("Failed to allocate memory for msg %d vdev %d"), + msg_type, vdev_id); + return NULL; + } + + WMA_LOGE(FL("vdev_id %d msg %d type %d"), vdev_id, msg_type, type); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + cdf_mc_timer_init(&req->event_timeout, CDF_TIMER_TYPE_SW, + wma_hold_req_timer, req); + cdf_mc_timer_start(&req->event_timeout, timeout); + cdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + status = cdf_list_insert_back(&wma->wma_hold_req_queue, &req->node); + if (CDF_STATUS_SUCCESS != status) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("Failed add request in queue")); + cdf_mem_free(req); + return NULL; + } + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + return req; +} + +/** + * wma_remove_req() - remove request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + WMA_LOGE(FL("Remove req for vdev: %d type: %d"), vdev_id, type); + req_msg = wma_find_req(wma, vdev_id, type); + if (!req_msg) { + WMA_LOGE(FL("target req not found for vdev: %d type: %d"), + vdev_id, type); + return; + } + + cdf_mc_timer_stop(&req_msg->event_timeout); + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); +} + +/** + * wma_vdev_resp_timer() - wma response timeout function + * @data: target request params + * + * Return: none + */ +void wma_vdev_resp_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + struct wma_target_req *msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + goto free_tgt_req; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + wma = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + goto free_tgt_req; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + cdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + + WMA_LOGA("%s: request %d is timed out for vdev_id - %d", __func__, + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_vdev_req(wma, tgt_req->vdev_id, tgt_req->type); + + if (!msg) { + WMA_LOGE("%s: Failed to lookup request message - %d", + __func__, tgt_req->msg_type); + goto free_tgt_req; + } + + if (tgt_req->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) tgt_req->user_data; + params->status = CDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_SWITCH_CHANNEL_REQ timedout", __func__); + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); + wma->roam_preauth_chan_context = NULL; + wma->roam_preauth_scan_id = -1; + } else if (tgt_req->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) tgt_req->user_data; + struct beacon_info *bcn; + struct wma_txrx_node *iface; + + if (tgt_req->vdev_id > wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d", __func__, + tgt_req->vdev_id); + cdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + + iface = &wma->interfaces[tgt_req->vdev_id]; + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, tgt_req->vdev_id); + cdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } +#ifdef QCA_IBSS_SUPPORT + if (wma_is_vdev_in_ibss_mode(wma, tgt_req->vdev_id)) + wma_delete_all_ibss_peers(wma, tgt_req->vdev_id); + else +#endif /* QCA_IBSS_SUPPORT */ + { + if (wma_is_vdev_in_ap_mode(wma, tgt_req->vdev_id)) { + wma_delete_all_ap_remote_peers(wma, + tgt_req-> + vdev_id); + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, + &peer_id); + wma_remove_peer(wma, params->bssid, tgt_req->vdev_id, + peer, false); + } + + if (wmi_unified_vdev_down_send(wma->wmi_handle, + tgt_req->vdev_id) < 0) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + tgt_req->vdev_id); + } else { + wma->interfaces[tgt_req->vdev_id].vdev_up = false; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, tgt_req->vdev_id, false); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + } + ol_txrx_vdev_flush(iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for WDA_DELETE_BSS_REQ timeout", + __func__, tgt_req->vdev_id); + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + cdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + + bcn = wma->interfaces[tgt_req->vdev_id].beacon; + + if (bcn) { + WMA_LOGD("%s: Freeing beacon struct %p, " + "template memory %p", __func__, bcn, bcn->buf); + if (bcn->dma_mapped) + cdf_nbuf_unmap_single(pdev->osdev, bcn->buf, + CDF_DMA_TO_DEVICE); + cdf_nbuf_free(bcn->buf); + cdf_mem_free(bcn); + wma->interfaces[tgt_req->vdev_id].beacon = NULL; + } +#ifdef QCA_IBSS_SUPPORT + /* recreate ibss vdev and bss peer for scan purpose */ + if (wma_is_vdev_in_ibss_mode(wma, tgt_req->vdev_id)) + wma_recreate_ibss_vdev_and_bss_peer(wma, + tgt_req->vdev_id); +#endif /* QCA_IBSS_SUPPORT */ + params->status = CDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_DELETE_BSS_REQ timedout", __func__); + wma_send_msg(wma, WMA_DELETE_BSS_RSP, (void *)params, 0); + if (iface->del_staself_req) { + WMA_LOGA("scheduling defered deletion(vdev id %x)", + tgt_req->vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } + } else if (tgt_req->msg_type == WMA_DEL_STA_SELF_REQ) { + struct wma_txrx_node *iface = + (struct wma_txrx_node *)tgt_req->user_data; + struct del_sta_self_params *params = + (struct del_sta_self_params *) iface->del_staself_req; + + params->status = CDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_DEL_STA_SELF_REQ timedout", __func__); + sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP; + sme_msg.bodyptr = iface->del_staself_req; + sme_msg.bodyval = 0; + + status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + cdf_mem_free(iface->del_staself_req); + } + if (iface->addBssStaContext) + cdf_mem_free(iface->addBssStaContext); +#if defined WLAN_FEATURE_VOWIFI_11R + if (iface->staKeyParams) + cdf_mem_free(iface->staKeyParams); +#endif /* WLAN_FEATURE_VOWIFI_11R */ + cdf_mem_zero(iface, sizeof(*iface)); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) tgt_req->user_data; + tDeleteBssParams *del_bss_params = + cdf_mem_malloc(sizeof(tDeleteBssParams)); + if (NULL == del_bss_params) { + WMA_LOGE("Failed to allocate memory for del_bss_params"); + peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, + &peer_id); + goto error0; + } + + del_bss_params->status = params->status = + CDF_STATUS_FW_MSG_TIMEDOUT; + del_bss_params->sessionId = params->sessionId; + del_bss_params->bssIdx = params->bssIdx; + cdf_mem_copy(del_bss_params->bssid, params->bssId, + sizeof(tSirMacAddr)); + + WMA_LOGA("%s: WMA_ADD_BSS_REQ timedout", __func__); + peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, &peer_id); + if (!peer) { + WMA_LOGP("%s: Failed to find peer %pM", __func__, + params->bssId); + } + msg = wma_fill_vdev_req(wma, tgt_req->vdev_id, WMA_DELETE_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_STOP, + del_bss_params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d", + __func__, tgt_req->vdev_id); + goto error0; + } + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (WDA_ADD_BSS_REQ timedout)", + __func__, tgt_req->vdev_id); + ol_txrx_vdev_pause(wma->interfaces[tgt_req->vdev_id].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma->interfaces[tgt_req->vdev_id].pause_bitmap |= + (1 << PAUSE_TYPE_HOST); + if (wmi_unified_vdev_stop_send + (wma->wmi_handle, tgt_req->vdev_id)) { + WMA_LOGP("%s: %d Failed to send vdev stop", __func__, + __LINE__); + wma_remove_vdev_req(wma, tgt_req->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + goto error0; + } + WMA_LOGI("%s: bssid %pM vdev_id %d", __func__, params->bssId, + tgt_req->vdev_id); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + goto free_tgt_req; +error0: + if (peer) + wma_remove_peer(wma, params->bssId, + tgt_req->vdev_id, peer, false); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + } else if (tgt_req->msg_type == WMA_OCB_SET_CONFIG_CMD) { + struct wma_txrx_node *iface; + + WMA_LOGE(FL("Failed to send OCB set config cmd")); + iface = &wma->interfaces[tgt_req->vdev_id]; + iface->vdev_up = false; + wma_ocb_set_config_resp(wma, CDF_STATUS_E_TIMEOUT); + } +free_tgt_req: + cdf_mc_timer_destroy(&tgt_req->event_timeout); + cdf_mem_free(tgt_req); +} + +/** + * wma_fill_vdev_req() - fill vdev request + * @wma: wma handle + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout) +{ + struct wma_target_req *req; + + req = cdf_mem_malloc(sizeof(*req)); + if (!req) { + WMA_LOGP("%s: Failed to allocate memory for msg %d vdev %d", + __func__, msg_type, vdev_id); + return NULL; + } + + WMA_LOGD("%s: vdev_id %d msg %d", __func__, vdev_id, msg_type); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + cdf_mc_timer_init(&req->event_timeout, CDF_TIMER_TYPE_SW, + wma_vdev_resp_timer, req); + cdf_mc_timer_start(&req->event_timeout, timeout); + cdf_spin_lock_bh(&wma->vdev_respq_lock); + list_add_tail(&req->node, &wma->vdev_resp_queue); + cdf_spin_unlock_bh(&wma->vdev_respq_lock); + return req; +} + +/** + * wma_remove_vdev_req() - remove vdev request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + req_msg = wma_find_vdev_req(wma, vdev_id, type); + if (!req_msg) + return; + + cdf_mc_timer_stop(&req_msg->event_timeout); + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); +} + +/** + * wma_vdev_set_bss_params() - BSS set params functions + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @shortSlotTimeSupported: short slot time + * @llbCoexist: llbCoexist + * @maxTxPower: max tx power + * + * Return: none + */ +static void +wma_vdev_set_bss_params(tp_wma_handle wma, int vdev_id, + tSirMacBeaconInterval beaconInterval, + uint8_t dtimPeriod, uint8_t shortSlotTimeSupported, + uint8_t llbCoexist, tPowerdBm maxTxPower) +{ + int ret; + uint32_t slot_time; + struct wma_txrx_node *intr = wma->interfaces; + + /* Beacon Interval setting */ + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_BEACON_INTERVAL, + beaconInterval); + + if (ret) + WMA_LOGE("failed to set WMI_VDEV_PARAM_BEACON_INTERVAL"); + + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, vdev_id, + &intr[vdev_id].config.gtx_info); + if (ret) + WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DTIM_PERIOD, + dtimPeriod); + if (ret) + WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + + if (!maxTxPower) { + WMA_LOGW("Setting Tx power limit to 0"); + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + maxTxPower); + if (ret) + WMA_LOGE("failed to set WMI_VDEV_PARAM_TX_PWRLIMIT"); + else + intr[vdev_id].max_tx_power = maxTxPower; + + /* Slot time */ + if (shortSlotTimeSupported) + slot_time = WMI_VDEV_SLOT_TIME_SHORT; + else + slot_time = WMI_VDEV_SLOT_TIME_LONG; + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SLOT_TIME, + slot_time); + if (ret) + WMA_LOGE("failed to set WMI_VDEV_PARAM_SLOT_TIME"); + + /* Initialize protection mode in case of coexistence */ + wma_update_protection_mode(wma, vdev_id, llbCoexist); +} + +/** + * wma_add_bss_ap_mode() - process add bss request in ap mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ap_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + struct wma_vdev_start_req req; + ol_txrx_peer_handle peer; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + CDF_STATUS status; + tPowerdBm maxTxPower; +#ifdef WLAN_FEATURE_11W + int ret = 0; +#endif /* WLAN_FEATURE_11W */ + struct sir_hw_mode_params hw_mode = {0}; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to get vdev handle", __func__); + goto send_fail_resp; + } + if (SAP_WPS_DISABLED == add_bss->wps_state) + wma_enable_disable_wakeup_event(wma, vdev_id, + (1 << WOW_PROBE_REQ_WPS_IE_EVENT), false); + wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss); + status = wma_create_peer(wma, pdev, vdev, add_bss->bssId, + WMI_PEER_TYPE_DEFAULT, vdev_id, false); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer); + + cdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; +#if defined WLAN_FEATURE_VOWIFI + req.max_txpow = add_bss->maxTxPower; + maxTxPower = add_bss->maxTxPower; +#else + req.max_txpow = 0; + maxTxPower = 0; +#endif /* WLAN_FEATURE_VOWIFI */ +#ifdef WLAN_FEATURE_11W + if (add_bss->rmfEnabled) { + /* + * when 802.11w PMF is enabled for hw encr/decr + * use hw MFP Qos bits 0x10 + */ + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_PMF_QOS, true); + if (ret) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_AP; + req.ssid.length = add_bss->ssId.length; + if (req.ssid.length > 0) + cdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!CDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if ((add_bss->nss == 2) && !hw_mode.dbs_cap) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != CDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + + wma_vdev_set_bss_params(wma, vdev_id, + add_bss->beaconInterval, add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, maxTxPower); + + return; + +peer_cleanup: + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); +send_fail_resp: + add_bss->status = CDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_add_bss_ibss_mode() - process add bss request in IBSS mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ibss_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + struct wma_vdev_start_req req; + ol_txrx_peer_handle peer = NULL; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + CDF_STATUS status; + struct add_sta_self_params add_sta_self_param; + struct del_sta_self_params del_sta_param; + tSetBssKeyParams key_info; + struct sir_hw_mode_params hw_mode = {0}; + + WMA_LOGD("%s: add_bss->sessionId = %d", __func__, add_bss->sessionId); + vdev_id = add_bss->sessionId; + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss); + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s: vdev not found for vdev id %d.", + __func__, vdev_id); + goto send_fail_resp; + } + + /* only change vdev type to ibss during 1st time join_ibss handling */ + + if (false == wma_is_vdev_in_ibss_mode(wma, vdev_id)) { + + WMA_LOGD("%s: vdev found for vdev id %d. deleting the vdev", + __func__, vdev_id); + + /* remove peers on the existing non-ibss vdev */ + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + WMA_LOGE("%s: peer found for vdev id %d. deleting the peer", + __func__, vdev_id); + wma_remove_peer(wma, (uint8_t *) &vdev->mac_addr, + vdev_id, peer, false); + } + + /* remove the non-ibss vdev */ + cdf_copy_macaddr( + (struct cdf_mac_addr *) &(del_sta_param.self_mac_addr), + (struct cdf_mac_addr *) &(vdev->mac_addr)); + del_sta_param.session_id = vdev_id; + del_sta_param.status = 0; + + wma_vdev_detach(wma, &del_sta_param, 0); + + /* create new vdev for ibss */ + cdf_copy_macaddr((struct cdf_mac_addr *) & + (add_sta_self_param.self_mac_addr), + (struct cdf_mac_addr *) &(add_bss->selfMacAddr)); + add_sta_self_param.session_id = vdev_id; + add_sta_self_param.type = WMI_VDEV_TYPE_IBSS; + add_sta_self_param.sub_type = 0; + add_sta_self_param.status = 0; + + vdev = wma_vdev_attach(wma, &add_sta_self_param, 0); + if (!vdev) { + WMA_LOGE("%s: Failed to create vdev", __func__); + goto send_fail_resp; + } + + /* Register with TxRx Module for Data Ack Complete Cb */ + ol_txrx_data_tx_cb_set(vdev, wma_data_tx_ack_comp_hdlr, wma); + WMA_LOGA("new IBSS vdev created with mac %pM", + add_bss->selfMacAddr); + + /* create ibss bss peer */ + status = wma_create_peer(wma, pdev, vdev, add_bss->selfMacAddr, + WMI_PEER_TYPE_DEFAULT, vdev_id, + false); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + WMA_LOGA("IBSS BSS peer created with mac %pM", + add_bss->selfMacAddr); + } + + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->selfMacAddr, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->selfMacAddr); + goto send_fail_resp; + } + + /* clear leftover ibss keys on bss peer */ + + WMA_LOGD("%s: ibss bss key clearing", __func__); + cdf_mem_set(&key_info, sizeof(key_info), 0); + key_info.smesessionId = vdev_id; + key_info.numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + cdf_mem_copy(&wma->ibsskey_info, &key_info, sizeof(tSetBssKeyParams)); + + /* start ibss vdev */ + + add_bss->operMode = BSS_OPERATIONAL_MODE_IBSS; + + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS enqueued", __func__); + + add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer); + + /* + * If IBSS Power Save is supported by firmware + * set the IBSS power save params to firmware. + */ + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_IBSS_PWRSAVE)) { + status = wma_set_ibss_pwrsave_params(wma, vdev_id); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to Set IBSS Power Save Params to firmware", + __func__); + goto peer_cleanup; + } + } + + cdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; +#if defined WLAN_FEATURE_VOWIF + req.max_txpow = add_bss->maxTxPower; +#else + req.max_txpow = 0; +#endif /* WLAN_FEATURE_VOWIF */ + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_IBSS; + req.ssid.length = add_bss->ssId.length; + if (req.ssid.length > 0) + cdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!CDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if ((add_bss->nss == 2) && !hw_mode.dbs_cap) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + WMA_LOGD("%s: chan %d chan_width %d", __func__, req.chan, + req.chan_width); + WMA_LOGD("%s: ssid = %s", __func__, req.ssid.ssId); + + status = wma_vdev_start(wma, &req, false); + if (status != CDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS sent to target", __func__); + + /* Initialize protection mode to no protection */ + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, + IEEE80211_PROT_NONE)) { + WMA_LOGE("Failed to initialize protection mode"); + } + + return; + +peer_cleanup: + if (peer) { + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); + } +send_fail_resp: + add_bss->status = CDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_add_bss_sta_mode() - process add bss request in sta mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + struct wma_vdev_start_req req; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + ol_txrx_peer_handle peer; + CDF_STATUS status; + struct wma_txrx_node *iface; + int ret = 0; + int pps_val = 0; + bool roam_synch_in_progress = false; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + struct sir_hw_mode_params hw_mode = {0}; + bool peer_assoc_sent = false; + + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + goto send_fail_resp; + } + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s Failed to get pdev", __func__); + goto send_fail_resp; + } + + vdev_id = add_bss->staContext.smesessionId; + iface = &wma->interfaces[vdev_id]; + + wma_set_bss_rate_flags(iface, add_bss); + if (add_bss->operMode) { + /* Save parameters later needed by WMA_ADD_STA_REQ */ + if (iface->addBssStaContext) { + cdf_mem_free(iface->addBssStaContext); + } + iface->addBssStaContext = cdf_mem_malloc(sizeof(tAddStaParams)); + if (!iface->addBssStaContext) { + WMA_LOGE("%s Failed to allocat memory", __func__); + goto send_fail_resp; + } + cdf_mem_copy(iface->addBssStaContext, &add_bss->staContext, + sizeof(tAddStaParams)); + +#if defined WLAN_FEATURE_VOWIFI_11R + if (iface->staKeyParams) { + cdf_mem_free(iface->staKeyParams); + iface->staKeyParams = NULL; + } + if (add_bss->extSetStaKeyParamValid) { + iface->staKeyParams = + cdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (!iface->staKeyParams) { + WMA_LOGE("%s Failed to allocat memory", + __func__); + goto send_fail_resp; + } + cdf_mem_copy(iface->staKeyParams, + &add_bss->extSetStaKeyParam, + sizeof(tSetStaKeyParams)); + } +#endif /* WLAN_FEATURE_VOWIFI_11R */ + /* Save parameters later needed by WMA_ADD_STA_REQ */ + iface->rmfEnabled = add_bss->rmfEnabled; + iface->beaconInterval = add_bss->beaconInterval; + iface->dtimPeriod = add_bss->dtimPeriod; + iface->llbCoexist = add_bss->llbCoexist; + iface->shortSlotTimeSupported = add_bss->shortSlotTimeSupported; + iface->nwType = add_bss->nwType; + if (add_bss->nonRoamReassoc) { + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (peer) { + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + goto send_bss_resp; + } + } + if (add_bss->reassocReq) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + ol_txrx_vdev_handle vdev; +#endif + /* Called in preassoc state. BSSID peer is already added by set_linkstate */ + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (iface->roam_synch_in_progress) { + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + goto send_bss_resp; + } +#endif + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, + add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + + cdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; +#if defined WLAN_FEATURE_VOWIFI + req.max_txpow = add_bss->maxTxPower; +#else + req.max_txpow = 0; +#endif + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.ssid.length = add_bss->ssId.length; + req.oper_mode = BSS_OPERATIONAL_MODE_STA; + if (req.ssid.length > 0) + cdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!CDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if ((add_bss->nss == 2) && !hw_mode.dbs_cap) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != CDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + ol_txrx_vdev_pause(vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + /* ADD_BSS_RESP will be deferred to completion of VDEV_START */ + + return; + } + if (!add_bss->updateBss) { + goto send_bss_resp; + + } + /* Update peer state */ + if (add_bss->staContext.encryptType == eSIR_ED_NONE) { + WMA_LOGD("%s: Update peer(%pM) state into auth", + __func__, add_bss->bssId); + ol_txrx_peer_state_update(pdev, add_bss->bssId, + ol_txrx_peer_state_auth); + } else { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + ol_txrx_vdev_handle vdev; +#endif + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, add_bss->bssId); + ol_txrx_peer_state_update(pdev, add_bss->bssId, + ol_txrx_peer_state_conn); +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s:%d Failed to find peer %pM", + __func__, __LINE__, add_bss->bssId); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + ol_txrx_vdev_pause(vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + + wmi_unified_send_txbf(wma, &add_bss->staContext); + + pps_val = + ((pMac-> + enable5gEBT << 31) & 0xffff0000) | (PKT_PWR_SAVE_5G_EBT & + 0xffff); + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + if (ret) + WMA_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("Sent PKT_PWR_SAVE_5G_EBT cmd to target, val = %x, ret = %d", + pps_val, ret); + + wmi_unified_send_peer_assoc(wma, add_bss->nwType, + &add_bss->staContext); + peer_assoc_sent = true; +#ifdef WLAN_FEATURE_11W + if (add_bss->rmfEnabled) { + /* when 802.11w PMF is enabled for hw encr/decr + use hw MFP Qos bits 0x10 */ + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_PMF_QOS, + true); + if (ret) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", + __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + wma_vdev_set_bss_params(wma, add_bss->staContext.smesessionId, + add_bss->beaconInterval, + add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, + add_bss->maxTxPower); + + /* + * Store the bssid in interface table, bssid will + * be used during group key setting sta mode. + */ + cdf_mem_copy(iface->bssid, add_bss->bssId, IEEE80211_ADDR_LEN); + + } +send_bss_resp: + ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &add_bss->staContext.staIdx); + add_bss->status = (add_bss->staContext.staIdx < 0) ? + CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS; + add_bss->bssIdx = add_bss->staContext.smesessionId; + cdf_mem_copy(add_bss->staContext.staMac, add_bss->bssId, + sizeof(add_bss->staContext.staMac)); + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + goto send_final_rsp; + } + + /* In case of reassoc, peer assoc cmd will not be sent */ + if (!peer_assoc_sent) + goto send_final_rsp; + + msg = wma_fill_hold_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_PEER_ASSOC_CNF_START, add_bss, + WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to allocate request for vdev_id %d"), + vdev_id); + wma_remove_req(wma, vdev_id, WMA_PEER_ASSOC_CNF_START); + goto peer_cleanup; + } + return; + +send_final_rsp: + WMA_LOGD("%s: opermode %d update_bss %d nw_type %d bssid %pM" + " staIdx %d status %d", __func__, add_bss->operMode, + add_bss->updateBss, add_bss->nwType, add_bss->bssId, + add_bss->staContext.staIdx, add_bss->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); + return; + +peer_cleanup: + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, + roam_synch_in_progress); +send_fail_resp: + add_bss->status = CDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +/** + * wma_add_bss() - Add BSS request to fw as per opmode + * @wma: wma handle + * @params: add bss params + * + * Return: none + */ +void wma_add_bss(tp_wma_handle wma, tpAddBssParams params) +{ + WMA_LOGD("%s: add_bss_param.halPersona = %d", + __func__, params->halPersona); + + switch (params->halPersona) { + + case CDF_SAP_MODE: + case CDF_P2P_GO_MODE: + /*If current bring up SAP/P2P channel matches the previous + *radar found channel then reset the last_radar_found_chan + *variable to avoid race conditions. + */ + if (params->currentOperChannel == + wma->dfs_ic->last_radar_found_chan) + wma->dfs_ic->last_radar_found_chan = 0; + + wma_add_bss_ap_mode(wma, params); + break; + +#ifdef QCA_IBSS_SUPPORT + case CDF_IBSS_MODE: + wma_add_bss_ibss_mode(wma, params); + break; +#endif + + default: + wma_add_bss_sta_mode(wma, params); + break; + } +} + +/** + * wmi_unified_vdev_up_send() - send vdev up command in fw + * @wmi: wmi handle + * @vdev_id: vdev id + * @aid: association ID + * @bssid: bssid + * + * Return: 0 for success or error code + */ +int wmi_unified_vdev_up_send(wmi_unified_t wmi, + uint8_t vdev_id, uint16_t aid, + uint8_t bssid[IEEE80211_ADDR_LEN]) +{ + wmi_vdev_up_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMA_LOGD("%s: VDEV_UP", __func__); + WMA_LOGD("%s: vdev_id %d aid %d bssid %pM", __func__, + vdev_id, aid, bssid); + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_vdev_up_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_up_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->vdev_assoc_id = aid; + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid, &cmd->vdev_bssid); + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_UP_CMDID)) { + WMA_LOGP("%s: Failed to send vdev up command", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_add_sta_req_ap_mode() - process add sta request in ap mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_sta_req_ap_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = ol_txrx_peer_state_conn; + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + CDF_STATUS status; + int32_t ret; +#ifdef WLAN_FEATURE_11W + struct wma_txrx_node *iface = NULL; +#endif /* WLAN_FEATURE_11W */ + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = CDF_STATUS_E_FAILURE; + goto send_rsp; + } + /* UMAC sends WMA_ADD_STA_REQ msg twice to WMA when the station + * associates. First WMA_ADD_STA_REQ will have staType as + * STA_ENTRY_PEER and second posting will have STA_ENTRY_SELF. + * Peer creation is done in first WMA_ADD_STA_REQ and second + * WMA_ADD_STA_REQ which has STA_ENTRY_SELF is ignored and + * send fake response with success to UMAC. Otherwise UMAC + * will get blocked. + */ + if (add_sta->staType != STA_ENTRY_PEER) { + add_sta->status = CDF_STATUS_SUCCESS; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = CDF_STATUS_E_FAILURE; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, + vdev, + add_sta->staMac, &peer_id); + if (peer) { + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + WMA_LOGE("%s: Peer already exists, Deleted peer with peer_addr %pM", + __func__, add_sta->staMac); + } + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_DEFAULT, add_sta->smesessionId, + false); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, + vdev, + add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to find peer handle using peer mac %pM", + __func__, add_sta->staMac); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } + + wmi_unified_send_txbf(wma, add_sta); + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + add_sta->smesessionId); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + ret = wmi_unified_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } +#ifdef QCA_IBSS_SUPPORT + /* + * In IBSS mode send the peer + * Atim Window length if IBSS + * power save is enabled by the + * firmware. + */ + if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId) && + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_IBSS_PWRSAVE)) { + /* + * If ATIM Window is present in the peer + * beacon then send it to firmware else + * configure Zero ATIM Window length to + * firmware. + */ + if (add_sta->atimIePresent) { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + add_sta->peerAtimWindowLength, + add_sta->smesessionId); + } else { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + 0, add_sta->smesessionId); + } + } +#endif + +#ifdef WLAN_FEATURE_11W + if (add_sta->rmfEnabled) { + /* + * We have to store the state of PMF connection + * per STA for SAP case + * We will isolate the ifaces based on vdevid + */ + iface = &wma->interfaces[vdev->vdev_id]; + iface->rmfEnabled = add_sta->rmfEnabled; + /* + * when 802.11w PMF is enabled for hw encr/decr + * use hw MFP Qos bits 0x10 + */ + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_PMF_QOS, true); + if (ret) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + if (add_sta->uAPSD) { + ret = wma_set_ap_peer_uapsd(wma, add_sta->smesessionId, + add_sta->staMac, + add_sta->uAPSD, add_sta->maxSPLen); + if (ret) { + WMA_LOGE("Failed to set peer uapsd param for %pM", + add_sta->staMac); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + } + + WMA_LOGD("%s: Moving peer %pM to state %d", + __func__, add_sta->staMac, state); + ol_txrx_peer_state_update(pdev, add_sta->staMac, state); + + add_sta->staIdx = ol_txrx_local_peer_id(peer); + add_sta->status = CDF_STATUS_SUCCESS; +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) { + WMA_LOGI(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + return; + } + + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + add_sta->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_add_tdls_sta() - process add sta request in TDLS mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + CDF_STATUS status; + int32_t ret; + tTdlsPeerStateParams *peerStateParams; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + + WMA_LOGD("%s: staType: %d, staIdx: %d, updateSta: %d, " + "bssId: %pM, staMac: %pM", + __func__, add_sta->staType, add_sta->staIdx, + add_sta->updateSta, add_sta->bssId, add_sta->staMac); + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = CDF_STATUS_E_FAILURE; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = CDF_STATUS_E_FAILURE; + goto send_rsp; + } + + if (0 == add_sta->updateSta) { + /* its a add sta request * */ + WMA_LOGD("%s: addSta, calling wma_create_peer for %pM, vdev_id %hu", + __func__, add_sta->staMac, add_sta->smesessionId); + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_TDLS, + add_sta->smesessionId, false); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: addSta, failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + + add_sta->staIdx = ol_txrx_local_peer_id(peer); + WMA_LOGD("%s: addSta, after calling ol_txrx_local_peer_id, " + "staIdx: %d, staMac: %pM", + __func__, add_sta->staIdx, add_sta->staMac); + + peerStateParams = cdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE + ("%s: Failed to allocate memory for peerStateParams for %pM", + __func__, add_sta->staMac); + add_sta->status = CDF_STATUS_E_NOMEM; + goto send_rsp; + } + + cdf_mem_zero(peerStateParams, sizeof(*peerStateParams)); + peerStateParams->peerState = WMI_TDLS_PEER_STATE_PEERING; + peerStateParams->vdevId = vdev->vdev_id; + cdf_mem_copy(&peerStateParams->peerMacAddr, + &add_sta->staMac, sizeof(tSirMacAddr)); + wma_update_tdls_peer_state(wma, peerStateParams); + } else { + /* its a change sta request * */ + peer = + ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: changeSta,failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + add_sta->smesessionId); + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + WMA_LOGD("%s: changeSta, calling wmi_unified_send_peer_assoc", + __func__); + + ret = + wmi_unified_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + } + +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + add_sta->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} +#endif + +/** + * wma_add_sta_req_sta_mode() - process add sta request in sta mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_sta_req_sta_mode(tp_wma_handle wma, tpAddStaParams params) +{ + ol_txrx_pdev_handle pdev; + CDF_STATUS status = CDF_STATUS_SUCCESS; + ol_txrx_peer_handle peer; + struct wma_txrx_node *iface; + tPowerdBm maxTxPower; + int ret = 0; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_add_tdls_sta(wma, params); + return; + } +#endif + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get pdev", __func__); + goto out; + } + + iface = &wma->interfaces[params->smesessionId]; + if (params->staType != STA_ENTRY_SELF) { + WMA_LOGP("%s: unsupported station type %d", + __func__, params->staType); + goto out; + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, ¶ms->staIdx); + if (params->nonRoamReassoc) { + ol_txrx_peer_state_update(pdev, params->bssId, + ol_txrx_peer_state_auth); + cdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + goto out; + } + + if (wma->interfaces[params->smesessionId].vdev_up == true) { + WMA_LOGE("%s: vdev id %d is already UP for %pM", __func__, + params->smesessionId, params->bssId); + status = CDF_STATUS_E_FAILURE; + goto out; + } + + if (peer != NULL && peer->state == ol_txrx_peer_state_disc) { + /* + * This is the case for reassociation. + * peer state update and peer_assoc is required since it + * was not done by WMA_ADD_BSS_REQ. + */ + + /* Update peer state */ + if (params->encryptType == eSIR_ED_NONE) { + WMA_LOGD("%s: Update peer(%pM) state into auth", + __func__, params->bssId); + ol_txrx_peer_state_update(pdev, params->bssId, + ol_txrx_peer_state_auth); + } else { + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, params->bssId); + ol_txrx_peer_state_update(pdev, params->bssId, + ol_txrx_peer_state_conn); + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (iface->roam_synch_in_progress) { + /* iface->nss = params->nss; */ + /*In LFR2.0, the following operations are performed as + * part of wmi_unified_send_peer_assoc. As we are + * skipping this operation, we are just executing the + * following which are useful for LFR3.0.*/ + ol_txrx_peer_state_update(pdev, params->bssId, + ol_txrx_peer_state_auth); + cdf_atomic_set(&iface->bss_status, + WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + goto out; + } +#endif + wmi_unified_send_txbf(wma, params); + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, params->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + params, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + params->smesessionId); + params->status = CDF_STATUS_E_FAILURE; + wma_remove_req(wma, params->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, params->staMac, + params->smesessionId, peer, false); + peer_assoc_cnf = false; + goto out; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + ret = wmi_unified_send_peer_assoc(wma, + iface->nwType, + (tAddStaParams *) iface->addBssStaContext); + if (ret) { + status = CDF_STATUS_E_FAILURE; + wma_remove_peer(wma, params->bssId, + params->smesessionId, peer, false); + goto out; + } +#ifdef WLAN_FEATURE_11W + if (params->rmfEnabled) { + /* when 802.11w PMF is enabled for hw encr/decr + use hw MFP Qos bits 0x10 */ + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_PMF_QOS, + true); + if (ret) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", + __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ +#if defined WLAN_FEATURE_VOWIFI_11R + /* + * Set the PTK in 11r mode because we already have it. + */ + if (iface->staKeyParams) { + wma_set_stakey(wma, + (tpSetStaKeyParams) iface->staKeyParams); + } +#endif + } +#if defined WLAN_FEATURE_VOWIFI + maxTxPower = params->maxTxPower; +#else + maxTxPower = 0; +#endif + wma_vdev_set_bss_params(wma, params->smesessionId, + iface->beaconInterval, iface->dtimPeriod, + iface->shortSlotTimeSupported, + iface->llbCoexist, maxTxPower); + + params->csaOffloadEnable = 0; + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_CSA_OFFLOAD)) { + params->csaOffloadEnable = 1; + if (wmi_unified_csa_offload_enable(wma, params->smesessionId) < + 0) { + WMA_LOGE("Unable to enable CSA offload for vdev_id:%d", + params->smesessionId); + } + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE)) { + if (wmi_unified_nat_keepalive_enable(wma, params->smesessionId) + < 0) { + WMA_LOGE("Unable to enable NAT keepalive for vdev_id:%d", + params->smesessionId); + } + } + + if (wmi_unified_vdev_up_send(wma->wmi_handle, params->smesessionId, + params->assocId, params->bssId) < 0) { + WMA_LOGP("%s: Failed to send vdev up cmd: vdev %d bssid %pM", + __func__, params->smesessionId, params->bssId); + status = CDF_STATUS_E_FAILURE; + } else { + wma->interfaces[params->smesessionId].vdev_up = true; + } + + cdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: STA mode (type %d subtype %d) BSS is started", + __func__, iface->type, iface->sub_type); + /* Sta is now associated, configure various params */ + + /* SM power save, configure the h/w as configured + * in the ini file. SMPS is not published in assoc + * request. Once configured, fw sends the required + * action frame to AP. + */ + if (params->enableHtSmps) + wma_set_mimops(wma, params->smesessionId, params->htSmpsconfig); + +#ifdef WLAN_FEATURE_11AC + /* Partial AID match power save, enable when SU bformee */ + if (params->enableVhtpAid && params->vhtTxBFCapable) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_PAID_MATCH, 1); +#endif + + /* Enable AMPDU power save, if htCapable/vhtCapable */ + if (params->enableAmpduPs && (params->htCapable || params->vhtCapable)) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_DELIM_CRC_FAIL, 1); + iface->aid = params->assocId; +out: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + params->status = status; + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + params->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); +} + +/** + * wma_delete_sta_req_ap_mode() - proces delete sta request from UMAC in AP mode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_ap_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + del_sta->status = CDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, del_sta->staIdx); + del_sta->status = CDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + wma_remove_peer(wma, peer->mac_addr.raw, del_sta->smesessionId, peer, + false); + del_sta->status = CDF_STATUS_SUCCESS; + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, del_sta->status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)del_sta, 0); + } +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_del_tdls_sta() - proces delete sta request from UMAC in TDLS + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_del_tdls_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + struct ol_txrx_peer_t *peer; + tTdlsPeerStateParams *peerStateParams; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + del_sta->status = CDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + vdev = wma_find_vdev_by_id(wma, del_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + del_sta->status = CDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, del_sta->staIdx); + del_sta->status = CDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peerStateParams = cdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE("%s: Failed to allocate memory for peerStateParams for: %pM", + __func__, del_sta->staMac); + del_sta->status = CDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + cdf_mem_zero(peerStateParams, sizeof(*peerStateParams)); + peerStateParams->peerState = WMA_TDLS_PEER_STATE_TEARDOWN; + peerStateParams->vdevId = vdev->vdev_id; + cdf_mem_copy(&peerStateParams->peerMacAddr, + &del_sta->staMac, sizeof(tSirMacAddr)); + + WMA_LOGD("%s: sending tdls_peer_state for peer mac: %pM, " + " peerState: %d", + __func__, peerStateParams->peerMacAddr, + peerStateParams->peerState); + + wma_update_tdls_peer_state(wma, peerStateParams); + + del_sta->status = CDF_STATUS_SUCCESS; + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, del_sta->status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)del_sta, 0); + } +} +#endif + +/** + * wma_delete_sta_req_sta_mode() - proces delete sta request from UMAC + * @wma: wma handle + * @params: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_sta_mode(tp_wma_handle wma, + tpDeleteStaParams params) +{ + CDF_STATUS status = CDF_STATUS_SUCCESS; + struct wma_txrx_node *iface; + iface = &wma->interfaces[params->smesessionId]; + iface->uapsd_cached_val = 0; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + /* In case of LFR3.0 we need not send any + * WMI commands to FW before SYNCH_CONFIRM */ + if (iface->roam_synch_in_progress) + goto send_del_sta_rsp; +#endif +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_del_tdls_sta(wma, params); + return; + } +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +send_del_sta_rsp: +#endif + params->status = status; + if (params->respReqd) { + WMA_LOGD("%s: vdev_id %d status %d", __func__, + params->smesessionId, status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)params, 0); + } +} + +/** + * wma_add_sta() - process add sta request as per opmode + * @wma: wma handle + * @add_Sta: add sta params + * + * Return: none + */ +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + + WMA_LOGD("%s: add_sta->sessionId = %d.", __func__, + add_sta->smesessionId); + WMA_LOGD("%s: add_sta->bssId = %x:%x:%x:%x:%x:%x", __func__, + add_sta->bssId[0], add_sta->bssId[1], add_sta->bssId[2], + add_sta->bssId[3], add_sta->bssId[4], add_sta->bssId[5]); + + if (wma_is_vdev_in_ap_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_AP; +#ifdef QCA_IBSS_SUPPORT + else if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_IBSS; +#endif + + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_add_sta_req_sta_mode(wma, add_sta); + break; + +#ifdef QCA_IBSS_SUPPORT + case BSS_OPERATIONAL_MODE_IBSS: /* IBSS should share the same code as AP mode */ +#endif + case BSS_OPERATIONAL_MODE_AP: + hif_vote_link_up(); + wma_add_sta_req_ap_mode(wma, add_sta); + break; + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for detecting ibss peer departure */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, add_sta->smesessionId, 1); +#endif + +} + +/** + * wma_delete_sta() - process del sta request as per opmode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + uint8_t smesession_id = del_sta->smesessionId; + bool rsp_requested = del_sta->respReqd; + + if (wma_is_vdev_in_ap_mode(wma, smesession_id)) + oper_mode = BSS_OPERATIONAL_MODE_AP; +#ifdef QCA_IBSS_SUPPORT + if (wma_is_vdev_in_ibss_mode(wma, smesession_id)) { + oper_mode = BSS_OPERATIONAL_MODE_IBSS; + WMA_LOGD("%s: to delete sta for IBSS mode", __func__); + } +#endif + + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_delete_sta_req_sta_mode(wma, del_sta); + break; + +#ifdef QCA_IBSS_SUPPORT + case BSS_OPERATIONAL_MODE_IBSS: /* IBSS shares AP code */ +#endif + case BSS_OPERATIONAL_MODE_AP: + hif_vote_link_down(); + wma_delete_sta_req_ap_mode(wma, del_sta); + break; + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for + * detecting ibss peer departure + */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, smesession_id, -1); +#endif + if (!rsp_requested) { + WMA_LOGD("%s: vdev_id %d status %d", __func__, + del_sta->smesessionId, del_sta->status); + cdf_mem_free(del_sta); + } +} + +/** + * wmi_unified_vdev_stop_send() - send vdev stop command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: 0 for success or erro code + */ +int32_t wmi_unified_vdev_stop_send(wmi_unified_t wmi, uint8_t vdev_id) +{ + wmi_vdev_stop_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMA_LOGP("%s : wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_vdev_stop_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_stop_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_STOP_CMDID)) { + WMA_LOGP("%s: Failed to send vdev stop command", __func__); + cdf_nbuf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_delete_bss() - process delete bss request from upper layer + * @wma: wma handle + * @params: del bss parameters + * + * Return: none + */ +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer = NULL; + struct wma_target_req *msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t peer_id; + uint8_t max_wait_iterations = 0; + ol_txrx_vdev_handle txrx_vdev = NULL; + bool roam_synch_in_progress = false; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s:Unable to get TXRX context", __func__); + goto out; + } +#ifdef QCA_IBSS_SUPPORT + if (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) + /* in rome ibss case, self mac is used to create the bss peer */ + peer = ol_txrx_find_peer_by_addr(pdev, + wma->interfaces[params->smesessionId].addr, + &peer_id); + else +#endif + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + + if (!peer) { + WMA_LOGP("%s: Failed to find peer %pM", __func__, + params->bssid); + status = CDF_STATUS_E_FAILURE; + goto out; + } + + cdf_mem_zero(wma->interfaces[params->smesessionId].bssid, + IEEE80211_ADDR_LEN); + + txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + status = CDF_STATUS_E_FAILURE; + goto out; + } + + /*Free the allocated stats response buffer for the the session */ + if (wma->interfaces[params->smesessionId].stats_rsp) { + cdf_mem_free(wma->interfaces[params->smesessionId].stats_rsp); + wma->interfaces[params->smesessionId].stats_rsp = NULL; + } + + if (wma->interfaces[params->smesessionId].psnr_req) { + cdf_mem_free(wma->interfaces[params->smesessionId].psnr_req); + wma->interfaces[params->smesessionId].psnr_req = NULL; + } + + if (wlan_op_mode_ibss == txrx_vdev->opmode) { + wma->ibss_started = 0; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (wma->interfaces[params->smesessionId].roam_synch_in_progress) { + roam_synch_in_progress = true; + WMA_LOGD("LFR3:%s: Setting vdev_up to FALSE for session %d", + __func__, params->smesessionId); + wma->interfaces[params->smesessionId].vdev_up = false; + goto detach_peer; + } +#endif + msg = wma_fill_vdev_req(wma, params->smesessionId, WMA_DELETE_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_STOP, params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d", + __func__, params->smesessionId); + status = CDF_STATUS_E_NOMEM; + goto detach_peer; + } + + WMA_LOGW(FL("Outstanding msdu packets: %d"), + ol_txrx_get_tx_pending(pdev)); + + max_wait_iterations = + wma->interfaces[params->smesessionId].delay_before_vdev_stop / + WMA_TX_Q_RECHECK_TIMER_WAIT; + + while (ol_txrx_get_tx_pending(pdev) && max_wait_iterations) { + WMA_LOGW(FL("Waiting for outstanding packet to drain.")); + cdf_wait_single_event(&wma->tx_queue_empty_event, + WMA_TX_Q_RECHECK_TIMER_MAX_WAIT); + max_wait_iterations--; + } + + if (ol_txrx_get_tx_pending(pdev)) { + WMA_LOGW(FL("Outstanding msdu packets before VDEV_STOP : %d"), + ol_txrx_get_tx_pending(pdev)); + } + + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + __func__, params->smesessionId); + ol_txrx_vdev_pause(wma->interfaces[params->smesessionId].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma->interfaces[params->smesessionId].pause_bitmap |= + (1 << PAUSE_TYPE_HOST); + + if (wmi_unified_vdev_stop_send(wma->wmi_handle, params->smesessionId)) { + WMA_LOGP("%s: %d Failed to send vdev stop", __func__, __LINE__); + wma_remove_vdev_req(wma, params->smesessionId, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + status = CDF_STATUS_E_FAILURE; + goto detach_peer; + } + WMA_LOGD("%s: bssid %pM vdev_id %d", + __func__, params->bssid, params->smesessionId); + return; +detach_peer: + wma_remove_peer(wma, params->bssid, params->smesessionId, peer, + roam_synch_in_progress); +out: + params->status = status; + wma_send_msg(wma, WMA_DELETE_BSS_RSP, (void *)params, 0); +} + +/** + * wma_find_ibss_vdev() - This function finds vdev_id based on input type + * @wma: wma handle + * @type: vdev type + * + * Return: vdev id + */ +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type) +{ + int32_t vdev_id = 0; + struct wma_txrx_node *intf = wma->interfaces; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (NULL != intf) { + if (intf[vdev_id].type == type) + return vdev_id; + } + } + + return -EFAULT; +} + +/** + * wma_set_vdev_intrabss_fwd() - set intra_fwd value to wni_in. + * @wma_handle: wma handle + * @pdis_intra_fwd: Pointer to DisableIntraBssFwd struct + * + * Return: none + */ +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd) +{ + ol_txrx_vdev_handle txrx_vdev; + WMA_LOGD("%s:intra_fwd:vdev(%d) intrabss_dis=%s", + __func__, pdis_intra_fwd->sessionId, + (pdis_intra_fwd->disableintrabssfwd ? "true" : "false")); + + txrx_vdev = wma_handle->interfaces[pdis_intra_fwd->sessionId].handle; + ol_vdev_rx_set_intrabss_fwd(txrx_vdev, + pdis_intra_fwd->disableintrabssfwd); +} diff --git a/core/wma/src/wma_dfs_interface.c b/core/wma/src/wma_dfs_interface.c new file mode 100644 index 0000000000..8c0fcd4ccb --- /dev/null +++ b/core/wma/src/wma_dfs_interface.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_dfs_interface.c + * + * Source code borrowed from QCA_MAIN DFS module + */ + +#include "wma.h" +#include "ath_dfs_structs.h" +#include "wma_dfs_interface.h" + +#ifndef ATH_SUPPORT_DFS +#define ATH_SUPPORT_DFS 1 +#endif + +/** + * ol_if_dfs_attach() - dfs attach + * @ic: ieee80211com ptr + * @ptr: ath_dfs_caps ptr + * @radar_info: radar info + * + * Return: 0 for success or error code + */ +int ol_if_dfs_attach(struct ieee80211com *ic, void *ptr, void *radar_info) +{ + struct ath_dfs_caps *pCap = (struct ath_dfs_caps *)ptr; + + cdf_print("%s: called; ptr=%p, radar_info=%p\n", + __func__, ptr, radar_info); + + pCap->ath_chip_is_bb_tlv = 1; + pCap->ath_dfs_combined_rssi_ok = 0; + pCap->ath_dfs_ext_chan_ok = 0; + pCap->ath_dfs_use_enhancement = 0; + pCap->ath_strong_signal_diversiry = 0; + pCap->ath_fastdiv_val = 0; + + return 0; +} + +/** + * ol_if_get_tsf64() - Place Holder API + * @ic: ieee80211com ptr + * + * We get the tsf from Firmware. + * + * Return: always return success(0) + */ +uint64_t ol_if_get_tsf64(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ol_if_dfs_disable() - Place Holder API + * @ic: ieee80211com ptr + * + * ic_dfs_disable is just a place holder + * function since firmware takes care of + * disabling the dfs phyerrors disabling. + * + * Return: always return success(0) + */ +int ol_if_dfs_disable(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ieee80211_find_channel() - find ieee80211 channel + * @ic: ieee80211com ptr + * @freq: frequency + * @flags: flags + * + * Locate a channel given a frequency+flags. We cache + * the previous lookup to optimize swithing between + * two channels--as happens with dynamic turbo. + * This verifies that found channels have not been + * excluded because of 11d. + * + * Return: returns ieee80211_channel or NULL for error + */ +struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *ic, + int freq, uint32_t flags) +{ + struct ieee80211_channel *c; + int i; + + flags &= IEEE80211_CHAN_ALLTURBO; + /* brute force search */ + for (i = 0; i < ic->ic_nchans; i++) { + c = &ic->ic_channels[i]; + + if ((!IEEE80211_IS_CHAN_11D_EXCLUDED(c)) && + (c->ic_freq == freq) && + ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)) { + return c; + } + } + + return NULL; +} + +/** + * ic_dfs_enable() - enable DFS + * @ic: ieee80211com ptr + * @is_fastclk: is fastclock + * + * For offload solutions, radar PHY errors will be enabled + * by the target firmware when DFS is requested for the + * current channel. + * + * Return: Always returns success + */ +int ol_if_dfs_enable(struct ieee80211com *ic, int *is_fastclk, void *pe) +{ + /* + * For peregrine, treat fastclk as the "oversampling" mode. + * It's on by default. This may change at some point, so + * we should really query the firmware to find out what + * the current configuration is. + */ + (*is_fastclk) = 1; + + return 0; +} + +/** + * ieee80211_ieee2mhz() - Convert IEEE channel number to MHz frequency. + * @chan: channel number + * @flags: flags + * + * Return: frequency in MHz + */ +uint32_t ieee80211_ieee2mhz(uint32_t chan, uint32_t flags) +{ + if (flags & IEEE80211_CHAN_2GHZ) { + /* 2GHz band */ + if (chan == 14) + return 2484; + if (chan < 14) + return 2407 + chan * 5; + else + return 2512 + ((chan - 15) * 20); + } else if (flags & IEEE80211_CHAN_5GHZ) { + /* 5Ghz band */ + return 5000 + (chan * 5); + } else { + /* either, guess */ + if (chan == 14) + return 2484; + if (chan < 14) /* 0-13 */ + return 2407 + chan * 5; + if (chan < 27) /* 15-26 */ + return 2512 + ((chan - 15) * 20); + return 5000 + (chan * 5); + } +} + +/** + * ol_if_dfs_get_ext_busy() - Place holder function ic_get_ext_busy + * @ic: ieee80211com ptr + * + * Return: Always return success (0) + */ +int ol_if_dfs_get_ext_busy(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ol_if_dfs_get_mib_cycle_counts_pct() - Place holder function + * @ic: ieee80211com ptr + * + * Return: Always return success (0) + */ +int +ol_if_dfs_get_mib_cycle_counts_pct(struct ieee80211com *ic, + uint32_t *rxc_pcnt, uint32_t *rxf_pcnt, + uint32_t *txf_pcnt) +{ + return 0; +} + +/** + * ol_if_dfs_usenol() - dfs usenol call + * @ic: ieee80211com ptr + * + * Return: 0 fo success or error code + */ +uint16_t ol_if_dfs_usenol(struct ieee80211com *ic) +{ +#if ATH_SUPPORT_DFS + return dfs_usenol(ic); +#else + return 0; +#endif /* ATH_SUPPORT_DFS */ + return 0; +} + +/** + * ieee80211_mark_dfs() - indicate radar on current operating freq + * @ic: ieee80211com ptr + * @ichan: channel + * + * Function to indicate Radar on the current + * SAP operating channel.This indication will + * be posted to SAP to select a new channel + * randomly and issue a vdev restart to + * operate on the new channel. + * + * Return: none + */ +void +ieee80211_mark_dfs(struct ieee80211com *ic, struct ieee80211_channel *ichan) +{ + int status; + status = wma_dfs_indicate_radar(ic, ichan); +} diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c new file mode 100644 index 0000000000..065f2e300b --- /dev/null +++ b/core/wma/src/wma_features.c @@ -0,0 +1,7171 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_features.c + * This file contains different features related functions like WoW, + * Offloads, TDLS etc. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "radar_filters.h" +#include "wma_internal.h" + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#define WMA_WOW_STA_WAKE_UP_EVENTS ((1 << WOW_CSA_IE_EVENT) |\ + (1 << WOW_CLIENT_KICKOUT_EVENT) |\ + (1 << WOW_PATTERN_MATCH_EVENT) |\ + (1 << WOW_MAGIC_PKT_RECVD_EVENT) |\ + (1 << WOW_DEAUTH_RECVD_EVENT) |\ + (1 << WOW_DISASSOC_RECVD_EVENT) |\ + (1 << WOW_BMISS_EVENT) |\ + (1 << WOW_GTK_ERR_EVENT) |\ + (1 << WOW_BETTER_AP_EVENT) |\ + (1 << WOW_HTT_EVENT) |\ + (1 << WOW_RA_MATCH_EVENT) |\ + (1 << WOW_NLO_DETECTED_EVENT) |\ + (1 << WOW_EXTSCAN_EVENT))\ + +#define WMA_WOW_SAP_WAKE_UP_EVENTS ((1 << WOW_PROBE_REQ_WPS_IE_EVENT) |\ + (1 << WOW_PATTERN_MATCH_EVENT) |\ + (1 << WOW_AUTH_REQ_EVENT) |\ + (1 << WOW_ASSOC_REQ_EVENT) |\ + (1 << WOW_DEAUTH_RECVD_EVENT) |\ + (1 << WOW_DISASSOC_RECVD_EVENT) |\ + (1 << WOW_HTT_EVENT))\ + +static const uint8_t arp_ptrn[] = {0x08, 0x06}; +static const uint8_t arp_mask[] = {0xff, 0xff}; +static const uint8_t ns_ptrn[] = {0x86, 0xDD}; +static const uint8_t discvr_ptrn[] = {0xe0, 0x00, 0x00, 0xf8}; +static const uint8_t discvr_mask[] = {0xf0, 0x00, 0x00, 0xf8}; + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_post_auto_shutdown_msg() - to post auto shutdown event to sme + * + * Return: 0 for success or error code + */ +static int wma_post_auto_shutdown_msg(void) +{ + tSirAutoShutdownEvtParams *auto_sh_evt; + CDF_STATUS cdf_status; + cds_msg_t sme_msg = { 0 }; + + auto_sh_evt = (tSirAutoShutdownEvtParams *) + cdf_mem_malloc(sizeof(tSirAutoShutdownEvtParams)); + if (!auto_sh_evt) { + WMA_LOGE(FL("No Mem")); + return -ENOMEM; + } + + auto_sh_evt->shutdown_reason = + WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY; + sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND; + sme_msg.bodyptr = auto_sh_evt; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME"); + cdf_mem_free(auto_sh_evt); + return -EINVAL; + } + + return 0; +} +#endif +/** + * wma_send_snr_request() - send request to fw to get RSSI stats + * @wma_handle: wma handle + * @pGetRssiReq: get RSSI request + * + * Return: CDF status + */ +CDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, + void *pGetRssiReq) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + tAniGetRssiReq *pRssiBkUp = NULL; + + /* command is in progess */ + if (NULL != wma_handle->pGetRssiReq) + return CDF_STATUS_SUCCESS; + + /* create a copy of csrRssiCallback to send rssi value + * after wmi event + */ + if (pGetRssiReq) { + pRssiBkUp = cdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (!pRssiBkUp) { + WMA_LOGE("Failed to allocate memory for tAniGetRssiReq"); + wma_handle->pGetRssiReq = NULL; + return CDF_STATUS_E_NOMEM; + } + cdf_mem_set(pRssiBkUp, sizeof(tAniGetRssiReq), 0); + pRssiBkUp->sessionId = + ((tAniGetRssiReq *) pGetRssiReq)->sessionId; + pRssiBkUp->rssiCallback = + ((tAniGetRssiReq *) pGetRssiReq)->rssiCallback; + pRssiBkUp->pDevContext = + ((tAniGetRssiReq *) pGetRssiReq)->pDevContext; + wma_handle->pGetRssiReq = (void *)pRssiBkUp; + } + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + cdf_mem_free(pRssiBkUp); + wma_handle->pGetRssiReq = NULL; + return CDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_STAT; + if (wmi_unified_cmd_send + (wma_handle->wmi_handle, buf, len, WMI_REQUEST_STATS_CMDID)) { + WMA_LOGE("Failed to send host stats request to fw"); + wmi_buf_free(buf); + cdf_mem_free(pRssiBkUp); + wma_handle->pGetRssiReq = NULL; + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_snr() - get RSSI from fw + * @psnr_req: request params + * + * Return: CDF status + */ +CDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + tAniGetSnrReq *psnr_req_bkp; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + tp_wma_handle wma_handle = NULL; + struct wma_txrx_node *intr; + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s : Failed to get wma_handle", __func__); + return CDF_STATUS_E_FAULT; + } + + intr = &wma_handle->interfaces[psnr_req->sessionId]; + /* command is in progess */ + if (NULL != intr->psnr_req) { + WMA_LOGE("%s : previous snr request is pending", __func__); + return CDF_STATUS_SUCCESS; + } + + psnr_req_bkp = cdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (!psnr_req_bkp) { + WMA_LOGE("Failed to allocate memory for tAniGetSnrReq"); + return CDF_STATUS_E_NOMEM; + } + + cdf_mem_set(psnr_req_bkp, sizeof(tAniGetSnrReq), 0); + psnr_req_bkp->staId = psnr_req->staId; + psnr_req_bkp->pDevContext = psnr_req->pDevContext; + psnr_req_bkp->snrCallback = psnr_req->snrCallback; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + cdf_mem_free(psnr_req_bkp); + return CDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + cmd->vdev_id = psnr_req->sessionId; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_STAT; + intr->psnr_req = (void *)psnr_req_bkp; + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMA_LOGE("Failed to send host stats request to fw"); + wmi_buf_free(buf); + cdf_mem_free(psnr_req_bkp); + intr->psnr_req = NULL; + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_link_status_req() - process link status request from UMAC + * @wma: wma handle + * @pGetLinkStatus: get link params + * + * Return: none + */ +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + struct wma_txrx_node *iface = + &wma->interfaces[pGetLinkStatus->sessionId]; + + if (iface->plink_status_req) { + WMA_LOGE("%s:previous link status request is pending,deleting the new request", + __func__); + cdf_mem_free(pGetLinkStatus); + return; + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + goto end; + } + + iface->plink_status_req = pGetLinkStatus; + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_RATE_STAT; + cmd->vdev_id = pGetLinkStatus->sessionId; + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMA_LOGE("Failed to send WMI link status request to fw"); + wmi_buf_free(buf); + iface->plink_status_req = NULL; + goto end; + } + + return; + +end: + wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY); +} + +#ifdef FEATURE_WLAN_LPHB +/** + * wma_lphb_conf_hbenable() - enable command of LPHB configuration requests + * @wma_handle: WMA handle + * @lphb_conf_req: configuration info + * @by_user: whether this call is from user or cached resent + * + * Return: CDF status + */ +CDF_STATUS wma_lphb_conf_hbenable(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req, bool by_user) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBEnableStruct *ts_lphb_enable; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp; + int len = sizeof(wmi_hb_set_enable_cmd_fixed_param); + int i; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + ts_lphb_enable = &(lphb_conf_req->params.lphbEnableReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_ENABLE enable=%d, item=%d, session=%d", + __func__, + ts_lphb_enable->enable, + ts_lphb_enable->item, ts_lphb_enable->session); + + if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) { + WMA_LOGE("%s : LPHB configuration wrong item %d", + __func__, ts_lphb_enable->item); + return CDF_STATUS_E_FAILURE; + } + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_enable_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_enable_cmd_fixed_param)); + + /* fill in values */ + hb_enable_fp->vdev_id = ts_lphb_enable->session; + hb_enable_fp->enable = ts_lphb_enable->enable; + hb_enable_fp->item = ts_lphb_enable->item; + hb_enable_fp->session = ts_lphb_enable->session; + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HB_SET_ENABLE_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_ENABLE returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + if (by_user) { + /* target already configured, now cache command status */ + if (ts_lphb_enable->enable) { + i = ts_lphb_enable->item - 1; + wma_handle->wow.lphb_cache[i].cmd + = LPHB_SET_EN_PARAMS_INDID; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + enable = ts_lphb_enable->enable; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + item = ts_lphb_enable->item; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + session = ts_lphb_enable->session; + + WMA_LOGI("%s: cached LPHB status in WMA context for item %d", + __func__, i); + } else { + cdf_mem_zero((void *)&wma_handle->wow.lphb_cache, + sizeof(wma_handle->wow.lphb_cache)); + WMA_LOGI("%s: cleared all cached LPHB status in WMA context", + __func__); + } + } + + return CDF_STATUS_SUCCESS; +error: + return cdf_status; +} + +/** + * wma_lphb_conf_tcp_params() - set tcp params of LPHB configuration requests + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +CDF_STATUS wma_lphb_conf_tcp_params(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBTcpParamStruct *ts_lphb_tcp_param; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp; + int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param); + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + ts_lphb_tcp_param = &(lphb_conf_req->params.lphbTcpParamReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, dev_ip=%08x, src_port=%d, " + "dst_port=%d, timeout=%d, session=%d, gateway_mac=%02x:%02x:%02x:%02x:%02x:%02x, " + "timePeriodSec=%d, tcpSn=%d", __func__, ts_lphb_tcp_param->srv_ip, + ts_lphb_tcp_param->dev_ip, ts_lphb_tcp_param->src_port, + ts_lphb_tcp_param->dst_port, ts_lphb_tcp_param->timeout, + ts_lphb_tcp_param->session, ts_lphb_tcp_param->gateway_mac[0], + ts_lphb_tcp_param->gateway_mac[1], + ts_lphb_tcp_param->gateway_mac[2], + ts_lphb_tcp_param->gateway_mac[3], + ts_lphb_tcp_param->gateway_mac[4], + ts_lphb_tcp_param->gateway_mac[5], + ts_lphb_tcp_param->timePeriodSec, ts_lphb_tcp_param->tcpSn); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_tcp_params_cmd_fixed_param)); + + /* fill in values */ + hb_tcp_params_fp->vdev_id = ts_lphb_tcp_param->session; + hb_tcp_params_fp->srv_ip = ts_lphb_tcp_param->srv_ip; + hb_tcp_params_fp->dev_ip = ts_lphb_tcp_param->dev_ip; + hb_tcp_params_fp->seq = ts_lphb_tcp_param->tcpSn; + hb_tcp_params_fp->src_port = ts_lphb_tcp_param->src_port; + hb_tcp_params_fp->dst_port = ts_lphb_tcp_param->dst_port; + hb_tcp_params_fp->interval = ts_lphb_tcp_param->timePeriodSec; + hb_tcp_params_fp->timeout = ts_lphb_tcp_param->timeout; + hb_tcp_params_fp->session = ts_lphb_tcp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac, + &hb_tcp_params_fp->gateway_mac); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HB_SET_TCP_PARAMS_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + return CDF_STATUS_SUCCESS; +error: + return cdf_status; +} + +/** + * wma_lphb_conf_tcp_pkt_filter() - configure tcp packet filter command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +CDF_STATUS wma_lphb_conf_tcp_pkt_filter(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBTcpFilterStruct *ts_lphb_tcp_filter; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp; + int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param); + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + ts_lphb_tcp_filter = &(lphb_conf_req->params.lphbTcpFilterReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__, + ts_lphb_tcp_filter->length, ts_lphb_tcp_filter->offset, + ts_lphb_tcp_filter->session, ts_lphb_tcp_filter->filter[0], + ts_lphb_tcp_filter->filter[1], ts_lphb_tcp_filter->filter[2], + ts_lphb_tcp_filter->filter[3], ts_lphb_tcp_filter->filter[4], + ts_lphb_tcp_filter->filter[5]); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_tcp_filter_fp = + (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param)); + + /* fill in values */ + hb_tcp_filter_fp->vdev_id = ts_lphb_tcp_filter->session; + hb_tcp_filter_fp->length = ts_lphb_tcp_filter->length; + hb_tcp_filter_fp->offset = ts_lphb_tcp_filter->offset; + hb_tcp_filter_fp->session = ts_lphb_tcp_filter->session; + memcpy((void *)&hb_tcp_filter_fp->filter, + (void *)&ts_lphb_tcp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HB_SET_TCP_PKT_FILTER_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + return CDF_STATUS_SUCCESS; +error: + return cdf_status; +} + +/** + * wma_lphb_conf_udp_params() - configure udp param command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +CDF_STATUS wma_lphb_conf_udp_params(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBUdpParamStruct *ts_lphb_udp_param; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp; + int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param); + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + ts_lphb_udp_param = &(lphb_conf_req->params.lphbUdpParamReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, " + "dst_port=%d, interval=%d, timeout=%d, session=%d, " + "gateway_mac=%2x:%2x:%2x:%2x:%2x:%2x", __func__, + ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip, + ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port, + ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout, + ts_lphb_udp_param->session, ts_lphb_udp_param->gateway_mac[0], + ts_lphb_udp_param->gateway_mac[1], + ts_lphb_udp_param->gateway_mac[2], + ts_lphb_udp_param->gateway_mac[3], + ts_lphb_udp_param->gateway_mac[4], + ts_lphb_udp_param->gateway_mac[5]); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_udp_params_cmd_fixed_param)); + + /* fill in values */ + hb_udp_params_fp->vdev_id = ts_lphb_udp_param->session; + hb_udp_params_fp->srv_ip = ts_lphb_udp_param->srv_ip; + hb_udp_params_fp->dev_ip = ts_lphb_udp_param->dev_ip; + hb_udp_params_fp->src_port = ts_lphb_udp_param->src_port; + hb_udp_params_fp->dst_port = ts_lphb_udp_param->dst_port; + hb_udp_params_fp->interval = ts_lphb_udp_param->interval; + hb_udp_params_fp->timeout = ts_lphb_udp_param->timeout; + hb_udp_params_fp->session = ts_lphb_udp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac, + &hb_udp_params_fp->gateway_mac); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HB_SET_UDP_PARAMS_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + return CDF_STATUS_SUCCESS; +error: + return cdf_status; +} + +/** + * wma_lphb_conf_udp_pkt_filter() - configure udp pkt filter command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +CDF_STATUS wma_lphb_conf_udp_pkt_filter(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBUdpFilterStruct *ts_lphb_udp_filter; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp; + int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param); + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + ts_lphb_udp_filter = &(lphb_conf_req->params.lphbUdpFilterReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__, + ts_lphb_udp_filter->length, ts_lphb_udp_filter->offset, + ts_lphb_udp_filter->session, ts_lphb_udp_filter->filter[0], + ts_lphb_udp_filter->filter[1], ts_lphb_udp_filter->filter[2], + ts_lphb_udp_filter->filter[3], ts_lphb_udp_filter->filter[4], + ts_lphb_udp_filter->filter[5]); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_udp_filter_fp = + (wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_udp_pkt_filter_cmd_fixed_param)); + + /* fill in values */ + hb_udp_filter_fp->vdev_id = ts_lphb_udp_filter->session; + hb_udp_filter_fp->length = ts_lphb_udp_filter->length; + hb_udp_filter_fp->offset = ts_lphb_udp_filter->offset; + hb_udp_filter_fp->session = ts_lphb_udp_filter->session; + memcpy((void *)&hb_udp_filter_fp->filter, + (void *)&ts_lphb_udp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HB_SET_UDP_PKT_FILTER_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + return CDF_STATUS_SUCCESS; +error: + return cdf_status; +} + +/** + * wma_process_lphb_conf_req() - handle LPHB configuration requests + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +CDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s : LPHB configuration cmd id is %d", __func__, + lphb_conf_req->cmd); + switch (lphb_conf_req->cmd) { + case LPHB_SET_EN_PARAMS_INDID: + cdf_status = wma_lphb_conf_hbenable(wma_handle, + lphb_conf_req, true); + break; + + case LPHB_SET_TCP_PARAMS_INDID: + cdf_status = wma_lphb_conf_tcp_params(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_TCP_PKT_FILTER_INDID: + cdf_status = wma_lphb_conf_tcp_pkt_filter(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_UDP_PARAMS_INDID: + cdf_status = wma_lphb_conf_udp_params(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_UDP_PKT_FILTER_INDID: + cdf_status = wma_lphb_conf_udp_pkt_filter(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_NETWORK_INFO_INDID: + default: + break; + } + + cdf_mem_free(lphb_conf_req); + return cdf_status; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * wma_process_dhcp_ind() - process dhcp indication from SME + * @wma_handle: wma handle + * @ta_dhcp_ind: DHCP indication + * + * Return: CDF Status + */ +CDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle, + tAniDHCPInd *ta_dhcp_ind) +{ + uint8_t vdev_id; + int status = 0; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_peer_set_param_cmd_fixed_param *peer_set_param_fp; + int len = sizeof(wmi_peer_set_param_cmd_fixed_param); + + if (!ta_dhcp_ind) { + WMA_LOGE("%s : DHCP indication is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (!wma_find_vdev_by_addr(wma_handle, ta_dhcp_ind->adapterMacAddr, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for DHCP indication", + __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s: WMA --> WMI_PEER_SET_PARAM triggered by DHCP, " + "msgType=%s," + "device_mode=%d, macAddr=" MAC_ADDRESS_STR, + __func__, + ta_dhcp_ind->msgType == WMA_DHCP_START_IND ? + "WMA_DHCP_START_IND" : "WMA_DHCP_STOP_IND", + ta_dhcp_ind->device_mode, + MAC_ADDR_ARRAY(ta_dhcp_ind->peerMacAddr)); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + peer_set_param_fp = (wmi_peer_set_param_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&peer_set_param_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_set_param_cmd_fixed_param)); + + /* fill in values */ + peer_set_param_fp->vdev_id = vdev_id; + peer_set_param_fp->param_id = WMI_PEER_CRIT_PROTO_HINT_ENABLED; + if (WMA_DHCP_START_IND == ta_dhcp_ind->msgType) + peer_set_param_fp->param_value = 1; + else + peer_set_param_fp->param_value = 0; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ta_dhcp_ind->peerMacAddr, + &peer_set_param_fp->peer_macaddr); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_PEER_SET_PARAM_CMDID); + if (status != EOK) { + WMA_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD" + " returned Error %d", __func__, status); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_chan_to_mode() - convert channel to phy mode + * @chan: channel number + * @chan_width: channel width + * @vht_capable: vht capable + * @dot11_mode: 802.11 mode + * + * Return: return phy mode + */ +WLAN_PHY_MODE wma_chan_to_mode(u8 chan, phy_ch_width chan_width, + u8 vht_capable, u8 dot11_mode) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + + /* 2.4 GHz band */ + if ((chan >= WMA_11G_CHANNEL_BEGIN) && (chan <= WMA_11G_CHANNEL_END)) { + switch (chan_width) { + case CH_WIDTH_20MHZ: + /* In case of no channel bonding, use dot11_mode + * to set phy mode + */ + switch (dot11_mode) { + case WNI_CFG_DOT11_MODE_11A: + phymode = MODE_11A; + break; + case WNI_CFG_DOT11_MODE_11B: + phymode = MODE_11B; + break; + case WNI_CFG_DOT11_MODE_11G: + phymode = MODE_11G; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + phymode = MODE_11GONLY; + break; + default: + /* Configure MODE_11NG_HT20 for + * self vdev(for vht too) + */ + phymode = MODE_11NG_HT20; + break; + } + break; + case CH_WIDTH_40MHZ: + phymode = vht_capable ? MODE_11AC_VHT40 : + MODE_11NG_HT40; + break; + default: + break; + } + } + + /* 5 GHz band */ + if ((chan >= WMA_11A_CHANNEL_BEGIN) && (chan <= WMA_11A_CHANNEL_END)) { + switch (chan_width) { + case CH_WIDTH_20MHZ: + phymode = vht_capable ? MODE_11AC_VHT20 : + MODE_11NA_HT20; + break; + case CH_WIDTH_40MHZ: + phymode = vht_capable ? MODE_11AC_VHT40 : + MODE_11NA_HT40; + break; + case CH_WIDTH_80MHZ: + phymode = MODE_11AC_VHT80; + break; +#if CONFIG_160MHZ_SUPPORT != 0 + case CH_WIDTH_160MHZ: + phymode = MODE_11AC_VHT160; + break; + case CH_WIDTH_80P80MHZ: + phymode = MODE_11AC_VHT80_80; + break; +#endif + + default: + break; + } + } + + /* 5.9 GHz Band */ + if ((chan >= WMA_11P_CHANNEL_BEGIN) && (chan <= WMA_11P_CHANNEL_END)) + /* Only Legacy Modulation Schemes are supported */ + phymode = MODE_11A; + + WMA_LOGD("%s: phymode %d channel %d ch_width %d vht_capable %d " + "dot11_mode %d", __func__, phymode, chan, + chan_width, vht_capable, dot11_mode); + + return phymode; +} + +/** + * wma_get_link_speed() -send command to get linkspeed + * @handle: wma handle + * @pLinkSpeed: link speed info + * + * Return: CDF status + */ +CDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_peer_get_estimated_linkspeed_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get link speed cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_ESTIMATE_LINKSPEED)) { + WMA_LOGE("%s: Linkspeed feature bit not enabled" + " Sending value 0 as link speed.", __func__); + wma_send_link_speed(0); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(wmi_peer_get_estimated_linkspeed_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_peer_get_estimated_linkspeed_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_get_estimated_linkspeed_cmd_fixed_param)); + + /* Copy the peer macaddress to the wma buffer */ + WMI_CHAR_ARRAY_TO_MAC_ADDR(pLinkSpeed->peer_macaddr, + &cmd->peer_macaddr); + + WMA_LOGD("%s: pLinkSpeed->peerMacAddr: %pM, " + "peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x", + __func__, pLinkSpeed->peer_macaddr, + cmd->peer_macaddr.mac_addr31to0, + cmd->peer_macaddr.mac_addr47to32); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID)) { + WMA_LOGE("%s: failed to send link speed command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_GREEN_AP + +/** + * wmi_unified_pdev_green_ap_ps_enable_cmd() - enable green ap powersave command + * @wmi_handle: wmi handle + * @value: value + * + * Return: 0 for success or error code + */ +int32_t wmi_unified_pdev_green_ap_ps_enable_cmd(wmi_unified_t wmi_handle, + uint32_t value) +{ + wmi_pdev_green_ap_ps_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMA_LOGD("Set Green AP PS val %d", value); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: Green AP PS Mem Alloc Failed", __func__); + return -ENOMEM; + } + + cmd = (wmi_pdev_green_ap_ps_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_green_ap_ps_enable_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->enable = value; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID)) { + WMA_LOGE("Set Green AP PS param Failed val %d", value); + cdf_nbuf_free(buf); + return -EIO; + } + return 0; +} +#endif /* FEATURE_GREEN_AP */ + +#ifdef FEATURE_WLAN_LPHB +/** + * wma_lphb_handler() - send LPHB indication to SME + * @wma: wma handle + * @event: event handler + * + * Return: 0 for success or error code + */ +static int wma_lphb_handler(tp_wma_handle wma, uint8_t *event) +{ + wmi_hb_ind_event_fixed_param *hb_fp; + tSirLPHBInd *slphb_indication; + CDF_STATUS cdf_status; + cds_msg_t sme_msg = { 0 }; + + hb_fp = (wmi_hb_ind_event_fixed_param *) event; + if (!hb_fp) { + WMA_LOGE("Invalid wmi_hb_ind_event_fixed_param buffer"); + return -EINVAL; + } + + WMA_LOGD("lphb indication received with vdev_id=%d, session=%d, reason=%d", + hb_fp->vdev_id, hb_fp->session, hb_fp->reason); + + slphb_indication = (tSirLPHBInd *) cdf_mem_malloc(sizeof(tSirLPHBInd)); + + if (!slphb_indication) { + WMA_LOGE("Invalid LPHB indication buffer"); + return -ENOMEM; + } + + slphb_indication->sessionIdx = hb_fp->session; + slphb_indication->protocolType = hb_fp->reason; + slphb_indication->eventReason = hb_fp->reason; + + sme_msg.type = eWNI_SME_LPHB_IND; + sme_msg.bodyptr = slphb_indication; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_LPHB_IND msg to SME"); + cdf_mem_free(slphb_indication); + return -EINVAL; + } + + return 0; +} +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * wma_wow_sta_ra_filter() - set RA filter pattern in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: CDF status + */ +static CDF_STATUS wma_wow_sta_ra_filter(tp_wma_handle wma, uint8_t vdev_id) +{ + + WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; + struct wma_txrx_node *iface; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len; + int ret; + + iface = &wma->interfaces[vdev_id]; + + len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_BITMAP_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->pattern_id = iface->num_wow_default_patterns++, + cmd->pattern_type = WOW_IPV6_RA_PATTERN; + buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for pattern_info_timeout but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for ra_ratelimit_interval. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(A_UINT32)); + buf_ptr += WMI_TLV_HDR_SIZE; + + *((A_UINT32 *) buf_ptr) = wma->RArateLimitInterval; + + WMA_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__, + wma->RArateLimitInterval, vdev_id); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_ADD_WAKE_PATTERN_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send RA rate limit to fw", __func__); + wmi_buf_free(buf); + iface->num_wow_default_patterns--; + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; + +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +/** + * wmi_unified_nat_keepalive_enable() - enable NAT keepalive filter + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id) +{ + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMA_LOGD("%s: vdev_id %d", __func__, vdev_id); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->action = IPSEC_NATKEEPALIVE_FILTER_ENABLE; + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID)) { + WMA_LOGP("%s: Failed to send NAT keepalive enable command", + __func__); + wmi_buf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wmi_unified_csa_offload_enable() - sen CSA offload enable command + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wmi_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id) +{ + wmi_csa_offload_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMA_LOGD("%s: vdev_id %d", __func__, vdev_id); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_csa_offload_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_csa_offload_enable_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->csa_offload_enable = WMI_CSA_OFFLOAD_ENABLE; + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_CSA_OFFLOAD_ENABLE_CMDID)) { + WMA_LOGP("%s: Failed to send CSA offload enable command", + __func__); + wmi_buf_free(buf); + return -EIO; + } + return 0; +} + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_rsp_event_handler() - Function is used to handle nan response + * @handle: wma handle + * @event_buf: event buffer + * @len: length of buffer + * + * Return: 0 for success or error code + */ +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_NAN_EVENTID_param_tlvs *param_buf; + tSirNanEvent *nan_rsp_event; + wmi_nan_event_hdr *nan_rsp_event_hdr; + CDF_STATUS status; + cds_msg_t cds_msg; + uint8_t *buf_ptr; + uint32_t alloc_len; + + /* + * This is how received event_buf looks like + * + * <-------------------- event_buf -----------------------------------> + * + * <--wmi_nan_event_hdr--><---WMI_TLV_HDR_SIZE---><----- data --------> + * + * +-----------+---------+-----------------------+--------------------+ + * | tlv_header| data_len| WMITLV_TAG_ARRAY_BYTE | nan_rsp_event_data | + * +-----------+---------+-----------------------+--------------------+ + */ + + WMA_LOGD("%s: Posting NaN response event to SME", __func__); + param_buf = (WMI_NAN_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid nan response event buf", __func__); + return -EINVAL; + } + nan_rsp_event_hdr = param_buf->fixed_param; + buf_ptr = (uint8_t *) nan_rsp_event_hdr; + alloc_len = sizeof(tSirNanEvent); + alloc_len += nan_rsp_event_hdr->data_len; + nan_rsp_event = (tSirNanEvent *) cdf_mem_malloc(alloc_len); + if (NULL == nan_rsp_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return -ENOMEM; + } + + nan_rsp_event->event_data_len = nan_rsp_event_hdr->data_len; + cdf_mem_copy(nan_rsp_event->event_data, buf_ptr + + sizeof(wmi_nan_event_hdr) + WMI_TLV_HDR_SIZE, + nan_rsp_event->event_data_len); + cds_msg.type = eWNI_SME_NAN_EVENT; + cds_msg.bodyptr = (void *)nan_rsp_event; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post NaN response event to SME", + __func__); + cdf_mem_free(nan_rsp_event); + return -EFAULT; + } + WMA_LOGD("%s: NaN response event Posted to SME", __func__); + return 0; +} +#endif /* WLAN_FEATURE_NAN */ + +/** + * wma_csa_offload_handler() - CSA event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * This event is sent by firmware when it receives CSA IE. + * + * Return: 0 for success or error code + */ +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_CSA_HANDLING_EVENTID_param_tlvs *param_buf; + wmi_csa_event_fixed_param *csa_event; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t vdev_id = 0; + uint8_t cur_chan = 0; + struct ieee80211_channelswitch_ie *csa_ie; + tpCSAOffloadParams csa_offload_event; + struct ieee80211_extendedchannelswitch_ie *xcsa_ie; + struct ieee80211_ie_wide_bw_switch *wb_ie; + struct wma_txrx_node *intr = wma->interfaces; + + param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event; + + WMA_LOGD("%s: Enter", __func__); + if (!param_buf) { + WMA_LOGE("Invalid csa event buffer"); + return -EINVAL; + } + csa_event = param_buf->fixed_param; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, &bssid[0]); + + if (wma_find_vdev_by_bssid(wma, bssid, &vdev_id) == NULL) { + WMA_LOGE("Invalid bssid received %s:%d", __func__, __LINE__); + return -EINVAL; + } + + csa_offload_event = cdf_mem_malloc(sizeof(*csa_offload_event)); + if (!csa_offload_event) { + WMA_LOGE("CDF MEM Alloc Failed for csa_offload_event"); + return -EINVAL; + } + + cdf_mem_zero(csa_offload_event, sizeof(*csa_offload_event)); + cdf_mem_copy(csa_offload_event->bssId, &bssid, IEEE80211_ADDR_LEN); + + if (csa_event->ies_present_flag & WMI_CSA_IE_PRESENT) { + csa_ie = (struct ieee80211_channelswitch_ie *) + (&csa_event->csa_ie[0]); + csa_offload_event->channel = csa_ie->newchannel; + csa_offload_event->switchmode = csa_ie->switchmode; + } else if (csa_event->ies_present_flag & WMI_XCSA_IE_PRESENT) { + xcsa_ie = (struct ieee80211_extendedchannelswitch_ie *) + (&csa_event->xcsa_ie[0]); + csa_offload_event->channel = xcsa_ie->newchannel; + csa_offload_event->switchmode = xcsa_ie->switchmode; + } else { + WMA_LOGE("CSA Event error: No CSA IE present"); + cdf_mem_free(csa_offload_event); + return -EINVAL; + } + + if (csa_event->ies_present_flag & WMI_WBW_IE_PRESENT) { + wb_ie = (struct ieee80211_ie_wide_bw_switch *) + (&csa_event->wb_ie[0]); + csa_offload_event->new_ch_width = wb_ie->new_ch_width; + csa_offload_event->new_ch_freq_seg1 = wb_ie->new_ch_freq_seg1; + csa_offload_event->new_ch_freq_seg2 = wb_ie->new_ch_freq_seg2; + } + + csa_offload_event->ies_present_flag = csa_event->ies_present_flag; + + WMA_LOGD("CSA: New Channel = %d BSSID:%pM", + csa_offload_event->channel, csa_offload_event->bssId); + + cur_chan = cds_freq_to_chan(intr[vdev_id].mhz); + /* + * basic sanity check: requested channel should not be 0 + * and equal to home channel + */ + if ((0 == csa_offload_event->channel) || + (cur_chan == csa_offload_event->channel)) { + WMA_LOGE("CSA Event with channel %d. Ignore !!", + csa_offload_event->channel); + cdf_mem_free(csa_offload_event); + return -EINVAL; + } + wma->interfaces[vdev_id].is_channel_switch = true; + wma_send_msg(wma, WMA_CSA_OFFLOAD_EVENT, (void *)csa_offload_event, 0); + return 0; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * wma_oem_capability_event_callback() - OEM capability event handler + * @handle: wma handle + * @datap: data ptr + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_oem_capability_event_callback(void *handle, + uint8_t *datap, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OEM_CAPABILITY_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + uint32_t *msg_subtype; + tStartOemDataRsp *pStartOemDataRsp; + + param_buf = (WMI_OEM_CAPABILITY_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return -EINVAL; + } + + /* wma puts 4 bytes prefix for msg subtype, so length + * of data received from target should be 4 bytes less + * then max allowed + */ + if (datalen > (OEM_DATA_RSP_SIZE - 4)) { + WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)", + __func__, datalen, (OEM_DATA_RSP_SIZE - 4)); + return -EINVAL; + } + + pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp)); + if (!pStartOemDataRsp) { + WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__); + return -ENOMEM; + } + + cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp)); + msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]); + *msg_subtype = WMI_OEM_CAPABILITY_RSP; + cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen); + + WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)", + __func__, datalen); + + wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0); + return 0; +} + +/** + * wma_oem_measurement_report_event_callback() - OEM measurement report handler + * @handle: wma handle + * @datap: data ptr + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_oem_measurement_report_event_callback(void *handle, + uint8_t *datap, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + uint32_t *msg_subtype; + tStartOemDataRsp *pStartOemDataRsp; + + param_buf = (WMI_OEM_MEASUREMENT_REPORT_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return -EINVAL; + } + + /* wma puts 4 bytes prefix for msg subtype, so length + * of data received from target should be 4 bytes less + * then max allowed + */ + if (datalen > (OEM_DATA_RSP_SIZE - 4)) { + WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)", + __func__, datalen, (OEM_DATA_RSP_SIZE - 4)); + return -EINVAL; + } + + pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp)); + if (!pStartOemDataRsp) { + WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__); + return -ENOMEM; + } + + cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp)); + msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]); + *msg_subtype = WMI_OEM_MEASUREMENT_RSP; + cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen); + + WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)", + __func__, datalen); + + wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0); + return 0; +} + +/** + * wma_oem_error_report_event_callback() - OEM error report handler + * @handle: wma handle + * @datap: data ptr + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_oem_error_report_event_callback(void *handle, + uint8_t *datap, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + uint32_t *msg_subtype; + tStartOemDataRsp *pStartOemDataRsp; + + param_buf = (WMI_OEM_ERROR_REPORT_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return -EINVAL; + } + + /* wma puts 4 bytes prefix for msg subtype, so length + * of data received from target should be 4 bytes less + * then max allowed + */ + if (datalen > (OEM_DATA_RSP_SIZE - 4)) { + WMA_LOGE("%s: Received data len (%d) exceeds max value (%d)", + __func__, datalen, (OEM_DATA_RSP_SIZE - 4)); + return -EINVAL; + } + + pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp)); + if (!pStartOemDataRsp) { + WMA_LOGE("%s: Failed to alloc pStartOemDataRsp", __func__); + return -ENOMEM; + } + + cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp)); + msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]); + *msg_subtype = WMI_OEM_ERROR_REPORT_RSP; + cdf_mem_copy(&pStartOemDataRsp->oemDataRsp[4], data, datalen); + + WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP, data len (%d)", + __func__, datalen); + + wma_send_msg(wma, WMA_START_OEM_DATA_RSP, (void *)pStartOemDataRsp, 0); + return 0; +} + +/** + * wma_start_oem_data_req() - start OEM data request to target + * @wma_handle: wma handle + * @startOemDataReq: start request params + * + * Return: none + */ +void wma_start_oem_data_req(tp_wma_handle wma_handle, + tStartOemDataReq *startOemDataReq) +{ + wmi_buf_t buf; + uint8_t *cmd; + int ret = 0; + uint32_t *msg_subtype; + tStartOemDataRsp *pStartOemDataRsp; + + WMA_LOGD("%s: Send OEM Data Request to target", __func__); + + if (!startOemDataReq) { + WMA_LOGE("%s: startOemDataReq is null", __func__); + goto out; + } + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not send Oem data request cmd", + __func__); + return; + } + + buf = wmi_buf_alloc(wma_handle->wmi_handle, + (OEM_DATA_REQ_SIZE + WMI_TLV_HDR_SIZE)); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + goto out; + } + + cmd = (uint8_t *) wmi_buf_data(buf); + + WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE, OEM_DATA_REQ_SIZE); + cmd += WMI_TLV_HDR_SIZE; + cdf_mem_copy(cmd, &startOemDataReq->oemDataReq[0], OEM_DATA_REQ_SIZE); + + WMA_LOGI("%s: Sending OEM Data Request to target, data len (%d)", + __func__, OEM_DATA_REQ_SIZE); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + (OEM_DATA_REQ_SIZE + + WMI_TLV_HDR_SIZE), WMI_OEM_REQ_CMDID); + + if (ret != EOK) { + WMA_LOGE("%s:wmi cmd send failed", __func__); + cdf_nbuf_free(buf); + } + +out: + /* free oem data req buffer received from UMAC */ + if (startOemDataReq) + cdf_mem_free(startOemDataReq); + + /* Now send data resp back to PE/SME with message sub-type of + * WMI_OEM_INTERNAL_RSP. This is required so that PE/SME clears + * up pending active command. Later when desired oem response(s) + * comes as wmi event from target then those shall be passed + * to oem application + */ + pStartOemDataRsp = cdf_mem_malloc(sizeof(*pStartOemDataRsp)); + if (!pStartOemDataRsp) { + WMA_LOGE("%s:failed to allocate memory for OEM Data Resp to PE", + __func__); + return; + } + cdf_mem_zero(pStartOemDataRsp, sizeof(tStartOemDataRsp)); + msg_subtype = (uint32_t *) (&pStartOemDataRsp->oemDataRsp[0]); + *msg_subtype = WMI_OEM_INTERNAL_RSP; + + WMA_LOGI("%s: Sending WMA_START_OEM_DATA_RSP to clear up PE/SME pending cmd", + __func__); + + wma_send_msg(wma_handle, WMA_START_OEM_DATA_RSP, + (void *)pStartOemDataRsp, 0); + + return; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + + +/** + * wma_unified_dfs_radar_rx_event_handler() - dfs radar rx event handler + * @handle: wma handle + * @data: data buffer + * @datalen: data length + * + * WMI handler for WMI_DFS_RADAR_EVENTID + * This handler is registered for handling + * filtered DFS Phyerror. This handler is + * will be invoked only when DFS Phyerr + * filtering offload is enabled. + * + * Return: 1 for Success and 0 for error + */ +static int wma_unified_dfs_radar_rx_event_handler(void *handle, + uint8_t *data, + uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + struct ieee80211com *ic; + struct ath_dfs *dfs; + struct dfs_event *event; + struct ieee80211_channel *chan; + int empty; + int do_check_chirp = 0; + int is_hw_chirp = 0; + int is_sw_chirp = 0; + int is_pri = 0; + + WMI_DFS_RADAR_EVENTID_param_tlvs *param_tlvs; + wmi_dfs_radar_event_fixed_param *radar_event; + + ic = wma->dfs_ic; + if (NULL == ic) { + WMA_LOGE("%s: dfs_ic is NULL ", __func__); + return 0; + } + + dfs = (struct ath_dfs *)ic->ic_dfs; + param_tlvs = (WMI_DFS_RADAR_EVENTID_param_tlvs *) data; + + if (NULL == dfs) { + WMA_LOGE("%s: dfs is NULL ", __func__); + return 0; + } + /* + * This parameter holds the number + * of phyerror interrupts to the host + * after the phyerrors have passed through + * false detect filters in the firmware. + */ + dfs->dfs_phyerr_count++; + + if (!param_tlvs) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return 0; + } + + radar_event = param_tlvs->fixed_param; + + cdf_mutex_acquire(&ic->chan_lock); + chan = ic->ic_curchan; + if (CHANNEL_STATE_DFS != cds_get_channel_state(chan->ic_ieee)) { + WMA_LOGE + ("%s: Invalid DFS Phyerror event. Channel=%d is Non-DFS", + __func__, chan->ic_ieee); + cdf_mutex_release(&ic->chan_lock); + return 0; + } + + cdf_mutex_release(&ic->chan_lock); + dfs->ath_dfs_stats.total_phy_errors++; + + if (dfs->dfs_caps.ath_chip_is_bb_tlv) { + do_check_chirp = 1; + is_pri = 1; + is_hw_chirp = radar_event->pulse_is_chirp; + + if ((uint32_t) dfs->dfs_phyerr_freq_min > + radar_event->pulse_center_freq) { + dfs->dfs_phyerr_freq_min = + (int)radar_event->pulse_center_freq; + } + + if (dfs->dfs_phyerr_freq_max < + (int)radar_event->pulse_center_freq) { + dfs->dfs_phyerr_freq_max = + (int)radar_event->pulse_center_freq; + } + } + + /* + * Now, add the parsed, checked and filtered + * radar phyerror event radar pulse event list. + * This event will then be processed by + * dfs_radar_processevent() to see if the pattern + * of pulses in radar pulse list match any radar + * singnature in the current regulatory domain. + */ + + ATH_DFSEVENTQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_UNLOCK(dfs); + if (empty) { + return 0; + } + /* + * Add the event to the list, if there's space. + */ + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + WMA_LOGE("%s: No more space left for queuing DFS Phyerror events", + __func__); + return 0; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + dfs->dfs_phyerr_queued_count++; + dfs->dfs_phyerr_w53_counter++; + event->re_dur = (uint8_t) radar_event->pulse_duration; + event->re_rssi = radar_event->rssi; + event->re_ts = radar_event->pulse_detect_ts & DFS_TSMASK; + event->re_full_ts = (((uint64_t) radar_event->upload_fullts_high) << 32) + | radar_event->upload_fullts_low; + + /* + * Index of peak magnitude + */ + event->sidx = radar_event->peak_sidx; + + /* + * Handle chirp flags. + */ + if (do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (is_hw_chirp) { + event->re_flags |= DFS_EVENT_HW_CHIRP; + } + if (is_sw_chirp) { + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + } + /* + * Correctly set which channel is being reported on + */ + if (is_pri) { + event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex; + } else { + if (dfs->dfs_extchan_radindex == -1) { + WMA_LOGI("%s phyerr on ext channel", __func__); + } + event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex; + WMA_LOGI("%s:New extension channel event is added to queue", + __func__); + } + + ATH_DFSQ_LOCK(dfs); + + STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); + + empty = STAILQ_EMPTY(&dfs->dfs_radarq); + + ATH_DFSQ_UNLOCK(dfs); + + if (!empty && !dfs->ath_radar_tasksched) { + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + } + + return 1; + +} + +/** + * wma_unified_phyerr_rx_event_handler() - phyerr event handler + * @handle: wma handle + * @data: data buffer + * @datalen: buffer length + * + * WMI Handler for WMI_PHYERR_EVENTID event from firmware. + * This handler is currently handling only DFS phy errors. + * This handler will be invoked only when the DFS phyerror + * filtering offload is disabled. + * + * Return: 1:Success, 0:Failure + */ +static int wma_unified_phyerr_rx_event_handler(void *handle, + uint8_t *data, uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PHYERR_EVENTID_param_tlvs *param_tlvs; + wmi_comb_phyerr_rx_hdr *pe_hdr; + uint8_t *bufp; + wmi_single_phyerr_rx_event *ev; + struct ieee80211com *ic = wma->dfs_ic; + cdf_size_t n; + A_UINT64 tsf64 = 0; + int phy_err_code = 0; + int error = 0; + tpAniSirGlobal mac_ctx = + (tpAniSirGlobal)cds_get_context(CDF_MODULE_ID_PE); + bool enable_log = false; + + if (NULL == mac_ctx) { + WMA_LOGE("%s: mac_ctx is NULL", __func__); + return 0; + } + enable_log = mac_ctx->sap.enable_dfs_phy_error_logs; + + param_tlvs = (WMI_PHYERR_EVENTID_param_tlvs *) data; + + if (!param_tlvs) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return 0; + } + + pe_hdr = param_tlvs->hdr; + if (pe_hdr == NULL) { + WMA_LOGE("%s: Received Data PE Header is NULL", __func__); + return 0; + } + + /* Ensure it's at least the size of the header */ + if (datalen < sizeof(*pe_hdr)) { + WMA_LOGE("%s: Expected minimum size %zu, received %d", + __func__, sizeof(*pe_hdr), datalen); + return 0; + } + if (pe_hdr->buf_len > DFS_MAX_BUF_LENGHT) { + WMA_LOGE("%s: Received Invalid Phyerror event buffer length = %d" + "Maximum allowed buf length = %d", __func__, + pe_hdr->buf_len, DFS_MAX_BUF_LENGHT); + + return 0; + } + + /* + * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's + * at the time the event was sent to us, the TSF value will be + * in the future. + */ + tsf64 = pe_hdr->tsf_l32; + tsf64 |= (((uint64_t) pe_hdr->tsf_u32) << 32); + + /* + * Loop over the bufp, extracting out phyerrors + * wmi_unified_comb_phyerr_rx_event.bufp is a char pointer, + * which isn't correct here - what we have received here + * is an array of TLV-style PHY errors. + */ + n = 0; /* Start just after the header */ + bufp = param_tlvs->bufp; + while (n < pe_hdr->buf_len) { + /* ensure there's at least space for the header */ + if ((pe_hdr->buf_len - n) < sizeof(ev->hdr)) { + WMA_LOGE("%s: Not enough space.(datalen=%d, n=%zu, hdr=%zu bytes", + __func__, pe_hdr->buf_len, n, sizeof(ev->hdr)); + error = 1; + break; + } + /* + * Obtain a pointer to the beginning of the current event. + * data[0] is the beginning of the WMI payload. + */ + ev = (wmi_single_phyerr_rx_event *) &bufp[n]; + + /* + * Sanity check the buffer length of the event against + * what we currently have. + * Since buf_len is 32 bits, we check if it overflows + * a large 32 bit value. It's not 0x7fffffff because + * we increase n by (buf_len + sizeof(hdr)), which would + * in itself cause n to overflow. + * If "int" is 64 bits then this becomes a moot point. + */ + if (ev->hdr.buf_len > 0x7f000000) { + WMA_LOGE("%s:buf_len is garbage (0x%x)", __func__, + ev->hdr.buf_len); + error = 1; + break; + } + if (n + ev->hdr.buf_len > pe_hdr->buf_len) { + WMA_LOGE("%s: buf_len exceeds available space n=%zu," + "buf_len=%d, datalen=%d", + __func__, n, ev->hdr.buf_len, pe_hdr->buf_len); + error = 1; + break; + } + phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr); + + /* + * If the phyerror category matches, + * pass radar events to the dfs pattern matching code. + * Don't pass radar events with no buffer payload. + */ + if (phy_err_code == 0x5 || phy_err_code == 0x24) { + if (ev->hdr.buf_len > 0) { + /* Calling in to the DFS module to process the phyerr */ + dfs_process_phyerr(ic, &ev->bufp[0], + ev->hdr.buf_len, + WMI_UNIFIED_RSSI_COMB_GET + (&ev->hdr) & 0xff, + /* Extension RSSI */ + WMI_UNIFIED_RSSI_COMB_GET + (&ev->hdr) & 0xff, + ev->hdr.tsf_timestamp, + tsf64, enable_log); + } + } + + /* + * Advance the buffer pointer to the next PHY error. + * buflen is the length of this payload, so we need to + * advance past the current header _AND_ the payload. + */ + n += sizeof(*ev) + ev->hdr.buf_len; + + } /*end while() */ + if (error) + return 0; + else + return 1; +} + +/** + * wma_register_dfs_event_handler() - register dfs event handler + * @wma_handle: wma handle + * + * Register appropriate dfs phyerror event handler + * based on phyerror filtering offload is enabled + * or disabled. + * + * Return: none + */ +void wma_register_dfs_event_handler(tp_wma_handle wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return; + } + + if (false == wma_handle->dfs_phyerr_filter_offload) { + /* + * Register the wma_unified_phyerr_rx_event_handler + * for filtering offload disabled case to handle + * the DFS phyerrors. + */ + WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini", + __func__); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PHYERR_EVENTID, + wma_unified_phyerr_rx_event_handler); + WMA_LOGD("%s: WMI_PHYERR_EVENTID event handler registered", + __func__); + } else { + WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini", + __func__); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DFS_RADAR_EVENTID, + wma_unified_dfs_radar_rx_event_handler); + WMA_LOGD("%s:WMI_DFS_RADAR_EVENTID event handler registered", + __func__); + } + + return; +} + + +/** + * wma_unified_dfs_phyerr_filter_offload_enable() - enable dfs phyerr filter + * @wma_handle: wma handle + * + * Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or + * WMI_DFS_PHYERR_FILTER_DIS_CMDID command + * to firmware based on phyerr filtering + * offload status. + * + * Return: 1 success, 0 failure + */ +int +wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle) +{ + wmi_dfs_phyerr_filter_ena_cmd_fixed_param *enable_phyerr_offload_cmd; + wmi_dfs_phyerr_filter_dis_cmd_fixed_param *disable_phyerr_offload_cmd; + wmi_buf_t buf; + uint16_t len; + int ret; + + if (NULL == wma_handle) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return 0; + } + + if (false == wma_handle->dfs_phyerr_filter_offload) { + WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini", + __func__); + len = sizeof(*disable_phyerr_offload_cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return 0; + } + disable_phyerr_offload_cmd = + (wmi_dfs_phyerr_filter_dis_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&disable_phyerr_offload_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_dfs_phyerr_filter_dis_cmd_fixed_param)); + + /* + * Send WMI_DFS_PHYERR_FILTER_DIS_CMDID + * to the firmware to disable the phyerror + * filtering offload. + */ + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DFS_PHYERR_FILTER_DIS_CMDID); + if (ret < 0) { + WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_DIS_CMDID ret=%d", + __func__, ret); + wmi_buf_free(buf); + return 0; + } + WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_DIS_CMDID Send Success", + __func__); + } else { + WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini", + __func__); + + len = sizeof(*enable_phyerr_offload_cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return 0; + } + + enable_phyerr_offload_cmd = + (wmi_dfs_phyerr_filter_ena_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&enable_phyerr_offload_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_dfs_phyerr_filter_ena_cmd_fixed_param)); + + /* + * Send a WMI_DFS_PHYERR_FILTER_ENA_CMDID + * to the firmware to enable the phyerror + * filtering offload. + */ + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DFS_PHYERR_FILTER_ENA_CMDID); + + if (ret < 0) { + WMA_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_ENA_CMDID ret=%d", + __func__, ret); + wmi_buf_free(buf); + return 0; + } + WMA_LOGD("%s: WMI_DFS_PHYERR_FILTER_ENA_CMDID Send Success", + __func__); + } + + return 1; +} + +#if !defined(REMOVE_PKT_LOG) +/** + * wma_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target + * @handle: wma handle + * @params: pktlog params + * + * Return: CDF status + */ +CDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_PKTLOG_EVENT PKTLOG_EVENT; + WMI_CMD_ID CMD_ID; + wmi_pdev_pktlog_enable_cmd_fixed_param *cmd; + wmi_pdev_pktlog_disable_cmd_fixed_param *disable_cmd; + int len = 0; + wmi_buf_t buf; + + /*Check if packet log is enabled in cfg.ini */ + if (!cds_is_packet_log_enabled()) { + WMA_LOGE("%s:pkt log is not enabled in cfg.ini", __func__); + return CDF_STATUS_E_FAILURE; + } + + PKTLOG_EVENT = params->pktlog_event; + CMD_ID = params->cmd_id; + + switch (CMD_ID) { + case WMI_PDEV_PKTLOG_ENABLE_CMDID: + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_pktlog_enable_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_pktlog_enable_cmd_fixed_param)); + cmd->evlist = PKTLOG_EVENT; + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_PKTLOG_ENABLE_CMDID)) { + WMA_LOGE("failed to send pktlog enable cmdid"); + goto wmi_send_failed; + } + break; + case WMI_PDEV_PKTLOG_DISABLE_CMDID: + len = sizeof(*disable_cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + disable_cmd = (wmi_pdev_pktlog_disable_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&disable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_pktlog_disable_cmd_fixed_param)); + disable_cmd->reserved0 = 0; + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_PKTLOG_DISABLE_CMDID)) { + WMA_LOGE("failed to send pktlog disable cmdid"); + goto wmi_send_failed; + } + break; + default: + WMA_LOGD("%s: invalid PKTLOG command", __func__); + break; + } + + return CDF_STATUS_SUCCESS; + +wmi_send_failed: + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; +} +#endif /* REMOVE_PKT_LOG */ + +static void wma_send_status_to_suspend_ind(tp_wma_handle wma, bool suspended) +{ + tSirReadyToSuspendInd *ready_to_suspend; + CDF_STATUS status; + cds_msg_t cds_msg; + uint8_t len; + + WMA_LOGD("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToSuspendInd); + ready_to_suspend = (tSirReadyToSuspendInd *) cdf_mem_malloc(len); + + if (NULL == ready_to_suspend) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + ready_to_suspend->mesgType = eWNI_SME_READY_TO_SUSPEND_IND; + ready_to_suspend->mesgLen = len; + ready_to_suspend->suspended = suspended; + + cds_msg.type = eWNI_SME_READY_TO_SUSPEND_IND; + cds_msg.bodyptr = (void *)ready_to_suspend; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post ready to suspend"); + cdf_mem_free(ready_to_suspend); + } +} + +/** + * wma_wow_wake_reason_str() - Converts wow wakeup reason code to text format + * @wake_reason - WOW wake reason + * + * Return: reason code in string format + */ +static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason) +{ + switch (wake_reason) { + case WOW_REASON_UNSPECIFIED: + return "UNSPECIFIED"; + case WOW_REASON_NLOD: + return "NLOD"; + case WOW_REASON_AP_ASSOC_LOST: + return "AP_ASSOC_LOST"; + case WOW_REASON_LOW_RSSI: + return "LOW_RSSI"; + case WOW_REASON_DEAUTH_RECVD: + return "DEAUTH_RECVD"; + case WOW_REASON_DISASSOC_RECVD: + return "DISASSOC_RECVD"; + case WOW_REASON_GTK_HS_ERR: + return "GTK_HS_ERR"; + case WOW_REASON_EAP_REQ: + return "EAP_REQ"; + case WOW_REASON_FOURWAY_HS_RECV: + return "FOURWAY_HS_RECV"; + case WOW_REASON_TIMER_INTR_RECV: + return "TIMER_INTR_RECV"; + case WOW_REASON_PATTERN_MATCH_FOUND: + return "PATTERN_MATCH_FOUND"; + case WOW_REASON_RECV_MAGIC_PATTERN: + return "RECV_MAGIC_PATTERN"; + case WOW_REASON_P2P_DISC: + return "P2P_DISC"; +#ifdef FEATURE_WLAN_LPHB + case WOW_REASON_WLAN_HB: + return "WLAN_HB"; +#endif /* FEATURE_WLAN_LPHB */ + + case WOW_REASON_CSA_EVENT: + return "CSA_EVENT"; + case WOW_REASON_PROBE_REQ_WPS_IE_RECV: + return "PROBE_REQ_RECV"; + case WOW_REASON_AUTH_REQ_RECV: + return "AUTH_REQ_RECV"; + case WOW_REASON_ASSOC_REQ_RECV: + return "ASSOC_REQ_RECV"; + case WOW_REASON_HTT_EVENT: + return "WOW_REASON_HTT_EVENT"; +#ifdef FEATURE_WLAN_RA_FILTERING + case WOW_REASON_RA_MATCH: + return "WOW_REASON_RA_MATCH"; +#endif /* FEATURE_WLAN_RA_FILTERING */ + case WOW_REASON_BEACON_RECV: + return "WOW_REASON_IBSS_BEACON_RECV"; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WOW_REASON_HOST_AUTO_SHUTDOWN: + return "WOW_REASON_HOST_AUTO_SHUTDOWN"; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WOW_REASON_ROAM_HO: + return "WOW_REASON_ROAM_HO"; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef FEATURE_WLAN_EXTSCAN + case WOW_REASON_EXTSCAN: + return "WOW_REASON_EXTSCAN"; +#endif + case WOW_REASON_RSSI_BREACH_EVENT: + return "WOW_REASON_RSSI_BREACH_EVENT"; + } + return "unknown"; +} + +/** + * wma_wow_wake_up_stats_display() - display wow wake up stats + * @wma: Pointer to wma handle + * + * Return: none + */ +static void wma_wow_wake_up_stats_display(tp_wma_handle wma) +{ + WMA_LOGA("uc %d bc %d v4_mc %d v6_mc %d ra %d ns %d na %d pno_match %d pno_complete %d gscan %d low_rssi %d rssi_breach %d", + wma->wow_ucast_wake_up_count, + wma->wow_bcast_wake_up_count, + wma->wow_ipv4_mcast_wake_up_count, + wma->wow_ipv6_mcast_wake_up_count, + wma->wow_ipv6_mcast_ra_stats, + wma->wow_ipv6_mcast_ns_stats, + wma->wow_ipv6_mcast_na_stats, + wma->wow_pno_match_wake_up_count, + wma->wow_pno_complete_wake_up_count, + wma->wow_gscan_wake_up_count, + wma->wow_low_rssi_wake_up_count, + wma->wow_rssi_breach_wake_up_count); + + return; +} + +/** + * wma_wow_ipv6_mcast_stats() - ipv6 mcast wake up stats + * @wma: Pointer to wma handle + * @data: Pointer to pattern match data + * + * Return: none + */ +static void wma_wow_ipv6_mcast_stats(tp_wma_handle wma, uint8_t *data) +{ + static const uint8_t ipv6_mcast[] = {0x86, 0xDD}; + + if (!memcmp(ipv6_mcast, (data + WMA_ETHER_TYPE_OFFSET), + sizeof(ipv6_mcast))) { + if (WMA_ICMP_V6_HEADER_TYPE == + *(data + WMA_ICMP_V6_HEADER_OFFSET)) { + if (WMA_ICMP_V6_RA_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + wma->wow_ipv6_mcast_ra_stats++; + else if (WMA_ICMP_V6_NS_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + wma->wow_ipv6_mcast_ns_stats++; + else if (WMA_ICMP_V6_NA_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + wma->wow_ipv6_mcast_na_stats++; + else + WMA_LOGA("ICMP V6 type : 0x%x", + *(data + WMA_ICMP_V6_TYPE_OFFSET)); + } else { + WMA_LOGA("ICMP_V6 header 0x%x", + *(data + WMA_ICMP_V6_HEADER_OFFSET)); + } + } else { + WMA_LOGA("Ethertype x%x:0x%x", + *(data + WMA_ETHER_TYPE_OFFSET), + *(data + WMA_ETHER_TYPE_OFFSET + 1)); + } + + return; +} + +/** + * wma_wow_wake_up_stats() - maintain wow pattern match wake up stats + * @wma: Pointer to wma handle + * @data: Pointer to pattern match data + * @len: Pattern match data length + * @event: Wake up event + * + * Return: none + */ +static void wma_wow_wake_up_stats(tp_wma_handle wma, uint8_t *data, + int32_t len, WOW_WAKE_REASON_TYPE event) +{ + switch (event) { + + case WOW_REASON_PATTERN_MATCH_FOUND: + if (WMA_BCAST_MAC_ADDR == *data) { + wma->wow_bcast_wake_up_count++; + } else if (WMA_MCAST_IPV4_MAC_ADDR == *data) { + wma->wow_ipv4_mcast_wake_up_count++; + } else if (WMA_MCAST_IPV6_MAC_ADDR == *data) { + wma->wow_ipv6_mcast_wake_up_count++; + if (len > WMA_ICMP_V6_TYPE_OFFSET) + wma_wow_ipv6_mcast_stats(wma, data); + else + WMA_LOGA("ICMP_V6 data len %d", len); + } else { + wma->wow_ucast_wake_up_count++; + } + break; + + case WOW_REASON_RA_MATCH: + wma->wow_ipv6_mcast_ra_stats++; + break; + + case WOW_REASON_NLOD: + wma->wow_pno_match_wake_up_count++; + break; + + case WOW_REASON_NLO_SCAN_COMPLETE: + wma->wow_pno_complete_wake_up_count++; + break; + + case WOW_REASON_LOW_RSSI: + wma->wow_low_rssi_wake_up_count++; + break; + + case WOW_REASON_EXTSCAN: + wma->wow_gscan_wake_up_count++; + break; + + case WOW_REASON_RSSI_BREACH_EVENT: + wma->wow_rssi_breach_wake_up_count++; + break; + + default: + WMA_LOGE("Unknown wake up reason"); + break; + } + + wma_wow_wake_up_stats_display(wma); + return; +} + +/** + * wma_wow_wakeup_host_event() - wakeup host event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Handler to catch wow wakeup host event. This event will have + * reason why the firmware has woken the host. + * + * Return: 0 for success or error + */ +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf; + WOW_EVENT_INFO_fixed_param *wake_info; +#ifdef FEATURE_WLAN_SCAN_PNO + struct wma_txrx_node *node; +#endif /* FEATURE_WLAN_SCAN_PNO */ + uint32_t wake_lock_duration = 0; + uint32_t wow_buf_pkt_len = 0; + + param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid wow wakeup host event buf"); + return -EINVAL; + } + + wake_info = param_buf->fixed_param; + + WMA_LOGA("WOW wakeup host event received (reason: %s(%d)) for vdev %d", + wma_wow_wake_reason_str(wake_info->wake_reason), + wake_info->wake_reason, wake_info->vdev_id); + + cdf_event_set(&wma->wma_resume_event); + + switch (wake_info->wake_reason) { + case WOW_REASON_AUTH_REQ_RECV: + wake_lock_duration = WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT; + break; + + case WOW_REASON_ASSOC_REQ_RECV: + wake_lock_duration = WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION; + break; + + case WOW_REASON_DEAUTH_RECVD: + wake_lock_duration = WMA_DEAUTH_RECV_WAKE_LOCK_DURATION; + break; + + case WOW_REASON_DISASSOC_RECVD: + wake_lock_duration = WMA_DISASSOC_RECV_WAKE_LOCK_DURATION; + break; + + case WOW_REASON_AP_ASSOC_LOST: + wake_lock_duration = WMA_BMISS_EVENT_WAKE_LOCK_DURATION; + WMA_LOGA("Beacon miss indication on vdev %x", + wake_info->vdev_id); + wma_beacon_miss_handler(wma, wake_info->vdev_id); + break; +#ifdef FEATURE_WLAN_RA_FILTERING + case WOW_REASON_RA_MATCH: + wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_RA_MATCH); + break; +#endif /* FEATURE_WLAN_RA_FILTERING */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WOW_REASON_HOST_AUTO_SHUTDOWN: + wake_lock_duration = WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION; + WMA_LOGA("Received WOW Auto Shutdown trigger in suspend"); + if (wma_post_auto_shutdown_msg()) + return -EINVAL; + break; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ +#ifdef FEATURE_WLAN_SCAN_PNO + case WOW_REASON_NLOD: + wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_NLOD); + node = &wma->interfaces[wake_info->vdev_id]; + if (node) { + WMA_LOGD("NLO match happened"); + node->nlo_match_evt_received = true; + cdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + } + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ + + case WOW_REASON_CSA_EVENT: + { + WMI_CSA_HANDLING_EVENTID_param_tlvs param; + WMA_LOGD("Host woken up because of CSA IE"); + param.fixed_param = (wmi_csa_event_fixed_param *) + (((uint8_t *) wake_info) + + sizeof(WOW_EVENT_INFO_fixed_param) + + WOW_CSA_EVENT_OFFSET); + wma_csa_offload_handler(handle, (uint8_t *) ¶m, + sizeof(param)); + } + break; + +#ifdef FEATURE_WLAN_LPHB + case WOW_REASON_WLAN_HB: + wma_lphb_handler(wma, (uint8_t *) param_buf->hb_indevt); + break; +#endif /* FEATURE_WLAN_LPHB */ + + case WOW_REASON_HTT_EVENT: + break; + case WOW_REASON_PATTERN_MATCH_FOUND: + wma_wow_wake_up_stats_display(wma); + WMA_LOGD("Wake up for Rx packet, dump starting from ethernet hdr"); + if (param_buf->wow_packet_buffer) { + /* First 4-bytes of wow_packet_buffer is the length */ + cdf_mem_copy((uint8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + wma_wow_wake_up_stats(wma, + param_buf->wow_packet_buffer + 4, + wow_buf_pkt_len, + WOW_REASON_PATTERN_MATCH_FOUND); + cdf_trace_hex_dump(CDF_MODULE_ID_WMA, + CDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer + 4, + wow_buf_pkt_len); + } else { + WMA_LOGE("No wow packet buffer present"); + } + break; + + case WOW_REASON_LOW_RSSI: + { + /* WOW_REASON_LOW_RSSI is used for all roaming events. + * WMI_ROAM_REASON_BETTER_AP, WMI_ROAM_REASON_BMISS, + * WMI_ROAM_REASON_SUITABLE_AP will be handled by + * wma_roam_event_callback(). + */ + WMI_ROAM_EVENTID_param_tlvs param; + wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_LOW_RSSI); + if (param_buf->wow_packet_buffer) { + /* Roam event is embedded in wow_packet_buffer */ + WMA_LOGD("Host woken up because of roam event"); + cdf_mem_copy((uint8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + WMA_LOGD("wow_packet_buffer dump"); + cdf_trace_hex_dump(CDF_MODULE_ID_WMA, + CDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer, + wow_buf_pkt_len); + if (wow_buf_pkt_len >= sizeof(param)) { + param.fixed_param = + (wmi_roam_event_fixed_param *) + (param_buf->wow_packet_buffer + 4); + wma_roam_event_callback(handle, + (uint8_t *) & + param, + sizeof(param)); + } else { + WMA_LOGE("Wrong length for roam event = %d bytes", + wow_buf_pkt_len); + } + } else { + /* No wow_packet_buffer means a better AP beacon + * will follow in a later event. + */ + WMA_LOGD("Host woken up because of better AP beacon"); + } + break; + } + case WOW_REASON_CLIENT_KICKOUT_EVENT: + { + WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs param; + if (param_buf->wow_packet_buffer) { + /* station kickout event embedded in wow_packet_buffer */ + WMA_LOGD("Host woken up because of sta_kickout event"); + cdf_mem_copy((u_int8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + WMA_LOGD("wow_packet_buffer dump"); + cdf_trace_hex_dump(CDF_MODULE_ID_WMA, + CDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer, wow_buf_pkt_len); + if (wow_buf_pkt_len >= sizeof(param)) { + param.fixed_param = (wmi_peer_sta_kickout_event_fixed_param *) + (param_buf->wow_packet_buffer + 4); + wma_peer_sta_kickout_event_handler(handle, + (u_int8_t *)¶m, sizeof(param)); + } else { + WMA_LOGE("Wrong length for sta_kickout event = %d bytes", + wow_buf_pkt_len); + } + } else { + WMA_LOGD("No wow_packet_buffer present"); + } + break; + } +#ifdef FEATURE_WLAN_EXTSCAN + case WOW_REASON_EXTSCAN: + WMA_LOGD("Host woken up because of extscan reason"); + wma_wow_wake_up_stats(wma, NULL, 0, WOW_REASON_EXTSCAN); + if (param_buf->wow_packet_buffer) { + wow_buf_pkt_len = + *(uint32_t *)param_buf->wow_packet_buffer; + wma_extscan_wow_event_callback(handle, + (u_int8_t *)(param_buf->wow_packet_buffer + 4), + wow_buf_pkt_len); + } else + WMA_LOGE("wow_packet_buffer is empty"); + break; +#endif + case WOW_REASON_RSSI_BREACH_EVENT: + { + WMI_RSSI_BREACH_EVENTID_param_tlvs param; + + wma_wow_wake_up_stats(wma, NULL, 0, + WOW_REASON_RSSI_BREACH_EVENT); + WMA_LOGD("Host woken up because of rssi breach reason"); + /* rssi breach event is embedded in wow_packet_buffer */ + if (param_buf->wow_packet_buffer) { + cdf_mem_copy((u_int8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + if (wow_buf_pkt_len >= sizeof(param)) { + param.fixed_param = + (wmi_rssi_breach_event_fixed_param *) + (param_buf->wow_packet_buffer + 4); + wma_rssi_breached_event_handler(handle, + (u_int8_t *)¶m, + sizeof(param)); + } else { + WMA_LOGE("%s: Wrong length: %d bytes", + __func__, wow_buf_pkt_len); + } + } else + WMA_LOGD("No wow_packet_buffer present"); + } + break; + default: + break; + } + + if (wake_lock_duration) { + cdf_wake_lock_timeout_acquire(&wma->wow_wake_lock, + wake_lock_duration, + WIFI_POWER_EVENT_WAKELOCK_WOW); + WMA_LOGA("Holding %d msec wake_lock", wake_lock_duration); + } + + return 0; +} + +/** + * wma_pdev_resume_event_handler() - PDEV resume event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Return: 0 for success or error + */ +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + WMA_LOGA("Received PDEV resume event"); + + cdf_event_set(&wma->wma_resume_event); + + return 0; +} +/** + * wma_set_wow_bus_suspend() - set suspend flag + * @wma: wma handle + * @val: value + * + * Return: none + */ +static inline void wma_set_wow_bus_suspend(tp_wma_handle wma, int val) +{ + + cdf_atomic_set(&wma->is_wow_bus_suspended, val); +} + + + +/** + * wma_add_wow_wakeup_event() - Configures wow wakeup events. + * @wma: wma handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: CDF status + */ +static CDF_STATUS wma_add_wow_wakeup_event(tp_wma_handle wma, + uint32_t vdev_id, + uint32_t bitmap, + bool enable) +{ + WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd; + uint16_t len; + wmi_buf_t buf; + int ret; + + len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->is_add = enable; + cmd->event_bitmap = bitmap; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + if (ret) { + WMA_LOGE("Failed to config wow wakeup event"); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Wakeup pattern 0x%x %s in fw", bitmap, + enable ? "enabled" : "disabled"); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_send_wow_patterns_to_fw() - Sends WOW patterns to FW. + * @wma: wma handle + * @vdev_id: vdev id + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * + * Return: CDF status + */ +static CDF_STATUS wma_send_wow_patterns_to_fw(tp_wma_handle wma, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user) +{ + WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; + WOW_BITMAP_PATTERN_T *bitmap_pattern; + struct wma_txrx_node *iface; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len; + int ret; + + iface = &wma->interfaces[vdev_id]; + + len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + + 1 * sizeof(WOW_BITMAP_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + /* + * For user configured wow pattern use pattern id sent by HDD + * and for default wow patterns generate pattern id internally + */ + if (user) + cmd->pattern_id = ptrn_id; + else + cmd->pattern_id = iface->num_wow_default_patterns++; + + cmd->pattern_type = WOW_BITMAP_PATTERN; + buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(WOW_BITMAP_PATTERN_T)); + buf_ptr += WMI_TLV_HDR_SIZE; + bitmap_pattern = (WOW_BITMAP_PATTERN_T *) buf_ptr; + + WMITLV_SET_HDR(&bitmap_pattern->tlv_header, + WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T, + WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T)); + + cdf_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len); + cdf_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len); + + bitmap_pattern->pattern_offset = ptrn_offset; + bitmap_pattern->pattern_len = ptrn_len; + + if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE) + bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE; + + if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE) + bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE; + + bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len; + bitmap_pattern->pattern_id = ptrn_id; + + WMA_LOGI("vdev id : %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d user %d", + cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len, + bitmap_pattern->pattern_offset, user); + + WMA_LOGI("Pattern : "); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO, + &bitmap_pattern->patternbuf[0], bitmap_pattern->pattern_len); + + WMA_LOGI("Mask : "); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO, + &bitmap_pattern->bitmaskbuf[0], bitmap_pattern->pattern_len); + + buf_ptr += sizeof(WOW_BITMAP_PATTERN_T); + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for pattern_info_timeout but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for ra_ratelimit_interval with dummy data as this fix elem */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(A_UINT32)); + buf_ptr += WMI_TLV_HDR_SIZE; + *(A_UINT32 *) buf_ptr = 0; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_ADD_WAKE_PATTERN_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send wow ptrn to fw", __func__); + wmi_buf_free(buf); + if (!user) + iface->num_wow_default_patterns--; + return CDF_STATUS_E_FAILURE; + } + + if (user) + iface->num_wow_user_patterns++; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_wow_ap() - set WOW patterns in ap mode + * @wma: wma handle + * @vdev_id: vdev id + * + * Configures default WOW pattern for the given vdev_id which is in AP mode. + * + * Return: CDF status + */ +static CDF_STATUS wma_wow_ap(tp_wma_handle wma, uint8_t vdev_id) +{ + CDF_STATUS ret; + uint8_t arp_offset = 20; + uint8_t mac_mask[IEEE80211_ADDR_LEN]; + + /* Setup unicast pkt pattern */ + cdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF); + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN, 0, mac_mask, + IEEE80211_ADDR_LEN, false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + /* + * Setup all ARP pkt pattern. This is dummy pattern hence the length + * is zero + */ + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + arp_ptrn, 0, arp_offset, arp_mask, 0, false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW ARP pattern ret %d", ret); + return ret; + } + + return ret; +} + +/** + * wma_wow_sta() - set WOW patterns in sta mode + * @wma: wma handle + * @vdev_id: vdev id + * + * Configures default WOW pattern for the given vdev_id which is in sta mode. + * + * Return: CDF status + */ +static CDF_STATUS wma_wow_sta(tp_wma_handle wma, uint8_t vdev_id) +{ + uint8_t arp_offset = 12; + uint8_t discvr_offset = 30; + uint8_t mac_mask[IEEE80211_ADDR_LEN]; + CDF_STATUS ret = CDF_STATUS_SUCCESS; + + /* Setup unicast pkt pattern */ + cdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF); + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN, 0, mac_mask, + IEEE80211_ADDR_LEN, false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + /* + * Setup multicast pattern for mDNS 224.0.0.251, + * SSDP 239.255.255.250 and LLMNR 224.0.0.252 + */ + if (wma->ssdp) { + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + discvr_ptrn, sizeof(discvr_ptrn), discvr_offset, + discvr_mask, sizeof(discvr_ptrn), false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW mDNS/SSDP/LLMNR pattern"); + return ret; + } + } else + WMA_LOGD("mDNS, SSDP, LLMNR patterns are disabled from ini"); + + /* when arp offload or ns offloaded is disabled + * from ini file, configure broad cast arp pattern + * to fw, so that host can wake up + */ + if (!(wma->ol_ini_info & 0x1)) { + /* Setup all ARP pkt pattern */ + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + arp_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW ARP pattern"); + return ret; + } + } + + /* for NS or NDP offload packets */ + if (!(wma->ol_ini_info & 0x2)) { + /* Setup all NS pkt pattern */ + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, 0, + ns_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW NS pattern"); + return ret; + } + } + + return ret; +} + +/** + * wma_register_wow_default_patterns() - register default wow patterns with fw + * @handle: Pointer to wma handle + * @vdev_id: vdev id + * + * WoW default wake up pattern rule is: + * - For STA & P2P CLI mode register for same STA specific wow patterns + * - For SAP/P2P GO & IBSS mode register for same SAP specific wow patterns + * + * Return: none + */ +void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id) +{ + tp_wma_handle wma = handle; + struct wma_txrx_node *iface; + + if (vdev_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", vdev_id); + return; + } + iface = &wma->interfaces[vdev_id]; + + if (iface->ptrn_match_enable) { + if (wma_is_vdev_in_ap_mode(wma, vdev_id) +#ifdef QCA_IBSS_SUPPORT + || + wma_is_vdev_in_ibss_mode(wma, vdev_id) +#endif + ) { + /* Configure SAP/GO/IBSS mode default wow patterns */ + WMA_LOGI("Config SAP specific default wow patterns vdev_id %d", + vdev_id); + wma_wow_ap(wma, vdev_id); + } else { + /* Configure STA/P2P CLI mode default wow patterns */ + WMA_LOGI("Config STA specific default wow patterns vdev_id %d", + vdev_id); + wma_wow_sta(wma, vdev_id); + if (wma->IsRArateLimitEnabled) { + WMA_LOGI("Config STA RA limit wow patterns vdev_id %d", + vdev_id); + wma_wow_sta_ra_filter(wma, vdev_id); + } + } + } + + return; +} + +/** + * wma_register_wow_wakeup_events() - register vdev specific wake events with fw + * @handle: Pointer to wma handle + * @vdev_id: vdev Id + * @vdev_type: vdev type + * @vdev_subtype: vdev sub type + * + * WoW wake up event rule is following: + * 1) STA mode and P2P CLI mode wake up events are same + * 2) SAP mode and P2P GO mode wake up events are same + * 3) IBSS mode wake events are same as STA mode plus WOW_BEACON_EVENT + * + * Return: none + */ +void wma_register_wow_wakeup_events(WMA_HANDLE handle, + uint8_t vdev_id, + uint8_t vdev_type, + uint8_t vdev_subtype) +{ + tp_wma_handle wma = handle; + uint32_t event_bitmap; + + WMA_LOGI("vdev_type %d vdev_subtype %d vdev_id %d", vdev_type, + vdev_subtype, vdev_id); + + if ((WMI_VDEV_TYPE_STA == vdev_type) || + ((WMI_VDEV_TYPE_AP == vdev_type) && + (WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == vdev_subtype))) { + /* Configure STA/P2P CLI mode specific default wake up events */ + event_bitmap = WMA_WOW_STA_WAKE_UP_EVENTS; + WMA_LOGI("STA specific default wake up event 0x%x vdev id %d", + event_bitmap, vdev_id); + } else if (WMI_VDEV_TYPE_IBSS == vdev_type) { + /* Configure IBSS mode specific default wake up events */ + event_bitmap = (WMA_WOW_STA_WAKE_UP_EVENTS | + (1 << WOW_BEACON_EVENT)); + WMA_LOGI("IBSS specific default wake up event 0x%x vdev id %d", + event_bitmap, vdev_id); + } else if (WMI_VDEV_TYPE_AP == vdev_type) { + /* Configure SAP/GO mode specific default wake up events */ + event_bitmap = WMA_WOW_SAP_WAKE_UP_EVENTS; + WMA_LOGI("SAP specific default wake up event 0x%x vdev id %d", + event_bitmap, vdev_id); + } else { + WMA_LOGE("unknown type %d subtype %d", vdev_type, vdev_subtype); + return; + } + + wma_add_wow_wakeup_event(wma, vdev_id, event_bitmap, true); + + return; +} + +/** + * wma_enable_disable_wakeup_event() - Configures wow wakeup events + * @wma: wma handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: none + */ +void wma_enable_disable_wakeup_event(WMA_HANDLE handle, + uint32_t vdev_id, + uint32_t bitmap, + bool enable) +{ + tp_wma_handle wma = handle; + + WMA_LOGI("vdev_id %d wake up event 0x%x enable %d", + vdev_id, bitmap, enable); + wma_add_wow_wakeup_event(wma, vdev_id, bitmap, enable); +} + +/** + * wma_enable_wow_in_fw() - wnable wow in fw + * @wma: wma handle + * + * Return: CDF status + */ +CDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle) +{ + tp_wma_handle wma = handle; + wmi_wow_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + struct ol_softc *scn; + int host_credits; + int wmi_pending_cmds; +#ifdef CONFIG_CNSS + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return CDF_STATUS_E_FAILURE; + } +#endif /* CONFIG_CNSS */ + + len = sizeof(wmi_wow_enable_cmd_fixed_param); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_wow_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wow_enable_cmd_fixed_param)); + cmd->enable = true; + if (hif_can_suspend_link()) + cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED; + else + cmd->pause_iface_config = WOW_IFACE_PAUSE_DISABLED; + + WMA_LOGI("suspend type: %s", + cmd->pause_iface_config == WOW_IFACE_PAUSE_ENABLED ? + "WOW_IFACE_PAUSE_ENABLED" : "WOW_IFACE_PAUSE_DISABLED"); + + cdf_event_reset(&wma->target_suspend); + wma->wow_nack = 0; + + host_credits = wmi_get_host_credits(wma->wmi_handle); + wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle); + + WMA_LOGD("Credits:%d; Pending_Cmds: %d", + host_credits, wmi_pending_cmds); + + if (host_credits < WMI_WOW_REQUIRED_CREDITS) { + WMA_LOGE("%s: Host Doesn't have enough credits to Post WMI_WOW_ENABLE_CMDID! " + "Credits:%d, pending_cmds:%d\n", __func__, host_credits, + wmi_pending_cmds); +#ifndef QCA_WIFI_3_0_EMU + goto error; +#endif + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_ENABLE_CMDID); + if (ret) { + WMA_LOGE("Failed to enable wow in fw"); + goto error; + } + + wmi_set_target_suspend(wma->wmi_handle, true); + + if (cdf_wait_single_event(&wma->target_suspend, + WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) + != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to receive WoW Enable Ack from FW"); + WMA_LOGE("Credits:%d; Pending_Cmds: %d", + wmi_get_host_credits(wma->wmi_handle), + wmi_get_pending_cmds(wma->wmi_handle)); +#ifdef CONFIG_CNSS + if (pMac->sme.enableSelfRecovery) { + cds_trigger_recovery(); + } else { + CDF_BUG(0); + } +#else + CDF_BUG(0); +#endif /* CONFIG_CNSS */ + wmi_set_target_suspend(wma->wmi_handle, false); + return CDF_STATUS_E_FAILURE; + } + + if (wma->wow_nack) { + WMA_LOGE("FW not ready to WOW"); + wmi_set_target_suspend(wma->wmi_handle, false); + return CDF_STATUS_E_AGAIN; + } + + host_credits = wmi_get_host_credits(wma->wmi_handle); + wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle); + + if (host_credits < WMI_WOW_REQUIRED_CREDITS) { + WMA_LOGE("%s: No Credits after HTC ACK:%d, pending_cmds:%d, " + "cannot resume back", __func__, host_credits, + wmi_pending_cmds); + htc_dump_counter_info(wma->htc_handle); + if (!cds_is_logp_in_progress()) + CDF_BUG(0); + else + WMA_LOGE("%s: SSR in progress, ignore no credit issue", + __func__); + } + + WMA_LOGD("WOW enabled successfully in fw: credits:%d" + "pending_cmds: %d", host_credits, wmi_pending_cmds); + + scn = cds_get_context(CDF_MODULE_ID_HIF); + + if (scn == NULL) { + WMA_LOGE("%s: Failed to get HIF context", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAULT; + } + + htc_cancel_deferred_target_sleep(scn); + + wma->wow.wow_enable_cmd_sent = true; + + return CDF_STATUS_SUCCESS; + +error: + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; +} + +/** + * wma_resume_req() - clear configured wow patterns in fw + * @wma: wma handle + * + * Return: CDF status + */ +CDF_STATUS wma_resume_req(tp_wma_handle wma) +{ + wma->no_of_resume_ind++; + + if (wma->no_of_resume_ind < wma_get_vdev_count(wma)) + return CDF_STATUS_SUCCESS; + + wma->no_of_resume_ind = 0; + + /* Reset the DTIM Parameters */ + wma_set_resume_dtim(wma); + /* need to reset if hif_pci_suspend_fails */ + wma_set_wow_bus_suspend(wma, 0); + /* unpause the vdev if left paused and hif_pci_suspend fails */ + wma_unpause_vdev(wma); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_wow_delete_pattern() - delete wow pattern in target + * @wma: wma handle + * @ptrn_id: pattern id + * @vdev_id: vdev id + * @user: true for user pattern and false for default pattern + * + * Return: CDF status + */ +static CDF_STATUS wma_wow_delete_pattern(tp_wma_handle wma, uint8_t ptrn_id, + uint8_t vdev_id, bool user) +{ + WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd; + struct wma_txrx_node *iface; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(WMI_WOW_DEL_PATTERN_CMD_fixed_param); + + iface = &wma->interfaces[vdev_id]; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_DEL_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->pattern_id = ptrn_id; + cmd->pattern_type = WOW_BITMAP_PATTERN; + + WMA_LOGI("Deleting pattern id: %d vdev id %d in fw", + cmd->pattern_id, vdev_id); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_DEL_WAKE_PATTERN_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to delete wow ptrn from fw", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + if (user) + iface->num_wow_user_patterns--; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_wow_add_pattern() - add wow pattern in target + * @wma: wma handle + * @ptrn: wow pattern + * + * This function does following: + * 1) Delete all default patterns of the vdev + * 2) Add received wow patterns for given vdev in target. + * + * Target is responsible for caching wow patterns accross multiple + * suspend/resumes until the pattern is deleted by user + * + * Return: CDF status + */ +CDF_STATUS wma_wow_add_pattern(tp_wma_handle wma, struct wow_add_pattern *ptrn) +{ + uint8_t id; + uint8_t bit_to_check, pos; + struct wma_txrx_node *iface; + CDF_STATUS ret = CDF_STATUS_SUCCESS; + uint8_t new_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + + if (ptrn->session_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", ptrn->session_id); + return CDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[ptrn->session_id]; + + /* clear all default patterns cofigured by wma */ + for (id = 0; id < iface->num_wow_default_patterns; id++) + wma_wow_delete_pattern(wma, id, ptrn->session_id, false); + + iface->num_wow_default_patterns = 0; + + WMA_LOGI("Add user passed wow pattern id %d vdev id %d", + ptrn->pattern_id, ptrn->session_id); + /* + * Convert received pattern mask value from bit representation + * to byte representation. + * + * For example, received value from umac, + * + * Mask value : A1 (equivalent binary is "1010 0001") + * Pattern value : 12:00:13:00:00:00:00:44 + * + * The value which goes to FW after the conversion from this + * function (1 in mask value will become FF and 0 will + * become 00), + * + * Mask value : FF:00:FF:00:0:00:00:FF + * Pattern value : 12:00:13:00:00:00:00:44 + */ + cdf_mem_zero(new_mask, sizeof(new_mask)); + for (pos = 0; pos < ptrn->pattern_size; pos++) { + bit_to_check = (WMA_NUM_BITS_IN_BYTE - 1) - + (pos % WMA_NUM_BITS_IN_BYTE); + bit_to_check = 0x1 << bit_to_check; + if (ptrn->pattern_mask[pos / WMA_NUM_BITS_IN_BYTE] & + bit_to_check) + new_mask[pos] = WMA_WOW_PTRN_MASK_VALID; + } + + ret = wma_send_wow_patterns_to_fw(wma, ptrn->session_id, + ptrn->pattern_id, + ptrn->pattern, ptrn->pattern_size, + ptrn->pattern_byte_offset, new_mask, + ptrn->pattern_size, true); + if (ret != CDF_STATUS_SUCCESS) + WMA_LOGE("Failed to add wow pattern %d", ptrn->pattern_id); + + return ret; +} + +/** + * wma_wow_delete_user_pattern() - delete user configured wow pattern in target + * @wma: wma handle + * @ptrn: wow pattern + * + * This function does following: + * 1) Deletes a particular user configured wow pattern in target + * 2) After deleting all user wow patterns add default wow patterns + * specific to that vdev. + * + * Return: CDF status + */ +CDF_STATUS wma_wow_delete_user_pattern(tp_wma_handle wma, + struct wow_delete_pattern *pattern) +{ + struct wma_txrx_node *iface; + + if (pattern->session_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", pattern->session_id); + return CDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[pattern->session_id]; + if (iface->num_wow_user_patterns <= 0) { + WMA_LOGE("No valid user pattern. Num user pattern %u vdev %d", + iface->num_wow_user_patterns, pattern->session_id); + return CDF_STATUS_E_INVAL; + } + + WMA_LOGI("Delete user passed wow pattern id %d total user pattern %d", + pattern->pattern_id, iface->num_wow_user_patterns); + + wma_wow_delete_pattern(wma, pattern->pattern_id, + pattern->session_id, true); + + /* configure default patterns once all user patterns are deleted */ + if (!iface->num_wow_user_patterns) + wma_register_wow_default_patterns(wma, pattern->session_id); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_wow_enter() - store enable/disable status for pattern + * @wma: wma handle + * @info: wow parameters + * + * Records pattern enable/disable status locally. This choice will + * take effect when the driver enter into suspend state. + * + * Return: CDF status + */ +CDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info) +{ + struct wma_txrx_node *iface; + + WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId); + + if (info->sessionId > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", info->sessionId); + cdf_mem_free(info); + return CDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[info->sessionId]; + iface->ptrn_match_enable = info->ucPatternFilteringEnable ? + true : false; + wma->wow.magic_ptrn_enable = info->ucMagicPktEnable ? true : false; + wma->wow.deauth_enable = info->ucWowDeauthRcv ? true : false; + wma->wow.disassoc_enable = info->ucWowDeauthRcv ? true : false; + wma->wow.bmiss_enable = info->ucWowMaxMissedBeacons ? true : false; + + cdf_mem_free(info); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_wow_exit() - clear all wma states + * @wma: wma handle + * @info: wow params + * + * Return: CDF status + */ +CDF_STATUS wma_wow_exit(tp_wma_handle wma, tpSirHalWowlExitParams info) +{ + struct wma_txrx_node *iface; + + WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId); + + if (info->sessionId > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", info->sessionId); + cdf_mem_free(info); + return CDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[info->sessionId]; + iface->ptrn_match_enable = false; + wma->wow.magic_ptrn_enable = false; + cdf_mem_free(info); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_suspend_req() - Handles suspend indication request received from umac. + * @wma: wma handle + * @info: suspend params + * + * Return: CDF status + */ +CDF_STATUS wma_suspend_req(tp_wma_handle wma, tpSirWlanSuspendParam info) +{ + struct wma_txrx_node *iface; + bool connected = false, pno_in_progress = false; + uint8_t i; + bool extscan_in_progress = false; + + wma->no_of_suspend_ind++; + + if (info->sessionId > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", info->sessionId); + cdf_mem_free(info); + return CDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[info->sessionId]; + if (!iface) { + WMA_LOGD("vdev %d node is not found", info->sessionId); + cdf_mem_free(info); + return CDF_STATUS_SUCCESS; + } + + if (!wma->wow.magic_ptrn_enable && !iface->ptrn_match_enable) { + cdf_mem_free(info); + + if (wma->no_of_suspend_ind == wma_get_vdev_count(wma)) { + WMA_LOGD("Both magic and pattern byte match are disabled"); + wma->no_of_suspend_ind = 0; + goto send_ready_to_suspend; + } + + return CDF_STATUS_SUCCESS; + } + + iface->conn_state = (info->connectedState) ? true : false; + + /* + * Once WOW is enabled in FW, host can't send anymore + * data to fw. umac sends suspend indication on each + * vdev during platform suspend. WMA has to wait until + * suspend indication received on last vdev before + * enabling wow in fw. + */ + if (wma->no_of_suspend_ind < wma_get_vdev_count(wma)) { + cdf_mem_free(info); + return CDF_STATUS_SUCCESS; + } + + wma->no_of_suspend_ind = 0; + wma->wow.gtk_pdev_enable = 0; + /* + * Enable WOW if any one of the condition meets, + * 1) Is any one of vdev in beaconning mode (in AP mode) ? + * 2) Is any one of vdev in connected state (in STA mode) ? + * 3) Is PNO in progress in any one of vdev ? + * 4) Is Extscan in progress in any one of vdev ? + */ + for (i = 0; i < wma->max_bssid; i++) { + if ((wma_is_vdev_in_ap_mode(wma, i) +#ifdef QCA_IBSS_SUPPORT + || wma_is_vdev_in_ibss_mode(wma, i) +#endif /* QCA_IBSS_SUPPORT */ + ) && wma->interfaces[i].vdev_up && + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + WMA_LOGD("vdev %d is in beaconning mode, enabling wow", + i); + goto enable_wow; + } + } + for (i = 0; i < wma->max_bssid; i++) { + if (wma->interfaces[i].conn_state) { + connected = true; + break; + } +#ifdef FEATURE_WLAN_SCAN_PNO + if (wma->interfaces[i].pno_in_progress) { + WMA_LOGD("PNO is in progress, enabling wow"); + pno_in_progress = true; + break; + } +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + if (wma->interfaces[i].extscan_in_progress) { + WMA_LOGD("Extscan is in progress, enabling wow"); + extscan_in_progress = true; + break; + } +#endif + } + for (i = 0; i < wma->max_bssid; i++) { + wma->wow.gtk_pdev_enable |= wma->wow.gtk_err_enable[i]; + WMA_LOGD("VDEV_ID:%d, gtk_err_enable[%d]:%d, gtk_pdev_enable:%d", i, + i, wma->wow.gtk_err_enable[i], wma->wow.gtk_pdev_enable); + } + + if (!connected && !pno_in_progress && !extscan_in_progress) { + WMA_LOGD("All vdev are in disconnected state and pno/extscan is not in progress, skipping wow"); + cdf_mem_free(info); + goto send_ready_to_suspend; + } + +enable_wow: + WMA_LOGE("WOW Suspend"); + + /* + * At this point, suspend indication is received on + * last vdev. It's the time to enable wow in fw. + */ +#ifdef FEATURE_WLAN_LPHB + /* LPHB cache, if any item was enabled, should be + * applied. + */ + WMA_LOGD("%s: checking LPHB cache", __func__); + for (i = 0; i < 2; i++) { + if (wma->wow.lphb_cache[i].params.lphbEnableReq.enable) { + WMA_LOGD("%s: LPHB cache for item %d is marked as enable", + __func__, i + 1); + wma_lphb_conf_hbenable(wma, &(wma->wow.lphb_cache[i]), + false); + } + } +#endif /* FEATURE_WLAN_LPHB */ + + wma->wow.wow_enable = true; + wma->wow.wow_enable_cmd_sent = false; + + cdf_mem_free(info); + +send_ready_to_suspend: + /* Set the Suspend DTIM Parameters */ + wma_set_suspend_dtim(wma); + wma_send_status_to_suspend_ind(wma, true); + + /* to handle race between hif_pci_suspend and + * unpause/pause tx handler + */ + wma_set_wow_bus_suspend(wma, 1); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_send_host_wakeup_ind_to_fw() - send wakeup ind to fw + * @wma: wma handle + * + * Sends host wakeup indication to FW. On receiving this indication, + * FW will come out of WOW. + * + * Return: CDF status + */ +static CDF_STATUS wma_send_host_wakeup_ind_to_fw(tp_wma_handle wma) +{ + wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd; + wmi_buf_t buf; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int32_t len; + int ret; +#ifdef CONFIG_CNSS + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return CDF_STATUS_E_FAILURE; + } +#endif /* CONFIG_CNSS */ + + len = sizeof(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param)); + + cdf_event_reset(&wma->wma_resume_event); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + if (ret) { + WMA_LOGE("Failed to send host wakeup indication to fw"); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Host wakeup indication sent to fw"); + + cdf_status = cdf_wait_single_event(&(wma->wma_resume_event), + WMA_RESUME_TIMEOUT); + if (CDF_STATUS_SUCCESS != cdf_status) { + WMA_LOGP("%s: Timeout waiting for resume event from FW", + __func__); + WMA_LOGP("%s: Pending commands %d credits %d", __func__, + wmi_get_pending_cmds(wma->wmi_handle), + wmi_get_host_credits(wma->wmi_handle)); + if (!cds_is_logp_in_progress()) { +#ifdef CONFIG_CNSS + if (pMac->sme.enableSelfRecovery) { + cds_trigger_recovery(); + } else { + CDF_BUG(0); + } +#else + CDF_BUG(0); +#endif /* CONFIG_CNSS */ + } else { + WMA_LOGE("%s: SSR in progress, ignore resume timeout", + __func__); + } + } else { + WMA_LOGD("Host wakeup received"); + } + + if (CDF_STATUS_SUCCESS == cdf_status) + wmi_set_target_suspend(wma->wmi_handle, false); + + return cdf_status; +} + +/** + * wma_disable_wow_in_fw() - Disable wow in PCIe resume context. + * @handle: wma handle + * + * Return: 0 for success or error code + */ +CDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle) +{ + tp_wma_handle wma = handle; + CDF_STATUS ret; + + if (!wma->wow.wow_enable || !wma->wow.wow_enable_cmd_sent) + return CDF_STATUS_SUCCESS; + + ret = wma_send_host_wakeup_ind_to_fw(wma); + + if (ret != CDF_STATUS_SUCCESS) + return ret; + + wma->wow.wow_enable = false; + wma->wow.wow_enable_cmd_sent = false; + + /* To allow the tx pause/unpause events */ + wma_set_wow_bus_suspend(wma, 0); + /* Unpause the vdev as we are resuming */ + wma_unpause_vdev(wma); + + return ret; +} + +#ifdef WLAN_FEATURE_LPSS +/** + * wma_is_lpass_enabled() - check if lpass is enabled + * @handle: Pointer to wma handle + * + * WoW is needed if LPASS or NaN feature is enabled in INI because + * target can't wake up itself if its put in PDEV suspend when LPASS + * or NaN features are supported + * + * Return: true if lpass is enabled else false + */ +bool static wma_is_lpass_enabled(tp_wma_handle wma) +{ + if (wma->is_lpass_enabled) + return true; + else + return false; +} +#else +bool static wma_is_lpass_enabled(tp_wma_handle wma) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_NAN +/** + * wma_is_nan_enabled() - check if NaN is enabled + * @handle: Pointer to wma handle + * + * WoW is needed if LPASS or NaN feature is enabled in INI because + * target can't wake up itself if its put in PDEV suspend when LPASS + * or NaN features are supported + * + * Return: true if NaN is enabled else false + */ +bool static wma_is_nan_enabled(tp_wma_handle wma) +{ + if (wma->is_nan_enabled) + return true; + else + return false; +} +#else +bool static wma_is_nan_enabled(tp_wma_handle wma) +{ + return false; +} +#endif + +/** + * wma_is_wow_mode_selected() - check if wow needs to be enabled in fw + * @handle: Pointer to wma handle + * + * If lpass is enabled then always do wow else check wow_enable config + * + * Return: true is wow mode is needed else false + */ +int wma_is_wow_mode_selected(WMA_HANDLE handle) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + if (wma_is_lpass_enabled(wma)) { + WMA_LOGD("LPASS is enabled select WoW"); + return true; + } else if (wma_is_nan_enabled(wma)) { + WMA_LOGD("NAN is enabled select WoW"); + return true; + } else { + WMA_LOGD("WoW enable %d", wma->wow.wow_enable); + return wma->wow.wow_enable; + } +} + +/** + * wma_del_ts_req() - send DELTS request to fw + * @wma: wma handle + * @msg: delts params + * + * Return: none + */ +void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg) +{ + wmi_vdev_wmm_delts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + goto err; + } + cmd = (wmi_vdev_wmm_delts_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_delts_cmd_fixed_param)); + cmd->vdev_id = msg->sessionId; + cmd->ac = TID_TO_WME_AC(msg->userPrio); + + WMA_LOGD("Delts vdev:%d, ac:%d, %s:%d", + cmd->vdev_id, cmd->ac, __FUNCTION__, __LINE__); + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_WMM_DELTS_CMDID)) { + WMA_LOGP("%s: Failed to send vdev DELTS command", __func__); + cdf_nbuf_free(buf); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->setRICparams == true) + wma_set_ric_req(wma, msg, false); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +err: + cdf_mem_free(msg); +} + +/** + * wma_aggr_qos_req() - send aggr qos request to fw + * @wma: handle to wma + * @pAggrQosRspMsg - combined struct for all ADD_TS requests. + * + * A function to handle WMA_AGGR_QOS_REQ. This will send out + * ADD_TS requestes to firmware in loop for all the ACs with + * active flow. + * + * Return: none + */ +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg) +{ + int i = 0; + wmi_vdev_wmm_addts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + /* if flow in this AC is active */ + if (((1 << i) & pAggrQosRspMsg->tspecIdx)) { + /* + * as per implementation of wma_add_ts_req() we + * are not waiting any response from firmware so + * apart from sending ADDTS to firmware just send + * success to upper layers + */ + pAggrQosRspMsg->status[i] = CDF_STATUS_SUCCESS; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + goto aggr_qos_exit; + } + cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_addts_cmd_fixed_param)); + cmd->vdev_id = pAggrQosRspMsg->sessionId; + cmd->ac = + TID_TO_WME_AC(pAggrQosRspMsg->tspec[i].tsinfo. + traffic.userPrio); + cmd->medium_time_us = + pAggrQosRspMsg->tspec[i].mediumTime * 32; + cmd->downgrade_type = WMM_AC_DOWNGRADE_DEPRIO; + WMA_LOGD("%s:%d: Addts vdev:%d, ac:%d, mediumTime:%d downgrade_type:%d", + __func__, __LINE__, cmd->vdev_id, cmd->ac, + cmd->medium_time_us, cmd->downgrade_type); + if (wmi_unified_cmd_send + (wma->wmi_handle, buf, len, + WMI_VDEV_WMM_ADDTS_CMDID)) { + WMA_LOGP("%s: Failed to send vdev ADDTS command", + __func__); + pAggrQosRspMsg->status[i] = + CDF_STATUS_E_FAILURE; + cdf_nbuf_free(buf); + } + } + } + +aggr_qos_exit: + /* send reponse to upper layers from here only. */ + wma_send_msg(wma, WMA_AGGR_QOS_RSP, pAggrQosRspMsg, 0); +} + +/** + * wma_add_ts_req() - send ADDTS request to fw + * @wma: wma handle + * @msg: ADDTS params + * + * Return: none + */ +void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg) +{ + wmi_vdev_wmm_addts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + +#ifdef FEATURE_WLAN_ESE + /* + * msmt_interval is in unit called TU (1 TU = 1024 us) + * max value of msmt_interval cannot make resulting + * interval_miliseconds overflow 32 bit + */ + uint32_t intervalMiliseconds; + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto err; + } + + intervalMiliseconds = (msg->tsm_interval * 1024) / 1000; + + ol_tx_set_compute_interval(pdev, intervalMiliseconds); +#endif /* FEATURE_WLAN_ESE */ + msg->status = CDF_STATUS_SUCCESS; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + goto err; + } + cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_addts_cmd_fixed_param)); + cmd->vdev_id = msg->sme_session_id; + cmd->ac = TID_TO_WME_AC(msg->tspec.tsinfo.traffic.userPrio); + cmd->medium_time_us = msg->tspec.mediumTime * 32; + cmd->downgrade_type = WMM_AC_DOWNGRADE_DROP; + WMA_LOGD("Addts vdev:%d, ac:%d, mediumTime:%d, downgrade_type:%d %s:%d", + cmd->vdev_id, cmd->ac, cmd->medium_time_us, + cmd->downgrade_type, __func__, __LINE__); + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_WMM_ADDTS_CMDID)) { + WMA_LOGP("%s: Failed to send vdev ADDTS command", __func__); + msg->status = CDF_STATUS_E_FAILURE; + cdf_nbuf_free(buf); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->setRICparams == true) + wma_set_ric_req(wma, msg, true); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +err: + wma_send_msg(wma, WMA_ADD_TS_RSP, msg, 0); +} + +/** + * wma_enable_disable_packet_filter() - enable/disable packet filter in target + * @wma: Pointer to wma handle + * @vdev_id: vdev id + * @enable: Flag to enable/disable packet filter + * + * Return: 0 for success or error code + */ +static int wma_enable_disable_packet_filter(tp_wma_handle wma, + uint8_t vdev_id, bool enable) +{ + int32_t len; + int ret = 0; + wmi_buf_t buf; + WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *cmd; + + len = sizeof(WMI_PACKET_FILTER_ENABLE_CMD_fixed_param); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return -ENOMEM; + } + + cmd = (WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_PACKET_FILTER_ENABLE_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + if (enable) + cmd->enable = PACKET_FILTER_SET_ENABLE; + else + cmd->enable = PACKET_FILTER_SET_DISABLE; + + WMA_LOGE("%s: Packet filter enable %d for vdev_id %d", + __func__, cmd->enable, vdev_id); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PACKET_FILTER_ENABLE_CMDID); + if (ret) + WMA_LOGE("Failed to send packet filter wmi cmd to fw"); + + return ret; +} + +/** + * wma_config_packet_filter() - configure packet filter in target + * @wma: Pointer to wma handle + * @vdev_id: vdev id + * @rcv_filter_param: Packet filter parameters + * @filter_id: Filter id + * @enable: Flag to add/delete packet filter configuration + * + * Return: 0 for success or error code + */ +static int wma_config_packet_filter(tp_wma_handle wma, + uint8_t vdev_id, tSirRcvPktFilterCfgType *rcv_filter_param, + uint8_t filter_id, bool enable) +{ + int len, i; + int err = 0; + wmi_buf_t buf; + WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *cmd; + + + /* allocate the memory */ + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set_param cmd"); + return -ENOMEM; + } + + cmd = (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->filter_id = filter_id; + if (enable) + cmd->filter_action = PACKET_FILTER_SET_ACTIVE; + else + cmd->filter_action = PACKET_FILTER_SET_INACTIVE; + + if (enable) { + cmd->num_params = CDF_MIN( + WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER, + rcv_filter_param->numFieldParams); + cmd->filter_type = rcv_filter_param->filterType; + cmd->coalesce_time = rcv_filter_param->coalesceTime; + + for (i = 0; i < cmd->num_params; i++) { + cmd->paramsData[i].proto_type = + rcv_filter_param->paramsData[i].protocolLayer; + cmd->paramsData[i].cmp_type = + rcv_filter_param->paramsData[i].cmpFlag; + cmd->paramsData[i].data_length = + rcv_filter_param->paramsData[i].dataLength; + cmd->paramsData[i].data_offset = + rcv_filter_param->paramsData[i].dataOffset; + memcpy(&cmd->paramsData[i].compareData, + rcv_filter_param->paramsData[i].compareData, + sizeof(cmd->paramsData[i].compareData)); + memcpy(&cmd->paramsData[i].dataMask, + rcv_filter_param->paramsData[i].dataMask, + sizeof(cmd->paramsData[i].dataMask)); + } + } + + WMA_LOGE("Packet filter action %d filter with id: %d, num_params=%d", + cmd->filter_action, cmd->filter_id, cmd->num_params); + /* send the command along with data */ + err = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PACKET_FILTER_CONFIG_CMDID); + if (err) { + WMA_LOGE("Failed to send pkt_filter cmd"); + wmi_buf_free(buf); + return -EIO; + } + + /* Enable packet filter */ + if (enable) + wma_enable_disable_packet_filter(wma, vdev_id, true); + + return 0; +} + +/** + * wma_process_receive_filter_set_filter_req() - enable packet filter + * @wma_handle: wma handle + * @rcv_filter_param: filter params + * + * Return: 0 for success or error code + */ +int wma_process_receive_filter_set_filter_req(tp_wma_handle wma, + tSirRcvPktFilterCfgType *rcv_filter_param) +{ + int ret = 0; + uint8_t vdev_id; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, rcv_filter_param->bssId, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + rcv_filter_param->bssId); + return -EINVAL; + } + + ret = wma_config_packet_filter(wma, vdev_id, rcv_filter_param, + rcv_filter_param->filterId, true); + + return ret; +} + +/** + * wma_process_receive_filter_clear_filter_req() - disable packet filter + * @wma_handle: wma handle + * @rcv_clear_param: filter params + * + * Return: 0 for success or error code + */ +int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma, + tSirRcvFltPktClearParam *rcv_clear_param) +{ + int ret = 0; + uint8_t vdev_id; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, rcv_clear_param->bssId, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", rcv_clear_param->bssId); + return -EINVAL; + } + + ret = wma_config_packet_filter(wma, vdev_id, NULL, + rcv_clear_param->filterId, false); + + return ret; +} + +#ifdef FEATURE_WLAN_ESE + +#define TSM_DELAY_HISTROGRAM_BINS 4 +/** + * wma_process_tsm_stats_req() - process tsm stats request + * @wma_handler - handle to wma + * @pTsmStatsMsg - TSM stats struct that needs to be populated and + * passed in message. + * + * A parallel function to WMA_ProcessTsmStatsReq for pronto. This + * function fetches stats from data path APIs and post + * WMA_TSM_STATS_RSP msg back to LIM. + * + * Return: CDF status + */ +CDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg) +{ + uint8_t counter; + uint32_t queue_delay_microsec = 0; + uint32_t tx_delay_microsec = 0; + uint16_t packet_count = 0; + uint16_t packet_loss_count = 0; + tpAniTrafStrmMetrics pTsmMetric = NULL; +#ifdef FEATURE_WLAN_ESE_UPLOAD + tpAniGetTsmStatsReq pStats = (tpAniGetTsmStatsReq) pTsmStatsMsg; + tpAniGetTsmStatsRsp pTsmRspParams = NULL; +#else + tpTSMStats pStats = (tpTSMStats) pTsmStatsMsg; +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + int tid = pStats->tid; + /* + * The number of histrogram bin report by data path api are different + * than required by TSM, hence different (6) size array used + */ + uint16_t bin_values[QCA_TX_DELAY_HIST_REPORT_BINS] = { 0, }; + + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + cdf_mem_free(pTsmStatsMsg); + return CDF_STATUS_E_INVAL; + } + + /* get required values from data path APIs */ + ol_tx_delay(pdev, &queue_delay_microsec, &tx_delay_microsec, tid); + ol_tx_delay_hist(pdev, bin_values, tid); + ol_tx_packet_count(pdev, &packet_count, &packet_loss_count, tid); + +#ifdef FEATURE_WLAN_ESE_UPLOAD + pTsmRspParams = + (tpAniGetTsmStatsRsp) cdf_mem_malloc(sizeof(tAniGetTsmStatsRsp)); + if (NULL == pTsmRspParams) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "%s: CDF MEM Alloc Failure", __func__); + CDF_ASSERT(0); + cdf_mem_free(pTsmStatsMsg); + return CDF_STATUS_E_NOMEM; + } + pTsmRspParams->staId = pStats->staId; + pTsmRspParams->rc = eSIR_FAILURE; + pTsmRspParams->tsmStatsReq = pStats; + pTsmMetric = &pTsmRspParams->tsmMetrics; +#else + pTsmMetric = (tpAniTrafStrmMetrics)&(pStats->tsmMetrics); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + /* populate pTsmMetric */ + pTsmMetric->UplinkPktQueueDly = queue_delay_microsec; + /* store only required number of bin values */ + for (counter = 0; counter < TSM_DELAY_HISTROGRAM_BINS; counter++) { + pTsmMetric->UplinkPktQueueDlyHist[counter] = + bin_values[counter]; + } + pTsmMetric->UplinkPktTxDly = tx_delay_microsec; + pTsmMetric->UplinkPktLoss = packet_loss_count; + pTsmMetric->UplinkPktCount = packet_count; + + /* + * No need to populate roaming delay and roaming count as they are + * being populated just before sending IAPP frame out + */ + /* post this message to LIM/PE */ +#ifdef FEATURE_WLAN_ESE_UPLOAD + wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmRspParams, 0); +#else + wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmStatsMsg, 0); +#endif /* FEATURE_WLAN_ESE_UPLOAD */ + return CDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * wma_add_clear_mcbc_filter() - set mcast filter command to fw + * @wma_handle: wma handle + * @vdev_id: vdev id + * @multicastAddr: mcast address + * @clearList: clear list flag + * + * Return: 0 for success or error code + */ +static int wma_add_clear_mcbc_filter(tp_wma_handle wma_handle, uint8_t vdev_id, + tSirMacAddr multicastAddr, bool clearList) +{ + WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set_param cmd"); + return -ENOMEM; + } + + cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf); + cdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param)); + cmd->action = + (clearList ? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET); + cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(multicastAddr, &cmd->mcastbdcastaddr); + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), + WMI_SET_MCASTBCAST_FILTER_CMDID); + if (err) { + WMA_LOGE("Failed to send set_param cmd"); + cdf_mem_free(buf); + return -EIO; + } + WMA_LOGD("Action:%d; vdev_id:%d; clearList:%d\n", + cmd->action, vdev_id, clearList); + WMA_LOGD("MCBC MAC Addr: %0x:%0x:%0x:%0x:%0x:%0x\n", + multicastAddr[0], multicastAddr[1], multicastAddr[2], + multicastAddr[3], multicastAddr[4], multicastAddr[5]); + return 0; +} + +/** + * wma_process_mcbc_set_filter_req() - process mcbc set filter request + * @wma_handle: wma handle + * @mcbc_param: mcbc params + * + * Return: CDF status + */ +CDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList * mcbc_param) +{ + uint8_t vdev_id = 0; + int i; + + if (mcbc_param->ulMulticastAddrCnt <= 0) { + WMA_LOGE("Number of multicast addresses is 0"); + return CDF_STATUS_E_FAILURE; + } + + if (!wma_find_vdev_by_addr + (wma_handle, mcbc_param->selfMacAddr, &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + mcbc_param->bssId); + return CDF_STATUS_E_FAILURE; + } + /* set mcbc_param->action to clear MCList and reset + * to configure the MCList in FW + */ + + for (i = 0; i < mcbc_param->ulMulticastAddrCnt; i++) { + wma_add_clear_mcbc_filter(wma_handle, vdev_id, + mcbc_param->multicastAddr[i], + (mcbc_param->action == 0)); + } + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define GTK_OFFLOAD_ENABLE 0 +#define GTK_OFFLOAD_DISABLE 1 + +/** + * wma_gtk_offload_status_event() - GTK offload status event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_gtk_offload_status_event(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *status; + WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf; + tpSirGtkOffloadGetInfoRspParams resp; + cds_msg_t cds_msg; + uint8_t *bssid; + + WMA_LOGD("%s Enter", __func__); + + param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("param_buf is NULL"); + return -EINVAL; + } + + status = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *) param_buf->fixed_param; + + if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) { + WMA_LOGE("Invalid length for GTK status"); + return -EINVAL; + } + bssid = wma_find_bssid_by_vdev_id(wma, status->vdev_id); + if (!bssid) { + WMA_LOGE("invalid bssid for vdev id %d", status->vdev_id); + return -ENOENT; + } + + resp = cdf_mem_malloc(sizeof(*resp)); + if (!resp) { + WMA_LOGE("%s: Failed to alloc response", __func__); + return -ENOMEM; + } + cdf_mem_zero(resp, sizeof(*resp)); + resp->mesgType = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP; + resp->mesgLen = sizeof(*resp); + resp->ulStatus = CDF_STATUS_SUCCESS; + resp->ulTotalRekeyCount = status->refresh_cnt; + /* TODO: Is the total rekey count and GTK rekey count same? */ + resp->ulGTKRekeyCount = status->refresh_cnt; + + cdf_mem_copy(&resp->ullKeyReplayCounter, &status->replay_counter, + GTK_REPLAY_COUNTER_BYTES); + + cdf_mem_copy(resp->bssId, bssid, IEEE80211_ADDR_LEN); + +#ifdef IGTK_OFFLOAD + /* TODO: Is the refresh count same for GTK and IGTK? */ + resp->ulIGTKRekeyCount = status->refresh_cnt; +#endif /* IGTK_OFFLOAD */ + + cds_msg.type = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP; + cds_msg.bodyptr = (void *)resp; + cds_msg.bodyval = 0; + + if (cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg) + != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post GTK response to SME"); + cdf_mem_free(resp); + return -EINVAL; + } + + WMA_LOGD("GTK: got target status with replay counter " + "%02x%02x%02x%02x%02x%02x%02x%02x. vdev %d " + "Refresh GTK %d times exchanges since last set operation", + status->replay_counter[0], + status->replay_counter[1], + status->replay_counter[2], + status->replay_counter[3], + status->replay_counter[4], + status->replay_counter[5], + status->replay_counter[6], + status->replay_counter[7], + status->vdev_id, status->refresh_cnt); + + WMA_LOGD("%s Exit", __func__); + + return 0; +} + +/** + * wma_send_gtk_offload_req() - send GTK offload command to fw + * @wma: wma handle + * @vdev_id: vdev id + * @params: GTK offload parameters + * + * Return: CDF status + */ +static CDF_STATUS wma_send_gtk_offload_req(tp_wma_handle wma, uint8_t vdev_id, + tpSirGtkOffloadParams params) +{ + int len; + wmi_buf_t buf; + WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + WMA_LOGD("%s Enter", __func__); + + len = sizeof(*cmd); + + /* alloc wmi buffer */ + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD"); + status = CDF_STATUS_E_NOMEM; + goto out; + } + + cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_GTK_OFFLOAD_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + + /* Request target to enable GTK offload */ + if (params->ulFlags == GTK_OFFLOAD_ENABLE) { + cmd->flags = GTK_OFFLOAD_ENABLE_OPCODE; + wma->wow.gtk_err_enable[vdev_id] = true; + + /* Copy the keys and replay counter */ + cdf_mem_copy(cmd->KCK, params->aKCK, GTK_OFFLOAD_KCK_BYTES); + cdf_mem_copy(cmd->KEK, params->aKEK, GTK_OFFLOAD_KEK_BYTES); + cdf_mem_copy(cmd->replay_counter, ¶ms->ullKeyReplayCounter, + GTK_REPLAY_COUNTER_BYTES); + } else { + wma->wow.gtk_err_enable[vdev_id] = false; + cmd->flags = GTK_OFFLOAD_DISABLE_OPCODE; + } + + /* send the wmi command */ + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_GTK_OFFLOAD_CMDID)) { + WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID"); + wmi_buf_free(buf); + status = CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("VDEVID: %d, GTK_FLAGS: x%x", vdev_id, cmd->flags); +out: + WMA_LOGD("%s Exit", __func__); + return status; +} + +/** + * wma_process_gtk_offload_req() - process GTK offload req from umac + * @handle: wma handle + * @params: GTK offload params + * + * Return: CDF status + */ +CDF_STATUS wma_process_gtk_offload_req(tp_wma_handle wma, + tpSirGtkOffloadParams params) +{ + uint8_t vdev_id; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + WMA_LOGD("%s Enter", __func__); + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", params->bssId); + status = CDF_STATUS_E_INVAL; + goto out; + } + + /* Validate vdev id */ + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("invalid vdev_id %d for %pM", vdev_id, params->bssId); + status = CDF_STATUS_E_INVAL; + goto out; + } + + if ((params->ulFlags == GTK_OFFLOAD_ENABLE) && + (wma->wow.gtk_err_enable[vdev_id] == true)) { + WMA_LOGE("%s GTK Offload already enabled. Disable it first " + "vdev_id %d", __func__, vdev_id); + params->ulFlags = GTK_OFFLOAD_DISABLE; + status = wma_send_gtk_offload_req(wma, vdev_id, params); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s Failed to disable GTK Offload", __func__); + goto out; + } + WMA_LOGD("%s Enable GTK Offload again with updated inputs", + __func__); + params->ulFlags = GTK_OFFLOAD_ENABLE; + } + status = wma_send_gtk_offload_req(wma, vdev_id, params); +out: + cdf_mem_free(params); + WMA_LOGD("%s Exit", __func__); + return status; +} + +/** + * wma_process_gtk_offload_getinfo_req() - send GTK offload cmd to fw + * @wma: wma handle + * @params: GTK offload params + * + * Return: CDF status + */ +CDF_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma, + tpSirGtkOffloadGetInfoRspParams params) +{ + uint8_t vdev_id; + int len; + wmi_buf_t buf; + WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + WMA_LOGD("%s Enter", __func__); + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, params->bssId, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", params->bssId); + status = CDF_STATUS_E_INVAL; + goto out; + } + + len = sizeof(*cmd); + + /* alloc wmi buffer */ + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD"); + status = CDF_STATUS_E_NOMEM; + goto out; + } + + cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_GTK_OFFLOAD_CMD_fixed_param)); + + /* Request for GTK offload status */ + cmd->flags = GTK_OFFLOAD_REQUEST_STATUS_OPCODE; + cmd->vdev_id = vdev_id; + + /* send the wmi command */ + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_GTK_OFFLOAD_CMDID)) { + WMA_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info"); + wmi_buf_free(buf); + status = CDF_STATUS_E_FAILURE; + } +out: + cdf_mem_free(params); + WMA_LOGD("%s Exit", __func__); + return status; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * wma_enable_arp_ns_offload() - enable ARP NS offload + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @bArpOnly: flag + * + * To configure ARP NS off load data to firmware + * when target goes to wow mode. + * + * Return: CDF Status + */ +CDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, + tpSirHostOffloadReq + pHostOffloadParams, bool bArpOnly) +{ + int32_t i; + int32_t res; + WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd; + WMI_NS_OFFLOAD_TUPLE *ns_tuple; + WMI_ARP_OFFLOAD_TUPLE *arp_tuple; + A_UINT8 *buf_ptr; + wmi_buf_t buf; + int32_t len; + uint8_t vdev_id; + uint32_t count = 0, num_ns_ext_tuples = 0; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, pHostOffloadParams->bssId, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + pHostOffloadParams->bssId); + cdf_mem_free(pHostOffloadParams); + return CDF_STATUS_E_INVAL; + } + + if (!wma->interfaces[vdev_id].vdev_up) { + + WMA_LOGE("vdev %d is not up skipping arp/ns offload", vdev_id); + cdf_mem_free(pHostOffloadParams); + return CDF_STATUS_E_FAILURE; + } + + if (!bArpOnly) + count = pHostOffloadParams->num_ns_offload_count; + + + len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) + WMI_TLV_HDR_SIZE + /* TLV place holder size for array of NS tuples */ + WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE) + WMI_TLV_HDR_SIZE + /* TLV place holder size for array of ARP tuples */ + WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE); + + /* + * If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate + * extra length for extended NS offload tuples which follows ARP offload + * tuples. Host needs to fill this structure in following format: + * 2 NS ofload tuples + * 2 ARP offload tuples + * N numbers of extended NS offload tuples if HDD has given more than + * 2 NS offload addresses + */ + if (!bArpOnly && count > WMI_MAX_NS_OFFLOADS) { + num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS; + len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples * + sizeof(WMI_NS_OFFLOAD_TUPLE); + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + cdf_mem_free(pHostOffloadParams); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (A_UINT8 *) wmi_buf_data(buf); + cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param)); + cmd->flags = 0; + cmd->vdev_id = vdev_id; + if (!bArpOnly) + cmd->num_ns_ext_tuples = num_ns_ext_tuples; + + WMA_LOGD("ARP NS Offload vdev_id: %d", cmd->vdev_id); + + /* Have copy of arp info to send along with NS, Since FW expects + * both ARP and NS info in single cmd */ + if (bArpOnly) + cdf_mem_copy(&wma->mArpInfo, pHostOffloadParams, + sizeof(tSirHostOffloadReq)); + + buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE))); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *) buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE) - + WMI_TLV_HDR_SIZE)); + + /* Fill data only for NS offload in the first ARP tuple for LA */ + if (!bArpOnly && + ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; + +#ifdef WLAN_NS_OFFLOAD + /*Copy the target/solicitation/remote ip addr */ + if (pHostOffloadParams->nsOffloadInfo. + targetIPv6AddrValid[i]) + A_MEMCPY(&ns_tuple->target_ipaddr[0], + &pHostOffloadParams->nsOffloadInfo. + targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + A_MEMCPY(&ns_tuple->solicitation_ipaddr, + &pHostOffloadParams->nsOffloadInfo. + selfIPv6Addr[i], sizeof(WMI_IPV6_ADDR)); + WMA_LOGD("NS solicitedIp: %pI6, targetIp: %pI6", + &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], + &pHostOffloadParams->nsOffloadInfo. + targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, + * if this is not valid, the target will use the known + * local MAC address rather than the tuple + */ + WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams-> + nsOffloadInfo.selfMacAddr, + &ns_tuple->target_mac); +#endif /* WLAN_NS_OFFLOAD */ + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE))); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *) buf_ptr; + WMITLV_SET_HDR(&arp_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, + WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE)); + + /* Fill data for ARP and NS in the first tupple for LA */ + if ((wma->mArpInfo.enableOrDisable & SIR_OFFLOAD_ENABLE) + && (i == 0)) { + /*Copy the target ip addr and flags */ + arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID; + A_MEMCPY(&arp_tuple->target_ipaddr, + wma->mArpInfo.params.hostIpv4Addr, + SIR_IPV4_ADDR_LEN); + WMA_LOGD("ARPOffload IP4 address: %pI4", + wma->mArpInfo.params.hostIpv4Addr); + } + buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE); + } + + /* Populate extended NS offload tuples */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (num_ns_ext_tuples*sizeof(WMI_NS_OFFLOAD_TUPLE))); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (num_ns_ext_tuples) { + for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); + + /* Fill data only for NS offload in the first ARP tuple for LA */ + if (!bArpOnly && + ((pHostOffloadParams->enableOrDisable & SIR_OFFLOAD_ENABLE))) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; +#ifdef WLAN_NS_OFFLOAD + /*Copy the target/solicitation/remote ip addr */ + if (pHostOffloadParams->nsOffloadInfo.targetIPv6AddrValid[i]) + A_MEMCPY(&ns_tuple->target_ipaddr[0], + &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + A_MEMCPY(&ns_tuple->solicitation_ipaddr, + &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + WMA_LOGD("Index %d NS solicitedIp: %pI6, targetIp: %pI6", i, + &pHostOffloadParams->nsOffloadInfo.selfIPv6Addr[i], + &pHostOffloadParams->nsOffloadInfo.targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, if this is not valid, + * the target will use the known local MAC address rather than the tuple */ + WMI_CHAR_ARRAY_TO_MAC_ADDR(pHostOffloadParams->nsOffloadInfo.selfMacAddr, + &ns_tuple->target_mac); +#endif + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } + } + + res = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_SET_ARP_NS_OFFLOAD_CMDID); + if (res) { + WMA_LOGE("Failed to enable ARP NDP/NSffload"); + wmi_buf_free(buf); + cdf_mem_free(pHostOffloadParams); + return CDF_STATUS_E_FAILURE; + } + + cdf_mem_free(pHostOffloadParams); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_add_periodic_tx_ptrn_ind - add periodic tx ptrn + * @handle: wma handle + * @pAddPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: CDF status + */ +CDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t vdev_id; + uint8_t *buf_ptr; + uint32_t ptrn_len, ptrn_len_aligned; + int j; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw add pattern cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + ptrn_len = pAddPeriodicTxPtrnParams->ucPtrnSize; + ptrn_len_aligned = roundup(ptrn_len, sizeof(uint32_t)); + len = sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + ptrn_len_aligned; + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + if (!wma_find_vdev_by_addr(wma_handle, + pAddPeriodicTxPtrnParams->macAddress, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pAddPeriodicTxPtrnParams->macAddress); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_INVAL; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param)); + + /* Pass the pattern id to delete for the corresponding vdev id */ + cmd->vdev_id = vdev_id; + cmd->pattern_id = pAddPeriodicTxPtrnParams->ucPtrnId; + cmd->timeout = pAddPeriodicTxPtrnParams->usPtrnIntervalMs; + cmd->length = pAddPeriodicTxPtrnParams->ucPtrnSize; + + /* Pattern info */ + buf_ptr += sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ptrn_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, pAddPeriodicTxPtrnParams->ucPattern, ptrn_len); + for (j = 0; j < pAddPeriodicTxPtrnParams->ucPtrnSize; j++) { + WMA_LOGD("%s: Add Ptrn: %02x", __func__, buf_ptr[j] & 0xff); + } + WMA_LOGD("%s: Add ptrn id: %d vdev_id: %d", + __func__, cmd->pattern_id, cmd->vdev_id); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID)) { + WMA_LOGE("%s: failed to add pattern set state command", + __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_del_periodic_tx_ptrn_ind - del periodic tx ptrn + * @handle: wma handle + * @pDelPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: CDF status + */ +CDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t vdev_id; + uint32_t len = + sizeof(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param); + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue Del Pattern cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + if (!wma_find_vdev_by_addr(wma_handle, + pDelPeriodicTxPtrnParams->macAddress, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pDelPeriodicTxPtrnParams->macAddress); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_INVAL; + } + cmd = (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *) + wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param)); + + /* Pass the pattern id to delete for the corresponding vdev id */ + cmd->vdev_id = vdev_id; + cmd->pattern_id = pDelPeriodicTxPtrnParams->ucPtrnId; + WMA_LOGD("%s: Del ptrn id: %d vdev_id: %d", + __func__, cmd->pattern_id, cmd->vdev_id); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID)) { + WMA_LOGE("%s: failed to send del pattern command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_req() - request ext stats from fw + * @wma_ptr: wma handle + * @preq: stats ext params + * + * Return: CDF status + */ +CDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + wmi_req_stats_ext_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + preq->request_data_len; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_req_stats_ext_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_req_stats_ext_cmd_fixed_param)); + cmd->vdev_id = preq->vdev_id; + cmd->data_len = preq->request_data_len; + + WMA_LOGD("%s: The data len value is %u and vdev id set is %u ", + __func__, preq->request_data_len, preq->vdev_id); + + buf_ptr += sizeof(wmi_req_stats_ext_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, cmd->data_len); + + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, preq->request_data, cmd->data_len); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_REQUEST_STATS_EXT_CMDID); + if (ret != EOK) { + WMA_LOGE("%s: Failed to send notify cmd ret = %d", __func__, + ret); + wmi_buf_free(buf); + } + + return ret; +} + +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * wma_send_status_of_ext_wow() - send ext wow status to SME + * @wma: wma handle + * @status: status + * + * Return: none + */ +static void wma_send_status_of_ext_wow(tp_wma_handle wma, bool status) +{ + tSirReadyToExtWoWInd *ready_to_extwow; + CDF_STATUS vstatus; + cds_msg_t cds_msg; + uint8_t len; + + WMA_LOGD("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToExtWoWInd); + ready_to_extwow = (tSirReadyToExtWoWInd *) cdf_mem_malloc(len); + + if (NULL == ready_to_extwow) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND; + ready_to_extwow->mesgLen = len; + ready_to_extwow->status = status; + + cds_msg.type = eWNI_SME_READY_TO_EXTWOW_IND; + cds_msg.bodyptr = (void *)ready_to_extwow; + cds_msg.bodyval = 0; + + vstatus = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (vstatus != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post ready to suspend"); + cdf_mem_free(ready_to_extwow); + } +} + +/** + * wma_enable_ext_wow() - enable ext wow in fw + * @wma: wma handle + * @params: ext wow params + * + * Return:0 for success or error code + */ +int wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params) +{ + wmi_extwow_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_enable_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_enable_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->type = params->type; + cmd->wakeup_pin_num = params->wakeup_pin_num; + + WMA_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x", + __func__, cmd->vdev_id, cmd->type, cmd->wakeup_pin_num); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_EXTWOW_ENABLE_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to set EXTWOW Enable", __func__); + wmi_buf_free(buf); + wma_send_status_of_ext_wow(wma, false); + return CDF_STATUS_E_FAILURE; + } + + wma_send_status_of_ext_wow(wma, true); + return CDF_STATUS_SUCCESS; + +} + +/** + * wma_set_app_type1_params_in_fw() - set app type1 params in fw + * @wma: wma handle + * @appType1Params: app type1 params + * + * Return: CDF status + */ +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params) +{ + wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_set_app_type1_params_cmd_fixed_param)); + + cmd->vdev_id = appType1Params->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(appType1Params->wakee_mac_addr, + &cmd->wakee_mac); + cdf_mem_copy(cmd->ident, appType1Params->identification_id, 8); + cmd->ident_len = appType1Params->id_length; + cdf_mem_copy(cmd->passwd, appType1Params->password, 16); + cmd->passwd_len = appType1Params->pass_length; + + WMA_LOGD("%s: vdev_id %d wakee_mac_addr %pM " + "identification_id %.8s id_length %u " + "password %.16s pass_length %u", + __func__, cmd->vdev_id, appType1Params->wakee_mac_addr, + cmd->ident, cmd->ident_len, cmd->passwd, cmd->passwd_len); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_app_type2_params_in_fw() - set app type2 params in fw + * @wma: wma handle + * @appType2Params: app type2 params + * + * Return: CDF status + */ +int wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params) +{ + wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_set_app_type2_params_cmd_fixed_param)); + + cmd->vdev_id = appType2Params->vdev_id; + + cdf_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16); + cmd->rc4_key_len = appType2Params->rc4_key_len; + + cmd->ip_id = appType2Params->ip_id; + cmd->ip_device_ip = appType2Params->ip_device_ip; + cmd->ip_server_ip = appType2Params->ip_server_ip; + + cmd->tcp_src_port = appType2Params->tcp_src_port; + cmd->tcp_dst_port = appType2Params->tcp_dst_port; + cmd->tcp_seq = appType2Params->tcp_seq; + cmd->tcp_ack_seq = appType2Params->tcp_ack_seq; + + cmd->keepalive_init = appType2Params->keepalive_init; + cmd->keepalive_min = appType2Params->keepalive_min; + cmd->keepalive_max = appType2Params->keepalive_max; + cmd->keepalive_inc = appType2Params->keepalive_inc; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac, + &cmd->gateway_mac); + cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; + cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; + + WMA_LOGD("%s: vdev_id %d gateway_mac %pM " + "rc4_key %.16s rc4_key_len %u " + "ip_id %x ip_device_ip %x ip_server_ip %x " + "tcp_src_port %u tcp_dst_port %u tcp_seq %u " + "tcp_ack_seq %u keepalive_init %u keepalive_min %u " + "keepalive_max %u keepalive_inc %u " + "tcp_tx_timeout_val %u tcp_rx_timeout_val %u", + __func__, cmd->vdev_id, appType2Params->gateway_mac, + cmd->rc4_key, cmd->rc4_key_len, + cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip, + cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq, + cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min, + cmd->keepalive_max, cmd->keepalive_inc, + cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; + +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_auto_shutdown_event_handler() - process auto shutdown timer trigger + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt; + WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf = + (WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *) + event; + + if (!param_buf || !param_buf->fixed_param) { + WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + return -EINVAL; + } + + wmi_auto_sh_evt = param_buf->fixed_param; + + if (wmi_auto_sh_evt->shutdown_reason + != WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) { + WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + return -EINVAL; + } + + WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__, + wmi_auto_sh_evt->shutdown_reason); + return wma_post_auto_shutdown_msg(); +} + +/** + * wma_set_auto_shutdown_timer_req() - sets auto shutdown timer in firmware + * @wma: wma handle + * @auto_sh_cmd: auto shutdown timer value + * + * Return: CDF status + */ +CDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + auto_sh_cmd) +{ + int status = 0; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_host_auto_shutdown_cfg_cmd_fixed_param *wmi_auto_sh_cmd; + int len = sizeof(wmi_host_auto_shutdown_cfg_cmd_fixed_param); + + if (auto_sh_cmd == NULL) { + WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Set WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID:TIMER_VAL=%d", + __func__, auto_sh_cmd->timer_val); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + wmi_auto_sh_cmd = + (wmi_host_auto_shutdown_cfg_cmd_fixed_param *) buf_ptr; + wmi_auto_sh_cmd->timer_value = auto_sh_cmd->timer_val; + + WMITLV_SET_HDR(&wmi_auto_sh_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_host_auto_shutdown_cfg_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + if (status != EOK) { + WMA_LOGE("%s: WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID Err %d", + __func__, status); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_req() - to send nan request to target + * @wma: wma_handle + * @nan_req: request data which will be non-null + * + * Return: CDF status + */ +CDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req) +{ + int ret; + tp_wma_handle wma_handle = (tp_wma_handle) wma_ptr; + wmi_nan_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + uint16_t nan_data_len, nan_data_len_aligned; + uint8_t *buf_ptr; + + /* + * <----- cmd ------------><-- WMI_TLV_HDR_SIZE --><--- data ----> + * +------------+----------+-----------------------+--------------+ + * | tlv_header | data_len | WMITLV_TAG_ARRAY_BYTE | nan_req_data | + * +------------+----------+-----------------------+--------------+ + */ + if (!nan_req) { + WMA_LOGE("%s:nan req is not valid", __func__); + return CDF_STATUS_E_FAILURE; + } + nan_data_len = nan_req->request_data_len; + nan_data_len_aligned = roundup(nan_req->request_data_len, + sizeof(uint32_t)); + len += WMI_TLV_HDR_SIZE + nan_data_len_aligned; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_nan_cmd_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nan_cmd_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_nan_cmd_param)); + cmd->data_len = nan_req->request_data_len; + WMA_LOGD("%s: The data len value is %u", + __func__, nan_req->request_data_len); + buf_ptr += sizeof(wmi_nan_cmd_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, nan_data_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, nan_req->request_data, cmd->data_len); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_NAN_CMDID); + if (ret != EOK) { + WMA_LOGE("%s Failed to send set param command ret = %d", + __func__, ret); + wmi_buf_free(buf); + } + return ret; +} +#endif /* WLAN_FEATURE_NAN */ + +#ifdef DHCP_SERVER_OFFLOAD +/** + * wma_process_dhcpserver_offload() - enable DHCP server offload + * @wma_handle: wma handle + * @pDhcpSrvOffloadInfo: DHCP server offload info + * + * Return: 0 for success or error code + */ +int wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo) +{ + wmi_set_dhcp_server_offload_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send " + "set_dhcp_server_offload cmd"); + return -ENOMEM; + } + + cmd = (wmi_set_dhcp_server_offload_cmd_fixed_param *) wmi_buf_data(buf); + cdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_set_dhcp_server_offload_cmd_fixed_param)); + cmd->vdev_id = pDhcpSrvOffloadInfo->vdev_id; + cmd->enable = pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled; + cmd->num_client = pDhcpSrvOffloadInfo->dhcpClientNum; + cmd->srv_ipv4 = pDhcpSrvOffloadInfo->dhcpSrvIP; + cmd->start_lsb = 0; + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), + WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + if (err) { + WMA_LOGE("Failed to send set_dhcp_server_offload cmd"); + wmi_buf_free(buf); + return -EIO; + } + WMA_LOGD("Set dhcp server offload to vdevId %d", + pDhcpSrvOffloadInfo->vdev_id); + return 0; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/** + * wma_set_led_flashing() - set led flashing in fw + * @wma_handle: wma handle + * @flashing: flashing request + * + * Return: CDF status + */ +CDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + tSirLedFlashingReq *flashing) +{ + wmi_set_led_flashing_cmd_fixed_param *cmd; + int status = 0; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len = sizeof(wmi_set_led_flashing_cmd_fixed_param); + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue cmd")); + return CDF_STATUS_E_INVAL; + } + if (!flashing) { + WMA_LOGE(FL("invalid parameter: flashing")); + return CDF_STATUS_E_INVAL; + } + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_set_led_flashing_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_set_led_flashing_cmd_fixed_param)); + cmd->pattern_id = flashing->pattern_id; + cmd->led_x0 = flashing->led_x0; + cmd->led_x1 = flashing->led_x1; + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_SET_LED_FLASHING_CMDID); + if (status != EOK) { + WMA_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD" + " returned Error %d", __func__, status); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * wma_channel_avoid_evt_handler() - process channel to avoid event from FW. + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_channel_avoid_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_avoid_freq_ranges_event_fixed_param *afr_fixed_param; + wmi_avoid_freq_range_desc *afr_desc; + uint32_t num_freq_ranges, freq_range_idx; + tSirChAvoidIndType *sca_indication; + CDF_STATUS cdf_status; + cds_msg_t sme_msg = { 0 }; + WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *param_buf = + (WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *) event; + + if (!param_buf) { + WMA_LOGE("Invalid channel avoid event buffer"); + return -EINVAL; + } + + afr_fixed_param = param_buf->fixed_param; + if (!afr_fixed_param) { + WMA_LOGE("Invalid channel avoid event fixed param buffer"); + return -EINVAL; + } + + num_freq_ranges = + (afr_fixed_param->num_freq_ranges > + SIR_CH_AVOID_MAX_RANGE) ? SIR_CH_AVOID_MAX_RANGE : + afr_fixed_param->num_freq_ranges; + + WMA_LOGD("Channel avoid event received with %d ranges", + num_freq_ranges); + for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; + freq_range_idx++) { + afr_desc = (wmi_avoid_freq_range_desc *) + ((void *)param_buf->avd_freq_range + + freq_range_idx * sizeof(wmi_avoid_freq_range_desc)); + + WMA_LOGD("range %d: tlv id = %u, start freq = %u, end freq = %u", + freq_range_idx, afr_desc->tlv_header, afr_desc->start_freq, + afr_desc->end_freq); + } + + sca_indication = (tSirChAvoidIndType *) + cdf_mem_malloc(sizeof(tSirChAvoidIndType)); + if (!sca_indication) { + WMA_LOGE("Invalid channel avoid indication buffer"); + return -EINVAL; + } + + sca_indication->avoid_range_count = num_freq_ranges; + for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; + freq_range_idx++) { + afr_desc = (wmi_avoid_freq_range_desc *) + ((void *)param_buf->avd_freq_range + + freq_range_idx * sizeof(wmi_avoid_freq_range_desc)); + sca_indication->avoid_freq_range[freq_range_idx].start_freq = + afr_desc->start_freq; + sca_indication->avoid_freq_range[freq_range_idx].end_freq = + afr_desc->end_freq; + } + + sme_msg.type = eWNI_SME_CH_AVOID_IND; + sme_msg.bodyptr = sca_indication; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_CH_AVOID_IND msg to SME"); + cdf_mem_free(sca_indication); + return -EINVAL; + } + + return 0; +} + +/** + * wma_process_ch_avoid_update_req() - handles channel avoid update request + * @wma_handle: wma handle + * @ch_avoid_update_req: channel avoid update params + * + * Return: CDF status + */ +CDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req) +{ + int status = 0; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_chan_avoid_update_cmd_param *ch_avoid_update_fp; + int len = sizeof(wmi_chan_avoid_update_cmd_param); + + if (ch_avoid_update_req == NULL) { + WMA_LOGE("%s : ch_avoid_update_req is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE", __func__); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + ch_avoid_update_fp = (wmi_chan_avoid_update_cmd_param *) buf_ptr; + WMITLV_SET_HDR(&ch_avoid_update_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_chan_avoid_update_cmd_param)); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_CHAN_AVOID_UPDATE_CMDID); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send" + " WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE" + " returned Error %d", status); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI", + __func__); + return CDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * wma_set_reg_domain() - set reg domain + * @clientCtxt: client context + * @regId: reg id + * + * Return: CDF status + */ +CDF_STATUS wma_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId) +{ + if (CDF_STATUS_SUCCESS != + cds_set_reg_domain(clientCtxt, regId)) + return CDF_STATUS_E_INVAL; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_send_regdomain_info_to_fw() - send regdomain info to fw + * @reg_dmn: reg domain + * @regdmn2G: 2G reg domain + * @regdmn5G: 5G reg domain + * @ctl2G: 2G test limit + * @ctl5G: 5G test limit + * + * Return: none + */ +void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G) +{ + wmi_buf_t buf; + wmi_pdev_set_regdomain_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + int32_t cck_mask_val = 0; + int ret = 0; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return; + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_pdev_set_regdomain_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_regdomain_cmd_fixed_param)); + cmd->reg_domain = reg_dmn; + cmd->reg_domain_2G = regdmn2G; + cmd->reg_domain_5G = regdmn5G; + cmd->conformance_test_limit_2G = ctl2G; + cmd->conformance_test_limit_5G = ctl5G; + + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_REGDOMAIN_CMDID)) { + WMA_LOGP("%s: Failed to send pdev set regdomain command", + __func__); + cdf_nbuf_free(buf); + } + + if ((((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_JAPAN) || + ((reg_dmn & ~COUNTRY_ERD_FLAG) == CTRY_KOREA_ROC)) && + (true == wma->tx_chain_mask_cck)) + cck_mask_val = 1; + + cck_mask_val |= (wma->self_gen_frm_pwr << 16); + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK, + cck_mask_val); + if (ret) + WMA_LOGE("failed to set PDEV tx_chain_mask_cck %d", + ret); + + return; +} + +/** + * wma_bus_suspend() - handles bus suspend request from hdd + * + * Calls the appropriate handler based on configuration and event + * + * Return: 0 for success or error code + */ +int wma_bus_suspend(void) +{ + WMA_HANDLE handle = cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == handle) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EFAULT; + } + + WMA_LOGE("%s: wow mode selected %d", __func__, + wma_is_wow_mode_selected(handle)); + + if (wma_check_scan_in_progress(handle)) { + WMA_LOGE("%s: Scan in progress. Aborting suspend", __func__); + return -EBUSY; + } + + if (wma_is_wow_mode_selected(handle)) + return cdf_status_to_os_return(wma_enable_wow_in_fw(handle)); + + return wma_suspend_target(handle, 0); +} + +/** + * wma_bus_resume() - handles bus resume request from hdd + * @handle: valid wma handle + * + * Calls the appropriate handler based on configuration + * + * Return: 0 for success or error code + */ +int wma_bus_resume(void) +{ + WMA_HANDLE handle = cds_get_context(CDF_MODULE_ID_WMA); + int wow_mode; + if (NULL == handle) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EFAULT; + } + + wow_mode = wma_is_wow_mode_selected(handle); + WMA_LOGE("%s: wow mode %d", __func__, wow_mode); + + if (!wow_mode) + return wma_resume_target(handle); + + return cdf_status_to_os_return(wma_disable_wow_in_fw(handle)); +} + +/** + * wma_suspend_target() - suspend target + * @handle: wma handle + * @disable_target_intr: disable target interrupt + * + * Return: 0 for success or error code + */ +int wma_suspend_target(WMA_HANDLE handle, int disable_target_intr) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_pdev_suspend_cmd_fixed_param *cmd; + wmi_buf_t wmibuf; + uint32_t len = sizeof(*cmd); + struct ol_softc *scn; + int ret; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("WMA is closed. can not issue suspend cmd"); + return -EINVAL; + } + /* + * send the comand to Target to ignore the + * PCIE reset so as to ensure that Host and target + * states are in sync + */ + wmibuf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (wmibuf == NULL) + return -ENOMEM; + + cmd = (wmi_pdev_suspend_cmd_fixed_param *) wmi_buf_data(wmibuf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_suspend_cmd_fixed_param)); + if (disable_target_intr) { + cmd->suspend_opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR; + } else { + cmd->suspend_opt = WMI_PDEV_SUSPEND; + } + cdf_event_reset(&wma_handle->target_suspend); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, wmibuf, len, + WMI_PDEV_SUSPEND_CMDID); + if (ret < 0) { + cdf_nbuf_free(wmibuf); + return ret; + } + + wmi_set_target_suspend(wma_handle->wmi_handle, true); + + if (cdf_wait_single_event(&wma_handle->target_suspend, + WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) + != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get ACK from firmware for pdev suspend"); + wmi_set_target_suspend(wma_handle->wmi_handle, false); + return -EFAULT; + } + + scn = cds_get_context(CDF_MODULE_ID_HIF); + + if (scn == NULL) { + WMA_LOGE("%s: Failed to get HIF context", __func__); + CDF_ASSERT(0); + return -EFAULT; + } + + htc_cancel_deferred_target_sleep(scn); + + return 0; +} + +/** + * wma_target_suspend_acknowledge() - update target susspend status + * @context: wma context + * + * Return: none + */ +void wma_target_suspend_acknowledge(void *context) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + int wow_nack = *((int *)context); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + wma->wow_nack = wow_nack; + cdf_event_set(&wma->target_suspend); + if (wow_nack) + cdf_wake_lock_timeout_acquire(&wma->wow_wake_lock, + WMA_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_WOW); +} + +/** + * wma_resume_target() - resume target + * @handle: wma handle + * + * Return: 0 for success or error code + */ +int wma_resume_target(WMA_HANDLE handle) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_buf_t wmibuf; + wmi_pdev_resume_cmd_fixed_param *cmd; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; +#ifdef CONFIG_CNSS + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return -EINVAL; + } +#endif /* CONFIG_CNSS */ + + wmibuf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); + if (wmibuf == NULL) { + return -ENOMEM; + } + cmd = (wmi_pdev_resume_cmd_fixed_param *) wmi_buf_data(wmibuf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_resume_cmd_fixed_param)); + cmd->reserved0 = 0; + cdf_event_reset(&wma->wma_resume_event); + ret = wmi_unified_cmd_send(wma->wmi_handle, wmibuf, sizeof(*cmd), + WMI_PDEV_RESUME_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command"); + wmi_buf_free(wmibuf); + } + + cdf_status = cdf_wait_single_event(&(wma->wma_resume_event), + WMA_RESUME_TIMEOUT); + if (CDF_STATUS_SUCCESS != cdf_status) { + WMA_LOGP("%s: Timeout waiting for resume event from FW", + __func__); + WMA_LOGP("%s: Pending commands %d credits %d", __func__, + wmi_get_pending_cmds(wma->wmi_handle), + wmi_get_host_credits(wma->wmi_handle)); + if (!cds_is_logp_in_progress()) { +#ifdef CONFIG_CNSS + if (pMac->sme.enableSelfRecovery) { + cds_trigger_recovery(); + } else { + CDF_BUG(0); + } +#else + CDF_BUG(0); +#endif /* CONFIG_CNSS */ + } else { + WMA_LOGE("%s: SSR in progress, ignore resume timeout", + __func__); + } + } else { + WMA_LOGD("Host wakeup received"); + } + + if (CDF_STATUS_SUCCESS == cdf_status) + wmi_set_target_suspend(wma->wmi_handle, false); + + return ret; +} + +/** + * wma_get_modeselect() - get modeSelect flag based on phy_capability + * @wma: wma handle + * @modeSelect: mode Select + * + * Return: none + */ +void wma_get_modeselect(tp_wma_handle wma, uint32_t *modeSelect) +{ + + switch (wma->phy_capability) { + case WMI_11G_CAPABILITY: + case WMI_11NG_CAPABILITY: + *modeSelect &= ~(REGDMN_MODE_11A | REGDMN_MODE_TURBO | + REGDMN_MODE_108A | REGDMN_MODE_11A_HALF_RATE | + REGDMN_MODE_11A_QUARTER_RATE | + REGDMN_MODE_11NA_HT20 | + REGDMN_MODE_11NA_HT40PLUS | + REGDMN_MODE_11NA_HT40MINUS | + REGDMN_MODE_11AC_VHT20 | + REGDMN_MODE_11AC_VHT40PLUS | + REGDMN_MODE_11AC_VHT40MINUS | + REGDMN_MODE_11AC_VHT80); + break; + case WMI_11A_CAPABILITY: + case WMI_11NA_CAPABILITY: + case WMI_11AC_CAPABILITY: + *modeSelect &= ~(REGDMN_MODE_11B | REGDMN_MODE_11G | + REGDMN_MODE_108G | REGDMN_MODE_11NG_HT20 | + REGDMN_MODE_11NG_HT40PLUS | + REGDMN_MODE_11NG_HT40MINUS | + REGDMN_MODE_11AC_VHT20_2G | + REGDMN_MODE_11AC_VHT40_2G | + REGDMN_MODE_11AC_VHT80_2G); + break; + } +} + + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_tdls_event_handler() - handle TDLS event + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TDLS_PEER_EVENTID_param_tlvs *param_buf = NULL; + wmi_tdls_peer_event_fixed_param *peer_event = NULL; + tSirTdlsEventnotify *tdls_event; + + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_TDLS_PEER_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + peer_event = param_buf->fixed_param; + if (!peer_event) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + + tdls_event = (tSirTdlsEventnotify *) + cdf_mem_malloc(sizeof(*tdls_event)); + if (!tdls_event) { + WMA_LOGE("%s: failed to allocate memory for tdls_event", + __func__); + return -ENOMEM; + } + + tdls_event->sessionId = peer_event->vdev_id; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_event->peer_macaddr, + tdls_event->peerMac); + + switch (peer_event->peer_status) { + case WMI_TDLS_SHOULD_DISCOVER: + tdls_event->messageType = WMA_TDLS_SHOULD_DISCOVER_CMD; + break; + case WMI_TDLS_SHOULD_TEARDOWN: + tdls_event->messageType = WMA_TDLS_SHOULD_TEARDOWN_CMD; + break; + case WMI_TDLS_PEER_DISCONNECTED: + tdls_event->messageType = WMA_TDLS_PEER_DISCONNECTED_CMD; + break; + default: + WMA_LOGE("%s: Discarding unknown tdls event(%d) from target", + __func__, peer_event->peer_status); + return -EINVAL; + } + + switch (peer_event->peer_reason) { + case WMI_TDLS_TEARDOWN_REASON_TX: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_TX; + break; + case WMI_TDLS_TEARDOWN_REASON_RSSI: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_RSSI; + break; + case WMI_TDLS_TEARDOWN_REASON_SCAN: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_SCAN; + break; + case WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE: + tdls_event->peer_reason = + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE; + break; + case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT; + break; + case WMI_TDLS_TEARDOWN_REASON_BAD_PTR: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_BAD_PTR; + break; + case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE; + break; + default: + WMA_LOGE("%s: unknown reason(%d) in tdls event(%d) from target", + __func__, peer_event->peer_reason, + peer_event->peer_status); + return -EINVAL; + } + + WMA_LOGD("%s: sending msg to umac, messageType: 0x%x, " + "for peer: %pM, reason: %d, smesessionId: %d", + __func__, tdls_event->messageType, tdls_event->peerMac, + tdls_event->peer_reason, tdls_event->sessionId); + + wma_send_msg(wma, tdls_event->messageType, (void *)tdls_event, 0); + return 0; +} + +/** + * wma_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; Negative errno otherwise + */ +int wma_set_tdls_offchan_mode(WMA_HANDLE handle, + tdls_chan_switch_params *chan_switch_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_tdls_set_offchan_mode_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + u_int16_t len = sizeof(wmi_tdls_set_offchan_mode_cmd_fixed_param); + int ret = 0; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL( + "WMA is closed, can not issue tdls off channel cmd" + )); + ret = -EINVAL; + goto end; + } + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + ret = -ENOMEM; + goto end; + } + cmd = (wmi_tdls_set_offchan_mode_cmd_fixed_param *) + wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_tdls_set_offchan_mode_cmd_fixed_param)); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(chan_switch_params->peer_mac_addr, + &cmd->peer_macaddr); + cmd->vdev_id = chan_switch_params->vdev_id; + cmd->offchan_mode = chan_switch_params->tdls_sw_mode; + cmd->is_peer_responder = chan_switch_params->is_responder; + cmd->offchan_num = chan_switch_params->tdls_off_ch; + cmd->offchan_bw_bitmap = chan_switch_params->tdls_off_ch_bw_offset; + cmd->offchan_oper_class = chan_switch_params->oper_class; + + WMA_LOGD(FL("Peer MAC Addr mac_addr31to0: 0x%x, mac_addr47to32: 0x%x"), + cmd->peer_macaddr.mac_addr31to0, + cmd->peer_macaddr.mac_addr47to32); + + WMA_LOGD(FL( + "vdev_id: %d, off channel mode: %d, off channel Num: %d, off channel offset: 0x%x, is_peer_responder: %d, operating class: %d" + ), + cmd->vdev_id, + cmd->offchan_mode, + cmd->offchan_num, + cmd->offchan_bw_bitmap, + cmd->is_peer_responder, + cmd->offchan_oper_class); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_TDLS_SET_OFFCHAN_MODE_CMDID)) { + WMA_LOGP(FL("failed to send tdls off chan command")); + cdf_nbuf_free(wmi_buf); + ret = -EIO; + } + +end: + if (chan_switch_params) + cdf_mem_free(chan_switch_params); + return ret; +} + +/** + * wma_update_fw_tdls_state() - send enable/disable tdls for a vdev + * @wma: wma handle + * @pwmaTdlsparams: TDLS params + * + * Return: 0 for sucess or error code + */ +int wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_tdls_set_state_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + t_wma_tdls_mode tdls_mode; + t_wma_tdls_params *wma_tdls = (t_wma_tdls_params *) pwmaTdlsparams; + uint16_t len = sizeof(wmi_tdls_set_state_cmd_fixed_param); + int ret = 0; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw tdls state cmd", + __func__); + ret = -EINVAL; + goto end_fw_tdls_state; + } + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmai_buf_alloc failed", __func__); + ret = ENOMEM; + goto end_fw_tdls_state; + } + tdls_mode = wma_tdls->tdls_state; + cmd = (wmi_tdls_set_state_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_tdls_set_state_cmd_fixed_param)); + cmd->vdev_id = wma_tdls->vdev_id; + + if (WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode) { + cmd->state = WMI_TDLS_ENABLE_PASSIVE; + } else if (WMA_TDLS_SUPPORT_ENABLED == tdls_mode) { + cmd->state = WMI_TDLS_ENABLE_ACTIVE; + } else { + cmd->state = WMI_TDLS_DISABLE; + } + + cmd->notification_interval_ms = wma_tdls->notification_interval_ms; + cmd->tx_discovery_threshold = wma_tdls->tx_discovery_threshold; + cmd->tx_teardown_threshold = wma_tdls->tx_teardown_threshold; + cmd->rssi_teardown_threshold = wma_tdls->rssi_teardown_threshold; + cmd->rssi_delta = wma_tdls->rssi_delta; + cmd->tdls_options = wma_tdls->tdls_options; + cmd->tdls_peer_traffic_ind_window = wma_tdls->peer_traffic_ind_window; + cmd->tdls_peer_traffic_response_timeout_ms = + wma_tdls->peer_traffic_response_timeout; + cmd->tdls_puapsd_mask = wma_tdls->puapsd_mask; + cmd->tdls_puapsd_inactivity_time_ms = wma_tdls->puapsd_inactivity_time; + cmd->tdls_puapsd_rx_frame_threshold = + wma_tdls->puapsd_rx_frame_threshold; + + WMA_LOGD("%s: tdls_mode: %d, state: %d, " + "notification_interval_ms: %d, " + "tx_discovery_threshold: %d, " + "tx_teardown_threshold: %d, " + "rssi_teardown_threshold: %d, " + "rssi_delta: %d, " + "tdls_options: 0x%x, " + "tdls_peer_traffic_ind_window: %d, " + "tdls_peer_traffic_response_timeout: %d, " + "tdls_puapsd_mask: 0x%x, " + "tdls_puapsd_inactivity_time: %d, " + "tdls_puapsd_rx_frame_threshold: %d ", + __func__, tdls_mode, cmd->state, + cmd->notification_interval_ms, + cmd->tx_discovery_threshold, + cmd->tx_teardown_threshold, + cmd->rssi_teardown_threshold, + cmd->rssi_delta, + cmd->tdls_options, + cmd->tdls_peer_traffic_ind_window, + cmd->tdls_peer_traffic_response_timeout_ms, + cmd->tdls_puapsd_mask, + cmd->tdls_puapsd_inactivity_time_ms, + cmd->tdls_puapsd_rx_frame_threshold); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_TDLS_SET_STATE_CMDID)) { + WMA_LOGP("%s: failed to send tdls set state command", __func__); + cdf_nbuf_free(wmi_buf); + ret = -EIO; + goto end_fw_tdls_state; + } + WMA_LOGD("%s: vdev_id %d", __func__, wma_tdls->vdev_id); + +end_fw_tdls_state: + if (pwmaTdlsparams) + cdf_mem_free(pwmaTdlsparams); + return ret; +} + +/** + * wma_update_tdls_peer_state() - update TDLS peer state + * @handle: wma handle + * @peerStateParams: TDLS peer state params + * + * Return: 0 for success or error code + */ +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_tdls_peer_update_cmd_fixed_param *cmd; + wmi_tdls_peer_capabilities *peer_cap; + wmi_channel *chan_info; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t i; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + struct ol_txrx_peer_t *peer; + int32_t len = sizeof(wmi_tdls_peer_update_cmd_fixed_param) + + sizeof(wmi_tdls_peer_capabilities); + int ret = 0; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + ret = -EINVAL; + goto end_tdls_peer_state; + } + + /* peer capability info is valid only when peer state is connected */ + if (WMA_TDLS_PEER_STATE_CONNECTED != peerStateParams->peerState) { + cdf_mem_zero(&peerStateParams->peerCap, + sizeof(tTdlsPeerCapParams)); + } + + len += WMI_TLV_HDR_SIZE + + sizeof(wmi_channel) * peerStateParams->peerCap.peerChanLen; + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + ret = ENOMEM; + goto end_tdls_peer_state; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_tdls_peer_update_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_tdls_peer_update_cmd_fixed_param)); + + cmd->vdev_id = peerStateParams->vdevId; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peerStateParams->peerMacAddr, + &cmd->peer_macaddr); + + switch (peerStateParams->peerState) { + case WMA_TDLS_PEER_STATE_PEERING: + cmd->peer_state = WMI_TDLS_PEER_STATE_PEERING; + break; + case WMA_TDLS_PEER_STATE_CONNECTED: + cmd->peer_state = WMI_TDLS_PEER_STATE_CONNECTED; + break; + case WMA_TDLS_PEER_STATE_TEARDOWN: + cmd->peer_state = WMI_TDLS_PEER_STATE_TEARDOWN; + break; + } + + WMA_LOGD("%s: vdev_id: %d, peerStateParams->peerMacAddr: %pM, " + "peer_macaddr.mac_addr31to0: 0x%x, " + "peer_macaddr.mac_addr47to32: 0x%x, peer_state: %d", + __func__, cmd->vdev_id, peerStateParams->peerMacAddr, + cmd->peer_macaddr.mac_addr31to0, + cmd->peer_macaddr.mac_addr47to32, cmd->peer_state); + + buf_ptr += sizeof(wmi_tdls_peer_update_cmd_fixed_param); + peer_cap = (wmi_tdls_peer_capabilities *) buf_ptr; + WMITLV_SET_HDR(&peer_cap->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, + WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_peer_capabilities)); + + if ((peerStateParams->peerCap.peerUapsdQueue & 0x08) >> 3) + WMI_SET_TDLS_PEER_VO_UAPSD(peer_cap); + if ((peerStateParams->peerCap.peerUapsdQueue & 0x04) >> 2) + WMI_SET_TDLS_PEER_VI_UAPSD(peer_cap); + if ((peerStateParams->peerCap.peerUapsdQueue & 0x02) >> 1) + WMI_SET_TDLS_PEER_BK_UAPSD(peer_cap); + if (peerStateParams->peerCap.peerUapsdQueue & 0x01) + WMI_SET_TDLS_PEER_BE_UAPSD(peer_cap); + + /* Ack and More Data Ack are sent as 0, so no need to set + * but fill SP + */ + WMI_SET_TDLS_PEER_SP_UAPSD(peer_cap, + peerStateParams->peerCap.peerMaxSp); + + peer_cap->buff_sta_support = + peerStateParams->peerCap.peerBuffStaSupport; + peer_cap->off_chan_support = + peerStateParams->peerCap.peerOffChanSupport; + peer_cap->peer_curr_operclass = + peerStateParams->peerCap.peerCurrOperClass; + /* self curr operclass is not being used and so pass op class for + * preferred off chan in it. + */ + peer_cap->self_curr_operclass = + peerStateParams->peerCap.opClassForPrefOffChan; + peer_cap->peer_chan_len = peerStateParams->peerCap.peerChanLen; + peer_cap->peer_operclass_len = + peerStateParams->peerCap.peerOperClassLen; + + WMA_LOGD("%s: peer_operclass_len: %d", + __func__, peer_cap->peer_operclass_len); + for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++) { + peer_cap->peer_operclass[i] = + peerStateParams->peerCap.peerOperClass[i]; + WMA_LOGD("%s: peer_operclass[%d]: %d", + __func__, i, peer_cap->peer_operclass[i]); + } + + peer_cap->is_peer_responder = peerStateParams->peerCap.isPeerResponder; + peer_cap->pref_offchan_num = peerStateParams->peerCap.prefOffChanNum; + peer_cap->pref_offchan_bw = + peerStateParams->peerCap.prefOffChanBandwidth; + + WMA_LOGD + ("%s: peer_qos: 0x%x, buff_sta_support: %d, off_chan_support: %d, peer_curr_operclass: %d, self_curr_operclass: %d, peer_chan_len: %d, peer_operclass_len: %d, is_peer_responder: %d, pref_offchan_num: %d, pref_offchan_bw: %d", + __func__, peer_cap->peer_qos, peer_cap->buff_sta_support, + peer_cap->off_chan_support, peer_cap->peer_curr_operclass, + peer_cap->self_curr_operclass, peer_cap->peer_chan_len, + peer_cap->peer_operclass_len, peer_cap->is_peer_responder, + peer_cap->pref_offchan_num, peer_cap->pref_offchan_bw); + + /* next fill variable size array of peer chan info */ + buf_ptr += sizeof(wmi_tdls_peer_capabilities); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_channel) * + peerStateParams->peerCap.peerChanLen); + chan_info = (wmi_channel *) (buf_ptr + WMI_TLV_HDR_SIZE); + + for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++i) { + WMITLV_SET_HDR(&chan_info->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan_info->mhz = + cds_chan_to_freq(peerStateParams->peerCap.peerChan[i]. + chanId); + chan_info->band_center_freq1 = chan_info->mhz; + chan_info->band_center_freq2 = 0; + + WMA_LOGD("%s: chan[%d] = %u", __func__, i, chan_info->mhz); + + if (peerStateParams->peerCap.peerChan[i].dfsSet) { + WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE); + WMA_LOGI("chan[%d] DFS[%d]\n", + peerStateParams->peerCap.peerChan[i].chanId, + peerStateParams->peerCap.peerChan[i].dfsSet); + } + + if (chan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) { + WMI_SET_CHANNEL_MODE(chan_info, MODE_11G); + } else { + WMI_SET_CHANNEL_MODE(chan_info, MODE_11A); + } + + WMI_SET_CHANNEL_MAX_TX_POWER(chan_info, + peerStateParams->peerCap. + peerChan[i].pwr); + + WMI_SET_CHANNEL_REG_POWER(chan_info, + peerStateParams->peerCap.peerChan[i]. + pwr); + WMA_LOGD("Channel TX power[%d] = %u: %d", i, chan_info->mhz, + peerStateParams->peerCap.peerChan[i].pwr); + + chan_info++; + } + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_TDLS_PEER_UPDATE_CMDID)) { + WMA_LOGE("%s: failed to send tdls peer update state command", + __func__); + cdf_nbuf_free(wmi_buf); + ret = -EIO; + goto end_tdls_peer_state; + } + + /* in case of teardown, remove peer from fw */ + if (WMA_TDLS_PEER_STATE_TEARDOWN == peerStateParams->peerState) { + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + ret = -EIO; + goto end_tdls_peer_state; + } + + peer = ol_txrx_find_peer_by_addr(pdev, + peerStateParams->peerMacAddr, + &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer mac %pM", + __func__, peerStateParams->peerMacAddr); + ret = -EIO; + goto end_tdls_peer_state; + } + + WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR + " vdevId: %d", __func__, + MAC_ADDR_ARRAY(peer->mac_addr.raw), + peerStateParams->vdevId); + wma_remove_peer(wma_handle, peer->mac_addr.raw, + peerStateParams->vdevId, peer, false); + } + +end_tdls_peer_state: + if (peerStateParams) + cdf_mem_free(peerStateParams); + return ret; +} +#endif /* FEATURE_WLAN_TDLS */ + + +/** + * wma_dfs_attach() - Attach DFS methods to the umac state. + * @dfs_ic: ieee80211com ptr + * + * Return: Return ieee80211com ptr with updated info + */ +struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic) +{ + /*Allocate memory for dfs_ic before passing it up to dfs_attach() */ + dfs_ic = (struct ieee80211com *) + os_malloc(NULL, sizeof(struct ieee80211com), GFP_ATOMIC); + if (dfs_ic == NULL) { + WMA_LOGE("%s:Allocation of dfs_ic failed %zu", + __func__, sizeof(struct ieee80211com)); + return NULL; + } + OS_MEMZERO(dfs_ic, sizeof(struct ieee80211com)); + /* DFS pattern matching hooks */ + dfs_ic->ic_dfs_attach = ol_if_dfs_attach; + dfs_ic->ic_dfs_disable = ol_if_dfs_disable; + dfs_ic->ic_find_channel = ieee80211_find_channel; + dfs_ic->ic_dfs_enable = ol_if_dfs_enable; + dfs_ic->ic_ieee2mhz = ieee80211_ieee2mhz; + + /* Hardware facing hooks */ + dfs_ic->ic_get_ext_busy = ol_if_dfs_get_ext_busy; + dfs_ic->ic_get_mib_cycle_counts_pct = + ol_if_dfs_get_mib_cycle_counts_pct; + dfs_ic->ic_get_TSF64 = ol_if_get_tsf64; + + /* NOL related hooks */ + dfs_ic->ic_dfs_usenol = ol_if_dfs_usenol; + /* + * Hooks from wma/dfs/ back + * into the PE/SME + * and shared DFS code + */ + dfs_ic->ic_dfs_notify_radar = ieee80211_mark_dfs; + cdf_mutex_init(&dfs_ic->chan_lock); + /* Initializes DFS Data Structures and queues */ + dfs_attach(dfs_ic); + + return dfs_ic; +} + +/** + * wma_dfs_detach() - Detach DFS methods + * @dfs_ic: ieee80211com ptr + * + * Return: none + */ +void wma_dfs_detach(struct ieee80211com *dfs_ic) +{ + dfs_detach(dfs_ic); + + cdf_mutex_destroy(&dfs_ic->chan_lock); + if (NULL != dfs_ic->ic_curchan) { + OS_FREE(dfs_ic->ic_curchan); + dfs_ic->ic_curchan = NULL; + } + + OS_FREE(dfs_ic); +} + +/** + * wma_dfs_configure() - configure dfs + * @ic: ieee80211com ptr + * + * Configures Radar Filters during + * vdev start/channel change/regulatory domain + * change.This Configuration enables to program + * the DFS pattern matching module. + * + * Return: none + */ +void wma_dfs_configure(struct ieee80211com *ic) +{ + struct ath_dfs_radar_tab_info rinfo; + int dfsdomain; + int radar_enabled_status = 0; + if (ic == NULL) { + WMA_LOGE("%s: DFS ic is Invalid", __func__); + return; + } + + dfsdomain = ic->current_dfs_regdomain; + + /* Fetch current radar patterns from the lmac */ + OS_MEMZERO(&rinfo, sizeof(rinfo)); + + /* + * Look up the current DFS + * regulatory domain and decide + * which radar pulses to use. + */ + switch (dfsdomain) { + case DFS_FCC_DOMAIN: + WMA_LOGI("%s: DFS-FCC domain", __func__); + rinfo.dfsdomain = DFS_FCC_DOMAIN; + rinfo.dfs_radars = dfs_fcc_radars; + rinfo.numradars = CDF_ARRAY_SIZE(dfs_fcc_radars); + rinfo.b5pulses = dfs_fcc_bin5pulses; + rinfo.numb5radars = CDF_ARRAY_SIZE(dfs_fcc_bin5pulses); + break; + case DFS_ETSI_DOMAIN: + WMA_LOGI("%s: DFS-ETSI domain", __func__); + rinfo.dfsdomain = DFS_ETSI_DOMAIN; + rinfo.dfs_radars = dfs_etsi_radars; + rinfo.numradars = CDF_ARRAY_SIZE(dfs_etsi_radars); + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + case DFS_MKK4_DOMAIN: + WMA_LOGI("%s: DFS-MKK4 domain", __func__); + rinfo.dfsdomain = DFS_MKK4_DOMAIN; + rinfo.dfs_radars = dfs_mkk4_radars; + rinfo.numradars = CDF_ARRAY_SIZE(dfs_mkk4_radars); + rinfo.b5pulses = dfs_jpn_bin5pulses; + rinfo.numb5radars = CDF_ARRAY_SIZE(dfs_jpn_bin5pulses); + break; + default: + WMA_LOGI("%s: DFS-UNINT domain", __func__); + rinfo.dfsdomain = DFS_UNINIT_DOMAIN; + rinfo.dfs_radars = NULL; + rinfo.numradars = 0; + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + } + + rinfo.dfs_pri_multiplier = ic->dfs_pri_multiplier; + + /* + * Set the regulatory domain, + * radar pulse table and enable + * radar events if required. + * dfs_radar_enable() returns + * 0 on success and non-zero + * failure. + */ + radar_enabled_status = dfs_radar_enable(ic, &rinfo); + if (radar_enabled_status != DFS_STATUS_SUCCESS) { + WMA_LOGE("%s[%d]: DFS- Radar Detection Enabling Failed", + __func__, __LINE__); + } +} + +/** + * wma_dfs_configure_channel() - configure DFS channel + * @dfs_ic: ieee80211com ptr + * @chan: wmi channel + * @chanmode: channel mode + * @ req: vdev start request + * + * Set the Channel parameters in to DFS module + * Also,configure the DFS radar filters for + * matching the DFS phyerrors. + * + * Return: ieee80211 channel / NULL for error + */ +struct ieee80211_channel *wma_dfs_configure_channel(struct ieee80211com *dfs_ic, + wmi_channel *chan, + WLAN_PHY_MODE chanmode, + struct wma_vdev_start_req + *req) +{ + if (dfs_ic == NULL) { + WMA_LOGE("%s: DFS ic is Invalid", __func__); + return NULL; + } + dfs_ic->ic_curchan = (struct ieee80211_channel *)os_malloc(NULL, + sizeof(struct ieee80211_channel), + GFP_ATOMIC); + if (dfs_ic->ic_curchan == NULL) { + WMA_LOGE("%s: allocation of dfs_ic->ic_curchan failed %zu", + __func__, sizeof(struct ieee80211_channel)); + return NULL; + } + OS_MEMZERO(dfs_ic->ic_curchan, sizeof(struct ieee80211_channel)); + + dfs_ic->ic_curchan->ic_ieee = req->chan; + dfs_ic->ic_curchan->ic_freq = chan->mhz; + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = chan->band_center_freq1; + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg2 = chan->band_center_freq2; + dfs_ic->ic_curchan->ic_pri_freq_center_freq_mhz_separation = + dfs_ic->ic_curchan->ic_freq - + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1; + + if ((dfs_ic->ic_curchan->ic_ieee >= WMA_11A_CHANNEL_BEGIN) && + (dfs_ic->ic_curchan->ic_ieee <= WMA_11A_CHANNEL_END)) { + dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_5GHZ; + } + if (CH_WIDTH_80MHZ == req->chan_width) { + dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_VHT80; + } + if (CH_WIDTH_40MHZ == req->chan_width) { + if (req->chan < req->ch_center_freq_seg0) + dfs_ic->ic_curchan->ic_flags |= (req->vht_capable ? + IEEE80211_CHAN_VHT40PLUS : + IEEE80211_CHAN_HT40PLUS); + else + dfs_ic->ic_curchan->ic_flags |= (req->vht_capable ? + IEEE80211_CHAN_VHT40MINUS : + IEEE80211_CHAN_HT40MINUS); + } else if (CH_WIDTH_20MHZ == req->chan_width) { + dfs_ic->ic_curchan->ic_flags |= + (req->vht_capable ? IEEE80211_CHAN_VHT20 : + IEEE80211_CHAN_HT20); + } + dfs_ic->ic_curchan->ic_flagext |= IEEE80211_CHAN_DFS; + + if (req->oper_mode == BSS_OPERATIONAL_MODE_AP) { + dfs_ic->ic_opmode = IEEE80211_M_HOSTAP; + dfs_ic->vdev_id = req->vdev_id; + } + + dfs_ic->dfs_pri_multiplier = req->dfs_pri_multiplier; + + /* + * Configuring the DFS with current channel and the radar filters + */ + wma_dfs_configure(dfs_ic); + WMA_LOGI("%s: DFS- CHANNEL CONFIGURED", __func__); + return dfs_ic->ic_curchan; +} + + +/** + * wma_set_dfs_region() - set DFS region + * @wma: wma handle + * + * Configure the DFS region for DFS radar filter initialization + * + * Return: none + */ +void wma_set_dfs_region(tp_wma_handle wma, uint8_t dfs_region) +{ + /* dfs information is passed */ + if (dfs_region > DFS_MKK4_DOMAIN || dfs_region == DFS_UNINIT_DOMAIN) + /* assign DFS_FCC_DOMAIN as default domain*/ + wma->dfs_ic->current_dfs_regdomain = DFS_FCC_DOMAIN; + else + wma->dfs_ic->current_dfs_regdomain = dfs_region; + + WMA_LOGI("%s: DFS Region Domain: %d", __func__, + wma->dfs_ic->current_dfs_regdomain); +} + +/** + * wma_get_channels() - prepare dfs radar channel list + * @ichan: channel + * @chan_list: return channel list + * + * Return: return number of channels + */ +int wma_get_channels(struct ieee80211_channel *ichan, + struct wma_dfs_radar_channel_list *chan_list) +{ + uint8_t center_chan = cds_freq_to_chan(ichan->ic_vhtop_ch_freq_seg1); + + chan_list->nchannels = 0; + + if (IEEE80211_IS_CHAN_11AC_VHT80(ichan)) { + chan_list->nchannels = 4; + chan_list->channels[0] = center_chan - 6; + chan_list->channels[1] = center_chan - 2; + chan_list->channels[2] = center_chan + 2; + chan_list->channels[3] = center_chan + 6; + } else if (IEEE80211_IS_CHAN_11N_HT40(ichan) || + IEEE80211_IS_CHAN_11AC_VHT40(ichan)) { + chan_list->nchannels = 2; + chan_list->channels[0] = center_chan - 2; + chan_list->channels[1] = center_chan + 2; + } else { + chan_list->nchannels = 1; + chan_list->channels[0] = center_chan; + } + + return chan_list->nchannels; +} + + +/** + * wma_dfs_indicate_radar() - Indicate Radar to SAP/HDD + * @ic: ieee80211com ptr + * @ichan: ieee 80211 channel + * + * Return: 0 for success or error code + */ +int wma_dfs_indicate_radar(struct ieee80211com *ic, + struct ieee80211_channel *ichan) +{ + tp_wma_handle wma; + void *hdd_ctx; + struct wma_dfs_radar_indication *radar_event; + struct wma_dfs_radar_ind wma_radar_event; + tpAniSirGlobal pmac = NULL; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (wma == NULL) { + WMA_LOGE("%s: DFS- Invalid wma", __func__); + return -ENOENT; + } + + hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + pmac = (tpAniSirGlobal) + cds_get_context(CDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid MAC handle", __func__); + return -ENOENT; + } + + if (wma->dfs_ic != ic) { + WMA_LOGE("%s:DFS- Invalid WMA handle", __func__); + return -ENOENT; + } + radar_event = (struct wma_dfs_radar_indication *) + cdf_mem_malloc(sizeof(struct wma_dfs_radar_indication)); + if (radar_event == NULL) { + WMA_LOGE("%s:DFS- Invalid radar_event", __func__); + return -ENOMEM; + } + + /* + * Do not post multiple Radar events on the same channel. + * But, when DFS test mode is enabled, allow multiple dfs + * radar events to be posted on the same channel. + */ + if ((ichan->ic_ieee != (wma->dfs_ic->last_radar_found_chan)) || + (pmac->sap.SapDfsInfo.disable_dfs_ch_switch == true)) { + wma->dfs_ic->last_radar_found_chan = ichan->ic_ieee; + /* Indicate the radar event to HDD to stop the netif Tx queues */ + wma_radar_event.ieee_chan_number = ichan->ic_ieee; + wma_radar_event.chan_freq = ichan->ic_freq; + wma_radar_event.dfs_radar_status = WMA_DFS_RADAR_FOUND; + wma->dfs_radar_indication_cb(hdd_ctx, &wma_radar_event); + WMA_LOGE("%s:DFS- RADAR INDICATED TO HDD", __func__); + + /* + * Indicate to the radar event to SAP to + * select a new channel and set CSA IE + */ + radar_event->vdev_id = ic->vdev_id; + wma_get_channels(ichan, &radar_event->chan_list); + radar_event->dfs_radar_status = WMA_DFS_RADAR_FOUND; + radar_event->use_nol = ic->ic_dfs_usenol(ic); + wma_send_msg(wma, WMA_DFS_RADAR_IND, (void *)radar_event, 0); + WMA_LOGE("%s:DFS- WMA_DFS_RADAR_IND Message Posted", __func__); + } + + return 0; +} + +#ifdef WLAN_FEATURE_MEMDUMP +/* + * wma_process_fw_mem_dump_req() - Function to request fw memory dump from + * firmware + * @wma: Pointer to WMA handle + * @mem_dump_req: Pointer for mem_dump_req + * + * This function sends memory dump request to firmware + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + * + */ +CDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + struct fw_dump_req *mem_dump_req) +{ + wmi_get_fw_mem_dump_fixed_param *cmd; + wmi_fw_mem_dump *dump_params; + struct fw_dump_seg_req *seg_req; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret, loop; + + if (!mem_dump_req || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return CDF_STATUS_E_FAILURE; + } + + /* + * len = sizeof(fixed param) that includes tlv header + + * tlv header for array of struc + + * sizeof (each struct) + */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += mem_dump_req->num_seg * sizeof(wmi_fw_mem_dump); + buf = wmi_buf_alloc(wma->wmi_handle, len); + + if (!buf) { + WMA_LOGE(FL("Failed allocate wmi buffer")); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + cmd = (wmi_get_fw_mem_dump_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_get_fw_mem_dump_fixed_param)); + + cmd->request_id = mem_dump_req->request_id; + cmd->num_fw_mem_dump_segs = mem_dump_req->num_seg; + + /* TLV indicating array of structures to follow */ + buf_ptr += sizeof(wmi_get_fw_mem_dump_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_fw_mem_dump) * + cmd->num_fw_mem_dump_segs); + + buf_ptr += WMI_TLV_HDR_SIZE; + dump_params = (wmi_fw_mem_dump *) buf_ptr; + + WMA_LOGI(FL("request_id:%d num_seg:%d"), + mem_dump_req->request_id, mem_dump_req->num_seg); + for (loop = 0; loop < cmd->num_fw_mem_dump_segs; loop++) { + seg_req = (struct fw_dump_seg_req *) + ((uint8_t *)(mem_dump_req->segment) + + loop * sizeof(*seg_req)); + WMITLV_SET_HDR(&dump_params->tlv_header, + WMITLV_TAG_STRUC_wmi_fw_mem_dump_params, + WMITLV_GET_STRUCT_TLVLEN(wmi_fw_mem_dump)); + dump_params->seg_id = seg_req->seg_id; + dump_params->seg_start_addr_lo = seg_req->seg_start_addr_lo; + dump_params->seg_start_addr_hi = seg_req->seg_start_addr_hi; + dump_params->seg_length = seg_req->seg_length; + dump_params->dest_addr_lo = seg_req->dst_addr_lo; + dump_params->dest_addr_hi = seg_req->dst_addr_hi; + WMA_LOGI(FL("seg_number:%d"), loop); + WMA_LOGI(FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + dump_params->seg_id, dump_params->seg_start_addr_lo, + dump_params->seg_start_addr_hi); + WMA_LOGI(FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + dump_params->seg_length, dump_params->dest_addr_lo, + dump_params->dest_addr_hi); + dump_params++; + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_GET_FW_MEM_DUMP_CMDID); + if (ret) { + WMA_LOGE(FL("Failed to send get firmware mem dump request")); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI(FL("Get firmware mem dump request sent successfully")); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_fw_mem_dump_rsp() - send fw mem dump response to SME + * + * @req_id - request id. + * @status - copy status from the firmware. + * + * This function is called by the memory dump response handler to + * indicate SME that firmware dump copy is complete + * + * Return: CDF_STATUS + */ +static CDF_STATUS wma_fw_mem_dump_rsp(uint32_t req_id, uint32_t status) +{ + struct fw_dump_rsp *dump_rsp; + cds_msg_t sme_msg = {0}; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + dump_rsp = cdf_mem_malloc(sizeof(*dump_rsp)); + + if (!dump_rsp) { + WMA_LOGE(FL("Memory allocation failed.")); + cdf_status = CDF_STATUS_E_NOMEM; + return cdf_status; + } + + WMA_LOGI(FL("FW memory dump copy complete status: %d for request: %d"), + status, req_id); + + dump_rsp->request_id = req_id; + dump_rsp->dump_complete = status; + + sme_msg.type = eWNI_SME_FW_DUMP_IND; + sme_msg.bodyptr = dump_rsp; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Fail to post fw mem dump ind msg")); + cdf_mem_free(dump_rsp); + } + + return cdf_status; +} + +/** + * wma_fw_mem_dump_event_handler() - handles fw memory dump event + * + * @handle: pointer to wma handle. + * @cmd_param_info: pointer to TLV info received in the event. + * @len: length of data in @cmd_param_info + * + * This function is a handler for firmware memory dump event. + * + * Return: integer (0 for success and error code otherwise) + */ +int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *param_buf; + wmi_update_fw_mem_dump_fixed_param *event; + CDF_STATUS status; + + param_buf = + (WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + + status = wma_fw_mem_dump_rsp(event->request_id, + event->fw_mem_dump_complete); + if (CDF_STATUS_SUCCESS != status) { + WMA_LOGE("Error posting FW MEM DUMP RSP."); + return -EINVAL; + } + + WMA_LOGI("FW MEM DUMP RSP posted successfully"); + return 0; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/* + * wma_process_set_ie_info() - Function to send IE info to firmware + * @wma: Pointer to WMA handle + * @ie_data: Pointer for ie data + * + * This function sends IE information to firmware + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + * + */ +CDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info) +{ + wmi_vdev_set_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len, ie_len_aligned; + int ret; + + if (!ie_info || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return CDF_STATUS_E_FAILURE; + } + + /* Validate the input */ + if (ie_info->length <= 0) { + WMA_LOGE(FL("Invalid IE length")); + return CDF_STATUS_E_INVAL; + } + + ie_len_aligned = roundup(ie_info->length, sizeof(uint32_t)); + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + ie_len_aligned; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_vdev_set_ie_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_ie_cmd_fixed_param)); + cmd->vdev_id = ie_info->vdev_id; + cmd->ie_id = ie_info->ie_id; + cmd->ie_len = ie_info->length; + + WMA_LOGD(FL("IE:%d of size:%d sent for vdev:%d"), ie_info->ie_id, + ie_info->length, ie_info->vdev_id); + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + + cdf_mem_copy(buf_ptr, ie_info->data, cmd->ie_len); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_SET_IE_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to send set IE command ret = %d"), ret); + wmi_buf_free(buf); + } + + return ret; +} + diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c new file mode 100644 index 0000000000..0676686d68 --- /dev/null +++ b/core/wma/src/wma_main.c @@ -0,0 +1,5382 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_main.c + * + * This file contains wma initialization and FW exchange + * related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +/* FIXME: Inclusion of .c looks odd + * but this is how it is in internal codebase + */ +#include "wmi_version_whitelist.c" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +#include "wma_ocb.h" + +#define WMA_LOG_COMPLETION_TIMER 10000 /* 10 seconds */ +#define WMA_SERVICE_READY_EXT_TIMEOUT 2000 /* 2 seconds */ + +static uint32_t g_fw_wlan_feat_caps; + +/** + * wma_get_fw_wlan_feat_caps() - get fw feature capablity + * @featEnumValue: feature enum value + * + * Return: true/false + */ +uint8_t wma_get_fw_wlan_feat_caps(uint8_t featEnumValue) +{ + return (g_fw_wlan_feat_caps & (1 << featEnumValue)) ? true : false; +} + +/** + * wma_set_default_tgt_config() - set default tgt config + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_set_default_tgt_config(tp_wma_handle wma_handle) +{ + struct ol_softc *scn; + uint8_t no_of_peers_supported; + wmi_resource_config tgt_cfg = { + 0, /* Filling zero for TLV Tag and Length fields */ + CFG_TGT_NUM_VDEV, + CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2, + CFG_TGT_NUM_OFFLOAD_PEERS, + CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS, + CFG_TGT_NUM_PEER_KEYS, + CFG_TGT_NUM_TIDS, + CFG_TGT_AST_SKID_LIMIT, + CFG_TGT_DEFAULT_TX_CHAIN_MASK, + CFG_TGT_DEFAULT_RX_CHAIN_MASK, + {CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, + CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_HI_PRI}, + CFG_TGT_RX_DECAP_MODE, + CFG_TGT_DEFAULT_SCAN_MAX_REQS, + CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV, + CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV, + CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES, + CFG_TGT_DEFAULT_NUM_MCAST_GROUPS, + CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS, + CFG_TGT_DEFAULT_MCAST2UCAST_MODE, + CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE, + CFG_TGT_WDS_ENTRIES, + CFG_TGT_DEFAULT_DMA_BURST_SIZE, + CFG_TGT_DEFAULT_MAC_AGGR_DELIM, + CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK, + CFG_TGT_DEFAULT_VOW_CONFIG, + CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV, + CFG_TGT_NUM_MSDU_DESC, + CFG_TGT_MAX_FRAG_TABLE_ENTRIES, + CFG_TGT_NUM_TDLS_VDEVS, + CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES, + CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV, + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES, + 0, + 0, + 0, + CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS, + CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS, + 0, + CFG_TGT_NUM_OCB_VDEVS, + CFG_TGT_NUM_OCB_CHANNELS, + CFG_TGT_NUM_OCB_SCHEDULES, + }; + + /* Update the max number of peers */ + scn = cds_get_context(CDF_MODULE_ID_HIF); + if (!scn) { + WMA_LOGE("%s: cds_context is NULL", __func__); + return; + } + no_of_peers_supported = ol_get_number_of_peers_supported(scn); + tgt_cfg.num_peers = no_of_peers_supported + CFG_TGT_NUM_VDEV + 2; + tgt_cfg.num_tids = (2 * (no_of_peers_supported + CFG_TGT_NUM_VDEV + 2)); + tgt_cfg.scan_max_pending_req = wma_handle->max_scan; + + WMITLV_SET_HDR(&tgt_cfg.tlv_header, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); + /* reduce the peer/vdev if CFG_TGT_NUM_MSDU_DESC exceeds 1000 */ +#ifdef PERE_IP_HDR_ALIGNMENT_WAR + if (scn->host_80211_enable) { + /* + * To make the IP header begins at dword aligned address, + * we make the decapsulation mode as Native Wifi. + */ + tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_NWIFI; + } +#endif /* PERE_IP_HDR_ALIGNMENT_WAR */ + wma_handle->wlan_resource_config = tgt_cfg; +} + +/** + * wma_cli_get_command() - WMA "get" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @vpdev: parameter category + * + * Return: parameter value on success, -EINVAL on failure + */ +int wma_cli_get_command(int vdev_id, int param_id, int vpdev) +{ + int ret = 0; + tp_wma_handle wma; + struct wma_txrx_node *intr = NULL; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return -EINVAL; + } + + intr = wma->interfaces; + + if (VDEV_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PARAM_NSS: + ret = intr[vdev_id].config.nss; + break; +#ifdef QCA_SUPPORT_GTX + case WMI_VDEV_PARAM_GTX_HT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case WMI_VDEV_PARAM_GTX_USR_CFG: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case WMI_VDEV_PARAM_GTX_THRE: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case WMI_VDEV_PARAM_GTX_MARGIN: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case WMI_VDEV_PARAM_GTX_STEP: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case WMI_VDEV_PARAM_GTX_MINTPC: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case WMI_VDEV_PARAM_GTX_BW_MASK: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; +#endif /* QCA_SUPPORT_GTX */ + case WMI_VDEV_PARAM_LDPC: + ret = intr[vdev_id].config.ldpc; + break; + case WMI_VDEV_PARAM_TX_STBC: + ret = intr[vdev_id].config.tx_stbc; + break; + case WMI_VDEV_PARAM_RX_STBC: + ret = intr[vdev_id].config.rx_stbc; + break; + case WMI_VDEV_PARAM_SGI: + ret = intr[vdev_id].config.shortgi; + break; + case WMI_VDEV_PARAM_ENABLE_RTSCTS: + ret = intr[vdev_id].config.rtscts_en; + break; + case WMI_VDEV_PARAM_CHWIDTH: + ret = intr[vdev_id].config.chwidth; + break; + case WMI_VDEV_PARAM_FIXED_RATE: + ret = intr[vdev_id].config.tx_rate; + break; + default: + WMA_LOGE("Invalid cli_get vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (PDEV_CMD == vpdev) { + switch (param_id) { + case WMI_PDEV_PARAM_ANI_ENABLE: + ret = wma->pdevconfig.ani_enable; + break; + case WMI_PDEV_PARAM_ANI_POLL_PERIOD: + ret = wma->pdevconfig.ani_poll_len; + break; + case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD: + ret = wma->pdevconfig.ani_listen_len; + break; + case WMI_PDEV_PARAM_ANI_OFDM_LEVEL: + ret = wma->pdevconfig.ani_ofdm_level; + break; + case WMI_PDEV_PARAM_ANI_CCK_LEVEL: + ret = wma->pdevconfig.ani_cck_level; + break; + case WMI_PDEV_PARAM_DYNAMIC_BW: + ret = wma->pdevconfig.cwmenable; + break; + case WMI_PDEV_PARAM_CTS_CBW: + ret = wma->pdevconfig.cts_cbw; + break; + case WMI_PDEV_PARAM_TX_CHAIN_MASK: + ret = wma->pdevconfig.txchainmask; + break; + case WMI_PDEV_PARAM_RX_CHAIN_MASK: + ret = wma->pdevconfig.rxchainmask; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT2G: + ret = wma->pdevconfig.txpow2g; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT5G: + ret = wma->pdevconfig.txpow5g; + break; + case WMI_PDEV_PARAM_POWER_GATING_SLEEP: + ret = wma->pdevconfig.pwrgating; + break; + case WMI_PDEV_PARAM_BURST_ENABLE: + ret = wma->pdevconfig.burst_enable; + break; + case WMI_PDEV_PARAM_BURST_DUR: + ret = wma->pdevconfig.burst_dur; + break; + default: + WMA_LOGE("Invalid cli_get pdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (GEN_CMD == vpdev) { + switch (param_id) { + case GEN_VDEV_PARAM_AMPDU: + ret = intr[vdev_id].config.ampdu; + break; + case GEN_VDEV_PARAM_AMSDU: + ret = intr[vdev_id].config.amsdu; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (PPS_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PPS_PAID_MATCH: + ret = intr[vdev_id].config.pps_params.paid_match_enable; + break; + case WMI_VDEV_PPS_GID_MATCH: + ret = intr[vdev_id].config.pps_params.gid_match_enable; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + ret = intr[vdev_id].config.pps_params.tim_clear; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + ret = intr[vdev_id].config.pps_params.dtim_clear; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + ret = intr[vdev_id].config.pps_params.eof_delim; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + ret = intr[vdev_id].config.pps_params.mac_match; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + ret = intr[vdev_id].config.pps_params.delim_fail; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + ret = intr[vdev_id].config.pps_params.nsts_zero; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + ret = intr[vdev_id].config.pps_params.rssi_chk; + break; + default: + WMA_LOGE("Invalid pps vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (QPOWER_CMD == vpdev) { + switch (param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + ret = intr[vdev_id].config.qpower_params. + max_ps_poll_cnt; + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + ret = intr[vdev_id].config.qpower_params. + max_tx_before_wake; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + ret = intr[vdev_id].config.qpower_params. + spec_ps_poll_wake_interval; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + ret = intr[vdev_id].config.qpower_params. + max_spec_nodata_ps_poll; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (GTX_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PARAM_GTX_HT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case WMI_VDEV_PARAM_GTX_USR_CFG: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case WMI_VDEV_PARAM_GTX_THRE: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case WMI_VDEV_PARAM_GTX_MARGIN: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case WMI_VDEV_PARAM_GTX_STEP: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case WMI_VDEV_PARAM_GTX_MINTPC: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case WMI_VDEV_PARAM_GTX_BW_MASK: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } + return ret; +} + +/** + * wma_cli_set2_command() - WMA "set 2 params" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval1: first parameter value + * @sval2: second parameter value + * @vpdev: parameter category + * + * Command handler for set operations which require 2 parameters + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev) +{ + cds_msg_t msg = { 0 }; + wma_cli_set_cmd_t *iwcmd; + + iwcmd = cdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + WMA_LOGE("%s: Failed alloc memory for iwcmd", __func__); + return -ENOMEM; + } + + cdf_mem_zero(iwcmd, sizeof(*iwcmd)); + iwcmd->param_value = sval1; + iwcmd->param_sec_value = sval2; + iwcmd->param_vdev_id = vdev_id; + iwcmd->param_id = param_id; + iwcmd->param_vp_dev = vpdev; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = iwcmd; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + WMA_LOGP("%s: Failed to post WMA_CLI_SET_CMD msg", + __func__); + cdf_mem_free(iwcmd); + return -EIO; + } + return 0; +} + +/** + * wma_cli_set_command() - WMA "set" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval: parameter value + * @vpdev: parameter category + * + * Command handler for set operations + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) +{ + return wma_cli_set2_command(vdev_id, param_id, sval, 0, vpdev); + +} + +/** + * wma_set_priv_cfg() - set private config parameters + * @wma_handle: wma handle + * @privcmd: private command + * + * Return: 0 for success or error code + */ +static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle, + wma_cli_set_cmd_t *privcmd) +{ + int32_t ret = 0; + + switch (privcmd->param_id) { + case WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: + ret = wma_set_txrx_fw_stats_level(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: + ret = wma_txrx_fw_stats_reset(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_FORCE_MODE_CMDID: + wma_set_mimops(wma_handle, privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_PARAM_CMDID: + wma_set_smps_params(wma_handle, privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_MCC_SET_TIME_LATENCY: + { + /* Extract first MCC adapter/vdev channel number and latency */ + uint8_t mcc_channel = privcmd->param_value & 0x000000FF; + uint8_t mcc_channel_latency = + (privcmd->param_value & 0x0000FF00) >> 8; + int ret = -1; + WMA_LOGD("%s: Parsed input: Channel #1:%d, latency:%dms", + __func__, mcc_channel, mcc_channel_latency); + ret = wma_set_mcc_channel_time_latency(wma_handle, + mcc_channel, + mcc_channel_latency); + } + break; + case WMA_VDEV_MCC_SET_TIME_QUOTA: + { + /* Extract the MCC 2 adapters/vdevs channel numbers and time + * quota value for the first adapter only (which is specified + * in iwpriv command. + */ + uint8_t adapter_2_chan_number = + privcmd->param_value & 0x000000FF; + uint8_t adapter_1_chan_number = + (privcmd->param_value & 0x0000FF00) >> 8; + uint8_t adapter_1_quota = + (privcmd->param_value & 0x00FF0000) >> 16; + int ret = -1; + + WMA_LOGD("%s: Parsed input: Channel #1:%d, Channel #2:%d, quota 1:%dms", + __func__, adapter_1_chan_number, + adapter_2_chan_number, adapter_1_quota); + + ret = wma_set_mcc_channel_time_quota(wma_handle, + adapter_1_chan_number, + adapter_1_quota, + adapter_2_chan_number); + } + break; + case WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE: + { + wma_handle->wma_ibss_power_save_params.atimWindowLength = + privcmd->param_value; + WMA_LOGD("%s: IBSS power save ATIM Window = %d", + __func__, wma_handle->wma_ibss_power_save_params. + atimWindowLength); + } + break; + case WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params.isPowerSaveAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Save Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerSaveAllowed); + } + break; + case WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params. isPowerCollapseAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Collapse Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerCollapseAllowed); + } + break; + case WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: + { + wma_handle->wma_ibss_power_save_params.isAwakeonTxRxEnabled = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Awake on Tx/Rx Enabled = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isAwakeonTxRxEnabled); + } + break; + case WMA_VDEV_IBSS_SET_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.inactivityCount = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Data Inactivity Count = %d", + __func__, wma_handle->wma_ibss_power_save_params. + inactivityCount); + } + break; + case WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.txSPEndInactivityTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Transmit EOSP inactivity time out = %d", + __func__, wma_handle->wma_ibss_power_save_params. + txSPEndInactivityTime); + } + break; + case WMA_VDEV_DFS_CONTROL_CMDID: + { + struct ieee80211com *dfs_ic = wma_handle->dfs_ic; + struct ath_dfs *dfs; + + if (!dfs_ic) { + ret = -ENOENT; + } else { + if (dfs_ic->ic_curchan) { + WMA_LOGD("%s: Debug cmd: %s received on ch: %d", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID", + dfs_ic->ic_curchan->ic_ieee); + + if (dfs_ic->ic_curchan->ic_flagext & + IEEE80211_CHAN_DFS) { + dfs = (struct ath_dfs *)dfs_ic->ic_dfs; + dfs->dfs_bangradar = 1; + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, + 0); + } else { + ret = -ENOENT; + } + } else { + ret = -ENOENT; + } + } + + if (ret == -ENOENT) { + WMA_LOGE("%s: Operating channel is not DFS capable,ignoring %s", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID"); + } else if (ret) { + WMA_LOGE("%s: Sending command %s failed with %d\n", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID", + ret); + } + } + break; + case WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: + { + wma_handle->wma_ibss_power_save_params.ibssPsWarmupTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Warm Up Time in Seconds = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPsWarmupTime); + } + break; + case WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: + { + wma_handle->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable + = privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save single RX Chain Enable In ATIM = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPs1RxChainInAtimEnable); + } + break; + + case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: + { + ol_txrx_pdev_handle pdev; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + ol_txrx_ipa_uc_get_stat(pdev); + } + break; + + default: + WMA_LOGE("Invalid wma config command id:%d", privcmd->param_id); + ret = -EINVAL; + } + return ret; +} + +/** + * wmi_unified_pdev_set_param() - set pdev parameters + * @wmi_handle: wmi handle + * @param_id: parameter id + * @param_value: parameter value + * + * Return: 0 on success, errno on failure + */ +int +wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id, + uint32_t param_value) +{ + int ret; + wmi_pdev_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_pdev_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_param_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->param_id = param_id; + cmd->param_value = param_value; + WMA_LOGD("Setting pdev param = %x, value = %u", param_id, param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_PARAM_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wma_set_modulated_dtim() - function to configure modulated dtim + * @wma: wma handle + * @privcmd: structure containing parameters + * + * This function configures the modulated dtim in firmware + * + * Return: none + */ +static void wma_set_modulated_dtim(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + uint8_t vdev_id = privcmd->param_vdev_id; + struct wma_txrx_node *iface = + &wma->interfaces[vdev_id]; + bool prev_dtim_enabled; + uint32_t listen_interval; + int ret; + + iface->alt_modulated_dtim = privcmd->param_value; + + prev_dtim_enabled = iface->alt_modulated_dtim_enabled; + + if (1 != privcmd->param_value) + iface->alt_modulated_dtim_enabled = true; + else + iface->alt_modulated_dtim_enabled = false; + + if ((true == iface->alt_modulated_dtim_enabled) || + (true == prev_dtim_enabled)) { + + listen_interval = iface->alt_modulated_dtim + * iface->dtimPeriod; + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + listen_interval); + if (ret) + /* Even if it fails, continue */ + WMA_LOGW("Failed to set listen interval %d", + listen_interval); + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY , + NORMAL_DTIM); + if (ret) + WMA_LOGE("Failed to Set to Normal DTIM policy"); + } +} + + +/** + * wma_process_cli_set_cmd() - set parameters to fw + * @wma: wma handle + * @privcmd: command + * + * Return: none + */ +static void wma_process_cli_set_cmd(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + int ret = 0, vid = privcmd->param_vdev_id, pps_val = 0; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + struct qpower_params *qparams = &intr[vid].config.qpower_params; + + WMA_LOGD("wmihandle %p", wma->wmi_handle); + + if (NULL == pMac) { + WMA_LOGE("%s: Failed to get pMac", __func__); + return; + } + + if (privcmd->param_id >= WMI_CMDID_MAX) { + /* + * This configuration setting is not done using any wmi + * command, call appropriate handler. + */ + if (wma_set_priv_cfg(wma, privcmd)) + WMA_LOGE("Failed to set wma priv congiuration"); + return; + } + + switch (privcmd->param_vp_dev) { + case VDEV_CMD: + WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + privcmd->param_vdev_id, + privcmd->param_id, + privcmd->param_value); + if (ret) { + WMA_LOGE("wmi_unified_vdev_set_param_send failed ret %d", + ret); + return; + } + break; + case PDEV_CMD: + WMA_LOGD("pdev pid %d pval %d", privcmd->param_id, + privcmd->param_value); + if ((privcmd->param_id == WMI_PDEV_PARAM_RX_CHAIN_MASK) || + (privcmd->param_id == WMI_PDEV_PARAM_TX_CHAIN_MASK)) { + wma_update_txrx_chainmask(wma->num_rf_chains, + &privcmd->param_value); + } + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + privcmd->param_id, + privcmd->param_value); + if (ret) { + WMA_LOGE("wmi_unified_vdev_set_param_send failed ret %d", + ret); + return; + } + break; + case GEN_CMD: + { + ol_txrx_vdev_handle vdev = NULL; + struct wma_txrx_node *intr = wma->interfaces; + + vdev = wma_find_vdev_by_id(wma, privcmd->param_vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return; + } + + WMA_LOGD("gen pid %d pval %d", privcmd->param_id, + privcmd->param_value); + + switch (privcmd->param_id) { + case GEN_VDEV_PARAM_AMPDU: + ret = ol_txrx_aggr_cfg(vdev, privcmd->param_value, 0); + if (ret) + WMA_LOGE("ol_txrx_aggr_cfg set ampdu failed ret %d", + ret); + else + intr[privcmd->param_vdev_id].config.ampdu = + privcmd->param_value; + break; + case GEN_VDEV_PARAM_AMSDU: + ret = ol_txrx_aggr_cfg(vdev, 0, privcmd->param_value); + if (ret) + WMA_LOGE("ol_txrx_aggr_cfg set amsdu failed ret %d", + ret); + else + intr[privcmd->param_vdev_id].config. + amsdu = privcmd->param_value; + break; + case GEN_PARAM_DUMP_AGC_START: + htc_dump(wma->htc_handle, AGC_DUMP, true); + break; + case GEN_PARAM_DUMP_AGC: + htc_dump(wma->htc_handle, AGC_DUMP, false); + break; + case GEN_PARAM_DUMP_CHANINFO_START: + htc_dump(wma->htc_handle, CHAN_DUMP, true); + break; + case GEN_PARAM_DUMP_CHANINFO: + htc_dump(wma->htc_handle, CHAN_DUMP, false); + break; + case GEN_PARAM_DUMP_WATCHDOG: + htc_dump(wma->htc_handle, WD_DUMP, false); + break; + case GEN_PARAM_CRASH_INJECT: + ret = wmi_crash_inject(wma->wmi_handle, + privcmd->param_value, + privcmd->param_sec_value); + break; +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + case GEN_PARAM_DUMP_PCIE_ACCESS_LOG: + htc_dump(wma->htc_handle, PCIE_DUMP, false); + break; +#endif /* CONFIG_ATH_PCIE_ACCESS_DEBUG */ + case GEN_PARAM_MODULATED_DTIM: + wma_set_modulated_dtim(wma, privcmd); + break; + default: + WMA_LOGE("Invalid param id 0x%x", + privcmd->param_id); + break; + } + break; + } + case DBG_CMD: + WMA_LOGD("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_DBGLOG_LOG_LEVEL: + ret = dbglog_set_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_set_log_lvl failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_ENABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + WMA_LOGE("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_DISABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + WMA_LOGE("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_ENABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_DISABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MOD_LOG_LEVEL: + ret = dbglog_set_mod_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_TYPE: + ret = dbglog_parser_type_init(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_parser_type_init failed ret %d", + ret); + break; + case WMI_DBGLOG_REPORT_ENABLE: + ret = dbglog_report_enable(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_report_enable failed ret %d", + ret); + break; +#ifdef FEATURE_GREEN_AP + case WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID: + /* Set the Green AP */ + ret = wmi_unified_pdev_green_ap_ps_enable_cmd + (wma->wmi_handle, privcmd->param_value); + if (ret) { + WMA_LOGE("Set GreenAP Failed val %d", + privcmd->param_value); + } + break; +#endif /* FEATURE_GREEN_AP */ + + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case PPS_CMD: + WMA_LOGD("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + + case WMI_VDEV_PPS_PAID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + intr[vid].config.pps_params.paid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + intr[vid].config.pps_params.gid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + intr[vid].config.pps_params.tim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + intr[vid].config.pps_params.dtim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + intr[vid].config.pps_params.eof_delim = + privcmd->param_value; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + intr[vid].config.pps_params.mac_match = + privcmd->param_value; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + intr[vid].config.pps_params.delim_fail = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + intr[vid].config.pps_params.nsts_zero = + privcmd->param_value; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + intr[vid].config.pps_params.rssi_chk = + privcmd->param_value; + break; + case WMI_VDEV_PPS_5G_EBT: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_5G_EBT & 0xffff); + intr[vid].config.pps_params.ebt_5g = + privcmd->param_value; + break; + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + + case QPOWER_CMD: + WMA_LOGD("QPOWER CLI CMD pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + WMA_LOGD("QPOWER CLI CMD:Ps Poll Cnt val %d", + privcmd->param_value); + /* Set the QPower Ps Poll Count */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-PsPollCnt Failed vdevId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_ps_poll_cnt = privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + WMA_LOGD("QPOWER CLI CMD:Max Tx Before wake val %d", + privcmd->param_value); + /* Set the QPower Max Tx Before Wake */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-MaxTxBefWake Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_tx_before_wake = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + WMA_LOGD("QPOWER CLI CMD:Ps Poll Wake Inv val %d", + privcmd->param_value); + /* Set the QPower Spec Ps Poll Wake Inv */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-PsPoll WakeIntv Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->spec_ps_poll_wake_interval = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + WMA_LOGD("QPOWER CLI CMD:Spec NoData Ps Poll val %d", + privcmd->param_value); + /* Set the QPower Spec NoData PsPoll */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-SpecNoDataPsPoll Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_spec_nodata_ps_poll = + privcmd->param_value; + } + break; + + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case GTX_CMD: + WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + switch (privcmd->param_id) { + case WMI_VDEV_PARAM_GTX_HT_MCS: + intr[vid].config.gtx_info.gtxRTMask[0] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + intr[vid].config.gtx_info.gtxRTMask[1] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_USR_CFG: + intr[vid].config.gtx_info.gtxUsrcfg = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_THRE: + intr[vid].config.gtx_info.gtxPERThreshold = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_MARGIN: + intr[vid].config.gtx_info.gtxPERMargin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_STEP: + intr[vid].config.gtx_info.gtxTPCstep = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_MINTPC: + intr[vid].config.gtx_info.gtxTPCMin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_BW_MASK: + intr[vid].config.gtx_info.gtxBWMask = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + if (ret) { + WMA_LOGE("wmi_unified_vdev_set_param_send" + " failed ret %d", ret); + return; + } + break; + default: + break; + } + break; + + default: + WMA_LOGE("Invalid vpdev command id"); + } + if (1 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case WMI_VDEV_PARAM_NSS: + intr[vid].config.nss = privcmd->param_value; + break; + case WMI_VDEV_PARAM_LDPC: + intr[vid].config.ldpc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_TX_STBC: + intr[vid].config.tx_stbc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_RX_STBC: + intr[vid].config.rx_stbc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_SGI: + intr[vid].config.shortgi = privcmd->param_value; + break; + case WMI_VDEV_PARAM_ENABLE_RTSCTS: + intr[vid].config.rtscts_en = privcmd->param_value; + break; + case WMI_VDEV_PARAM_CHWIDTH: + intr[vid].config.chwidth = privcmd->param_value; + break; + case WMI_VDEV_PARAM_FIXED_RATE: + intr[vid].config.tx_rate = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE: + intr[vid].config.erx_adjust = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM: + intr[vid].config.erx_bmiss_num = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE: + intr[vid].config.erx_bmiss_cycle = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP: + intr[vid].config.erx_slop_step = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP: + intr[vid].config.erx_init_slop = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE: + intr[vid].config.erx_adj_pause = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE: + intr[vid].config.erx_dri_sample = privcmd->param_value; + break; + default: + WMA_LOGE("Invalid wma_cli_set vdev command/Not" + " yet implemented 0x%x", privcmd->param_id); + break; + } + } else if (2 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case WMI_PDEV_PARAM_ANI_ENABLE: + wma->pdevconfig.ani_enable = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_POLL_PERIOD: + wma->pdevconfig.ani_poll_len = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD: + wma->pdevconfig.ani_listen_len = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_OFDM_LEVEL: + wma->pdevconfig.ani_ofdm_level = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_CCK_LEVEL: + wma->pdevconfig.ani_cck_level = privcmd->param_value; + break; + case WMI_PDEV_PARAM_DYNAMIC_BW: + wma->pdevconfig.cwmenable = privcmd->param_value; + break; + case WMI_PDEV_PARAM_CTS_CBW: + wma->pdevconfig.cts_cbw = privcmd->param_value; + break; + case WMI_PDEV_PARAM_TX_CHAIN_MASK: + wma->pdevconfig.txchainmask = privcmd->param_value; + break; + case WMI_PDEV_PARAM_RX_CHAIN_MASK: + wma->pdevconfig.rxchainmask = privcmd->param_value; + break; + case WMI_PDEV_PARAM_BURST_ENABLE: + wma->pdevconfig.burst_enable = privcmd->param_value; + if ((wma->pdevconfig.burst_enable == 1) && + (wma->pdevconfig.burst_dur == 0)) + wma->pdevconfig.burst_dur = + WMA_DEFAULT_SIFS_BURST_DURATION; + else if (wma->pdevconfig.burst_enable == 0) + wma->pdevconfig.burst_dur = 0; + break; + case WMI_PDEV_PARAM_BURST_DUR: + wma->pdevconfig.burst_dur = privcmd->param_value; + break; + case WMI_PDEV_PARAM_POWER_GATING_SLEEP: + wma->pdevconfig.pwrgating = privcmd->param_value; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT2G: + wma->pdevconfig.txpow2g = privcmd->param_value; + if ((pMac->roam.configParam.bandCapability == + eCSR_BAND_ALL) || + (pMac->roam.configParam.bandCapability == + eCSR_BAND_24)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + eSIR_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 2G"); + } + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT5G: + wma->pdevconfig.txpow5g = privcmd->param_value; + if ((pMac->roam.configParam.bandCapability == + eCSR_BAND_ALL) || + (pMac->roam.configParam.bandCapability == + eCSR_BAND_5G)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + eSIR_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 5G"); + } + break; + default: + WMA_LOGE("Invalid wma_cli_set pdev command/Not yet implemented 0x%x", + privcmd->param_id); + break; + } + } else if (5 == privcmd->param_vp_dev) { + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + if (ret) + WMA_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("Sent packet power save cmd %d value %x to target", + privcmd->param_id, pps_val); + } +} + +/** + * wma_process_fw_event() - process any fw event + * @wma: wma handle + * @buf: fw event buffer + * + * This function process any fw event to serialize it through mc thread. + * + * Return: none + */ +static int wma_process_fw_event(tp_wma_handle wma, + wma_process_fw_event_params *buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)buf->wmi_handle; + + wmi_process_fw_event(wmi_handle, buf->evt_buf); + return 0; +} + +/** + * wma_process_fw_event_handler() - common event handler to serialize + * event processing through mc_thread + * @wmi_handle: wmi handle + * @evt_buf: event buffer + * + * Return: 0 on success, errno on failure + */ +int wma_process_fw_event_handler(struct wmi_unified *wmi_handle, + wmi_buf_t evt_buf) +{ + wma_process_fw_event_params *params_buf; + cds_msg_t cds_msg = { 0 }; + + params_buf = cdf_mem_malloc(sizeof(wma_process_fw_event_params)); + if (!params_buf) { + WMA_LOGE("%s: Failed alloc memory for params_buf", __func__); + cdf_nbuf_free(evt_buf); + return -ENOMEM; + } + + params_buf->wmi_handle = wmi_handle; + params_buf->evt_buf = evt_buf; + + cds_msg.type = WMA_PROCESS_FW_EVENT; + cds_msg.bodyptr = params_buf; + cds_msg.bodyval = 0; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_WMA, &cds_msg)) { + WMA_LOGP("%s: Failed to post WMA_PROCESS_FW_EVENT msg", + __func__); + cdf_nbuf_free(evt_buf); + cdf_mem_free(params_buf); + return -EFAULT; + } + WMA_LOGD("WMA_PROCESS_FW_EVENT posted"); + return 0; + +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_cfg_set_flow_control_parameters() - set flow control parameters + * @olCfg: cfg parameters + * @mac_params: mac parameters + * + * Return: none + */ +static +void ol_cfg_set_flow_control_parameters(struct txrx_pdev_cfg_param_t *olCfg, + tMacOpenParameters *mac_params) +{ + olCfg->tx_flow_start_queue_offset = + mac_params->tx_flow_start_queue_offset; + olCfg->tx_flow_stop_queue_th = + mac_params->tx_flow_stop_queue_th; +} +#else +static +void ol_cfg_set_flow_control_parameters(struct txrx_pdev_cfg_param_t *olCfg, + tMacOpenParameters *mac_params) +{ + return; +} +#endif + +#ifdef WLAN_FEATURE_NAN +/** + * wma_set_nan_enable() - set nan enable flag in WMA handle + * @wma_handle: Pointer to wma handle + * @mac_param: Pointer to mac_param + * + * Return: none + */ +static void wma_set_nan_enable(tp_wma_handle wma_handle, + tMacOpenParameters *mac_param) +{ + wma_handle->is_nan_enabled = mac_param->is_nan_enabled; +} +#else +static void wma_set_nan_enable(tp_wma_handle wma_handle, + tMacOpenParameters *mac_param) +{ +} +#endif + +/** + * wma_open() - Allocate wma context and initialize it. + * @cds_context: cds context + * @wma_tgt_cfg_cb: tgt config callback fun + * @radar_ind_cb: dfs radar indication callback + * @mac_params: mac parameters + * + * Return: 0 on success, errno on failure + */ +CDF_STATUS wma_open(void *cds_context, + wma_tgt_cfg_cb tgt_cfg_cb, + wma_dfs_radar_indication_cb radar_ind_cb, + tMacOpenParameters *mac_params) +{ + tp_wma_handle wma_handle; + HTC_HANDLE htc_handle; + cdf_device_t cdf_dev; + void *wmi_handle; + CDF_STATUS cdf_status; + struct ol_softc *scn; + struct txrx_pdev_cfg_param_t olCfg = { 0 }; + + WMA_LOGD("%s: Enter", __func__); + + cdf_dev = cds_get_context(CDF_MODULE_ID_CDF_DEVICE); + htc_handle = cds_get_context(CDF_MODULE_ID_HTC); + + if (!htc_handle) { + WMA_LOGP("%s: Invalid HTC handle", __func__); + return CDF_STATUS_E_INVAL; + } + + /* Alloc memory for WMA Context */ + cdf_status = cds_alloc_context(cds_context, CDF_MODULE_ID_WMA, + (void **)&wma_handle, + sizeof(t_wma_handle)); + + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Memory allocation failed for wma_handle", + __func__); + return cdf_status; + } + + cdf_mem_zero(wma_handle, sizeof(t_wma_handle)); + + if (cds_get_conparam() != CDF_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + cdf_wake_lock_init(&wma_handle->pno_wake_lock, "wlan_pno_wl"); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + cdf_wake_lock_init(&wma_handle->extscan_wake_lock, + "wlan_extscan_wl"); +#endif /* FEATURE_WLAN_EXTSCAN */ + cdf_wake_lock_init(&wma_handle->wow_wake_lock, "wlan_wow_wl"); + } + + /* attach the wmi */ + wmi_handle = wmi_unified_attach(wma_handle, + wma_process_fw_event_handler); + if (!wmi_handle) { + WMA_LOGP("%s: failed to attach WMI", __func__); + cdf_status = CDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + WMA_LOGA("WMA --> wmi_unified_attach - success"); + + /* Save the WMI & HTC handle */ + wma_handle->wmi_handle = wmi_handle; + wma_handle->htc_handle = htc_handle; + wma_handle->cds_context = cds_context; + wma_handle->cdf_dev = cdf_dev; + wma_handle->max_scan = mac_params->max_scan; + + /* initialize default target config */ + wma_set_default_tgt_config(wma_handle); + + olCfg.is_uc_offload_enabled = mac_params->ucOffloadEnabled; + olCfg.uc_tx_buffer_count = mac_params->ucTxBufCount; + olCfg.uc_tx_buffer_size = mac_params->ucTxBufSize; + olCfg.uc_rx_indication_ring_count = mac_params->ucRxIndRingCount; + olCfg.uc_tx_partition_base = mac_params->ucTxPartitionBase; + + + wma_handle->tx_chain_mask_cck = mac_params->tx_chain_mask_cck; + wma_handle->self_gen_frm_pwr = mac_params->self_gen_frm_pwr; + + /* Allocate cfg handle */ + + /* RX Full reorder should enable for PCIe, ROME3.X project only now + * MDM should enable later, schedule TBD + * HL also sdould be enabled, schedule TBD + */ +#ifdef WLAN_FEATURE_RX_FULL_REORDER_OL + olCfg.is_full_reorder_offload = mac_params->reorderOffload; +#else + olCfg.is_full_reorder_offload = 0; +#endif /* WLAN_FEATURE_RX_FULL_REORDER_OL */ + olCfg.enable_rxthread = mac_params->enable_rxthread; + olCfg.ip_tcp_udp_checksum_offload = + mac_params->ip_tcp_udp_checksum_offload; + olCfg.ce_classify_enabled = mac_params->ce_classify_enabled; + + ol_cfg_set_flow_control_parameters(&olCfg, mac_params); + + ((p_cds_contextType) cds_context)->cfg_ctx = + ol_pdev_cfg_attach(((p_cds_contextType) cds_context)->cdf_ctx, + olCfg); + if (!(((p_cds_contextType) cds_context)->cfg_ctx)) { + WMA_LOGP("%s: failed to init cfg handle", __func__); + cdf_status = CDF_STATUS_E_NOMEM; + goto err_wmi_handle; + } + + /* adjust the cfg_ctx default value based on setting */ + ol_set_cfg_rx_fwd_disabled((ol_pdev_handle) + ((p_cds_contextType) cds_context)->cfg_ctx, + (uint8_t) mac_params->apDisableIntraBssFwd); + + /* adjust the packet log enable default value based on CFG INI setting */ + ol_set_cfg_packet_log_enabled((ol_pdev_handle) + ((p_cds_contextType) cds_context)-> + cfg_ctx, + (uint8_t)cds_is_packet_log_enabled()); + + /* Allocate dfs_ic and initialize DFS */ + wma_handle->dfs_ic = wma_dfs_attach(wma_handle->dfs_ic); + if (wma_handle->dfs_ic == NULL) { + WMA_LOGE("%s: Memory allocation failed for dfs_ic", __func__); + goto err_wmi_handle; + } +#if defined(QCA_WIFI_FTM) + if (cds_get_conparam() == CDF_FTM_MODE) + wma_utf_attach(wma_handle); +#endif /* QCA_WIFI_FTM */ + + /*TODO: Recheck below parameters */ + scn = cds_get_context(CDF_MODULE_ID_HIF); + + if (NULL == scn) { + WMA_LOGE("%s: Failed to get scn", __func__); + cdf_status = CDF_STATUS_E_NOMEM; + goto err_scn_context; + } + + mac_params->maxStation = ol_get_number_of_peers_supported(scn); + + mac_params->maxBssId = WMA_MAX_SUPPORTED_BSS; + mac_params->frameTransRequired = 0; + + wma_handle->wlan_resource_config.num_wow_filters = + mac_params->maxWoWFilters; + wma_handle->wlan_resource_config.num_keep_alive_pattern = + WMA_MAXNUM_PERIODIC_TX_PTRNS; + + /* The current firmware implementation requires the number of + * offload peers should be (number of vdevs + 1). + */ + wma_handle->wlan_resource_config.num_offload_peers = + mac_params->apMaxOffloadPeers + 1; + + wma_handle->wlan_resource_config.num_offload_reorder_buffs = + mac_params->apMaxOffloadReorderBuffs + 1; + + wma_handle->ol_ini_info = mac_params->olIniInfo; + wma_handle->max_station = mac_params->maxStation; + wma_handle->max_bssid = mac_params->maxBssId; + wma_handle->frame_xln_reqd = mac_params->frameTransRequired; + wma_handle->driver_type = mac_params->driverType; + wma_handle->ssdp = mac_params->ssdp; +#ifdef FEATURE_WLAN_RA_FILTERING + wma_handle->IsRArateLimitEnabled = mac_params->IsRArateLimitEnabled; + wma_handle->RArateLimitInterval = mac_params->RArateLimitInterval; +#endif /* FEATURE_WLAN_RA_FILTERING */ +#ifdef WLAN_FEATURE_LPSS + wma_handle->is_lpass_enabled = mac_params->is_lpass_enabled; +#endif + wma_set_nan_enable(wma_handle, mac_params); + /* + * Indicates if DFS Phyerr filtering offload + * is Enabled/Disabed from ini + */ + wma_handle->dfs_phyerr_filter_offload = + mac_params->dfsPhyerrFilterOffload; + wma_handle->dfs_pri_multiplier = mac_params->dfsRadarPriMultiplier; + wma_handle->interfaces = cdf_mem_malloc(sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + if (!wma_handle->interfaces) { + WMA_LOGP("%s: failed to allocate interface table", __func__); + cdf_status = CDF_STATUS_E_NOMEM; + goto err_scn_context; + } + cdf_mem_zero(wma_handle->interfaces, sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + /* Register the debug print event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_PRINT_EVENTID, + wma_unified_debug_print_event_handler); + + wma_handle->tgt_cfg_update_cb = tgt_cfg_cb; + wma_handle->dfs_radar_indication_cb = radar_ind_cb; + wma_handle->old_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->new_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->saved_wmi_init_cmd.buf = NULL; + + cdf_status = cdf_event_init(&wma_handle->wma_ready_event); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: wma_ready_event initialization failed", __func__); + goto err_event_init; + } + cdf_status = cdf_event_init(&wma_handle->target_suspend); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: target suspend event initialization failed", + __func__); + goto err_event_init; + } + + /* Init Tx Frame Complete event */ + cdf_status = cdf_event_init(&wma_handle->tx_frm_download_comp_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("%s: failed to init tx_frm_download_comp_event", + __func__); + goto err_event_init; + } + + /* Init tx queue empty check event */ + cdf_status = cdf_event_init(&wma_handle->tx_queue_empty_event); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGP("%s: failed to init tx_queue_empty_event", __func__); + goto err_event_init; + } + + cdf_status = cdf_event_init(&wma_handle->wma_resume_event); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: wma_resume_event initialization failed", + __func__); + goto err_event_init; + } + + cdf_status = cdf_event_init(&wma_handle->recovery_event); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: recovery event initialization failed", __func__); + goto err_event_init; + } + + INIT_LIST_HEAD(&wma_handle->vdev_resp_queue); + cdf_spinlock_init(&wma_handle->vdev_respq_lock); + cdf_list_init(&wma_handle->wma_hold_req_queue, + MAX_ENTRY_HOLD_REQ_QUEUE); + cdf_spinlock_init(&wma_handle->wma_hold_req_q_lock); + cdf_atomic_init(&wma_handle->is_wow_bus_suspended); + cdf_atomic_init(&wma_handle->scan_id_counter); + + /* Register vdev start response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_START_RESP_EVENTID, + wma_vdev_start_resp_handler); + + /* Register vdev stop response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_STOPPED_EVENTID, + wma_vdev_stop_resp_handler); + + /* register for STA kickout function */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_STA_KICKOUT_EVENTID, + wma_peer_sta_kickout_event_handler); + + /* register for stats response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_STATS_EVENTID, + wma_stats_event_handler); + /* register for linkspeed response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID, + wma_link_speed_event_handler); + +#ifdef FEATURE_OEM_DATA_SUPPORT + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OEM_CAPABILITY_EVENTID, + wma_oem_capability_event_callback); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OEM_MEASUREMENT_REPORT_EVENTID, + wma_oem_measurement_report_event_callback); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OEM_ERROR_REPORT_EVENTID, + wma_oem_error_report_event_callback); +#endif /* FEATURE_OEM_DATA_SUPPORT */ + /* + * Register appropriate DFS phyerr event handler for + * Phyerror events. Handlers differ for phyerr filtering + * offload enable and disable cases. + */ + wma_register_dfs_event_handler(wma_handle); + + /* Register peer change event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_STATE_EVENTID, + wma_peer_state_change_event_handler); + + /* Register beacon tx complete event id. The event is required + * for sending channel switch announcement frames + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID, + wma_unified_bcntx_status_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_VDEV_RATE_STATS_EVENTID, + wma_link_status_event_handler); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + /* Register event handler for processing Link Layer Stats + * response from the FW + */ + wma_register_ll_stats_event_handler(wma_handle); + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + /* + * Register event handler to receive firmware mem dump + * copy complete indication + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_FW_MEM_DUMP_EVENTID, + wma_fw_mem_dump_event_handler); + + /* Firmware debug log */ + cdf_status = dbglog_init(wma_handle->wmi_handle); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Firmware Dbglog initialization failed", __func__); + goto err_dbglog_init; + } + + /* + * Update Powersave mode + * 1 - Legacy Powersave + Deepsleep Disabled + * 2 - QPower + Deepsleep Disabled + * 3 - Legacy Powersave + Deepsleep Enabled + * 4 - QPower + Deepsleep Enabled + */ + wma_handle->powersave_mode = mac_params->powersaveOffloadEnabled; + wma_handle->staMaxLIModDtim = mac_params->staMaxLIModDtim; + wma_handle->staModDtim = mac_params->staModDtim; + wma_handle->staDynamicDtim = mac_params->staDynamicDtim; + + /* + * Value of mac_params->wowEnable can be, + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic patter and pattern byte match on + * all interfaces. + */ + wma_handle->wow.magic_ptrn_enable = + (mac_params->wowEnable & 0x01) ? true : false; + wma_handle->ptrn_match_enable_all_vdev = + (mac_params->wowEnable & 0x02) ? true : false; + +#ifdef FEATURE_WLAN_TDLS + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TDLS_PEER_EVENTID, + wma_tdls_event_handler); +#endif /* FEATURE_WLAN_TDLS */ + + /* register for install key completion event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + wma_vdev_install_key_complete_event_handler); +#ifdef WLAN_FEATURE_NAN + /* register for nan response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NAN_EVENTID, + wma_nan_rsp_event_handler); +#endif /* WLAN_FEATURE_NAN */ + +#ifdef WLAN_FEATURE_STATS_EXT + /* register for extended stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_STATS_EXT_EVENTID, + wma_stats_ext_event_handler); +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef FEATURE_WLAN_EXTSCAN + wma_register_extscan_event_handler(wma_handle); +#endif /* WLAN_FEATURE_STATS_EXT */ + + WMA_LOGD("%s: Exit", __func__); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_ROAM_SYNCH_EVENTID, + wma_roam_synch_event_handler); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RSSI_BREACH_EVENTID, + wma_rssi_breached_event_handler); + + /* Register peer assoc conf event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_ASSOC_CONF_EVENTID, + wma_peer_assoc_conf_handler); + + return CDF_STATUS_SUCCESS; + +err_dbglog_init: + cdf_spinlock_destroy(&wma_handle->vdev_respq_lock); + cdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock); +err_event_init: + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_PRINT_EVENTID); + cdf_mem_free(wma_handle->interfaces); +err_scn_context: + wma_dfs_detach(wma_handle->dfs_ic); +#if defined(QCA_WIFI_FTM) + wma_utf_detach(wma_handle); +#endif /* QCA_WIFI_FTM */ +err_wmi_handle: + cdf_mem_free(((p_cds_contextType) cds_context)->cfg_ctx); + OS_FREE(wmi_handle); + +err_wma_handle: + + if (cds_get_conparam() != CDF_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + cdf_wake_lock_destroy(&wma_handle->pno_wake_lock); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + cdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + cdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + } + cds_free_context(cds_context, CDF_MODULE_ID_WMA, wma_handle); + + WMA_LOGD("%s: Exit", __func__); + + return cdf_status; +} + +/** + * wma_pre_start() - wma pre start + * @cds_ctx: cds context + * + * Return: 0 on success, errno on failure + */ +CDF_STATUS wma_pre_start(void *cds_ctx) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + A_STATUS status = A_OK; + tp_wma_handle wma_handle; + cds_msg_t wma_msg = { 0 }; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + /* Validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: invalid argument", __func__); + cdf_status = CDF_STATUS_E_INVAL; + goto end; + } + /* Open endpoint for ctrl path - WMI <--> HTC */ + status = wmi_unified_connect_htc_service(wma_handle->wmi_handle, + wma_handle->htc_handle); + if (A_OK != status) { + WMA_LOGP("%s: wmi_unified_connect_htc_service", __func__); + cdf_status = CDF_STATUS_E_FAULT; + goto end; + } + + WMA_LOGA("WMA --> wmi_unified_connect_htc_service - success"); + + /* Trigger the CFG DOWNLOAD */ + wma_msg.type = WNI_CFG_DNLD_REQ; + wma_msg.bodyptr = NULL; + wma_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &wma_msg); + if (CDF_STATUS_SUCCESS != cdf_status) { + WMA_LOGP("%s: Failed to post WNI_CFG_DNLD_REQ msg", __func__); + CDF_ASSERT(0); + cdf_status = CDF_STATUS_E_FAILURE; + } +end: + WMA_LOGD("%s: Exit", __func__); + return cdf_status; +} + +/** + * wma_send_msg() - Send wma message to PE. + * @wma_handle: wma handle + * @msg_type: message type + * @body_ptr: message body ptr + * @body_val: message body value + * + * Return: none + */ +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val) +{ + tSirMsgQ msg = { 0 }; + uint32_t status = CDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + msg.type = msg_type; + msg.bodyval = body_val; + msg.bodyptr = body_ptr; + status = lim_post_msg_api(pMac, &msg); + if (CDF_STATUS_SUCCESS != status) { + if (NULL != body_ptr) + cdf_mem_free(body_ptr); + CDF_ASSERT(0); + } + return; +} + +/** + * wma_set_base_macaddr_indicate() - set base mac address in fw + * @wma_handle: wma handle + * @customAddr: base mac address + * + * Return: 0 for success or error code + */ +static int wma_set_base_macaddr_indicate(tp_wma_handle wma_handle, + tSirMacAddr *customAddr) +{ + wmi_pdev_set_base_macaddr_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set_base_macaddr cmd"); + return -ENOMEM; + } + + cmd = (wmi_pdev_set_base_macaddr_cmd_fixed_param *) wmi_buf_data(buf); + cdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_base_macaddr_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(*customAddr, &cmd->base_macaddr); + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), + WMI_PDEV_SET_BASE_MACADDR_CMDID); + if (err) { + WMA_LOGE("Failed to send set_base_macaddr cmd"); + cdf_mem_free(buf); + return -EIO; + } + WMA_LOGD("Base MAC Addr: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY((*customAddr))); + + return 0; +} + +/** + * wma_log_supported_evt_handler() - Enable/Disable FW diag/log events + * @handle: WMA handle + * @event: Event received from FW + * @len: Length of the event + * + * Enables the low frequency events and disables the high frequency + * events. Bit 17 indicates if the event if low/high frequency. + * 1 - high frequency, 0 - low frequency + * + * Return: 0 on successfully enabling/disabling the events + */ +static int wma_log_supported_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + uint32_t num_of_diag_events_logs; + wmi_diag_event_log_config_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t *cmd_args, *evt_args; + uint32_t buf_len, i; + + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *param_buf; + wmi_diag_event_log_supported_event_fixed_params *wmi_event; + + WMA_LOGI("Received WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID"); + + param_buf = (WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid log supported event buffer"); + return -EINVAL; + } + wmi_event = param_buf->fixed_param; + num_of_diag_events_logs = wmi_event->num_of_diag_events_logs; + evt_args = param_buf->diag_events_logs_list; + if (!evt_args) { + WMA_LOGE("%s: Event list is empty, num_of_diag_events_logs=%d", + __func__, num_of_diag_events_logs); + return -EINVAL; + } + + WMA_LOGD("%s: num_of_diag_events_logs=%d", + __func__, num_of_diag_events_logs); + + /* Free any previous allocation */ + if (wma->events_logs_list) + cdf_mem_free(wma->events_logs_list); + + /* Store the event list for run time enable/disable */ + wma->events_logs_list = cdf_mem_malloc(num_of_diag_events_logs * + sizeof(uint32_t)); + if (!wma->events_logs_list) { + WMA_LOGE("%s: event log list memory allocation failed", + __func__); + return -ENOMEM; + } + wma->num_of_diag_events_logs = num_of_diag_events_logs; + + /* Prepare the send buffer */ + buf_len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + (num_of_diag_events_logs * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wma->wmi_handle, buf_len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + cdf_mem_free(wma->events_logs_list); + wma->events_logs_list = NULL; + return -ENOMEM; + } + + cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_diag_event_log_config_fixed_param)); + + cmd->num_of_diag_events_logs = num_of_diag_events_logs; + + buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (num_of_diag_events_logs * sizeof(uint32_t))); + + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Populate the events */ + for (i = 0; i < num_of_diag_events_logs; i++) { + /* Low freq (0) - Enable (1) the event + * High freq (1) - Disable (0) the event + */ + WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[i], + !(WMI_DIAG_FREQUENCY_GET(evt_args[i]))); + /* Set the event ID */ + WMI_DIAG_ID_SET(cmd_args[i], + WMI_DIAG_ID_GET(evt_args[i])); + /* Set the type */ + WMI_DIAG_TYPE_SET(cmd_args[i], + WMI_DIAG_TYPE_GET(evt_args[i])); + /* Storing the event/log list in WMA */ + wma->events_logs_list[i] = evt_args[i]; + } + + if (wmi_unified_cmd_send(wma->wmi_handle, buf, buf_len, + WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) { + WMA_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed", + __func__); + wmi_buf_free(buf); + /* Not clearing events_logs_list, though wmi cmd failed. + * Host can still have this list + */ + return -EINVAL; + } + + return 0; +} + +/** + * wma_flush_complete_evt_handler() - FW log flush complete event handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + */ +static int wma_flush_complete_evt_handler(void *handle, + u_int8_t *event, + u_int32_t len) +{ + CDF_STATUS status; + tp_wma_handle wma = (tp_wma_handle) handle; + + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *param_buf; + wmi_debug_mesg_flush_complete_fixed_param *wmi_event; + uint32_t reason_code; + + param_buf = (WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid log flush complete event buffer"); + return CDF_STATUS_E_FAILURE; + } + + wmi_event = param_buf->fixed_param; + reason_code = wmi_event->reserved0; + + /* + * reason_code = 0; Flush event in response to flush command + * reason_code = other value; Asynchronous flush event for fatal events + */ + if (!reason_code && (cds_is_log_report_in_progress() == false)) { + WMA_LOGE("Received WMI flush event without sending CMD"); + return -EINVAL; + } else if (!reason_code && cds_is_log_report_in_progress() == true) { + /* Flush event in response to flush command */ + WMA_LOGI("Received WMI flush event in response to flush CMD"); + status = cdf_mc_timer_stop(&wma->log_completion_timer); + if (status != CDF_STATUS_SUCCESS) + WMA_LOGE("Failed to stop the log completion timeout"); + cds_logging_set_fw_flush_complete(); + } else if (reason_code && cds_is_log_report_in_progress() == false) { + /* Asynchronous flush event for fatal events */ + WMA_LOGE("Received asynchronous WMI flush event: reason=%d", + reason_code); + status = cds_set_log_completion(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, + reason_code); + if (CDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to set log trigger params", + __func__); + return CDF_STATUS_E_FAILURE; + } + cds_logging_set_fw_flush_complete(); + return status; + } else { + /* Asynchronous flush event for fatal event, + * but, report in progress already + */ + WMA_LOGI("%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, reason_code); + return CDF_STATUS_E_FAILURE; + } + return 0; +} + +/** + * wma_soc_set_hw_mode_resp_evt_handler() - Set HW mode resp evt handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + * Event handler for WMI_SOC_SET_HW_MODE_RESP_EVENTID that is sent to host + * driver in response to a WMI_SOC_SET_HW_MODE_CMDID being sent to WLAN firmware + * + * Return: Success on receiving valid params from FW + */ +static int wma_soc_set_hw_mode_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_SOC_SET_HW_MODE_RESP_EVENTID_param_tlvs *param_buf; + wmi_soc_set_hw_mode_response_event_fixed_param *wmi_event; + wmi_soc_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + uint32_t i; + struct sir_set_hw_mode_resp *hw_mode_resp; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* Since WMA handle itself is NULL, we cannot send fail + * response back to LIM here + */ + return CDF_STATUS_E_NULL_VALUE; + } + + hw_mode_resp = cdf_mem_malloc(sizeof(*hw_mode_resp)); + if (!hw_mode_resp) { + WMA_LOGI("%s: Memory allocation failed", __func__); + /* Since this memory allocation itself failed, we cannot + * send fail response back to LIM here + */ + return CDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_SOC_SET_HW_MODE_RESP_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid WMI_SOC_SET_HW_MODE_RESP_EVENTID event"); + /* Need to send response back to upper layer to free + * active command list + */ + goto fail; + } + + wmi_event = param_buf->fixed_param; + hw_mode_resp->status = wmi_event->status; + hw_mode_resp->cfgd_hw_mode_index = wmi_event->cfgd_hw_mode_index; + hw_mode_resp->num_vdev_mac_entries = wmi_event->num_vdev_mac_entries; + + WMA_LOGI("%s: status:%d cfgd_hw_mode_index:%d num_vdev_mac_entries:%d", + __func__, wmi_event->status, + wmi_event->cfgd_hw_mode_index, + wmi_event->num_vdev_mac_entries); + vdev_mac_entry = + param_buf->wmi_soc_set_hw_mode_response_vdev_mac_mapping; + + /* Store the vdev-mac map in WMA and prepare to send to PE */ + for (i = 0; i < wmi_event->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id; + vdev_id = vdev_mac_entry[i].vdev_id; + mac_id = vdev_mac_entry[i].mac_id; + + WMA_LOGI("%s: vdev_id:%d mac_id:%d", + __func__, vdev_id, mac_id); + + hw_mode_resp->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_resp->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + wmi_event->cfgd_hw_mode_index); + } + + if (hw_mode_resp->status == SET_HW_MODE_STATUS_OK) { + if (WMA_DEFAULT_HW_MODE_INDEX == wma->new_hw_mode_index) { + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } else { + wma->old_hw_mode_index = wma->new_hw_mode_index; + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } + } + + WMA_LOGI("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, wma->old_hw_mode_index, wma->new_hw_mode_index); + + wma_send_msg(wma, SIR_HAL_SOC_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return CDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Sending fail response to LIM", __func__); + hw_mode_resp->status = SET_HW_MODE_STATUS_ECANCELED; + hw_mode_resp->cfgd_hw_mode_index = 0; + hw_mode_resp->num_vdev_mac_entries = 0; + wma_send_msg(wma, SIR_HAL_SOC_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wma_soc_hw_mode_transition_evt_handler() - HW mode transition evt handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + * Event handler for WMI_SOC_HW_MODE_TRANSITION_EVENTID that indicates an + * asynchronous hardware mode transition. This event notifies the host driver + * that firmware independently changed the hardware mode for some reason, such + * as Coex, LFR 3.0, etc + * + * Return: Success on receiving valid params from FW + */ +static int wma_soc_hw_mode_transition_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + uint32_t i; + WMI_SOC_HW_MODE_TRANSITION_EVENTID_param_tlvs *param_buf; + wmi_soc_hw_mode_transition_event_fixed_param *wmi_event; + wmi_soc_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + struct sir_hw_mode_trans_ind *hw_mode_trans_ind; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma) { + /* This is an async event. So, not sending any event to LIM */ + WMA_LOGE("Invalid WMA handle"); + return CDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_SOC_HW_MODE_TRANSITION_EVENTID_param_tlvs *) event; + if (!param_buf) { + /* This is an async event. So, not sending any event to LIM */ + WMA_LOGE("Invalid WMI_SOC_HW_MODE_TRANSITION_EVENTID event"); + return CDF_STATUS_E_FAILURE; + } + + hw_mode_trans_ind = cdf_mem_malloc(sizeof(*hw_mode_trans_ind)); + if (!hw_mode_trans_ind) { + WMA_LOGI("%s: Memory allocation failed", __func__); + return CDF_STATUS_E_NULL_VALUE; + } + + wmi_event = param_buf->fixed_param; + hw_mode_trans_ind->old_hw_mode_index = wmi_event->old_hw_mode_index; + hw_mode_trans_ind->new_hw_mode_index = wmi_event->new_hw_mode_index; + hw_mode_trans_ind->num_vdev_mac_entries = + wmi_event->num_vdev_mac_entries; + WMA_LOGI("%s: old_hw_mode_index:%d new_hw_mode_index:%d entries=%d", + __func__, wmi_event->old_hw_mode_index, + wmi_event->new_hw_mode_index, wmi_event->num_vdev_mac_entries); + + vdev_mac_entry = + param_buf->wmi_soc_set_hw_mode_response_vdev_mac_mapping; + + /* Store the vdev-mac map in WMA and prepare to send to HDD */ + for (i = 0; i < wmi_event->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id; + vdev_id = vdev_mac_entry[i].vdev_id; + mac_id = vdev_mac_entry[i].mac_id; + + WMA_LOGI("%s: vdev_id:%d mac_id:%d", + __func__, vdev_id, mac_id); + + hw_mode_trans_ind->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_trans_ind->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + wmi_event->new_hw_mode_index); + } + wma->old_hw_mode_index = wmi_event->old_hw_mode_index; + wma->new_hw_mode_index = wmi_event->new_hw_mode_index; + + WMA_LOGI("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, wma->old_hw_mode_index, wma->new_hw_mode_index); + + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_SOC_HW_MODE_TRANS_IND, + (void *) hw_mode_trans_ind, 0); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_soc_set_dual_mode_config_resp_evt_handler() - Dual mode evt handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + * Notifies the host driver of the completion or failure of a + * WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID command. This event would be returned to + * the host driver once the firmware has completed a reconfiguration of the Scan + * and FW mode configuration. This changes could include entering or leaving a + * dual mac configuration for either scan and/or more permanent firmware mode. + * + * Return: Success on receiving valid params from FW + */ +static int wma_soc_set_dual_mode_config_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID_param_tlvs *param_buf; + wmi_soc_set_dual_mac_config_response_event_fixed_param *wmi_event; + tp_wma_handle wma = (tp_wma_handle) handle; + struct sir_dual_mac_config_resp *dual_mac_cfg_resp; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* Since the WMA handle is NULL, we cannot send resp to LIM. + * So, returning from here. + */ + return CDF_STATUS_E_NULL_VALUE; + } + + dual_mac_cfg_resp = cdf_mem_malloc(sizeof(*dual_mac_cfg_resp)); + if (!dual_mac_cfg_resp) { + WMA_LOGE("%s: Memory allocation failed", __func__); + /* Since the mem alloc failed, we cannot send resp to LIM. + * So, returning from here. + */ + return CDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID_param_tlvs *) + event; + if (!param_buf) { + WMA_LOGE("%s: Invalid event", __func__); + goto fail; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGI("%s: status:%d", __func__, wmi_event->status); + dual_mac_cfg_resp->status = wmi_event->status; + + if (SET_HW_MODE_STATUS_OK == dual_mac_cfg_resp->status) { + wma->dual_mac_cfg.prev_scan_config = + wma->dual_mac_cfg.cur_scan_config; + wma->dual_mac_cfg.prev_fw_mode_config = + wma->dual_mac_cfg.cur_fw_mode_config; + wma->dual_mac_cfg.cur_scan_config = + wma->dual_mac_cfg.req_scan_config; + wma->dual_mac_cfg.cur_fw_mode_config = + wma->dual_mac_cfg.req_fw_mode_config; + } + + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_SOC_DUAL_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return CDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Sending fail response to LIM", __func__); + dual_mac_cfg_resp->status = SET_HW_MODE_STATUS_ECANCELED; + wma_send_msg(wma, SIR_HAL_SOC_DUAL_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return CDF_STATUS_E_FAILURE; + +} + +/** + * wma_start() - wma start function. + * Intialize event handlers and timers. + * @cds_ctx: cds context + * + * Return: 0 on success, CDF Error on failure + */ +CDF_STATUS wma_start(void *cds_ctx) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + int status; + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid handle", __func__); + cdf_status = CDF_STATUS_E_INVAL; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_SCAN_EVENTID, + wma_scan_event_callback); + if (0 != status) { + WMA_LOGP("%s: Failed to register scan callback", __func__); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_ROAM_EVENTID, + wma_roam_event_callback); + if (0 != status) { + WMA_LOGP("%s: Failed to register Roam callback", __func__); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WOW_WAKEUP_HOST_EVENTID, + wma_wow_wakeup_host_event); + if (status) { + WMA_LOGP("%s: Failed to register wow wakeup host event handler", + __func__); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_RESUME_EVENTID, + wma_pdev_resume_event_handler); + if (status) { + WMA_LOGP("%s: Failed to register PDEV resume event handler", + __func__); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + +#ifdef FEATURE_WLAN_SCAN_PNO + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_NLO)) { + + WMA_LOGD("FW supports pno offload, registering nlo match handler"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NLO_MATCH_EVENTID, + wma_nlo_match_evt_handler); + if (status) { + WMA_LOGE("Failed to register nlo match event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NLO_SCAN_COMPLETE_EVENTID, + wma_nlo_scan_cmp_evt_handler); + if (status) { + WMA_LOGE("Failed to register nlo scan comp event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + } +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + WMA_LOGE("MCC TX Pause Event Handler register"); + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TX_PAUSE_EVENTID, + wma_mcc_vdev_tx_pause_evt_handler); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef FEATURE_WLAN_CH_AVOID + WMA_LOGD("Registering channel to avoid handler"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WLAN_FREQ_AVOID_EVENTID, + wma_channel_avoid_evt_handler); + if (status) { + WMA_LOGE("Failed to register channel to avoid event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + WMA_LOGD("Registering auto shutdown handler"); + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_HOST_AUTO_SHUTDOWN_EVENTID, + wma_auto_shutdown_event_handler); + if (status) { + WMA_LOGE("Failed to register WMI Auto shutdown event handler"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_THERMAL_MGMT_EVENTID, + wma_thermal_mgmt_evt_handler); + if (status) { + WMA_LOGE("Failed to register thermal mitigation event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + status = wma_ocb_register_event_handlers(wma_handle); + if (status) { + WMA_LOGE("Failed to register ocb event handlers"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + cdf_status = CDF_STATUS_SUCCESS; + +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt attach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt attach. + */ + if (cds_get_conparam() == CDF_FTM_MODE) + goto end; +#endif /* QCA_WIFI_FTM */ + + cdf_status = wma_tx_attach(wma_handle); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Failed to register tx management", __func__); + goto end; + } + + /* Initialize log completion timeout */ + cdf_status = cdf_mc_timer_init(&wma_handle->log_completion_timer, + CDF_TIMER_TYPE_SW, + wma_log_completion_timeout, + wma_handle); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to initialize log completion timeout"); + goto end; + } + + /* Initialize the get temperature event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_TEMPERATURE_EVENTID, + wma_pdev_temperature_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register get_temperature event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the log flush complete event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID, + wma_flush_complete_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register log flush complete event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the WMI_SOC_SET_HW_MODE_RESP_EVENTID event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_SOC_SET_HW_MODE_RESP_EVENTID, + wma_soc_set_hw_mode_resp_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register set hw mode resp event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the WMI_SOC_HW_MODE_TRANSITION_EVENTID event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_SOC_HW_MODE_TRANSITION_EVENTID, + wma_soc_hw_mode_transition_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the set dual mac configuration event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID, + wma_soc_set_dual_mode_config_resp_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + cdf_status = CDF_STATUS_E_FAILURE; + goto end; + } + + cdf_status = cdf_event_init(&wma_handle->service_ready_ext_evt); + if (CDF_STATUS_SUCCESS != cdf_status) { + WMA_LOGE("Unable to init service_ready_ext_evt"); + goto end; + } + +end: + WMA_LOGD("%s: Exit", __func__); + return cdf_status; +} + +/** + * wma_stop() - wma stop function. + * cleanup timers and suspend target. + * @cds_ctx: cds context + * @reason: reason for wma_stop. + * + * Return: 0 on success, CDF Error on failure + */ +CDF_STATUS wma_stop(void *cds_ctx, uint8_t reason) +{ + tp_wma_handle wma_handle; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + WMA_LOGD("%s: Enter", __func__); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid handle", __func__); + cdf_status = CDF_STATUS_E_INVAL; + goto end; + } +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt detach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt detach. + */ + if (cds_get_conparam() == CDF_FTM_MODE) { + cdf_status = CDF_STATUS_SUCCESS; + goto end; + } +#endif /* QCA_WIFI_FTM */ + + if (wma_handle->ack_work_ctx) { + cds_flush_work(&wma_handle->ack_work_ctx->ack_cmp_work); + cdf_mem_free(wma_handle->ack_work_ctx); + wma_handle->ack_work_ctx = NULL; + } + + /* Destroy the timer for log completion */ + cdf_status = cdf_mc_timer_destroy(&wma_handle->log_completion_timer); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to destroy the log completion timer"); + } + + /* There's no need suspend target which is already down during SSR. */ + if (!cds_is_logp_in_progress()) { +#ifdef HIF_USB + /* Suspend the target and enable interrupt */ + if (wma_suspend_target(wma_handle, 0)) + WMA_LOGE("Failed to suspend target"); +#else + /* Suspend the target and disable interrupt */ + if (wma_suspend_target(wma_handle, 1)) + WMA_LOGE("Failed to suspend target"); +#endif /* HIF_USB */ + } + + cdf_status = wma_tx_detach(wma_handle); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Failed to deregister tx management", __func__); + goto end; + } + + cdf_status = cdf_event_destroy(&wma_handle->service_ready_ext_evt); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to destroy service_ready_ext_evt"); + goto end; + } + +end: + WMA_LOGD("%s: Exit", __func__); + return cdf_status; +} + +/** + * wma_cleanup_hold_req() - cleanup hold request queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_hold_req(tp_wma_handle wma) +{ + struct wma_target_req *req_msg = NULL; + cdf_list_node_t *node1 = NULL, *node2 = NULL; + CDF_STATUS status; + + cdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (CDF_STATUS_SUCCESS != cdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGI(FL("request queue maybe empty")); + return; + } + + do { + node1 = node2; + req_msg = (struct wma_target_req *)node1; + status = cdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (CDF_STATUS_SUCCESS != status) { + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("Failed to remove request for vdev_id %d type %d"), + req_msg->vdev_id, req_msg->type); + return; + } else { + cdf_mc_timer_destroy(&req_msg->event_timeout); + cdf_mem_free(req_msg); + } + } while (CDF_STATUS_SUCCESS == + cdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + cdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); +} + +/** + * wma_cleanup_vdev_resp() - cleanup vdev response queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_vdev_resp(tp_wma_handle wma) +{ + struct wma_target_req *msg, *tmp; + + cdf_spin_lock_bh(&wma->vdev_respq_lock); + list_for_each_entry_safe(msg, tmp, &wma->vdev_resp_queue, node) { + list_del(&msg->node); + cdf_mc_timer_destroy(&msg->event_timeout); + cdf_mem_free(msg); + } + cdf_spin_unlock_bh(&wma->vdev_respq_lock); +} + +/** + * wma_wmi_service_close() - close wma wmi service interface. + * @cds_ctx: cds context + * + * Return: 0 on success, CDF Error on failure + */ +CDF_STATUS wma_wmi_service_close(void *cds_ctx) +{ + tp_wma_handle wma_handle; + struct beacon_info *bcn; + int i; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return CDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return CDF_STATUS_E_INVAL; + } + + /* dettach the wmi serice */ + WMA_LOGD("calling wmi_unified_detach"); + wmi_unified_detach(wma_handle->wmi_handle); + wma_handle->wmi_handle = NULL; + + for (i = 0; i < wma_handle->max_bssid; i++) { + bcn = wma_handle->interfaces[i].beacon; + + if (bcn) { + if (bcn->dma_mapped) + cdf_nbuf_unmap_single(wma_handle->cdf_dev, + bcn->buf, CDF_DMA_TO_DEVICE); + cdf_nbuf_free(bcn->buf); + cdf_mem_free(bcn); + wma_handle->interfaces[i].beacon = NULL; + } + + if (wma_handle->interfaces[i].handle) { + cdf_mem_free(wma_handle->interfaces[i].handle); + wma_handle->interfaces[i].handle = NULL; + } + } + + cdf_mem_free(wma_handle->interfaces); + /* free the wma_handle */ + cds_free_context(wma_handle->cds_context, CDF_MODULE_ID_WMA, + wma_handle); + + cdf_mem_free(((p_cds_contextType) cds_ctx)->cfg_ctx); + WMA_LOGD("%s: Exit", __func__); + return CDF_STATUS_SUCCESS; +} + + + +/** + * wma_close() - wma close function. + * cleanup resources attached with wma. + * @cds_ctx: cds context + * + * Return: 0 on success, CDF Error on failure + */ +CDF_STATUS wma_close(void *cds_ctx) +{ + tp_wma_handle wma_handle; + uint32_t idx; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return CDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGP("%s: Invalid wmi handle", __func__); + return CDF_STATUS_E_INVAL; + } + + /* Free DBS list */ + if (wma_handle->hw_mode.hw_mode_list) { + cdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGI("%s: DBS list is freed", __func__); + } + + if (wma_handle->events_logs_list) { + cdf_mem_free(wma_handle->events_logs_list); + wma_handle->events_logs_list = NULL; + WMA_LOGD("%s: Event log list freed", __func__); + } + + if (wma_handle->saved_wmi_init_cmd.buf) { + wmi_buf_free(wma_handle->saved_wmi_init_cmd.buf); + wma_handle->saved_wmi_init_cmd.buf = NULL; + } + + if (cds_get_conparam() != CDF_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + cdf_wake_lock_destroy(&wma_handle->pno_wake_lock); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + cdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + cdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + } + + /* unregister Firmware debug log */ + cdf_status = dbglog_deinit(wma_handle->wmi_handle); + if (cdf_status != CDF_STATUS_SUCCESS) + WMA_LOGP("%s: dbglog_deinit failed", __func__); + + /* close the cdf events */ + cdf_event_destroy(&wma_handle->wma_ready_event); + cdf_event_destroy(&wma_handle->target_suspend); + cdf_event_destroy(&wma_handle->wma_resume_event); + cdf_event_destroy(&wma_handle->recovery_event); + wma_cleanup_vdev_resp(wma_handle); + wma_cleanup_hold_req(wma_handle); + for (idx = 0; idx < wma_handle->num_mem_chunks; ++idx) { + cdf_os_mem_free_consistent(wma_handle->cdf_dev, + wma_handle->mem_chunks[idx].len, + wma_handle->mem_chunks[idx].vaddr, + wma_handle->mem_chunks[idx].paddr, + cdf_get_dma_mem_context( + (&(wma_handle->mem_chunks[idx])), + memctx)); + } + +#if defined(QCA_WIFI_FTM) + /* Detach UTF and unregister the handler */ + if (cds_get_conparam() == CDF_FTM_MODE) + wma_utf_detach(wma_handle); +#endif /* QCA_WIFI_FTM */ + + if (NULL != wma_handle->dfs_ic) { + wma_dfs_detach(wma_handle->dfs_ic); + wma_handle->dfs_ic = NULL; + } + + if (NULL != wma_handle->pGetRssiReq) { + cdf_mem_free(wma_handle->pGetRssiReq); + wma_handle->pGetRssiReq = NULL; + } + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + wmi_desc_pool_deinit(wma_handle); + } + + WMA_LOGD("%s: Exit", __func__); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_update_fw_config() - update fw configuration + * @wma_handle: wma handle + * @tgt_cap: target capabality + * + * Return: none + */ +static void wma_update_fw_config(tp_wma_handle wma_handle, + struct wma_target_cap *tgt_cap) +{ + /* + * tgt_cap contains default target resource configuration + * which can be modified here, if required + */ + /* Override the no. of max fragments as per platform configuration */ + tgt_cap->wlan_resource_config.max_frag_entries = + CDF_MIN(QCA_OL_11AC_TX_MAX_FRAGS, + wma_handle->max_frag_entry); + wma_handle->max_frag_entry = + tgt_cap->wlan_resource_config.max_frag_entries; +} + +/** + * wma_alloc_host_mem_chunk() - allocate host memory + * @wma_handle: wma handle + * @req_id: request id + * @idx: index + * @num_units: number of units + * @unit_len: unit length + * + * allocate a chunk of memory at the index indicated and + * if allocation fail allocate smallest size possiblr and + * return number of units allocated. + * + * Return: number of units or 0 for error. + */ +static uint32_t wma_alloc_host_mem_chunk(tp_wma_handle wma_handle, + uint32_t req_id, uint32_t idx, + uint32_t num_units, uint32_t unit_len) +{ + cdf_dma_addr_t paddr; + if (!num_units || !unit_len) { + return 0; + } + wma_handle->mem_chunks[idx].vaddr = NULL; + /** reduce the requested allocation by half until allocation succeeds */ + while (wma_handle->mem_chunks[idx].vaddr == NULL && num_units) { + wma_handle->mem_chunks[idx].vaddr = + cdf_os_mem_alloc_consistent(wma_handle->cdf_dev, + num_units * unit_len, &paddr, + cdf_get_dma_mem_context( + (&(wma_handle->mem_chunks[idx])), + memctx)); + if (wma_handle->mem_chunks[idx].vaddr == NULL) { + num_units = (num_units >> 1);/* reduce length by half */ + } else { + wma_handle->mem_chunks[idx].paddr = paddr; + wma_handle->mem_chunks[idx].len = num_units * unit_len; + wma_handle->mem_chunks[idx].req_id = req_id; + } + } + return num_units; +} + +#define HOST_MEM_SIZE_UNIT 4 +/** + * wma_alloc_host_mem() - allocate amount of memory requested by FW. + * @wma_handle: wma handle + * @req_id: request id + * @num_units: number of units + * @unit_len: unit length + * + * Return: none + */ +static void wma_alloc_host_mem(tp_wma_handle wma_handle, uint32_t req_id, + uint32_t num_units, uint32_t unit_len) +{ + uint32_t remaining_units, allocated_units, idx; + + /* adjust the length to nearest multiple of unit size */ + unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) & + (~(HOST_MEM_SIZE_UNIT - 1)); + idx = wma_handle->num_mem_chunks; + remaining_units = num_units; + while (remaining_units) { + allocated_units = wma_alloc_host_mem_chunk(wma_handle, req_id, + idx, remaining_units, + unit_len); + if (allocated_units == 0) { + WMA_LOGE("FAILED TO ALLOCATED memory unit len %d" + " units requested %d units allocated %d ", + unit_len, num_units, + (num_units - remaining_units)); + wma_handle->num_mem_chunks = idx; + break; + } + remaining_units -= allocated_units; + ++idx; + if (idx == MAX_MEM_CHUNKS) { + WMA_LOGE("RWACHED MAX CHUNK LIMIT for memory units %d" + " unit len %d requested by FW," + " only allocated %d ", + num_units, unit_len, + (num_units - remaining_units)); + wma_handle->num_mem_chunks = idx; + break; + } + } + wma_handle->num_mem_chunks = idx; +} + +/** + * wma_update_target_services() - update target services from wma handle + * @wh: wma handle + * @cfg: target services + * + * Return: none + */ +static inline void wma_update_target_services(tp_wma_handle wh, + struct wma_tgt_services *cfg) +{ + /* STA power save */ + cfg->sta_power_save = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_STA_PWRSAVE); + + /* Enable UAPSD */ + cfg->uapsd = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_AP_UAPSD); + + /* Update AP DFS service */ + cfg->ap_dfs = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_AP_DFS); + + /* Enable 11AC */ + cfg->en_11ac = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_11AC); + if (cfg->en_11ac) + g_fw_wlan_feat_caps |= (1 << DOT11AC); + + /* Proactive ARP response */ + g_fw_wlan_feat_caps |= (1 << WLAN_PERIODIC_TX_PTRN); + + /* Enable WOW */ + g_fw_wlan_feat_caps |= (1 << WOW); + + /* ARP offload */ + cfg->arp_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_ARPNS_OFFLOAD); + + /* Adaptive early-rx */ + cfg->early_rx = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_EARLY_RX); +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NLO)) + cfg->pno_offload = true; +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef FEATURE_WLAN_EXTSCAN + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_EXTSCAN)) { + g_fw_wlan_feat_caps |= (1 << EXTENDED_SCAN); + } +#endif /* FEATURE_WLAN_EXTSCAN */ + cfg->lte_coex_ant_share = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT); +#ifdef FEATURE_WLAN_TDLS + /* Enable TDLS */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_TDLS)) { + cfg->en_tdls = 1; + g_fw_wlan_feat_caps |= (1 << TDLS); + } + /* Enable advanced TDLS features */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_OFFCHAN)) { + cfg->en_tdls_offchan = 1; + g_fw_wlan_feat_caps |= (1 << TDLS_OFF_CHANNEL); + } + + cfg->en_tdls_uapsd_buf_sta = + WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA); + cfg->en_tdls_uapsd_sleep_sta = + WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); +#endif /* FEATURE_WLAN_TDLS */ + if (WMI_SERVICE_IS_ENABLED + (wh->wmi_service_bitmap, WMI_SERVICE_BEACON_OFFLOAD)) + cfg->beacon_offload = true; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + /* Enable Roam Offload */ + cfg->en_roam_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_ROAM_HO_OFFLOAD); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NAN)) + g_fw_wlan_feat_caps |= (1 << NAN); +#endif /* WLAN_FEATURE_NAN */ + + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_RTT)) + g_fw_wlan_feat_caps |= (1 << RTT); +} + +/** + * wma_update_target_ht_cap() - update ht capabality from wma handle + * @wh: wma handle + * @cfg: ht capabality + * + * Return: none + */ +static inline void wma_update_target_ht_cap(tp_wma_handle wh, + struct wma_tgt_ht_cap *cfg) +{ + /* RX STBC */ + cfg->ht_rx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_RX_STBC); + + /* TX STBC */ + cfg->ht_tx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_TX_STBC); + + /* MPDU density */ + cfg->mpdu_density = wh->ht_cap_info & WMI_HT_CAP_MPDU_DENSITY; + + /* HT RX LDPC */ + cfg->ht_rx_ldpc = !!(wh->ht_cap_info & WMI_HT_CAP_LDPC); + + /* HT SGI */ + cfg->ht_sgi_20 = !!(wh->ht_cap_info & WMI_HT_CAP_HT20_SGI); + + cfg->ht_sgi_40 = !!(wh->ht_cap_info & WMI_HT_CAP_HT40_SGI); + + /* RF chains */ + cfg->num_rf_chains = wh->num_rf_chains; + + WMA_LOGD("%s: ht_cap_info - %x ht_rx_stbc - %d, ht_tx_stbc - %d\n\ + mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n\ + ht_sgi_40 - %d num_rf_chains - %d ", __func__, wh->ht_cap_info, + cfg->ht_rx_stbc, cfg->ht_tx_stbc, cfg->mpdu_density, + cfg->ht_rx_ldpc, cfg->ht_sgi_20, cfg->ht_sgi_40, + cfg->num_rf_chains); + +} + +#ifdef WLAN_FEATURE_11AC +/** + * wma_update_target_vht_cap() - update vht capabality from wma handle + * @wh: wma handle + * @cfg: vht capabality + * + * Return: none + */ +static inline void wma_update_target_vht_cap(tp_wma_handle wh, + struct wma_tgt_vht_cap *cfg) +{ + + if (wh->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (wh->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + cfg->vht_max_mpdu = 0; + + + if (wh->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + cfg->supp_chan_width |= 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (wh->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ) + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_160MHZ; + else + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + + cfg->vht_rx_ldpc = wh->vht_cap_info & WMI_VHT_CAP_RX_LDPC; + + cfg->vht_short_gi_80 = wh->vht_cap_info & WMI_VHT_CAP_SGI_80MHZ; + cfg->vht_short_gi_160 = wh->vht_cap_info & WMI_VHT_CAP_SGI_160MHZ; + + cfg->vht_tx_stbc = wh->vht_cap_info & WMI_VHT_CAP_TX_STBC; + + cfg->vht_rx_stbc = (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_1SS) | + (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_2SS) | + (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_3SS) ; + + cfg->vht_max_ampdu_len_exp = (wh->vht_cap_info & + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) + >> WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + + cfg->vht_su_bformer = wh->vht_cap_info & WMI_VHT_CAP_SU_BFORMER; + + cfg->vht_su_bformee = wh->vht_cap_info & WMI_VHT_CAP_SU_BFORMEE; + + cfg->vht_mu_bformer = wh->vht_cap_info & WMI_VHT_CAP_MU_BFORMER; + + cfg->vht_mu_bformee = wh->vht_cap_info & WMI_VHT_CAP_MU_BFORMEE; + + cfg->vht_txop_ps = wh->vht_cap_info & WMI_VHT_CAP_TXOP_PS; + + WMA_LOGD(" %s: max_mpdu %d supp_chan_width %x rx_ldpc %x\n \ + short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n \ + su_bformee %x mu_bformee %x max_ampdu_len_exp %d", __func__, + cfg->vht_max_mpdu, cfg->supp_chan_width, cfg->vht_rx_ldpc, + cfg->vht_short_gi_80, cfg->vht_tx_stbc, cfg->vht_rx_stbc, + cfg->vht_txop_ps, cfg->vht_su_bformee, cfg->vht_mu_bformee, + cfg->vht_max_ampdu_len_exp); +} +#endif /* #ifdef WLAN_FEATURE_11AC */ + +/** + * wma_update_hdd_cfg() - update HDD config + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_update_hdd_cfg(tp_wma_handle wma_handle) +{ + struct wma_tgt_cfg tgt_cfg; + void *hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD); + + tgt_cfg.reg_domain = wma_handle->reg_cap.eeprom_rd; + tgt_cfg.eeprom_rd_ext = wma_handle->reg_cap.eeprom_rd_ext; + + switch (wma_handle->phy_capability) { + case WMI_11G_CAPABILITY: + case WMI_11NG_CAPABILITY: + tgt_cfg.band_cap = eCSR_BAND_24; + break; + case WMI_11A_CAPABILITY: + case WMI_11NA_CAPABILITY: + case WMI_11AC_CAPABILITY: + tgt_cfg.band_cap = eCSR_BAND_5G; + break; + case WMI_11AG_CAPABILITY: + case WMI_11NAG_CAPABILITY: + default: + tgt_cfg.band_cap = eCSR_BAND_ALL; + } + + tgt_cfg.max_intf_count = wma_handle->wlan_resource_config.num_vdevs; + + cdf_mem_copy(tgt_cfg.hw_macaddr.bytes, wma_handle->hwaddr, + ATH_MAC_LEN); + + wma_update_target_services(wma_handle, &tgt_cfg.services); + wma_update_target_ht_cap(wma_handle, &tgt_cfg.ht_cap); +#ifdef WLAN_FEATURE_11AC + wma_update_target_vht_cap(wma_handle, &tgt_cfg.vht_cap); +#endif /* #ifdef WLAN_FEATURE_11AC */ + + tgt_cfg.target_fw_version = wma_handle->target_fw_version; +#ifdef WLAN_FEATURE_LPSS + tgt_cfg.lpss_support = wma_handle->lpss_support; +#endif /* WLAN_FEATURE_LPSS */ + tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support; + wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg); +} + +/** + * wma_setup_wmi_init_msg() - fill wmi init message buffer + * @wma_handle: wma handle + * @ev: ready event fixed params + * @param_buf: redy event TLVs + * @len: buffer length + * + * Return: wmi buffer or NULL for error + */ +static wmi_buf_t wma_setup_wmi_init_msg(tp_wma_handle wma_handle, + wmi_service_ready_event_fixed_param *ev, + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf, + uint32_t *len) +{ + wmi_buf_t buf; + wmi_init_cmd_fixed_param *cmd; + wlan_host_mem_req *ev_mem_reqs; + wmi_abi_version my_vers; + int num_whitelist; + uint8_t *buf_ptr; + wmi_resource_config *resource_cfg; + wlan_host_memory_chunk *host_mem_chunks; + uint32_t mem_chunk_len = 0; + uint16_t idx; + uint32_t num_units; + + *len = sizeof(*cmd) + sizeof(wmi_resource_config) + WMI_TLV_HDR_SIZE; + mem_chunk_len = (sizeof(wlan_host_memory_chunk) * MAX_MEM_CHUNKS); + buf = wmi_buf_alloc(wma_handle->wmi_handle, *len + mem_chunk_len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return NULL; + } + + ev_mem_reqs = param_buf->mem_reqs; + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_init_cmd_fixed_param *) buf_ptr; + resource_cfg = (wmi_resource_config *) (buf_ptr + sizeof(*cmd)); + host_mem_chunks = (wlan_host_memory_chunk *) + (buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config) + + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_init_cmd_fixed_param)); + + *resource_cfg = wma_handle->wlan_resource_config; + WMITLV_SET_HDR(&resource_cfg->tlv_header, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); + + /* allocate memory requested by FW */ + if (ev->num_mem_reqs > WMI_MAX_MEM_REQS) { + CDF_ASSERT(0); + cdf_nbuf_free(buf); + return NULL; + } + + cmd->num_host_mem_chunks = 0; + for (idx = 0; idx < ev->num_mem_reqs; ++idx) { + num_units = ev_mem_reqs[idx].num_units; + if (ev_mem_reqs[idx].num_unit_info & NUM_UNITS_IS_NUM_PEERS) { + /* + * number of units to allocate is number + * of peers, 1 extra for self peer on + * target. this needs to be fied, host + * and target can get out of sync + */ + num_units = resource_cfg->num_peers + 1; + } + WMA_LOGD + ("idx %d req %d num_units %d num_unit_info %d unit size %d actual units %d ", + idx, ev_mem_reqs[idx].req_id, + ev_mem_reqs[idx].num_units, + ev_mem_reqs[idx].num_unit_info, + ev_mem_reqs[idx].unit_size, num_units); + wma_alloc_host_mem(wma_handle, ev_mem_reqs[idx].req_id, + num_units, ev_mem_reqs[idx].unit_size); + } + for (idx = 0; idx < wma_handle->num_mem_chunks; ++idx) { + WMITLV_SET_HDR(&(host_mem_chunks[idx].tlv_header), + WMITLV_TAG_STRUC_wlan_host_memory_chunk, + WMITLV_GET_STRUCT_TLVLEN + (wlan_host_memory_chunk)); + host_mem_chunks[idx].ptr = wma_handle->mem_chunks[idx].paddr; + host_mem_chunks[idx].size = wma_handle->mem_chunks[idx].len; + host_mem_chunks[idx].req_id = + wma_handle->mem_chunks[idx].req_id; + WMA_LOGD("chunk %d len %d requested ,ptr 0x%x ", + idx, host_mem_chunks[idx].size, + host_mem_chunks[idx].ptr); + } + cmd->num_host_mem_chunks = wma_handle->num_mem_chunks; + len += (wma_handle->num_mem_chunks * sizeof(wlan_host_memory_chunk)); + WMITLV_SET_HDR((buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config)), + WMITLV_TAG_ARRAY_STRUC, + (sizeof(wlan_host_memory_chunk) * + wma_handle->num_mem_chunks)); + cdf_mem_copy(&wma_handle->target_abi_vers, + ¶m_buf->fixed_param->fw_abi_vers, + sizeof(wmi_abi_version)); + num_whitelist = sizeof(version_whitelist) / + sizeof(wmi_whitelist_version_info); + my_vers.abi_version_0 = WMI_ABI_VERSION_0; + my_vers.abi_version_1 = WMI_ABI_VERSION_1; + my_vers.abi_version_ns_0 = WMI_ABI_VERSION_NS_0; + my_vers.abi_version_ns_1 = WMI_ABI_VERSION_NS_1; + my_vers.abi_version_ns_2 = WMI_ABI_VERSION_NS_2; + my_vers.abi_version_ns_3 = WMI_ABI_VERSION_NS_3; + + wmi_cmp_and_set_abi_version(num_whitelist, version_whitelist, + &my_vers, + ¶m_buf->fixed_param->fw_abi_vers, + &cmd->host_abi_vers); + + WMA_LOGD("%s: INIT_CMD version: %d, %d, 0x%x, 0x%x, 0x%x, 0x%x", + __func__, WMI_VER_GET_MAJOR(cmd->host_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(cmd->host_abi_vers.abi_version_0), + cmd->host_abi_vers.abi_version_ns_0, + cmd->host_abi_vers.abi_version_ns_1, + cmd->host_abi_vers.abi_version_ns_2, + cmd->host_abi_vers.abi_version_ns_3); + + cdf_mem_copy(&wma_handle->final_abi_vers, &cmd->host_abi_vers, + sizeof(wmi_abi_version)); + return buf; +} + +/** + * wma_dump_dbs_hw_mode() - Print the DBS HW modes + * @wma_handle: WMA handle + * + * Prints the DBS HW modes sent by the FW as part + * of WMI ready event + * + * Return: None + */ +void wma_dump_dbs_hw_mode(tp_wma_handle wma_handle) +{ + uint32_t i, param; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + for (i = 0; i < wma_handle->num_dbs_hw_modes; i++) { + param = wma_handle->hw_mode.hw_mode_list[i]; + WMA_LOGA("%s:[%d]-MAC0: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(param), + WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(param), + WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(param)); + WMA_LOGA("%s:[%d]-MAC1: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(param), + WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(param), + WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(param)); + WMA_LOGA("%s:[%d] DBS:%d Agile DFS:%d", __func__, i, + WMI_DBS_HW_MODE_DBS_MODE_GET(param), + WMI_DBS_HW_MODE_AGILE_DFS_GET(param)); + } +} + +/** + * wma_init_scan_fw_mode_config() - Initialize scan/fw mode config + * @wma_handle: WMA handle + * + * Enables all the valid bits of concurrent_scan_config_bits and + * fw_mode_config_bits. + * + * Return: None + */ +void wma_init_scan_fw_mode_config(tp_wma_handle wma_handle) +{ + tpAniSirGlobal mac = cds_get_context(CDF_MODULE_ID_PE); + + WMA_LOGD("%s: Enter", __func__); + + if (!mac) { + WMA_LOGE("%s: Invalid mac handle", __func__); + return; + } + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + wma_handle->dual_mac_cfg.cur_scan_config = 0; + wma_handle->dual_mac_cfg.cur_fw_mode_config = 0; + + /* If dual mac features are disabled in the INI, we + * need not proceed further + */ + if (mac->dual_mac_feature_disable) { + WMA_LOGE("%s: Disabling dual mac capabilities", __func__); + /* All capabilites are initialized to 0. We can return */ + goto done; + } + + /* The input from FW team is that, by default all the + * bits of concurrent_scan_config_bits and + * FW_mode_config_bits will be enabled. So, + * enabling all the bits here. Adding this API so that + * in the future/variant chipsets, when not all bits are + * enabled, FW can send the initial configuration of the above + * two parameters using the service ready event and they + * can be initialized here. + */ + /* Initialize concurrent_scan_config_bits */ + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, 1); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, 1); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, 1); + + /* Initialize FW_mode_config_bits */ + WMI_DBS_FW_MODE_CFG_DBS_SET( + wma_handle->dual_mac_cfg.cur_fw_mode_config, 1); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET( + wma_handle->dual_mac_cfg.cur_fw_mode_config, 1); +done: + /* Initialize the previous scan/fw mode config */ + wma_handle->dual_mac_cfg.prev_scan_config = + wma_handle->dual_mac_cfg.cur_scan_config; + wma_handle->dual_mac_cfg.prev_fw_mode_config = + wma_handle->dual_mac_cfg.cur_fw_mode_config; + + WMA_LOGD("%s: cur_scan_config:%x cur_fw_mode_config:%x", + __func__, + wma_handle->dual_mac_cfg.cur_scan_config, + wma_handle->dual_mac_cfg.cur_fw_mode_config); +} + +/** + * wma_rx_service_ready_event() - event handler to process + * wmi rx sevice ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * + * Return: none + */ +void wma_rx_service_ready_event(WMA_HANDLE handle, void *cmd_param_info) +{ + wmi_buf_t buf; + uint32_t len; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wma_target_cap target_cap; + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + int status; + uint32_t *ev_wlan_dbs_hw_mode_list; + + WMA_LOGD("%s: Enter", __func__); + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(handle && param_buf)) { + WMA_LOGP("%s: Invalid arguments", __func__); + return; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGP("%s: Invalid buffer", __func__); + return; + } + + WMA_LOGA("WMA <-- WMI_SERVICE_READY_EVENTID"); + + wma_handle->num_dbs_hw_modes = ev->num_dbs_hw_modes; + ev_wlan_dbs_hw_mode_list = param_buf->wlan_dbs_hw_mode_list; + wma_handle->hw_mode.hw_mode_list = + cdf_mem_malloc(sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes); + if (!wma_handle->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for DBS", __func__); + /* Continuing with the rest of the processing */ + } + cdf_mem_copy(wma_handle->hw_mode.hw_mode_list, + ev_wlan_dbs_hw_mode_list, + (sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes)); + + wma_dump_dbs_hw_mode(wma_handle); + + wma_init_scan_fw_mode_config(wma_handle); + + wma_handle->phy_capability = ev->phy_capability; + wma_handle->max_frag_entry = ev->max_frag_entry; + wma_handle->num_rf_chains = ev->num_rf_chains; + cdf_mem_copy(&wma_handle->reg_cap, param_buf->hal_reg_capabilities, + sizeof(HAL_REG_CAPABILITIES)); + wma_handle->ht_cap_info = ev->ht_cap_info; +#ifdef WLAN_FEATURE_11AC + wma_handle->vht_cap_info = ev->vht_cap_info; + wma_handle->vht_supp_mcs = ev->vht_supp_mcs; +#endif /* WLAN_FEATURE_11AC */ + wma_handle->num_rf_chains = ev->num_rf_chains; + + wma_handle->target_fw_version = ev->fw_build_vers; + ol_tx_set_desc_global_pool_size(ev->num_msdu_desc); + wma_handle->new_hw_mode_index = ev->default_dbs_hw_mode_index; + + WMA_LOGD("%s: Firmware default hw mode index : %d", + __func__, ev->default_dbs_hw_mode_index); + WMA_LOGE("%s: Firmware build version : %08x", + __func__, ev->fw_build_vers); + + if (ev->hw_bd_id) { + wma_handle->hw_bd_id = ev->hw_bd_id; + cdf_mem_copy(wma_handle->hw_bd_info, + ev->hw_bd_info, sizeof(ev->hw_bd_info)); + + WMA_LOGE("%s: Board version: %x.%x", + __func__, + wma_handle->hw_bd_info[0], wma_handle->hw_bd_info[1]); + } else { + wma_handle->hw_bd_id = 0; + cdf_mem_zero(wma_handle->hw_bd_info, + sizeof(wma_handle->hw_bd_info)); + WMA_LOGE("%s: Board version is unknown!", __func__); + } + + /* TODO: Recheck below line to dump service ready event */ + /* dbg_print_wmi_service_11ac(ev); */ + + /* wmi service is ready */ + cdf_mem_copy(wma_handle->wmi_service_bitmap, + param_buf->wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + /* SWBA event handler for beacon transmission */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_HOST_SWBA_EVENTID, + wma_beacon_swba_handler); + if (status) { + WMA_LOGE("Failed to register swba beacon event cb"); + return; + } +#ifdef WLAN_FEATURE_LPSS + wma_handle->lpss_support = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_LPASS); +#endif /* WLAN_FEATURE_LPSS */ + + /* + * This Service bit is added to check for ARP/NS Offload + * support for LL/HL targets + */ + wma_handle->ap_arpns_support = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_AP_ARPNS_OFFLOAD); + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_CSA_OFFLOAD)) { + WMA_LOGD("%s: FW support CSA offload capability", __func__); + status = + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_CSA_HANDLING_EVENTID, + wma_csa_offload_handler); + if (status) { + WMA_LOGE("Failed to register CSA offload event cb"); + return; + } + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + WMA_LOGE("Firmware supports management TX over WMI,use WMI interface instead of HTT for management Tx"); + status = wmi_desc_pool_init(wma_handle, WMI_DESC_POOL_MAX); + if (status) { + WMA_LOGE("Failed to initialize wmi descriptor pool"); + return; + } + /* + * Register Tx completion event handler for MGMT Tx over WMI + * case + */ + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_MGMT_TX_COMPLETION_EVENTID, + wma_mgmt_tx_completion_handler); + if (status) { + WMA_LOGE("Failed to register MGMT over WMI completion handler"); + return; + } + + } else { + WMA_LOGE("FW doesnot support WMI_SERVICE_MGMT_TX_WMI, Use HTT interface for Management Tx"); + } +#ifdef WLAN_FEATURE_GTK_OFFLOAD + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_GTK_OFFLOAD)) { + status = + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_GTK_OFFLOAD_STATUS_EVENTID, + wma_gtk_offload_status_event); + if (status) { + WMA_LOGE("Failed to register GTK offload event cb"); + return; + } + } +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_P2P_NOA_EVENTID, + wma_p2p_noa_event_handler); + if (status) { + WMA_LOGE("Failed to register WMI_P2P_NOA_EVENTID callback"); + return; + } + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TBTTOFFSET_UPDATE_EVENTID, + wma_tbttoffset_update_event_handler); + if (status) { + WMA_LOGE + ("Failed to register WMI_TBTTOFFSET_UPDATE_EVENTID callback"); + return; + } + + /* Initialize the log supported event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID, + wma_log_supported_evt_handler); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register log supported event cb"); + return; + } + + cdf_mem_copy(target_cap.wmi_service_bitmap, + param_buf->wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + target_cap.wlan_resource_config = wma_handle->wlan_resource_config; + wma_update_fw_config(wma_handle, &target_cap); + cdf_mem_copy(wma_handle->wmi_service_bitmap, + target_cap.wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + wma_handle->wlan_resource_config = target_cap.wlan_resource_config; + + buf = wma_setup_wmi_init_msg(wma_handle, ev, param_buf, &len); + if (!buf) { + WMA_LOGE("Failed to setup buffer for wma init command"); + return; + } + + WMA_LOGA("WMA --> WMI_INIT_CMDID"); + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_INIT_CMDID); + if (status != EOK) { + WMA_LOGE("Failed to send WMI_INIT_CMDID command"); + wmi_buf_free(buf); + return; + } +} + +/** + * wma_rx_service_ready_ext_event() - evt handler for sevice ready ext event. + * @handle: wma handle + * @event: params of the service ready extended event + * + * Return: none + */ +void wma_rx_service_ready_ext_event(WMA_HANDLE handle, void *event) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf; + wmi_service_ready_ext_event_fixed_param *ev; + int status; + CDF_STATUS ret; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma_handle) { + WMA_LOGP("%s: Invalid WMA handle", __func__); + return; + } + + param_buf = (WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGP("%s: Invalid event", __func__); + return; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGP("%s: Invalid buffer", __func__); + return; + } + + WMA_LOGA("WMA <-- WMI_SERVICE_READY_EXT_EVENTID"); + + if (!wma_handle->saved_wmi_init_cmd.buf) { + WMA_LOGP("Service ready ext event w/o WMI_SERVICE_EXT_MSG!"); + return; + } + + ret = cdf_event_set(&wma_handle->service_ready_ext_evt); + if (CDF_STATUS_SUCCESS != ret) { + WMA_LOGP("Failed to set service_ready_ext_evt"); + return; + } + + WMA_LOGA("WMA --> WMI_INIT_CMDID"); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, + wma_handle->saved_wmi_init_cmd.buf, + wma_handle->saved_wmi_init_cmd.buf_len, + WMI_INIT_CMDID); + if (status != EOK) { + /* In success case, WMI layer will free after getting copy + * engine TX complete interrupt + */ + WMA_LOGE("Failed to send WMI_INIT_CMDID command"); + wmi_buf_free(wma_handle->saved_wmi_init_cmd.buf); + } + wma_handle->saved_wmi_init_cmd.buf = NULL; + +} + +/** + * wma_rx_ready_event() - event handler to process + * wmi rx ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * + * Return: none + */ +void wma_rx_ready_event(WMA_HANDLE handle, void *cmd_param_info) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + + WMA_LOGD("%s: Enter", __func__); + + param_buf = (WMI_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(wma_handle && param_buf)) { + WMA_LOGP("%s: Invalid arguments", __func__); + CDF_ASSERT(0); + return; + } + + WMA_LOGA("WMA <-- WMI_READY_EVENTID"); + + ev = param_buf->fixed_param; + /* Indicate to the waiting thread that the ready + * event was received */ + wma_handle->wmi_ready = true; + wma_handle->wlan_init_status = ev->status; + + /* + * We need to check the WMI versions and make sure both + * host and fw are compatible. + */ + if (!wmi_versions_are_compatible(&wma_handle->final_abi_vers, + &ev->fw_abi_vers)) { + /* + * Error: Our host version and the given firmware version + * are incompatible. + */ + WMA_LOGE("%s: Error: Incompatible WMI version." + "Host: %d,%d,0x%x 0x%x 0x%x 0x%x, FW: %d,%d,0x%x 0x%x 0x%x 0x%x", + __func__, + WMI_VER_GET_MAJOR(wma_handle->final_abi_vers. + abi_version_0), + WMI_VER_GET_MINOR(wma_handle->final_abi_vers. + abi_version_0), + wma_handle->final_abi_vers.abi_version_ns_0, + wma_handle->final_abi_vers.abi_version_ns_1, + wma_handle->final_abi_vers.abi_version_ns_2, + wma_handle->final_abi_vers.abi_version_ns_3, + WMI_VER_GET_MAJOR(ev->fw_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(ev->fw_abi_vers.abi_version_0), + ev->fw_abi_vers.abi_version_ns_0, + ev->fw_abi_vers.abi_version_ns_1, + ev->fw_abi_vers.abi_version_ns_2, + ev->fw_abi_vers.abi_version_ns_3); + if (wma_handle->wlan_init_status == WLAN_INIT_STATUS_SUCCESS) { + /* Failed this connection to FW */ + wma_handle->wlan_init_status = + WLAN_INIT_STATUS_GEN_FAILED; + } + } + cdf_mem_copy(&wma_handle->final_abi_vers, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); + cdf_mem_copy(&wma_handle->target_abi_vers, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); + + /* copy the mac addr */ + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->myaddr); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->hwaddr); + + wma_update_hdd_cfg(wma_handle); + + cdf_event_set(&wma_handle->wma_ready_event); + + WMA_LOGD("Exit"); +} + +/** + * wma_setneedshutdown() - setting wma needshutdown flag + * @cds_ctx: cds context + * + * Return: none + */ +void wma_setneedshutdown(void *cds_ctx) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid arguments", __func__); + CDF_ASSERT(0); + return; + } + + wma_handle->needShutdown = true; + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_needshutdown() - Is wma needs shutdown? + * @cds_ctx: cds context + * + * Return: returns true/false + */ +bool wma_needshutdown(void *cds_ctx) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid arguments", __func__); + CDF_ASSERT(0); + return false; + } + + WMA_LOGD("%s: Exit", __func__); + return wma_handle->needShutdown; +} + +/** + * wma_wait_for_ready_event() - wait for wma ready event + * @handle: wma handle + * + * Return: 0 for success or CDF error + */ +CDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + CDF_STATUS cdf_status; + + /* wait until WMI_READY_EVENTID received from FW */ + cdf_status = cdf_wait_single_event(&(wma_handle->wma_ready_event), + WMA_READY_EVENTID_TIMEOUT); + + if (CDF_STATUS_SUCCESS != cdf_status) { + WMA_LOGP("%s: Timeout waiting for ready event from FW", + __func__); + cdf_status = CDF_STATUS_E_FAILURE; + } + return cdf_status; +} + +/** + * wma_set_ppsconfig() - set pps config in fw + * @vdev_id: vdev id + * @pps_param: pps params + * @val : param value + * + * Return: 0 for success or CDF error + */ +CDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int val) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + int ret = -EIO; + uint32_t pps_val; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return CDF_STATUS_E_INVAL; + } + + switch (pps_param) { + case WMA_VHT_PPS_PAID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_DELIM_CRC_FAIL: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + goto pkt_pwr_save_config; + + /* Enable the code below as and when the functionality + * is supported/added in host. + */ +#ifdef NOT_YET + case WMA_VHT_PPS_EARLY_TIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EARLY_DTIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EOF_PAD_DELIM: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_MACADDR_MISMATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_NSTS_ZERO: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_RSSI_CHECK: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + goto pkt_pwr_save_config; +#endif /* NOT_YET */ +pkt_pwr_save_config: + WMA_LOGD("vdev_id:%d val:0x%x pps_val:0x%x", vdev_id, + val, pps_val); + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + break; + default: + WMA_LOGE("%s:INVALID PPS CONFIG", __func__); + } + + return (ret) ? CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_mas() - Function to enable/disable MAS + * @wma: Pointer to WMA handle + * @mas_val: 1-Enable MAS, 0-Disable MAS + * + * This function enables/disables the MAS value + * + * Return: CDF_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_process_set_mas(tp_wma_handle wma, + uint32_t *mas_val) +{ + uint32_t val; + + if (NULL == wma || NULL == mas_val) { + WMA_LOGE("%s: Invalid input to enable/disable MAS", __func__); + return CDF_STATUS_E_FAILURE; + } + + val = (*mas_val); + + if (CDF_STATUS_SUCCESS != + wma_set_enable_disable_mcc_adaptive_scheduler(val)) { + WMA_LOGE("%s: Unable to enable/disable MAS", __func__); + return CDF_STATUS_E_FAILURE; + } else { + WMA_LOGE("%s: Value is %d", __func__, val); + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_miracast() - Function to set miracast value in WMA + * @wma: Pointer to WMA handle + * @miracast_val: 0-Disabled,1-Source,2-Sink + * + * This function stores the miracast value in WMA + * + * Return: CDF_SUCCESS for success otherwise failure + * + */ +CDF_STATUS wma_process_set_miracast(tp_wma_handle wma, uint32_t *miracast_val) +{ + if (NULL == wma || NULL == miracast_val) { + WMA_LOGE("%s: Invalid input to store miracast value", __func__); + return CDF_STATUS_E_FAILURE; + } + + wma->miracast_value = *miracast_val; + WMA_LOGE("%s: Miracast value is %d", __func__, wma->miracast_value); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_config_stats_factor() - Function to configure stats avg. factor + * @wma: pointer to WMA handle + * @avg_factor: stats. avg. factor passed down by userspace + * + * This function configures the avg. stats value in firmware + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + * + */ +static CDF_STATUS wma_config_stats_factor(tp_wma_handle wma, + struct sir_stats_avg_factor *avg_factor) +{ + int ret; + + if (NULL == wma || NULL == avg_factor) { + WMA_LOGE("%s: Invalid input of stats avg factor", __func__); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + avg_factor->vdev_id, + WMI_VDEV_PARAM_STATS_AVG_FACTOR, + avg_factor->stats_avg_factor); + if (ret) { + WMA_LOGE(" failed to set avg_factor for vdev_id %d", + avg_factor->vdev_id); + } + + WMA_LOGD("%s: Set stats_avg_factor %d for vdev_id %d", __func__, + avg_factor->stats_avg_factor, avg_factor->vdev_id); + + return ret; +} + +/** + * wma_config_guard_time() - Function to set guard time in firmware + * @wma: pointer to WMA handle + * @guard_time: guard time passed down by userspace + * + * This function configures the guard time in firmware + * + * Return: CDF_STATUS_SUCCESS for success otherwise failure + * + */ +static CDF_STATUS wma_config_guard_time(tp_wma_handle wma, + struct sir_guard_time_request *guard_time) +{ + int ret; + + if (NULL == wma || NULL == guard_time) { + WMA_LOGE("%s: Invalid input of guard time", __func__); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + guard_time->vdev_id, + WMI_VDEV_PARAM_RX_LEAK_WINDOW, + guard_time->guard_time); + if (ret) { + WMA_LOGE(" failed to set guard time for vdev_id %d", + guard_time->vdev_id); + } + + WMA_LOGD("Set guard time %d for vdev_id %d", + guard_time->guard_time, guard_time->vdev_id); + + return ret; +} + +/** + * wma_enable_specific_fw_logs() - Start/Stop logging of diag event/log id + * @wma_handle: WMA handle + * @start_log: Start logging related parameters + * + * Send the command to the FW based on which specific logging of diag + * event/log id can be started/stopped + * + * Return: None + */ +void wma_enable_specific_fw_logs(tp_wma_handle wma_handle, + struct sir_wifi_start_log *start_log) +{ + wmi_diag_event_log_config_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len, count, log_level, i; + uint32_t *cmd_args; + uint32_t total_len; + count = 0; + + if (!start_log) { + WMA_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + if (!((start_log->ring_id == RING_ID_CONNECTIVITY) || + (start_log->ring_id == RING_ID_FIRMWARE_DEBUG))) { + WMA_LOGD("%s: Not connectivity or fw debug ring: %d", + __func__, start_log->ring_id); + return; + } + + if (!wma_handle->events_logs_list) { + WMA_LOGE("%s: Not received event/log list from FW, yet", + __func__); + return; + } + + /* total_len stores the number of events where BITS 17 and 18 are set. + * i.e., events of high frequency (17) and for extended debugging (18) + */ + total_len = 0; + for (i = 0; i < wma_handle->num_of_diag_events_logs; i++) { + if ((WMI_DIAG_FREQUENCY_GET(wma_handle->events_logs_list[i])) && + (WMI_DIAG_EXT_FEATURE_GET(wma_handle->events_logs_list[i]))) + total_len++; + } + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + (total_len * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_diag_event_log_config_fixed_param)); + + cmd->num_of_diag_events_logs = total_len; + + buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (total_len * sizeof(uint32_t))); + + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + + if (start_log->verbose_level >= LOG_LEVEL_ACTIVE) + log_level = 1; + else + log_level = 0; + + WMA_LOGD("%s: Length:%d, Log_level:%d", __func__, total_len, log_level); + for (i = 0; i < wma_handle->num_of_diag_events_logs; i++) { + uint32_t val = wma_handle->events_logs_list[i]; + if ((WMI_DIAG_FREQUENCY_GET(val)) && + (WMI_DIAG_EXT_FEATURE_GET(val))) { + + WMI_DIAG_ID_SET(cmd_args[count], + WMI_DIAG_ID_GET(val)); + WMI_DIAG_TYPE_SET(cmd_args[count], + WMI_DIAG_TYPE_GET(val)); + WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[count], + log_level); + WMA_LOGD("%s: Idx:%d, val:%x", __func__, i, val); + count++; + } + } + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) { + WMA_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed", + __func__); + wmi_buf_free(buf); + } + return; +} + +#if !defined(REMOVE_PKT_LOG) +/** + * wma_set_wifi_start_packet_stats() - Start/stop packet stats + * @wma_handle: WMA handle + * @start_log: Struture containing the start wifi logger params + * + * This function is used to send the WMA commands to start/stop logging + * of per packet statistics + * + * Return: None + * + */ +void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ + struct ol_softc *scn; + uint32_t log_state; + + if (!start_log) { + WMA_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + /* No need to register for ring IDs other than packet stats */ + if (start_log->ring_id != RING_ID_PER_PACKET_STATS) { + WMA_LOGI("%s: Ring id is not for per packet stats: %d", + __func__, start_log->ring_id); + return; + } + + scn = cds_get_context(CDF_MODULE_ID_HIF); + + log_state = ATH_PKTLOG_ANI | ATH_PKTLOG_RCUPDATE | ATH_PKTLOG_RCFIND | + ATH_PKTLOG_RX | ATH_PKTLOG_TX | ATH_PKTLOG_TEXT; + + if (start_log->verbose_level == WLAN_LOG_LEVEL_ACTIVE) { + pktlog_enable(scn, log_state); + WMA_LOGI("%s: Enabling per packet stats", __func__); + } else { + pktlog_enable(scn, 0); + WMA_LOGI("%s: Disabling per packet stats", __func__); + } +} +#endif + +/** + * wma_send_flush_logs_to_fw() - Send log flush command to FW + * @wma_handle: WMI handle + * + * This function is used to send the flush command to the FW, + * that will flush the fw logs that are residue in the FW + * + * Return: None + */ +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle) +{ + CDF_STATUS status; + wmi_debug_mesg_flush_fixed_param *cmd; + wmi_buf_t buf; + int len = sizeof(*cmd); + int ret; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return; + } + + cmd = (wmi_debug_mesg_flush_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_debug_mesg_flush_fixed_param)); + cmd->reserved0 = 0; + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, + buf, + len, + WMI_DEBUG_MESG_FLUSH_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_DEBUG_MESG_FLUSH_CMDID"); + wmi_buf_free(buf); + return; + } + WMA_LOGI("Sent WMI_DEBUG_MESG_FLUSH_CMDID to FW"); + + status = cdf_mc_timer_start(&wma_handle->log_completion_timer, + WMA_LOG_COMPLETION_TIMER); + if (status != CDF_STATUS_SUCCESS) + WMA_LOGE("Failed to start the log completion timer"); +} + +/** + * wma_mc_process_msg() - process wma messages and call appropriate function. + * @cds_context: cds context + * @msg: message + * + * Return: CDF_SUCCESS for success otherwise failure + */ +CDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + ol_txrx_vdev_handle txrx_vdev_handle = NULL; + extern uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); + + WMA_LOGI("%s: Enter", __func__); + if (NULL == msg) { + WMA_LOGE("msg is NULL"); + CDF_ASSERT(0); + cdf_status = CDF_STATUS_E_INVAL; + goto end; + } + + WMA_LOGD("msg->type = %x %s", msg->type, + mac_trace_get_wma_msg_string(msg->type)); + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: wma_handle is NULL", __func__); + CDF_ASSERT(0); + cdf_mem_free(msg->bodyptr); + cdf_status = CDF_STATUS_E_INVAL; + goto end; + } + + switch (msg->type) { + + /* Message posted by wmi for all control path related + * FW events to serialize through mc_thread. + */ + case WMA_PROCESS_FW_EVENT: + wma_process_fw_event(wma_handle, + (wma_process_fw_event_params *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_REQ: + WMA_LOGA("McThread: WMA_TSM_STATS_REQ"); + wma_process_tsm_stats_req(wma_handle, (void *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_ESE */ + case WNI_CFG_DNLD_REQ: + WMA_LOGA("McThread: WNI_CFG_DNLD_REQ"); + cdf_status = wma_wni_cfg_dnld(wma_handle); + if (CDF_IS_STATUS_SUCCESS(cdf_status)) { + cds_wma_complete_cback(cds_context); + } else { + WMA_LOGD("config download failure"); + } + break; + case WMA_ADD_STA_SELF_REQ: + txrx_vdev_handle = + wma_vdev_attach(wma_handle, + (struct add_sta_self_params *) msg-> + bodyptr, 1); + if (!txrx_vdev_handle) { + WMA_LOGE("Failed to attach vdev"); + } else { + /* Register with TxRx Module for Data Ack Complete Cb */ + ol_txrx_data_tx_cb_set(txrx_vdev_handle, + wma_data_tx_ack_comp_hdlr, + wma_handle); + } + break; + case WMA_DEL_STA_SELF_REQ: + wma_vdev_detach(wma_handle, + (struct del_sta_self_params *) msg->bodyptr, 1); + break; + case WMA_START_SCAN_OFFLOAD_REQ: + wma_start_scan(wma_handle, msg->bodyptr, msg->type); + cdf_mem_free(msg->bodyptr); + break; + case WMA_STOP_SCAN_OFFLOAD_REQ: + wma_stop_scan(wma_handle, msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_CHAN_LIST_REQ: + wma_update_channel_list(wma_handle, + (tSirUpdateChanList *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_LINK_STATE: + wma_set_linkstate(wma_handle, (tpLinkStateParams) msg->bodyptr); + break; + case WMA_CHNL_SWITCH_REQ: + wma_set_channel(wma_handle, + (tpSwitchChannelParams) msg->bodyptr); + break; + case WMA_ADD_BSS_REQ: + wma_add_bss(wma_handle, (tpAddBssParams) msg->bodyptr); + break; + case WMA_ADD_STA_REQ: + wma_add_sta(wma_handle, (tpAddStaParams) msg->bodyptr); + break; + case WMA_SET_BSSKEY_REQ: + wma_set_bsskey(wma_handle, (tpSetBssKeyParams) msg->bodyptr); + break; + case WMA_SET_STAKEY_REQ: + wma_set_stakey(wma_handle, (tpSetStaKeyParams) msg->bodyptr); + break; + case WMA_DELETE_STA_REQ: + wma_delete_sta(wma_handle, (tpDeleteStaParams) msg->bodyptr); + break; + case WMA_DELETE_BSS_REQ: + wma_delete_bss(wma_handle, (tpDeleteBssParams) msg->bodyptr); + break; + case WMA_UPDATE_EDCA_PROFILE_IND: + wma_process_update_edca_param_req(wma_handle, + (tEdcaParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_BEACON_REQ: + wma_send_beacon(wma_handle, (tpSendbeaconParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_PROBE_RSP_TMPL: + wma_send_probe_rsp_tmpl(wma_handle, + (tpSendProbeRespParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_CLI_SET_CMD: + wma_process_cli_set_cmd(wma_handle, + (wma_cli_set_cmd_t *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#if !defined(REMOVE_PKT_LOG) + case WMA_PKTLOG_ENABLE_REQ: + wma_pktlog_wmi_send_cmd(wma_handle, + (struct ath_pktlog_wmi_params *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* REMOVE_PKT_LOG */ +#if defined(QCA_WIFI_FTM) + case WMA_FTM_CMD_REQ: + wma_process_ftm_command(wma_handle, + (struct ar6k_testmode_cmd_data *)msg->bodyptr); + break; +#endif /* QCA_WIFI_FTM */ + case WMA_ENTER_PS_REQ: + wma_enable_sta_ps_mode(wma_handle, + (tpEnablePsParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXIT_PS_REQ: + wma_disable_sta_ps_mode(wma_handle, + (tpDisablePsParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_ENABLE_UAPSD_REQ: + wma_enable_uapsd_mode(wma_handle, + (tpEnableUapsdParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_DISABLE_UAPSD_REQ: + wma_disable_uapsd_mode(wma_handle, + (tpDisableUapsdParams) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_TX_POWER_REQ: + wma_set_tx_power(wma_handle, (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_MAX_TX_POWER_REQ: + wma_set_max_tx_power(wma_handle, + (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_KEEP_ALIVE: + wma_set_keepalive_req(wma_handle, + (tSirKeepAliveReq *) msg->bodyptr); + break; +#ifdef FEATURE_WLAN_SCAN_PNO + case WMA_SET_PNO_REQ: + wma_config_pno(wma_handle, (tpSirPNOScanReq) msg->bodyptr); + break; + + case WMA_SME_SCAN_CACHE_UPDATED: + wma_scan_cache_updated_ind(wma_handle, msg->bodyval); + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + case WMA_SET_PLM_REQ: + wma_config_plm(wma_handle, (tpSirPlmReq) msg->bodyptr); + break; +#endif + case WMA_GET_STATISTICS_REQ: + wma_get_stats_req(wma_handle, + (tAniGetPEStatsReq *) msg->bodyptr); + break; + + case WMA_CONFIG_PARAM_UPDATE_REQ: + wma_update_cfg_params(wma_handle, (tSirMsgQ *) msg); + break; + + case WMA_UPDATE_OP_MODE: + wma_process_update_opmode(wma_handle, + (tUpdateVHTOpMode *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_RX_NSS: + wma_process_update_rx_nss(wma_handle, + (tUpdateRxNss *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_11AC + case WMA_UPDATE_MEMBERSHIP: + wma_process_update_membership(wma_handle, + (tUpdateMembership *) msg->bodyptr); + break; + case WMA_UPDATE_USERPOS: + wma_process_update_userpos(wma_handle, + (tUpdateUserPos *) msg->bodyptr); + break; +#endif /* WLAN_FEATURE_11AC */ + case WMA_UPDATE_BEACON_IND: + wma_process_update_beacon_params(wma_handle, + (tUpdateBeaconParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + + case WMA_ADD_TS_REQ: + wma_add_ts_req(wma_handle, (tAddTsParams *) msg->bodyptr); + break; + + case WMA_DEL_TS_REQ: + wma_del_ts_req(wma_handle, (tDelTsParams *) msg->bodyptr); + break; + + case WMA_AGGR_QOS_REQ: + wma_aggr_qos_req(wma_handle, (tAggrAddTsParams *) msg->bodyptr); + break; + + case WMA_RECEIVE_FILTER_SET_FILTER_REQ: + wma_process_receive_filter_set_filter_req(wma_handle, + (tSirRcvPktFilterCfgType *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + + case WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ: + wma_process_receive_filter_clear_filter_req(wma_handle, + (tSirRcvFltPktClearParam *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + + case WMA_WOW_ADD_PTRN: + wma_wow_add_pattern(wma_handle, + (struct wow_add_pattern *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_WOW_DEL_PTRN: + wma_wow_delete_user_pattern(wma_handle, + (struct wow_delete_pattern *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_WOWL_ENTER_REQ: + wma_wow_enter(wma_handle, + (tpSirHalWowlEnterParams) msg->bodyptr); + break; + case WMA_WOWL_EXIT_REQ: + wma_wow_exit(wma_handle, (tpSirHalWowlExitParams) msg->bodyptr); + break; + case WMA_WLAN_SUSPEND_IND: + wma_suspend_req(wma_handle, + (tpSirWlanSuspendParam) msg->bodyptr); + break; + case WMA_8023_MULTICAST_LIST_REQ: + wma_process_mcbc_set_filter_req(wma_handle, + (tpSirRcvFltMcAddrList) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + case WMA_GTK_OFFLOAD_REQ: + wma_process_gtk_offload_req(wma_handle, + (tpSirGtkOffloadParams) msg->bodyptr); + break; + + case WMA_GTK_OFFLOAD_GETINFO_REQ: + wma_process_gtk_offload_getinfo_req(wma_handle, + (tpSirGtkOffloadGetInfoRspParams)msg->bodyptr); + break; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_OEM_DATA_SUPPORT + case WMA_START_OEM_DATA_REQ: + wma_start_oem_data_req(wma_handle, + (tStartOemDataReq *) msg->bodyptr); + break; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + case WMA_SET_HOST_OFFLOAD: + wma_enable_arp_ns_offload(wma_handle, + (tpSirHostOffloadReq) msg->bodyptr, + true); + break; +#ifdef WLAN_NS_OFFLOAD + case WMA_SET_NS_OFFLOAD: + wma_enable_arp_ns_offload(wma_handle, + (tpSirHostOffloadReq) msg->bodyptr, + false); + break; +#endif /*WLAN_NS_OFFLOAD */ + case WMA_ROAM_SCAN_OFFLOAD_REQ: + /* + * Main entry point or roaming directives from CSR. + */ + wma_process_roam_scan_req(wma_handle, + (tSirRoamOffloadScanReq *) msg->bodyptr); + break; + + case WMA_RATE_UPDATE_IND: + wma_process_rate_update_indicate(wma_handle, + (tSirRateUpdateInd *) msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_TDLS + case WMA_UPDATE_FW_TDLS_STATE: + wma_update_fw_tdls_state(wma_handle, + (t_wma_tdls_params *) msg->bodyptr); + break; + case WMA_UPDATE_TDLS_PEER_STATE: + wma_update_tdls_peer_state(wma_handle, + (tTdlsPeerStateParams *) msg->bodyptr); + break; + case WMA_TDLS_SET_OFFCHAN_MODE: + wma_set_tdls_offchan_mode(wma_handle, + (tdls_chan_switch_params *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_TDLS */ + case WMA_ADD_PERIODIC_TX_PTRN_IND: + wma_process_add_periodic_tx_ptrn_ind(wma_handle, + (tSirAddPeriodicTxPtrn *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_DEL_PERIODIC_TX_PTRN_IND: + wma_process_del_periodic_tx_ptrn_ind(wma_handle, + (tSirDelPeriodicTxPtrn *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_TX_POWER_LIMIT: + wma_process_tx_power_limits(wma_handle, + (tSirTxPowerLimit *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef FEATURE_WLAN_LPHB + case WMA_LPHB_CONF_REQ: + wma_process_lphb_conf_req(wma_handle, + (tSirLPHBReq *) msg->bodyptr); + break; +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID + case WMA_CH_AVOID_UPDATE_REQ: + wma_process_ch_avoid_update_req(wma_handle, + (tSirChAvoidUpdateReq *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WMA_SET_AUTO_SHUTDOWN_TIMER_REQ: + wma_set_auto_shutdown_timer_req(wma_handle, msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + case WMA_DHCP_START_IND: + case WMA_DHCP_STOP_IND: + wma_process_dhcp_ind(wma_handle, (tAniDHCPInd *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + + case WMA_INIT_THERMAL_INFO_CMD: + wma_process_init_thermal_info(wma_handle, + (t_thermal_mgmt *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + + case WMA_SET_THERMAL_LEVEL: + wma_process_set_thermal_level(wma_handle, msg->bodyval); + break; + + case WMA_SET_P2P_GO_NOA_REQ: + wma_process_set_p2pgo_noa_req(wma_handle, + (tP2pPsParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_MIMOPS_REQ: + wma_process_set_mimops_req(wma_handle, + (tSetMIMOPS *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_SAP_INTRABSS_DIS: + wma_set_vdev_intrabss_fwd(wma_handle, + (tDisableIntraBssFwd *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_GET_LINK_SPEED: + wma_get_link_speed(wma_handle, msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_MODEM_POWER_STATE_IND: + wma_notify_modem_power_state(wma_handle, + (tSirModemPowerStateInd *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_RESUME_REQ: + wma_resume_req(wma_handle); + break; + +#ifdef WLAN_FEATURE_STATS_EXT + case WMA_STATS_EXT_REQUEST: + wma_stats_ext_req(wma_handle, + (tpStatsExtRequest) (msg->bodyptr)); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_STATS_EXT */ + case WMA_HIDDEN_SSID_VDEV_RESTART: + wma_hidden_ssid_vdev_restart(wma_handle, + (tHalHiddenSsidVdevRestart *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case WMA_WLAN_EXT_WOW: + wma_enable_ext_wow(wma_handle, + (tSirExtWoWParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE1_PARAMS: + wma_set_app_type1_params_in_fw(wma_handle, + (tSirAppType1Params *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE2_PARAMS: + wma_set_app_type2_params_in_fw(wma_handle, + (tSirAppType2Params *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ +#ifdef FEATURE_WLAN_EXTSCAN + case WMA_EXTSCAN_START_REQ: + wma_start_extscan(wma_handle, + (tSirWifiScanCmdReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_STOP_REQ: + wma_stop_extscan(wma_handle, + (tSirExtScanStopReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ: + wma_extscan_start_hotlist_monitor(wma_handle, + (tSirExtScanSetBssidHotListReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ: + wma_extscan_stop_hotlist_monitor(wma_handle, + (tSirExtScanResetBssidHotlistReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ: + wma_extscan_start_change_monitor(wma_handle, + (tSirExtScanSetSigChangeReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ: + wma_extscan_stop_change_monitor(wma_handle, + (tSirExtScanResetSignificantChangeReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CACHED_RESULTS_REQ: + wma_extscan_get_cached_results(wma_handle, + (tSirExtScanGetCachedResultsReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CAPABILITIES_REQ: + wma_extscan_get_capabilities(wma_handle, + (tSirGetExtScanCapabilitiesReqParams *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_EPNO_LIST_REQ: + wma_set_epno_network_list(wma_handle, + (struct wifi_epno_params *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PASSPOINT_LIST_REQ: + /* Issue reset passpoint network list first and clear + * the entries */ + wma_reset_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + + wma_set_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_RESET_PASSPOINT_LIST_REQ: + wma_reset_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + break; + case WMA_EXTSCAN_SET_SSID_HOTLIST_REQ: + wma_set_ssid_hotlist(wma_handle, + (struct sir_set_ssid_hotlist_request *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_EXTSCAN */ + case WMA_SET_SCAN_MAC_OUI_REQ: + wma_scan_probe_setoui(wma_handle, msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + case WMA_LINK_LAYER_STATS_CLEAR_REQ: + wma_process_ll_stats_clear_req(wma_handle, + (tpSirLLStatsClearReq) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_SET_REQ: + wma_process_ll_stats_set_req(wma_handle, + (tpSirLLStatsSetReq) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_GET_REQ: + wma_process_ll_stats_get_req(wma_handle, + (tpSirLLStatsGetReq) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + case SIR_HAL_UNIT_TEST_CMD: + wma_process_unit_test_cmd(wma_handle, + (t_wma_unit_test_cmd *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMA_ROAM_OFFLOAD_SYNCH_CNF: + wma_process_roam_synch_complete(wma_handle, + (tSirSmeRoamOffloadSynchCnf *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_ROAM_OFFLOAD_SYNCH_FAIL: + wma_process_roam_synch_fail(wma_handle, + (struct roam_offload_synch_fail *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_ROAM_INVOKE: + wma_process_roam_invoke(wma_handle, + (struct wma_roam_invoke_cmd *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + case WMA_NAN_REQUEST: + wma_nan_req(wma_handle, (tNanRequest *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_NAN */ + case SIR_HAL_SET_BASE_MACADDR_IND: + wma_set_base_macaddr_indicate(wma_handle, + (tSirMacAddr *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_STATUS_GET_REQ: + wma_process_link_status_req(wma_handle, + (tAniGetLinkStatus *) msg->bodyptr); + break; + case WMA_GET_TEMPERATURE_REQ: + wma_get_temperature(wma_handle); + cdf_mem_free(msg->bodyptr); + break; +#ifdef DHCP_SERVER_OFFLOAD + case WMA_SET_DHCP_SERVER_OFFLOAD_CMD: + wma_process_dhcpserver_offload(wma_handle, + (tSirDhcpSrvOffloadInfo *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WMA_LED_FLASHING_REQ: + wma_set_led_flashing(wma_handle, + (tSirLedFlashingReq *) msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + case SIR_HAL_SET_MAS: + wma_process_set_mas(wma_handle, + (uint32_t *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SET_MIRACAST: + wma_process_set_miracast(wma_handle, + (uint32_t *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_STATS_FACTOR: + wma_config_stats_factor(wma_handle, + (struct sir_stats_avg_factor *) + msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_GUARD_TIME: + wma_config_guard_time(wma_handle, + (struct sir_guard_time_request *) + msg->bodyptr); + case WMA_IPA_OFFLOAD_ENABLE_DISABLE: + wma_ipa_offload_enable_disable(wma_handle, + (struct sir_ipa_offload_enable_disable *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_START_STOP_LOGGING: + wma_set_wifi_start_packet_stats(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + wma_enable_specific_fw_logs(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_FLUSH_LOG_TO_FW: + wma_send_flush_logs_to_fw(wma_handle); + /* Body ptr is NULL here */ + break; + case WMA_SET_RSSI_MONITOR_REQ: + wma_set_rssi_monitoring(wma_handle, + (struct rssi_monitor_req *)msg->bodyptr); + break; + case WMA_FW_MEM_DUMP_REQ: + wma_process_fw_mem_dump_req(wma_handle, + (struct fw_dump_req *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_SET_PCL_TO_FW: + wma_send_soc_set_pcl_cmd(wma_handle, + (struct sir_pcl_list *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_SET_HW_MODE: + wma_send_soc_set_hw_mode_cmd(wma_handle, + (struct sir_hw_mode *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_SET_CONFIG_CMD: + wma_ocb_set_config_req(wma_handle, + (struct sir_ocb_config *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_SET_UTC_TIME_CMD: + wma_ocb_set_utc_time(wma_handle, + (struct sir_ocb_utc *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_START_TIMING_ADVERT_CMD: + wma_ocb_start_timing_advert(wma_handle, + (struct sir_ocb_timing_advert *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_STOP_TIMING_ADVERT_CMD: + wma_ocb_stop_timing_advert(wma_handle, + (struct sir_ocb_timing_advert *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_CLEAR_STATS_CMD: + wma_dcc_clear_stats(wma_handle, + (struct sir_dcc_clear_stats *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_GET_TSF_TIMER_CMD: + wma_ocb_get_tsf_timer(wma_handle, + (struct sir_ocb_get_tsf_timer *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_GET_STATS_CMD: + wma_dcc_get_stats(wma_handle, + (struct sir_dcc_get_stats *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_UPDATE_NDL_CMD: + wma_dcc_update_ndl(wma_handle, + (struct sir_dcc_update_ndl *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_DUAL_MAC_CFG_REQ: + wma_send_soc_set_dual_mac_config(wma_handle, + (struct sir_dual_mac_config *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_SET_IE_INFO: + wma_process_set_ie_info(wma_handle, + (struct vdev_ie_info *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + case WMA_LRO_CONFIG_CMD: + wma_lro_config_cmd(wma_handle, + (struct wma_lro_config_cmd_t *)msg->bodyptr); + cdf_mem_free(msg->bodyptr); + break; + default: + WMA_LOGD("unknow msg type %x", msg->type); + /* Do Nothing? MSG Body should be freed at here */ + if (NULL != msg->bodyptr) { + cdf_mem_free(msg->bodyptr); + } + } +end: + WMA_LOGI("%s: Exit", __func__); + return cdf_status; +} + +/** + * wma_log_completion_timeout() - Log completion timeout + * @data: Timeout handler data + * + * This function is called when log completion timer expires + * + * Return: None + */ +void wma_log_completion_timeout(void *data) +{ + tp_wma_handle wma_handle; + + WMA_LOGE("%s: Timeout occured for log completion command", __func__); + + wma_handle = (tp_wma_handle) data; + if (!wma_handle) + WMA_LOGE("%s: Invalid WMA handle", __func__); + + /* Though we did not receive any event from FW, + * we can flush whatever logs we have with us */ + cds_logging_set_fw_flush_complete(); + + return; +} + +/** + * wma_send_soc_set_pcl_cmd() - Send WMI_SOC_SET_PCL_CMDID to FW + * @wma_handle: WMA handle + * @msg: PCL structure containing the PCL and the number of channels + * + * WMI_SOC_SET_PCL_CMDID provides a Preferred Channel List (PCL) to the WLAN + * firmware. The DBS Manager is the consumer of this information in the WLAN + * firmware. The channel list will be used when a Virtual DEVice (VDEV) needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). Generally, the host will + * manage the channel selection without firmware involvement. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +CDF_STATUS wma_send_soc_set_pcl_cmd(tp_wma_handle wma_handle, + struct sir_pcl_list *msg) +{ + wmi_soc_set_pcl_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t *cmd_args, i, len; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return CDF_STATUS_E_NULL_VALUE; + } + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + (msg->pcl_len * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_soc_set_pcl_cmd_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_soc_set_pcl_cmd_fixed_param)); + cmd->num_chan = msg->pcl_len; + WMA_LOGI("%s: PCL len:%d", __func__, cmd->num_chan); + + buf_ptr += sizeof(wmi_soc_set_pcl_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (msg->pcl_len * sizeof(uint32_t))); + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < msg->pcl_len ; i++) { + cmd_args[i] = msg->pcl_list[i]; + WMA_LOGI("%s: PCL chan:%d", __func__, cmd_args[i]); + } + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_SOC_SET_PCL_CMDID)) { + WMA_LOGE("%s: Failed to send WMI_SOC_SET_PCL_CMDID", __func__); + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_send_soc_set_hw_mode_cmd() - Send WMI_SOC_SET_HW_MODE_CMDID to FW + * @wma_handle: WMA handle + * @msg: Structure containing the following parameters + * + * - hw_mode_index: The HW_Mode field is a enumerated type that is selected + * from the HW_Mode table, which is returned in the WMI_SERVICE_READY_EVENTID. + * + * Provides notification to the WLAN firmware that host driver is requesting a + * HardWare (HW) Mode change. This command is needed to support iHelium in the + * configurations that include the Dual Band Simultaneous (DBS) feature. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +CDF_STATUS wma_send_soc_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct sir_hw_mode *msg) +{ + wmi_soc_set_hw_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + struct sir_set_hw_mode_resp *param; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + /* Handle is NULL. Will not be able to send failure + * response as well + */ + return CDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set HW mode param is NULL", __func__); + /* Lets try to free the active command list */ + goto fail; + } + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + goto fail; + } + + cmd = (wmi_soc_set_hw_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_soc_set_hw_mode_cmd_fixed_param)); + cmd->hw_mode_index = msg->hw_mode_index; + WMA_LOGI("%s: HW mode index:%d", __func__, cmd->hw_mode_index); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_SOC_SET_HW_MODE_CMDID)) { + WMA_LOGE("%s: Failed to send WMI_SOC_SET_HW_MODE_CMDID", + __func__); + cdf_nbuf_free(buf); + goto fail; + } + return CDF_STATUS_SUCCESS; +fail: + param = cdf_mem_malloc(sizeof(*param)); + if (!param) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return CDF_STATUS_E_NULL_VALUE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + WMA_LOGE("%s: Sending HW mode fail response to LIM", __func__); + wma_send_msg(wma_handle, SIR_HAL_SOC_SET_HW_MODE_RESP, + (void *) param, 0); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_send_soc_set_dual_mac_config() - Set dual mac config to FW + * @wma_handle: WMA handle + * @msg: Dual MAC config parameters + * + * Configures WLAN firmware with the dual MAC features + * + * Return: CDF_STATUS. 0 on success. + */ +CDF_STATUS wma_send_soc_set_dual_mac_config(tp_wma_handle wma_handle, + struct sir_dual_mac_config *msg) +{ + wmi_soc_set_dual_mac_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return CDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set dual mode config is NULL", __func__); + return CDF_STATUS_E_NULL_VALUE; + } + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_FAILURE; + } + + cmd = (wmi_soc_set_dual_mac_config_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_soc_set_dual_mac_config_cmd_fixed_param)); + cmd->concurrent_scan_config_bits = msg->scan_config; + cmd->fw_mode_config_bits = msg->fw_mode_config; + WMA_LOGI("%s: scan_config:%x fw_mode_config:%x", + __func__, msg->scan_config, msg->fw_mode_config); + + wma_handle->dual_mac_cfg.req_scan_config = msg->scan_config; + wma_handle->dual_mac_cfg.req_fw_mode_config = msg->fw_mode_config; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID)) { + WMA_LOGE("%s: Failed to send WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID", + __func__); + cdf_nbuf_free(buf); + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_crash_inject() - sends command to FW to simulate crash + * @wma_handle: pointer of WMA context + * @type: subtype of the command + * @delay_time_ms: time in milliseconds for FW to delay the crash + * + * This function will send a command to FW in order to simulate different + * kinds of FW crashes. + * + * Return: 0 for success or reasons for failure + */ +int wma_crash_inject(tp_wma_handle wma_handle, uint32_t type, + uint32_t delay_time_ms) +{ + return wmi_crash_inject(wma_handle->wmi_handle, type, delay_time_ms); +} +#if defined(FEATURE_LRO) +/** + * wma_lro_init() - sends LRO configuration to FW + * @lro_config: pointer to the config parameters + * + * This function ends LRO configuration to FW. + * + * Return: 0 for success or reasons for failure + */ +int wma_lro_init(struct wma_lro_config_cmd_t *lro_config) +{ + cds_msg_t msg = {0}; + struct wma_lro_config_cmd_t *iwcmd; + + iwcmd = cdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + WMA_LOGE("memory allocation for WMA_LRO_CONFIG_CMD failed!"); + return -ENOMEM; + } + + *iwcmd = *lro_config; + + msg.type = WMA_LRO_CONFIG_CMD; + msg.reserved = 0; + msg.bodyptr = iwcmd; + + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) { + WMA_LOGE("Failed to post WMA_LRO_CONFIG_CMD msg!"); + cdf_mem_free(iwcmd); + return -EAGAIN; + } + + WMA_LOGD("sending the LRO configuration to the fw"); + return 0; +} +#endif diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c new file mode 100644 index 0000000000..c6f0b3ab6b --- /dev/null +++ b/core/wma/src/wma_mgmt.c @@ -0,0 +1,3208 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_mgmt.c + * + * This file contains STA/SAP/IBSS and protocol related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" +#include "dfs.h" +#include "wma_internal.h" + +/** + * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL + * @wma: wma handle + * @pdev: txrx pdev + * @vdev_id: vdev id + * @param_buf: SWBA parameters + * + * Return: none + */ +static void wma_send_bcn_buf_ll(tp_wma_handle wma, + ol_txrx_pdev_handle pdev, + uint8_t vdev_id, + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf) +{ + wmi_bcn_send_from_host_cmd_fixed_param *cmd; + struct ieee80211_frame *wh; + struct beacon_info *bcn; + wmi_tim_info *tim_info = param_buf->tim_info; + uint8_t *bcn_payload; + wmi_buf_t wmi_buf; + CDF_STATUS ret; + struct beacon_tim_ie *tim_ie; + wmi_p2p_noa_info *p2p_noa_info = param_buf->p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + uint8_t i; + int status; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn->buf) { + WMA_LOGE("%s: Invalid beacon buffer", __func__); + return; + } + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return; + } + + cdf_spin_lock_bh(&bcn->lock); + + bcn_payload = cdf_nbuf_data(bcn->buf); + + tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]); + + if (tim_info->tim_changed) { + if (tim_info->tim_num_ps_pending) + cdf_mem_copy(&tim_ie->tim_bitmap, tim_info->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + else + cdf_mem_zero(&tim_ie->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + /* + * Currently we support fixed number of + * peers as limited by HAL_NUM_STA. + * tim offset is always 0 + */ + tim_ie->tim_bitctl = 0; + } + + /* Update DTIM Count */ + if (tim_ie->dtim_count == 0) + tim_ie->dtim_count = tim_ie->dtim_period - 1; + else + tim_ie->dtim_count--; + + /* + * DTIM count needs to be backedup so that + * when umac updates the beacon template + * current dtim count can be updated properly + */ + bcn->dtim_count = tim_ie->dtim_count; + + /* update state for buffered multicast frames on DTIM */ + if (tim_info->tim_mcast && (tim_ie->dtim_count == 0 || + tim_ie->dtim_period == 1)) + tim_ie->tim_bitctl |= 1; + else + tim_ie->tim_bitctl &= ~1; + + /* To avoid sw generated frame sequence the same as H/W generated frame, + * the value lower than min_sw_seq is reserved for HW generated frame */ + if ((bcn->seq_no & IEEE80211_SEQ_MASK) < MIN_SW_SEQ) + bcn->seq_no = MIN_SW_SEQ; + + wh = (struct ieee80211_frame *)bcn_payload; + *(uint16_t *) &wh->i_seq[0] = htole16(bcn->seq_no + << IEEE80211_SEQ_SEQ_SHIFT); + bcn->seq_no++; + + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + cdf_mem_zero(&noa_ie, sizeof(noa_ie)); + + noa_ie.index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + noa_ie.oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + noa_ie.ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + noa_ie.num_descriptors = + (uint8_t) WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " + "num_descriptors = %u", __func__, noa_ie.index, + noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); + for (i = 0; i < noa_ie.num_descriptors; i++) { + noa_ie.noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + noa_ie.noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + noa_ie.noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + noa_ie.noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + WMA_LOGI("%s: NoA descriptor[%d] type_count %u, " + "duration %u, interval %u, start_time = %u", + __func__, i, + noa_ie.noa_descriptors[i].type_count, + noa_ie.noa_descriptors[i].duration, + noa_ie.noa_descriptors[i].interval, + noa_ie.noa_descriptors[i].start_time); + } + wma_update_noa(bcn, &noa_ie); + + /* Send a msg to LIM to update the NoA IE in probe response + * frames transmitted by the host */ + wma_update_probe_resp_noa(wma, &noa_ie); + } + + if (bcn->dma_mapped) { + cdf_nbuf_unmap_single(pdev->osdev, bcn->buf, CDF_DMA_TO_DEVICE); + bcn->dma_mapped = 0; + } + ret = cdf_nbuf_map_single(pdev->osdev, bcn->buf, CDF_DMA_TO_DEVICE); + if (ret != CDF_STATUS_SUCCESS) { + cdf_nbuf_free(wmi_buf); + WMA_LOGE("%s: failed map beacon buf to DMA region", __func__); + cdf_spin_unlock_bh(&bcn->lock); + return; + } + + bcn->dma_mapped = 1; + cmd = (wmi_bcn_send_from_host_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_bcn_send_from_host_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->data_len = bcn->len; + cmd->frame_ctrl = *((A_UINT16 *) wh->i_fc); + cmd->frag_ptr = cdf_nbuf_get_frag_paddr_lo(bcn->buf, 0); + + /* notify Firmware of DTM and mcast/bcast traffic */ + if (tim_ie->dtim_count == 0) { + cmd->dtim_flag |= WMI_BCN_SEND_DTIM_ZERO; + /* deliver mcast/bcast traffic in next DTIM beacon */ + if (tim_ie->tim_bitctl & 0x01) + cmd->dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET; + } + + status = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, sizeof(*cmd), + WMI_PDEV_SEND_BCN_CMDID); + + if (status != EOK) { + WMA_LOGE("Failed to send WMI_PDEV_SEND_BCN_CMDID command"); + wmi_buf_free(wmi_buf); + } + cdf_spin_unlock_bh(&bcn->lock); +} + +/** + * wma_beacon_swba_handler() - swba event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * SWBA event is alert event to Host requesting host to Queue a beacon + * for transmission use only in host beacon mode + * + * Return: 0 for success or error code + */ +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_host_swba_event_fixed_param *swba_event; + uint32_t vdev_map; + ol_txrx_pdev_handle pdev; + uint8_t vdev_id = 0; + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid swba event buffer"); + return -EINVAL; + } + swba_event = param_buf->fixed_param; + vdev_map = swba_event->vdev_map; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + + for (; vdev_map; vdev_id++, vdev_map >>= 1) { + if (!(vdev_map & 0x1)) + continue; + if (!ol_cfg_is_high_latency(pdev->ctrl_pdev)) + wma_send_bcn_buf_ll(wma, pdev, vdev_id, param_buf); + break; + } + return 0; +} + +/** + * wma_peer_sta_kickout_event_handler() - kickout event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * Kickout event is received from firmware on observing beacon miss + * It handles kickout event for different modes and indicate to + * upper layers. + * + * Return: 0 for success or error code + */ +int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL; + wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL; + uint8_t vdev_id, peer_id, macaddr[IEEE80211_ADDR_LEN]; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + tpDeleteStaContext del_sta_ctx; + tpSirIbssPeerInactivityInd p_inactivity; + + WMA_LOGD("%s: Enter", __func__); + param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event; + kickout_event = param_buf->fixed_param; + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr); + peer = ol_txrx_find_peer_by_addr(pdev, macaddr, &peer_id); + if (!peer) { + WMA_LOGE("PEER [%pM] not found", macaddr); + return -EINVAL; + } + + if (ol_txrx_get_vdevid(peer, &vdev_id) != CDF_STATUS_SUCCESS) { + WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr); + return -EINVAL; + } + + WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d", + __func__, macaddr, wma->interfaces[vdev_id].addr, vdev_id, + peer_id, kickout_event->reason); + + switch (kickout_event->reason) { + case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT: + p_inactivity = (tpSirIbssPeerInactivityInd) + cdf_mem_malloc(sizeof(tSirIbssPeerInactivityInd)); + if (!p_inactivity) { + WMA_LOGE("CDF MEM Alloc Failed for tSirIbssPeerInactivity"); + return -ENOMEM; + } + + p_inactivity->staIdx = peer_id; + cdf_mem_copy(p_inactivity->peerAddr, macaddr, + IEEE80211_ADDR_LEN); + wma_send_msg(wma, WMA_IBSS_PEER_INACTIVITY_IND, + (void *)p_inactivity, 0); + goto exit_handler; + break; + +#ifdef FEATURE_WLAN_TDLS + case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT: + del_sta_ctx = (tpDeleteStaContext) + cdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + WMA_LOGE("%s: mem alloc failed for tDeleteStaContext for TDLS peer: %pM", + __func__, macaddr); + return -ENOMEM; + } + + del_sta_ctx->staId = peer_id; + cdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + cdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].bssid, + IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); + goto exit_handler; + break; +#endif /* FEATURE_WLAN_TDLS */ + + case WMI_PEER_STA_KICKOUT_REASON_XRETRY: + if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && + (wma->interfaces[vdev_id].sub_type == 0 || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && + cdf_mem_compare(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + /* + * KICKOUT event is for current station-AP connection. + * Treat it like final beacon miss. Station may not have + * missed beacons but not able to transmit frames to AP + * for a long time. Must disconnect to get out of + * this sticky situation. + * In future implementation, roaming module will also + * handle this event and perform a scan. + */ + WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id); + goto exit_handler; + } + break; + + case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED: + /* + * Default legacy value used by original firmware implementation. + */ + if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && + (wma->interfaces[vdev_id].sub_type == 0 || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && + cdf_mem_compare(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + /* + * KICKOUT event is for current station-AP connection. + * Treat it like final beacon miss. Station may not have + * missed beacons but not able to transmit frames to AP + * for a long time. Must disconnect to get out of + * this sticky situation. + * In future implementation, roaming module will also + * handle this event and perform a scan. + */ + WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id); + goto exit_handler; + } + break; + + case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY: + default: + break; + } + + /* + * default action is to send delete station context indication to LIM + */ + del_sta_ctx = + (tpDeleteStaContext) cdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + WMA_LOGE("CDF MEM Alloc Failed for tDeleteStaContext"); + return -ENOMEM; + } + + del_sta_ctx->staId = peer_id; + cdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + cdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx, + 0); + +exit_handler: + WMA_LOGD("%s: Exit", __func__); + return 0; +} + +/** + * wma_unified_bcntx_status_event_handler() - beacon tx status event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: data length + * + * WMI Handler for WMI_OFFLOAD_BCN_TX_STATUS_EVENTID event from firmware. + * This event is generated by FW when the beacon transmission is offloaded + * and the host performs beacon template modification using WMI_BCN_TMPL_CMDID + * The FW generates this event when the first successful beacon transmission + * after template update + * + * Return: 0 for success or error code + */ +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *param_buf; + wmi_offload_bcn_tx_status_event_fixed_param *resp_event; + tSirFirstBeaconTxCompleteInd *beacon_tx_complete_ind; + + param_buf = + (WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid bcn tx response event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + + /* Check for valid handle to ensure session is not + * deleted in any race + */ + if (!wma->interfaces[resp_event->vdev_id].handle) { + WMA_LOGE("%s: The session does not exist", __func__); + return -EINVAL; + } + + /* Beacon Tx Indication supports only AP mode. Ignore in other modes */ + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == false) { + WMA_LOGI("%s: Beacon Tx Indication does not support type %d and sub_type %d", + __func__, wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + return 0; + } + + beacon_tx_complete_ind = (tSirFirstBeaconTxCompleteInd *) + cdf_mem_malloc(sizeof(tSirFirstBeaconTxCompleteInd)); + if (!beacon_tx_complete_ind) { + WMA_LOGE("%s: Failed to alloc beacon_tx_complete_ind", + __func__); + return -ENOMEM; + } + + beacon_tx_complete_ind->messageType = WMA_DFS_BEACON_TX_SUCCESS_IND; + beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd); + beacon_tx_complete_ind->bssIdx = resp_event->vdev_id; + + wma_send_msg(wma, WMA_DFS_BEACON_TX_SUCCESS_IND, + (void *)beacon_tx_complete_ind, 0); + return 0; +} + +/** + * wma_get_link_probe_timeout() - get link timeout based on sub type + * @mac: UMAC handler + * @sub_type: vdev syb type + * @max_inactive_time: return max inactive time + * @max_unresponsive_time: return max unresponsive time + * + * Return: none + */ +static inline void wma_get_link_probe_timeout(struct sAniSirGlobal *mac, + uint32_t sub_type, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ + uint32_t keep_alive; + uint16_t lm_id, ka_id; + + switch (sub_type) { + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + lm_id = WNI_CFG_GO_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_GO_KEEP_ALIVE_TIMEOUT; + break; + default: + /*For softAp the subtype value will be zero */ + lm_id = WNI_CFG_AP_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_AP_KEEP_ALIVE_TIMEOUT; + } + + if (wlan_cfg_get_int(mac, lm_id, max_inactive_time) != eSIR_SUCCESS) { + WMA_LOGE("Failed to read link monitor for subtype %d", + sub_type); + *max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS; + } + + if (wlan_cfg_get_int(mac, ka_id, &keep_alive) != eSIR_SUCCESS) { + WMA_LOGE("Failed to read keep alive for subtype %d", sub_type); + keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS; + } + *max_unresponsive_time = *max_inactive_time + keep_alive; +} + +/** + * wma_set_sap_keepalive() - set SAP keep alive parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t min_inactive_time, max_inactive_time, max_unresponsive_time; + struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + return; + } + + wma_get_link_probe_timeout(mac, wma->interfaces[vdev_id].sub_type, + &max_inactive_time, &max_unresponsive_time); + + min_inactive_time = max_inactive_time / 2; + + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, + vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + min_inactive_time)) + WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME"); + + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, + vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + max_inactive_time)) + WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME"); + + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, + vdev_id, WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + max_unresponsive_time)) + WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME"); + + WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u" + " max_unresponsive_time: %u", __func__, vdev_id, + min_inactive_time, max_inactive_time, max_unresponsive_time); +} + +/** + * wma_set_sta_keep_alive() - set sta keep alive parameters + * @wma: wma handle + * @vdev_id: vdev id + * @method: method for keep alive + * @timeperiod: time period + * @hostv4addr: host ipv4 address + * @destv4addr: dst ipv4 address + * @destmac: destination mac + * + * This function sets keep alive related parameters in fw. + * + * Return: none + */ +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac) +{ + wmi_buf_t buf; + WMI_STA_KEEPALIVE_CMD_fixed_param *cmd; + WMI_STA_KEEPALVE_ARP_RESPONSE *arp_rsp; + uint8_t *buf_ptr; + int len; + + WMA_LOGD("%s: Enter", __func__); + + if (timeperiod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + WMA_LOGE("Invalid period %d Max limit %d", timeperiod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return; + } + + len = sizeof(*cmd) + sizeof(*arp_rsp); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("wmi_buf_alloc failed"); + return; + } + + cmd = (WMI_STA_KEEPALIVE_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_STA_KEEPALIVE_CMD_fixed_param)); + cmd->interval = timeperiod; + cmd->enable = (timeperiod) ? 1 : 0; + cmd->vdev_id = vdev_id; + WMA_LOGD("Keep Alive: vdev_id:%d interval:%u method:%d", vdev_id, + timeperiod, method); + arp_rsp = (WMI_STA_KEEPALVE_ARP_RESPONSE *) (buf_ptr + sizeof(*cmd)); + WMITLV_SET_HDR(&arp_rsp->tlv_header, + WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, + WMITLV_GET_STRUCT_TLVLEN(WMI_STA_KEEPALVE_ARP_RESPONSE)); + + if (method == SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP) { + cmd->method = WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE; + cdf_mem_copy(&arp_rsp->sender_prot_addr, hostv4addr, + SIR_IPV4_ADDR_LEN); + cdf_mem_copy(&arp_rsp->target_prot_addr, destv4addr, + SIR_IPV4_ADDR_LEN); + WMI_CHAR_ARRAY_TO_MAC_ADDR(destmac, &arp_rsp->dest_mac_addr); + } else { + cmd->method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; + } + + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_STA_KEEPALIVE_CMDID)) { + WMA_LOGE("Failed to set KeepAlive"); + cdf_nbuf_free(buf); + } + + WMA_LOGD("%s: Exit", __func__); + return; +} + +/** + * wma_vdev_install_key_complete_event_handler() - install key complete handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * This event is sent by fw once WPA/WPA2 keys are installed in fw. + * + * Return: 0 for success or error code + */ +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *param_buf = NULL; + wmi_vdev_install_key_complete_event_fixed_param *key_fp = NULL; + + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + key_fp = param_buf->fixed_param; + if (!key_fp) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + /* + * Do nothing for now. Completion of set key is already indicated to lim + */ + WMA_LOGI("%s: WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID", __func__); + return 0; +} +/* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec + * 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ +static const uint8_t wma_mpdu_spacing[] = { 0, 1, 1, 1, 2, 4, 8, 16 }; + +/** + * wma_parse_mpdudensity() - give mpdu spacing from mpdu density + * @mpdudensity: mpdu density + * + * Return: mpdu spacing or 0 for error + */ +static inline uint8_t wma_parse_mpdudensity(uint8_t mpdudensity) +{ + if (mpdudensity < sizeof(wma_mpdu_spacing)) + return wma_mpdu_spacing[mpdudensity]; + else + return 0; +} + +/** + * wmi_unified_send_peer_assoc() - send peer assoc command to fw + * @wma: wma handle + * @nw_type: nw type + * @params: add sta params + * + * This function send peer assoc command to firmware with + * different parameters. + * + * Return: 0 for success or error code + */ +int32_t wmi_unified_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params) +{ + ol_txrx_pdev_handle pdev; + wmi_peer_assoc_complete_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int32_t ret, max_rates, i; + uint8_t rx_stbc, tx_stbc; + uint8_t *rate_pos, *buf_ptr; + wmi_rate_set peer_legacy_rates, peer_ht_rates; + wmi_vht_rate_set *mcs; + uint32_t num_peer_legacy_rates; + uint32_t num_peer_ht_rates; + uint32_t num_peer_11b_rates = 0; + uint32_t num_peer_11a_rates = 0; + uint32_t phymode; + uint32_t peer_nss = 1; + struct wma_txrx_node *intr = NULL; + + if (NULL == params) { + WMA_LOGE("%s: params is NULL", __func__); + return -EINVAL; + } + intr = &wma->interfaces[params->smesessionId]; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return -EINVAL; + } + + cdf_mem_zero(&peer_legacy_rates, sizeof(wmi_rate_set)); + cdf_mem_zero(&peer_ht_rates, sizeof(wmi_rate_set)); + + phymode = wma_peer_phymode(nw_type, params->staType, + params->htCapable, + params->ch_width, + params->vhtCapable); + + /* Legacy Rateset */ + rate_pos = (uint8_t *) peer_legacy_rates.rates; + for (i = 0; i < SIR_NUM_11B_RATES; i++) { + if (!params->supportedRates.llbRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llbRates[i]; + num_peer_11b_rates++; + } + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (!params->supportedRates.llaRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llaRates[i]; + num_peer_11a_rates++; + } + + if ((phymode == MODE_11A && num_peer_11a_rates == 0) || + (phymode == MODE_11B && num_peer_11b_rates == 0)) { + WMA_LOGW("%s: Invalid phy rates. phymode 0x%x, 11b_rates %d, 11a_rates %d", + __func__, phymode, num_peer_11b_rates, num_peer_11a_rates); + return -EINVAL; + } + /* Set the Legacy Rates to Word Aligned */ + num_peer_legacy_rates = roundup(peer_legacy_rates.num_rates, + sizeof(uint32_t)); + + /* HT Rateset */ + max_rates = sizeof(peer_ht_rates.rates) / + sizeof(peer_ht_rates.rates[0]); + rate_pos = (uint8_t *) peer_ht_rates.rates; + for (i = 0; i < MAX_SUPPORTED_RATES; i++) { + if (params->supportedRates.supportedMCSSet[i / 8] & + (1 << (i % 8))) { + rate_pos[peer_ht_rates.num_rates++] = i; + if (i >= 8) { + /* MCS8 or higher rate is present, must be 2x2 */ + peer_nss = 2; + } + } + if (peer_ht_rates.num_rates == max_rates) + break; + } + + if (params->htCapable && !peer_ht_rates.num_rates) { + uint8_t temp_ni_rates[8] = { 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7}; + /* + * Workaround for EV 116382: The peer is marked HT but with + * supported rx mcs set is set to 0. 11n spec mandates MCS0-7 + * for a HT STA. So forcing the supported rx mcs rate to + * MCS 0-7. This workaround will be removed once we get + * clarification from WFA regarding this STA behavior. + */ + + /* TODO: Do we really need this? */ + WMA_LOGW("Peer is marked as HT capable but supported mcs rate is 0"); + peer_ht_rates.num_rates = sizeof(temp_ni_rates); + cdf_mem_copy((uint8_t *) peer_ht_rates.rates, temp_ni_rates, + peer_ht_rates.num_rates); + } + + /* Set the Peer HT Rates to Word Aligned */ + num_peer_ht_rates = roundup(peer_ht_rates.num_rates, sizeof(uint32_t)); + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + /* Place holder for peer legacy rate array */ + (num_peer_legacy_rates * sizeof(uint8_t)) + /* peer legacy rate array size */ + WMI_TLV_HDR_SIZE + /* Place holder for peer Ht rate array */ + (num_peer_ht_rates * sizeof(uint8_t)) + /* peer HT rate array size */ + sizeof(wmi_vht_rate_set); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_peer_assoc_complete_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_assoc_complete_cmd_fixed_param)); + + /* in ap/ibss mode and for tdls peer, use mac address of the peer in + * the other end as the new peer address; in sta mode, use bss id to + * be the new peer address + */ + if ((wma_is_vdev_in_ap_mode(wma, params->smesessionId)) +#ifdef QCA_IBSS_SUPPORT + || (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) +#endif /* QCA_IBSS_SUPPORT */ +#ifdef FEATURE_WLAN_TDLS + || (STA_ENTRY_TDLS_PEER == params->staType) +#endif /* FEATURE_WLAN_TDLS */ + ) + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->staMac, &cmd->peer_macaddr); + else + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssId, &cmd->peer_macaddr); + cmd->vdev_id = params->smesessionId; + cmd->peer_new_assoc = 1; + cmd->peer_associd = params->assocId; + + /* + * The target only needs a subset of the flags maintained in the host. + * Just populate those flags and send it down + */ + cmd->peer_flags = 0; + + if (params->wmmEnabled) + cmd->peer_flags |= WMI_PEER_QOS; + + if (params->uAPSD) { + cmd->peer_flags |= WMI_PEER_APSD; + WMA_LOGD("Set WMI_PEER_APSD: uapsd Mask %d", params->uAPSD); + } + + if (params->htCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->ch_width) { + cmd->peer_flags |= WMI_PEER_40MHZ; + cmd->peer_rate_caps |= WMI_RC_CW40_FLAG; + if (params->fShortGI40Mhz) + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + } else if (params->fShortGI20Mhz) + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + +#ifdef WLAN_FEATURE_11AC + if (params->vhtCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_VHT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->ch_width == CH_WIDTH_80MHZ) + cmd->peer_flags |= WMI_PEER_80MHZ; + else if (params->ch_width == CH_WIDTH_160MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + else if (params->ch_width == CH_WIDTH_80P80MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + + cmd->peer_vht_caps = params->vht_caps; +#endif /* WLAN_FEATURE_11AC */ + + if (params->rmfEnabled) + cmd->peer_flags |= WMI_PEER_PMF; + + rx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_RXSTBC) >> + IEEE80211_HTCAP_C_RXSTBC_S; + if (rx_stbc) { + cmd->peer_flags |= WMI_PEER_STBC; + cmd->peer_rate_caps |= (rx_stbc << WMI_RC_RX_STBC_FLAG_S); + } + + tx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_TXSTBC) >> + IEEE80211_HTCAP_C_TXSTBC_S; + if (tx_stbc) { + cmd->peer_flags |= WMI_PEER_STBC; + cmd->peer_rate_caps |= (tx_stbc << WMI_RC_TX_STBC_FLAG_S); + } + + if (params->htLdpcCapable || params->vhtLdpcCapable) + cmd->peer_flags |= WMI_PEER_LDPC; + + switch (params->mimoPS) { + case eSIR_HT_MIMO_PS_STATIC: + cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS; + break; + case eSIR_HT_MIMO_PS_DYNAMIC: + cmd->peer_flags |= WMI_PEER_DYN_MIMOPS; + break; + case eSIR_HT_MIMO_PS_NO_LIMIT: + cmd->peer_flags |= WMI_PEER_SPATIAL_MUX; + break; + default: + break; + } + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) + cmd->peer_flags |= WMI_PEER_AUTH; +#endif /* FEATURE_WLAN_TDLS */ + + if (params->wpa_rsn +#ifdef FEATURE_WLAN_WAPI + || params->encryptType == eSIR_ED_WPI +#endif /* FEATURE_WLAN_WAPI */ + ) + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; + if (params->wpa_rsn >> 1) + cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; + + ol_txrx_peer_state_update(pdev, params->bssId, ol_txrx_peer_state_auth); + +#ifdef FEATURE_WLAN_WAPI + if (params->encryptType == eSIR_ED_WPI) { + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_DROP_UNENCRY, + false); + if (ret) { + WMA_LOGE + ("Set WMI_VDEV_PARAM_DROP_UNENCRY Param status:%d\n", + ret); + cdf_nbuf_free(buf); + return ret; + } + } +#endif /* FEATURE_WLAN_WAPI */ + + cmd->peer_caps = params->capab_info; + cmd->peer_listen_intval = params->listenInterval; + cmd->peer_ht_caps = params->ht_caps; + cmd->peer_max_mpdu = (1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + params->maxAmpduSize)) - 1; + cmd->peer_mpdu_density = wma_parse_mpdudensity(params->maxAmpduDensity); + + if (params->supportedRates.supportedMCSSet[1] && + params->supportedRates.supportedMCSSet[2]) + cmd->peer_rate_caps |= WMI_RC_TS_FLAG; + else if (params->supportedRates.supportedMCSSet[1]) + cmd->peer_rate_caps |= WMI_RC_DS_FLAG; + + /* Update peer legacy rate information */ + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, num_peer_legacy_rates); + buf_ptr += WMI_TLV_HDR_SIZE; + cmd->num_peer_legacy_rates = peer_legacy_rates.num_rates; + cdf_mem_copy(buf_ptr, peer_legacy_rates.rates, + peer_legacy_rates.num_rates); + + /* Update peer HT rate information */ + buf_ptr += num_peer_legacy_rates; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, num_peer_ht_rates); + buf_ptr += WMI_TLV_HDR_SIZE; + cmd->num_peer_ht_rates = peer_ht_rates.num_rates; + cdf_mem_copy(buf_ptr, peer_ht_rates.rates, peer_ht_rates.num_rates); + + /* VHT Rates */ + buf_ptr += num_peer_ht_rates; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_wmi_vht_rate_set, + WMITLV_GET_STRUCT_TLVLEN(wmi_vht_rate_set)); + + cmd->peer_nss = peer_nss; + + WMA_LOGD("peer_nss %d peer_ht_rates.num_rates %d ", cmd->peer_nss, + peer_ht_rates.num_rates); + + mcs = (wmi_vht_rate_set *) buf_ptr; + if (params->vhtCapable) { +#define VHT2x2MCSMASK 0xc + mcs->rx_max_rate = params->supportedRates.vhtRxHighestDataRate; + mcs->rx_mcs_set = params->supportedRates.vhtRxMCSMap; + mcs->tx_max_rate = params->supportedRates.vhtTxHighestDataRate; + mcs->tx_mcs_set = params->supportedRates.vhtTxMCSMap; + + if (params->vhtSupportedRxNss) { + cmd->peer_nss = params->vhtSupportedRxNss; + } else { + cmd->peer_nss = ((mcs->rx_mcs_set & VHT2x2MCSMASK) + == VHT2x2MCSMASK) ? 1 : 2; + } + } + + /* + * Limit nss to max number of rf chain supported by target + * Otherwise Fw will crash + */ + wma_update_txrx_chainmask(wma->num_rf_chains, &cmd->peer_nss); + + intr->nss = cmd->peer_nss; + cmd->peer_phymode = phymode; + WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x " + "peer_caps %x listen_intval %d ht_caps %x max_mpdu %d " + "nss %d phymode %d peer_mpdu_density %d encr_type %d " + "cmd->peer_vht_caps %x", __func__, + cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + cmd->peer_rate_caps, cmd->peer_caps, + cmd->peer_listen_intval, cmd->peer_ht_caps, + cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode, + cmd->peer_mpdu_density, params->encryptType, + cmd->peer_vht_caps); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PEER_ASSOC_CMDID); + if (ret != EOK) { + WMA_LOGP("%s: Failed to send peer assoc command ret = %d", + __func__, ret); + cdf_nbuf_free(buf); + } + return ret; +} + +/** + * wmi_unified_vdev_set_gtx_cfg_send() - set GTX params + * @wmi_handle: wmi handle + * @if_id: vdev id + * @gtx_info: GTX config params + * + * This function set GTX related params in firmware. + * + * Return: 0 for success or error code + */ +int wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, uint32_t if_id, + gtx_config_t *gtx_info) +{ + wmi_vdev_set_gtx_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_set_gtx_params_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __FUNCTION__); + return -ENOMEM; + } + cmd = (wmi_vdev_set_gtx_params_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_gtx_params_cmd_fixed_param)); + cmd->vdev_id = if_id; + + cmd->gtxRTMask[0] = gtx_info->gtxRTMask[0]; + cmd->gtxRTMask[1] = gtx_info->gtxRTMask[1]; + cmd->userGtxMask = gtx_info->gtxUsrcfg; + cmd->gtxPERThreshold = gtx_info->gtxPERThreshold; + cmd->gtxPERMargin = gtx_info->gtxPERMargin; + cmd->gtxTPCstep = gtx_info->gtxTPCstep; + cmd->gtxTPCMin = gtx_info->gtxTPCMin; + cmd->gtxBWMask = gtx_info->gtxBWMask; + + WMA_LOGD("Setting vdev%d GTX values:htmcs 0x%x, vhtmcs 0x%x, usermask 0x%x, \ + gtxPERThreshold %d, gtxPERMargin %d, gtxTPCstep %d, gtxTPCMin %d, \ + gtxBWMask 0x%x.", if_id, cmd->gtxRTMask[0], cmd->gtxRTMask[1], + cmd->userGtxMask, cmd->gtxPERThreshold, cmd->gtxPERMargin, + cmd->gtxTPCstep, cmd->gtxTPCMin, cmd->gtxBWMask); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_GTX_PARAMS_CMDID); +} + +/** + * wma_update_protection_mode() - update protection mode + * @wma: wma handle + * @vdev_id: vdev id + * @llbcoexist: protection mode info + * + * This function set protection mode(RTS/CTS) to fw for passed vdev id. + * + * Return: none + */ +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist) +{ + int ret; + enum ieee80211_protmode prot_mode; + + prot_mode = llbcoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE; + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, + prot_mode); + + if (ret) + WMA_LOGE("Failed to send wmi protection mode cmd"); + else + WMA_LOGD("Updated protection mode %d to target", prot_mode); +} + +/** + * wma_update_beacon_interval() - update beacon interval in fw + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: becon interval + * + * Return: none + */ +static void +wma_update_beacon_interval(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beaconInterval) +{ + int ret; + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_BEACON_INTERVAL, + beaconInterval); + + if (ret) + WMA_LOGE("Failed to update beacon interval"); + else + WMA_LOGI("Updated beacon interval %d for vdev %d", + beaconInterval, vdev_id); +} + +/** + * wma_process_update_beacon_params() - update beacon parameters to target + * @wma: wma handle + * @bcn_params: beacon parameters + * + * Return: none + */ +void +wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params) +{ + if (!bcn_params) { + WMA_LOGE("bcn_params NULL"); + return; + } + + if (bcn_params->smeSessionId >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", bcn_params->smeSessionId); + return; + } + + if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) { + wma_update_beacon_interval(wma, bcn_params->smeSessionId, + bcn_params->beaconInterval); + } + + if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED) + wma_update_protection_mode(wma, bcn_params->smeSessionId, + bcn_params->llbCoexist); +} + +/** + * wma_update_cfg_params() - update cfg parameters to target + * @wma: wma handle + * @cfgParam: cfg parameter + * + * Return: none + */ +void wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam) +{ + uint8_t vdev_id; + uint32_t param_id; + uint32_t cfg_val; + int ret; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *pmac; + + switch (cfgParam->bodyval) { + case WNI_CFG_RTS_THRESHOLD: + param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + break; + case WNI_CFG_FRAGMENTATION_THRESHOLD: + param_id = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD; + break; + default: + WMA_LOGD("Unhandled cfg parameter %d", cfgParam->bodyval); + return; + } + + pmac = cds_get_context(CDF_MODULE_ID_PE); + + if (NULL == pmac) { + WMA_LOGE("%s: Failed to get pmac", __func__); + return; + } + + if (wlan_cfg_get_int(pmac, (uint16_t) cfgParam->bodyval, + &cfg_val) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for CFG PARAMS %d. returning without updating", + cfgParam->bodyval); + return; + } + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (wma->interfaces[vdev_id].handle != 0) { + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, + vdev_id, param_id, + cfg_val); + if (ret) + WMA_LOGE("Update cfg params failed for vdevId %d", + vdev_id); + } + } +} + +/** + * wma_read_cfg_wepkey() - fill key_info for WEP key + * @wma_handle: wma handle + * @key_info: key_info ptr + * @def_key_idx: default key index + * @num_keys: number of keys + * + * This function reads WEP keys from cfg and fills + * up key_info. + * + * Return: none + */ +static void wma_read_cfg_wepkey(tp_wma_handle wma_handle, + tSirKeys *key_info, uint32_t *def_key_idx, + uint8_t *num_keys) +{ + tSirRetStatus status; + uint32_t val = SIR_MAC_KEY_LENGTH; + uint8_t i, j; + + WMA_LOGD("Reading WEP keys from cfg"); + /* NOTE:def_key_idx is initialized to 0 by the caller */ + status = wlan_cfg_get_int(wma_handle->mac_context, + WNI_CFG_WEP_DEFAULT_KEYID, def_key_idx); + if (status != eSIR_SUCCESS) + WMA_LOGE("Unable to read default id, defaulting to 0"); + + for (i = 0, j = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + status = wlan_cfg_get_str(wma_handle->mac_context, + (uint16_t) WNI_CFG_WEP_DEFAULT_KEY_1 + + i, key_info[j].key, &val); + if (status != eSIR_SUCCESS) { + WMA_LOGE("WEP key is not configured at :%d", i); + } else { + key_info[j].keyId = i; + key_info[j].keyLength = (uint16_t) val; + j++; + } + } + *num_keys = j; +} + +/** + * wma_setup_install_key_cmd() - fill wmi buffer as per key parameters + * @wma_handle: wma handle + * @key_params: key parameters + * @len: length + * @mode: op mode + * + * This function setsup wmi buffer from information + * passed in key_params. + * + * Return: filled wmi buffer ptr or NULL for error + */ +static wmi_buf_t wma_setup_install_key_cmd(tp_wma_handle wma_handle, + struct wma_set_key_params + *key_params, uint32_t *len, + uint8_t mode) +{ + wmi_vdev_install_key_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t *key_data; +#ifdef WLAN_FEATURE_11W + struct wma_txrx_node *iface = NULL; +#endif /* WLAN_FEATURE_11W */ + if ((key_params->key_type == eSIR_ED_NONE && + key_params->key_len) || (key_params->key_type != eSIR_ED_NONE && + !key_params->key_len)) { + WMA_LOGE("%s:Invalid set key request", __func__); + return NULL; + } + + *len = sizeof(*cmd) + roundup(key_params->key_len, sizeof(uint32_t)) + + WMI_TLV_HDR_SIZE; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, *len); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set key cmd"); + return NULL; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_install_key_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_install_key_cmd_fixed_param)); + cmd->vdev_id = key_params->vdev_id; + cmd->key_ix = key_params->key_idx; + WMI_CHAR_ARRAY_TO_MAC_ADDR(key_params->peer_mac, &cmd->peer_macaddr); + if (key_params->unicast) + cmd->key_flags |= PAIRWISE_USAGE; + else + cmd->key_flags |= GROUP_USAGE; + + switch (key_params->key_type) { + case eSIR_ED_NONE: + cmd->key_cipher = WMI_CIPHER_NONE; + break; + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + cmd->key_cipher = WMI_CIPHER_WEP; + if (key_params->unicast && + cmd->key_ix == key_params->def_key_idx) + cmd->key_flags |= TX_USAGE; + break; + case eSIR_ED_TKIP: + cmd->key_txmic_len = WMA_TXMIC_LEN; + cmd->key_rxmic_len = WMA_RXMIC_LEN; + cmd->key_cipher = WMI_CIPHER_TKIP; + break; +#ifdef FEATURE_WLAN_WAPI +#define WPI_IV_LEN 16 + case eSIR_ED_WPI: + { + /*initialize receive and transmit IV with default values */ + /* **Note: tx_iv must be sent in reverse** */ + unsigned char tx_iv[16] = { 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c}; + unsigned char rx_iv[16] = { 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x37}; + if (mode == wlan_op_mode_ap) { + /* Authenticator initializes the value of PN as + * 0x5C365C365C365C365C365C365C365C36 for MCastkey Update + */ + if (key_params->unicast) + tx_iv[0] = 0x37; + + rx_iv[WPI_IV_LEN - 1] = 0x36; + } else { + if (!key_params->unicast) + rx_iv[WPI_IV_LEN - 1] = 0x36; + } + + cmd->key_txmic_len = WMA_TXMIC_LEN; + cmd->key_rxmic_len = WMA_RXMIC_LEN; + + cdf_mem_copy(&cmd->wpi_key_rsc_counter, &rx_iv, + WPI_IV_LEN); + cdf_mem_copy(&cmd->wpi_key_tsc_counter, &tx_iv, + WPI_IV_LEN); + cmd->key_cipher = WMI_CIPHER_WAPI; + break; + } +#endif /* FEATURE_WLAN_WAPI */ + case eSIR_ED_CCMP: + cmd->key_cipher = WMI_CIPHER_AES_CCM; + break; +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: + cmd->key_cipher = WMI_CIPHER_AES_CMAC; + break; +#endif /* WLAN_FEATURE_11W */ + default: + /* TODO: MFP ? */ + WMA_LOGE("%s:Invalid encryption type:%d", __func__, + key_params->key_type); + cdf_nbuf_free(buf); + return NULL; + } + + buf_ptr += sizeof(wmi_vdev_install_key_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(key_params->key_len, sizeof(uint32_t))); + key_data = (A_UINT8 *) (buf_ptr + WMI_TLV_HDR_SIZE); +#ifdef BIG_ENDIAN_HOST + { + /* for big endian host, copy engine byte_swap is enabled + * But the key data content is in network byte order + * Need to byte swap the key data content - so when copy engine + * does byte_swap - target gets key_data content in the correct + * order. + */ + int8_t i; + uint32_t *destp, *srcp; + + destp = (uint32_t *) key_data; + srcp = (uint32_t *) key_params->key_data; + for (i = 0; + i < roundup(key_params->key_len, sizeof(uint32_t)) / 4; + i++) { + *destp = le32_to_cpu(*srcp); + destp++; + srcp++; + } + } +#else + cdf_mem_copy((void *)key_data, + (const void *)key_params->key_data, key_params->key_len); +#endif /* BIG_ENDIAN_HOST */ + cmd->key_len = key_params->key_len; + +#ifdef WLAN_FEATURE_11W + if (key_params->key_type == eSIR_ED_AES_128_CMAC) { + iface = &wma_handle->interfaces[key_params->vdev_id]; + if (iface) { + iface->key.key_length = key_params->key_len; + cdf_mem_copy(iface->key.key, + (const void *)key_params->key_data, + iface->key.key_length); + if ((cmd->key_ix == WMA_IGTK_KEY_INDEX_4) || + (cmd->key_ix == WMA_IGTK_KEY_INDEX_5)) + cdf_mem_zero(iface->key.key_id[cmd->key_ix - + WMA_IGTK_KEY_INDEX_4].ipn, + CMAC_IPN_LEN); + } + } +#endif /* WLAN_FEATURE_11W */ + + WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d" + " unicast %d peer_mac %pM def_key_idx %d", key_params->vdev_id, + key_params->key_idx, key_params->key_type, key_params->key_len, + key_params->unicast, key_params->peer_mac, + key_params->def_key_idx); + + return buf; +} + +/** + * wma_set_bsskey() - set encryption key to fw. + * @wma_handle: wma handle + * @key_info: key info + * + * Return: none + */ +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info) +{ + struct wma_set_key_params key_params; + wmi_buf_t buf; + int32_t status; + uint32_t len = 0, i; + uint32_t def_key_idx = 0; + ol_txrx_vdev_handle txrx_vdev; + + WMA_LOGD("BSS key setup"); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + + /* + * For IBSS, WMI expects the BSS key to be set per peer key + * So cache the BSS key in the wma_handle and re-use it when the + * STA key is been setup for a peer + */ + if (wlan_op_mode_ibss == txrx_vdev->opmode) { + key_info->status = CDF_STATUS_SUCCESS; + if (wma_handle->ibss_started > 0) + goto out; + WMA_LOGD("Caching IBSS Key"); + cdf_mem_copy(&wma_handle->ibsskey_info, key_info, + sizeof(tSetBssKeyParams)); + } + + cdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + if (txrx_vdev->opmode == wlan_op_mode_sta) { + cdf_mem_copy(key_params.peer_mac, + wma_handle->interfaces[key_info->smesessionId].bssid, + IEEE80211_ADDR_LEN); + } else { + /* vdev mac address will be passed for all other modes */ + cdf_mem_copy(key_params.peer_mac, txrx_vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + WMA_LOGA("BSS Key setup with vdev_mac %pM\n", + txrx_vdev->mac_addr.raw); + } + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = key_info->key[i].keyId; + + key_params.key_len = key_info->key[i].keyLength; + if (key_info->encType == eSIR_ED_TKIP) { + cdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + cdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + cdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + cdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: bss key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len, + txrx_vdev->opmode); + if (!buf) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = CDF_STATUS_E_NOMEM; + goto out; + } + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_INSTALL_KEY_CMDID); + if (status) { + cdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + } + + wma_handle->ibss_started++; + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = CDF_STATUS_SUCCESS; + +out: + wma_send_msg(wma_handle, WMA_SET_BSSKEY_RSP, (void *)key_info, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_calc_ibss_heart_beat_timer() - calculate IBSS heart beat timer + * @peer_num: number of peers + * + * Return: heart beat timer value + */ +static uint16_t wma_calc_ibss_heart_beat_timer(int16_t peer_num) +{ + /* heart beat timer value look-up table */ + /* entry index : (the number of currently connected peers) - 1 + entry value : the heart time threshold value in seconds for + detecting ibss peer departure */ + static const uint16_t heart_beat_timer[MAX_IBSS_PEERS] = { + 4, 4, 4, 4, 4, 4, 4, 4, + 8, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 16, 16, 16, 16 + }; + + if (peer_num < 1 || peer_num > MAX_IBSS_PEERS) + return 0; + + return heart_beat_timer[peer_num - 1]; + +} + +/** + * wma_adjust_ibss_heart_beat_timer() - set ibss heart beat timer in fw. + * @wma: wma handle + * @vdev_id: vdev id + * @peer_num_delta: peer number delta value + * + * Return: none + */ +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta) +{ + ol_txrx_vdev_handle vdev; + int16_t new_peer_num; + uint16_t new_timer_value_sec; + uint32_t new_timer_value_ms; + + if (peer_num_delta != 1 && peer_num_delta != -1) { + WMA_LOGE("Invalid peer_num_delta value %d", peer_num_delta); + return; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("vdev not found : vdev_id %d", vdev_id); + return; + } + + new_peer_num = vdev->ibss_peer_num + peer_num_delta; + if (new_peer_num > MAX_IBSS_PEERS || new_peer_num < 0) { + WMA_LOGE("new peer num %d out of valid boundary", new_peer_num); + return; + } + + /* adjust peer numbers */ + vdev->ibss_peer_num = new_peer_num; + + /* reset timer value if all peers departed */ + if (new_peer_num == 0) { + vdev->ibss_peer_heart_beat_timer = 0; + return; + } + + /* calculate new timer value */ + new_timer_value_sec = wma_calc_ibss_heart_beat_timer(new_peer_num); + if (new_timer_value_sec == 0) { + WMA_LOGE("timer value %d is invalid for peer number %d", + new_timer_value_sec, new_peer_num); + return; + } + if (new_timer_value_sec == vdev->ibss_peer_heart_beat_timer) { + WMA_LOGD("timer value %d stays same, no need to notify target", + new_timer_value_sec); + return; + } + + /* send new timer value to target */ + vdev->ibss_peer_heart_beat_timer = new_timer_value_sec; + + new_timer_value_ms = ((uint32_t) new_timer_value_sec) * 1000; + + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + new_timer_value_ms)) { + WMA_LOGE("Failed to set IBSS link monitoring timer value"); + return; + } + + WMA_LOGD("Set IBSS link monitor timer: peer_num = %d timer_value = %d", + new_peer_num, new_timer_value_ms); +} + +#endif /* QCA_IBSS_SUPPORT */ +/** + * wma_set_ibsskey_helper() - cached IBSS key in wma handle + * @wma_handle: wma handle + * @key_info: set bss key info + * @peerMacAddr: peer mac address + * + * Return: none + */ +static void wma_set_ibsskey_helper(tp_wma_handle wma_handle, + tpSetBssKeyParams key_info, + uint8_t *peerMacAddr) +{ + struct wma_set_key_params key_params; + wmi_buf_t buf; + int32_t status; + uint32_t len = 0, i; + uint32_t def_key_idx = 0; + ol_txrx_vdev_handle txrx_vdev; + + WMA_LOGD("BSS key setup for peer"); + ASSERT(NULL != peerMacAddr); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = CDF_STATUS_E_FAILURE; + return; + } + + cdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + ASSERT(wlan_op_mode_ibss == txrx_vdev->opmode); + + cdf_mem_copy(key_params.peer_mac, peerMacAddr, IEEE80211_ADDR_LEN); + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + key_params.key_idx = key_info->key[i].keyId; + key_params.key_len = key_info->key[i].keyLength; + if (key_info->encType == eSIR_ED_TKIP) { + cdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + cdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + cdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + cdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: peer bcast key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len, + txrx_vdev->opmode); + if (!buf) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + return; + } + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_INSTALL_KEY_CMDID); + if (status) { + cdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send install key command", + __func__); + } + } +} + +/** + * wma_set_stakey() - set encryption key + * @wma_handle: wma handle + * @key_info: station key info + * + * This function sets encryption key for WEP/WPA/WPA2 + * encryption mode in firmware and send response to upper layer. + * + * Return: none + */ +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info) +{ + wmi_buf_t buf; + int32_t status, i; + uint32_t len = 0; + ol_txrx_pdev_handle txrx_pdev; + ol_txrx_vdev_handle txrx_vdev; + struct ol_txrx_peer_t *peer; + uint8_t num_keys = 0, peer_id; + struct wma_set_key_params key_params; + uint32_t def_key_idx = 0; + + WMA_LOGD("STA key setup"); + + /* Get the txRx Pdev handle */ + txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + WMA_LOGE("%s:Invalid txrx pdev handle", __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + + peer = ol_txrx_find_peer_by_addr(txrx_pdev, key_info->peerMacAddr, + &peer_id); + if (!peer) { + WMA_LOGE("%s:Invalid peer for key setting", __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:TxRx Vdev Handle is NULL", __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + + if (key_info->defWEPIdx == WMA_INVALID_KEY_IDX && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104) && + txrx_vdev->opmode != wlan_op_mode_ap) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &num_keys); + key_info->defWEPIdx = def_key_idx; + } else { + num_keys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + if (key_info->encType != eSIR_ED_NONE) { + for (i = 0; i < num_keys; i++) { + if (key_info->key[i].keyDirection == + eSIR_TX_DEFAULT) { + key_info->defWEPIdx = i; + break; + } + } + } + } + cdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = true; + key_params.def_key_idx = key_info->defWEPIdx; + cdf_mem_copy((void *)key_params.peer_mac, + (const void *)key_info->peerMacAddr, IEEE80211_ADDR_LEN); + for (i = 0; i < num_keys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_TKIP) { + cdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + cdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + cdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + cdf_mem_copy(key_params.key_data, key_info->key[i].key, + key_info->key[i].keyLength); + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = i; + + key_params.key_len = key_info->key[i].keyLength; + buf = wma_setup_install_key_cmd(wma_handle, &key_params, &len, + txrx_vdev->opmode); + if (!buf) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = CDF_STATUS_E_NOMEM; + goto out; + } + + WMA_LOGD("%s: peer unicast key[%d] %d ", __func__, i, + key_info->key[i].keyLength); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_INSTALL_KEY_CMDID); + if (status) { + cdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = CDF_STATUS_E_FAILURE; + goto out; + } + } + + /* In IBSS mode, set the BSS KEY for this peer + * BSS key is supposed to be cache into wma_handle + */ + if (wlan_op_mode_ibss == txrx_vdev->opmode) { + wma_set_ibsskey_helper(wma_handle, &wma_handle->ibsskey_info, + key_info->peerMacAddr); + } + + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = CDF_STATUS_SUCCESS; +out: + if (key_info->sendRsp) + wma_send_msg(wma_handle, WMA_SET_STAKEY_RSP, (void *)key_info, + 0); +} + +/** + * wma_process_update_edca_param_req() - update EDCA params + * @handle: wma handle + * @edca_params: edca parameters + * + * This function updates EDCA parameters to the target + * + * Return: CDF Status + */ +CDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t *buf_ptr; + wmi_buf_t buf; + wmi_vdev_set_wmm_params_cmd_fixed_param *cmd; + wmi_wmm_vparams *wmm_param; + tSirMacEdcaParamRecord *edca_record; + int ac; + int len = sizeof(*cmd); + ol_txrx_pdev_handle pdev; + struct ol_tx_wmm_param_t ol_tx_wmm_param; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_set_wmm_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_wmm_params_cmd_fixed_param)); + cmd->vdev_id = edca_params->bssIdx; + + for (ac = 0; ac < WME_NUM_AC; ac++) { + wmm_param = (wmi_wmm_vparams *) (&cmd->wmm_params[ac]); + WMITLV_SET_HDR(&wmm_param->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_wmm_vparams)); + switch (ac) { + case WME_AC_BE: + edca_record = &edca_params->acbe; + break; + case WME_AC_BK: + edca_record = &edca_params->acbk; + break; + case WME_AC_VI: + edca_record = &edca_params->acvi; + break; + case WME_AC_VO: + edca_record = &edca_params->acvo; + break; + default: + goto fail; + } + + wma_update_edca_params_for_ac(edca_record, wmm_param, ac); + + ol_tx_wmm_param.ac[ac].aifs = wmm_param->aifs; + ol_tx_wmm_param.ac[ac].cwmin = wmm_param->cwmin; + ol_tx_wmm_param.ac[ac].cwmax = wmm_param->cwmax; + } + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_SET_WMM_PARAMS_CMDID)) + goto fail; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + ol_txrx_set_wmm_param(pdev, ol_tx_wmm_param); + + return CDF_STATUS_SUCCESS; + +fail: + wmi_buf_free(buf); + WMA_LOGE("%s: Failed to set WMM Paremeters", __func__); + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_probe_rsp_tmpl_send() - send probe response template to fw + * @wma: wma handle + * @vdev_id: vdev id + * @probe_rsp_info: probe response info + * + * Return: 0 for success or error code + */ +static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + tpSendProbeRespParams probe_rsp_info) +{ + wmi_prb_tmpl_cmd_fixed_param *cmd; + wmi_bcn_prb_info *bcn_prb_info; + wmi_buf_t wmi_buf; + uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len; + uint8_t *frm, *buf_ptr; + int ret; + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + + WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id); + + frm = probe_rsp_info->pProbeRespTemplate; + tmpl_len = probe_rsp_info->probeRespTemplateLen; + tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32)); + /* + * Make the TSF offset negative so probe response in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the probe response buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)frm; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + wmi_buf_len = sizeof(wmi_prb_tmpl_cmd_fixed_param) + + sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE + + tmpl_len_aligned; + + if (wmi_buf_len > BEACON_TX_BUFFER_SIZE) { + WMA_LOGE(FL("wmi_buf_len: %d > %d. Can't send wmi cmd"), + wmi_buf_len, BEACON_TX_BUFFER_SIZE); + return -EINVAL; + } + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_prb_tmpl_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_prb_tmpl_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->buf_len = tmpl_len; + buf_ptr += sizeof(wmi_prb_tmpl_cmd_fixed_param); + + bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr; + WMITLV_SET_HDR(&bcn_prb_info->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info)); + bcn_prb_info->caps = 0; + bcn_prb_info->erp = 0; + buf_ptr += sizeof(wmi_bcn_prb_info); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, frm, tmpl_len); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + wmi_buf, wmi_buf_len, WMI_PRB_TMPL_CMDID); + if (ret) { + WMA_LOGE(FL("Failed to send PRB RSP tmpl: %d"), ret); + wmi_buf_free(wmi_buf); + } + + return ret; +} + +/** + * wmi_unified_bcn_tmpl_send() - send beacon template to fw + * @wma:wma handle + * @vdev_id: vdev id + * @bcn_info: beacon info + * @bytes_to_strip: bytes to strip + * + * Return: 0 for success or error code + */ +static int wmi_unified_bcn_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + tpSendbeaconParams bcn_info, + uint8_t bytes_to_strip) +{ + wmi_bcn_tmpl_cmd_fixed_param *cmd; + wmi_bcn_prb_info *bcn_prb_info; + wmi_buf_t wmi_buf; + uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len; + uint8_t *frm, *buf_ptr; + int ret; + uint8_t *p2p_ie; + uint16_t p2p_ie_len = 0; + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + + WMA_LOGD("Send beacon template for vdev %d", vdev_id); + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + p2p_ie_len = (uint16_t) p2p_ie[1] + 2; + } + + /* + * XXX: The first byte of beacon buffer contains beacon length + * only when UMAC in sending the beacon template. In othercases + * (ex: from tbtt update) beacon length is read from beacon + * information. + */ + if (bytes_to_strip) + tmpl_len = *(uint32_t *) &bcn_info->beacon[0]; + else + tmpl_len = bcn_info->beaconLength; + if (p2p_ie_len) { + tmpl_len -= (uint32_t) p2p_ie_len; + } + + frm = bcn_info->beacon + bytes_to_strip; + tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32)); + /* + * Make the TSF offset negative so beacons in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the beacon buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)frm; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) + + sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE + + tmpl_len_aligned; + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_bcn_tmpl_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip; + cmd->buf_len = tmpl_len; + buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param); + + bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr; + WMITLV_SET_HDR(&bcn_prb_info->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info)); + bcn_prb_info->caps = 0; + bcn_prb_info->erp = 0; + buf_ptr += sizeof(wmi_bcn_prb_info); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, frm, tmpl_len); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + wmi_buf, wmi_buf_len, WMI_BCN_TMPL_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret); + wmi_buf_free(wmi_buf); + } + + return ret; +} + +/** + * wma_store_bcn_tmpl() - store beacon template + * @wma: wma handle + * @vdev_id: vdev id + * @bcn_info: beacon params + * + * This function stores beacon template locally. + * This will send to target on the reception of + * SWBA event. + * + * Return: CDF status + */ +CDF_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, uint8_t vdev_id, + tpSendbeaconParams bcn_info) +{ + struct beacon_info *bcn; + uint32_t len; + uint8_t *bcn_payload; + struct beacon_tim_ie *tim_ie; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn || !bcn->buf) { + WMA_LOGE("%s: Memory is not allocated to hold bcn template", + __func__); + return CDF_STATUS_E_INVAL; + } + + len = *(u32 *) &bcn_info->beacon[0]; + if (len > WMA_BCN_BUF_MAX_SIZE) { + WMA_LOGE("%s: Received beacon len %d exceeding max limit %d", + __func__, len, WMA_BCN_BUF_MAX_SIZE); + return CDF_STATUS_E_INVAL; + } + WMA_LOGD("%s: Storing received beacon template buf to local buffer", + __func__); + cdf_spin_lock_bh(&bcn->lock); + + /* + * Copy received beacon template content in local buffer. + * this will be send to target on the reception of SWBA + * event from target. + */ + cdf_nbuf_trim_tail(bcn->buf, cdf_nbuf_len(bcn->buf)); + memcpy(cdf_nbuf_data(bcn->buf), + bcn_info->beacon + 4 /* Exclude beacon length field */, + len); + if (bcn_info->timIeOffset > 3) { + bcn->tim_ie_offset = bcn_info->timIeOffset - 4; + } else { + bcn->tim_ie_offset = bcn_info->timIeOffset; + } + + if (bcn_info->p2pIeOffset > 3) { + bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4; + } else { + bcn->p2p_ie_offset = bcn_info->p2pIeOffset; + } + bcn_payload = cdf_nbuf_data(bcn->buf); + if (bcn->tim_ie_offset) { + tim_ie = + (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]); + /* + * Intial Value of bcn->dtim_count will be 0. + * But if the beacon gets updated then current dtim + * count will be restored + */ + tim_ie->dtim_count = bcn->dtim_count; + tim_ie->tim_bitctl = 0; + } + + cdf_nbuf_put_tail(bcn->buf, len); + bcn->len = len; + + cdf_spin_unlock_bh(&bcn->lock); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_tbttoffset_update_event_handler() - tbtt offset update handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf; + wmi_tbtt_offset_event_fixed_param *tbtt_offset_event; + struct wma_txrx_node *intf; + struct beacon_info *bcn; + tSendbeaconParams bcn_info; + uint32_t *adjusted_tsf = NULL; + uint32_t if_id = 0, vdev_map; + + if (!wma) { + WMA_LOGE("Invalid wma handle"); + return -EINVAL; + } + + param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid tbtt update event buffer"); + return -EINVAL; + } + + tbtt_offset_event = param_buf->fixed_param; + intf = wma->interfaces; + vdev_map = tbtt_offset_event->vdev_map; + adjusted_tsf = param_buf->tbttoffset_list; + if (!adjusted_tsf) { + WMA_LOGE("%s: Invalid adjusted_tsf", __func__); + return -EINVAL; + } + + for (; (vdev_map); vdev_map >>= 1, if_id++) { + if (!(vdev_map & 0x1) || (!(intf[if_id].handle))) + continue; + + bcn = intf[if_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Invalid beacon", __func__); + return -EINVAL; + } + if (!bcn->buf) { + WMA_LOGE("%s: Invalid beacon buffer", __func__); + return -EINVAL; + } + /* Save the adjusted TSF */ + intf[if_id].tsfadjust = adjusted_tsf[if_id]; + + cdf_spin_lock_bh(&bcn->lock); + cdf_mem_zero(&bcn_info, sizeof(bcn_info)); + bcn_info.beacon = cdf_nbuf_data(bcn->buf); + bcn_info.p2pIeOffset = bcn->p2p_ie_offset; + bcn_info.beaconLength = bcn->len; + bcn_info.timIeOffset = bcn->tim_ie_offset; + cdf_spin_unlock_bh(&bcn->lock); + + /* Update beacon template in firmware */ + wmi_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0); + } + return 0; +} + +/** + * wma_p2p_go_set_beacon_ie() - set beacon IE for p2p go + * @wma_handle: wma handle + * @vdev_id: vdev id + * @p2pIe: p2p IE + * + * Return: 0 for success or error code + */ +static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle, + A_UINT32 vdev_id, uint8_t *p2pIe) +{ + int ret; + wmi_p2p_go_set_beacon_ie_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t ie_len, ie_len_aligned, wmi_buf_len; + uint8_t *buf_ptr; + + ie_len = (uint32_t) (p2pIe[1] + 2); + + /* More than one P2P IE may be included in a single frame. + If multiple P2P IEs are present, the complete P2P attribute + data consists of the concatenation of the P2P Attribute + fields of the P2P IEs. The P2P Attributes field of each + P2P IE may be any length up to the maximum (251 octets). + In this case host sends one P2P IE to firmware so the length + should not exceed more than 251 bytes + */ + if (ie_len > 251) { + WMA_LOGE("%s : invalid p2p ie length %u", __func__, ie_len); + return -EINVAL; + } + + ie_len_aligned = roundup(ie_len, sizeof(A_UINT32)); + + wmi_buf_len = + sizeof(wmi_p2p_go_set_beacon_ie_fixed_param) + ie_len_aligned + + WMI_TLV_HDR_SIZE; + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_p2p_go_set_beacon_ie_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_go_set_beacon_ie_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->ie_buf_len = ie_len; + + buf_ptr += sizeof(wmi_p2p_go_set_beacon_ie_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, p2pIe, ie_len); + + WMA_LOGI("%s: Sending WMI_P2P_GO_SET_BEACON_IE", __func__); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, + wmi_buf, wmi_buf_len, + WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + WMA_LOGE("Failed to send bcn tmpl: %d", ret); + wmi_buf_free(wmi_buf); + } + + WMA_LOGI("%s: Successfully sent WMI_P2P_GO_SET_BEACON_IE", __func__); + return ret; +} + +/** + * wma_send_probe_rsp_tmpl() - send probe resp template + * @wma: wma handle + * @probe_rsp_info: probe response info + * + * This funciton sends probe response template to fw which + * firmware will use in case of probe response offload. + * + * Return: none + */ +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info) +{ + ol_txrx_vdev_handle vdev; + uint8_t vdev_id; + tpAniProbeRspStruct probe_rsp; + + if (!probe_rsp_info) { + WMA_LOGE(FL("probe_rsp_info is NULL")); + return; + } + + probe_rsp = (tpAniProbeRspStruct) (probe_rsp_info->pProbeRespTemplate); + if (!probe_rsp) { + WMA_LOGE(FL("probe_rsp is NULL")); + return; + } + + vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE(FL("failed to get vdev handle")); + return; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + WMA_LOGI("Beacon Offload Enabled Sending Unified command"); + if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id, + probe_rsp_info) < 0) { + WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed ")); + return; + } + } +} + +/** + * wma_send_beacon() - send beacon template + * @wma: wma handle + * @bcn_info: beacon info + * + * This funciton store beacon template locally and + * update keep alive parameters + * + * Return: none + */ +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info) +{ + ol_txrx_vdev_handle vdev; + uint8_t vdev_id; + CDF_STATUS status; + uint8_t *p2p_ie; + tpAniBeaconStruct beacon; + + beacon = (tpAniBeaconStruct) (bcn_info->beacon); + vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE("%s : failed to get vdev handle", __func__); + return; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + WMA_LOGI("Beacon Offload Enabled Sending Unified command"); + if (wmi_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4) < 0) { + WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + return; + } + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + WMA_LOGI + (" %s: p2pIe is present - vdev_id %hu, p2p_ie = %p, p2p ie len = %hu", + __func__, vdev_id, p2p_ie, p2p_ie[1]); + if (wma_p2p_go_set_beacon_ie(wma, vdev_id, p2p_ie) < 0) { + WMA_LOGE + ("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + return; + } + } + } + status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__); + return; + } + if (!wma->interfaces[vdev_id].vdev_up) { + if (wmi_unified_vdev_up_send(wma->wmi_handle, vdev_id, 0, + bcn_info->bssId) < 0) { + WMA_LOGE("%s : failed to send vdev up", __func__); + return; + } + wma->interfaces[vdev_id].vdev_up = true; + wma_set_sap_keepalive(wma, vdev_id); + } +} + +/** + * wma_set_keepalive_req() - send keep alive request to fw + * @wma: wma handle + * @keepalive: keep alive parameters + * + * Return: none + */ +void wma_set_keepalive_req(tp_wma_handle wma, + tSirKeepAliveReq *keepalive) +{ + WMA_LOGD("KEEPALIVE:PacketType:%d", keepalive->packetType); + wma_set_sta_keep_alive(wma, keepalive->sessionId, + keepalive->packetType, + keepalive->timePeriod, + keepalive->hostIpv4Addr, + keepalive->destIpv4Addr, keepalive->destMacAddr); + + cdf_mem_free(keepalive); +} + +/** + * wma_beacon_miss_handler() - beacon miss event handler + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send beacon miss indication to upper layers. + * + * Return: none + */ +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + tSirSmeMissedBeaconInd *beacon_miss_ind; + + beacon_miss_ind = (tSirSmeMissedBeaconInd *) cdf_mem_malloc + (sizeof(tSirSmeMissedBeaconInd)); + + if (NULL == beacon_miss_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND; + beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd); + beacon_miss_ind->bssIdx = vdev_id; + + wma_send_msg(wma, WMA_MISSED_BEACON_IND, (void *)beacon_miss_ind, 0); +} + +/** + * wma_mgmt_tx_completion_handler() - wma mgmt Tx completion event handler + * @handle: wma handle + * @cmpl_event_params: completion event handler data + * @len: length of @cmpl_event_params + * + * Return: 0 on success; error number otherwise + */ + +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_event_fixed_param *cmpl_params; + struct wmi_desc_t *wmi_desc; + + ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX); + + param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *) + cmpl_event_params; + if (!param_buf && !wma_handle) { + WMA_LOGE("%s: Invalid mgmt Tx completion event", __func__); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + + WMA_LOGI("%s: status:%d wmi_desc_id:%d", __func__, cmpl_params->status, + cmpl_params->desc_id); + + wmi_desc = (struct wmi_desc_t *) + (&wma_handle->wmi_desc_pool.array[cmpl_params->desc_id]); + + if (!wmi_desc) { + WMA_LOGE("%s: Invalid wmi desc", __func__); + return -EINVAL; + } + + if (wmi_desc->nbuf) + cdf_nbuf_unmap_single(pdev->osdev, wmi_desc->nbuf, + CDF_DMA_TO_DEVICE); + if (wmi_desc->tx_cmpl_cb) + wmi_desc->tx_cmpl_cb(wma_handle->mac_context, + wmi_desc->nbuf, 1); + + if (wmi_desc->ota_post_proc_cb) + wmi_desc->ota_post_proc_cb((tpAniSirGlobal) + wma_handle->mac_context, + cmpl_params->status); + + wmi_desc_put(wma_handle, wmi_desc); + + return 0; +} + +/** + * wma_process_update_opmode() - process update VHT opmode cmd from UMAC + * @wma_handle: wma handle + * @update_vht_opmode: vht opmode + * + * Return: none + */ +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode) +{ + WMA_LOGD("%s: opMode = %d", __func__, update_vht_opmode->opMode); + + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_PEER_CHWIDTH, update_vht_opmode->opMode, + update_vht_opmode->smesessionId); +} + +/** + * wma_process_update_rx_nss() - process update RX NSS cmd from UMAC + * @wma_handle: wma handle + * @update_rx_nss: rx nss value + * + * Return: none + */ +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss) +{ + struct wma_txrx_node *intr = + &wma_handle->interfaces[update_rx_nss->smesessionId]; + int rx_nss = update_rx_nss->rxNss; + + wma_update_txrx_chainmask(wma_handle->num_rf_chains, &rx_nss); + + intr->nss = (uint8_t)rx_nss; + update_rx_nss->rxNss = (uint32_t)rx_nss; + + WMA_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss); + + wma_set_peer_param(wma_handle, update_rx_nss->peer_mac, + WMI_PEER_NSS, update_rx_nss->rxNss, + update_rx_nss->smesessionId); +} + +#ifdef WLAN_FEATURE_11AC +/** + * wma_process_update_membership() - process update group membership cmd + * @wma_handle: wma handle + * @membership: group membership info + * + * Return: none + */ +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership) +{ + WMA_LOGD("%s: membership = %x ", __func__, membership->membership); + + wma_set_peer_param(wma_handle, membership->peer_mac, + WMI_PEER_MEMBERSHIP, membership->membership, + membership->smesessionId); +} + +/** + * wma_process_update_userpos() - process update user pos cmd from UMAC + * @wma_handle: wma handle + * @userpos: user pos value + * + * Return: none + */ +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos) +{ + WMA_LOGD("%s: userPos = %x ", __func__, userpos->userPos); + + wma_set_peer_param(wma_handle, userpos->peer_mac, + WMI_PEER_USERPOS, userpos->userPos, + userpos->smesessionId); + + /* Now that membership/userpos is updated in fw, + * enable GID PPS. + */ + wma_set_ppsconfig(userpos->smesessionId, WMA_VHT_PPS_GID_MATCH, 1); + +} +#endif /* WLAN_FEATURE_11AC */ + +/** + * wma_set_htconfig() - set ht config parameters to target + * @vdev_id: vdev id + * @ht_capab: ht capablity + * @value: value of ht param + * + * Return: CDF status + */ +CDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + int ret = -EIO; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return CDF_STATUS_E_INVAL; + } + + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LDPC, + value); + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_STBC, + value); + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_RX_STBC, + value); + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + WMA_LOGE("%s: ht_capab = %d, value = %d", __func__, ht_capab, + value); + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SGI, value); + if (ret == 0) + wma->interfaces[vdev_id].config.shortgi = value; + break; + default: + WMA_LOGE("%s:INVALID HT CONFIG", __func__); + } + + return (ret) ? CDF_STATUS_E_FAILURE : CDF_STATUS_SUCCESS; +} + +/** + * wma_hidden_ssid_vdev_restart() - vdev restart for hidden ssid + * @wma_handle: wma handle + * @pReq: hidden ssid vdev restart request + * + * Return: none + */ +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle, + tHalHiddenSsidVdevRestart *pReq) +{ + struct wma_txrx_node *intr = wma_handle->interfaces; + + if ((pReq->sessionId != + intr[pReq->sessionId].vdev_restart_params.vdev_id) + || !((intr[pReq->sessionId].type == WMI_VDEV_TYPE_AP) + && (intr[pReq->sessionId].sub_type == 0))) { + WMA_LOGE("%s : invalid session id", __func__); + return; + } + + intr[pReq->sessionId].vdev_restart_params.ssidHidden = pReq->ssidHidden; + cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 1); + + /* vdev stop -> vdev restart -> vdev up */ + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", + __func__, pReq->sessionId); + ol_txrx_vdev_pause(wma_handle->interfaces[pReq->sessionId].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_handle->interfaces[pReq->sessionId].pause_bitmap |= + (1 << PAUSE_TYPE_HOST); + if (wmi_unified_vdev_stop_send(wma_handle->wmi_handle, pReq->sessionId)) { + WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__); + cdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + return; + } +} + + +#ifdef WLAN_FEATURE_11W + +/** + * wma_extract_ccmp_pn() - extract 6 byte PN from the CCMP header + * @ccmp_ptr: CCMP header + * + * Return: PN extracted from header. + */ +static uint64_t wma_extract_ccmp_pn(uint8_t *ccmp_ptr) +{ + uint8_t rsvd, key, pn[6]; + uint64_t new_pn; + + /* + * +-----+-----+------+----------+-----+-----+-----+-----+ + * | PN0 | PN1 | rsvd | rsvd/key | PN2 | PN3 | PN4 | PN5 | + * +-----+-----+------+----------+-----+-----+-----+-----+ + * CCMP Header Format + */ + + /* Extract individual bytes */ + pn[0] = (uint8_t) *ccmp_ptr; + pn[1] = (uint8_t) *(ccmp_ptr + 1); + rsvd = (uint8_t) *(ccmp_ptr + 2); + key = (uint8_t) *(ccmp_ptr + 3); + pn[2] = (uint8_t) *(ccmp_ptr + 4); + pn[3] = (uint8_t) *(ccmp_ptr + 5); + pn[4] = (uint8_t) *(ccmp_ptr + 6); + pn[5] = (uint8_t) *(ccmp_ptr + 7); + + /* Form 6 byte PN with 6 individual bytes of PN */ + new_pn = ((uint64_t) pn[5] << 40) | + ((uint64_t) pn[4] << 32) | + ((uint64_t) pn[3] << 24) | + ((uint64_t) pn[2] << 16) | + ((uint64_t) pn[1] << 8) | ((uint64_t) pn[0] << 0); + + WMA_LOGE("PN of received packet is %llu", new_pn); + return new_pn; +} + +/** + * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP + * @cds_ctx: cds context + * @wh: 802.11 frame header + * @ccmp_ptr: CCMP frame header + * + * Return: true/false + */ +static bool +wma_is_ccmp_pn_replay_attack(void *cds_ctx, struct ieee80211_frame *wh, + uint8_t *ccmp_ptr) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t vdev_id, peer_id; + uint8_t *last_pn_valid; + uint64_t *last_pn, new_pn; + uint32_t *rmf_pn_replays; + + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + return true; + } + + vdev = wma_find_vdev_by_addr(cds_ctx, wh->i_addr2, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + return true; + } + + /* Retrieve the peer based on vdev and addr */ + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, wh->i_addr2, + &peer_id); + + if (NULL == peer) { + WMA_LOGE("%s: Failed to find peer, Not able to validate PN", + __func__); + return true; + } + + new_pn = wma_extract_ccmp_pn(ccmp_ptr); + last_pn_valid = &peer->last_rmf_pn_valid; + last_pn = &peer->last_rmf_pn; + rmf_pn_replays = &peer->rmf_pn_replays; + + if (*last_pn_valid) { + if (new_pn > *last_pn) { + *last_pn = new_pn; + WMA_LOGE("%s: PN validation successful", __func__); + } else { + WMA_LOGE("%s: PN Replay attack detected", __func__); + /* per 11W amendment, keeping track of replay attacks */ + *rmf_pn_replays += 1; + return true; + } + } else { + *last_pn_valid = 1; + *last_pn = new_pn; + } + + return false; +} + +/** + * wma_process_rmf_frame() - process rmf frame + * @wma_handle: wma handle + * @iface: txrx node + * @wh: 80211 frame + * @rx_pkt: rx packet + * @wbuf: Buffer + * + * Return: 0 for success or error code + */ +static +int wma_process_rmf_frame(tp_wma_handle wma_handle, + struct wma_txrx_node *iface, + struct ieee80211_frame *wh, + cds_pkt_t *rx_pkt, + cdf_nbuf_t wbuf) +{ + uint8_t *efrm, *orig_hdr; + uint16_t key_id; + uint8_t *ccmp; + + if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) { + if (IEEE80211_IS_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + WMA_LOGE("Encrypted BC/MC frame dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + orig_hdr = (uint8_t *) cdf_nbuf_data(wbuf); + /* Pointer to head of CCMP header */ + ccmp = orig_hdr + sizeof(*wh); + if (wma_is_ccmp_pn_replay_attack( + wma_handle, wh, ccmp)) { + WMA_LOGE("Dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + /* Strip privacy headers (and trailer) + * for a received frame + */ + cdf_mem_move(orig_hdr + + IEEE80211_CCMP_HEADERLEN, wh, + sizeof(*wh)); + cdf_nbuf_pull_head(wbuf, + IEEE80211_CCMP_HEADERLEN); + cdf_nbuf_trim_tail(wbuf, IEEE80211_CCMP_MICLEN); + + rx_pkt->pkt_meta.mpdu_hdr_ptr = + cdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_len = cdf_nbuf_len(wbuf); + rx_pkt->pkt_meta.mpdu_data_len = + rx_pkt->pkt_meta.mpdu_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.mpdu_data_ptr = + rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.tsf_delta = rx_pkt->pkt_meta.tsf_delta; + rx_pkt->pkt_buf = wbuf; + WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"), + MAC_ADDR_ARRAY(wh->i_addr3), rx_pkt->pkt_meta.tsf_delta); + } else { + if (IEEE80211_IS_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + efrm = cdf_nbuf_data(wbuf) + + cdf_nbuf_len(wbuf); + + key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2); + if (!((key_id == WMA_IGTK_KEY_INDEX_4) + || (key_id == WMA_IGTK_KEY_INDEX_5))) { + WMA_LOGE("Invalid KeyID(%d) dropping the frame", key_id); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + if (cds_is_mmie_valid(iface->key.key, + iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn, + (uint8_t *) wh, efrm)) { + WMA_LOGE("Protected BC/MC frame MMIE validation successful"); + /* Remove MMIE */ + cdf_nbuf_trim_tail(wbuf, + cds_get_mmie_size()); + } else { + WMA_LOGE("BC/MC MIC error or MMIE not present, dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + } else { + WMA_LOGE("Rx unprotected unicast mgmt frame"); + rx_pkt->pkt_meta.dpuFeedback = + DPU_FEEDBACK_UNPROTECTED_ERROR; + } + } + return 0; +} +#endif + +/** + * wma_mgmt_rx_process() - process management rx frame. + * @handle: wma handle + * @data: rx data + * @data_len: data length + * + * Return: 0 for success or error code + */ +static int wma_mgmt_rx_process(void *handle, uint8_t *data, + uint32_t data_len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL; + wmi_mgmt_rx_hdr *hdr = NULL; + struct wma_txrx_node *iface = NULL; + uint8_t vdev_id; + cds_pkt_t *rx_pkt; + cdf_nbuf_t wbuf; + struct ieee80211_frame *wh; + uint8_t mgt_type, mgt_subtype; + int status; + + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) data; + if (!param_tlvs) { + WMA_LOGE("Get NULL point message from FW"); + return -EINVAL; + } + + hdr = param_tlvs->hdr; + if (!hdr) { + WMA_LOGE("Rx event is NULL"); + return -EINVAL; + } + + if (hdr->buf_len < sizeof(struct ieee80211_frame)) { + WMA_LOGE("Invalid rx mgmt packet"); + return -EINVAL; + } + + rx_pkt = cdf_mem_malloc(sizeof(*rx_pkt)); + if (!rx_pkt) { + WMA_LOGE("Failed to allocate rx packet"); + return -ENOMEM; + } + + cdf_mem_zero(rx_pkt, sizeof(*rx_pkt)); + + /* + * Fill in meta information needed by pe/lim + * TODO: Try to maintain rx metainfo as part of skb->data. + */ + rx_pkt->pkt_meta.channel = hdr->channel; + rx_pkt->pkt_meta.scan_src = hdr->flags; + /*Get the absolute rssi value from the current rssi value + *the sinr value is hardcoded into 0 in the core stack*/ + rx_pkt->pkt_meta.rssi = hdr->snr + WMA_TGT_NOISE_FLOOR_DBM; + rx_pkt->pkt_meta.snr = hdr->snr; + /* + * FIXME: Assigning the local timestamp as hw timestamp is not + * available. Need to see if pe/lim really uses this data. + */ + rx_pkt->pkt_meta.timestamp = (uint32_t) jiffies; + rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame); + rx_pkt->pkt_meta.mpdu_len = hdr->buf_len; + rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + + rx_pkt->pkt_meta.roamCandidateInd = 0; + + /* Why not just use rx_event->hdr.buf_len? */ + wbuf = cdf_nbuf_alloc(NULL, roundup(hdr->buf_len, 4), 0, 4, false); + if (!wbuf) { + WMA_LOGE("%s: Failed to allocate wbuf for mgmt rx len(%u)", + __func__, hdr->buf_len); + cdf_mem_free(rx_pkt); + return -ENOMEM; + } + + cdf_nbuf_put_tail(wbuf, hdr->buf_len); + cdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL); + wh = (struct ieee80211_frame *)cdf_nbuf_data(wbuf); + + rx_pkt->pkt_meta.mpdu_hdr_ptr = cdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.tsf_delta = hdr->tsf_delta; + rx_pkt->pkt_buf = wbuf; + + WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"), + MAC_ADDR_ARRAY(wh->i_addr3), hdr->tsf_delta); + +#ifdef BIG_ENDIAN_HOST + { + /* + * for big endian host, copy engine byte_swap is enabled + * But the rx mgmt frame buffer content is in network byte order + * Need to byte swap the mgmt frame buffer content - so when + * copy engine does byte_swap - host gets buffer content in the + * correct byte order. + */ + int i; + uint32_t *destp, *srcp; + destp = (uint32_t *) wh; + srcp = (uint32_t *) param_tlvs->bufp; + for (i = 0; + i < (roundup(hdr->buf_len, sizeof(uint32_t)) / 4); i++) { + *destp = cpu_to_le32(*srcp); + destp++; + srcp++; + } + } +#else + cdf_mem_copy(wh, param_tlvs->bufp, hdr->buf_len); +#endif + + if (!wma_handle->mgmt_rx) { + WMA_LOGE("Not registered for Mgmt rx, dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + /* If it is a beacon/probe response, save it for future use */ + mgt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + mgt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + iface = wma_find_vdev_by_addr(wma_handle, wh->i_addr3, &vdev_id); + rx_pkt->pkt_meta.sessionId = vdev_id; + +#ifdef WLAN_FEATURE_11W + if (mgt_type == IEEE80211_FC0_TYPE_MGT && + (mgt_subtype == IEEE80211_FC0_SUBTYPE_DISASSOC || + mgt_subtype == IEEE80211_FC0_SUBTYPE_DEAUTH || + mgt_subtype == IEEE80211_FC0_SUBTYPE_ACTION)) { + if (iface && iface->rmfEnabled) { + status = wma_process_rmf_frame(wma_handle, + iface, wh, rx_pkt, wbuf); + if (status != 0) + return status; + } + } +#endif /* WLAN_FEATURE_11W */ + wma_handle->mgmt_rx(wma_handle, rx_pkt); + return 0; +} + +/** + * wma_de_register_mgmt_frm_client() - deregister management frame + * @cds_ctx: cds context + * + * Return: CDF status + */ +CDF_STATUS wma_de_register_mgmt_frm_client(void *cds_ctx) +{ + tp_wma_handle wma_handle; + +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == CDF_FTM_MODE) + return CDF_STATUS_SUCCESS; +#endif + + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_MGMT_RX_EVENTID) != 0) { + WMA_LOGE("Failed to Unregister rx mgmt handler with wmi"); + return CDF_STATUS_E_FAILURE; + } + wma_handle->mgmt_rx = NULL; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_register_mgmt_frm_client() - register management frame callback + * @cds_ctx: cds context + * @mgmt_frm_rx: management frame + * + * Return: CDF status + */ +CDF_STATUS wma_register_mgmt_frm_client( + void *cds_ctx, wma_mgmt_frame_rx_callback mgmt_frm_rx) +{ + tp_wma_handle wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_MGMT_RX_EVENTID, + wma_mgmt_rx_process) != 0) { + WMA_LOGE("Failed to register rx mgmt handler with wmi"); + return CDF_STATUS_E_FAILURE; + } + wma_handle->mgmt_rx = mgmt_frm_rx; + + return CDF_STATUS_SUCCESS; +} diff --git a/core/wma/src/wma_ocb.c b/core/wma/src/wma_ocb.c new file mode 100644 index 0000000000..15d321202a --- /dev/null +++ b/core/wma/src/wma_ocb.c @@ -0,0 +1,1119 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "wma_ocb.h" +#include "wmi_unified_api.h" +#include "cds_utils.h" + +/** + * wma_ocb_resp() - send the OCB set config response via callback + * @wma_handle: pointer to the WMA handle + * @status: status of the set config command + */ +int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status) +{ + CDF_STATUS cdf_status; + struct sir_ocb_set_config_response *resp; + cds_msg_t msg = {0}; + struct sir_ocb_config *req = wma_handle->ocb_config_req; + ol_txrx_vdev_handle vdev = (req ? + wma_handle->interfaces[req->session_id].handle : NULL); + + /* + * If the command was successful, save the channel information in the + * vdev. + */ + if (status == CDF_STATUS_SUCCESS && vdev && req) { + if (vdev->ocb_channel_info) + cdf_mem_free(vdev->ocb_channel_info); + vdev->ocb_channel_count = + req->channel_count; + if (req->channel_count) { + int i; + int buf_size = sizeof(*vdev->ocb_channel_info) * + req->channel_count; + vdev->ocb_channel_info = + cdf_mem_malloc(buf_size); + cdf_mem_zero(vdev->ocb_channel_info, buf_size); + for (i = 0; i < req->channel_count; i++) { + vdev->ocb_channel_info[i].chan_freq = + req->channels[i].chan_freq; + if (req->channels[i].flags & + OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR) + vdev->ocb_channel_info[i]. + disable_rx_stats_hdr = 1; + } + } else { + vdev->ocb_channel_info = 0; + } + } + + /* Free the configuration that was saved in wma_ocb_set_config. */ + cdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = NULL; + + resp = cdf_mem_malloc(sizeof(*resp)); + if (!resp) + return -ENOMEM; + + resp->status = status; + + msg.type = eWNI_SME_OCB_SET_CONFIG_RSP; + msg.bodyptr = resp; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Fail to post msg to SME")); + cdf_mem_free(resp); + return -EINVAL; + } + + return 0; +} + +/** + * copy_sir_ocb_config() - deep copy of an OCB config struct + * @src: pointer to the source struct + * + * Return: pointer to the copied struct + */ +static struct sir_ocb_config *copy_sir_ocb_config(struct sir_ocb_config *src) +{ + struct sir_ocb_config *dst; + uint32_t length; + void *cursor; + + length = sizeof(*src) + + src->channel_count * sizeof(*src->channels) + + src->schedule_size * sizeof(*src->schedule) + + src->dcc_ndl_chan_list_len + + src->dcc_ndl_active_state_list_len; + + dst = cdf_mem_malloc(length); + if (!dst) + return NULL; + + *dst = *src; + + cursor = dst; + cursor += sizeof(*dst); + dst->channels = cursor; + cursor += src->channel_count * sizeof(*dst->channels); + cdf_mem_copy(dst->channels, src->channels, + src->channel_count * sizeof(*dst->channels)); + dst->schedule = cursor; + cursor += src->schedule_size * sizeof(*dst->schedule); + cdf_mem_copy(dst->schedule, src->schedule, + src->schedule_size * sizeof(*dst->schedule)); + dst->dcc_ndl_chan_list = cursor; + cursor += src->dcc_ndl_chan_list_len; + cdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, + src->dcc_ndl_chan_list_len); + dst->dcc_ndl_active_state_list = cursor; + cursor += src->dcc_ndl_active_state_list_len; + cdf_mem_copy(dst->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list_len); + return dst; +} + +/** + * wma_ocb_set_config_req() - send the OCB config request + * @wma_handle: pointer to the WMA handle + * @config_req: the configuration to be set. + */ +int wma_ocb_set_config_req(tp_wma_handle wma_handle, + struct sir_ocb_config *config_req) +{ + struct wma_target_req *msg; + struct wma_vdev_start_req req; + CDF_STATUS status = CDF_STATUS_SUCCESS; + + /* if vdev is not yet up, send vdev start request and wait for response. + * OCB set_config request should be sent on receiving + * vdev start response message + */ + if (!wma_handle->interfaces[config_req->session_id].vdev_up) { + cdf_mem_zero(&req, sizeof(req)); + /* Enqueue OCB Set Schedule request message */ + msg = wma_fill_vdev_req(wma_handle, config_req->session_id, + WMA_OCB_SET_CONFIG_CMD, + WMA_TARGET_REQ_TYPE_VDEV_START, + (void *)config_req, 1000); + if (!msg) { + WMA_LOGE(FL("Failed to fill vdev req %d"), req.vdev_id); + status = CDF_STATUS_E_NOMEM; + return status; + } + req.chan = cds_freq_to_chan(config_req->channels[0].chan_freq); + req.vdev_id = msg->vdev_id; + if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ) + req.dot11_mode = WNI_CFG_DOT11_MODE_11G; + else + req.dot11_mode = WNI_CFG_DOT11_MODE_11A; + + if (wma_handle->ocb_config_req) + cdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = copy_sir_ocb_config(config_req); + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + + status = wma_vdev_start(wma_handle, &req, false); + if (status != CDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma_handle, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGE(FL("vdev_start failed, status = %d"), status); + } + return 0; + } else { + return wma_ocb_set_config(wma_handle, config_req); + } +} + +int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle) +{ + CDF_STATUS cdf_status = 0; + + if (!wma_handle->ocb_config_req) { + WMA_LOGE(FL("The request could not be found")); + return CDF_STATUS_E_EMPTY; + } + + cdf_status = wma_ocb_set_config(wma_handle, wma_handle->ocb_config_req); + return cdf_status; +} + +static WLAN_PHY_MODE wma_ocb_freq_to_mode(uint32_t freq) +{ + if (cds_chan_to_band(cds_freq_to_chan(freq)) == CDS_BAND_2GHZ) + return MODE_11G; + else + return MODE_11A; +} + +/** + * wma_send_ocb_set_config() - send the OCB config to the FW + * @wma_handle: pointer to the WMA handle + * @config: the OCB configuration + * + * Return: 0 on success + */ +int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config) +{ + int32_t ret; + wmi_ocb_set_config_cmd_fixed_param *cmd; + wmi_channel *chan; + wmi_ocb_channel *ocb_chan; + wmi_qos_parameter *qos_param; + wmi_dcc_ndl_chan *ndl_chan; + wmi_dcc_ndl_active_state_config *ndl_active_config; + wmi_ocb_schedule_element *sched_elem; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + int32_t i, j, active_state_count; + + /* + * Validate the dcc_ndl_chan_list_len and count the number of active + * states. Validate dcc_ndl_active_state_list_len. + */ + active_state_count = 0; + if (config->dcc_ndl_chan_list_len) { + if (!config->dcc_ndl_chan_list || + config->dcc_ndl_chan_list_len != + config->channel_count * sizeof(wmi_dcc_ndl_chan)) { + WMA_LOGE(FL("NDL channel is invalid. List len: %d"), + config->dcc_ndl_chan_list_len); + return -EINVAL; + } + + for (i = 0, ndl_chan = config->dcc_ndl_chan_list; + i < config->channel_count; ++i, ++ndl_chan) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(ndl_chan); + + if (active_state_count) { + if (!config->dcc_ndl_active_state_list || + config->dcc_ndl_active_state_list_len != + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)) { + WMA_LOGE(FL("NDL active state is invalid.")); + return -EINVAL; + } + } + } + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_ocb_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_qos_parameter) * WLAN_MAX_AC + + WMI_TLV_HDR_SIZE + config->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config) + + WMI_TLV_HDR_SIZE + config->schedule_size * + sizeof(wmi_ocb_schedule_element); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_config_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_config_cmd_fixed_param)); + cmd->vdev_id = config->session_id; + cmd->channel_count = config->channel_count; + cmd->schedule_size = config->schedule_size; + cmd->flags = config->flags; + buf_ptr += sizeof(*cmd); + + /* Add the wmi_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + chan = (wmi_channel *)buf_ptr; + WMITLV_SET_HDR(&chan->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan->mhz = config->channels[i].chan_freq; + chan->band_center_freq1 = config->channels[i].chan_freq; + chan->band_center_freq2 = 0; + chan->info = 0; + + WMI_SET_CHANNEL_MODE(chan, wma_ocb_freq_to_mode(chan->mhz)); + WMI_SET_CHANNEL_MAX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_MIN_POWER(chan, config->channels[i].min_pwr); + WMI_SET_CHANNEL_MAX_TX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_REG_POWER(chan, config->channels[i].reg_pwr); + WMI_SET_CHANNEL_ANTENNA_MAX(chan, + config->channels[i].antenna_max); + + if (config->channels[i].bandwidth < 10) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE); + else if (config->channels[i].bandwidth < 20) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE); + buf_ptr += sizeof(*chan); + } + + /* Add the wmi_ocb_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_ocb_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + ocb_chan = (wmi_ocb_channel *)buf_ptr; + WMITLV_SET_HDR(&ocb_chan->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_channel)); + ocb_chan->bandwidth = config->channels[i].bandwidth; + WMI_CHAR_ARRAY_TO_MAC_ADDR(config->channels[i].mac_address, + &ocb_chan->mac_address); + buf_ptr += sizeof(*ocb_chan); + } + + /* Add the wmi_qos_parameter info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count * sizeof(wmi_qos_parameter)*WLAN_MAX_AC); + buf_ptr += WMI_TLV_HDR_SIZE; + /* WLAN_MAX_AC parameters for each channel */ + for (i = 0; i < config->channel_count; i++) { + for (j = 0; j < WLAN_MAX_AC; j++) { + qos_param = (wmi_qos_parameter *)buf_ptr; + WMITLV_SET_HDR(&qos_param->tlv_header, + WMITLV_TAG_STRUC_wmi_qos_parameter, + WMITLV_GET_STRUCT_TLVLEN(wmi_qos_parameter)); + qos_param->aifsn = + config->channels[i].qos_params[j].aifsn; + qos_param->cwmin = + config->channels[i].qos_params[j].cwmin; + qos_param->cwmax = + config->channels[i].qos_params[j].cwmax; + buf_ptr += sizeof(*qos_param); + } + } + + /* Add the wmi_dcc_ndl_chan (per channel) */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + if (config->dcc_ndl_chan_list_len) { + ndl_chan = (wmi_dcc_ndl_chan *)buf_ptr; + cdf_mem_copy(ndl_chan, config->dcc_ndl_chan_list, + config->dcc_ndl_chan_list_len); + for (i = 0; i < config->channel_count; i++) + WMITLV_SET_HDR(&(ndl_chan[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN(wmi_dcc_ndl_chan)); + buf_ptr += config->dcc_ndl_chan_list_len; + } + + /* Add the wmi_dcc_ndl_active_state_config */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)); + buf_ptr += WMI_TLV_HDR_SIZE; + if (active_state_count) { + ndl_active_config = (wmi_dcc_ndl_active_state_config *)buf_ptr; + cdf_mem_copy(ndl_active_config, + config->dcc_ndl_active_state_list, + active_state_count * sizeof(*ndl_active_config)); + for (i = 0; i < active_state_count; ++i) + WMITLV_SET_HDR(&(ndl_active_config[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + buf_ptr += active_state_count * + sizeof(*ndl_active_config); + } + + /* Add the wmi_ocb_schedule_element info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->schedule_size * sizeof(wmi_ocb_schedule_element)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->schedule_size; i++) { + sched_elem = (wmi_ocb_schedule_element *)buf_ptr; + WMITLV_SET_HDR(&sched_elem->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_schedule_element, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_schedule_element)); + sched_elem->channel_freq = config->schedule[i].chan_freq; + sched_elem->total_duration = config->schedule[i].total_duration; + sched_elem->guard_interval = config->schedule[i].guard_interval; + buf_ptr += sizeof(*sched_elem); + } + + /* + * Save the configuration so that it can be used in + * wma_ocb_set_config_event_handler. + */ + if (wma_handle->ocb_config_req != config) { + if (wma_handle->ocb_config_req) + cdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = copy_sir_ocb_config(config); + } + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_OCB_SET_CONFIG_CMDID); + if (ret != EOK) { + if (wma_handle->ocb_config_req) { + cdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = NULL; + } + + WMA_LOGE("Failed to set OCB config"); + wmi_buf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_ocb_set_config_event_handler() - Response event for the set config cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_ocb_set_config_resp_event_fixed_param *fix_param; + param_tlvs = (WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + return wma_ocb_set_config_resp(handle, fix_param->status); +}; + +/** + * wma_ocb_set_utc_time() - send the UTC time to the firmware + * @wma_handle: pointer to the WMA handle + * @utc: pointer to the UTC time struct + * + * Return: 0 on succes + */ +int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc) +{ + int32_t ret; + wmi_ocb_set_utc_time_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, i; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_utc_time_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_utc_time_cmd_fixed_param)); + cmd->vdev_id = utc->vdev_id; + + for (i = 0; i < SIZE_UTC_TIME; i++) + WMI_UTC_TIME_SET(cmd, i, utc->utc_time[i]); + + for (i = 0; i < SIZE_UTC_TIME_ERROR; i++) + WMI_TIME_ERROR_SET(cmd, i, utc->time_error[i]); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_OCB_SET_UTC_TIME_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to set OCB UTC time")); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_start_timing_advert() - start sending the timing advertisement + * frames on a channel + * @wma_handle: pointer to the WMA handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + int32_t ret; + wmi_ocb_start_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, len_template; + wmi_buf_t buf; + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE; + + len_template = timing_advert->template_length; + /* Add padding to the template if needed */ + if (len_template % 4 != 0) + len_template += 4 - (len_template % 4); + len += len_template; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_start_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_start_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->repeat_rate = timing_advert->repeat_rate; + cmd->channel_freq = timing_advert->chan_freq; + cmd->timestamp_offset = timing_advert->timestamp_offset; + cmd->time_value_offset = timing_advert->time_value_offset; + cmd->timing_advert_template_length = timing_advert->template_length; + buf_ptr += sizeof(*cmd); + + /* Add the timing advert template */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + len_template); + cdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)timing_advert->template_value, + timing_advert->template_length); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_OCB_START_TIMING_ADVERT_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to start OCB timing advert")); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_stop_timing_advert() - stop sending the timing advertisement frames + * on a channel + * @wma_handle: pointer to the WMA handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + int32_t ret; + wmi_ocb_stop_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_stop_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_stop_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->channel_freq = timing_advert->chan_freq; + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_OCB_STOP_TIMING_ADVERT_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to stop OCB timing advert")); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_get_tsf_timer() - stop sending the timing advertisement frames on a + * channel + * @wma_handle: pointer to the WMA handle + * @request: pointer to the request + * + * Return: 0 on succes + */ +int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, + struct sir_ocb_get_tsf_timer *request) +{ + CDF_STATUS ret; + wmi_ocb_get_tsf_timer_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr; + cdf_mem_zero(cmd, len); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_get_tsf_timer_cmd_fixed_param)); + cmd->vdev_id = request->vdev_id; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_OCB_GET_TSF_TIMER_CMDID); + /* If there is an error, set the completion event */ + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_ocb_get_tsf_timer_resp_event_handler() - Event for the get TSF timer cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_ocb_get_tsf_timer_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + CDF_STATUS cdf_status; + struct sir_ocb_get_tsf_timer_response *response; + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + + /* Allocate and populate the response */ + response = cdf_mem_malloc(sizeof(*response)); + if (response == NULL) + return -ENOMEM; + response->vdev_id = fix_param->vdev_id; + response->timer_high = fix_param->tsf_timer_high; + response->timer_low = fix_param->tsf_timer_low; + + msg.type = eWNI_SME_OCB_GET_TSF_TIMER_RSP; + msg.bodyptr = response; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + cdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_get_stats() - get the DCC channel stats + * @wma_handle: pointer to the WMA handle + * @get_stats_param: pointer to the dcc stats + * + * Return: 0 on succes + */ +int wma_dcc_get_stats(tp_wma_handle wma_handle, + struct sir_dcc_get_stats *get_stats_param) +{ + int32_t ret; + wmi_dcc_get_stats_cmd_fixed_param *cmd; + wmi_dcc_channel_stats_request *channel_stats_array; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* Validate the input */ + if (get_stats_param->request_array_len != + get_stats_param->channel_count * sizeof(*channel_stats_array)) { + WMA_LOGE(FL("Invalid parameter")); + return -EINVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + get_stats_param->request_array_len; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_get_stats_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_get_stats_cmd_fixed_param)); + cmd->vdev_id = get_stats_param->vdev_id; + cmd->num_channels = get_stats_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + get_stats_param->request_array_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + channel_stats_array = (wmi_dcc_channel_stats_request *)buf_ptr; + cdf_mem_copy(channel_stats_array, get_stats_param->request_array, + get_stats_param->request_array_len); + for (i = 0; i < cmd->num_channels; i++) + WMITLV_SET_HDR(&channel_stats_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_channel_stats_request)); + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DCC_GET_STATS_CMDID); + + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_get_stats_resp_event_handler() - Response event for the get stats cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_get_stats_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + CDF_STATUS cdf_status; + struct sir_dcc_get_stats_response *response; + WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_get_stats_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + + /* Allocate and populate the response */ + response = cdf_mem_malloc(sizeof(*response) + fix_param->num_channels * + sizeof(wmi_dcc_ndl_stats_per_channel)); + if (response == NULL) + return -ENOMEM; + + response->vdev_id = fix_param->vdev_id; + response->num_channels = fix_param->num_channels; + response->channel_stats_array_len = + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); + response->channel_stats_array = ((void *)response) + sizeof(*response); + cdf_mem_copy(response->channel_stats_array, + param_tlvs->stats_per_channel_list, + response->channel_stats_array_len); + + msg.type = eWNI_SME_DCC_GET_STATS_RSP; + msg.bodyptr = response; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + cdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_clear_stats() - command to clear the DCC stats + * @wma_handle: pointer to the WMA handle + * @clear_stats_param: parameters to the command + * + * Return: 0 on succes + */ +int wma_dcc_clear_stats(tp_wma_handle wma_handle, + struct sir_dcc_clear_stats *clear_stats_param) +{ + int32_t ret; + wmi_dcc_clear_stats_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_clear_stats_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_clear_stats_cmd_fixed_param)); + cmd->vdev_id = clear_stats_param->vdev_id; + cmd->dcc_stats_bitmap = clear_stats_param->dcc_stats_bitmap; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DCC_CLEAR_STATS_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to send the WMI command")); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_update_ndl() - command to update the NDL data + * @wma_handle: pointer to the WMA handle + * @update_ndl_param: pointer to the request parameters + * + * Return: 0 on success + */ +int wma_dcc_update_ndl(tp_wma_handle wma_handle, + struct sir_dcc_update_ndl *update_ndl_param) +{ + CDF_STATUS cdf_status; + wmi_dcc_update_ndl_cmd_fixed_param *cmd; + wmi_dcc_ndl_chan *ndl_chan_array; + wmi_dcc_ndl_active_state_config *ndl_active_state_array; + uint32_t active_state_count; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* validate the input */ + if (update_ndl_param->dcc_ndl_chan_list_len != + update_ndl_param->channel_count * sizeof(*ndl_chan_array)) { + WMA_LOGE(FL("Invalid parameter")); + return CDF_STATUS_E_INVAL; + } + active_state_count = 0; + ndl_chan_array = update_ndl_param->dcc_ndl_chan_list; + for (i = 0; i < update_ndl_param->channel_count; i++) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(&ndl_chan_array[i]); + if (update_ndl_param->dcc_ndl_active_state_list_len != + active_state_count * sizeof(*ndl_active_state_array)) { + WMA_LOGE(FL("Invalid parameter")); + return CDF_STATUS_E_INVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + update_ndl_param->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + + update_ndl_param->dcc_ndl_active_state_list_len; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_update_ndl_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_update_ndl_cmd_fixed_param)); + cmd->vdev_id = update_ndl_param->vdev_id; + cmd->num_channel = update_ndl_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_chan_array = (wmi_dcc_ndl_chan *)buf_ptr; + cdf_mem_copy(ndl_chan_array, update_ndl_param->dcc_ndl_chan_list, + update_ndl_param->dcc_ndl_chan_list_len); + for (i = 0; i < cmd->num_channel; i++) + WMITLV_SET_HDR(&ndl_chan_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_chan)); + buf_ptr += update_ndl_param->dcc_ndl_chan_list_len; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_active_state_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_active_state_array = (wmi_dcc_ndl_active_state_config *) buf_ptr; + cdf_mem_copy(ndl_active_state_array, + update_ndl_param->dcc_ndl_active_state_list, + update_ndl_param->dcc_ndl_active_state_list_len); + for (i = 0; i < active_state_count; i++) { + WMITLV_SET_HDR(&ndl_active_state_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + } + buf_ptr += update_ndl_param->dcc_ndl_active_state_list_len; + + /* Send the WMI command */ + cdf_status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_DCC_UPDATE_NDL_CMDID); + /* If there is an error, set the completion event */ + if (cdf_status) { + WMA_LOGE(FL("Failed to send WMI message: %d"), cdf_status); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_update_ndl_resp_event_handler() - Response event for the update NDL + * command + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_update_ndl_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + CDF_STATUS cdf_status; + struct sir_dcc_update_ndl_response *resp; + WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_update_ndl_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + /* Allocate and populate the response */ + resp = cdf_mem_malloc(sizeof(*resp)); + if (!resp) { + WMA_LOGE(FL("Error allocating memory for the response.")); + return -ENOMEM; + } + resp->vdev_id = fix_param->vdev_id; + resp->status = fix_param->status; + + msg.type = eWNI_SME_DCC_UPDATE_NDL_RSP; + msg.bodyptr = resp; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + cdf_mem_free(resp); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_stats_event_handler() - Response event for the get stats cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_stats_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + CDF_STATUS cdf_status; + struct sir_dcc_get_stats_response *response; + WMI_DCC_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_stats_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_STATS_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + /* Allocate and populate the response */ + response = cdf_mem_malloc(sizeof(*response) + + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel)); + if (response == NULL) + return -ENOMEM; + response->vdev_id = fix_param->vdev_id; + response->num_channels = fix_param->num_channels; + response->channel_stats_array_len = + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); + response->channel_stats_array = ((void *)response) + sizeof(*response); + cdf_mem_copy(response->channel_stats_array, + param_tlvs->stats_per_channel_list, + response->channel_stats_array_len); + + msg.type = eWNI_SME_DCC_STATS_EVENT; + msg.bodyptr = response; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + cdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_ocb_register_event_handlers() - register handlers for the OCB WMI + * events + * @wma_handle: pointer to the WMA handle + * + * Return: 0 on success, non-zero on failure + */ +int wma_ocb_register_event_handlers(tp_wma_handle wma_handle) +{ + int status; + + if (!wma_handle) { + WMA_LOGE(FL("wma_handle is NULL")); + return -EINVAL; + } + + /* Initialize the members in WMA used by wma_ocb */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OCB_SET_CONFIG_RESP_EVENTID, + wma_ocb_set_config_event_handler); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + wma_ocb_get_tsf_timer_resp_event_handler); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_DCC_GET_STATS_RESP_EVENTID, + wma_dcc_get_stats_resp_event_handler); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_DCC_UPDATE_NDL_RESP_EVENTID, + wma_dcc_update_ndl_resp_event_handler); + if (status) + return status; + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DCC_STATS_EVENTID, + wma_dcc_stats_event_handler); + if (status) + return status; + + return CDF_STATUS_SUCCESS; +} diff --git a/core/wma/src/wma_ocb.h b/core/wma/src/wma_ocb.h new file mode 100644 index 0000000000..c2e5ae37eb --- /dev/null +++ b/core/wma/src/wma_ocb.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WMA_OCB_H +#define __WMA_OCB_H + +#include "wma.h" +#include "sir_api.h" + +int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status); + +int wma_ocb_set_config_req(tp_wma_handle handle, + struct sir_ocb_config *config_req); + +int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle); + +int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config); + +int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc); + +int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert); + +int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert); + +int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, + struct sir_ocb_get_tsf_timer *request); + +int wma_dcc_get_stats(tp_wma_handle wma_handle, + struct sir_dcc_get_stats *get_stats_param); + +int wma_dcc_clear_stats(tp_wma_handle wma_handle, + struct sir_dcc_clear_stats *clear_stats_param); + +int wma_dcc_update_ndl(tp_wma_handle wma_handle, + struct sir_dcc_update_ndl *update_ndl_param); + +int wma_ocb_register_event_handlers(tp_wma_handle wma_handle); + +#endif /* __WMA_OCB_H */ diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c new file mode 100644 index 0000000000..59e79759b0 --- /dev/null +++ b/core/wma/src/wma_power.c @@ -0,0 +1,2250 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_power.c + * This file contains powersave related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +/** + * wmi_unified_modem_power_state() - set modem power state to fw + * @wmi_handle: wmi handle + * @param_value: parameter value + * + * Return: 0 for success or error code + */ +static int +wmi_unified_modem_power_state(wmi_unified_t wmi_handle, uint32_t param_value) +{ + int ret; + wmi_modem_power_state_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_modem_power_state_cmd_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_modem_power_state_cmd_param)); + cmd->modem_power_state = param_value; + WMA_LOGD("%s: Setting cmd->modem_power_state = %u", __func__, + param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MODEM_POWER_STATE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send notify cmd ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wmi_unified_set_sta_ps_param() - set sta power save parameter to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param: param + * @value: parameter value + * + * Return: 0 for success or error code. + */ +int32_t wmi_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value) +{ + wmi_sta_powersave_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + tp_wma_handle wma; + struct wma_txrx_node *iface; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return -EIO; + } + iface = &wma->interfaces[vdev_id]; + + WMA_LOGD("Set Sta Ps param vdevId %d Param %d val %d", + vdev_id, param, value); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: Set Sta Ps param Mem Alloc Failed", __func__); + return -ENOMEM; + } + + cmd = (wmi_sta_powersave_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_powersave_param_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->param = param; + cmd->value = value; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_POWERSAVE_PARAM_CMDID)) { + WMA_LOGE("Set Sta Ps param Failed vdevId %d Param %d val %d", + vdev_id, param, value); + cdf_nbuf_free(buf); + return -EIO; + } + /* Store the PS Status */ + iface->ps_enabled = value ? true : false; + return 0; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_set_ibss_pwrsave_params() - set ibss power save parameter to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code. + */ +CDF_STATUS +wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id) +{ + int ret; + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH, + wma->wma_ibss_power_save_params.atimWindowLength); + if (ret < 0) { + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH ret = %d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerSaveAllowed); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerCollapseAllowed); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + wma->wma_ibss_power_save_params.isAwakeonTxRxEnabled); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_INACTIVITY_CNT, + wma->wma_ibss_power_save_params.inactivityCount); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_INACTIVITY_CNT ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + wma->wma_ibss_power_save_params.txSPEndInactivityTime); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + wma->wma_ibss_power_save_params.ibssPsWarmupTime); + if (ret < 0) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, + wma->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable); + if (ret < 0) { + WMA_LOGE("Failed to set IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE ret=%d", + ret); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wmi_unified_set_ap_ps_param() - set ap powersave parameters + * @wma_ctx: wma context + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @param: parameter + * @value: prameter value + * + * Return: 0 for success or error code + */ +static int32_t wmi_unified_set_ap_ps_param(void *wma_ctx, uint32_t vdev_id, + uint8_t *peer_addr, uint32_t param, + uint32_t value) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + wmi_ap_ps_peer_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set_ap_ps_param cmd"); + return -ENOMEM; + } + cmd = (wmi_ap_ps_peer_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_ap_ps_peer_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param = param; + cmd->value = value; + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), WMI_AP_PS_PEER_PARAM_CMDID); + if (err) { + WMA_LOGE("Failed to send set_ap_ps_param cmd"); + cdf_mem_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_set_ap_peer_uapsd() - set powersave parameters in ap mode to fw + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @uapsd_value: uapsd value + * @max_sp: maximum service period + * + * Return: 0 for success or error code. + */ +int32_t wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp) +{ + uint32_t uapsd = 0; + uint32_t max_sp_len = 0; + int32_t ret = 0; + + if (uapsd_value & UAPSD_VO_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_VI_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC2_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BK_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC1_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BE_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; + } + + switch (max_sp) { + case UAPSD_MAX_SP_LEN_2: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_2; + break; + case UAPSD_MAX_SP_LEN_4: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_4; + break; + case UAPSD_MAX_SP_LEN_6: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_6; + break; + default: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED; + break; + } + + WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for %pM", + uapsd, peer_addr); + + ret = wmi_unified_set_ap_ps_param(wma, vdev_id, + peer_addr, + WMI_AP_PS_PEER_PARAM_UAPSD, uapsd); + if (ret) { + WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for %pM", + peer_addr); + return ret; + } + + WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for %pM", + max_sp_len, peer_addr); + + ret = wmi_unified_set_ap_ps_param(wma, vdev_id, + peer_addr, + WMI_AP_PS_PEER_PARAM_MAX_SP, + max_sp_len); + if (ret) { + WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for %pM", + peer_addr); + return ret; + } + return 0; +} + +/** + * wma_update_edca_params_for_ac() - to update per ac EDCA parameters + * @edca_param: EDCA parameters + * @wmm_param: wmm parameters + * @ac: access category + * + * Return: none + */ +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + wmi_wmm_vparams *wmm_param, int ac) +{ +#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1) + wmm_param->cwmin = WMA_WMM_EXPO_TO_VAL(edca_param->cw.min); + wmm_param->cwmax = WMA_WMM_EXPO_TO_VAL(edca_param->cw.max); + wmm_param->aifs = edca_param->aci.aifsn; + wmm_param->txoplimit = edca_param->txoplimit; + wmm_param->acm = edca_param->aci.acm; + + /* TODO: No ack is not present in EdcaParamRecord */ + wmm_param->no_ack = 0; + + WMA_LOGI("WMM PARAMS AC[%d]: AIFS %d Min %d Max %d TXOP %d ACM %d NOACK %d", + ac, wmm_param->aifs, wmm_param->cwmin, wmm_param->cwmax, + wmm_param->txoplimit, wmm_param->acm, wmm_param->no_ack); +} + +/** + * wma_set_tx_power() - set tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + int ret = -1; + void *pdev; + + if (tx_pwr_params->dev_mode == CDF_SAP_MODE || + tx_pwr_params->dev_mode == CDF_P2P_GO_MODE) { + pdev = wma_find_vdev_by_addr(wma_handle, + tx_pwr_params->bssId, &vdev_id); + } else { + pdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId, &vdev_id); + } + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId); + cdf_mem_free(tx_pwr_params); + return; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up for %pM", __func__, vdev_id, + tx_pwr_params->bssId); + cdf_mem_free(tx_pwr_params); + return; + } + + if (tx_pwr_params->power == 0) { + /* set to default. Since the app does not care the tx power + * we keep the previous setting */ + wma_handle->interfaces[vdev_id].tx_power = 0; + ret = 0; + goto end; + } + if (wma_handle->interfaces[vdev_id].max_tx_power != 0) { + /* make sure tx_power less than max_tx_power */ + if (tx_pwr_params->power > + wma_handle->interfaces[vdev_id].max_tx_power) { + tx_pwr_params->power = + wma_handle->interfaces[vdev_id].max_tx_power; + } + } + if (wma_handle->interfaces[vdev_id].tx_power != tx_pwr_params->power) { + + /* tx_power changed, Push the tx_power to FW */ + WMA_LOGW("%s: Set TX power limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + __func__, tx_pwr_params->power); + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + tx_pwr_params->power); + if (ret == 0) + wma_handle->interfaces[vdev_id].tx_power = + tx_pwr_params->power; + } else { + /* no tx_power change */ + ret = 0; + } +end: + cdf_mem_free(tx_pwr_params); + if (ret) + WMA_LOGE("Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT"); +} + +/** + * wma_set_max_tx_power() - set max tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + int ret = -1; + void *pdev; + tPowerdBm prev_max_power; + + pdev = wma_find_vdev_by_addr(wma_handle, tx_pwr_params->bssId, &vdev_id); + if (pdev == NULL) { + /* not in SAP array. Try the station/p2p array */ + pdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId, &vdev_id); + } + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId); + cdf_mem_free(tx_pwr_params); + return; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + cdf_mem_free(tx_pwr_params); + return; + } + + if (wma_handle->interfaces[vdev_id].max_tx_power == + tx_pwr_params->power) { + ret = 0; + goto end; + } + prev_max_power = wma_handle->interfaces[vdev_id].max_tx_power; + wma_handle->interfaces[vdev_id].max_tx_power = tx_pwr_params->power; + if (wma_handle->interfaces[vdev_id].max_tx_power == 0) { + ret = 0; + goto end; + } + WMA_LOGW("Set MAX TX power limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + wma_handle->interfaces[vdev_id].max_tx_power); + ret = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + wma_handle->interfaces[vdev_id].max_tx_power); + if (ret == 0) + wma_handle->interfaces[vdev_id].tx_power = + wma_handle->interfaces[vdev_id].max_tx_power; + else + wma_handle->interfaces[vdev_id].max_tx_power = prev_max_power; +end: + cdf_mem_free(tx_pwr_params); + if (ret) + WMA_LOGE("%s: Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT", + __func__); +} + +/** + * wmi_unified_set_sta_ps() - set sta powersave params in fw + * @handle: wma handle + * @vdev_id: vdev id + * @val: value + * + * Return: 0 for success or error code. + */ +int32_t wmi_unified_set_sta_ps(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val) +{ + wmi_sta_powersave_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMA_LOGD("Set Sta Mode Ps vdevId %d val %d", vdev_id, val); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: Set Sta Mode Ps Mem Alloc Failed", __func__); + return -ENOMEM; + } + cmd = (wmi_sta_powersave_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_powersave_mode_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (val) + cmd->sta_ps_mode = WMI_STA_PS_MODE_ENABLED; + else + cmd->sta_ps_mode = WMI_STA_PS_MODE_DISABLED; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_POWERSAVE_MODE_CMDID)) { + WMA_LOGE("Set Sta Mode Ps Failed vdevId %d val %d", + vdev_id, val); + cdf_nbuf_free(buf); + return -EIO; + } + return 0; +} + +/** + * wma_get_uapsd_mask() - get uapsd mask based on uapsd parameters + * @uapsd_params: uapsed parameters + * + * Return: uapsd mask + */ +static inline uint32_t wma_get_uapsd_mask(tpUapsd_Params uapsd_params) +{ + uint32_t uapsd_val = 0; + + if (uapsd_params->beDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_DELIVERY_EN; + + if (uapsd_params->beTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; + + if (uapsd_params->bkDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_DELIVERY_EN; + + if (uapsd_params->bkTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; + + if (uapsd_params->viDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_DELIVERY_EN; + + if (uapsd_params->viTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; + + if (uapsd_params->voDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_DELIVERY_EN; + + if (uapsd_params->voTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; + + return uapsd_val; +} + +/** + * wma_set_force_sleep() - set power save parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * @enable: enable/disable + * @qpower_config: qpower configuration + * + * Return: 0 for success or error code + */ +static int32_t wma_set_force_sleep(tp_wma_handle wma, + uint32_t vdev_id, + uint8_t enable, + enum powersave_qpower_mode qpower_config) +{ + int32_t ret; + uint32_t cfg_data_val = 0; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE); + uint32_t rx_wake_policy; + uint32_t tx_wake_threshold; + uint32_t pspoll_count; + uint32_t inactivity_time; + uint32_t psmode; + + WMA_LOGD("Set Force Sleep vdevId %d val %d", vdev_id, enable); + + if (NULL == mac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return -ENOMEM; + } + + /* Set Tx/Rx Data InActivity Timeout */ + if (wlan_cfg_get_int(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT"); + cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + inactivity_time = (uint32_t) cfg_data_val; + + if (enable) { + /* override normal configuration and force station asleep */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) + pspoll_count = (uint32_t) cfg_data_val; + else + pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE; + + psmode = WMI_STA_PS_MODE_ENABLED; + } else { + /* Ps Poll Wake Policy */ + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) { + /* Ps Poll is enabled */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + pspoll_count = (uint32_t) cfg_data_val; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + } else { + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_WAKE; + pspoll_count = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; + } + psmode = WMI_STA_PS_MODE_ENABLED; + } + + /* + * QPower is enabled by default in Firmware + * So Disable QPower explicitly + */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + qpower_config); + if (ret) { + WMA_LOGE("Disable QPower Failed vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("QPower Disabled vdevId %d", vdev_id); + + /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_RX_WAKE_POLICY, + rx_wake_policy); + + if (ret) { + WMA_LOGE("Setting wake policy Failed vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("Setting wake policy to %d vdevId %d", + rx_wake_policy, vdev_id); + + /* Set the Tx Wake Threshold */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + tx_wake_threshold); + + if (ret) { + WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("Setting TxWake Threshold to %d vdevId %d", + tx_wake_threshold, vdev_id); + + /* Set the Ps Poll Count */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_PSPOLL_COUNT, + pspoll_count); + + if (ret) { + WMA_LOGE("Set Ps Poll Count Failed vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + return ret; + } + WMA_LOGD("Set Ps Poll Count vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + + /* Set the Tx/Rx InActivity */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + inactivity_time); + + if (ret) { + WMA_LOGE("Setting Tx/Rx InActivity Failed vdevId %d InAct %d", + vdev_id, inactivity_time); + return ret; + } + WMA_LOGD("Set Tx/Rx InActivity vdevId %d InAct %d", + vdev_id, inactivity_time); + + /* Enable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true); + + if (ret) { + WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id); + return ret; + } + + /* Set Listen Interval */ + if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_LISTEN_INTERVAL"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (ret) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id); + } + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + return 0; +} + +/** + * wma_set_qpower_force_sleep() - set qpower params in fw + * @wma: wma handle + * @vdev_id: vdev id + * @enable: value + * + * Return: 0 for success or error code. + */ +int32_t wma_set_qpower_force_sleep(tp_wma_handle wma, uint32_t vdev_id, + uint8_t enable) +{ + int32_t ret; + uint32_t cfg_data_val = 0; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE); + uint32_t pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE; + + WMA_LOGE("Set QPower Force(1)/Normal(0) Sleep vdevId %d val %d", + vdev_id, enable); + + if (NULL == mac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return -ENOMEM; + } + + /* Get Configured Ps Poll Count */ + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) { + pspoll_count = (uint32_t) cfg_data_val; + } + + /* Enable QPower */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_ENABLE_QPOWER, 1); + + if (ret) { + WMA_LOGE("Enable QPower Failed vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("QPower Enabled vdevId %d", vdev_id); + + /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_RX_WAKE_POLICY, + WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD); + + if (ret) { + WMA_LOGE("Setting wake policy to pspoll/uapsd Failed vdevId %d", + vdev_id); + return ret; + } + WMA_LOGD("Wake policy set to to pspoll/uapsd vdevId %d", vdev_id); + + if (enable) { + /* Set the Tx Wake Threshold */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER); + + if (ret) { + WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("TxWake Threshold set to TX_WAKE_THRESHOLD_NEVER %d", + vdev_id); + } + + /* Set the QPower Ps Poll Count */ + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + pspoll_count); + + if (ret) { + WMA_LOGE("Set QPower Ps Poll Count Failed vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + return ret; + } + WMA_LOGD("Set QPower Ps Poll Count vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + + /* Enable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true); + + if (ret) { + WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", vdev_id); + return ret; + } + + /* Set Listen Interval */ + if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_LISTEN_INTERVAL"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (ret) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id); + } + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + return 0; +} + +/** + * wma_get_qpower_config() - get qpower configuration + * @wma: WMA handle + * + * Power Save Offload configuration: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Return: enum powersave_qpower_mode with below values + * QPOWER_DISABLED if QPOWER is disabled + * QPOWER_ENABLED if QPOWER is enabled + * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled + */ +static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma) +{ + switch (wma->powersave_mode) { + case PS_QPOWER_NODEEPSLEEP: + case PS_QPOWER_DEEPSLEEP: + WMA_LOGI("QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_ENABLED; + case PS_DUTY_CYCLING_QPOWER: + WMA_LOGI("DUTY cycling QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DUTY_CYCLING; + + default: + WMA_LOGI("QPOWER is disabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DISABLED; + } +} + +/** + * wma_enable_sta_ps_mode() - enable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req) +{ + uint32_t vdev_id = ps_req->sessionid; + int32_t ret; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("vdev id %d is not active", vdev_id); + return; + } + if (eSIR_ADDON_NOTHING == ps_req->psSetting) { + WMA_LOGD("Enable Sta Mode Ps vdevId %d", vdev_id); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (ret) { + WMA_LOGE("Set Uapsd param 0 Failed vdevId %d", vdev_id); + return; + } + + ret = wma_set_force_sleep(wma, vdev_id, false, + qpower_config); + if (ret) { + WMA_LOGE("Enable Sta Ps Failed vdevId %d", vdev_id); + return; + } + } else if (eSIR_ADDON_ENABLE_UAPSD == ps_req->psSetting) { + uint32_t uapsd_val = 0; + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + if (uapsd_val != iface->uapsd_cached_val) { + WMA_LOGD("Enable Uapsd vdevId %d Mask %d", + vdev_id, uapsd_val); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_UAPSD, + uapsd_val); + if (ret) { + WMA_LOGE("Enable Uapsd Failed vdevId %d", + vdev_id); + return; + } + /* Cache the Uapsd Mask */ + iface->uapsd_cached_val = uapsd_val; + } else { + WMA_LOGD("Already Uapsd Enabled vdevId %d Mask %d", + vdev_id, uapsd_val); + } + + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config); + + if (ret) { + WMA_LOGE("Enable Forced Sleep Failed vdevId %d", + vdev_id); + return; + } + } + iface->dtimPeriod = ps_req->bcnDtimPeriod; +} + +/** + * wma_disable_sta_ps_mode() - disable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req) +{ + int32_t ret; + uint32_t vdev_id = ps_req->sessionid; + + WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (ret) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + /* Disable UAPSD incase if additional Req came */ + if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) { + WMA_LOGD("Disable Uapsd vdevId %d", vdev_id); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (ret) { + WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id); + /* + * Even this fails we can proceed as success + * since we disabled powersave + */ + } + } +} + +/** + * wma_enable_uapsd_mode() - enable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req) +{ + int32_t ret; + uint32_t vdev_id = ps_req->sessionid; + uint32_t uapsd_val = 0; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (ret) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + WMA_LOGD("Enable Uapsd vdevId %d Mask %d", vdev_id, uapsd_val); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, uapsd_val); + if (ret) { + WMA_LOGE("Enable Uapsd Failed vdevId %d", vdev_id); + return; + } + + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config); + if (ret) { + WMA_LOGE("Enable Forced Sleep Failed vdevId %d", vdev_id); + return; + } + +} + +/** + * wma_disable_uapsd_mode() - disable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_uapsd_mode(tp_wma_handle wma, + tpDisableUapsdParams ps_req) +{ + int32_t ret; + uint32_t vdev_id = ps_req->sessionid; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + WMA_LOGD("Disable Uapsd vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (ret) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (ret) { + WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id); + return; + } + + /* Re enable Sta Mode Powersave with proper configuration */ + ret = wma_set_force_sleep(wma, vdev_id, false, + qpower_config); + if (ret) { + WMA_LOGE("Disable Forced Sleep Failed vdevId %d", vdev_id); + return; + } +} + +/** + * wmi_unified_set_sta_uapsd_auto_trig_cmd() - set uapsd auto trigger command + * @wmi_handle: wma handle + * @vdevid: vdev id + * @peer_addr: peer mac address + * @autoTriggerparam: auto trigger parameters + * @num_ac: number of access category + * + * This function sets the trigger + * uapsd params such as service interval, delay interval + * and suspend interval which will be used by the firmware + * to send trigger frames periodically when there is no + * traffic on the transmit side. + * + * Return: 0 for success or error code. + */ +int32_t +wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_unified_t wmi_handle, + uint32_t vdevid, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t *autoTriggerparam, + uint32_t num_ac) +{ + wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd; + int32_t ret; + uint32_t param_len = num_ac * sizeof(wmi_sta_uapsd_auto_trig_param); + uint32_t cmd_len = sizeof(*cmd) + param_len + WMI_TLV_HDR_SIZE; + uint32_t i; + wmi_buf_t buf; + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wmi_handle, cmd_len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_sta_uapsd_auto_trig_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_uapsd_auto_trig_cmd_fixed_param)); + cmd->vdev_id = vdevid; + cmd->num_ac = num_ac; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + + /* TLV indicating array of structures to follow */ + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, param_len); + + buf_ptr += WMI_TLV_HDR_SIZE; + cdf_mem_copy(buf_ptr, autoTriggerparam, param_len); + + /* + * Update tag and length for uapsd auto trigger params (this will take + * care of updating tag and length if it is not pre-filled by caller). + */ + for (i = 0; i < num_ac; i++) { + WMITLV_SET_HDR((buf_ptr + + (i * sizeof(wmi_sta_uapsd_auto_trig_param))), + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_uapsd_auto_trig_param)); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, cmd_len, + WMI_STA_UAPSD_AUTO_TRIG_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set uapsd param ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wma_trigger_uapsd_params() - set trigger uapsd parameter + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @trigger_uapsd_params: trigger uapsd parameters + * + * This function sets the trigger uapsd + * params such as service interval, delay + * interval and suspend interval which + * will be used by the firmware to send + * trigger frames periodically when there + * is no traffic on the transmit side. + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params) +{ + int32_t ret; + wmi_sta_uapsd_auto_trig_param uapsd_trigger_param; + + WMA_LOGD("Trigger uapsd params vdev id %d", vdev_id); + + WMA_LOGD("WMM AC %d User Priority %d SvcIntv %d DelIntv %d SusIntv %d", + trigger_uapsd_params->wmm_ac, + trigger_uapsd_params->user_priority, + trigger_uapsd_params->service_interval, + trigger_uapsd_params->delay_interval, + trigger_uapsd_params->suspend_interval); + + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_STA_UAPSD_BASIC_AUTO_TRIG) || + !WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_STA_UAPSD_VAR_AUTO_TRIG)) { + WMA_LOGD("Trigger uapsd is not supported vdev id %d", vdev_id); + return CDF_STATUS_SUCCESS; + } + + uapsd_trigger_param.wmm_ac = trigger_uapsd_params->wmm_ac; + uapsd_trigger_param.user_priority = trigger_uapsd_params->user_priority; + uapsd_trigger_param.service_interval = + trigger_uapsd_params->service_interval; + uapsd_trigger_param.suspend_interval = + trigger_uapsd_params->suspend_interval; + uapsd_trigger_param.delay_interval = + trigger_uapsd_params->delay_interval; + + ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + (uint8_t *) (&uapsd_trigger_param), 1); + if (ret) { + WMA_LOGE("Fail to send uapsd param cmd for vdevid %d ret = %d", + ret, vdev_id); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_disable_uapsd_per_ac() - disable uapsd per ac + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @ac: access category + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac) +{ + int32_t ret; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + wmi_sta_uapsd_auto_trig_param uapsd_trigger_param; + enum uapsd_up user_priority; + + WMA_LOGD("Disable Uapsd per ac vdevId %d ac %d", vdev_id, ac); + + switch (ac) { + case UAPSD_VO: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN); + user_priority = UAPSD_UP_VO; + break; + case UAPSD_VI: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN); + user_priority = UAPSD_UP_VI; + break; + case UAPSD_BK: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN); + user_priority = UAPSD_UP_BK; + break; + case UAPSD_BE: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN); + user_priority = UAPSD_UP_BE; + break; + default: + WMA_LOGE("Invalid AC vdevId %d ac %d", vdev_id, ac); + return CDF_STATUS_E_FAILURE; + } + + /* + * Disable Auto Trigger Functionality before + * disabling uapsd for a particular AC + */ + uapsd_trigger_param.wmm_ac = ac; + uapsd_trigger_param.user_priority = user_priority; + uapsd_trigger_param.service_interval = 0; + uapsd_trigger_param.suspend_interval = 0; + uapsd_trigger_param.delay_interval = 0; + + ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + (uint8_t *)(&uapsd_trigger_param), 1); + if (ret) { + WMA_LOGE("Fail to send auto trig cmd for vdevid %d ret = %d", + ret, vdev_id); + return CDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_set_sta_ps_param(wma_handle->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, + iface->uapsd_cached_val); + if (ret) { + WMA_LOGE("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id, + ac); + return CDF_STATUS_E_FAILURE; + } + WMA_LOGD("Disable Uapsd per ac vdevId %d val %d", vdev_id, + iface->uapsd_cached_val); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_temperature() - get pdev temperature req + * @wmi_handle: wma handle + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_get_temperature(tp_wma_handle wma_handle) +{ + wmi_pdev_get_temperature_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = sizeof(wmi_pdev_get_temperature_cmd_fixed_param); + uint8_t *buf_ptr; + + if (!wma_handle) { + WMA_LOGE(FL("WMA is closed, can not issue cmd")); + return CDF_STATUS_E_INVAL; + } + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_pdev_get_temperature_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_get_temperature_cmd_fixed_param)); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_PDEV_GET_TEMPERATURE_CMDID)) { + WMA_LOGE(FL("failed to send get temperature command")); + wmi_buf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_pdev_temperature_evt_handler() - pdev temperature event handler + * @handle: wma handle + * @event: event buffer + * @len : length + * + * Return: 0 for success or error code. + */ +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *param_buf; + wmi_pdev_temperature_event_fixed_param *wmi_event; + + param_buf = (WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid pdev_temperature event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGI(FL("temperature: %d"), wmi_event->value); + + sme_msg.type = eWNI_SME_MSG_GET_TEMPERATURE_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = wmi_event->value; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE(FL("Fail to post get temperature ind msg")); + } + + return 0; +} + +/** + * wma_process_tx_power_limits() - sends the power limits for 2g/5g to firmware + * @handle: wma handle + * @ptxlim: power limit value + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + tSirTxPowerLimit *ptxlim) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int32_t ret = 0; + uint32_t txpower_params2g = 0; + uint32_t txpower_params5g = 0; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue tx power limit", + __func__); + return CDF_STATUS_E_INVAL; + } + /* Set value and reason code for 2g and 5g power limit */ + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params2g, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params2g, ptxlim->txPower2g); + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params5g, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params5g, ptxlim->txPower5g); + + WMA_LOGD("%s: txpower2g: %x txpower5g: %x", + __func__, txpower_params2g, txpower_params5g); + + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + txpower_params2g); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 2g (%d)", __func__, ret); + return CDF_STATUS_E_FAILURE; + } + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + txpower_params5g); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 5g (%d)", __func__, ret); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_add_p2p_ie() - add p2p IE + * @frm: ptr where p2p ie needs to add + * + * Return: ptr after p2p ie + */ +uint8_t *wma_add_p2p_ie(uint8_t *frm) +{ + uint8_t wfa_oui[3] = WMA_P2P_WFA_OUI; + struct p2p_ie *p2p_ie = (struct p2p_ie *)frm; + + p2p_ie->p2p_id = WMA_P2P_IE_ID; + p2p_ie->p2p_oui[0] = wfa_oui[0]; + p2p_ie->p2p_oui[1] = wfa_oui[1]; + p2p_ie->p2p_oui[2] = wfa_oui[2]; + p2p_ie->p2p_oui_type = WMA_P2P_WFA_VER; + p2p_ie->p2p_len = 4; + return frm + sizeof(struct p2p_ie); +} + +/** + * wma_update_beacon_noa_ie() - update beacon ie + * @bcn: beacon info + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_update_beacon_noa_ie(struct beacon_info *bcn, + uint16_t new_noa_sub_ie_len) +{ + struct p2p_ie *p2p_ie; + uint8_t *buf; + + /* if there is nothing to add, just return */ + if (new_noa_sub_ie_len == 0) { + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + WMA_LOGD("%s: NoA is present in previous beacon, " + "but not present in swba event, " + "So Reset the NoA", __func__); + /* TODO: Assuming p2p noa ie is last ie in the beacon */ + cdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie))); + bcn->len -= (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie)); + bcn->noa_ie = NULL; + bcn->noa_sub_ie_len = 0; + } + WMA_LOGD("%s: No need to update NoA", __func__); + return; + } + + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + /* NoA present in previous beacon, update it */ + WMA_LOGD("%s: NoA present in previous beacon, " + "update the NoA IE, bcn->len %u" + "bcn->noa_sub_ie_len %u", + __func__, bcn->len, bcn->noa_sub_ie_len); + bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)); + cdf_mem_zero(bcn->noa_ie, + (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))); + } else { /* NoA is not present in previous beacon */ + WMA_LOGD("%s: NoA not present in previous beacon, add it" + "bcn->len %u", __func__, bcn->len); + buf = cdf_nbuf_data(bcn->buf); + bcn->noa_ie = buf + bcn->len; + } + + bcn->noa_sub_ie_len = new_noa_sub_ie_len; + wma_add_p2p_ie(bcn->noa_ie); + p2p_ie = (struct p2p_ie *)bcn->noa_ie; + p2p_ie->p2p_len += new_noa_sub_ie_len; + cdf_mem_copy((bcn->noa_ie + sizeof(struct p2p_ie)), bcn->noa_sub_ie, + new_noa_sub_ie_len); + + bcn->len += (new_noa_sub_ie_len + sizeof(struct p2p_ie)); + WMA_LOGI("%s: Updated beacon length with NoA Ie is %u", + __func__, bcn->len); +} + +/** + * wma_p2p_create_sub_ie_noa() - put p2p noa ie + * @buf: buffer + * @noa: noa element ie + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_p2p_create_sub_ie_noa(uint8_t *buf, + struct p2p_sub_element_noa *noa, + uint16_t *new_noa_sub_ie_len) +{ + uint8_t tmp_octet = 0; + int i; + uint8_t *buf_start = buf; + + *buf++ = WMA_P2P_SUB_ELEMENT_NOA; /* sub-element id */ + ASSERT(noa->num_descriptors <= WMA_MAX_NOA_DESCRIPTORS); + + /* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + P2PIE_PUT_LE16(buf, WMA_NOA_IE_SIZE(noa->num_descriptors)); + buf += 2; + + *buf++ = noa->index; /* Instance Index */ + + tmp_octet = noa->ctwindow & WMA_P2P_NOA_IE_CTWIN_MASK; + if (noa->oppPS) { + tmp_octet |= WMA_P2P_NOA_IE_OPP_PS_SET; + } + *buf++ = tmp_octet; /* Opp Ps and CTWin capabilities */ + + for (i = 0; i < noa->num_descriptors; i++) { + ASSERT(noa->noa_descriptors[i].type_count != 0); + + *buf++ = noa->noa_descriptors[i].type_count; + + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].duration); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].interval); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].start_time); + buf += 4; + } + *new_noa_sub_ie_len = (buf - buf_start); +} + +/** + * wma_update_noa() - update noa params + * @beacon: beacon info + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie) +{ + uint16_t new_noa_sub_ie_len; + + /* Call this function by holding the spinlock on beacon->lock */ + + if (noa_ie) { + if ((noa_ie->ctwindow == 0) && (noa_ie->oppPS == 0) && + (noa_ie->num_descriptors == 0)) { + /* NoA is not present */ + WMA_LOGD("%s: NoA is not present", __func__); + new_noa_sub_ie_len = 0; + } else { + /* Create the binary blob containing NOA sub-IE */ + WMA_LOGD("%s: Create NOA sub ie", __func__); + wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0], + noa_ie, &new_noa_sub_ie_len); + } + } else { + WMA_LOGD("%s: No need to add NOA", __func__); + new_noa_sub_ie_len = 0; /* no NOA IE sub-attributes */ + } + + wma_update_beacon_noa_ie(beacon, new_noa_sub_ie_len); +} + +/** + * wma_update_probe_resp_noa() - update noa IE in probe response + * @wma_handle: wma handle + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie) +{ + tSirP2PNoaAttr *noa_attr = + (tSirP2PNoaAttr *) cdf_mem_malloc(sizeof(tSirP2PNoaAttr)); + WMA_LOGD("Received update NoA event"); + if (!noa_attr) { + WMA_LOGE("Failed to allocate memory for tSirP2PNoaAttr"); + return; + } + + cdf_mem_zero(noa_attr, sizeof(tSirP2PNoaAttr)); + + noa_attr->index = noa_ie->index; + noa_attr->oppPsFlag = noa_ie->oppPS; + noa_attr->ctWin = noa_ie->ctwindow; + if (!noa_ie->num_descriptors) { + WMA_LOGD("Zero NoA descriptors"); + } else { + WMA_LOGD("%d NoA descriptors", noa_ie->num_descriptors); + noa_attr->uNoa1IntervalCnt = + noa_ie->noa_descriptors[0].type_count; + noa_attr->uNoa1Duration = noa_ie->noa_descriptors[0].duration; + noa_attr->uNoa1Interval = noa_ie->noa_descriptors[0].interval; + noa_attr->uNoa1StartTime = + noa_ie->noa_descriptors[0].start_time; + if (noa_ie->num_descriptors > 1) { + noa_attr->uNoa2IntervalCnt = + noa_ie->noa_descriptors[1].type_count; + noa_attr->uNoa2Duration = + noa_ie->noa_descriptors[1].duration; + noa_attr->uNoa2Interval = + noa_ie->noa_descriptors[1].interval; + noa_attr->uNoa2StartTime = + noa_ie->noa_descriptors[1].start_time; + } + } + WMA_LOGI("Sending SIR_HAL_P2P_NOA_ATTR_IND to LIM"); + wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr, 0); +} + +/** + * wma_p2p_noa_event_handler() - p2p noa event handler + * @handle: wma handle + * @event: event data + * @len: length + * + * Return: 0 for success or error code. + */ +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_P2P_NOA_EVENTID_param_tlvs *param_buf; + wmi_p2p_noa_event_fixed_param *p2p_noa_event; + uint8_t vdev_id, i; + wmi_p2p_noa_info *p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + uint8_t *buf_ptr; + uint32_t descriptors; + + param_buf = (WMI_P2P_NOA_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid P2P NoA event buffer"); + return -EINVAL; + } + + p2p_noa_event = param_buf->fixed_param; + buf_ptr = (uint8_t *) p2p_noa_event; + buf_ptr += sizeof(wmi_p2p_noa_event_fixed_param); + p2p_noa_info = (wmi_p2p_noa_info *) (buf_ptr); + vdev_id = p2p_noa_event->vdev_id; + + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + + cdf_mem_zero(&noa_ie, sizeof(noa_ie)); + noa_ie.index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + noa_ie.oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + noa_ie.ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + noa_ie.num_descriptors = (uint8_t) descriptors; + + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " + "num_descriptors = %u", __func__, noa_ie.index, + noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); + for (i = 0; i < noa_ie.num_descriptors; i++) { + noa_ie.noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + noa_ie.noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + noa_ie.noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + noa_ie.noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + WMA_LOGI("%s: NoA descriptor[%d] type_count %u, " + "duration %u, interval %u, start_time = %u", + __func__, i, + noa_ie.noa_descriptors[i].type_count, + noa_ie.noa_descriptors[i].duration, + noa_ie.noa_descriptors[i].interval, + noa_ie.noa_descriptors[i].start_time); + } + + /* Send a msg to LIM to update the NoA IE in probe response + * frames transmitted by the host */ + wma_update_probe_resp_noa(wma, &noa_ie); + } + + return 0; +} + +/** + * wma_set_p2pgo_noa_req() - send p2p go noa request to fw + * @wma: wma handle + * @noa: p2p power save parameters + * + * Return: none + */ +static void wma_set_p2pgo_noa_req(tp_wma_handle wma, tP2pPsParams *noa) +{ + wmi_p2p_set_noa_cmd_fixed_param *cmd; + wmi_p2p_noa_descriptor *noa_discriptor; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint16_t len; + int32_t status; + uint32_t duration; + + WMA_LOGD("%s: Enter", __func__); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + sizeof(*noa_discriptor); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("Failed to allocate memory"); + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_p2p_set_noa_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_set_noa_cmd_fixed_param)); + duration = (noa->count == 1) ? noa->single_noa_duration : noa->duration; + cmd->vdev_id = noa->sessionId; + cmd->enable = (duration) ? true : false; + cmd->num_noa = 1; + + WMITLV_SET_HDR((buf_ptr + sizeof(wmi_p2p_set_noa_cmd_fixed_param)), + WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_p2p_noa_descriptor)); + noa_discriptor = (wmi_p2p_noa_descriptor *) (buf_ptr + + sizeof + (wmi_p2p_set_noa_cmd_fixed_param) + + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(&noa_discriptor->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor, + WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_noa_descriptor)); + noa_discriptor->type_count = noa->count; + noa_discriptor->duration = duration; + noa_discriptor->interval = noa->interval; + noa_discriptor->start_time = 0; + + WMA_LOGI("SET P2P GO NOA:vdev_id:%d count:%d duration:%d interval:%d", + cmd->vdev_id, noa->count, noa_discriptor->duration, + noa->interval); + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + if (status != EOK) { + WMA_LOGE("Failed to send WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID"); + wmi_buf_free(buf); + } + +end: + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_set_p2pgo_oppps_req() - send p2p go opp power save request to fw + * @wma: wma handle + * @noa: p2p opp power save parameters + * + * Return: none + */ +static void wma_set_p2pgo_oppps_req(tp_wma_handle wma, tP2pPsParams *oppps) +{ + wmi_p2p_set_oppps_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t status; + + WMA_LOGD("%s: Enter", __func__); + buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate memory"); + goto end; + } + + cmd = (wmi_p2p_set_oppps_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_set_oppps_cmd_fixed_param)); + cmd->vdev_id = oppps->sessionId; + if (oppps->ctWindow) + WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(cmd); + + WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(cmd, oppps->ctWindow); + WMA_LOGI("SET P2P GO OPPPS:vdev_id:%d ctwindow:%d", + cmd->vdev_id, oppps->ctWindow); + status = wmi_unified_cmd_send(wma->wmi_handle, buf, sizeof(*cmd), + WMI_P2P_SET_OPPPS_PARAM_CMDID); + if (status != EOK) { + WMA_LOGE("Failed to send WMI_P2P_SET_OPPPS_PARAM_CMDID"); + wmi_buf_free(buf); + } + +end: + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_process_set_p2pgo_noa_req() - process p2pgo noa request + * @handle: wma handle + * @ps_params: powersave params + * + * Return: none + */ +void wma_process_set_p2pgo_noa_req(tp_wma_handle wma, + tP2pPsParams *ps_params) +{ + WMA_LOGD("%s: Enter", __func__); + if (ps_params->opp_ps) { + wma_set_p2pgo_oppps_req(wma, ps_params); + } else { + wma_set_p2pgo_noa_req(wma, ps_params); + } + + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_process_set_mimops_req() - Set the received MiMo PS state to firmware + * @handle: wma handle + * @mimops: MIMO powersave params + * + * Return: none + */ +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops) +{ + /* Translate to what firmware understands */ + if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_DYNAMIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_DYNAMIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_STATIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_STATIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_NO_LIMIT) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_NONE; + + WMA_LOGD("%s: htMIMOPSState = %d, sessionId = %d \ + peerMac <%02x:%02x:%02x:%02x:%02x:%02x>", __func__, + mimops->htMIMOPSState, mimops->sessionId, mimops->peerMac[0], + mimops->peerMac[1], mimops->peerMac[2], mimops->peerMac[3], + mimops->peerMac[4], mimops->peerMac[5]); + + wma_set_peer_param(wma_handle, mimops->peerMac, + WMI_PEER_MIMO_PS_STATE, mimops->htMIMOPSState, + mimops->sessionId); +} + +/** + * wma_set_mimops() - set MIMO powersave + * @handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value) +{ + int ret = CDF_STATUS_SUCCESS; + wmi_sta_smps_force_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_sta_smps_force_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_smps_force_mode_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + + switch (value) { + case 0: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_NONE; + break; + case 1: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_DISABLED; + break; + case 2: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_STATIC; + break; + case 3: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_DYNAMIC; + break; + default: + WMA_LOGE("%s:INVALID Mimo PS CONFIG", __func__); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Setting vdev %d value = %u", vdev_id, value); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_STA_SMPS_FORCE_MODE_CMDID); + if (ret < 0) { + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * wma_notify_modem_power_state() - notify modem power state + * @wma_ptr: wma handle + * @pReq: modem power state + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + + WMA_LOGD("%s: WMA notify Modem Power State %d", __func__, pReq->param); + + ret = wmi_unified_modem_power_state(wma->wmi_handle, pReq->param); + if (ret) { + WMA_LOGE("%s: Fail to notify Modem Power State %d", + __func__, pReq->param); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully notify Modem Power State %d", pReq->param); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_idle_ps_config() - enable/disble Low Power Support(Pdev Specific) + * @wma_ptr: wma handle + * @idle_ps: idle powersave + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + + WMA_LOGD("WMA Set Idle Ps Config [1:set 0:clear] val %d", idle_ps); + + /* Set Idle Mode Power Save Config */ + ret = wmi_unified_pdev_set_param(wma->wmi_handle, + WMI_PDEV_PARAM_IDLE_PS_CONFIG, + idle_ps); + if (ret) { + WMA_LOGE("Fail to Set Idle Ps Config %d", idle_ps); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully Set Idle Ps Config %d", idle_ps); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_smps_params() - set smps params + * @wma: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: CDF_STATUS_SUCCESS for success or error code. + */ +CDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value) +{ + int ret = CDF_STATUS_SUCCESS; + wmi_sta_smps_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_sta_smps_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_smps_param_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->value = value & WMA_SMPS_MASK_LOWER_16BITS; + cmd->param = + (value >> WMA_SMPS_PARAM_VALUE_S) & WMA_SMPS_MASK_UPPER_3BITS; + + WMA_LOGD("Setting vdev %d value = %x param %x", vdev_id, cmd->value, + cmd->param); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_STA_SMPS_PARAM_CMDID); + if (ret < 0) { + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * wma_set_vdev_suspend_dtim() - set suspend dtim parameters in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + if ((iface->type == WMI_VDEV_TYPE_STA) && + (iface->ps_enabled == true) && + (iface->dtimPeriod != 0)) { + int32_t ret; + uint32_t listen_interval; + uint32_t max_mod_dtim; + + if (wma->staDynamicDtim) { + listen_interval = wma->staDynamicDtim; + } else if ((wma->staModDtim) && + (wma->staMaxLIModDtim)) { + /* + * When the system is in suspend + * (maximum beacon will be at 1s == 10) + * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM) + * equal or larger than MDTIM + * (configured in WCNSS_qcom_cfg.ini) + * Set LI to MDTIM * AP_DTIM + * If Dtim = 2 and Mdtim = 2 then LI is 4 + * Else + * Set LI to maxModulatedDTIM * AP_DTIM + */ + max_mod_dtim = wma->staMaxLIModDtim / iface->dtimPeriod; + if (max_mod_dtim >= wma->staModDtim) { + listen_interval = + (wma->staModDtim * iface->dtimPeriod); + } else { + listen_interval = + (max_mod_dtim * iface->dtimPeriod); + } + } else { + return; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + listen_interval); + if (ret) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, listen_interval); + + if (qpower_config) { + WMA_LOGD("disable Qpower in suspend mode!"); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + 0); + if (ret) + WMA_LOGE("Failed to disable Qpower in suspend mode!"); + + iface->ps_enabled = true; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY, + NORMAL_DTIM); + if (ret) + WMA_LOGE("Failed to Set to Normal DTIM vdevId %d", + vdev_id); + + /* Set it to Normal DTIM */ + iface->dtim_policy = NORMAL_DTIM; + WMA_LOGD("Set DTIM Policy to Normal Dtim vdevId %d", vdev_id); + } +} + +/** + * wma_set_suspend_dtim() - set suspend dtim + * @wma: wma handle + * + * Return: none + */ +void wma_set_suspend_dtim(tp_wma_handle wma) +{ + uint8_t i; + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + for (i = 0; i < wma->max_bssid; i++) { + if ((wma->interfaces[i].handle) && + (false == wma->interfaces[i].alt_modulated_dtim_enabled)) { + wma_set_vdev_suspend_dtim(wma, i); + } + } +} + +/** + * wma_set_vdev_resume_dtim() - set resume dtim parameters in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_set_vdev_resume_dtim(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + if ((iface->type == WMI_VDEV_TYPE_STA) && + (iface->ps_enabled == true) && + (iface->dtim_policy == NORMAL_DTIM)) { + int32_t ret; + uint32_t cfg_data_val = 0; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(CDF_MODULE_ID_PE); + /* Set Listen Interval */ + if ((NULL == mac) || (wlan_cfg_get_int(mac, + WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != + eSIR_SUCCESS)) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get value for listen interval"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (ret) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + + ret = wmi_unified_vdev_set_param_send(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY, + STICK_DTIM); + if (ret) { + /* Set it back to Stick DTIM */ + WMA_LOGE("Failed to Set to Stick DTIM vdevId %d", + vdev_id); + } + iface->dtim_policy = STICK_DTIM; + WMA_LOGD("Set DTIM Policy to Stick Dtim vdevId %d", vdev_id); + + if (qpower_config) { + WMA_LOGD("enable Qpower in resume mode!"); + ret = wmi_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + 1); + if (ret) + WMA_LOGE("Failed to enable Qpower in resume mode!"); + } + } +} + +/** + * wma_set_resume_dtim() - set resume dtim + * @wma: wma handle + * + * Return: none + */ +void wma_set_resume_dtim(tp_wma_handle wma) +{ + uint8_t i; + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + for (i = 0; i < wma->max_bssid; i++) { + if ((wma->interfaces[i].handle) && + (false == wma->interfaces[i].alt_modulated_dtim_enabled)) { + wma_set_vdev_resume_dtim(wma, i); + } + } +} + diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c new file mode 100644 index 0000000000..708202473f --- /dev/null +++ b/core/wma/src/wma_scan_roam.c @@ -0,0 +1,6886 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_scan_roam.c + * This file contains functions related to scan and + * roaming functionality. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +/* FIXME: Inclusion of .c looks odd but this is how it is in internal codebase */ +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +#define WMA_MCC_MIRACAST_REST_TIME 400 +#define WMA_SCAN_ID_MASK 0x0fff + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * enum extscan_report_events_type - extscan report events type + * @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full + * @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan + * @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results + * (beacons/probe responses + IEs) + * in real time to HAL, in addition to completion events. + * Note: To keep backward compatibility, + * fire completion events regardless of REPORT_EVENTS_EACH_SCAN. + * @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching, + * 0 => batching, 1 => no batching + */ +enum extscan_report_events_type { + EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00, + EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01, + EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02, + EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04, +}; + +#define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#endif + +/** + * wma_set_p2p_scan_info() - set p2p scan info in wma handle + * @wma_handle: wma handle + * @scan_id: scan id + * @vdev_id: vdev id + * @p2p_scan_type: p2p scan type + * + * Return: none + */ +static inline void wma_set_p2p_scan_info(tp_wma_handle wma_handle, + uint32_t scan_id, + uint32_t vdev_id, + tSirP2pScanType p2p_scan_type) +{ + wma_handle->interfaces[vdev_id].p2p_scan_info.scan_id = scan_id; + wma_handle->interfaces[vdev_id].p2p_scan_info.p2p_scan_type = + p2p_scan_type; +} + +/** + * wma_reset_p2p_scan_info() - reset scan info from wma handle + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static inline void wma_reset_p2p_scan_info(tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + cdf_mem_zero((void *)&(wma_handle->interfaces[vdev_id].p2p_scan_info), + sizeof(struct p2p_scan_param)); +} + +/** + * wma_is_mcc_24G() - check that if device is in 2.4GHz MCC + * @handle: wma handle + * + * Return: true/false + */ +static bool wma_is_mcc_24G(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int32_t prev_chan = 0; + int32_t i; + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return false; + } + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].handle && + wma_handle->interfaces[i].vdev_up) { + if ((prev_chan != 0 && + prev_chan != wma_handle->interfaces[i].mhz) && + (wma_handle->interfaces[i].mhz <= + CDS_CHAN_14_FREQ)) + return true; + else + prev_chan = wma_handle->interfaces[i].mhz; + } + } + return false; +} + +/** + * wma_get_buf_start_scan_cmd() - Fill start scan command + * @wma_handle: wma handle + * @scan_req: scan request + * @buf: wmi buffer to be filled in + * @buf_len: buf length + * + * Fill individual elements of wmi_start_scan_req and TLV for + * channel list, bssid, ssid etc. + * + * Return: CDF status + */ +CDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, + wmi_buf_t *buf, int *buf_len) +{ + wmi_start_scan_cmd_fixed_param *cmd; + wmi_chan_list *chan_list = NULL; + wmi_mac_addr *bssid; + wmi_ssid *ssid = NULL; + uint32_t *tmp_ptr, ie_len_with_pad; + CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE; + uint8_t *buf_ptr; + uint32_t dwell_time; + uint8_t SSID_num; + int i; + int len = sizeof(*cmd); + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGP("%s: pMac is NULL!", __func__); + return CDF_STATUS_E_FAILURE; + } + + len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of uint32_t */ + /* calculate the length of buffer required */ + if (scan_req->channelList.numChannels) + len += scan_req->channelList.numChannels * sizeof(uint32_t); + + len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of wmi_ssid structures */ + if (scan_req->numSsid) + len += scan_req->numSsid * sizeof(wmi_ssid); + + len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of wmi_mac_addr structures */ + len += sizeof(wmi_mac_addr); + + len += WMI_TLV_HDR_SIZE; /* Length TLV placeholder for array of bytes */ + if (scan_req->uIEFieldLen) + len += roundup(scan_req->uIEFieldLen, sizeof(uint32_t)); + + /* Allocate the memory */ + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory for start scan cmd", + __func__); + return CDF_STATUS_E_FAILURE; + } + + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = (wmi_start_scan_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_scan_cmd_fixed_param)); + + cmd->vdev_id = scan_req->sessionId; + /* + * host cycles through the lower 12 bits for scan id generation + * and prefix 0xA000 to scan id + */ + if (scan_req->scan_id < WMA_HOST_SCAN_REQID_PREFIX) { + WMA_LOGE("Received scan_id 0x%x is wrong", + cmd->scan_id); + scan_req->scan_id = scan_req->scan_id & WMA_SCAN_ID_MASK; + /* Appending the 0xA000 to scan Id*/ + cmd->scan_id = scan_req->scan_id | WMA_HOST_SCAN_REQID_PREFIX; + } else { + cmd->scan_id = scan_req->scan_id; + } + cmd->scan_priority = WMI_SCAN_PRIORITY_LOW; + cmd->scan_req_id = WMA_HOST_SCAN_REQUESTOR_ID_PREFIX | + WMA_DEFAULT_SCAN_REQUESTER_ID; + + /* Set the scan events which the driver is intereseted to receive */ + /* TODO: handle all the other flags also */ + cmd->notify_scan_events = WMI_SCAN_EVENT_STARTED | + WMI_SCAN_EVENT_START_FAILED | + WMI_SCAN_EVENT_FOREIGN_CHANNEL | + WMI_SCAN_EVENT_COMPLETED | + WMI_SCAN_EVENT_DEQUEUED | + WMI_SCAN_EVENT_PREEMPTED | WMI_SCAN_EVENT_RESTARTED; + + cmd->dwell_time_active = scan_req->maxChannelTime; + + if (scan_req->scanType == eSIR_ACTIVE_SCAN) { + /* In Active scan case, the firmware has to do passive scan on DFS channels + * So the passive scan duration should be updated properly so that the duration + * will be sufficient enough to receive the beacon from AP */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + &dwell_time) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get passive max channel value" + "using default value"); + dwell_time = WMA_DWELL_TIME_PASSIVE_DEFAULT; + } + cmd->dwell_time_passive = dwell_time; + } else + cmd->dwell_time_passive = scan_req->maxChannelTime; + + WMA_LOGI("Scan Type %x, Active dwell time %u, Passive dwell time %u", + scan_req->scanType, cmd->dwell_time_active, + cmd->dwell_time_passive); + + /* Ensure correct number of probes are sent on active channel */ + cmd->repeat_probe_time = + cmd->dwell_time_active / WMA_SCAN_NPROBES_DEFAULT; + + /* CSR sends only one value restTime for staying on home channel + * to continue data traffic. Rome fw has facility to monitor the traffic + * and move to next channel. Stay on the channel for at least half + * of the requested time and then leave if there is no traffic. + */ + cmd->min_rest_time = scan_req->restTime / 2; + cmd->max_rest_time = scan_req->restTime; + + /* Check for traffic at idle_time interval after min_rest_time. + * Default value is 25 ms to allow full use of max_rest_time + * when voice packets are running at 20 ms interval. + */ + cmd->idle_time = WMA_SCAN_IDLE_TIME_DEFAULT; + + /* Large timeout value for full scan cycle, 30 seconds */ + cmd->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + + /* do not add OFDM rates in 11B mode */ + if (scan_req->dot11mode != WNI_CFG_DOT11_MODE_11B) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; + else + WMA_LOGD("OFDM_RATES not included in 11B mode"); + + /* Do not combine multiple channels in a single burst. Come back + * to home channel for data traffic after every foreign channel. + * By default, prefer throughput performance over scan cycle time. + */ + cmd->burst_duration = 0; + + if (!scan_req->p2pScanType) { + WMA_LOGD("Normal Scan request"); + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; + if (!scan_req->numSsid) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_BCAST_PROBE_REQ; + if (scan_req->scanType == eSIR_PASSIVE_SCAN) + cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + + /* + * Decide burst_duration and dwell_time_active based on + * what type of devices are active. + */ + do { + if (wma_is_sap_active(wma_handle) && + wma_is_p2p_go_active(wma_handle) && + wma_is_sta_active(wma_handle)) { + if (scan_req->maxChannelTime <= + WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION) + cmd->burst_duration = + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION; + break; + } + if (wma_is_sap_active(wma_handle)) { + /* Background scan while SoftAP is sending beacons. + * Max duration of CTS2self is 32 ms, which limits + * the dwell time. + */ + cmd->dwell_time_active = + CDF_MIN(scan_req->maxChannelTime, + (WMA_CTS_DURATION_MS_MAX - + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME)); + cmd->dwell_time_passive = + cmd->dwell_time_active; + cmd->burst_duration = 0; + break; + } + if (wma_handle->miracast_value && + wma_is_mcc_24G(wma_handle)) { + cmd->max_rest_time = + pMac->f_sta_miracast_mcc_rest_time_val; + } + if (wma_is_p2p_go_active(wma_handle)) { + /* Background scan while GO is sending beacons. + * Every off-channel transition has overhead of 2 beacon + * intervals for NOA. Maximize number of channels in + * every transition by using burst scan. + */ + if (wma_handle->miracast_value) { + /* When miracast is running, burst duration + * needs to be minimum to avoid any stutter + * or glitch in miracast during station scan + */ + if (scan_req->maxChannelTime <= + WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION) + cmd->burst_duration = + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION; + } else { + /* If miracast is not running, accomodate max + * stations to make the scans faster + */ + cmd->burst_duration = + WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * + scan_req->maxChannelTime; + if (cmd->burst_duration > + WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION) { + uint8_t channels = + WMA_P2P_SCAN_MAX_BURST_DURATION + / scan_req->maxChannelTime; + if (channels) + cmd->burst_duration = + channels * + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION; + } + } + break; + } + if (wma_is_sta_active(wma_handle) || + wma_is_p2p_cli_active(wma_handle)) { + /* Typical background scan. Disable burst scan for now. */ + cmd->burst_duration = 0; + break; + } + } while (0); + + } else { + WMA_LOGD("P2P Scan"); + switch (scan_req->p2pScanType) { + case P2P_SCAN_TYPE_LISTEN: + WMA_LOGD("P2P_SCAN_TYPE_LISTEN"); + cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + cmd->notify_scan_events |= + WMI_SCAN_EVENT_FOREIGN_CHANNEL; + cmd->repeat_probe_time = 0; + break; + case P2P_SCAN_TYPE_SEARCH: + WMA_LOGD("P2P_SCAN_TYPE_SEARCH"); + cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + /* Default P2P burst duration of 120 ms will cover + * 3 channels with default max dwell time 40 ms. + * Cap limit will be set by + * WMA_P2P_SCAN_MAX_BURST_DURATION. Burst duration + * should be such that no channel is scanned less + * than the dwell time in normal scenarios. + */ + if (scan_req->channelList.numChannels == + P2P_SOCIAL_CHANNELS + && (!(wma_handle->miracast_value))) + cmd->repeat_probe_time = + scan_req->maxChannelTime / 5; + else + cmd->repeat_probe_time = + scan_req->maxChannelTime / 3; + + cmd->burst_duration = + WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * + scan_req->maxChannelTime; + if (cmd->burst_duration > + WMA_P2P_SCAN_MAX_BURST_DURATION) { + uint8_t channels = + WMA_P2P_SCAN_MAX_BURST_DURATION / + scan_req->maxChannelTime; + if (channels) + cmd->burst_duration = + channels * scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_P2P_SCAN_MAX_BURST_DURATION; + } + break; + default: + WMA_LOGE("Invalid scan type"); + goto error; + } + } + + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->dwell_time_active / cmd->repeat_probe_time : 0; + + buf_ptr += sizeof(*cmd); + tmp_ptr = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + + if (scan_req->channelList.numChannels) { + chan_list = (wmi_chan_list *) tmp_ptr; + cmd->num_chan = scan_req->channelList.numChannels; + for (i = 0; i < scan_req->channelList.numChannels; ++i) { + tmp_ptr[i] = + cds_chan_to_freq(scan_req->channelList. + channelNumber[i]); + } + } + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_UINT32, + (cmd->num_chan * sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_chan * sizeof(uint32_t)); + if (scan_req->numSsid > SIR_SCAN_MAX_NUM_SSID) { + WMA_LOGE("Invalid value for numSsid"); + goto error; + } + cmd->num_ssids = scan_req->numSsid; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (cmd->num_ssids * sizeof(wmi_ssid))); + if (scan_req->numSsid) { + ssid = (wmi_ssid *) (buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < scan_req->numSsid; ++i) { + ssid->ssid_len = scan_req->ssId[i].length; + cdf_mem_copy(ssid->ssid, scan_req->ssId[i].ssId, + scan_req->ssId[i].length); + ssid++; + } + } + buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_ssids * sizeof(wmi_ssid)); + + cmd->num_bssid = 1; + + if (!scan_req->p2pScanType) { + if (wma_is_sap_active(wma_handle)) { + SSID_num = cmd->num_ssids * cmd->num_bssid; + cmd->repeat_probe_time = probe_time_dwell_time_map[ + CDF_MIN(SSID_num, + WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE + - 1)].probe_time; + } + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (cmd->num_bssid * sizeof(wmi_mac_addr))); + bssid = (wmi_mac_addr *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(scan_req->bssId, bssid); + buf_ptr += WMI_TLV_HDR_SIZE + (cmd->num_bssid * sizeof(wmi_mac_addr)); + + cmd->ie_len = scan_req->uIEFieldLen; + ie_len_with_pad = roundup(scan_req->uIEFieldLen, sizeof(uint32_t)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_with_pad); + if (scan_req->uIEFieldLen) { + cdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *) scan_req + + (scan_req->uIEFieldOffset), scan_req->uIEFieldLen); + } + buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad; + + *buf_len = len; + return CDF_STATUS_SUCCESS; +error: + cdf_mem_free(*buf); + *buf = NULL; + return cdf_status; +} + +/** + * wma_get_buf_stop_scan_cmd() - Fill stop scan command + * @wma_handle: wma handle + * @buf: wmi buffer to be filled in + * @buf_len: buf length + * @abort_scan_req: abort scan request + * + * Fill wmi_stop_scan_cmd buffer. + * + * Return: CDF status + */ +CDF_STATUS wma_get_buf_stop_scan_cmd(tp_wma_handle wma_handle, + wmi_buf_t *buf, + int *buf_len, + tAbortScanParams *abort_scan_req) +{ + wmi_stop_scan_cmd_fixed_param *cmd; + CDF_STATUS cdf_status; + int len = sizeof(*cmd); + + /* Allocate the memory */ + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory for stop scan cmd", + __func__); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + cmd = (wmi_stop_scan_cmd_fixed_param *) wmi_buf_data(*buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_stop_scan_cmd_fixed_param)); + cmd->vdev_id = abort_scan_req->SessionId; + cmd->requestor = WMA_HOST_SCAN_REQUESTOR_ID_PREFIX | + WMA_DEFAULT_SCAN_REQUESTER_ID; + cmd->scan_id = abort_scan_req->scan_id; + /* stop the scan with the corresponding scan_id */ + cmd->req_type = WMI_SCAN_STOP_ONE; + + *buf_len = len; + cdf_status = CDF_STATUS_SUCCESS; +error: + return cdf_status; + +} + + +/** + * wma_start_scan() - start scan command + * @wma_handle: wma handle + * @scan_req: scan request params + * @msg_type: message time + * + * Send start scan command to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_start_scan(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, uint16_t msg_type) +{ + uint32_t vdev_id, scan_id; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + wmi_start_scan_cmd_fixed_param *cmd; + int status = 0; + int len; + tSirScanOffloadEvent *scan_event; + + if (scan_req->sessionId > wma_handle->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d, msg_type : 0x%x", __func__, + scan_req->sessionId, msg_type); + goto error; + } + + /* Sanity check to find whether vdev id active or not */ + if (msg_type != WMA_START_SCAN_OFFLOAD_REQ && + !wma_handle->interfaces[scan_req->sessionId].handle) { + WMA_LOGA("vdev id [%d] is not active", scan_req->sessionId); + goto error; + } + + /* Fill individual elements of wmi_start_scan_req and + * TLV for channel list, bssid, ssid etc ... */ + cdf_status = wma_get_buf_start_scan_cmd(wma_handle, scan_req, + &buf, &len); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get buffer for start scan cmd"); + goto error; + } + + if (NULL == buf) { + WMA_LOGE("Failed to get buffer for saving current scan info"); + goto error; + } + + /* Save current scan info */ + cmd = (wmi_start_scan_cmd_fixed_param *) wmi_buf_data(buf); + if (msg_type == WMA_CHNL_SWITCH_REQ) { + /* Adjust parameters for channel switch scan */ + cmd->min_rest_time = WMA_ROAM_PREAUTH_REST_TIME; + cmd->max_rest_time = WMA_ROAM_PREAUTH_REST_TIME; + cmd->max_scan_time = WMA_ROAM_PREAUTH_MAX_SCAN_TIME; + cmd->scan_priority = WMI_SCAN_PRIORITY_HIGH; + cmd->scan_id = scan_req->scan_id; + wma_handle->roam_preauth_scan_id = cmd->scan_id; + } + if (scan_req->p2pScanType == P2P_SCAN_TYPE_LISTEN) + wma_set_p2p_scan_info(wma_handle, cmd->scan_id, + cmd->vdev_id, P2P_SCAN_TYPE_LISTEN); + WMA_LOGE("scan_id 0x%x, vdev_id %d, p2pScanType %d, msg_type 0x%x", + cmd->scan_id, cmd->vdev_id, scan_req->p2pScanType, msg_type); + /* + * Cache vdev_id and scan_id because cmd is freed after calling + * wmi_unified_cmd_send cmd. WMI internally frees cmd buffer after + * getting TX complete from CE + */ + vdev_id = cmd->vdev_id; + scan_id = cmd->scan_id; + WMA_LOGI("ActiveDwell %d, PassiveDwell %d, ScanFlags 0x%x NumChan %d", + cmd->dwell_time_active, cmd->dwell_time_passive, + cmd->scan_ctrl_flags, cmd->num_chan); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_START_SCAN_CMDID); + /* Call the wmi api to request the scan */ + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("WMA --> WMI_START_SCAN_CMDID"); + + return CDF_STATUS_SUCCESS; +error: + /* Send completion event for only for start scan request */ + if (msg_type == WMA_START_SCAN_OFFLOAD_REQ) { + scan_event = + (tSirScanOffloadEvent *) + cdf_mem_malloc(sizeof(tSirScanOffloadEvent)); + if (!scan_event) { + WMA_LOGP("%s: Failed to allocate memory for scan rsp", + __func__); + return CDF_STATUS_E_NOMEM; + } + memset(scan_event, 0x00, sizeof(*scan_event)); + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + scan_event->sessionId = scan_req->sessionId; + scan_event->p2pScanType = scan_req->p2pScanType; + scan_event->scanId = scan_req->scan_id; + wma_send_msg(wma_handle, WMA_RX_SCAN_EVENT, (void *)scan_event, + 0); + } + return cdf_status; +} + +/** + * wma_stop_scan() - stop scan command + * @wma_handle: wma handle + * @abort_scan_req: abort scan params + * + * Send stop scan command to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_stop_scan(tp_wma_handle wma_handle, + tAbortScanParams *abort_scan_req) +{ + CDF_STATUS cdf_status; + wmi_buf_t buf; + int status = 0; + int len; + + cdf_status = wma_get_buf_stop_scan_cmd(wma_handle, &buf, &len, + abort_scan_req); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get buffer for stop scan cmd"); + goto error1; + } + + if (NULL == buf) { + WMA_LOGE("Failed to get buffer for stop scan cmd"); + cdf_status = CDF_STATUS_E_FAULT; + goto error1; + } + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_STOP_SCAN_CMDID); + /* Call the wmi api to request the scan */ + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_STOP_SCAN_CMDID returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + WMA_LOGE("scan_id %x, vdev_id %x", + abort_scan_req->scan_id, abort_scan_req->SessionId); + WMA_LOGI("WMA --> WMI_STOP_SCAN_CMDID"); + + return CDF_STATUS_SUCCESS; +error: + if (buf) + cdf_nbuf_free(buf); +error1: + return cdf_status; +} + +/** + * wma_update_channel_list() - update channel list + * @handle: wma handle + * @chan_list: channel list + * + * Function is used to update the support channel list in fw. + * + * Return: CDF status + */ +CDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_buf_t buf; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_scan_chan_list_cmd_fixed_param *cmd; + int status, i; + uint8_t *buf_ptr; + wmi_channel *chan_info; + uint16_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + + len += sizeof(wmi_channel) * chan_list->numChan; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("Failed to allocate memory"); + cdf_status = CDF_STATUS_E_NOMEM; + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_scan_chan_list_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_chan_list_cmd_fixed_param)); + + WMA_LOGD("no of channels = %d, len = %d", chan_list->numChan, len); + + cmd->num_scan_chans = chan_list->numChan; + WMITLV_SET_HDR((buf_ptr + sizeof(wmi_scan_chan_list_cmd_fixed_param)), + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_channel) * chan_list->numChan); + chan_info = (wmi_channel *) (buf_ptr + sizeof(*cmd) + WMI_TLV_HDR_SIZE); + + for (i = 0; i < chan_list->numChan; ++i) { + WMITLV_SET_HDR(&chan_info->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan_info->mhz = + cds_chan_to_freq(chan_list->chanParam[i].chanId); + chan_info->band_center_freq1 = chan_info->mhz; + chan_info->band_center_freq2 = 0; + + WMA_LOGD("chan[%d] = %u", i, chan_info->mhz); + if (chan_list->chanParam[i].dfsSet) { + WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE); + WMA_LOGI("chan[%d] DFS[%d]\n", + chan_list->chanParam[i].chanId, + chan_list->chanParam[i].dfsSet); + } + + if (chan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) + WMI_SET_CHANNEL_MODE(chan_info, MODE_11G); + else + WMI_SET_CHANNEL_MODE(chan_info, MODE_11A); + + if (chan_list->chanParam[i].half_rate) + WMI_SET_CHANNEL_FLAG(chan_info, + WMI_CHAN_FLAG_HALF_RATE); + else if (chan_list->chanParam[i].quarter_rate) + WMI_SET_CHANNEL_FLAG(chan_info, + WMI_CHAN_FLAG_QUARTER_RATE); + + WMI_SET_CHANNEL_MAX_TX_POWER(chan_info, + chan_list->chanParam[i].pwr); + + WMI_SET_CHANNEL_REG_POWER(chan_info, + chan_list->chanParam[i].pwr); + WMA_LOGD("Channel TX power[%d] = %u: %d", i, chan_info->mhz, + chan_list->chanParam[i].pwr); + /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ + /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ + /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ + chan_info++; + } + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_SCAN_CHAN_LIST_CMDID); + + if (status != EOK) { + cdf_status = CDF_STATUS_E_FAILURE; + WMA_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + wmi_buf_free(buf); + } +end: + return cdf_status; +} + + +/** + * wma_roam_scan_offload_mode() - send roam scan mode request to fw + * @wma_handle: wma handle + * @scan_cmd_fp: start scan command ptr + * @roam_req: roam request param + * @mode: mode + * @vdev_id: vdev id + * + * send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback + * of WMI_ROAM_SCAN_MODE. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_mode_fixed_param *roam_scan_mode_fp; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + int auth_mode = WMI_AUTH_NONE; + wmi_roam_offload_tlv_param *roam_offload_params; + wmi_roam_11i_offload_tlv_param *roam_offload_11i; + wmi_roam_11r_offload_tlv_param *roam_offload_11r; + wmi_roam_ese_offload_tlv_param *roam_offload_ese; + if (roam_req) + auth_mode = e_csr_auth_type_to_rsn_authmode + (roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + WMA_LOGD("%s : auth mode = %d", __func__, auth_mode); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + /* Need to create a buf with roam_scan command at + * front and piggyback with scan command */ + len = sizeof(wmi_roam_scan_mode_fixed_param) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + (2 * WMI_TLV_HDR_SIZE) + +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + sizeof(wmi_start_scan_cmd_fixed_param); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_req && roam_req->RoamOffloadEnabled) { + len += sizeof(wmi_roam_offload_tlv_param); + len += WMI_TLV_HDR_SIZE; + if ((auth_mode != WMI_AUTH_NONE) && + ((auth_mode != WMI_AUTH_OPEN) || + (auth_mode == WMI_AUTH_OPEN && + roam_req->MDID.mdiePresent) || roam_req->IsESEAssoc)) { + len += WMI_TLV_HDR_SIZE; + if (roam_req->IsESEAssoc) + len += sizeof(wmi_roam_ese_offload_tlv_param); + else if (auth_mode == WMI_AUTH_FT_RSNA || + auth_mode == WMI_AUTH_FT_RSNA_PSK || + (auth_mode == WMI_AUTH_OPEN && + roam_req->MDID.mdiePresent)) + len += sizeof(wmi_roam_11r_offload_tlv_param); + else + len += sizeof(wmi_roam_11i_offload_tlv_param); + } else { + len += WMI_TLV_HDR_SIZE; + } + } else { + if (roam_req) + WMA_LOGD("%s : roam offload = %d", + __func__, roam_req->RoamOffloadEnabled); + else + WMA_LOGD("%s : roam_req is NULL", __func__); + len += (2 * WMI_TLV_HDR_SIZE); + } + if (roam_req && roam_req->RoamOffloadEnabled) { + mode = mode | WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + roam_scan_mode_fp = (wmi_roam_scan_mode_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_scan_mode_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_mode_fixed_param)); + + roam_scan_mode_fp->roam_scan_mode = mode; + roam_scan_mode_fp->vdev_id = vdev_id; + /* Fill in scan parameters suitable for roaming scan */ + buf_ptr += sizeof(wmi_roam_scan_mode_fixed_param); + cdf_mem_copy(buf_ptr, scan_cmd_fp, + sizeof(wmi_start_scan_cmd_fixed_param)); + /* Ensure there is no additional IEs */ + scan_cmd_fp->ie_len = 0; + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_scan_cmd_fixed_param)); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + buf_ptr += sizeof(wmi_start_scan_cmd_fixed_param); + if (roam_req && roam_req->RoamOffloadEnabled) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_params = (wmi_roam_offload_tlv_param *) buf_ptr; + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_offload_tlv_param)); + roam_offload_params->prefer_5g = roam_req->Prefer5GHz; + roam_offload_params->rssi_cat_gap = roam_req->RoamRssiCatGap; + roam_offload_params->select_5g_margin = + roam_req->Select5GHzMargin; + roam_offload_params->reassoc_failure_timeout = + roam_req->ReassocFailureTimeout; + /* Fill the capabilities */ + wma_roam_scan_fill_self_caps(wma_handle, roam_offload_params, + roam_req); + buf_ptr += sizeof(wmi_roam_offload_tlv_param); + /* The TLV's are in the order of 11i, 11R, ESE. Hence, + * they are filled in the same order.Depending on the + * authentication type, the other mode TLV's are nullified + * and only headers are filled.*/ + if ((auth_mode != WMI_AUTH_NONE) && + ((auth_mode != WMI_AUTH_OPEN) || + (auth_mode == WMI_AUTH_OPEN + && roam_req->MDID.mdiePresent) || roam_req->IsESEAssoc)) { + if (roam_req->IsESEAssoc) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_ese_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_ese = + (wmi_roam_ese_offload_tlv_param *) buf_ptr; + cdf_mem_copy(roam_offload_ese->krk, + roam_req->KRK, + sizeof(roam_req->KRK)); + cdf_mem_copy(roam_offload_ese->btk, + roam_req->BTK, + sizeof(roam_req->BTK)); + WMITLV_SET_HDR(&roam_offload_ese->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_ese_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_ese_offload_tlv_param); + } else if (auth_mode == WMI_AUTH_FT_RSNA + || auth_mode == WMI_AUTH_FT_RSNA_PSK + || (auth_mode == WMI_AUTH_OPEN + && roam_req->MDID.mdiePresent)) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11r_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_11r = + (wmi_roam_11r_offload_tlv_param *) buf_ptr; + roam_offload_11r->r0kh_id_len = + roam_req->R0KH_ID_Length; + cdf_mem_copy(roam_offload_11r->r0kh_id, + roam_req->R0KH_ID, + roam_offload_11r->r0kh_id_len); + cdf_mem_copy(roam_offload_11r->psk_msk, + roam_req->PSK_PMK, + sizeof(roam_req->PSK_PMK)); + roam_offload_11r->psk_msk_len = + roam_req->pmk_len; + roam_offload_11r->mdie_present = + roam_req->MDID.mdiePresent; + roam_offload_11r->mdid = + roam_req->MDID.mobilityDomain; + if (auth_mode == WMI_AUTH_OPEN) { + /* If FT-Open ensure pmk length + and r0khid len are zero */ + roam_offload_11r->r0kh_id_len = 0; + roam_offload_11r->psk_msk_len = 0; + } + WMITLV_SET_HDR(&roam_offload_11r->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_11r_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_11r_offload_tlv_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11i_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_11i = + (wmi_roam_11i_offload_tlv_param *) buf_ptr; + if (roam_req->RoamKeyMgmtOffloadEnabled) { + WMI_SET_ROAM_OFFLOAD_OKC_ENABLED + (roam_offload_11i->flags); + WMA_LOGE("LFR3:OKC Enabled"); + } else { + WMI_SET_ROAM_OFFLOAD_OKC_DISABLED + (roam_offload_11i->flags); + WMA_LOGE("LFR3:OKC Disabled"); + } + + cdf_mem_copy(roam_offload_11i->pmk, + roam_req->PSK_PMK, + sizeof(roam_req->PSK_PMK)); + roam_offload_11i->pmk_len = roam_req->pmk_len; + WMITLV_SET_HDR(&roam_offload_11i->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_11i_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_11i_offload_tlv_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + } + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + } + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_SCAN_MODE); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_MODE returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_roam_scan_offload_rssi_threshold() - set scan offload rssi threashold + * @wma_handle: wma handle + * @roam_req: Roaming request buffer + * + * Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len, rssi_thresh, rssi_thresh_diff; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_threshold_fixed_param *rssi_threshold_fp; + wmi_roam_scan_extended_threshold_param *ext_thresholds = NULL; + struct roam_ext_params *roam_params; + int32_t good_rssi_threshold; + uint32_t hirssi_scan_max_count; + uint32_t hirssi_scan_delta; + int32_t hirssi_upper_bound; + + /* Send rssi threshold */ + roam_params = &roam_req->roam_params; + rssi_thresh = roam_req->LookupThreshold - WMA_NOISE_FLOOR_DBM_DEFAULT; + rssi_thresh_diff = roam_req->OpportunisticScanThresholdDiff; + hirssi_scan_max_count = roam_req->hi_rssi_scan_max_count; + hirssi_scan_delta = roam_req->hi_rssi_scan_rssi_delta; + hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub - + WMA_NOISE_FLOOR_DBM_DEFAULT; + len = sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/ + len += sizeof(wmi_roam_scan_extended_threshold_param); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + rssi_threshold_fp = + (wmi_roam_scan_rssi_threshold_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&rssi_threshold_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_threshold_fixed_param)); + /* fill in threshold values */ + rssi_threshold_fp->vdev_id = roam_req->sessionId; + rssi_threshold_fp->roam_scan_rssi_thresh = rssi_thresh & 0x000000ff; + rssi_threshold_fp->roam_rssi_thresh_diff = + rssi_thresh_diff & 0x000000ff; + rssi_threshold_fp->hirssi_scan_max_count = hirssi_scan_max_count; + rssi_threshold_fp->hirssi_scan_delta = hirssi_scan_delta; + rssi_threshold_fp->hirssi_upper_bound = hirssi_upper_bound & 0x00000ff; + + buf_ptr += sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_scan_extended_threshold_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + ext_thresholds = (wmi_roam_scan_extended_threshold_param *) buf_ptr; + /* + * The current Noise floor in firmware is -96dBm. Penalty/Boost + * threshold is applied on a weaker signal to make it even more weaker. + * So, there is a chance that the user may configure a very low + * Penalty/Boost threshold beyond the noise floor. If that is the case, + * then suppress the penalty/boost threshold to the noise floor. + */ + if (roam_params->raise_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + ext_thresholds->penalty_threshold_5g = 0; + else + ext_thresholds->boost_threshold_5g = + (roam_params->raise_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + if (roam_params->drop_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + ext_thresholds->penalty_threshold_5g = 0; + else + ext_thresholds->penalty_threshold_5g = + (roam_params->drop_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + ext_thresholds->boost_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->boost_factor_5g = roam_params->raise_factor_5g; + ext_thresholds->penalty_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->penalty_factor_5g = roam_params->drop_factor_5g; + ext_thresholds->max_boost_5g = roam_params->max_raise_rssi_5g; + ext_thresholds->max_penalty_5g = roam_params->max_drop_rssi_5g; + + if (roam_params->good_rssi_roam) + good_rssi_threshold = WMA_NOISE_FLOOR_DBM_DEFAULT; + else + good_rssi_threshold = 0; + ext_thresholds->good_rssi_threshold = + (good_rssi_threshold - WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + + WMA_LOGD("WMA --> good_rssi_threshold=%d", + ext_thresholds->good_rssi_threshold); + + WMITLV_SET_HDR(&ext_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_extended_threshold_param)); + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_SCAN_RSSI_THRESHOLD); + if (status != EOK) { + WMA_LOGE("cmd WMI_ROAM_SCAN_RSSI_THRESHOLD returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI(FL("roam_scan_rssi_thresh=%d, roam_rssi_thresh_diff=%d"), + rssi_thresh, rssi_thresh_diff); + WMA_LOGI( + FL("hirssi_scan max_count=%d, delta=%d, hirssi_upper_bound=%d"), + hirssi_scan_max_count, hirssi_scan_delta, hirssi_upper_bound); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_roam_scan_offload_scan_period() - set roam offload scan period + * @wma_handle: wma handle + * @scan_period: scan period + * @scan_age: scan age + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_period_fixed_param *scan_period_fp; + + /* Send scan period values */ + len = sizeof(wmi_roam_scan_period_fixed_param); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + scan_period_fp = (wmi_roam_scan_period_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&scan_period_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_period_fixed_param)); + /* fill in scan period values */ + scan_period_fp->vdev_id = vdev_id; + scan_period_fp->roam_scan_period = scan_period; /* 20 seconds */ + scan_period_fp->roam_scan_age = scan_age; + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_SCAN_PERIOD); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_PERIOD returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_PERIOD roam_scan_period=%d, roam_scan_age=%d", + __func__, scan_period, scan_age); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_roam_scan_offload_rssi_change() - set roam offload RSSI change threshold + * @wma_handle: wma handle + * @rssi_change_thresh: RSSI Change threshold + * @bcn_rssi_weight: beacon RSSI weight + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_change_threshold_fixed_param *rssi_change_fp; + + /* Send rssi change parameters */ + len = sizeof(wmi_roam_scan_rssi_change_threshold_fixed_param); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + rssi_change_fp = + (wmi_roam_scan_rssi_change_threshold_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&rssi_change_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_change_threshold_fixed_param)); + /* fill in rssi change threshold (hysteresis) values */ + rssi_change_fp->vdev_id = vdev_id; + rssi_change_fp->roam_scan_rssi_change_thresh = rssi_change_thresh; + rssi_change_fp->bcn_rssi_weight = bcn_rssi_weight; + rssi_change_fp->hirssi_delay_btw_scans = hirssi_delay_btw_scans; + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI(FL("roam_scan_rssi_change_thresh=%d, bcn_rssi_weight=%d"), + rssi_change_thresh, bcn_rssi_weight); + WMA_LOGI(FL("hirssi_delay_btw_scans=%d"), hirssi_delay_btw_scans); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_roam_scan_offload_chan_list() - set roam offload channel list + * @wma_handle: wma handle + * @chan_count: channel count + * @chan_list: channel list + * @list_type: list type + * @vdev_id: vdev id + * + * Set roam offload channel list. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len, list_tlv_len; + int i; + uint8_t *buf_ptr; + wmi_roam_chan_list_fixed_param *chan_list_fp; + A_UINT32 *roam_chan_list_array; + + if (chan_count == 0) { + WMA_LOGD("%s : invalid number of channels %d", __func__, + chan_count); + return CDF_STATUS_E_EMPTY; + } + /* Channel list is a table of 2 TLV's */ + list_tlv_len = WMI_TLV_HDR_SIZE + chan_count * sizeof(A_UINT32); + len = sizeof(wmi_roam_chan_list_fixed_param) + list_tlv_len; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + chan_list_fp = (wmi_roam_chan_list_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&chan_list_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_chan_list_fixed_param)); + chan_list_fp->vdev_id = vdev_id; + chan_list_fp->num_chan = chan_count; + if (chan_count > 0 && list_type == CHANNEL_LIST_STATIC) { + /* external app is controlling channel list */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC; + } else { + /* umac supplied occupied channel list in LFR */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC; + } + + buf_ptr += sizeof(wmi_roam_chan_list_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (chan_list_fp->num_chan * sizeof(uint32_t))); + roam_chan_list_array = (A_UINT32 *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMA_LOGI("%s: %d channels = ", __func__, chan_list_fp->num_chan); + for (i = 0; ((i < chan_list_fp->num_chan) && + (i < SIR_ROAM_MAX_CHANNELS)); i++) { + roam_chan_list_array[i] = cds_chan_to_freq(chan_list[i]); + WMA_LOGI("%d,", roam_chan_list_array[i]); + } + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_CHAN_LIST); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_CHAN_LIST returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_CHAN_LIST", __func__); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * e_csr_auth_type_to_rsn_authmode() - map csr auth type to rsn authmode + * @authtype: CSR authtype + * @encr: CSR Encryption + * + * Map CSR's authentication type into RSN auth mode used by firmware + * + * Return: WMI RSN auth mode + */ +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr) +{ + switch (authtype) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + return WMI_AUTH_OPEN; + case eCSR_AUTH_TYPE_WPA: + return WMI_AUTH_WPA; + case eCSR_AUTH_TYPE_WPA_PSK: + return WMI_AUTH_WPA_PSK; + case eCSR_AUTH_TYPE_RSN: + return WMI_AUTH_RSNA; + case eCSR_AUTH_TYPE_RSN_PSK: + return WMI_AUTH_RSNA_PSK; +#if defined WLAN_FEATURE_VOWIFI_11R + case eCSR_AUTH_TYPE_FT_RSN: + return WMI_AUTH_FT_RSNA; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + return WMI_AUTH_FT_RSNA_PSK; +#endif /* WLAN_FEATURE_VOWIFI_11R */ +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return WMI_AUTH_WAPI; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return WMI_AUTH_WAPI_PSK; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: + return WMI_AUTH_CCKM; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + return WMI_AUTH_RSNA_PSK_SHA256; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + return WMI_AUTH_RSNA_8021X_SHA256; +#endif /* WLAN_FEATURE_11W */ + case eCSR_AUTH_TYPE_NONE: + case eCSR_AUTH_TYPE_AUTOSWITCH: + /* In case of WEP and other keys, NONE means OPEN auth */ + if (encr == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP40 || + encr == eCSR_ENCRYPT_TYPE_WEP104 || + encr == eCSR_ENCRYPT_TYPE_TKIP || + encr == eCSR_ENCRYPT_TYPE_AES) { + return WMI_AUTH_OPEN; + } + return WMI_AUTH_NONE; + default: + return WMI_AUTH_NONE; + } +} + +/** + * e_csr_encryption_type_to_rsn_cipherset() - map csr enc type to ESN cipher + * @encr: CSR Encryption + * + * Map CSR's encryption type into RSN cipher types used by firmware + * + * Return: WMI RSN cipher + */ +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr) +{ + + switch (encr) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + return WMI_CIPHER_WEP; + case eCSR_ENCRYPT_TYPE_TKIP: + return WMI_CIPHER_TKIP; + case eCSR_ENCRYPT_TYPE_AES: + return WMI_CIPHER_AES_CCM; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + return WMI_CIPHER_WAPI; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + return WMI_CIPHER_ANY; + case eCSR_ENCRYPT_TYPE_NONE: + default: + return WMI_CIPHER_NONE; + } +} + +/** + * wma_roam_scan_fill_ap_profile() - fill ap_profile + * @wma_handle: wma handle + * @pMac: Mac ptr + * @roam_req: roam offload scan request + * @ap_profile_p: ap profile + * + * Fill ap_profile structure from configured parameters + * + * Return: none + */ +void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_ap_profile *ap_profile_p) +{ + cdf_mem_zero(ap_profile_p, sizeof(wmi_ap_profile)); + if (roam_req == NULL) { + ap_profile_p->ssid.ssid_len = 0; + ap_profile_p->ssid.ssid[0] = 0; + ap_profile_p->rsn_authmode = WMI_AUTH_NONE; + ap_profile_p->rsn_ucastcipherset = WMI_CIPHER_NONE; + ap_profile_p->rsn_mcastcipherset = WMI_CIPHER_NONE; + ap_profile_p->rsn_mcastmgmtcipherset = WMI_CIPHER_NONE; + ap_profile_p->rssi_threshold = WMA_ROAM_RSSI_DIFF_DEFAULT; + } else { + ap_profile_p->ssid.ssid_len = + roam_req->ConnectedNetwork.ssId.length; + cdf_mem_copy(ap_profile_p->ssid.ssid, + roam_req->ConnectedNetwork.ssId.ssId, + ap_profile_p->ssid.ssid_len); + ap_profile_p->rsn_authmode = + e_csr_auth_type_to_rsn_authmode(roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + ap_profile_p->rsn_ucastcipherset = + e_csr_encryption_type_to_rsn_cipherset(roam_req->ConnectedNetwork.encryption); + ap_profile_p->rsn_mcastcipherset = + e_csr_encryption_type_to_rsn_cipherset(roam_req->ConnectedNetwork.mcencryption); + ap_profile_p->rsn_mcastmgmtcipherset = + ap_profile_p->rsn_mcastcipherset; + ap_profile_p->rssi_threshold = roam_req->RoamRssiDiff; +#ifdef WLAN_FEATURE_11W + if (roam_req->ConnectedNetwork.mfp_enabled) + ap_profile_p->flags |= WMI_AP_PROFILE_FLAG_PMF; +#endif + } +} + +/** + * wma_roam_scan_scan_params() - fill roam scan params + * @wma_handle: wma handle + * @pMac: Mac ptr + * @scan_params: scan parameters + * @roam_req: NULL if this routine is called before connect + * It will be non-NULL if called after assoc. + * + * Fill scan_params structure from configured parameters + * + * Return: none + */ +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params) +{ + uint8_t channels_per_burst = 0; + uint32_t val = 0; + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + return; + } + + cdf_mem_zero(scan_params, sizeof(wmi_start_scan_cmd_fixed_param)); + scan_params->scan_ctrl_flags = WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES; + if (roam_req != NULL) { + /* Parameters updated after association is complete */ + WMA_LOGI("%s: Input parameters: NeighborScanChannelMinTime" + " = %d, NeighborScanChannelMaxTime = %d", + __func__, + roam_req->NeighborScanChannelMinTime, + roam_req->NeighborScanChannelMaxTime); + WMA_LOGI("%s: Input parameters: NeighborScanTimerPeriod =" + " %d, HomeAwayTime = %d, nProbes = %d", + __func__, + roam_req->NeighborScanTimerPeriod, + roam_req->HomeAwayTime, roam_req->nProbes); + + /* + * roam_req->NeighborScanChannelMaxTime = SCAN_CHANNEL_TIME + * roam_req->HomeAwayTime = SCAN_HOME_AWAY_TIME + * roam_req->NeighborScanTimerPeriod = SCAN_HOME_TIME + * + * scan_params->dwell_time_active = time station stays on channel + * and sends probes; + * scan_params->dwell_time_passive = time station stays on channel + * and listens probes; + * scan_params->burst_duration = time station goes off channel + * to scan; + */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + &val) != eSIR_SUCCESS) { + /* + * Could not get max channel value from CFG. Log error. + */ + WMA_LOGE + ("could not retrieve passive max channel value"); + + /* use a default value of 110ms */ + val = WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + } + + scan_params->dwell_time_passive = val; + /* + * Here is the formula, + * T(HomeAway) = N * T(dwell) + (N+1) * T(cs) + * where N is number of channels scanned in single burst + */ + scan_params->dwell_time_active = + roam_req->NeighborScanChannelMaxTime; + if (roam_req->HomeAwayTime < + 2 * WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) { + /* clearly we can't follow home away time. + * Make it a split scan. + */ + scan_params->burst_duration = 0; + } else { + channels_per_burst = + (roam_req->HomeAwayTime - + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) + / (scan_params->dwell_time_active + + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME); + + if (channels_per_burst < 1) { + /* dwell time and home away time conflicts */ + /* we will override dwell time */ + scan_params->dwell_time_active = + roam_req->HomeAwayTime - + 2 * WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME; + scan_params->burst_duration = + scan_params->dwell_time_active; + } else { + scan_params->burst_duration = + channels_per_burst * + scan_params->dwell_time_active; + } + } + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL + && roam_req->HomeAwayTime > 0 + && roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) { + /* Roaming on DFS channels is supported and it is not + * app channel list. It is ok to override homeAwayTime + * to accomodate DFS dwell time in burst + * duration. + */ + scan_params->burst_duration = + CDF_MAX(scan_params->burst_duration, + scan_params->dwell_time_passive); + } + scan_params->min_rest_time = roam_req->NeighborScanTimerPeriod; + scan_params->max_rest_time = roam_req->NeighborScanTimerPeriod; + scan_params->repeat_probe_time = (roam_req->nProbes > 0) ? + CDF_MAX(scan_params->dwell_time_active / roam_req->nProbes, + 1) : 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + /* 30 seconds for full scan cycle */ + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->n_probes = roam_req->nProbes; + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_DISABLED) { + scan_params->scan_ctrl_flags |= WMI_SCAN_BYPASS_DFS_CHN; + } else { + /* Roaming scan on DFS channel is allowed. + * No need to change any flags for default + * allowDFSChannelRoam = 1. + * Special case where static channel list is given by\ + * application that contains DFS channels. + * Assume that the application has knowledge of matching + * APs being active and that probe request transmission + * is permitted on those channel. + * Force active scans on those channels. + */ + + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE && + roam_req->ChannelCacheType == CHANNEL_LIST_STATIC && + roam_req->ConnectedNetwork.ChannelCount > 0) { + scan_params->scan_ctrl_flags |= + WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS; + } + } + } else { + /* roam_req = NULL during initial or pre-assoc invocation */ + scan_params->dwell_time_active = + WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT; + scan_params->dwell_time_passive = + WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + scan_params->min_rest_time = WMA_ROAM_MIN_REST_TIME_DEFAULT; + scan_params->max_rest_time = WMA_ROAM_MAX_REST_TIME_DEFAULT; + scan_params->repeat_probe_time = 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->burst_duration = 0; + scan_params->n_probes = 0; + } + + WMA_LOGI("%s: Rome roam scan parameters:" + " dwell_time_active = %d, dwell_time_passive = %d", + __func__, + scan_params->dwell_time_active, + scan_params->dwell_time_passive); + WMA_LOGI("%s: min_rest_time = %d, max_rest_time = %d," + " repeat_probe_time = %d n_probes = %d", + __func__, + scan_params->min_rest_time, + scan_params->max_rest_time, + scan_params->repeat_probe_time, scan_params->n_probes); + WMA_LOGI("%s: max_scan_time = %d, idle_time = %d," + " burst_duration = %d, scan_ctrl_flags = 0x%x", + __func__, + scan_params->max_scan_time, + scan_params->idle_time, + scan_params->burst_duration, scan_params->scan_ctrl_flags); +} + +/** + * wma_roam_scan_offload_ap_profile() - set roam ap profile in fw + * @wma_handle: wma handle + * @ap_profile_p: ap profile + * @vdev_id: vdev id + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf = NULL; + int status = 0; + int len; + uint8_t *buf_ptr; + wmi_roam_ap_profile_fixed_param *roam_ap_profile_fp; + + len = sizeof(wmi_roam_ap_profile_fixed_param) + sizeof(wmi_ap_profile); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + roam_ap_profile_fp = (wmi_roam_ap_profile_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_ap_profile_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_ap_profile_fixed_param)); + /* fill in threshold values */ + roam_ap_profile_fp->vdev_id = vdev_id; + roam_ap_profile_fp->id = 0; + buf_ptr += sizeof(wmi_roam_ap_profile_fixed_param); + + cdf_mem_copy(buf_ptr, ap_profile_p, sizeof(wmi_ap_profile)); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_ap_profile, + WMITLV_GET_STRUCT_TLVLEN(wmi_ap_profile)); + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_AP_PROFILE); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_AP_PROFILE returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("WMA --> WMI_ROAM_AP_PROFILE and other parameters"); + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_roam_scan_filter() - Filter to be applied while roaming + * @wma_handle: Global WMA Handle + * @roam_req: Request which contains the filters + * + * There are filters such as whitelist, blacklist and preferred + * list that need to be applied to the scan results to form the + * probable candidates for roaming. + * + * Return: Return success upon succesfully passing the + * parameters to the firmware, otherwise failure. + */ +CDF_STATUS wma_roam_scan_filter(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + wmi_buf_t buf = NULL; + int status = 0, i; + uint32_t len, num_bssid_black_list = 0, num_ssid_white_list = 0, + num_bssid_preferred_list = 0; + uint32_t op_bitmap = 0; + uint8_t *buf_ptr; + wmi_roam_filter_fixed_param *roam_filter; + uint8_t *bssid_src_ptr = NULL; + wmi_mac_addr *bssid_dst_ptr = NULL; + wmi_ssid *ssid_ptr = NULL; + uint32_t *bssid_preferred_factor_ptr = NULL; + struct roam_ext_params *roam_params; + + roam_params = &roam_req->roam_params; + len = sizeof(wmi_roam_filter_fixed_param); + len += WMI_TLV_HDR_SIZE; + if (roam_req->Command != ROAM_SCAN_OFFLOAD_STOP) { + switch (roam_req->reason) { + case REASON_ROAM_SET_BLACKLIST_BSSID: + op_bitmap |= 0x1; + num_bssid_black_list = + roam_params->num_bssid_avoid_list; + len += num_bssid_black_list * sizeof(wmi_mac_addr); + len += WMI_TLV_HDR_SIZE; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + op_bitmap |= 0x2; + num_ssid_white_list = + roam_params->num_ssid_allowed_list; + len += num_ssid_white_list * sizeof(wmi_ssid); + len += WMI_TLV_HDR_SIZE; + break; + case REASON_ROAM_SET_FAVORED_BSSID: + op_bitmap |= 0x4; + num_bssid_preferred_list = + roam_params->num_bssid_favored; + len += num_bssid_preferred_list * sizeof(wmi_mac_addr); + len += WMI_TLV_HDR_SIZE; + len += num_bssid_preferred_list * sizeof(A_UINT32); + break; + default: + WMA_LOGD("%s : Roam Filter need not be sent", __func__); + return CDF_STATUS_SUCCESS; + break; + } + } else { + /* In case of STOP command, reset all the variables + * except for blacklist BSSID which should be retained + * across connections.*/ + op_bitmap = 0x2 | 0x4; + num_ssid_white_list = roam_params->num_ssid_allowed_list; + len += num_ssid_white_list * sizeof(wmi_ssid); + num_bssid_preferred_list = roam_params->num_bssid_favored; + len += num_bssid_preferred_list * sizeof(wmi_mac_addr); + len += num_bssid_preferred_list * sizeof(A_UINT32); + len += (2 * WMI_TLV_HDR_SIZE); + } + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + roam_filter = (wmi_roam_filter_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_filter->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_filter_fixed_param)); + /* fill in fixed values */ + roam_filter->vdev_id = roam_req->sessionId; + roam_filter->flags = 0; + roam_filter->op_bitmap = op_bitmap; + roam_filter->num_bssid_black_list = num_bssid_black_list; + roam_filter->num_ssid_white_list = num_ssid_white_list; + roam_filter->num_bssid_preferred_list = num_bssid_preferred_list; + buf_ptr += sizeof(wmi_roam_filter_fixed_param); + + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (num_bssid_black_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_params->bssid_avoid_list; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < num_bssid_black_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (num_bssid_black_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (num_ssid_white_list * sizeof(wmi_ssid))); + ssid_ptr = (wmi_ssid *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < num_ssid_white_list; i++) { + memcpy(&ssid_ptr->ssid, &roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + ssid_ptr->ssid_len = roam_params->ssid_allowed_list[i].length; + WMA_LOGD("%s: SSID length=%d", __func__, ssid_ptr->ssid_len); + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_DEBUG, + (uint8_t *)ssid_ptr->ssid, + ssid_ptr->ssid_len); + ssid_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid_white_list * sizeof(wmi_ssid)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (num_bssid_preferred_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_params->bssid_favored; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < num_bssid_preferred_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, + (wmi_mac_addr *)bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (num_bssid_preferred_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (num_bssid_preferred_list * sizeof(uint32_t))); + bssid_preferred_factor_ptr = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < num_bssid_preferred_list; i++) { + *bssid_preferred_factor_ptr = + roam_params->bssid_favored_factor[i]; + bssid_preferred_factor_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (num_bssid_preferred_list * sizeof(uint32_t)); + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_FILTER_CMDID); + if (status != EOK) { + WMA_LOGE("cmd WMI_ROAM_FILTER_CMDID returned Error %d", + status); + goto error; + } + return CDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; +} + +/** + * wma_roam_scan_bmiss_cnt() - set bmiss count to fw + * @wma_handle: wma handle + * @first_bcnt: first bmiss count + * @final_bcnt: final bmiss count + * @vdev_id: vdev id + * + * set first & final biss count to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id) +{ + int status = 0; + + WMA_LOGI("%s: first_bcnt=%d, final_bcnt=%d", __func__, first_bcnt, + final_bcnt); + + status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_BMISS_FIRST_BCNT, + first_bcnt); + if (status != EOK) { + WMA_LOGE("wmi_unified_vdev_set_param_send WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d", + status); + return CDF_STATUS_E_FAILURE; + } + + status = wmi_unified_vdev_set_param_send(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_BMISS_FINAL_BCNT, + final_bcnt); + if (status != EOK) { + WMA_LOGE("wmi_unified_vdev_set_param_send WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d", + status); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_roam_scan_offload_command() - set roam offload command + * @wma_handle: wma handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id) +{ + CDF_STATUS cdf_status; + wmi_roam_scan_cmd_fixed_param *cmd_fp; + wmi_buf_t buf = NULL; + int status = 0; + int len; + uint8_t *buf_ptr; + + len = sizeof(wmi_roam_scan_cmd_fixed_param); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + cmd_fp = (wmi_roam_scan_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_cmd_fixed_param)); + cmd_fp->vdev_id = vdev_id; + cmd_fp->command_arg = command; + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + len, WMI_ROAM_SCAN_CMD); + if (status != EOK) { + WMA_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_CMD returned Error %d", + status); + cdf_status = CDF_STATUS_E_FAILURE; + goto error; + } + + WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_CMD", __func__); + return CDF_STATUS_SUCCESS; + +error: + wmi_buf_free(buf); + + return cdf_status; +} + +/** + * wma_process_roam_scan_req() - process roam request + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * Main routine to handle ROAM commands coming from CSR module. + * + * Return: CDF status + */ +CDF_STATUS wma_process_roam_scan_req(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_start_scan_cmd_fixed_param scan_params; + wmi_ap_profile ap_profile; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + uint32_t mode = 0; + struct wma_txrx_node *intr = NULL; + + WMA_LOGI("%s: command 0x%x, reason %d", __func__, roam_req->Command, + roam_req->reason); + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (!wma_handle->roam_offload_enabled) { + /* roam scan offload is not enabled in firmware. + * Cannot initialize it in the middle of connection. + */ + cdf_mem_free(roam_req); + return CDF_STATUS_E_PERM; + } + switch (roam_req->Command) { + case ROAM_SCAN_OFFLOAD_START: + intr = &wma_handle->interfaces[roam_req->sessionId]; + intr->delay_before_vdev_stop = roam_req->delay_before_vdev_stop; + /* + * Scan/Roam threshold parameters are translated from fields of + * tSirRoamOffloadScanReq to WMITLV values sent to Rome firmware. + * some of these parameters are configurable in qcom_cfg.ini file. + */ + + /* First parameter is positive rssi value to trigger rssi based scan. + * Opportunistic scan is started at 30 dB higher that trigger rssi. + */ + wma_handle->suitable_ap_hb_failure = false; + + cdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + cdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + /* Opportunistic scan runs on a timer, value set by + * EmptyRefreshScanPeriod. Age out the entries after 3 such + * cycles. + */ + if (roam_req->EmptyRefreshScanPeriod > 0) { + cdf_status = + wma_roam_scan_offload_scan_period(wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + /* Start new rssi triggered scan only if it changes by RoamRssiDiff value. + * Beacon weight of 14 means average rssi is taken over 14 previous samples + + * 2 times the current beacon's rssi. + */ + cdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, + &ap_profile); + + cdf_status = wma_roam_scan_offload_ap_profile(wma_handle, + &ap_profile, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + cdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + if ((cdf_status != CDF_STATUS_SUCCESS) && + (cdf_status != CDF_STATUS_E_EMPTY)) + break; + + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + cdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + cdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Sending start for roam scan filter failed"); + break; + } + break; + + case ROAM_SCAN_OFFLOAD_STOP: + wma_handle->suitable_ap_hb_failure = false; + if (wma_handle->roam_offload_enabled) { + + wma_roam_scan_fill_scan_params(wma_handle, pMac, + NULL, &scan_params); + cdf_status = wma_roam_scan_offload_mode(wma_handle, + &scan_params, + NULL, + WMI_ROAM_SCAN_MODE_NONE, + roam_req->sessionId); + } + /* + * If the STOP command is due to a disconnect, then + * send the filter command to clear all the filter + * entries. If it is roaming scenario, then do not + * send the cleared entries. + */ + if (!roam_req->middle_of_roaming) { + cdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("clear for roam scan filter failed"); + break; + } + } + + if (roam_req->reason == + REASON_OS_REQUESTED_ROAMING_NOW) { + cds_msg_t cds_msg; + tSirRoamOffloadScanRsp *scan_offload_rsp; + scan_offload_rsp = + cdf_mem_malloc(sizeof(*scan_offload_rsp)); + if (!scan_offload_rsp) { + WMA_LOGE("%s: Alloc failed for scan_offload_rsp", + __func__); + cdf_mem_free(roam_req); + return CDF_STATUS_E_NOMEM; + } + cds_msg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP; + scan_offload_rsp->sessionId = roam_req->sessionId; + scan_offload_rsp->reason = roam_req->reason; + cds_msg.bodyptr = scan_offload_rsp; + /* + * Since REASSOC request is processed in + * Roam_Scan_Offload_Rsp post a dummy rsp msg back to + * SME with proper reason code. + */ + if (CDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, + (cds_msg_t *) &cds_msg)) { + cdf_mem_free(scan_offload_rsp); + CDF_TRACE(CDF_MODULE_ID_WMA, + CDF_TRACE_LEVEL_INFO, + "%s: Failed to post Scan Offload Rsp to UMAC", + __func__); + } + } + break; + + case ROAM_SCAN_OFFLOAD_ABORT_SCAN: + /* If roam scan is running, stop that cycle. + * It will continue automatically on next trigger. + */ + cdf_status = wma_roam_scan_offload_command(wma_handle, + WMI_ROAM_SCAN_STOP_CMD, + roam_req->sessionId); + break; + + case ROAM_SCAN_OFFLOAD_RESTART: + /* Rome offload engine does not stop after any scan. + * If this command is sent because all preauth attempts failed + * and WMI_ROAM_REASON_SUITABLE_AP event was received earlier, + * now it is time to call it heartbeat failure. + */ + if ((roam_req->reason == REASON_PREAUTH_FAILED_FOR_ALL) + && wma_handle->suitable_ap_hb_failure) { + WMA_LOGE("%s: Sending heartbeat failure after preauth failures", + __func__); + wma_beacon_miss_handler(wma_handle, + roam_req->sessionId); + wma_handle->suitable_ap_hb_failure = false; + } + break; + + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + wma_handle->suitable_ap_hb_failure = false; + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + cdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, + WMI_ROAM_SCAN_MODE_NONE, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + if (roam_req->RoamScanOffloadEnabled == false) + break; + + cdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + cdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("Sending update for roam scan filter failed"); + break; + } + + + /* + * Runtime (after association) changes to rssi thresholds and + * other parameters. + */ + cdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + /* + * Even though the channel list is empty, we can + * still go ahead and start Roaming. + */ + if ((cdf_status != CDF_STATUS_SUCCESS) && + (cdf_status != CDF_STATUS_E_EMPTY)) + break; + + + cdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + if (roam_req->EmptyRefreshScanPeriod > 0) { + cdf_status = + wma_roam_scan_offload_scan_period(wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + cdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, + &ap_profile); + cdf_status = + wma_roam_scan_offload_ap_profile(wma_handle, &ap_profile, + roam_req->sessionId); + if (cdf_status != CDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + cdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + + break; + + default: + break; + } + cdf_mem_free(roam_req); + return cdf_status; +} + +/** + * wma_roam_preauth_chan_set() - set preauth channel + * @wma_handle: wma handle + * @params: switch channel params + * @vdev_id: vdev id + * + * Send a single channel passive scan request + * to handle set_channel operation for preauth + * + * Return: CDF atatus + */ +CDF_STATUS wma_roam_preauth_chan_set(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tSirScanOffloadReq scan_req; + uint8_t bssid[IEEE80211_ADDR_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + WMA_LOGI("%s: channel %d", __func__, params->channelNumber); + + /* Check for prior operation in progress */ + if (wma_handle->roam_preauth_chan_context != NULL) { + cdf_status = CDF_STATUS_E_FAILURE; + WMA_LOGE("%s: Rejected request. Previous operation in progress", + __func__); + goto send_resp; + } + wma_handle->roam_preauth_chan_context = params; + + /* Prepare a dummy scan request and get the + * wmi_start_scan_cmd_fixed_param structure filled properly + */ + cdf_mem_zero(&scan_req, sizeof(scan_req)); + cdf_copy_macaddr((struct cdf_mac_addr *) &scan_req.bssId, + (struct cdf_mac_addr *) bssid); + cdf_copy_macaddr((struct cdf_mac_addr *) &scan_req.selfMacAddr, + (struct cdf_mac_addr *) ¶ms->selfStaMacAddr); + scan_req.channelList.numChannels = 1; + scan_req.channelList.channelNumber[0] = params->channelNumber; + scan_req.numSsid = 0; + scan_req.minChannelTime = WMA_ROAM_PREAUTH_SCAN_TIME; + scan_req.maxChannelTime = WMA_ROAM_PREAUTH_SCAN_TIME; + scan_req.scanType = eSIR_PASSIVE_SCAN; + scan_req.p2pScanType = P2P_SCAN_TYPE_LISTEN; + scan_req.sessionId = vdev_id; + wma_get_scan_id(&scan_req.scan_id); + wma_handle->roam_preauth_chanfreq = + cds_chan_to_freq(params->channelNumber); + + /* set the state in advance before calling wma_start_scan and be ready + * to handle scan events from firmware. Otherwise print statments + * in wma_start_can create a race condition. + */ + wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_REQUESTED; + cdf_status = wma_start_scan(wma_handle, &scan_req, WMA_CHNL_SWITCH_REQ); + + if (cdf_status == CDF_STATUS_SUCCESS) + return cdf_status; + wma_handle->roam_preauth_scan_state = WMA_ROAM_PREAUTH_CHAN_NONE; + /* Failed operation. Safely clear context */ + wma_handle->roam_preauth_chan_context = NULL; + +send_resp: + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, cdf_status); + params->chainMask = wma_handle->pdevconfig.txchainmask; + params->smpsMode = SMPS_MODE_DISABLED; + params->status = cdf_status; + wma_send_msg(wma_handle, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); + return cdf_status; +} + +/** + * wma_roam_preauth_chan_cancel() - cancel preauth scan + * @wma_handle: wma handle + * @params: switch channel parameters + * @vdev_id: vdev id + * + * Return: CDF status + */ +CDF_STATUS wma_roam_preauth_chan_cancel(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id) +{ + tAbortScanParams abort_scan_req; + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + + WMA_LOGI("%s: channel %d", __func__, params->channelNumber); + /* Check for prior operation in progress */ + if (wma_handle->roam_preauth_chan_context != NULL) { + cdf_status = CDF_STATUS_E_FAILURE; + WMA_LOGE("%s: Rejected request. Previous operation in progress", + __func__); + goto send_resp; + } + wma_handle->roam_preauth_chan_context = params; + + abort_scan_req.SessionId = vdev_id; + wma_handle->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED; + cdf_status = wma_stop_scan(wma_handle, &abort_scan_req); + if (cdf_status == CDF_STATUS_SUCCESS) + return cdf_status; + /* Failed operation. Safely clear context */ + wma_handle->roam_preauth_chan_context = NULL; + +send_resp: + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, cdf_status); + params->chainMask = wma_handle->pdevconfig.txchainmask; + params->smpsMode = SMPS_MODE_DISABLED; + params->status = cdf_status; + wma_send_msg(wma_handle, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); + return cdf_status; +} + +/** + * wma_roam_preauth_scan_event_handler() - preauth scan event handler + * @wma_handle: wma handle + * @vdev_id: vdev id + * @wmi_event: event data + * + * This function handles preauth scan event and send appropriate + * message to upper layers. + * + * Return: none + */ +void wma_roam_preauth_scan_event_handler(tp_wma_handle wma_handle, + uint8_t vdev_id, + wmi_scan_event_fixed_param * + wmi_event) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + tSwitchChannelParams *params; + + WMA_LOGI("%s: preauth_scan_state %d, event 0x%x, reason 0x%x", + __func__, wma_handle->roam_preauth_scan_state, + wmi_event->event, wmi_event->reason); + switch (wma_handle->roam_preauth_scan_state) { + case WMA_ROAM_PREAUTH_CHAN_REQUESTED: + if (wmi_event->event & WMI_SCAN_EVENT_FOREIGN_CHANNEL) { + /* complete set_chan request */ + wma_handle->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_ON_CHAN; + cdf_status = CDF_STATUS_SUCCESS; + } else if (wmi_event->event & WMI_SCAN_FINISH_EVENTS) { + /* Failed to get preauth channel or finished (unlikely) */ + wma_handle->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_CHAN_NONE; + cdf_status = CDF_STATUS_E_FAILURE; + } else + return; + break; + case WMA_ROAM_PREAUTH_CHAN_CANCEL_REQUESTED: + /* Completed or cancelled, complete set_chan cancel request */ + wma_handle->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_CHAN_NONE; + break; + + case WMA_ROAM_PREAUTH_ON_CHAN: + if ((wmi_event->event & WMI_SCAN_EVENT_BSS_CHANNEL) || + (wmi_event->event & WMI_SCAN_FINISH_EVENTS)) + wma_handle->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_CHAN_COMPLETED; + + /* There is no WMA request to complete. Next set channel request will + * look at this state and complete it. + */ + break; + default: + WMA_LOGE("%s: unhandled event 0x%x, reason 0x%x", + __func__, wmi_event->event, wmi_event->reason); + return; + } + + params = (tpSwitchChannelParams) wma_handle->roam_preauth_chan_context; + if (params) { + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, cdf_status); + params->chainMask = wma_handle->pdevconfig.txchainmask; + params->smpsMode = SMPS_MODE_DISABLED; + params->status = cdf_status; + wma_send_msg(wma_handle, WMA_SWITCH_CHANNEL_RSP, (void *)params, + 0); + wma_handle->roam_preauth_chan_context = NULL; + } + +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +/** + * wma_process_roam_invoke() - send roam invoke command to fw. + * @handle: wma handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: none + */ +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_roam_invoke_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + u_int8_t *buf_ptr; + u_int16_t len, args_tlv_len; + A_UINT32 *channel_list; + wmi_mac_addr *bssid_list; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not send roam invoke", + __func__); + return; + } + /* Host sends only one channel and one bssid */ + args_tlv_len = 2 * WMI_TLV_HDR_SIZE + sizeof(A_UINT32) + + sizeof(wmi_mac_addr); + len = sizeof(wmi_roam_invoke_cmd_fixed_param) + args_tlv_len; + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmai_buf_alloc failed", __func__); + return; + } + + cmd = (wmi_roam_invoke_cmd_fixed_param *)wmi_buf_data(wmi_buf); + buf_ptr = (u_int8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_invoke_cmd_fixed_param)); + cmd->vdev_id = roaminvoke->vdev_id; + cmd->flags = 0; + cmd->roam_scan_mode = 0; + cmd->roam_ap_sel_mode = 0; + cmd->roam_delay = 0; + cmd->num_chan = 1; + cmd->num_bssid = 1; + buf_ptr += sizeof(wmi_roam_invoke_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (sizeof(u_int32_t))); + channel_list = (A_UINT32 *)(buf_ptr + WMI_TLV_HDR_SIZE); + *channel_list = (A_UINT32)cds_chan_to_freq(roaminvoke->channel); + buf_ptr += sizeof(A_UINT32) + WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (sizeof(wmi_mac_addr))); + bssid_list = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(roaminvoke->bssid, bssid_list); + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_ROAM_INVOKE_CMDID)) { + WMA_LOGP("%s: failed to send roam invoke command", __func__); + wmi_buf_free(wmi_buf); + return; + } + return; +} + +/** + * wma_process_roam_synch_fail() -roam synch failure handle + * @handle: wma handle + * @synch_fail: roam synch fail parameters + * + * Return: none + */ +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not clean-up roam synch", + __func__); + return; + } + /* Hand Off Failure could happen as an exception, when a roam synch + * indication is posted to Host, but a roam synch complete is not + * posted to the firmware.So, clear the roam synch in progress + * flag before disconnecting the session through this event.*/ + wma_handle->interfaces[synch_fail->session_id].roam_synch_in_progress = + false; +} + +/** + * wma_roam_synch_event_handler() - roam synch event handler + * @handle: wma handle + * @event: event data + * @len: length of data + * + * This function is roam synch event handler. It sends roam + * indication for upper layer. + */ +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_synch_event_fixed_param *synch_event = NULL; + uint8_t *bcn_probersp_ptr = NULL; + uint8_t *reassoc_rsp_ptr = NULL; + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_channel *chan = NULL; + wmi_key_material *key = NULL; + int size = 0; + roam_offload_synch_ind *roam_synch_ind_ptr; + + WMA_LOGD("LFR3:%s", __func__); + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + synch_event = param_buf->fixed_param; + if (!synch_event) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + + if (wma->interfaces[synch_event->vdev_id].roam_synch_in_progress) { + WMA_LOGE("%s: Ignoring RSI since one is already in progress", + __func__); + return -EINVAL; + } + wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = true; + len = sizeof(roam_offload_synch_ind) + + synch_event->bcn_probe_rsp_len + synch_event->reassoc_rsp_len; + roam_synch_ind_ptr = + (roam_offload_synch_ind *) cdf_mem_malloc(len); + if (!roam_synch_ind_ptr) { + WMA_LOGE("%s: failed to allocate memory for roam_synch_event", + __func__); + return -ENOMEM; + } + + /* abort existing scan if any */ + if (wma->interfaces[synch_event->vdev_id].scan_info.scan_id != 0) { + tAbortScanParams abort_scan; + WMA_LOGD("LFR3: Aborting Scan with scan_id=%d\n", + wma->interfaces[synch_event->vdev_id].scan_info.scan_id); + abort_scan.SessionId = synch_event->vdev_id; + wma_stop_scan(wma, &abort_scan); + } + + roam_synch_ind_ptr->messageType = eWNI_SME_ROAM_OFFLOAD_SYNCH_IND; + roam_synch_ind_ptr->length = size; + roam_synch_ind_ptr->roamedVdevId = synch_event->vdev_id; + roam_synch_ind_ptr->authStatus = synch_event->auth_status; + roam_synch_ind_ptr->roamReason = synch_event->roam_reason; + roam_synch_ind_ptr->rssi = synch_event->rssi; + roam_synch_ind_ptr->isBeacon = synch_event->is_beacon; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, + roam_synch_ind_ptr->bssId); + roam_synch_ind_ptr->beaconProbeRespOffset = + sizeof(roam_offload_synch_ind); + bcn_probersp_ptr = + (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->beaconProbeRespOffset; + roam_synch_ind_ptr->beaconProbeRespLength = + synch_event->bcn_probe_rsp_len; + cdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame, + roam_synch_ind_ptr->beaconProbeRespLength); + roam_synch_ind_ptr->reassocRespOffset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength; + roam_synch_ind_ptr->reassocRespLength = synch_event->reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassocRespOffset; + cdf_mem_copy(reassoc_rsp_ptr, + param_buf->reassoc_rsp_frame, + roam_synch_ind_ptr->reassocRespLength); + chan = (wmi_channel *) param_buf->chan; + roam_synch_ind_ptr->chan_freq = chan->mhz; + key = (wmi_key_material *) param_buf->key; + if (key != NULL) { + CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_DEBUG, + key->replay_counter, SIR_REPLAY_CTR_LEN); + cdf_mem_copy(roam_synch_ind_ptr->kck, key->kck, + SIR_KCK_KEY_LEN); + cdf_mem_copy(roam_synch_ind_ptr->kek, key->kek, + SIR_KEK_KEY_LEN); + cdf_mem_copy(roam_synch_ind_ptr->replay_ctr, + key->replay_counter, SIR_REPLAY_CTR_LEN); + } + wma_send_msg(wma, WMA_ROAM_OFFLOAD_SYNCH_IND, + (void *) roam_synch_ind_ptr, 0); + return 0; +} + +/** + * wma_rssi_breached_event_handler() - rssi breached event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: 0 on success; error number otherwise + */ +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf; + wmi_rssi_breach_event_fixed_param *event; + struct rssi_breach_event rssi; + tpAniSirGlobal mac = cds_get_context(CDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.rssi_threshold_breached_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid rssi breached event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + + rssi.request_id = event->request_id; + rssi.session_id = event->vdev_id; + rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); + + WMA_LOGD("%s: req_id: %u vdev_id: %d curr_rssi: %d", __func__, + rssi.request_id, rssi.session_id, rssi.curr_rssi); + WMA_LOGI("%s: curr_bssid: %pM", __func__, rssi.curr_bssid.bytes); + + mac->sme.rssi_threshold_breached_cb(mac->hHdd, &rssi); + WMA_LOGD("%s: Invoke HDD rssi breached callback", __func__); + return 0; +} + +/** + * wma_roam_scan_fill_self_caps() - fill capabilities + * @wma_handle: wma handle + * @roam_offload_params: offload parameters + * @roam_req: roam request + * + * This function fills roam self capablities. + * + * Return: CDF status + */ +CDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + wmi_roam_offload_tlv_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req) +{ + struct sAniSirGlobal *pMac = NULL; + tSirMacCapabilityInfo selfCaps; + uint32_t val = 0; + uint32_t nCfgValue; + uint16_t *pCfgValue16; + uint8_t nCfgValue8, *pCfgValue8; + tSirMacQosInfoStation macQosInfoSta; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + cdf_mem_set(&macQosInfoSta, sizeof(tSirMacQosInfoStation), 0); + /* Roaming is done only for INFRA STA type. + * So, ess will be one and ibss will be Zero */ + pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PRIVACY_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + selfCaps.ess = 1; + selfCaps.ibss = 0; + if (val) + selfCaps.privacy = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SHORT_PREAMBLE"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortPreamble = 1; + + selfCaps.pbcc = 0; + selfCaps.channelAgility = 0; + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortSlotTime = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11H_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.spectrumMgt = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_QOS_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.qos = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_APSD_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.apsd = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_RRM_ENABLED, &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_RRM_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.rrm = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_BLOCK_ACK_ENABLED"); + return CDF_STATUS_E_FAILURE; + } + selfCaps.delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + selfCaps.immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + pCfgValue16 = (uint16_t *) &selfCaps; + roam_offload_params->capability = (*pCfgValue16) & 0xFFFF; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &nCfgValue) != + eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_CAP_INFO"); + return CDF_STATUS_E_FAILURE; + } + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_caps_info = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &nCfgValue) != + eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_AMPDU_PARAMS"); + return CDF_STATUS_E_FAILURE; + } + /* tSirMacHTParametersInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ampdu_param = (nCfgValue8) & 0xFF; + + val = ROAM_OFFLOAD_NUM_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + (uint8_t *) roam_offload_params->mcsset, + &val) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SUPPORTED_MCS_SET"); + return CDF_STATUS_E_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_EXT_HT_CAP_INFO, &nCfgValue) != + eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_EXT_HT_CAP_INFO"); + return CDF_STATUS_E_FAILURE; + } + /* uHTCapabilityInfo.extHtCapInfo */ + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_ext_cap = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + + if (wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &nCfgValue) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_TX_BF_CAP"); + return CDF_STATUS_E_FAILURE; + } + /* tSirMacTxBFCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ht_txbf = nCfgValue8 & 0xFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &nCfgValue) != eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_AS_CAP"); + return CDF_STATUS_E_FAILURE; + } + /* tSirMacASCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->asel_cap = nCfgValue8 & 0xFF; + + /* QOS Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &nCfgValue) != + eSIR_SUCCESS) { + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_MAX_SP_LENGTH"); + return CDF_STATUS_E_FAILURE; + } + nCfgValue8 = (uint8_t) nCfgValue; + macQosInfoSta.maxSpLen = nCfgValue8; + macQosInfoSta.moreDataAck = 0; + macQosInfoSta.qack = 0; + macQosInfoSta.acbe_uapsd = roam_req->AcUapsd.acbe_uapsd; + macQosInfoSta.acbk_uapsd = roam_req->AcUapsd.acbk_uapsd; + macQosInfoSta.acvi_uapsd = roam_req->AcUapsd.acvi_uapsd; + macQosInfoSta.acvo_uapsd = roam_req->AcUapsd.acvo_uapsd; + pCfgValue8 = (uint8_t *) &macQosInfoSta; + /* macQosInfoSta Only queue_request is set.Refer to + * populate_dot11f_wmm_caps for more details + */ + roam_offload_params->qos_caps = (*pCfgValue8) & 0xFF; + roam_offload_params->wmm_caps = 0x4 & 0xFF; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_ric_req() - set ric request element + * @wma: wma handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: none + */ +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) +{ + wmi_ric_request_fixed_param *cmd; + wmi_ric_tspec *tspec_param; + wmi_buf_t buf; + uint8_t *buf_ptr; + tSirMacTspecIE *ptspecIE; + int32_t len = sizeof(wmi_ric_request_fixed_param) + + WMI_TLV_HDR_SIZE + sizeof(wmi_ric_tspec); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + cmd = (wmi_ric_request_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_request_fixed_param)); + if (is_add_ts) + cmd->vdev_id = ((tAddTsParams *) msg)->sessionId; + else + cmd->vdev_id = ((tDelTsParams *) msg)->sessionId; + cmd->num_ric_request = 1; /* Today we are sending only 1 ric at once */ + cmd->is_add_ric = is_add_ts; + + buf_ptr += sizeof(wmi_ric_request_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_ric_tspec)); + + buf_ptr += WMI_TLV_HDR_SIZE; + tspec_param = (wmi_ric_tspec *) buf_ptr; + WMITLV_SET_HDR(&tspec_param->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_tspec, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_tspec)); + + if (is_add_ts) + ptspecIE = &(((tAddTsParams *) msg)->tspec); + else + ptspecIE = &(((tDelTsParams *) msg)->delTsInfo.tspec); + + /* Fill the tsinfo in the format expected by firmware */ +#ifndef ANI_LITTLE_BIT_ENDIAN + cdf_mem_copy(((uint8_t *) &tspec_param->ts_info) + 1, + ((uint8_t *) &ptspecIE->tsinfo) + 1, 2); +#else + cdf_mem_copy(((uint8_t *) &tspec_param->ts_info), + ((uint8_t *) &ptspecIE->tsinfo) + 1, 2); +#endif /* ANI_LITTLE_BIT_ENDIAN */ + + tspec_param->nominal_msdu_size = ptspecIE->nomMsduSz; + tspec_param->maximum_msdu_size = ptspecIE->maxMsduSz; + tspec_param->min_service_interval = ptspecIE->minSvcInterval; + tspec_param->max_service_interval = ptspecIE->maxSvcInterval; + tspec_param->inactivity_interval = ptspecIE->inactInterval; + tspec_param->suspension_interval = ptspecIE->suspendInterval; + tspec_param->svc_start_time = ptspecIE->svcStartTime; + tspec_param->min_data_rate = ptspecIE->minDataRate; + tspec_param->mean_data_rate = ptspecIE->meanDataRate; + tspec_param->peak_data_rate = ptspecIE->peakDataRate; + tspec_param->max_burst_size = ptspecIE->maxBurstSz; + tspec_param->delay_bound = ptspecIE->delayBound; + tspec_param->min_phy_rate = ptspecIE->minPhyRate; + tspec_param->surplus_bw_allowance = ptspecIE->surplusBw; + tspec_param->medium_time = 0; + + WMA_LOGI("%s: Set RIC Req is_add_ts:%d", __func__, is_add_ts); + + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_ROAM_SET_RIC_REQUEST_CMDID)) { + WMA_LOGP("%s: Failed to send vdev Set RIC Req command", + __func__); + if (is_add_ts) + ((tAddTsParams *) msg)->status = CDF_STATUS_E_FAILURE; + cdf_nbuf_free(buf); + } +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wma_process_unit_test_cmd() - send unit test command to fw. + * @handle: wma handle + * @wma_utest: unit test command + * + * This function send unit test command to fw. + * + * Return: none + */ +void wma_process_unit_test_cmd(WMA_HANDLE handle, + t_wma_unit_test_cmd *wma_utest) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_unit_test_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + int i; + uint16_t len, args_tlv_len; + A_UINT32 *unit_test_cmd_args; + + args_tlv_len = + WMI_TLV_HDR_SIZE + wma_utest->num_args * sizeof(A_UINT32); + len = sizeof(wmi_unit_test_cmd_fixed_param) + args_tlv_len; + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw unit test cmd", + __func__); + return; + } + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmai_buf_alloc failed", __func__); + return; + } + + cmd = (wmi_unit_test_cmd_fixed_param *) wmi_buf_data(wmi_buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_unit_test_cmd_fixed_param)); + cmd->vdev_id = wma_utest->vdev_id; + cmd->module_id = wma_utest->module_id; + cmd->num_args = wma_utest->num_args; + buf_ptr += sizeof(wmi_unit_test_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (wma_utest->num_args * sizeof(uint32_t))); + unit_test_cmd_args = (A_UINT32 *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMA_LOGI("%s: %d num of args = ", __func__, wma_utest->num_args); + for (i = 0; (i < wma_utest->num_args && i < WMA_MAX_NUM_ARGS); i++) { + unit_test_cmd_args[i] = wma_utest->args[i]; + WMA_LOGI("%d,", wma_utest->args[i]); + } + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_UNIT_TEST_CMDID)) { + WMA_LOGP("%s: failed to send unit test command", __func__); + cdf_nbuf_free(wmi_buf); + return; + } + return; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +/** + * wma_roam_ho_fail_handler() - LFR3.0 roam hand off failed handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_roam_ho_fail_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + tSirSmeHOFailureInd *ho_failure_ind; + cds_msg_t sme_msg = { 0 }; + CDF_STATUS cdf_status; + + ho_failure_ind = cdf_mem_malloc(sizeof(tSirSmeHOFailureInd)); + + if (NULL == ho_failure_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + ho_failure_ind->sessionId = vdev_id; + sme_msg.type = eWNI_SME_HO_FAIL_IND; + sme_msg.bodyptr = ho_failure_ind; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_HO_FAIL_IND msg to SME"); + cdf_mem_free(ho_failure_ind); + return; + } + return; +} + +/** + * wma_process_roam_synch_complete() - roam synch complete command to fw. + * @handle: wma handle + * @synchcnf: offload synch confirmation params + * + * This function sends roam synch complete event to fw. + * + * Return: none + */ +void wma_process_roam_synch_complete(WMA_HANDLE handle, + tSirSmeRoamOffloadSynchCnf *synchcnf) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_roam_synch_complete_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint16_t len; + bool roam_synch_in_progress; + len = sizeof(wmi_roam_synch_complete_fixed_param); + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue roam synch cnf", + __func__); + return; + } + roam_synch_in_progress = + wma_handle->interfaces[synchcnf->sessionId].roam_synch_in_progress; + if (roam_synch_in_progress == false) { + WMA_LOGE("%s: Dont send roam synch complete", __func__); + return; + } else { + wma_handle->interfaces[synchcnf->sessionId].roam_synch_in_progress = + false; + } + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_roam_synch_complete_fixed_param *) wmi_buf_data(wmi_buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_synch_complete_fixed_param)); + cmd->vdev_id = synchcnf->sessionId; + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_ROAM_SYNCH_COMPLETE)) { + WMA_LOGP("%s: failed to send roam synch confirmation", + __func__); + cdf_nbuf_free(wmi_buf); + return; + } + return; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wma_set_channel() - set channel + * @wma: wma handle + * @params: switch channel parameters + * + * Return: none + */ +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params) +{ + struct wma_vdev_start_req req; + struct wma_target_req *msg; + CDF_STATUS status = CDF_STATUS_SUCCESS; + uint8_t vdev_id, peer_id; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + struct wma_txrx_node *intr = wma->interfaces; + struct sir_hw_mode_params hw_mode = {0}; + + WMA_LOGD("%s: Enter", __func__); + if (!wma_find_vdev_by_addr(wma, params->selfStaMacAddr, &vdev_id)) { + WMA_LOGP("%s: Failed to find vdev id for %pM", + __func__, params->selfStaMacAddr); + status = CDF_STATUS_E_FAILURE; + goto send_resp; + } + pdev = cds_get_context(CDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + status = CDF_STATUS_E_FAILURE; + goto send_resp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, intr[vdev_id].bssid, &peer_id); + + /* + * Roam offload feature is currently supported + * only in STA mode. Other modes still require + * to issue a Vdev Start/Vdev Restart for + * channel change. + */ + if (((wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA) && + (wma->interfaces[vdev_id].sub_type == 0)) && + !wma->interfaces[vdev_id].is_channel_switch) { + + if (peer && (peer->state == ol_txrx_peer_state_conn || + peer->state == ol_txrx_peer_state_auth)) { + /* Trying to change channel while connected + * should not invoke VDEV_START. + * Instead, use start scan command in passive + * mode to park station on that channel + */ + WMA_LOGI("%s: calling set_scan, state 0x%x", + __func__, wma->roam_preauth_scan_state); + if (wma->roam_preauth_scan_state == + WMA_ROAM_PREAUTH_CHAN_NONE) { + /* Is channel change required? + */ + if (cds_chan_to_freq(params->channelNumber) != + wma->interfaces[vdev_id].mhz) { + status = wma_roam_preauth_chan_set(wma, + params, + vdev_id); + /* response will be asynchronous */ + return; + } + } else if (wma->roam_preauth_scan_state == + WMA_ROAM_PREAUTH_CHAN_REQUESTED || + wma->roam_preauth_scan_state == + WMA_ROAM_PREAUTH_ON_CHAN) { + status = + wma_roam_preauth_chan_cancel(wma, params, + vdev_id); + /* response will be asynchronous */ + return; + } else if (wma->roam_preauth_scan_state == + WMA_ROAM_PREAUTH_CHAN_COMPLETED) { + /* Already back on home channel. Complete the request */ + wma->roam_preauth_scan_state = + WMA_ROAM_PREAUTH_CHAN_NONE; + status = CDF_STATUS_SUCCESS; + } + goto send_resp; + } + } + cdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + msg = wma_fill_vdev_req(wma, req.vdev_id, WMA_CHNL_SWITCH_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, params, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill channel switch request for vdev %d", + __func__, req.vdev_id); + status = CDF_STATUS_E_NOMEM; + goto send_resp; + } + req.chan = params->channelNumber; + req.chan_width = params->ch_width; + req.vht_capable = params->vhtCapable; + req.ch_center_freq_seg0 = params->ch_center_freq_seg0; + req.ch_center_freq_seg1 = params->ch_center_freq_seg1; + req.dot11_mode = params->dot11_mode; + status = wma_get_current_hw_mode(&hw_mode); + if (!CDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if ((params->nss == 2) && !hw_mode.dbs_cap) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + +#ifdef WLAN_FEATURE_VOWIFI + req.max_txpow = params->maxTxPower; +#else + req.max_txpow = params->localPowerConstraint; +#endif /* WLAN_FEATURE_VOWIFI */ + req.beacon_intval = 100; + req.dtim_period = 1; + req.is_dfs = params->isDfsChannel; + + /* In case of AP mode, once radar is detected, we need to + * issuse VDEV RESTART, so we making is_channel_switch as + * true + */ + if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true) || + (params->restart_on_chan_switch == true)) + wma->interfaces[req.vdev_id].is_channel_switch = true; + + status = wma_vdev_start(wma, &req, + wma->interfaces[req.vdev_id].is_channel_switch); + if (status != CDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGP("%s: vdev start failed status = %d", __func__, status); + goto send_resp; + } + + if (wma->interfaces[req.vdev_id].is_channel_switch) + wma->interfaces[req.vdev_id].is_channel_switch = false; + return; +send_resp: + WMA_LOGD("%s: channel %d ch_width %d txpower %d status %d", __func__, + params->channelNumber, params->ch_width, +#ifdef WLAN_FEATURE_VOWIFI + params->maxTxPower, +#else + params->localPowerConstraint, +#endif /* WLAN_FEATURE_VOWIFI */ + status); + params->status = status; + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, status); + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); +} + +#ifdef FEATURE_WLAN_SCAN_PNO + +/** + * wma_pno_start() - PNO start request + * @wma: wma handle + * @pno: PNO request + * + * This function request FW to start PNO request. + * Request: CDF status + */ +CDF_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + nlo_configured_parameters *nlo_list; + uint32_t *channel_list; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t i; + int ret; + + WMA_LOGD("PNO Start"); + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + /* TLV place holder for array of structures nlo_configured_parameters(nlo_list) */ + WMI_TLV_HDR_SIZE; /* TLV place holder for array of uint32_t channel_list */ + + len += sizeof(uint32_t) * CDF_MIN(pno->aNetworks[0].ucChannelCount, + WMI_NLO_MAX_CHAN); + len += sizeof(nlo_configured_parameters) * + CDF_MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_nlo_config_cmd_fixed_param)); + cmd->vdev_id = pno->sessionId; + cmd->flags = WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN; + + /* Copy scan interval */ + if (pno->scanTimers.ucScanTimersCount) { + cmd->fast_scan_period = + WMA_SEC_TO_MSEC(pno->scanTimers.aTimerValues[0]. + uTimerValue); + cmd->slow_scan_period = cmd->fast_scan_period; + WMA_LOGD("Scan period : %d msec", cmd->slow_scan_period); + } + + buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param); + + cmd->no_of_ssids = CDF_MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS); + WMA_LOGD("SSID count : %d", cmd->no_of_ssids); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->no_of_ssids * sizeof(nlo_configured_parameters)); + buf_ptr += WMI_TLV_HDR_SIZE; + + nlo_list = (nlo_configured_parameters *) buf_ptr; + for (i = 0; i < cmd->no_of_ssids; i++) { + WMITLV_SET_HDR(&nlo_list[i].tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN + (nlo_configured_parameters)); + /* Copy ssid and it's length */ + nlo_list[i].ssid.valid = true; + nlo_list[i].ssid.ssid.ssid_len = pno->aNetworks[i].ssId.length; + cdf_mem_copy(nlo_list[i].ssid.ssid.ssid, + pno->aNetworks[i].ssId.ssId, + nlo_list[i].ssid.ssid.ssid_len); + WMA_LOGD("index: %d ssid: %.*s len: %d", i, + nlo_list[i].ssid.ssid.ssid_len, + (char *)nlo_list[i].ssid.ssid.ssid, + nlo_list[i].ssid.ssid.ssid_len); + + /* Copy rssi threshold */ + if (pno->aNetworks[i].rssiThreshold && + pno->aNetworks[i].rssiThreshold > WMA_RSSI_THOLD_DEFAULT) { + nlo_list[i].rssi_cond.valid = true; + nlo_list[i].rssi_cond.rssi = + pno->aNetworks[i].rssiThreshold; + WMA_LOGD("RSSI threshold : %d dBm", + nlo_list[i].rssi_cond.rssi); + } + nlo_list[i].bcast_nw_type.valid = true; + nlo_list[i].bcast_nw_type.bcast_nw_type = + pno->aNetworks[i].bcastNetwType; + WMA_LOGI("Broadcast NW type (%u)", + nlo_list[i].bcast_nw_type.bcast_nw_type); + } + buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters); + + /* Copy channel info */ + cmd->num_of_channels = CDF_MIN(pno->aNetworks[0].ucChannelCount, + WMI_NLO_MAX_CHAN); + WMA_LOGD("Channel count: %d", cmd->num_of_channels); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (cmd->num_of_channels * sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE; + + channel_list = (uint32_t *) buf_ptr; + for (i = 0; i < cmd->num_of_channels; i++) { + channel_list[i] = pno->aNetworks[0].aChannels[i]; + + if (channel_list[i] < WMA_NLO_FREQ_THRESH) + channel_list[i] = cds_chan_to_freq(channel_list[i]); + + WMA_LOGD("Ch[%d]: %d MHz", i, channel_list[i]); + } + buf_ptr += cmd->num_of_channels * sizeof(uint32_t); + + /* TODO: Discrete firmware doesn't have command/option to configure + * App IE which comes from wpa_supplicant as of part PNO start request. + */ + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + wma->interfaces[pno->sessionId].pno_in_progress = true; + + WMA_LOGD("PNO start request sent successfully for vdev %d", + pno->sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_pno_stop() - PNO stop request + * @wma: wma handle + * @vdev_id: vdev id + * + * This function request FW to stop ongoing PNO operation. + * + * Return: CDF status + */ +CDF_STATUS wma_pno_stop(tp_wma_handle wma, uint8_t vdev_id) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (!wma->interfaces[vdev_id].pno_in_progress) { + WMA_LOGD("No active pno session found for vdev %d, skip pno stop request", + vdev_id); + return CDF_STATUS_SUCCESS; + } + + WMA_LOGD("PNO Stop"); + + len += WMI_TLV_HDR_SIZE + /* TLV place holder for array of structures nlo_configured_parameters(nlo_list) */ + WMI_TLV_HDR_SIZE; /* TLV place holder for array of uint32_t channel_list */ + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_nlo_config_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->flags = WMI_NLO_CONFIG_STOP; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + wma->interfaces[vdev_id].pno_in_progress = false; + + WMA_LOGD("PNO stop request sent successfully for vdev %d", vdev_id); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_config_pno() - config PNO + * @wma: wma handle + * @pno: PNO request parameters + * + * Return: none + */ +void wma_config_pno(tp_wma_handle wma, tpSirPNOScanReq pno) +{ + CDF_STATUS ret; + + if (pno->enable) + ret = wma_pno_start(wma, pno); + else + ret = wma_pno_stop(wma, pno->sessionId); + + if (ret) + WMA_LOGE("%s: PNO %s failed %d", __func__, + pno->enable ? "start" : "stop", ret); + + /* SME expects WMA to free tpSirPNOScanReq memory after + * processing PNO request. */ + cdf_mem_free(pno); +} + +#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD) + +/** + * wma_plm_start() - plm start request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: CDF status + */ +CDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm) +{ + wmi_vdev_plmreq_start_cmd_fixed_param *cmd; + uint32_t *channel_list; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t count; + int ret; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return CDF_STATUS_E_FAILURE; + } + WMA_LOGD("PLM Start"); + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; /* TLV place holder for channel_list */ + len += sizeof(uint32_t) * plm->plmNumCh; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_plmreq_start_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_start_cmd_fixed_param)); + + cmd->vdev_id = plm->sessionId; + + cmd->meas_token = plm->meas_token; + cmd->dialog_token = plm->diag_token; + cmd->number_bursts = plm->numBursts; + cmd->burst_interval = WMA_SEC_TO_MSEC(plm->burstInt); + cmd->off_duration = plm->measDuration; + cmd->burst_cycle = plm->burstLen; + cmd->tx_power = plm->desiredTxPwr; + WMI_CHAR_ARRAY_TO_MAC_ADDR(plm->macAddr, &cmd->dest_mac); + cmd->num_chans = plm->plmNumCh; + + buf_ptr += sizeof(wmi_vdev_plmreq_start_cmd_fixed_param); + + WMA_LOGD("vdev : %d measu token : %d", cmd->vdev_id, cmd->meas_token); + WMA_LOGD("dialog_token: %d", cmd->dialog_token); + WMA_LOGD("number_bursts: %d", cmd->number_bursts); + WMA_LOGD("burst_interval: %d", cmd->burst_interval); + WMA_LOGD("off_duration: %d", cmd->off_duration); + WMA_LOGD("burst_cycle: %d", cmd->burst_cycle); + WMA_LOGD("tx_power: %d", cmd->tx_power); + WMA_LOGD("Number of channels : %d", cmd->num_chans); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (cmd->num_chans * sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + if (cmd->num_chans) { + channel_list = (uint32_t *) buf_ptr; + for (count = 0; count < cmd->num_chans; count++) { + channel_list[count] = plm->plmChList[count]; + if (channel_list[count] < WMA_NLO_FREQ_THRESH) + channel_list[count] = + cds_chan_to_freq(channel_list[count]); + WMA_LOGD("Ch[%d]: %d MHz", count, channel_list[count]); + } + buf_ptr += cmd->num_chans * sizeof(uint32_t); + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_PLMREQ_START_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send plm start wmi cmd", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + wma->interfaces[plm->sessionId].plm_in_progress = true; + + WMA_LOGD("Plm start request sent successfully for vdev %d", + plm->sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_plm_stop() - plm stop request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: CDF status + */ +CDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm) +{ + wmi_vdev_plmreq_stop_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (false == wma->interfaces[plm->sessionId].plm_in_progress) { + WMA_LOGE("No active plm req found, skip plm stop req"); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("PLM Stop"); + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_plmreq_stop_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_stop_cmd_fixed_param)); + + cmd->vdev_id = plm->sessionId; + + cmd->meas_token = plm->meas_token; + WMA_LOGD("vdev %d meas token %d", cmd->vdev_id, cmd->meas_token); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_VDEV_PLMREQ_STOP_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send plm stop wmi cmd", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + wma->interfaces[plm->sessionId].plm_in_progress = false; + + WMA_LOGD("Plm stop request sent successfully for vdev %d", + plm->sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_config_plm()- config PLM + * @wma: wma handle + * @plm: plm request parameters + * + * Return: none + */ +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm) +{ + CDF_STATUS ret = 0; + + if (NULL == plm || NULL == wma) + return; + + if (plm->enable) + ret = wma_plm_start(wma, plm); + else + ret = wma_plm_stop(wma, plm); + + if (ret) + WMA_LOGE("%s: PLM %s failed %d", __func__, + plm->enable ? "start" : "stop", ret); + + /* SME expects WMA to free tpSirPlmReq memory after + * processing PLM request. */ + cdf_mem_free(plm); + plm = NULL; +} +#endif + +/** + * wma_scan_cache_updated_ind() - scan update indication + * @wma: wma handle + * @sessionId: session ID + * + * After pushing cached scan results (that are stored in LIM) to SME, + * PE will post WMA_SME_SCAN_CACHE_UPDATED message indication to + * wma and intern this function handles that message. This function will + * check for PNO completion (by checking NLO match event) and post PNO + * completion back to SME if PNO operation is completed successfully. + * + * Return: none + */ +void wma_scan_cache_updated_ind(tp_wma_handle wma, uint8_t sessionId) +{ + tSirPrefNetworkFoundInd *nw_found_ind; + CDF_STATUS status; + cds_msg_t cds_msg; + uint8_t len, i; + + for (i = 0; i < wma->max_bssid; i++) { + if (wma->interfaces[i].nlo_match_evt_received) + break; + } + + if (i == wma->max_bssid) { + WMA_LOGD("PNO match event is not received in any vdev, skip scan cache update indication"); + return; + } + wma->interfaces[i].nlo_match_evt_received = false; + + WMA_LOGD("Posting PNO completion to umac"); + + len = sizeof(tSirPrefNetworkFoundInd); + nw_found_ind = (tSirPrefNetworkFoundInd *) cdf_mem_malloc(len); + + if (NULL == nw_found_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + nw_found_ind->mesgType = eWNI_SME_PREF_NETWORK_FOUND_IND; + nw_found_ind->mesgLen = len; + nw_found_ind->sessionId = sessionId; + + cds_msg.type = eWNI_SME_PREF_NETWORK_FOUND_IND; + cds_msg.bodyptr = (void *)nw_found_ind; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post PNO completion match event to SME", + __func__); + cdf_mem_free(nw_found_ind); + } +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * wma_extscan_get_eventid_from_tlvtag() - map tlv tag to corresponding event id + * @tag: WMI TLV tag + * + * Return: + * 0 if TLV tag is invalid + * else return corresponding WMI event id + */ +static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag) +{ + uint32_t event_id; + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + event_id = WMI_EXTSCAN_START_STOP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + event_id = WMI_EXTSCAN_OPERATION_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + event_id = WMI_EXTSCAN_TABLE_USAGE_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + event_id = WMI_EXTSCAN_CACHED_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + event_id = WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + event_id = WMI_EXTSCAN_HOTLIST_MATCH_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + event_id = WMI_EXTSCAN_CAPABILITIES_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param: + event_id = WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID; + break; + + default: + event_id = 0; + WMA_LOGE("%s: Unknown tag: %d", __func__, tag); + break; + } + + WMA_LOGI("%s: For tag %d WMI event 0x%x", __func__, tag, event_id); + return event_id; +} + +/** + * wma_extscan_wow_event_callback() - extscan wow event callback + * @handle: WMA handle + * @event: event buffer + * @len: length of @event buffer + * + * In wow case, the wow event is followed by the payload of the event + * which generated the wow event. + * payload is 4 bytes of length followed by event buffer. the first 4 bytes + * of event buffer is common tlv header, which is a combination + * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to + * identify the event which triggered wow event. + * + * @Return: none + */ +void wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len) +{ + uint32_t id; + int tlv_ok_status = 0; + void *wmi_cmd_struct_ptr = NULL; + uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event)); + + id = wma_extscan_get_eventid_from_tlvtag(tag); + if (!id) { + WMA_LOGE("%s: Invalid Tag: %d", __func__, tag); + return; + } + + tlv_ok_status = wmitlv_check_and_pad_event_tlvs( + handle, event, len, id, + &wmi_cmd_struct_ptr); + if (tlv_ok_status != 0) { + WMA_LOGE("%s: Invalid Tag: %d could not check and pad tlvs", + __func__, tag); + return; + } + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + wma_extscan_start_stop_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + wma_extscan_operations_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + wma_extscan_table_usage_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + wma_extscan_cached_results_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + wma_extscan_change_results_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + wma_extscan_hotlist_match_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + wma_extscan_capabilities_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param: + wma_extscan_hotlist_ssid_match_event_handler(handle, + wmi_cmd_struct_ptr, len); + break; + + default: + WMA_LOGE("%s: Unknown tag: %d", __func__, tag); + break; + } + wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); + + return; +} +#endif + +/** + * wma_nlo_match_evt_handler() - nlo match event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * Record NLO match event comes from FW. It's a indication that + * one of the profile is matched. + * + * Return: 0 for success or error code. + */ +int wma_nlo_match_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_nlo_event *nlo_event; + WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = + (WMI_NLO_MATCH_EVENTID_param_tlvs *) event; + struct wma_txrx_node *node; + + if (!param_buf) { + WMA_LOGE("Invalid NLO match event buffer"); + return -EINVAL; + } + + nlo_event = param_buf->fixed_param; + WMA_LOGD("PNO match event received for vdev %d", nlo_event->vdev_id); + + node = &wma->interfaces[nlo_event->vdev_id]; + if (node) + node->nlo_match_evt_received = true; + + cdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + + return 0; +} + +/** + * wma_nlo_scan_cmp_evt_handler() - nlo scan completion handler + * @handle: wma handle + * @event: event handler + * @len: length of data + * + * This function handles NLO scan completion event. + * + * Return: 0 for success or error code. + */ +int wma_nlo_scan_cmp_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_nlo_event *nlo_event; + WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *param_buf = + (WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *) event; + tSirScanOffloadEvent *scan_event; + struct wma_txrx_node *node; + + if (!param_buf) { + WMA_LOGE("Invalid NLO scan comp event buffer"); + return -EINVAL; + } + + nlo_event = param_buf->fixed_param; + WMA_LOGD("PNO scan completion event received for vdev %d", + nlo_event->vdev_id); + + node = &wma->interfaces[nlo_event->vdev_id]; + + /* Handle scan completion event only after NLO match event. */ + if (!node || !node->nlo_match_evt_received) { + + WMA_LOGD("NLO match not recieved skipping PNO complete ind for vdev %d", + nlo_event->vdev_id); + goto skip_pno_cmp_ind; + } + + cdf_wake_lock_release(&wma->pno_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_PNO); + scan_event = + (tSirScanOffloadEvent *) + cdf_mem_malloc(sizeof(tSirScanOffloadEvent)); + if (scan_event) { + /* Posting scan completion msg would take scan cache result + * from LIM module and update in scan cache maintained in SME.*/ + WMA_LOGE("Posting PNO Scan completion to umac"); + cdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + cdf_mem_zero(scan_event, sizeof(tSirScanOffloadEvent)); + scan_event->reasonCode = eSIR_PNO_SCAN_SUCCESS; + scan_event->event = SCAN_EVENT_COMPLETED; + scan_event->sessionId = nlo_event->vdev_id; + wma_send_msg(wma, WMA_RX_SCAN_EVENT, (void *)scan_event, 0); + } else { + WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent"); + } + +skip_pno_cmp_ind: + return 0; +} + +#endif + +/** + * wma_register_extscan_event_handler() - register extscan event handler + * @wma_handle: wma handle + * + * This function register extscan related event handlers. + * + * Return: none + */ +void wma_register_extscan_event_handler(tp_wma_handle wma_handle) +{ + if (!wma_handle) { + WMA_LOGE("%s: extscan wma_handle is NULL", __func__); + return; + } + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_START_STOP_EVENTID, + wma_extscan_start_stop_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_CAPABILITIES_EVENTID, + wma_extscan_capabilities_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID, + wma_extscan_hotlist_match_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + wma_extscan_change_results_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_OPERATION_EVENTID, + wma_extscan_operations_event_handler); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_TABLE_USAGE_EVENTID, + wma_extscan_table_usage_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_CACHED_RESULTS_EVENTID, + wma_extscan_cached_results_event_handler); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PASSPOINT_MATCH_EVENTID, + wma_passpoint_match_event_handler); + + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID, + wma_extscan_hotlist_ssid_match_event_handler); + + return; +} + +#ifdef FEATURE_WLAN_EXTSCAN + +/** + * wma_extscan_start_stop_event_handler() - extscan start/stop event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: data length + * + * This function handles different extscan related commands + * like start/stop/get results etc and indicate to upper layers. + * + * Return: 0 for success or error code. + */ +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf; + wmi_extscan_start_stop_event_fixed_param *event; + struct sir_extscan_generic_response *extscan_ind; + uint16_t event_type; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid extscan event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + extscan_ind = cdf_mem_malloc(sizeof(*extscan_ind)); + if (!extscan_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + return -ENOMEM; + } + switch (event->command) { + case WMI_EXTSCAN_START_CMDID: + event_type = eSIR_EXTSCAN_START_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_STOP_CMDID: + event_type = eSIR_EXTSCAN_STOP_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP; + } else { + event_type = + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP; + } + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP; + } else { + event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP; + } + break; + case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP; + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP; + } else { + event_type = + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP; + } + break; + default: + WMA_LOGE("%s: Unknown event(%d) from target", + __func__, event->status); + cdf_mem_free(extscan_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hHdd, event_type, extscan_ind); + WMA_LOGD("%s: sending event to umac for requestid %u" + "with status %d", __func__, + extscan_ind->request_id, extscan_ind->status); + cdf_mem_free(extscan_ind); + return 0; +} + +/** + * wma_extscan_operations_event_handler() - extscan operation event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles different operations related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf; + wmi_extscan_operation_event_fixed_param *oprn_event; + tSirExtScanOnScanEventIndParams *oprn_ind; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid scan operation event", __func__); + return -EINVAL; + } + oprn_event = param_buf->fixed_param; + oprn_ind = cdf_mem_malloc(sizeof(*oprn_ind)); + if (!oprn_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + cdf_mem_free(oprn_ind); + return -ENOMEM; + } + + oprn_ind->requestId = oprn_event->request_id; + + switch (oprn_event->event) { + case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT: + oprn_ind->scanEventType = WIFI_SCAN_COMPLETE; + oprn_ind->status = 0; + break; + case WMI_EXTSCAN_CYCLE_STARTED_EVENT: + WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_STARTED_EVENT", + __func__); + cdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock, + WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + goto exit_handler; + case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT: + WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT", + __func__); + cdf_wake_lock_release(&wma->extscan_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + goto exit_handler; + default: + WMA_LOGE("%s: Unknown event(%d) from target", + __func__, oprn_event->event); + cdf_mem_free(oprn_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); + WMA_LOGI("%s: sending scan progress event to hdd", __func__); +exit_handler: + cdf_mem_free(oprn_ind); + return 0; +} + +/** + * wma_extscan_table_usage_event_handler() - extscan table usage event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles table usage related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf; + wmi_extscan_table_usage_event_fixed_param *event; + tSirExtScanResultsAvailableIndParams *tbl_usg_ind; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid table usage event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + tbl_usg_ind = cdf_mem_malloc(sizeof(*tbl_usg_ind)); + if (!tbl_usg_ind) { + WMA_LOGE("%s: table usage allocation failed", __func__); + return -ENOMEM; + } + tbl_usg_ind->requestId = event->request_id; + tbl_usg_ind->numResultsAvailable = event->entries_in_use; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + tbl_usg_ind); + WMA_LOGI("%s: sending scan_res available event to hdd", __func__); + cdf_mem_free(tbl_usg_ind); + return 0; +} + +/** + * wma_extscan_capabilities_event_handler() - extscan capabilities event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles capabilities event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf; + wmi_extscan_capabilities_event_fixed_param *event; + wmi_extscan_cache_capabilities *src_cache; + wmi_extscan_hotlist_monitor_capabilities *src_hotlist; + wmi_extscan_wlan_change_monitor_capabilities *src_change; + + struct ext_scan_capabilities_response *dest_capab; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid capabilities event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_cache = param_buf->extscan_cache_capabilities; + src_hotlist = param_buf->hotlist_capabilities; + src_change = param_buf->wlan_change_capabilities; + + if (!src_cache || !src_hotlist || !src_change) { + WMA_LOGE("%s: Invalid capabilities list", __func__); + return -EINVAL; + } + dest_capab = cdf_mem_malloc(sizeof(*dest_capab)); + if (!dest_capab) { + WMA_LOGE("%s: Allocation failed for capabilities buffer", + __func__); + return -ENOMEM; + } + dest_capab->requestId = event->request_id; + dest_capab->max_scan_buckets = src_cache->max_buckets; + dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size; + dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan; + dest_capab->max_scan_reporting_threshold = + src_cache->max_table_usage_threshold; + + dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries; + dest_capab->max_rssi_sample_size = src_change->max_rssi_averaging_samples; + dest_capab->max_bssid_history_entries = + src_change->max_rssi_history_entries; + dest_capab->max_significant_wifi_change_aps = + src_change->max_wlan_change_entries; + dest_capab->max_hotlist_ssids = + event->num_extscan_hotlist_ssid; + dest_capab->max_number_epno_networks = + event->num_epno_networks; + dest_capab->max_number_epno_networks_by_ssid = + event->num_epno_networks; + dest_capab->max_number_of_white_listed_ssid = + event->num_roam_ssid_whitelist; + dest_capab->status = 0; + + WMA_LOGD("%s: request_id: %u status: %d", + __func__, dest_capab->requestId, dest_capab->status); + + WMA_LOGD("%s: Capabilities: max_scan_buckets: %d," + "max_hotlist_bssids: %d, max_scan_cache_size: %d," + "max_ap_cache_per_scan: %d, max_scan_reporting_threshold: %d," + "max_rssi_sample_size: %d, max_bssid_history_entries: %d," + "max_significant_wifi_change_aps: %d", + __func__, dest_capab->max_scan_buckets, + dest_capab->max_hotlist_bssids, + dest_capab->max_scan_cache_size, + dest_capab->max_ap_cache_per_scan, + dest_capab->max_scan_reporting_threshold, + dest_capab->max_rssi_sample_size, + dest_capab->max_bssid_history_entries, + dest_capab->max_significant_wifi_change_aps); + + WMA_LOGD("%s: Capabilities: max_hotlist_ssids: %d," + "max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d," + "max_number_of_white_listed_ssid: %d", + __func__, dest_capab->max_hotlist_ssids, + dest_capab->max_number_epno_networks, + dest_capab->max_number_epno_networks_by_ssid, + dest_capab->max_number_of_white_listed_ssid); + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab); + WMA_LOGI("%s: sending capabilities event to hdd", __func__); + cdf_mem_free(dest_capab); + return 0; +} + +/** + * wma_extscan_hotlist_match_event_handler() - hotlist match event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles hotlist match event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf; + wmi_extscan_hotlist_match_event_fixed_param *event; + struct extscan_hotlist_match *dest_hotlist; + tSirWifiScanResult *dest_ap; + wmi_extscan_wlan_descriptor *src_hotlist; + int numap, j, ap_found = 0; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid hotlist match event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->hotlist_match; + numap = event->total_entries; + + if (!src_hotlist || !numap) { + WMA_LOGE("%s: Hotlist AP's list invalid", __func__); + return -EINVAL; + } + dest_hotlist = cdf_mem_malloc(sizeof(*dest_hotlist) + + sizeof(*dest_ap) * numap); + if (!dest_hotlist) { + WMA_LOGE("%s: Allocation failed for hotlist buffer", __func__); + return -ENOMEM; + } + dest_ap = &dest_hotlist->ap[0]; + dest_hotlist->numOfAps = event->total_entries; + dest_hotlist->requestId = event->config_request_id; + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + dest_hotlist->moreData = 1; + else + dest_hotlist->moreData = 0; + + WMA_LOGD("%s: Hotlist match: requestId: %u," + "numOfAps: %d", __func__, + dest_hotlist->requestId, dest_hotlist->numOfAps); + + /* + * Currently firmware sends only one bss information in-case + * of both hotlist ap found and lost. + */ + for (j = 0; j < numap; j++) { + dest_ap->rssi = 0; + dest_ap->channel = src_hotlist->channel; + dest_ap->ts = src_hotlist->tstamp; + ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; + dest_ap->rtt = src_hotlist->rtt; + dest_ap->rtt_sd = src_hotlist->rtt_sd; + dest_ap->beaconPeriod = src_hotlist->beacon_interval; + dest_ap->capability = src_hotlist->capabilities; + dest_ap->ieLength = src_hotlist->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + dest_ap->bssid.bytes); + cdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + dest_ap++; + src_hotlist++; + } + dest_hotlist->ap_found = ap_found; + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); + WMA_LOGI("%s: sending hotlist match event to hdd", __func__); + cdf_mem_free(dest_hotlist); + return 0; +} + +/** wma_extscan_find_unique_scan_ids() - find unique scan ids + * @cmd_param_info: event data. + * + * This utility function parses the input bss table of information + * and find the unique number of scan ids + * + * Return: 0 on success; error number otherwise + */ +static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int prev_scan_id, scan_ids_cnt, i; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + + /* Find the unique number of scan_id's for grouping */ + prev_scan_id = src_rssi->scan_cycle_id; + scan_ids_cnt = 1; + for (i = 1; i < event->num_entries_in_page; i++) { + src_rssi++; + + if (prev_scan_id != src_rssi->scan_cycle_id) { + scan_ids_cnt++; + prev_scan_id = src_rssi->scan_cycle_id; + } + } + + return scan_ids_cnt; +} + +/** wma_fill_num_results_per_scan_id() - fill number of bss per scan id + * @cmd_param_info: event data. + * @scan_id_group: pointer to scan id group. + * + * This utility function parses the input bss table of information + * and finds how many bss are there per unique scan id. + * + * Return: 0 on success; error number otherwise + */ +static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_result *scan_id_group) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, prev_scan_id; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_scan_id_grp = scan_id_group; + + prev_scan_id = src_rssi->scan_cycle_id; + + t_scan_id_grp->scan_id = src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->num_results = 1; + for (i = 1; i < event->num_entries_in_page; i++) { + src_rssi++; + if (prev_scan_id == src_rssi->scan_cycle_id) { + t_scan_id_grp->num_results++; + } else { + t_scan_id_grp++; + prev_scan_id = t_scan_id_grp->scan_id = + src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->num_results = 1; + } + } + return 0; +} + +/** wma_group_num_bss_to_scan_id() - group bss to scan id table + * @cmd_param_info: event data. + * @cached_result: pointer to cached table. + * + * This function reads the bss information from the format + * ------------------------------------------------------------------------ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags | + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags | + * ........................................................................ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags | + * ------------------------------------------------------------------------ + * + * and converts it into the below format and store it + * + * ------------------------------------------------------------------------ + * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1 + * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2 + * ...................... + * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn + * ------------------------------------------------------------------------ + * + * Return: 0 on success; error number otherwise + */ +static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_results *cached_result) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_results *t_cached_result; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, j; + tSirWifiScanResult *ap; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_cached_result = cached_result; + t_scan_id_grp = &t_cached_result->result[0]; + + WMA_LOGD("%s: num_scan_ids:%d", __func__, + t_cached_result->num_scan_ids); + for (i = 0; i < t_cached_result->num_scan_ids; i++) { + WMA_LOGD("%s: num_results:%d", __func__, + t_scan_id_grp->num_results); + t_scan_id_grp->ap = cdf_mem_malloc(t_scan_id_grp->num_results * + sizeof(*ap)); + if (!t_scan_id_grp->ap) { + WMA_LOGD("%s: cdf_mem_malloc failed", __func__); + return -ENOMEM; + } + + ap = &t_scan_id_grp->ap[0]; + for (j = 0; j < t_scan_id_grp->num_results; j++) { + ap->channel = src_hotlist->channel; + ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp); + ap->rtt = src_hotlist->rtt; + ap->rtt_sd = src_hotlist->rtt_sd; + ap->beaconPeriod = src_hotlist->beacon_interval; + ap->capability = src_hotlist->capabilities; + ap->ieLength = src_hotlist->ie_length; + + /* Firmware already applied noise floor adjustment and + * due to WMI interface "UINT32 rssi", host driver + * receives a positive value, hence convert to + * signed char to get the absolute rssi. + */ + ap->rssi = (signed char) src_rssi->rssi; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + ap->bssid.bytes); + + cdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + ap++; + src_rssi++; + src_hotlist++; + } + t_scan_id_grp++; + } + return 0; +} + +/** + * wma_extscan_cached_results_event_handler() - cached results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length of @cmd_param_info + * + * This function handles cached results event and indicate + * cached results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + struct extscan_cached_scan_results *dest_cachelist; + struct extscan_cached_scan_result *dest_result; + struct extscan_cached_scan_results empty_cachelist; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int numap, i, moredata, scan_ids_cnt, buf_len; + + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid cached results event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + numap = event->num_entries_in_page; + WMA_LOGI("Total_entries %u first_entry_index %u", event->total_entries, + event->first_entry_index); + WMA_LOGI("num_entries_in_page %d", numap); + if (!src_hotlist || !src_rssi || !numap) { + WMA_LOGE("%s: Cached results empty, send 0 results", __func__); + goto noresults; + } + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + moredata = 1; + else + moredata = 0; + + dest_cachelist = cdf_mem_malloc(sizeof(*dest_cachelist)); + if (!dest_cachelist) { + WMA_LOGE("%s: cdf_mem_malloc failed", __func__); + return -ENOMEM; + } + cdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist)); + dest_cachelist->request_id = event->request_id; + dest_cachelist->more_data = moredata; + + scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info); + WMA_LOGI("%s: scan_ids_cnt %d", __func__, scan_ids_cnt); + dest_cachelist->num_scan_ids = scan_ids_cnt; + + buf_len = sizeof(*dest_result) * scan_ids_cnt; + dest_cachelist->result = cdf_mem_malloc(buf_len); + if (!dest_cachelist->result) { + WMA_LOGE("%s: Allocation failed for scanid grouping", __func__); + cdf_mem_free(dest_cachelist); + return -ENOMEM; + } + + dest_result = dest_cachelist->result; + wma_fill_num_results_per_scan_id(cmd_param_info, dest_result); + wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist); + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + dest_cachelist); + WMA_LOGI("%s: sending cached results event", __func__); + dest_result = dest_cachelist->result; + for (i = 0; i < dest_cachelist->num_scan_ids; i++) { + cdf_mem_free(dest_result->ap); + dest_result++; + } + cdf_mem_free(dest_cachelist->result); + cdf_mem_free(dest_cachelist); + return 0; + +noresults: + empty_cachelist.request_id = event->request_id; + empty_cachelist.more_data = 0; + empty_cachelist.num_scan_ids = 0; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + &empty_cachelist); + WMA_LOGI("%s: sending cached results event", __func__); + return 0; +} + +/** + * wma_extscan_change_results_event_handler() - change results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles change results event and indicate + * change results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_wlan_change_results_event_fixed_param *event; + tSirWifiSignificantChangeEvent *dest_chglist; + tSirWifiSignificantChange *dest_ap; + wmi_extscan_wlan_change_result_bssid *src_chglist; + + int numap; + int i, k; + uint8_t *src_rssi; + int count = 0; + int moredata; + int rssi_num = 0; + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid change monitor event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_chglist = param_buf->bssid_signal_descriptor_list; + src_rssi = param_buf->rssi_list; + numap = event->num_entries_in_page; + + if (!src_chglist || !numap) { + WMA_LOGE("%s: Results invalid", __func__); + return -EINVAL; + } + for (i = 0; i < numap; i++) { + rssi_num += src_chglist->num_rssi_samples; + } + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) { + moredata = 1; + } else { + moredata = 0; + } + dest_chglist = cdf_mem_malloc(sizeof(*dest_chglist) + + sizeof(*dest_ap) * numap + + sizeof(int32_t) * rssi_num); + if (!dest_chglist) { + WMA_LOGE("%s: Allocation failed for change monitor", __func__); + return -ENOMEM; + } + dest_ap = &dest_chglist->ap[0]; + for (i = 0; i < numap; i++) { + dest_ap->channel = src_chglist->channel; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid, + dest_ap->bssid.bytes); + dest_ap->numOfRssi = src_chglist->num_rssi_samples; + if (dest_ap->numOfRssi) { + for (k = 0; k < dest_ap->numOfRssi; k++) { + dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM + + src_rssi[count++]; + } + } + dest_ap += dest_ap->numOfRssi * sizeof(int32_t); + src_chglist++; + } + dest_chglist->requestId = event->request_id; + dest_chglist->moreData = moredata; + dest_chglist->numResults = event->total_entries; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + dest_chglist); + WMA_LOGI("%s: sending change monitor results", __func__); + cdf_mem_free(dest_chglist); + return 0; +} + +/** + * wma_passpoint_match_event_handler() - passpoint match found event handler + * @handle: WMA handle + * @cmd_param_info: event data + * @len: event data length + * + * This is the passpoint match found event handler; it reads event data from + * @cmd_param_info and fill in the destination buffer and sends indication + * up layer. + * + * Return: 0 on success; error number otherwise + */ +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf; + wmi_passpoint_event_hdr *event; + struct wifi_passpoint_match *dest_match; + tSirWifiScanResult *dest_ap; + uint8_t *buf_ptr; + tpAniSirGlobal mac = cds_get_context(CDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + if (!mac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid passpoint match event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + buf_ptr = (uint8_t *)param_buf->fixed_param; + + dest_match = cdf_mem_malloc(sizeof(*dest_match) + + event->ie_length + event->anqp_length); + if (!dest_match) { + WMA_LOGE("%s: cdf_mem_malloc failed", __func__); + return -EINVAL; + } + dest_ap = &dest_match->ap; + dest_match->request_id = 0; + dest_match->id = event->id; + dest_match->anqp_len = event->anqp_length; + WMA_LOGI("%s: passpoint match: id: %u anqp length %u", __func__, + dest_match->id, dest_match->anqp_len); + + dest_ap->channel = event->channel_mhz; + dest_ap->ts = event->timestamp; + dest_ap->rtt = event->rtt; + dest_ap->rssi = event->rssi; + dest_ap->rtt_sd = event->rtt_sd; + dest_ap->beaconPeriod = event->beacon_period; + dest_ap->capability = event->capability; + dest_ap->ieLength = event->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes); + cdf_mem_copy(dest_ap->ssid, event->ssid.ssid, + event->ssid.ssid_len); + dest_ap->ssid[event->ssid.ssid_len] = '\0'; + cdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE, dest_ap->ieLength); + cdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE + dest_ap->ieLength, + dest_match->anqp_len); + + mac->sme.pExtScanIndCb(mac->hHdd, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + dest_match); + WMA_LOGI("%s: sending passpoint match event to hdd", __func__); + cdf_mem_free(dest_match); + return 0; +} + +/** + * wma_extscan_hotlist_ssid_match_event_handler() - + * Handler for SSID hotlist match event from firmware + * @handle: WMA handle + * @cmd_param_info: WMI command buffer + * @len: length of @cmd_param_info + * + * Return: 0 on success, non-zero on failure + */ +int +wma_extscan_hotlist_ssid_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID_param_tlvs *param_buf; + wmi_extscan_hotlist_ssid_match_event_fixed_param *event; + tSirWifiScanResultEvent *dest_hotlist; + tSirWifiScanResult *dest_ap; + wmi_extscan_wlan_descriptor *src_hotlist; + int numap, j; + bool ssid_found = false; + tpAniSirGlobal mac = cds_get_context(CDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + + if (!mac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = (WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid hotlist match event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + src_hotlist = param_buf->hotlist_ssid_match; + numap = event->total_entries; + if (!src_hotlist || !numap) { + WMA_LOGE("%s: Hotlist AP's list invalid", __func__); + return -EINVAL; + } + + dest_hotlist = cdf_mem_malloc(sizeof(*dest_hotlist) + + sizeof(*dest_ap) * numap); + if (!dest_hotlist) { + WMA_LOGE("%s: Allocation failed for hotlist buffer", + __func__); + return -EINVAL; + } + + dest_ap = &dest_hotlist->ap[0]; + dest_hotlist->numOfAps = event->total_entries; + dest_hotlist->requestId = event->config_request_id; + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + dest_hotlist->moreData = 1; + else + dest_hotlist->moreData = 0; + + WMA_LOGD("%s: Hotlist match: requestId: %u,numOfAps: %d", __func__, + dest_hotlist->requestId, dest_hotlist->numOfAps); + + for (j = 0; j < numap; j++) { + dest_ap->channel = src_hotlist->channel; + dest_ap->ts = src_hotlist->tstamp; + ssid_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; + dest_ap->rtt = src_hotlist->rtt; + dest_ap->rtt_sd = src_hotlist->rtt_sd; + dest_ap->beaconPeriod = src_hotlist->beacon_interval; + dest_ap->capability = src_hotlist->capabilities; + dest_ap->ieLength = src_hotlist->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + dest_ap->bssid.bytes); + cdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + dest_ap++; + src_hotlist++; + } + + dest_hotlist->ap_found = ssid_found; + mac->sme.pExtScanIndCb(mac->hHdd, + eSIR_EXTSCAN_HOTLIST_SSID_MATCH_IND, + dest_hotlist); + WMA_LOGI("%s: sending hotlist ssid match event", __func__); + cdf_mem_free(dest_hotlist); + return 0; +} + +/** + * wma_get_buf_extscan_start_cmd() - Fill extscan start request + * @handle: wma handle + * @pstart: scan command request params + * @buf: event buffer + * @buf_len: length of buffer + * + * This function fills individual elements of extscan request and + * TLV for buckets, channel list. + * + * Return: CDF Status. + */ +CDF_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle, + tSirWifiScanCmdReqParams *pstart, + wmi_buf_t *buf, int *buf_len) +{ + wmi_extscan_start_cmd_fixed_param *cmd; + wmi_extscan_bucket *dest_blist; + wmi_extscan_bucket_channel *dest_clist; + tSirWifiScanBucketSpec *src_bucket = pstart->buckets; + tSirWifiScanChannelSpec *src_channel = src_bucket->channels; + tSirWifiScanChannelSpec save_channel[WLAN_EXTSCAN_MAX_CHANNELS]; + + uint8_t *buf_ptr; + int i, k, count = 0; + int len = sizeof(*cmd); + int nbuckets = pstart->numBuckets; + int nchannels = 0; + + /* These TLV's are are NULL by default */ + uint32_t ie_len_with_pad = 0; + int num_ssid = 0; + int num_bssid = 0; + int ie_len = 0; + + uint32_t base_period = pstart->basePeriod; + + /* TLV placeholder for ssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_ssid * sizeof(wmi_ssid); + + /* TLV placeholder for bssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_bssid * sizeof(wmi_mac_addr); + + /* TLV placeholder for ie_data (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += ie_len * sizeof(uint32_t); + + /* TLV placeholder for bucket */ + len += WMI_TLV_HDR_SIZE; + len += nbuckets * sizeof(wmi_extscan_bucket); + + /* TLV channel placeholder */ + len += WMI_TLV_HDR_SIZE; + for (i = 0; i < nbuckets; i++) { + nchannels += src_bucket->numChannels; + src_bucket++; + } + + WMA_LOGD("%s: Total buckets: %d total #of channels is %d", + __func__, nbuckets, nchannels); + len += nchannels * sizeof(wmi_extscan_bucket_channel); + /* Allocate the memory */ + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory" + " for start extscan cmd", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = (wmi_extscan_start_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_start_cmd_fixed_param)); + + cmd->request_id = pstart->requestId; + cmd->vdev_id = pstart->sessionId; + cmd->base_period = pstart->basePeriod; + cmd->num_buckets = nbuckets; + cmd->configuration_flags = 0; + if (pstart->configuration_flags & EXTSCAN_LP_EXTENDED_BATCHING) + cmd->configuration_flags |= WMI_EXTSCAN_EXTENDED_BATCHING_EN; + WMA_LOGI("%s: configuration_flags: 0x%x", __func__, + cmd->configuration_flags); + + cmd->min_rest_time = WMA_EXTSCAN_REST_TIME; + cmd->max_rest_time = WMA_EXTSCAN_REST_TIME; + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + + /* The max dwell time is retrieved from the first channel + * of the first bucket and kept common for all channels. + */ + cmd->min_dwell_time_active = pstart->min_dwell_time_active; + cmd->max_dwell_time_active = pstart->max_dwell_time_active; + cmd->min_dwell_time_passive = pstart->min_dwell_time_passive; + cmd->max_dwell_time_passive = pstart->max_dwell_time_passive; + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + cmd->max_table_usage = pstart->report_threshold_percent; + cmd->report_threshold_num_scans = pstart->report_threshold_num_scans; + + cmd->repeat_probe_time = cmd->max_dwell_time_active / + WMA_SCAN_NPROBES_DEFAULT; + cmd->max_scan_time = WMA_EXTSCAN_MAX_SCAN_TIME; + cmd->probe_delay = 0; + cmd->probe_spacing_time = 0; + cmd->idle_time = 0; + cmd->burst_duration = WMA_EXTSCAN_BURST_DURATION; + cmd->scan_ctrl_flags = WMI_SCAN_ADD_BCAST_PROBE_REQ | + WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; + cmd->scan_priority = WMI_SCAN_PRIORITY_HIGH; + cmd->num_ssids = 0; + cmd->num_bssid = 0; + cmd->ie_len = 0; + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->max_dwell_time_active / cmd->repeat_probe_time : 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_ssid * sizeof(wmi_ssid)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid * sizeof(wmi_ssid)); + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_bssid * sizeof(wmi_mac_addr)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid * sizeof(wmi_mac_addr)); + + ie_len_with_pad = 0; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_with_pad); + buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad; + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nbuckets * sizeof(wmi_extscan_bucket)); + dest_blist = (wmi_extscan_bucket *) + (buf_ptr + WMI_TLV_HDR_SIZE); + src_bucket = pstart->buckets; + + /* Retrieve scanning information from each bucket and + * channels and send it to the target + */ + for (i = 0; i < nbuckets; i++) { + WMITLV_SET_HDR(dest_blist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_extscan_bucket)); + + dest_blist->bucket_id = src_bucket->bucket; + dest_blist->base_period_multiplier = + src_bucket->period / base_period; + dest_blist->min_period = src_bucket->period; + dest_blist->max_period = src_bucket->max_period; + dest_blist->exp_backoff = src_bucket->exponent; + dest_blist->exp_max_step_count = src_bucket->step_count; + dest_blist->channel_band = src_bucket->band; + dest_blist->num_channels = src_bucket->numChannels; + dest_blist->notify_extscan_events = 0; + + if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_EACH_SCAN) + dest_blist->notify_extscan_events = + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT; + + if (src_bucket->reportEvents & + EXTSCAN_REPORT_EVENTS_FULL_RESULTS) { + dest_blist->forwarding_flags = + WMI_EXTSCAN_FORWARD_FRAME_TO_HOST; + dest_blist->notify_extscan_events |= + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT | + WMI_EXTSCAN_CYCLE_STARTED_EVENT | + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT; + } else { + dest_blist->forwarding_flags = + WMI_EXTSCAN_NO_FORWARDING; + } + + if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_NO_BATCH) + dest_blist->configuration_flags = 0; + else + dest_blist->configuration_flags = + WMI_EXTSCAN_BUCKET_CACHE_RESULTS; + + WMA_LOGI("%s: ntfy_extscan_events:%u cfg_flags:%u fwd_flags:%u", + __func__, dest_blist->notify_extscan_events, + dest_blist->configuration_flags, + dest_blist->forwarding_flags); + + dest_blist->min_dwell_time_active = src_bucket->min_dwell_time_active; + dest_blist->max_dwell_time_active = src_bucket->max_dwell_time_active; + dest_blist->min_dwell_time_passive = src_bucket->min_dwell_time_passive; + dest_blist->max_dwell_time_passive = src_bucket->max_dwell_time_passive; + src_channel = src_bucket->channels; + + /* save the channel info to later populate + * the channel TLV + */ + for (k = 0; k < src_bucket->numChannels; k++) { + save_channel[count++].channel = src_channel->channel; + src_channel++; + } + dest_blist++; + src_bucket++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (nbuckets * sizeof(wmi_extscan_bucket)); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nchannels * sizeof(wmi_extscan_bucket_channel)); + dest_clist = (wmi_extscan_bucket_channel *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Active or passive scan is based on the bucket dwell time + * and channel specific active,passive scans are not + * supported yet + */ + for (i = 0; i < nchannels; i++) { + WMITLV_SET_HDR(dest_clist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_bucket_channel)); + dest_clist->channel = save_channel[i].channel; + dest_clist++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (nchannels * sizeof(wmi_extscan_bucket_channel)); + *buf_len = len; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_start_extscan() - start extscan command to fw. + * @handle: wma handle + * @pstart: scan command request params + * + * This function sends start extscan request to fw. + * + * Return: CDF Status. + */ +CDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf; + int len; + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue extscan cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan feature bit not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + /* Fill individual elements of extscan request and + * TLV for buckets, channel list. + */ + cdf_status = wma_get_buf_extscan_start_cmd(wma, pstart, &buf, &len); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to get buffer for ext scan cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + if (!buf) { + WMA_LOGE("%s:Failed to get buffer" + "for current extscan info", __func__); + return CDF_STATUS_E_FAILURE; + } + if (wmi_unified_cmd_send(wma->wmi_handle, buf, + len, WMI_EXTSCAN_START_CMDID)) { + WMA_LOGE("%s: failed to send command", __func__); + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + wma->interfaces[pstart->sessionId].extscan_in_progress = true; + WMA_LOGD("Extscan start request sent successfully for vdev %d", + pstart->sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_stop_extscan() - stop extscan command to fw. + * @handle: wma handle + * @pstopcmd: stop scan command request params + * + * This function sends stop extscan request to fw. + * + * Return: CDF Status. + */ +CDF_STATUS wma_stop_extscan(tp_wma_handle wma, + tSirExtScanStopReqParams *pstopcmd) +{ + wmi_extscan_stop_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_stop_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_stop_cmd_fixed_param)); + + cmd->request_id = pstopcmd->requestId; + cmd->vdev_id = pstopcmd->sessionId; + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_STOP_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + wma->interfaces[pstopcmd->sessionId].extscan_in_progress = false; + WMA_LOGD("Extscan stop request sent successfully for vdev %d", + pstopcmd->sessionId); + + return CDF_STATUS_SUCCESS; +} + +/** wma_get_hotlist_entries_per_page() - hotlist entries per page + * @wmi_handle: wmi handle. + * @cmd: size of command structure. + * @per_entry_size: per entry size. + * + * This utility function calculates how many hotlist entries can + * fit in one page. + * + * Return: number of entries + */ +static inline int wma_get_hotlist_entries_per_page(wmi_unified_t wmi_handle, + size_t cmd_size, + size_t per_entry_size) +{ + uint32_t avail_space = 0; + int num_entries = 0; + uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle); + + /* Calculate number of hotlist entries that can + * be passed in wma message request. + */ + avail_space = max_msg_len - cmd_size; + num_entries = avail_space / per_entry_size; + return num_entries; +} + +/** + * wma_get_buf_extscan_hotlist_cmd() - prepare hotlist command + * @handle: wma handle + * @photlist: hotlist command params + * @buf_len: buffer length + * + * This function fills individual elements for hotlist request and + * TLV for bssid entries + * + * Return: CDF Status. + */ +CDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle, + tSirExtScanSetBssidHotListReqParams * + photlist, int *buf_len) +{ + wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd = NULL; + wmi_extscan_hotlist_entry *dest_hotlist; + tSirAPThresholdParam *src_ap = photlist->ap; + wmi_buf_t buf; + uint8_t *buf_ptr; + + int j, index = 0; + int cmd_len = 0; + int num_entries = 0; + int min_entries = 0; + int numap = photlist->numAp; + int len = sizeof(*cmd); + + len += WMI_TLV_HDR_SIZE; + cmd_len = len; + + /* setbssid hotlist expects the bssid list + * to be non zero value + */ + if (!numap) { + WMA_LOGE("%s: Invalid number of bssid's", __func__); + return CDF_STATUS_E_INVAL; + } + num_entries = wma_get_hotlist_entries_per_page(wma_handle->wmi_handle, + cmd_len, + sizeof(*dest_hotlist)); + + /* Split the hot list entry pages and send multiple command + * requests if the buffer reaches the maximum request size + */ + while (index < numap) { + min_entries = CDF_MIN(num_entries, numap); + len += min_entries * sizeof(wmi_extscan_hotlist_entry); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param)); + + /* Multiple requests are sent until the num_entries_in_page + * matches the total_entries + */ + cmd->request_id = photlist->requestId; + cmd->vdev_id = photlist->sessionId; + cmd->total_entries = numap; + cmd->mode = 1; + cmd->num_entries_in_page = min_entries; + cmd->lost_ap_scan_count = photlist->lost_ap_sample_size; + cmd->first_entry_index = index; + + WMA_LOGD("%s: vdev id:%d total_entries: %d num_entries: %d lost_ap_sample_size: %d", + __func__, cmd->vdev_id, cmd->total_entries, + cmd->num_entries_in_page, + cmd->lost_ap_scan_count); + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + min_entries * sizeof(wmi_extscan_hotlist_entry)); + dest_hotlist = (wmi_extscan_hotlist_entry *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Populate bssid, channel info and rssi + * for the bssid's that are sent as hotlists. + */ + for (j = 0; j < min_entries; j++) { + WMITLV_SET_HDR(dest_hotlist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_hotlist_entry)); + + dest_hotlist->min_rssi = src_ap->low; + WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes, + &dest_hotlist->bssid); + + WMA_LOGD("%s:channel:%d min_rssi %d", + __func__, dest_hotlist->channel, + dest_hotlist->min_rssi); + WMA_LOGD + ("%s: bssid mac_addr31to0: 0x%x, mac_addr47to32: 0x%x", + __func__, dest_hotlist->bssid.mac_addr31to0, + dest_hotlist->bssid.mac_addr47to32); + dest_hotlist++; + src_ap++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (min_entries * sizeof(wmi_extscan_hotlist_entry)); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) { + WMA_LOGE("%s: failed to send command", __func__); + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + index = index + min_entries; + num_entries = numap - min_entries; + len = cmd_len; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_start_hotlist_monitor() - start hotlist monitor + * @wma: wma handle + * @photlist: hotlist request params + * + * This function configures hotlist monitor in fw. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + tSirExtScanSetBssidHotListReqParams + *photlist) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + int len; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + /* Fill individual elements for hotlist request and + * TLV for bssid entries + */ + cdf_status = wma_get_buf_extscan_hotlist_cmd(wma, photlist, &len); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to get buffer" + "for hotlist scan cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_stop_hotlist_monitor() - stop hotlist monitor + * @wma: wma handle + * @photlist_reset: hotlist reset params + * + * This function configures hotlist monitor to stop in fw. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + tSirExtScanResetBssidHotlistReqParams + *photlist_reset) +{ + wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + int hotlist_entries = 0; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + if (!photlist_reset) { + WMA_LOGE("%s: Invalid reset hotlist buffer", __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(*cmd); + + /* reset bssid hotlist with tlv set to 0 */ + len += WMI_TLV_HDR_SIZE; + len += hotlist_entries * sizeof(wmi_extscan_hotlist_entry); + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param)); + + cmd->request_id = photlist_reset->requestId; + cmd->vdev_id = photlist_reset->sessionId; + cmd->mode = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + hotlist_entries * sizeof(wmi_extscan_hotlist_entry)); + buf_ptr += WMI_TLV_HDR_SIZE + + (hotlist_entries * sizeof(wmi_extscan_hotlist_entry)); + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_buf_extscan_change_monitor_cmd() - fill change monitor request + * @wma: wma handle + * @psigchange: change monitor request params + * @buf: wmi buffer + * @buf_len: buffer length + * + * This function fills elements of change monitor request buffer. + * + * Return: CDF status + */ +CDF_STATUS wma_get_buf_extscan_change_monitor_cmd(tp_wma_handle wma_handle, + tSirExtScanSetSigChangeReqParams + *psigchange, wmi_buf_t *buf, + int *buf_len) +{ + wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd; + wmi_extscan_wlan_change_bssid_param *dest_chglist; + uint8_t *buf_ptr; + int j; + int len = sizeof(*cmd); + int numap = psigchange->numAp; + tSirAPThresholdParam *src_ap = psigchange->ap; + + if (!numap) { + WMA_LOGE("%s: Invalid number of bssid's", __func__); + return CDF_STATUS_E_INVAL; + } + len += WMI_TLV_HDR_SIZE; + len += numap * sizeof(wmi_extscan_wlan_change_bssid_param); + + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory for change monitor cmd", + __func__); + return CDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param)); + + cmd->request_id = psigchange->requestId; + cmd->vdev_id = psigchange->sessionId; + cmd->total_entries = numap; + cmd->mode = 1; + cmd->num_entries_in_page = numap; + cmd->lost_ap_scan_count = psigchange->lostApSampleSize; + cmd->max_rssi_samples = psigchange->rssiSampleSize; + cmd->rssi_averaging_samples = psigchange->rssiSampleSize; + cmd->max_out_of_range_count = psigchange->minBreaching; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + dest_chglist = (wmi_extscan_wlan_change_bssid_param *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + for (j = 0; j < numap; j++) { + WMITLV_SET_HDR(dest_chglist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_wlan_change_bssid_param)); + + dest_chglist->lower_rssi_limit = src_ap->low; + dest_chglist->upper_rssi_limit = src_ap->high; + WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes, + &dest_chglist->bssid); + + WMA_LOGD("%s: min_rssi %d", __func__, + dest_chglist->lower_rssi_limit); + dest_chglist++; + src_ap++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + *buf_len = len; + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_start_change_monitor() - send start change monitor cmd + * @wma: wma handle + * @psigchange: change monitor request params + * + * This function sends start change monitor request to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_start_change_monitor(tp_wma_handle wma, + tSirExtScanSetSigChangeReqParams * + psigchange) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + wmi_buf_t buf; + int len; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue extscan cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + /* Fill individual elements of change monitor and + * TLV info ... */ + + cdf_status = wma_get_buf_extscan_change_monitor_cmd(wma, + psigchange, &buf, + &len); + if (cdf_status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to get buffer for change monitor cmd", + __func__); + return CDF_STATUS_E_FAILURE; + } + if (!buf) { + WMA_LOGE("%s: Failed to get buffer", __func__); + return CDF_STATUS_E_FAILURE; + } + if (wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) { + WMA_LOGE("%s: failed to send command", __func__); + cdf_nbuf_free(buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_stop_change_monitor() - send stop change monitor cmd + * @wma: wma handle + * @pResetReq: Reset change request params + * + * This function sends stop change monitor request to fw. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + tSirExtScanResetSignificantChangeReqParams + *pResetReq) +{ + wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + int change_list = 0; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: ext scan not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(*cmd); + + /* reset significant change tlv is set to 0 */ + len += WMI_TLV_HDR_SIZE; + len += change_list * sizeof(wmi_extscan_wlan_change_bssid_param); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param)); + + cmd->request_id = pResetReq->requestId; + cmd->vdev_id = pResetReq->sessionId; + cmd->mode = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + change_list * + sizeof(wmi_extscan_wlan_change_bssid_param)); + buf_ptr += WMI_TLV_HDR_SIZE + (change_list * + sizeof + (wmi_extscan_wlan_change_bssid_param)); + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_get_cached_results() - extscan get cached results + * @wma: wma handle + * @pcached_results: cached results parameters + * + * This function send request to fw to get cached results. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_get_cached_results(tp_wma_handle wma, + tSirExtScanGetCachedResultsReqParams * + pcached_results) +{ + wmi_extscan_get_cached_results_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_get_cached_results_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_get_cached_results_cmd_fixed_param)); + + cmd->request_id = pcached_results->requestId; + cmd->vdev_id = pcached_results->sessionId; + cmd->control_flags = pcached_results->flush; + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_get_capabilities() - extscan get capabilities + * @wma: wma handle + * @pgetcapab: get capabilities params + * + * This function send request to fw to get extscan capabilities. + * + * Return: CDF status + */ +CDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab) +{ + wmi_extscan_get_capabilities_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_FAILURE; + } + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_get_capabilities_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_get_capabilities_cmd_fixed_param)); + + cmd->request_id = pgetcapab->requestId; + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_GET_CAPABILITIES_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +CDF_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma, + struct sir_ipa_offload_enable_disable *ipa_offload) +{ + wmi_ipa_offload_enable_disable_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + u_int8_t *buf_ptr; + ol_txrx_vdev_handle vdev; + struct txrx_pdev_cfg_t *cfg; + int32_t intra_bss_fwd = 0; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", + __func__); + return CDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + ((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD) ? + WMI_SERVICE_HSOFFLOAD : + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT))) { + WMA_LOGE("%s: %s not supported", __func__, + ((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD) ? + "WMI_SERVICE_HSOFFLOAD" : + "WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT")); + return CDF_STATUS_E_FAILURE; + } + + if (ipa_offload->offload_type > STA_RX_DATA_OFFLOAD) { + return CDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed (len=%d)", __func__, len); + return CDF_STATUS_E_NOMEM; + } + + WMA_LOGE("%s: offload_type=%d, enable=%d", __func__, + ipa_offload->offload_type, ipa_offload->enable); + + buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_ipa_offload_enable_disable_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ipa_offload_enable_disable_cmd_fixed_param)); + + cmd->offload_type = ipa_offload->offload_type; + cmd->vdev_id = ipa_offload->vdev_id; + cmd->enable = ipa_offload->enable; + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID)) { + WMA_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + + /* + * Check if VDEV is already deleted. If deleted, don't + * send INTRA BSS FWD WMI command + */ + vdev = wma_find_vdev_by_id(wma, ipa_offload->vdev_id); + if (!vdev) + return CDF_STATUS_SUCCESS; + + /* Disable Intra-BSS FWD offload when gDisableIntraBssFwd=1 in INI */ + cfg = (struct txrx_pdev_cfg_t *)vdev->pdev->ctrl_pdev; + if (!ipa_offload->enable || cfg->rx_fwd_disabled) { + WMA_LOGE("%s: ipa_offload->enable=%d, rx_fwd_disabled=%d", + __func__, + ipa_offload->enable, cfg->rx_fwd_disabled); + intra_bss_fwd = 1; + } + + /* Disable/enable WMI_VDEV_PARAM_INTRA_BSS_FWD */ + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, + ipa_offload->vdev_id, WMI_VDEV_PARAM_INTRA_BSS_FWD, + intra_bss_fwd)) { + WMA_LOGE("Failed to disable WMI_VDEV_PARAM_INTRA_BSS_FWD"); + return CDF_STATUS_E_FAILURE; + } + + return CDF_STATUS_SUCCESS; +} + +/** wma_set_epno_network_list() - set epno network list + * @wma: WMA handle + * @req: epno config params request structure + * + * This function reads the incoming epno config request structure + * and constructs the WMI message to the firmware. + * + * Returns: 0 on success, error number otherwise + */ +CDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + nlo_configured_parameters *nlo_list; + u_int8_t i, *buf_ptr; + wmi_buf_t buf; + uint32_t len; + int ret; + + WMA_LOGD("wma_set_epno_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_NOSUPPORT; + } + + /* TLV place holder for array of structures + * nlo_configured_parameters(nlo_list) */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += sizeof(nlo_configured_parameters) * + CDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (u_int8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_nlo_config_cmd_fixed_param)); + cmd->vdev_id = req->session_id; + cmd->flags = WMI_NLO_CONFIG_ENLO; + + buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param); + + cmd->no_of_ssids = CDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS); + WMA_LOGD("SSID count: %d", cmd->no_of_ssids); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->no_of_ssids * sizeof(nlo_configured_parameters)); + buf_ptr += WMI_TLV_HDR_SIZE; + + nlo_list = (nlo_configured_parameters *) buf_ptr; + for (i = 0; i < cmd->no_of_ssids; i++) { + WMITLV_SET_HDR(&nlo_list[i].tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN(nlo_configured_parameters)); + /* Copy ssid and it's length */ + nlo_list[i].ssid.valid = true; + nlo_list[i].ssid.ssid.ssid_len = req->networks[i].ssid.length; + cdf_mem_copy(nlo_list[i].ssid.ssid.ssid, + req->networks[i].ssid.ssId, + nlo_list[i].ssid.ssid.ssid_len); + WMA_LOGD("index: %d ssid: %.*s len: %d", i, + nlo_list[i].ssid.ssid.ssid_len, + (char *) nlo_list[i].ssid.ssid.ssid, + nlo_list[i].ssid.ssid.ssid_len); + + /* Copy rssi threshold */ + nlo_list[i].rssi_cond.valid = true; + nlo_list[i].rssi_cond.rssi = + req->networks[i].rssi_threshold; + WMA_LOGD("RSSI threshold : %d dBm", + nlo_list[i].rssi_cond.rssi); + + /* Copy pno flags */ + nlo_list[i].bcast_nw_type.valid = true; + nlo_list[i].bcast_nw_type.bcast_nw_type = + req->networks[i].flags; + WMA_LOGD("PNO flags (%u)", + nlo_list[i].bcast_nw_type.bcast_nw_type); + + /* Copy auth bit field */ + nlo_list[i].auth_type.valid = true; + nlo_list[i].auth_type.auth_type = + req->networks[i].auth_bit_field; + WMA_LOGD("Auth bit field (%u)", + nlo_list[i].auth_type.auth_type); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("set ePNO list request sent successfully for vdev %d", + req->session_id); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_passpoint_network_list() - set passpoint network list + * @handle: WMA handle + * @req: passpoint network request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the passpoint configs down to the firmware + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req) +{ + wmi_passpoint_config_cmd_fixed_param *cmd; + u_int8_t i, j, *bytes; + wmi_buf_t buf; + uint32_t len; + int ret; + + WMA_LOGD("wma_set_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_NOSUPPORT; + } + + len = sizeof(*cmd); + for (i = 0; i < req->num_networks; i++) { + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_passpoint_config_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_passpoint_config_cmd_fixed_param)); + cmd->id = req->networks[i].id; + WMA_LOGD("%s: network id: %u", __func__, cmd->id); + cdf_mem_copy(cmd->realm, req->networks[i].realm, + strlen(req->networks[i].realm) + 1); + WMA_LOGD("%s: realm: %s", __func__, cmd->realm); + for (j = 0; j < PASSPOINT_ROAMING_CONSORTIUM_ID_NUM; j++) { + bytes = (uint8_t *) &req->networks[i].roaming_consortium_ids[j]; + WMA_LOGD("index: %d rcids: %02x %02x %02x %02x %02x %02x %02x %02x", + j, bytes[0], bytes[1], bytes[2], bytes[3], + bytes[4], bytes[5], bytes[6], bytes[7]); + + cdf_mem_copy(&cmd->roaming_consortium_ids[j], + &req->networks[i].roaming_consortium_ids[j], + PASSPOINT_ROAMING_CONSORTIUM_ID_LEN); + } + cdf_mem_copy(cmd->plmn, req->networks[i].plmn, + PASSPOINT_PLMN_ID_LEN); + WMA_LOGD("%s: plmn: %02x:%02x:%02x", __func__, + cmd->plmn[0], cmd->plmn[1], cmd->plmn[2]); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PASSPOINT_LIST_CONFIG_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send set passpoint network list wmi cmd", + __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + } + + WMA_LOGD("Set passpoint network list request is sent successfully for vdev %d", + req->session_id); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_reset_passpoint_network_list() - reset passpoint network list + * @handle: WMA handle + * @req: passpoint network request structure + * + * This function sends down WMI command with network id set to wildcard id. + * firmware shall clear all the config entries + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req) +{ + wmi_passpoint_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + int ret; + + WMA_LOGD("wma_reset_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return CDF_STATUS_E_NOSUPPORT; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_passpoint_config_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_passpoint_config_cmd_fixed_param)); + cmd->id = WMI_PASSPOINT_NETWORK_ID_WILDCARD; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PASSPOINT_LIST_CONFIG_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send reset passpoint network list wmi cmd", + __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Reset passpoint network list request is sent successfully for vdev %d", + req->session_id); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_set_ssid_hotlist() - Handle an SSID hotlist set request + * @wma: WMA handle + * @request: SSID hotlist set request from SME + * + * Return: CDF_STATUS enumeration + */ +CDF_STATUS +wma_set_ssid_hotlist(tp_wma_handle wma, + struct sir_set_ssid_hotlist_request *request) +{ + wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint32_t array_size; + uint8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd", + __func__); + return CDF_STATUS_E_FAILURE; + } + if (!request) { + WMA_LOGE("%s: Invalid request buffer", __func__); + return CDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", + __func__); + return CDF_STATUS_E_NOSUPPORT; + } + + /* length of fixed portion */ + len = sizeof(*cmd); + + /* length of variable portion */ + array_size = + request->ssid_count * sizeof(wmi_extscan_hotlist_ssid_entry); + len += WMI_TLV_HDR_SIZE + array_size; + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR + (&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param)); + + cmd->request_id = request->request_id; + cmd->requestor_id = 0; + cmd->vdev_id = request->session_id; + cmd->table_id = 0; + cmd->lost_ap_scan_count = request->lost_ssid_sample_size; + cmd->total_entries = request->ssid_count; + cmd->num_entries_in_page = request->ssid_count; + cmd->first_entry_index = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, array_size); + + if (request->ssid_count) { + wmi_extscan_hotlist_ssid_entry *entry; + int i; + + buf_ptr += WMI_TLV_HDR_SIZE; + entry = (wmi_extscan_hotlist_ssid_entry *)buf_ptr; + for (i = 0; i < request->ssid_count; i++) { + WMITLV_SET_HDR + (entry, + WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_hotlist_ssid_entry)); + entry->ssid.ssid_len = request->ssids[i].ssid.length; + cdf_mem_copy(entry->ssid.ssid, + request->ssids[i].ssid.ssId, + request->ssids[i].ssid.length); + entry->band = request->ssids[i].band; + entry->min_rssi = request->ssids[i].rssi_low; + entry->max_rssi = request->ssids[i].rssi_high; + entry++; + } + cmd->mode = WMI_EXTSCAN_MODE_START; + } else { + cmd->mode = WMI_EXTSCAN_MODE_STOP; + } + + if (wmi_unified_cmd_send + (wma->wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID)) { + WMA_LOGE("%s: failed to send command", __func__); + wmi_buf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_scan_probe_setoui() - set scan probe OUI + * @wma: wma handle + * @psetoui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: CDF status + */ +CDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui) +{ + wmi_scan_prob_req_oui_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + uint32_t *oui_buf; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return CDF_STATUS_E_INVAL; + } + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_scan_prob_req_oui_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_prob_req_oui_cmd_fixed_param)); + + oui_buf = &cmd->prob_req_oui; + cdf_mem_zero(oui_buf, sizeof(cmd->prob_req_oui)); + *oui_buf = psetoui->oui[0] << 16 | psetoui->oui[1] << 8 + | psetoui->oui[2]; + WMA_LOGD("%s: wma:oui received from hdd %08x", __func__, + cmd->prob_req_oui); + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_SCAN_PROB_REQ_OUI_CMDID)) { + WMA_LOGE("%s: failed to send command", __func__); + cdf_nbuf_free(wmi_buf); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_scan_event_callback() - scan event callback + * @handle: wma handle + * @data: event data + * @len: data length + * + * This function process scan event and provide indication + * to upper layers. + * + * Return: 0 for success or error code. + */ +int wma_scan_event_callback(WMA_HANDLE handle, uint8_t *data, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SCAN_EVENTID_param_tlvs *param_buf = NULL; + wmi_scan_event_fixed_param *wmi_event = NULL; + tSirScanOffloadEvent *scan_event; + uint8_t vdev_id; + uint32_t scan_id; + + param_buf = (WMI_SCAN_EVENTID_param_tlvs *) data; + wmi_event = param_buf->fixed_param; + vdev_id = wmi_event->vdev_id; + scan_id = wma_handle->interfaces[vdev_id].scan_info.scan_id; + + if (wma_handle->roam_preauth_scan_id == wmi_event->scan_id) { + /* This is the scan requested by roam preauth set_channel operation */ + + if (wmi_event->event & WMI_SCAN_FINISH_EVENTS) { + WMA_LOGE("roam scan complete: scan_id 0x%x, vdev_id %d", + wmi_event->scan_id, vdev_id); + /*wma_reset_scan_info(wma_handle, vdev_id);*/ + } + + vdev_id = wmi_event->vdev_id; + if (vdev_id >= wma_handle->max_bssid) { + WMA_LOGE("%s:Invalid vdev_id %d wmi_event %p", __func__, + vdev_id, wmi_event); + return -EFAULT; + } + + wma_roam_preauth_scan_event_handler(wma_handle, + vdev_id, wmi_event); + return 0; + + } + + scan_event = (tSirScanOffloadEvent *) cdf_mem_malloc + (sizeof(tSirScanOffloadEvent)); + if (!scan_event) { + WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent"); + return -ENOMEM; + } + + scan_event->event = wmi_event->event; + + WMA_LOGI("WMA <-- wmi_scan_event : event %u, scan_id %u, " + "freq %u, reason %u", + wmi_event->event, wmi_event->scan_id, + wmi_event->channel_freq, wmi_event->reason); + + scan_event->scanId = wmi_event->scan_id; + scan_event->chanFreq = wmi_event->channel_freq; + + if (scan_event->scanId == + wma_handle->interfaces[vdev_id].p2p_scan_info.scan_id) { + scan_event->p2pScanType = P2P_SCAN_TYPE_LISTEN; + if (scan_event->event == SCAN_EVENT_COMPLETED) + wma_reset_p2p_scan_info(wma_handle, vdev_id); + } + scan_event->sessionId = vdev_id; + + if (wmi_event->reason == WMI_SCAN_REASON_COMPLETED || + wmi_event->reason == WMI_SCAN_REASON_TIMEDOUT) + scan_event->reasonCode = eSIR_SME_SUCCESS; + else + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + + switch (wmi_event->event) { + case WMI_SCAN_EVENT_COMPLETED: + case WMI_SCAN_EVENT_DEQUEUED: + /* + * return success always so that SME can pick whatever scan + * results is available in scan cache(due to partial or + * aborted scan) + */ + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SUCCESS; + break; + case WMI_SCAN_EVENT_START_FAILED: + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + break; + case WMI_SCAN_EVENT_PREEMPTED: + WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_PREEMPTED", + __func__); + break; + case WMI_SCAN_EVENT_RESTARTED: + WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_RESTARTED", + __func__); + break; + } + + /* Stop the scan completion timeout if the event is WMI_SCAN_EVENT_COMPLETED */ + if (scan_event->event == (tSirScanEventType) WMI_SCAN_EVENT_COMPLETED) { + WMA_LOGE(" scan complete - scan_id 0x%x, vdev_id %d", + wmi_event->scan_id, vdev_id); + } + + wma_send_msg(wma_handle, WMA_RX_SCAN_EVENT, (void *)scan_event, 0); + return 0; +} + + +/** + * wma_roam_better_ap_handler() - better ap event handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome. + * This event means roam algorithm in Rome has found a better matching + * candidate AP. The indication is sent to SME. + * + * Return: none + */ +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + cds_msg_t cds_msg; + tSirSmeCandidateFoundInd *candidate_ind; + + /* abort existing scans from GUI, but not roaming preauth scan */ + if (wma->interfaces[vdev_id].scan_info.scan_id != 0 && + (wma->interfaces[vdev_id].scan_info.scan_id & + WMA_HOST_ROAM_SCAN_REQID_PREFIX) != + WMA_HOST_ROAM_SCAN_REQID_PREFIX) { + tAbortScanParams abortScan; + abortScan.SessionId = vdev_id; + wma_stop_scan(wma, &abortScan); + } + + candidate_ind = cdf_mem_malloc(sizeof(tSirSmeCandidateFoundInd)); + if (!candidate_ind) { + WMA_LOGE("%s: Alloc failed for tSirSmeCandidateFoundInd", + __func__); + return; + } + + candidate_ind->messageType = eWNI_SME_CANDIDATE_FOUND_IND; + candidate_ind->sessionId = vdev_id; + candidate_ind->length = sizeof(tSirSmeCandidateFoundInd); + + cds_msg.type = eWNI_SME_CANDIDATE_FOUND_IND; + cds_msg.bodyptr = candidate_ind; + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_INFO, + FL("posting candidate ind to SME")); + + if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, + (cds_msg_t *) &cds_msg)) { + cdf_mem_free(candidate_ind); + CDF_TRACE(CDF_MODULE_ID_WMA, CDF_TRACE_LEVEL_ERROR, + FL("Failed to post candidate ind to SME")); + } +} + +/** + * wma_roam_event_callback() - roam event callback + * @handle: wma handle + * @event_buf: event buffer + * @len: buffer length + * + * Handler for all events from roam engine in firmware + * + * Return: 0 for success or error code + */ +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_ROAM_EVENTID_param_tlvs *param_buf; + wmi_roam_event_fixed_param *wmi_event; + + param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGD("%s: Reason %x for vdevid %x, rssi %d", + __func__, wmi_event->reason, wmi_event->vdev_id, + wmi_event->rssi); + + switch (wmi_event->reason) { + case WMI_ROAM_REASON_BMISS: + WMA_LOGD("Beacon Miss for vdevid %x", wmi_event->vdev_id); + wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id); + break; + case WMI_ROAM_REASON_BETTER_AP: + WMA_LOGD("%s:Better AP found for vdevid %x, rssi %d", __func__, + wmi_event->vdev_id, wmi_event->rssi); + wma_handle->suitable_ap_hb_failure = false; + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; + case WMI_ROAM_REASON_SUITABLE_AP: + wma_handle->suitable_ap_hb_failure = true; + WMA_LOGD("%s:Bmiss scan AP found for vdevid %x, rssi %d", + __func__, wmi_event->vdev_id, wmi_event->rssi); + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMI_ROAM_REASON_HO_FAILED: + WMA_LOGE("LFR3:Hand-Off Failed for vdevid %x", + wmi_event->vdev_id); + wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id); + break; +#endif + default: + WMA_LOGD("%s:Unhandled Roam Event %x for vdevid %x", __func__, + wmi_event->reason, wmi_event->vdev_id); + break; + } + return 0; +} + + +/** + * wma_set_rssi_monitoring() - set rssi monitoring + * @handle: WMA handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: 0 on success; error number otherwise + */ +CDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req) +{ + wmi_rssi_breach_monitor_config_fixed_param *cmd; + wmi_buf_t buf; + int ret, len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return CDF_STATUS_E_NOMEM; + } + + cmd = (wmi_rssi_breach_monitor_config_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_rssi_breach_monitor_config_fixed_param)); + + cmd->vdev_id = req->session_id; + cmd->request_id = req->request_id; + cmd->lo_rssi_reenable_hysteresis = 0; + cmd->hi_rssi_reenable_histeresis = 0; + cmd->min_report_interval = 0; + cmd->max_num_report = 1; + if (req->control) { + /* enable one threshold for each min/max */ + cmd->enabled_bitmap = 0x09; + cmd->low_rssi_breach_threshold[0] = req->min_rssi; + cmd->hi_rssi_breach_threshold[0] = req->max_rssi; + } else { + cmd->enabled_bitmap = 0; + cmd->low_rssi_breach_threshold[0] = 0; + cmd->hi_rssi_breach_threshold[0] = 0; + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID"); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGI("Sent WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID to FW"); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_scan_id() - Generates scan id + * @scan_id: Scan id + * + * This function generates the scan id. + * + * Return: CDF_STATUS + */ + +CDF_STATUS wma_get_scan_id(uint32_t *scan_id) +{ + tp_wma_handle wma = cds_get_context(CDF_MODULE_ID_WMA); + + if (!scan_id) { + WMA_LOGE("Scan_id is NULL"); + return CDF_STATUS_E_FAULT; + } + + /* host need to cycle through the lower 12 bits to generate ids */ + *scan_id = cdf_atomic_inc_return(&wma->scan_id_counter) & + WMA_SCAN_ID_MASK; + /* + * Firmware expects the host scan request id appended + * by PREFIX 0xA000 + */ + *scan_id = *scan_id | WMI_HOST_SCAN_REQ_ID_PREFIX; + return CDF_STATUS_SUCCESS; +} + diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c new file mode 100644 index 0000000000..1411a3511e --- /dev/null +++ b/core/wma/src/wma_utils.c @@ -0,0 +1,3526 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_utis.c + * This file contains utilities and stats related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include "wlan_tgt_def_config.h" + +#include "cdf_nbuf.h" +#include "cdf_types.h" +#include "ol_txrx_api.h" +#include "cdf_memory.h" +#include "ol_txrx_types.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +/* MCS Based rate table */ +/* HT MCS parameters with Nss = 1 */ +static struct index_data_rate_type supported_mcs_rate_nss1[] = { + /* MCS L20 L40 S20 S40 */ + {0, {65, 135, 72, 150} }, + {1, {130, 270, 144, 300} }, + {2, {195, 405, 217, 450} }, + {3, {260, 540, 289, 600} }, + {4, {390, 810, 433, 900} }, + {5, {520, 1080, 578, 1200} }, + {6, {585, 1215, 650, 1350} }, + {7, {650, 1350, 722, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static struct index_data_rate_type supported_mcs_rate_nss2[] = { + /* MCS L20 L40 S20 S40 */ + {0, {130, 270, 144, 300} }, + {1, {260, 540, 289, 600} }, + {2, {390, 810, 433, 900} }, + {3, {520, 1080, 578, 1200} }, + {4, {780, 1620, 867, 1800} }, + {5, {1040, 2160, 1156, 2400} }, + {6, {1170, 2430, 1300, 2700} }, + {7, {1300, 2700, 1444, 3000} } +}; + +#ifdef WLAN_FEATURE_11AC +/* MCS Based VHT rate table */ +/* MCS parameters with Nss = 1*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { + /* MCS L80 S80 L40 S40 L20 S40 */ + {0, {293, 325}, {135, 150}, {65, 72} }, + {1, {585, 650}, {270, 300}, {130, 144} }, + {2, {878, 975}, {405, 450}, {195, 217} }, + {3, {1170, 1300}, {540, 600}, {260, 289} }, + {4, {1755, 1950}, {810, 900}, {390, 433} }, + {5, {2340, 2600}, {1080, 1200}, {520, 578} }, + {6, {2633, 2925}, {1215, 1350}, {585, 650} }, + {7, {2925, 3250}, {1350, 1500}, {650, 722} }, + {8, {3510, 3900}, {1620, 1800}, {780, 867} }, + {9, {3900, 4333}, {1800, 2000}, {780, 867} } +}; + +/*MCS parameters with Nss = 2*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { + /* MCS L80 S80 L40 S40 L20 S40 */ + {0, {585, 650}, {270, 300}, {130, 144} }, + {1, {1170, 1300}, {540, 600}, {260, 289} }, + {2, {1755, 1950}, {810, 900}, {390, 433} }, + {3, {2340, 2600}, {1080, 1200}, {520, 578} }, + {4, {3510, 3900}, {1620, 1800}, {780, 867} }, + {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, + {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, + {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, + {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, + {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } +}; +#endif /* WLAN_FEATURE_11AC */ + +#ifdef BIG_ENDIAN_HOST + +/* ############# function definitions ############ */ + +/** + * wma_swap_bytes() - swap bytes + * @pv: buffer + * @n: swap bytes + * + * Return: none + */ +void wma_swap_bytes(void *pv, uint32_t n) +{ + int32_t no_words; + int32_t i; + uint32_t *word_ptr; + + no_words = n / sizeof(uint32_t); + word_ptr = (uint32_t *) pv; + for (i = 0; i < no_words; i++) { + *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i)); + } +} + +#define SWAPME(x, len) wma_swap_bytes(&x, len); +#endif /* BIG_ENDIAN_HOST */ + +/** + * wma_get_mcs_idx() - get mcs index + * @maxRate: max rate + * @rate_flags: rate flags + * @nss: number of nss + * @mcsRateFlag: mcs rate flag + * + * Return: return mcs index + */ +static uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags, + uint8_t nss, uint8_t *mcsRateFlag) +{ + uint8_t rateFlag = 0, curIdx = 0; + uint16_t curRate; + bool found = false; +#ifdef WLAN_FEATURE_11AC + struct index_vht_data_rate_type *supported_vht_mcs_rate; +#endif /* WLAN_FEATURE_11AC */ + struct index_data_rate_type *supported_mcs_rate; + + WMA_LOGD("%s rate:%d rate_flgs:%d", __func__, maxRate, rate_flags); +#ifdef WLAN_FEATURE_11AC + supported_vht_mcs_rate = (struct index_vht_data_rate_type *) + ((nss == 1) ? &supported_vht_mcs_rate_nss1 : + &supported_vht_mcs_rate_nss2); +#endif /* WLAN_FEATURE_11AC */ + supported_mcs_rate = (struct index_data_rate_type *) + ((nss == 1) ? &supported_mcs_rate_nss1 : &supported_mcs_rate_nss2); + + *mcsRateFlag = rate_flags; + *mcsRateFlag &= ~eHAL_TX_RATE_SGI; +#ifdef WLAN_FEATURE_11AC + if (rate_flags & + (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | eHAL_TX_RATE_VHT80)) { + + if (rate_flags & eHAL_TX_RATE_VHT80) { + for (curIdx = 0; curIdx < MAX_VHT_MCS_IDX; curIdx++) { + rateFlag = 0; + if (curIdx >= 7) { + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 0x1; + } + + curRate = supported_vht_mcs_rate[curIdx].supported_VHT80_rate[rateFlag]; + if (curRate == maxRate) { + found = true; + break; + } + } + } + + if ((found == false) && + ((rate_flags & eHAL_TX_RATE_VHT80) || + (rate_flags & eHAL_TX_RATE_VHT40))) { + for (curIdx = 0; curIdx < MAX_VHT_MCS_IDX; curIdx++) { + rateFlag = 0; + if (curIdx >= 7) { + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 0x1; + } + + curRate = supported_vht_mcs_rate[curIdx].supported_VHT40_rate[rateFlag]; + if (curRate == maxRate) { + found = true; + *mcsRateFlag &= ~eHAL_TX_RATE_VHT80; + break; + } + } + } + + if ((found == false) && + ((rate_flags & eHAL_TX_RATE_VHT80) || + (rate_flags & eHAL_TX_RATE_VHT40) || + (rate_flags & eHAL_TX_RATE_VHT20))) { + for (curIdx = 0; curIdx < MAX_VHT_MCS_IDX; curIdx++) { + rateFlag = 0; + if (curIdx >= 7) { + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 0x1; + } + + curRate = supported_vht_mcs_rate[curIdx].supported_VHT20_rate[rateFlag]; + if (curRate == maxRate) { + found = true; + *mcsRateFlag &= + ~(eHAL_TX_RATE_VHT80 | + eHAL_TX_RATE_VHT40); + break; + } + } + } + } +#endif /* WLAN_FEATURE_11AC */ + if ((found == false) && + (rate_flags & (eHAL_TX_RATE_HT40 | eHAL_TX_RATE_HT20))) { + if (rate_flags & eHAL_TX_RATE_HT40) { + rateFlag = 0x1; + + for (curIdx = 0; curIdx < MAX_HT_MCS_IDX; curIdx++) { + if (curIdx == 7) { + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 0x2; + } + + curRate = supported_mcs_rate[curIdx].supported_rate[rateFlag]; + if (curRate == maxRate) { + found = true; + *mcsRateFlag = eHAL_TX_RATE_HT40; + break; + } + } + } + + if (found == false) { + rateFlag = 0; + for (curIdx = 0; curIdx < MAX_HT_MCS_IDX; curIdx++) { + if (curIdx == 7) { + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 0x2; + } + + curRate = supported_mcs_rate[curIdx].supported_rate[rateFlag]; + if (curRate == maxRate) { + found = true; + *mcsRateFlag = eHAL_TX_RATE_HT20; + break; + } + } + } + } + + /*SGI rates are used by firmware only for MCS >= 7 */ + if (found && (curIdx >= 7)) + *mcsRateFlag |= eHAL_TX_RATE_SGI; + + return found ? curIdx : INVALID_MCS_IDX; +} + +/** + * host_map_smps_mode() - map fw smps mode to tSmpsModeValue + * @fw_smps_mode: fw smps mode + * + * Return: return tSmpsModeValue + */ +tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode) +{ + tSmpsModeValue smps_mode = SMPS_MODE_DISABLED; + switch (fw_smps_mode) { + case WMI_SMPS_FORCED_MODE_STATIC: + smps_mode = STATIC_SMPS_MODE; + break; + case WMI_SMPS_FORCED_MODE_DYNAMIC: + smps_mode = DYNAMIC_SMPS_MODE; + break; + default: + smps_mode = SMPS_MODE_DISABLED; + } + + return smps_mode; +} + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_event_handler() - extended stats event handler + * @handle: wma handle + * @event_buf: event buffer received from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_STATS_EXT_EVENTID_param_tlvs *param_buf; + tSirStatsExtEvent *stats_ext_event; + wmi_stats_ext_event_fixed_param *stats_ext_info; + CDF_STATUS status; + cds_msg_t cds_msg; + uint8_t *buf_ptr; + uint32_t alloc_len; + + WMA_LOGD("%s: Posting stats ext event to SME", __func__); + + param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid stats ext event buf", __func__); + return -EINVAL; + } + + stats_ext_info = param_buf->fixed_param; + buf_ptr = (uint8_t *) stats_ext_info; + + alloc_len = sizeof(tSirStatsExtEvent); + alloc_len += stats_ext_info->data_len; + + stats_ext_event = (tSirStatsExtEvent *) cdf_mem_malloc(alloc_len); + if (NULL == stats_ext_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return -ENOMEM; + } + + buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + + stats_ext_event->vdev_id = stats_ext_info->vdev_id; + stats_ext_event->event_data_len = stats_ext_info->data_len; + cdf_mem_copy(stats_ext_event->event_data, + buf_ptr, stats_ext_event->event_data_len); + + cds_msg.type = eWNI_SME_STATS_EXT_EVENT; + cds_msg.bodyptr = (void *)stats_ext_event; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post stats ext event to SME", __func__); + cdf_mem_free(stats_ext_event); + return -EFAULT; + } + + WMA_LOGD("%s: stats ext event Posted to SME", __func__); + return 0; +} +#endif /* WLAN_FEATURE_STATS_EXT */ + + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * wma_unified_link_peer_stats_event_handler() - peer stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_peer_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_peer_stats_event_fixed_param *fixed_param; + wmi_peer_link_stats *peer_stats, *temp_peer_stats; + wmi_rate_stats *rate_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_peer_stats, *t_rate_stats; + uint32_t count, num_rates = 0; + uint32_t next_res_offset, next_peer_offset, next_rate_offset; + size_t peer_info_size, peer_stats_size, rate_stats_size; + size_t link_stats_results_size; + + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting Peer Stats event to HDD", __func__); + param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + /* + * cmd_param_info contains + * wmi_peer_stats_event_fixed_param fixed_param; + * num_peers * size of(struct wmi_peer_link_stats) + * num_rates * size of(struct wmi_rate_stats) + * num_rates is the sum of the rates of all the peers. + */ + fixed_param = param_tlvs->fixed_param; + peer_stats = param_tlvs->peer_stats; + rate_stats = param_tlvs->peer_rate_stats; + + if (!fixed_param || !peer_stats || + (peer_stats->num_rates && !rate_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__); + return -EINVAL; + } + + /* + * num_rates - sum of the rates of all the peers + */ + temp_peer_stats = (wmi_peer_link_stats *) peer_stats; + for (count = 0; count < fixed_param->num_peers; count++) { + num_rates += temp_peer_stats->num_rates; + temp_peer_stats++; + } + + peer_stats_size = sizeof(tSirWifiPeerStat); + peer_info_size = sizeof(tSirWifiPeerInfo); + rate_stats_size = sizeof(tSirWifiRateStat); + link_stats_results_size = + sizeof(*link_stats_results) + peer_stats_size + + (fixed_param->num_peers * peer_info_size) + + (num_rates * rate_stats_size); + + link_stats_results = cdf_mem_malloc(link_stats_results_size); + if (NULL == link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + + WMA_LOGD("Peer stats from FW event buf"); + WMA_LOGD("Fixed Param:"); + WMA_LOGD("request_id %u num_peers %u peer_event_number %u more_data %u", + fixed_param->request_id, fixed_param->num_peers, + fixed_param->peer_event_number, fixed_param->more_data); + + cdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = 0; + link_stats_results->num_peers = fixed_param->num_peers; + link_stats_results->peer_event_number = fixed_param->peer_event_number; + link_stats_results->moreResultToFollow = fixed_param->more_data; + + cdf_mem_copy(link_stats_results->results, + &fixed_param->num_peers, peer_stats_size); + + results = (uint8_t *) link_stats_results->results; + t_peer_stats = (uint8_t *) peer_stats; + t_rate_stats = (uint8_t *) rate_stats; + next_res_offset = peer_stats_size; + next_peer_offset = WMI_TLV_HDR_SIZE; + next_rate_offset = WMI_TLV_HDR_SIZE; + for (count = 0; count < fixed_param->num_peers; count++) { + WMA_LOGD("Peer Info:"); + WMA_LOGD("peer_type %u capabilities %u num_rates %u", + peer_stats->peer_type, peer_stats->capabilities, + peer_stats->num_rates); + + cdf_mem_copy(results + next_res_offset, + t_peer_stats + next_peer_offset, peer_info_size); + next_res_offset += peer_info_size; + + /* Copy rate stats associated with this peer */ + for (count = 0; count < peer_stats->num_rates; count++) { + WMA_LOGD("Rate Stats Info:"); + WMA_LOGD("rate %u bitrate %u tx_mpdu %u rx_mpdu %u " + "mpdu_lost %u retries %u retries_short %u " + "retries_long %u", rate_stats->rate, + rate_stats->bitrate, rate_stats->tx_mpdu, + rate_stats->rx_mpdu, rate_stats->mpdu_lost, + rate_stats->retries, rate_stats->retries_short, + rate_stats->retries_long); + rate_stats++; + + cdf_mem_copy(results + next_res_offset, + t_rate_stats + next_rate_offset, + rate_stats_size); + next_res_offset += rate_stats_size; + next_rate_offset += sizeof(*rate_stats); + } + next_peer_offset += sizeof(*peer_stats); + peer_stats++; + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + WMA_LOGD("%s: Peer Stats event posted to HDD", __func__); + cdf_mem_free(link_stats_results); + + return 0; +} + + +/** + * wma_unified_link_radio_stats_event_handler() - radio link stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_radio_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_radio_link_stats_event_fixed_param *fixed_param; + wmi_radio_link_stats *radio_stats; + wmi_channel_stats *channel_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_radio_stats, *t_channel_stats; + uint32_t next_res_offset, next_chan_offset, count; + size_t radio_stats_size, chan_stats_size; + size_t link_stats_results_size; + + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting Radio Stats event to HDD", __func__); + param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_radio_link_stats_event_fixed_param fixed_param; + * size of(struct wmi_radio_link_stats); + * num_channels * size of(struct wmi_channel_stats) + */ + fixed_param = param_tlvs->fixed_param; + radio_stats = param_tlvs->radio_stats; + channel_stats = param_tlvs->channel_stats; + + if (!fixed_param || !radio_stats || + (radio_stats->num_channels && !channel_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__); + return -EINVAL; + } + + radio_stats_size = sizeof(tSirWifiRadioStat); + chan_stats_size = sizeof(tSirWifiChannelStats); + link_stats_results_size = sizeof(*link_stats_results) + + radio_stats_size + (radio_stats->num_channels * chan_stats_size); + + link_stats_results = cdf_mem_malloc(link_stats_results_size); + if (NULL == link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + + WMA_LOGD("Radio stats from FW event buf"); + WMA_LOGD("Fixed Param:"); + WMA_LOGD("request_id %u num_radio %u more_radio_events %u", + fixed_param->request_id, fixed_param->num_radio, + fixed_param->more_radio_events); + + WMA_LOGD("Radio Info"); + WMA_LOGD("radio_id %u on_time %u tx_time %u rx_time %u on_time_scan %u " + "on_time_nbd %u on_time_gscan %u on_time_roam_scan %u " + "on_time_pno_scan %u on_time_hs20 %u num_channels %u", + radio_stats->radio_id, radio_stats->on_time, + radio_stats->tx_time, radio_stats->rx_time, + radio_stats->on_time_scan, radio_stats->on_time_nbd, + radio_stats->on_time_gscan, + radio_stats->on_time_roam_scan, + radio_stats->on_time_pno_scan, + radio_stats->on_time_hs20, radio_stats->num_channels); + + cdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_RADIO; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = 0; + link_stats_results->num_radio = fixed_param->num_radio; + link_stats_results->peer_event_number = 0; + link_stats_results->moreResultToFollow = fixed_param->more_radio_events; + + results = (uint8_t *) link_stats_results->results; + t_radio_stats = (uint8_t *) radio_stats; + t_channel_stats = (uint8_t *) channel_stats; + + cdf_mem_copy(results, t_radio_stats + WMI_TLV_HDR_SIZE, + radio_stats_size); + + next_res_offset = radio_stats_size; + next_chan_offset = WMI_TLV_HDR_SIZE; + WMA_LOGD("Channel Stats Info"); + for (count = 0; count < radio_stats->num_channels; count++) { + WMA_LOGD("channel_width %u center_freq %u center_freq0 %u " + "center_freq1 %u radio_awake_time %u cca_busy_time %u", + channel_stats->channel_width, + channel_stats->center_freq, + channel_stats->center_freq0, + channel_stats->center_freq1, + channel_stats->radio_awake_time, + channel_stats->cca_busy_time); + channel_stats++; + + cdf_mem_copy(results + next_res_offset, + t_channel_stats + next_chan_offset, + chan_stats_size); + next_res_offset += chan_stats_size; + next_chan_offset += sizeof(*channel_stats); + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + WMA_LOGD("%s: Radio Stats event posted to HDD", __func__); + cdf_mem_free(link_stats_results); + + return 0; +} + +/** + * wma_register_ll_stats_event_handler() - register link layer stats related + * event handler + * @wma_handle: wma handle + * + * Return: none + */ +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return; + } + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_IFACE_LINK_STATS_EVENTID, + wma_unified_link_iface_stats_event_handler); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_LINK_STATS_EVENTID, + wma_unified_link_peer_stats_event_handler); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RADIO_LINK_STATS_EVENTID, + wma_unified_link_radio_stats_event_handler); + + return; +} + + +/** + * wma_process_ll_stats_clear_req() - clear link layer stats + * @wma: wma handle + * @clearReq: ll stats clear request command params + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_process_ll_stats_clear_req + (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq) +{ + wmi_clear_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (!clearReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + cmd = (wmi_clear_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_clear_link_stats_cmd_fixed_param)); + + cmd->stop_stats_collection_req = clearReq->stopReq; + cmd->vdev_id = clearReq->staId; + cmd->stats_clear_req_mask = clearReq->statsClearReqMask; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[clearReq->staId].addr, + &cmd->peer_macaddr); + + WMA_LOGD("LINK_LAYER_STATS - Clear Request Params"); + WMA_LOGD("StopReq : %d", cmd->stop_stats_collection_req); + WMA_LOGD("Vdev Id : %d", cmd->vdev_id); + WMA_LOGD("Clear Stat Mask : %d", cmd->stats_clear_req_mask); + WMA_LOGD("Peer MAC Addr : %pM", + wma->interfaces[clearReq->staId].addr); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_CLEAR_LINK_STATS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send clear link stats req", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Clear Link Layer Stats request sent successfully"); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_ll_stats_set_req() - link layer stats set request + * @wma: wma handle + * @setReq: ll stats set request command params + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_process_ll_stats_set_req + (tp_wma_handle wma, const tpSirLLStatsSetReq setReq) +{ + wmi_start_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (!setReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + cmd = (wmi_start_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_link_stats_cmd_fixed_param)); + + cmd->mpdu_size_threshold = setReq->mpduSizeThreshold; + cmd->aggressive_statistics_gathering = + setReq->aggressiveStatisticsGathering; + + WMA_LOGD("LINK_LAYER_STATS - Start/Set Request Params"); + WMA_LOGD("MPDU Size Thresh : %d", cmd->mpdu_size_threshold); + WMA_LOGD("Aggressive Gather: %d", cmd->aggressive_statistics_gathering); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_START_LINK_STATS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send set link stats request", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Set Link Layer Stats request sent successfully"); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_process_ll_stats_get_req() - link layer stats get request + * @wma:wma handle + * @getReq:ll stats get request command params + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_process_ll_stats_get_req + (tp_wma_handle wma, const tpSirLLStatsGetReq getReq) +{ + wmi_request_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (!getReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return CDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + cmd = (wmi_request_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_link_stats_cmd_fixed_param)); + + cmd->request_id = getReq->reqId; + cmd->stats_type = getReq->paramIdMask; + cmd->vdev_id = getReq->staId; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(wma->interfaces[getReq->staId].addr, + &cmd->peer_macaddr); + + WMA_LOGD("LINK_LAYER_STATS - Get Request Params"); + WMA_LOGD("Request ID : %d", cmd->request_id); + WMA_LOGD("Stats Type : %d", cmd->stats_type); + WMA_LOGD("Vdev ID : %d", cmd->vdev_id); + WMA_LOGD("Peer MAC Addr : %pM", wma->interfaces[getReq->staId].addr); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_REQUEST_LINK_STATS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send get link stats request", __func__); + wmi_buf_free(buf); + return CDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Get Link Layer Stats request sent successfully"); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_unified_link_iface_stats_event_handler() - link iface stats event handler + * @wma:wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_iface_link_stats_event_fixed_param *fixed_param; + wmi_iface_link_stats *link_stats; + wmi_wmm_ac_stats *ac_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_link_stats, *t_ac_stats; + uint32_t next_res_offset, next_ac_offset, count; + uint32_t roaming_offset, roaming_size; + size_t link_stats_size, ac_stats_size, iface_info_size; + size_t link_stats_results_size; + + tpAniSirGlobal pMac = cds_get_context(CDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting Iface Stats event to HDD", __func__); + param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_iface_link_stats_event_fixed_param fixed_param; + * wmi_iface_link_stats iface_link_stats; + * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats) + */ + fixed_param = param_tlvs->fixed_param; + link_stats = param_tlvs->iface_link_stats; + ac_stats = param_tlvs->ac; + + if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__); + return -EINVAL; + } + + link_stats_size = sizeof(tSirWifiIfaceStat); + iface_info_size = sizeof(tSirWifiInterfaceInfo); + ac_stats_size = sizeof(tSirWifiWmmAcStat); + link_stats_results_size = sizeof(*link_stats_results) + link_stats_size; + + link_stats_results = cdf_mem_malloc(link_stats_results_size); + if (!link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + + WMA_LOGD("Interface stats from FW event buf"); + WMA_LOGD("Fixed Param:"); + WMA_LOGD("request_id %u vdev_id %u", + fixed_param->request_id, fixed_param->vdev_id); + + WMA_LOGD("Iface Stats:"); + WMA_LOGD("beacon_rx %u mgmt_rx %u mgmt_action_rx %u mgmt_action_tx %u " + "rssi_mgmt %u rssi_data %u rssi_ack %u num_peers %u " + "num_peer_events %u num_ac %u roam_state %u" + " avg_bcn_spread_offset_high %u" + " avg_bcn_spread_offset_low %u" + " is leaky_ap %u" + " avg_rx_frames_leaked %u" + " rx_leak_window %u", + link_stats->beacon_rx, link_stats->mgmt_rx, + link_stats->mgmt_action_rx, link_stats->mgmt_action_tx, + link_stats->rssi_mgmt, link_stats->rssi_data, + link_stats->rssi_ack, link_stats->num_peers, + link_stats->num_peer_events, link_stats->num_ac, + link_stats->roam_state, + link_stats->avg_bcn_spread_offset_high, + link_stats->avg_bcn_spread_offset_low, + link_stats->is_leaky_ap, + link_stats->avg_rx_frms_leaked, + link_stats->rx_leak_window); + + cdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_IFACE; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = fixed_param->vdev_id; + link_stats_results->num_peers = link_stats->num_peers; + link_stats_results->peer_event_number = 0; + link_stats_results->moreResultToFollow = 0; + + results = (uint8_t *) link_stats_results->results; + t_link_stats = (uint8_t *) link_stats; + t_ac_stats = (uint8_t *) ac_stats; + + /* Copy roaming state */ + roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming); + roaming_size = member_size(tSirWifiInterfaceInfo, roaming); + + cdf_mem_copy(results + roaming_offset, &link_stats->roam_state, + roaming_size); + + cdf_mem_copy(results + iface_info_size, + t_link_stats + WMI_TLV_HDR_SIZE, + link_stats_size - iface_info_size - + WIFI_AC_MAX * ac_stats_size); + + next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size; + next_ac_offset = WMI_TLV_HDR_SIZE; + + WMA_LOGD("AC Stats:"); + for (count = 0; count < link_stats->num_ac; count++) { + WMA_LOGD("ac_type %u tx_mpdu %u rx_mpdu %u tx_mcast %u " + "rx_mcast %u rx_ampdu %u tx_ampdu %u mpdu_lost %u " + "retries %u retries_short %u retries_long %u " + "contention_time_min %u contention_time_max %u " + "contention_time_avg %u contention_num_samples %u", + ac_stats->ac_type, ac_stats->tx_mpdu, + ac_stats->rx_mpdu, ac_stats->tx_mcast, + ac_stats->rx_mcast, ac_stats->rx_ampdu, + ac_stats->tx_ampdu, ac_stats->mpdu_lost, + ac_stats->retries, ac_stats->retries_short, + ac_stats->retries_long, ac_stats->contention_time_min, + ac_stats->contention_time_max, + ac_stats->contention_time_avg, + ac_stats->contention_num_samples); + ac_stats++; + + cdf_mem_copy(results + next_res_offset, + t_ac_stats + next_ac_offset, ac_stats_size); + next_res_offset += ac_stats_size; + next_ac_offset += sizeof(*ac_stats); + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + WMA_LOGD("%s: Iface Stats event posted to HDD", __func__); + cdf_mem_free(link_stats_results); + + return 0; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * wma_update_pdev_stats() - update pdev stats + * @wma: wma handle + * @pdev_stats: pdev stats + * + * Return: none + */ +static void wma_update_pdev_stats(tp_wma_handle wma, + wmi_pdev_stats *pdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t temp_mask; + uint8_t *stats_buf; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_PDEV_STATS_SET; + WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = + (tCsrGlobalClassAStatsInfo *) stats_buf; + classa_stats->max_pwr = pdev_stats->chan_tx_pwr; + } + } + } +} + +/** + * wma_update_vdev_stats() - update vdev stats + * @wma: wma handle + * @vdev_stats: vdev stats + * + * Return: none + */ +static void wma_update_vdev_stats(tp_wma_handle wma, + wmi_vdev_stats *vdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrSummaryStatsInfo *summary_stats = NULL; + uint8_t *stats_buf; + struct wma_txrx_node *node; + uint8_t i; + int8_t rssi = 0; + CDF_STATUS cdf_status; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq; + cds_msg_t sme_msg = { 0 }; + + node = &wma->interfaces[vdev_stats->vdev_id]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + stats_buf = (uint8_t *) (stats_rsp_params + 1); + node->fw_stats_set |= FW_VDEV_STATS_SET; + WMA_LOGD("<---FW VDEV STATS received for vdevId:%d", + vdev_stats->vdev_id); + if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) { + summary_stats = (tCsrSummaryStatsInfo *) stats_buf; + for (i = 0; i < 4; i++) { + summary_stats->tx_frm_cnt[i] = + vdev_stats->tx_frm_cnt[i]; + summary_stats->fail_cnt[i] = + vdev_stats->fail_cnt[i]; + summary_stats->multiple_retry_cnt[i] = + vdev_stats->multiple_retry_cnt[i]; + } + + summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt; + summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt; + summary_stats->rx_discard_cnt = + vdev_stats->rx_discard_cnt; + summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt; + summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt; + summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt; + } + } + + WMA_LOGD("vdev id %d beancon snr %d data snr %d", + vdev_stats->vdev_id, + vdev_stats->vdev_snr.bcn_snr, vdev_stats->vdev_snr.dat_snr); + + if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) { + if ((vdev_stats->vdev_snr.bcn_snr == WMA_TGT_INVALID_SNR) && + (vdev_stats->vdev_snr.dat_snr == WMA_TGT_INVALID_SNR)) { + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return the last know + * rssi during connection. + */ + WMA_LOGE("Invalid SNR from firmware"); + + } else { + if (vdev_stats->vdev_snr.bcn_snr != WMA_TGT_INVALID_SNR) { + rssi = vdev_stats->vdev_snr.bcn_snr; + } else if (vdev_stats->vdev_snr.dat_snr != + WMA_TGT_INVALID_SNR) { + rssi = vdev_stats->vdev_snr.dat_snr; + } + + /* + * Get the absolute rssi value from the current rssi value + * the sinr value is hardcoded into 0 in the core stack + */ + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + } + + WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi, + pGetRssiReq->sessionId); + + /* update the average rssi value to UMAC layer */ + if (NULL != pGetRssiReq->rssiCallback) { + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } + + cdf_mem_free(pGetRssiReq); + wma->pGetRssiReq = NULL; + } + + if (node->psnr_req) { + tAniGetSnrReq *p_snr_req = node->psnr_req; + + if (vdev_stats->vdev_snr.bcn_snr != WMA_TGT_INVALID_SNR) + p_snr_req->snr = vdev_stats->vdev_snr.bcn_snr; + else if (vdev_stats->vdev_snr.dat_snr != WMA_TGT_INVALID_SNR) + p_snr_req->snr = vdev_stats->vdev_snr.dat_snr; + else + p_snr_req->snr = WMA_TGT_INVALID_SNR; + + sme_msg.type = eWNI_SME_SNR_IND; + sme_msg.bodyptr = p_snr_req; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("%s: Fail to post snr ind msg", __func__); + cdf_mem_free(p_snr_req); + } + + node->psnr_req = NULL; + } +} + +/** + * wma_post_stats() - update stats to PE + * @wma: wma handle + * @node: txrx node + * + * Return: none + */ +static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node) +{ + tAniGetPEStatsRsp *stats_rsp_params; + + stats_rsp_params = node->stats_rsp; + /* send response to UMAC */ + wma_send_msg(wma, WMA_GET_STATISTICS_RSP, (void *)stats_rsp_params, 0); + node->stats_rsp = NULL; + node->fw_stats_set = 0; +} + +/** + * wma_update_peer_stats() - update peer stats + * @wma: wma handle + * @peer_stats: peer stats + * + * Return: none + */ +static void wma_update_peer_stats(tp_wma_handle wma, + wmi_peer_stats *peer_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags; + uint32_t temp_mask; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]); + if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id)) + return; + + node = &wma->interfaces[vdev_id]; + if (node->stats_rsp) { + node->fw_stats_set |= FW_PEER_STATS_SET; + WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id); + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf; + WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate); + /*The linkspeed returned by fw is in kbps so convert + *it in to units of 500kbps which is expected by UMAC*/ + if (peer_stats->peer_tx_rate) { + classa_stats->tx_rate = + peer_stats->peer_tx_rate / 500; + } + + classa_stats->tx_rate_flags = node->rate_flags; + if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) { + classa_stats->mcs_index = + wma_get_mcs_idx((peer_stats->peer_tx_rate / + 100), node->rate_flags, + node->nss, &mcsRateFlags); + /* rx_frag_cnt and promiscuous_rx_frag_cnt + * parameter is currently not used. lets use the + * same parameter to hold the nss value and mcs + * rate flags */ + classa_stats->rx_frag_cnt = node->nss; + classa_stats->promiscuous_rx_frag_cnt = + mcsRateFlags; + WMA_LOGD("Computed mcs_idx:%d mcs_rate_flags:%d", + classa_stats->mcs_index, mcsRateFlags); + } + /* FW returns tx power in intervals of 0.5 dBm + Convert it back to intervals of 1 dBm */ + classa_stats->max_pwr = + roundup(classa_stats->max_pwr, 2) >> 1; + WMA_LOGD("peer tx rate flags:%d nss:%d max_txpwr:%d", + node->rate_flags, node->nss, + classa_stats->max_pwr); + } + + if (node->fw_stats_set & FW_STATS_SET) { + WMA_LOGD("<--STATS RSP VDEV_ID:%d", vdev_id); + wma_post_stats(wma, node); + } + } +} + +/** + * wma_post_link_status() - post link status to SME + * @pGetLinkStatus: SME Link status + * @link_status: Link status + * + * Return: none + */ +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + + pGetLinkStatus->linkStatus = link_status; + sme_msg.type = eWNI_SME_LINK_STATUS_IND; + sme_msg.bodyptr = pGetLinkStatus; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("%s: Fail to post link status ind msg", __func__); + cdf_mem_free(pGetLinkStatus); + } +} + +/** + * wma_link_status_event_handler() - link status event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_vdev_rate_stats_event_fixed_param *event; + wmi_vdev_rate_ht_info *ht_info; + struct wma_txrx_node *intr = wma->interfaces; + uint8_t link_status = LINK_STATUS_LEGACY; + int i; + + param_buf = + (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + event = (wmi_vdev_rate_stats_event_fixed_param *) param_buf->fixed_param; + ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info; + + WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats); + for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { + WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d", + __func__, ht_info->vdevid, ht_info->tx_nss, + ht_info->rx_nss, ht_info->tx_preamble, + ht_info->rx_preamble); + if (ht_info->vdevid < wma->max_bssid + && intr[ht_info->vdevid].plink_status_req) { + if (ht_info->tx_nss || ht_info->rx_nss) + link_status = LINK_STATUS_MIMO; + + if ((ht_info->tx_preamble == LINK_RATE_VHT) || + (ht_info->rx_preamble == LINK_RATE_VHT)) + link_status |= LINK_STATUS_VHT; + + if (intr[ht_info->vdevid].nss == 2) + link_status |= LINK_SUPPORT_MIMO; + + if (intr[ht_info->vdevid].rate_flags & + (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | + eHAL_TX_RATE_VHT80)) + link_status |= LINK_SUPPORT_VHT; + + wma_post_link_status(intr[ht_info->vdevid].plink_status_req, + link_status); + intr[ht_info->vdevid].plink_status_req = NULL; + link_status = LINK_STATUS_LEGACY; + } + + ht_info++; + } + + return 0; +} + +/** + * wma_stats_event_handler() - stats event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *event; + wmi_pdev_stats *pdev_stats; + wmi_vdev_stats *vdev_stats; + wmi_peer_stats *peer_stats; + uint8_t i, *temp; + + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + temp = (uint8_t *) param_buf->data; + + WMA_LOGD("%s: num_stats: pdev: %u vdev: %u peer %u", + __func__, event->num_pdev_stats, event->num_vdev_stats, + event->num_peer_stats); + if (event->num_pdev_stats > 0) { + for (i = 0; i < event->num_pdev_stats; i++) { + pdev_stats = (wmi_pdev_stats *) temp; + wma_update_pdev_stats(wma, pdev_stats); + temp += sizeof(wmi_pdev_stats); + } + } + + if (event->num_vdev_stats > 0) { + for (i = 0; i < event->num_vdev_stats; i++) { + vdev_stats = (wmi_vdev_stats *) temp; + wma_update_vdev_stats(wma, vdev_stats); + temp += sizeof(wmi_vdev_stats); + } + } + + if (event->num_peer_stats > 0) { + for (i = 0; i < event->num_peer_stats; i++) { + peer_stats = (wmi_peer_stats *) temp; + wma_update_peer_stats(wma, peer_stats); + temp += sizeof(wmi_peer_stats); + } + } + + WMA_LOGI("%s: Exit", __func__); + return 0; +} + +/** + * wma_send_link_speed() - send link speed to SME + * @link_speed: link speed + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_send_link_speed(uint32_t link_speed) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + tSirLinkSpeedInfo *ls_ind = + (tSirLinkSpeedInfo *) cdf_mem_malloc(sizeof(tSirLinkSpeedInfo)); + if (!ls_ind) { + WMA_LOGE("%s: Memory allocation failed.", __func__); + cdf_status = CDF_STATUS_E_NOMEM; + } else { + ls_ind->estLinkSpeed = link_speed; + sme_msg.type = eWNI_SME_LINK_SPEED_IND; + sme_msg.bodyptr = ls_ind; + sme_msg.bodyval = 0; + + cdf_status = cds_mq_post_message(CDF_MODULE_ID_SME, &sme_msg); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + WMA_LOGE("%s: Fail to post linkspeed ind msg", + __func__); + cdf_mem_free(ls_ind); + } + } + return cdf_status; +} + +/** + * wma_link_speed_event_handler() - link speed event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf; + wmi_peer_estimated_linkspeed_event_fixed_param *event; + CDF_STATUS cdf_status; + + param_buf = + (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid linkspeed event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + cdf_status = wma_send_link_speed(event->est_linkspeed_kbps); + if (!CDF_IS_STATUS_SUCCESS(cdf_status)) { + return -EINVAL; + } + return 0; +} + +/** + * wma_wni_cfg_dnld() - cfg download request + * @handle: wma handle + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle) +{ + CDF_STATUS cdf_status = CDF_STATUS_SUCCESS; + void *mac = cds_get_context(CDF_MODULE_ID_PE); + + WMA_LOGD("%s: Enter", __func__); + + if (NULL == mac) { + WMA_LOGP("%s: Invalid context", __func__); + CDF_ASSERT(0); + return CDF_STATUS_E_FAILURE; + } + + process_cfg_download_req(mac); + + WMA_LOGD("%s: Exit", __func__); + return cdf_status; +} + +/** + * wma_unified_debug_print_event_handler() - debug print event handler + * @handle: wma handle + * @datap: data pointer + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len) +{ + WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + + param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("Get NULL point message from FW"); + return -ENOMEM; + } + data = param_buf->data; + datalen = param_buf->num_data; + +#ifdef BIG_ENDIAN_HOST + { + char dbgbuf[500] = { 0 }; + memcpy(dbgbuf, data, datalen); + SWAPME(dbgbuf, datalen); + WMA_LOGD("FIRMWARE:%s", dbgbuf); + return 0; + } +#else + WMA_LOGD("FIRMWARE:%s", data); + return 0; +#endif /* BIG_ENDIAN_HOST */ +} + +/** + * wma_check_scan_in_progress() - check scan is progress or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_check_scan_in_progress(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = handle; + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].scan_info.scan_id) { + + WMA_LOGE("%s: scan in progress on interface[%d],scanid = %d", + __func__, i, + wma_handle->interfaces[i].scan_info.scan_id); + return true; + } + } + return false; +} + +/** + * wma_is_sap_active() - check sap is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sap_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == 0) + return true; + } + return false; +} + +/** + * wma_is_p2p_go_active() - check p2p go is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_go_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) + return true; + } + return false; +} + +/** + * wma_is_p2p_cli_active() - check p2p cli is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) + return true; + } + return false; +} + +/** + * wma_is_sta_active() - check sta is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sta_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == 0) + return true; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS) + return true; + } + return false; +} + +/** + * wma_peer_phymode() - get phymode + * @nw_type: nw type + * @sta_type: sta type + * @is_ht: is ht supported + * @is_cw40: is channel width 40 supported + * @is_vht: is vht supported + * @is_cw_vht: is channel width 80 supported + * + * Return: WLAN_PHY_MODE + */ +WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + + switch (nw_type) { + case eSIR_11B_NW_TYPE: + phymode = MODE_11B; + if (is_ht || is_vht) + WMA_LOGE("HT/VHT is enabled with 11B NW type"); + break; + case eSIR_11G_NW_TYPE: + if (!(is_ht || is_vht)) { + phymode = MODE_11G; + break; + } + if (CH_WIDTH_40MHZ < ch_width) + WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz"); + if (ch_width) + phymode = (is_vht) ? + MODE_11AC_VHT40 : MODE_11NG_HT40; + else + phymode = (is_vht) ? + MODE_11AC_VHT20 : MODE_11NG_HT20; + break; + case eSIR_11A_NW_TYPE: + if (!(is_ht || is_vht)) { + phymode = MODE_11A; + break; + } + if (is_vht) { +#if CONFIG_160MHZ_SUPPORT != 0 + if (ch_width == CH_WIDTH_160MHZ) + phymode = MODE_11AC_VHT160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = MODE_11AC_VHT80_80; + else +#endif + if (ch_width == CH_WIDTH_80MHZ) + phymode = MODE_11AC_VHT80; + else + phymode = (ch_width) ? + MODE_11AC_VHT40 : MODE_11AC_VHT20; + } else + phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20; + break; + default: + WMA_LOGP("%s: Invalid nw type %d", __func__, nw_type); + break; + } + WMA_LOGD("%s: nw_type %d is_ht %d ch_width %d is_vht %d phymode %d", + __func__, nw_type, is_ht, ch_width, is_vht, phymode); + + return phymode; +} + +/** + * wma_txrx_fw_stats_reset() - reset txrx fw statistics + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + ol_txrx_vdev_handle vdev; + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return -EINVAL; + } + cdf_mem_zero(&req, sizeof(req)); + req.stats_type_reset_mask = value; + ol_txrx_fw_stats_get(vdev, &req); + + return 0; +} + +#ifdef HELIUMPLUS +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info ## _V2)) +#else /* !HELIUMPLUS */ +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info)) +#endif + +/** + * wma_set_txrx_fw_stats_level() - set txrx fw stats level + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + ol_txrx_vdev_handle vdev; + uint32_t l_up_mask; + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return -EINVAL; + } + cdf_mem_zero(&req, sizeof(req)); + req.print.verbose = 1; + + switch (value) { + /* txrx_fw_stats 1 */ + case WMA_FW_PHY_STATS: + l_up_mask = 1 << HTT_DBG_STATS_WAL_PDEV_TXRX; + break; + + /* txrx_fw_stats 2 */ + case WMA_FW_RX_REORDER_STATS: + l_up_mask = 1 << HTT_DBG_STATS_RX_REORDER; + break; + + /* txrx_fw_stats 3 */ + case WMA_FW_RX_RC_STATS: + SET_UPLOAD_MASK(l_up_mask, HTT_DBG_STATS_RX_RATE_INFO); + break; + + /* txrx_fw_stats 5 */ + case WMA_FW_TX_CONCISE_STATS: + req.print.concise = 1; + /* No break here, since l_up_mask is same for + * both WMA_FW_TX_CONCISE_STATS & WMA_FW_TX_PPDU_STATS */ + + /* txrx_fw_stats 4 */ + case WMA_FW_TX_PPDU_STATS: + l_up_mask = 1 << HTT_DBG_STATS_TX_PPDU_LOG; + break; + + /* txrx_fw_stats 6 */ + case WMA_FW_TX_RC_STATS: + SET_UPLOAD_MASK(l_up_mask, HTT_DBG_STATS_TX_RATE_INFO); + break; + + /* txrx_fw_stats 12 */ + /* + * This is 1:1 correspondence with WMA defined value + * and the f/w bitmask. + */ + case WMA_FW_RX_REM_RING_BUF: + l_up_mask = 1 << HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO; + break; + + /* txrx_fw_stats 7 */ + case WMA_FW_TXBF_INFO_STATS: + l_up_mask = 1 << HTT_DBG_STATS_TXBF_INFO; + break; + + /* txrx_fw_stats 8 */ + case WMA_FW_SND_INFO_STATS: + l_up_mask = 1 << HTT_DBG_STATS_SND_INFO; + break; + + /* txrx_fw_stats 9 */ + case WMA_FW_ERROR_INFO_STATS: + l_up_mask = 1 << HTT_DBG_STATS_ERROR_INFO; + break; + + /* txrx_fw_stats 10 */ + case WMA_FW_TX_SELFGEN_INFO_STATS: + l_up_mask = 1 << HTT_DBG_STATS_TX_SELFGEN_INFO; + break; + + /* txrx_fw_stats 15 */ + /* + * This is 1:1 correspondence with WMA defined value + * and the f/w bitmask. + */ + case WMA_FW_RX_TXBF_MUSU_NDPA: + l_up_mask = 1 << HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT; + break; + + default: + cdf_print("%s %d Invalid value %d\n", + __func__, __LINE__, value); + return 0; + } + req.stats_type_upload_mask = l_up_mask; + + ol_txrx_fw_stats_get(vdev, &req); + + return 0; +} + +/** + * wmi_crash_inject() - inject fw crash + * @wma_handle: wma handle + * @type: type + * @delay_time_ms: delay time in ms + * + * Return: 0 for success or return error + */ +int wmi_crash_inject(wmi_unified_t wmi_handle, uint32_t type, + uint32_t delay_time_ms) +{ + int ret = 0; + WMI_FORCE_FW_HANG_CMD_fixed_param *cmd; + uint16_t len = sizeof(*cmd); + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed!", __func__); + return -ENOMEM; + } + + cmd = (WMI_FORCE_FW_HANG_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_FORCE_FW_HANG_CMD_fixed_param)); + cmd->type = type; + cmd->delay_time_ms = delay_time_ms; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_FORCE_FW_HANG_CMDID); + if (ret < 0) { + WMA_LOGE("%s: Failed to send set param command, ret = %d", + __func__, ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * wma_get_stats_rsp_buf() - fill get stats response buffer + * @get_stats_param: get stats parameters + * + * Return: stats response buffer + */ +static tAniGetPEStatsRsp *wma_get_stats_rsp_buf + (tAniGetPEStatsReq *get_stats_param) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t len, temp_mask, counter = 0; + + len = sizeof(tAniGetPEStatsRsp); + temp_mask = get_stats_param->statsMask; + + while (temp_mask) { + if (temp_mask & 1) { + switch (counter) { + case eCsrSummaryStats: + len += sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + len += sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + len += sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + len += sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrGlobalClassDStats: + len += sizeof(tCsrGlobalClassDStatsInfo); + break; + case eCsrPerStaStats: + len += sizeof(tCsrPerStaStatsInfo); + break; + } + } + + counter++; + temp_mask >>= 1; + } + + stats_rsp_params = (tAniGetPEStatsRsp *) cdf_mem_malloc(len); + if (!stats_rsp_params) { + WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp"); + CDF_ASSERT(0); + return NULL; + } + + cdf_mem_zero(stats_rsp_params, len); + stats_rsp_params->staId = get_stats_param->staId; + stats_rsp_params->statsMask = get_stats_param->statsMask; + stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP; + stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp); + stats_rsp_params->rc = CDF_STATUS_SUCCESS; + return stats_rsp_params; +} + +/** + * wma_get_stats_req() - get stats request + * @handle: wma handle + * @get_stats_param: stats params + * + * Return: none + */ +void wma_get_stats_req(WMA_HANDLE handle, + tAniGetPEStatsReq *get_stats_param) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wma_txrx_node *node; + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + tAniGetPEStatsRsp *pGetPEStatsRspParams; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + WMA_LOGD("%s: Enter", __func__); + node = &wma_handle->interfaces[get_stats_param->sessionId]; + if (node->stats_rsp) { + pGetPEStatsRspParams = node->stats_rsp; + if (pGetPEStatsRspParams->staId == get_stats_param->staId && + pGetPEStatsRspParams->statsMask == + get_stats_param->statsMask) { + WMA_LOGI("Stats for staId %d with stats mask %d " + "is pending.... ignore new request", + get_stats_param->staId, + get_stats_param->statsMask); + goto end; + } else { + cdf_mem_free(node->stats_rsp); + node->stats_rsp = NULL; + node->fw_stats_set = 0; + } + } + + pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param); + if (!pGetPEStatsRspParams) + goto end; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed to allocate wmi buffer", __func__); + goto failed; + } + + node->fw_stats_set = 0; + node->stats_rsp = pGetPEStatsRspParams; + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = + WMI_REQUEST_PEER_STAT | WMI_REQUEST_PDEV_STAT | + WMI_REQUEST_VDEV_STAT; + cmd->vdev_id = get_stats_param->sessionId; + WMI_CHAR_ARRAY_TO_MAC_ADDR(node->bssid, &cmd->peer_macaddr); + WMA_LOGD("STATS REQ VDEV_ID:%d-->", cmd->vdev_id); + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + + WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID", + __func__); + wmi_buf_free(buf); + goto failed; + } + + goto end; +failed: + + pGetPEStatsRspParams->rc = CDF_STATUS_E_FAILURE; + node->stats_rsp = NULL; + /* send response to UMAC */ + wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams, + 0); +end: + cdf_mem_free(get_stats_param); + WMA_LOGD("%s: Exit", __func__); + return; +} + +/** + * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID + * @vdev_id: vdev id + * @buffer_size: size of buffer + * + * Return: none + */ +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size) +{ + tp_wma_handle wma; + struct beacon_info *beacon; + uint8_t *buf; + uint32_t buf_size; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id); + return NULL; + } + + beacon = wma->interfaces[vdev_id].beacon; + + if (!beacon) { + WMA_LOGE("%s: beacon invalid", __func__); + return NULL; + } + + cdf_spin_lock_bh(&beacon->lock); + + buf_size = cdf_nbuf_len(beacon->buf); + buf = cdf_mem_malloc(buf_size); + + if (!buf) { + cdf_spin_unlock_bh(&beacon->lock); + WMA_LOGE("%s: alloc failed for beacon buf", __func__); + return NULL; + } + + cdf_mem_copy(buf, cdf_nbuf_data(beacon->buf), buf_size); + + cdf_spin_unlock_bh(&beacon->lock); + + if (buffer_size) + *buffer_size = buf_size; + + return buf; +} + +/** + * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID + * @vdev_id: vdev id + * + * Return: mac address + */ +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return wma->interfaces[vdev_id].addr; +} + +/** + * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID + * @vdev_id: vdev id + * + * Return: entry from vdev table + */ +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return &wma->interfaces[vdev_id]; +} + +/** + * wma_is_vdev_up() - return whether a vdev is up + * @vdev_id: vdev id + * + * Return: true if the vdev is up, false otherwise + */ +bool wma_is_vdev_up(uint8_t vdev_id) +{ + struct wma_txrx_node *vdev = wma_get_interface_by_vdev_id(vdev_id); + if (vdev) + return vdev->vdev_up; + else + return false; +} + +#if defined(QCA_WIFI_FTM) +/** + * wma_utf_rsp() - utf response + * @wma_handle: wma handle + * @payload: payload + * @len: length of payload + * + * Return: 0 for success or error code + */ +int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload, uint32_t *len) +{ + int ret = -1; + uint32_t payload_len; + + payload_len = wma_handle->utf_event_info.length; + if (payload_len) { + ret = 0; + + /* + * The first 4 bytes holds the payload size + * and the actual payload sits next to it + */ + *payload = (uint8_t *) cdf_mem_malloc((uint32_t) payload_len + + sizeof(A_UINT32)); + *(A_UINT32 *) &(*payload[0]) = + wma_handle->utf_event_info.length; + memcpy(*payload + sizeof(A_UINT32), + wma_handle->utf_event_info.data, payload_len); + wma_handle->utf_event_info.length = 0; + *len = payload_len; + } + + return ret; +} + +/** + * wma_post_ftm_response() - post ftm response to upper layer + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_post_ftm_response(tp_wma_handle wma_handle) +{ + int ret; + uint8_t *payload; + uint32_t data_len; + cds_msg_t msg = { 0 }; + CDF_STATUS status; + + ret = wma_utf_rsp(wma_handle, &payload, &data_len); + + if (ret) { + return; + } + + sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg); + msg.bodyptr = payload; + msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SYS, &msg); + + if (status != CDF_STATUS_SUCCESS) { + WMA_LOGE("failed to post ftm response to SYS"); + cdf_mem_free(payload); + } +} + +/** + * wma_process_utf_event() - process utf event + * @handle: wma handle + * @datap: data buffer + * @dataplen: data length + * + * Return: 0 for success or error code + */ +static int +wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + SEG_HDR_INFO_STRUCT segHdrInfo; + uint8_t totalNumOfSegments, currentSeq; + WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + + param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("Get NULL point message from FW"); + return -EINVAL; + } + data = param_buf->data; + datalen = param_buf->num_data; + + segHdrInfo = *(SEG_HDR_INFO_STRUCT *) &(data[0]); + + wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF); + + currentSeq = (segHdrInfo.segmentInfo & 0xF); + totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF; + + datalen = datalen - sizeof(segHdrInfo); + + if (currentSeq == 0) { + wma_handle->utf_event_info.expectedSeq = 0; + wma_handle->utf_event_info.offset = 0; + } else { + if (wma_handle->utf_event_info.expectedSeq != currentSeq) + WMA_LOGE("Mismatch in expecting seq expected" + " Seq %d got seq %d", + wma_handle->utf_event_info.expectedSeq, + currentSeq); + } + + memcpy(&wma_handle->utf_event_info. + data[wma_handle->utf_event_info.offset], + &data[sizeof(segHdrInfo)], datalen); + wma_handle->utf_event_info.offset = + wma_handle->utf_event_info.offset + datalen; + wma_handle->utf_event_info.expectedSeq++; + + if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) { + if (wma_handle->utf_event_info.offset != segHdrInfo.len) + WMA_LOGE("All segs received total len mismatch.." + " len %zu total len %d", + wma_handle->utf_event_info.offset, + segHdrInfo.len); + + wma_handle->utf_event_info.length = + wma_handle->utf_event_info.offset; + } + + wma_post_ftm_response(wma_handle); + + return 0; +} + +/** + * wma_utf_detach() - utf detach + * @wma_handle: wma handle + * + * Return: none + */ +void wma_utf_detach(tp_wma_handle wma_handle) +{ + if (wma_handle->utf_event_info.data) { + cdf_mem_free(wma_handle->utf_event_info.data); + wma_handle->utf_event_info.data = NULL; + wma_handle->utf_event_info.length = 0; + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_PDEV_UTF_EVENTID); + } +} + +/** + * wma_utf_attach() - utf attach + * @wma_handle: wma handle + * + * Return: none + */ +void wma_utf_attach(tp_wma_handle wma_handle) +{ + int ret; + + wma_handle->utf_event_info.data = (unsigned char *) + cdf_mem_malloc(MAX_UTF_EVENT_LENGTH); + wma_handle->utf_event_info.length = 0; + + ret = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_UTF_EVENTID, + wma_process_utf_event); + + if (ret) + WMA_LOGP("%s: Failed to register UTF event callback", __func__); +} + +/** + * wmi_unified_pdev_utf_cmd() - send utf command to fw + * @wmi_handle: wmi handle + * @utf_payload: utf payload + * @len: length + * + * Return: 0 for success or error code + */ +static int +wmi_unified_pdev_utf_cmd(wmi_unified_t wmi_handle, uint8_t *utf_payload, + uint16_t len) +{ + wmi_buf_t buf; + uint8_t *cmd; + int ret = 0; + static uint8_t msgref = 1; + uint8_t segNumber = 0, segInfo, numSegments; + uint16_t chunk_len, total_bytes; + uint8_t *bufpos; + SEG_HDR_INFO_STRUCT segHdrInfo; + + bufpos = utf_payload; + total_bytes = len; + ASSERT(total_bytes / MAX_WMI_UTF_LEN == + (uint8_t) (total_bytes / MAX_WMI_UTF_LEN)); + numSegments = (uint8_t) (total_bytes / MAX_WMI_UTF_LEN); + + if (len - (numSegments * MAX_WMI_UTF_LEN)) + numSegments++; + + while (len) { + if (len > MAX_WMI_UTF_LEN) + chunk_len = MAX_WMI_UTF_LEN; /* MAX messsage */ + else + chunk_len = len; + + buf = wmi_buf_alloc(wmi_handle, + (chunk_len + sizeof(segHdrInfo) + + WMI_TLV_HDR_SIZE)); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + + cmd = (uint8_t *) wmi_buf_data(buf); + + segHdrInfo.len = total_bytes; + segHdrInfo.msgref = msgref; + segInfo = ((numSegments << 4) & 0xF0) | (segNumber & 0xF); + segHdrInfo.segmentInfo = segInfo; + segHdrInfo.pad = 0; + + WMA_LOGD("%s:segHdrInfo.len = %d, segHdrInfo.msgref = %d," + " segHdrInfo.segmentInfo = %d", + __func__, segHdrInfo.len, segHdrInfo.msgref, + segHdrInfo.segmentInfo); + + WMA_LOGD("%s:total_bytes %d segNumber %d totalSegments %d" + "chunk len %d", __func__, total_bytes, segNumber, + numSegments, chunk_len); + + segNumber++; + + WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE, + (chunk_len + sizeof(segHdrInfo))); + cmd += WMI_TLV_HDR_SIZE; + memcpy(cmd, &segHdrInfo, sizeof(segHdrInfo)); /* 4 bytes */ + memcpy(&cmd[sizeof(segHdrInfo)], bufpos, chunk_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, + (chunk_len + sizeof(segHdrInfo) + + WMI_TLV_HDR_SIZE), + WMI_PDEV_UTF_CMDID); + + if (ret != EOK) { + WMA_LOGE("Failed to send WMI_PDEV_UTF_CMDID command"); + wmi_buf_free(buf); + break; + } + + len -= chunk_len; + bufpos += chunk_len; + } + + msgref++; + + return ret; +} + +/** + * wma_utf_cmd() - utf command + * @wma_handle: wma handle + * @data: data + * @len: length + * + * Return: 0 for success or error code + */ +int wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data, uint16_t len) +{ + wma_handle->utf_event_info.length = 0; + return wmi_unified_pdev_utf_cmd(wma_handle->wmi_handle, data, len); +} + +/** + * wma_process_ftm_command() - process ftm command + * @wma_handle: wma handle + * @msg_buffer: message buffer + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS +wma_process_ftm_command(tp_wma_handle wma_handle, + struct ar6k_testmode_cmd_data *msg_buffer) +{ + uint8_t *data = NULL; + uint16_t len = 0; + int ret; + + if (!msg_buffer) + return CDF_STATUS_E_INVAL; + + if (cds_get_conparam() != CDF_FTM_MODE) { + WMA_LOGE("FTM command issued in non-FTM mode"); + cdf_mem_free(msg_buffer->data); + cdf_mem_free(msg_buffer); + return CDF_STATUS_E_NOSUPPORT; + } + + data = msg_buffer->data; + len = msg_buffer->len; + + ret = wma_utf_cmd(wma_handle, data, len); + + cdf_mem_free(msg_buffer->data); + cdf_mem_free(msg_buffer); + + if (ret) + return CDF_STATUS_E_FAILURE; + + return CDF_STATUS_SUCCESS; +} +#endif /* QCA_WIFI_FTM */ + +/** + * wma_get_wcnss_software_version() - get wcnss software version + * @p_cds_gctx: cds context + * @pVersion: version pointer + * @versionBufferSize: buffer size + * + * Return: CDF_STATUS_SUCCESS for success or error code + */ +CDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + tp_wma_handle wma_handle; + wma_handle = cds_get_context(CDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: Failed to get wma", __func__); + return CDF_STATUS_E_FAULT; + } + + snprintf(pVersion, versionBufferSize, "%x", + (unsigned int)wma_handle->target_fw_version); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_tx_rx_ss_from_config() - Get Tx/Rx spatial stream from HW mode config + * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config' + * @tx_ss: Contains the Tx spatial stream + * @rx_ss: Contains the Rx spatial stream + * + * Returns the number of spatial streams of Tx and Rx + * + * Return: None + */ +void wma_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss, + uint32_t *tx_ss, + uint32_t *rx_ss) +{ + switch (mac_ss) { + case HW_MODE_SS_0x0: + *tx_ss = 0; + *rx_ss = 0; + break; + case HW_MODE_SS_1x1: + *tx_ss = 1; + *rx_ss = 1; + break; + case HW_MODE_SS_2x2: + *tx_ss = 2; + *rx_ss = 2; + break; + case HW_MODE_SS_3x3: + *tx_ss = 3; + *rx_ss = 3; + break; + case HW_MODE_SS_4x4: + *tx_ss = 4; + *rx_ss = 4; + break; + default: + *tx_ss = 0; + *rx_ss = 0; + } +} + +/** + * wma_get_matching_hw_mode_index() - Get matching HW mode index + * @wma: WMA handle + * @mac0_tx_ss: Number of tx spatial streams of MAC0 + * @mac0_rx_ss: Number of rx spatial streams of MAC0 + * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth' + * @mac1_tx_ss: Number of tx spatial streams of MAC1 + * @mac1_rx_ss: Number of rx spatial streams of MAC1 + * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth' + * @dbs: DBS capability of type 'hw_mode_dbs_capab' + * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab' + * + * Fetches the HW mode index corresponding to the HW mode provided + * + * Return: Positive hw mode index in case a match is found or a negative + * value, otherwise + */ +static int8_t wma_get_matching_hw_mode_index(tp_wma_handle wma, + uint32_t mac0_tx_ss, uint32_t mac0_rx_ss, + enum hw_mode_bandwidth mac0_bw, + uint32_t mac1_tx_ss, uint32_t mac1_rx_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs) +{ + uint32_t i; + uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw; + uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw; + uint32_t dbs_mode, agile_dfs_mode; + int8_t found = -EINVAL; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return found; + } + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + t_mac0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac0_tx_ss != mac0_tx_ss) + continue; + + t_mac0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac0_rx_ss != mac0_rx_ss) + continue; + + t_mac0_bw = WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac0_bw != mac0_bw) + continue; + + t_mac1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_tx_ss != mac1_tx_ss) + continue; + + t_mac1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_rx_ss != mac1_rx_ss) + continue; + + t_mac1_bw = WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_bw != mac1_bw) + continue; + + dbs_mode = WMI_DBS_HW_MODE_DBS_MODE_GET( + wma->hw_mode.hw_mode_list[i]); + if (dbs_mode != dbs) + continue; + + agile_dfs_mode = WMI_DBS_HW_MODE_AGILE_DFS_GET( + wma->hw_mode.hw_mode_list[i]); + if (agile_dfs_mode != dfs) + continue; + + found = i; + WMA_LOGI("%s: hw_mode index %d found", + __func__, i); + break; + } + return found; +} + +/** + * wma_get_hw_mode_from_dbs_hw_list() - Get hw_mode index + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * + * Get the HW mode index corresponding to the HW modes spatial stream, + * bandwidth, DBS and Agile DFS capability + * + * Return: Index number if a match is found or -negative value if not found + */ +int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs) +{ + tp_wma_handle wma; + uint32_t mac0_tx_ss, mac0_rx_ss; + uint32_t mac1_tx_ss, mac1_rx_ss; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + wma_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss); + wma_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss); + + WMA_LOGI("%s: MAC0: TxSS=%d, RxSS=%d, BW=%d", + __func__, mac0_tx_ss, mac0_rx_ss, mac0_bw); + WMA_LOGI("%s: MAC1: TxSS=%d, RxSS=%d, BW=%d", + __func__, mac1_tx_ss, mac1_rx_ss, mac1_bw); + WMA_LOGI("%s: DBS capab=%d, Agile DFS capab=%d", + __func__, dbs, dfs); + + return wma_get_matching_hw_mode_index(wma, mac0_tx_ss, mac0_rx_ss, + mac0_bw, + mac1_tx_ss, mac1_rx_ss, + mac1_bw, + dbs, dfs); +} + +/** + * wma_get_hw_mode_from_idx() - Get HW mode based on index + * @idx: HW mode index + * @hw_mode: HW mode params + * + * Fetches the HW mode parameters + * + * Return: Success if hw mode is obtained and the hw mode params + */ +CDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx, + struct sir_hw_mode_params *hw_mode) +{ + tp_wma_handle wma; + uint32_t param; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (idx > wma->num_dbs_hw_modes) { + WMA_LOGE("%s: Invalid index", __func__); + return CDF_STATUS_E_FAILURE; + } + + param = wma->hw_mode.hw_mode_list[idx]; + + hw_mode->mac0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(param); + hw_mode->mac0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(param); + hw_mode->mac0_bw = WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(param); + hw_mode->mac1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(param); + hw_mode->mac1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(param); + hw_mode->mac1_bw = WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(param); + hw_mode->dbs_cap = WMI_DBS_HW_MODE_DBS_MODE_GET(param); + hw_mode->agile_dfs_cap = WMI_DBS_HW_MODE_AGILE_DFS_GET(param); + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_num_dbs_hw_modes() - Get number of HW mode + * + * Fetches the number of DBS HW modes returned by the FW + * + * Return: Negative value on error or returns the number of DBS HW modes + */ +int8_t wma_get_num_dbs_hw_modes(void) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + return wma->num_dbs_hw_modes; +} + +/** + * wma_is_hw_dbs_capable() - Check if HW is DBS capable + * + * Checks if the HW is DBS capable + * + * Return: true if the HW is DBS capable + */ +bool wma_is_hw_dbs_capable(void) +{ + tp_wma_handle wma; + uint32_t param, i, found = 0; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + if (!wma_is_dbs_enable()) { + WMA_LOGI("%s: DBS is disabled", __func__); + return false; + } + + WMA_LOGI("%s: DBS service bit map: %d", __func__, + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)); + + /* The agreement with FW is that: To know if the target is DBS + * capable, DBS needs to be supported both in the HW mode list + * and in the service ready event + */ + if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT))) + return false; + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + param = wma->hw_mode.hw_mode_list[i]; + WMA_LOGI("%s: HW param: %x", __func__, param); + if (WMI_DBS_HW_MODE_DBS_MODE_GET(param)) { + WMA_LOGI("%s: HW (%d) is DBS capable", __func__, i); + found = 1; + break; + } + } + + if (found) + return true; + + return false; +} + +/** + * wma_is_hw_agile_dfs_capable() - Check if HW is agile DFS capable + * + * Checks if the HW is agile DFS capable + * + * Return: true if the HW is agile DFS capable + */ +bool wma_is_hw_agile_dfs_capable(void) +{ + tp_wma_handle wma; + uint32_t param, i, found = 0; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + if (!wma_is_agile_dfs_enable()) { + WMA_LOGI("%s: Agile DFS is disabled", __func__); + return false; + } + + WMA_LOGI("%s: DBS service bit map: %d", __func__, + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)); + + /* The agreement with FW is that to know if the target is Agile DFS + * capable, DBS needs to be supported in the service bit map and + * Agile DFS needs to be supported in the HW mode list + */ + if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT))) + return false; + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + param = wma->hw_mode.hw_mode_list[i]; + WMA_LOGI("%s: HW param: %x", __func__, param); + if (WMI_DBS_HW_MODE_AGILE_DFS_GET(param)) { + WMA_LOGI("%s: HW %d is agile DFS capable", + __func__, i); + found = 1; + break; + } + } + + if (found) + return true; + + return false; +} + +/** + * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev + * @vdev_id: VDEV whose MAC ID is required + * + * Get MAC id corresponding to a vdev id from the WMA structure + * + * Return: Negative value on failure and MAC id on success + */ +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + if (wma->interfaces) + return wma->interfaces[vdev_id].mac_id; + + return -EINVAL; +} + +/** + * wma_get_old_and_new_hw_index() - Get the old and new HW index + * @old_hw_mode_index: Value at this pointer contains the old HW mode index + * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX + * @new_hw_mode_index: Value at this pointer contains the new HW mode index + * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX + * + * Get the old and new HW index configured in the driver + * + * Return: Failure in case the HW mode indices cannot be fetched and Success + * otherwise. When no HW mode transition has happened the values of + * old_hw_mode_index and new_hw_mode_index will be the same. + */ +CDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return CDF_STATUS_E_INVAL; + } + + *old_hw_mode_index = wma->old_hw_mode_index; + *new_hw_mode_index = wma->new_hw_mode_index; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_update_intf_hw_mode_params() - Update WMA params + * @vdev_id: VDEV id whose params needs to be updated + * @mac_id: MAC id to be updated + * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated + * + * Updates the MAC id, tx spatial stream, rx spatial stream in WMA + * + * Return: None + */ +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + if (!wma->interfaces) { + WMA_LOGE("%s: Interface is NULL", __func__); + return; + } + + wma->interfaces[vdev_id].mac_id = mac_id; + if (mac_id == 0) { + wma->interfaces[vdev_id].tx_streams = + WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(cfgd_hw_mode_index); + wma->interfaces[vdev_id].rx_streams = + WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(cfgd_hw_mode_index); + } else { + wma->interfaces[vdev_id].tx_streams = + WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(cfgd_hw_mode_index); + wma->interfaces[vdev_id].rx_streams = + WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(cfgd_hw_mode_index); + } +} + +/** + * wma_get_dbs_hw_modes() - Get the DBS HW modes for userspace + * @one_by_one_dbs: 1x1 DBS capability of HW + * @two_by_two_dbs: 2x2 DBS capability of HW + * + * Provides the DBS HW mode capability such as whether + * 1x1 DBS, 2x2 DBS is supported by the HW or not. + * + * Return: Failure in case of error and 0 on success + * one_by_one_dbs/two_by_two_dbs will be false, + * if they are not supported. + * one_by_one_dbs/two_by_two_dbs will be true, + * if they are supported. + * false values of one_by_one_dbs/two_by_two_dbs, + * indicate DBS is disabled + */ +CDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs) +{ + tp_wma_handle wma; + uint32_t i; + int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL; + uint32_t conf1_tx_ss, conf1_rx_ss; + uint32_t conf2_tx_ss, conf2_rx_ss; + + *one_by_one_dbs = false; + *two_by_two_dbs = false; + + if (wma_is_hw_dbs_capable() == false) { + WMA_LOGE("%s: HW is not DBS capable", __func__); + /* Caller will understand that DBS is disabled */ + return CDF_STATUS_SUCCESS; + + } + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return CDF_STATUS_E_FAILURE; + } + + /* To check 1x1 capability */ + wma_get_tx_rx_ss_from_config(HW_MODE_SS_1x1, + &conf1_tx_ss, &conf1_rx_ss); + /* To check 2x2 capability */ + wma_get_tx_rx_ss_from_config(HW_MODE_SS_2x2, + &conf2_tx_ss, &conf2_rx_ss); + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + uint32_t t_conf0_tx_ss, t_conf0_rx_ss; + uint32_t t_conf1_tx_ss, t_conf1_rx_ss; + uint32_t dbs_mode; + + t_conf0_tx_ss = WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf0_rx_ss = WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf1_tx_ss = WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf1_rx_ss = WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + dbs_mode = WMI_DBS_HW_MODE_DBS_MODE_GET( + wma->hw_mode.hw_mode_list[i]); + + if (((((t_conf0_tx_ss == conf1_tx_ss) && + (t_conf0_rx_ss == conf1_rx_ss)) || + ((t_conf1_tx_ss == conf1_tx_ss) && + (t_conf1_rx_ss == conf1_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_one_by_one < 0)) { + found_one_by_one = i; + WMA_LOGI("%s: 1x1 hw_mode index %d found", + __func__, i); + /* Once an entry is found, need not check for 1x1 + * again + */ + continue; + } + + if (((((t_conf0_tx_ss == conf2_tx_ss) && + (t_conf0_rx_ss == conf2_rx_ss)) || + ((t_conf1_tx_ss == conf2_tx_ss) && + (t_conf1_rx_ss == conf2_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_two_by_two < 0)) { + found_two_by_two = i; + WMA_LOGI("%s: 2x2 hw_mode index %d found", + __func__, i); + /* Once an entry is found, need not check for 2x2 + * again + */ + continue; + } + } + + if (found_one_by_one >= 0) + *one_by_one_dbs = true; + if (found_two_by_two >= 0) + *two_by_two_dbs = true; + + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_current_hw_mode() - Get current HW mode params + * @hw_mode: HW mode parameters + * + * Provides the current HW mode parameters if the HW mode is initialized + * in the driver + * + * Return: Success if the current HW mode params are successfully populated + */ +CDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode) +{ + CDF_STATUS status; + uint32_t old_hw_index = 0, new_hw_index = 0; + + WMA_LOGI("%s: Get the current hw mode", __func__); + + status = wma_get_old_and_new_hw_index(&old_hw_index, + &new_hw_index); + if (CDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to get HW mode index", __func__); + return CDF_STATUS_E_FAILURE; + } + + if (new_hw_index == WMA_DEFAULT_HW_MODE_INDEX) { + WMA_LOGE("%s: HW mode is not yet initialized", __func__); + return CDF_STATUS_E_FAILURE; + } + + status = wma_get_hw_mode_from_idx(new_hw_index, hw_mode); + if (CDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to get HW mode index", __func__); + return CDF_STATUS_E_FAILURE; + } + return CDF_STATUS_SUCCESS; +} + +/** + * wma_is_dbs_enable() - Check if master DBS control is enabled + * + * Checks if the master DBS control is enabled. This will be used + * to override any other DBS capability + * + * Return: True if master DBS control is enabled + */ +bool wma_is_dbs_enable(void) +{ + tp_wma_handle wma; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + WMA_LOGD("%s: DBS=%d", __func__, + WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config)); + + if (WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config)) + return true; + + return false; +} + +/** + * wma_is_agile_dfs_enable() - Check if master Agile DFS control is enabled + * + * Checks if the master Agile DFS control is enabled. This will be used + * to override any other Agile DFS capability + * + * Return: True if master Agile DFS control is enabled + */ +bool wma_is_agile_dfs_enable(void) +{ + tp_wma_handle wma; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + WMA_LOGD("%s: DFS=%d Single mac with DFS=%d", __func__, + WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET( + wma->dual_mac_cfg.cur_fw_mode_config), + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET( + wma->dual_mac_cfg.cur_scan_config)); + + if ((WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET( + wma->dual_mac_cfg.cur_fw_mode_config)) && + (WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET( + wma->dual_mac_cfg.cur_scan_config))) + return true; + + return false; +} + +/** + * wma_get_updated_scan_config() - Get the updated scan configuration + * @scan_config: Pointer containing the updated scan config + * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled + * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be + * enabled/disabled + * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS + * needs to be enabled/disabled + * + * Takes the current scan configuration and set the necessary scan config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +CDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return CDF_STATUS_E_FAILURE; + } + *scan_config = wma->dual_mac_cfg.cur_scan_config; + + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config, + dbs_plus_agile_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config, + single_mac_scan_with_dfs); + + WMA_LOGD("%s: *scan_config:%x ", __func__, *scan_config); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_updated_fw_mode_config() - Get the updated fw mode configuration + * @fw_mode_config: Pointer containing the updated fw mode config + * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled + * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled + * + * Takes the current fw mode configuration and set the necessary fw mode config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +CDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs) +{ + tp_wma_handle wma; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return CDF_STATUS_E_FAILURE; + } + *fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs); + + WMA_LOGD("%s: *fw_mode_config:%x ", __func__, *fw_mode_config); + return CDF_STATUS_SUCCESS; +} + +/** + * wma_get_dbs_config() - Get DBS bit + * + * Gets the DBS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the DBS bit + */ +bool wma_get_dbs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); +} + +/** + * wma_get_agile_dfs_config() - Get Agile DFS bit + * + * Gets the Agile DFS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the Agile DFS bit + */ +bool wma_get_agile_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); +} + +/** + * wma_get_dbs_scan_config() - Get DBS scan bit + * + * Gets the DBS scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS scan bit + */ +bool wma_get_dbs_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); +} + +/** + * wma_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit + * + * Gets the DBS plus agile scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS plus agile scan bit + */ +bool wma_get_dbs_plus_agile_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config); +} + +/** + * wma_get_single_mac_scan_with_dfs_config() - Get Single MAC scan with DFS bit + * + * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the Single MAC scan with DFS bit + */ +bool wma_get_single_mac_scan_with_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config); +} + +/** + * wma_is_dual_mac_disabled_in_ini() - Check if dual mac is disabled in INI + * + * Checks if the dual mac feature is disabled in INI + * + * Return: true if the dual mac feature is disabled from INI + */ +bool wma_is_dual_mac_disabled_in_ini(void) +{ + tpAniSirGlobal mac = cds_get_context(CDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac pointer", __func__); + return true; + } + + if (mac->dual_mac_feature_disable) + return true; + + return false; +} + +/** + * wma_get_prev_dbs_config() - Get prev DBS bit + * + * Gets the previous DBS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the DBS bit + */ +bool wma_get_prev_dbs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); +} + +/** + * wma_get_prev_agile_dfs_config() - Get prev Agile DFS bit + * + * Gets the previous Agile DFS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the Agile DFS bit + */ +bool wma_get_prev_agile_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); +} + +/** + * wma_get_prev_dbs_scan_config() - Get prev DBS scan bit + * + * Gets the previous DBS scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS scan bit + */ +bool wma_get_prev_dbs_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); +} + +/** + * wma_get_prev_dbs_plus_agile_scan_config() - Get prev DBS plus agile scan bit + * + * Gets the previous DBS plus agile scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS plus agile scan bit + */ +bool wma_get_prev_dbs_plus_agile_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config); +} + +/** + * wma_get_prev_single_mac_scan_with_dfs_config() - Get prev Single MAC scan + * with DFS bit + * + * Gets the previous Single MAC scan with DFS bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the Single MAC scan with DFS bit + */ +bool wma_get_prev_single_mac_scan_with_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config); +} + +/** + * wma_is_scan_simultaneous_capable() - Check if scan parallelization is + * supported or not + * + * currently scan parallelization feature support is dependent on DBS but + * it can be independent in future. + * + * Return: True if master DBS control is enabled + */ +bool wma_is_scan_simultaneous_capable(void) +{ + if (wma_is_hw_dbs_capable()) + return true; + + return false; +} diff --git a/core/wma/src/wma_utils_ut.c b/core/wma/src/wma_utils_ut.c new file mode 100644 index 0000000000..d36c6ca54c --- /dev/null +++ b/core/wma/src/wma_utils_ut.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_utils_ut.c + * This file contains utilities related to unit test framework + */ + +/* Header files */ + +#include "wma.h" + +/** + * wma_set_dbs_capability_ut() - Set DBS capability for UT framework + * @dbs: Value of DBS capability to be set + * + * Sets the DBS capability for unit test framework. If the HW mode is + * already sent by the FW, only the DBS capability needs to be set. If the + * FW did not send any HW mode list, a single entry is created and DBS mode + * is set in it. The DBS capability is also set in the service bit map. + * + * Return: None + */ +void wma_set_dbs_capability_ut(uint32_t dbs) +{ + tp_wma_handle wma; + uint32_t i; + + wma = cds_get_context(CDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + /* DBS list was not configured by the FW, so + * for UT, we can configure a single entry + */ + if (wma->hw_mode.hw_mode_list == NULL) { + wma->num_dbs_hw_modes = 1; + wma->hw_mode.hw_mode_list = + cdf_mem_malloc(sizeof(*wma->hw_mode.hw_mode_list) * + wma->num_dbs_hw_modes); + if (!wma->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for UT-DBS", + __func__); + return; + } + wma->hw_mode.hw_mode_list[0] = 0x0000; + } + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + WMI_DBS_HW_MODE_DBS_MODE_SET(wma->hw_mode.hw_mode_list[i], + dbs); + } + + WMI_SERVICE_ENABLE(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT); +} diff --git a/core/wmi/wmi_tlv_helper.c b/core/wmi/wmi_tlv_helper.c new file mode 100644 index 0000000000..0e35755536 --- /dev/null +++ b/core/wmi/wmi_tlv_helper.c @@ -0,0 +1,1190 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* wmi_tlv_platform.c file will be different for different components like Pronto firmware, Pronto windows host driver, + Pronto LA host driver because their memory management functions are different */ +#include "wmi_tlv_platform.c" +#include "wmi_tlv_defs.h" +#include "wmi_version.h" + +#define WMITLV_GET_ATTRIB_NUM_TLVS 0xFFFFFFFF + +#define WMITLV_GET_CMDID(val) (val & 0x00FFFFFF) +#define WMITLV_GET_NUM_TLVS(val) ((val >> 24) & 0xFF) + +#define WMITLV_GET_TAGID(val) (val & 0x00000FFF) +#define WMITLV_GET_TAG_STRUCT_SIZE(val) ((val >> 12) & 0x000001FF) +#define WMITLV_GET_TAG_ARRAY_SIZE(val) ((val >> 21) & 0x000001FF) +#define WMITLV_GET_TAG_VARIED(val) ((val >> 30) & 0x00000001) + +#define WMITLV_SET_ATTRB0(id) ((WMITLV_GET_TAG_NUM_TLV_ATTRIB(id) << 24) | (id & 0x00FFFFFF)) +#define WMITLV_SET_ATTRB1(tagID, tagStructSize, tagArraySize, tagVaried) (((tagVaried&0x1)<<30) | ((tagArraySize&0x1FF)<<21) | ((tagStructSize&0x1FF)<<12) | (tagID&0xFFF)) + +#define WMITLV_OP_SET_TLV_ATTRIB_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + WMITLV_SET_ATTRB1(elem_tlv_tag, sizeof(elem_struc_type), arr_size, var_len), + +#define WMITLV_GET_CMD_EVT_ATTRB_LIST(id) \ + WMITLV_SET_ATTRB0(id), \ + WMITLV_TABLE(id,SET_TLV_ATTRIB,NULL,0) + +A_UINT32 cmd_attr_list[] = { + WMITLV_ALL_CMD_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST) +}; + +A_UINT32 evt_attr_list[] = { + WMITLV_ALL_EVT_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST) +}; + +#ifdef NO_DYNAMIC_MEM_ALLOC +static wmitlv_cmd_param_info *g_wmi_static_cmd_param_info_buf = NULL; +A_UINT32 g_wmi_static_max_cmd_param_tlvs = 0; +#endif + +/* TLV helper routines */ + +/* + * WMI TLV Helper function to set the static cmd_param_tlv structure and number of TLVs that can be + * accomodated in the structure. This function should be used when dynamic memory allocation is not + * supported. + * + * When dynamic memory allocation is not supported by any component then NO_DYNAMIC_MEMALLOC + * macro has to be defined in respective tlv_platform.c file. And respective component has to allocate + * cmd_param_tlv structure buffer to accomodate whatever number of TLV's. Both the buffer address + * and number of TLV's that can be accomodated in the buffer should be sent as arguments to this function. + * + * Return None + */ +void +wmitlv_set_static_param_tlv_buf(void *param_tlv_buf, + A_UINT32 max_tlvs_accomodated) +{ +#ifdef NO_DYNAMIC_MEM_ALLOC + g_wmi_static_cmd_param_info_buf = param_tlv_buf; + g_wmi_static_max_cmd_param_tlvs = max_tlvs_accomodated; +#endif +} + +/* + * WMI TLV Helper functions to find the attributes of the Command/Event TLVs. + * Return 0 if success. Return >=1 if failure. + */ +A_UINT32 wmitlv_get_attributes(A_UINT32 is_cmd_id, A_UINT32 cmd_event_id, + A_UINT32 curr_tlv_order, + wmitlv_attributes_struc *tlv_attr_ptr) +{ + A_UINT32 i, base_index, num_tlvs, num_entries; + A_UINT32 *pAttrArrayList; + + if (is_cmd_id) { + pAttrArrayList = &cmd_attr_list[0]; + num_entries = CDF_ARRAY_SIZE(cmd_attr_list); + } else { + pAttrArrayList = &evt_attr_list[0]; + num_entries = CDF_ARRAY_SIZE(evt_attr_list); + } + + for (i = 0; i < num_entries; i++) { + num_tlvs = WMITLV_GET_NUM_TLVS(pAttrArrayList[i]); + if (WMITLV_GET_CMDID(cmd_event_id) == + WMITLV_GET_CMDID(pAttrArrayList[i])) { + tlv_attr_ptr->cmd_num_tlv = num_tlvs; + /* Return success from here when only number of TLVS for this command/event is required */ + if (curr_tlv_order == WMITLV_GET_ATTRIB_NUM_TLVS) { + wmi_tlv_print_verbose + ("%s: WMI TLV attribute definitions for %s:0x%x found; num_of_tlvs:%d\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), + cmd_event_id, num_tlvs); + return 0; + } + + /* Return failure if tlv_order is more than the expected number of TLVs */ + if (curr_tlv_order >= num_tlvs) { + wmi_tlv_print_error + ("%s: ERROR: TLV order %d greater than num_of_tlvs:%d for %s:0x%x\n", + __func__, curr_tlv_order, num_tlvs, + (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id); + return 1; + } + + base_index = i + 1; /* index to first TLV attributes */ + wmi_tlv_print_verbose + ("%s: WMI TLV attributes for %s:0x%x tlv[%d]:0x%x\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), + cmd_event_id, curr_tlv_order, + pAttrArrayList[(base_index + curr_tlv_order)]); + tlv_attr_ptr->tag_order = curr_tlv_order; + tlv_attr_ptr->tag_id = + WMITLV_GET_TAGID(pAttrArrayList + [(base_index + curr_tlv_order)]); + tlv_attr_ptr->tag_struct_size = + WMITLV_GET_TAG_STRUCT_SIZE(pAttrArrayList + [(base_index + + curr_tlv_order)]); + tlv_attr_ptr->tag_varied_size = + WMITLV_GET_TAG_VARIED(pAttrArrayList + [(base_index + + curr_tlv_order)]); + tlv_attr_ptr->tag_array_size = + WMITLV_GET_TAG_ARRAY_SIZE(pAttrArrayList + [(base_index + + curr_tlv_order)]); + return 0; + } + i += num_tlvs; + } + + wmi_tlv_print_error + ("%s: ERROR: Didn't found WMI TLV attribute definitions for %s:0x%x\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id); + return 1; +} + +/* + * Helper Function to vaidate the prepared TLV's for an WMI event/command to be sent + * Return 0 if success. + * <0 if failure. + */ +static int +wmitlv_check_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 is_cmd_id, + A_UINT32 wmi_cmd_event_id) +{ + wmitlv_attributes_struc attr_struct_ptr; + A_UINT32 buf_idx = 0; + A_UINT32 tlv_index = 0; + A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr; + A_UINT32 expected_num_tlvs, expected_tlv_len; + + /* Get the number of TLVs for this command/event */ + if (wmitlv_get_attributes + (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS, + &attr_struct_ptr) != 0) { + wmi_tlv_print_error + ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n", + __func__, wmi_cmd_event_id); + goto Error_wmitlv_check_tlv_params; + } + + /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */ + + expected_num_tlvs = attr_struct_ptr.cmd_num_tlv; + + while ((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) { + A_UINT32 curr_tlv_tag = + WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); + A_UINT32 curr_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); + + if ((buf_idx + WMI_TLV_HDR_SIZE + curr_tlv_len) > param_buf_len) { + wmi_tlv_print_error + ("%s: ERROR: Invalid TLV length for Cmd=%d Tag_order=%d buf_idx=%d Tag:%d Len:%d TotalLen:%d\n", + __func__, wmi_cmd_event_id, tlv_index, buf_idx, + curr_tlv_tag, curr_tlv_len, param_buf_len); + goto Error_wmitlv_check_tlv_params; + } + + /* Get the attributes of the TLV with the given order in "tlv_index" */ + wmi_tlv_OS_MEMZERO(&attr_struct_ptr, + sizeof(wmitlv_attributes_struc)); + if (wmitlv_get_attributes + (is_cmd_id, wmi_cmd_event_id, tlv_index, + &attr_struct_ptr) != 0) { + wmi_tlv_print_error + ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n", + __func__, wmi_cmd_event_id, tlv_index); + goto Error_wmitlv_check_tlv_params; + } + + /* Found the TLV that we wanted */ + wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n", + __func__, tlv_index, curr_tlv_tag, + curr_tlv_len); + + /* Validating Tag ID order */ + if (curr_tlv_tag != attr_struct_ptr.tag_id) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n", + __func__, wmi_cmd_event_id, curr_tlv_tag, + attr_struct_ptr.tag_id); + goto Error_wmitlv_check_tlv_params; + } + + /* Validate Tag length */ + /* Array TLVs length checking needs special handling */ + if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM) + && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) { + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* Array size can't be invalid for fixed size Array TLV */ + if (WMITLV_ARR_SIZE_INVALID == + attr_struct_ptr.tag_array_size) { + wmi_tlv_print_error + ("%s: ERROR: array_size can't be invalid for Array TLV Cmd=0x%x Tag=%d\n", + __func__, wmi_cmd_event_id, + curr_tlv_tag); + goto Error_wmitlv_check_tlv_params; + } + + expected_tlv_len = + attr_struct_ptr.tag_array_size * + attr_struct_ptr.tag_struct_size; + /* Paddding is only required for Byte array Tlvs all other array tlv's should be aligned to 4 bytes during their definition */ + if (WMITLV_TAG_ARRAY_BYTE == + attr_struct_ptr.tag_id) { + expected_tlv_len = + roundup(expected_tlv_len, + sizeof(A_UINT32)); + } + + if (curr_tlv_len != expected_tlv_len) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%d Expected_Len=%d.\n", + __func__, wmi_cmd_event_id, + tlv_index, curr_tlv_tag, + curr_tlv_len, expected_tlv_len); + goto Error_wmitlv_check_tlv_params; + } + } else { + /* Array size should be invalid for variable size Array TLV */ + if (WMITLV_ARR_SIZE_INVALID != + attr_struct_ptr.tag_array_size) { + wmi_tlv_print_error + ("%s: ERROR: array_size should be invalid for Array TLV Cmd=0x%x Tag=%d\n", + __func__, wmi_cmd_event_id, + curr_tlv_tag); + goto Error_wmitlv_check_tlv_params; + } + + /* Incase of variable length TLV's, there is no expectation on the length field so do whatever checking + you can depending on the TLV tag if TLV length is non-zero */ + if (curr_tlv_len != 0) { + /* Verify TLV length is aligned to the size of structure */ + if ((curr_tlv_len % + attr_struct_ptr.tag_struct_size) != + 0) { + wmi_tlv_print_error + ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to size of structure(%d bytes)\n", + __func__, curr_tlv_len, + wmi_cmd_event_id, + attr_struct_ptr. + tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + + if (curr_tlv_tag == + WMITLV_TAG_ARRAY_STRUC) { + A_UINT8 *tlv_buf_ptr = NULL; + A_UINT32 in_tlv_len; + A_UINT32 idx; + A_UINT32 num_of_elems; + + /* Verify length of inner TLVs */ + + num_of_elems = + curr_tlv_len / + attr_struct_ptr. + tag_struct_size; + /* Set tlv_buf_ptr to the first inner TLV address */ + tlv_buf_ptr = + buf_ptr + WMI_TLV_HDR_SIZE; + for (idx = 0; + idx < num_of_elems; + idx++) { + in_tlv_len = + WMITLV_GET_TLVLEN + (WMITLV_GET_HDR + (tlv_buf_ptr)); + if ((in_tlv_len + + WMI_TLV_HDR_SIZE) + != + attr_struct_ptr. + tag_struct_size) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%zu Expected_Len=%d.\n", + __func__, + wmi_cmd_event_id, + tlv_index, + curr_tlv_tag, + (in_tlv_len + + + WMI_TLV_HDR_SIZE), + attr_struct_ptr. + tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + tlv_buf_ptr += + in_tlv_len + + WMI_TLV_HDR_SIZE; + } + } else + if ((curr_tlv_tag == + WMITLV_TAG_ARRAY_UINT32) + || (curr_tlv_tag == + WMITLV_TAG_ARRAY_BYTE) + || (curr_tlv_tag == + WMITLV_TAG_ARRAY_FIXED_STRUC)) + { + /* Nothing to verify here */ + } else { + wmi_tlv_print_error + ("%s ERROR Need to handle the Array tlv %d for variable length for Cmd=0x%x\n", + __func__, + attr_struct_ptr.tag_id, + wmi_cmd_event_id); + goto Error_wmitlv_check_tlv_params; + } + } + } + } else { + /* Non-array TLV. */ + + if ((curr_tlv_len + WMI_TLV_HDR_SIZE) != + attr_struct_ptr.tag_struct_size) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Given=%zu, Expected=%d.\n", + __func__, wmi_cmd_event_id, + (curr_tlv_len + WMI_TLV_HDR_SIZE), + attr_struct_ptr.tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + } + + /* Check TLV length is aligned to 4 bytes or not */ + if ((curr_tlv_len % sizeof(A_UINT32)) != 0) { + wmi_tlv_print_error + ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to %zu bytes\n", + __func__, curr_tlv_len, wmi_cmd_event_id, + sizeof(A_UINT32)); + goto Error_wmitlv_check_tlv_params; + } + + tlv_index++; + buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE; + buf_idx += curr_tlv_len + WMI_TLV_HDR_SIZE; + } + + if (tlv_index != expected_num_tlvs) { + wmi_tlv_print_verbose + ("%s: INFO: Less number of TLVs filled for Cmd=0x%x Filled %d Expected=%d\n", + __func__, wmi_cmd_event_id, tlv_index, expected_num_tlvs); + } + + return (0); +Error_wmitlv_check_tlv_params: + return (-1); +} + +/* + * Helper Function to vaidate the prepared TLV's for an WMI event to be sent + * Return 0 if success. + * <0 if failure. + */ +int +wmitlv_check_event_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id) +{ + A_UINT32 is_cmd_id = 0; + return (wmitlv_check_tlv_params + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id)); +} + +/* + * Helper Function to vaidate the prepared TLV's for an WMI command to be sent + * Return 0 if success. + * <0 if failure. + */ +int +wmitlv_check_command_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id) +{ + A_UINT32 is_cmd_id = 1; + return (wmitlv_check_tlv_params + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id)); +} + +/* + * Helper Function to vaidate the TLV's coming for an event/command and also pads data to TLV's if necessary + * Return 0 if success. + <0 if failure. + */ +static int +wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 is_cmd_id, + A_UINT32 wmi_cmd_event_id, void **wmi_cmd_struct_ptr) +{ + wmitlv_attributes_struc attr_struct_ptr; + A_UINT32 buf_idx = 0; + A_UINT32 tlv_index = 0; + A_UINT32 num_of_elems = 0; + int tlv_size_diff = 0; + A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr; + wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL; + A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF; + A_UINT32 len_wmi_cmd_struct_buf; + + /* Get the number of TLVs for this command/event */ + if (wmitlv_get_attributes + (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS, + &attr_struct_ptr) != 0) { + wmi_tlv_print_error + ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n", + __func__, wmi_cmd_event_id); + return -1; + } + /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */ + + /* Create base structure of format wmi_cmd_event_id##_param_tlvs */ + len_wmi_cmd_struct_buf = + attr_struct_ptr.cmd_num_tlv * sizeof(wmitlv_cmd_param_info); +#ifndef NO_DYNAMIC_MEM_ALLOC + /* Dynamic memory allocation supported */ + wmi_tlv_os_mem_alloc(os_handle, *wmi_cmd_struct_ptr, + len_wmi_cmd_struct_buf); +#else + /* Dynamic memory allocation is not supported. Use the buffer g_wmi_static_cmd_param_info_buf, which should be set using wmi_tlv_set_static_param_tlv_buf(), + for base structure of format wmi_cmd_event_id##_param_tlvs */ + *wmi_cmd_struct_ptr = g_wmi_static_cmd_param_info_buf; + if (attr_struct_ptr.cmd_num_tlv > g_wmi_static_max_cmd_param_tlvs) { + /* Error: Expecting more TLVs that accomodated for static structure */ + wmi_tlv_print_error + ("%s: Error: Expecting more TLVs that accomodated for static structure. Expected:%d Accomodated:%d\n", + __func__, attr_struct_ptr.cmd_num_tlv, + g_wmi_static_max_cmd_param_tlvs); + return -1; + } +#endif + if (*wmi_cmd_struct_ptr == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for TLV\n", + __func__, len_wmi_cmd_struct_buf); + return -1; + } + + cmd_param_tlvs_ptr = (wmitlv_cmd_param_info *) *wmi_cmd_struct_ptr; + wmi_tlv_OS_MEMZERO(cmd_param_tlvs_ptr, len_wmi_cmd_struct_buf); + remaining_expected_tlvs = attr_struct_ptr.cmd_num_tlv; + + while (((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) + && (remaining_expected_tlvs)) { + A_UINT32 curr_tlv_tag = + WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); + A_UINT32 curr_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); + int num_padding_bytes = 0; + + /* Get the attributes of the TLV with the given order in "tlv_index" */ + wmi_tlv_OS_MEMZERO(&attr_struct_ptr, + sizeof(wmitlv_attributes_struc)); + if (wmitlv_get_attributes + (is_cmd_id, wmi_cmd_event_id, tlv_index, + &attr_struct_ptr) != 0) { + wmi_tlv_print_error + ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n", + __func__, wmi_cmd_event_id, tlv_index); + goto Error_wmitlv_check_and_pad_tlvs; + } + + /* Found the TLV that we wanted */ + wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n", + __func__, tlv_index, curr_tlv_tag, + curr_tlv_len); + + /* Validating Tag order */ + if (curr_tlv_tag != attr_struct_ptr.tag_id) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n", + __func__, wmi_cmd_event_id, curr_tlv_tag, + attr_struct_ptr.tag_id); + goto Error_wmitlv_check_and_pad_tlvs; + } + + if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM) + && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) { + /* Current Tag is an array of some kind. */ + /* Skip the TLV header of this array */ + buf_ptr += WMI_TLV_HDR_SIZE; + buf_idx += WMI_TLV_HDR_SIZE; + } else { + /* Non-array TLV. */ + curr_tlv_len += WMI_TLV_HDR_SIZE; + } + + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* This TLV is fixed length */ + if (WMITLV_ARR_SIZE_INVALID == + attr_struct_ptr.tag_array_size) { + tlv_size_diff = + curr_tlv_len - + attr_struct_ptr.tag_struct_size; + num_of_elems = + (curr_tlv_len > WMI_TLV_HDR_SIZE) ? 1 : 0; + } else { + tlv_size_diff = + curr_tlv_len - + (attr_struct_ptr.tag_struct_size * + attr_struct_ptr.tag_array_size); + num_of_elems = attr_struct_ptr.tag_array_size; + } + } else { + /* This TLV has a variable number of elements */ + if (WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) { + A_UINT32 in_tlv_len = 0; + + if (curr_tlv_len != 0) { + in_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR + (buf_ptr)); + in_tlv_len += WMI_TLV_HDR_SIZE; + tlv_size_diff = + in_tlv_len - + attr_struct_ptr.tag_struct_size; + num_of_elems = + curr_tlv_len / in_tlv_len; + wmi_tlv_print_verbose + ("%s: WARN: TLV array of structures in_tlv_len=%d struct_size:%d diff:%d num_of_elems=%d \n", + __func__, in_tlv_len, + attr_struct_ptr.tag_struct_size, + tlv_size_diff, num_of_elems); + } else { + tlv_size_diff = 0; + num_of_elems = 0; + } + } else + if ((WMITLV_TAG_ARRAY_UINT32 == + attr_struct_ptr.tag_id) + || (WMITLV_TAG_ARRAY_BYTE == + attr_struct_ptr.tag_id) + || (WMITLV_TAG_ARRAY_FIXED_STRUC == + attr_struct_ptr.tag_id)) { + tlv_size_diff = 0; + num_of_elems = + curr_tlv_len / + attr_struct_ptr.tag_struct_size; + } else { + wmi_tlv_print_error + ("%s ERROR Need to handle this tag ID for variable length %d\n", + __func__, attr_struct_ptr.tag_id); + goto Error_wmitlv_check_and_pad_tlvs; + } + } + + if ((WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) && + (tlv_size_diff != 0)) { + void *new_tlv_buf = NULL; + A_UINT8 *tlv_buf_ptr = NULL; + A_UINT32 in_tlv_len; + A_UINT32 i; + + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* This is not allowed. The tag WMITLV_TAG_ARRAY_STRUC can only be used with variable-length structure array + should not have a fixed number of elements (contradicting). Use WMITLV_TAG_ARRAY_FIXED_STRUC tag for + fixed size structure array(where structure never change without breaking compatibility) */ + wmi_tlv_print_error + ("%s: ERROR: TLV (tag=%d) should be variable-length and not fixed length\n", + __func__, curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + /* Warning: Needs to allocate a larger structure and pad with zeros */ + wmi_tlv_print_error + ("%s: WARN: TLV array of structures needs padding. tlv_size_diff=%d\n", + __func__, tlv_size_diff); + + /* incoming structure length */ + in_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)) + + WMI_TLV_HDR_SIZE; +#ifndef NO_DYNAMIC_MEM_ALLOC + wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf, + (num_of_elems * + attr_struct_ptr.tag_struct_size)); + if (new_tlv_buf == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for padding the TLV array %d\n", + __func__, + (num_of_elems * + attr_struct_ptr.tag_struct_size), + curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + wmi_tlv_OS_MEMZERO(new_tlv_buf, + (num_of_elems * + attr_struct_ptr.tag_struct_size)); + tlv_buf_ptr = (A_UINT8 *) new_tlv_buf; + for (i = 0; i < num_of_elems; i++) { + if (tlv_size_diff > 0) { + /* Incoming structure size is greater than expected structure size. + so copy the number of bytes equal to expected structure size */ + wmi_tlv_OS_MEMCPY(tlv_buf_ptr, + (void *)(buf_ptr + + i * + in_tlv_len), + attr_struct_ptr. + tag_struct_size); + } else { + /* Incoming structure size is smaller than expected structure size. + so copy the number of bytes equal to incoming structure size + (other bytes would be zeroes) */ + wmi_tlv_OS_MEMCPY(tlv_buf_ptr, + (void *)(buf_ptr + + i * + in_tlv_len), + in_tlv_len); + } + tlv_buf_ptr += attr_struct_ptr.tag_struct_size; + } +#else + { + A_UINT8 *src_addr; + A_UINT8 *dst_addr; + A_UINT32 buf_mov_len; + + if (tlv_size_diff < 0) { + /* Incoming structure size is smaller than expected size then this needs padding for each element in the array */ + + /* Find amount of bytes to be padded for one element */ + num_padding_bytes = tlv_size_diff * -1; + + /* Move subsequent TLVs by number of bytes to be padded for all elements */ + if (param_buf_len > + (buf_idx + curr_tlv_len)) { + src_addr = + buf_ptr + curr_tlv_len; + dst_addr = + buf_ptr + curr_tlv_len + + (num_padding_bytes * + num_of_elems); + buf_mov_len = + param_buf_len - (buf_idx + + curr_tlv_len); + + wmi_tlv_OS_MEMMOVE(dst_addr, + src_addr, + buf_mov_len); + } + + /* Move subsequent elements of array down by number of bytes to be padded for one element and alse set padding bytes to zero */ + tlv_buf_ptr = buf_ptr; + for (i = 0; i < num_of_elems; i++) { + src_addr = + tlv_buf_ptr + in_tlv_len; + if (i != (num_of_elems - 1)) { + /* Need not move anything for last element in the array */ + dst_addr = + tlv_buf_ptr + + in_tlv_len + + num_padding_bytes; + buf_mov_len = + curr_tlv_len - + ((i + + 1) * in_tlv_len); + + wmi_tlv_OS_MEMMOVE + (dst_addr, src_addr, + buf_mov_len); + } + + /* Set the padding bytes to zeroes */ + wmi_tlv_OS_MEMZERO(src_addr, + num_padding_bytes); + + tlv_buf_ptr += + attr_struct_ptr. + tag_struct_size; + } + + /* Update the number of padding bytes to total number of bytes padded for all elements in the array */ + num_padding_bytes = + num_padding_bytes * num_of_elems; + + new_tlv_buf = buf_ptr; + } else { + /* Incoming structure size is greater than expected size then this needs shrinking for each element in the array */ + + /* Find amount of bytes to be shrinked for one element */ + num_padding_bytes = tlv_size_diff * -1; + + /* Move subsequent elements of array up by number of bytes to be shrinked for one element */ + tlv_buf_ptr = buf_ptr; + for (i = 0; i < (num_of_elems - 1); i++) { + src_addr = + tlv_buf_ptr + in_tlv_len; + dst_addr = + tlv_buf_ptr + in_tlv_len + + num_padding_bytes; + buf_mov_len = + curr_tlv_len - + ((i + 1) * in_tlv_len); + + wmi_tlv_OS_MEMMOVE(dst_addr, + src_addr, + buf_mov_len); + + tlv_buf_ptr += + attr_struct_ptr. + tag_struct_size; + } + + /* Move subsequent TLVs by number of bytes to be shrinked for all elements */ + if (param_buf_len > + (buf_idx + curr_tlv_len)) { + src_addr = + buf_ptr + curr_tlv_len; + dst_addr = + buf_ptr + curr_tlv_len + + (num_padding_bytes * + num_of_elems); + buf_mov_len = + param_buf_len - (buf_idx + + curr_tlv_len); + + wmi_tlv_OS_MEMMOVE(dst_addr, + src_addr, + buf_mov_len); + } + + /* Update the number of padding bytes to total number of bytes shrinked for all elements in the array */ + num_padding_bytes = + num_padding_bytes * num_of_elems; + + new_tlv_buf = buf_ptr; + } + } +#endif + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */ + + } else if (tlv_size_diff >= 0) { + /* Warning: some parameter truncation */ + if (tlv_size_diff > 0) { + wmi_tlv_print_verbose + ("%s: WARN: TLV truncated. tlv_size_diff=%d, curr_tlv_len=%d\n", + __func__, tlv_size_diff, curr_tlv_len); + } + /* TODO: this next line needs more comments and explanation */ + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = + (attr_struct_ptr.tag_varied_size + && !curr_tlv_len) ? NULL : (void *)buf_ptr; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 0; /* Indicates that buffer is not allocated */ + } else { + void *new_tlv_buf = NULL; + + /* Warning: Needs to allocate a larger structure and pad with zeros */ + wmi_tlv_print_verbose + ("%s: WARN: TLV needs padding. tlv_size_diff=%d\n", + __func__, tlv_size_diff); +#ifndef NO_DYNAMIC_MEM_ALLOC + /* Dynamic memory allocation is supported */ + wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf, + (curr_tlv_len - tlv_size_diff)); + if (new_tlv_buf == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for padding the TLV %d\n", + __func__, (curr_tlv_len - tlv_size_diff), + curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + wmi_tlv_OS_MEMZERO(new_tlv_buf, + (curr_tlv_len - tlv_size_diff)); + wmi_tlv_OS_MEMCPY(new_tlv_buf, (void *)buf_ptr, + curr_tlv_len); +#else + /* Dynamic memory allocation is not supported. Padding has to be done with in the existing buffer assuming we have enough space + to grow */ + { + /* Note: tlv_size_diff is a value less than zero */ + /* Move the Subsequent TLVs by amount of bytes needs to be padded */ + A_UINT8 *src_addr; + A_UINT8 *dst_addr; + A_UINT32 src_len; + + num_padding_bytes = (tlv_size_diff * -1); + + src_addr = buf_ptr + curr_tlv_len; + dst_addr = + buf_ptr + curr_tlv_len + num_padding_bytes; + src_len = + param_buf_len - (buf_idx + curr_tlv_len); + + wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, src_len); + + /* Set the padding bytes to zeroes */ + wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes); + + new_tlv_buf = buf_ptr; + } +#endif + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */ + } + + tlv_index++; + remaining_expected_tlvs--; + buf_ptr += curr_tlv_len + num_padding_bytes; + buf_idx += curr_tlv_len + num_padding_bytes; + } + + return (0); +Error_wmitlv_check_and_pad_tlvs: + if (is_cmd_id) { + wmitlv_free_allocated_command_tlvs(wmi_cmd_event_id, + wmi_cmd_struct_ptr); + } else { + wmitlv_free_allocated_event_tlvs(wmi_cmd_event_id, + wmi_cmd_struct_ptr); + } + *wmi_cmd_struct_ptr = NULL; + return (-1); +} + +/* + * Helper Function to validate and pad(if necessary) for incoming WMI Event TLVs + * Return 0 if success. + <0 if failure. + */ +int +wmitlv_check_and_pad_event_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + A_UINT32 is_cmd_id = 0; + return (wmitlv_check_and_pad_tlvs + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id, wmi_cmd_struct_ptr)); +} + +/* + * Helper Function to validate and pad(if necessary) for incoming WMI Command TLVs + * Return 0 if success. + <0 if failure. + */ +int +wmitlv_check_and_pad_command_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + A_UINT32 is_cmd_id = 1; + return (wmitlv_check_and_pad_tlvs + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id, wmi_cmd_struct_ptr)); +} + +/* + * Helper Function to free any allocated buffers for WMI Event/Command TLV processing + * Return None + */ +static void wmitlv_free_allocated_tlvs(A_UINT32 is_cmd_id, + A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + void *ptr = *wmi_cmd_struct_ptr; + + if (!ptr) { + wmi_tlv_print_error("%s: Nothing to free for CMD/Event 0x%x\n", + __func__, cmd_event_id); + return; + } +#ifndef NO_DYNAMIC_MEM_ALLOC + +/* macro to free that previously allocated memory for this TLV. When (op==FREE_TLV_ELEM). */ +#define WMITLV_OP_FREE_TLV_ELEM_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + if ((((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name)) && \ + (((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name != NULL)) \ + { \ + wmi_tlv_os_mem_free(((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name); \ + } + +#define WMITLV_FREE_TLV_ELEMS(id) \ +case id: \ +{ \ + WMITLV_TABLE(id, FREE_TLV_ELEM, NULL, 0) \ +} \ +break; + + if (is_cmd_id) { + switch (cmd_event_id) { + WMITLV_ALL_CMD_LIST(WMITLV_FREE_TLV_ELEMS); + default: + wmi_tlv_print_error + ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n", + __func__, cmd_event_id, cmd_event_id); + } + } else { + switch (cmd_event_id) { + WMITLV_ALL_EVT_LIST(WMITLV_FREE_TLV_ELEMS); + default: + wmi_tlv_print_error + ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n", + __func__, cmd_event_id, cmd_event_id); + } + } + + wmi_tlv_os_mem_free(*wmi_cmd_struct_ptr); + *wmi_cmd_struct_ptr = NULL; +#endif + + return; +} + +/* + * Helper Function to free any allocated buffers for WMI Command TLV processing + * Return None + */ +void wmitlv_free_allocated_command_tlvs(A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + wmitlv_free_allocated_tlvs(1, cmd_event_id, wmi_cmd_struct_ptr); +} + +/* + * Helper Function to free any allocated buffers for WMI Event TLV processing + * Return None + */ +void wmitlv_free_allocated_event_tlvs(A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + wmitlv_free_allocated_tlvs(0, cmd_event_id, wmi_cmd_struct_ptr); +} + +/* + * Returns 1 if the two given versions are compatible. + * Else return 0 if Incompatible. + */ +int +wmi_versions_are_compatible(wmi_abi_version *vers1, wmi_abi_version *vers2) +{ + if ((vers1->abi_version_ns_0 != vers2->abi_version_ns_0) || + (vers1->abi_version_ns_1 != vers2->abi_version_ns_1) || + (vers1->abi_version_ns_2 != vers2->abi_version_ns_2) || + (vers1->abi_version_ns_3 != vers2->abi_version_ns_3)) { + /* The namespaces are different. Incompatible. */ + return 0; + } + + if (vers1->abi_version_0 != vers2->abi_version_0) { + /* The major or minor versions are different. Incompatible */ + return 0; + } + /* We ignore the build version */ + return 1; +} + +/* + * Returns 1 if the two given versions are compatible. + * Else return 0 if Incompatible. + */ +int +wmi_versions_can_downgrade(int num_whitelist, + wmi_whitelist_version_info *version_whitelist_table, + wmi_abi_version *my_vers, + wmi_abi_version *opp_vers, + wmi_abi_version *out_vers) +{ + A_UINT8 can_try_to_downgrade; + A_UINT32 my_major_vers = WMI_VER_GET_MAJOR(my_vers->abi_version_0); + A_UINT32 my_minor_vers = WMI_VER_GET_MINOR(my_vers->abi_version_0); + A_UINT32 opp_major_vers = WMI_VER_GET_MAJOR(opp_vers->abi_version_0); + A_UINT32 opp_minor_vers = WMI_VER_GET_MINOR(opp_vers->abi_version_0); + A_UINT32 downgraded_minor_vers; + + if ((my_vers->abi_version_ns_0 != opp_vers->abi_version_ns_0) || + (my_vers->abi_version_ns_1 != opp_vers->abi_version_ns_1) || + (my_vers->abi_version_ns_2 != opp_vers->abi_version_ns_2) || + (my_vers->abi_version_ns_3 != opp_vers->abi_version_ns_3)) { + /* The namespaces are different. Incompatible. */ + can_try_to_downgrade = false; + } else if (my_major_vers != opp_major_vers) { + /* Major version is different. Incompatible and cannot downgrade. */ + can_try_to_downgrade = false; + } else { + /* Same major version. */ + + if (my_minor_vers < opp_minor_vers) { + /* Opposite party is newer. Incompatible and cannot downgrade. */ + can_try_to_downgrade = false; + } else if (my_minor_vers > opp_minor_vers) { + /* Opposite party is older. Check whitelist if we can downgrade */ + can_try_to_downgrade = true; + } else { + /* Same version */ + wmi_tlv_OS_MEMCPY(out_vers, my_vers, + sizeof(wmi_abi_version)); + return 1; + } + } + + if (!can_try_to_downgrade) { + wmi_tlv_print_error("%s: Warning: incompatible WMI version.\n", + __func__); + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + return 0; + } + /* Try to see we can downgrade the supported version */ + downgraded_minor_vers = my_minor_vers; + while (downgraded_minor_vers > opp_minor_vers) { + A_UINT8 downgraded = false; + int i; + + for (i = 0; i < num_whitelist; i++) { + if (version_whitelist_table[i].major != my_major_vers) { + continue; /* skip */ + } + if ((version_whitelist_table[i].namespace_0 != + my_vers->abi_version_ns_0) + || (version_whitelist_table[i].namespace_1 != + my_vers->abi_version_ns_1) + || (version_whitelist_table[i].namespace_2 != + my_vers->abi_version_ns_2) + || (version_whitelist_table[i].namespace_3 != + my_vers->abi_version_ns_3)) { + continue; /* skip */ + } + if (version_whitelist_table[i].minor == + downgraded_minor_vers) { + /* Found the next version that I can downgrade */ + wmi_tlv_print_error + ("%s: Note: found a whitelist entry to downgrade. wh. list ver: %d,%d,0x%x 0x%x 0x%x 0x%x\n", + __func__, version_whitelist_table[i].major, + version_whitelist_table[i].minor, + version_whitelist_table[i].namespace_0, + version_whitelist_table[i].namespace_1, + version_whitelist_table[i].namespace_2, + version_whitelist_table[i].namespace_3); + downgraded_minor_vers--; + downgraded = true; + break; + } + } + if (!downgraded) { + break; /* Done since we did not find any whitelist to downgrade version */ + } + } + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + out_vers->abi_version_0 = + WMI_VER_GET_VERSION_0(my_major_vers, downgraded_minor_vers); + if (downgraded_minor_vers != opp_minor_vers) { + wmi_tlv_print_error + ("%s: Warning: incompatible WMI version and cannot downgrade.\n", + __func__); + return 0; /* Incompatible */ + } else { + return 1; /* Compatible */ + } +} + +/* + * This routine will compare and set the WMI ABI version. + * First, compare my version with the opposite side's version. + * If incompatible, then check the whitelist to see if our side can downgrade. + * Finally, fill in the final ABI version into the output, out_vers. + * Return 0 if the output version is compatible . + * Else return 1 if the output version is incompatible. . + */ +int +wmi_cmp_and_set_abi_version(int num_whitelist, + wmi_whitelist_version_info * + version_whitelist_table, + struct _wmi_abi_version *my_vers, + struct _wmi_abi_version *opp_vers, + struct _wmi_abi_version *out_vers) +{ + wmi_tlv_print_verbose + ("%s: Our WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(my_vers->abi_version_0), + WMI_VER_GET_MINOR(my_vers->abi_version_0), my_vers->abi_version_1, + my_vers->abi_version_ns_0, my_vers->abi_version_ns_1, + my_vers->abi_version_ns_2, my_vers->abi_version_ns_3); + + wmi_tlv_print_verbose + ("%s: Opposite side WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(opp_vers->abi_version_0), + WMI_VER_GET_MINOR(opp_vers->abi_version_0), + opp_vers->abi_version_1, opp_vers->abi_version_ns_0, + opp_vers->abi_version_ns_1, opp_vers->abi_version_ns_2, + opp_vers->abi_version_ns_3); + + /* By default, the output version is our version. */ + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + if (!wmi_versions_are_compatible(my_vers, opp_vers)) { + /* Our host version and the given firmware version are incompatible. */ + if (wmi_versions_can_downgrade + (num_whitelist, version_whitelist_table, my_vers, opp_vers, + out_vers)) { + /* We can downgrade our host versions to match firmware. */ + wmi_tlv_print_error + ("%s: Host downgraded WMI Versions to match fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, + WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, + out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, + out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + return 0; /* Compatible */ + } else { + /* Warn: We cannot downgrade our host versions to match firmware. */ + wmi_tlv_print_error + ("%s: WARN: Host WMI Versions mismatch with fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, + WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, + out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, + out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + + return 1; /* Incompatible */ + } + } else { + /* We are compatible. Our host version is the output version */ + wmi_tlv_print_verbose + ("%s: Host and FW Compatible WMI Versions. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + return 0; /* Compatible */ + } +} diff --git a/core/wmi/wmi_tlv_platform.c b/core/wmi/wmi_tlv_platform.c new file mode 100644 index 0000000000..f3c20be4f0 --- /dev/null +++ b/core/wmi/wmi_tlv_platform.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * LMAC offload interface functions for WMI TLV Interface + */ + +#include "ol_if_athvar.h" +#include /* cdf_mem_malloc,free, etc. */ +#include +#include "htc_api.h" +#include "wmi.h" +#include "wma.h" + +/* QCA Main host has dynamic memory allocation and should not define NO_DYNAMIC_MEM_ALLOC */ +/* #define NO_DYNAMIC_MEM_ALLOC */ + +/* Following macro definitions use OS or platform specific functions */ +/* Following macro definitions use QCA MAIN windows host driver(applicable for Perigrene and its future platforms, + Pronto and its future platforms) specific APIs */ +#define dummy_print(fmt, ...) {} +#define wmi_tlv_print_verbose dummy_print +#define wmi_tlv_print_error cdf_print +#define wmi_tlv_OS_MEMCPY OS_MEMCPY +#define wmi_tlv_OS_MEMZERO OS_MEMZERO +#define wmi_tlv_OS_MEMMOVE OS_MEMMOVE + +#ifndef NO_DYNAMIC_MEM_ALLOC +#define wmi_tlv_os_mem_alloc(scn, ptr, numBytes) \ + { \ + (ptr) = os_malloc(NULL, (numBytes), GFP_ATOMIC); \ + } +#define wmi_tlv_os_mem_free cdf_mem_free +#endif diff --git a/core/wmi/wmi_unified.c b/core/wmi/wmi_unified.c new file mode 100644 index 0000000000..52a3ea5fed --- /dev/null +++ b/core/wmi/wmi_unified.c @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Host WMI unified implementation + */ +#include "athdefs.h" +#include "osapi_linux.h" +#include "a_types.h" +#include "a_debug.h" +#include "ol_if_athvar.h" +#include "ol_defines.h" +#include "ol_fw.h" +#include "htc_api.h" +#include "htc_api.h" +#include "dbglog_host.h" +#include "wmi.h" +#include "wmi_unified_priv.h" +#include "wma_api.h" +#include "wma.h" +#include "mac_trace.h" + +#define WMI_MIN_HEAD_ROOM 64 + +#ifdef WMI_INTERFACE_EVENT_LOGGING +/* WMI commands */ +uint32_t g_wmi_command_buf_idx = 0; +struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI commands TX completed */ +uint32_t g_wmi_command_tx_cmp_buf_idx = 0; +struct wmi_command_debug + wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI events when processed */ +uint32_t g_wmi_event_buf_idx = 0; +struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI events when queued */ +uint32_t g_wmi_rx_event_buf_idx = 0; +struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +#define WMI_COMMAND_RECORD(a, b) { \ + if (WMI_EVENT_DEBUG_MAX_ENTRY <= g_wmi_command_buf_idx) \ + g_wmi_command_buf_idx = 0; \ + wmi_command_log_buffer[g_wmi_command_buf_idx].command = a; \ + cdf_mem_copy(wmi_command_log_buffer[g_wmi_command_buf_idx].data, b, 16); \ + wmi_command_log_buffer[g_wmi_command_buf_idx].time = \ + cdf_get_log_timestamp(); \ + g_wmi_command_buf_idx++; \ +} + +#define WMI_COMMAND_TX_CMP_RECORD(a, b) { \ + if (WMI_EVENT_DEBUG_MAX_ENTRY <= g_wmi_command_tx_cmp_buf_idx) \ + g_wmi_command_tx_cmp_buf_idx = 0; \ + wmi_command_tx_cmp_log_buffer[g_wmi_command_tx_cmp_buf_idx].command = a; \ + cdf_mem_copy(wmi_command_tx_cmp_log_buffer \ + [g_wmi_command_tx_cmp_buf_idx].data, b, 16); \ + wmi_command_tx_cmp_log_buffer[g_wmi_command_tx_cmp_buf_idx].time = \ + cdf_get_log_timestamp(); \ + g_wmi_command_tx_cmp_buf_idx++; \ +} + +#define WMI_EVENT_RECORD(a, b) { \ + if (WMI_EVENT_DEBUG_MAX_ENTRY <= g_wmi_event_buf_idx) \ + g_wmi_event_buf_idx = 0; \ + wmi_event_log_buffer[g_wmi_event_buf_idx].event = a; \ + cdf_mem_copy(wmi_event_log_buffer[g_wmi_event_buf_idx].data, b, 16); \ + wmi_event_log_buffer[g_wmi_event_buf_idx].time = \ + cdf_get_log_timestamp(); \ + g_wmi_event_buf_idx++; \ +} + +#define WMI_RX_EVENT_RECORD(a,b) { \ + if (WMI_EVENT_DEBUG_MAX_ENTRY <= g_wmi_rx_event_buf_idx) \ + g_wmi_rx_event_buf_idx = 0; \ + wmi_rx_event_log_buffer[g_wmi_rx_event_buf_idx].event = a; \ + cdf_mem_copy(wmi_rx_event_log_buffer[g_wmi_rx_event_buf_idx].data, b, 16); \ + wmi_rx_event_log_buffer[g_wmi_rx_event_buf_idx].time = \ + cdf_get_log_timestamp(); \ + g_wmi_rx_event_buf_idx++; \ +} + +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + +static void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf); +int wmi_get_host_credits(wmi_unified_t wmi_handle); +/* WMI buffer APIs */ + +#ifdef MEMORY_DEBUG +wmi_buf_t +wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint16_t len, uint8_t *file_name, + uint32_t line_num) +{ + wmi_buf_t wmi_buf; + + if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { + CDF_ASSERT(0); + return NULL; + } + + wmi_buf = cdf_nbuf_alloc_debug(NULL, + roundup(len + WMI_MIN_HEAD_ROOM, 4), + WMI_MIN_HEAD_ROOM, 4, false, file_name, + line_num); + + if (!wmi_buf) + return NULL; + + /* Clear the wmi buffer */ + OS_MEMZERO(cdf_nbuf_data(wmi_buf), len); + + /* + * Set the length of the buffer to match the allocation size. + */ + cdf_nbuf_set_pktlen(wmi_buf, len); + + return wmi_buf; +} + +void wmi_buf_free(wmi_buf_t net_buf) +{ + cdf_nbuf_free(net_buf); +} +#else +wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, uint16_t len) +{ + wmi_buf_t wmi_buf; + + if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { + CDF_ASSERT(0); + return NULL; + } + + wmi_buf = cdf_nbuf_alloc(NULL, roundup(len + WMI_MIN_HEAD_ROOM, 4), + WMI_MIN_HEAD_ROOM, 4, false); + if (!wmi_buf) + return NULL; + + /* Clear the wmi buffer */ + OS_MEMZERO(cdf_nbuf_data(wmi_buf), len); + + /* + * Set the length of the buffer to match the allocation size. + */ + cdf_nbuf_set_pktlen(wmi_buf, len); + return wmi_buf; +} + +void wmi_buf_free(wmi_buf_t net_buf) +{ + cdf_nbuf_free(net_buf); +} +#endif + +/** + * wmi_get_max_msg_len() - get maximum WMI message length + * @wmi_handle: WMI handle. + * + * This function returns the maximum WMI message length + * + * Return: maximum WMI message length + */ +uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle) +{ + return wmi_handle->max_msg_len - WMI_MIN_HEAD_ROOM; +} + +static uint8_t *get_wmi_cmd_string(WMI_CMD_ID wmi_command) +{ + switch (wmi_command) { + /** initialize the wlan sub system */ + CASE_RETURN_STRING(WMI_INIT_CMDID); + + /* Scan specific commands */ + + /** start scan request to FW */ + CASE_RETURN_STRING(WMI_START_SCAN_CMDID); + /** stop scan request to FW */ + CASE_RETURN_STRING(WMI_STOP_SCAN_CMDID); + /** full list of channels as defined by the regulatory that will be used by scanner */ + CASE_RETURN_STRING(WMI_SCAN_CHAN_LIST_CMDID); + /** overwrite default priority table in scan scheduler */ + CASE_RETURN_STRING(WMI_SCAN_SCH_PRIO_TBL_CMDID); + /** This command to adjust the priority and min.max_rest_time + * of an on ongoing scan request. + */ + CASE_RETURN_STRING(WMI_SCAN_UPDATE_REQUEST_CMDID); + + /* PDEV(physical device) specific commands */ + /** set regulatorty ctl id used by FW to determine the exact ctl power limits */ + CASE_RETURN_STRING(WMI_PDEV_SET_REGDOMAIN_CMDID); + /** set channel. mainly used for supporting monitor mode */ + CASE_RETURN_STRING(WMI_PDEV_SET_CHANNEL_CMDID); + /** set pdev specific parameters */ + CASE_RETURN_STRING(WMI_PDEV_SET_PARAM_CMDID); + /** enable packet log */ + CASE_RETURN_STRING(WMI_PDEV_PKTLOG_ENABLE_CMDID); + /** disable packet log*/ + CASE_RETURN_STRING(WMI_PDEV_PKTLOG_DISABLE_CMDID); + /** set wmm parameters */ + CASE_RETURN_STRING(WMI_PDEV_SET_WMM_PARAMS_CMDID); + /** set HT cap ie that needs to be carried probe requests HT/VHT channels */ + CASE_RETURN_STRING(WMI_PDEV_SET_HT_CAP_IE_CMDID); + /** set VHT cap ie that needs to be carried on probe requests on VHT channels */ + CASE_RETURN_STRING(WMI_PDEV_SET_VHT_CAP_IE_CMDID); + + /** Command to send the DSCP-to-TID map to the target */ + CASE_RETURN_STRING(WMI_PDEV_SET_DSCP_TID_MAP_CMDID); + /** set quiet ie parameters. primarily used in AP mode */ + CASE_RETURN_STRING(WMI_PDEV_SET_QUIET_MODE_CMDID); + /** Enable/Disable Green AP Power Save */ + CASE_RETURN_STRING(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID); + /** get TPC config for the current operating channel */ + CASE_RETURN_STRING(WMI_PDEV_GET_TPC_CONFIG_CMDID); + + /** set the base MAC address for the physical device before a VDEV is created. + * For firmware that doesn’t support this feature and this command, the pdev + * MAC address will not be changed. */ + CASE_RETURN_STRING(WMI_PDEV_SET_BASE_MACADDR_CMDID); + + /* eeprom content dump , the same to bdboard data */ + CASE_RETURN_STRING(WMI_PDEV_DUMP_CMDID); + + /* VDEV(virtual device) specific commands */ + /** vdev create */ + CASE_RETURN_STRING(WMI_VDEV_CREATE_CMDID); + /** vdev delete */ + CASE_RETURN_STRING(WMI_VDEV_DELETE_CMDID); + /** vdev start request */ + CASE_RETURN_STRING(WMI_VDEV_START_REQUEST_CMDID); + /** vdev restart request (RX only, NO TX, used for CAC period)*/ + CASE_RETURN_STRING(WMI_VDEV_RESTART_REQUEST_CMDID); + /** vdev up request */ + CASE_RETURN_STRING(WMI_VDEV_UP_CMDID); + /** vdev stop request */ + CASE_RETURN_STRING(WMI_VDEV_STOP_CMDID); + /** vdev down request */ + CASE_RETURN_STRING(WMI_VDEV_DOWN_CMDID); + /* set a vdev param */ + CASE_RETURN_STRING(WMI_VDEV_SET_PARAM_CMDID); + /* set a key (used for setting per peer unicast and per vdev multicast) */ + CASE_RETURN_STRING(WMI_VDEV_INSTALL_KEY_CMDID); + + /* wnm sleep mode command */ + CASE_RETURN_STRING(WMI_VDEV_WNM_SLEEPMODE_CMDID); + CASE_RETURN_STRING(WMI_VDEV_WMM_ADDTS_CMDID); + CASE_RETURN_STRING(WMI_VDEV_WMM_DELTS_CMDID); + CASE_RETURN_STRING(WMI_VDEV_SET_WMM_PARAMS_CMDID); + CASE_RETURN_STRING(WMI_VDEV_SET_GTX_PARAMS_CMDID); + CASE_RETURN_STRING(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); + + CASE_RETURN_STRING(WMI_VDEV_PLMREQ_START_CMDID); + CASE_RETURN_STRING(WMI_VDEV_PLMREQ_STOP_CMDID); + CASE_RETURN_STRING(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + CASE_RETURN_STRING(WMI_VDEV_SET_IE_CMDID); + + /* peer specific commands */ + + /** create a peer */ + CASE_RETURN_STRING(WMI_PEER_CREATE_CMDID); + /** delete a peer */ + CASE_RETURN_STRING(WMI_PEER_DELETE_CMDID); + /** flush specific tid queues of a peer */ + CASE_RETURN_STRING(WMI_PEER_FLUSH_TIDS_CMDID); + /** set a parameter of a peer */ + CASE_RETURN_STRING(WMI_PEER_SET_PARAM_CMDID); + /** set peer to associated state. will cary all parameters determined during assocication time */ + CASE_RETURN_STRING(WMI_PEER_ASSOC_CMDID); + /**add a wds (4 address ) entry. used only for testing WDS feature on AP products */ + CASE_RETURN_STRING(WMI_PEER_ADD_WDS_ENTRY_CMDID); + /**remove wds (4 address ) entry. used only for testing WDS feature on AP products */ + CASE_RETURN_STRING(WMI_PEER_REMOVE_WDS_ENTRY_CMDID); + /** set up mcast group infor for multicast to unicast conversion */ + CASE_RETURN_STRING(WMI_PEER_MCAST_GROUP_CMDID); + /** request peer info from FW. FW shall respond with PEER_INFO_EVENTID */ + CASE_RETURN_STRING(WMI_PEER_INFO_REQ_CMDID); + + /* beacon/management specific commands */ + + /** transmit beacon by reference . used for transmitting beacon on low latency interface like pcie */ + CASE_RETURN_STRING(WMI_BCN_TX_CMDID); + /** transmit beacon by value */ + CASE_RETURN_STRING(WMI_PDEV_SEND_BCN_CMDID); + /** set the beacon template. used in beacon offload mode to setup the + * the common beacon template with the FW to be used by FW to generate beacons */ + CASE_RETURN_STRING(WMI_BCN_TMPL_CMDID); + /** set beacon filter with FW */ + CASE_RETURN_STRING(WMI_BCN_FILTER_RX_CMDID); + /* enable/disable filtering of probe requests in the firmware */ + CASE_RETURN_STRING(WMI_PRB_REQ_FILTER_RX_CMDID); + /** transmit management frame by value. will be deprecated */ + CASE_RETURN_STRING(WMI_MGMT_TX_CMDID); + /** set the probe response template. used in beacon offload mode to setup the + * the common probe response template with the FW to be used by FW to generate + * probe responses */ + CASE_RETURN_STRING(WMI_PRB_TMPL_CMDID); + + /** commands to directly control ba negotiation directly from host. only used in test mode */ + + /** turn off FW Auto addba mode and let host control addba */ + CASE_RETURN_STRING(WMI_ADDBA_CLEAR_RESP_CMDID); + /** send add ba request */ + CASE_RETURN_STRING(WMI_ADDBA_SEND_CMDID); + CASE_RETURN_STRING(WMI_ADDBA_STATUS_CMDID); + /** send del ba */ + CASE_RETURN_STRING(WMI_DELBA_SEND_CMDID); + /** set add ba response will be used by FW to generate addba response*/ + CASE_RETURN_STRING(WMI_ADDBA_SET_RESP_CMDID); + /** send single VHT MPDU with AMSDU */ + CASE_RETURN_STRING(WMI_SEND_SINGLEAMSDU_CMDID); + + /** Station power save specific config */ + /** enable/disable station powersave */ + CASE_RETURN_STRING(WMI_STA_POWERSAVE_MODE_CMDID); + /** set station power save specific parameter */ + CASE_RETURN_STRING(WMI_STA_POWERSAVE_PARAM_CMDID); + /** set station mimo powersave mode */ + CASE_RETURN_STRING(WMI_STA_MIMO_PS_MODE_CMDID); + + /** DFS-specific commands */ + /** enable DFS (radar detection)*/ + CASE_RETURN_STRING(WMI_PDEV_DFS_ENABLE_CMDID); + /** disable DFS (radar detection)*/ + CASE_RETURN_STRING(WMI_PDEV_DFS_DISABLE_CMDID); + /** enable DFS phyerr/parse filter offload */ + CASE_RETURN_STRING(WMI_DFS_PHYERR_FILTER_ENA_CMDID); + /** enable DFS phyerr/parse filter offload */ + CASE_RETURN_STRING(WMI_DFS_PHYERR_FILTER_DIS_CMDID); + + /* Roaming specific commands */ + /** set roam scan mode */ + CASE_RETURN_STRING(WMI_ROAM_SCAN_MODE); + /** set roam scan rssi threshold below which roam scan is enabled */ + CASE_RETURN_STRING(WMI_ROAM_SCAN_RSSI_THRESHOLD); + /** set roam scan period for periodic roam scan mode */ + CASE_RETURN_STRING(WMI_ROAM_SCAN_PERIOD); + /** set roam scan trigger rssi change threshold */ + CASE_RETURN_STRING(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + /** set roam AP profile */ + CASE_RETURN_STRING(WMI_ROAM_AP_PROFILE); + /** set channel list for roam scans */ + CASE_RETURN_STRING(WMI_ROAM_CHAN_LIST); + /** offload scan specific commands */ + /** set offload scan AP profile */ + CASE_RETURN_STRING(WMI_OFL_SCAN_ADD_AP_PROFILE); + /** remove offload scan AP profile */ + CASE_RETURN_STRING(WMI_OFL_SCAN_REMOVE_AP_PROFILE); + /** set offload scan period */ + CASE_RETURN_STRING(WMI_OFL_SCAN_PERIOD); + + /* P2P specific commands */ + /**set P2P device info. FW will used by FW to create P2P IE to be carried in probe response + * generated during p2p listen and for p2p discoverability */ + CASE_RETURN_STRING(WMI_P2P_DEV_SET_DEVICE_INFO); + /** enable/disable p2p discoverability on STA/AP VDEVs */ + CASE_RETURN_STRING(WMI_P2P_DEV_SET_DISCOVERABILITY); + /** set p2p ie to be carried in beacons generated by FW for GO */ + CASE_RETURN_STRING(WMI_P2P_GO_SET_BEACON_IE); + /** set p2p ie to be carried in probe response frames generated by FW for GO */ + CASE_RETURN_STRING(WMI_P2P_GO_SET_PROBE_RESP_IE); + /** set the vendor specific p2p ie data. FW will use this to parse the P2P NoA + * attribute in the beacons/probe responses received. + */ + CASE_RETURN_STRING(WMI_P2P_SET_VENDOR_IE_DATA_CMDID); + /** set the configure of p2p find offload */ + CASE_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_CONFIG_CMDID); + /** set the vendor specific p2p ie data for p2p find offload using */ + CASE_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_APPIE_CMDID); + /** set the BSSID/device name pattern of p2p find offload */ + CASE_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID); + /** set OppPS related parameters **/ + CASE_RETURN_STRING(WMI_P2P_SET_OPPPS_PARAM_CMDID); + + /** AP power save specific config */ + /** set AP power save specific param */ + CASE_RETURN_STRING(WMI_AP_PS_PEER_PARAM_CMDID); + /** set AP UAPSD coex pecific param */ + CASE_RETURN_STRING(WMI_AP_PS_PEER_UAPSD_COEX_CMDID); + + /** Rate-control specific commands */ + CASE_RETURN_STRING(WMI_PEER_RATE_RETRY_SCHED_CMDID); + + /** WLAN Profiling commands. */ + CASE_RETURN_STRING(WMI_WLAN_PROFILE_TRIGGER_CMDID); + CASE_RETURN_STRING(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID); + CASE_RETURN_STRING(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID); + CASE_RETURN_STRING(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); + CASE_RETURN_STRING(WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID); + + /** Suspend resume command Ids */ + CASE_RETURN_STRING(WMI_PDEV_SUSPEND_CMDID); + CASE_RETURN_STRING(WMI_PDEV_RESUME_CMDID); + + /* Beacon filter commands */ + /** add a beacon filter */ + CASE_RETURN_STRING(WMI_ADD_BCN_FILTER_CMDID); + /** remove a beacon filter */ + CASE_RETURN_STRING(WMI_RMV_BCN_FILTER_CMDID); + + /* WOW Specific WMI commands */ + /** add pattern for awake */ + CASE_RETURN_STRING(WMI_WOW_ADD_WAKE_PATTERN_CMDID); + /** deleta a wake pattern */ + CASE_RETURN_STRING(WMI_WOW_DEL_WAKE_PATTERN_CMDID); + /** enable/deisable wake event */ + CASE_RETURN_STRING(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + /** enable WOW */ + CASE_RETURN_STRING(WMI_WOW_ENABLE_CMDID); + /** host woke up from sleep event to FW. Generated in response to WOW Hardware event */ + CASE_RETURN_STRING(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + + /* RTT measurement related cmd */ + /** reques to make an RTT measurement */ + CASE_RETURN_STRING(WMI_RTT_MEASREQ_CMDID); + /** reques to report a tsf measurement */ + CASE_RETURN_STRING(WMI_RTT_TSF_CMDID); + + /** spectral scan command */ + /** configure spectral scan */ + CASE_RETURN_STRING(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); + /** enable/disable spectral scan and trigger */ + CASE_RETURN_STRING(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + + /* F/W stats */ + /** one time request for stats */ + CASE_RETURN_STRING(WMI_REQUEST_STATS_CMDID); + /** Push MCC Adaptive Scheduler Stats to Firmware */ + CASE_RETURN_STRING(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID); + + /** ARP OFFLOAD REQUEST*/ + CASE_RETURN_STRING(WMI_SET_ARP_NS_OFFLOAD_CMDID); + + /** Proactive ARP Response Add Pattern Command*/ + CASE_RETURN_STRING(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID); + + /** Proactive ARP Response Del Pattern Command*/ + CASE_RETURN_STRING(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID); + + /** NS offload confid*/ + CASE_RETURN_STRING(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + + /* GTK offload Specific WMI commands */ + CASE_RETURN_STRING(WMI_GTK_OFFLOAD_CMDID); + + /* CSA offload Specific WMI commands */ + /** csa offload enable */ + CASE_RETURN_STRING(WMI_CSA_OFFLOAD_ENABLE_CMDID); + /** chan switch command */ + CASE_RETURN_STRING(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID); + + /* Chatter commands */ + /* Change chatter mode of operation */ + CASE_RETURN_STRING(WMI_CHATTER_SET_MODE_CMDID); + /** chatter add coalescing filter command */ + CASE_RETURN_STRING(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID); + /** chatter delete coalescing filter command */ + CASE_RETURN_STRING(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID); + /** chatter coalecing query command */ + CASE_RETURN_STRING(WMI_CHATTER_COALESCING_QUERY_CMDID); + + /**addba specific commands */ + /** start the aggregation on this TID */ + CASE_RETURN_STRING(WMI_PEER_TID_ADDBA_CMDID); + /** stop the aggregation on this TID */ + CASE_RETURN_STRING(WMI_PEER_TID_DELBA_CMDID); + + /** set station mimo powersave method */ + CASE_RETURN_STRING(WMI_STA_DTIM_PS_METHOD_CMDID); + /** Configure the Station UAPSD AC Auto Trigger Parameters */ + CASE_RETURN_STRING(WMI_STA_UAPSD_AUTO_TRIG_CMDID); + /** Configure the Keep Alive Parameters */ + CASE_RETURN_STRING(WMI_STA_KEEPALIVE_CMDID); + + /* Request ssn from target for a sta/tid pair */ + CASE_RETURN_STRING(WMI_BA_REQ_SSN_CMDID); + /* misc command group */ + /** echo command mainly used for testing */ + CASE_RETURN_STRING(WMI_ECHO_CMDID); + + /* !!IMPORTANT!! + * If you need to add a new WMI command to the CASE_RETURN_STRING(WMI_GRP_MISC sub-group, + * please make sure you add it BEHIND CASE_RETURN_STRING(WMI_PDEV_UTF_CMDID); + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /** UTF WMI commands */ + CASE_RETURN_STRING(WMI_PDEV_UTF_CMDID); + + /** set debug log config */ + CASE_RETURN_STRING(WMI_DBGLOG_CFG_CMDID); + /* QVIT specific command id */ + CASE_RETURN_STRING(WMI_PDEV_QVIT_CMDID); + /* Factory Testing Mode request command + * used for integrated chipsets */ + CASE_RETURN_STRING(WMI_PDEV_FTM_INTG_CMDID); + /* set and get keepalive parameters command */ + CASE_RETURN_STRING(WMI_VDEV_SET_KEEPALIVE_CMDID); + CASE_RETURN_STRING(WMI_VDEV_GET_KEEPALIVE_CMDID); + /* For fw recovery test command */ + CASE_RETURN_STRING(WMI_FORCE_FW_HANG_CMDID); + /* Set Mcast/Bdcast filter */ + CASE_RETURN_STRING(WMI_SET_MCASTBCAST_FILTER_CMDID); + /** set thermal management params **/ + CASE_RETURN_STRING(WMI_THERMAL_MGMT_CMDID); + CASE_RETURN_STRING(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_LRO_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_MAWC_SENSOR_REPORT_IND_CMDID); + CASE_RETURN_STRING(WMI_ROAM_CONFIGURE_MAWC_CMDID); + CASE_RETURN_STRING(WMI_NLO_CONFIGURE_MAWC_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID); + /* GPIO Configuration */ + CASE_RETURN_STRING(WMI_GPIO_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_GPIO_OUTPUT_CMDID); + + /* Txbf configuration command */ + CASE_RETURN_STRING(WMI_TXBF_CMDID); + + /* FWTEST Commands */ + CASE_RETURN_STRING(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID); + /** set NoA descs **/ + CASE_RETURN_STRING(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + + /** TDLS Configuration */ + /** enable/disable TDLS */ + CASE_RETURN_STRING(WMI_TDLS_SET_STATE_CMDID); + /** set tdls peer state */ + CASE_RETURN_STRING(WMI_TDLS_PEER_UPDATE_CMDID); + + /** Resmgr Configuration */ + /** Adaptive OCS is enabled by default in the FW. This command is used to + * disable FW based adaptive OCS. + */ + CASE_RETURN_STRING + (WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + /** set the requested channel time quota for the home channels */ + CASE_RETURN_STRING(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + /** set the requested latency for the home channels */ + CASE_RETURN_STRING(WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + + /** STA SMPS Configuration */ + /** force SMPS mode */ + CASE_RETURN_STRING(WMI_STA_SMPS_FORCE_MODE_CMDID); + /** set SMPS parameters */ + CASE_RETURN_STRING(WMI_STA_SMPS_PARAM_CMDID); + + /* Wlan HB commands */ + /* enalbe/disable wlan HB */ + CASE_RETURN_STRING(WMI_HB_SET_ENABLE_CMDID); + /* set tcp parameters for wlan HB */ + CASE_RETURN_STRING(WMI_HB_SET_TCP_PARAMS_CMDID); + /* set tcp pkt filter for wlan HB */ + CASE_RETURN_STRING(WMI_HB_SET_TCP_PKT_FILTER_CMDID); + /* set udp parameters for wlan HB */ + CASE_RETURN_STRING(WMI_HB_SET_UDP_PARAMS_CMDID); + /* set udp pkt filter for wlan HB */ + CASE_RETURN_STRING(WMI_HB_SET_UDP_PKT_FILTER_CMDID); + + /** Wlan RMC commands*/ + /** enable/disable RMC */ + CASE_RETURN_STRING(WMI_RMC_SET_MODE_CMDID); + /** configure action frame period */ + CASE_RETURN_STRING(WMI_RMC_SET_ACTION_PERIOD_CMDID); + /** For debug/future enhancement purposes only, + * configures/finetunes RMC algorithms */ + CASE_RETURN_STRING(WMI_RMC_CONFIG_CMDID); + + /** WLAN MHF offload commands */ + /** enable/disable MHF offload */ + CASE_RETURN_STRING(WMI_MHF_OFFLOAD_SET_MODE_CMDID); + /** Plumb routing table for MHF offload */ + CASE_RETURN_STRING(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID); + + /*location scan commands */ + /*start batch scan */ + CASE_RETURN_STRING(WMI_BATCH_SCAN_ENABLE_CMDID); + /*stop batch scan */ + CASE_RETURN_STRING(WMI_BATCH_SCAN_DISABLE_CMDID); + /*get batch scan result */ + CASE_RETURN_STRING(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID); + /* OEM related cmd */ + CASE_RETURN_STRING(WMI_OEM_REQ_CMDID); + /* NAN request cmd */ + CASE_RETURN_STRING(WMI_NAN_CMDID); + /* Modem power state cmd */ + CASE_RETURN_STRING(WMI_MODEM_POWER_STATE_CMDID); + CASE_RETURN_STRING(WMI_REQUEST_STATS_EXT_CMDID); + CASE_RETURN_STRING(WMI_OBSS_SCAN_ENABLE_CMDID); + CASE_RETURN_STRING(WMI_OBSS_SCAN_DISABLE_CMDID); + CASE_RETURN_STRING(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID); + CASE_RETURN_STRING(WMI_ROAM_SCAN_CMD); + CASE_RETURN_STRING(WMI_PDEV_SET_LED_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + CASE_RETURN_STRING(WMI_CHAN_AVOID_UPDATE_CMDID); + CASE_RETURN_STRING(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID); + CASE_RETURN_STRING(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID); + CASE_RETURN_STRING(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID); + CASE_RETURN_STRING(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID); + CASE_RETURN_STRING(WMI_REQUEST_LINK_STATS_CMDID); + CASE_RETURN_STRING(WMI_START_LINK_STATS_CMDID); + CASE_RETURN_STRING(WMI_CLEAR_LINK_STATS_CMDID); + CASE_RETURN_STRING(WMI_GET_FW_MEM_DUMP_CMDID); + CASE_RETURN_STRING(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_LPI_START_SCAN_CMDID); + CASE_RETURN_STRING(WMI_LPI_STOP_SCAN_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_START_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_STOP_CMDID); + CASE_RETURN_STRING + (WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_SET_CAPABILITIES_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_GET_CAPABILITIES_CMDID); + CASE_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID); + CASE_RETURN_STRING(WMI_ROAM_SYNCH_COMPLETE); + CASE_RETURN_STRING(WMI_D0_WOW_ENABLE_DISABLE_CMDID); + CASE_RETURN_STRING(WMI_EXTWOW_ENABLE_CMDID); + CASE_RETURN_STRING(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + CASE_RETURN_STRING(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + CASE_RETURN_STRING(WMI_UNIT_TEST_CMDID); + CASE_RETURN_STRING(WMI_ROAM_SET_RIC_REQUEST_CMDID); + CASE_RETURN_STRING(WMI_PDEV_GET_TEMPERATURE_CMDID); + CASE_RETURN_STRING(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + CASE_RETURN_STRING(WMI_TPC_CHAINMASK_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID); + CASE_RETURN_STRING(WMI_SCAN_PROB_REQ_OUI_CMDID); + CASE_RETURN_STRING(WMI_TDLS_SET_OFFCHAN_MODE_CMDID); + CASE_RETURN_STRING(WMI_PDEV_SET_LED_FLASHING_CMDID); + CASE_RETURN_STRING(WMI_MDNS_OFFLOAD_ENABLE_CMDID); + CASE_RETURN_STRING(WMI_MDNS_SET_FQDN_CMDID); + CASE_RETURN_STRING(WMI_MDNS_SET_RESPONSE_CMDID); + CASE_RETURN_STRING(WMI_MDNS_GET_STATS_CMDID); + CASE_RETURN_STRING(WMI_ROAM_INVOKE_CMDID); + CASE_RETURN_STRING(WMI_SET_ANTENNA_DIVERSITY_CMDID); + CASE_RETURN_STRING(WMI_SAP_OFL_ENABLE_CMDID); + CASE_RETURN_STRING(WMI_APFIND_CMDID); + CASE_RETURN_STRING(WMI_PASSPOINT_LIST_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_OCB_SET_SCHED_CMDID); + CASE_RETURN_STRING(WMI_OCB_SET_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_OCB_SET_UTC_TIME_CMDID); + CASE_RETURN_STRING(WMI_OCB_START_TIMING_ADVERT_CMDID); + CASE_RETURN_STRING(WMI_OCB_STOP_TIMING_ADVERT_CMDID); + CASE_RETURN_STRING(WMI_OCB_GET_TSF_TIMER_CMDID); + CASE_RETURN_STRING(WMI_DCC_GET_STATS_CMDID); + CASE_RETURN_STRING(WMI_DCC_CLEAR_STATS_CMDID); + CASE_RETURN_STRING(WMI_DCC_UPDATE_NDL_CMDID); + CASE_RETURN_STRING(WMI_ROAM_FILTER_CMDID); + CASE_RETURN_STRING(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_DEBUG_MESG_FLUSH_CMDID); + CASE_RETURN_STRING(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID); + CASE_RETURN_STRING(WMI_SOC_SET_PCL_CMDID); + CASE_RETURN_STRING(WMI_SOC_SET_HW_MODE_CMDID); + CASE_RETURN_STRING(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID); + CASE_RETURN_STRING(WMI_DIAG_EVENT_LOG_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_PACKET_FILTER_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_PACKET_FILTER_ENABLE_CMDID); + CASE_RETURN_STRING(WMI_SAP_SET_BLACKLIST_PARAM_CMDID); + CASE_RETURN_STRING(WMI_WOW_UDP_SVC_OFLD_CMDID); + CASE_RETURN_STRING(WMI_MGMT_TX_SEND_CMDID); + CASE_RETURN_STRING(WMI_SOC_SET_ANTENNA_MODE_CMDID); + CASE_RETURN_STRING(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID); + CASE_RETURN_STRING(WMI_AP_PS_EGAP_PARAM_CMDID); + CASE_RETURN_STRING(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID); + } + return "Invalid WMI cmd"; +} + +#ifdef QCA_WIFI_3_0_EMU +static inline void wma_log_cmd_id(WMI_CMD_ID cmd_id) +{ + WMA_LOGE("Send WMI command:%s command_id:%d", + get_wmi_cmd_string(cmd_id), cmd_id); +} +#else +static inline void wma_log_cmd_id(WMI_CMD_ID cmd_id) +{ + WMA_LOGD("Send WMI command:%s command_id:%d", + get_wmi_cmd_string(cmd_id), cmd_id); +} +#endif + +/* WMI command API */ +int wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, int len, + WMI_CMD_ID cmd_id) +{ + HTC_PACKET *pkt; + A_STATUS status; + struct ol_softc *scn; + + if (cdf_atomic_read(&wmi_handle->is_target_suspended) && + ((WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID != cmd_id) && + (WMI_PDEV_RESUME_CMDID != cmd_id))) { + pr_err("%s: Target is suspended could not send WMI command\n", + __func__); + CDF_ASSERT(0); + return -EBUSY; + } + + /* Do sanity check on the TLV parameter structure */ + { + void *buf_ptr = (void *)cdf_nbuf_data(buf); + + if (wmitlv_check_command_tlv_params(NULL, buf_ptr, len, cmd_id) + != 0) { + cdf_print + ("\nERROR: %s: Invalid WMI Parameter Buffer for Cmd:%d\n", + __func__, cmd_id); + return -1; + } + } + + if (cdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) { + pr_err("%s, Failed to send cmd %x, no memory\n", + __func__, cmd_id); + return -ENOMEM; + } + + WMI_SET_FIELD(cdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); + + cdf_atomic_inc(&wmi_handle->pending_cmds); + if (cdf_atomic_read(&wmi_handle->pending_cmds) >= WMI_MAX_CMDS) { + scn = cds_get_context(CDF_MODULE_ID_HIF); + pr_err("\n%s: hostcredits = %d\n", __func__, + wmi_get_host_credits(wmi_handle)); + htc_dump_counter_info(wmi_handle->htc_handle); + /* dump_ce_register(scn); */ + /* dump_ce_debug_register(scn->hif_sc); */ + cdf_atomic_dec(&wmi_handle->pending_cmds); + pr_err("%s: MAX 1024 WMI Pending cmds reached.\n", __func__); + CDF_BUG(0); + return -EBUSY; + } + + pkt = cdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + cdf_atomic_dec(&wmi_handle->pending_cmds); + pr_err("%s, Failed to alloc htc packet %x, no memory\n", + __func__, cmd_id); + return -ENOMEM; + } + + SET_HTC_PACKET_INFO_TX(pkt, + NULL, + cdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR), + /* htt_host_data_dl_len(buf)+20 */ + wmi_handle->wmi_endpoint_id, 0 /*htc_tag */ ); + + SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf); + + wma_log_cmd_id(cmd_id); + +#ifdef WMI_INTERFACE_EVENT_LOGGING + cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); + /*Record 16 bytes of WMI cmd data - exclude TLV and WMI headers */ + WMI_COMMAND_RECORD(cmd_id, ((uint32_t *) cdf_nbuf_data(buf) + 2)); + cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); +#endif + + status = htc_send_pkt(wmi_handle->htc_handle, pkt); + + if (A_OK != status) { + cdf_atomic_dec(&wmi_handle->pending_cmds); + pr_err("%s %d, htc_send_pkt failed\n", __func__, __LINE__); + } + + return ((status == A_OK) ? EOK : -1); +} + +/* WMI Event handler register API */ +int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, + WMI_EVT_ID event_id) +{ + uint32_t idx = 0; + for (idx = 0; (idx < wmi_handle->max_event_idx && + idx < WMI_UNIFIED_MAX_EVENT); ++idx) { + if (wmi_handle->event_id[idx] == event_id && + wmi_handle->event_handler[idx] != NULL) { + return idx; + } + } + return -1; +} + +int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, + WMI_EVT_ID event_id, + wmi_unified_event_handler handler_func) +{ + uint32_t idx = 0; + + if (wmi_unified_get_event_handler_ix(wmi_handle, event_id) != -1) { + printk("%s : event handler already registered 0x%x \n", + __func__, event_id); + return -1; + } + if (wmi_handle->max_event_idx == WMI_UNIFIED_MAX_EVENT) { + printk("%s : no more event handlers 0x%x \n", + __func__, event_id); + return -1; + } + idx = wmi_handle->max_event_idx; + wmi_handle->event_handler[idx] = handler_func; + wmi_handle->event_id[idx] = event_id; + wmi_handle->max_event_idx++; + return 0; +} + +int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, + WMI_EVT_ID event_id) +{ + uint32_t idx = 0; + if ((idx = + wmi_unified_get_event_handler_ix(wmi_handle, event_id)) == -1) { + printk("%s : event handler is not registered: event id 0x%x \n", + __func__, event_id); + return -1; + } + wmi_handle->event_handler[idx] = NULL; + wmi_handle->event_id[idx] = 0; + --wmi_handle->max_event_idx; + wmi_handle->event_handler[idx] = + wmi_handle->event_handler[wmi_handle->max_event_idx]; + wmi_handle->event_id[idx] = + wmi_handle->event_id[wmi_handle->max_event_idx]; + return 0; +} + +#if 0 /* currently not used */ +static int wmi_unified_event_rx(struct wmi_unified *wmi_handle, + wmi_buf_t evt_buf) +{ + uint32_t id; + uint8_t *event; + uint16_t len; + int status = -1; + uint32_t idx = 0; + + ASSERT(evt_buf != NULL); + + id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + + if (cdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) + goto end; + + idx = wmi_unified_get_event_handler_ix(wmi_handle, id); + if (idx == -1) { + pr_err("%s : event handler is not registered: event id: 0x%x\n", + __func__, id); + goto end; + } + + event = cdf_nbuf_data(evt_buf); + len = cdf_nbuf_len(evt_buf); + + /* Call the WMI registered event handler */ + status = wmi_handle->event_handler[idx] (wmi_handle->scn_handle, + event, len); + +end: + cdf_nbuf_free(evt_buf); + return status; +} +#endif /* 0 */ +/* + * Event process by below function will be in tasket context. + * Please use this method only for time sensitive functions. + */ +static void wmi_process_fw_event_tasklet_ctx(struct wmi_unified *wmi_handle, + HTC_PACKET *htc_packet) +{ + + wmi_buf_t evt_buf; + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + + __wmi_control_rx(wmi_handle, evt_buf); + return; +} + +/* + * Event process by below function will be in mc_thread context. + * By default all event will be executed in mc_thread context. + * Use this method for all events which are processed by protocol stack. + * This method will reduce context switching and race conditions. + */ +static void wmi_process_fw_event_mc_thread_ctx(struct wmi_unified *wmi_handle, + HTC_PACKET *htc_packet) +{ + wmi_buf_t evt_buf; + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + + wmi_handle->wma_process_fw_event_handler_cbk(wmi_handle, evt_buf); + return; +} + +/* + * Event process by below function will be in worker thread context. + * Use this method for events which are not critical and not + * handled in protocol stack. + */ +static void wmi_process_fw_event_worker_thread_ctx + (struct wmi_unified *wmi_handle, HTC_PACKET *htc_packet) +{ + wmi_buf_t evt_buf; + uint32_t id; + uint8_t *data; + + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + data = cdf_nbuf_data(evt_buf); + + cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); + /* Exclude 4 bytes of TLV header */ + WMI_RX_EVENT_RECORD(id, ((uint8_t *) data + 4)); + cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); + cdf_spin_lock_bh(&wmi_handle->eventq_lock); + cdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); + cdf_spin_unlock_bh(&wmi_handle->eventq_lock); + schedule_work(&wmi_handle->rx_event_work); + return; +} + +/* + * Temporarily added to support older WMI events. We should move all events to unified + * when the target is ready to support it. + */ +void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; + wmi_buf_t evt_buf; + uint32_t id; + + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + switch (id) { + /*Event will be handled in tasklet ctx*/ + case WMI_TX_PAUSE_EVENTID: + case WMI_WOW_WAKEUP_HOST_EVENTID: + case WMI_PDEV_RESUME_EVENTID: + case WMI_D0_WOW_DISABLE_ACK_EVENTID: + wmi_process_fw_event_tasklet_ctx + (wmi_handle, htc_packet); + break; + /*Event will be handled in worker thread ctx*/ + case WMI_DEBUG_MESG_EVENTID: + case WMI_DFS_RADAR_EVENTID: + case WMI_PHYERR_EVENTID: + case WMI_PEER_STATE_EVENTID: + case WMI_MGMT_RX_EVENTID: + case WMI_ROAM_EVENTID: + wmi_process_fw_event_worker_thread_ctx + (wmi_handle, htc_packet); + break; + /*Event will be handled in mc_thread ctx*/ + default: + wmi_process_fw_event_mc_thread_ctx + (wmi_handle, htc_packet); + break; + } +} + +void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) +{ + __wmi_control_rx(wmi_handle, evt_buf); +} + +void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) +{ + uint32_t id; + uint8_t *data; + uint32_t len; + void *wmi_cmd_struct_ptr = NULL; + int tlv_ok_status = 0; + + id = WMI_GET_FIELD(cdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + + if (cdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) + goto end; + + data = cdf_nbuf_data(evt_buf); + len = cdf_nbuf_len(evt_buf); + + /* Validate and pad(if necessary) the TLVs */ + tlv_ok_status = wmitlv_check_and_pad_event_tlvs(wmi_handle->scn_handle, + data, len, id, + &wmi_cmd_struct_ptr); + if (tlv_ok_status != 0) { + pr_err("%s: Error: id=0x%d, wmitlv_check_and_pad_tlvs ret=%d\n", + __func__, id, tlv_ok_status); + goto end; + } + + if (id >= WMI_EVT_GRP_START_ID(WMI_GRP_START)) { + uint32_t idx = 0; + + idx = wmi_unified_get_event_handler_ix(wmi_handle, id); + if (idx == -1) { + pr_err + ("%s : event handler is not registered: event id 0x%x\n", + __func__, id); + goto end; + } +#ifdef WMI_INTERFACE_EVENT_LOGGING + cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); + /* Exclude 4 bytes of TLV header */ + WMI_EVENT_RECORD(id, ((uint8_t *) data + 4)); + cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); +#endif + /* Call the WMI registered event handler */ + wmi_handle->event_handler[idx] (wmi_handle->scn_handle, + wmi_cmd_struct_ptr, len); + goto end; + } + + switch (id) { + default: + pr_info("%s: Unhandled WMI event %d\n", __func__, id); + break; + case WMI_SERVICE_READY_EVENTID: + pr_info("%s: WMI UNIFIED SERVICE READY event\n", __func__); + wma_rx_service_ready_event(wmi_handle->scn_handle, + wmi_cmd_struct_ptr); + break; + case WMI_SERVICE_READY_EXT_EVENTID: + WMA_LOGA("%s: WMI UNIFIED SERVICE READY Extended event", + __func__); + wma_rx_service_ready_ext_event(wmi_handle->scn_handle, + wmi_cmd_struct_ptr); + break; + case WMI_READY_EVENTID: + pr_info("%s: WMI UNIFIED READY event\n", __func__); + wma_rx_ready_event(wmi_handle->scn_handle, wmi_cmd_struct_ptr); + break; + } +end: + wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); + cdf_nbuf_free(evt_buf); +} + +void wmi_rx_event_work(struct work_struct *work) +{ + struct wmi_unified *wmi = container_of(work, struct wmi_unified, + rx_event_work); + wmi_buf_t buf; + + cdf_spin_lock_bh(&wmi->eventq_lock); + buf = cdf_nbuf_queue_remove(&wmi->event_queue); + cdf_spin_unlock_bh(&wmi->eventq_lock); + while (buf) { + __wmi_control_rx(wmi, buf); + cdf_spin_lock_bh(&wmi->eventq_lock); + buf = cdf_nbuf_queue_remove(&wmi->event_queue); + cdf_spin_unlock_bh(&wmi->eventq_lock); + } +} + +/* WMI Initialization functions */ + +void *wmi_unified_attach(ol_scn_t scn_handle, + wma_process_fw_event_handler_cbk func) +{ + struct wmi_unified *wmi_handle; + wmi_handle = + (struct wmi_unified *)os_malloc(NULL, sizeof(struct wmi_unified), + GFP_ATOMIC); + if (wmi_handle == NULL) { + printk("allocation of wmi handle failed %zu \n", + sizeof(struct wmi_unified)); + return NULL; + } + OS_MEMZERO(wmi_handle, sizeof(struct wmi_unified)); + wmi_handle->scn_handle = scn_handle; + cdf_atomic_init(&wmi_handle->pending_cmds); + cdf_atomic_init(&wmi_handle->is_target_suspended); + cdf_spinlock_init(&wmi_handle->eventq_lock); + cdf_nbuf_queue_init(&wmi_handle->event_queue); +#ifdef CONFIG_CNSS + cnss_init_work(&wmi_handle->rx_event_work, wmi_rx_event_work); +#else + INIT_WORK(&wmi_handle->rx_event_work, wmi_rx_event_work); +#endif +#ifdef WMI_INTERFACE_EVENT_LOGGING + cdf_spinlock_init(&wmi_handle->wmi_record_lock); +#endif + wmi_handle->wma_process_fw_event_handler_cbk = func; + return wmi_handle; +} + +void wmi_unified_detach(struct wmi_unified *wmi_handle) +{ + wmi_buf_t buf; + + cds_flush_work(&wmi_handle->rx_event_work); + cdf_spin_lock_bh(&wmi_handle->eventq_lock); + buf = cdf_nbuf_queue_remove(&wmi_handle->event_queue); + while (buf) { + cdf_nbuf_free(buf); + buf = cdf_nbuf_queue_remove(&wmi_handle->event_queue); + } + cdf_spin_unlock_bh(&wmi_handle->eventq_lock); + if (wmi_handle != NULL) { + OS_FREE(wmi_handle); + wmi_handle = NULL; + } +} + +void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; + wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); +#ifdef WMI_INTERFACE_EVENT_LOGGING + uint32_t cmd_id; +#endif + + ASSERT(wmi_cmd_buf); +#ifdef WMI_INTERFACE_EVENT_LOGGING + cmd_id = WMI_GET_FIELD(cdf_nbuf_data(wmi_cmd_buf), + WMI_CMD_HDR, COMMANDID); + +#ifdef QCA_WIFI_3_0_EMU + printk("\nSent WMI command:%s command_id:0x%x over dma and recieved tx complete interupt\n", + get_wmi_cmd_string(cmd_id), cmd_id); +#endif + + cdf_spin_lock_bh(&wmi_handle->wmi_record_lock); + /* Record 16 bytes of WMI cmd tx complete data + - exclude TLV and WMI headers */ + WMI_COMMAND_TX_CMP_RECORD(cmd_id, + ((uint32_t *) cdf_nbuf_data(wmi_cmd_buf) + + 2)); + cdf_spin_unlock_bh(&wmi_handle->wmi_record_lock); +#endif + cdf_nbuf_free(wmi_cmd_buf); + cdf_mem_free(htc_pkt); + cdf_atomic_dec(&wmi_handle->pending_cmds); +} + +int +wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, + void *htc_handle) +{ + + int status; + HTC_SERVICE_CONNECT_RESP response; + HTC_SERVICE_CONNECT_REQ connect; + + OS_MEMZERO(&connect, sizeof(connect)); + OS_MEMZERO(&response, sizeof(response)); + + /* meta data is unused for now */ + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + /* these fields are the same for all service endpoints */ + connect.EpCallbacks.pContext = wmi_handle; + connect.EpCallbacks.EpTxCompleteMultiple = + NULL /* Control path completion ar6000_tx_complete */; + connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; + connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */; + connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */; + connect.EpCallbacks.EpTxComplete = + wmi_htc_tx_complete /* ar6000_tx_queue_full */; + + /* connect to control service */ + connect.ServiceID = WMI_CONTROL_SVC; + + if ((status = + htc_connect_service(htc_handle, &connect, &response)) != EOK) { + printk + (" Failed to connect to WMI CONTROL service status:%d \n", + status); + return -1;; + } + wmi_handle->wmi_endpoint_id = response.Endpoint; + wmi_handle->htc_handle = htc_handle; + wmi_handle->max_msg_len = response.MaxMsgLength; + + return EOK; +} + +int wmi_get_host_credits(wmi_unified_t wmi_handle) +{ + int host_credits; + + htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle, + &host_credits); + return host_credits; +} + +int wmi_get_pending_cmds(wmi_unified_t wmi_handle) +{ + return cdf_atomic_read(&wmi_handle->pending_cmds); +} + +void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val) +{ + cdf_atomic_set(&wmi_handle->is_target_suspended, val); +} + diff --git a/core/wmi/wmi_unified_api.h b/core/wmi/wmi_unified_api.h new file mode 100644 index 0000000000..5fc1322066 --- /dev/null +++ b/core/wmi/wmi_unified_api.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the API definitions for the Unified Wireless Module Interface (WMI). + */ + +#ifndef _WMI_UNIFIED_API_H_ +#define _WMI_UNIFIED_API_H_ + +#include +#include "a_types.h" +#include "ol_defines.h" +#include "wmi.h" +#include "htc_api.h" + +typedef cdf_nbuf_t wmi_buf_t; +#define wmi_buf_data(_buf) cdf_nbuf_data(_buf) + +/** + * attach for unified WMI + * + * @param scn_handle : handle to SCN. + * @return opaque handle. + */ +void *wmi_unified_attach(void *scn_handle, + int (*func)(struct wmi_unified *, wmi_buf_t)); +/** + * detach for unified WMI + * + * @param wmi_handle : handle to WMI. + * @return void. + */ +void wmi_unified_detach(struct wmi_unified *wmi_handle); + +/** + * generic function to allocate WMI buffer + * + * @param wmi_handle : handle to WMI. + * @param len : length of the buffer + * @return wmi_buf_t. + */ +#ifdef MEMORY_DEBUG +#define wmi_buf_alloc(h, l) wmi_buf_alloc_debug(h, l, __FILE__, __LINE__) +wmi_buf_t +wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint16_t len, + uint8_t *file_name, uint32_t line_num); +#else +wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, uint16_t len); +#endif + +/** + * generic function frees WMI net buffer + * + * @param net_buf : Pointer ot net_buf to be freed + */ +void wmi_buf_free(wmi_buf_t net_buf); + +/** + * generic function to send unified WMI command + * + * @param wmi_handle : handle to WMI. + * @param buf : wmi command buffer + * @param buflen : wmi command buffer length + * @return 0 on success and -ve on failure. + */ +int +wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, int buflen, + WMI_CMD_ID cmd_id); + +/** + * WMI event handler register function + * + * @param wmi_handle : handle to WMI. + * @param event_id : WMI event ID + * @param handler_func : Event handler call back function + * @return 0 on success and -ve on failure. + */ +int +wmi_unified_register_event_handler(wmi_unified_t wmi_handle, + WMI_EVT_ID event_id, + wmi_unified_event_handler handler_func); + +/** + * WMI event handler unregister function + * + * @param wmi_handle : handle to WMI. + * @param event_id : WMI event ID + * @return 0 on success and -ve on failure. + */ +int +wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, + WMI_EVT_ID event_id); + +/** + * request wmi to connet its htc service. + * @param wmi_handle : handle to WMI. + * @return void + */ +int +wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, + void *htc_handle); + +/* + * WMI API to verify the host has enough credits to suspend + */ + +int wmi_is_suspend_ready(wmi_unified_t wmi_handle); + +/** + WMI API to get updated host_credits + */ + +int wmi_get_host_credits(wmi_unified_t wmi_handle); + +/** + WMI API to get WMI Pending Commands in the HTC queue + */ + +int wmi_get_pending_cmds(wmi_unified_t wmi_handle); + +/** + WMI API to set target suspend state + */ + +void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val); + +/** + * WMA Callback to process fw event. + */ +typedef int (*wma_process_fw_event_handler_cbk)(struct wmi_unified *wmi_handle, + wmi_buf_t evt_buf); + +void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf); +uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle); +#endif /* _WMI_UNIFIED_API_H_ */ diff --git a/core/wmi/wmi_unified_priv.h b/core/wmi/wmi_unified_priv.h new file mode 100644 index 0000000000..f0f8702853 --- /dev/null +++ b/core/wmi/wmi_unified_priv.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the API definitions for the Unified Wireless Module Interface (WMI). + */ +#ifndef _WMI_UNIFIED_PRIV_H_ +#define _WMI_UNIFIED_PRIV_H_ +#include +#include "a_types.h" +#include "wmi.h" +#include "wmi_unified.h" +#include "cdf_atomic.h" + +#define WMI_UNIFIED_MAX_EVENT 0x100 +#define WMI_MAX_CMDS 1024 + +typedef cdf_nbuf_t wmi_buf_t; + +#ifdef WMI_INTERFACE_EVENT_LOGGING + +#define WMI_EVENT_DEBUG_MAX_ENTRY (1024) + +struct wmi_command_debug { + uint32_t command; + uint32_t data[4]; /*16 bytes of WMI cmd excluding TLV and WMI headers */ + uint64_t time; +}; + +struct wmi_event_debug { + uint32_t event; + uint32_t data[4]; /*16 bytes of WMI event data excluding TLV header */ + uint64_t time; +}; + +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + +#ifdef WLAN_OPEN_SOURCE +struct fwdebug { + struct sk_buff_head fwlog_queue; + struct completion fwlog_completion; + A_BOOL fwlog_open; +}; +#endif /* WLAN_OPEN_SOURCE */ + +struct wmi_unified { + ol_scn_t scn_handle; /* handle to device */ + cdf_atomic_t pending_cmds; + HTC_ENDPOINT_ID wmi_endpoint_id; + uint16_t max_msg_len; + WMI_EVT_ID event_id[WMI_UNIFIED_MAX_EVENT]; + wmi_unified_event_handler event_handler[WMI_UNIFIED_MAX_EVENT]; + uint32_t max_event_idx; + void *htc_handle; + cdf_spinlock_t eventq_lock; + cdf_nbuf_queue_t event_queue; + struct work_struct rx_event_work; +#ifdef WLAN_OPEN_SOURCE + struct fwdebug dbglog; + struct dentry *debugfs_phy; +#endif /* WLAN_OPEN_SOURCE */ + +#ifdef WMI_INTERFACE_EVENT_LOGGING + cdf_spinlock_t wmi_record_lock; +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + + cdf_atomic_t is_target_suspended; + int (*wma_process_fw_event_handler_cbk)(struct wmi_unified *wmi_handle, + wmi_buf_t evt_buf); +}; +#endif diff --git a/core/wmi/wmi_version_whitelist.c b/core/wmi/wmi_version_whitelist.c new file mode 100644 index 0000000000..ccad7fbeab --- /dev/null +++ b/core/wmi/wmi_version_whitelist.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Every Product Line or chipset or team can have its own Whitelist table. + * The following is a list of versions that the present software can support + * even though its versions are incompatible. Any entry here means that the + * indicated version does not break WMI compatibility even though it has + * a minor version change. + */ +wmi_whitelist_version_info version_whitelist[] = { + {0, 0, 0x5F414351, 0x00004C4D, 0, 0} + , /* Placeholder: Major=0, Minor=0, Namespace="QCA_ML" (Dummy entry) */ +}; diff --git a/target/inc/a_osapi.h b/target/inc/a_osapi.h new file mode 100644 index 0000000000..0eabec0a62 --- /dev/null +++ b/target/inc/a_osapi.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ============================================================================== */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ +#ifndef _A_OSAPI_H_ +#define _A_OSAPI_H_ + +#if defined(__linux__) && !defined(LINUX_EMULATION) +#include "osapi_linux.h" +#endif + +/*=== the following primitives have the same definition for all platforms ===*/ + +#define A_COMPILE_TIME_ASSERT(assertion_name, predicate) \ + typedef char assertion_name[(predicate) ? 1 : -1] + +/* + * If N is a power of 2, then N and N-1 are orthogonal + * (N-1 has all the least-significant bits set which are zero in N) + * so N ^ (N-1) = (N << 1) - 1 + */ +#define A_COMPILE_TIME_ASSERT_IS_PWR2(assertion_name, value) \ + A_COMPILE_TIME_ASSERT (assertion_name, \ + (((value) ^ ((value)-1)) == ((value) << 1) - 1)) + +#ifndef __ubicom32__ +#define HIF_MALLOC_DIAGMEM(osdev, size, pa, context, retry) \ + os_malloc_CONSISTENT(osdev, size, pa, context, retry) +#define HIF_FREE_DIAGMEM(osdev, size, vaddr, pa, context) \ + OS_FREE_CONSISTENT(osdev, size, vaddr, pa, context) +#define HIF_DIAGMEM_SYNC(osdev, pa, size, dir, context) +#else +#define HIF_MALLOC_DIAGMEM(osdev, size, pa, context, retry) \ + os_malloc_NONCONSISTENT(osdev, size, pa, context, retry) +#define HIF_FREE_DIAGMEM(osdev, size, vaddr, pa, context) \ + OS_FREE_NONCONSISTENT(osdev, size, vaddr, pa, context) +#define HIF_DIAGMEM_SYNC(osdev, pa, size, dir, context) \ + OS_SYNC_SINGLE(osdev, pa, size, dir, context) +#endif /* ubicom32 */ + +#endif /* _OSAPI_H_ */ diff --git a/target/inc/a_usb_defs.h b/target/inc/a_usb_defs.h new file mode 100644 index 0000000000..1664a0a158 --- /dev/null +++ b/target/inc/a_usb_defs.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +/* + * Shared USB definitions + * + * + * + * + */ + +#ifndef __A_USB_DEFS_H__ +#define __A_USB_DEFS_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* USB endpoint definitions */ + +#define USB_EP_ADDR_APP_CTRL_IN 0x81 +#define USB_EP_ADDR_APP_DATA_IN 0x82 +#define USB_EP_ADDR_APP_DATA2_IN 0x83 +#define USB_EP_ADDR_APP_INT_IN 0x84 + +#define USB_EP_ADDR_APP_CTRL_OUT 0x01 +#define USB_EP_ADDR_APP_DATA_LP_OUT 0x02 +#define USB_EP_ADDR_APP_DATA_MP_OUT 0x03 +#define USB_EP_ADDR_APP_DATA_HP_OUT 0x04 + +#define USB_CONTROL_REQ_SEND_BMI_CMD 1 +#define USB_CONTROL_REQ_RECV_BMI_RESP 2 +#define USB_CONTROL_REQ_DIAG_CMD 3 +#define USB_CONTROL_REQ_DIAG_RESP 4 + +/* #define USB_CONTROL_MAX_BMI_TRANSFER_SIZE 64 */ +#define USB_CONTROL_MAX_BMI_TRANSFER_SIZE 252 + +#define HIF_BMI_MAX_TRANSFER_SIZE USB_CONTROL_MAX_BMI_TRANSFER_SIZE + +/* 512 Bytes Maxp for High Speed for BULK EP */ +#define USB_HS_BULK_MAXP_SIZE 0x200 +/* 64 Bytes Maxp for Full Speed for BULK EP */ +#define USB_FS_BULK_MAXP_SIZE 0x40 + +/* diagnostic command defnitions */ +#define USB_CTRL_DIAG_CC_READ 0 +#define USB_CTRL_DIAG_CC_WRITE 1 +#define USB_CTRL_DIAG_CC_WARM_RESET 2 + +typedef PREPACK struct { + A_UINT32 Cmd; + A_UINT32 Address; + A_UINT32 Value; + A_UINT32 _pad[1]; +} POSTPACK USB_CTRL_DIAG_CMD_WRITE; + +typedef PREPACK struct { + A_UINT32 Cmd; + A_UINT32 Address; +} POSTPACK USB_CTRL_DIAG_CMD_READ; + +typedef PREPACK struct { + A_UINT32 ReadValue; +} POSTPACK USB_CTRL_DIAG_RESP_READ; + +#define USB_CTRL_MAX_DIAG_CMD_SIZE (sizeof(USB_CTRL_DIAG_CMD_WRITE)) +#define USB_CTRL_MAX_DIAG_RESP_SIZE (sizeof(USB_CTRL_DIAG_RESP_READ)) + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif diff --git a/target/inc/apb_athr_wlan_map.h b/target/inc/apb_athr_wlan_map.h new file mode 100644 index 0000000000..3e48543f0d --- /dev/null +++ b/target/inc/apb_athr_wlan_map.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _APB_ATHR_WLAN_MAP_H_ +#define _APB_ATHR_WLAN_MAP_H_ + +#define RTC_SOC_BASE_ADDRESS 0x00004000 +#define RTC_WMAC_BASE_ADDRESS 0x00005000 +#define MAC_COEX_BASE_ADDRESS 0x00006000 +#define BT_COEX_BASE_ADDRESS 0x00007000 +#define SOC_PCIE_BASE_ADDRESS 0x00008000 +#define SOC_CORE_BASE_ADDRESS 0x00009000 +#define WLAN_UART_BASE_ADDRESS 0x0000c000 +#define WLAN_SI_BASE_ADDRESS 0x00010000 +#define WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 +#define WLAN_MAC_BASE_ADDRESS 0x00020000 +#define EFUSE_BASE_ADDRESS 0x00030000 +#define FPGA_REG_BASE_ADDRESS 0x00039000 +#define WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define CE_WRAPPER_BASE_ADDRESS 0x00057000 +#define CE0_BASE_ADDRESS 0x00057400 +#define CE1_BASE_ADDRESS 0x00057800 +#define CE2_BASE_ADDRESS 0x00057c00 +#define CE3_BASE_ADDRESS 0x00058000 +#define CE4_BASE_ADDRESS 0x00058400 +#define CE5_BASE_ADDRESS 0x00058800 +#define CE6_BASE_ADDRESS 0x00058c00 +#define CE7_BASE_ADDRESS 0x00059000 +#define DBI_BASE_ADDRESS 0x00060000 +#define WLAN_MBOX_BASE_ADDRESS 0x00068000 +#define WLAN_DBG_UART_BASE_ADDRESS 0x00069000 +#define USB_DMA_BASE_ADDRESS 0x0006a000 + +#endif /* _APB_ATHR_WLAN_MAP_REG_H_ */ diff --git a/target/inc/athdefs.h b/target/inc/athdefs.h new file mode 100644 index 0000000000..d1ee6cb6ab --- /dev/null +++ b/target/inc/athdefs.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __ATHDEFS_H__ +#define __ATHDEFS_H__ + +/* + * This file contains definitions that may be used across both + * Host and Target software. Nothing here is module-dependent + * or platform-dependent. + */ + +/* + * Generic error codes that can be used by hw, sta, ap, sim, dk + * and any other environments. Since these are enums, feel free to + * add any more codes that you need. + */ + +typedef enum { + A_ERROR = -1, /* Generic error return */ + A_OK = 0, /* success */ + /* Following values start at 1 */ + A_DEVICE_NOT_FOUND, /* not able to find PCI device */ + A_NO_MEMORY, /* not able to allocate memory, not available */ + A_MEMORY_NOT_AVAIL, /* memory region is not free for mapping */ + A_NO_FREE_DESC, /* no free descriptors available */ + A_BAD_ADDRESS, /* address does not match descriptor */ + A_WIN_DRIVER_ERROR, /* used in NT_HW version, if problem at init */ + A_REGS_NOT_MAPPED, /* registers not correctly mapped */ + A_EPERM, /* Not superuser */ + A_EACCES, /* Access denied */ + A_ENOENT, /* No such entry, search failed, etc. */ + A_EEXIST, /* The object already exists (can't create) */ + A_EFAULT, /* Bad address fault */ + A_EBUSY, /* Object is busy */ + A_EINVAL, /* Invalid parameter */ + A_EMSGSIZE, /* Inappropriate message buffer length */ + A_ECANCELED, /* Operation canceled */ + A_ENOTSUP, /* Operation not supported */ + A_ECOMM, /* Communication error on send */ + A_EPROTO, /* Protocol error */ + A_ENODEV, /* No such device */ + A_EDEVNOTUP, /* device is not UP */ + A_NO_RESOURCE, /* No resources for requested operation */ + A_HARDWARE, /* Hardware failure */ + A_PENDING, /* Asynchronous routine; will send up results la + ter (typically in callback) */ + A_EBADCHANNEL, /* The channel cannot be used */ + A_DECRYPT_ERROR, /* Decryption error */ + A_PHY_ERROR, /* RX PHY error */ + A_CONSUMED, /* Object was consumed */ + A_CLONE, /* The buffer is cloned */ + A_USB_ERROR, /* Rome USB Target error */ +} A_STATUS; + +#define A_SUCCESS(x) (x == A_OK) +#define A_FAILED(x) (!A_SUCCESS(x)) + +#endif /* __ATHDEFS_H__ */ diff --git a/target/inc/athendpack.h b/target/inc/athendpack.h new file mode 100644 index 0000000000..977909eb6e --- /dev/null +++ b/target/inc/athendpack.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef VXWORKS +#endif /* VXWORKS */ + +#if defined(LINUX) || defined(__linux__) +#endif /* LINUX */ + +#ifdef QNX +#endif /* QNX */ diff --git a/target/inc/bin_sig.h b/target/inc/bin_sig.h new file mode 100644 index 0000000000..b723acc2bd --- /dev/null +++ b/target/inc/bin_sig.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012,2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef BIN_SIGN_H_ +#define BIN_SIGN_H_ + +#define SIGN_HEADER_MAGIC 0x454D4F52 + +/* Signed binary MetaData */ +typedef struct { + unsigned int magic_num; + unsigned int total_len; + unsigned int rampatch_len; + unsigned int product_id; + unsigned int patch_ver; + unsigned short sign_format_ver; + unsigned short sign_algorithm; + unsigned char reserved[8]; +} SIGN_HEADER_T; + +#endif /* BIN_SIGN_H_ */ diff --git a/target/inc/bmi_msg.h b/target/inc/bmi_msg.h new file mode 100644 index 0000000000..11982cfabe --- /dev/null +++ b/target/inc/bmi_msg.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __BMI_MSG_H__ +#define __BMI_MSG_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* + * Bootloader Messaging Interface (BMI) + * + * BMI is a very simple messaging interface used during initialization + * to read memory, write memory, execute code, and to define an + * application entry PC. + * + * It is used to download an application to AR6K, to provide + * patches to code that is already resident on AR6K, and generally + * to examine and modify state. The Host has an opportunity to use + * BMI only once during bootup. Once the Host issues a BMI_DONE + * command, this opportunity ends. + * + * The Host writes BMI requests to mailbox0, and reads BMI responses + * from mailbox0. BMI requests all begin with a command + * (see below for specific commands), and are followed by + * command-specific data. + * + * Flow control: + * The Host can only issue a command once the Target gives it a + * "BMI Command Credit", using AR6K Counter #4. As soon as the + * Target has completed a command, it issues another BMI Command + * Credit (so the Host can issue the next command). + * + * BMI handles all required Target-side cache flushing. + */ + +/* Maximum data size used for BMI transfers */ +#define BMI_DATASZ_MAX 256 + +/* BMI Commands */ + +#define BMI_NO_COMMAND 0 + +#define BMI_DONE 1 +/* + * Semantics: Host is done using BMI + * Request format: + * A_UINT32 command (BMI_DONE) + * Response format: none + */ + +#define BMI_READ_MEMORY 2 +/* + * Semantics: Host reads AR6K memory + * Request format: + * A_UINT32 command (BMI_READ_MEMORY) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * Response format: + * A_UINT8 data[length] + */ + +#define BMI_WRITE_MEMORY 3 +/* + * Semantics: Host writes AR6K memory + * Request format: + * A_UINT32 command (BMI_WRITE_MEMORY) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * A_UINT8 data[length] + * Response format: none + */ +/* + * Capbility to write "segmented files" is provided for two reasons + * 1) backwards compatibility for certain situations where Hosts + * have limited flexibility + * 2) because it's darn convenient. + * + * A segmented file consists of a file header followed by an arbitrary number + * of segments. Each segment contains segment metadata -- a Target address and + * a length -- followed by "length" bytes of data. A segmented file ends with + * a segment that specifies length=BMI_SGMTFILE_DONE. When a segmented file + * is sent to the Target, firmware writes each segment to the specified address. + * + * Special cases: + * 1) If a segment's metadata indicates length=BMI_SGMTFILE_EXEC, then the + * specified address is used as a function entry point for a brief function + * with prototype "(void *)(void)". That function is called immediately. + * After execution of the function completes, firmware continues with the + * next segment. No data is expected when length=BMI_SGMTFILE_EXEC. + * + * 2) If a segment's metadata indicates length=BMI_SGMTFILE_BEGINADDR, then + * the specified address is established as the application start address + * so that a subsequent BMI_DONE jumps there. + * + * 3) If a segment's metadata indicates length=BMI_SGMTFILE_BDDATA, then + * the specified address is used as the (possibly compressed) length of board + * data, which is loaded into the proper Target address as specified by + * hi_board_data. In addition, the hi_board_data_initialized flag is set. + * + * A segmented file is sent to the Target using a sequence of 1 or more + * BMI_WRITE_MEMORY commands. The first such command must have + * address=BMI_SEGMENTED_WRITE_ADDR. Subsequent BMI_WRITE_MEMORY commands + * can use an arbitrary address. In each BMI_WRITE_MEMORY command, the + * length specifies the number of data bytes transmitted (except for the + * special cases listed above). + * + * Alternatively, a segmented file may be sent to the Target using a + * BMI_LZ_STREAM_START command with address=BMI_SEGMENTED_WRITE_ADDR + * followed by a series of BMI_LZ_DATA commands that each send the next portion + * of the segmented file. + * + * The data segments may be lz77 compressed. In this case, the segmented file + * header flag, BMI_SGMTFILE_FLAG_COMPRESS, must be set. Note that segmented + * file METAdata is never compressed; only the data segments themselves are + * compressed. There is no way to mix compressed and uncompressed data segments + * in a single segmented file. Compressed (or uncompressed) segments are handled + * by both BMI_WRITE_MEMORY and by BMI_LZ_DATA commands. (Compression is an + * attribute of the segmented file rather than of the command used to transmit + * it.) + */ +#define BMI_SEGMENTED_WRITE_ADDR 0x1234 + +/* File header for a segmented file */ +struct bmi_segmented_file_header { + A_UINT32 magic_num; + A_UINT32 file_flags; +}; +#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */ +#define BMI_SGMTFILE_FLAG_COMPRESS 1 + +/* Metadata for a segmented file segment */ +struct bmi_segmented_metadata { + A_UINT32 addr; + A_UINT32 length; +}; +/* Special values for bmi_segmented_metadata.length (all have high bit set) */ +#define BMI_SGMTFILE_DONE 0xffffffff /* end of segmented data */ +#define BMI_SGMTFILE_BDDATA 0xfffffffe /* Board Data segment */ +#define BMI_SGMTFILE_BEGINADDR 0xfffffffd /* set beginning address */ +#define BMI_SGMTFILE_EXEC 0xfffffffc /* immediate function execution */ + +#define BMI_EXECUTE 4 +/* + * Semantics: Causes AR6K to execute code + * Request format: + * A_UINT32 command (BMI_EXECUTE) + * A_UINT32 address + * A_UINT32 parameter + * Response format: + * A_UINT32 return value + */ +/* + * Note: In order to support the segmented file feature + * (see BMI_WRITE_MEMORY), when the address specified in a + * BMI_EXECUTE command matches (same physical address) + * BMI_SEGMENTED_WRITE_ADDR, it is ignored. Instead, execution + * begins at the address specified by hi_app_start. + */ + +#define BMI_SET_APP_START 5 +/* + * Semantics: Set Target application starting address + * Request format: + * A_UINT32 command (BMI_SET_APP_START) + * A_UINT32 address + * Response format: none + */ + +#define BMI_READ_SOC_REGISTER 6 +#define BMI_READ_SOC_WORD 6 +/* + * Semantics: Read a 32-bit Target SOC word. + * Request format: + * A_UINT32 command (BMI_READ_REGISTER) + * A_UINT32 address + * Response format: + * A_UINT32 value + */ + +#define BMI_WRITE_SOC_REGISTER 7 +#define BMI_WRITE_SOC_WORD 7 +/* + * Semantics: Write a 32-bit Target SOC word. + * Request format: + * A_UINT32 command (BMI_WRITE_REGISTER) + * A_UINT32 address + * A_UINT32 value + * + * Response format: none + */ + +#define BMI_GET_TARGET_ID 8 +#define BMI_GET_TARGET_INFO 8 +/* + * Semantics: Fetch the 4-byte Target information + * Request format: + * A_UINT32 command (BMI_GET_TARGET_ID/INFO) + * + * Response format1 (old firmware): + * A_UINT32 TargetVersionID + * + * Response format2 (intermediate firmware, during transition): + * A_UINT32 TARGET_VERSION_SENTINAL + * struct bmi_target_info; + * + * Response format3 (newest firmware) + * struct bmi_target_info; + */ +#ifdef FEATURE_BMI_2 +PREPACK struct bmi_target_info { + /* size of this structure */ + A_UINT32 target_info_byte_count; + A_UINT32 target_ver; + A_UINT32 target_type; + A_UINT32 flags; +} POSTPACK; +#else +PREPACK struct bmi_target_info { + /* size of this structure */ + A_UINT32 target_info_byte_count; + A_UINT32 target_ver; + A_UINT32 target_type; +} POSTPACK; +#endif +#define TARGET_VERSION_SENTINAL 0xffffffff +#define BMI_ROMPATCH_INSTALL 9 +/* + * Semantics: Install a ROM Patch. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_INSTALL) + * A_UINT32 Target ROM Address + * A_UINT32 Target RAM Address or Value (depending on Target Type) + * A_UINT32 Size, in bytes + * A_UINT32 Activate? 1-->activate; + * 0-->install but do not activate + * Response format: + * A_UINT32 PatchID + */ + +#define BMI_ROMPATCH_UNINSTALL 10 +/* + * Semantics: Uninstall a previously-installed ROM Patch, + * automatically deactivating, if necessary. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_UNINSTALL) + * A_UINT32 PatchID + * + * Response format: none + */ + +#define BMI_ROMPATCH_ACTIVATE 11 +/* + * Semantics: Activate a list of previously-installed ROM Patches. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_ACTIVATE) + * A_UINT32 rompatch_count + * A_UINT32 PatchID[rompatch_count] + * + * Response format: none + */ + +#define BMI_ROMPATCH_DEACTIVATE 12 +/* + * Semantics: Deactivate a list of active ROM Patches. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_DEACTIVATE) + * A_UINT32 rompatch_count + * A_UINT32 PatchID[rompatch_count] + * + * Response format: none + */ + +#define BMI_LZ_STREAM_START 13 +/* + * Semantics: Begin an LZ-compressed stream of input + * which is to be uncompressed by the Target to an + * output buffer at address. The output buffer must + * be sufficiently large to hold the uncompressed + * output from the compressed input stream. This BMI + * command should be followed by a series of 1 or more + * BMI_LZ_DATA commands. + * A_UINT32 command (BMI_LZ_STREAM_START) + * A_UINT32 address + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_LZ_DATA 14 +/* + * Semantics: Host writes AR6K memory with LZ-compressed + * data which is uncompressed by the Target. This command + * must be preceded by a BMI_LZ_STREAM_START command. A series + * of BMI_LZ_DATA commands are considered part of a single + * input stream until another BMI_LZ_STREAM_START is issued. + * Request format: + * A_UINT32 command (BMI_LZ_DATA) + * A_UINT32 length (of compressed data), + * at most BMI_DATASZ_MAX + * A_UINT8 CompressedData[length] + * Response format: none + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_NVRAM_PROCESS 15 +#define BMI_NVRAM_SEG_NAME_SZ 16 +/* + * Semantics: Cause Target to search NVRAM (if any) for a + * segment with the specified name and process it according + * to NVRAM metadata. + * Request format: + * A_UINT32 command (BMI_NVRAM_PROCESS) + * A_UCHAR name[BMI_NVRAM_SEG_NAME_SZ] name (LE format) + * Response format: + * A_UINT32 0, if nothing was executed; + * otherwise the value returned from the + * last NVRAM segment that was executed + */ + +#define BMI_SIGN_STREAM_START 17 +/* + * Semantics: Trigger target start/end binary signature verification + * flow. + * Request format: + * A_UINT32 command (BMI_SIGN_STREAM_START) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * A_UINT8 data[length] + * Response format: none + */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +/* TBDXXX: Need a better place for these */ +#define BMI_CE_NUM_TO_TARG 0 +#define BMI_CE_NUM_TO_HOST 1 + +#endif /* __BMI_MSG_H__ */ diff --git a/target/inc/cepci.h b/target/inc/cepci.h new file mode 100644 index 0000000000..9cebbc590d --- /dev/null +++ b/target/inc/cepci.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CEPCI_H__ +#define __CEPCI_H__ + +/* + * Support for Copy Engine over PCI. + * Structures shared between Host software and Target firmware. + */ + +/* + * Total number of PCIe MSI interrupts requested for all interrupt sources. + * PCIe standard forces this to be a power of 2. + * Some Host OS's limit MSI requests that can be granted to 8 + * so for now we abide by this limit and avoid requesting more + * than that. + */ +#define MSI_NUM_REQUEST_LOG2 4 +#define MSI_NUM_REQUEST 1 /* (1<hi_interconnect_state points + * here (and all members are 32-bit quantities in order to + * facilitate Host access). In particular, Host software is + * required to initialize pipe_cfg_addr and svc_to_pipe_map. + */ +struct pcie_state_s { + A_UINT32 pipe_cfg_addr; /* Pipe configuration Target address */ + /* NB: CE_pipe_config[CE_COUNT] */ + + A_UINT32 svc_to_pipe_map; /* Service to pipe map Target address */ + /* NB: service_to_pipe[PIPE_TO_CE_MAP_CN] */ + + A_UINT32 MSI_requested; /* number of MSI interrupts requested */ + A_UINT32 MSI_granted; /* number of MSI interrupts granted */ + A_UINT32 MSI_addr; /* Message Signalled Interrupt address */ + A_UINT32 MSI_data; /* Base data */ + A_UINT32 MSI_fw_intr_data; /* Data for firmware interrupt; + MSI data for other interrupts are + in various SoC registers */ + + A_UINT32 power_mgmt_method; /* PCIE_PWR_METHOD_* */ + A_UINT32 config_flags; /* PCIE_CONFIG_FLAG_* */ +}; + +/* + * PCIE_CONFIG_FLAG definitions + */ +#define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001 +#define PCIE_CONFIG_FLAG_CLK_SWITCH_WAIT 0x0000002 +#define PCIE_CONFIG_FLAG_AXI_CLK_GATE 0x0000004 + +#define PIPE_TO_CE_MAP_CNT 32 /* simple implementation constant */ + +/* + * Configuration information for a Copy Engine pipe. + * Passed from Host to Target during startup (one per CE). + */ +struct CE_pipe_config { + A_UINT32 pipenum; + A_UINT32 pipedir; + A_UINT32 nentries; + A_UINT32 nbytes_max; + A_UINT32 flags; + A_UINT32 reserved; +}; + +/* + * HIA Map Definition + */ +struct host_interest_area_t { + uint32_t hi_interconnect_state; + uint32_t hi_early_alloc; + uint32_t hi_option_flag2; + uint32_t hi_board_data; + uint32_t hi_board_data_initialized; + uint32_t hi_failure_state; + uint32_t hi_rddi_msi_num; + uint32_t hi_pcie_perst_couple_en; + uint32_t hi_sw_protocol_version; +}; + +struct shadow_reg_cfg { + A_UINT16 ce_id; + A_UINT16 reg_offset; +}; + +#endif /* __CEPCI_H__ */ diff --git a/target/inc/dbglog.h b/target/inc/dbglog.h new file mode 100644 index 0000000000..94cf15430c --- /dev/null +++ b/target/inc/dbglog.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2012, 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_H_ +#define _DBGLOG_H_ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +#include "wlan_module_ids.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define DBGLOG_TIMESTAMP_OFFSET 0 +#define DBGLOG_TIMESTAMP_MASK 0xFFFFFFFF /* Bit 0-15. Contains bit + 8-23 of the LF0 timer */ +#define DBGLOG_DBGID_OFFSET 0 +#define DBGLOG_DBGID_MASK 0x000003FF /* Bit 0-9 */ +#define DBGLOG_DBGID_NUM_MAX 256 /* Upper limit is width of mask */ + +#define DBGLOG_MODULEID_OFFSET 10 +#define DBGLOG_MODULEID_MASK 0x0003FC00 /* Bit 10-17 */ +#define DBGLOG_MODULEID_NUM_MAX 32 /* Upper limit is width of mask */ + +#define DBGLOG_VDEVID_OFFSET 18 +#define DBGLOG_VDEVID_MASK 0x03FC0000 /* Bit 20-25 */ +#define DBGLOG_VDEVID_NUM_MAX 16 + +#define DBGLOG_NUM_ARGS_OFFSET 26 +#define DBGLOG_NUM_ARGS_MASK 0xFC000000 /* Bit 26-31 */ +/* it is limited bcoz of limitations of corebsp MSG*() to accept max 9 arg */ +#define DBGLOG_NUM_ARGS_MAX 9 + +#define DBGLOG_LOG_BUFFER_SIZE 1500 +#define DBGLOG_DBGID_DEFINITION_LEN_MAX 90 + +#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE + +#define DBGLOG_GET_DBGID(arg) \ + ((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET) + +#define DBGLOG_GET_MODULEID(arg) \ + ((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET) + +#define DBGLOG_GET_VDEVID(arg) \ + ((arg & DBGLOG_VDEVID_MASK) >> DBGLOG_VDEVID_OFFSET) + +#define DBGLOG_GET_NUMARGS(arg) \ + ((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET) + +#define DBGLOG_GET_TIME_STAMP(arg) \ + ((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET) + +#define DIAG_FWID_OFFSET 24 +#define DIAG_FWID_MASK 0xFF000000 /* Bit 24-31 */ + +#define DIAG_TIMESTAMP_OFFSET 0 +#define DIAG_TIMESTAMP_MASK 0x00FFFFFF /* Bit 0-23 */ + +#define DIAG_ID_OFFSET 16 +#define DIAG_ID_MASK 0xFFFF0000 /* Bit 16-31 */ + +#define DIAG_VDEVID_OFFSET 11 +#define DIAG_VDEVID_MASK 0x0000F800 /* Bit 11-15 */ +#define DIAG_VDEVID_NUM_MAX 16 + +#define DIAG_VDEVLEVEL_OFFSET 8 +#define DIAG_VDEVLEVEL_MASK 0x00000700 /* Bit 8-10 */ + +#define DIAG_PAYLEN_OFFSET 0 +#define DIAG_PAYLEN_MASK 0x000000FF /* Bit 0-7 */ + +#define DIAG_PAYLEN_OFFSET16 0 +#define DIAG_PAYLEN_MASK16 0x0000FFFF /* Bit 0-16 */ + +#define DIAG_GET_TYPE(arg) \ + ((arg & DIAG_FWID_MASK) >> DIAG_FWID_OFFSET) + +#define DIAG_GET_TIME_STAMP(arg) \ + ((arg & DIAG_TIMESTAMP_MASK) >> DIAG_TIMESTAMP_OFFSET) + +#define DIAG_GET_ID(arg) \ + ((arg & DIAG_ID_MASK) >> DIAG_ID_OFFSET) + +#define DIAG_GET_VDEVID(arg) \ + ((arg & DIAG_VDEVID_MASK) >> DIAG_VDEVID_OFFSET) + +#define DIAG_GET_VDEVLEVEL(arg) \ + ((arg & DIAG_VDEVLEVEL_MASK) >> DIAG_VDEVLEVEL_OFFSET) + +#define DIAG_GET_PAYLEN(arg) \ + ((arg & DIAG_PAYLEN_MASK) >> DIAG_PAYLEN_OFFSET) + +#define DIAG_GET_PAYLEN16(arg) \ + ((arg & DIAG_PAYLEN_MASK16) >> DIAG_PAYLEN_OFFSET16) + +/* Debug Log levels*/ + +typedef enum { + DBGLOG_VERBOSE = 0, + DBGLOG_INFO, + DBGLOG_INFO_LVL_1, + DBGLOG_INFO_LVL_2, + DBGLOG_WARN, + DBGLOG_ERR, + DBGLOG_LVL_MAX +} DBGLOG_LOG_LVL; + +PREPACK struct dbglog_buf_s { + struct dbglog_buf_s *next; + A_UINT8 *buffer; + A_UINT32 bufsize; + A_UINT32 length; + A_UINT32 count; + A_UINT32 free; +} POSTPACK; + +PREPACK struct dbglog_hdr_s { + struct dbglog_buf_s *dbuf; + A_UINT32 dropped; +} POSTPACK; + +PREPACK struct dbglog_buf_host { + A_UINT32 next; + A_UINT32 buffer; + A_UINT32 bufsize; + A_UINT32 length; + A_UINT32 count; + A_UINT32 free; +} POSTPACK; + +PREPACK struct dbglog_hdr_host { + A_UINT32 dbuf; + A_UINT32 dropped; +} POSTPACK; + +#define DBGLOG_MAX_VDEVID 15 /* 0-15 */ + +#ifdef __cplusplus +} +#endif +#endif /* _DBGLOG_H_ */ diff --git a/target/inc/dbglog_id.h b/target/inc/dbglog_id.h new file mode 100644 index 0000000000..7ddea2d88a --- /dev/null +++ b/target/inc/dbglog_id.h @@ -0,0 +1,1586 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_ID_H_ +#define _DBGLOG_ID_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The target state machine framework will send dbglog messages on behalf on + * other modules. We do this do avoid each target module adding identical + * dbglog code for state transitions and event processing. We also don't want + * to force each module to define the the same XXX_DBGID_SM_MSG with the same + * value below. Instead we use a special ID that the host dbglog code + * recognizes as a message sent by the SM on behalf on another module. + */ +#define DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG 1000 + +/* + * The nomenclature for the debug identifiers is MODULE_DESCRIPTION. + * Please ensure that the definition of any new debugid introduced is captured + * between the _DBGID_DEFINITION_START and + * _DBGID_DEFINITION_END defines. The structure is required for the + * parser to correctly pick up the values for different debug identifiers. + */ + +/* + * The target state machine framework will send dbglog messages on behalf on + * other modules. We do this do avoid each module adding identical dbglog code + * for state transitions and event processing. We also don't want to force each + * module to define the the same XXX_DBGID_SM_MSG with the same value below. + * Instead we use a special ID that the host dbglog code recognizes as a + * message sent by the SM on behalf on another module. + */ +#define DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG 1000 + +/* INF debug identifier definitions */ +#define INF_DBGID_DEFINITION_START 0 +#define INF_ASSERTION_FAILED 1 +#define INF_TARGET_ID 2 +#define INF_TARGET_MEM_REMAING 3 +#define INF_TARGET_MEM_EXT_REMAING 4 +#define INF_TARGET_MEM_ALLOC_TRACK 5 +#define INF_TARGET_MEM_ALLOC_RAM 6 +#define INF_DBGID_DEFINITION_END 7 + +/* WMI debug identifier definitions */ +#define WMI_DBGID_DEFINITION_START 0 +#define WMI_CMD_RX_XTND_PKT_TOO_SHORT 1 +#define WMI_EXTENDED_CMD_NOT_HANDLED 2 +#define WMI_CMD_RX_PKT_TOO_SHORT 3 +#define WMI_CALLING_WMI_EXTENSION_FN 4 +#define WMI_CMD_NOT_HANDLED 5 +#define WMI_IN_SYNC 6 +#define WMI_TARGET_WMI_SYNC_CMD 7 +#define WMI_SET_SNR_THRESHOLD_PARAMS 8 +#define WMI_SET_RSSI_THRESHOLD_PARAMS 9 +#define WMI_SET_LQ_TRESHOLD_PARAMS 10 +#define WMI_TARGET_CREATE_PSTREAM_CMD 11 +#define WMI_WI_DTM_INUSE 12 +#define WMI_TARGET_DELETE_PSTREAM_CMD 13 +#define WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD 14 +#define WMI_TARGET_GET_BIT_RATE_CMD 15 +#define WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS 16 +#define WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD 17 +#define WMI_TARGET_GET_TX_PWR_CMD 18 +#define WMI_FREE_EVBUF_WMIBUF 19 +#define WMI_FREE_EVBUF_DATABUF 20 +#define WMI_FREE_EVBUF_BADFLAG 21 +#define WMI_HTC_RX_ERROR_DATA_PACKET 22 +#define WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX 23 +#define WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT 24 +#define WMI_SENDING_READY_EVENT 25 +#define WMI_SETPOWER_MDOE_TO_MAXPERF 26 +#define WMI_SETPOWER_MDOE_TO_REC 27 +#define WMI_BSSINFO_EVENT_FROM 28 +#define WMI_TARGET_GET_STATS_CMD 29 +#define WMI_SENDING_SCAN_COMPLETE_EVENT 30 +#define WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT 31 +#define WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT 32 +#define WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT 33 +#define WMI_SENDING_ERROR_REPORT_EVENT 34 +#define WMI_SENDING_CAC_EVENT 35 +#define WMI_TARGET_GET_ROAM_TABLE_CMD 36 +#define WMI_TARGET_GET_ROAM_DATA_CMD 37 +#define WMI_SENDING_GPIO_INTR_EVENT 38 +#define WMI_SENDING_GPIO_ACK_EVENT 39 +#define WMI_SENDING_GPIO_DATA_EVENT 40 +#define WMI_CMD_RX 41 +#define WMI_CMD_RX_XTND 42 +#define WMI_EVENT_SEND 43 +#define WMI_EVENT_SEND_XTND 44 +#define WMI_CMD_PARAMS_DUMP_START 45 +#define WMI_CMD_PARAMS_DUMP_END 46 +#define WMI_CMD_PARAMS 47 +#define WMI_EVENT_ALLOC_FAILURE 48 +#define WMI_DBGID_DCS_PARAM_CMD 49 +#define WMI_SEND_EVENT_WRONG_TLV 50 +#define WMI_SEND_EVENT_NO_TLV_DEF 51 +#define WMI_DBGID_DEFINITION_END 52 + +/* PM Message definition*/ +#define PS_STA_DEFINITION_START 0 +#define PS_STA_PM_ARB_REQUEST 1 +#define PS_STA_DELIVER_EVENT 2 +#define PS_STA_PSPOLL_SEQ_DONE 3 +#define PS_STA_COEX_MODE 4 +#define PS_STA_PSPOLL_ALLOW 5 +#define PS_STA_SET_PARAM 6 +#define PS_STA_SPECPOLL_TIMER_STARTED 7 +#define PS_STA_SPECPOLL_TIMER_STOPPED 8 +#define PS_STA_AVG_CHANNEL_CONGESTION 9 +#define PS_STA_DEFINITION_END 10 + +/** RESMGR dbg ids */ +/* TODO: 1. Segregate IDs as per sub-module. (Give 100 per sub-module?) + * 2. Add chmgr IDs over here. + * 3. Update prints in dbglog_host.c + * 4. Deprecate WLAN_MODULE_RESMGR_CHAN_MANAGER */ +#define RESMGR_DEFINITION_START 0 +#define RESMGR_OCS_ALLOCRAM_SIZE 1 +#define RESMGR_OCS_RESOURCES 2 +#define RESMGR_LINK_CREATE 3 +#define RESMGR_LINK_DELETE 4 +#define RESMGR_OCS_CHREQ_CREATE 5 +#define RESMGR_OCS_CHREQ_DELETE 6 +#define RESMGR_OCS_CHREQ_START 7 +#define RESMGR_OCS_CHREQ_STOP 8 +#define RESMGR_OCS_SCHEDULER_INVOKED 9 +#define RESMGR_OCS_CHREQ_GRANT 10 +#define RESMGR_OCS_CHREQ_COMPLETE 11 +#define RESMGR_OCS_NEXT_TSFTIME 12 +#define RESMGR_OCS_TSF_TIMEOUT_US 13 +#define RESMGR_OCS_CURR_CAT_WINDOW 14 +#define RESMGR_OCS_CURR_CAT_WINDOW_REQ 15 +#define RESMGR_OCS_CURR_CAT_WINDOW_TIMESLOT 16 +#define RESMGR_OCS_CHREQ_RESTART 17 +#define RESMGR_OCS_CLEANUP_CH_ALLOCATORS 18 +#define RESMGR_OCS_PURGE_CHREQ 19 +#define RESMGR_OCS_CH_ALLOCATOR_FREE 20 +#define RESMGR_OCS_RECOMPUTE_SCHEDULE 21 +#define RESMGR_OCS_NEW_CAT_WINDOW_REQ 22 +#define RESMGR_OCS_NEW_CAT_WINDOW_TIMESLOT 23 +#define RESMGR_OCS_CUR_CH_ALLOC 24 +#define RESMGR_OCS_WIN_CH_ALLOC 25 +#define RESMGR_OCS_SCHED_CH_CHANGE 26 +#define RESMGR_OCS_CONSTRUCT_CAT_WIN 27 +#define RESMGR_OCS_CHREQ_PREEMPTED 28 +#define RESMGR_OCS_CH_SWITCH_REQ 29 +#define RESMGR_OCS_CHANNEL_SWITCHED 30 +#define RESMGR_OCS_CLEANUP_STALE_REQS 31 +#define RESMGR_OCS_CHREQ_UPDATE 32 +#define RESMGR_OCS_REG_NOA_NOTIF 33 +#define RESMGR_OCS_DEREG_NOA_NOTIF 34 +#define RESMGR_OCS_GEN_PERIODIC_NOA 35 +#define RESMGR_OCS_RECAL_QUOTAS 36 +#define RESMGR_OCS_GRANTED_QUOTA_STATS 37 +#define RESMGR_OCS_ALLOCATED_QUOTA_STATS 38 +#define RESMGR_OCS_REQ_QUOTA_STATS 39 +#define RESMGR_OCS_TRACKING_TIME_FIRED 40 +#define RESMGR_VC_ARBITRATE_ATTRIBUTES 41 +#define RESMGR_OCS_LATENCY_STRICT_TIME_SLOT 42 +#define RESMGR_OCS_CURR_TSF 43 +#define RESMGR_OCS_QUOTA_REM 44 +#define RESMGR_OCS_LATENCY_CASE_NO 45 +#define RESMGR_OCS_WIN_CAT_DUR 46 +#define RESMGR_VC_UPDATE_CUR_VC 47 +#define RESMGR_VC_REG_UNREG_LINK 48 +#define RESMGR_VC_PRINT_LINK 49 +#define RESMGR_OCS_MISS_TOLERANCE 50 +#define RESMGR_DYN_SCH_ALLOCRAM_SIZE 51 +#define RESMGR_DYN_SCH_ENABLE 52 +#define RESMGR_DYN_SCH_ACTIVE 53 +#define RESMGR_DYN_SCH_CH_STATS_START 54 +#define RESMGR_DYN_SCH_CH_SX_STATS 55 +#define RESMGR_DYN_SCH_TOT_UTIL_PER 56 +#define RESMGR_DYN_SCH_HOME_CH_QUOTA 57 +#define RESMGR_OCS_REG_RECAL_QUOTA_NOTIF 58 +#define RESMGR_OCS_DEREG_RECAL_QUOTA_NOTIF 59 +#define RESMGR_DYN_SCH_CH_STATS_END 60 +#define RESMGR_DEFINITION_END 61 + +/* RESMGR CHNMGR debug ids */ +#define RESMGR_CHMGR_DEFINITION_START 0 +#define RESMGR_CHMGR_PAUSE_COMPLETE 1 +#define RESMGR_CHMGR_CHANNEL_CHANGE 2 +#define RESMGR_CHMGR_RESUME_COMPLETE 3 +#define RESMGR_CHMGR_VDEV_PAUSE 4 +#define RESMGR_CHMGR_VDEV_UNPAUSE 5 +#define RESMGR_CHMGR_CTS2S_TX_COMP 6 +#define RESMGR_CHMGR_CFEND_TX_COMP 7 +#define RESMGR_CHMGR_DEFINITION_END 8 + +/* VDEV manager debug ids */ +#define VDEV_MGR_DEFINITION_START 0 +#define VDEV_MGR_FIRST_BMISS_DETECTED 1 +#define VDEV_MGR_FINAL_BMISS_DETECTED 2 +#define VDEV_MGR_BCN_IN_SYNC 3 +#define VDEV_MGR_AP_KEEPALIVE_IDLE 4 +#define VDEV_MGR_AP_KEEPALIVE_INACTIVE 5 +#define VDEV_MGR_AP_KEEPALIVE_UNRESPONSIVE 6 +#define VDEV_MGR_AP_TBTT_CONFIG 7 +#define VDEV_MGR_FIRST_BCN_RECEIVED 8 +#define VDEV_MGR_VDEV_START 9 +#define VDEV_MGR_VDEV_UP 10 +#define VDEV_MGR_PEER_AUTHORIZED 11 +#define VDEV_MGR_OCS_HP_LP_REQ_POSTED 12 +#define VDEV_MGR_VDEV_START_OCS_HP_REQ_COMPLETE 13 +#define VDEV_MGR_VDEV_START_OCS_HP_REQ_STOP 14 +#define VDEV_MGR_HP_START_TIME 15 +#define VDEV_MGR_VDEV_PAUSE_DELAY_UPDATE 16 +#define VDEV_MGR_VDEV_PAUSE_FAIL 17 +#define VDEV_MGR_GEN_PERIODIC_NOA 18 +#define VDEV_MGR_OFF_CHAN_GO_CH_REQ_SETUP 19 +#define VDEV_MGR_DEFINITION_END 20 + +/* WHAL debug identifier definitions */ +#define WHAL_DBGID_DEFINITION_START 0 +#define WHAL_ERROR_ANI_CONTROL 1 +#define WHAL_ERROR_CHIP_TEST1 2 +#define WHAL_ERROR_CHIP_TEST2 3 +#define WHAL_ERROR_EEPROM_CHECKSUM 4 +#define WHAL_ERROR_EEPROM_MACADDR 5 +#define WHAL_ERROR_INTERRUPT_HIU 6 +#define WHAL_ERROR_KEYCACHE_RESET 7 +#define WHAL_ERROR_KEYCACHE_SET 8 +#define WHAL_ERROR_KEYCACHE_TYPE 9 +#define WHAL_ERROR_KEYCACHE_TKIPENTRY 10 +#define WHAL_ERROR_KEYCACHE_WEPLENGTH 11 +#define WHAL_ERROR_PHY_INVALID_CHANNEL 12 +#define WHAL_ERROR_POWER_AWAKE 13 +#define WHAL_ERROR_POWER_SET 14 +#define WHAL_ERROR_RECV_STOPDMA 15 +#define WHAL_ERROR_RECV_STOPPCU 16 +#define WHAL_ERROR_RESET_CHANNF1 17 +#define WHAL_ERROR_RESET_CHANNF2 18 +#define WHAL_ERROR_RESET_PM 19 +#define WHAL_ERROR_RESET_OFFSETCAL 20 +#define WHAL_ERROR_RESET_RFGRANT 21 +#define WHAL_ERROR_RESET_RXFRAME 22 +#define WHAL_ERROR_RESET_STOPDMA 23 +#define WHAL_ERROR_RESET_ERRID 24 +#define WHAL_ERROR_RESET_ADCDCCAL1 25 +#define WHAL_ERROR_RESET_ADCDCCAL2 26 +#define WHAL_ERROR_RESET_TXIQCAL 27 +#define WHAL_ERROR_RESET_RXIQCAL 28 +#define WHAL_ERROR_RESET_CARRIERLEAK 29 +#define WHAL_ERROR_XMIT_COMPUTE 30 +#define WHAL_ERROR_XMIT_NOQUEUE 31 +#define WHAL_ERROR_XMIT_ACTIVEQUEUE 32 +#define WHAL_ERROR_XMIT_BADTYPE 33 +#define WHAL_ERROR_XMIT_STOPDMA 34 +#define WHAL_ERROR_INTERRUPT_BB_PANIC 35 +#define WHAL_ERROR_PAPRD_MAXGAIN_ABOVE_WINDOW 36 +#define WHAL_ERROR_QCU_HW_PAUSE_MISMATCH 37 +#define WHAL_ERROR_POWER_RFLP_CONFIG 38 +#define WHAL_ERROR_POWER_RFLP_SYNTHBYPASS_CONFIG 39 +#define WHAL_ERROR_POWER_RFLP_BIAS2X_CONFIG 40 +#define WHAL_ERROR_POWER_RFLP_PLLBYPASS_CONFIG 41 +#define WHAL_ERROR_POWER_RFLP_OFF1CHAN_CONFIG 42 +#define WHAL_ERROR_POWER_ANTENNA_LMIT 43 +#define WHAL_ERROR_POWER_REGDMN_TX_LMIT 44 +#define WHAL_ERROR_POWER_MODE_SCALED_PWR 45 +#define WHAL_ERROR_POWER_EDGE_PWR_TPSCALE 46 +#define WHAL_ERROR_POWER_CHAN_REGALLOW 47 +#define WHAL_ERROR_WAIT_REG_TIMEOUT 48 +#define WHAL_ERROR_XTAL_SET 49 +#define WHAL_DBGID_DEFINITION_END 50 + +#define COEX_DEBUGID_START 0 +#define BTCOEX_DBG_MCI_1 1 +#define BTCOEX_DBG_MCI_2 2 +#define BTCOEX_DBG_MCI_3 3 +#define BTCOEX_DBG_MCI_4 4 +#define BTCOEX_DBG_MCI_5 5 +#define BTCOEX_DBG_MCI_6 6 +#define BTCOEX_DBG_MCI_7 7 +#define BTCOEX_DBG_MCI_8 8 +#define BTCOEX_DBG_MCI_9 9 +#define BTCOEX_DBG_MCI_10 10 +#define COEX_WAL_BTCOEX_INIT 11 +#define COEX_WAL_PAUSE 12 +#define COEX_WAL_RESUME 13 +#define COEX_UPDATE_AFH 14 +#define COEX_HWQ_EMPTY_CB 15 +#define COEX_MCI_TIMER_HANDLER 16 +#define COEX_MCI_RECOVER 17 +#define ERROR_COEX_MCI_ISR 18 +#define ERROR_COEX_MCI_GPM 19 +#define COEX_ProfileType 20 +#define COEX_LinkID 21 +#define COEX_LinkState 22 +#define COEX_LinkRole 23 +#define COEX_LinkRate 24 +#define COEX_VoiceType 25 +#define COEX_TInterval 26 +#define COEX_WRetrx 27 +#define COEX_Attempts 28 +#define COEX_PerformanceState 29 +#define COEX_LinkType 30 +#define COEX_RX_MCI_GPM_VERSION_QUERY 31 +#define COEX_RX_MCI_GPM_VERSION_RESPONSE 32 +#define COEX_RX_MCI_GPM_STATUS_QUERY 33 +#define COEX_STATE_WLAN_VDEV_DOWN 34 +#define COEX_STATE_WLAN_VDEV_START 35 +#define COEX_STATE_WLAN_VDEV_CONNECTED 36 +#define COEX_STATE_WLAN_VDEV_SCAN_STARTED 37 +#define COEX_STATE_WLAN_VDEV_SCAN_END 38 +#define COEX_STATE_WLAN_DEFAULT 39 +#define COEX_CHANNEL_CHANGE 40 +#define COEX_POWER_CHANGE 41 +#define COEX_CONFIG_MGR 42 +#define COEX_TX_MCI_GPM_BT_CAL_REQ 43 +#define COEX_TX_MCI_GPM_BT_CAL_GRANT 44 +#define COEX_TX_MCI_GPM_BT_CAL_DONE 45 +#define COEX_TX_MCI_GPM_WLAN_CAL_REQ 46 +#define COEX_TX_MCI_GPM_WLAN_CAL_GRANT 47 +#define COEX_TX_MCI_GPM_WLAN_CAL_DONE 48 +#define COEX_TX_MCI_GPM_BT_DEBUG 49 +#define COEX_TX_MCI_GPM_VERSION_QUERY 50 +#define COEX_TX_MCI_GPM_VERSION_RESPONSE 51 +#define COEX_TX_MCI_GPM_STATUS_QUERY 52 +#define COEX_TX_MCI_GPM_HALT_BT_GPM 53 +#define COEX_TX_MCI_GPM_WLAN_CHANNELS 54 +#define COEX_TX_MCI_GPM_BT_PROFILE_INFO 55 +#define COEX_TX_MCI_GPM_BT_STATUS_UPDATE 56 +#define COEX_TX_MCI_GPM_BT_UPDATE_FLAGS 57 +#define COEX_TX_MCI_GPM_UNKNOWN 58 +#define COEX_TX_MCI_SYS_WAKING 59 +#define COEX_TX_MCI_LNA_TAKE 60 +#define COEX_TX_MCI_LNA_TRANS 61 +#define COEX_TX_MCI_SYS_SLEEPING 62 +#define COEX_TX_MCI_REQ_WAKE 63 +#define COEX_TX_MCI_REMOTE_RESET 64 +#define COEX_TX_MCI_TYPE_UNKNOWN 65 +#define COEX_WHAL_MCI_RESET 66 +#define COEX_POLL_BT_CAL_DONE_TIMEOUT 67 +#define COEX_WHAL_PAUSE 68 +#define COEX_RX_MCI_GPM_BT_CAL_REQ 69 +#define COEX_RX_MCI_GPM_BT_CAL_DONE 70 +#define COEX_RX_MCI_GPM_BT_CAL_GRANT 71 +#define COEX_WLAN_CAL_START 72 +#define COEX_WLAN_CAL_RESULT 73 +#define COEX_BtMciState 74 +#define COEX_BtCalState 75 +#define COEX_WlanCalState 76 +#define COEX_RxReqWakeCount 77 +#define COEX_RxRemoteResetCount 78 +#define COEX_RESTART_CAL 79 +#define COEX_SENDMSG_QUEUE 80 +#define COEX_RESETSEQ_LNAINFO_TIMEOUT 81 +#define COEX_MCI_ISR_IntRaw 82 +#define COEX_MCI_ISR_Int1Raw 83 +#define COEX_MCI_ISR_RxMsgRaw 84 +#define COEX_WHAL_COEX_RESET 85 +#define COEX_WAL_COEX_INIT 86 +#define COEX_TXRX_CNT_LIMIT_ISR 87 +#define COEX_CH_BUSY 88 +#define COEX_REASSESS_WLAN_STATE 89 +#define COEX_BTCOEX_WLAN_STATE_UPDATE 90 +#define COEX_BT_NUM_OF_PROFILES 91 +#define COEX_BT_NUM_OF_HID_PROFILES 92 +#define COEX_BT_NUM_OF_ACL_PROFILES 93 +#define COEX_BT_NUM_OF_HI_ACL_PROFILES 94 +#define COEX_BT_NUM_OF_VOICE_PROFILES 95 +#define COEX_WLAN_AGGR_LIMIT 96 +#define COEX_BT_LOW_PRIO_BUDGET 97 +#define COEX_BT_HI_PRIO_BUDGET 98 +#define COEX_BT_IDLE_TIME 99 +#define COEX_SET_COEX_WEIGHT 100 +#define COEX_WLAN_WEIGHT_GROUP 101 +#define COEX_BT_WEIGHT_GROUP 102 +#define COEX_BT_INTERVAL_ALLOC 103 +#define COEX_BT_SCHEME 104 +#define COEX_BT_MGR 105 +#define COEX_BT_SM_ERROR 106 +#define COEX_SYSTEM_UPDATE 107 +#define COEX_LOW_PRIO_LIMIT 108 +#define COEX_HI_PRIO_LIMIT 109 +#define COEX_BT_INTERVAL_START 110 +#define COEX_WLAN_INTERVAL_START 111 +#define COEX_NON_LINK_BUDGET 112 +#define COEX_CONTENTION_MSG 113 +#define COEX_SET_NSS 114 +#define COEX_SELF_GEN_MASK 115 +#define COEX_PROFILE_ERROR 116 +#define COEX_WLAN_INIT 117 +#define COEX_BEACON_MISS 118 +#define COEX_BEACON_OK 119 +#define COEX_BTCOEX_SCAN_ACTIVITY 120 +#define COEX_SCAN_ACTIVITY 121 +#define COEX_FORCE_QUIETTIME 122 +#define COEX_BT_MGR_QUIETTIME 123 +#define COEX_BT_INACTIVITY_TRIGGER 124 +#define COEX_BT_INACTIVITY_REPORTED 125 +#define COEX_TX_MCI_GPM_WLAN_PRIO 126 +#define COEX_TX_MCI_GPM_BT_PAUSE_PROFILE 127 +#define COEX_TX_MCI_GPM_WLAN_SET_ACL_INACTIVITY 128 +#define COEX_RX_MCI_GPM_BT_ACL_INACTIVITY_REPORT 129 +#define COEX_GENERIC_ERROR 130 +#define COEX_RX_RATE_THRESHOLD 131 +#define COEX_RSSI 132 + +#define COEX_WLAN_VDEV_NOTIF_START 133 +#define COEX_WLAN_VDEV_NOTIF_UP 134 +#define COEX_WLAN_VDEV_NOTIF_DOWN 135 +#define COEX_WLAN_VDEV_NOTIF_STOP 136 +#define COEX_WLAN_VDEV_NOTIF_ADD_PEER 137 +#define COEX_WLAN_VDEV_NOTIF_DELETE_PEER 138 +#define COEX_WLAN_VDEV_NOTIF_CONNECTED_PEER 139 +#define COEX_WLAN_VDEV_NOTIF_PAUSE 140 +#define COEX_WLAN_VDEV_NOTIF_UNPAUSED 141 +#define COEX_STATE_WLAN_VDEV_PEER_ADD 142 +#define COEX_STATE_WLAN_VDEV_CONNECTED_PEER 143 +#define COEX_STATE_WLAN_VDEV_DELETE_PEER 144 +#define COEX_STATE_WLAN_VDEV_PAUSE 145 +#define COEX_STATE_WLAN_VDEV_UNPAUSED 146 +#define COEX_SCAN_CALLBACK 147 +#define COEX_RC_SET_CHAINMASK 148 +#define COEX_TX_MCI_GPM_WLAN_SET_BT_RXSS_THRES 149 +#define COEX_TX_MCI_GPM_BT_RXSS_THRES_QUERY 150 +#define COEX_BT_RXSS_THRES 151 +#define COEX_BT_PROFILE_ADD_RMV 152 +#define COEX_BT_SCHED_INFO 153 +#define COEX_TRF_MGMT 154 +#define COEX_SCHED_START 155 +#define COEX_SCHED_RESULT 156 +#define COEX_SCHED_ERROR 157 +#define COEX_SCHED_PRE_OP 158 +#define COEX_SCHED_POST_OP 159 +#define COEX_RX_RATE 160 +#define COEX_ACK_PRIORITY 161 +#define COEX_STATE_WLAN_VDEV_UP 162 +#define COEX_STATE_WLAN_VDEV_PEER_UPDATE 163 +#define COEX_STATE_WLAN_VDEV_STOP 164 +#define COEX_WLAN_PAUSE_PEER 165 +#define COEX_WLAN_UNPAUSE_PEER 166 +#define COEX_WLAN_PAUSE_INTERVAL_START 167 +#define COEX_WLAN_POSTPAUSE_INTERVAL_START 168 +#define COEX_TRF_FREERUN 169 +#define COEX_TRF_SHAPE_PM 170 +#define COEX_TRF_SHAPE_PSP 171 +#define COEX_TRF_SHAPE_S_CTS 172 +#define COEX_CHAIN_CONFIG 173 +#define COEX_SYSTEM_MONITOR 174 +#define COEX_SINGLECHAIN_INIT 175 +#define COEX_MULTICHAIN_INIT 176 +#define COEX_SINGLECHAIN_DBG_1 177 +#define COEX_SINGLECHAIN_DBG_2 178 +#define COEX_SINGLECHAIN_DBG_3 179 +#define COEX_MULTICHAIN_DBG_1 180 +#define COEX_MULTICHAIN_DBG_2 181 +#define COEX_MULTICHAIN_DBG_3 182 +#define COEX_PSP_TX_CB 183 +#define COEX_PSP_RX_CB 184 +#define COEX_PSP_STAT_1 185 +#define COEX_PSP_SPEC_POLL 186 +#define COEX_PSP_READY_STATE 187 +#define COEX_PSP_TX_STATUS_STATE 188 +#define COEX_PSP_RX_STATUS_STATE_1 189 +#define COEX_PSP_NOT_READY_STATE 190 +#define COEX_PSP_DISABLED_STATE 191 +#define COEX_PSP_ENABLED_STATE 192 +#define COEX_PSP_SEND_PSPOLL 193 +#define COEX_PSP_MGR_ENTER 194 +#define COEX_PSP_MGR_RESULT 195 +#define COEX_PSP_NONWLAN_INTERVAL 196 +#define COEX_PSP_STAT_2 197 +#define COEX_PSP_RX_STATUS_STATE_2 198 +#define COEX_PSP_ERROR 199 +#define COEX_T2BT 200 +#define COEX_BT_DURATION 201 +#define COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG 202 +#define COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG_RSP 203 +#define COEX_TX_MCI_GPM_SCAN_OP 204 +#define COEX_TX_MCI_GPM_BT_PAUSE_GPM_TX 205 +#define COEX_CTS2S_SEND 206 +#define COEX_CTS2S_RESULT 207 +#define COEX_ENTER_OCS 208 +#define COEX_EXIT_OCS 209 +#define COEX_UPDATE_OCS 210 +#define COEX_STATUS_OCS 211 +#define COEX_STATS_BT 212 + +#define COEX_MWS_WLAN_INIT 213 +#define COEX_MWS_WBTMR_SYNC 214 +#define COEX_MWS_TYPE2_RX 215 +#define COEX_MWS_TYPE2_TX 216 +#define COEX_MWS_WLAN_CHAVD 217 +#define COEX_MWS_WLAN_CHAVD_INSERT 218 +#define COEX_MWS_WLAN_CHAVD_MERGE 219 +#define COEX_MWS_WLAN_CHAVD_RPT 220 +#define COEX_MWS_CP_MSG_SEND 221 +#define COEX_MWS_CP_ESCAPE 222 +#define COEX_MWS_CP_UNFRAME 223 +#define COEX_MWS_CP_SYNC_UPDATE 224 +#define COEX_MWS_CP_SYNC 225 +#define COEX_MWS_CP_WLAN_STATE_IND 226 +#define COEX_MWS_CP_SYNCRESP_TIMEOUT 227 +#define COEX_MWS_SCHEME_UPDATE 228 +#define COEX_MWS_WLAN_EVENT 229 +#define COEX_MWS_UART_UNESCAPE 230 +#define COEX_MWS_UART_ENCODE_SEND 231 +#define COEX_MWS_UART_RECV_DECODE 232 +#define COEX_MWS_UL_HDL 233 +#define COEX_MWS_REMOTE_EVENT 234 +#define COEX_MWS_OTHER 235 +#define COEX_MWS_ERROR 236 +#define COEX_MWS_ANT_DIVERSITY 237 + +#define COEX_P2P_GO 238 +#define COEX_P2P_CLIENT 239 +#define COEX_SCC_1 240 +#define COEX_SCC_2 241 +#define COEX_MCC_1 242 +#define COEX_MCC_2 243 +#define COEX_TRF_SHAPE_NOA 244 +#define COEX_NOA_ONESHOT 245 +#define COEX_NOA_PERIODIC 246 +#define COEX_LE_1 247 +#define COEX_LE_2 248 +#define COEX_ANT_1 249 +#define COEX_ANT_2 250 +#define COEX_ENTER_NOA 251 +#define COEX_EXIT_NOA 252 +#define COEX_BT_SCAN_PROTECT 253 + +#define COEX_DEBUG_ID_END 254 + +#define SCAN_START_COMMAND_FAILED 0 +#define SCAN_STOP_COMMAND_FAILED 1 +#define SCAN_EVENT_SEND_FAILED 2 +#define SCAN_ENGINE_START 3 +#define SCAN_ENGINE_CANCEL_COMMAND 4 +#define SCAN_ENGINE_STOP_DUE_TO_TIMEOUT 5 +#define SCAN_EVENT_SEND_TO_HOST 6 +#define SCAN_FWLOG_EVENT_ADD 7 +#define SCAN_FWLOG_EVENT_REM 8 +#define SCAN_FWLOG_EVENT_PREEMPTED 9 +#define SCAN_FWLOG_EVENT_RESTARTED 10 +#define SCAN_FWLOG_EVENT_COMPLETED 11 +#define SCAN_SM_REQ_NEXT_CH 12 +#define SCAN_DBGID_DEFINITION_END 13 + +#define BEACON_EVENT_SWBA_SEND_FAILED 0 +#define BEACON_EVENT_EARLY_RX_BMISS_STATUS 1 +#define BEACON_EVENT_EARLY_RX_SLEEP_SLOP 2 +#define BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT 3 +#define BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM 4 +#define BEACON_EVENT_EARLY_RX_CLK_DRIFT 5 +#define BEACON_EVENT_EARLY_RX_AP_DRIFT 6 +#define BEACON_EVENT_EARLY_RX_BCN_TYPE 7 + +#define RATECTRL_DBGID_DEFINITION_START 0 +#define RATECTRL_DBGID_ASSOC 1 +#define RATECTRL_DBGID_NSS_CHANGE 2 +#define RATECTRL_DBGID_CHAINMASK_ERR 3 +#define RATECTRL_DBGID_UNEXPECTED_FRAME 4 +#define RATECTRL_DBGID_WAL_RCQUERY 5 +#define RATECTRL_DBGID_WAL_RCUPDATE 6 +#define RATECTRL_DBGID_GTX_UPDATE 7 +#define RATECTRL_DBGID_DEFINITION_END 8 + +#define AP_PS_DBGID_DEFINITION_START 0 +#define AP_PS_DBGID_UPDATE_TIM 1 +#define AP_PS_DBGID_PEER_STATE_CHANGE 2 +#define AP_PS_DBGID_PSPOLL 3 +#define AP_PS_DBGID_PEER_CREATE 4 +#define AP_PS_DBGID_PEER_DELETE 5 +#define AP_PS_DBGID_VDEV_CREATE 6 +#define AP_PS_DBGID_VDEV_DELETE 7 +#define AP_PS_DBGID_SYNC_TIM 8 +#define AP_PS_DBGID_NEXT_RESPONSE 9 +#define AP_PS_DBGID_START_SP 10 +#define AP_PS_DBGID_COMPLETED_EOSP 11 +#define AP_PS_DBGID_TRIGGER 12 +#define AP_PS_DBGID_DUPLICATE_TRIGGER 13 +#define AP_PS_DBGID_UAPSD_RESPONSE 14 +#define AP_PS_DBGID_SEND_COMPLETE 15 +#define AP_PS_DBGID_SEND_N_COMPLETE 16 +#define AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA 17 +#define AP_PS_DBGID_DELIVER_CAB 18 +#define AP_PS_DBGID_NO_CLIENT 27 +#define AP_PS_DBGID_CLIENT_IN_PS_ACTIVE 28 +#define AP_PS_DBGID_CLIENT_IN_PS_NON_ACTIVE 29 +#define AP_PS_DBGID_CLIENT_IN_AWAKE 30 + +/* WLAN_MODULE_MGMT_TXRX Debugids*/ +#define MGMT_TXRX_DBGID_DEFINITION_START 0 +#define MGMT_TXRX_FORWARD_TO_HOST 1 +#define MGMT_TXRX_MGMT_FRAME_BUFFER_FULL 2 +#define MGMT_TXRX_VDEV_USED_TO_SEND_FRAME_IS_FREE 3 +#define MGMT_TXRX_LOCAL_FRAME_SEND_FAILED 4 +#define MGMT_TXRX_DBGID_DEFINITION_END 5 + +#define WAL_DBGID_DEFINITION_START 0 +#define WAL_DBGID_FAST_WAKE_REQUEST 1 +#define WAL_DBGID_FAST_WAKE_RELEASE 2 +#define WAL_DBGID_SET_POWER_STATE 3 +#define WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET 5 +#define WAL_DBGID_CHANNEL_CHANGE 6 +#define WAL_DBGID_VDEV_START 7 +#define WAL_DBGID_VDEV_STOP 8 +#define WAL_DBGID_VDEV_UP 9 +#define WAL_DBGID_VDEV_DOWN 10 +#define WAL_DBGID_SW_WDOG_RESET 11 +#define WAL_DBGID_TX_SCH_REGISTER_TIDQ 12 +#define WAL_DBGID_TX_SCH_UNREGISTER_TIDQ 13 +#define WAL_DBGID_TX_SCH_TICKLE_TIDQ 14 + +#define WAL_DBGID_XCESS_FAILURES 15 +#define WAL_DBGID_AST_ADD_WDS_ENTRY 16 +#define WAL_DBGID_AST_DEL_WDS_ENTRY 17 +#define WAL_DBGID_AST_WDS_ENTRY_PEER_CHG 18 +#define WAL_DBGID_AST_WDS_SRC_LEARN_FAIL 19 +#define WAL_DBGID_STA_KICKOUT 20 +#define WAL_DBGID_BAR_TX_FAIL 21 +#define WAL_DBGID_BAR_ALLOC_FAIL 22 +#define WAL_DBGID_LOCAL_DATA_TX_FAIL 23 +#define WAL_DBGID_SECURITY_PM4_QUEUED 24 +#define WAL_DBGID_SECURITY_GM1_QUEUED 25 +#define WAL_DBGID_SECURITY_PM4_SENT 26 +#define WAL_DBGID_SECURITY_ALLOW_DATA 27 +#define WAL_DBGID_SECURITY_UCAST_KEY_SET 28 +#define WAL_DBGID_SECURITY_MCAST_KEY_SET 29 +#define WAL_DBGID_SECURITY_ENCR_EN 30 +#define WAL_DBGID_BB_WDOG_TRIGGERED 31 +#define WAL_DBGID_RX_LOCAL_BUFS_LWM 32 +#define WAL_DBGID_RX_LOCAL_DROP_LARGE_MGMT 33 +#define WAL_DBGID_VHT_ILLEGAL_RATE_PHY_ERR_DETECTED 34 +#define WAL_DBGID_DEV_RESET 35 +#define WAL_DBGID_TX_BA_SETUP 36 +#define WAL_DBGID_RX_BA_SETUP 37 +#define WAL_DBGID_DEV_TX_TIMEOUT 38 +#define WAL_DBGID_DEV_RX_TIMEOUT 39 +#define WAL_DBGID_STA_VDEV_XRETRY 40 +#define WAL_DBGID_DCS 41 +#define WAL_DBGID_MGMT_TX_FAIL 42 +#define WAL_DBGID_SET_M4_SENT_MANUALLY 43 +#define WAL_DBGID_PROCESS_4_WAY_HANDSHAKE 44 +#define WAL_DBGID_WAL_CHANNEL_CHANGE_START 45 +#define WAL_DBGID_WAL_CHANNEL_CHANGE_COMPLETE 46 +#define WAL_DBGID_WHAL_CHANNEL_CHANGE_START 47 +#define WAL_DBGID_WHAL_CHANNEL_CHANGE_COMPLETE 48 +#define WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN 49 +#define WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN 50 +#define WAL_DBGID_TX_DISCARD 51 +#define WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS 52 +#define WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS 53 +#define WAL_DBGID_RESET_PCU_CYCLE_CNT 54 +#define WAL_DBGID_SETUP_RSSI_INTERRUPTS 55 +#define WAL_DBGID_BRSSI_CONFIG 56 +#define WAL_DBGID_CURRENT_BRSSI_AVE 57 +#define WAL_DBGID_BCN_TX_COMP 58 +#define WAL_DBGID_RX_REENTRY 59 +#define WAL_DBGID_SET_HW_CHAINMASK 60 +#define WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL 61 +#define WAL_DBGID_GET_HW_CHAINMASK 62 +#define WAL_DBGID_SMPS_DISABLE 63 +#define WAL_DBGID_SMPS_ENABLE_HW_CNTRL 64 +#define WAL_DBGID_SMPS_SWSEL_CHAINMASK 65 +#define WAL_DBGID_SUSPEND 66 +#define WAL_DBGID_RESUME 67 +#define WAL_DBGID_PEER_TX_FAIL_CNT_THRES_EXCEEDED 68 +#define WAL_DBGID_RX_FULL_REORDER_SUPPORT 69 +#define WAL_DBGID_HCM_BIN 70 +#define WAL_DBGID_HCM_BIN_PENALIZE 71 +#define WAL_DBGID_HCM_BIN_DEPENALIZE 72 +#define WAL_DBGID_AST_UPDATE_WDS_ENTRY 73 +#define WAL_DBGID_PEER_EXT_STATS 74 +#define WAL_DBGID_TX_AC_BUFFER_SET 75 +#define WAL_DBGID_AST_ENTRY_EXIST 76 +#define WAL_DBGID_AST_ENTRY_FULL 77 +#define WAL_DBGID_WMMAC_TXQ_STATUS 78 +#define WAL_DBGID_PROLONGED_TX_PPDU_TOTAL_US 79 +#define WAL_DBGID_UPDATE_USED_TIME 80 +#define WAL_DBGID_PAST_WB_ACK_TIMESTAMP 81 +#define WAL_DBGID_WMMAC_ADD_DEL_TSPEC 82 +#define WAL_DBGID_WMMAC_TIMER_EXPIRY 83 +#define WAL_DBGID_WMMAC_PARAMS 84 +#define WAL_DBGID_TX_MGMT_WAL_PEER_DOES_NOT_EXIST 85 +#define WAL_DBGID_TX_MGMT_WAL_PEER_DELETE_IN_PROGRESS 86 +#define WAL_DBGID_TX_MGMT_FRAME_DESC_ALLOC_FAILED 87 +#define WAL_DBGID_TX_MGMT_TID_STRUCT_NOT_FOUND 88 +#define WAL_DBGID_TX_MGMT_ENQUEUE_FAILED 89 +#define WAL_DBGID_DEFINITION_END 90 + +#define ANI_DBGID_POLL 0 +#define ANI_DBGID_CONTROL 1 +#define ANI_DBGID_OFDM_PARAMS 2 +#define ANI_DBGID_CCK_PARAMS 3 +#define ANI_DBGID_RESET 4 +#define ANI_DBGID_RESTART 5 +#define ANI_DBGID_OFDM_LEVEL 6 +#define ANI_DBGID_CCK_LEVEL 7 +#define ANI_DBGID_FIRSTEP 8 +#define ANI_DBGID_CYCPWR 9 +#define ANI_DBGID_MRC_CCK 10 +#define ANI_DBGID_SELF_CORR_LOW 11 +#define ANI_DBGID_ENABLE 12 + +#define ANI_DBGID_CURRENT_LEVEL 13 +#define ANI_DBGID_POLL_PERIOD 14 +#define ANI_DBGID_LISTEN_PERIOD 15 +#define ANI_DBGID_OFDM_LEVEL_CFG 16 +#define ANI_DBGID_CCK_LEVEL_CFG 17 + +/* OFFLOAD Manager Debugids*/ +#define OFFLOAD_MGR_DBGID_DEFINITION_START 0 +#define OFFLOADMGR_REGISTER_OFFLOAD 1 +#define OFFLOADMGR_DEREGISTER_OFFLOAD 2 +#define OFFLOADMGR_NO_REG_DATA_HANDLERS 3 +#define OFFLOADMGR_NO_REG_EVENT_HANDLERS 4 +#define OFFLOADMGR_REG_OFFLOAD_FAILED 5 +#define OFFLOADMGR_DEREG_OFFLOAD_FAILED 6 +#define OFFLOADMGR_ENTER_FAILED 7 +#define OFFLOADMGR_EXIT_FAILED 8 +#define OFFLOADMGR_DBGID_DEFINITION_END 9 + +/*Resource Debug IDs*/ +#define RESOURCE_DBGID_DEFINITION_START 0 +#define RESOURCE_PEER_ALLOC 1 +#define RESOURCE_PEER_FREE 2 +#define RESOURCE_PEER_ALLOC_WAL_PEER 3 +#define RESOURCE_PEER_NBRHOOD_MGMT_ALLOC 4 +#define RESOURCE_PEER_NBRHOOD_MGMT_INFO 5 +#define RESOURCE_SMALL_MGMT_BUF_FULL 6 +#define RESOURCE_MGMT_AVAIL_BUF_CNT_NOT_ENOUGH 7 +#define RESOURCE_MGMT_BUF_FULL 8 +#define RESOURCE_MGMT_BUF_INC 9 +#define RESOURCE_MGMT_BUF_DEC 10 +#define RESOURCE_DBGID_DEFINITION_END 11 + +/* DCS debug IDs*/ +#define WLAN_DCS_DBGID_INIT 0 +#define WLAN_DCS_DBGID_WMI_CWINT 1 +#define WLAN_DCS_DBGID_TIMER 2 +#define WLAN_DCS_DBGID_CMDG 3 +#define WLAN_DCS_DBGID_CMDS 4 +#define WLAN_DCS_DBGID_DINIT 5 + +/*P2P Module ids*/ +#define P2P_DBGID_DEFINITION_START 0 +#define P2P_DEV_REGISTER 1 +#define P2P_HANDLE_NOA 2 +#define P2P_UPDATE_SCHEDULE_OPPS 3 +#define P2P_UPDATE_SCHEDULE 4 +#define P2P_UPDATE_START_TIME 5 +#define P2P_UPDATE_START_TIME_DIFF_TSF32 6 +#define P2P_UPDATE_START_TIME_FINAL 7 +#define P2P_SETUP_SCHEDULE_TIMER 8 +#define P2P_PROCESS_SCHEDULE_AFTER_CALC 9 +#define P2P_PROCESS_SCHEDULE_STARTED_TIMER 10 +#define P2P_CALC_SCHEDULES_FIRST_CALL_ALL_NEXT_EVENT 11 +#define P2P_CALC_SCHEDULES_FIRST_VALUE 12 +#define P2P_CALC_SCHEDULES_EARLIEST_NEXT_EVENT 13 +#define P2P_CALC_SCHEDULES_SANITY_COUNT 14 +#define P2P_CALC_SCHEDULES_CALL_ALL_NEXT_EVENT_FROM_WHILE_LOOP 15 +#define P2P_CALC_SCHEDULES_TIMEOUT_1 16 +#define P2P_CALC_SCHEDULES_TIMEOUT_2 17 +#define P2P_FIND_ALL_NEXT_EVENTS_REQ_EXPIRED 18 +#define P2P_FIND_ALL_NEXT_EVENTS_REQ_ACTIVE 19 +#define P2P_FIND_NEXT_EVENT_REQ_NOT_STARTED 20 +#define P2P_FIND_NEXT_EVENT_REQ_COMPLETE_NON_PERIODIC 21 +#define P2P_FIND_NEXT_EVENT_IN_MID_OF_NOA 22 +#define P2P_FIND_NEXT_EVENT_REQ_COMPLETE 23 +#define P2P_SCHEDULE_TIMEOUT 24 +#define P2P_CALC_SCHEDULES_ENTER 25 +#define P2P_PROCESS_SCHEDULE_ENTER 26 +#define P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_AFTER_CHANGE 27 +#define P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_BEFORE_CHANGE 28 +#define P2P_FIND_ALL_NEXT_EVENTS_ENTER 29 +#define P2P_FIND_NEXT_EVENT_ENTER 30 +#define P2P_NOA_GO_PRESENT 31 +#define P2P_NOA_GO_ABSENT 32 +#define P2P_GO_NOA_NOTIF 33 +#define P2P_GO_TBTT_OFFSET 34 +#define P2P_GO_GET_NOA_INFO 35 +#define P2P_GO_ADD_ONE_SHOT_NOA 36 +#define P2P_GO_GET_NOA_IE 37 +#define P2P_GO_BCN_TX_COMP 38 +#define P2P_DBGID_DEFINITION_END 39 + +/* CSA modules DBGIDs */ +#define CSA_DBGID_DEFINITION_START 0 +#define CSA_OFFLOAD_POOL_INIT 1 +#define CSA_OFFLOAD_REGISTER_VDEV 2 +#define CSA_OFFLOAD_DEREGISTER_VDEV 3 +#define CSA_DEREGISTER_VDEV_ERROR 4 +#define CSA_OFFLOAD_BEACON_RECEIVED 5 +#define CSA_OFFLOAD_BEACON_CSA_RECV 6 +#define CSA_OFFLOAD_CSA_RECV_ERROR_IE 7 +#define CSA_OFFLOAD_CSA_TIMER_ERROR 8 +#define CSA_OFFLOAD_CSA_TIMER_EXP 9 +#define CSA_OFFLOAD_WMI_EVENT_ERROR 10 +#define CSA_OFFLOAD_WMI_EVENT_SENT 11 +#define CSA_OFFLOAD_WMI_CHANSWITCH_RECV 12 +#define CSA_DBGID_DEFINITION_END 13 + +/* Chatter module DBGIDs */ +#define WLAN_CHATTER_DBGID_DEFINITION_START 0 +#define WLAN_CHATTER_ENTER 1 +#define WLAN_CHATTER_EXIT 2 +#define WLAN_CHATTER_FILTER_HIT 3 +#define WLAN_CHATTER_FILTER_MISS 4 +#define WLAN_CHATTER_FILTER_FULL 5 +#define WLAN_CHATTER_FILTER_TM_ADJ 6 +#define WLAN_CHATTER_BUFFER_FULL 7 +#define WLAN_CHATTER_TIMEOUT 8 +#define WLAN_CHATTER_MC_FILTER_ADD 9 +#define WLAN_CHATTER_MC_FILTER_DEL 10 +#define WLAN_CHATTER_MC_FILTER_ALLOW 11 +#define WLAN_CHATTER_MC_FILTER_DROP 12 +#define WLAN_CHATTER_COALESCING_FILTER_ADD 13 +#define WLAN_CHATTER_COALESCING_FILTER_DEL 14 +#define WLAN_CHATTER_DBGID_DEFINITION_END 15 + +#define WOW_DBGID_DEFINITION_START 0 +#define WOW_ENABLE_CMDID 1 +#define WOW_RECV_DATA_PKT 2 +#define WOW_WAKE_HOST_DATA 3 +#define WOW_RECV_MGMT 4 +#define WOW_WAKE_HOST_MGMT 5 +#define WOW_RECV_EVENT 6 +#define WOW_WAKE_HOST_EVENT 7 +#define WOW_INIT 8 +#define WOW_RECV_MAGIC_PKT 9 +#define WOW_RECV_BITMAP_PATTERN 10 +#define WOW_AP_VDEV_DISALLOW 11 +#define WOW_STA_VDEV_DISALLOW 12 +#define WOW_P2PGO_VDEV_DISALLOW 13 +#define WOW_NS_OFLD_ENABLE 14 +#define WOW_ARP_OFLD_ENABLE 15 +#define WOW_NS_ARP_OFLD_DISABLE 16 +#define WOW_NS_RECEIVED 17 +#define WOW_NS_REPLIED 18 +#define WOW_ARP_RECEIVED 19 +#define WOW_ARP_REPLIED 20 +#define WOW_BEACON_OFFLOAD_TX 21 +#define WOW_BEACON_OFFLOAD_CFG 22 +#define WOW_IBSS_VDEV_ALLOW 23 +#define WOW_DBGID_DEFINITION_END 24 + +/* SWBMISS module DBGIDs */ +#define SWBMISS_DBGID_DEFINITION_START 0 +#define SWBMISS_ENABLED 1 +#define SWBMISS_DISABLED 2 +#define SWBMISS_UPDATE_BEACON_RSSI 3 +#define SWBMISS_DBGID_DEFINITION_END 4 + +/* WLAN module DBGIDS */ +#define ROAM_DBGID_DEFINITION_START 0 +#define ROAM_MODULE_INIT 1 +#define ROAM_DEV_START 2 +#define ROAM_CONFIG_RSSI_THRESH 3 +#define ROAM_CONFIG_SCAN_PERIOD 4 +#define ROAM_CONFIG_AP_PROFILE 5 +#define ROAM_CONFIG_CHAN_LIST 6 +#define ROAM_CONFIG_SCAN_PARAMS 7 +#define ROAM_CONFIG_RSSI_CHANGE 8 +#define ROAM_SCAN_TIMER_START 9 +#define ROAM_SCAN_TIMER_EXPIRE 10 +#define ROAM_SCAN_TIMER_STOP 11 +#define ROAM_SCAN_STARTED 12 +#define ROAM_SCAN_COMPLETE 13 +#define ROAM_SCAN_CANCELLED 14 +#define ROAM_CANDIDATE_FOUND 15 +#define ROAM_RSSI_ACTIVE_SCAN 16 +#define ROAM_RSSI_ACTIVE_ROAM 17 +#define ROAM_RSSI_GOOD 18 +#define ROAM_BMISS_FIRST_RECV 19 +#define ROAM_DEV_STOP 20 +#define ROAM_FW_OFFLOAD_ENABLE 21 +#define ROAM_CANDIDATE_SSID_MATCH 22 +#define ROAM_CANDIDATE_SECURITY_MATCH 23 +#define ROAM_LOW_RSSI_INTERRUPT 24 +#define ROAM_HIGH_RSSI_INTERRUPT 25 +#define ROAM_SCAN_REQUESTED 26 +#define ROAM_BETTER_CANDIDATE_FOUND 27 +#define ROAM_BETTER_AP_EVENT 28 +#define ROAM_CANCEL_LOW_PRIO_SCAN 29 +#define ROAM_FINAL_BMISS_RECVD 30 +#define ROAM_CONFIG_SCAN_MODE 31 +#define ROAM_BMISS_FINAL_SCAN_ENABLE 32 +#define ROAM_SUITABLE_AP_EVENT 33 +#define ROAM_RSN_IE_PARSE_ERROR 34 +#define ROAM_WPA_IE_PARSE_ERROR 35 +#define ROAM_SCAN_CMD_FROM_HOST 36 +#define ROAM_HO_SORT_CANDIDATE 37 +#define ROAM_HO_SAVE_CANDIDATE 38 +#define ROAM_HO_GET_CANDIDATE 39 +#define ROAM_HO_OFFLOAD_SET_PARAM 40 +#define ROAM_HO_SM 41 +#define ROAM_HO_HTT_SAVED 42 +#define ROAM_HO_SYNC_START 43 +#define ROAM_HO_START 44 +#define ROAM_HO_SYNC_COMPLETE 45 +#define ROAM_HO_STOP 46 +#define ROAM_HO_HTT_FORWARD 47 +#define ROAM_CONFIG_SCAN_PARAMS_1 48 +#define ROAM_SCAN_COMPLETE_1 49 +#define ROAM_SWBMISS_BCN_RECV_VAL 50 +#define ROAM_SWBMISS_BCN_RECV_THRE2 51 +#define ROAM_SCAN_REQUESTED_1 52 +#define ROAM_HO_SORT_CANDIDATE_CUR 53 +#define ROAM_HO_SAVE_CANDIDATE_DUP 54 +#define ROAM_HO_SM_EVENT 55 +#define ROAM_HO_ENTER_CH 56 +#define ROAM_HO_MGMT_RX 57 +#define ROAM_HO_CANDIDATE_INFO 58 +#define ROAM_HO_OFFLD_DATA_STORE 59 +#define ROAM_HO_HTT_DATA_STORE 60 +#define ROAM_HO_UPDATE_STATUS 61 +#define ROAM_HO_OCS_CH_CB 62 +#define ROAM_RSSI_INTERRUPT_STATE 63 +#define ROAM_INVOKE_PARAM_CHECK 64 +#define ROAM_INVOKE_PARAM_CHAN 65 +#define ROAM_INVOKE_PARAM_BSSID 66 +#define ROAM_INVOKE_STATE_CHECK 67 +#define ROAM_INVOKE_START_SUCCESS 68 +#define ROAM_INVOKE_START_FAILURE 69 +#define ROAM_INVOKE_BSSID_CHECK 70 +#define ROAM_CANDIDATE_INFO 71 +#define ROAM_CANDIDATE_FILTER_MATCH 72 +#define ROAM_CANDIDATE_RSSI_ADJUST 73 +#define ROAM_CONFIG_ROAM_FILTER 74 +#define ROAM_EXTENDED_RSSI_TRESHOLD_1 75 +#define ROAM_EXTENDED_RSSI_TRESHOLD_2 76 +#define ROAM_BLACKLIST_BSSID 77 +#define ROAM_WHITELIST_SSID 78 +#define ROAM_WHITELIST_SSID_2 79 +#define ROAM_PREFERRED_BSSID 80 +#define ROAM_PREFERRED_FACTOR 81 +#define ROAM_SCAN_HIRSSI_THRESHOLD 82 +#define ROAM_SCAN_HIRSSI_CHECK 83 +#define ROAM_SCAN_HIRSSI_TIMER_EXPIRED 84 +#define ROAM_SCAN_EXTSCAN_CHECK 85 +#define ROAM_DBGID_DEFINITION_END 86 + +/* DATA_TXRX module DBGIDs*/ +#define DATA_TXRX_DBGID_DEFINITION_START 0 +#define DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO 1 +#define DATA_TXRX_DBGID_REPLAY_CHECK 2 +#define DATA_TXRX_DBGID_DUP_CHECK 3 +#define DATA_TXRX_INVALID_PEER_AST_STA 4 +#define DATA_TXRX_INVALID_PEER_AST_P2P 5 +#define DATA_TXRX_INVALID_ADDR1_STA 6 +#define DATA_TXRX_INVALID_ADDR1_P2P 7 +#define DATA_TXRX_MULTICAST_BROADCAST_FRAME 8 +#define DATA_TXRX_INVALID_FRAME_CTRL_OR_ADDR 9 +#define DATA_TXRX_DBGID_DEFINITION_END 10 + +/* HTT module DBGIDs */ +#define HTT_DBGID_DEFINITION_START 0 +#define HTT_DBGID_INVALID_VDEVID_OR_GROUP 1 +#define HTT_DBGID_DISCARD_INTERNAL_PKTS 2 +#define HTT_DBGID_DISCARD_TX_PKTS 3 +#define HTT_DBGID_GROUP_CHANGE 4 +#define HTT_DBGID_GROUP_CREDIT_STATS 5 +#define HTT_DBGID_DISCARD_INTERNAL_PKTS_NUM 6 +#define HTT_DBGID_DEFINITION_END 7 + +/* TDLS module DBGIDs*/ +#define TDLS_DBGID_DEFINITION_START 0 +#define TDLS_DBGID_VDEV_CREATE 1 +#define TDLS_DBGID_VDEV_DELETE 2 +#define TDLS_DBGID_ENABLED_PASSIVE 3 +#define TDLS_DBGID_ENABLED_ACTIVE 4 +#define TDLS_DBGID_DISABLED 5 +#define TDLS_DBGID_CONNTRACK_TIMER 6 +#define TDLS_DBGID_WAL_SET 7 +#define TDLS_DBGID_WAL_GET 8 +#define TDLS_DBGID_WAL_PEER_UPDATE_SET 9 +#define TDLS_DBGID_WAL_PEER_UPDATE_EVT 10 +#define TDLS_DBGID_WAL_VDEV_CREATE 11 +#define TDLS_DBGID_WAL_VDEV_DELETE 12 +#define TDLS_DBGID_WLAN_EVENT 13 +#define TDLS_DBGID_WLAN_PEER_UPDATE_SET 14 +#define TDLS_DBGID_PEER_EVT_DRP_THRESH 15 +#define TDLS_DBGID_PEER_EVT_DRP_RATE 16 +#define TDLS_DBGID_PEER_EVT_DRP_RSSI 17 +#define TDLS_DBGID_PEER_EVT_DISCOVER 18 +#define TDLS_DBGID_PEER_EVT_DELETE 19 +#define TDLS_DBGID_PEER_CAP_UPDATE 20 +#define TDLS_DBGID_UAPSD_SEND_PTI_FRAME 21 +#define TDLS_DBGID_UAPSD_SEND_PTI_FRAME2PEER 22 +#define TDLS_DBGID_UAPSD_START_PTR_TIMER 23 +#define TDLS_DBGID_UAPSD_CANCEL_PTR_TIMER 24 +#define TDLS_DBGID_UAPSD_PTR_TIMER_TIMEOUT 25 +#define TDLS_DBGID_UAPSD_STA_PS_EVENT_HANDLER 26 +#define TDLS_DBGID_UAPSD_PEER_EVENT_HANDLER 27 +#define TDLS_DBGID_UAPSD_PS_DEFAULT_SETTINGS 28 +#define TDLS_DBGID_UAPSD_GENERIC 29 + +/* TXBF Module IDs */ +#define TXBFEE_DBGID_START 0 +#define TXBFEE_DBGID_NDPA_RECEIVED 1 +#define TXBFEE_DBGID_HOST_CONFIG_TXBFEE_TYPE 2 +#define TXBFER_DBGID_SEND_NDPA 3 +#define TXBFER_DBGID_GET_NDPA_BUF_FAIL 4 +#define TXBFER_DBGID_SEND_NDPA_FAIL 5 +#define TXBFER_DBGID_GET_NDP_BUF_FAIL 6 +#define TXBFER_DBGID_SEND_NDP_FAIL 7 +#define TXBFER_DBGID_GET_BRPOLL_BUF_FAIL 8 +#define TXBFER_DBGID_SEND_BRPOLL_FAIL 9 +#define TXBFER_DBGID_HOST_CONFIG_CMDID 10 +#define TXBFEE_DBGID_HOST_CONFIG_CMDID 11 +#define TXBFEE_DBGID_ENABLE_UPLOAD_H 12 +#define TXBFEE_DBGID_UPLOADH_CV_TAG 13 +#define TXBFEE_DBGID_UPLOADH_H_TAG 14 +#define TXBFEE_DBGID_CAPTUREH_RECEIVED 15 +#define TXBFEE_DBGID_PACKET_IS_STEERED 16 +#define TXBFEE_UPLOADH_EVENT_ALLOC_MEM_FAIL 17 +#define TXBFEE_DBGID_SW_WAR_AID_ZERO 18 +#define TXBFEE_DBGID_BRPOLL_RECEIVED 19 +#define TXBFEE_DBGID_GID_RECEIVED 20 +#define TXBFEE_DBGID_END 21 + +/* SMPS module DBGIDs */ +#define STA_SMPS_DBGID_DEFINITION_START 0 +#define STA_SMPS_DBGID_CREATE_PDEV_INSTANCE 1 +#define STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE 2 +#define STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE 3 +#define STA_SMPS_DBGID_CREATE_STA_INSTANCE 4 +#define STA_SMPS_DBGID_DELETE_STA_INSTANCE 5 +#define STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START 6 +#define STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP 7 +#define STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME 8 +#define STA_SMPS_DBGID_HOST_FORCED_MODE 9 +#define STA_SMPS_DBGID_FW_FORCED_MODE 10 +#define STA_SMPS_DBGID_RSSI_THRESHOLD_CROSSED 11 +#define STA_SMPS_DBGID_SMPS_ACTION_FRAME_COMPLETION 12 +#define STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE 13 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE 14 +#define STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE 15 +#define STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE 16 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP 17 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE 18 + +#define STA_SMPS_DBGID_DEFINITION_END 18 + +/* RTT module DBGIDs*/ +#define RTT_CALL_FLOW 0 +#define RTT_REQ_SUB_TYPE 1 +#define RTT_MEAS_REQ_HEAD 2 +#define RTT_MEAS_REQ_BODY 3 +#define RTT_INIT_GLOBAL_STATE 6 +#define RTT_REPORT 8 +#define RTT_ERROR_REPORT 10 +#define RTT_TIMER_STOP 11 +#define RTT_SEND_TM_FRAME 12 +#define RTT_V3_RESP_CNT 13 +#define RTT_V3_RESP_FINISH 14 +#define RTT_CHANNEL_SWITCH_REQ 15 +#define RTT_CHANNEL_SWITCH_GRANT 16 +#define RTT_CHANNEL_SWITCH_COMPLETE 17 +#define RTT_CHANNEL_SWITCH_PREEMPT 18 +#define RTT_CHANNEL_SWITCH_STOP 19 +#define RTT_TIMER_START 20 + +#define RTT_FTM_PARAM_INFO 21 +#define RTT_RX_TM_FRAME 22 +#define RTT_INITR_TSTAMP 23 +#define RTT_RSPDR_TSTAMP 24 +#define RTT_TX_COMP_STATUS 25 +#define RTT_ERROR_WMI_EVENT 26 +#define RTT_MEASUREMENT_VALUES 27 + +/* WLAN HB module DBGIDs */ +#define WLAN_HB_DBGID_DEFINITION_START 0 +#define WLAN_HB_DBGID_INIT 1 +#define WLAN_HB_DBGID_TCP_GET_TXBUF_FAIL 2 +#define WLAN_HB_DBGID_TCP_SEND_FAIL 3 +#define WLAN_HB_DBGID_BSS_PEER_NULL 4 +#define WLAN_HB_DBGID_UDP_GET_TXBUF_FAIL 5 +#define WLAN_HB_DBGID_UDP_SEND_FAIL 6 +#define WLAN_HB_DBGID_WMI_CMD_INVALID_PARAM 7 +#define WLAN_HB_DBGID_WMI_CMD_INVALID_OP 8 +#define WLAN_HB_DBGID_WOW_NOT_ENTERED 9 +#define WLAN_HB_DBGID_ALLOC_SESS_FAIL 10 +#define WLAN_HB_DBGID_CTX_NULL 11 +#define WLAN_HB_DBGID_CHKSUM_ERR 12 +#define WLAN_HB_DBGID_UDP_TX 13 +#define WLAN_HB_DBGID_TCP_TX 14 +#define WLAN_HB_DBGID_DEFINITION_END 15 + +/* Thermal Manager DBGIDs*/ +#define THERMAL_MGR_DBGID_DEFINITION_START 0 +#define THERMAL_MGR_NEW_THRESH 1 +#define THERMAL_MGR_THRESH_CROSSED 2 +#define THERMAL_MGR_DBGID_DEFINITION_END 3 + +/* WLAN PHYERR DFS(parse/filter) DBGIDs */ +#define WLAN_PHYERR_DFS_DBGID_DEFINITION_START 0 +#define WLAN_PHYERR_DFS_PHYERR_INFO_CHAN_BUFLEN 1 +#define WLAN_PHYERR_DFS_PHYERR_INFO_PPDU 2 +#define WLAN_PHYERR_DFS_DBDID_RADAR_SUMMARY 3 +#define WLAN_PHYERR_DFS_DBDID_SEARCH_FFT 4 +#define WLAN_PHTERR_DFS_DBDID_FILTER_STATUS 5 +#define WLAN_PHYERR_DFS_DBGID_DEFINITION_END 6 + +/* RMC DBGIDs */ +#define RMC_DBGID_DEFINITION_START 0 +#define RMC_SM_INIT_ERR 1 +#define RMC_VDEV_ALLOC_ERR 2 +#define RMC_CREATE_INSTANCE 3 +#define RMC_DELETE_INSTANCE 4 +#define RMC_NEW_PRI_LEADER 5 +#define RMC_NEW_SEC_LEADER 6 +#define RMC_NO_LDR_CHANGE 7 +#define RMC_LDR_INFORM_SENT 8 +#define RMC_PEER_ADD 9 +#define RMC_PEER_DELETE 10 +#define RMC_PEER_UNKNOWN 11 +#define RMC_PRI_LDR_RSSI_UPDATE 12 +#define RMC_SEC_LDR_RSSI_UPDATE 13 +#define RMC_SET_MODE 14 +#define RMC_SET_ACTION_PERIOD 15 +#define RMC_DBGID_DEFINITION_END 16 + +/* UNIT_TEST module DBGIDs */ +#define UNIT_TEST_GEN 0 + +/* MLME module DBGIDs */ +#define MLME_DEBUG_CMN 0 +#define MLME_DEBUG_IF 1 +#define MLME_DEBUG_AUTH 2 +#define MLME_DEBUG_REASSOC 3 +#define MLME_DEBUG_DEAUTH 4 +#define MLME_DEBUG_DISASSOC 5 +#define MLME_DEBUG_ROAM 6 +#define MLME_DEBUG_RETRY 7 +#define MLME_DEBUG_TIMER 8 +#define MLME_DEBUG_FRAMEPARSE 9 + +/* SUPPL module DBGIDs */ +#define SUPPL_DBGID_INIT 0 +#define SUPPL_DBGID_RECV_EAPOL 1 +#define SUPPL_DBGID_RECV_EAPOL_TIMEOUT 2 +#define SUPPL_DBGID_SEND_EAPOL 3 +#define SUPPL_DBGID_MIC_MISMATCH 4 +#define SUPPL_DBGID_FINISH 5 +#define SUPPL_DBGID_GET_FRM_INFO 6 +#define SUPPL_DBGID_DUMP_TYPE 7 +#define SUPPL_DBGID_DUMP_HEX 8 +#define SUPPL_DBGID_NODE_NOT_FOUND 9 +#define SUPPL_DBGID_GET_EAPOL_BUF 10 +#define SUPPL_DBGID_GET_BUF_FAIL 11 +#define SUPPL_DBGID_RECV_EAPOL_ERROR 12 + +/* Stats Module DBGIDs */ +#define WLAN_STATS_DBGID_DEFINITION_START 0 +#define WLAN_STATS_DBGID_EST_LINKSPEED_VDEV_EN_DIS 1 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_START 2 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_END 3 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CALC 4 +#define WLAN_STATS_DBGID_EST_LINKSPEED_UPDATE_HOME_CHAN 5 +#define WLAN_STATS_DBGID_DEFINITION_END 6 +/* NAN DBGIDs */ +#define NAN_DBGID_START 0 + +/* Debug IDs for debug logs. 3 args max, not fixed. */ +#define NAN_DBGID_DBG_LOG_FIRST 1 +#define NAN_DBGID_FUNC_BEGIN NAN_DBGID_DBG_LOG_FIRST +#define NAN_DBGID_FUNC_END 2 +#define NAN_DBGID_MAIN_DEBUG 3 +#define NAN_DBGID_MAC_DEBUG 4 +#define NAN_DBGID_BLOOM_FILTER_DEBUG 5 +#define NAN_DBGID_MAC_ADDR 6 +#define NAN_DBGID_PARAM_UPDATED 7 +#define NAN_DBGID_NULL_PTR 8 +#define NAN_DBGID_INVALID_FUNC_ARG 9 +#define NAN_DBGID_INVALID_MSG_PARAM 10 +#define NAN_DBGID_MISSING_MSG_PARAM 11 +#define NAN_DBGID_DEPRECATED_MSG_PARAM 12 +#define NAN_DBGID_UNSUPPORTED_MSG_PARAM 13 +#define NAN_DBGID_INVALID_PKT_DATA 14 +#define NAN_DBGID_LOG_PKT_DATA 15 +#define NAN_DBGID_INVALID_VALUE 16 +#define NAN_DBGID_INVALID_OPERATION 17 +#define NAN_DBGID_INVALID_STATE 18 +#define NAN_DBGID_FUNCTION_ENABLED 19 +#define NAN_DBGID_FUNCTION_DISABLED 20 +#define NAN_DBGID_INVALID_FUNCTION_STATE 21 +#define NAN_DBGID_READ_ERROR 22 +#define NAN_DBGID_WRITE_ERROR 23 +#define NAN_DBGID_RECEIVE_ERROR 24 +#define NAN_DBGID_TRANSMIT_ERROR 25 +#define NAN_DBGID_PARSE_ERROR 26 +#define NAN_DBGID_RES_ALLOC_ERROR 27 +/* PLEASE KEEP THIS ONE AT THE END */ +#define NAN_DBGID_DBG_LOG_LAST 28 + +/* Debug IDs for event logs. */ + +#define NAN_DBGID_EVT_BASE NAN_DBGID_DBG_LOG_LAST +/* args: */ +#define NAN_DBGID_NAN_ENABLED (NAN_DBGID_EVT_BASE + 0) +/* args: */ +#define NAN_DBGID_NAN_DISABLED (NAN_DBGID_EVT_BASE + 1) +/* args: */ +#define NAN_DBGID_CONFIG_RESTORED (NAN_DBGID_EVT_BASE + 2) +/* args: framesQueued */ +#define NAN_DBGID_SDF_QUEUED (NAN_DBGID_EVT_BASE + 3) +/* args: old, new */ +#define NAN_DBGID_TW_CHANGED (NAN_DBGID_EVT_BASE + 4) +/* args: */ +#define NAN_DBGID_DW_START (NAN_DBGID_EVT_BASE + 5) +/* args: busyDiff */ +#define NAN_DBGID_DW_END (NAN_DBGID_EVT_BASE + 6) +/* args: oldClusterId, newClusterId */ +#define NAN_DBGID_CLUSTER_ID_CHANGED (NAN_DBGID_EVT_BASE + 7) +/* args: cmd, buffer, length */ +#define NAN_DBGID_WMI_CMD_RECEIVED (NAN_DBGID_EVT_BASE + 8) +/* args: pEventPkt, pEventBuf, eventSize, dataSize */ +#define NAN_DBGID_WMI_EVT_SENT (NAN_DBGID_EVT_BASE + 9) +/* args: type length, readLen */ +#define NAN_DBGID_TLV_READ (NAN_DBGID_EVT_BASE + 10) +/* args: type length, writeLen */ +#define NAN_DBGID_TLV_WRITE (NAN_DBGID_EVT_BASE + 11) +/* args: handle */ +#define NAN_DBGID_PUBSUB_UPDATED (NAN_DBGID_EVT_BASE + 12) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVE_DEFERED (NAN_DBGID_EVT_BASE + 13) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVE_PENDING (NAN_DBGID_EVT_BASE + 14) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVED (NAN_DBGID_EVT_BASE + 15) +/* args: handle */ +#define NAN_DBGID_PUBSUB_PROCESSED (NAN_DBGID_EVT_BASE + 16) +/* args: handle, sid1, sid2, svcCtrl, length */ +#define NAN_DBGID_PUBSUB_MATCHED (NAN_DBGID_EVT_BASE + 17) +/* args: handle, flags */ +#define NAN_DBGID_PUBSUB_PREPARED (NAN_DBGID_EVT_BASE + 18) +/* args: handle, mac1, mac2 */ +#define NAN_DBGID_PUBSUB_FOLLOWUP_TRANSMIT (NAN_DBGID_EVT_BASE + 19) +/* args: handle, mac1, mac2 */ +#define NAN_DBGID_PUBSUB_FOLLOWUP_RECEIVED (NAN_DBGID_EVT_BASE + 20) +/* args: subscribeHandle, matchHandle, oldTimeout, newTimeout */ +#define NAN_DBGID_SUBSCRIBE_UNMATCH_TIMEOUT_UPDATE (NAN_DBGID_EVT_BASE + 21) +/* args: subscribeHandle, matchHandle, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_NEW (NAN_DBGID_EVT_BASE + 22) +/* args: subscribeHandle, matchHandle, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_REPEAT (NAN_DBGID_EVT_BASE + 23) +/* args: subscribeHandle, matchHandle, matchTimestamp, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_EXPIRED (NAN_DBGID_EVT_BASE + 24) +/* args: subscribeHandle, matchHandle, matchTimestamp, timestamp */ +#define NAN_DBGID_SUBSCRIBE_MATCH_LOG (NAN_DBGID_EVT_BASE + 25) +/* args: sid1, sid2 */ +#define NAN_DBGID_SERVICE_ID_CREATED (NAN_DBGID_EVT_BASE + 26) +/* args: size */ +#define NAN_DBGID_SD_ATTR_BUILT (NAN_DBGID_EVT_BASE + 27) +/* args: offset */ +#define NAN_DBGID_SERVICE_RSP_OFFSET (NAN_DBGID_EVT_BASE + 28) +/* args: offset */ +#define NAN_DBGID_SERVICE_INFO_OFFSET (NAN_DBGID_EVT_BASE + 29) +/* args: chan, interval, start_time */ +#define NAN_DBGID_CHREQ_CREATE (NAN_DBGID_EVT_BASE + 30) +/* args: start_time, status */ +#define NAN_DBGID_CHREQ_UPDATE (NAN_DBGID_EVT_BASE + 31) +/* args: chan, interval, status */ +#define NAN_DBGID_CHREQ_REMOVE (NAN_DBGID_EVT_BASE + 32) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_GRANT (NAN_DBGID_EVT_BASE + 33) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_END (NAN_DBGID_EVT_BASE + 34) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_ERROR (NAN_DBGID_EVT_BASE + 35) +/* args: type, length, timestamp, rssi */ +#define NAN_DBGID_RX_CALLBACK (NAN_DBGID_EVT_BASE + 36) +/* args: type, handle, bufp, status, timestamp */ +#define NAN_DBGID_TX_COMPLETE (NAN_DBGID_EVT_BASE + 37) +/* args: tsf, tsf */ +#define NAN_DBGID_TSF_TIMEOUT (NAN_DBGID_EVT_BASE + 38) +/* args: clusterId, clusterStart */ +#define NAN_DBGID_SYNC_START (NAN_DBGID_EVT_BASE + 39) +/* args: clusterId */ +#define NAN_DBGID_SYNC_STOP (NAN_DBGID_EVT_BASE + 40) +/* args: enable, scanType, rval */ +#define NAN_DBGID_NAN_SCAN (NAN_DBGID_EVT_BASE + 41) +/* args: scanType */ +#define NAN_DBGID_NAN_SCAN_COMPLETE (NAN_DBGID_EVT_BASE + 42) +/* args: masterPref */ +#define NAN_DBGID_MPREF_CHANGE (NAN_DBGID_EVT_BASE + 43) +/* args: masterPref, randFactor */ +#define NAN_DBGID_WARMUP_EXPIRE (NAN_DBGID_EVT_BASE + 44) +/* args: randFactor */ +#define NAN_DBGID_RANDOM_FACTOR_EXPIRE (NAN_DBGID_EVT_BASE + 45) +/* args: tsf, tsf */ +#define NAN_DBGID_DW_SKIP (NAN_DBGID_EVT_BASE + 46) +/* args: type, tsfDiff */ +#define NAN_DBGID_DB_SKIP (NAN_DBGID_EVT_BASE + 47) +/* args: TBD */ +#define NAN_DBGID_BEACON_RX (NAN_DBGID_EVT_BASE + 48) +/* args: TBD */ +#define NAN_DBGID_BEACON_TX (NAN_DBGID_EVT_BASE + 49) +/* args: clusterId */ +#define NAN_DBGID_CLUSTER_MERGE (NAN_DBGID_EVT_BASE + 50) +/* args: cmd, status, value */ +#define NAN_DBGID_TEST_CMD_EXEC (NAN_DBGID_EVT_BASE + 51) +/* args: tsfHi, tsfLo, age */ +#define NAN_DBGID_APPLY_BEACON_TSF (NAN_DBGID_EVT_BASE + 52) +/* args: behindFlag, diff */ +#define NAN_DBGID_TSF_UPDATE (NAN_DBGID_EVT_BASE + 53) +/* args: argc==4 (rawTsfHi, rawTsfLo, nanTsfHi, nanTsfLo), argc==2(offsetHi, offsetLo) */ +#define NAN_DBGID_SET_TSF (NAN_DBGID_EVT_BASE + 54) +/* args: rankHi, rankLo, mp, rf */ +#define NAN_DBGID_NEW_MASTERRANK (NAN_DBGID_EVT_BASE + 55) +/* args: amRankHi, amRankLo, mp, rf */ +#define NAN_DBGID_NEW_ANCHORMASTER (NAN_DBGID_EVT_BASE + 56) +/* args: amRankHi, amRankLo, HC, BTT */ +#define NAN_DBGID_ANCHORMASTER_RECORD_UPDATE (NAN_DBGID_EVT_BASE + 57) +/* args: amRankHi, amRankLo, HC, BTT */ +#define NAN_DBGID_ANCHORMASTER_RECORD_EXPIRED (NAN_DBGID_EVT_BASE + 58) +/* args: reason, transitionsToAM */ +#define NAN_DBGID_BECOMING_ANCHORMASTER (NAN_DBGID_EVT_BASE + 59) +/* args: oldRole, newRole */ +#define NAN_DBGID_ROLE_CHANGE (NAN_DBGID_EVT_BASE + 60) +/* args: TBD */ +#define NAN_DBGID_SYNC_BEACON_DW_STATS (NAN_DBGID_EVT_BASE + 61) +/* args: attrId */ +#define NAN_DBGID_RX_UNSUPPORTED_SDF_ATTR_ID (NAN_DBGID_EVT_BASE + 62) +/* args: handle, sid1, sid2, svcCtrl, length */ +#define NAN_DBGID_PUBSUB_MATCHED_SKIPPED_SSI (NAN_DBGID_EVT_BASE + 63) +/* args: offset */ +#define NAN_DBGID_MATCH_FILTER_OFFSET (NAN_DBGID_EVT_BASE + 64) +/* args: twSize, n, twIndex */ +#define NAN_DBGID_TW_PARAMS (NAN_DBGID_EVT_BASE + 65) +/* args: */ +#define NAN_DBGID_BEACON_SENDER (NAN_DBGID_EVT_BASE + 66) +/* args: currTsf, nextDwTsf */ +#define NAN_DBGID_TSF_DUMP (NAN_DBGID_EVT_BASE + 67) +/* args: chan, startSlot, numSlots, repeat */ +#define NAN_DBGID_FAW_CONFIG (NAN_DBGID_EVT_BASE + 68) +/* args: */ +#define NAN_DBGID_FAW_START (NAN_DBGID_EVT_BASE + 69) +/* args: */ +#define NAN_DBGID_FAW_END (NAN_DBGID_EVT_BASE + 70) +/* args: offset, oldval, newval */ +#define NAN_DBGID_CONFIG_PARAM_CHANGED (NAN_DBGID_EVT_BASE + 71) +/* args: */ +#define NAN_DBGID_CONN_CAP_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 72) +/* args: connType */ +#define NAN_DBGID_POST_DISC_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 73) +/* args: */ +#define NAN_DBGID_VENDOR_SPECIFIC_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 74) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_MAP_CTRL_OFFSET (NAN_DBGID_EVT_BASE + 75) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_AI_BITMAP_OFFSET (NAN_DBGID_EVT_BASE + 76) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_DEVICE_ROLE_OFFSET (NAN_DBGID_EVT_BASE + 77) +/* args: offset */ +#define NAN_DBGID_MESH_ID_OFFSET (NAN_DBGID_EVT_BASE + 78) +/* args: */ +#define NAN_DBGID_SPARE_79 (NAN_DBGID_EVT_BASE + 79) +/* args: */ +#define NAN_DBGID_SPARE_80 (NAN_DBGID_EVT_BASE + 80) +/* args: */ +#define NAN_DBGID_SPARE_81 (NAN_DBGID_EVT_BASE + 81) +/* args: */ +#define NAN_DBGID_SPARE_82 (NAN_DBGID_EVT_BASE + 82) +/* args: */ +#define NAN_DBGID_SPARE_83 (NAN_DBGID_EVT_BASE + 83) +/* PLEASE KEEP THIS ONE AT THE END */ +#define NAN_DBGID_EVT_LOG_LAST (NAN_DBGID_EVT_BASE + 84) + +/* Debug IDs for message logs. */ +#define NAN_DBGID_API_MSG_BASE NAN_DBGID_EVT_LOG_LAST +#define NAN_DBGID_API_MSG_HEADER (NAN_DBGID_API_MSG_BASE + 0) +#define NAN_DBGID_API_MSG_DATA (NAN_DBGID_API_MSG_BASE + 1) +#define NAN_DBGID_API_MSG_LAST (NAN_DBGID_API_MSG_BASE + 2) + +/* Debug IDs for packet logs. */ +#define NAN_DBGID_OTA_PKT_BASE NAN_DBGID_API_MSG_LAST +#define NAN_DBGID_OTA_PKT_HEADER (NAN_DBGID_OTA_PKT_BASE + 0) +#define NAN_DBGID_OTA_PKT_DATA (NAN_DBGID_OTA_PKT_BASE + 1) +#define NAN_DBGID_OTA_PKT_LAST (NAN_DBGID_OTA_PKT_BASE + 2) /* not really the last! */ + +#define NAN_DBGID_BEACON_RX_TIMES (NAN_DBGID_OTA_PKT_LAST + 0) +#define NAN_DBGID_BEACON_RX_MANDATORY_ATTRS (NAN_DBGID_OTA_PKT_LAST + 1) +#define NAN_DBGID_BEACON_RX_SID_ATTR (NAN_DBGID_OTA_PKT_LAST + 2) +#define NAN_DBGID_BEACON_RX_VSA_ATTR (NAN_DBGID_OTA_PKT_LAST + 3) +#define NAN_DBGID_BEACON_RX_AVG_RSSI (NAN_DBGID_OTA_PKT_LAST + 4) +#define NAN_DBGID_CANDIDATE_BEACONS (NAN_DBGID_OTA_PKT_LAST + 5) +#define NAN_DBGID_TSF_OFFSET (NAN_DBGID_OTA_PKT_LAST + 6) +#define NAN_DBGID_ANCHORMASTER_RECORD_UPDATE_LAST (NAN_DBGID_OTA_PKT_LAST + 7) +#define NAN_DBGID_ANCHORMASTER_RECORD_EXPIRED2 (NAN_DBGID_OTA_PKT_LAST + 8) +#define NAN_DBGID_BEACON_TX_SEND (NAN_DBGID_OTA_PKT_LAST + 9) +#define NAN_DBGID_BEACON_TX_CANCEL (NAN_DBGID_OTA_PKT_LAST + 10) +#define NAN_DBGID_NAN_SCAN_EVENT (NAN_DBGID_OTA_PKT_LAST + 11) +#define NAN_DBGID_NAN_SDF_QUEUED (NAN_DBGID_OTA_PKT_LAST + 12) +#define NAN_DBGID_NAN_BEACON_QUEUED (NAN_DBGID_OTA_PKT_LAST + 13) +#define NAN_DBGID_NAN_NOT_ALLOWED (NAN_DBGID_OTA_PKT_LAST + 14) + +#define NAN_DBGID_END (NAN_DBGID_NAN_NOT_ALLOWED + 1) + +/* IBSS PS module DBGIDs*/ +#define IBSS_PS_DBGID_DEFINITION_START 0 +#define IBSS_PS_DBGID_PEER_CREATE 1 +#define IBSS_PS_DBGID_PEER_DELETE 2 +#define IBSS_PS_DBGID_VDEV_CREATE 3 +#define IBSS_PS_DBGID_VDEV_DELETE 4 +#define IBSS_PS_DBGID_VDEV_EVENT 5 +#define IBSS_PS_DBGID_PEER_EVENT 6 +#define IBSS_PS_DBGID_DELIVER_CAB 7 +#define IBSS_PS_DBGID_DELIVER_UC_DATA 8 +#define IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR 9 +#define IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART 10 +#define IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART 11 +#define IBSS_PS_DBGID_NULL_TX_COMPLETION 12 +#define IBSS_PS_DBGID_ATIM_TIMER_START 13 +#define IBSS_PS_DBGID_UC_ATIM_SEND 14 +#define IBSS_PS_DBGID_BC_ATIM_SEND 15 +#define IBSS_PS_DBGID_UC_TIMEOUT 16 +#define IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED 17 +#define IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED 18 +#define IBSS_PS_DBGID_SET_PARAM 19 +#define IBSS_PS_DBGID_HOST_TX_PAUSE 20 +#define IBSS_PS_DBGID_HOST_TX_UNPAUSE 21 +#define IBSS_PS_DBGID_PS_DESC_BIN_HWM 22 +#define IBSS_PS_DBGID_PS_DESC_BIN_LWM 23 +#define IBSS_PS_DBGID_PS_KICKOUT_PEER 24 +#define IBSS_PS_DBGID_SET_PEER_PARAM 25 +#define IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH 26 +#define IBSS_PS_DBGID_RX_CHAINMASK_CHANGE 27 + +/* HIF UART Interface DBGIDs */ +#define HIF_UART_DBGID_START 0 +#define HIF_UART_DBGID_POWER_STATE 1 +#define HIF_UART_DBGID_TXRX_FLOW 2 +#define HIF_UART_DBGID_TXRX_CTRL_CHAR 3 +#define HIF_UART_DBGID_TXRX_BUF_DUMP 4 + +/* EXTSCAN DBGIDs */ +#define EXTSCAN_START 0 +#define EXTSCAN_STOP 1 +#define EXTSCAN_CLEAR_ENTRY_CONTENT 2 +#define EXTSCAN_GET_FREE_ENTRY_SUCCESS 3 +#define EXTSCAN_GET_FREE_ENTRY_INCONSISTENT 4 +#define EXTSCAN_GET_FREE_ENTRY_NO_MORE_ENTRIES 5 +#define EXTSCAN_CREATE_ENTRY_SUCCESS 6 +#define EXTSCAN_CREATE_ENTRY_ERROR 7 +#define EXTSCAN_SEARCH_SCAN_ENTRY_QUEUE 8 +#define EXTSCAN_SEARCH_SCAN_ENTRY_KEY_FOUND 9 +#define EXTSCAN_SEARCH_SCAN_ENTRY_KEY_NOT_FOUND 10 +#define EXTSCAN_ADD_ENTRY 11 +#define EXTSCAN_BUCKET_SEND_OPERATION_EVENT 12 +#define EXTSCAN_BUCKET_SEND_OPERATION_EVENT_FAILED 13 +#define EXTSCAN_BUCKET_START_SCAN_CYCLE 14 +#define EXTSCAN_BUCKET_PERIODIC_TIMER 15 +#define EXTSCAN_SEND_START_STOP_EVENT 16 +#define EXTSCAN_NOTIFY_WLAN_CHANGE 17 +#define EXTSCAN_NOTIFY_WLAN_HOTLIST_MATCH 18 +#define EXTSCAN_MAIN_RECEIVED_FRAME 19 +#define EXTSCAN_MAIN_NO_SSID_IE 20 +#define EXTSCAN_MAIN_MALFORMED_FRAME 21 +#define EXTSCAN_FIND_BSSID_BY_REFERENCE 22 +#define EXTSCAN_FIND_BSSID_BY_REFERENCE_ERROR 23 +#define EXTSCAN_NOTIFY_TABLE_USAGE 24 +#define EXTSCAN_FOUND_RSSI_ENTRY 25 +#define EXTSCAN_BSSID_FOUND_RSSI_SAMPLE 26 +#define EXTSCAN_BSSID_ADDED_RSSI_SAMPLE 27 +#define EXTSCAN_BSSID_REPLACED_RSSI_SAMPLE 28 +#define EXTSCAN_BSSID_TRANSFER_CURRENT_SAMPLES 29 +#define EXTSCAN_BUCKET_PROCESS_SCAN_EVENT 30 +#define EXTSCAN_BUCKET_CANNOT_FIND_BUCKET 31 +#define EXTSCAN_START_SCAN_REQUEST_FAILED 32 +#define EXTSCAN_BUCKET_STOP_CURRENT_SCANS 33 +#define EXTSCAN_BUCKET_SCAN_STOP_REQUEST 34 +#define EXTSCAN_BUCKET_PERIODIC_TIMER_ERROR 35 +#define EXTSCAN_BUCKET_START_OPERATION 36 +#define EXTSCAN_START_INTERNAL_ERROR 37 +#define EXTSCAN_NOTIFY_HOTLIST_MATCH 38 +#define EXTSCAN_CONFIG_HOTLIST_TABLE 39 +#define EXTSCAN_CONFIG_WLAN_CHANGE_TABLE 40 + +/* NLO DBGIDs */ +#define NLO_DBGID_SSID_TO_BE_SCANNED_LIST 0 +#define NLO_DBGID_SSID_TO_BE_SKIPPED_LIST 1 + +/* Channel prediction/reduction DBGIDs */ +#define SCAN_CH_PREDICT_DBGID_DEFINITION_START 0 +#define SCAN_CH_PREDICT_CALCULATE 1 +#define SCAN_CH_PREDICT_CALCULATE_SAMPLE 2 +#define SCAN_CH_PREDICT_CALCULATE_RESULT 3 +#define SCAN_CH_PREDICT_FOUND_BSS 4 +#define SCAN_CH_PREDICT_SCAN_START 5 +#define SCAN_CH_PREDICT_START 6 +#define SCAN_CH_PREDICT_STOP 7 +#define SCAN_CH_PREDICT_DBGID_DEFINITION_END 8 + +/* DSRC DBGIDs */ +#define OCB_DBGID_VDEV_CREATE 0 +#define OCB_DBGID_VDEV_DELETE 1 +#define OCB_DBGID_CHAN_PAUSE 2 +#define OCB_DBGID_CHAN_UNPAUSE 3 +#define OCB_DBGID_PEER_CREATE 4 +#define OCB_DBGID_PEER_DELETE 5 +#define OCB_DBGID_DCC_START 6 +#define OCB_DBGID_DCC_STOP 7 +#define OCB_DBGID_SET_CONFIG_CMD 8 +#define OCB_DBGID_SET_UTC_TIME_CMD 9 +#define OCB_DBGID_START_TIMING_ADVERT_CMD 10 +#define OCB_DBGID_STOP_TIMING_ADVERT_CMD 11 +#define OCB_DBGID_GET_TSF_TIMER_CMD 12 +#define OCB_DBGID_GET_DCC_STATS_CMD 13 +#define OCB_DBGID_UPDATE_DCC_NDL_CMD 14 +#define OCB_DBGID_SET_CONFIG_RESP_EVENT 15 +#define OCB_DBGID_GET_TSF_TIMER_RESP_EVENT 16 +#define OCB_DBGID_GET_DCC_STATS_RESP_EVENT 17 +#define OCB_DBGID_DCC_STATS_EVENT 18 +#define OCB_UPDATE_DCC_NDL_RESP_EVENT 19 +#define OCB_DBGID_GENERIC 20 +#define OCB_DBGID_VDEV_START 21 +#define OCB_DBGID_CHANNEL_SCHED_EVENT 22 +#define OCB_DBGID_GPS_EVENT_START 23 +#define OCB_DBGID_GPS_EVENT_END 24 +#define OCB_DBGID_TX_TA_FRAME 25 +#define OCB_DBGID_RX_TA_FRAME 26 + +/* Up to 255 reserved for OCB debug IDs */ + +#define DCC_DBGID_START 256 +#define DCC_DBGID_STOP 257 +#define DCC_DBGID_DCC_STATS_EVENT 258 +#define DCC_DBGID_SM_INIT 259 +#define DCC_DBGID_SM_EVENT 260 +#define DCC_DBGID_SM_CHANGE 261 +#define DCC_DBGID_GET_TX_ALLOWED 262 +#define DCC_DBGID_NOTIFY_TX_COMPLETION 263 +#define DCC_DBGID_NOTIFY_RX 264 +#define DCC_DBGID_GET_TX_POWER 265 +#define DCC_DBGID_GET_TX_RATE 266 +#define DCC_DBGID_TICKLE_SCHED 267 +#define DCC_DBGID_GENERIC 268 +#define DCC_DBGID_RX_PATH 269 +#define DCC_DBGID_TX_PATH 270 + +/* RSSI Threshold Monitor DBGIDs*/ +#define RSSI_MONITOR_DBGID_DEFINITION_START 0 +#define RSSI_MONITOR_VDEV_INIT 1 +#define RSSI_MONITOR_VDEV_FREE 2 +#define RSSI_MONITOR_VDEV_EVENT 3 +#define RSSI_MONITOR_HW_EVENT 4 +#define RSSI_MONITOR_ENABLE_THRESHOLDS_CLIENT_REQ 5 +#define RSSI_MONITOR_ENABLE_THRESHOLDS_CLIENT_REQ_ERR 6 +#define RSSI_MONITOR_DISABLE_THRESHOLDS_CLIENT_REQ 7 +#define RSSI_MONITOR_DISABLE_THRESHOLDS_CLIENT_REQ_ERR 8 +#define RSSI_MONITOR_ARBITER 9 +#define RSSI_MONITOR_ARBITER_CONFIG_HW 10 +#define RSSI_MONITOR_CHECK_AND_DELIVER_EVENT 11 +#define RSSI_MONITOR_DELIVER_EVENT 12 +#define RSSI_MONITOR_UPDATE_BEACON_RSSI 13 +#define RSSI_MONITOR_DBGID_DEFINITION_END 14 + +#ifdef __cplusplus +} +#endif +#endif /* _DBGLOG_ID_H_ */ diff --git a/target/inc/efuse_reg.h b/target/inc/efuse_reg.h new file mode 100644 index 0000000000..2bff9f8a28 --- /dev/null +++ b/target/inc/efuse_reg.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _EFUSE_REG_REG_H_ +#define _EFUSE_REG_REG_H_ + +#define EFUSE_WR_ENABLE_REG_ADDRESS 0x00000000 +#define EFUSE_WR_ENABLE_REG_OFFSET 0x00000000 +#define EFUSE_WR_ENABLE_REG_V_MSB 0 +#define EFUSE_WR_ENABLE_REG_V_LSB 0 +#define EFUSE_WR_ENABLE_REG_V_MASK 0x00000001 +#define EFUSE_WR_ENABLE_REG_V_GET(x) (((x) & EFUSE_WR_ENABLE_REG_V_MASK) >> EFUSE_WR_ENABLE_REG_V_LSB) +#define EFUSE_WR_ENABLE_REG_V_SET(x) (((x) << EFUSE_WR_ENABLE_REG_V_LSB) & EFUSE_WR_ENABLE_REG_V_MASK) + +#define EFUSE_INT_ENABLE_REG_ADDRESS 0x00000004 +#define EFUSE_INT_ENABLE_REG_OFFSET 0x00000004 +#define EFUSE_INT_ENABLE_REG_V_MSB 0 +#define EFUSE_INT_ENABLE_REG_V_LSB 0 +#define EFUSE_INT_ENABLE_REG_V_MASK 0x00000001 +#define EFUSE_INT_ENABLE_REG_V_GET(x) (((x) & EFUSE_INT_ENABLE_REG_V_MASK) >> EFUSE_INT_ENABLE_REG_V_LSB) +#define EFUSE_INT_ENABLE_REG_V_SET(x) (((x) << EFUSE_INT_ENABLE_REG_V_LSB) & EFUSE_INT_ENABLE_REG_V_MASK) + +#define EFUSE_INT_STATUS_REG_ADDRESS 0x00000008 +#define EFUSE_INT_STATUS_REG_OFFSET 0x00000008 +#define EFUSE_INT_STATUS_REG_V_MSB 0 +#define EFUSE_INT_STATUS_REG_V_LSB 0 +#define EFUSE_INT_STATUS_REG_V_MASK 0x00000001 +#define EFUSE_INT_STATUS_REG_V_GET(x) (((x) & EFUSE_INT_STATUS_REG_V_MASK) >> EFUSE_INT_STATUS_REG_V_LSB) +#define EFUSE_INT_STATUS_REG_V_SET(x) (((x) << EFUSE_INT_STATUS_REG_V_LSB) & EFUSE_INT_STATUS_REG_V_MASK) + +#define BITMASK_WR_REG_ADDRESS 0x0000000c +#define BITMASK_WR_REG_OFFSET 0x0000000c +#define BITMASK_WR_REG_V_MSB 31 +#define BITMASK_WR_REG_V_LSB 0 +#define BITMASK_WR_REG_V_MASK 0xffffffff +#define BITMASK_WR_REG_V_GET(x) (((x) & BITMASK_WR_REG_V_MASK) >> BITMASK_WR_REG_V_LSB) +#define BITMASK_WR_REG_V_SET(x) (((x) << BITMASK_WR_REG_V_LSB) & BITMASK_WR_REG_V_MASK) + +#define VDDQ_SETTLE_TIME_REG_ADDRESS 0x00000010 +#define VDDQ_SETTLE_TIME_REG_OFFSET 0x00000010 +#define VDDQ_SETTLE_TIME_REG_V_MSB 31 +#define VDDQ_SETTLE_TIME_REG_V_LSB 0 +#define VDDQ_SETTLE_TIME_REG_V_MASK 0xffffffff +#define VDDQ_SETTLE_TIME_REG_V_GET(x) (((x) & VDDQ_SETTLE_TIME_REG_V_MASK) >> VDDQ_SETTLE_TIME_REG_V_LSB) +#define VDDQ_SETTLE_TIME_REG_V_SET(x) (((x) << VDDQ_SETTLE_TIME_REG_V_LSB) & VDDQ_SETTLE_TIME_REG_V_MASK) + +#define VDDQ_HOLD_TIME_REG_ADDRESS 0x00000014 +#define VDDQ_HOLD_TIME_REG_OFFSET 0x00000014 +#define VDDQ_HOLD_TIME_REG_V_MSB 31 +#define VDDQ_HOLD_TIME_REG_V_LSB 0 +#define VDDQ_HOLD_TIME_REG_V_MASK 0xffffffff +#define VDDQ_HOLD_TIME_REG_V_GET(x) (((x) & VDDQ_HOLD_TIME_REG_V_MASK) >> VDDQ_HOLD_TIME_REG_V_LSB) +#define VDDQ_HOLD_TIME_REG_V_SET(x) (((x) << VDDQ_HOLD_TIME_REG_V_LSB) & VDDQ_HOLD_TIME_REG_V_MASK) + +#define RD_STROBE_PW_REG_ADDRESS 0x00000018 +#define RD_STROBE_PW_REG_OFFSET 0x00000018 +#define RD_STROBE_PW_REG_V_MSB 31 +#define RD_STROBE_PW_REG_V_LSB 0 +#define RD_STROBE_PW_REG_V_MASK 0xffffffff +#define RD_STROBE_PW_REG_V_GET(x) (((x) & RD_STROBE_PW_REG_V_MASK) >> RD_STROBE_PW_REG_V_LSB) +#define RD_STROBE_PW_REG_V_SET(x) (((x) << RD_STROBE_PW_REG_V_LSB) & RD_STROBE_PW_REG_V_MASK) + +#define PG_STROBE_PW_REG_ADDRESS 0x0000001c +#define PG_STROBE_PW_REG_OFFSET 0x0000001c +#define PG_STROBE_PW_REG_V_MSB 31 +#define PG_STROBE_PW_REG_V_LSB 0 +#define PG_STROBE_PW_REG_V_MASK 0xffffffff +#define PG_STROBE_PW_REG_V_GET(x) (((x) & PG_STROBE_PW_REG_V_MASK) >> PG_STROBE_PW_REG_V_LSB) +#define PG_STROBE_PW_REG_V_SET(x) (((x) << PG_STROBE_PW_REG_V_LSB) & PG_STROBE_PW_REG_V_MASK) + +#define PGENB_SETUP_HOLD_TIME_REG_ADDRESS 0x00000020 +#define PGENB_SETUP_HOLD_TIME_REG_OFFSET 0x00000020 +#define PGENB_SETUP_HOLD_TIME_REG_V_MSB 31 +#define PGENB_SETUP_HOLD_TIME_REG_V_LSB 0 +#define PGENB_SETUP_HOLD_TIME_REG_V_MASK 0xffffffff +#define PGENB_SETUP_HOLD_TIME_REG_V_GET(x) (((x) & PGENB_SETUP_HOLD_TIME_REG_V_MASK) >> PGENB_SETUP_HOLD_TIME_REG_V_LSB) +#define PGENB_SETUP_HOLD_TIME_REG_V_SET(x) (((x) << PGENB_SETUP_HOLD_TIME_REG_V_LSB) & PGENB_SETUP_HOLD_TIME_REG_V_MASK) + +#define STROBE_PULSE_INTERVAL_REG_ADDRESS 0x00000024 +#define STROBE_PULSE_INTERVAL_REG_OFFSET 0x00000024 +#define STROBE_PULSE_INTERVAL_REG_V_MSB 31 +#define STROBE_PULSE_INTERVAL_REG_V_LSB 0 +#define STROBE_PULSE_INTERVAL_REG_V_MASK 0xffffffff +#define STROBE_PULSE_INTERVAL_REG_V_GET(x) (((x) & STROBE_PULSE_INTERVAL_REG_V_MASK) >> STROBE_PULSE_INTERVAL_REG_V_LSB) +#define STROBE_PULSE_INTERVAL_REG_V_SET(x) (((x) << STROBE_PULSE_INTERVAL_REG_V_LSB) & STROBE_PULSE_INTERVAL_REG_V_MASK) + +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_ADDRESS 0x00000028 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_OFFSET 0x00000028 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MSB 31 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB 0 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK 0xffffffff +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_GET(x) (((x) & CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK) >> CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB) +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_SET(x) (((x) << CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB) & CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK) + +#define EFUSE_INTF0_ADDRESS 0x00000800 +#define EFUSE_INTF0_OFFSET 0x00000800 +#define EFUSE_INTF0_R_MSB 31 +#define EFUSE_INTF0_R_LSB 0 +#define EFUSE_INTF0_R_MASK 0xffffffff +#define EFUSE_INTF0_R_GET(x) (((x) & EFUSE_INTF0_R_MASK) >> EFUSE_INTF0_R_LSB) +#define EFUSE_INTF0_R_SET(x) (((x) << EFUSE_INTF0_R_LSB) & EFUSE_INTF0_R_MASK) + +#define EFUSE_INTF1_ADDRESS 0x00001000 +#define EFUSE_INTF1_OFFSET 0x00001000 +#define EFUSE_INTF1_R_MSB 31 +#define EFUSE_INTF1_R_LSB 0 +#define EFUSE_INTF1_R_MASK 0xffffffff +#define EFUSE_INTF1_R_GET(x) (((x) & EFUSE_INTF1_R_MASK) >> EFUSE_INTF1_R_LSB) +#define EFUSE_INTF1_R_SET(x) (((x) << EFUSE_INTF1_R_LSB) & EFUSE_INTF1_R_MASK) + +#ifndef __ASSEMBLER__ +typedef struct efuse_reg_reg_s { + volatile unsigned int efuse_wr_enable_reg; + volatile unsigned int efuse_int_enable_reg; + volatile unsigned int efuse_int_status_reg; + volatile unsigned int bitmask_wr_reg; + volatile unsigned int vddq_settle_time_reg; + volatile unsigned int vddq_hold_time_reg; + volatile unsigned int rd_strobe_pw_reg; + volatile unsigned int pg_strobe_pw_reg; + volatile unsigned int pgenb_setup_hold_time_reg; + volatile unsigned int strobe_pulse_interval_reg; + volatile unsigned int csb_addr_load_setup_hold_reg; + unsigned char pad0[2004]; /* pad to 0x800 */ + volatile unsigned int efuse_intf0[512]; + volatile unsigned int efuse_intf1[512]; +} efuse_reg_reg_t; +#endif /* __ASSEMBLER__ */ + +#endif /* _EFUSE_REG_H_ */ diff --git a/target/inc/enet.h b/target/inc/enet.h new file mode 100644 index 0000000000..c3f0cd68fc --- /dev/null +++ b/target/inc/enet.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ENET__H_ +#define _ENET__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +#define ETHERNET_ADDR_LEN 6 /* bytes */ +#define ETHERNET_TYPE_LEN 2 /* bytes - length of the Ethernet type field */ + +struct ethernet_hdr_t { + A_UINT8 dest_addr[ETHERNET_ADDR_LEN]; + A_UINT8 src_addr[ETHERNET_ADDR_LEN]; + A_UINT8 ethertype[ETHERNET_TYPE_LEN]; +}; + +#define ETHERNET_HDR_LEN (sizeof(struct ethernet_hdr_t)) + +#define ETHERNET_CRC_LEN 4 /* bytes - length of the Ethernet CRC */ +#define ETHERNET_MAX_LEN 1518 /* bytes */ + +#define ETHERNET_MTU (ETHERNET_MAX_LEN - (ETHERNET_HDR_LEN + ETHER_CRC_LEN)) + +struct llc_snap_hdr_t { + A_UINT8 dsap; + A_UINT8 ssap; + A_UINT8 cntl; + A_UINT8 org_code[3]; + A_UINT8 ethertype[2]; +}; + +#define LLC_SNAP_HDR_LEN (sizeof(struct llc_snap_hdr_t)) +#define LLC_SNAP_HDR_OFFSET_ETHERTYPE \ + (offsetof(struct llc_snap_hdr_t, ethertype[0])) + +#define ETHERTYPE_VLAN_LEN 4 + +struct ethernet_vlan_hdr_t { + A_UINT8 dest_addr[ETHERNET_ADDR_LEN]; + A_UINT8 src_addr[ETHERNET_ADDR_LEN]; + A_UINT8 vlan_tpid[2]; + A_UINT8 vlan_tci[2]; + A_UINT8 ethertype[2]; +}; + +#define ETHERTYPE_IS_EAPOL_WAPI(typeorlen) \ + ((typeorlen) == ETHERTYPE_PAE || \ + (typeorlen) == ETHERTYPE_WAI) + +#define IS_ETHERTYPE(_typeOrLen) ((_typeOrLen) >= 0x0600) + +#ifndef ETHERTYPE_IPV4 +#define ETHERTYPE_IPV4 0x0800 /* Internet Protocol, Version 4 (IPv4) */ +#endif + +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 /* Internal QCA AARP protocol */ +#endif + +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 /* IPX over DIX protocol */ +#endif + +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* Address Resolution Protocol (ARP) */ +#endif + +#ifndef ETHERTYPE_RARP +#define ETHERTYPE_RARP 0x8035 /* Reverse Address Resolution Protocol (RARP) */ +#endif + +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* VLAN TAG protocol */ +#endif + +#ifndef ETHERTYPE_SNMP +#define ETHERTYPE_SNMP 0x814C /* Simple Network Management Protocol (SNMP) */ +#endif + +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86DD /* Internet Protocol, Version 6 (IPv6) */ +#endif + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888E /* EAP over LAN (EAPOL) */ +#endif + +#ifndef ETHERTYPE_WAI +#define ETHERTYPE_WAI 0x88B4 /* WAPI */ +#endif + +#ifndef ETHERTYPE_TDLS +#define ETHERTYPE_TDLS 0x890D /* TDLS */ +#endif + +#define LLC_SNAP_LSAP 0xaa +#define LLC_UI 0x3 + +#define RFC1042_SNAP_ORGCODE_0 0x00 +#define RFC1042_SNAP_ORGCODE_1 0x00 +#define RFC1042_SNAP_ORGCODE_2 0x00 + +#define BTEP_SNAP_ORGCODE_0 0x00 +#define BTEP_SNAP_ORGCODE_1 0x00 +#define BTEP_SNAP_ORGCODE_2 0xf8 + +#define IS_SNAP(_llc) ((_llc)->dsap == LLC_SNAP_LSAP && \ + (_llc)->ssap == LLC_SNAP_LSAP && \ + (_llc)->cntl == LLC_UI) + +#define IS_RFC1042(_llc) ((_llc)->org_code[0] == RFC1042_SNAP_ORGCODE_0 && \ + (_llc)->org_code[1] == RFC1042_SNAP_ORGCODE_1 && \ + (_llc)->org_code[2] == RFC1042_SNAP_ORGCODE_2) + +#define IS_BTEP(_llc) ((_llc)->org_code[0] == BTEP_SNAP_ORGCODE_0 && \ + (_llc)->org_code[1] == BTEP_SNAP_ORGCODE_1 && \ + (_llc)->org_code[2] == BTEP_SNAP_ORGCODE_2) + +#endif /* _ENET__H_ */ diff --git a/target/inc/epping_test.h b/target/inc/epping_test.h new file mode 100644 index 0000000000..b8e6d01785 --- /dev/null +++ b/target/inc/epping_test.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* This file contains shared definitions for the host/target endpoint ping test */ + +#ifndef EPPING_TEST_H +#define EPPING_TEST_H + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* alignment to 4-bytes */ +#define EPPING_ALIGNMENT_PAD (((sizeof(HTC_FRAME_HDR) + 3) & (~0x3)) - sizeof(HTC_FRAME_HDR)) + +#ifndef A_OFFSETOF +#define A_OFFSETOF(type,field) (int)(&(((type *)NULL)->field)) +#endif + +#define EPPING_RSVD_FILL 0xCC + +#define HCI_RSVD_EXPECTED_PKT_TYPE_RECV_OFFSET 7 + +typedef PREPACK struct { + A_UINT8 _HCIRsvd[8]; /* reserved for HCI packet header (GMBOX) testing */ + A_UINT8 StreamEcho_h; /* stream no. to echo this packet on (filled by host) */ + A_UINT8 StreamEchoSent_t; /* stream no. packet was echoed to (filled by target) + When echoed: StreamEchoSent_t == StreamEcho_h */ + A_UINT8 StreamRecv_t; /* stream no. that target received this packet on (filled by target) */ + A_UINT8 StreamNo_h; /* stream number to send on (filled by host) */ + A_UINT8 Magic_h[4]; /* magic number to filter for this packet on the host */ + A_UINT8 _rsvd[6]; /* reserved fields that must be set to a "reserved" value + since this packet maps to a 14-byte ethernet frame we want + to make sure ethertype field is set to something unknown */ + + A_UINT8 _pad[2]; /* padding for alignment */ + A_UINT8 TimeStamp[8]; /* timestamp of packet (host or target) */ + A_UINT32 HostContext_h; /* 4 byte host context, target echos this back */ + A_UINT32 SeqNo; /* sequence number (set by host or target) */ + A_UINT16 Cmd_h; /* ping command (filled by host) */ + A_UINT16 CmdFlags_h; /* optional flags */ + A_UINT8 CmdBuffer_h[8]; /* buffer for command (host -> target) */ + A_UINT8 CmdBuffer_t[8]; /* buffer for command (target -> host) */ + A_UINT16 DataLength; /* length of data */ + A_UINT16 DataCRC; /* 16 bit CRC of data */ + A_UINT16 HeaderCRC; /* header CRC (fields : StreamNo_h to end, minus HeaderCRC) */ +} POSTPACK EPPING_HEADER; + +#define EPPING_PING_MAGIC_0 0xAA +#define EPPING_PING_MAGIC_1 0x55 +#define EPPING_PING_MAGIC_2 0xCE +#define EPPING_PING_MAGIC_3 0xEC + +#define IS_EPPING_PACKET(pPkt) (((pPkt)->Magic_h[0] == EPPING_PING_MAGIC_0) && \ + ((pPkt)->Magic_h[1] == EPPING_PING_MAGIC_1) && \ + ((pPkt)->Magic_h[2] == EPPING_PING_MAGIC_2) && \ + ((pPkt)->Magic_h[3] == EPPING_PING_MAGIC_3)) + +#define SET_EPPING_PACKET_MAGIC(pPkt) { (pPkt)->Magic_h[0] = EPPING_PING_MAGIC_0; \ + (pPkt)->Magic_h[1] = EPPING_PING_MAGIC_1; \ + (pPkt)->Magic_h[2] = EPPING_PING_MAGIC_2; \ + (pPkt)->Magic_h[3] = EPPING_PING_MAGIC_3; } + +#define CMD_FLAGS_DATA_CRC (1 << 0) /* DataCRC field is valid */ +#define CMD_FLAGS_DELAY_ECHO (1 << 1) /* delay the echo of the packet */ +#define CMD_FLAGS_NO_DROP (1 << 2) /* do not drop at HTC layer no matter what the stream is */ + +#define IS_EPING_PACKET_NO_DROP(pPkt) ((pPkt)->CmdFlags_h & CMD_FLAGS_NO_DROP) + +#define EPPING_CMD_ECHO_PACKET 1 /* echo packet test */ +#define EPPING_CMD_RESET_RECV_CNT 2 /* reset recv count */ +#define EPPING_CMD_CAPTURE_RECV_CNT 3 /* fetch recv count, 4-byte count returned in CmdBuffer_t */ +#define EPPING_CMD_NO_ECHO 4 /* non-echo packet test (tx-only) */ +#define EPPING_CMD_CONT_RX_START 5 /* continous RX packets, parameters are in CmdBuffer_h */ +#define EPPING_CMD_CONT_RX_STOP 6 /* stop continuous RX packet transmission */ + +/* test command parameters may be no more than 8 bytes */ +typedef PREPACK struct { + A_UINT16 BurstCnt; /* number of packets to burst together (for HTC 2.1 testing) */ + A_UINT16 PacketLength; /* length of packet to generate including header */ + A_UINT16 Flags; /* flags */ + +#define EPPING_CONT_RX_DATA_CRC (1 << 0) /* Add CRC to all data */ +#define EPPING_CONT_RX_RANDOM_DATA (1 << 1) /* randomize the data pattern */ +#define EPPING_CONT_RX_RANDOM_LEN (1 << 2) /* randomize the packet lengths */ +#define EPPING_CONT_RX_NO_DATA_FILL (1 << 3) /* target will not fill buffers */ + A_UINT16 Context; /* flags */ + +} POSTPACK EPPING_CONT_RX_PARAMS; + +#define EPPING_HDR_CRC_OFFSET A_OFFSETOF(EPPING_HEADER,StreamNo_h) +#define EPPING_HDR_BYTES_CRC (sizeof(EPPING_HEADER) - EPPING_HDR_CRC_OFFSET - (sizeof(A_UINT16))) + +#define HCI_TRANSPORT_STREAM_NUM 16 /* this number is higher than the define WMM AC classes so we + can use this to distinguish packets */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* EPPING_TEST_H */ diff --git a/target/inc/htc.h b/target/inc/htc.h new file mode 100644 index 0000000000..19239abdf3 --- /dev/null +++ b/target/inc/htc.h @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HTC_H__ +#define __HTC_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#undef GET_FIELD +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) +#undef SET_FIELD +#define SET_FIELD(_addr, _f, _val) \ + (*((A_UINT32 *)(_addr) + WO(_f)) = \ + (*((A_UINT32 *)(_addr) + WO(_f)) & ~_f ## _MASK) | SM(_val, _f)) + +#define HTC_GET_FIELD(_msg_buf, _msg_type, _f) \ + GET_FIELD(_msg_buf, _msg_type ## _ ## _f) + +#define HTC_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ + SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) + +#define HTC_WRITE32(_addr, _val) \ + (*(A_UINT32 *)(_addr) = (_val)) + +#ifndef A_OFFSETOF +#define A_OFFSETOF(type,field) (unsigned long)(&(((type *)NULL)->field)) +#endif + +#define ASSEMBLE_UNALIGNED_UINT16(p,highbyte,lowbyte) \ + (((A_UINT16)(((A_UINT8 *)(p))[(highbyte)])) << 8 | (A_UINT16)(((A_UINT8 *)(p))[(lowbyte)])) + +/****** DANGER DANGER *************** + * + * The frame header length and message formats defined herein were + * selected to accommodate optimal alignment for target processing. This reduces code + * size and improves performance. + * + * Any changes to the header length may alter the alignment and cause exceptions + * on the target. When adding to the message structures insure that fields are + * properly aligned. + * + */ + +/* HTC frame header */ +typedef PREPACK struct _HTC_FRAME_HDR { + /* do not remove or re-arrange these fields, these are minimally required + * to take advantage of 4-byte lookaheads in some hardware implementations */ + A_UINT32 EndpointID : 8, Flags : 8, PayloadLen : 16; /* length of data (including trailer) that follows the header */ + + /***** end of 4-byte lookahead ****/ + + A_UINT32 ControlBytes0 : 8,/*used for CRC check if CRC_CHECK flag set*/ + ControlBytes1 : 8, /*used for seq check if SEQ_CHECK flag set*/ + reserved : 16; /*used by bundle processing in SDIO systems*/ + + /* message payload starts after the header */ + +} POSTPACK HTC_FRAME_HDR; + +#define HTC_FRAME_HDR_ENDPOINTID_LSB 0 +#define HTC_FRAME_HDR_ENDPOINTID_MASK 0x000000ff +#define HTC_FRAME_HDR_ENDPOINTID_OFFSET 0x00000000 +#define HTC_FRAME_HDR_FLAGS_LSB 8 +#define HTC_FRAME_HDR_FLAGS_MASK 0x0000ff00 +#define HTC_FRAME_HDR_FLAGS_OFFSET 0x00000000 +#define HTC_FRAME_HDR_PAYLOADLEN_LSB 16 +#define HTC_FRAME_HDR_PAYLOADLEN_MASK 0xffff0000 +#define HTC_FRAME_HDR_PAYLOADLEN_OFFSET 0x00000000 +#define HTC_FRAME_HDR_CONTROLBYTES0_LSB 0 +#define HTC_FRAME_HDR_CONTROLBYTES0_MASK 0x000000ff +#define HTC_FRAME_HDR_CONTROLBYTES0_OFFSET 0x00000004 +#define HTC_FRAME_HDR_CONTROLBYTES1_LSB 8 +#define HTC_FRAME_HDR_CONTROLBYTES1_MASK 0x0000ff00 +#define HTC_FRAME_HDR_CONTROLBYTES1_OFFSET 0x00000004 +#define HTC_FRAME_HDR_RESERVED_LSB 16 +#define HTC_FRAME_HDR_RESERVED_MASK 0xffff0000 +#define HTC_FRAME_HDR_RESERVED_OFFSET 0x00000004 + +/* frame header flags */ + +/* send direction */ +#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) +#define HTC_FLAGS_SEND_BUNDLE (1 << 1) /* start or part of bundle */ +#define HTC_FLAGS_SEQ_CHECK (1 << 2) /* seq check on rx side */ +#define HTC_FLAGS_CRC CHECK (1 << 3) /* CRC check on rx side */ + +/* receive direction */ +#define HTC_FLAGS_RECV_UNUSED_0 (1 << 0) /* bit 0 unused */ +#define HTC_FLAGS_RECV_TRAILER (1 << 1) /* bit 1 trailer data present */ +#define HTC_FLAGS_RECV_UNUSED_2 (1 << 0) /* bit 2 unused */ +#define HTC_FLAGS_RECV_UNUSED_3 (1 << 0) /* bit 3 unused */ +#define HTC_FLAGS_RECV_BUNDLE_CNT_MASK (0xF0) /* bits 7..4 */ +#define HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT 4 + +#define HTC_HDR_LENGTH (sizeof(HTC_FRAME_HDR)) +#define HTC_HDR_ALIGNMENT_PADDING \ + (((sizeof(HTC_FRAME_HDR) + 3) & (~0x3)) - sizeof(HTC_FRAME_HDR)) +#define HTC_MAX_TRAILER_LENGTH 255 +#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(HTC_FRAME_HDR)) + +/* HTC control message IDs */ + +#define HTC_MSG_READY_ID 1 +#define HTC_MSG_CONNECT_SERVICE_ID 2 +#define HTC_MSG_CONNECT_SERVICE_RESPONSE_ID 3 +#define HTC_MSG_SETUP_COMPLETE_ID 4 +#define HTC_MSG_SETUP_COMPLETE_EX_ID 5 +#define HTC_MSG_SEND_SUSPEND_COMPLETE 6 +#define HTC_MSG_NACK_SUSPEND 7 + +#define HTC_MAX_CONTROL_MESSAGE_LENGTH 256 + +/* base message ID header */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; +} POSTPACK HTC_UNKNOWN_MSG; + +#define HTC_UNKNOWN_MSG_MESSAGEID_LSB 0 +#define HTC_UNKNOWN_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_UNKNOWN_MSG_MESSAGEID_OFFSET 0x00000000 + +/* HTC ready message + * direction : target-to-host */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, /* ID */ + CreditCount : 16; /* number of credits the target can offer */ + A_UINT32 CreditSize : 16, /* size of each credit */ + MaxEndpoints : 8, /* maximum number of endpoints the target has resources for */ + _Pad1 : 8; +} POSTPACK HTC_READY_MSG; + +#define HTC_READY_MSG_MESSAGEID_LSB 0 +#define HTC_READY_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_READY_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_READY_MSG_CREDITCOUNT_LSB 16 +#define HTC_READY_MSG_CREDITCOUNT_MASK 0xffff0000 +#define HTC_READY_MSG_CREDITCOUNT_OFFSET 0x00000000 +#define HTC_READY_MSG_CREDITSIZE_LSB 0 +#define HTC_READY_MSG_CREDITSIZE_MASK 0x0000ffff +#define HTC_READY_MSG_CREDITSIZE_OFFSET 0x00000004 +#define HTC_READY_MSG_MAXENDPOINTS_LSB 16 +#define HTC_READY_MSG_MAXENDPOINTS_MASK 0x00ff0000 +#define HTC_READY_MSG_MAXENDPOINTS_OFFSET 0x00000004 + +/* extended HTC ready message */ +typedef PREPACK struct { + HTC_READY_MSG Version2_0_Info; /* legacy version 2.0 information at the front... */ + /* extended information */ + A_UINT32 HTCVersion : 8, MaxMsgsPerHTCBundle : 8, reserved : 16; +} POSTPACK HTC_READY_EX_MSG; + +#define HTC_READY_EX_MSG_HTCVERSION_LSB 0 +#define HTC_READY_EX_MSG_HTCVERSION_MASK 0x000000ff +#define HTC_READY_EX_MSG_HTCVERSION_OFFSET sizeof(HTC_READY_MSG) +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_LSB 8 +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_MASK 0x0000ff00 +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_OFFSET sizeof(HTC_READY_MSG) + +#define HTC_VERSION_2P0 0x00 +#define HTC_VERSION_2P1 0x01 /* HTC 2.1 */ + +#define HTC_SERVICE_META_DATA_MAX_LENGTH 128 + +/* connect service + * direction : host-to-target */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, ServiceID : 16; /* service ID of the service to connect to */ + A_UINT32 ConnectionFlags : 16, /* connection flags */ +#define HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE (1 << 2) + /* reduce credit dribbling when + the host needs credits */ +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK (0x3) +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH 0x0 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF 0x1 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS 0x2 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_UNITY 0x3 + /* disable credit flow control on a specific service */ +#define HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL (1 << 3) + /* enable htc schedule on a specific service */ +#define HTC_CONNECT_FLAGS_ENABLE_HTC_SCHEDULE (1 << 4) + ServiceMetaLength : 8, /* length of meta data that follows */ + _Pad1 : 8; + + /* service-specific meta data starts after the header */ + +} POSTPACK HTC_CONNECT_SERVICE_MSG; + +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_LSB 0 +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_LSB 16 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_LSB 0 +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_LSB 16 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_MASK 0x00ff0000 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_OFFSET 0x00000004 + +#define HTC_SET_RECV_ALLOC_SHIFT 8 +#define HTC_SET_RECV_ALLOC_MASK 0xFF00 +#define HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(value) (((A_UINT8)value) << HTC_SET_RECV_ALLOC_SHIFT) +#define HTC_CONNECT_FLAGS_GET_RECV_ALLOCATION(value) (A_UINT8)(((value) & HTC_SET_RECV_ALLOC_MASK) >> HTC_SET_RECV_ALLOC_SHIFT) + +/* connect response + * direction : target-to-host */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, ServiceID : 16; /* service ID that the connection request was made */ + A_UINT32 Status : 8, /* service connection status */ + EndpointID : 8, /* assigned endpoint ID */ + MaxMsgSize : 16; /* maximum expected message size on this endpoint */ + A_UINT32 ServiceMetaLength : 8, /* length of meta data that follows */ + _Pad1 : 8, reserved : 16; + + /* service-specific meta data starts after the header */ + +} POSTPACK HTC_CONNECT_SERVICE_RESPONSE_MSG; + +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_LSB 16 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_MASK 0x000000ff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_LSB 8 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_MASK 0x0000ff00 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_LSB 16 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_MASK 0x000000ff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_OFFSET 0x00000008 + +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; + /* currently, no other fields */ +} POSTPACK HTC_SETUP_COMPLETE_MSG; + +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_LSB 0 +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_OFFSET 0x00000000 + +/* extended setup completion message */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; + A_UINT32 SetupFlags : 32; + A_UINT32 MaxMsgsPerBundledRecv : 8, Rsvd0 : 8, Rsvd1 : 8, Rsvd2 : 8; +} POSTPACK HTC_SETUP_COMPLETE_EX_MSG; + +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_MASK 0xffffffff +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_OFFSET 0x00000004 +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_MASK 0x000000ff +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_LSB 8 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_MASK 0x0000ff00 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_LSB 16 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_MASK 0x00ff0000 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_LSB 24 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_MASK 0xff000000 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_OFFSET 0x00000008 + +#define HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV (1 << 0) /* enable recv bundling from target */ +#define HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW (1 << 1) /* disable credit based flow control, + only supported on some interconnects */ + +/* connect response status codes */ +#define HTC_SERVICE_SUCCESS 0 /* success */ +#define HTC_SERVICE_NOT_FOUND 1 /* service could not be found */ +#define HTC_SERVICE_FAILED 2 /* specific service failed the connect */ +#define HTC_SERVICE_NO_RESOURCES 3 /* no resources (i.e. no more endpoints) */ +#define HTC_SERVICE_NO_MORE_EP 4 /* specific service is not allowing any more + endpoints */ + +/* report record IDs */ + +#define HTC_RECORD_NULL 0 +#define HTC_RECORD_CREDITS 1 +#define HTC_RECORD_LOOKAHEAD 2 +#define HTC_RECORD_LOOKAHEAD_BUNDLE 3 + +typedef PREPACK struct { + A_UINT32 RecordID : 8, /* Record ID */ + Length : 8, /* Length of record */ + reserved : 16; +} POSTPACK HTC_RECORD_HDR; + +#define HTC_RECORD_HDR_RECORDID_LSB 0 +#define HTC_RECORD_HDR_RECORDID_MASK 0x000000ff +#define HTC_RECORD_HDR_RECORDID_OFFSET 0x00000000 +#define HTC_RECORD_HDR_LENGTH_LSB 8 +#define HTC_RECORD_HDR_LENGTH_MASK 0x0000ff00 +#define HTC_RECORD_HDR_LENGTH_OFFSET 0x00000000 + +typedef PREPACK struct { + A_UINT32 EndpointID : 8, /* Endpoint that owns these credits */ + Credits : 8, /* credits to report since last report */ + reserved : 16; +} POSTPACK HTC_CREDIT_REPORT; + +#define HTC_CREDIT_REPORT_ENDPOINTID_LSB 0 +#define HTC_CREDIT_REPORT_ENDPOINTID_MASK 0x000000ff +#define HTC_CREDIT_REPORT_ENDPOINTID_OFFSET 0x00000000 +#define HTC_CREDIT_REPORT_CREDITS_LSB 8 +#define HTC_CREDIT_REPORT_CREDITS_MASK 0x0000ff00 +#define HTC_CREDIT_REPORT_CREDITS_OFFSET 0x00000000 + +typedef PREPACK struct { + A_UINT32 PreValid : 8, /* pre valid guard */ + reserved0 : 24; + A_UINT32 LookAhead0 : 8, /* 4 byte lookahead */ + LookAhead1 : 8, LookAhead2 : 8, LookAhead3 : 8; + A_UINT32 PostValid : 8, /* post valid guard */ + reserved1 : 24; + + /* NOTE: the LookAhead array is guarded by a PreValid and Post Valid guard bytes. + * The PreValid bytes must equal the inverse of the PostValid byte */ + +} POSTPACK HTC_LOOKAHEAD_REPORT; + +#define HTC_LOOKAHEAD_REPORT_PREVALID_LSB 0 +#define HTC_LOOKAHEAD_REPORT_PREVALID_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_PREVALID_OFFSET 0x00000000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_LSB 0 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_LSB 8 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_MASK 0x0000ff00 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_LSB 16 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_MASK 0x00ff0000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_LSB 24 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_MASK 0xff000000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_POSTVALID_LSB 0 +#define HTC_LOOKAHEAD_REPORT_POSTVALID_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_POSTVALID_OFFSET 0x00000008 + +typedef PREPACK struct { + A_UINT32 LookAhead0 : 8, /* 4 byte lookahead */ + LookAhead1 : 8, LookAhead2 : 8, LookAhead3 : 8; +} POSTPACK HTC_BUNDLED_LOOKAHEAD_REPORT; + +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_LSB 0 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_MASK 0x000000ff +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_LSB 8 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_MASK 0x0000ff00 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_LSB 16 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_MASK 0x00ff0000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_LSB 24 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_MASK 0xff000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_OFFSET 0x00000000 + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* __HTC_H__ */ diff --git a/target/inc/htc_services.h b/target/inc/htc_services.h new file mode 100644 index 0000000000..bd43772ac5 --- /dev/null +++ b/target/inc/htc_services.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HTC_SERVICES_H__ +#define __HTC_SERVICES_H__ + +/* Current service IDs */ + +typedef enum { + RSVD_SERVICE_GROUP = 0, + WMI_SERVICE_GROUP = 1, + NMI_SERVICE_GROUP = 2, + HTT_SERVICE_GROUP = 3, + CFG_NV_SERVICE_GROUP = 4, + WDI_IPA_SERVICE_GROUP = 5, + HTC_TEST_GROUP = 254, + HTC_SERVICE_GROUP_LAST = 255 +} HTC_SERVICE_GROUP_IDS; + +#define MAKE_SERVICE_ID(group,index) \ + (int)(((int)group << 8) | (int)(index)) + +/* NOTE: service ID of 0x0000 is reserved and should never be used */ +#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP,1) +#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,0) +#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,1) +#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,2) +#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,3) +#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,4) +#define WMI_MAX_SERVICES 5 + +#define NMI_CONTROL_SVC MAKE_SERVICE_ID(NMI_SERVICE_GROUP,0) +#define NMI_DATA_SVC MAKE_SERVICE_ID(NMI_SERVICE_GROUP,1) + +#define HTT_DATA_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,0) +#define HTT_DATA2_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,1) + +/* raw stream service (i.e. flash, tcmd, calibration apps) */ +#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0) + +#define CFG_NV_SVC MAKE_SERVICE_ID(CFG_NV_SERVICE_GROUP,0) +#define WDI_IPA_TX_SVC MAKE_SERVICE_ID(WDI_IPA_SERVICE_GROUP,0) + +/* + * Directions for interconnect pipe configuration. + * These definitions may be used during configuration and are shared + * between Host and Target. + * + * Pipe Directions are relative to the Host, so PIPEDIR_IN means + * "coming IN over air through Target to Host" as with a WiFi Rx operation. + * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" + * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" + * Target since things that are "PIPEDIR_OUT" are coming IN to the Target + * over the interconnect. + */ +typedef A_UINT32 PIPEDIR; +#define PIPEDIR_NONE 0 +#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ +#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ +#define PIPEDIR_INOUT 3 /* bidirectional - target to target */ +#define PIPEDIR_INOUT_H2H 4 /* bidirectional - host to host */ +#define PIPEDIR_MATCH(d1, d2) (((PIPEDIR)(d1) & (PIPEDIR)(d2)) != 0) + +/* Establish a mapping between a service/direction and a pipe. */ +struct service_to_pipe { + A_UINT32 service_id; + A_UINT32 pipedir; + A_UINT32 pipenum; +}; + +#endif /*HTC_SERVICES_H_ */ diff --git a/target/inc/htt.h b/target/inc/htt.h new file mode 100644 index 0000000000..d9a081e636 --- /dev/null +++ b/target/inc/htt.h @@ -0,0 +1,7034 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt.h + * + * @details the public header file of HTT layer + */ + +#ifndef _HTT_H_ +#define _HTT_H_ + +#include /* A_UINT32 */ +#include /* PREPACK, POSTPACK */ +#ifdef ATHR_WIN_NWF +#pragma warning(disable:4214) /*bit field types other than int */ +#endif +#include "wlan_defs.h" +#include + +/* + * Unless explicitly specified to use 64 bits to represent physical addresses + * (or more precisely, bus addresses), default to 32 bits. + */ +#ifndef HTT_PADDR64 +#define HTT_PADDR64 0 +#endif + +#ifndef offsetof +#define offsetof(type, field) ((unsigned int)(&((type *)0)->field)) +#endif + +/* + * HTT version history: + * 1.0 initial numbered version + * 1.1 modifications to STATS messages. + * These modifications are not backwards compatible, but since the + * STATS messages themselves are non-essential (they are for debugging), + * the 1.1 version of the HTT message library as a whole is compatible + * with the 1.0 version. + * 1.2 reset mask IE added to STATS_REQ message + * 1.3 stat config IE added to STATS_REQ message + *---- + * 2.0 FW rx PPDU desc added to RX_IND message + * 2.1 Enable msdu_ext/frag_desc banking change for WIFI2.0 + *---- + * 3.0 Remove HTT_H2T_MSG_TYPE_MGMT_TX message + * 3.1 Added HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND message + * 3.2 Added HTT_H2T_MSG_TYPE_WDI_IPA_CFG, + * HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQUEST messages + * 3.3 Added HTT_H2T_MSG_TYPE_AGGR_CFG_EX message + * 3.4 Added tx_compl_req flag in HTT tx descriptor + * 3.5 Added flush and fail stats in rx_reorder stats structure + * 3.6 Added frag flag in HTT RX INORDER PADDR IND header + * 3.7 Made changes to support EOS Mac_core 3.0 + * 3.8 Added txq_group information element definition; + * added optional txq_group suffix to TX_CREDIT_UPDATE_IND message + * 3.9 Added HTT_T2H CHAN_CHANGE message; + * Allow buffer addresses in bus-address format to be stored as + * either 32 bits or 64 bits. + * 3.10 Add optional TLV extensions to the VERSION_REQ and VERSION_CONF + * messages to specify which HTT options to use. + * Initial TLV options cover: + * - whether to use 32 or 64 bits to represent LL bus addresses + * - whether to use TX_COMPL_IND or TX_CREDIT_UPDATE_IND in HL systems + * - how many tx queue groups to use + * 3.11 Expand rx debug stats: + * - Expand the rx_reorder_stats struct with stats about successful and + * failed rx buffer allcoations. + * - Add a new rx_remote_buffer_mgmt_stats struct with stats about + * the supply, allocation, use, and recycling of rx buffers for the + * "remote ring" of rx buffers in host member in LL systems. + * Add RX_REMOTE_RING_BUFFER_INFO stats type for uploading these stats. + * 3.12 Add "rx offload packet error" message with initial "MIC error" subtype + * 3.13 Add constants + macros to support 64-bit address format for the + * tx fragments descriptor, the rx ring buffer, and the rx ring + * index shadow register. + * 3.14 Add a method for the host to provide detailed per-frame tx specs: + * - Add htt_tx_msdu_desc_ext_t struct def. + * - Add TLV to specify whether the target supports the HTT tx MSDU + * extension descriptor. + * - Change a reserved bit in the HTT tx MSDU descriptor to an + * "extension" bit, to specify whether a HTT tx MSDU extension + * descriptor is present. + * 3.15 Add HW rx desc info to per-MSDU info elems in RX_IN_ORD_PADDR_IND msg. + * (This allows the host to obtain key information about the MSDU + * from a memory location already in the cache, rather than taking a + * cache miss for each MSDU by reading the HW rx descs.) + * 3.16 Add htt_pkt_type_eth2 and define pkt_subtype flags to indicate + * whether a copy-engine classification result is appended to TX_FRM. + * 3.17 Add a version of the WDI_IPA_CFG message; add RX_RING2 to WDI_IPA_CFG + * 3.18 Add a PEER_DEL tx completion indication status, for HL cleanup of + * tx frames in the target after the peer has already been deleted. + * 3.19 Add HTT_DBG_STATS_RX_RATE_INFO_V2 and HTT_DBG_STATS_TX_RATE_INFO_V2 + * 3.20 Expand rx_reorder_stats. + * 3.21 Add optional rx channel spec to HL RX_IND. + * 3.22 Expand rx_reorder_stats + * (distinguish duplicates within vs. outside block ack window) + * 3.23 Add HTT_T2H_MSG_TYPE_RATE_REPORT to report peer justified rate. + * The justified rate is calculated by two steps. The first is to multiply + * user-rate by (1 - PER) and the other is to smooth the step 1's result + * by a low pass filter. + * This change allows HL download scheduling to consider the WLAN rate + * that will be used for transmitting the downloaded frames. + * 3.24 Expand rx_reorder_stats + * (add counter for decrypt / MIC errors) + * 3.25 Expand rx_reorder_stats + * (add counter of frames received into both local + remote rings) + * 3.26 Add stats struct for counting rx of tx BF, MU, SU, and NDPA frames + * (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT, rx_txbf_musu_ndpa_pkts_stats) + * 3.27 Add a new interface for flow-control. The following t2h messages have + * been included: HTT_T2H_MSG_TYPE_FLOW_POOL_MAP and + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + */ +#define HTT_CURRENT_VERSION_MAJOR 3 +#define HTT_CURRENT_VERSION_MINOR 27 + +#define HTT_NUM_TX_FRAG_DESC 1024 + +#define HTT_WIFI_IP_VERSION(x, y) ((x) == (y)) + +#define HTT_CHECK_SET_VAL(field, val) \ + A_ASSERT(!((val) & ~((field ## _M) >> (field ## _S)))) + +/* macros to assist in sign-extending fields from HTT messages */ +#define HTT_SIGN_BIT_MASK(field) \ + ((field ## _M + (1 << field ## _S)) >> 1) + #define HTT_SIGN_BIT(_val, field) \ + (_val & HTT_SIGN_BIT_MASK(field)) + #define HTT_SIGN_BIT_UNSHIFTED(_val, field) \ + (HTT_SIGN_BIT(_val, field) >> field ## _S) + #define HTT_SIGN_BIT_UNSHIFTED_MINUS_ONE(_val, field) \ + (HTT_SIGN_BIT_UNSHIFTED(_val, field) - 1) + #define HTT_SIGN_BIT_EXTENSION(_val, field) \ + (~(HTT_SIGN_BIT_UNSHIFTED(_val, field) | \ + HTT_SIGN_BIT_UNSHIFTED_MINUS_ONE(_val, field))) + #define HTT_SIGN_BIT_EXTENSION_MASK(_val, field) \ + (HTT_SIGN_BIT_EXTENSION(_val, field) & ~(field ## _M >> field ## _S)) + + +/* + * TEMPORARY: + * Provide HTT_H2T_MSG_TYPE_MGMT_TX as an alias for + * DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX until all code + * that refers to HTT_H2T_MSG_TYPE_MGMT_TX has been + * updated. + */ +#define HTT_H2T_MSG_TYPE_MGMT_TX DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX + +/* + * TEMPORARY: + * Provide HTT_T2H_MSG_TYPE_RC_UPDATE_IND as an alias for + * DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND until all code + * that refers to HTT_T2H_MSG_TYPE_RC_UPDATE_IND has been + * updated. + */ +#define HTT_T2H_MSG_TYPE_RC_UPDATE_IND DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND + +/* HTT Access Category values */ +enum HTT_AC_WMM { + /* WMM Access Categories */ + HTT_AC_WMM_BE = 0x0, + HTT_AC_WMM_BK = 0x1, + HTT_AC_WMM_VI = 0x2, + HTT_AC_WMM_VO = 0x3, + /* extension Access Categories */ + HTT_AC_EXT_NON_QOS = 0x4, + HTT_AC_EXT_UCAST_MGMT = 0x5, + HTT_AC_EXT_MCAST_DATA = 0x6, + HTT_AC_EXT_MCAST_MGMT = 0x7, +}; +enum HTT_AC_WMM_MASK { + /* WMM Access Categories */ + HTT_AC_WMM_BE_MASK = (1 << HTT_AC_WMM_BE), + HTT_AC_WMM_BK_MASK = (1 << HTT_AC_WMM_BK), + HTT_AC_WMM_VI_MASK = (1 << HTT_AC_WMM_VI), + HTT_AC_WMM_VO_MASK = (1 << HTT_AC_WMM_VO), + /* extension Access Categories */ + HTT_AC_EXT_NON_QOS_MASK = (1 << HTT_AC_EXT_NON_QOS), + HTT_AC_EXT_UCAST_MGMT_MASK = (1 << HTT_AC_EXT_UCAST_MGMT), + HTT_AC_EXT_MCAST_DATA_MASK = (1 << HTT_AC_EXT_MCAST_DATA), + HTT_AC_EXT_MCAST_MGMT_MASK = (1 << HTT_AC_EXT_MCAST_MGMT), +}; +#define HTT_AC_MASK_WMM \ + (HTT_AC_WMM_BE_MASK | HTT_AC_WMM_BK_MASK | \ + HTT_AC_WMM_VI_MASK | HTT_AC_WMM_VO_MASK) +#define HTT_AC_MASK_EXT \ + (HTT_AC_EXT_NON_QOS_MASK | HTT_AC_EXT_UCAST_MGMT_MASK | \ + HTT_AC_EXT_MCAST_DATA_MASK | HTT_AC_EXT_MCAST_MGMT_MASK) +#define HTT_AC_MASK_ALL (HTT_AC_MASK_WMM | HTT_AC_MASK_EXT) + +/* + * htt_dbg_stats_type - + * bit positions for each stats type within a stats type bitmask + * The bitmask contains 24 bits. + */ +enum htt_dbg_stats_type { + HTT_DBG_STATS_WAL_PDEV_TXRX = 0, /* bit 0 -> 0x1 */ + HTT_DBG_STATS_RX_REORDER = 1, /* bit 1 -> 0x2 */ + HTT_DBG_STATS_RX_RATE_INFO = 2, /* bit 2 -> 0x4 */ + HTT_DBG_STATS_TX_PPDU_LOG = 3, /* bit 3 -> 0x8 */ + HTT_DBG_STATS_TX_RATE_INFO = 4, /* bit 4 -> 0x10 */ + HTT_DBG_STATS_TIDQ = 5, /* bit 5 -> 0x20 */ + HTT_DBG_STATS_TXBF_INFO = 6, /* bit 6 -> 0x40 */ + HTT_DBG_STATS_SND_INFO = 7, /* bit 7 -> 0x80 */ + HTT_DBG_STATS_ERROR_INFO = 8, /* bit 8 -> 0x100 */ + HTT_DBG_STATS_TX_SELFGEN_INFO = 9, /* bit 9 -> 0x200 */ + HTT_DBG_STATS_TX_MU_INFO = 10, /* bit 10 -> 0x400 */ + HTT_DBG_STATS_SIFS_RESP_INFO = 11, /* bit 11 -> 0x800 */ + HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO = 12, /* bit 12 -> 0x1000 */ + HTT_DBG_STATS_RX_RATE_INFO_V2 = 13, /* bit 13 -> 0x2000 */ + HTT_DBG_STATS_TX_RATE_INFO_V2 = 14, /* bit 14 -> 0x4000 */ + HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT = 15, /* bit 15 -> 0x8000 */ + /* bits 16-23 currently reserved */ + + /* keep this last */ + HTT_DBG_NUM_STATS +}; + +/*=== HTT option selection TLVs === + * Certain HTT messages have alternatives or options. + * For such cases, the host and target need to agree on which option to use. + * Option specification TLVs can be appended to the VERSION_REQ and + * VERSION_CONF messages to select options other than the default. + * These TLVs are entirely optional - if they are not provided, there is a + * well-defined default for each option. If they are provided, they can be + * provided in any order. Each TLV can be present or absent independent of + * the presence / absence of other TLVs. + * + * The HTT option selection TLVs use the following format: + * |31 16|15 8|7 0| + * |---------------------------------+----------------+----------------| + * | value (payload) | length | tag | + * |-------------------------------------------------------------------| + * The value portion need not be only 2 bytes; it can be extended by any + * integer number of 4-byte units. The total length of the TLV, including + * the tag and length fields, must be a multiple of 4 bytes. The length + * field specifies the total TLV size in 4-byte units. Thus, the typical + * TLV, with a 1-byte tag field, a 1-byte length field, and a 2-byte value + * field, would store 0x1 in its length field, to show that the TLV occupies + * a single 4-byte unit. + */ + +/*--- TLV header format - applies to all HTT option TLVs ---*/ + +enum HTT_OPTION_TLV_TAGS { + HTT_OPTION_TLV_TAG_RESERVED0 = 0x0, + HTT_OPTION_TLV_TAG_LL_BUS_ADDR_SIZE = 0x1, + HTT_OPTION_TLV_TAG_HL_SUPPRESS_TX_COMPL_IND = 0x2, + HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS = 0x3, + HTT_OPTION_TLV_TAG_SUPPORT_TX_MSDU_DESC_EXT = 0x4, +}; + +PREPACK struct htt_option_tlv_header_t { + A_UINT8 tag; + A_UINT8 length; +} POSTPACK; + +#define HTT_OPTION_TLV_TAG_M 0x000000ff +#define HTT_OPTION_TLV_TAG_S 0 +#define HTT_OPTION_TLV_LENGTH_M 0x0000ff00 +#define HTT_OPTION_TLV_LENGTH_S 8 +/* + * value0 - 16 bit value field stored in word0 + * The TLV's value field may be longer than 2 bytes, in which case + * the remainder of the value is stored in word1, word2, etc. + */ +#define HTT_OPTION_TLV_VALUE0_M 0xffff0000 +#define HTT_OPTION_TLV_VALUE0_S 16 + +#define HTT_OPTION_TLV_TAG_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_TAG, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_TAG_S); \ + } while (0) +#define HTT_OPTION_TLV_TAG_GET(word) \ + (((word) & HTT_OPTION_TLV_TAG_M) >> HTT_OPTION_TLV_TAG_S) + +#define HTT_OPTION_TLV_LENGTH_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_LENGTH, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_LENGTH_S); \ + } while (0) +#define HTT_OPTION_TLV_LENGTH_GET(word) \ + (((word) & HTT_OPTION_TLV_LENGTH_M) >> HTT_OPTION_TLV_LENGTH_S) + +#define HTT_OPTION_TLV_VALUE0_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_VALUE0, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_VALUE0_S); \ + } while (0) +#define HTT_OPTION_TLV_VALUE0_GET(word) \ + (((word) & HTT_OPTION_TLV_VALUE0_M) >> HTT_OPTION_TLV_VALUE0_S) + +/*--- format of specific HTT option TLVs ---*/ + +/* + * HTT option TLV for specifying LL bus address size + * Some chips require bus addresses used by the target to access buffers + * within the host's memory to be 32 bits; others require bus addresses + * used by the target to access buffers within the host's memory to be + * 64 bits. + * The LL_BUS_ADDR_SIZE TLV can be sent from the target to the host as + * a suffix to the VERSION_CONF message to specify which bus address format + * the target requires. + * If this LL_BUS_ADDR_SIZE TLV is not sent by the target, the host should + * default to providing bus addresses to the target in 32-bit format. + */ +enum HTT_OPTION_TLV_LL_BUS_ADDR_SIZE_VALUES { + HTT_OPTION_TLV_LL_BUS_ADDR_SIZE32 = 0x0, + HTT_OPTION_TLV_LL_BUS_ADDR_SIZE64 = 0x1, +}; +PREPACK struct htt_option_tlv_ll_bus_addr_size_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 ll_bus_addr_size; /* LL_BUS_ADDR_SIZE_VALUES enum */ +} POSTPACK; + +/* + * HTT option TLV for specifying whether HL systems should indicate + * over-the-air tx completion for individual frames, or should instead + * send a bulk TX_CREDIT_UPDATE_IND except when the host explicitly + * requests an OTA tx completion for a particular tx frame. + * This option does not apply to LL systems, where the TX_COMPL_IND + * is mandatory. + * This option is primarily intended for HL systems in which the tx frame + * downloads over the host --> target bus are as slow as or slower than + * the transmissions over the WLAN PHY. For cases where the bus is faster + * than the WLAN PHY, the target will transmit relatively large A-MPDUs, + * and consquently will send one TX_COMPL_IND message that covers several + * tx frames. For cases where the WLAN PHY is faster than the bus, + * the target will end up transmitting very short A-MPDUs, and consequently + * sending many TX_COMPL_IND messages, which each cover a very small number + * of tx frames. + * The HL_SUPPRESS_TX_COMPL_IND TLV can be sent by the host to the target as + * a suffix to the VERSION_REQ message to request whether the host desires to + * use TX_CREDIT_UPDATE_IND rather than TX_COMPL_IND. The target can then + * send a HTT_SUPPRESS_TX_COMPL_IND TLV to the host as a suffix to the + * VERSION_CONF message to confirm whether TX_CREDIT_UPDATE_IND will be used + * rather than TX_COMPL_IND. TX_CREDIT_UPDATE_IND shall only be used if the + * host sends a HL_SUPPRESS_TX_COMPL_IND TLV requesting use of + * TX_CREDIT_UPDATE_IND, and the target sends a HL_SUPPRESS_TX_COMPLE_IND TLV + * back to the host confirming use of TX_CREDIT_UPDATE_IND. + * Lack of a HL_SUPPRESS_TX_COMPL_IND TLV from either host --> target or + * target --> host is equivalent to a HL_SUPPRESS_TX_COMPL_IND that + * explicitly specifies HL_ALLOW_TX_COMPL_IND in the value payload of the + * TLV. + */ +enum HTT_OPTION_TLV_HL_SUPPRESS_TX_COMPL_IND_VALUES { + HTT_OPTION_TLV_HL_ALLOW_TX_COMPL_IND = 0x0, + HTT_OPTION_TLV_HL_SUPPRESS_TX_COMPL_IND = 0x1, +}; +PREPACK struct htt_option_tlv_hl_suppress_tx_compl_ind_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 hl_suppress_tx_compl_ind;/*HL_SUPPRESS_TX_COMPL_IND enum*/ +} POSTPACK; + +/* + * HTT option TLV for specifying how many tx queue groups the target + * may establish. + * This TLV specifies the maximum value the target may send in the + * txq_group_id field of any TXQ_GROUP information elements sent by + * the target to the host. This allows the host to pre-allocate an + * appropriate number of tx queue group structs. + * + * The MAX_TX_QUEUE_GROUPS_TLV can be sent from the host to the target as + * a suffix to the VERSION_REQ message to specify whether the host supports + * tx queue groups at all, and if so if there is any limit on the number of + * tx queue groups that the host supports. + * The MAX_TX_QUEUE_GROUPS TLV can be sent from the target to the host as + * a suffix to the VERSION_CONF message. If the host has specified in the + * VER_REQ message a limit on the number of tx queue groups the host can + * supprt, the target shall limit its specification of the maximum tx groups + * to be no larger than this host-specified limit. + * + * If the target does not provide a MAX_TX_QUEUE_GROUPS TLV, then the host + * shall preallocate 4 tx queue group structs, and the target shall not + * specify a txq_group_id larger than 3. + */ +enum HTT_OPTION_TLV_MAX_TX_QUEUE_GROUPS_VALUES { + HTT_OPTION_TLV_TX_QUEUE_GROUPS_UNSUPPORTED = 0, + /* + * values 1 through N specify the max number of tx queue groups + * the sender supports + */ + HTT_OPTION_TLV_TX_QUEUE_GROUPS_UNLIMITED = 0xffff, +}; +/* TEMPORARY backwards-compatibility alias for a typo fix - + * The htt_option_tlv_mac_tx_queue_groups_t typo has been corrected + * to htt_option_tlv_max_tx_queue_groups_t, but an alias is provided + * to support the old name (with the typo) until all references to the + * old name are replaced with the new name. + */ +#define htt_option_tlv_mac_tx_queue_groups_t \ + htt_option_tlv_max_tx_queue_groups_t +PREPACK struct htt_option_tlv_max_tx_queue_groups_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 max_tx_queue_groups; /* max txq_group_id + 1 */ +} POSTPACK; + +/* + * HTT option TLV for specifying whether the target supports an extended + * version of the HTT tx descriptor. If the target provides this TLV + * and specifies in the TLV that the target supports an extended version + * of the HTT tx descriptor, the target must check the "extension" bit in + * the HTT tx descriptor, and if the extension bit is set, to expect a + * HTT tx MSDU extension descriptor immediately following the HTT tx MSDU + * descriptor. Furthermore, the target must provide room for the HTT + * tx MSDU extension descriptor in the target's TX_FRM buffer. + * This option is intended for systems where the host needs to explicitly + * control the transmission parameters such as tx power for individual + * tx frames. + * The SUPPORT_TX_MSDU_DESC_EXT TLB can be sent by the target to the host + * as a suffix to the VERSION_CONF message to explicitly specify whether + * the target supports the HTT tx MSDU extension descriptor. + * Lack of a SUPPORT_TX_MSDU_DESC_EXT from the target shall be interpreted + * by the host as lack of target support for the HTT tx MSDU extension + * descriptor; the host shall provide HTT tx MSDU extension descriptors in + * the HTT_H2T TX_FRM messages only if the target indicates it supports + * the HTT tx MSDU extension descriptor. + * The host is not required to provide the HTT tx MSDU extension descriptor + * just because the target supports it; the target must check the + * "extension" bit in the HTT tx MSDU descriptor to determine whether an + * extension descriptor is present. + */ +enum HTT_OPTION_TLV_SUPPORT_TX_MSDU_DESC_EXT_VALUES { + HTT_OPTION_TLV_TX_MSDU_DESC_EXT_NO_SUPPORT = 0x0, + HTT_OPTION_TLV_TX_MSDU_DESC_EXT_SUPPORT = 0x1, +}; +PREPACK struct htt_option_tlv_support_tx_msdu_desc_ext_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 tx_msdu_desc_ext_support;/*SUPPORT_TX_MSDU_DESC_EXT enum*/ +} POSTPACK; + + +/*=== host -> target messages ===============================================*/ + +enum htt_h2t_msg_type { + HTT_H2T_MSG_TYPE_VERSION_REQ = 0x0, + HTT_H2T_MSG_TYPE_TX_FRM = 0x1, + HTT_H2T_MSG_TYPE_RX_RING_CFG = 0x2, + HTT_H2T_MSG_TYPE_STATS_REQ = 0x3, + HTT_H2T_MSG_TYPE_SYNC = 0x4, + HTT_H2T_MSG_TYPE_AGGR_CFG = 0x5, + HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 0x6, + DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX = 0x7, /* no longer used */ + HTT_H2T_MSG_TYPE_WDI_IPA_CFG = 0x8, + HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ = 0x9, + HTT_H2T_MSG_TYPE_AGGR_CFG_EX = 0xa, /*per vdev amsdu subfrm limit*/ + /* keep this last */ + HTT_H2T_NUM_MSGS +}; + +/* + * HTT host to target message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_H2T_MSG_TYPE_M 0xff +#define HTT_H2T_MSG_TYPE_S 0 + +#define HTT_H2T_MSG_TYPE_SET(word, msg_type) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE, msg_type); \ + (word) |= ((msg_type) << HTT_H2T_MSG_TYPE_S); \ + } while (0) +#define HTT_H2T_MSG_TYPE_GET(word) \ + (((word) & HTT_H2T_MSG_TYPE_M) >> HTT_H2T_MSG_TYPE_S) + +/** + * @brief target -> host version number request message definition + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | msg type | + * |-------------------------------------------------------------------| + * : option request TLV (optional) | + * :...................................................................: + * + * The VER_REQ message may consist of a single 4-byte word, or may be + * extended with TLVs that specify which HTT options the host is requesting + * from the target. + * The following option TLVs may be appended to the VER_REQ message: + * - HL_SUPPRESS_TX_COMPL_IND + * - HL_MAX_TX_QUEUE_GROUPS + * These TLVs may appear in an arbitrary order. Any number of these TLVs + * may be appended to the VER_REQ message (but only one TLV of each type). + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a version number request message + * Value: 0x0 + */ + +#define HTT_VER_REQ_BYTES 4 + +/* TBDXXX: figure out a reasonable number */ +#define HTT_HL_DATA_SVC_PIPE_DEPTH 24 +#define HTT_LL_DATA_SVC_PIPE_DEPTH 64 + +/** + * @brief HTT tx MSDU descriptor + * + * @details + * The HTT tx MSDU descriptor is created by the host HTT SW for each + * tx MSDU. The HTT tx MSDU descriptor contains the information that + * the target firmware needs for the FW's tx processing, particularly + * for creating the HW msdu descriptor. + * The same HTT tx descriptor is used for HL and LL systems, though + * a few fields within the tx descriptor are used only by LL or + * only by HL. + * The HTT tx descriptor is defined in two manners: by a struct with + * bitfields, and by a series of [dword offset, bit mask, bit shift] + * definitions. + * The target should use the struct def, for simplicitly and clarity, + * but the host shall use the bit-mast + bit-shift defs, to be endian- + * neutral. Specifically, the host shall use the get/set macros built + * around the mask + shift defs. + */ +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_80211_HDR_S 0 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_80211_HDR_M 0x1 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_S 1 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_M 0x2 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S 2 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_M 0x4 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_CLASSIFY_S 3 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_CLASSIFY_M 0x8 + +#define HTT_TX_VDEV_ID_WORD 0 +#define HTT_TX_VDEV_ID_MASK 0x3f +#define HTT_TX_VDEV_ID_SHIFT 16 + +#define HTT_TX_L3_CKSUM_OFFLOAD 1 +#define HTT_TX_L4_CKSUM_OFFLOAD 2 + +#define HTT_TX_MSDU_LEN_DWORD 1 +#define HTT_TX_MSDU_LEN_MASK 0xffff; + +/* + * HTT_VAR_PADDR macros + * Allow physical / bus addresses to be either a single 32-bit value, + * or a 64-bit value, stored as a little-endian lo,hi pair of 32-bit parts + */ + +/* + * Note that in this macro A_UINT32 has been converted to + * uint32_t only to address checkpath errors caused by declaring + * var_name as A_UINT32. + */ +#define HTT_VAR_PADDR32(var_name) uint32_t (var_name) + +#define HTT_VAR_PADDR64_LE(var_name) \ + struct { \ + /* little-endian: lo precedes hi */ \ + A_UINT32 lo; \ + A_UINT32 hi; \ + } var_name + +/* + * TEMPLATE_HTT_TX_MSDU_DESC_T: + * This macro defines a htt_tx_msdu_descXXX_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_tx_msdu_desc32_t and + * htt_tx_msdu_desc64_t structs. + */ +#define TEMPLATE_HTT_TX_MSDU_DESC_T(_paddr_bits_, _paddr__frags_desc_ptr_) \ +PREPACK struct htt_tx_msdu_desc ## _paddr_bits_ ## _t \ +{ \ + /* DWORD 0: flags and meta-data */ \ + A_UINT32 \ + msg_type:8, /* HTT_H2T_MSG_TYPE_TX_FRM */ \ + \ + /* pkt_subtype - \ + * Detailed specification of the tx frame contents, extending the \ + * general specification provided by pkt_type. \ + * FIX THIS: ADD COMPLETE SPECS FOR THIS FIELDS VALUE, e.g. \ + *pkt_type | pkt_subtype \ + *============================================================== \ + *802.3 | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message in the \ + * | format: \ + * | [HTT tx desc, frame header, \ + * | CE classification results] \ + * | The CE classification results begin \ + * | at the next 4-byte boundary after \ + * | the frame header. \ + *------------+------------------------------------------------- \ + *Eth2 | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + *------------+------------------------------------------------- \ + *native WiFi | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + *------------+------------------------------------------------- \ + *mgmt | 0x0 - 802.11 MAC header absent \ + * | 0x1 - 802.11 MAC header present \ + *------------+------------------------------------------------- \ + *raw | bit 0: 0x0 - 802.11 MAC header absent \ + * | 0x1 - 802.11 MAC header present \ + * | bit 1: 0x0 - allow aggregation \ + * | 0x1 - don't allow aggregation \ + * | bit 2: 0x0 - perform encryption \ + * | 0x1 - don't perform encryption \ + * | bit 3: 0x0 - perform tx classification / queuing \ + * | 0x1 - don't perform tx classification; \ + * | insert the frame into the "misc" \ + * | tx queue \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + */ \ + pkt_subtype:5, \ + \ + /* pkt_type - \ + * General specification of the tx frame contents. \ + * The htt_pkt_type enum should be used to specify \ + * and check the value of this field. \ + */ \ + pkt_type:3, \ + \ + /* vdev_id - \ + * ID for the vdev that is sending this tx frame. \ + * For certain non-standard packet types, e.g. pkt_type == raw \ + * and (pkt_subtype >> 3) == 1, this field is not relevant/valid. \ + * This field is used primarily for determining where to queue \ + * broadcast and multicast frames. \ + */ \ + vdev_id:6, \ + /* ext_tid - \ + * The extended traffic ID. \ + * If the TID is unknown, the extended TID is set to \ + * HTT_TX_EXT_TID_INVALID. \ + * If the tx frame is QoS data, then the extended TID has the 0-15 \ + * value of the QoS TID. \ + * If the tx frame is non-QoS data, then the extended TID is set to \ + * HTT_TX_EXT_TID_NON_QOS. \ + * If the tx frame is multicast or broadcast, then the extended TID \ + * is set to HTT_TX_EXT_TID_MCAST_BCAST. \ + */ \ + ext_tid:5, \ + \ + /* postponed - \ + * This flag indicates whether the tx frame has been downloaded to \ + * the target before but discarded by the target, and now is being \ + * downloaded again; or if this is a new frame that is being \ + * downloaded for the first time. \ + * This flag allows the target to determine the correct order for \ + * transmitting new vs. old frames. \ + * value: 0 -> new frame, 1 -> re-send of a previously + * sent frame \ + * This flag only applies to HL systems, since in LL systems, \ + * the tx flow control is handled entirely within the target. \ + */ \ + postponed:1, \ + \ + /* extension - \ + * This flag indicates whether a HTT tx MSDU extension descriptor\ + * (htt_tx_msdu_desc_ext_t) follows this HTT tx MSDU descriptor.\ + * \ + * 0x0 - no extension MSDU descriptor is present \ + * 0x1 - an extension MSDU descriptor immediately follows the \ + * regular MSDU descriptor \ + */ \ + extension:1, \ + \ + /* cksum_offload - \ + * This flag indicates whether checksum offload is enabled or not \ + * for this frame. Target FW use this flag to turn on HW checksumming \ + * 0x0 - No checksum offload \ + * 0x1 - L3 header checksum only \ + * 0x2 - L4 checksum only \ + * 0x3 - L3 header checksum + L4 checksum \ + */ \ + cksum_offload:2, \ + \ + /* tx_comp_req - \ + * This flag indicates whether Tx Completion \ + * from fw is required or not. \ + * This flag is only relevant if tx completion is not \ + * universally enabled. \ + * For all LL systems, tx completion is mandatory, \ + * so this flag will be irrelevant. \ + * For HL systems tx completion is optional, but HL systems in which \ + * the bus throughput exceeds the WLAN throughput will \ + * probably want to always use tx completion, and thus \ + * would not check this flag. \ + * This flag is required when tx completions are not used universally, \ + * but are still required for certain tx frames for which \ + * an OTA delivery acknowledgment is needed by the host. \ + * In practice, this would be for HL systems in which the \ + * bus throughput is less than the WLAN throughput. \ + * \ + * 0x0 - Tx Completion Indication from Fw not required \ + * 0x1 - Tx Completion Indication from Fw is required \ + */ \ + tx_compl_req:1; \ + \ + \ + /* DWORD 1: MSDU length and ID */ \ + A_UINT32 \ + len:16, /* MSDU length, in bytes */ \ + id:16; /* MSDU ID used to identify the MSDU to the host, \ + * and this id is used to calculate fragmentation \ + * descriptor pointer inside the target based on \ + * the base address, configured inside the target. \ + */ \ + \ + /* DWORD 2 (or 2-3): fragmentation descriptor bus address */ \ + /* frags_desc_ptr - \ + * The fragmentation descriptor pointer tells the HW's MAC DMA \ + * where the tx frame's fragments reside in memory. \ + * This field only applies to LL systems, since in HL systems the \ + * (degenerate single-fragment) fragmentation descriptor is created \ + * within the target. \ + */ \ + _paddr__frags_desc_ptr_; \ + \ + /* DWORD 3 (or 4): peerid, chanfreq */ \ + /* \ + * Peer ID : Target can use this value to know which peer-id packet \ + * destined to. \ + * It's intended to be specified by host in case of NAWDS. \ + */ \ + A_UINT16 peerid; \ + \ + /* \ + * Channel frequency: This identifies the desired channel \ + * frequency (in mhz) for tx frames. This is used by FW to help \ + * determine when it is safe to transmit or drop frames for \ + * off-channel operation. \ + * The default value of zero indicates to FW that the \ + * corresponding VDEV's home channel (if there is one) is \ + * the desired channel frequency. \ + */ \ + A_UINT16 chanfreq; \ + \ + /* Reason reserved is commented is increasing the htt + * structure size leads to some wierd issues. + * A_UINT32 reserved_dword3_bits0_31; \ + */ \ +} POSTPACK +/* define a htt_tx_msdu_desc32_t type */ +TEMPLATE_HTT_TX_MSDU_DESC_T(32, HTT_VAR_PADDR32(frags_desc_ptr)); +/* define a htt_tx_msdu_desc64_t type */ +TEMPLATE_HTT_TX_MSDU_DESC_T(64, HTT_VAR_PADDR64_LE(frags_desc_ptr)); +/* + * Make htt_tx_msdu_desc_t be an alias for either + * htt_tx_msdu_desc32_t or htt_tx_msdu_desc64_t + */ +#if HTT_PADDR64 +#define htt_tx_msdu_desc_t htt_tx_msdu_desc64_t +#else +#define htt_tx_msdu_desc_t htt_tx_msdu_desc32_t +#endif + +/* decriptor information for Management frame*/ +/* + * THIS htt_mgmt_tx_desc_t STRUCT IS DEPRECATED - DON'T USE IT. + * BOTH MANAGEMENT AND DATA FRAMES SHOULD USE htt_tx_msdu_desc_t. + */ +#define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +extern A_UINT32 mgmt_hdr_len; +PREPACK struct htt_mgmt_tx_desc_t { + A_UINT32 msg_type; +#if HTT_PADDR64 + A_UINT64 frag_paddr; /* DMAble address of the data */ +#else + A_UINT32 frag_paddr; /* DMAble address of the data */ +#endif + A_UINT32 desc_id; /* returned to host during completion + * to free the meory*/ + A_UINT32 len; /* Fragment length */ + A_UINT32 vdev_id; /* virtual device ID */ + A_UINT8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; /* frm header */ +} POSTPACK; + +PREPACK struct htt_mgmt_tx_compl_ind { + A_UINT32 desc_id; + A_UINT32 status; +} POSTPACK; + +/* + * This SDU header size comes from the summation of the following: + * 1. Max of: + * a. Native WiFi header, for native WiFi frames: 24 bytes + * (frame control, duration / ID, addr1, addr2, addr3, seq ctrl, addr4) + * b. 802.11 header, for raw frames: 36 bytes + * (frame control, duration / ID, addr1, addr2, addr3, seq ctrl, addr4, + * QoS header, HT header) + * c. 802.3 header, for ethernet frames: 14 bytes + * (destination address, source address, ethertype / length) + * 2. Max of: + * a. IPv4 header, up through the DiffServ Code Point: 2 bytes + * b. IPv6 header, up through the Traffic Class: 2 bytes + * 3. 802.1Q VLAN header: 4 bytes + * 4. LLC/SNAP header: 8 bytes + */ +#define HTT_TX_HDR_SIZE_NATIVE_WIFI 30 +#define HTT_TX_HDR_SIZE_802_11_RAW 36 +#define HTT_TX_HDR_SIZE_ETHERNET 14 + +#define HTT_TX_HDR_SIZE_OUTER_HDR_MAX HTT_TX_HDR_SIZE_802_11_RAW +A_COMPILE_TIME_ASSERT(htt_encap_hdr_size_max_check_nwifi, + HTT_TX_HDR_SIZE_OUTER_HDR_MAX >= + HTT_TX_HDR_SIZE_NATIVE_WIFI); +A_COMPILE_TIME_ASSERT(htt_encap_hdr_size_max_check_enet, + HTT_TX_HDR_SIZE_OUTER_HDR_MAX >= + HTT_TX_HDR_SIZE_ETHERNET); + +#define HTT_HL_TX_HDR_SIZE_IP 1600 /* also include payload */ +#define HTT_LL_TX_HDR_SIZE_IP 16 /*up to the end of UDP hdr for v4*/ + +#define HTT_TX_HDR_SIZE_802_1Q 4 +#define HTT_TX_HDR_SIZE_LLC_SNAP 8 + + +#define HTT_COMMON_TX_FRM_HDR_LEN \ + (HTT_TX_HDR_SIZE_OUTER_HDR_MAX + \ + HTT_TX_HDR_SIZE_802_1Q + \ + HTT_TX_HDR_SIZE_LLC_SNAP) + +#define HTT_HL_TX_FRM_HDR_LEN \ + (HTT_COMMON_TX_FRM_HDR_LEN + HTT_HL_TX_HDR_SIZE_IP) + +#define HTT_LL_TX_FRM_HDR_LEN \ + (HTT_COMMON_TX_FRM_HDR_LEN + HTT_LL_TX_HDR_SIZE_IP) + +#define HTT_TX_DESC_LEN sizeof(struct htt_tx_msdu_desc_t) + +/* dword 0 */ +#define HTT_TX_DESC_PKT_SUBTYPE_OFFSET_BYTES 0 +#define HTT_TX_DESC_PKT_SUBTYPE_OFFSET_DWORD 0 +#define HTT_TX_DESC_PKT_SUBTYPE_M 0x00001f00 +#define HTT_TX_DESC_PKT_SUBTYPE_S 8 + +#define HTT_TX_DESC_NO_ENCRYPT_OFFSET_BYTES 0 +#define HTT_TX_DESC_NO_ENCRYPT_OFFSET_DWORD 0 +#define HTT_TX_DESC_NO_ENCRYPT_M 0x00000400 +#define HTT_TX_DESC_NO_ENCRYPT_S 10 + +#define HTT_TX_DESC_PKT_TYPE_OFFSET_BYTES 0 +#define HTT_TX_DESC_PKT_TYPE_OFFSET_DWORD 0 +#define HTT_TX_DESC_PKT_TYPE_M 0x0000e000 +#define HTT_TX_DESC_PKT_TYPE_S 13 + +#define HTT_TX_DESC_VDEV_ID_OFFSET_BYTES 0 +#define HTT_TX_DESC_VDEV_ID_OFFSET_DWORD 0 +#define HTT_TX_DESC_VDEV_ID_M 0x003f0000 +#define HTT_TX_DESC_VDEV_ID_S 16 + +#define HTT_TX_DESC_EXT_TID_OFFSET_BYTES 0 +#define HTT_TX_DESC_EXT_TID_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXT_TID_M 0x07c00000 +#define HTT_TX_DESC_EXT_TID_S 22 + +#define HTT_TX_DESC_POSTPONED_OFFSET_BYTES 0 +#define HTT_TX_DESC_POSTPONED_OFFSET_DWORD 0 +#define HTT_TX_DESC_POSTPONED_M 0x08000000 +#define HTT_TX_DESC_POSTPONED_S 27 + +#define HTT_TX_DESC_CKSUM_OFFLOAD_OFFSET_BYTES 0 +#define HTT_TX_DESC_CKSUM_OFFLOAD_OFFSET_DWORD 0 +#define HTT_TX_DESC_CKSUM_OFFLOAD_M 0x60000000 +#define HTT_TX_DESC_CKSUM_OFFLOAD_S 29 + +#define HTT_TX_DESC_TX_COMP_OFFSET_BYTES 0 +#define HTT_TX_DESC_TX_COMP_OFFSET_DWORD 0 +#define HTT_TX_DESC_TX_COMP_M 0x80000000 +#define HTT_TX_DESC_TX_COMP_S 31 + +/* dword 1 */ +#define HTT_TX_DESC_FRM_LEN_OFFSET_BYTES 4 +#define HTT_TX_DESC_FRM_LEN_OFFSET_DWORD 1 +#define HTT_TX_DESC_FRM_LEN_M 0x0000ffff +#define HTT_TX_DESC_FRM_LEN_S 0 + +#define HTT_TX_DESC_FRM_ID_OFFSET_BYTES 4 +#define HTT_TX_DESC_FRM_ID_OFFSET_DWORD 1 +#define HTT_TX_DESC_FRM_ID_M 0xffff0000 +#define HTT_TX_DESC_FRM_ID_S 16 + +/* dword 2 */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_BYTES 8 +#define HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD 2 +/* for systems using 64-bit format for bus addresses */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_HI_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_HI_S 0 +#define HTT_TX_DESC_FRAGS_DESC_PADDR_LO_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_LO_S 0 +/* for systems using 32-bit format for bus addresses */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_S 0 + +/* dword 3 */ +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 16 +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 12 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD_64 \ + (HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 >> 2) +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD_32 \ + (HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 >> 2) + +#if HTT_PADDR64 +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD HTT_TX_DESC_PEER_ID_OFFSET_DWORD_64 +#else +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD HTT_TX_DESC_PEER_ID_OFFSET_DWORD_32 +#endif + +#define HTT_TX_DESC_PEER_ID_M 0x0000ffff +#define HTT_TX_DESC_PEER_ID_S 0 +/* + * TEMPORARY: + * The original definitions for the PEER_ID fields contained typos + * (with _DESC_PADDR appended to this PEER_ID field name). + * Retain deprecated original names for PEER_ID fields until all code that + * refers to them has been updated. + */ +#define HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES \ + HTT_TX_DESC_PEER_ID_OFFSET_BYTES +#define HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_DWORD \ + HTT_TX_DESC_PEER_ID_OFFSET_DWORD +#define HTT_TX_DESC_PEERID_DESC_PADDR_M \ + HTT_TX_DESC_PEER_ID_M +#define HTT_TX_DESC_PEERID_DESC_PADDR_S \ + HTT_TX_DESC_PEER_ID_S + +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 16 /* to dword with chan freq */ +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 12 /* to dword with chan freq */ +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_64 \ + (HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 >> 2) +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_32 \ + (HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 >> 2) + +#if HTT_PADDR64 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_64 +#else +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_32 +#endif + +#define HTT_TX_DESC_CHAN_FREQ_M 0xffff0000 +#define HTT_TX_DESC_CHAN_FREQ_S 16 + +#define HTT_TX_DESC_PKT_SUBTYPE_GET(_var) \ + (((_var) & HTT_TX_DESC_PKT_SUBTYPE_M) >> HTT_TX_DESC_PKT_SUBTYPE_S) +#define HTT_TX_DESC_PKT_SUBTYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PKT_SUBTYPE, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PKT_SUBTYPE_S)); \ + } while (0) + +#define HTT_TX_DESC_NO_ENCRYPT_GET(_var) \ + (((_var) & HTT_TX_DESC_NO_ENCRYPT_M) >> HTT_TX_DESC_NO_ENCRYPT_S) +#define HTT_TX_DESC_NO_ENCRYPT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_NO_ENCRYPT, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_NO_ENCRYPT_S)); \ + } while (0) + +#define HTT_TX_DESC_PKT_TYPE_GET(_var) \ + (((_var) & HTT_TX_DESC_PKT_TYPE_M) >> HTT_TX_DESC_PKT_TYPE_S) +#define HTT_TX_DESC_PKT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PKT_TYPE, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PKT_TYPE_S)); \ + } while (0) + +#define HTT_TX_DESC_VDEV_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_VDEV_ID_M) >> HTT_TX_DESC_VDEV_ID_S) +#define HTT_TX_DESC_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_VDEV_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_EXT_TID_GET(_var) \ + (((_var) & HTT_TX_DESC_EXT_TID_M) >> HTT_TX_DESC_EXT_TID_S) +#define HTT_TX_DESC_EXT_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXT_TID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXT_TID_S)); \ + } while (0) + +#define HTT_TX_DESC_POSTPONED_GET(_var) \ + (((_var) & HTT_TX_DESC_POSTPONED_M) >> HTT_TX_DESC_POSTPONED_S) +#define HTT_TX_DESC_POSTPONED_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_POSTPONED, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_POSTPONED_S)); \ + } while (0) + +#define HTT_TX_DESC_FRM_LEN_GET(_var) \ + (((_var) & HTT_TX_DESC_FRM_LEN_M) >> HTT_TX_DESC_FRM_LEN_S) +#define HTT_TX_DESC_FRM_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_FRM_LEN, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_FRM_LEN_S)); \ + } while (0) + +#define HTT_TX_DESC_FRM_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_FRM_ID_M) >> HTT_TX_DESC_FRM_ID_S) +#define HTT_TX_DESC_FRM_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_FRM_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_FRM_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_CKSUM_OFFLOAD_GET(_var) \ + (((_var) & HTT_TX_DESC_CKSUM_OFFLOAD_M) >> HTT_TX_DESC_CKSUM_OFFLOAD_S) +#define HTT_TX_DESC_CKSUM_OFFLOAD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_CKSUM_OFFLOAD, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_CKSUM_OFFLOAD_S)); \ + } while (0) + +#define HTT_TX_DESC_TX_COMP_GET(_var) \ + (((_var) & HTT_TX_DESC_TX_COMP_M) >> HTT_TX_DESC_TX_COMP_S) +#define HTT_TX_DESC_TX_COMP_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_TX_COMP, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_TX_COMP_S)); \ + } while (0) + +#define HTT_TX_DESC_PEER_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_PEER_ID_M) >> HTT_TX_DESC_PEER_ID_S) +#define HTT_TX_DESC_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PEER_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_CHAN_FREQ_GET(_var) \ + (((_var) & HTT_TX_DESC_CHAN_FREQ_M) >> HTT_TX_DESC_CHAN_FREQ_S) +#define HTT_TX_DESC_CHAN_FREQ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_CHAN_FREQ, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_CHAN_FREQ_S)); \ + } while (0) + + +/* enums used in the HTT tx MSDU extension descriptor */ +enum { + htt_tx_guard_interval_regular = 0, + htt_tx_guard_interval_short = 1, +}; + +enum { + htt_tx_preamble_type_ofdm = 0, + htt_tx_preamble_type_cck = 1, + htt_tx_preamble_type_ht = 2, + htt_tx_preamble_type_vht = 3, +}; + +enum { + htt_tx_bandwidth_5MHz = 0, + htt_tx_bandwidth_10MHz = 1, + htt_tx_bandwidth_20MHz = 2, + htt_tx_bandwidth_40MHz = 3, + htt_tx_bandwidth_80MHz = 4, + htt_tx_bandwidth_160MHz = 5, /* includes 80+80 */ +}; + +/** + * @brief HTT tx MSDU extension descriptor + * @details + * If the target supports HTT tx MSDU extension descriptors, the host has + * the option of appending the following struct following the regular + * HTT tx MSDU descriptor (and setting the "extension" flag in the regular + * HTT tx MSDU descriptor, to show that the extension descriptor is present). + * The HTT tx MSDU extension descriptors allows the host to provide detailed + * tx specs for each frame. + */ +PREPACK struct htt_tx_msdu_desc_ext_t { + /* DWORD 0: flags */ + A_UINT32 valid_pwr:1,/* bit 0:if set, tx pwr spec is valid */ + valid_mcs_mask:1,/* bit 1:if set, tx MCS mask spec is valid */ + valid_nss_mask:1,/* bit 2:if set, tx Nss mask spec is valid */ + valid_guard_interval:1,/* bit 3:if set, tx guard intv spec is valid */ + valid_preamble_type_mask:1,/* 4:if set, tx preamble mask is valid */ + valid_chainmask:1,/* bit 5:if set, tx chainmask spec is valid */ + valid_retries:1,/* bit 6:if set, tx retries spec is valid */ + valid_bandwidth:1,/* bit 7:if set, tx bandwidth spec is valid */ + valid_expire_tsf:1,/* bit 8:if set, tx expire TSF spec is valid */ + is_dsrc:1, /* bit 9:if set, MSDU is a DSRC frame */ + reserved0_31_7:22; /* bits 31:10 - unused, set to 0x0 */ + + /* DWORD 1:tx power, tx rate, tx BW */ + A_UINT32 + /* pwr - + * Specify what power the tx frame needs to be transmitted at. + * The power a signed (two's complement) value is in units of 0.5 dBm. + * The value needs to be appropriately sign-extended when extracting + * the value from the message and storing it in a variable that is + * larger than A_INT8. (The HTT_TX_MSDU_EXT_DESC_FLAG_PWR_GET macro + * automatically handles this sign-extension.) + * If the transmission uses multiple tx chains, this power spec is + * the total transmit power, assuming incoherent combination of + * per-chain power to produce the total power. + */ + pwr:8, + /* mcs_mask - + * Specify the allowable values for MCS index (modulation and coding) + * to use for transmitting the frame. + * + * For HT / VHT preamble types, this mask directly corresponds to + * the HT or VHT MCS indices that are allowed. For each bit N set + * within the mask, MCS index N is allowed for transmitting the frame. + * For legacy CCK and OFDM rates, separate bits are provided for CCK + * rates versus OFDM rates, so the host has the option of specifying + * that the target must transmit the frame with CCK or OFDM rates + * (not HT or VHT), but leaving the decision to the target whether + * to use CCK or OFDM. + * + * For CCK and OFDM, the bits within this mask are interpreted as + * follows: + * bit 0 -> CCK 1 Mbps rate is allowed + * bit 1 -> CCK 2 Mbps rate is allowed + * bit 2 -> CCK 5.5 Mbps rate is allowed + * bit 3 -> CCK 11 Mbps rate is allowed + * bit 4 -> OFDM BPSK modulation, 1/2 coding rate is allowed + * bit 5 -> OFDM BPSK modulation, 3/4 coding rate is allowed + * bit 6 -> OFDM QPSK modulation, 1/2 coding rate is allowed + * bit 7 -> OFDM QPSK modulation, 3/4 coding rate is allowed + * bit 8 -> OFDM 16-QAM modulation, 1/2 coding rate is allowed + * bit 9 -> OFDM 16-QAM modulation, 3/4 coding rate is allowed + * bit 10 -> OFDM 64-QAM modulation, 2/3 coding rate is allowed + * bit 11 -> OFDM 64-QAM modulation, 3/4 coding rate is allowed + * + * The MCS index specification needs to be compatible with the + * bandwidth mask specification. For example, a MCS index == 9 + * specification is inconsistent with a preamble type == VHT, + * Nss == 1, and channel bandwidth == 20 MHz. + * + * Furthermore, the host has only a limited ability to specify to + * the target to select from HT + legacy rates, or VHT + legacy rates, + * since this mcs_mask can specify either HT/VHT rates or legacy rates. + */ + mcs_mask:12, + /* nss_mask - + * Specify which numbers of spatial streams (MIMO factor) are permitted. + * Each bit in this mask corresponds to a Nss value: + * bit 0: if set, Nss = 1 (non-MIMO) is permitted + * bit 1: if set, Nss = 2 (2x2 MIMO) is permitted + * bit 2: if set, Nss = 3 (3x3 MIMO) is permitted + * bit 3: if set, Nss = 4 (4x4 MIMO) is permitted + * The values in the Nss mask must be suitable for the recipient, e.g. + * a value of 0x4 (Nss = 3) cannot be specified for a tx frame to a + * recipient which only supports 2x2 MIMO. + */ + nss_mask:4, + /* guard_interval - + * Specify a htt_tx_guard_interval enum value to indicate whether + * the transmission should use a regular guard interval or a + * short guard interval. + */ + guard_interval:1, + /* preamble_type_mask - + * Specify which preamble types (CCK, OFDM, HT, VHT) the target + * may choose from for transmitting this frame. + * The bits in this mask correspond to the values in the + * htt_tx_preamble_type enum. For example, to allow the target + * to transmit the frame as either CCK or OFDM, this field would + * be set to + * (1 << htt_tx_preamble_type_ofdm) | + * (1 << htt_tx_preamble_type_cck) + */ + preamble_type_mask:4, + + reserved1_31_29:3; /* unused, set to 0x0 */ + + /* DWORD 2: tx chain mask, tx retries */ + A_UINT32 + /* chain_mask - specify which chains to transmit from */ + chain_mask:4, + /* retry_limit - + * Specify the maximum number of transmissions, including the + * initial transmission, to attempt before giving up if no ack + * is received. + * If the tx rate is specified, then all retries shall use the + * same rate as the initial transmission. + * If no tx rate is specified, the target can choose whether to + * retain the original rate during the retransmissions, or to + * fall back to a more robust rate. + */ + retry_limit:4, + /* bandwidth_mask - + * Specify what channel widths may be used for the transmission. + * A value of zero indicates "don't care" - the target may choose + * the transmission bandwidth. + * The bits within this mask correspond to the htt_tx_bandwidth + * enum values - bit 0 is for 5 MHz, bit 1 is for 10 MHz, etc. + * The bandwidth_mask must be consistent with the + * preamble_type_mask * and mcs_mask specs, if they are + * provided. For example, + * 80 MHz and 160 MHz can only be enabled in the mask + * if preamble_type == VHT. + */ + bandwidth_mask:6, + + reserved2_31_14:18; /* unused, set to 0x0 */ + + /* DWORD 3: tx expiry time (TSF) LSBs */ + A_UINT32 expire_tsf_lo; + + /* DWORD 4: tx expiry time (TSF) MSBs */ + A_UINT32 expire_tsf_hi; + + A_UINT32 reserved_for_future_expansion_set_to_zero[3]; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_M 0x00000001 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S 0 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_M 0x00000002 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S 1 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_NSS_MASK_M 0x00000004 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_NSS_MASK_S 2 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_M 0x00000008 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S 3 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_M 0x00000010 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S 4 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_M 0x00000020 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S 5 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_M 0x00000040 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S 6 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_M 0x00000080 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S 7 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_M 0x00000100 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S 8 +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_M 0x00000200 +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S 9 + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT_DESC_PWR_M 0x000000ff +#define HTT_TX_MSDU_EXT_DESC_PWR_S 0 +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_M 0x000fff00 +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_S 8 +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_M 0x00f00000 +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_S 20 +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_M 0x01000000 +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S 24 +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_M 0x1c000000 +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S 25 + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_M 0x0000000f +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S 0 +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_M 0x000000f0 +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S 4 +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_M 0x00003f00 +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S 8 + + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_M) >>\ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK, _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S));\ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S)); \ +} while (0) + + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT_DESC_PWR_GET_BASE(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_PWR_M) >> \ + HTT_TX_MSDU_EXT_DESC_PWR_S) +#define HTT_TX_MSDU_EXT_DESC_PWR_GET(_var) \ + (HTT_TX_MSDU_EXT_DESC_PWR_GET_BASE(_var) | \ + HTT_SIGN_BIT_EXTENSION_MASK(_var, HTT_TX_MSDU_EXT_DESC_PWR)) +#define HTT_TX_MSDU_EXT_DESC_PWR_SET(_var, _val) \ + ((_var) |= (((_val) << HTT_TX_MSDU_EXT_DESC_PWR_S)) & \ + HTT_TX_MSDU_EXT_DESC_PWR_M) + +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_MCS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_MCS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_MCS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_NSS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_NSS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_NSS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_NSS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_M) >> \ + HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S)); \ + } while (0) + + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_CHAIN_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_M) >> \ + HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S) +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S)); \ + } while (0) + + +/** + * @brief MAC DMA rx ring setup specification + * @details + * To allow for dynamic rx ring reconfiguration and to avoid race + * conditions, the host SW never directly programs the MAC DMA rx ring(s) + * it uses. Instead, it sends this message to the target, indicating how + * the rx ring used by the host should be set up and maintained. + * The message consists of a 4-octet header followed by 1 or 2 rx ring setup + * specifications. + * + * |31 16|15 8|7 0| + * |---------------------------------------------------------------| + * header: | reserved | num rings | msg type | + * |---------------------------------------------------------------| + * payload 1: | FW_IDX shadow register physical address (bits 31:0) | + #if HTT_PADDR64 + * | FW_IDX shadow register physical address (bits 63:32) | + #endif + * |---------------------------------------------------------------| + * | rx ring base physical address (bits 31:0) | + #if HTT_PADDR64 + * | rx ring base physical address (bits 63:32) | + #endif + * |---------------------------------------------------------------| + * | rx ring buffer size | rx ring length | + * |---------------------------------------------------------------| + * | FW_IDX initial value | enabled flags | + * |---------------------------------------------------------------| + * | MSDU payload offset | 802.11 header offset | + * |---------------------------------------------------------------| + * | PPDU end offset | PPDU start offset | + * |---------------------------------------------------------------| + * | MPDU end offset | MPDU start offset | + * |---------------------------------------------------------------| + * | MSDU end offset | MSDU start offset | + * |---------------------------------------------------------------| + * | frag info offset | rx attention offset | + * |---------------------------------------------------------------| + * payload 2, if present, has the same format as payload 1 + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx ring configuration message + * Value: 0x2 + * - NUM_RINGS + * Bits 15:8 + * Purpose: indicates whether the host is setting up one rx ring or two + * Value: 1 or 2 + * Payload: + * for systems using 64-bit format for bus addresses: + * - IDX_SHADOW_REG_PADDR_LO + * Bits 31:0 + * Value: lower 4 bytes of physical address of the host's + * FW_IDX shadow register + * - IDX_SHADOW_REG_PADDR_HI + * Bits 31:0 + * Value: upper 4 bytes of physical address of the host's + * FW_IDX shadow register + * - RING_BASE_PADDR_LO + * Bits 31:0 + * Value: lower 4 bytes of physical address of the host's rx ring + * - RING_BASE_PADDR_HI + * Bits 31:0 + * Value: uppper 4 bytes of physical address of the host's rx ring + * for systems using 32-bit format for bus addresses: + * - IDX_SHADOW_REG_PADDR + * Bits 31:0 + * Value: physical address of the host's FW_IDX shadow register + * - RING_BASE_PADDR + * Bits 31:0 + * Value: physical address of the host's rx ring + * - RING_LEN + * Bits 15:0 + * Value: number of elements in the rx ring + * - RING_BUF_SZ + * Bits 31:16 + * Value: size of the buffers referenced by the rx ring, in byte units + * - ENABLED_FLAGS + * Bits 15:0 + * Value: 1-bit flags to show whether different rx fields are enabled + * bit 0: 802.11 header enabled (1) or disabled (0) + * bit 1: MSDU payload enabled (1) or disabled (0) + * bit 2: PPDU start enabled (1) or disabled (0) + * bit 3: PPDU end enabled (1) or disabled (0) + * bit 4: MPDU start enabled (1) or disabled (0) + * bit 5: MPDU end enabled (1) or disabled (0) + * bit 6: MSDU start enabled (1) or disabled (0) + * bit 7: MSDU end enabled (1) or disabled (0) + * bit 8: rx attention enabled (1) or disabled (0) + * bit 9: frag info enabled (1) or disabled (0) + * bit 10: unicast rx enabled (1) or disabled (0) + * bit 11: multicast rx enabled (1) or disabled (0) + * bit 12: ctrl rx enabled (1) or disabled (0) + * bit 13: mgmt rx enabled (1) or disabled (0) + * bit 14: null rx enabled (1) or disabled (0) + * bit 15: phy data rx enabled (1) or disabled (0) + * - IDX_INIT_VAL + * Bits 31:16 + * Purpose: Specify the initial value for the FW_IDX. + * Value: the number of buffers initially present in the host's rx ring + * - OFFSET_802_11_HDR + * Bits 15:0 + * Value: offset in QUAD-bytes of 802.11 header from the buffer start + * - OFFSET_MSDU_PAYLOAD + * Bits 31:16 + * Value: offset in QUAD-bytes of MSDU payload from the buffer start + * - OFFSET_PPDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of PPDU start rx desc from the buffer start + * - OFFSET_PPDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of PPDU end rx desc from the buffer start + * - OFFSET_MPDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of MPDU start rx desc from the buffer start + * - OFFSET_MPDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of MPDU end rx desc from the buffer start + * - OFFSET_MSDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of MSDU start rx desc from the buffer start + * - OFFSET_MSDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of MSDU end rx desc from the buffer start + * - OFFSET_RX_ATTN + * Bits 15:0 + * Value: offset in QUAD-bytes of rx attention word from the buffer start + * - OFFSET_FRAG_INFO + * Bits 31:16 + * Value: offset in QUAD-bytes of frag info table + */ +/* header fields */ +#define HTT_RX_RING_CFG_NUM_RINGS_M 0xff00 +#define HTT_RX_RING_CFG_NUM_RINGS_S 8 + +/* payload fields */ +/* for systems using a 64-bit format for bus addresses */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_S 0 +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_HI_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_HI_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_LO_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_LO_S 0 + +/* for systems using a 32-bit format for bus addresses */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_S 0 + +#define HTT_RX_RING_CFG_LEN_M 0xffff +#define HTT_RX_RING_CFG_LEN_S 0 +#define HTT_RX_RING_CFG_BUF_SZ_M 0xffff0000 +#define HTT_RX_RING_CFG_BUF_SZ_S 16 +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_M 0x1 +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_S 0 +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_M 0x2 +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S 1 +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_M 0x4 +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_S 2 +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_M 0x8 +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_S 3 +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_M 0x10 +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_S 4 +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_M 0x20 +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_S 5 +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_M 0x40 +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_S 6 +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_M 0x80 +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_S 7 +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_M 0x100 +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_S 8 +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_M 0x200 +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S 9 +#define HTT_RX_RING_CFG_ENABLED_UCAST_M 0x400 +#define HTT_RX_RING_CFG_ENABLED_UCAST_S 10 +#define HTT_RX_RING_CFG_ENABLED_MCAST_M 0x800 +#define HTT_RX_RING_CFG_ENABLED_MCAST_S 11 +#define HTT_RX_RING_CFG_ENABLED_CTRL_M 0x1000 +#define HTT_RX_RING_CFG_ENABLED_CTRL_S 12 +#define HTT_RX_RING_CFG_ENABLED_MGMT_M 0x2000 +#define HTT_RX_RING_CFG_ENABLED_MGMT_S 13 +#define HTT_RX_RING_CFG_ENABLED_NULL_M 0x4000 +#define HTT_RX_RING_CFG_ENABLED_NULL_S 14 +#define HTT_RX_RING_CFG_ENABLED_PHY_M 0x8000 +#define HTT_RX_RING_CFG_ENABLED_PHY_S 15 +#define HTT_RX_RING_CFG_IDX_INIT_VAL_M 0xffff0000 +#define HTT_RX_RING_CFG_IDX_INIT_VAL_S 16 +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_S 0 +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S 16 +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_S 0 +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S 16 + +#define HTT_RX_RING_CFG_HDR_BYTES 4 +#define HTT_RX_RING_CFG_PAYLD_BYTES_64 44 +#define HTT_RX_RING_CFG_PAYLD_BYTES_32 36 +#if HTT_PADDR64 +#define HTT_RX_RING_CFG_PAYLD_BYTES HTT_RX_RING_CFG_PAYLD_BYTES_64 +#else +#define HTT_RX_RING_CFG_PAYLD_BYTES HTT_RX_RING_CFG_PAYLD_BYTES_32 +#endif +#define HTT_RX_RING_CFG_BYTES(num_rings) \ + (HTT_RX_RING_CFG_HDR_BYTES + (num_rings) * HTT_RX_RING_CFG_PAYLD_BYTES) + + +#define HTT_RX_RING_CFG_NUM_RINGS_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_NUM_RINGS_M) >> HTT_RX_RING_CFG_NUM_RINGS_S) +#define HTT_RX_RING_CFG_NUM_RINGS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_NUM_RINGS, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_NUM_RINGS_S)); \ + } while (0) + +/* degenerate case for 32-bit fields */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_SET(_var, _val) \ + ((_var) = (_val)) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_SET(_var, _val) \ + ((_var) = (_val)) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET(_var, _val) \ + ((_var) = (_val)) + +/* degenerate case for 32-bit fields */ +#define HTT_RX_RING_CFG_BASE_PADDR_HI_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_HI_SET(_var, _val) ((_var) = (_val)) +#define HTT_RX_RING_CFG_BASE_PADDR_LO_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_LO_SET(_var, _val) ((_var) = (_val)) +#define HTT_RX_RING_CFG_BASE_PADDR_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_SET(_var, _val) ((_var) = (_val)) + +#define HTT_RX_RING_CFG_LEN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_LEN_M) >> HTT_RX_RING_CFG_LEN_S) +#define HTT_RX_RING_CFG_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_LEN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_LEN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_BUF_SZ_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_BUF_SZ_M) >> HTT_RX_RING_CFG_BUF_SZ_S) +#define HTT_RX_RING_CFG_BUF_SZ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_BUF_SZ, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_BUF_SZ_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_IDX_INIT_VAL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_IDX_INIT_VAL_M) >> \ + HTT_RX_RING_CFG_IDX_INIT_VAL_S) +#define HTT_RX_RING_CFG_IDX_INIT_VAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_IDX_INIT_VAL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_IDX_INIT_VAL_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_802_11_HDR_M) >> \ + HTT_RX_RING_CFG_ENABLED_802_11_HDR_S) +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_802_11_HDR, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_802_11_HDR_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PPDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_PPDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PPDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_PPDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MPDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_MPDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MPDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_MPDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_RX_ATTN_M) >> \ + HTT_RX_RING_CFG_ENABLED_RX_ATTN_S) +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_RX_ATTN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_RX_ATTN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_FRAG_INFO_M) >> \ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S) +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_FRAG_INFO, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_UCAST_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_UCAST_M) >> \ + HTT_RX_RING_CFG_ENABLED_UCAST_S) +#define HTT_RX_RING_CFG_ENABLED_UCAST_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_UCAST, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_UCAST_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MCAST_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MCAST_M) >> \ + HTT_RX_RING_CFG_ENABLED_MCAST_S) +#define HTT_RX_RING_CFG_ENABLED_MCAST_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MCAST, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MCAST_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_CTRL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_CTRL_M) >> \ + HTT_RX_RING_CFG_ENABLED_CTRL_S) +#define HTT_RX_RING_CFG_ENABLED_CTRL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_CTRL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_CTRL_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_MGMT_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MGMT_M) >> \ + HTT_RX_RING_CFG_ENABLED_MGMT_S) +#define HTT_RX_RING_CFG_ENABLED_MGMT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MGMT, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MGMT_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_NULL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_NULL_M) >> \ + HTT_RX_RING_CFG_ENABLED_NULL_S) +#define HTT_RX_RING_CFG_ENABLED_NULL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_NULL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_NULL_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_PHY_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PHY_M) >> \ + HTT_RX_RING_CFG_ENABLED_PHY_S) +#define HTT_RX_RING_CFG_ENABLED_PHY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PHY, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PHY_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_802_11_HDR_M) >> \ + HTT_RX_RING_CFG_OFFSET_802_11_HDR_S) +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_802_11_HDR, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_802_11_HDR_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_PPDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_PPDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_PPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_PPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_PPDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_PPDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_PPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_PPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MPDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_MPDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MPDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_MPDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_RX_ATTN_M) >> \ + HTT_RX_RING_CFG_OFFSET_RX_ATTN_S) +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_RX_ATTN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_RX_ATTN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_FRAG_INFO_M) >> \ + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S) +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_FRAG_INFO, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S)); \ + } while (0) + +/** + * @brief host -> target FW statistics retrieve + * + * @details + * The following field definitions describe the format of the HTT host + * to target FW stats retrieve message. The message specifies the type of + * stats host wants to retrieve. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | stats types request bitmask | msg type | + * |-----------------------------------------------------------| + * | stats types reset bitmask | reserved | + * |-----------------------------------------------------------| + * | stats type | config value | + * |-----------------------------------------------------------| + * | cookie LSBs | + * |-----------------------------------------------------------| + * | cookie MSBs | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this is a stats upload request message + * Value: 0x3 + * - UPLOAD_TYPES + * Bits 31:8 + * Purpose: identifies which types of FW statistics to upload + * Value: mask with bits set in positions defined by htt_dbg_stats_type + * - RESET_TYPES + * Bits 31:8 + * Purpose: identifies which types of FW statistics to reset + * Value: mask with bits set in positions defined by htt_dbg_stats_type + * - CFG_VAL + * Bits 23:0 + * Purpose: give an opaque configuration value to the specified stats type + * Value: stats-type specific configuration value + * if stats type == tx PPDU log, then CONFIG_VAL has the format: + * bits 7:0 - how many per-MPDU byte counts to include in a record + * bits 15:8 - how many per-MPDU MSDU counts to include in a record + * bits 23:16 - how many per-MSDU byte counts to include in a record + * - CFG_STAT_TYPE + * Bits 31:24 + * Purpose: specify which stats type (if any) the config value applies to + * Value: htt_dbg_stats_type value, or 0xff if the message doesn't have + * a valid configuration specification + * - COOKIE_LSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: LSBs of the opaque cookie specified by the host-side requestor + * - COOKIE_MSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + */ + +#define HTT_H2T_STATS_REQ_MSG_SZ 20 /* bytes */ + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID 0xff + +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_M 0xffffff00 +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_S 8 + +#define HTT_H2T_STATS_REQ_RESET_TYPES_M 0xffffff00 +#define HTT_H2T_STATS_REQ_RESET_TYPES_S 8 + +#define HTT_H2T_STATS_REQ_CFG_VAL_M 0x00ffffff +#define HTT_H2T_STATS_REQ_CFG_VAL_S 0 + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_M 0xff000000 +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S 24 + +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_UPLOAD_TYPES_M) >> \ + HTT_H2T_STATS_REQ_UPLOAD_TYPES_S) +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_UPLOAD_TYPES, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_UPLOAD_TYPES_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_RESET_TYPES_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_RESET_TYPES_M) >> \ + HTT_H2T_STATS_REQ_RESET_TYPES_S) +#define HTT_H2T_STATS_REQ_RESET_TYPES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_RESET_TYPES, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_RESET_TYPES_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_CFG_VAL_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_CFG_VAL_M) >> \ + HTT_H2T_STATS_REQ_CFG_VAL_S) +#define HTT_H2T_STATS_REQ_CFG_VAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_CFG_VAL, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_CFG_VAL_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_CFG_STAT_TYPE_M) >> \ + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S) +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_CFG_STAT_TYPE, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S)); \ + } while (0) + +/** + * @brief host -> target HTT out-of-band sync request + * + * @details + * The HTT SYNC tells the target to suspend processing of subsequent + * HTT host-to-target messages until some other target agent locally + * informs the target HTT FW that the current sync counter is equal to + * or greater than (in a modulo sense) the sync counter specified in + * the SYNC message. + * This allows other host-target components to synchronize their operation + * with HTT, e.g. to ensure that tx frames don't get transmitted until a + * security key has been downloaded to and activated by the target. + * In the absence of any explicit synchronization counter value + * specification, the target HTT FW will use zero as the default current + * sync value. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | reserved | sync count | msg type | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a sync message + * Value: 0x4 + * - SYNC_COUNT + * Bits 15:8 + * Purpose: specifies what sync value the HTT FW will wait for from + * an out-of-band specification to resume its operation + * Value: in-band sync counter value to compare against the out-of-band + * counter spec. + * The HTT target FW will suspend its host->target message processing + * as long as + * 0 < (in-band sync counter - out-of-band sync counter) & 0xff < 128 + */ + +#define HTT_H2T_SYNC_MSG_SZ 4 + +#define HTT_H2T_SYNC_COUNT_M 0x0000ff00 +#define HTT_H2T_SYNC_COUNT_S 8 + +#define HTT_H2T_SYNC_COUNT_GET(_var) \ + (((_var) & HTT_H2T_SYNC_COUNT_M) >> \ + HTT_H2T_SYNC_COUNT_S) +#define HTT_H2T_SYNC_COUNT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_SYNC_COUNT, _val); \ + ((_var) |= ((_val) << HTT_H2T_SYNC_COUNT_S)); \ + } while (0) + + +/** + * @brief HTT aggregation configuration + */ +#define HTT_AGGR_CFG_MSG_SZ 4 + +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_M 0xff00 +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S 8 +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_M 0x1f0000 +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S 16 + +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S) +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S)); \ + } while (0) + +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S) +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S)); \ + } while (0) + + +/** + * @brief host -> target HTT configure max amsdu info per vdev + * + * @details + * The HTT AGGR CFG EX tells the target to configure max_amsdu info per vdev + * + * |31 21|20 16|15 8|7 0| + * |-----------------------------------------------------------| + * | reserved | vdev id | max amsdu | msg type | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a aggr cfg ex message + * Value: 0xa + * - MAX_NUM_AMSDU_SUBFRM + * Bits 15:8 + * Purpose: max MSDUs per A-MSDU + * - VDEV_ID + * Bits 20:16 + * Purpose: ID of the vdev to which this limit is applied + */ +#define HTT_AGGR_CFG_EX_MSG_SZ 4 + +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_M 0xff00 +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S 8 +#define HTT_AGGR_CFG_EX_VDEV_ID_M 0x1f0000 +#define HTT_AGGR_CFG_EX_VDEV_ID_S 16 + +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S) +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S)); \ +} while (0) + +#define HTT_AGGR_CFG_EX_VDEV_ID_GET(_var) \ + (((_var) & HTT_AGGR_CFG_EX_VDEV_ID_M) >> \ + HTT_AGGR_CFG_EX_VDEV_ID_S) +#define HTT_AGGR_CFG_EX_VDEV_ID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_EX_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_EX_VDEV_ID_S)); \ +} while (0) + +/** + * @brief HTT WDI_IPA Config Message + * + * @details + * The HTT WDI_IPA config message is created/sent by host at driver + * init time. It contains information about data structures used on + * WDI_IPA TX and RX path. + * TX CE ring is used for pushing packet metadata from IPA uC + * to WLAN FW + * TX Completion ring is used for generating TX completions from + * WLAN FW to IPA uC + * RX Indication ring is used for indicating RX packets from FW + * to IPA uC + * RX Ring2 is used as either completion ring or as second + * indication ring. when Ring2 is used as completion ring, IPA uC + * puts completed RX packet meta data to Ring2. when Ring2 is used + * as second indication ring, RX packets for LTE-WLAN aggregation are + * indicated in Ring2, other RX packets (e.g. hotspot related) are + * indicated in RX Indication ring. Please see WDI_IPA specification + * for more details. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | tx pkt pool size | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * | tx comp ring base (bits 31:0) | +#if HTT_PADDR64 + * | tx comp ring base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | tx comp ring size | + * |-------------------------------------------------------------------| + * | tx comp WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | tx comp WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | tx CE WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | tx CE WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx indication ring base (bits 31:0) | +#if HTT_PADDR64 + * | rx indication ring base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx indication ring size | + * |-------------------------------------------------------------------| + * | rx ind RD_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ind RD_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ind WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ind WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * |-------------------------------------------------------------------| + * | rx ring2 base (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ring2 size | + * |-------------------------------------------------------------------| + * | rx ring2 RD_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 RD_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ring2 WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * + * Header fields: + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA config message + * value: = 0x8 + * - TX_PKT_POOL_SIZE + * Bits 15:0 + * Purpose: Total number of TX packet buffer pool allocated by Host for + * WDI_IPA TX path + * For systems using 32-bit format for bus addresses: + * - TX_COMP_RING_BASE_ADDR + * Bits 31:0 + * Purpose: TX Completion Ring base address in DDR + * - TX_COMP_RING_SIZE + * Bits 31:0 + * Purpose: TX Completion Ring size (must be power of 2) + * - TX_COMP_WR_IDX_ADDR + * Bits 31:0 + * Purpose: IPA doorbell register address OR DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_CE_WR_IDX_ADDR + * Bits 31:0 + * Purpose: DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - RX_IND_RING_BASE_ADDR + * Bits 31:0 + * Purpose: RX Indication Ring base address in DDR + * - RX_IND_RING_SIZE + * Bits 31:0 + * Purpose: RX Indication Ring size + * - RX_IND_RD_IDX_ADDR + * Bits 31:0 + * Purpose: DDR address where IPA uC updates the Read Index for WDI_IPA + * RX indication ring + * - RX_IND_WR_IDX_ADDR + * Bits 31:0 + * Purpose: IPA doorbell register address OR DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_RING2_BASE_ADDR + * Bits 31:0 + * Purpose: Second RX Ring(Indication or completion)base address in DDR + * - RX_RING2_SIZE + * Bits 31:0 + * Purpose: Second RX Ring size (must be >= RX_IND_RING_SIZE) + * - RX_RING2_RD_IDX_ADDR + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, DDR address where + * IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_WR_IDX_ADDR + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, DDR address where + * WIFI FW updates the Write Index for WDI_IPA RX ring2 + * If second RX ring is completion ring, DDR address where + * IPA uC updates the Write Index for Ring 2. + * For systems using 64-bit format for bus addresses: + * - TX_COMP_RING_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of TX Completion Ring base physical + * address in DDR + * - TX_COMP_RING_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of TX Completion Ring base physical + * address in DDR + * - TX_COMP_RING_SIZE + * Bits 31:0 + * Purpose: TX Completion Ring size (must be power of 2) + * - TX_COMP_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of IPA doorbell register address OR + * Lower 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_COMP_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of IPA doorbell register address OR + * Higher 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_CE_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - TX_CE_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - RX_IND_RING_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of RX Indication Ring base address in DDR + * - RX_IND_RING_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of RX Indication Ring base address in DDR + * - RX_IND_RING_SIZE + * Bits 31:0 + * Purpose: RX Indication Ring size + * - RX_IND_RD_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of DDR address where IPA uC updates the + * Read Index for WDI_IPA RX indication ring + * - RX_IND_RD_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of DDR address where IPA uC updates the + * Read Index for WDI_IPA RX indication ring + * - RX_IND_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of IPA doorbell register address OR + * Lower 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_IND_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of IPA doorbell register address OR + * Higher 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_RING2_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of Second RX Ring(Indication OR completion) + * base address in DDR + * - RX_RING2_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of Second RX Ring(Indication OR completion) + * base address in DDR + * - RX_RING2_SIZE + * Bits 31:0 + * Purpose: Second RX Ring size (must be >= RX_IND_RING_SIZE) + * - RX_RING2_RD_IDX_ADDR_LO + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, lower 4 bytes of + * DDR address where IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_RD_IDX_ADDR_HI + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, higher 4 bytes of + * DDR address where IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, lower 4 bytes of + * DDR address where WIFI FW updates the Write Index + * for WDI_IPA RX ring2 + * If second RX ring is completion ring, lower 4 bytes of + * DDR address where IPA uC updates the Write Index for Ring 2. + * - RX_RING2_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, higher 4 bytes of + * DDR address where WIFI FW updates the Write Index + * for WDI_IPA RX ring2 + * If second RX ring is completion ring, higher 4 bytes of + * DDR address where IPA uC updates the Write Index for Ring 2. + */ + +#if HTT_PADDR64 +#define HTT_WDI_IPA_CFG_SZ 88 /* bytes */ +#else +#define HTT_WDI_IPA_CFG_SZ 52 /* bytes */ +#endif + +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_M 0xffff0000 +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S 16 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_M) >> \ + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S) +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR, _val);\ + ((_var) |= \ + ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI, _val);\ + ((_var) |= \ + ((_val) << \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S)); \ +} while (0) + + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_M) >>\ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_SIZE_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_SIZE_S) +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_SIZE_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S)); \ +} while (0) + +/* + * TEMPLATE_HTT_WDI_IPA_CONFIG_T: + * This macro defines a htt_wdi_ipa_configXXX_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_wdi_ipa_config32_t and + * htt_wdi_ipa_config64_t structs. + */ +#define TEMPLATE_HTT_WDI_IPA_CONFIG_T(_paddr_bits_, \ + _paddr__tx_comp_ring_base_addr_, \ + _paddr__tx_comp_wr_idx_addr_, \ + _paddr__tx_ce_wr_idx_addr_, \ + _paddr__rx_ind_ring_base_addr_, \ + _paddr__rx_ind_rd_idx_addr_, \ + _paddr__rx_ind_wr_idx_addr_, \ + _paddr__rx_ring2_base_addr_,\ + _paddr__rx_ring2_rd_idx_addr_,\ + _paddr__rx_ring2_wr_idx_addr_) \ +PREPACK struct htt_wdi_ipa_cfg ## _paddr_bits_ ## _t \ +{ \ + /* DWORD 0: flags and meta-data */ \ + A_UINT32 \ + msg_type:8, /* HTT_H2T_MSG_TYPE_WDI_IPA_CFG */ \ + reserved:8, \ + tx_pkt_pool_size:16;\ + /* DWORD 1 */\ + _paddr__tx_comp_ring_base_addr_;\ + /* DWORD 2 (or 3)*/\ + A_UINT32 tx_comp_ring_size;\ + /* DWORD 3 (or 4)*/\ + _paddr__tx_comp_wr_idx_addr_;\ + /* DWORD 4 (or 6)*/\ + _paddr__tx_ce_wr_idx_addr_;\ + /* DWORD 5 (or 8)*/\ + _paddr__rx_ind_ring_base_addr_;\ + /* DWORD 6 (or 10)*/\ + A_UINT32 rx_ind_ring_size;\ + /* DWORD 7 (or 11)*/\ + _paddr__rx_ind_rd_idx_addr_;\ + /* DWORD 8 (or 13)*/\ + _paddr__rx_ind_wr_idx_addr_;\ + /* DWORD 9 (or 15)*/\ + _paddr__rx_ring2_base_addr_;\ + /* DWORD 10 (or 17) */\ + A_UINT32 rx_ring2_size;\ + /* DWORD 11 (or 18) */\ + _paddr__rx_ring2_rd_idx_addr_;\ + /* DWORD 12 (or 20) */\ + _paddr__rx_ring2_wr_idx_addr_;\ +} POSTPACK + +/* define a htt_wdi_ipa_config32_t type */ +TEMPLATE_HTT_WDI_IPA_CONFIG_T(32, HTT_VAR_PADDR32(tx_comp_ring_base_addr), + HTT_VAR_PADDR32(tx_comp_wr_idx_addr), + HTT_VAR_PADDR32(tx_ce_wr_idx_addr), + HTT_VAR_PADDR32(rx_ind_ring_base_addr), + HTT_VAR_PADDR32(rx_ind_rd_idx_addr), + HTT_VAR_PADDR32(rx_ind_wr_idx_addr), + HTT_VAR_PADDR32(rx_ring2_base_addr), + HTT_VAR_PADDR32(rx_ring2_rd_idx_addr), + HTT_VAR_PADDR32(rx_ring2_wr_idx_addr)); + +/* define a htt_wdi_ipa_config64_t type */ +TEMPLATE_HTT_WDI_IPA_CONFIG_T(64, HTT_VAR_PADDR64_LE(tx_comp_ring_base_addr), + HTT_VAR_PADDR64_LE(tx_comp_wr_idx_addr), + HTT_VAR_PADDR64_LE(tx_ce_wr_idx_addr), + HTT_VAR_PADDR64_LE(rx_ind_ring_base_addr), + HTT_VAR_PADDR64_LE(rx_ind_rd_idx_addr), + HTT_VAR_PADDR64_LE(rx_ind_wr_idx_addr), + HTT_VAR_PADDR64_LE(rx_ring2_base_addr), + HTT_VAR_PADDR64_LE(rx_ring2_rd_idx_addr), + HTT_VAR_PADDR64_LE(rx_ring2_wr_idx_addr)); + +#if HTT_PADDR64 +#define htt_wdi_ipa_cfg_t htt_wdi_ipa_cfg64_t +#else +#define htt_wdi_ipa_cfg_t htt_wdi_ipa_cfg32_t +#endif + +enum htt_wdi_ipa_op_code { + HTT_WDI_IPA_OPCODE_TX_SUSPEND = 0, + HTT_WDI_IPA_OPCODE_TX_RESUME = 1, + HTT_WDI_IPA_OPCODE_RX_SUSPEND = 2, + HTT_WDI_IPA_OPCODE_RX_RESUME = 3, + HTT_WDI_IPA_OPCODE_DBG_STATS = 4, + /* keep this last */ + HTT_WDI_IPA_OPCODE_MAX +}; + +/** + * @brief HTT WDI_IPA Operation Request Message + * + * @details + * HTT WDI_IPA Operation Request message is sent by host + * to either suspend or resume WDI_IPA TX or RX path. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | op_code | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA Operation Request message + * value: = 0x9 + * - OP_CODE + * Bits 31:16 + * Purpose: Identifies operation host is requesting (e.g. TX suspend) + * value: = enum htt_wdi_ipa_op_code + */ + +PREPACK struct htt_wdi_ipa_op_request_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 + msg_type:8, /* HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQUEST */ + reserved:8, + op_code:16; +} POSTPACK; + +#define HTT_WDI_IPA_OP_REQUEST_SZ 4 /* bytes */ + +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_M 0xffff0000 +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_S 16 + +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQUEST_OP_CODE_M) >> \ + HTT_WDI_IPA_OP_REQUEST_OP_CODE_S) +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_REQUEST_OP_CODE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_REQUEST_OP_CODE_S)); \ + } while (0) + + + + +/*=== target -> host messages ===============================================*/ + + +enum htt_t2h_msg_type { + HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0, + HTT_T2H_MSG_TYPE_RX_IND = 0x1, + HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2, + HTT_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4, + HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5, + HTT_T2H_MSG_TYPE_RX_DELBA = 0x6, + HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7, + HTT_T2H_MSG_TYPE_PKTLOG = 0x8, + HTT_T2H_MSG_TYPE_STATS_CONF = 0x9, + HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa, + HTT_T2H_MSG_TYPE_SEC_IND = 0xb, + DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,/* no longer used */ + HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, + HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe, + /* only used for HL, add HTT MSG for HTT CREDIT update */ + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf, + HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10, + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11, + HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12, + /* 0x13 is reserved for RX_RING_LOW_IND (RX Full reordering related) */ + HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14, + HTT_T2H_MSG_TYPE_CHAN_CHANGE = 0x15, + HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR = 0x16, + HTT_T2H_MSG_TYPE_RATE_REPORT = 0x17, + HTT_T2H_MSG_TYPE_FLOW_POOL_MAP = 0x18, + HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP = 0x19, + + HTT_T2H_MSG_TYPE_TEST, + /* keep this last */ + HTT_T2H_NUM_MSGS +}; + +/* + * HTT target to host message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_T2H_MSG_TYPE_M 0xff +#define HTT_T2H_MSG_TYPE_S 0 + +#define HTT_T2H_MSG_TYPE_SET(word, msg_type) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_MSG_TYPE, msg_type); \ + (word) |= ((msg_type) << HTT_T2H_MSG_TYPE_S); \ + } while (0) +#define HTT_T2H_MSG_TYPE_GET(word) \ + (((word) & HTT_T2H_MSG_TYPE_M) >> HTT_T2H_MSG_TYPE_S) + +/** + * @brief target -> host version number confirmation message definition + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | major number | minor number | msg type | + * |-------------------------------------------------------------------| + * : option request TLV (optional) | + * :...................................................................: + * + * The VER_CONF message may consist of a single 4-byte word, or may be + * extended with TLVs that specify HTT options selected by the target. + * The following option TLVs may be appended to the VER_CONF message: + * - LL_BUS_ADDR_SIZE + * - HL_SUPPRESS_TX_COMPL_IND + * - MAX_TX_QUEUE_GROUPS + * These TLVs may appear in an arbitrary order. Any number of these TLVs + * may be appended to the VER_CONF message (but only one TLV of each type). + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a version number confirmation message + * Value: 0x0 + * - VER_MINOR + * Bits 15:8 + * Purpose: Specify the minor number of the HTT message library version + * in use by the target firmware. + * The minor number specifies the specific revision within a range + * of fundamentally compatible HTT message definition revisions. + * Compatible revisions involve adding new messages or perhaps + * adding new fields to existing messages, in a backwards-compatible + * manner. + * Incompatible revisions involve changing the message type values, + * or redefining existing messages. + * Value: minor number + * - VER_MAJOR + * Bits 15:8 + * Purpose: Specify the major number of the HTT message library version + * in use by the target firmware. + * The major number specifies the family of minor revisions that are + * fundamentally compatible with each other, but not with prior or + * later families. + * Value: major number + */ + +#define HTT_VER_CONF_MINOR_M 0x0000ff00 +#define HTT_VER_CONF_MINOR_S 8 +#define HTT_VER_CONF_MAJOR_M 0x00ff0000 +#define HTT_VER_CONF_MAJOR_S 16 + + +#define HTT_VER_CONF_MINOR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_VER_CONF_MINOR, value); \ + (word) |= (value) << HTT_VER_CONF_MINOR_S; \ + } while (0) +#define HTT_VER_CONF_MINOR_GET(word) \ + (((word) & HTT_VER_CONF_MINOR_M) >> HTT_VER_CONF_MINOR_S) + +#define HTT_VER_CONF_MAJOR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_VER_CONF_MAJOR, value); \ + (word) |= (value) << HTT_VER_CONF_MAJOR_S; \ + } while (0) +#define HTT_VER_CONF_MAJOR_GET(word) \ + (((word) & HTT_VER_CONF_MAJOR_M) >> HTT_VER_CONF_MAJOR_S) + + +#define HTT_VER_CONF_BYTES 4 + + +/** + * @brief - target -> host HTT Rx In order indication message + * + * @details + * + * |31 24|23 |15|14|13|12|11|10|9|8|7|6|5|4 0| + * |----------------+-------------------+---------------------+---------------| + * | peer ID | | F| O| ext TID | msg type | + * |--------------------------------------------------------------------------| + * | MSDU count | Reserved | vdev id | + * |--------------------------------------------------------------------------| + * | MSDU 0 bus address (bits 31:0) | + #if HTT_PADDR64 + * | MSDU 0 bus address (bits 63:32) | + #endif + * |--------------------------------------------------------------------------| + * | MSDU info | MSDU 0 FW Desc | MSDU 0 Length | + * |--------------------------------------------------------------------------| + * | MSDU 1 bus address (bits 31:0) | + #if HTT_PADDR64 + * | MSDU 1 bus address (bits 63:32) | + #endif + * |--------------------------------------------------------------------------| + * | MSDU info | MSDU 1 FW Desc | MSDU 1 Length | + * |--------------------------------------------------------------------------| + */ + + +/** @brief - MSDU info byte for TCP_CHECKSUM_OFFLOAD use + * + * @details + * bits + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * |-----+----+-------+--------+--------+---------+---------+-----------| + * | reserved | is IP | is UDP | is TCP | is IPv6 |IP chksum| TCP/UDP | + * | | frag | | | | fail |chksum fail| + * |-----+----+-------+--------+--------+---------+---------+-----------| + * (see fw_rx_msdu_info def in wal_rx_desc.h) + */ + +struct htt_rx_in_ord_paddr_ind_hdr_t { + A_UINT32 /* word 0 */ + msg_type:8, + ext_tid:5, + offload:1, + frag:1, + reserved_0:1, + peer_id:16; + + A_UINT32 /* word 1 */ + vap_id:8, + reserved_1:8, + msdu_cnt:16; +}; + +struct htt_rx_in_ord_paddr_ind_msdu32_t { + A_UINT32 dma_addr; + A_UINT32 + length:16, + fw_desc:8, + msdu_info:8; +}; +struct htt_rx_in_ord_paddr_ind_msdu64_t { + A_UINT32 dma_addr_lo; + A_UINT32 dma_addr_hi; + A_UINT32 + length:16, + fw_desc:8, + msdu_info:8; +}; +#if HTT_PADDR64 +#define htt_rx_in_ord_paddr_ind_msdu_t htt_rx_in_ord_paddr_ind_msdu64_t +#else +#define htt_rx_in_ord_paddr_ind_msdu_t htt_rx_in_ord_paddr_ind_msdu32_t +#endif + + +#define HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES \ + (sizeof(struct htt_rx_in_ord_paddr_ind_hdr_t)) +#define HTT_RX_IN_ORD_PADDR_IND_HDR_DWORDS \ + (HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTE_OFFSET \ + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORD_OFFSET \ + HTT_RX_IN_ORD_PADDR_IND_HDR_DWORDS +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_64 \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu64_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS_64 \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_64 >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_32 \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu32_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS_32 \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_32 >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES >> 2) + +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_M 0x00001f00 +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S 8 +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_M 0x00002000 +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_S 13 +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_M 0x00004000 +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_S 14 +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_M 0xffff0000 +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S 16 +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_M 0x000000ff +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_M 0xffff0000 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S 16 +/* for systems using 64-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S 0 +/* for systems using 32-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_M 0x0000ffff +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_M 0x00ff0000 +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S 16 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_M 0xff000000 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S 24 + + +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_EXT_TID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_EXT_TID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PEER_ID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_VAP_ID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_VAP_ID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S) + +/* for systems using 64-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR_HI, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR_LO, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S) + +/* for systems using 32-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN, value);\ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S) + +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_FW_DESC, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_FW_DESC_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO, value);\ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S;\ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S) + +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_IND_OFFLOAD, value);\ + (word) |= (value) << HTT_RX_IN_ORD_IND_OFFLOAD_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_S) + +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_IND_FRAG, value); \ + (word) |= (value) << HTT_RX_IN_ORD_IND_FRAG_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_FRAG_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_FRAG_S) + +/* definitions used within target -> host rx indication message */ + +PREPACK struct htt_rx_ind_hdr_prefix_t { + A_UINT32 /* word 0 */ + msg_type:8, + ext_tid:5, + release_valid:1, + flush_valid:1, + reserved0:1, + peer_id:16; + + A_UINT32 /* word 1 */ + flush_start_seq_num:6, + flush_end_seq_num:6, + release_start_seq_num:6, + release_end_seq_num:6, + num_mpdu_ranges:8; +} POSTPACK; + +#define HTT_RX_IND_HDR_PREFIX_BYTES (sizeof(struct htt_rx_ind_hdr_prefix_t)) +#define HTT_RX_IND_HDR_PREFIX_SIZE32 (HTT_RX_IND_HDR_PREFIX_BYTES >> 2) + +#define HTT_TGT_RSSI_INVALID 0x80 + +PREPACK struct htt_rx_ppdu_desc_t { +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI_CMB 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_TIMESTAMP_SUBMICROSEC 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_PHY_ERR_CODE 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_PHY_ERR 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_LEGACY_RATE 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_LEGACY_RATE_SEL 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_END_VALID 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_START_VALID 0 + A_UINT32 /* word 0 */ + rssi_cmb:8, + timestamp_submicrosec:8, + phy_err_code:8, + phy_err:1, + legacy_rate:4, + legacy_rate_sel:1, + end_valid:1, + start_valid:1; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI0 1 + union { + A_UINT32 /* word 1 */ + rssi0_pri20:8, + rssi0_ext20:8, + rssi0_ext40:8, + rssi0_ext80:8; + A_UINT32 rssi0; /* access all 20/40/80 per-b/w RSSIs together */ + } u0; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI1 2 + union { + A_UINT32 /* word 2 */ + rssi1_pri20:8, + rssi1_ext20:8, + rssi1_ext40:8, + rssi1_ext80:8; + A_UINT32 rssi1; /* access all 20/40/80 per-b/w RSSIs together */ + } u1; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI2 3 + union { + A_UINT32 /* word 3 */ + rssi2_pri20:8, + rssi2_ext20:8, + rssi2_ext40:8, + rssi2_ext80:8; + A_UINT32 rssi2; /* access all 20/40/80 per-b/w RSSIs together */ + } u2; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI3 4 + union { + A_UINT32 /* word 4 */ + rssi3_pri20:8, + rssi3_ext20:8, + rssi3_ext40:8, + rssi3_ext80:8; + A_UINT32 rssi3; /* access all 20/40/80 per-b/w RSSIs together */ + } u3; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_TSF32 5 + A_UINT32 tsf32; /* word 5 */ + +#define HTT_RX_IND_PPDU_OFFSET_WORD_TIMESTAMP_MICROSEC 6 + A_UINT32 timestamp_microsec; /* word 6 */ + +#define HTT_RX_IND_PPDU_OFFSET_WORD_PREAMBLE_TYPE 7 +#define HTT_RX_IND_PPDU_OFFSET_WORD_VHT_SIG_A1 7 + A_UINT32 /* word 7 */ + vht_sig_a1:24, + preamble_type:8; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_VHT_SIG_A2 8 + A_UINT32 /* word 8 */ + vht_sig_a2:24, + reserved0:8; +} POSTPACK; + +#define HTT_RX_PPDU_DESC_BYTES (sizeof(struct htt_rx_ppdu_desc_t)) +#define HTT_RX_PPDU_DESC_SIZE32 (HTT_RX_PPDU_DESC_BYTES >> 2) + +PREPACK struct htt_rx_ind_hdr_suffix_t { + A_UINT32 /* word 0 */ + fw_rx_desc_bytes:16, + reserved0:16; +} POSTPACK; + +#define HTT_RX_IND_HDR_SUFFIX_BYTES (sizeof(struct htt_rx_ind_hdr_suffix_t)) +#define HTT_RX_IND_HDR_SUFFIX_SIZE32 (HTT_RX_IND_HDR_SUFFIX_BYTES >> 2) + +PREPACK struct htt_rx_ind_hdr_t { + struct htt_rx_ind_hdr_prefix_t prefix; + struct htt_rx_ppdu_desc_t rx_ppdu_desc; + struct htt_rx_ind_hdr_suffix_t suffix; +} POSTPACK; + +#define HTT_RX_IND_HDR_BYTES (sizeof(struct htt_rx_ind_hdr_t)) +#define HTT_RX_IND_HDR_SIZE32 (HTT_RX_IND_HDR_BYTES >> 2) + +/* confirm that HTT_RX_IND_HDR_BYTES is a multiple of 4 */ +A_COMPILE_TIME_ASSERT(HTT_RX_IND_hdr_size_quantum, + (HTT_RX_IND_HDR_BYTES & 0x3) == 0); + +/* + * HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the + * FW rx PPDU descriptor resides + */ +#define HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET HTT_RX_IND_HDR_PREFIX_BYTES + +/* + * HTT_RX_IND_HDR_SUFFIX_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the + * header suffix (FW rx MSDU byte count) resides + */ +#define HTT_RX_IND_HDR_SUFFIX_BYTE_OFFSET \ + (HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET + HTT_RX_PPDU_DESC_BYTES) + +/* + * HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the per-MSDU + * information starts + * Bytes 0-7 are the message header; bytes 8-11 contain the length of the + * per-MSDU information portion of the message. The per-MSDU info itself + * starts at byte 12. + */ +#define HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET HTT_RX_IND_HDR_BYTES + + +/** + * @brief target -> host rx indication message definition + * + * @details + * The following field definitions describe the format of the rx indication + * message sent from the target to the host. + * The message consists of three major sections: + * 1. a fixed-length header + * 2. a variable-length list of firmware rx MSDU descriptors + * 3. one or more 4-octet MPDU range information elements + * The fixed length header itself has two sub-sections + * 1. the message meta-information, including identification of the + * sender and type of the received data, and a 4-octet flush/release IE + * 2. the firmware rx PPDU descriptor + * + * The format of the message is depicted below. + * in this depiction, the following abbreviations are used for information + * elements within the message: + * - SV - start valid: this flag is set if the FW rx PPDU descriptor + * elements associated with the PPDU start are valid. + * Specifically, the following fields are valid only if SV is set: + * RSSI (all variants), L, legacy rate, preamble type, service, + * VHT-SIG-A + * - EV - end valid: this flag is set if the FW rx PPDU descriptor + * elements associated with the PPDU end are valid. + * Specifically, the following fields are valid only if EV is set: + * P, PHY err code, TSF, microsec / sub-microsec timestamp + * - L - Legacy rate selector - if legacy rates are used, this flag + * indicates whether the rate is from a CCK (L == 1) or OFDM + * (L == 0) PHY. + * - P - PHY error flag - boolean indication of whether the rx frame had + * a PHY error + * + * |31 24|23 18|17|16|15|14|13|12|11|10|9|8|7|6|5|4 0| + * |----------------+-------------------+---------------------+---------------| + * | peer ID | |RV|FV| ext TID | msg type | + * |--------------------------------------------------------------------------| + * | num | release | release | flush | flush | + * | MPDU | end | start | end | start | + * | ranges | seq num | seq num | seq num | seq num | + * |==========================================================================| + * |S|E|L| legacy |P| PHY err code | sub-microsec | combined | + * |V|V| | rate | | | timestamp | RSSI | + * |--------------------------------------------------------------------------| + * | RSSI rx0 ext80 | RSSI rx0 ext40 | RSSI rx0 ext20 | RSSI rx0 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx1 ext80 | RSSI rx1 ext40 | RSSI rx1 ext20 | RSSI rx1 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx2 ext80 | RSSI rx2 ext40 | RSSI rx2 ext20 | RSSI rx2 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx3 ext80 | RSSI rx3 ext40 | RSSI rx3 ext20 | RSSI rx3 pri20| + * |--------------------------------------------------------------------------| + * | TSF LSBs | + * |--------------------------------------------------------------------------| + * | microsec timestamp | + * |--------------------------------------------------------------------------| + * | preamble type | HT-SIG / VHT-SIG-A1 | + * |--------------------------------------------------------------------------| + * | service | HT-SIG / VHT-SIG-A2 | + * |==========================================================================| + * | reserved | FW rx desc bytes | + * |--------------------------------------------------------------------------| + * | MSDU Rx | MSDU Rx | MSDU Rx | MSDU Rx | + * | desc B3 | desc B2 | desc B1 | desc B0 | + * |--------------------------------------------------------------------------| + * : : : + * |--------------------------------------------------------------------------| + * | alignment | MSDU Rx | + * | padding | desc Bn | + * |--------------------------------------------------------------------------| + * | reserved | MPDU range status | MPDU count | + * |--------------------------------------------------------------------------| + * : reserved : MPDU range status : MPDU count : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - : + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx indication message + * Value: 0x1 + * - EXT_TID + * Bits 12:8 + * Purpose: identify the traffic ID of the rx data, including + * special "extended" TID values for multicast, broadcast, and + * non-QoS data frames + * Value: 0-15 for regular TIDs, or >= 16 for bcast/mcast/non-QoS + * - FLUSH_VALID (FV) + * Bit 13 + * Purpose: indicate whether the flush IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> flush IE is valid and needs to be processed + * 0 -> flush IE is not valid and should be ignored + * - REL_VALID (RV) + * Bit 13 + * Purpose: indicate whether the release IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> release IE is valid and needs to be processed + * 0 -> release IE is not valid and should be ignored + * - PEER_ID + * Bits 31:16 + * Purpose: Identify, by ID, which peer sent the rx data + * Value: ID of the peer who sent the rx data + * - FLUSH_SEQ_NUM_START + * Bits 5:0 + * Purpose: Indicate the start of a series of MPDUs to flush + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Value: + * The sequence number for the first MPDUs to check to flush. + * The sequence number is masked by 0x3f. + * - FLUSH_SEQ_NUM_END + * Bits 11:6 + * Purpose: Indicate the end of a series of MPDUs to flush + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to flush. + * The sequence number is masked by 0x3f. + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * - REL_SEQ_NUM_START + * Bits 17:12 + * Purpose: Indicate the start of a series of MPDUs to release. + * All MPDUs within this series are present and valid - the host + * need not check each sequence number within this range to see if + * the corresponding MPDU is actually present. + * This field is only valid if the RV bit is set. + * Value: + * The sequence number for the first MPDUs to check to release. + * The sequence number is masked by 0x3f. + * - REL_SEQ_NUM_END + * Bits 23:18 + * Purpose: Indicate the end of a series of MPDUs to release. + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to release. + * The sequence number is masked by 0x3f. + * All MPDUs within this series are present and valid - the host + * need not check each sequence number within this range to see if + * the corresponding MPDU is actually present. + * This field is only valid if the RV bit is set. + * - NUM_MPDU_RANGES + * Bits 31:24 + * Purpose: Indicate how many ranges of MPDUs are present. + * Each MPDU range consists of a series of contiguous MPDUs within the + * rx frame sequence which all have the same MPDU status. + * Value: 1-63 (typically a small number, like 1-3) + * + * Rx PPDU descriptor fields: + * - RSSI_CMB + * Bits 7:0 + * Purpose: Combined RSSI from all active rx chains, across the active + * bandwidth. + * Value: RSSI dB units w.r.t. noise floor + * - TIMESTAMP_SUBMICROSEC + * Bits 15:8 + * Purpose: high-resolution timestamp + * Value: + * Sub-microsecond time of PPDU reception. + * This timestamp ranges from [0,MAC clock MHz). + * This timestamp can be used in conjunction with TIMESTAMP_MICROSEC + * to form a high-resolution, large range rx timestamp. + * - PHY_ERR_CODE + * Bits 23:16 + * Purpose: + * If the rx frame processing resulted in a PHY error, indicate what + * type of rx PHY error occurred. + * Value: + * This field is valid if the "P" (PHY_ERR) flag is set. + * TBD: document/specify the values for this field + * - PHY_ERR + * Bit 24 + * Purpose: indicate whether the rx PPDU had a PHY error + * Value: 0 -> no rx PHY error, 1 -> rx PHY error encountered + * - LEGACY_RATE + * Bits 28:25 + * Purpose: + * If the rx frame used a legacy rate rather than a HT or VHT rate, + * specify which rate was used. + * Value: + * The LEGACY_RATE field's value depends on the "L" (LEGACY_RATE_SEL) + * flag. + * If LEGACY_RATE_SEL is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If LEGACY_RATE_SEL is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * - LEGACY_RATE_SEL + * Bit 29 + * Purpose: if rx used a legacy rate, specify whether it was OFDM or CCK + * Value: + * This field is valid if the PREAMBLE_TYPE field indicates the rx + * used a legacy rate. + * 0 -> OFDM, 1 -> CCK + * - END_VALID + * Bit 30 + * Purpose: Indicate whether the FW rx PPDU desc fields associated with + * the start of the PPDU are valid. Specifically, the following + * fields are only valid if END_VALID is set: + * PHY_ERR, PHY_ERR_CODE, TSF32, TIMESTAMP_MICROSEC, + * TIMESTAMP_SUBMICROSEC + * Value: + * 0 -> rx PPDU desc end fields are not valid + * 1 -> rx PPDU desc end fields are valid + * - START_VALID + * Bit 31 + * Purpose: Indicate whether the FW rx PPDU desc fields associated with + * the end of the PPDU are valid. Specifically, the following + * fields are only valid if START_VALID is set: + * RSSI, LEGACY_RATE_SEL, LEGACY_RATE, PREAMBLE_TYPE, SERVICE, + * VHT-SIG-A + * Value: + * 0 -> rx PPDU desc start fields are not valid + * 1 -> rx PPDU desc start fields are valid + * - RSSI0_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI0_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI0_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI0_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI1_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI2_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI3_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - TSF32 + * Bits 31:0 + * Purpose: specify the time the rx PPDU was received, in TSF units + * Value: 32 LSBs of the TSF + * - TIMESTAMP_MICROSEC + * Bits 31:0 + * Purpose: specify the time the rx PPDU was received, in microsecond units + * Value: PPDU rx time, in microseconds + * - VHT_SIG_A1 + * Bits 23:0 + * Purpose: Provide the HT-SIG (initial 24 bits) or VHT-SIG-A1 field + * from the rx PPDU + * Value: + * If PREAMBLE_TYPE specifies VHT, then this field contains the + * VHT-SIG-A1 data. + * If PREAMBLE_TYPE specifies HT, then this field contains the + * first 24 bits of the HT-SIG data. + * Otherwise, this field is invalid. + * Refer to the the 802.11 protocol for the definition of the + * HT-SIG and VHT-SIG-A1 fields + * - VHT_SIG_A2 + * Bits 23:0 + * Purpose: Provide the HT-SIG (final 24 bits) or VHT-SIG-A2 field + * from the rx PPDU + * Value: + * If PREAMBLE_TYPE specifies VHT, then this field contains the + * VHT-SIG-A2 data. + * If PREAMBLE_TYPE specifies HT, then this field contains the + * last 24 bits of the HT-SIG data. + * Otherwise, this field is invalid. + * Refer to the the 802.11 protocol for the definition of the + * HT-SIG and VHT-SIG-A2 fields + * - PREAMBLE_TYPE + * Bits 31:24 + * Purpose: indicate the PHY format of the received burst + * Value: + * 0x4: Legacy (OFDM/CCK) + * 0x8: HT + * 0x9: HT with TxBF + * 0xC: VHT + * 0xD: VHT with TxBF + * - SERVICE + * Bits 31:24 + * Purpose: TBD + * Value: TBD + * + * Rx MSDU descriptor fields: + * - FW_RX_DESC_BYTES + * Bits 15:0 + * Purpose: Indicate how many bytes in the Rx indication are used for + * FW Rx descriptors + * + * Payload fields: + * - MPDU_COUNT + * Bits 7:0 + * Purpose: Indicate how many sequential MPDUs share the same status. + * All MPDUs within the indicated list are from the same RA-TA-TID. + * - MPDU_STATUS + * Bits 15:8 + * Purpose: Indicate whether the (group of sequential) MPDU(s) were + * received successfully. + * Value: + * 0x1: success + * 0x2: FCS error + * 0x3: duplicate error + * 0x4: replay error + * 0x5: invalid peer + */ +/* header fields */ +#define HTT_RX_IND_EXT_TID_M 0x1f00 +#define HTT_RX_IND_EXT_TID_S 8 +#define HTT_RX_IND_FLUSH_VALID_M 0x2000 +#define HTT_RX_IND_FLUSH_VALID_S 13 +#define HTT_RX_IND_REL_VALID_M 0x4000 +#define HTT_RX_IND_REL_VALID_S 14 +#define HTT_RX_IND_PEER_ID_M 0xffff0000 +#define HTT_RX_IND_PEER_ID_S 16 + +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_M 0x3f +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_S 0 +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_M 0xfc0 +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_S 6 +#define HTT_RX_IND_REL_SEQ_NUM_START_M 0x3f000 +#define HTT_RX_IND_REL_SEQ_NUM_START_S 12 +#define HTT_RX_IND_REL_SEQ_NUM_END_M 0xfc0000 +#define HTT_RX_IND_REL_SEQ_NUM_END_S 18 +#define HTT_RX_IND_NUM_MPDU_RANGES_M 0xff000000 +#define HTT_RX_IND_NUM_MPDU_RANGES_S 24 + +/* rx PPDU descriptor fields */ +#define HTT_RX_IND_RSSI_CMB_M 0x000000ff +#define HTT_RX_IND_RSSI_CMB_S 0 +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_M 0x0000ff00 +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S 8 +#define HTT_RX_IND_PHY_ERR_CODE_M 0x00ff0000 +#define HTT_RX_IND_PHY_ERR_CODE_S 16 +#define HTT_RX_IND_PHY_ERR_M 0x01000000 +#define HTT_RX_IND_PHY_ERR_S 24 +#define HTT_RX_IND_LEGACY_RATE_M 0x1e000000 +#define HTT_RX_IND_LEGACY_RATE_S 25 +#define HTT_RX_IND_LEGACY_RATE_SEL_M 0x20000000 +#define HTT_RX_IND_LEGACY_RATE_SEL_S 29 +#define HTT_RX_IND_END_VALID_M 0x40000000 +#define HTT_RX_IND_END_VALID_S 30 +#define HTT_RX_IND_START_VALID_M 0x80000000 +#define HTT_RX_IND_START_VALID_S 31 + +#define HTT_RX_IND_RSSI_PRI20_M 0x000000ff +#define HTT_RX_IND_RSSI_PRI20_S 0 +#define HTT_RX_IND_RSSI_EXT20_M 0x0000ff00 +#define HTT_RX_IND_RSSI_EXT20_S 8 +#define HTT_RX_IND_RSSI_EXT40_M 0x00ff0000 +#define HTT_RX_IND_RSSI_EXT40_S 16 +#define HTT_RX_IND_RSSI_EXT80_M 0xff000000 +#define HTT_RX_IND_RSSI_EXT80_S 24 + +#define HTT_RX_IND_VHT_SIG_A1_M 0x00ffffff +#define HTT_RX_IND_VHT_SIG_A1_S 0 +#define HTT_RX_IND_VHT_SIG_A2_M 0x00ffffff +#define HTT_RX_IND_VHT_SIG_A2_S 0 +#define HTT_RX_IND_PREAMBLE_TYPE_M 0xff000000 +#define HTT_RX_IND_PREAMBLE_TYPE_S 24 +#define HTT_RX_IND_SERVICE_M 0xff000000 +#define HTT_RX_IND_SERVICE_S 24 + +/* rx MSDU descriptor fields */ +#define HTT_RX_IND_FW_RX_DESC_BYTES_M 0xffff +#define HTT_RX_IND_FW_RX_DESC_BYTES_S 0 + +/* payload fields */ +#define HTT_RX_IND_MPDU_COUNT_M 0xff +#define HTT_RX_IND_MPDU_COUNT_S 0 +#define HTT_RX_IND_MPDU_STATUS_M 0xff00 +#define HTT_RX_IND_MPDU_STATUS_S 8 + + +#define HTT_RX_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_EXT_TID, value); \ + (word) |= (value) << HTT_RX_IND_EXT_TID_S; \ + } while (0) +#define HTT_RX_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_IND_EXT_TID_M) >> HTT_RX_IND_EXT_TID_S) + +#define HTT_RX_IND_FLUSH_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_VALID, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_VALID_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_VALID_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_VALID_M) >> HTT_RX_IND_FLUSH_VALID_S) + +#define HTT_RX_IND_REL_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_VALID, value); \ + (word) |= (value) << HTT_RX_IND_REL_VALID_S; \ + } while (0) +#define HTT_RX_IND_REL_VALID_GET(word) \ + (((word) & HTT_RX_IND_REL_VALID_M) >> HTT_RX_IND_REL_VALID_S) + +#define HTT_RX_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_IND_PEER_ID_M) >> HTT_RX_IND_PEER_ID_S) + + +#define HTT_RX_IND_FW_RX_DESC_BYTES_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FW_RX_DESC_BYTES, value); \ + (word) |= (value) << HTT_RX_IND_FW_RX_DESC_BYTES_S; \ + } while (0) +#define HTT_RX_IND_FW_RX_DESC_BYTES_GET(word) \ + (((word) & HTT_RX_IND_FW_RX_DESC_BYTES_M) >> \ + HTT_RX_IND_FW_RX_DESC_BYTES_S) + + +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_SEQ_NUM_START_M) >> \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_S) + +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_SEQ_NUM_END_M) >> \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_S) + +#define HTT_RX_IND_REL_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_IND_REL_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_IND_REL_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_IND_REL_SEQ_NUM_START_M) >> \ + HTT_RX_IND_REL_SEQ_NUM_START_S) + +#define HTT_RX_IND_REL_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_IND_REL_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_IND_REL_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_IND_REL_SEQ_NUM_END_M) >> \ + HTT_RX_IND_REL_SEQ_NUM_END_S) + +#define HTT_RX_IND_NUM_MPDU_RANGES_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_NUM_MPDU_RANGES, value); \ + (word) |= (value) << HTT_RX_IND_NUM_MPDU_RANGES_S; \ + } while (0) +#define HTT_RX_IND_NUM_MPDU_RANGES_GET(word) \ + (((word) & HTT_RX_IND_NUM_MPDU_RANGES_M) >> \ + HTT_RX_IND_NUM_MPDU_RANGES_S) + +/* FW rx PPDU descriptor fields */ +#define HTT_RX_IND_RSSI_CMB_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_CMB, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_CMB_S; \ + } while (0) +#define HTT_RX_IND_RSSI_CMB_GET(word) \ + (((word) & HTT_RX_IND_RSSI_CMB_M) >> \ + HTT_RX_IND_RSSI_CMB_S) + +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_TIMESTAMP_SUBMICROSEC, value); \ + (word) |= (value) << HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S; \ + } while (0) +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(word) \ + (((word) & HTT_RX_IND_TIMESTAMP_SUBMICROSEC_M) >> \ + HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S) + +#define HTT_RX_IND_PHY_ERR_CODE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PHY_ERR_CODE, value); \ + (word) |= (value) << HTT_RX_IND_PHY_ERR_CODE_S; \ + } while (0) +#define HTT_RX_IND_PHY_ERR_CODE_GET(word) \ + (((word) & HTT_RX_IND_PHY_ERR_CODE_M) >> \ + HTT_RX_IND_PHY_ERR_CODE_S) + +#define HTT_RX_IND_PHY_ERR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PHY_ERR, value); \ + (word) |= (value) << HTT_RX_IND_PHY_ERR_S; \ + } while (0) +#define HTT_RX_IND_PHY_ERR_GET(word) \ + (((word) & HTT_RX_IND_PHY_ERR_M) >> \ + HTT_RX_IND_PHY_ERR_S) + +#define HTT_RX_IND_LEGACY_RATE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_LEGACY_RATE, value); \ + (word) |= (value) << HTT_RX_IND_LEGACY_RATE_S; \ + } while (0) +#define HTT_RX_IND_LEGACY_RATE_GET(word) \ + (((word) & HTT_RX_IND_LEGACY_RATE_M) >> \ + HTT_RX_IND_LEGACY_RATE_S) + +#define HTT_RX_IND_LEGACY_RATE_SEL_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_LEGACY_RATE_SEL, value); \ + (word) |= (value) << HTT_RX_IND_LEGACY_RATE_SEL_S; \ + } while (0) +#define HTT_RX_IND_LEGACY_RATE_SEL_GET(word) \ + (((word) & HTT_RX_IND_LEGACY_RATE_SEL_M) >> \ + HTT_RX_IND_LEGACY_RATE_SEL_S) + +#define HTT_RX_IND_END_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_END_VALID, value); \ + (word) |= (value) << HTT_RX_IND_END_VALID_S; \ + } while (0) +#define HTT_RX_IND_END_VALID_GET(word) \ + (((word) & HTT_RX_IND_END_VALID_M) >> \ + HTT_RX_IND_END_VALID_S) + +#define HTT_RX_IND_START_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_START_VALID, value); \ + (word) |= (value) << HTT_RX_IND_START_VALID_S; \ + } while (0) +#define HTT_RX_IND_START_VALID_GET(word) \ + (((word) & HTT_RX_IND_START_VALID_M) >> \ + HTT_RX_IND_START_VALID_S) + +#define HTT_RX_IND_RSSI_PRI20_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_PRI20, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_PRI20_S; \ + } while (0) +#define HTT_RX_IND_RSSI_PRI20_GET(word) \ + (((word) & HTT_RX_IND_RSSI_PRI20_M) >> \ + HTT_RX_IND_RSSI_PRI20_S) + +#define HTT_RX_IND_RSSI_EXT20_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT20, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT20_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT20_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT20_M) >> \ + HTT_RX_IND_RSSI_EXT20_S) + +#define HTT_RX_IND_RSSI_EXT40_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT40, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT40_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT40_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT40_M) >> \ + HTT_RX_IND_RSSI_EXT40_S) + +#define HTT_RX_IND_RSSI_EXT80_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT80, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT80_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT80_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT80_M) >> \ + HTT_RX_IND_RSSI_EXT80_S) + +#define HTT_RX_IND_VHT_SIG_A1_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_VHT_SIG_A1, value); \ + (word) |= (value) << HTT_RX_IND_VHT_SIG_A1_S; \ + } while (0) +#define HTT_RX_IND_VHT_SIG_A1_GET(word) \ + (((word) & HTT_RX_IND_VHT_SIG_A1_M) >> \ + HTT_RX_IND_VHT_SIG_A1_S) + +#define HTT_RX_IND_VHT_SIG_A2_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_VHT_SIG_A2, value); \ + (word) |= (value) << HTT_RX_IND_VHT_SIG_A2_S; \ + } while (0) +#define HTT_RX_IND_VHT_SIG_A2_GET(word) \ + (((word) & HTT_RX_IND_VHT_SIG_A2_M) >> \ + HTT_RX_IND_VHT_SIG_A2_S) + +#define HTT_RX_IND_PREAMBLE_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PREAMBLE_TYPE, value); \ + (word) |= (value) << HTT_RX_IND_PREAMBLE_TYPE_S; \ + } while (0) +#define HTT_RX_IND_PREAMBLE_TYPE_GET(word) \ + (((word) & HTT_RX_IND_PREAMBLE_TYPE_M) >> \ + HTT_RX_IND_PREAMBLE_TYPE_S) + +#define HTT_RX_IND_SERVICE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_SERVICE, value); \ + (word) |= (value) << HTT_RX_IND_SERVICE_S; \ + } while (0) +#define HTT_RX_IND_SERVICE_GET(word) \ + (((word) & HTT_RX_IND_SERVICE_M) >> \ + HTT_RX_IND_SERVICE_S) + + +#define HTT_RX_IND_MPDU_COUNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_MPDU_COUNT, value); \ + (word) |= (value) << HTT_RX_IND_MPDU_COUNT_S; \ + } while (0) +#define HTT_RX_IND_MPDU_COUNT_GET(word) \ + (((word) & HTT_RX_IND_MPDU_COUNT_M) >> HTT_RX_IND_MPDU_COUNT_S) + +#define HTT_RX_IND_MPDU_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_MPDU_STATUS, value); \ + (word) |= (value) << HTT_RX_IND_MPDU_STATUS_S; \ + } while (0) +#define HTT_RX_IND_MPDU_STATUS_GET(word) \ + (((word) & HTT_RX_IND_MPDU_STATUS_M) >> HTT_RX_IND_MPDU_STATUS_S) + + +#define HTT_RX_IND_HL_BYTES \ + (HTT_RX_IND_HDR_BYTES + \ + 4 /* single FW rx MSDU descriptor, plus padding */ + \ + 4 /* single MPDU range information element */) +#define HTT_RX_IND_HL_SIZE32 (HTT_RX_IND_HL_BYTES >> 2) + +/* Could we use one macro entry? */ +#define HTT_WORD_SET(word, field, value) \ + do { \ + HTT_CHECK_SET_VAL(field, value); \ + (word) |= ((value) << field ## _S); \ + } while (0) +#define HTT_WORD_GET(word, field) \ + (((word) & field ## _M) >> field ## _S) + +PREPACK struct hl_htt_rx_ind_base { + /* + * align with LL case rx indication message,but + * reduced to 5 words + */ + A_UINT32 rx_ind_msg[HTT_RX_IND_HL_SIZE32]; +} POSTPACK; + +/* + * HTT_RX_IND_HL_RX_DESC_BASE_OFFSET + * Currently, we use a resv field in hl_htt_rx_ind_base to store some + * HL host needed info. The field is just after the msdu fw rx desc. + */ +#define HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + (HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + 1) +struct htt_rx_ind_hl_rx_desc_t { + A_UINT8 ver; + A_UINT8 len; + struct { + A_UINT8 + first_msdu:1, + last_msdu:1, + c3_failed:1, + c4_failed:1, + ipv6:1, + tcp:1, + udp:1, + reserved:1; + } flags; +}; + +#define HTT_RX_IND_HL_RX_DESC_VER_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, ver)) +#define HTT_RX_IND_HL_RX_DESC_VER 0 + +#define HTT_RX_IND_HL_RX_DESC_LEN_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, len)) + +#define HTT_RX_IND_HL_FLAG_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, flags)) + +#define HTT_RX_IND_HL_FLAG_FIRST_MSDU (0x01 << 0) +#define HTT_RX_IND_HL_FLAG_LAST_MSDU (0x01 << 1) +#define HTT_RX_IND_HL_FLAG_C3_FAILED (0x01 << 2) /* L3 checksum failed */ +#define HTT_RX_IND_HL_FLAG_C4_FAILED (0x01 << 3) /* L4 checksum failed */ +#define HTT_RX_IND_HL_FLAG_IPV6 (0x01 << 4) /* is ipv6, or ipv4 */ +#define HTT_RX_IND_HL_FLAG_TCP (0x01 << 5) /* is tcp */ +#define HTT_RX_IND_HL_FLAG_UDP (0x01 << 6) /* is udp */ +/* This structure is used in HL, the basic descriptor information + * used by host. the structure is translated by FW from HW desc + * or generated by FW. But in HL monitor mode, the host would use + * the same structure with LL. + */ +PREPACK struct hl_htt_rx_desc_base { + A_UINT32 + seq_num:12, + encrypted:1, + chan_info_present:1, + resv0:2, + mcast_bcast:1, + fragment:1, + key_id_oct:8, + resv1:6; + A_UINT32 pn_31_0; + union { + struct { + A_UINT16 pn_47_32; + A_UINT16 pn_63_48; + } pn16; + A_UINT32 pn_63_32; + } u0; + A_UINT32 pn_95_64; + A_UINT32 pn_127_96; +} POSTPACK; + +/* + * Channel information can optionally be appended after hl_htt_rx_desc_base. + * If so, the len field in htt_rx_ind_hl_rx_desc_t will be updated accordingly, + * and the chan_info_present flag in hl_htt_rx_desc_base will be set. + * Please see htt_chan_change_t for description of the fields. + */ +PREPACK struct htt_chan_info_t +{ + A_UINT32 + primary_chan_center_freq_mhz:16, + contig_chan1_center_freq_mhz:16; + A_UINT32 + contig_chan2_center_freq_mhz:16, + phy_mode:8, + reserved:8; +} POSTPACK; + +#define HTT_CHAN_INFO_SIZE sizeof(struct htt_chan_info_t) + +#define HL_RX_DESC_SIZE (sizeof(struct hl_htt_rx_desc_base)) +#define HL_RX_DESC_SIZE_DWORD (HL_RX_STD_DESC_SIZE >> 2) + +#define HTT_HL_RX_DESC_MPDU_SEQ_NUM_M 0xfff +#define HTT_HL_RX_DESC_MPDU_SEQ_NUM_S 0 +#define HTT_HL_RX_DESC_MPDU_ENC_M 0x1000 +#define HTT_HL_RX_DESC_MPDU_ENC_S 12 +#define HTT_HL_RX_DESC_CHAN_INFO_PRESENT_M 0x2000 +#define HTT_HL_RX_DESC_CHAN_INFO_PRESENT_S 13 +#define HTT_HL_RX_DESC_MCAST_BCAST_M 0x10000 +#define HTT_HL_RX_DESC_MCAST_BCAST_S 16 +#define HTT_HL_RX_DESC_FRAGMENT_M 0x20000 +#define HTT_HL_RX_DESC_FRAGMENT_S 17 +#define HTT_HL_RX_DESC_KEY_ID_OCT_M 0x3fc0000 +#define HTT_HL_RX_DESC_KEY_ID_OCT_S 18 + +#define HTT_HL_RX_DESC_PN_OFFSET \ + offsetof(struct hl_htt_rx_desc_base, pn_31_0) +#define HTT_HL_RX_DESC_PN_WORD_OFFSET \ + (HTT_HL_RX_DESC_PN_OFFSET >> 2) + +/* Channel information */ +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_M 0x0000ffff +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S 0 +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_M 0xffff0000 +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S 16 +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_M 0x0000ffff +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S 0 +#define HTT_CHAN_INFO_PHY_MODE_M 0x00ff0000 +#define HTT_CHAN_INFO_PHY_MODE_S 16 + + +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_PHY_MODE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_PHY_MODE, value); \ + (word) |= (value) << HTT_CHAN_INFO_PHY_MODE_S; \ + } while (0) +#define HTT_CHAN_INFO_PHY_MODE_GET(word) \ + (((word) & HTT_CHAN_INFO_PHY_MODE_M) \ + >> HTT_CHAN_INFO_PHY_MODE_S) + +/* + * @brief target -> host rx reorder flush message definition + * + * @details + * The following field definitions describe the format of the rx flush + * message sent from the target to the host. + * The message consists of a 4-octet header, followed by one or more + * 4-octet payload information elements. + * + * |31 24|23 8|7 0| + * |--------------------------------------------------------------| + * | TID | peer ID | msg type | + * |--------------------------------------------------------------| + * | seq num end | seq num start | MPDU status | reserved | + * |--------------------------------------------------------------| + * First DWORD: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx flush message + * Value: 0x2 + * - PEER_ID + * Bits 23:8 (only bits 18:8 actually used) + * Purpose: identify which peer's rx data is being flushed + * Value: (rx) peer ID + * - TID + * Bits 31:24 (only bits 27:24 actually used) + * Purpose: Specifies which traffic identifier's rx data is being flushed + * Value: traffic identifier + * Second DWORD: + * - MPDU_STATUS + * Bits 15:8 + * Purpose: + * Indicate whether the flushed MPDUs should be discarded or processed. + * Value: + * 0x1: send the MPDUs from the rx reorder buffer to subsequent + * stages of rx processing + * other: discard the MPDUs + * It is anticipated that flush messages will always have + * MPDU status == 1, but the status flag is included for + * flexibility. + * - SEQ_NUM_START + * Bits 23:16 + * Purpose: + * Indicate the start of a series of consecutive MPDUs being flushed. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * Value: + * The sequence number for the first MPDU in the sequence. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * - SEQ_NUM_END + * Bits 30:24 + * Purpose: + * Indicate the end of a series of consecutive MPDUs being flushed. + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU being flushed. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * The range of MPDUs from [SEQ_NUM_START,SEQ_NUM_END-1] inclusive + * are to be released for further rx processing. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + */ +/* first DWORD */ +#define HTT_RX_FLUSH_PEER_ID_M 0xffff00 +#define HTT_RX_FLUSH_PEER_ID_S 8 +#define HTT_RX_FLUSH_TID_M 0xff000000 +#define HTT_RX_FLUSH_TID_S 24 +/* second DWORD */ +#define HTT_RX_FLUSH_MPDU_STATUS_M 0x0000ff00 +#define HTT_RX_FLUSH_MPDU_STATUS_S 8 +#define HTT_RX_FLUSH_SEQ_NUM_START_M 0x00ff0000 +#define HTT_RX_FLUSH_SEQ_NUM_START_S 16 +#define HTT_RX_FLUSH_SEQ_NUM_END_M 0xff000000 +#define HTT_RX_FLUSH_SEQ_NUM_END_S 24 + +#define HTT_RX_FLUSH_BYTES 8 + +#define HTT_RX_FLUSH_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_PEER_ID, value); \ + (word) |= (value) << HTT_RX_FLUSH_PEER_ID_S; \ + } while (0) +#define HTT_RX_FLUSH_PEER_ID_GET(word) \ + (((word) & HTT_RX_FLUSH_PEER_ID_M) >> HTT_RX_FLUSH_PEER_ID_S) + +#define HTT_RX_FLUSH_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_TID, value); \ + (word) |= (value) << HTT_RX_FLUSH_TID_S; \ + } while (0) +#define HTT_RX_FLUSH_TID_GET(word) \ + (((word) & HTT_RX_FLUSH_TID_M) >> HTT_RX_FLUSH_TID_S) + +#define HTT_RX_FLUSH_MPDU_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_MPDU_STATUS, value); \ + (word) |= (value) << HTT_RX_FLUSH_MPDU_STATUS_S; \ + } while (0) +#define HTT_RX_FLUSH_MPDU_STATUS_GET(word) \ + (((word) & HTT_RX_FLUSH_MPDU_STATUS_M) >> HTT_RX_FLUSH_MPDU_STATUS_S) + +#define HTT_RX_FLUSH_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_FLUSH_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_FLUSH_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_FLUSH_SEQ_NUM_START_M) >> \ + HTT_RX_FLUSH_SEQ_NUM_START_S) + +#define HTT_RX_FLUSH_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_FLUSH_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_FLUSH_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_FLUSH_SEQ_NUM_END_M) >> HTT_RX_FLUSH_SEQ_NUM_END_S) + +/* + * @brief target -> host rx pn check indication message + * + * @details + * The following field definitions describe the format of the Rx PN check + * indication message sent from the target to the host. + * The message consists of a 4-octet header, followed by the start and + * end sequence numbers to be released, followed by the PN IEs. Each PN + * IE is one octet containing the sequence number that failed the PN + * check. + * + * |31 24|23 8|7 0| + * |--------------------------------------------------------------| + * | TID | peer ID | msg type | + * |--------------------------------------------------------------| + * | Reserved | PN IE count | seq num end | seq num start| + * |--------------------------------------------------------------| + * l : PN IE 2 | PN IE 1 | PN IE 0 | + * |--------------------------------------------------------------| + + * First DWORD: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as an rx pn check indication message + * Value: 0x2 + * - PEER_ID + * Bits 23:8 (only bits 18:8 actually used) + * Purpose: identify which peer + * Value: (rx) peer ID + * - TID + * Bits 31:24 (only bits 27:24 actually used) + * Purpose: identify traffic identifier + * Value: traffic identifier + * Second DWORD: + * - SEQ_NUM_START + * Bits 7:0 + * Purpose: + * Indicates the starting sequence number of the MPDU in this + * series of MPDUs that went though PN check. + * Value: + * The sequence number for the first MPDU in the sequence. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * - SEQ_NUM_END + * Bits 15:8 + * Purpose: + * Indicates the ending sequence number of the MPDU in this + * series of MPDUs that went though PN check. + * Value: + * The sequence number one larger then the sequence number of the last + * MPDU being flushed. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * The range of MPDUs from [SEQ_NUM_START,SEQ_NUM_END-1] + * have been checked for invalid PN numbers and are ready + * to be released for further processing. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * - PN_IE_COUNT + * Bits 23:16 + * Purpose: + * Used to determine the variable number of PN information + * elements in this message + * + * PN information elements: + * - PN_IE_x- + * Purpose: + * Each PN information element contains the sequence number + * of the MPDU that has failed the target PN check. + * Value: + * Contains the 6 LSBs of the 802.11 sequence number + * corresponding to the MPDU that failed the PN check. + */ +/* first DWORD */ +#define HTT_RX_PN_IND_PEER_ID_M 0xffff00 +#define HTT_RX_PN_IND_PEER_ID_S 8 +#define HTT_RX_PN_IND_TID_M 0xff000000 +#define HTT_RX_PN_IND_TID_S 24 +/* second DWORD */ +#define HTT_RX_PN_IND_SEQ_NUM_START_M 0x000000ff +#define HTT_RX_PN_IND_SEQ_NUM_START_S 0 +#define HTT_RX_PN_IND_SEQ_NUM_END_M 0x0000ff00 +#define HTT_RX_PN_IND_SEQ_NUM_END_S 8 +#define HTT_RX_PN_IND_PN_IE_CNT_M 0x00ff0000 +#define HTT_RX_PN_IND_PN_IE_CNT_S 16 + +#define HTT_RX_PN_IND_BYTES 8 + +#define HTT_RX_PN_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_PN_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_PN_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_PN_IND_PEER_ID_M) >> HTT_RX_PN_IND_PEER_ID_S) + +#define HTT_RX_PN_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_TID, value); \ + (word) |= (value) << HTT_RX_PN_IND_TID_S; \ + } while (0) +#define HTT_RX_PN_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_PN_IND_TID_M) >> HTT_RX_PN_IND_TID_S) + +#define HTT_RX_PN_IND_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_PN_IND_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_PN_IND_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_PN_IND_SEQ_NUM_START_M) >> \ + HTT_RX_PN_IND_SEQ_NUM_START_S) + +#define HTT_RX_PN_IND_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_PN_IND_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_PN_IND_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_PN_IND_SEQ_NUM_END_M) >> HTT_RX_PN_IND_SEQ_NUM_END_S) + +#define HTT_RX_PN_IND_PN_IE_CNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_PN_IE_CNT, value); \ + (word) |= (value) << HTT_RX_PN_IND_PN_IE_CNT_S; \ + } while (0) +#define HTT_RX_PN_IND_PN_IE_CNT_GET(word) \ + (((word) & HTT_RX_PN_IND_PN_IE_CNT_M) >> HTT_RX_PN_IND_PN_IE_CNT_S) + +/* + * @brief target -> host rx offload deliver message for LL system + * + * @details + * In a low latency system this message is sent whenever the offload + * manager flushes out the packets it has coalesced in its coalescing buffer. + * The DMA of the actual packets into host memory is done before sending out + * this message. This message indicates only how many MSDUs to reap. The + * peer ID, vdev ID, tid and MSDU length are copied inline into the header + * portion of the MSDU while DMA'ing into the host memory. Unlike the packets + * DMA'd by the MAC directly into host memory these packets do not contain + * the MAC descriptors in the header portion of the packet. Instead they contain + * the peer ID, vdev ID, tid and MSDU length. Also when the host receives this + * message, the packets are delivered directly to the NW stack without going + * through the regular reorder buffering and PN checking path since it has + * already been done in target. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | Total MSDU count | reserved | msg type | + * |-----------------------------------------------------------------------| + * + * @brief target -> host rx offload deliver message for HL system + * + * @details + * In a high latency system this message is sent whenever the offload manager + * flushes out the packets it has coalesced in its coalescing buffer. The + * actual packets are also carried along with this message. When the host + * receives this message, it is expected to deliver these packets to the NW + * stack directly instead of routing them through the reorder buffering and + * PN checking path since it has already been done in target. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | Total MSDU count | reserved | msg type | + * |-----------------------------------------------------------------------| + * | peer ID | MSDU length | + * |-----------------------------------------------------------------------| + * | MSDU payload | FW Desc | tid | vdev ID | + * |-----------------------------------------------------------------------| + * | MSDU payload contd. | + * |-----------------------------------------------------------------------| + * | peer ID | MSDU length | + * |-----------------------------------------------------------------------| + * | MSDU payload | FW Desc | tid | vdev ID | + * |-----------------------------------------------------------------------| + * | MSDU payload contd. | + * |-----------------------------------------------------------------------| + * + */ +/* first DWORD */ +#define HTT_RX_OFFLOAD_DELIVER_IND_HDR_BYTES 4 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES 7 + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_M 0xffff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S 16 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_M 0x0000ffff +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S 0 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_M 0xffff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S 16 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_M 0x000000ff +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S 0 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_M 0x0000ff00 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S 8 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_M 0x00ff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S 16 + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S; \ +} while (0) \ + +/** + * @brief target -> host rx peer map/unmap message definition + * + * @details + * The following diagram shows the format of the rx peer map message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | VDEV ID | msg type | + * |-----------------------------------------------------------------------| + * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | + * |-----------------------------------------------------------------------| + * | reserved | MAC addr 5 | MAC addr 4 | + * |-----------------------------------------------------------------------| + * + * + * The following diagram shows the format of the rx peer unmap message sent + * from the target to the host. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | VDEV ID | msg type | + * |-----------------------------------------------------------------------| + * + * The following field definitions describe the format of the rx peer map + * and peer unmap messages sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx peer map or peer unmap message + * Value: peer map -> 0x3, peer unmap -> 0x4 + * - VDEV_ID + * Bits 15:8 + * Purpose: Indicates which virtual device the peer is associated + * with. + * Value: vdev ID (used in the host to look up the vdev object) + * - PEER_ID + * Bits 31:16 + * Purpose: The peer ID (index) that WAL is allocating (map) or + * freeing (unmap) + * Value: (rx) peer ID + * - MAC_ADDR_L32 (peer map only) + * Bits 31:0 + * Purpose: Identifies which peer node the peer ID is for. + * Value: lower 4 bytes of peer node's MAC address + * - MAC_ADDR_U16 (peer map only) + * Bits 15:0 + * Purpose: Identifies which peer node the peer ID is for. + * Value: upper 2 bytes of peer node's MAC address + */ +#define HTT_RX_PEER_MAP_VDEV_ID_M 0xff00 +#define HTT_RX_PEER_MAP_VDEV_ID_S 8 +#define HTT_RX_PEER_MAP_PEER_ID_M 0xffff0000 +#define HTT_RX_PEER_MAP_PEER_ID_S 16 +#define HTT_RX_PEER_MAP_MAC_ADDR_L32_M 0xffffffff +#define HTT_RX_PEER_MAP_MAC_ADDR_L32_S 0 +#define HTT_RX_PEER_MAP_MAC_ADDR_U16_M 0xffff +#define HTT_RX_PEER_MAP_MAC_ADDR_U16_S 0 + +#define HTT_RX_PEER_MAP_VAP_ID_SET HTT_RX_PEER_MAP_VDEV_ID_SET /* deprecated */ +#define HTT_RX_PEER_MAP_VDEV_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PEER_MAP_VDEV_ID, value); \ + (word) |= (value) << HTT_RX_PEER_MAP_VDEV_ID_S; \ + } while (0) +#define HTT_RX_PEER_MAP_VAP_ID_GET HTT_RX_PEER_MAP_VDEV_ID_GET /* deprecated */ +#define HTT_RX_PEER_MAP_VDEV_ID_GET(word) \ + (((word) & HTT_RX_PEER_MAP_VDEV_ID_M) >> HTT_RX_PEER_MAP_VDEV_ID_S) + +#define HTT_RX_PEER_MAP_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PEER_MAP_PEER_ID, value); \ + (word) |= (value) << HTT_RX_PEER_MAP_PEER_ID_S; \ + } while (0) +#define HTT_RX_PEER_MAP_PEER_ID_GET(word) \ + (((word) & HTT_RX_PEER_MAP_PEER_ID_M) >> HTT_RX_PEER_MAP_PEER_ID_S) + +#define HTT_RX_PEER_MAP_MAC_ADDR_OFFSET 4 /* bytes */ + +#define HTT_RX_PEER_MAP_BYTES 12 + + +#define HTT_RX_PEER_UNMAP_PEER_ID_M HTT_RX_PEER_MAP_PEER_ID_M +#define HTT_RX_PEER_UNMAP_PEER_ID_S HTT_RX_PEER_MAP_PEER_ID_S + +#define HTT_RX_PEER_UNMAP_PEER_ID_SET HTT_RX_PEER_MAP_PEER_ID_SET +#define HTT_RX_PEER_UNMAP_PEER_ID_GET HTT_RX_PEER_MAP_PEER_ID_GET + +#define HTT_RX_PEER_UNMAP_VDEV_ID_SET HTT_RX_PEER_MAP_VDEV_ID_SET +#define HTT_RX_PEER_UNMAP_VDEV_ID_GET HTT_RX_PEER_MAP_VDEV_ID_GET + +#define HTT_RX_PEER_UNMAP_BYTES 4 + + +/** + * @brief target -> host message specifying security parameters + * + * @details + * The following diagram shows the format of the security specification + * message sent from the target to the host. + * This security specification message tells the host whether a PN check is + * necessary on rx data frames, and if so, how large the PN counter is. + * This message also tells the host about the security processing to apply + * to defragmented rx frames - specifically, whether a Message Integrity + * Check is required, and the Michael key to use. + * + * |31 24|23 16|15|14 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | U| security type | msg type | + * |-----------------------------------------------------------------------| + * | Michael Key K0 | + * |-----------------------------------------------------------------------| + * | Michael Key K1 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Low0 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Low1 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Hi0 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Hi1 | + * |-----------------------------------------------------------------------| + * + * The following field definitions describe the format of the security + * indication message sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a security specification message + * Value: 0xb + * - SEC_TYPE + * Bits 14:8 + * Purpose: specifies which type of security applies to the peer + * Value: htt_sec_type enum value + * - UNICAST + * Bit 15 + * Purpose: whether this security is applied to unicast or multicast data + * Value: 1 -> unicast, 0 -> multicast + * - PEER_ID + * Bits 31:16 + * Purpose: The ID number for the peer the security specification is for + * Value: peer ID + * - MICHAEL_KEY_K0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 1st half of the TKIP Michael key + * Value: Michael Key K0 (if security type is TKIP) + * - MICHAEL_KEY_K1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 2nd half of the TKIP Michael key + * Value: Michael Key K1 (if security type is TKIP) + * - WAPI_RSC_LOW0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 1st quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Low0 (if security type is WAPI) + * - WAPI_RSC_LOW1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 2nd quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Low1 (if security type is WAPI) + * - WAPI_RSC_HI0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 3rd quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Hi0 (if security type is WAPI) + * - WAPI_RSC_HI1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 4th quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Hi1 (if security type is WAPI) + */ + +#define HTT_SEC_IND_SEC_TYPE_M 0x00007f00 +#define HTT_SEC_IND_SEC_TYPE_S 8 +#define HTT_SEC_IND_UNICAST_M 0x00008000 +#define HTT_SEC_IND_UNICAST_S 15 +#define HTT_SEC_IND_PEER_ID_M 0xffff0000 +#define HTT_SEC_IND_PEER_ID_S 16 + +#define HTT_SEC_IND_SEC_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_SEC_TYPE, value); \ + (word) |= (value) << HTT_SEC_IND_SEC_TYPE_S; \ + } while (0) +#define HTT_SEC_IND_SEC_TYPE_GET(word) \ + (((word) & HTT_SEC_IND_SEC_TYPE_M) >> HTT_SEC_IND_SEC_TYPE_S) + +#define HTT_SEC_IND_UNICAST_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_UNICAST, value); \ + (word) |= (value) << HTT_SEC_IND_UNICAST_S; \ + } while (0) +#define HTT_SEC_IND_UNICAST_GET(word) \ + (((word) & HTT_SEC_IND_UNICAST_M) >> HTT_SEC_IND_UNICAST_S) + +#define HTT_SEC_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_PEER_ID, value); \ + (word) |= (value) << HTT_SEC_IND_PEER_ID_S; \ + } while (0) +#define HTT_SEC_IND_PEER_ID_GET(word) \ + (((word) & HTT_SEC_IND_PEER_ID_M) >> HTT_SEC_IND_PEER_ID_S) + + +#define HTT_SEC_IND_BYTES 28 + + +/** + * @brief target -> host rx ADDBA / DELBA message definitions + * + * @details + * The following diagram shows the format of the rx ADDBA message sent + * from the target to the host: + * + * |31 20|19 16|15 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | window size | msg type | + * |---------------------------------------------------------------------| + * + * The following diagram shows the format of the rx DELBA message sent + * from the target to the host: + * + * |31 20|19 16|15 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | reserved | msg type | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the rx ADDBA + * and DELBA messages sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx ADDBA or DELBA message + * Value: ADDBA -> 0x5, DELBA -> 0x6 + * - WIN_SIZE + * Bits 15:8 (ADDBA only) + * Purpose: Specifies the length of the block ack window (max = 64). + * Value: + * block ack window length specified by the received ADDBA + * management message. + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the ADDBA / DELBA is for. + * Value: + * TID specified by the received ADDBA or DELBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the ADDBA / DELBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + */ +#define HTT_RX_ADDBA_WIN_SIZE_M 0xff00 +#define HTT_RX_ADDBA_WIN_SIZE_S 8 +#define HTT_RX_ADDBA_TID_M 0xf0000 +#define HTT_RX_ADDBA_TID_S 16 +#define HTT_RX_ADDBA_PEER_ID_M 0xfff00000 +#define HTT_RX_ADDBA_PEER_ID_S 20 + +#define HTT_RX_ADDBA_WIN_SIZE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_WIN_SIZE, value); \ + (word) |= (value) << HTT_RX_ADDBA_WIN_SIZE_S; \ + } while (0) +#define HTT_RX_ADDBA_WIN_SIZE_GET(word) \ + (((word) & HTT_RX_ADDBA_WIN_SIZE_M) >> HTT_RX_ADDBA_WIN_SIZE_S) + +#define HTT_RX_ADDBA_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_TID, value); \ + (word) |= (value) << HTT_RX_ADDBA_TID_S; \ + } while (0) +#define HTT_RX_ADDBA_TID_GET(word) \ + (((word) & HTT_RX_ADDBA_TID_M) >> HTT_RX_ADDBA_TID_S) + +#define HTT_RX_ADDBA_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_PEER_ID, value); \ + (word) |= (value) << HTT_RX_ADDBA_PEER_ID_S; \ + } while (0) +#define HTT_RX_ADDBA_PEER_ID_GET(word) \ + (((word) & HTT_RX_ADDBA_PEER_ID_M) >> HTT_RX_ADDBA_PEER_ID_S) + +#define HTT_RX_ADDBA_BYTES 4 + + +#define HTT_RX_DELBA_TID_M HTT_RX_ADDBA_TID_M +#define HTT_RX_DELBA_TID_S HTT_RX_ADDBA_TID_S +#define HTT_RX_DELBA_PEER_ID_M HTT_RX_ADDBA_PEER_ID_M +#define HTT_RX_DELBA_PEER_ID_S HTT_RX_ADDBA_PEER_ID_S + +#define HTT_RX_DELBA_TID_SET HTT_RX_ADDBA_TID_SET +#define HTT_RX_DELBA_TID_GET HTT_RX_ADDBA_TID_GET +#define HTT_RX_DELBA_PEER_ID_SET HTT_RX_ADDBA_PEER_ID_SET +#define HTT_RX_DELBA_PEER_ID_GET HTT_RX_ADDBA_PEER_ID_GET + +#define HTT_RX_DELBA_BYTES 4 + +/** + * @brief tx queue group information element definition + * + * @details + * The following diagram shows the format of the tx queue group + * information element, which can be included in target --> host + * messages to specify the number of tx "credits" (tx descriptors + * for LL, or tx buffers for HL) available to a particular group + * of host-side tx queues, and which host-side tx queues belong to + * the group. + * + * |31|30 24|23 16|15|14|13 0| + * |------------------------------------------------------------------------| + * | X| reserved | tx queue grp ID | A| S| credit count | + * |------------------------------------------------------------------------| + * | vdev ID mask | AC mask | + * |------------------------------------------------------------------------| + * + * The following definitions describe the fields within the tx queue group + * information element: + * - credit_count + * Bits 13:1 + * Purpose: specify how many tx credits are available to the tx queue group + * Value: An absolute or relative, positive or negative credit value + * The 'A' bit specifies whether the value is absolute or relative. + * The 'S' bit specifies whether the value is positive or negative. + * A negative value can only be relative, not absolute. + * An absolute value replaces any prior credit value the host has for + * the tx queue group in question. + * A relative value is added to the prior credit value the host has for + * the tx queue group in question. + * - sign + * Bit 14 + * Purpose: specify whether the credit count is positive or negative + * Value: 0 -> positive, 1 -> negative + * - absolute + * Bit 15 + * Purpose: specify whether the credit count is absolute or relative + * Value: 0 -> relative, 1 -> absolute + * - txq_group_id + * Bits 23:16 + * Purpose: indicate which tx queue group's credit and/or membership are + * being specified + * Value: 0 to max_tx_queue_groups-1 + * - reserved + * Bits 30:16 + * Value: 0x0 + * - eXtension + * Bit 31 + * Purpose: specify whether another tx queue group info element follows + * Value: 0 -> no more tx queue group information elements + * 1 -> another tx queue group information element immediately follows + * - ac_mask + * Bits 15:0 + * Purpose: specify which Access Categories belong to the tx queue group + * Value: bit-OR of masks for the ACs (WMM and extension) that belong to + * the tx queue group. + * The AC bit-mask values are obtained by left-shifting by the + * corresponding HTT_AC_WMM enum values, e.g. (1 << HTT_AC_WMM_BE) == 0x1 + * - vdev_id_mask + * Bits 31:16 + * Purpose: specify which vdev's tx queues belong to the tx queue group + * Value: bit-OR of masks based on the IDs of the vdevs whose tx queues + * belong to the tx queue group. + * For example, if vdev IDs 1 and 4 belong to a tx queue group, the + * vdev_id_mask would be (1 << 1) | (1 << 4) = 0x12 + */ +PREPACK struct htt_txq_group { + A_UINT32 + credit_count:14, + sign:1, + absolute:1, + tx_queue_group_id:8, + reserved0:7, + extension:1; + A_UINT32 + ac_mask:16, + vdev_id_mask:16; +} POSTPACK; + +/* first word */ +#define HTT_TXQ_GROUP_CREDIT_COUNT_S 0 +#define HTT_TXQ_GROUP_CREDIT_COUNT_M 0x00003fff +#define HTT_TXQ_GROUP_SIGN_S 14 +#define HTT_TXQ_GROUP_SIGN_M 0x00004000 +#define HTT_TXQ_GROUP_ABS_S 15 +#define HTT_TXQ_GROUP_ABS_M 0x00008000 +#define HTT_TXQ_GROUP_ID_S 16 +#define HTT_TXQ_GROUP_ID_M 0x00ff0000 +#define HTT_TXQ_GROUP_EXT_S 31 +#define HTT_TXQ_GROUP_EXT_M 0x80000000 +/* second word */ +#define HTT_TXQ_GROUP_AC_MASK_S 0 +#define HTT_TXQ_GROUP_AC_MASK_M 0x0000ffff +#define HTT_TXQ_GROUP_VDEV_ID_MASK_S 16 +#define HTT_TXQ_GROUP_VDEV_ID_MASK_M 0xffff0000 + +#define HTT_TXQ_GROUP_CREDIT_COUNT_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_CREDIT_COUNT, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_CREDIT_COUNT_S)); \ + } while (0) +#define HTT_TXQ_GROUP_CREDIT_COUNT_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_CREDIT_COUNT_M) >> \ + HTT_TXQ_GROUP_CREDIT_COUNT_S) + +#define HTT_TXQ_GROUP_SIGN_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_SIGN, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_SIGN_S)); \ + } while (0) +#define HTT_TXQ_GROUP_SIGN_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_SIGN_M) >> HTT_TXQ_GROUP_SIGN_S) + +#define HTT_TXQ_GROUP_ABS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_ABS, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_ABS_S)); \ + } while (0) +#define HTT_TXQ_GROUP_ABS_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_ABS_M) >> HTT_TXQ_GROUP_ABS_S) + +#define HTT_TXQ_GROUP_ID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_ID, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_ID_S)); \ + } while (0) +#define HTT_TXQ_GROUP_ID_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_ID_M) >> HTT_TXQ_GROUP_ID_S) + +#define HTT_TXQ_GROUP_EXT_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_EXT, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_EXT_S)); \ + } while (0) +#define HTT_TXQ_GROUP_EXT_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_EXT_M) >> HTT_TXQ_GROUP_EXT_S) + +#define HTT_TXQ_GROUP_AC_MASK_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_AC_MASK, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_AC_MASK_S)); \ + } while (0) +#define HTT_TXQ_GROUP_AC_MASK_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_AC_MASK_M) >> HTT_TXQ_GROUP_AC_MASK_S) + +#define HTT_TXQ_GROUP_VDEV_ID_MASK_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_VDEV_ID_MASK, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_VDEV_ID_MASK_S)); \ + } while (0) +#define HTT_TXQ_GROUP_VDEV_ID_MASK_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_VDEV_ID_MASK_M) >> \ + HTT_TXQ_GROUP_VDEV_ID_MASK_S) + +/** + * @brief target -> host TX completion indication message definition + * + * @details + * The following diagram shows the format of the TX completion indication sent + * from the target to the host + * + * |31 25| 24|23 16| 15 |14 11|10 8|7 0| + * |-------------------------------------------------------------| + * header: | reserved |append| num | t_i| tid |status| msg_type | + * |-------------------------------------------------------------| + * payload: | MSDU1 ID | MSDU0 ID | + * |-------------------------------------------------------------| + * : MSDU3 ID : MSDU2 ID : + * |-------------------------------------------------------------| + * | struct htt_tx_compl_ind_append_retries | + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * The following field definitions describe the format of the TX completion + * indication sent from the target to the host + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: identifies this as HTT TX completion indication + * Value: 0x7 + * - status + * Bits 10:8 + * Purpose: the TX completion status of payload fragmentations descriptors + * Value: could be HTT_TX_COMPL_IND_STAT_OK or HTT_TX_COMPL_IND_STAT_DISCARD + * - tid + * Bits 14:11 + * Purpose: the tid associated with those fragmentation descriptors. It is + * valid or not, depending on the tid_invalid bit. + * Value: 0 to 15 + * - tid_invalid + * Bits 15:15 + * Purpose: this bit indicates whether the tid field is valid or not + * Value: 0 indicates valid; 1 indicates invalid + * - num + * Bits 23:16 + * Purpose: the number of payload in this indication + * Value: 1 to 255 + * - append + * Bits 24:24 + * Purpose: append the struct htt_tx_compl_ind_append_retries which contains + * the number of tx retries for one MSDU at the end of this message + * Value: 0 indicates no appending; 1 indicates appending + * Payload fields: + * - hmsdu_id + * Bits 15:0 + * Purpose: this ID is used to track the Tx buffer in host + * Value: 0 to "size of host MSDU descriptor pool - 1" + */ + +#define HTT_TX_COMPL_IND_STATUS_S 8 +#define HTT_TX_COMPL_IND_STATUS_M 0x00000700 +#define HTT_TX_COMPL_IND_TID_S 11 +#define HTT_TX_COMPL_IND_TID_M 0x00007800 +#define HTT_TX_COMPL_IND_TID_INV_S 15 +#define HTT_TX_COMPL_IND_TID_INV_M 0x00008000 +#define HTT_TX_COMPL_IND_NUM_S 16 +#define HTT_TX_COMPL_IND_NUM_M 0x00ff0000 +#define HTT_TX_COMPL_IND_APPEND_S 24 +#define HTT_TX_COMPL_IND_APPEND_M 0x01000000 + +#define HTT_TX_COMPL_IND_STATUS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_STATUS, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_STATUS_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_STATUS_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_STATUS_M) >> HTT_TX_COMPL_IND_STATUS_S) +#define HTT_TX_COMPL_IND_NUM_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_NUM, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_NUM_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_NUM_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_NUM_M) >> HTT_TX_COMPL_IND_NUM_S) +#define HTT_TX_COMPL_IND_TID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_TID, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_TID_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_TID_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_TID_M) >> HTT_TX_COMPL_IND_TID_S) +#define HTT_TX_COMPL_IND_TID_INV_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_TID_INV, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_TID_INV_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_TID_INV_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_TID_INV_M) >> \ + HTT_TX_COMPL_IND_TID_INV_S) +#define HTT_TX_COMPL_IND_APPEND_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_APPEND, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_APPEND_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_APPEND_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_APPEND_M) >> HTT_TX_COMPL_IND_APPEND_S) + +#define HTT_TX_COMPL_CTXT_SZ sizeof(A_UINT16) +#define HTT_TX_COMPL_CTXT_NUM(_bytes) ((_bytes) >> 1) + +#define HTT_TX_COMPL_INV_MSDU_ID 0xffff + +#define HTT_TX_COMPL_IND_STAT_OK 0 +#define HTT_TX_COMPL_IND_STAT_DISCARD 1 +#define HTT_TX_COMPL_IND_STAT_NO_ACK 2 +#define HTT_TX_COMPL_IND_STAT_POSTPONE 3 +/* + * The PEER_DEL tx completion status is used for HL cases + * where the peer the frame is for has been deleted. + * The host has already discarded its copy of the frame, but + * it still needs the tx completion to restore its credit. + */ +#define HTT_TX_COMPL_IND_STAT_PEER_DEL 4 + + +#define HTT_TX_COMPL_IND_APPEND_SET_MORE_RETRY(f) ((f) |= 0x1) +#define HTT_TX_COMPL_IND_APPEND_CLR_MORE_RETRY(f) ((f) &= (~0x1)) + +PREPACK struct htt_tx_compl_ind_base { + A_UINT32 hdr; + A_UINT16 payload[1 /*or more */]; +} POSTPACK; + +PREPACK struct htt_tx_compl_ind_append_retries { + A_UINT16 msdu_id; + A_UINT8 tx_retries; + A_UINT8 flag;/* Bit 0, 1: another append_retries struct is appended + 0: this is the last append_retries struct */ +} POSTPACK; + +/** + * @brief target -> host rate-control update indication message + * + * @details + * The following diagram shows the format of the RC Update message + * sent from the target to the host, while processing the tx-completion + * of a transmitted PPDU. + * + * |31 24|23 16|15 8|7 0| + * |-------------------------------------------------------------| + * | peer ID | vdev ID | msg_type | + * |-------------------------------------------------------------| + * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | + * |-------------------------------------------------------------| + * | reserved | num elems | MAC addr 5 | MAC addr 4 | + * |-------------------------------------------------------------| + * | : | + * : HTT_RC_TX_DONE_PARAMS (DWORD-aligned) : + * | : | + * |-------------------------------------------------------------| + * | : | + * : HTT_RC_TX_DONE_PARAMS (DWORD-aligned) : + * | : | + * |-------------------------------------------------------------| + * : : + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + */ + +typedef struct { + A_UINT32 rate_code; /* rate code, bw, chain mask sgi */ + A_UINT32 rate_code_flags; + A_UINT32 flags; /* Encodes information such as excessive + retransmission, aggregate, some info + from .11 frame control, + STBC, LDPC, (SGI and Tx Chain Mask + are encoded in ptx_rc->flags field), + AMPDU truncation (BT/time based etc.), + RTS/CTS attempt */ + + A_UINT32 num_enqued;/* # of MPDUs (for non-AMPDU 1) for this rate */ + A_UINT32 num_retries;/* Total # of transmission attempt for this rate */ + A_UINT32 num_failed;/* # of failed MPDUs in A-MPDU, 0 otherwise */ + A_UINT32 ack_rssi;/* ACK RSSI: b'7..b'0 avg RSSI across all chain */ + A_UINT32 time_stamp; /* ACK timestamp (helps determine age) */ + A_UINT32 is_probe; /* Valid if probing. Else, 0 */ +} HTT_RC_TX_DONE_PARAMS; + +#define HTT_RC_UPDATE_CTXT_SZ (sizeof(HTT_RC_TX_DONE_PARAMS))/* bytes */ +#define HTT_RC_UPDATE_HDR_SZ (12) /* bytes */ + +#define HTT_RC_UPDATE_MAC_ADDR_OFFSET (4) /* bytes */ +#define HTT_RC_UPDATE_MAC_ADDR_LENGTH IEEE80211_ADDR_LEN /* bytes */ + +#define HTT_RC_UPDATE_VDEVID_S 8 +#define HTT_RC_UPDATE_VDEVID_M 0xff00 +#define HTT_RC_UPDATE_PEERID_S 16 +#define HTT_RC_UPDATE_PEERID_M 0xffff0000 + +#define HTT_RC_UPDATE_NUM_ELEMS_S 16 +#define HTT_RC_UPDATE_NUM_ELEMS_M 0x00ff0000 + +#define HTT_RC_UPDATE_VDEVID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_VDEVID, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_VDEVID_S)); \ + } while (0) + +#define HTT_RC_UPDATE_VDEVID_GET(_info) \ + (((_info) & HTT_RC_UPDATE_VDEVID_M) >> HTT_RC_UPDATE_VDEVID_S) + +#define HTT_RC_UPDATE_PEERID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_PEERID, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_PEERID_S)); \ + } while (0) + +#define HTT_RC_UPDATE_PEERID_GET(_info) \ + (((_info) & HTT_RC_UPDATE_PEERID_M) >> HTT_RC_UPDATE_PEERID_S) + +#define HTT_RC_UPDATE_NUM_ELEMS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_NUM_ELEMS, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_NUM_ELEMS_S)); \ + } while (0) + +#define HTT_RC_UPDATE_NUM_ELEMS_GET(_info) \ + (((_info) & HTT_RC_UPDATE_NUM_ELEMS_M) >> HTT_RC_UPDATE_NUM_ELEMS_S) + +/** + * @brief target -> host rx fragment indication message definition + * + * @details + * The following field definitions describe the format of the rx fragment + * indication message sent from the target to the host. + * The rx fragment indication message shares the format of the + * rx indication message, but not all fields from the rx indication message + * are relevant to the rx fragment indication message. + * + * + * |31 24|23 18|17|16|15|14|13|12|11|10|9|8|7|6|5|4 0| + * |-----------+-------------------+---------------------+-------------| + * | peer ID | |FV| ext TID | msg type | + * |-------------------------------------------------------------------| + * | | flush | flush | + * | | end | start | + * | | seq num | seq num | + * |-------------------------------------------------------------------| + * | reserved | FW rx desc bytes | + * |-------------------------------------------------------------------| + * | | FW MSDU Rx | + * | | desc B0 | + * |-------------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx fragment indication message + * Value: 0xa + * - EXT_TID + * Bits 12:8 + * Purpose: identify the traffic ID of the rx data, including + * special "extended" TID values for multicast, broadcast, and + * non-QoS data frames + * Value: 0-15 for regular TIDs, or >= 16 for bcast/mcast/non-QoS + * - FLUSH_VALID (FV) + * Bit 13 + * Purpose: indicate whether the flush IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> flush IE is valid and needs to be processed + * 0 -> flush IE is not valid and should be ignored + * - PEER_ID + * Bits 31:16 + * Purpose: Identify, by ID, which peer sent the rx data + * Value: ID of the peer who sent the rx data + * - FLUSH_SEQ_NUM_START + * Bits 5:0 + * Purpose: Indicate the start of a series of MPDUs to flush + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Value: + * The sequence number for the first MPDUs to check to flush. + * The sequence number is masked by 0x3f. + * - FLUSH_SEQ_NUM_END + * Bits 11:6 + * Purpose: Indicate the end of a series of MPDUs to flush + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to flush. + * The sequence number is masked by 0x3f. + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Rx descriptor fields: + * - FW_RX_DESC_BYTES + * Bits 15:0 + * Purpose: Indicate how many bytes in the Rx indication are used for + * FW Rx descriptors + * Value: 1 + */ +#define HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32 2 + +#define HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET 12 + +#define HTT_RX_FRAG_IND_EXT_TID_SET HTT_RX_IND_EXT_TID_SET +#define HTT_RX_FRAG_IND_EXT_TID_GET HTT_RX_IND_EXT_TID_GET + +#define HTT_RX_FRAG_IND_PEER_ID_SET HTT_RX_IND_PEER_ID_SET +#define HTT_RX_FRAG_IND_PEER_ID_GET HTT_RX_IND_PEER_ID_GET + +#define HTT_RX_FRAG_IND_FLUSH_VALID_SET HTT_RX_IND_FLUSH_VALID_SET +#define HTT_RX_FRAG_IND_FLUSH_VALID_GET HTT_RX_IND_FLUSH_VALID_GET + +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_SET \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_SET +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_GET + +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_SET \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_SET +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_GET + +#define HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET HTT_RX_IND_FW_RX_DESC_BYTES_GET + +#define HTT_RX_FRAG_IND_BYTES \ + (4 /* msg hdr */ + \ + 4 /* flush spec */ + \ + 4 /* (unused) FW rx desc bytes spec */ + \ + 4 /* FW rx desc */) + +/** + * @brief target -> host test message definition + * + * @details + * The following field definitions describe the format of the test + * message sent from the target to the host. + * The message consists of a 4-octet header, followed by a variable + * number of 32-bit integer values, followed by a variable number + * of 8-bit character values. + * + * |31 16|15 8|7 0| + * |-----------------------------------------------------------| + * | num chars | num ints | msg type | + * |-----------------------------------------------------------| + * | int 0 | + * |-----------------------------------------------------------| + * | int 1 | + * |-----------------------------------------------------------| + * | ... | + * |-----------------------------------------------------------| + * | char 3 | char 2 | char 1 | char 0 | + * |-----------------------------------------------------------| + * | | | ... | char 4 | + * |-----------------------------------------------------------| + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a test message + * Value: HTT_MSG_TYPE_TEST + * - NUM_INTS + * Bits 15:8 + * Purpose: indicate how many 32-bit integers follow the message header + * - NUM_CHARS + * Bits 31:16 + * Purpose: indicate how many 8-bit charaters follow the series of integers + */ +#define HTT_RX_TEST_NUM_INTS_M 0xff00 +#define HTT_RX_TEST_NUM_INTS_S 8 +#define HTT_RX_TEST_NUM_CHARS_M 0xffff0000 +#define HTT_RX_TEST_NUM_CHARS_S 16 + +#define HTT_RX_TEST_NUM_INTS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_TEST_NUM_INTS, value); \ + (word) |= (value) << HTT_RX_TEST_NUM_INTS_S; \ + } while (0) +#define HTT_RX_TEST_NUM_INTS_GET(word) \ + (((word) & HTT_RX_TEST_NUM_INTS_M) >> HTT_RX_TEST_NUM_INTS_S) + +#define HTT_RX_TEST_NUM_CHARS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_TEST_NUM_CHARS, value); \ + (word) |= (value) << HTT_RX_TEST_NUM_CHARS_S; \ + } while (0) +#define HTT_RX_TEST_NUM_CHARS_GET(word) \ + (((word) & HTT_RX_TEST_NUM_CHARS_M) >> HTT_RX_TEST_NUM_CHARS_S) + +/** + * @brief target -> host packet log message + * + * @details + * The following field definitions describe the format of the packet log + * message sent from the target to the host. + * The message consists of a 4-octet header,followed by a variable number + * of 32-bit character values. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | | | | msg type | + * |-----------------------------------------------------------| + * | payload | + * |-----------------------------------------------------------| + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a test message + * Value: HTT_MSG_TYPE_PACKETLOG + */ +PREPACK struct htt_pktlog_msg { + A_UINT32 header; + A_UINT32 payload[1 /* or more */]; +} POSTPACK; + + +/* + * Rx reorder statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_reorder_stats { + /* Non QoS MPDUs received */ + A_UINT32 deliver_non_qos; + /* MPDUs received in-order */ + A_UINT32 deliver_in_order; + /* Flush due to reorder timer expired */ + A_UINT32 deliver_flush_timeout; + /* Flush due to move out of window */ + A_UINT32 deliver_flush_oow; + /* Flush due to DELBA */ + A_UINT32 deliver_flush_delba; + /* MPDUs dropped due to FCS error */ + A_UINT32 fcs_error; + /* MPDUs dropped due to monitor mode non-data packet */ + A_UINT32 mgmt_ctrl; + /* Unicast-data MPDUs dropped due to invalid peer */ + A_UINT32 invalid_peer; + /* MPDUs dropped due to duplication (non aggregation) */ + A_UINT32 dup_non_aggr; + /* MPDUs dropped due to processed before */ + A_UINT32 dup_past; + /* MPDUs dropped due to duplicate in reorder queue */ + A_UINT32 dup_in_reorder; + /* Reorder timeout happened */ + A_UINT32 reorder_timeout; + /* invalid bar ssn */ + A_UINT32 invalid_bar_ssn; + /* reorder reset due to bar ssn */ + A_UINT32 ssn_reset; + /* Flush due to delete peer */ + A_UINT32 deliver_flush_delpeer; + /* Flush due to offload */ + A_UINT32 deliver_flush_offload; + /* Flush due to out of buffer */ + A_UINT32 deliver_flush_oob; + /* MPDUs dropped due to PN check fail */ + A_UINT32 pn_fail; + /* MPDUs dropped due to unable to allocate memory */ + A_UINT32 store_fail; + /* Number of times the tid pool alloc succeeded */ + A_UINT32 tid_pool_alloc_succ; + /* Number of times the MPDU pool alloc succeeded */ + A_UINT32 mpdu_pool_alloc_succ; + /* Number of times the MSDU pool alloc succeeded */ + A_UINT32 msdu_pool_alloc_succ; + /* Number of times the tid pool alloc failed */ + A_UINT32 tid_pool_alloc_fail; + /* Number of times the MPDU pool alloc failed */ + A_UINT32 mpdu_pool_alloc_fail; + /* Number of times the MSDU pool alloc failed */ + A_UINT32 msdu_pool_alloc_fail; + /* Number of times the tid pool freed */ + A_UINT32 tid_pool_free; + /* Number of times the MPDU pool freed */ + A_UINT32 mpdu_pool_free; + /* Number of times the MSDU pool freed */ + A_UINT32 msdu_pool_free; + /* number of MSDUs undelivered to HTT and queued + * to Data Rx MSDU free list */ + A_UINT32 msdu_queued; + /* Number of MSDUs released from Data Rx MSDU list to MAC ring */ + A_UINT32 msdu_recycled; + /* Number of MPDUs with invalid peer but A2 found in AST */ + A_UINT32 invalid_peer_a2_in_ast; + /* Number of MPDUs with invalid peer but A3 found in AST */ + A_UINT32 invalid_peer_a3_in_ast; + /* Number of MPDUs with invalid peer, Broadcast or Multicast frame */ + A_UINT32 invalid_peer_bmc_mpdus; + /* Number of MSDUs with err attention word */ + A_UINT32 rxdesc_err_att; + /* Number of MSDUs with flag of peer_idx_invalid */ + A_UINT32 rxdesc_err_peer_idx_inv; + /* Number of MSDUs with flag of peer_idx_timeout */ + A_UINT32 rxdesc_err_peer_idx_to; + /* Number of MSDUs with flag of overflow */ + A_UINT32 rxdesc_err_ov; + /* Number of MSDUs with flag of msdu_length_err */ + A_UINT32 rxdesc_err_msdu_len; + /* Number of MSDUs with flag of mpdu_length_err */ + A_UINT32 rxdesc_err_mpdu_len; + /* Number of MSDUs with flag of tkip_mic_err */ + A_UINT32 rxdesc_err_tkip_mic; + /* Number of MSDUs with flag of decrypt_err */ + A_UINT32 rxdesc_err_decrypt; + /* Number of MSDUs with flag of fcs_err */ + A_UINT32 rxdesc_err_fcs; + /* Number of Unicast (bc_mc bit is not set in attention word) + * frames with invalid peer handler + */ + A_UINT32 rxdesc_uc_msdus_inv_peer; + /* Number of unicast frame directly (direct bit is set in attention word) + * to DUT with invalid peer handler + */ + A_UINT32 rxdesc_direct_msdus_inv_peer; + /* Number of Broadcast/Multicast (bc_mc bit set in attention word) + * frames with invalid peer handler + */ + A_UINT32 rxdesc_bmc_msdus_inv_peer; + /* Number of MSDUs dropped due to no first MSDU flag */ + A_UINT32 rxdesc_no_1st_msdu; + /* Number of MSDUs droped due to ring overflow */ + A_UINT32 msdu_drop_ring_ov; + /* Number of MSDUs dropped due to FC mismatch */ + A_UINT32 msdu_drop_fc_mismatch; + /* Number of MSDUs dropped due to mgt frame in Remote ring */ + A_UINT32 msdu_drop_mgmt_remote_ring; + /* Number of MSDUs dropped due to errors not reported in attention word */ + A_UINT32 msdu_drop_misc; + /* Number of MSDUs go to offload before reorder */ + A_UINT32 offload_msdu_wal; + /* Number of data frame dropped by offload after reorder */ + A_UINT32 offload_msdu_reorder; + /* Number of MPDUs with sequence number in the past and within + the BA window */ + A_UINT32 dup_past_within_window; + /* Number of MPDUs with sequence number in the past and + * outside the BA window */ + A_UINT32 dup_past_outside_window; + /* Number of MSDUs with decrypt/MIC error */ + A_UINT32 rxdesc_err_decrypt_mic; + /* Number of data MSDUs received on both local and remote rings */ + A_UINT32 data_msdus_on_both_rings; +}; + + +/* + * Rx Remote buffer statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_remote_buffer_mgmt_stats { + /* Total number of MSDUs reaped for Rx processing */ + A_UINT32 remote_reaped; + /* MSDUs recycled within firmware */ + A_UINT32 remote_recycled; + /* MSDUs stored by Data Rx */ + A_UINT32 data_rx_msdus_stored; + /* Number of HTT indications from WAL Rx MSDU */ + A_UINT32 wal_rx_ind; + /* Number of unconsumed HTT indications from WAL Rx MSDU */ + A_UINT32 wal_rx_ind_unconsumed; + /* Number of HTT indications from Data Rx MSDU */ + A_UINT32 data_rx_ind; + /* Number of unconsumed HTT indications from Data Rx MSDU */ + A_UINT32 data_rx_ind_unconsumed; + /* Number of HTT indications from ATHBUF */ + A_UINT32 athbuf_rx_ind; + /* Number of remote buffers requested for refill */ + A_UINT32 refill_buf_req; + /* Number of remote buffers filled by the host */ + A_UINT32 refill_buf_rsp; + /* Number of times MAC hw_index = f/w write_index */ + A_INT32 mac_no_bufs; + /* Number of times f/w write_index = f/w read_index for MAC Rx ring */ + A_INT32 fw_indices_equal; + /* Number of times f/w finds no buffers to post */ + A_INT32 host_no_bufs; +}; + +/* + * TXBF MU/SU packets and NDPA statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_txbf_musu_ndpa_pkts_stats { + /* number of TXBF MU packets received */ + A_UINT32 number_mu_pkts; + /* number of TXBF SU packets received */ + A_UINT32 number_su_pkts; + /* number of TXBF directed NDPA */ + A_UINT32 txbf_directed_ndpa_count; + /* number of TXBF retried NDPA */ + A_UINT32 txbf_ndpa_retry_count; + /* total number of TXBF NDPA */ + A_UINT32 txbf_total_ndpa_count; + /* must be set to 0x0 */ + A_UINT32 reserved[3]; +}; + +/* + * htt_dbg_stats_status - + * present - The requested stats have been delivered in full. + * This indicates that either the stats information was contained + * in its entirety within this message, or else this message + * completes the delivery of the requested stats info that was + * partially delivered through earlier STATS_CONF messages. + * partial - The requested stats have been delivered in part. + * One or more subsequent STATS_CONF messages with the same + * cookie value will be sent to deliver the remainder of the + * information. + * error - The requested stats could not be delivered, for example due + * to a shortage of memory to construct a message holding the + * requested stats. + * invalid - The requested stat type is either not recognized, or the + * target is configured to not gather the stats type in question. + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * series_done - This special value indicates that no further stats info + * elements are present within a series of stats info elems + * (within a stats upload confirmation message). + */ +enum htt_dbg_stats_status { + HTT_DBG_STATS_STATUS_PRESENT = 0, + HTT_DBG_STATS_STATUS_PARTIAL = 1, + HTT_DBG_STATS_STATUS_ERROR = 2, + HTT_DBG_STATS_STATUS_INVALID = 3, + + + HTT_DBG_STATS_STATUS_SERIES_DONE = 7 +}; + +/** + * @brief target -> host statistics upload + * + * @details + * The following field definitions describe the format of the HTT target + * to host stats upload confirmation message. + * The message contains a cookie echoed from the HTT host->target stats + * upload request, which identifies which request the confirmation is + * for, and a series of tag-length-value stats information elements. + * The tag-length header for each stats info element also includes a + * status field, to indicate whether the request for the stat type in + * question was fully met, partially met, unable to be met, or invalid + * (if the stat type in question is disabled in the target). + * A special value of all 1's in this status field is used to indicate + * the end of the series of stats info elements. + * + * + * |31 16|15 8|7 5|4 0| + * |------------------------------------------------------------| + * | reserved | msg type | + * |------------------------------------------------------------| + * | cookie LSBs | + * |------------------------------------------------------------| + * | cookie MSBs | + * |------------------------------------------------------------| + * | stats entry length | reserved | S |stat type| + * |------------------------------------------------------------| + * | | + * | type-specific stats info | + * | | + * |------------------------------------------------------------| + * | stats entry length | reserved | S |stat type| + * |------------------------------------------------------------| + * | | + * | type-specific stats info | + * | | + * |------------------------------------------------------------| + * | n/a | reserved | 111 | n/a | + * |------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this is a statistics upload confirmation message + * Value: 0x9 + * - COOKIE_LSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: LSBs of the opaque cookie specified by the host-side requestor + * - COOKIE_MSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + * + * Stats Information Element tag-length header fields: + * - STAT_TYPE + * Bits 4:0 + * Purpose: identifies the type of statistics info held in the + * following information element + * Value: htt_dbg_stats_type + * - STATUS + * Bits 7:5 + * Purpose: indicate whether the requested stats are present + * Value: htt_dbg_stats_status, including a special value (0x7) to mark + * the completion of the stats entry series + * - LENGTH + * Bits 31:16 + * Purpose: indicate the stats information size + * Value: This field specifies the number of bytes of stats information + * that follows the element tag-length header. + * It is expected but not required that this length is a multiple of + * 4 bytes. Even if the length is not an integer multiple of 4, the + * subsequent stats entry header will begin on a 4-byte aligned + * boundary. + */ +#define HTT_T2H_STATS_COOKIE_SIZE 8 + +#define HTT_T2H_STATS_CONF_TAIL_SIZE 4 + +#define HTT_T2H_STATS_CONF_HDR_SIZE 4 + +#define HTT_T2H_STATS_CONF_TLV_HDR_SIZE 4 + +#define HTT_T2H_STATS_CONF_TLV_TYPE_M 0x0000001f +#define HTT_T2H_STATS_CONF_TLV_TYPE_S 0 +#define HTT_T2H_STATS_CONF_TLV_STATUS_M 0x000000e0 +#define HTT_T2H_STATS_CONF_TLV_STATUS_S 5 +#define HTT_T2H_STATS_CONF_TLV_LENGTH_M 0xffff0000 +#define HTT_T2H_STATS_CONF_TLV_LENGTH_S 16 + +#define HTT_T2H_STATS_CONF_TLV_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_TYPE, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_TYPE_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_TYPE_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_TYPE_M) >> \ + HTT_T2H_STATS_CONF_TLV_TYPE_S) + +#define HTT_T2H_STATS_CONF_TLV_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_STATUS, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_STATUS_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_STATUS_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_STATUS_M) >> \ + HTT_T2H_STATS_CONF_TLV_STATUS_S) + +#define HTT_T2H_STATS_CONF_TLV_LENGTH_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_LENGTH, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_LENGTH_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_LENGTH_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_LENGTH_M) >> \ + HTT_T2H_STATS_CONF_TLV_LENGTH_S) + +#define HL_HTT_FW_RX_DESC_RSVD_SIZE 18 +#define HTT_MAX_AGGR 64 +#define HTT_HL_MAX_AGGR 18 + +/** + * @brief host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank + * + * @details + * The following field definitions describe the format of the HTT host + * to target frag_desc/msdu_ext bank configuration message. + * The message contains the based address and the min and max id of the + * MSDU_EXT/FRAG_DESC that will be used by the HTT to map MSDU DESC and + * MSDU_EXT/FRAG_DESC. + * HTT will use id in HTT descriptor instead sending the frag_desc_ptr. + * In peregrine the firmware will use fragment_desc_ptr but in WIFI2.0 + * the hardware does the mapping/translation. + * + * Total banks that can be configured is configured to 16. + * + * This should be called before any TX has be initiated by the HTT + * + * |31 16|15 8|7 5|4 0| + * |------------------------------------------------------------| + * | DESC_SIZE | NUM_BANKS | RES |SWP|pdev| msg type | + * |------------------------------------------------------------| + * | BANK0_BASE_ADDRESS (bits 31:0) | + #if HTT_PADDR64 + * | BANK0_BASE_ADDRESS (bits 63:32) | + #endif + * |------------------------------------------------------------| + * | ... | + * |------------------------------------------------------------| + * | BANK15_BASE_ADDRESS (bits 31:0) | + #if HTT_PADDR64 + * | BANK15_BASE_ADDRESS (bits 63:32) | + #endif + * |------------------------------------------------------------| + * | BANK0_MAX_ID | BANK0_MIN_ID | + * |------------------------------------------------------------| + * | ... | + * |------------------------------------------------------------| + * | BANK15_MAX_ID | BANK15_MIN_ID | + * |------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Value: 0x6 + * for systems with 64-bit format for bus addresses: + * - BANKx_BASE_ADDRESS_LO + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: lower 4 bytes of MSDU_EXT bank physical / bus address + * - BANKx_BASE_ADDRESS_HI + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: higher 4 bytes of MSDU_EXT bank physical / bus address + * for systems with 32-bit format for bus addresses: + * - BANKx_BASE_ADDRESS + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: MSDU_EXT bank physical / bus address + * - BANKx_MIN_ID + * Bits 15:0 + * Purpose: Provide a mechanism to specify the min index that needs to + * mapped. + * - BANKx_MAX_ID + * Bits 31:16 + * Purpose: Provide a mechanism to specify the max index that needs to + * mapped. + * + */ + +/** @todo Compress the fields to fit MAX HTT Message size, until then + * configure to a safe value. + * @note MAX supported banks is 16. + */ +#define HTT_TX_MSDU_EXT_BANK_MAX 4 + +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_M 0x300 +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_S 8 + +#define HTT_H2T_FRAG_DESC_BANK_SWAP_M 0x400 +#define HTT_H2T_FRAG_DESC_BANK_SWAP_S 10 + +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_M 0xff0000 +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S 16 + +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_M 0xff000000 +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S 24 + +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_M 0xffff +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S 0 + +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_M 0xffff0000 +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S 16 + +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_PDEVID, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_PDEVID_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_PDEVID_M) >> \ + HTT_H2T_FRAG_DESC_BANK_PDEVID_S) + +#define HTT_H2T_FRAG_DESC_BANK_SWAP_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_SWAP, value);\ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_SWAP_S);\ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_SWAP_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_SWAP_M) >> \ + HTT_H2T_FRAG_DESC_BANK_SWAP_S) + +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_NUM_BANKS, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_M) >> \ + HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S) + +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_DESC_SIZE, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_M) >> \ + HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S) + +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_MIN_IDX, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_MIN_IDX_M) >> \ + HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S) + +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_MAX_IDX, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_MAX_IDX_M) >> \ + HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S) + + +/* + * TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T: + * This macro defines a htt_tx_frag_descXXX_bank_cfg_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_tx_frag_desc32_bank_cfg_t and + * htt_tx_frag_desc64_bank_cfg_t structs. + */ +#define TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T( \ + _paddr_bits_, \ + _paddr__bank_base_address_) \ + PREPACK struct htt_tx_frag_desc ## _paddr_bits_ ## _bank_cfg_t { \ + /** word 0 \ + * msg_type: 8, \ + * pdev_id: 2, \ + * swap: 1, \ + * reserved0: 5, \ + * num_banks: 8, \ + * desc_size: 8; \ + */ \ + A_UINT32 word0; \ + /* \ + * If bank_base_address is 64 bits, the upper / lower + * halves are stored \ + * in little-endian order (bytes 0-3 in the first A_UINT32, + * bytes 4-7 in the second A_UINT32). \ + */ \ + _paddr__bank_base_address_[HTT_TX_MSDU_EXT_BANK_MAX]; \ + A_UINT32 bank_info[HTT_TX_MSDU_EXT_BANK_MAX]; \ + } POSTPACK +/* define htt_tx_frag_desc32_bank_cfg_t */ +TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T(32, HTT_VAR_PADDR32(bank_base_address)); +/* define htt_tx_frag_desc64_bank_cfg_t */ +TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T(64, HTT_VAR_PADDR64_LE(bank_base_address)); +/* + * Make htt_tx_frag_desc_bank_cfg_t be an alias for either + * htt_tx_frag_desc32_bank_cfg_t or htt_tx_frag_desc64_bank_cfg_t + */ +#if HTT_PADDR64 +#define htt_tx_frag_desc_bank_cfg_t htt_tx_frag_desc64_bank_cfg_t +#else +#define htt_tx_frag_desc_bank_cfg_t htt_tx_frag_desc32_bank_cfg_t +#endif + + +/** + * @brief target -> host HTT TX Credit total count update message definition + * + *|31 16|15|14 9| 8 |7 0 | + *|---------------------+--+----------+-------+----------| + *|cur htt credit delta | Q| reserved | sign | msg type | + *|------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a htt tx credit delta update message + * Value: 0xe + * - SIGN + * Bits 8 + * identifies whether credit delta is positive or negative + * Value: + * - 0x0: credit delta is positive, rebalance in some buffers + * - 0x1: credit delta is negative, rebalance out some buffers + * - reserved + * Bits 14:9 + * Value: 0x0 + * - TXQ_GRP + * Bit 15 + * Purpose: indicates whether any tx queue group information elements + * are appended to the tx credit update message + * Value: 0 -> no tx queue group information element is present + * 1 -> a tx queue group information element immediately follows + * - DELTA_COUNT + * Bits 31:16 + * Purpose: Specify current htt credit delta absolute count + */ + +#define HTT_TX_CREDIT_SIGN_BIT_M 0x00000100 +#define HTT_TX_CREDIT_SIGN_BIT_S 8 +#define HTT_TX_CREDIT_TXQ_GRP_M 0x00008000 +#define HTT_TX_CREDIT_TXQ_GRP_S 15 +#define HTT_TX_CREDIT_DELTA_ABS_M 0xffff0000 +#define HTT_TX_CREDIT_DELTA_ABS_S 16 + + +#define HTT_TX_CREDIT_SIGN_BIT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_SIGN_BIT, value); \ + (word) |= (value) << HTT_TX_CREDIT_SIGN_BIT_S; \ + } while (0) + +#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \ + (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S) + +#define HTT_TX_CREDIT_TXQ_GRP_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_TXQ_GRP, value); \ + (word) |= (value) << HTT_TX_CREDIT_TXQ_GRP_S; \ + } while (0) + +#define HTT_TX_CREDIT_TXQ_GRP_GET(word) \ + (((word) & HTT_TX_CREDIT_TXQ_GRP_M) >> HTT_TX_CREDIT_TXQ_GRP_S) + +#define HTT_TX_CREDIT_DELTA_ABS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_DELTA_ABS, value); \ + (word) |= (value) << HTT_TX_CREDIT_DELTA_ABS_S; \ + } while (0) + +#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \ + (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S) + + +#define HTT_TX_CREDIT_MSG_BYTES 4 + +#define HTT_TX_CREDIT_SIGN_BIT_POSITIVE 0x0 +#define HTT_TX_CREDIT_SIGN_BIT_NEGATIVE 0x1 + + +/** + * @brief HTT WDI_IPA Operation Response Message + * + * @details + * HTT WDI_IPA Operation Response message is sent by target + * to host confirming suspend or resume operation. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | op_code | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * | Rsvd | Response len | + * |-------------------------------------------------------------------| + * | | + * | Response-type specific info | + * | | + * | | + * |-------------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA Operation Response message + * value: = 0x13 + * - OP_CODE + * Bits 31:16 + * Purpose: Identifies the operation target is responding to + * (e.g. TX suspend) + * value: = enum htt_wdi_ipa_op_code + * - RSP_LEN + * Bits 16:0 + * Purpose: length for the response-type specific info + * value: = length in bytes for response-type specific info + * For example, if OP_CODE == HTT_WDI_IPA_OPCODE_DBG_STATS, the + * length value will be sizeof(struct wlan_wdi_ipa_dbg_stats_t). + */ + +PREPACK struct htt_wdi_ipa_op_response_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 + msg_type:8, /* HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE */ + reserved1:8, + op_code:16; + A_UINT32 + rsp_len:16, + reserved2:16; +} POSTPACK; + +#define HTT_WDI_IPA_OP_RESPONSE_SZ 8 /* bytes */ + +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_M 0xffff0000 +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S 16 + +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_M 0x0000ffff +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S 0 + +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_RESPONSE_OP_CODE_M) >> \ + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S) +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_RESPONSE_OP_CODE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S)); \ + } while (0) + +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_M) >> \ + HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S) +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_RESPONSE_RSP_LEN, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S)); \ + } while (0) + + +enum htt_phy_mode { + htt_phy_mode_11a = 0, + htt_phy_mode_11g = 1, + htt_phy_mode_11b = 2, + htt_phy_mode_11g_only = 3, + htt_phy_mode_11na_ht20 = 4, + htt_phy_mode_11ng_ht20 = 5, + htt_phy_mode_11na_ht40 = 6, + htt_phy_mode_11ng_ht40 = 7, + htt_phy_mode_11ac_vht20 = 8, + htt_phy_mode_11ac_vht40 = 9, + htt_phy_mode_11ac_vht80 = 10, + htt_phy_mode_11ac_vht20_2g = 11, + htt_phy_mode_11ac_vht40_2g = 12, + htt_phy_mode_11ac_vht80_2g = 13, + htt_phy_mode_11ac_vht80_80 = 14, /* 80+80 */ + htt_phy_mode_11ac_vht160 = 15, + + htt_phy_mode_max, +}; + +/** + * @brief target -> host HTT channel change indication + * @details + * Specify when a channel change occurs. + * This allows the host to precisely determine which rx frames arrived + * on the old channel and which rx frames arrived on the new channel. + * + *|31 |7 0 | + *|-------------------------------------------+----------| + *| reserved | msg type | + *|------------------------------------------------------| + *| primary_chan_center_freq_mhz | + *|------------------------------------------------------| + *| contiguous_chan1_center_freq_mhz | + *|------------------------------------------------------| + *| contiguous_chan2_center_freq_mhz | + *|------------------------------------------------------| + *| phy_mode | + *|------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a htt channel change indication message + * Value: 0x15 + * - PRIMARY_CHAN_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: identify the (center of the) new 20 MHz primary channel + * Value: center frequency of the 20 MHz primary channel, in MHz units + * - CONTIG_CHAN1_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: identify the (center of the) contiguous frequency range + * comprising the new channel. + * For example, if the new channel is a 80 MHz channel extending + * 60 MHz beyond the primary channel, this field would be 30 larger + * than the primary channel center frequency field. + * Value: center frequency of the contiguous frequency range comprising + * the full channel in MHz units + * (80+80 channels also use the CONTIG_CHAN2 field) + * - CONTIG_CHAN2_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: Identify the (center of the) 80 MHz extension frequency range + * within a VHT 80+80 channel. + * This field is only relevant for VHT 80+80 channels. + * Value: center frequency of the 80 MHz extension channel in a VHT 80+80 + * channel (arbitrary value for cases besides VHT 80+80) + * - PHY_MODE + * Bits 31:0 + * Purpose: specify the PHY channel's type (legacy vs. HT vs. VHT), width, + * and band + * Value: htt_phy_mode enum value + */ + +PREPACK struct htt_chan_change_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 msg_type:8, /* HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE */ + reserved1:24; + A_UINT32 primary_chan_center_freq_mhz; + A_UINT32 contig_chan1_center_freq_mhz; + A_UINT32 contig_chan2_center_freq_mhz; + A_UINT32 phy_mode; +} POSTPACK; + +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_PHY_MODE_M 0xffffffff +#define HTT_CHAN_CHANGE_PHY_MODE_S 0 + + +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_PHY_MODE_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_CHANGE_PHY_MODE, value); \ + (word) |= (value) << HTT_CHAN_CHANGE_PHY_MODE_S; \ +} while (0) +#define HTT_CHAN_CHANGE_PHY_MODE_GET(word) \ + (((word) & HTT_CHAN_CHANGE_PHY_MODE_M) \ + >> HTT_CHAN_CHANGE_PHY_MODE_S) + +#define HTT_CHAN_CHANGE_BYTES sizeof(struct htt_chan_change_t) + + +/** + * @brief rx offload packet error message + * + * @details + * HTT_RX_OFLD_PKT_ERR message is sent by target to host to indicate err + * of target payload like mic err. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | tid | vdev_id | msg_sub_type | msg_type | + * |-------------------------------------------------------------------| + * : (sub-type dependent content) : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -: + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: Identifies this as HTT_RX_OFLD_PKT_ERR message + * value: 0x16 (HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR) + * - msg_sub_type + * Bits 15:8 + * Purpose: Identifies which type of rx error is reported by this message + * value: htt_rx_ofld_pkt_err_type + * - vdev_id + * Bits 23:16 + * Purpose: Identifies which vdev received the erroneous rx frame + * value: + * - tid + * Bits 31:24 + * Purpose: Identifies the traffic type of the rx frame + * value: + * + * - The payload fields used if the sub-type == MIC error are shown below. + * Note - MIC err is per MSDU, while PN is per MPDU. + * The FW will discard the whole MPDU if any MSDU within the MPDU is marked + * with MIC err in A-MSDU case, so FW will send only one HTT message + * with the PN of this MPDU attached to indicate MIC err for one MPDU + * instead of sending separate HTT messages for each wrong MSDU within + * the MPDU. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | Rsvd | key_id | peer_id | + * |-------------------------------------------------------------------| + * | receiver MAC addr 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | receiver MAC addr 47:32 | + * |-------------------------------------------------------------------| + * | transmitter MAC addr 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | transmitter MAC addr 47:32 | + * |-------------------------------------------------------------------| + * | PN 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | PN 47:32 | + * |-------------------------------------------------------------------| + * - peer_id + * Bits 15:0 + * Purpose: identifies which peer is frame is from + * value: + * - key_id + * Bits 23:16 + * Purpose: identifies key_id of rx frame + * value: + * - RA_31_0 (receiver MAC addr 31:0) + * Bits 31:0 + * Purpose: identifies by MAC address which vdev received the frame + * value: MAC address lower 4 bytes + * - RA_47_32 (receiver MAC addr 47:32) + * Bits 15:0 + * Purpose: identifies by MAC address which vdev received the frame + * value: MAC address upper 2 bytes + * - TA_31_0 (transmitter MAC addr 31:0) + * Bits 31:0 + * Purpose: identifies by MAC address which peer transmitted the frame + * value: MAC address lower 4 bytes + * - TA_47_32 (transmitter MAC addr 47:32) + * Bits 15:0 + * Purpose: identifies by MAC address which peer transmitted the frame + * value: MAC address upper 2 bytes + * - PN_31_0 + * Bits 31:0 + * Purpose: Identifies pn of rx frame + * value: PN lower 4 bytes + * - PN_47_32 + * Bits 15:0 + * Purpose: Identifies pn of rx frame + * value: + * TKIP or CCMP: PN upper 2 bytes + * WAPI: PN bytes 6:5 (bytes 15:7 not included in this message) + */ + +enum htt_rx_ofld_pkt_err_type { + HTT_RX_OFLD_PKT_ERR_TYPE_NONE = 0, + HTT_RX_OFLD_PKT_ERR_TYPE_MIC_ERR, +}; + +/* definition for HTT_RX_OFLD_PKT_ERR msg hdr */ +#define HTT_RX_OFLD_PKT_ERR_HDR_BYTES 4 + +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_M 0x0000ff00 +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S 8 + +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_M 0x00ff0000 +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_S 16 + +#define HTT_RX_OFLD_PKT_ERR_TID_M 0xff000000 +#define HTT_RX_OFLD_PKT_ERR_TID_S 24 + +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_M) \ + >> HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S) +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S)); \ + } while (0) + +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_VDEV_ID_M) >> \ + HTT_RX_OFLD_PKT_ERR_VDEV_ID_S) +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_VDEV_ID_S)); \ + } while (0) + +#define HTT_RX_OFLD_PKT_ERR_TID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_TID_M) >> HTT_RX_OFLD_PKT_ERR_TID_S) +#define HTT_RX_OFLD_PKT_ERR_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_TID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_TID_S)); \ + } while (0) + +/* definition for HTT_RX_OFLD_PKT_ERR_MIC_ERR msg sub-type payload */ +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_BYTES 28 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_M 0x00ff0000 +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S 16 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S)); \ +} while (0) + +/** + * @brief peer rate report message + * + * @details + * HTT_T2H_MSG_TYPE_RATE_REPORT message is sent by target to host to indicate the + * justified rate of all the peers. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | peer_count | | msg_type | + * |-------------------------------------------------------------------| + * : Payload (variant number of peer rate report) : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -: + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: Identifies this as HTT_T2H_MSG_TYPE_RATE_REPORT message. + * value: 0x17 (HTT_T2H_MSG_TYPE_RATE_REPORT) + * - reserved + * Bits 15:8 + * Purpose: + * value: + * - peer_count + * Bits 31:16 + * Purpose: Specify how many peer rate report elements are present in the payload. + * value: + * + * Payload: + * There are variant number of peer rate report follow the first 32 bits. + * The peer rate report is defined as follows. + * + * |31 20|19 16|15 0| + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #0 + * | rate | / + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #1 + * | rate | / + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #2 + * | rate | / + * |-------------------------------------------------------------------|- + * : : + * : : + * : : + * :-------------------------------------------------------------------: + * + * - peer_id + * Bits 15:0 + * Purpose: identify the peer + * value: + * - phy + * Bits 19:16 + * Purpose: identify which phy is in use + * value: 0=11b, 1=11a/g, 2=11n, 3=11ac. + * Please see enum htt_peer_report_phy_type for detail. + * - reserved + * Bits 31:20 + * Purpose: + * value: + * - rate + * Bits 31:0 + * Purpose: represent the justified rate of the peer specified by peer_id + * value: + */ + +enum htt_peer_rate_report_phy_type { + HTT_PEER_RATE_REPORT_11B = 0, + HTT_PEER_RATE_REPORT_11A_G, + HTT_PEER_RATE_REPORT_11N, + HTT_PEER_RATE_REPORT_11AC, +}; + +#define HTT_PEER_RATE_REPORT_SIZE 8 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_M 0xffff0000 +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S 16 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_M 0x0000ffff +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_S 0 + +#define HTT_PEER_RATE_REPORT_MSG_PHY_M 0x000f0000 +#define HTT_PEER_RATE_REPORT_MSG_PHY_S 16 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S) +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PEER_COUNT, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S)); \ + } while (0) + +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PEER_ID_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PEER_ID_S) +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PEER_ID_S)); \ + } while (0) + +#define HTT_PEER_RATE_REPORT_MSG_PHY_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PHY_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PHY_S) +#define HTT_PEER_RATE_REPORT_MSG_PHY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PHY, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PHY_S)); \ + } while (0) + +/** + * @brief HTT_T2H_MSG_TYPE_FLOW_POOL_MAP Message + * + * @details + * HTT_T2H_MSG_TYPE_FLOW_POOL_MAP message is sent by the target when setting up + * a flow of descriptors. + * + * This message is in TLV format and indicates the parameters to be setup a + * flow in the host. Each entry indicates that a particular flow ID is ready to + * receive descriptors from a specified pool. + * + * The message would appear as follows: + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * header | reserved | num_flows | msg_type | + * |-------------------------------------------------------------------| + * | | + * : payload : + * | | + * |-------------------------------------------------------------------| + * + * The header field is one DWORD long and is interpreted as follows: + * b'0:7 - msg_type: This will be set to HTT_T2H_MSG_TYPE_FLOW_POOL_MAP + * b'8-15 - num_flows: This will indicate the number of flows being setup in + * this message + * b'16-31 - reserved: These bits are reserved for future use + * + * Payload: + * The payload would contain multiple objects of the following structure. Each + * object represents a flow. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * header | reserved | num_flows | msg_type | + * |-------------------------------------------------------------------| + * payload0| flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved0 | flow_pool_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_size | + * |-------------------------------------------------------------------| + * | reserved2 | + * |-------------------------------------------------------------------| + * payload1| flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved0 | flow_pool_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_size | + * |-------------------------------------------------------------------| + * | reserved2 | + * |-------------------------------------------------------------------| + * | . | + * | . | + * | . | + * |-------------------------------------------------------------------| + * + * Each payload is 5 DWORDS long and is interpreted as follows: + * dword0 - b'0:31 - flow_type: This indicates the type of the entity to which + * this flow is associated. It can be VDEV, peer, + * or tid (AC). Based on enum htt_flow_type. + * + * dword1 - b'0:31 - flow_id: Identifier for the flow corresponding to this + * object. For flow_type vdev it is set to the + * vdevid, for peer it is peerid and for tid, it is + * tid_num. + * + * dword2 - b'0:15 - flow_pool_id: Identifier of the descriptor-pool being used + * in the host for this flow + * b'16:31 - reserved0: This field in reserved for the future. In case + * we have a hierarchical implementation (HCM) of + * pools, it can be used to indicate the ID of the + * parent-pool. + * + * dword3 - b'0:15 - flow_pool_size: Size of the pool in number of descriptors. + * Descriptors for this flow will be + * allocated from this pool in the host. + * b'16:31 - reserved1: This field in reserved for the future. In case + * we have a hierarchical implementation of pools, + * it can be used to indicate the max number of + * descriptors in the pool. The b'0:15 can be used + * to indicate min number of descriptors in the + * HCM scheme. + * + * dword4 - b'0:31 - reserved2: This field in reserved for the future. In case + * we have a hierarchical implementation of pools, + * b'0:15 can be used to indicate the + * priority-based borrowing (PBB) threshold of + * the flow's pool. The b'16:31 are still left + * reserved. + */ + +enum htt_flow_type { + FLOW_TYPE_VDEV = 0, + /* Insert new flow types above this line */ +}; + +PREPACK struct htt_flow_pool_map_payload_t { + A_UINT32 flow_type; + A_UINT32 flow_id; + A_UINT32 flow_pool_id:16, + reserved0:16; + A_UINT32 flow_pool_size:16, + reserved1:16; + A_UINT32 reserved2; +} POSTPACK; + +#define HTT_FLOW_POOL_MAP_HEADER_SZ (sizeof(A_UINT32)) + +#define HTT_FLOW_POOL_MAP_PAYLOAD_SZ \ + (sizeof(struct htt_flow_pool_map_payload_t)) + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_M 0x0000ff00 +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_S 8 + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_M 0xffffffff +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_ID_M 0xffffffff +#define HTT_FLOW_POOL_MAP_FLOW_ID_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_M 0x0000ffff +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_M 0x0000ffff +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S 0 + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_NUM_FLOWS_M) >> HTT_FLOW_POOL_MAP_NUM_FLOWS_S) + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_TYPE_M) >> HTT_FLOW_POOL_MAP_FLOW_TYPE_S) + +#define HTT_FLOW_POOL_MAP_FLOW_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_ID_M) >> HTT_FLOW_POOL_MAP_FLOW_ID_S) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_POOL_ID_M) >> \ + HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_M) >> \ + HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S) + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_NUM_FLOWS, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_NUM_FLOWS_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_TYPE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_TYPE_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_POOL_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S)); \ + } while (0) + +/** + * @brief HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP Message + * + * @details + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP message is sent by the target when tearing + * down a flow of descriptors. + * This message indicates that for the flow (whose ID is provided) is wanting + * to stop receiving descriptors. This flow ID corresponds to the ID of the + * pool of descriptors from where descriptors are being allocated for this + * flow. When a flow (and its pool) are unmapped, all the child-pools will also + * be unmapped by the host. + * + * The message would appear as follows: + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved0 | msg_type | + * |-------------------------------------------------------------------| + * | flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_id | + * |-------------------------------------------------------------------| + * + * The message is interpreted as follows: + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * b'8:31 - reserved0: Reserved for future use + * + * dword1 - b'0:31 - flow_type: This indicates the type of the entity to which + * this flow is associated. It can be VDEV, peer, + * or tid (AC). Based on enum htt_flow_type. + * + * dword2 - b'0:31 - flow_id: Identifier for the flow corresponding to this + * object. For flow_type vdev it is set to the + * vdevid, for peer it is peerid and for tid, it is + * tid_num. + * + * dword3 - b'0:15 - flow_pool_id: Identifier of the descriptor-pool being + * used in the host for this flow + * b'16:31 - reserved0: This field in reserved for the future. + * + */ + +PREPACK struct htt_flow_pool_unmap_t { + A_UINT32 msg_type:8, + reserved0:24; + A_UINT32 flow_type; + A_UINT32 flow_id; + A_UINT32 flow_pool_id:16, + reserved1:16; +} POSTPACK; + +#define HTT_FLOW_POOL_UNMAP_SZ (sizeof(struct htt_flow_pool_unmap_t)) + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_M 0xffffffff +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_M 0xffffffff +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_M 0x0000ffff +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_TYPE_M) >> \ + HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_ID_M) >> HTT_FLOW_POOL_UNMAP_FLOW_ID_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_M) >> \ + HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_TYPE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S)); \ + } while (0) + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S)); \ + } while (0) + +#endif diff --git a/target/inc/htt_common.h b/target/inc/htt_common.h new file mode 100644 index 0000000000..0e9d7c357d --- /dev/null +++ b/target/inc/htt_common.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_common.h + * + * @details the public header file of HTT layer shared between host and firmware + */ + +#ifndef _HTT_COMMON_H_ +#define _HTT_COMMON_H_ + +enum htt_sec_type { + htt_sec_type_none, + htt_sec_type_wep128, + htt_sec_type_wep104, + htt_sec_type_wep40, + htt_sec_type_tkip, + htt_sec_type_tkip_nomic, + htt_sec_type_aes_ccmp, + htt_sec_type_wapi, + htt_sec_type_aes_ccmp_256, + htt_sec_type_aes_gcmp, + htt_sec_type_aes_gcmp_256, + + /* keep this last! */ + htt_num_sec_types +}; + +enum htt_rx_ind_mpdu_status { + HTT_RX_IND_MPDU_STATUS_UNKNOWN = 0x0, + HTT_RX_IND_MPDU_STATUS_OK, + HTT_RX_IND_MPDU_STATUS_ERR_FCS, + HTT_RX_IND_MPDU_STATUS_ERR_DUP, + HTT_RX_IND_MPDU_STATUS_ERR_REPLAY, + HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER, + HTT_RX_IND_MPDU_STATUS_UNAUTH_PEER, /* only accept EAPOL frames */ + HTT_RX_IND_MPDU_STATUS_OUT_OF_SYNC, + HTT_RX_IND_MPDU_STATUS_MGMT_CTRL, /* Non-data in promiscous mode */ + HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR, + HTT_RX_IND_MPDU_STATUS_DECRYPT_ERR, + HTT_RX_IND_MPDU_STATUS_MPDU_LENGTH_ERR, + HTT_RX_IND_MPDU_STATUS_ENCRYPT_REQUIRED_ERR, + HTT_RX_IND_MPDU_STATUS_PRIVACY_ERR, + + /* + * MISC: discard for unspecified reasons. + * Leave this enum value last. + */ + HTT_RX_IND_MPDU_STATUS_ERR_MISC = 0xFF +}; + +#define HTT_INVALID_PEER 0xffff +#define HTT_INVALID_VDEV 0xff + +#define HTT_NON_QOS_TID 16 +#define HTT_INVALID_TID 31 + +#define HTT_TX_EXT_TID_DEFAULT 0 +#define HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST HTT_NON_QOS_TID +#define HTT_TX_EXT_TID_MGMT 17 +#define HTT_TX_EXT_TID_INVALID HTT_INVALID_TID +#define HTT_TX_EXT_TID_NONPAUSE 19 + + + +#define HTT_TX_L3_CKSUM_OFFLOAD 1 +#define HTT_TX_L4_CKSUM_OFFLOAD 2 + + +/** + * @brief General specification of the tx frame contents + * + * @details + * For efficiency, the HTT packet type values correspond + * to the bit positions of the WAL packet type values, so the + * translation is a simple shift operation. + * The exception is the "mgmt" type, which specifies frame payload + * type rather than L2 header type. + */ +enum htt_pkt_type { + htt_pkt_type_raw = 0, + htt_pkt_type_native_wifi = 1, + htt_pkt_type_ethernet = 2, + htt_pkt_type_mgmt = 3, + htt_pkt_type_eth2 = 4, + + /* keep this last */ + htt_pkt_num_types +}; + +#define HTT_TX_HOST_MSDU_ID_SPACE_BEGIN 0 +#define HTT_TX_IPA_MSDU_ID_SPACE_BEGIN 3000 +#define TGT_RX2TX_MSDU_ID_SPACE_BEGIN 6000 + +#endif /* _HTT_COMMON_H_ */ diff --git a/target/inc/htt_isoc.h b/target/inc/htt_isoc.h new file mode 100644 index 0000000000..c149192211 --- /dev/null +++ b/target/inc/htt_isoc.h @@ -0,0 +1,1058 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_isoc.h + * + * @details + * This file defines the target --> host messages that configure the + * host data-path SW with the information required for data transfers + * to and from the target. + */ + +#ifndef _HTT_ISOC_H_ +#define _HTT_ISOC_H_ + +#include /* A_UINT32, A_UINT8 */ + +#ifdef ATHR_WIN_NWF +#pragma warning( disable:4214 ) /* bit field types other than int */ +#endif + +#include "htt_common.h" + +/*=== definitions that apply to all messages ================================*/ + +typedef enum htt_isoc_t2h_msg_type { + /* 0x0 reserved for VERSION message (probably not needed) */ + + /* PEER_INFO - specify ID and parameters of a new peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_INFO = 0x1, + + /* PEER_UNMAP - deallocate the ID that refers to a peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_UNMAP = 0x2, + + /* ADDBA - start rx aggregation for the specified peer-TID */ + HTT_ISOC_T2H_MSG_TYPE_RX_ADDBA = 0x3, + + /* DELBA - stop rx aggregation for the specified peer-TID */ + HTT_ISOC_T2H_MSG_TYPE_RX_DELBA = 0x4, + + /* TX_COMPL_IND - over-the-air tx completion notification for a tx frame */ + HTT_ISOC_T2H_MSG_TYPE_TX_COMPL_IND = 0x5, + + /* SEC_IND - notification of the type of security used for a new peer */ + HTT_ISOC_T2H_MSG_TYPE_SEC_IND = 0x6, + + /* PEER_TX_READY - the target is ready to transmit to a new peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_TX_READY = 0x7, + + /* RX_ERR - notification that an rx frame was discarded due to errors */ + HTT_ISOC_T2H_MSG_TYPE_RX_ERR = 0x8, + + /* keep this last */ + HTT_ISOC_T2H_NUM_MSGS +} htt_isoc_t2h_msg_type; + +/* + * HTT ISOC target to host message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_ISOC_T2H_MSG_TYPE_M 0xff +#define HTT_ISOC_T2H_MSG_TYPE_S 0 + +#define HTT_ISOC_T2H_MSG_TYPE_SET(msg_addr, msg_type) \ + (*((A_UINT8 *) msg_addr) = (msg_type)) +#define HTT_ISOC_T2H_MSG_TYPE_GET(msg_addr) \ + (*((A_UINT8 *) msg_addr)) + +#ifndef INLINE +/* target FW */ +#define INLINE __inline +#define HTT_ISOC_INLINE_DEF +#endif /* INLINE */ + +static INLINE void +htt_isoc_t2h_field_set(A_UINT32 *msg_addr32, + unsigned offset32, + unsigned mask, unsigned shift, unsigned value) +{ + /* sanity check: make sure the value fits within the field */ + /* cdf_assert(value << shift == (value << shift) | mask); */ + + msg_addr32 += offset32; + /* clear the field */ + *msg_addr32 &= ~mask; + /* write the new value */ + *msg_addr32 |= (value << shift); +} + +#ifdef HTT_ISOC_INLINE_DEF +#undef HTT_ISOC_INLINE_DEF +#undef INLINE +#endif + +#define HTT_ISOC_T2H_FIELD_GET(msg_addr32, offset32, mask, shift) \ + (((*(msg_addr32 + offset32)) & mask) >> shift) + +typedef enum { + /* ASSOC - "real" peer from STA-AP association */ + HTT_ISOC_T2H_PEER_TYPE_ASSOC = 0x0, + + /* SELF - self-peer for unicast tx to unassociated peer */ + HTT_ISOC_T2H_PEER_TYPE_SELF = 0x1, + + /* BSSID - reserved for FW use for BT-AMP+IBSS */ + HTT_ISOC_T2H_PEER_TYPE_BSSID = 0x2, + + /* BCAST - self-peer for multicast / broadcast tx */ + HTT_ISOC_T2H_PEER_TYPE_BCAST = 0x3 +} HTT_ISOC_T2H_PEER_TYPE_ENUM; + +enum { + HTT_ISOC_NON_QOS = 0, + HTT_ISOC_QOS = 1 +}; + +enum { + HTT_ISOC_RMF_DISABLED = 0, + HTT_ISOC_RMF_ENABLED = 1 +}; + +enum { + HTT_ISOC_TID_MGMT = 7 +}; + +/*=== definitions for specific messages =====================================*/ + +/*=== PEER_INFO message ===*/ + +/** + * @brief target -> host peer info message definition + * + * @details + * The following diagram shows the format of the peer info message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 25|24|23 18|17|16|15 11|10|9|8|7|6| 0| + * |-----------------------------------------------------------------------| + * | mgmt DPU idx | bcast DPU idx | DPU idx | msg type | + * |-----------------------------------------------------------------------| + * | mgmt DPU sig |bcast DPU sig | DPU sig | peer ID | + * |-----------------------------------------------------------------------| + * | MAC addr 1 | MAC addr 0 | vdev ID | |R| peer type | + * |-----------------------------------------------------------------------| + * | MAC addr 5 | MAC addr 4 | MAC addr 3 | MAC addr 2 | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer info message + * Value: 0x1 + * - DPU_IDX + * Bits 15:8 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * unicast data frames sent to this peer + * Value: key ID + * - BCAST_DPU_IDX + * Bits 23:16 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * broadcast data frames sent by this (self) peer + * Value: key ID + * - MGMT_DPU_IDX + * Bits 31:24 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * unicast management frames sent by this (self) peer + * Value: key ID + * WORD 1: + * - PEER_ID + * Bits 10:0 + * Purpose: The ID that the target has allocated to refer to the peer + * - DPU_SIG + * Bits 17:11 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for unicast data frames sent to this peer + * - BCAST_DPU_SIG + * Bits 24:18 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for broadcast data frames sent by this + * (self) peer + * - MGMT_DPU_SIG + * Bits 31:25 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for unicast management frames sent by this + * (self) peer + * WORD 2: + * - PEER_TYPE + * Bits 5:0 + * Purpose: specify whether the peer in question is a real peer or + * one of the types of "self-peer" created for the vdev + * Value: HTT_ISOC_T2H_PEER_TYPE enum + * - RMF_ENABLED (R) + * Bit 6 + * Purpose: specify whether the peer in question has enable robust + * management frames, to encrypt certain managment frames + * Value: HTT_ISOC_RMF enum + * Value: HTT_ISOC_NON_QOS or HTT_ISOC_QOS + * - VDEV_ID + * Bits 15:8 + * Purpose: For a real peer, the vdev ID indicates which virtual device + * the peer is associated with. For a self-peer, the vdev ID shows + * which virtual device the self-peer represents. + * - MAC_ADDR_L16 + * Bits 31:16 + * Purpose: Identifies which peer the peer ID is for. + * Value: lower 2 bytes of the peer's MAC address + * For a self-peer, the peer's MAC address is the MAC address of the + * vdev the self-peer represents. + * WORD 3: + * - MAC_ADDR_U32 + * Bits 31:0 + * Purpose: Identifies which peer the peer ID is for. + * Value: upper 4 bytes of the peer's MAC address + * For a self-peer, the peer's MAC address is the MAC address of the + * vdev the self-peer represents. + */ +typedef struct htt_isoc_t2h_peer_info_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_INFO */ + dpu_idx : 8, bcast_dpu_idx : 8, mgmt_dpu_idx : 8; + /* word 1 */ + A_UINT32 peer_id : 11, dpu_sig : 7, bcast_dpu_sig : 7, mgmt_dpu_sig : 7; + /* word 2 */ + A_UINT32 + peer_type : 6, rmf_enabled : 1, reserved0 : 1, vdev_id : 8, mac_addr_l16 : 16; + /* word 3 */ + A_UINT32 mac_addr_u32; +} htt_isoc_t2h_peer_info_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_M 0x0000ff00 +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_S 8 + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_M 0x00ff0000 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_S 16 + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_M 0xff000000 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_S 24 + +/* word 1 */ +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_M 0x000007ff +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_S 0 + +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_M 0x0003f800 +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_S 11 + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_M 0x01fc0000 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_S 18 + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_M 0xfe000000 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_S 25 + +/* word 2 */ +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_M 0x0000003f +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_S 0 + +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_M 0x00000040 +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_S 6 + +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_M 0x0000ff00 +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_S 8 + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_M 0xffff0000 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_S 16 + +/* word 3 */ +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_OFFSET32 3 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_M 0xffffffff +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_S 0 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_INFO_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_INFO_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(DPU_IDX, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(BCAST_DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(BCAST_DPU_IDX, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MGMT_DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MGMT_DPU_IDX, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(DPU_SIG, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(BCAST_DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(BCAST_DPU_SIG, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MGMT_DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MGMT_DPU_SIG, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(PEER_TYPE, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(PEER_TYPE, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_QOS_CAPABLE_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(QOS_CAPABLE, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_QOS_CAPABLE_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(QOS_CAPABLE, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(RMF_ENABLED, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(RMF_ENABLED, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(VDEV_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(VDEV_ID, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MAC_ADDR_L16, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MAC_ADDR_L16, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MAC_ADDR_U32, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MAC_ADDR_U32, msg_addr) + +/*=== PEER_UNMAP message ===*/ + +/** + * @brief target -> host peer unmap message definition + * + * @details + * The following diagram shows the format of the peer unmap message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 19|18 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | peer ID | msg type | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer unmap message + * Value: 0x2 + * - PEER_ID + * Bits 18:8 + * Purpose: The ID that the target has allocated to refer to the peer + */ +typedef struct htt_isoc_t2h_peer_unmap_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_UNMAP */ + peer_id : 11, reserved0 : 13; +} htt_isoc_t2h_peer_unmap_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_M 0x0007ff00 +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_UNMAP_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_UNMAP_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_UNMAP_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_UNMAP_FIELD_GET(PEER_ID, msg_addr) + +/*=== ADDBA message ===*/ +enum { + htt_isoc_addba_success = 0, + /* TBD: use different failure values to specify failure causes? */ + htt_isoc_addba_fail = 1, +}; + +/** + * @brief target -> host ADDBA message definition + * + * @details + * The following diagram shows the format of the rx ADDBA message sent + * from the target to the host: + * + * |31 20|19 16|15 12|11 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | window size | msg type | + * |---------------------------------------------------------------------| + * | reserved |S| start seq num | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the ADDBA + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an ADDBA message + * Value: 0x3 + * - WIN_SIZE + * Bits 15:8 + * Purpose: Specifies the length of the block ack window (max = 64). + * Value: + * block ack window length specified by the received ADDBA + * management message. + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the ADDBA is for. + * Value: + * TID specified by the received ADDBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the ADDBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + * - START_SEQ_NUM + * Bits 11:0 + * Purpose: Specifies the initial location of the block ack window + * Value: start sequence value specified by the ADDBA-request message + * - STATUS + * Bit 12 + * Purpose: status of the WMI ADDBA request + * Value: 0 - SUCCESS, 1 - FAILURE + */ +typedef struct htt_isoc_t2h_addba_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_ADDBA */ + win_size : 8, tid : 4, peer_id : 12; + /* word 1 */ + A_UINT32 start_seq_num : 12, status : 1, reserved0 : 19; +} htt_isoc_t2h_addba_t; + +/* word 0 */ +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_M 0x0000ff00 +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_S 8 + +#define HTT_ISOC_T2H_ADDBA_TID_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_TID_M 0x000f0000 +#define HTT_ISOC_T2H_ADDBA_TID_S 16 + +#define HTT_ISOC_T2H_ADDBA_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_PEER_ID_M 0xfff00000 +#define HTT_ISOC_T2H_ADDBA_PEER_ID_S 20 + +/* word 1 */ +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_OFFSET32 1 +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_M 0x00000fff +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_S 0 + +#define HTT_ISOC_T2H_ADDBA_STATUS_OFFSET32 1 +#define HTT_ISOC_T2H_ADDBA_STATUS_M 0x00001000 +#define HTT_ISOC_T2H_ADDBA_STATUS_S 12 + +/* general field access macros */ +#define HTT_ISOC_T2H_ADDBA_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_ADDBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _M, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_ADDBA_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_ADDBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _M, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(WIN_SIZE, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(WIN_SIZE, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(TID, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_TID_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(TID, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(START_SEQ_NUM, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(START_SEQ_NUM, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_STATUS_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(STATUS, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_STATUS_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(STATUS, msg_addr) + +/*=== DELBA message ===*/ + +/** + * @brief target -> host DELBA message definition + * + * @details + * The following diagram shows the format of the rx DELBA message sent + * from the target to the host: + * + * |31 20|19 16|15 12|11 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | reserved |S| msg type | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the ADDBA + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an DELBA message + * Value: 0x4 + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the DELBA is for. + * Value: + * TID specified by the received DELBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the DELBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + * - STATUS + * Bit 8 + * Purpose: status of the WMI DELBA request + * Value: 0 - SUCCESS, 1 - FAILURE + */ +typedef struct htt_isoc_t2h_delba_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_DELBA */ + status : 1, reserved0 : 7, tid : 4, peer_id : 12; +} htt_isoc_t2h_delba_t; + +/* word 0 */ +#define HTT_ISOC_T2H_DELBA_TID_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_TID_M 0x000f0000 +#define HTT_ISOC_T2H_DELBA_TID_S 16 + +#define HTT_ISOC_T2H_DELBA_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_PEER_ID_M 0xfff00000 +#define HTT_ISOC_T2H_DELBA_PEER_ID_S 20 + +#define HTT_ISOC_T2H_DELBA_STATUS_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_STATUS_M 0x00000100 +#define HTT_ISOC_T2H_DELBA_STATUS_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_DELBA_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_DELBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_DELBA_ ## field ## _M, \ + HTT_ISOC_T2H_DELBA_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_DELBA_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_DELBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_DELBA_ ## field ## _M, \ + HTT_ISOC_T2H_DELBA_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_DELBA_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(TID, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_TID_GET(msg_addr) \ + HTT_ISOC_T2H_DELBA_FIELD_GET(TID, msg_addr) + +#define HTT_ISOC_T2H_DELBA_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_DELBA_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_DELBA_STATUS_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(STATUS, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_STATUS_GET(msg_addr) \ + HTT_ISOC_T2H_DELBA_FIELD_GET(STATUS, msg_addr) + +/*=== SEC_IND message ===*/ + +/** + * @brief target -> host Security indication message definition + * + * @details + * The following diagram shows the format of the SEC_IND message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 25|24|23 18|17|16|15 11|10|9|8|7|6| 0| + * |-----------------------------------------------------------------------| + * | is unicast | sec type | Peer id | msg type | + * |-----------------------------------------------------------------------| + * | mic key1 | + * |-----------------------------------------------------------------------| + * | mic key2 | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as SEC_IND message + * Value: 0x6 + * - PEER_ID + * Bits 15:8 + * Purpose: The ID that the target has allocated to refer to the peer + * Value: Peer ID + * - SEC_TYPE + * Bits 23:16 + * Purpose: specify the security encryption type + * Value: htt_sec_type + * - is unicast + * Bits 31:24 + * Purpose: specify unicast/bcast + * Value: 1-unicast/0-bcast + * WORD 1: + * - MIC1 + * Bits 31:0 + * Purpose: Mickey1 + * WORD 2: + * - MIC2 + * Bits 31:0 + * Purpose: Mickey2 + */ +typedef struct htt_isoc_t2h_sec_ind_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_SEC_IND */ + peer_id : 8, sec_type : 8, is_unicast : 8; + /* word 1 */ + A_UINT32 mic_key1; + /* word 2 */ + A_UINT32 mic_key2; + /* word 3 */ + A_UINT32 status; +} htt_isoc_t2h_sec_ind_t; + +/* word 0 */ +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_M 0x0000ff00 +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_S 8 + +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_M 0x00ff0000 +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_S 16 + +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_M 0xff000000 +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_S 24 + +/* word 1 */ +#define HTT_ISOC_T2H_SEC_IND_MIC1_OFFSET32 1 +#define HTT_ISOC_T2H_SEC_IND_MIC1_M 0xffffffff +#define HTT_ISOC_T2H_SEC_IND_MIC1_S 0 + +/* word 2 */ +#define HTT_ISOC_T2H_SEC_IND_MIC2_OFFSET32 2 +#define HTT_ISOC_T2H_SEC_IND_MIC2_M 0xffffffff +#define HTT_ISOC_T2H_SEC_IND_MIC2_S 0 + +/* general field access macros */ +#define HTT_ISOC_T2H_SEC_IND_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _M, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_SEC_IND_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _M, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _S) + +/* access macros for specific fields */ +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(SEC_TYPE, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(SEC_TYPE, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(IS_UNICAST, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(IS_UNICAST, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_MIC1_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(MIC1, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_MIC1_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(MIC1, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_MIC2_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(MIC2, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_MIC2_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(MIC2, msg_addr) + +/*=== PEER_TX_READY message ===*/ + +/** + * @brief target -> host peer tx ready message definition + * + * @details + * The following diagram shows the format of the peer tx ready message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 19|18 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | peer ID | msg type | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer tx ready message + * Value: 0x7 + * - PEER_ID + * Bits 18:8 + * Purpose: The ID assigned to the peer by the PEER_INFO message + */ +typedef struct htt_isoc_t2h_peer_tx_ready_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_TX_READY */ + peer_id : 11, reserved0 : 13; +} htt_isoc_t2h_peer_tx_ready_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_M 0x0007ff00 +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_TX_READY_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_TX_READY_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_TX_READY_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_TX_READY_FIELD_GET(PEER_ID, msg_addr) + +/*=== RX_ERR message ===*/ + +/** + * @brief target -> host rx error notification message definition + * + * @details + * The following diagram shows the format of the rx err message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 16|15 8|7|6|5|4 0| + * |---------------------------------------------------------------------| + * | peer ID | rx err type | msg type | + * |---------------------------------------------------------------------| + * | reserved | rx err count |M| r | ext TID | + * |---------------------------------------------------------------------| + * M = multicast + * r = reserved + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx err message + * Value: 0x8 + * - RX_ERR_TYPE + * Bits 15:8 + * Purpose: specifies which type of rx error is being reported + * Value: htt_rx_ind_mpdu_status enum + * - PEER_ID + * Bits 31:16 + * Purpose: specify which peer sent the frame that resulted in an error + * WORD 1: + * - EXT_TID + * Bits 4:0 + * Purpose: specifies which traffic type had the rx error + * Value: 0-15 for a real TID value, 16 for non-QoS data, 31 for unknown + * - MCAST + * Bit 6 + * Purpose: specify whether the rx error frame was unicast or multicast + * Value: 0 -> unicast, 1 -> multicast + * - L2_HDR_IS_80211 + * Bit 7 + * Purpose: specifies whether the included L2 header (if present) is in + * 802.3 or 802.11 format + * Value: 0 -> 802.3, 1 -> 802.11 + * - L2_HDR_BYTES + * Bits 15:8 + * Purpose: Specify the size of the L2 header in this rx error report. + * Value: + * If no L2 header is included, this field shall be 0. + * If a 802.3 + LLC/SNAP header is included, this field shall be + * 14 (ethernet header) + 8 (LLC/SNAP). + * If a 802.11 header is included, this field shall be 24 bytes for + * a basic header, or 26 bytes if a QoS control field is included, + * or 30 bytes if a 4th address is included, or 32 bytes if a 4th + * address and a QoS control field are included, etc. + * Though the L2 header included in the message needs to include + * padding up to a 4-byte boundary, this L2 header size field need + * not account for the padding following the L2 header. + * - SEC_HDR_BYTES + * Bits 23:16 + * Purpose: Specify the size of the security encapsulation header in + * this rx error report. + * Value: + * If no security header is included, this field shall be 0. + * If a security header is included, this field depends on the + * security type, which can be inferred from the rx error type. + * For TKIP MIC errors, the security header could be any of: + * 8 - if IV / KeyID and Extended IV are included + * 16 - if MIC is also included + * 20 - if ICV is also included + * - RX_ERR_CNT + * Bits 31:24 + * Purpose: specifies how many rx errors are reported in this message + * Value: + * Rx error reports that include a L2 header and/or security header + * will set this field to 1, to indicate that the error notification + * is for a single frame. + * Rx error reports that don't include a L2 header or security header + * can use this field to send a single message to report multiple + * erroneous rx frames. + */ +typedef struct htt_isoc_t2h_rx_err_s { + /* word 0 */ + A_UINT32 msg_type : 8, /* HTT_ISOC_T2H_MSG_TYPE_RX_ERR */ + rx_err_type : 8, peer_id : 16; + /* word 1 */ + A_UINT32 + ext_tid : 5, + reserved1 : 1, + mcast : 1, + l2_hdr_is_80211 : 1, l2_hdr_bytes : 8, sec_hdr_bytes : 8, rx_err_cnt : 8; + /* words 2 - M-1: L2 header */ + /* words M - N: security header */ +} htt_isoc_t2h_rx_err_t; + +/* word 0 */ +#define HTT_ISOC_T2H_RX_ERR_TYPE_OFFSET32 0 +#define HTT_ISOC_T2H_RX_ERR_TYPE_M 0x0000ff00 +#define HTT_ISOC_T2H_RX_ERR_TYPE_ID_S 8 + +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_M 0xffff0000 +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_S 16 + +/* word 1 */ +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_M 0x0000001f +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_ID_S 0 + +#define HTT_ISOC_T2H_RX_ERR_MCAST_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_MCAST_M 0x00000040 +#define HTT_ISOC_T2H_RX_ERR_MCAST_ID_S 6 + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_M 0x00000080 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_ID_S 7 + +#define HTT_ISOC_T2H_RX_L2_HDR_BYTES_OFFSET32 1 +#define HTT_ISOC_T2H_RX_L2_HDR_BYTES_M 0x0000ff00 +#define HTT_ISOC_T2H_RX_L2_HDR_BYTES_ID_S 8 + +#define HTT_ISOC_T2H_RX_SEC_HDR_BYTES_OFFSET32 1 +#define HTT_ISOC_T2H_RX_SEC_HDR_BYTES_M 0x00ff0000 +#define HTT_ISOC_T2H_RX_SEC_HDR_BYTES_ID_S 16 + +#define HTT_ISOC_T2H_RX_ERR_CNT_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_CNT_M 0xff000000 +#define HTT_ISOC_T2H_RX_ERR_CNT_ID_S 24 + +/* general field access macros */ + +#define HTT_ISOC_T2H_RX_ERR_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _M, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_RX_ERR_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _M, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_RX_ERR_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(TYPE, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(TYPE, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(EXT_TID, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(EXT_TID, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_MCAST_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(MCAST, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_MCAST_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(MCAST, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(L2_HDR_IS_80211, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(L2_HDR_IS_80211, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(L2_HDR_BYTES, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(L2_HDR_BYTES, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(SEC_HDR_BYTES, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(SEC_HDR_BYTES, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_CNT_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(CNT, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_CNT_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(CNT, msg_addr) + +#endif /* _HTT_ISOC_H_ */ diff --git a/target/inc/ip_prot.h b/target/inc/ip_prot.h new file mode 100644 index 0000000000..a1722fe3eb --- /dev/null +++ b/target/inc/ip_prot.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IP_PROT__H_ +#define _IP_PROT__H_ + +#define IP_PROTOCOL_ICMP 0x01 /* Internet Control Message Protocol */ +#define IP_PROTOCOL_IGMP 0x02 /* Internet Group Management Protocol */ +#define IP_PROTOCOL_IPV4 0x04 /* IPv4 (encapsulation) */ +#define IP_PROTOCOL_TCP 0x06 /* Transmission Control Protocol */ +#define IP_PROTOCOL_UDP 0x11 /* User Datagram Protocol */ +#define IP_PROTOCOL_RDP 0x1B /* Reliable Datagram Protocol */ +#define IP_PROTOCOL_IPV6 0x29 /* IPv6 (encapsulation) */ +#define IP_PROTOCOL_IPV6_ROUTE 0x2B /* Routing Header for IPv6 */ +#define IP_PROTOCOL_IPV6_FRAG 0x2C /* Fragment Header for IPv6 */ +#define IP_PROTOCOL_RSVP 0x2E /* Resource Reservation Protocol */ +#define IP_PROTOCOL_GRE 0x2F /* Generic Routing Encapsulation */ +#define IP_PROTOCOL_MHRP 0x30 /* Mobile Host Routing Protocol */ +#define IP_PROTOCOL_BNA 0x31 /* BNA */ +#define IP_PROTOCOL_ESP 0x32 /* Encapsulating Security Payload */ +#define IP_PROTOCOL_MOBILE 0x37 /* IP Mobility (Min Encap) */ +#define IP_PROTOCOL_IPV6_ICMP 0x3A /* ICMP for IPv6 */ +#define IP_PROTOCOL_IPV6_NONXT 0x3B /* No Next Header for IPv6 */ +#define IP_PROTOCOL_IPV6_OPTS 0x3C /* Destination Options for IPv6 */ +#define IP_PROTOCOL_IPCOMP 0x6C /* IP Payload Compression Protocol */ +#define IP_PROTOCOL_L2TP 0x73 /* Layer Two Tunneling Protocol Version 3 */ +#define IP_PROTOCOL_SMP 0x79 /* Simple Message Protocol */ +#define IP_PROTOCOL_SCTP 0x84 /* Stream Control Transmission Protocol */ +#define IP_PROTOCOL_SHIM6 0x8C /* Site Multihoming by IPv6 Intermediation */ + +/* IPv6 ICMP types */ +#define IPV6_ICMP_TYPE_MLD 0x8F + +#endif /* _IP_PROT__H_ */ diff --git a/target/inc/ipv4.h b/target/inc/ipv4.h new file mode 100644 index 0000000000..67eb337550 --- /dev/null +++ b/target/inc/ipv4.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IPV4__H_ +#define _IPV4__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +#define IPV4_ADDR_LEN 4 /* bytes */ +struct ipv4_hdr_t { + A_UINT8 ver_hdrlen; /* version and hdr length */ + A_UINT8 tos; /* type of service */ + A_UINT8 len[2]; /* total length */ + A_UINT8 id[2]; + A_UINT8 flags_fragoff[2]; /* flags and fragment offset field */ + A_UINT8 ttl; /* time to live */ + A_UINT8 protocol; + A_UINT8 hdr_checksum[2]; + A_UINT8 src_addr[IPV4_ADDR_LEN]; + A_UINT8 dst_addr[IPV4_ADDR_LEN]; +}; + +#define IPV4_HDR_LEN (sizeof(struct ipv4_hdr_t)) +#define IPV4_HDR_OFFSET_PROTOCOL (offsetof(struct ipv4_hdr_t, protocol)) +#define IPV4_HDR_OFFSET_DST_ADDR (offsetof(struct ipv4_hdr_t, dst_addr[0])) + +#endif /* _IPV4__H_ */ diff --git a/target/inc/ol_fw_tx_dbg.h b/target/inc/ol_fw_tx_dbg.h new file mode 100644 index 0000000000..35303b7ac3 --- /dev/null +++ b/target/inc/ol_fw_tx_dbg.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_fw_tx_dbg.h + * + * @details data structs used for uploading summary info about the FW's tx + */ + +#ifndef _OL_FW_TX_DBG__H_ +#define _OL_FW_TX_DBG__H_ + +/* + * Undef ATH_SUPPORT_FW_TX_DBG to remove the FW tx debug feature. + * Removing the FW tx debug feature saves a modest amount of program memory. + * The data memory allocation for the FW tx debug feature is controlled + * by the host --> target resource configuration parameters; even if + * ATH_SUPPORT_FW_TX_DBG is defined, no data memory will be allocated for + * the FW tx debug log unless the host --> target resource configuration + * specifies it. + */ +#define ATH_SUPPORT_FW_TX_DBG 1 /* enabled */ +/* #undef ATH_SUPPORT_FW_TX_DBG / * disabled * / */ + +#if defined(ATH_TARGET) +#include /* A_UINT32 */ +#else +#include /* A_UINT32 */ +#include /* PREPACK, POSTPACK */ +#endif + +enum ol_fw_tx_dbg_log_mode { + ol_fw_tx_dbg_log_mode_wraparound, /* overwrite old data with new */ + ol_fw_tx_dbg_log_mode_single, /* fill log once, then stop */ +}; + +/* + * tx PPDU stats upload message header + */ +struct ol_fw_tx_dbg_ppdu_msg_hdr { + /* word 0 */ +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_S 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_M 0x000000ff + A_UINT8 mpdu_bytes_array_len; /* length of array of per-MPDU byte counts */ + +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_S 8 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_M 0x0000ff00 + A_UINT8 msdu_bytes_array_len; /* length of array of per-MSDU byte counts */ + +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_S 16 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_M 0x00ff0000 + A_UINT8 mpdu_msdus_array_len; /* length of array of per-MPDU MSDU counts */ + + A_UINT8 reserved; + + /* word 1 */ +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_WORD 1 +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_S 0 +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_M 0xffffffff + A_UINT32 microsec_per_tick; /* conversion for timestamp entries */ +}; + +/* + * tx PPDU log element / stats upload message element + */ +struct ol_fw_tx_dbg_ppdu_base { + /* word 0 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_16 0 +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S 0 +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M 0x0000ffff + A_UINT16 start_seq_num; +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_16 0 +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_S 16 +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_M 0xffff0000 + A_UINT16 start_pn_lsbs; + + /* word 1 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_16 1 +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_S 0 +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_M 0xffffffff + A_UINT32 num_bytes; + + /* word 2 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_16 2 +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_S 0 +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_M 0x000000ff + A_UINT8 num_msdus; +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_16 2 +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_S 8 +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_M 0x0000ff00 + A_UINT8 num_mpdus; + A_UINT16 +#define OL_FW_TX_DBG_PPDU_EXT_TID_16 2 +#define OL_FW_TX_DBG_PPDU_EXT_TID_S 16 +#define OL_FW_TX_DBG_PPDU_EXT_TID_M 0x001f0000 + ext_tid : 5, +#define OL_FW_TX_DBG_PPDU_PEER_ID_16 2 +#define OL_FW_TX_DBG_PPDU_PEER_ID_S 21 +#define OL_FW_TX_DBG_PPDU_PEER_ID_M 0xffe00000 + peer_id : 11; + + /* word 3 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_16 3 +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_S 0 +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_M 0xffffffff + A_UINT32 timestamp_enqueue; + + /* word 4 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_16 4 +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_S 0 +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_M 0xffffffff + A_UINT32 timestamp_completion; + + /* word 5 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_16 5 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_S 0 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_M 0xffffffff + A_UINT32 block_ack_bitmap_lsbs; + + /* word 6 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_16 6 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_S 0 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_M 0xffffffff + A_UINT32 block_ack_bitmap_msbs; + + /* word 7 - filled in during tx completion (enqueue would work too) */ +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_16 7 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_S 0 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_M 0xffffffff + A_UINT32 enqueued_bitmap_lsbs; + + /* word 8 - filled in during tx completion (enqueue would work too) */ +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_16 8 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_S 0 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_M 0xffffffff + A_UINT32 enqueued_bitmap_msbs; + + /* word 9 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_RATE_CODE_16 9 +#define OL_FW_TX_DBG_PPDU_RATE_CODE_S 0 +#define OL_FW_TX_DBG_PPDU_RATE_CODE_M 0x000000ff + A_UINT8 rate_code; +#define OL_FW_TX_DBG_PPDU_RATEFLAGS_16 9 +#define OL_FW_TX_DBG_PPDU_RATE_FLAGS_S 8 +#define OL_FW_TX_DBG_PPDU_RATE_FLAGS_M 0x0000ff00 + A_UINT8 rate_flags; /* includes dynamic bandwidth info */ +#define OL_FW_TX_DBG_PPDU_TRIES_16 9 +#define OL_FW_TX_DBG_PPDU_TRIES_S 16 +#define OL_FW_TX_DBG_PPDU_TRIES_M 0x00ff0000 + A_UINT8 tries; +#define OL_FW_TX_DBG_PPDU_COMPLETE_16 9 +#define OL_FW_TX_DBG_PPDU_COMPLETE_S 24 +#define OL_FW_TX_DBG_PPDU_COMPLETE_M 0xff000000 + A_UINT8 complete; +}; + +#endif /* _OL_FW_TX_DBG__H_ */ diff --git a/target/inc/rtc_soc_reg.h b/target/inc/rtc_soc_reg.h new file mode 100644 index 0000000000..11e80b1f1f --- /dev/null +++ b/target/inc/rtc_soc_reg.h @@ -0,0 +1,1966 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _RTC_SOC_REG_REG_H_ +#define _RTC_SOC_REG_REG_H_ + +#define SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define SOC_RESET_CONTROL_OFFSET 0x00000000 +#define SOC_RESET_CONTROL_SPI2_RST_MSB 30 +#define SOC_RESET_CONTROL_SPI2_RST_LSB 30 +#define SOC_RESET_CONTROL_SPI2_RST_MASK 0x40000000 +#define SOC_RESET_CONTROL_SPI2_RST_GET(x) (((x) & SOC_RESET_CONTROL_SPI2_RST_MASK) >> SOC_RESET_CONTROL_SPI2_RST_LSB) +#define SOC_RESET_CONTROL_SPI2_RST_SET(x) (((x) << SOC_RESET_CONTROL_SPI2_RST_LSB) & SOC_RESET_CONTROL_SPI2_RST_MASK) +#define SOC_RESET_CONTROL_I2S_1_RST_MSB 29 +#define SOC_RESET_CONTROL_I2S_1_RST_LSB 29 +#define SOC_RESET_CONTROL_I2S_1_RST_MASK 0x20000000 +#define SOC_RESET_CONTROL_I2S_1_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_1_RST_MASK) >> SOC_RESET_CONTROL_I2S_1_RST_LSB) +#define SOC_RESET_CONTROL_I2S_1_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_1_RST_LSB) & SOC_RESET_CONTROL_I2S_1_RST_MASK) +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_MSB 28 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB 28 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK 0x10000000 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK) >> SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB) & SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK) +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_MSB 27 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB 27 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK 0x08000000 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK) >> SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB) +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB) & SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK) +#define SOC_RESET_CONTROL_USB_PHY_ARST_MSB 26 +#define SOC_RESET_CONTROL_USB_PHY_ARST_LSB 26 +#define SOC_RESET_CONTROL_USB_PHY_ARST_MASK 0x04000000 +#define SOC_RESET_CONTROL_USB_PHY_ARST_GET(x) (((x) & SOC_RESET_CONTROL_USB_PHY_ARST_MASK) >> SOC_RESET_CONTROL_USB_PHY_ARST_LSB) +#define SOC_RESET_CONTROL_USB_PHY_ARST_SET(x) (((x) << SOC_RESET_CONTROL_USB_PHY_ARST_LSB) & SOC_RESET_CONTROL_USB_PHY_ARST_MASK) +#define SOC_RESET_CONTROL_USB_PHY_RST_MSB 25 +#define SOC_RESET_CONTROL_USB_PHY_RST_LSB 25 +#define SOC_RESET_CONTROL_USB_PHY_RST_MASK 0x02000000 +#define SOC_RESET_CONTROL_USB_PHY_RST_GET(x) (((x) & SOC_RESET_CONTROL_USB_PHY_RST_MASK) >> SOC_RESET_CONTROL_USB_PHY_RST_LSB) +#define SOC_RESET_CONTROL_USB_PHY_RST_SET(x) (((x) << SOC_RESET_CONTROL_USB_PHY_RST_LSB) & SOC_RESET_CONTROL_USB_PHY_RST_MASK) +#define SOC_RESET_CONTROL_USB_RST_MSB 24 +#define SOC_RESET_CONTROL_USB_RST_LSB 24 +#define SOC_RESET_CONTROL_USB_RST_MASK 0x01000000 +#define SOC_RESET_CONTROL_USB_RST_GET(x) (((x) & SOC_RESET_CONTROL_USB_RST_MASK) >> SOC_RESET_CONTROL_USB_RST_LSB) +#define SOC_RESET_CONTROL_USB_RST_SET(x) (((x) << SOC_RESET_CONTROL_USB_RST_LSB) & SOC_RESET_CONTROL_USB_RST_MASK) +#define SOC_RESET_CONTROL_MMAC_RST_MSB 23 +#define SOC_RESET_CONTROL_MMAC_RST_LSB 23 +#define SOC_RESET_CONTROL_MMAC_RST_MASK 0x00800000 +#define SOC_RESET_CONTROL_MMAC_RST_GET(x) (((x) & SOC_RESET_CONTROL_MMAC_RST_MASK) >> SOC_RESET_CONTROL_MMAC_RST_LSB) +#define SOC_RESET_CONTROL_MMAC_RST_SET(x) (((x) << SOC_RESET_CONTROL_MMAC_RST_LSB) & SOC_RESET_CONTROL_MMAC_RST_MASK) +#define SOC_RESET_CONTROL_MDIO_RST_MSB 22 +#define SOC_RESET_CONTROL_MDIO_RST_LSB 22 +#define SOC_RESET_CONTROL_MDIO_RST_MASK 0x00400000 +#define SOC_RESET_CONTROL_MDIO_RST_GET(x) (((x) & SOC_RESET_CONTROL_MDIO_RST_MASK) >> SOC_RESET_CONTROL_MDIO_RST_LSB) +#define SOC_RESET_CONTROL_MDIO_RST_SET(x) (((x) << SOC_RESET_CONTROL_MDIO_RST_LSB) & SOC_RESET_CONTROL_MDIO_RST_MASK) +#define SOC_RESET_CONTROL_GE0_RST_MSB 21 +#define SOC_RESET_CONTROL_GE0_RST_LSB 21 +#define SOC_RESET_CONTROL_GE0_RST_MASK 0x00200000 +#define SOC_RESET_CONTROL_GE0_RST_GET(x) (((x) & SOC_RESET_CONTROL_GE0_RST_MASK) >> SOC_RESET_CONTROL_GE0_RST_LSB) +#define SOC_RESET_CONTROL_GE0_RST_SET(x) (((x) << SOC_RESET_CONTROL_GE0_RST_LSB) & SOC_RESET_CONTROL_GE0_RST_MASK) +#define SOC_RESET_CONTROL_I2S_RST_MSB 20 +#define SOC_RESET_CONTROL_I2S_RST_LSB 20 +#define SOC_RESET_CONTROL_I2S_RST_MASK 0x00100000 +#define SOC_RESET_CONTROL_I2S_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_RST_MASK) >> SOC_RESET_CONTROL_I2S_RST_LSB) +#define SOC_RESET_CONTROL_I2S_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_RST_LSB) & SOC_RESET_CONTROL_I2S_RST_MASK) +#define SOC_RESET_CONTROL_I2S_MBOX_RST_MSB 19 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_LSB 19 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_MASK 0x00080000 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_MBOX_RST_MASK) >> SOC_RESET_CONTROL_I2S_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_I2S_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_MBOX_RST_LSB) & SOC_RESET_CONTROL_I2S_MBOX_RST_MASK) +/* TODO: */ +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MSB 18 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB 18 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_GET(x) (((x) & SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK) >> SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB) +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_SET(x) (((x) << SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB) & SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK) +#define SOC_RESET_CONTROL_CE_RST_MSB 18 +#define SOC_RESET_CONTROL_CE_RST_LSB 18 +#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CE_RST_GET(x) (((x) & SOC_RESET_CONTROL_CE_RST_MASK) >> SOC_RESET_CONTROL_CE_RST_LSB) +#define SOC_RESET_CONTROL_CE_RST_SET(x) (((x) << SOC_RESET_CONTROL_CE_RST_LSB) & SOC_RESET_CONTROL_CE_RST_MASK) +#define SOC_RESET_CONTROL_UART2_RST_MSB 17 +#define SOC_RESET_CONTROL_UART2_RST_LSB 17 +#define SOC_RESET_CONTROL_UART2_RST_MASK 0x00020000 +#define SOC_RESET_CONTROL_UART2_RST_GET(x) (((x) & SOC_RESET_CONTROL_UART2_RST_MASK) >> SOC_RESET_CONTROL_UART2_RST_LSB) +#define SOC_RESET_CONTROL_UART2_RST_SET(x) (((x) << SOC_RESET_CONTROL_UART2_RST_LSB) & SOC_RESET_CONTROL_UART2_RST_MASK) +#define SOC_RESET_CONTROL_DEBUG_UART_RST_MSB 16 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_LSB 16 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_MASK 0x00010000 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_GET(x) (((x) & SOC_RESET_CONTROL_DEBUG_UART_RST_MASK) >> SOC_RESET_CONTROL_DEBUG_UART_RST_LSB) +#define SOC_RESET_CONTROL_DEBUG_UART_RST_SET(x) (((x) << SOC_RESET_CONTROL_DEBUG_UART_RST_LSB) & SOC_RESET_CONTROL_DEBUG_UART_RST_MASK) +#define SOC_RESET_CONTROL_CPU_INIT_RESET_MSB 11 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_LSB 11 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_MASK 0x00000800 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_GET(x) (((x) & SOC_RESET_CONTROL_CPU_INIT_RESET_MASK) >> SOC_RESET_CONTROL_CPU_INIT_RESET_LSB) +#define SOC_RESET_CONTROL_CPU_INIT_RESET_SET(x) (((x) << SOC_RESET_CONTROL_CPU_INIT_RESET_LSB) & SOC_RESET_CONTROL_CPU_INIT_RESET_MASK) +#define SOC_RESET_CONTROL_RST_OUT_MSB 9 +#define SOC_RESET_CONTROL_RST_OUT_LSB 9 +#define SOC_RESET_CONTROL_RST_OUT_MASK 0x00000200 +#define SOC_RESET_CONTROL_RST_OUT_GET(x) (((x) & SOC_RESET_CONTROL_RST_OUT_MASK) >> SOC_RESET_CONTROL_RST_OUT_LSB) +#define SOC_RESET_CONTROL_RST_OUT_SET(x) (((x) << SOC_RESET_CONTROL_RST_OUT_LSB) & SOC_RESET_CONTROL_RST_OUT_MASK) +#define SOC_RESET_CONTROL_COLD_RST_MSB 8 +#define SOC_RESET_CONTROL_COLD_RST_LSB 8 +#define SOC_RESET_CONTROL_COLD_RST_MASK 0x00000100 +#define SOC_RESET_CONTROL_COLD_RST_GET(x) (((x) & SOC_RESET_CONTROL_COLD_RST_MASK) >> SOC_RESET_CONTROL_COLD_RST_LSB) +#define SOC_RESET_CONTROL_COLD_RST_SET(x) (((x) << SOC_RESET_CONTROL_COLD_RST_LSB) & SOC_RESET_CONTROL_COLD_RST_MASK) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MSB 6 +#define SOC_RESET_CONTROL_CPU_WARM_RST_LSB 6 +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define SOC_RESET_CONTROL_CPU_WARM_RST_GET(x) (((x) & SOC_RESET_CONTROL_CPU_WARM_RST_MASK) >> SOC_RESET_CONTROL_CPU_WARM_RST_LSB) +#define SOC_RESET_CONTROL_CPU_WARM_RST_SET(x) (((x) << SOC_RESET_CONTROL_CPU_WARM_RST_LSB) & SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +/* TODO: */ +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MSB 2 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000004 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_GET(x) (((x) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) >> SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_SET(x) (((x) << SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) +#define SOC_RESET_CONTROL_MBOX_RST_MSB 2 +#define SOC_RESET_CONTROL_MBOX_RST_LSB 2 +#define SOC_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define SOC_RESET_CONTROL_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_MBOX_RST_MASK) >> SOC_RESET_CONTROL_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_MBOX_RST_LSB) & SOC_RESET_CONTROL_MBOX_RST_MASK) +#define SOC_RESET_CONTROL_UART_RST_MSB 1 +#define SOC_RESET_CONTROL_UART_RST_LSB 1 +#define SOC_RESET_CONTROL_UART_RST_MASK 0x00000002 +#define SOC_RESET_CONTROL_UART_RST_GET(x) (((x) & SOC_RESET_CONTROL_UART_RST_MASK) >> SOC_RESET_CONTROL_UART_RST_LSB) +#define SOC_RESET_CONTROL_UART_RST_SET(x) (((x) << SOC_RESET_CONTROL_UART_RST_LSB) & SOC_RESET_CONTROL_UART_RST_MASK) +#define SOC_RESET_CONTROL_SI0_RST_MSB 0 +#define SOC_RESET_CONTROL_SI0_RST_LSB 0 +#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define SOC_RESET_CONTROL_SI0_RST_GET(x) (((x) & SOC_RESET_CONTROL_SI0_RST_MASK) >> SOC_RESET_CONTROL_SI0_RST_LSB) +#define SOC_RESET_CONTROL_SI0_RST_SET(x) (((x) << SOC_RESET_CONTROL_SI0_RST_LSB) & SOC_RESET_CONTROL_SI0_RST_MASK) + +#define SOC_TCXO_DETECT_ADDRESS 0x00000004 +#define SOC_TCXO_DETECT_OFFSET 0x00000004 +#define SOC_TCXO_DETECT_PRESENT_MSB 0 +#define SOC_TCXO_DETECT_PRESENT_LSB 0 +#define SOC_TCXO_DETECT_PRESENT_MASK 0x00000001 +#define SOC_TCXO_DETECT_PRESENT_GET(x) (((x) & SOC_TCXO_DETECT_PRESENT_MASK) >> SOC_TCXO_DETECT_PRESENT_LSB) +#define SOC_TCXO_DETECT_PRESENT_SET(x) (((x) << SOC_TCXO_DETECT_PRESENT_LSB) & SOC_TCXO_DETECT_PRESENT_MASK) + +#define SOC_XTAL_TEST_ADDRESS 0x00000008 +#define SOC_XTAL_TEST_OFFSET 0x00000008 +#define SOC_XTAL_TEST_NOTCXODET_MSB 0 +#define SOC_XTAL_TEST_NOTCXODET_LSB 0 +#define SOC_XTAL_TEST_NOTCXODET_MASK 0x00000001 +#define SOC_XTAL_TEST_NOTCXODET_GET(x) (((x) & SOC_XTAL_TEST_NOTCXODET_MASK) >> SOC_XTAL_TEST_NOTCXODET_LSB) +#define SOC_XTAL_TEST_NOTCXODET_SET(x) (((x) << SOC_XTAL_TEST_NOTCXODET_LSB) & SOC_XTAL_TEST_NOTCXODET_MASK) + +#define SOC_CPU_CLOCK_ADDRESS 0x00000020 +#define SOC_CPU_CLOCK_OFFSET 0x00000020 +#define SOC_CPU_CLOCK_STANDARD_MSB 1 +#define SOC_CPU_CLOCK_STANDARD_LSB 0 +#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define SOC_CPU_CLOCK_STANDARD_GET(x) (((x) & SOC_CPU_CLOCK_STANDARD_MASK) >> SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & SOC_CPU_CLOCK_STANDARD_MASK) + +#define SOC_CLOCK_CONTROL_ADDRESS 0x00000028 +#define SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define SOC_CLOCK_CONTROL_USB_CLOCK_MSB 3 +#define SOC_CLOCK_CONTROL_USB_CLOCK_LSB 3 +#define SOC_CLOCK_CONTROL_USB_CLOCK_MASK 0x00000008 +#define SOC_CLOCK_CONTROL_USB_CLOCK_GET(x) (((x) & SOC_CLOCK_CONTROL_USB_CLOCK_MASK) >> SOC_CLOCK_CONTROL_USB_CLOCK_LSB) +#define SOC_CLOCK_CONTROL_USB_CLOCK_SET(x) (((x) << SOC_CLOCK_CONTROL_USB_CLOCK_LSB) & SOC_CLOCK_CONTROL_USB_CLOCK_MASK) +#define SOC_CLOCK_CONTROL_LF_CLK32_MSB 2 +#define SOC_CLOCK_CONTROL_LF_CLK32_LSB 2 +#define SOC_CLOCK_CONTROL_LF_CLK32_MASK 0x00000004 +#define SOC_CLOCK_CONTROL_LF_CLK32_GET(x) (((x) & SOC_CLOCK_CONTROL_LF_CLK32_MASK) >> SOC_CLOCK_CONTROL_LF_CLK32_LSB) +#define SOC_CLOCK_CONTROL_LF_CLK32_SET(x) (((x) << SOC_CLOCK_CONTROL_LF_CLK32_LSB) & SOC_CLOCK_CONTROL_LF_CLK32_MASK) +#define SOC_CLOCK_CONTROL_SI0_CLK_MSB 0 +#define SOC_CLOCK_CONTROL_SI0_CLK_LSB 0 +#define SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define SOC_CLOCK_CONTROL_SI0_CLK_GET(x) (((x) & SOC_CLOCK_CONTROL_SI0_CLK_MASK) >> SOC_CLOCK_CONTROL_SI0_CLK_LSB) +#define SOC_CLOCK_CONTROL_SI0_CLK_SET(x) (((x) << SOC_CLOCK_CONTROL_SI0_CLK_LSB) & SOC_CLOCK_CONTROL_SI0_CLK_MASK) + +#define SOC_WDT_CONTROL_ADDRESS 0x00000030 +#define SOC_WDT_CONTROL_OFFSET 0x00000030 +#define SOC_WDT_CONTROL_ACTION_MSB 2 +#define SOC_WDT_CONTROL_ACTION_LSB 0 +#define SOC_WDT_CONTROL_ACTION_MASK 0x00000007 +#define SOC_WDT_CONTROL_ACTION_GET(x) (((x) & SOC_WDT_CONTROL_ACTION_MASK) >> SOC_WDT_CONTROL_ACTION_LSB) +#define SOC_WDT_CONTROL_ACTION_SET(x) (((x) << SOC_WDT_CONTROL_ACTION_LSB) & SOC_WDT_CONTROL_ACTION_MASK) + +#define SOC_WDT_STATUS_ADDRESS 0x00000034 +#define SOC_WDT_STATUS_OFFSET 0x00000034 +#define SOC_WDT_STATUS_INTERRUPT_MSB 0 +#define SOC_WDT_STATUS_INTERRUPT_LSB 0 +#define SOC_WDT_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_WDT_STATUS_INTERRUPT_GET(x) (((x) & SOC_WDT_STATUS_INTERRUPT_MASK) >> SOC_WDT_STATUS_INTERRUPT_LSB) +#define SOC_WDT_STATUS_INTERRUPT_SET(x) (((x) << SOC_WDT_STATUS_INTERRUPT_LSB) & SOC_WDT_STATUS_INTERRUPT_MASK) + +#define SOC_WDT_ADDRESS 0x00000038 +#define SOC_WDT_OFFSET 0x00000038 +#define SOC_WDT_TARGET_MSB 21 +#define SOC_WDT_TARGET_LSB 0 +#define SOC_WDT_TARGET_MASK 0x003fffff +#define SOC_WDT_TARGET_GET(x) (((x) & SOC_WDT_TARGET_MASK) >> SOC_WDT_TARGET_LSB) +#define SOC_WDT_TARGET_SET(x) (((x) << SOC_WDT_TARGET_LSB) & SOC_WDT_TARGET_MASK) + +#define SOC_WDT_COUNT_ADDRESS 0x0000003c +#define SOC_WDT_COUNT_OFFSET 0x0000003c +#define SOC_WDT_COUNT_VALUE_MSB 21 +#define SOC_WDT_COUNT_VALUE_LSB 0 +#define SOC_WDT_COUNT_VALUE_MASK 0x003fffff +#define SOC_WDT_COUNT_VALUE_GET(x) (((x) & SOC_WDT_COUNT_VALUE_MASK) >> SOC_WDT_COUNT_VALUE_LSB) +#define SOC_WDT_COUNT_VALUE_SET(x) (((x) << SOC_WDT_COUNT_VALUE_LSB) & SOC_WDT_COUNT_VALUE_MASK) + +#define SOC_WDT_RESET_ADDRESS 0x00000040 +#define SOC_WDT_RESET_OFFSET 0x00000040 +#define SOC_WDT_RESET_VALUE_MSB 0 +#define SOC_WDT_RESET_VALUE_LSB 0 +#define SOC_WDT_RESET_VALUE_MASK 0x00000001 +#define SOC_WDT_RESET_VALUE_GET(x) (((x) & SOC_WDT_RESET_VALUE_MASK) >> SOC_WDT_RESET_VALUE_LSB) +#define SOC_WDT_RESET_VALUE_SET(x) (((x) << SOC_WDT_RESET_VALUE_LSB) & SOC_WDT_RESET_VALUE_MASK) + +#define SOC_INT_STATUS_ADDRESS 0x00000044 +#define SOC_INT_STATUS_OFFSET 0x00000044 +#define SOC_INT_STATUS_MAC_4_MSB 23 +#define SOC_INT_STATUS_MAC_4_LSB 23 +#define SOC_INT_STATUS_MAC_4_MASK 0x00800000 +#define SOC_INT_STATUS_MAC_4_GET(x) (((x) & SOC_INT_STATUS_MAC_4_MASK) >> SOC_INT_STATUS_MAC_4_LSB) +#define SOC_INT_STATUS_MAC_4_SET(x) (((x) << SOC_INT_STATUS_MAC_4_LSB) & SOC_INT_STATUS_MAC_4_MASK) +#define SOC_INT_STATUS_MAC_3_MSB 22 +#define SOC_INT_STATUS_MAC_3_LSB 22 +#define SOC_INT_STATUS_MAC_3_MASK 0x00400000 +#define SOC_INT_STATUS_MAC_3_GET(x) (((x) & SOC_INT_STATUS_MAC_3_MASK) >> SOC_INT_STATUS_MAC_3_LSB) +#define SOC_INT_STATUS_MAC_3_SET(x) (((x) << SOC_INT_STATUS_MAC_3_LSB) & SOC_INT_STATUS_MAC_3_MASK) +#define SOC_INT_STATUS_MAC_2_MSB 21 +#define SOC_INT_STATUS_MAC_2_LSB 21 +#define SOC_INT_STATUS_MAC_2_MASK 0x00200000 +#define SOC_INT_STATUS_MAC_2_GET(x) (((x) & SOC_INT_STATUS_MAC_2_MASK) >> SOC_INT_STATUS_MAC_2_LSB) +#define SOC_INT_STATUS_MAC_2_SET(x) (((x) << SOC_INT_STATUS_MAC_2_LSB) & SOC_INT_STATUS_MAC_2_MASK) +#define SOC_INT_STATUS_MAC_1_MSB 20 +#define SOC_INT_STATUS_MAC_1_LSB 20 +#define SOC_INT_STATUS_MAC_1_MASK 0x00100000 +#define SOC_INT_STATUS_MAC_1_GET(x) (((x) & SOC_INT_STATUS_MAC_1_MASK) >> SOC_INT_STATUS_MAC_1_LSB) +#define SOC_INT_STATUS_MAC_1_SET(x) (((x) << SOC_INT_STATUS_MAC_1_LSB) & SOC_INT_STATUS_MAC_1_MASK) +#define SOC_INT_STATUS_USBDMA_MSB 19 +#define SOC_INT_STATUS_USBDMA_LSB 19 +#define SOC_INT_STATUS_USBDMA_MASK 0x00080000 +#define SOC_INT_STATUS_USBDMA_GET(x) (((x) & SOC_INT_STATUS_USBDMA_MASK) >> SOC_INT_STATUS_USBDMA_LSB) +#define SOC_INT_STATUS_USBDMA_SET(x) (((x) << SOC_INT_STATUS_USBDMA_LSB) & SOC_INT_STATUS_USBDMA_MASK) +#define SOC_INT_STATUS_USBIP_MSB 18 +#define SOC_INT_STATUS_USBIP_LSB 18 +#define SOC_INT_STATUS_USBIP_MASK 0x00040000 +#define SOC_INT_STATUS_USBIP_GET(x) (((x) & SOC_INT_STATUS_USBIP_MASK) >> SOC_INT_STATUS_USBIP_LSB) +#define SOC_INT_STATUS_USBIP_SET(x) (((x) << SOC_INT_STATUS_USBIP_LSB) & SOC_INT_STATUS_USBIP_MASK) +#define SOC_INT_STATUS_THERM_MSB 17 +#define SOC_INT_STATUS_THERM_LSB 17 +#define SOC_INT_STATUS_THERM_MASK 0x00020000 +#define SOC_INT_STATUS_THERM_GET(x) (((x) & SOC_INT_STATUS_THERM_MASK) >> SOC_INT_STATUS_THERM_LSB) +#define SOC_INT_STATUS_THERM_SET(x) (((x) << SOC_INT_STATUS_THERM_LSB) & SOC_INT_STATUS_THERM_MASK) +#define SOC_INT_STATUS_EFUSE_OVERWRITE_MSB 16 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_LSB 16 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_MASK 0x00010000 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_GET(x) (((x) & SOC_INT_STATUS_EFUSE_OVERWRITE_MASK) >> SOC_INT_STATUS_EFUSE_OVERWRITE_LSB) +#define SOC_INT_STATUS_EFUSE_OVERWRITE_SET(x) (((x) << SOC_INT_STATUS_EFUSE_OVERWRITE_LSB) & SOC_INT_STATUS_EFUSE_OVERWRITE_MASK) +#define SOC_INT_STATUS_RDMA_MSB 15 +#define SOC_INT_STATUS_RDMA_LSB 15 +#define SOC_INT_STATUS_RDMA_MASK 0x00008000 +#define SOC_INT_STATUS_RDMA_GET(x) (((x) & SOC_INT_STATUS_RDMA_MASK) >> SOC_INT_STATUS_RDMA_LSB) +#define SOC_INT_STATUS_RDMA_SET(x) (((x) << SOC_INT_STATUS_RDMA_LSB) & SOC_INT_STATUS_RDMA_MASK) +#define SOC_INT_STATUS_BTCOEX_MSB 14 +#define SOC_INT_STATUS_BTCOEX_LSB 14 +#define SOC_INT_STATUS_BTCOEX_MASK 0x00004000 +#define SOC_INT_STATUS_BTCOEX_GET(x) (((x) & SOC_INT_STATUS_BTCOEX_MASK) >> SOC_INT_STATUS_BTCOEX_LSB) +#define SOC_INT_STATUS_BTCOEX_SET(x) (((x) << SOC_INT_STATUS_BTCOEX_LSB) & SOC_INT_STATUS_BTCOEX_MASK) +#define SOC_INT_STATUS_RTC_POWER_MSB 13 +#define SOC_INT_STATUS_RTC_POWER_LSB 13 +#define SOC_INT_STATUS_RTC_POWER_MASK 0x00002000 +#define SOC_INT_STATUS_RTC_POWER_GET(x) (((x) & SOC_INT_STATUS_RTC_POWER_MASK) >> SOC_INT_STATUS_RTC_POWER_LSB) +#define SOC_INT_STATUS_RTC_POWER_SET(x) (((x) << SOC_INT_STATUS_RTC_POWER_LSB) & SOC_INT_STATUS_RTC_POWER_MASK) +#define SOC_INT_STATUS_MAC_MSB 12 +#define SOC_INT_STATUS_MAC_LSB 12 +#define SOC_INT_STATUS_MAC_MASK 0x00001000 +#define SOC_INT_STATUS_MAC_GET(x) (((x) & SOC_INT_STATUS_MAC_MASK) >> SOC_INT_STATUS_MAC_LSB) +#define SOC_INT_STATUS_MAC_SET(x) (((x) << SOC_INT_STATUS_MAC_LSB) & SOC_INT_STATUS_MAC_MASK) +#define SOC_INT_STATUS_MAILBOX_MSB 11 +#define SOC_INT_STATUS_MAILBOX_LSB 11 +#define SOC_INT_STATUS_MAILBOX_MASK 0x00000800 +#define SOC_INT_STATUS_MAILBOX_GET(x) (((x) & SOC_INT_STATUS_MAILBOX_MASK) >> SOC_INT_STATUS_MAILBOX_LSB) +#define SOC_INT_STATUS_MAILBOX_SET(x) (((x) << SOC_INT_STATUS_MAILBOX_LSB) & SOC_INT_STATUS_MAILBOX_MASK) +#define SOC_INT_STATUS_RTC_ALARM_MSB 10 +#define SOC_INT_STATUS_RTC_ALARM_LSB 10 +#define SOC_INT_STATUS_RTC_ALARM_MASK 0x00000400 +#define SOC_INT_STATUS_RTC_ALARM_GET(x) (((x) & SOC_INT_STATUS_RTC_ALARM_MASK) >> SOC_INT_STATUS_RTC_ALARM_LSB) +#define SOC_INT_STATUS_RTC_ALARM_SET(x) (((x) << SOC_INT_STATUS_RTC_ALARM_LSB) & SOC_INT_STATUS_RTC_ALARM_MASK) +#define SOC_INT_STATUS_HF_TIMER_MSB 9 +#define SOC_INT_STATUS_HF_TIMER_LSB 9 +#define SOC_INT_STATUS_HF_TIMER_MASK 0x00000200 +#define SOC_INT_STATUS_HF_TIMER_GET(x) (((x) & SOC_INT_STATUS_HF_TIMER_MASK) >> SOC_INT_STATUS_HF_TIMER_LSB) +#define SOC_INT_STATUS_HF_TIMER_SET(x) (((x) << SOC_INT_STATUS_HF_TIMER_LSB) & SOC_INT_STATUS_HF_TIMER_MASK) +#define SOC_INT_STATUS_LF_TIMER3_MSB 8 +#define SOC_INT_STATUS_LF_TIMER3_LSB 8 +#define SOC_INT_STATUS_LF_TIMER3_MASK 0x00000100 +#define SOC_INT_STATUS_LF_TIMER3_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER3_MASK) >> SOC_INT_STATUS_LF_TIMER3_LSB) +#define SOC_INT_STATUS_LF_TIMER3_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER3_LSB) & SOC_INT_STATUS_LF_TIMER3_MASK) +#define SOC_INT_STATUS_LF_TIMER2_MSB 7 +#define SOC_INT_STATUS_LF_TIMER2_LSB 7 +#define SOC_INT_STATUS_LF_TIMER2_MASK 0x00000080 +#define SOC_INT_STATUS_LF_TIMER2_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER2_MASK) >> SOC_INT_STATUS_LF_TIMER2_LSB) +#define SOC_INT_STATUS_LF_TIMER2_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER2_LSB) & SOC_INT_STATUS_LF_TIMER2_MASK) +#define SOC_INT_STATUS_LF_TIMER1_MSB 6 +#define SOC_INT_STATUS_LF_TIMER1_LSB 6 +#define SOC_INT_STATUS_LF_TIMER1_MASK 0x00000040 +#define SOC_INT_STATUS_LF_TIMER1_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER1_MASK) >> SOC_INT_STATUS_LF_TIMER1_LSB) +#define SOC_INT_STATUS_LF_TIMER1_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER1_LSB) & SOC_INT_STATUS_LF_TIMER1_MASK) +#define SOC_INT_STATUS_LF_TIMER0_MSB 5 +#define SOC_INT_STATUS_LF_TIMER0_LSB 5 +#define SOC_INT_STATUS_LF_TIMER0_MASK 0x00000020 +#define SOC_INT_STATUS_LF_TIMER0_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER0_MASK) >> SOC_INT_STATUS_LF_TIMER0_LSB) +#define SOC_INT_STATUS_LF_TIMER0_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER0_LSB) & SOC_INT_STATUS_LF_TIMER0_MASK) +#define SOC_INT_STATUS_SI_MSB 4 +#define SOC_INT_STATUS_SI_LSB 4 +#define SOC_INT_STATUS_SI_MASK 0x00000010 +#define SOC_INT_STATUS_SI_GET(x) (((x) & SOC_INT_STATUS_SI_MASK) >> SOC_INT_STATUS_SI_LSB) +#define SOC_INT_STATUS_SI_SET(x) (((x) << SOC_INT_STATUS_SI_LSB) & SOC_INT_STATUS_SI_MASK) +#define SOC_INT_STATUS_GPIO_MSB 3 +#define SOC_INT_STATUS_GPIO_LSB 3 +#define SOC_INT_STATUS_GPIO_MASK 0x00000008 +#define SOC_INT_STATUS_GPIO_GET(x) (((x) & SOC_INT_STATUS_GPIO_MASK) >> SOC_INT_STATUS_GPIO_LSB) +#define SOC_INT_STATUS_GPIO_SET(x) (((x) << SOC_INT_STATUS_GPIO_LSB) & SOC_INT_STATUS_GPIO_MASK) +#define SOC_INT_STATUS_DEBUG_UART_MSB 2 +#define SOC_INT_STATUS_DEBUG_UART_LSB 2 +#define SOC_INT_STATUS_DEBUG_UART_MASK 0x00000004 +#define SOC_INT_STATUS_DEBUG_UART_GET(x) (((x) & SOC_INT_STATUS_DEBUG_UART_MASK) >> SOC_INT_STATUS_DEBUG_UART_LSB) +#define SOC_INT_STATUS_DEBUG_UART_SET(x) (((x) << SOC_INT_STATUS_DEBUG_UART_LSB) & SOC_INT_STATUS_DEBUG_UART_MASK) +#define SOC_INT_STATUS_ERROR_MSB 1 +#define SOC_INT_STATUS_ERROR_LSB 1 +#define SOC_INT_STATUS_ERROR_MASK 0x00000002 +#define SOC_INT_STATUS_ERROR_GET(x) (((x) & SOC_INT_STATUS_ERROR_MASK) >> SOC_INT_STATUS_ERROR_LSB) +#define SOC_INT_STATUS_ERROR_SET(x) (((x) << SOC_INT_STATUS_ERROR_LSB) & SOC_INT_STATUS_ERROR_MASK) +#define SOC_INT_STATUS_WDT_INT_MSB 0 +#define SOC_INT_STATUS_WDT_INT_LSB 0 +#define SOC_INT_STATUS_WDT_INT_MASK 0x00000001 +#define SOC_INT_STATUS_WDT_INT_GET(x) (((x) & SOC_INT_STATUS_WDT_INT_MASK) >> SOC_INT_STATUS_WDT_INT_LSB) +#define SOC_INT_STATUS_WDT_INT_SET(x) (((x) << SOC_INT_STATUS_WDT_INT_LSB) & SOC_INT_STATUS_WDT_INT_MASK) + +#define SOC_LF_TIMER0_ADDRESS 0x00000048 +#define SOC_LF_TIMER0_OFFSET 0x00000048 +#define SOC_LF_TIMER0_TARGET_MSB 31 +#define SOC_LF_TIMER0_TARGET_LSB 0 +#define SOC_LF_TIMER0_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER0_TARGET_GET(x) (((x) & SOC_LF_TIMER0_TARGET_MASK) >> SOC_LF_TIMER0_TARGET_LSB) +#define SOC_LF_TIMER0_TARGET_SET(x) (((x) << SOC_LF_TIMER0_TARGET_LSB) & SOC_LF_TIMER0_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT0_ADDRESS 0x0000004c +#define SOC_LF_TIMER_COUNT0_OFFSET 0x0000004c +#define SOC_LF_TIMER_COUNT0_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT0_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT0_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT0_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT0_VALUE_MASK) >> SOC_LF_TIMER_COUNT0_VALUE_LSB) +#define SOC_LF_TIMER_COUNT0_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT0_VALUE_LSB) & SOC_LF_TIMER_COUNT0_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define SOC_LF_TIMER_CONTROL0_OFFSET 0x00000050 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL0_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL0_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL0_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL0_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_ENABLE_LSB) & SOC_LF_TIMER_CONTROL0_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL0_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL0_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL0_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL0_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_RESET_MASK) >> SOC_LF_TIMER_CONTROL0_RESET_LSB) +#define SOC_LF_TIMER_CONTROL0_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_RESET_LSB) & SOC_LF_TIMER_CONTROL0_RESET_MASK) + +#define SOC_LF_TIMER_STATUS0_ADDRESS 0x00000054 +#define SOC_LF_TIMER_STATUS0_OFFSET 0x00000054 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS0_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS0_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS0_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS0_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS0_INTERRUPT_MASK) + +#define SOC_LF_TIMER1_ADDRESS 0x00000058 +#define SOC_LF_TIMER1_OFFSET 0x00000058 +#define SOC_LF_TIMER1_TARGET_MSB 31 +#define SOC_LF_TIMER1_TARGET_LSB 0 +#define SOC_LF_TIMER1_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER1_TARGET_GET(x) (((x) & SOC_LF_TIMER1_TARGET_MASK) >> SOC_LF_TIMER1_TARGET_LSB) +#define SOC_LF_TIMER1_TARGET_SET(x) (((x) << SOC_LF_TIMER1_TARGET_LSB) & SOC_LF_TIMER1_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT1_ADDRESS 0x0000005c +#define SOC_LF_TIMER_COUNT1_OFFSET 0x0000005c +#define SOC_LF_TIMER_COUNT1_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT1_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT1_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT1_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT1_VALUE_MASK) >> SOC_LF_TIMER_COUNT1_VALUE_LSB) +#define SOC_LF_TIMER_COUNT1_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT1_VALUE_LSB) & SOC_LF_TIMER_COUNT1_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL1_ADDRESS 0x00000060 +#define SOC_LF_TIMER_CONTROL1_OFFSET 0x00000060 +#define SOC_LF_TIMER_CONTROL1_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL1_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL1_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL1_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL1_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL1_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_ENABLE_LSB) & SOC_LF_TIMER_CONTROL1_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL1_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL1_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL1_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL1_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_RESET_MASK) >> SOC_LF_TIMER_CONTROL1_RESET_LSB) +#define SOC_LF_TIMER_CONTROL1_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_RESET_LSB) & SOC_LF_TIMER_CONTROL1_RESET_MASK) + +#define SOC_LF_TIMER_STATUS1_ADDRESS 0x00000064 +#define SOC_LF_TIMER_STATUS1_OFFSET 0x00000064 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS1_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS1_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS1_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS1_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS1_INTERRUPT_MASK) + +#define SOC_LF_TIMER2_ADDRESS 0x00000068 +#define SOC_LF_TIMER2_OFFSET 0x00000068 +#define SOC_LF_TIMER2_TARGET_MSB 31 +#define SOC_LF_TIMER2_TARGET_LSB 0 +#define SOC_LF_TIMER2_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER2_TARGET_GET(x) (((x) & SOC_LF_TIMER2_TARGET_MASK) >> SOC_LF_TIMER2_TARGET_LSB) +#define SOC_LF_TIMER2_TARGET_SET(x) (((x) << SOC_LF_TIMER2_TARGET_LSB) & SOC_LF_TIMER2_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT2_ADDRESS 0x0000006c +#define SOC_LF_TIMER_COUNT2_OFFSET 0x0000006c +#define SOC_LF_TIMER_COUNT2_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT2_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT2_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT2_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT2_VALUE_MASK) >> SOC_LF_TIMER_COUNT2_VALUE_LSB) +#define SOC_LF_TIMER_COUNT2_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT2_VALUE_LSB) & SOC_LF_TIMER_COUNT2_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL2_ADDRESS 0x00000070 +#define SOC_LF_TIMER_CONTROL2_OFFSET 0x00000070 +#define SOC_LF_TIMER_CONTROL2_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL2_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL2_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL2_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL2_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL2_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_ENABLE_LSB) & SOC_LF_TIMER_CONTROL2_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL2_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL2_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL2_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL2_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_RESET_MASK) >> SOC_LF_TIMER_CONTROL2_RESET_LSB) +#define SOC_LF_TIMER_CONTROL2_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_RESET_LSB) & SOC_LF_TIMER_CONTROL2_RESET_MASK) + +#define SOC_LF_TIMER_STATUS2_ADDRESS 0x00000074 +#define SOC_LF_TIMER_STATUS2_OFFSET 0x00000074 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS2_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS2_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS2_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS2_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS2_INTERRUPT_MASK) + +#define SOC_LF_TIMER3_ADDRESS 0x00000078 +#define SOC_LF_TIMER3_OFFSET 0x00000078 +#define SOC_LF_TIMER3_TARGET_MSB 31 +#define SOC_LF_TIMER3_TARGET_LSB 0 +#define SOC_LF_TIMER3_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER3_TARGET_GET(x) (((x) & SOC_LF_TIMER3_TARGET_MASK) >> SOC_LF_TIMER3_TARGET_LSB) +#define SOC_LF_TIMER3_TARGET_SET(x) (((x) << SOC_LF_TIMER3_TARGET_LSB) & SOC_LF_TIMER3_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT3_ADDRESS 0x0000007c +#define SOC_LF_TIMER_COUNT3_OFFSET 0x0000007c +#define SOC_LF_TIMER_COUNT3_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT3_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT3_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT3_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT3_VALUE_MASK) >> SOC_LF_TIMER_COUNT3_VALUE_LSB) +#define SOC_LF_TIMER_COUNT3_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT3_VALUE_LSB) & SOC_LF_TIMER_COUNT3_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL3_ADDRESS 0x00000080 +#define SOC_LF_TIMER_CONTROL3_OFFSET 0x00000080 +#define SOC_LF_TIMER_CONTROL3_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL3_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL3_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL3_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL3_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL3_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_ENABLE_LSB) & SOC_LF_TIMER_CONTROL3_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL3_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL3_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL3_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL3_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_RESET_MASK) >> SOC_LF_TIMER_CONTROL3_RESET_LSB) +#define SOC_LF_TIMER_CONTROL3_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_RESET_LSB) & SOC_LF_TIMER_CONTROL3_RESET_MASK) + +#define SOC_LF_TIMER_STATUS3_ADDRESS 0x00000084 +#define SOC_LF_TIMER_STATUS3_OFFSET 0x00000084 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS3_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS3_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS3_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS3_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS3_INTERRUPT_MASK) + +#define SOC_HF_TIMER_ADDRESS 0x00000088 +#define SOC_HF_TIMER_OFFSET 0x00000088 +#define SOC_HF_TIMER_TARGET_MSB 31 +#define SOC_HF_TIMER_TARGET_LSB 12 +#define SOC_HF_TIMER_TARGET_MASK 0xfffff000 +#define SOC_HF_TIMER_TARGET_GET(x) (((x) & SOC_HF_TIMER_TARGET_MASK) >> SOC_HF_TIMER_TARGET_LSB) +#define SOC_HF_TIMER_TARGET_SET(x) (((x) << SOC_HF_TIMER_TARGET_LSB) & SOC_HF_TIMER_TARGET_MASK) + +#define SOC_HF_TIMER_COUNT_ADDRESS 0x0000008c +#define SOC_HF_TIMER_COUNT_OFFSET 0x0000008c +#define SOC_HF_TIMER_COUNT_VALUE_MSB 31 +#define SOC_HF_TIMER_COUNT_VALUE_LSB 12 +#define SOC_HF_TIMER_COUNT_VALUE_MASK 0xfffff000 +#define SOC_HF_TIMER_COUNT_VALUE_GET(x) (((x) & SOC_HF_TIMER_COUNT_VALUE_MASK) >> SOC_HF_TIMER_COUNT_VALUE_LSB) +#define SOC_HF_TIMER_COUNT_VALUE_SET(x) (((x) << SOC_HF_TIMER_COUNT_VALUE_LSB) & SOC_HF_TIMER_COUNT_VALUE_MASK) + +#define SOC_HF_LF_COUNT_ADDRESS 0x00000090 +#define SOC_HF_LF_COUNT_OFFSET 0x00000090 +#define SOC_HF_LF_COUNT_VALUE_MSB 31 +#define SOC_HF_LF_COUNT_VALUE_LSB 0 +#define SOC_HF_LF_COUNT_VALUE_MASK 0xffffffff +#define SOC_HF_LF_COUNT_VALUE_GET(x) (((x) & SOC_HF_LF_COUNT_VALUE_MASK) >> SOC_HF_LF_COUNT_VALUE_LSB) +#define SOC_HF_LF_COUNT_VALUE_SET(x) (((x) << SOC_HF_LF_COUNT_VALUE_LSB) & SOC_HF_LF_COUNT_VALUE_MASK) + +#define SOC_HF_TIMER_CONTROL_ADDRESS 0x00000094 +#define SOC_HF_TIMER_CONTROL_OFFSET 0x00000094 +#define SOC_HF_TIMER_CONTROL_ENABLE_MSB 3 +#define SOC_HF_TIMER_CONTROL_ENABLE_LSB 3 +#define SOC_HF_TIMER_CONTROL_ENABLE_MASK 0x00000008 +#define SOC_HF_TIMER_CONTROL_ENABLE_GET(x) (((x) & SOC_HF_TIMER_CONTROL_ENABLE_MASK) >> SOC_HF_TIMER_CONTROL_ENABLE_LSB) +#define SOC_HF_TIMER_CONTROL_ENABLE_SET(x) (((x) << SOC_HF_TIMER_CONTROL_ENABLE_LSB) & SOC_HF_TIMER_CONTROL_ENABLE_MASK) +#define SOC_HF_TIMER_CONTROL_ON_MSB 2 +#define SOC_HF_TIMER_CONTROL_ON_LSB 2 +#define SOC_HF_TIMER_CONTROL_ON_MASK 0x00000004 +#define SOC_HF_TIMER_CONTROL_ON_GET(x) (((x) & SOC_HF_TIMER_CONTROL_ON_MASK) >> SOC_HF_TIMER_CONTROL_ON_LSB) +#define SOC_HF_TIMER_CONTROL_ON_SET(x) (((x) << SOC_HF_TIMER_CONTROL_ON_LSB) & SOC_HF_TIMER_CONTROL_ON_MASK) +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_MSB 1 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB 1 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK 0x00000002 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_GET(x) (((x) & SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK) >> SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB) +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_SET(x) (((x) << SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB) & SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK) +#define SOC_HF_TIMER_CONTROL_RESET_MSB 0 +#define SOC_HF_TIMER_CONTROL_RESET_LSB 0 +#define SOC_HF_TIMER_CONTROL_RESET_MASK 0x00000001 +#define SOC_HF_TIMER_CONTROL_RESET_GET(x) (((x) & SOC_HF_TIMER_CONTROL_RESET_MASK) >> SOC_HF_TIMER_CONTROL_RESET_LSB) +#define SOC_HF_TIMER_CONTROL_RESET_SET(x) (((x) << SOC_HF_TIMER_CONTROL_RESET_LSB) & SOC_HF_TIMER_CONTROL_RESET_MASK) + +#define SOC_HF_TIMER_STATUS_ADDRESS 0x00000098 +#define SOC_HF_TIMER_STATUS_OFFSET 0x00000098 +#define SOC_HF_TIMER_STATUS_INTERRUPT_MSB 0 +#define SOC_HF_TIMER_STATUS_INTERRUPT_LSB 0 +#define SOC_HF_TIMER_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_HF_TIMER_STATUS_INTERRUPT_GET(x) (((x) & SOC_HF_TIMER_STATUS_INTERRUPT_MASK) >> SOC_HF_TIMER_STATUS_INTERRUPT_LSB) +#define SOC_HF_TIMER_STATUS_INTERRUPT_SET(x) (((x) << SOC_HF_TIMER_STATUS_INTERRUPT_LSB) & SOC_HF_TIMER_STATUS_INTERRUPT_MASK) + +#define SOC_RTC_CONTROL_ADDRESS 0x0000009c +#define SOC_RTC_CONTROL_OFFSET 0x0000009c +#define SOC_RTC_CONTROL_ENABLE_MSB 2 +#define SOC_RTC_CONTROL_ENABLE_LSB 2 +#define SOC_RTC_CONTROL_ENABLE_MASK 0x00000004 +#define SOC_RTC_CONTROL_ENABLE_GET(x) (((x) & SOC_RTC_CONTROL_ENABLE_MASK) >> SOC_RTC_CONTROL_ENABLE_LSB) +#define SOC_RTC_CONTROL_ENABLE_SET(x) (((x) << SOC_RTC_CONTROL_ENABLE_LSB) & SOC_RTC_CONTROL_ENABLE_MASK) +#define SOC_RTC_CONTROL_LOAD_RTC_MSB 1 +#define SOC_RTC_CONTROL_LOAD_RTC_LSB 1 +#define SOC_RTC_CONTROL_LOAD_RTC_MASK 0x00000002 +#define SOC_RTC_CONTROL_LOAD_RTC_GET(x) (((x) & SOC_RTC_CONTROL_LOAD_RTC_MASK) >> SOC_RTC_CONTROL_LOAD_RTC_LSB) +#define SOC_RTC_CONTROL_LOAD_RTC_SET(x) (((x) << SOC_RTC_CONTROL_LOAD_RTC_LSB) & SOC_RTC_CONTROL_LOAD_RTC_MASK) +#define SOC_RTC_CONTROL_LOAD_ALARM_MSB 0 +#define SOC_RTC_CONTROL_LOAD_ALARM_LSB 0 +#define SOC_RTC_CONTROL_LOAD_ALARM_MASK 0x00000001 +#define SOC_RTC_CONTROL_LOAD_ALARM_GET(x) (((x) & SOC_RTC_CONTROL_LOAD_ALARM_MASK) >> SOC_RTC_CONTROL_LOAD_ALARM_LSB) +#define SOC_RTC_CONTROL_LOAD_ALARM_SET(x) (((x) << SOC_RTC_CONTROL_LOAD_ALARM_LSB) & SOC_RTC_CONTROL_LOAD_ALARM_MASK) + +#define SOC_RTC_TIME_ADDRESS 0x000000a0 +#define SOC_RTC_TIME_OFFSET 0x000000a0 +#define SOC_RTC_TIME_WEEK_DAY_MSB 26 +#define SOC_RTC_TIME_WEEK_DAY_LSB 24 +#define SOC_RTC_TIME_WEEK_DAY_MASK 0x07000000 +#define SOC_RTC_TIME_WEEK_DAY_GET(x) (((x) & SOC_RTC_TIME_WEEK_DAY_MASK) >> SOC_RTC_TIME_WEEK_DAY_LSB) +#define SOC_RTC_TIME_WEEK_DAY_SET(x) (((x) << SOC_RTC_TIME_WEEK_DAY_LSB) & SOC_RTC_TIME_WEEK_DAY_MASK) +#define SOC_RTC_TIME_HOUR_MSB 21 +#define SOC_RTC_TIME_HOUR_LSB 16 +#define SOC_RTC_TIME_HOUR_MASK 0x003f0000 +#define SOC_RTC_TIME_HOUR_GET(x) (((x) & SOC_RTC_TIME_HOUR_MASK) >> SOC_RTC_TIME_HOUR_LSB) +#define SOC_RTC_TIME_HOUR_SET(x) (((x) << SOC_RTC_TIME_HOUR_LSB) & SOC_RTC_TIME_HOUR_MASK) +#define SOC_RTC_TIME_MINUTE_MSB 14 +#define SOC_RTC_TIME_MINUTE_LSB 8 +#define SOC_RTC_TIME_MINUTE_MASK 0x00007f00 +#define SOC_RTC_TIME_MINUTE_GET(x) (((x) & SOC_RTC_TIME_MINUTE_MASK) >> SOC_RTC_TIME_MINUTE_LSB) +#define SOC_RTC_TIME_MINUTE_SET(x) (((x) << SOC_RTC_TIME_MINUTE_LSB) & SOC_RTC_TIME_MINUTE_MASK) +#define SOC_RTC_TIME_SECOND_MSB 6 +#define SOC_RTC_TIME_SECOND_LSB 0 +#define SOC_RTC_TIME_SECOND_MASK 0x0000007f +#define SOC_RTC_TIME_SECOND_GET(x) (((x) & SOC_RTC_TIME_SECOND_MASK) >> SOC_RTC_TIME_SECOND_LSB) +#define SOC_RTC_TIME_SECOND_SET(x) (((x) << SOC_RTC_TIME_SECOND_LSB) & SOC_RTC_TIME_SECOND_MASK) + +#define SOC_RTC_DATE_ADDRESS 0x000000a4 +#define SOC_RTC_DATE_OFFSET 0x000000a4 +#define SOC_RTC_DATE_YEAR_MSB 23 +#define SOC_RTC_DATE_YEAR_LSB 16 +#define SOC_RTC_DATE_YEAR_MASK 0x00ff0000 +#define SOC_RTC_DATE_YEAR_GET(x) (((x) & SOC_RTC_DATE_YEAR_MASK) >> SOC_RTC_DATE_YEAR_LSB) +#define SOC_RTC_DATE_YEAR_SET(x) (((x) << SOC_RTC_DATE_YEAR_LSB) & SOC_RTC_DATE_YEAR_MASK) +#define SOC_RTC_DATE_MONTH_MSB 12 +#define SOC_RTC_DATE_MONTH_LSB 8 +#define SOC_RTC_DATE_MONTH_MASK 0x00001f00 +#define SOC_RTC_DATE_MONTH_GET(x) (((x) & SOC_RTC_DATE_MONTH_MASK) >> SOC_RTC_DATE_MONTH_LSB) +#define SOC_RTC_DATE_MONTH_SET(x) (((x) << SOC_RTC_DATE_MONTH_LSB) & SOC_RTC_DATE_MONTH_MASK) +#define SOC_RTC_DATE_MONTH_DAY_MSB 5 +#define SOC_RTC_DATE_MONTH_DAY_LSB 0 +#define SOC_RTC_DATE_MONTH_DAY_MASK 0x0000003f +#define SOC_RTC_DATE_MONTH_DAY_GET(x) (((x) & SOC_RTC_DATE_MONTH_DAY_MASK) >> SOC_RTC_DATE_MONTH_DAY_LSB) +#define SOC_RTC_DATE_MONTH_DAY_SET(x) (((x) << SOC_RTC_DATE_MONTH_DAY_LSB) & SOC_RTC_DATE_MONTH_DAY_MASK) + +#define SOC_RTC_SET_TIME_ADDRESS 0x000000a8 +#define SOC_RTC_SET_TIME_OFFSET 0x000000a8 +#define SOC_RTC_SET_TIME_WEEK_DAY_MSB 26 +#define SOC_RTC_SET_TIME_WEEK_DAY_LSB 24 +#define SOC_RTC_SET_TIME_WEEK_DAY_MASK 0x07000000 +#define SOC_RTC_SET_TIME_WEEK_DAY_GET(x) (((x) & SOC_RTC_SET_TIME_WEEK_DAY_MASK) >> SOC_RTC_SET_TIME_WEEK_DAY_LSB) +#define SOC_RTC_SET_TIME_WEEK_DAY_SET(x) (((x) << SOC_RTC_SET_TIME_WEEK_DAY_LSB) & SOC_RTC_SET_TIME_WEEK_DAY_MASK) +#define SOC_RTC_SET_TIME_HOUR_MSB 21 +#define SOC_RTC_SET_TIME_HOUR_LSB 16 +#define SOC_RTC_SET_TIME_HOUR_MASK 0x003f0000 +#define SOC_RTC_SET_TIME_HOUR_GET(x) (((x) & SOC_RTC_SET_TIME_HOUR_MASK) >> SOC_RTC_SET_TIME_HOUR_LSB) +#define SOC_RTC_SET_TIME_HOUR_SET(x) (((x) << SOC_RTC_SET_TIME_HOUR_LSB) & SOC_RTC_SET_TIME_HOUR_MASK) +#define SOC_RTC_SET_TIME_MINUTE_MSB 14 +#define SOC_RTC_SET_TIME_MINUTE_LSB 8 +#define SOC_RTC_SET_TIME_MINUTE_MASK 0x00007f00 +#define SOC_RTC_SET_TIME_MINUTE_GET(x) (((x) & SOC_RTC_SET_TIME_MINUTE_MASK) >> SOC_RTC_SET_TIME_MINUTE_LSB) +#define SOC_RTC_SET_TIME_MINUTE_SET(x) (((x) << SOC_RTC_SET_TIME_MINUTE_LSB) & SOC_RTC_SET_TIME_MINUTE_MASK) +#define SOC_RTC_SET_TIME_SECOND_MSB 6 +#define SOC_RTC_SET_TIME_SECOND_LSB 0 +#define SOC_RTC_SET_TIME_SECOND_MASK 0x0000007f +#define SOC_RTC_SET_TIME_SECOND_GET(x) (((x) & SOC_RTC_SET_TIME_SECOND_MASK) >> SOC_RTC_SET_TIME_SECOND_LSB) +#define SOC_RTC_SET_TIME_SECOND_SET(x) (((x) << SOC_RTC_SET_TIME_SECOND_LSB) & SOC_RTC_SET_TIME_SECOND_MASK) + +#define SOC_RTC_SET_DATE_ADDRESS 0x000000ac +#define SOC_RTC_SET_DATE_OFFSET 0x000000ac +#define SOC_RTC_SET_DATE_YEAR_MSB 23 +#define SOC_RTC_SET_DATE_YEAR_LSB 16 +#define SOC_RTC_SET_DATE_YEAR_MASK 0x00ff0000 +#define SOC_RTC_SET_DATE_YEAR_GET(x) (((x) & SOC_RTC_SET_DATE_YEAR_MASK) >> SOC_RTC_SET_DATE_YEAR_LSB) +#define SOC_RTC_SET_DATE_YEAR_SET(x) (((x) << SOC_RTC_SET_DATE_YEAR_LSB) & SOC_RTC_SET_DATE_YEAR_MASK) +#define SOC_RTC_SET_DATE_MONTH_MSB 12 +#define SOC_RTC_SET_DATE_MONTH_LSB 8 +#define SOC_RTC_SET_DATE_MONTH_MASK 0x00001f00 +#define SOC_RTC_SET_DATE_MONTH_GET(x) (((x) & SOC_RTC_SET_DATE_MONTH_MASK) >> SOC_RTC_SET_DATE_MONTH_LSB) +#define SOC_RTC_SET_DATE_MONTH_SET(x) (((x) << SOC_RTC_SET_DATE_MONTH_LSB) & SOC_RTC_SET_DATE_MONTH_MASK) +#define SOC_RTC_SET_DATE_MONTH_DAY_MSB 5 +#define SOC_RTC_SET_DATE_MONTH_DAY_LSB 0 +#define SOC_RTC_SET_DATE_MONTH_DAY_MASK 0x0000003f +#define SOC_RTC_SET_DATE_MONTH_DAY_GET(x) (((x) & SOC_RTC_SET_DATE_MONTH_DAY_MASK) >> SOC_RTC_SET_DATE_MONTH_DAY_LSB) +#define SOC_RTC_SET_DATE_MONTH_DAY_SET(x) (((x) << SOC_RTC_SET_DATE_MONTH_DAY_LSB) & SOC_RTC_SET_DATE_MONTH_DAY_MASK) + +#define SOC_RTC_SET_ALARM_ADDRESS 0x000000b0 +#define SOC_RTC_SET_ALARM_OFFSET 0x000000b0 +#define SOC_RTC_SET_ALARM_HOUR_MSB 21 +#define SOC_RTC_SET_ALARM_HOUR_LSB 16 +#define SOC_RTC_SET_ALARM_HOUR_MASK 0x003f0000 +#define SOC_RTC_SET_ALARM_HOUR_GET(x) (((x) & SOC_RTC_SET_ALARM_HOUR_MASK) >> SOC_RTC_SET_ALARM_HOUR_LSB) +#define SOC_RTC_SET_ALARM_HOUR_SET(x) (((x) << SOC_RTC_SET_ALARM_HOUR_LSB) & SOC_RTC_SET_ALARM_HOUR_MASK) +#define SOC_RTC_SET_ALARM_MINUTE_MSB 14 +#define SOC_RTC_SET_ALARM_MINUTE_LSB 8 +#define SOC_RTC_SET_ALARM_MINUTE_MASK 0x00007f00 +#define SOC_RTC_SET_ALARM_MINUTE_GET(x) (((x) & SOC_RTC_SET_ALARM_MINUTE_MASK) >> SOC_RTC_SET_ALARM_MINUTE_LSB) +#define SOC_RTC_SET_ALARM_MINUTE_SET(x) (((x) << SOC_RTC_SET_ALARM_MINUTE_LSB) & SOC_RTC_SET_ALARM_MINUTE_MASK) +#define SOC_RTC_SET_ALARM_SECOND_MSB 6 +#define SOC_RTC_SET_ALARM_SECOND_LSB 0 +#define SOC_RTC_SET_ALARM_SECOND_MASK 0x0000007f +#define SOC_RTC_SET_ALARM_SECOND_GET(x) (((x) & SOC_RTC_SET_ALARM_SECOND_MASK) >> SOC_RTC_SET_ALARM_SECOND_LSB) +#define SOC_RTC_SET_ALARM_SECOND_SET(x) (((x) << SOC_RTC_SET_ALARM_SECOND_LSB) & SOC_RTC_SET_ALARM_SECOND_MASK) + +#define SOC_RTC_CONFIG_ADDRESS 0x000000b4 +#define SOC_RTC_CONFIG_OFFSET 0x000000b4 +#define SOC_RTC_CONFIG_BCD_MSB 2 +#define SOC_RTC_CONFIG_BCD_LSB 2 +#define SOC_RTC_CONFIG_BCD_MASK 0x00000004 +#define SOC_RTC_CONFIG_BCD_GET(x) (((x) & SOC_RTC_CONFIG_BCD_MASK) >> SOC_RTC_CONFIG_BCD_LSB) +#define SOC_RTC_CONFIG_BCD_SET(x) (((x) << SOC_RTC_CONFIG_BCD_LSB) & SOC_RTC_CONFIG_BCD_MASK) +#define SOC_RTC_CONFIG_TWELVE_HOUR_MSB 1 +#define SOC_RTC_CONFIG_TWELVE_HOUR_LSB 1 +#define SOC_RTC_CONFIG_TWELVE_HOUR_MASK 0x00000002 +#define SOC_RTC_CONFIG_TWELVE_HOUR_GET(x) (((x) & SOC_RTC_CONFIG_TWELVE_HOUR_MASK) >> SOC_RTC_CONFIG_TWELVE_HOUR_LSB) +#define SOC_RTC_CONFIG_TWELVE_HOUR_SET(x) (((x) << SOC_RTC_CONFIG_TWELVE_HOUR_LSB) & SOC_RTC_CONFIG_TWELVE_HOUR_MASK) +#define SOC_RTC_CONFIG_DSE_MSB 0 +#define SOC_RTC_CONFIG_DSE_LSB 0 +#define SOC_RTC_CONFIG_DSE_MASK 0x00000001 +#define SOC_RTC_CONFIG_DSE_GET(x) (((x) & SOC_RTC_CONFIG_DSE_MASK) >> SOC_RTC_CONFIG_DSE_LSB) +#define SOC_RTC_CONFIG_DSE_SET(x) (((x) << SOC_RTC_CONFIG_DSE_LSB) & SOC_RTC_CONFIG_DSE_MASK) + +#define SOC_RTC_ALARM_STATUS_ADDRESS 0x000000b8 +#define SOC_RTC_ALARM_STATUS_OFFSET 0x000000b8 +#define SOC_RTC_ALARM_STATUS_ENABLE_MSB 1 +#define SOC_RTC_ALARM_STATUS_ENABLE_LSB 1 +#define SOC_RTC_ALARM_STATUS_ENABLE_MASK 0x00000002 +#define SOC_RTC_ALARM_STATUS_ENABLE_GET(x) (((x) & SOC_RTC_ALARM_STATUS_ENABLE_MASK) >> SOC_RTC_ALARM_STATUS_ENABLE_LSB) +#define SOC_RTC_ALARM_STATUS_ENABLE_SET(x) (((x) << SOC_RTC_ALARM_STATUS_ENABLE_LSB) & SOC_RTC_ALARM_STATUS_ENABLE_MASK) +#define SOC_RTC_ALARM_STATUS_INTERRUPT_MSB 0 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_LSB 0 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_GET(x) (((x) & SOC_RTC_ALARM_STATUS_INTERRUPT_MASK) >> SOC_RTC_ALARM_STATUS_INTERRUPT_LSB) +#define SOC_RTC_ALARM_STATUS_INTERRUPT_SET(x) (((x) << SOC_RTC_ALARM_STATUS_INTERRUPT_LSB) & SOC_RTC_ALARM_STATUS_INTERRUPT_MASK) + +#define SOC_UART_WAKEUP_ADDRESS 0x000000bc +#define SOC_UART_WAKEUP_OFFSET 0x000000bc +#define SOC_UART_WAKEUP_ENABLE_MSB 0 +#define SOC_UART_WAKEUP_ENABLE_LSB 0 +#define SOC_UART_WAKEUP_ENABLE_MASK 0x00000001 +#define SOC_UART_WAKEUP_ENABLE_GET(x) (((x) & SOC_UART_WAKEUP_ENABLE_MASK) >> SOC_UART_WAKEUP_ENABLE_LSB) +#define SOC_UART_WAKEUP_ENABLE_SET(x) (((x) << SOC_UART_WAKEUP_ENABLE_LSB) & SOC_UART_WAKEUP_ENABLE_MASK) + +#define SOC_RESET_CAUSE_ADDRESS 0x000000c0 +#define SOC_RESET_CAUSE_OFFSET 0x000000c0 +#define SOC_RESET_CAUSE_LAST_MSB 2 +#define SOC_RESET_CAUSE_LAST_LSB 0 +#define SOC_RESET_CAUSE_LAST_MASK 0x00000007 +#define SOC_RESET_CAUSE_LAST_GET(x) (((x) & SOC_RESET_CAUSE_LAST_MASK) >> SOC_RESET_CAUSE_LAST_LSB) +#define SOC_RESET_CAUSE_LAST_SET(x) (((x) << SOC_RESET_CAUSE_LAST_LSB) & SOC_RESET_CAUSE_LAST_MASK) + +#define SOC_SYSTEM_SLEEP_ADDRESS 0x000000c4 +#define SOC_SYSTEM_SLEEP_OFFSET 0x000000c4 +#define SOC_SYSTEM_SLEEP_MCI_MSB 5 +#define SOC_SYSTEM_SLEEP_MCI_LSB 5 +#define SOC_SYSTEM_SLEEP_MCI_MASK 0x00000020 +#define SOC_SYSTEM_SLEEP_MCI_GET(x) (((x) & SOC_SYSTEM_SLEEP_MCI_MASK) >> SOC_SYSTEM_SLEEP_MCI_LSB) +#define SOC_SYSTEM_SLEEP_MCI_SET(x) (((x) << SOC_SYSTEM_SLEEP_MCI_LSB) & SOC_SYSTEM_SLEEP_MCI_MASK) +#define SOC_SYSTEM_SLEEP_HOST_IF_MSB 4 +#define SOC_SYSTEM_SLEEP_HOST_IF_LSB 4 +#define SOC_SYSTEM_SLEEP_HOST_IF_MASK 0x00000010 +#define SOC_SYSTEM_SLEEP_HOST_IF_GET(x) (((x) & SOC_SYSTEM_SLEEP_HOST_IF_MASK) >> SOC_SYSTEM_SLEEP_HOST_IF_LSB) +#define SOC_SYSTEM_SLEEP_HOST_IF_SET(x) (((x) << SOC_SYSTEM_SLEEP_HOST_IF_LSB) & SOC_SYSTEM_SLEEP_HOST_IF_MASK) +#define SOC_SYSTEM_SLEEP_MBOX_MSB 3 +#define SOC_SYSTEM_SLEEP_MBOX_LSB 3 +#define SOC_SYSTEM_SLEEP_MBOX_MASK 0x00000008 +#define SOC_SYSTEM_SLEEP_MBOX_GET(x) (((x) & SOC_SYSTEM_SLEEP_MBOX_MASK) >> SOC_SYSTEM_SLEEP_MBOX_LSB) +#define SOC_SYSTEM_SLEEP_MBOX_SET(x) (((x) << SOC_SYSTEM_SLEEP_MBOX_LSB) & SOC_SYSTEM_SLEEP_MBOX_MASK) +#define SOC_SYSTEM_SLEEP_MAC_IF_MSB 2 +#define SOC_SYSTEM_SLEEP_MAC_IF_LSB 2 +#define SOC_SYSTEM_SLEEP_MAC_IF_MASK 0x00000004 +#define SOC_SYSTEM_SLEEP_MAC_IF_GET(x) (((x) & SOC_SYSTEM_SLEEP_MAC_IF_MASK) >> SOC_SYSTEM_SLEEP_MAC_IF_LSB) +#define SOC_SYSTEM_SLEEP_MAC_IF_SET(x) (((x) << SOC_SYSTEM_SLEEP_MAC_IF_LSB) & SOC_SYSTEM_SLEEP_MAC_IF_MASK) +#define SOC_SYSTEM_SLEEP_LIGHT_MSB 1 +#define SOC_SYSTEM_SLEEP_LIGHT_LSB 1 +#define SOC_SYSTEM_SLEEP_LIGHT_MASK 0x00000002 +#define SOC_SYSTEM_SLEEP_LIGHT_GET(x) (((x) & SOC_SYSTEM_SLEEP_LIGHT_MASK) >> SOC_SYSTEM_SLEEP_LIGHT_LSB) +#define SOC_SYSTEM_SLEEP_LIGHT_SET(x) (((x) << SOC_SYSTEM_SLEEP_LIGHT_LSB) & SOC_SYSTEM_SLEEP_LIGHT_MASK) +#define SOC_SYSTEM_SLEEP_DISABLE_MSB 0 +#define SOC_SYSTEM_SLEEP_DISABLE_LSB 0 +#define SOC_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define SOC_SYSTEM_SLEEP_DISABLE_GET(x) (((x) & SOC_SYSTEM_SLEEP_DISABLE_MASK) >> SOC_SYSTEM_SLEEP_DISABLE_LSB) +#define SOC_SYSTEM_SLEEP_DISABLE_SET(x) (((x) << SOC_SYSTEM_SLEEP_DISABLE_LSB) & SOC_SYSTEM_SLEEP_DISABLE_MASK) + +#define SOC_SDIO_WRAPPER_ADDRESS 0x000000c8 +#define SOC_SDIO_WRAPPER_OFFSET 0x000000c8 +#define SOC_SDIO_WRAPPER_SLEEP_MSB 3 +#define SOC_SDIO_WRAPPER_SLEEP_LSB 3 +#define SOC_SDIO_WRAPPER_SLEEP_MASK 0x00000008 +#define SOC_SDIO_WRAPPER_SLEEP_GET(x) (((x) & SOC_SDIO_WRAPPER_SLEEP_MASK) >> SOC_SDIO_WRAPPER_SLEEP_LSB) +#define SOC_SDIO_WRAPPER_SLEEP_SET(x) (((x) << SOC_SDIO_WRAPPER_SLEEP_LSB) & SOC_SDIO_WRAPPER_SLEEP_MASK) +#define SOC_SDIO_WRAPPER_WAKEUP_MSB 2 +#define SOC_SDIO_WRAPPER_WAKEUP_LSB 2 +#define SOC_SDIO_WRAPPER_WAKEUP_MASK 0x00000004 +#define SOC_SDIO_WRAPPER_WAKEUP_GET(x) (((x) & SOC_SDIO_WRAPPER_WAKEUP_MASK) >> SOC_SDIO_WRAPPER_WAKEUP_LSB) +#define SOC_SDIO_WRAPPER_WAKEUP_SET(x) (((x) << SOC_SDIO_WRAPPER_WAKEUP_LSB) & SOC_SDIO_WRAPPER_WAKEUP_MASK) +#define SOC_SDIO_WRAPPER_SOC_ON_MSB 1 +#define SOC_SDIO_WRAPPER_SOC_ON_LSB 1 +#define SOC_SDIO_WRAPPER_SOC_ON_MASK 0x00000002 +#define SOC_SDIO_WRAPPER_SOC_ON_GET(x) (((x) & SOC_SDIO_WRAPPER_SOC_ON_MASK) >> SOC_SDIO_WRAPPER_SOC_ON_LSB) +#define SOC_SDIO_WRAPPER_SOC_ON_SET(x) (((x) << SOC_SDIO_WRAPPER_SOC_ON_LSB) & SOC_SDIO_WRAPPER_SOC_ON_MASK) +#define SOC_SDIO_WRAPPER_ON_MSB 0 +#define SOC_SDIO_WRAPPER_ON_LSB 0 +#define SOC_SDIO_WRAPPER_ON_MASK 0x00000001 +#define SOC_SDIO_WRAPPER_ON_GET(x) (((x) & SOC_SDIO_WRAPPER_ON_MASK) >> SOC_SDIO_WRAPPER_ON_LSB) +#define SOC_SDIO_WRAPPER_ON_SET(x) (((x) << SOC_SDIO_WRAPPER_ON_LSB) & SOC_SDIO_WRAPPER_ON_MASK) + +#define SOC_INT_SLEEP_MASK_ADDRESS 0x000000cc +#define SOC_INT_SLEEP_MASK_OFFSET 0x000000cc +#define SOC_INT_SLEEP_MASK_BITMAP_MSB 31 +#define SOC_INT_SLEEP_MASK_BITMAP_LSB 0 +#define SOC_INT_SLEEP_MASK_BITMAP_MASK 0xffffffff +#define SOC_INT_SLEEP_MASK_BITMAP_GET(x) (((x) & SOC_INT_SLEEP_MASK_BITMAP_MASK) >> SOC_INT_SLEEP_MASK_BITMAP_LSB) +#define SOC_INT_SLEEP_MASK_BITMAP_SET(x) (((x) << SOC_INT_SLEEP_MASK_BITMAP_LSB) & SOC_INT_SLEEP_MASK_BITMAP_MASK) + +#define SOC_LPO_CAL_TIME_ADDRESS 0x000000d4 +#define SOC_LPO_CAL_TIME_OFFSET 0x000000d4 +#define SOC_LPO_CAL_TIME_LENGTH_MSB 13 +#define SOC_LPO_CAL_TIME_LENGTH_LSB 0 +#define SOC_LPO_CAL_TIME_LENGTH_MASK 0x00003fff +#define SOC_LPO_CAL_TIME_LENGTH_GET(x) (((x) & SOC_LPO_CAL_TIME_LENGTH_MASK) >> SOC_LPO_CAL_TIME_LENGTH_LSB) +#define SOC_LPO_CAL_TIME_LENGTH_SET(x) (((x) << SOC_LPO_CAL_TIME_LENGTH_LSB) & SOC_LPO_CAL_TIME_LENGTH_MASK) + +#define SOC_LPO_INIT_DIVIDEND_INT_ADDRESS 0x000000d8 +#define SOC_LPO_INIT_DIVIDEND_INT_OFFSET 0x000000d8 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_MSB 23 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB 0 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK 0x00ffffff +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_GET(x) (((x) & SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK) >> SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB) +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_SET(x) (((x) << SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB) & SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK) + +#define SOC_LPO_INIT_DIVIDEND_FRACTION_ADDRESS 0x000000dc +#define SOC_LPO_INIT_DIVIDEND_FRACTION_OFFSET 0x000000dc +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MSB 10 +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB 0 +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK 0x000007ff +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_GET(x) (((x) & SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK) >> SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB) +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_SET(x) (((x) << SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB) & SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK) + +#define SOC_LPO_CAL_ADDRESS 0x000000e0 +#define SOC_LPO_CAL_OFFSET 0x000000e0 +#define SOC_LPO_CAL_ENABLE_MSB 20 +#define SOC_LPO_CAL_ENABLE_LSB 20 +#define SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define SOC_LPO_CAL_ENABLE_GET(x) (((x) & SOC_LPO_CAL_ENABLE_MASK) >> SOC_LPO_CAL_ENABLE_LSB) +#define SOC_LPO_CAL_ENABLE_SET(x) (((x) << SOC_LPO_CAL_ENABLE_LSB) & SOC_LPO_CAL_ENABLE_MASK) +#define SOC_LPO_CAL_COUNT_MSB 19 +#define SOC_LPO_CAL_COUNT_LSB 0 +#define SOC_LPO_CAL_COUNT_MASK 0x000fffff +#define SOC_LPO_CAL_COUNT_GET(x) (((x) & SOC_LPO_CAL_COUNT_MASK) >> SOC_LPO_CAL_COUNT_LSB) +#define SOC_LPO_CAL_COUNT_SET(x) (((x) << SOC_LPO_CAL_COUNT_LSB) & SOC_LPO_CAL_COUNT_MASK) + +#define SOC_LPO_CAL_TEST_CONTROL_ADDRESS 0x000000e4 +#define SOC_LPO_CAL_TEST_CONTROL_OFFSET 0x000000e4 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_MSB 16 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB 16 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK 0x00010000 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_GET(x) (((x) & SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK) >> SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB) +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_SET(x) (((x) << SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB) & SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK) +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MSB 15 +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB 0 +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK 0x0000ffff +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_GET(x) (((x) & SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK) >> SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB) +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_SET(x) (((x) << SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB) & SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK) + +#define SOC_LPO_CAL_TEST_STATUS_ADDRESS 0x000000e8 +#define SOC_LPO_CAL_TEST_STATUS_OFFSET 0x000000e8 +#define SOC_LPO_CAL_TEST_STATUS_READY_MSB 16 +#define SOC_LPO_CAL_TEST_STATUS_READY_LSB 16 +#define SOC_LPO_CAL_TEST_STATUS_READY_MASK 0x00010000 +#define SOC_LPO_CAL_TEST_STATUS_READY_GET(x) (((x) & SOC_LPO_CAL_TEST_STATUS_READY_MASK) >> SOC_LPO_CAL_TEST_STATUS_READY_LSB) +#define SOC_LPO_CAL_TEST_STATUS_READY_SET(x) (((x) << SOC_LPO_CAL_TEST_STATUS_READY_LSB) & SOC_LPO_CAL_TEST_STATUS_READY_MASK) +#define SOC_LPO_CAL_TEST_STATUS_COUNT_MSB 15 +#define SOC_LPO_CAL_TEST_STATUS_COUNT_LSB 0 +#define SOC_LPO_CAL_TEST_STATUS_COUNT_MASK 0x0000ffff +#define SOC_LPO_CAL_TEST_STATUS_COUNT_GET(x) (((x) & SOC_LPO_CAL_TEST_STATUS_COUNT_MASK) >> SOC_LPO_CAL_TEST_STATUS_COUNT_LSB) +#define SOC_LPO_CAL_TEST_STATUS_COUNT_SET(x) (((x) << SOC_LPO_CAL_TEST_STATUS_COUNT_LSB) & SOC_LPO_CAL_TEST_STATUS_COUNT_MASK) + +#define LEGACY_SOC_CHIP_ID_ADDRESS 0x000000ec +#define LEGACY_SOC_CHIP_ID_OFFSET 0x000000ec +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_MSB 31 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB 16 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK 0xffff0000 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK) >> LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB) +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB) & LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK) +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_MSB 15 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB 4 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK 0x0000fff0 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK) >> LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB) +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB) & LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK) +#define LEGACY_SOC_CHIP_ID_VERSION_ID_MSB 3 +#define LEGACY_SOC_CHIP_ID_VERSION_ID_LSB 0 +#define LEGACY_SOC_CHIP_ID_VERSION_ID_MASK 0x0000000f +#define LEGACY_SOC_CHIP_ID_VERSION_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_VERSION_ID_MASK) >> LEGACY_SOC_CHIP_ID_VERSION_ID_LSB) +#define LEGACY_SOC_CHIP_ID_VERSION_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_VERSION_ID_LSB) & LEGACY_SOC_CHIP_ID_VERSION_ID_MASK) + +#define SOC_CHIP_ID_ADDRESS 0x000000f0 +#define SOC_CHIP_ID_OFFSET 0x000000f0 +#define SOC_CHIP_ID_DEVICE_ID_MSB 31 +#define SOC_CHIP_ID_DEVICE_ID_LSB 16 +#define SOC_CHIP_ID_DEVICE_ID_MASK 0xffff0000 +#define SOC_CHIP_ID_DEVICE_ID_GET(x) (((x) & SOC_CHIP_ID_DEVICE_ID_MASK) >> SOC_CHIP_ID_DEVICE_ID_LSB) +#define SOC_CHIP_ID_DEVICE_ID_SET(x) (((x) << SOC_CHIP_ID_DEVICE_ID_LSB) & SOC_CHIP_ID_DEVICE_ID_MASK) +#define SOC_CHIP_ID_CONFIG_ID_MSB 15 +#define SOC_CHIP_ID_CONFIG_ID_LSB 4 +#define SOC_CHIP_ID_CONFIG_ID_MASK 0x0000fff0 +#define SOC_CHIP_ID_CONFIG_ID_GET(x) (((x) & SOC_CHIP_ID_CONFIG_ID_MASK) >> SOC_CHIP_ID_CONFIG_ID_LSB) +#define SOC_CHIP_ID_CONFIG_ID_SET(x) (((x) << SOC_CHIP_ID_CONFIG_ID_LSB) & SOC_CHIP_ID_CONFIG_ID_MASK) +#define SOC_CHIP_ID_VERSION_ID_MSB 3 +#define SOC_CHIP_ID_VERSION_ID_LSB 0 +#define SOC_CHIP_ID_VERSION_ID_MASK 0x0000000f +#define SOC_CHIP_ID_VERSION_ID_GET(x) (((x) & SOC_CHIP_ID_VERSION_ID_MASK) >> SOC_CHIP_ID_VERSION_ID_LSB) +#define SOC_CHIP_ID_VERSION_ID_SET(x) (((x) << SOC_CHIP_ID_VERSION_ID_LSB) & SOC_CHIP_ID_VERSION_ID_MASK) + +#define SOC_POWER_REG_ADDRESS 0x0000010c +#define SOC_POWER_REG_OFFSET 0x0000010c +#define SOC_POWER_REG_DISCON_MODE_EN_MSB 16 +#define SOC_POWER_REG_DISCON_MODE_EN_LSB 16 +#define SOC_POWER_REG_DISCON_MODE_EN_MASK 0x00010000 +#define SOC_POWER_REG_DISCON_MODE_EN_GET(x) (((x) & SOC_POWER_REG_DISCON_MODE_EN_MASK) >> SOC_POWER_REG_DISCON_MODE_EN_LSB) +#define SOC_POWER_REG_DISCON_MODE_EN_SET(x) (((x) << SOC_POWER_REG_DISCON_MODE_EN_LSB) & SOC_POWER_REG_DISCON_MODE_EN_MASK) +#define SOC_POWER_REG_DEEP_SLEEP_EN_MSB 15 +#define SOC_POWER_REG_DEEP_SLEEP_EN_LSB 15 +#define SOC_POWER_REG_DEEP_SLEEP_EN_MASK 0x00008000 +#define SOC_POWER_REG_DEEP_SLEEP_EN_GET(x) (((x) & SOC_POWER_REG_DEEP_SLEEP_EN_MASK) >> SOC_POWER_REG_DEEP_SLEEP_EN_LSB) +#define SOC_POWER_REG_DEEP_SLEEP_EN_SET(x) (((x) << SOC_POWER_REG_DEEP_SLEEP_EN_LSB) & SOC_POWER_REG_DEEP_SLEEP_EN_MASK) +#define SOC_POWER_REG_DEBUG_EN_MSB 14 +#define SOC_POWER_REG_DEBUG_EN_LSB 14 +#define SOC_POWER_REG_DEBUG_EN_MASK 0x00004000 +#define SOC_POWER_REG_DEBUG_EN_GET(x) (((x) & SOC_POWER_REG_DEBUG_EN_MASK) >> SOC_POWER_REG_DEBUG_EN_LSB) +#define SOC_POWER_REG_DEBUG_EN_SET(x) (((x) << SOC_POWER_REG_DEBUG_EN_LSB) & SOC_POWER_REG_DEBUG_EN_MASK) +#define SOC_POWER_REG_WLAN_BB_PWD_EN_MSB 13 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_LSB 13 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_MASK 0x00002000 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_BB_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_BB_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_BB_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_BB_PWD_EN_LSB) & SOC_POWER_REG_WLAN_BB_PWD_EN_MASK) +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_MSB 12 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB 12 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK 0x00001000 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB) & SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK) +#define SOC_POWER_REG_CPU_INT_ENABLE_MSB 7 +#define SOC_POWER_REG_CPU_INT_ENABLE_LSB 7 +#define SOC_POWER_REG_CPU_INT_ENABLE_MASK 0x00000080 +#define SOC_POWER_REG_CPU_INT_ENABLE_GET(x) (((x) & SOC_POWER_REG_CPU_INT_ENABLE_MASK) >> SOC_POWER_REG_CPU_INT_ENABLE_LSB) +#define SOC_POWER_REG_CPU_INT_ENABLE_SET(x) (((x) << SOC_POWER_REG_CPU_INT_ENABLE_LSB) & SOC_POWER_REG_CPU_INT_ENABLE_MASK) +#define SOC_POWER_REG_WLAN_ISO_DIS_MSB 6 +#define SOC_POWER_REG_WLAN_ISO_DIS_LSB 6 +#define SOC_POWER_REG_WLAN_ISO_DIS_MASK 0x00000040 +#define SOC_POWER_REG_WLAN_ISO_DIS_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_DIS_MASK) >> SOC_POWER_REG_WLAN_ISO_DIS_LSB) +#define SOC_POWER_REG_WLAN_ISO_DIS_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_DIS_LSB) & SOC_POWER_REG_WLAN_ISO_DIS_MASK) +#define SOC_POWER_REG_WLAN_ISO_CNTL_MSB 5 +#define SOC_POWER_REG_WLAN_ISO_CNTL_LSB 5 +#define SOC_POWER_REG_WLAN_ISO_CNTL_MASK 0x00000020 +#define SOC_POWER_REG_WLAN_ISO_CNTL_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_CNTL_MASK) >> SOC_POWER_REG_WLAN_ISO_CNTL_LSB) +#define SOC_POWER_REG_WLAN_ISO_CNTL_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_CNTL_LSB) & SOC_POWER_REG_WLAN_ISO_CNTL_MASK) +#define SOC_POWER_REG_RADIO_PWD_EN_MSB 4 +#define SOC_POWER_REG_RADIO_PWD_EN_LSB 4 +#define SOC_POWER_REG_RADIO_PWD_EN_MASK 0x00000010 +#define SOC_POWER_REG_RADIO_PWD_EN_GET(x) (((x) & SOC_POWER_REG_RADIO_PWD_EN_MASK) >> SOC_POWER_REG_RADIO_PWD_EN_LSB) +#define SOC_POWER_REG_RADIO_PWD_EN_SET(x) (((x) << SOC_POWER_REG_RADIO_PWD_EN_LSB) & SOC_POWER_REG_RADIO_PWD_EN_MASK) +#define SOC_POWER_REG_SOC_ISO_EN_MSB 3 +#define SOC_POWER_REG_SOC_ISO_EN_LSB 3 +#define SOC_POWER_REG_SOC_ISO_EN_MASK 0x00000008 +#define SOC_POWER_REG_SOC_ISO_EN_GET(x) (((x) & SOC_POWER_REG_SOC_ISO_EN_MASK) >> SOC_POWER_REG_SOC_ISO_EN_LSB) +#define SOC_POWER_REG_SOC_ISO_EN_SET(x) (((x) << SOC_POWER_REG_SOC_ISO_EN_LSB) & SOC_POWER_REG_SOC_ISO_EN_MASK) +#define SOC_POWER_REG_WLAN_ISO_EN_MSB 2 +#define SOC_POWER_REG_WLAN_ISO_EN_LSB 2 +#define SOC_POWER_REG_WLAN_ISO_EN_MASK 0x00000004 +#define SOC_POWER_REG_WLAN_ISO_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_EN_MASK) >> SOC_POWER_REG_WLAN_ISO_EN_LSB) +#define SOC_POWER_REG_WLAN_ISO_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_EN_LSB) & SOC_POWER_REG_WLAN_ISO_EN_MASK) +#define SOC_POWER_REG_WLAN_PWD_EN_MSB 1 +#define SOC_POWER_REG_WLAN_PWD_EN_LSB 1 +#define SOC_POWER_REG_WLAN_PWD_EN_MASK 0x00000002 +#define SOC_POWER_REG_WLAN_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_PWD_EN_LSB) & SOC_POWER_REG_WLAN_PWD_EN_MASK) +#define SOC_POWER_REG_POWER_EN_MSB 0 +#define SOC_POWER_REG_POWER_EN_LSB 0 +#define SOC_POWER_REG_POWER_EN_MASK 0x00000001 +#define SOC_POWER_REG_POWER_EN_GET(x) (((x) & SOC_POWER_REG_POWER_EN_MASK) >> SOC_POWER_REG_POWER_EN_LSB) +#define SOC_POWER_REG_POWER_EN_SET(x) (((x) << SOC_POWER_REG_POWER_EN_LSB) & SOC_POWER_REG_POWER_EN_MASK) + +#define SOC_CORE_CLK_CTRL_ADDRESS 0x00000110 +#define SOC_CORE_CLK_CTRL_OFFSET 0x00000110 +#define SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define SOC_CORE_CLK_CTRL_DIV_GET(x) (((x) & SOC_CORE_CLK_CTRL_DIV_MASK) >> SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & SOC_CORE_CLK_CTRL_DIV_MASK) + +#define SOC_GPIO_WAKEUP_CONTROL_ADDRESS 0x00000114 +#define SOC_GPIO_WAKEUP_CONTROL_OFFSET 0x00000114 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_MSB 0 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB 0 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK 0x00000001 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_GET(x) (((x) & SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK) >> SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB) +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_SET(x) (((x) << SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB) & SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK) + +#define SLEEP_RETENTION_ADDRESS 0x00000214 +#define SLEEP_RETENTION_OFFSET 0x00000214 +#define SLEEP_RETENTION_GREEN_SAVE_MSB 10 +#define SLEEP_RETENTION_GREEN_SAVE_LSB 10 +#define SLEEP_RETENTION_GREEN_SAVE_MASK 0x00000400 +#define SLEEP_RETENTION_GREEN_SAVE_GET(x) (((x) & SLEEP_RETENTION_GREEN_SAVE_MASK) >> SLEEP_RETENTION_GREEN_SAVE_LSB) +#define SLEEP_RETENTION_GREEN_SAVE_SET(x) (((x) << SLEEP_RETENTION_GREEN_SAVE_LSB) & SLEEP_RETENTION_GREEN_SAVE_MASK) +#define SLEEP_RETENTION_TIME_MSB 9 +#define SLEEP_RETENTION_TIME_LSB 2 +#define SLEEP_RETENTION_TIME_MASK 0x000003fc +#define SLEEP_RETENTION_TIME_GET(x) (((x) & SLEEP_RETENTION_TIME_MASK) >> SLEEP_RETENTION_TIME_LSB) +#define SLEEP_RETENTION_TIME_SET(x) (((x) << SLEEP_RETENTION_TIME_LSB) & SLEEP_RETENTION_TIME_MASK) +#define SLEEP_RETENTION_MODE_MSB 1 +#define SLEEP_RETENTION_MODE_LSB 1 +#define SLEEP_RETENTION_MODE_MASK 0x00000002 +#define SLEEP_RETENTION_MODE_GET(x) (((x) & SLEEP_RETENTION_MODE_MASK) >> SLEEP_RETENTION_MODE_LSB) +#define SLEEP_RETENTION_MODE_SET(x) (((x) << SLEEP_RETENTION_MODE_LSB) & SLEEP_RETENTION_MODE_MASK) +#define SLEEP_RETENTION_ENABLE_MSB 0 +#define SLEEP_RETENTION_ENABLE_LSB 0 +#define SLEEP_RETENTION_ENABLE_MASK 0x00000001 +#define SLEEP_RETENTION_ENABLE_GET(x) (((x) & SLEEP_RETENTION_ENABLE_MASK) >> SLEEP_RETENTION_ENABLE_LSB) +#define SLEEP_RETENTION_ENABLE_SET(x) (((x) << SLEEP_RETENTION_ENABLE_LSB) & SLEEP_RETENTION_ENABLE_MASK) + +#define LP_PERF_COUNTER_ADDRESS 0x00000284 +#define LP_PERF_COUNTER_OFFSET 0x00000284 +#define LP_PERF_COUNTER_EN_MSB 0 +#define LP_PERF_COUNTER_EN_LSB 0 +#define LP_PERF_COUNTER_EN_MASK 0x00000001 +#define LP_PERF_COUNTER_EN_GET(x) (((x) & LP_PERF_COUNTER_EN_MASK) >> LP_PERF_COUNTER_EN_LSB) +#define LP_PERF_COUNTER_EN_SET(x) (((x) << LP_PERF_COUNTER_EN_LSB) & LP_PERF_COUNTER_EN_MASK) + +#define LP_PERF_LIGHT_SLEEP_ADDRESS 0x00000288 +#define LP_PERF_LIGHT_SLEEP_OFFSET 0x00000288 +#define LP_PERF_LIGHT_SLEEP_CNT_MSB 31 +#define LP_PERF_LIGHT_SLEEP_CNT_LSB 0 +#define LP_PERF_LIGHT_SLEEP_CNT_MASK 0xffffffff +#define LP_PERF_LIGHT_SLEEP_CNT_GET(x) (((x) & LP_PERF_LIGHT_SLEEP_CNT_MASK) >> LP_PERF_LIGHT_SLEEP_CNT_LSB) +#define LP_PERF_LIGHT_SLEEP_CNT_SET(x) (((x) << LP_PERF_LIGHT_SLEEP_CNT_LSB) & LP_PERF_LIGHT_SLEEP_CNT_MASK) + +#define LP_PERF_DEEP_SLEEP_ADDRESS 0x0000028c +#define LP_PERF_DEEP_SLEEP_OFFSET 0x0000028c +#define LP_PERF_DEEP_SLEEP_CNT_MSB 31 +#define LP_PERF_DEEP_SLEEP_CNT_LSB 0 +#define LP_PERF_DEEP_SLEEP_CNT_MASK 0xffffffff +#define LP_PERF_DEEP_SLEEP_CNT_GET(x) (((x) & LP_PERF_DEEP_SLEEP_CNT_MASK) >> LP_PERF_DEEP_SLEEP_CNT_LSB) +#define LP_PERF_DEEP_SLEEP_CNT_SET(x) (((x) << LP_PERF_DEEP_SLEEP_CNT_LSB) & LP_PERF_DEEP_SLEEP_CNT_MASK) + +#define LP_PERF_ON_ADDRESS 0x00000290 +#define LP_PERF_ON_OFFSET 0x00000290 +#define LP_PERF_ON_CNT_MSB 31 +#define LP_PERF_ON_CNT_LSB 0 +#define LP_PERF_ON_CNT_MASK 0xffffffff +#define LP_PERF_ON_CNT_GET(x) (((x) & LP_PERF_ON_CNT_MASK) >> LP_PERF_ON_CNT_LSB) +#define LP_PERF_ON_CNT_SET(x) (((x) << LP_PERF_ON_CNT_LSB) & LP_PERF_ON_CNT_MASK) + +#define CHIP_MODE_ADDRESS 0x000002a8 +#define CHIP_MODE_OFFSET 0x000002a8 +#define CHIP_MODE_BIT_MSB 1 +#define CHIP_MODE_BIT_LSB 0 +#define CHIP_MODE_BIT_MASK 0x00000003 +#define CHIP_MODE_BIT_GET(x) (((x) & CHIP_MODE_BIT_MASK) >> CHIP_MODE_BIT_LSB) +#define CHIP_MODE_BIT_SET(x) (((x) << CHIP_MODE_BIT_LSB) & CHIP_MODE_BIT_MASK) + +#define CLK_REQ_FALL_EDGE_ADDRESS 0x000002ac +#define CLK_REQ_FALL_EDGE_OFFSET 0x000002ac +#define CLK_REQ_FALL_EDGE_EN_MSB 31 +#define CLK_REQ_FALL_EDGE_EN_LSB 31 +#define CLK_REQ_FALL_EDGE_EN_MASK 0x80000000 +#define CLK_REQ_FALL_EDGE_EN_GET(x) (((x) & CLK_REQ_FALL_EDGE_EN_MASK) >> CLK_REQ_FALL_EDGE_EN_LSB) +#define CLK_REQ_FALL_EDGE_EN_SET(x) (((x) << CLK_REQ_FALL_EDGE_EN_LSB) & CLK_REQ_FALL_EDGE_EN_MASK) +#define CLK_REQ_FALL_EDGE_DELAY_MSB 7 +#define CLK_REQ_FALL_EDGE_DELAY_LSB 0 +#define CLK_REQ_FALL_EDGE_DELAY_MASK 0x000000ff +#define CLK_REQ_FALL_EDGE_DELAY_GET(x) (((x) & CLK_REQ_FALL_EDGE_DELAY_MASK) >> CLK_REQ_FALL_EDGE_DELAY_LSB) +#define CLK_REQ_FALL_EDGE_DELAY_SET(x) (((x) << CLK_REQ_FALL_EDGE_DELAY_LSB) & CLK_REQ_FALL_EDGE_DELAY_MASK) + +#define OTP_ADDRESS 0x000002b0 +#define OTP_OFFSET 0x000002b0 +#define OTP_LDO25_EN_MSB 1 +#define OTP_LDO25_EN_LSB 1 +#define OTP_LDO25_EN_MASK 0x00000002 +#define OTP_LDO25_EN_GET(x) (((x) & OTP_LDO25_EN_MASK) >> OTP_LDO25_EN_LSB) +#define OTP_LDO25_EN_SET(x) (((x) << OTP_LDO25_EN_LSB) & OTP_LDO25_EN_MASK) +#define OTP_VDD12_EN_MSB 0 +#define OTP_VDD12_EN_LSB 0 +#define OTP_VDD12_EN_MASK 0x00000001 +#define OTP_VDD12_EN_GET(x) (((x) & OTP_VDD12_EN_MASK) >> OTP_VDD12_EN_LSB) +#define OTP_VDD12_EN_SET(x) (((x) << OTP_VDD12_EN_LSB) & OTP_VDD12_EN_MASK) + +#define OTP_STATUS_ADDRESS 0x000002b4 +#define OTP_STATUS_OFFSET 0x000002b4 +#define OTP_STATUS_LDO25_EN_READY_MSB 1 +#define OTP_STATUS_LDO25_EN_READY_LSB 1 +#define OTP_STATUS_LDO25_EN_READY_MASK 0x00000002 +#define OTP_STATUS_LDO25_EN_READY_GET(x) (((x) & OTP_STATUS_LDO25_EN_READY_MASK) >> OTP_STATUS_LDO25_EN_READY_LSB) +#define OTP_STATUS_LDO25_EN_READY_SET(x) (((x) << OTP_STATUS_LDO25_EN_READY_LSB) & OTP_STATUS_LDO25_EN_READY_MASK) +#define OTP_STATUS_VDD12_EN_READY_MSB 0 +#define OTP_STATUS_VDD12_EN_READY_LSB 0 +#define OTP_STATUS_VDD12_EN_READY_MASK 0x00000001 +#define OTP_STATUS_VDD12_EN_READY_GET(x) (((x) & OTP_STATUS_VDD12_EN_READY_MASK) >> OTP_STATUS_VDD12_EN_READY_LSB) +#define OTP_STATUS_VDD12_EN_READY_SET(x) (((x) << OTP_STATUS_VDD12_EN_READY_LSB) & OTP_STATUS_VDD12_EN_READY_MASK) + +#define PMU_ADDRESS 0x000002b8 +#define PMU_OFFSET 0x000002b8 +#define PMU_REG_WAKEUP_TIME_SEL_MSB 1 +#define PMU_REG_WAKEUP_TIME_SEL_LSB 0 +#define PMU_REG_WAKEUP_TIME_SEL_MASK 0x00000003 +#define PMU_REG_WAKEUP_TIME_SEL_GET(x) (((x) & PMU_REG_WAKEUP_TIME_SEL_MASK) >> PMU_REG_WAKEUP_TIME_SEL_LSB) +#define PMU_REG_WAKEUP_TIME_SEL_SET(x) (((x) << PMU_REG_WAKEUP_TIME_SEL_LSB) & PMU_REG_WAKEUP_TIME_SEL_MASK) + +#define PMU_CONFIG_ADDRESS 0x000002bc +#define PMU_CONFIG_OFFSET 0x000002bc +#define PMU_CONFIG_VALUE_MSB 4 +#define PMU_CONFIG_VALUE_LSB 0 +#define PMU_CONFIG_VALUE_MASK 0x0000001f +#define PMU_CONFIG_VALUE_GET(x) (((x) & PMU_CONFIG_VALUE_MASK) >> PMU_CONFIG_VALUE_LSB) +#define PMU_CONFIG_VALUE_SET(x) (((x) << PMU_CONFIG_VALUE_LSB) & PMU_CONFIG_VALUE_MASK) + +#define PMU_PAREG_ADDRESS 0x000002c0 +#define PMU_PAREG_OFFSET 0x000002c0 +#define PMU_PAREG_LVL_CTR_MSB 2 +#define PMU_PAREG_LVL_CTR_LSB 0 +#define PMU_PAREG_LVL_CTR_MASK 0x00000007 +#define PMU_PAREG_LVL_CTR_GET(x) (((x) & PMU_PAREG_LVL_CTR_MASK) >> PMU_PAREG_LVL_CTR_LSB) +#define PMU_PAREG_LVL_CTR_SET(x) (((x) << PMU_PAREG_LVL_CTR_LSB) & PMU_PAREG_LVL_CTR_MASK) + +#define PMU_BYPASS_ADDRESS 0x000002c4 +#define PMU_BYPASS_OFFSET 0x000002c4 +#define PMU_BYPASS_SWREG_MSB 2 +#define PMU_BYPASS_SWREG_LSB 2 +#define PMU_BYPASS_SWREG_MASK 0x00000004 +#define PMU_BYPASS_SWREG_GET(x) (((x) & PMU_BYPASS_SWREG_MASK) >> PMU_BYPASS_SWREG_LSB) +#define PMU_BYPASS_SWREG_SET(x) (((x) << PMU_BYPASS_SWREG_LSB) & PMU_BYPASS_SWREG_MASK) +#define PMU_BYPASS_DREG_MSB 1 +#define PMU_BYPASS_DREG_LSB 1 +#define PMU_BYPASS_DREG_MASK 0x00000002 +#define PMU_BYPASS_DREG_GET(x) (((x) & PMU_BYPASS_DREG_MASK) >> PMU_BYPASS_DREG_LSB) +#define PMU_BYPASS_DREG_SET(x) (((x) << PMU_BYPASS_DREG_LSB) & PMU_BYPASS_DREG_MASK) +#define PMU_BYPASS_PAREG_MSB 0 +#define PMU_BYPASS_PAREG_LSB 0 +#define PMU_BYPASS_PAREG_MASK 0x00000001 +#define PMU_BYPASS_PAREG_GET(x) (((x) & PMU_BYPASS_PAREG_MASK) >> PMU_BYPASS_PAREG_LSB) +#define PMU_BYPASS_PAREG_SET(x) (((x) << PMU_BYPASS_PAREG_LSB) & PMU_BYPASS_PAREG_MASK) + +#define THERM_CTRL1_ADDRESS 0x000002dc +#define THERM_CTRL1_OFFSET 0x000002dc +#define THERM_CTRL1_BYPASS_MSB 16 +#define THERM_CTRL1_BYPASS_LSB 16 +#define THERM_CTRL1_BYPASS_MASK 0x00010000 +#define THERM_CTRL1_BYPASS_GET(x) (((x) & THERM_CTRL1_BYPASS_MASK) >> THERM_CTRL1_BYPASS_LSB) +#define THERM_CTRL1_BYPASS_SET(x) (((x) << THERM_CTRL1_BYPASS_LSB) & THERM_CTRL1_BYPASS_MASK) +#define THERM_CTRL1_WIDTH_ARBITOR_MSB 15 +#define THERM_CTRL1_WIDTH_ARBITOR_LSB 12 +#define THERM_CTRL1_WIDTH_ARBITOR_MASK 0x0000f000 +#define THERM_CTRL1_WIDTH_ARBITOR_GET(x) (((x) & THERM_CTRL1_WIDTH_ARBITOR_MASK) >> THERM_CTRL1_WIDTH_ARBITOR_LSB) +#define THERM_CTRL1_WIDTH_ARBITOR_SET(x) (((x) << THERM_CTRL1_WIDTH_ARBITOR_LSB) & THERM_CTRL1_WIDTH_ARBITOR_MASK) +#define THERM_CTRL1_WIDTH_MSB 11 +#define THERM_CTRL1_WIDTH_LSB 5 +#define THERM_CTRL1_WIDTH_MASK 0x00000fe0 +#define THERM_CTRL1_WIDTH_GET(x) (((x) & THERM_CTRL1_WIDTH_MASK) >> THERM_CTRL1_WIDTH_LSB) +#define THERM_CTRL1_WIDTH_SET(x) (((x) << THERM_CTRL1_WIDTH_LSB) & THERM_CTRL1_WIDTH_MASK) +#define THERM_CTRL1_TYPE_MSB 4 +#define THERM_CTRL1_TYPE_LSB 3 +#define THERM_CTRL1_TYPE_MASK 0x00000018 +#define THERM_CTRL1_TYPE_GET(x) (((x) & THERM_CTRL1_TYPE_MASK) >> THERM_CTRL1_TYPE_LSB) +#define THERM_CTRL1_TYPE_SET(x) (((x) << THERM_CTRL1_TYPE_LSB) & THERM_CTRL1_TYPE_MASK) +#define THERM_CTRL1_MEASURE_MSB 2 +#define THERM_CTRL1_MEASURE_LSB 2 +#define THERM_CTRL1_MEASURE_MASK 0x00000004 +#define THERM_CTRL1_MEASURE_GET(x) (((x) & THERM_CTRL1_MEASURE_MASK) >> THERM_CTRL1_MEASURE_LSB) +#define THERM_CTRL1_MEASURE_SET(x) (((x) << THERM_CTRL1_MEASURE_LSB) & THERM_CTRL1_MEASURE_MASK) +#define THERM_CTRL1_INT_EN_MSB 1 +#define THERM_CTRL1_INT_EN_LSB 1 +#define THERM_CTRL1_INT_EN_MASK 0x00000002 +#define THERM_CTRL1_INT_EN_GET(x) (((x) & THERM_CTRL1_INT_EN_MASK) >> THERM_CTRL1_INT_EN_LSB) +#define THERM_CTRL1_INT_EN_SET(x) (((x) << THERM_CTRL1_INT_EN_LSB) & THERM_CTRL1_INT_EN_MASK) +#define THERM_CTRL1_INT_STATUS_MSB 0 +#define THERM_CTRL1_INT_STATUS_LSB 0 +#define THERM_CTRL1_INT_STATUS_MASK 0x00000001 +#define THERM_CTRL1_INT_STATUS_GET(x) (((x) & THERM_CTRL1_INT_STATUS_MASK) >> THERM_CTRL1_INT_STATUS_LSB) +#define THERM_CTRL1_INT_STATUS_SET(x) (((x) << THERM_CTRL1_INT_STATUS_LSB) & THERM_CTRL1_INT_STATUS_MASK) + +#define THERM_CTRL2_ADDRESS 0x000002e0 +#define THERM_CTRL2_OFFSET 0x000002e0 +#define THERM_CTRL2_ADC_OFF_MSB 25 +#define THERM_CTRL2_ADC_OFF_LSB 25 +#define THERM_CTRL2_ADC_OFF_MASK 0x02000000 +#define THERM_CTRL2_ADC_OFF_GET(x) (((x) & THERM_CTRL2_ADC_OFF_MASK) >> THERM_CTRL2_ADC_OFF_LSB) +#define THERM_CTRL2_ADC_OFF_SET(x) (((x) << THERM_CTRL2_ADC_OFF_LSB) & THERM_CTRL2_ADC_OFF_MASK) +#define THERM_CTRL2_ADC_ON_MSB 24 +#define THERM_CTRL2_ADC_ON_LSB 24 +#define THERM_CTRL2_ADC_ON_MASK 0x01000000 +#define THERM_CTRL2_ADC_ON_GET(x) (((x) & THERM_CTRL2_ADC_ON_MASK) >> THERM_CTRL2_ADC_ON_LSB) +#define THERM_CTRL2_ADC_ON_SET(x) (((x) << THERM_CTRL2_ADC_ON_LSB) & THERM_CTRL2_ADC_ON_MASK) +#define THERM_CTRL2_SAMPLE_MSB 23 +#define THERM_CTRL2_SAMPLE_LSB 16 +#define THERM_CTRL2_SAMPLE_MASK 0x00ff0000 +#define THERM_CTRL2_SAMPLE_GET(x) (((x) & THERM_CTRL2_SAMPLE_MASK) >> THERM_CTRL2_SAMPLE_LSB) +#define THERM_CTRL2_SAMPLE_SET(x) (((x) << THERM_CTRL2_SAMPLE_LSB) & THERM_CTRL2_SAMPLE_MASK) +#define THERM_CTRL2_HIGH_MSB 15 +#define THERM_CTRL2_HIGH_LSB 8 +#define THERM_CTRL2_HIGH_MASK 0x0000ff00 +#define THERM_CTRL2_HIGH_GET(x) (((x) & THERM_CTRL2_HIGH_MASK) >> THERM_CTRL2_HIGH_LSB) +#define THERM_CTRL2_HIGH_SET(x) (((x) << THERM_CTRL2_HIGH_LSB) & THERM_CTRL2_HIGH_MASK) +#define THERM_CTRL2_LOW_MSB 7 +#define THERM_CTRL2_LOW_LSB 0 +#define THERM_CTRL2_LOW_MASK 0x000000ff +#define THERM_CTRL2_LOW_GET(x) (((x) & THERM_CTRL2_LOW_MASK) >> THERM_CTRL2_LOW_LSB) +#define THERM_CTRL2_LOW_SET(x) (((x) << THERM_CTRL2_LOW_LSB) & THERM_CTRL2_LOW_MASK) + +#define THERM_CTRL3_ADDRESS 0x000002e4 +#define THERM_CTRL3_OFFSET 0x000002e4 +#define THERM_CTRL3_ADC_GAIN_MSB 16 +#define THERM_CTRL3_ADC_GAIN_LSB 8 +#define THERM_CTRL3_ADC_GAIN_MASK 0x0001ff00 +#define THERM_CTRL3_ADC_GAIN_GET(x) (((x) & THERM_CTRL3_ADC_GAIN_MASK) >> THERM_CTRL3_ADC_GAIN_LSB) +#define THERM_CTRL3_ADC_GAIN_SET(x) (((x) << THERM_CTRL3_ADC_GAIN_LSB) & THERM_CTRL3_ADC_GAIN_MASK) +#define THERM_CTRL3_ADC_OFFSET_MSB 7 +#define THERM_CTRL3_ADC_OFFSET_LSB 0 +#define THERM_CTRL3_ADC_OFFSET_MASK 0x000000ff +#define THERM_CTRL3_ADC_OFFSET_GET(x) (((x) & THERM_CTRL3_ADC_OFFSET_MASK) >> THERM_CTRL3_ADC_OFFSET_LSB) +#define THERM_CTRL3_ADC_OFFSET_SET(x) (((x) << THERM_CTRL3_ADC_OFFSET_LSB) & THERM_CTRL3_ADC_OFFSET_MASK) + +#define LISTEN_MODE1_ADDRESS 0x000002e8 +#define LISTEN_MODE1_OFFSET 0x000002e8 +#define LISTEN_MODE1_TIMER_CLEAR_MSB 19 +#define LISTEN_MODE1_TIMER_CLEAR_LSB 19 +#define LISTEN_MODE1_TIMER_CLEAR_MASK 0x00080000 +#define LISTEN_MODE1_TIMER_CLEAR_GET(x) (((x) & LISTEN_MODE1_TIMER_CLEAR_MASK) >> LISTEN_MODE1_TIMER_CLEAR_LSB) +#define LISTEN_MODE1_TIMER_CLEAR_SET(x) (((x) << LISTEN_MODE1_TIMER_CLEAR_LSB) & LISTEN_MODE1_TIMER_CLEAR_MASK) +#define LISTEN_MODE1_TIMER_THRESH_WAKE_MSB 18 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_LSB 3 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_MASK 0x0007fff8 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_GET(x) (((x) & LISTEN_MODE1_TIMER_THRESH_WAKE_MASK) >> LISTEN_MODE1_TIMER_THRESH_WAKE_LSB) +#define LISTEN_MODE1_TIMER_THRESH_WAKE_SET(x) (((x) << LISTEN_MODE1_TIMER_THRESH_WAKE_LSB) & LISTEN_MODE1_TIMER_THRESH_WAKE_MASK) +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MSB 2 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB 2 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK 0x00000004 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_GET(x) (((x) & LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK) >> LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB) +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_SET(x) (((x) << LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB) & LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK) +#define LISTEN_MODE1_CLOCK_GATE_MSB 1 +#define LISTEN_MODE1_CLOCK_GATE_LSB 1 +#define LISTEN_MODE1_CLOCK_GATE_MASK 0x00000002 +#define LISTEN_MODE1_CLOCK_GATE_GET(x) (((x) & LISTEN_MODE1_CLOCK_GATE_MASK) >> LISTEN_MODE1_CLOCK_GATE_LSB) +#define LISTEN_MODE1_CLOCK_GATE_SET(x) (((x) << LISTEN_MODE1_CLOCK_GATE_LSB) & LISTEN_MODE1_CLOCK_GATE_MASK) +#define LISTEN_MODE1_ENABLE_MSB 0 +#define LISTEN_MODE1_ENABLE_LSB 0 +#define LISTEN_MODE1_ENABLE_MASK 0x00000001 +#define LISTEN_MODE1_ENABLE_GET(x) (((x) & LISTEN_MODE1_ENABLE_MASK) >> LISTEN_MODE1_ENABLE_LSB) +#define LISTEN_MODE1_ENABLE_SET(x) (((x) << LISTEN_MODE1_ENABLE_LSB) & LISTEN_MODE1_ENABLE_MASK) + +#define LISTEN_MODE2_ADDRESS 0x000002ec +#define LISTEN_MODE2_OFFSET 0x000002ec +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_MSB 15 +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB 0 +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK 0x0000ffff +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_GET(x) (((x) & LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK) >> LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB) +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_SET(x) (((x) << LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB) & LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK) + +#define AUDIO_PLL_CONFIG_ADDRESS 0x000002f0 +#define AUDIO_PLL_CONFIG_OFFSET 0x000002f0 +#define AUDIO_PLL_CONFIG_UPDATING_MSB 31 +#define AUDIO_PLL_CONFIG_UPDATING_LSB 31 +#define AUDIO_PLL_CONFIG_UPDATING_MASK 0x80000000 +#define AUDIO_PLL_CONFIG_UPDATING_GET(x) (((x) & AUDIO_PLL_CONFIG_UPDATING_MASK) >> AUDIO_PLL_CONFIG_UPDATING_LSB) +#define AUDIO_PLL_CONFIG_UPDATING_SET(x) (((x) << AUDIO_PLL_CONFIG_UPDATING_LSB) & AUDIO_PLL_CONFIG_UPDATING_MASK) +#define AUDIO_PLL_CONFIG_EXT_DIV_MSB 14 +#define AUDIO_PLL_CONFIG_EXT_DIV_LSB 12 +#define AUDIO_PLL_CONFIG_EXT_DIV_MASK 0x00007000 +#define AUDIO_PLL_CONFIG_EXT_DIV_GET(x) (((x) & AUDIO_PLL_CONFIG_EXT_DIV_MASK) >> AUDIO_PLL_CONFIG_EXT_DIV_LSB) +#define AUDIO_PLL_CONFIG_EXT_DIV_SET(x) (((x) << AUDIO_PLL_CONFIG_EXT_DIV_LSB) & AUDIO_PLL_CONFIG_EXT_DIV_MASK) +#define AUDIO_PLL_CONFIG_POSTPLLDIV_MSB 9 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_LSB 7 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_MASK 0x00000380 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_GET(x) (((x) & AUDIO_PLL_CONFIG_POSTPLLDIV_MASK) >> AUDIO_PLL_CONFIG_POSTPLLDIV_LSB) +#define AUDIO_PLL_CONFIG_POSTPLLDIV_SET(x) (((x) << AUDIO_PLL_CONFIG_POSTPLLDIV_LSB) & AUDIO_PLL_CONFIG_POSTPLLDIV_MASK) +#define AUDIO_PLL_CONFIG_PLLPWD_MSB 5 +#define AUDIO_PLL_CONFIG_PLLPWD_LSB 5 +#define AUDIO_PLL_CONFIG_PLLPWD_MASK 0x00000020 +#define AUDIO_PLL_CONFIG_PLLPWD_GET(x) (((x) & AUDIO_PLL_CONFIG_PLLPWD_MASK) >> AUDIO_PLL_CONFIG_PLLPWD_LSB) +#define AUDIO_PLL_CONFIG_PLLPWD_SET(x) (((x) << AUDIO_PLL_CONFIG_PLLPWD_LSB) & AUDIO_PLL_CONFIG_PLLPWD_MASK) +#define AUDIO_PLL_CONFIG_BYPASS_MSB 4 +#define AUDIO_PLL_CONFIG_BYPASS_LSB 4 +#define AUDIO_PLL_CONFIG_BYPASS_MASK 0x00000010 +#define AUDIO_PLL_CONFIG_BYPASS_GET(x) (((x) & AUDIO_PLL_CONFIG_BYPASS_MASK) >> AUDIO_PLL_CONFIG_BYPASS_LSB) +#define AUDIO_PLL_CONFIG_BYPASS_SET(x) (((x) << AUDIO_PLL_CONFIG_BYPASS_LSB) & AUDIO_PLL_CONFIG_BYPASS_MASK) +#define AUDIO_PLL_CONFIG_REFDIV_MSB 3 +#define AUDIO_PLL_CONFIG_REFDIV_LSB 0 +#define AUDIO_PLL_CONFIG_REFDIV_MASK 0x0000000f +#define AUDIO_PLL_CONFIG_REFDIV_GET(x) (((x) & AUDIO_PLL_CONFIG_REFDIV_MASK) >> AUDIO_PLL_CONFIG_REFDIV_LSB) +#define AUDIO_PLL_CONFIG_REFDIV_SET(x) (((x) << AUDIO_PLL_CONFIG_REFDIV_LSB) & AUDIO_PLL_CONFIG_REFDIV_MASK) + +#define AUDIO_PLL_MODULATION_ADDRESS 0x000002f4 +#define AUDIO_PLL_MODULATION_OFFSET 0x000002f4 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MSB 28 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB 11 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK 0x1ffff800 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_GET(x) (((x) & AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK) >> AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB) +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_SET(x) (((x) << AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB) & AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK) +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_MSB 6 +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB 1 +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK 0x0000007e +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_GET(x) (((x) & AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK) >> AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB) +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_SET(x) (((x) << AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB) & AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK) +#define AUDIO_PLL_MODULATION_START_MSB 0 +#define AUDIO_PLL_MODULATION_START_LSB 0 +#define AUDIO_PLL_MODULATION_START_MASK 0x00000001 +#define AUDIO_PLL_MODULATION_START_GET(x) (((x) & AUDIO_PLL_MODULATION_START_MASK) >> AUDIO_PLL_MODULATION_START_LSB) +#define AUDIO_PLL_MODULATION_START_SET(x) (((x) << AUDIO_PLL_MODULATION_START_LSB) & AUDIO_PLL_MODULATION_START_MASK) + +#define AUDIO_PLL_MOD_STEP_ADDRESS 0x000002f8 +#define AUDIO_PLL_MOD_STEP_OFFSET 0x000002f8 +#define AUDIO_PLL_MOD_STEP_FRAC_MSB 31 +#define AUDIO_PLL_MOD_STEP_FRAC_LSB 14 +#define AUDIO_PLL_MOD_STEP_FRAC_MASK 0xffffc000 +#define AUDIO_PLL_MOD_STEP_FRAC_GET(x) (((x) & AUDIO_PLL_MOD_STEP_FRAC_MASK) >> AUDIO_PLL_MOD_STEP_FRAC_LSB) +#define AUDIO_PLL_MOD_STEP_FRAC_SET(x) (((x) << AUDIO_PLL_MOD_STEP_FRAC_LSB) & AUDIO_PLL_MOD_STEP_FRAC_MASK) +#define AUDIO_PLL_MOD_STEP_INT_MSB 13 +#define AUDIO_PLL_MOD_STEP_INT_LSB 4 +#define AUDIO_PLL_MOD_STEP_INT_MASK 0x00003ff0 +#define AUDIO_PLL_MOD_STEP_INT_GET(x) (((x) & AUDIO_PLL_MOD_STEP_INT_MASK) >> AUDIO_PLL_MOD_STEP_INT_LSB) +#define AUDIO_PLL_MOD_STEP_INT_SET(x) (((x) << AUDIO_PLL_MOD_STEP_INT_LSB) & AUDIO_PLL_MOD_STEP_INT_MASK) +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_MSB 3 +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB 0 +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK 0x0000000f +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_GET(x) (((x) & AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK) >> AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB) +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_SET(x) (((x) << AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB) & AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK) + +#define CURRENT_AUDIO_PLL_MODULATION_ADDRESS 0x000002fc +#define CURRENT_AUDIO_PLL_MODULATION_OFFSET 0x000002fc +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_MSB 27 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB 10 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK 0x0ffffc00 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_GET(x) (((x) & CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK) >> CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB) +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_SET(x) (((x) << CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB) & CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK) +#define CURRENT_AUDIO_PLL_MODULATION_INT_MSB 6 +#define CURRENT_AUDIO_PLL_MODULATION_INT_LSB 1 +#define CURRENT_AUDIO_PLL_MODULATION_INT_MASK 0x0000007e +#define CURRENT_AUDIO_PLL_MODULATION_INT_GET(x) (((x) & CURRENT_AUDIO_PLL_MODULATION_INT_MASK) >> CURRENT_AUDIO_PLL_MODULATION_INT_LSB) +#define CURRENT_AUDIO_PLL_MODULATION_INT_SET(x) (((x) << CURRENT_AUDIO_PLL_MODULATION_INT_LSB) & CURRENT_AUDIO_PLL_MODULATION_INT_MASK) + +#define ETH_PLL_CONFIG_ADDRESS 0x00000300 +#define ETH_PLL_CONFIG_OFFSET 0x00000300 +#define ETH_PLL_CONFIG_GE0_MASTER_MSB 30 +#define ETH_PLL_CONFIG_GE0_MASTER_LSB 30 +#define ETH_PLL_CONFIG_GE0_MASTER_MASK 0x40000000 +#define ETH_PLL_CONFIG_GE0_MASTER_GET(x) (((x) & ETH_PLL_CONFIG_GE0_MASTER_MASK) >> ETH_PLL_CONFIG_GE0_MASTER_LSB) +#define ETH_PLL_CONFIG_GE0_MASTER_SET(x) (((x) << ETH_PLL_CONFIG_GE0_MASTER_LSB) & ETH_PLL_CONFIG_GE0_MASTER_MASK) +#define ETH_PLL_CONFIG_GE0_MSB 29 +#define ETH_PLL_CONFIG_GE0_LSB 29 +#define ETH_PLL_CONFIG_GE0_MASK 0x20000000 +#define ETH_PLL_CONFIG_GE0_GET(x) (((x) & ETH_PLL_CONFIG_GE0_MASK) >> ETH_PLL_CONFIG_GE0_LSB) +#define ETH_PLL_CONFIG_GE0_SET(x) (((x) << ETH_PLL_CONFIG_GE0_LSB) & ETH_PLL_CONFIG_GE0_MASK) +#define ETH_PLL_CONFIG_RANGE_MSB 28 +#define ETH_PLL_CONFIG_RANGE_LSB 28 +#define ETH_PLL_CONFIG_RANGE_MASK 0x10000000 +#define ETH_PLL_CONFIG_RANGE_GET(x) (((x) & ETH_PLL_CONFIG_RANGE_MASK) >> ETH_PLL_CONFIG_RANGE_LSB) +#define ETH_PLL_CONFIG_RANGE_SET(x) (((x) << ETH_PLL_CONFIG_RANGE_LSB) & ETH_PLL_CONFIG_RANGE_MASK) +#define ETH_PLL_CONFIG_FRAC_MSB 27 +#define ETH_PLL_CONFIG_FRAC_LSB 18 +#define ETH_PLL_CONFIG_FRAC_MASK 0x0ffc0000 +#define ETH_PLL_CONFIG_FRAC_GET(x) (((x) & ETH_PLL_CONFIG_FRAC_MASK) >> ETH_PLL_CONFIG_FRAC_LSB) +#define ETH_PLL_CONFIG_FRAC_SET(x) (((x) << ETH_PLL_CONFIG_FRAC_LSB) & ETH_PLL_CONFIG_FRAC_MASK) +#define ETH_PLL_CONFIG_INT_MSB 17 +#define ETH_PLL_CONFIG_INT_LSB 12 +#define ETH_PLL_CONFIG_INT_MASK 0x0003f000 +#define ETH_PLL_CONFIG_INT_GET(x) (((x) & ETH_PLL_CONFIG_INT_MASK) >> ETH_PLL_CONFIG_INT_LSB) +#define ETH_PLL_CONFIG_INT_SET(x) (((x) << ETH_PLL_CONFIG_INT_LSB) & ETH_PLL_CONFIG_INT_MASK) +#define ETH_PLL_CONFIG_OUTDIV_MSB 9 +#define ETH_PLL_CONFIG_OUTDIV_LSB 7 +#define ETH_PLL_CONFIG_OUTDIV_MASK 0x00000380 +#define ETH_PLL_CONFIG_OUTDIV_GET(x) (((x) & ETH_PLL_CONFIG_OUTDIV_MASK) >> ETH_PLL_CONFIG_OUTDIV_LSB) +#define ETH_PLL_CONFIG_OUTDIV_SET(x) (((x) << ETH_PLL_CONFIG_OUTDIV_LSB) & ETH_PLL_CONFIG_OUTDIV_MASK) +#define ETH_PLL_CONFIG_PLLPWD_MSB 6 +#define ETH_PLL_CONFIG_PLLPWD_LSB 6 +#define ETH_PLL_CONFIG_PLLPWD_MASK 0x00000040 +#define ETH_PLL_CONFIG_PLLPWD_GET(x) (((x) & ETH_PLL_CONFIG_PLLPWD_MASK) >> ETH_PLL_CONFIG_PLLPWD_LSB) +#define ETH_PLL_CONFIG_PLLPWD_SET(x) (((x) << ETH_PLL_CONFIG_PLLPWD_LSB) & ETH_PLL_CONFIG_PLLPWD_MASK) +#define ETH_PLL_CONFIG_BYPASS_MSB 5 +#define ETH_PLL_CONFIG_BYPASS_LSB 5 +#define ETH_PLL_CONFIG_BYPASS_MASK 0x00000020 +#define ETH_PLL_CONFIG_BYPASS_GET(x) (((x) & ETH_PLL_CONFIG_BYPASS_MASK) >> ETH_PLL_CONFIG_BYPASS_LSB) +#define ETH_PLL_CONFIG_BYPASS_SET(x) (((x) << ETH_PLL_CONFIG_BYPASS_LSB) & ETH_PLL_CONFIG_BYPASS_MASK) +#define ETH_PLL_CONFIG_REFDIV_MSB 4 +#define ETH_PLL_CONFIG_REFDIV_LSB 0 +#define ETH_PLL_CONFIG_REFDIV_MASK 0x0000001f +#define ETH_PLL_CONFIG_REFDIV_GET(x) (((x) & ETH_PLL_CONFIG_REFDIV_MASK) >> ETH_PLL_CONFIG_REFDIV_LSB) +#define ETH_PLL_CONFIG_REFDIV_SET(x) (((x) << ETH_PLL_CONFIG_REFDIV_LSB) & ETH_PLL_CONFIG_REFDIV_MASK) + +#define CPU_PLL_CONFIG_ADDRESS 0x00000304 +#define CPU_PLL_CONFIG_OFFSET 0x00000304 +#define CPU_PLL_CONFIG_RANGE_MSB 28 +#define CPU_PLL_CONFIG_RANGE_LSB 28 +#define CPU_PLL_CONFIG_RANGE_MASK 0x10000000 +#define CPU_PLL_CONFIG_RANGE_GET(x) (((x) & CPU_PLL_CONFIG_RANGE_MASK) >> CPU_PLL_CONFIG_RANGE_LSB) +#define CPU_PLL_CONFIG_RANGE_SET(x) (((x) << CPU_PLL_CONFIG_RANGE_LSB) & CPU_PLL_CONFIG_RANGE_MASK) +#define CPU_PLL_CONFIG_FRAC_MSB 25 +#define CPU_PLL_CONFIG_FRAC_LSB 20 +#define CPU_PLL_CONFIG_FRAC_MASK 0x03f00000 +#define CPU_PLL_CONFIG_FRAC_GET(x) (((x) & CPU_PLL_CONFIG_FRAC_MASK) >> CPU_PLL_CONFIG_FRAC_LSB) +#define CPU_PLL_CONFIG_FRAC_SET(x) (((x) << CPU_PLL_CONFIG_FRAC_LSB) & CPU_PLL_CONFIG_FRAC_MASK) +#define CPU_PLL_CONFIG_INT_MSB 17 +#define CPU_PLL_CONFIG_INT_LSB 12 +#define CPU_PLL_CONFIG_INT_MASK 0x0003f000 +#define CPU_PLL_CONFIG_INT_GET(x) (((x) & CPU_PLL_CONFIG_INT_MASK) >> CPU_PLL_CONFIG_INT_LSB) +#define CPU_PLL_CONFIG_INT_SET(x) (((x) << CPU_PLL_CONFIG_INT_LSB) & CPU_PLL_CONFIG_INT_MASK) +#define CPU_PLL_CONFIG_OUTDIV_MSB 9 +#define CPU_PLL_CONFIG_OUTDIV_LSB 7 +#define CPU_PLL_CONFIG_OUTDIV_MASK 0x00000380 +#define CPU_PLL_CONFIG_OUTDIV_GET(x) (((x) & CPU_PLL_CONFIG_OUTDIV_MASK) >> CPU_PLL_CONFIG_OUTDIV_LSB) +#define CPU_PLL_CONFIG_OUTDIV_SET(x) (((x) << CPU_PLL_CONFIG_OUTDIV_LSB) & CPU_PLL_CONFIG_OUTDIV_MASK) +#define CPU_PLL_CONFIG_PLLPWD_MSB 6 +#define CPU_PLL_CONFIG_PLLPWD_LSB 6 +#define CPU_PLL_CONFIG_PLLPWD_MASK 0x00000040 +#define CPU_PLL_CONFIG_PLLPWD_GET(x) (((x) & CPU_PLL_CONFIG_PLLPWD_MASK) >> CPU_PLL_CONFIG_PLLPWD_LSB) +#define CPU_PLL_CONFIG_PLLPWD_SET(x) (((x) << CPU_PLL_CONFIG_PLLPWD_LSB) & CPU_PLL_CONFIG_PLLPWD_MASK) +#define CPU_PLL_CONFIG_REFDIV_MSB 4 +#define CPU_PLL_CONFIG_REFDIV_LSB 0 +#define CPU_PLL_CONFIG_REFDIV_MASK 0x0000001f +#define CPU_PLL_CONFIG_REFDIV_GET(x) (((x) & CPU_PLL_CONFIG_REFDIV_MASK) >> CPU_PLL_CONFIG_REFDIV_LSB) +#define CPU_PLL_CONFIG_REFDIV_SET(x) (((x) << CPU_PLL_CONFIG_REFDIV_LSB) & CPU_PLL_CONFIG_REFDIV_MASK) + +#define BB_PLL_CONFIG_ADDRESS 0x00000308 +#define BB_PLL_CONFIG_OFFSET 0x00000308 +#define BB_PLL_CONFIG_FRAC_MSB 17 +#define BB_PLL_CONFIG_FRAC_LSB 0 +#define BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define BB_PLL_CONFIG_FRAC_GET(x) (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) + +#define ETH_XMII_ADDRESS 0x0000030c +#define ETH_XMII_OFFSET 0x0000030c +#define ETH_XMII_TX_INVERT_MSB 31 +#define ETH_XMII_TX_INVERT_LSB 31 +#define ETH_XMII_TX_INVERT_MASK 0x80000000 +#define ETH_XMII_TX_INVERT_GET(x) (((x) & ETH_XMII_TX_INVERT_MASK) >> ETH_XMII_TX_INVERT_LSB) +#define ETH_XMII_TX_INVERT_SET(x) (((x) << ETH_XMII_TX_INVERT_LSB) & ETH_XMII_TX_INVERT_MASK) +#define ETH_XMII_GIGE_QUAD_MSB 30 +#define ETH_XMII_GIGE_QUAD_LSB 30 +#define ETH_XMII_GIGE_QUAD_MASK 0x40000000 +#define ETH_XMII_GIGE_QUAD_GET(x) (((x) & ETH_XMII_GIGE_QUAD_MASK) >> ETH_XMII_GIGE_QUAD_LSB) +#define ETH_XMII_GIGE_QUAD_SET(x) (((x) << ETH_XMII_GIGE_QUAD_LSB) & ETH_XMII_GIGE_QUAD_MASK) +#define ETH_XMII_RX_DELAY_MSB 29 +#define ETH_XMII_RX_DELAY_LSB 28 +#define ETH_XMII_RX_DELAY_MASK 0x30000000 +#define ETH_XMII_RX_DELAY_GET(x) (((x) & ETH_XMII_RX_DELAY_MASK) >> ETH_XMII_RX_DELAY_LSB) +#define ETH_XMII_RX_DELAY_SET(x) (((x) << ETH_XMII_RX_DELAY_LSB) & ETH_XMII_RX_DELAY_MASK) +#define ETH_XMII_TX_DELAY_MSB 27 +#define ETH_XMII_TX_DELAY_LSB 26 +#define ETH_XMII_TX_DELAY_MASK 0x0c000000 +#define ETH_XMII_TX_DELAY_GET(x) (((x) & ETH_XMII_TX_DELAY_MASK) >> ETH_XMII_TX_DELAY_LSB) +#define ETH_XMII_TX_DELAY_SET(x) (((x) << ETH_XMII_TX_DELAY_LSB) & ETH_XMII_TX_DELAY_MASK) +#define ETH_XMII_GIGE_MSB 25 +#define ETH_XMII_GIGE_LSB 25 +#define ETH_XMII_GIGE_MASK 0x02000000 +#define ETH_XMII_GIGE_GET(x) (((x) & ETH_XMII_GIGE_MASK) >> ETH_XMII_GIGE_LSB) +#define ETH_XMII_GIGE_SET(x) (((x) << ETH_XMII_GIGE_LSB) & ETH_XMII_GIGE_MASK) +#define ETH_XMII_OFFSET_PHASE_MSB 24 +#define ETH_XMII_OFFSET_PHASE_LSB 24 +#define ETH_XMII_OFFSET_PHASE_MASK 0x01000000 +#define ETH_XMII_OFFSET_PHASE_GET(x) (((x) & ETH_XMII_OFFSET_PHASE_MASK) >> ETH_XMII_OFFSET_PHASE_LSB) +#define ETH_XMII_OFFSET_PHASE_SET(x) (((x) << ETH_XMII_OFFSET_PHASE_LSB) & ETH_XMII_OFFSET_PHASE_MASK) +#define ETH_XMII_OFFSET_COUNT_MSB 23 +#define ETH_XMII_OFFSET_COUNT_LSB 16 +#define ETH_XMII_OFFSET_COUNT_MASK 0x00ff0000 +#define ETH_XMII_OFFSET_COUNT_GET(x) (((x) & ETH_XMII_OFFSET_COUNT_MASK) >> ETH_XMII_OFFSET_COUNT_LSB) +#define ETH_XMII_OFFSET_COUNT_SET(x) (((x) << ETH_XMII_OFFSET_COUNT_LSB) & ETH_XMII_OFFSET_COUNT_MASK) +#define ETH_XMII_PHASE1_COUNT_MSB 15 +#define ETH_XMII_PHASE1_COUNT_LSB 8 +#define ETH_XMII_PHASE1_COUNT_MASK 0x0000ff00 +#define ETH_XMII_PHASE1_COUNT_GET(x) (((x) & ETH_XMII_PHASE1_COUNT_MASK) >> ETH_XMII_PHASE1_COUNT_LSB) +#define ETH_XMII_PHASE1_COUNT_SET(x) (((x) << ETH_XMII_PHASE1_COUNT_LSB) & ETH_XMII_PHASE1_COUNT_MASK) +#define ETH_XMII_PHASE0_COUNT_MSB 7 +#define ETH_XMII_PHASE0_COUNT_LSB 0 +#define ETH_XMII_PHASE0_COUNT_MASK 0x000000ff +#define ETH_XMII_PHASE0_COUNT_GET(x) (((x) & ETH_XMII_PHASE0_COUNT_MASK) >> ETH_XMII_PHASE0_COUNT_LSB) +#define ETH_XMII_PHASE0_COUNT_SET(x) (((x) << ETH_XMII_PHASE0_COUNT_LSB) & ETH_XMII_PHASE0_COUNT_MASK) + +#define USB_PHY_CONFIG_ADDRESS 0x00000310 +#define USB_PHY_CONFIG_OFFSET 0x00000310 +#define USB_PHY_CONFIG_REFCLK_SEL_MSB 7 +#define USB_PHY_CONFIG_REFCLK_SEL_LSB 4 +#define USB_PHY_CONFIG_REFCLK_SEL_MASK 0x000000f0 +#define USB_PHY_CONFIG_REFCLK_SEL_GET(x) (((x) & USB_PHY_CONFIG_REFCLK_SEL_MASK) >> USB_PHY_CONFIG_REFCLK_SEL_LSB) +#define USB_PHY_CONFIG_REFCLK_SEL_SET(x) (((x) << USB_PHY_CONFIG_REFCLK_SEL_LSB) & USB_PHY_CONFIG_REFCLK_SEL_MASK) +#define USB_PHY_CONFIG_REFDIV_MSB 3 +#define USB_PHY_CONFIG_REFDIV_LSB 3 +#define USB_PHY_CONFIG_REFDIV_MASK 0x00000008 +#define USB_PHY_CONFIG_REFDIV_GET(x) (((x) & USB_PHY_CONFIG_REFDIV_MASK) >> USB_PHY_CONFIG_REFDIV_LSB) +#define USB_PHY_CONFIG_REFDIV_SET(x) (((x) << USB_PHY_CONFIG_REFDIV_LSB) & USB_PHY_CONFIG_REFDIV_MASK) +#define USB_PHY_CONFIG_TESTMODE_MSB 2 +#define USB_PHY_CONFIG_TESTMODE_LSB 2 +#define USB_PHY_CONFIG_TESTMODE_MASK 0x00000004 +#define USB_PHY_CONFIG_TESTMODE_GET(x) (((x) & USB_PHY_CONFIG_TESTMODE_MASK) >> USB_PHY_CONFIG_TESTMODE_LSB) +#define USB_PHY_CONFIG_TESTMODE_SET(x) (((x) << USB_PHY_CONFIG_TESTMODE_LSB) & USB_PHY_CONFIG_TESTMODE_MASK) +#define USB_PHY_CONFIG_PLL_PWD_MSB 1 +#define USB_PHY_CONFIG_PLL_PWD_LSB 1 +#define USB_PHY_CONFIG_PLL_PWD_MASK 0x00000002 +#define USB_PHY_CONFIG_PLL_PWD_GET(x) (((x) & USB_PHY_CONFIG_PLL_PWD_MASK) >> USB_PHY_CONFIG_PLL_PWD_LSB) +#define USB_PHY_CONFIG_PLL_PWD_SET(x) (((x) << USB_PHY_CONFIG_PLL_PWD_LSB) & USB_PHY_CONFIG_PLL_PWD_MASK) +#define USB_PHY_CONFIG_HOSTMODE_MSB 0 +#define USB_PHY_CONFIG_HOSTMODE_LSB 0 +#define USB_PHY_CONFIG_HOSTMODE_MASK 0x00000001 +#define USB_PHY_CONFIG_HOSTMODE_GET(x) (((x) & USB_PHY_CONFIG_HOSTMODE_MASK) >> USB_PHY_CONFIG_HOSTMODE_LSB) +#define USB_PHY_CONFIG_HOSTMODE_SET(x) (((x) << USB_PHY_CONFIG_HOSTMODE_LSB) & USB_PHY_CONFIG_HOSTMODE_MASK) + +#define USBCORE_CLK60M_ADDRESS 0x00000314 +#define USBCORE_CLK60M_OFFSET 0x00000314 +#define USBCORE_CLK60M_SEL_MSB 0 +#define USBCORE_CLK60M_SEL_LSB 0 +#define USBCORE_CLK60M_SEL_MASK 0x00000001 +#define USBCORE_CLK60M_SEL_GET(x) (((x) & USBCORE_CLK60M_SEL_MASK) >> USBCORE_CLK60M_SEL_LSB) +#define USBCORE_CLK60M_SEL_SET(x) (((x) << USBCORE_CLK60M_SEL_LSB) & USBCORE_CLK60M_SEL_MASK) + +#define USBPHY_UTMI_CLK_ADDRESS 0x00000318 +#define USBPHY_UTMI_CLK_OFFSET 0x00000318 +#define USBPHY_UTMI_CLK_EN_MSB 0 +#define USBPHY_UTMI_CLK_EN_LSB 0 +#define USBPHY_UTMI_CLK_EN_MASK 0x00000001 +#define USBPHY_UTMI_CLK_EN_GET(x) (((x) & USBPHY_UTMI_CLK_EN_MASK) >> USBPHY_UTMI_CLK_EN_LSB) +#define USBPHY_UTMI_CLK_EN_SET(x) (((x) << USBPHY_UTMI_CLK_EN_LSB) & USBPHY_UTMI_CLK_EN_MASK) + +#define USB_TXVALID_DLY_CONFIG_ADDRESS 0x0000031c +#define USB_TXVALID_DLY_CONFIG_OFFSET 0x0000031c +#define USB_TXVALID_DLY_CONFIG_UTMI16_MSB 7 +#define USB_TXVALID_DLY_CONFIG_UTMI16_LSB 4 +#define USB_TXVALID_DLY_CONFIG_UTMI16_MASK 0x000000f0 +#define USB_TXVALID_DLY_CONFIG_UTMI16_GET(x) (((x) & USB_TXVALID_DLY_CONFIG_UTMI16_MASK) >> USB_TXVALID_DLY_CONFIG_UTMI16_LSB) +#define USB_TXVALID_DLY_CONFIG_UTMI16_SET(x) (((x) << USB_TXVALID_DLY_CONFIG_UTMI16_LSB) & USB_TXVALID_DLY_CONFIG_UTMI16_MASK) +#define USB_TXVALID_DLY_CONFIG_UTMI8_MSB 3 +#define USB_TXVALID_DLY_CONFIG_UTMI8_LSB 0 +#define USB_TXVALID_DLY_CONFIG_UTMI8_MASK 0x0000000f +#define USB_TXVALID_DLY_CONFIG_UTMI8_GET(x) (((x) & USB_TXVALID_DLY_CONFIG_UTMI8_MASK) >> USB_TXVALID_DLY_CONFIG_UTMI8_LSB) +#define USB_TXVALID_DLY_CONFIG_UTMI8_SET(x) (((x) << USB_TXVALID_DLY_CONFIG_UTMI8_LSB) & USB_TXVALID_DLY_CONFIG_UTMI8_MASK) + +#define SECOND_HOST_INFT_ADDRESS 0x00000320 +#define SECOND_HOST_INFT_OFFSET 0x00000320 +#define SECOND_HOST_INFT_SDIO_MODE_MSB 0 +#define SECOND_HOST_INFT_SDIO_MODE_LSB 0 +#define SECOND_HOST_INFT_SDIO_MODE_MASK 0x00000001 +#define SECOND_HOST_INFT_SDIO_MODE_GET(x) (((x) & SECOND_HOST_INFT_SDIO_MODE_MASK) >> SECOND_HOST_INFT_SDIO_MODE_LSB) +#define SECOND_HOST_INFT_SDIO_MODE_SET(x) (((x) << SECOND_HOST_INFT_SDIO_MODE_LSB) & SECOND_HOST_INFT_SDIO_MODE_MASK) + +#define SDIO_HOST_ADDRESS 0x00000324 +#define SDIO_HOST_OFFSET 0x00000324 +#define SDIO_HOST_RESET_MSB 0 +#define SDIO_HOST_RESET_LSB 0 +#define SDIO_HOST_RESET_MASK 0x00000001 +#define SDIO_HOST_RESET_GET(x) (((x) & SDIO_HOST_RESET_MASK) >> SDIO_HOST_RESET_LSB) +#define SDIO_HOST_RESET_SET(x) (((x) << SDIO_HOST_RESET_LSB) & SDIO_HOST_RESET_MASK) + +#define ENTERPRISE_CONFIG_ADDRESS 0x00000328 +#define ENTERPRISE_CONFIG_OFFSET 0x00000328 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MSB 12 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB 12 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK 0x00001000 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_GET(x) (((x) & ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK) >> ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB) +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_SET(x) (((x) << ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB) & ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK) +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MSB 11 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB 11 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK 0x00000800 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_GET(x) (((x) & ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK) >> ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB) +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_SET(x) (((x) << ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB) & ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK) +#define ENTERPRISE_CONFIG_STBC_DISABLE_MSB 10 +#define ENTERPRISE_CONFIG_STBC_DISABLE_LSB 10 +#define ENTERPRISE_CONFIG_STBC_DISABLE_MASK 0x00000400 +#define ENTERPRISE_CONFIG_STBC_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_STBC_DISABLE_MASK) >> ENTERPRISE_CONFIG_STBC_DISABLE_LSB) +#define ENTERPRISE_CONFIG_STBC_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_STBC_DISABLE_LSB) & ENTERPRISE_CONFIG_STBC_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LDPC_DISABLE_MSB 9 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_LSB 9 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_MASK 0x00000200 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LDPC_DISABLE_MASK) >> ENTERPRISE_CONFIG_LDPC_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LDPC_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LDPC_DISABLE_LSB) & ENTERPRISE_CONFIG_LDPC_DISABLE_MASK) +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MSB 8 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB 8 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK 0x00000100 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK) >> ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB) +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB) & ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK) +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MSB 7 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB 7 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK 0x00000080 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK) >> ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB) +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB) & ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_MSB 6 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB 6 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK 0x00000040 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK) >> ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB) & ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MSB 5 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB 5 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK 0x00000020 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK) >> ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB) & ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MSB 4 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB 4 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK 0x00000010 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK) >> ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB) & ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK) +#define ENTERPRISE_CONFIG_TXBF_DISABLE_MSB 3 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_LSB 3 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_MASK 0x00000008 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_TXBF_DISABLE_MASK) >> ENTERPRISE_CONFIG_TXBF_DISABLE_LSB) +#define ENTERPRISE_CONFIG_TXBF_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_TXBF_DISABLE_LSB) & ENTERPRISE_CONFIG_TXBF_DISABLE_MASK) +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MSB 2 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB 2 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK 0x00000004 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK) >> ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB) +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB) & ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MSB 1 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB 1 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK 0x00000002 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK) >> ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB) & ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_MSB 0 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB 0 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK 0x00000001 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK) >> ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB) & ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK) + +#define RTC_DEBUG_BUS_ADDRESS 0x0000032c +#define RTC_DEBUG_BUS_OFFSET 0x0000032c +#define RTC_DEBUG_BUS_SEL_MSB 0 +#define RTC_DEBUG_BUS_SEL_LSB 0 +#define RTC_DEBUG_BUS_SEL_MASK 0x00000001 +#define RTC_DEBUG_BUS_SEL_GET(x) (((x) & RTC_DEBUG_BUS_SEL_MASK) >> RTC_DEBUG_BUS_SEL_LSB) +#define RTC_DEBUG_BUS_SEL_SET(x) (((x) << RTC_DEBUG_BUS_SEL_LSB) & RTC_DEBUG_BUS_SEL_MASK) + +#define RTC_EXT_CLK_BUF_ADDRESS 0x00000330 +#define RTC_EXT_CLK_BUF_OFFSET 0x00000330 +#define RTC_EXT_CLK_BUF_EN_MSB 0 +#define RTC_EXT_CLK_BUF_EN_LSB 0 +#define RTC_EXT_CLK_BUF_EN_MASK 0x00000001 +#define RTC_EXT_CLK_BUF_EN_GET(x) (((x) & RTC_EXT_CLK_BUF_EN_MASK) >> RTC_EXT_CLK_BUF_EN_LSB) +#define RTC_EXT_CLK_BUF_EN_SET(x) (((x) << RTC_EXT_CLK_BUF_EN_LSB) & RTC_EXT_CLK_BUF_EN_MASK) + +#define WLAN_AHB_BRIDGE_TIMEOUT_ADDRESS 0x00000334 +#define WLAN_AHB_BRIDGE_TIMEOUT_OFFSET 0x00000334 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MSB 13 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB 0 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK 0x00003fff +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_GET(x) (((x) & WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK) >> WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB) +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_SET(x) (((x) << WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB) & WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK) + +#define WLAN_AHB_CONFIG_ADDRESS 0x00000338 +#define WLAN_AHB_CONFIG_OFFSET 0x00000338 +#define WLAN_AHB_CONFIG_MAX_BURST_16_MSB 2 +#define WLAN_AHB_CONFIG_MAX_BURST_16_LSB 2 +#define WLAN_AHB_CONFIG_MAX_BURST_16_MASK 0x00000004 +#define WLAN_AHB_CONFIG_MAX_BURST_16_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_16_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_16_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_16_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_16_LSB) & WLAN_AHB_CONFIG_MAX_BURST_16_MASK) +#define WLAN_AHB_CONFIG_MAX_BURST_8_MSB 1 +#define WLAN_AHB_CONFIG_MAX_BURST_8_LSB 1 +#define WLAN_AHB_CONFIG_MAX_BURST_8_MASK 0x00000002 +#define WLAN_AHB_CONFIG_MAX_BURST_8_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_8_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_8_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_8_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_8_LSB) & WLAN_AHB_CONFIG_MAX_BURST_8_MASK) +#define WLAN_AHB_CONFIG_MAX_BURST_4_MSB 0 +#define WLAN_AHB_CONFIG_MAX_BURST_4_LSB 0 +#define WLAN_AHB_CONFIG_MAX_BURST_4_MASK 0x00000001 +#define WLAN_AHB_CONFIG_MAX_BURST_4_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_4_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_4_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_4_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_4_LSB) & WLAN_AHB_CONFIG_MAX_BURST_4_MASK) + +#define RTC_AXI_AHB_BRIDGE_ADDRESS 0x0000033c +#define RTC_AXI_AHB_BRIDGE_OFFSET 0x0000033c +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MSB 3 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB 3 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK 0x00000008 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK) >> RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB) +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB) & RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK) +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MSB 2 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB 2 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK 0x00000004 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK) >> RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB) +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB) & RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK) +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_MSB 1 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB 0 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK 0x00000003 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK) >> RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB) +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB) & RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK) + +#define WLAN2BT_CPUCOM_INT_STS_ADDRESS 0x00000400 +#define WLAN2BT_CPUCOM_INT_STS_OFFSET 0x00000400 +#define WLAN2BT_CPUCOM_INT_STS_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_STS_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_STS_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_STS_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_STS_REG_MASK) >> WLAN2BT_CPUCOM_INT_STS_REG_LSB) +#define WLAN2BT_CPUCOM_INT_STS_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_STS_REG_LSB) & WLAN2BT_CPUCOM_INT_STS_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_MASK_N_ADDRESS 0x00000404 +#define WLAN2BT_CPUCOM_INT_MASK_N_OFFSET 0x00000404 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK) >> WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB) +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB) & WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_EOI_ADDRESS 0x00000408 +#define WLAN2BT_CPUCOM_INT_EOI_OFFSET 0x00000408 +#define WLAN2BT_CPUCOM_INT_EOI_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_EOI_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_EOI_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_EOI_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_EOI_REG_MASK) >> WLAN2BT_CPUCOM_INT_EOI_REG_LSB) +#define WLAN2BT_CPUCOM_INT_EOI_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_EOI_REG_LSB) & WLAN2BT_CPUCOM_INT_EOI_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_STS_ADDRESS 0x0000040c +#define WLAN2BT_CPUCOM_INT_ACK_STS_OFFSET 0x0000040c +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_ADDRESS 0x00000410 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_OFFSET 0x00000410 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK) + +#define WLAN_CPUCOM_CRD_CNT0_ADDRESS 0x00000414 +#define WLAN_CPUCOM_CRD_CNT0_OFFSET 0x00000414 +#define WLAN_CPUCOM_CRD_CNT0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_CNT0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_CNT0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_CNT0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_CNT0_REG_MASK) >> WLAN_CPUCOM_CRD_CNT0_REG_LSB) +#define WLAN_CPUCOM_CRD_CNT0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_CNT0_REG_LSB) & WLAN_CPUCOM_CRD_CNT0_REG_MASK) + +#define WLAN_CPUCOM_CRD_INC0_ADDRESS 0x00000418 +#define WLAN_CPUCOM_CRD_INC0_OFFSET 0x00000418 +#define WLAN_CPUCOM_CRD_INC0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_INC0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_INC0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_INC0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_INC0_REG_MASK) >> WLAN_CPUCOM_CRD_INC0_REG_LSB) +#define WLAN_CPUCOM_CRD_INC0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_INC0_REG_LSB) & WLAN_CPUCOM_CRD_INC0_REG_MASK) + +#define WLAN_CPUCOM_CRD_DEC0_ADDRESS 0x0000041c +#define WLAN_CPUCOM_CRD_DEC0_OFFSET 0x0000041c +#define WLAN_CPUCOM_CRD_DEC0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_DEC0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_DEC0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_DEC0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_DEC0_REG_MASK) >> WLAN_CPUCOM_CRD_DEC0_REG_LSB) +#define WLAN_CPUCOM_CRD_DEC0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_DEC0_REG_LSB) & WLAN_CPUCOM_CRD_DEC0_REG_MASK) + +#define WLAN_CPUCOM_CRD_CNT1_ADDRESS 0x00000420 +#define WLAN_CPUCOM_CRD_CNT1_OFFSET 0x00000420 +#define WLAN_CPUCOM_CRD_CNT1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_CNT1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_CNT1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_CNT1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_CNT1_REG_MASK) >> WLAN_CPUCOM_CRD_CNT1_REG_LSB) +#define WLAN_CPUCOM_CRD_CNT1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_CNT1_REG_LSB) & WLAN_CPUCOM_CRD_CNT1_REG_MASK) + +#define WLAN_CPUCOM_CRD_INC1_ADDRESS 0x00000424 +#define WLAN_CPUCOM_CRD_INC1_OFFSET 0x00000424 +#define WLAN_CPUCOM_CRD_INC1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_INC1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_INC1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_INC1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_INC1_REG_MASK) >> WLAN_CPUCOM_CRD_INC1_REG_LSB) +#define WLAN_CPUCOM_CRD_INC1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_INC1_REG_LSB) & WLAN_CPUCOM_CRD_INC1_REG_MASK) + +#define WLAN_CPUCOM_CRD_DEC1_ADDRESS 0x00000428 +#define WLAN_CPUCOM_CRD_DEC1_OFFSET 0x00000428 +#define WLAN_CPUCOM_CRD_DEC1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_DEC1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_DEC1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_DEC1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_DEC1_REG_MASK) >> WLAN_CPUCOM_CRD_DEC1_REG_LSB) +#define WLAN_CPUCOM_CRD_DEC1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_DEC1_REG_LSB) & WLAN_CPUCOM_CRD_DEC1_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH0_ADDRESS 0x0000042c +#define WLAN_CPUCOM_SCRATCH0_OFFSET 0x0000042c +#define WLAN_CPUCOM_SCRATCH0_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH0_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH0_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH0_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH0_REG_MASK) >> WLAN_CPUCOM_SCRATCH0_REG_LSB) +#define WLAN_CPUCOM_SCRATCH0_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH0_REG_LSB) & WLAN_CPUCOM_SCRATCH0_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH1_ADDRESS 0x00000430 +#define WLAN_CPUCOM_SCRATCH1_OFFSET 0x00000430 +#define WLAN_CPUCOM_SCRATCH1_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH1_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH1_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH1_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH1_REG_MASK) >> WLAN_CPUCOM_SCRATCH1_REG_LSB) +#define WLAN_CPUCOM_SCRATCH1_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH1_REG_LSB) & WLAN_CPUCOM_SCRATCH1_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH2_ADDRESS 0x00000434 +#define WLAN_CPUCOM_SCRATCH2_OFFSET 0x00000434 +#define WLAN_CPUCOM_SCRATCH2_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH2_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH2_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH2_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH2_REG_MASK) >> WLAN_CPUCOM_SCRATCH2_REG_LSB) +#define WLAN_CPUCOM_SCRATCH2_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH2_REG_LSB) & WLAN_CPUCOM_SCRATCH2_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH3_ADDRESS 0x00000438 +#define WLAN_CPUCOM_SCRATCH3_OFFSET 0x00000438 +#define WLAN_CPUCOM_SCRATCH3_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH3_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH3_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH3_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH3_REG_MASK) >> WLAN_CPUCOM_SCRATCH3_REG_LSB) +#define WLAN_CPUCOM_SCRATCH3_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH3_REG_LSB) & WLAN_CPUCOM_SCRATCH3_REG_MASK) + +#define WLAN_CPUCOM_DBG_ADDRESS 0x0000043c +#define WLAN_CPUCOM_DBG_OFFSET 0x0000043c +#define WLAN_CPUCOM_DBG_RESERVE_MSB 7 +#define WLAN_CPUCOM_DBG_RESERVE_LSB 4 +#define WLAN_CPUCOM_DBG_RESERVE_MASK 0x000000f0 +#define WLAN_CPUCOM_DBG_RESERVE_GET(x) (((x) & WLAN_CPUCOM_DBG_RESERVE_MASK) >> WLAN_CPUCOM_DBG_RESERVE_LSB) +#define WLAN_CPUCOM_DBG_RESERVE_SET(x) (((x) << WLAN_CPUCOM_DBG_RESERVE_LSB) & WLAN_CPUCOM_DBG_RESERVE_MASK) +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MSB 3 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB 3 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK 0x00000008 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_MSB 2 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB 2 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK 0x00000004 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MSB 1 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB 1 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK 0x00000002 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_MSB 0 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB 0 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK 0x00000001 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_EN_ADDRESS 0x00000440 +#define WLAN2BT_CPUCOM_INT_ACK_EN_OFFSET 0x00000440 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_MSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK 0x00000001 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK) + +#define BT2WLAN_CPUCOM_INT_EN_ADDRESS 0x00000444 +#define BT2WLAN_CPUCOM_INT_EN_OFFSET 0x00000444 +#define BT2WLAN_CPUCOM_INT_EN_REG_MSB 0 +#define BT2WLAN_CPUCOM_INT_EN_REG_LSB 0 +#define BT2WLAN_CPUCOM_INT_EN_REG_MASK 0x00000001 +#define BT2WLAN_CPUCOM_INT_EN_REG_GET(x) (((x) & BT2WLAN_CPUCOM_INT_EN_REG_MASK) >> BT2WLAN_CPUCOM_INT_EN_REG_LSB) +#define BT2WLAN_CPUCOM_INT_EN_REG_SET(x) (((x) << BT2WLAN_CPUCOM_INT_EN_REG_LSB) & BT2WLAN_CPUCOM_INT_EN_REG_MASK) + +#ifndef __ASSEMBLER__ +typedef struct rtc_soc_reg_reg_s { + volatile unsigned int soc_reset_control; + volatile unsigned int soc_tcxo_detect; + volatile unsigned int soc_xtal_test; + unsigned char pad0[20]; /* pad to 0x20 */ + volatile unsigned int soc_cpu_clock; + unsigned char pad1[4]; /* pad to 0x28 */ + volatile unsigned int soc_clock_control; + unsigned char pad2[4]; /* pad to 0x30 */ + volatile unsigned int soc_wdt_control; + volatile unsigned int soc_wdt_status; + volatile unsigned int soc_wdt; + volatile unsigned int soc_wdt_count; + volatile unsigned int soc_wdt_reset; + volatile unsigned int soc_int_status; + volatile unsigned int soc_lf_timer0; + volatile unsigned int soc_lf_timer_count0; + volatile unsigned int soc_lf_timer_control0; + volatile unsigned int soc_lf_timer_status0; + volatile unsigned int soc_lf_timer1; + volatile unsigned int soc_lf_timer_count1; + volatile unsigned int soc_lf_timer_control1; + volatile unsigned int soc_lf_timer_status1; + volatile unsigned int soc_lf_timer2; + volatile unsigned int soc_lf_timer_count2; + volatile unsigned int soc_lf_timer_control2; + volatile unsigned int soc_lf_timer_status2; + volatile unsigned int soc_lf_timer3; + volatile unsigned int soc_lf_timer_count3; + volatile unsigned int soc_lf_timer_control3; + volatile unsigned int soc_lf_timer_status3; + volatile unsigned int soc_hf_timer; + volatile unsigned int soc_hf_timer_count; + volatile unsigned int soc_hf_lf_count; + volatile unsigned int soc_hf_timer_control; + volatile unsigned int soc_hf_timer_status; + volatile unsigned int soc_rtc_control; + volatile unsigned int soc_rtc_time; + volatile unsigned int soc_rtc_date; + volatile unsigned int soc_rtc_set_time; + volatile unsigned int soc_rtc_set_date; + volatile unsigned int soc_rtc_set_alarm; + volatile unsigned int soc_rtc_config; + volatile unsigned int soc_rtc_alarm_status; + volatile unsigned int soc_uart_wakeup; + volatile unsigned int soc_reset_cause; + volatile unsigned int soc_system_sleep; + volatile unsigned int soc_sdio_wrapper; + volatile unsigned int soc_int_sleep_mask; + unsigned char pad3[4]; /* pad to 0xd4 */ + volatile unsigned int soc_lpo_cal_time; + volatile unsigned int soc_lpo_init_dividend_int; + volatile unsigned int soc_lpo_init_dividend_fraction; + volatile unsigned int soc_lpo_cal; + volatile unsigned int soc_lpo_cal_test_control; + volatile unsigned int soc_lpo_cal_test_status; + volatile unsigned int legacy_soc_chip_id; + volatile unsigned int soc_chip_id; + unsigned char pad4[24]; /* pad to 0x10c */ + volatile unsigned int soc_power_reg; + volatile unsigned int soc_core_clk_ctrl; + volatile unsigned int soc_gpio_wakeup_control; + unsigned char pad5[252]; /* pad to 0x214 */ + volatile unsigned int sleep_retention; + unsigned char pad6[108]; /* pad to 0x284 */ + volatile unsigned int lp_perf_counter; + volatile unsigned int lp_perf_light_sleep; + volatile unsigned int lp_perf_deep_sleep; + volatile unsigned int lp_perf_on; + unsigned char pad7[20]; /* pad to 0x2a8 */ + volatile unsigned int chip_mode; + volatile unsigned int clk_req_fall_edge; + volatile unsigned int otp; + volatile unsigned int otp_status; + volatile unsigned int pmu; + volatile unsigned int pmu_config; + volatile unsigned int pmu_pareg; + volatile unsigned int pmu_bypass; + unsigned char pad8[20]; /* pad to 0x2dc */ + volatile unsigned int therm_ctrl1; + volatile unsigned int therm_ctrl2; + volatile unsigned int therm_ctrl3; + volatile unsigned int listen_mode1; + volatile unsigned int listen_mode2; + volatile unsigned int audio_pll_config; + volatile unsigned int audio_pll_modulation; + volatile unsigned int audio_pll_mod_step; + volatile unsigned int current_audio_pll_modulation; + volatile unsigned int eth_pll_config; + volatile unsigned int cpu_pll_config; + volatile unsigned int bb_pll_config; + volatile unsigned int eth_xmii; + volatile unsigned int usb_phy_config; + volatile unsigned int usbcore_clk60m; + volatile unsigned int usbphy_utmi_clk; + volatile unsigned int usb_txvalid_dly_config; + volatile unsigned int second_host_inft; + volatile unsigned int sdio_host; + volatile unsigned int enterprise_config; + volatile unsigned int rtc_debug_bus; + volatile unsigned int rtc_ext_clk_buf; + volatile unsigned int wlan_ahb_bridge_timeout; + volatile unsigned int wlan_ahb_config; + volatile unsigned int rtc_axi_ahb_bridge; + unsigned char pad9[192]; /* pad to 0x400 */ + volatile unsigned int wlan2bt_cpucom_int_sts; + volatile unsigned int wlan2bt_cpucom_int_mask_n; + volatile unsigned int wlan2bt_cpucom_int_eoi; + volatile unsigned int wlan2bt_cpucom_int_ack_sts; + volatile unsigned int wlan2bt_cpucom_int_ack_mask_n; + volatile unsigned int wlan_cpucom_crd_cnt0; + volatile unsigned int wlan_cpucom_crd_inc0[1]; + volatile unsigned int wlan_cpucom_crd_dec0[1]; + volatile unsigned int wlan_cpucom_crd_cnt1; + volatile unsigned int wlan_cpucom_crd_inc1[1]; + volatile unsigned int wlan_cpucom_crd_dec1[1]; + volatile unsigned int wlan_cpucom_scratch0; + volatile unsigned int wlan_cpucom_scratch1; + volatile unsigned int wlan_cpucom_scratch2; + volatile unsigned int wlan_cpucom_scratch3; + volatile unsigned int wlan_cpucom_dbg; + volatile unsigned int wlan2bt_cpucom_int_ack_en; + volatile unsigned int bt2wlan_cpucom_int_en; +} rtc_soc_reg_reg_t; +#endif /* __ASSEMBLER__ */ + +#endif /* _RTC_SOC_REG_H_ */ diff --git a/target/inc/targaddrs.h b/target/inc/targaddrs.h new file mode 100644 index 0000000000..7cf64d385c --- /dev/null +++ b/target/inc/targaddrs.h @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __TARGADDRS_H__ +#define __TARGADDRS_H__ + +#if defined(ATH_TARGET) +#include "soc_addrs.h" +#endif + +#if !defined(ATH_TARGET) +#include "athstartpack.h" +#endif + +/* + * SOC option bits, to enable/disable various features. + * By default, all option bits are 0. + * AR6004: These bits can be set in LOCAL_SCRATCH register 0. + * AR9888: These bits can be set in soc_core register SCRATCH_0. + */ +#define SOC_OPTION_BMI_DISABLE 0x01 /* Disable BMI comm with Host */ +#define SOC_OPTION_SERIAL_ENABLE 0x02 /* Enable serial port msgs */ +#define SOC_OPTION_WDT_DISABLE 0x04 /* WatchDog Timer override */ +#define SOC_OPTION_SLEEP_DISABLE 0x08 /* Disable system sleep */ +#define SOC_OPTION_STOP_BOOT 0x10 /* Stop boot processes (for ATE) */ +#define SOC_OPTION_ENABLE_NOANI 0x20 /* Operate without ANI */ +#define SOC_OPTION_DSET_DISABLE 0x40 /* Ignore DataSets */ +#define SOC_OPTION_IGNORE_FLASH 0x80 /* Ignore flash during bootup */ + +/* + * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the + * host_interest structure. It must match the address of the _host_interest + * symbol (see linker script). + * + * Host Interest is shared between Host and Target in order to coordinate + * between the two, and is intended to remain constant (with additions only + * at the end) across software releases. + * + * All addresses are available here so that it's possible to + * write a single binary that works with all Target Types. + * May be used in assembler code as well as C. + */ +#define AR6002_HOST_INTEREST_ADDRESS 0x00500400 +#define AR6003_HOST_INTEREST_ADDRESS 0x00540600 +#define AR6004_HOST_INTEREST_ADDRESS 0x00400800 +#define AR9888_HOST_INTEREST_ADDRESS 0x00400800 +#define AR900B_HOST_INTEREST_ADDRESS 0x00400800 +#define AR6320_HOST_INTEREST_ADDRESS 0x00400800 +#define QCA6180_HOST_INTEREST_ADDRESS 0x005d96a0 +#define AR6004_SOC_RESET_ADDRESS 0X00004000 +#define AR6004_SOC_RESET_CPU_INIT_RESET_MASK 0X00000800 +#if defined(AR6006_MEMORY_NEW_ARCH) +#define AR6006_HOST_INTEREST_ADDRESS 0x00428800 +#else +#define AR6006_HOST_INTEREST_ADDRESS 0x00400800 +#endif +#define AR6006_SOC_RESET_ADDRESS 0X00004000 +#define AR6006_SOC_RESET_CPU_INIT_RESET_MASK 0X00000800 + +#define HOST_INTEREST_MAX_SIZE 0x200 + +#if !defined(__ASSEMBLER__) +struct register_dump_s; +struct dbglog_hdr_s; + +/* + * These are items that the Host may need to access + * via BMI or via the Diagnostic Window. The position + * of items in this structure must remain constant + * across firmware revisions! + * + * Types for each item must be fixed size across + * target and host platforms. + * + * More items may be added at the end. + */ +PREPACK64 struct host_interest_s { + /* + * Pointer to application-defined area, if any. + * Set by Target application during startup. + */ + A_UINT32 hi_app_host_interest; /* 0x00 */ + + /* Pointer to register dump area, valid after Target crash. */ + A_UINT32 hi_failure_state; /* 0x04 */ + + /* Pointer to debug logging header */ + A_UINT32 hi_dbglog_hdr; /* 0x08 */ + + /* Save SW ROM version */ + A_UINT32 hi_sw_rom_version; /* 0x0c */ + + /* + * General-purpose flag bits, similar to SOC_OPTION_* flags. + * Can be used by application rather than by OS. + */ + A_UINT32 hi_option_flag; /* 0x10 */ + + /* + * Boolean that determines whether or not to + * display messages on the serial port. + */ + A_UINT32 hi_serial_enable; /* 0x14 */ + + /* Start address of DataSet index, if any */ + A_UINT32 hi_dset_list_head; /* 0x18 */ + + /* Override Target application start address */ + A_UINT32 hi_app_start; /* 0x1c */ + + /* Clock and voltage tuning */ + A_UINT32 hi_skip_clock_init; /* 0x20 */ + A_UINT32 hi_core_clock_setting; /* 0x24 */ + A_UINT32 hi_cpu_clock_setting; /* 0x28 */ + A_UINT32 hi_system_sleep_setting; /* 0x2c */ + A_UINT32 hi_xtal_control_setting; /* 0x30 */ + A_UINT32 hi_pll_ctrl_setting_24ghz; /* 0x34 */ + A_UINT32 hi_pll_ctrl_setting_5ghz; /* 0x38 */ + A_UINT32 hi_ref_voltage_trim_setting; /* 0x3c */ + A_UINT32 hi_clock_info; /* 0x40 */ + + /* Host uses BE CPU or not */ + A_UINT32 hi_be; /* 0x44 */ + + A_UINT32 hi_stack; /* normal stack *//* 0x48 */ + A_UINT32 hi_err_stack; /* error stack *//* 0x4c */ + A_UINT32 hi_desired_cpu_speed_hz; /* 0x50 */ + + /* Pointer to Board Data */ + A_UINT32 hi_board_data; /* 0x54 */ + + /* + * Indication of Board Data state: + * 0: board data is not yet initialized. + * 1: board data is initialized; unknown size + * >1: number of bytes of initialized board data (varies with board type) + */ + A_UINT32 hi_board_data_initialized; /* 0x58 */ + + A_UINT32 hi_dset_RAM_index_table; /* 0x5c */ + + A_UINT32 hi_desired_baud_rate; /* 0x60 */ + A_UINT32 hi_dbglog_config; /* 0x64 */ + A_UINT32 hi_end_RAM_reserve_sz; /* 0x68 */ + A_UINT32 hi_mbox_io_block_sz; /* 0x6c */ + + A_UINT32 hi_num_bpatch_streams; /* 0x70 -- unused */ + A_UINT32 hi_mbox_isr_yield_limit; /* 0x74 */ + + A_UINT32 hi_refclk_hz; /* 0x78 */ + A_UINT32 hi_ext_clk_detected; /* 0x7c */ + A_UINT32 hi_dbg_uart_txpin; /* 0x80 */ + A_UINT32 hi_dbg_uart_rxpin; /* 0x84 */ + A_UINT32 hi_hci_uart_baud; /* 0x88 */ + A_UINT32 hi_hci_uart_pin_assignments; /* 0x8C */ + /* NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts pin */ + A_UINT32 hi_hci_uart_baud_scale_val; /* 0x90 */ + A_UINT32 hi_hci_uart_baud_step_val; /* 0x94 */ + + A_UINT32 hi_allocram_start; /* 0x98 */ + A_UINT32 hi_allocram_sz; /* 0x9c */ + A_UINT32 hi_hci_bridge_flags; /* 0xa0 */ + A_UINT32 hi_hci_uart_support_pins; /* 0xa4 */ + /* NOTE: byte [0] = RESET pin (bit 7 is polarity), bytes[1]..bytes[3] are for future use */ + A_UINT32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */ + /* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high + * [31:16]: wakeup timeout in ms + */ + /* Pointer to extended board Data */ + A_UINT32 hi_board_ext_data; /* 0xac */ + A_UINT32 hi_board_ext_data_config; /* 0xb0 */ + /* + * Bit [0] : valid + * Bit[31:16: size + */ + /* + * hi_reset_flag is used to do some stuff when target reset. + * such as restore app_start after warm reset or + * preserve host Interest area, or preserve ROM data, literals etc. + */ + A_UINT32 hi_reset_flag; /* 0xb4 */ + /* indicate hi_reset_flag is valid */ + A_UINT32 hi_reset_flag_valid; /* 0xb8 */ + A_UINT32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */ + /* 0xbc - [31:0]: idle timeout in ms + */ + /* ACS flags */ + A_UINT32 hi_acs_flags; /* 0xc0 */ + A_UINT32 hi_console_flags; /* 0xc4 */ + A_UINT32 hi_nvram_state; /* 0xc8 */ + A_UINT32 hi_option_flag2; /* 0xcc */ + + /* If non-zero, override values sent to Host in WMI_READY event. */ + A_UINT32 hi_sw_version_override; /* 0xd0 */ + A_UINT32 hi_abi_version_override; /* 0xd4 */ + + /* Percentage of high priority RX traffic to total expected RX traffic - + * applicable only to ar6004 */ + A_UINT32 hi_hp_rx_traffic_ratio; /* 0xd8 */ + + /* test applications flags */ + A_UINT32 hi_test_apps_related; /* 0xdc */ + /* location of test script */ + A_UINT32 hi_ota_testscript; /* 0xe0 */ + /* location of CAL data */ + A_UINT32 hi_cal_data; /* 0xe4 */ + + /* Number of packet log buffers */ + A_UINT32 hi_pktlog_num_buffers; /* 0xe8 */ + + /* wow extension configuration */ + A_UINT32 hi_wow_ext_config; /* 0xec */ + A_UINT32 hi_pwr_save_flags; /* 0xf0 */ + + /* Spatial Multiplexing Power Save (SMPS) options */ + A_UINT32 hi_smps_options; /* 0xf4 */ + + /* Interconnect-specific state */ + A_UINT32 hi_interconnect_state; /* 0xf8 */ + + /* Coex configuration flags */ + A_UINT32 hi_coex_config; /* 0xfc */ + + /* Early allocation support */ + A_UINT32 hi_early_alloc; /* 0x100 */ + + /* FW swap field */ + /* Bits of this 32bit word will be used to pass specific swap + instruction to FW */ + /* Bit 0 -- AP Nart descriptor no swap. When this bit is set + FW will not swap TX descriptor. Meaning packets are formed + on the target processor. */ + /* Bit 1 -- TBD */ + + A_UINT32 hi_fw_swap; /* 0x104 */ + + /* global arenas pointer address, used by host driver debug */ + A_UINT32 hi_dynamic_mem_arenas_addr; /* 0x108 */ + + /* allocated bytes of DRAM use by allocated */ + A_UINT32 hi_dynamic_mem_allocated; /* 0x10C */ + + /* remaining bytes of DRAM */ + A_UINT32 hi_dynamic_mem_remaining; /* 0x110 */ + + /* memory track count, configured by host */ + A_UINT32 hi_dynamic_mem_track_max; /* 0x114 */ + + /* minidump buffer */ + A_UINT32 hi_minidump; /* 0x118 */ + + /* bdata's sig and key addr */ + A_UINT32 hi_bd_sig_key; /* 0x11c */ + +} POSTPACK64; + +/* bitmap for hi_test_apps_related */ +#define HI_TEST_APPS_TESTSCRIPT_LOADED 0x00000001 +#define HI_TEST_APPS_CAL_DATA_AVAIL 0x00000002 + +/* Bits defined in hi_option_flag */ +#define HI_OPTION_TIMER_WAR 0x01 /* Enable timer workaround */ +#define HI_OPTION_BMI_CRED_LIMIT 0x02 /* Limit BMI command credits */ +#define HI_OPTION_RELAY_DOT11_HDR 0x04 /* Relay Dot11 hdr to/from host */ +#define HI_OPTION_MAC_ADDR_METHOD 0x08 /* MAC addr method 0-locally administred 1-globally unique addrs */ +#define HI_OPTION_FW_BRIDGE 0x10 /* Firmware Bridging */ +#define HI_OPTION_ENABLE_PROFILE 0x20 /* Enable CPU profiling */ +#define HI_OPTION_DISABLE_DBGLOG 0x40 /* Disable debug logging */ +#define HI_OPTION_SKIP_ERA_TRACKING 0x80 /* Skip Era Tracking */ +#define HI_OPTION_PAPRD_DISABLE 0x100 /* Disable PAPRD (debug) */ +#define HI_OPTION_NUM_DEV_LSB 0x200 +#define HI_OPTION_NUM_DEV_MSB 0x800 +#define HI_OPTION_DEV_MODE_LSB 0x1000 +#define HI_OPTION_DEV_MODE_MSB 0x8000000 +#define HI_OPTION_NO_LFT_STBL 0x10000000 /* Disable LowFreq Timer Stabilization */ +#define HI_OPTION_SKIP_REG_SCAN 0x20000000 /* Skip regulatory scan */ +#define HI_OPTION_INIT_REG_SCAN 0x40000000 /* Do regulatory scan during init before + * sending WMI ready event to host */ +#define HI_OPTION_SKIP_MEMMAP 0x80000000 /* REV6: Do not adjust memory map */ + +#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3 + +/* 2 bits of hi_option_flag are used to represent 3 modes */ +#define HI_OPTION_FW_MODE_IBSS 0x0 /* IBSS Mode */ +#define HI_OPTION_FW_MODE_BSS_STA 0x1 /* STA Mode */ +#define HI_OPTION_FW_MODE_AP 0x2 /* AP Mode */ +#define HI_OPTION_FW_MODE_BT30AMP 0x3 /* BT30 AMP Mode */ + +/* 2 bits of hi_option flag are usedto represent 4 submodes */ +#define HI_OPTION_FW_SUBMODE_NONE 0x0 /* Normal mode */ +#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 /* p2p device mode */ +#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 /* p2p client mode */ +#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 /* p2p go mode */ + +/* Num dev Mask */ +#define HI_OPTION_NUM_DEV_MASK 0x7 +#define HI_OPTION_NUM_DEV_SHIFT 0x9 + +/* firmware bridging */ +#define HI_OPTION_FW_BRIDGE_SHIFT 0x04 + +/* Fw Mode/SubMode Mask + |-------------------------------------------------------------------------------| + | SUB | SUB | SUB | SUB | | | | | + | MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0] | + | (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) | + |||-------------------------------------------------------------------------------| + */ +#define HI_OPTION_FW_MODE_BITS 0x2 +#define HI_OPTION_FW_MODE_MASK 0x3 +#define HI_OPTION_FW_MODE_SHIFT 0xC +#define HI_OPTION_ALL_FW_MODE_MASK 0xFF + +#define HI_OPTION_FW_SUBMODE_BITS 0x2 +#define HI_OPTION_FW_SUBMODE_MASK 0x3 +#define HI_OPTION_FW_SUBMODE_SHIFT 0x14 +#define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00 +#define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8 + +/* hi_option_flag2 options */ +#define HI_OPTION_OFFLOAD_AMSDU 0x01 +#define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */ +#define HI_OPTION_ENABLE_RFKILL 0x04 /* RFKill Enable Feature */ +#define HI_OPTION_RADIO_RETENTION_DISABLE 0x08 /* Disable radio retention */ +#define HI_OPTION_EARLY_CFG_DONE 0x10 /* Early configuration is complete */ + +#define HI_OPTION_RF_KILL_SHIFT 0x2 +#define HI_OPTION_RF_KILL_MASK 0x1 + +/* AR9888 1.0 only. Enable/disable CDC max perf support from host */ +#define HI_OPTION_DISABLE_CDC_MAX_PERF_WAR 0x20 +#define CDC_MAX_PERF_WAR_ENABLED() \ + (!(HOST_INTEREST->hi_option_flag2 & HI_OPTION_DISABLE_CDC_MAX_PERF_WAR)) + +#define HI_OPTION_USE_EXT_LDO 0x40 /* use LDO27 for 1.1V instead of PMU */ +#define HI_OPTION_DBUART_SUPPORT 0x80 /* Enable uart debug support */ +#define HT_OPTION_GPIO_WAKEUP_SUPPORT 0x200 /* GPIO wake up support */ +#define GPIO_WAKEUP_ENABLED() \ + (HOST_INTEREST->hi_option_flag2 & HT_OPTION_GPIO_WAKEUP_SUPPORT) + +/* hi_reset_flag */ +#define HI_RESET_FLAG_PRESERVE_APP_START 0x01 /* preserve App Start address */ +#define HI_RESET_FLAG_PRESERVE_HOST_INTEREST 0x02 /* preserve host interest */ +#define HI_RESET_FLAG_PRESERVE_ROMDATA 0x04 /* preserve ROM data */ +#define HI_RESET_FLAG_PRESERVE_NVRAM_STATE 0x08 +#define HI_RESET_FLAG_PRESERVE_BOOT_INFO 0x10 +#define HI_RESET_FLAG_WARM_RESET 0x20 + +/* define hi_fw_swap bits */ +#define HI_DESC_IN_FW_BIT 0x01 + +#define HI_RESET_FLAG_IS_VALID 0x12345678 /* indicate the reset flag is valid */ + +#define ON_RESET_FLAGS_VALID() \ + (HOST_INTEREST->hi_reset_flag_valid == HI_RESET_FLAG_IS_VALID) + +#define RESET_FLAGS_VALIDATE() \ + (HOST_INTEREST->hi_reset_flag_valid = HI_RESET_FLAG_IS_VALID) + +#define RESET_FLAGS_INVALIDATE() \ + (HOST_INTEREST->hi_reset_flag_valid = 0) + +#define ON_RESET_PRESERVE_APP_START() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_APP_START) + +#define ON_RESET_PRESERVE_NVRAM_STATE() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_NVRAM_STATE) + +#define ON_RESET_PRESERVE_HOST_INTEREST() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_HOST_INTEREST) + +#define ON_RESET_PRESERVE_ROMDATA() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_ROMDATA) + +#define ON_RESET_PRESERVE_BOOT_INFO() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_BOOT_INFO) + +#define ON_RESET_WARM_RESET() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_WARM_RESET) + +/* host CPU endianness */ +#define HOST_ON_BE_CPU() \ + (HOST_INTEREST->hi_be) + +/* AP nart no swap descriptor flag. Decsriptors are created on the target processor. */ +#define DESC_IN_FW() \ + (HOST_INTEREST->hi_fw_swap & HI_DESC_IN_FW_BIT) + +#define HI_ACS_FLAGS_ENABLED (1 << 0) /* ACS is enabled */ +#define HI_ACS_FLAGS_USE_WWAN (1 << 1) /* Use physical WWAN device */ +#define HI_ACS_FLAGS_TEST_VAP (1 << 2) /* Use test VAP */ + +/* CONSOLE FLAGS + * + * Bit Range Meaning + * --------- -------------------------------- + * 2..0 UART ID (0 = Default) + * 3 Baud Select (0 = 9600, 1 = 115200) + * 30..4 Reserved + * 31 Enable Console + * + * */ + +#define HI_CONSOLE_FLAGS_ENABLE (1 << 31) +#define HI_CONSOLE_FLAGS_UART_MASK (0x7) +#define HI_CONSOLE_FLAGS_UART_SHIFT 0 +#define HI_CONSOLE_FLAGS_BAUD_SELECT (1 << 3) + +/* SM power save options */ +#define HI_SMPS_ALLOW_MASK (0x00000001) +#define HI_SMPS_MODE_MASK (0x00000002) +#define HI_SMPS_MODE_STATIC (0x00000000) +#define HI_SMPS_MODE_DYNAMIC (0x00000002) +#define HI_SMPS_DISABLE_AUTO_MODE (0x00000004) +#define HI_SMPS_DATA_THRESH_MASK (0x000007f8) +#define HI_SMPS_DATA_THRESH_SHIFT (3) +#define HI_SMPS_RSSI_THRESH_MASK (0x0007f800) +#define HI_SMPS_RSSI_THRESH_SHIFT (11) +#define HI_SMPS_LOWPWR_CM_MASK (0x00380000) +#define HI_SMPS_LOWPWR_CM_SHIFT (15) +#define HI_SMPS_HIPWR_CM_MASK (0x03c00000) +#define HI_SMPS_HIPWR_CM_SHIFT (19) + +#define HOST_INTEREST_SMPS_GET_MODE() (HOST_INTEREST->hi_smps_options & HI_SMPS_MODE_MASK) +#define HOST_INTEREST_SMPS_GET_DATA_THRESH() ((HOST_INTEREST->hi_smps_options & HI_SMPS_DATA_THRESH_MASK) >> HI_SMPS_DATA_THRESH_SHIFT) +#define HOST_INTEREST_SMPS_SET_DATA_THRESH(x) (((x) << HI_SMPS_DATA_THRESH_SHIFT) & HI_SMPS_DATA_THRESH_MASK) +#define HOST_INTEREST_SMPS_GET_RSSI_THRESH() ((HOST_INTEREST->hi_smps_options & HI_SMPS_RSSI_THRESH_MASK) >> HI_SMPS_RSSI_THRESH_SHIFT) +#define HOST_INTEREST_SMPS_SET_RSSI_THRESH(x) (((x) << HI_SMPS_RSSI_THRESH_SHIFT) & HI_SMPS_RSSI_THRESH_MASK) +#define HOST_INTEREST_SMPS_SET_LOWPWR_CM() ((HOST_INTEREST->hi_smps_options & HI_SMPS_LOWPWR_CM_MASK) >> HI_SMPS_LOWPWR_CM_SHIFT) +#define HOST_INTEREST_SMPS_SET_HIPWR_CM() ((HOST_INTEREST->hi_smps_options << HI_SMPS_HIPWR_CM_MASK) & HI_SMPS_HIPWR_CM_SHIFT) +#define HOST_INTEREST_SMPS_IS_AUTO_MODE_DISABLED() (HOST_INTEREST->hi_smps_options & HI_SMPS_DISABLE_AUTO_MODE) + +/* WOW Extension configuration + * + * Bit Range Meaning + * --------- -------------------------------- + * 8..0 Size of each WOW pattern (max 511) + * 15..9 Number of patterns per list (max 127) + * 17..16 Number of lists (max 4) + * 30..18 Reserved + * 31 Enabled + * + * set values (except enable) to zeros for default settings + * + * */ + +#define HI_WOW_EXT_ENABLED_MASK (1 << 31) +#define HI_WOW_EXT_NUM_LIST_SHIFT 16 +#define HI_WOW_EXT_NUM_LIST_MASK (0x3 << HI_WOW_EXT_NUM_LIST_SHIFT) +#define HI_WOW_EXT_NUM_PATTERNS_SHIFT 9 +#define HI_WOW_EXT_NUM_PATTERNS_MASK (0x7F << HI_WOW_EXT_NUM_PATTERNS_SHIFT) +#define HI_WOW_EXT_PATTERN_SIZE_SHIFT 0 +#define HI_WOW_EXT_PATTERN_SIZE_MASK (0x1FF << HI_WOW_EXT_PATTERN_SIZE_SHIFT) + +#define HI_WOW_EXT_MAKE_CONFIG(num_lists,count,size) \ + ((((num_lists) << HI_WOW_EXT_NUM_LIST_SHIFT) & HI_WOW_EXT_NUM_LIST_MASK) | \ + (((count) << HI_WOW_EXT_NUM_PATTERNS_SHIFT) & HI_WOW_EXT_NUM_PATTERNS_MASK) | \ + (((size) << HI_WOW_EXT_PATTERN_SIZE_SHIFT) & HI_WOW_EXT_PATTERN_SIZE_MASK)) + +#define HI_WOW_EXT_GET_NUM_LISTS(config) \ + (((config) & HI_WOW_EXT_NUM_LIST_MASK) >> HI_WOW_EXT_NUM_LIST_SHIFT) +#define HI_WOW_EXT_GET_NUM_PATTERNS(config) \ + (((config) & HI_WOW_EXT_NUM_PATTERNS_MASK) >> HI_WOW_EXT_NUM_PATTERNS_SHIFT) +#define HI_WOW_EXT_GET_PATTERN_SIZE(config) \ + (((config) & HI_WOW_EXT_PATTERN_SIZE_MASK) >> HI_WOW_EXT_PATTERN_SIZE_SHIFT) + +/* + * Early allocation configuration + * Support RAM bank configuration before BMI done and this eases the memory + * allocation at very early stage + * Bit Range Meaning + * --------- ---------------------------------- + * [0:3] number of bank assigned to be IRAM + * [4:15] reserved + * [16:31] magic number + * + * Note: + * 1. target firmware would check magic number and if it's a match, firmware + * would consider the bits[0:15] are valid and base on that to calculate + * the end of DRAM. Early allocation would be located at that area and + * may be reclaimed when necesary + * 2. if no magic number is found, early allocation would happen at "_end" + * symbol of ROM which is located before the app-data and might NOT be + * re-claimable. If this is adopted, link script should keep this in + * mind to avoid data corruption. + */ +#define HI_EARLY_ALLOC_MAGIC 0x6d8a +#define HI_EARLY_ALLOC_MAGIC_MASK 0xffff0000 +#define HI_EARLY_ALLOC_MAGIC_SHIFT 16 +#define HI_EARLY_ALLOC_IRAM_BANKS_MASK 0x0000000f +#define HI_EARLY_ALLOC_IRAM_BANKS_SHIFT 0 + +#define HI_EARLY_ALLOC_VALID() \ + ((((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_MAGIC_MASK) >> HI_EARLY_ALLOC_MAGIC_SHIFT) \ + == (HI_EARLY_ALLOC_MAGIC)) +#define HI_EARLY_ALLOC_GET_IRAM_BANKS() \ + (((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_IRAM_BANKS_MASK) >> HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) + +/* + * Intended for use by Host software, this macro returns the Target RAM + * address of any item in the host_interest structure. + * Example: target_addr = AR6002_HOST_INTEREST_ITEM_ADDRESS(hi_board_data); + */ +#define AR6002_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6002_HOST_INTEREST_ADDRESS))->item))) + +#define AR6003_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6003_HOST_INTEREST_ADDRESS))->item))) + +#define AR6004_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6004_HOST_INTEREST_ADDRESS))->item))) + +#define AR6006_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6006_HOST_INTEREST_ADDRESS))->item))) + +#define AR9888_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR9888_HOST_INTEREST_ADDRESS))->item))) + +#define AR6320_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6320_HOST_INTEREST_ADDRESS))->item))) + +#define AR900B_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR900B_HOST_INTEREST_ADDRESS))->item))) + +#define HOST_INTEREST_DBGLOG_IS_ENABLED() \ + (!((volatile A_UINT32)HOST_INTEREST->hi_option_flag & HI_OPTION_DISABLE_DBGLOG)) + +#define HOST_INTEREST_PKTLOG_IS_ENABLED() \ + (((volatile A_UINT32)HOST_INTEREST->hi_pktlog_num_buffers)) + +#define HOST_INTEREST_PROFILE_IS_ENABLED() \ + ((volatile A_UINT32)HOST_INTEREST->hi_option_flag & HI_OPTION_ENABLE_PROFILE) + +#define LF_TIMER_STABILIZATION_IS_ENABLED() \ + (!((volatile A_UINT32)HOST_INTEREST->hi_option_flag & HI_OPTION_NO_LFT_STBL)) + +#define IS_AMSDU_OFFLAOD_ENABLED() \ + (((volatile A_UINT32)HOST_INTEREST->hi_option_flag2 & HI_OPTION_OFFLOAD_AMSDU)) + +#define HOST_INTEREST_DFS_IS_ENABLED() \ + (((volatile A_UINT32)HOST_INTEREST->hi_option_flag2 & HI_OPTION_DFS_SUPPORT)) + +#define HOST_INTEREST_EARLY_CFG_DONE() \ + (((volatile A_UINT32)HOST_INTEREST->hi_option_flag2 & HI_OPTION_EARLY_CFG_DONE)) + +/*power save flag bit definitions*/ +#define HI_PWR_SAVE_LPL_ENABLED 0x1 +/*b1-b3 reserved*/ +/*b4-b5 : dev0 LPL type : 0 - none + 1- Reduce Pwr Search + 2- Reduce Pwr Listen*/ +/*b6-b7 : dev1 LPL type and so on for Max 8 devices*/ +#define HI_PWR_SAVE_LPL_DEV0_LSB 4 +#define HI_PWR_SAVE_LPL_DEV_MASK 0x3 +/*power save related utility macros*/ +#define HI_LPL_ENABLED() \ + ((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED)) +#define HI_DEV_LPL_TYPE_GET(_devix) \ + (HOST_INTEREST->hi_pwr_save_flags & \ + ((HI_PWR_SAVE_LPL_DEV_MASK) << \ + (HI_PWR_SAVE_LPL_DEV0_LSB + \ + (_devix)*2))) + +#define HOST_INTEREST_SMPS_IS_ALLOWED() \ + ((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK)) + +/* Convert a Target virtual address into a Target physical address */ +#define AR6002_VTOP(vaddr) ((vaddr) & 0x001fffff) +#define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff) +#define AR6004_VTOP(vaddr) (vaddr) +#define AR6006_VTOP(vaddr) (vaddr) +#define AR9888_VTOP(vaddr) (vaddr) +#define AR6320_VTOP(vaddr) (vaddr) +#define AR900B_VTOP(vaddr) (vaddr) +#define TARG_VTOP(TargetType, vaddr) \ + (((TargetType) == TARGET_TYPE_AR6002) ? AR6002_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6006) ? AR6006_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR9888) ? AR9888_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6320) ? AR6320_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR900B) ? AR900B_VTOP(vaddr) : \ + 0))))))) + +#define HOST_INTEREST_ITEM_ADDRESS(TargetType, item) \ + (((TargetType) == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6004) ? AR6004_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6006) ? AR6006_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR9888) ? AR9888_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6320) ? AR6320_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6320V2) ? AR6320_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR900B) ? AR900B_HOST_INTEREST_ITEM_ADDRESS(item) : \ + 0)))))))) + +#define AR6002_BOARD_DATA_SZ 768 +#define AR6002_BOARD_EXT_DATA_SZ 0 +#define AR6003_BOARD_DATA_SZ 1024 +/* Reserve 1024 bytes for extended board data */ +#if defined(AR6002_REV43) +#define AR6003_BOARD_EXT_DATA_SZ 1024 +#else +#define AR6003_BOARD_EXT_DATA_SZ 768 +#endif +#define AR6004_BOARD_DATA_SZ 7168 +#define AR6004_BOARD_EXT_DATA_SZ 0 +#define AR9888_BOARD_DATA_SZ 7168 +#define AR9888_BOARD_EXT_DATA_SZ 0 +#define AR6320_BOARD_DATA_SZ 8192 +#define AR6320_BOARD_EXT_DATA_SZ 0 +#define AR900B_BOARD_DATA_SZ 7168 +#define AR900B_BOARD_EXT_DATA_SZ 0 + +#define AR6003_REV3_APP_START_OVERRIDE 0x946100 +#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 +#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 +#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 +#define AR6003_REV3_RAM_RESERVE_SIZE 4096 + +#define AR6004_REV1_BOARD_DATA_ADDRESS 0x423900 +#define AR6004_REV1_RAM_RESERVE_SIZE 19456 +#define AR6004_REV1_DATASET_PATCH_ADDRESS 0x425294 + +#define AR6004_REV2_BOARD_DATA_ADDRESS 0x426400 +#define AR6004_REV2_RAM_RESERVE_SIZE 7168 +#define AR6004_REV2_DATASET_PATCH_ADDRESS 0x435294 + +#define AR6004_REV5_BOARD_DATA_ADDRESS 0x436400 +#define AR6004_REV5_RAM_RESERVE_SIZE 7168 +#define AR6004_REV5_DATASET_PATCH_ADDRESS 0x437860 + +/* Reserve 4K for OTA test script */ +#define AR6004_REV1_RAM_RESERVE_SIZE_FOR_TEST_SCRIPT 4096 +#define AR6004_REV1_TEST_SCRIPT_ADDRESS 0x422900 + +/* # of A_UINT32 entries in targregs, used by DIAG_FETCH_TARG_REGS */ +#define AR6003_FETCH_TARG_REGS_COUNT 64 +#define AR6004_FETCH_TARG_REGS_COUNT 64 +#define AR9888_FETCH_TARG_REGS_COUNT 64 +#define AR6320_FETCH_TARG_REGS_COUNT 64 +#define AR900B_FETCH_TARG_REGS_COUNT 64 + +#endif /* !__ASSEMBLER__ */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* __TARGADDRS_H__ */ diff --git a/target/inc/targcfg.h b/target/inc/targcfg.h new file mode 100644 index 0000000000..52a8d41eaf --- /dev/null +++ b/target/inc/targcfg.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __TARGCFG_H__ +#define __TARGCFG_H__ + +#if defined(ATH_TARGET) +#include /* A_UINT32 */ +#else +#include /* A_UINT32 */ +#endif + +typedef struct _targcfg_t { + A_UINT32 num_vdev; + A_UINT32 num_peers; + A_UINT32 num_peer_ast; + A_UINT32 num_peer_keys; + A_UINT32 num_peer_tid; + A_UINT32 num_mcast_keys; + A_UINT32 num_tx; + A_UINT32 num_rx; + A_UINT32 num_mgmt_tx; + A_UINT32 num_mgmt_rx; + A_UINT32 tx_chain_mask; + A_UINT32 rx_chain_mask; + A_UINT32 override; /* Override target with the values supplied above */ +} targcfg_t; + +#endif /* __TARGCFG_H__ */ diff --git a/target/inc/wal_rx_desc.h b/target/inc/wal_rx_desc.h new file mode 100644 index 0000000000..04cd50dda8 --- /dev/null +++ b/target/inc/wal_rx_desc.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WAL_RX_DESC__H_ +#define _WAL_RX_DESC__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +/* + * As this header is used by host also, + * and host will access target registers by target reg tbl, + * so disable direct-reference here for host. + * + */ +#if !defined(ATH_PERF_PWR_OFFLOAD) +/* HW rx descriptor definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +/* + * This struct defines the basic descriptor information, which is + * written by the 11ac HW MAC into the WAL's rx status descriptor + * ring. + */ +struct hw_rx_desc_base { + struct rx_attention attention; + struct rx_frag_info frag_info; + struct rx_mpdu_start mpdu_start; + struct rx_msdu_start msdu_start; + struct rx_msdu_end msdu_end; + struct rx_mpdu_end mpdu_end; + struct rx_ppdu_start ppdu_start; + struct rx_ppdu_end ppdu_end; +}; +#endif + +/* + * This struct defines the basic MSDU rx descriptor created by FW. + */ +struct fw_rx_desc_base { + union { + struct { + A_UINT8 discard : 1, + forward : 1, + any_err : 1, + dup_err : 1, reserved : 1, inspect : 1, extension : 2; + } bits; + A_UINT8 val; + } u; +}; + +#define FW_RX_DESC_DISCARD_M 0x1 +#define FW_RX_DESC_DISCARD_S 0 +#define FW_RX_DESC_FORWARD_M 0x2 +#define FW_RX_DESC_FORWARD_S 1 +#define FW_RX_DESC_MIC_ERR_M 0x4 +#define FW_RX_DESC_MIC_ERR_S 2 +#define FW_RX_DESC_DUP_ERR_M 0x8 +#define FW_RX_DESC_DUP_ERR_S 3 +#define FW_RX_DESC_INSPECT_M 0x20 +#define FW_RX_DESC_INSPECT_S 5 +#define FW_RX_DESC_EXT_M 0xc0 +#define FW_RX_DESC_EXT_S 6 + +#define FW_RX_DESC_CNT_2_BYTES(_fw_desc_cnt) (_fw_desc_cnt) + +enum { + FW_RX_DESC_EXT_NONE = 0, + FW_RX_DESC_EXT_LRO_ONLY, + FW_RX_DESC_EXT_LRO_AND_OTHER, + FW_RX_DESC_EXT_OTHER +}; + +#define FW_RX_DESC_DISCARD_GET(_var) \ + (((_var) & FW_RX_DESC_DISCARD_M) >> FW_RX_DESC_DISCARD_S) +#define FW_RX_DESC_DISCARD_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_DISCARD_S)) + +#define FW_RX_DESC_FORWARD_GET(_var) \ + (((_var) & FW_RX_DESC_FORWARD_M) >> FW_RX_DESC_FORWARD_S) +#define FW_RX_DESC_FORWARD_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_FORWARD_S)) + +#define FW_RX_DESC_INSPECT_GET(_var) \ + (((_var) & FW_RX_DESC_INSPECT_M) >> FW_RX_DESC_INSPECT_S) +#define FW_RX_DESC_INSPECT_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_INSPECT_S)) + +#define FW_RX_DESC_EXT_GET(_var) \ + (((_var) & FW_RX_DESC_EXT_M) >> FW_RX_DESC_EXT_S) +#define FW_RX_DESC_EXT_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_EXT_S)) + +#endif /* _WAL_RX_DESC__H_ */ diff --git a/target/inc/wlan_defs.h b/target/inc/wlan_defs.h new file mode 100644 index 0000000000..3588a3008b --- /dev/null +++ b/target/inc/wlan_defs.h @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2004-2010, 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLANDEFS_H__ +#define __WLANDEFS_H__ + +/* A_COMPILE_TIME_ASSERT */ +#include +#include + +/* + * This file contains WLAN definitions that may be used across both + * Host and Target software. + */ +/* + * MAX_SPATIAL_STREAM should be defined in a fwconfig_xxx.h file, + * but for now provide a default value here in case it's not defined + * in the fwconfig_xxx.h file. + */ +#ifndef MAX_SPATIAL_STREAM +#define MAX_SPATIAL_STREAM 3 +#endif + +/* + * MAX_SPATIAL_STREAM_ANY - + * what is the largest number of spatial streams that any target supports + */ +#define MAX_SPATIAL_STREAM_ANY 4 + +#ifndef CONFIG_160MHZ_SUPPORT +#define CONFIG_160MHZ_SUPPORT 0 +#endif + +typedef enum { + MODE_11A = 0, /* 11a Mode */ + MODE_11G = 1, /* 11b/g Mode */ + MODE_11B = 2, /* 11b Mode */ + MODE_11GONLY = 3, /* 11g only Mode */ + MODE_11NA_HT20 = 4, /* 11a HT20 mode */ + MODE_11NG_HT20 = 5, /* 11g HT20 mode */ + MODE_11NA_HT40 = 6, /* 11a HT40 mode */ + MODE_11NG_HT40 = 7, /* 11g HT40 mode */ + MODE_11AC_VHT20 = 8, + MODE_11AC_VHT40 = 9, + MODE_11AC_VHT80 = 10, + MODE_11AC_VHT20_2G = 11, + MODE_11AC_VHT40_2G = 12, + MODE_11AC_VHT80_2G = 13, +#if CONFIG_160MHZ_SUPPORT != 0 + MODE_11AC_VHT80_80 = 14, + MODE_11AC_VHT160 = 15, +#endif + + MODE_UNKNOWN, + MODE_UNKNOWN_NO_160MHZ_SUPPORT = 14, + MODE_UNKNOWN_160MHZ_SUPPORT = 16, + MODE_MAX = MODE_UNKNOWN, + MODE_MAX_NO_160_MHZ_SUPPORT = MODE_UNKNOWN_NO_160MHZ_SUPPORT, + MODE_MAX_160_MHZ_SUPPORT = MODE_UNKNOWN_160MHZ_SUPPORT, +} WLAN_PHY_MODE; + +#if CONFIG_160MHZ_SUPPORT == 0 +A_COMPILE_TIME_ASSERT( + mode_unknown_value_consistency_Check, + MODE_UNKNOWN == MODE_UNKNOWN_NO_160MHZ_SUPPORT); +#else +A_COMPILE_TIME_ASSERT( + mode_unknown_value_consistency_Check, + MODE_UNKNOWN == MODE_UNKNOWN_160MHZ_SUPPORT); +#endif + +typedef enum { + VHT_MODE_NONE = 0, /* NON VHT Mode, e.g., HT, DSSS, CCK */ + VHT_MODE_20M = 1, + VHT_MODE_40M = 2, + VHT_MODE_80M = 3, + VHT_MODE_160M = 4 +} VHT_OPER_MODE; + +typedef enum { + WLAN_11A_CAPABILITY = 1, + WLAN_11G_CAPABILITY = 2, + WLAN_11AG_CAPABILITY = 3, +} WLAN_CAPABILITY; + +#if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) +#define A_RATEMASK A_UINT64 +#else +#define A_RATEMASK A_UINT32 +#endif + +#define A_RATEMASK_NUM_OCTET (sizeof (A_RATEMASK)) +#define A_RATEMASK_NUM_BITS ((sizeof (A_RATEMASK)) << 3) + +#if CONFIG_160MHZ_SUPPORT != 0 +#define IS_MODE_VHT(mode) (((mode) == MODE_11AC_VHT20) || \ + ((mode) == MODE_11AC_VHT40) || \ + ((mode) == MODE_11AC_VHT80) || \ + ((mode) == MODE_11AC_VHT80_80) || \ + ((mode) == MODE_11AC_VHT160)) +#else +#define IS_MODE_VHT(mode) (((mode) == MODE_11AC_VHT20) || \ + ((mode) == MODE_11AC_VHT40) || \ + ((mode) == MODE_11AC_VHT80)) +#endif + +#define IS_MODE_VHT_2G(mode) (((mode) == MODE_11AC_VHT20_2G) || \ + ((mode) == MODE_11AC_VHT40_2G) || \ + ((mode) == MODE_11AC_VHT80_2G)) + +#define IS_MODE_11A(mode) (((mode) == MODE_11A) || \ + ((mode) == MODE_11NA_HT20) || \ + ((mode) == MODE_11NA_HT40) || \ + (IS_MODE_VHT(mode))) + +#define IS_MODE_11B(mode) ((mode) == MODE_11B) +#define IS_MODE_11G(mode) (((mode) == MODE_11G) || \ + ((mode) == MODE_11GONLY) || \ + ((mode) == MODE_11NG_HT20) || \ + ((mode) == MODE_11NG_HT40) || \ + (IS_MODE_VHT_2G(mode))) +#define IS_MODE_11GN(mode) (((mode) == MODE_11NG_HT20) || \ + ((mode) == MODE_11NG_HT40)) +#define IS_MODE_11GONLY(mode) ((mode) == MODE_11GONLY) + +enum { + /* 11a channels */ + REGDMN_MODE_11A = 0x00000001, + /* 11a turbo-only channels */ + REGDMN_MODE_TURBO = 0x00000002, + /* 11b channels */ + REGDMN_MODE_11B = 0x00000004, + /* 11g channels (OFDM only) */ + REGDMN_MODE_PUREG = 0x00000008, + /* XXX historical */ + REGDMN_MODE_11G = 0x00000008, + /* 11g+Turbo channels */ + REGDMN_MODE_108G = 0x00000020, + /* 11a+Turbo channels */ + REGDMN_MODE_108A = 0x00000040, + /* XR channels */ + REGDMN_MODE_XR = 0x00000100, + /* 11A half rate channels */ + REGDMN_MODE_11A_HALF_RATE = 0x00000200, + /* 11A quarter rate channels */ + REGDMN_MODE_11A_QUARTER_RATE = 0x00000400, + /* 11N-G HT20 channels */ + REGDMN_MODE_11NG_HT20 = 0x00000800, + /* 11N-A HT20 channels */ + REGDMN_MODE_11NA_HT20 = 0x00001000, + /* 11N-G HT40 + channels */ + REGDMN_MODE_11NG_HT40PLUS = 0x00002000, + /* 11N-G HT40 - channels */ + REGDMN_MODE_11NG_HT40MINUS = 0x00004000, + /* 11N-A HT40 + channels */ + REGDMN_MODE_11NA_HT40PLUS = 0x00008000, + /* 11N-A HT40 - channels */ + REGDMN_MODE_11NA_HT40MINUS = 0x00010000, + /* 5Ghz, VHT20 */ + REGDMN_MODE_11AC_VHT20 = 0x00020000, + /* 5Ghz, VHT40 + channels */ + REGDMN_MODE_11AC_VHT40PLUS = 0x00040000, + /* 5Ghz VHT40 - channels */ + REGDMN_MODE_11AC_VHT40MINUS = 0x00080000, + /* 5Ghz, VHT80 channels */ + REGDMN_MODE_11AC_VHT80 = 0x000100000, + REGDMN_MODE_11AC_VHT20_2G = 0x000200000, /* 2Ghz, VHT20 */ + REGDMN_MODE_11AC_VHT40_2G = 0x000400000, /* 2Ghz, VHT40 */ + REGDMN_MODE_11AC_VHT80_2G = 0x000800000, /* 2Ghz, VHT80 */ + REGDMN_MODE_11AC_VHT160 = 0x001000000, /* 5Ghz, VHT160 */ +}; + +#define REGDMN_MODE_ALL (0xFFFFFFFF) /* REGDMN_MODE_ALL is defined out of the enum + * to prevent the ARM compile "warning #66: + * enumeration value is out of int range" + * Anyway, this is a BIT-OR of all possible values. + */ + +#define REGDMN_CAP1_CHAN_HALF_RATE 0x00000001 +#define REGDMN_CAP1_CHAN_QUARTER_RATE 0x00000002 +#define REGDMN_CAP1_CHAN_HAL49GHZ 0x00000004 + +/* regulatory capabilities */ +#define REGDMN_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_STRUC_HAL_REG_CAPABILITIES */ + A_UINT32 eeprom_rd; /* regdomain value specified in EEPROM */ + A_UINT32 eeprom_rd_ext; /* regdomain */ + A_UINT32 regcap1; /* CAP1 capabilities bit map. */ + A_UINT32 regcap2; /* REGDMN EEPROM CAP. */ + A_UINT32 wireless_modes; /* REGDMN MODE */ + A_UINT32 low_2ghz_chan; + A_UINT32 high_2ghz_chan; + A_UINT32 low_5ghz_chan; + A_UINT32 high_5ghz_chan; +} HAL_REG_CAPABILITIES; + +typedef enum { + WHAL_REG_EXT_FCC_MIDBAND = 0, + WHAL_REG_EXT_JAPAN_MIDBAND = 1, + WHAL_REG_EXT_FCC_DFS_HT40 = 2, + WHAL_REG_EXT_JAPAN_NONDFS_HT40 = 3, + WHAL_REG_EXT_JAPAN_DFS_HT40 = 4, + WHAL_REG_EXT_FCC_CH_144 = 5, +} WHAL_REG_EXT_BITMAP; + +/* + * Used to update rate-control logic with the status of the tx-completion. + * In host-based implementation of the rate-control feature, this struture is used to + * create the payload for HTT message/s from target to host. + */ + +typedef struct { + A_UINT8 rateCode; + A_UINT8 flags; +} RATE_CODE; + +typedef struct { + RATE_CODE ptx_rc; /* rate code, bw, chain mask sgi */ + A_UINT8 reserved[2]; + A_UINT32 flags; /* Encodes information such as excessive + retransmission, aggregate, some info + from .11 frame control, + STBC, LDPC, (SGI and Tx Chain Mask + are encoded in ptx_rc->flags field), + AMPDU truncation (BT/time based etc.), + RTS/CTS attempt */ + A_UINT32 num_enqued; /* # of MPDUs (for non-AMPDU 1) for this rate */ + A_UINT32 num_retries; /* Total # of transmission attempt for this rate */ + A_UINT32 num_failed; /* # of failed MPDUs in A-MPDU, 0 otherwise */ + A_UINT32 ack_rssi; /* ACK RSSI: b'7..b'0 avg RSSI across all chain */ + A_UINT32 time_stamp; /* ACK timestamp (helps determine age) */ + A_UINT32 is_probe; /* Valid if probing. Else, 0 */ + A_UINT32 ba_win_size; /* b'7..b0, block Ack Window size, b'31..b8 Resvd */ + A_UINT32 failed_ba_bmap_0_31; /* failed BA bitmap 0..31 */ + A_UINT32 failed_ba_bmap_32_63; /* failed BA bitmap 32..63 */ + A_UINT32 bmap_tried_0_31; /* enqued bitmap 0..31 */ + A_UINT32 bmap_tried_32_63; /* enqued bitmap 32..63 */ +} RC_TX_DONE_PARAMS; + +#define RC_SET_TX_DONE_INFO(_dst, _rc, _f, _nq, _nr, _nf, _rssi, _ts) \ + do { \ + (_dst).ptx_rc.rateCode = (_rc).rateCode; \ + (_dst).ptx_rc.flags = (_rc).flags; \ + (_dst).flags = (_f); \ + (_dst).num_enqued = (_nq); \ + (_dst).num_retries = (_nr); \ + (_dst).num_failed = (_nf); \ + (_dst).ack_rssi = (_rssi); \ + (_dst).time_stamp = (_ts); \ + } while (0) + +#define RC_SET_TXBF_DONE_INFO(_dst, _f) \ + do { \ + (_dst).flags |= (_f); \ + } while (0) + +/* NOTE: NUM_DYN_BW and NUM_SCHED_ENTRIES cannot be changed without breaking WMI Compatibility */ +#define NUM_SCHED_ENTRIES 2 +#define NUM_DYN_BW_MAX 4 + +/* Some products only use 20/40/80; some use 20/40/80/160 */ +#ifndef NUM_DYN_BW +/* default: support up through 80 MHz */ +#define NUM_DYN_BW 3 +#endif + +#define NUM_DYN_BW_MASK 0x3 + +#define PROD_SCHED_BW_ENTRIES (NUM_SCHED_ENTRIES * NUM_DYN_BW) +typedef A_UINT8 A_RATE; + +#if NUM_DYN_BW > 4 +/* Extend rate table module first*/ +#error "Extend rate table module first" +#endif + +#define MAX_IBSS_PEERS 32 + +#if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) +typedef struct { + A_UINT32 psdu_len[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 flags[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_RATE rix[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_UINT8 tpc[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_UINT32 antmask[NUM_SCHED_ENTRIES]; + A_UINT8 num_mpdus[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 txbf_cv_len; + A_UINT32 txbf_cv_ptr; + A_UINT16 txbf_flags; + A_UINT16 txbf_cv_size; + A_UINT8 txbf_nc_idx; + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 bw_mask[NUM_SCHED_ENTRIES]; + A_UINT8 max_bw[NUM_SCHED_ENTRIES]; + A_UINT8 num_sched_entries; + A_UINT8 paprd_mask; + A_UINT8 rts_rix; + A_UINT8 sh_pream; + A_UINT8 min_spacing_1_4_us; + A_UINT8 fixed_delims; + A_UINT8 bw_in_service; + A_RATE probe_rix; + A_UINT8 num_valid_rates; + A_UINT8 rtscts_tpc; +} RC_TX_RATE_SCHEDULE; + +#else +typedef struct { + A_UINT32 psdu_len[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 flags[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_RATE rix[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT8 tpc[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT8 num_mpdus[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT32 antmask[NUM_SCHED_ENTRIES]; + A_UINT32 txbf_cv_ptr; + A_UINT16 txbf_cv_len; + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 num_valid_rates; + A_UINT8 paprd_mask; + A_UINT8 rts_rix; + A_UINT8 sh_pream; + A_UINT8 min_spacing_1_4_us; + A_UINT8 fixed_delims; + A_UINT8 bw_in_service; + A_RATE probe_rix; +} RC_TX_RATE_SCHEDULE; +#endif + +typedef struct { + A_UINT16 flags[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_RATE rix[NUM_DYN_BW * NUM_SCHED_ENTRIES]; +#ifdef DYN_TPC_ENABLE + A_UINT8 tpc[NUM_DYN_BW * NUM_SCHED_ENTRIES]; +#endif +#ifdef SECTORED_ANTENNA + A_UINT32 antmask[NUM_SCHED_ENTRIES]; +#endif + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 num_valid_rates; + A_UINT8 rts_rix; + A_UINT8 sh_pream; + A_UINT8 bw_in_service; + A_RATE probe_rix; + A_UINT8 dd_profile; +} RC_TX_RATE_INFO; + +/* + * Temporarily continue to provide the WHAL_RC_INIT_RC_MASKS def in wlan_defsh + * for older targets. + * The WHAL_RX_INIT_RC_MASKS macro def needs to be moved into ratectrl_11ac.h + * for all targets, but until this is complete, the WHAL_RC_INIT_RC_MASKS def + * will be maintained here in its old location. + */ +#if CONFIG_160MHZ_SUPPORT == 0 + +#define WHAL_RC_INIT_RC_MASKS(_rm) do { \ + _rm[WHAL_RC_MASK_IDX_NON_HT] = A_RATEMASK_OFDM_CCK; \ + _rm[WHAL_RC_MASK_IDX_HT_20] = A_RATEMASK_HT_20; \ + _rm[WHAL_RC_MASK_IDX_HT_40] = A_RATEMASK_HT_40; \ + _rm[WHAL_RC_MASK_IDX_VHT_20] = A_RATEMASK_VHT_20; \ + _rm[WHAL_RC_MASK_IDX_VHT_40] = A_RATEMASK_VHT_40; \ + _rm[WHAL_RC_MASK_IDX_VHT_80] = A_RATEMASK_VHT_80; \ +} while (0) +#endif + +/** + * strucutre describing host memory chunk. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wlan_host_memory_chunk */ + /** id of the request that is passed up in service ready */ + A_UINT32 req_id; + /** the physical address the memory chunk */ + A_UINT32 ptr; + /** size of the chunk */ + A_UINT32 size; +} wlan_host_memory_chunk; + +#define NUM_UNITS_IS_NUM_VDEVS 0x1 +#define NUM_UNITS_IS_NUM_PEERS 0x2 + +/** + * structure used by FW for requesting host memory + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_STRUC_wlan_host_mem_req */ + + /** ID of the request */ + A_UINT32 req_id; + /** size of the of each unit */ + A_UINT32 unit_size; + /** + * flags to indicate that + * the number units is dependent + * on number of resources(num vdevs num peers .. etc) + */ + A_UINT32 num_unit_info; + /* + * actual number of units to allocate . if flags in the num_unit_info + * indicate that number of units is tied to number of a particular + * resource to allocate then num_units filed is set to 0 and host + * will derive the number units from number of the resources it is + * requesting. + */ + A_UINT32 num_units; +} wlan_host_mem_req; + +typedef enum { + IGNORE_DTIM = 0x01, + NORMAL_DTIM = 0x02, + STICK_DTIM = 0x03, + AUTO_DTIM = 0x04, +} BEACON_DTIM_POLICY; + +/* During test it is observed that 6 * 400 = 2400 can + * be alloced in addition to CFG_TGT_NUM_MSDU_DESC. + * If there is any change memory requirement, this number + * needs to be revisited. */ +#define TOTAL_VOW_ALLOCABLE 2400 +#define VOW_DESC_GRAB_MAX 800 + +#define VOW_GET_NUM_VI_STA(vow_config) (((vow_config) & 0xffff0000) >> 16) +#define VOW_GET_DESC_PER_VI_STA(vow_config) ((vow_config) & 0x0000ffff) + +/***TODO!!! Get these values dynamically in WMI_READY event and use it to calculate the mem req*/ +/* size in bytes required for msdu descriptor. If it changes, this should be updated. LARGE_AP + * case is not considered. LARGE_AP is disabled when VoW is enabled.*/ +#define MSDU_DESC_SIZE 20 + +/* size in bytes required to support a peer in target. + * This obtained by considering Two tids per peer. + * peer structure = 168 bytes + * tid = 96 bytes (per sta 2 means we need 192 bytes) + * peer_cb = 16 * 2 + * key = 52 * 2 + * AST = 12 * 2 + * rate, reorder.. = 384 + * smart antenna = 50 + */ +#define MEMORY_REQ_FOR_PEER 800 + +/* + * NB: it is important to keep all the fields in the structure dword long + * so that it is easy to handle the statistics in BE host. + */ + +struct wlan_dbg_tx_stats { + /* Num HTT cookies queued to dispatch list */ + A_INT32 comp_queued; + /* Num HTT cookies dispatched */ + A_INT32 comp_delivered; + /* Num MSDU queued to WAL */ + A_INT32 msdu_enqued; + /* Num MPDU queue to WAL */ + A_INT32 mpdu_enqued; + /* Num MSDUs dropped by WMM limit */ + A_INT32 wmm_drop; + /* Num Local frames queued */ + A_INT32 local_enqued; + /* Num Local frames done */ + A_INT32 local_freed; + /* Num queued to HW */ + A_INT32 hw_queued; + /* Num PPDU reaped from HW */ + A_INT32 hw_reaped; + /* Num underruns */ + A_INT32 underrun; +#if defined(AR900B) + /* HW Paused. */ + A_UINT32 hw_paused; +#endif + /* Num PPDUs cleaned up in TX abort */ + A_INT32 tx_abort; + /* Num MPDUs requed by SW */ + A_INT32 mpdus_requed; + /* excessive retries */ + A_UINT32 tx_ko; +#if defined(AR900B) + A_UINT32 tx_xretry; +#endif + /* data hw rate code */ + A_UINT32 data_rc; + /* Scheduler self triggers */ + A_UINT32 self_triggers; + /* frames dropped due to excessive sw retries */ + A_UINT32 sw_retry_failure; + /* illegal rate phy errors */ + A_UINT32 illgl_rate_phy_err; + /* wal pdev continous xretry */ + A_UINT32 pdev_cont_xretry; + /* wal pdev continous xretry */ + A_UINT32 pdev_tx_timeout; + /* wal pdev resets */ + A_UINT32 pdev_resets; + /* frames dropped due to non-availability of stateless TIDs */ + A_UINT32 stateless_tid_alloc_failure; + /* PhY/BB underrun */ + A_UINT32 phy_underrun; + /* MPDU is more than txop limit */ + A_UINT32 txop_ovf; +#if defined(AR900B) + /* Number of Sequences posted */ + A_UINT32 seq_posted; + /* Number of Sequences failed queueing */ + A_UINT32 seq_failed_queueing; + /* Number of Sequences completed */ + A_UINT32 seq_completed; + /* Number of Sequences restarted */ + A_UINT32 seq_restarted; + /* Number of MU Sequences posted */ + A_UINT32 mu_seq_posted; + /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT (Reset,channel change) */ + A_INT32 mpdus_sw_flush; + /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ + A_INT32 mpdus_hw_filter; + /* Num MPDUs truncated by PDG (TXOP, TBTT, PPDU_duration based on rate, dyn_bw) */ + A_INT32 mpdus_truncated; + /* Num MPDUs that was tried but didn't receive ACK or BA */ + A_INT32 mpdus_ack_failed; + /* Num MPDUs that was dropped du to expiry. */ + A_INT32 mpdus_expired; + /* Num mc drops */ + /* A_UINT32 mc_drop; */ +#endif +}; + +struct wlan_dbg_rx_stats { + /* Cnts any change in ring routing mid-ppdu */ + A_INT32 mid_ppdu_route_change; + /* Total number of statuses processed */ + A_INT32 status_rcvd; + /* Extra frags on rings 0-3 */ + A_INT32 r0_frags; + A_INT32 r1_frags; + A_INT32 r2_frags; + A_INT32 r3_frags; + /* MSDUs / MPDUs delivered to HTT */ + A_INT32 htt_msdus; + A_INT32 htt_mpdus; + /* MSDUs / MPDUs delivered to local stack */ + A_INT32 loc_msdus; + A_INT32 loc_mpdus; + /* AMSDUs that have more MSDUs than the status ring size */ + A_INT32 oversize_amsdu; + /* Number of PHY errors */ + A_INT32 phy_errs; + /* Number of PHY errors drops */ + A_INT32 phy_err_drop; + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + A_INT32 mpdu_errs; +#if defined(AR900B) + /* Number of rx overflow errors. */ + A_INT32 rx_ovfl_errs; +#endif +}; + +struct wlan_dbg_mem_stats { + A_UINT32 iram_free_size; + A_UINT32 dram_free_size; +}; + +struct wlan_dbg_peer_stats { + + A_INT32 dummy; /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ +}; + +typedef struct { + A_UINT32 mcs[10]; + A_UINT32 sgi[10]; + A_UINT32 nss[4]; + A_UINT32 nsts; + A_UINT32 stbc[10]; + A_UINT32 bw[3]; + A_UINT32 pream[6]; + A_UINT32 ldpc; + A_UINT32 txbf; + A_UINT32 mgmt_rssi; + A_UINT32 data_rssi; + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; +#if defined(AR900B) + A_UINT32 rssi_chain3; +#endif +} wlan_dbg_rx_rate_info_t; + +typedef struct { + A_UINT32 mcs[10]; + A_UINT32 sgi[10]; +#if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) + A_UINT32 nss[4]; +#else + A_UINT32 nss[3]; +#endif + A_UINT32 stbc[10]; + A_UINT32 bw[3]; + A_UINT32 pream[4]; + A_UINT32 ldpc; + A_UINT32 rts_cnt; + A_UINT32 ack_rssi; +} wlan_dbg_tx_rate_info_t ; + +#define WLAN_MAX_MCS 10 + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY]; + A_UINT32 nsts; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[6]; + A_UINT32 ldpc; + A_UINT32 txbf; + A_UINT32 mgmt_rssi; + A_UINT32 data_rssi; + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; + A_UINT32 rssi_chain3; + A_UINT32 reserved[8]; +} wlan_dbg_rx_rate_info_v2_t ; + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY]; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[4]; + A_UINT32 ldpc; + A_UINT32 rts_cnt; + A_UINT32 ack_rssi; + A_UINT32 reserved[8]; +} wlan_dbg_tx_rate_info_v2_t ; + +#define WHAL_DBG_PHY_ERR_MAXCNT 18 +#define WHAL_DBG_SIFS_STATUS_MAXCNT 8 +#define WHAL_DBG_SIFS_ERR_MAXCNT 8 +#define WHAL_DBG_CMD_RESULT_MAXCNT 10 +#define WHAL_DBG_CMD_STALL_ERR_MAXCNT 4 +#define WHAL_DBG_FLUSH_REASON_MAXCNT 40 + +typedef enum { + WIFI_URRN_STATS_FIRST_PKT, + WIFI_URRN_STATS_BETWEEN_MPDU, + WIFI_URRN_STATS_WITHIN_MPDU, + WHAL_MAX_URRN_STATS +} wifi_urrn_type_t; + +typedef struct wlan_dbg_txbf_snd_stats { + A_UINT32 cbf_20[4]; + A_UINT32 cbf_40[4]; + A_UINT32 cbf_80[4]; + A_UINT32 sounding[9]; +} wlan_dbg_txbf_snd_stats_t; + +typedef struct wlan_dbg_wifi2_error_stats { + A_UINT32 urrn_stats[WHAL_MAX_URRN_STATS]; + A_UINT32 flush_errs[WHAL_DBG_FLUSH_REASON_MAXCNT]; + A_UINT32 schd_stall_errs[WHAL_DBG_CMD_STALL_ERR_MAXCNT]; + A_UINT32 schd_cmd_result[WHAL_DBG_CMD_RESULT_MAXCNT]; + A_UINT32 sifs_status[WHAL_DBG_SIFS_STATUS_MAXCNT]; + A_UINT8 phy_errs[WHAL_DBG_PHY_ERR_MAXCNT]; + A_UINT32 rx_rate_inval; +} wlan_dbg_wifi2_error_stats_t; + +typedef struct wlan_dbg_wifi2_error2_stats { + A_UINT32 schd_errs[WHAL_DBG_CMD_STALL_ERR_MAXCNT]; + A_UINT32 sifs_errs[WHAL_DBG_SIFS_ERR_MAXCNT]; +} wlan_dbg_wifi2_error2_stats_t; + +#define WLAN_DBG_STATS_SIZE_TXBF_VHT 10 +#define WLAN_DBG_STATS_SIZE_TXBF_HT 8 +#define WLAN_DBG_STATS_SIZE_TXBF_OFDM 8 +#define WLAN_DBG_STATS_SIZE_TXBF_CCK 7 + +typedef struct wlan_dbg_txbf_data_stats { + A_UINT32 tx_txbf_vht[WLAN_DBG_STATS_SIZE_TXBF_VHT]; + A_UINT32 rx_txbf_vht[WLAN_DBG_STATS_SIZE_TXBF_VHT]; + A_UINT32 tx_txbf_ht[WLAN_DBG_STATS_SIZE_TXBF_HT]; + A_UINT32 tx_txbf_ofdm[WLAN_DBG_STATS_SIZE_TXBF_OFDM]; + A_UINT32 tx_txbf_cck[WLAN_DBG_STATS_SIZE_TXBF_CCK]; +} wlan_dbg_txbf_data_stats_t; + +struct wlan_dbg_tx_mu_stats { + A_UINT32 mu_sch_nusers_2; + A_UINT32 mu_sch_nusers_3; + A_UINT32 mu_mpdus_queued_usr[4]; + A_UINT32 mu_mpdus_tried_usr[4]; + A_UINT32 mu_mpdus_failed_usr[4]; + A_UINT32 mu_mpdus_requeued_usr[4]; + A_UINT32 mu_err_no_ba_usr[4]; + A_UINT32 mu_mpdu_underrun_usr[4]; + A_UINT32 mu_ampdu_underrun_usr[4]; +}; + +struct wlan_dbg_tx_selfgen_stats { + A_UINT32 su_ndpa; + A_UINT32 su_ndp; + A_UINT32 mu_ndpa; + A_UINT32 mu_ndp; + A_UINT32 mu_brpoll_1; + A_UINT32 mu_brpoll_2; + A_UINT32 mu_bar_1; + A_UINT32 mu_bar_2; + A_UINT32 cts_burst; + A_UINT32 su_ndp_err; + A_UINT32 su_ndpa_err; + A_UINT32 mu_ndp_err; + A_UINT32 mu_brp1_err; + A_UINT32 mu_brp2_err; +}; + +typedef struct wlan_dbg_sifs_resp_stats { + A_UINT32 ps_poll_trigger; /* num ps-poll trigger frames */ + A_UINT32 uapsd_trigger; /* num uapsd trigger frames */ + A_UINT32 qb_data_trigger[2]; /* num data trigger frames; idx 0: explicit and idx 1: implicit */ + A_UINT32 qb_bar_trigger[2]; /* num bar trigger frames; idx 0: explicit and idx 1: implicit */ + A_UINT32 sifs_resp_data; /* num ppdus transmitted at SIFS interval */ + A_UINT32 sifs_resp_err; /* num ppdus failed to meet SIFS resp timing */ +} wlan_dgb_sifs_resp_stats_t; + +/** wlan_dbg_wifi2_error_stats_t is not grouped with the + * following structure as it is allocated differently and only + * belongs to whal + */ +typedef struct wlan_dbg_stats_wifi2 { + wlan_dbg_txbf_snd_stats_t txbf_snd_info; + wlan_dbg_txbf_data_stats_t txbf_data_info; + struct wlan_dbg_tx_selfgen_stats tx_selfgen; + struct wlan_dbg_tx_mu_stats tx_mu; + wlan_dgb_sifs_resp_stats_t sifs_resp_info; +} wlan_dbg_wifi2_stats_t; + +typedef struct { + wlan_dbg_rx_rate_info_t rx_phy_info; + wlan_dbg_tx_rate_info_t tx_rate_info; +} wlan_dbg_rate_info_t; + +typedef struct { + wlan_dbg_rx_rate_info_v2_t rx_phy_info; + wlan_dbg_tx_rate_info_v2_t tx_rate_info; +} wlan_dbg_rate_info_v2_t; + +struct wlan_dbg_stats { + struct wlan_dbg_tx_stats tx; + struct wlan_dbg_rx_stats rx; +#if defined(AR900B) + struct wlan_dbg_mem_stats mem; +#endif + struct wlan_dbg_peer_stats peer; +}; + +#define DBG_STATS_MAX_HWQ_NUM 10 +#define DBG_STATS_MAX_TID_NUM 20 +#define DBG_STATS_MAX_CONG_NUM 16 +struct wlan_dbg_txq_stats { + A_UINT16 num_pkts_queued[DBG_STATS_MAX_HWQ_NUM]; + A_UINT16 tid_hw_qdepth[DBG_STATS_MAX_TID_NUM]; /* WAL_MAX_TID is 20 */ + A_UINT16 tid_sw_qdepth[DBG_STATS_MAX_TID_NUM]; /* WAL_MAX_TID is 20 */ +}; + +struct wlan_dbg_tidq_stats { + A_UINT32 wlan_dbg_tid_txq_status; + struct wlan_dbg_txq_stats txq_st; +}; + +#endif /* __WLANDEFS_H__ */ diff --git a/target/inc/wlan_module_ids.h b/target/inc/wlan_module_ids.h new file mode 100644 index 0000000000..c650ef5a52 --- /dev/null +++ b/target/inc/wlan_module_ids.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_MODULE_IDS_H_ +#define _WLAN_MODULE_IDS_H_ + +/* Wlan module ids , global across all the modules */ +typedef enum { + WLAN_MODULE_ID_MIN = 0, + WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, /* 0x00 */ + WLAN_MODULE_WMI, + WLAN_MODULE_STA_PWRSAVE, + WLAN_MODULE_WHAL, + WLAN_MODULE_COEX, + WLAN_MODULE_ROAM, + WLAN_MODULE_RESMGR_CHAN_MANAGER, + WLAN_MODULE_RESMGR, + WLAN_MODULE_VDEV_MGR, + WLAN_MODULE_SCAN, + WLAN_MODULE_RATECTRL, + WLAN_MODULE_AP_PWRSAVE, + WLAN_MODULE_BLOCKACK, + WLAN_MODULE_MGMT_TXRX, + WLAN_MODULE_DATA_TXRX, + WLAN_MODULE_HTT, + WLAN_MODULE_HOST, /* 0x10 */ + WLAN_MODULE_BEACON, + WLAN_MODULE_OFFLOAD, + WLAN_MODULE_WAL, + WAL_MODULE_DE, + WLAN_MODULE_PCIELP, + WLAN_MODULE_RTT, + WLAN_MODULE_RESOURCE, + WLAN_MODULE_DCS, + WLAN_MODULE_CACHEMGR, + WLAN_MODULE_ANI, + WLAN_MODULE_P2P, + WLAN_MODULE_CSA, + WLAN_MODULE_NLO, + WLAN_MODULE_CHATTER, + WLAN_MODULE_WOW, + WLAN_MODULE_WAL_VDEV, /* 0x20 */ + WLAN_MODULE_WAL_PDEV, + WLAN_MODULE_TEST, + WLAN_MODULE_STA_SMPS, + WLAN_MODULE_SWBMISS, + WLAN_MODULE_WMMAC, + WLAN_MODULE_TDLS, + WLAN_MODULE_HB, + WLAN_MODULE_TXBF, + WLAN_MODULE_BATCH_SCAN, + WLAN_MODULE_THERMAL_MGR, + WLAN_MODULE_PHYERR_DFS, + WLAN_MODULE_RMC, + WLAN_MODULE_STATS, + WLAN_MODULE_NAN, + WLAN_MODULE_IBSS_PWRSAVE, + WLAN_MODULE_HIF_UART, /* 0x30 */ + WLAN_MODULE_LPI, + WLAN_MODULE_EXTSCAN, + WLAN_MODULE_UNIT_TEST, + WLAN_MODULE_MLME, + WLAN_MODULE_SUPPL, + WLAN_MODULE_ERE, + WLAN_MODULE_OCB, + WLAN_MODULE_RSSI_MONITOR, + WLAN_MODULE_WPM, + WLAN_MODULE_CSS, /* 0x3a */ + WLAN_MODULE_PPS, /* 0x3b */ + WLAN_MODULE_SCAN_CH_PREDICT, /* 0x3c */ + WLAN_MODULE_MAWC, + WLAN_MODULE_CMC_QMIC, /* 0x3e */ + WLAN_MODULE_EGAP, /* 0x3f */ + + WLAN_MODULE_ID_MAX, + WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, +} WLAN_MODULE_ID; + +#endif /* _WLAN_MODULE_IDS_H_ */ diff --git a/target/inc/wlan_tgt_def_config.h b/target/inc/wlan_tgt_def_config.h new file mode 100644 index 0000000000..2bcf796f9e --- /dev/null +++ b/target/inc/wlan_tgt_def_config.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * set of default target config , that can be over written by platform + */ + +/* + * default limit of 8 VAPs per device. + */ +/* Rome PRD support 3 vdevs */ +#define CFG_TGT_NUM_VDEV 3 + +/* + * We would need 1 AST entry per peer. Scale it by a factor of 2 to minimize hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 0 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_AST_SKID_LIMIT 16 + +/* + * total number of peers per device. + */ +#define CFG_TGT_NUM_PEERS 14 + +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ + +/* + * The current firmware implementation requires the number of offload peers + * should be (number of vdevs + 1). + + * The reason for this is the firmware clubbed the self peer and offload peer + * in the same pool. So if the firmware wanted to support n vdevs then the + * number of offload peer must be n+1 of which n buffers will be used for + * self peer and the remaining 1 is used for offload peer to support chatter + * mode for single STA. + + * Technically the macro should be 1 however the current firmware requires n+1. + + * TODO: This MACRO need to be modified in the future, if the firmware modified + * to allocate buffers for self peer and offload peer independently. + */ + +#define CFG_TGT_NUM_OFFLOAD_PEERS (CFG_TGT_NUM_VDEV+1) + +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 4 + +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of data TX and RX TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2)) +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x7 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x7 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of VDEV offload Roaming to support */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x2 + +/* default: mcast->ucast disabled if ATH_SUPPORT_MCAST2UCAST not defined */ +#ifndef ATH_SUPPORT_MCAST2UCAST +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ +#else +/* (for testing) small multicast group membership table enabled */ +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 4 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 16 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 2 +#endif + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 5 +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 + +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#define CFG_TGT_NUM_MSDU_DESC (1024 + 32) + +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 10 + +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 2 + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 32 + +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * resv for furture use, bit 30 is used for fix tpc, bit0-3 for Power save balance + */ +#define CFG_TGT_DEFAULT_GTX_USR_CFG 0xa +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/target/inc/wmi.h b/target/inc/wmi.h new file mode 100644 index 0000000000..6645ebac19 --- /dev/null +++ b/target/inc/wmi.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2004-2010, 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the definitions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all the + * commands and events. Commands are messages from the host to the WM. + * Events and Replies are messages from the WM to the host. + * + * Ownership of correctness in regards to commands + * belongs to the host driver and the WMI is not required to validate + * parameters for value, proper range, or any other checking. + * + */ + +#ifndef _WMI_H_ +#define _WMI_H_ + +#include "wlan_defs.h" +#include "wmix.h" +#include "wmi_unified.h" +#include "wmi_tlv_helper.h" +#include "wmi_tlv_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HTC_PROTOCOL_VERSION 0x0002 + +#define WMI_PROTOCOL_VERSION 0x0002 + +#define WMI_MODE_MAX 8 +#define WMI_MAX_RATE_MASK 6 + +PREPACK struct host_app_area_s { + A_UINT32 wmi_protocol_ver; +} POSTPACK; + +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#undef GET_FIELD +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) +#undef SET_FIELD +#define SET_FIELD(_addr, _f, _val) \ + (*((A_UINT32 *)(_addr) + WO(_f)) = \ + (*((A_UINT32 *)(_addr) + WO(_f)) & ~_f ## _MASK) | SM(_val, _f)) + +#define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \ + GET_FIELD(_msg_buf, _msg_type ## _ ## _f) + +#define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ + SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) + +#define WMI_EP_APASS 0x0 +#define WMI_EP_LPASS 0x1 +#define WMI_EP_SENSOR 0x2 + +/* + * Control Path + */ +typedef PREPACK struct { + A_UINT32 commandId : 24, reserved : 2, /* used for WMI endpoint ID */ + plt_priv : 6; /* platform private */ +} POSTPACK WMI_CMD_HDR; /* used for commands and events */ + +#define WMI_CMD_HDR_COMMANDID_LSB 0 +#define WMI_CMD_HDR_COMMANDID_MASK 0x00ffffff +#define WMI_CMD_HDR_COMMANDID_OFFSET 0x00000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_MASK 0x03000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET 24 +#define WMI_CMD_HDR_PLT_PRIV_LSB 24 +#define WMI_CMD_HDR_PLT_PRIV_MASK 0xff000000 +#define WMI_CMD_HDR_PLT_PRIV_OFFSET 0x00000000 + +/* + * List of Commnands + */ +typedef enum { + WMI_EXTENSION_CMDID, /* used in wmi_svc.c / * Non-wireless extensions * / */ + WMI_IGNORE_CMDID, /* used in wlan_wmi.c */ +} WMI_COMMAND_ID; + +typedef enum { + NONE_CRYPT = 0x01, + WEP_CRYPT = 0x02, + TKIP_CRYPT = 0x04, + AES_CRYPT = 0x08, +#ifdef WAPI_ENABLE + WAPI_CRYPT = 0x10, +#endif /*WAPI_ENABLE */ +} CRYPTO_TYPE; + +#define WMI_MAX_SSID_LEN 32 + +/* + * WMI_SET_PMK_CMDID + */ +#define WMI_PMK_LEN 32 + +/* + * WMI_ADD_CIPHER_KEY_CMDID + */ +typedef enum { + PAIRWISE_USAGE = 0x00, + GROUP_USAGE = 0x01, + TX_USAGE = 0x02, /* default Tx Key - Static WEP only */ +} KEY_USAGE; + +/* + * List of Events (target to host) + */ +typedef enum { + WMI_EXTENSION_EVENTID, /* wmi_profhook.c and umac_wmi_events.c */ +} WMI_EVENT_ID; + +typedef enum { + WMI_11A_CAPABILITY = 1, + WMI_11G_CAPABILITY = 2, + WMI_11AG_CAPABILITY = 3, + WMI_11NA_CAPABILITY = 4, + WMI_11NG_CAPABILITY = 5, + WMI_11NAG_CAPABILITY = 6, + WMI_11AC_CAPABILITY = 7, + /* END CAPABILITY */ + WMI_11N_CAPABILITY_OFFSET = + (WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY), +} WMI_PHY_CAPABILITY; + +/* Deprectated, need clean up */ +#define WMI_MAX_RX_META_SZ (12) + +typedef PREPACK struct { + A_INT8 rssi; + A_UINT8 info; /* usage of 'info' field(8-bit): + * b1:b0 - WMI_MSG_TYPE + * b4:b3:b2 - UP(tid) + * b5 - Used in AP mode. More-data in tx dir, PS in rx. + * b7:b6 - Dot3 header(0), + * Dot11 Header(1), + * ACL data(2) + */ + + A_UINT16 info2; /* usage of 'info2' field(16-bit): + * b11:b0 - seq_no + * b12 - A-MSDU? + * b15:b13 - META_DATA_VERSION 0 - 7 + */ + A_UINT16 info3; /* b3:b2:b1:b0 - device id + * b4 - Used in AP mode. uAPSD trigger in rx, EOSP in tx + * b7:b5 - unused? + * b15:b8 - pad before data start(irrespective of meta version) + */ +} POSTPACK WMI_DATA_HDR; + +#ifdef __cplusplus +} +#endif +#endif /* _WMI_H_ */ diff --git a/target/inc/wmi_services.h b/target/inc/wmi_services.h new file mode 100644 index 0000000000..b2b1dfa71e --- /dev/null +++ b/target/inc/wmi_services.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * This file defines WMI services bitmap and the set of WMI services . + * defines macrso to set/clear/get different service bits from the bitmap. + * the service bitmap is sent up to the host via WMI_READY command. + * + */ + +#ifndef _WMI_SERVICES_H_ +#define _WMI_SERVICES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */ + WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */ + WMI_SERVICE_ROAM_SCAN_OFFLOAD, /* roam scan offload */ + WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */ + WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */ + WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */ + WMI_SERVICE_AP_UAPSD, /* uapsd on AP */ + WMI_SERVICE_AP_DFS, /* DFS on AP */ + WMI_SERVICE_11AC, /* supports 11ac */ + WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host */ + WMI_SERVICE_PHYERR, /* PHY error */ + WMI_SERVICE_BCN_FILTER, /* Beacon filter support */ + WMI_SERVICE_RTT, /* RTT (round trip time) support */ + WMI_SERVICE_WOW, /* WOW Support */ + WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */ + WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */ + WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support for STA vdev*/ + WMI_SERVICE_NLO, /* Network list offload service */ + WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */ + WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */ + WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */ + WMI_SERVICE_CHATTER, /* Chatter service */ + WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */ + WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */ + WMI_SERVICE_FORCE_FW_HANG, /* Service to test the firmware recovery mechanism */ + WMI_SERVICE_GPIO, /* GPIO service */ + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */ + WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* Basic version of station UAPSD AC Trigger Generation Method with + * variable tigger periods (service, delay, and suspend intervals) */ + WMI_STA_UAPSD_VAR_AUTO_TRIG, /* Station UAPSD AC Trigger Generation Method with variable + * trigger periods (service, delay, and suspend intervals) */ + WMI_SERVICE_STA_KEEP_ALIVE, /* Serivce to support the STA KEEP ALIVE mechanism */ + WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */ + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, /* detect out-of-sync sleeping stations */ + WMI_SERVICE_EARLY_RX, /* adaptive early-rx feature */ + WMI_SERVICE_STA_SMPS, /* STA MIMO-PS */ + WMI_SERVICE_FWTEST, /* Firmware test service */ + WMI_SERVICE_STA_WMMAC, /* STA WMMAC */ + WMI_SERVICE_TDLS, /* TDLS support */ + WMI_SERVICE_BURST, /* SIFS spaced burst support */ + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, /* Dynamic beaocn interval change for SAP/P2p GO in MCC scenario */ + WMI_SERVICE_ADAPTIVE_OCS, /* Service to support adaptive off-channel scheduler */ + WMI_SERVICE_BA_SSN_SUPPORT, /* target will provide Sequence number for the peer/tid combo */ + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, + WMI_SERVICE_WLAN_HB, /* wlan HB service */ + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, /* support LTE/WLAN antenna sharing */ + WMI_SERVICE_BATCH_SCAN, /*Service to support batch scan */ + WMI_SERVICE_QPOWER, /* QPower service */ + WMI_SERVICE_PLMREQ, + WMI_SERVICE_THERMAL_MGMT, + WMI_SERVICE_RMC, /* RMC support */ + WMI_SERVICE_MHF_OFFLOAD, /* multi-hop forwarding offload */ + WMI_SERVICE_COEX_SAR, /* target support SAR tx limit from WMI_PDEV_PARAM_TXPOWER_LIMITxG */ + WMI_SERVICE_BCN_TXRATE_OVERRIDE, /* Will support the bcn/prb rsp rate override */ + WMI_SERVICE_NAN, /* Neighbor Awareness Network */ + WMI_SERVICE_L1SS_STAT, /* L1SS statistics counter report */ + WMI_SERVICE_ESTIMATE_LINKSPEED, /* Linkspeed Estimation per peer */ + WMI_SERVICE_OBSS_SCAN, /* Service to support OBSS scan */ + WMI_SERVICE_TDLS_OFFCHAN, /* TDLS off channel support */ + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, /* TDLS UAPSD Buffer STA support */ + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, /* TDLS UAPSD Sleep STA support */ + WMI_SERVICE_IBSS_PWRSAVE, /* IBSS power save support */ + WMI_SERVICE_LPASS, /*Service to support LPASS */ + WMI_SERVICE_EXTSCAN, /* Extended Scans */ + WMI_SERVICE_D0WOW, /* D0-WOW Support */ + WMI_SERVICE_HSOFFLOAD, /* Hotspot offload feature Support */ + WMI_SERVICE_ROAM_HO_OFFLOAD, /* roam handover offload */ + WMI_SERVICE_RX_FULL_REORDER, /* target-based Rx full reorder */ + WMI_SERVICE_DHCP_OFFLOAD, /* DHCP offload support */ + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, /* STA RX DATA offload to IPA support */ + WMI_SERVICE_MDNS_OFFLOAD, /* mDNS responder offload support */ + WMI_SERVICE_SAP_AUTH_OFFLOAD, /* softap auth offload */ + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT, /* Dual Band Simultaneous support */ + WMI_SERVICE_OCB, /* OCB mode support */ + WMI_SERVICE_AP_ARPNS_OFFLOAD, /* arp offload support for ap mode vdev */ + WMI_SERVICE_PER_BAND_CHAINMASK_SUPPORT, /* Per band chainmask support */ + WMI_SERVICE_PACKET_FILTER_OFFLOAD, /* Per vdev packet filters */ + WMI_SERVICE_MGMT_TX_HTT, /* Mgmt Tx via HTT interface */ + WMI_SERVICE_MGMT_TX_WMI, /* Mgmt Tx via WMI interface */ + WMI_SERVICE_EXT_MSG, /* WMI_SERVICE_READY_EXT msg follows */ + WMI_SERVICE_MAWC, /* Motion Aided WiFi Connectivity (MAWC)*/ + + /* target will send ASSOC_CONF after ASSOC_CMD is processed */ + WMI_SERVICE_PEER_ASSOC_CONF, + + /* enhanced green ap support */ + WMI_SERVICE_EGAP, + /* FW supports 11W PMF Offload for STA */ + WMI_SERVICE_STA_PMF_OFFLOAD, + + WMI_MAX_SERVICE = 128 /* max service */ +} WMI_SERVICE; + +#define WMI_SERVICE_BM_SIZE ((WMI_MAX_SERVICE + sizeof(A_UINT32)- 1)/sizeof(A_UINT32)) + +/* + * depreciated the name WMI_SERVICE_ROAM_OFFLOAD, but here to help compiling + * with old host driver + */ +#define WMI_SERVICE_ROAM_OFFLOAD WMI_SERVICE_ROAM_SCAN_OFFLOAD + +/* + * turn on the WMI service bit corresponding to the WMI service. + */ +#define WMI_SERVICE_ENABLE(pwmi_svc_bmap,svc_id) \ + ( (pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] |= \ + (1 << ((svc_id)%(sizeof(A_UINT32)))) ) + +#define WMI_SERVICE_DISABLE(pwmi_svc_bmap,svc_id) \ + ( (pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] &= \ + ( ~(1 << ((svc_id)%(sizeof(A_UINT32)))) ) ) + +#define WMI_SERVICE_IS_ENABLED(pwmi_svc_bmap,svc_id) \ + ( ((pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] & \ + (1 << ((svc_id)%(sizeof(A_UINT32)))) ) != 0) + +#ifdef __cplusplus +} +#endif +#endif /*_WMI_SERVICES_H_*/ diff --git a/target/inc/wmi_tlv_defs.h b/target/inc/wmi_tlv_defs.h new file mode 100644 index 0000000000..081de734b2 --- /dev/null +++ b/target/inc/wmi_tlv_defs.h @@ -0,0 +1,2996 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WMI_TLV_DEFS_H_ +#define _WMI_TLV_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name) \ + is_allocated_ ## elem_name + +#define WMITLV_FIELD_NUM_OF(elem_name) \ + num_ ## elem_name + +/* Define the structure typedef for the TLV parameters of each cmd/event */ +#define WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) \ + wmi_cmd_event_id ## _param_tlvs + +/* + * The following macro WMITLV_OP_* are created by the macro WMITLV_ELEM(). + */ +/* macro to define the TLV name in the correct order. When (op==TAG_ORDER) */ +#define WMITLV_OP_TAG_ORDER_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id ## _tlv_order_ ## elem_name, + +/* macro to define the TLV name with the TLV Tag value. When (op==TAG_ID) */ +#define WMITLV_OP_TAG_ID_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id ## _tlv_tag_ ## elem_name = elem_tlv_tag, + +/* macro to define the TLV name with the TLV structure size. May not be accurate when variable length. When (op==TAG_SIZEOF) */ +#define WMITLV_OP_TAG_SIZEOF_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id ## _sizeof_ ## elem_name = sizeof(elem_struc_type), + +/* macro to define the TLV name with value indicating whether the TLV is variable length. When (op==TAG_VAR_SIZED) */ +#define WMITLV_OP_TAG_VAR_SIZED_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id ## _var_sized_ ## elem_name = var_len, + +/* macro to define the TLV name with value indicating the fixed array size. When (op==TAG_ARR_SIZE) */ +#define WMITLV_OP_TAG_ARR_SIZE_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id ## _arr_size_ ## elem_name = arr_size, + +/* + * macro to define afew fields associated to a TLV. For example, a structure pointer with the TLV name. + * This macro is expand from WMITLV_ELEM(op) when (op==STRUCT_FIELD). + * NOTE: If this macro is changed, then "mirror" structure wmitlv_cmd_param_info + * should be updated too. + */ +#define WMITLV_OP_STRUCT_FIELD_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + elem_struc_type *elem_name; \ + A_UINT32 WMITLV_FIELD_NUM_OF(elem_name); \ + A_UINT32 WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name); + +/* + * A "mirror" structure that contains the fields that is created by the + * macro WMITLV_OP_STRUCT_FIELD_macro. + * NOTE: you should modify this structure and WMITLV_OP_STRUCT_FIELD_macro + * so that they both has the same kind of fields. + */ +typedef struct { + void *tlv_ptr; /* Pointer to the TLV Buffer. But the "real" one will have the right type instead of void. */ + A_UINT32 num_elements; /* Number of elements. For non-array, this is one. For array, this is the number of elements. */ + A_UINT32 buf_is_allocated; /* Boolean flag to indicate that a new buffer is allocated for this TLV. */ +} wmitlv_cmd_param_info; + +/* + * NOTE TRICKY MACRO: + * WMITLV_ELEM is re-defined to a "op" specific macro. + * Eg. WMITLV_OP_TAG_ORDER_macro is created for the op_type=TAG_ORDER. + */ +#define WMITLV_ELEM(wmi_cmd_event_id, op_type, param_ptr, param_len, elem_tlv_tag, elem_struc_type, elem_name, var_len) \ + WMITLV_OP_ ## op_type ## _macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, WMITLV_ARR_SIZE_INVALID) +/* + * WMITLV_FXAR (FiX ARray) is similar to WMITLV_ELEM except it has an extra parameter for the fixed number of elements. + * It is re-defined to a "op" specific macro. + * Eg. WMITLV_OP_TAG_ORDER_macro is created for the op_type=TAG_ORDER. + */ +#define WMITLV_FXAR(wmi_cmd_event_id, op_type, param_ptr, param_len, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + WMITLV_OP_ ## op_type ## _macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) + +#define WMITLV_TABLE(id,op,buf,len) WMITLV_TABLE_ ## id(id,op,buf,len) + +/* + * This macro will create various enumerations and structures to describe the TLVs for + * the given Command/Event ID. + * + * For example, the following is for WMI_SERVICE_READY_EVENTID: + * #define WMITLV_TABLE_WMI_SERVICE_READY_EVENTID(id,op,buf,len) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, wmi_service_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, HAL_REG_CAPABILITIES, hal_reg_capabilities, WMITLV_SIZE_FIX) \ + * WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wmi_service_bitmap, WMITLV_SIZE_FIX, WMI_SERVICE_BM_SIZE) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_host_mem_req, mem_reqs, WMITLV_SIZE_VAR) + * WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EVENTID); + * This macro will create the following text: + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_tlv_order_wmi_service_ready_event_fixed_param, + * WMI_SERVICE_READY_EVENTID_tlv_order_hal_reg_capabilities, + * WMI_SERVICE_READY_EVENTID_tlv_order_wmi_service_bitmap, + * WMI_SERVICE_READY_EVENTID_tlv_order_mem_reqs, + * WMI_TLV_HLPR_NUM_TLVS_FOR_WMI_SERVICE_READY_EVENTID + * } WMI_SERVICE_READY_EVENTID_TAG_ID_enum_type; + * //NOTE: WMI_TLV_HLPR_NUM_TLVS_FOR_WMI_SERVICE_READY_EVENTID is the number of TLVs. + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_tlv_tag_wmi_service_ready_event_fixed_param = WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, + * WMI_SERVICE_READY_EVENTID_tlv_tag_hal_reg_capabilities = WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, + * WMI_SERVICE_READY_EVENTID_tlv_tag_wmi_service_bitmap = WMITLV_TAG_ARRAY_UINT32, + * WMI_SERVICE_READY_EVENTID_tlv_tag_mem_reqs = WMITLV_TAG_ARRAY_STRUC, + * } WMI_SERVICE_READY_EVENTID_TAG_ORDER_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_sizeof_wmi_service_ready_event_fixed_param = sizeof(wmi_service_ready_event_fixed_param), + * WMI_SERVICE_READY_EVENTID_sizeof_hal_reg_capabilities = sizeof(HAL_REG_CAPABILITIES), + * WMI_SERVICE_READY_EVENTID_sizeof_wmi_service_bitmap = sizeof(A_UINT32), + * WMI_SERVICE_READY_EVENTID_sizeof_mem_reqs = sizeof(wlan_host_mem_req), + * } WMI_SERVICE_READY_EVENTID_TAG_SIZEOF_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_var_sized_wmi_service_ready_event_fixed_param = WMITLV_SIZE_FIX, + * WMI_SERVICE_READY_EVENTID_var_sized_hal_reg_capabilities = WMITLV_SIZE_FIX, + * WMI_SERVICE_READY_EVENTID_var_sized_wmi_service_bitmap = WMITLV_SIZE_VAR, + * WMI_SERVICE_READY_EVENTID_var_sized_mem_reqs = WMITLV_SIZE_VAR, + * } WMI_SERVICE_READY_EVENTID_TAG_VAR_SIZED_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_arr_size_wmi_service_ready_event_fixed_param = WMITLV_ARR_SIZE_INVALID, + * WMI_SERVICE_READY_EVENTID_arr_size_hal_reg_capabilities = WMITLV_ARR_SIZE_INVALID, + * WMI_SERVICE_READY_EVENTID_arr_size_wmi_service_bitmap = WMI_SERVICE_BM_SIZE, + * WMI_SERVICE_READY_EVENTID_arr_size_mem_reqs = WMITLV_ARR_SIZE_INVALID, + * } WMI_SERVICE_READY_EVENTID_TAG_ARR_SIZE_enum_type; + * + * typedef struct { + * wmi_service_ready_event_fixed_param *fixed_param; + * A_UINT32 num_fixed_param; + * A_UINT32 is_allocated_fixed_param; + * HAL_REG_CAPABILITIES *hal_reg_capabilities; + * A_UINT32 num_hal_reg_capabilities; + * A_UINT32 is_allocated_hal_reg_capabilities; + * A_UINT32 *wmi_service_bitmap; + * A_UINT32 num_wmi_service_bitmap; + * A_UINT32 is_allocated_wmi_service_bitmap; + * wlan_host_mem_req *mem_reqs; + * A_UINT32 num_mem_reqs; + * A_UINT32 is_allocated_mem_reqs; + * + * } WMI_SERVICE_READY_EVENTID_param_tlvs; + * + */ + +#define WMITLV_CREATE_PARAM_STRUC(wmi_cmd_event_id) \ + typedef enum { \ + WMITLV_TABLE(wmi_cmd_event_id, TAG_ORDER, NULL, 0) \ + WMI_TLV_HLPR_NUM_TLVS_FOR_ ## wmi_cmd_event_id \ + } wmi_cmd_event_id ## _TAG_ORDER_enum_type; \ + \ + typedef struct { \ + WMITLV_TABLE(wmi_cmd_event_id, STRUCT_FIELD, NULL, 0) \ + } WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS (wmi_cmd_event_id); \ + +/** Enum list of TLV Tags for each parameter structure type. */ +typedef enum { + /* 0 to 15 is reserved */ + WMITLV_TAG_LAST_RESERVED = 15, + WMITLV_TAG_FIRST_ARRAY_ENUM, /* First entry of ARRAY type tags */ + WMITLV_TAG_ARRAY_UINT32 = WMITLV_TAG_FIRST_ARRAY_ENUM, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_TAG_ARRAY_STRUC, + WMITLV_TAG_ARRAY_FIXED_STRUC, + WMITLV_TAG_LAST_ARRAY_ENUM = 31, /* Last entry of ARRAY type tags */ + WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, + WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, + WMITLV_TAG_STRUC_wlan_host_mem_req, + WMITLV_TAG_STRUC_wmi_ready_event_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr, + WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr, + WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_event_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INFO_SECTION_BITMAP, + WMITLV_TAG_STRUC_wmi_rtt_event_header, + WMITLV_TAG_STRUC_wmi_rtt_error_report_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rtt_meas_event_fixed_param, + WMITLV_TAG_STRUC_wmi_echo_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param, + WMITLV_TAG_STRUC_wmi_csa_event_fixed_param, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, + WMITLV_TAG_STRUC_wmi_igtk_info, + WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param, + WMITLV_TAG_STRUC_ath_dcs_cw_int, + WMITLV_TAG_STRUC_ath_dcs_wlan_int_stat, + WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t, + WMITLV_TAG_STRUC_wmi_wlan_profile_t, + WMITLV_TAG_STRUC_wmi_pdev_qvit_event_fixed_param, + WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tim_info, + WMITLV_TAG_STRUC_wmi_p2p_noa_info, + WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param, + WMITLV_TAG_STRUC_wmi_avoid_freq_range_desc, + WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param, + WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_TAG_STRUC_wlan_host_memory_chunk, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wmm_params, + WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor, + WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vht_rate_set, + WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param, + WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, + WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_rate_retry_sched_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_rtt_measreq_head, + WMITLV_TAG_STRUC_wmi_rtt_measreq_body, + WMITLV_TAG_STRUC_wmi_rtt_tsf_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_TAG_STRUC_nlo_configured_parameters, + WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bcn_tx_hdr, + WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr, + WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_profile, + WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T, + WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD, + WMITLV_TAG_STRUC_WMI_scan_update_request_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_pkt_coalescing_filter, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_event, + WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param, + WMITLV_TAG_STRUC_wmi_upload_h_hdr, + WMITLV_TAG_STRUC_wmi_capture_h_event_hdr, + WMITLV_TAG_STRUC_WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, + WMITLV_TAG_STRUC_wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_sub_struct_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_event_sub_struct_param, + WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mcc_sched_sta_traffic_stats, + WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_ind_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_pause_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rfkill_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_radar_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_result_scan_list, + WMITLV_TAG_STRUC_wmi_batch_scan_result_network_info, + WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_result_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info, + WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_cmd_param, + WMITLV_TAG_STRUC_wmi_nan_event_hdr, + WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_data_container_event_fixed_param, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_estimated_linkspeed_event_fixed_param, + WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_routing_table_entry, + WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_stats_ext_event_fixed_param, + WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_led_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param, + WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, + WMITLV_TAG_STRUC_WOW_IOAC_PKT_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IOAC_TMR_PATTERN_T, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_KEEPALIVE_T, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_radio_link_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_channel_stats, + WMITLV_TAG_STRUC_wmi_radio_link_stats, + WMITLV_TAG_STRUC_wmi_rate_stats, + WMITLV_TAG_STRUC_wmi_peer_link_stats, + WMITLV_TAG_STRUC_wmi_wmm_ac_stats, + WMITLV_TAG_STRUC_wmi_iface_link_stats, + WMITLV_TAG_STRUC_wmi_lpi_mgmt_snooping_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_start_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_stop_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_result_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_state_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_bssid_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_descriptor_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_rssi_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_result_bssid_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_cache_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_monitor_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_monitor_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param, + WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_handoff_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_rate_ht_info, + WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param, + WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tpc_chainmask_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ric_tspec, + WMITLV_TAG_STRUC_wmi_tpc_chainmask_config, + WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_key_material, + WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param, + WMITLV_TAG_STRUC_wmi_apfind_cmd_param, + WMITLV_TAG_STRUC_wmi_apfind_event_hdr, + WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param, /* DEPRECATED */ + WMITLV_TAG_STRUC_wmi_ocb_set_sched_event_fixed_param, /* DEPRECATED */ + WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_channel, + WMITLV_TAG_STRUC_wmi_ocb_schedule_element, + WMITLV_TAG_STRUC_wmi_dcc_ndl_stats_per_channel, + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_TAG_STRUC_wmi_qos_parameter, + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, + WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_passpoint_event_hdr, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param, + WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, + WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param, + WMITLV_TAG_STRUC_wmi_fw_mem_dump_params, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, + WMITLV_TAG_STRUC_wmi_rssi_breach_event_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INITIAL_WAKEUP_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_txrx_streams, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_vdev_mac_entry, + WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param, + WMITLV_TAG_STRUC_WOW_IOAC_SOCK_PATTERN_T, + WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_event_log_supported_event_fixed_params, + WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, + WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_event_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_earlystop_rssi_thres_param, + WMITLV_TAG_STRUC_wmi_service_ready_ext_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_event_fixed_param, + WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, +} WMITLV_TAG_ID; + +/* + * IMPORTANT: Please add _ALL_ WMI Commands Here. + * Otherwise, these WMI TLV Functions will be process them. + */ +#define WMITLV_ALL_CMD_LIST(OP) \ + OP(WMI_INIT_CMDID) \ + OP(WMI_PEER_CREATE_CMDID) \ + OP(WMI_PEER_DELETE_CMDID) \ + OP(WMI_PEER_FLUSH_TIDS_CMDID) \ + OP(WMI_PEER_SET_PARAM_CMDID) \ + OP(WMI_STA_POWERSAVE_MODE_CMDID) \ + OP(WMI_STA_POWERSAVE_PARAM_CMDID) \ + OP(WMI_STA_DTIM_PS_METHOD_CMDID) \ + OP(WMI_PDEV_SET_REGDOMAIN_CMDID) \ + OP(WMI_PEER_TID_ADDBA_CMDID) \ + OP(WMI_PEER_TID_DELBA_CMDID) \ + OP(WMI_PDEV_FTM_INTG_CMDID) \ + OP(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID) \ + OP(WMI_WOW_ENABLE_CMDID) \ + OP(WMI_RMV_BCN_FILTER_CMDID) \ + OP(WMI_ROAM_SCAN_MODE) \ + OP(WMI_ROAM_SCAN_RSSI_THRESHOLD) \ + OP(WMI_ROAM_SCAN_PERIOD) \ + OP(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD) \ + OP(WMI_START_SCAN_CMDID) \ + OP(WMI_VDEV_PLMREQ_START_CMDID) \ + OP(WMI_VDEV_PLMREQ_STOP_CMDID) \ + OP(WMI_PDEV_SET_CHANNEL_CMDID) \ + OP(WMI_PDEV_SET_WMM_PARAMS_CMDID) \ + OP(WMI_VDEV_START_REQUEST_CMDID) \ + OP(WMI_VDEV_RESTART_REQUEST_CMDID) \ + OP(WMI_P2P_GO_SET_BEACON_IE) \ + OP(WMI_GTK_OFFLOAD_CMDID) \ + OP(WMI_SCAN_CHAN_LIST_CMDID) \ + OP(WMI_STA_UAPSD_AUTO_TRIG_CMDID) \ + OP(WMI_PRB_TMPL_CMDID) \ + OP(WMI_BCN_TMPL_CMDID) \ + OP(WMI_VDEV_INSTALL_KEY_CMDID) \ + OP(WMI_PEER_ASSOC_CMDID) \ + OP(WMI_ADD_BCN_FILTER_CMDID) \ + OP(WMI_STA_KEEPALIVE_CMDID) \ + OP(WMI_SET_ARP_NS_OFFLOAD_CMDID) \ + OP(WMI_P2P_SET_VENDOR_IE_DATA_CMDID) \ + OP(WMI_AP_PS_PEER_PARAM_CMDID) \ + OP(WMI_WLAN_PROFILE_TRIGGER_CMDID) \ + OP(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID) \ + OP(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID) \ + OP(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID) \ + OP(WMI_WOW_DEL_WAKE_PATTERN_CMDID) \ + OP(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID) \ + OP(WMI_RTT_MEASREQ_CMDID) \ + OP(WMI_RTT_TSF_CMDID) \ + OP(WMI_OEM_REQ_CMDID) \ + OP(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID) \ + OP(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID) \ + OP(WMI_REQUEST_STATS_CMDID) \ + OP(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID) \ + OP(WMI_CSA_OFFLOAD_ENABLE_CMDID) \ + OP(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID) \ + OP(WMI_CHATTER_SET_MODE_CMDID) \ + OP(WMI_ECHO_CMDID) \ + OP(WMI_PDEV_UTF_CMDID) \ + OP(WMI_PDEV_QVIT_CMDID) \ + OP(WMI_VDEV_SET_KEEPALIVE_CMDID) \ + OP(WMI_VDEV_GET_KEEPALIVE_CMDID) \ + OP(WMI_FORCE_FW_HANG_CMDID) \ + OP(WMI_GPIO_CONFIG_CMDID) \ + OP(WMI_GPIO_OUTPUT_CMDID) \ + OP(WMI_PEER_ADD_WDS_ENTRY_CMDID) \ + OP(WMI_PEER_REMOVE_WDS_ENTRY_CMDID) \ + OP(WMI_BCN_TX_CMDID) \ + OP(WMI_PDEV_SEND_BCN_CMDID) \ + OP(WMI_MGMT_TX_CMDID) \ + OP(WMI_ADDBA_CLEAR_RESP_CMDID) \ + OP(WMI_ADDBA_SEND_CMDID) \ + OP(WMI_DELBA_SEND_CMDID) \ + OP(WMI_ADDBA_SET_RESP_CMDID) \ + OP(WMI_SEND_SINGLEAMSDU_CMDID) \ + OP(WMI_PDEV_PKTLOG_ENABLE_CMDID) \ + OP(WMI_PDEV_PKTLOG_DISABLE_CMDID) \ + OP(WMI_PDEV_SET_HT_CAP_IE_CMDID) \ + OP(WMI_PDEV_SET_VHT_CAP_IE_CMDID) \ + OP(WMI_PDEV_SET_DSCP_TID_MAP_CMDID) \ + OP(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID) \ + OP(WMI_PDEV_GET_TPC_CONFIG_CMDID) \ + OP(WMI_PDEV_SET_BASE_MACADDR_CMDID) \ + OP(WMI_PEER_MCAST_GROUP_CMDID) \ + OP(WMI_ROAM_AP_PROFILE) \ + OP(WMI_SCAN_SCH_PRIO_TBL_CMDID) \ + OP(WMI_PDEV_DFS_ENABLE_CMDID) \ + OP(WMI_PDEV_DFS_DISABLE_CMDID) \ + OP(WMI_WOW_ADD_WAKE_PATTERN_CMDID) \ + OP(WMI_PDEV_SUSPEND_CMDID) \ + OP(WMI_PDEV_RESUME_CMDID) \ + OP(WMI_STOP_SCAN_CMDID) \ + OP(WMI_PDEV_SET_PARAM_CMDID) \ + OP(WMI_PDEV_SET_QUIET_MODE_CMDID) \ + OP(WMI_VDEV_CREATE_CMDID) \ + OP(WMI_VDEV_DELETE_CMDID) \ + OP(WMI_VDEV_UP_CMDID) \ + OP(WMI_VDEV_STOP_CMDID) \ + OP(WMI_VDEV_DOWN_CMDID) \ + OP(WMI_VDEV_SET_PARAM_CMDID) \ + OP(WMI_SCAN_UPDATE_REQUEST_CMDID) \ + OP(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID) \ + OP(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID) \ + OP(WMI_CHATTER_COALESCING_QUERY_CMDID) \ + OP(WMI_TXBF_CMDID) \ + OP(WMI_DBGLOG_CFG_CMDID) \ + OP(WMI_VDEV_WNM_SLEEPMODE_CMDID) \ + OP(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID) \ + OP(WMI_VDEV_WMM_ADDTS_CMDID) \ + OP(WMI_VDEV_WMM_DELTS_CMDID) \ + OP(WMI_VDEV_SET_WMM_PARAMS_CMDID) \ + OP(WMI_VDEV_SET_GTX_PARAMS_CMDID) \ + OP(WMI_TDLS_SET_STATE_CMDID) \ + OP(WMI_TDLS_PEER_UPDATE_CMDID) \ + OP(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID) \ + OP(WMI_ROAM_CHAN_LIST) \ + OP(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID) \ + OP(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID) \ + OP(WMI_RESMGR_SET_CHAN_LATENCY_CMDID) \ + OP(WMI_BA_REQ_SSN_CMDID) \ + OP(WMI_STA_SMPS_FORCE_MODE_CMDID) \ + OP(WMI_SET_MCASTBCAST_FILTER_CMDID) \ + OP(WMI_P2P_SET_OPPPS_PARAM_CMDID) \ + OP(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID) \ + OP(WMI_STA_SMPS_PARAM_CMDID) \ + OP(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID) \ + OP(WMI_HB_SET_ENABLE_CMDID) \ + OP(WMI_HB_SET_TCP_PARAMS_CMDID) \ + OP(WMI_HB_SET_TCP_PKT_FILTER_CMDID) \ + OP(WMI_HB_SET_UDP_PARAMS_CMDID) \ + OP(WMI_HB_SET_UDP_PKT_FILTER_CMDID) \ + OP(WMI_PEER_INFO_REQ_CMDID) \ + OP(WMI_RMC_SET_MODE_CMDID) \ + OP(WMI_RMC_SET_ACTION_PERIOD_CMDID) \ + OP(WMI_RMC_CONFIG_CMDID) \ + OP(WMI_MHF_OFFLOAD_SET_MODE_CMDID) \ + OP(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID) \ + OP(WMI_DFS_PHYERR_FILTER_ENA_CMDID) \ + OP(WMI_DFS_PHYERR_FILTER_DIS_CMDID) \ + OP(WMI_BATCH_SCAN_ENABLE_CMDID) \ + OP(WMI_BATCH_SCAN_DISABLE_CMDID) \ + OP(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID) \ + OP(WMI_THERMAL_MGMT_CMDID) \ + OP(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID) \ + OP(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID) \ + OP(WMI_NAN_CMDID) \ + OP(WMI_MODEM_POWER_STATE_CMDID) \ + OP(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID) \ + OP(WMI_ROAM_SCAN_CMD) \ + OP(WMI_REQUEST_STATS_EXT_CMDID) \ + OP(WMI_OBSS_SCAN_ENABLE_CMDID) \ + OP(WMI_OBSS_SCAN_DISABLE_CMDID) \ + OP(WMI_PDEV_SET_LED_CONFIG_CMDID) \ + OP(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID) \ + OP(WMI_TPC_CHAINMASK_CONFIG_CMDID) \ + OP(WMI_CHAN_AVOID_UPDATE_CMDID) \ + OP(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID) \ + OP(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID) \ + OP(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID) \ + OP(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID) \ + OP(WMI_REQUEST_LINK_STATS_CMDID) \ + OP(WMI_START_LINK_STATS_CMDID) \ + OP(WMI_CLEAR_LINK_STATS_CMDID) \ + OP(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID) \ + OP(WMI_LPI_START_SCAN_CMDID) \ + OP(WMI_LPI_STOP_SCAN_CMDID) \ + OP(WMI_EXTSCAN_START_CMDID) \ + OP(WMI_EXTSCAN_STOP_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID) \ + OP(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID) \ + OP(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID) \ + OP(WMI_EXTSCAN_SET_CAPABILITIES_CMDID) \ + OP(WMI_EXTSCAN_GET_CAPABILITIES_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID) \ + OP(WMI_D0_WOW_ENABLE_DISABLE_CMDID) \ + OP(WMI_UNIT_TEST_CMDID) \ + OP(WMI_ROAM_SYNCH_COMPLETE) \ + OP(WMI_EXTWOW_ENABLE_CMDID) \ + OP(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID) \ + OP(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID) \ + OP(WMI_ROAM_SET_RIC_REQUEST_CMDID) \ + OP(WMI_PDEV_GET_TEMPERATURE_CMDID) \ + OP(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID) \ + OP(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID) \ + OP(WMI_SCAN_PROB_REQ_OUI_CMDID) \ + OP(WMI_TDLS_SET_OFFCHAN_MODE_CMDID) \ + OP(WMI_PDEV_SET_LED_FLASHING_CMDID) \ + OP(WMI_ROAM_INVOKE_CMDID) \ + OP(WMI_MDNS_OFFLOAD_ENABLE_CMDID) \ + OP(WMI_MDNS_SET_FQDN_CMDID) \ + OP(WMI_MDNS_SET_RESPONSE_CMDID) \ + OP(WMI_MDNS_GET_STATS_CMDID) \ + OP(WMI_SET_ANTENNA_DIVERSITY_CMDID) \ + OP(WMI_SAP_OFL_ENABLE_CMDID) \ + OP(WMI_APFIND_CMDID) \ + OP(WMI_OCB_SET_SCHED_CMDID) \ + OP(WMI_OCB_SET_CONFIG_CMDID) \ + OP(WMI_OCB_SET_UTC_TIME_CMDID) \ + OP(WMI_OCB_START_TIMING_ADVERT_CMDID) \ + OP(WMI_OCB_STOP_TIMING_ADVERT_CMDID) \ + OP(WMI_OCB_GET_TSF_TIMER_CMDID) \ + OP(WMI_DCC_GET_STATS_CMDID) \ + OP(WMI_DCC_CLEAR_STATS_CMDID) \ + OP(WMI_DCC_UPDATE_NDL_CMDID) \ + OP(WMI_ROAM_FILTER_CMDID) \ + OP(WMI_PASSPOINT_LIST_CONFIG_CMDID) \ + OP(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID) \ + OP(WMI_GET_FW_MEM_DUMP_CMDID) \ + OP(WMI_DEBUG_MESG_FLUSH_CMDID) \ + OP(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID) \ + OP(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID) \ + OP(WMI_VDEV_SET_IE_CMDID) \ + OP(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID) \ + OP(WMI_SOC_SET_PCL_CMDID) \ + OP(WMI_SOC_SET_HW_MODE_CMDID) \ + OP(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID) \ + OP(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID) \ + OP(WMI_DIAG_EVENT_LOG_CONFIG_CMDID) \ + OP(WMI_PACKET_FILTER_CONFIG_CMDID) \ + OP(WMI_PACKET_FILTER_ENABLE_CMDID) \ + OP(WMI_SAP_SET_BLACKLIST_PARAM_CMDID) \ + OP(WMI_MGMT_TX_SEND_CMDID) \ + OP(WMI_SOC_SET_ANTENNA_MODE_CMDID) \ + OP(WMI_WOW_UDP_SVC_OFLD_CMDID) \ + OP(WMI_LRO_CONFIG_CMDID) \ + OP(WMI_MAWC_SENSOR_REPORT_IND_CMDID) \ + OP(WMI_ROAM_CONFIGURE_MAWC_CMDID) \ + OP(WMI_NLO_CONFIGURE_MAWC_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID) \ + OP(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID) \ + OP(WMI_AP_PS_EGAP_PARAM_CMDID) \ + OP(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID) +/* + * IMPORTANT: Please add _ALL_ WMI Events Here. + * Otherwise, these WMI TLV Functions will be process them. + */ +#define WMITLV_ALL_EVT_LIST(OP) \ + OP(WMI_SERVICE_READY_EVENTID) \ + OP(WMI_SERVICE_READY_EXT_EVENTID) \ + OP(WMI_READY_EVENTID) \ + OP(WMI_SCAN_EVENTID) \ + OP(WMI_PDEV_TPC_CONFIG_EVENTID) \ + OP(WMI_CHAN_INFO_EVENTID) \ + OP(WMI_PHYERR_EVENTID) \ + OP(WMI_VDEV_START_RESP_EVENTID) \ + OP(WMI_VDEV_STOPPED_EVENTID) \ + OP(WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID) \ + OP(WMI_PEER_STA_KICKOUT_EVENTID) \ + OP(WMI_MGMT_RX_EVENTID) \ + OP(WMI_TBTTOFFSET_UPDATE_EVENTID) \ + OP(WMI_TX_DELBA_COMPLETE_EVENTID) \ + OP(WMI_TX_ADDBA_COMPLETE_EVENTID) \ + OP(WMI_ROAM_EVENTID) \ + OP(WMI_WOW_WAKEUP_HOST_EVENTID) \ + OP(WMI_RTT_ERROR_REPORT_EVENTID) \ + OP(WMI_OEM_MEASUREMENT_REPORT_EVENTID) \ + OP(WMI_OEM_ERROR_REPORT_EVENTID) \ + OP(WMI_OEM_CAPABILITY_EVENTID) \ + OP(WMI_ECHO_EVENTID) \ + OP(WMI_PDEV_FTM_INTG_EVENTID) \ + OP(WMI_VDEV_GET_KEEPALIVE_EVENTID) \ + OP(WMI_GPIO_INPUT_EVENTID) \ + OP(WMI_CSA_HANDLING_EVENTID) \ + OP(WMI_DEBUG_MESG_EVENTID) \ + OP(WMI_GTK_OFFLOAD_STATUS_EVENTID) \ + OP(WMI_DCS_INTERFERENCE_EVENTID) \ + OP(WMI_WLAN_PROFILE_DATA_EVENTID) \ + OP(WMI_PDEV_UTF_EVENTID) \ + OP(WMI_DEBUG_PRINT_EVENTID) \ + OP(WMI_RTT_MEASUREMENT_REPORT_EVENTID) \ + OP(WMI_HOST_SWBA_EVENTID) \ + OP(WMI_UPDATE_STATS_EVENTID) \ + OP(WMI_PDEV_QVIT_EVENTID) \ + OP(WMI_WLAN_FREQ_AVOID_EVENTID) \ + OP(WMI_GTK_REKEY_FAIL_EVENTID) \ + OP(WMI_NLO_MATCH_EVENTID) \ + OP(WMI_NLO_SCAN_COMPLETE_EVENTID) \ + OP(WMI_APFIND_EVENTID) \ + OP(WMI_CHATTER_PC_QUERY_EVENTID) \ + OP(WMI_UPLOADH_EVENTID) \ + OP(WMI_CAPTUREH_EVENTID) \ + OP(WMI_TDLS_PEER_EVENTID) \ + OP(WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID) \ + OP(WMI_BA_RSP_SSN_EVENTID) \ + OP(WMI_OFFLOAD_BCN_TX_STATUS_EVENTID) \ + OP(WMI_P2P_NOA_EVENTID) \ + OP(WMI_TX_PAUSE_EVENTID) \ + OP(WMI_RFKILL_STATE_CHANGE_EVENTID) \ + OP(WMI_PEER_INFO_EVENTID) \ + OP(WMI_PEER_TX_FAIL_CNT_THR_EVENTID) \ + OP(WMI_DFS_RADAR_EVENTID) \ + OP(WMI_BATCH_SCAN_ENABLED_EVENTID) \ + OP(WMI_BATCH_SCAN_RESULT_EVENTID) \ + OP(WMI_THERMAL_MGMT_EVENTID) \ + OP(WMI_NAN_EVENTID) \ + OP(WMI_PDEV_L1SS_TRACK_EVENTID) \ + OP(WMI_DIAG_DATA_CONTAINER_EVENTID) \ + OP(WMI_PEER_ESTIMATED_LINKSPEED_EVENTID) \ + OP(WMI_AGGR_STATE_TRIG_EVENTID) \ + OP(WMI_STATS_EXT_EVENTID) \ + OP(WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID) \ + OP(WMI_HOST_AUTO_SHUTDOWN_EVENTID) \ + OP(WMI_UPDATE_WHAL_MIB_STATS_EVENTID) \ + OP(WMI_IFACE_LINK_STATS_EVENTID) \ + OP(WMI_PEER_LINK_STATS_EVENTID) \ + OP(WMI_RADIO_LINK_STATS_EVENTID) \ + OP(WMI_LPI_RESULT_EVENTID) \ + OP(WMI_PEER_STATE_EVENTID) \ + OP(WMI_EXTSCAN_START_STOP_EVENTID) \ + OP(WMI_EXTSCAN_OPERATION_EVENTID) \ + OP(WMI_EXTSCAN_TABLE_USAGE_EVENTID) \ + OP(WMI_EXTSCAN_CACHED_RESULTS_EVENTID) \ + OP(WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID) \ + OP(WMI_EXTSCAN_HOTLIST_MATCH_EVENTID) \ + OP(WMI_EXTSCAN_CAPABILITIES_EVENTID) \ + OP(WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID) \ + OP(WMI_D0_WOW_DISABLE_ACK_EVENTID) \ + OP(WMI_ROAM_SYNCH_EVENTID) \ + OP(WMI_LPI_STATUS_EVENTID) \ + OP(WMI_LPI_HANDOFF_EVENTID) \ + OP(WMI_UPDATE_VDEV_RATE_STATS_EVENTID) \ + OP(WMI_PDEV_TEMPERATURE_EVENTID) \ + OP(WMI_DIAG_EVENTID) \ + OP(WMI_MDNS_STATS_EVENTID) \ + OP(WMI_PDEV_RESUME_EVENTID) \ + OP(WMI_SAP_OFL_ADD_STA_EVENTID) \ + OP(WMI_SAP_OFL_DEL_STA_EVENTID) \ + OP(WMI_OCB_SET_SCHED_EVENTID) \ + OP(WMI_OCB_SET_CONFIG_RESP_EVENTID) \ + OP(WMI_OCB_GET_TSF_TIMER_RESP_EVENTID) \ + OP(WMI_DCC_GET_STATS_RESP_EVENTID) \ + OP(WMI_DCC_UPDATE_NDL_RESP_EVENTID) \ + OP(WMI_DCC_STATS_EVENTID) \ + OP(WMI_PASSPOINT_MATCH_EVENTID)\ + OP(WMI_VDEV_TSF_REPORT_EVENTID) \ + OP(WMI_UPDATE_FW_MEM_DUMP_EVENTID) \ + OP(WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID) \ + OP(WMI_RSSI_BREACH_EVENTID) \ + OP(WMI_WOW_INITIAL_WAKEUP_EVENTID) \ + OP(WMI_SOC_SET_HW_MODE_RESP_EVENTID) \ + OP(WMI_SOC_HW_MODE_TRANSITION_EVENTID) \ + OP(WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID) \ + OP(WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID) \ + OP(WMI_MGMT_TX_COMPLETION_EVENTID) \ + OP(WMI_MAWC_ENABLE_SENSOR_EVENTID) \ + OP(WMI_PEER_ASSOC_CONF_EVENTID) \ + OP(WMI_AP_PS_EGAP_INFO_EVENTID) + +/* TLV definitions of WMI commands */ + +/* Init Cmd */ +#define WMITLV_TABLE_WMI_INIT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, wmi_init_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resource_config, wmi_resource_config, resource_config, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_host_memory_chunk, host_mem_chunks, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_INIT_CMDID); + +/* Peer create Cmd */ +#define WMITLV_TABLE_WMI_PEER_CREATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, wmi_peer_create_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_CREATE_CMDID); + +/* Peer delete Cmd */ +#define WMITLV_TABLE_WMI_PEER_DELETE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, wmi_peer_delete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_DELETE_CMDID); + +/* Peer flush Cmd*/ +#define WMITLV_TABLE_WMI_PEER_FLUSH_TIDS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, wmi_peer_flush_tids_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_FLUSH_TIDS_CMDID); + +/* Peer Set Param Cmd */ +#define WMITLV_TABLE_WMI_PEER_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, wmi_peer_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SET_PARAM_CMDID); + +/* STA Powersave Mode Cmd */ +#define WMITLV_TABLE_WMI_STA_POWERSAVE_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, wmi_sta_powersave_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_POWERSAVE_MODE_CMDID); + +/* STA Powersave Param Cmd */ +#define WMITLV_TABLE_WMI_STA_POWERSAVE_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, wmi_sta_powersave_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_POWERSAVE_PARAM_CMDID); + +/* STA DTIM PS METHOD Cmd */ +#define WMITLV_TABLE_WMI_STA_DTIM_PS_METHOD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param, wmi_sta_dtim_ps_method_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_DTIM_PS_METHOD_CMDID); + +/* Pdev Set Reg Domain Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_REGDOMAIN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, wmi_pdev_set_regdomain_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_REGDOMAIN_CMDID); + +/* Peer TID ADD BA Cmd */ +#define WMITLV_TABLE_WMI_PEER_TID_ADDBA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param, wmi_peer_tid_addba_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TID_ADDBA_CMDID); + +/* Peer TID DEL BA Cmd */ +#define WMITLV_TABLE_WMI_PEER_TID_DELBA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd_fixed_param, wmi_peer_tid_delba_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TID_DELBA_CMDID); +/* Peer Req Add BA Ssn for staId/tid pair Cmd */ +#define WMITLV_TABLE_WMI_BA_REQ_SSN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param, wmi_ba_req_ssn_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_ba_req_ssn, ba_req_ssn_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BA_REQ_SSN_CMDID); + +/* PDEV FTM integration Cmd */ +#define WMITLV_TABLE_WMI_PDEV_FTM_INTG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param, wmi_ftm_intg_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FTM_INTG_CMDID); + +/* WOW Wakeup from sleep Cmd */ +#define WMITLV_TABLE_WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + +/* WOW Enable Cmd */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, wmi_wow_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_CMDID); + +/* WOW ICMPv6 NA filtering command */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID); + +/* Remove Bcn Filter Cmd */ +#define WMITLV_TABLE_WMI_RMV_BCN_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, wmi_rmv_bcn_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMV_BCN_FILTER_CMDID); + +/** Service bit WMI_SERVICE_ROAM_OFFLOAD for Roaming feature */ +/* Roam scan mode Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_MODE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, wmi_roam_scan_mode_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, wmi_start_scan_cmd_fixed_param, scan_params, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_offload_tlv_param, offload_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_11i_offload_tlv_param, offload_11i_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_11r_offload_tlv_param, offload_11r_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_ese_offload_tlv_param, offload_ese_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_MODE); + +/* Roam scan Rssi Threshold Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_RSSI_THRESHOLD(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, wmi_roam_scan_rssi_threshold_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_scan_extended_threshold_param, extended_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_earlystop_rssi_thres_param, earlystop_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_RSSI_THRESHOLD); + +/* Roam Scan Period Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_PERIOD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, wmi_roam_scan_period_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_PERIOD); + +/* Roam scan change Rssi Threshold Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, wmi_roam_scan_rssi_change_threshold_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); +/* Roam Scan Channel list Cmd */ +#define WMITLV_TABLE_WMI_ROAM_CHAN_LIST(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, wmi_roam_chan_list_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_CHAN_LIST); + +/* Roam scan mode Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_CMD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, wmi_roam_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_CMD); + +#define WMITLV_TABLE_WMI_VDEV_PLMREQ_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, wmi_vdev_plmreq_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_PLMREQ_START_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_PLMREQ_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, wmi_vdev_plmreq_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_PLMREQ_STOP_CMDID); + +/* Start scan Cmd */ +#define WMITLV_TABLE_WMI_START_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, wmi_start_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_START_SCAN_CMDID); + +/* Start ExtScan Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, wmi_extscan_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_bucket, bucket_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_bucket_channel, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_START_CMDID); + +/* Stop ExtScan Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, wmi_extscan_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_STOP_CMDID); + +/* Start ExtScan BSSID Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_bssid_param, wlan_change_descriptor_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC + (WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID); + +/* Start Hot List Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_entry, hotlist, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID); + +/* Get ExtScan BSSID/RSSI list Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, wmi_extscan_get_cached_results_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID); + +/* Get ExtScan BSSID monitor results Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param, wmi_extscan_get_wlan_change_results_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID); + +/* Set ExtScan Capabilities Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_SET_CAPABILITIES_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param, wmi_extscan_set_capabilities_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_cache_capabilities, extscan_cache_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_monitor_capabilities, wlan_change_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_monitor_capabilities, hotlist_capabilities, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_SET_CAPABILITIES_CMDID); + +/* Get ExtScan Capabilities Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_CAPABILITIES_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, wmi_extscan_get_capabilities_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_CAPABILITIES_CMDID); + +/* Start SSID Hot List Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_ssid_entry, hotlist_ssid, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID); + +/* P2P set vendor ID data Cmd */ +#define WMITLV_TABLE_WMI_P2P_SET_VENDOR_IE_DATA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param, wmi_p2p_set_vendor_ie_data_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_VENDOR_IE_DATA_CMDID); +/* P2P set OppPS parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_SET_OPPPS_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, wmi_p2p_set_oppps_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_OPPPS_PARAM_CMDID); + +/* Pdev set channel Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_CHANNEL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_CHANNEL_CMDID); + +/* Echo Cmd */ +#define WMITLV_TABLE_WMI_ECHO_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param, wmi_echo_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ECHO_CMDID); + +/* Pdev set wmm params */ +#define WMITLV_TABLE_WMI_PDEV_SET_WMM_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param, wmi_pdev_set_wmm_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_be, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_bk, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_vi, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_vo, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_WMM_PARAMS_CMDID); + +/* Vdev start request Cmd */ +#define WMITLV_TABLE_WMI_VDEV_START_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, wmi_vdev_start_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptors, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_START_REQUEST_CMDID); + +/* Vdev restart request cmd */ +#define WMITLV_TABLE_WMI_VDEV_RESTART_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, wmi_vdev_start_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptors, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_RESTART_REQUEST_CMDID); + +/* P2P Go set beacon IE cmd */ +#define WMITLV_TABLE_WMI_P2P_GO_SET_BEACON_IE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, wmi_p2p_go_set_beacon_ie_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_GO_SET_BEACON_IE); + +/* GTK offload Cmd */ +#define WMITLV_TABLE_WMI_GTK_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, WMI_GTK_OFFLOAD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_OFFLOAD_CMDID); + +/* PMF 11w offload Set SA query cmd */ +#define WMITLV_TABLE_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, \ + WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, \ + WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, fixed_param, \ + WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID); + +/* Scan channel list Cmd */ +#define WMITLV_TABLE_WMI_SCAN_CHAN_LIST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, wmi_scan_chan_list_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, chan_info, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_CHAN_LIST_CMDID); + +/* STA UAPSD Auto trigger Cmd */ +#define WMITLV_TABLE_WMI_STA_UAPSD_AUTO_TRIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, wmi_sta_uapsd_auto_trig_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_sta_uapsd_auto_trig_param, ac_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_UAPSD_AUTO_TRIG_CMDID); + +/* Probe template Cmd */ +#define WMITLV_TABLE_WMI_PRB_TMPL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, wmi_prb_tmpl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_prb_info, wmi_bcn_prb_info, bcn_prb_info, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PRB_TMPL_CMDID); + +/* Beacon template Cmd */ +#define WMITLV_TABLE_WMI_BCN_TMPL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, wmi_bcn_tmpl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_prb_info, wmi_bcn_prb_info, bcn_prb_info, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BCN_TMPL_CMDID); + +/* VDEV install key complete Cmd */ +#define WMITLV_TABLE_WMI_VDEV_INSTALL_KEY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, wmi_vdev_install_key_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, key_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_INSTALL_KEY_CMDID); +/* VDEV WNM SLEEP MODE Cmd */ +#define WMITLV_TABLE_WMI_VDEV_WNM_SLEEPMODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WNM_SLEEPMODE_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); + +/* Peer Assoc Cmd */ +#define WMITLV_TABLE_WMI_PEER_ASSOC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, wmi_peer_assoc_complete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, peer_legacy_rates, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, peer_ht_rates, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vht_rate_set, wmi_vht_rate_set, peer_vht_rates, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CMDID); + +/* Peer Set Rate Report Condition Cmd */ +#define WMITLV_TABLE_WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param, wmi_peer_set_rate_report_condition_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID); + +/* Add Beacon filter Cmd */ +#define WMITLV_TABLE_WMI_ADD_BCN_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, wmi_add_bcn_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, ie_map, WMITLV_SIZE_FIX, BCN_FLT_MAX_ELEMS_IE_LIST) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADD_BCN_FILTER_CMDID); + +/* Sta keepalive cmd */ +#define WMITLV_TABLE_WMI_STA_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, WMI_STA_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, WMI_STA_KEEPALVE_ARP_RESPONSE, arp_resp, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_KEEPALIVE_CMDID); + +/* ARP NS offload Cmd */ +#define WMITLV_TABLE_WMI_SET_ARP_NS_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_NS_OFFLOAD_TUPLE, ns_tuples, WMITLV_SIZE_FIX, WMI_MAX_NS_OFFLOADS) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_ARP_OFFLOAD_TUPLE, arp_tuples, WMITLV_SIZE_FIX, WMI_MAX_ARP_OFFLOADS) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_NS_OFFLOAD_TUPLE, ns_ext_tuples, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SET_ARP_NS_OFFLOAD_CMDID); + +/* AP PS peer param Cmd */ +#define WMITLV_TABLE_WMI_AP_PS_PEER_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, wmi_ap_ps_peer_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_PEER_PARAM_CMDID); + +/* AP PS enhanced green ap param Cmd */ +#define WMITLV_TABLE_WMI_AP_PS_EGAP_PARAM_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len,\ + WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param,\ + wmi_ap_ps_egap_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_EGAP_PARAM_CMDID); + +/* Profile Trigger Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_TRIGGER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param, wmi_wlan_profile_trigger_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_TRIGGER_CMDID); + +/* WLAN Profile set hist interval Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID); + +/* WLAN Profile get profile data Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param, wmi_wlan_profile_get_prof_data_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID); + +/* WLAN Profile enable profile ID Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param, wmi_wlan_profile_enable_profile_id_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); + +/* WOW Delete Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_DEL_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, WMI_WOW_DEL_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_DEL_WAKE_PATTERN_CMDID); + +#define WMITLV_TABLE_WMI_WOW_UDP_SVC_OFLD_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, pattern, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, response, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_UDP_SVC_OFLD_CMDID); + +#define WMITLV_TABLE_WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len,\ + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param,\ + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param, fixed_param,\ + WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID); + +/* Wow enable/disable wake up Cmd */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + +/* RTT measurement request Cmd */ +#define WMITLV_TABLE_WMI_RTT_MEASREQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_MEASREQ_CMDID); + +/* RTT TSF Cmd */ +#define WMITLV_TABLE_WMI_RTT_TSF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_TSF_CMDID); + +/*RTT OEM req Cmd */ +#define WMITLV_TABLE_WMI_OEM_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_REQ_CMDID); + +/* Spectral scan configure Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param, wmi_vdev_spectral_configure_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); + +/* Spectral scan enable Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param, wmi_vdev_spectral_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + +/* Request stats Cmd */ +#define WMITLV_TABLE_WMI_REQUEST_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, wmi_request_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_STATS_CMDID); + +/* flush debug messages */ +#define WMITLV_TABLE_WMI_GET_FW_MEM_DUMP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, wmi_get_fw_mem_dump_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_fw_mem_dump,fw_mem_dump_params, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_GET_FW_MEM_DUMP_CMDID); + +/* Request for memory dump stats Cmd */ +#define WMITLV_TABLE_WMI_DEBUG_MESG_FLUSH_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, wmi_debug_mesg_flush_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_FLUSH_CMDID); + +/* Request to config the DIAG Events and LOGs */ +#define WMITLV_TABLE_WMI_DIAG_EVENT_LOG_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, wmi_diag_event_log_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, diag_events_logs_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENT_LOG_CONFIG_CMDID); + +/* Set config params */ +#define WMITLV_TABLE_WMI_START_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, wmi_start_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_START_LINK_STATS_CMDID); + +/* Request to clear link stats */ +#define WMITLV_TABLE_WMI_CLEAR_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, wmi_clear_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CLEAR_LINK_STATS_CMDID); + +/* Request Link stats Cmd */ +#define WMITLV_TABLE_WMI_REQUEST_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, wmi_request_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_LINK_STATS_CMDID); + +/* Network list offload config Cmd */ +#define WMITLV_TABLE_WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, wmi_nlo_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, nlo_configured_parameters, nlo_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, nlo_channel_prediction_cfg, channel_prediction_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + +/* Passpoint list offload config Cmd */ +#define WMITLV_TABLE_WMI_PASSPOINT_LIST_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, wmi_passpoint_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PASSPOINT_LIST_CONFIG_CMDID); + +/* CSA offload enable Cmd */ +#define WMITLV_TABLE_WMI_CSA_OFFLOAD_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, wmi_csa_offload_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_OFFLOAD_ENABLE_CMDID); + +/* CSA offload channel switch Cmd */ +#define WMITLV_TABLE_WMI_CSA_OFFLOAD_CHANSWITCH_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param, wmi_csa_offload_chanswitch_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID); + +/* Chatter set mode Cmd */ +#define WMITLV_TABLE_WMI_CHATTER_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param, wmi_chatter_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_SET_MODE_CMDID); + +/* PDEV UTF Cmd */ +#define WMITLV_TABLE_WMI_PDEV_UTF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UTF_CMDID); + +/* PDEV QVIT Cmd */ +#define WMITLV_TABLE_WMI_PDEV_QVIT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_QVIT_CMDID); + +/* Vdev Set keep alive Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param, wmi_vdev_set_keepalive_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_KEEPALIVE_CMDID); + +/* Vdev Get keep alive Cmd */ +#define WMITLV_TABLE_WMI_VDEV_GET_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param, wmi_vdev_get_keepalive_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_KEEPALIVE_CMDID); +/*FWTEST Set TBTT mode Cmd*/ +#define WMITLV_TABLE_WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID); + +/* FWTEST set NoA parameters Cmd */ +#define WMITLV_TABLE_WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, wmi_p2p_set_noa_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptor, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + +/* Unit test FW */ +#define WMITLV_TABLE_WMI_UNIT_TEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, wmi_unit_test_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, args, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UNIT_TEST_CMDID); + +/* Force Fw Hang Cmd */ +#define WMITLV_TABLE_WMI_FORCE_FW_HANG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, WMI_FORCE_FW_HANG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_FORCE_FW_HANG_CMDID); +/* Set Mcast address Cmd */ +#define WMITLV_TABLE_WMI_SET_MCASTBCAST_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_MCASTBCAST_FILTER_CMDID); + +/* GPIO config Cmd */ +#define WMITLV_TABLE_WMI_GPIO_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, wmi_gpio_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_CONFIG_CMDID); + +/* GPIO output Cmd */ +#define WMITLV_TABLE_WMI_GPIO_OUTPUT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param, wmi_gpio_output_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_OUTPUT_CMDID); + +/* Peer add WDA entry Cmd */ +#define WMITLV_TABLE_WMI_PEER_ADD_WDS_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param, wmi_peer_add_wds_entry_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ADD_WDS_ENTRY_CMDID); + +/*Peer remove WDS entry Cmd */ +#define WMITLV_TABLE_WMI_PEER_REMOVE_WDS_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param, wmi_peer_remove_wds_entry_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_REMOVE_WDS_ENTRY_CMDID); + +/* Beacon tx Cmd */ +#define WMITLV_TABLE_WMI_BCN_TX_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_tx_hdr, wmi_bcn_tx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_BCN_TX_CMDID); + +/* PDEV send Beacon Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SEND_BCN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, wmi_bcn_send_from_host_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SEND_BCN_CMDID); + +/* Management tx Cmd */ +#define WMITLV_TABLE_WMI_MGMT_TX_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr, wmi_mgmt_tx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_CMDID); + +/* Management tx send cmd */ +#define WMITLV_TABLE_WMI_MGMT_TX_SEND_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, wmi_mgmt_tx_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_SEND_CMDID); + +/* ADD clear response Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_CLEAR_RESP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param, wmi_addba_clear_resp_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_CLEAR_RESP_CMDID); + +/* ADD BA send Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param, wmi_addba_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_SEND_CMDID); + +/* DEL BA send Cmd */ +#define WMITLV_TABLE_WMI_DELBA_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param, wmi_delba_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DELBA_SEND_CMDID); + +/* ADD BA set response Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_SET_RESP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param, wmi_addba_setresponse_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_SET_RESP_CMDID); + +/* Send single AMSDU Cmd */ +#define WMITLV_TABLE_WMI_SEND_SINGLEAMSDU_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param, wmi_send_singleamsdu_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_SEND_SINGLEAMSDU_CMDID); + +/* PDev Packet Log enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_PKTLOG_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, wmi_pdev_pktlog_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_PKTLOG_ENABLE_CMDID); + +/* PDev Packet Log disable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_PKTLOG_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, wmi_pdev_pktlog_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_PKTLOG_DISABLE_CMDID); + +/* PDev set HT Cap IE Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_HT_CAP_IE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, wmi_pdev_set_ht_ie_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_HT_CAP_IE_CMDID); + +/* PDev set VHT Cap IE Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_VHT_CAP_IE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, wmi_pdev_set_vht_ie_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_VHT_CAP_IE_CMDID); + +/* PDev Set DSCP to TID map Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_DSCP_TID_MAP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param, wmi_pdev_set_dscp_tid_map_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_DSCP_TID_MAP_CMDID); + +/* PDev Green AP PS enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, wmi_pdev_green_ap_ps_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID); + +/* PDEV Get TPC Config Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_TPC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param, wmi_pdev_get_tpc_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_TPC_CONFIG_CMDID); + +/* PDEV Set Base Mac Address Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_BASE_MACADDR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, wmi_pdev_set_base_macaddr_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_BASE_MACADDR_CMDID); + +/* Peer multicast group Cmd */ +#define WMITLV_TABLE_WMI_PEER_MCAST_GROUP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param, wmi_peer_mcast_group_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_MCAST_GROUP_CMDID); + +/* Roam AP profile Cmd */ +#define WMITLV_TABLE_WMI_ROAM_AP_PROFILE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, wmi_roam_ap_profile_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_profile, wmi_ap_profile, ap_profile, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_AP_PROFILE); + +/* Roam sync complete Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SYNCH_COMPLETE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, wmi_roam_synch_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SYNCH_COMPLETE); + +#define WMITLV_TABLE_WMI_ROAM_SET_RIC_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, wmi_ric_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ric_tspec, ric_tspec_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SET_RIC_REQUEST_CMDID); + +/* Scan scheduler priority Table Cmd */ +#define WMITLV_TABLE_WMI_SCAN_SCH_PRIO_TBL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param, wmi_scan_sch_priority_table_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, mapping_table, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_SCH_PRIO_TBL_CMDID); + +/* PDEV DFS enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param, wmi_pdev_dfs_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_ENABLE_CMDID); + +/* PDEV DFS disable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param, wmi_pdev_dfs_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_DISABLE_CMDID); + +/* DFS phyerr parse/filter offload enable Cmd */ +#define WMITLV_TABLE_WMI_DFS_PHYERR_FILTER_ENA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, wmi_dfs_phyerr_filter_ena_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_PHYERR_FILTER_ENA_CMDID); + +/* DFS phyerr parse/filter offload disable Cmd */ +#define WMITLV_TABLE_WMI_DFS_PHYERR_FILTER_DIS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, wmi_dfs_phyerr_filter_dis_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_PHYERR_FILTER_DIS_CMDID); + +/* WOW Add Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_ADD_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, WMI_WOW_ADD_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_BITMAP_PATTERN_T, pattern_info_bitmap, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IPV4_SYNC_PATTERN_T, pattern_info_ipv4, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IPV6_SYNC_PATTERN_T, pattern_info_ipv6, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_MAGIC_PATTERN_CMD, pattern_info_magic_pattern, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, pattern_info_timeout, WMITLV_SIZE_VAR) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, ra_ratelimit_interval, WMITLV_SIZE_FIX, 1) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ADD_WAKE_PATTERN_CMDID); + +/* IOAC add keep alive cmd. */ +#define WMITLV_TABLE_WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_WOW_IOAC_KEEPALIVE_T, keepalive_set, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID); + +/* IOAC del keep alive cmd. */ +#define WMITLV_TABLE_WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID); + +/* WOW IOAC Add Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_PKT_PATTERN_T, pattern_info_pkt, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_TMR_PATTERN_T, pattern_info_tmr, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_SOCK_PATTERN_T, pattern_info_sock, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID); + +/* WOW IOAC Delete Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID); + +/* extwow enable Cmd */ +#define WMITLV_TABLE_WMI_EXTWOW_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, wmi_extwow_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_ENABLE_CMDID); + +/* extwow set wakeup params cmd for app type1 */ +#define WMITLV_TABLE_WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, wmi_extwow_set_app_type1_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + +/* extwow set wakeup params cmd for app type2 */ +#define WMITLV_TABLE_WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, wmi_extwow_set_app_type2_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + +/* Stop scan Cmd */ +#define WMITLV_TABLE_WMI_STOP_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, wmi_stop_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STOP_SCAN_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, wmi_pdev_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_PARAM_CMDID); + +/* PDev set quiet Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_QUIET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param, wmi_pdev_set_quiet_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_QUIET_MODE_CMDID); + +/* Vdev create Cmd */ +#define WMITLV_TABLE_WMI_VDEV_CREATE_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, wmi_vdev_create_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_txrx_streams, cfg_txrx_streams, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_CREATE_CMDID); + +/* Vdev delete Cmd */ +#define WMITLV_TABLE_WMI_VDEV_DELETE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, wmi_vdev_delete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DELETE_CMDID); + +/* Vdev up Cmd */ +#define WMITLV_TABLE_WMI_VDEV_UP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, wmi_vdev_up_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_UP_CMDID); + +/* Vdev stop cmd */ +#define WMITLV_TABLE_WMI_VDEV_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, wmi_vdev_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_STOP_CMDID); + +/* Vdev down Cmd */ +#define WMITLV_TABLE_WMI_VDEV_DOWN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, wmi_vdev_down_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DOWN_CMDID); + +/* Vdev set param Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, wmi_vdev_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_PARAM_CMDID); + +/* Pdev suspend Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SUSPEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, wmi_pdev_suspend_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SUSPEND_CMDID); + +/* Pdev Resume Cmd */ +#define WMITLV_TABLE_WMI_PDEV_RESUME_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, wmi_pdev_resume_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_RESUME_CMDID); + +#define WMITLV_TABLE_WMI_SCAN_UPDATE_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_scan_update_request_cmd_fixed_param, wmi_scan_update_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_UPDATE_REQUEST_CMDID); + +#define WMITLV_TABLE_WMI_SCAN_PROB_REQ_OUI_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, wmi_scan_prob_req_oui_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_PROB_REQ_OUI_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_ADD_COALESCING_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param, wmi_chatter_coalescing_add_filter_cmd_fixed_param, fixed_param,WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, chatter_pkt_coalescing_filter, coalescing_filter, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param,wmi_chatter_coalescing_delete_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_COALESCING_QUERY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param, wmi_chatter_coalescing_query_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_COALESCING_QUERY_CMDID); + +#define WMITLV_TABLE_WMI_TXBF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param, wmi_txbf_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_TXBF_CMDID); + +#define WMITLV_TABLE_WMI_DBGLOG_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, wmi_debug_log_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len,WMITLV_TAG_ARRAY_UINT32, A_UINT32, module_id_bitmap, WMITLV_SIZE_FIX, MAX_MODULE_ID_BITMAP_WORDS) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_DBGLOG_CFG_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_WMM_ADDTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, wmi_vdev_wmm_addts_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WMM_ADDTS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_WMM_DELTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, wmi_vdev_wmm_delts_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WMM_DELTS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_SET_WMM_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, wmi_vdev_set_wmm_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_WMM_PARAMS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_SET_GTX_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, wmi_vdev_set_gtx_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_GTX_PARAMS_CMDID); + +/* TDLS Enable/Disable Cmd */ +#define WMITLV_TABLE_WMI_TDLS_SET_STATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, \ + wmi_tdls_set_state_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_SET_STATE_CMDID); + +/* TDLS Peer Update Cmd */ +#define WMITLV_TABLE_WMI_TDLS_PEER_UPDATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, wmi_tdls_peer_update_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, wmi_tdls_peer_capabilities, peer_caps, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, peer_chan_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_PEER_UPDATE_CMDID); + +/* Enable/Disable TDLS Offchannel Cmd */ +#define WMITLV_TABLE_WMI_TDLS_SET_OFFCHAN_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, \ + wmi_tdls_set_offchan_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_SET_OFFCHAN_MODE_CMDID); + +/* Resmgr Enable/Disable Adaptive OCS CMD */ +#define WMITLV_TABLE_WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, \ + wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC + (WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + +/* Resmgr Set Channel Time Quota CMD */ +#define WMITLV_TABLE_WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, \ + wmi_resmgr_set_chan_time_quota_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + +/* Resmgr Set Channel Latency CMD */ +#define WMITLV_TABLE_WMI_RESMGR_SET_CHAN_LATENCY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, \ + wmi_resmgr_set_chan_latency_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + +/* STA SMPS Force Mode CMD */ +#define WMITLV_TABLE_WMI_STA_SMPS_FORCE_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, \ + wmi_sta_smps_force_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_SMPS_FORCE_MODE_CMDID); + +/* wlan hb enable/disable CMD */ +#define WMITLV_TABLE_WMI_HB_SET_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, \ + wmi_hb_set_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_ENABLE_CMDID); + +/* wlan hb set tcp params CMD */ +#define WMITLV_TABLE_WMI_HB_SET_TCP_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, \ + wmi_hb_set_tcp_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_TCP_PARAMS_CMDID); + +/* wlan hb set tcp pkt filter CMD */ +#define WMITLV_TABLE_WMI_HB_SET_TCP_PKT_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, \ + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_TCP_PKT_FILTER_CMDID); + +/* wlan set udp params CMD */ +#define WMITLV_TABLE_WMI_HB_SET_UDP_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, \ + wmi_hb_set_udp_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_UDP_PARAMS_CMDID); + +/* wlan hb set udp pkt filter CMD */ +#define WMITLV_TABLE_WMI_HB_SET_UDP_PKT_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, \ + wmi_hb_set_udp_pkt_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_UDP_PKT_FILTER_CMDID); + +/* STA SMPS Param CMD */ +#define WMITLV_TABLE_WMI_STA_SMPS_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, \ + wmi_sta_smps_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_SMPS_PARAM_CMDID); + +/* MCC Adaptive Scheduler Traffic Stats */ +#define WMITLV_TABLE_WMI_MCC_SCHED_TRAFFIC_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param, wmi_mcc_sched_traffic_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_mcc_sched_sta_traffic_stats, mcc_sched_sta_traffic_stats_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param, wmi_batch_scan_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_ENABLE_CMDID); + +#define WMITLV_TABLE_WMI_PEER_INFO_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, \ + wmi_peer_info_req_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_INFO_REQ_CMDID); + +#define WMITLV_TABLE_WMI_RMC_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, \ + wmi_rmc_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_SET_MODE_CMDID); + +#define WMITLV_TABLE_WMI_RMC_SET_ACTION_PERIOD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, \ + wmi_rmc_set_action_period_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_SET_ACTION_PERIOD_CMDID); + +#define WMITLV_TABLE_WMI_RMC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param, \ + wmi_rmc_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_CONFIG_CMDID); + +#define WMITLV_TABLE_WMI_MHF_OFFLOAD_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param, \ + wmi_mhf_offload_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_MHF_OFFLOAD_SET_MODE_CMDID); + +#define WMITLV_TABLE_WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param, \ + wmi_mhf_offload_plumb_routing_table_cmd, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_mhf_offload_routing_table_entry, \ + routing_tbl_entries, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID) +#define WMITLV_TABLE_WMI_BATCH_SCAN_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param, wmi_batch_scan_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_DISABLE_CMDID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param, wmi_batch_scan_trigger_result_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID); + +/* LPI mgmt snooping config Cmd */ +#define WMITLV_TABLE_WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_mgmt_snooping_config_cmd_fixed_param, wmi_lpi_mgmt_snooping_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID); + +/* LPI start scan Cmd */ +#define WMITLV_TABLE_WMI_LPI_START_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_start_scan_cmd_fixed_param, wmi_lpi_start_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_START_SCAN_CMDID); + +/* LPI stop scan Cmd */ +#define WMITLV_TABLE_WMI_LPI_STOP_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_stop_scan_cmd_fixed_param, wmi_lpi_stop_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_STOP_SCAN_CMDID); + +#define WMITLV_TABLE_WMI_LPI_RESULT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_result_event_fixed_param, wmi_lpi_result_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_RESULT_EVENTID); + +/* LPI Status Event */ +#define WMITLV_TABLE_WMI_LPI_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_status_event_fixed_param, wmi_lpi_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_STATUS_EVENTID); + +/* LPI Handoff Event */ +#define WMITLV_TABLE_WMI_LPI_HANDOFF_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_handoff_event_fixed_param, wmi_lpi_handoff_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_HANDOFF_EVENTID); + +/* Thermal Manager Params*/ +#define WMITLV_TABLE_WMI_THERMAL_MGMT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, wmi_thermal_mgmt_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_THERMAL_MGMT_CMDID); + +#define WMITLV_TABLE_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, pattern, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID); + +#define WMITLV_TABLE_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID); + +/* NaN Request */ +#define WMITLV_TABLE_WMI_NAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_cmd_param, wmi_nan_cmd_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_CMDID); + +/* Modem power state cmd */ +#define WMITLV_TABLE_WMI_MODEM_POWER_STATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, wmi_modem_power_state_cmd_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MODEM_POWER_STATE_CMDID); + +/* get estimated link speed cmd */ +#define WMITLV_TABLE_WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, wmi_peer_get_estimated_linkspeed_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID); + +/* ext stats Request */ +#define WMITLV_TABLE_WMI_REQUEST_STATS_EXT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, wmi_req_stats_ext_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_STATS_EXT_CMDID); + +/* 2.4Ghz HT40 OBSS scan enable */ +#define WMITLV_TABLE_WMI_OBSS_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, wmi_obss_scan_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, channels, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_field, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OBSS_SCAN_ENABLE_CMDID); + +/* 2.4Ghz HT40 OBSS scan disable */ +#define WMITLV_TABLE_WMI_OBSS_SCAN_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, wmi_obss_scan_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OBSS_SCAN_DISABLE_CMDID); + +/* Pdev Set LED Config Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_LED_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_led_config_cmd_fixed_param, wmi_pdev_set_led_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_LED_CONFIG_CMDID); + +/* host auto shut down config cmd */ +#define WMITLV_TABLE_WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, wmi_host_auto_shutdown_cfg_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + +/* tpc chainmask config cmd */ +#define WMITLV_TABLE_WMI_TPC_CHAINMASK_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tpc_chainmask_config_cmd_fixed_param, wmi_tpc_chainmask_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tpc_chainmask_config, config_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_TPC_CHAINMASK_CONFIG_CMDID); + +/* Ch avoidance update cmd */ +#define WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, wmi_chan_avoid_update_cmd_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHAN_AVOID_UPDATE_CMDID); + +/* D0-WOW Enable Disable Cmd */ +#define WMITLV_TABLE_WMI_D0_WOW_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, wmi_d0_wow_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_D0_WOW_ENABLE_DISABLE_CMDID); + +/* Pdev get chip temperature Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_TEMPERATURE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, wmi_pdev_get_temperature_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_TEMPERATURE_CMDID); + +/* Set antenna diversity Cmd */ +#define WMITLV_TABLE_WMI_SET_ANTENNA_DIVERSITY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param, wmi_pdev_set_antenna_diversity_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_ANTENNA_DIVERSITY_CMDID); + +#define WMITLV_TABLE_WMI_LRO_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, wmi_lro_info_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LRO_CONFIG_CMDID); + + +/* MAWC sensor report indication cmd */ +#define WMITLV_TABLE_WMI_MAWC_SENSOR_REPORT_IND_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param, wmi_mawc_sensor_report_ind_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MAWC_SENSOR_REPORT_IND_CMDID); + +/* Roam configure MAWC cmd */ +#define WMITLV_TABLE_WMI_ROAM_CONFIGURE_MAWC_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param, wmi_roam_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_CONFIGURE_MAWC_CMDID); + +/* NLO configure MAWC cmd */ +#define WMITLV_TABLE_WMI_NLO_CONFIGURE_MAWC_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param, wmi_nlo_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NLO_CONFIGURE_MAWC_CMDID); + +/* Extscan configure MAWC cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_MAWC_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param, wmi_extscan_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID); + +/* Set rssi monitoring config Cmd */ +#define WMITLV_TABLE_WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, wmi_rssi_breach_monitor_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + +/* DHCP server offload param Cmd */ +#define WMITLV_TABLE_WMI_SET_DHCP_SERVER_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, wmi_set_dhcp_server_offload_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + +/* IPA Offload Enable Disable Cmd */ +#define WMITLV_TABLE_WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, wmi_ipa_offload_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID); + +/* Set LED flashing parameter Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_LED_FLASHING_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, wmi_set_led_flashing_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_LED_FLASHING_CMDID); + +/* mDNS responder offload param Cmd */ +#define WMITLV_TABLE_WMI_MDNS_OFFLOAD_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param, wmi_mdns_offload_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_OFFLOAD_ENABLE_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_SET_FQDN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param, wmi_mdns_set_fqdn_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, fqdn_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_SET_FQDN_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_SET_RESPONSE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param, wmi_mdns_set_resp_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, resp_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_SET_RESPONSE_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_GET_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param, wmi_mdns_get_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_GET_STATS_CMDID); + +/* roam invoke Cmd */ +#define WMITLV_TABLE_WMI_ROAM_INVOKE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, wmi_roam_invoke_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_INVOKE_CMDID); + +/* SAP Authentication offload param Cmd */ +#define WMITLV_TABLE_WMI_SAP_OFL_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param, wmi_sap_ofl_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, psk, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_ENABLE_CMDID); + +/* SAP set blacklist param cmd */ +#define WMITLV_TABLE_WMI_SAP_SET_BLACKLIST_PARAM_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param, wmi_sap_set_blacklist_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_SET_BLACKLIST_PARAM_CMDID); + +/* APFIND Request */ +#define WMITLV_TABLE_WMI_APFIND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_apfind_cmd_param, wmi_apfind_cmd_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_APFIND_CMDID); + +/* Set OCB schedule cmd, DEPRECATED */ +#define WMITLV_TABLE_WMI_OCB_SET_SCHED_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param, wmi_ocb_set_sched_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_SCHED_CMDID); + +/* Set OCB configuration cmd */ +#define WMITLV_TABLE_WMI_OCB_SET_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, wmi_ocb_set_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, chan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ocb_channel, ocb_chan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_qos_parameter, qos_parameter_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_chan, chan_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_active_state_config, ndl_active_state_config_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ocb_schedule_element, schedule_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_CONFIG_CMDID); + +/* Set UTC time cmd */ +#define WMITLV_TABLE_WMI_OCB_SET_UTC_TIME_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, wmi_ocb_set_utc_time_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_UTC_TIME_CMDID); + +/* Start timing advertisement cmd */ +#define WMITLV_TABLE_WMI_OCB_START_TIMING_ADVERT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, wmi_ocb_start_timing_advert_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_START_TIMING_ADVERT_CMDID); + +/* Stop timing advertisement cmd */ +#define WMITLV_TABLE_WMI_OCB_STOP_TIMING_ADVERT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, wmi_ocb_stop_timing_advert_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_STOP_TIMING_ADVERT_CMDID); + +/* Get TSF timer cmd */ +#define WMITLV_TABLE_WMI_OCB_GET_TSF_TIMER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, wmi_ocb_get_tsf_timer_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_GET_TSF_TIMER_CMDID); + +/* Get DCC stats cmd */ +#define WMITLV_TABLE_WMI_DCC_GET_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, wmi_dcc_get_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_channel_stats_request, channel_stats_request, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_GET_STATS_CMDID); + +/* Clear DCC stats cmd */ +#define WMITLV_TABLE_WMI_DCC_CLEAR_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, wmi_dcc_clear_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_CLEAR_STATS_CMDID); + +/* Update DCC NDL cmd */ +#define WMITLV_TABLE_WMI_DCC_UPDATE_NDL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, wmi_dcc_update_ndl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_chan, chan_ndl_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_active_state_config, ndl_active_state_config_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_UPDATE_NDL_CMDID); + +#define WMITLV_TABLE_WMI_ROAM_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, wmi_roam_filter_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_black_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_white_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_preferred_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, bssid_preferred_factor, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_FILTER_CMDID); +/* TSF timestamp action cmd */ +#define WMITLV_TABLE_WMI_VDEV_TSF_TSTAMP_ACTION_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, wmi_vdev_tsf_tstamp_action_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + +/* LFR subnet change config Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, wmi_roam_subnet_change_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, skip_subnet_change_detection_bssid_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + +/* Set the SOC Preferred Channel List (PCL) Cmd */ +#define WMITLV_TABLE_WMI_SOC_SET_PCL_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param, wmi_soc_set_pcl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_PCL_CMDID); + +/* Set the SOC Hardware Mode Cmd */ +#define WMITLV_TABLE_WMI_SOC_SET_HW_MODE_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param, wmi_soc_set_hw_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_HW_MODE_CMDID); + +/* Set the SOC Dual MAC Config Cmd */ +#define WMITLV_TABLE_WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param, wmi_soc_set_dual_mac_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID); + +/* Set the SOC Antenna Mode Cmd */ +#define WMITLV_TABLE_WMI_SOC_SET_ANTENNA_MODE_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param, wmi_soc_set_antenna_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_ANTENNA_MODE_CMDID); + +/************************** TLV definitions of WMI events *******************************/ + +/* Service Ready event */ +#define WMITLV_TABLE_WMI_SERVICE_READY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, wmi_service_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, HAL_REG_CAPABILITIES, hal_reg_capabilities, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wmi_service_bitmap, WMITLV_SIZE_FIX, WMI_SERVICE_BM_SIZE) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wlan_host_mem_req, mem_reqs, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wlan_dbs_hw_mode_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EVENTID); + +/* Service Ready Extension event */ +#define WMITLV_TABLE_WMI_SERVICE_READY_EXT_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_service_ready_ext_event_fixed_param, wmi_service_ready_ext_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EXT_EVENTID); + +/* Ready event */ +#define WMITLV_TABLE_WMI_READY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ready_event_fixed_param, wmi_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_READY_EVENTID); + +/* Scan Event */ +#define WMITLV_TABLE_WMI_SCAN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_event_fixed_param, wmi_scan_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_EVENTID); + +/* ExtScan Start/Stop Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_START_STOP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param, wmi_extscan_start_stop_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_START_STOP_EVENTID); + +/* ExtScan Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_OPERATION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param, wmi_extscan_operation_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, bucket_id, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_OPERATION_EVENTID); + +/* ExtScan Table Usage Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_TABLE_USAGE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param, wmi_extscan_table_usage_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_TABLE_USAGE_EVENTID); + +/* ExtScan Result Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_CACHED_RESULTS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param, wmi_extscan_cached_results_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_rssi_info, rssi_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CACHED_RESULTS_EVENTID); + +/* ExtScan Monitor RSSI List Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param, wmi_extscan_wlan_change_results_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_result_bssid, bssid_signal_descriptor_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, rssi_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_HOTLIST_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param, wmi_extscan_hotlist_match_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, hotlist_match, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_HOTLIST_MATCH_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_CAPABILITIES_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param, wmi_extscan_capabilities_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_cache_capabilities, extscan_cache_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_monitor_capabilities, wlan_change_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_monitor_capabilities, hotlist_capabilities, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CAPABILITIES_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param, wmi_extscan_hotlist_ssid_match_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, hotlist_ssid_match, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID); + +/* Update_whal_mib_stats Event */ +#define WMITLV_TABLE_WMI_UPDATE_WHAL_MIB_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param, wmi_update_whal_mib_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_WHAL_MIB_STATS_EVENTID); + +/* PDEV TPC Config Event */ +#define WMITLV_TABLE_WMI_PDEV_TPC_CONFIG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param, wmi_pdev_tpc_config_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ratesArray, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_TPC_CONFIG_EVENTID); + +/* Channel Info Event */ +#define WMITLV_TABLE_WMI_CHAN_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param, wmi_chan_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHAN_INFO_EVENTID); + +/* Phy Error Event */ +#define WMITLV_TABLE_WMI_PHYERR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr, wmi_comb_phyerr_rx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PHYERR_EVENTID); + +/* TX Pause/Unpause event */ +#define WMITLV_TABLE_WMI_TX_PAUSE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_pause_event_fixed_param, wmi_tx_pause_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_PAUSE_EVENTID); + +/* Mgmt TX completion event */ +#define WMITLV_TABLE_WMI_MGMT_TX_COMPLETION_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_event_fixed_param, wmi_mgmt_tx_compl_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_COMPLETION_EVENTID); + +/* VDEV Start response Event */ +#define WMITLV_TABLE_WMI_VDEV_START_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param, wmi_vdev_start_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_START_RESP_EVENTID); + +/* VDEV Stopped Event */ +#define WMITLV_TABLE_WMI_VDEV_STOPPED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param, wmi_vdev_stopped_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_STOPPED_EVENTID); + +/* VDEV Install Key Complete Event */ +#define WMITLV_TABLE_WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param, wmi_vdev_install_key_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID); + +/* Peer STA Kickout Event */ +#define WMITLV_TABLE_WMI_PEER_STA_KICKOUT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param, wmi_peer_sta_kickout_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STA_KICKOUT_EVENTID); + +/* Management Rx Event */ +#define WMITLV_TABLE_WMI_MGMT_RX_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr, wmi_mgmt_rx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_RX_EVENTID); + +/* TBTT offset Event */ +#define WMITLV_TABLE_WMI_TBTTOFFSET_UPDATE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param, wmi_tbtt_offset_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tbttoffset_list, WMITLV_SIZE_FIX, WMI_MAX_AP_VDEV) +WMITLV_CREATE_PARAM_STRUC(WMI_TBTTOFFSET_UPDATE_EVENTID); + +/* TX DELBA Complete Event */ +#define WMITLV_TABLE_WMI_TX_DELBA_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param, wmi_tx_delba_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_DELBA_COMPLETE_EVENTID); + +/* Tx ADDBA Complete Event */ +#define WMITLV_TABLE_WMI_TX_ADDBA_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param, wmi_tx_addba_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_ADDBA_COMPLETE_EVENTID); + +/* ADD BA Req ssn Event */ +#define WMITLV_TABLE_WMI_BA_RSP_SSN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param, wmi_ba_rsp_ssn_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_ba_event_ssn, ba_event_ssn_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BA_RSP_SSN_EVENTID); + +/* Aggregation Request event */ +#define WMITLV_TABLE_WMI_AGGR_STATE_TRIG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param, wmi_aggr_state_trig_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AGGR_STATE_TRIG_EVENTID); + +/* Roam Event */ +#define WMITLV_TABLE_WMI_ROAM_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_event_fixed_param, wmi_roam_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_EVENTID); + +/* Roam Synch Event */ +#define WMITLV_TABLE_WMI_ROAM_SYNCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param, wmi_roam_synch_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bcn_probe_rsp_frame, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, reassoc_rsp_frame, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_key_material, key, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, status, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SYNCH_EVENTID); + +/* WOW Wakeup Host Event */ +/* NOTE: Make sure wow_bitmap_info can be zero or one elements only */ +#define WMITLV_TABLE_WMI_WOW_WAKEUP_HOST_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param, WOW_EVENT_INFO_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_EVENT_INFO_SECTION_BITMAP, wow_bitmap_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, wow_packet_buffer, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hb_ind_event_fixed_param, hb_indevt, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, wow_gtkigtk, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_WAKEUP_HOST_EVENTID); + + +#define WMITLV_TABLE_WMI_WOW_INITIAL_WAKEUP_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_WOW_EVENT_INITIAL_WAKEUP_fixed_param, WOW_INITIAL_WAKEUP_EVENT_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_INITIAL_WAKEUP_EVENTID); + + +/* RTT error report Event */ +#define WMITLV_TABLE_WMI_RTT_ERROR_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_ERROR_REPORT_EVENTID); + +/* Echo Event */ +#define WMITLV_TABLE_WMI_ECHO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_echo_event_fixed_param, wmi_echo_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ECHO_EVENTID); + +/* FTM Integration Event */ +#define WMITLV_TABLE_WMI_PDEV_FTM_INTG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param, wmi_ftm_intg_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FTM_INTG_EVENTID); + +/* VDEV get Keepalive Event */ +#define WMITLV_TABLE_WMI_VDEV_GET_KEEPALIVE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param, wmi_vdev_get_keepalive_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_KEEPALIVE_EVENTID); + +/* GPIO Input Event */ +#define WMITLV_TABLE_WMI_GPIO_INPUT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param, wmi_gpio_input_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_INPUT_EVENTID); + +/* CSA Handling Event */ +#define WMITLV_TABLE_WMI_CSA_HANDLING_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_event_fixed_param, wmi_csa_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_HANDLING_EVENTID); + +/* Rfkill state change Event */ +#define WMITLV_TABLE_WMI_RFKILL_STATE_CHANGE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rfkill_event_fixed_param, wmi_rfkill_mode_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RFKILL_STATE_CHANGE_EVENTID); + +/* Debug Message Event */ +#define WMITLV_TABLE_WMI_DEBUG_MESG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_EVENTID); + +#define WMITLV_TABLE_WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param, wmi_debug_mesg_flush_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID); + +#define WMITLV_TABLE_WMI_RSSI_BREACH_EVENTID(id, op, buf, len)\ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_rssi_breach_event_fixed_param, wmi_rssi_breach_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RSSI_BREACH_EVENTID); + +/* Diagnostics Event */ +#define WMITLV_TABLE_WMI_DIAG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENTID); + +/* IGTK Offload Event */ +#define WMITLV_TABLE_WMI_GTK_OFFLOAD_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_OFFLOAD_STATUS_EVENTID); + +/* DCA interferance Event */ +#define WMITLV_TABLE_WMI_DCS_INTERFERENCE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param, wmi_dcs_interference_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, ath_dcs_cw_int, cw_int, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_dcs_im_tgt_stats_t, wlan_stat, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCS_INTERFERENCE_EVENTID); + +/* Profile data Event */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_DATA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t, wmi_wlan_profile_ctx_t, profile_ctx, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_wlan_profile_t, profile_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_DATA_EVENTID); + +/* PDEV UTF Event */ +#define WMITLV_TABLE_WMI_PDEV_UTF_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UTF_EVENTID); + +/* Debug print Event */ +#define WMITLV_TABLE_WMI_DEBUG_PRINT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_PRINT_EVENTID); + +/* RTT measurement report Event */ +#define WMITLV_TABLE_WMI_RTT_MEASUREMENT_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_MEASUREMENT_REPORT_EVENTID); + +/*oem measurement report Event*/ +#define WMITLV_TABLE_WMI_OEM_MEASUREMENT_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_MEASUREMENT_REPORT_EVENTID); + +/*oem error report event*/ +#define WMITLV_TABLE_WMI_OEM_ERROR_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_ERROR_REPORT_EVENTID); + +/*oem capability report event*/ +#define WMITLV_TABLE_WMI_OEM_CAPABILITY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_CAPABILITY_EVENTID); + +/* HOST SWBA Event */ +#define WMITLV_TABLE_WMI_HOST_SWBA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param, wmi_host_swba_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tim_info, tim_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_info, p2p_noa_info, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_SWBA_EVENTID); + +/* Update stats Event */ +#define WMITLV_TABLE_WMI_UPDATE_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, wmi_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_STATS_EVENTID); + +/* For vdev based ht/vht info upload*/ +#define WMITLV_TABLE_WMI_UPDATE_VDEV_RATE_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, wmi_vdev_rate_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_rate_ht_info, ht_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_VDEV_RATE_STATS_EVENTID); + +/* Update memory dump complete Event */ +#define WMITLV_TABLE_WMI_UPDATE_FW_MEM_DUMP_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param, wmi_update_fw_mem_dump_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_FW_MEM_DUMP_EVENTID); + +/* Event indicating the DIAG LOGs/Events supported by FW */ +#define WMITLV_TABLE_WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_diag_event_log_supported_event_fixed_params, wmi_diag_event_log_supported_event_fixed_params, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, diag_events_logs_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID); + + +/* Update iface link stats Event */ +#define WMITLV_TABLE_WMI_IFACE_LINK_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param, wmi_iface_link_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_iface_link_stats, iface_link_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_wmm_ac_stats, ac, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_IFACE_LINK_STATS_EVENTID); + +/* Update Peer link stats Event */ +#define WMITLV_TABLE_WMI_PEER_LINK_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param, wmi_peer_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_link_stats, peer_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rate_stats, peer_rate_stats, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_LINK_STATS_EVENTID); + +/* Update radio stats Event */ +#define WMITLV_TABLE_WMI_RADIO_LINK_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_radio_link_stats_event_fixed_param, wmi_radio_link_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_radio_link_stats, radio_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel_stats, channel_stats, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_LINK_STATS_EVENTID); + +/* PDEV QVIT Event */ +#define WMITLV_TABLE_WMI_PDEV_QVIT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_QVIT_EVENTID); + +/* WLAN Frequency avoid Event */ +#define WMITLV_TABLE_WMI_WLAN_FREQ_AVOID_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param, wmi_avoid_freq_ranges_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_avoid_freq_range_desc, avd_freq_range, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_FREQ_AVOID_EVENTID); + +/* GTK rekey fail Event */ +#define WMITLV_TABLE_WMI_GTK_REKEY_FAIL_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param, wmi_gtk_rekey_fail_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_REKEY_FAIL_EVENTID); + +/* NLO match event */ +#define WMITLV_TABLE_WMI_NLO_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_event, wmi_nlo_event, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NLO_MATCH_EVENTID); + +/* NLO scan complete event */ +#define WMITLV_TABLE_WMI_NLO_SCAN_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_event, wmi_nlo_event, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NLO_SCAN_COMPLETE_EVENTID); + +/* APFIND event */ +#define WMITLV_TABLE_WMI_APFIND_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_apfind_event_hdr, wmi_apfind_event_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_APFIND_EVENTID); + +/* WMI_PASSPOINT_MATCH_EVENTID */ +#define WMITLV_TABLE_WMI_PASSPOINT_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_passpoint_event_hdr, wmi_passpoint_event_hdr, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PASSPOINT_MATCH_EVENTID); + +/* Chatter query reply event */ +#define WMITLV_TABLE_WMI_CHATTER_PC_QUERY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param, wmi_chatter_query_reply_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_PC_QUERY_EVENTID); + +/* Upload H_CV info event */ +#define WMITLV_TABLE_WMI_UPLOADH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_upload_h_hdr, wmi_upload_h_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UPLOADH_EVENTID); + +/* Capture H info event */ +#define WMITLV_TABLE_WMI_CAPTUREH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_capture_h_event_hdr, wmi_capture_h_event_hdr, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CAPTUREH_EVENTID); +/* TDLS Peer Update event */ +#define WMITLV_TABLE_WMI_TDLS_PEER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param, wmi_tdls_peer_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_PEER_EVENTID); + +/* VDEV MCC Beacon Interval Change Request Event */ +#define WMITLV_TABLE_WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC + (WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_ENABLED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param, wmi_batch_scan_enabled_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_ENABLED_EVENTID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_RESULT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_result_event_fixed_param, wmi_batch_scan_result_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_batch_scan_result_scan_list, scan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_batch_scan_result_network_info, network_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_RESULT_EVENTID); + +#define WMITLV_TABLE_WMI_OFFLOAD_BCN_TX_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param, wmi_offload_bcn_tx_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OFFLOAD_BCN_TX_STATUS_EVENTID); + +/* NOA Event */ +#define WMITLV_TABLE_WMI_P2P_NOA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param, wmi_p2p_noa_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_noa_info, wmi_p2p_noa_info, p2p_noa_info, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_NOA_EVENTID); + + /* AP PS enhanced green ap Event */ +#define WMITLV_TABLE_WMI_AP_PS_EGAP_INFO_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len,\ + WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_event_fixed_param,\ + wmi_ap_ps_egap_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC,\ + wmi_ap_ps_egap_info_chainmask_list, chainmask_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_EGAP_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param, wmi_peer_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_TX_FAIL_CNT_THR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param, wmi_peer_tx_fail_cnt_thr_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TX_FAIL_CNT_THR_EVENTID); + +/* DFS radar Event */ +#define WMITLV_TABLE_WMI_DFS_RADAR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_radar_event_fixed_param, wmi_dfs_radar_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_RADAR_EVENTID); + +/* Thermal Event */ +#define WMITLV_TABLE_WMI_THERMAL_MGMT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param, wmi_thermal_mgmt_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_THERMAL_MGMT_EVENTID); + +/* NAN Response/Indication Event */ +#define WMITLV_TABLE_WMI_NAN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_event_hdr, wmi_nan_event_hdr, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_EVENTID); + +/* L1SS track Event */ +#define WMITLV_TABLE_WMI_PDEV_L1SS_TRACK_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param, wmi_pdev_l1ss_track_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_L1SS_TRACK_EVENTID); + +#define WMITLV_TABLE_WMI_DIAG_DATA_CONTAINER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_diag_data_container_event_fixed_param, wmi_diag_data_container_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_DATA_CONTAINER_EVENTID); + +/* Estimated Link Speed Indication*/ +#define WMITLV_TABLE_WMI_PEER_ESTIMATED_LINKSPEED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_estimated_linkspeed_event_fixed_param, wmi_peer_estimated_linkspeed_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ESTIMATED_LINKSPEED_EVENTID); + +#define WMITLV_TABLE_WMI_STATS_EXT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stats_ext_event_fixed_param, wmi_stats_ext_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_STATS_EXT_EVENTID); + +#define WMITLV_TABLE_WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param, wmi_offload_prb_rsp_tx_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID); + +/* host auto shut down event */ +#define WMITLV_TABLE_WMI_HOST_AUTO_SHUTDOWN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param, wmi_host_auto_shutdown_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_AUTO_SHUTDOWN_EVENTID); + +/* peer state Event */ +#define WMITLV_TABLE_WMI_PEER_STATE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_state_event_fixed_param, wmi_peer_state_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STATE_EVENTID); + +/* peer assoc conf Event */ +#define WMITLV_TABLE_WMI_PEER_ASSOC_CONF_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param, wmi_peer_assoc_conf_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CONF_EVENTID); + +/* D0-WOW Disable Ack event */ +#define WMITLV_TABLE_WMI_D0_WOW_DISABLE_ACK_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param, wmi_d0_wow_disable_ack_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_D0_WOW_DISABLE_ACK_EVENTID); + +/* Pdev get chip temperature event */ +#define WMITLV_TABLE_WMI_PDEV_TEMPERATURE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param, wmi_pdev_temperature_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_TEMPERATURE_EVENTID); + +/* mDNS offload stats event */ +#define WMITLV_TABLE_WMI_MDNS_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param, wmi_mdns_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_STATS_EVENTID); + +/* pdev resume event */ +#define WMITLV_TABLE_WMI_PDEV_RESUME_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param, wmi_pdev_resume_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_RESUME_EVENTID); + +/* SAP Authentication offload event */ +#define WMITLV_TABLE_WMI_SAP_OFL_ADD_STA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param, wmi_sap_ofl_add_sta_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_ADD_STA_EVENTID); + +#define WMITLV_TABLE_WMI_SAP_OFL_DEL_STA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param, wmi_sap_ofl_del_sta_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_DEL_STA_EVENTID); + +/* Set OCB schedule cmd, DEPRECATED */ +#define WMITLV_TABLE_WMI_OCB_SET_SCHED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_ocb_set_sched_event_fixed_param, wmi_ocb_set_sched_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_SCHED_EVENTID); + +/* Set OCB configuration response event */ +#define WMITLV_TABLE_WMI_OCB_SET_CONFIG_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param, wmi_ocb_set_config_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_CONFIG_RESP_EVENTID); + +/* Get TSF timer response event */ +#define WMITLV_TABLE_WMI_OCB_GET_TSF_TIMER_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param, wmi_ocb_get_tsf_timer_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_GET_TSF_TIMER_RESP_EVENTID); + +/* Get DCC stats response event */ +#define WMITLV_TABLE_WMI_DCC_GET_STATS_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param, wmi_dcc_get_stats_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_stats_per_channel, stats_per_channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_GET_STATS_RESP_EVENTID); + +/* Update DCC NDL response event */ +#define WMITLV_TABLE_WMI_DCC_UPDATE_NDL_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param, wmi_dcc_update_ndl_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_UPDATE_NDL_RESP_EVENTID); + +/* DCC stats event */ +#define WMITLV_TABLE_WMI_DCC_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param, wmi_dcc_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_stats_per_channel, stats_per_channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_STATS_EVENTID); + +/* Read TSF timer response event */ +#define WMITLV_TABLE_WMI_VDEV_TSF_REPORT_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param, wmi_vdev_tsf_report_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_TSF_REPORT_EVENTID); + +/* Vdev capabilities IE to be transmitted in mgmt frames */ +#define WMITLV_TABLE_WMI_VDEV_SET_IE_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, wmi_vdev_set_ie_cmd_fixed_param, vdev_ie, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_IE_CMDID); + +/* SOC Set Hardware Mode Response event */ +#define WMITLV_TABLE_WMI_SOC_SET_HW_MODE_RESP_EVENTID(id, op, buf, len) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param, wmi_soc_set_hw_mode_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_soc_set_hw_mode_response_vdev_mac_entry, wmi_soc_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_HW_MODE_RESP_EVENTID); + +/* SOC Hardware Mode Transition event */ +#define WMITLV_TABLE_WMI_SOC_HW_MODE_TRANSITION_EVENTID(id, op, buf, len) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param, wmi_soc_hw_mode_transition_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_soc_set_hw_mode_response_vdev_mac_entry, wmi_soc_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_HW_MODE_TRANSITION_EVENTID); + +/* SOC Set Dual MAC Config Response event */ +#define WMITLV_TABLE_WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param, wmi_soc_set_dual_mac_config_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID); + +/* Packet Filter configure command*/ +#define WMITLV_TABLE_WMI_PACKET_FILTER_CONFIG_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, WMI_PACKET_FILTER_CONFIG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PACKET_FILTER_CONFIG_CMDID); + +/* Packet Filter enable command*/ +#define WMITLV_TABLE_WMI_PACKET_FILTER_ENABLE_CMDID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, WMI_PACKET_FILTER_ENABLE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PACKET_FILTER_ENABLE_CMDID); + +/* MAWC enable/disable sensor event */ +#define WMITLV_TABLE_WMI_MAWC_ENABLE_SENSOR_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param, wmi_mawc_enable_sensor_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MAWC_ENABLE_SENSOR_EVENTID); + + +#ifdef __cplusplus +} +#endif +#endif /*_WMI_TLV_DEFS_H_*/ diff --git a/target/inc/wmi_tlv_helper.h b/target/inc/wmi_tlv_helper.h new file mode 100644 index 0000000000..7631e5df9e --- /dev/null +++ b/target/inc/wmi_tlv_helper.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WMI_TLV_HELPER_H_ +#define _WMI_TLV_HELPER_H_ + +/* + * Every command or event parameter structure will need a TLV definition. + * The macro WMITLV_TABLE is used to help build this TLV definition. Inside this macro define, the + * individual TLV's are specified. The parameters for WMITLV_ELEM are: + * (1) the list of parameters that are passed unchanged from the WMITLV_TABLE. Currently, they are id,op,buf,len + * (2) The TLV Tag. You should create a new tag for each cmd/event in WMITLV_TAG_ID. The name of the + * tag is . There are special tags, + * e.g. WMI_TLVTAG_ARRAY_UINT32 and WMI_TLVTAG_ARRAY_STRUC. WMI_TLVTAG_ARRAY_UINT32 is for a + * variable size array of UINT32 elements. WMI_TLVTAG_ARRAY_STRUC is for a varialbe size array + * of structures. + * (3) type of the TLV. For WMI_TLVTAG_ARRAY_* tag, then it is the type of each element. + * (4) Name of this TLV. It must be unique in this TLV TABLE. + * (5) Either WMITLV_SIZE_FIX or WMITLV_SIZE_VAR to indicate if this TLV is variable size. + * + * Note: It is important that the last TLV_ELEM does not have the "\" character. + */ + +/* Size of the TLV Header which is the Tag and Length fields */ +#define WMI_TLV_HDR_SIZE (1 * sizeof(A_UINT32)) + +/** TLV Helper macro to get the TLV Header given the pointer + * to the TLV buffer. */ +#define WMITLV_GET_HDR(tlv_buf) (((A_UINT32 *)(tlv_buf))[0]) + +/** TLV Helper macro to set the TLV Header given the pointer + * to the TLV buffer. */ +#define WMITLV_SET_HDR(tlv_buf, tag, len) (((A_UINT32 *)(tlv_buf))[0]) = ((tag << 16) | (len & 0x0000FFFF)) + +/** TLV Helper macro to get the TLV Tag given the TLV header. */ +#define WMITLV_GET_TLVTAG(tlv_header) ((A_UINT32)((tlv_header)>>16)) + +/** TLV Helper macro to get the TLV Buffer Length (minus TLV + * header size) given the TLV header. */ +#define WMITLV_GET_TLVLEN(tlv_header) ((A_UINT32)((tlv_header) & 0x0000FFFF)) + +/** TLV Helper macro to get the TLV length from TLV structure size by removing TLV header size */ +#define WMITLV_GET_STRUCT_TLVLEN(tlv_struct) ((A_UINT32)(sizeof(tlv_struct)-WMI_TLV_HDR_SIZE)) + +/* Indicates whether the TLV is fixed size or variable length */ +#define WMITLV_SIZE_FIX 0 +#define WMITLV_SIZE_VAR 1 + +typedef struct { + A_UINT32 tag_order; + A_UINT32 tag_id; + A_UINT32 tag_struct_size; + A_UINT32 tag_varied_size; + A_UINT32 tag_array_size; + A_UINT32 cmd_num_tlv; +} wmitlv_attributes_struc; + +/* Template structure definition for a variable size array of UINT32 */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_ARRAY_UINT32 */ + A_UINT32 uint32_array[1]; /* variable length Array of UINT32 */ +} wmitlv_array_uint32; + +/* Template structure definition for a variable size array of unknown structure */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_ARRAY_STRUC */ + A_UINT32 struc_array[1]; /* variable length Array of structures */ +} wmitlv_array_struc; + +/* + * Used to fill in the "arr_size" parameter when it is not specified and hence, invalid. Can be used to + * indicate if the original TLV definition specify this fixed array size. + */ +#define WMITLV_ARR_SIZE_INVALID 0x1FE + +#define WMITLV_GET_TAG_NUM_TLV_ATTRIB(wmi_cmd_event_id) \ + WMI_TLV_HLPR_NUM_TLVS_FOR_ ## wmi_cmd_event_id + +void +wmitlv_set_static_param_tlv_buf(void *param_tlv_buf, + A_UINT32 max_tlvs_accomodated); + +void +wmitlv_free_allocated_command_tlvs(A_UINT32 cmd_id, void **wmi_cmd_struct_ptr); + +void +wmitlv_free_allocated_event_tlvs(A_UINT32 event_id, void **wmi_cmd_struct_ptr); + +int +wmitlv_check_command_tlv_params(void *os_ctx, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id); + +int +wmitlv_check_event_tlv_params(void *os_ctx, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id); + +int +wmitlv_check_and_pad_command_tlvs(void *os_ctx, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr); + +int +wmitlv_check_and_pad_event_tlvs(void *os_ctx, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr); + +/** This structure is the element for the Version WhiteList + * table. */ +typedef struct { + A_UINT32 major; + A_UINT32 minor; + A_UINT32 namespace_0; + A_UINT32 namespace_1; + A_UINT32 namespace_2; + A_UINT32 namespace_3; +} wmi_whitelist_version_info; + +struct _wmi_abi_version; /* Forward declaration to make the ARM compiler happy */ + +int +wmi_cmp_and_set_abi_version(int num_whitelist, + wmi_whitelist_version_info * + version_whitelist_table, + struct _wmi_abi_version *my_vers, + struct _wmi_abi_version *opp_vers, + struct _wmi_abi_version *out_vers); + +int +wmi_versions_are_compatible(struct _wmi_abi_version *vers1, + struct _wmi_abi_version *vers2); + +#endif /*_WMI_TLV_HELPER_H_*/ diff --git a/target/inc/wmi_unified.h b/target/inc/wmi_unified.h new file mode 100644 index 0000000000..7684d33f6b --- /dev/null +++ b/target/inc/wmi_unified.h @@ -0,0 +1,12299 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @addtogroup WMIAPI + ***@{ + */ + +/** @file + * This file specifies the WMI interface for the Software Architecture. + * + * It includes definitions of all the commands and events. Commands are messages + * from the host to the target. Events and Replies are messages from the target + * to the host. + * + * Ownership of correctness in regards to WMI commands + * belongs to the host driver and the target is not required to validate + * parameters for value, proper range, or any other checking. + * + * Guidelines for extending this interface are below. + * + * 1. Add new WMI commands ONLY within the specified range - 0x9000 - 0x9fff + * 2. Use ONLY A_UINT32 type for defining member variables within WMI command/event + * structures. Do not use A_UINT8, A_UINT16, A_BOOL or enum types within these structures. + * 3. DO NOT define bit fields within structures. Implement bit fields using masks + * if necessary. Do not use the programming language's bit field definition. + * 4. Define macros for encode/decode of A_UINT8, A_UINT16 fields within the A_UINT32 + * variables. Use these macros for set/get of these fields. Try to use this to + * optimize the structure without bloating it with A_UINT32 variables for every lower + * sized field. + * 5. Do not use PACK/UNPACK attributes for the structures as each member variable is + * already 4-byte aligned by virtue of being a A_UINT32 type. + * 6. Comment each parameter part of the WMI command/event structure by using the + * 2 stars at the begining of C comment instead of one star to enable HTML document + * generation using Doxygen. + * + */ + +#ifndef _WMI_UNIFIED_H_ +#define _WMI_UNIFIED_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define ATH_MAC_LEN 6 /**< length of MAC in bytes */ +#define WMI_EVENT_STATUS_SUCCESS 0 /* Success return status to host */ +#define WMI_EVENT_STATUS_FAILURE 1 /* Failure return status to host */ + +#define MAX_TX_RATE_VALUES 10 /*Max Tx Rates */ +#define MAX_RSSI_VALUES 10 /*Max Rssi values */ + +/* The WLAN_MAX_AC macro cannot be changed without breaking + * WMI compatibility. + * The maximum value of access category + */ +#define WLAN_MAX_AC 4 + +/* + * These don't necessarily belong here; but as the MS/SM macros require + * ar6000_internal.h to be included, it may not be defined as yet. + */ +#define WMI_F_MS(_v, _f) \ + ( ((_v) & (_f)) >> (_f ## _S) ) + +/* + * This breaks the "good macro practice" of only referencing each + * macro field once (to avoid things like field++ from causing issues.) + */ +#define WMI_F_RMW(_var, _v, _f) \ + do { \ + (_var) &= ~(_f); \ + (_var) |= ( ((_v) << (_f ## _S)) & (_f)); \ + } while (0) + +#define WMI_GET_BITS(_val, _index, _num_bits) \ + (((_val) >> (_index)) & ((1 << (_num_bits)) - 1)) + +#define WMI_SET_BITS(_var, _index, _num_bits, _val) do { \ + (_var) &= ~(((1 << (_num_bits)) - 1) << (_index)); \ + (_var) |= (((_val) & ((1 << (_num_bits)) - 1)) << (_index)); \ + } while (0) + +/** + * A packed array is an array where each entry in the array is less than + * or equal to 16 bits, and the entries are stuffed into an A_UINT32 array. + * For example, if each entry in the array is 11 bits, then you can stuff + * an array of 4 11-bit values into an array of 2 A_UINT32 values. + * The first 2 11-bit values will be stored in the first A_UINT32, + * and the last 2 11-bit values will be stored in the second A_UINT32. + */ +#define WMI_PACKED_ARR_SIZE(num_entries, bits_per_entry) \ + (((num_entries) / (32 / (bits_per_entry))) + \ + (((num_entries) % (32 / (bits_per_entry))) ? 1 : 0)) + +static INLINE A_UINT32 wmi_packed_arr_get_bits(A_UINT32 * arr, + A_UINT32 entry_index, A_UINT32 bits_per_entry) +{ + A_UINT32 entries_per_uint = (32 / bits_per_entry); + A_UINT32 uint_index = (entry_index / entries_per_uint); + A_UINT32 num_entries_in_prev_uints = (uint_index * entries_per_uint); + A_UINT32 index_in_uint = (entry_index - num_entries_in_prev_uints); + A_UINT32 start_bit_in_uint = (index_in_uint * bits_per_entry); + return ((arr[uint_index] >> start_bit_in_uint) & + ((1 << bits_per_entry) - 1)); +} + +static INLINE void wmi_packed_arr_set_bits(A_UINT32 *arr, A_UINT32 entry_index, + A_UINT32 bits_per_entry, A_UINT32 val) +{ + A_UINT32 entries_per_uint = (32 / bits_per_entry); + A_UINT32 uint_index = (entry_index / entries_per_uint); + A_UINT32 num_entries_in_prev_uints = (uint_index * entries_per_uint); + A_UINT32 index_in_uint = (entry_index - num_entries_in_prev_uints); + A_UINT32 start_bit_in_uint = (index_in_uint * bits_per_entry); + + arr[uint_index] &= ~(((1 << bits_per_entry) - 1) << start_bit_in_uint); + arr[uint_index] |= + ((val & ((1 << bits_per_entry) - 1)) << start_bit_in_uint); +} + +/** 2 word representation of MAC addr */ +typedef struct { + /** upper 4 bytes of MAC address */ + A_UINT32 mac_addr31to0; + /** lower 2 bytes of MAC address */ + A_UINT32 mac_addr47to32; +} wmi_mac_addr; + +/** macro to convert MAC address from WMI word format to char array */ +#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr,c_macaddr) do { \ + (c_macaddr)[0] = ((pwmi_mac_addr)->mac_addr31to0) & 0xff; \ + (c_macaddr)[1] = ( ((pwmi_mac_addr)->mac_addr31to0) >> 8) & 0xff; \ + (c_macaddr)[2] = ( ((pwmi_mac_addr)->mac_addr31to0) >> 16) & 0xff; \ + (c_macaddr)[3] = ( ((pwmi_mac_addr)->mac_addr31to0) >> 24) & 0xff; \ + (c_macaddr)[4] = ((pwmi_mac_addr)->mac_addr47to32) & 0xff; \ + (c_macaddr)[5] = ( ((pwmi_mac_addr)->mac_addr47to32) >> 8) & 0xff; \ +} while(0) + +/** macro to convert MAC address from char array to WMI word format */ +#define WMI_CHAR_ARRAY_TO_MAC_ADDR(c_macaddr,pwmi_mac_addr) do { \ + (pwmi_mac_addr)->mac_addr31to0 = \ + ( (c_macaddr)[0] | ((c_macaddr)[1] << 8) \ + | ((c_macaddr)[2] << 16) | ((c_macaddr)[3] << 24) ); \ + (pwmi_mac_addr)->mac_addr47to32 = \ + ( (c_macaddr)[4] | ((c_macaddr)[5] << 8)); \ +} while(0) + +/* + * wmi command groups. + */ +typedef enum { + /* 0 to 2 are reserved */ + WMI_GRP_START = 0x3, + WMI_GRP_SCAN = WMI_GRP_START, + WMI_GRP_PDEV, + WMI_GRP_VDEV, + WMI_GRP_PEER, + WMI_GRP_MGMT, + WMI_GRP_BA_NEG, + WMI_GRP_STA_PS, + WMI_GRP_DFS, + WMI_GRP_ROAM, + WMI_GRP_OFL_SCAN, + WMI_GRP_P2P, + WMI_GRP_AP_PS, + WMI_GRP_RATE_CTRL, + WMI_GRP_PROFILE, + WMI_GRP_SUSPEND, + WMI_GRP_BCN_FILTER, + WMI_GRP_WOW, + WMI_GRP_RTT, + WMI_GRP_SPECTRAL, + WMI_GRP_STATS, + WMI_GRP_ARP_NS_OFL, + WMI_GRP_NLO_OFL, + WMI_GRP_GTK_OFL, + WMI_GRP_CSA_OFL, + WMI_GRP_CHATTER, + WMI_GRP_TID_ADDBA, + WMI_GRP_MISC, + WMI_GRP_GPIO, + WMI_GRP_FWTEST, + WMI_GRP_TDLS, + WMI_GRP_RESMGR, + WMI_GRP_STA_SMPS, + WMI_GRP_WLAN_HB, + WMI_GRP_RMC, + WMI_GRP_MHF_OFL, + WMI_GRP_LOCATION_SCAN, + WMI_GRP_OEM, + WMI_GRP_NAN, + WMI_GRP_COEX, + WMI_GRP_OBSS_OFL, + WMI_GRP_LPI, + WMI_GRP_EXTSCAN, + WMI_GRP_DHCP_OFL, + WMI_GRP_IPA, + WMI_GRP_MDNS_OFL, + WMI_GRP_SAP_OFL, + WMI_GRP_OCB, + WMI_GRP_SOC, + WMI_GRP_PKT_FILTER, + WMI_GRP_MAWC, + WMI_GRP_PMF_OFFLOAD, +} WMI_GRP_ID; + +#define WMI_CMD_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_EVT_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) + +/** + * Command IDs and commange events + */ +typedef enum { + /** initialize the wlan sub system */ + WMI_INIT_CMDID = 0x1, + + /* Scan specific commands */ + + /** start scan request to FW */ + WMI_START_SCAN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SCAN), + /** stop scan request to FW */ + WMI_STOP_SCAN_CMDID, + /** full list of channels as defined by the regulatory that will be used by scanner */ + WMI_SCAN_CHAN_LIST_CMDID, + /** overwrite default priority table in scan scheduler */ + WMI_SCAN_SCH_PRIO_TBL_CMDID, + /** This command to adjust the priority and min.max_rest_time + * of an on ongoing scan request. + */ + WMI_SCAN_UPDATE_REQUEST_CMDID, + + /** set OUI to be used in probe request if enabled */ + WMI_SCAN_PROB_REQ_OUI_CMDID, + + /* PDEV(physical device) specific commands */ + /** set regulatorty ctl id used by FW to determine the exact ctl power limits */ + WMI_PDEV_SET_REGDOMAIN_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_PDEV), + /** set channel. mainly used for supporting monitor mode */ + WMI_PDEV_SET_CHANNEL_CMDID, + /** set pdev specific parameters */ + WMI_PDEV_SET_PARAM_CMDID, + /** enable packet log */ + WMI_PDEV_PKTLOG_ENABLE_CMDID, + /** disable packet log*/ + WMI_PDEV_PKTLOG_DISABLE_CMDID, + /** set wmm parameters */ + WMI_PDEV_SET_WMM_PARAMS_CMDID, + /** set HT cap ie that needs to be carried probe requests HT/VHT channels */ + WMI_PDEV_SET_HT_CAP_IE_CMDID, + /** set VHT cap ie that needs to be carried on probe requests on VHT channels */ + WMI_PDEV_SET_VHT_CAP_IE_CMDID, + + /** Command to send the DSCP-to-TID map to the target */ + WMI_PDEV_SET_DSCP_TID_MAP_CMDID, + /** set quiet ie parameters. primarily used in AP mode */ + WMI_PDEV_SET_QUIET_MODE_CMDID, + /** Enable/Disable Green AP Power Save */ + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID, + /** get TPC config for the current operating channel */ + WMI_PDEV_GET_TPC_CONFIG_CMDID, + + /** set the base MAC address for the physical device before a VDEV is created. + * For firmware that doesn't support this feature and this command, the pdev + * MAC address will not be changed. */ + WMI_PDEV_SET_BASE_MACADDR_CMDID, + + /* eeprom content dump , the same to bdboard data */ + WMI_PDEV_DUMP_CMDID, + /* set LED configuration */ + WMI_PDEV_SET_LED_CONFIG_CMDID, + /* Get Current temprature of chip in Celcius degree */ + WMI_PDEV_GET_TEMPERATURE_CMDID, + /* Set LED flashing behavior */ + WMI_PDEV_SET_LED_FLASHING_CMDID, + + /* VDEV(virtual device) specific commands */ + /** vdev create */ + WMI_VDEV_CREATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_VDEV), + /** vdev delete */ + WMI_VDEV_DELETE_CMDID, + /** vdev start request */ + WMI_VDEV_START_REQUEST_CMDID, + /** vdev restart request (RX only, NO TX, used for CAC period)*/ + WMI_VDEV_RESTART_REQUEST_CMDID, + /** vdev up request */ + WMI_VDEV_UP_CMDID, + /** vdev stop request */ + WMI_VDEV_STOP_CMDID, + /** vdev down request */ + WMI_VDEV_DOWN_CMDID, + /* set a vdev param */ + WMI_VDEV_SET_PARAM_CMDID, + /* set a key (used for setting per peer unicast and per vdev multicast) */ + WMI_VDEV_INSTALL_KEY_CMDID, + + /* wnm sleep mode command */ + WMI_VDEV_WNM_SLEEPMODE_CMDID, + WMI_VDEV_WMM_ADDTS_CMDID, + WMI_VDEV_WMM_DELTS_CMDID, + WMI_VDEV_SET_WMM_PARAMS_CMDID, + WMI_VDEV_SET_GTX_PARAMS_CMDID, + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID, + + WMI_VDEV_PLMREQ_START_CMDID, + WMI_VDEV_PLMREQ_STOP_CMDID, + /* TSF timestamp action for specified vdev */ + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID, + /* + * set the capabilties IE, e.g. for extended caps in probe + * requests, assoc req etc for frames FW locally generates + */ + WMI_VDEV_SET_IE_CMDID, + + /* peer specific commands */ + + /** create a peer */ + WMI_PEER_CREATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PEER), + /** delete a peer */ + WMI_PEER_DELETE_CMDID, + /** flush specific tid queues of a peer */ + WMI_PEER_FLUSH_TIDS_CMDID, + /** set a parameter of a peer */ + WMI_PEER_SET_PARAM_CMDID, + /** set peer to associated state. will cary all parameters determined during assocication time */ + WMI_PEER_ASSOC_CMDID, + /**add a wds (4 address ) entry. used only for testing WDS feature on AP products */ + WMI_PEER_ADD_WDS_ENTRY_CMDID, + /**remove wds (4 address ) entry. used only for testing WDS feature on AP products */ + WMI_PEER_REMOVE_WDS_ENTRY_CMDID, + /** set up mcast group infor for multicast to unicast conversion */ + WMI_PEER_MCAST_GROUP_CMDID, + /** request peer info from FW. FW shall respond with PEER_INFO_EVENTID */ + WMI_PEER_INFO_REQ_CMDID, + + /** request the estimated link speed for the peer. FW shall respond with + * WMI_PEER_ESTIMATED_LINKSPEED_EVENTID. + */ + WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID, + /* + * Set the conditions to report peer justified rate to driver + * The justified rate means the the user-rate is justified by PER. + */ + WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID, + /* beacon/management specific commands */ + + /** transmit beacon by reference . used for transmitting beacon on low latency interface like pcie */ + WMI_BCN_TX_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MGMT), + /** transmit beacon by value */ + WMI_PDEV_SEND_BCN_CMDID, + /** set the beacon template. used in beacon offload mode to setup the + * the common beacon template with the FW to be used by FW to generate beacons */ + WMI_BCN_TMPL_CMDID, + /** set beacon filter with FW */ + WMI_BCN_FILTER_RX_CMDID, + /* enable/disable filtering of probe requests in the firmware */ + WMI_PRB_REQ_FILTER_RX_CMDID, + /** transmit management frame by value. will be deprecated */ + WMI_MGMT_TX_CMDID, + /** set the probe response template. used in beacon offload mode to setup the + * the common probe response template with the FW to be used by FW to generate + * probe responses */ + WMI_PRB_TMPL_CMDID, + /** Transmit Mgmt frame by reference */ + WMI_MGMT_TX_SEND_CMDID, + + /** commands to directly control ba negotiation directly from host. only used in test mode */ + + /** turn off FW Auto addba mode and let host control addba */ + WMI_ADDBA_CLEAR_RESP_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_BA_NEG), + /** send add ba request */ + WMI_ADDBA_SEND_CMDID, + WMI_ADDBA_STATUS_CMDID, + /** send del ba */ + WMI_DELBA_SEND_CMDID, + /** set add ba response will be used by FW to generate addba response*/ + WMI_ADDBA_SET_RESP_CMDID, + /** send single VHT MPDU with AMSDU */ + WMI_SEND_SINGLEAMSDU_CMDID, + + /** Station power save specific config */ + /** enable/disable station powersave */ + WMI_STA_POWERSAVE_MODE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_STA_PS), + /** set station power save specific parameter */ + WMI_STA_POWERSAVE_PARAM_CMDID, + /** set station mimo powersave mode */ + WMI_STA_MIMO_PS_MODE_CMDID, + + /** DFS-specific commands */ + /** enable DFS (radar detection)*/ + WMI_PDEV_DFS_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_DFS), + /** disable DFS (radar detection)*/ + WMI_PDEV_DFS_DISABLE_CMDID, + /** enable DFS phyerr/parse filter offload */ + WMI_DFS_PHYERR_FILTER_ENA_CMDID, + /** enable DFS phyerr/parse filter offload */ + WMI_DFS_PHYERR_FILTER_DIS_CMDID, + + /* Roaming specific commands */ + /** set roam scan mode */ + WMI_ROAM_SCAN_MODE = WMI_CMD_GRP_START_ID(WMI_GRP_ROAM), + /** set roam scan rssi threshold below which roam scan is enabled */ + WMI_ROAM_SCAN_RSSI_THRESHOLD, + /** set roam scan period for periodic roam scan mode */ + WMI_ROAM_SCAN_PERIOD, + /** set roam scan trigger rssi change threshold */ + WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + /** set roam AP profile */ + WMI_ROAM_AP_PROFILE, + /** set channel list for roam scans */ + WMI_ROAM_CHAN_LIST, + /** Stop scan command */ + WMI_ROAM_SCAN_CMD, + /** roaming sme offload sync complete */ + WMI_ROAM_SYNCH_COMPLETE, + /** set ric request element for 11r roaming */ + WMI_ROAM_SET_RIC_REQUEST_CMDID, + /** Invoke roaming forcefully */ + WMI_ROAM_INVOKE_CMDID, + /** roaming filter cmd to allow further filtering of roaming candidate */ + WMI_ROAM_FILTER_CMDID, + /** set gateway ip, mac and retries for subnet change detection */ + WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID, + /** configure thresholds for MAWC */ + WMI_ROAM_CONFIGURE_MAWC_CMDID, + + /** offload scan specific commands */ + /** set offload scan AP profile */ + WMI_OFL_SCAN_ADD_AP_PROFILE = + WMI_CMD_GRP_START_ID(WMI_GRP_OFL_SCAN), + /** remove offload scan AP profile */ + WMI_OFL_SCAN_REMOVE_AP_PROFILE, + /** set offload scan period */ + WMI_OFL_SCAN_PERIOD, + + /* P2P specific commands */ + /**set P2P device info. FW will used by FW to create P2P IE to be carried in probe response + * generated during p2p listen and for p2p discoverability */ + WMI_P2P_DEV_SET_DEVICE_INFO = WMI_CMD_GRP_START_ID(WMI_GRP_P2P), + /** enable/disable p2p discoverability on STA/AP VDEVs */ + WMI_P2P_DEV_SET_DISCOVERABILITY, + /** set p2p ie to be carried in beacons generated by FW for GO */ + WMI_P2P_GO_SET_BEACON_IE, + /** set p2p ie to be carried in probe response frames generated by FW for GO */ + WMI_P2P_GO_SET_PROBE_RESP_IE, + /** set the vendor specific p2p ie data. FW will use this to parse the P2P NoA + * attribute in the beacons/probe responses received. + */ + WMI_P2P_SET_VENDOR_IE_DATA_CMDID, + /** set the configure of p2p find offload */ + WMI_P2P_DISC_OFFLOAD_CONFIG_CMDID, + /** set the vendor specific p2p ie data for p2p find offload using */ + WMI_P2P_DISC_OFFLOAD_APPIE_CMDID, + /** set the BSSID/device name pattern of p2p find offload */ + WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID, + /** set OppPS related parameters **/ + WMI_P2P_SET_OPPPS_PARAM_CMDID, + + /** AP power save specific config */ + /** set AP power save specific param */ + WMI_AP_PS_PEER_PARAM_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_AP_PS), + /** set AP UAPSD coex pecific param */ + WMI_AP_PS_PEER_UAPSD_COEX_CMDID, + + /** set Enhanced Green AP param */ + WMI_AP_PS_EGAP_PARAM_CMDID, + + /** Rate-control specific commands */ + WMI_PEER_RATE_RETRY_SCHED_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_RATE_CTRL), + + /** WLAN Profiling commands. */ + WMI_WLAN_PROFILE_TRIGGER_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_PROFILE), + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + + /** Suspend resume command Ids */ + WMI_PDEV_SUSPEND_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SUSPEND), + WMI_PDEV_RESUME_CMDID, + + /* Beacon filter commands */ + /** add a beacon filter */ + WMI_ADD_BCN_FILTER_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_BCN_FILTER), + /** remove a beacon filter */ + WMI_RMV_BCN_FILTER_CMDID, + + /* WOW Specific WMI commands */ + /** add pattern for awake */ + WMI_WOW_ADD_WAKE_PATTERN_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_WOW), + /** deleta a wake pattern */ + WMI_WOW_DEL_WAKE_PATTERN_CMDID, + /** enable/deisable wake event */ + WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + /** enable WOW */ + WMI_WOW_ENABLE_CMDID, + /** host woke up from sleep event to FW. Generated in response to WOW Hardware event */ + WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + /* IOAC add keep alive cmd. */ + WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID, + /* IOAC del keep alive cmd. */ + WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID, + /* IOAC add pattern for awake */ + WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID, + /* IOAC deleta a wake pattern */ + WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID, + /* D0-WOW enable or disable cmd */ + WMI_D0_WOW_ENABLE_DISABLE_CMDID, + /* enable extend WoW */ + WMI_EXTWOW_ENABLE_CMDID, + /* Extend WoW command to configure app type1 parameter */ + WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, + /* Extend WoW command to configure app type2 parameter */ + WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, + /* enable ICMPv6 Network advertisement filtering */ + WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID, + /* + * Set a pattern to match UDP packet in WOW mode. + * If match, construct a tx frame in a local buffer + * to send through the peer AP to the entity in the + * IP network that sent the UDP packet to this STA. + */ + WMI_WOW_UDP_SVC_OFLD_CMDID, + + /* configure WOW host wakeup PIN pattern */ + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID, + + /* RTT measurement related cmd */ + /** request to make an RTT measurement */ + WMI_RTT_MEASREQ_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RTT), + /** request to report a tsf measurement */ + WMI_RTT_TSF_CMDID, + + /** spectral scan command */ + /** configure spectral scan */ + WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_SPECTRAL), + /** enable/disable spectral scan and trigger */ + WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + + /* F/W stats */ + /** one time request for stats */ + WMI_REQUEST_STATS_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_STATS), + /** Push MCC Adaptive Scheduler Stats to Firmware */ + WMI_MCC_SCHED_TRAFFIC_STATS_CMDID, + /** one time request for txrx stats */ + WMI_REQUEST_STATS_EXT_CMDID, + + /* Link Layer stats */ + /** Request for link layer stats */ + WMI_REQUEST_LINK_STATS_CMDID, + /** Request for setting params to link layer stats */ + WMI_START_LINK_STATS_CMDID, + /** Request to clear stats*/ + WMI_CLEAR_LINK_STATS_CMDID, + + /** Request for getting the Firmware Memory Dump */ + WMI_GET_FW_MEM_DUMP_CMDID, + + /** Request to flush of the buffered debug messages */ + WMI_DEBUG_MESG_FLUSH_CMDID, + + /** Cmd to configure the verbose level */ + WMI_DIAG_EVENT_LOG_CONFIG_CMDID, + + /** ARP OFFLOAD REQUEST*/ + WMI_SET_ARP_NS_OFFLOAD_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_ARP_NS_OFL), + + /** Proactive ARP Response Add Pattern Command*/ + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID, + + /** Proactive ARP Response Del Pattern Command*/ + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID, + + /** NS offload config*/ + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_NLO_OFL), + + /** APFIND Config */ + WMI_APFIND_CMDID, + + /** Passpoint list config */ + WMI_PASSPOINT_LIST_CONFIG_CMDID, + + /** configure supprssing parameters for MAWC */ + WMI_NLO_CONFIGURE_MAWC_CMDID, + + /* GTK offload Specific WMI commands */ + WMI_GTK_OFFLOAD_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_GTK_OFL), + + /* CSA offload Specific WMI commands */ + /** csa offload enable */ + WMI_CSA_OFFLOAD_ENABLE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_CSA_OFL), + /** chan switch command */ + WMI_CSA_OFFLOAD_CHANSWITCH_CMDID, + + /* Chatter commands */ + /* Change chatter mode of operation */ + WMI_CHATTER_SET_MODE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_CHATTER), + /** chatter add coalescing filter command */ + WMI_CHATTER_ADD_COALESCING_FILTER_CMDID, + /** chatter delete coalescing filter command */ + WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID, + /** chatter coalecing query command */ + WMI_CHATTER_COALESCING_QUERY_CMDID, + + /**addba specific commands */ + /** start the aggregation on this TID */ + WMI_PEER_TID_ADDBA_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_TID_ADDBA), + /** stop the aggregation on this TID */ + WMI_PEER_TID_DELBA_CMDID, + + /** set station mimo powersave method */ + WMI_STA_DTIM_PS_METHOD_CMDID, + /** Configure the Station UAPSD AC Auto Trigger Parameters */ + WMI_STA_UAPSD_AUTO_TRIG_CMDID, + /** Configure the Keep Alive Parameters */ + WMI_STA_KEEPALIVE_CMDID, + + /* Request ssn from target for a sta/tid pair */ + WMI_BA_REQ_SSN_CMDID, + /* misc command group */ + /** echo command mainly used for testing */ + WMI_ECHO_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MISC), + + /* !!IMPORTANT!! + * If you need to add a new WMI command to the WMI_GRP_MISC sub-group, + * please make sure you add it BEHIND WMI_PDEV_UTF_CMDID, + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /** UTF WMI commands */ + WMI_PDEV_UTF_CMDID, + + /** set debug log config */ + WMI_DBGLOG_CFG_CMDID, + /* QVIT specific command id */ + WMI_PDEV_QVIT_CMDID, + /* Factory Testing Mode request command + * used for integrated chipsets */ + WMI_PDEV_FTM_INTG_CMDID, + /* set and get keepalive parameters command */ + WMI_VDEV_SET_KEEPALIVE_CMDID, + WMI_VDEV_GET_KEEPALIVE_CMDID, + /* For fw recovery test command */ + WMI_FORCE_FW_HANG_CMDID, + /* Set Mcast/Bdcast filter */ + WMI_SET_MCASTBCAST_FILTER_CMDID, + /** set thermal management params **/ + WMI_THERMAL_MGMT_CMDID, + /** set host auto shutdown params **/ + WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID, + /** set tpc chainmask config command */ + WMI_TPC_CHAINMASK_CONFIG_CMDID, + /** set Antenna diversity command */ + WMI_SET_ANTENNA_DIVERSITY_CMDID, + /** Set OCB Sched Request, deprecated */ + WMI_OCB_SET_SCHED_CMDID, + /* Set rssi monitoring config command */ + WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID, + /* Enable/disable Large Receive Offload processing; + * provide cfg params */ + WMI_LRO_CONFIG_CMDID, + /* GPIO Configuration */ + WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_GPIO), + WMI_GPIO_OUTPUT_CMDID, + + /* Txbf configuration command */ + WMI_TXBF_CMDID, + + /* FWTEST Commands */ + WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_FWTEST), + /** set NoA descs **/ + WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID, + /* UNIT Tests */ + WMI_UNIT_TEST_CMDID, + + /** TDLS Configuration */ + /** enable/disable TDLS */ + WMI_TDLS_SET_STATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_TDLS), + /** set tdls peer state */ + WMI_TDLS_PEER_UPDATE_CMDID, + /** TDLS Offchannel control */ + WMI_TDLS_SET_OFFCHAN_MODE_CMDID, + + /** Resmgr Configuration */ + /** Adaptive OCS is enabled by default in the FW. This command is used to + * disable FW based adaptive OCS. + */ + WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_RESMGR), + /** set the requested channel time quota for the home channels */ + WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, + /** set the requested latency for the home channels */ + WMI_RESMGR_SET_CHAN_LATENCY_CMDID, + + /** STA SMPS Configuration */ + /** force SMPS mode */ + WMI_STA_SMPS_FORCE_MODE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_STA_SMPS), + /** set SMPS parameters */ + WMI_STA_SMPS_PARAM_CMDID, + + /* Wlan HB commands */ + /* enalbe/disable wlan HB */ + WMI_HB_SET_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_WLAN_HB), + /* set tcp parameters for wlan HB */ + WMI_HB_SET_TCP_PARAMS_CMDID, + /* set tcp pkt filter for wlan HB */ + WMI_HB_SET_TCP_PKT_FILTER_CMDID, + /* set udp parameters for wlan HB */ + WMI_HB_SET_UDP_PARAMS_CMDID, + /* set udp pkt filter for wlan HB */ + WMI_HB_SET_UDP_PKT_FILTER_CMDID, + + /** Wlan RMC commands*/ + /** enable/disable RMC */ + WMI_RMC_SET_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RMC), + /** configure action frame period */ + WMI_RMC_SET_ACTION_PERIOD_CMDID, + /** For debug/future enhancement purposes only, + * configures/finetunes RMC algorithms */ + WMI_RMC_CONFIG_CMDID, + + /** WLAN MHF offload commands */ + /** enable/disable MHF offload */ + WMI_MHF_OFFLOAD_SET_MODE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_MHF_OFL), + /** Plumb routing table for MHF offload */ + WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID, + + /*location scan commands */ + /*start batch scan */ + WMI_BATCH_SCAN_ENABLE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_LOCATION_SCAN), + /*stop batch scan */ + WMI_BATCH_SCAN_DISABLE_CMDID, + /*get batch scan result */ + WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID, + /* OEM related cmd */ + WMI_OEM_REQ_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_OEM), + + /** Nan Request */ + WMI_NAN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_NAN), + + /** Modem power state command */ + WMI_MODEM_POWER_STATE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_COEX), + WMI_CHAN_AVOID_UPDATE_CMDID, + + /** + * OBSS scan offload enable/disable commands + * OBSS scan enable CMD will send to FW after VDEV UP, if these conditions are true: + * 1. WMI_SERVICE_OBSS_SCAN is reported by FW in service ready, + * 2. STA connect to a 2.4Ghz ht20/ht40 AP, + * 3. AP enable 20/40 coexistence (OBSS_IE-74 can be found in beacon or association response) + * If OBSS parameters from beacon changed, also use enable CMD to update parameters. + * OBSS scan disable CMD will send to FW if have enabled when tearing down connection. + */ + WMI_OBSS_SCAN_ENABLE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_OBSS_OFL), + WMI_OBSS_SCAN_DISABLE_CMDID, + + /**LPI commands*/ + /**LPI mgmt snooping config command*/ + WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_LPI), + /**LPI scan start command*/ + WMI_LPI_START_SCAN_CMDID, + /**LPI scan stop command*/ + WMI_LPI_STOP_SCAN_CMDID, + + /** ExtScan commands */ + WMI_EXTSCAN_START_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_EXTSCAN), + WMI_EXTSCAN_STOP_CMDID, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID, + WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID, + WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID, + WMI_EXTSCAN_SET_CAPABILITIES_CMDID, + WMI_EXTSCAN_GET_CAPABILITIES_CMDID, + WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID, + WMI_EXTSCAN_CONFIGURE_MAWC_CMDID, + + /** DHCP server offload commands */ + WMI_SET_DHCP_SERVER_OFFLOAD_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_DHCP_OFL), + + /** IPA Offload features related commands */ + WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_IPA), + + /** mDNS responder offload commands */ + WMI_MDNS_OFFLOAD_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MDNS_OFL), + WMI_MDNS_SET_FQDN_CMDID, + WMI_MDNS_SET_RESPONSE_CMDID, + WMI_MDNS_GET_STATS_CMDID, + + /* enable/disable AP Authentication offload */ + WMI_SAP_OFL_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SAP_OFL), + WMI_SAP_SET_BLACKLIST_PARAM_CMDID, + + /** Out-of-context-of-BSS (OCB) commands */ + WMI_OCB_SET_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_OCB), + WMI_OCB_SET_UTC_TIME_CMDID, + WMI_OCB_START_TIMING_ADVERT_CMDID, + WMI_OCB_STOP_TIMING_ADVERT_CMDID, + WMI_OCB_GET_TSF_TIMER_CMDID, + WMI_DCC_GET_STATS_CMDID, + WMI_DCC_CLEAR_STATS_CMDID, + WMI_DCC_UPDATE_NDL_CMDID, + /* System-On-Chip commands */ + WMI_SOC_SET_PCL_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SOC), + WMI_SOC_SET_HW_MODE_CMDID, + WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID, + WMI_SOC_SET_ANTENNA_MODE_CMDID, + + /* packet filter commands */ + WMI_PACKET_FILTER_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PKT_FILTER), + WMI_PACKET_FILTER_ENABLE_CMDID, + /** Motion Aided WiFi Connectivity (MAWC) commands */ + WMI_MAWC_SENSOR_REPORT_IND_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MAWC), + + /** WMI commands related to PMF 11w Offload */ + WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID = + WMI_CMD_GRP_START_ID(WMI_GRP_PMF_OFFLOAD), + +} WMI_CMD_ID; + +typedef enum { + /** WMI service is ready; after this event WMI messages can be sent/received */ + WMI_SERVICE_READY_EVENTID = 0x1, + /** WMI is ready; after this event the wlan subsystem is initialized and can process commands. */ + WMI_READY_EVENTID, + + /** Scan specific events */ + WMI_SCAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SCAN), + + /* PDEV specific events */ + /** TPC config for the current operating channel */ + WMI_PDEV_TPC_CONFIG_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_PDEV), + /** Channel stats event */ + WMI_CHAN_INFO_EVENTID, + + /** PHY Error specific WMI event */ + WMI_PHYERR_EVENTID, + + /** eeprom dump event */ + WMI_PDEV_DUMP_EVENTID, + + /** traffic pause event */ + WMI_TX_PAUSE_EVENTID, + + /** DFS radar event */ + WMI_DFS_RADAR_EVENTID, + + /** track L1SS entry and residency event */ + WMI_PDEV_L1SS_TRACK_EVENTID, + + /** Report current temprature of the chip in Celcius degree */ + WMI_PDEV_TEMPERATURE_EVENTID, + + /* Extension of WMI_SERVICE_READY msg with + * extra target capability info + */ + WMI_SERVICE_READY_EXT_EVENTID, + + /* VDEV specific events */ + /** VDEV started event in response to VDEV_START request */ + WMI_VDEV_START_RESP_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_VDEV), + /** vdev stopped event , generated in response to VDEV_STOP request */ + WMI_VDEV_STOPPED_EVENTID, + /* Indicate the set key (used for setting per + * peer unicast and per vdev multicast) + * operation has completed */ + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + /* NOTE: WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID would be deprecated. Please + don't use this for any new implementations */ + /* Firmware requests dynamic change to a specific beacon interval for a specific vdev ID in MCC scenario. + This request is valid only for vdevs operating in soft AP or P2P GO mode */ + WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + + /* Return the TSF timestamp of specified vdev */ + WMI_VDEV_TSF_REPORT_EVENTID, + /* peer specific events */ + /** FW reauet to kick out the station for reasons like inactivity,lack of response ..etc */ + WMI_PEER_STA_KICKOUT_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_PEER), + + /** Peer Info Event with data_rate, rssi, tx_fail_cnt etc */ + WMI_PEER_INFO_EVENTID, + + /** Event indicating that TX fail count reaching threshold */ + WMI_PEER_TX_FAIL_CNT_THR_EVENTID, + /** Return the estimate link speed for the Peer specified in the + * WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID command. + */ + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID, + /* Return the peer state + * WMI_PEER_SET_PARAM_CMDID, WMI_PEER_AUTHORIZE + */ + WMI_PEER_STATE_EVENTID, + + /* Peer Assoc Conf event to confirm fw had received PEER_ASSOC_CMD. + * After that, host will send Mx message. + * Otherwise, host will pause any Mx(STA:M2/M4) message + */ + WMI_PEER_ASSOC_CONF_EVENTID, + + /* beacon/mgmt specific events */ + /** RX management frame. the entire frame is carried along with the event. */ + WMI_MGMT_RX_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MGMT), + /** software beacon alert event to Host requesting host to Queue a beacon for transmission + use only in host beacon mode */ + WMI_HOST_SWBA_EVENTID, + /** beacon tbtt offset event indicating the tsf offset of the tbtt from the theritical value. + tbtt offset is normally 0 and will be non zero if there are multiple VDEVs operating in + staggered beacon transmission mode */ + WMI_TBTTOFFSET_UPDATE_EVENTID, + + /** event after the first beacon is transmitted following + a change in the template.*/ + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID, + /** event after the first probe response is transmitted following + a change in the template.*/ + WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, + /** Event for Mgmt TX completion event */ + WMI_MGMT_TX_COMPLETION_EVENTID, + + /*ADDBA Related WMI Events */ + /** Indication the completion of the prior + WMI_PEER_TID_DELBA_CMDID(initiator) */ + WMI_TX_DELBA_COMPLETE_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_BA_NEG), + /** Indication the completion of the prior + *WMI_PEER_TID_ADDBA_CMDID(initiator) */ + WMI_TX_ADDBA_COMPLETE_EVENTID, + + /* Seq num returned from hw for a sta/tid pair */ + WMI_BA_RSP_SSN_EVENTID, + + /* Aggregation state requested by BTC */ + WMI_AGGR_STATE_TRIG_EVENTID, + + /** Roam event to trigger roaming on host */ + WMI_ROAM_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_ROAM), + + /** matching AP found from list of profiles */ + WMI_PROFILE_MATCH, + /** roam synch event */ + WMI_ROAM_SYNCH_EVENTID, + + /** P2P disc found */ + WMI_P2P_DISC_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_P2P), + + /*send noa info to host when noa is changed for beacon tx offload enable */ + WMI_P2P_NOA_EVENTID, + + /** Send EGAP Info to host */ + WMI_AP_PS_EGAP_INFO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_AP_PS), + + /* send pdev resume event to host after pdev resume. */ + WMI_PDEV_RESUME_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SUSPEND), + + /** WOW wake up host event.generated in response to WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID. + will cary wake reason */ + WMI_WOW_WAKEUP_HOST_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_WOW), + WMI_D0_WOW_DISABLE_ACK_EVENTID, + WMI_WOW_INITIAL_WAKEUP_EVENTID, + + /*RTT related event ID */ + /** RTT measurement report */ + WMI_RTT_MEASUREMENT_REPORT_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_RTT), + /** TSF measurement report */ + WMI_TSF_MEASUREMENT_REPORT_EVENTID, + /** RTT error report */ + WMI_RTT_ERROR_REPORT_EVENTID, + /*STATS specific events */ + /** txrx stats event requested by host */ + WMI_STATS_EXT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_STATS), + /** FW iface link stats Event */ + WMI_IFACE_LINK_STATS_EVENTID, + /** FW iface peer link stats Event */ + WMI_PEER_LINK_STATS_EVENTID, + /** FW Update radio stats Event */ + WMI_RADIO_LINK_STATS_EVENTID, + /** Firmware memory dump Complete event*/ + WMI_UPDATE_FW_MEM_DUMP_EVENTID, + + /** Event indicating the DIAG logs/events supported by FW */ + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID, + + /** NLO specific events */ + /** NLO match event after the first match */ + WMI_NLO_MATCH_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_NLO_OFL), + + /** NLO scan complete event */ + WMI_NLO_SCAN_COMPLETE_EVENTID, + + /** APFIND specific events */ + WMI_APFIND_EVENTID, + + /** passpoint network match event */ + WMI_PASSPOINT_MATCH_EVENTID, + + /** GTK offload stautus event requested by host */ + WMI_GTK_OFFLOAD_STATUS_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_GTK_OFL), + + /** GTK offload failed to rekey event */ + WMI_GTK_REKEY_FAIL_EVENTID, + /* CSA IE received event */ + WMI_CSA_HANDLING_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_CSA_OFL), + + /*chatter query reply event */ + WMI_CHATTER_PC_QUERY_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_CHATTER), + + /** echo event in response to echo command */ + WMI_ECHO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MISC), + + /* !!IMPORTANT!! + * If you need to add a new WMI event ID to the WMI_GRP_MISC sub-group, + * please make sure you add it BEHIND WMI_PDEV_UTF_EVENTID, + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /** UTF specific WMI event */ + WMI_PDEV_UTF_EVENTID, + + /** event carries buffered debug messages */ + WMI_DEBUG_MESG_EVENTID, + /** FW stats(periodic or on shot) */ + WMI_UPDATE_STATS_EVENTID, + /** debug print message used for tracing FW code while debugging */ + WMI_DEBUG_PRINT_EVENTID, + /** DCS wlan or non-wlan interference event + */ + WMI_DCS_INTERFERENCE_EVENTID, + /** VI spoecific event */ + WMI_PDEV_QVIT_EVENTID, + /** FW code profile data in response to profile request */ + WMI_WLAN_PROFILE_DATA_EVENTID, + /* Factory Testing Mode request event + * used for integrated chipsets */ + WMI_PDEV_FTM_INTG_EVENTID, + /* avoid list of frequencies . + */ + WMI_WLAN_FREQ_AVOID_EVENTID, + /* Indicate the keepalive parameters */ + WMI_VDEV_GET_KEEPALIVE_EVENTID, + /* Thermal Management event */ + WMI_THERMAL_MGMT_EVENTID, + + /* Container for QXDM/DIAG events */ + WMI_DIAG_DATA_CONTAINER_EVENTID, + + /* host auto shutdown event */ + WMI_HOST_AUTO_SHUTDOWN_EVENTID, + + /*update mib counters together with WMI_UPDATE_STATS_EVENTID */ + WMI_UPDATE_WHAL_MIB_STATS_EVENTID, + + /*update ht/vht info based on vdev (rx and tx NSS and preamble) */ + WMI_UPDATE_VDEV_RATE_STATS_EVENTID, + + WMI_DIAG_EVENTID, + + /** Set OCB Sched Response, deprecated */ + WMI_OCB_SET_SCHED_EVENTID, + + /* event to indicate the flush of the buffered debug messages is complete*/ + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID, + /* event to report mix/max RSSI breach events */ + WMI_RSSI_BREACH_EVENTID, + + /* GPIO Event */ + WMI_GPIO_INPUT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_GPIO), + /** upload H_CV info WMI event + * to indicate uploaded H_CV info to host + */ + WMI_UPLOADH_EVENTID, + + /** capture H info WMI event + * to indicate captured H info to host + */ + WMI_CAPTUREH_EVENTID, + /* hw RFkill */ + WMI_RFKILL_STATE_CHANGE_EVENTID, + + /* TDLS Event */ + WMI_TDLS_PEER_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_TDLS), + + /*location scan event */ + /*report the firmware's capability of batch scan */ + WMI_BATCH_SCAN_ENABLED_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_LOCATION_SCAN), + /*batch scan result */ + WMI_BATCH_SCAN_RESULT_EVENTID, + /* OEM Event */ + WMI_OEM_CAPABILITY_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_OEM), + WMI_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_OEM_ERROR_REPORT_EVENTID, + + /* NAN Event */ + WMI_NAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_NAN), + + /* LPI Event */ + WMI_LPI_RESULT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_LPI), + WMI_LPI_STATUS_EVENTID, + WMI_LPI_HANDOFF_EVENTID, + + /* ExtScan events */ + WMI_EXTSCAN_START_STOP_EVENTID = + WMI_EVT_GRP_START_ID(WMI_GRP_EXTSCAN), + WMI_EXTSCAN_OPERATION_EVENTID, + WMI_EXTSCAN_TABLE_USAGE_EVENTID, + WMI_EXTSCAN_CACHED_RESULTS_EVENTID, + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID, + WMI_EXTSCAN_CAPABILITIES_EVENTID, + WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID, + + /* mDNS offload events */ + WMI_MDNS_STATS_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MDNS_OFL), + + /* SAP Authentication offload events */ + WMI_SAP_OFL_ADD_STA_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SAP_OFL), + WMI_SAP_OFL_DEL_STA_EVENTID, + + /** Out-of-context-of-bss (OCB) events */ + WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_OCB), + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + WMI_DCC_GET_STATS_RESP_EVENTID, + WMI_DCC_UPDATE_NDL_RESP_EVENTID, + WMI_DCC_STATS_EVENTID, + /* System-On-Chip events */ + WMI_SOC_SET_HW_MODE_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SOC), + WMI_SOC_HW_MODE_TRANSITION_EVENTID, + WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID, + /** Motion Aided WiFi Connectivity (MAWC) events */ + WMI_MAWC_ENABLE_SENSOR_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MAWC), + +} WMI_EVT_ID; + +/* defines for OEM message sub-types */ +#define WMI_OEM_CAPABILITY_REQ 0x01 +#define WMI_OEM_CAPABILITY_RSP 0x02 +#define WMI_OEM_MEASUREMENT_REQ 0x03 +#define WMI_OEM_MEASUREMENT_RSP 0x04 +#define WMI_OEM_ERROR_REPORT_RSP 0x05 +#define WMI_OEM_NAN_MEAS_REQ 0x06 +#define WMI_OEM_NAN_MEAS_RSP 0x07 +#define WMI_OEM_NAN_PEER_INFO 0x08 +#define WMI_OEM_CONFIGURE_LCR 0x09 +#define WMI_OEM_CONFIGURE_LCI 0x0A + +/* below message subtype is internal to CLD. Target should + * never use internal response type + */ +#define WMI_OEM_INTERNAL_RSP 0xdeadbeef + +#define WMI_CHAN_LIST_TAG 0x1 +#define WMI_SSID_LIST_TAG 0x2 +#define WMI_BSSID_LIST_TAG 0x3 +#define WMI_IE_TAG 0x4 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_channel */ + /** primary 20 MHz channel frequency in mhz */ + A_UINT32 mhz; + /** Center frequency 1 in MHz*/ + A_UINT32 band_center_freq1; + /** Center frequency 2 in MHz - valid only for 11acvht 80plus80 mode*/ + A_UINT32 band_center_freq2; + /** channel info described below */ + A_UINT32 info; + /** contains min power, max power, reg power and reg class id. */ + A_UINT32 reg_info_1; + /** contains antennamax */ + A_UINT32 reg_info_2; +} wmi_channel; + +typedef enum { + WMI_CHANNEL_CHANGE_CAUSE_NONE = 0, + WMI_CHANNEL_CHANGE_CAUSE_CSA, +} wmi_channel_change_cause; + +/** channel info consists of 6 bits of channel mode */ + +#define WMI_SET_CHANNEL_MODE(pwmi_channel,val) do { \ + (pwmi_channel)->info &= 0xffffffc0; \ + (pwmi_channel)->info |= (val); \ +} while(0) + +#define WMI_GET_CHANNEL_MODE(pwmi_channel) ((pwmi_channel)->info & 0x0000003f ) + +#define WMI_CHAN_FLAG_HT40_PLUS 6 +#define WMI_CHAN_FLAG_PASSIVE 7 +#define WMI_CHAN_ADHOC_ALLOWED 8 +#define WMI_CHAN_AP_DISABLED 9 +#define WMI_CHAN_FLAG_DFS 10 +#define WMI_CHAN_FLAG_ALLOW_HT 11 /* HT is allowed on this channel */ +#define WMI_CHAN_FLAG_ALLOW_VHT 12 /* VHT is allowed on this channel */ +#define WMI_CHANNEL_CHANGE_CAUSE_CSA 13 /*Indicate reason for channel switch */ +#define WMI_CHAN_FLAG_HALF_RATE 14 /* Indicates half rate channel */ +#define WMI_CHAN_FLAG_QUARTER_RATE 15 /* Indicates quarter rate channel */ + +#define WMI_SET_CHANNEL_FLAG(pwmi_channel,flag) do { \ + (pwmi_channel)->info |= (1 << flag); \ +} while(0) + +#define WMI_GET_CHANNEL_FLAG(pwmi_channel,flag) \ + (((pwmi_channel)->info & (1 << flag)) >> flag) + +#define WMI_SET_CHANNEL_MIN_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xffffff00; \ + (pwmi_channel)->reg_info_1 |= (val&0xff); \ +} while(0) +#define WMI_GET_CHANNEL_MIN_POWER(pwmi_channel) ((pwmi_channel)->reg_info_1 & 0xff ) + +#define WMI_SET_CHANNEL_MAX_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xffff00ff; \ + (pwmi_channel)->reg_info_1 |= ((val&0xff) << 8); \ +} while(0) +#define WMI_GET_CHANNEL_MAX_POWER(pwmi_channel) ( (((pwmi_channel)->reg_info_1) >> 8) & 0xff ) + +#define WMI_SET_CHANNEL_REG_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xff00ffff; \ + (pwmi_channel)->reg_info_1 |= ((val&0xff) << 16); \ +} while(0) +#define WMI_GET_CHANNEL_REG_POWER(pwmi_channel) ( (((pwmi_channel)->reg_info_1) >> 16) & 0xff ) +#define WMI_SET_CHANNEL_REG_CLASSID(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0x00ffffff; \ + (pwmi_channel)->reg_info_1 |= ((val&0xff) << 24); \ +} while(0) +#define WMI_GET_CHANNEL_REG_CLASSID(pwmi_channel) ( (((pwmi_channel)->reg_info_1) >> 24) & 0xff ) + +#define WMI_SET_CHANNEL_ANTENNA_MAX(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_2 &= 0xffffff00; \ + (pwmi_channel)->reg_info_2 |= (val&0xff); \ +} while(0) +#define WMI_GET_CHANNEL_ANTENNA_MAX(pwmi_channel) ((pwmi_channel)->reg_info_2 & 0xff ) + +/* max tx power is in 1 dBm units */ +#define WMI_SET_CHANNEL_MAX_TX_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_2 &= 0xffff00ff; \ + (pwmi_channel)->reg_info_2 |= ((val&0xff)<<8); \ +} while(0) +#define WMI_GET_CHANNEL_MAX_TX_POWER(pwmi_channel) ( (((pwmi_channel)->reg_info_2)>>8) & 0xff ) + + +/** HT Capabilities*/ +#define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ +#define WMI_HT_CAP_HT20_SGI 0x0002 /* Short Guard Interval with HT20 */ +#define WMI_HT_CAP_DYNAMIC_SMPS 0x0004 /* Dynamic MIMO powersave */ +#define WMI_HT_CAP_TX_STBC 0x0008 /* B3 TX STBC */ +#define WMI_HT_CAP_TX_STBC_MASK_SHIFT 3 +#define WMI_HT_CAP_RX_STBC 0x0030 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_MASK_SHIFT 4 +#define WMI_HT_CAP_LDPC 0x0040 /* LDPC supported */ +#define WMI_HT_CAP_L_SIG_TXOP_PROT 0x0080 /* L-SIG TXOP Protection */ +#define WMI_HT_CAP_MPDU_DENSITY 0x0700 /* MPDU Density */ +#define WMI_HT_CAP_MPDU_DENSITY_MASK_SHIFT 8 +#define WMI_HT_CAP_HT40_SGI 0x0800 + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_HT_CAP_RX_STBC_1SS 0x0010 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_2SS 0x0020 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_3SS 0x0030 /* B4-B5 RX STBC */ + +#define WMI_HT_CAP_DEFAULT_ALL (WMI_HT_CAP_ENABLED | \ + WMI_HT_CAP_HT20_SGI | \ + WMI_HT_CAP_HT40_SGI | \ + WMI_HT_CAP_TX_STBC | \ + WMI_HT_CAP_RX_STBC | \ + WMI_HT_CAP_LDPC) + +/* WMI_VHT_CAP_* these maps to ieee 802.11ac vht capability information + field. The fields not defined here are not supported, or reserved. + Do not change these masks and if you have to add new one follow the + bitmask as specified by 802.11ac draft. + */ + +#define WMI_VHT_CAP_MAX_MPDU_LEN_7935 0x00000001 +#define WMI_VHT_CAP_MAX_MPDU_LEN_11454 0x00000002 +#define WMI_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003 +#define WMI_VHT_CAP_CH_WIDTH_160MHZ 0x00000004 +#define WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ 0x00000008 +#define WMI_VHT_CAP_RX_LDPC 0x00000010 +#define WMI_VHT_CAP_SGI_80MHZ 0x00000020 +#define WMI_VHT_CAP_SGI_160MHZ 0x00000040 +#define WMI_VHT_CAP_TX_STBC 0x00000080 +#define WMI_VHT_CAP_RX_STBC_MASK 0x00000300 +#define WMI_VHT_CAP_RX_STBC_MASK_SHIFT 8 +#define WMI_VHT_CAP_SU_BFORMER 0x00000800 +#define WMI_VHT_CAP_SU_BFORMEE 0x00001000 +#define WMI_VHT_CAP_MAX_CS_ANT_MASK 0x0000E000 +#define WMI_VHT_CAP_MAX_CS_ANT_MASK_SHIFT 13 +#define WMI_VHT_CAP_MAX_SND_DIM_MASK 0x00070000 +#define WMI_VHT_CAP_MAX_SND_DIM_MASK_SHIFT 16 +#define WMI_VHT_CAP_MU_BFORMER 0x00080000 +#define WMI_VHT_CAP_MU_BFORMEE 0x00100000 +#define WMI_VHT_CAP_TXOP_PS 0x00200000 +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000 +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT 23 +#define WMI_VHT_CAP_RX_FIXED_ANT 0x10000000 +#define WMI_VHT_CAP_TX_FIXED_ANT 0x20000000 + +/* TEMPORARY: + * Preserve the incorrect old name as an alias for the correct new name + * until all references to the old name have been removed from all hosts + * and targets. + */ +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIT WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_VHT_CAP_RX_STBC_1SS 0x00000100 +#define WMI_VHT_CAP_RX_STBC_2SS 0x00000200 +#define WMI_VHT_CAP_RX_STBC_3SS 0x00000300 + +/* TEMPORARY: + * Preserve the incorrect old name as an alias for the correct new name + * until all references to the old name have been removed from all hosts + * and targets. + */ +#define WMI_vHT_CAP_RX_STBC_3SS WMI_VHT_CAP_RX_STBC_3SS + +#define WMI_VHT_CAP_DEFAULT_ALL (WMI_VHT_CAP_MAX_MPDU_LEN_11454 | \ + WMI_VHT_CAP_SGI_80MHZ | \ + WMI_VHT_CAP_TX_STBC | \ + WMI_VHT_CAP_RX_STBC_MASK | \ + WMI_VHT_CAP_RX_LDPC | \ + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP | \ + WMI_VHT_CAP_RX_FIXED_ANT | \ + WMI_VHT_CAP_TX_FIXED_ANT) + +/* Interested readers refer to Rx/Tx MCS Map definition as defined in + 802.11ac + */ +#define WMI_VHT_MAX_MCS_4_SS_MASK(r,ss) ((3 & (r)) << (((ss) - 1) << 1)) +#define WMI_VHT_MAX_SUPP_RATE_MASK 0x1fff0000 +#define WMI_VHT_MAX_SUPP_RATE_MASK_SHIFT 16 + +/* WMI_SYS_CAPS_* refer to the capabilities that system support + */ +#define WMI_SYS_CAP_ENABLE 0x00000001 +#define WMI_SYS_CAP_TXPOWER 0x00000002 + +/* + * WMI Dual Band Simultaneous (DBS) hardware mode list bit-mask definitions. + * Bits 5:0 are reserved + */ +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS (28) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS (24) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS (20) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS (16) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS (12) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS (8) +#define WMI_DBS_HW_MODE_DBS_MODE_BITPOS (7) +#define WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS (6) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_MASK (0xf << WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_MASK (0xf << WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_DBS_MODE_MASK (0x1 << WMI_DBS_HW_MODE_DBS_MODE_BITPOS) +#define WMI_DBS_HW_MODE_AGILE_DFS_MODE_MASK (0x1 << WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_DBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_DBS_MODE_BITPOS, 1, value) +#define WMI_DBS_HW_MODE_AGILE_DFS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS, 1, value) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_TX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_RX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_TX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_RX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_BANDWIDTH_MASK) >> WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_BANDWIDTH_MASK) >> WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_DBS_MODE_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_DBS_MODE_MASK) >> WMI_DBS_HW_MODE_DBS_MODE_BITPOS) +#define WMI_DBS_HW_MODE_AGILE_DFS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_AGILE_DFS_MODE_MASK) >> WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS (31) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS (30) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS (29) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS, 1, value) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS) + +#define WMI_DBS_FW_MODE_CFG_DBS_BITPOS (31) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS (30) + +#define WMI_DBS_FW_MODE_CFG_DBS_MASK (0x1 << WMI_DBS_FW_MODE_CFG_DBS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_MASK (0x1 << WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS) + +#define WMI_DBS_FW_MODE_CFG_DBS_SET(fw_mode, value) \ + WMI_SET_BITS(fw_mode, WMI_DBS_FW_MODE_CFG_DBS_BITPOS, 1, value) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(fw_mode, value) \ + WMI_SET_BITS(fw_mode, WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS, 1, value) + +#define WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode) \ + ((fw_mode & WMI_DBS_FW_MODE_CFG_DBS_MASK) >> WMI_DBS_FW_MODE_CFG_DBS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode) \ + ((fw_mode & WMI_DBS_FW_MODE_CFG_AGILE_DFS_MASK) >> WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS) + +/** NOTE: This structure cannot be extended in the future without breaking WMI compatibility */ +typedef struct _wmi_abi_version { + A_UINT32 abi_version_0; + /** WMI Major and Minor versions */ + A_UINT32 abi_version_1; + /** WMI change revision */ + A_UINT32 abi_version_ns_0; + /** ABI version namespace first four dwords */ + A_UINT32 abi_version_ns_1; + /** ABI version namespace second four dwords */ + A_UINT32 abi_version_ns_2; + /** ABI version namespace third four dwords */ + A_UINT32 abi_version_ns_3; + /** ABI version namespace fourth four dwords */ +} wmi_abi_version; + +/* + * maximum number of memroy requests allowed from FW. + */ +#define WMI_MAX_MEM_REQS 16 + +/* !!NOTE!!: + * This HW_BD_INFO_SIZE cannot be changed without breaking compatibility. + * Please don't change it. + */ +#define HW_BD_INFO_SIZE 5 + +/** + * The following struct holds optional payload for + * wmi_service_ready_event_fixed_param,e.g., 11ac pass some of the + * device capability to the host. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SERVICE_READY_EVENT */ + A_UINT32 fw_build_vers; /* firmware build number */ + wmi_abi_version fw_abi_vers; + A_UINT32 phy_capability; /* WMI_PHY_CAPABILITY */ + A_UINT32 max_frag_entry; /* Maximum number of frag table entries that SW will populate less 1 */ + A_UINT32 num_rf_chains; + /* The following field is only valid for service type WMI_SERVICE_11AC */ + A_UINT32 ht_cap_info; /* WMI HT Capability */ + A_UINT32 vht_cap_info; /* VHT capability info field of 802.11ac */ + A_UINT32 vht_supp_mcs; /* VHT Supported MCS Set field Rx/Tx same */ + A_UINT32 hw_min_tx_power; + A_UINT32 hw_max_tx_power; + A_UINT32 sys_cap_info; + A_UINT32 min_pkt_size_enable; /* Enterprise mode short pkt enable */ + /** Max beacon and Probe Response IE offload size (includes + * optional P2P IEs) */ + A_UINT32 max_bcn_ie_size; + /* + * request to host to allocate a chuck of memory and pss it down to FW via WM_INIT. + * FW uses this as FW extesnsion memory for saving its data structures. Only valid + * for low latency interfaces like PCIE where FW can access this memory directly (or) + * by DMA. + */ + A_UINT32 num_mem_reqs; + /* Max No. scan channels target can support + * If FW is too old and doesn't indicate this number, host side value will default to + * 0, and host will take the original compatible value (62) for future scan channel + * setup. + */ + A_UINT32 max_num_scan_channels; + + /* Hardware board specific ID. Values defined in enum WMI_HWBOARD_ID. + * Default 0 means tha hw_bd_info[] is invalid(legacy board). + */ + A_UINT32 hw_bd_id; + A_UINT32 hw_bd_info[HW_BD_INFO_SIZE]; /* Board specific information. Invalid if hw_hd_id is zero. */ + + /* + * Number of MACs supported, i.e. a DBS-capable device will return 2 + */ + A_UINT32 max_supported_macs; + + /* + * FW sub-feature capabilities to be used in concurrence with + * wmi_service_bitmap + * values from enum WMI_FW_SUB_FEAT_CAPS + */ + A_UINT32 wmi_fw_sub_feat_caps; + /* + * Number of Dual Band Simultaneous (DBS) hardware modes + */ + A_UINT32 num_dbs_hw_modes; + /* + * txrx_chainmask + * [7:0] - 2G band tx chain mask + * [15:8] - 2G band rx chain mask + * [23:16] - 5G band tx chain mask + * [31:24] - 5G band rx chain mask + * + */ + A_UINT32 txrx_chainmask; + + /* + * default Dual Band Simultaneous (DBS) hardware mode + */ + A_UINT32 default_dbs_hw_mode_index; + + /* + * Number of msdu descriptors target would use + */ + A_UINT32 num_msdu_desc; + + /* The TLVs for hal_reg_capabilities, wmi_service_bitmap and mem_reqs[] will follow this TLV. + * HAL_REG_CAPABILITIES hal_reg_capabilities; + * A_UINT32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + * wlan_host_mem_req mem_reqs[]; + * wlan_dbs_hw_mode_list[]; + */ +} wmi_service_ready_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + *WMITLV_TAG_STRUC_WMI_SERVICE_EXT_READY_EVENT + */ + A_UINT32 tlv_header; + /* which WMI_DBS_CONC_SCAN_CFG setting the FW is initialized with */ + A_UINT32 default_conc_scan_config_bits; + /* which WMI_DBS_FW_MODE_CFG setting the FW is initialized with */ + A_UINT32 default_fw_config_bits; +} wmi_service_ready_ext_event_fixed_param; + +typedef enum { + WMI_HWBD_NONE = 0, /* No hw board information is given */ + WMI_HWBD_QCA6174 = 1, /* Rome(AR6320) */ + WMI_HWBD_QCA2582 = 2, /* Killer 1525 */ +} WMI_HWBD_ID; + +typedef enum { + WMI_FW_STA_RTT_INITR = 0x00000001, + WMI_FW_STA_RTT_RESPR = 0x00000002, + WMI_FW_P2P_CLI_RTT_INITR = 0x00000004, + WMI_FW_P2P_CLI_RTT_RESPR = 0x00000008, + WMI_FW_P2P_GO_RTT_INITR = 0x00000010, + WMI_FW_P2P_GO_RTT_RESPR = 0x00000020, + WMI_FW_AP_RTT_INITR = 0x00000040, + WMI_FW_AP_RTT_RESPR = 0x00000080, + WMI_FW_NAN_RTT_INITR = 0x00000100, + WMI_FW_NAN_RTT_RESPR = 0x00000200, + /* + * New fw sub feature capabilites before + * WMI_FW_MAX_SUB_FEAT_CAP + */ + WMI_FW_MAX_SUB_FEAT_CAP = 0x80000000, +} WMI_FW_SUB_FEAT_CAPS; + +#define ATH_BD_DATA_REV_MASK 0x000000FF +#define ATH_BD_DATA_REV_SHIFT 0 + +#define ATH_BD_DATA_PROJ_ID_MASK 0x0000FF00 +#define ATH_BD_DATA_PROJ_ID_SHIFT 8 + +#define ATH_BD_DATA_CUST_ID_MASK 0x00FF0000 +#define ATH_BD_DATA_CUST_ID_SHIFT 16 + +#define ATH_BD_DATA_REF_DESIGN_ID_MASK 0xFF000000 +#define ATH_BD_DATA_REF_DESIGN_ID_SHIFT 24 + +#define SET_BD_DATA_REV(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_REV_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_REV_SHIFT)) + +#define GET_BD_DATA_REV(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_REV_MASK) >> ATH_BD_DATA_REV_SHIFT) + +#define SET_BD_DATA_PROJ_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_PROJ_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_PROJ_ID_SHIFT)) + +#define GET_BD_DATA_PROJ_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_PROJ_ID_MASK) >> ATH_BD_DATA_PROJ_ID_SHIFT) + +#define SET_BD_DATA_CUST_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_CUST_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_CUST_ID_SHIFT)) + +#define GET_BD_DATA_CUST_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_CUST_ID_MASK) >> ATH_BD_DATA_CUST_ID_SHIFT) + +#define SET_BD_DATA_REF_DESIGN_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_REF_DESIGN_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_REF_DESIGN_ID_SHIFT)) + +#define GET_BD_DATA_REF_DESIGN_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_REF_DESIGN_ID_MASK) >> ATH_BD_DATA_REF_DESIGN_ID_SHIFT) + +#ifdef ROME_LTE_COEX_FREQ_AVOID +typedef struct { + A_UINT32 start_freq; /* start frequency, not channel center freq */ + A_UINT32 end_freq; /* end frequency */ +} avoid_freq_range_desc; + +typedef struct { + /* bad channel range count, multi range is allowed, 0 means all channel clear */ + A_UINT32 num_freq_ranges; + /* multi range with num_freq_ranges, LTE advance multi carrier, CDMA,etc */ + avoid_freq_range_desc avd_freq_range[0]; +} wmi_wlan_avoid_freq_ranges_event; +#endif + +/** status consists of upper 16 bits fo A_STATUS status and lower 16 bits of module ID that retuned status */ +#define WLAN_INIT_STATUS_SUCCESS 0x0 +#define WLAN_INIT_STATUS_GEN_FAILED 0x1 +#define WLAN_GET_INIT_STATUS_REASON(status) ((status) & 0xffff) +#define WLAN_GET_INIT_STATUS_MODULE_ID(status) (((status) >> 16) & 0xffff) + +typedef A_UINT32 WLAN_INIT_STATUS; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ready_event_fixed_param */ + wmi_abi_version fw_abi_vers; + wmi_mac_addr mac_addr; + A_UINT32 status; +} wmi_ready_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resource_config */ +/** + * @brief num_vdev - number of virtual devices (VAPs) to support + */ + A_UINT32 num_vdevs; +/** + * @brief num_peers - number of peer nodes to support + */ + A_UINT32 num_peers; +/* + * @brief In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ + A_UINT32 num_offload_peers; +/* @brief Number of reorder buffers available for doing target based reorder + * Rx reorder buffering + */ + A_UINT32 num_offload_reorder_buffs; +/** + * @brief num_peer_keys - number of keys per peer + */ + A_UINT32 num_peer_keys; +/** + * @brief num_peer_tids - number of TIDs to provide storage for per peer. + */ + A_UINT32 num_tids; +/** + * @brief ast_skid_limit - max skid for resolving hash collisions + * @details + * The address search table is sparse, so that if two MAC addresses + * result in the same hash value, the second of these conflicting + * entries can slide to the next index in the address search table, + * and use it, if it is unoccupied. This ast_skid_limit parameter + * specifies the upper bound on how many subsequent indices to search + * over to find an unoccupied space. + */ + A_UINT32 ast_skid_limit; +/** + * @brief tx_chain_mask - the nominal chain mask for transmit + * @details + * The chain mask may be modified dynamically, e.g. to operate AP tx with + * a reduced number of chains if no clients are associated. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of tx chains. + */ + A_UINT32 tx_chain_mask; +/** + * @brief rx_chain_mask - the nominal chain mask for receive + * @details + * The chain mask may be modified dynamically, e.g. for a client to use + * a reduced number of chains for receive if the traffic to the client + * is low enough that it doesn't require downlink MIMO or antenna + * diversity. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of rx chains. + */ + A_UINT32 rx_chain_mask; +/** + * @brief rx_timeout_pri - what rx reorder timeout (ms) to use for the AC + * @details + * Each WMM access class (voice, video, best-effort, background) will + * have its own timeout value to dictate how long to wait for missing + * rx MPDUs to arrive before flushing subsequent MPDUs that have already + * been received. + * This parameter specifies the timeout in milliseconds for each class . + * NOTE: the number of class (defined as 4) cannot be + * changed in the future without breaking WMI compatibility. + */ + A_UINT32 rx_timeout_pri[4]; +/** + * @brief rx_decap mode - what mode the rx should decap packets to + * @details + * MAC can decap to RAW (no decap), native wifi or Ethernet types + * THis setting also determines the default TX behavior, however TX + * behavior can be modified on a per VAP basis during VAP init + */ + A_UINT32 rx_decap_mode; + /** + * @brief scan_max_pending_req - what is the maximum scan requests than can be queued + */ + A_UINT32 scan_max_pending_req; + + /** + * @brief maximum VDEV that could use BMISS offload + */ + A_UINT32 bmiss_offload_max_vdev; + + /** + * @brief maximum VDEV that could use offload roaming + */ + A_UINT32 roam_offload_max_vdev; + + /** + * @brief maximum AP profiles that would push to offload roaming + */ + A_UINT32 roam_offload_max_ap_profiles; + +/** + * @brief num_mcast_groups - how many groups to use for mcast->ucast conversion + * @details + * The target's WAL maintains a table to hold information regarding which + * peers belong to a given multicast group, so that if multicast->unicast + * conversion is enabled, the target can convert multicast tx frames to a + * series of unicast tx frames, to each peer within the multicast group. + * This num_mcast_groups configuration parameter tells the target how + * many multicast groups to provide storage for within its multicast + * group membership table. + */ + A_UINT32 num_mcast_groups; + +/** + * @brief num_mcast_table_elems - size to alloc for the mcast membership table + * @details + * This num_mcast_table_elems configuration parameter tells the target + * how many peer elements it needs to provide storage for in its + * multicast group membership table. + * These multicast group membership table elements are shared by the + * multicast groups stored within the table. + */ + A_UINT32 num_mcast_table_elems; + +/** + * @brief mcast2ucast_mode - whether/how to do multicast->unicast conversion + * @details + * This configuration parameter specifies whether the target should + * perform multicast --> unicast conversion on transmit, and if so, + * what to do if it finds no entries in its multicast group membership + * table for the multicast IP address in the tx frame. + * Configuration value: + * 0 -> Do not perform multicast to unicast conversion. + * 1 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, drop the frame. + * 2 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, transmit the + * frame as multicast. + */ + A_UINT32 mcast2ucast_mode; + + /** + * @brief tx_dbg_log_size - how much memory to allocate for a tx PPDU dbg log + * @details + * This parameter controls how much memory the target will allocate to + * store a log of tx PPDU meta-information (how large the PPDU was, + * when it was sent, whether it was successful, etc.) + */ + A_UINT32 tx_dbg_log_size; + + /** + * @brief num_wds_entries - how many AST entries to be allocated for WDS + */ + A_UINT32 num_wds_entries; + + /** + * @brief dma_burst_size - MAC DMA burst size, e.g., on Peregrine on PCI + * this limit can be 0 -default, 1 256B + */ + A_UINT32 dma_burst_size; + + /** + * @brief mac_aggr_delim - Fixed delimiters to be inserted after every MPDU + * to account for interface latency to avoid underrun. + */ + A_UINT32 mac_aggr_delim; + /** + * @brief rx_skip_defrag_timeout_dup_detection_check + * @details + * determine whether target is responsible for detecting duplicate + * non-aggregate MPDU and timing out stale fragments. + * + * A-MPDU reordering is always performed on the target. + * + * 0: target responsible for frag timeout and dup checking + * 1: host responsible for frag timeout and dup checking + */ + A_UINT32 rx_skip_defrag_timeout_dup_detection_check; + + /** + * @brief vow_config - Configuration for VoW : No of Video Nodes to be supported + * and Max no of descriptors for each Video link (node). + */ + A_UINT32 vow_config; + + /** + * @brief maximum VDEV that could use GTK offload + */ + A_UINT32 gtk_offload_max_vdev; + + /** + * @brief num_msdu_desc - Number of msdu descriptors target should use + */ + A_UINT32 num_msdu_desc; /* Number of msdu desc */ + /** + * @brief max_frag_entry - Max. number of Tx fragments per MSDU + * @details + * This parameter controls the max number of Tx fragments per MSDU. + * This is sent by the target as part of the WMI_SERVICE_READY event + * and is overriden by the OS shim as required. + */ + A_UINT32 max_frag_entries; + + /** + * @brief num_tdls_vdevs - Max. number of vdevs that can support TDLS + * @brief num_msdu_desc - Number of vdev that can support beacon offload + */ + + A_UINT32 num_tdls_vdevs; /* number of vdevs allowed to do tdls */ + + /** + * @brief num_tdls_conn_table_entries - Number of peers tracked by tdls vdev + * @details + * Each TDLS enabled vdev can track outgoing transmits/rssi/rates to/of + * peers in a connection tracking table for possible TDLS link creation + * or deletion. This controls the number of tracked peers per vdev. + */ + A_UINT32 num_tdls_conn_table_entries; /* number of peers to track per TDLS vdev */ + A_UINT32 beacon_tx_offload_max_vdev; + A_UINT32 num_multicast_filter_entries; + A_UINT32 num_wow_filters; /*host can configure the number of wow filters */ + + /** + * @brief num_keep_alive_pattern - Num of keep alive patterns configured + * from host. + */ + A_UINT32 num_keep_alive_pattern; + /** + * @brief keep_alive_pattern_size - keep alive pattern size. + */ + A_UINT32 keep_alive_pattern_size; + + /** + * @brief max_tdls_concurrent_sleep_sta - Number of tdls sleep sta supported + * @details + * Each TDLS STA can become a sleep STA independently. This parameter + * mentions how many such sleep STAs can be supported concurrently. + */ + A_UINT32 max_tdls_concurrent_sleep_sta; + + /** + * @brief max_tdls_concurrent_buffer_sta - Number of tdls buffer sta supported + * @details + * Each TDLS STA can become a buffer STA independently. This parameter + * mentions how many such buffer STAs can be supported concurrently. + */ + A_UINT32 max_tdls_concurrent_buffer_sta; + + /** + * @brief wmi_send_separate - host configures fw to send the wmi separately + */ + A_UINT32 wmi_send_separate; + + /** + * @brief num_ocb_vdevs - Number of vdevs used for OCB support + */ + A_UINT32 num_ocb_vdevs; + + /** + * @brief num_ocb_channels - The supported number of simultaneous OCB channels + */ + A_UINT32 num_ocb_channels; + + /** + * @brief num_ocb_schedules - The supported number of OCB schedule segments + */ + A_UINT32 num_ocb_schedules; +} wmi_resource_config; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param */ + + /** The following indicate the WMI versions to be supported by + * the host driver. Note that the host driver decide to + * "downgrade" its WMI version support and this may not be the + * native version of the host driver. */ + wmi_abi_version host_abi_vers; + + A_UINT32 num_host_mem_chunks; + /** size of array host_mem_chunks[] */ + /* The TLVs for resource_config and host_mem_chunks[] will follow. + * wmi_resource_config resource_config; + * wlan_host_memory_chunk host_mem_chunks[]; + */ + +} wmi_init_cmd_fixed_param; + +/** + * TLV for channel list + */ +typedef struct { + /** WMI_CHAN_LIST_TAG */ + A_UINT32 tag; + /** # of channels to scan */ + A_UINT32 num_chan; + /** channels in Mhz */ + A_UINT32 channel_list[1]; +} wmi_chan_list; + +/** + * TLV for bssid list + */ +typedef struct { + /** WMI_BSSID_LIST_TAG */ + A_UINT32 tag; + /** number of bssids */ + A_UINT32 num_bssid; + /** bssid list */ + wmi_mac_addr bssid_list[1]; +} wmi_bssid_list; + +/** + * TLV for ie data. + */ +typedef struct { + /** WMI_IE_TAG */ + A_UINT32 tag; + /** number of bytes in ie data */ + A_UINT32 ie_len; + /** ie data array (ie_len adjusted to number of words (ie_len + 4)/4 ) */ + A_UINT32 ie_data[1]; +} wmi_ie_data; + +typedef struct { + /** Len of the SSID */ + A_UINT32 ssid_len; + /** SSID */ + A_UINT32 ssid[8]; +} wmi_ssid; + +typedef struct { + /** WMI_SSID_LIST_TAG */ + A_UINT32 tag; + A_UINT32 num_ssids; + wmi_ssid ssids[1]; +} wmi_ssid_list; + +/* prefix used by scan requestor ids on the host */ +#define WMI_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000 +/* prefix used by scan request ids generated on the host */ +/* host cycles through the lower 12 bits to generate ids */ +#define WMI_HOST_SCAN_REQ_ID_PREFIX 0xA000 + +#define WLAN_SCAN_PARAMS_MAX_SSID 16 +#define WLAN_SCAN_PARAMS_MAX_BSSID 4 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param */ + /** Scan ID */ + A_UINT32 scan_id; + /** Scan requestor ID */ + A_UINT32 scan_req_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** Scan events subscription */ + A_UINT32 notify_scan_events; + /** dwell time in msec on active channels */ + A_UINT32 dwell_time_active; + /** dwell time in msec on passive channels */ + A_UINT32 dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_chan; + /** number of bssids. In the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid. In the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in ie data. In the TLV ie_data[]. Max len is defined by WLAN_SCAN_PARAMS_MAX_IE_LEN */ + A_UINT32 ie_len; + /** Max number of probes to be sent */ + A_UINT32 n_probes; + + /** + * TLV (tag length value ) parameters follow the scan_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + */ +} wmi_start_scan_cmd_fixed_param; + +/** + * scan control flags. + */ + +/** passively scan all channels including active channels */ +#define WMI_SCAN_FLAG_PASSIVE 0x1 +/** add wild card ssid probe request even though ssid_list is specified. */ +#define WMI_SCAN_ADD_BCAST_PROBE_REQ 0x2 +/** add cck rates to rates/xrate ie for the generated probe request */ +#define WMI_SCAN_ADD_CCK_RATES 0x4 +/** add ofdm rates to rates/xrate ie for the generated probe request */ +#define WMI_SCAN_ADD_OFDM_RATES 0x8 +/** To enable indication of Chan load and Noise floor to host */ +#define WMI_SCAN_CHAN_STAT_EVENT 0x10 +/** Filter Probe request frames */ +#define WMI_SCAN_FILTER_PROBE_REQ 0x20 +/**When set, not to scan DFS channels*/ +#define WMI_SCAN_BYPASS_DFS_CHN 0x40 +/**When set, certain errors are ignored and scan continues. + * Different FW scan engine may use its own logic to decide what errors to ignore*/ +#define WMI_SCAN_CONTINUE_ON_ERROR 0x80 +/** Enable promiscous mode for ese */ +#define WMI_SCAN_FILTER_PROMISCOUS 0x100 +/** allow to send probe req on DFS channel */ +#define WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS 0x200 +/** add TPC content in probe req frame */ +#define WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ 0x400 +/** add DS content in probe req frame */ +#define WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ 0x800 +/** use random mac address for TA for probe request frame and add + * oui specified by WMI_SCAN_PROB_REQ_OUI_CMDID to the probe req frame. + * if oui is not set by WMI_SCAN_PROB_REQ_OUI_CMDID then the flag is ignored*/ +#define WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ 0x1000 + +/** WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ +#define WMI_SCAN_CLASS_MASK 0xFF000000 + +/* + * Masks identifying types/ID of scans + * Scan_Stop macros should be the same value as below defined in UMAC + * #define IEEE80211_SPECIFIC_SCAN 0x00000000 + * #define IEEE80211_VAP_SCAN 0x01000000 + * #define IEEE80211_ALL_SCANS 0x04000000 + */ +#define WMI_SCAN_STOP_ONE 0x00000000 +#define WMI_SCN_STOP_VAP_ALL 0x01000000 +#define WMI_SCAN_STOP_ALL 0x04000000 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param */ + /** requestor requesting cancel */ + A_UINT32 requestor; + /** Scan ID */ + A_UINT32 scan_id; + /** + * Req Type + * req_type should be WMI_SCAN_STOP_ONE, WMI_SCN_STOP_VAP_ALL or WMI_SCAN_STOP_ALL + * WMI_SCAN_STOP_ONE indicates to stop a specific scan with scan_id + * WMI_SCN_STOP_VAP_ALL indicates to stop all scan requests on a specific vDev with vdev_id + * WMI_SCAN_STOP_ALL indicates to stop all scan requests in both Scheduler's queue and Scan Engine + */ + A_UINT32 req_type; + /** + * vDev ID + * used when req_type equals to WMI_SCN_STOP_VAP_ALL, it indexed the vDev on which to stop the scan + */ + A_UINT32 vdev_id; +} wmi_stop_scan_cmd_fixed_param; + +#define MAX_NUM_CHAN_PER_WMI_CMD 58 /* each WMI cmd can hold 58 channel entries at most */ +#define APPEND_TO_EXISTING_CHAN_LIST 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param */ + A_UINT32 num_scan_chans; + /** no of elements in chan_info[] */ + A_UINT32 flags; /* Flags used to control the behavior of channel list update on target side */ + /** Followed by the variable length TLV chan_info: + * wmi_channel chan_info[] */ +} wmi_scan_chan_list_cmd_fixed_param; + +/* + * Priority numbers must be sequential, starting with 0. + */ +/* NOTE: WLAN SCAN_PRIORITY_COUNT can't be changed without breaking the compatibility */ +typedef enum { + WMI_SCAN_PRIORITY_VERY_LOW = 0, + WMI_SCAN_PRIORITY_LOW, + WMI_SCAN_PRIORITY_MEDIUM, + WMI_SCAN_PRIORITY_HIGH, + WMI_SCAN_PRIORITY_VERY_HIGH, + + WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */ +} wmi_scan_priority; + +/* Five Levels for Requested Priority */ +/* VERY_LOW LOW MEDIUM HIGH VERY_HIGH */ +typedef A_UINT32 WLAN_PRIORITY_MAPPING[WMI_SCAN_PRIORITY_COUNT]; + +/** + * to keep align with UMAC implementation, we pass only vdev_type but not vdev_subtype when we overwrite an entry for a specific vdev_subtype + * ex. if we need overwrite P2P Client prority entry, we will overwrite the whole table for WLAN_M_STA + * we will generate the new WLAN_M_STA table with modified P2P Client Entry but keep STA entry intact + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param */ + /** + * used as an index to find the proper table for a specific vdev type in default_scan_priority_mapping_table + * vdev_type should be one of enum in WLAN_OPMODE which inculdes WLAN_M_IBSS, WLAN_M_STA, WLAN_M_AP and WLAN_M_MONITOR currently + */ + A_UINT32 vdev_type; + /** + * number of rows in mapping_table for a specific vdev + * for WLAN_M_STA type, there are 3 entries in the table (refer to default_scan_priority_mapping_table definition) + */ + A_UINT32 number_rows; + /** mapping_table for a specific vdev follows this TLV + * WLAN_PRIORITY_MAPPING mapping_table[]; */ +} wmi_scan_sch_priority_table_cmd_fixed_param; + +/** update flags */ +#define WMI_SCAN_UPDATE_SCAN_PRIORITY 0x1 +#define WMI_SCAN_UPDATE_SCAN_MIN_REST_TIME 0x2 +#define WMI_SCAN_UPDATE_SCAN_MAX_REST_TIME 0x4 + +typedef struct { + A_UINT32 tlv_header; + /** requestor requesting update scan request */ + A_UINT32 requestor; + /** Scan ID of the scan request that need to be update */ + A_UINT32 scan_id; + /** update flags, indicating which of the following fields are valid and need to be updated*/ + A_UINT32 scan_update_flags; + /** scan priority. Only valid if WMI_SCAN_UPDATE_SCAN_PRIORITY flag is set in scan_update_flag */ + A_UINT32 scan_priority; + /** min rest time. Only valid if WMI_SCAN_UPDATE_MIN_REST_TIME flag is set in scan_update_flag */ + A_UINT32 min_rest_time; + /** min rest time. Only valid if WMI_SCAN_UPDATE_MAX_REST_TIME flag is set in scan_update_flag */ + A_UINT32 max_rest_time; +} wmi_scan_update_request_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** oui to be used in probe request frame when random mac addresss is + * requested part of scan parameters. this is applied to both FW internal scans and + * host initated scans. host can request for random mac address with + * WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ flag. */ + A_UINT32 prob_req_oui; +} wmi_scan_prob_req_oui_cmd_fixed_param; + +enum wmi_scan_event_type { + WMI_SCAN_EVENT_STARTED = 0x1, + WMI_SCAN_EVENT_COMPLETED = 0x2, + WMI_SCAN_EVENT_BSS_CHANNEL = 0x4, + WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, + WMI_SCAN_EVENT_DEQUEUED = 0x10, /* scan request got dequeued */ + WMI_SCAN_EVENT_PREEMPTED = 0x20, /* preempted by other high priority scan */ + WMI_SCAN_EVENT_START_FAILED = 0x40, /* scan start failed */ + WMI_SCAN_EVENT_RESTARTED = 0x80, /*scan restarted */ + WMI_SCAN_EVENT_MAX = 0x8000 +}; + +enum wmi_scan_completion_reason { + /** scan related events */ + WMI_SCAN_REASON_NONE = 0xFF, + WMI_SCAN_REASON_COMPLETED = 0, + WMI_SCAN_REASON_CANCELLED = 1, + WMI_SCAN_REASON_PREEMPTED = 2, + WMI_SCAN_REASON_TIMEDOUT = 3, + WMI_SCAN_REASON_INTERNAL_FAILURE = 4, /* This reason indication failures when performaing scan */ + WMI_SCAN_REASON_MAX, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_event_fixed_param */ + /** scan event (wmi_scan_event_type) */ + A_UINT32 event; + /** status of the scan completion event */ + A_UINT32 reason; + /** channel freq , only valid for FOREIGN channel event*/ + A_UINT32 channel_freq; + /**id of the requestor whose scan is in progress */ + A_UINT32 requestor; + /**id of the scan that is in progress */ + A_UINT32 scan_id; + /**id of VDEV that requested the scan */ + A_UINT32 vdev_id; +} wmi_scan_event_fixed_param; + +/* WMI Diag event */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag is WMITLV_TAG_STRUC_wmi_diag_event_fixed_param */ + A_UINT32 time_stamp; /* Reference timestamp. diag frame contains diff value */ + A_UINT32 count; /* Number of diag frames added to current event */ + A_UINT32 dropped; + /* followed by WMITLV_TAG_ARRAY_BYTE */ +} wmi_diag_event_fixed_param; + +/* + * If FW has multiple active channels due to MCC(multi channel concurrency), + * then these stats are combined stats for all the active channels. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param */ + /** ack count, it is an incremental number, not accumulated number */ + A_UINT32 ackRcvBad; + /** bad rts count, it is an incremental number, not accumulated number */ + A_UINT32 rtsBad; + /** good rts, it is an incremental number, not accumulated number */ + A_UINT32 rtsGood; + /** fcs count, it is an incremental number, not accumulated number */ + A_UINT32 fcsBad; + /** beacon count, it is an incremental number, not accumulated number */ + A_UINT32 noBeacons; +} wmi_update_whal_mib_stats_event_fixed_param; + +/* + * This defines how much headroom is kept in the + * receive frame between the descriptor and the + * payload, in order for the WMI PHY error and + * management handler to insert header contents. + * + * This is in bytes. + */ +#define WMI_MGMT_RX_HDR_HEADROOM sizeof(wmi_comb_phyerr_rx_hdr) + WMI_TLV_HDR_SIZE + sizeof(wmi_single_phyerr_rx_hdr) + +/** This event will be used for sending scan results + * as well as rx mgmt frames to the host. The rx buffer + * will be sent as part of this WMI event. It would be a + * good idea to pass all the fields in the RX status + * descriptor up to the host. + */ +/* ATH_MAX_ANTENNA value (4) can't be changed without breaking the compatibility */ +#define ATH_MAX_ANTENNA 4 /* To support beelinear, which is up to 4 chains */ + +/** flag indicating that the the mgmt frame (probe req/beacon) is received in the context of extscan performed by FW */ +#define WMI_MGMT_RX_HDR_EXTSCAN 0x01 + +/** + * flag indicating that the the mgmt frame (probe req/beacon) is received in + * the context of matched network by FW ENLO + */ +#define WMI_MGMT_RX_HDR_ENLO 0x02 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr */ + /** channel on which this frame is received. */ + A_UINT32 channel; + /** snr information used to cal rssi */ + A_UINT32 snr; + /** Rate kbps */ + A_UINT32 rate; + /** rx phy mode WLAN_PHY_MODE */ + A_UINT32 phy_mode; + /** length of the frame */ + A_UINT32 buf_len; + /** rx status */ + A_UINT32 status; + /** RSSI of PRI 20MHz for each chain. */ + A_UINT32 rssi_ctl[ATH_MAX_ANTENNA]; + /** information about the management frame e.g. can give a scan source for a scan result mgmt frame */ + A_UINT32 flags; + /** combined RSSI, i.e. the sum of the snr + noise floor (dBm units) */ + A_INT32 rssi; + + /** delta between local TSF(TSF timestamp when frame was RXd) + * and remote TSF(TSF timestamp in the IE for mgmt frame + * beacon,proberesp for e.g). If remote TSF is not available, + * delta set to 0. + * Although tsf_delta is stored as A_UINT32, it can be negative, + * and thus would need to be sign-extended if added to a value + * larger than 32 bits. + */ + A_UINT32 tsf_delta; + /* This TLV is followed by array of bytes: + * // management frame buffer + * A_UINT8 bufp[]; + */ +} wmi_mgmt_rx_hdr; + +/* WMI PHY Error RX */ + +typedef struct { + /** TSF timestamp */ + A_UINT32 tsf_timestamp; + + /** + * Current freq1, freq2 + * + * [7:0]: freq1[lo] + * [15:8] : freq1[hi] + * [23:16]: freq2[lo] + * [31:24]: freq2[hi] + */ + A_UINT32 freq_info_1; + + /** + * Combined RSSI over all chains and channel width for this PHY error + * + * [7:0]: RSSI combined + * [15:8]: Channel width (MHz) + * [23:16]: PHY error code + * [24:16]: reserved (future use) + */ + A_UINT32 freq_info_2; + + /** + * RSSI on chain 0 through 3 + * + * This is formatted the same as the PPDU_START RX descriptor + * field: + * + * [7:0]: pri20 + * [15:8]: sec20 + * [23:16]: sec40 + * [31:24]: sec80 + */ + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; + A_UINT32 rssi_chain3; + + /** + * Last calibrated NF value for chain 0 through 3 + * + * nf_list_1: + * + * + [15:0] - chain 0 + * + [31:16] - chain 1 + * + * nf_list_2: + * + * + [15:0] - chain 2 + * + [31:16] - chain 3 + */ + A_UINT32 nf_list_1; + A_UINT32 nf_list_2; + + /** Length of the frame */ + A_UINT32 buf_len; +} wmi_single_phyerr_rx_hdr; + +#define WMI_UNIFIED_FREQINFO_1_LO 0x000000ff +#define WMI_UNIFIED_FREQINFO_1_LO_S 0 +#define WMI_UNIFIED_FREQINFO_1_HI 0x0000ff00 +#define WMI_UNIFIED_FREQINFO_1_HI_S 8 +#define WMI_UNIFIED_FREQINFO_2_LO 0x00ff0000 +#define WMI_UNIFIED_FREQINFO_2_LO_S 16 +#define WMI_UNIFIED_FREQINFO_2_HI 0xff000000 +#define WMI_UNIFIED_FREQINFO_2_HI_S 24 + +/* + * Please keep in mind that these _SET macros break macro side effect + * assumptions; don't be clever with them. + */ +#define WMI_UNIFIED_FREQ_INFO_GET(hdr, f) \ + ( WMI_F_MS( (hdr)->freq_info_1, \ + WMI_UNIFIED_FREQINFO_ ## f ## _LO ) \ + | (WMI_F_MS( (hdr)->freq_info_1, \ + WMI_UNIFIED_FREQINFO_ ## f ## _HI ) << 8) ) + +#define WMI_UNIFIED_FREQ_INFO_SET(hdr, f, v) \ + do { \ + WMI_F_RMW((hdr)->freq_info_1, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_ ## f ## _LO); \ + WMI_F_RMW((hdr)->freq_info_1, ((v) >> 8) & 0xff, \ + WMI_UNIFIED_FREQINFO_ ## f ## _HI); \ + } while (0) + +#define WMI_UNIFIED_FREQINFO_2_RSSI_COMB 0x000000ff +#define WMI_UNIFIED_FREQINFO_2_RSSI_COMB_S 0 +#define WMI_UNIFIED_FREQINFO_2_CHWIDTH 0x0000ff00 +#define WMI_UNIFIED_FREQINFO_2_CHWIDTH_S 8 +#define WMI_UNIFIED_FREQINFO_2_PHYERRCODE 0x00ff0000 +#define WMI_UNIFIED_FREQINFO_2_PHYERRCODE_S 16 + +#define WMI_UNIFIED_RSSI_COMB_GET(hdr) \ + ( (int8_t) (WMI_F_MS((hdr)->freq_info_2, \ + WMI_UNIFIED_FREQINFO_2_RSSI_COMB))) + +#define WMI_UNIFIED_RSSI_COMB_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_RSSI_COMB); + +#define WMI_UNIFIED_CHWIDTH_GET(hdr) \ + WMI_F_MS((hdr)->freq_info_2, WMI_UNIFIED_FREQINFO_2_CHWIDTH) + +#define WMI_UNIFIED_CHWIDTH_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_CHWIDTH); + +#define WMI_UNIFIED_PHYERRCODE_GET(hdr) \ + WMI_F_MS((hdr)->freq_info_2, WMI_UNIFIED_FREQINFO_2_PHYERRCODE) + +#define WMI_UNIFIED_PHYERRCODE_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_PHYERRCODE); + +#define WMI_UNIFIED_CHAIN_0 0x0000ffff +#define WMI_UNIFIED_CHAIN_0_S 0 +#define WMI_UNIFIED_CHAIN_1 0xffff0000 +#define WMI_UNIFIED_CHAIN_1_S 16 +#define WMI_UNIFIED_CHAIN_2 0x0000ffff +#define WMI_UNIFIED_CHAIN_2_S 0 +#define WMI_UNIFIED_CHAIN_3 0xffff0000 +#define WMI_UNIFIED_CHAIN_3_S 16 + +#define WMI_UNIFIED_CHAIN_0_FIELD nf_list_1 +#define WMI_UNIFIED_CHAIN_1_FIELD nf_list_1 +#define WMI_UNIFIED_CHAIN_2_FIELD nf_list_2 +#define WMI_UNIFIED_CHAIN_3_FIELD nf_list_2 + +#define WMI_UNIFIED_NF_CHAIN_GET(hdr, c) \ + ((int16_t) (WMI_F_MS((hdr)->WMI_UNIFIED_CHAIN_ ## c ## _FIELD, \ + WMI_UNIFIED_CHAIN_ ## c))) + +#define WMI_UNIFIED_NF_CHAIN_SET(hdr, c, nf) \ + WMI_F_RMW((hdr)->WMI_UNIFIED_CHAIN_ ## c ## _FIELD, (nf) & 0xffff, \ + WMI_UNIFIED_CHAIN_ ## c); + +/* + * For now, this matches what the underlying hardware is doing. + * Update ar6000ProcRxDesc() to use these macros when populating + * the rx descriptor and then we can just copy the field over + * to the WMI PHY notification without worrying about breaking + * things. + */ +#define WMI_UNIFIED_RSSI_CHAN_PRI20 0x000000ff +#define WMI_UNIFIED_RSSI_CHAN_PRI20_S 0 +#define WMI_UNIFIED_RSSI_CHAN_SEC20 0x0000ff00 +#define WMI_UNIFIED_RSSI_CHAN_SEC20_S 8 +#define WMI_UNIFIED_RSSI_CHAN_SEC40 0x00ff0000 +#define WMI_UNIFIED_RSSI_CHAN_SEC40_S 16 +#define WMI_UNIFIED_RSSI_CHAN_SEC80 0xff000000 +#define WMI_UNIFIED_RSSI_CHAN_SEC80_S 24 + +#define WMI_UNIFIED_RSSI_CHAN_SET(hdr, c, ch, rssi) \ + WMI_F_RMW((hdr)->rssi_chain ## c, (rssi) & 0xff, \ + WMI_UNIFIED_RSSI_CHAN_ ## ch); + +#define WMI_UNIFIED_RSSI_CHAN_GET(hdr, c, ch) \ + ((int8_t) (WMI_F_MS((hdr)->rssi_chain ## c, \ + WMI_UNIFIED_RSSI_CHAN_ ## ch))) + +typedef struct { + /** Phy error event header */ + wmi_single_phyerr_rx_hdr hdr; + /** frame buffer */ + A_UINT8 bufp[1]; +} wmi_single_phyerr_rx_event; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr */ + /** Phy error phy error count */ + A_UINT32 num_phyerr_events; + A_UINT32 tsf_l32; + A_UINT32 tsf_u32; + A_UINT32 buf_len; + A_UINT32 pmac_id; + /* This TLV is followed by array of bytes: + * // frame buffer - contains multiple payloads in the order: + * // header - payload, header - payload... + * (The header is of type: wmi_single_phyerr_rx_hdr) + * A_UINT8 bufp[]; + */ +} wmi_comb_phyerr_rx_hdr; + +/* WMI MGMT TX */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** xmit rate */ + A_UINT32 tx_rate; + /** xmit power */ + A_UINT32 tx_power; + /** Buffer length in bytes */ + A_UINT32 buf_len; + /* This TLV is followed by array of bytes: + * // management frame buffer + * A_UINT8 bufp[]; + */ +} wmi_mgmt_tx_hdr; + +typedef struct { + /* + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /* echoed in tx_compl_event */ + A_UINT32 desc_id; + /* MHz units */ + A_UINT32 chanfreq; + A_UINT32 paddr_lo; + A_UINT32 paddr_hi; + A_UINT32 frame_len; + /* Buffer length in bytes */ + A_UINT32 buf_len; + /* + * This TLV is followed by array of bytes: + * First 64 bytes of management frame + * A_UINT8 bufp[]; + */ +} wmi_mgmt_tx_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_echo_event_fixed_param */ + A_UINT32 value; +} wmi_echo_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param */ + A_UINT32 value; +} wmi_echo_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param */ + + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /** reg domain code */ + A_UINT32 reg_domain; + A_UINT32 reg_domain_2G; + A_UINT32 reg_domain_5G; + A_UINT32 conformance_test_limit_2G; + A_UINT32 conformance_test_limit_5G; +} wmi_pdev_set_regdomain_cmd_fixed_param; + +typedef struct { + /** true for scan start and flase for scan end */ + A_UINT32 scan_start; +} wmi_pdev_scan_cmd; + +/*Command to set/unset chip in quiet mode*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 period; /*period in TUs */ + A_UINT32 duration; /*duration in TUs */ + A_UINT32 next_start; /*offset in TUs */ + A_UINT32 enabled; /*enable/disable */ +} wmi_pdev_set_quiet_cmd_fixed_param; + +/* + * Command to enable/disable Green AP Power Save. + * This helps conserve power during AP operation. When the AP has no + * stations associated with it, the host can enable Green AP Power Save + * to request the firmware to shut down all but one transmit and receive + * chains. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 enable; /*1:enable, 0:disable */ +} wmi_pdev_green_ap_ps_enable_cmd_fixed_param; + +#define MAX_HT_IE_LEN 32 +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 ie_len; /*length of the ht ie in the TLV ie_data[] */ + A_UINT32 tx_streams; /* Tx streams supported for this HT IE */ + A_UINT32 rx_streams; /* Rx streams supported for this HT IE */ + /** The TLV for the HT IE follows: + * A_UINT32 ie_data[]; + */ +} wmi_pdev_set_ht_ie_cmd_fixed_param; + +#define MAX_VHT_IE_LEN 32 +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 ie_len; /*length of the vht ie in the TLV ie_data[] */ + A_UINT32 tx_streams; /* Tx streams supported for this HT IE */ + A_UINT32 rx_streams; /* Rx streams supported for this HT IE */ + /** The TLV for the VHT IE follows: + * A_UINT32 ie_data[]; + */ +} wmi_pdev_set_vht_ie_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + wmi_mac_addr base_macaddr; +} wmi_pdev_set_base_macaddr_cmd_fixed_param; + +/* + * For now, the spectral configuration is global rather than + * per-vdev. The vdev is a placeholder and will be ignored + * by the firmware. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 spectral_scan_count; + A_UINT32 spectral_scan_period; + A_UINT32 spectral_scan_priority; + A_UINT32 spectral_scan_fft_size; + A_UINT32 spectral_scan_gc_ena; + A_UINT32 spectral_scan_restart_ena; + A_UINT32 spectral_scan_noise_floor_ref; + A_UINT32 spectral_scan_init_delay; + A_UINT32 spectral_scan_nb_tone_thr; + A_UINT32 spectral_scan_str_bin_thr; + A_UINT32 spectral_scan_wb_rpt_mode; + A_UINT32 spectral_scan_rssi_rpt_mode; + A_UINT32 spectral_scan_rssi_thr; + A_UINT32 spectral_scan_pwr_format; + A_UINT32 spectral_scan_rpt_mode; + A_UINT32 spectral_scan_bin_scale; + A_UINT32 spectral_scan_dBm_adj; + A_UINT32 spectral_scan_chn_mask; +} wmi_vdev_spectral_configure_cmd_fixed_param; + +/* + * Enabling, disabling and triggering the spectral scan + * is a per-vdev operation. That is, it will set channel + * flags per vdev rather than globally; so concurrent scan/run + * and multiple STA (eg p2p, tdls, multi-band STA) is possible. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + /* 0 - ignore; 1 - trigger, 2 - clear trigger */ + A_UINT32 trigger_cmd; + /* 0 - ignore; 1 - enable, 2 - disable */ + A_UINT32 enable_cmd; +} wmi_vdev_spectral_enable_cmd_fixed_param; + +typedef enum { + WMI_CSA_IE_PRESENT = 0x00000001, + WMI_XCSA_IE_PRESENT = 0x00000002, + WMI_WBW_IE_PRESENT = 0x00000004, + WMI_CSWARP_IE_PRESENT = 0x00000008, +} WMI_CSA_EVENT_IES_PRESENT_FLAG; + +/* wmi CSA receive event from beacon frame */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_event_fixed_param */ + A_UINT32 i_fc_dur; +/* Bit 0-15: FC */ +/* Bit 16-31: DUR */ + wmi_mac_addr i_addr1; + wmi_mac_addr i_addr2; + /* NOTE: size of array of csa_ie[], xcsa_ie[], and wb_ie[] cannot be + * changed in the future without breaking WMI compatibility */ + A_UINT32 csa_ie[2]; + A_UINT32 xcsa_ie[2]; + A_UINT32 wb_ie[2]; + A_UINT32 cswarp_ie; + A_UINT32 ies_present_flag; /* WMI_CSA_EVENT_IES_PRESENT_FLAG */ +} wmi_csa_event_fixed_param; + +typedef enum { + /** TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + /** RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK, + /** TX power limit for 2G Radio */ + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + /** TX power limit for 5G Radio */ + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + /** TX power scale */ + WMI_PDEV_PARAM_TXPOWER_SCALE, + /** Beacon generation mode . 0: host, 1: target */ + WMI_PDEV_PARAM_BEACON_GEN_MODE, + /** Beacon generation mode . 0: staggered 1: bursted */ + WMI_PDEV_PARAM_BEACON_TX_MODE, + /** Resource manager off chan mode . + * 0: turn off off chan mode. 1: turn on offchan mode + */ + WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + /** Protection mode 0: no protection 1:use CTS-to-self 2: use RTS/CTS */ + WMI_PDEV_PARAM_PROTECTION_MODE, + /** Dynamic bandwidth 0: disable 1: enable */ + WMI_PDEV_PARAM_DYNAMIC_BW, + /** Non aggregrate/ 11g sw retry threshold.0-disable */ + WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + /** aggregrate sw retry threshold. 0-disable*/ + WMI_PDEV_PARAM_AGG_SW_RETRY_TH, + /** Station kickout threshold (non of consecutive failures).0-disable */ + WMI_PDEV_PARAM_STA_KICKOUT_TH, + /** Aggerate size scaling configuration per AC */ + WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING, + /** LTR enable */ + WMI_PDEV_PARAM_LTR_ENABLE, + /** LTR latency for BE, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_BE, + /** LTR latency for BK, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_BK, + /** LTR latency for VI, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_VI, + /** LTR latency for VO, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_VO, + /** LTR AC latency timeout, in ms */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + /** LTR platform latency override, in us */ + WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + /** LTR-M override, in us */ + WMI_PDEV_PARAM_LTR_RX_OVERRIDE, + /** Tx activity timeout for LTR, in us */ + WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + /** L1SS state machine enable */ + WMI_PDEV_PARAM_L1SS_ENABLE, + /** Deep sleep state machine enable */ + WMI_PDEV_PARAM_DSLEEP_ENABLE, + /** RX buffering flush enable */ + WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + /** RX buffering matermark */ + WMI_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + /** RX buffering timeout enable */ + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + /** RX buffering timeout value */ + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + /** pdev level stats update period in ms */ + WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + /** vdev level stats update period in ms */ + WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + /** peer level stats update period in ms */ + WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + /** beacon filter status update period */ + WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + /** QOS Mgmt frame protection MFP/PMF 0: disable, 1: enable */ + WMI_PDEV_PARAM_PMF_QOS, + /** Access category on which ARP frames are sent */ + WMI_PDEV_PARAM_ARP_AC_OVERRIDE, + /** DCS configuration */ + WMI_PDEV_PARAM_DCS, + /** Enable/Disable ANI on target */ + WMI_PDEV_PARAM_ANI_ENABLE, + /** configure the ANI polling period */ + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + /** configure the ANI listening period */ + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + /** configure OFDM immunity level */ + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + /** configure CCK immunity level */ + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + /** Enable/Disable CDD for 1x1 STAs in rate control module */ + WMI_PDEV_PARAM_DYNTXCHAIN, + /** Enable/Disable proxy STA */ + WMI_PDEV_PARAM_PROXY_STA, + /** Enable/Disable low power state when all VDEVs are inactive/idle. */ + WMI_PDEV_PARAM_IDLE_PS_CONFIG, + /** Enable/Disable power gating sleep */ + WMI_PDEV_PARAM_POWER_GATING_SLEEP, + /** Enable/Disable Rfkill */ + WMI_PDEV_PARAM_RFKILL_ENABLE, + /** Set Bursting DUR */ + WMI_PDEV_PARAM_BURST_DUR, + /** Set Bursting ENABLE */ + WMI_PDEV_PARAM_BURST_ENABLE, + /** HW rfkill config */ + WMI_PDEV_PARAM_HW_RFKILL_CONFIG, + /** Enable radio low power features */ + WMI_PDEV_PARAM_LOW_POWER_RF_ENABLE, + /** L1SS entry and residency time track */ + WMI_PDEV_PARAM_L1SS_TRACK, + /** set hyst at runtime, requirement from SS */ + WMI_PDEV_PARAM_HYST_EN, + /** Enable/ Disable POWER COLLAPSE */ + WMI_PDEV_PARAM_POWER_COLLAPSE_ENABLE, + /** configure LED system state */ + WMI_PDEV_PARAM_LED_SYS_STATE, + /** Enable/Disable LED */ + WMI_PDEV_PARAM_LED_ENABLE, + /** set DIRECT AUDIO time latency */ + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY, + /** set DIRECT AUDIO Feature ENABLE */ + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE, + /** pdev level whal mib stats update enable */ + WMI_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE, + /** ht/vht info based on vdev */ + WMI_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD, + /** Set CTS channel BW for dynamic BW adjustment feature */ + WMI_PDEV_PARAM_CTS_CBW, + /** Set GPIO pin info used by WNTS */ + WMI_PDEV_PARAM_WNTS_CONFIG, + /** Enable/Disable hardware adaptive early rx feature */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_ENABLE, + /** The minimum early rx duration, to ensure early rx duration is non-zero */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_MIN_SLEEP_SLOP, + /** Increasing/decreasing step used by hardware */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_INC_DEC_STEP, + /** The fixed early rx duration when adaptive early rx is disabled */ + WMI_PDEV_PARAM_EARLY_RX_FIX_SLEEP_SLOP, + /** Enable/Disable bmiss based adaptive beacon timeout feature */ + WMI_PDEV_PARAM_BMISS_BASED_ADAPTIVE_BTO_ENABLE, + /* + * The minimum beacon timeout duration, to ensure beacon timeout + * duration is non-zero + */ + WMI_PDEV_PARAM_BMISS_BTO_MIN_BCN_TIMEOUT, + /** Increasing/decreasing step used by hardware */ + WMI_PDEV_PARAM_BMISS_BTO_INC_DEC_STEP, + /* + * The fixed beacon timeout duration when bmiss based adaptive beacon + * timeout is disabled + */ + WMI_PDEV_PARAM_BTO_FIX_BCN_TIMEOUT, + /* + * Enable/Disable Congestion Estimator based adaptive beacon + * timeout feature */ + WMI_PDEV_PARAM_CE_BASED_ADAPTIVE_BTO_ENABLE, + /* + * combo value of ce_id, ce_threshold, ce_time, refer + * to WMI_CE_BTO_CE_ID_MASK + */ + WMI_PDEV_PARAM_CE_BTO_COMBO_CE_VALUE, + /** 2G TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_2G, + /** 2G RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK_2G, + /** 5G TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_5G, + /** 5G RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK_5G, + /* Set tx chain mask for CCK rates */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK, + /* Set tx chain mask for 1SS stream */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS, +} WMI_PDEV_PARAM; + +typedef enum { + /** Set the loglevel */ + WMI_DBGLOG_LOG_LEVEL = 0x1, + /** Enable VAP level debug */ + WMI_DBGLOG_VAP_ENABLE, + /** Disable VAP level debug */ + WMI_DBGLOG_VAP_DISABLE, + /** Enable MODULE level debug */ + WMI_DBGLOG_MODULE_ENABLE, + /** Disable MODULE level debug */ + WMI_DBGLOG_MODULE_DISABLE, + /** Enable MODULE level debug */ + WMI_DBGLOG_MOD_LOG_LEVEL, + /** set type of the debug output */ + WMI_DBGLOG_TYPE, + /** Enable Disable debug */ + WMI_DBGLOG_REPORT_ENABLE +} WMI_DBG_PARAM; + +/* param_value for param_id WMI_PDEV_PARAM_CTS_CBW */ +typedef enum { + WMI_CTS_CBW_INVALID = 0, + WMI_CTS_CBW_20, + WMI_CTS_CBW_40, + WMI_CTS_CBW_80, + WMI_CTS_CBW_80_80, + WMI_CTS_CBW_160, +} WMI_CTS_CBW; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /** parameter id */ + A_UINT32 param_id; + /** parametr value */ + A_UINT32 param_value; +} wmi_pdev_set_param_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /** parameter */ + A_UINT32 param; +} wmi_pdev_get_tpc_config_cmd_fixed_param; + +#define WMI_FAST_DIVERSITY_BIT_OFFSET 0 +#define WMI_SLOW_DIVERSITY_BIT_OFFSET 1 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param */ + A_UINT32 mac_id; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /** parameter */ + A_UINT32 value; /** bit0 is for enable/disable FAST diversity, and bit1 is for enable/disable SLOW diversity, 0->disable, 1->enable */ +} wmi_pdev_set_antenna_diversity_cmd_fixed_param; + +#define WMI_MAX_RSSI_THRESHOLD_SUPPORTED 3 + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_cmd_fixed_param + */ + A_UINT32 tlv_header; + /* vdev_id, where RSSI monitoring will take place */ + A_UINT32 vdev_id; + /* + * host will configure request_id and firmware echo + * this id in RSSI_BREACH_EVENT + */ + A_UINT32 request_id; + /* + * bit [0-2] = low_rssi_breach_enabled[0-2] + * enabled, bit [3-5] = hi_rssi_breach_enabled[0-2] + */ + A_UINT32 enabled_bitmap; + /* unit dBm. host driver to make sure [0] > [1] > [2] */ + A_UINT32 low_rssi_breach_threshold[WMI_MAX_RSSI_THRESHOLD_SUPPORTED]; + /* unit dBm. host driver to make sure [0] < [1] < [2] */ + A_UINT32 hi_rssi_breach_threshold[WMI_MAX_RSSI_THRESHOLD_SUPPORTED]; + /* + * unit dBm. once low rssi[] breached, same event + * bitmap will be generated only after signal gets better + * than this level. This value is adopted for all low_rssi_breach_threshold[3] + */ + A_UINT32 lo_rssi_reenable_hysteresis; + /* + * unit dBm. once hi rssi[] breached, same event bitmap + * will be generated only after signal gets worse than this + * level. This value is adopted for all hi_rssi_breach_threshold[3] + */ + A_UINT32 hi_rssi_reenable_histeresis; + /* + * After last event is generated, we wait + * until this interval to generate next event + */ + A_UINT32 min_report_interval; + /* this is to suppress number of event to be generated */ + A_UINT32 max_num_report; +} wmi_rssi_breach_monitor_config_fixed_param; + +typedef struct { + /** parameter */ + A_UINT32 param; +} wmi_pdev_dump_cmd; + +typedef enum { + PAUSE_TYPE_CHOP = 0x1, + /** for MCC (switch channel), only vdev_map is valid */ + PAUSE_TYPE_PS = 0x2, /** for peer station sleep in sap mode, only peer_id is valid */ + PAUSE_TYPE_UAPSD = 0x3, + /** for uapsd, only peer_id and tid_map are valid. */ + PAUSE_TYPE_P2P_CLIENT_NOA = 0x4, + /** only vdev_map is valid, actually only one vdev id is set at one time */ + PAUSE_TYPE_P2P_GO_PS = 0x5, + /** only vdev_map is valid, actually only one vdev id is set at one time */ + PAUSE_TYPE_STA_ADD_BA = 0x6, + /** only peer_id and tid_map are valid, actually only one tid is set at one time */ + PAUSE_TYPE_AP_PS = 0x7, + /** for pausing AP vdev when all the connected clients are in PS. only vdev_map is valid */ + PAUSE_TYPE_IBSS_PS = 0x8, + /** for pausing IBSS vdev when all the peers are in PS. only vdev_map is valid */ + PAUSE_TYPE_HOST = 0x15, + /** host is requesting vdev pause */ +} wmi_tx_pause_type; + +typedef enum { + ACTION_PAUSE = 0x0, + ACTION_UNPAUSE = 0x1, +} wmi_tx_pause_action; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pause_type; + A_UINT32 action; + A_UINT32 vdev_map; + A_UINT32 peer_id; + A_UINT32 tid_map; +} wmi_tx_pause_event_fixed_param; + +typedef enum { + WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK = 0, + WMI_MGMT_TX_COMP_TYPE_DISCARD, + WMI_MGMT_TX_COMP_TYPE_INSPECT, + WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK, + WMI_MGMT_TX_COMP_TYPE_MAX, +} WMI_MGMT_TX_COMP_STATUS_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 desc_id; /* from tx_send_cmd */ + A_UINT32 status; /* WMI_MGMT_TX_COMP_STATUS_TYPE */ +} wmi_mgmt_tx_compl_event_fixed_param; + +#define WMI_TPC_RATE_MAX 160 +/* WMI_TPC_TX_NUM_CHAIN macro can't be changed without breaking the WMI compatibility */ +#define WMI_TPC_TX_NUM_CHAIN 4 + +typedef enum { + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1, + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC = 0x2, + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF = 0x4, +} WMI_TPC_CONFIG_EVENT_FLAG; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param */ + A_UINT32 regDomain; + A_UINT32 chanFreq; + A_UINT32 phyMode; + A_UINT32 twiceAntennaReduction; + A_UINT32 twiceMaxRDPower; + A_INT32 twiceAntennaGain; + A_UINT32 powerLimit; + A_UINT32 rateMax; + A_UINT32 numTxChain; + A_UINT32 ctl; + A_UINT32 flags; + /* WMI_TPC_TX_NUM_CHAIN macro can't be changed without breaking the WMI compatibility */ + A_INT8 maxRegAllowedPower[WMI_TPC_TX_NUM_CHAIN]; + A_INT8 + maxRegAllowedPowerAGCDD[WMI_TPC_TX_NUM_CHAIN] + [WMI_TPC_TX_NUM_CHAIN]; + A_INT8 + maxRegAllowedPowerAGSTBC[WMI_TPC_TX_NUM_CHAIN] + [WMI_TPC_TX_NUM_CHAIN]; + A_INT8 + maxRegAllowedPowerAGTXBF[WMI_TPC_TX_NUM_CHAIN] + [WMI_TPC_TX_NUM_CHAIN]; + /* This TLV is followed by a byte array: + * A_UINT8 ratesArray[]; + */ +} wmi_pdev_tpc_config_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param */ + A_UINT32 periodCnt; + A_UINT32 L1Cnt; + A_UINT32 L11Cnt; + A_UINT32 L12Cnt; + A_UINT32 L1Entry; + A_UINT32 L11Entry; + A_UINT32 L12Entry; +} wmi_pdev_l1ss_track_event_fixed_param; + +typedef struct { + A_UINT32 len; + A_UINT32 msgref; + A_UINT32 segmentInfo; +} wmi_pdev_seg_hdr_info; + +/* + * Transmit power scale factor. + * + */ +typedef enum { + WMI_TP_SCALE_MAX = 0, /* no scaling (default) */ + WMI_TP_SCALE_50 = 1, /* 50% of max (-3 dBm) */ + WMI_TP_SCALE_25 = 2, /* 25% of max (-6 dBm) */ + WMI_TP_SCALE_12 = 3, /* 12% of max (-9 dBm) */ + WMI_TP_SCALE_MIN = 4, /* min, but still on */ + WMI_TP_SCALE_SIZE = 5, /* max num of enum */ +} WMI_TP_SCALE; + +#define WMI_MAX_DEBUG_MESG (sizeof(A_UINT32) * 32) + +typedef struct { + /** message buffer, NULL terminated */ + char bufp[WMI_MAX_DEBUG_MESG]; +} wmi_debug_mesg_event; + +enum { + /** IBSS station */ + VDEV_TYPE_IBSS = 0, + /** infra STA */ + VDEV_TYPE_STA = 1, + /** infra AP */ + VDEV_TYPE_AP = 2, + /** Monitor */ + VDEV_TYPE_MONITOR = 3, + /** OCB */ + VDEV_TYPE_OCB = 6, +}; + +enum { + /** P2P device */ + VDEV_SUBTYPE_P2PDEV = 0, + /** P2P client */ + VDEV_SUBTYPE_P2PCLI, + /** P2P GO */ + VDEV_SUBTYPE_P2PGO, + /** BT3.0 HS */ + VDEV_SUBTYPE_BT, +}; + +typedef struct { + /** idnore power , only use flags , mode and freq */ + wmi_channel chan; +} wmi_pdev_set_channel_cmd; + +typedef enum { + WMI_PKTLOG_EVENT_RX = 0x1, + WMI_PKTLOG_EVENT_TX = 0x2, + WMI_PKTLOG_EVENT_RCF = 0x4, /* Rate Control Find */ + WMI_PKTLOG_EVENT_RCU = 0x8, /* Rate Control Update */ + /* 0x10 used by deprecated DBG_PRINT */ + WMI_PKTLOG_EVENT_SMART_ANTENNA = 0x20, /* To support Smart Antenna */ +} WMI_PKTLOG_EVENT; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + WMI_PKTLOG_EVENT evlist; +} wmi_pdev_pktlog_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param */ + A_UINT32 reserved0; +} wmi_pdev_pktlog_disable_cmd_fixed_param; + +/** Customize the DSCP (bit) to TID (0-7) mapping for QOS. + * NOTE: This constant cannot be changed without breaking + * WMI Compatibility. */ + +#define WMI_DSCP_MAP_MAX (64) +/* + * @brief dscp_tid_map_cmdid - command to send the dscp to tid map to the target + * @details + * Create an API for sending the custom DSCP-to-TID map to the target + * If this is a request from the user space or from above the UMAC + * then the best place to implement this is in the umac_if_offload of the OL path. + * Provide a place holder for this API in the ieee80211com (ic). + * + * This API will be a function pointer in the ieee80211com (ic). Any user space calls for manually setting the DSCP-to-TID mapping + * in the target should be directed to the function pointer in the ic. + * + * Implementation details of the API to send the map to the target are as described- + * + * 1. The function will have 2 arguments- struct ieee80211com, DSCP-to-TID map. + * DSCP-to-TID map is a one dimensional uint32_t array of length 64 to accomodate + * 64 TID values for 2^6 (64) DSCP ids. + * Example: + * A_UINT32 dscp_tid_map[WMI_DSCP_MAP_MAX] = { + * 0, 0, 0, 0, 0, 0, 0, 0, + * 1, 1, 1, 1, 1, 1, 1, 1, + * 2, 2, 2, 2, 2, 2, 2, 2, + * 3, 3, 3, 3, 3, 3, 3, 3, + * 4, 4, 4, 4, 4, 4, 4, 4, + * 5, 5, 5, 5, 5, 5, 5, 5, + * 6, 6, 6, 6, 6, 6, 6, 6, + * 7, 7, 7, 7, 7, 7, 7, 7, + * }; + * + * 2. Request for the WMI buffer of size equal to the size of the DSCP-to-TID map. + * + * 3. Copy the DSCP-to-TID map into the WMI buffer. + * + * 4. Invoke the wmi_unified_cmd_send to send the cmd buffer to the target with the + * WMI_PDEV_SET_DSCP_TID_MAP_CMDID. Arguments to the wmi send cmd API + * (wmi_unified_send_cmd) are wmi handle, cmd buffer, length of the cmd buffer and + * the WMI_PDEV_SET_DSCP_TID_MAP_CMDID id. + * + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /* map indicating DSCP to TID conversion */ + A_UINT32 dscp_to_tid_map[WMI_DSCP_MAP_MAX]; +} wmi_pdev_set_dscp_tid_map_cmd_fixed_param; + +/** Fixed rate (rate-code) for broadcast/ multicast data frames */ +/* @brief bcast_mcast_data_rate - set the rates for the bcast/ mcast frames + * @details + * Create an API for setting the custom rate for the MCAST and BCAST frames + * in the target. If this is a request from the user space or from above the UMAC + * then the best place to implement this is in the umac_if_offload of the OL path. + * Provide a place holder for this API in the ieee80211com (ic). + * + * Implementation details of the API to set custom rates for MCAST and BCAST in + * the target are as described- + * + * 1. The function will have 3 arguments- + * vap structure, + * MCAST/ BCAST identifier code, + * 8 bit rate code + * + * The rate-code is a 1-byte field in which:for given rate, nss and preamble + * b'7-b-6 indicate the preamble (0 OFDM, 1 CCK, 2, HT, 3 VHT) + * b'5-b'4 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3) + * b'3-b'0 indicate the rate, which is indicated as follows: + * OFDM : 0: OFDM 48 Mbps + * 1: OFDM 24 Mbps + * 2: OFDM 12 Mbps + * 3: OFDM 6 Mbps + * 4: OFDM 54 Mbps + * 5: OFDM 36 Mbps + * 6: OFDM 18 Mbps + * 7: OFDM 9 Mbps + * CCK (pream == 1) + * 0: CCK 11 Mbps Long + * 1: CCK 5.5 Mbps Long + * 2: CCK 2 Mbps Long + * 3: CCK 1 Mbps Long + * 4: CCK 11 Mbps Short + * 5: CCK 5.5 Mbps Short + * 6: CCK 2 Mbps Short + * HT/VHT (pream == 2/3) + * 0..7: MCS0..MCS7 (HT) + * 0..9: MCS0..MCS9 (VHT) + * + * 2. Invoke the wmi_unified_vdev_set_param_send to send the rate value + * to the target. + * Arguments to the API are- + * wmi handle, + * VAP interface id (av_if_id) defined in ol_ath_vap_net80211, + * WMI_VDEV_PARAM_BCAST_DATA_RATE/ WMI_VDEV_PARAM_MCAST_DATA_RATE, + * rate value. + */ +typedef enum { + WMI_SET_MCAST_RATE, + WMI_SET_BCAST_RATE +} MCAST_BCAST_RATE_ID; + +typedef struct { + MCAST_BCAST_RATE_ID rate_id; + A_UINT32 rate; +} mcast_bcast_rate; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wmm_params */ + A_UINT32 cwmin; + A_UINT32 cwmax; + A_UINT32 aifs; + A_UINT32 txoplimit; + A_UINT32 acm; + A_UINT32 no_ack; +} wmi_wmm_params; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param */ + A_UINT32 reserved0; + /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 dg_type; + + /* The TLVs for the 4 AC follows: + * wmi_wmm_params wmm_params_ac_be; + * wmi_wmm_params wmm_params_ac_bk; + * wmi_wmm_params wmm_params_ac_vi; + * wmi_wmm_params wmm_params_ac_vo; + */ +} wmi_pdev_set_wmm_params_cmd_fixed_param; + +typedef enum { + WMI_REQUEST_PEER_STAT = 0x01, + WMI_REQUEST_AP_STAT = 0x02, + WMI_REQUEST_PDEV_STAT = 0x04, + WMI_REQUEST_VDEV_STAT = 0x08, + WMI_REQUEST_BCNFLT_STAT = 0x10, + WMI_REQUEST_VDEV_RATE_STAT = 0x20, +} wmi_stats_id; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param */ + wmi_stats_id stats_id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_request_stats_cmd_fixed_param; + +/* stats type bitmap */ +#define WMI_LINK_STATS_RADIO 0x00000001 +#define WMI_LINK_STATS_IFACE 0x00000002 +#define WMI_LINK_STATS_ALL_PEER 0x00000004 +#define WMI_LINK_STATS_PER_PEER 0x00000008 + +/* wifi clear statistics bitmap */ +#define WIFI_STATS_RADIO 0x00000001 /** all radio statistics */ +#define WIFI_STATS_RADIO_CCA 0x00000002 /** cca_busy_time (within radio statistics) */ +#define WIFI_STATS_RADIO_CHANNELS 0x00000004 /** all channel statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_SCAN 0x00000008 /** all scan statistics (within radio statistics) */ +#define WIFI_STATS_IFACE 0x00000010 /** all interface statistics */ +#define WIFI_STATS_IFACE_TXRATE 0x00000020 /** all tx rate statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_AC 0x00000040 /** all ac statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_CONTENTION 0x00000080 /** all contention (min, max, avg) statistics (within ac statisctics) */ +#define WMI_STATS_IFACE_ALL_PEER 0x00000100 /** All peer stats on this interface */ +#define WMI_STATS_IFACE_PER_PEER 0x00000200 /** Clear particular peer stats depending on the peer_mac */ + +/** Default value for stats if the stats collection has not started */ +#define WMI_STATS_VALUE_INVALID 0xffffffff + +#define WMI_DIAG_ID_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 0, 16) +#define WMI_DIAG_ID_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 0, 16, value) +#define WMI_DIAG_TYPE_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 16, 1) +#define WMI_DIAG_TYPE_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 16, 1, value) +#define WMI_DIAG_ID_ENABLED_DISABLED_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 17, 1) +#define WMI_DIAG_ID_ENABLED_DISABLED_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 17, 1, value) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param */ + A_UINT32 num_of_diag_events_logs; +/* The TLVs will follow. + * A_UINT32 diag_events_logs_list[]; 0-15 Bits Diag EVENT/LOG ID, + * Bit 16 - DIAG type EVENT/LOG, 0 - Event, 1 - LOG + * Bit 17 Indicate if the DIAG type is Enabled/Disabled. + */ +} wmi_diag_event_log_config_fixed_param; + +#define WMI_DIAG_FREQUENCY_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 17, 1) +#define WMI_DIAG_FREQUENCY_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 17, 1, value) +#define WMI_DIAG_EXT_FEATURE_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 18, 1) +#define WMI_DIAG_EXT_FEATURE_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 18, 1, value) + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 num_of_diag_events_logs; +/* The TLVs will follow. + * A_UINT32 diag_events_logs_list[]; 0-15 Bits Diag EVENT/LOG ID, + * Bit 16 - DIAG type EVENT/LOG, 0 - Event, 1 - LOG + * Bit 17 - Frequncy of the DIAG EVENT/LOG High Frequency -1, Low Frequency - 0 + * Bit 18 - Set if the EVENTS/LOGs are used for EXT DEBUG Framework + */ +} wmi_diag_event_log_supported_event_fixed_params; + +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param + */ + A_UINT32 tlv_header; + /** placeholder for future */ + A_UINT32 reserved0; +} wmi_debug_mesg_flush_fixed_param; + +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param + */ + A_UINT32 tlv_header; + /** placeholder for future */ + A_UINT32 reserved0; +} wmi_debug_mesg_flush_complete_fixed_param; + + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rssi_breach_fixed_param + * vdev_id, where RSSI breach event occurred + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /* request id */ + A_UINT32 request_id; + /* + * bitmap[0-2] is corresponding to low_rssi[0-2]. bitmap[3-5] is + * corresponding to hi_rssi[0-2] + */ + A_UINT32 event_bitmap; + /* rssi at the time of RSSI breach. Unit dBm */ + A_UINT32 rssi; + /* bssid of the monitored AP's */ + wmi_mac_addr bssid; +} wmi_rssi_breach_event_fixed_param; + + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_fw_mem_dump */ + A_UINT32 tlv_header; + /** unique id identifying the segment */ + A_UINT32 seg_id; + /** Start address of the segment to be read */ + A_UINT32 seg_start_addr_lo; + A_UINT32 seg_start_addr_hi; + /** Length of the segment to be read */ + A_UINT32 seg_length; + /** Host bufeer address to which the segment will be read and dumped */ + A_UINT32 dest_addr_lo; + A_UINT32 dest_addr_hi; +} wmi_fw_mem_dump; + +/* Command to get firmware memory dump*/ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the request */ + A_UINT32 request_id; + /** number of memory dump segments */ + A_UINT32 num_fw_mem_dump_segs; + /** + * This TLV is followed by another TLV + * wmi_fw_mem_dump fw_mem_dump[]; + */ +} wmi_get_fw_mem_dump_fixed_param; + +/** Event to indicate the completion of fw mem dump */ +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the request, given + * in the request stats command */ + A_UINT32 request_id; + /*In case of Firmware memory dump */ + A_UINT32 fw_mem_dump_complete; +} wmi_update_fw_mem_dump_fixed_param; + +typedef enum { + WMI_ROAMING_IDLE = 0, + WMI_ROAMING_ACTIVE = 1, +} wmi_roam_state; + +/* access categories */ +typedef enum { + WMI_AC_VO = 0, + WMI_AC_VI = 1, + WMI_AC_BE = 2, + WMI_AC_BK = 3, + WMI_AC_MAX = 4, +} wmi_traffic_ac; + +typedef enum { + WMI_STA_STATS = 0, + WMI_SOFTAP_STATS = 1, + WMI_IBSS_STATS = 2, + WMI_P2P_CLIENT_STATS = 3, + WMI_P2P_GO_STATS = 4, + WMI_NAN_STATS = 5, + WMI_MESH_STATS = 6, +} wmi_link_iface_type; + +/* channel operating width */ +typedef enum { + WMI_CHAN_WIDTH_20 = 0, + WMI_CHAN_WIDTH_40 = 1, + WMI_CHAN_WIDTH_80 = 2, + WMI_CHAN_WIDTH_160 = 3, + WMI_CHAN_WIDTH_80P80 = 4, + WMI_CHAN_WIDTH_5 = 5, + WMI_CHAN_WIDTH_10 = 6, +} wmi_channel_width; + +/*Clear stats*/ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** stop_stats_collection_req = 1 will imply stop the statistics collection */ + A_UINT32 stop_stats_collection_req; + /** identifies what stats to be cleared */ + A_UINT32 stats_clear_req_mask; + /** identifies which peer stats to be cleared. Valid only while clearing PER_REER */ + wmi_mac_addr peer_macaddr; +} wmi_clear_link_stats_cmd_fixed_param; + +/* Link Stats configuration params. Trigger the link layer statistics collection*/ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param */ + /** threshold to classify the pkts as short or long */ + A_UINT32 mpdu_size_threshold; + /** set for field debug mode. Driver should collect all statistics regardless of performance impact.*/ + A_UINT32 aggressive_statistics_gathering; +} wmi_start_link_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param */ + /** Type of stats required. This is a bitmask WMI_LINK_STATS_RADIO, WMI_LINK_STATS_IFACE */ + A_UINT32 stats_type; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** unique id identifying the request, generated by the caller */ + A_UINT32 request_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_request_link_stats_cmd_fixed_param; + +/* channel statistics */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_channel_stats */ + /** Channel width (20, 40, 80, 80+80, 160) enum wmi_channel_width*/ + A_UINT32 channel_width; + /** Primary 20 MHz channel */ + A_UINT32 center_freq; + /** center frequency (MHz) first segment */ + A_UINT32 center_freq0; + /** center frequency (MHz) second segment */ + A_UINT32 center_freq1; + /** msecs the radio is awake (32 bits number accruing over time) */ + A_UINT32 radio_awake_time; + /** msecs the CCA register is busy (32 bits number accruing over time) */ + A_UINT32 cca_busy_time; +} wmi_channel_stats; + +/* radio statistics */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_radio_link_stats */ + /** Wifi radio (if multiple radio supported) */ + A_UINT32 radio_id; + /** msecs the radio is awake (32 bits number accruing over time) */ + A_UINT32 on_time; + /** msecs the radio is transmitting (32 bits number accruing over time) */ + A_UINT32 tx_time; + /** msecs the radio is in active receive (32 bits number accruing over time) */ + A_UINT32 rx_time; + /** msecs the radio is awake due to all scan (32 bits number accruing over time) */ + A_UINT32 on_time_scan; + /** msecs the radio is awake due to NAN (32 bits number accruing over time) */ + A_UINT32 on_time_nbd; + /** msecs the radio is awake due to G?scan (32 bits number accruing over time) */ + A_UINT32 on_time_gscan; + /** msecs the radio is awake due to roam?scan (32 bits number accruing over time) */ + A_UINT32 on_time_roam_scan; + /** msecs the radio is awake due to PNO scan (32 bits number accruing over time) */ + A_UINT32 on_time_pno_scan; + /** msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits number accruing over time) */ + A_UINT32 on_time_hs20; + /** number of channels */ + A_UINT32 num_channels; +} wmi_radio_link_stats; + +/** Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** Number of radios*/ + A_UINT32 num_radio; + /** more_data will be set depending on the number of radios */ + A_UINT32 more_radio_events; +/* + * This TLV is followed by another TLV of array of bytes + * size of(struct wmi_radio_link_stats); + * + * This TLV is followed by another TLV of array of bytes + * num_channels * size of(struct wmi_channel_stats) + */ + +} wmi_radio_link_stats_event_fixed_param; + +/* per rate statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rate_stats */ + /** rate information + * The rate-code is a 1-byte field in which:for given rate, nss and preamble + * b'7-b-6 indicate the preamble (0 OFDM, 1 CCK, 2, HT, 3 VHT) + * b'5-b'4 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3) + * b'3-b'0 indicate the rate, which is indicated as follows: + * OFDM : 0: OFDM 48 Mbps + * 1: OFDM 24 Mbps + * 2: OFDM 12 Mbps + * 3: OFDM 6 Mbps + * 4: OFDM 54 Mbps + * 5: OFDM 36 Mbps + * 6: OFDM 18 Mbps + * 7: OFDM 9 Mbps + * CCK (pream == 1) + * 0: CCK 11 Mbps Long + * 1: CCK 5.5 Mbps Long + * 2: CCK 2 Mbps Long + * 3: CCK 1 Mbps Long + * 4: CCK 11 Mbps Short + * 5: CCK 5.5 Mbps Short + * 6: CCK 2 Mbps Short + * HT/VHT (pream == 2/3) + * 0..7: MCS0..MCS7 (HT) + * 0..9: MCS0..MCS9 (VHT) + */ + A_UINT32 rate; + /** units of 100 Kbps */ + A_UINT32 bitrate; + /** number of successfully transmitted data pkts (ACK rcvd) */ + A_UINT32 tx_mpdu; + /** number of received data pkts */ + A_UINT32 rx_mpdu; + /** number of data packet losses (no ACK) */ + A_UINT32 mpdu_lost; + /** total number of data pkt retries */ + A_UINT32 retries; + /** number of short data pkt retries */ + A_UINT32 retries_short; + /** number of long data pkt retries */ + A_UINT32 retries_long; +} wmi_rate_stats; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_link_stats */ + /** peer type (AP, TDLS, GO etc.) enum wmi_peer_type*/ + A_UINT32 peer_type; + /** mac address */ + wmi_mac_addr peer_mac_address; + /** peer wmi_CAPABILITY_XXX */ + A_UINT32 capabilities; + /** number of rates */ + A_UINT32 num_rates; +} wmi_peer_link_stats; + +/** PEER statistics (once started) reset and start afresh after each connection */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** number of peers accomidated in this particular event */ + A_UINT32 num_peers; + /** Indicates the fragment number */ + A_UINT32 peer_event_number; + /** Indicates if there are more peers which will be sent as seperate peer_stats event */ + A_UINT32 more_data; + +/** + * This TLV is followed by another TLV + * num_peers * size of(struct wmi_peer_stats) + * num_rates * size of(struct wmi_rate_stats). num_rates is the sum of the rates of all the peers. + */ +} wmi_peer_stats_event_fixed_param; + +/* per access category statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wmm_ac_stats */ + /** access category (VI, VO, BE, BK) enum wmi_traffic_ac*/ + A_UINT32 ac_type; + /** number of successfully transmitted unicast data pkts (ACK rcvd) */ + A_UINT32 tx_mpdu; + /** number of received unicast mpdus */ + A_UINT32 rx_mpdu; + /** number of succesfully transmitted multicast data packets */ + /** STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent */ + A_UINT32 tx_mcast; + /** number of received multicast data packets */ + A_UINT32 rx_mcast; + /** number of received unicast a-mpdus */ + A_UINT32 rx_ampdu; + /** number of transmitted unicast a-mpdus */ + A_UINT32 tx_ampdu; + /** number of data pkt losses (no ACK) */ + A_UINT32 mpdu_lost; + /** total number of data pkt retries */ + A_UINT32 retries; + /** number of short data pkt retries */ + A_UINT32 retries_short; + /** number of long data pkt retries */ + A_UINT32 retries_long; + /** data pkt min contention time (usecs) */ + A_UINT32 contention_time_min; + /** data pkt max contention time (usecs) */ + A_UINT32 contention_time_max; + /** data pkt avg contention time (usecs) */ + A_UINT32 contention_time_avg; + /** num of data pkts used for contention statistics */ + A_UINT32 contention_num_samples; +} wmi_wmm_ac_stats; + +/* interface statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_iface_link_stats */ + /** access point beacon received count from connected AP */ + A_UINT32 beacon_rx; + /** access point mgmt frames received count from connected AP (including Beacon) */ + A_UINT32 mgmt_rx; + /** action frames received count */ + A_UINT32 mgmt_action_rx; + /** action frames transmit count */ + A_UINT32 mgmt_action_tx; + /** access Point Beacon and Management frames RSSI (averaged) */ + A_UINT32 rssi_mgmt; + /** access Point Data Frames RSSI (averaged) from connected AP */ + A_UINT32 rssi_data; + /** access Point ACK RSSI (averaged) from connected AP */ + A_UINT32 rssi_ack; + /** number of peers */ + A_UINT32 num_peers; + /** Indicates how many peer_stats events will be sent depending on the num_peers. */ + A_UINT32 num_peer_events; + /** number of ac */ + A_UINT32 num_ac; + /** Roaming Stat */ + A_UINT32 roam_state; + /** + * Average Beacon spread offset is the averaged time delay between TBTT + * and beacon TSF */ + /** Upper 32 bits of averaged 64 bit beacon spread offset */ + A_UINT32 avg_bcn_spread_offset_high; + /** Lower 32 bits of averaged 64 bit beacon spread offset */ + A_UINT32 avg_bcn_spread_offset_low; + /** Takes value of 1 if AP leaks packets after sending an ACK for PM=1 otherwise 0 */ + A_UINT32 is_leaky_ap; + /** Average number of frames received from AP after receiving the ACK for a frame with PM=1 */ + A_UINT32 avg_rx_frms_leaked; + /** Rx leak watch window currently in force to minimize data loss + * because of leaky AP. Rx leak window is the + * time driver waits before shutting down the radio or switching the + * channel and after receiving an ACK for + * a data frame with PM bit set) */ + A_UINT32 rx_leak_window; +} wmi_iface_link_stats; + +/** Interface statistics (once started) reset and start afresh after each connection */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +/* + * This TLV is followed by another TLV + * wmi_iface_link_stats iface_link_stats; + * num_ac * size of(struct wmi_wmm_ac_stats) + */ +} wmi_iface_link_stats_event_fixed_param; + +/** Suspend option */ +enum { + WMI_PDEV_SUSPEND, /* suspend */ + WMI_PDEV_SUSPEND_AND_DISABLE_INTR, /* suspend and disable all interrupts */ +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param */ + /* suspend option sent to target */ + A_UINT32 reserved0; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 suspend_opt; +} wmi_pdev_suspend_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_pdev_resume_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, */ + A_UINT32 num_vdev_stats; /* number of vdevs */ +} wmi_vdev_rate_stats_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len, tag equals WMITLV_TAG_STRUC_wmi_vdev_rate_ht_info */ + A_UINT32 vdevid; /* Id of the wlan vdev */ + A_UINT32 tx_nss; /* Bit 28 of tx_rate_kbps has this info - based on last data packet transmitted */ + A_UINT32 rx_nss; /* Bit 24 of rx_rate_kbps - same as above */ + A_UINT32 tx_preamble; /* Bits 30-29 from tx_rate_kbps */ + A_UINT32 rx_preamble; /* Bits 26-25 from rx_rate_kbps */ +} wmi_vdev_rate_ht_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats_event_fixed_param */ + wmi_stats_id stats_id; + /** number of pdev stats event structures (wmi_pdev_stats) 0 or 1 */ + A_UINT32 num_pdev_stats; + /** number of vdev stats event structures (wmi_vdev_stats) 0 or max vdevs */ + A_UINT32 num_vdev_stats; + /** number of peer stats event structures (wmi_peer_stats) 0 or max peers */ + A_UINT32 num_peer_stats; + A_UINT32 num_bcnflt_stats; + /** number of chan stats event structures (wmi_chan_stats) 0 to MAX MCC CHANS */ + A_UINT32 num_chan_stats; + /* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_pdev_stats * size of(struct wmi_pdev_stats) + * num_vdev_stats * size of(struct wmi_vdev_stats) + * num_peer_stats * size of(struct wmi_peer_stats) + * num_bcnflt_stats * size_of() + * num_chan_stats * size of(struct wmi_chan_stats) + * + */ +} wmi_stats_event_fixed_param; + +/** + * PDEV statistics + * @todo + * add all PDEV stats here + */ +typedef struct { + /** Channel noise floor */ + A_INT32 chan_nf; + /** TX frame count */ + A_UINT32 tx_frame_count; + /** RX frame count */ + A_UINT32 rx_frame_count; + /** rx clear count */ + A_UINT32 rx_clear_count; + /** cycle count */ + A_UINT32 cycle_count; + /** Phy error count */ + A_UINT32 phy_err_count; + /** Channel Tx Power */ + A_UINT32 chan_tx_pwr; + /** WAL dbg stats */ + struct wlan_dbg_stats pdev_stats; + +} wmi_pdev_stats; + +/** + * VDEV statistics + * @todo + * add all VDEV stats here + */ + +typedef struct { + A_INT32 bcn_snr; + A_INT32 dat_snr; +} wmi_snr_info; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + wmi_snr_info vdev_snr; + A_UINT32 tx_frm_cnt[WLAN_MAX_AC]; /* Total number of packets(per AC) that were successfully transmitted(with and without retries, including multi-cast, broadcast) */ + A_UINT32 rx_frm_cnt; /* Total number of packets that were successfully received (after appropriate filter rules including multi-cast, broadcast) */ + A_UINT32 multiple_retry_cnt[WLAN_MAX_AC]; /*The number of MSDU packets and MMPDU frames per AC + that the 802.11 station successfully transmitted after more than one retransmission attempt */ + A_UINT32 fail_cnt[WLAN_MAX_AC]; /*Total number packets(per AC) failed to transmit */ + A_UINT32 rts_fail_cnt; /*Total number of RTS/CTS sequence failures for transmission of a packet */ + A_UINT32 rts_succ_cnt; /*Total number of RTS/CTS sequence success for transmission of a packet */ + A_UINT32 rx_err_cnt; /*The receive error count. HAL will provide the RxP FCS error global */ + A_UINT32 rx_discard_cnt; /* The sum of the receive error count and dropped-receive-buffer error count. (FCS error) */ + A_UINT32 ack_fail_cnt; /*Total number packets failed transmit because of no ACK from the remote entity */ + A_UINT32 tx_rate_history[MAX_TX_RATE_VALUES]; /*History of last ten transmit rate, in units of 500 kbit/sec */ + A_UINT32 bcn_rssi_history[MAX_RSSI_VALUES]; /*History of last ten Beacon rssi of the connected Bss */ +} wmi_vdev_stats; + +/** + * peer statistics. + * + * @todo + * add more stats + * + */ +typedef struct { + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** rssi */ + A_UINT32 peer_rssi; + /** last tx data rate used for peer */ + A_UINT32 peer_tx_rate; + /** last rx data rate used for peer */ + A_UINT32 peer_rx_rate; +} wmi_peer_stats; + +typedef struct { + /** Primary channel freq of the channel for which stats are sent */ + A_UINT32 chan_mhz; + /** Time spent on the channel */ + A_UINT32 sampling_period_us; + /** Aggregate duration over a sampling period for which channel activity was observed */ + A_UINT32 rx_clear_count; + /** Accumalation of the TX PPDU duration over a sampling period */ + A_UINT32 tx_duration_us; + /** Accumalation of the RX PPDU duration over a sampling period */ + A_UINT32 rx_duration_us; +} wmi_chan_stats; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** VDEV type (AP,STA,IBSS,MONITOR) */ + A_UINT32 vdev_type; + /** VDEV subtype (P2PDEV, P2PCLI, P2PGO, BT3.0)*/ + A_UINT32 vdev_subtype; + /** VDEV MAC address */ + wmi_mac_addr vdev_macaddr; + /* Number of configured txrx streams */ + A_UINT32 num_cfg_txrx_streams; + /* + * This TLV is followed by another TLV of array of structures + * wmi_vdev_txrx_streams cfg_txrx_streams[]; + */ +} wmi_vdev_create_cmd_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_txrx_streams + */ + A_UINT32 tlv_header; + /* band - Should take values from wmi_channel_band_mask */ + A_UINT32 band; + /* max supported tx streams per given band for this vdev */ + A_UINT32 supported_tx_streams; + /* max supported rx streams per given band for this vdev */ + A_UINT32 supported_rx_streams; +} wmi_vdev_txrx_streams; + +/* wmi_p2p_noa_descriptor structure can't be modified without breaking the compatibility for WMI_HOST_SWBA_EVENTID */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor */ + A_UINT32 type_count; + /** 255: continuous schedule, 0: reserved */ + A_UINT32 duration; + /** Absent period duration in micro seconds */ + A_UINT32 interval; + /** Absent period interval in micro seconds */ + A_UINT32 start_time; + /** 32 bit tsf time when in starts */ +} wmi_p2p_noa_descriptor; + +/** values for vdev_type */ +#define WMI_VDEV_TYPE_AP 0x1 +#define WMI_VDEV_TYPE_STA 0x2 +#define WMI_VDEV_TYPE_IBSS 0x3 +#define WMI_VDEV_TYPE_MONITOR 0x4 + +/** VDEV type is for social wifi interface.This VDEV is Currently mainly needed + * by FW to execute the NAN specific WMI commands and also implement NAN specific + * operations like Network discovery, service provisioning and service + * subscription ..etc. If FW needs NAN VDEV then Host should issue VDEV create + * WMI command to create this VDEV once during initialization and host is not + * expected to use any VDEV specific WMI commands on this VDEV. + **/ +#define WMI_VDEV_TYPE_NAN 0x5 + +#define WMI_VDEV_TYPE_OCB 0x6 + +/** values for vdev_subtype */ +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE 0x1 +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT 0x2 +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO 0x3 + +/** values for vdev_start_request flags */ +/** Indicates that AP VDEV uses hidden ssid. only valid for + * AP/GO */ +#define WMI_UNIFIED_VDEV_START_HIDDEN_SSID (1<<0) +/** Indicates if robust management frame/management frame + * protection is enabled. For GO/AP vdevs, it indicates that + * it may support station/client associations with RMF enabled. + * For STA/client vdevs, it indicates that sta will + * associate with AP with RMF enabled. */ +#define WMI_UNIFIED_VDEV_START_PMF_ENABLED (1<<1) + +/* + * Host is sending bcn_tx_rate to override the beacon tx rates. + */ +#define WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT (1<<2) + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** requestor id identifying the caller module */ + A_UINT32 requestor_id; + /** beacon interval from received beacon */ + A_UINT32 beacon_interval; + /** DTIM Period from the received beacon */ + A_UINT32 dtim_period; + /** Flags */ + A_UINT32 flags; + /** ssid field. Only valid for AP/GO/IBSS/BTAmp VDEV type. */ + wmi_ssid ssid; + /** beacon/probe reponse xmit rate. Applicable for SoftAP. */ + /** This field will be invalid and ignored unless the */ + /** flags field has the WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT bit. */ + /** When valid, this field contains the fixed tx rate for the beacon */ + /** and probe response frames send by the GO or SoftAP */ + A_UINT32 bcn_tx_rate; + /** beacon/probe reponse xmit power. Applicable for SoftAP. */ + A_UINT32 bcn_txPower; + /** number of p2p NOA descriptor(s) from scan entry */ + A_UINT32 num_noa_descriptors; + /** Disable H/W ack. This used by WMI_VDEV_RESTART_REQUEST_CMDID. + During CAC, Our HW shouldn't ack ditected frames */ + A_UINT32 disable_hw_ack; + /** This field will be invalid unless the Dual Band Simultaneous (DBS) feature is enabled. */ + /** The DBS policy manager indicates the preferred number of transmit streams. */ + A_UINT32 preferred_tx_streams; + /** This field will be invalid unless the Dual Band Simultaneous (DBS) feature is enabled. */ + /** the DBS policy manager indicates the preferred number of receive streams. */ + A_UINT32 preferred_rx_streams; + /* The TLVs follows this structure: + * wmi_channel chan; //WMI channel + * wmi_p2p_noa_descriptor noa_descriptors[]; //actual p2p NOA descriptor from scan entry + */ +} wmi_vdev_start_request_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_delete_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_up_cmdid_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** aid (assoc id) received in association response for STA VDEV */ + A_UINT32 vdev_assoc_id; + /** bssid of the BSS the VDEV is joining */ + wmi_mac_addr vdev_bssid; +} wmi_vdev_up_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_stop_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_down_cmd_fixed_param; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_standby_response_cmd; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_resume_response_cmd; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** parameter id */ + A_UINT32 param_id; + /** parameter value */ + A_UINT32 param_value; +} wmi_vdev_set_param_cmd_fixed_param; + +typedef struct { + A_UINT32 key_seq_counter_l; + A_UINT32 key_seq_counter_h; +} wmi_key_seq_counter; + +#define WMI_CIPHER_NONE 0x0 /* clear key */ +#define WMI_CIPHER_WEP 0x1 +#define WMI_CIPHER_TKIP 0x2 +#define WMI_CIPHER_AES_OCB 0x3 +#define WMI_CIPHER_AES_CCM 0x4 +#define WMI_CIPHER_WAPI 0x5 +#define WMI_CIPHER_CKIP 0x6 +#define WMI_CIPHER_AES_CMAC 0x7 +#define WMI_CIPHER_ANY 0x8 + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** MAC address used for installing */ + wmi_mac_addr peer_macaddr; + /** key index */ + A_UINT32 key_ix; + /** key flags */ + A_UINT32 key_flags; + /** key cipher, defined above */ + A_UINT32 key_cipher; + /** key rsc counter */ + wmi_key_seq_counter key_rsc_counter; + /** global key rsc counter */ + wmi_key_seq_counter key_global_rsc_counter; + /** global key tsc counter */ + wmi_key_seq_counter key_tsc_counter; + /** WAPI key rsc counter */ + A_UINT8 wpi_key_rsc_counter[16]; + /** WAPI key tsc counter */ + A_UINT8 wpi_key_tsc_counter[16]; + /** key length */ + A_UINT32 key_len; + /** key tx mic length */ + A_UINT32 key_txmic_len; + /** key rx mic length */ + A_UINT32 key_rxmic_len; + /* + * Following this struct are this TLV. + * // actual key data + * A_UINT8 key_data[]; // contains key followed by tx mic followed by rx mic + */ +} wmi_vdev_install_key_cmd_fixed_param; + +/** Preamble types to be used with VDEV fixed rate configuration */ +typedef enum { + WMI_RATE_PREAMBLE_OFDM, + WMI_RATE_PREAMBLE_CCK, + WMI_RATE_PREAMBLE_HT, + WMI_RATE_PREAMBLE_VHT, +} WMI_RATE_PREAMBLE; + +/** Value to disable fixed rate setting */ +#define WMI_FIXED_RATE_NONE (0xff) + +/** the definition of different VDEV parameters */ +typedef enum { + /** RTS Threshold */ + WMI_VDEV_PARAM_RTS_THRESHOLD = 0x1, + /** Fragmentation threshold */ + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + /** beacon interval in TUs */ + WMI_VDEV_PARAM_BEACON_INTERVAL, + /** Listen interval in TUs */ + WMI_VDEV_PARAM_LISTEN_INTERVAL, + /** muticast rate in Mbps */ + WMI_VDEV_PARAM_MULTICAST_RATE, + /** management frame rate in Mbps */ + WMI_VDEV_PARAM_MGMT_TX_RATE, + /** slot time (long vs short) */ + WMI_VDEV_PARAM_SLOT_TIME, + /** preamble (long vs short) */ + WMI_VDEV_PARAM_PREAMBLE, + /** SWBA time (time before tbtt in msec) */ + WMI_VDEV_PARAM_SWBA_TIME, + /** time period for updating VDEV stats */ + WMI_VDEV_STATS_UPDATE_PERIOD, + /** age out time in msec for frames queued for station in power save*/ + WMI_VDEV_PWRSAVE_AGEOUT_TIME, + /** Host SWBA interval (time in msec before tbtt for SWBA event generation) */ + WMI_VDEV_HOST_SWBA_INTERVAL, + /** DTIM period (specified in units of num beacon intervals) */ + WMI_VDEV_PARAM_DTIM_PERIOD, + /** scheduler air time limit for this VDEV. used by off chan scheduler */ + WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + /** enable/dsiable WDS for this VDEV */ + WMI_VDEV_PARAM_WDS, + /** ATIM Window */ + WMI_VDEV_PARAM_ATIM_WINDOW, + /** BMISS max */ + WMI_VDEV_PARAM_BMISS_COUNT_MAX, + /** BMISS first time */ + WMI_VDEV_PARAM_BMISS_FIRST_BCNT, + /** BMISS final time */ + WMI_VDEV_PARAM_BMISS_FINAL_BCNT, + /** WMM enables/disabled */ + WMI_VDEV_PARAM_FEATURE_WMM, + /** Channel width */ + WMI_VDEV_PARAM_CHWIDTH, + /** Channel Offset */ + WMI_VDEV_PARAM_CHEXTOFFSET, + /** Disable HT Protection */ + WMI_VDEV_PARAM_DISABLE_HTPROTECTION, + /** Quick STA Kickout */ + WMI_VDEV_PARAM_STA_QUICKKICKOUT, + /** Rate to be used with Management frames */ + WMI_VDEV_PARAM_MGMT_RATE, + /** Protection Mode */ + WMI_VDEV_PARAM_PROTECTION_MODE, + /** Fixed rate setting */ + WMI_VDEV_PARAM_FIXED_RATE, + /** Short GI Enable/Disable */ + WMI_VDEV_PARAM_SGI, + /** Enable LDPC */ + WMI_VDEV_PARAM_LDPC, + /** Enable Tx STBC */ + WMI_VDEV_PARAM_TX_STBC, + /** Enable Rx STBC */ + WMI_VDEV_PARAM_RX_STBC, + /** Intra BSS forwarding */ + WMI_VDEV_PARAM_INTRA_BSS_FWD, + /** Setting Default xmit key for Vdev */ + WMI_VDEV_PARAM_DEF_KEYID, + /** NSS width */ + WMI_VDEV_PARAM_NSS, + /** Set the custom rate for the broadcast data frames */ + WMI_VDEV_PARAM_BCAST_DATA_RATE, + /** Set the custom rate (rate-code) for multicast data frames */ + WMI_VDEV_PARAM_MCAST_DATA_RATE, + /** Tx multicast packet indicate Enable/Disable */ + WMI_VDEV_PARAM_MCAST_INDICATE, + /** Tx DHCP packet indicate Enable/Disable */ + WMI_VDEV_PARAM_DHCP_INDICATE, + /** Enable host inspection of Tx unicast packet to unknown destination */ + WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + + /* The minimum amount of time AP begins to consider STA inactive */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + + /* An associated STA is considered inactive when there is no recent TX/RX + * activity and no downlink frames are buffered for it. Once a STA exceeds + * the maximum idle inactive time, the AP will send an 802.11 data-null as + * a keep alive to verify the STA is still associated. If the STA does ACK + * the data-null, or if the data-null is buffered and the STA does not + * retrieve it, the STA will be considered unresponsive (see + * WMI_VDEV_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS). */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + + /* An associated STA is considered unresponsive if there is no recent + * TX/RX activity and downlink frames are buffered for it. Once a STA + * exceeds the maximum unresponsive time, the AP will send a + * WMI_STA_KICKOUT event to the host so the STA can be deleted. */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + + /* Enable NAWDS : MCAST INSPECT Enable, NAWDS Flag set */ + WMI_VDEV_PARAM_AP_ENABLE_NAWDS, + /** Enable/Disable RTS-CTS */ + WMI_VDEV_PARAM_ENABLE_RTSCTS, + /* Enable TXBFee/er */ + WMI_VDEV_PARAM_TXBF, + + /**Set packet power save */ + WMI_VDEV_PARAM_PACKET_POWERSAVE, + + /**Drops un-encrypted packets if any received in an encryted connection + * otherwise forwards to host + */ + WMI_VDEV_PARAM_DROP_UNENCRY, + + /* + * Set TX encap type. + * + * enum wmi_pkt_type is to be used as the parameter + * specifying the encap type. + */ + WMI_VDEV_PARAM_TX_ENCAP_TYPE, + + /* + * Try to detect stations that woke-up and exited power save but did not + * successfully transmit data-null with PM=0 to AP. When this happens, + * STA and AP power save state are out-of-sync. Use buffered but + * undelivered MSDU to the STA as a hint that the STA is really awake + * and expecting normal ASAP delivery, rather than retrieving BU with + * PS-Poll, U-APSD trigger, etc. + * + * 0 disables out-of-sync detection. Maximum time is 255 seconds. + */ + WMI_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + + /* Enable/Disable early rx dynamic adjust feature. + * Early-rx dynamic adjust is a advance power save feature. + * Early-rx is a wakeup duration before exact TBTT,which is deemed necessary to provide a cushion for various + * timing discrepancies in the system. + * In current code branch, the duration is set to a very conservative fix value to make sure the drift impact is minimum. + * The fix early-tx will result in the unnessary power consume, so a dynamic early-rx adjust algorithm can be designed + * properly to minimum the power consume.*/ + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + + /* set target bmiss number per sample cycle if bmiss adjust was chosen. + * In this adjust policy,early-rx is adjusted by comparing the current bmiss rate to target bmiss rate + * which can be set by user through WMI command. + */ + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + + /* set sample cycle(in the unit of beacon interval) if bmiss adjust was chosen */ + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + + /* set slop_step */ + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP, + + /* set init slop */ + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP, + + /* pause adjust enable/disable */ + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + + /* Set channel pwr limit value of the vdev the minimal value of all + * vdevs operating on this channel will be set as channel tx power + * limit, which is used to configure ratearray + */ + WMI_VDEV_PARAM_TX_PWRLIMIT, + + /* set the count of snr value for calculation in snr monitor */ + WMI_VDEV_PARAM_SNR_NUM_FOR_CAL, + + /** Roaming offload */ + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, + + /** Enable Leader request RX functionality for RMC */ + WMI_VDEV_PARAM_ENABLE_RMC, + + /* IBSS does not have deauth/disassoc, vdev has to detect peer gone event + * by himself. If the beacon lost time exceed this threshold, the peer is + * thought to be gone. */ + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + + /** max rate in kpbs, transmit rate can't go beyond it */ + WMI_VDEV_PARAM_MAX_RATE, + + /* enable/disable drift sample. 0: disable; 1: clk_drift; 2: ap_drift; 3 both clk and ap drift */ + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + /* set Tx failure count threshold for the vdev */ + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + + /* set ebt resync timeout value, in the unit of TU */ + WMI_VDEV_PARAM_EBT_RESYNC_TIMEOUT, + + /* Enable Aggregation State Trigger Event */ + WMI_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE, + + /* This parameter indicates whether IBSS station can enter into power save + * mode by sending Null frame (with PM=1). When not allowed, IBSS station has to stay + * awake all the time and should never set PM=1 in its transmitted frames. + * This parameter is meaningful/valid only when WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH + * is non-zero. */ + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + + /* This parameter indicates if this station can enter into power collapse + * for the remaining beacon interval after the ATIM window. + * This parameter is meaningful/valid only when WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED + * is set to true. */ + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + + /* This parameter indicates whether IBSS station exit power save mode and + * enter power active state (by sending Null frame with PM=0 in the immediate ATIM Window) + * whenever there is a TX/RX activity. */ + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + + /* If Awake on TX/RX activity is enabled, this parameter indicates + * the data inactivity time in number of beacon intervals after which + * IBSS station reenters power save by sending Null frame with PM=1. */ + WMI_VDEV_PARAM_INACTIVITY_CNT, + + /* Inactivity time in msec after which TX Service Period (SP) is + * terminated by sending a Qos Null frame with EOSP. + * If value is 0, TX SP is terminated with the last buffered packet itself + * instead of waiting for the inactivity timeout. */ + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + + /** DTIM policy */ + WMI_VDEV_PARAM_DTIM_POLICY, + + /* When IBSS network is initialized, PS-supporting device + * does not enter protocol sleep state during first + * WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS seconds. */ + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + + /* Enable/Disable 1 RX chain usage during the ATIM window */ + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, + /** + * RX Leak window is the time driver waits before shutting down + * the radio or switching the channel and after receiving an ACK + * for a data frame with PM bit set) + */ + WMI_VDEV_PARAM_RX_LEAK_WINDOW, + + /** + * Averaging factor(16 bit value) is used in the calculations to + * perform averaging of different link level statistics like average + * beacon spread or average number of frames leaked + */ + WMI_VDEV_PARAM_STATS_AVG_FACTOR, + /* + * disconnect threshold, once the consecutive error for specific peer + * exceed this threhold, FW will send kickout event to host + */ + WMI_VDEV_PARAM_DISCONNECT_TH, + /* + * The rate_code of RTS_CTS changed by host. Now FW can support + * more non-HT rates rather than 1Mbps or 6Mbps */ + WMI_VDEV_PARAM_RTSCTS_RATE, + + /** This parameter indicates whether using a long duration RTS-CTS + * protection when a SAP goes off channel in MCC mode */ + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE, + + /* + * This parameter indicates whether using a broadcast probe response + * to increase the detectability of SAP in MCC mode + */ + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE, +} WMI_VDEV_PARAM; + +/* Length of ATIM Window in TU */ +#define WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH WMI_VDEV_PARAM_ATIM_WINDOW + +enum wmi_pkt_type { + WMI_PKT_TYPE_RAW = 0, + WMI_PKT_TYPE_NATIVE_WIFI = 1, + WMI_PKT_TYPE_ETHERNET = 2, +}; + +typedef struct { + A_UINT8 sutxbfee : 1, mutxbfee : 1, sutxbfer : 1, mutxbfer : 1, +#if defined(AR900B) + txb_sts_cap : 3, implicit_bf : 1; +#else + reserved : 4; +#endif +} wmi_vdev_txbf_en; + +/** Upto 8 bits are available for Roaming module to be sent along with + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD WMI_VDEV_PARAM **/ +/* Enable Roaming FW offload LFR1.5/LFR2.0 implementation */ +#define WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG 0x1 +/* Enable Roaming module in FW to do scan based on Final BMISS */ +#define WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG 0x2 + +/** slot time long */ +#define WMI_VDEV_SLOT_TIME_LONG 0x1 +/** slot time short */ +#define WMI_VDEV_SLOT_TIME_SHORT 0x2 +/** preablbe long */ +#define WMI_VDEV_PREAMBLE_LONG 0x1 +/** preablbe short */ +#define WMI_VDEV_PREAMBLE_SHORT 0x2 + +/** the definition of different START/RESTART Event response */ +typedef enum { + /* Event respose of START CMD */ + WMI_VDEV_START_RESP_EVENT = 0, + /* Event respose of RESTART CMD */ + WMI_VDEV_RESTART_RESP_EVENT, +} WMI_START_EVENT_PARAM; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** requestor id that requested the VDEV start request */ + A_UINT32 requestor_id; + /* Respose of Event type START/RESTART */ + WMI_START_EVENT_PARAM resp_type; + /** status of the response */ + A_UINT32 status; + /** Vdev chain mask */ + A_UINT32 chain_mask; + /** Vdev mimo power save mode */ + A_UINT32 smps_mode; + /** mac_id field contains the MAC identifier that the VDEV is bound to. The valid range is 0 to (num_macs-1). */ + A_UINT32 mac_id; + /** Configured Transmit Streams **/ + A_UINT32 cfgd_tx_streams; + /** Configured Receive Streams **/ + A_UINT32 cfgd_rx_streams; +} wmi_vdev_start_response_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_stopped_event_fixed_param; + +/** common structure used for simple events (stopped, resume_req, standby response) */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag would be equivalent to actual event */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_simple_event_fixed_param; + +/** VDEV start response status codes */ +#define WMI_VDEV_START_RESPONSE_STATUS_SUCCESS 0x0 /** VDEV succesfully started */ +#define WMI_VDEV_START_RESPONSE_INVALID_VDEVID 0x1 /** requested VDEV not found */ +#define WMI_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2 /** unsupported VDEV combination */ + +/** Beacon processing related command and event structures */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_tx_hdr */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** xmit rate */ + A_UINT32 tx_rate; + /** xmit power */ + A_UINT32 txPower; + /** beacon buffer length in bytes */ + A_UINT32 buf_len; + /* This TLV is followed by array of bytes: + * // beacon frame buffer + * A_UINT8 bufp[]; + */ +} wmi_bcn_tx_hdr; + +/* Beacon filter */ +#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ +#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ +#define WMI_BCN_FILTER_RSSI 2 /* Pass Beacons RSSI >= RSSI threshold */ +#define WMI_BCN_FILTER_BSSID 3 /* Pass Beacons with matching BSSID */ +#define WMI_BCN_FILTER_SSID 4 /* Pass Beacons with matching SSID */ + +typedef struct { + /** Filter ID */ + A_UINT32 bcn_filter_id; + /** Filter type - wmi_bcn_filter */ + A_UINT32 bcn_filter; + /** Buffer len */ + A_UINT32 bcn_filter_len; + /** Filter info (threshold, BSSID, RSSI) */ + A_UINT8 *bcn_filter_buf; +} wmi_bcn_filter_rx_cmd; + +/** Capabilities and IEs to be passed to firmware */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_prb_info */ + /** Capabilities */ + A_UINT32 caps; + /** ERP info */ + A_UINT32 erp; + /** Advanced capabilities */ + /** HT capabilities */ + /** HT Info */ + /** ibss_dfs */ + /** wpa Info */ + /** rsn Info */ + /** rrm info */ + /** ath_ext */ + /** app IE */ +} wmi_bcn_prb_info; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** TIM IE offset from the beginning of the template. */ + A_UINT32 tim_ie_offset; + /** beacon buffer length. data is in TLV data[] */ + A_UINT32 buf_len; + /* + * The TLVs follows: + * wmi_bcn_prb_info bcn_prb_info; //beacon probe capabilities and IEs + * A_UINT8 data[]; //Variable length data + */ +} wmi_bcn_tmpl_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** beacon buffer length. data is in TLV data[] */ + A_UINT32 buf_len; + /* + * The TLVs follows: + * wmi_bcn_prb_info bcn_prb_info; //beacon probe capabilities and IEs + * A_UINT8 data[]; //Variable length data + */ +} wmi_prb_tmpl_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** bcn tx status, values defined in enum WMI_FRAME_TX_STATUS */ + A_UINT32 tx_status; +} wmi_offload_bcn_tx_status_event_fixed_param; + +enum wmi_sta_ps_mode { + /** enable power save for the given STA VDEV */ + WMI_STA_PS_MODE_DISABLED = 0, + /** disable power save for a given STA VDEV */ + WMI_STA_PS_MODE_ENABLED = 1, +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + + /** Power save mode + * + * (see enum wmi_sta_ps_mode) + */ + A_UINT32 sta_ps_mode; +} wmi_sta_powersave_mode_cmd_fixed_param; + +enum wmi_csa_offload_en { + WMI_CSA_OFFLOAD_DISABLE = 0, + WMI_CSA_OFFLOAD_ENABLE = 1, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 csa_offload_enable; +} wmi_csa_offload_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param */ + A_UINT32 vdev_id; + /* + * The TLVs follows: + * wmi_channel chan; + */ +} wmi_csa_offload_chanswitch_cmd_fixed_param; +/** + * This parameter controls the policy for retrieving frames from AP while the + * STA is in sleep state. + * + * Only takes affect if the sta_ps_mode is enabled + */ +enum wmi_sta_ps_param_rx_wake_policy { + /* Wake up when ever there is an RX activity on the VDEV. In this mode + * the Power save SM(state machine) will come out of sleep by either + * sending null frame (or) a data frame (with PS==0) in response to TIM + * bit set in the received beacon frame from AP. + */ + WMI_STA_PS_RX_WAKE_POLICY_WAKE = 0, + + /* Here the power save state machine will not wakeup in response to TIM + * bit, instead it will send a PSPOLL (or) UASPD trigger based on UAPSD + * configuration setup by WMISET_PS_SET_UAPSD WMI command. When all + * access categories are delivery-enabled, the station will send a UAPSD + * trigger frame, otherwise it will send a PS-Poll. + */ + WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1, +}; + +/** Number of tx frames/beacon that cause the power save SM to wake up. + * + * Value 1 causes the SM to wake up for every TX. Value 0 has a special + * meaning, It will cause the SM to never wake up. This is useful if you want + * to keep the system to sleep all the time for some kind of test mode . host + * can change this parameter any time. It will affect at the next tx frame. + */ +enum wmi_sta_ps_param_tx_wake_threshold { + WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER = 0, + WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS = 1, + + /* Values greater than one indicate that many TX attempts per beacon + * interval before the STA will wake up + */ +}; + +/** + * The maximum number of PS-Poll frames the FW will send in response to + * traffic advertised in TIM before waking up (by sending a null frame with PS + * = 0). Value 0 has a special meaning: there is no maximum count and the FW + * will send as many PS-Poll as are necessary to retrieve buffered BU. This + * parameter is used when the RX wake policy is + * WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD and ignored when the RX wake + * policy is WMI_STA_PS_RX_WAKE_POLICY_WAKE. + */ +enum wmi_sta_ps_param_pspoll_count { + WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0, + /* Values greater than 0 indicate the maximum numer of PS-Poll frames FW + * will send before waking up. + */ +}; + +/* + * This will include the delivery and trigger enabled state for every AC. + * This is the negotiated state with AP. The host MLME needs to set this based + * on AP capability and the state Set in the association request by the + * station MLME.Lower 8 bits of the value specify the UAPSD configuration. + */ +#define WMI_UAPSD_AC_TYPE_DELI 0 +#define WMI_UAPSD_AC_TYPE_TRIG 1 + +#define WMI_UAPSD_AC_BIT_MASK(ac,type) (type == WMI_UAPSD_AC_TYPE_DELI) ? (1<<(ac<<1)) : (1<<((ac<<1)+1)) + +enum wmi_sta_ps_param_uapsd { + WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_STA_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_STA_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_STA_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; + +enum wmi_sta_powersave_param { + /** + * Controls how frames are retrievd from AP while STA is sleeping + * + * (see enum wmi_sta_ps_param_rx_wake_policy) + */ + WMI_STA_PS_PARAM_RX_WAKE_POLICY = 0, + + /** + * The STA will go active after this many TX + * + * (see enum wmi_sta_ps_param_tx_wake_threshold) + */ + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1, + + /** + * Number of PS-Poll to send before STA wakes up + * + * (see enum wmi_sta_ps_param_pspoll_count) + * + */ + WMI_STA_PS_PARAM_PSPOLL_COUNT = 2, + + /** + * TX/RX inactivity time in msec before going to sleep. + * + * The power save SM will monitor tx/rx activity on the VDEV, if no + * activity for the specified msec of the parameter the Power save SM will + * go to sleep. + */ + WMI_STA_PS_PARAM_INACTIVITY_TIME = 3, + + /** + * Set uapsd configuration. + * + * (see enum wmi_sta_ps_param_uapsd) + */ + WMI_STA_PS_PARAM_UAPSD = 4, + /** + * Number of PS-Poll to send before STA wakes up in QPower Mode + */ + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT = 5, + + /** + * Enable QPower + */ + WMI_STA_PS_ENABLE_QPOWER = 6, + + /** + * Number of TX frames before the entering the Active state + */ + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE = 7, + + /** + * QPower SPEC PSPOLL interval + */ + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL = 8, + + /** + * Max SPEC PSPOLL to be sent when the PSPOLL response has + * no-data bit set + */ + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL = 9, +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** station power save parameter (see enum wmi_sta_powersave_param) */ + A_UINT32 param; + A_UINT32 value; +} wmi_sta_powersave_param_cmd_fixed_param; + +/** No MIMO power save */ +#define WMI_STA_MIMO_PS_MODE_DISABLE +/** mimo powersave mode static*/ +#define WMI_STA_MIMO_PS_MODE_STATIC +/** mimo powersave mode dynamic */ +#define WMI_STA_MIMO_PS_MODE_DYNAMI + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** mimo powersave mode as defined above */ + A_UINT32 mimo_pwrsave_mode; +} wmi_sta_mimo_ps_mode_cmd; + +/** U-APSD configuration of peer station from (re)assoc request and TSPECs */ +enum wmi_ap_ps_param_uapsd { + WMI_AP_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_AP_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_AP_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_AP_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_AP_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_AP_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_AP_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; + +/** U-APSD maximum service period of peer station */ +enum wmi_ap_ps_peer_param_max_sp { + WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED = 0, + WMI_AP_PS_PEER_PARAM_MAX_SP_2 = 1, + WMI_AP_PS_PEER_PARAM_MAX_SP_4 = 2, + WMI_AP_PS_PEER_PARAM_MAX_SP_6 = 3, + + /* keep last! */ + MAX_WMI_AP_PS_PEER_PARAM_MAX_SP, +}; + +/** + * AP power save parameter + * Set a power save specific parameter for a peer station + */ +enum wmi_ap_ps_peer_param { + /** Set uapsd configuration for a given peer. + * + * This will include the delivery and trigger enabled state for every AC. + * The host MLME needs to set this based on AP capability and stations + * request Set in the association request received from the station. + * + * Lower 8 bits of the value specify the UAPSD configuration. + * + * (see enum wmi_ap_ps_param_uapsd) + * The default value is 0. + */ + WMI_AP_PS_PEER_PARAM_UAPSD = 0, + + /** + * Set the service period for a UAPSD capable station + * + * The service period from wme ie in the (re)assoc request frame. + * + * (see enum wmi_ap_ps_peer_param_max_sp) + */ + WMI_AP_PS_PEER_PARAM_MAX_SP = 1, + + /** Time in seconds for aging out buffered frames for STA in power save */ + WMI_AP_PS_PEER_PARAM_AGEOUT_TIME = 2, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** AP powersave param (see enum wmi_ap_ps_peer_param) */ + A_UINT32 param; + /** AP powersave param value */ + A_UINT32 value; +} wmi_ap_ps_peer_cmd_fixed_param; + +/** Configure peer station 11v U-APSD coexistance + * + * Two parameters from uaspd coexistence ie info (as specified in 11v) are + * sent down to FW along with this command. + * + * The semantics of these fields are described in the following text extracted + * from 802.11v. + * + * --- If the non-AP STA specified a non-zero TSF 0 Offset value in the + * U-APSD Coexistence element, the AP should not transmit frames to the + * non-AP STA outside of the U-APSD Coexistence Service Period, which + * begins when the AP receives the U-APSD trigger frame and ends after + * the transmission period specified by the result of the following + * calculation: + * + * End of transmission period = T + (Interval . ((T . TSF 0 Offset) mod Interval)) + * + * Where T is the time the U-APSD trigger frame was received at the AP + * Interval is the UAPSD Coexistence element Duration/Interval field + * value (see 7.3.2.91) or upon the successful transmission of a frame + * with EOSP bit set to 1, whichever is earlier. + * + * + * --- If the non-AP STA specified a zero TSF 0 Offset value in the U-APSD + * Coexistence element, the AP should not transmit frames to the non-AP + * STA outside of the U-APSD Coexistence Service Period, which begins + * when the AP receives a U-APSD trigger frame and ends after the + * transmission period specified by the result of the following + * calculation: End of transmission period = T + Duration + */ +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Enable U-APSD coexistence support for this peer + * + * 0 -> disabled (default) + * 1 -> enabled + */ + A_UINT32 enabled; + /** Duration/Interval as defined by 11v U-ASPD coexistance */ + A_UINT32 duration_interval; + /** Upper 32 bits of 64-bit TSF offset */ + A_UINT32 tsf_offset_high; + /** Lower 32 bits of 64-bit TSF offset */ + A_UINT32 tsf_offset_low; +} wmi_ap_powersave_peer_uapsd_coex_cmd; + +typedef enum { + WMI_AP_PS_EGAP_F_ENABLE_PHYERR_DETECTION = 0x0001, + WMI_AP_PS_EGAP_F_ENABLE_PWRSAVE_BY_PS_STATE = 0x0002, + WMI_AP_PS_EGAP_F_ENABLE_PWRSAVE_BY_INACTIVITY = 0x0004, + + WMI_AP_PS_EGAP_FLAG_MAX = 0x8000 +} wmi_ap_ps_egap_flag_type; + +/** + * configure ehanced green ap parameters + */ +typedef struct { + /* + * TLV tag and len; tag equals + * wmi_ap_powersave_egap_param_cmd_fixed_param + */ + A_UINT32 tlv_header; + /** Enable enhanced green ap + * 0 -> disabled + * 1 -> enabled + */ + A_UINT32 enable; + /** The param indicates a duration that all STAs connected + * to S-AP have no traffic. + */ + A_UINT32 inactivity_time; /* in unit of milliseconds */ + /** The param indicates a duration that all STAs connected + * to S-AP have no traffic, after all STAs have entered powersave. + */ + A_UINT32 wait_time; /* in unit of milliseconds */ + /** The param is used to turn on/off some functions within E-GAP. + */ + A_UINT32 flags; /* wmi_ap_ps_egap_flag_type bitmap */ +} wmi_ap_ps_egap_param_cmd_fixed_param; + +typedef enum { + WMI_AP_PS_EGAP_STATUS_IDLE = 1, + WMI_AP_PS_EGAP_STATUS_PWRSAVE_OFF = 2, + WMI_AP_PS_EGAP_STATUS_PWRSAVE_ON = 3, + + WMI_AP_PS_EGAP_STATUS_MAX = 15 +} wmi_ap_ps_egap_status_type; + +/** + * send ehanced green ap status to host + */ +typedef struct { + A_UINT32 tlv_header; + /** The param indicates a mac under dual-mac */ + A_UINT32 mac_id; + /** The param indicates the current tx chainmask with the mac id. */ + A_UINT32 tx_chainmask; + /** The param indicates the current rx chainmask with the mac id. */ + A_UINT32 rx_chainmask; +} wmi_ap_ps_egap_info_chainmask_list; + +typedef struct { + /* + * TLV tag and len; tag equals + * wmi_ap_powersave_egap_param_cmd_fixed_param + */ + A_UINT32 tlv_header; + /** Enhanced green ap status (WMI_AP_PS_EGAP_STATUS). */ + A_UINT32 status; + /* This TLV is followed by + * wmi_ap_ps_egap_info_chainmask_list chainmask_list[]; + */ +} wmi_ap_ps_egap_info_event_fixed_param; + + +/* 128 clients = 4 words */ +/* WMI_TIM_BITMAP_ARRAY_SIZE can't be modified without breaking the compatibility */ +#define WMI_TIM_BITMAP_ARRAY_SIZE 4 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tim_info */ + /** TIM bitmap len (in bytes)*/ + A_UINT32 tim_len; + /** TIM Partial Virtual Bitmap */ + A_UINT32 tim_mcast; + A_UINT32 tim_bitmap[WMI_TIM_BITMAP_ARRAY_SIZE]; + A_UINT32 tim_changed; + A_UINT32 tim_num_ps_pending; +} wmi_tim_info; + +typedef struct { + /** Flag to enable quiet period IE support */ + A_UINT32 is_enabled; + /** Quiet start */ + A_UINT32 tbttcount; + /** Beacon intervals between quiets*/ + A_UINT32 period; + /** TUs of each quiet*/ + A_UINT32 duration; + /** TUs of from TBTT of quiet start*/ + A_UINT32 offset; +} wmi_quiet_info; + +/* WMI_P2P_MAX_NOA_DESCRIPTORS can't be modified without breaking the compatibility */ +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 /* Maximum number of NOA Descriptors supported */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_info */ + /** Bit 0: Flag to indicate an update in NOA schedule + * Bits 7-1: Reserved + * Bits 15-8: Index (identifies the instance of NOA sub element) + * Bit 16: Opp PS state of the AP + * Bits 23-17: Ctwindow in TUs + * Bits 31-24: Number of NOA descriptors + */ + A_UINT32 noa_attributes; + wmi_p2p_noa_descriptor + noa_descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} wmi_p2p_noa_info; + +#define WMI_UNIFIED_NOA_ATTR_MODIFIED 0x1 +#define WMI_UNIFIED_NOA_ATTR_MODIFIED_S 0 + +#define WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_MODIFIED) + +#define WMI_UNIFIED_NOA_ATTR_MODIFIED_SET(hdr) \ + WMI_F_RMW((hdr)->noa_attributes, 0x1, \ + WMI_UNIFIED_NOA_ATTR_MODIFIED); + +#define WMI_UNIFIED_NOA_ATTR_INDEX 0xff00 +#define WMI_UNIFIED_NOA_ATTR_INDEX_S 8 + +#define WMI_UNIFIED_NOA_ATTR_INDEX_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_INDEX) + +#define WMI_UNIFIED_NOA_ATTR_INDEX_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0xff, \ + WMI_UNIFIED_NOA_ATTR_INDEX); + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS 0x10000 +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_S 16 + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_OPP_PS) + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_SET(hdr) \ + WMI_F_RMW((hdr)->noa_attributes, 0x1, \ + WMI_UNIFIED_NOA_ATTR_OPP_PS); + +#define WMI_UNIFIED_NOA_ATTR_CTWIN 0xfe0000 +#define WMI_UNIFIED_NOA_ATTR_CTWIN_S 17 + +#define WMI_UNIFIED_NOA_ATTR_CTWIN_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_CTWIN) + +#define WMI_UNIFIED_NOA_ATTR_CTWIN_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0x7f, \ + WMI_UNIFIED_NOA_ATTR_CTWIN); + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC 0xff000000 +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_S 24 + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_NUM_DESC) + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0xff, \ + WMI_UNIFIED_NOA_ATTR_NUM_DESC); + +typedef struct { + /** TIM info */ + wmi_tim_info tim_info; + /** P2P NOA info */ + wmi_p2p_noa_info p2p_noa_info; + /* TBD: More info elements to be added later */ +} wmi_bcn_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param */ + /** bitmap identifying the VDEVs, generated by the caller */ + A_UINT32 vdev_map; + /* This TLV is followed by tim_info and p2p_noa_info for each vdev in vdevmap : + * wmi_tim_info tim_info[]; + * wmi_p2p_noa_info p2p_noa_info[]; + * + */ +} wmi_host_swba_event_fixed_param; + +#define WMI_MAX_AP_VDEV 16 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param */ + /** bimtap of VDEVs that has tbtt offset updated */ + A_UINT32 vdev_map; + /* The TLVs for tbttoffset_list will follow this TLV. + * tbtt offset list in the order of the LSB to MSB in the vdev_map bitmap + * A_UINT32 tbttoffset_list[WMI_MAX_AP_VDEV]; + */ +} wmi_tbtt_offset_event_fixed_param; + +/* Peer Specific commands and events */ + +typedef struct { + A_UINT32 percentage; /* in unit of 12.5% */ + A_UINT32 min_delta; /* in unit of Mbps */ +} rate_delta_t; + +#define PEER_RATE_REPORT_COND_FLAG_DELTA 0x01 +#define PEER_RATE_REPORT_COND_FLAG_THRESHOLD 0x02 +#define MAX_NUM_OF_RATE_THRESH 4 + +typedef struct { + /* + * PEER_RATE_REPORT_COND_FLAG_DELTA, + * PEER_RATE_REPORT_COND_FLAG_THRESHOLD + * Any of these two conditions or both of + * them can be set. + */ + A_UINT32 val_cond_flags; + rate_delta_t rate_delta; + /* + * In unit of Mbps. There are at most 4 thresholds + * If the threshold count is less than 4, set zero to + * the one following the last threshold + */ + A_UINT32 rate_threshold[MAX_NUM_OF_RATE_THRESH]; +} report_cond_per_phy_t; + + +enum peer_rate_report_cond_phy_type { + PEER_RATE_REPORT_COND_11B = 0, + PEER_RATE_REPORT_COND_11A_G, + PEER_RATE_REPORT_COND_11N, + PEER_RATE_REPORT_COND_11AC, + PEER_RATE_REPORT_COND_MAX_NUM +}; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_rate_report_condtion_fixed_param + */ + A_UINT32 tlv_header; + /* 1= enable, 0=disable */ + A_UINT32 enable_rate_report; + A_UINT32 report_backoff_time; /* in unit of msecond */ + A_UINT32 report_timer_period; /* in unit of msecond */ + /* + *In the following field, the array index means the phy type, + * please see enum peer_rate_report_cond_phy_type for detail + */ + report_cond_per_phy_t cond_per_phy[PEER_RATE_REPORT_COND_MAX_NUM]; +} wmi_peer_set_rate_report_condition_fixed_param; + +/* Peer Type: + * NB: This can be left DEFAULT for the normal case, and f/w will determine BSS type based + * on address and vdev opmode. This is largely here to allow host to indicate that + * peer is explicitly a TDLS peer + */ +enum wmi_peer_type { + WMI_PEER_TYPE_DEFAULT = 0, /* Generic/Non-BSS/Self Peer */ + WMI_PEER_TYPE_BSS = 1, /* Peer is BSS Peer entry */ + WMI_PEER_TYPE_TDLS = 2, /* Peer is a TDLS Peer */ + WMI_PEER_TYPE_OCB = 3, /* Peer is a OCB Peer */ + WMI_PEER_TYPE_HOST_MAX = 127, /* Host <-> Target Peer type + * is assigned up to 127 */ + /* Reserved from 128 - 255 for + * target internal use.*/ + WMI_PEER_TYPE_ROAMOFFLOAD_TEMP = 128, /* Temporarily created during offload roam */ +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** peer type: see enum values above */ + A_UINT32 peer_type; +} wmi_peer_create_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_delete_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** tid bitmap identifying the tids to flush */ + A_UINT32 peer_tid_bitmap; +} wmi_peer_flush_tids_cmd_fixed_param; + +typedef struct { + /** rate mode . 0: disable fixed rate (auto rate) + * 1: legacy (non 11n) rate specified as ieee rate 2*Mbps + * 2: ht20 11n rate specified as mcs index + * 3: ht40 11n rate specified as mcs index + */ + A_UINT32 rate_mode; + /** 4 rate values for 4 rate series. series 0 is stored in byte 0 (LSB) + * and series 3 is stored at byte 3 (MSB) */ + A_UINT32 rate_series; + /** 4 retry counts for 4 rate series. retry count for rate 0 is stored in byte 0 (LSB) + * and retry count for rate 3 is stored at byte 3 (MSB) */ + A_UINT32 rate_retries; +} wmi_fixed_rate; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** fixed rate */ + wmi_fixed_rate peer_fixed_rate; +} wmi_peer_fixed_rate_cmd; + +#define WMI_MGMT_TID 17 + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_addba_clear_resp_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Buffer/Window size*/ + A_UINT32 buffersize; +} wmi_addba_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Is Initiator */ + A_UINT32 initiator; + /** Reason code */ + A_UINT32 reasoncode; +} wmi_delba_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** status code */ + A_UINT32 statuscode; +} wmi_addba_setresponse_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; +} wmi_send_singleamsdu_cmd_fixed_param; + +/* Type of Station DTIM Power Save method */ +enum { + /* For NORMAL DTIM, the parameter is the number of beacon intervals and + * also the same value as the listen interval. For this method, the + * station will wake up based on the listen interval. If this + * listen interval is not equal to DTIM, then the station may + * miss certain DTIM beacons. If this value is 1, then the + * station will wake up for every beacon. + */ + WMI_STA_DTIM_PS_NORMAL_DTIM = 0x01, + /* For MODULATED_DTIM, parameter is a multiple of DTIM beacons to skip. + * When this value is 1, then the station will wake at every DTIM beacon. + * If this value is >1, then the station will skip certain DTIM beacons. + * This value is the multiple of DTIM intervals that the station will + * wake up to receive the DTIM beacons. + */ + WMI_STA_DTIM_PS_MODULATED_DTIM = 0x02, +}; + +/* Parameter structure for the WMI_STA_DTIM_PS_METHOD_CMDID */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* Station DTIM Power Save method as defined above */ + A_UINT32 dtim_pwrsave_method; + /* DTIM PS value. Contents depends on the method */ + A_UINT32 value; + /* Modulated DTIM value */ + A_UINT32 MaxLIModulatedDTIM; +} wmi_sta_dtim_ps_method_cmd_fixed_param; + +/* + * For Station UAPSD Auto Trigger feature, the Firmware monitors the + * uAPSD uplink and downlink traffic for each uAPSD enabled WMM ACs. + * If there is no uplink/download for the specified service interval (field service_interval), + * firmware will auto generate a QOS-NULL trigger for that WMM-AP with the TID value + * specified in the UP (field user_priority). + * Firmware also monitors the responses for these QOS-NULL triggers. + * If the peer does not have any delivery frames, it will respond with + * QOS-NULL (EOSP=1). This feature of only using service interval is assumed to be mandatory for all + * firmware implementation. For this basic implementation, the suspend_interval and delay_interval + * are unused and should be set to 0. + * When service_interval is 0, then the firmware will not send any trigger frames. This is for + * certain host-based implementations that don't want this firmware offload. + * Note that the per-AC intervals are required for some usage scenarios. This is why the intervals + * are given in the array of ac_param[]. For example, Voice service interval may defaults to 20 ms + * and rest of the AC default to 300 ms. + * + * The service bit, WMI_STA_UAPSD_VAR_AUTO_TRIG, will indicate that the more advanced feature + * of variable auto trigger is supported. The suspend_interval and delay_interval is used in + * the more advanced monitoring method. + * If the PEER does not have any delivery enabled data frames (non QOS-NULL) for the + * suspend interval (field suspend_interval), firmware will change its auto trigger interval + * to delay interval (field delay_interval). This way, when there is no traffic, the station + * will save more power by waking up less and sending less trigger frames. + * The (service_interval < suspend_interval) and (service_interval < delay_interval). + * If this variable auto trigger is not required, then the suspend_interval and delay_interval + * should be 0. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param */ + /** WMM Access category from 0 to 3 */ + A_UINT32 wmm_ac; + /** User priority to use in trigger frames. It is the TID + * value. This field needs to be specified and may not be + * equivalent to AC since some implementation may use the TSPEC + * to enable UAPSD and negotiate a particular user priority. */ + A_UINT32 user_priority; + /** service interval in ms */ + A_UINT32 service_interval; + /** Suspend interval in ms */ + A_UINT32 suspend_interval; + /** delay interval in ms */ + A_UINT32 delay_interval; +} wmi_sta_uapsd_auto_trig_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Number of AC to specify */ + A_UINT32 num_ac; + /* + * Following this struc is the TLV: + * wmi_sta_uapsd_auto_trig_param ac_param[]; //Variable number of AC parameters (defined by field num_ac) + */ + +} wmi_sta_uapsd_auto_trig_cmd_fixed_param; + +/** mimo powersave state */ +#define WMI_PEER_MIMO_PS_STATE 0x1 +/** enable/disable AMPDU . initial value (enabled) */ +#define WMI_PEER_AMPDU 0x2 +/** authorize/unauthorize peer. initial value is unauthorized (0) */ +#define WMI_PEER_AUTHORIZE 0x3 +/** peer channel bandwidth */ +#define WMI_PEER_CHWIDTH 0x4 +/** peer NSS */ +#define WMI_PEER_NSS 0x5 +/** USE 4 ADDR */ +#define WMI_PEER_USE_4ADDR 0x6 +/* set group membership status */ +#define WMI_PEER_MEMBERSHIP 0x7 +#define WMI_PEER_USERPOS 0x8 +/* + * A critical high-level protocol is being used with this peer. Target + * should take appropriate measures (if possible) to ensure more + * reliable link with minimal latency. This *may* include modifying the + * station power save policy, enabling more RX chains, increased + * priority of channel scheduling, etc. + * + * NOTE: This parameter should only be considered a hint as specific + * behavior will depend on many factors including current network load + * and vdev/peer configuration. + * + * For STA VDEV this peer corresponds to the AP's BSS peer. + * For AP VDEV this peer corresponds to the remote peer STA. + */ +#define WMI_PEER_CRIT_PROTO_HINT_ENABLED 0x9 +/* set Tx failure count threshold for the peer - Currently unused */ +#define WMI_PEER_TX_FAIL_CNT_THR 0xA +/* Enable H/W retry and Enable H/W Send CTS2S before Data */ +#define WMI_PEER_SET_HW_RETRY_CTS2S 0xB + +/* Set peer advertised IBSS atim window length */ +#define WMI_PEER_IBSS_ATIM_WINDOW_LENGTH 0xC + +/** peer phy mode */ +#define WMI_PEER_PHYMODE 0xD + +/** mimo ps values for the parameter WMI_PEER_MIMO_PS_STATE */ +#define WMI_PEER_MIMO_PS_NONE 0x0 +#define WMI_PEER_MIMO_PS_STATIC 0x1 +#define WMI_PEER_MIMO_PS_DYNAMIC 0x2 + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** parameter id */ + A_UINT32 param_id; + /** parametr value */ + A_UINT32 param_value; +} wmi_peer_set_param_cmd_fixed_param; + +#define MAX_SUPPORTED_RATES 128 + +typedef struct { + /** total number of rates */ + A_UINT32 num_rates; + /** + * rates (each 8bit value) packed into a 32 bit word. + * the rates are filled from least significant byte to most + * significant byte. + */ + A_UINT32 rates[(MAX_SUPPORTED_RATES / 4) + 1]; +} wmi_rate_set; + +/* NOTE: It would bea good idea to represent the Tx MCS + * info in one word and Rx in another word. This is split + * into multiple words for convenience + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vht_rate_set */ + A_UINT32 rx_max_rate; /* Max Rx data rate */ + A_UINT32 rx_mcs_set; /* Negotiated RX VHT rates */ + A_UINT32 tx_max_rate; /* Max Tx data rate */ + A_UINT32 tx_mcs_set; /* Negotiated TX VHT rates */ +} wmi_vht_rate_set; + +/* + * IMPORTANT: Make sure the bit definitions here are consistent + * with the ni_flags definitions in wlan_peer.h + */ +#define WMI_PEER_AUTH 0x00000001 /* Authorized for data */ +#define WMI_PEER_QOS 0x00000002 /* QoS enabled */ +#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 /* Needs PTK 4 way handshake for authorization */ +#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 /* Needs GTK 2 way handshake after 4-way handshake */ +#define WMI_PEER_APSD 0x00000800 /* U-APSD power save enabled */ +#define WMI_PEER_HT 0x00001000 /* HT enabled */ +#define WMI_PEER_40MHZ 0x00002000 /* 40MHz enabld */ +#define WMI_PEER_STBC 0x00008000 /* STBC Enabled */ +#define WMI_PEER_LDPC 0x00010000 /* LDPC ENabled */ +#define WMI_PEER_DYN_MIMOPS 0x00020000 /* Dynamic MIMO PS Enabled */ +#define WMI_PEER_STATIC_MIMOPS 0x00040000 /* Static MIMO PS enabled */ +#define WMI_PEER_SPATIAL_MUX 0x00200000 /* SM Enabled */ +#define WMI_PEER_VHT 0x02000000 /* VHT Enabled */ +#define WMI_PEER_80MHZ 0x04000000 /* 80MHz enabld */ +#define WMI_PEER_PMF 0x08000000 /* Robust Management Frame Protection enabled */ +/** CAUTION TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. Need to be clean up */ +#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 /* P2P capable peer */ +#define WMI_PEER_160MHZ 0x40000000 /* 160 MHz enabled */ +#define WMI_PEER_SAFEMODE_EN 0x80000000 /* Fips Mode Enabled */ + +/** + * Peer rate capabilities. + * + * This is of interest to the ratecontrol + * module which resides in the firmware. The bit definitions are + * consistent with that defined in if_athrate.c. + * + * @todo + * Move this to a common header file later so there is no need to + * duplicate the definitions or maintain consistency. + */ +#define WMI_RC_DS_FLAG 0x01 /* Dual stream flag */ +#define WMI_RC_CW40_FLAG 0x02 /* CW 40 */ +#define WMI_RC_SGI_FLAG 0x04 /* Short Guard Interval */ +#define WMI_RC_HT_FLAG 0x08 /* HT */ +#define WMI_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ +#define WMI_RC_TX_STBC_FLAG 0x20 /* TX STBC */ +#define WMI_RC_TX_STBC_FLAG_S 5 /* TX STBC */ +#define WMI_RC_RX_STBC_FLAG 0xC0 /* RX STBC ,2 bits */ +#define WMI_RC_RX_STBC_FLAG_S 6 /* RX STBC ,2 bits */ +#define WMI_RC_WEP_TKIP_FLAG 0x100 /* WEP/TKIP encryption */ +#define WMI_RC_TS_FLAG 0x200 /* Three stream flag */ +#define WMI_RC_UAPSD_FLAG 0x400 /* UAPSD Rate Control */ + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** VDEV id */ + A_UINT32 vdev_id; + /** assoc = 1 reassoc = 0 */ + A_UINT32 peer_new_assoc; + /** peer associd (16 bits) */ + A_UINT32 peer_associd; + /** peer station flags: see definition above */ + A_UINT32 peer_flags; + /** negotiated capabilities (lower 16 bits)*/ + A_UINT32 peer_caps; + /** Listen interval */ + A_UINT32 peer_listen_intval; + /** HT capabilties of the peer */ + A_UINT32 peer_ht_caps; + /** maximum rx A-MPDU length */ + A_UINT32 peer_max_mpdu; + /** mpdu density of the peer in usec(0 to 16) */ + A_UINT32 peer_mpdu_density; + /** peer rate capabilties see flags above */ + A_UINT32 peer_rate_caps; + /** num spatial streams */ + A_UINT32 peer_nss; + /** VHT capabilties of the peer */ + A_UINT32 peer_vht_caps; + /** phy mode */ + A_UINT32 peer_phymode; + /** HT Operation Element of the peer. Five bytes packed in 2 + * INT32 array and filled from lsb to msb. + * Note that the size of array peer_ht_info[] cannotbe changed + * without breaking WMI Compatibility. */ + A_UINT32 peer_ht_info[2]; + /** total number of negotiated legacy rate set. Also the sizeof + * peer_legacy_rates[] */ + A_UINT32 num_peer_legacy_rates; + /** total number of negotiated ht rate set. Also the sizeof + * peer_ht_rates[] */ + A_UINT32 num_peer_ht_rates; + /* Following this struc are the TLV's: + * A_UINT8 peer_legacy_rates[]; + * A_UINT8 peer_ht_rates[]; + * wmi_vht_rate_set peer_vht_rates; //VHT capabilties of the peer + */ +} wmi_peer_assoc_complete_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** wds MAC addr */ + wmi_mac_addr wds_macaddr; +} wmi_peer_add_wds_entry_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param */ + /** wds MAC addr */ + wmi_mac_addr wds_macaddr; +} wmi_peer_remove_wds_entry_cmd_fixed_param; + +typedef struct { + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_q_empty_callback_event; + +/** + * Channel info WMI event + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param */ + /** Error code */ + A_UINT32 err_code; + /** Channel freq */ + A_UINT32 freq; + /** Read flags */ + A_UINT32 cmd_flags; + /** Noise Floor value */ + A_UINT32 noise_floor; + /** rx clear count */ + A_UINT32 rx_clear_count; + /** cycle count */ + A_UINT32 cycle_count; +} wmi_chan_info_event_fixed_param; + +/** + * Non wlan interference event + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_ath_dcs_cw_int */ + A_UINT32 channel; /* either number or freq in mhz */ +} ath_dcs_cw_int; + +/** + * wlan_dcs_im_tgt_stats + * + */ +typedef struct _wlan_dcs_im_tgt_stats { + /** current running TSF from the TSF-1 */ + A_UINT32 reg_tsf32; + + /** Known last frame rssi, in case of multiple stations, if + * and at different ranges, this would not gaurantee that + * this is the least rssi. + */ + A_UINT32 last_ack_rssi; + + /** Sum of all the failed durations in the last one second interval. + */ + A_UINT32 tx_waste_time; + /** count how many times the hal_rxerr_phy is marked, in this + * time period + */ + A_UINT32 rx_time; + A_UINT32 phyerr_cnt; + + /** + * WLAN IM stats from target to host + * + * Below statistics are sent from target to host periodically. + * These are collected at target as long as target is running + * and target chip is not in sleep. + * + */ + + /** listen time from ANI */ + A_INT32 listen_time; + + /** tx frame count, MAC_PCU_TX_FRAME_CNT_ADDRESS */ + A_UINT32 reg_tx_frame_cnt; + + /** rx frame count, MAC_PCU_RX_FRAME_CNT_ADDRESS */ + A_UINT32 reg_rx_frame_cnt; + + /** rx clear count, MAC_PCU_RX_CLEAR_CNT_ADDRESS */ + A_UINT32 reg_rxclr_cnt; + + /** total cycle counts MAC_PCU_CYCLE_CNT_ADDRESS */ + A_UINT32 reg_cycle_cnt; /* delta cycle count */ + + /** extenstion channel rx clear count */ + A_UINT32 reg_rxclr_ext_cnt; + + /** OFDM phy error counts, MAC_PCU_PHY_ERR_CNT_1_ADDRESS */ + A_UINT32 reg_ofdm_phyerr_cnt; + + /** CCK phy error count, MAC_PCU_PHY_ERR_CNT_2_ADDRESS */ + A_UINT32 reg_cck_phyerr_cnt; /* CCK err count since last reset, read from register */ + +} wlan_dcs_im_tgt_stats_t; + +/** + * wmi_dcs_interference_event_t + * + * Right now this is event and stats together. Partly this is + * because cw interference is handled in target now. This + * can be done at host itself, if we can carry the NF alone + * as a stats event. In future this would be done and this + * event would carry only stats. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param */ + /** + * Type of the event present, either the cw interference event, or the wlan_im stats + */ + A_UINT32 interference_type; /* type of interference, wlan or cw */ + /* + * Following this struct are these TLVs. Note that they are both array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field interference_type. This is to emulate an union with cw_int and wlan_stat + * elements (not arrays). union { ath_dcs_cw_int cw_int; wlan_dcs_im_tgt_stats_t wlan_stat; } int_event; + * + * //cw_interference event + * ath_dcs_cw_int cw_int[]; this element + * // wlan im interfernce stats + * wlan_dcs_im_tgt_stats_t wlan_stat[]; + */ +} wmi_dcs_interference_event_fixed_param; + +enum wmi_peer_mcast_group_action { + wmi_peer_mcast_group_action_add = 0, + wmi_peer_mcast_group_action_del = 1 +}; +#define WMI_PEER_MCAST_GROUP_FLAG_ACTION_M 0x1 +#define WMI_PEER_MCAST_GROUP_FLAG_ACTION_S 0 +#define WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_M 0x2 +#define WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_S 1 +/* multicast group membership commands */ +/* TODO: Converting this will be tricky since it uses an union. + Also, the mac_addr is not aligned. We will convert to the wmi_mac_addr */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param */ + A_UINT32 flags; + wmi_mac_addr ucast_mac_addr; + A_UINT8 mcast_ip_addr[16]; /* in network byte order */ +} wmi_peer_mcast_group_cmd_fixed_param; + +/** Offload Scan and Roaming related commands */ +/** The FW performs 2 different kinds of offload scans independent + * of host. One is Roam scan which is primarily performed on a + * station VDEV after association to look for a better AP that + * the station VDEV can roam to. The second scan is connect scan + * which is mainly performed when the station is not associated + * and to look for a matching AP profile from a list of + * configured profiles. */ + +/** + * WMI_ROAM_SCAN_MODE: Set Roam Scan mode + * the roam scan mode is one of the periodic, rssi change, both, none. + * None : Disable Roam scan. No Roam scan at all. + * Periodic : Scan periodically with a configurable period. + * Rssi change : Scan when ever rssi to current AP changes by the threshold value + * set by WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD command. + * Both : Both of the above (scan when either period expires or rss to current AP changes by X amount) + * + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param */ + A_UINT32 roam_scan_mode; + A_UINT32 vdev_id; +} wmi_roam_scan_mode_fixed_param; + +#define WMI_ROAM_SCAN_MODE_NONE 0x0 +#define WMI_ROAM_SCAN_MODE_PERIODIC 0x1 +#define WMI_ROAM_SCAN_MODE_RSSI_CHANGE 0x2 +#define WMI_ROAM_SCAN_MODE_BOTH 0x3 +/* Note: WMI_ROAM_SCAN_MODE_ROAMOFFLOAD is one bit not conflict with LFR2.0 SCAN_MODE. */ +#define WMI_ROAM_SCAN_MODE_ROAMOFFLOAD 0x4 + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 command_arg; +} wmi_roam_scan_cmd_fixed_param; + +#define WMI_ROAM_SCAN_STOP_CMD 0x1 + +/** + * WMI_ROAM_SCAN_RSSI_THRESHOLD : set scan rssi thresold + * scan rssi threshold is the rssi threshold below which the FW will start running Roam scans. + * Applicable when WMI_ROAM_SCAN_MODE is not set to none. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan rssi threshold */ + A_UINT32 roam_scan_rssi_thresh; + /** When using Hw generated beacon RSSI interrupts */ + A_UINT32 roam_rssi_thresh_diff; + /** 5G scan max count */ + A_UINT32 hirssi_scan_max_count; + /** 5G scan rssi change threshold value */ + A_UINT32 hirssi_scan_delta; + /** 5G scan upper bound */ + A_UINT32 hirssi_upper_bound; + /* The TLVs will follow. + * wmi_roam_scan_extended_threshold_param extended_param; + * wmi_roam_earlystop_rssi_thres_param earlystop_param; + */ +} wmi_roam_scan_rssi_threshold_fixed_param; + +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_FIXED 0x0 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR 0x1 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LOG 0x2 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_EXP 0x3 + +typedef struct { + /** TLV tag and len; tag equals + *WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param */ + A_UINT32 tlv_header; + A_UINT32 boost_threshold_5g; /** RSSI threshold above which 5GHz RSSI is favored */ + A_UINT32 penalty_threshold_5g; /** RSSI threshold below which 5GHz RSSI is penalized */ + A_UINT32 boost_algorithm_5g; /** 0 == fixed, 1 == linear, 2 == logarithm ..etc */ + A_UINT32 boost_factor_5g; /** factor by which 5GHz RSSI is boosted */ + A_UINT32 penalty_algorithm_5g; /** 0 == fixed, 1 == linear, 2 == logarithm ..etc */ + A_UINT32 penalty_factor_5g; /** factor by which 5GHz RSSI is penalized */ + A_UINT32 max_boost_5g; /** maximum boost that can be applied to a 5GHz RSSI */ + A_UINT32 max_penalty_5g; /** maximum penality that can be applied to a 5GHz RSSI */ + /** + * RSSI below which roam is kicked in by background scan + * although rssi is still good + */ + A_UINT32 good_rssi_threshold; +} wmi_roam_scan_extended_threshold_param; + + +/** + * WMI_ROAM_SCAN_PERIOD: period for roam scan. + * Applicable when the scan mode is Periodic or both. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan period value */ + A_UINT32 roam_scan_period; + /** Aging for Roam scans */ + A_UINT32 roam_scan_age; +} wmi_roam_scan_period_fixed_param; + +/** + * WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD : rssi delta to trigger the roam scan. + * Rssi change threshold used when mode is Rssi change (or) Both. + * The FW will run the roam scan when ever the rssi changes (up or down) by the value set by this parameter. + * Note scan is triggered based on the rssi threshold condition set by WMI_ROAM_SCAN_RSSI_THRESHOLD + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan rssi change threshold value */ + A_UINT32 roam_scan_rssi_change_thresh; + /** When using Hw generated beacon RSSI interrupts */ + A_UINT32 bcn_rssi_weight; + /** Minimum delay between two 5G scans */ + A_UINT32 hirssi_delay_btw_scans; +} wmi_roam_scan_rssi_change_threshold_fixed_param; + +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_NONE 0x1 +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC 0x2 +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC 0x3 +/** + * TLV for roaming channel list + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** WMI_CHAN_LIST_TAG */ + A_UINT32 chan_list_type; + /** # if channels to scan */ + A_UINT32 num_chan; +/** + * TLV (tag length value ) parameters follow the wmi_roam_chan_list + * structure. The TLV's are: + * A_UINT32 channel_list[]; + **/ +} wmi_roam_chan_list_fixed_param; + +/** Authentication modes */ +enum { + WMI_AUTH_NONE, /* no upper level auth */ + WMI_AUTH_OPEN, /* open */ + WMI_AUTH_SHARED, /* shared-key */ + WMI_AUTH_8021X, /* 802.1x */ + WMI_AUTH_AUTO, /* Auto */ + WMI_AUTH_WPA, /* WPA */ + WMI_AUTH_RSNA, /* WPA2/RSNA */ + WMI_AUTH_CCKM, /* CCK */ + WMI_AUTH_WAPI, /* WAPI */ + WMI_AUTH_AUTO_PSK, + WMI_AUTH_WPA_PSK, + WMI_AUTH_RSNA_PSK, + WMI_AUTH_WAPI_PSK, + WMI_AUTH_FT_RSNA, /* 11r FT */ + WMI_AUTH_FT_RSNA_PSK, + WMI_AUTH_RSNA_PSK_SHA256, + WMI_AUTH_RSNA_8021X_SHA256, +}; + +typedef struct { + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; +} wmi_rsn_params; + +/** looking for a wps enabled AP */ +#define WMI_AP_PROFILE_FLAG_WPS 0x1 +/** looking for a secure AP */ +#define WMI_AP_PROFILE_FLAG_CRYPTO 0x2 +/** looking for a PMF enabled AP */ +#define WMI_AP_PROFILE_FLAG_PMF 0x4 + +/** To match an open AP, the rs_authmode should be set to WMI_AUTH_NONE + * and WMI_AP_PROFILE_FLAG_CRYPTO should be clear. + * To match a WEP enabled AP, the rs_authmode should be set to WMI_AUTH_NONE + * and WMI_AP_PROFILE_FLAG_CRYPTO should be set . + */ + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ap_profile */ + /** flags as defined above */ + A_UINT32 flags; + /** + * rssi thresold value: the value of the the candidate AP should + * higher by this threshold than the rssi of the currrently associated AP. + */ + A_UINT32 rssi_threshold; + /** + * ssid vlaue to be matched. + */ + wmi_ssid ssid; + + /** + * security params to be matched. + */ + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; +} wmi_ap_profile; + +/** Support early stop roaming scanning when finding a strong candidate AP + * A 'strong' candidate is + * 1) Is eligible candidate + * (all conditions are met in existing candidate selection). + * 2) Its rssi is better than earlystop threshold. + * Earlystop threshold will be relaxed as each channel is scanned. + */ +typedef struct { + A_UINT32 tlv_header; + /* Minimum RSSI threshold value for early stop, unit is dB above NF. */ + A_UINT32 roam_earlystop_thres_min; + /* Maminum RSSI threshold value for early stop, unit is dB above NF. */ + A_UINT32 roam_earlystop_thres_max; +} wmi_roam_earlystop_rssi_thres_param; + +/** Beacon filter wmi command info */ + +#define BCN_FLT_MAX_SUPPORTED_IES 256 +#define BCN_FLT_MAX_ELEMS_IE_LIST BCN_FLT_MAX_SUPPORTED_IES/32 + +typedef struct bss_bcn_stats { + A_UINT32 vdev_id; + A_UINT32 bss_bcnsdropped; + A_UINT32 bss_bcnsdelivered; +} wmi_bss_bcn_stats_t; + +typedef struct bcn_filter_stats { + A_UINT32 bcns_dropped; + A_UINT32 bcns_delivered; + A_UINT32 activefilters; + wmi_bss_bcn_stats_t bss_stats; +} wmi_bcnfilter_stats_t; + +typedef struct wmi_add_bcn_filter_cmd { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param */ + A_UINT32 vdev_id; + /* + * Following this structure is the TLV: + * A_UINT32 ie_map[BCN_FLT_MAX_ELEMS_IE_LIST]; + */ +} wmi_add_bcn_filter_cmd_fixed_param; + +typedef struct wmi_rmv_bcn_filter_cmd { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_rmv_bcn_filter_cmd_fixed_param; + +#define WMI_BCN_SEND_DTIM_ZERO 1 +#define WMI_BCN_SEND_DTIM_BITCTL_SET 2 +typedef struct wmi_bcn_send_from_host { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 data_len; + A_UINT32 frag_ptr; /* Physical address of the frame */ + A_UINT32 frame_ctrl; /* farme ctrl to setup PPDU desc */ + A_UINT32 dtim_flag; /* to control CABQ traffic */ +} wmi_bcn_send_from_host_cmd_fixed_param; + +/* cmd to support bcn snd for all vaps at once */ +typedef struct wmi_pdev_send_bcn { + A_UINT32 num_vdevs; + wmi_bcn_send_from_host_cmd_fixed_param bcn_cmd[1]; +} wmi_pdev_send_bcn_cmd_t; + +/* + * WMI_ROAM_AP_PROFILE: AP profile of connected AP for roaming. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param */ + /** id of AP criteria */ + A_UINT32 id; + + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + + /* + * Following this structure is the TLV: + * wmi_ap_profile ap_profile; //AP profile info + */ +} wmi_roam_ap_profile_fixed_param; + +/** + * WMI_OFL_SCAN_ADD_AP_PROFILE: add an AP profile. + */ +typedef struct { + /** id of AP criteria */ + A_UINT32 id; + + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + + /** AP profile info */ + wmi_ap_profile ap_profile; + +} wmi_ofl_scan_add_ap_profile; + +/** + * WMI_OFL_SCAN_REMOVE_AP_CRITERIA: remove an ap profile. + */ +typedef struct { + /** id of AP criteria */ + A_UINT32 id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_ofl_scan_remove_ap_profile; + +/** + * WMI_OFL_SCAN_PERIOD: period in msec for offload scan. + * 0 will disable ofload scan and a very low value will perform a continous + * scan. + */ +typedef struct { + /** offload scan period value, used for scans used when not connected */ + A_UINT32 ofl_scan_period; +} wmi_ofl_scan_period; + +/* Do not modify XXX_BYTES or XXX_LEN below as it is fixed by standard */ +#define ROAM_OFFLOAD_PMK_BYTES (32) +#define ROAM_OFFLOAD_PSK_MSK_BYTES (32) +#define ROAM_OFFLOAD_KRK_BYTES (16) +#define ROAM_OFFLOAD_BTK_BYTES (32) +#define ROAM_OFFLOAD_R0KH_ID_MAX_LEN (48) +#define ROAM_OFFLOAD_NUM_MCS_SET (16) + +/* This TLV will be filled only in case roam offload + * for wpa2-psk/okc/ese/11r is enabled */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_offload_fixed_param */ + A_UINT32 rssi_cat_gap; /* gap for every category bucket */ + A_UINT32 prefer_5g; /* prefer select 5G candidate */ + A_UINT32 select_5g_margin; + A_UINT32 reassoc_failure_timeout; /* reassoc failure timeout */ + A_UINT32 capability; + A_UINT32 ht_caps_info; + A_UINT32 ampdu_param; + A_UINT32 ht_ext_cap; + A_UINT32 ht_txbf; + A_UINT32 asel_cap; + A_UINT32 qos_enabled; + A_UINT32 qos_caps; + A_UINT32 wmm_caps; + A_UINT32 mcsset[ROAM_OFFLOAD_NUM_MCS_SET >> 2]; /* since this 4 byte aligned, + * we don't declare it as + * tlv array */ +} wmi_roam_offload_tlv_param; + +/* flags for 11i offload */ +#define WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED 0 /* okc is enabled */ +/* from bit 1 to bit 31 are reserved */ + +#define WMI_SET_ROAM_OFFLOAD_OKC_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED); \ +} while(0) + +#define WMI_SET_ROAM_OFFLOAD_OKC_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED); \ +} while(0) + +#define WMI_GET_ROAM_OFFLOAD_OKC_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED)) + +/* This TLV will be filled only in case of wpa-psk/wpa2-psk */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_11i_offload_fixed_param */ + A_UINT32 flags; + /** flags. see WMI_ROAM_OFFLOAD_FLAG_ above */ + A_UINT32 pmk[ROAM_OFFLOAD_PMK_BYTES >> 2]; /* pmk offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 pmk_len; + /**the length of pmk. in normal case it should be 32, but for LEAP, is should be 16*/ +} wmi_roam_11i_offload_tlv_param; + +/* This TLV will be filled only in case of 11R*/ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_11r_offload_fixed_param */ + A_UINT32 mdie_present; + A_UINT32 mdid; + A_UINT32 r0kh_id[ROAM_OFFLOAD_R0KH_ID_MAX_LEN >> 2]; + A_UINT32 r0kh_id_len; + A_UINT32 psk_msk[ROAM_OFFLOAD_PSK_MSK_BYTES >> 2]; /* psk/msk offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 psk_msk_len; + /**length of psk_msk*/ +} wmi_roam_11r_offload_tlv_param; + +/* This TLV will be filled only in case of ESE */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_ese_offload_fixed_param */ + A_UINT32 krk[ROAM_OFFLOAD_KRK_BYTES >> 2]; /* KRK offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 btk[ROAM_OFFLOAD_BTK_BYTES >> 2]; /* BTK offload. As this 4 byte aligned, we don't declare it as tlv array */ +} wmi_roam_ese_offload_tlv_param; + +/** WMI_ROAM_EVENT: roam event triggering the host roam logic. + * generated when ever a better AP is found in the recent roam scan (or) + * when beacon miss is detected (or) when a DEAUTH/DISASSOC is received + * from the current AP. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** reason for roam event */ + A_UINT32 reason; + /** associated AP's rssi calculated by FW when reason code is WMI_ROAM_REASON_LOW_RSSI*/ + A_UINT32 rssi; + +} wmi_roam_event_fixed_param; + +#define WMI_ROAM_REASON_BETTER_AP 0x1 /** found a better AP */ +#define WMI_ROAM_REASON_BMISS 0x2 /** beacon miss detected */ +#define WMI_ROAM_REASON_DEAUTH 0x2 /** deauth/disassoc received */ +#define WMI_ROAM_REASON_LOW_RSSI 0x3 /** connected AP's low rssi condition detected */ +#define WMI_ROAM_REASON_SUITABLE_AP 0x4 /** found another AP that matches + SSID and Security profile in + WMI_ROAM_AP_PROFILE, found during scan + triggered upon FINAL_BMISS **/ +#define WMI_ROAM_REASON_HO_FAILED 0x5 /** LFR3.0 roaming failed, indicate the disconnection to host */ + +/* + * These will be used in WMI_ROAM_SYNCH_EVENTID for passing the subnet change + * info. Once roaming happens, firmware checks if subnet has changed and + * populates roam_reason field in WMI_ROAM_SYNCH_EVENTID using the definitions + * below. + */ +typedef enum { + WMI_ROAM_SUBNET_CHANGE_STATUS_UNKNOWN = 0, + WMI_ROAM_SUBNET_CHANGE_STATUS_UNCHANGED, + WMI_ROAM_SUBNET_CHANGE_STATUS_CHANGED, +} wmi_roam_subnet_change_status; + +/**whenever RIC request information change, host driver should pass all ric related information to firmware (now only support tsepc) + * Once, 11r roaming happens, firmware can generate RIC request in reassoc request based on these informations + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ric_request_fixed_param */ + A_UINT32 vdev_id; + /**unique id identifying the VDEV, generated by the caller*/ + A_UINT32 num_ric_request; + /**number of ric request ie send to firmware.(max value is 2 now)*/ + A_UINT32 is_add_ric; + /**support add ric or delete ric*/ +} wmi_ric_request_fixed_param; + +/**tspec element: refer to 8.4.2.32 of 802.11 2012 spec + * these elements are used to construct tspec field in RIC request, which allow station to require specific TS when 11r roaming + */ +typedef struct { + A_UINT32 tlv_header; + A_UINT32 ts_info; /** bits value of TS Info field.*/ + A_UINT32 nominal_msdu_size; /**Nominal MSDU Size field*/ + A_UINT32 maximum_msdu_size; /**The Maximum MSDU Size field*/ + A_UINT32 min_service_interval; /**The Minimum Service Interval field*/ + A_UINT32 max_service_interval; /**The Maximum Service Interval field*/ + A_UINT32 inactivity_interval; /**The Inactivity Interval field*/ + A_UINT32 suspension_interval; /**The Suspension Interval field*/ + A_UINT32 svc_start_time; /**The Service Start Time field*/ + A_UINT32 min_data_rate; /**The Minimum Data Rate field*/ + A_UINT32 mean_data_rate; /**The Mean Data Rate field*/ + A_UINT32 peak_data_rate; /**The Peak Data Rate field*/ + A_UINT32 max_burst_size; /**The Burst Size field*/ + A_UINT32 delay_bound; /**The Delay Bound field*/ + A_UINT32 min_phy_rate; /**The Minimum PHY Rate field*/ + A_UINT32 surplus_bw_allowance; /**The Surplus Bandwidth Allowance field*/ + A_UINT32 medium_time; /**The Medium Time field,in units of 32 us/s.*/ +} wmi_ric_tspec; + +/* flags for roam_invoke_cmd */ +/* add this channel into roam cache channel list after this command is finished */ +#define WMI_ROAM_INVOKE_FLAG_ADD_CH_TO_CACHE 0 +/* from bit 1 to bit 31 are reserved */ + +#define WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) do { \ + (flag) |= (1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE); \ + } while(0) + +#define WMI_CLEAR_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) do { \ + (flag) &= ~(1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE); \ + } while(0) + +#define WMI_GET_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) \ + ((flag) & (1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE)) + + +#define WMI_ROAM_INVOKE_SCAN_MODE_FIXED_CH 0 /* scan given channel only */ +#define WMI_ROAM_INVOKE_SCAN_MODE_CACHE_LIST 1 /* scan cached channel list */ +#define WMI_ROAM_INVOKE_SCAN_MODE_FULL_CH 2 /* scan full channel */ + +#define WMI_ROAM_INVOKE_AP_SEL_FIXED_BSSID 0 /* roam to given BSSID only */ +#define WMI_ROAM_INVOKE_AP_SEL_ANY_BSSID 1 /* roam to any BSSID */ + +/** WMI_ROAM_INVOKE_CMD: command to invoke roaming forcefully + * + * if is zero and is not given, roaming is not executed. + * if is zero and = 0 + * = 0 + * = 0 + * |= WMI_ROAM_INVOKE_FLAG_ADD_CH_TO_CACHE + * = do not fill (there will be no actual roaming because of ap_sel_mode is zero, but no BSSID is given) + * = channel list to be added + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_invoke_fixed_param */ + A_UINT32 vdev_id; /** Unique id identifying the VDEV on which roaming is invoked */ + A_UINT32 flags; /** flags. see WMI_ROAM_INVOKE_FLAG_ above */ + A_UINT32 roam_scan_mode; /** see WMI_ROAM_INVOKE_SCAN_ above */ + A_UINT32 roam_ap_sel_mode; /** see WMI_ROAM_INVOKE_AP_SEL_ above */ + A_UINT32 roam_delay; /** 0 = immediate roam, 1-2^32 = roam after this delay (msec) */ + A_UINT32 num_chan; /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_bssid; /** number of bssids. In the TLV bssid_list[] */ + /** + * TLV (tag length value ) parameters follows roam_invoke_req + * The TLV's are: + * A_UINT32 channel_list[]; + * wmi_mac_addr bssid_list[]; + */ +} wmi_roam_invoke_cmd_fixed_param; + +/* Definition for op_bitmap */ +enum { + ROAM_FILTER_OP_BITMAP_BLACK_LIST = 0x1, + ROAM_FILTER_OP_BITMAP_WHITE_LIST = 0x2, + ROAM_FILTER_OP_BITMAP_PREFER_BSSID = 0x4, +}; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_filter_list_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV on which roaming filter is adopted */ + A_UINT32 vdev_id; + A_UINT32 flags; /** flags for filter */ + /** 32 bit bitmap to be set on. + * bit0 = first param, + * bit 1 = second param...etc. Can be or'ed + */ + A_UINT32 op_bitmap; + /* number of blacklist in the TLV variable bssid_black_list */ + A_UINT32 num_bssid_black_list; + /* number of whitelist in the TLV variable ssid_white_list */ + A_UINT32 num_ssid_white_list; + /* only for lfr 3.0. number of preferred list & factor in the TLV */ + A_UINT32 num_bssid_preferred_list; + /** + * TLV (tag length value ) parameters follows roam_filter_list_cmd + * The TLV's are: + * wmi_mac_addr bssid_black_list[]; + * wmi_ssid ssid_white_list[]; + * wmi_mac_addr bssid_preferred_list[]; + * A_UINT32 bssid_preferred_factor[]; + */ +} wmi_roam_filter_fixed_param; + +typedef struct { + A_UINT8 address[4]; /* IPV4 address in Network Byte Order */ +} WMI_IPV4_ADDR; + +typedef struct _WMI_IPV6_ADDR { + A_UINT8 address[16]; /* IPV6 in Network Byte Order */ +} WMI_IPV6_ADDR; + +/* flags for subnet change detection */ +#define WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED 0 +#define WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED 1 +/* bit 2 to bit 31 are reserved */ + +/* set IPv4 enabled/disabled flag and get the flag */ +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED); \ +} while (0) + +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED); \ +} while (0) + +#define WMI_GET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED)) + +/* set IPv6 enabled flag, disabled and get the flag */ +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED); \ +} while (0) + +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED); \ +} while (0) + +#define WMI_GET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED)) + +/** + * WMI_ROAM_SUBNET_CHANGE_CONFIG : Pass the gateway IP and MAC addresses + * to FW. FW uses these parameters for subnet change detection. + */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param + */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** IPv4/IPv6 enabled/disabled */ + /** This flag sets the WMI_SET_ROAM_SUBNET_CHANGE_FLAG_xxx_ENABLED/ + DISABLED */ + A_UINT32 flag; + /** Gateway MAC address */ + wmi_mac_addr inet_gw_mac_addr; + /** IP addresses */ + WMI_IPV4_ADDR inet_gw_ip_v4_addr; + WMI_IPV6_ADDR inet_gw_ip_v6_addr; + /** Number of software retries for ARP/Neighbor solicitation request */ + A_UINT32 max_retries; + /** timeout in milliseconds for each ARP request*/ + A_UINT32 timeout; + /** number of skipped aps **/ + A_UINT32 num_skip_subnet_change_detection_bssid_list; +/** + * TLV (tag length value ) parameters follows roam_subnet_change_config_cmd + * structure. The TLV's are: + * wmi_mac_addr skip_subnet_change_detection_bssid_list []; + **/ +} wmi_roam_subnet_change_config_fixed_param; + +/** WMI_PROFILE_MATCH_EVENT: offload scan + * generated when ever atleast one of the matching profiles is found + * in recent NLO scan. no data is carried with the event. + */ + +/** P2P specific commands */ + +/** + * WMI_P2P_DEV_SET_DEVICE_INFO : p2p device info, which will be used by + * FW to generate P2P IE tobe carried in probe response frames. + * FW will respond to probe requests while in listen state. + */ +typedef struct { + /* number of secondary device types,supported */ + A_UINT32 num_secondary_dev_types; + /** + * followed by 8 bytes of primary device id and + * num_secondary_dev_types * 8 bytes of secondary device + * id. + */ +} wmi_p2p_dev_set_device_info; + +/** WMI_P2P_DEV_SET_DISCOVERABILITY: enable/disable discoverability + * state. if enabled, an active STA/AP will respond to P2P probe requests on + * the operating channel of the VDEV. + */ + +typedef struct { + /* 1:enable disoverability, 0:disable discoverability */ + A_UINT32 enable_discoverability; +} wmi_p2p_set_discoverability; + +/** WMI_P2P_GO_SET_BEACON_IE: P2P IE to be added to + * beacons generated by FW. used in FW beacon mode. + * the FW will add this IE to beacon in addition to the beacon + * template set by WMI_BCN_TMPL_CMDID command. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* ie length */ + A_UINT32 ie_buf_len; + /* Following this structure is the TLV byte stream of ie data of length ie_buf_len: + * A_UINT8 ie_data[]; // length in byte given by field num_data. + */ + +} wmi_p2p_go_set_beacon_ie_fixed_param; + +/** WMI_P2P_GO_PROBE_RESP_IE: P2P IE to be added to + * probe response generated by FW. used in FW beacon mode. + * the FW will add this IE to probe response in addition to the probe response + * template set by WMI_PRB_TMPL_CMDID command. + */ +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* ie length */ + A_UINT32 ie_buf_len; + /*followed by byte stream of ie data of length ie_buf_len */ +} wmi_p2p_go_set_probe_resp_ie; + +/** WMI_P2P_SET_VENDOR_IE_DATA_CMDID: Vendor specific P2P IE data, which will + * be used by the FW to parse the P2P NoA attribute in beacons, probe resposes + * and action frames received by the P2P Client. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param */ + /** OS specific P2P IE OUI (3 bytes) + OUI type (1 byte) */ + A_UINT32 p2p_ie_oui_type; + /** OS specific NoA Attribute ID */ + A_UINT32 p2p_noa_attribute; +} wmi_p2p_set_vendor_ie_data_cmd_fixed_param; + +/*----P2P disc offload definition ----*/ + +typedef struct { + A_UINT32 pattern_type; + /** + * TLV (tag length value ) paramerters follow the pattern structure. + * TLV can contain bssid list, ssid list and + * ie. the TLV tags are defined above; + */ +} wmi_p2p_disc_offload_pattern_cmd; + +typedef struct { + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* mgmt type of the ie */ + A_UINT32 mgmt_type; + /* ie length */ + A_UINT32 ie_buf_len; + /*followed by byte stream of ie data of length ie_buf_len */ +} wmi_p2p_disc_offload_appie_cmd; + +typedef struct { + /* enable/disable p2p find offload */ + A_UINT32 enable; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* p2p find type */ + A_UINT32 disc_type; + /* p2p find perodic */ + A_UINT32 perodic; + /* p2p find listen channel */ + A_UINT32 listen_channel; + /* p2p find full channel number */ + A_UINT32 num_scan_chans; + /** + * TLV (tag length value ) paramerters follow the pattern structure. + * TLV contain channel list + */ +} wmi_p2p_disc_offload_config_cmd; + +/*----P2P OppPS definition ----*/ +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* OppPS attributes */ + /** Bit 0: Indicate enable/disable of OppPS + * Bits 7-1: Ctwindow in TUs + * Bits 31-8: Reserved + */ + A_UINT32 oppps_attr; +} wmi_p2p_set_oppps_cmd_fixed_param; + +#define WMI_UNIFIED_OPPPS_ATTR_ENALBED 0x1 +#define WMI_UNIFIED_OPPPS_ATTR_ENALBED_S 0 + +#define WMI_UNIFIED_OPPPS_ATTR_IS_ENABLED(hdr) \ + WMI_F_MS((hdr)->oppps_attr, WMI_UNIFIED_OPPPS_ATTR_ENALBED) + +#define WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(hdr) \ + WMI_F_RMW((hdr)->oppps_attr, 0x1, \ + WMI_UNIFIED_OPPPS_ATTR_ENALBED); + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN 0xfe +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_S 1 + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_GET(hdr) \ + WMI_F_MS((hdr)->oppps_attr, WMI_UNIFIED_OPPPS_ATTR_CTWIN) + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(hdr, v) \ + WMI_F_RMW((hdr)->oppps_attr, (v) & 0x7f, \ + WMI_UNIFIED_OPPPS_ATTR_CTWIN); + +typedef struct { + A_UINT32 time32; /* upper 32 bits of time stamp */ + A_UINT32 time0; /* lower 32 bits of time stamp */ +} A_TIME64; + +typedef enum wmi_peer_sta_kickout_reason { + WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED = 0, /* default value to preserve legacy behavior */ + WMI_PEER_STA_KICKOUT_REASON_XRETRY = 1, + WMI_PEER_STA_KICKOUT_REASON_INACTIVITY = 2, + WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT = 3, + WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT = 4, /* TDLS peer has disappeared. All tx is failing */ + WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5, +} PEER_KICKOUT_REASON; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param */ + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Reason code, defined as above */ + A_UINT32 reason; + /** RSSI of the last bcn (averaged) in dB. 0 means Noise Floor value */ + A_UINT32 rssi; +} wmi_peer_sta_kickout_event_fixed_param; + +#define WMI_WLAN_PROFILE_MAX_HIST 3 +#define WMI_WLAN_PROFILE_MAX_BIN_CNT 32 + +typedef struct _wmi_wlan_profile_t { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_t */ + A_UINT32 id; + A_UINT32 cnt; + A_UINT32 tot; + A_UINT32 min; + A_UINT32 max; + A_UINT32 hist_intvl; + A_UINT32 hist[WMI_WLAN_PROFILE_MAX_HIST]; +} wmi_wlan_profile_t; + +typedef struct _wmi_wlan_profile_ctx_t { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t */ + A_UINT32 tot; /* time in us */ + A_UINT32 tx_msdu_cnt; + A_UINT32 tx_mpdu_cnt; + A_UINT32 tx_ppdu_cnt; + A_UINT32 rx_msdu_cnt; + A_UINT32 rx_mpdu_cnt; + A_UINT32 bin_count; +} wmi_wlan_profile_ctx_t; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param */ + A_UINT32 enable; +} wmi_wlan_profile_trigger_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param */ + A_UINT32 value; +} wmi_wlan_profile_get_prof_data_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param */ + A_UINT32 profile_id; + A_UINT32 value; +} wmi_wlan_profile_set_hist_intvl_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param */ + A_UINT32 profile_id; + A_UINT32 enable; +} wmi_wlan_profile_enable_profile_id_cmd_fixed_param; + +/*Wifi header is upto 26, LLC is 8, with 14 byte duplicate in 802.3 header, that's 26+8-14=20. + 146-128=18. So this means it is converted to non-QoS header. Riva FW take care of the QOS/non-QOS + when comparing wifi header.*/ +/* NOTE: WOW_DEFAULT_BITMAP_PATTERN_SIZE(_DWORD) and WOW_DEFAULT_BITMASK_SIZE(_DWORD) can't be changed without breaking the compatibility */ +#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 146 +#define WOW_DEFAULT_BITMAP_PATTERN_SIZE_DWORD 37 /* Convert WOW_DEFAULT_EVT_BUF_SIZE into Int32 size */ +#define WOW_DEFAULT_BITMASK_SIZE 146 +#define WOW_DEFAULT_BITMASK_SIZE_DWORD 37 +#define WOW_MAX_BITMAP_FILTERS 32 +#define WOW_DEFAULT_MAGIG_PATTERN_MATCH_CNT 16 +#define WOW_EXTEND_PATTERN_MATCH_CNT 16 +#define WOW_SHORT_PATTERN_MATCH_CNT 8 +#define WOW_DEFAULT_EVT_BUF_SIZE 148 /* Maximum 148 bytes of the data is copied starting from header incase if the match is found. + The 148 comes from (128 - 14 ) payload size + 8bytes LLC + 26bytes MAC header */ +#define WOW_DEFAULT_IOAC_PATTERN_SIZE 6 +#define WOW_DEFAULT_IOAC_PATTERN_SIZE_DWORD 2 +#define WOW_DEFAULT_IOAC_RANDOM_SIZE 6 +#define WOW_DEFAULT_IOAC_RANDOM_SIZE_DWORD 2 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE 120 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE_DWORD 30 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE 32 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE_DWORD 8 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE 32 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE_DWORD 8 + +typedef enum pattern_type_e { + WOW_PATTERN_MIN = 0, + WOW_BITMAP_PATTERN = WOW_PATTERN_MIN, + WOW_IPV4_SYNC_PATTERN, + WOW_IPV6_SYNC_PATTERN, + WOW_WILD_CARD_PATTERN, + WOW_TIMER_PATTERN, + WOW_MAGIC_PATTERN, + WOW_IPV6_RA_PATTERN, + WOW_IOAC_PKT_PATTERN, + WOW_IOAC_TMR_PATTERN, + WOW_IOAC_SOCK_PATTERN, + WOW_PATTERN_MAX +} WOW_PATTERN_TYPE; + +typedef enum event_type_e { + WOW_BMISS_EVENT = 0, + WOW_BETTER_AP_EVENT, + WOW_DEAUTH_RECVD_EVENT, + WOW_MAGIC_PKT_RECVD_EVENT, + WOW_GTK_ERR_EVENT, + WOW_FOURWAY_HSHAKE_EVENT, + WOW_EAPOL_RECVD_EVENT, + WOW_NLO_DETECTED_EVENT, + WOW_DISASSOC_RECVD_EVENT, + WOW_PATTERN_MATCH_EVENT, + WOW_CSA_IE_EVENT, + WOW_PROBE_REQ_WPS_IE_EVENT, + WOW_AUTH_REQ_EVENT, + WOW_ASSOC_REQ_EVENT, + WOW_HTT_EVENT, + WOW_RA_MATCH_EVENT, + WOW_HOST_AUTO_SHUTDOWN_EVENT, + WOW_IOAC_MAGIC_EVENT, + WOW_IOAC_SHORT_EVENT, + WOW_IOAC_EXTEND_EVENT, + WOW_IOAC_TIMER_EVENT, + WOW_DFS_PHYERR_RADAR_EVENT, + WOW_BEACON_EVENT, + WOW_CLIENT_KICKOUT_EVENT, + WOW_NAN_EVENT, + WOW_EXTSCAN_EVENT, + WOW_IOAC_REV_KA_FAIL_EVENT, + WOW_IOAC_SOCK_EVENT, + WOW_NLO_SCAN_COMPLETE_EVENT, +} WOW_WAKE_EVENT_TYPE; + +typedef enum wake_reason_e { + WOW_REASON_UNSPECIFIED = -1, + WOW_REASON_NLOD = 0, + WOW_REASON_AP_ASSOC_LOST, + WOW_REASON_LOW_RSSI, + WOW_REASON_DEAUTH_RECVD, + WOW_REASON_DISASSOC_RECVD, + WOW_REASON_GTK_HS_ERR, + WOW_REASON_EAP_REQ, + WOW_REASON_FOURWAY_HS_RECV, + WOW_REASON_TIMER_INTR_RECV, + WOW_REASON_PATTERN_MATCH_FOUND, + WOW_REASON_RECV_MAGIC_PATTERN, + WOW_REASON_P2P_DISC, + WOW_REASON_WLAN_HB, + WOW_REASON_CSA_EVENT, + WOW_REASON_PROBE_REQ_WPS_IE_RECV, + WOW_REASON_AUTH_REQ_RECV, + WOW_REASON_ASSOC_REQ_RECV, + WOW_REASON_HTT_EVENT, + WOW_REASON_RA_MATCH, + WOW_REASON_HOST_AUTO_SHUTDOWN, + WOW_REASON_IOAC_MAGIC_EVENT, + WOW_REASON_IOAC_SHORT_EVENT, + WOW_REASON_IOAC_EXTEND_EVENT, + WOW_REASON_IOAC_TIMER_EVENT, + WOW_REASON_ROAM_HO, + WOW_REASON_DFS_PHYERR_RADADR_EVENT, + WOW_REASON_BEACON_RECV, + WOW_REASON_CLIENT_KICKOUT_EVENT, + WOW_REASON_NAN_EVENT, + WOW_REASON_EXTSCAN, + WOW_REASON_RSSI_BREACH_EVENT, + WOW_REASON_IOAC_REV_KA_FAIL_EVENT, + WOW_REASON_IOAC_SOCK_EVENT, + WOW_REASON_NLO_SCAN_COMPLETE, + WOW_REASON_PACKET_FILTER_MATCH, + WOW_REASON_ASSOC_RES_RECV, + WOW_REASON_REASSOC_REQ_RECV, + WOW_REASON_REASSOC_RES_RECV, + WOW_REASON_ACTION_FRAME_RECV, + WOW_REASON_DEBUG_TEST = 0xFF, +} WOW_WAKE_REASON_TYPE; + +typedef enum { + WOW_IFACE_PAUSE_ENABLED, + WOW_IFACE_PAUSE_DISABLED +} WOW_IFACE_STATUS; + +enum { + /* some win10 platfrom will not assert pcie_reset for wow.*/ + WMI_WOW_FLAG_IGNORE_PCIE_RESET = 0x00000001, +}; + + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param */ + A_UINT32 enable; + A_UINT32 pause_iface_config; + A_UINT32 flags; /* WMI_WOW_FLAG enums */ +} wmi_wow_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_wow_hostwakeup_from_sleep_cmd_fixed_param; + +#define WOW_ICMPV6_NA_FILTER_DISABLE 0 +#define WOW_ICMPV6_NA_FILTER_ENABLE 1 + +typedef struct { + /* TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; /* WOW_ICMPV6_NA_FILTER_ENABLE/DISABLE */ +} wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param; + +typedef struct bitmap_pattern_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T */ + A_UINT32 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE_DWORD]; + A_UINT32 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE_DWORD]; + A_UINT32 pattern_offset; + A_UINT32 pattern_len; + A_UINT32 bitmask_len; + A_UINT32 pattern_id; /* must be less than max_bitmap_filters */ +} WOW_BITMAP_PATTERN_T; + +typedef struct ipv4_sync_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T */ + A_UINT32 ipv4_src_addr; + A_UINT32 ipv4_dst_addr; + A_UINT32 tcp_src_prt; + A_UINT32 tcp_dst_prt; +} WOW_IPV4_SYNC_PATTERN_T; + +typedef struct ipv6_sync_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T */ + A_UINT32 ipv6_src_addr[4]; + A_UINT32 ipv6_dst_addr[4]; + A_UINT32 tcp_src_prt; + A_UINT32 tcp_dst_prt; +} WOW_IPV6_SYNC_PATTERN_T; + +typedef struct WOW_MAGIC_PATTERN_CMD { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD */ + wmi_mac_addr macaddr; +} WOW_MAGIC_PATTERN_CMD; + +typedef enum wow_ioac_pattern_type { + WOW_IOAC_MAGIC_PATTERN = 1, + WOW_IOAC_SHORT_PATTERN, + WOW_IOAC_EXTEND_PATTERN, +} WOW_IOAC_PATTERN_TYPE; + +typedef struct ioac_sock_pattern_s { + /** + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_WOW_IOAC_SOCK_PATTERN_T + */ + A_UINT32 tlv_header; + A_UINT32 id; + A_UINT32 local_ipv4; + A_UINT32 remote_ipv4; + A_UINT32 local_port; + A_UINT32 remote_port; + A_UINT32 pattern_len; /* units = bytes */ + A_UINT32 pattern[WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE_DWORD]; +} WOW_IOAC_SOCK_PATTERN_T; + +typedef struct ioac_pkt_pattern_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IOAC_PKT_PATTERN_T */ + A_UINT32 pattern_type; + A_UINT32 pattern[WOW_DEFAULT_IOAC_PATTERN_SIZE_DWORD]; + A_UINT32 random[WOW_DEFAULT_IOAC_RANDOM_SIZE_DWORD]; + A_UINT32 pattern_len; + A_UINT32 random_len; +} WOW_IOAC_PKT_PATTERN_T; + +typedef struct ioac_tmr_pattern_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IOAC_TMR_PATTERN_T */ + A_UINT32 wake_in_s; + A_UINT32 vdev_id; +} WOW_IOAC_TMR_PATTERN_T; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param */ + A_UINT32 nID; +} WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param */ + A_UINT32 nID; +} WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param; + +typedef struct ioac_keepalive_s { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_KEEPALIVE_T */ + A_UINT32 + keepalive_pkt_buf + [WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE_DWORD]; + A_UINT32 keepalive_pkt_len; + A_UINT32 period_in_ms; + A_UINT32 vdev_id; + A_UINT32 max_loss_cnt; + A_UINT32 local_ipv4; + A_UINT32 remote_ipv4; + A_UINT32 local_port; + A_UINT32 remote_port; + A_UINT32 recv_period_in_ms; + A_UINT32 rev_ka_size; + A_UINT32 rev_ka_data[WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE_DWORD]; +} WMI_WOW_IOAC_KEEPALIVE_T; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_type; +/* + * Following this struct are these TLVs. Note that they are all array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field pattern_type. This is to emulate an union. + * WOW_IOAC_PKT_PATTERN_T pattern_info_pkt[]; + * WOW_IOAC_TMR_PATTERN_T pattern_info_tmr[]; + */ +} WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_type; + A_UINT32 pattern_id; +} WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 pattern_type; + /* + * Following this struct are these TLVs. Note that they are all array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field pattern_type. This is to emulate an union. + * WOW_BITMAP_PATTERN_T pattern_info_bitmap[]; + * WOW_IPV4_SYNC_PATTERN_T pattern_info_ipv4[]; + * WOW_IPV6_SYNC_PATTERN_T pattern_info_ipv6[]; + * WOW_MAGIC_PATTERN_CMD pattern_info_magic_pattern[]; + * A_UINT32 pattern_info_timeout[]; + * A_UINT32 ra_ratelimit_interval; + */ +} WMI_WOW_ADD_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 pattern_type; +} WMI_WOW_DEL_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 is_add; + A_UINT32 event_bitmap; +} WMI_WOW_ADD_DEL_EVT_CMD_fixed_param; + +/* + * This structure is used to set the pattern to check UDP packet in WOW mode. + * If match, construct a tx frame in a local buffer to send through the peer + * AP to the entity in the IP network that sent the UDP packet to this STA. + */ +typedef struct { + /* + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; /* 1: enable, 0: disable */ + /* + * dest_port - + * bits 7:0 contain the LSB of the UDP dest port, + * bits 15:8 contain the MSB of the UDP dest port + */ + A_UINT32 dest_port; + A_UINT32 pattern_len; /* length in byte of pattern[] */ + A_UINT32 response_len; /* length in byte of response[] */ + /* + * Following this struct are the TLV's: + * payload of UDP packet to be checked, network byte order + * A_UINT8 pattern[]; + * payload of UDP packet to be response, network byte order + * A_UINT8 response[]; + */ +} WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param; + +/* + * This structure is used to set the pattern for WOW host wakeup pin pulse + * pattern confirguration. + */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_WMI_WOW_HOSTWAKEUP_PIN_PATTERN_CONFIG_CMD_fixed_param + */ + A_UINT32 tlv_header; + + /* 1: enable, 0: disable */ + A_UINT32 enable; + + /* pin for host wakeup */ + A_UINT32 pin; + + /* interval for keeping low voltage, unit: ms */ + A_UINT32 interval_low; + + /* interval for keeping high voltage, unit: ms */ + A_UINT32 interval_high; + + /* repeat times for pulse (0xffffffff means forever) */ + A_UINT32 repeat_cnt; +} WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param; + +typedef struct wow_event_info_s { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 flag; /*This is current reserved. */ + A_INT32 wake_reason; + A_UINT32 data_len; +} WOW_EVENT_INFO_fixed_param; + +typedef struct wow_initial_wakeup_event_s { + /* + * TLV tag and len; tag equals + * WOW_INITIAL_WAKEUP_EVENT_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} WOW_INITIAL_WAKEUP_EVENT_fixed_param; + +typedef enum { + WOW_EVENT_INFO_TYPE_PACKET = 0x0001, + WOW_EVENT_INFO_TYPE_BITMAP, + WOW_EVENT_INFO_TYPE_GTKIGTK, +} WOW_EVENT_INFO_TYPE; + +typedef struct wow_event_info_section_s { + A_UINT32 data_type; + A_UINT32 data_len; +} WOW_EVENT_INFO_SECTION; + +typedef struct wow_event_info_section_packet_s { + A_UINT8 packet[WOW_DEFAULT_EVT_BUF_SIZE]; +} WOW_EVENT_INFO_SECTION_PACKET; + +typedef struct wow_event_info_section_bitmap_s { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_EVENT_INFO_SECTION_BITMAP */ + A_UINT32 flag; /*This is current reserved. */ + A_UINT32 value; /*This could be the pattern id for bitmap pattern. */ + A_UINT32 org_len; /*The length of the orginal packet. */ +} WOW_EVENT_INFO_SECTION_BITMAP; + +/** + * This command is sent from WLAN host driver to firmware to + * enable or disable D0-WOW. D0-WOW means APSS suspend with + * PCIe link and DDR being active. + * + * + * Entering D0-WOW Mode (based on kernel suspend request): + * host->target: WMI_DO_WOW_ENABLE_DISABLE_CMDID (enable = 1) + * target: Take action (e.g. dbglog suspend) + * target->host: HTC_ACK (HTC_MSG_SEND_SUSPEND_COMPLETE message) + * + * Exiting D0-WOW mode (based on kernel resume OR target->host message received) + * host->target: WMI_DO_WOW_ENABLE_DISABLE_CMDID (enable = 0) + * target: Take action (e.g. dbglog resume) + * target->host: WMI_D0_WOW_DISABLE_ACK_EVENTID + * + * This command is applicable only on the PCIE LL systems + * Host can enter either D0-WOW or WOW mode, but NOT both at same time + * Decision to enter D0-WOW or WOW is based on active interfaces + * + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param */ + A_UINT32 enable; /* 1 = enable, 0 = disable */ +} wmi_d0_wow_enable_disable_cmd_fixed_param; + +typedef enum extend_wow_type_e { + EXTWOW_TYPE_APP_TYPE1, /* extend wow type: only enable wakeup for app type1 */ + EXTWOW_TYPE_APP_TYPE2, /* extend wow type: only enable wakeup for app type2 */ + EXTWOW_TYPE_APP_TYPE1_2, /* extend wow type: enable wakeup for app type1&2 */ + EXTWOW_DISABLED = 255, +} EXTWOW_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 type; + A_UINT32 wakeup_pin_num; +} wmi_extwow_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_set_app_type1_params_cmd_fixed_param */ + A_UINT32 vdev_id; + wmi_mac_addr wakee_mac; + A_UINT8 ident[8]; + A_UINT8 passwd[16]; + A_UINT32 ident_len; + A_UINT32 passwd_len; +} wmi_extwow_set_app_type1_params_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_set_app_type2_params_cmd_fixed_param */ + A_UINT32 vdev_id; + + A_UINT8 rc4_key[16]; + A_UINT32 rc4_key_len; + + /** ip header parameter */ + A_UINT32 ip_id; /* NC id */ + A_UINT32 ip_device_ip; /* NC IP address */ + A_UINT32 ip_server_ip; /* Push server IP address */ + + /** tcp header parameter */ + A_UINT16 tcp_src_port; /* NC TCP port */ + A_UINT16 tcp_dst_port; /* Push server TCP port */ + A_UINT32 tcp_seq; + A_UINT32 tcp_ack_seq; + + A_UINT32 keepalive_init; /* Initial ping interval */ + A_UINT32 keepalive_min; /* Minimum ping interval */ + A_UINT32 keepalive_max; /* Maximum ping interval */ + A_UINT32 keepalive_inc; /* Increment of ping interval */ + + wmi_mac_addr gateway_mac; + A_UINT32 tcp_tx_timeout_val; + A_UINT32 tcp_rx_timeout_val; + + /** add extra parameter for backward-compatible */ + /* + * For all byte arrays, natural order is used. E.g. + * rc4_write_sandbox[0] holds the 1st RC4 S-box byte, + * rc4_write_sandbox[1] holds the 2nd RC4 S-box byte, etc. + */ + + /* used to encrypt transmit packet such as keep-alive */ + A_UINT8 rc4_write_sandbox[256]; + A_UINT32 rc4_write_x; + A_UINT32 rc4_write_y; + + /* used to decrypt received packet such as wow data */ + A_UINT8 rc4_read_sandbox[256]; + A_UINT32 rc4_read_x; + A_UINT32 rc4_read_y; + + /* used to caculate HMAC hash for transmit packet such as keep-alive */ + A_UINT8 ssl_write_seq[8]; + A_UINT8 ssl_sha1_write_key[64]; + A_UINT32 ssl_sha1_write_key_len; + + /* used to calculate HAMC hash for receive packet such as wow data */ + A_UINT8 ssl_read_seq[8]; + A_UINT8 ssl_sha1_read_key[64]; + A_UINT32 ssl_sha1_read_key_len; + + /* optional element for specifying TCP options data to include in + * transmit packets such as keep-alive + */ + A_UINT32 tcp_options_len; + A_UINT8 tcp_options[40]; + + A_UINT32 async_id; /* keep-alive request id */ +} wmi_extwow_set_app_type2_params_cmd_fixed_param; + +#define WMI_RXERR_CRC 0x01 /* CRC error on frame */ +#define WMI_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */ +#define WMI_RXERR_MIC 0x10 /* Michael MIC decrypt error */ +#define WMI_RXERR_KEY_CACHE_MISS 0x20 /* No/incorrect key matter in h/w */ + +typedef enum { + PKT_PWR_SAVE_PAID_MATCH = 0x0001, + PKT_PWR_SAVE_GID_MATCH = 0x0002, + PKT_PWR_SAVE_EARLY_TIM_CLEAR = 0x0004, + PKT_PWR_SAVE_EARLY_DTIM_CLEAR = 0x0008, + PKT_PWR_SAVE_EOF_PAD_DELIM = 0x0010, + PKT_PWR_SAVE_MACADDR_MISMATCH = 0x0020, + PKT_PWR_SAVE_DELIM_CRC_FAIL = 0x0040, + PKT_PWR_SAVE_GID_NSTS_ZERO = 0x0080, + PKT_PWR_SAVE_RSSI_CHECK = 0x0100, + PKT_PWR_SAVE_5G_EBT = 0x0200, + PKT_PWR_SAVE_2G_EBT = 0x0400, + WMI_PKT_PWR_SAVE_MAX = 0x0800, +} WMI_PKT_PWR_SAVE_TYPE; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param */ + A_UINT32 num_data; + /** length in byte of data[]. */ + /* This structure is used to send Factory Test Mode [FTM] command + * from host to firmware for integrated chips which are binary blobs. + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field num_data. + */ +} wmi_ftm_intg_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param */ + A_UINT32 num_data; + /** length in byte of data[]. */ + /* This structure is used to receive Factory Test Mode [FTM] event + * from firmware to host for integrated chips which are binary blobs. + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field num_data. + */ +} wmi_ftm_intg_event_fixed_param; + +#define WMI_MAX_NS_OFFLOADS 2 +#define WMI_MAX_ARP_OFFLOADS 2 + +#define WMI_ARPOFF_FLAGS_VALID (1 << 0) /* the tuple entry is valid */ +#define WMI_ARPOFF_FLAGS_MAC_VALID (1 << 1) /* the target mac address is valid */ +#define WMI_ARPOFF_FLAGS_REMOTE_IP_VALID (1 << 2) /* remote IP field is valid */ + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE */ + A_UINT32 flags; /* flags */ + A_UINT8 target_ipaddr[4]; /* IPV4 addresses of the local node */ + A_UINT8 remote_ipaddr[4]; /* source address of the remote node requesting the ARP (qualifier) */ + wmi_mac_addr target_mac; /* mac address for this tuple, if not valid, the local MAC is used */ +} WMI_ARP_OFFLOAD_TUPLE; + +#define WMI_NSOFF_FLAGS_VALID (1 << 0) /* the tuple entry is valid */ +#define WMI_NSOFF_FLAGS_MAC_VALID (1 << 1) /* the target mac address is valid */ +#define WMI_NSOFF_FLAGS_REMOTE_IP_VALID (1 << 2) /* remote IP field is valid */ + +#define WMI_NSOFF_MAX_TARGET_IPS 2 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE */ + A_UINT32 flags; /* flags */ + /* NOTE: This size of array target_ipaddr[] cannot be changed without breaking WMI compatibility. */ + WMI_IPV6_ADDR target_ipaddr[WMI_NSOFF_MAX_TARGET_IPS]; /* IPV6 target addresses of the local node */ + WMI_IPV6_ADDR solicitation_ipaddr; /* multi-cast source IP addresses for receiving solicitations */ + WMI_IPV6_ADDR remote_ipaddr; /* address of remote node requesting the solicitation (qualifier) */ + wmi_mac_addr target_mac; /* mac address for this tuple, if not valid, the local MAC is used */ +} WMI_NS_OFFLOAD_TUPLE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param */ + A_UINT32 flags; + A_UINT32 vdev_id; + A_UINT32 num_ns_ext_tuples; + /* Following this structure are the TLVs: + * WMI_NS_OFFLOAD_TUPLE ns_tuples[WMI_MAX_NS_OFFLOADS]; + * WMI_ARP_OFFLOAD_TUPLE arp_tuples[WMI_MAX_ARP_OFFLOADS]; + * size of ns_ext_tuples is based on num_ns_ext_tuples + * WMI_NS_OFFLOAD_TUPLE ns_ext_tuples[]; + */ +} WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 timeout; + A_UINT32 length; + /* Following this would be the pattern + A_UINT8 pattern[] of length specifed by length + field in the structure. */ +} WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 pattern_id; +} WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Initiator (1) or Responder (0) for this aggregation */ + A_UINT32 initiator; + /** size of the negotiated window */ + A_UINT32 window_size; + /** starting sequence number (only valid for initiator) */ + A_UINT32 ssn; + /** timeout field represents the time to wait for Block Ack in + * initiator case and the time to wait for BAR in responder + * case. 0 represents no timeout. */ + A_UINT32 timeout; + /* BA policy: immediate ACK (0) or delayed ACK (1) */ + A_UINT32 policy; +} wmi_peer_tid_addba_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Initiator (1) or Responder (0) for this aggregation */ + A_UINT32 initiator; +} wmi_peer_tid_delba_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Event status */ + A_UINT32 status; +} wmi_tx_addba_complete_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Event status */ + A_UINT32 status; +} wmi_tx_delba_complete_event_fixed_param; +/* + * Structure to request sequence numbers for a given + * peer station on different TIDs. The TIDs are + * indicated in the tidBitMap, tid 0 would + * be represented by LSB bit 0. tid 1 would be + * represented by LSB bit 1 etc. + * The target will retrieve the current sequence + * numbers for the peer on all the TIDs requested + * and send back a response in a WMI event. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_sub_struct_param */ + wmi_mac_addr peer_macaddr; + A_UINT32 tidBitmap; +} wmi_ba_req_ssn; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Number of requested SSN In the TLV wmi_ba_req_ssn[] */ + A_UINT32 num_ba_req_ssn; +/* Following this struc are the TLV's: + * wmi_ba_req_ssn ba_req_ssn_list; All peer and tidBitMap for which the ssn is requested + */ +} wmi_ba_req_ssn_cmd_fixed_param; + +/* + * Max transmit categories + * + * Note: In future if we need to increase WMI_MAX_TC definition + * It would break the compatibility for WMI_BA_RSP_SSN_EVENTID. + */ +#define WMI_MAX_TC 8 + +/* + * Structure to send response sequence numbers + * for a give peer and tidmap. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_event_sub_struct_param */ + wmi_mac_addr peer_macaddr; + /* A bool to indicate if ssn is present */ + A_UINT32 ssn_present_for_tid[WMI_MAX_TC]; + /* The ssn from target, valid only if + * ssn_present_for_tid[tidn] equals 1 + */ + A_UINT32 ssn_for_tid[WMI_MAX_TC]; +} wmi_ba_event_ssn; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Event status, success or failure of the overall operation */ + A_UINT32 status; + /** Number of requested SSN In the TLV wmi_ba_req_ssn[] */ + A_UINT32 num_ba_event_ssn; +/* Following this struc are the TLV's: + * wmi_ba_event_ssn ba_event_ssn_list; All peer and tidBitMap for which the ssn is requested + */ +} wmi_ba_rsp_ssn_event_fixed_param; + +enum wmi_aggr_state_req_type { + WMI_DISABLE_AGGREGATION, + WMI_ENABLE_AGGREGATION +}; + +/* + * This event is generated by the COEX module + * when esco call is begins the coex module in fw genrated this event to host to + * disable the RX aggregation and after completion of the esco call fw will indicate to + * enable back the Rx aggregation . + */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** req_type contains values from enum + * wmi_aggr_state_req_type; 0 (disable) 1(enable) */ + A_UINT32 req_type; +} wmi_aggr_state_trig_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** MAC address used for installing */ + wmi_mac_addr peer_macaddr; + /** key index */ + A_UINT32 key_ix; + /** key flags */ + A_UINT32 key_flags; + /** Event status */ + A_UINT32 status; +} wmi_vdev_install_key_complete_event_fixed_param; + +typedef enum _WMI_NLO_AUTH_ALGORITHM { + WMI_NLO_AUTH_ALGO_80211_OPEN = 1, + WMI_NLO_AUTH_ALGO_80211_SHARED_KEY = 2, + WMI_NLO_AUTH_ALGO_WPA = 3, + WMI_NLO_AUTH_ALGO_WPA_PSK = 4, + WMI_NLO_AUTH_ALGO_WPA_NONE = 5, + WMI_NLO_AUTH_ALGO_RSNA = 6, + WMI_NLO_AUTH_ALGO_RSNA_PSK = 7, +} WMI_NLO_AUTH_ALGORITHM; + +typedef enum _WMI_NLO_CIPHER_ALGORITHM { + WMI_NLO_CIPHER_ALGO_NONE = 0x00, + WMI_NLO_CIPHER_ALGO_WEP40 = 0x01, + WMI_NLO_CIPHER_ALGO_TKIP = 0x02, + WMI_NLO_CIPHER_ALGO_CCMP = 0x04, + WMI_NLO_CIPHER_ALGO_WEP104 = 0x05, + WMI_NLO_CIPHER_ALGO_BIP = 0x06, + WMI_NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, + WMI_NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + WMI_NLO_CIPHER_ALGO_WEP = 0x101, +} WMI_NLO_CIPHER_ALGORITHM; + +/* SSID broadcast type passed in NLO params */ +typedef enum _WMI_NLO_SSID_BcastNwType { + WMI_NLO_BCAST_UNKNOWN = 0, + WMI_NLO_BCAST_NORMAL = 1, + WMI_NLO_BCAST_HIDDEN = 2, +} WMI_NLO_SSID_BcastNwType; + +#define WMI_NLO_MAX_SSIDS 16 +#define WMI_NLO_MAX_CHAN 48 + +#define WMI_NLO_CONFIG_STOP (0x1 << 0) +#define WMI_NLO_CONFIG_START (0x1 << 1) +#define WMI_NLO_CONFIG_RESET (0x1 << 2) +#define WMI_NLO_CONFIG_SLOW_SCAN (0x1 << 4) +#define WMI_NLO_CONFIG_FAST_SCAN (0x1 << 5) +#define WMI_NLO_CONFIG_SSID_HIDE_EN (0x1 << 6) +/* This bit is used to indicate if EPNO or supplicant PNO is enabled. Only + * one of them can be enabled at a given time */ +#define WMI_NLO_CONFIG_ENLO (0x1 << 7) +#define WMI_NLO_CONFIG_SCAN_PASSIVE (0x1 << 8) + +/* Whether directed scan needs to be performed (for hidden SSIDs) */ +#define WMI_ENLO_FLAG_DIRECTED_SCAN 1 +/* Whether PNO event shall be triggered if the network is found on A band */ +#define WMI_ENLO_FLAG_A_BAND 2 +/* Whether PNO event shall be triggered if the network is found on G band */ +#define WMI_ENLO_FLAG_G_BAND 4 +/* Whether strict matching is required (i.e. firmware shall not match on the entire SSID) */ +#define WMI_ENLO_FLAG_STRICT_MATCH 8 +/* Code for matching the beacon AUTH IE - additional codes TBD open */ +#define WMI_ENLO_AUTH_CODE_OPEN 1 +/* WPA_PSK or WPA2PSK */ +#define WMI_ENLO_AUTH_CODE_PSK 2 +/* any EAPOL */ +#define WMI_ENLO_AUTH_CODE_EAPOL 4 + +/* NOTE: wmi_nlo_ssid_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_ssid_param { + A_UINT32 valid; + wmi_ssid ssid; +} wmi_nlo_ssid_param; + +/* NOTE: wmi_nlo_enc_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_enc_param { + A_UINT32 valid; + A_UINT32 enc_type; +} wmi_nlo_enc_param; + +/* NOTE: wmi_nlo_auth_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_auth_param { + A_UINT32 valid; + A_UINT32 auth_type; +} wmi_nlo_auth_param; + +/* NOTE: wmi_nlo_bcast_nw_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_bcast_nw_param { + A_UINT32 valid; + /** + * If WMI_NLO_CONFIG_EPNO is not set. Supplicant PNO is enabled. The value + * should be true/false.Otherwise EPNO is enabled. bcast_nw_type would be used + * as a bit flag contains WMI_ENLO_FLAG_XXX + */ + A_UINT32 bcast_nw_type; +} wmi_nlo_bcast_nw_param; + +/* NOTE: wmi_nlo_rssi_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_rssi_param { + A_UINT32 valid; + A_INT32 rssi; +} wmi_nlo_rssi_param; + +typedef struct nlo_configured_parameters { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_nlo_configured_parameters */ + wmi_nlo_ssid_param ssid; + wmi_nlo_enc_param enc_type; + wmi_nlo_auth_param auth_type; + wmi_nlo_rssi_param rssi_cond; + wmi_nlo_bcast_nw_param bcast_nw_type; /* indicates if the SSID is hidden or not */ +} nlo_configured_parameters; + +/* Support channel prediction for PNO scan after scanning top_k_num channels + * if stationary_threshold is met. + */ +typedef struct nlo_channel_prediction_cfg { + A_UINT32 tlv_header; + /* Enable or disable this feature. */ + A_UINT32 enable; + /* Top K channels will be scanned before deciding whether to further + * scan or stop. Minimum value is 3 and maximum is 5. */ + A_UINT32 top_k_num; + /* Preconfigured stationary threshold. Lesser value means more + * conservative. Bigger value means more aggressive. + * Maximum is 100 and mininum is 0. */ + A_UINT32 stationary_threshold; + /* Periodic full channel scan in milliseconds unit. + * After full_scan_period_ms since last full scan, channel prediction + * scan is suppressed and will do full scan. + * This is to help detecting sudden AP power-on or -off. + * Value 0 means no full scan at all (not recommended). + */ + A_UINT32 full_scan_period_ms; +} nlo_channel_prediction_cfg; + +typedef struct wmi_nlo_config { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param */ + A_UINT32 flags; + A_UINT32 vdev_id; + A_UINT32 fast_scan_max_cycles; + A_UINT32 active_dwell_time; + A_UINT32 passive_dwell_time; /* PDT in msecs */ + A_UINT32 probe_bundle_size; + A_UINT32 rest_time; /* ART = IRT */ + A_UINT32 max_rest_time; /* Max value that can be reached after SBM */ + A_UINT32 scan_backoff_multiplier; /* SBM */ + A_UINT32 fast_scan_period; /* SCBM */ + A_UINT32 slow_scan_period; /* specific to windows */ + A_UINT32 no_of_ssids; + A_UINT32 num_of_channels; + A_UINT32 delay_start_time; /* NLO scan start delay time in milliseconds */ + /* The TLVs will follow. + * nlo_configured_parameters nlo_list[]; + * A_UINT32 channel_list[]; + * nlo_channel_prediction_cfg ch_prediction_cfg; + */ + +} wmi_nlo_config_cmd_fixed_param; + +typedef struct wmi_nlo_event { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nlo_event */ + A_UINT32 vdev_id; +} wmi_nlo_event; + +/* WMI_PASSPOINT_CONFIG_SET + * Sets a list for passpoint networks for PNO purposes; + * it should be matched against any passpoint networks found + * during regular PNO scan. + */ +#define WMI_PASSPOINT_CONFIG_SET (0x1 << 0) +/* WMI_PASSPOINT_CONFIG_RESET + * Reset passpoint network list - + * no Passpoint networks should be matched after this. + */ +#define WMI_PASSPOINT_CONFIG_RESET (0x1 << 1) +#define PASSPOINT_REALM_LEN 256 +#define PASSPOINT_ROAMING_CONSORTIUM_ID_LEN 5 +#define PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define PASSPOINT_PLMN_ID_LEN 3 +#define PASSPOINT_PLMN_ID_ALLOC_LEN /* round up to A_UINT32 boundary */ \ + (((PASSPOINT_PLMN_ID_LEN + 3) >> 2) << 2) + +/* + * Confirm PASSPOINT_REALM_LEN is a multiple of 4, so the + * A_UINT8 realm[PASSPOINT_REALM_LEN] + * array will end on a 4-byte boundary. + * (This 4-byte alignment simplifies endianness-correction byte swapping.) + */ +A_COMPILE_TIME_ASSERT(check_passpoint_realm_size,(PASSPOINT_REALM_LEN % sizeof(A_UINT32)) == 0); + +/* + * Confirm the product of PASSPOINT_ROAMING_CONSORTIUM_ID_NUM and + * PASSPOINT_ROAMING_CONSORTIUM_ID_LEN is a multiple of 4, so the + * roaming_consortium_ids array below will end on a 4-byte boundary. + * (This 4-byte alignment simplifies endianness-correction byte swapping.) + */ +A_COMPILE_TIME_ASSERT(check_passpoint_roaming_consortium_ids_size, +((PASSPOINT_ROAMING_CONSORTIUM_ID_NUM*PASSPOINT_ROAMING_CONSORTIUM_ID_LEN) % sizeof(A_UINT32)) == 0); + +/* wildcard ID to allow an action (reset) to apply to all networks */ +#define WMI_PASSPOINT_NETWORK_ID_WILDCARD 0xFFFFFFFF +typedef struct wmi_passpoint_config { + /* TLV tag and len; tag equals wmi_passpoint_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /* (network) id + * identifier of the matched network, report this in event + * This id can be a wildcard (WMI_PASSPOINT_NETWORK_ID_WILDCARD) + * that indicates the action should be applied to all networks. + * Currently, the only action that is applied to all networks is "reset". + * If a non-wildcard ID is specified, that particular network is configured. + * If a wildcard ID is specified, all networks are reset. + */ + A_UINT32 id; + A_UINT32 req_id; + /*null terminated UTF8 encoded realm, 0 if unspecified*/ + A_UINT8 realm[PASSPOINT_REALM_LEN]; + /*roaming consortium ids to match, 0s if unspecified*/ + A_UINT8 roaming_consortium_ids[PASSPOINT_ROAMING_CONSORTIUM_ID_NUM][PASSPOINT_ROAMING_CONSORTIUM_ID_LEN]; + /*This would be bytes-stream as same as defition of realm id in 802.11 standard*/ + /*PLMN id mcc/mnc combination as per rules, 0s if unspecified */ + A_UINT8 plmn[PASSPOINT_PLMN_ID_ALLOC_LEN]; +} wmi_passpoint_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals +wmi_passpoint_event_hdr */ + A_UINT32 id; /* identifier of the matched network */ + A_UINT32 vdev_id; + A_UINT32 timestamp; /* time since boot (in microsecond) when the +result was retrieved*/ + wmi_ssid ssid; + wmi_mac_addr bssid; /* bssid of the network */ + A_UINT32 channel_mhz; /* channel frequency in MHz */ + A_UINT32 rssi; /* rssi value */ + A_UINT32 rtt; /* timestamp in nanoseconds*/ + A_UINT32 rtt_sd; /* standard deviation in rtt */ + A_UINT32 beacon_period; /* beacon advertised in the beacon */ + A_UINT32 capability; /* capabilities advertised in the beacon */ + A_UINT32 ie_length; /* size of the ie_data blob */ + A_UINT32 anqp_length; /* length of ANQP blob */ + /** + * Following this structure is the byte stream of ie data of length ie_buf_len: + * A_UINT8 ie_data[]; // length in byte given by field ie_length, blob of ie data in beacon + * A_UINT8 anqp_ie[]; // length in byte given by field anqp_len, blob of anqp data of IE + * Implicitly, combing ie_data and anqp_ie into a single bufp, and the bytes + * stream of each ie should be same as BEACON/Action-frm by 802.11 spec + */ +} wmi_passpoint_event_hdr; + +#define GTK_OFFLOAD_OPCODE_MASK 0xFF000000 +/** Enable GTK offload, and provided parameters KEK,KCK and replay counter values */ +#define GTK_OFFLOAD_ENABLE_OPCODE 0x01000000 +/** Disable GTK offload */ +#define GTK_OFFLOAD_DISABLE_OPCODE 0x02000000 +/** Read GTK offload parameters, generates WMI_GTK_OFFLOAD_STATUS_EVENT */ +#define GTK_OFFLOAD_REQUEST_STATUS_OPCODE 0x04000000 +enum wmi_chatter_mode { + /* Chatter enter/exit happens + * automatically based on preset + * params + */ + WMI_CHATTER_MODE_AUTO, + /* Chatter enter is triggered + * manually by the user + */ + WMI_CHATTER_MODE_MANUAL_ENTER, + /* Chatter exit is triggered + * manually by the user + */ + WMI_CHATTER_MODE_MANUAL_EXIT, + /* Placeholder max value, always last */ + WMI_CHATTER_MODE_MAX +}; + +enum wmi_chatter_query_type { + /*query coalescing filter match counter */ + WMI_CHATTER_QUERY_FILTER_MATCH_CNT, + WMI_CHATTER_QUERY_MAX +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param */ + A_UINT32 chatter_mode; +} wmi_chatter_set_mode_cmd_fixed_param; + +/** maximum number of filter supported*/ +#define CHATTER_MAX_COALESCING_RULES 11 +/** maximum number of field tests per filter*/ +#define CHATTER_MAX_FIELD_TEST 5 +/** maximum field length in number of DWORDS*/ +#define CHATTER_MAX_TEST_FIELD_LEN32 2 + +/** field test kinds*/ +#define CHATTER_COALESCING_TEST_EQUAL 1 +#define CHATTER_COALESCING_TEST_MASKED_EQUAL 2 +#define CHATTER_COALESCING_TEST_NOT_EQUAL 3 + +/** packet type*/ +#define CHATTER_COALESCING_PKT_TYPE_UNICAST (1 << 0) +#define CHATTER_COALESCING_PKT_TYPE_MULTICAST (1 << 1) +#define CHATTER_COALESCING_PKT_TYPE_BROADCAST (1 << 2) + +/** coalescing field test*/ +typedef struct _chatter_pkt_coalescing_hdr_test { + /** offset from start of mac header, for windows native wifi host driver + * should assume standard 802.11 frame format without QoS info and address4 + * FW would account for any non-stand fields for final offset value. + */ + A_UINT32 offset; + A_UINT32 length; /* length of test field */ + A_UINT32 test; /*equal, not equal or masked equal */ + A_UINT32 mask[CHATTER_MAX_TEST_FIELD_LEN32]; /*mask byte stream */ + A_UINT32 value[CHATTER_MAX_TEST_FIELD_LEN32]; /*value byte stream */ +} chatter_pkt_coalescing_hdr_test; + +/** packet coalescing filter*/ +typedef struct _chatter_pkt_coalescing_filter { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_pkt_coalescing_filter */ + A_UINT32 filter_id; /*unique id assigned by OS */ + A_UINT32 max_coalescing_delay; /*max miliseconds 1st pkt can be hold */ + A_UINT32 pkt_type; /*unicast/multicast/broadcast */ + A_UINT32 num_of_test_field; /*number of field test in table */ + chatter_pkt_coalescing_hdr_test test_fields[CHATTER_MAX_FIELD_TEST]; /*field test tbl */ +} chatter_pkt_coalescing_filter; + +/** packet coalescing filter add command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param */ + A_UINT32 num_of_filters; + /* Following this tlv, there comes an array of structure of type chatter_pkt_coalescing_filter + chatter_pkt_coalescing_filter rx_filter[1]; */ +} wmi_chatter_coalescing_add_filter_cmd_fixed_param; +/** packet coalescing filter delete command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param */ + A_UINT32 filter_id; /*filter id which will be deleted */ +} wmi_chatter_coalescing_delete_filter_cmd_fixed_param; +/** packet coalescing query command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param */ + A_UINT32 type; /*type of query */ +} wmi_chatter_coalescing_query_cmd_fixed_param; +/** chatter query reply event*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param */ + A_UINT32 type; /*query type */ + A_UINT32 filter_match_cnt; /*coalescing filter match counter */ +} wmi_chatter_query_reply_event_fixed_param; + +/* NOTE: This constants GTK_OFFLOAD_KEK_BYTES, GTK_OFFLOAD_KCK_BYTES, and GTK_REPLAY_COUNTER_BYTES + * cannot be changed without breaking WMI compatibility. */ +#define GTK_OFFLOAD_KEK_BYTES 16 +#define GTK_OFFLOAD_KCK_BYTES 16 +/* NOTE: GTK_REPLAY_COUNTER_BYTES, WMI_MAX_KEY_LEN, IGTK_PN_SIZE cannot be changed in the future without breaking WMI compatibility */ +#define GTK_REPLAY_COUNTER_BYTES 8 +#define WMI_MAX_KEY_LEN 32 +#define IGTK_PN_SIZE 6 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param */ + A_UINT32 vdev_id; + /** unique id identifying the VDEV */ + A_UINT32 flags; /* status flags */ + A_UINT32 refresh_cnt; /* number of successful GTK refresh exchanges since last SET operation */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; /* current replay counter */ + A_UINT8 igtk_keyIndex; /* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_keyLength; /* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_keyRSC[IGTK_PN_SIZE]; /* key replay sequence counter *//* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_key[WMI_MAX_KEY_LEN]; /* Use if IGTK_OFFLOAD is defined */ +} WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param */ + A_UINT32 vdev_id; /** unique id identifying the VDEV */ + A_UINT32 flags; /* control flags, GTK offload command use high byte */ + /* The size of following 3 arrays cannot be changed without breaking WMI compatibility. */ + A_UINT8 KEK[GTK_OFFLOAD_KEK_BYTES]; /* key encryption key */ + A_UINT8 KCK[GTK_OFFLOAD_KCK_BYTES]; /* key confirmation key */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; /* replay counter for re-key */ +} WMI_GTK_OFFLOAD_CMD_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 sa_query_retry_interval; /* in msec */ + A_UINT32 sa_query_max_retry_count; +} WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param; + +typedef enum { + WMI_STA_KEEPALIVE_METHOD_NULL_FRAME = 1, /* 802.11 NULL frame */ + WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE = 2, /* ARP response */ + WMI_STA_KEEPALIVE_METHOD_ETHERNET_LOOPBACK = 3, /*ETHERNET LOOPBACK */ + /* gratuitous ARP req*/ + WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST = 4, +} WMI_STA_KEEPALIVE_METHOD; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE */ + WMI_IPV4_ADDR sender_prot_addr; /* Sender protocol address */ + WMI_IPV4_ADDR target_prot_addr; /* Target protocol address */ + wmi_mac_addr dest_mac_addr; /* destination MAC address */ +} WMI_STA_KEEPALVE_ARP_RESPONSE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; /* 1 - Enable, 0 - disable */ + A_UINT32 method; /* keep alive method */ + A_UINT32 interval; /* time interval in seconds */ + /* + * NOTE: following this structure is the TLV for ARP Resonse: + * WMI_STA_KEEPALVE_ARP_RESPONSE arp_resp; // ARP response + */ +} WMI_STA_KEEPALIVE_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 action; +} WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param; +typedef WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param WMI_STA_WNMSLEEP_CMD; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 keepaliveInterval; /* seconds */ + A_UINT32 keepaliveMethod; +} wmi_vdev_set_keepalive_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_vdev_get_keepalive_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 keepaliveInterval; /* seconds */ + A_UINT32 keepaliveMethod; /* seconds */ +} wmi_vdev_get_keepalive_event_fixed_param; + +#define IPSEC_NATKEEPALIVE_FILTER_DISABLE 0 +#define IPSEC_NATKEEPALIVE_FILTER_ENABLE 1 + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 action; +} WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param; + +typedef WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param +WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 mcc_tbttmode; + wmi_mac_addr mcc_bssid; +} wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* home vdev id */ + A_UINT32 meas_token; /* from measure request frame */ + A_UINT32 dialog_token; + A_UINT32 number_bursts; /* zero keep sending until cancel, bigger than 0 means times e.g. 1,2 */ + A_UINT32 burst_interval; /* unit in mill seconds, interval between consecutive burst */ + A_UINT32 burst_cycle; /* times cycle through within one burst */ + A_UINT32 tx_power; /* for path frame */ + A_UINT32 off_duration; /* uint in mill seconds, channel off duraiton for path loss frame sending */ + wmi_mac_addr dest_mac; /* multicast DA, for path loss frame */ + A_UINT32 num_chans; +} wmi_vdev_plmreq_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 meas_token; /* same value from req */ +} wmi_vdev_plmreq_stop_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* enable/disable NoA */ + A_UINT32 enable; + /** number of NoA desc. In the TLV noa_descriptor[] */ + A_UINT32 num_noa; + /** + * TLV (tag length value ) paramerters follow the pattern structure. + * TLV contain NoA desc with num of num_noa + */ +} wmi_p2p_set_noa_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* Identify the wlan module */ + A_UINT32 module_id; + /* Num of test arguments passed */ + A_UINT32 num_args; +/** + * TLV (tag length value ) parameters follow the wmi_roam_chan_list + * structure. The TLV's are: + * A_UINT32 args[]; + **/ +} wmi_unit_test_cmd_fixed_param; + +/** Roaming offload SYNCH_COMPLETE from host when host finished sync logic + * after it received WMI_ROAM_SYNCH_EVENTID. + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_roam_synch_complete_fixed_param; + +typedef enum { + RECOVERY_SIM_ASSERT = 0x01, + RECOVERY_SIM_NO_DETECT = 0x02, + RECOVERY_SIM_CTR_EP_FULL = 0x03, + RECOVERY_SIM_EMPTY_POINT = 0x04, + RECOVERY_SIM_STACK_OV = 0x05, + RECOVERY_SIM_INFINITE_LOOP = 0x06, + RECOVERY_SIM_PCIE_LINKDOWN = 0x07, + RECOVERY_SIM_SELF_RECOVERY = 0x08, +} RECOVERY_SIM_TYPE; + +/* WMI_FORCE_FW_HANG_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param */ + A_UINT32 type; /*0:unused 1: ASSERT, 2: not respond detect command,3: simulate ep-full(),4:... */ + A_UINT32 delay_time_ms; /*0xffffffff means the simulate will delay for random time (0 ~0xffffffff ms) */ +} WMI_FORCE_FW_HANG_CMD_fixed_param; +#define WMI_MCAST_FILTER_SET 1 +#define WMI_MCAST_FILTER_DELETE 2 +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 index; + A_UINT32 action; + wmi_mac_addr mcastbdcastaddr; +} WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param; + +/* GPIO Command and Event data structures */ + +/* WMI_GPIO_CONFIG_CMDID */ +enum { + WMI_GPIO_PULL_NONE, + WMI_GPIO_PULL_UP, + WMI_GPIO_PULL_DOWN, +}; + +enum { + WMI_GPIO_INTTYPE_DISABLE, + WMI_GPIO_INTTYPE_RISING_EDGE, + WMI_GPIO_INTTYPE_FALLING_EDGE, + WMI_GPIO_INTTYPE_BOTH_EDGE, + WMI_GPIO_INTTYPE_LEVEL_LOW, + WMI_GPIO_INTTYPE_LEVEL_HIGH +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param */ + A_UINT32 gpio_num; /* GPIO number to be setup */ + A_UINT32 input; /* 0 - Output/ 1 - Input */ + A_UINT32 pull_type; /* Pull type defined above */ + A_UINT32 intr_mode; /* Interrupt mode defined above (Input) */ +} wmi_gpio_config_cmd_fixed_param; + +/* WMI_GPIO_OUTPUT_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param */ + A_UINT32 gpio_num; /* GPIO number to be setup */ + A_UINT32 set; /* Set the GPIO pin */ +} wmi_gpio_output_cmd_fixed_param; + +/* WMI_GPIO_INPUT_EVENTID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param */ + A_UINT32 gpio_num; /* GPIO number which changed state */ +} wmi_gpio_input_event_fixed_param; + +/* WMI_P2P_DISC_EVENTID */ +enum { + P2P_DISC_SEARCH_PROB_REQ_HIT = 0, /* prob req hit the p2p find pattern */ + P2P_DISC_SEARCH_PROB_RESP_HIT, /* prob resp hit the p2p find pattern */ +}; + +enum { + P2P_DISC_MODE_SEARCH = 0, /* do search when p2p find offload */ + P2P_DISC_MODE_LISTEN, /* do listen when p2p find offload */ + P2P_DISC_MODE_AUTO, /* do listen and search when p2p find offload */ +}; + +enum { + P2P_DISC_PATTERN_TYPE_BSSID = 0, /* BSSID pattern */ + P2P_DISC_PATTERN_TYPE_DEV_NAME, /* device name pattern */ +}; + +typedef struct { + A_UINT32 vdev_id; + A_UINT32 reason; /* P2P DISC wake up reason */ +} wmi_p2p_disc_event; + +typedef WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param +WOW_EVENT_INFO_SECTION_GTKIGTK; + +typedef enum { + WMI_FAKE_TXBFER_SEND_NDPA, + WMI_FAKE_TXBFER_SEND_MU, + WMI_FAKE_TXBFER_NDPA_FBTYPE, + WMI_FAKE_TXBFER_NDPA_NCIDX, + WMI_FAKE_TXBFER_NDPA_POLL, + WMI_FAKE_TXBFER_NDPA_BW, + WMI_FAKE_TXBFER_NDPA_PREAMBLE, + WMI_FAKE_TXBFER_NDPA_RATE, + WMI_FAKE_TXBFER_NDP_BW, + WMI_FAKE_TXBFER_NDP_NSS, + WMI_TXBFEE_ENABLE_UPLOAD_H, + WMI_TXBFEE_ENABLE_CAPTURE_H, + WMI_TXBFEE_SET_CBF_TBL, + WMI_TXBFEE_CBF_TBL_LSIG, + WMI_TXBFEE_CBF_TBL_SIGA1, + WMI_TXBFEE_CBF_TBL_SIGA2, + WMI_TXBFEE_CBF_TBL_SIGB, + WMI_TXBFEE_CBF_TBL_PAD, + WMI_TXBFEE_CBF_TBL_DUR, + WMI_TXBFEE_SU_NCIDX, + WMI_TXBFEE_CBIDX, + WMI_TXBFEE_NGIDX, +} WMI_TXBF_PARAM_ID; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param */ + /** parameter id */ + A_UINT32 param_id; + /** parameter value */ + A_UINT32 param_value; +} wmi_txbf_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_upload_h_hdr */ + A_UINT32 h_length; + A_UINT32 cv_length; + /* This TLV is followed by array of bytes: + * // h_cv info buffer + * A_UINT8 bufp[]; + */ +} wmi_upload_h_hdr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_capture_h_event_hdr */ + A_UINT32 svd_num; + A_UINT32 tone_num; + A_UINT32 reserved; +} wmi_capture_h_event_hdr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_avoid_freq_range_desc */ + A_UINT32 start_freq; /* start frequency, not channel center freq */ + A_UINT32 end_freq; /* end frequency */ +} wmi_avoid_freq_range_desc; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param */ + /* bad channel range count, multi range is allowed, 0 means all channel clear */ + A_UINT32 num_freq_ranges; + + /* The TLVs will follow. + * multi range with num_freq_ranges, LTE advance multi carrier, CDMA,etc + * wmi_avoid_freq_range_desc avd_freq_range[]; // message buffer, NULL terminated + */ +} wmi_avoid_freq_ranges_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; + A_UINT32 vdev_id; +} wmi_gtk_rekey_fail_event_fixed_param; + +enum wmm_ac_downgrade_policy { + WMM_AC_DOWNGRADE_DEPRIO, + WMM_AC_DOWNGRADE_DROP, + WMM_AC_DOWNGRADE_INVALID, +}; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 cwmin; + A_UINT32 cwmax; + A_UINT32 aifs; + A_UINT32 txoplimit; + A_UINT32 acm; + A_UINT32 no_ack; +} wmi_wmm_vparams; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + wmi_wmm_vparams wmm_params[4]; /* 0 be, 1 bk, 2 vi, 3 vo */ +} wmi_vdev_set_wmm_params_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 gtxRTMask[2]; /* for HT and VHT rate masks */ + A_UINT32 userGtxMask; /* host request for GTX mask */ + A_UINT32 gtxPERThreshold; /* default: 10% */ + A_UINT32 gtxPERMargin; /* default: 2% */ + A_UINT32 gtxTPCstep; /* default: 1 */ + A_UINT32 gtxTPCMin; /* default: 5 */ + A_UINT32 gtxBWMask; /* 20/40/80/160 Mhz */ +} wmi_vdev_set_gtx_params_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ac; + A_UINT32 medium_time_us; /* per second unit, the Admitted time granted, unit in micro seconds */ + A_UINT32 downgrade_type; +} wmi_vdev_wmm_addts_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ac; +} wmi_vdev_wmm_delts_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_pdev_dfs_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_pdev_dfs_disable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param + */ + A_UINT32 tlv_header; + + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_dfs_phyerr_filter_ena_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param + */ + A_UINT32 tlv_header; + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_dfs_phyerr_filter_dis_cmd_fixed_param; + +/** TDLS COMMANDS */ + +/* WMI_TDLS_SET_STATE_CMDID */ +/* TDLS State */ +enum wmi_tdls_state { + /** TDLS disable */ + WMI_TDLS_DISABLE, + /** TDLS enabled - no firmware connection tracking/notifications */ + WMI_TDLS_ENABLE_PASSIVE, + /** TDLS enabled - with firmware connection tracking/notifications */ + WMI_TDLS_ENABLE_ACTIVE, + /* TDLS enabled - firmware waits for peer mac for connection tracking */ + WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL, +}; + +/* TDLS Options */ +#define WMI_TDLS_OFFCHAN_EN (1 << 0) /** TDLS Off Channel support */ +#define WMI_TDLS_BUFFER_STA_EN (1 << 1) /** TDLS Buffer STA support */ +#define WMI_TDLS_SLEEP_STA_EN (1 << 2) /** TDLS Sleep STA support (not currently supported) */ + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Enable/Disable TDLS (wmi_tdls_state) */ + A_UINT32 state; + /* Duration (in ms) over which to calculate tx/rx threshold + * to trigger TDLS Discovery + */ + A_UINT32 notification_interval_ms; + /** number of packets OVER which notify/suggest TDLS Discovery: + * if current tx pps counter / notification interval >= threshold + * then a notification will be sent to host to advise TDLS Discovery */ + A_UINT32 tx_discovery_threshold; + /** number of packets UNDER which notify/suggest TDLS Teardown: + * if current tx pps counter / notification interval < threshold + * then a notification will be sent to host to advise TDLS Tear down */ + A_UINT32 tx_teardown_threshold; + /** Absolute RSSI value under which notify/suggest TDLS Teardown */ + A_INT32 rssi_teardown_threshold; + /** Peer RSSI < (AP RSSI + delta) will trigger a teardown */ + A_INT32 rssi_delta; + /** TDLS Option Control + * Off-Channel, Buffer STA, (later)Sleep STA support */ + A_UINT32 tdls_options; + /* Buffering time in number of beacon intervals */ + A_UINT32 tdls_peer_traffic_ind_window; + /* Wait time for PTR frame */ + A_UINT32 tdls_peer_traffic_response_timeout_ms; + /* Self PUAPSD mask */ + A_UINT32 tdls_puapsd_mask; + /* Inactivity timeout */ + A_UINT32 tdls_puapsd_inactivity_time_ms; + /* Max of rx frame during SP */ + A_UINT32 tdls_puapsd_rx_frame_threshold; + /* Duration (in ms) over which to check whether TDLS link + * needs to be torn down + */ + A_UINT32 teardown_notification_ms; + /* STA kickout threshold for TDLS peer */ + A_UINT32 tdls_peer_kickout_threshold; +} wmi_tdls_set_state_cmd_fixed_param; + +/* WMI_TDLS_PEER_UPDATE_CMDID */ + +enum wmi_tdls_peer_state { + /** tx peer TDLS link setup now starting, traffic to DA should be + * paused (except TDLS frames) until state is moved to CONNECTED (or + * TEARDOWN on setup failure) */ + WMI_TDLS_PEER_STATE_PEERING, + /** tx peer TDLS link established, running (all traffic to DA unpaused) */ + WMI_TDLS_PEER_STATE_CONNECTED, + /** tx peer TDLS link tear down started (link paused, any frames + * queued for DA will be requeued back through the AP)*/ + WMI_TDLS_PEER_STATE_TEARDOWN, + /* Add peer mac into connection table */ + WMI_TDLS_PEER_ADD_MAC_ADDR, + /* Remove peer mac from connection table */ + WMI_TDLS_PEER_REMOVE_MAC_ADDR, +}; + +/* NB: These defines are fixed, and cannot be changed without breaking WMI compatibility */ +#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32 +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities */ + A_UINT32 tlv_header; + /* Peer's QoS Info - for U-APSD */ + /* AC FLAGS - accessed through macros below */ + /* Ack, SP, More Data Ack - accessed through macros below */ + A_UINT32 peer_qos; + /*TDLS Peer's U-APSD Buffer STA Support */ + A_UINT32 buff_sta_support; + /*TDLS off channel related params */ + A_UINT32 off_chan_support; + A_UINT32 peer_curr_operclass; + A_UINT32 self_curr_operclass; + /* Number of channels available for off channel operation */ + A_UINT32 peer_chan_len; + A_UINT32 peer_operclass_len; + A_UINT8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES]; + /* Is peer initiator or responder of TDLS setup request */ + A_UINT32 is_peer_responder; + /* Preferred off channel number as configured by user */ + A_UINT32 pref_offchan_num; + /* Preferred off channel bandwidth as configured by user */ + A_UINT32 pref_offchan_bw; + + /** Followed by the variable length TLV peer_chan_list: + * wmi_channel peer_chan_list[]. + * Array size would be peer_chan_len. + * This array is intersected channels which is supported by both peer + * and DUT. freq1 in chan_info shall be same as mhz, freq2 shall be 0. + * FW shall compute BW for an offchan based on peer's ht/vht cap + * received in peer_assoc cmd during change STA operation + */ +} wmi_tdls_peer_capabilities; + +#define WMI_TDLS_QOS_VO_FLAG 0 +#define WMI_TDLS_QOS_VI_FLAG 1 +#define WMI_TDLS_QOS_BK_FLAG 2 +#define WMI_TDLS_QOS_BE_FLAG 3 +#define WMI_TDLS_QOS_ACK_FLAG 4 +#define WMI_TDLS_QOS_SP_FLAG 5 +#define WMI_TDLS_QOS_MOREDATA_FLAG 7 + +#define WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps,flag) do { \ + (ppeer_caps)->peer_qos |= (1 << flag); \ +} while(0) +#define WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps,flag) \ + (((ppeer_caps)->peer_qos & (1 << flag)) >> flag) + +#define WMI_SET_TDLS_PEER_VO_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VO_FLAG) +#define WMI_GET_TDLS_PEER_VO_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VO_FLAG) +#define WMI_SET_TDLS_PEER_VI_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VI_FLAG) +#define WMI_GET_TDLS_PEER_VI_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VI_FLAG) +#define WMI_SET_TDLS_PEER_BK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BK_FLAG) +#define WMI_GET_TDLS_PEER_BK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BK_FLAG) +#define WMI_SET_TDLS_PEER_BE_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BE_FLAG) +#define WMI_GET_TDLS_PEER_BE_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BE_FLAG) +#define WMI_SET_TDLS_PEER_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_ACK_FLAG) +#define WMI_GET_TDLS_PEER_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_ACK_FLAG) +/* SP has 2 bits */ +#define WMI_SET_TDLS_PEER_SP_UAPSD(ppeer_caps,val) do { \ + (ppeer_caps)->peer_qos |= (((val)&0x3) << WMI_TDLS_QOS_SP_FLAG); \ +} while(0) +#define WMI_GET_TDLS_PEER_SP_UAPSD(ppeer_caps) \ + (((ppeer_caps)->peer_qos & (0x3 << WMI_TDLS_QOS_SP_FLAG)) >> WMI_TDLS_QOS_SP_FLAG) + +#define WMI_SET_TDLS_PEER_MORE_DATA_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_MOREDATA_FLAG) +#define WMI_GET_TDLS_PEER_MORE_DATA_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_MOREDATA_FLAG) + +#define WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd,flag) do { \ + (pset_cmd)->tdls_puapsd_mask |= (1 << flag); \ +} while(0) +#define WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd,flag) \ + (((pset_cmd)->tdls_puapsd_mask & (1 << flag)) >> flag) + +#define WMI_SET_TDLS_SELF_VO_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VO_FLAG) +#define WMI_GET_TDLS_SELF_VO_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VO_FLAG) +#define WMI_SET_TDLS_SELF_VI_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VI_FLAG) +#define WMI_GET_TDLS_SELF_VI_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VI_FLAG) +#define WMI_SET_TDLS_SELF_BK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BK_FLAG) +#define WMI_GET_TDLS_SELF__BK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BK_FLAG) +#define WMI_SET_TDLS_SELF_BE_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BE_FLAG) +#define WMI_GET_TDLS_SELF_BE_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BE_FLAG) +#define WMI_SET_TDLS_SELF_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_ACK_FLAG) +#define WMI_GET_TDLS_SELF_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_ACK_FLAG) +/* SP has 2 bits */ +#define WMI_SET_TDLS_SELF_SP_UAPSD(pset_cmd,val) do { \ + (pset_cmd)->tdls_puapsd_mask |= (((val)&0x3) << WMI_TDLS_QOS_SP_FLAG); \ +} while(0) +#define WMI_GET_TDLS_SELF_SP_UAPSD(pset_cmd) \ + (((pset_cmd)->tdls_puapsd_mask & (0x3 << WMI_TDLS_QOS_SP_FLAG)) >> WMI_TDLS_QOS_SP_FLAG) + +#define WMI_SET_TDLS_SELF_MORE_DATA_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_MOREDATA_FLAG) +#define WMI_GET_TDLS_SELF_MORE_DATA_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_MOREDATA_FLAG) + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** new TDLS state for peer (wmi_tdls_peer_state) */ + A_UINT32 peer_state; + /* The TLV for wmi_tdls_peer_capabilities will follow. + * wmi_tdls_peer_capabilities peer_caps; + */ + /** Followed by the variable length TLV chan_info: + * wmi_channel chan_info[] */ +} wmi_tdls_peer_update_cmd_fixed_param; + +/* WMI_TDLS_SET_OFFCHAN_MODE_CMDID */ + +/* bitmap 20, 40, 80 or 160 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_20MHZ 0x1 /* 20 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_40MHZ 0x2 /* 40 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_80MHZ 0x4 /* 80 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_160MHZ 0x8 /* 160 MHz wide channel */ + +enum wmi_tdls_offchan_mode { + WMI_TDLS_ENABLE_OFFCHANNEL, + WMI_TDLS_DISABLE_OFFCHANNEL +}; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Enable/Disable TDLS offchannel */ + A_UINT32 offchan_mode; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* Is peer initiator or responder of TDLS setup request */ + A_UINT32 is_peer_responder; + /* off channel number */ + A_UINT32 offchan_num; + /* off channel bandwidth bitmap, e.g. WMI_OFFCHAN_20MHZ */ + A_UINT32 offchan_bw_bitmap; + /* operating class for offchan */ + A_UINT32 offchan_oper_class; +} wmi_tdls_set_offchan_mode_cmd_fixed_param; + +/** TDLS EVENTS */ +enum wmi_tdls_peer_notification { + /** tdls discovery recommended for peer (based + * on tx bytes per second > tx_discover threshold) */ + WMI_TDLS_SHOULD_DISCOVER, + /** tdls link tear down recommended for peer + * due to tx bytes per second below tx_teardown_threshold + * NB: this notification sent once */ + WMI_TDLS_SHOULD_TEARDOWN, + /** tx peer TDLS link tear down complete */ + WMI_TDLS_PEER_DISCONNECTED, +}; + +enum wmi_tdls_peer_reason { + /** tdls teardown recommended due to low transmits */ + WMI_TDLS_TEARDOWN_REASON_TX, + /** tdls link tear down recommended due to poor RSSI */ + WMI_TDLS_TEARDOWN_REASON_RSSI, + /** tdls link tear down recommended due to offchannel scan */ + WMI_TDLS_TEARDOWN_REASON_SCAN, + /** tdls peer disconnected due to peer deletion */ + WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + /** tdls peer disconnected due to PTR timeout */ + WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + /** tdls peer disconnected due wrong PTR format */ + WMI_TDLS_TEARDOWN_REASON_BAD_PTR, + /** tdls peer not responding */ + WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE, +}; + +/* WMI_TDLS_PEER_EVENTID */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param */ + A_UINT32 tlv_header; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** TDLS peer status (wmi_tdls_peer_notification)*/ + A_UINT32 peer_status; + /** TDLS peer reason (wmi_tdls_peer_reason) */ + A_UINT32 peer_reason; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_tdls_peer_event_fixed_param; + +/* NOTE: wmi_vdev_mcc_bcn_intvl_change_event_fixed_param would be deprecated. Please + don't use this for any new implementations */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* New beacon interval to be used for the specified VDEV suggested by firmware */ + A_UINT32 new_bcn_intvl; +} wmi_vdev_mcc_bcn_intvl_change_event_fixed_param; + +/* WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param */ + A_UINT32 tlv_header; + /** 1: enable fw based adaptive ocs, + * 0: disable fw based adaptive ocs + */ + A_UINT32 enable; + /** This field contains the MAC identifier in order to lookup the appropriate OCS instance. */ + /** The valid range is 0 to (num_macs-1). */ + A_UINT32 mac_id; +} wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param; + +/* WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID */ +typedef struct { + /* Frequency of the channel for which the quota is set */ + A_UINT32 chan_mhz; + /* Requested channel time quota expressed as percentage */ + A_UINT32 channel_time_quota; +} wmi_resmgr_chan_time_quota; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param */ + A_UINT32 tlv_header; + /** number of channel time quota command structures + * (wmi_resmgr_chan_time_quota) 1 or 2 + */ + A_UINT32 num_chans; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_chans * size of(struct wmi_resmgr_chan_time_quota) + */ +} wmi_resmgr_set_chan_time_quota_cmd_fixed_param; + +/* WMI_RESMGR_SET_CHAN_LATENCY_CMDID */ +typedef struct { + /* Frequency of the channel for which the latency is set */ + A_UINT32 chan_mhz; + /* Requested channel latency in milliseconds */ + A_UINT32 latency; +} wmi_resmgr_chan_latency; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param */ + A_UINT32 tlv_header; + /** number of channel latency command structures + * (wmi_resmgr_chan_latency) 1 or 2 + */ + A_UINT32 num_chans; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_chans * size of(struct wmi_resmgr_chan_latency) + */ +} wmi_resmgr_set_chan_latency_cmd_fixed_param; + +/* WMI_STA_SMPS_FORCE_MODE_CMDID */ + +/** STA SMPS Forced Mode */ +typedef enum { + WMI_SMPS_FORCED_MODE_NONE = 0, + WMI_SMPS_FORCED_MODE_DISABLED, + WMI_SMPS_FORCED_MODE_STATIC, + WMI_SMPS_FORCED_MODE_DYNAMIC +} wmi_sta_smps_forced_mode; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** The mode of SMPS that is to be forced in the FW. */ + A_UINT32 forced_mode; +} wmi_sta_smps_force_mode_cmd_fixed_param; + +/** wlan HB commands */ +#define WMI_WLAN_HB_ITEM_UDP 0x1 +#define WMI_WLAN_HB_ITEM_TCP 0x2 +#define WMI_WLAN_HB_MAX_FILTER_SIZE 32 /* should be equal to WLAN_HB_MAX_FILTER_SIZE, must be a multiple of 4 bytes */ + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; + A_UINT32 item; + A_UINT32 session; +} wmi_hb_set_enable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 srv_ip; + A_UINT32 dev_ip; + A_UINT32 seq; + A_UINT32 src_port; + A_UINT32 dst_port; + A_UINT32 interval; + A_UINT32 timeout; + A_UINT32 session; + wmi_mac_addr gateway_mac; +} wmi_hb_set_tcp_params_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 length; + A_UINT32 offset; + A_UINT32 session; + A_UINT8 filter[WMI_WLAN_HB_MAX_FILTER_SIZE]; +} wmi_hb_set_tcp_pkt_filter_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 srv_ip; + A_UINT32 dev_ip; + A_UINT32 src_port; + A_UINT32 dst_port; + A_UINT32 interval; + A_UINT32 timeout; + A_UINT32 session; + wmi_mac_addr gateway_mac; +} wmi_hb_set_udp_params_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 length; + A_UINT32 offset; + A_UINT32 session; + A_UINT8 filter[WMI_WLAN_HB_MAX_FILTER_SIZE]; +} wmi_hb_set_udp_pkt_filter_cmd_fixed_param; + +/** wlan HB events */ +typedef enum { + WMI_WLAN_HB_REASON_UNKNOWN = 0, + WMI_WLAN_HB_REASON_TCP_TIMEOUT = 1, + WMI_WLAN_HB_REASON_UDP_TIMEOUT = 2, +} WMI_HB_WAKEUP_REASON; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_hb_ind_event_fixed_param */ + A_UINT32 vdev_id; /* unique id identifying the VDEV */ + A_UINT32 session; /* Session ID from driver */ + A_UINT32 reason; /* wakeup reason */ +} wmi_hb_ind_event_fixed_param; + +/** WMI_STA_SMPS_PARAM_CMDID */ +typedef enum { + /** RSSI threshold to enter Dynamic SMPS mode from inactive mode */ + WMI_STA_SMPS_PARAM_UPPER_RSSI_THRESH = 0, + /** RSSI threshold to enter Stalled-D-SMPS mode from D-SMPS mode or + * to enter D-SMPS mode from Stalled-D-SMPS mode */ + WMI_STA_SMPS_PARAM_STALL_RSSI_THRESH = 1, + /** RSSI threshold to disable SMPS modes */ + WMI_STA_SMPS_PARAM_LOWER_RSSI_THRESH = 2, + /** Upper threshold for beacon-RSSI. Used to reduce RX chainmask. */ + WMI_STA_SMPS_PARAM_UPPER_BRSSI_THRESH = 3, + /** Lower threshold for beacon-RSSI. Used to increase RX chainmask. */ + WMI_STA_SMPS_PARAM_LOWER_BRSSI_THRESH = 4, + /** Enable/Disable DTIM 1chRx feature */ + WMI_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5 +} wmi_sta_smps_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** SMPS parameter (see wmi_sta_smps_param) */ + A_UINT32 param; + /** Value of SMPS parameter */ + A_UINT32 value; +} wmi_sta_smps_param_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mcc_sched_sta_traffic_stats */ + A_UINT32 tlv_header; + /* TX stats */ + A_UINT32 txBytesPushed; + A_UINT32 txPacketsPushed; + /* RX stats */ + A_UINT32 rxBytesRcvd; + A_UINT32 rxPacketsRcvd; + A_UINT32 rxTimeTotal; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_mcc_sched_sta_traffic_stats; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Duration over which the host stats were collected */ + A_UINT32 duration; + /** Number of stations filled in following stats array */ + A_UINT32 num_sta; + /* Following this struct are the TLVs: + * wmi_mcc_sched_sta_traffic_stats mcc_sched_sta_traffic_stats_list; + */ +} wmi_mcc_sched_traffic_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param */ + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /*Batch scan enable command parameters */ + A_UINT32 scanInterval; + A_UINT32 numScan2Batch; + A_UINT32 bestNetworks; + A_UINT32 rfBand; + A_UINT32 rtt; +} wmi_batch_scan_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param */ + A_UINT32 supportedMscan; +} wmi_batch_scan_enabled_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param */ +/* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + A_UINT32 param; +} wmi_batch_scan_disable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + A_UINT32 param; +} wmi_batch_scan_trigger_result_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + wmi_mac_addr bssid; /* BSSID */ + wmi_ssid ssid; /* SSID */ + A_UINT32 ch; /* Channel */ + A_UINT32 rssi; /* RSSI or Level */ + /* Timestamp when Network was found. Used to calculate age based on timestamp in GET_RSP msg header */ + A_UINT32 timestamp; +} wmi_batch_scan_result_network_info; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 scanId; /* Scan List ID. */ + /* No of AP in a Scan Result. Should be same as bestNetwork in SET_REQ msg */ + A_UINT32 numNetworksInScanList; + A_UINT32 netWorkStartIndex; /* indicate the start index of network info */ +} wmi_batch_scan_result_scan_list; + +#define LPI_IE_BITMAP_BSSID 0x00000001 /* if this bit is set, bssid of the scan response frame is sent as the first IE in the data buffer sent to LOWI LP.*/ +#define LPI_IE_BITMAP_IS_PROBE 0x00000002 /*send true or false based on scan response frame being a Probe Rsp or not*/ +#define LPI_IE_BITMAP_SSID 0x00000004 /*send ssid from received scan response frame*/ +#define LPI_IE_BITMAP_RSSI 0x00000008 /* end RSSI value reported by HW for the received scan response after adjusting with noise floor*/ +#define LPI_IE_BITMAP_CHAN 0x00000010 /*send channel number from the received scan response*/ +#define LPI_IE_BITMAP_AP_TX_PWR 0x00000020 /* sen Tx power from TPC IE of scan rsp*/ +#define LPI_IE_BITMAP_TX_RATE 0x00000040 /*send rate of the received frame as reported by HW.*/ +#define LPI_IE_BITMAP_80211_MC_SUPPORT 0x00000080 /*send true or false based on the received scan rsp was from a 11mc supported AP or not.*/ +#define LPI_IE_BITMAP_TSF_TIMER_VALUE 0x00000100 /*send timestamp reported in the received scan rsp frame.*/ +#define LPI_IE_BITMAP_AGE_OF_MEASUREMENT 0x00000200 /* current system time - received time) = duration of time scan rsp frame data is kept in the buffer before sending to LOWI LP.*/ +/* + * TEMPORARY alias of incorrect old name the correct name. + * This alias will be removed once all references to the old name have been fixed. + */ +#define LPI_IE_BITMAP_AGE_OF_MESAUREMENT LPI_IE_BITMAP_AGE_OF_MEASUREMENT +#define LPI_IE_BITMAP_CONN_STATUS 0x00000400 /* If an infra STA is active and connected to an AP, true value is sent else false.*/ +#define LPI_IE_BITMAP_MSAP_IE 0x00000800 /* info on the vendor specific proprietary IE MSAP*/ +#define LPI_IE_BITMAP_SEC_STATUS 0x00001000 /* we indicate true or false based on if the AP has WPA or RSN security enabled*/ +#define LPI_IE_BITMAP_DEVICE_TYPE 0x00002000 /* info about the beacons coming from an AP or P2P or NAN device.*/ +#define LPI_IE_BITMAP_CHAN_IS_PASSIVE 0x00004000 /* info on whether the scan rsp was received from a passive channel*/ +#define LPI_IE_BITMAP_DWELL_TIME 0x00008000 /* send the scan dwell time of the channel on which the current scan rsp frame was received.*/ +#define LPI_IE_BITMAP_BAND_CENTER_FREQ1 0x00010000 /* the center frequencies in case AP is supporting wider channels than 20 MHz*/ +#define LPI_IE_BITMAP_BAND_CENTER_FREQ2 0x00020000 /* same as above*/ +#define LPI_IE_BITMAP_PHY_MODE 0x00040000 /* PHY mode indicates a, b, ,g, ac and other combinations*/ +#define LPI_IE_BITMAP_SCAN_MODULE_ID 0x00080000 /* scan module id indicates the scan client who originated the scan*/ +#define LPI_IE_BITMAP_SCAN_ID 0x00100000 /*extscan inserts the scan cycle count for this value; other scan clients can insert the scan id of the scan, if needed.*/ +#define LPI_IE_BITMAP_FLAGS 0x00200000 /* reserved as a bitmap to indicate more scan information; one such use being to indicate if the on-going scan is interrupted or not*/ +#define LPI_IE_BITMAP_CACHING_REQD 0x00400000 /*extscan will use this field to indicate if this frame info needs to be cached in LOWI LP or not*/ +#define LPI_IE_BITMAP_ALL 0xFFFFFFFF + +typedef struct { + A_UINT32 tlv_header; + /**A_BOOL indicates LPI mgmt snooping enable/disable*/ + A_UINT32 enable; + /**LPI snooping mode*/ + A_UINT32 snooping_mode; + /** LPI interested IEs in snooping context */ + A_UINT32 ie_bitmap; +} wmi_lpi_mgmt_snooping_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param */ + /** Scan ID */ + A_UINT32 scan_id; + /** Scan requestor ID */ + A_UINT32 scan_req_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** LPI interested IEs in scan context */ + A_UINT32 ie_bitmap; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** dwell time in msec on active channels */ + A_UINT32 dwell_time_active; + /** dwell time in msec on passive channels */ + A_UINT32 dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_chan; + /** number of bssids. In the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid. In the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in ie data. In the TLV ie_data[] */ + A_UINT32 ie_len; + +/** + * TLV (tag length value ) parameters follow the scan_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + */ +} wmi_lpi_start_scan_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param */ + /** Scan requestor ID */ + A_UINT32 scan_req_id; + /** Scan ID */ + A_UINT32 scan_id; + /** + * Req Type + * req_type should be WMI_SCAN_STOP_ONE, WMI_SCN_STOP_VAP_ALL or WMI_SCAN_STOP_ALL + * WMI_SCAN_STOP_ONE indicates to stop a specific scan with scan_id + * WMI_SCN_STOP_VAP_ALL indicates to stop all scan requests on a specific vDev with vdev_id + * WMI_SCAN_STOP_ALL indicates to stop all scan requests in both Scheduler's queue and Scan Engine + */ + A_UINT32 req_type; + /** + * vDev ID + * used when req_type equals to WMI_SCN_STOP_VAP_ALL, it indexed the vDev on which to stop the scan + */ + A_UINT32 vdev_id; +} wmi_lpi_stop_scan_cmd_fixed_param; + +typedef enum { + WMI_LPI_DEVICE_TYPE_AP = 1, + WMI_LPI_DEVICE_TYPE_P2P = 2, + WMI_LPI_DEVICE_TYPE_NAN = 3, +} wmi_lpi_device_type; + +typedef struct { + A_UINT32 tlv_header; + /** Scan requestor ID */ + A_UINT32 scan_req_id; + A_UINT32 ie_bitmap; + A_UINT32 data_len; +} wmi_lpi_result_event_fixed_param; + +typedef enum { + /** User scan Request completed */ + WMI_LPI_STATUS_SCAN_REQ_COMPLED = 0, + /** User Request was never serviced */ + WMI_LPI_STATUS_DROPPED_REQ = 1, + /** Illegal channel Req */ + WMI_LPI_STATUS_ILLEGAL_CHAN_REQ = 2, + /** Illegal Operation Req */ + WMI_LPI_STATUS_ILLEGAL_OPER_REQ = 3, + /** Request Aborted */ + WMI_LPI_STATUS_REQ_ABORTED = 4, + /** Request Timed Out */ + WMI_LPI_STATUS_REQ_TIME_OUT = 5, + /** Medium Busy, already there + * is a scan is going on */ + WMI_LPI_STATUS_MEDIUM_BUSY = 6, + /* Extscan is the scan client whose scan complete event is triggered */ + WMI_LPI_STATUS_EXTSCAN_CYCLE_AND_SCAN_REQ_COMPLETED = 7, +} wmi_lpi_staus; + +typedef struct { + A_UINT32 tlv_header; + wmi_lpi_staus status; + /** Scan requestor ID */ + A_UINT32 scan_req_id; +} wmi_lpi_status_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + wmi_mac_addr bssid; + wmi_ssid ssid; + A_UINT32 freq; + A_UINT32 rssi; + A_UINT32 vdev_id; +} wmi_lpi_handoff_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 timestamp; /*timestamp of batch scan event */ + A_UINT32 numScanLists; /*number of scan in this event */ + A_UINT32 isLastResult; /*is this event a last event of the whole batch scan */ +} wmi_batch_scan_result_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param */ + A_UINT32 vdev_id; + /* This TLV is followed by p2p_noa_info for vdev : + * wmi_p2p_noa_info p2p_noa_info; + */ +} wmi_p2p_noa_event_fixed_param; + +#define WMI_RFKILL_CFG_RADIO_LEVEL_OFFSET 6 +#define WMI_RFKILL_CFG_RADIO_LEVEL_MASK 0x1 + +#define WMI_RFKILL_CFG_GPIO_PIN_NUM_OFFSET 0 +#define WMI_RFKILL_CFG_GPIO_PIN_NUM_MASK 0x3f + +#define WMI_RFKILL_CFG_PIN_AS_GPIO_OFFSET 7 +#define WMI_RFKILL_CFG_PIN_AS_GPIO_MASK 0xf + +typedef struct { + /** TLV tag and len; tag equals + * */ + A_UINT32 tlv_header; + /** gpip pin number */ + A_UINT32 gpio_pin_num; + /** gpio interupt type */ + A_UINT32 int_type; + /** RF radio status */ + A_UINT32 radio_state; +} wmi_rfkill_mode_param; + +typedef enum { + WMI_SET_LED_SYS_POWEROFF, + WMI_SET_LED_SYS_S3_SUSPEND, + WMI_SET_LED_SYS_S4_S5, + WMI_SET_LED_SYS_DRIVER_DISABLE, + WMI_SET_LED_SYS_WAKEUP, + WMI_SET_LED_SYS_ALWAYS_ON, /* just for test! */ + WMI_SET_LED_SYS_POWERON, +} wmi_led_sys_state_param; + +typedef enum { + WMI_CONFIG_LED_TO_VDD = 0, + WMI_CONFIG_LED_TO_GND = 1, +} wmi_config_led_connect_type; + +typedef enum { + WMI_CONFIG_LED_NOT_WITH_BT = 0, + WMI_CONFIG_LED_WITH_BT = 1, +} wmi_config_led_with_bt_flag; + +typedef enum { + WMI_CONFIG_LED_DISABLE = 0, + WMI_CONFIG_LED_ENABLE = 1, +} wmi_config_led_enable_flag; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Set GPIO pin */ + A_UINT32 led_gpio_pin; + /* Set connect type defined in wmi_config_led_connect_type */ + A_UINT32 connect_type; + /* Set flag defined in wmi_config_led_with_bt_flag */ + A_UINT32 with_bt; + /* Set LED enablement defined in wmi_config_led_enable_flag */ + A_UINT32 led_enable; +} wmi_pdev_set_led_config_cmd_fixed_param; + +#define WMI_WNTS_CFG_GPIO_PIN_NUM_OFFSET 0 +#define WMI_WNTS_CFG_GPIO_PIN_NUM_MASK 0xff + +/** WMI_PEER_INFO_REQ_CMDID + * Request FW to provide peer info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param */ + A_UINT32 tlv_header; + /** In order to get the peer info for a single peer, host shall + * issue the peer_mac_address of that peer. For getting the + * info all peers, the host shall issue 0xFFFFFFFF as the mac + * address. The firmware will return the peer info for all the + * peers on the specified vdev_id */ + wmi_mac_addr peer_mac_address; + /** vdev id */ + A_UINT32 vdev_id; +} wmi_peer_info_req_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info */ + A_UINT32 tlv_header; + /** mac addr of the peer */ + wmi_mac_addr peer_mac_address; + /** data_rate of the peer */ + A_UINT32 data_rate; + /** rssi of the peer */ + A_UINT32 rssi; + /** tx fail count */ + A_UINT32 tx_fail_cnt; +} wmi_peer_info; + +/** FW response with the peer info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param */ + A_UINT32 tlv_header; + /** number of peers in peer_info */ + A_UINT32 num_peers; + /* This TLV is followed by another TLV of array of structs + * wmi_peer_info peer_info[]; + */ +} wmi_peer_info_event_fixed_param; + +/** FW response when tx failure count has reached threshold + * for a peer */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** mac address */ + wmi_mac_addr peer_mac_address; + /** tx failure count- will eventually be removed and not used * */ + A_UINT32 tx_fail_cnt; + /** seq number of the nth tx_fail_event */ + A_UINT32 seq_no; +} wmi_peer_tx_fail_cnt_thr_event_fixed_param; + +enum wmi_rmc_mode { + /** Disable RMC */ + WMI_RMC_MODE_DISABLED = 0, + /** Enable RMC */ + WMI_RMC_MODE_ENABLED = 1, +}; + +/** Enable RMC transmitter functionality. Upon + * receiving this, the FW shall mutlicast frames with + * reliablity. This is a vendor + * proprietary feature. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** enable_rmc contains values from enum wmi_rmc_mode; + * Default value: 0 (disabled) */ + A_UINT32 enable_rmc; +} wmi_rmc_set_mode_cmd_fixed_param; + +/** Configure transmission periodicity of action frames in a + * RMC network for the multicast transmitter */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id */ + A_UINT32 vdev_id; + /** time period in milliseconds. Default: 300 ms. + An action frame indicating the current leader is transmitted by the + RMC transmitter once every 'periodity_msec' */ + A_UINT32 periodicity_msec; +} wmi_rmc_set_action_period_cmd_fixed_param; + +/** Optimise Leader selection process in RMC functionality. For + * Enhancement/Debug purposes only */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id */ + A_UINT32 vdev_id; + /** flags :: + * 0x0001 - Enable beacon averaging + * 0x0002 - Force leader selection + * 0x0004 - Enable Timer based leader switch + * 0x0008 - Use qos/NULL based for multicast reliability */ + A_UINT32 flags; + /** control leader change timeperiod (in seconds) */ + A_UINT32 peridocity_leader_switch; + /** control activity timeout value for data rx (in seconds) */ + A_UINT32 data_activity_timeout; + /** mac address of leader */ + wmi_mac_addr forced_leader_mac_addr; +} wmi_rmc_config_cmd_fixed_param; + +/** MHF is generally implemented in + * the kernel. To decrease system power consumption, the + * driver can enable offloading this to the chipset. In + * order for the offload, the firmware needs the routing table. + * The host shall plumb the routing table into FW. The firmware + * shall perform an IP address lookup and forward the packet to + * the next hop using next hop's mac address. This is a vendor + * proprietary feature. */ +enum wmi_mhf_ofl_mode { + /** Disable MHF offload */ + WMI_MHF_OFL_MODE_DISABLED = 0, + /** Enable MHF offload */ + WMI_MHF_OFL_MODE_ENABLED = 1, +}; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** enable_mhf_ofl contains values from enum + * wmi_mhf_ofl_mode; Default value: 0 (disabled) */ + A_UINT32 enable_mhf_ofl; +} wmi_mhf_offload_set_mode_cmd_fixed_param; + +enum wmi_mhf_ofl_table_action { + /** Create forwarding offload table in FW */ + WMI_MHF_OFL_TBL_CREATE = 0, + /** Append to existing MHF offload table */ + WMI_MHF_OFL_TBL_APPEND = 1, + /** Flush entire MHF offload table in FW */ + WMI_MHF_OFL_TBL_FLUSH = 2, +}; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** action corresponds to values from enum + * wmi_mhf_ofl_table_action */ + A_UINT32 action; + /** number of entries in the table */ + A_UINT32 num_entries; +/** Followed by the variable length TLV + * wmi_mhf_offload_routing_table_entry entries[] */ +} wmi_mhf_offload_plumb_routing_table_cmd; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_routing_table_entry */ + A_UINT32 tlv_header; + /** Destination node's IP address */ + WMI_IPV4_ADDR dest_ipv4_addr; + /** Next hop node's MAC address */ + wmi_mac_addr next_hop_mac_addr; +} wmi_mhf_offload_routing_table_entry; + +typedef struct { + /** tlv tag and len, tag equals + * WMITLV_TAG_STRUC_wmi_dfs_radar_event */ + A_UINT32 tlv_header; + + /** full 64 tsf timestamp get from MAC tsf timer indicates + * the time that the radar event uploading to host, split + * it to high 32 bit and lower 32 bit in fulltsf_high and + * full_tsf_low + */ + A_UINT32 upload_fullts_low; + A_UINT32 upload_fullts_high; + + /** timestamp indicates the time when DFS pulse is detected + * equal to ppdu_end_ts - radar_pusle_summary_ts_offset + */ + A_UINT32 pulse_detect_ts; + + /** the duaration of the pulse in us */ + A_UINT32 pulse_duration; + + /** the center frequency of the radar pulse detected, KHz */ + A_UINT32 pulse_center_freq; + + /** bandwidth of current DFS channel, MHz */ + A_UINT32 ch_bandwidth; + + /** center channel frequency1 of current DFS channel, MHz */ + A_UINT16 ch_center_freq1; + + /** center channel frequency2 of current DFS channel, MHz, + * reserved for 160 BW mode + */ + A_UINT16 ch_center_freq2; + + /** flag to indicate if this pulse is chirp */ + A_UINT8 pulse_is_chirp; + + /** RSSI recorded in the ppdu */ + A_UINT8 rssi; + + /** extened RSSI info */ + A_UINT8 rssi_ext; + + /** For 4-byte aligment padding */ + A_UINT8 reserved; + + /** pmac_id for the radar event */ + A_UINT8 pmac_id; + + /** index of peak magnitude bin (signed) */ + A_INT32 peak_sidx; + +} wmi_dfs_radar_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param */ + + /*Thermal thresholds */ + A_UINT32 lower_thresh_degreeC; /* in degree C */ + A_UINT32 upper_thresh_degreeC; /* in degree C */ + + /*Enable/Disable Thermal Monitoring for Mitigation */ + A_UINT32 enable; +} wmi_thermal_mgmt_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param */ + + A_UINT32 temperature_degreeC; /* temperature in degree C */ +} wmi_thermal_mgmt_event_fixed_param; + +/** + * This command is sent from WLAN host driver to firmware to + * request firmware to configure auto shutdown timer in fw + * 0 - Disable <1-19600>-Enabled and timer value is seconds (86400 seconds = 1 day maximum> + */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_param */ + A_UINT32 timer_value; + /** timer value; 0=disable */ +} wmi_host_auto_shutdown_cfg_cmd_fixed_param; + +enum wmi_host_auto_shutdown_reason { + WMI_HOST_AUTO_SHUTDOWN_REASON_UNKNOWN = 0, + WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY = 1, + WMI_HOST_AUTO_SHUTDOWN_REASON_MAX, +}; + +/* WMI_HOST_AUTO_SHUTDOWN_EVENTID */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param */ + A_UINT32 shutdown_reason; /* value: wmi_host_auto_shutdown_reason */ +} wmi_host_auto_shutdown_event_fixed_param; + +/** New WMI command to support TPC CHAINMASK ADJUSTMENT ACCORDING TO a set of conditions specified in the command. + * fw will save c tpc offset/chainmask along with conditions and adjust tpc/chainmask when condition meet. + * This command is only used by some customer for verification test. It is not for end-user. + * + * array of wmi_tpc_chainmask_config structures are passed with the command to specify multiple conditions. + * + * The set of conditions include bt status, stbc status, band, phy_mode, 1stream/2streams, channel, rate. when all these conditions meet, + * the output(tpc_offset,chainmask) will be applied on per packet basis. ack_offset is applied based on channel condtion only. When multiple + * conditions has the same channel ,then the first ack_offset will be applied. It is better for host driver to make sure the + * pair is unique. + * + * the conditions (bt status, stbc status, band, phy_mode, 1steam/2streams, tpc_offset, ack_offset, chainmask) are combinedi into a single word + * called basic_config_info by bitmap + * to save memory. And channel & rate info will be tracked by 'channel' field and 'rate0', 'rate1' field because of its large combination. + * + * 'rate bit' or 'channel bit' field of basic_config_info indicate validity of the channel and rate fields.if rate bit is 0 then the rate field + * is ignored. + * disable will remove preious conditions from FW. + * conditions from the later command will over write conditions stored from a previous command. + * + */ + +#define WMI_TPC_CHAINMASK_CONFIG_BT_ON_OFF 0 /** dont' care the bt status */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_ON 1 /** apply only when bt on */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_OFF 2 /** apply only when bt off */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_RESV1 3 /** reserved */ + +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_DONT_CARE 0 /** don't care the chainmask */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN0 1 /** force to use Chain0 to send */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN1 2 /** force to use Chain1 to send */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN0_CHAIN1 3 /** force to use Chain0 & Chain1 to send */ + +#define WMI_TPC_CHAINMASK_CONFIG_STBC_ON_OFF 0 /** don't care about stbc */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_ON 1 /** apply only when stbc on */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_OFF 2 /** apply only when stbc off */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_RESV1 3 /** reserved */ + +#define WMI_TPC_CHAINMASK_CONFIG_BAND_2G 0 /** 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_BAND_5G 1 /** 5G */ + +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11B_2G 0 /** 11b 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11G_2G 1 /** 11g 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_2G 2 /** 11n 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_2G 3 /** 11n + 11ac 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11A_5G 4 /** 11a 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_5G 5 /** 11n 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11AC_5G 6 /** 11ac 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_5G 7 /** 11n + 11ac 5G */ + +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_1 0 /** 1 stream */ +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_2 1 /** 2 streams */ + +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_OFF 0 /** channel field is ignored */ +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_ON 1 /** channel field needs to be checked */ + +#define WMI_TPC_CHAINMASK_CONFIG_RATE_OFF 0 /** rate field is ignored */ +#define WMI_TPC_CHAINMASK_CONFIG_RATE_ON 1 /** rate field needs to be checked */ + +/** Bit map definition for basic_config_info starts */ +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_S 0 +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET (0x1f << WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_S) +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET) +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_SET(x,z) WMI_F_RMW(x,(z) & 0x1f,WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET) + +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_S 5 +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET (0x1f << WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_S) +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET) +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_SET(x,z) WMI_F_RMW(x, (z) & 0x1f, WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET) + +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_S 10 +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK (0x3 << WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_S) +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_CHAINMASK) +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_SET(x,z) WMI_F_RMW(x, (z)&0x3, WMI_TPC_CHAINMASK_CONFIG_CHAINMASK) + +#define WMI_TPC_CHAINMASK_CONFIG_BT_S 12 +#define WMI_TPC_CHAINMASK_CONFIG_BT (0x3 << WMI_TPC_CHAINMASK_CONFIG_BT_S) +#define WMI_TPC_CHAINMASK_CONFIG_BT_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_BT) +#define WMI_TPC_CHAINMASK_CONFIG_BT_SET(x,z) WMI_F_RMW(x, (z)&0x3, WMI_TPC_CHAINMASK_CONFIG_BT) + +#define WMI_TPC_CHAINMASK_CONFIG_STBC_S 14 +#define WMI_TPC_CHAINMASK_CONFIG_STBC (0x3 << WMI_TPC_CHAINMASK_CONFIG_STBC_S) +#define WMI_TPC_CHAINMASK_CONFIG_STBC_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_STBC) +#define WMI_TPC_CHAINMASK_CONFIG_STBC_SET(x,z) WMI_F_RMW(x, (z)& 0x3, WMI_TPC_CHAINMASK_CONFIG_STBC) + +#define WMI_TPC_CHAINMASK_CONFIG_BAND_S 16 +#define WMI_TPC_CHAINMASK_CONFIG_BAND (0x1 << WMI_TPC_CHAINMASK_CONFIG_BAND_S) +#define WMI_TPC_CHAINMASK_CONFIG_BAND_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_BAND) +#define WMI_TPC_CHAINMASK_CONFIG_BAND_SET(x,z) WMI_F_RMW(x, (z) &0x1, WMI_TPC_CHAINMASK_CONFIG_BAND) + +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_S 17 +#define WMI_TPC_CHAINMASK_CONFIG_STREAM (0x1 << WMI_TPC_CHAINMASK_CONFIG_STREAM_S) +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_STREAM) +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_SET(x,z) WMI_F_RMW(x, (z)&0x1, WMI_TPC_CHAINMASK_CONFIG_STREAM) + +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_S 18 +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE (0x7 << WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_S) +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_PHY_MODE) +#define WMI_TPC_CHAINAMSK_CONFIG_PHY_MODE_SET(x,z) WMI_F_RMW(x, (z)&0x7, WMI_TPC_CHAINMASK_CONFIG_PHY_MODE) + +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_S 21 +/* + * The deprecated old name (WMI_TPC_CHAINMASK_CONFIG_CHANNEL_EXIST) + * is temporarily maintained as an alias for the correct name + * (WMI_TPC_CHAINMASK_CONFIG_CHANNEL) + */ +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_EXIST WMI_TPC_CHAINMASK_CONFIG_CHANNEL +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL (0x1 << WMI_TPC_CHAINMASK_CONFIG_CHANNEL_S) +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_CHANNEL) +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_SET(x,z) WMI_F_RMW(x, (z)&0x1, WMI_TPC_CHAINMASK_CONFIG_CHANNEL) + +#define WMI_TPC_CHAINMASK_CONFIG_RATE_S 22 +/* + * The deprecated old name (WMI_TPC_CHAINMASK_CONFIG_RATE_EXIST) + * is temporarily maintained as an alias for the correct name + * (WMI_TPC_CHAINMASK_CONFIG_RATE) + */ +#define WMI_TPC_CHAINMASK_CONFIG_RATE_EXIST WMI_TPC_CHAINMASK_CONFIG_RATE +#define WMI_TPC_CHAINMASK_CONFIG_RATE (0x1 << WMI_TPC_CHAINMASK_CONFIG_RATE_S) +#define WMI_TPC_CHAINMASK_CONFIG_RATE_GET(x) WMI_F_MS(x, WMI_TPC_CHAINMASK_CONFIG_RATE) +#define WMI_TPC_CHAINMASK_CONFIG_RATE_SET(x,z) WMI_F_RMW(x, (z)&0x1, WMI_TPC_CHAINMASK_CONFIG_RATE) + +/** Bit map definition for basic_config_info ends */ + +typedef struct { + A_UINT32 tlv_header; + /** Basic condition defined as bit map above, bitmap is chosen to save memory. + * Bit0 ~ Bit4: tpc offset which will be adjusted if condtion matches, the unit is 0.5dB. bit4 indicates signed + * Bit5 ~ Bit9: ack offset which will be adjusted if condtion matches, the unit is 0.5dB. bit9 indicates signed + * Bit10 ~ Bit11: chainmask b'00: don't care, b'01: force to use chain0, b'10: force to use chain1, b'11: force to use chain0&chain1 + * Bit12 ~ Bit13: bt condition b'00: don't care, b'01: apply only when bt on, b'10: apply only when bt off, b'11: reserved + * Bit14 ~ Bit15: stbc condition b'00: don't care, b'01: apply only when stbc on, b'10: apply only when stbc off, b'11: reserved + * Bit16 : band condition b'0: 2G, b'1: 5G + * Bit17 : stream condition: b'0: 1 stream, b'1: 2 streams + * Bit18 ~ Bit20: phy mode condition: b'000: 11b 2g, b'001: 11g 2g, b'010: 11n 2g, b'011: 11n+11ac 2g, b'100: 11a, b'101: 11n 5g, b'110: 11ac 5g, b'111: 11n+11ac 5g + * Bit21 : channel bit, if this bit is 0, then the following channel field is ignored + * Bit22 : rate bit, if this bit is 0, then the following rate0&rate1 is ignored. + * Bit23 ~ Bit31: reserved + */ + A_UINT32 basic_config_info; + + /** channel mapping bit rule: The lower bit corresponds with smaller channel. + * it depends on Bit14 of basic_config_info + * Total 24 channels for 5G + * 36 40 44 48 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 149 153 157 161 165 + * Total 14 channels for 2G + * 1 ~ 14 + */ + A_UINT32 channel; + + /** rate mapping bit rule: The lower bit corresponds with lower rate. + * it depends on Bit16 ~ Bit18 of basic_config_info, "phy mode condition" + * Legacy rates , 11b, 11g, 11A + * 11n one stream ( ht20, ht40 ) 8+8 + * 11n two streams ( ht20, ht40 ) 8+8 + * 11ac one stream ( vht20, vht40, vht80 ) 10+10+10 + * 11ac two streams (vht20, vht40, vht80 ) 10+10+10 + */ + A_UINT32 rate0; + /** For example, for 11b, when rate0 equals 0x3, it means if actual_rate in [ "1Mbps", "2Mbps"] connection, the rate condition is true. + * For example, for 11g/11a, when rate0 equals 0xf0,it means "54Mbps", "48Mbps", "36Mbps", "24Mb's" is selected, while "18Mbps", "12Mbps", "9Mbps", "6Mbps" is not selected + */ + + /** only used for "11n+11ac" combined phy_mode, (WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_2G , WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_5G) in this case, 11n rates begins on rate0, while 11ac rates begins on rate1 + */ + A_UINT32 rate1; +} wmi_tpc_chainmask_config; + +#define WMI_TPC_CHAINMASK_CONFIG_DISABLE 0 /** control the off for the tpc & chainmask*/ +#define WMI_TPC_CHAINMASK_CONFIG_ENABLE 1 /** control the on for the tpc & chainmask*/ + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 enable; + /** enable to set tpc & chainmask when condtions meet, 0: disabled, 1: enabled. */ + A_UINT32 num_tpc_chainmask_configs; + /** following this structure is num_tpc_chainmask_configs number of wmi_tpc_chainmask_config */ +} wmi_tpc_chainmask_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_cmd_param */ + A_UINT32 data_len; + /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs + * from application/service to firmware where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_nan_cmd_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_event_hdr */ + A_UINT32 data_len; + /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs + * from firmware to application/service where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_nan_event_hdr; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 num_data; + /* followed by WMITLV_TAG_ARRAY_BYTE */ +} wmi_diag_data_container_event_fixed_param; + +enum { + WMI_PDEV_PARAM_TXPOWER_REASON_NONE = 0, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR, + WMI_PDEV_PARAM_TXPOWER_REASON_MAX +}; + +#define PDEV_PARAM_TXPOWER_VALUE_MASK 0x000000FF +#define PDEV_PARAM_TXPOWER_VALUE_SHIFT 0 + +#define PDEV_PARAM_TXPOWER_REASON_MASK 0x0000FF00 +#define PDEV_PARAM_TXPOWER_REASON_SHIFT 8 + +#define SET_PDEV_PARAM_TXPOWER_VALUE(txpower_param, value) \ + ((txpower_param) &= ~PDEV_PARAM_TXPOWER_VALUE_MASK, (txpower_param) |= ((value) << PDEV_PARAM_TXPOWER_VALUE_SHIFT)) + +#define SET_PDEV_PARAM_TXPOWER_REASON(txpower_param, value) \ + ((txpower_param) &= ~PDEV_PARAM_TXPOWER_REASON_MASK, (txpower_param) |= ((value) << PDEV_PARAM_TXPOWER_REASON_SHIFT)) + +#define GET_PDEV_PARAM_TXPOWER_VALUE(txpower_param) \ + (((txpower_param) & PDEV_PARAM_TXPOWER_VALUE_MASK) >> PDEV_PARAM_TXPOWER_VALUE_SHIFT) + +#define GET_PDEV_PARAM_TXPOWER_REASON(txpower_param) \ + (((txpower_param) & PDEV_PARAM_TXPOWER_REASON_MASK) >> PDEV_PARAM_TXPOWER_REASON_SHIFT) + +/** + * This command is sent from WLAN host driver to firmware to + * notify the current modem power state. Host would receive a + * message from modem when modem is powered on. Host driver + * would then send this command to firmware. Firmware would then + * power on WCI-2 (UART) interface for LTE/MWS Coex. + * + * This command is only applicable for APQ platform which has + * modem on the platform. If firmware doesn't support MWS Coex, + * this command can be dropped by firmware. + * + * This is a requirement from modem team that WCN can't toggle + * UART before modem is powered on. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param */ + A_UINT32 tlv_header; + + /** Modem power state parameter */ + A_UINT32 modem_power_state; +} wmi_modem_power_state_cmd_param; + +enum { + WMI_MODEM_STATE_OFF = 0, + WMI_MODEM_STATE_ON +}; + +#define WMI_ROAM_AUTH_STATUS_CONNECTED 0x1 /** connected, but not authenticated */ +#define WMI_ROAM_AUTH_STATUS_AUTHENTICATED 0x2 /** connected and authenticated */ + +/** WMI_ROAM_SYNCH_EVENT: roam synch event triggering the host propagation logic + generated whenever firmware roamed to new AP silently and + (a) If the host is awake, FW sends the event to the host immediately . + (b) If host is in sleep then either + (1) FW waits until host sends WMI_PDEV_RESUME_CMDID or WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID + command to FW (part of host wake up sequence from low power mode) before sending the event host. + (2) data/mgmt frame is received from roamed AP, which needs to return to host + */ + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_key_material */ + A_UINT32 tlv_header; + + A_UINT8 kck[GTK_OFFLOAD_KCK_BYTES]; /* EAPOL-Key Key Confirmation Key (KCK) */ + A_UINT8 kek[GTK_OFFLOAD_KEK_BYTES]; /* EAPOL-Key Key Encryption Key (KEK) */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; +} wmi_key_material; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param */ + /** Unique id identifying the VDEV on which roaming is done by firmware */ + A_UINT32 vdev_id; + /** auth_status: connected or authorized */ + A_UINT32 auth_status; + /* + * roam_reason: whether roaming went to a new subnet; + * see WMI_ROAM_SUBNET_CHANGE_STATUS_XXX + */ + A_UINT32 roam_reason; + /** associated AP's rssi calculated by FW when reason code is WMI_ROAM_REASON_LOW_RSSI. not valid if roam_reason is BMISS */ + A_UINT32 rssi; + /** MAC address of roamed AP */ + wmi_mac_addr bssid; /* BSSID */ + /** whether the frame is beacon or probe rsp */ + A_UINT32 is_beacon; + /** the length of beacon/probe rsp */ + A_UINT32 bcn_probe_rsp_len; + /** the length of reassoc rsp */ + A_UINT32 reassoc_rsp_len; + /** + * TLV (tag length value ) parameters follows roam_synch_event + * The TLV's are: + * A_UINT8 bcn_probe_rsp_frame[]; length identified by bcn_probe_rsp_len + * A_UINT8 reassoc_rsp_frame[]; length identified by reassoc_rsp_len + * wmi_channel chan; + * wmi_key_material key; + * A_UINT32 status; subnet changed status not being used + * currently. will pass the information using roam_status. + **/ +} wmi_roam_synch_event_fixed_param; + +#define WMI_PEER_ESTIMATED_LINKSPEED_INVALID 0xFFFFFFFF + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_get_estimated_linkspeed_cmd_fixed_param */ + A_UINT32 tlv_header; + /** MAC address of the peer for which the estimated link speed is required. */ + wmi_mac_addr peer_macaddr; +} wmi_peer_get_estimated_linkspeed_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_estimated_linkspeed_event_fixed_param */ + A_UINT32 tlv_header; + /** MAC address of the peer for which the estimated link speed is required. + */ + wmi_mac_addr peer_macaddr; + /* Estimated link speed in kbps. + * When est_linkspeed_kbps is not valid, the value is set to WMI_PEER_ESTIMATED_LINKSPEED_INVALID. + */ + A_UINT32 est_linkspeed_kbps; +} wmi_peer_estimated_linkspeed_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals */ + /* vdev ID */ + A_UINT32 vdev_id; + A_UINT32 data_len; + /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs + * from application/service to firmware where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_req_stats_ext_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats1_event_fix_param */ + A_UINT32 vdev_id; + /** vdev ID */ + A_UINT32 data_len; + /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs + * from firmware to application/service where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_stats_ext_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_state_event_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* vdev ID */ + /* MAC address of the peer for which the estimated link speed is required. */ + wmi_mac_addr peer_macaddr; + A_UINT32 state; /* peer state */ +} wmi_peer_state_event_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param + */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_assoc_conf_event_fixed_param; + +enum { + WMI_2G4_HT40_OBSS_SCAN_PASSIVE = 0, + /** scan_type: passive */ + WMI_2G4_HT40_OBSS_SCAN_ACTIVE, + /** scan_type: active */ +}; + +typedef struct { + /** + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_obss_scan_enalbe_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /** + * active or passive. if active all the channels are actively scanned. + * if passive then all the channels are passively scanned + */ + A_UINT32 scan_type; + /** + * FW can perform multiple scans with in a OBSS scan interval. + * For each scan, + * if the scan is passive then obss_scan_passive_dwell is minimum dwell to be used for each channel , + * if the scan is active then obss_scan_active_dwell is minimum dwell to be used for each channel . + * The unit for these 2 parameters is TUs. + */ + A_UINT32 obss_scan_passive_dwell; + A_UINT32 obss_scan_active_dwell; + /** + * OBSS scan interval . FW needs to perform one or more OBSS scans within this interval and fulfill the + * both min and total per channel dwell time requirement + */ + A_UINT32 bss_channel_width_trigger_scan_interval; + /** + * FW can perform multiple scans with in a OBSS scan interval. + * For each scan, + * the total per channel dwell time across all scans with in OBSS scan interval should be + * atleast obss_scan_passive_total_per channel for passive scas and obss_scan_active_total_per channel + * for active scans and , + * The unit for these 2 parameters is TUs. + */ + A_UINT32 obss_scan_passive_total_per_channel; + A_UINT32 obss_scan_active_total_per_channel; + A_UINT32 bss_width_channel_transition_delay_factor; + /** parameter to check exemption from scan */ + A_UINT32 obss_scan_activity_threshold; + /** parameter to check exemption from scan */ + /** following two parameters used by FW to fill IEs when sending 20/40 coexistence action frame to AP */ + A_UINT32 forty_mhz_intolerant; + /** STA 40M bandwidth intolerant capability */ + A_UINT32 current_operating_class; + /** STA current operating class */ + /** length of 2.4GHz channel list to scan at, channel list in tlv->channels[] */ + A_UINT32 channel_len; + /** length of optional ie data to append to probe reqest when active scan, ie data in tlv->ie_field[] */ + A_UINT32 ie_len; +} wmi_obss_scan_enable_cmd_fixed_param; + +typedef struct { + /** + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_obss_scan_disalbe_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_obss_scan_disable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** prb rsp tx status, values defined in enum WMI_FRAME_TX_STATUS */ + A_UINT32 tx_status; +} wmi_offload_prb_rsp_tx_status_event_fixed_param; + +typedef enum { + WMI_FRAME_TX_OK, /* frame tx ok */ + WMI_FRAME_TX_XRETRY, /* excessivley retried */ + WMI_FRAME_TX_DROP, /* frame dropped by FW due to resources */ + WMI_FRAME_TX_FILTERED, /* frame filtered by hardware */ +} WMI_FRAME_TX_STATUS; + +/** + * This command is sent from WLAN host driver to firmware to + * request firmware to send the latest channel avoidance range + * to host. + * + * This command is only applicable for APQ platform which has + * modem on the platform. If firmware doesn't support MWS Coex, + * this command can be dropped by firmware. + * + * Host would send this command to firmware to request a channel + * avoidance information update. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param */ + A_UINT32 tlv_header; +} wmi_chan_avoid_update_cmd_param; + +/* ExtScan operation mode */ +typedef enum { + WMI_EXTSCAN_MODE_NONE = 0x0000, + WMI_EXTSCAN_MODE_START = 0x0001, /* ExtScan/TableMonitoring operation started */ + WMI_EXTSCAN_MODE_STOP = 0x0002, /* ExtScan/TableMonitoring operation stopped */ + WMI_EXTSCAN_MODE_IGNORED = 0x0003, /* ExtScan command ignored due to error */ +} wmi_extscan_operation_mode; + +/* Channel Mask */ +typedef enum { + WMI_CHANNEL_BAND_UNSPECIFIED = 0x0000, + WMI_CHANNEL_BAND_24 = 0x0001, /* 2.4 channel */ + WMI_CHANNEL_BAND_5_NON_DFS = 0x0002, /* 5G Channels (No DFS channels) */ + WMI_CHANNEL_BAND_DFS = 0x0004, /* DFS channels */ +} wmi_channel_band_mask; + +typedef enum { + WMI_EXTSCAN_CYCLE_STARTED_EVENT = 0x0001, + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT = 0x0002, + WMI_EXTSCAN_BUCKET_STARTED_EVENT = 0x0004, + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT = 0x0008, + WMI_EXTSCAN_BUCKET_FAILED_EVENT = 0x0010, + WMI_EXTSCAN_BUCKET_OVERRUN_EVENT = 0x0020, + + WMI_EXTSCAN_EVENT_MAX = 0x8000 +} wmi_extscan_event_type; + +#define WMI_EXTSCAN_CYCLE_EVENTS_MASK (WMI_EXTSCAN_CYCLE_STARTED_EVENT | \ + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT) + +#define WMI_EXTSCAN_BUCKET_EVENTS_MASK (WMI_EXTSCAN_BUCKET_STARTED_EVENT | \ + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT | \ + WMI_EXTSCAN_BUCKET_FAILED_EVENT | \ + WMI_EXTSCAN_BUCKET_OVERRUN_EVENT) + +typedef enum { + WMI_EXTSCAN_NO_FORWARDING = 0x0000, + WMI_EXTSCAN_FORWARD_FRAME_TO_HOST = 0x0001 +} wmi_extscan_forwarding_flags; + +typedef enum { + /* Use Motion Sensor Detection */ + WMI_EXTSCAN_USE_MSD = 0x0001, + /* Extscan LPASS extended batching feature is supported and enabled */ + WMI_EXTSCAN_EXTENDED_BATCHING_EN = 0x0002, +} wmi_extscan_configuration_flags; +typedef enum { + /* + * Cache the results of bucket whose + * configuration flags has this bit set + */ + WMI_EXTSCAN_BUCKET_CACHE_RESULTS = 0x0001, +} wmi_extscan_bucket_configuration_flags; + +typedef enum { + WMI_EXTSCAN_STATUS_OK = 0, + WMI_EXTSCAN_STATUS_ERROR = 0x80000000, + WMI_EXTSCAN_STATUS_INVALID_PARAMETERS, + WMI_EXTSCAN_STATUS_INTERNAL_ERROR +} wmi_extscan_start_stop_status; + +typedef struct { + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting ExtScan */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; +} wmi_extscan_command_id; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** channel number */ + A_UINT32 channel; + + /** dwell time in msec - use defaults if 0 */ + A_UINT32 min_dwell_time; + A_UINT32 max_dwell_time; + /** passive/active channel and other flags */ + A_UINT32 control_flags; /* 0 => active, 1 => passive scan; ignored for DFS */ +} wmi_extscan_bucket_channel; + +/* Scan Bucket specification */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** Bucket ID - 0-based */ + A_UINT32 bucket_id; + /** ExtScan events subscription - events to be reported to client (see wmi_extscan_event_type) */ + A_UINT32 notify_extscan_events; + /** Options to forward scan results - see wmi_extscan_forwarding_flags */ + A_UINT32 forwarding_flags; + /* + * ExtScan configuration flags - + * wmi_extscan__bucket_configuration_flags + */ + A_UINT32 configuration_flags; + /** DEPRECATED member:multiplier to be applied to the periodic scan's base period */ + A_UINT32 base_period_multiplier; + /** dwell time in msec on active channels - use defaults if 0 */ + A_UINT32 min_dwell_time_active; + A_UINT32 max_dwell_time_active; + /** dwell time in msec on passive channels - use defaults if 0 */ + A_UINT32 min_dwell_time_passive; + A_UINT32 max_dwell_time_passive; + /** see wmi_channel_band_mask; when equal to WMI_CHANNEL_UNSPECIFIED, use channel list */ + A_UINT32 channel_band; + /** number of channels (if channel_band is WMI_CHANNEL_UNSPECIFIED) */ + A_UINT32 num_channels; + /** scan period upon start or restart of the bucket - periodicity of the bucket to begin with */ + A_UINT32 min_period; + /** period above which exponent is not applied anymore */ + A_UINT32 max_period; + /** + * back off value to be applied to bucket's periodicity after exp_max_step_count scan cycles + * new_bucket_period = last_bucket_period + last_exponent_period exp_backoff + */ + A_UINT32 exp_backoff; + /** number of scans performed at a given periodicity after which exponential back off value is + * applied to current periodicity to obtain a newer one + */ + A_UINT32 exp_max_step_count; +/** Followed by the variable length TLV chan_list: + * wmi_extscan_bucket_channel chan_list[] */ +} wmi_extscan_bucket; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting ExtScan */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /** Base period (milliseconds) used by scan buckets to define periodicity of the scans */ + A_UINT32 base_period; + /** Maximum number of iterations to run - one iteration is the scanning of the least frequent bucket */ + A_UINT32 max_iterations; + /** Options to forward scan results - see wmi_extscan_forwarding_flags */ + A_UINT32 forwarding_flags; + /** ExtScan configuration flags - wmi_extscan_configuration_flags */ + A_UINT32 configuration_flags; + /** ExtScan events subscription - bitmask indicating which events should be send to client (see wmi_extscan_event_type) */ + A_UINT32 notify_extscan_events; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** Maximum number of BSSIDs to cache on each scan cycle */ + A_UINT32 max_bssids_per_scan_cycle; + /** Minimum RSSI value to report */ + A_UINT32 min_rssi; + /** Maximum table usage in percentage */ + A_UINT32 max_table_usage; + /** default dwell time in msec on active channels */ + A_UINT32 min_dwell_time_active; + A_UINT32 max_dwell_time_active; + /** default dwell time in msec on passive channels */ + A_UINT32 min_dwell_time_passive; + A_UINT32 max_dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + /** Max number of probes to be sent */ + A_UINT32 n_probes; + /** time in msec between 2 sets of probe requests. */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** number of bssids in the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid in the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in TLV ie_data[] */ + A_UINT32 ie_len; + /** number of buckets in the TLV bucket_list[] */ + A_UINT32 num_buckets; + /** in number of scans, send notifications to host after these many scans */ + A_UINT32 report_threshold_num_scans; + + /** number of channels in channel_list[] determined by the + sum of wmi_extscan_bucket.num_channels in array */ + +/** + * TLV (tag length value ) parameters follow the extscan_cmd + * structure. The TLV's are: + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + * wmi_extscan_bucket bucket_list[]; + * wmi_extscan_bucket_channel channel_list[]; + */ +} wmi_extscan_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param */ + /** Request ID - to match running command. 0 matches any request */ + A_UINT32 request_id; + /** Requestor ID - client requesting stop */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_stop_cmd_fixed_param; + +enum wmi_extscan_get_cached_results_flags { + WMI_EXTSCAN_GET_CACHED_RESULTS_FLAG_NONE = 0x0000, + WMI_EXTSCAN_GET_CACHED_RESULTS_FLAG_FLUSH_TABLE = 0x0001 +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param */ + /** request ID - used to correlate command with events */ + A_UINT32 request_id; + /** Requestor ID - client that requested results */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /** maximum number of results to be returned */ + A_UINT32 max_results; + /** flush BSSID list - wmi_extscan_get_cached_results_flags */ + A_UINT32 control_flags; /* enum wmi_extscan_get_cached_results_flags */ +} wmi_extscan_get_cached_results_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param */ + /** request ID - used to correlate command with events */ + A_UINT32 request_id; + /** Requestor ID - client that requested results */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_get_wlan_change_results_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**channel number */ + A_UINT32 channel; + /**upper RSSI limit */ + A_UINT32 upper_rssi_limit; + /**lower RSSI limit */ + A_UINT32 lower_rssi_limit; +} wmi_extscan_wlan_change_bssid_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting wlan change monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /** number of rssi samples to store */ + A_UINT32 max_rssi_samples; + /** number of samples to use to calculate RSSI average */ + A_UINT32 rssi_averaging_samples; + /** number of scans to confirm loss of contact with RSSI */ + A_UINT32 lost_ap_scan_count; + /** number of out-of-range BSSIDs necessary to send event */ + A_UINT32 max_out_of_range_count; + /** total number of bssid signal descriptors (in all pages) */ + A_UINT32 total_entries; + /** index of the first bssid entry found in the TLV wlan_change_descriptor_list*/ + A_UINT32 first_entry_index; + /** number of bssid signal descriptors in this page */ + A_UINT32 num_entries_in_page; + /* Following this structure is the TLV: + * wmi_extscan_wlan_change_bssid_param wlan_change_descriptor_list[]; // number of elements given by field num_page_entries. + */ +} wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + A_UINT32 tlv_header; + /**ssid */ + wmi_ssid ssid; + /**band */ + A_UINT32 band; + /**RSSI threshold for reporting */ + A_UINT32 min_rssi; + A_UINT32 max_rssi; +} wmi_extscan_hotlist_ssid_entry; + +typedef struct { + /** + * TLV tag and len; tag equals + * MITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param + */ + A_UINT32 tlv_header; + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting hotlist ssid monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; // wmi_extscan_operation_mode + /**total number of ssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first ssid entry found in the TLV extscan_hotlist_ssid_entry*/ + A_UINT32 first_entry_index; + /**number of ssids in this page */ + A_UINT32 num_entries_in_page; + /** number of consecutive scans to confirm loss of an ssid **/ + A_UINT32 lost_ap_scan_count; + /* Following this structure is the TLV: + * wmi_extscan_hotlist_ssid_entry hotlist_ssid[]; + * number of element given by field num_page_entries. + */ +} wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**RSSI min threshold for reporting */ + A_UINT32 min_rssi; + /**Deprecated entry channel number */ + A_UINT32 channel; + /** RSSI max threshold for reporting */ + A_UINT32 max_rssi; +} wmi_extscan_hotlist_entry; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting hotlist monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /**total number of bssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid entry found in the TLV wmi_extscan_hotlist_entry*/ + A_UINT32 first_entry_index; + /**number of bssids in this page */ + A_UINT32 num_entries_in_page; + /** number of consecutive scans to confirm loss of contact with AP */ + A_UINT32 lost_ap_scan_count; + /* Following this structure is the TLV: + * wmi_extscan_hotlist_entry hotlist[]; // number of elements given by field num_page_entries. + */ +} wmi_extscan_configure_hotlist_monitor_cmd_fixed_param; + + typedef struct { + /* TLV tag and len; tag equals + *WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param */ + A_UINT32 tlv_header; + /** Request ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID + that configured the table */ + A_UINT32 config_requestor_id; + /** + * VDEV id(interface) of the + * WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID that configured the table + */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**total number of ssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first ssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of ssids in this page */ + A_UINT32 num_entries_in_page; + /* Following this structure is the TLV: + * wmi_extscan_wlan_descriptor hotlist_match[]; + * number of descriptors given by field num_entries_in_page + */ +} wmi_extscan_hotlist_ssid_match_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of scan cache entry */ + A_UINT32 scan_cache_entry_size; + /** maximum number of scan cache entries */ + A_UINT32 max_scan_cache_entries; + /** maximum number of buckets per extscan request */ + A_UINT32 max_buckets; + /** maximum number of BSSIDs that will be stored in each scan (best n/w as per RSSI) */ + A_UINT32 max_bssid_per_scan; + /** table usage level at which indication must be sent to host */ + A_UINT32 max_table_usage_threshold; +} wmi_extscan_cache_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of wlan change entry */ + A_UINT32 wlan_change_entry_size; + /** maximum number of entries in wlan change table */ + A_UINT32 max_wlan_change_entries; + /** number of RSSI samples used for averaging RSSI */ + A_UINT32 max_rssi_averaging_samples; + /** number of BSSID/RSSI entries (BSSID pointer, RSSI, timestamp) that device can hold */ + A_UINT32 max_rssi_history_entries; +} wmi_extscan_wlan_change_monitor_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of hotlist entry */ + A_UINT32 wlan_hotlist_entry_size; + /** maximum number of entries in wlan change table */ + A_UINT32 max_hotlist_entries; +} wmi_extscan_hotlist_monitor_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param */ + /** Request ID - matches request ID used to start hot list monitoring */ + A_UINT32 request_id; + /** Requestor ID - client requesting stop */ + A_UINT32 requestor_id; + /** number of extscan caches */ + A_UINT32 num_extscan_cache_tables; + /** number of wlan change lists */ + A_UINT32 num_wlan_change_monitor_tables; + /** number of hotlists */ + A_UINT32 num_hotlist_monitor_tables; + /** if one sided rtt data collection is supported */ + A_UINT32 rtt_one_sided_supported; + /** if 11v data collection is supported */ + A_UINT32 rtt_11v_supported; + /** if 11mc data collection is supported */ + A_UINT32 rtt_ftm_supported; + /** number of extscan cache capabilities (one per table) */ + A_UINT32 num_extscan_cache_capabilities; + /** number of wlan change capabilities (one per table) */ + A_UINT32 num_extscan_wlan_change_capabilities; + /** number of extscan hotlist capabilities (one per table) */ + A_UINT32 num_extscan_hotlist_capabilities; + /* Following this structure is the TLV: + * wmi_extscan_cache_capabilities extscan_cache_capabilities; // number of capabilities given by num_extscan_caches + * wmi_extscan_wlan_change_monitor_capabilities wlan_change_capabilities; // number of capabilities given by num_wlan_change_monitor_tables + * wmi_extscan_hotlist_monitor_capabilities hotlist_capabilities; // number of capabilities given by num_hotlist_monitor_tables + */ +} wmi_extscan_set_capabilities_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param */ + /** Request ID - matches request ID used to start hot list monitoring */ + A_UINT32 request_id; + /** Requestor ID - client requesting capabilities */ + A_UINT32 requestor_id; +} wmi_extscan_get_capabilities_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param */ + /** Request ID of the operation that was started/stopped */ + A_UINT32 request_id; + /** Requestor ID of the operation that was started/stopped */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the operation that was started/stopped */ + A_UINT32 vdev_id; + /** extscan WMI command */ + A_UINT32 command; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /**success/failure */ + A_UINT32 status; /* enum wmi_extscan_start_stop_status */ + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_start_stop_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param */ + /** Request ID of the extscan operation that is currently running */ + A_UINT32 request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 vdev_id; + /** scan event (wmi_scan_event_type) */ + A_UINT32 event; /* wmi_extscan_event_type */ + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /**number of buckets */ + A_UINT32 num_buckets; + /* Following this structure is the TLV: + * A_UINT32 bucket_id[]; // number of elements given by field num_buckets. + */ +} wmi_extscan_operation_event_fixed_param; + +/* Types of extscan tables */ +typedef enum { + EXTSCAN_TABLE_NONE = 0, + EXTSCAN_TABLE_BSSID = 1, + EXTSCAN_TABLE_RSSI = 2, +} wmi_extscan_table_type; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param */ + /** Request ID of the extscan operation that is currently running */ + A_UINT32 request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**see wmi_extscan_table_type for table reporting usage */ + A_UINT32 table_type; + /**number of entries in use */ + A_UINT32 entries_in_use; + /**maximum number of entries in table */ + A_UINT32 maximum_entries; +} wmi_extscan_table_usage_event_fixed_param; + +typedef enum { + /** + * Indicates scan got interrupted i.e. aborted or pre-empted for a long time (> 1sec) + * this can be used to discard scan results + */ + WMI_SCAN_STATUS_INTERRUPTED = 1 +} wmi_scan_status_flags; + + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**RSSI */ + A_UINT32 rssi; + /**time stamp in milliseconds */ + A_UINT32 tstamp; + /** Extscan cycle during which this entry was scanned */ + A_UINT32 scan_cycle_id; + /** + * flag to indicate if the given result was obtained as part of + * interrupted (aborted/large time gap preempted) scan + */ + A_UINT32 flags; +} wmi_extscan_rssi_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**ssid */ + wmi_ssid ssid; + /**channel number */ + A_UINT32 channel; + /* capabilities */ + A_UINT32 capabilities; + /* beacon interval in TUs */ + A_UINT32 beacon_interval; + /**time stamp in milliseconds - time last seen */ + A_UINT32 tstamp; + /**flags - _tExtScanEntryFlags */ + A_UINT32 flags; + /**RTT in ns */ + A_UINT32 rtt; + /**rtt standard deviation */ + A_UINT32 rtt_sd; + /* rssi information */ + A_UINT32 number_rssi_samples; + /** IE length */ + A_UINT32 ie_length; /* length of IE data */ +} wmi_extscan_wlan_descriptor; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 vdev_id; + /** Request ID of the extscan operation that is currently running */ + A_UINT32 extscan_request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 extscan_requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 extscan_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**current time stamp in seconds. Used to provide a baseline for the relative timestamps returned for each block and entry */ + A_UINT32 current_tstamp; + /**total number of bssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids in this page */ + A_UINT32 num_entries_in_page; + /* Followed by the variable length TLVs + * wmi_extscan_wlan_descriptor bssid_list[] + * wmi_extscan_rssi_info rssi_list[] + * A_UINT8 ie_list[] + */ +} wmi_extscan_cached_results_event_fixed_param; + +typedef enum { + EXTSCAN_WLAN_CHANGE_FLAG_NONE = 0x00, + EXTSCAN_WLAN_CHANGE_FLAG_OUT_OF_RANGE = 0x01, + EXTSCAN_WLAN_CHANGE_FLAG_AP_LOST = 0x02, +} wmi_extscan_wlan_change_flags; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**time stamp in milliseconds */ + A_UINT32 tstamp; + /**upper RSSI limit */ + A_UINT32 upper_rssi_limit; + /**lower RSSI limit */ + A_UINT32 lower_rssi_limit; + /** channel */ + A_UINT32 channel; /* in MHz */ + /**current RSSI average */ + A_UINT32 rssi_average; + /**flags - wmi_extscan_wlan_change_flags */ + A_UINT32 flags; + /**legnth of RSSI history to follow (number of values) */ + A_UINT32 num_rssi_samples; +} wmi_extscan_wlan_change_result_bssid; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 vdev_id; + /** Request ID of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**number of entries with RSSI out of range or BSSID not detected */ + A_UINT32 change_count; + /**total number of bssid signal descriptors (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid signal descriptor entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids signal descriptors in this page */ + A_UINT32 num_entries_in_page; + /* Following this structure is the TLV: + * wmi_extscan_wlan_change_result_bssid bssid_signal_descriptor_list[]; // number of descriptors given by field num_entries_in_page. + * Following this structure is the list of RSSI values (each is an A_UINT8): + * A_UINT8 rssi_list[]; // last N RSSI values. + */ +} wmi_extscan_wlan_change_results_event_fixed_param; + +enum _tExtScanEntryFlags { + WMI_HOTLIST_FLAG_NONE = 0x00, + WMI_HOTLIST_FLAG_PRESENCE = 0x01, + WMI_HOTLIST_FLAG_DUPLICATE_SSID = 0x80, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**total number of bssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids in this page */ + A_UINT32 num_entries_in_page; + /* Following this structure is the TLV: + * wmi_extscan_wlan_descriptor hotlist_match[]; // number of descriptors given by field num_entries_in_page. + */ +} wmi_extscan_hotlist_match_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 vdev_id; + /** number of extscan caches */ + A_UINT32 num_extscan_cache_tables; + /** number of wlan change lists */ + A_UINT32 num_wlan_change_monitor_tables; + /** number of hotlists */ + A_UINT32 num_hotlist_monitor_tables; + /** if one sided rtt data collection is supported */ + A_UINT32 rtt_one_sided_supported; + /** if 11v data collection is supported */ + A_UINT32 rtt_11v_supported; + /** if 11mc data collection is supported */ + A_UINT32 rtt_ftm_supported; + /** number of extscan cache capabilities (one per table) */ + A_UINT32 num_extscan_cache_capabilities; + /** number of wlan change capabilities (one per table) */ + A_UINT32 num_extscan_wlan_change_capabilities; + /** number of extscan hotlist capabilities (one per table) */ + A_UINT32 num_extscan_hotlist_capabilities; + /* max number of roaming ssid whitelist firmware can support */ + A_UINT32 num_roam_ssid_whitelist; + /* max number of blacklist bssid firmware can support */ + A_UINT32 num_roam_bssid_blacklist; + /* max number of preferred list firmware can support */ + A_UINT32 num_roam_bssid_preferred_list; + /* max number of hotlist ssids firmware can support */ + A_UINT32 num_extscan_hotlist_ssid; + /* max number of epno networks firmware can support */ + A_UINT32 num_epno_networks; + + /* Following this structure are the TLVs describing the capabilities of of the various types of lists. The FW theoretically + * supports multiple lists of each type. + * + * wmi_extscan_cache_capabilities extscan_cache_capabilities[] // capabilities of extscan cache (BSSID/RSSI lists) + * wmi_extscan_wlan_change_monitor_capabilities wlan_change_capabilities[] // capabilities of wlan_change_monitor_tables + * wmi_extscan_hotlist_monitor_capabilities hotlist_capabilities[] // capabilities of hotlist_monitor_tables + */ +} wmi_extscan_capabilities_event_fixed_param; + +/* WMI_D0_WOW_DISABLE_ACK_EVENTID */ +typedef struct { + A_UINT32 tlv_header; + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param */ + A_UINT32 reserved0; /* for future need */ +} wmi_d0_wow_disable_ack_event_fixed_param; + +/** WMI_PDEV_RESUME_EVENTID : generated in response to WMI_PDEV_RESUME_CMDID */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param */ + A_UINT32 rsvd; /* for future need */ +} wmi_pdev_resume_event_fixed_param; + +/** value representing all modules */ +#define WMI_DEBUG_LOG_MODULE_ALL 0xffff + +/* param definitions */ + +/** + * Log level for a given module. Value contains both module id and log level. + * here is the bitmap definition for value. + * module Id : 16 + * Flags : reserved + * Level : 8 + * if odule Id is WMI_DEBUG_LOG_MODULE_ALL then log level is applied to all modules (global). + * WMI_DEBUG_LOG_MIDULE_ALL will overwrites per module level setting. + */ +#define WMI_DEBUG_LOG_PARAM_LOG_LEVEL 0x1 + +#define WMI_DBGLOG_SET_LOG_LEVEL(val,lvl) do { \ + (val) |= (lvl & 0xff); \ +} while(0) + +#define WMI_DBGLOG_GET_LOG_LEVEL(val) ((val) & 0xff) + +#define WMI_DBGLOG_SET_MODULE_ID(val,mid) do { \ + (val) |= ((mid & 0xffff) << 16); \ +} while(0) + +#define WMI_DBGLOG_GET_MODULE_ID(val) (( (val) >> 16) & 0xffff) + +/** + * Enable the debug log for a given vdev. Value is vdev id + */ +#define WMI_DEBUG_LOG_PARAM_VDEV_ENABLE 0x2 + +/** + * Disable the debug log for a given vdev. Value is vdev id + * All the log level for a given VDEV is disabled except the ERROR log messages + */ + +#define WMI_DEBUG_LOG_PARAM_VDEV_DISABLE 0x3 + +/** + * set vdev enable bitmap. value is the vden enable bitmap + */ +#define WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP 0x4 + +/** + * set a given log level to all the modules specified in the module bitmap. + * and set the log levle for all other modules to DBGLOG_ERR. + * value: log levelt to be set. + * module_id_bitmap : identifies the modules for which the log level should be set and + * modules for which the log level should be reset to DBGLOG_ERR. + */ +#define WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP 0x5 + +#define NUM_MODULES_PER_ENTRY ((sizeof(A_UINT32)) << 3) + +#define WMI_MODULE_ENABLE(pmid_bitmap,mod_id) \ + ( (pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY] |= \ + (1 << ((mod_id)%NUM_MODULES_PER_ENTRY)) ) + +#define WMI_MODULE_DISABLE(pmid_bitmap,mod_id) \ + ( (pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY] &= \ + ( ~(1 << ((mod_id)%NUM_MODULES_PER_ENTRY)) ) ) + +#define WMI_MODULE_IS_ENABLED(pmid_bitmap,mod_id) \ + ( ((pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY ] & \ + (1 << ((mod_id)%NUM_MODULES_PER_ENTRY)) ) != 0) + +#define MAX_MODULE_ID_BITMAP_WORDS 16 /* 16*32=512 module ids. should be more than sufficient */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param */ + A_UINT32 dbg_log_param; + /** param types are defined above */ + A_UINT32 value; + /* The below array will follow this tlv ->fixed length module_id_bitmap[] + A_UINT32 module_id_bitmap[MAX_MODULE_ID_BITMAP_WORDS]; + */ +} wmi_debug_log_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param */ + A_UINT32 param; /* Reserved for future use */ +} wmi_pdev_get_temperature_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param */ + A_INT32 value; /* temprature value in Celcius degree */ +} wmi_pdev_temperature_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; + A_UINT32 srv_ipv4; /* server IP */ + A_UINT32 start_lsb; /* starting address assigned to client */ + A_UINT32 num_client; /* number of clients we support */ +} wmi_set_dhcp_server_offload_cmd_fixed_param; + +typedef enum { + AP_RX_DATA_OFFLOAD = 0x00, + STA_RX_DATA_OFFLOAD = 0x01, +} wmi_ipa_offload_types; + +/** + * This command is sent from WLAN host driver to firmware for + * enabling/disabling IPA data-path offload features. + * + * + * Enabling data path offload to IPA(based on host INI configuration), example: + * when STA interface comes up, + * host->target: WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMD, + * (enable = 1, vdev_id = STA vdev id, offload_type = STA_RX_DATA_OFFLOAD) + * + * Disabling data path offload to IPA, example: + * host->target: WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMD, + * (enable = 0, vdev_id = STA vdev id, offload_type = STA_RX_DATA_OFFLOAD) + * + * + * This command is applicable only on the PCIE LL systems + * + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ipa_offload_enable_disable_cmd_fixed_param */ + A_UINT32 offload_type; /* wmi_ipa_offload_types enum values */ + A_UINT32 vdev_id; + A_UINT32 enable; /* 1 == enable, 0 == disable */ +} wmi_ipa_offload_enable_disable_cmd_fixed_param; + +typedef enum { + WMI_LED_FLASHING_PATTERN_NOT_CONNECTED = 0, + WMI_LED_FLASHING_PATTERN_CONNECTED = 1, + WMI_LED_FLASHING_PATTERN_RESERVED = 2, +} wmi_set_led_flashing_type; + +/** + The state of the LED GPIO control is determined by two 32 bit values(X_0 and X_1) to produce a 64 bit value. + Each 32 bit value consists of 4 bytes, where each byte defines the number of 50ms intervals that the GPIO will + remain at a predetermined state. The 64 bit value provides 8 unique GPIO timing intervals. The pattern starts + with the MSB of X_0 and continues to the LSB of X_1. After executing the timer interval of the LSB of X_1, the + pattern returns to the MSB of X_0 and repeats. The GPIO state for each timing interval alternates from Low to + High and the first interval of the pattern represents the time when the GPIO is Low. When a timing interval of + Zero is reached, it is skipped and moves on to the next interval. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param */ + A_UINT32 pattern_id; /* pattern identifier */ + A_UINT32 led_x0; /* led flashing parameter0 */ + A_UINT32 led_x1; /* led flashing parameter1 */ + A_UINT32 gpio_num; /* GPIO number */ +} wmi_set_led_flashing_cmd_fixed_param; + +/** + * The purpose of the multicast Domain Name System (mDNS) is to resolve host names to IP addresses + * within small networks that do not include a local name server. + * It utilizes essentially the same programming interfaces, packet formats and operating semantics + * as the unicast DNS, and the advantage is zero configuration service while no need for central or + * global server. + * Based on mDNS, the DNS-SD (Service Discovery) allows clients to discover a named list of services + * by type in a specified domain using standard DNS queries. + * Here, we provide the ability to advertise the available services by responding to mDNS queries. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; +} wmi_mdns_offload_cmd_fixed_param; + +#define WMI_MAX_MDNS_FQDN_LEN 64 +#define WMI_MAX_MDNS_RESP_LEN 512 +#define WMI_MDNS_FQDN_TYPE_GENERAL 0 +#define WMI_MDNS_FQDN_TYPE_UNIQUE 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param */ + A_UINT32 vdev_id; + /** type of fqdn, general or unique */ + A_UINT32 type; + /** length of fqdn */ + A_UINT32 fqdn_len; + /* Following this structure is the TLV byte stream of fqdn data of length fqdn_len + * A_UINT8 fqdn_data[]; // fully-qualified domain name to check if match with the received queries + */ +} wmi_mdns_set_fqdn_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param */ + A_UINT32 vdev_id; + /** Answer Resource Record count */ + A_UINT32 AR_count; + /** length of response */ + A_UINT32 resp_len; + /* Following this structure is the TLV byte stream of resp data of length resp_len + * A_UINT8 resp_data[]; // responses consisits of Resource Records + */ +} wmi_mdns_set_resp_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_mdns_get_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param */ + A_UINT32 vdev_id; + /** curTimestamp in milliseconds */ + A_UINT32 curTimestamp; + /** last received Query in milliseconds */ + A_UINT32 lastQueryTimestamp; + /** last sent Response in milliseconds */ + A_UINT32 lastResponseTimestamp; + /** stats of received queries */ + A_UINT32 totalQueries; + /** stats of macth queries */ + A_UINT32 totalMatches; + /** stats of responses */ + A_UINT32 totalResponses; + /** indicate the current status of mDNS offload */ + A_UINT32 status; +} wmi_mdns_stats_event_fixed_param; + +/** + * The purpose of the SoftAP authenticator offload is to offload the association and 4-way handshake process + * down to the firmware. When this feature is enabled, firmware can process the association/disassociation + * request and create/remove connection even host is suspended. + * 3 major components are offloaded: + * 1. ap-mlme. Firmware will process auth/deauth, association/disassociation request and send out response. + * 2. 4-way handshake. Firmware will send out m1/m3 and receive m2/m4. + * 3. key installation. Firmware will generate PMK from the psk info which is sent from the host and install PMK/GTK. + * Current implementation only supports WPA2 CCMP. + */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_ENABLE_CMDID */ + A_UINT32 vdev_id; + /** enable/disable sap auth offload */ + A_UINT32 enable; + /** sap ssid */ + wmi_ssid ap_ssid; + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; + /** sap channel */ + A_UINT32 channel; + /** length of psk */ + A_UINT32 psk_len; + /* Following this structure is the TLV byte stream of wpa passphrase data of length psk_len + * A_UINT8 psk[]; + */ +} wmi_sap_ofl_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_ADD_STA_EVENTID */ + A_UINT32 vdev_id; + /** aid (association id) of this station */ + A_UINT32 assoc_id; + /** peer station's mac addr */ + wmi_mac_addr peer_macaddr; + /** length of association request frame */ + A_UINT32 data_len; + /* Following this structure is the TLV byte stream of a whole association request frame of length data_len + * A_UINT8 bufp[]; + */ +} wmi_sap_ofl_add_sta_event_fixed_param; + +typedef enum { + SAP_OFL_DEL_STA_FLAG_NONE = 0x00, + SAP_OFL_DEL_STA_FLAG_RECONNECT = 0x01, +} wmi_sap_ofl_del_sta_flags; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_DEL_STA_EVENTID */ + A_UINT32 vdev_id; + /** aid (association id) of this station */ + A_UINT32 assoc_id; + /** peer station's mac addr */ + wmi_mac_addr peer_macaddr; + /** disassociation reason */ + A_UINT32 reason; + /** flags - wmi_sap_ofl_del_sta_flags */ + A_UINT32 flags; +} wmi_sap_ofl_del_sta_event_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /* Number of client failure connection attempt */ + A_UINT32 num_retry; + /*Time in milliseconds to record the client's failure connection attempts*/ + A_UINT32 retry_allow_time_ms; + /* + * Time in milliseconds to drop the connection request if + * client is blacklisted + */ + A_UINT32 blackout_time_ms; +} wmi_sap_set_blacklist_param_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_apfind_cmd_param */ + A_UINT32 data_len; /** length in byte of data[]. */ + /** This structure is used to send REQ binary blobs + * from application/service to firmware where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_apfind_cmd_param; + +typedef enum apfind_event_type_e { + APFIND_MATCH_EVENT = 0, + APFIND_WAKEUP_EVENT, +} APFIND_EVENT_TYPE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_apfind_event_hdr */ + A_UINT32 event_type; /** APFIND_EVENT_TYPE */ + A_UINT32 data_len; /** length in byte of data[]. */ + /** This structure is used to send event binary blobs + * from firmware to application/service and Host drv. + * Following this structure is the TLV: + * A_UINT8 data[]; // length in byte given by field data_len. + */ +} wmi_apfind_event_hdr; + +/** + * OCB DCC types and structures. + */ + +/** + * DCC types as described in ETSI TS 102 687 + * Type Format stepSize referenceValue numBits + * ------------------------------------------------------------------------- + * ndlType_acPrio INTEGER (0...7) 1 number 3 + * ndlType_controlLoop INTEGER (0...7) 1 0 3 + * ndlType_arrivalRate INTEGER (0..8191) 0.01 /s 0 13 + * ndlType_channelLoad INTEGER (0..1000) 0.1 % 0 % 10 + * ndlType_channelUse INTEGER (0..8000) 0.0125 % 0 % 13 + * ndlType_datarate INTEGER (0..7) Table 8 3 + * ndlType_distance INTEGER (0..4095) 1 m 0 12 + * ndlType_numberElements INTEGER (0..63) number 6 + * ndlType_packetDuration INTEGER (0..2047) TSYM 0 11 + * ndlType_packetInterval INTEGER (0..1023) 10 ms 0 10 + * ndlType_pathloss INTEGER (0..31) 0.1 1.0 5 + * ndlType_rxPower INTEGER (0..127) -0.5 dB -40 dBm 7 + * ndlType_snr INTEGER (0..127) 0.5 dB -10 dB 7 + * ndlType_timing INTEGER (0..4095) 10 ms 0 12 + * ndlType_txPower INTEGER (0..127) 0.5 dB -20 dBm 7 + * ndlType_ratio INTEGER (0..100) 1 % 0 % 7 + * ndlType_exponent INTEGER (0..100) 0.1 0 7 + * ndlType_queueStatus Enumeration Table A.2 1 + * ndlType_dccMechanism Bitset Table A.2 6 + * + * NOTE: All of following size macros (SIZE_NDLTYPE_ACPRIO through SIZE_BYTE) + * cannot be changed without breaking WMI compatibility. + * + * NOTE: For each of the types, one additional bit is allocated. This + * leftmost bit is used to indicate that the value is invalid. + */ +#define SIZE_NDLTYPE_ACPRIO (1 + 3) +#define SIZE_NDLTYPE_CONTROLLOOP (1 + 3) +#define SIZE_NDLTYPE_ARRIVALRATE (1 + 13) +#define SIZE_NDLTYPE_CHANNELLOAD (1 + 10) +#define SIZE_NDLTYPE_CHANNELUSE (1 + 13) +#define SIZE_NDLTYPE_DATARATE (1 + 3) +#define SIZE_NDLTYPE_DISTANCE (1 + 12) +#define SIZE_NDLTYPE_NUMBERELEMENTS (1 + 6) +#define SIZE_NDLTYPE_PACKETDURATION (1 + 11) +#define SIZE_NDLTYPE_PACKETINTERVAL (1 + 10) +#define SIZE_NDLTYPE_PATHLOSS (1 + 5) +#define SIZE_NDLTYPE_RXPOWER (1 + 7) +#define SIZE_NDLTYPE_SNR (1 + 7) +#define SIZE_NDLTYPE_TIMING (1 + 12) +#define SIZE_NDLTYPE_TXPOWER (1 + 7) +#define SIZE_NDLTYPE_RATIO (1 + 7) +#define SIZE_NDLTYPE_EXPONENT (1 + 7) +#define SIZE_NDLTYPE_QUEUESTATUS (1 + 1) +#define SIZE_NDLTYPE_DCCMECHANISM (1 + 6) +#define SIZE_BYTE (8) + +#define INVALID_ACPRIO ((1 << SIZE_NDLTYPE_ACPRIO) - 1) +#define INVALID_CONTROLLOOP ((1 << SIZE_NDLTYPE_CONTROLLOOP) - 1) +#define INVALID_ARRIVALRATE ((1 << SIZE_NDLTYPE_ARRIVALRATE) - 1) +#define INVALID_CHANNELLOAD ((1 << SIZE_NDLTYPE_CHANNELLOAD) - 1) +#define INVALID_CHANNELUSE ((1 << SIZE_NDLTYPE_CHANNELUSE) - 1) +#define INVALID_DATARATE ((1 << SIZE_NDLTYPE_DATARATE) - 1) +#define INVALID_DISTANCE ((1 << SIZE_NDLTYPE_DISTANCE) - 1) +#define INVALID_NUMBERELEMENTS ((1 << SIZE_NDLTYPE_NUMBERELEMENTS) - 1) +#define INVALID_PACKETDURATION ((1 << SIZE_NDLTYPE_PACKETDURATION) - 1) +#define INVALID_PACKETINTERVAL ((1 << SIZE_NDLTYPE_PACKETINTERVAL) - 1) +#define INVALID_PATHLOSS ((1 << SIZE_NDLTYPE_PATHLOSS) - 1) +#define INVALID_RXPOWER ((1 << SIZE_NDLTYPE_RXPOWER) - 1) +#define INVALID_SNR ((1 << SIZE_NDLTYPE_SNR) - 1) +#define INVALID_TIMING ((1 << SIZE_NDLTYPE_TIMING) - 1) +#define INVALID_TXPOWER ((1 << SIZE_NDLTYPE_TXPOWER) - 1) +#define INVALID_RATIO ((1 << SIZE_NDLTYPE_RATIO) - 1) +#define INVALID_EXPONENT ((1 << SIZE_NDLTYPE_EXPONENT) - 1) +#define INVALID_QUEUESTATS ((1 << SIZE_NDLTYPE_QUEUESTATUS) - 1) +#define INVALID_DCCMECHANISM ((1 << SIZE_NDLTYPE_DCCMECHANISM) - 1) + +/** + * The MCS_COUNT macro cannot be modified without breaking + * WMI compatibility. + */ +#define MCS_COUNT (8) + +/** + * Flags for ndlType_dccMechanism. + */ +typedef enum { + DCC_MECHANISM_TPC = 1, + DCC_MECHANISM_TRC = 2, + DCC_MECHANISM_TDC = 4, + DCC_MECHANISM_DSC = 8, + DCC_MECHANISM_TAC = 16, + DCC_MECHANISM_RESERVED = 32, + DCC_MECHANISM_ALL = 0x3f, +} wmi_dcc_ndl_type_dcc_mechanism; + +/** Values for ndlType_queueStatus. */ +typedef enum { + DCC_QUEUE_CLOSED = 0, + DCC_QUEUE_OPEN = 1, +} wmi_dcc_ndl_type_queue_status; + +/** + * For ndlType_acPrio, use the values in wmi_traffic_ac. + * Values for ndlType_datarate. + */ +typedef enum { + DCC_DATARATE_3_MBPS = 0, + DCC_DATARATE_4_5_MBPS = 1, + DCC_DATARATE_6_MBPS = 2, + DCC_DATARATE_9_MBPS = 3, + DCC_DATARATE_12_MBPS = 4, + DCC_DATARATE_18_MBPS = 5, + DCC_DATARATE_24_MBPS = 6, + DCC_DATARATE_27_MBPS = 7, +} wmi_dcc_ndl_type_datarate; + +/** Data structure for active state configuration. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config + */ + A_UINT32 tlv_header; + /** + * NDL_asStateId, ndlType_numberElements, 1+6 bits. + * NDL_asChanLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 state_info; + /** + * NDL_asDcc(AC_BK), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_BE), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_VI), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_VO), ndlType_dccMechanism, 1+6 bits. + */ + A_UINT32 as_dcc[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_DCCMECHANISM)]; + /** + * NDL_asTxPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 as_tx_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; + /** + * NDL_asPacketInterval(AC_BK), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_BE), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_VI), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_VO), ndlType_packetInterval, 1+10 bits. + */ + A_UINT32 as_packet_interval_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETINTERVAL)]; + /** + * NDL_asDatarate(AC_BK), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_BE), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_VI), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_VO), ndlType_datarate, 1+3 bits. + */ + A_UINT32 as_datarate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_DATARATE)]; + /** + * NDL_asCarrierSense(AC_BK), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_BE), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_VI), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_VO), ndlType_rxPower, 1+7 bits. + */ + A_UINT32 as_carrier_sense_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_RXPOWER)]; +} wmi_dcc_ndl_active_state_config; + +#define WMI_NDL_AS_STATE_ID_GET(ptr) WMI_GET_BITS((ptr)->state_info, 0, 7) +#define WMI_NDL_AS_STATE_ID_SET(ptr, val) WMI_SET_BITS((ptr)->state_info, 0, 7, val) +#define WMI_NDL_AS_CHAN_LOAD_GET(ptr) WMI_GET_BITS((ptr)->state_info, 7, 11) +#define WMI_NDL_AS_CHAN_LOAD_SET(ptr, val) WMI_SET_BITS((ptr)->state_info, 7, 11, val) +#define WMI_NDL_AS_DCC_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->as_dcc, acprio, SIZE_NDLTYPE_DCCMECHANISM) +#define WMI_NDL_AS_DCC_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->as_dcc, acprio, SIZE_NDLTYPE_DCCMECHANISM, val) +#define WMI_NDL_AS_TX_POWER_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->as_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_AS_TX_POWER_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->as_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) +#define WMI_NDL_AS_PACKET_INTERVAL_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->as_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL) +#define WMI_NDL_AS_PACKET_INTERVAL_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->as_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL, val) +#define WMI_NDL_AS_DATARATE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->as_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE) +#define WMI_NDL_AS_DATARATE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->as_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE, val) +#define WMI_NDL_AS_CARRIER_SENSE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->as_carrier_sense_ac, acprio, SIZE_NDLTYPE_RXPOWER) +#define WMI_NDL_AS_CARRIER_SENSE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->as_carrier_sense_ac, acprio, SIZE_NDLTYPE_RXPOWER, val) + +/** Data structure for EDCA/QOS parameters. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_qos_parameter */ + A_UINT32 tlv_header; + /** Arbitration Inter-Frame Spacing. Range: 2-15 */ + A_UINT32 aifsn; + /** Contention Window minimum. Range: 1 - 10 */ + A_UINT32 cwmin; + /** Contention Window maximum. Range: 1 - 10 */ + A_UINT32 cwmax; +} wmi_qos_parameter; + +/** Data structure for information specific to a channel. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_channel */ + A_UINT32 tlv_header; + A_UINT32 bandwidth; /* MHz units */ + wmi_mac_addr mac_address; +} wmi_ocb_channel; + +/** Data structure for an element of the schedule array. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_schedule_element */ + A_UINT32 tlv_header; + A_UINT32 channel_freq; /* MHz units */ + A_UINT32 total_duration; /* ms units */ + A_UINT32 guard_interval; /* ms units */ +} wmi_ocb_schedule_element; + +/** Data structure for OCB configuration. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** VDEV id(interface) that is being configured */ + A_UINT32 vdev_id; + A_UINT32 channel_count; + A_UINT32 schedule_size; + A_UINT32 flags; + + /** This is followed by a TLV array of wmi_channel. + * This is followed by a TLV array of wmi_ocb_channel. + * This is followed by a TLV array of wmi_qos_parameter. + * This is followed by a TLV array of wmi_dcc_ndl_chan. + * This is followed by a TLV array of wmi_dcc_ndl_active_state_config. + * This is followed by a TLV array of wmi_ocb_schedule_element. + */ +} wmi_ocb_set_config_cmd_fixed_param; + + +#define EXPIRY_TIME_IN_TSF_TIMESTAMP_OFFSET 0 +#define EXPIRY_TIME_IN_TSF_TIMESTAMP_MASK 1 + +#define WMI_OCB_EXPIRY_TIME_IN_TSF(ptr) \ + (((ptr)->flags & EXPIRY_TIME_IN_TSF_TIMESTAMP_MASK) >> EXPIRY_TIME_IN_TSF_TIMESTAMP_OFFSET) + + +/** Data structure for the response to the WMI_OCB_SET_CONFIG_CMDID command. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV id(interface)*/ + A_UINT32 vdev_id; + A_UINT32 status; +} wmi_ocb_set_config_resp_event_fixed_param; + +/* SIZE_UTC_TIME and SIZE_UTC_TIME_ERROR cannot be modified without breaking + * WMI compatibility. + */ +/* The size of the utc time in bytes. */ +#define SIZE_UTC_TIME (10) +/* The size of the utc time error in bytes. */ +#define SIZE_UTC_TIME_ERROR (5) + +/** Data structure to set the UTC time. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param */ + A_UINT32 tlv_header; + /*VDEV Identifier*/ + A_UINT32 vdev_id; + /** 10 bytes of the utc time. */ + A_UINT32 utc_time[WMI_PACKED_ARR_SIZE(SIZE_UTC_TIME, SIZE_BYTE)]; + /** 5 bytes of the time error. */ + A_UINT32 time_error[WMI_PACKED_ARR_SIZE(SIZE_UTC_TIME_ERROR, SIZE_BYTE)]; +} wmi_ocb_set_utc_time_cmd_fixed_param; + +#define WMI_UTC_TIME_GET(ptr, byte_index) wmi_packed_arr_get_bits((ptr)->utc_time, byte_index, SIZE_BYTE) +#define WMI_UTC_TIME_SET(ptr, byte_index, val) wmi_packed_arr_set_bits((ptr)->utc_time, byte_index, SIZE_BYTE, val) +#define WMI_TIME_ERROR_GET(ptr, byte_index) wmi_packed_arr_get_bits((ptr)->time_error, byte_index, SIZE_BYTE) +#define WMI_TIME_ERROR_SET(ptr, byte_index, val) wmi_packed_arr_set_bits((ptr)->time_error, byte_index, SIZE_BYTE, val) + +/** Data structure start the timing advertisement. The template for the + * timing advertisement frame follows this structure in the WMI command. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param */ + A_UINT32 tlv_header; + /*VDEV Identifier*/ + A_UINT32 vdev_id; + /** Number of times the TA is sent every 5 seconds. */ + A_UINT32 repeat_rate; + /** The frequency on which to transmit. */ + A_UINT32 channel_freq; /* MHz units */ + /** The offset into the template of the timestamp. */ + A_UINT32 timestamp_offset; + /** The offset into the template of the time value. */ + A_UINT32 time_value_offset; + /** The length of the timing advertisement template. The + * template is in the TLV data. */ + A_UINT32 timing_advert_template_length; + /** This is followed by a binary array containing the TA template. */ +} wmi_ocb_start_timing_advert_cmd_fixed_param; + +/** Data structure to stop the timing advertisement. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param */ + A_UINT32 tlv_header; + /*VDEV Identifier*/ + A_UINT32 vdev_id; + A_UINT32 channel_freq; /* MHz units */ +} wmi_ocb_stop_timing_advert_cmd_fixed_param; + +/** Data structure for the request for WMI_OCB_GET_TSF_TIMER_CMDID. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param */ + A_UINT32 tlv_header; + /*VDEV Identifier*/ + A_UINT32 vdev_id; + A_UINT32 reserved; +} wmi_ocb_get_tsf_timer_cmd_fixed_param; + +/** Data structure for the response to WMI_OCB_GET_TSF_TIMER_CMDID. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param */ + A_UINT32 tlv_header; + /*VDEV Identifier*/ + A_UINT32 vdev_id; + A_UINT32 tsf_timer_high; + A_UINT32 tsf_timer_low; +} wmi_ocb_get_tsf_timer_resp_event_fixed_param; + +/** Data structure for DCC stats configuration per channel. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_stats_per_channel */ + A_UINT32 tlv_header; + + /*VDEV Identifier*/ + A_UINT32 vdev_id; + + /** The channel for which this applies, 16 bits. + * The dcc_stats_bitmap, 8 bits. */ + A_UINT32 chan_info; + + /** Demodulation model parameters. + * + * NDL_snrBackoff(MCS0), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS1), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS2), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS3), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS4), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS5), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS6), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS7), ndlType_snr, 1+7 bits. + */ + A_UINT32 snr_backoff_mcs[WMI_PACKED_ARR_SIZE(MCS_COUNT, SIZE_NDLTYPE_SNR)]; + + /** Communication ranges. + * + * tx_power, ndlType_txPower, 1+7 bits. + * datarate, ndlType_datarate, 1+3 bits. + */ + A_UINT32 tx_power_datarate; + /** + * NDL_carrierSenseRange, ndlType_distance, 1+12 bits. + * NDL_estCommRange, ndlType_distance, 1+12 bits. + */ + A_UINT32 carrier_sense_est_comm_range; + + /** Channel load measures. */ + /** + * dccSensitivity, ndlType_rxPower, 1+7 bits. + * carrierSense, ndlType_rxPower, 1+7 bits. + * NDL_channelLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 dcc_stats; + /** + * NDL_packetArrivalRate, ndlType_arrivalRate, 1+13 bits. + * NDL_packetAvgDuration, ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 packet_stats; + /** + * NDL_channelBusyTime, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 channel_busy_time; + /** + *Transmit packet statistics. + * NDL_txPacketArrivalRate(AC_BK), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_BE), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_VI), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_VO), ndlType_arrivalRate, 1+13 bits. + */ + A_UINT32 tx_packet_arrival_rate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_ARRIVALRATE)]; + /** + * NDL_txPacketAvgDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 tx_packet_avg_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_txChannelUse(AC_BK), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_BE), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_VI), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_VO), ndlType_channelUse, 1+13 bits. + */ + A_UINT32 tx_channel_use_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_CHANNELUSE)]; + /** + * NDL_txSignalAvgPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 tx_signal_avg_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; +} wmi_dcc_ndl_stats_per_channel; + +#define WMI_NDL_STATS_SNR_BACKOFF_GET(ptr, mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_STATS_SNR_BACKOFF_SET(ptr, mcs, val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) +#define WMI_NDL_STATS_CHAN_FREQ_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 0, 16) +#define WMI_NDL_STATS_CHAN_FREQ_SET(ptr, val) WMI_SET_BITS((ptr)->chan_info, 0, 16, val) +#define WMI_NDL_STATS_DCC_STATS_BITMAP_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 16, 8) +#define WMI_NDL_STATS_DCC_STATS_BITMAP_SET(ptr, val) WMI_SET_BITS((ptr)->chan_info, 16, 8, val) +#define WMI_NDL_STATS_SNR_BACKOFF_GET(ptr, mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_STATS_SNR_BACKOFF_SET(ptr, mcs, val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) +#define WMI_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->tx_power_datarate, 0, 8) +#define WMI_TX_POWER_SET(ptr, val) WMI_SET_BITS((ptr)->tx_power_datarate, 0, 8, val) +#define WMI_TX_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->tx_power_datarate, 0, 4) +#define WMI_TX_DATARATE_SET(ptr, val) WMI_SET_BITS((ptr)->tx_power_datarate, 0, 4, val) +#define WMI_NDL_CARRIER_SENSE_RANGE_GET(ptr) WMI_GET_BITS((ptr)->carrier_sense_est_comm_range, 0, 13) +#define WMI_NDL_CARRIER_SENSE_RANGE_SET(ptr, val) WMI_SET_BITS((ptr)->carrier_sense_est_comm_range, 0, 13, val) +#define WMI_NDL_EST_COMM_RANGE_GET(ptr) WMI_GET_BITS((ptr)->carrier_sense_est_comm_range, 13, 13) +#define WMI_NDL_EST_COMM_RANGE_SET(ptr, val) WMI_SET_BITS((ptr)->carrier_sense_est_comm_range, 13, 13, val) +#define WMI_DCC_SENSITIVITY_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 0, 8) +#define WMI_DCC_SENSITIVITY_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_stats, 0, 8, val) +#define WMI_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 8, 8) +#define WMI_CARRIER_SENSE_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_stats, 8, 8, val) +#define WMI_NDL_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 16, 11) +#define WMI_NDL_CHANNEL_LOAD_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_stats, 16, 11, val) +#define WMI_NDL_PACKET_ARRIVAL_RATE_GET(ptr) WMI_GET_BITS((ptr)->packet_stats, 0, 14) +#define WMI_NDL_PACKET_ARRIVAL_RATE_SET(ptr, val) WMI_SET_BITS((ptr)->packet_stats, 0, 14, val) +#define WMI_NDL_PACKET_AVG_DURATION_GET(ptr) WMI_GET_BITS((ptr)->packet_stats, 14, 12) +#define WMI_NDL_PACKET_AVG_DURATION_SET(ptr, val) WMI_SET_BITS((ptr)->packet_stats, 14, 12, val) +#define WMI_NDL_CHANNEL_BUSY_TIME_GET(ptr) WMI_GET_BITS((ptr)->channel_busy_time, 0, 11) +#define WMI_NDL_CHANNEL_BUSY_TIME_SET(ptr, val) WMI_SET_BITS((ptr)->channel_busy_time, 0, 11, val) + +#define WMI_NDL_TX_PACKET_ARRIVAL_RATE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tx_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE) +#define WMI_NDL_TX_PACKET_ARRIVAL_RATE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tx_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE, val) +#define WMI_NDL_TX_PACKET_AVG_DURATION_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tx_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_TX_PACKET_AVG_DURATION_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tx_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_TX_CHANNEL_USE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tx_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE) +#define WMI_NDL_TX_CHANNEL_USE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tx_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE, val) +#define WMI_NDL_TX_SIGNAL_AVG_POWER_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tx_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_TX_SIGNAL_AVG_POWER_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tx_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) + +/** Bitmap for DCC stats. */ +typedef enum { + DCC_STATS_DEMODULATION_MODEL = 1, + DCC_STATS_COMMUNICATION_RANGES = 2, + DCC_STATS_CHANNEL_LOAD_MEASURES = 4, + DCC_STATS_TRANSMIT_PACKET_STATS = 8, + DCC_STATS_TRANSMIT_MODEL_PARAMETER = 16, + DCC_STATS_ALL = 0xff, +} wmi_dcc_stats_bitmap; + +/** Data structure for getting the DCC stats. */ +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /**The number of channels for which stats are being requested. */ + A_UINT32 num_channels; + /** This is followed by a TLV array of wmi_dcc_channel_stats_request. */ +} wmi_dcc_get_stats_cmd_fixed_param; + +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request. + */ + A_UINT32 tlv_header; + /** The channel for which this applies. */ + A_UINT32 chan_freq; /* MHz units */ + /** The DCC stats being requested. */ + A_UINT32 dcc_stats_bitmap; +} wmi_dcc_channel_stats_request; + +/** Data structure for the response with the DCC stats. */ +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** Number of channels in the response. */ + A_UINT32 num_channels; + /** This is followed by a TLV array of wmi_dcc_ndl_stats_per_channel. */ +} wmi_dcc_get_stats_resp_event_fixed_param; + +/** Data structure for clearing the DCC stats. */ +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 dcc_stats_bitmap; +} wmi_dcc_clear_stats_cmd_fixed_param; + +/** Data structure for the pushed DCC stats */ +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** The number of channels in the response. */ + A_UINT32 num_channels; + /** This is followed by a TLV array of wmi_dcc_ndl_stats_per_channel. */ +} wmi_dcc_stats_event_fixed_param; + +/** Data structure for updating NDL per channel. */ +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_chan + */ + A_UINT32 tlv_header; + /** + * Channel frequency, 16 bits + * NDL_numActiveState, ndlType_numberElements, 1+6 bits + */ + A_UINT32 chan_info; + /** + * NDL_minDccSampling, 10 bits. + * Maximum time interval between subsequent checks of the DCC rules. + */ + A_UINT32 ndl_min_dcc_sampling; + /** + * dcc_enable, 1 bit. + * dcc_stats_enable, 1 bit. + * dcc_stats_interval, 16 bits. + */ + A_UINT32 dcc_flags; + /** General DCC configuration. + * NDL_timeUp, ndlType_timing, 1+12 bits. + * NDL_timeDown, ndlType_timing, 1+12 bits. + */ + A_UINT32 general_config; + /** Transmit power thresholds. + * NDL_minTxPower, ndlType_txPower, 1+7 bits. + * NDL_maxTxPower, ndlType_txPower, 1+7 bits. + */ + /* see "ETSI TS 102 687" table above for units */ + A_UINT32 min_max_tx_power; + /** + * NDL_defTxPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + /* see "ETSI TS 102 687" table above for units */ + A_UINT32 def_tx_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; + /** Packet timing thresholds. + * NDL_maxPacketDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 max_packet_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_minPacketInterval, ndlType_packetInterval, 1+10 bits. + * NDL_maxPacketInterval, ndlType_packetInterval, 1+10 bits. + */ + A_UINT32 min_max_packet_interval; + /** + * NDL_defPacketInterval(AC_BK), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_BE), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_VI), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_VO), ndlType_packetInterval, 1+10 bits + */ + A_UINT32 def_packet_interval_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETINTERVAL)]; + /** Packet datarate thresholds. + * NDL_minDatarate, ndlType_datarate, 1+3 bits. + * NDL_maxDatarate, ndlType_datarate, 1+3 bits. + */ + A_UINT32 min_max_datarate; + /** + * NDL_defDatarate(AC_BK), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_BE), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_VI), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_VO), ndlType_datarate, 1+3 bits. + */ + A_UINT32 def_datarate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_DATARATE)]; + /** Receive signal thresholds. + * NDL_minCarrierSense, ndlType_rxPower, 1+7 bits. + * NDL_maxCarrierSense, ndlType_rxPower, 1+7 bits. + * NDL_defCarrierSense, ndlType_rxPower, 1+7 bits. + */ + A_UINT32 min_max_def_carrier_sense; + + /** Receive model parameter. + * NDL_defDccSensitivity, ndlType_rxPower, 1+7 bits. + * NDL_maxCsRange, ndlType_distance, 1+12 bits. + * NDL_refPathLoss, ndlType_pathloss, 1+5 bits. + */ + A_UINT32 receive_model_parameter; + + /** + * NDL_minSNR, ndlType_snr, 1+7 bits. + */ + A_UINT32 receive_model_parameter_2; + + /** Demodulation model parameters. + * NDL_snrBackoff(MCS0), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS1), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS2), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS3), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS4), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS5), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS6), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS7), ndlType_snr, 1+7 bits. + */ + A_UINT32 snr_backoff_mcs[WMI_PACKED_ARR_SIZE(MCS_COUNT, SIZE_NDLTYPE_SNR)]; + /** Transmit model parameters. + * NDL_tmPacketArrivalRate(AC_BK), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_BE), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_VI), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_VO), ndlType_arrivalRate, 1+13 bits. + */ + A_UINT32 tm_packet_arrival_rate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_ARRIVALRATE)]; + /** + * NDL_tmPacketAvgDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 tm_packet_avg_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_tmSignalAvgPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 tm_signal_avg_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; + /* NDL_tmMaxChannelUse, ndlType_channelUse, 1+13 bits. */ + A_UINT32 tm_max_channel_use; + /** + * NDL_tmChannelUse(AC_BK), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_BE), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_VI), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_VO), ndlType_channelUse, 1+13 bits. + */ + A_UINT32 tm_channel_use_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_CHANNELUSE)]; + /** Channel load thresholds. + * NDL_minChannelLoad, ndlType_channelLoad, 1+10 bits. + * NDL_maxChannelLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 min_max_channel_load; + /** Transmit queue parameters. + * NDL_numQueue, ndlType_acPrio, 1+3 bits. + * NDL_refQueueStatus(AC_BK), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_BE), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_VI), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_VO), ndlType_queueStatus, 1+1 bit. + */ + A_UINT32 transmit_queue_parameters; + /** + * NDL_refQueueLen(AC_BK), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_BE), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_VI), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_VO), ndlType_numberElements, 1+6 bits. + */ + A_UINT32 numberElements[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_NUMBERELEMENTS)]; +} wmi_dcc_ndl_chan; + +#define WMI_CHAN_FREQ_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 0, 16) +#define WMI_CHAN_FREQ_SET(ptr, val) WMI_SET_BITS((ptr)->chan_info, 0, 16, val) +#define WMI_NDL_NUM_ACTIVE_STATE_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 16, 7) +#define WMI_NDL_NUM_ACTIVE_STATE_SET(ptr, val) WMI_SET_BITS((ptr)->chan_info, 16, 7, val) + +#define WMI_NDL_MIN_DCC_SAMPLING_GET(ptr) WMI_GET_BITS((ptr)->ndl_min_dcc_sampling, 0, 10) +#define WMI_NDL_MIN_DCC_SAMPLING_SET(ptr, val) WMI_SET_BITS((ptr)->ndl_min_dcc_sampling, 0, 10, val) + +#define WMI_NDL_MEASURE_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->ndl_min_dcc_sampling, 10, 16) +#define WMI_NDL_MEASURE_INTERVAL_SET(ptr, val) WMI_SET_BITS((ptr)->ndl_min_dcc_sampling, 10, 16, val) + + +#define WMI_NDL_DCC_ENABLE_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 0, 1) +#define WMI_NDL_DCC_ENABLE_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_flags, 0, 1, val) +#define WMI_NDL_DCC_STATS_ENABLE_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 1, 1) +#define WMI_NDL_DCC_STATS_ENABLE_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_flags, 1, 1, val) +#define WMI_NDL_DCC_STATS_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 2, 16) +#define WMI_NDL_DCC_STATS_INTERVAL_SET(ptr, val) WMI_SET_BITS((ptr)->dcc_flags, 2, 16, val) + +#define WMI_NDL_TIME_UP_GET(ptr) WMI_GET_BITS((ptr)->general_config, 0, 13) +#define WMI_NDL_TIME_UP_SET(ptr, val) WMI_SET_BITS((ptr)->general_config, 0, 13, val) +#define WMI_NDL_TIME_DOWN_GET(ptr) WMI_GET_BITS((ptr)->general_config, 13, 13) +#define WMI_NDL_TIME_DOWN_SET(ptr, val) WMI_SET_BITS((ptr)->general_config, 13, 13, val) + +#define WMI_NDL_MIN_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->min_max_tx_power, 0, 8) +#define WMI_NDL_MIN_TX_POWER_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_tx_power, 0, 8, val) +#define WMI_NDL_MAX_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->min_max_tx_power, 8, 8) +#define WMI_NDL_MAX_TX_POWER_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_tx_power, 8, 8, val) + +#define WMI_NDL_DEF_TX_POWER_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->def_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_DEF_TX_POWER_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->def_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) + +#define WMI_NDL_MAX_PACKET_DURATION_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->max_packet_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_MAX_PACKET_DURATION_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->max_packet_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_MIN_PACKET_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->min_max_packet_interval, 0, 11) +#define WMI_NDL_MIN_PACKET_INTERVAL_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_packet_interval, 0, 11, val) +#define WMI_NDL_MAX_PACKET_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->min_max_packet_interval, 11, 11) +#define WMI_NDL_MAX_PACKET_INTERVAL_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_packet_interval, 11, 11, val) +#define WMI_NDL_DEF_PACKET_INTERVAL_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->def_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL) +#define WMI_NDL_DEF_PACKET_INTERVAL_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->def_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL, val) + +#define WMI_NDL_MIN_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->min_max_datarate, 0, 4) +#define WMI_NDL_MIN_DATARATE_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_datarate, 0, 4, val) +#define WMI_NDL_MAX_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->min_max_datarate, 4, 4) +#define WMI_NDL_MAX_DATARATE_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_datarate, 4, 4, val) +#define WMI_NDL_DEF_DATARATE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->def_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE) +#define WMI_NDL_DEF_DATARATE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->def_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE, val) + +#define WMI_NDL_MIN_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 0, 8) +#define WMI_NDL_MIN_CARRIER_SENSE_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 0, 8, val) +#define WMI_NDL_MAX_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 8, 8) +#define WMI_NDL_MAX_CARRIER_SENSE_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 8, 8, val) +#define WMI_NDL_DEF_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 16, 8) +#define WMI_NDL_DEF_CARRIER_SENSE_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 16, 8, val) + +#define WMI_NDL_DEF_DCC_SENSITIVITY_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 0, 8) +#define WMI_NDL_DEF_DCC_SENSITIVITY_SET(ptr, val) WMI_SET_BITS((ptr)->receive_model_parameter, 0, 8, val) +#define WMI_NDL_MAX_CS_RANGE_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 8, 13) +#define WMI_NDL_MAX_CS_RANGE_SET(ptr, val) WMI_SET_BITS((ptr)->receive_model_parameter, 8, 13, val) +#define WMI_NDL_REF_PATH_LOSS_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 21, 6) +#define WMI_NDL_REF_PATH_LOSS_SET(ptr, val) WMI_SET_BITS((ptr)->receive_model_parameter, 21, 6, val) + +#define WMI_NDL_MIN_SNR_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter_2, 0, 8) +#define WMI_NDL_MIN_SNR_SET(ptr, val) WMI_SET_BITS((ptr)->receive_model_parameter_2, 0, 8, val) + +#define WMI_NDL_SNR_BACKOFF_GET(ptr, mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_SNR_BACKOFF_SET(ptr, mcs, val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) + +#define WMI_NDL_TM_PACKET_ARRIVAL_RATE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tm_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE) +#define WMI_NDL_TM_PACKET_ARRIVAL_RATE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tm_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE, val) +#define WMI_NDL_TM_PACKET_AVG_DURATION_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tm_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_TM_PACKET_AVG_DURATION_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tm_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_TM_SIGNAL_AVG_POWER_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tm_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_TM_SIGNAL_AVG_POWER_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tm_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) +#define WMI_NDL_TM_MAX_CHANNEL_USE_GET(ptr) WMI_GET_BITS((ptr)->tm_max_channel_use, 0, 14) +#define WMI_NDL_TM_MAX_CHANNEL_USE_SET(ptr, val) WMI_SET_BITS((ptr)->tm_max_channel_use, 0, 14, val) +#define WMI_NDL_TM_CHANNEL_USE_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->tm_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE) +#define WMI_NDL_TM_CHANNEL_USE_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->tm_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE, val) + +#define WMI_NDL_MIN_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->min_max_channel_load, 0, 11) +#define WMI_NDL_MIN_CHANNEL_LOAD_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_channel_load, 0, 11, val) +#define WMI_NDL_MAX_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->min_max_channel_load, 11, 11) +#define WMI_NDL_MAX_CHANNEL_LOAD_SET(ptr, val) WMI_SET_BITS((ptr)->min_max_channel_load, 11, 11, val) + +#define WMI_NDL_NUM_QUEUE_GET(ptr) WMI_GET_BITS((ptr)->transmit_queue_parameters, 0, 4) +#define WMI_NDL_NUM_QUEUE_SET(ptr, val) WMI_SET_BITS((ptr)->transmit_queue_parameters, 0, 4, val) +#define WMI_NDL_REF_QUEUE_STATUS_GET(ptr, acprio) WMI_GET_BITS((ptr)->transmit_queue_parameters, (4 + (acprio * 2)), 2) +#define WMI_NDL_REF_QUEUE_STATUS_SET(ptr, acprio, val) WMI_SET_BITS((ptr)->transmit_queue_parameters, (4 + (acprio * 2)), 2, val) +#define WMI_NDL_REF_QUEUE_LEN_GET(ptr, acprio) wmi_packed_arr_get_bits((ptr)->numberElements, acprio, SIZE_NDLTYPE_NUMBERELEMENTS) +#define WMI_NDL_REF_QUEUE_LEN_SET(ptr, acprio, val) wmi_packed_arr_set_bits((ptr)->numberElements, acprio, SIZE_NDLTYPE_NUMBERELEMENTS, val) + +/** Data structure for updating the NDL. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** The number of channels in the request. */ + A_UINT32 num_channel; + /** This is followed by a TLV array of wmi_dcc_ndl_chan. */ + /** This is followed by a TLV array of wmi_dcc_ndl_active_state_config. */ +} wmi_dcc_update_ndl_cmd_fixed_param; + +typedef struct { + /** + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param + */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 status; +} wmi_dcc_update_ndl_resp_event_fixed_param; + +/* Actions for TSF timestamp */ +typedef enum { + TSF_TSTAMP_CAPTURE_REQ = 1, + TSF_TSTAMP_CAPTURE_RESET = 2, + TSF_TSTAMP_READ_VALUE = 3, +} wmi_tsf_tstamp_action; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* action type, refer to wmi_tsf_tstamp_action */ + A_UINT32 tsf_action; +} wmi_vdev_tsf_tstamp_action_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* low 32bit of tsf */ + A_UINT32 tsf_low; + /* high 32 bit of tsf */ + A_UINT32 tsf_high; +} wmi_vdev_tsf_report_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* unique id to identify the ie_data as defined by ieee 802.11 spec */ + A_UINT32 ie_id; + /* ie_len corresponds to num of bytes in ie_data[] */ + A_UINT32 ie_len; + /* + * Following this structure is the TLV byte stream of ie data of length + * buf_len: + * A_UINT8 ie_data[]; + */ +} wmi_vdev_set_ie_cmd_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param + * Set Preferred Channel List + */ + A_UINT32 tlv_header; + + /* # of channels to scan */ + A_UINT32 num_chan; + /* + * TLV (tag length value ) parameters follow the wmi_soc_set_pcl_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + */ +} wmi_soc_set_pcl_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param + * Set Hardware Mode */ + A_UINT32 tlv_header; + + /* Hardware Mode Index */ + A_UINT32 hw_mode_index; +} wmi_soc_set_hw_mode_cmd_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param + * Set Dual MAC Firmware Configuration + */ + A_UINT32 tlv_header; + + /* Concurrent scan configuration bits */ + A_UINT32 concurrent_scan_config_bits; + /* Firmware mode configuration bits */ + A_UINT32 fw_mode_config_bits; +} wmi_soc_set_dual_mac_config_cmd_fixed_param; + +typedef struct { + A_UINT32 num_tx_chains; + A_UINT32 num_rx_chains; + A_UINT32 reserved[2]; +} soc_num_tx_rx_chains; + +typedef struct { + A_UINT32 num_tx_chains_2g; + A_UINT32 num_rx_chains_2g; + A_UINT32 num_tx_chains_5g; + A_UINT32 num_rx_chains_5g; +} band_num_tx_rx_chains; + +typedef union { + soc_num_tx_rx_chains soc_txrx_chain_setting; + band_num_tx_rx_chains band_txrx_chain_setting; +} antenna_num_tx_rx_chains; + +typedef enum { + ANTENNA_MODE_DISABLED = 0x0, + ANTENNA_MODE_LOW_POWER_LOCATION_SCAN = 0x01, + /* reserved */ +} antenna_mode_reason; + +typedef struct { + /* + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param + */ + A_UINT32 tlv_header; + + /* the reason for setting antenna mode, refer antenna_mode_reason */ + A_UINT32 reason; + + /* + * The above reason parameter will select whether the following union + * is soc_num_tx_rx_chains or band_num_tx_rx_chains. + */ + antenna_num_tx_rx_chains num_txrx_chains_setting; +} wmi_soc_set_antenna_mode_cmd_fixed_param; + + +/** Data structure for information specific to a VDEV to MAC mapping. */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_vdev_mac_entry */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* VDEV ID */ + A_UINT32 mac_id; /* MAC ID */ +} wmi_soc_set_hw_mode_response_vdev_mac_entry; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param + * Set Hardware Mode Response Event **/ + A_UINT32 tlv_header; + + /* Status of set_hw_mode command + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 2 - ECANCELED; HW mode change canceled + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 5 - EPENDING; HW mode change is pending + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; + /* Configured Hardware Mode */ + A_UINT32 cfgd_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; + /* + * TLV (tag length value ) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_soc_set_hw_mode_response_event_fixed_param; + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param + * Hardware Mode Transition Event + */ + A_UINT32 tlv_header; + /* Original or old Hardware mode */ + A_UINT32 old_hw_mode_index; + /* New Hardware Mode */ + A_UINT32 new_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; + + /** + * TLV (tag length value ) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_soc_hw_mode_transition_event_fixed_param; + + +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param + * Set Dual MAC Config Response Event + */ + A_UINT32 tlv_header; + + /* Status for set_dual_mac_config command */ + /* + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; +} wmi_soc_set_dual_mac_config_response_event_fixed_param; + +typedef enum { + MAWC_MOTION_STATE_UNKNOWN, + MAWC_MOTION_STATE_STATIONARY, + MAWC_MOTION_STATE_WALK, + MAWC_MOTION_STATE_TRANSIT, +} MAWC_MOTION_STATE; + +typedef enum { + MAWC_SENSOR_STATUS_OK, + MAWC_SENSOR_STATUS_FAILED_TO_ENABLE, + MAWC_SENSOR_STATUS_SHUTDOWN, +} MAWC_SENSOR_STATUS; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param */ + A_UINT32 tlv_header; + /** new motion state, MAWC_MOTION_STATE */ + A_UINT32 motion_state; + /** status code of sensor, MAWC_SENSOR_STATUS */ + A_UINT32 sensor_status; +} wmi_mawc_sensor_report_ind_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param */ + A_UINT32 tlv_header; + /* enable(1) or disable(0) */ + A_UINT32 enable; +} wmi_mawc_enable_sensor_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* ratio of skipping suppressing scan, skip one out of x */ + A_UINT32 suppress_ratio; +} wmi_extscan_configure_mawc_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* ratio of exponential backoff, next = current + current*ratio/100 */ + A_UINT32 exp_backoff_ratio; + /* initial scan interval(msec) */ + A_UINT32 init_scan_interval; + /* max scan interval(msec) */ + A_UINT32 max_scan_interval; +} wmi_nlo_configure_mawc_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* data traffic load (kBps) to register CMC */ + A_UINT32 traffic_load_threshold; + /* RSSI threshold (dBm) to scan for Best AP */ + A_UINT32 best_ap_rssi_threshold; + /* high RSSI threshold adjustment in Stationary to suppress scan */ + A_UINT32 rssi_stationary_high_adjust; + /* low RSSI threshold adjustment in Stationary to suppress scan */ + A_UINT32 rssi_stationary_low_adjust; +} wmi_roam_configure_mawc_cmd_fixed_param; + +#define WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD 2 +#define WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER 10 + +typedef enum { + PACKET_FILTER_TYPE_INVALID = 0, + PACKET_FILTER_TYPE_FILTER_PKT, + PACKET_FILTER_TYPE_RESERVE_PKT, /* not used */ + PACKET_FILTER_TYPE_MAX_ENUM_SIZE +} WMI_PACKET_FILTER_FILTER_TYPE; + +typedef enum { + PACKET_FILTER_PROTO_TYPE_INVALID = 0, + + /* L2 header */ + PACKET_FILTER_PROTO_TYPE_MAC, + PACKET_FILTER_PROTO_TYPE_SNAP, + + /* L3 header (EtherType) */ + PACKET_FILTER_PROTO_TYPE_IPV4, + PACKET_FILTER_PROTO_TYPE_IPV6, + + /* L4 header (IP protocol) */ + PACKET_FILTER_PROTO_TYPE_UDP, + PACKET_FILTER_PROTO_TYPE_TCP, + PACKET_FILTER_PROTO_TYPE_ICMPV6, + + PACKET_FILTER_PROTO_TYPE_MAX +} WMI_PACKET_FILTER_PROTO_TYPE; + +typedef enum { + PACKET_FILTER_CMP_TYPE_INVALID = 0, + PACKET_FILTER_CMP_TYPE_EQUAL, + PACKET_FILTER_CMP_TYPE_MASK_EQUAL, + PACKET_FILTER_CMP_TYPE_NOT_EQUAL, + PACKET_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + PACKET_FILTER_CMP_TYPE_ADDRTYPE, + PACKET_FILTER_CMP_TYPE_MAX +} WMI_PACKET_FILTER_CMP_TYPE; + +typedef enum { + PACKET_FILTER_SET_INACTIVE = 0, + PACKET_FILTER_SET_ACTIVE +} WMI_PACKET_FILTER_ACTION; + +typedef enum { + PACKET_FILTER_SET_DISABLE = 0, + PACKET_FILTER_SET_ENABLE +} WMI_PACKET_FILTER_RUNTIME_ENABLE; + +typedef struct { + A_UINT32 proto_type; + A_UINT32 cmp_type; + A_UINT32 data_length; /* Length of the data to compare (units = bytes) */ + /* + * from start of the respective frame header ( + * units = bytes) + */ + A_UINT32 data_offset; + /* Data to compare, little-endian order */ + A_UINT32 compareData[WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD]; + /* Mask to be applied on rcvd packet data before compare, little-endian order */ + A_UINT32 dataMask[WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD]; +} WMI_PACKET_FILTER_PARAMS_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 filter_id; + A_UINT32 filter_action; /* WMI_PACKET_FILTER_ACTION */ + A_UINT32 filter_type; + A_UINT32 num_params; /* how many entries in paramsData are valid */ + A_UINT32 coalesce_time; /* not currently used - fill with 0x0 */ + WMI_PACKET_FILTER_PARAMS_TYPE paramsData[WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER]; +} WMI_PACKET_FILTER_CONFIG_CMD_fixed_param; + +/* enable / disable all filters within the specified vdev */ +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; /* WMI_PACKET_FILTER_RUNTIME_ENABLE */ +} WMI_PACKET_FILTER_ENABLE_CMD_fixed_param; + + +#define WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS 0 +#define WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS 9 + +#define WMI_LRO_INFO_TCP_FLAG_VALS_SET(tcp_flag_u32, tcp_flag_values) \ + WMI_SET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS, \ + WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS, \ + tcp_flag_values) +#define WMI_LRO_INFO_TCP_FLAG_VALS_GET(tcp_flag_u32) \ + WMI_GET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS, \ + WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS) + +#define WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS 9 +#define WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS 9 + +#define WMI_LRO_INFO_TCP_FLAGS_MASK_SET(tcp_flag_u32, tcp_flags_mask) \ + WMI_SET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS, \ + tcp_flags_mask) +#define WMI_LRO_INFO_TCP_FLAGS_MASK_GET(tcp_flag_u32) \ + WMI_GET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS) + +typedef struct { + A_UINT32 tlv_header; + /** + * @brief lro_enable - indicates whether lro is enabled + * [0] LRO Enable + */ + A_UINT32 lro_enable; + /** + * @brief tcp_flag_u32 - mask of which TCP flags to check and + * values to check for + * [8:0] TCP flag values - If the TCP flags from the packet do not match + * the values in this field after masking with TCP flags mask + * below,LRO eligible will not be set + * [17:9] TCP flags mask - Mask field for comparing the TCP values + * provided above with the TCP flags field in the received packet + * Use WMI_LRO_INFO_TCP_FLAG_VALS and WMI_LRO_INFO_TCP_FLAGS_MASK + * macros to isolate the mask field and values field that are packed + * into this u32 "word". + */ + A_UINT32 tcp_flag_u32; + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 0 to 3 + * + * In this and all the below toeplitz_hash fields, the bytes are + * specified in little-endian order. For example: + * toeplitz_hash_ipv4_0_3 bits 7:0 holds seed byte 0 + * toeplitz_hash_ipv4_0_3 bits 15:8 holds seed byte 1 + * toeplitz_hash_ipv4_0_3 bits 23:16 holds seed byte 2 + * toeplitz_hash_ipv4_0_3 bits 31:24 holds seed byte 3 + */ + A_UINT32 toeplitz_hash_ipv4_0_3; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 4 to 7 + */ + A_UINT32 toeplitz_hash_ipv4_4_7; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 8 to 11 + */ + A_UINT32 toeplitz_hash_ipv4_8_11; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 12 to 15 + */ + A_UINT32 toeplitz_hash_ipv4_12_15; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * byte 16 + */ + A_UINT32 toeplitz_hash_ipv4_16; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 0 to 3 + */ + A_UINT32 toeplitz_hash_ipv6_0_3; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 4 to 7 + */ + A_UINT32 toeplitz_hash_ipv6_4_7; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 8 to 11 + */ + A_UINT32 toeplitz_hash_ipv6_8_11; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 12 to 15 + */ + A_UINT32 toeplitz_hash_ipv6_12_15; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 16 to 19 + */ + A_UINT32 toeplitz_hash_ipv6_16_19; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 20 to 22 + */ + A_UINT32 toeplitz_hash_ipv6_20_23; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 24 to 27 + */ + A_UINT32 toeplitz_hash_ipv6_24_27; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 28 to 31 + */ + A_UINT32 toeplitz_hash_ipv6_28_31; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 32 to 35 + */ + A_UINT32 toeplitz_hash_ipv6_32_35; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 36 to 39 + */ + A_UINT32 toeplitz_hash_ipv6_36_39; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * byte 40 + */ + A_UINT32 toeplitz_hash_ipv6_40; +} wmi_lro_info_cmd_fixed_param; + +/* ADD NEW DEFS HERE */ + +/***************************************************************************** + * The following structures are deprecated. DO NOT USE THEM! + */ + +/** Max number of channels in the schedule. */ +#define OCB_CHANNEL_MAX (5) + +/* NOTE: Make sure these data structures are identical to those 9235 +* defined in sirApi.h */ + +typedef struct +{ + /** Arbitration Inter-Frame Spacing. Range: 2-15 */ + A_UINT32 aifsn; + /** Contention Window minimum. Range: 1 - 10 */ + A_UINT32 cwmin; + /** Contention Window maximum. Range: 1 - 10 */ + A_UINT32 cwmax; +} wmi_qos_params_t; + +typedef struct +{ + /** Channel frequency in MHz */ + A_UINT32 chan_freq; + /** Channel duration in ms */ + A_UINT32 duration; + /** Start guard interval in ms */ + A_UINT32 start_guard_interval; + /** End guard interval in ms */ + A_UINT32 end_guard_interval; + /** Transmit power in dBm, range 0 - 23 */ + A_UINT32 tx_power; + /** Transmit datarate in Mbps */ + A_UINT32 tx_rate; + /** QoS parameters for each AC */ + wmi_qos_params_t qos_params[WLAN_MAX_AC]; + /** 1 to enable RX stats for this channel, 0 otherwise */ + A_UINT32 rx_stats; +} wmi_ocb_channel_t; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** Number of valid channels in the channels array */ + A_UINT32 num_channels; + /** The array of channels */ + wmi_ocb_channel_t channels[OCB_CHANNEL_MAX]; + /** 1 to allow off-channel tx, 0 otherwise */ + A_UINT32 off_channel_tx; // Not supported +} wmi_ocb_set_sched_cmd_fixed_param; + +typedef struct { + /** Return status. 0 for success, non-zero otherwise */ + A_UINT32 status; +} wmi_ocb_set_sched_event_fixed_param; + +/** +* END DEPRECATED +*/ +#ifdef __cplusplus +} +#endif +#endif /*_WMI_UNIFIED_H_*/ +/**@}*/ diff --git a/target/inc/wmi_version.h b/target/inc/wmi_version.h new file mode 100644 index 0000000000..0c1b628cc3 --- /dev/null +++ b/target/inc/wmi_version.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * IMPORTANT NOTE: For all change to WMI Interface, the ABI version number _must_ be updated. + */ +/** Major version number is incremented when there are significant changes to WMI Interface that break compatibility. */ +#define __WMI_VER_MAJOR_ 1 +/** Minor version number is incremented when there are changes + * (however minor) to WMI Interface that break + * compatibility. */ +#define __WMI_VER_MINOR_ 0 +/** WMI revision number has to be incremented when there is a + * change that may or may not break compatibility */ +#define __WMI_REVISION_ 173 + +/** The Version Namespace should not be normally changed. Only + * host and firmware of the same WMI namespace will work + * together. + * For example, "QCA_ML" converts to 0x4C, 0x4D5F414351. + * where 'Q'=0x51, 'C'=0x43, 'A'=0x41, '_'=0x5F. 'M'=4D, 'L'=4C + */ +#define __NAMESPACE_0_ 0x5F414351 +#define __NAMESPACE_1_ 0x00004C4D +#define __NAMESPACE_2_ 0x00000000 +#define __NAMESPACE_3_ 0x00000000 + +/* Format of the version number. */ +#define WMI_VER_MAJOR_BIT_OFFSET 24 +#define WMI_VER_MINOR_BIT_OFFSET 0 + +#define WMI_VER_MAJOR_BIT_MASK 0xFF000000 +#define WMI_VER_MINOR_BIT_MASK 0x00FFFFFF + +/* Macros to extract the sw_version components. + */ +#define WMI_VER_GET_MAJOR(x) (((x) & WMI_VER_MAJOR_BIT_MASK)>>WMI_VER_MAJOR_BIT_OFFSET) +#define WMI_VER_GET_MINOR(x) (((x) & WMI_VER_MINOR_BIT_MASK)>>WMI_VER_MINOR_BIT_OFFSET) + +#define WMI_VER_GET_VERSION_0(major, minor) ( (( major << WMI_VER_MAJOR_BIT_OFFSET ) & WMI_VER_MAJOR_BIT_MASK) + (( minor << WMI_VER_MINOR_BIT_OFFSET ) & WMI_VER_MINOR_BIT_MASK) ) +/* + * The version has the following format: + * Bits 24-31: Major version + * Bits 0-23: Minor version + * Bits 0-31: Build number + * E.g. Build 1.1.7 would be represented as 0x01000001 for Major/Minor & 0x00000007 for buildnum. + * + * DO NOT split the following macro into multiple lines as this may confuse the build scripts. + */ +/* ABI Version. Reflects the version of binary interface exposed by Target firmware. */ +#define WMI_ABI_VERSION_0 WMI_VER_GET_VERSION_0(__WMI_VER_MAJOR_, __WMI_VER_MINOR_) +#define WMI_ABI_VERSION_1 __WMI_REVISION_ +#define WMI_ABI_VERSION_NS_0 __NAMESPACE_0_ +#define WMI_ABI_VERSION_NS_1 __NAMESPACE_1_ +#define WMI_ABI_VERSION_NS_2 __NAMESPACE_2_ +#define WMI_ABI_VERSION_NS_3 __NAMESPACE_3_ diff --git a/target/inc/wmix.h b/target/inc/wmix.h new file mode 100644 index 0000000000..e7c7934b67 --- /dev/null +++ b/target/inc/wmix.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains extensions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all + * extended commands and events. Extensions include useful commands + * that are not directly related to wireless activities. They may + * be hardware-specific, and they might not be supported on all + * implementations. + * + * Extended WMIX commands are encapsulated in a WMI message with + * cmd=WMI_EXTENSION_CMD. + */ + +#ifndef _WMIX_H_ +#define _WMIX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Extended WMI commands are those that are needed during wireless + * operation, but which are not really wireless commands. This allows, + * for instance, platform-specific commands. Extended WMI commands are + * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID. + * Extended WMI events are similarly embedded in a WMI event message with + * WMI_EVENT_ID=WMI_EXTENSION_EVENTID. + */ +typedef struct { + A_UINT32 commandId; +} POSTPACK WMIX_CMD_HDR; + +typedef enum { + WMIX_DSETOPEN_REPLY_CMDID = 0x2001, + WMIX_DSETDATA_REPLY_CMDID, + WMIX_HB_CHALLENGE_RESP_CMDID, + WMIX_DBGLOG_CFG_MODULE_CMDID, + WMIX_PROF_CFG_CMDID, /* 0x200a */ + WMIX_PROF_ADDR_SET_CMDID, + WMIX_PROF_START_CMDID, + WMIX_PROF_STOP_CMDID, + WMIX_PROF_COUNT_GET_CMDID, +} WMIX_COMMAND_ID; + +typedef enum { + WMIX_DSETOPENREQ_EVENTID = 0x3001, + WMIX_DSETCLOSE_EVENTID, + WMIX_DSETDATAREQ_EVENTID, + WMIX_HB_CHALLENGE_RESP_EVENTID, + WMIX_DBGLOG_EVENTID, + WMIX_PROF_COUNT_EVENTID, + WMIX_PKTLOG_EVENTID, +} WMIX_EVENT_ID; + +/* + * =============DataSet support================= + */ + +/* + * WMIX_DSETOPENREQ_EVENTID + * DataSet Open Request Event + */ +typedef struct { + A_UINT32 dset_id; + A_UINT32 targ_dset_handle; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */ +} POSTPACK WMIX_DSETOPENREQ_EVENT; + +/* + * WMIX_DSETCLOSE_EVENTID + * DataSet Close Event + */ +typedef struct { + A_UINT32 access_cookie; +} POSTPACK WMIX_DSETCLOSE_EVENT; + +/* + * WMIX_DSETDATAREQ_EVENTID + * DataSet Data Request Event + */ +typedef struct { + A_UINT32 access_cookie; + A_UINT32 offset; + A_UINT32 length; + A_UINT32 targ_buf; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */ +} WMIX_DSETDATAREQ_EVENT; + +typedef struct { + A_UINT32 status; + A_UINT32 targ_dset_handle; + A_UINT32 targ_reply_fn; + A_UINT32 targ_reply_arg; + A_UINT32 access_cookie; + A_UINT32 size; + A_UINT32 version; +} WMIX_DSETOPEN_REPLY_CMD; + +typedef struct { + A_UINT32 status; + A_UINT32 targ_buf; + A_UINT32 targ_reply_fn; + A_UINT32 targ_reply_arg; + A_UINT32 length; + A_UINT8 buf[1]; +} WMIX_DSETDATA_REPLY_CMD; + +/* + * =============Error Detection support================= + */ + +/* + * WMIX_HB_CHALLENGE_RESP_CMDID + * Heartbeat Challenge Response command + */ +typedef struct { + A_UINT32 cookie; + A_UINT32 source; +} WMIX_HB_CHALLENGE_RESP_CMD; + +/* + * WMIX_HB_CHALLENGE_RESP_EVENTID + * Heartbeat Challenge Response Event + */ +#define WMIX_HB_CHALLENGE_RESP_EVENT WMIX_HB_CHALLENGE_RESP_CMD + +/* + * =============Target Profiling support================= + */ + +typedef struct { + A_UINT32 period; /* Time (in 30.5us ticks) between samples */ + A_UINT32 nbins; +} WMIX_PROF_CFG_CMD; + +typedef struct { + A_UINT32 addr; +} WMIX_PROF_ADDR_SET_CMD; + +/* + * Target responds to Hosts's earlier WMIX_PROF_COUNT_GET_CMDID request + * using a WMIX_PROF_COUNT_EVENT with + * addr set to the next address + * count set to the corresponding count + */ +typedef struct { + A_UINT32 addr; + A_UINT32 count; +} WMIX_PROF_COUNT_EVENT; + +#ifdef __cplusplus +} +#endif +#endif /* _WMIX_H_ */ diff --git a/uapi/linux/a_debug.h b/uapi/linux/a_debug.h new file mode 100644 index 0000000000..62931060cf --- /dev/null +++ b/uapi/linux/a_debug.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _A_DEBUG_H_ +#define _A_DEBUG_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include "osapi_linux.h" + +/* standard debug print masks bits 0..7 */ +#define ATH_DEBUG_ERR (1 << 0) /* errors */ +#define ATH_DEBUG_WARN (1 << 1) /* warnings */ +#define ATH_DEBUG_INFO (1 << 2) /* informational (module startup info) */ +#define ATH_DEBUG_TRC (1 << 3) /* generic function call tracing */ +#define ATH_DEBUG_RSVD1 (1 << 4) +#define ATH_DEBUG_RSVD2 (1 << 5) +#define ATH_DEBUG_RSVD3 (1 << 6) +#define ATH_DEBUG_RSVD4 (1 << 7) + +#define ATH_DEBUG_MASK_DEFAULTS (ATH_DEBUG_ERR | ATH_DEBUG_WARN) +#define ATH_DEBUG_ANY 0xFFFF + +/* other aliases used throughout */ +#define ATH_DEBUG_ERROR ATH_DEBUG_ERR +#define ATH_LOG_ERR ATH_DEBUG_ERR +#define ATH_LOG_INF ATH_DEBUG_INFO +#define ATH_LOG_TRC ATH_DEBUG_TRC +#define ATH_DEBUG_TRACE ATH_DEBUG_TRC +#define ATH_DEBUG_INIT ATH_DEBUG_INFO + +/* bits 8..31 are module-specific masks */ +#define ATH_DEBUG_MODULE_MASK_SHIFT 8 + +/* macro to make a module-specific masks */ +#define ATH_DEBUG_MAKE_MODULE_MASK(index) (1 << (ATH_DEBUG_MODULE_MASK_SHIFT + (index))) + +void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, + char *pDescription); + +/* Debug support on a per-module basis + * + * Usage: + * + * Each module can utilize it's own debug mask variable. A set of commonly used + * masks are provided (ERRORS, WARNINGS, TRACE etc..). It is up to each module + * to define module-specific masks using the macros above. + * + * Each module defines a single debug mask variable debug_XXX where the "name" of the module is + * common to all C-files within that module. This requires every C-file that includes a_debug.h + * to define the module name in that file. + * + * Example: + * + * #define ATH_MODULE_NAME htc + * #include "a_debug.h" + * + * This will define a debug mask structure called debug_htc and all debug macros will reference this + * variable. + * + * A module can define module-specific bit masks using the ATH_DEBUG_MAKE_MODULE_MASK() macro: + * + * #define ATH_DEBUG_MY_MASK1 ATH_DEBUG_MAKE_MODULE_MASK(0) + * #define ATH_DEBUG_MY_MASK2 ATH_DEBUG_MAKE_MODULE_MASK(1) + * + * The instantiation of the debug structure should be made by the module. When a module is + * instantiated, the module can set a description string, a default mask and an array of description + * entries containing information on each module-defined debug mask. + * NOTE: The instantiation is statically allocated, only one instance can exist per module. + * + * Example: + * + * + * #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) + * + * #ifdef DEBUG + * static ATH_DEBUG_MASK_DESCRIPTION bmi_debug_desc[] = { + * { ATH_DEBUG_BMI , "BMI Tracing"}, <== description of the module specific mask + * }; + * + * ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi, + * "bmi" <== module name + * "Boot Manager Interface", <== description of module + * ATH_DEBUG_MASK_DEFAULTS, <== defaults + * ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc), + * bmi_debug_desc); + * + * #endif + * + * A module can optionally register it's debug module information in order for other tools to change the + * bit mask at runtime. A module can call A_REGISTER_MODULE_DEBUG_INFO() in it's module + * init code. This macro can be called multiple times without consequence. The debug info maintains + * state to indicate whether the information was previously registered. + * + * */ + +#define ATH_DEBUG_MAX_MASK_DESC_LENGTH 32 +#define ATH_DEBUG_MAX_MOD_DESC_LENGTH 64 + +typedef struct { + A_UINT32 Mask; + A_CHAR Description[ATH_DEBUG_MAX_MASK_DESC_LENGTH]; +} ATH_DEBUG_MASK_DESCRIPTION; + +#define ATH_DEBUG_INFO_FLAGS_REGISTERED (1 << 0) + +typedef struct _ATH_DEBUG_MODULE_DBG_INFO { + struct _ATH_DEBUG_MODULE_DBG_INFO *pNext; + A_CHAR ModuleName[16]; + A_CHAR ModuleDescription[ATH_DEBUG_MAX_MOD_DESC_LENGTH]; + A_UINT32 Flags; + A_UINT32 CurrentMask; + int MaxDescriptions; + ATH_DEBUG_MASK_DESCRIPTION *pMaskDescriptions; /* pointer to array of descriptions */ +} ATH_DEBUG_MODULE_DBG_INFO; + +#define ATH_DEBUG_DESCRIPTION_COUNT(d) (int)((sizeof((d))) / (sizeof(ATH_DEBUG_MASK_DESCRIPTION))) + +#define GET_ATH_MODULE_DEBUG_VAR_NAME(s) _XGET_ATH_MODULE_NAME_DEBUG_(s) +#define GET_ATH_MODULE_DEBUG_VAR_MASK(s) _XGET_ATH_MODULE_NAME_DEBUG_(s).CurrentMask +#define _XGET_ATH_MODULE_NAME_DEBUG_(s) debug_ ## s + +#ifdef DEBUG + +/* for source files that will instantiate the debug variables */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions) \ + ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) = \ + {NULL,(name),(moddesc),0,(initmask),count,(descriptions)} + +#ifdef ATH_MODULE_NAME +extern ATH_DEBUG_MODULE_DBG_INFO +GET_ATH_MODULE_DEBUG_VAR_NAME(ATH_MODULE_NAME); +#define AR_DEBUG_LVL_CHECK(lvl) (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (lvl)) +#endif /* ATH_MODULE_NAME */ + +#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl) GET_ATH_MODULE_DEBUG_VAR_MASK(s) = (lvl) + +#define ATH_DEBUG_DECLARE_EXTERN(s) \ + extern ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) + +#define AR_DEBUG_PRINTBUF(buffer, length, desc) debug_dump_bytes(buffer,length,desc) + +#define AR_DEBUG_ASSERT A_ASSERT + +void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +#ifdef A_SIMOS_DEVHOST +#define A_DUMP_MODULE_DEBUG_INFO(s) a_dump_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#define A_REGISTER_MODULE_DEBUG_INFO(s) a_register_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#else +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) +#endif + +#else /* !DEBUG */ +/* NON DEBUG */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions) +#define AR_DEBUG_LVL_CHECK(lvl) 0 +#define AR_DEBUG_PRINTBUF(buffer, length, desc) +#define AR_DEBUG_ASSERT(test) +#define ATH_DEBUG_DECLARE_EXTERN(s) +#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl) +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) + +#endif + +#if defined(__linux__) && !defined(LINUX_EMULATION) +#include "debug_linux.h" +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/uapi/linux/a_types.h b/uapi/linux/a_types.h new file mode 100644 index 0000000000..b47f4a8390 --- /dev/null +++ b/uapi/linux/a_types.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* depot/sw/qca_main/perf_pwr_offload/drivers/host/include/a_types.h#7 - integrate change 1327637 (ktext) */ +/* ============================================================================== */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ + +#ifndef _A_TYPES_H_ +#define _A_TYPES_H_ +#include + +typedef unsigned int A_UINT32; +typedef unsigned long long A_UINT64; +typedef unsigned short A_UINT16; +typedef unsigned char A_UINT8; +typedef int A_INT32; +typedef short A_INT16; +typedef char A_INT8; +typedef unsigned char A_UCHAR; +typedef char A_CHAR; +typedef _Bool A_BOOL; + +#endif /* _ATHTYPES_H_ */ diff --git a/uapi/linux/athstartpack.h b/uapi/linux/athstartpack.h new file mode 100644 index 0000000000..c6c051eb29 --- /dev/null +++ b/uapi/linux/athstartpack.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ATHSTARTPACK_H +#define _ATHSTARTPACK_H + +#if defined(LINUX) || defined(__linux__) +#include "osapi_linux.h" +#endif /* LINUX */ + +#ifdef QNX +#endif /* QNX */ + +#if __LONG_MAX__ == __INT_MAX__ +/* 32-bit compilation */ +#define PREPACK64 +#define POSTPACK64 +#else +/* 64-bit compilation */ +#define PREPACK64 PREPACK +#define POSTPACK64 POSTPACK +#endif + +#endif /* _ATHSTARTPACK_H */ diff --git a/uapi/linux/dbglog_common.h b/uapi/linux/dbglog_common.h new file mode 100644 index 0000000000..152862fa66 --- /dev/null +++ b/uapi/linux/dbglog_common.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_COMMON_H_ +#define _DBGLOG_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dbglog_id.h" +#include "dbglog.h" + +#define MAX_DBG_MSGS 256 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DBGLOG_PRINT_PREFIX "FWLOG: " + +/* Handy Macros to read data length and type from FW */ +#define WLAN_DIAG_0_TYPE_S 0 +#define WLAN_DIAG_0_TYPE 0x000000ff +#define WLAN_DIAG_0_TYPE_GET(x) WMI_F_MS(x, WLAN_DIAG_0_TYPE) +#define WLAN_DIAG_0_TYPE_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_TYPE) +/* bits 8-15 reserved */ + +/* length includes the size of wlan_diag_data */ +#define WLAN_DIAG_0_LEN_S 16 +#define WLAN_DIAG_0_LEN 0xffff0000 +#define WLAN_DIAG_0_LEN_GET(x) WMI_F_MS(x, WLAN_DIAG_0_LEN) +#define WLAN_DIAG_0_LEN_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_LEN) + +#define CNSS_DIAG_SLEEP_INTERVAL 5 /* In secs */ + +#define ATH6KL_FWLOG_MAX_ENTRIES 20 +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DIAG_WLAN_DRIVER_UNLOADED 6 +#define DIAG_WLAN_DRIVER_LOADED 7 +#define DIAG_TYPE_LOGS 1 +#define DIAG_TYPE_EVENTS 2 + +typedef enum { + DBGLOG_PROCESS_DEFAULT = 0, + DBGLOG_PROCESS_PRINT_RAW, /* print them in debug view */ + DBGLOG_PROCESS_POOL_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_NET_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_MAX, +} dbglog_process_t; + +enum cnss_diag_type { + DIAG_TYPE_FW_EVENT, /* send fw event- to diag */ + DIAG_TYPE_FW_LOG, /* send log event- to diag */ + DIAG_TYPE_FW_DEBUG_MSG, /* send dbg message- to diag */ + DIAG_TYPE_INIT_REQ, /* cnss_diag initialization- from diag */ + DIAG_TYPE_FW_MSG, /* fw msg command-to diag */ + DIAG_TYPE_HOST_MSG, /* host command-to diag */ + DIAG_TYPE_CRASH_INJECT, /*crash inject-from diag */ + DIAG_TYPE_DBG_LEVEL, /* DBG LEVEL-from diag */ +}; + +enum wlan_diag_config_type { + DIAG_VERSION_INFO, +}; + +enum wlan_diag_frame_type { + WLAN_DIAG_TYPE_CONFIG, + WLAN_DIAG_TYPE_EVENT, + WLAN_DIAG_TYPE_LOG, + WLAN_DIAG_TYPE_MSG, + WLAN_DIAG_TYPE_LEGACY_MSG, +}; + +/* log/event are always 32-bit aligned. Padding is inserted after + * optional payload to satisify this requirement */ +struct wlan_diag_data { + unsigned int word0; /* type, length */ + unsigned int target_time; + unsigned int code; /* Diag log or event Code */ + uint8_t payload[0]; +}; + +struct dbglog_slot { + unsigned int diag_type; + unsigned int timestamp; + unsigned int length; + unsigned int dropped; + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + uint8_t payload[0]; +} __packed; + +typedef struct event_report_s { + unsigned int diag_type; + unsigned short event_id; + unsigned short length; +} event_report_t; + +/* + * Custom debug_print handlers + * Args: + * module Id + * vap id + * debug msg id + * Time stamp + * no of arguments + * pointer to the buffer holding the args + */ +typedef A_BOOL (*module_dbg_print)(A_UINT32, A_UINT16, A_UINT32, + A_UINT32, A_UINT16, A_UINT32 *); + +/** Register module specific dbg print*/ +void dbglog_reg_modprint(A_UINT32 mod_id, module_dbg_print printfn); + +#ifdef __cplusplus +} +#endif + +#endif /* _DBGLOG_COMMON_H_ */ diff --git a/uapi/linux/debug_linux.h b/uapi/linux/debug_linux.h new file mode 100644 index 0000000000..57c3590efb --- /dev/null +++ b/uapi/linux/debug_linux.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DEBUG_LINUX_H_ +#define _DEBUG_LINUX_H_ + +/* macro to remove parens */ +#define ATH_PRINTX_ARG(arg ...) arg + +#ifdef DEBUG +/* NOTE: the AR_DEBUG_PRINTF macro is defined here to handle special handling of variable arg macros + * which may be compiler dependent. */ +#define AR_DEBUG_PRINTF(mask, args) do { \ + if (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (mask)) { \ + A_LOGGER(mask, ATH_MODULE_NAME, ATH_PRINTX_ARG args); \ + } \ +} while (0) +#else +/* on non-debug builds, keep in error and warning messages in the driver, all other + * message tracing will get compiled out */ +#define AR_DEBUG_PRINTF(mask, args) \ + if ((mask) & (ATH_DEBUG_ERR | ATH_DEBUG_WARN)) { A_PRINTF(ATH_PRINTX_ARG args); } + +#endif + +#endif /* _DEBUG_LINUX_H_ */ diff --git a/uapi/linux/osapi_linux.h b/uapi/linux/osapi_linux.h new file mode 100644 index 0000000000..e0420bc12e --- /dev/null +++ b/uapi/linux/osapi_linux.h @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ------------------------------------------------------------------------------ */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* ------------------------------------------------------------------------------ */ + +#ifndef _OSAPI_LINUX_H_ +#define _OSAPI_LINUX_H_ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* #include */ +#include "a_types.h" + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((A_UINT8 *)(dst), (src), (len)) +#define A_MEMZERO(addr, len) memset(addr, 0, len) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#if defined(ANDROID_ENV) && defined(CONFIG_ANDROID_LOGGER) +extern unsigned int enablelogcat; +extern int android_logger_lv(void *module, int mask); +enum logidx { LOG_MAIN_IDX = 0 }; +extern int logger_write(const enum logidx idx, + const unsigned char prio, + const char __kernel *const tag, + const char __kernel *const fmt, ...); +#define A_ANDROID_PRINTF(mask, module, tags, args ...) do { \ + if (enablelogcat) \ + logger_write(LOG_MAIN_IDX, android_logger_lv(module, mask), tags, args); \ + else \ + printk(KERN_ALERT args); \ +} while (0) +#ifdef DEBUG +#define A_LOGGER_MODULE_NAME(x) # x +#define A_LOGGER(mask, mod, args ...) \ + A_ANDROID_PRINTF(mask, &GET_ATH_MODULE_DEBUG_VAR_NAME(mod), "ar6k_" A_LOGGER_MODULE_NAME(mod), args); +#endif +#define A_PRINTF(args ...) A_ANDROID_PRINTF(ATH_DEBUG_INFO, NULL, "ar6k_driver", args) +#else +#define A_LOGGER(mask, mod, args ...) printk(args) +#define A_PRINTF(args ...) printk(args) +#endif /* ANDROID */ +#define A_PRINTF_LOG(args ...) printk(args) +#define A_SNPRINTF(buf, len, args ...) snprintf (buf, len, args) + +/* + * Timer Functions + */ +#define A_MSLEEP(msecs) \ + { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout((HZ * (msecs)) / 1000); \ + set_current_state(TASK_RUNNING); \ + } + +typedef struct timer_list A_TIMER; + +/* + * Wait Queue related functions + */ +#ifndef wait_event_interruptible_timeout +#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 /* wait_event_interruptible_timeout */ + +#ifdef DEBUG +#ifdef A_SIMOS_DEVHOST +extern unsigned int panic_on_assert; +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,# expr); \ + if (panic_on_assert) panic(# expr); \ + } +#else +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s \n",__FILE__, __LINE__,# expr); \ + } +#endif +#else +#define A_ASSERT(expr) +#endif /* DEBUG */ + +#ifdef ANDROID_ENV +struct firmware; +int android_request_firmware(const struct firmware **firmware_p, + const char *filename, struct device *device); +void android_release_firmware(const struct firmware *firmware); +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) android_request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) android_release_firmware(_pf) +#else +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) release_firmware(_pf) +#endif + +/* + * Network buffer queue support + */ +typedef struct sk_buff_head A_NETBUF_QUEUE_T; + +#define A_NETBUF_FREE(bufPtr) \ + a_netbuf_free(bufPtr) +#define A_NETBUF_LEN(bufPtr) \ + a_netbuf_to_len(bufPtr) +#define A_NETBUF_PUSH(bufPtr, len) \ + a_netbuf_push(bufPtr, len) +#define A_NETBUF_PUT(bufPtr, len) \ + a_netbuf_put(bufPtr, len) +#define A_NETBUF_TRIM(bufPtr,len) \ + a_netbuf_trim(bufPtr, len) +#define A_NETBUF_PULL(bufPtr, len) \ + a_netbuf_pull(bufPtr, len) +#define A_NETBUF_HEADROOM(bufPtr) \ + a_netbuf_headroom(bufPtr) +#define A_NETBUF_SETLEN(bufPtr,len) \ + a_netbuf_setlen(bufPtr, len) + +/* Add data to end of a buffer */ +#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \ + a_netbuf_put_data(bufPtr, srcPtr, len) + +/* Add data to start of the buffer */ +#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \ + a_netbuf_push_data(bufPtr, srcPtr, len) + +/* Remove data at start of the buffer */ +#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \ + a_netbuf_pull_data(bufPtr, dstPtr, len) + +/* Remove data from the end of the buffer */ +#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \ + a_netbuf_trim_data(bufPtr, dstPtr, len) + +/* View data as "size" contiguous bytes of type "t" */ +#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \ + (t )( ((struct skbuf *)(bufPtr))->data) + +/* return the beginning of the headroom for the buffer */ +#define A_NETBUF_HEAD(bufPtr) \ + ((((struct sk_buff *)(bufPtr))->head)) + +/* + * OS specific network buffer access routines + */ +void a_netbuf_free(void *bufPtr); +void *a_netbuf_to_data(void *bufPtr); +A_UINT32 a_netbuf_to_len(void *bufPtr); +A_STATUS a_netbuf_push(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_put(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_pull(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_trim(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_setlen(void *bufPtr, A_INT32 len); +A_INT32 a_netbuf_headroom(void *bufPtr); +void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt); +void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt); +void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q); + +#ifdef QCA_PARTNER_PLATFORM +#include "ath_carr_pltfrm.h" +#endif /* QCA_PARTNER_PLATFORM */ + +#else /* __KERNEL__ */ + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#ifndef INLINE +#define INLINE __inline__ +#endif +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#ifndef INLINE +#define INLINE __inline +#endif +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((dst), (src), (len)) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMZERO(addr, len) memset((addr), 0, (len)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#ifdef ANDROID +#ifndef err +#include +#define err(_s, args ...) do { \ + fprintf(stderr, "%s: line %d ", __FILE__, __LINE__); \ + fprintf(stderr, args); fprintf(stderr, ": %d\n", errno); \ + exit(_s); } while (0) +#endif +#else +#include +#endif + +#endif /* __KERNEL__ */ + +#endif /* _OSAPI_LINUX_H_ */ diff --git a/uapi/linux/pktlog_ac_fmt.h b/uapi/linux/pktlog_ac_fmt.h new file mode 100644 index 0000000000..bde0d3e6fe --- /dev/null +++ b/uapi/linux/pktlog_ac_fmt.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef REMOVE_PKT_LOG +#ifndef _PKTLOG_FMT_H_ +#define _PKTLOG_FMT_H_ + +#define CUR_PKTLOG_VER 10010 /* Packet log version */ +#define PKTLOG_MAGIC_NUM 7735225 + +#ifdef __linux__ +#define PKTLOG_PROC_DIR "ath_pktlog" +#define PKTLOG_PROC_SYSTEM "system" +#define WLANDEV_BASENAME "cld" +#endif + +#ifdef WIN32 +#pragma pack(push, pktlog_fmt, 1) +#define __ATTRIB_PACK +#elif defined(__EFI__) +#define __ATTRIB_PACK +#else +#ifndef __ATTRIB_PACK +#define __ATTRIB_PACK __attribute__ ((packed)) +#endif +#endif +#include +/* + * Each packet log entry consists of the following fixed length header + * followed by variable length log information determined by log_type + */ + +struct ath_pktlog_hdr { + uint16_t flags; + uint16_t missed_cnt; + uint16_t log_type; + uint16_t size; + uint32_t timestamp; +#ifdef HELIUMPLUS + uint32_t type_specific_data; +#endif +} __ATTRIB_PACK; + +#define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff +#define ATH_PKTLOG_HDR_FLAGS_SHIFT 0 +#define ATH_PKTLOG_HDR_FLAGS_OFFSET 0 +#define ATH_PKTLOG_HDR_MISSED_CNT_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_MISSED_CNT_SHIFT 16 +#define ATH_PKTLOG_HDR_MISSED_CNT_OFFSET 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_MASK 0xffff +#define ATH_PKTLOG_HDR_LOG_TYPE_SHIFT 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_OFFSET 1 +#define ATH_PKTLOG_HDR_SIZE_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_SIZE_SHIFT 16 +#define ATH_PKTLOG_HDR_SIZE_OFFSET 1 +#define ATH_PKTLOG_HDR_TIMESTAMP_OFFSET 2 +#define ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET 3 + +/** + * enum - Pktlog flag field details + * packet origin [1:0] + * 00 - Local + * 01 - Remote + * 10 - Unknown/Not applicable + * 11 - Reserved + * reserved [15:2] + */ +enum { + PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, + PKTLOG_FLG_FRM_TYPE_REMOTE_S, + PKTLOG_FLG_FRM_TYPE_CLONE_S, + PKTLOG_FLG_FRM_TYPE_CBF_S, + PKTLOG_FLG_FRM_TYPE_UNKNOWN_S +}; + +#define PHFLAGS_INTERRUPT_CONTEXT 0x80000000 + +/* Masks for setting pktlog events filters */ +#define ATH_PKTLOG_TX 0x000000001 +#define ATH_PKTLOG_RX 0x000000002 +#define ATH_PKTLOG_RCFIND 0x000000004 +#define ATH_PKTLOG_RCUPDATE 0x000000008 +#define ATH_PKTLOG_ANI 0x000000010 +#define ATH_PKTLOG_TEXT 0x000000020 +#define ATH_PKTLOG_PHYERR 0x000000040 +#define ATH_PKTLOG_PROMISC 0x000000080 + +/* Types of packet log events */ +#define PKTLOG_TYPE_TX_CTRL 1 +#define PKTLOG_TYPE_TX_STAT 2 +#define PKTLOG_TYPE_TX_MSDU_ID 3 +#define PKTLOG_TYPE_TX_FRM_HDR 4 +#define PKTLOG_TYPE_RX_STAT 5 +#define PKTLOG_TYPE_RC_FIND 6 +#define PKTLOG_TYPE_RC_UPDATE 7 +#define PKTLOG_TYPE_TX_VIRT_ADDR 8 +#define PKTLOG_TYPE_MAX 9 + +#define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ +#define PKTLOG_MAX_TXSTATUS_WORDS 32 +#define PKTLOG_MAX_PROTO_WORDS 16 +#define PKTLOG_MAX_RXDESC_WORDS 62 + +struct txctl_frm_hdr { + uint16_t framectrl; /* frame control field from header */ + uint16_t seqctrl; /* frame control field from header */ + uint16_t bssid_tail; /* last two octets of bssid */ + uint16_t sa_tail; /* last two octets of SA */ + uint16_t da_tail; /* last two octets of DA */ + uint16_t resvd; +}; + +#if defined(HELIUMPLUS) +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 1 +#else +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 192 +#endif /* defined(HELIUMPLUS) */ + +/* + * msdu_id_info_t is defined for reference only + */ +struct msdu_id_info { + uint32_t num_msdu; + uint8_t bound_bmap[(MAX_PKT_INFO_MSDU_ID + 7)>>3]; + /* TODO: + * Convert the id's to uint32_t + * Reduces computation in the driver code + */ + uint16_t id[MAX_PKT_INFO_MSDU_ID]; +} __ATTRIB_PACK; +#define MSDU_ID_INFO_NUM_MSDU_OFFSET 0 /* char offset */ +#define MSDU_ID_INFO_BOUND_BM_OFFSET offsetof(struct msdu_id_info, bound_bmap) +#define MSDU_ID_INFO_ID_OFFSET offsetof(struct msdu_id_info, id) + + +struct ath_pktlog_txctl { + struct ath_pktlog_hdr pl_hdr; + /* struct txctl_frm_hdr frm_hdr; */ + void *txdesc_hdr_ctl; /* frm_hdr + Tx descriptor words */ + struct { + struct txctl_frm_hdr frm_hdr; + uint32_t txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; + /* uint32_t *proto_hdr; / * protocol header (variable length!) * / */ + /* uint32_t *misc; / * Can be used for HT specific or other misc info * / */ + } priv; +} __ATTRIB_PACK; + +struct ath_pktlog_tx_status { + struct ath_pktlog_hdr pl_hdr; + void *ds_status; + int32_t misc[0]; /* Can be used for HT specific or other misc info */ +} __ATTRIB_PACK; + +struct ath_pktlog_msdu_info { + struct ath_pktlog_hdr pl_hdr; + void *ath_msdu_info; + A_UINT32 num_msdu; + struct { + /* + * Provision to add more information fields + */ + struct msdu_info_t { + A_UINT32 num_msdu; + A_UINT8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; + } msdu_id_info; + /* + * array of num_msdu + * Static implementation will consume unwanted memory + * Need to split the pktlog_get_buf to get the buffer pointer only + */ + uint16_t msdu_len[MAX_PKT_INFO_MSDU_ID]; + } priv; + size_t priv_size; + +} __ATTRIB_PACK; + +struct ath_pktlog_rx_info { + struct ath_pktlog_hdr pl_hdr; + void *rx_desc; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_find { + struct ath_pktlog_hdr pl_hdr; + void *rcFind; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_update { + struct ath_pktlog_hdr pl_hdr; + void *txRateCtrl; /* rate control state proper */ +} __ATTRIB_PACK; + +#ifdef WIN32 +#pragma pack(pop, pktlog_fmt) +#endif +#ifdef __ATTRIB_PACK +#undef __ATTRIB_PACK +#endif /* __ATTRIB_PACK */ + +/* + * The following header is included in the beginning of the file, + * followed by log entries when the log buffer is read through procfs + */ + +struct ath_pktlog_bufhdr { + uint32_t magic_num; /* Used by post processing scripts */ + uint32_t version; /* Set to CUR_PKTLOG_VER */ +}; + +struct ath_pktlog_buf { + struct ath_pktlog_bufhdr bufhdr; + int32_t rd_offset; + volatile int32_t wr_offset; + /* Whenever this bytes written value croses 4K bytes, + * logging will be triggered + */ + int32_t bytes_written; + /* Index of the messages sent to userspace */ + uint32_t msg_index; + /* Offset for read */ + loff_t offset; + char log_data[0]; +}; + +#define PKTLOG_MOV_RD_IDX(_rd_offset, _log_buf, _log_size) \ + do { \ + if((_rd_offset + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size) <= _log_size) { \ + _rd_offset = ((_rd_offset) + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size); \ + } else { \ + _rd_offset = ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size; \ + } \ + (_rd_offset) = (((_log_size) - (_rd_offset)) >= \ + sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \ + } while(0) + +#endif /* _PKTLOG_FMT_H_ */ +#endif /* REMOVE_PKT_LOG */